From 895f96d2f772ab90b010ce9c17b99412a4c5efd2 Mon Sep 17 00:00:00 2001 From: Matt Jenkins Date: Wed, 9 Apr 2014 14:27:18 +0100 Subject: [PATCH] Initial Import from SVN --- Makefile | 193 + README | 130 + cross.mk | 31 + etc/MAKEDEV | 175 + etc/MAKEDEV.local | 26 + etc/Makefile | 79 + etc/fstab | 2 + etc/gettytab | 164 + etc/group | 10 + etc/motd | 1 + etc/passwd | 8 + etc/rc | 73 + etc/rc.local | 2 + etc/root/Makefile | 18 + etc/root/dot.cshrc | 14 + etc/root/dot.login | 14 + etc/root/dot.profile | 8 + etc/shadow | 8 + etc/shells | 5 + etc/syslog.conf | 14 + etc/ttys | 16 + include/Makefile | 99 + include/Makefile.install | 63 + include/a.out.h | 90 + include/alloca.h | 15 + include/ar.h | 58 + include/arpa/inet.h | 37 + include/assert.h | 9 + include/ctype.h | 28 + include/curses.h | 191 + include/dbm.h | 28 + include/errno.h | 1 + include/fcntl.h | 51 + include/float.h | 6 + include/fstab.h | 75 + include/grp.h | 15 + include/kmem.h | 6 + include/lastlog.h | 13 + include/limits.h | 71 + include/machine | 1 + include/math.h | 33 + include/mtab.h | 16 + include/ndbm.h | 66 + include/netinet/in.h | 165 + include/nlist.h | 75 + include/paths.h | 59 + include/pcc.h | 229 + include/pic32 | 1 + include/psout.h | 40 + include/pwd.h | 39 + include/ranlib.h | 46 + include/regexp.h | 21 + include/setjmp.h | 42 + include/sgtty.h | 5 + include/signal.h | 1 + include/smallc/curses.h | 114 + include/smallc/fcntl.h | 38 + include/smallc/signal.h | 77 + include/smallc/stdio.h | 24 + include/smallc/sys/gpio.h | 22 + include/smallc/sys/spi.h | 9 + include/smallc/wiznet.h | 12 + include/stab.h | 42 + include/stdarg.h | 35 + include/stddef.h | 8 + include/stdint.h | 15 + include/stdio.h | 134 + include/stdlib.h | 102 + include/string.h | 43 + include/strings.h | 42 + include/struct.h | 9 + include/sys | 1 + include/syscall.h | 176 + include/sysexits.h | 97 + include/syslog.h | 1 + include/tcl/tcl.h | 242 + include/term.h | 11 + include/termios-todo.h | 149 + include/time.h | 35 + include/ttyent.h | 22 + include/tzfile.h | 100 + include/unistd.h | 161 + include/utmp.h | 27 + include/vmf.h | 64 + include/wiznet/client.h | 29 + include/wiznet/ethernet.h | 12 + include/wiznet/server.h | 16 + include/wiznet/socket.h | 56 + include/wiznet/udp.h | 79 + include/wiznet/w5100.h | 262 + lib/Makefile | 65 + lib/libc/Makefile | 111 + lib/libcurses/Makefile | 22 + lib/libtermlib/Makefile | 17 + lib/libwiznet/Makefile | 17 + lib/startup/Makefile | 22 + share/example/Makefile | 14 + share/example/Makefile-host | 30 + share/example/ashello.S | 25 + share/example/blkjack.bas | 61 + share/example/chello.c | 7 + share/example/cplus.cpp | 11 + share/example/echo.S | 67 + share/example/fact.fth | 23 + share/example/hilow.bas | 13 + share/example/prime.scm | 29 + share/example/stars.bas | 14 + share/smallc/Makefile | 41 + share/smallc/adc.c | 26 + share/smallc/gpio.c | 24 + share/smallc/hello.c | 6 + share/smallc/primelist.c | 31 + share/smallc/primesum.c | 32 + share/smallc/q8.c | 208 + share/smallc/rain.c | 129 + share/smallc/test1.c | 219 + share/smallc/test2.c | 127 + share/smallc/test3.c | 49 + share/smallc/webserver.c | 88 + src/Makefile | 28 + src/cmd/Makefile | 127 + src/cmd/Makefile-sbin | 24 + src/cmd/adb/Makefile | 26 + src/cmd/adb/READ_ME | 73 + src/cmd/adb/access.c | 130 + src/cmd/adb/command.c | 239 + src/cmd/adb/cross/Makefile | 55 + src/cmd/adb/defs.h | 303 + src/cmd/adb/doc/adb-figures.ms | 961 + src/cmd/adb/doc/adb-figures.txt | 527 + src/cmd/adb/doc/adb-summary.txt | 91 + src/cmd/adb/doc/adb.ms | 1292 + src/cmd/adb/doc/adb.pdf | Bin 0 -> 46054 bytes src/cmd/adb/doc/adb.txt | 760 + src/cmd/adb/expr.c | 318 + src/cmd/adb/findfn.c | 44 + src/cmd/adb/format.c | 315 + src/cmd/adb/input.c | 86 + src/cmd/adb/main.c | 167 + src/cmd/adb/message.c | 30 + src/cmd/adb/opset.c | 439 + src/cmd/adb/output.c | 393 + src/cmd/adb/pcs.c | 108 + src/cmd/adb/print.c | 426 + src/cmd/adb/runpcs.c | 296 + src/cmd/adb/setup.c | 127 + src/cmd/adb/sym.c | 349 + src/cmd/adc-demo/Makefile | 27 + src/cmd/adc-demo/adc-demo.c | 93 + src/cmd/ar/Makefile | 34 + src/cmd/ar/append.c | 101 + src/cmd/ar/ar.1 | 255 + src/cmd/ar/ar.5.5 | 143 + src/cmd/ar/ar.c | 255 + src/cmd/ar/archive.c | 346 + src/cmd/ar/archive.h | 128 + src/cmd/ar/contents.c | 118 + src/cmd/ar/delete.c | 102 + src/cmd/ar/extern.h | 41 + src/cmd/ar/extract.c | 137 + src/cmd/ar/misc.c | 164 + src/cmd/ar/move.c | 147 + src/cmd/ar/print.c | 93 + src/cmd/ar/replace.c | 196 + src/cmd/ar/strmode.c | 146 + src/cmd/as/Makefile | 44 + src/cmd/as/aout.c | 313 + src/cmd/as/as.c | 2717 ++ src/cmd/as/mips-dis.c | 1451 + src/cmd/as/mips-instruction-set.txt | 350 + src/cmd/as/mips-opc.c | 1184 + src/cmd/as/mips-opcode.h | 1092 + src/cmd/as/mips16-opc.c | 224 + src/cmd/as/tests/Makefile | 19 + src/cmd/as/tests/hello.c | 4 + src/cmd/as/tests/test1.s | 117 + src/cmd/as/tests/test2.s | 37 + src/cmd/as/tests/test3.s | 49 + src/cmd/as/tests/test4.s | 90 + src/cmd/awk/EXPLAIN | 87 + src/cmd/awk/Makefile | 44 + src/cmd/awk/README | 99 + src/cmd/awk/awk.def.h | 135 + src/cmd/awk/awk.g.y | 274 + src/cmd/awk/awk.lx.l | 169 + src/cmd/awk/b.c | 536 + src/cmd/awk/freeze.c | 39 + src/cmd/awk/lib.c | 295 + src/cmd/awk/main.c | 98 + src/cmd/awk/parse.c | 148 + src/cmd/awk/proc.c | 99 + src/cmd/awk/run.c | 887 + src/cmd/awk/tokenscript | 8 + src/cmd/awk/tran.c | 252 + src/cmd/basename.c | 30 + src/cmd/basic/Makefile | 30 + src/cmd/basic/basic.c | 1759 + src/cmd/basic/blkjack.bas | 61 + src/cmd/basic/hilow.bas | 13 + src/cmd/basic/readme.txt | 20 + src/cmd/basic/renumber.c | 122 + src/cmd/basic/stars.bas | 14 + src/cmd/bc.y | 613 + src/cmd/cal.c | 208 + src/cmd/cat.c | 217 + src/cmd/cb.c | 380 + src/cmd/cc/Makefile | 29 + src/cmd/cc/cc.1 | 335 + src/cmd/cc/cc.c | 1423 + src/cmd/ccom/Makefile | 107 + src/cmd/ccom/arch-arm/code.c | 889 + src/cmd/ccom/arch-arm/local.c | 814 + src/cmd/ccom/arch-arm/local2.c | 1496 + src/cmd/ccom/arch-arm/macdefs.h | 263 + src/cmd/ccom/arch-arm/order.c | 339 + src/cmd/ccom/arch-arm/table.c | 1847 + src/cmd/ccom/arch-mips/TODO | 2 + src/cmd/ccom/arch-mips/code.c | 726 + src/cmd/ccom/arch-mips/local.c | 925 + src/cmd/ccom/arch-mips/local2.c | 1329 + src/cmd/ccom/arch-mips/macdefs.h | 350 + src/cmd/ccom/arch-mips/order.c | 259 + src/cmd/ccom/arch-mips/table.c | 1580 + src/cmd/ccom/builtins.c | 504 + src/cmd/ccom/ccom.1 | 192 + src/cmd/ccom/cgram.y | 2248 + src/cmd/ccom/config.h | 177 + src/cmd/ccom/external.c | 293 + src/cmd/ccom/external.h | 25 + src/cmd/ccom/gcc_compat.c | 501 + src/cmd/ccom/init.c | 1055 + src/cmd/ccom/inline.c | 523 + src/cmd/ccom/main.c | 454 + src/cmd/ccom/mip/common.c | 695 + src/cmd/ccom/mip/compat.c | 922 + src/cmd/ccom/mip/compat.h | 45 + src/cmd/ccom/mip/manifest.h | 370 + src/cmd/ccom/mip/match.c | 1260 + src/cmd/ccom/mip/mkext.c | 469 + src/cmd/ccom/mip/node.h | 236 + src/cmd/ccom/mip/optim2.c | 2144 + src/cmd/ccom/mip/pass2.h | 544 + src/cmd/ccom/mip/reader.c | 1653 + src/cmd/ccom/mip/regs.c | 2856 ++ src/cmd/ccom/optim.c | 379 + src/cmd/ccom/pass1.h | 603 + src/cmd/ccom/pftn.c | 3255 ++ src/cmd/ccom/scan.l | 647 + src/cmd/ccom/softfloat.c | 359 + src/cmd/ccom/stabs.c | 459 + src/cmd/ccom/symtabs.c | 361 + src/cmd/ccom/trees.c | 2876 ++ src/cmd/chflags/Makefile | 45 + src/cmd/chflags/chflags.1 | 102 + src/cmd/chflags/chflags.c | 191 + src/cmd/chgrp.c | 208 + src/cmd/chmod.c | 315 + src/cmd/chown/Makefile | 38 + src/cmd/chown/chown.8 | 49 + src/cmd/chown/chown.c | 190 + src/cmd/chpass/Makefile | 61 + src/cmd/chpass/chpass.1 | 161 + src/cmd/chpass/chpass.c | 453 + src/cmd/chpass/chpass.h | 24 + src/cmd/chpass/field.c | 201 + src/cmd/chpass/util.c | 152 + src/cmd/chroot/Makefile | 53 + src/cmd/chroot/chroot.8 | 44 + src/cmd/chroot/chroot.c | 54 + src/cmd/cmp.c | 240 + src/cmd/col.c | 308 + src/cmd/comm.c | 169 + src/cmd/compress/Makefile | 34 + src/cmd/compress/README | 283 + src/cmd/compress/USERMEM | 1 + src/cmd/compress/compress.c | 1511 + src/cmd/compress/usermem.sh | 75 + src/cmd/cp.c | 233 + src/cmd/cpp/Makefile | 63 + src/cmd/cpp/cpp.1 | 210 + src/cmd/cpp/cpp.c | 1767 + src/cmd/cpp/cpp.h | 150 + src/cmd/cpp/cpy.y | 217 + src/cmd/cpp/scanner.l | 932 + src/cmd/cpp/tests/res1 | 8 + src/cmd/cpp/tests/res10 | 16 + src/cmd/cpp/tests/res2 | 26 + src/cmd/cpp/tests/res3 | 16 + src/cmd/cpp/tests/res4 | 6 + src/cmd/cpp/tests/res5 | 5 + src/cmd/cpp/tests/res6 | 5 + src/cmd/cpp/tests/res7 | 6 + src/cmd/cpp/tests/res8 | 9 + src/cmd/cpp/tests/res9 | 6 + src/cmd/cpp/tests/test1 | 6 + src/cmd/cpp/tests/test10 | 14 + src/cmd/cpp/tests/test2 | 25 + src/cmd/cpp/tests/test3 | 15 + src/cmd/cpp/tests/test4 | 4 + src/cmd/cpp/tests/test5 | 3 + src/cmd/cpp/tests/test6 | 5 + src/cmd/cpp/tests/test7 | 4 + src/cmd/cpp/tests/test8 | 7 + src/cmd/cpp/tests/test9 | 4 + src/cmd/cpp/token.c | 1289 + src/cmd/cron/Makefile | 109 + src/cmd/cron/README | 72 + src/cmd/cron/README.2BSD | 58 + src/cmd/cron/bitstring.3 | 168 + src/cmd/cron/bitstring.h | 122 + src/cmd/cron/compat.c | 58 + src/cmd/cron/compat.h | 32 + src/cmd/cron/config.h | 86 + src/cmd/cron/cron.8 | 61 + src/cmd/cron/cron.c | 277 + src/cmd/cron/cron.h | 275 + src/cmd/cron/crontab.1 | 100 + src/cmd/cron/crontab.5 | 188 + src/cmd/cron/crontab.c | 586 + src/cmd/cron/database.c | 261 + src/cmd/cron/do_command.c | 433 + src/cmd/cron/entry.c | 504 + src/cmd/cron/env.c | 178 + src/cmd/cron/externs.h | 28 + src/cmd/cron/grot/CHANGES | 155 + src/cmd/cron/grot/CONVERSION | 85 + src/cmd/cron/grot/FEATURES | 84 + src/cmd/cron/grot/INSTALL | 87 + src/cmd/cron/grot/MAIL | 475 + src/cmd/cron/grot/MANIFEST | 33 + src/cmd/cron/grot/THANKS | 29 + src/cmd/cron/grot/diffs | 1933 + src/cmd/cron/job.c | 74 + src/cmd/cron/misc.c | 649 + src/cmd/cron/pathnames.h | 79 + src/cmd/cron/popen.c | 170 + src/cmd/cron/putman.sh | 26 + src/cmd/cron/user.c | 102 + src/cmd/csh/Makefile | 55 + src/cmd/csh/alloc.c | 382 + src/cmd/csh/printf.c | 300 + src/cmd/csh/sh.c | 932 + src/cmd/csh/sh.char.c | 109 + src/cmd/csh/sh.char.h | 36 + src/cmd/csh/sh.dir.c | 467 + src/cmd/csh/sh.dir.h | 18 + src/cmd/csh/sh.dol.c | 708 + src/cmd/csh/sh.err.c | 144 + src/cmd/csh/sh.exec.c | 333 + src/cmd/csh/sh.exec.h | 23 + src/cmd/csh/sh.exec2.c | 244 + src/cmd/csh/sh.exp.c | 591 + src/cmd/csh/sh.file.c | 592 + src/cmd/csh/sh.func.c | 1139 + src/cmd/csh/sh.glob.c | 745 + src/cmd/csh/sh.h | 479 + src/cmd/csh/sh.hist.c | 142 + src/cmd/csh/sh.init.c | 242 + src/cmd/csh/sh.lex.c | 1330 + src/cmd/csh/sh.local.h | 38 + src/cmd/csh/sh.misc.c | 378 + src/cmd/csh/sh.parse.c | 626 + src/cmd/csh/sh.print.c | 84 + src/cmd/csh/sh.proc.c | 1094 + src/cmd/csh/sh.proc.h | 84 + src/cmd/csh/sh.sem.c | 404 + src/cmd/csh/sh.set.c | 691 + src/cmd/csh/sh.time.c | 196 + src/cmd/date.c | 224 + src/cmd/date2/Makefile | 36 + src/cmd/date2/date.c | 412 + src/cmd/dc/Makefile | 19 + src/cmd/dc/dc.c | 1997 + src/cmd/dc/dc.h | 112 + src/cmd/dd.c | 605 + src/cmd/devupdate/Makefile | 36 + src/cmd/devupdate/devupdate.c | 302 + src/cmd/df.c | 286 + src/cmd/diff/Makefile | 33 + src/cmd/diff/diff.c | 208 + src/cmd/diff/diff.h | 84 + src/cmd/diff/diffdir.c | 420 + src/cmd/diff/diffh.c | 266 + src/cmd/diff/diffreg.c | 1047 + src/cmd/disktool/Makefile | 21 + src/cmd/disktool/disktool.c | 277 + src/cmd/du.c | 160 + src/cmd/echo.c | 24 + src/cmd/ed.c | 1587 + src/cmd/egrep.y | 616 + src/cmd/env/Makefile | 27 + src/cmd/env/env.1 | 122 + src/cmd/env/env.c | 77 + src/cmd/expr.y | 681 + src/cmd/false.sh | 1 + src/cmd/fdisk/Makefile | 41 + src/cmd/fdisk/fdisk.1 | 54 + src/cmd/fdisk/fdisk.c | 339 + src/cmd/fdisk/fdisk.h | 12 + src/cmd/fgrep.c | 384 + src/cmd/file.c | 484 + src/cmd/find/Makefile | 39 + src/cmd/find/bigram.c | 45 + src/cmd/find/code.c | 117 + src/cmd/find/find.c | 1211 + src/cmd/find/updatedb.sh | 39 + src/cmd/forth/Makefile | 30 + src/cmd/forth/fact.fth | 23 + src/cmd/forth/forth.c | 800 + src/cmd/forth/forth.h | 195 + src/cmd/forth/func.c | 2001 + src/cmd/forth/func.txt | 302 + src/cmd/forth/io.h | 114 + src/cmd/fsck/Makefile | 68 + src/cmd/fsck/cross.c | 197 + src/cmd/fsck/dir.c | 581 + src/cmd/fsck/fsck.h | 260 + src/cmd/fsck/inode.c | 310 + src/cmd/fsck/main.c | 346 + src/cmd/fsck/pass1.c | 187 + src/cmd/fsck/pass1b.c | 56 + src/cmd/fsck/pass2.c | 263 + src/cmd/fsck/pass3.c | 48 + src/cmd/fsck/pass4.c | 83 + src/cmd/fsck/pass5.c | 187 + src/cmd/fsck/setup.c | 157 + src/cmd/fsck/utilities.c | 567 + src/cmd/fstat/Makefile | 42 + src/cmd/fstat/fstat.8 | 111 + src/cmd/fstat/fstat.c | 541 + src/cmd/getty/Makefile | 29 + src/cmd/getty/get_date.c | 53 + src/cmd/getty/gettytab.c | 302 + src/cmd/getty/gettytab.h | 110 + src/cmd/getty/init.c | 80 + src/cmd/getty/main.c | 444 + src/cmd/getty/subr.c | 399 + src/cmd/glcdtest/Makefile | 39 + src/cmd/glcdtest/glcdtest.1 | 0 src/cmd/glcdtest/glcdtest.c | 285 + src/cmd/grep.c | 520 + src/cmd/gtest/Makefile | 48 + src/cmd/gtest/globdump.c | 19 + src/cmd/gtest/globread.c | 16 + src/cmd/gtest/globwrite.c | 16 + src/cmd/head.c | 79 + src/cmd/hostid.c | 58 + src/cmd/hostname/Makefile | 40 + src/cmd/hostname/hostname.1 | 69 + src/cmd/hostname/hostname.c | 73 + src/cmd/id/Makefile | 47 + src/cmd/id/groups.1 | 60 + src/cmd/id/groups.sh | 37 + src/cmd/id/id.1 | 135 + src/cmd/id/id.c | 312 + src/cmd/id/whoami.1 | 59 + src/cmd/id/whoami.sh | 37 + src/cmd/init/Makefile | 39 + src/cmd/init/init.8 | 144 + src/cmd/init/init.c | 732 + src/cmd/iostat.c | 246 + src/cmd/join.c | 217 + src/cmd/kill.c | 74 + src/cmd/la/Makefile | 30 + src/cmd/la/la.1 | 19 + src/cmd/la/la.c | 20 + src/cmd/last.c | 233 + src/cmd/lcc/Makefile | 40 + src/cmd/lcc/bprint.1 | 83 + src/cmd/lcc/bprint.c | 213 + src/cmd/lcc/gcc-solaris.c | 51 + src/cmd/lcc/irix.c | 69 + src/cmd/lcc/lcc.1 | 605 + src/cmd/lcc/lcc.c | 821 + src/cmd/lcc/linux.c | 61 + src/cmd/lcc/ops.c | 60 + src/cmd/lcc/osf.c | 54 + src/cmd/lcc/retrobsd.c | 79 + src/cmd/lcc/solaris.c | 51 + src/cmd/lcc/win32.c | 41 + src/cmd/lccom/CPYRIGHT | 62 + src/cmd/lccom/LOG | 383 + src/cmd/lccom/Makefile | 141 + src/cmd/lccom/README | 22 + src/cmd/lccom/alloc.c | 101 + src/cmd/lccom/alpha.md | 1188 + src/cmd/lccom/bind.c | 40 + src/cmd/lccom/bytecode.c | 287 + src/cmd/lccom/c.h | 598 + src/cmd/lccom/config.h | 103 + src/cmd/lccom/dag.c | 741 + src/cmd/lccom/dagcheck.md | 212 + src/cmd/lccom/decl.c | 1174 + src/cmd/lccom/doc/install.html | 774 + src/cmd/lccom/enode.c | 550 + src/cmd/lccom/error.c | 136 + src/cmd/lccom/event.c | 26 + src/cmd/lccom/expr.c | 711 + src/cmd/lccom/gen.c | 839 + src/cmd/lccom/init.c | 317 + src/cmd/lccom/inits.c | 6 + src/cmd/lccom/input.c | 144 + src/cmd/lccom/lburg/gram.y | 202 + src/cmd/lccom/lburg/lburg.1 | 358 + src/cmd/lccom/lburg/lburg.c | 682 + src/cmd/lccom/lburg/lburg.h | 132 + src/cmd/lccom/lex.c | 930 + src/cmd/lccom/lib/assert.c | 19 + src/cmd/lccom/lib/bbexit.c | 136 + src/cmd/lccom/lib/yynull.c | 16 + src/cmd/lccom/list.c | 55 + src/cmd/lccom/main.c | 265 + src/cmd/lccom/mips.md | 1158 + src/cmd/lccom/null.c | 73 + src/cmd/lccom/ops.h | 131 + src/cmd/lccom/output.c | 133 + src/cmd/lccom/prof.c | 231 + src/cmd/lccom/profio.c | 285 + src/cmd/lccom/simp.c | 614 + src/cmd/lccom/sparc.md | 1176 + src/cmd/lccom/stab.c | 329 + src/cmd/lccom/stab.h | 108 + src/cmd/lccom/stmt.c | 707 + src/cmd/lccom/string.c | 125 + src/cmd/lccom/sym.c | 334 + src/cmd/lccom/symbolic.c | 524 + src/cmd/lccom/token.h | 133 + src/cmd/lccom/trace.c | 169 + src/cmd/lccom/tree.c | 240 + src/cmd/lccom/tst/8q.0 | 0 src/cmd/lccom/tst/8q.c | 39 + src/cmd/lccom/tst/array.0 | 0 src/cmd/lccom/tst/array.c | 48 + src/cmd/lccom/tst/cf.0 | 32 + src/cmd/lccom/tst/cf.c | 32 + src/cmd/lccom/tst/cq.0 | 0 src/cmd/lccom/tst/cq.c | 5316 +++ src/cmd/lccom/tst/cvt.0 | 0 src/cmd/lccom/tst/cvt.c | 35 + src/cmd/lccom/tst/fields.0 | 0 src/cmd/lccom/tst/fields.c | 34 + src/cmd/lccom/tst/front.0 | 0 src/cmd/lccom/tst/front.c | 120 + src/cmd/lccom/tst/incr.0 | 0 src/cmd/lccom/tst/incr.c | 39 + src/cmd/lccom/tst/init.0 | 0 src/cmd/lccom/tst/init.c | 59 + src/cmd/lccom/tst/limits.0 | 0 src/cmd/lccom/tst/limits.c | 19 + src/cmd/lccom/tst/mips-eb/8q.1bk | 92 + src/cmd/lccom/tst/mips-eb/8q.2bk | 2 + src/cmd/lccom/tst/mips-eb/8q.sbk | 169 + src/cmd/lccom/tst/mips-eb/array.1bk | 4 + src/cmd/lccom/tst/mips-eb/array.2bk | 2 + src/cmd/lccom/tst/mips-eb/array.sbk | 235 + src/cmd/lccom/tst/mips-eb/assert.h | 14 + src/cmd/lccom/tst/mips-eb/cf.1bk | 51 + src/cmd/lccom/tst/mips-eb/cf.2bk | 0 src/cmd/lccom/tst/mips-eb/cf.sbk | 153 + src/cmd/lccom/tst/mips-eb/cq.1bk | 48 + src/cmd/lccom/tst/mips-eb/cq.2bk | 25 + src/cmd/lccom/tst/mips-eb/cq.sbk | 13620 ++++++ src/cmd/lccom/tst/mips-eb/ctype.h | 40 + src/cmd/lccom/tst/mips-eb/cvt.1bk | 11 + src/cmd/lccom/tst/mips-eb/cvt.2bk | 2 + src/cmd/lccom/tst/mips-eb/cvt.sbk | 557 + src/cmd/lccom/tst/mips-eb/errno.h | 8 + src/cmd/lccom/tst/mips-eb/fields.1bk | 5 + src/cmd/lccom/tst/mips-eb/fields.2bk | 4 + src/cmd/lccom/tst/mips-eb/fields.sbk | 304 + src/cmd/lccom/tst/mips-eb/float.h | 37 + src/cmd/lccom/tst/mips-eb/front.2bk | 29 + src/cmd/lccom/tst/mips-eb/front.sbk | 416 + src/cmd/lccom/tst/mips-eb/incr.2bk | 9 + src/cmd/lccom/tst/mips-eb/incr.sbk | 149 + src/cmd/lccom/tst/mips-eb/init.1bk | 16 + src/cmd/lccom/tst/mips-eb/init.2bk | 3 + src/cmd/lccom/tst/mips-eb/init.sbk | 325 + src/cmd/lccom/tst/mips-eb/limits.1bk | 14 + src/cmd/lccom/tst/mips-eb/limits.2bk | 0 src/cmd/lccom/tst/mips-eb/limits.h | 30 + src/cmd/lccom/tst/mips-eb/limits.sbk | 396 + src/cmd/lccom/tst/mips-eb/locale.h | 38 + src/cmd/lccom/tst/mips-eb/math.h | 29 + src/cmd/lccom/tst/mips-eb/paranoia.1bk | 178 + src/cmd/lccom/tst/mips-eb/paranoia.2bk | 16 + src/cmd/lccom/tst/mips-eb/paranoia.sbk | 18657 ++++++++ src/cmd/lccom/tst/mips-eb/setjmp.h | 11 + src/cmd/lccom/tst/mips-eb/signal.h | 20 + src/cmd/lccom/tst/mips-eb/sort.1bk | 20 + src/cmd/lccom/tst/mips-eb/sort.2bk | 5 + src/cmd/lccom/tst/mips-eb/sort.sbk | 309 + src/cmd/lccom/tst/mips-eb/spill.2bk | 6 + src/cmd/lccom/tst/mips-eb/spill.sbk | 271 + src/cmd/lccom/tst/mips-eb/stdarg.1bk | 6 + src/cmd/lccom/tst/mips-eb/stdarg.2bk | 1 + src/cmd/lccom/tst/mips-eb/stdarg.h | 27 + src/cmd/lccom/tst/mips-eb/stdarg.sbk | 396 + src/cmd/lccom/tst/mips-eb/stddef.h | 35 + src/cmd/lccom/tst/mips-eb/stdio.h | 102 + src/cmd/lccom/tst/mips-eb/stdlib.h | 66 + src/cmd/lccom/tst/mips-eb/string.h | 38 + src/cmd/lccom/tst/mips-eb/struct.1bk | 5 + src/cmd/lccom/tst/mips-eb/struct.2bk | 2 + src/cmd/lccom/tst/mips-eb/struct.sbk | 485 + src/cmd/lccom/tst/mips-eb/switch.1bk | 76 + src/cmd/lccom/tst/mips-eb/switch.2bk | 5 + src/cmd/lccom/tst/mips-eb/switch.sbk | 836 + src/cmd/lccom/tst/mips-eb/time.h | 51 + src/cmd/lccom/tst/mips-eb/wf1.1bk | 74 + src/cmd/lccom/tst/mips-eb/wf1.2bk | 2 + src/cmd/lccom/tst/mips-eb/wf1.sbk | 378 + src/cmd/lccom/tst/mips-eb/yacc.1bk | 10 + src/cmd/lccom/tst/mips-eb/yacc.2bk | 3 + src/cmd/lccom/tst/mips-eb/yacc.sbk | 2240 + src/cmd/lccom/tst/paranoia.0 | 0 src/cmd/lccom/tst/paranoia.c | 2203 + src/cmd/lccom/tst/run.sh | 37 + src/cmd/lccom/tst/sort.0 | 0 src/cmd/lccom/tst/sort.c | 65 + src/cmd/lccom/tst/spill.0 | 0 src/cmd/lccom/tst/spill.c | 17 + src/cmd/lccom/tst/stdarg.0 | 0 src/cmd/lccom/tst/stdarg.c | 51 + src/cmd/lccom/tst/struct.0 | 0 src/cmd/lccom/tst/struct.c | 69 + src/cmd/lccom/tst/switch.0 | 0 src/cmd/lccom/tst/switch.c | 137 + src/cmd/lccom/tst/wf1.0 | 115 + src/cmd/lccom/tst/wf1.c | 101 + src/cmd/lccom/tst/x86-linux/8q.1bk | 92 + src/cmd/lccom/tst/x86-linux/8q.2bk | 2 + src/cmd/lccom/tst/x86-linux/8q.sbk | 180 + src/cmd/lccom/tst/x86-linux/array.1bk | 4 + src/cmd/lccom/tst/x86-linux/array.2bk | 2 + src/cmd/lccom/tst/x86-linux/array.sbk | 235 + src/cmd/lccom/tst/x86-linux/assert.h | 14 + src/cmd/lccom/tst/x86-linux/cf.1bk | 51 + src/cmd/lccom/tst/x86-linux/cf.2bk | 0 src/cmd/lccom/tst/x86-linux/cf.sbk | 164 + src/cmd/lccom/tst/x86-linux/cq.1bk | 48 + src/cmd/lccom/tst/x86-linux/cq.2bk | 25 + src/cmd/lccom/tst/x86-linux/cq.sbk | 16528 ++++++++ src/cmd/lccom/tst/x86-linux/cvt.1bk | 11 + src/cmd/lccom/tst/x86-linux/cvt.2bk | 2 + src/cmd/lccom/tst/x86-linux/cvt.sbk | 993 + src/cmd/lccom/tst/x86-linux/fields.1bk | 5 + src/cmd/lccom/tst/x86-linux/fields.2bk | 4 + src/cmd/lccom/tst/x86-linux/fields.sbk | 321 + src/cmd/lccom/tst/x86-linux/float.h | 37 + src/cmd/lccom/tst/x86-linux/front.2bk | 29 + src/cmd/lccom/tst/x86-linux/front.sbk | 530 + src/cmd/lccom/tst/x86-linux/incr.1bk | 0 src/cmd/lccom/tst/x86-linux/incr.2bk | 9 + src/cmd/lccom/tst/x86-linux/incr.sbk | 181 + src/cmd/lccom/tst/x86-linux/init.1bk | 16 + src/cmd/lccom/tst/x86-linux/init.2bk | 3 + src/cmd/lccom/tst/x86-linux/init.sbk | 336 + src/cmd/lccom/tst/x86-linux/limits.1bk | 14 + src/cmd/lccom/tst/x86-linux/limits.2bk | 0 src/cmd/lccom/tst/x86-linux/limits.h | 30 + src/cmd/lccom/tst/x86-linux/limits.sbk | 396 + src/cmd/lccom/tst/x86-linux/math.h | 29 + src/cmd/lccom/tst/x86-linux/paranoia.1bk | 183 + src/cmd/lccom/tst/x86-linux/paranoia.2bk | 16 + src/cmd/lccom/tst/x86-linux/paranoia.sbk | 20618 +++++++++ src/cmd/lccom/tst/x86-linux/sort.1bk | 20 + src/cmd/lccom/tst/x86-linux/sort.2bk | 5 + src/cmd/lccom/tst/x86-linux/sort.sbk | 331 + src/cmd/lccom/tst/x86-linux/spill.1bk | 0 src/cmd/lccom/tst/x86-linux/spill.2bk | 6 + src/cmd/lccom/tst/x86-linux/spill.sbk | 286 + src/cmd/lccom/tst/x86-linux/stdarg.1bk | 6 + src/cmd/lccom/tst/x86-linux/stdarg.2bk | 1 + src/cmd/lccom/tst/x86-linux/stdarg.h | 26 + src/cmd/lccom/tst/x86-linux/stdarg.sbk | 400 + src/cmd/lccom/tst/x86-linux/struct.1bk | 5 + src/cmd/lccom/tst/x86-linux/struct.2bk | 2 + src/cmd/lccom/tst/x86-linux/struct.sbk | 476 + src/cmd/lccom/tst/x86-linux/switch.1bk | 76 + src/cmd/lccom/tst/x86-linux/switch.2bk | 5 + src/cmd/lccom/tst/x86-linux/switch.sbk | 899 + src/cmd/lccom/tst/x86-linux/wf1.1bk | 74 + src/cmd/lccom/tst/x86-linux/wf1.2bk | 2 + src/cmd/lccom/tst/x86-linux/wf1.sbk | 437 + src/cmd/lccom/tst/x86-linux/yacc.1bk | 10 + src/cmd/lccom/tst/x86-linux/yacc.2bk | 3 + src/cmd/lccom/tst/x86-linux/yacc.sbk | 2384 ++ src/cmd/lccom/tst/yacc.0 | 1 + src/cmd/lccom/tst/yacc.c | 592 + src/cmd/lccom/types.c | 754 + src/cmd/lccom/x86.md | 1011 + src/cmd/lccom/x86linux.md | 1078 + src/cmd/lcpp/Makefile | 49 + src/cmd/lcpp/cpp.c | 323 + src/cmd/lcpp/cpp.h | 162 + src/cmd/lcpp/eval.c | 530 + src/cmd/lcpp/hideset.c | 111 + src/cmd/lcpp/include.c | 118 + src/cmd/lcpp/lex.c | 579 + src/cmd/lcpp/macro.c | 516 + src/cmd/lcpp/nlist.c | 103 + src/cmd/lcpp/tokens.c | 372 + src/cmd/lcpp/unix.c | 114 + src/cmd/ld/Makefile | 32 + src/cmd/ld/ld.1 | 334 + src/cmd/ld/ld.c | 1572 + src/cmd/lex/Makefile | 31 + src/cmd/lex/header.c | 112 + src/cmd/lex/ldefs.c | 166 + src/cmd/lex/lmain.c | 230 + src/cmd/lex/ncform | 181 + src/cmd/lex/nrform | 155 + src/cmd/lex/once.c | 131 + src/cmd/lex/parser.y | 714 + src/cmd/lex/sub1.c | 692 + src/cmd/lex/sub2.c | 952 + src/cmd/ln.c | 89 + src/cmd/login/Makefile | 51 + src/cmd/login/login.c | 577 + src/cmd/lorder.sh | 34 + src/cmd/ls/Makefile | 32 + src/cmd/ls/ls.c | 695 + src/cmd/ls/stat_flags.c | 148 + src/cmd/m4/Makefile | 28 + src/cmd/m4/NOTES | 64 + src/cmd/m4/TEST/ack.m4 | 40 + src/cmd/m4/TEST/hanoi.m4 | 45 + src/cmd/m4/TEST/hash.m4 | 55 + src/cmd/m4/TEST/sqroot.m4 | 45 + src/cmd/m4/TEST/string.m4 | 45 + src/cmd/m4/TEST/test.m4 | 243 + src/cmd/m4/eval.c | 787 + src/cmd/m4/expr.c | 626 + src/cmd/m4/extern.h | 98 + src/cmd/m4/look.c | 144 + src/cmd/m4/main.c | 422 + src/cmd/m4/mdef.h | 176 + src/cmd/m4/misc.c | 244 + src/cmd/m4/pathnames.h | 57 + src/cmd/m4/stdd.h | 60 + src/cmd/m4/tags | 70 + src/cmd/mail.c | 693 + src/cmd/make/Makefile | 29 + src/cmd/make/defs.h | 154 + src/cmd/make/doname.c | 351 + src/cmd/make/dosys.c | 182 + src/cmd/make/files.c | 547 + src/cmd/make/gram.y | 288 + src/cmd/make/history.txt | 98 + src/cmd/make/main.c | 395 + src/cmd/make/misc.c | 319 + src/cmd/man/Makefile | 63 + src/cmd/man/apropos.c | 206 + src/cmd/man/man.c | 447 + src/cmd/med/Makefile | 27 + src/cmd/med/med.c | 534 + src/cmd/mesg.c | 57 + src/cmd/mkdep.sh | 102 + src/cmd/mkdir.c | 108 + src/cmd/mkfs/Makefile | 43 + src/cmd/mkfs/mkfs.8 | 87 + src/cmd/mkfs/mkfs.c | 500 + src/cmd/mknod/Makefile | 42 + src/cmd/mknod/mknod.8 | 45 + src/cmd/mknod/mknod.c | 47 + src/cmd/mkpasswd/Makefile | 52 + src/cmd/mkpasswd/mkpasswd.8 | 59 + src/cmd/mkpasswd/mkpasswd.c | 211 + src/cmd/more/Makefile | 28 + src/cmd/more/more.c | 1773 + src/cmd/more/more.help | 24 + src/cmd/mount/Makefile | 42 + src/cmd/mount/getmntopts.3 | 178 + src/cmd/mount/getmntopts.c | 82 + src/cmd/mount/mntopts.h | 81 + src/cmd/mount/mount.8 | 276 + src/cmd/mount/mount.c | 488 + src/cmd/mount/mount_ufs.c | 108 + src/cmd/msec/Makefile | 40 + src/cmd/msec/msec.1 | 0 src/cmd/msec/msec.c | 10 + src/cmd/mv.c | 299 + src/cmd/nice.c | 34 + src/cmd/nm.c.use.disk | 430 + src/cmd/nm/Makefile | 25 + src/cmd/nm/nm.c | 427 + src/cmd/nohup.sh | 7 + src/cmd/od.c | 883 + src/cmd/pagesize.c | 12 + src/cmd/passwd/Makefile | 55 + src/cmd/passwd/passwd.1 | 48 + src/cmd/passwd/passwd.c | 256 + src/cmd/pforth/..bin | Bin 0 -> 60116 bytes src/cmd/pforth/Makefile | 50 + src/cmd/pforth/Makefile-orig | 110 + src/cmd/pforth/fth/ansilocs.fth | 203 + src/cmd/pforth/fth/bench.fth | 198 + src/cmd/pforth/fth/c_struct.fth | 242 + src/cmd/pforth/fth/case.fth | 78 + src/cmd/pforth/fth/condcomp.fth | 50 + src/cmd/pforth/fth/coretest.fth | 999 + src/cmd/pforth/fth/filefind.fth | 119 + src/cmd/pforth/fth/floats.fth | 502 + src/cmd/pforth/fth/forget.fth | 97 + src/cmd/pforth/fth/history.fth | 513 + src/cmd/pforth/fth/loadhist.fth | 7 + src/cmd/pforth/fth/loadp4th.fth | 46 + src/cmd/pforth/fth/locals.fth | 77 + src/cmd/pforth/fth/math.fth | 89 + src/cmd/pforth/fth/member.fth | 155 + src/cmd/pforth/fth/misc1.fth | 175 + src/cmd/pforth/fth/misc2.fth | 235 + src/cmd/pforth/fth/numberio.fth | 204 + src/cmd/pforth/fth/private.fth | 48 + src/cmd/pforth/fth/savedicd.fth | 177 + src/cmd/pforth/fth/see.fth | 218 + src/cmd/pforth/fth/siev.fth | 31 + src/cmd/pforth/fth/smart_if.fth | 57 + src/cmd/pforth/fth/strings.fth | 97 + src/cmd/pforth/fth/system.fth | 825 + src/cmd/pforth/fth/t_alloc.fth | 116 + src/cmd/pforth/fth/t_case.fth | 16 + src/cmd/pforth/fth/t_corex.fth | 226 + src/cmd/pforth/fth/t_floats.fth | 134 + src/cmd/pforth/fth/t_include.fth | 18 + src/cmd/pforth/fth/t_load.fth | 7 + src/cmd/pforth/fth/t_load_defer.fth | 5 + src/cmd/pforth/fth/t_load_pairs.fth | 5 + src/cmd/pforth/fth/t_load_semi.fth | 6 + src/cmd/pforth/fth/t_load_undef.fth | 5 + src/cmd/pforth/fth/t_locals.fth | 52 + src/cmd/pforth/fth/t_nolf.fth | 4 + src/cmd/pforth/fth/t_strings.fth | 106 + src/cmd/pforth/fth/t_tools.fth | 83 + src/cmd/pforth/fth/termio.fth | 88 + src/cmd/pforth/fth/tester.fth | 54 + src/cmd/pforth/fth/trace.fth | 460 + src/cmd/pforth/fth/tut.fth | 70 + src/cmd/pforth/fth/utils/clone.fth | 489 + src/cmd/pforth/fth/utils/dump_struct.fth | 122 + src/cmd/pforth/fth/utils/load_file.fth | 39 + src/cmd/pforth/fth/utils/make_all256.fth | 57 + src/cmd/pforth/fth/utils/trace.fth | 438 + src/cmd/pforth/fth/wordslik.fth | 44 + src/cmd/pforth/pf_all.h | 67 + src/cmd/pforth/pf_cglue.c | 100 + src/cmd/pforth/pf_cglue.h | 45 + src/cmd/pforth/pf_clib.c | 64 + src/cmd/pforth/pf_clib.h | 63 + src/cmd/pforth/pf_core.c | 584 + src/cmd/pforth/pf_core.h | 38 + src/cmd/pforth/pf_float.h | 43 + src/cmd/pforth/pf_guts.h | 597 + src/cmd/pforth/pf_host.h | 24 + src/cmd/pforth/pf_inc1.h | 48 + src/cmd/pforth/pf_inner.c | 1803 + src/cmd/pforth/pf_io.c | 225 + src/cmd/pforth/pf_io.h | 156 + src/cmd/pforth/pf_io_none.c | 49 + src/cmd/pforth/pf_io_posix.c | 142 + src/cmd/pforth/pf_io_stdio.c | 56 + src/cmd/pforth/pf_main.c | 150 + src/cmd/pforth/pf_mem.c | 366 + src/cmd/pforth/pf_mem.h | 47 + src/cmd/pforth/pf_save.c | 845 + src/cmd/pforth/pf_save.h | 100 + src/cmd/pforth/pf_text.c | 407 + src/cmd/pforth/pf_text.h | 71 + src/cmd/pforth/pf_types.h | 35 + src/cmd/pforth/pf_win32.h | 41 + src/cmd/pforth/pf_words.c | 223 + src/cmd/pforth/pf_words.h | 36 + src/cmd/pforth/pfcompfp.h | 78 + src/cmd/pforth/pfcompil.c | 1187 + src/cmd/pforth/pfcompil.h | 73 + src/cmd/pforth/pfcustom.c | 121 + src/cmd/pforth/pfdicdat.h | 3364 ++ src/cmd/pforth/pfinnrfp.h | 336 + src/cmd/pforth/pforth.dic | Bin 0 -> 53728 bytes src/cmd/pforth/pforth.h | 101 + src/cmd/pforth/readme.txt | 97 + src/cmd/pforth/releases.txt | 273 + src/cmd/picoc/Makefile | 65 + src/cmd/picoc/README | 91 + src/cmd/picoc/clibrary.c | 679 + src/cmd/picoc/cstdlib/ctype.c | 110 + src/cmd/picoc/cstdlib/errno.c | 655 + src/cmd/picoc/cstdlib/math.c | 187 + src/cmd/picoc/cstdlib/stdbool.c | 22 + src/cmd/picoc/cstdlib/stdio.c | 742 + src/cmd/picoc/cstdlib/stdlib.c | 174 + src/cmd/picoc/cstdlib/string.c | 190 + src/cmd/picoc/cstdlib/time.c | 140 + src/cmd/picoc/cstdlib/unistd.c | 531 + src/cmd/picoc/debug.c | 127 + src/cmd/picoc/expression.c | 1492 + src/cmd/picoc/heap.c | 289 + src/cmd/picoc/include.c | 115 + src/cmd/picoc/interpreter.h | 523 + src/cmd/picoc/lex.c | 978 + src/cmd/picoc/msvc/picoc/picoc.sln | 20 + src/cmd/picoc/msvc/picoc/picoc.vcxproj | 111 + .../picoc/msvc/picoc/picoc.vcxproj.filters | 99 + src/cmd/picoc/parse.c | 917 + src/cmd/picoc/picoc.c | 104 + src/cmd/picoc/picoc.h | 52 + src/cmd/picoc/platform.c | 242 + src/cmd/picoc/platform.h | 148 + src/cmd/picoc/platform/library_ffox.c | 13 + src/cmd/picoc/platform/library_msvc.c | 5 + src/cmd/picoc/platform/library_srv1.c | 809 + src/cmd/picoc/platform/library_surveyor.c | 944 + src/cmd/picoc/platform/library_unix.c | 29 + src/cmd/picoc/platform/platform_ffox.c | 51 + src/cmd/picoc/platform/platform_msvc.c | 80 + src/cmd/picoc/platform/platform_surveyor.c | 71 + src/cmd/picoc/platform/platform_unix.c | 137 + src/cmd/picoc/retrobsd.c | 20 + src/cmd/picoc/table.c | 190 + src/cmd/picoc/tests/00_assignment.c | 13 + src/cmd/picoc/tests/00_assignment.expect | 3 + src/cmd/picoc/tests/01_comment.c | 10 + src/cmd/picoc/tests/01_comment.expect | 5 + src/cmd/picoc/tests/02_printf.c | 13 + src/cmd/picoc/tests/02_printf.expect | 15 + src/cmd/picoc/tests/03_struct.c | 21 + src/cmd/picoc/tests/03_struct.expect | 2 + src/cmd/picoc/tests/04_for.c | 10 + src/cmd/picoc/tests/04_for.expect | 10 + src/cmd/picoc/tests/05_array.c | 16 + src/cmd/picoc/tests/05_array.expect | 10 + src/cmd/picoc/tests/06_case.c | 24 + src/cmd/picoc/tests/06_case.expect | 8 + src/cmd/picoc/tests/07_function.c | 25 + src/cmd/picoc/tests/07_function.expect | 4 + src/cmd/picoc/tests/08_while.c | 19 + src/cmd/picoc/tests/08_while.expect | 11 + src/cmd/picoc/tests/09_do_while.c | 20 + src/cmd/picoc/tests/09_do_while.expect | 11 + src/cmd/picoc/tests/10_pointer.c | 37 + src/cmd/picoc/tests/10_pointer.expect | 7 + src/cmd/picoc/tests/11_precedence.c | 38 + src/cmd/picoc/tests/11_precedence.expect | 15 + src/cmd/picoc/tests/12_hashdefine.c | 10 + src/cmd/picoc/tests/12_hashdefine.expect | 2 + src/cmd/picoc/tests/13_integer_literals.c | 16 + .../picoc/tests/13_integer_literals.expect | 5 + src/cmd/picoc/tests/14_if.c | 17 + src/cmd/picoc/tests/14_if.expect | 2 + src/cmd/picoc/tests/15_recursion.c | 16 + src/cmd/picoc/tests/15_recursion.expect | 10 + src/cmd/picoc/tests/16_nesting.c | 16 + src/cmd/picoc/tests/16_nesting.expect | 18 + src/cmd/picoc/tests/17_enum.c | 24 + src/cmd/picoc/tests/17_enum.expect | 4 + src/cmd/picoc/tests/18_include.c | 7 + src/cmd/picoc/tests/18_include.expect | 3 + src/cmd/picoc/tests/18_include.h | 1 + src/cmd/picoc/tests/19_pointer_arithmetic.c | 24 + .../picoc/tests/19_pointer_arithmetic.expect | 3 + src/cmd/picoc/tests/20_pointer_comparison.c | 20 + .../picoc/tests/20_pointer_comparison.expect | 6 + src/cmd/picoc/tests/21_char_array.c | 29 + src/cmd/picoc/tests/21_char_array.expect | 7 + src/cmd/picoc/tests/22_floating_point.c | 45 + src/cmd/picoc/tests/22_floating_point.expect | 16 + src/cmd/picoc/tests/23_type_coercion.c | 49 + src/cmd/picoc/tests/23_type_coercion.expect | 15 + src/cmd/picoc/tests/24_math_library.c | 23 + src/cmd/picoc/tests/24_math_library.expect | 18 + src/cmd/picoc/tests/25_quicksort.c | 80 + src/cmd/picoc/tests/25_quicksort.expect | 2 + src/cmd/picoc/tests/26_character_constants.c | 13 + .../picoc/tests/26_character_constants.expect | 8 + src/cmd/picoc/tests/27_sizeof.c | 12 + src/cmd/picoc/tests/27_sizeof.expect | 3 + src/cmd/picoc/tests/28_strings.c | 41 + src/cmd/picoc/tests/28_strings.expect | 19 + src/cmd/picoc/tests/29_array_address.c | 8 + src/cmd/picoc/tests/29_array_address.expect | 1 + src/cmd/picoc/tests/30_hanoi.c | 125 + src/cmd/picoc/tests/30_hanoi.expect | 71 + src/cmd/picoc/tests/31_args.c | 12 + src/cmd/picoc/tests/31_args.expect | 6 + src/cmd/picoc/tests/32_led.c | 264 + src/cmd/picoc/tests/32_led.expect | 4 + src/cmd/picoc/tests/33_ternary_op.c | 10 + src/cmd/picoc/tests/33_ternary_op.expect | 10 + src/cmd/picoc/tests/34_array_assignment.c | 18 + .../picoc/tests/34_array_assignment.expect | 2 + src/cmd/picoc/tests/35_sizeof.c | 9 + src/cmd/picoc/tests/35_sizeof.expect | 2 + src/cmd/picoc/tests/36_array_initialisers.c | 16 + .../picoc/tests/36_array_initialisers.expect | 20 + src/cmd/picoc/tests/37_sprintf.c | 12 + src/cmd/picoc/tests/37_sprintf.expect | 20 + src/cmd/picoc/tests/38_multiple_array_index.c | 29 + .../tests/38_multiple_array_index.expect | 4 + src/cmd/picoc/tests/39_typedef.c | 26 + src/cmd/picoc/tests/39_typedef.expect | 3 + src/cmd/picoc/tests/40_stdio.c | 47 + src/cmd/picoc/tests/40_stdio.expect | 27 + src/cmd/picoc/tests/41_hashif.c | 80 + src/cmd/picoc/tests/41_hashif.expect | 6 + src/cmd/picoc/tests/42_function_pointer.c | 15 + src/cmd/picoc/tests/43_void_param.c | 10 + src/cmd/picoc/tests/43_void_param.expect | 1 + src/cmd/picoc/tests/44_scoped_declarations.c | 12 + .../picoc/tests/44_scoped_declarations.expect | 1 + src/cmd/picoc/tests/45_empty_for.c | 16 + src/cmd/picoc/tests/45_empty_for.expect | 10 + src/cmd/picoc/tests/46_grep.c | 562 + src/cmd/picoc/tests/47_switch_return.c | 23 + src/cmd/picoc/tests/47_switch_return.expect | 4 + src/cmd/picoc/tests/48_nested_break.c | 24 + src/cmd/picoc/tests/48_nested_break.expect | 1 + src/cmd/picoc/tests/49_bracket_evaluation.c | 21 + .../picoc/tests/49_bracket_evaluation.expect | 1 + src/cmd/picoc/tests/50_logical_second_arg.c | 27 + .../picoc/tests/50_logical_second_arg.expect | 20 + src/cmd/picoc/tests/51_static.c | 26 + src/cmd/picoc/tests/51_static.expect | 8 + src/cmd/picoc/tests/52_unnamed_enum.c | 24 + src/cmd/picoc/tests/52_unnamed_enum.expect | 9 + src/cmd/picoc/tests/54_goto.c | 52 + src/cmd/picoc/tests/54_goto.expect | 8 + src/cmd/picoc/tests/55_array_initialiser.c | 12 + .../picoc/tests/55_array_initialiser.expect | 2 + src/cmd/picoc/tests/Makefile | 74 + src/cmd/picoc/type.c | 549 + src/cmd/picoc/variable.c | 369 + src/cmd/portio/Makefile | 28 + src/cmd/portio/font6x10.c | 2361 ++ src/cmd/portio/lol.c | 219 + src/cmd/portio/portio.c | 306 + src/cmd/pr.c | 457 + src/cmd/printenv.c | 51 + src/cmd/printf/Makefile | 42 + src/cmd/printf/printf.1 | 294 + src/cmd/printf/printf.c | 386 + src/cmd/ps.c | 831 + src/cmd/pstat/Makefile | 42 + src/cmd/pstat/pstat.8 | 358 + src/cmd/pstat/pstat.c | 556 + src/cmd/pwd.c | 26 + src/cmd/pwm/Makefile | 39 + src/cmd/pwm/pwm.1 | 0 src/cmd/pwm/pwm.c | 72 + src/cmd/ranlib/Makefile | 36 + src/cmd/ranlib/ranlib.1 | 84 + src/cmd/ranlib/ranlib.5.5 | 70 + src/cmd/ranlib/ranlib.c | 467 + src/cmd/rdprof/Makefile | 40 + src/cmd/rdprof/rdprof.1 | 0 src/cmd/rdprof/rdprof.c | 196 + src/cmd/re/Makefile | 32 + src/cmd/re/Makefile-linux | 24 + src/cmd/re/README.txt | 44 + src/cmd/re/help.txt | 23 + src/cmd/re/r.cmd.c | 830 + src/cmd/re/r.defs.h | 348 + src/cmd/re/r.display.c | 577 + src/cmd/re/r.edit.c | 1380 + src/cmd/re/r.file.c | 302 + src/cmd/re/r.gettc.c | 237 + src/cmd/re/r.macro.c | 190 + src/cmd/re/r.main.c | 466 + src/cmd/re/r.misc.c | 214 + src/cmd/re/r.termcap.c | 248 + src/cmd/re/r.ttyio.c | 419 + src/cmd/re/r.window.c | 400 + src/cmd/reboot/Makefile | 47 + src/cmd/reboot/reboot.8 | 133 + src/cmd/reboot/reboot.c | 181 + src/cmd/reloc/Makefile | 12 + src/cmd/reloc/reloc.1 | 71 + src/cmd/reloc/reloc.c | 668 + src/cmd/renice/Makefile | 42 + src/cmd/renice/renice.8 | 75 + src/cmd/renice/renice.c | 89 + src/cmd/retroforth/LICENSE | 30 + src/cmd/retroforth/Makefile | 29 + src/cmd/retroforth/NOTES | 48 + src/cmd/retroforth/README | 43 + .../doc/An_Introduction_to_Retro.rst | 1199 + src/cmd/retroforth/doc/Coding_Style.rst | 129 + src/cmd/retroforth/doc/Commentary.txt | 2009 + src/cmd/retroforth/doc/Core_Functions.rst | 741 + src/cmd/retroforth/doc/Implementations.rst | 148 + .../doc/The_Ngaro_Virtual_Machine.rst | 1082 + src/cmd/retroforth/doc/default.css | 216 + src/cmd/retroforth/doc/quickref.rst | 211 + src/cmd/retroforth/doc/retro.1 | 78 + src/cmd/retroforth/examples/Makefile | 11 + src/cmd/retroforth/examples/autopsy.rx | 517 + .../examples/casket/corpse/Makefile | 18 + .../retroforth/examples/casket/corpse/NOTES | 68 + .../examples/casket/corpse/corpse.rx | 135 + .../casket/corpse/templates/corpse.css | 11 + .../casket/corpse/templates/discuss.erx | 13 + .../casket/corpse/templates/footer.html | 5 + .../casket/corpse/templates/header.html | 10 + .../examples/casket/corpse/templates/rss | 7 + .../examples/casket/incision/Makefile | 20 + .../examples/casket/incision/current | 1 + .../examples/casket/incision/cuts/0 | 5 + .../examples/casket/incision/incision.rx | 55 + .../casket/incision/templates/footer.erx | 2 + .../casket/incision/templates/header.erx | 9 + .../casket/incision/templates/incision.css | 11 + .../casket/incision/templates/index.erx | 4 + .../examples/casket/rancid/Makefile | 18 + .../examples/casket/rancid/rancid.rx | 81 + .../casket/rancid/templates/default.erx | 90 + .../casket/rancid/templates/footer.html | 4 + .../casket/rancid/templates/header.html | 81 + .../casket/rancid/templates/rancid.css | 199 + .../casket/rancid/templates/script.erx | 39 + .../examples/casket/unwell/Makefile | 18 + .../examples/casket/unwell/autopsy.rx | 193 + .../examples/casket/unwell/templates/css | 7 + .../examples/casket/unwell/templates/eval.erx | 11 + .../casket/unwell/templates/examine.erx | 14 + .../casket/unwell/templates/footer.html | 10 + .../casket/unwell/templates/header.html | 12 + .../casket/unwell/templates/trace.erx | 14 + .../examples/casket/unwell/unwell.rx | 197 + src/cmd/retroforth/examples/editor.rx | 293 + src/cmd/retroforth/examples/games/chess.rx | 87 + .../examples/games/cloak-of-darkness.rx | 267 + .../examples/games/hangman/dict.retro | 49 + .../examples/games/hangman/graphics.retro | 41 + .../retroforth/examples/games/hangman/hangman | 14 + .../examples/games/hangman/hangman.retro | 110 + src/cmd/retroforth/examples/games/life.rx | 95 + src/cmd/retroforth/examples/games/maze.rx | 79 + src/cmd/retroforth/examples/games/spots.rx | 4 + .../retroforth/examples/games/tic-tac-toe.rx | 40 + src/cmd/retroforth/examples/langs/Makefile | 13 + .../retroforth/examples/langs/assembler.rx | 170 + src/cmd/retroforth/examples/langs/basic.rx | 284 + src/cmd/retroforth/examples/langs/bf.rx | 74 + .../examples/langs/examples/hello.bf | 9 + .../examples/langs/examples/squares.bf | 10 + .../examples/master_theorem/8-bit_classics.rx | 13 + .../masters_of_many_theorems.rx | 26 + .../examples/master_theorem/murder_at_sea.rx | 48 + .../examples/master_theorem/my_star_chart.rx | 63 + .../examples/master_theorem/prison_life.rx | 18 + .../examples/master_theorem/synesthesia.rx | 183 + .../what_i_do_in_my_basement.rx | 63 + .../master_theorem/words_words_words_2.rx | 23 + src/cmd/retroforth/examples/misc/bmi.rx | 23 + src/cmd/retroforth/examples/misc/draw.rx | 44 + .../examples/rosetta_code/100_doors.rx | 4 + .../rosetta_code/1d-cellular-automota.rx | 38 + .../rosetta_code/99_bottles_of_beer.rx | 16 + .../retroforth/examples/rosetta_code/README | 16 + .../examples/rosetta_code/a_plus_b.rx | 1 + .../rosetta_code/accumulator_factory.rx | 11 + .../rosetta_code/address_of_a_variable.rx | 7 + .../apply_a_callback_to_an_array.rx | 8 + .../rosetta_code/arithmetic_integer.rx | 8 + .../examples/rosetta_code/binary_digits.rx | 2 + .../rosetta_code/bitwise_operations.rx | 11 + .../rosetta_code/boolean_functions.rx | 2 + .../examples/rosetta_code/character_codes.rx | 1 + .../rosetta_code/character_matching.rx | 14 + .../examples/rosetta_code/comments.rx | 2 + .../rosetta_code/conditional_structures.rx | 9 + .../rosetta_code/conways_game_of_life.rx | 78 + .../examples/rosetta_code/copy_a_string.rx | 1 + .../rosetta_code/counting_in_octal.rx | 3 + .../examples/rosetta_code/create_a_file.rx | 3 + .../rosetta_code/create_an_html_table.rx | 16 + .../rosetta_code/define_a_primitive_type.rx | 17 + .../examples/rosetta_code/delete_a_file.rx | 3 + .../determine_if_a_string_is_numeric.rx | 3 + .../examples/rosetta_code/documentation.rx | 20 + .../rosetta_code/dynamic_variable_names.rx | 11 + .../examples/rosetta_code/empty_program.rx | 7 + .../examples/rosetta_code/empty_string.rx | 23 + .../rosetta_code/environment_variables.rx | 2 + .../rosetta_code/execute_brainf___.rx | 155 + .../rosetta_code/exponentiaion_operator.rx | 9 + .../rosetta_code/extend_your_language.rx | 18 + .../examples/rosetta_code/factorial.rx | 4 + .../rosetta_code/fibonacci_sequence.rx | 11 + .../examples/rosetta_code/file_io.rx | 2 + .../examples/rosetta_code/file_size.rx | 22 + .../rosetta_code/find_limit_of_recursion.rx | 4 + .../examples/rosetta_code/fizzbuzz.rx | 16 + .../rosetta_code/function_definition.rx | 1 + .../rosetta_code/greatest_common_divisor.rx | 3 + .../examples/rosetta_code/guess_the_number.rx | 12 + .../guess_the_number_with_feedback.rx | 16 + .../retroforth/examples/rosetta_code/hanoi.rx | 14 + .../hello_world_standard_error.rx | 1 + .../examples/rosetta_code/hello_world_text.rx | 1 + .../increment_a_numerical_string.rx | 1 + .../rosetta_code/integer_comparison.rx | 15 + .../examples/rosetta_code/integer_sequence.rx | 1 + .../rosetta_code/interactive_programming.rx | 6 + .../examples/rosetta_code/leap_year.rx | 5 + .../rosetta_code/least_common_multiple.rx | 4 + .../examples/rosetta_code/literals_integer.rx | 9 + .../examples/rosetta_code/literals_string.rx | 5 + .../rosetta_code/loops_downward_for.rx | 2 + .../examples/rosetta_code/loops_for.rx | 2 + .../examples/rosetta_code/loops_infinite.rx | 2 + .../examples/rosetta_code/loops_while.rx | 2 + .../rosetta_code/memory_allocation.rx | 19 + .../examples/rosetta_code/mouse_position.rx | 4 + .../rosetta_code/palindrome_detection.rx | 5 + .../examples/rosetta_code/pangram_checker.rx | 5 + .../rosetta_code/program_termination.rx | 2 + .../examples/rosetta_code/read_entire_file.rx | 2 + .../examples/rosetta_code/repeat_a_string.rx | 5 + .../examples/rosetta_code/reverse_a_string.rx | 2 + .../examples/rosetta_code/roman_numerals.rx | 28 + .../examples/rosetta_code/rot-13.rx | 11 + .../examples/rosetta_code/shell_one-liner.rx | 2 + .../singly_linked_list_transversal.rx | 9 + .../retroforth/examples/rosetta_code/sleep.rx | 9 + .../retroforth/examples/rosetta_code/stack.rx | 15 + .../examples/rosetta_code/string_case.rx | 3 + .../rosetta_code/string_concatenation.rx | 2 + .../examples/rosetta_code/string_length.rx | 23 + .../examples/rosetta_code/system_time.rx | 3 + .../terminal_control_clear_the_screen.rx | 2 + ...height_and_width_of_the_terminal_window.rx | 5 + ...or_to_a_specific_location_on_the_screen.rx | 2 + ...minal_control_ringing_the_terminal_bell.rx | 1 + .../examples/rosetta_code/time_a_function.rx | 9 + .../rosetta_code/tokenize_a_string.rx | 22 + .../rosetta_code/unicode_variable_names.rx | 8 + .../examples/rosetta_code/user_input_text.rx | 6 + src/cmd/retroforth/examples/util/cat.rx | 2 + .../retroforth/examples/util/extract-doc.rx | 20 + src/cmd/retroforth/examples/util/grep.rx | 29 + src/cmd/retroforth/examples/util/head.rx | 8 + src/cmd/retroforth/examples/util/wc.rx | 28 + src/cmd/retroforth/image/kernel.rx | 826 + src/cmd/retroforth/image/meta-alt.rx | 88 + src/cmd/retroforth/image/meta.rx | 87 + src/cmd/retroforth/library/array.rx | 177 + src/cmd/retroforth/library/assertion.rx | 178 + src/cmd/retroforth/library/bad.rx | 128 + src/cmd/retroforth/library/bstrings.rx | 130 + src/cmd/retroforth/library/calendar.rx | 114 + src/cmd/retroforth/library/canvas.rx | 137 + src/cmd/retroforth/library/casket.rx | 236 + src/cmd/retroforth/library/char.rx | 72 + src/cmd/retroforth/library/combinators.rx | 68 + src/cmd/retroforth/library/console.rx | 76 + src/cmd/retroforth/library/crypto.rx | 156 + src/cmd/retroforth/library/decompose.rx | 107 + src/cmd/retroforth/library/decorator.rx | 60 + src/cmd/retroforth/library/dissect.rx | 75 + src/cmd/retroforth/library/enum.rx | 56 + src/cmd/retroforth/library/eval.rx | 98 + src/cmd/retroforth/library/forth.rx | 186 + src/cmd/retroforth/library/hash.rx | 93 + src/cmd/retroforth/library/infix.rx | 75 + src/cmd/retroforth/library/linkedList.rx | 111 + src/cmd/retroforth/library/locals.rx | 88 + src/cmd/retroforth/library/math.rx | 47 + src/cmd/retroforth/library/stack.rx | 90 + src/cmd/retroforth/library/struct.rx | 83 + src/cmd/retroforth/library/values.rx | 75 + src/cmd/retroforth/library/variations.rx | 32 + src/cmd/retroforth/retro.c | 704 + src/cmd/retroforth/retroImage | Bin 0 -> 38228 bytes src/cmd/retroforth/test/core.rx | 1122 + src/cmd/retroforth/test/io/output.txt | 5 + src/cmd/retroforth/test/io_files.rx | 141 + src/cmd/retroforth/test/io_output.rx | 48 + src/cmd/retroforth/test/library/array.rx | 97 + src/cmd/retroforth/test/library/bad.rx | 44 + src/cmd/retroforth/test/library/bstrings.rx | 43 + src/cmd/retroforth/test/library/char.rx | 65 + src/cmd/retroforth/test/library/decorator.rx | 23 + src/cmd/retroforth/test/library/enum.rx | 37 + src/cmd/retroforth/test/library/hash.rx | 29 + src/cmd/retroforth/test/library/infix.rx | 39 + src/cmd/retroforth/test/library/locals.rx | 24 + src/cmd/retroforth/test/library/math.rx | 30 + src/cmd/retroforth/test/library/stack.rx | 67 + src/cmd/retroforth/test/library/struct.rx | 42 + src/cmd/retroforth/test/library/values.rx | 32 + src/cmd/retroforth/test/vocabs.rx | 168 + src/cmd/retroforth/tools/convert.c | 103 + src/cmd/retroforth/tools/tweakterm.c | 69 + src/cmd/rev.c | 46 + src/cmd/rm.c | 259 + src/cmd/rmail.c | 120 + src/cmd/rmdir.c | 30 + src/cmd/scm/Makefile | 35 + src/cmd/scm/Syntax.txt | 75 + src/cmd/scm/TODO.txt | 138 + src/cmd/scm/examples/prime.scm | 29 + src/cmd/scm/func.c | 1009 + src/cmd/scm/scm.c | 1409 + src/cmd/scm/scm.h | 230 + src/cmd/scm/tests/apply.expected | 12 + src/cmd/scm/tests/apply.scm | 8 + src/cmd/scm/tests/cxr.expected | 31 + src/cmd/scm/tests/cxr.scm | 34 + src/cmd/scm/tests/define.expected | 11 + src/cmd/scm/tests/define.scm | 11 + src/cmd/scm/tests/flo.expected | 28 + src/cmd/scm/tests/flo.scm | 32 + src/cmd/scm/tests/int.expected | 64 + src/cmd/scm/tests/int.scm | 67 + src/cmd/scm/tests/list.expected | 20 + src/cmd/scm/tests/list.scm | 20 + src/cmd/scm/tests/member.expected | 13 + src/cmd/scm/tests/member.scm | 14 + src/cmd/scm/tests/quote.expected | 12 + src/cmd/scm/tests/quote.scm | 12 + src/cmd/scm/tests/string.expected | 20 + src/cmd/scm/tests/string.scm | 21 + src/cmd/scm/tests/t.expected | 20 + src/cmd/scm/tests/t.scm | 21 + src/cmd/sed/Makefile | 24 + src/cmd/sed/sed.h | 161 + src/cmd/sed/sed0.c | 975 + src/cmd/sed/sed1.c | 718 + src/cmd/setty/Makefile | 27 + src/cmd/setty/setty.c | 104 + src/cmd/sh/Makefile | 42 + src/cmd/sh/args.c | 306 + src/cmd/sh/blok.c | 187 + src/cmd/sh/brkincr.h | 2 + src/cmd/sh/cmd.c | 560 + src/cmd/sh/ctype.c | 233 + src/cmd/sh/ctype.h | 95 + src/cmd/sh/defs.c | 76 + src/cmd/sh/defs.h | 358 + src/cmd/sh/dup.h | 8 + src/cmd/sh/echo.c | 88 + src/cmd/sh/error.c | 96 + src/cmd/sh/expand.c | 356 + src/cmd/sh/fault.c | 203 + src/cmd/sh/func.c | 380 + src/cmd/sh/hash.c | 144 + src/cmd/sh/hash.h | 34 + src/cmd/sh/hashserv.c | 467 + src/cmd/sh/io.c | 313 + src/cmd/sh/mac.h | 26 + src/cmd/sh/macro.c | 340 + src/cmd/sh/main.c | 411 + src/cmd/sh/mode.h | 202 + src/cmd/sh/msg.c | 192 + src/cmd/sh/name.c | 591 + src/cmd/sh/name.h | 22 + src/cmd/sh/print.c | 250 + src/cmd/sh/profile.c | 32 + src/cmd/sh/pushd | 72 + src/cmd/sh/pwd.c | 284 + src/cmd/sh/service.c | 677 + src/cmd/sh/setbrk.c | 18 + src/cmd/sh/stak.c | 82 + src/cmd/sh/stak.h | 73 + src/cmd/sh/string.c | 60 + src/cmd/sh/sym.h | 45 + src/cmd/sh/test.c | 247 + src/cmd/sh/timeout.h | 7 + src/cmd/sh/trace.c | 32 + src/cmd/sh/word.c | 243 + src/cmd/sh/xec.c | 877 + src/cmd/shutdown/Makefile | 43 + src/cmd/shutdown/shutdown.8 | 112 + src/cmd/shutdown/shutdown.c | 392 + src/cmd/size.c | 67 + src/cmd/sl/Makefile | 27 + src/cmd/sl/README | 12 + src/cmd/sl/sl.1 | 34 + src/cmd/sl/sl.c | 225 + src/cmd/sl/sl.h | 104 + src/cmd/sl/sl.txt | 23 + src/cmd/sleep.c | 24 + src/cmd/smallc/6809/ccstart.u | 25 + src/cmd/smallc/6809/crunas09.u | 85 + src/cmd/smallc/6809/exit.u | 3 + src/cmd/smallc/6809/faults.u | 10 + src/cmd/smallc/6809/io.u | 28 + src/cmd/smallc/6809/mrabs.u | 26 + src/cmd/smallc/6809/prabs.u | 27 + src/cmd/smallc/6809/sdiv.u | 55 + src/cmd/smallc/6809/shift.u | 32 + src/cmd/smallc/6809/smod.u | 54 + src/cmd/smallc/6809/sumul.u | 32 + src/cmd/smallc/8080/Makefile | 8 + src/cmd/smallc/8080/arglist.c | 34 + src/cmd/smallc/8080/bdos.c | 18 + src/cmd/smallc/8080/bdos1.c | 5 + src/cmd/smallc/8080/chio8080.c | 12 + src/cmd/smallc/8080/cret.asm | 27 + src/cmd/smallc/8080/crun.asm | 352 + src/cmd/smallc/8080/exit.c | 6 + src/cmd/smallc/8080/inout.c | 28 + src/cmd/smallc/8080/io8080.c | 305 + src/cmd/smallc/Makefile | 46 + src/cmd/smallc/README | 98 + src/cmd/smallc/code8080.c | 752 + src/cmd/smallc/codeas09.c | 671 + src/cmd/smallc/codem68k.c | 722 + src/cmd/smallc/codemips.c | 824 + src/cmd/smallc/codevax.c | 704 + src/cmd/smallc/data.c | 47 + src/cmd/smallc/data.h | 44 + src/cmd/smallc/defs.h | 262 + src/cmd/smallc/error.c | 45 + src/cmd/smallc/expr.c | 730 + src/cmd/smallc/function.c | 194 + src/cmd/smallc/gen.c | 163 + src/cmd/smallc/includes/ctype.h | 1 + src/cmd/smallc/includes/hello.c | 4 + src/cmd/smallc/includes/stdio.h | 6 + src/cmd/smallc/initialise.c | 103 + src/cmd/smallc/io.c | 94 + src/cmd/smallc/lex.c | 228 + src/cmd/smallc/lib/Makefile | 34 + src/cmd/smallc/lib/abs.c | 5 + src/cmd/smallc/lib/atoi.c | 21 + src/cmd/smallc/lib/binary.c | 22 + src/cmd/smallc/lib/charclass.c | 33 + src/cmd/smallc/lib/fgets.c | 27 + src/cmd/smallc/lib/fputs.c | 7 + src/cmd/smallc/lib/getchar.c | 5 + src/cmd/smallc/lib/gets.c | 28 + src/cmd/smallc/lib/index.c | 18 + src/cmd/smallc/lib/itoa.c | 14 + src/cmd/smallc/lib/lorder8080 | 12 + src/cmd/smallc/lib/printn.c | 16 + src/cmd/smallc/lib/putchar.c | 5 + src/cmd/smallc/lib/puts.c | 6 + src/cmd/smallc/lib/rand.c | 20 + src/cmd/smallc/lib/reverse.c | 17 + src/cmd/smallc/lib/sbrk.c | 17 + src/cmd/smallc/lib/shell.c | 21 + src/cmd/smallc/lib/strcat.c | 20 + src/cmd/smallc/lib/strcmp.c | 13 + src/cmd/smallc/lib/strcpy.c | 18 + src/cmd/smallc/lib/strlen.c | 8 + src/cmd/smallc/lib/strncat.c | 25 + src/cmd/smallc/lib/strncmp.c | 16 + src/cmd/smallc/lib/strncpy.c | 23 + src/cmd/smallc/main.c | 314 + src/cmd/smallc/preproc.c | 291 + src/cmd/smallc/primary.c | 332 + src/cmd/smallc/stmt.c | 406 + src/cmd/smallc/sym.c | 345 + src/cmd/smallc/vax/B2test.c | 31 + src/cmd/smallc/vax/Makefile | 11 + src/cmd/smallc/vax/b2test.dat | 2 + src/cmd/smallc/vax/chiovax.c | 51 + src/cmd/smallc/vax/crt0.c | 34 + src/cmd/smallc/vax/crt0.s | 61 + src/cmd/smallc/vax/crunvax.c | 90 + src/cmd/smallc/vax/iovax.c | 129 + src/cmd/smallc/vax/optest.c | 103 + src/cmd/smallc/vax/vscc | 9 + src/cmd/smallc/while.c | 70 + src/cmd/smlrc/Makefile | 30 + src/cmd/smlrc/cgmips.c | 1610 + src/cmd/smlrc/cgx86.c | 3221 ++ src/cmd/smlrc/lb.c | 1399 + src/cmd/smlrc/license.txt | 26 + src/cmd/smlrc/readme.txt | 20 + src/cmd/smlrc/smlrc.c | 7385 ++++ src/cmd/smux/Makefile | 10 + src/cmd/smux/common/packet.h | 45 + src/cmd/smux/linux/Makefile | 9 + src/cmd/smux/linux/smux.c | 469 + src/cmd/smux/retro/Makefile | 34 + src/cmd/smux/retro/smux.c | 232 + src/cmd/sort.c | 911 + src/cmd/split.c | 82 + src/cmd/sre/HISTORY | 45 + src/cmd/sre/Makefile | 13 + src/cmd/sre/cmd.c | 2848 ++ src/cmd/sre/edit.h | 155 + src/cmd/sre/file.c | 422 + src/cmd/sre/init.c | 133 + src/cmd/sre/main.c | 572 + src/cmd/sre/misc.c | 168 + src/cmd/sre/render.c | 413 + src/cmd/sre/setup.c | 269 + src/cmd/sre/srch.c | 641 + src/cmd/sre/srerc_example | 2 + src/cmd/sre/tag.c | 175 + src/cmd/sre/tutorial | 206 + src/cmd/strip.c | 87 + src/cmd/stty/Makefile | 42 + src/cmd/stty/stty.1 | 409 + src/cmd/stty/stty.c | 520 + src/cmd/su.c | 176 + src/cmd/sum.c | 48 + src/cmd/sync.c | 5 + src/cmd/sysctl/Makefile | 42 + src/cmd/sysctl/sysctl.8 | 238 + src/cmd/sysctl/sysctl.c | 556 + src/cmd/tail.c | 232 + src/cmd/talloc/Makefile | 41 + src/cmd/talloc/talloc.1 | 0 src/cmd/talloc/talloc.c | 36 + src/cmd/tar.c | 1407 + src/cmd/tcl/Makefile | 46 + src/cmd/tcl/tclsh.c | 221 + src/cmd/tee.c | 95 + src/cmd/test/Makefile | 36 + src/cmd/test/TEST.csh | 153 + src/cmd/test/operators.c | 158 + src/cmd/test/operators.h | 73 + src/cmd/test/test.1 | 284 + src/cmd/test/test.c | 558 + src/cmd/time.c | 57 + src/cmd/tip/Makefile | 103 + src/cmd/tip/README | 61 + src/cmd/tip/TODO | 18 + src/cmd/tip/acu.c | 162 + src/cmd/tip/aculib/.depend | 552 + src/cmd/tip/aculib/Makefile | 53 + src/cmd/tip/aculib/biz22.c | 154 + src/cmd/tip/aculib/biz31.c | 212 + src/cmd/tip/aculib/courier.c | 353 + src/cmd/tip/aculib/df.c | 93 + src/cmd/tip/aculib/dn11.c | 106 + src/cmd/tip/aculib/hayes.c | 268 + src/cmd/tip/aculib/penril.c | 224 + src/cmd/tip/aculib/v3451.c | 179 + src/cmd/tip/aculib/v831.c | 226 + src/cmd/tip/aculib/ventel.c | 220 + src/cmd/tip/acutab.c | 64 + src/cmd/tip/cmds.c | 862 + src/cmd/tip/cmdtab.c | 32 + src/cmd/tip/cu.c | 101 + src/cmd/tip/hunt.c | 67 + src/cmd/tip/log.c | 56 + src/cmd/tip/m | 5 + src/cmd/tip/partab.c | 27 + src/cmd/tip/phones-file | 17 + src/cmd/tip/remcap.c | 394 + src/cmd/tip/remote-file | 104 + src/cmd/tip/remote.c | 160 + src/cmd/tip/tip.c | 568 + src/cmd/tip/tip.h | 266 + src/cmd/tip/tipout.c | 120 + src/cmd/tip/uucplock.c | 199 + src/cmd/tip/value.c | 318 + src/cmd/tip/vars.c | 79 + src/cmd/touch.c | 121 + src/cmd/tr.c | 139 + src/cmd/true.sh | 1 + src/cmd/tsort.c | 207 + src/cmd/tty.c | 19 + src/cmd/umount/Makefile | 42 + src/cmd/umount/umount.8 | 115 + src/cmd/umount/umount.c | 299 + src/cmd/uname/Makefile | 42 + src/cmd/uname/uname.1 | 90 + src/cmd/uname/uname.c | 152 + src/cmd/uniq.c | 144 + src/cmd/unixbench/Makefile | 331 + src/cmd/unixbench/README | 303 + src/cmd/unixbench/Run | 320 + src/cmd/unixbench/pgms/cleanup.sh | 137 + src/cmd/unixbench/pgms/fs.awk | 71 + src/cmd/unixbench/pgms/index.awk | 19 + src/cmd/unixbench/pgms/index.base | 11 + src/cmd/unixbench/pgms/index.sh | 73 + src/cmd/unixbench/pgms/loopm.awk | 58 + src/cmd/unixbench/pgms/loops.awk | 55 + src/cmd/unixbench/pgms/lps.awk | 35 + src/cmd/unixbench/pgms/multi.sh | 23 + src/cmd/unixbench/pgms/mwips.awk | 35 + src/cmd/unixbench/pgms/perlbench | 357 + src/cmd/unixbench/pgms/report.awk | 25 + src/cmd/unixbench/pgms/report.sh | 38 + src/cmd/unixbench/pgms/select | Bin 0 -> 7564 bytes src/cmd/unixbench/pgms/tst.sh | 20 + src/cmd/unixbench/pgms/unixbench.logo | 15 + src/cmd/unixbench/results/log | 13 + src/cmd/unixbench/results/log.accum | 21 + src/cmd/unixbench/results/report | 18 + src/cmd/unixbench/results/times | 32 + src/cmd/unixbench/src/arith.c | 110 + src/cmd/unixbench/src/big.c | 591 + src/cmd/unixbench/src/context1.c | 111 + src/cmd/unixbench/src/dhry.h | 435 + src/cmd/unixbench/src/dhry_1.c | 431 + src/cmd/unixbench/src/dhry_2.c | 209 + src/cmd/unixbench/src/dummy.c | 319 + src/cmd/unixbench/src/execl.c | 95 + src/cmd/unixbench/src/fstime.c | 320 + src/cmd/unixbench/src/getopt.c | 99 + src/cmd/unixbench/src/hanoi.c | 77 + src/cmd/unixbench/src/limit.c | 164 + src/cmd/unixbench/src/looper.c | 100 + src/cmd/unixbench/src/pipe.c | 68 + src/cmd/unixbench/src/spawn.c | 80 + src/cmd/unixbench/src/syscall.c | 62 + src/cmd/unixbench/src/time-polling.c | 573 + src/cmd/unixbench/src/timeit.c | 41 + src/cmd/unixbench/src/whets.c | 1287 + src/cmd/unixbench/testdir/cctest.c | 153 + src/cmd/unixbench/testdir/dc.dat | 8 + src/cmd/unixbench/testdir/sort.src | 362 + src/cmd/unixbench/tmp/kill_run | 1 + src/cmd/update/Makefile | 41 + src/cmd/update/update.8 | 39 + src/cmd/update/update.c | 66 + src/cmd/uucp/CHANGES | 166 + src/cmd/uucp/Makefile | 142 + src/cmd/uucp/README | 216 + src/cmd/uucp/README.TCP | 56 + src/cmd/uucp/README.dialino | 28 + src/cmd/uucp/UUAIDS/L-devices | 63 + src/cmd/uucp/UUAIDS/L-dialcodes | 15 + src/cmd/uucp/UUAIDS/L.aliases | 19 + src/cmd/uucp/UUAIDS/L.cmds | 25 + src/cmd/uucp/UUAIDS/L.sys | 121 + src/cmd/uucp/UUAIDS/Notes.L.sys | 84 + src/cmd/uucp/UUAIDS/USERFILE | 12 + src/cmd/uucp/UUAIDS/setup.tblms | 269 + src/cmd/uucp/UUAIDS/uu.daily | 33 + src/cmd/uucp/UUAIDS/uu.daily.seism | 36 + src/cmd/uucp/UUAIDS/uu.hourly | 10 + src/cmd/uucp/UUAIDS/uu.weekly | 4 + src/cmd/uucp/UUAIDS/uucp.daily | 89 + src/cmd/uucp/UUAIDS/uucpsrv.c | 41 + src/cmd/uucp/UUAIDS/uucpsummary | 240 + src/cmd/uucp/UUAIDS/uucpsummary.mo | 130 + src/cmd/uucp/UUAIDS/uurate | 37 + src/cmd/uucp/UUAIDS/uutbl | 42 + src/cmd/uucp/UUAIDS/uuusage | 272 + src/cmd/uucp/acucntrl.8 | 132 + src/cmd/uucp/acucntrl.c | 774 + src/cmd/uucp/aculib/Makefile | 22 + src/cmd/uucp/aculib/att2224.c | 156 + src/cmd/uucp/aculib/bsdtcp.c | 96 + src/cmd/uucp/aculib/cds224.c | 110 + src/cmd/uucp/aculib/df12.c | 156 + src/cmd/uucp/aculib/df2.c | 146 + src/cmd/uucp/aculib/dk.c | 42 + src/cmd/uucp/aculib/dn.c | 144 + src/cmd/uucp/aculib/hys.c | 191 + src/cmd/uucp/aculib/hys24.c | 126 + src/cmd/uucp/aculib/hysq.c | 159 + src/cmd/uucp/aculib/mic.c | 110 + src/cmd/uucp/aculib/nov.c | 122 + src/cmd/uucp/aculib/pen.c | 103 + src/cmd/uucp/aculib/pnet.c | 47 + src/cmd/uucp/aculib/rvmacs.c | 183 + src/cmd/uucp/aculib/sy.c | 163 + src/cmd/uucp/aculib/unet.c | 66 + src/cmd/uucp/aculib/va212.c | 126 + src/cmd/uucp/aculib/va811.c | 123 + src/cmd/uucp/aculib/va820.c | 167 + src/cmd/uucp/aculib/vad.c | 132 + src/cmd/uucp/aculib/vent.c | 100 + src/cmd/uucp/aculib/vmacs.c | 168 + src/cmd/uucp/anlwrk.c | 362 + src/cmd/uucp/anyread.c | 25 + src/cmd/uucp/assert.c | 51 + src/cmd/uucp/cfgets.c | 61 + src/cmd/uucp/chkpth.c | 250 + src/cmd/uucp/chksum.c | 56 + src/cmd/uucp/cico.c | 896 + src/cmd/uucp/cntrl.c | 942 + src/cmd/uucp/condevs.c | 564 + src/cmd/uucp/condevs.h | 114 + src/cmd/uucp/conn.c | 1143 + src/cmd/uucp/cpmv.c | 72 + src/cmd/uucp/expfile.c | 128 + src/cmd/uucp/fio.c | 549 + src/cmd/uucp/gename.c | 86 + src/cmd/uucp/getargs.c | 98 + src/cmd/uucp/getprm.c | 68 + src/cmd/uucp/getpwinfo.c | 67 + src/cmd/uucp/gio.c | 236 + src/cmd/uucp/gnamef.c | 41 + src/cmd/uucp/gnsys.c | 137 + src/cmd/uucp/gnxseq.c | 122 + src/cmd/uucp/imsg.c | 101 + src/cmd/uucp/lastpart.c | 27 + src/cmd/uucp/logent.c | 235 + src/cmd/uucp/mailst.c | 105 + src/cmd/uucp/pk.h | 128 + src/cmd/uucp/pk0.c | 573 + src/cmd/uucp/pk1.c | 431 + src/cmd/uucp/prefix.c | 41 + src/cmd/uucp/setline.c | 50 + src/cmd/uucp/subdir.c | 108 + src/cmd/uucp/sysacct.c | 19 + src/cmd/uucp/systat.c | 149 + src/cmd/uucp/tio.c | 264 + src/cmd/uucp/ulockf.c | 197 + src/cmd/uucp/uuclean.c | 231 + src/cmd/uucp/uucp.c | 468 + src/cmd/uucp/uucp.h | 424 + src/cmd/uucp/uucpd.c | 303 + src/cmd/uucp/uucpdefs.c | 31 + src/cmd/uucp/uucpname.c | 227 + src/cmd/uucp/uudecode.c | 175 + src/cmd/uucp/uuencode.c | 110 + src/cmd/uucp/uulog.c | 94 + src/cmd/uucp/uuname.c | 78 + src/cmd/uucp/uupoll.c | 79 + src/cmd/uucp/uuq.c | 379 + src/cmd/uucp/uusend.c | 357 + src/cmd/uucp/uusnap.c | 285 + src/cmd/uucp/uust.h | 8 + src/cmd/uucp/uusub.h | 4 + src/cmd/uucp/uux.c | 549 + src/cmd/uucp/uuxqt.c | 718 + src/cmd/uucp/versys.c | 114 + src/cmd/uucp/vms.tar.Z | Bin 0 -> 36070 bytes src/cmd/uucp/xqt.c | 112 + src/cmd/vipw/Makefile | 55 + src/cmd/vipw/vipw.8 | 53 + src/cmd/vipw/vipw.c | 267 + src/cmd/virus/Makefile | 15 + src/cmd/virus/lib/last_char_is.c | 39 + src/cmd/virus/lib/strlcat.c | 73 + src/cmd/virus/lib/strlcpy.3 | 190 + src/cmd/virus/lib/strlcpy.c | 69 + src/cmd/virus/virus.c | 4002 ++ src/cmd/vmstat.c | 444 + src/cmd/w.c | 593 + src/cmd/wall.c | 141 + src/cmd/wc.c | 109 + src/cmd/whereis.c | 293 + src/cmd/who.c | 80 + src/cmd/wiznet/Makefile | 49 + src/cmd/wiznet/chat-server.c | 50 + src/cmd/wiznet/ntpdate.c | 142 + src/cmd/wiznet/telnet.c | 290 + .../todo/barometric-pressure-web-server.c | 225 + src/cmd/wiznet/todo/pachube-client-string.c | 124 + src/cmd/wiznet/todo/pachube-client.c | 139 + src/cmd/wiznet/todo/udp-send-receive-string.c | 109 + src/cmd/wiznet/web-client.c | 73 + src/cmd/wiznet/web-server.c | 82 + src/cmd/write.c | 240 + src/cmd/xargs/Makefile | 39 + src/cmd/xargs/xargs.1 | 169 + src/cmd/xargs/xargs.c | 323 + src/cmd/yacc/Makefile | 24 + src/cmd/yacc/dextern | 262 + src/cmd/yacc/files | 20 + src/cmd/yacc/y1.c | 658 + src/cmd/yacc/y2.c | 866 + src/cmd/yacc/y3.c | 413 + src/cmd/yacc/y4.c | 329 + src/cmd/yacc/yaccdiffs | 198 + src/cmd/yacc/yaccnews | 149 + src/cmd/yacc/yaccpar | 153 + src/cmd/zmodem/Makefile | 53 + src/cmd/zmodem/crc.1 | 32 + src/cmd/zmodem/crc.c | 160 + src/cmd/zmodem/crctab.c | 140 + src/cmd/zmodem/genie.c | 111 + src/cmd/zmodem/makefile.generic | 126 + src/cmd/zmodem/minirb.1 | 53 + src/cmd/zmodem/minirb.c | 175 + src/cmd/zmodem/ptest.sh | 4 + src/cmd/zmodem/rbsb.c | 340 + src/cmd/zmodem/rz.1 | 360 + src/cmd/zmodem/rz.c | 1532 + src/cmd/zmodem/sz.1 | 487 + src/cmd/zmodem/sz.c | 2052 + src/cmd/zmodem/vmodem.h | 43 + src/cmd/zmodem/vrzsz.c | 254 + src/cmd/zmodem/vupl.t | 18 + src/cmd/zmodem/vuplfile.t | 13 + src/cmd/zmodem/vvmodem.c | 273 + src/cmd/zmodem/zm.c | 917 + src/cmd/zmodem/zmodem.h | 135 + src/cmd/zmodem/zmr.c | 185 + src/cmd/zmodem/zupl.t | 26 + src/elf32-mips.ld | 253 + src/games/Makefile | 89 + src/games/adventure/Makefile | 35 + src/games/adventure/adventure.6 | 21 + src/games/adventure/adventure.dat | Bin 0 -> 72040 bytes src/games/adventure/done.c | 99 + src/games/adventure/glorkz | 1813 + src/games/adventure/glorkz-ru | 1815 + src/games/adventure/hdr.h | 325 + src/games/adventure/init.c | 150 + src/games/adventure/io.c | 487 + src/games/adventure/main.c | 549 + src/games/adventure/save.c | 95 + src/games/adventure/subr.c | 801 + src/games/adventure/vocab.c | 202 + src/games/adventure/wizard.c | 105 + src/games/arithmetic.6 | 56 + src/games/arithmetic.c | 227 + src/games/atc/BUGS | 4 + src/games/atc/Makefile | 30 + src/games/atc/def.h | 42 + src/games/atc/extern.c | 36 + src/games/atc/extern.h | 24 + src/games/atc/games/ATC_scores | 5 + src/games/atc/games/Game_List | 5 + src/games/atc/games/Killer | 21 + src/games/atc/games/crossover | 14 + src/games/atc/games/default | 21 + src/games/atc/games/easy | 15 + src/games/atc/games/game_2 | 22 + src/games/atc/grammar.y | 349 + src/games/atc/graphics.c | 378 + src/games/atc/include.h | 50 + src/games/atc/input.c | 626 + src/games/atc/lex.l | 28 + src/games/atc/list.c | 75 + src/games/atc/log.c | 213 + src/games/atc/main.c | 279 + src/games/atc/struct.h | 73 + src/games/atc/tunable.c | 24 + src/games/atc/tunable.h | 12 + src/games/atc/update.c | 365 + src/games/backgammon/Makefile | 46 + src/games/backgammon/allow.c | 79 + src/games/backgammon/back.h | 148 + src/games/backgammon/backgammon.6 | 11 + src/games/backgammon/backgammon.src | 195 + src/games/backgammon/board.c | 149 + src/games/backgammon/check.c | 128 + src/games/backgammon/data.c | 283 + src/games/backgammon/extra.c | 228 + src/games/backgammon/fancy.c | 729 + src/games/backgammon/init.c | 33 + src/games/backgammon/main.c | 559 + src/games/backgammon/message.c | 9 + src/games/backgammon/move.c | 538 + src/games/backgammon/odds.c | 84 + src/games/backgammon/one.c | 139 + src/games/backgammon/save.c | 148 + src/games/backgammon/subs.c | 475 + src/games/backgammon/table.c | 276 + src/games/backgammon/teach.c | 126 + src/games/backgammon/text.c | 100 + src/games/backgammon/ttext1.c | 152 + src/games/backgammon/ttext2.c | 160 + src/games/backgammon/tutor.c | 127 + src/games/backgammon/tutor.h | 16 + src/games/banner.6 | 45 + src/games/banner.c | 923 + src/games/battlestar/Makefile | 43 + src/games/battlestar/Makefile-linux | 23 + src/games/battlestar/battlestar.6 | 140 + src/games/battlestar/battlestar.c | 59 + src/games/battlestar/cmd1.c | 236 + src/games/battlestar/cmd2.c | 271 + src/games/battlestar/cmd3.c | 285 + src/games/battlestar/cmd4.c | 350 + src/games/battlestar/cmd5.c | 297 + src/games/battlestar/cmd6.c | 188 + src/games/battlestar/cmd7.c | 237 + src/games/battlestar/curses.c | 637 + src/games/battlestar/cypher.c | 400 + src/games/battlestar/dayfile.c | 1175 + src/games/battlestar/dayobjs.c | 106 + src/games/battlestar/doprnt.c | 203 + src/games/battlestar/externs.h | 339 + src/games/battlestar/fly.c | 257 + src/games/battlestar/getcom.c | 67 + src/games/battlestar/globals.c | 193 + src/games/battlestar/init.c | 102 + src/games/battlestar/misc.c | 32 + src/games/battlestar/mkstr.c | 284 + src/games/battlestar/nightfile.c | 1147 + src/games/battlestar/nightobjs.c | 68 + src/games/battlestar/parse.c | 73 + src/games/battlestar/room.c | 276 + src/games/battlestar/save.c | 117 + src/games/battlestar/words.c | 174 + src/games/bcd.6 | 18 + src/games/bcd.c | 151 + src/games/boggle/Makefile | 32 + src/games/boggle/boggle.6 | 49 + src/games/boggle/boggle.c | 652 + src/games/boggle/comp.c | 37 + src/games/boggle/inst | 42 + src/games/boggle/sfile | 10 + src/games/btlgammon/Makefile | 36 + src/games/btlgammon/backrules | 19 + src/games/btlgammon/btlgammon.c | 717 + src/games/canfield.6 | 91 + src/games/canfield.c | 1637 + src/games/cfscores.c | 114 + src/games/cribbage/Makefile | 51 + src/games/cribbage/_ctfix | 3 + src/games/cribbage/cards.c | 134 + src/games/cribbage/crib.c | 587 + src/games/cribbage/cribbage.6 | 102 + src/games/cribbage/cribbage.h | 34 + src/games/cribbage/cribbage.n | 318 + src/games/cribbage/cribcur.h | 30 + src/games/cribbage/deck.h | 58 + src/games/cribbage/extern.c | 40 + src/games/cribbage/io.c | 575 + src/games/cribbage/macro | 126 + src/games/cribbage/score.c | 337 + src/games/cribbage/support.c | 330 + src/games/cribbage/test.c | 131 + src/games/factor.c | 100 + src/games/fish.6 | 35 + src/games/fish.c | 559 + src/games/fortune/Do_troff | 4 + src/games/fortune/Makefile | 72 + src/games/fortune/Troff.mac | 26 + src/games/fortune/Troff.sed | 13 + src/games/fortune/fortune.6 | 54 + src/games/fortune/fortune.c | 237 + src/games/fortune/notes | 140 + src/games/fortune/obscene | 10500 +++++ src/games/fortune/obscene.4.3 | 1499 + src/games/fortune/obscene.sp.ok | 238 + src/games/fortune/rnd.c | 365 + src/games/fortune/scene | 35245 ++++++++++++++++ src/games/fortune/scene.4.3 | 9761 +++++ src/games/fortune/scene.sp.ok | 1175 + src/games/fortune/strfile.c | 394 + src/games/fortune/strfile.h | 20 + src/games/fortune/unstr.c | 127 + src/games/hangman/Makefile | 22 + src/games/hangman/endgame.c | 36 + src/games/hangman/extern.c | 37 + src/games/hangman/getguess.c | 70 + src/games/hangman/getword.c | 55 + src/games/hangman/hangman.6 | 23 + src/games/hangman/hangman.h | 46 + src/games/hangman/main.c | 29 + src/games/hangman/playgame.c | 23 + src/games/hangman/prdata.c | 21 + src/games/hangman/prman.c | 18 + src/games/hangman/prword.c | 12 + src/games/hangman/setup.c | 35 + src/games/hunt/Makefile | 127 + src/games/hunt/README | 9 + src/games/hunt/answer.c | 359 + src/games/hunt/connect.c | 28 + src/games/hunt/draw.c | 388 + src/games/hunt/driver.c | 671 + src/games/hunt/execute.c | 497 + src/games/hunt/expl.c | 198 + src/games/hunt/extern.c | 45 + src/games/hunt/hunt.6 | 266 + src/games/hunt/hunt.c | 717 + src/games/hunt/hunt.h | 307 + src/games/hunt/makemaze.c | 145 + src/games/hunt/pathname.c | 37 + src/games/hunt/playit.c | 386 + src/games/hunt/shots.c | 823 + src/games/hunt/terminal.c | 114 + src/games/mille/Makefile | 75 + src/games/mille/comp.c | 431 + src/games/mille/end.c | 111 + src/games/mille/extern.c | 135 + src/games/mille/init.c | 214 + src/games/mille/mille.6 | 351 + src/games/mille/mille.c | 135 + src/games/mille/mille.h | 195 + src/games/mille/misc.c | 224 + src/games/mille/move.c | 517 + src/games/mille/print.c | 132 + src/games/mille/roll.c | 20 + src/games/mille/save.c | 132 + src/games/mille/table.c | 21 + src/games/mille/types.c | 38 + src/games/mille/unctrl.h | 9 + src/games/mille/varpush.c | 53 + src/games/monop/Makefile | 87 + src/games/monop/_rofix | 3 + src/games/monop/brd.dat | 43 + src/games/monop/cards.c | 170 + src/games/monop/cards.inp | 122 + src/games/monop/deck.h | 13 + src/games/monop/execute.c | 224 + src/games/monop/getinp.c | 83 + src/games/monop/houses.c | 230 + src/games/monop/initdeck.c | 140 + src/games/monop/jail.c | 90 + src/games/monop/misc.c | 326 + src/games/monop/mon.dat | 9 + src/games/monop/monop.6 | 164 + src/games/monop/monop.c | 121 + src/games/monop/monop.def | 89 + src/games/monop/monop.ext | 22 + src/games/monop/monop.h | 98 + src/games/monop/morg.c | 173 + src/games/monop/print.c | 154 + src/games/monop/prop.c | 172 + src/games/monop/prop.dat | 23 + src/games/monop/rent.c | 55 + src/games/monop/roll.c | 37 + src/games/monop/spec.c | 49 + src/games/monop/strcmp.c | 21 + src/games/monop/strings | 0 src/games/monop/trade.c | 271 + src/games/morse.c | 89 + src/games/number.6 | 12 + src/games/number.c | 207 + src/games/phantasia/Makefile | 35 + src/games/phantasia/Makefile-linux | 80 + src/games/phantasia/fight.c | 607 + src/games/phantasia/func0.c | 1008 + src/games/phantasia/func1.c | 904 + src/games/phantasia/func2.c | 850 + src/games/phantasia/main.c | 555 + src/games/phantasia/monsters | 99 + src/games/phantasia/phant.h | 162 + src/games/phantasia/phant.nr | 1184 + src/games/phantasia/phant_run.c | 16 + src/games/phantasia/setfiles.c | 138 + src/games/phantasia/test.c | 7 + src/games/ppt.c | 34 + src/games/primes.c | 143 + src/games/quiz/Makefile | 42 + src/games/quiz/quiz.6 | 67 + src/games/quiz/quiz.c | 477 + src/games/quiz/quiz.k/africa | 44 + src/games/quiz/quiz.k/america | 27 + src/games/quiz/quiz.k/areas | 124 + src/games/quiz/quiz.k/arith | 45 + src/games/quiz/quiz.k/asia | 41 + src/games/quiz/quiz.k/babies | 21 + src/games/quiz/quiz.k/bard | 228 + src/games/quiz/quiz.k/chinese | 12 + src/games/quiz/quiz.k/collectives | 88 + src/games/quiz/quiz.k/ed | 84 + src/games/quiz/quiz.k/elements | 103 + src/games/quiz/quiz.k/europe | 33 + src/games/quiz/quiz.k/greek | 7 + src/games/quiz/quiz.k/inca | 12 + src/games/quiz/quiz.k/index | 30 + src/games/quiz/quiz.k/latin | 157 + src/games/quiz/quiz.k/locomotive | 11 + src/games/quiz/quiz.k/midearth | 10 + src/games/quiz/quiz.k/morse | 26 + src/games/quiz/quiz.k/murders | 25 + src/games/quiz/quiz.k/poetry | 184 + src/games/quiz/quiz.k/posneg | 50 + src/games/quiz/quiz.k/pres | 38 + src/games/quiz/quiz.k/province | 13 + src/games/quiz/quiz.k/seq-easy | 14 + src/games/quiz/quiz.k/seq-hard | 15 + src/games/quiz/quiz.k/sexes | 26 + src/games/quiz/quiz.k/sov | 42 + src/games/quiz/quiz.k/spell | 2 + src/games/quiz/quiz.k/state | 50 + src/games/quiz/quiz.k/trek | 19 + src/games/quiz/quiz.k/ucc | 127 + src/games/rain.6 | 27 + src/games/rain.c | 189 + src/games/robots/Makefile | 31 + src/games/robots/extern.c | 48 + src/games/robots/flush_in.c | 24 + src/games/robots/init_field.c | 90 + src/games/robots/main.c | 167 + src/games/robots/make_level.c | 62 + src/games/robots/move.c | 272 + src/games/robots/move_robs.c | 124 + src/games/robots/play_level.c | 88 + src/games/robots/query.c | 33 + src/games/robots/rnd_pos.c | 41 + src/games/robots/robots.6 | 130 + src/games/robots/robots.h | 83 + src/games/robots/score.c | 155 + src/games/rogue/CHANGES | 53 + src/games/rogue/Makefile | 63 + src/games/rogue/Makefile-linux | 46 + src/games/rogue/curses.c | 688 + src/games/rogue/doprnt.c | 203 + src/games/rogue/hit.c | 423 + src/games/rogue/init.c | 300 + src/games/rogue/inventory.c | 740 + src/games/rogue/level.c | 860 + src/games/rogue/machdep.c | 626 + src/games/rogue/main.c | 34 + src/games/rogue/message.c | 343 + src/games/rogue/monster.c | 841 + src/games/rogue/move.c | 609 + src/games/rogue/object.c | 754 + src/games/rogue/pack.c | 545 + src/games/rogue/play.c | 283 + src/games/rogue/random.c | 93 + src/games/rogue/ring.c | 296 + src/games/rogue/rogue.6 | 93 + src/games/rogue/rogue.h | 696 + src/games/rogue/room.c | 622 + src/games/rogue/save.c | 376 + src/games/rogue/score.c | 544 + src/games/rogue/spec_hit.c | 504 + src/games/rogue/throw.c | 280 + src/games/rogue/trap.c | 239 + src/games/rogue/use.c | 582 + src/games/rogue/zap.c | 365 + src/games/sail/Makefile | 35 + src/games/sail/Makefile-linux | 21 + src/games/sail/assorted.c | 245 + src/games/sail/doprnt.c | 203 + src/games/sail/dr_1.c | 438 + src/games/sail/dr_2.c | 252 + src/games/sail/dr_3.c | 323 + src/games/sail/dr_4.c | 35 + src/games/sail/dr_5.c | 63 + src/games/sail/dr_main.c | 79 + src/games/sail/driver.h | 10 + src/games/sail/externs.h | 351 + src/games/sail/game.c | 58 + src/games/sail/globals.c | 475 + src/games/sail/lo_main.c | 62 + src/games/sail/machdep.h | 11 + src/games/sail/main.c | 102 + src/games/sail/misc.c | 207 + src/games/sail/parties.c | 47 + src/games/sail/pl_1.c | 104 + src/games/sail/pl_2.c | 123 + src/games/sail/pl_3.c | 247 + src/games/sail/pl_4.c | 101 + src/games/sail/pl_5.c | 225 + src/games/sail/pl_6.c | 167 + src/games/sail/pl_7.c | 468 + src/games/sail/pl_main.c | 229 + src/games/sail/player.h | 92 + src/games/sail/sail.6 | 872 + src/games/sail/sync.c | 399 + src/games/sail/version.c | 6 + src/games/snake/Makefile | 41 + src/games/snake/busy.c | 36 + src/games/snake/move.c | 634 + src/games/snake/snake.6 | 93 + src/games/snake/snake.c | 914 + src/games/snake/snake.h | 49 + src/games/snake/snscore.c | 83 + src/games/trek/Makefile | 42 + src/games/trek/README | 4 + src/games/trek/abandon.c | 129 + src/games/trek/attack.c | 156 + src/games/trek/autover.c | 45 + src/games/trek/board.x | 59 + src/games/trek/capture.c | 98 + src/games/trek/check_out.c | 38 + src/games/trek/checkcond.c | 69 + src/games/trek/compkl.c | 79 + src/games/trek/computer.c | 311 + src/games/trek/damage.c | 59 + src/games/trek/damaged.c | 35 + src/games/trek/dcrept.c | 67 + src/games/trek/destruct.c | 83 + src/games/trek/dock.c | 113 + src/games/trek/docs/read_me.nr | 251 + src/games/trek/docs/things | 10 + src/games/trek/docs/trekmanual.nr | 895 + src/games/trek/dumpgame.c | 130 + src/games/trek/dumpme.c | 56 + src/games/trek/dumpssradio.c | 53 + src/games/trek/events.c | 435 + src/games/trek/externs.c | 66 + src/games/trek/getcodi.c | 35 + src/games/trek/getpar.c | 288 + src/games/trek/getpar.h | 26 + src/games/trek/help.c | 131 + src/games/trek/impulse.c | 53 + src/games/trek/initquad.c | 118 + src/games/trek/kill.c | 192 + src/games/trek/klmove.c | 152 + src/games/trek/lose.c | 54 + src/games/trek/lrscan.c | 74 + src/games/trek/main.c | 202 + src/games/trek/move.c | 199 + src/games/trek/nova.c | 108 + src/games/trek/out.c | 24 + src/games/trek/phaser.c | 344 + src/games/trek/play.c | 81 + src/games/trek/ram.c | 69 + src/games/trek/ranf.c | 27 + src/games/trek/rest.c | 48 + src/games/trek/schedule.c | 141 + src/games/trek/score.c | 72 + src/games/trek/setup.c | 273 + src/games/trek/setwarp.c | 36 + src/games/trek/shell.c | 33 + src/games/trek/shield.c | 113 + src/games/trek/snova.c | 123 + src/games/trek/srscan.c | 161 + src/games/trek/systemname.c | 35 + src/games/trek/torped.c | 217 + src/games/trek/trek.6 | 63 + src/games/trek/trek.h | 403 + src/games/trek/utility.c | 98 + src/games/trek/visual.c | 71 + src/games/trek/warp.c | 151 + src/games/trek/win.c | 57 + src/games/warp/EXTERN.h | 24 + src/games/warp/INTERN.h | 22 + src/games/warp/MANIFEST | 58 + src/games/warp/Makefile | 56 + src/games/warp/Makefile-linux | 57 + src/games/warp/README | 95 + src/games/warp/bang.c | 153 + src/games/warp/bang.h | 30 + src/games/warp/init.c | 531 + src/games/warp/init.h | 9 + src/games/warp/intrp.c | 554 + src/games/warp/intrp.h | 23 + src/games/warp/move.c | 676 + src/games/warp/move.h | 14 + src/games/warp/object.c | 78 + src/games/warp/object.h | 67 + src/games/warp/patchlevel.h | 1 + src/games/warp/play.c | 180 + src/games/warp/play.h | 13 + src/games/warp/score.c | 694 + src/games/warp/score.h | 49 + src/games/warp/sig.c | 220 + src/games/warp/sig.h | 16 + src/games/warp/sm.c | 90 + src/games/warp/smp.0 | 23 + src/games/warp/smp.1 | 23 + src/games/warp/smp.2 | 23 + src/games/warp/smp.3 | 23 + src/games/warp/smp.4 | 23 + src/games/warp/smp.5 | 23 + src/games/warp/smp.6 | 23 + src/games/warp/smp.7 | 23 + src/games/warp/term.c | 776 + src/games/warp/term.h | 259 + src/games/warp/them.c | 403 + src/games/warp/them.h | 11 + src/games/warp/us.c | 510 + src/games/warp/us.h | 61 + src/games/warp/util.c | 197 + src/games/warp/util.h | 33 + src/games/warp/version.c | 22 + src/games/warp/version.h | 9 + src/games/warp/warp.6 | 133 + src/games/warp/warp.c | 381 + src/games/warp/warp.doc | 193 + src/games/warp/warp.h | 402 + src/games/warp/warp.man | 133 + src/games/warp/warp.news | 4 + src/games/warp/weapon.c | 688 + src/games/warp/weapon.h | 22 + src/games/worm.6 | 39 + src/games/worm.c | 257 + src/games/worms.6 | 48 + src/games/worms.c | 354 + src/games/wump.6 | 26 + src/games/wump.c | 398 + src/libc/Makefile | 59 + src/libc/compat/Makefile | 50 + src/libc/compat/creat.c | 41 + src/libc/compat/ftime.c | 35 + src/libc/compat/gethostid.c | 49 + src/libc/compat/gtty.c | 17 + src/libc/compat/memccpy.c | 25 + src/libc/compat/memchr.c | 23 + src/libc/compat/memcmp.c | 22 + src/libc/compat/memcpy.c | 24 + src/libc/compat/memset.c | 23 + src/libc/compat/nice.c | 24 + src/libc/compat/pause.c | 19 + src/libc/compat/rand.c | 23 + src/libc/compat/sethostid.c | 47 + src/libc/compat/setregid.c | 58 + src/libc/compat/setreuid.c | 58 + src/libc/compat/setrgid.c | 40 + src/libc/compat/setruid.c | 40 + src/libc/compat/sigcompat.c | 82 + src/libc/compat/strchr.c | 17 + src/libc/compat/strrchr.c | 20 + src/libc/compat/stty.c | 17 + src/libc/compat/times.c | 34 + src/libc/compat/tmpnam.c | 76 + src/libc/compat/utime.c | 22 + src/libc/gen/Makefile | 78 + src/libc/gen/abort.c | 59 + src/libc/gen/abs.c | 11 + src/libc/gen/alarm.c | 27 + src/libc/gen/atof.c | 99 + src/libc/gen/atoi.c | 25 + src/libc/gen/atol.c | 25 + src/libc/gen/bcmp-disabled.c | 23 + src/libc/gen/bcopy-disabled.c | 27 + src/libc/gen/bzero-disabled.c | 19 + src/libc/gen/calloc.c | 28 + src/libc/gen/closedir.c | 22 + src/libc/gen/crypt.c | 378 + src/libc/gen/ctime.c | 391 + src/libc/gen/ctype_.c | 21 + src/libc/gen/daemon.c | 69 + src/libc/gen/devname.c | 71 + src/libc/gen/ecvt.c | 104 + src/libc/gen/err.c | 201 + src/libc/gen/execvp.c | 88 + src/libc/gen/fabs.c | 11 + src/libc/gen/fakcu.c | 7 + src/libc/gen/ffs-disabled.c | 20 + src/libc/gen/frexp.c | 40 + src/libc/gen/fstab.c | 209 + src/libc/gen/gcvt.c | 61 + src/libc/gen/getenv.c | 53 + src/libc/gen/getgrent.c | 64 + src/libc/gen/getgrgid.c | 14 + src/libc/gen/getgrnam.c | 15 + src/libc/gen/getgrouplist.c | 83 + src/libc/gen/gethostname.c | 50 + src/libc/gen/getloadavg.c | 63 + src/libc/gen/getlogin.c | 46 + src/libc/gen/getmntinfo.c | 64 + src/libc/gen/getpagesize.c | 48 + src/libc/gen/getpass.c | 41 + src/libc/gen/getpwent.c | 208 + src/libc/gen/getttyent.c | 136 + src/libc/gen/getttynam.c | 22 + src/libc/gen/getusershell.c | 115 + src/libc/gen/getwd.c | 110 + src/libc/gen/index-disabled.c | 17 + src/libc/gen/initgroups.c | 46 + src/libc/gen/insque.c | 25 + src/libc/gen/isatty.c | 15 + src/libc/gen/isinf.c | 22 + src/libc/gen/isinff.c | 30 + src/libc/gen/isnan.c | 26 + src/libc/gen/isnanf.c | 30 + src/libc/gen/knlist.c | 33 + src/libc/gen/ldexp.c | 46 + src/libc/gen/malloc.c | 232 + src/libc/gen/mktemp.c | 94 + src/libc/gen/modf.c | 79 + src/libc/gen/modff.c | 55 + src/libc/gen/ndbm.c | 504 + src/libc/gen/nlist.c | 97 + src/libc/gen/opendir.c | 31 + src/libc/gen/perror.c | 62 + src/libc/gen/popen.c | 133 + src/libc/gen/psignal.c | 35 + src/libc/gen/qsort.c | 202 + src/libc/gen/random.c | 318 + src/libc/gen/readdir.c | 39 + src/libc/gen/regex.c | 400 + src/libc/gen/remque.c | 23 + src/libc/gen/rindex-disabled.c | 20 + src/libc/gen/scandir.c | 92 + src/libc/gen/seekdir.c | 35 + src/libc/gen/setenv.c | 88 + src/libc/gen/sethostname.c | 48 + src/libc/gen/setmode.c | 453 + src/libc/gen/siginterrupt.c | 57 + src/libc/gen/siglist.c | 41 + src/libc/gen/signal.c | 56 + src/libc/gen/sigsetops.c | 81 + src/libc/gen/sleep.c | 47 + src/libc/gen/strcasecmp.c | 71 + src/libc/gen/strcat.c | 21 + src/libc/gen/strcmp-disabled.c | 14 + src/libc/gen/strcpy.c | 18 + src/libc/gen/strdup.c | 35 + src/libc/gen/strftime.c | 264 + src/libc/gen/strlen-disabled.c | 17 + src/libc/gen/strncat.c | 26 + src/libc/gen/strncmp.c | 19 + src/libc/gen/strncpy.c | 24 + src/libc/gen/swab.c | 26 + src/libc/gen/sysctl.c | 126 + src/libc/gen/syslog.c | 231 + src/libc/gen/system.c | 72 + src/libc/gen/telldir.c | 19 + src/libc/gen/time.c | 24 + src/libc/gen/timezone.c | 99 + src/libc/gen/ttyname.c | 46 + src/libc/gen/ttyslot.c | 43 + src/libc/gen/ualarm.c | 32 + src/libc/gen/uname.c | 87 + src/libc/gen/usleep.c | 32 + src/libc/gen/valloc.c | 26 + src/libc/gen/wait.c | 43 + src/libc/gen/wait3.c | 45 + src/libc/gen/waitpid.c | 45 + src/libc/inet/Makefile | 46 + src/libc/inet/inet_addr.c | 99 + src/libc/inet/inet_lnaof.c | 27 + src/libc/inet/inet_maddr.c | 28 + src/libc/inet/inet_netof.c | 53 + src/libc/inet/inet_network.c | 61 + src/libc/inet/inet_ntoa.c | 27 + src/libc/mips/Makefile | 35 + src/libc/mips/gen/Makefile | 44 + src/libc/mips/gen/_setjmp.S | 85 + src/libc/mips/gen/htonl.S | 58 + src/libc/mips/gen/htons.S | 50 + src/libc/mips/gen/setjmp.S | 117 + src/libc/mips/gen/sigsetjmp.S | 67 + src/libc/mips/string/Makefile | 52 + src/libc/mips/string/bcmp.S | 113 + src/libc/mips/string/bcopy.S | 270 + src/libc/mips/string/bzero.S | 68 + src/libc/mips/string/ffs.S | 46 + src/libc/mips/string/index.S | 45 + src/libc/mips/string/memcpy.S | 2 + src/libc/mips/string/memmove.S | 2 + src/libc/mips/string/memset.S | 43 + src/libc/mips/string/rindex.S | 44 + src/libc/mips/string/strcmp.S | 55 + src/libc/mips/string/strlen.S | 42 + src/libc/mips/sys/Makefile | 51 + src/libc/mips/sys/SYS.h | 17 + src/libc/mips/sys/_brk.S | 15 + src/libc/mips/sys/_exit.S | 9 + src/libc/mips/sys/execl.c | 14 + src/libc/mips/sys/execle.c | 22 + src/libc/mips/sys/execv.c | 16 + src/libc/mips/sys/pipe.S | 22 + src/libc/mips/sys/ptrace.S | 21 + src/libc/mips/sys/sbrk.c | 41 + src/libc/mips/sys/sigaction.S | 77 + src/libc/net/Makefile | 111 + src/libc/net/getnbyaddr.c | 29 + src/libc/net/getnbyname.c | 34 + src/libc/net/getnent.c | 109 + src/libc/net/getpent.c | 107 + src/libc/net/getpname.c | 34 + src/libc/net/getproto.c | 28 + src/libc/net/getsbyname.c | 37 + src/libc/net/getsbyport.c | 32 + src/libc/net/getsent.c | 110 + src/libc/net/herror.c | 49 + src/libc/net/hosttable/Makefile | 56 + src/libc/net/hosttable/gethnamadr.c | 156 + src/libc/net/hosttable/gethostent.c | 133 + src/libc/net/named/Makefile | 57 + src/libc/net/named/gethnamadr.c | 401 + src/libc/net/named/sethostent.c | 34 + src/libc/net/rcmd.c | 339 + src/libc/net/res_comp.c | 310 + src/libc/net/res_debug.c | 439 + src/libc/net/res_init.c | 138 + src/libc/net/res_mkquery.c | 200 + src/libc/net/res_query.c | 248 + src/libc/net/res_send.c | 364 + src/libc/net/rexec.c | 116 + src/libc/net/ruserpass.c | 810 + src/libc/ns/Makefile | 61 + src/libc/ns/ns_addr.c | 196 + src/libc/ns/ns_ntoa.c | 73 + src/libc/runtime/CREDITS.txt | 24 + src/libc/runtime/LICENSE.txt | 97 + src/libc/runtime/Makefile | 37 + src/libc/runtime/README.txt | 343 + src/libc/runtime/addsf3.c | 150 + src/libc/runtime/comparesf2.c | 143 + src/libc/runtime/divsf3.c | 165 + src/libc/runtime/fixsfsi.c | 46 + src/libc/runtime/floatsisf.c | 57 + src/libc/runtime/fp_lib.h | 155 + src/libc/runtime/mulsf3.c | 110 + src/libc/runtime/negsf2.c | 21 + src/libc/runtime/sc_case.S | 34 + src/libc/runtime/subsf3.c | 25 + src/libc/stdio/Makefile | 61 + src/libc/stdio/clrerr.c | 9 + src/libc/stdio/doprnt.c | 780 + src/libc/stdio/doscan.c | 290 + src/libc/stdio/exit.c | 21 + src/libc/stdio/fdopen.c | 57 + src/libc/stdio/feof.c | 14 + src/libc/stdio/ferror.c | 14 + src/libc/stdio/fgetc.c | 8 + src/libc/stdio/fgets.c | 22 + src/libc/stdio/filbuf.c | 67 + src/libc/stdio/fileno.c | 14 + src/libc/stdio/findiop.c | 124 + src/libc/stdio/flsbuf.c | 118 + src/libc/stdio/fopen.c | 59 + src/libc/stdio/fprintf.c | 30 + src/libc/stdio/fputc.c | 9 + src/libc/stdio/fputs.c | 36 + src/libc/stdio/fread.c | 44 + src/libc/stdio/freopen.c | 56 + src/libc/stdio/fseek.c | 59 + src/libc/stdio/ftell.c | 29 + src/libc/stdio/fwrite.c | 47 + src/libc/stdio/getchar.c | 13 + src/libc/stdio/gets.c | 17 + src/libc/stdio/getw.c | 35 + src/libc/stdio/printf.c | 13 + src/libc/stdio/putchar.c | 14 + src/libc/stdio/puts.c | 12 + src/libc/stdio/putw.c | 30 + src/libc/stdio/remove.c | 48 + src/libc/stdio/rew.c | 15 + src/libc/stdio/scanf.c | 45 + src/libc/stdio/setbuf.c | 44 + src/libc/stdio/setbuffer.c | 57 + src/libc/stdio/setvbuf.c | 125 + src/libc/stdio/snprintf.c | 34 + src/libc/stdio/sprintf.c | 34 + src/libc/stdio/strout.c | 24 + src/libc/stdio/ungetc.c | 22 + src/libc/stdio/vfprintf.c | 42 + src/libc/stdio/vprintf.c | 29 + src/libc/stdio/vsprintf.c | 34 + src/libc/stdlib/Makefile | 34 + src/libc/stdlib/getopt.c | 112 + src/libc/stdlib/getsubopt.c | 94 + src/libc/stdlib/strtod.c | 200 + src/libc/stdlib/strtol.c | 123 + src/libc/stdlib/strtoul.c | 102 + src/libc/string/Makefile | 34 + src/libc/string/strcspn.c | 63 + src/libc/string/strerror.c | 73 + src/libc/string/strpbrk.c | 55 + src/libc/string/strsep.c | 75 + src/libc/string/strspn.c | 56 + src/libc/string/strstr.c | 60 + src/libc/string/strtok.c | 85 + src/libc/string/strtok_r.c | 80 + src/libcurses/Makefile | 75 + src/libcurses/addch.c | 97 + src/libcurses/addstr.c | 23 + src/libcurses/box.c | 35 + src/libcurses/clear.c | 17 + src/libcurses/clrtobot.c | 35 + src/libcurses/clrtoeol.c | 39 + src/libcurses/cr_put.c | 390 + src/libcurses/cr_tty.c | 197 + src/libcurses/curses.c | 49 + src/libcurses/curses.ext | 40 + src/libcurses/delch.c | 27 + src/libcurses/deleteln.c | 42 + src/libcurses/delwin.c | 48 + src/libcurses/endwin.c | 23 + src/libcurses/erase.c | 38 + src/libcurses/fullname.c | 33 + src/libcurses/getch.c | 39 + src/libcurses/getstr.c | 24 + src/libcurses/id_subwins.c | 33 + src/libcurses/idlok.c | 22 + src/libcurses/initscr.c | 65 + src/libcurses/insch.c | 35 + src/libcurses/insertln.c | 42 + src/libcurses/longname.c | 27 + src/libcurses/move.c | 25 + src/libcurses/mvprintw.c | 30 + src/libcurses/mvscanw.c | 29 + src/libcurses/mvwin.c | 45 + src/libcurses/newwin.c | 199 + src/libcurses/overlay.c | 54 + src/libcurses/overwrite.c | 40 + src/libcurses/printw.c | 58 + src/libcurses/putchar.c | 17 + src/libcurses/refresh.c | 302 + src/libcurses/scanw.c | 60 + src/libcurses/scroll.c | 38 + src/libcurses/standout.c | 36 + src/libcurses/test.c | 26 + src/libcurses/toucholap.c | 41 + src/libcurses/touchwin.c | 53 + src/libcurses/tstp.c | 56 + src/libcurses/unctrl.c | 23 + src/libicache/icache.ld | 300 + src/libicache/icachec.c | 1262 + src/libicache/icaches.s | 285 + src/libicache/license.txt | 26 + src/libicache/readme.txt | 10 + src/libm/Makefile | 31 + src/libm/asin.c | 53 + src/libm/atan.c | 99 + src/libm/erf.c | 118 + src/libm/exp.c | 44 + src/libm/fabs.c | 11 + src/libm/floor.c | 29 + src/libm/fmod.c | 111 + src/libm/hypot.c | 45 + src/libm/ieee.h | 23 + src/libm/j0.c | 192 + src/libm/j1.c | 198 + src/libm/jn.c | 103 + src/libm/log.c | 61 + src/libm/pow.c | 36 + src/libm/sin.c | 75 + src/libm/sinh.c | 66 + src/libm/sqrt.c | 55 + src/libm/tan.c | 73 + src/libm/tanh.c | 26 + src/libtcl/Makefile | 40 + src/libtcl/doc/AddErrInfo.3 | 136 + src/libtcl/doc/AssembCmd.3 | 87 + src/libtcl/doc/Backslash.3 | 57 + src/libtcl/doc/Concat.3 | 55 + src/libtcl/doc/CrtCommand.3 | 124 + src/libtcl/doc/CrtInterp.3 | 50 + src/libtcl/doc/CrtPipelin.3 | 105 + src/libtcl/doc/CrtTrace.3 | 114 + src/libtcl/doc/Eval.3 | 124 + src/libtcl/doc/ExprLong.3 | 102 + src/libtcl/doc/Fork.3 | 150 + src/libtcl/doc/GetInt.3 | 85 + src/libtcl/doc/Hash.3 | 211 + src/libtcl/doc/History.3 | 72 + src/libtcl/doc/Interp.3 | 127 + src/libtcl/doc/SetResult.3 | 163 + src/libtcl/doc/SetVar.3 | 156 + src/libtcl/doc/SplitList.3 | 159 + src/libtcl/doc/StrMatch.3 | 41 + src/libtcl/doc/Tcl.n | 2832 ++ src/libtcl/doc/TildeSubst.3 | 58 + src/libtcl/doc/TraceVar.3 | 340 + src/libtcl/doc/library.n | 228 + src/libtcl/doc/man.macros | 176 + src/libtcl/hash.h | 125 + src/libtcl/internal.h | 689 + src/libtcl/regexp.c | 1227 + src/libtcl/regexp.h | 29 + src/libtcl/regpriv.h | 49 + src/libtcl/regsub.c | 69 + src/libtcl/tclassem.c | 232 + src/libtcl/tclbasic.c | 1059 + src/libtcl/tclcmdah.c | 885 + src/libtcl/tclcmdil.c | 1156 + src/libtcl/tclcmdmz.c | 1372 + src/libtcl/tclenv.c | 501 + src/libtcl/tclexpr.c | 1053 + src/libtcl/tclget.c | 136 + src/libtcl/tclglob.c | 566 + src/libtcl/tclhash.c | 908 + src/libtcl/tclparse.c | 1212 + src/libtcl/tclproc.c | 575 + src/libtcl/tclunxaz.c | 1719 + src/libtcl/tclutil.c | 1389 + src/libtcl/tcluxstr.c | 725 + src/libtcl/tcluxutl.c | 1016 + src/libtcl/tclvar.c | 2254 + src/libtermlib/Makefile | 63 + src/libtermlib/tc1.c | 26 + src/libtermlib/tc2.c | 53 + src/libtermlib/tc3.c | 78 + src/libtermlib/tcattr.c | 35 + src/libtermlib/termcap.c | 351 + src/libtermlib/termcap/Makefile | 29 + src/libtermlib/termcap/README | 42 + src/libtermlib/termcap/map3270 | 539 + src/libtermlib/termcap/reorder | 40 + src/libtermlib/termcap/tabset/3101 | 1 + src/libtermlib/termcap/tabset/aa | 1 + src/libtermlib/termcap/tabset/aed512 | 1 + src/libtermlib/termcap/tabset/beehive | 2 + src/libtermlib/termcap/tabset/diablo | 3 + src/libtermlib/termcap/tabset/dtc382 | 1 + src/libtermlib/termcap/tabset/ibm3101 | 1 + src/libtermlib/termcap/tabset/std | 1 + src/libtermlib/termcap/tabset/stdcrt | 1 + src/libtermlib/termcap/tabset/tandem653 | 1 + src/libtermlib/termcap/tabset/teleray | 1 + src/libtermlib/termcap/tabset/vt100 | 3 + src/libtermlib/termcap/tabset/wyse-adds | 3 + src/libtermlib/termcap/tabset/xerox1720 | 1 + src/libtermlib/termcap/tabset/xerox1730 | Bin 0 -> 222 bytes src/libtermlib/termcap/tabset/xerox1730-lm | Bin 0 -> 224 bytes src/libtermlib/termcap/tabset/zenith29 | 1 + src/libtermlib/termcap/termcap.local | 3 + src/libtermlib/termcap/termcap.src | 2971 ++ src/libtermlib/tgoto.c | 176 + src/libtermlib/tputs.c | 92 + src/libutil/Makefile | 47 + src/libutil/login.c | 41 + src/libutil/logout.c | 50 + src/libutil/logwtmp.c | 45 + src/libvmf/Makefile | 44 + src/libvmf/vmf.3 | 142 + src/libvmf/vmf.c | 375 + src/libvmf/vmlib.ms | 406 + src/libwiznet/Makefile | 17 + src/libwiznet/client.c | 157 + src/libwiznet/ethernet.c | 131 + src/libwiznet/server.c | 96 + src/libwiznet/socket.c | 329 + src/libwiznet/udp.c | 150 + src/libwiznet/w5100.c | 246 + src/share/Makefile | 24 + src/share/misc/Makefile | 21 + src/startup-mips/Makefile | 56 + src/startup-mips/crt0.c | 81 + src/startup-mips/mcount.S | 90 + src/startup-mips/mon.c | 124 + src/startup-mips/mon.ex | 5 + sys/include/adc.h | 29 + sys/include/buf.h | 227 + sys/include/callout.h | 31 + sys/include/clist.h | 17 + sys/include/conf.h | 69 + sys/include/debug.h | 84 + sys/include/dir.h | 105 + sys/include/disk.h | 113 + sys/include/dk.h | 31 + sys/include/dkbad.h | 57 + sys/include/errno.h | 121 + sys/include/exec.h | 28 + sys/include/fcntl.h | 149 + sys/include/file.h | 120 + sys/include/fs.h | 163 + sys/include/glcd.h | 149 + sys/include/glob.h | 12 + sys/include/gpio.h | 52 + sys/include/inode.h | 430 + sys/include/ioctl.h | 259 + sys/include/kernel.h | 27 + sys/include/map.h | 53 + sys/include/mount.h | 101 + sys/include/msgbuf.h | 23 + sys/include/mtio.h | 80 + sys/include/namei.h | 104 + sys/include/oc.h | 38 + sys/include/param.h | 123 + sys/include/picga.h | 100 + sys/include/proc.h | 305 + sys/include/ptrace.h | 46 + sys/include/pty.h | 49 + sys/include/rd_flash.h | 14 + sys/include/rd_mrams.h | 9 + sys/include/rd_sdramp.h | 14 + sys/include/rd_sramc.h | 14 + sys/include/rdisk.h | 97 + sys/include/reboot.h | 31 + sys/include/resource.h | 107 + sys/include/select.h | 75 + sys/include/signal.h | 189 + sys/include/signalvar.h | 120 + sys/include/spi.h | 34 + sys/include/spi_bus.h | 62 + sys/include/stat.h | 103 + sys/include/swap.h | 29 + sys/include/sysctl.h | 393 + sys/include/syslog.h | 171 + sys/include/systm.h | 275 + sys/include/time.h | 114 + sys/include/times.h | 17 + sys/include/trace.h | 85 + sys/include/tty.h | 247 + sys/include/ttychars.h | 52 + sys/include/ttydev.h | 57 + sys/include/types.h | 93 + sys/include/uart.h | 65 + sys/include/uio.h | 80 + sys/include/usb_uart.h | 47 + sys/include/user.h | 113 + sys/include/utsname.h | 49 + sys/include/vm.h | 16 + sys/include/vmmac.h | 11 + sys/include/vmmeter.h | 71 + sys/include/vmparam.h | 22 + sys/include/vmsystm.h | 35 + sys/include/wait.h | 87 + sys/kernel/init_main.c | 341 + sys/kernel/init_sysent.c | 211 + sys/kernel/kern_clock.c | 373 + sys/kernel/kern_descrip.c | 532 + sys/kernel/kern_exec.c | 539 + sys/kernel/kern_exit.c | 280 + sys/kernel/kern_fork.c | 254 + sys/kernel/kern_glob.c | 61 + sys/kernel/kern_mman.c | 38 + sys/kernel/kern_proc.c | 65 + sys/kernel/kern_prot.c | 155 + sys/kernel/kern_prot2.c | 114 + sys/kernel/kern_resource.c | 270 + sys/kernel/kern_sig.c | 664 + sys/kernel/kern_sig2.c | 371 + sys/kernel/kern_subr.c | 126 + sys/kernel/kern_synch.c | 538 + sys/kernel/kern_sysctl.c | 909 + sys/kernel/kern_time.c | 342 + sys/kernel/subr_log.c | 336 + sys/kernel/subr_prf.c | 565 + sys/kernel/subr_rmap.c | 230 + sys/kernel/sys_generic.c | 544 + sys/kernel/sys_inode.c | 698 + sys/kernel/sys_pipe.c | 307 + sys/kernel/sys_process.c | 137 + sys/kernel/syscalls.c | 169 + sys/kernel/tty.c | 1653 + sys/kernel/tty_pty.c | 520 + sys/kernel/tty_subr.c | 406 + sys/kernel/tty_tty.c | 90 + sys/kernel/ufs_alloc.c | 302 + sys/kernel/ufs_bio.c | 485 + sys/kernel/ufs_bmap.c | 154 + sys/kernel/ufs_dsort.c | 84 + sys/kernel/ufs_fio.c | 186 + sys/kernel/ufs_inode.c | 695 + sys/kernel/ufs_mount.c | 301 + sys/kernel/ufs_namei.c | 1258 + sys/kernel/ufs_subr.c | 145 + sys/kernel/ufs_syscalls.c | 1338 + sys/kernel/ufs_syscalls2.c | 279 + sys/kernel/vfs_vnops.c | 212 + sys/kernel/vm_sched.c | 262 + sys/kernel/vm_swap.c | 115 + sys/kernel/vm_swp.c | 177 + sys/pic32/MAKEDEV.sh | 63 + sys/pic32/Makefile | 22 + sys/pic32/README | 22 + sys/pic32/_startup.S | 1 + sys/pic32/adc.c | 149 + sys/pic32/baremetal/BAREMETAL | 13 + sys/pic32/baremetal/Makefile | 66 + sys/pic32/baremetal/bare-metal.ld | 186 + sys/pic32/baremetal/devcfg.c | 25 + sys/pic32/cfg/adc.dev | 4 + sys/pic32/cfg/bare.ld | 179 + sys/pic32/cfg/boot.ld | 151 + sys/pic32/cfg/bootloader-max32.ld | 117 + sys/pic32/cfg/bootloader-maxcolor.ld | 117 + sys/pic32/cfg/bootloader-maximite.ld | 117 + sys/pic32/cfg/bootloader-sdram.ld | 136 + sys/pic32/cfg/bootloader-ubw32.ld | 117 + sys/pic32/cfg/bootloader.dev | 83 + sys/pic32/cfg/bootloader.ld | 116 + sys/pic32/cfg/console.dev | 18 + sys/pic32/cfg/devcfg.dev | 3 + sys/pic32/cfg/foreignbootloader.dev | 3 + sys/pic32/cfg/fubarino.map | 53 + sys/pic32/cfg/generic.map | 113 + sys/pic32/cfg/glcd.dev | 4 + sys/pic32/cfg/glob.dev | 8 + sys/pic32/cfg/global.dev | 456 + sys/pic32/cfg/gpio.dev | 4 + sys/pic32/cfg/kernel.dev | 78 + sys/pic32/cfg/log.dev | 4 + sys/pic32/cfg/max32.map | 105 + sys/pic32/cfg/mrams.dev | 84 + sys/pic32/cfg/oc.dev | 4 + sys/pic32/cfg/picga.dev | 14 + sys/pic32/cfg/power.dev | 19 + sys/pic32/cfg/pty.dev | 4 + sys/pic32/cfg/rdisk.dev | 25 + sys/pic32/cfg/sd.dev | 23 + sys/pic32/cfg/sdramp.dev | 7 + sys/pic32/cfg/spi.dev | 5 + sys/pic32/cfg/spibus.dev | 3 + sys/pic32/cfg/sramc.dev | 26 + sys/pic32/cfg/tty.dev | 5 + sys/pic32/cfg/uart.dev | 13 + sys/pic32/cfg/uartconsole.dev | 0 sys/pic32/cfg/uartusb.dev | 16 + sys/pic32/cfg/ufs.dev | 13 + sys/pic32/cfg/usbconsole.dev | 0 sys/pic32/clock.c | 21 + sys/pic32/cons.c | 109 + sys/pic32/cpu.h | 40 + sys/pic32/devcfg.c | 20 + sys/pic32/devsw.c | 372 + sys/pic32/diag/Makefile | 145 + sys/pic32/diag/main.c | 550 + sys/pic32/dip/DIP | 22 + sys/pic32/dip/Makefile | 88 + sys/pic32/dip/bare-metal.ld | 162 + sys/pic32/dip/devcfg.c | 25 + sys/pic32/dip/using-bootloader.ld | 114 + sys/pic32/drivers.mk | 43 + sys/pic32/duinomite-e-uart/DUINOMITE-E-UART | 19 + sys/pic32/duinomite-e-uart/Makefile | 35 + sys/pic32/duinomite-e/DUINOMITE-E | 21 + sys/pic32/duinomite-e/Makefile | 34 + sys/pic32/duinomite-uart/DUINOMITE-UART | 20 + sys/pic32/duinomite-uart/Makefile | 68 + sys/pic32/duinomite-uart/using-bootloader.ld | 115 + sys/pic32/duinomite/DUINOMITE | 21 + sys/pic32/duinomite/Makefile | 67 + sys/pic32/duinomite/using-bootloader.ld | 115 + sys/pic32/exception.c | 575 + sys/pic32/explorer16/EXPLORER16 | 18 + sys/pic32/explorer16/Makefile | 69 + sys/pic32/explorer16/bare-metal.ld | 162 + sys/pic32/explorer16/devcfg.c | 25 + sys/pic32/float.h | 50 + .../fubarino-uart-sramc/FUBARINO-UART-SRAMC | 17 + sys/pic32/fubarino-uart-sramc/Makefile | 76 + sys/pic32/fubarino-uart-sramc/Makefile.local | 50 + sys/pic32/fubarino-uart-sramc/Makefile_old | 144 + .../fubarino-uart-sramc/using-bootloader.ld | 114 + sys/pic32/fubarino-uart/FUBARINO-UART | 14 + sys/pic32/fubarino-uart/Makefile | 65 + sys/pic32/fubarino-uart/using-bootloader.ld | 114 + sys/pic32/fubarino/FUBARINO | 16 + sys/pic32/fubarino/Makefile | 79 + sys/pic32/fubarino/using-bootloader.ld | 114 + sys/pic32/gcc-config.mk | 35 + sys/pic32/glcd.c | 683 + sys/pic32/gpio.c | 621 + sys/pic32/io.h | 209 + sys/pic32/kernel-post.mk | 85 + sys/pic32/limits.h | 66 + sys/pic32/machdep.c | 888 + sys/pic32/machparam.h | 199 + sys/pic32/max32-eth/MAX32-ETH | 25 + sys/pic32/max32-eth/Makefile | 70 + sys/pic32/max32-eth/using-bootloader.ld | 115 + sys/pic32/max32/MAX32 | 21 + sys/pic32/max32/MAX32-ETH | 0 sys/pic32/max32/Makefile | 70 + sys/pic32/max32/using-bootloader.ld | 115 + sys/pic32/maximite-color/MAXCOLOR | 23 + sys/pic32/maximite-color/Makefile | 78 + sys/pic32/maximite/MAXIMITE | 23 + sys/pic32/maximite/Makefile | 80 + sys/pic32/maximite/kbd.c | 263 + sys/pic32/maximite/kbd.h | 20 + sys/pic32/maximite/russian.inc | 50 + sys/pic32/maximite/usascii.inc | 50 + sys/pic32/maximite/using-bootloader.ld | 115 + sys/pic32/meb/MEB | 18 + sys/pic32/meb/Makefile | 67 + sys/pic32/meb/README | 5 + sys/pic32/meb/using-bootloader.ld | 114 + sys/pic32/mem.c | 85 + sys/pic32/mmb-mx7/MMB-MX7 | 21 + sys/pic32/mmb-mx7/Makefile | 97 + sys/pic32/newvers.sh | 38 + sys/pic32/oc.c | 219 + sys/pic32/pic32mx.h | 1320 + sys/pic32/picga.c | 166 + sys/pic32/pinguino-micro/Makefile | 77 + sys/pic32/pinguino-micro/PINGUINO-MICRO | 22 + sys/pic32/pinguino-micro/using-bootloader.ld | 115 + sys/pic32/power_control.c | 74 + sys/pic32/rd_flash.c | 56 + sys/pic32/rd_mrams.c | 307 + sys/pic32/rd_sd.c | 647 + sys/pic32/rd_sdramp.c | 425 + sys/pic32/rd_sdramp_config.h | 182 + sys/pic32/rd_sramc.c | 258 + sys/pic32/rdisk.c | 684 + sys/pic32/retroone/Makefile | 142 + sys/pic32/retroone/bare-metal.ld | 162 + sys/pic32/retroone/devcfg.c | 25 + sys/pic32/sdram.S | 538 + sys/pic32/sdram.h | 35 + sys/pic32/signal.c | 197 + sys/pic32/spi.c | 178 + sys/pic32/spi_bus.c | 678 + sys/pic32/ssd1926-sdcard.c | 854 + sys/pic32/ssd1926.h | 157 + sys/pic32/starter-kit/Makefile | 84 + sys/pic32/starter-kit/STARTER-KIT | 23 + sys/pic32/starter-kit/using-bootloader.ld | 114 + sys/pic32/startup.S | 405 + sys/pic32/swap.c | 258 + sys/pic32/sysctl.c | 358 + sys/pic32/uart.c | 779 + sys/pic32/ubw32-uart-sdram/Makefile | 94 + sys/pic32/ubw32-uart-sdram/UBW32-UART-SDRAM | 20 + .../ubw32-uart-sdram/using-bootloader-ker.ld | 134 + .../ubw32-uart-sdram/using-bootloader.ld | 115 + sys/pic32/ubw32-uart/Makefile | 95 + sys/pic32/ubw32-uart/UBW32-UART | 21 + sys/pic32/ubw32-uart/using-bootloader.ld | 115 + sys/pic32/ubw32/Makefile | 95 + sys/pic32/ubw32/UBW32 | 23 + sys/pic32/ubw32/using-bootloader.ld | 115 + sys/pic32/usb_boot.c | 837 + sys/pic32/usb_ch9.h | 365 + sys/pic32/usb_console.c | 452 + sys/pic32/usb_device.c | 1534 + sys/pic32/usb_device.h | 1740 + sys/pic32/usb_function_cdc.c | 284 + sys/pic32/usb_function_cdc.h | 409 + sys/pic32/usb_function_hid.c | 221 + sys/pic32/usb_function_hid.h | 119 + sys/pic32/usb_hal_pic32.h | 149 + sys/pic32/usb_uart.c | 479 + target.mk | 48 + tools/Makefile | 8 + tools/configsys/Makefile | 18 + tools/configsys/Makefile.test | 40 + tools/configsys/cluster.cpp | 55 + tools/configsys/cluster.h | 24 + tools/configsys/config.cpp | 177 + tools/configsys/config.h | 25 + tools/configsys/core.cpp | 55 + tools/configsys/core.h | 21 + tools/configsys/cores/pic32mx7.cor | 16 + tools/configsys/device.cpp | 50 + tools/configsys/device.h | 19 + tools/configsys/gstore.cpp | 34 + tools/configsys/gstore.h | 19 + tools/configsys/instance.h | 17 + tools/configsys/main.cpp | 652 + tools/configsys/mapping.cpp | 40 + tools/configsys/mapping.h | 17 + tools/configsys/util.cpp | 27 + tools/configsys/util.h | 11 + tools/elf2aout/Makefile | 18 + tools/elf2aout/elf2aout.c | 723 + tools/fsutil/Makefile | 34 + tools/fsutil/block.c | 163 + tools/fsutil/bsdfs.h | 188 + tools/fsutil/check.c | 1004 + tools/fsutil/create.c | 386 + tools/fsutil/file.c | 82 + tools/fsutil/fsutil.c | 519 + tools/fsutil/inode.c | 832 + tools/fsutil/superblock.c | 315 + tools/icache/Makefile | 18 + tools/icache/ice2aout.c | 521 + tools/icache/license.txt | 26 + tools/icache/readme.txt | 10 + tools/libufs/Makefile | 20 + tools/libufs/fops.c | 665 + tools/libufs/fs.c | 464 + tools/libufs/libufs.h | 350 + tools/libufs/set.c | 84 + tools/libufs/ucat.c | 56 + tools/libufs/ucd.c | 60 + tools/libufs/uchgrp.c | 51 + tools/libufs/uchmod.c | 51 + tools/libufs/uchown.c | 51 + tools/libufs/ulogin.c | 37 + tools/libufs/uls.c | 40 + tools/libufs/umkdir.c | 42 + tools/libufs/umkfs.c | 48 + tools/libufs/util.c | 62 + tools/mkrd/Makefile | 11 + tools/mkrd/mkrd.c | 174 + tools/mkrd/rdisk.h | 39 + tools/virtualmips/.indent.pro | 24 + tools/virtualmips/.le.ini | 39 + tools/virtualmips/LICENSE | 4 + tools/virtualmips/Makefile | 78 + tools/virtualmips/README | 1 + tools/virtualmips/SConstruct | 122 + tools/virtualmips/adm5120/adm5120.c | 366 + tools/virtualmips/adm5120/adm5120.conf | 34 + tools/virtualmips/adm5120/adm5120.h | 425 + .../virtualmips/adm5120/adm5120_dev_intctrl.c | 89 + tools/virtualmips/adm5120/adm5120_dev_mpmc.c | 76 + tools/virtualmips/adm5120/adm5120_dev_pci.c | 79 + tools/virtualmips/adm5120/adm5120_dev_sw.c | 101 + tools/virtualmips/adm5120/adm5120_dev_uart.c | 257 + .../virtualmips/adm5120/adm5120_host_alarm.c | 92 + tools/virtualmips/bsd_syscalls.h | 164 + tools/virtualmips/config.c | 315 + tools/virtualmips/config.h | 31 + tools/virtualmips/cpu.c | 304 + tools/virtualmips/cpu.h | 60 + tools/virtualmips/crc.c | 100 + tools/virtualmips/crc.h | 62 + tools/virtualmips/debug.c | 89 + tools/virtualmips/debug.h | 20 + tools/virtualmips/dev_cs8900.c | 917 + tools/virtualmips/dev_cs8900.h | 54 + tools/virtualmips/dev_nand_flash_1g.c | 494 + tools/virtualmips/dev_nand_flash_1g.h | 78 + tools/virtualmips/dev_nor_flash_4m.c | 326 + tools/virtualmips/dev_ram.c | 59 + tools/virtualmips/dev_sdcard.c | 352 + tools/virtualmips/dev_sdcard.h | 34 + tools/virtualmips/dev_swap.c | 123 + tools/virtualmips/dev_swap.h | 34 + tools/virtualmips/dev_vtty.c | 1037 + tools/virtualmips/dev_vtty.h | 128 + tools/virtualmips/device.c | 237 + tools/virtualmips/device.h | 76 + tools/virtualmips/gdb_interface.c | 723 + tools/virtualmips/gdb_interface.h | 31 + tools/virtualmips/jz4740/jz4740.c | 105 + tools/virtualmips/jz4740/jz4740.h | 760 + tools/virtualmips/jz4740/jz4740_dev_cpm.c | 91 + tools/virtualmips/jz4740/jz4740_dev_dma.c | 294 + tools/virtualmips/jz4740/jz4740_dev_emc.c | 111 + tools/virtualmips/jz4740/jz4740_dev_gpio.c | 529 + tools/virtualmips/jz4740/jz4740_dev_int.c | 141 + tools/virtualmips/jz4740/jz4740_dev_lcd.c | 246 + tools/virtualmips/jz4740/jz4740_dev_rtc.c | 207 + tools/virtualmips/jz4740/jz4740_dev_ts.c | 235 + tools/virtualmips/jz4740/jz4740_dev_uart.c | 293 + tools/virtualmips/jz4740/jz4740_dev_wdt_tcu.c | 515 + tools/virtualmips/main.c | 95 + tools/virtualmips/mempool.c | 246 + tools/virtualmips/mempool.h | 96 + tools/virtualmips/mips-dis.c | 1529 + tools/virtualmips/mips-opc.c | 2068 + tools/virtualmips/mips-opcode.h | 1097 + tools/virtualmips/mips.c | 603 + tools/virtualmips/mips.h | 503 + tools/virtualmips/mips16-opc.c | 259 + tools/virtualmips/mips_codetable.c | 2169 + tools/virtualmips/mips_cp0.c | 550 + tools/virtualmips/mips_cp0.h | 42 + tools/virtualmips/mips_exec.c | 25 + tools/virtualmips/mips_exec.h | 37 + tools/virtualmips/mips_fdd.c | 299 + tools/virtualmips/mips_fdd.h | 17 + tools/virtualmips/mips_hostalarm.c | 257 + tools/virtualmips/mips_hostalarm.h | 17 + tools/virtualmips/mips_jit.c | 749 + tools/virtualmips/mips_jit.h | 279 + tools/virtualmips/mips_memory.c | 1520 + tools/virtualmips/mips_memory.h | 111 + tools/virtualmips/net.h | 38 + tools/virtualmips/net_io.c | 1529 + tools/virtualmips/net_io.h | 293 + tools/virtualmips/pavo.c | 397 + tools/virtualmips/pavo.conf | 32 + tools/virtualmips/pavo.h | 49 + tools/virtualmips/pic32.c | 689 + tools/virtualmips/pic32.h | 153 + tools/virtualmips/pic32_dev_adc.c | 157 + tools/virtualmips/pic32_dev_bmxcon.c | 157 + tools/virtualmips/pic32_dev_devcfg.c | 101 + tools/virtualmips/pic32_dev_dmacon.c | 127 + tools/virtualmips/pic32_dev_flash.c | 137 + tools/virtualmips/pic32_dev_gpio.c | 568 + tools/virtualmips/pic32_dev_intcon.c | 174 + tools/virtualmips/pic32_dev_prefetch.c | 105 + tools/virtualmips/pic32_dev_rtcc.c | 143 + tools/virtualmips/pic32_dev_spi.c | 227 + tools/virtualmips/pic32_dev_syscon.c | 191 + tools/virtualmips/pic32_dev_timer.c | 190 + tools/virtualmips/pic32_dev_uart.c | 328 + tools/virtualmips/pic32_explorer16.conf | 42 + tools/virtualmips/pic32_max32.conf | 41 + tools/virtualmips/pic32_maximite.conf | 42 + tools/virtualmips/pic32_ubw32.conf | 56 + tools/virtualmips/pic32mx.h | 906 + tools/virtualmips/sbox.c | 87 + tools/virtualmips/sbox.h | 49 + tools/virtualmips/system.h | 24 + tools/virtualmips/types.h | 78 + tools/virtualmips/utils.c | 516 + tools/virtualmips/utils.h | 348 + tools/virtualmips/vm.c | 458 + tools/virtualmips/vm.h | 129 + tools/virtualmips/vp_clock.c | 72 + tools/virtualmips/vp_clock.h | 31 + tools/virtualmips/vp_lock.h | 45 + tools/virtualmips/vp_sdl.c | 142 + tools/virtualmips/vp_sdl.h | 93 + tools/virtualmips/vp_timer.c | 129 + tools/virtualmips/vp_timer.h | 39 + tools/virtualmips/x86-codegen.h | 1708 + tools/virtualmips/x86_trans.c | 3025 ++ tools/virtualmips/x86_trans.h | 75 + var/log/messages | 0 var/log/wtmp | 0 3153 files changed, 748589 insertions(+) create mode 100644 Makefile create mode 100644 README create mode 100644 cross.mk create mode 100755 etc/MAKEDEV create mode 100755 etc/MAKEDEV.local create mode 100644 etc/Makefile create mode 100644 etc/fstab create mode 100644 etc/gettytab create mode 100644 etc/group create mode 100644 etc/motd create mode 100644 etc/passwd create mode 100755 etc/rc create mode 100755 etc/rc.local create mode 100644 etc/root/Makefile create mode 100644 etc/root/dot.cshrc create mode 100644 etc/root/dot.login create mode 100644 etc/root/dot.profile create mode 100644 etc/shadow create mode 100644 etc/shells create mode 100644 etc/syslog.conf create mode 100644 etc/ttys create mode 100644 include/Makefile create mode 100644 include/Makefile.install create mode 100644 include/a.out.h create mode 100644 include/alloca.h create mode 100644 include/ar.h create mode 100644 include/arpa/inet.h create mode 100644 include/assert.h create mode 100644 include/ctype.h create mode 100644 include/curses.h create mode 100644 include/dbm.h create mode 120000 include/errno.h create mode 100644 include/fcntl.h create mode 100644 include/float.h create mode 100644 include/fstab.h create mode 100644 include/grp.h create mode 100644 include/kmem.h create mode 100644 include/lastlog.h create mode 100644 include/limits.h create mode 120000 include/machine create mode 100644 include/math.h create mode 100644 include/mtab.h create mode 100644 include/ndbm.h create mode 100644 include/netinet/in.h create mode 100644 include/nlist.h create mode 100644 include/paths.h create mode 100644 include/pcc.h create mode 120000 include/pic32 create mode 100644 include/psout.h create mode 100644 include/pwd.h create mode 100644 include/ranlib.h create mode 100644 include/regexp.h create mode 100644 include/setjmp.h create mode 100644 include/sgtty.h create mode 120000 include/signal.h create mode 100644 include/smallc/curses.h create mode 100644 include/smallc/fcntl.h create mode 100644 include/smallc/signal.h create mode 100644 include/smallc/stdio.h create mode 100644 include/smallc/sys/gpio.h create mode 100644 include/smallc/sys/spi.h create mode 100644 include/smallc/wiznet.h create mode 100644 include/stab.h create mode 100644 include/stdarg.h create mode 100644 include/stddef.h create mode 100644 include/stdint.h create mode 100644 include/stdio.h create mode 100644 include/stdlib.h create mode 100644 include/string.h create mode 100644 include/strings.h create mode 100644 include/struct.h create mode 120000 include/sys create mode 100644 include/syscall.h create mode 100644 include/sysexits.h create mode 120000 include/syslog.h create mode 100644 include/tcl/tcl.h create mode 100644 include/term.h create mode 100644 include/termios-todo.h create mode 100644 include/time.h create mode 100644 include/ttyent.h create mode 100644 include/tzfile.h create mode 100644 include/unistd.h create mode 100644 include/utmp.h create mode 100644 include/vmf.h create mode 100644 include/wiznet/client.h create mode 100644 include/wiznet/ethernet.h create mode 100644 include/wiznet/server.h create mode 100644 include/wiznet/socket.h create mode 100644 include/wiznet/udp.h create mode 100644 include/wiznet/w5100.h create mode 100644 lib/Makefile create mode 100644 lib/libc/Makefile create mode 100644 lib/libcurses/Makefile create mode 100644 lib/libtermlib/Makefile create mode 100644 lib/libwiznet/Makefile create mode 100644 lib/startup/Makefile create mode 100644 share/example/Makefile create mode 100644 share/example/Makefile-host create mode 100644 share/example/ashello.S create mode 100644 share/example/blkjack.bas create mode 100644 share/example/chello.c create mode 100644 share/example/cplus.cpp create mode 100644 share/example/echo.S create mode 100644 share/example/fact.fth create mode 100644 share/example/hilow.bas create mode 100644 share/example/prime.scm create mode 100644 share/example/stars.bas create mode 100644 share/smallc/Makefile create mode 100644 share/smallc/adc.c create mode 100644 share/smallc/gpio.c create mode 100644 share/smallc/hello.c create mode 100644 share/smallc/primelist.c create mode 100644 share/smallc/primesum.c create mode 100644 share/smallc/q8.c create mode 100644 share/smallc/rain.c create mode 100644 share/smallc/test1.c create mode 100644 share/smallc/test2.c create mode 100644 share/smallc/test3.c create mode 100644 share/smallc/webserver.c create mode 100644 src/Makefile create mode 100644 src/cmd/Makefile create mode 100644 src/cmd/Makefile-sbin create mode 100644 src/cmd/adb/Makefile create mode 100644 src/cmd/adb/READ_ME create mode 100644 src/cmd/adb/access.c create mode 100644 src/cmd/adb/command.c create mode 100644 src/cmd/adb/cross/Makefile create mode 100644 src/cmd/adb/defs.h create mode 100644 src/cmd/adb/doc/adb-figures.ms create mode 100644 src/cmd/adb/doc/adb-figures.txt create mode 100644 src/cmd/adb/doc/adb-summary.txt create mode 100644 src/cmd/adb/doc/adb.ms create mode 100644 src/cmd/adb/doc/adb.pdf create mode 100644 src/cmd/adb/doc/adb.txt create mode 100644 src/cmd/adb/expr.c create mode 100644 src/cmd/adb/findfn.c create mode 100644 src/cmd/adb/format.c create mode 100644 src/cmd/adb/input.c create mode 100644 src/cmd/adb/main.c create mode 100644 src/cmd/adb/message.c create mode 100644 src/cmd/adb/opset.c create mode 100644 src/cmd/adb/output.c create mode 100644 src/cmd/adb/pcs.c create mode 100644 src/cmd/adb/print.c create mode 100644 src/cmd/adb/runpcs.c create mode 100644 src/cmd/adb/setup.c create mode 100644 src/cmd/adb/sym.c create mode 100644 src/cmd/adc-demo/Makefile create mode 100644 src/cmd/adc-demo/adc-demo.c create mode 100644 src/cmd/ar/Makefile create mode 100644 src/cmd/ar/append.c create mode 100644 src/cmd/ar/ar.1 create mode 100644 src/cmd/ar/ar.5.5 create mode 100644 src/cmd/ar/ar.c create mode 100644 src/cmd/ar/archive.c create mode 100644 src/cmd/ar/archive.h create mode 100644 src/cmd/ar/contents.c create mode 100644 src/cmd/ar/delete.c create mode 100644 src/cmd/ar/extern.h create mode 100644 src/cmd/ar/extract.c create mode 100644 src/cmd/ar/misc.c create mode 100644 src/cmd/ar/move.c create mode 100644 src/cmd/ar/print.c create mode 100644 src/cmd/ar/replace.c create mode 100644 src/cmd/ar/strmode.c create mode 100644 src/cmd/as/Makefile create mode 100644 src/cmd/as/aout.c create mode 100644 src/cmd/as/as.c create mode 100644 src/cmd/as/mips-dis.c create mode 100644 src/cmd/as/mips-instruction-set.txt create mode 100644 src/cmd/as/mips-opc.c create mode 100644 src/cmd/as/mips-opcode.h create mode 100644 src/cmd/as/mips16-opc.c create mode 100644 src/cmd/as/tests/Makefile create mode 100644 src/cmd/as/tests/hello.c create mode 100644 src/cmd/as/tests/test1.s create mode 100644 src/cmd/as/tests/test2.s create mode 100644 src/cmd/as/tests/test3.s create mode 100644 src/cmd/as/tests/test4.s create mode 100644 src/cmd/awk/EXPLAIN create mode 100644 src/cmd/awk/Makefile create mode 100644 src/cmd/awk/README create mode 100644 src/cmd/awk/awk.def.h create mode 100644 src/cmd/awk/awk.g.y create mode 100644 src/cmd/awk/awk.lx.l create mode 100644 src/cmd/awk/b.c create mode 100644 src/cmd/awk/freeze.c create mode 100644 src/cmd/awk/lib.c create mode 100644 src/cmd/awk/main.c create mode 100644 src/cmd/awk/parse.c create mode 100644 src/cmd/awk/proc.c create mode 100644 src/cmd/awk/run.c create mode 100644 src/cmd/awk/tokenscript create mode 100644 src/cmd/awk/tran.c create mode 100644 src/cmd/basename.c create mode 100644 src/cmd/basic/Makefile create mode 100644 src/cmd/basic/basic.c create mode 100644 src/cmd/basic/blkjack.bas create mode 100644 src/cmd/basic/hilow.bas create mode 100644 src/cmd/basic/readme.txt create mode 100644 src/cmd/basic/renumber.c create mode 100644 src/cmd/basic/stars.bas create mode 100644 src/cmd/bc.y create mode 100644 src/cmd/cal.c create mode 100644 src/cmd/cat.c create mode 100644 src/cmd/cb.c create mode 100644 src/cmd/cc/Makefile create mode 100644 src/cmd/cc/cc.1 create mode 100644 src/cmd/cc/cc.c create mode 100644 src/cmd/ccom/Makefile create mode 100644 src/cmd/ccom/arch-arm/code.c create mode 100644 src/cmd/ccom/arch-arm/local.c create mode 100644 src/cmd/ccom/arch-arm/local2.c create mode 100644 src/cmd/ccom/arch-arm/macdefs.h create mode 100644 src/cmd/ccom/arch-arm/order.c create mode 100644 src/cmd/ccom/arch-arm/table.c create mode 100644 src/cmd/ccom/arch-mips/TODO create mode 100644 src/cmd/ccom/arch-mips/code.c create mode 100644 src/cmd/ccom/arch-mips/local.c create mode 100644 src/cmd/ccom/arch-mips/local2.c create mode 100644 src/cmd/ccom/arch-mips/macdefs.h create mode 100644 src/cmd/ccom/arch-mips/order.c create mode 100644 src/cmd/ccom/arch-mips/table.c create mode 100644 src/cmd/ccom/builtins.c create mode 100644 src/cmd/ccom/ccom.1 create mode 100644 src/cmd/ccom/cgram.y create mode 100644 src/cmd/ccom/config.h create mode 100644 src/cmd/ccom/external.c create mode 100644 src/cmd/ccom/external.h create mode 100644 src/cmd/ccom/gcc_compat.c create mode 100644 src/cmd/ccom/init.c create mode 100644 src/cmd/ccom/inline.c create mode 100644 src/cmd/ccom/main.c create mode 100644 src/cmd/ccom/mip/common.c create mode 100644 src/cmd/ccom/mip/compat.c create mode 100644 src/cmd/ccom/mip/compat.h create mode 100644 src/cmd/ccom/mip/manifest.h create mode 100644 src/cmd/ccom/mip/match.c create mode 100644 src/cmd/ccom/mip/mkext.c create mode 100644 src/cmd/ccom/mip/node.h create mode 100644 src/cmd/ccom/mip/optim2.c create mode 100644 src/cmd/ccom/mip/pass2.h create mode 100644 src/cmd/ccom/mip/reader.c create mode 100644 src/cmd/ccom/mip/regs.c create mode 100644 src/cmd/ccom/optim.c create mode 100644 src/cmd/ccom/pass1.h create mode 100644 src/cmd/ccom/pftn.c create mode 100644 src/cmd/ccom/scan.l create mode 100644 src/cmd/ccom/softfloat.c create mode 100644 src/cmd/ccom/stabs.c create mode 100644 src/cmd/ccom/symtabs.c create mode 100644 src/cmd/ccom/trees.c create mode 100644 src/cmd/chflags/Makefile create mode 100644 src/cmd/chflags/chflags.1 create mode 100644 src/cmd/chflags/chflags.c create mode 100644 src/cmd/chgrp.c create mode 100644 src/cmd/chmod.c create mode 100644 src/cmd/chown/Makefile create mode 100644 src/cmd/chown/chown.8 create mode 100644 src/cmd/chown/chown.c create mode 100644 src/cmd/chpass/Makefile create mode 100644 src/cmd/chpass/chpass.1 create mode 100644 src/cmd/chpass/chpass.c create mode 100644 src/cmd/chpass/chpass.h create mode 100644 src/cmd/chpass/field.c create mode 100644 src/cmd/chpass/util.c create mode 100644 src/cmd/chroot/Makefile create mode 100644 src/cmd/chroot/chroot.8 create mode 100644 src/cmd/chroot/chroot.c create mode 100644 src/cmd/cmp.c create mode 100644 src/cmd/col.c create mode 100644 src/cmd/comm.c create mode 100644 src/cmd/compress/Makefile create mode 100644 src/cmd/compress/README create mode 100644 src/cmd/compress/USERMEM create mode 100644 src/cmd/compress/compress.c create mode 100644 src/cmd/compress/usermem.sh create mode 100644 src/cmd/cp.c create mode 100644 src/cmd/cpp/Makefile create mode 100644 src/cmd/cpp/cpp.1 create mode 100644 src/cmd/cpp/cpp.c create mode 100644 src/cmd/cpp/cpp.h create mode 100644 src/cmd/cpp/cpy.y create mode 100644 src/cmd/cpp/scanner.l create mode 100644 src/cmd/cpp/tests/res1 create mode 100644 src/cmd/cpp/tests/res10 create mode 100644 src/cmd/cpp/tests/res2 create mode 100644 src/cmd/cpp/tests/res3 create mode 100644 src/cmd/cpp/tests/res4 create mode 100644 src/cmd/cpp/tests/res5 create mode 100644 src/cmd/cpp/tests/res6 create mode 100644 src/cmd/cpp/tests/res7 create mode 100644 src/cmd/cpp/tests/res8 create mode 100644 src/cmd/cpp/tests/res9 create mode 100644 src/cmd/cpp/tests/test1 create mode 100644 src/cmd/cpp/tests/test10 create mode 100644 src/cmd/cpp/tests/test2 create mode 100644 src/cmd/cpp/tests/test3 create mode 100644 src/cmd/cpp/tests/test4 create mode 100644 src/cmd/cpp/tests/test5 create mode 100644 src/cmd/cpp/tests/test6 create mode 100644 src/cmd/cpp/tests/test7 create mode 100644 src/cmd/cpp/tests/test8 create mode 100644 src/cmd/cpp/tests/test9 create mode 100644 src/cmd/cpp/token.c create mode 100755 src/cmd/cron/Makefile create mode 100755 src/cmd/cron/README create mode 100755 src/cmd/cron/README.2BSD create mode 100755 src/cmd/cron/bitstring.3 create mode 100755 src/cmd/cron/bitstring.h create mode 100755 src/cmd/cron/compat.c create mode 100755 src/cmd/cron/compat.h create mode 100755 src/cmd/cron/config.h create mode 100755 src/cmd/cron/cron.8 create mode 100755 src/cmd/cron/cron.c create mode 100755 src/cmd/cron/cron.h create mode 100755 src/cmd/cron/crontab.1 create mode 100755 src/cmd/cron/crontab.5 create mode 100755 src/cmd/cron/crontab.c create mode 100755 src/cmd/cron/database.c create mode 100755 src/cmd/cron/do_command.c create mode 100755 src/cmd/cron/entry.c create mode 100755 src/cmd/cron/env.c create mode 100755 src/cmd/cron/externs.h create mode 100755 src/cmd/cron/grot/CHANGES create mode 100755 src/cmd/cron/grot/CONVERSION create mode 100755 src/cmd/cron/grot/FEATURES create mode 100755 src/cmd/cron/grot/INSTALL create mode 100755 src/cmd/cron/grot/MAIL create mode 100755 src/cmd/cron/grot/MANIFEST create mode 100755 src/cmd/cron/grot/THANKS create mode 100755 src/cmd/cron/grot/diffs create mode 100755 src/cmd/cron/job.c create mode 100755 src/cmd/cron/misc.c create mode 100755 src/cmd/cron/pathnames.h create mode 100755 src/cmd/cron/popen.c create mode 100755 src/cmd/cron/putman.sh create mode 100755 src/cmd/cron/user.c create mode 100644 src/cmd/csh/Makefile create mode 100644 src/cmd/csh/alloc.c create mode 100644 src/cmd/csh/printf.c create mode 100644 src/cmd/csh/sh.c create mode 100644 src/cmd/csh/sh.char.c create mode 100644 src/cmd/csh/sh.char.h create mode 100644 src/cmd/csh/sh.dir.c create mode 100644 src/cmd/csh/sh.dir.h create mode 100644 src/cmd/csh/sh.dol.c create mode 100644 src/cmd/csh/sh.err.c create mode 100644 src/cmd/csh/sh.exec.c create mode 100644 src/cmd/csh/sh.exec.h create mode 100644 src/cmd/csh/sh.exec2.c create mode 100644 src/cmd/csh/sh.exp.c create mode 100644 src/cmd/csh/sh.file.c create mode 100644 src/cmd/csh/sh.func.c create mode 100644 src/cmd/csh/sh.glob.c create mode 100644 src/cmd/csh/sh.h create mode 100644 src/cmd/csh/sh.hist.c create mode 100644 src/cmd/csh/sh.init.c create mode 100644 src/cmd/csh/sh.lex.c create mode 100644 src/cmd/csh/sh.local.h create mode 100644 src/cmd/csh/sh.misc.c create mode 100644 src/cmd/csh/sh.parse.c create mode 100644 src/cmd/csh/sh.print.c create mode 100644 src/cmd/csh/sh.proc.c create mode 100644 src/cmd/csh/sh.proc.h create mode 100644 src/cmd/csh/sh.sem.c create mode 100644 src/cmd/csh/sh.set.c create mode 100644 src/cmd/csh/sh.time.c create mode 100644 src/cmd/date.c create mode 100644 src/cmd/date2/Makefile create mode 100644 src/cmd/date2/date.c create mode 100644 src/cmd/dc/Makefile create mode 100644 src/cmd/dc/dc.c create mode 100644 src/cmd/dc/dc.h create mode 100644 src/cmd/dd.c create mode 100644 src/cmd/devupdate/Makefile create mode 100644 src/cmd/devupdate/devupdate.c create mode 100644 src/cmd/df.c create mode 100644 src/cmd/diff/Makefile create mode 100644 src/cmd/diff/diff.c create mode 100644 src/cmd/diff/diff.h create mode 100644 src/cmd/diff/diffdir.c create mode 100644 src/cmd/diff/diffh.c create mode 100644 src/cmd/diff/diffreg.c create mode 100644 src/cmd/disktool/Makefile create mode 100644 src/cmd/disktool/disktool.c create mode 100644 src/cmd/du.c create mode 100644 src/cmd/echo.c create mode 100644 src/cmd/ed.c create mode 100644 src/cmd/egrep.y create mode 100644 src/cmd/env/Makefile create mode 100644 src/cmd/env/env.1 create mode 100644 src/cmd/env/env.c create mode 100644 src/cmd/expr.y create mode 100644 src/cmd/false.sh create mode 100644 src/cmd/fdisk/Makefile create mode 100644 src/cmd/fdisk/fdisk.1 create mode 100644 src/cmd/fdisk/fdisk.c create mode 100644 src/cmd/fdisk/fdisk.h create mode 100644 src/cmd/fgrep.c create mode 100644 src/cmd/file.c create mode 100644 src/cmd/find/Makefile create mode 100644 src/cmd/find/bigram.c create mode 100644 src/cmd/find/code.c create mode 100644 src/cmd/find/find.c create mode 100644 src/cmd/find/updatedb.sh create mode 100644 src/cmd/forth/Makefile create mode 100644 src/cmd/forth/fact.fth create mode 100644 src/cmd/forth/forth.c create mode 100644 src/cmd/forth/forth.h create mode 100644 src/cmd/forth/func.c create mode 100644 src/cmd/forth/func.txt create mode 100644 src/cmd/forth/io.h create mode 100644 src/cmd/fsck/Makefile create mode 100644 src/cmd/fsck/cross.c create mode 100644 src/cmd/fsck/dir.c create mode 100644 src/cmd/fsck/fsck.h create mode 100644 src/cmd/fsck/inode.c create mode 100644 src/cmd/fsck/main.c create mode 100644 src/cmd/fsck/pass1.c create mode 100644 src/cmd/fsck/pass1b.c create mode 100644 src/cmd/fsck/pass2.c create mode 100644 src/cmd/fsck/pass3.c create mode 100644 src/cmd/fsck/pass4.c create mode 100644 src/cmd/fsck/pass5.c create mode 100644 src/cmd/fsck/setup.c create mode 100644 src/cmd/fsck/utilities.c create mode 100644 src/cmd/fstat/Makefile create mode 100644 src/cmd/fstat/fstat.8 create mode 100644 src/cmd/fstat/fstat.c create mode 100644 src/cmd/getty/Makefile create mode 100644 src/cmd/getty/get_date.c create mode 100644 src/cmd/getty/gettytab.c create mode 100644 src/cmd/getty/gettytab.h create mode 100644 src/cmd/getty/init.c create mode 100644 src/cmd/getty/main.c create mode 100644 src/cmd/getty/subr.c create mode 100644 src/cmd/glcdtest/Makefile create mode 100644 src/cmd/glcdtest/glcdtest.1 create mode 100644 src/cmd/glcdtest/glcdtest.c create mode 100644 src/cmd/grep.c create mode 100644 src/cmd/gtest/Makefile create mode 100644 src/cmd/gtest/globdump.c create mode 100644 src/cmd/gtest/globread.c create mode 100644 src/cmd/gtest/globwrite.c create mode 100644 src/cmd/head.c create mode 100644 src/cmd/hostid.c create mode 100644 src/cmd/hostname/Makefile create mode 100644 src/cmd/hostname/hostname.1 create mode 100644 src/cmd/hostname/hostname.c create mode 100644 src/cmd/id/Makefile create mode 100644 src/cmd/id/groups.1 create mode 100644 src/cmd/id/groups.sh create mode 100644 src/cmd/id/id.1 create mode 100644 src/cmd/id/id.c create mode 100644 src/cmd/id/whoami.1 create mode 100644 src/cmd/id/whoami.sh create mode 100644 src/cmd/init/Makefile create mode 100644 src/cmd/init/init.8 create mode 100644 src/cmd/init/init.c create mode 100644 src/cmd/iostat.c create mode 100644 src/cmd/join.c create mode 100644 src/cmd/kill.c create mode 100644 src/cmd/la/Makefile create mode 100644 src/cmd/la/la.1 create mode 100644 src/cmd/la/la.c create mode 100644 src/cmd/last.c create mode 100644 src/cmd/lcc/Makefile create mode 100644 src/cmd/lcc/bprint.1 create mode 100644 src/cmd/lcc/bprint.c create mode 100644 src/cmd/lcc/gcc-solaris.c create mode 100644 src/cmd/lcc/irix.c create mode 100644 src/cmd/lcc/lcc.1 create mode 100644 src/cmd/lcc/lcc.c create mode 100644 src/cmd/lcc/linux.c create mode 100644 src/cmd/lcc/ops.c create mode 100644 src/cmd/lcc/osf.c create mode 100644 src/cmd/lcc/retrobsd.c create mode 100644 src/cmd/lcc/solaris.c create mode 100644 src/cmd/lcc/win32.c create mode 100644 src/cmd/lccom/CPYRIGHT create mode 100644 src/cmd/lccom/LOG create mode 100644 src/cmd/lccom/Makefile create mode 100644 src/cmd/lccom/README create mode 100644 src/cmd/lccom/alloc.c create mode 100644 src/cmd/lccom/alpha.md create mode 100644 src/cmd/lccom/bind.c create mode 100644 src/cmd/lccom/bytecode.c create mode 100644 src/cmd/lccom/c.h create mode 100644 src/cmd/lccom/config.h create mode 100644 src/cmd/lccom/dag.c create mode 100644 src/cmd/lccom/dagcheck.md create mode 100644 src/cmd/lccom/decl.c create mode 100644 src/cmd/lccom/doc/install.html create mode 100644 src/cmd/lccom/enode.c create mode 100644 src/cmd/lccom/error.c create mode 100644 src/cmd/lccom/event.c create mode 100644 src/cmd/lccom/expr.c create mode 100644 src/cmd/lccom/gen.c create mode 100644 src/cmd/lccom/init.c create mode 100644 src/cmd/lccom/inits.c create mode 100644 src/cmd/lccom/input.c create mode 100644 src/cmd/lccom/lburg/gram.y create mode 100644 src/cmd/lccom/lburg/lburg.1 create mode 100644 src/cmd/lccom/lburg/lburg.c create mode 100644 src/cmd/lccom/lburg/lburg.h create mode 100644 src/cmd/lccom/lex.c create mode 100644 src/cmd/lccom/lib/assert.c create mode 100644 src/cmd/lccom/lib/bbexit.c create mode 100644 src/cmd/lccom/lib/yynull.c create mode 100644 src/cmd/lccom/list.c create mode 100644 src/cmd/lccom/main.c create mode 100644 src/cmd/lccom/mips.md create mode 100644 src/cmd/lccom/null.c create mode 100644 src/cmd/lccom/ops.h create mode 100644 src/cmd/lccom/output.c create mode 100644 src/cmd/lccom/prof.c create mode 100644 src/cmd/lccom/profio.c create mode 100644 src/cmd/lccom/simp.c create mode 100644 src/cmd/lccom/sparc.md create mode 100644 src/cmd/lccom/stab.c create mode 100644 src/cmd/lccom/stab.h create mode 100644 src/cmd/lccom/stmt.c create mode 100644 src/cmd/lccom/string.c create mode 100644 src/cmd/lccom/sym.c create mode 100644 src/cmd/lccom/symbolic.c create mode 100644 src/cmd/lccom/token.h create mode 100644 src/cmd/lccom/trace.c create mode 100644 src/cmd/lccom/tree.c create mode 100644 src/cmd/lccom/tst/8q.0 create mode 100644 src/cmd/lccom/tst/8q.c create mode 100644 src/cmd/lccom/tst/array.0 create mode 100644 src/cmd/lccom/tst/array.c create mode 100644 src/cmd/lccom/tst/cf.0 create mode 100644 src/cmd/lccom/tst/cf.c create mode 100644 src/cmd/lccom/tst/cq.0 create mode 100644 src/cmd/lccom/tst/cq.c create mode 100644 src/cmd/lccom/tst/cvt.0 create mode 100644 src/cmd/lccom/tst/cvt.c create mode 100644 src/cmd/lccom/tst/fields.0 create mode 100644 src/cmd/lccom/tst/fields.c create mode 100644 src/cmd/lccom/tst/front.0 create mode 100644 src/cmd/lccom/tst/front.c create mode 100644 src/cmd/lccom/tst/incr.0 create mode 100644 src/cmd/lccom/tst/incr.c create mode 100644 src/cmd/lccom/tst/init.0 create mode 100644 src/cmd/lccom/tst/init.c create mode 100644 src/cmd/lccom/tst/limits.0 create mode 100644 src/cmd/lccom/tst/limits.c create mode 100644 src/cmd/lccom/tst/mips-eb/8q.1bk create mode 100644 src/cmd/lccom/tst/mips-eb/8q.2bk create mode 100644 src/cmd/lccom/tst/mips-eb/8q.sbk create mode 100644 src/cmd/lccom/tst/mips-eb/array.1bk create mode 100644 src/cmd/lccom/tst/mips-eb/array.2bk create mode 100644 src/cmd/lccom/tst/mips-eb/array.sbk create mode 100644 src/cmd/lccom/tst/mips-eb/assert.h create mode 100644 src/cmd/lccom/tst/mips-eb/cf.1bk create mode 100644 src/cmd/lccom/tst/mips-eb/cf.2bk create mode 100644 src/cmd/lccom/tst/mips-eb/cf.sbk create mode 100644 src/cmd/lccom/tst/mips-eb/cq.1bk create mode 100644 src/cmd/lccom/tst/mips-eb/cq.2bk create mode 100644 src/cmd/lccom/tst/mips-eb/cq.sbk create mode 100644 src/cmd/lccom/tst/mips-eb/ctype.h create mode 100644 src/cmd/lccom/tst/mips-eb/cvt.1bk create mode 100644 src/cmd/lccom/tst/mips-eb/cvt.2bk create mode 100644 src/cmd/lccom/tst/mips-eb/cvt.sbk create mode 100644 src/cmd/lccom/tst/mips-eb/errno.h create mode 100644 src/cmd/lccom/tst/mips-eb/fields.1bk create mode 100644 src/cmd/lccom/tst/mips-eb/fields.2bk create mode 100644 src/cmd/lccom/tst/mips-eb/fields.sbk create mode 100644 src/cmd/lccom/tst/mips-eb/float.h create mode 100644 src/cmd/lccom/tst/mips-eb/front.2bk create mode 100644 src/cmd/lccom/tst/mips-eb/front.sbk create mode 100644 src/cmd/lccom/tst/mips-eb/incr.2bk create mode 100644 src/cmd/lccom/tst/mips-eb/incr.sbk create mode 100644 src/cmd/lccom/tst/mips-eb/init.1bk create mode 100644 src/cmd/lccom/tst/mips-eb/init.2bk create mode 100644 src/cmd/lccom/tst/mips-eb/init.sbk create mode 100644 src/cmd/lccom/tst/mips-eb/limits.1bk create mode 100644 src/cmd/lccom/tst/mips-eb/limits.2bk create mode 100644 src/cmd/lccom/tst/mips-eb/limits.h create mode 100644 src/cmd/lccom/tst/mips-eb/limits.sbk create mode 100644 src/cmd/lccom/tst/mips-eb/locale.h create mode 100644 src/cmd/lccom/tst/mips-eb/math.h create mode 100644 src/cmd/lccom/tst/mips-eb/paranoia.1bk create mode 100644 src/cmd/lccom/tst/mips-eb/paranoia.2bk create mode 100644 src/cmd/lccom/tst/mips-eb/paranoia.sbk create mode 100644 src/cmd/lccom/tst/mips-eb/setjmp.h create mode 100644 src/cmd/lccom/tst/mips-eb/signal.h create mode 100644 src/cmd/lccom/tst/mips-eb/sort.1bk create mode 100644 src/cmd/lccom/tst/mips-eb/sort.2bk create mode 100644 src/cmd/lccom/tst/mips-eb/sort.sbk create mode 100644 src/cmd/lccom/tst/mips-eb/spill.2bk create mode 100644 src/cmd/lccom/tst/mips-eb/spill.sbk create mode 100644 src/cmd/lccom/tst/mips-eb/stdarg.1bk create mode 100644 src/cmd/lccom/tst/mips-eb/stdarg.2bk create mode 100644 src/cmd/lccom/tst/mips-eb/stdarg.h create mode 100644 src/cmd/lccom/tst/mips-eb/stdarg.sbk create mode 100644 src/cmd/lccom/tst/mips-eb/stddef.h create mode 100644 src/cmd/lccom/tst/mips-eb/stdio.h create mode 100644 src/cmd/lccom/tst/mips-eb/stdlib.h create mode 100644 src/cmd/lccom/tst/mips-eb/string.h create mode 100644 src/cmd/lccom/tst/mips-eb/struct.1bk create mode 100644 src/cmd/lccom/tst/mips-eb/struct.2bk create mode 100644 src/cmd/lccom/tst/mips-eb/struct.sbk create mode 100644 src/cmd/lccom/tst/mips-eb/switch.1bk create mode 100644 src/cmd/lccom/tst/mips-eb/switch.2bk create mode 100644 src/cmd/lccom/tst/mips-eb/switch.sbk create mode 100644 src/cmd/lccom/tst/mips-eb/time.h create mode 100644 src/cmd/lccom/tst/mips-eb/wf1.1bk create mode 100644 src/cmd/lccom/tst/mips-eb/wf1.2bk create mode 100644 src/cmd/lccom/tst/mips-eb/wf1.sbk create mode 100644 src/cmd/lccom/tst/mips-eb/yacc.1bk create mode 100644 src/cmd/lccom/tst/mips-eb/yacc.2bk create mode 100644 src/cmd/lccom/tst/mips-eb/yacc.sbk create mode 100644 src/cmd/lccom/tst/paranoia.0 create mode 100644 src/cmd/lccom/tst/paranoia.c create mode 100755 src/cmd/lccom/tst/run.sh create mode 100644 src/cmd/lccom/tst/sort.0 create mode 100644 src/cmd/lccom/tst/sort.c create mode 100644 src/cmd/lccom/tst/spill.0 create mode 100644 src/cmd/lccom/tst/spill.c create mode 100644 src/cmd/lccom/tst/stdarg.0 create mode 100644 src/cmd/lccom/tst/stdarg.c create mode 100644 src/cmd/lccom/tst/struct.0 create mode 100644 src/cmd/lccom/tst/struct.c create mode 100644 src/cmd/lccom/tst/switch.0 create mode 100644 src/cmd/lccom/tst/switch.c create mode 100644 src/cmd/lccom/tst/wf1.0 create mode 100644 src/cmd/lccom/tst/wf1.c create mode 100644 src/cmd/lccom/tst/x86-linux/8q.1bk create mode 100644 src/cmd/lccom/tst/x86-linux/8q.2bk create mode 100644 src/cmd/lccom/tst/x86-linux/8q.sbk create mode 100644 src/cmd/lccom/tst/x86-linux/array.1bk create mode 100644 src/cmd/lccom/tst/x86-linux/array.2bk create mode 100644 src/cmd/lccom/tst/x86-linux/array.sbk create mode 100644 src/cmd/lccom/tst/x86-linux/assert.h create mode 100644 src/cmd/lccom/tst/x86-linux/cf.1bk create mode 100644 src/cmd/lccom/tst/x86-linux/cf.2bk create mode 100644 src/cmd/lccom/tst/x86-linux/cf.sbk create mode 100644 src/cmd/lccom/tst/x86-linux/cq.1bk create mode 100644 src/cmd/lccom/tst/x86-linux/cq.2bk create mode 100644 src/cmd/lccom/tst/x86-linux/cq.sbk create mode 100644 src/cmd/lccom/tst/x86-linux/cvt.1bk create mode 100644 src/cmd/lccom/tst/x86-linux/cvt.2bk create mode 100644 src/cmd/lccom/tst/x86-linux/cvt.sbk create mode 100644 src/cmd/lccom/tst/x86-linux/fields.1bk create mode 100644 src/cmd/lccom/tst/x86-linux/fields.2bk create mode 100644 src/cmd/lccom/tst/x86-linux/fields.sbk create mode 100644 src/cmd/lccom/tst/x86-linux/float.h create mode 100644 src/cmd/lccom/tst/x86-linux/front.2bk create mode 100644 src/cmd/lccom/tst/x86-linux/front.sbk create mode 100644 src/cmd/lccom/tst/x86-linux/incr.1bk create mode 100644 src/cmd/lccom/tst/x86-linux/incr.2bk create mode 100644 src/cmd/lccom/tst/x86-linux/incr.sbk create mode 100644 src/cmd/lccom/tst/x86-linux/init.1bk create mode 100644 src/cmd/lccom/tst/x86-linux/init.2bk create mode 100644 src/cmd/lccom/tst/x86-linux/init.sbk create mode 100644 src/cmd/lccom/tst/x86-linux/limits.1bk create mode 100644 src/cmd/lccom/tst/x86-linux/limits.2bk create mode 100644 src/cmd/lccom/tst/x86-linux/limits.h create mode 100644 src/cmd/lccom/tst/x86-linux/limits.sbk create mode 100644 src/cmd/lccom/tst/x86-linux/math.h create mode 100644 src/cmd/lccom/tst/x86-linux/paranoia.1bk create mode 100644 src/cmd/lccom/tst/x86-linux/paranoia.2bk create mode 100644 src/cmd/lccom/tst/x86-linux/paranoia.sbk create mode 100644 src/cmd/lccom/tst/x86-linux/sort.1bk create mode 100644 src/cmd/lccom/tst/x86-linux/sort.2bk create mode 100644 src/cmd/lccom/tst/x86-linux/sort.sbk create mode 100644 src/cmd/lccom/tst/x86-linux/spill.1bk create mode 100644 src/cmd/lccom/tst/x86-linux/spill.2bk create mode 100644 src/cmd/lccom/tst/x86-linux/spill.sbk create mode 100644 src/cmd/lccom/tst/x86-linux/stdarg.1bk create mode 100644 src/cmd/lccom/tst/x86-linux/stdarg.2bk create mode 100644 src/cmd/lccom/tst/x86-linux/stdarg.h create mode 100644 src/cmd/lccom/tst/x86-linux/stdarg.sbk create mode 100644 src/cmd/lccom/tst/x86-linux/struct.1bk create mode 100644 src/cmd/lccom/tst/x86-linux/struct.2bk create mode 100644 src/cmd/lccom/tst/x86-linux/struct.sbk create mode 100644 src/cmd/lccom/tst/x86-linux/switch.1bk create mode 100644 src/cmd/lccom/tst/x86-linux/switch.2bk create mode 100644 src/cmd/lccom/tst/x86-linux/switch.sbk create mode 100644 src/cmd/lccom/tst/x86-linux/wf1.1bk create mode 100644 src/cmd/lccom/tst/x86-linux/wf1.2bk create mode 100644 src/cmd/lccom/tst/x86-linux/wf1.sbk create mode 100644 src/cmd/lccom/tst/x86-linux/yacc.1bk create mode 100644 src/cmd/lccom/tst/x86-linux/yacc.2bk create mode 100644 src/cmd/lccom/tst/x86-linux/yacc.sbk create mode 100644 src/cmd/lccom/tst/yacc.0 create mode 100644 src/cmd/lccom/tst/yacc.c create mode 100644 src/cmd/lccom/types.c create mode 100644 src/cmd/lccom/x86.md create mode 100644 src/cmd/lccom/x86linux.md create mode 100644 src/cmd/lcpp/Makefile create mode 100644 src/cmd/lcpp/cpp.c create mode 100644 src/cmd/lcpp/cpp.h create mode 100644 src/cmd/lcpp/eval.c create mode 100644 src/cmd/lcpp/hideset.c create mode 100644 src/cmd/lcpp/include.c create mode 100644 src/cmd/lcpp/lex.c create mode 100644 src/cmd/lcpp/macro.c create mode 100644 src/cmd/lcpp/nlist.c create mode 100644 src/cmd/lcpp/tokens.c create mode 100644 src/cmd/lcpp/unix.c create mode 100644 src/cmd/ld/Makefile create mode 100644 src/cmd/ld/ld.1 create mode 100644 src/cmd/ld/ld.c create mode 100644 src/cmd/lex/Makefile create mode 100644 src/cmd/lex/header.c create mode 100644 src/cmd/lex/ldefs.c create mode 100644 src/cmd/lex/lmain.c create mode 100644 src/cmd/lex/ncform create mode 100644 src/cmd/lex/nrform create mode 100644 src/cmd/lex/once.c create mode 100644 src/cmd/lex/parser.y create mode 100644 src/cmd/lex/sub1.c create mode 100644 src/cmd/lex/sub2.c create mode 100644 src/cmd/ln.c create mode 100644 src/cmd/login/Makefile create mode 100644 src/cmd/login/login.c create mode 100644 src/cmd/lorder.sh create mode 100644 src/cmd/ls/Makefile create mode 100644 src/cmd/ls/ls.c create mode 100644 src/cmd/ls/stat_flags.c create mode 100644 src/cmd/m4/Makefile create mode 100644 src/cmd/m4/NOTES create mode 100644 src/cmd/m4/TEST/ack.m4 create mode 100644 src/cmd/m4/TEST/hanoi.m4 create mode 100644 src/cmd/m4/TEST/hash.m4 create mode 100644 src/cmd/m4/TEST/sqroot.m4 create mode 100644 src/cmd/m4/TEST/string.m4 create mode 100644 src/cmd/m4/TEST/test.m4 create mode 100644 src/cmd/m4/eval.c create mode 100644 src/cmd/m4/expr.c create mode 100644 src/cmd/m4/extern.h create mode 100644 src/cmd/m4/look.c create mode 100644 src/cmd/m4/main.c create mode 100644 src/cmd/m4/mdef.h create mode 100644 src/cmd/m4/misc.c create mode 100644 src/cmd/m4/pathnames.h create mode 100644 src/cmd/m4/stdd.h create mode 100644 src/cmd/m4/tags create mode 100644 src/cmd/mail.c create mode 100644 src/cmd/make/Makefile create mode 100644 src/cmd/make/defs.h create mode 100644 src/cmd/make/doname.c create mode 100644 src/cmd/make/dosys.c create mode 100644 src/cmd/make/files.c create mode 100644 src/cmd/make/gram.y create mode 100644 src/cmd/make/history.txt create mode 100644 src/cmd/make/main.c create mode 100644 src/cmd/make/misc.c create mode 100644 src/cmd/man/Makefile create mode 100644 src/cmd/man/apropos.c create mode 100644 src/cmd/man/man.c create mode 100644 src/cmd/med/Makefile create mode 100644 src/cmd/med/med.c create mode 100644 src/cmd/mesg.c create mode 100644 src/cmd/mkdep.sh create mode 100644 src/cmd/mkdir.c create mode 100644 src/cmd/mkfs/Makefile create mode 100644 src/cmd/mkfs/mkfs.8 create mode 100644 src/cmd/mkfs/mkfs.c create mode 100644 src/cmd/mknod/Makefile create mode 100644 src/cmd/mknod/mknod.8 create mode 100644 src/cmd/mknod/mknod.c create mode 100644 src/cmd/mkpasswd/Makefile create mode 100644 src/cmd/mkpasswd/mkpasswd.8 create mode 100644 src/cmd/mkpasswd/mkpasswd.c create mode 100644 src/cmd/more/Makefile create mode 100644 src/cmd/more/more.c create mode 100644 src/cmd/more/more.help create mode 100644 src/cmd/mount/Makefile create mode 100644 src/cmd/mount/getmntopts.3 create mode 100644 src/cmd/mount/getmntopts.c create mode 100644 src/cmd/mount/mntopts.h create mode 100644 src/cmd/mount/mount.8 create mode 100644 src/cmd/mount/mount.c create mode 100644 src/cmd/mount/mount_ufs.c create mode 100644 src/cmd/msec/Makefile create mode 100644 src/cmd/msec/msec.1 create mode 100644 src/cmd/msec/msec.c create mode 100644 src/cmd/mv.c create mode 100644 src/cmd/nice.c create mode 100644 src/cmd/nm.c.use.disk create mode 100644 src/cmd/nm/Makefile create mode 100644 src/cmd/nm/nm.c create mode 100644 src/cmd/nohup.sh create mode 100644 src/cmd/od.c create mode 100644 src/cmd/pagesize.c create mode 100644 src/cmd/passwd/Makefile create mode 100644 src/cmd/passwd/passwd.1 create mode 100644 src/cmd/passwd/passwd.c create mode 100644 src/cmd/pforth/..bin create mode 100644 src/cmd/pforth/Makefile create mode 100644 src/cmd/pforth/Makefile-orig create mode 100644 src/cmd/pforth/fth/ansilocs.fth create mode 100644 src/cmd/pforth/fth/bench.fth create mode 100644 src/cmd/pforth/fth/c_struct.fth create mode 100644 src/cmd/pforth/fth/case.fth create mode 100644 src/cmd/pforth/fth/condcomp.fth create mode 100644 src/cmd/pforth/fth/coretest.fth create mode 100644 src/cmd/pforth/fth/filefind.fth create mode 100644 src/cmd/pforth/fth/floats.fth create mode 100644 src/cmd/pforth/fth/forget.fth create mode 100644 src/cmd/pforth/fth/history.fth create mode 100644 src/cmd/pforth/fth/loadhist.fth create mode 100644 src/cmd/pforth/fth/loadp4th.fth create mode 100644 src/cmd/pforth/fth/locals.fth create mode 100644 src/cmd/pforth/fth/math.fth create mode 100644 src/cmd/pforth/fth/member.fth create mode 100644 src/cmd/pforth/fth/misc1.fth create mode 100644 src/cmd/pforth/fth/misc2.fth create mode 100644 src/cmd/pforth/fth/numberio.fth create mode 100644 src/cmd/pforth/fth/private.fth create mode 100644 src/cmd/pforth/fth/savedicd.fth create mode 100644 src/cmd/pforth/fth/see.fth create mode 100644 src/cmd/pforth/fth/siev.fth create mode 100644 src/cmd/pforth/fth/smart_if.fth create mode 100644 src/cmd/pforth/fth/strings.fth create mode 100644 src/cmd/pforth/fth/system.fth create mode 100644 src/cmd/pforth/fth/t_alloc.fth create mode 100644 src/cmd/pforth/fth/t_case.fth create mode 100644 src/cmd/pforth/fth/t_corex.fth create mode 100644 src/cmd/pforth/fth/t_floats.fth create mode 100644 src/cmd/pforth/fth/t_include.fth create mode 100644 src/cmd/pforth/fth/t_load.fth create mode 100644 src/cmd/pforth/fth/t_load_defer.fth create mode 100644 src/cmd/pforth/fth/t_load_pairs.fth create mode 100644 src/cmd/pforth/fth/t_load_semi.fth create mode 100644 src/cmd/pforth/fth/t_load_undef.fth create mode 100644 src/cmd/pforth/fth/t_locals.fth create mode 100644 src/cmd/pforth/fth/t_nolf.fth create mode 100644 src/cmd/pforth/fth/t_strings.fth create mode 100644 src/cmd/pforth/fth/t_tools.fth create mode 100644 src/cmd/pforth/fth/termio.fth create mode 100644 src/cmd/pforth/fth/tester.fth create mode 100644 src/cmd/pforth/fth/trace.fth create mode 100644 src/cmd/pforth/fth/tut.fth create mode 100644 src/cmd/pforth/fth/utils/clone.fth create mode 100644 src/cmd/pforth/fth/utils/dump_struct.fth create mode 100644 src/cmd/pforth/fth/utils/load_file.fth create mode 100644 src/cmd/pforth/fth/utils/make_all256.fth create mode 100644 src/cmd/pforth/fth/utils/trace.fth create mode 100644 src/cmd/pforth/fth/wordslik.fth create mode 100644 src/cmd/pforth/pf_all.h create mode 100644 src/cmd/pforth/pf_cglue.c create mode 100644 src/cmd/pforth/pf_cglue.h create mode 100644 src/cmd/pforth/pf_clib.c create mode 100644 src/cmd/pforth/pf_clib.h create mode 100644 src/cmd/pforth/pf_core.c create mode 100644 src/cmd/pforth/pf_core.h create mode 100644 src/cmd/pforth/pf_float.h create mode 100644 src/cmd/pforth/pf_guts.h create mode 100644 src/cmd/pforth/pf_host.h create mode 100644 src/cmd/pforth/pf_inc1.h create mode 100644 src/cmd/pforth/pf_inner.c create mode 100644 src/cmd/pforth/pf_io.c create mode 100644 src/cmd/pforth/pf_io.h create mode 100644 src/cmd/pforth/pf_io_none.c create mode 100644 src/cmd/pforth/pf_io_posix.c create mode 100644 src/cmd/pforth/pf_io_stdio.c create mode 100644 src/cmd/pforth/pf_main.c create mode 100644 src/cmd/pforth/pf_mem.c create mode 100644 src/cmd/pforth/pf_mem.h create mode 100644 src/cmd/pforth/pf_save.c create mode 100644 src/cmd/pforth/pf_save.h create mode 100644 src/cmd/pforth/pf_text.c create mode 100644 src/cmd/pforth/pf_text.h create mode 100644 src/cmd/pforth/pf_types.h create mode 100644 src/cmd/pforth/pf_win32.h create mode 100644 src/cmd/pforth/pf_words.c create mode 100644 src/cmd/pforth/pf_words.h create mode 100644 src/cmd/pforth/pfcompfp.h create mode 100644 src/cmd/pforth/pfcompil.c create mode 100644 src/cmd/pforth/pfcompil.h create mode 100644 src/cmd/pforth/pfcustom.c create mode 100644 src/cmd/pforth/pfdicdat.h create mode 100644 src/cmd/pforth/pfinnrfp.h create mode 100644 src/cmd/pforth/pforth.dic create mode 100644 src/cmd/pforth/pforth.h create mode 100644 src/cmd/pforth/readme.txt create mode 100644 src/cmd/pforth/releases.txt create mode 100644 src/cmd/picoc/Makefile create mode 100644 src/cmd/picoc/README create mode 100644 src/cmd/picoc/clibrary.c create mode 100644 src/cmd/picoc/cstdlib/ctype.c create mode 100644 src/cmd/picoc/cstdlib/errno.c create mode 100644 src/cmd/picoc/cstdlib/math.c create mode 100644 src/cmd/picoc/cstdlib/stdbool.c create mode 100644 src/cmd/picoc/cstdlib/stdio.c create mode 100644 src/cmd/picoc/cstdlib/stdlib.c create mode 100644 src/cmd/picoc/cstdlib/string.c create mode 100644 src/cmd/picoc/cstdlib/time.c create mode 100644 src/cmd/picoc/cstdlib/unistd.c create mode 100644 src/cmd/picoc/debug.c create mode 100644 src/cmd/picoc/expression.c create mode 100644 src/cmd/picoc/heap.c create mode 100644 src/cmd/picoc/include.c create mode 100644 src/cmd/picoc/interpreter.h create mode 100644 src/cmd/picoc/lex.c create mode 100644 src/cmd/picoc/msvc/picoc/picoc.sln create mode 100644 src/cmd/picoc/msvc/picoc/picoc.vcxproj create mode 100644 src/cmd/picoc/msvc/picoc/picoc.vcxproj.filters create mode 100644 src/cmd/picoc/parse.c create mode 100644 src/cmd/picoc/picoc.c create mode 100644 src/cmd/picoc/picoc.h create mode 100644 src/cmd/picoc/platform.c create mode 100644 src/cmd/picoc/platform.h create mode 100644 src/cmd/picoc/platform/library_ffox.c create mode 100644 src/cmd/picoc/platform/library_msvc.c create mode 100644 src/cmd/picoc/platform/library_srv1.c create mode 100644 src/cmd/picoc/platform/library_surveyor.c create mode 100644 src/cmd/picoc/platform/library_unix.c create mode 100644 src/cmd/picoc/platform/platform_ffox.c create mode 100644 src/cmd/picoc/platform/platform_msvc.c create mode 100644 src/cmd/picoc/platform/platform_surveyor.c create mode 100644 src/cmd/picoc/platform/platform_unix.c create mode 100644 src/cmd/picoc/retrobsd.c create mode 100644 src/cmd/picoc/table.c create mode 100644 src/cmd/picoc/tests/00_assignment.c create mode 100644 src/cmd/picoc/tests/00_assignment.expect create mode 100644 src/cmd/picoc/tests/01_comment.c create mode 100644 src/cmd/picoc/tests/01_comment.expect create mode 100644 src/cmd/picoc/tests/02_printf.c create mode 100644 src/cmd/picoc/tests/02_printf.expect create mode 100644 src/cmd/picoc/tests/03_struct.c create mode 100644 src/cmd/picoc/tests/03_struct.expect create mode 100644 src/cmd/picoc/tests/04_for.c create mode 100644 src/cmd/picoc/tests/04_for.expect create mode 100644 src/cmd/picoc/tests/05_array.c create mode 100644 src/cmd/picoc/tests/05_array.expect create mode 100644 src/cmd/picoc/tests/06_case.c create mode 100644 src/cmd/picoc/tests/06_case.expect create mode 100644 src/cmd/picoc/tests/07_function.c create mode 100644 src/cmd/picoc/tests/07_function.expect create mode 100644 src/cmd/picoc/tests/08_while.c create mode 100644 src/cmd/picoc/tests/08_while.expect create mode 100644 src/cmd/picoc/tests/09_do_while.c create mode 100644 src/cmd/picoc/tests/09_do_while.expect create mode 100644 src/cmd/picoc/tests/10_pointer.c create mode 100644 src/cmd/picoc/tests/10_pointer.expect create mode 100644 src/cmd/picoc/tests/11_precedence.c create mode 100644 src/cmd/picoc/tests/11_precedence.expect create mode 100644 src/cmd/picoc/tests/12_hashdefine.c create mode 100644 src/cmd/picoc/tests/12_hashdefine.expect create mode 100644 src/cmd/picoc/tests/13_integer_literals.c create mode 100644 src/cmd/picoc/tests/13_integer_literals.expect create mode 100644 src/cmd/picoc/tests/14_if.c create mode 100644 src/cmd/picoc/tests/14_if.expect create mode 100644 src/cmd/picoc/tests/15_recursion.c create mode 100644 src/cmd/picoc/tests/15_recursion.expect create mode 100644 src/cmd/picoc/tests/16_nesting.c create mode 100644 src/cmd/picoc/tests/16_nesting.expect create mode 100644 src/cmd/picoc/tests/17_enum.c create mode 100644 src/cmd/picoc/tests/17_enum.expect create mode 100644 src/cmd/picoc/tests/18_include.c create mode 100644 src/cmd/picoc/tests/18_include.expect create mode 100644 src/cmd/picoc/tests/18_include.h create mode 100644 src/cmd/picoc/tests/19_pointer_arithmetic.c create mode 100644 src/cmd/picoc/tests/19_pointer_arithmetic.expect create mode 100644 src/cmd/picoc/tests/20_pointer_comparison.c create mode 100644 src/cmd/picoc/tests/20_pointer_comparison.expect create mode 100644 src/cmd/picoc/tests/21_char_array.c create mode 100644 src/cmd/picoc/tests/21_char_array.expect create mode 100644 src/cmd/picoc/tests/22_floating_point.c create mode 100644 src/cmd/picoc/tests/22_floating_point.expect create mode 100644 src/cmd/picoc/tests/23_type_coercion.c create mode 100644 src/cmd/picoc/tests/23_type_coercion.expect create mode 100644 src/cmd/picoc/tests/24_math_library.c create mode 100644 src/cmd/picoc/tests/24_math_library.expect create mode 100644 src/cmd/picoc/tests/25_quicksort.c create mode 100644 src/cmd/picoc/tests/25_quicksort.expect create mode 100644 src/cmd/picoc/tests/26_character_constants.c create mode 100644 src/cmd/picoc/tests/26_character_constants.expect create mode 100644 src/cmd/picoc/tests/27_sizeof.c create mode 100644 src/cmd/picoc/tests/27_sizeof.expect create mode 100644 src/cmd/picoc/tests/28_strings.c create mode 100644 src/cmd/picoc/tests/28_strings.expect create mode 100644 src/cmd/picoc/tests/29_array_address.c create mode 100644 src/cmd/picoc/tests/29_array_address.expect create mode 100644 src/cmd/picoc/tests/30_hanoi.c create mode 100644 src/cmd/picoc/tests/30_hanoi.expect create mode 100644 src/cmd/picoc/tests/31_args.c create mode 100644 src/cmd/picoc/tests/31_args.expect create mode 100644 src/cmd/picoc/tests/32_led.c create mode 100644 src/cmd/picoc/tests/32_led.expect create mode 100644 src/cmd/picoc/tests/33_ternary_op.c create mode 100644 src/cmd/picoc/tests/33_ternary_op.expect create mode 100644 src/cmd/picoc/tests/34_array_assignment.c create mode 100644 src/cmd/picoc/tests/34_array_assignment.expect create mode 100644 src/cmd/picoc/tests/35_sizeof.c create mode 100644 src/cmd/picoc/tests/35_sizeof.expect create mode 100644 src/cmd/picoc/tests/36_array_initialisers.c create mode 100644 src/cmd/picoc/tests/36_array_initialisers.expect create mode 100644 src/cmd/picoc/tests/37_sprintf.c create mode 100644 src/cmd/picoc/tests/37_sprintf.expect create mode 100644 src/cmd/picoc/tests/38_multiple_array_index.c create mode 100644 src/cmd/picoc/tests/38_multiple_array_index.expect create mode 100644 src/cmd/picoc/tests/39_typedef.c create mode 100644 src/cmd/picoc/tests/39_typedef.expect create mode 100644 src/cmd/picoc/tests/40_stdio.c create mode 100644 src/cmd/picoc/tests/40_stdio.expect create mode 100644 src/cmd/picoc/tests/41_hashif.c create mode 100644 src/cmd/picoc/tests/41_hashif.expect create mode 100644 src/cmd/picoc/tests/42_function_pointer.c create mode 100644 src/cmd/picoc/tests/43_void_param.c create mode 100644 src/cmd/picoc/tests/43_void_param.expect create mode 100644 src/cmd/picoc/tests/44_scoped_declarations.c create mode 100644 src/cmd/picoc/tests/44_scoped_declarations.expect create mode 100644 src/cmd/picoc/tests/45_empty_for.c create mode 100644 src/cmd/picoc/tests/45_empty_for.expect create mode 100644 src/cmd/picoc/tests/46_grep.c create mode 100644 src/cmd/picoc/tests/47_switch_return.c create mode 100644 src/cmd/picoc/tests/47_switch_return.expect create mode 100644 src/cmd/picoc/tests/48_nested_break.c create mode 100644 src/cmd/picoc/tests/48_nested_break.expect create mode 100644 src/cmd/picoc/tests/49_bracket_evaluation.c create mode 100644 src/cmd/picoc/tests/49_bracket_evaluation.expect create mode 100644 src/cmd/picoc/tests/50_logical_second_arg.c create mode 100644 src/cmd/picoc/tests/50_logical_second_arg.expect create mode 100644 src/cmd/picoc/tests/51_static.c create mode 100644 src/cmd/picoc/tests/51_static.expect create mode 100644 src/cmd/picoc/tests/52_unnamed_enum.c create mode 100644 src/cmd/picoc/tests/52_unnamed_enum.expect create mode 100644 src/cmd/picoc/tests/54_goto.c create mode 100644 src/cmd/picoc/tests/54_goto.expect create mode 100644 src/cmd/picoc/tests/55_array_initialiser.c create mode 100644 src/cmd/picoc/tests/55_array_initialiser.expect create mode 100644 src/cmd/picoc/tests/Makefile create mode 100644 src/cmd/picoc/type.c create mode 100644 src/cmd/picoc/variable.c create mode 100644 src/cmd/portio/Makefile create mode 100644 src/cmd/portio/font6x10.c create mode 100644 src/cmd/portio/lol.c create mode 100644 src/cmd/portio/portio.c create mode 100644 src/cmd/pr.c create mode 100644 src/cmd/printenv.c create mode 100644 src/cmd/printf/Makefile create mode 100644 src/cmd/printf/printf.1 create mode 100644 src/cmd/printf/printf.c create mode 100644 src/cmd/ps.c create mode 100644 src/cmd/pstat/Makefile create mode 100644 src/cmd/pstat/pstat.8 create mode 100644 src/cmd/pstat/pstat.c create mode 100644 src/cmd/pwd.c create mode 100644 src/cmd/pwm/Makefile create mode 100644 src/cmd/pwm/pwm.1 create mode 100644 src/cmd/pwm/pwm.c create mode 100644 src/cmd/ranlib/Makefile create mode 100644 src/cmd/ranlib/ranlib.1 create mode 100644 src/cmd/ranlib/ranlib.5.5 create mode 100644 src/cmd/ranlib/ranlib.c create mode 100644 src/cmd/rdprof/Makefile create mode 100644 src/cmd/rdprof/rdprof.1 create mode 100644 src/cmd/rdprof/rdprof.c create mode 100644 src/cmd/re/Makefile create mode 100644 src/cmd/re/Makefile-linux create mode 100644 src/cmd/re/README.txt create mode 100644 src/cmd/re/help.txt create mode 100644 src/cmd/re/r.cmd.c create mode 100644 src/cmd/re/r.defs.h create mode 100644 src/cmd/re/r.display.c create mode 100644 src/cmd/re/r.edit.c create mode 100644 src/cmd/re/r.file.c create mode 100644 src/cmd/re/r.gettc.c create mode 100644 src/cmd/re/r.macro.c create mode 100644 src/cmd/re/r.main.c create mode 100644 src/cmd/re/r.misc.c create mode 100644 src/cmd/re/r.termcap.c create mode 100644 src/cmd/re/r.ttyio.c create mode 100644 src/cmd/re/r.window.c create mode 100644 src/cmd/reboot/Makefile create mode 100644 src/cmd/reboot/reboot.8 create mode 100644 src/cmd/reboot/reboot.c create mode 100644 src/cmd/reloc/Makefile create mode 100644 src/cmd/reloc/reloc.1 create mode 100644 src/cmd/reloc/reloc.c create mode 100644 src/cmd/renice/Makefile create mode 100644 src/cmd/renice/renice.8 create mode 100644 src/cmd/renice/renice.c create mode 100644 src/cmd/retroforth/LICENSE create mode 100644 src/cmd/retroforth/Makefile create mode 100644 src/cmd/retroforth/NOTES create mode 100644 src/cmd/retroforth/README create mode 100644 src/cmd/retroforth/doc/An_Introduction_to_Retro.rst create mode 100644 src/cmd/retroforth/doc/Coding_Style.rst create mode 100644 src/cmd/retroforth/doc/Commentary.txt create mode 100644 src/cmd/retroforth/doc/Core_Functions.rst create mode 100644 src/cmd/retroforth/doc/Implementations.rst create mode 100644 src/cmd/retroforth/doc/The_Ngaro_Virtual_Machine.rst create mode 100644 src/cmd/retroforth/doc/default.css create mode 100644 src/cmd/retroforth/doc/quickref.rst create mode 100644 src/cmd/retroforth/doc/retro.1 create mode 100644 src/cmd/retroforth/examples/Makefile create mode 100644 src/cmd/retroforth/examples/autopsy.rx create mode 100644 src/cmd/retroforth/examples/casket/corpse/Makefile create mode 100644 src/cmd/retroforth/examples/casket/corpse/NOTES create mode 100644 src/cmd/retroforth/examples/casket/corpse/corpse.rx create mode 100644 src/cmd/retroforth/examples/casket/corpse/templates/corpse.css create mode 100644 src/cmd/retroforth/examples/casket/corpse/templates/discuss.erx create mode 100644 src/cmd/retroforth/examples/casket/corpse/templates/footer.html create mode 100644 src/cmd/retroforth/examples/casket/corpse/templates/header.html create mode 100644 src/cmd/retroforth/examples/casket/corpse/templates/rss create mode 100644 src/cmd/retroforth/examples/casket/incision/Makefile create mode 100644 src/cmd/retroforth/examples/casket/incision/current create mode 100644 src/cmd/retroforth/examples/casket/incision/cuts/0 create mode 100644 src/cmd/retroforth/examples/casket/incision/incision.rx create mode 100644 src/cmd/retroforth/examples/casket/incision/templates/footer.erx create mode 100644 src/cmd/retroforth/examples/casket/incision/templates/header.erx create mode 100644 src/cmd/retroforth/examples/casket/incision/templates/incision.css create mode 100644 src/cmd/retroforth/examples/casket/incision/templates/index.erx create mode 100644 src/cmd/retroforth/examples/casket/rancid/Makefile create mode 100644 src/cmd/retroforth/examples/casket/rancid/rancid.rx create mode 100644 src/cmd/retroforth/examples/casket/rancid/templates/default.erx create mode 100644 src/cmd/retroforth/examples/casket/rancid/templates/footer.html create mode 100644 src/cmd/retroforth/examples/casket/rancid/templates/header.html create mode 100644 src/cmd/retroforth/examples/casket/rancid/templates/rancid.css create mode 100644 src/cmd/retroforth/examples/casket/rancid/templates/script.erx create mode 100644 src/cmd/retroforth/examples/casket/unwell/Makefile create mode 100644 src/cmd/retroforth/examples/casket/unwell/autopsy.rx create mode 100644 src/cmd/retroforth/examples/casket/unwell/templates/css create mode 100644 src/cmd/retroforth/examples/casket/unwell/templates/eval.erx create mode 100644 src/cmd/retroforth/examples/casket/unwell/templates/examine.erx create mode 100644 src/cmd/retroforth/examples/casket/unwell/templates/footer.html create mode 100644 src/cmd/retroforth/examples/casket/unwell/templates/header.html create mode 100644 src/cmd/retroforth/examples/casket/unwell/templates/trace.erx create mode 100644 src/cmd/retroforth/examples/casket/unwell/unwell.rx create mode 100644 src/cmd/retroforth/examples/editor.rx create mode 100644 src/cmd/retroforth/examples/games/chess.rx create mode 100644 src/cmd/retroforth/examples/games/cloak-of-darkness.rx create mode 100644 src/cmd/retroforth/examples/games/hangman/dict.retro create mode 100644 src/cmd/retroforth/examples/games/hangman/graphics.retro create mode 100755 src/cmd/retroforth/examples/games/hangman/hangman create mode 100644 src/cmd/retroforth/examples/games/hangman/hangman.retro create mode 100644 src/cmd/retroforth/examples/games/life.rx create mode 100644 src/cmd/retroforth/examples/games/maze.rx create mode 100644 src/cmd/retroforth/examples/games/spots.rx create mode 100644 src/cmd/retroforth/examples/games/tic-tac-toe.rx create mode 100644 src/cmd/retroforth/examples/langs/Makefile create mode 100644 src/cmd/retroforth/examples/langs/assembler.rx create mode 100644 src/cmd/retroforth/examples/langs/basic.rx create mode 100644 src/cmd/retroforth/examples/langs/bf.rx create mode 100644 src/cmd/retroforth/examples/langs/examples/hello.bf create mode 100644 src/cmd/retroforth/examples/langs/examples/squares.bf create mode 100644 src/cmd/retroforth/examples/master_theorem/8-bit_classics.rx create mode 100644 src/cmd/retroforth/examples/master_theorem/masters_of_many_theorems.rx create mode 100644 src/cmd/retroforth/examples/master_theorem/murder_at_sea.rx create mode 100644 src/cmd/retroforth/examples/master_theorem/my_star_chart.rx create mode 100644 src/cmd/retroforth/examples/master_theorem/prison_life.rx create mode 100644 src/cmd/retroforth/examples/master_theorem/synesthesia.rx create mode 100644 src/cmd/retroforth/examples/master_theorem/what_i_do_in_my_basement.rx create mode 100644 src/cmd/retroforth/examples/master_theorem/words_words_words_2.rx create mode 100644 src/cmd/retroforth/examples/misc/bmi.rx create mode 100644 src/cmd/retroforth/examples/misc/draw.rx create mode 100644 src/cmd/retroforth/examples/rosetta_code/100_doors.rx create mode 100644 src/cmd/retroforth/examples/rosetta_code/1d-cellular-automota.rx create mode 100644 src/cmd/retroforth/examples/rosetta_code/99_bottles_of_beer.rx create mode 100644 src/cmd/retroforth/examples/rosetta_code/README create mode 100644 src/cmd/retroforth/examples/rosetta_code/a_plus_b.rx create mode 100644 src/cmd/retroforth/examples/rosetta_code/accumulator_factory.rx create mode 100644 src/cmd/retroforth/examples/rosetta_code/address_of_a_variable.rx create mode 100644 src/cmd/retroforth/examples/rosetta_code/apply_a_callback_to_an_array.rx create mode 100644 src/cmd/retroforth/examples/rosetta_code/arithmetic_integer.rx create mode 100644 src/cmd/retroforth/examples/rosetta_code/binary_digits.rx create mode 100644 src/cmd/retroforth/examples/rosetta_code/bitwise_operations.rx create mode 100644 src/cmd/retroforth/examples/rosetta_code/boolean_functions.rx create mode 100644 src/cmd/retroforth/examples/rosetta_code/character_codes.rx create mode 100644 src/cmd/retroforth/examples/rosetta_code/character_matching.rx create mode 100644 src/cmd/retroforth/examples/rosetta_code/comments.rx create mode 100644 src/cmd/retroforth/examples/rosetta_code/conditional_structures.rx create mode 100644 src/cmd/retroforth/examples/rosetta_code/conways_game_of_life.rx create mode 100644 src/cmd/retroforth/examples/rosetta_code/copy_a_string.rx create mode 100644 src/cmd/retroforth/examples/rosetta_code/counting_in_octal.rx create mode 100644 src/cmd/retroforth/examples/rosetta_code/create_a_file.rx create mode 100644 src/cmd/retroforth/examples/rosetta_code/create_an_html_table.rx create mode 100644 src/cmd/retroforth/examples/rosetta_code/define_a_primitive_type.rx create mode 100644 src/cmd/retroforth/examples/rosetta_code/delete_a_file.rx create mode 100644 src/cmd/retroforth/examples/rosetta_code/determine_if_a_string_is_numeric.rx create mode 100644 src/cmd/retroforth/examples/rosetta_code/documentation.rx create mode 100644 src/cmd/retroforth/examples/rosetta_code/dynamic_variable_names.rx create mode 100644 src/cmd/retroforth/examples/rosetta_code/empty_program.rx create mode 100644 src/cmd/retroforth/examples/rosetta_code/empty_string.rx create mode 100644 src/cmd/retroforth/examples/rosetta_code/environment_variables.rx create mode 100644 src/cmd/retroforth/examples/rosetta_code/execute_brainf___.rx create mode 100644 src/cmd/retroforth/examples/rosetta_code/exponentiaion_operator.rx create mode 100644 src/cmd/retroforth/examples/rosetta_code/extend_your_language.rx create mode 100644 src/cmd/retroforth/examples/rosetta_code/factorial.rx create mode 100644 src/cmd/retroforth/examples/rosetta_code/fibonacci_sequence.rx create mode 100644 src/cmd/retroforth/examples/rosetta_code/file_io.rx create mode 100644 src/cmd/retroforth/examples/rosetta_code/file_size.rx create mode 100644 src/cmd/retroforth/examples/rosetta_code/find_limit_of_recursion.rx create mode 100644 src/cmd/retroforth/examples/rosetta_code/fizzbuzz.rx create mode 100644 src/cmd/retroforth/examples/rosetta_code/function_definition.rx create mode 100644 src/cmd/retroforth/examples/rosetta_code/greatest_common_divisor.rx create mode 100644 src/cmd/retroforth/examples/rosetta_code/guess_the_number.rx create mode 100644 src/cmd/retroforth/examples/rosetta_code/guess_the_number_with_feedback.rx create mode 100644 src/cmd/retroforth/examples/rosetta_code/hanoi.rx create mode 100644 src/cmd/retroforth/examples/rosetta_code/hello_world_standard_error.rx create mode 100644 src/cmd/retroforth/examples/rosetta_code/hello_world_text.rx create mode 100644 src/cmd/retroforth/examples/rosetta_code/increment_a_numerical_string.rx create mode 100644 src/cmd/retroforth/examples/rosetta_code/integer_comparison.rx create mode 100644 src/cmd/retroforth/examples/rosetta_code/integer_sequence.rx create mode 100644 src/cmd/retroforth/examples/rosetta_code/interactive_programming.rx create mode 100644 src/cmd/retroforth/examples/rosetta_code/leap_year.rx create mode 100644 src/cmd/retroforth/examples/rosetta_code/least_common_multiple.rx create mode 100644 src/cmd/retroforth/examples/rosetta_code/literals_integer.rx create mode 100644 src/cmd/retroforth/examples/rosetta_code/literals_string.rx create mode 100644 src/cmd/retroforth/examples/rosetta_code/loops_downward_for.rx create mode 100644 src/cmd/retroforth/examples/rosetta_code/loops_for.rx create mode 100644 src/cmd/retroforth/examples/rosetta_code/loops_infinite.rx create mode 100644 src/cmd/retroforth/examples/rosetta_code/loops_while.rx create mode 100644 src/cmd/retroforth/examples/rosetta_code/memory_allocation.rx create mode 100644 src/cmd/retroforth/examples/rosetta_code/mouse_position.rx create mode 100644 src/cmd/retroforth/examples/rosetta_code/palindrome_detection.rx create mode 100644 src/cmd/retroforth/examples/rosetta_code/pangram_checker.rx create mode 100644 src/cmd/retroforth/examples/rosetta_code/program_termination.rx create mode 100644 src/cmd/retroforth/examples/rosetta_code/read_entire_file.rx create mode 100644 src/cmd/retroforth/examples/rosetta_code/repeat_a_string.rx create mode 100644 src/cmd/retroforth/examples/rosetta_code/reverse_a_string.rx create mode 100644 src/cmd/retroforth/examples/rosetta_code/roman_numerals.rx create mode 100644 src/cmd/retroforth/examples/rosetta_code/rot-13.rx create mode 100644 src/cmd/retroforth/examples/rosetta_code/shell_one-liner.rx create mode 100644 src/cmd/retroforth/examples/rosetta_code/singly_linked_list_transversal.rx create mode 100644 src/cmd/retroforth/examples/rosetta_code/sleep.rx create mode 100644 src/cmd/retroforth/examples/rosetta_code/stack.rx create mode 100644 src/cmd/retroforth/examples/rosetta_code/string_case.rx create mode 100644 src/cmd/retroforth/examples/rosetta_code/string_concatenation.rx create mode 100644 src/cmd/retroforth/examples/rosetta_code/string_length.rx create mode 100644 src/cmd/retroforth/examples/rosetta_code/system_time.rx create mode 100644 src/cmd/retroforth/examples/rosetta_code/terminal_control_clear_the_screen.rx create mode 100644 src/cmd/retroforth/examples/rosetta_code/terminal_control_determine_the_height_and_width_of_the_terminal_window.rx create mode 100644 src/cmd/retroforth/examples/rosetta_code/terminal_control_moving_the_cursor_to_a_specific_location_on_the_screen.rx create mode 100644 src/cmd/retroforth/examples/rosetta_code/terminal_control_ringing_the_terminal_bell.rx create mode 100644 src/cmd/retroforth/examples/rosetta_code/time_a_function.rx create mode 100644 src/cmd/retroforth/examples/rosetta_code/tokenize_a_string.rx create mode 100644 src/cmd/retroforth/examples/rosetta_code/unicode_variable_names.rx create mode 100644 src/cmd/retroforth/examples/rosetta_code/user_input_text.rx create mode 100644 src/cmd/retroforth/examples/util/cat.rx create mode 100644 src/cmd/retroforth/examples/util/extract-doc.rx create mode 100644 src/cmd/retroforth/examples/util/grep.rx create mode 100644 src/cmd/retroforth/examples/util/head.rx create mode 100644 src/cmd/retroforth/examples/util/wc.rx create mode 100644 src/cmd/retroforth/image/kernel.rx create mode 100644 src/cmd/retroforth/image/meta-alt.rx create mode 100644 src/cmd/retroforth/image/meta.rx create mode 100644 src/cmd/retroforth/library/array.rx create mode 100644 src/cmd/retroforth/library/assertion.rx create mode 100644 src/cmd/retroforth/library/bad.rx create mode 100644 src/cmd/retroforth/library/bstrings.rx create mode 100644 src/cmd/retroforth/library/calendar.rx create mode 100644 src/cmd/retroforth/library/canvas.rx create mode 100644 src/cmd/retroforth/library/casket.rx create mode 100644 src/cmd/retroforth/library/char.rx create mode 100644 src/cmd/retroforth/library/combinators.rx create mode 100644 src/cmd/retroforth/library/console.rx create mode 100644 src/cmd/retroforth/library/crypto.rx create mode 100644 src/cmd/retroforth/library/decompose.rx create mode 100644 src/cmd/retroforth/library/decorator.rx create mode 100644 src/cmd/retroforth/library/dissect.rx create mode 100644 src/cmd/retroforth/library/enum.rx create mode 100644 src/cmd/retroforth/library/eval.rx create mode 100644 src/cmd/retroforth/library/forth.rx create mode 100644 src/cmd/retroforth/library/hash.rx create mode 100644 src/cmd/retroforth/library/infix.rx create mode 100644 src/cmd/retroforth/library/linkedList.rx create mode 100644 src/cmd/retroforth/library/locals.rx create mode 100644 src/cmd/retroforth/library/math.rx create mode 100644 src/cmd/retroforth/library/stack.rx create mode 100644 src/cmd/retroforth/library/struct.rx create mode 100644 src/cmd/retroforth/library/values.rx create mode 100644 src/cmd/retroforth/library/variations.rx create mode 100644 src/cmd/retroforth/retro.c create mode 100644 src/cmd/retroforth/retroImage create mode 100644 src/cmd/retroforth/test/core.rx create mode 100644 src/cmd/retroforth/test/io/output.txt create mode 100644 src/cmd/retroforth/test/io_files.rx create mode 100644 src/cmd/retroforth/test/io_output.rx create mode 100644 src/cmd/retroforth/test/library/array.rx create mode 100644 src/cmd/retroforth/test/library/bad.rx create mode 100644 src/cmd/retroforth/test/library/bstrings.rx create mode 100644 src/cmd/retroforth/test/library/char.rx create mode 100644 src/cmd/retroforth/test/library/decorator.rx create mode 100644 src/cmd/retroforth/test/library/enum.rx create mode 100644 src/cmd/retroforth/test/library/hash.rx create mode 100644 src/cmd/retroforth/test/library/infix.rx create mode 100644 src/cmd/retroforth/test/library/locals.rx create mode 100644 src/cmd/retroforth/test/library/math.rx create mode 100644 src/cmd/retroforth/test/library/stack.rx create mode 100644 src/cmd/retroforth/test/library/struct.rx create mode 100644 src/cmd/retroforth/test/library/values.rx create mode 100644 src/cmd/retroforth/test/vocabs.rx create mode 100644 src/cmd/retroforth/tools/convert.c create mode 100644 src/cmd/retroforth/tools/tweakterm.c create mode 100644 src/cmd/rev.c create mode 100644 src/cmd/rm.c create mode 100644 src/cmd/rmail.c create mode 100644 src/cmd/rmdir.c create mode 100644 src/cmd/scm/Makefile create mode 100644 src/cmd/scm/Syntax.txt create mode 100644 src/cmd/scm/TODO.txt create mode 100644 src/cmd/scm/examples/prime.scm create mode 100644 src/cmd/scm/func.c create mode 100644 src/cmd/scm/scm.c create mode 100644 src/cmd/scm/scm.h create mode 100644 src/cmd/scm/tests/apply.expected create mode 100644 src/cmd/scm/tests/apply.scm create mode 100644 src/cmd/scm/tests/cxr.expected create mode 100644 src/cmd/scm/tests/cxr.scm create mode 100644 src/cmd/scm/tests/define.expected create mode 100644 src/cmd/scm/tests/define.scm create mode 100644 src/cmd/scm/tests/flo.expected create mode 100644 src/cmd/scm/tests/flo.scm create mode 100644 src/cmd/scm/tests/int.expected create mode 100644 src/cmd/scm/tests/int.scm create mode 100644 src/cmd/scm/tests/list.expected create mode 100644 src/cmd/scm/tests/list.scm create mode 100644 src/cmd/scm/tests/member.expected create mode 100644 src/cmd/scm/tests/member.scm create mode 100644 src/cmd/scm/tests/quote.expected create mode 100644 src/cmd/scm/tests/quote.scm create mode 100644 src/cmd/scm/tests/string.expected create mode 100644 src/cmd/scm/tests/string.scm create mode 100644 src/cmd/scm/tests/t.expected create mode 100644 src/cmd/scm/tests/t.scm create mode 100644 src/cmd/sed/Makefile create mode 100644 src/cmd/sed/sed.h create mode 100644 src/cmd/sed/sed0.c create mode 100644 src/cmd/sed/sed1.c create mode 100644 src/cmd/setty/Makefile create mode 100644 src/cmd/setty/setty.c create mode 100644 src/cmd/sh/Makefile create mode 100644 src/cmd/sh/args.c create mode 100644 src/cmd/sh/blok.c create mode 100644 src/cmd/sh/brkincr.h create mode 100644 src/cmd/sh/cmd.c create mode 100644 src/cmd/sh/ctype.c create mode 100644 src/cmd/sh/ctype.h create mode 100644 src/cmd/sh/defs.c create mode 100644 src/cmd/sh/defs.h create mode 100644 src/cmd/sh/dup.h create mode 100644 src/cmd/sh/echo.c create mode 100644 src/cmd/sh/error.c create mode 100644 src/cmd/sh/expand.c create mode 100644 src/cmd/sh/fault.c create mode 100644 src/cmd/sh/func.c create mode 100644 src/cmd/sh/hash.c create mode 100644 src/cmd/sh/hash.h create mode 100644 src/cmd/sh/hashserv.c create mode 100644 src/cmd/sh/io.c create mode 100644 src/cmd/sh/mac.h create mode 100644 src/cmd/sh/macro.c create mode 100644 src/cmd/sh/main.c create mode 100644 src/cmd/sh/mode.h create mode 100644 src/cmd/sh/msg.c create mode 100644 src/cmd/sh/name.c create mode 100644 src/cmd/sh/name.h create mode 100644 src/cmd/sh/print.c create mode 100644 src/cmd/sh/profile.c create mode 100644 src/cmd/sh/pushd create mode 100644 src/cmd/sh/pwd.c create mode 100644 src/cmd/sh/service.c create mode 100644 src/cmd/sh/setbrk.c create mode 100644 src/cmd/sh/stak.c create mode 100644 src/cmd/sh/stak.h create mode 100644 src/cmd/sh/string.c create mode 100644 src/cmd/sh/sym.h create mode 100644 src/cmd/sh/test.c create mode 100644 src/cmd/sh/timeout.h create mode 100644 src/cmd/sh/trace.c create mode 100644 src/cmd/sh/word.c create mode 100644 src/cmd/sh/xec.c create mode 100644 src/cmd/shutdown/Makefile create mode 100644 src/cmd/shutdown/shutdown.8 create mode 100644 src/cmd/shutdown/shutdown.c create mode 100644 src/cmd/size.c create mode 100644 src/cmd/sl/Makefile create mode 100644 src/cmd/sl/README create mode 100644 src/cmd/sl/sl.1 create mode 100644 src/cmd/sl/sl.c create mode 100644 src/cmd/sl/sl.h create mode 100644 src/cmd/sl/sl.txt create mode 100644 src/cmd/sleep.c create mode 100644 src/cmd/smallc/6809/ccstart.u create mode 100644 src/cmd/smallc/6809/crunas09.u create mode 100644 src/cmd/smallc/6809/exit.u create mode 100644 src/cmd/smallc/6809/faults.u create mode 100644 src/cmd/smallc/6809/io.u create mode 100644 src/cmd/smallc/6809/mrabs.u create mode 100644 src/cmd/smallc/6809/prabs.u create mode 100644 src/cmd/smallc/6809/sdiv.u create mode 100644 src/cmd/smallc/6809/shift.u create mode 100644 src/cmd/smallc/6809/smod.u create mode 100644 src/cmd/smallc/6809/sumul.u create mode 100644 src/cmd/smallc/8080/Makefile create mode 100644 src/cmd/smallc/8080/arglist.c create mode 100644 src/cmd/smallc/8080/bdos.c create mode 100644 src/cmd/smallc/8080/bdos1.c create mode 100644 src/cmd/smallc/8080/chio8080.c create mode 100644 src/cmd/smallc/8080/cret.asm create mode 100644 src/cmd/smallc/8080/crun.asm create mode 100644 src/cmd/smallc/8080/exit.c create mode 100644 src/cmd/smallc/8080/inout.c create mode 100644 src/cmd/smallc/8080/io8080.c create mode 100644 src/cmd/smallc/Makefile create mode 100644 src/cmd/smallc/README create mode 100644 src/cmd/smallc/code8080.c create mode 100644 src/cmd/smallc/codeas09.c create mode 100644 src/cmd/smallc/codem68k.c create mode 100644 src/cmd/smallc/codemips.c create mode 100644 src/cmd/smallc/codevax.c create mode 100644 src/cmd/smallc/data.c create mode 100644 src/cmd/smallc/data.h create mode 100644 src/cmd/smallc/defs.h create mode 100644 src/cmd/smallc/error.c create mode 100644 src/cmd/smallc/expr.c create mode 100644 src/cmd/smallc/function.c create mode 100644 src/cmd/smallc/gen.c create mode 100644 src/cmd/smallc/includes/ctype.h create mode 100644 src/cmd/smallc/includes/hello.c create mode 100644 src/cmd/smallc/includes/stdio.h create mode 100644 src/cmd/smallc/initialise.c create mode 100644 src/cmd/smallc/io.c create mode 100644 src/cmd/smallc/lex.c create mode 100644 src/cmd/smallc/lib/Makefile create mode 100644 src/cmd/smallc/lib/abs.c create mode 100644 src/cmd/smallc/lib/atoi.c create mode 100644 src/cmd/smallc/lib/binary.c create mode 100644 src/cmd/smallc/lib/charclass.c create mode 100644 src/cmd/smallc/lib/fgets.c create mode 100644 src/cmd/smallc/lib/fputs.c create mode 100644 src/cmd/smallc/lib/getchar.c create mode 100644 src/cmd/smallc/lib/gets.c create mode 100644 src/cmd/smallc/lib/index.c create mode 100644 src/cmd/smallc/lib/itoa.c create mode 100644 src/cmd/smallc/lib/lorder8080 create mode 100644 src/cmd/smallc/lib/printn.c create mode 100644 src/cmd/smallc/lib/putchar.c create mode 100644 src/cmd/smallc/lib/puts.c create mode 100644 src/cmd/smallc/lib/rand.c create mode 100644 src/cmd/smallc/lib/reverse.c create mode 100644 src/cmd/smallc/lib/sbrk.c create mode 100644 src/cmd/smallc/lib/shell.c create mode 100644 src/cmd/smallc/lib/strcat.c create mode 100644 src/cmd/smallc/lib/strcmp.c create mode 100644 src/cmd/smallc/lib/strcpy.c create mode 100644 src/cmd/smallc/lib/strlen.c create mode 100644 src/cmd/smallc/lib/strncat.c create mode 100644 src/cmd/smallc/lib/strncmp.c create mode 100644 src/cmd/smallc/lib/strncpy.c create mode 100644 src/cmd/smallc/main.c create mode 100644 src/cmd/smallc/preproc.c create mode 100644 src/cmd/smallc/primary.c create mode 100644 src/cmd/smallc/stmt.c create mode 100644 src/cmd/smallc/sym.c create mode 100644 src/cmd/smallc/vax/B2test.c create mode 100644 src/cmd/smallc/vax/Makefile create mode 100644 src/cmd/smallc/vax/b2test.dat create mode 100644 src/cmd/smallc/vax/chiovax.c create mode 100644 src/cmd/smallc/vax/crt0.c create mode 100644 src/cmd/smallc/vax/crt0.s create mode 100644 src/cmd/smallc/vax/crunvax.c create mode 100644 src/cmd/smallc/vax/iovax.c create mode 100644 src/cmd/smallc/vax/optest.c create mode 100644 src/cmd/smallc/vax/vscc create mode 100644 src/cmd/smallc/while.c create mode 100644 src/cmd/smlrc/Makefile create mode 100644 src/cmd/smlrc/cgmips.c create mode 100644 src/cmd/smlrc/cgx86.c create mode 100644 src/cmd/smlrc/lb.c create mode 100644 src/cmd/smlrc/license.txt create mode 100644 src/cmd/smlrc/readme.txt create mode 100644 src/cmd/smlrc/smlrc.c create mode 100644 src/cmd/smux/Makefile create mode 100644 src/cmd/smux/common/packet.h create mode 100644 src/cmd/smux/linux/Makefile create mode 100644 src/cmd/smux/linux/smux.c create mode 100644 src/cmd/smux/retro/Makefile create mode 100644 src/cmd/smux/retro/smux.c create mode 100644 src/cmd/sort.c create mode 100644 src/cmd/split.c create mode 100644 src/cmd/sre/HISTORY create mode 100644 src/cmd/sre/Makefile create mode 100644 src/cmd/sre/cmd.c create mode 100644 src/cmd/sre/edit.h create mode 100644 src/cmd/sre/file.c create mode 100644 src/cmd/sre/init.c create mode 100644 src/cmd/sre/main.c create mode 100644 src/cmd/sre/misc.c create mode 100644 src/cmd/sre/render.c create mode 100644 src/cmd/sre/setup.c create mode 100644 src/cmd/sre/srch.c create mode 100644 src/cmd/sre/srerc_example create mode 100644 src/cmd/sre/tag.c create mode 100644 src/cmd/sre/tutorial create mode 100644 src/cmd/strip.c create mode 100644 src/cmd/stty/Makefile create mode 100644 src/cmd/stty/stty.1 create mode 100644 src/cmd/stty/stty.c create mode 100644 src/cmd/su.c create mode 100644 src/cmd/sum.c create mode 100644 src/cmd/sync.c create mode 100644 src/cmd/sysctl/Makefile create mode 100644 src/cmd/sysctl/sysctl.8 create mode 100644 src/cmd/sysctl/sysctl.c create mode 100644 src/cmd/tail.c create mode 100644 src/cmd/talloc/Makefile create mode 100644 src/cmd/talloc/talloc.1 create mode 100644 src/cmd/talloc/talloc.c create mode 100644 src/cmd/tar.c create mode 100644 src/cmd/tcl/Makefile create mode 100644 src/cmd/tcl/tclsh.c create mode 100644 src/cmd/tee.c create mode 100644 src/cmd/test/Makefile create mode 100755 src/cmd/test/TEST.csh create mode 100644 src/cmd/test/operators.c create mode 100644 src/cmd/test/operators.h create mode 100644 src/cmd/test/test.1 create mode 100644 src/cmd/test/test.c create mode 100644 src/cmd/time.c create mode 100644 src/cmd/tip/Makefile create mode 100644 src/cmd/tip/README create mode 100644 src/cmd/tip/TODO create mode 100644 src/cmd/tip/acu.c create mode 100644 src/cmd/tip/aculib/.depend create mode 100644 src/cmd/tip/aculib/Makefile create mode 100644 src/cmd/tip/aculib/biz22.c create mode 100644 src/cmd/tip/aculib/biz31.c create mode 100644 src/cmd/tip/aculib/courier.c create mode 100644 src/cmd/tip/aculib/df.c create mode 100644 src/cmd/tip/aculib/dn11.c create mode 100644 src/cmd/tip/aculib/hayes.c create mode 100644 src/cmd/tip/aculib/penril.c create mode 100644 src/cmd/tip/aculib/v3451.c create mode 100644 src/cmd/tip/aculib/v831.c create mode 100644 src/cmd/tip/aculib/ventel.c create mode 100644 src/cmd/tip/acutab.c create mode 100644 src/cmd/tip/cmds.c create mode 100644 src/cmd/tip/cmdtab.c create mode 100644 src/cmd/tip/cu.c create mode 100644 src/cmd/tip/hunt.c create mode 100644 src/cmd/tip/log.c create mode 100644 src/cmd/tip/m create mode 100644 src/cmd/tip/partab.c create mode 100644 src/cmd/tip/phones-file create mode 100644 src/cmd/tip/remcap.c create mode 100644 src/cmd/tip/remote-file create mode 100644 src/cmd/tip/remote.c create mode 100644 src/cmd/tip/tip.c create mode 100644 src/cmd/tip/tip.h create mode 100644 src/cmd/tip/tipout.c create mode 100644 src/cmd/tip/uucplock.c create mode 100644 src/cmd/tip/value.c create mode 100644 src/cmd/tip/vars.c create mode 100644 src/cmd/touch.c create mode 100644 src/cmd/tr.c create mode 100644 src/cmd/true.sh create mode 100644 src/cmd/tsort.c create mode 100644 src/cmd/tty.c create mode 100644 src/cmd/umount/Makefile create mode 100644 src/cmd/umount/umount.8 create mode 100644 src/cmd/umount/umount.c create mode 100644 src/cmd/uname/Makefile create mode 100644 src/cmd/uname/uname.1 create mode 100644 src/cmd/uname/uname.c create mode 100644 src/cmd/uniq.c create mode 100644 src/cmd/unixbench/Makefile create mode 100644 src/cmd/unixbench/README create mode 100755 src/cmd/unixbench/Run create mode 100755 src/cmd/unixbench/pgms/cleanup.sh create mode 100755 src/cmd/unixbench/pgms/fs.awk create mode 100644 src/cmd/unixbench/pgms/index.awk create mode 100644 src/cmd/unixbench/pgms/index.base create mode 100755 src/cmd/unixbench/pgms/index.sh create mode 100755 src/cmd/unixbench/pgms/loopm.awk create mode 100755 src/cmd/unixbench/pgms/loops.awk create mode 100755 src/cmd/unixbench/pgms/lps.awk create mode 100755 src/cmd/unixbench/pgms/multi.sh create mode 100755 src/cmd/unixbench/pgms/mwips.awk create mode 100755 src/cmd/unixbench/pgms/perlbench create mode 100755 src/cmd/unixbench/pgms/report.awk create mode 100755 src/cmd/unixbench/pgms/report.sh create mode 100755 src/cmd/unixbench/pgms/select create mode 100755 src/cmd/unixbench/pgms/tst.sh create mode 100644 src/cmd/unixbench/pgms/unixbench.logo create mode 100644 src/cmd/unixbench/results/log create mode 100644 src/cmd/unixbench/results/log.accum create mode 100644 src/cmd/unixbench/results/report create mode 100644 src/cmd/unixbench/results/times create mode 100644 src/cmd/unixbench/src/arith.c create mode 100644 src/cmd/unixbench/src/big.c create mode 100644 src/cmd/unixbench/src/context1.c create mode 100644 src/cmd/unixbench/src/dhry.h create mode 100644 src/cmd/unixbench/src/dhry_1.c create mode 100644 src/cmd/unixbench/src/dhry_2.c create mode 100644 src/cmd/unixbench/src/dummy.c create mode 100644 src/cmd/unixbench/src/execl.c create mode 100644 src/cmd/unixbench/src/fstime.c create mode 100644 src/cmd/unixbench/src/getopt.c create mode 100644 src/cmd/unixbench/src/hanoi.c create mode 100644 src/cmd/unixbench/src/limit.c create mode 100644 src/cmd/unixbench/src/looper.c create mode 100644 src/cmd/unixbench/src/pipe.c create mode 100644 src/cmd/unixbench/src/spawn.c create mode 100644 src/cmd/unixbench/src/syscall.c create mode 100644 src/cmd/unixbench/src/time-polling.c create mode 100644 src/cmd/unixbench/src/timeit.c create mode 100644 src/cmd/unixbench/src/whets.c create mode 100644 src/cmd/unixbench/testdir/cctest.c create mode 100644 src/cmd/unixbench/testdir/dc.dat create mode 100644 src/cmd/unixbench/testdir/sort.src create mode 100755 src/cmd/unixbench/tmp/kill_run create mode 100644 src/cmd/update/Makefile create mode 100644 src/cmd/update/update.8 create mode 100644 src/cmd/update/update.c create mode 100644 src/cmd/uucp/CHANGES create mode 100644 src/cmd/uucp/Makefile create mode 100644 src/cmd/uucp/README create mode 100644 src/cmd/uucp/README.TCP create mode 100644 src/cmd/uucp/README.dialino create mode 100644 src/cmd/uucp/UUAIDS/L-devices create mode 100644 src/cmd/uucp/UUAIDS/L-dialcodes create mode 100644 src/cmd/uucp/UUAIDS/L.aliases create mode 100644 src/cmd/uucp/UUAIDS/L.cmds create mode 100644 src/cmd/uucp/UUAIDS/L.sys create mode 100644 src/cmd/uucp/UUAIDS/Notes.L.sys create mode 100644 src/cmd/uucp/UUAIDS/USERFILE create mode 100644 src/cmd/uucp/UUAIDS/setup.tblms create mode 100644 src/cmd/uucp/UUAIDS/uu.daily create mode 100644 src/cmd/uucp/UUAIDS/uu.daily.seism create mode 100644 src/cmd/uucp/UUAIDS/uu.hourly create mode 100644 src/cmd/uucp/UUAIDS/uu.weekly create mode 100644 src/cmd/uucp/UUAIDS/uucp.daily create mode 100644 src/cmd/uucp/UUAIDS/uucpsrv.c create mode 100644 src/cmd/uucp/UUAIDS/uucpsummary create mode 100644 src/cmd/uucp/UUAIDS/uucpsummary.mo create mode 100644 src/cmd/uucp/UUAIDS/uurate create mode 100644 src/cmd/uucp/UUAIDS/uutbl create mode 100644 src/cmd/uucp/UUAIDS/uuusage create mode 100644 src/cmd/uucp/acucntrl.8 create mode 100644 src/cmd/uucp/acucntrl.c create mode 100644 src/cmd/uucp/aculib/Makefile create mode 100644 src/cmd/uucp/aculib/att2224.c create mode 100644 src/cmd/uucp/aculib/bsdtcp.c create mode 100644 src/cmd/uucp/aculib/cds224.c create mode 100644 src/cmd/uucp/aculib/df12.c create mode 100644 src/cmd/uucp/aculib/df2.c create mode 100644 src/cmd/uucp/aculib/dk.c create mode 100644 src/cmd/uucp/aculib/dn.c create mode 100644 src/cmd/uucp/aculib/hys.c create mode 100644 src/cmd/uucp/aculib/hys24.c create mode 100644 src/cmd/uucp/aculib/hysq.c create mode 100644 src/cmd/uucp/aculib/mic.c create mode 100644 src/cmd/uucp/aculib/nov.c create mode 100644 src/cmd/uucp/aculib/pen.c create mode 100644 src/cmd/uucp/aculib/pnet.c create mode 100644 src/cmd/uucp/aculib/rvmacs.c create mode 100644 src/cmd/uucp/aculib/sy.c create mode 100644 src/cmd/uucp/aculib/unet.c create mode 100644 src/cmd/uucp/aculib/va212.c create mode 100644 src/cmd/uucp/aculib/va811.c create mode 100644 src/cmd/uucp/aculib/va820.c create mode 100644 src/cmd/uucp/aculib/vad.c create mode 100644 src/cmd/uucp/aculib/vent.c create mode 100644 src/cmd/uucp/aculib/vmacs.c create mode 100644 src/cmd/uucp/anlwrk.c create mode 100644 src/cmd/uucp/anyread.c create mode 100644 src/cmd/uucp/assert.c create mode 100644 src/cmd/uucp/cfgets.c create mode 100644 src/cmd/uucp/chkpth.c create mode 100644 src/cmd/uucp/chksum.c create mode 100644 src/cmd/uucp/cico.c create mode 100644 src/cmd/uucp/cntrl.c create mode 100644 src/cmd/uucp/condevs.c create mode 100644 src/cmd/uucp/condevs.h create mode 100644 src/cmd/uucp/conn.c create mode 100644 src/cmd/uucp/cpmv.c create mode 100644 src/cmd/uucp/expfile.c create mode 100644 src/cmd/uucp/fio.c create mode 100644 src/cmd/uucp/gename.c create mode 100644 src/cmd/uucp/getargs.c create mode 100644 src/cmd/uucp/getprm.c create mode 100644 src/cmd/uucp/getpwinfo.c create mode 100644 src/cmd/uucp/gio.c create mode 100644 src/cmd/uucp/gnamef.c create mode 100644 src/cmd/uucp/gnsys.c create mode 100644 src/cmd/uucp/gnxseq.c create mode 100644 src/cmd/uucp/imsg.c create mode 100644 src/cmd/uucp/lastpart.c create mode 100644 src/cmd/uucp/logent.c create mode 100644 src/cmd/uucp/mailst.c create mode 100644 src/cmd/uucp/pk.h create mode 100644 src/cmd/uucp/pk0.c create mode 100644 src/cmd/uucp/pk1.c create mode 100644 src/cmd/uucp/prefix.c create mode 100644 src/cmd/uucp/setline.c create mode 100644 src/cmd/uucp/subdir.c create mode 100644 src/cmd/uucp/sysacct.c create mode 100644 src/cmd/uucp/systat.c create mode 100644 src/cmd/uucp/tio.c create mode 100644 src/cmd/uucp/ulockf.c create mode 100644 src/cmd/uucp/uuclean.c create mode 100644 src/cmd/uucp/uucp.c create mode 100644 src/cmd/uucp/uucp.h create mode 100644 src/cmd/uucp/uucpd.c create mode 100644 src/cmd/uucp/uucpdefs.c create mode 100644 src/cmd/uucp/uucpname.c create mode 100644 src/cmd/uucp/uudecode.c create mode 100644 src/cmd/uucp/uuencode.c create mode 100644 src/cmd/uucp/uulog.c create mode 100644 src/cmd/uucp/uuname.c create mode 100644 src/cmd/uucp/uupoll.c create mode 100644 src/cmd/uucp/uuq.c create mode 100644 src/cmd/uucp/uusend.c create mode 100644 src/cmd/uucp/uusnap.c create mode 100644 src/cmd/uucp/uust.h create mode 100644 src/cmd/uucp/uusub.h create mode 100644 src/cmd/uucp/uux.c create mode 100644 src/cmd/uucp/uuxqt.c create mode 100644 src/cmd/uucp/versys.c create mode 100644 src/cmd/uucp/vms.tar.Z create mode 100644 src/cmd/uucp/xqt.c create mode 100644 src/cmd/vipw/Makefile create mode 100644 src/cmd/vipw/vipw.8 create mode 100644 src/cmd/vipw/vipw.c create mode 100644 src/cmd/virus/Makefile create mode 100644 src/cmd/virus/lib/last_char_is.c create mode 100644 src/cmd/virus/lib/strlcat.c create mode 100644 src/cmd/virus/lib/strlcpy.3 create mode 100644 src/cmd/virus/lib/strlcpy.c create mode 100644 src/cmd/virus/virus.c create mode 100644 src/cmd/vmstat.c create mode 100644 src/cmd/w.c create mode 100644 src/cmd/wall.c create mode 100644 src/cmd/wc.c create mode 100644 src/cmd/whereis.c create mode 100644 src/cmd/who.c create mode 100644 src/cmd/wiznet/Makefile create mode 100644 src/cmd/wiznet/chat-server.c create mode 100644 src/cmd/wiznet/ntpdate.c create mode 100644 src/cmd/wiznet/telnet.c create mode 100644 src/cmd/wiznet/todo/barometric-pressure-web-server.c create mode 100644 src/cmd/wiznet/todo/pachube-client-string.c create mode 100644 src/cmd/wiznet/todo/pachube-client.c create mode 100644 src/cmd/wiznet/todo/udp-send-receive-string.c create mode 100644 src/cmd/wiznet/web-client.c create mode 100644 src/cmd/wiznet/web-server.c create mode 100644 src/cmd/write.c create mode 100644 src/cmd/xargs/Makefile create mode 100644 src/cmd/xargs/xargs.1 create mode 100644 src/cmd/xargs/xargs.c create mode 100644 src/cmd/yacc/Makefile create mode 100644 src/cmd/yacc/dextern create mode 100644 src/cmd/yacc/files create mode 100644 src/cmd/yacc/y1.c create mode 100644 src/cmd/yacc/y2.c create mode 100644 src/cmd/yacc/y3.c create mode 100644 src/cmd/yacc/y4.c create mode 100644 src/cmd/yacc/yaccdiffs create mode 100644 src/cmd/yacc/yaccnews create mode 100644 src/cmd/yacc/yaccpar create mode 100644 src/cmd/zmodem/Makefile create mode 100644 src/cmd/zmodem/crc.1 create mode 100644 src/cmd/zmodem/crc.c create mode 100644 src/cmd/zmodem/crctab.c create mode 100644 src/cmd/zmodem/genie.c create mode 100644 src/cmd/zmodem/makefile.generic create mode 100644 src/cmd/zmodem/minirb.1 create mode 100644 src/cmd/zmodem/minirb.c create mode 100644 src/cmd/zmodem/ptest.sh create mode 100644 src/cmd/zmodem/rbsb.c create mode 100644 src/cmd/zmodem/rz.1 create mode 100644 src/cmd/zmodem/rz.c create mode 100644 src/cmd/zmodem/sz.1 create mode 100644 src/cmd/zmodem/sz.c create mode 100644 src/cmd/zmodem/vmodem.h create mode 100644 src/cmd/zmodem/vrzsz.c create mode 100644 src/cmd/zmodem/vupl.t create mode 100644 src/cmd/zmodem/vuplfile.t create mode 100644 src/cmd/zmodem/vvmodem.c create mode 100644 src/cmd/zmodem/zm.c create mode 100644 src/cmd/zmodem/zmodem.h create mode 100644 src/cmd/zmodem/zmr.c create mode 100644 src/cmd/zmodem/zupl.t create mode 100644 src/elf32-mips.ld create mode 100644 src/games/Makefile create mode 100644 src/games/adventure/Makefile create mode 100644 src/games/adventure/adventure.6 create mode 100644 src/games/adventure/adventure.dat create mode 100644 src/games/adventure/done.c create mode 100644 src/games/adventure/glorkz create mode 100644 src/games/adventure/glorkz-ru create mode 100644 src/games/adventure/hdr.h create mode 100644 src/games/adventure/init.c create mode 100644 src/games/adventure/io.c create mode 100644 src/games/adventure/main.c create mode 100644 src/games/adventure/save.c create mode 100644 src/games/adventure/subr.c create mode 100644 src/games/adventure/vocab.c create mode 100644 src/games/adventure/wizard.c create mode 100644 src/games/arithmetic.6 create mode 100644 src/games/arithmetic.c create mode 100644 src/games/atc/BUGS create mode 100644 src/games/atc/Makefile create mode 100644 src/games/atc/def.h create mode 100644 src/games/atc/extern.c create mode 100644 src/games/atc/extern.h create mode 100644 src/games/atc/games/ATC_scores create mode 100644 src/games/atc/games/Game_List create mode 100644 src/games/atc/games/Killer create mode 100644 src/games/atc/games/crossover create mode 100644 src/games/atc/games/default create mode 100644 src/games/atc/games/easy create mode 100644 src/games/atc/games/game_2 create mode 100644 src/games/atc/grammar.y create mode 100644 src/games/atc/graphics.c create mode 100644 src/games/atc/include.h create mode 100644 src/games/atc/input.c create mode 100644 src/games/atc/lex.l create mode 100644 src/games/atc/list.c create mode 100644 src/games/atc/log.c create mode 100644 src/games/atc/main.c create mode 100644 src/games/atc/struct.h create mode 100644 src/games/atc/tunable.c create mode 100644 src/games/atc/tunable.h create mode 100644 src/games/atc/update.c create mode 100644 src/games/backgammon/Makefile create mode 100644 src/games/backgammon/allow.c create mode 100644 src/games/backgammon/back.h create mode 100644 src/games/backgammon/backgammon.6 create mode 100644 src/games/backgammon/backgammon.src create mode 100644 src/games/backgammon/board.c create mode 100644 src/games/backgammon/check.c create mode 100644 src/games/backgammon/data.c create mode 100644 src/games/backgammon/extra.c create mode 100644 src/games/backgammon/fancy.c create mode 100644 src/games/backgammon/init.c create mode 100644 src/games/backgammon/main.c create mode 100644 src/games/backgammon/message.c create mode 100644 src/games/backgammon/move.c create mode 100644 src/games/backgammon/odds.c create mode 100644 src/games/backgammon/one.c create mode 100644 src/games/backgammon/save.c create mode 100644 src/games/backgammon/subs.c create mode 100644 src/games/backgammon/table.c create mode 100644 src/games/backgammon/teach.c create mode 100644 src/games/backgammon/text.c create mode 100644 src/games/backgammon/ttext1.c create mode 100644 src/games/backgammon/ttext2.c create mode 100644 src/games/backgammon/tutor.c create mode 100644 src/games/backgammon/tutor.h create mode 100644 src/games/banner.6 create mode 100644 src/games/banner.c create mode 100644 src/games/battlestar/Makefile create mode 100644 src/games/battlestar/Makefile-linux create mode 100644 src/games/battlestar/battlestar.6 create mode 100644 src/games/battlestar/battlestar.c create mode 100644 src/games/battlestar/cmd1.c create mode 100644 src/games/battlestar/cmd2.c create mode 100644 src/games/battlestar/cmd3.c create mode 100644 src/games/battlestar/cmd4.c create mode 100644 src/games/battlestar/cmd5.c create mode 100644 src/games/battlestar/cmd6.c create mode 100644 src/games/battlestar/cmd7.c create mode 100644 src/games/battlestar/curses.c create mode 100644 src/games/battlestar/cypher.c create mode 100644 src/games/battlestar/dayfile.c create mode 100644 src/games/battlestar/dayobjs.c create mode 100644 src/games/battlestar/doprnt.c create mode 100644 src/games/battlestar/externs.h create mode 100644 src/games/battlestar/fly.c create mode 100644 src/games/battlestar/getcom.c create mode 100644 src/games/battlestar/globals.c create mode 100644 src/games/battlestar/init.c create mode 100644 src/games/battlestar/misc.c create mode 100644 src/games/battlestar/mkstr.c create mode 100644 src/games/battlestar/nightfile.c create mode 100644 src/games/battlestar/nightobjs.c create mode 100644 src/games/battlestar/parse.c create mode 100644 src/games/battlestar/room.c create mode 100644 src/games/battlestar/save.c create mode 100644 src/games/battlestar/words.c create mode 100644 src/games/bcd.6 create mode 100644 src/games/bcd.c create mode 100644 src/games/boggle/Makefile create mode 100644 src/games/boggle/boggle.6 create mode 100644 src/games/boggle/boggle.c create mode 100644 src/games/boggle/comp.c create mode 100644 src/games/boggle/inst create mode 100644 src/games/boggle/sfile create mode 100644 src/games/btlgammon/Makefile create mode 100644 src/games/btlgammon/backrules create mode 100644 src/games/btlgammon/btlgammon.c create mode 100644 src/games/canfield.6 create mode 100644 src/games/canfield.c create mode 100644 src/games/cfscores.c create mode 100644 src/games/cribbage/Makefile create mode 100644 src/games/cribbage/_ctfix create mode 100644 src/games/cribbage/cards.c create mode 100644 src/games/cribbage/crib.c create mode 100644 src/games/cribbage/cribbage.6 create mode 100644 src/games/cribbage/cribbage.h create mode 100644 src/games/cribbage/cribbage.n create mode 100644 src/games/cribbage/cribcur.h create mode 100644 src/games/cribbage/deck.h create mode 100644 src/games/cribbage/extern.c create mode 100644 src/games/cribbage/io.c create mode 100644 src/games/cribbage/macro create mode 100644 src/games/cribbage/score.c create mode 100644 src/games/cribbage/support.c create mode 100644 src/games/cribbage/test.c create mode 100644 src/games/factor.c create mode 100644 src/games/fish.6 create mode 100644 src/games/fish.c create mode 100644 src/games/fortune/Do_troff create mode 100644 src/games/fortune/Makefile create mode 100644 src/games/fortune/Troff.mac create mode 100644 src/games/fortune/Troff.sed create mode 100644 src/games/fortune/fortune.6 create mode 100644 src/games/fortune/fortune.c create mode 100644 src/games/fortune/notes create mode 100644 src/games/fortune/obscene create mode 100644 src/games/fortune/obscene.4.3 create mode 100644 src/games/fortune/obscene.sp.ok create mode 100644 src/games/fortune/rnd.c create mode 100644 src/games/fortune/scene create mode 100644 src/games/fortune/scene.4.3 create mode 100644 src/games/fortune/scene.sp.ok create mode 100644 src/games/fortune/strfile.c create mode 100644 src/games/fortune/strfile.h create mode 100644 src/games/fortune/unstr.c create mode 100644 src/games/hangman/Makefile create mode 100644 src/games/hangman/endgame.c create mode 100644 src/games/hangman/extern.c create mode 100644 src/games/hangman/getguess.c create mode 100644 src/games/hangman/getword.c create mode 100644 src/games/hangman/hangman.6 create mode 100644 src/games/hangman/hangman.h create mode 100644 src/games/hangman/main.c create mode 100644 src/games/hangman/playgame.c create mode 100644 src/games/hangman/prdata.c create mode 100644 src/games/hangman/prman.c create mode 100644 src/games/hangman/prword.c create mode 100644 src/games/hangman/setup.c create mode 100644 src/games/hunt/Makefile create mode 100644 src/games/hunt/README create mode 100644 src/games/hunt/answer.c create mode 100644 src/games/hunt/connect.c create mode 100644 src/games/hunt/draw.c create mode 100644 src/games/hunt/driver.c create mode 100644 src/games/hunt/execute.c create mode 100644 src/games/hunt/expl.c create mode 100644 src/games/hunt/extern.c create mode 100644 src/games/hunt/hunt.6 create mode 100644 src/games/hunt/hunt.c create mode 100644 src/games/hunt/hunt.h create mode 100644 src/games/hunt/makemaze.c create mode 100644 src/games/hunt/pathname.c create mode 100644 src/games/hunt/playit.c create mode 100644 src/games/hunt/shots.c create mode 100644 src/games/hunt/terminal.c create mode 100644 src/games/mille/Makefile create mode 100644 src/games/mille/comp.c create mode 100644 src/games/mille/end.c create mode 100644 src/games/mille/extern.c create mode 100644 src/games/mille/init.c create mode 100644 src/games/mille/mille.6 create mode 100644 src/games/mille/mille.c create mode 100644 src/games/mille/mille.h create mode 100644 src/games/mille/misc.c create mode 100644 src/games/mille/move.c create mode 100644 src/games/mille/print.c create mode 100644 src/games/mille/roll.c create mode 100644 src/games/mille/save.c create mode 100644 src/games/mille/table.c create mode 100644 src/games/mille/types.c create mode 100644 src/games/mille/unctrl.h create mode 100644 src/games/mille/varpush.c create mode 100644 src/games/monop/Makefile create mode 100644 src/games/monop/_rofix create mode 100644 src/games/monop/brd.dat create mode 100644 src/games/monop/cards.c create mode 100644 src/games/monop/cards.inp create mode 100644 src/games/monop/deck.h create mode 100644 src/games/monop/execute.c create mode 100644 src/games/monop/getinp.c create mode 100644 src/games/monop/houses.c create mode 100644 src/games/monop/initdeck.c create mode 100644 src/games/monop/jail.c create mode 100644 src/games/monop/misc.c create mode 100644 src/games/monop/mon.dat create mode 100644 src/games/monop/monop.6 create mode 100644 src/games/monop/monop.c create mode 100644 src/games/monop/monop.def create mode 100644 src/games/monop/monop.ext create mode 100644 src/games/monop/monop.h create mode 100644 src/games/monop/morg.c create mode 100644 src/games/monop/print.c create mode 100644 src/games/monop/prop.c create mode 100644 src/games/monop/prop.dat create mode 100644 src/games/monop/rent.c create mode 100644 src/games/monop/roll.c create mode 100644 src/games/monop/spec.c create mode 100644 src/games/monop/strcmp.c create mode 100644 src/games/monop/strings create mode 100644 src/games/monop/trade.c create mode 100644 src/games/morse.c create mode 100644 src/games/number.6 create mode 100644 src/games/number.c create mode 100644 src/games/phantasia/Makefile create mode 100644 src/games/phantasia/Makefile-linux create mode 100644 src/games/phantasia/fight.c create mode 100644 src/games/phantasia/func0.c create mode 100644 src/games/phantasia/func1.c create mode 100644 src/games/phantasia/func2.c create mode 100644 src/games/phantasia/main.c create mode 100644 src/games/phantasia/monsters create mode 100644 src/games/phantasia/phant.h create mode 100644 src/games/phantasia/phant.nr create mode 100644 src/games/phantasia/phant_run.c create mode 100644 src/games/phantasia/setfiles.c create mode 100644 src/games/phantasia/test.c create mode 100644 src/games/ppt.c create mode 100644 src/games/primes.c create mode 100644 src/games/quiz/Makefile create mode 100644 src/games/quiz/quiz.6 create mode 100644 src/games/quiz/quiz.c create mode 100644 src/games/quiz/quiz.k/africa create mode 100644 src/games/quiz/quiz.k/america create mode 100644 src/games/quiz/quiz.k/areas create mode 100644 src/games/quiz/quiz.k/arith create mode 100644 src/games/quiz/quiz.k/asia create mode 100644 src/games/quiz/quiz.k/babies create mode 100644 src/games/quiz/quiz.k/bard create mode 100644 src/games/quiz/quiz.k/chinese create mode 100644 src/games/quiz/quiz.k/collectives create mode 100644 src/games/quiz/quiz.k/ed create mode 100644 src/games/quiz/quiz.k/elements create mode 100644 src/games/quiz/quiz.k/europe create mode 100644 src/games/quiz/quiz.k/greek create mode 100644 src/games/quiz/quiz.k/inca create mode 100644 src/games/quiz/quiz.k/index create mode 100644 src/games/quiz/quiz.k/latin create mode 100644 src/games/quiz/quiz.k/locomotive create mode 100644 src/games/quiz/quiz.k/midearth create mode 100644 src/games/quiz/quiz.k/morse create mode 100644 src/games/quiz/quiz.k/murders create mode 100644 src/games/quiz/quiz.k/poetry create mode 100644 src/games/quiz/quiz.k/posneg create mode 100644 src/games/quiz/quiz.k/pres create mode 100644 src/games/quiz/quiz.k/province create mode 100644 src/games/quiz/quiz.k/seq-easy create mode 100644 src/games/quiz/quiz.k/seq-hard create mode 100644 src/games/quiz/quiz.k/sexes create mode 100644 src/games/quiz/quiz.k/sov create mode 100644 src/games/quiz/quiz.k/spell create mode 100644 src/games/quiz/quiz.k/state create mode 100644 src/games/quiz/quiz.k/trek create mode 100644 src/games/quiz/quiz.k/ucc create mode 100644 src/games/rain.6 create mode 100644 src/games/rain.c create mode 100644 src/games/robots/Makefile create mode 100644 src/games/robots/extern.c create mode 100644 src/games/robots/flush_in.c create mode 100644 src/games/robots/init_field.c create mode 100644 src/games/robots/main.c create mode 100644 src/games/robots/make_level.c create mode 100644 src/games/robots/move.c create mode 100644 src/games/robots/move_robs.c create mode 100644 src/games/robots/play_level.c create mode 100644 src/games/robots/query.c create mode 100644 src/games/robots/rnd_pos.c create mode 100644 src/games/robots/robots.6 create mode 100644 src/games/robots/robots.h create mode 100644 src/games/robots/score.c create mode 100644 src/games/rogue/CHANGES create mode 100644 src/games/rogue/Makefile create mode 100644 src/games/rogue/Makefile-linux create mode 100644 src/games/rogue/curses.c create mode 100644 src/games/rogue/doprnt.c create mode 100644 src/games/rogue/hit.c create mode 100644 src/games/rogue/init.c create mode 100644 src/games/rogue/inventory.c create mode 100644 src/games/rogue/level.c create mode 100644 src/games/rogue/machdep.c create mode 100644 src/games/rogue/main.c create mode 100644 src/games/rogue/message.c create mode 100644 src/games/rogue/monster.c create mode 100644 src/games/rogue/move.c create mode 100644 src/games/rogue/object.c create mode 100644 src/games/rogue/pack.c create mode 100644 src/games/rogue/play.c create mode 100644 src/games/rogue/random.c create mode 100644 src/games/rogue/ring.c create mode 100644 src/games/rogue/rogue.6 create mode 100644 src/games/rogue/rogue.h create mode 100644 src/games/rogue/room.c create mode 100644 src/games/rogue/save.c create mode 100644 src/games/rogue/score.c create mode 100644 src/games/rogue/spec_hit.c create mode 100644 src/games/rogue/throw.c create mode 100644 src/games/rogue/trap.c create mode 100644 src/games/rogue/use.c create mode 100644 src/games/rogue/zap.c create mode 100644 src/games/sail/Makefile create mode 100644 src/games/sail/Makefile-linux create mode 100644 src/games/sail/assorted.c create mode 100644 src/games/sail/doprnt.c create mode 100644 src/games/sail/dr_1.c create mode 100644 src/games/sail/dr_2.c create mode 100644 src/games/sail/dr_3.c create mode 100644 src/games/sail/dr_4.c create mode 100644 src/games/sail/dr_5.c create mode 100644 src/games/sail/dr_main.c create mode 100644 src/games/sail/driver.h create mode 100644 src/games/sail/externs.h create mode 100644 src/games/sail/game.c create mode 100644 src/games/sail/globals.c create mode 100644 src/games/sail/lo_main.c create mode 100644 src/games/sail/machdep.h create mode 100644 src/games/sail/main.c create mode 100644 src/games/sail/misc.c create mode 100644 src/games/sail/parties.c create mode 100644 src/games/sail/pl_1.c create mode 100644 src/games/sail/pl_2.c create mode 100644 src/games/sail/pl_3.c create mode 100644 src/games/sail/pl_4.c create mode 100644 src/games/sail/pl_5.c create mode 100644 src/games/sail/pl_6.c create mode 100644 src/games/sail/pl_7.c create mode 100644 src/games/sail/pl_main.c create mode 100644 src/games/sail/player.h create mode 100644 src/games/sail/sail.6 create mode 100644 src/games/sail/sync.c create mode 100644 src/games/sail/version.c create mode 100644 src/games/snake/Makefile create mode 100644 src/games/snake/busy.c create mode 100644 src/games/snake/move.c create mode 100644 src/games/snake/snake.6 create mode 100644 src/games/snake/snake.c create mode 100644 src/games/snake/snake.h create mode 100644 src/games/snake/snscore.c create mode 100644 src/games/trek/Makefile create mode 100644 src/games/trek/README create mode 100644 src/games/trek/abandon.c create mode 100644 src/games/trek/attack.c create mode 100644 src/games/trek/autover.c create mode 100644 src/games/trek/board.x create mode 100644 src/games/trek/capture.c create mode 100644 src/games/trek/check_out.c create mode 100644 src/games/trek/checkcond.c create mode 100644 src/games/trek/compkl.c create mode 100644 src/games/trek/computer.c create mode 100644 src/games/trek/damage.c create mode 100644 src/games/trek/damaged.c create mode 100644 src/games/trek/dcrept.c create mode 100644 src/games/trek/destruct.c create mode 100644 src/games/trek/dock.c create mode 100644 src/games/trek/docs/read_me.nr create mode 100644 src/games/trek/docs/things create mode 100644 src/games/trek/docs/trekmanual.nr create mode 100644 src/games/trek/dumpgame.c create mode 100644 src/games/trek/dumpme.c create mode 100644 src/games/trek/dumpssradio.c create mode 100644 src/games/trek/events.c create mode 100644 src/games/trek/externs.c create mode 100644 src/games/trek/getcodi.c create mode 100644 src/games/trek/getpar.c create mode 100644 src/games/trek/getpar.h create mode 100644 src/games/trek/help.c create mode 100644 src/games/trek/impulse.c create mode 100644 src/games/trek/initquad.c create mode 100644 src/games/trek/kill.c create mode 100644 src/games/trek/klmove.c create mode 100644 src/games/trek/lose.c create mode 100644 src/games/trek/lrscan.c create mode 100644 src/games/trek/main.c create mode 100644 src/games/trek/move.c create mode 100644 src/games/trek/nova.c create mode 100644 src/games/trek/out.c create mode 100644 src/games/trek/phaser.c create mode 100644 src/games/trek/play.c create mode 100644 src/games/trek/ram.c create mode 100644 src/games/trek/ranf.c create mode 100644 src/games/trek/rest.c create mode 100644 src/games/trek/schedule.c create mode 100644 src/games/trek/score.c create mode 100644 src/games/trek/setup.c create mode 100644 src/games/trek/setwarp.c create mode 100644 src/games/trek/shell.c create mode 100644 src/games/trek/shield.c create mode 100644 src/games/trek/snova.c create mode 100644 src/games/trek/srscan.c create mode 100644 src/games/trek/systemname.c create mode 100644 src/games/trek/torped.c create mode 100644 src/games/trek/trek.6 create mode 100644 src/games/trek/trek.h create mode 100644 src/games/trek/utility.c create mode 100644 src/games/trek/visual.c create mode 100644 src/games/trek/warp.c create mode 100644 src/games/trek/win.c create mode 100644 src/games/warp/EXTERN.h create mode 100644 src/games/warp/INTERN.h create mode 100644 src/games/warp/MANIFEST create mode 100644 src/games/warp/Makefile create mode 100644 src/games/warp/Makefile-linux create mode 100644 src/games/warp/README create mode 100644 src/games/warp/bang.c create mode 100644 src/games/warp/bang.h create mode 100644 src/games/warp/init.c create mode 100644 src/games/warp/init.h create mode 100644 src/games/warp/intrp.c create mode 100644 src/games/warp/intrp.h create mode 100644 src/games/warp/move.c create mode 100644 src/games/warp/move.h create mode 100644 src/games/warp/object.c create mode 100644 src/games/warp/object.h create mode 100644 src/games/warp/patchlevel.h create mode 100644 src/games/warp/play.c create mode 100644 src/games/warp/play.h create mode 100644 src/games/warp/score.c create mode 100644 src/games/warp/score.h create mode 100644 src/games/warp/sig.c create mode 100644 src/games/warp/sig.h create mode 100644 src/games/warp/sm.c create mode 100644 src/games/warp/smp.0 create mode 100644 src/games/warp/smp.1 create mode 100644 src/games/warp/smp.2 create mode 100644 src/games/warp/smp.3 create mode 100644 src/games/warp/smp.4 create mode 100644 src/games/warp/smp.5 create mode 100644 src/games/warp/smp.6 create mode 100644 src/games/warp/smp.7 create mode 100644 src/games/warp/term.c create mode 100644 src/games/warp/term.h create mode 100644 src/games/warp/them.c create mode 100644 src/games/warp/them.h create mode 100644 src/games/warp/us.c create mode 100644 src/games/warp/us.h create mode 100644 src/games/warp/util.c create mode 100644 src/games/warp/util.h create mode 100644 src/games/warp/version.c create mode 100644 src/games/warp/version.h create mode 100644 src/games/warp/warp.6 create mode 100644 src/games/warp/warp.c create mode 100644 src/games/warp/warp.doc create mode 100644 src/games/warp/warp.h create mode 100644 src/games/warp/warp.man create mode 100644 src/games/warp/warp.news create mode 100644 src/games/warp/weapon.c create mode 100644 src/games/warp/weapon.h create mode 100644 src/games/worm.6 create mode 100644 src/games/worm.c create mode 100644 src/games/worms.6 create mode 100644 src/games/worms.c create mode 100644 src/games/wump.6 create mode 100644 src/games/wump.c create mode 100644 src/libc/Makefile create mode 100644 src/libc/compat/Makefile create mode 100644 src/libc/compat/creat.c create mode 100644 src/libc/compat/ftime.c create mode 100644 src/libc/compat/gethostid.c create mode 100644 src/libc/compat/gtty.c create mode 100644 src/libc/compat/memccpy.c create mode 100644 src/libc/compat/memchr.c create mode 100644 src/libc/compat/memcmp.c create mode 100644 src/libc/compat/memcpy.c create mode 100644 src/libc/compat/memset.c create mode 100644 src/libc/compat/nice.c create mode 100644 src/libc/compat/pause.c create mode 100644 src/libc/compat/rand.c create mode 100644 src/libc/compat/sethostid.c create mode 100644 src/libc/compat/setregid.c create mode 100644 src/libc/compat/setreuid.c create mode 100644 src/libc/compat/setrgid.c create mode 100644 src/libc/compat/setruid.c create mode 100644 src/libc/compat/sigcompat.c create mode 100644 src/libc/compat/strchr.c create mode 100644 src/libc/compat/strrchr.c create mode 100644 src/libc/compat/stty.c create mode 100644 src/libc/compat/times.c create mode 100644 src/libc/compat/tmpnam.c create mode 100644 src/libc/compat/utime.c create mode 100644 src/libc/gen/Makefile create mode 100644 src/libc/gen/abort.c create mode 100644 src/libc/gen/abs.c create mode 100644 src/libc/gen/alarm.c create mode 100644 src/libc/gen/atof.c create mode 100644 src/libc/gen/atoi.c create mode 100644 src/libc/gen/atol.c create mode 100644 src/libc/gen/bcmp-disabled.c create mode 100644 src/libc/gen/bcopy-disabled.c create mode 100644 src/libc/gen/bzero-disabled.c create mode 100644 src/libc/gen/calloc.c create mode 100644 src/libc/gen/closedir.c create mode 100644 src/libc/gen/crypt.c create mode 100644 src/libc/gen/ctime.c create mode 100644 src/libc/gen/ctype_.c create mode 100644 src/libc/gen/daemon.c create mode 100644 src/libc/gen/devname.c create mode 100644 src/libc/gen/ecvt.c create mode 100644 src/libc/gen/err.c create mode 100644 src/libc/gen/execvp.c create mode 100644 src/libc/gen/fabs.c create mode 100644 src/libc/gen/fakcu.c create mode 100644 src/libc/gen/ffs-disabled.c create mode 100644 src/libc/gen/frexp.c create mode 100644 src/libc/gen/fstab.c create mode 100644 src/libc/gen/gcvt.c create mode 100644 src/libc/gen/getenv.c create mode 100644 src/libc/gen/getgrent.c create mode 100644 src/libc/gen/getgrgid.c create mode 100644 src/libc/gen/getgrnam.c create mode 100644 src/libc/gen/getgrouplist.c create mode 100644 src/libc/gen/gethostname.c create mode 100644 src/libc/gen/getloadavg.c create mode 100644 src/libc/gen/getlogin.c create mode 100644 src/libc/gen/getmntinfo.c create mode 100644 src/libc/gen/getpagesize.c create mode 100644 src/libc/gen/getpass.c create mode 100644 src/libc/gen/getpwent.c create mode 100644 src/libc/gen/getttyent.c create mode 100644 src/libc/gen/getttynam.c create mode 100644 src/libc/gen/getusershell.c create mode 100644 src/libc/gen/getwd.c create mode 100644 src/libc/gen/index-disabled.c create mode 100644 src/libc/gen/initgroups.c create mode 100644 src/libc/gen/insque.c create mode 100644 src/libc/gen/isatty.c create mode 100644 src/libc/gen/isinf.c create mode 100644 src/libc/gen/isinff.c create mode 100644 src/libc/gen/isnan.c create mode 100644 src/libc/gen/isnanf.c create mode 100644 src/libc/gen/knlist.c create mode 100644 src/libc/gen/ldexp.c create mode 100644 src/libc/gen/malloc.c create mode 100644 src/libc/gen/mktemp.c create mode 100644 src/libc/gen/modf.c create mode 100644 src/libc/gen/modff.c create mode 100644 src/libc/gen/ndbm.c create mode 100644 src/libc/gen/nlist.c create mode 100644 src/libc/gen/opendir.c create mode 100644 src/libc/gen/perror.c create mode 100644 src/libc/gen/popen.c create mode 100644 src/libc/gen/psignal.c create mode 100644 src/libc/gen/qsort.c create mode 100644 src/libc/gen/random.c create mode 100644 src/libc/gen/readdir.c create mode 100644 src/libc/gen/regex.c create mode 100644 src/libc/gen/remque.c create mode 100644 src/libc/gen/rindex-disabled.c create mode 100644 src/libc/gen/scandir.c create mode 100644 src/libc/gen/seekdir.c create mode 100644 src/libc/gen/setenv.c create mode 100644 src/libc/gen/sethostname.c create mode 100644 src/libc/gen/setmode.c create mode 100644 src/libc/gen/siginterrupt.c create mode 100644 src/libc/gen/siglist.c create mode 100644 src/libc/gen/signal.c create mode 100644 src/libc/gen/sigsetops.c create mode 100644 src/libc/gen/sleep.c create mode 100644 src/libc/gen/strcasecmp.c create mode 100644 src/libc/gen/strcat.c create mode 100644 src/libc/gen/strcmp-disabled.c create mode 100644 src/libc/gen/strcpy.c create mode 100644 src/libc/gen/strdup.c create mode 100644 src/libc/gen/strftime.c create mode 100644 src/libc/gen/strlen-disabled.c create mode 100644 src/libc/gen/strncat.c create mode 100644 src/libc/gen/strncmp.c create mode 100644 src/libc/gen/strncpy.c create mode 100644 src/libc/gen/swab.c create mode 100644 src/libc/gen/sysctl.c create mode 100644 src/libc/gen/syslog.c create mode 100644 src/libc/gen/system.c create mode 100644 src/libc/gen/telldir.c create mode 100644 src/libc/gen/time.c create mode 100644 src/libc/gen/timezone.c create mode 100644 src/libc/gen/ttyname.c create mode 100644 src/libc/gen/ttyslot.c create mode 100644 src/libc/gen/ualarm.c create mode 100644 src/libc/gen/uname.c create mode 100644 src/libc/gen/usleep.c create mode 100644 src/libc/gen/valloc.c create mode 100644 src/libc/gen/wait.c create mode 100644 src/libc/gen/wait3.c create mode 100644 src/libc/gen/waitpid.c create mode 100644 src/libc/inet/Makefile create mode 100644 src/libc/inet/inet_addr.c create mode 100644 src/libc/inet/inet_lnaof.c create mode 100644 src/libc/inet/inet_maddr.c create mode 100644 src/libc/inet/inet_netof.c create mode 100644 src/libc/inet/inet_network.c create mode 100644 src/libc/inet/inet_ntoa.c create mode 100644 src/libc/mips/Makefile create mode 100644 src/libc/mips/gen/Makefile create mode 100644 src/libc/mips/gen/_setjmp.S create mode 100644 src/libc/mips/gen/htonl.S create mode 100644 src/libc/mips/gen/htons.S create mode 100644 src/libc/mips/gen/setjmp.S create mode 100644 src/libc/mips/gen/sigsetjmp.S create mode 100644 src/libc/mips/string/Makefile create mode 100644 src/libc/mips/string/bcmp.S create mode 100644 src/libc/mips/string/bcopy.S create mode 100644 src/libc/mips/string/bzero.S create mode 100644 src/libc/mips/string/ffs.S create mode 100644 src/libc/mips/string/index.S create mode 100644 src/libc/mips/string/memcpy.S create mode 100644 src/libc/mips/string/memmove.S create mode 100644 src/libc/mips/string/memset.S create mode 100644 src/libc/mips/string/rindex.S create mode 100644 src/libc/mips/string/strcmp.S create mode 100644 src/libc/mips/string/strlen.S create mode 100644 src/libc/mips/sys/Makefile create mode 100644 src/libc/mips/sys/SYS.h create mode 100644 src/libc/mips/sys/_brk.S create mode 100644 src/libc/mips/sys/_exit.S create mode 100644 src/libc/mips/sys/execl.c create mode 100644 src/libc/mips/sys/execle.c create mode 100644 src/libc/mips/sys/execv.c create mode 100644 src/libc/mips/sys/pipe.S create mode 100644 src/libc/mips/sys/ptrace.S create mode 100644 src/libc/mips/sys/sbrk.c create mode 100644 src/libc/mips/sys/sigaction.S create mode 100644 src/libc/net/Makefile create mode 100644 src/libc/net/getnbyaddr.c create mode 100644 src/libc/net/getnbyname.c create mode 100644 src/libc/net/getnent.c create mode 100644 src/libc/net/getpent.c create mode 100644 src/libc/net/getpname.c create mode 100644 src/libc/net/getproto.c create mode 100644 src/libc/net/getsbyname.c create mode 100644 src/libc/net/getsbyport.c create mode 100644 src/libc/net/getsent.c create mode 100644 src/libc/net/herror.c create mode 100644 src/libc/net/hosttable/Makefile create mode 100644 src/libc/net/hosttable/gethnamadr.c create mode 100644 src/libc/net/hosttable/gethostent.c create mode 100644 src/libc/net/named/Makefile create mode 100644 src/libc/net/named/gethnamadr.c create mode 100644 src/libc/net/named/sethostent.c create mode 100644 src/libc/net/rcmd.c create mode 100644 src/libc/net/res_comp.c create mode 100644 src/libc/net/res_debug.c create mode 100644 src/libc/net/res_init.c create mode 100644 src/libc/net/res_mkquery.c create mode 100644 src/libc/net/res_query.c create mode 100644 src/libc/net/res_send.c create mode 100644 src/libc/net/rexec.c create mode 100644 src/libc/net/ruserpass.c create mode 100644 src/libc/ns/Makefile create mode 100644 src/libc/ns/ns_addr.c create mode 100644 src/libc/ns/ns_ntoa.c create mode 100644 src/libc/runtime/CREDITS.txt create mode 100644 src/libc/runtime/LICENSE.txt create mode 100644 src/libc/runtime/Makefile create mode 100644 src/libc/runtime/README.txt create mode 100644 src/libc/runtime/addsf3.c create mode 100644 src/libc/runtime/comparesf2.c create mode 100644 src/libc/runtime/divsf3.c create mode 100644 src/libc/runtime/fixsfsi.c create mode 100644 src/libc/runtime/floatsisf.c create mode 100644 src/libc/runtime/fp_lib.h create mode 100644 src/libc/runtime/mulsf3.c create mode 100644 src/libc/runtime/negsf2.c create mode 100644 src/libc/runtime/sc_case.S create mode 100644 src/libc/runtime/subsf3.c create mode 100644 src/libc/stdio/Makefile create mode 100644 src/libc/stdio/clrerr.c create mode 100644 src/libc/stdio/doprnt.c create mode 100644 src/libc/stdio/doscan.c create mode 100644 src/libc/stdio/exit.c create mode 100644 src/libc/stdio/fdopen.c create mode 100644 src/libc/stdio/feof.c create mode 100644 src/libc/stdio/ferror.c create mode 100644 src/libc/stdio/fgetc.c create mode 100644 src/libc/stdio/fgets.c create mode 100644 src/libc/stdio/filbuf.c create mode 100644 src/libc/stdio/fileno.c create mode 100644 src/libc/stdio/findiop.c create mode 100644 src/libc/stdio/flsbuf.c create mode 100644 src/libc/stdio/fopen.c create mode 100644 src/libc/stdio/fprintf.c create mode 100644 src/libc/stdio/fputc.c create mode 100644 src/libc/stdio/fputs.c create mode 100644 src/libc/stdio/fread.c create mode 100644 src/libc/stdio/freopen.c create mode 100644 src/libc/stdio/fseek.c create mode 100644 src/libc/stdio/ftell.c create mode 100644 src/libc/stdio/fwrite.c create mode 100644 src/libc/stdio/getchar.c create mode 100644 src/libc/stdio/gets.c create mode 100644 src/libc/stdio/getw.c create mode 100644 src/libc/stdio/printf.c create mode 100644 src/libc/stdio/putchar.c create mode 100644 src/libc/stdio/puts.c create mode 100644 src/libc/stdio/putw.c create mode 100644 src/libc/stdio/remove.c create mode 100644 src/libc/stdio/rew.c create mode 100644 src/libc/stdio/scanf.c create mode 100644 src/libc/stdio/setbuf.c create mode 100644 src/libc/stdio/setbuffer.c create mode 100644 src/libc/stdio/setvbuf.c create mode 100644 src/libc/stdio/snprintf.c create mode 100644 src/libc/stdio/sprintf.c create mode 100644 src/libc/stdio/strout.c create mode 100644 src/libc/stdio/ungetc.c create mode 100644 src/libc/stdio/vfprintf.c create mode 100644 src/libc/stdio/vprintf.c create mode 100644 src/libc/stdio/vsprintf.c create mode 100644 src/libc/stdlib/Makefile create mode 100644 src/libc/stdlib/getopt.c create mode 100644 src/libc/stdlib/getsubopt.c create mode 100644 src/libc/stdlib/strtod.c create mode 100644 src/libc/stdlib/strtol.c create mode 100644 src/libc/stdlib/strtoul.c create mode 100644 src/libc/string/Makefile create mode 100644 src/libc/string/strcspn.c create mode 100644 src/libc/string/strerror.c create mode 100644 src/libc/string/strpbrk.c create mode 100644 src/libc/string/strsep.c create mode 100644 src/libc/string/strspn.c create mode 100644 src/libc/string/strstr.c create mode 100644 src/libc/string/strtok.c create mode 100644 src/libc/string/strtok_r.c create mode 100644 src/libcurses/Makefile create mode 100644 src/libcurses/addch.c create mode 100644 src/libcurses/addstr.c create mode 100644 src/libcurses/box.c create mode 100644 src/libcurses/clear.c create mode 100644 src/libcurses/clrtobot.c create mode 100644 src/libcurses/clrtoeol.c create mode 100644 src/libcurses/cr_put.c create mode 100644 src/libcurses/cr_tty.c create mode 100644 src/libcurses/curses.c create mode 100644 src/libcurses/curses.ext create mode 100644 src/libcurses/delch.c create mode 100644 src/libcurses/deleteln.c create mode 100644 src/libcurses/delwin.c create mode 100644 src/libcurses/endwin.c create mode 100644 src/libcurses/erase.c create mode 100644 src/libcurses/fullname.c create mode 100644 src/libcurses/getch.c create mode 100644 src/libcurses/getstr.c create mode 100644 src/libcurses/id_subwins.c create mode 100644 src/libcurses/idlok.c create mode 100644 src/libcurses/initscr.c create mode 100644 src/libcurses/insch.c create mode 100644 src/libcurses/insertln.c create mode 100644 src/libcurses/longname.c create mode 100644 src/libcurses/move.c create mode 100644 src/libcurses/mvprintw.c create mode 100644 src/libcurses/mvscanw.c create mode 100644 src/libcurses/mvwin.c create mode 100644 src/libcurses/newwin.c create mode 100644 src/libcurses/overlay.c create mode 100644 src/libcurses/overwrite.c create mode 100644 src/libcurses/printw.c create mode 100644 src/libcurses/putchar.c create mode 100644 src/libcurses/refresh.c create mode 100644 src/libcurses/scanw.c create mode 100644 src/libcurses/scroll.c create mode 100644 src/libcurses/standout.c create mode 100644 src/libcurses/test.c create mode 100644 src/libcurses/toucholap.c create mode 100644 src/libcurses/touchwin.c create mode 100644 src/libcurses/tstp.c create mode 100644 src/libcurses/unctrl.c create mode 100644 src/libicache/icache.ld create mode 100644 src/libicache/icachec.c create mode 100644 src/libicache/icaches.s create mode 100644 src/libicache/license.txt create mode 100644 src/libicache/readme.txt create mode 100644 src/libm/Makefile create mode 100644 src/libm/asin.c create mode 100644 src/libm/atan.c create mode 100644 src/libm/erf.c create mode 100644 src/libm/exp.c create mode 100644 src/libm/fabs.c create mode 100644 src/libm/floor.c create mode 100644 src/libm/fmod.c create mode 100644 src/libm/hypot.c create mode 100644 src/libm/ieee.h create mode 100644 src/libm/j0.c create mode 100644 src/libm/j1.c create mode 100644 src/libm/jn.c create mode 100644 src/libm/log.c create mode 100644 src/libm/pow.c create mode 100644 src/libm/sin.c create mode 100644 src/libm/sinh.c create mode 100644 src/libm/sqrt.c create mode 100644 src/libm/tan.c create mode 100644 src/libm/tanh.c create mode 100644 src/libtcl/Makefile create mode 100644 src/libtcl/doc/AddErrInfo.3 create mode 100644 src/libtcl/doc/AssembCmd.3 create mode 100644 src/libtcl/doc/Backslash.3 create mode 100644 src/libtcl/doc/Concat.3 create mode 100644 src/libtcl/doc/CrtCommand.3 create mode 100644 src/libtcl/doc/CrtInterp.3 create mode 100644 src/libtcl/doc/CrtPipelin.3 create mode 100644 src/libtcl/doc/CrtTrace.3 create mode 100644 src/libtcl/doc/Eval.3 create mode 100644 src/libtcl/doc/ExprLong.3 create mode 100644 src/libtcl/doc/Fork.3 create mode 100644 src/libtcl/doc/GetInt.3 create mode 100644 src/libtcl/doc/Hash.3 create mode 100644 src/libtcl/doc/History.3 create mode 100644 src/libtcl/doc/Interp.3 create mode 100644 src/libtcl/doc/SetResult.3 create mode 100644 src/libtcl/doc/SetVar.3 create mode 100644 src/libtcl/doc/SplitList.3 create mode 100644 src/libtcl/doc/StrMatch.3 create mode 100644 src/libtcl/doc/Tcl.n create mode 100644 src/libtcl/doc/TildeSubst.3 create mode 100644 src/libtcl/doc/TraceVar.3 create mode 100644 src/libtcl/doc/library.n create mode 100644 src/libtcl/doc/man.macros create mode 100644 src/libtcl/hash.h create mode 100644 src/libtcl/internal.h create mode 100644 src/libtcl/regexp.c create mode 100644 src/libtcl/regexp.h create mode 100644 src/libtcl/regpriv.h create mode 100644 src/libtcl/regsub.c create mode 100644 src/libtcl/tclassem.c create mode 100644 src/libtcl/tclbasic.c create mode 100644 src/libtcl/tclcmdah.c create mode 100644 src/libtcl/tclcmdil.c create mode 100644 src/libtcl/tclcmdmz.c create mode 100644 src/libtcl/tclenv.c create mode 100644 src/libtcl/tclexpr.c create mode 100644 src/libtcl/tclget.c create mode 100644 src/libtcl/tclglob.c create mode 100644 src/libtcl/tclhash.c create mode 100644 src/libtcl/tclparse.c create mode 100644 src/libtcl/tclproc.c create mode 100644 src/libtcl/tclunxaz.c create mode 100644 src/libtcl/tclutil.c create mode 100644 src/libtcl/tcluxstr.c create mode 100644 src/libtcl/tcluxutl.c create mode 100644 src/libtcl/tclvar.c create mode 100644 src/libtermlib/Makefile create mode 100644 src/libtermlib/tc1.c create mode 100644 src/libtermlib/tc2.c create mode 100644 src/libtermlib/tc3.c create mode 100644 src/libtermlib/tcattr.c create mode 100644 src/libtermlib/termcap.c create mode 100644 src/libtermlib/termcap/Makefile create mode 100644 src/libtermlib/termcap/README create mode 100644 src/libtermlib/termcap/map3270 create mode 100644 src/libtermlib/termcap/reorder create mode 100644 src/libtermlib/termcap/tabset/3101 create mode 100644 src/libtermlib/termcap/tabset/aa create mode 100644 src/libtermlib/termcap/tabset/aed512 create mode 100644 src/libtermlib/termcap/tabset/beehive create mode 100644 src/libtermlib/termcap/tabset/diablo create mode 100644 src/libtermlib/termcap/tabset/dtc382 create mode 100644 src/libtermlib/termcap/tabset/ibm3101 create mode 100644 src/libtermlib/termcap/tabset/std create mode 100644 src/libtermlib/termcap/tabset/stdcrt create mode 100644 src/libtermlib/termcap/tabset/tandem653 create mode 100644 src/libtermlib/termcap/tabset/teleray create mode 100644 src/libtermlib/termcap/tabset/vt100 create mode 100644 src/libtermlib/termcap/tabset/wyse-adds create mode 100644 src/libtermlib/termcap/tabset/xerox1720 create mode 100644 src/libtermlib/termcap/tabset/xerox1730 create mode 100644 src/libtermlib/termcap/tabset/xerox1730-lm create mode 100644 src/libtermlib/termcap/tabset/zenith29 create mode 100644 src/libtermlib/termcap/termcap.local create mode 100644 src/libtermlib/termcap/termcap.src create mode 100644 src/libtermlib/tgoto.c create mode 100644 src/libtermlib/tputs.c create mode 100644 src/libutil/Makefile create mode 100644 src/libutil/login.c create mode 100644 src/libutil/logout.c create mode 100644 src/libutil/logwtmp.c create mode 100644 src/libvmf/Makefile create mode 100644 src/libvmf/vmf.3 create mode 100644 src/libvmf/vmf.c create mode 100644 src/libvmf/vmlib.ms create mode 100644 src/libwiznet/Makefile create mode 100644 src/libwiznet/client.c create mode 100644 src/libwiznet/ethernet.c create mode 100644 src/libwiznet/server.c create mode 100644 src/libwiznet/socket.c create mode 100644 src/libwiznet/udp.c create mode 100644 src/libwiznet/w5100.c create mode 100644 src/share/Makefile create mode 100644 src/share/misc/Makefile create mode 100644 src/startup-mips/Makefile create mode 100644 src/startup-mips/crt0.c create mode 100644 src/startup-mips/mcount.S create mode 100644 src/startup-mips/mon.c create mode 100644 src/startup-mips/mon.ex create mode 100644 sys/include/adc.h create mode 100644 sys/include/buf.h create mode 100644 sys/include/callout.h create mode 100644 sys/include/clist.h create mode 100644 sys/include/conf.h create mode 100644 sys/include/debug.h create mode 100644 sys/include/dir.h create mode 100644 sys/include/disk.h create mode 100644 sys/include/dk.h create mode 100644 sys/include/dkbad.h create mode 100644 sys/include/errno.h create mode 100644 sys/include/exec.h create mode 100644 sys/include/fcntl.h create mode 100644 sys/include/file.h create mode 100644 sys/include/fs.h create mode 100644 sys/include/glcd.h create mode 100644 sys/include/glob.h create mode 100644 sys/include/gpio.h create mode 100644 sys/include/inode.h create mode 100644 sys/include/ioctl.h create mode 100644 sys/include/kernel.h create mode 100644 sys/include/map.h create mode 100644 sys/include/mount.h create mode 100644 sys/include/msgbuf.h create mode 100644 sys/include/mtio.h create mode 100644 sys/include/namei.h create mode 100644 sys/include/oc.h create mode 100644 sys/include/param.h create mode 100644 sys/include/picga.h create mode 100644 sys/include/proc.h create mode 100644 sys/include/ptrace.h create mode 100644 sys/include/pty.h create mode 100644 sys/include/rd_flash.h create mode 100644 sys/include/rd_mrams.h create mode 100644 sys/include/rd_sdramp.h create mode 100644 sys/include/rd_sramc.h create mode 100644 sys/include/rdisk.h create mode 100644 sys/include/reboot.h create mode 100644 sys/include/resource.h create mode 100644 sys/include/select.h create mode 100644 sys/include/signal.h create mode 100644 sys/include/signalvar.h create mode 100644 sys/include/spi.h create mode 100644 sys/include/spi_bus.h create mode 100644 sys/include/stat.h create mode 100644 sys/include/swap.h create mode 100644 sys/include/sysctl.h create mode 100644 sys/include/syslog.h create mode 100644 sys/include/systm.h create mode 100644 sys/include/time.h create mode 100644 sys/include/times.h create mode 100644 sys/include/trace.h create mode 100644 sys/include/tty.h create mode 100644 sys/include/ttychars.h create mode 100644 sys/include/ttydev.h create mode 100644 sys/include/types.h create mode 100644 sys/include/uart.h create mode 100644 sys/include/uio.h create mode 100644 sys/include/usb_uart.h create mode 100644 sys/include/user.h create mode 100644 sys/include/utsname.h create mode 100644 sys/include/vm.h create mode 100644 sys/include/vmmac.h create mode 100644 sys/include/vmmeter.h create mode 100644 sys/include/vmparam.h create mode 100644 sys/include/vmsystm.h create mode 100644 sys/include/wait.h create mode 100644 sys/kernel/init_main.c create mode 100644 sys/kernel/init_sysent.c create mode 100644 sys/kernel/kern_clock.c create mode 100644 sys/kernel/kern_descrip.c create mode 100644 sys/kernel/kern_exec.c create mode 100644 sys/kernel/kern_exit.c create mode 100644 sys/kernel/kern_fork.c create mode 100644 sys/kernel/kern_glob.c create mode 100644 sys/kernel/kern_mman.c create mode 100644 sys/kernel/kern_proc.c create mode 100644 sys/kernel/kern_prot.c create mode 100644 sys/kernel/kern_prot2.c create mode 100644 sys/kernel/kern_resource.c create mode 100644 sys/kernel/kern_sig.c create mode 100644 sys/kernel/kern_sig2.c create mode 100644 sys/kernel/kern_subr.c create mode 100644 sys/kernel/kern_synch.c create mode 100644 sys/kernel/kern_sysctl.c create mode 100644 sys/kernel/kern_time.c create mode 100644 sys/kernel/subr_log.c create mode 100644 sys/kernel/subr_prf.c create mode 100644 sys/kernel/subr_rmap.c create mode 100644 sys/kernel/sys_generic.c create mode 100644 sys/kernel/sys_inode.c create mode 100644 sys/kernel/sys_pipe.c create mode 100644 sys/kernel/sys_process.c create mode 100644 sys/kernel/syscalls.c create mode 100644 sys/kernel/tty.c create mode 100644 sys/kernel/tty_pty.c create mode 100644 sys/kernel/tty_subr.c create mode 100644 sys/kernel/tty_tty.c create mode 100644 sys/kernel/ufs_alloc.c create mode 100644 sys/kernel/ufs_bio.c create mode 100644 sys/kernel/ufs_bmap.c create mode 100644 sys/kernel/ufs_dsort.c create mode 100644 sys/kernel/ufs_fio.c create mode 100644 sys/kernel/ufs_inode.c create mode 100644 sys/kernel/ufs_mount.c create mode 100644 sys/kernel/ufs_namei.c create mode 100644 sys/kernel/ufs_subr.c create mode 100644 sys/kernel/ufs_syscalls.c create mode 100644 sys/kernel/ufs_syscalls2.c create mode 100644 sys/kernel/vfs_vnops.c create mode 100644 sys/kernel/vm_sched.c create mode 100644 sys/kernel/vm_swap.c create mode 100644 sys/kernel/vm_swp.c create mode 100644 sys/pic32/MAKEDEV.sh create mode 100644 sys/pic32/Makefile create mode 100644 sys/pic32/README create mode 120000 sys/pic32/_startup.S create mode 100644 sys/pic32/adc.c create mode 100644 sys/pic32/baremetal/BAREMETAL create mode 100644 sys/pic32/baremetal/Makefile create mode 100644 sys/pic32/baremetal/bare-metal.ld create mode 100644 sys/pic32/baremetal/devcfg.c create mode 100644 sys/pic32/cfg/adc.dev create mode 100644 sys/pic32/cfg/bare.ld create mode 100644 sys/pic32/cfg/boot.ld create mode 100644 sys/pic32/cfg/bootloader-max32.ld create mode 100644 sys/pic32/cfg/bootloader-maxcolor.ld create mode 100644 sys/pic32/cfg/bootloader-maximite.ld create mode 100644 sys/pic32/cfg/bootloader-sdram.ld create mode 100644 sys/pic32/cfg/bootloader-ubw32.ld create mode 100644 sys/pic32/cfg/bootloader.dev create mode 100644 sys/pic32/cfg/bootloader.ld create mode 100644 sys/pic32/cfg/console.dev create mode 100644 sys/pic32/cfg/devcfg.dev create mode 100644 sys/pic32/cfg/foreignbootloader.dev create mode 100644 sys/pic32/cfg/fubarino.map create mode 100644 sys/pic32/cfg/generic.map create mode 100644 sys/pic32/cfg/glcd.dev create mode 100644 sys/pic32/cfg/glob.dev create mode 100644 sys/pic32/cfg/global.dev create mode 100644 sys/pic32/cfg/gpio.dev create mode 100644 sys/pic32/cfg/kernel.dev create mode 100644 sys/pic32/cfg/log.dev create mode 100644 sys/pic32/cfg/max32.map create mode 100644 sys/pic32/cfg/mrams.dev create mode 100644 sys/pic32/cfg/oc.dev create mode 100644 sys/pic32/cfg/picga.dev create mode 100644 sys/pic32/cfg/power.dev create mode 100644 sys/pic32/cfg/pty.dev create mode 100644 sys/pic32/cfg/rdisk.dev create mode 100644 sys/pic32/cfg/sd.dev create mode 100644 sys/pic32/cfg/sdramp.dev create mode 100644 sys/pic32/cfg/spi.dev create mode 100644 sys/pic32/cfg/spibus.dev create mode 100644 sys/pic32/cfg/sramc.dev create mode 100644 sys/pic32/cfg/tty.dev create mode 100644 sys/pic32/cfg/uart.dev create mode 100644 sys/pic32/cfg/uartconsole.dev create mode 100644 sys/pic32/cfg/uartusb.dev create mode 100644 sys/pic32/cfg/ufs.dev create mode 100644 sys/pic32/cfg/usbconsole.dev create mode 100644 sys/pic32/clock.c create mode 100644 sys/pic32/cons.c create mode 100644 sys/pic32/cpu.h create mode 100644 sys/pic32/devcfg.c create mode 100644 sys/pic32/devsw.c create mode 100644 sys/pic32/diag/Makefile create mode 100644 sys/pic32/diag/main.c create mode 100644 sys/pic32/dip/DIP create mode 100644 sys/pic32/dip/Makefile create mode 100644 sys/pic32/dip/bare-metal.ld create mode 100644 sys/pic32/dip/devcfg.c create mode 100644 sys/pic32/dip/using-bootloader.ld create mode 100644 sys/pic32/drivers.mk create mode 100644 sys/pic32/duinomite-e-uart/DUINOMITE-E-UART create mode 100644 sys/pic32/duinomite-e-uart/Makefile create mode 100644 sys/pic32/duinomite-e/DUINOMITE-E create mode 100644 sys/pic32/duinomite-e/Makefile create mode 100644 sys/pic32/duinomite-uart/DUINOMITE-UART create mode 100644 sys/pic32/duinomite-uart/Makefile create mode 100644 sys/pic32/duinomite-uart/using-bootloader.ld create mode 100644 sys/pic32/duinomite/DUINOMITE create mode 100644 sys/pic32/duinomite/Makefile create mode 100644 sys/pic32/duinomite/using-bootloader.ld create mode 100644 sys/pic32/exception.c create mode 100644 sys/pic32/explorer16/EXPLORER16 create mode 100644 sys/pic32/explorer16/Makefile create mode 100644 sys/pic32/explorer16/bare-metal.ld create mode 100644 sys/pic32/explorer16/devcfg.c create mode 100644 sys/pic32/float.h create mode 100644 sys/pic32/fubarino-uart-sramc/FUBARINO-UART-SRAMC create mode 100644 sys/pic32/fubarino-uart-sramc/Makefile create mode 100644 sys/pic32/fubarino-uart-sramc/Makefile.local create mode 100644 sys/pic32/fubarino-uart-sramc/Makefile_old create mode 100644 sys/pic32/fubarino-uart-sramc/using-bootloader.ld create mode 100644 sys/pic32/fubarino-uart/FUBARINO-UART create mode 100644 sys/pic32/fubarino-uart/Makefile create mode 100644 sys/pic32/fubarino-uart/using-bootloader.ld create mode 100644 sys/pic32/fubarino/FUBARINO create mode 100644 sys/pic32/fubarino/Makefile create mode 100644 sys/pic32/fubarino/using-bootloader.ld create mode 100644 sys/pic32/gcc-config.mk create mode 100644 sys/pic32/glcd.c create mode 100644 sys/pic32/gpio.c create mode 100644 sys/pic32/io.h create mode 100644 sys/pic32/kernel-post.mk create mode 100644 sys/pic32/limits.h create mode 100644 sys/pic32/machdep.c create mode 100644 sys/pic32/machparam.h create mode 100644 sys/pic32/max32-eth/MAX32-ETH create mode 100644 sys/pic32/max32-eth/Makefile create mode 100644 sys/pic32/max32-eth/using-bootloader.ld create mode 100644 sys/pic32/max32/MAX32 create mode 100644 sys/pic32/max32/MAX32-ETH create mode 100644 sys/pic32/max32/Makefile create mode 100644 sys/pic32/max32/using-bootloader.ld create mode 100644 sys/pic32/maximite-color/MAXCOLOR create mode 100644 sys/pic32/maximite-color/Makefile create mode 100644 sys/pic32/maximite/MAXIMITE create mode 100644 sys/pic32/maximite/Makefile create mode 100644 sys/pic32/maximite/kbd.c create mode 100644 sys/pic32/maximite/kbd.h create mode 100644 sys/pic32/maximite/russian.inc create mode 100644 sys/pic32/maximite/usascii.inc create mode 100644 sys/pic32/maximite/using-bootloader.ld create mode 100644 sys/pic32/meb/MEB create mode 100644 sys/pic32/meb/Makefile create mode 100644 sys/pic32/meb/README create mode 100644 sys/pic32/meb/using-bootloader.ld create mode 100644 sys/pic32/mem.c create mode 100644 sys/pic32/mmb-mx7/MMB-MX7 create mode 100644 sys/pic32/mmb-mx7/Makefile create mode 100644 sys/pic32/newvers.sh create mode 100644 sys/pic32/oc.c create mode 100644 sys/pic32/pic32mx.h create mode 100644 sys/pic32/picga.c create mode 100644 sys/pic32/pinguino-micro/Makefile create mode 100644 sys/pic32/pinguino-micro/PINGUINO-MICRO create mode 100644 sys/pic32/pinguino-micro/using-bootloader.ld create mode 100644 sys/pic32/power_control.c create mode 100644 sys/pic32/rd_flash.c create mode 100644 sys/pic32/rd_mrams.c create mode 100644 sys/pic32/rd_sd.c create mode 100644 sys/pic32/rd_sdramp.c create mode 100644 sys/pic32/rd_sdramp_config.h create mode 100644 sys/pic32/rd_sramc.c create mode 100644 sys/pic32/rdisk.c create mode 100644 sys/pic32/retroone/Makefile create mode 100644 sys/pic32/retroone/bare-metal.ld create mode 100644 sys/pic32/retroone/devcfg.c create mode 100644 sys/pic32/sdram.S create mode 100644 sys/pic32/sdram.h create mode 100644 sys/pic32/signal.c create mode 100644 sys/pic32/spi.c create mode 100644 sys/pic32/spi_bus.c create mode 100644 sys/pic32/ssd1926-sdcard.c create mode 100644 sys/pic32/ssd1926.h create mode 100644 sys/pic32/starter-kit/Makefile create mode 100644 sys/pic32/starter-kit/STARTER-KIT create mode 100644 sys/pic32/starter-kit/using-bootloader.ld create mode 100644 sys/pic32/startup.S create mode 100644 sys/pic32/swap.c create mode 100644 sys/pic32/sysctl.c create mode 100644 sys/pic32/uart.c create mode 100644 sys/pic32/ubw32-uart-sdram/Makefile create mode 100644 sys/pic32/ubw32-uart-sdram/UBW32-UART-SDRAM create mode 100644 sys/pic32/ubw32-uart-sdram/using-bootloader-ker.ld create mode 100644 sys/pic32/ubw32-uart-sdram/using-bootloader.ld create mode 100644 sys/pic32/ubw32-uart/Makefile create mode 100644 sys/pic32/ubw32-uart/UBW32-UART create mode 100644 sys/pic32/ubw32-uart/using-bootloader.ld create mode 100644 sys/pic32/ubw32/Makefile create mode 100644 sys/pic32/ubw32/UBW32 create mode 100644 sys/pic32/ubw32/using-bootloader.ld create mode 100644 sys/pic32/usb_boot.c create mode 100644 sys/pic32/usb_ch9.h create mode 100644 sys/pic32/usb_console.c create mode 100644 sys/pic32/usb_device.c create mode 100644 sys/pic32/usb_device.h create mode 100644 sys/pic32/usb_function_cdc.c create mode 100644 sys/pic32/usb_function_cdc.h create mode 100644 sys/pic32/usb_function_hid.c create mode 100644 sys/pic32/usb_function_hid.h create mode 100644 sys/pic32/usb_hal_pic32.h create mode 100644 sys/pic32/usb_uart.c create mode 100644 target.mk create mode 100644 tools/Makefile create mode 100644 tools/configsys/Makefile create mode 100644 tools/configsys/Makefile.test create mode 100644 tools/configsys/cluster.cpp create mode 100644 tools/configsys/cluster.h create mode 100644 tools/configsys/config.cpp create mode 100644 tools/configsys/config.h create mode 100644 tools/configsys/core.cpp create mode 100644 tools/configsys/core.h create mode 100644 tools/configsys/cores/pic32mx7.cor create mode 100644 tools/configsys/device.cpp create mode 100644 tools/configsys/device.h create mode 100644 tools/configsys/gstore.cpp create mode 100644 tools/configsys/gstore.h create mode 100644 tools/configsys/instance.h create mode 100644 tools/configsys/main.cpp create mode 100644 tools/configsys/mapping.cpp create mode 100644 tools/configsys/mapping.h create mode 100644 tools/configsys/util.cpp create mode 100644 tools/configsys/util.h create mode 100644 tools/elf2aout/Makefile create mode 100644 tools/elf2aout/elf2aout.c create mode 100644 tools/fsutil/Makefile create mode 100644 tools/fsutil/block.c create mode 100644 tools/fsutil/bsdfs.h create mode 100644 tools/fsutil/check.c create mode 100644 tools/fsutil/create.c create mode 100644 tools/fsutil/file.c create mode 100644 tools/fsutil/fsutil.c create mode 100644 tools/fsutil/inode.c create mode 100644 tools/fsutil/superblock.c create mode 100644 tools/icache/Makefile create mode 100644 tools/icache/ice2aout.c create mode 100644 tools/icache/license.txt create mode 100644 tools/icache/readme.txt create mode 100644 tools/libufs/Makefile create mode 100644 tools/libufs/fops.c create mode 100644 tools/libufs/fs.c create mode 100644 tools/libufs/libufs.h create mode 100644 tools/libufs/set.c create mode 100644 tools/libufs/ucat.c create mode 100644 tools/libufs/ucd.c create mode 100644 tools/libufs/uchgrp.c create mode 100644 tools/libufs/uchmod.c create mode 100644 tools/libufs/uchown.c create mode 100644 tools/libufs/ulogin.c create mode 100644 tools/libufs/uls.c create mode 100644 tools/libufs/umkdir.c create mode 100644 tools/libufs/umkfs.c create mode 100644 tools/libufs/util.c create mode 100644 tools/mkrd/Makefile create mode 100644 tools/mkrd/mkrd.c create mode 100644 tools/mkrd/rdisk.h create mode 100644 tools/virtualmips/.indent.pro create mode 100644 tools/virtualmips/.le.ini create mode 100644 tools/virtualmips/LICENSE create mode 100644 tools/virtualmips/Makefile create mode 100644 tools/virtualmips/README create mode 100644 tools/virtualmips/SConstruct create mode 100644 tools/virtualmips/adm5120/adm5120.c create mode 100644 tools/virtualmips/adm5120/adm5120.conf create mode 100644 tools/virtualmips/adm5120/adm5120.h create mode 100644 tools/virtualmips/adm5120/adm5120_dev_intctrl.c create mode 100644 tools/virtualmips/adm5120/adm5120_dev_mpmc.c create mode 100644 tools/virtualmips/adm5120/adm5120_dev_pci.c create mode 100644 tools/virtualmips/adm5120/adm5120_dev_sw.c create mode 100644 tools/virtualmips/adm5120/adm5120_dev_uart.c create mode 100644 tools/virtualmips/adm5120/adm5120_host_alarm.c create mode 100644 tools/virtualmips/bsd_syscalls.h create mode 100644 tools/virtualmips/config.c create mode 100644 tools/virtualmips/config.h create mode 100644 tools/virtualmips/cpu.c create mode 100644 tools/virtualmips/cpu.h create mode 100644 tools/virtualmips/crc.c create mode 100644 tools/virtualmips/crc.h create mode 100644 tools/virtualmips/debug.c create mode 100644 tools/virtualmips/debug.h create mode 100644 tools/virtualmips/dev_cs8900.c create mode 100644 tools/virtualmips/dev_cs8900.h create mode 100644 tools/virtualmips/dev_nand_flash_1g.c create mode 100644 tools/virtualmips/dev_nand_flash_1g.h create mode 100644 tools/virtualmips/dev_nor_flash_4m.c create mode 100644 tools/virtualmips/dev_ram.c create mode 100644 tools/virtualmips/dev_sdcard.c create mode 100644 tools/virtualmips/dev_sdcard.h create mode 100644 tools/virtualmips/dev_swap.c create mode 100644 tools/virtualmips/dev_swap.h create mode 100644 tools/virtualmips/dev_vtty.c create mode 100644 tools/virtualmips/dev_vtty.h create mode 100644 tools/virtualmips/device.c create mode 100644 tools/virtualmips/device.h create mode 100644 tools/virtualmips/gdb_interface.c create mode 100644 tools/virtualmips/gdb_interface.h create mode 100644 tools/virtualmips/jz4740/jz4740.c create mode 100644 tools/virtualmips/jz4740/jz4740.h create mode 100644 tools/virtualmips/jz4740/jz4740_dev_cpm.c create mode 100644 tools/virtualmips/jz4740/jz4740_dev_dma.c create mode 100644 tools/virtualmips/jz4740/jz4740_dev_emc.c create mode 100644 tools/virtualmips/jz4740/jz4740_dev_gpio.c create mode 100644 tools/virtualmips/jz4740/jz4740_dev_int.c create mode 100644 tools/virtualmips/jz4740/jz4740_dev_lcd.c create mode 100644 tools/virtualmips/jz4740/jz4740_dev_rtc.c create mode 100644 tools/virtualmips/jz4740/jz4740_dev_ts.c create mode 100644 tools/virtualmips/jz4740/jz4740_dev_uart.c create mode 100644 tools/virtualmips/jz4740/jz4740_dev_wdt_tcu.c create mode 100644 tools/virtualmips/main.c create mode 100644 tools/virtualmips/mempool.c create mode 100644 tools/virtualmips/mempool.h create mode 100644 tools/virtualmips/mips-dis.c create mode 100644 tools/virtualmips/mips-opc.c create mode 100644 tools/virtualmips/mips-opcode.h create mode 100644 tools/virtualmips/mips.c create mode 100644 tools/virtualmips/mips.h create mode 100644 tools/virtualmips/mips16-opc.c create mode 100644 tools/virtualmips/mips_codetable.c create mode 100644 tools/virtualmips/mips_cp0.c create mode 100644 tools/virtualmips/mips_cp0.h create mode 100644 tools/virtualmips/mips_exec.c create mode 100644 tools/virtualmips/mips_exec.h create mode 100644 tools/virtualmips/mips_fdd.c create mode 100644 tools/virtualmips/mips_fdd.h create mode 100644 tools/virtualmips/mips_hostalarm.c create mode 100644 tools/virtualmips/mips_hostalarm.h create mode 100644 tools/virtualmips/mips_jit.c create mode 100644 tools/virtualmips/mips_jit.h create mode 100644 tools/virtualmips/mips_memory.c create mode 100644 tools/virtualmips/mips_memory.h create mode 100644 tools/virtualmips/net.h create mode 100644 tools/virtualmips/net_io.c create mode 100644 tools/virtualmips/net_io.h create mode 100644 tools/virtualmips/pavo.c create mode 100644 tools/virtualmips/pavo.conf create mode 100644 tools/virtualmips/pavo.h create mode 100644 tools/virtualmips/pic32.c create mode 100644 tools/virtualmips/pic32.h create mode 100644 tools/virtualmips/pic32_dev_adc.c create mode 100644 tools/virtualmips/pic32_dev_bmxcon.c create mode 100644 tools/virtualmips/pic32_dev_devcfg.c create mode 100644 tools/virtualmips/pic32_dev_dmacon.c create mode 100644 tools/virtualmips/pic32_dev_flash.c create mode 100644 tools/virtualmips/pic32_dev_gpio.c create mode 100644 tools/virtualmips/pic32_dev_intcon.c create mode 100644 tools/virtualmips/pic32_dev_prefetch.c create mode 100644 tools/virtualmips/pic32_dev_rtcc.c create mode 100644 tools/virtualmips/pic32_dev_spi.c create mode 100644 tools/virtualmips/pic32_dev_syscon.c create mode 100644 tools/virtualmips/pic32_dev_timer.c create mode 100644 tools/virtualmips/pic32_dev_uart.c create mode 100644 tools/virtualmips/pic32_explorer16.conf create mode 100644 tools/virtualmips/pic32_max32.conf create mode 100644 tools/virtualmips/pic32_maximite.conf create mode 100644 tools/virtualmips/pic32_ubw32.conf create mode 100644 tools/virtualmips/pic32mx.h create mode 100644 tools/virtualmips/sbox.c create mode 100644 tools/virtualmips/sbox.h create mode 100644 tools/virtualmips/system.h create mode 100644 tools/virtualmips/types.h create mode 100644 tools/virtualmips/utils.c create mode 100644 tools/virtualmips/utils.h create mode 100644 tools/virtualmips/vm.c create mode 100644 tools/virtualmips/vm.h create mode 100644 tools/virtualmips/vp_clock.c create mode 100644 tools/virtualmips/vp_clock.h create mode 100644 tools/virtualmips/vp_lock.h create mode 100644 tools/virtualmips/vp_sdl.c create mode 100644 tools/virtualmips/vp_sdl.h create mode 100644 tools/virtualmips/vp_timer.c create mode 100644 tools/virtualmips/vp_timer.h create mode 100644 tools/virtualmips/x86-codegen.h create mode 100644 tools/virtualmips/x86_trans.c create mode 100644 tools/virtualmips/x86_trans.h create mode 100644 var/log/messages create mode 100644 var/log/wtmp diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..25556c1 --- /dev/null +++ b/Makefile @@ -0,0 +1,193 @@ +# Copyright (c) 1986 Regents of the University of California. +# All rights reserved. The Berkeley software License Agreement +# specifies the terms and conditions for redistribution. +# +# This makefile is designed to be run as: +# make +# +# The `make' will compile everything, including a kernel, utilities +# and a root filesystem image. + +# +# Supported boards +# +MAX32 = sys/pic32/max32/MAX32 +UBW32 = sys/pic32/ubw32/UBW32 +UBW32UART = sys/pic32/ubw32-uart/UBW32-UART +UBW32UARTSDRAM = sys/pic32/ubw32-uart-sdram/UBW32-UART-SDRAM +MAXIMITE = sys/pic32/maximite/MAXIMITE +MAXCOLOR = sys/pic32/maximite-color/MAXCOLOR +EXPLORER16 = sys/pic32/explorer16/EXPLORER16 +STARTERKIT = sys/pic32/starter-kit/STARTER-KIT +DUINOMITE = sys/pic32/duinomite/DUINOMITE +DUINOMITEUART = sys/pic32/duinomite-uart/DUINOMITE-UART +DUINOMITEE = sys/pic32/duinomite-e/DUINOMITE-E +DUINOMITEEUART = sys/pic32/duinomite-e-uart/DUINOMITE-E-UART +PINGUINO = sys/pic32/pinguino-micro/PINGUINO-MICRO +DIP = sys/pic32/dip/DIP +BAREMETAL = sys/pic32/baremetal/BAREMETAL +RETROONE = sys/pic32/retroone/RETROONE +FUBARINO = sys/pic32/fubarino/FUBARINO +FUBARINOUART = sys/pic32/fubarino-uart/FUBARINO-UART +MMBMX7 = sys/pic32/mmb-mx7/MMB-MX7 + +# Select target board +TARGET ?= $(MAX32) + +# Filesystem and swap sizes. +FS_KBYTES = 102400 +U_KBYTES = 102400 +SWAP_KBYTES = 2048 + +# Set this to the device name for your SD card. With this +# enabled you can use "make installfs" to copy the filesys.img +# to the SD card. + +#SDCARD = /dev/sdb + +# +# C library options: passed to libc makefile. +# See lib/libc/Makefile for explanation. +# +DEFS = + +FSUTIL = tools/fsutil/fsutil + +-include Makefile.user + +TARGETDIR = $(shell dirname $(TARGET)) +TARGETNAME = $(shell basename $(TARGET)) +TOPSRC = $(shell pwd) +CONFIG = $(TOPSRC)/tools/configsys/config +# +# Filesystem contents. +# +BIN_FILES := $(wildcard bin/*) +SBIN_FILES := $(wildcard sbin/*) +GAMES_FILES := $(shell find games -type f ! -path '*/.*') +LIBEXEC_FILES := $(wildcard libexec/*) +LIB_FILES := lib/crt0.o lib/retroImage $(wildcard lib/*.a) +ETC_FILES = etc/rc etc/rc.local etc/ttys etc/gettytab etc/group \ + etc/passwd etc/shadow etc/fstab etc/motd etc/shells \ + etc/termcap etc/MAKEDEV etc/phones etc/remote +INC_FILES = $(wildcard include/*.h) \ + $(wildcard include/sys/*.h) \ + $(wildcard include/machine/*.h) \ + $(wildcard include/smallc/*.h) \ + $(wildcard include/smallc/sys/*.h) \ + $(wildcard include/arpa/*.h) +SHARE_FILES = share/re.help share/example/Makefile \ + share/example/ashello.S share/example/chello.c \ + share/example/blkjack.bas share/example/hilow.bas \ + share/example/stars.bas share/example/prime.scm \ + share/example/fact.fth share/example/echo.S \ + $(wildcard share/smallc/*) +MANFILES = share/man/ share/man/cat1/ share/man/cat2/ share/man/cat3/ \ + share/man/cat4/ share/man/cat5/ share/man/cat6/ share/man/cat7/ \ + share/man/cat8/ $(wildcard share/man/cat?/*) +ALLFILES = $(SBIN_FILES) $(ETC_FILES) $(BIN_FILES) $(LIB_FILES) $(LIBEXEC_FILES) \ + $(INC_FILES) $(SHARE_FILES) $(GAMES_FILES) \ + var/log/messages var/log/wtmp .profile +ALLDIRS = games/ sbin/ bin/ dev/ etc/ tmp/ lib/ libexec/ share/ include/ \ + var/ u/ share/example/ share/misc/ share/smallc/ \ + var/run/ var/log/ var/lock/ games/ games/lib/ include/sys/ \ + include/machine/ include/arpa/ include/smallc/ \ + include/smallc/sys/ share/misc/ share/smallc/ include/sys/ \ + games/lib/ +BDEVS = dev/rd0!b0:0 dev/rd0a!b0:1 dev/rd0b!b0:2 dev/rd0c!b0:3 dev/rd0d!b0:4 +BDEVS += dev/rd1!b1:0 dev/rd1a!b1:1 dev/rd1b!b1:2 dev/rd1c!b1:3 dev/rd1d!b1:4 +BDEVS += dev/rd2!b2:0 dev/rd2a!b2:1 dev/rd2b!b2:2 dev/rd2c!b2:3 dev/rd2d!b2:4 +BDEVS += dev/rd3!b3:0 dev/rd3a!b3:1 dev/rd3b!b3:2 dev/rd3c!b3:3 dev/rd3d!b3:4 +BDEVS += dev/swap!b4:64 dev/swap0!b4:0 dev/swap1!b4:1 dev/swap2!b4:2 + +D_CONSOLE = dev/console!c0:0 +D_MEM = dev/mem!c1:0 dev/kmem!c1:1 dev/null!c1:2 dev/zero!c1:3 +D_TTY = dev/tty!c2:0 +D_FD = dev/stdin!c3:0 dev/stdout!c3:1 dev/stderr!c3:2 +D_TEMP = dev/temp0!c4:0 dev/temp1!c4:1 dev/temp2!c4:2 + +U_DIRS = $(addsuffix /,$(shell find u -type d ! -path '*/.svn*')) +U_FILES = $(shell find u -type f ! -path '*/.svn/*') +#U_ALL = $(patsubst u/%,%,$(U_DIRS) $(U_FILES)) + +CDEVS = $(D_CONSOLE) $(D_MEM) $(D_TTY) $(D_FD) $(D_TEMP) + +all: tools build kernel + $(MAKE) fs + +fs: sdcard.rd + +.PHONY: tools +tools: + $(MAKE) -C tools + +kernel: $(TARGETDIR)/Makefile + $(MAKE) -C $(TARGETDIR) + +$(TARGETDIR)/Makefile: $(CONFIG) $(TARGETDIR)/$(TARGETNAME) + cd $(TARGETDIR) && ../../../tools/configsys/config $(TARGETNAME) + +.PHONY: lib +lib: + $(MAKE) -C lib + +build: tools lib + $(MAKE) -C src install + +filesys.img: $(FSUTIL) $(ALLFILES) + rm -f $@ + $(FSUTIL) -n$(FS_KBYTES) $@ + $(FSUTIL) -a $@ $(ALLDIRS) + $(FSUTIL) -a $@ $(CDEVS) + $(FSUTIL) -a $@ $(BDEVS) + $(FSUTIL) -a $@ $(ALLFILES) + $(FSUTIL) -a $@ $(MANFILES) + +swap.img: + dd if=/dev/zero of=$@ bs=1k count=$(SWAP_KBYTES) + +user.img: $(FSUTIL) +ifneq ($(U_KBYTES), 0) + rm -f $@ + $(FSUTIL) -n$(U_KBYTES) $@ + (cd u; find . -type d -exec ../$(FSUTIL) -a ../$@ '{}/' \;) + (cd u; find . -type f -exec ../$(FSUTIL) -a ../$@ '{}' \+) +endif + +sdcard.rd: filesys.img swap.img user.img +ifneq ($(U_KBYTES), 0) + tools/mkrd/mkrd -out $@ -boot filesys.img -swap swap.img -fs user.img +else + tools/mkrd/mkrd -out $@ -boot filesys.img -swap swap.img +endif + +$(FSUTIL): + cd tools/fsutil; $(MAKE) + +$(CONFIG): + make -C tools/configsys + +clean: + rm -f *~ + for dir in tools lib src sys/pic32; do $(MAKE) -C $$dir -k clean; done + +cleanall: clean + $(MAKE) -C lib clean + rm -f sys/pic32/*/unix.hex bin/* sbin/* games/[a-k]* games/[m-z]* libexec/* share/man/cat*/* + rm -f games/lib/adventure.dat + rm -f games/lib/cfscores + rm -f share/re.help + rm -f share/misc/more.help + rm -f etc/termcap etc/remote etc/phones + rm -rf share/unixbench + rm -f games/lib/adventure.dat games/lib/cfscores share/re.help share/misc/more.help etc/termcap + rm -f tools/configsys/.depend + rm -f var/log/aculog + rm -rf var/lock + +installfs: filesys.img +ifdef SDCARD + sudo dd bs=32k if=sdcard.rd of=$(SDCARD) +else + @echo "Error: No SDCARD defined." +endif diff --git a/README b/README new file mode 100644 index 0000000..7c4de43 --- /dev/null +++ b/README @@ -0,0 +1,130 @@ +This is the RetroBSD source directory. + + +Source Roadmap +~~~~~~~~~~~~~~ + bin User commands. + etc Template files for /etc. + include System include files. + lib System libraries. + libexec System binaries. + sbin System administration commands. + share Shared resources. + sys Kernel sources. + tools Build tools and simulators. + + +Supported hardware +~~~~~~~~~~~~~~~~~~ + * chipKIT Max32 board. + * Sparkfun UBW32 board. + * Maximite and Colour Maximite computers. + * Microchip Explorer 16 board, with PIC32 CAN-USB plug-in module and SD & MMC pictail. + * Microchip PIC32 USB or Ethernet Starter Kit, with I/O Expansion board and SD & MMC pictail. + * Olimex Duinomite, Duinomite-Mini and Duinomite-Mega boards. + * Olimex Pinguino-Micro board with PIC32MX795F512H microcontroller. + * eflightworks DIP board. + + +Build +~~~~~ +By default, the system is configured for the Max32 board. +To select another target board, edit a top-level Makefile +and change a TARGET value under section "Select target board": + + TARGET = $(UBW32) # for the UBW32 board with USB console + TARGET = $(UBW32UART) # for the UBW32 board with UART console + TARGET = $(MAXIMITE) # for the Maximite board + TARGET = $(MAXCOLOR) # for the Colour Maximite board + TARGET = $(EXPLORER16) # for the Explorer 16 board + TARGET = $(STARTERKIT) # for the PIC32 USB or Ethernet Starter Kit + TARGET = $(MAX32) # default + TARGET = $(DUINOMITE) # for the Duinomite board + TARGET = $(PINGUINO) # for the Pinguino-Micro board + TARGET = $(DIP) # for the DIP board + +You can also change a desired filesystem size and swap area size, +as required. Default is: + + FS_KBYTES = 16384 + SWAP_KBYTES = 2048 + +To compile the kernel and build a filesystem image, run: + + make + +A resulting root filesystem image is in file `filesys.img`. +A kernel is in file `unix.hex` in your target board subdirectory. + + +Filesystem image +~~~~~~~~~~~~~~~~ +You need to put a filesystem image on a SD card. On Windows, use +Win32DiskImager utility (https://launchpad.net/win32-image-writer/+download). +On Linux, run: + + sudo dd if=filesys.img of=/dev/XYZ + +Here `XYZ` is a device name of SD card, as recognized by Linux (sdb in my case). + + +Install kernel +~~~~~~~~~~~~~~ +Kernel image should be written to PIC32 flash memory. The procedure depends +on a board used. + +Max32 board: + cd sys/pic32/ubw32 + AVRTOOLS=/Applications/Mpide.app/Contents/Resources/Java/hardware/tools + $AVRTOOLS/bin/avrdude -C$AVRTOOLS/etc/avrdude.conf -c stk500v2 -p pic32 \ + -P /dev/tty.usbserial-* -b 115200 -v -U flash:w:unix.hex:i + + Here you need to change AVRTOOLS path and tty name according to your system. + +UBW32 board: + Use a pic32prog utility (http://code.google.com/p/pic32prog/) + and a USB cable to install a kernel: + + pic32prog sys/pic32/ubw32/unix.hex + +Maximite: + Use the bootload program for Windows, available for download by link: + http://geoffg.net/Downloads/Maximite/Maximite_Update_V2.7B.zip + +Explorer 16 board: + There is an auxiliary PIC18 chip on the Explorer 16 board, which can be + used as a built-in programmer device. You will need a PICkit 2 adapter + to install a needed firmware, as described in article: + http://www.paintyourdragon.com/?p=51 + (section "Hack #2: Lose the PICkit 2, Save $35"). + This should be done only once. + + Then, you can use a pic32prog utility (http://code.google.com/p/pic32prog/) + and a USB cable to install a kernel: + + pic32prog sys/pic32/explorer16/unix.hex + +PIC32 Starter Kit: + Use PICkit 2 adapter and software to install a boot loader from + file `sys/pic32/starter-kit/boot.hex`. This should be done only once. + + Then, you can use a pic32prog utility (http://code.google.com/p/pic32prog/) + and a USB cable to install a kernel: + + pic32prog sys/pic32/starter-kit/unix.hex + + +Simulator +~~~~~~~~~ +You can use a MIPS32 simulator to develop a debug a RetroBSD software, +without a need for hardware board. By default, a simulator is configured +to imitate a Max32 board. To build it: + + cd tools/virtualmips + make + +Run it: + + ./pic32 + +Configuration of simulated board is stored in file `pic32_max32.conf`. diff --git a/cross.mk b/cross.mk new file mode 100644 index 0000000..8dec173 --- /dev/null +++ b/cross.mk @@ -0,0 +1,31 @@ +DESTDIR = /usr/local/retrobsd +MACHINE = mips + +CC = gcc + +AS = $(CC) -x assembler-with-cpp +LD = ld +AR = ar +RANLIB = ranlib +YACC = byacc +LEX = flex +SIZE = size +#OBJDUMP = objdump +OBJDUMP = sync -- +INSTALL = install -m 644 +INSTALLDIR = install -m 755 -d +TAGSFILE = tags +MANROFF = nroff -man -h +ELF2AOUT = cp + +CFLAGS = -O -DCROSS +LDFLAGS = +LIBS = + +# Add system include path +ifeq (,$(wildcard /usr/include/i386-linux-gnu)) + CFLAGS += -I/usr/include +else + CFLAGS += -I/usr/include/i386-linux-gnu +endif +CFLAGS += -I$(TOPSRC)/include diff --git a/etc/MAKEDEV b/etc/MAKEDEV new file mode 100755 index 0000000..e6aaae7 --- /dev/null +++ b/etc/MAKEDEV @@ -0,0 +1,175 @@ +#!/bin/sh - +# +# Copyright (c) 1980 Regents of the University of California. +# All rights reserved. The Berkeley software License Agreement +# specifies the terms and conditions for redistribution. +# +# @(#)MAKEDEV 4.27.6 (2.11BSD) 1999/2/19 +# +# Device "make" file. Valid arguments: +# std standard devices +# local configuration specific devices +# fd file descriptor driver +# Tapes: +# ht* unibus tu77 & te16 +# tm* unibus tm11 & te10 emulations (e.g. Emulex tc-11) +# ts* unibus ts11 +# tu* tmscp (tk50/tu81) +# Disks: +# br* unibus Eaton br1538 or br1711 +# hk* unibus rk06 and rk07 +# ra* unibus uda50 w/ ra?? +# rk* unibus rk05 +# rl* unibus rl01/rl02 +# rx* unibus rx02 +# si* unibus cdc 9766 w/ si 9500 +# xp* unibus rm02/03/05, rp04/05/06, diva, eagle, cdc9766, fuji 160. +# Terminal multiplexors: +# dl* dl-11 units other than the console +# dz* unibus dz11 and dz32 +# dh* unibus dh11 and emulations (e.g. Able dmax, Emulex cs-11) +# dmf* unibus dmf32 +# dhu* unibus dhu11 +# dmz* unibus dmz32 +# dhv* qbus dhv11 +# Pseudo terminals: +# pty* set of 16 master and slave pseudo terminals +# Printers: +# lp* unibus lp11 parallel interface +# va* unibus varian parallel interface +# vp* unibus versatec parallel interface +# Call units: +# Special purpose devices: +# dr* unibus dr11 +# ram* memory disk +# dn* dn11 dialer +# ingreslock Ingres lock driver. + +PATH=/etc:/sbin:/usr/sbin:/bin:/usr/bin +umask 77 +for i +do +case $i in + +std) + mknod console c 0 0 + mknod mem c 1 0 ; chmod 640 mem ; chgrp kmem mem + mknod kmem c 1 1 ; chmod 640 kmem ; chgrp kmem kmem + mknod null c 1 2 ; chmod 666 null + mknod zero c 1 3 ; chmod 444 zero + mknod tty c 2 0 ; chmod 666 tty + mknod klog c 3 0 ; chmod 600 klog + ;; + +fd) + umask 0 + rm -rf fd + rm -f stdin stdout stderr + mkdir fd + chmod 755 fd + mknod stdin c 4 0 + mknod stdout c 4 1 + mknod stderr c 4 2 + eval `echo "" | awk '{ for (i = 0; i < 32; i++) + printf("mknod fd/%d c 4 %d; ",i,i); }'` + ;; + +rd) + umask 2 + rm -f rd[0123] rd[0123][abcd] + mknod rd0 b 0 0 + mknod rd0a b 0 1 + mknod rd0b b 0 2 + mknod rd0c b 0 2 + mknod rd0d b 0 2 + mknod rd1 b 1 0 + mknod rd1a b 1 1 + mknod rd1b b 1 2 + mknod rd1c b 1 2 + mknod rd1d b 1 2 + mknod rd2 b 2 0 + mknod rd2a b 2 1 + mknod rd2b b 2 2 + mknod rd2c b 2 2 + mknod rd2d b 2 2 + mknod rd3 b 3 0 + mknod rd3a b 3 1 + mknod rd3b b 3 2 + mknod rd3c b 3 2 + mknod rd3d b 3 2 + chgrp operator rd[0123] + chgrp operator rd[0123][abcd] + chmod 640 rd[0123][abcd] + chmod 640 rd[0123] + ;; + +gpio) + umask 0 + rm -f port[abcdefg] conf[abcdef] + mknod porta c 5 0 + mknod portb c 5 1 + mknod portc c 5 2 + mknod portd c 5 3 + mknod porte c 5 4 + mknod portf c 5 5 + mknod portg c 5 6 + mknod confa c 5 64 + mknod confb c 5 65 + mknod confc c 5 66 + mknod confd c 5 67 + mknod confe c 5 68 + mknod conff c 5 69 + mknod confg c 5 70 + ;; + +adc) + umask 0 + rm -f adc[0123456789] adc1[012345] + mknod adc0 c 6 0 + mknod adc1 c 6 1 + mknod adc2 c 6 2 + mknod adc3 c 6 3 + mknod adc4 c 6 4 + mknod adc5 c 6 5 + mknod adc6 c 6 6 + mknod adc7 c 6 7 + mknod adc8 c 6 8 + mknod adc9 c 6 9 + mknod adc10 c 6 10 + mknod adc11 c 6 11 + mknod adc12 c 6 12 + mknod adc13 c 6 13 + mknod adc14 c 6 14 + mknod adc15 c 6 15 + ;; + +spi) + umask 0 + rm -f spi[1234] + mknod spi1 c 7 0 + mknod spi2 c 7 1 + mknod spi3 c 7 2 + mknod spi4 c 7 3 + ;; + +glcd) + umask 0 + rm -f glcd0 + mknod glcd0 c 8 0 + ;; + +oc) + umask 0 + rm -f oc[12345] + mknod oc1 c 9 0 + mknod oc2 c 9 1 + mknod oc3 c 9 2 + mknod oc4 c 9 3 + mknod oc5 c 9 4 + ;; + +local) + sh MAKEDEV.local + ;; +esac +done diff --git a/etc/MAKEDEV.local b/etc/MAKEDEV.local new file mode 100755 index 0000000..81f36ea --- /dev/null +++ b/etc/MAKEDEV.local @@ -0,0 +1,26 @@ +rm -f swap +ln ra0a swap +chgrp kmem swap +chmod 640 swap + +rm -f ttyi6 ttyd0; mknod ttyd0 c 3 22 +rm -f ttyi7 ttyd1; mknod ttyd1 c 3 23 +rm -f ttyi8 ttyd2; mknod ttyd2 c 3 24 +rm -f ttyi9 ttyd3; mknod ttyd3 c 3 25 +rm -f ttyia ttyd4; mknod ttyd4 c 3 26 +rm -f ttyic ttyd5; mknod ttyd5 c 3 156 + +rm -f ttyh1 dir-shasta; mknod dir-shasta c 3 1 +rm -f ttyh6 dir-rose; mknod dir-rose c 3 6 +rm -f ttyh7 dir-namsan; mknod dir-namsan c 3 7 +rm -f ttyid dir-ps; mknod dir-ps c 3 157 +rm -f ttyie cua0; mknod cua0 c 3 158 +rm -f ttyif dir-scgl; mknod dir-scgl c 3 159 +chown uucp dir-* +chmod 660 dir-* +# Cua* can't be owned by anyone real who wants to use the dialer if the mode +# 060 below and the dialer group is to work. Note that the uucp programs +# must be in the dialer group. +chown 32767 cua* +chgrp dialer cua* +chmod 060 cua* diff --git a/etc/Makefile b/etc/Makefile new file mode 100644 index 0000000..40dcc59 --- /dev/null +++ b/etc/Makefile @@ -0,0 +1,79 @@ +# +# DESTDIR is defined here to be something which does *NOT* exist - it must be +# specified on the command line when doing a "make DESTDIR=/mnt distribution". +# This is aimed at avoiding overwriting the system disk's /etc files. +# +# Example: +# mount /dev/ra1a /mnt +# make DESTDIR=/mnt distribution + +DESTDIR = /foobar +OWN = root +GRP = wheel + +SUBDIR = root +FILES = crontab fstab gettytab group motd passwd \ + rc rc.local shells syslog.conf ttys + +all install depend lint tags: + +clean: + rm -f *~ + -for i in ${SUBDIR}; do \ + (cd $$i; make DESTDIR=${DESTDIR} $@); done + +distribution: + -@mkdir -p ${DESTDIR}/dev + @chmod 755 ${DESTDIR}/dev + -@mkdir -p ${DESTDIR}/etc + @chmod 755 ${DESTDIR}/etc + @chown ${OWN}.${GRP} ${DESTDIR}/dev ${DESTDIR}/etc + -@mkdir -p ${DESTDIR}/usr/spool/mqueue + @chmod 755 ${DESTDIR}/usr/spool/mqueue + @chown ${OWN}.${GRP} ${DESTDIR}/usr/spool/mqueue + + install -c -o ${OWN} -g ${GRP} -m 644 ${FILES} ${DESTDIR}/etc + install -c -o root -g wheel -m 600 master.passwd ${DESTDIR}/etc + install -c -o ${OWN} -g ${GRP} -m 600 hosts.equiv ${DESTDIR}/etc + install -c -o ${OWN} -g ${GRP} -m 555 MAKEDEV.local MAKEDEV \ + ${DESTDIR}/dev + install -c -o ${OWN} -g operator -m 664 /dev/null \ + ${DESTDIR}/etc/dumpdates + install -c -o ${OWN} -g operator -m 664 /dev/null \ + ${DESTDIR}/etc/sendmail.cw + install -c -o ${OWN} -g operator -m 664 /dev/null \ + ${DESTDIR}/etc/sendmail.fc + -@mkdir -p ${DESTDIR}/usr/adm ${DESTDIR}/var/run ${DESTDIR}/var/db + @chmod 655 ${DESTDIR}/usr/adm ${DESTDIR}/var/run ${DESTDIR}/var/db + @chown ${OWN}.${GRP} ${DESTDIR}/usr/adm ${DESTDIR}/var/run \ + ${DESTDIR}/var/db + install -c -o ${OWN} -g ${GRP} -m 644 /dev/null \ + ${DESTDIR}/usr/adm/messages + install -c -o ${OWN} -g ${GRP} -m 644 /dev/null \ + ${DESTDIR}/usr/adm/daemonlog + install -c -o ${OWN} -g ${GRP} -m 644 /dev/null \ + ${DESTDIR}/usr/adm/debuglog + install -c -o ${OWN} -g operator -m 664 /dev/null \ + ${DESTDIR}/usr/adm/shutdownlog + install -c -o ${OWN} -g ${GRP} -m 644 /dev/null \ + ${DESTDIR}/usr/spool/mqueue/syslog + install -c -o ${OWN} -g ${GRP} -m 644 /dev/null \ + ${DESTDIR}/usr/adm/lpd-errs + install -c -o ${OWN} -g ${GRP} -m 644 /dev/null \ + ${DESTDIR}/var/run/utmp + install -c -o nobody -g ${GRP} -m 644 /dev/null \ + ${DESTDIR}/var/db/find.codes + install -c -o ${OWN} -g ${GRP} -m 644 /dev/null \ + ${DESTDIR}/usr/adm/lastlog + install -c -o ${OWN} -g ${GRP} -m 644 /dev/null \ + ${DESTDIR}/usr/adm/wtmp + install -c -o ${OWN} -g ${GRP} -m 644 /dev/null \ + ${DESTDIR}/usr/adm/acct + install -c -o ${OWN} -g ${GRP} -m 644 /dev/null \ + ${DESTDIR}/usr/adm/usracct + install -c -o ${OWN} -g ${GRP} -m 644 /dev/null \ + ${DESTDIR}/usr/adm/savacct + install -c -o uucp -g daemon -m 600 /dev/null \ + ${DESTDIR}/usr/adm/aculog + -for i in ${SUBDIR}; do \ + (cd $$i; make DESTDIR=${DESTDIR} distribution); done diff --git a/etc/fstab b/etc/fstab new file mode 100644 index 0000000..38305c1 --- /dev/null +++ b/etc/fstab @@ -0,0 +1,2 @@ +/dev/rd0a / ufs rw,async 1 1 +#/dev/rd0c /u ufs rw,async 1 2 diff --git a/etc/gettytab b/etc/gettytab new file mode 100644 index 0000000..5a873c3 --- /dev/null +++ b/etc/gettytab @@ -0,0 +1,164 @@ +# Copyright (c) 1980 Regents of the University of California. +# All rights reserved. The Berkeley software License Agreement +# specifies the terms and conditions for redistribution. +# +# @(#)gettytab 5.7.2 (2.11BSD GTE) 1997/3/28 +# +# +# Most of the table entries here are just copies of the +# old getty table, it is by no means certain, or even likely, +# then any of them are optimal for any purpose whatever. +# Nor is it likely that more than a couple are even correct +# + +# +# The default gettytab entry, used to set defaults for all other +# entries, and in cases where getty is called with no table name +# +default:\ + :ap:im=\r\n\r\n2.11 BSD UNIX (%h) (%t)\r\n\r\r\n\r:sp#1200: + +# +# Fixed speed entries +# +# The "std.NNN" names are known to the special case +# portselector code in getty, however they can +# be assigned to any table desired. +# The "NNN-baud" names are known to the special case +# autobaud code in getty, and likewise can +# be assigned to any table desired (hopefully the same speed). +# +a|std.50|50-baud:\ + :sp#50: +b|std.75|75-baud:\ + :ep:sp#75:ht:nl: +1|std.150|150-baud:\ + :ep:sp#150:ht:nl:lm=\E\72\6\6\17login\72 : +c|std.300|300-baud:\ + :sp#300: +d|std.600|600-baud:\ + :sp#600: +f|std.1200|1200-baud:\ + :sp#1200: +6|std.2400|2400-baud:\ + :sp#2400:ht: +7|std.4800|4800-baud:\ + :sp#4800:ht: +2|std.9600|9600-baud:\ + :sp#9600: +g|std.19200|19200-baud:\ + :sp#19200: +h|std.38400|38400-baud:\ + :sp#38400: +i|std.57600|57600-baud:\ + :sp#57600: +j|std.115200|115200-baud:\ + :sp#115200: +k|std.230400|230400-baud:\ + :sp#230400: +l|std.460800|460800-baud:\ + :sp#460800: +m|std.500000|500000-baud:\ + :sp#500000: +n|std.576000|576000-baud:\ + :sp#576000: +o|std.921600|921600-baud:\ + :sp#921600: +p|std.1000000|1000000-baud:\ + :sp#1000000: +q|std.1152000|1152000-baud:\ + :sp#1152000: +r|std.1500000|1500000-baud:\ + :sp#1500000: +s|std.2000000|2000000-baud:\ + :sp#2000000: +t|std.2500000|2500000-baud:\ + :sp#2500000: +u|std.3000000|3000000-baud:\ + :sp#3000000: +v|std.3500000|3500000-baud:\ + :sp#3500000: +w|std.4000000|4000000-baud:\ + :sp#4000000: +x|std.default|default-baud:\ + :sp#0: + + +# +# Hardware flow control lines +# +t9600-hf:hf:sp#9600 +t19200-hf:hf:sp#19200 +t38400-hf:hf:sp#38400 + +# +# Dial in rotary tables, speed selection via 'break' +# +0|d300|Dial-300:\ + :nx=d1200:sp#300: +d1200|Dial-1200:\ + :nx=d150:sp#1200: +d150|Dial-150:\ + :nx=d110:lm@:tc=150-baud: +d110|Dial-110:\ + :nx=d300:tc=300-baud: + +# +# Odd special case terminals +# +-|tty33|asr33|Pity the poor user of this beast:\ + :tc=110-baud: + +4|Console|Console Decwriter II:\ + :rw:tc=300-baud: + +e|Console-1200|Console Decwriter III:\ + :rw:tc=1200-baud: + +l|lsi chess terminal:\ + :sp#300: + +X|Xwindow|X window system:\ + :rw:sp#9600: + +# +# Fast dialup terminals, 2400/1200/300 rotary (can start either way) +# +D2400|Fast-Dial-2400:\ + :nx=D1200:tc=2400-baud: +3|D1200|Fast-Dial-1200:\ + :nx=D300:tc=1200-baud: +5|D300|Fast-Dial-300:\ + :nx=D2400:tc=300-baud: + +# +# Wierdo special case for fast crt's with hardcopy devices +# +8|T9600|CRT with hardcopy:\ + :nx=T300:tc=9600-baud: +9|T300|CRT with hardcopy (300):\ + :nx=T9600:tc=300-baud: + +# +# Plugboard, and misc other terminals +# +p|P9600|Plugboard-9600:\ + :nx=P300:tc=9600-baud: +q|P300|Plugboard-300:\ + :nx=P1200:tc=300-baud: +r|P1200|Plugboard-1200:\ + :nx=P9600:tc=1200-baud: + +# +# XXXX Port selector +# +s|DSW|Port Selector:\ + :ps:sp#2400: + +# +# Auto-baud speed detect entry for Micom 600. +# Special code in getty will switch this out +# to one of the NNN-baud entries. +# +A|Auto-baud:\ + :ab:sp#2400:f0#040: diff --git a/etc/group b/etc/group new file mode 100644 index 0000000..b9fffc8 --- /dev/null +++ b/etc/group @@ -0,0 +1,10 @@ +wheel:*:0:root +daemon:*:1:daemon +kmem:*:2: +sys:*:3: +tty:*:4: +operator:*:5: +staff:*:10: +bin:*:20: +guest:*:31: +ingres:*:74: diff --git a/etc/motd b/etc/motd new file mode 100644 index 0000000..fe24079 --- /dev/null +++ b/etc/motd @@ -0,0 +1 @@ +Welcome to RetroBSD! diff --git a/etc/passwd b/etc/passwd new file mode 100644 index 0000000..78feefb --- /dev/null +++ b/etc/passwd @@ -0,0 +1,8 @@ +root:5:0:1:The Man:/:/bin/sh +daemon:*:1:1:The devil himself:/:/bin/sh +sys:*:4:2:Operating System:/tmp:nologin +operator:*:2:5:System &:/usr/guest/operator:/bin/csh +bin:*:3:20:Binaries Commands and Source:/:/bin/csh +nobody:*:32767:31:Nobody:/nonexistent:/bin/sh +uucp:*:66:1:UNIX-to-UNIX Copy:/usr/spool/uucppublic:/usr/sbin/uucico +ingres:*:39:74:INGRES Owner:/usr/ingres:/bin/csh diff --git a/etc/rc b/etc/rc new file mode 100755 index 0000000..c72f050 --- /dev/null +++ b/etc/rc @@ -0,0 +1,73 @@ +#!/bin/sh +HOME=/; export HOME +PATH=/bin:/sbin; export PATH +exec >/dev/console 2>&1 + +/sbin/devupdate + +if test "$1" != "autoboot"; then + # + # Switch from single-user to multi-user mode. + # + echo + + # Halt the processor. + #reboot -l -h + exit 0 +fi + +# +# Entering multiuser mode: check filesystems +# +# This will *only* work if fsck can do your root file system +# without a temporary file, and if the root file system is +# checked alone in a pass by itself -- be careful! This can +# *seriously* mess you up. +# +fsck -p +case $? in +0) + # Filesystems are clean + ;; +2) + echo "--- Critical errors detected: run fsck to repair manually" + exit 1 ;; +4) + # Root filesystem modified: NO SYNC! + echo "--- Errors repaired, rebooting..." + reboot -n ;; +8) + echo "--- Filesystem check failed... help!" + exit 1 ;; +12) + echo "--- Interrupted by user" + exit 1 ;; +*) + echo "--- Unknown error in fsck" + exit 1 ;; +esac + +hostname "pic32" + +# +# First umount everything in case the system is going back into multiuser +# mode. If the system is being booted for the first time nothing is mounted +# except the root filesystem and umount ignores attempts to unmount /. +# +umount -a + +# +# Now mount everything mentioned in /etc/fstab *except* filesystems with the +# 'na' (noauto) option. +# +mount -a + +rm -f /etc/nologin + +echo -n "Starting daemons:" +update && echo -n "update" +cron && echo -n "cron" +echo + +#/etc/rc.local +exit 0 diff --git a/etc/rc.local b/etc/rc.local new file mode 100755 index 0000000..5e7fc44 --- /dev/null +++ b/etc/rc.local @@ -0,0 +1,2 @@ +#! /bin/sh - +# site-specific startup actions, daemons diff --git a/etc/root/Makefile b/etc/root/Makefile new file mode 100644 index 0000000..01769c3 --- /dev/null +++ b/etc/root/Makefile @@ -0,0 +1,18 @@ +# +# DESTDIR is defined here to be something which does *NOT* exist - it must be +# specified on the command line when doing a "make DESTDIR=/mnt distribution". +# This is aimed at avoiding overwriting the system disk's /etc files. + +DESTDIR = /foobar +OWN = root +GRP = wheel + +all install depend lint tags: + +distribution: + install -c -o ${OWN} -g ${GRP} -m 644 dot.cshrc ${DESTDIR}/.cshrc + install -c -o ${OWN} -g ${GRP} -m 644 dot.login ${DESTDIR}/.login + install -c -o ${OWN} -g ${GRP} -m 644 dot.profile ${DESTDIR}/.profile + +clean: + rm -f *~ diff --git a/etc/root/dot.cshrc b/etc/root/dot.cshrc new file mode 100644 index 0000000..48788b6 --- /dev/null +++ b/etc/root/dot.cshrc @@ -0,0 +1,14 @@ +set history=30 +set path=(/bin /sbin /etc /usr/sbin /usr/ucb /usr/bin /usr/new /usr/local) +if ($?prompt) then + set prompt="\!% " +endif + +set filec +set mail=( 0 /usr/spool/mail/$USER ) +set cdpath=( ~ /usr/spool/mqueue) +set prompt="\!% root--> " +alias mail /usr/ucb/Mail +alias pwd 'echo $cwd' +alias h history +alias q5 'tail -5 /usr/spool/mqueue/syslog' diff --git a/etc/root/dot.login b/etc/root/dot.login new file mode 100644 index 0000000..6efc4fc --- /dev/null +++ b/etc/root/dot.login @@ -0,0 +1,14 @@ +unset noglob +set path=(/bin /etc /sbin /usr/sbin /usr/ucb /usr/bin /usr/local /usr/new) +umask 26 +stty dec erase ^H kill ^U eof ^D +set prompt="[\!] root--> " + +if ( "$TERM" == dialup || "$TERM" == network) then + setenv TERM vt100 + echo -n "Terminal ($TERM)? " + set argv = "$<" + if ( "$argv" != '' ) setenv TERM "$argv" +endif + +biff y diff --git a/etc/root/dot.profile b/etc/root/dot.profile new file mode 100644 index 0000000..b08cb22 --- /dev/null +++ b/etc/root/dot.profile @@ -0,0 +1,8 @@ +echo 'erase, kill ^U, intr ^C' +stty dec +stty erase +PATH=/bin:/sbin:/usr/sbin:/etc:/usr/ucb:/usr/bin:/usr/new +export PATH +HOME=/ +export HOME +export TERM diff --git a/etc/shadow b/etc/shadow new file mode 100644 index 0000000..7276907 --- /dev/null +++ b/etc/shadow @@ -0,0 +1,8 @@ +root:ro46DZg1ViGBs:0:1:The Man:/:/bin/sh +daemon:*:1:1:The devil himself:/:/bin/sh +sys:*:4:2:Operating System:/tmp:nologin +operator:*:2:5:System &:/usr/guest/operator:/bin/csh +bin:*:3:20:Binaries Commands and Source:/:/bin/csh +nobody:*:32767:31:Nobody:/nonexistent:/bin/sh +uucp:*:66:1:UNIX-to-UNIX Copy:/usr/spool/uucppublic:/usr/sbin/uucico +ingres:*:39:74:INGRES Owner:/usr/ingres:/bin/csh diff --git a/etc/shells b/etc/shells new file mode 100644 index 0000000..236dd2b --- /dev/null +++ b/etc/shells @@ -0,0 +1,5 @@ +# List of acceptable shells for chsh/passwd -s +# Ftpd will not allow users to connect who do not have one of these shells +# +/bin/sh +/bin/csh diff --git a/etc/syslog.conf b/etc/syslog.conf new file mode 100644 index 0000000..90163fb --- /dev/null +++ b/etc/syslog.conf @@ -0,0 +1,14 @@ +local7.debug /dev/null +*.crit;*.err;kern.debug;auth.notice,local7.none /dev/console + +*.err;auth.notice;*.info;kern.debug;local3,local7,mail,daemon,lpr.none /usr/adm/messages + +cron.debug /usr/adm/cron +lpr.debug /usr/adm/lpd-errs +mail.debug /usr/spool/mqueue/syslog +mark.debug;daemon.debug /usr/adm/daemonlog +user.debug /usr/adm/debuglog + +*.alert;kern.err operator,root + +*.emerg * diff --git a/etc/ttys b/etc/ttys new file mode 100644 index 0000000..80edd05 --- /dev/null +++ b/etc/ttys @@ -0,0 +1,16 @@ +# +# name getty type status comments +# +console "/libexec/getty std.default" vt100 on secure #special + +# Enable some of these for additional logins. Do NOT enable the same one as the +# console port, or strange things will happen. You can turn off the console port +# if you would rather use the getty on the real tty - it's up to you. + +tty0 "/libexec/getty std.default" vt100 off secure +tty1 "/libexec/getty std.default" vt100 off secure +tty2 "/libexec/getty std.default" vt100 off secure +tty3 "/libexec/getty std.default" vt100 off secure +tty4 "/libexec/getty std.default" vt100 off secure +tty5 "/libexec/getty std.default" vt100 off secure +ttyUSB0 "/libexec/getty std.default" vt100 off secure diff --git a/include/Makefile b/include/Makefile new file mode 100644 index 0000000..acafbe1 --- /dev/null +++ b/include/Makefile @@ -0,0 +1,99 @@ +# +# Copyright (c) 1980 Regents of the University of California. +# All rights reserved. The Berkeley software License Agreement +# specifies the terms and conditions for redistribution. +# +# @(#)Makefile 5.16.1 (2.11BSD GTE) 1997/9/22 +# +# Doing a make install builds /usr/include +# +# Define SHARED to indicate whether you want +# symbolic links to the system source (``symlinks''), +# or a separate copy (``copies''). +# (latter useful in environments where it's +# not possible to keep /sys publicly readable) +# +# The ``rm -rf''s used below are safe because rm doesn't +# follow symbolic links. +# +DESTDIR= +SUBDIRS=arpa pascal protocols OLD +STD= a.out.h ar.h assert.h ctype.h curses.h disktab.h fcntl.h \ + fstab.h grp.h lastlog.h math.h memory.h mp.h mtab.h ndbm.h \ + netdb.h nlist.h pcc.h pwd.h ranlib.h resolv.h setjmp.h \ + sgtty.h short_names.h stab.h stdio.h string.h strings.h \ + struct.h syscall.h sysexits.h time.h ttyent.h tzfile.h utmp.h \ + varargs.h vfont.h vmf.h +LINKS= errno.h signal.h syslog.h +MACHINE=pdp +MACHDEP=${MACHINE} pdpif pdpuba pdpmba vaxuba +NETDIRS=net netimp netinet netns netpup +SYSDIRS=${NETDIRS} ${MACHDEP} +SHARED= symlinks +TAGSFILE=tags + +all: + +install: ${SHARED} + -for i in ${STD}; do \ + cmp -s $$i ${DESTDIR}/usr/include/$$i || \ + install -c -m 444 $$i ${DESTDIR}/usr/include/$$i; \ + done + -for i in ${SUBDIRS}; do \ + if [ ! -d ${DESTDIR}/usr/include/$$i ]; \ + then \ + mkdir ${DESTDIR}/usr/include/$$i; \ + fi; \ + (cd $$i; for j in *.[ih]; do \ + cmp -s $$j ${DESTDIR}/usr/include/$$i/$$j || \ + install -c -m 444 $$j ${DESTDIR}/usr/include/$$i/$$j; \ + done); \ + done + -cmp -s Makefile.install ${DESTDIR}/usr/include/Makefile || \ + install -c -m 444 Makefile.install ${DESTDIR}/usr/include/Makefile + -for i in ${LINKS}; do \ + rm -f ${DESTDIR}/usr/include/$$i; \ + ln -s sys/$$i ${DESTDIR}/usr/include/$$i; \ + done + rm -f ${DESTDIR}/usr/include/machine + ln -s ${MACHINE} ${DESTDIR}/usr/include/machine + rm -f ${DESTDIR}/usr/include/frame.h + ln -s machine/frame.h ${DESTDIR}/usr/include/frame.h + +symlinks: + -for i in ${SYSDIRS}; do \ + rm -rf ${DESTDIR}/usr/include/$$i; \ + if [ ! -s ${DESTDIR}/usr/include/$$i ]; \ + then \ + ln -s ../../sys/$$i ${DESTDIR}/usr/include/$$i; \ + else \ + echo ${DESTDIR}/usr/include/$$i not removed; \ + fi; \ + done + rm -rf ${DESTDIR}/usr/include/sys + -if [ ! -s ${DESTDIR}/usr/include/sys ]; \ + then \ + ln -s ../../sys/h ${DESTDIR}/usr/include/sys; \ + else \ + echo ${DESTDIR}/usr/include/sys not removed; \ + fi + +copies: + -for i in ${SYSDIRS}; do \ + rm -rf ${DESTDIR}/usr/include/$$i; \ + cd /sys; \ + tar cf - $$i/*.h | (cd ${DESTDIR}/usr/include; tar xpfB -); \ + done + rm -rf ${DESTDIR}/usr/include/sys; + mkdir ${DESTDIR}/usr/include/sys; + chmod 775 ${DESTDIR}/usr/include/sys; + -(cd /sys/h; tar cf - *.h | (cd ${DESTDIR}/usr/include/sys; tar xpfB -)) + +tags: + cwd=/usr/include; \ + for i in ${STD} ${LINKS}; do \ + ctags -a -f ${TAGSFILE} $$cwd/$$i; \ + done + +clean: + rm -f tags diff --git a/include/Makefile.install b/include/Makefile.install new file mode 100644 index 0000000..e75e157 --- /dev/null +++ b/include/Makefile.install @@ -0,0 +1,63 @@ +# +# Copyright (c) 1983,1986 Regents of the University of California. +# All rights reserved. The Berkeley software License Agreement +# specifies the terms and conditions for redistribution. +# +# @(#)Makefile.install 5.3 (Berkeley) 10/13/86 +# +# Makefile for /usr/include, used to convert system include subdirectories +# between symbolic links and copies of kernel headers. +# May also be used to update copies from kernel header files. +# +# The ``rm -rf''s used below are safe because rm doesn't +# follow symbolic links. +# +DESTDIR= +#ifdef vax +#MACHINE=vax +#MACHDEP=${MACHINE} vaxif vaxmba vaxuba +#endif +MACHINE=pdp +MACHDEP=${MACHINE} pdpmba pdpuba stand vaxif vaxuba +NETDIRS=net netimp netinet netns netpup +SYSDIRS=${NETDIRS} ${MACHDEP} +SYS=/sys + +all: + @echo "\"make symlinks\", \"make copies\", or \"make update\" only" + @false + +symlinks: + for i in ${SYSDIRS}; do \ + rm -rf $$i; \ + ln -s ../../${SYS}/$$i $$i; \ + done + rm -rf sys + ln -s ../../${SYS}/h sys + +copies: + -for i in ${SYSDIRS}; do \ + rm -rf $$i; \ + (cd ${SYS}; tar cf - $$i/*.h) | tar xpfB -; \ + done + rm -rf sys; + mkdir sys; + chmod 775 sys; + -(cd ${SYS}/h; tar cf - *.h) | (cd sys; tar xpfB -) + +update: + -for i in ${SYSDIRS}; do \ + if [ ! -d $$i ]; \ + then \ + mkdir $$i; \ + fi; \ + for j in `cd ${SYS}/$$i; echo *.[ih]`; do \ + cmp -s ${SYS}/$$i/$$j $$i/$$j || \ + install -c -m 444 ${SYS}/$$i/$$j $$i/$$j; \ + done; \ + done + for j in `cd ${SYS}/h; echo *.[ih]`; do \ + cmp -s ${SYS}/h/$$j sys/$$j || \ + { echo "install -c -m 444 ${SYS}/h/$$j sys/$$j"; \ + install -c -m 444 ${SYS}/h/$$j sys/$$j; } \ + done; diff --git a/include/a.out.h b/include/a.out.h new file mode 100644 index 0000000..af3533e --- /dev/null +++ b/include/a.out.h @@ -0,0 +1,90 @@ +/*- + * Copyright (c) 1991 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#ifndef _AOUT_H_ +#define _AOUT_H_ + +#include + +/* Valid magic number check. */ +#define N_BADMAG(x) (((x).a_magic) != RMAGIC && \ + ((x).a_magic) != OMAGIC && \ + ((x).a_magic) != NMAGIC) + +/* Text segment offset. */ +#define N_TXTOFF(x) sizeof(struct exec) + +/* Data segment offset. */ +#define N_DATOFF(x) (N_TXTOFF(x) + (x).a_text) + +/* Text relocation table offset. */ +#define N_TRELOFF(x) (N_DATOFF(x) + (x).a_data) + +/* Data relocation table offset. */ +#define N_DRELOFF(x) (N_TRELOFF(x) + (x).a_reltext) + +/* Symbol table offset. */ +#define N_SYMOFF(x) ((x).a_magic == RMAGIC ? \ + N_DRELOFF(x) + (x).a_reldata : \ + N_DATOFF(x) + (x).a_data) + +#define _AOUT_INCLUDE_ +#include + +/* Relocations */ +struct reloc { + unsigned flags; +#define RSMASK 0x70 /* bitmask for segments */ +#define RABS 0 +#define RTEXT 0x20 +#define RDATA 0x30 +#define RBSS 0x40 +#define RSTRNG 0x60 /* for assembler */ +#define REXT 0x70 /* externals and bitmask */ + +#define RGPREL 0x08 /* gp relative */ + +#define RFMASK 0x07 /* bitmask for format */ +#define RBYTE16 0x00 /* low part of byte address: bits 15:0 */ +#define RBYTE32 0x01 /* 32-bit byte address */ +#define RHIGH16 0x02 /* upper part of byte address: bits 31:16 */ +#define RHIGH16S 0x03 /* upper part of address with signed offset */ +#define RWORD16 0x04 /* word address: bits 17:2 */ +#define RWORD26 0x05 /* word address: bits 27:2 */ + + unsigned index; /* 24-bit index in symbol table, + * for REXT */ + unsigned offset; /* 16-bit offset, + * for RIGH16 and RIGH16S */ +}; + +#endif /* !_AOUT_H_ */ diff --git a/include/alloca.h b/include/alloca.h new file mode 100644 index 0000000..b73c543 --- /dev/null +++ b/include/alloca.h @@ -0,0 +1,15 @@ +/* alloca.h - Allocate memory on stack */ + +#ifndef ALLOCA_H +#define ALLOCA_H + +#undef alloca + +#ifdef __GNUC__ +#define alloca(size) __builtin_alloca(size) +#else +#include +void *alloca(size_t); +#endif + +#endif diff --git a/include/ar.h b/include/ar.h new file mode 100644 index 0000000..8f6ae7c --- /dev/null +++ b/include/ar.h @@ -0,0 +1,58 @@ +/*- + * Copyright (c) 1991 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 _AR_H_ +#define _AR_H_ + +#define ARMAG "!\n" /* ar "magic number" */ +#define SARMAG 8 /* strlen(ARMAG); */ + +#define AR_EFMT1 "#1/" /* extended format #1 */ + +struct ar_hdr { + char ar_name[16]; /* name */ + char ar_date[12]; /* modification time */ + char ar_uid[6]; /* user id */ + char ar_gid[6]; /* group id */ + char ar_mode[8]; /* octal file permissions */ + char ar_size[10]; /* size in bytes */ +#define ARFMAG "`\n" + char ar_fmag[2]; /* consistency check */ +}; + +#define ARHDRSZ 60 + +#endif /* !_AR_H_ */ diff --git a/include/arpa/inet.h b/include/arpa/inet.h new file mode 100644 index 0000000..e9cc391 --- /dev/null +++ b/include/arpa/inet.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 1983 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. + */ + +/* + * External definitions for + * functions in inet(3N) + */ +struct in_addr; + +unsigned long inet_addr (char *); +char *inet_ntoa (struct in_addr); +struct in_addr inet_makeaddr (long, long); +unsigned long inet_network (char *); +unsigned long inet_netof (struct in_addr); +unsigned long inet_lnaof (struct in_addr); + +/* + * Macros for number representation conversion. + */ +unsigned htonl (unsigned hostlong); +unsigned htons (unsigned hostshort); +unsigned ntohl (unsigned netlong); +unsigned ntohs (unsigned netshort); diff --git a/include/assert.h b/include/assert.h new file mode 100644 index 0000000..1529b79 --- /dev/null +++ b/include/assert.h @@ -0,0 +1,9 @@ +/* assert.h 4.2 85/01/21 */ + +# ifndef NDEBUG +# define _assert(ex) {if (!(ex)){fprintf(stderr,"Assertion failed: file \"%s\", line %d\n", __FILE__, __LINE__);exit(1);}} +# define assert(ex) _assert(ex) +# else +# define _assert(ex) +# define assert(ex) +# endif diff --git a/include/ctype.h b/include/ctype.h new file mode 100644 index 0000000..f3faa24 --- /dev/null +++ b/include/ctype.h @@ -0,0 +1,28 @@ +/* ctype.h 4.2 85/09/04 */ + +#define _U 01 +#define _L 02 +#define _N 04 +#define _S 010 +#define _P 020 +#define _C 040 +#define _X 0100 +#define _B 0200 + +extern char _ctype_[]; + +#define isalpha(c) ((_ctype_+1)[(int)(c)]&(_U|_L)) +#define isupper(c) ((_ctype_+1)[(int)(c)]&_U) +#define islower(c) ((_ctype_+1)[(int)(c)]&_L) +#define isdigit(c) ((_ctype_+1)[(int)(c)]&_N) +#define isxdigit(c) ((_ctype_+1)[(int)(c)]&(_N|_X)) +#define isspace(c) ((_ctype_+1)[(int)(c)]&_S) +#define ispunct(c) ((_ctype_+1)[(int)(c)]&_P) +#define isalnum(c) ((_ctype_+1)[(int)(c)]&(_U|_L|_N)) +#define isprint(c) ((_ctype_+1)[(int)(c)]&(_P|_U|_L|_N|_B)) +#define isgraph(c) ((_ctype_+1)[(int)(c)]&(_P|_U|_L|_N)) +#define iscntrl(c) ((_ctype_+1)[(int)(c)]&_C) +#define isascii(c) ((unsigned)(c)<=0177) +#define toupper(c) ((c)-'a'+'A') +#define tolower(c) ((c)-'A'+'a') +#define toascii(c) ((c)&0177) diff --git a/include/curses.h b/include/curses.h new file mode 100644 index 0000000..0370865 --- /dev/null +++ b/include/curses.h @@ -0,0 +1,191 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#ifndef CURSES_H + +#include +#include +#include + +#define bool int +#define reg register + +#define TRUE (1) +#define FALSE (0) +#define ERR (0) +#define OK (1) + +#define _ENDLINE 001 +#define _FULLWIN 002 +#define _SCROLLWIN 004 +#define _FLUSH 010 +#define _FULLLINE 020 +#define _IDLINE 040 +#define _STANDOUT 0200 +#define _NOCHANGE -1 + +#define _puts(s) tputs(s, 0, _putchar) + +typedef struct sgttyb SGTTY; + +/* + * Capabilities from termcap + */ + +extern bool AM, BS, CA, DA, DB, EO, HC, HZ, IN, MI, MS, NC, NS, OS, UL, + XB, XN, XT, XS, XX; +extern char *AL, *BC, *BT, *CD, *CE, *CL, *CM, *CR, *CS, *DC, *DL, + *DM, *DO, *ED, *EI, *K0, *K1, *K2, *K3, *K4, *K5, *K6, + *K7, *K8, *K9, *HO, *IC, *IM, *IP, *KD, *KE, *KH, *KL, + *KR, *KS, *KU, *LL, *MA, *ND, *NL, *RC, *SC, *SE, *SF, + *SO, *SR, *TA, *TE, *TI, *UC, *UE, *UP, *US, *VB, *VS, + *VE, *AL_PARM, *DL_PARM, *UP_PARM, *DOWN_PARM, + *LEFT_PARM, *RIGHT_PARM; +extern char PC; + +/* + * From the tty modes... + */ + +extern bool GT, NONL, UPPERCASE, normtty, _pfast; + +struct _win_st { + short _cury, _curx; + short _maxy, _maxx; + short _begy, _begx; + short _flags; + short _ch_off; + bool _clear; + bool _leave; + bool _scroll; + char **_y; + short *_firstch; + short *_lastch; + struct _win_st *_nextp, *_orig; +}; + +#define WINDOW struct _win_st + +extern bool My_term, _echoit, _rawmode, _endwin; + +extern char *Def_term, ttytype[]; + +extern int LINES, COLS, _tty_ch, _res_flg; + +extern SGTTY _tty; + +extern WINDOW *stdscr, *curscr; + +/* + * Define VOID to stop lint from generating "null effect" + * comments. + */ +#ifdef lint +int __void__; +#define VOID(x) (__void__ = (int) (x)) +#else +#define VOID(x) (x) +#endif + +/* + * psuedo functions for standard screen + */ +#define addch(ch) VOID(waddch(stdscr, ch)) +#define getch() VOID(wgetch(stdscr)) +#define addstr(str) VOID(waddstr(stdscr, str)) +#define getstr(str) VOID(wgetstr(stdscr, str)) +#define move(y, x) VOID(wmove(stdscr, y, x)) +#define clear() VOID(wclear(stdscr)) +#define erase() VOID(werase(stdscr)) +#define clrtobot() VOID(wclrtobot(stdscr)) +#define clrtoeol() VOID(wclrtoeol(stdscr)) +#define insertln() VOID(winsertln(stdscr)) +#define deleteln() VOID(wdeleteln(stdscr)) +#define refresh() VOID(wrefresh(stdscr)) +#define inch() VOID(winch(stdscr)) +#define insch(c) VOID(winsch(stdscr,c)) +#define delch() VOID(wdelch(stdscr)) +#define standout() VOID(wstandout(stdscr)) +#define standend() VOID(wstandend(stdscr)) + +/* + * mv functions + */ +#define mvwaddch(win,y,x,ch) VOID(wmove(win,y,x)==ERR?ERR:waddch(win,ch)) +#define mvwgetch(win,y,x) VOID(wmove(win,y,x)==ERR?ERR:wgetch(win)) +#define mvwaddstr(win,y,x,str) VOID(wmove(win,y,x)==ERR?ERR:waddstr(win,str)) +#define mvwgetstr(win,y,x,str) VOID(wmove(win,y,x)==ERR?ERR:wgetstr(win,str)) +#define mvwinch(win,y,x) VOID(wmove(win,y,x) == ERR ? ERR : winch(win)) +#define mvwdelch(win,y,x) VOID(wmove(win,y,x) == ERR ? ERR : wdelch(win)) +#define mvwinsch(win,y,x,c) VOID(wmove(win,y,x) == ERR ? ERR:winsch(win,c)) +#define mvaddch(y,x,ch) mvwaddch(stdscr,y,x,ch) +#define mvgetch(y,x) mvwgetch(stdscr,y,x) +#define mvaddstr(y,x,str) mvwaddstr(stdscr,y,x,str) +#define mvgetstr(y,x,str) mvwgetstr(stdscr,y,x,str) +#define mvinch(y,x) mvwinch(stdscr,y,x) +#define mvdelch(y,x) mvwdelch(stdscr,y,x) +#define mvinsch(y,x,c) mvwinsch(stdscr,y,x,c) + +/* + * psuedo functions + */ + +#define clearok(win,bf) (win->_clear = bf) +#define leaveok(win,bf) (win->_leave = bf) +#define scrollok(win,bf) (win->_scroll = bf) +#define flushok(win,bf) (bf ? (win->_flags |= _FLUSH):(win->_flags &= ~_FLUSH)) +#define getyx(win,y,x) y = win->_cury, x = win->_curx +#define winch(win) (win->_y[win->_cury][win->_curx] & 0177) + +#define raw() (_tty.sg_flags|=RAW, _pfast=_rawmode=TRUE, ioctl(_tty_ch,TIOCSETP,&_tty)) +#define noraw() (_tty.sg_flags&=~RAW,_rawmode=FALSE,_pfast=!(_tty.sg_flags&CRMOD),ioctl(_tty_ch,TIOCSETP,&_tty)) +#define cbreak() (_tty.sg_flags |= CBREAK, _rawmode = TRUE, ioctl(_tty_ch,TIOCSETP,&_tty)) +#define nocbreak() (_tty.sg_flags &= ~CBREAK,_rawmode=FALSE,ioctl(_tty_ch,TIOCSETP,&_tty)) +#define crmode() cbreak() /* backwards compatability */ +#define nocrmode() nocbreak() /* backwards compatability */ +#define echo() (_tty.sg_flags |= ECHO, _echoit = TRUE, ioctl(_tty_ch, TIOCSETP, &_tty)) +#define noecho() (_tty.sg_flags &= ~ECHO, _echoit = FALSE, ioctl(_tty_ch, TIOCSETP, &_tty)) +#define nl() (_tty.sg_flags |= CRMOD, _pfast = _rawmode,ioctl(_tty_ch, TIOCSETP, &_tty)) +#define nonl() (_tty.sg_flags &= ~CRMOD,_pfast = TRUE, ioctl(_tty_ch, TIOCSETP,&_tty)) +#define savetty() ((void) ioctl(_tty_ch, TIOCGETP, &_tty), _res_flg = _tty.sg_flags) +#define resetty() (_tty.sg_flags = _res_flg, (void) ioctl(_tty_ch, TIOCSETP, &_tty)) + +#define erasechar() (_tty.sg_erase) +#define killchar() (_tty.sg_kill) +#define baudrate() (_tty.sg_ospeed) + +WINDOW *initscr(), *newwin(), *subwin(); +char *longname(), *getcap(); + +int wmove (WINDOW *, int, int); +int wrefresh (WINDOW *); +int wclear (WINDOW *); +int waddch (WINDOW *, char); +int wgetch (WINDOW *); +char *wstandout (WINDOW *); +char *wstandend (WINDOW *); +int touchwin (WINDOW *); +int touchline (WINDOW *, int, int, int); +void box (WINDOW *, char, char); +void endwin (void); +int printw (char *, ...); +int wprintw (WINDOW *, char *, ...); +int scroll (WINDOW *); +void wclrtoeol (WINDOW *); +void werase (WINDOW *); +int setterm (char *); +int delwin (WINDOW *); +int waddstr (WINDOW *, char *); +int wgetstr (WINDOW *, char *); +int wdeleteln (WINDOW *); +void mvcur(int ly, int lx, int y, int x); + +/* + * Used to be in unctrl.h. + */ +#define unctrl(c) _unctrl[(c) & 0177] +extern char *_unctrl[]; + +#endif diff --git a/include/dbm.h b/include/dbm.h new file mode 100644 index 0000000..bb1685f --- /dev/null +++ b/include/dbm.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + * + * @(#)dbm.h 5.1 (Berkeley) 3/27/86 + */ + +#ifndef NULL +/* + * this is lunacy, we no longer use it (and never should have + * unconditionally defined it), but, this whole file is for + * backwards compatability - someone may rely on this. + */ +#define NULL ((char *) 0) +#endif + +#include + +datum fetch(); +datum firstkey(); +datum nextkey(); +#if 0 +datum makdatum(); +datum firsthash(); +long calchash(); +long hashinc(); +#endif diff --git a/include/errno.h b/include/errno.h new file mode 120000 index 0000000..7280063 --- /dev/null +++ b/include/errno.h @@ -0,0 +1 @@ +sys/errno.h \ No newline at end of file diff --git a/include/fcntl.h b/include/fcntl.h new file mode 100644 index 0000000..ea89bb8 --- /dev/null +++ b/include/fcntl.h @@ -0,0 +1,51 @@ +/*- + * Copyright (c) 1983, 1990, 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. + * + * @(#)fcntl.h 8.3.1 (2.11BSD GTE) 11/25/94 + * + * Copied from 4.4-Lite and modified for 2.11BSD. The modifications consisted + * of removing: function prototypes (I don't like them, the compiler does not + * support them, and it would mean dragging in cdefs.h to leave them in here), + * #ifndef _POSIX_SOURCE lines (silly) and record locking related definitions + * If anyone adds any of the above it will be easy enough to modify this file. + * In the meantime why bog down (or blow up) cpp any further? + */ +#include + +int open (const char *path, int oflag, ...); +int creat (const char *path, mode_t mode); +int fcntl (int fildes, int cmd, ...); diff --git a/include/float.h b/include/float.h new file mode 100644 index 0000000..bc05594 --- /dev/null +++ b/include/float.h @@ -0,0 +1,6 @@ +#ifndef _FLOAT_H_ +#define _FLOAT_H_ + +#include + +#endif /* _FLOAT_H_ */ diff --git a/include/fstab.h b/include/fstab.h new file mode 100644 index 0000000..878ec89 --- /dev/null +++ b/include/fstab.h @@ -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. + * + * @(#)fstab.h 8.1.1 (2.11BSD) 1996/1/15 + */ + +#ifndef _FSTAB_H_ +#define _FSTAB_H_ + +/* + * File system table, see fstab(5). + * + * Used by dump, mount, umount, swapon, fsck, df, ... + * + * For ufs fs_spec field is the block special name. Programs that want to + * use the character special name must create that name by prepending a 'r' + * after the right most slash. Quota files are always named "quotas", so + * if type is "rq", then use concatenation of fs_file and "quotas" to locate + * quota file. + */ +#define _PATH_FSTAB "/etc/fstab" +#define FSTAB "/etc/fstab" /* deprecated */ + +#define FSTAB_RW "rw" /* read/write device */ +#define FSTAB_RQ "rq" /* read/write with quotas */ +#define FSTAB_RO "ro" /* read-only device */ +#define FSTAB_SW "sw" /* swap device */ +#define FSTAB_XX "xx" /* ignore totally */ + +struct fstab { + char *fs_spec; /* block special device name */ + char *fs_file; /* file system path prefix */ + char *fs_vfstype; /* File system type, ufs, nfs */ + char *fs_mntops; /* Mount options ala -o */ + char *fs_type; /* FSTAB_* from fs_mntops */ + int fs_freq; /* dump frequency, in days */ + int fs_passno; /* pass number on parallel dump */ +}; + +struct fstab *getfsent(); +struct fstab *getfsspec(); +struct fstab *getfsfile(); +int setfsent(); +void endfsent(); + +#endif /* !_FSTAB_H_ */ diff --git a/include/grp.h b/include/grp.h new file mode 100644 index 0000000..b32ebd9 --- /dev/null +++ b/include/grp.h @@ -0,0 +1,15 @@ +/* grp.h 4.1 83/05/03 */ + +struct group { /* see getgrent(3) */ + char *gr_name; + char *gr_passwd; + int gr_gid; + char **gr_mem; +}; + +struct group *getgrent(void); +struct group *getgrnam(const char *name); +struct group *getgrgid(gid_t gid); +void setgrent(void); +void endgrent(void); +int setgroups(size_t size, const gid_t *list); diff --git a/include/kmem.h b/include/kmem.h new file mode 100644 index 0000000..bf3e5ea --- /dev/null +++ b/include/kmem.h @@ -0,0 +1,6 @@ +#ifndef _KMEM_H +#define _KMEM_H + +extern dev_t kmemdev(); + +#endif diff --git a/include/lastlog.h b/include/lastlog.h new file mode 100644 index 0000000..3686a91 --- /dev/null +++ b/include/lastlog.h @@ -0,0 +1,13 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + * + * @(#)lastlog.h 5.1 (Berkeley) 5/30/85 + */ + +struct lastlog { + time_t ll_time; + char ll_line[8]; + char ll_host[16]; /* same as in utmp */ +}; diff --git a/include/limits.h b/include/limits.h new file mode 100644 index 0000000..53174cf --- /dev/null +++ b/include/limits.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. + * + * @(#)limits.h 8.2.1 (2.11BSD) 1996/1/11 + */ + +#ifndef _LIMITS_H_ +#define _LIMITS_H_ + +/* + * We don't need this crud at the moment so save on abuse of the C + * preprocessor by not doing the defines. + +#define _POSIX_ARG_MAX 4096 +#define _POSIX_CHILD_MAX 6 +#define _POSIX_LINK_MAX 8 +#define _POSIX_MAX_CANON 255 +#define _POSIX_MAX_INPUT 255 +#define _POSIX_NAME_MAX 14 +#define _POSIX_NGROUPS_MAX 0 +#define _POSIX_OPEN_MAX 16 +#define _POSIX_PATH_MAX 255 +#define _POSIX_PIPE_BUF 512 +#define _POSIX_SSIZE_MAX 32767 +#define _POSIX_STREAM_MAX 8 +#define _POSIX_TZNAME_MAX 3 + +#define _POSIX2_BC_BASE_MAX 99 +#define _POSIX2_BC_DIM_MAX 2048 +#define _POSIX2_BC_SCALE_MAX 99 +#define _POSIX2_BC_STRING_MAX 1000 +#define _POSIX2_EQUIV_CLASS_MAX 2 +#define _POSIX2_EXPR_NEST_MAX 32 +#define _POSIX2_LINE_MAX 2048 +#define _POSIX2_RE_DUP_MAX 255 + +*/ + +#include +/* #include */ + +#endif /* !_LIMITS_H_ */ diff --git a/include/machine b/include/machine new file mode 120000 index 0000000..554870e --- /dev/null +++ b/include/machine @@ -0,0 +1 @@ +pic32 \ No newline at end of file diff --git a/include/math.h b/include/math.h new file mode 100644 index 0000000..666123d --- /dev/null +++ b/include/math.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +extern double fabs(), floor(), ceil(), fmod(), ldexp(); +extern double sqrt(), hypot(), atof(); +extern double sin(), cos(), tan(), asin(), acos(), atan(), atan2(); +extern double exp(), log(), log10(), pow(); +extern double sinh(), cosh(), tanh(); +extern double gamma(); +extern double j0(), j1(), jn(), y0(), y1(), yn(); + +#define HUGE 1.701411733192644270e38 +#define LOGHUGE 39 + +int isnanf(float x); +int isnan(double x); + +int isinff(float x); +int isinf(double x); + +float modff(float x, float *iptr); +double modf(double x, double *iptr); + +float frexpf(float x, int *exp); +double frexp(double x, int *exp); + +float ldexpf(float x, int exp); +double ldexp(double x, int exp); + +double fmod(double x, double y); diff --git a/include/mtab.h b/include/mtab.h new file mode 100644 index 0000000..bfe07ce --- /dev/null +++ b/include/mtab.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + * + * @(#)mtab.h 5.1 (Berkeley) 5/30/85 + */ + +/* + * Mounted device accounting file. + */ +struct mtab { + char m_path[32]; /* mounted on pathname */ + char m_dname[32]; /* block device pathname */ + char m_type[4]; /* read-only, quotas */ +}; diff --git a/include/ndbm.h b/include/ndbm.h new file mode 100644 index 0000000..dd624bb --- /dev/null +++ b/include/ndbm.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + * + * @(#)ndbm.h 5.1.1 (2.11BSD GTE) 12/31/93 + */ + +/* + * Hashed key data base library. + */ +#define PBLKSIZ 1024 +#ifdef pdp11 +#define DBLKSIZ 512 +#else +#define DBLKSIZ 4096 +#endif + +typedef struct { + int dbm_dirf; /* open directory file */ + int dbm_pagf; /* open page file */ + int dbm_flags; /* flags, see below */ + long dbm_maxbno; /* last ``bit'' in dir file */ + long dbm_bitno; /* current bit number */ + long dbm_hmask; /* hash mask */ + long dbm_blkptr; /* current block for dbm_nextkey */ + int dbm_keyptr; /* current key for dbm_nextkey */ + long dbm_blkno; /* current page to read/write */ + long dbm_pagbno; /* current page in pagbuf */ + char dbm_pagbuf[PBLKSIZ]; /* page file block buffer */ + long dbm_dirbno; /* current block in dirbuf */ + char dbm_dirbuf[DBLKSIZ]; /* directory file block buffer */ +} DBM; + +#define _DBM_RDONLY 0x1 /* data base open read-only */ +#define _DBM_IOERR 0x2 /* data base I/O error */ + +#define dbm_rdonly(db) ((db)->dbm_flags & _DBM_RDONLY) + +#define dbm_error(db) ((db)->dbm_flags & _DBM_IOERR) + /* use this one at your own risk! */ +#define dbm_clearerr(db) ((db)->dbm_flags &= ~_DBM_IOERR) + +/* for flock(2) and fstat(2) */ +#define dbm_dirfno(db) ((db)->dbm_dirf) +#define dbm_pagfno(db) ((db)->dbm_pagf) + +typedef struct { + char *dptr; + int dsize; +} datum; + +/* + * flags to dbm_store() + */ +#define DBM_INSERT 0 +#define DBM_REPLACE 1 + +DBM *dbm_open(); +void dbm_close(); +datum dbm_fetch(); +datum dbm_firstkey(); +datum dbm_nextkey(); +long dbm_forder(); +int dbm_delete(); +int dbm_store(); diff --git a/include/netinet/in.h b/include/netinet/in.h new file mode 100644 index 0000000..a108500 --- /dev/null +++ b/include/netinet/in.h @@ -0,0 +1,165 @@ +/* + * Copyright (c) 1982, 1986 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that this notice is preserved and that due credit is given + * to the University of California at Berkeley. The name of the University + * may not be used to endorse or promote products derived from this + * software without specific prior written permission. This software + * is provided ``as is'' without express or implied warranty. + */ + +/* + * Constants and structures defined by the internet system, + * Per RFC 790, September 1981. + */ + +/* + * Protocols + */ +#define IPPROTO_IP 0 /* dummy for IP */ +#define IPPROTO_ICMP 1 /* control message protocol */ +#define IPPROTO_GGP 3 /* gateway^2 (deprecated) */ +#define IPPROTO_TCP 6 /* tcp */ +#define IPPROTO_EGP 8 /* exterior gateway protocol */ +#define IPPROTO_PUP 12 /* pup */ +#define IPPROTO_UDP 17 /* user datagram protocol */ +#define IPPROTO_IDP 22 /* xns idp */ + +#define IPPROTO_RAW 255 /* raw IP packet */ +#define IPPROTO_MAX 256 + + +/* + * Ports < IPPORT_RESERVED are reserved for + * privileged processes (e.g. root). + * Ports > IPPORT_USERRESERVED are reserved + * for servers, not necessarily privileged. + */ +#define IPPORT_RESERVED 1024 +#define IPPORT_USERRESERVED 5000 + +/* + * Link numbers + */ +#define IMPLINK_IP 155 +#define IMPLINK_LOWEXPER 156 +#define IMPLINK_HIGHEXPER 158 + +/* + * Internet address (a structure for historical reasons) + */ +struct in_addr { + u_long s_addr; +}; + +/* + * Definitions of bits in internet address integers. + * On subnets, the decomposition of addresses to host and net parts + * is done according to subnet mask, not the masks here. + */ +#define IN_CLASSA(i) (((long)(i) & 0x80000000L) == 0) +#define IN_CLASSA_NET 0xff000000L +#define IN_CLASSA_NSHIFT 24 +#define IN_CLASSA_HOST 0x00ffffffL +#define IN_CLASSA_MAX 128 + +#define IN_CLASSB(i) (((long)(i) & 0xc0000000L) == 0x80000000L) +#define IN_CLASSB_NET 0xffff0000L +#define IN_CLASSB_NSHIFT 16 +#define IN_CLASSB_HOST 0x0000ffffL +#define IN_CLASSB_MAX 65536 + +#define IN_CLASSC(i) (((long)(i) & 0xe0000000L) == 0xc0000000L) +#define IN_CLASSC_NET 0xffffff00L +#define IN_CLASSC_NSHIFT 8 +#define IN_CLASSC_HOST 0x000000ffL + +#define IN_CLASSD(i) (((long)(i) & 0xf0000000L) == 0xe0000000L) +#define IN_MULTICAST(i) IN_CLASSD(i) + +#define IN_EXPERIMENTAL(i) (((long)(i) & 0xe0000000L) == 0xe0000000L) +#define IN_BADCLASS(i) (((long)(i) & 0xf0000000L) == 0xf0000000L) + +#define INADDR_ANY 0x00000000L +#define INADDR_BROADCAST 0xffffffffL /* must be masked */ +#ifndef KERNEL +#define INADDR_NONE 0xffffffffL /* -1 return */ +#endif + +#define IN_LOOPBACKNET 127 /* official! */ + +/* + * Socket address, internet style. + */ +struct sockaddr_in { + short sin_family; + u_short sin_port; + struct in_addr sin_addr; + char sin_zero[8]; +}; + +/* + * Options for use with [gs]etsockopt at the IP level. + */ +#define IP_OPTIONS 1 /* set/get IP per-packet options */ + +/* + * Definitions for inet sysctl operations. + * + * Third level is protocol number. + * Fourth level is desired variable within that protocol. + */ +#define IPPROTO_MAXID (IPPROTO_IDP + 1) /* don't list to IPPROTO_MAX */ + +#ifndef KERNEL +#define CTL_IPPROTO_NAMES { \ + { "ip", CTLTYPE_NODE }, \ + { "icmp", CTLTYPE_NODE }, \ + { "igmp", CTLTYPE_NODE }, \ + { 0, 0 }, \ + { 0, 0 }, \ + { 0, 0 }, \ + { "tcp", CTLTYPE_NODE }, \ + { 0, 0 }, \ + { 0, 0 }, \ + { 0, 0 }, \ + { 0, 0 }, \ + { 0, 0 }, \ + { 0, 0 }, \ + { 0, 0 }, \ + { 0, 0 }, \ + { 0, 0 }, \ + { 0, 0 }, \ + { "udp", CTLTYPE_NODE }, \ + { 0, 0 }, \ + { 0, 0 }, \ + { 0, 0 }, \ + { 0, 0 }, \ + { "idp", CTLTYPE_NODE }, \ +} +#endif /* KERNEL */ + +/* + * Names for IP sysctl objects + */ +#define IPCTL_FORWARDING 1 /* act as router */ +#define IPCTL_SENDREDIRECTS 2 /* may send redirects when forwarding */ +#define IPCTL_DEFTTL 3 /* default TTL */ +#ifdef notyet +#define IPCTL_DEFMTU 4 /* default MTU */ +#endif +#define IPCTL_FORWSRCRT 5 /* forward source-routed dgrams */ +#define IPCTL_MAXID 6 + +#ifndef KERNEL +#define IPCTL_NAMES { \ + { 0, 0 }, \ + { "forwarding", CTLTYPE_INT }, \ + { "redirect", CTLTYPE_INT }, \ + { "ttl", CTLTYPE_INT }, \ + { "mtu", CTLTYPE_INT }, \ + { "forwsrcrt", CTLTYPE_INT }, \ +} +#endif /* KERNEL */ diff --git a/include/nlist.h b/include/nlist.h new file mode 100644 index 0000000..8380246 --- /dev/null +++ b/include/nlist.h @@ -0,0 +1,75 @@ +/*- + * Copyright (c) 1991 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#ifndef _NLIST_H_ +#define _NLIST_H_ +#include + +/* + * Symbol table entry format. + */ +struct nlist { + char *n_name; /* In memory address of symbol name, + or string table offset (file) */ + u_short n_len; /* Length of name in bytes */ + u_short n_type; /* Type of symbol - see below */ + u_int n_value; /* Symbol value */ +}; + +/* + * Simple values for n_type. + */ +#define N_UNDF 0x00 /* undefined */ +#define N_ABS 0x01 /* absolute */ +#define N_TEXT 0x02 /* text segment */ +#define N_DATA 0x03 /* data segment */ +#define N_BSS 0x04 /* bss segment */ +#define N_STRNG 0x05 /* string segment (for assembler) */ +#define N_COMM 0x06 /* .comm segment (for assembler) */ +#define N_FN 0x1f /* file name */ + +#define N_TYPE 0x1f /* mask for all the type bits */ +#define N_EXT 0x20 /* external (global) bit, OR'ed in */ +#define N_WEAK 0x40 /* weak reference bit, OR'ed in */ +#define N_LOC 0x80 /* local, for assembler */ + +/* + * Get symbols from a file. + */ +int nlist (char *name, struct nlist *list); + +/* + * Get kernel symbols. + */ +int knlist (struct nlist *list); + +#endif /* !_NLIST_H_ */ diff --git a/include/paths.h b/include/paths.h new file mode 100644 index 0000000..e04b1de --- /dev/null +++ b/include/paths.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ +#define _PATH_BSHELL "/bin/sh" +#define _PATH_CSHELL "/bin/csh" +#define _PATH_CP "/bin/cp" +#define _PATH_ECHO "/bin/echo" +#define _PATH_MORE "/bin/more" +#define _PATH_RSH "/bin/rsh" +#define _PATH_VI "/bin/vi" +#define _PATH_CORE "/core" +#define _PATH_DEV "/dev/" +#define _PATH_CONSOLE "/dev/console" +#define _PATH_DEVNULL "/dev/null" +#define _PATH_TTY "/dev/tty" +#define _PATH_MEM "/dev/mem" +#define _PATH_SWAP "/dev/swap" +#define _PATH_LOCALTIME "/etc/localtime" +#define _PATH_MOTD "/etc/motd" +#define _PATH_NOLOGIN "/etc/nologin" +#define _PATH_USRLIB "/lib/" +#define _PATH_CTIMED "/libexec/ctimed" +#define _PATH_LOCALLIB "/local/lib/" +#define _PATH_SBIN "/sbin/" +#define _PATH_USRSBIN "/sbin/" +#define _PATH_SENDMAIL "/sbin/sendmail" +#define _PATH_SHARE "/share/" +#define _PATH_ZONEINFO "/share/zoneinfo" /* Time zone object file directory */ +#define _PATH_TMP "/tmp/" +#define _PATH_USRTMP "/tmp/" +#define _PATH_LASTLOG "/var/log/lastlog" +#define _PATH_MESSAGES "/var/log/messages" +#define _PATH_WTMP "/var/log/wtmp" +#define _PATH_MAIL "/var/mail/" +#define _PATH_VARRUN "/var/run/" +#define _PATH_DEVDB "/var/run/dev" +#define _PATH_UTMP "/var/run/utmp" +#define _PATH_ARTMP "/tmp/ar.XXXXXX" +#define _PATH_RANTMP "/tmp/ranlib.XXXXXX" + +#define _PATH_STDPATH "/bin" +#define _PATH_SYSPATH "/bin:/sbin:/local" +#define _PATH_MAN "/share/man:/local/man" +#define _PATH_LOCALMAN "/local/man" + +#define _PATH_HUSHLOGIN ".hushlogin" diff --git a/include/pcc.h b/include/pcc.h new file mode 100644 index 0000000..efc6da5 --- /dev/null +++ b/include/pcc.h @@ -0,0 +1,229 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + * + * @(#)pcc.h 5.1 (Berkeley) 5/30/85 + */ + +/* + * This file contains definitions for all the constants and structures + * needed to use the intermediate code files generated and read by + * the Portable C Compiler and related compilers. + * + * Rules for changing this code: + * 1) All op values must be integer constants -- this permits us to run + * a 'sed' script on this file to create %term declarations for yacc. + * 2) Because the PCC uses fancy ASG and UNARY macros, assignment + * operators must have values 1 greater than corresponding normal + * operators, and unary operators must have values 2 greater ditto. + * 3) Ops used only by f1 must have values >= 150 (PCCF_FORTOPS). + * 4) Other language-dependent ops must have values >= 200. + */ + +# ifndef PCC_TOKENS + +# define PCC_TOKENS 0 + +# define PCC_ERROR 1 /* an error node */ +# define PCC_FREE 2 /* an unused node */ + +/* + * Constants. + */ +# define PCC_STRING 3 /* a string constant */ +# define PCC_ICON 4 /* an integer constant */ +# define PCC_FCON 5 /* a floating point constant */ +# define PCC_DCON 6 /* a double precision f.p. constant */ + +/* + * Leaf types. + */ +# define PCC_NAME 7 /* an identifier */ +# define PCC_REG 8 /* a register */ +# define PCC_OREG 9 /* register and offset */ +# define PCC_CCODES 10 /* condition codes */ +# define PCC_FLD 11 /* a bit field */ + +/* + * Arithmetic operators. + */ +# define PCC_PLUS 12 /* + */ +# define PCC_PLUSEQ 13 /* += */ +# define PCC_UPLUS 14 /* unary + (for completeness) */ +# define PCC_MINUS 15 /* - */ +# define PCC_MINUSEQ 16 /* -= */ +# define PCC_UMINUS 17 /* unary - */ +# define PCC_MUL 18 /* * */ +# define PCC_MULEQ 19 /* *= */ +/* Reserve a slot for 'unary *', which is PCC jargon for PCC_DEREF (yech) */ +# define PCC_DIV 21 /* / */ +# define PCC_DIVEQ 22 /* /= */ +# define PCC_MOD 23 /* % */ +# define PCC_MODEQ 24 /* %= */ +# define PCC_INCR 25 /* ++ */ +# define PCC_DECR 26 /* -- */ +# define PCC_ASSIGN 27 /* = (these last 3 are stretching it) */ + +/* + * Bit operators. + */ +# define PCC_AND 28 /* & */ +# define PCC_ANDEQ 29 /* &= */ +/* Reserve a slot for 'unary &', jargon for PCC_ADDROF */ +# define PCC_OR 31 /* | */ +# define PCC_OREQ 32 /* |= */ +# define PCC_ER 33 /* ^ */ +# define PCC_EREQ 34 /* ^= */ +# define PCC_LS 35 /* << */ +# define PCC_LSEQ 36 /* <<= */ +# define PCC_RS 37 /* >> */ +# define PCC_RSEQ 38 /* >>= */ +# define PCC_COMPL 39 /* ~ */ + +/* + * Booleans. + */ +# define PCC_EQ 40 /* == */ +# define PCC_NE 41 /* != */ +# define PCC_LE 42 /* <= */ +# define PCC_LT 43 /* < */ +# define PCC_GE 44 /* >= */ +# define PCC_GT 45 /* > */ +# define PCC_ULE 46 /* unsigned <= */ +# define PCC_ULT 47 /* unsigned < */ +# define PCC_UGE 48 /* unsigned >= */ +# define PCC_UGT 49 /* unsigned > */ +# define PCC_QUEST 50 /* ? (for conditional expressions) */ +# define PCC_COLON 51 /* : (for conditional expressions) */ +# define PCC_ANDAND 52 /* && */ +# define PCC_OROR 53 /* || */ +# define PCC_NOT 54 /* ! */ + +/* + * Function calls. + */ +# define PCC_CALL 55 /* call by value */ +/* no ASG */ +# define PCC_UCALL 57 /* call with no arguments */ +# define PCC_FORTCALL 58 /* call by reference? */ +/* no ASG */ +# define PCC_UFORTCALL 60 /* ??? */ +# ifdef INLINE +# define PCC_INLINE 61 /* inline function */ +/* no ASG */ +# define PCC_UINLINE 63 /* inline with no arguments */ +# endif INLINE + +/* + * Referencing and dereferencing. + */ +# define PCC_DEREF 20 /* * */ +# define PCC_ADDROF 30 /* & */ + +/* + * Special structure operators. + */ +# define PCC_DOT 64 /* . */ +# define PCC_STREF 65 /* -> */ +# define PCC_STASG 66 /* structure assignment */ +# define PCC_STARG 67 /* an argument of type structure */ +# define PCC_STCALL 68 /* a function of type structure */ +/* no ASG */ +# define PCC_USTCALL 70 /* unary structure function */ + +/* + * Conversions. + */ +# define PCC_SCONV 71 /* scalar conversion */ +# define PCC_PCONV 72 /* pointer conversion */ +# define PCC_PMCONV 73 /* pointer multiply conversion */ +# define PCC_PVCONV 74 /* pointer divide conversion */ +# define PCC_CAST 75 /* redundant? */ + +/* + * Bracket types. + */ +# define PCC_LB 76 /* [ */ +# define PCC_RB 77 /* ] */ + +/* + * Comma nodes. + */ +# define PCC_COMOP 78 /* , (in expressions) */ +# define PCC_CM 79 /* , (in argument lists) */ + +/* + * Miscellaneous. + */ +# define PCC_FORCE 80 /* result of last expression goes in r0 */ +# define PCC_GOTO 81 /* unconditional goto */ +# define PCC_CBRANCH 82 /* goto label if !test */ +# define PCC_RETURN 83 /* return from function */ +# define PCC_INIT 84 /* initialized data */ +# define PCC_TYPE 85 /* a type */ +# define PCC_CLASS 86 /* a storage class */ + +# define PCC_MAXOP 86 /* highest numbered PCC op */ + +/* + * Special codes for interfacing to /lib/f1. + */ +# define PCCF_FORTOPS 150 +# define PCCF_FTEXT 150 /* pass literal assembler text */ +# define PCCF_FEXPR 151 /* a statement */ +# define PCCF_FSWITCH 152 /* not implemented */ +# define PCCF_FLBRAC 153 /* beginning of subroutine */ +# define PCCF_FRBRAC 154 /* end of subroutine */ +# define PCCF_FEOF 155 /* end of file */ +# define PCCF_FARIF 156 /* not implemented */ +# define PCCF_FLABEL 157 /* an f77 label */ + +# endif PCC_TOKENS + + +/* + * Types, as encoded in intermediate file cookies. + */ +# define PCCT_UNDEF 0 +# define PCCT_FARG 1 /* function argument */ +# define PCCT_CHAR 2 +# define PCCT_SHORT 3 +# define PCCT_INT 4 +# define PCCT_LONG 5 +# define PCCT_FLOAT 6 +# define PCCT_DOUBLE 7 +# define PCCT_STRTY 8 +# define PCCT_UNIONTY 9 +# define PCCT_ENUMTY 10 +# define PCCT_MOETY 11 /* member of enum */ +# define PCCT_UCHAR 12 +# define PCCT_USHORT 13 +# define PCCT_UNSIGNED 14 +# define PCCT_ULONG 15 + +/* + * Type modifiers. + */ +# define PCCTM_PTR 020 +# define PCCTM_FTN 040 +# define PCCTM_ARY 060 +# define PCCTM_BASETYPE 017 +# define PCCTM_TYPESHIFT 2 + + +/* + * Useful macros. 'PCCOM' macros apply to ops. + */ +# define PCCOM_ASG 1+ +# define PCCOM_UNARY 2+ +# define PCCOM_NOASG (-1)+ +# define PCCOM_NOUNARY (-2)+ + +# define PCCM_TRIPLE(op, var, type) \ + ((op) | ((var) << 8) | (long) (type) << 16) +# define PCCM_TEXT(s) \ + PCCM_TRIPLE(PCCF_FTEXT, (strlen(s) + 3) / 4, 0) +# define PCCM_ADDTYPE(t, m) \ + ((((t) &~ PCCTM_BASETYPE) << PCCTM_TYPESHIFT) | \ + (m) | ((t) & PCCTM_BASETYPE)) diff --git a/include/pic32 b/include/pic32 new file mode 120000 index 0000000..574b94c --- /dev/null +++ b/include/pic32 @@ -0,0 +1 @@ +../sys/pic32 \ No newline at end of file diff --git a/include/psout.h b/include/psout.h new file mode 100644 index 0000000..47a185e --- /dev/null +++ b/include/psout.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +/* + * psout: structure output by 'ps -U'. + * Mostly the pre-processed /dev directory. + */ + +#ifndef makedev +#include +#endif + +struct psout { + dev_t o_ttyd; /* u_ttyd */ + int o_flag; /* p_flag */ + short o_pid; /* p_pid */ + char o_tty[3]; /* 1st 2 chars of tty after 'tty' */ + char o_stat; /* p_stat */ + short o_uid; /* p_uid */ + char o_uname[UT_NAMESIZE]; /* login name of process owner */ + short o_ppid; /* p_ppid */ + char o_cpu; /* p_cpu */ + char o_pri; /* p_pri */ + char o_nice; /* p_nice */ + short o_addr0; /* p_addr[0] */ + short o_size; /* p_size */ + caddr_t o_wchan; /* p_wchan */ + time_t o_utime; /* u_utime */ + time_t o_stime; /* u_stime */ + time_t o_cutime; /* u_cutime */ + time_t o_cstime; /* u_cstime */ + short o_pgrp; /* p_pgrp */ + int o_sigs; /* sum of SIGINT & SIGQUIT, + if == 2 proc is ignoring both.*/ + char o_comm[MAXCOMLEN+1]; /* u_comm */ + char o_args[64]; /* best guess at args to process */ +}; diff --git a/include/pwd.h b/include/pwd.h new file mode 100644 index 0000000..3f6745b --- /dev/null +++ b/include/pwd.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 1988 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#define _PATH_PASSWD "/etc/passwd" +#define _PATH_SHADOW "/etc/shadow" +#define _PATH_MKPASSWD "/sbin/mkpasswd" +#define _PATH_PTMP "/etc/ptmp" + +#define _PW_KEYBYNAME '0' +#define _PW_KEYBYUID '1' + +struct passwd { + char *pw_name; /* user name */ + char *pw_passwd; /* encrypted password */ + int pw_uid; /* user uid */ + int pw_gid; /* user gid */ + char *pw_gecos; /* real name */ + char *pw_dir; /* home directory */ + char *pw_shell; /* default shell */ +}; + +struct passwd *getpwent(), *getpwuid(), *getpwnam(); +void endpwent(), setpwfile(); +int setpwent(); +int setpassent (int); diff --git a/include/ranlib.h b/include/ranlib.h new file mode 100644 index 0000000..6cd1da8 --- /dev/null +++ b/include/ranlib.h @@ -0,0 +1,46 @@ +/*- + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _RANLIB_H_ +#define _RANLIB_H_ + +#define RANLIBMAG "__.SYMDEF" /* archive file name */ +#define RANLIBSKEW 3 /* creation time offset */ + +struct ranlib { + int ran_len; /* 1 byte - name length in bytes */ + unsigned ran_off; /* 4 bytes - file offset */ + char *ran_name; /* in memory symbol name */ +}; + +#endif /* !_RANLIB_H_ */ diff --git a/include/regexp.h b/include/regexp.h new file mode 100644 index 0000000..73d6bf4 --- /dev/null +++ b/include/regexp.h @@ -0,0 +1,21 @@ +/* + * Definitions etc. for regexp(3) routines. + * + * Caveat: this is V8 regexp(3) [actually, a reimplementation thereof], + * not the System V one. + */ +#define NSUBEXP 10 +typedef struct regexp { + char *startp[NSUBEXP]; + char *endp[NSUBEXP]; + char regstart; /* Internal use only. */ + char reganch; /* Internal use only. */ + char *regmust; /* Internal use only. */ + int regmlen; /* Internal use only. */ + char program[1]; /* Unwarranted chumminess with compiler. */ +} regexp; + +extern regexp *regcomp(); +extern int regexec(); +extern void regsub(); +extern void regerror(); diff --git a/include/setjmp.h b/include/setjmp.h new file mode 100644 index 0000000..14f4327 --- /dev/null +++ b/include/setjmp.h @@ -0,0 +1,42 @@ +#ifndef _SETJMP_H +#define _SETJMP_H +/* + * Total 12 registers for MIPS architecture: + * 0 - $s0 + * 1 - $s1 + * 2 - $s2 + * 3 - $s3 + * 4 - $s4 + * 5 - $s5 + * 6 - $s6 + * 7 - $s7 + * 8 - $s8 + * 9 - $ra - return address + * 10 - $gp - global data pointer + * 11 - $sp - stack pointer + * 12 - signal mask saved + * 13 - signal mask + */ +typedef int jmp_buf [14]; +typedef jmp_buf sigjmp_buf; + +/* + * Save and restore only CPU state. + * Signal mask is not saved. + */ +int _setjmp (jmp_buf env); +void _longjmp (jmp_buf env, int val); + +/* + * Save and restore CPU state and signal mask. + */ +int setjmp (jmp_buf env); +void longjmp (jmp_buf env, int val); + +/* + * Save and restore CPU state and optionally a signal mask. + * Signal mask is saved only when savesigs is nonzero. + */ +int sigsetjmp (sigjmp_buf env, int savesigs); +void siglongjmp (sigjmp_buf env, int val); +#endif diff --git a/include/sgtty.h b/include/sgtty.h new file mode 100644 index 0000000..e1186ca --- /dev/null +++ b/include/sgtty.h @@ -0,0 +1,5 @@ +/* sgtty.h 4.2 85/01/03 */ + +#ifndef _IOCTL_ +#include +#endif diff --git a/include/signal.h b/include/signal.h new file mode 120000 index 0000000..df1896d --- /dev/null +++ b/include/signal.h @@ -0,0 +1 @@ +sys/signal.h \ No newline at end of file diff --git a/include/smallc/curses.h b/include/smallc/curses.h new file mode 100644 index 0000000..f9aa9a1 --- /dev/null +++ b/include/smallc/curses.h @@ -0,0 +1,114 @@ +/* + * SmallC: interface to curses library. + */ +#define WINDOW int + +extern WINDOW *stdscr, *curscr; + +extern int LINES, COLS; + +/* + * pseudo functions for standard screen + */ +#define addch(ch) waddch(stdscr, ch) +#define getch() wgetch(stdscr) +#define addstr(str) waddstr(stdscr, str) +#define getstr(str) wgetstr(stdscr, str) +#define move(y, x) wmove(stdscr, y, x) +#define clear() wclear(stdscr) +#define erase() werase(stdscr) +#define clrtobot() wclrtobot(stdscr) +#define clrtoeol() wclrtoeol(stdscr) +#define insertln() winsertln(stdscr) +#define deleteln() wdeleteln(stdscr) +#define refresh() wrefresh(stdscr) +#define inch() winch(stdscr) +#define insch(c) winsch(stdscr,c) +#define delch() wdelch(stdscr) +#define standout() wstandout(stdscr) +#define standend() wstandend(stdscr) + +/* + * mv functions + */ +#define mvwaddch(win,y,x,ch) wmove(win,y,x) == 0 ? 0 : waddch(win,ch) +#define mvwgetch(win,y,x) wmove(win,y,x) == 0 ? 0 : wgetch(win) +#define mvwaddstr(win,y,x,str) wmove(win,y,x) == 0 ? 0 : waddstr(win,str) +#define mvwgetstr(win,y,x,str) wmove(win,y,x) == 0 ? 0 : wgetstr(win,str) +#define mvwinch(win,y,x) wmove(win,y,x) == 0 ? 0 : winch(win) +#define mvwdelch(win,y,x) wmove(win,y,x) == 0 ? 0 : wdelch(win) +#define mvwinsch(win,y,x,c) wmove(win,y,x) == 0 ? 0 : winsch(win,c) +#define mvaddch(y,x,ch) mvwaddch(stdscr,y,x,ch) +#define mvgetch(y,x) mvwgetch(stdscr,y,x) +#define mvaddstr(y,x,str) mvwaddstr(stdscr,y,x,str) +#define mvgetstr(y,x,str) mvwgetstr(stdscr,y,x,str) +#define mvinch(y,x) mvwinch(stdscr,y,x) +#define mvdelch(y,x) mvwdelch(stdscr,y,x) +#define mvinsch(y,x,c) mvwinsch(stdscr,y,x,c) + +#ifdef TODO + +#define TRUE (1) +#define FALSE (0) +#define ERR (0) +#define OK (1) + +/* + * Capabilities from termcap + */ +extern int AM, BS, CA, DA, DB, EO, HC, HZ, IN, MI, MS, NC, NS, OS, UL, + XB, XN, XT, XS, XX; +extern char *AL, *BC, *BT, *CD, *CE, *CL, *CM, *CR, *CS, *DC, *DL, + *DM, *DO, *ED, *EI, *K0, *K1, *K2, *K3, *K4, *K5, *K6, + *K7, *K8, *K9, *HO, *IC, *IM, *IP, *KD, *KE, *KH, *KL, + *KR, *KS, *KU, *LL, *MA, *ND, *NL, *RC, *SC, *SE, *SF, + *SO, *SR, *TA, *TE, *TI, *UC, *UE, *UP, *US, *VB, *VS, + *VE, *AL_PARM, *DL_PARM, *UP_PARM, *DOWN_PARM, + *LEFT_PARM, *RIGHT_PARM; +extern char PC; + +/* + * From the tty modes... + */ +extern int GT, NONL, UPPERCASE, normtty, _pfast; + +extern int My_term, _echoit, _rawmode, _endwin; + +extern char *Def_term, ttytype[]; + +extern int _tty_ch, _res_flg; + +extern SGTTY _tty; + +/* + * pseudo functions + */ +#define clearok(win,bf) (win->_clear = bf) +#define leaveok(win,bf) (win->_leave = bf) +#define scrollok(win,bf) (win->_scroll = bf) +#define flushok(win,bf) (bf ? (win->_flags |= _FLUSH):(win->_flags &= ~_FLUSH)) +#define getyx(win,y,x) y = win->_cury, x = win->_curx +#define winch(win) (win->_y[win->_cury][win->_curx] & 0177) + +#define raw() (_tty.sg_flags|=RAW, _pfast=_rawmode=TRUE, ioctl(_tty_ch,TIOCSETP,&_tty)) +#define noraw() (_tty.sg_flags&=~RAW,_rawmode=FALSE,_pfast=!(_tty.sg_flags&CRMOD),ioctl(_tty_ch,TIOCSETP,&_tty)) +#define cbreak() (_tty.sg_flags |= CBREAK, _rawmode = TRUE, ioctl(_tty_ch,TIOCSETP,&_tty)) +#define nocbreak() (_tty.sg_flags &= ~CBREAK,_rawmode=FALSE,ioctl(_tty_ch,TIOCSETP,&_tty)) +#define echo() (_tty.sg_flags |= ECHO, _echoit = TRUE, ioctl(_tty_ch, TIOCSETP, &_tty)) +#define noecho() (_tty.sg_flags &= ~ECHO, _echoit = FALSE, ioctl(_tty_ch, TIOCSETP, &_tty)) +#define nl() (_tty.sg_flags |= CRMOD, _pfast = _rawmode,ioctl(_tty_ch, TIOCSETP, &_tty)) +#define nonl() (_tty.sg_flags &= ~CRMOD,_pfast = TRUE, ioctl(_tty_ch, TIOCSETP,&_tty)) +#define savetty() ((void) ioctl(_tty_ch, TIOCGETP, &_tty), _res_flg = _tty.sg_flags) +#define resetty() (_tty.sg_flags = _res_flg, (void) ioctl(_tty_ch, TIOCSETP, &_tty)) + +#define erasechar() (_tty.sg_erase) +#define killchar() (_tty.sg_kill) +#define baudrate() (_tty.sg_ospeed) + +/* + * Used to be in unctrl.h. + */ +#define unctrl(c) _unctrl[(c) & 0177] +extern char *_unctrl[]; + +#endif diff --git a/include/smallc/fcntl.h b/include/smallc/fcntl.h new file mode 100644 index 0000000..f1eb11c --- /dev/null +++ b/include/smallc/fcntl.h @@ -0,0 +1,38 @@ + +/* open-only flags */ +#define O_RDONLY 0x0000 /* open for reading only */ +#define O_WRONLY 0x0001 /* open for writing only */ +#define O_RDWR 0x0002 /* open for reading and writing */ +#define O_ACCMODE 0x0003 /* mask for above modes */ + +#define O_NONBLOCK 0x0004 /* no delay */ +#define O_APPEND 0x0008 /* set append mode */ +#define O_SHLOCK 0x0010 /* open with shared file lock */ +#define O_EXLOCK 0x0020 /* open with exclusive file lock */ +#define O_ASYNC 0x0040 /* signal pgrp when data ready */ +#define O_FSYNC 0x0080 /* synchronous writes */ +#define O_CREAT 0x0200 /* create if nonexistant */ +#define O_TRUNC 0x0400 /* truncate to zero length */ +#define O_EXCL 0x0800 /* error if already exists */ + +/* + * Constants used for fcntl(2) + */ + +/* command values */ +#define F_DUPFD 0 /* duplicate file descriptor */ +#define F_GETFD 1 /* get file descriptor flags */ +#define F_SETFD 2 /* set file descriptor flags */ +#define F_GETFL 3 /* get file status flags */ +#define F_SETFL 4 /* set file status flags */ +#define F_GETOWN 5 /* get SIGIO/SIGURG proc/pgrp */ +#define F_SETOWN 6 /* set SIGIO/SIGURG proc/pgrp */ + +/* file descriptor flags (F_GETFD, F_SETFD) */ +#define FD_CLOEXEC 1 /* close-on-exec flag */ + +/* lock operations for flock() */ +#define LOCK_SH 1 /* shared file lock */ +#define LOCK_EX 2 /* exclusive file lock */ +#define LOCK_NB 4 /* don't block when locking */ +#define LOCK_UN 8 /* unlock file */ diff --git a/include/smallc/signal.h b/include/smallc/signal.h new file mode 100644 index 0000000..ae8f7a2 --- /dev/null +++ b/include/smallc/signal.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#ifndef NSIG + +#define NSIG 32 + +#define SIGHUP 1 /* hangup */ +#define SIGINT 2 /* interrupt */ +#define SIGQUIT 3 /* quit */ +#define SIGILL 4 /* illegal instruction (not reset when caught) */ +#define SIGTRAP 5 /* trace trap (not reset when caught) */ +#define SIGIOT 6 /* IOT instruction */ +#define SIGABRT SIGIOT /* compatibility */ +#define SIGEMT 7 /* EMT instruction */ +#define SIGFPE 8 /* floating point exception */ +#define SIGKILL 9 /* kill (cannot be caught or ignored) */ +#define SIGBUS 10 /* bus error */ +#define SIGSEGV 11 /* segmentation violation */ +#define SIGSYS 12 /* bad argument to system call */ +#define SIGPIPE 13 /* write on a pipe with no one to read it */ +#define SIGALRM 14 /* alarm clock */ +#define SIGTERM 15 /* software termination signal from kill */ +#define SIGURG 16 /* urgent condition on IO channel */ +#define SIGSTOP 17 /* sendable stop signal not from tty */ +#define SIGTSTP 18 /* stop signal from tty */ +#define SIGCONT 19 /* continue a stopped process */ +#define SIGCHLD 20 /* to parent on child stop or exit */ +#define SIGCLD SIGCHLD /* compatibility */ +#define SIGTTIN 21 /* to readers pgrp upon background tty read */ +#define SIGTTOU 22 /* like TTIN for output if (tp->t_local<OSTOP) */ +#define SIGIO 23 /* input/output possible signal */ +#define SIGXCPU 24 /* exceeded CPU time limit */ +#define SIGXFSZ 25 /* exceeded file size limit */ +#define SIGVTALRM 26 /* virtual time alarm */ +#define SIGPROF 27 /* profiling time alarm */ +#define SIGWINCH 28 /* window size changes */ +#define SIGUSR1 30 /* user defined signal 1 */ +#define SIGUSR2 31 /* user defined signal 2 */ + +#define SIG_ERR -1 +#define SIG_DFL 0 +#define SIG_IGN 1 +#define BADSIG SIG_ERR + +#define SA_ONSTACK 0x0001 /* take signal on signal stack */ +#define SA_RESTART 0x0002 /* restart system on signal return */ +#define SA_DISABLE 0x0004 /* disable taking signals on alternate stack */ +#define SA_NOCLDSTOP 0x0008 /* do not generate SIGCHLD on child stop */ + +/* + * Flags for sigprocmask: + */ +#define SIG_BLOCK 1 /* block specified signal set */ +#define SIG_UNBLOCK 2 /* unblock specified signal set */ +#define SIG_SETMASK 3 /* set specified signal set */ + +#define MINSIGSTKSZ 128 /* minimum allowable stack */ +#define SIGSTKSZ (MINSIGSTKSZ + 384) /* recommended stack size */ + +#define SV_ONSTACK SA_ONSTACK /* take signal on signal stack */ +#define SV_INTERRUPT SA_RESTART /* same bit, opposite sense */ + +/* + * Macro for converting signal number to a mask suitable for + * sigblock(). + */ +#define sigmask(m) (1L << ((m)-1)) +#define sigaddset(set, signo) (*(set) |= 1L << ((signo) - 1), 0) +#define sigdelset(set, signo) (*(set) &= ~(1L << ((signo) - 1)), 0) +#define sigemptyset(set) (*(set) = (sigset_t)0, (int)0) +#define sigfillset(set) (*(set) = ~(sigset_t)0, (int)0) +#define sigismember(set, signo) ((*(set) & (1L << ((signo) - 1))) != 0) + +#endif /* NSIG */ diff --git a/include/smallc/stdio.h b/include/smallc/stdio.h new file mode 100644 index 0000000..c0278d0 --- /dev/null +++ b/include/smallc/stdio.h @@ -0,0 +1,24 @@ +/* + * SmallC: interface to stdio library. + */ +#define BUFSIZ 1024 + +#ifndef NULL +#define NULL 0 +#endif + +#define FILE int +#define EOF (-1) + +extern int _iob[]; + +#define stdin (&_iob[0]) +#define stdout (&_iob[5]) +#define stderr (&_iob[10]) + +#define SEEK_SET 0 /* set file offset to offset */ +#define SEEK_CUR 1 /* set file offset to current plus offset */ +#define SEEK_END 2 /* set file offset to EOF plus offset */ + +#define getc fgetc +#define putc fputc diff --git a/include/smallc/sys/gpio.h b/include/smallc/sys/gpio.h new file mode 100644 index 0000000..ff1a68e --- /dev/null +++ b/include/smallc/sys/gpio.h @@ -0,0 +1,22 @@ +/* + * Ioctl definitions for GPIO driver. + */ +#define GPIO_PORT(n) (n) /* port number */ +#define GPIO_PORTA 0 +#define GPIO_PORTB 1 +#define GPIO_PORTC 2 +#define GPIO_PORTD 3 +#define GPIO_PORTE 4 +#define GPIO_PORTF 5 +#define GPIO_PORTG 6 + +#define GPIO_CONFIN 0x20016700 /* configure as input */ +#define GPIO_CONFOUT 0x20026700 /* configure as output */ +#define GPIO_CONFOD 0x20046700 /* configure as open drain */ +#define GPIO_DECONF 0x20086700 /* deconfigure */ +#define GPIO_STORE 0x20106700 /* store all outputs */ +#define GPIO_SET 0x20206700 /* set to 1 by mask */ +#define GPIO_CLEAR 0x20406700 /* set to 0 by mask */ +#define GPIO_INVERT 0x20806700 /* invert by mask */ +#define GPIO_POLL 0x21006700 /* poll */ +#define GPIO_LOL 0x82006700 /* display lol picture */ diff --git a/include/smallc/sys/spi.h b/include/smallc/sys/spi.h new file mode 100644 index 0000000..6d5b154 --- /dev/null +++ b/include/smallc/sys/spi.h @@ -0,0 +1,9 @@ +/* + * Ioctl definitions for SPI driver. + */ +#define SPICTL_SETMODE 0x20007000 /* set SPI mode */ +#define SPICTL_SETRATE 0x20007001 /* set clock rate, kHz */ +#define SPICTL_SETSELPIN 0x20007002 /* set select pin */ +#define SPICTL_IO8(n) (0xc0007003 | (n)<<16) /* transfer n*8 bits */ +#define SPICTL_IO16(n) (0xc0007004 | (n)<<16) /* transfer n*16 bits */ +#define SPICTL_IO32(n) (0xc0007005 | (n)<<16) /* transfer n*32 bits */ diff --git a/include/smallc/wiznet.h b/include/smallc/wiznet.h new file mode 100644 index 0000000..23f2ec7 --- /dev/null +++ b/include/smallc/wiznet.h @@ -0,0 +1,12 @@ +/* + * SmallC: interface to wiznet library. + */ +#define MAX_SOCK_NUM 4 /* Max number of sockets per chip */ +#define CLIENT_SIZE 3 /* Size of client structure in words */ +#define UDP_SIZE 2 /* Size of UDP structure in words */ + +extern unsigned _socket_port[]; + +extern unsigned _client_srcport; + +extern unsigned _server_port; diff --git a/include/stab.h b/include/stab.h new file mode 100644 index 0000000..d7547d4 --- /dev/null +++ b/include/stab.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + * + * @(#)stab.h 5.1 (Berkeley) 5/30/85 + */ + +/* IF YOU ADD DEFINITIONS, ADD THEM TO nm.c as well */ +/* + * This file gives definitions supplementing + * for permanent symbol table entries. + * These must have one of the N_STAB bits on, + * and are subject to relocation according to the masks in . + */ +/* + * for symbolic debugger, sdb(1): + */ +#define N_GSYM 0x20 /* global symbol: name,,0,type,0 */ +#define N_FNAME 0x22 /* procedure name (f77 kludge): name,,0 */ +#define N_FUN 0x24 /* procedure: name,,0,linenumber,address */ +#define N_STSYM 0x26 /* static symbol: name,,0,type,address */ +#define N_LCSYM 0x28 /* .lcomm symbol: name,,0,type,address */ +#define N_RSYM 0x40 /* register sym: name,,0,type,register */ +#define N_SLINE 0x44 /* src line: 0,,0,linenumber,address */ +#define N_SSYM 0x60 /* structure elt: name,,0,type,struct_offset */ +#define N_SO 0x64 /* source file name: name,,0,0,address */ +#define N_LSYM 0x80 /* local sym: name,,0,type,offset */ +#define N_SOL 0x84 /* #included file name: name,,0,0,address */ +#define N_PSYM 0xa0 /* parameter: name,,0,type,offset */ +#define N_ENTRY 0xa4 /* alternate entry: name,linenumber,address */ +#define N_LBRAC 0xc0 /* left bracket: 0,,0,nesting level,address */ +#define N_RBRAC 0xe0 /* right bracket: 0,,0,nesting level,address */ +#define N_BCOMM 0xe2 /* begin common: name,, */ +#define N_ECOMM 0xe4 /* end common: name,, */ +#define N_ECOML 0xe8 /* end common (local name): ,,address */ +#define N_LENG 0xfe /* second stab entry with length information */ + +/* + * for the berkeley pascal compiler, pc(1): + */ +#define N_PC 0x30 /* global pascal symbol: name,,0,subtype,line */ diff --git a/include/stdarg.h b/include/stdarg.h new file mode 100644 index 0000000..27ffdda --- /dev/null +++ b/include/stdarg.h @@ -0,0 +1,35 @@ +/* + * ISO C Standard: 7.15 Variable arguments + */ +#ifndef _STDARG_H +#define _STDARG_H + +/* Define __gnuc_va_list. */ + + +#ifdef __GNUC__ +# ifndef __GNUC_VA_LIST +# define __GNUC_VA_LIST + typedef __builtin_va_list __gnuc_va_list; +# endif +# define va_start(ap, last) __builtin_va_start((ap), last) +#endif +#ifdef __PCC__ +# define va_start(ap, last) __builtin_stdarg_start((ap), last) +#endif +#define va_arg(ap, type) __builtin_va_arg((ap), type) +#define va_end(ap) __builtin_va_end((ap)) +#define va_copy(dest, src) __builtin_va_copy((dest), (src)) + + +#ifndef _VA_LIST_T +#define _VA_LIST_T +#ifdef __GNUC__ + typedef __builtin_va_list va_list; +#endif +#ifdef __SMALLER_C__ + typedef int *va_list; +#endif +#endif + +#endif /* not _STDARG_H */ diff --git a/include/stddef.h b/include/stddef.h new file mode 100644 index 0000000..5b6206f --- /dev/null +++ b/include/stddef.h @@ -0,0 +1,8 @@ + +/* Offset of member MEMBER in a struct of type TYPE. */ + +#if defined(__GNUC__) && __GNUC__ > 3 +#define offsetof(TYPE, MEMBER) __builtin_offsetof (TYPE, MEMBER) +#else +#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE*)0)->MEMBER) +#endif diff --git a/include/stdint.h b/include/stdint.h new file mode 100644 index 0000000..3d530a3 --- /dev/null +++ b/include/stdint.h @@ -0,0 +1,15 @@ + +#ifndef _STDINT_H +#define _STDINT_H + +typedef signed char int8_t; +typedef short int int16_t; +typedef int int32_t; + +typedef unsigned char uint8_t; +typedef unsigned short int uint16_t; +typedef unsigned int uint32_t; + + +#endif + diff --git a/include/stdio.h b/include/stdio.h new file mode 100644 index 0000000..97e47a5 --- /dev/null +++ b/include/stdio.h @@ -0,0 +1,134 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#ifndef FILE + +#include + +#define BUFSIZ 1024 +extern struct _iobuf { + int _cnt; + char *_ptr; /* should be unsigned char */ + char *_base; /* ditto */ + int _bufsiz; + short _flag; + short _file; +} _iob[]; + +#define _IOREAD 01 +#define _IOWRT 02 +#define _IONBF 04 +#define _IOMYBUF 010 +#define _IOEOF 020 +#define _IOERR 040 +#define _IOSTRG 0100 +#define _IOLBF 0200 +#define _IORW 0400 + +/* + * The following definition is for ANSI C, which took them + * from System V, which brilliantly took internal interface macros and + * made them official arguments to setvbuf(), without renaming them. + * Hence, these ugly _IOxxx names are *supposed* to appear in user code. +*/ +#define _IOFBF 0 /* setvbuf should set fully buffered */ + /* _IONBF and _IOLBF are used from the flags above */ + +#ifndef NULL +#define NULL 0 +#endif + +#define FILE struct _iobuf +#define EOF (-1) + +#define stdin (&_iob[0]) +#define stdout (&_iob[1]) +#define stderr (&_iob[2]) + +#define SEEK_SET 0 /* set file offset to offset */ +#define SEEK_CUR 1 /* set file offset to current plus offset */ +#define SEEK_END 2 /* set file offset to EOF plus offset */ + +#ifndef lint +#define getc(p) (--(p)->_cnt>=0? (int)(*(unsigned char *)(p)->_ptr++):_filbuf(p)) +#define putc(x, p) (--(p)->_cnt >= 0 ?\ + (int)(*(unsigned char *)(p)->_ptr++ = (x)) :\ + (((p)->_flag & _IOLBF) && -(p)->_cnt < (p)->_bufsiz ?\ + ((*(p)->_ptr = (x)) != '\n' ?\ + (int)(*(unsigned char *)(p)->_ptr++) :\ + _flsbuf(*(unsigned char *)(p)->_ptr, p)) :\ + _flsbuf((unsigned char)(x), p))) +#endif /* not lint */ + +#define getchar() getc(stdin) +#define putchar(x) putc(x,stdout) +#define feof(p) (((p)->_flag&_IOEOF)!=0) +#define ferror(p) (((p)->_flag&_IOERR)!=0) +#define fileno(p) ((p)->_file) +#define clearerr(p) ((p)->_flag &= ~(_IOERR|_IOEOF)) + +FILE *fopen (const char *, const char *); +FILE *fdopen (int, const char *); +FILE *freopen (const char *, const char *, FILE *); +FILE *popen (const char *, const char *); +FILE *tmpfile (void); +int fclose (FILE *); +long ftell (FILE *); +int fflush (FILE *); +int fgetc (FILE *); +int ungetc (int, FILE *); +int fputc (int, FILE *); +int fputs (const char *, FILE *); +int puts (const char *); +char *fgets (char *, int, FILE *); +char *gets (char *); +FILE *_findiop (void); +int _filbuf (FILE *); +int _flsbuf (unsigned char, FILE *); +void setbuf (FILE *, char *); +void setbuffer (FILE *, char *, size_t); +void setlinebuf (FILE *); +int setvbuf (FILE *, char *, int, size_t); +int fseek (FILE *, long, int); +void rewind (FILE *); +int remove (const char *); +int getw(FILE *stream); +int putw(int w, FILE *stream); + +size_t fread (void *, size_t, size_t, FILE *); +size_t fwrite (const void *, size_t, size_t, FILE *); + +int fprintf (FILE *, const char *, ...); +int printf (const char *, ...); +int sprintf (char *, const char *, ...); +int snprintf (char *, size_t, const char *, ...); + +int fscanf (FILE *, const char *, ...); +int scanf (const char *, ...); +int sscanf (const char *, const char *, ...); + +#ifndef _VA_LIST_ +#define va_list __builtin_va_list /* For GCC */ +#endif + +int vfprintf (FILE *, const char *, va_list); +int vprintf (const char *, va_list); +int vsprintf (char *, const char *, va_list); +int vsnprintf (char *, size_t, const char *, va_list); + +int vfscanf (FILE *, const char *, va_list); +int vscanf (const char *, va_list); +int vsscanf (const char *, const char *, va_list); + +int _doprnt (const char *, va_list, FILE *); +int _doscan (FILE *, const char *, va_list); + +#ifndef _VA_LIST_ +#undef va_list +#endif + +void perror (const char *); + +#endif /* _FILE */ diff --git a/include/stdlib.h b/include/stdlib.h new file mode 100644 index 0000000..40b310f --- /dev/null +++ b/include/stdlib.h @@ -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. + * + * @(#)stdlib.h 8.3.2 (2.11BSD) 1996/1/12 + * + * Adapted from the 4.4-Lite CD. The odds of a ANSI C compiler for 2.11BSD + * being slipped under the door are not distinguishable from 0 - so the + * prototypes and ANSI ifdefs have been removed from this file. + * + * Some functions (strtoul for example) do not exist yet but are retained in + * this file because additions to libc.a are anticipated shortly. + */ + +#ifndef _STDLIB_H_ +#define _STDLIB_H_ + +#include + +#ifndef NULL +#define NULL 0 +#endif + +#define EXIT_FAILURE 1 +#define EXIT_SUCCESS 0 + +#define RAND_MAX 0x7fff + +void abort(); +int abs (int); +int atexit (void (*)(void)); +double atof(); +int atoi(); +long atol(); +void *calloc (size_t, size_t); +void exit (int); +void free (void *); +char *getenv(); +long labs (long); +void *malloc (size_t); +char *mktemp (char *); +int mkstemp (char *); +void qsort(); +int rand(); +void *realloc (void*, size_t); +void srand(); +double strtod(); +long strtol(); +unsigned long strtoul(); +int system(); + +int putenv (char *string); +int setenv (const char *name, const char *value, int overwrite); +int unsetenv (const char *name); +char *_findenv (const char *name, int *offset); + +void *alloca(); + +int daemon(); +char *devname(); +int getloadavg(unsigned loadavg[], int nelem); + +extern char *suboptarg; /* getsubopt(3) external variable */ +int getsubopt(); + +long random (void); +char *setstate (char *); +void srandom (unsigned); + +char *ecvt (double, int, int *, int *); +char *fcvt (double, int, int *, int *); +char *gcvt (double, int, char *); + +#endif /* _STDLIB_H_ */ diff --git a/include/string.h b/include/string.h new file mode 100644 index 0000000..088eceb --- /dev/null +++ b/include/string.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 1985 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include + +#ifndef NULL +#define NULL 0 +#endif + +char *strcat (char *, const char *); +char *strncat (char *, const char *, size_t); +char *strcpy (char *, const char *); +char *strncpy (char *, const char *, size_t); + +char *strstr (const char *, const char *); + +int strcmp (const char *, const char *); +int strncmp (const char *, const char *, size_t); +size_t strlen (const char *); + +int memcmp (const void *, const void *, size_t); + +void *memmove (void *, const void *, size_t); +void *memccpy (void *, const void *, int, size_t); +void *memchr (const void *, int, size_t); +void *memcpy (void *, const void *, size_t); +void *memset (void *, int, size_t); +char *strchr (const char *, int); + +char *strdup (const char *); +char *strpbrk (const char *, const char *); +char *strrchr (const char *, int); +char *strsep (char **, const char *); +char *strtok (char *, const char *); +char *strtok_r (char *, const char *, char **); + +size_t strcspn (const char *, const char *); +size_t strspn (const char *, const char *); + +char *strerror (int); +const char *syserrlst (int); diff --git a/include/strings.h b/include/strings.h new file mode 100644 index 0000000..66c429c --- /dev/null +++ b/include/strings.h @@ -0,0 +1,42 @@ +/*- + * 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. + */ +#include + +int bcmp(const void *, const void *, size_t); +void bcopy(const void *, void *, size_t); +void bzero(void *, unsigned long); +int ffs(int); +char *index(const char *, int); +char *rindex(const char *, int); +int strcasecmp(const char *, const char *); +int strncasecmp(const char *, const char *, size_t); diff --git a/include/struct.h b/include/struct.h new file mode 100644 index 0000000..2486388 --- /dev/null +++ b/include/struct.h @@ -0,0 +1,9 @@ +/* struct.h 4.1 83/05/03 */ + +/* + * access to information relating to the fields of a structure + */ + +#define fldoff(str, fld) ((int)&(((struct str *)0)->fld)) +#define fldsiz(str, fld) (sizeof(((struct str *)0)->fld)) +#define strbase(str, ptr, fld) ((struct str *)((char *)(ptr)-fldoff(str, fld))) diff --git a/include/sys b/include/sys new file mode 120000 index 0000000..16daa13 --- /dev/null +++ b/include/sys @@ -0,0 +1 @@ +../sys/include \ No newline at end of file diff --git a/include/syscall.h b/include/syscall.h new file mode 100644 index 0000000..49f8262 --- /dev/null +++ b/include/syscall.h @@ -0,0 +1,176 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +/* + * DO NOT place any comments on the same line as a SYS_* definition. This + * causes cpp to leave a trailing tab when expanding macros in pdp/sys/SYS.h + */ + +#define SYS_exit 1 +#define SYS_fork 2 +#define SYS_read 3 +#define SYS_write 4 +#define SYS_open 5 +#define SYS_close 6 +#define SYS_wait4 7 + /* 8 is old; creat */ +#define SYS_link 9 +#define SYS_unlink 10 +#define SYS_execv 11 +#define SYS_chdir 12 +#define SYS_fchdir 13 +#define SYS_mknod 14 +#define SYS_chmod 15 +#define SYS_chown 16 +#define SYS_chflags 17 +#define SYS_fchflags 18 +#define SYS_lseek 19 +#define SYS_getpid 20 +#define SYS_mount 21 +#define SYS_umount 22 +#define SYS___sysctl 23 +#define SYS_getuid 24 +#define SYS_geteuid 25 +#define SYS_ptrace 26 +#define SYS_getppid 27 +#define SYS_statfs 28 +#define SYS_fstatfs 29 +#define SYS_getfsstat 30 +#define SYS_sigaction 31 +#define SYS_sigprocmask 32 +#define SYS_access 33 +#define SYS_sigpending 34 +#define SYS_sigaltstack 35 +#define SYS_sync 36 +#define SYS_kill 37 +#define SYS_stat 38 + /* 39 was getlogin */ +#define SYS_lstat 40 +#define SYS_dup 41 +#define SYS_pipe 42 + /* 43 was setlogin */ +#define SYS_profil 44 +#define SYS_setuid 45 +#define SYS_seteuid 46 +#define SYS_getgid 47 +#define SYS_getegid 48 +#define SYS_setgid 49 +#define SYS_setegid 50 +#define SYS_kmemdev 51 +#define SYS_phys 52 +#define SYS_lock 53 +#define SYS_ioctl 54 +#define SYS_reboot 55 +#define SYS_sigwait 56 +#define SYS_symlink 57 +#define SYS_readlink 58 +#define SYS_execve 59 +#define SYS_umask 60 +#define SYS_chroot 61 +#define SYS_fstat 62 + /* 63 is unused */ + /* 64 is old; getpagesize */ +#define SYS_pselect 65 +#define SYS_vfork 2 /* 66 - not fixed yet */ + /* 67 is old; vread */ + /* 68 is old; vwrite */ +#define SYS_sbrk 69 +#define SYS_rdglob 70 +#define SYS_wrglob 71 + /* 71 is unused 4.3: mmap */ +#define SYS_msec 72 /* 72 is unused 4.3: vadvise */ + /* 73 is unused 4.3: munmap */ + /* 74 is unused 4.3: mprotect */ + /* 75 is unused 4.3: madvise */ +#define SYS_vhangup 76 + /* 77 is old; vlimit */ + /* 78 is unused 4.3: mincore */ +#define SYS_getgroups 79 +#define SYS_setgroups 80 +#define SYS_getpgrp 81 +#define SYS_setpgrp 82 +#define SYS_setitimer 83 + /* 84 is old; wait,wait3 */ +#define SYS_swapon 85 +#define SYS_getitimer 86 + /* 87 is old; gethostname */ + /* 88 is old; sethostname */ +#define SYS_getdtablesize 89 +#define SYS_dup2 90 + /* 91 is unused 4.3: getdopt */ +#define SYS_fcntl 92 +#define SYS_select 93 + /* 94 is unused 4.3: setdopt */ +#define SYS_fsync 95 +#define SYS_setpriority 96 +#define SYS_socket 97 +#define SYS_connect 98 +#define SYS_accept 99 +#define SYS_getpriority 100 +#define SYS_send 101 +#define SYS_recv 102 +#define SYS_sigreturn 103 +#define SYS_bind 104 +#define SYS_setsockopt 105 +#define SYS_listen 106 +#define SYS_sigsuspend 107 +/* + * 108 thru 112 are 4.3BSD compatibility syscalls. sigstack has to remain + * defined because no replacement routine exists. Sigh. +*/ + /* 108 is old; sigvec */ + /* 109 is old; sigblock */ + /* 110 is old; sigsetmask */ + /* 111 is old; sigpause */ +#define SYS_sigstack 112 + +#define SYS_recvmsg 113 +#define SYS_sendmsg 114 + /* 115 is old; vtrace */ +#define SYS_gettimeofday 116 +#define SYS_getrusage 117 +#define SYS_getsockopt 118 + /* 119 is old; resuba */ +#define SYS_readv 120 +#define SYS_writev 121 +#define SYS_settimeofday 122 +#define SYS_fchown 123 +#define SYS_fchmod 124 +#define SYS_recvfrom 125 + /* 126 is old; setreuid */ + /* 127 is old; setregid */ +#define SYS_rename 128 +#define SYS_truncate 129 +#define SYS_ftruncate 130 +#define SYS_flock 131 + /* 132 is unused */ +#define SYS_sendto 133 +#define SYS_shutdown 134 +#define SYS_socketpair 135 +#define SYS_mkdir 136 +#define SYS_rmdir 137 +#define SYS_utimes 138 + /* 139 is unused */ +#define SYS_adjtime 140 +#define SYS_getpeername 141 + /* 142 is old; gethostid */ + /* 143 is old; sethostid */ +#define SYS_getrlimit 144 +#define SYS_setrlimit 145 +#define SYS_killpg 146 + /* 147 is unused */ +#define SYS_setquota 148 +#define SYS_quota 149 +#define SYS_getsockname 150 + +/* + * 2BSD special calls + */ + /* 151 is unused */ +#define SYS_ustore 152 +#define SYS_ufetch 153 +#define SYS_ucall 154 + /* 155 is unused */ diff --git a/include/sysexits.h b/include/sysexits.h new file mode 100644 index 0000000..e9bc87f --- /dev/null +++ b/include/sysexits.h @@ -0,0 +1,97 @@ +/* + * Copyright (c) 1987 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that this notice is preserved and that due credit is given + * to the University of California at Berkeley. The name of the University + * may not be used to endorse or promote products derived from this + * software without specific prior written permission. This software + * is provided ``as is'' without express or implied warranty. + * + * @(#)sysexits.h 4.4.1 (2.11BSD) 1996/11/29 + */ + +/* +** SYSEXITS.H -- Exit status codes for system programs. +** +** This include file attempts to categorize possible error +** exit statuses for system programs, notably delivermail +** and the Berkeley network. +** +** Error numbers begin at EX__BASE to reduce the possibility of +** clashing with other exit statuses that random programs may +** already return. The meaning of the codes is approximately +** as follows: +** +** EX_USAGE -- The command was used incorrectly, e.g., with +** the wrong number of arguments, a bad flag, a bad +** syntax in a parameter, or whatever. +** EX_DATAERR -- The input data was incorrect in some way. +** This should only be used for user's data & not +** system files. +** EX_NOINPUT -- An input file (not a system file) did not +** exist or was not readable. This could also include +** errors like "No message" to a mailer (if it cared +** to catch it). +** EX_NOUSER -- The user specified did not exist. This might +** be used for mail addresses or remote logins. +** EX_NOHOST -- The host specified did not exist. This is used +** in mail addresses or network requests. +** EX_UNAVAILABLE -- A service is unavailable. This can occur +** if a support program or file does not exist. This +** can also be used as a catchall message when something +** you wanted to do doesn't work, but you don't know +** why. +** EX_SOFTWARE -- An internal software error has been detected. +** This should be limited to non-operating system related +** errors as possible. +** EX_OSERR -- An operating system error has been detected. +** This is intended to be used for such things as "cannot +** fork", "cannot create pipe", or the like. It includes +** things like getuid returning a user that does not +** exist in the passwd file. +** EX_OSFILE -- Some system file (e.g., /etc/passwd, /var/run/utmp, +** etc.) does not exist, cannot be opened, or has some +** sort of error (e.g., syntax error). +** EX_CANTCREAT -- A (user specified) output file cannot be +** created. +** EX_IOERR -- An error occurred while doing I/O on some file. +** EX_TEMPFAIL -- temporary failure, indicating something that +** is not really an error. In sendmail, this means +** that a mailer (e.g.) could not create a connection, +** and the request should be reattempted later. +** EX_PROTOCOL -- the remote system returned something that +** was "not possible" during a protocol exchange. +** EX_NOPERM -- You did not have sufficient permission to +** perform the operation. This is not intended for +** file system problems, which should use NOINPUT or +** CANTCREAT, but rather for higher level permissions. +** For example, kre uses this to restrict who students +** can send mail to. +** +** Maintained by Eric Allman (eric@berkeley, ucbvax!eric) -- +** please mail changes to me. +** +** @(#)sysexits.h 4.4 3/24/88 +*/ + +# define EX_OK 0 /* successful termination */ + +# define EX__BASE 64 /* base value for error messages */ + +# define EX_USAGE 64 /* command line usage error */ +# define EX_DATAERR 65 /* data format error */ +# define EX_NOINPUT 66 /* cannot open input */ +# define EX_NOUSER 67 /* addressee unknown */ +# define EX_NOHOST 68 /* host name unknown */ +# define EX_UNAVAILABLE 69 /* service unavailable */ +# define EX_SOFTWARE 70 /* internal software error */ +# define EX_OSERR 71 /* system error (e.g., can't fork) */ +# define EX_OSFILE 72 /* critical OS file missing */ +# define EX_CANTCREAT 73 /* can't create (user) output file */ +# define EX_IOERR 74 /* input/output error */ +# define EX_TEMPFAIL 75 /* temp failure; user is invited to retry */ +# define EX_PROTOCOL 76 /* remote error in protocol */ +# define EX_NOPERM 77 /* permission denied */ +# define EX_CONFIG 78 /* configuration error */ diff --git a/include/syslog.h b/include/syslog.h new file mode 120000 index 0000000..11b106a --- /dev/null +++ b/include/syslog.h @@ -0,0 +1 @@ +sys/syslog.h \ No newline at end of file diff --git a/include/tcl/tcl.h b/include/tcl/tcl.h new file mode 100644 index 0000000..1804323 --- /dev/null +++ b/include/tcl/tcl.h @@ -0,0 +1,242 @@ +/* + * tcl.h -- + * + * This header file describes the externally-visible facilities + * of the Tcl interpreter. + * + * Copyright 1987-1991 Regents of the University of California + * 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. The University of California + * makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without + * express or implied warranty. + */ +#ifndef _TCL +#define _TCL + +#define TCL_VERSION "6.7" +#define TCL_MAJOR_VERSION 6 +#define TCL_MINOR_VERSION 7 + +/* + * Data structures defined opaquely in this module. The definitions + * below just provide dummy types. A few fields are made visible in + * Tcl_Interp structures, namely those for returning string values. + * Note: any change to the Tcl_Interp definition below must be mirrored + * in the "real" definition in tclInt.h. + */ +typedef struct Tcl_Interp { + unsigned char *result; /* Points to result string returned by last + * command. */ + void (*freeProc) (unsigned char *blockPtr); + /* Zero means result is statically allocated. + * If non-zero, gives address of procedure + * to invoke to free the result. Must be + * freed by Tcl_Eval before executing next + * command. */ + unsigned short errorLine; /* When TCL_ERROR is returned, this gives + * the line number within the command where + * the error occurred (1 means first line). */ +} Tcl_Interp; + +typedef void *Tcl_Trace; +typedef void *Tcl_CmdBuf; + +/* + * When a TCL command returns, the string pointer interp->result points to + * a string containing return information from the command. In addition, + * the command procedure returns an integer value, which is one of the + * following: + * + * TCL_OK Command completed normally; interp->result contains + * the command's result. + * TCL_ERROR The command couldn't be completed successfully; + * interp->result describes what went wrong. + * TCL_RETURN The command requests that the current procedure + * return; interp->result contains the procedure's + * return value. + * TCL_BREAK The command requests that the innermost loop + * be exited; interp->result is meaningless. + * TCL_CONTINUE Go on to the next iteration of the current loop; + * interp->result is meaninless. + */ +#define TCL_OK 0 +#define TCL_ERROR 1 +#define TCL_RETURN 2 +#define TCL_BREAK 3 +#define TCL_CONTINUE 4 + +#define TCL_RESULT_SIZE 199 + +/* + * Procedure types defined by Tcl: + */ +typedef void (Tcl_CmdDeleteProc) (void *clientData); +typedef int (Tcl_CmdProc) (void *clientData, + Tcl_Interp *interp, int argc, unsigned char *argv[]); +typedef void (Tcl_CmdTraceProc) (void *clientData, + Tcl_Interp *interp, int level, unsigned char *command, Tcl_CmdProc *proc, + void *cmdClientData, int argc, unsigned char *argv[]); +typedef void (Tcl_FreeProc) (unsigned char *blockPtr); +typedef unsigned char *(Tcl_VarTraceProc) (void *clientData, + Tcl_Interp *interp, unsigned char *part1, unsigned char *part2, int flags); + +/* + * Flag values passed to Tcl_Eval (see the man page for details; also + * see tclInt.h for additional flags that are only used internally by + * Tcl): + */ +#define TCL_BRACKET_TERM 1 + +/* + * Flag that may be passed to Tcl_ConvertElement to force it not to + * output braces (careful! if you change this flag be sure to change + * the definitions at the front of tclUtil.c). + */ +#define TCL_DONT_USE_BRACES 1 + +/* + * Flag value passed to Tcl_RecordAndEval to request no evaluation + * (record only). + */ +#define TCL_NO_EVAL -1 + +/* + * Specil freeProc values that may be passed to Tcl_SetResult (see + * the man page for details): + */ +#define TCL_STATIC ((Tcl_FreeProc *) 0) +#define TCL_VOLATILE ((Tcl_FreeProc *) -1) +#define TCL_DYNAMIC ((Tcl_FreeProc *) -2) + +/* + * Flag values passed to variable-related procedures. + */ +#define TCL_GLOBAL_ONLY 1 +#define TCL_APPEND_VALUE 2 +#define TCL_LIST_ELEMENT 4 +#define TCL_NO_SPACE 8 +#define TCL_TRACE_READS 0x10 +#define TCL_TRACE_WRITES 0x20 +#define TCL_TRACE_UNSETS 0x40 +#define TCL_TRACE_DESTROYED 0x80 +#define TCL_INTERP_DESTROYED 0x100 +#define TCL_LEAVE_ERR_MSG 0x200 + +/* + * Additional flag passed back to variable watchers. This flag must + * not overlap any of the TCL_TRACE_* flags defined above or the + * TRACE_* flags defined in tclInt.h. + */ +#define TCL_VARIABLE_UNDEFINED 8 + +/* + * Exported Tcl procedures: + */ +extern void Tcl_AppendElement (Tcl_Interp *interp, unsigned char *string, + int noSep); +extern void Tcl_AppendResult (Tcl_Interp *interp, ...); +extern unsigned char * Tcl_AssembleCmd (Tcl_CmdBuf buffer, unsigned char *string); +extern void Tcl_AddErrorInfo (Tcl_Interp *interp, unsigned char *message); +extern char Tcl_Backslash (unsigned char *src, int *readPtr); +extern int Tcl_CommandComplete (unsigned char *cmd); +extern unsigned char * Tcl_Concat (int argc, unsigned char **argv); +extern int Tcl_ConvertElement (unsigned char *src, unsigned char *dst, int flags); +extern Tcl_CmdBuf Tcl_CreateCmdBuf (void); +extern void Tcl_CreateCommand (Tcl_Interp *interp, unsigned char *cmdName, + Tcl_CmdProc *proc, void *clientData, + Tcl_CmdDeleteProc *deleteProc); +extern Tcl_Interp * Tcl_CreateInterp (void); +extern int Tcl_CreatePipeline (Tcl_Interp *interp, int argc, + unsigned char **argv, int **pidArrayPtr, + int *inPipePtr, int *outPipePtr, + int *errFilePtr); +extern Tcl_Trace Tcl_CreateTrace (Tcl_Interp *interp, + int level, Tcl_CmdTraceProc *proc, + void *clientData); +extern void Tcl_DeleteCmdBuf (Tcl_CmdBuf buffer); +extern int Tcl_DeleteCommand (Tcl_Interp *interp, + unsigned char *cmdName); +extern void Tcl_DeleteInterp (Tcl_Interp *interp); +extern void Tcl_DeleteTrace (Tcl_Interp *interp, + Tcl_Trace trace); +extern void Tcl_DetachPids (int numPids, int *pidPtr); +extern unsigned char * Tcl_ErrnoId (void); +extern int Tcl_Eval (Tcl_Interp *interp, unsigned char *cmd, + int flags, unsigned char **termPtr); +extern int Tcl_EvalFile (Tcl_Interp *interp, + unsigned char *fileName); +extern int Tcl_ExprBoolean (Tcl_Interp *interp, unsigned char *string, + int *ptr); +extern int Tcl_ExprLong (Tcl_Interp *interp, unsigned char *string, + long *ptr); +extern int Tcl_ExprString (Tcl_Interp *interp, unsigned char *string); +extern int Tcl_Fork (void); +extern void Tcl_FreeResult (Tcl_Interp *interp); +extern int Tcl_GetBoolean (Tcl_Interp *interp, + unsigned char *string, int *boolPtr); +extern int Tcl_GetInt (Tcl_Interp *interp, + unsigned char *string, int *intPtr); +extern unsigned char * Tcl_GetVar (Tcl_Interp *interp, + unsigned char *varName, int flags); +extern unsigned char * Tcl_GetVar2 (Tcl_Interp *interp, + unsigned char *part1, unsigned char *part2, int flags); +extern int Tcl_GlobalEval (Tcl_Interp *interp, + unsigned char *command); +extern void Tcl_InitHistory (Tcl_Interp *interp); +extern void Tcl_InitMemory (Tcl_Interp *interp); +extern unsigned char * Tcl_Merge (int argc, unsigned char **argv); +extern unsigned char * Tcl_ParseVar (Tcl_Interp *interp, + unsigned char *string, unsigned char **termPtr); +extern int Tcl_RecordAndEval (Tcl_Interp *interp, + unsigned char *cmd, int flags); +extern void Tcl_ResetResult (Tcl_Interp *interp); +extern int Tcl_ScanElement (unsigned char *string, + int *flagPtr); +extern void Tcl_SetErrorCode (Tcl_Interp *interp, ...); +extern void Tcl_SetResult (Tcl_Interp *interp, + unsigned char *string, Tcl_FreeProc *freeProc); +extern unsigned char * Tcl_SetVar (Tcl_Interp *interp, + unsigned char *varName, unsigned char *newValue, int flags); +extern unsigned char * Tcl_SetVar2 (Tcl_Interp *interp, + unsigned char *part1, unsigned char *part2, + unsigned char *newValue, int flags); +extern unsigned char * Tcl_SignalId (int sig); +extern unsigned char * Tcl_SignalMsg (int sig); +extern int Tcl_SplitList (Tcl_Interp *interp, + unsigned char *list, int *argcPtr, unsigned char ***argvPtr); +extern int Tcl_StringMatch (unsigned char *string, + unsigned char *pattern); +extern unsigned char * Tcl_TildeSubst (Tcl_Interp *interp, + unsigned char *name); +extern int Tcl_TraceVar (Tcl_Interp *interp, + unsigned char *varName, int flags, Tcl_VarTraceProc *proc, + void *clientData); +extern int Tcl_TraceVar2 (Tcl_Interp *interp, + unsigned char *part1, unsigned char *part2, int flags, + Tcl_VarTraceProc *proc, void *clientData); +extern int Tcl_UnsetVar (Tcl_Interp *interp, + unsigned char *varName, int flags); +extern int Tcl_UnsetVar2 (Tcl_Interp *interp, + unsigned char *part1, unsigned char *part2, int flags); +extern void Tcl_UntraceVar (Tcl_Interp *interp, + unsigned char *varName, int flags, Tcl_VarTraceProc *proc, + void *clientData); +extern void Tcl_UntraceVar2 (Tcl_Interp *interp, + unsigned char *part1, unsigned char *part2, int flags, + Tcl_VarTraceProc *proc, void *clientData); +extern int Tcl_VarEval (Tcl_Interp *interp, ...); +extern void * Tcl_VarTraceInfo (Tcl_Interp *interp, + unsigned char *varName, int flags, + Tcl_VarTraceProc *procPtr, + void *prevClientData); +extern void * Tcl_VarTraceInfo2 (Tcl_Interp *interp, + unsigned char *part1, unsigned char *part2, int flags, + Tcl_VarTraceProc *procPtr, + void *prevClientData); +extern int Tcl_WaitPids (int numPids, int *pidPtr, + int *statusPtr); + +#endif /* _TCL */ diff --git a/include/term.h b/include/term.h new file mode 100644 index 0000000..bc1865e --- /dev/null +++ b/include/term.h @@ -0,0 +1,11 @@ +#ifndef _TERM_H +#define _TERM_H + +extern int tgetent(char *, char *); +extern int tgetnum(char *); +extern int tgetflag(char *); +extern char *tgetstr(char *, char **); +extern char *tgoto(char *, int, int); +extern int tputs(register char *, int, int (*)()); + +#endif diff --git a/include/termios-todo.h b/include/termios-todo.h new file mode 100644 index 0000000..514f179 --- /dev/null +++ b/include/termios-todo.h @@ -0,0 +1,149 @@ +#ifndef _TERMIOS_H +#define _TERMIOS_H + +#include +#include + +#define E_TERMCAP "/etc/termcap" + +typedef unsigned char cc_t; +typedef unsigned int speed_t; +typedef unsigned int tcflag_t; + +#define NCCS 32 +struct termios + { + tcflag_t c_iflag; /* input mode flags */ + tcflag_t c_oflag; /* output mode flags */ + tcflag_t c_cflag; /* control mode flags */ + tcflag_t c_lflag; /* local mode flags */ + cc_t c_line; /* line discipline */ + cc_t c_cc[NCCS]; /* control characters */ + speed_t c_ispeed; /* input speed */ + speed_t c_ospeed; /* output speed */ +#define _HAVE_STRUCT_TERMIOS_C_ISPEED 1 +#define _HAVE_STRUCT_TERMIOS_C_OSPEED 1 + }; + +extern int tcgetattr(int, struct termios *); +extern int tcsetattr(int, int, struct termios *); + +/* c_cc characters */ +#define VINTR 0 +#define VQUIT 1 +#define VERASE 2 +#define VKILL 3 +#define VEOF 4 +#define VTIME 5 +#define VMIN 6 +#define VSWTC 7 +#define VSTART 8 +#define VSTOP 9 +#define VSUSP 10 +#define VEOL 11 +#define VREPRINT 12 +#define VDISCARD 13 +#define VWERASE 14 +#define VLNEXT 15 +#define VEOL2 16 + +/* c_iflag bits */ +#define IGNBRK 0000001 +#define BRKINT 0000002 +#define IGNPAR 0000004 +#define PARMRK 0000010 +#define INPCK 0000020 +#define ISTRIP 0000040 +#define INLCR 0000100 +#define IGNCR 0000200 +#define ICRNL 0000400 +#define IUCLC 0001000 +#define IXON 0002000 +#define IXANY 0004000 +#define IXOFF 0010000 +#define IMAXBEL 0020000 +#define IUTF8 0040000 + +/* c_oflag bits */ +#define OPOST 0000001 +#define OLCUC 0000002 +#define ONLCR 0000004 +#define OCRNL 0000010 +#define ONOCR 0000020 +#define ONLRET 0000040 +#define OFILL 0000100 +#define OFDEL 0000200 +#if defined __USE_MISC || defined __USE_XOPEN +# define NLDLY 0000400 +# define NL0 0000000 +# define NL1 0000400 +# define CRDLY 0003000 +# define CR0 0000000 +# define CR1 0001000 +# define CR2 0002000 +# define CR3 0003000 +# define TABDLY 0014000 +# define TAB0 0000000 +# define TAB1 0004000 +# define TAB2 0010000 +# define TAB3 0014000 +# define BSDLY 0020000 +# define BS0 0000000 +# define BS1 0020000 +# define FFDLY 0100000 +# define FF0 0000000 +# define FF1 0100000 +#endif + +#define VTDLY 0040000 +#define VT0 0000000 +#define VT1 0040000 + +#ifdef __USE_MISC +# define XTABS 0014000 +#endif + +/* c_lflag bits */ +#define ISIG 0000001 +#define ICANON 0000002 + +#define CSIZE 0000060 +#define CS5 0000000 +#define CS6 0000020 +#define CS7 0000040 +#define CS8 0000060 +#define CSTOPB 0000100 +#define CREAD 0000200 +#define PARENB 0000400 +#define PARODD 0001000 +#define HUPCL 0002000 +#define CLOCAL 0004000 + +#define IEXTEN 0100000 + +/* tcflow() and TCXONC use these */ +#define TCOOFF 0 +#define TCOON 1 +#define TCIOFF 2 +#define TCION 3 + +/* tcflush() and TCFLSH use these */ +#define TCIFLUSH 0 +#define TCOFLUSH 1 +#define TCIOFLUSH 2 + +/* tcsetattr uses these */ +#define TCSANOW 0 +#define TCSADRAIN 1 +#define TCSAFLUSH 2 + +#define TCSASOFT 0x10 +#define CIGNORE 0x00000001 + +#define TIOCGETA _IOR(i, 92, struct termios) +#define TIOCSETA _IOW(i, 92, struct termios) +#define TIOCSETAW _IOW(i, 92, struct termios) +#define TIOCSETAF _IOW(i, 92, struct termios) + + +#endif diff --git a/include/time.h b/include/time.h new file mode 100644 index 0000000..6691c17 --- /dev/null +++ b/include/time.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 1983, 1987 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#ifndef _TIME_H +#define _TIME_H + +#include /* for time_t */ + +/* + * Structure returned by gmtime and localtime calls (see ctime(3)). + */ +struct tm { + int tm_sec; + int tm_min; + int tm_hour; + int tm_mday; + int tm_mon; + int tm_year; + int tm_wday; + int tm_yday; + int tm_isdst; + long tm_gmtoff; + char *tm_zone; +}; + +extern struct tm *gmtime(), *localtime(); +extern char *asctime(), *ctime(); +extern time_t time(); + +size_t strftime (char *s, size_t maxsize, const char *format, + const struct tm *timeptr); + +#endif diff --git a/include/ttyent.h b/include/ttyent.h new file mode 100644 index 0000000..3e70681 --- /dev/null +++ b/include/ttyent.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +struct ttyent { /* see getttyent(3) */ + char *ty_name; /* terminal device name */ + char *ty_getty; /* command to execute, usually getty */ + char *ty_type; /* terminal type for termcap (3X) */ + int ty_status; /* status flags (see below for defines) */ + char *ty_window; /* command to start up window manager */ + char *ty_comment; /* usually the location of the terminal */ +}; + +#define TTY_ON 0x1 /* enable logins (startup getty) */ +#define TTY_SECURE 0x2 /* allow root to login */ + +struct ttyent *getttyent (void); +struct ttyent *getttynam (const char *name); +void setttyent (void); +void endttyent (void); diff --git a/include/tzfile.h b/include/tzfile.h new file mode 100644 index 0000000..8b4c60a --- /dev/null +++ b/include/tzfile.h @@ -0,0 +1,100 @@ +/* + * @(#)tzfile.h 5.2.1 (2.11BSD) 1996/11/29 + */ + +/* +** Information about time zone files. +*/ + + /* Time zone object file directory */ +#define TZDEFAULT "/etc/localtime" + +/* +** Each file begins with. . . +*/ + +struct tzhead { + char tzh_reserved[32]; /* reserved for future use */ + char tzh_timecnt[4]; /* coded number of transition times */ + char tzh_typecnt[4]; /* coded number of local time types */ + char tzh_charcnt[4]; /* coded number of abbr. chars */ +}; + +/* +** . . .followed by. . . +** +** tzh_timecnt (char [4])s coded transition times a la time(2) +** tzh_timecnt (unsigned char)s types of local time starting at above +** tzh_typecnt repetitions of +** one (char [4]) coded GMT offset in seconds +** one (unsigned char) used to set tm_isdt +** one (unsigned char) that's an abbreviation list index +** tzh_charcnt (char)s '\0'-terminated zone abbreviaton strings +*/ + +/* +** In the current implementation, "tzset()" refuses to deal with files that +** exceed any of the limits below. +*/ + +/* +** The TZ_MAX_TIMES value below is enough to handle a bit more than a +** year's worth of solar time (corrected daily to the nearest second) or +** 138 years of Pacific Presidential Election time +** (where there are three time zone transitions every fourth year). +*/ +#define TZ_MAX_TIMES 370 + +#define NOSOLAR /* We currently don't handle solar time */ + +#ifndef NOSOLAR +#define TZ_MAX_TYPES 256 /* Limited by what (unsigned char)'s can hold */ +#else /* !NOSOLAR */ +#define TZ_MAX_TYPES 10 /* Maximum number of local time types */ +#endif /* !NOSOLAR */ + +#define TZ_MAX_CHARS 50 /* Maximum number of abbreviation characters */ + +#define SECS_PER_MIN 60 +#define MINS_PER_HOUR 60 +#define HOURS_PER_DAY 24 +#define DAYS_PER_WEEK 7 +#define DAYS_PER_NYEAR 365 +#define DAYS_PER_LYEAR 366 +#define SECS_PER_HOUR (SECS_PER_MIN * MINS_PER_HOUR) +#define SECS_PER_DAY ((long) SECS_PER_HOUR * HOURS_PER_DAY) +#define MONS_PER_YEAR 12 + +#define TM_SUNDAY 0 +#define TM_MONDAY 1 +#define TM_TUESDAY 2 +#define TM_WEDNESDAY 3 +#define TM_THURSDAY 4 +#define TM_FRIDAY 5 +#define TM_SATURDAY 6 + +#define TM_JANUARY 0 +#define TM_FEBRUARY 1 +#define TM_MARCH 2 +#define TM_APRIL 3 +#define TM_MAY 4 +#define TM_JUNE 5 +#define TM_JULY 6 +#define TM_AUGUST 7 +#define TM_SEPTEMBER 8 +#define TM_OCTOBER 9 +#define TM_NOVEMBER 10 +#define TM_DECEMBER 11 +#define TM_SUNDAY 0 + +#define TM_YEAR_BASE 1900 + +#define EPOCH_YEAR 1970 +#define EPOCH_WDAY TM_THURSDAY + +/* +** Accurate only for the past couple of centuries; +** that will probably do. +*/ + +#define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0) diff --git a/include/unistd.h b/include/unistd.h new file mode 100644 index 0000000..e16b28e --- /dev/null +++ b/include/unistd.h @@ -0,0 +1,161 @@ +/*- + * 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. + */ + +/* + * Modified for 2.11BSD by removing prototypes. To save time and space + * functions not returning 'int' and functions not present in the system + * are not listed. +*/ + +#ifndef _UNISTD_H_ +#define _UNISTD_H_ + +#include + +#define STDIN_FILENO 0 /* standard input file descriptor */ +#define STDOUT_FILENO 1 /* standard output file descriptor */ +#define STDERR_FILENO 2 /* standard error file descriptor */ + +#ifndef NULL +#define NULL 0 /* null pointer constant */ +#endif + +/* Values for the second argument to access. + These may be OR'd together. */ +#define R_OK 4 /* Test for read permission. */ +#define W_OK 2 /* Test for write permission. */ +#define X_OK 1 /* Test for execute permission. */ +#define F_OK 0 /* Test for existence. */ + +void _exit (int); +int access(); +unsigned int alarm(); +pid_t fork(); +gid_t getegid(); +uid_t geteuid(); +gid_t getgid(); +char *getlogin(); +pid_t getpgrp(); +pid_t getpid(); +pid_t getppid(); +uid_t getuid(); +off_t lseek(); +ssize_t read(); +unsigned int sleep(); +char *ttyname(); +ssize_t write (int fd, const void *buf, size_t count); +int truncate (const char *path, off_t length); +int ftruncate (int fd, off_t length); + +void *brk (const void *addr); +int _brk (const void *addr); +char *crypt(); +void endusershell(); +long gethostid(); +char *getpass(); +char *getusershell(); +char *getwd(); +void psignal(); +extern char *sys_siglist[]; +char *re_comp(); +void *sbrk (int incr); +int sethostid(); +void setusershell(); +void sync(); +unsigned int ualarm(); +void usleep(); +int pause (void); +pid_t vfork(); + +int pipe (int pipefd[2]); +int close (int fd); +int dup (int oldfd); +int dup2 (int oldfd, int newfd); +int unlink (const char *pathname); +int link (const char *oldpath, const char *newpath); +ssize_t readlink (const char *path, char *buf, size_t bufsiz); +int chown (const char *path, uid_t owner, gid_t group); +int nice (int inc); +int setuid (uid_t uid); +int setgid (gid_t gid); +int seteuid (uid_t euid); +int setegid (gid_t egid); +int setreuid (uid_t ruid, uid_t euid); +int setregid (gid_t rgid, gid_t egid); +int isatty (int fd); +int chdir (const char *path); +int fchdir (int fd); +int chflags (const char *path, u_long flags); +int fchflags (int fd, u_long flags); +int getgroups (int size, gid_t list[]); +int getdtablesize (void); +int rmdir (const char *pathname); + +struct stat; +int stat (const char *path, struct stat *buf); +int fstat (int fd, struct stat *buf); +int lstat (const char *path, struct stat *buf); + +int execl (const char *path, const char *arg0, ... /* NULL */); +int execle (const char *path, const char *arg0, ... /* NULL, char *envp[] */); +int execlp (const char *file, const char *arg0, ... /* NULL */); + +int execv (const char *path, char *const argv[]); +int execve (const char *path, char *const arg0[], char *const envp[]); +int execvp (const char *file, char *const argv[]); + +extern char **environ; /* Environment, from crt0. */ +extern const char *__progname; /* Program name, from crt0. */ + +int getopt (int argc, char * const argv[], const char *optstring); + +extern char *optarg; /* getopt(3) external variables */ +extern int opterr, optind, optopt; + +#ifndef _VA_LIST_ +#define va_list __builtin_va_list /* For GCC */ +#endif + +void err (int eval, const char *fmt, ...); +void errx (int eval, const char *fmt, ...); +void warn (const char *fmt, ...); +void warnx (const char *fmt, ...); +void verr (int eval, const char *fmt, va_list ap); +void verrx (int eval, const char *fmt, va_list ap); +void vwarn (const char *fmt, va_list ap); +void vwarnx (const char *fmt, va_list ap); + +#ifndef _VA_LIST_ +#undef va_list +#endif +#endif /* !_UNISTD_H_ */ diff --git a/include/utmp.h b/include/utmp.h new file mode 100644 index 0000000..c22e9ed --- /dev/null +++ b/include/utmp.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 1988 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#define UT_NAMESIZE 15 +#define UT_LINESIZE 8 +#define UT_HOSTSIZE 16 + +struct utmp { + char ut_line[UT_LINESIZE]; + char ut_name[UT_NAMESIZE]; + char ut_host[UT_HOSTSIZE]; + long ut_time; +}; diff --git a/include/vmf.h b/include/vmf.h new file mode 100644 index 0000000..0144f4e --- /dev/null +++ b/include/vmf.h @@ -0,0 +1,64 @@ +/* Program Name: vmf.h + * Author: S.M. Schultz + * + * ----------- Modification History ------------ + * Version Date Reason For Modification + * 1.0 01Jan80 1. Initial release. + * 2.0 31Mar83 2. Cleanup. + * 3.0 08Sep93 3. Change v_foffset to off_t instead of int. + * 3.1 21Oct93 4. Create union member of structure to + * make 'int' or 'char' access to data easy. + * Define segment+offset and modified macros. + * Place into the public domain. + * -------------------------------------------------- +*/ + +#include + +#define MAXSEGNO 16384 /* max number of segments in a space */ +#define BYTESPERSEG 1024 /* must be power of two! */ +#define LOG2BPS 10 /* log2(BYTESPERSEG) */ +#define WORDSPERSEG (BYTESPERSEG/sizeof (int)) + +struct vspace { + int v_fd; /* file for swapping */ + off_t v_foffset; /* offset for computing file addresses */ + int v_maxsegno; /* number of segments in this space */ + }; + +struct dlink { /* general double link structure */ + struct dlink *fwd; /* forward link */ + struct dlink *back; /* back link */ + }; + +struct vseg { /* structure of a segment in memory */ + struct dlink s_link; /* for linking into lru list */ + int s_segno; /* segment number */ + struct vspace *s_vspace; /* which virtual space */ + int s_lock_count; + int s_flags; + union + { + int _winfo[WORDSPERSEG]; /* the actual segment */ + char _cinfo[BYTESPERSEG]; + } v_un; + }; + +#define s_winfo v_un._winfo +#define s_cinfo v_un._cinfo + +/* masks for s_flags */ +#define S_DIRTY 01 /* segment has been modified */ + + long nswaps; /* number of swaps */ + long nmapsegs; /* number of mapseg calls */ + + int vminit(), vmopen(); + struct vseg *vmmapseg(); + void vmlock(), vmunlock(), vmclrseg(), vmmodify(); + void vmflush(), vmclose(); + +typedef long VADDR; +#define VMMODIFY(seg) (seg->s_flags |= S_DIRTY) +#define VSEG(va) ((short)(va >> LOG2BPS)) +#define VOFF(va) ((u_short)va % BYTESPERSEG) diff --git a/include/wiznet/client.h b/include/wiznet/client.h new file mode 100644 index 0000000..da96049 --- /dev/null +++ b/include/wiznet/client.h @@ -0,0 +1,29 @@ +#ifndef client_h +#define client_h + +struct _client_t { + unsigned sock; + uint8_t *ip; + unsigned port; +}; +typedef struct _client_t client_t; + +extern unsigned _client_srcport; + +void client_init (client_t *c, uint8_t *ip, unsigned port); +void client_init_sock (client_t *c, unsigned sock); + +unsigned client_status (client_t *); +int client_connect (client_t *); +void client_putc (client_t *, uint8_t); +void client_puts (client_t *c, const char *str); +void client_write (client_t *c, const uint8_t *buf, unsigned size); +int client_available (client_t *); +int client_getc (client_t *); +int client_read (client_t *c, uint8_t *buf, unsigned size); +int client_peek (client_t *); +void client_flush (client_t *); +void client_stop (client_t *); +int client_connected (client_t *); + +#endif diff --git a/include/wiznet/ethernet.h b/include/wiznet/ethernet.h new file mode 100644 index 0000000..e895bef --- /dev/null +++ b/include/wiznet/ethernet.h @@ -0,0 +1,12 @@ +#ifndef ethernet_h +#define ethernet_h + +#include +#include "client.h" +#include "server.h" + +#define MAX_SOCK_NUM 4 + +void ethernet_init (void); + +#endif diff --git a/include/wiznet/server.h b/include/wiznet/server.h new file mode 100644 index 0000000..60450b8 --- /dev/null +++ b/include/wiznet/server.h @@ -0,0 +1,16 @@ +#ifndef server_h +#define server_h + +#include "client.h" + +extern unsigned _server_port; + +void server_init (unsigned port); + +int server_available (client_t *); +void server_accept (void); +void server_putc (uint8_t byte); +void server_puts (const char *str); +void server_write (const uint8_t *buf, unsigned size); + +#endif diff --git a/include/wiznet/socket.h b/include/wiznet/socket.h new file mode 100644 index 0000000..67ddd37 --- /dev/null +++ b/include/wiznet/socket.h @@ -0,0 +1,56 @@ +#ifndef _SOCKET_H_ +#define _SOCKET_H_ + +#include "w5100.h" + +extern unsigned _socket_port [MAX_SOCK_NUM]; + +/* + * Opens a socket(TCP or UDP or IP_RAW mode) + */ +unsigned socket_init (unsigned sock, unsigned protocol, unsigned port, unsigned flag); + +/* + * Close socket + */ +void socket_close (unsigned sock); + +/* + * Establish TCP connection (Active connection) + */ +unsigned socket_connect (unsigned sock, uint8_t *addr, unsigned port); + +/* + * disconnect the connection + */ +void socket_disconnect (unsigned sock); + +/* + * Establish TCP connection (Passive connection) + */ +unsigned socket_listen (unsigned sock); + +/* + * Send data (TCP) + */ +unsigned socket_send (unsigned sock, const uint8_t *buf, unsigned len); + +/* + * Receive data (TCP) + */ +unsigned socket_recv (unsigned sock, uint8_t *buf, unsigned len); +unsigned socket_peek (unsigned sock); + +/* + * Send data (UDP/IP RAW) + */ +unsigned socket_sendto (unsigned sock, const uint8_t *buf, unsigned len, uint8_t *addr, unsigned port); + +/* + * Receive data (UDP/IP RAW) + */ +unsigned socket_recvfrom (unsigned sock, uint8_t *buf, unsigned len, uint8_t *addr, unsigned *port); + +unsigned socket_igmpsend (unsigned sock, const uint8_t *buf, unsigned len); + +#endif /* _SOCKET_H_ */ diff --git a/include/wiznet/udp.h b/include/wiznet/udp.h new file mode 100644 index 0000000..0988339 --- /dev/null +++ b/include/wiznet/udp.h @@ -0,0 +1,79 @@ +/* + * Udp.cpp: Library to send/receive UDP packets with the Arduino ethernet shield. + * This version only offers minimal wrapping of socket.c/socket.h + * + * NOTE: UDP is fast, but has some important limitations (thanks to Warren Gray for mentioning these) + * 1) UDP does not guarantee the order in which assembled UDP packets are received. This + * might not happen often in practice, but in larger network topologies, a UDP + * packet can be received out of sequence. + * 2) UDP does not guard against lost packets - so packets *can* disappear without the sender being + * aware of it. Again, this may not be a concern in practice on small local networks. + * For more information, see http://www.cafeaulait.org/course/week12/35.html + * + * MIT License: + * Copyright (c) 2008 Bjoern Hartmann + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * bjoern@cs.stanford.edu 12/30/2008 + */ +#ifndef udp_h +#define udp_h + +#define UDP_TX_PACKET_MAX_SIZE 24 + +struct _udp_t { + unsigned port; // local port to listen on + unsigned sock; // socket ID for Wiz5100 +}; +typedef struct _udp_t udp_t; + +/* + * Initialize, start listening on specified port. + * Returns 1 if successful, 0 if there are no sockets available to use. + */ +int udp_init (udp_t *u, unsigned port); + +/* + * Has data been received? + */ +unsigned udp_available (udp_t *u); + +/* + * Finish with the UDP socket. + */ +void udp_stop (udp_t *u); + +/* + * Send a packet to specified peer. + */ +unsigned udp_send_packet (udp_t *u, const uint8_t *data, unsigned len, + uint8_t *ip, unsigned port); + +/* + * Send a zero-terminated string to specified peer. + */ +unsigned udp_send_string (udp_t *u, const char *data, + uint8_t *ip, unsigned port); + +/* + * Read a received packet, also return sender's ip and port. + */ +int udp_read_packet (udp_t *u, uint8_t *buf, unsigned len, uint8_t *ip, unsigned *port); + +#endif diff --git a/include/wiznet/w5100.h b/include/wiznet/w5100.h new file mode 100644 index 0000000..edd958e --- /dev/null +++ b/include/wiznet/w5100.h @@ -0,0 +1,262 @@ +/* + * Copyright (c) 2010 by Cristian Maglie + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of either the GNU General Public License version 2 + * or the GNU Lesser General Public License version 2.1, both as + * published by the Free Software Foundation. + * + * Updated August/3/2011 by Lowell Scott Hanson to be compatable with chipKIT boards + * Updated April/13/2012 by Serge Vakulenko for RetroBSD project + */ +#ifndef W5100_H_INCLUDED +#define W5100_H_INCLUDED + +#include + +#define MAX_SOCK_NUM 4 + +/* + * Common Mode Register. + */ +#define MR_IND 0x01 /* Indirect bus interface mode */ +#define MR_AI 0x02 /* Address auto-increment for indirect mode */ +#define MR_PPPoE 0x08 /* PPPoE mode */ +#define MR_PB 0x10 /* Ping block mode */ +#define MR_RST 0x80 /* Software reset */ + +/* + * Socket Mode Register. + */ +#define SnMR_CLOSE 0x00 +#define SnMR_TCP 0x01 +#define SnMR_UDP 0x02 +#define SnMR_IPRAW 0x03 +#define SnMR_MACRAW 0x04 +#define SnMR_PPPOE 0x05 +#define SnMR_ND 0x20 /* No delayed ACK */ +#define SnMR_MULTI 0x80 /* Enable multicasting */ + +/* + * Socket Command Register. + */ +#define Sock_OPEN 0x01 +#define Sock_LISTEN 0x02 +#define Sock_CONNECT 0x04 +#define Sock_DISCON 0x08 +#define Sock_CLOSE 0x10 +#define Sock_SEND 0x20 +#define Sock_SEND_MAC 0x21 +#define Sock_SEND_KEEP 0x22 +#define Sock_RECV 0x40 + +/* + * Socket Interrupt Register. + */ +#define SnIR_SEND_OK 0x10 +#define SnIR_TIMEOUT 0x08 +#define SnIR_RECV 0x04 +#define SnIR_DISCON 0x02 +#define SnIR_CON 0x01 + +/* + * Socket Status Register. + */ +#define SnSR_CLOSED 0x00 +#define SnSR_INIT 0x13 +#define SnSR_LISTEN 0x14 +#define SnSR_SYNSENT 0x15 +#define SnSR_SYNRECV 0x16 +#define SnSR_ESTABLISHED 0x17 +#define SnSR_FIN_WAIT 0x18 +#define SnSR_CLOSING 0x1A +#define SnSR_TIME_WAIT 0x1B +#define SnSR_CLOSE_WAIT 0x1C +#define SnSR_LAST_ACK 0x1D +#define SnSR_UDP 0x22 +#define SnSR_IPRAW 0x32 +#define SnSR_MACRAW 0x42 +#define SnSR_PPPOE 0x5F + +#define TXBUF_SIZE 2048 // Max Tx buffer size +#define RXBUF_SIZE 2048 // Max Rx buffer size + +#define CH_BASE 0x0400 +#define CH_SIZE 0x0100 + +/*---------------------------------------------- + * W5100 Registers + */ +unsigned w5100_write_byte (unsigned addr, int byte); +unsigned w5100_write (unsigned addr, const uint8_t *buf, unsigned len); +unsigned w5100_read_byte (unsigned addr); +unsigned w5100_read (unsigned addr, uint8_t *buf, unsigned len); + +#define __GP_REGISTER8(name, address) \ + static inline void w5100_write##name (unsigned data) { \ + w5100_write_byte (address, data); \ + } \ + static inline unsigned w5100_read##name() { \ + return w5100_read_byte (address); \ + } +#define __GP_REGISTER16(name, address) \ + static inline void w5100_write##name(unsigned data) { \ + w5100_write_byte (address, data >> 8); \ + w5100_write_byte (address+1, data & 0xFF); \ + } \ + static inline unsigned w5100_read##name() { \ + unsigned res = w5100_read_byte (address); \ + res = (res << 8) + w5100_read_byte (address + 1); \ + return res; \ + } +#define __GP_REGISTER_N(name, address, size) \ + static inline unsigned w5100_write##name(uint8_t *buff) { \ + return w5100_write(address, buff, size); \ + } \ + static inline unsigned w5100_read##name(uint8_t *buff) { \ + return w5100_read(address, buff, size); \ + } + +__GP_REGISTER8 (MR, 0x0000); // Mode +__GP_REGISTER_N(GAR, 0x0001, 4); // Gateway IP address +__GP_REGISTER_N(SUBR, 0x0005, 4); // Subnet mask address +__GP_REGISTER_N(SHAR, 0x0009, 6); // Source MAC address +__GP_REGISTER_N(SIPR, 0x000F, 4); // Source IP address +__GP_REGISTER8 (IR, 0x0015); // Interrupt +__GP_REGISTER8 (IMR, 0x0016); // Interrupt Mask +__GP_REGISTER16(RTR, 0x0017); // Timeout address +__GP_REGISTER8 (RCR, 0x0019); // Retry count +__GP_REGISTER8 (RMSR, 0x001A); // Receive memory size +__GP_REGISTER8 (TMSR, 0x001B); // Transmit memory size +__GP_REGISTER8 (PATR, 0x001C); // Authentication type address in PPPoE mode +__GP_REGISTER8 (PTIMER, 0x0028); // PPP LCP Request Timer +__GP_REGISTER8 (PMAGIC, 0x0029); // PPP LCP Magic Number +__GP_REGISTER_N(UIPR, 0x002A, 4); // Unreachable IP address in UDP mode +__GP_REGISTER16(UPORT, 0x002E); // Unreachable Port address in UDP mode + +#undef __GP_REGISTER8 +#undef __GP_REGISTER16 +#undef __GP_REGISTER_N + +/*---------------------------------------------- + * W5100 Socket registers + */ +static inline unsigned +w5100_readSn_byte (unsigned sock, unsigned addr) +{ + return w5100_read_byte (CH_BASE + sock*CH_SIZE + addr); +} + +static inline unsigned +w5100_writeSn_byte (unsigned sock, unsigned addr, unsigned data) +{ + return w5100_write_byte (CH_BASE + sock*CH_SIZE + addr, data); +} + +static inline unsigned +w5100_readSn (unsigned sock, unsigned addr, uint8_t *buf, unsigned len) +{ + return w5100_read (CH_BASE + sock*CH_SIZE + addr, buf, len); +} + +static inline unsigned +w5100_writeSn (unsigned sock, unsigned addr, uint8_t *buf, unsigned len) +{ + return w5100_write (CH_BASE + sock*CH_SIZE + addr, buf, len); +} + +#define __SOCKET_REGISTER8(name, address) \ + static inline void w5100_write##name (unsigned sock, unsigned data) { \ + w5100_writeSn_byte (sock, address, data); \ + } \ + static inline unsigned w5100_read##name (unsigned sock) { \ + return w5100_readSn_byte (sock, address); \ + } +#define __SOCKET_REGISTER16(name, address) \ + static inline void w5100_write##name (unsigned sock, unsigned data) { \ + w5100_writeSn_byte (sock, address, data >> 8); \ + w5100_writeSn_byte (sock, address+1, data & 0xFF); \ + } \ + static inline unsigned w5100_read##name (unsigned sock) { \ + unsigned res = w5100_readSn_byte (sock, address); \ + res = (res << 8) + w5100_readSn_byte (sock, address + 1); \ + return res; \ + } +#define __SOCKET_REGISTER_N(name, address, size) \ + static inline unsigned w5100_write##name (unsigned sock, uint8_t *buf) { \ + return w5100_writeSn (sock, address, buf, size); \ + } \ + static inline unsigned read##name (unsigned sock, uint8_t *buf) { \ + return w5100_readSn (sock, address, buf, size); \ + } + +__SOCKET_REGISTER8(SnMR, 0x0000) // Mode +__SOCKET_REGISTER8(SnCR, 0x0001) // Command +__SOCKET_REGISTER8(SnIR, 0x0002) // Interrupt +__SOCKET_REGISTER8(SnSR, 0x0003) // Status +__SOCKET_REGISTER16(SnPORT, 0x0004) // Source Port +__SOCKET_REGISTER_N(SnDHAR, 0x0006, 6) // Destination Hardw Addr +__SOCKET_REGISTER_N(SnDIPR, 0x000C, 4) // Destination IP Addr +__SOCKET_REGISTER16(SnDPORT, 0x0010) // Destination Port +__SOCKET_REGISTER16(SnMSSR, 0x0012) // Max Segment Size +__SOCKET_REGISTER8(SnPROTO, 0x0014) // Protocol in IP RAW Mode +__SOCKET_REGISTER8(SnTOS, 0x0015) // IP TOS +__SOCKET_REGISTER8(SnTTL, 0x0016) // IP TTL +__SOCKET_REGISTER16(SnTX_FSR, 0x0020) // TX Free Size +__SOCKET_REGISTER16(SnTX_RD, 0x0022) // TX Read Pointer +__SOCKET_REGISTER16(SnTX_WR, 0x0024) // TX Write Pointer +__SOCKET_REGISTER16(SnRX_RSR, 0x0026) // RX Free Size +__SOCKET_REGISTER16(SnRX_RD, 0x0028) // RX Read Pointer +__SOCKET_REGISTER16(SnRX_WR, 0x002A) // RX Write Pointer (supported?) + +#undef __SOCKET_REGISTER8 +#undef __SOCKET_REGISTER16 +#undef __SOCKET_REGISTER_N + +/*---------------------------------------------- + * W5100 functions + */ +void w5100_init(); + +/* + * This function is being used for copy the data form Receive buffer + * of the chip to application buffer. + * + * It calculate the actual physical address where one has to read + * the data from Receive buffer. Here also take care of the condition + * while it exceed the Rx memory uper-bound of socket. + */ +void w5100_read_data (unsigned sock, unsigned src, uint8_t *dst, unsigned len); + +/* + * This function is being called by send() and sendto() function also. + * + * This function read the Tx write pointer register and after copy the data + * in buffer update the Tx write pointer register. + */ +void w5100_send_chunk (unsigned sock, const uint8_t *data, unsigned len); + +/* + * This function is being called by recv() also. + * + * This function read the Rx read pointer register and after copy + * the data from receive buffer update the Rx write pointer register. + */ +void w5100_recv_chunk (unsigned sock, uint8_t *data, unsigned len); + +unsigned w5100_recv_peek (unsigned sock); + +void w5100_socket_cmd (unsigned sock, int cmd); + +unsigned w5100_getTXFreeSize (unsigned sock); +unsigned w5100_getRXReceivedSize (unsigned sock); + +/* + * Debug output. + */ +//#define W5100_DEBUG printf +#ifndef W5100_DEBUG +# define W5100_DEBUG(...) /* empty */ +#endif + +#endif diff --git a/lib/Makefile b/lib/Makefile new file mode 100644 index 0000000..e821099 --- /dev/null +++ b/lib/Makefile @@ -0,0 +1,65 @@ +TOPSRC = $(shell cd ..; pwd) +SUBDIR = startup libc libcurses libtermlib libwiznet +PROG = ar as aout ld nm ranlib size strip + +# Build a list of the host include directories. +CPP = $(shell gcc -print-prog-name=cc1) +HOSTINC = $(addprefix -I,$(shell echo | $(CPP) -v 2>&1 | grep '^ /.*include')) + +# Add system include path +ifeq (,$(wildcard /usr/include/i386-linux-gnu)) + HOSTINC += -I/usr/include +else + HOSTINC += -I/usr/include/i386-linux-gnu +endif + +CFLAGS += -nostdinc -fno-builtin -g -Werror -Wall -DCROSS -I. $(HOSTINC) \ + -I$(TOPSRC)/include -I$(TOPSRC)/src/cmd/ar \ + -I$(TOPSRC)/src/cmd/as +LDFLAGS += -g + +AR_OBJS = ar.o append.o archive.o contents.o delete.o extract.o \ + misc.o move.o print.o replace.o strmode.o +AOUT_OBJS = aout.o mips-dis.o +RANLIB_OBJS = ranlib.o archive.o +HEADERS = a.out.h ar.h nlist.h ranlib.h + +vpath %.c $(TOPSRC)/src/cmd/ar $(TOPSRC)/src/cmd/as $(TOPSRC)/src/cmd/ld \ + $(TOPSRC)/src/cmd/nm $(TOPSRC)/src/cmd/ranlib $(TOPSRC)/src/cmd + +all install depend: $(HEADERS) $(SUBDIR) $(PROG) + -for i in $(SUBDIR); do $(MAKE) -C $$i $(MFLAGS) DESTDIR=$(DESTDIR) $@; done + +clean: + rm -f *~ *.o *.a *.h $(PROG) retroImage gccdump.s + for i in $(SUBDIR); do $(MAKE) -C $$i $(MFLAGS) clean; done + +ar: $(AR_OBJS) + $(CC) $(LDFLAGS) -o $@ $(AR_OBJS) $(LIBS) + +as: as.o + $(CC) $(LDFLAGS) -o $@ $< $(LIBS) + +aout: $(AOUT_OBJS) + $(CC) $(LDFLAGS) -o $@ $(AOUT_OBJS) $(LIBS) + +ld: ld.o + $(CC) $(LDFLAGS) -o $@ $< $(LIBS) + +nm: nm.o + $(CC) $(LDFLAGS) -o $@ $< $(LIBS) + +ranlib: $(RANLIB_OBJS) + $(CC) $(LDFLAGS) -o $@ $(RANLIB_OBJS) $(LIBS) + +size: size.o + $(CC) $(LDFLAGS) -o $@ $< $(LIBS) + +strip: strip.o + $(CC) $(LDFLAGS) -o $@ $< $(LIBS) + +$(HEADERS): + -ln -s -f ../include/a.out.h . + -ln -s -f ../include/ar.h . + -ln -s -f ../include/nlist.h . + -ln -s -f ../include/ranlib.h . diff --git a/lib/libc/Makefile b/lib/libc/Makefile new file mode 100644 index 0000000..d01b709 --- /dev/null +++ b/lib/libc/Makefile @@ -0,0 +1,111 @@ +TOPSRC = $(shell cd ../..; pwd) +include $(TOPSRC)/target.mk + +LIBCDIR = $(TOPSRC)/src/libc +vpath %.S $(LIBCDIR)/mips/sys $(LIBCDIR)/mips/string $(LIBCDIR)/mips/gen \ + $(LIBCDIR)/runtime +vpath %.c $(LIBCDIR)/mips/sys $(LIBCDIR)/gen $(LIBCDIR)/stdio \ + $(LIBCDIR)/stdlib $(LIBCDIR)/string $(LIBCDIR)/inet \ + $(LIBCDIR)/compat $(LIBCDIR)/runtime + +CFLAGS += -B$(TOPSRC)/lib/ $(DEFS) -Wa,-x -Wall -Werror +ASFLAGS += -B$(TOPSRC)/lib/ $(DEFS) -Wa,-x -I$(LIBCDIR)/mips/sys + +# modules which can not use SYSCALL and must be assembled from sources. The +# rest of the system calls are generated with printf(1) and do not have +# source files associated with them. + +# libc/mips/sys +SYSOBJS = __sysctl.o accept.o access.o adjtime.o bind.o chdir.o \ + chflags.o chmod.o chown.o chroot.o close.o connect.o dup.o \ + dup2.o execve.o fchdir.o fchflags.o fchmod.o fchown.o \ + fcntl.o flock.o fork.o fstat.o fsync.o ftruncate.o \ + getdtablesize.o getgroups.o getitimer.o getsockname.o \ + getpeername.o getpriority.o getrlimit.o getrusage.o \ + getsockopt.o gettimeofday.o ioctl.o kill.o killpg.o link.o \ + listen.o lstat.o mkdir.o mknod.o mount.o open.o pselect.o \ + quota.o read.o readlink.o readv.o reboot.o recv.o \ + recvfrom.o recvmsg.o rename.o rmdir.o select.o send.o \ + sendmsg.o sendto.o setgroups.o setitimer.o setpgrp.o \ + setpriority.o setquota.o setuid.o seteuid.o setgid.o \ + setegid.o setrlimit.o setsockopt.o settimeofday.o \ + shutdown.o sigaltstack.o socket.o socketpair.o stat.o \ + symlink.o sigprocmask.o sigstack.o sigwait.o statfs.o \ + fstatfs.o getfsstat.o truncate.o umount.o unlink.o \ + utimes.o wait4.o write.o writev.o lseek.o sigsuspend.o \ + getgid.o getegid.o getpgrp.o getpid.o getppid.o getuid.o \ + geteuid.o profil.o sigpending.o sync.o ufetch.o ustore.o \ + ucall.o umask.o vfork.o vhangup.o rdglob.o wrglob.o + +OBJS = $(SYSOBJS) sbrk.o execl.o execle.o execv.o \ + _exit.o _brk.o pipe.o ptrace.o sigaction.o + +# libc/mips/string +ASFLAGS += -DLWHI=lwr -DLWLO=lwl -DSWHI=swr -DSWLO=swl +OBJS += bcopy.o bzero.o ffs.o memcpy.o memmove.o memset.o \ + strlen.o bcmp.o index.o rindex.o strcmp.o + +# libc/mips/gen +OBJS += _setjmp.o htonl.o htons.o + +# libc/gen +OBJS += abort.o alarm.o atof.o atoi.o atol.o calloc.o closedir.o crypt.o \ + ctime.o ctype_.o daemon.o devname.o ecvt.o err.o \ + execvp.o fakcu.o frexp.o fstab.o gcvt.o getenv.o getgrent.o \ + getgrgid.o getgrnam.o getlogin.o \ + getgrouplist.o gethostname.o getpagesize.o \ + getpass.o getpwent.o getloadavg.o getmntinfo.o \ + getttyent.o getttynam.o getusershell.o getwd.o \ + initgroups.o isatty.o isinff.o isnanf.o ldexp.o malloc.o mktemp.o \ + modff.o ndbm.o nlist.o knlist.o opendir.o perror.o popen.o \ + psignal.o qsort.o random.o readdir.o regex.o scandir.o \ + seekdir.o setmode.o sethostname.o setenv.o siglist.o \ + signal.o siginterrupt.o sigsetops.o \ + sleep.o strcasecmp.o strftime.o swab.o sysctl.o syslog.o system.o \ + strcat.o strncat.o strcpy.o strncpy.o strncmp.o \ + telldir.o time.o timezone.o ttyname.o ttyslot.o ualarm.o usleep.o \ + strdup.o uname.o wait.o wait3.o waitpid.o + +# libc/stdio +OBJS += fgetc.o fgets.o fputc.o fputs.o gets.o puts.o \ + clrerr.o doscan.o exit.o fdopen.o filbuf.o findiop.o \ + flsbuf.o fopen.o fprintf.o fread.o freopen.o fseek.o \ + ftell.o fwrite.o getchar.o getw.o printf.o putchar.o putw.o \ + rew.o scanf.o setbuf.o setbuffer.o setvbuf.o snprintf.o sprintf.o \ + strout.o ungetc.o vfprintf.o vprintf.o vsprintf.o doprnt.o \ + remove.o feof.o ferror.o fileno.o + +# libc/stdlib +OBJS += getopt.o getsubopt.o strtol.o strtoul.o strtod.o + +# libc/string +OBJS += strcspn.o strpbrk.o strerror.o strsep.o strspn.o \ + strstr.o strtok.o strtok_r.o + +# libc/inet +OBJS += inet_addr.o inet_network.o inet_netof.o \ + inet_ntoa.o inet_lnaof.o inet_maddr.o + +# libc/compat +OBJS += creat.o ftime.o gethostid.o gtty.o memccpy.o memchr.o \ + memcmp.o memcpy.o memset.o nice.o pause.o rand.o \ + sethostid.o setregid.o setreuid.o setrgid.o setruid.o \ + sigcompat.o strchr.o strrchr.o stty.o times.o tmpnam.o \ + utime.o + +# libc/runtime +OBJS += addsf3.o comparesf2.o divsf3.o fixsfsi.o floatsisf.o \ + mulsf3.o negsf2.o subsf3.o sc_case.o + +all: ../libc.a + +../libc.a: ../ar ../ranlib $(OBJS) + ../ar rc $@ $(OBJS) + ../ranlib $@ + +$(SYSOBJS): $(LIBCDIR)/mips/sys/SYS.h + @echo creating $*.o + @printf '#include "SYS.h"\nSYS($*)\n' | $(AS) $(ASFLAGS) - -c -o $*.o + +clean: + rm -f *~ *.o a.out *.a diff --git a/lib/libcurses/Makefile b/lib/libcurses/Makefile new file mode 100644 index 0000000..b2fde22 --- /dev/null +++ b/lib/libcurses/Makefile @@ -0,0 +1,22 @@ +TOPSRC = $(shell cd ../..; pwd) +include $(TOPSRC)/target.mk + +vpath %.c $(TOPSRC)/src/libcurses + +CFLAGS += -B$(TOPSRC)/lib/ $(DEFS) -Wa,-x -Wall -Werror + +OBJS = addch.o addstr.o box.o clear.o clrtobot.o clrtoeol.o cr_put.o \ + cr_tty.o curses.o delch.o deleteln.o delwin.o endwin.o erase.o \ + fullname.o getch.o getstr.o idlok.o id_subwins.o initscr.o insch.o \ + insertln.o longname.o move.o mvprintw.o mvscanw.o mvwin.o newwin.o \ + overlay.o overwrite.o printw.o putchar.o refresh.o scanw.o scroll.o \ + toucholap.o standout.o touchwin.o tstp.o unctrl.o + +all: ../libcurses.a + +../libcurses.a: ../ar ../ranlib $(OBJS) + ../ar rc $@ $(OBJS) + ../ranlib $@ + +clean: + rm -f *~ *.o a.out *.a diff --git a/lib/libtermlib/Makefile b/lib/libtermlib/Makefile new file mode 100644 index 0000000..2b3fb1a --- /dev/null +++ b/lib/libtermlib/Makefile @@ -0,0 +1,17 @@ +TOPSRC = $(shell cd ../..; pwd) +include $(TOPSRC)/target.mk + +vpath %.c $(TOPSRC)/src/libtermlib + +CFLAGS += -B$(TOPSRC)/lib/ $(DEFS) -Wa,-x -Wall -Werror + +OBJS = termcap.o tgoto.o tputs.o tcattr.o + +all: ../libtermlib.a + +../libtermlib.a: ../ar ../ranlib $(OBJS) + ../ar rc $@ $(OBJS) + ../ranlib $@ + +clean: + rm -f *~ *.o a.out *.a diff --git a/lib/libwiznet/Makefile b/lib/libwiznet/Makefile new file mode 100644 index 0000000..d7883bc --- /dev/null +++ b/lib/libwiznet/Makefile @@ -0,0 +1,17 @@ +TOPSRC = $(shell cd ../..; pwd) +include $(TOPSRC)/target.mk + +vpath %.c $(TOPSRC)/src/libwiznet + +CFLAGS += -B$(TOPSRC)/lib/ $(DEFS) -Wa,-x -Wall -Werror + +OBJS = w5100.o socket.o ethernet.o client.o server.o udp.o + +all: ../libwiznet.a + +../libwiznet.a: ../ar ../ranlib $(OBJS) + ../ar rc $@ $(OBJS) + ../ranlib $@ + +clean: + rm -f *~ *.o a.out *.a diff --git a/lib/startup/Makefile b/lib/startup/Makefile new file mode 100644 index 0000000..a4e47a6 --- /dev/null +++ b/lib/startup/Makefile @@ -0,0 +1,22 @@ +# +# Copyright (c) 1987 Regents of the University of California. +# All rights reserved. The Berkeley software License Agreement +# specifies the terms and conditions for redistribution. +# +# crt0 Normal C run time startoff +# +TOPSRC = $(shell cd ../..; pwd) +include $(TOPSRC)/target.mk +vpath %.c $(TOPSRC)/src/startup-mips + +CFLAGS = -B$(TOPSRC)/lib/ -O -Wa,-x $(DEFS) + +OBJS = ../crt0.o + +all: $(OBJS) + +../crt0.o: crt0.c + $(CC) $(DEFS) $(CFLAGS) -c $< -o $@ + +clean: + rm -f $(OBJS) *~ diff --git a/share/example/Makefile b/share/example/Makefile new file mode 100644 index 0000000..97b9a6d --- /dev/null +++ b/share/example/Makefile @@ -0,0 +1,14 @@ + +all: ashello echo + +ashello: ashello.o + $(LD) ashello.o -o $@ + +chello: chello.o + $(CC) chello.o -o $@ + +echo: echo.o + $(LD) $@.o -o $@ + +clean: + rm -f *.o ashello echo *.dis *~ diff --git a/share/example/Makefile-host b/share/example/Makefile-host new file mode 100644 index 0000000..b18e867 --- /dev/null +++ b/share/example/Makefile-host @@ -0,0 +1,30 @@ +TOPSRC = $(shell cd ../..; pwd) +include $(TOPSRC)/target.mk + +CFLAGS += -Werror +ASFLAGS += -DCROSS +ASLDFLAGS = --oformat=elf32-tradlittlemips -N -nostartfiles -T $(TOPSRC)/src/elf32-mips.ld + +all: hello cplus + +hello: hello.o + ${CC} ${LDFLAGS} -o hello.elf hello.o ${LIBS} + ${OBJDUMP} -S hello.elf > hello.dis + ${SIZE} hello.elf + ${ELF2AOUT} hello.elf $@ + +cplus: cplus.o + ${CXX} ${LDFLAGS} -nostdlib -o cplus.elf cplus.o ${LIBS} + ${OBJDUMP} -S cplus.elf > cplus.dis + ${SIZE} cplus.elf + ${ELF2AOUT} cplus.elf $@ + +echo: echo.o + ${LD} ${ASLDFLAGS} -o $@.elf $@.o + ${OBJDUMP} -S $@.elf > $@.dis + ${SIZE} $@.elf + ${ELF2AOUT} $@.elf $@ + ./aout $@ > $@.dis + +clean: + rm -f *.o *.elf ${MAN} hello cplus *.elf *.dis tags *~ diff --git a/share/example/ashello.S b/share/example/ashello.S new file mode 100644 index 0000000..51c2e58 --- /dev/null +++ b/share/example/ashello.S @@ -0,0 +1,25 @@ +/* + * This is an example of MIPS assembly program for RetroBSD. + * + * To compile this program, type: + * cc -c ashello.S + * ld ashello.o -o ashello + */ +#include + + .data // begin data segment +hello: .ascii "Hello, assembly world!\n" // a string + + .text // begin code segment + .globl start // entry point for ld +start: + li $a0, 0 // arg 1: stdout fd + la $a1, hello // arg 2: string address + li $a2, 23 // arg 3: string length + syscall SYS_write // call the kernel: write() + nop // returns here on error + nop // skips two words on success + + li $a0, 0 // arg 1: exit status + syscall SYS_exit // call the kernel: exit() + // no return diff --git a/share/example/blkjack.bas b/share/example/blkjack.bas new file mode 100644 index 0000000..489dd0a --- /dev/null +++ b/share/example/blkjack.bas @@ -0,0 +1,61 @@ +10 rem ************************************** +20 rem *** Play the "blackjack" (21) game *** +30 rem ************************************** +40 dim C(52): m = 1000 +50 rem +60 rem Create deck of cards and shuffle it +70 rem +80 for i=0 to 51: c(i) = i: next i +90 for i=0 to 51: i1=rnd(52): i2=c(i): c(i)=c(i2): c(i2)=i1: next i +100 rem +110 rem Prompt for amount of bet (on this game) +120 rem +130 print "You have", m, " dollars" +140 input "How much do you wish to bet?", b: if b=0 then stop +150 lif b>m then print "You don't have enough money":goto 140 +160 t = 0: d = 0 +170 rem +180 rem Prompt PLAYER for another card +190 rem +200 print "Total:", t,:Input " Another card (Y/N)?", a$ +210 if a$="n" then 380 +220 lif a$<>"y" then print "Please answer y-Yes or n-No":goto 200 +230 c = c(d): d = d + 1: gosub 530 +240 c = c % 13: if c > 9 then c = 9 +250 if c > 0 then 300 +260 input "(1)one or (t)ten ?", a$ +270 if a$="1" then 300 +280 if a$<>"t" then 260 +290 c = 9 +300 t = t + c + 1 +310 if t <= 21 then 200 +320 print "You went over 21! - you LOSE!" +330 m = m - b: if m > 0 then 80 +340 print "You went BUST!":end +350 rem +360 rem Play DEALER +370 rem +380 t1 = 0 +390 c = c(d): d = d + 1: print "Dealer draws ",: gosub 530 +400 c = c % 13: if c > 9 then c = 9 +410 if c > 0 then 470 +420 if t1 < 10 then 450 +430 if (t1+10) > 23 then 460 +440 if (t1+10) >= t then 450 +450 c = 9 +460 print "Dealer chooses", c+1 +470 t1 = t1 + c + 1: print "Dealer totals", t1: if t1 < t then 390 +480 lif t1 <= 21 then print "Dealer wins - You LOSE!": goto 330 +490 print "Dealer loses - You WIN!!!": m = m + b: goto 80 +500 rem +510 rem Subroutine to display text description of a card +520 rem +530 order 590 +540 for a = 0 to c / 13: read a$: next a +550 order 600 +560 for a = 0 to c % 13: read a1$:next a +570 print a1$, " of ", a$ +580 return +590 data "Hearts", "Diamonds", "Clubs", "Spades" +600 data "Ace", "Two", "Three", "Four", "Five", "Six", "Seven" +610 data "Eight", "Nine", "Ten", "Jack", "Queen", "King" diff --git a/share/example/chello.c b/share/example/chello.c new file mode 100644 index 0000000..14d9b7d --- /dev/null +++ b/share/example/chello.c @@ -0,0 +1,7 @@ +#include + +int main() +{ + printf ("Hello, C World!\n"); + return 0; +} diff --git a/share/example/cplus.cpp b/share/example/cplus.cpp new file mode 100644 index 0000000..272c9f8 --- /dev/null +++ b/share/example/cplus.cpp @@ -0,0 +1,11 @@ +extern "C" { + #include + #include +}; + +int main() +{ + const char *message = "Hello, C++ World!\n"; + write (1, message, strlen (message)); + return 0; +} diff --git a/share/example/echo.S b/share/example/echo.S new file mode 100644 index 0000000..12087a0 --- /dev/null +++ b/share/example/echo.S @@ -0,0 +1,67 @@ +/* + * This is a standard /bin/echo utility, rewritten in MIPS assembler. + * + * To compile this program, type: + * cc -c echo.S + * ld echo.o -o echo + * + * Run as: + * ./echo Make love not war + */ +#include + + .data // begin data segment +eoln: .ascii "\n" +space: .ascii " " + + .text // begin code segment +start: .globl start // entry point for ld + + // + // Program gets three arguments: + // argc in $a0 - number of words in command line + // argv in $a1 - address of list of pointers to words + // env in $a2 - address of list of pointers to environment variables + // + addi $s0, $a0, -1 // argc - 1 + beq $s0, $zero, done // if (argc == 0) goto gone + addi $s1, $a1, 4 // argv + 4 +loop: + jal print // print string + lw $a0, 0($s1) // arg 1: *argv + + addi $s0, $s0, -1 // --argc + la $a1, eoln // arg2: newline + beq $s0, $zero, last // if (argc == 0) goto last + li $a0, 1 // arg1: stdout + la $a1, space // arg2: space +last: + li $a2, 1 // arg3: length + syscall SYS_write // call the kernel: write() + nop // ignore errors + nop + + bne $s0, $zero, loop // if (argc == 0) goto gone + addi $s1, $s1, 4 // ++argv +done: + li $a0, 0 // arg1: exit status + syscall SYS_exit // call the kernel: exit() + // no return + +print: move $a1, $a0 // arg2: string + + addi $a2, $a0, 1 // compute length +strlen: + lb $v0, 0($a0) // get byte from string + bne $v0, $zero, strlen // continue if not end + addi $a0, $a0, 1 // increment pointer + + subu $a2, $a0, $a2 // arg3: length + + li $a0, 1 // arg1: stdout + syscall SYS_write // call the kernel: write() + nop // ignore errors + nop + + jr $ra + nop diff --git a/share/example/fact.fth b/share/example/fact.fth new file mode 100644 index 0000000..5e4869b --- /dev/null +++ b/share/example/fact.fth @@ -0,0 +1,23 @@ +\ Iterative factorial function. + +." Defining fact function ... " +: fact ( n -- n! ) + dup 2 < if drop 1 else + dup begin 1- swap over * swap dup 1 = until + drop then +; ." done." cr + +." 1! = " 1 fact . cr +." 2! = " 2 fact . cr +." 3! = " 3 fact . cr +." 4! = " 4 fact . cr +." 5! = " 5 fact . cr +." 6! = " 6 fact . cr +." 7! = " 7 fact . cr +." 8! = " 8 fact . cr +." 9! = " 9 fact . cr +." 10! = " 10 fact . cr +." 11! = " 11 fact . cr +." 12! = " 12 fact . cr + +halt diff --git a/share/example/hilow.bas b/share/example/hilow.bas new file mode 100644 index 0000000..6e721b5 --- /dev/null +++ b/share/example/hilow.bas @@ -0,0 +1,13 @@ +10 rem **************************** +20 rem *** Play the HI/LOW game *** +30 rem **************************** +40 n = rnd(100) +50 c = 0 +60 input "Guess a number? ", g +70 c = c+1 +80 if g=n then 120 +90 if g>n then print "lower" +100 if g (square test-divisor) n) n) + ((divides? test-divisor n) test-divisor) + (else (find-divisor n (+ test-divisor 1))))) + +(define (smallest-divisor n) + (find-divisor n 2)) + +(define (prime? n) + (= n (smallest-divisor n))) + +(define (t n) + (display n) + (if (prime? n) + (display '-prime) + (display '-compound)) + (newline)) + +(t 2) +(t 20) +(t 23) +(t 65) +(t 67) +(t 2011) diff --git a/share/example/stars.bas b/share/example/stars.bas new file mode 100644 index 0000000..c2ff2bb --- /dev/null +++ b/share/example/stars.bas @@ -0,0 +1,14 @@ +10 INPUT "Your name: ", U$ +20 PRINT "Hello ", U$ +30 INPUT "How many stars do you want: ", N +40 S$ = "" +50 FOR I = 1 TO N +60 S$ = S$ + "*" +70 NEXT I +80 PRINT S$ +90 INPUT "Do you want more stars? ", A$ +100 IF A$ = "" THEN GOTO 90 +110 IF A$ = "Y" THEN GOTO 30 +120 IF A$ = "y" THEN GOTO 30 +130 PRINT "Goodbye ", U$ +140 END diff --git a/share/smallc/Makefile b/share/smallc/Makefile new file mode 100644 index 0000000..8c17d23 --- /dev/null +++ b/share/smallc/Makefile @@ -0,0 +1,41 @@ +CC = scc +PROG = hello primelist primesum test1 test2 test3 gpio adc rain \ + webserver q8 + +all: $(PROG) + +hello: hello.c + $(CC) $(CFLAGS) -o $@ $(LDFLAGS) hello.c + +primelist: primelist.c + $(CC) $(CFLAGS) -o $@ $(LDFLAGS) primelist.c + +primesum: primesum.c + $(CC) $(CFLAGS) -o $@ $(LDFLAGS) primesum.c + +webserver: webserver.c + $(CC) $(CFLAGS) -o $@ $(LDFLAGS) webserver.c -lwiznet + +gpio: gpio.c + $(CC) $(CFLAGS) -o $@ $(LDFLAGS) gpio.c + +adc: adc.c + $(CC) $(CFLAGS) -o $@ $(LDFLAGS) adc.c + +rain: rain.c + $(CC) $(CFLAGS) -o $@ $(LDFLAGS) rain.c + +q8: q8.c + $(CC) $(CFLAGS) -o $@ $(LDFLAGS) q8.c + +test1: test1.c + $(CC) $(CFLAGS) -o $@ $(LDFLAGS) test1.c + +test2: test2.c + $(CC) $(CFLAGS) -o $@ $(LDFLAGS) test2.c + +test3: test3.c + $(CC) $(CFLAGS) -o $@ $(LDFLAGS) test3.c + +clean: + rm -f *.o $(PROG) diff --git a/share/smallc/adc.c b/share/smallc/adc.c new file mode 100644 index 0000000..79a11e0 --- /dev/null +++ b/share/smallc/adc.c @@ -0,0 +1,26 @@ +/* + * Example of reading ADC data. + */ +#include + +char buf[100]; + +main() +{ + int i, fd, value; + + for (i=0; i<16; i++) { + sprintf(buf, "/dev/adc%d", i); + fd = open(buf, O_RDWR); + if (fd < 0) { + printf("Error: unable to open %s\n", buf); + } else { + if (read(fd, buf, 20) > 0) { + value = strtol (buf, 0, 0); + printf("adc%-2d = %d\n", i, value); + } + close(fd); + } + } + return 0; +} diff --git a/share/smallc/gpio.c b/share/smallc/gpio.c new file mode 100644 index 0000000..fd667e1 --- /dev/null +++ b/share/smallc/gpio.c @@ -0,0 +1,24 @@ +/* + * Example of polling general purpose i/o pins. + */ +#include +#include + +main () +{ + int fd, pnum, value; + + fd = open ("/dev/porta", O_RDWR); + if (fd < 0) { + perror ("/dev/porta"); + return -1; + } + + for (pnum=0; pnum<7; pnum++) { + value = ioctl (fd, GPIO_POLL | GPIO_PORT (pnum), 0); + if (value < 0) + perror ("GPIO_POLL"); + printf ("port%c = 0x%04x\n", pnum + 'A', value); + } + return 0; +} diff --git a/share/smallc/hello.c b/share/smallc/hello.c new file mode 100644 index 0000000..7df6764 --- /dev/null +++ b/share/smallc/hello.c @@ -0,0 +1,6 @@ +extern int printf(); + +int main() +{ + printf ("Hello, SmallC World!\n"); +} diff --git a/share/smallc/primelist.c b/share/smallc/primelist.c new file mode 100644 index 0000000..3df189f --- /dev/null +++ b/share/smallc/primelist.c @@ -0,0 +1,31 @@ +/* + * Print the list of prime numbers up to 100. + */ +main() +{ + int n; + + for (n=2; n<100; ++n) { + if (isprime(n)) { + printf("%d ", n); + } + } + printf("\n"); +} + +isprime(n) + int n; +{ + int j; + + if (n == 2) + return 1; + + if (n % 2 == 0) + return 0; + + for (j=3; j*j<=n; j+=2) + if (n % j == 0) + return 0; + return 1; +} diff --git a/share/smallc/primesum.c b/share/smallc/primesum.c new file mode 100644 index 0000000..81acb3e --- /dev/null +++ b/share/smallc/primesum.c @@ -0,0 +1,32 @@ +/* + * Compute the sum of prime numbers up to 10000. + */ +main() +{ + int sum, n; + + sum = 0; + for (n=2; n<10000; ++n) { + if (isprime(n)) { + sum += n; + } + } + printf("Sum of primes less than 10000: %d\n", sum); +} + +isprime(n) + int n; +{ + int j; + + if (n == 2) + return 1; + + if (n % 2 == 0) + return 0; + + for (j=3; j*j<=n; j+=2) + if (n % j == 0) + return 0; + return 1; +} diff --git a/share/smallc/q8.c b/share/smallc/q8.c new file mode 100644 index 0000000..e4f90e2 --- /dev/null +++ b/share/smallc/q8.c @@ -0,0 +1,208 @@ +/* + * Eight Queens puzzle + * + * (C) 2010 by Mark Sproul + * Open source as per standard Arduino code + * Modified by Pito 12/2012 for SmallC + */ +#define TRUE 1 +#define FALSE 0 + +unsigned int gChessBoard[8]; +unsigned int gLoopCounter; +int gValidCount; + +CheckCurrentBoard() +{ + int ii; + int jj; + int theRow; + int theLongRow; + int theLongColumns; + int bitCount; + + //* we know we have 1 in each row, + //* Check for 1 in each column + theRow = 0; + for (ii=0; ii<8; ii++) { + theRow |= gChessBoard[ii]; + } + if (theRow != 0x0ff) { + return FALSE; + } + + //* we have 1 in each column, now check the diagonals + theLongColumns = 0; + for (ii=0; ii<8; ii++) { + theLongRow = gChessBoard[ii] & 0x0ff; + theLongRow = theLongRow << ii; + + theLongColumns |= theLongRow; + } + + //* now count the bits + bitCount = 0; + for (ii=0; ii<16; ii++) { + if ((theLongColumns & 0x01) == 0x01) { + bitCount++; + } + theLongColumns = theLongColumns >> 1; + } + + if (bitCount != 8) { + return FALSE; + } + + //* we now have to check the other diagonal + theLongColumns = 0; + for (ii=0; ii<8; ii++) { + theLongRow = gChessBoard[ii] & 0x0ff; + theLongRow = theLongRow << 8; + theLongRow = theLongRow >> ii; + + theLongColumns |= theLongRow; + } + + //* now count the bits + bitCount = 0; + for (ii=0; ii<16; ii++) { + if ((theLongColumns & 0x01) == 0x01) { + bitCount++; + } + theLongColumns = theLongColumns >> 1; + } + + if (bitCount != 8) { + return FALSE; + } + return TRUE; +} + +CheckForDone() +{ + int ii; + int weAreDone; + int theRow; + + weAreDone = FALSE; + + //* we know we have 1 in each row, + //* Check for 1 in each column + theRow = 0; + for (ii=0; ii<8; ii++) { + theRow |= gChessBoard[ii]; + } + + if (theRow == 0x01) { + weAreDone = TRUE; + } + return weAreDone; +} + +RotateQueens() +{ + int ii; + int keepGoing; + int theRow; + + ii = 0; + keepGoing = TRUE; + while (keepGoing && (ii < 8)) { + theRow = gChessBoard[ii] & 0x0ff; + theRow = (theRow >> 1) & 0x0ff; + if (theRow != 0) { + gChessBoard[ii] = theRow; + keepGoing = FALSE; + } else { + gChessBoard[ii] = 0x080; + } + ii++; + } +} + +PrintChessBoard() +{ + int ii; + int jj; + int theRow; + char textString[32]; + + printf("\nLoop= %d\n", gLoopCounter); + printf("Solution count= %d\n", gValidCount); + + printf("+----------------+\n"); + for (ii=0; ii<8; ii++) { + theRow = gChessBoard[ii]; + + printf("|"); + for (jj=0; jj<8; jj++) { + if (theRow & 0x080) { + printf("Q "); + } else { + printf(". "); + } + theRow = theRow << 1; + } + printf("|\n"); + } + printf("+----------------+\n"); +} + +main() +{ + int ii; + + printf("\nEight Queens brute force"); + printf("\n************************\n"); + //* put the 8 queens on the board, 1 in each row + for (ii=0; ii<8; ii++) { + gChessBoard[ii] = 0x080; + } + PrintChessBoard(); + + gLoopCounter = 0; + gValidCount = 0; + + + while (1) { + gLoopCounter++; + + if (CheckCurrentBoard()) { + gValidCount++; + PrintChessBoard(); + } else if ((gLoopCounter % 1000) == 0) { + //PrintChessBoard(); + } + + RotateQueens(); + if (CheckForDone()) { + //int elapsedSeconds; + //int elapsedMinutes; + //int elapsedHours; + + //elapsedSeconds = millis() / 1000; + //elapsedMinutes = elapsedSeconds / 60; + //elapsedHours = elapsedMinutes / 60; + + printf("----------------------------------\n"); + printf("All done\n"); + + PrintChessBoard(); + printf("----------------------------------\n"); + + //Serial.print("total seconds="); + //Serial.println(elapsedSeconds); + + //Serial.print("hours="); + //Serial.println(elapsedHours); + + //Serial.print("minutes="); + //Serial.println(elapsedMinutes % 60); + + //Serial.print("seconds="); + //Serial.println(elapsedSeconds % 60); + + return (1); + } + } +} diff --git a/share/smallc/rain.c b/share/smallc/rain.c new file mode 100644 index 0000000..d0a617d --- /dev/null +++ b/share/smallc/rain.c @@ -0,0 +1,129 @@ +/* + * Example of using termcap library for SmallC. + * 11/3/1980 EPS/CITHEP + * + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include +#include + +#define CO 80 /* number of columns */ +#define LI 24 /* number of lines */ + +#define CL "\33[H\33[J" /* clear the screen */ +#define CM "\33[%u;%uH" /* move the cursor to row, column */ +#define BC "\b" /* move cursor left */ +#define DN "\33[B" /* move cursor down */ +#define ND " " /* move cursor right */ + +int xpos[5], ypos[5]; +char outbuf[BUFSIZ]; + +moveto(col, row) + int col, row; +{ + printf(CM, row, col); +} + +onsig(n) + int n; +{ + moveto(0, LI - 1); + fflush(stdout); + _exit(0); +} + +main() +{ + int x, y, j; + + setbuf(stdout, outbuf); + for (j = SIGHUP; j <= SIGTERM; j++) + if (signal(j, SIG_IGN) != SIG_IGN) + signal(j, onsig); + + fputs(CL, stdout); + fflush(stdout); + for (j = 5; --j >= 0; ) { + xpos[j] = 2 + rand() % (CO - 4); + ypos[j] = 2 + rand() % (LI - 4); + } + for (j = 0; ; ) { + x = 2 + rand() % (CO - 4); + y = 2 + rand() % (LI - 4); + moveto(x, y); + putchar('.'); + moveto(xpos[j], ypos[j]); + putchar('o'); + if (j == 0) + j = 4; + else + --j; + moveto(xpos[j], ypos[j]); + putchar('O'); + if (j == 0) + j = 4; + else + --j; + moveto(xpos[j], ypos[j]-1); + putchar('-'); + fputs(DN, stdout); + fputs(BC, stdout); + fputs(BC, stdout); + fputs("|.|", stdout); + fputs(DN, stdout); + fputs(BC, stdout); + fputs(BC, stdout); + putchar('-'); + if (j == 0) + j = 4; + else + --j; + moveto(xpos[j], ypos[j]-2); + putchar('-'); + fputs(DN, stdout); + fputs(BC, stdout); + fputs(BC, stdout); + fputs("/ \\", stdout); + moveto(xpos[j]-2, ypos[j]); + fputs("| O |", stdout); + moveto(xpos[j]-1, ypos[j]+1); + fputs("\\ /", stdout); + fputs(DN, stdout); + fputs(BC, stdout); + fputs(BC, stdout); + putchar('-'); + if (j == 0) + j = 4; + else + --j; + moveto(xpos[j], ypos[j]-2); + putchar(' '); + fputs(DN, stdout); + fputs(BC, stdout); + fputs(BC, stdout); + putchar(' '); + fputs(ND, stdout); + putchar(' '); + moveto(xpos[j]-2, ypos[j]); + putchar(' '); + fputs(ND, stdout); + putchar(' '); + fputs(ND, stdout); + putchar(' '); + moveto(xpos[j]-1, ypos[j]+1); + putchar(' '); + fputs(ND, stdout); + putchar(' '); + fputs(DN, stdout); + fputs(BC, stdout); + fputs(BC, stdout); + putchar(' '); + xpos[j] = x; + ypos[j] = y; + fflush(stdout); + usleep(100000); + } +} diff --git a/share/smallc/test1.c b/share/smallc/test1.c new file mode 100644 index 0000000..182ec29 --- /dev/null +++ b/share/smallc/test1.c @@ -0,0 +1,219 @@ +int ga[5]; + +main() +{ + int a, b, c, d; + int arr[5]; + int *pi; + char arrc[5]; + char *pic; + int s1, s2; + int z; + int t; + int *pip; + int *picp; + int e1, e2; + + ga[0] = 10; + ga[1] = 20; + ga[2] = 30; + ga[3] = 40; + ga[4] = 50; + + a = 21; + b = 31; + c = 71; + d = 82; + + arr[0] = 10; + arr[1] = 20; + arr[2] = 30; + arr[3] = 40; + arr[4] = 50; + pi = &arr[0]; + + arrc[0] = 13; + arrc[1] = 23; + arrc[2] = 33; + arrc[3] = 43; + arrc[4] = 53; + pic = &arrc[0]; + + printf(" 21 + 31 = %d (52)\n", a + b); + printf(" 21 - 31 = %d (-10)\n", a - b); + printf(" 21 & 71 = %d (5)\n", a & c); + printf(" 21 | 82 = %d (87)\n", a | d); + printf(" 21 ^ 82 = %d (71)\n", a ^ d); + printf(" 21 * 82 = %d (1722)\n", a * d); + printf(" 82 % 21 = %d (19)\n", d % a); + printf(" 82 / 21 = %d (3)\n", d / a); + printf(" *pi = %d (10)\n", *pi); + printf(" *pi + 1 = %d (11)\n", *pi + 1); + printf(" *(pi + 1) = %d (20)\n", *(pi + 1)); + printf("&arr[3] - &arr[0] = %d (3)\n", &arr[3] - &arr[0]); + printf(" arr[3]-arr[0] = %d (30)\n", arr[3] - arr[0]); + printf(" arr[3]+arr[0] = %d (50)\n", arr[3] + arr[0]); + printf(" &ga[3] - &ga[0] = %d (3)\n", &ga[3] - &ga[0]); + printf(" ga[3]-ga[0] = %d (30)\n", ga[3] - ga[0]); + printf(" ga[3]+ga[0] = %d (50)\n", ga[3] + ga[0]); + printf("\n"); + + printf(" *pic = %d (13)\n", *pic); + printf(" *pic + 1 = %d (14)\n", *pic+1); + printf(" *(pic + 1) = %d (23)\n", *(pic+1)); + printf("&arrc[3] - &arrc[0] = %d (3)\n", &arrc[3]-&arrc[0]); + printf("\n"); + + s1 = 3; + s2 = -200; + printf(" 82 << 3 = %d (656)\n", d << s1); + printf(" 82 >> 3 = %d (10)\n", d >> s1); + printf("-200 >> 3 = %d (-25)\n", s2 >> s1); + printf("-200 << 3 = %d (-1600)\n", s2 << s1); + printf("\n"); + + printf("-s1 = %d (-3)\n", -s1); + printf("-s2 = %d (200)\n", -s2); + printf("\n"); + + printf("~82 = %d (-83)\n", ~d); + printf("\n"); + + z = 0; + printf("!82 = %d (0)\n", !d); + printf(" !0 = %d (1)\n", !z); + printf("\n"); + + printf(" 0 && 0 = %d (0)\n", z && z); + printf(" 0 && 21 = %d (0)\n", z && a); + printf(" 3 && 21 = %d (1)\n", s1 && a); + printf("21 && 3 = %d (1)\n", a && s1); + printf("\n"); + + printf(" 0 || 0 = %d (0)\n", z || z); + printf(" 0 || 21 = %d (1)\n", z || a); + printf(" 3 || 21 = %d (1)\n", s1 || a); + printf("21 || 3 = %d (1)\n", a || s1); + printf("\n"); + + pi = 4; + printf("pi++ = %d (4)\n", pi++); + printf(" pi = %d (8)\n", pi); + printf("++pi = %d (12)\n", ++pi); + printf("pi-- = %d (12)\n", pi--); + printf(" pi = %d (8)\n", pi); + printf("--pi = %d (4)\n", --pi); + printf("\n"); + + pic = 4; + printf("pic++ = %d (4)\n", pic++); + printf(" pic = %d (5)\n", pic); + printf("++pic = %d (6)\n", ++pic); + printf("pic-- = %d (6)\n", pic--); + printf(" pic = %d (5)\n", pic); + printf("--pic = %d (4)\n", --pic); + printf("\n"); + + t = 4; + printf("t++ = %d (4)\n", t++); + printf(" t = %d (5)\n", t); + printf("++t = %d (6)\n", ++t); + printf("t-- = %d (6)\n", t--); + printf(" t = %d (5)\n", t); + printf("--t = %d (4)\n", --t); + printf("\n"); + + t = 4; + printf(" t==4 = %d (1)\n", t == 4); + printf(" t==3 = %d (0)\n", t == 3); + printf(" t==5 = %d (0)\n", t == 5); + t = -4; + printf("t==-4 = %d (1)\n", t == -4); + printf("t==-3 = %d (0)\n", t == -3); + printf("t==-5 = %d (0)\n", t == -5); + printf(" t==4 = %d (0)\n", t == 4); + printf(" t==3 = %d (0)\n", t == 3); + printf(" t==5 = %d (0)\n", t == 5); + printf("\n"); + + t = 4; + printf(" t!=4 = %d (0)\n", t != 4); + printf(" t!=3 = %d (1)\n", t != 3); + printf(" t!=5 = %d (1)\n", t != 5); + t = -4; + printf("t!=-4 = %d (0)\n", t != -4); + printf("t!=-3 = %d (1)\n", t != -3); + printf("t!=-5 = %d (1)\n", t != -5); + printf(" t!=4 = %d (1)\n", t != 4); + printf(" t!=3 = %d (1)\n", t != 3); + printf(" t!=5 = %d (1)\n", t != 5); + printf("\n"); + + t = 4; + printf(" t<4 = %d (0)\n", t < 4); + printf(" t<3 = %d (0)\n", t < 3); + printf(" t<5 = %d (1)\n", t < 5); + printf("t<-1 = %d (0)\n", t < -1); + printf("\n"); + + printf(" t<=4 = %d (1)\n", t <= 4); + printf(" t<=3 = %d (0)\n", t <= 3); + printf(" t<=5 = %d (1)\n", t <= 5); + printf("t<=-1 = %d (0)\n", t <= -1); + printf("\n"); + + t = 4; + printf(" t>4 = %d (0)\n", t > 4); + printf(" t>3 = %d (1)\n", t > 3); + printf(" t>5 = %d (0)\n", t > 5); + printf("t>-1 = %d (1)\n", t > -1); + printf("\n"); + + printf(" t>=4 = %d (1)\n", t >= 4); + printf(" t>=3 = %d (1)\n", t >= 3); + printf(" t>=5 = %d (0)\n", t >= 5); + printf("t>=-1 = %d (1)\n", t >= -1); + printf("\n"); + + pi = -100; + printf(" pi<4 = %d (0)\n", pi < 4); + printf(" pi<3 = %d (0)\n", pi < 3); + printf("pi<-100 = %d (0)\n", pi < -100); + printf(" pi<-1 = %d (1)\n", pi < -1); + printf("\n"); + + printf(" pi<=4 = %d (0)\n", pi <= 4); + printf(" pi<=3 = %d (0)\n", pi <= 3); + printf("pi<=-100 = %d (1)\n", pi <= -100); + printf(" pi<=-1 = %d (1)\n", pi <= -1); + printf("\n"); + + pi = -100; + printf(" pi>4 = %d (1)\n", pi > 4); + printf(" pi>3 = %d (1)\n", pi > 3); + printf("pi>-100 = %d (0)\n", pi > -100); + printf(" pi>-1 = %d (0)\n", pi > -1); + printf("\n"); + + printf(" pi>=4 = %d (1)\n", pi >= 4); + printf(" pi>=3 = %d (1)\n", pi >= 3); + printf("pi>=-100 = %d (1)\n", pi >= -100); + printf(" pi>=-1 = %d (0)\n", pi >= -1); + printf("\n"); + + pi = &arr[0]; + pip = &arr[3]; + printf(" *pip - *pi: %d 30\n", *pip - *pi); + printf(" pip - pi: %d 3\n", pip - pi); + printf(" *pip: %d 40\n", *pip); + printf(" *(pip - 3): %d 10\n", *(pip - 3)); + printf(" *&arr[3]: %d 40\n", *&arr[3]); + printf("*(&arr[3] - 3): %d 10\n", *(&arr[3]-3)); +} + +printt (t, str) + int t; + char *str; +{ + printf("bool test on value %d %s\n", t, str); +} diff --git a/share/smallc/test2.c b/share/smallc/test2.c new file mode 100644 index 0000000..64f8cca --- /dev/null +++ b/share/smallc/test2.c @@ -0,0 +1,127 @@ +#include + +int aaa; +int bbb; +int ccc; +char gc; +char gbuffer[3]; +int gibuffer[4]; + +extern errno; + +main() +{ + char b; + int la; + unsigned int u1, u2; + int s1, s2; + unsigned char uc1, uc2; + char sc1, sc2; + int fd; + char buffer[6]; + int ibuffer[7]; + + printf(" sizeof(uc1): %d 1\n", sizeof(uc1)); + printf(" sizeof(sc1): %d 1\n", sizeof(sc1)); + printf(" sizeof(u1): %d 4\n", sizeof(u1)); + printf(" sizeof(s1): %d 4\n", sizeof(s1)); + printf(" sizeof(aaa): %d 4\n", sizeof(aaa)); + printf(" sizeof(bbb): %d 4\n", sizeof(bbb)); + printf(" sizeof(gc): %d 1\n", sizeof(gc)); + printf(" sizeof(buffer): %d 6\n", sizeof(buffer)); + printf(" sizeof(ibuffer): %d 28\n", sizeof(ibuffer)); + printf(" sizeof(char): %d 1\n", sizeof(char)); + printf(" sizeof(int): %d 4\n", sizeof(int)); + printf(" sizeof(gbuffer): %d 3\n", sizeof(gbuffer)); + printf(" sizeof(gibuffer): %d 16\n", sizeof(gibuffer)); + // sizeof(ibuffer[0]) is not supported, so the following can be used... + printf("sizeof(ibuffer)/sizeof(int): %d 7\n", sizeof(ibuffer)/sizeof(int)); + + aaa = 1; + bbb = 2; + la = 4; + printf("%d 1\n", aaa); + printf("%d 2\n", bbb); + printf("%d 4\n", la); + + uc1 = 0x80; + sc1 = 0x80; + s1 = uc1; + s2 = sc1; + printf("unsigned char (0x80) -> int: %d 128\n", s1); + printf(" signed char (0x80) -> int: %d -128\n", s2); + + u1 = uc1; + u2 = sc1; + printf("unsigned char (0x80) -> unsigned: %d 128\n", u1); + printf(" signed char (0x80) -> unsigned: %d -128\n", u2); + + la = errno; + printf("errno: %d 0\n", la); + + write(1, "abcd ", 5); + la = errno; + printf("errno after good write call: %d 0\n", la); + + write(10, "abcde", 5); + la = errno; + printf("errno after bad write call: %d 9\n", la); + + write(1, "abcd ", 5); + la = errno; + printf("good write after failed should not overwrite errno: %d 9\n", la); + + errno = 0; + write(1, "abcd ", 5); + la = errno; + printf("good write after errno set to zero: %d 0\n", la); + + la = write(1, "abcd ", 5); + printf("write() return: %d 5\n", la); + + la = write(10, "abcd ", 5); + printf("write(bad fd) return: %d -1\n", la); + + fd = open("/a.txt", O_WRONLY | O_CREAT, 0666); + if (fd != -1) { + printf("open success\n"); + la = write(fd, "abcd\n", 5); + if (la == 5) printf("write success\n"); else printf("write failed\n"); + la = close(fd); + if (la != -1) printf("close success\n"); else printf("close failed\n"); + } else { + printf("open failed\n"); + } + + buffer[0] = 0; + buffer[1] = 0; + buffer[2] = 0; + buffer[3] = 0; + buffer[4] = 0; + buffer[5] = 0; + + fd = open("/a.txt", O_RDONLY, 0666); + if (fd != -1) { + printf("open success\n"); + la = read(fd, buffer, 5); + printf(buffer); + if (la == 5) printf("read success\n"); else printf("read failed\n"); + la = close(fd); + if (la != -1) printf("close success\n"); else printf("close failed\n"); + } else { + printf("open failed\n"); + } + + if (buffer[0] != 'a') printf("data0 readback from file MISMATCH\n"); + if (buffer[1] != 'b') printf("data1 readback from file MISMATCH\n"); + if (buffer[2] != 'c') printf("data2 readback from file MISMATCH\n"); + if (buffer[3] != 'd') printf("data3 readback from file MISMATCH\n"); + if (buffer[4] != '\n') printf("data4 readback from file MISMATCH\n"); + + if (buffer[0] != 'a' || buffer[1] != 'b' || buffer[2] != 'c' || + buffer[3] != 'd' || buffer[4] != '\n') { + printf("data readback from file MISMATCH\n"); + } else { + printf("data readback from file OK\n"); + } +} diff --git a/share/smallc/test3.c b/share/smallc/test3.c new file mode 100644 index 0000000..edb0ab0 --- /dev/null +++ b/share/smallc/test3.c @@ -0,0 +1,49 @@ +main() +{ + int t; + + t = 0; + if (t) printt(t, "failure"); else printt(t, "success"); + t = 1; + if (t) printt(t, "success"); else printt(t, "failure"); + t = 8; + if (t) printt(t, "success"); else printt(t, "failure"); + t = -2; + if (t) printt(t, "success"); else printt(t, "failure"); + printf("\n"); + + t = 4; + printf("switch test: "); + switch (t) { + case 3: + printf("failure"); + break; + case 4: + printf("success"); + break; + case 5: + printf("failure"); + break; + } + printf("\n"); + + printf("switch fallthrough test: "); + switch (t) { + case 3: + printf("failure"); + break; + case 4: + printf("OKSOFAR: "); + case 5: + printf("success if oksofar printed before this in caps"); + break; + } + printf("\n"); +} + +printt (t, str) + int t; + char *str; +{ + printf("bool test on value %d %s\n", t, str); +} diff --git a/share/smallc/webserver.c b/share/smallc/webserver.c new file mode 100644 index 0000000..4f6a81d --- /dev/null +++ b/share/smallc/webserver.c @@ -0,0 +1,88 @@ +/* + * Web server, written in SmallC. + * + * A simple web server that shows the value of the analog input pins. + * using an Arduino Wiznet Ethernet shield. + * + * 18 Dec 2009 created by David A. Mellis + * 4 Sep 2010 modified by Tom Igoe + * 16 Apr 2012 ported to RetroBSD by Serge Vakulenko + */ +#include +#include +#include +#include + +int client [CLIENT_SIZE]; + +char buf [80]; + +main() +{ + /* Initialize the Ethernet server library + * with the IP address and port you want to use + * (port 80 is default for HTTP). */ + ethernet_init (); + server_init (80); + + for (;;) { + /* Listen for incoming clients. */ + if (server_available (client)) { + process_request(); + } + } +} + +process_request() +{ + int current_line_is_blank; + int c, fd, pnum, value; + + /* An http request ends with a blank line. */ + current_line_is_blank = 1; + + /* Parse the http request. */ + while (client_connected (client)) { + if (client_available (client)) { + c = client_getc (client); + + /* If you've gotten to the end of the line (received + * a newline character) and the line is blank, the http + * request has ended, so you can send a reply. */ + if (c == '\n' && current_line_is_blank) + break; + + if (c == '\n') { + /* You're starting a new line. */ + current_line_is_blank = 1; + } + else if (c != '\r') { + /* You've gotten a character on the current line. */ + current_line_is_blank = 0; + } + } + } + + /* Send a standard http response header. */ + client_puts (client, "HTTP/1.1 200 OK\n"); + client_puts (client, "Content-Type: text/html\n\n"); + + /* Output the value of each digital pin. */ + fd = open ("/dev/porta", O_RDONLY); + if (fd < 0) { + client_puts (client, "Failed to open /dev/porta\n"); + } else { + for (pnum = 0; pnum < 6; pnum++) { + value = ioctl (fd, GPIO_POLL | GPIO_PORT (pnum), 0); + sprintf (buf, "PORT%c = 0x%04x
\n", pnum+'A', value); + client_puts (client, buf); + } + close (fd); + } + + /* Give the web browser time to receive the data. */ + usleep (1000); + + /* Close the connection. */ + client_stop (client); +} diff --git a/src/Makefile b/src/Makefile new file mode 100644 index 0000000..137d055 --- /dev/null +++ b/src/Makefile @@ -0,0 +1,28 @@ +# +# Copyright (c) 1980 Regents of the University of California. +# All rights reserved. The Berkeley software License Agreement +# specifies the terms and conditions for redistribution. +# +TOPSRC = $(shell cd ..; pwd) +include $(TOPSRC)/target.mk + +# Programs that live in subdirectories, and have makefiles of their own. +# +SUBDIR = startup-$(MACHINE) libc libm libutil libtermlib libcurses \ + libvmf libwiznet share cmd games + +all: $(SUBDIR) + +$(SUBDIR): FRC + $(MAKE) -C $@ + +FRC: + +install: elf32-mips.ld + -for i in $(SUBDIR); do \ + $(MAKE) -C $$i DESTDIR=$(DESTDIR) all install; done +# cp -p elf32-mips.ld $(DESTDIR)/lib/elf32-mips.ld + +clean: + rm -f a.out core *.s *.o *.a *~ + -for i in $(SUBDIR); do $(MAKE) -C $$i clean; done diff --git a/src/cmd/Makefile b/src/cmd/Makefile new file mode 100644 index 0000000..f3fdf44 --- /dev/null +++ b/src/cmd/Makefile @@ -0,0 +1,127 @@ +# +# Copyright (c) 1980 Regents of the University of California. +# All rights reserved. The Berkeley software License Agreement +# specifies the terms and conditions for redistribution. +# +TOPSRC = $(shell cd ../..; pwd) +include $(TOPSRC)/target.mk + +CFLAGS += -Werror + +# Programs that live in subdirectories, and have makefiles of their own. +# /bin +SUBDIR = adb adc-demo ar as awk basic cc chflags chpass \ + cpp dc diff env fdisk find forth fstat glcdtest hostname \ + id la lcc lcpp ld ls login make man med \ + more nm passwd picoc portio printf pwm \ + rdprof ranlib re renice retroforth scm setty sl \ + sed sh smallc smlrc stty sysctl test uname wiznet xargs \ + zmodem gtest msec unixbench cron compress date2 tip \ + talloc devupdate uucp smux + +# /sbin +SUBDIR += chown chroot disktool fsck getty init \ + mkfs mknod mkpasswd mount pstat \ + reboot shutdown umount update vipw virus + +# TODO: ccom lex m4 yacc reloc sre pforth + +# Shell scripts that need only be installed and are never removed. +# +SCRIPT = false nohup true #lorder mkdep + +# C programs that live in the current directory and do not need +# explicit make lines. +# +STD = basename cal cat cb chgrp chmod cmp col comm cp dd du \ + echo ed fgrep file grep head hostid join kill last ln \ + mesg mkdir mv nice od pagesize pr printenv pwd rev rm rmail rmdir \ + size sleep sort split sum sync tail tar tee time touch tr \ + tsort tty uniq w wc whereis who + +# C programs that live in the current directory and need explicit make lines. +# +NSTD = bc expr egrep + +# Programs that must run setuid to root +# +SETUID = mail su + +# Programs that run set-group-id operator +# +OPERATOR = df + +# Programs that must run set-group-id kmem. +# +KMEM = ps iostat vmstat + +# Programs that must run set-group-id tty. +# +TTY = wall write + +# 'strip' is handled specially because 'install -s' now uses 'strip' and +# thus we can't do a 'install -s strip /bin/strip' without an error. +# +BINS = $(STD) $(NSTD) $(SETUID) $(OPERATOR) $(KMEM) $(TTY) $(SCRIPT) strip + +all: $(SUBDIR) $(BINS) + +$(SUBDIR): FRC + $(MAKE) -C $@ $(MFLAGS) + +FRC: + +# $(STD) $(SETUID) $(KMEM) $(OPERATOR) $(TTY) strip +%: %.c + $(CC) $(CFLAGS) $(LDFLAGS) -o $@.elf $< $(LIBS) + $(OBJDUMP) -S $@.elf > $@.dis + $(SIZE) $@.elf + $(ELF2AOUT) $@.elf $@ && /bin/rm $@.elf + +# Files listed in $(NSTD) have explicit make lines given below. + +# bc egrep expr +%.c: %.y + $(YACC) $(YFLAGS) $< + -/bin/mv y.tab.c $@ + +$(SCRIPT): + install -c $@.sh $@ + +install: $(BINS) + install $(STD) $(NSTD) strip $(DESTDIR)/bin/ + -for i in $(SUBDIR); do \ + $(MAKE) -C $$i $(MFLAGS) DESTDIR=$(DESTDIR) install; done + -for i in $(SCRIPT); do install $$i.sh $(DESTDIR)/bin/$$i; done + -for i in $(SETUID); do \ + install -m 4751 $$i $(DESTDIR)/bin/$$i; done + -for i in $(OPERATOR); do \ + install -m 2751 $$i $(DESTDIR)/bin/$$i; done + -for i in $(KMEM); do \ + install -m 2751 $$i $(DESTDIR)/bin/$$i; done + -for i in $(TTY); do \ + install -m 2751 $$i $(DESTDIR)/bin/$$i; done + +clean: + /bin/rm -f $(BINS) expr.c a.out core *.s *.o *.dis *.elf *~ y.tab.c errs + for i in $(SUBDIR); do (cd $$i; $(MAKE) $(MFLAGS) clean); done + +depend: expr.c + for i in $(BINS); do \ + cc -M $(INCPATH) $$i.c | sed 's/\.o//' | \ + 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 ) ' >> makedep; done + echo '/^# DO NOT DELETE THIS LINE/+2,$$d' >eddep + echo '$$r makedep' >>eddep + echo 'w' >>eddep + cp Makefile Makefile.bak + ed - Makefile < eddep + /bin/rm eddep makedep + echo '# DEPENDENCIES MUST END AT END OF FILE' >> Makefile + echo '# IF YOU PUT STUFF HERE IT WILL GO AWAY' >> Makefile + echo '# see make depend above' >> Makefile + +# DO NOT DELETE THIS LINE -- make depend uses it diff --git a/src/cmd/Makefile-sbin b/src/cmd/Makefile-sbin new file mode 100644 index 0000000..e835b55 --- /dev/null +++ b/src/cmd/Makefile-sbin @@ -0,0 +1,24 @@ +# +# Public domain - 1996/10/26 - sms +# +TOPSRC = $(shell cd ..; pwd) +include $(TOPSRC)/target.mk + +SUBDIR = chown-src chroot-src disktool-src fsck-src getty-src init-src \ + mkfs-src mknod-src mkpasswd-src mount-src pstat-src \ + reboot-src shutdown-src umount-src update-src vipw-src + +all: ${SUBDIR} + +${SUBDIR}: FRC + cd $@; make ${MFLAGS} all + +FRC: + +install: FRC + -for i in ${SUBDIR}; do \ + (cd $$i; make ${MFLAGS} DESTDIR=${DESTDIR} install); done + +clean: + for i in ${SUBDIR}; do (cd $$i; make ${MFLAGS} clean); done + rm -f *~ diff --git a/src/cmd/adb/Makefile b/src/cmd/adb/Makefile new file mode 100644 index 0000000..baaff88 --- /dev/null +++ b/src/cmd/adb/Makefile @@ -0,0 +1,26 @@ +TOPSRC = $(shell cd ../../..; pwd) +include $(TOPSRC)/target.mk +#include $(TOPSRC)/cross.mk +#CFLAGS = -DCROSS -I$(TOPSRC)/include -I/usr/include -D__mips__ -ggdb3 + +OBJS = message.o access.o command.o expr.o findfn.o format.o input.o \ + main.o opset.o output.o pcs.o print.o \ + runpcs.o setup.o sym.o + +CFLAGS += -DNUM_SYMS_CACHE=50 -Wall -Werror + +all: adb + +adb: $(OBJS) + ${CC} ${LDFLAGS} -o adb.elf $(OBJS) ${LIBS} + ${OBJDUMP} -S adb.elf > adb.dis + ${SIZE} adb.elf + ${ELF2AOUT} adb.elf $@ && rm adb.elf + +clean: + rm -f *.o *.0 *.elf adb *.elf *.dis tags *~ + +install: all + install adb $(DESTDIR)/bin/ + +$(OBJS): defs.h diff --git a/src/cmd/adb/READ_ME b/src/cmd/adb/READ_ME new file mode 100644 index 0000000..cd2857a --- /dev/null +++ b/src/cmd/adb/READ_ME @@ -0,0 +1,73 @@ + The makefile can be adjusted to make a version of adb for +nonseparate I/D machines. Change the -DNUM_VM_PAGES value to +something like 6 to 8, this will use less real memory (and cause +adb to run a bit slower) and allow adb to run on a non-split I/D +machine. + +Changes for overlaid processes are intended to work in the most obvious way +and are: + + 1. There is an additional map for an overlay (430 or 431) object + file, described by the triple (bo,eo,fo). bo is initialized + on startup, and the others are changed on setting an overlay. + This is done automatically if there is an appropriate corefile + or when a traced subprocess stops, and can be done manually + (described below). + + 2. There are two additional internal variables set for overlay objects. + The variable o is the sum of the overlay sizes. c is the current + overlay number. It is set automatically as described above, + and can be changed manually (#>c). This changes the overlay + map (eo and fo) to map in the named overlay. This affects only + adb's mapping. + + 3. Although the variable c controls the overlay map, the "register" + variable "ov" reflects the overlay actually mapped when the + process stopped (or dumped core). This value is shown as "ov" + in the register list ($r). It may also be used as other register + variables, in the "<" and ">" commands. In the latter case, + this actually causes the kernel to remap the subprocess, and the + correct overlay must be mapped to restart the process. NOTE: + the kernel routine procxmt must support overlay changes for this + to work. The (1982) 2bsd distribution includes the necessary + changes. + + 4. For text symbols in overlaid objects, the default symbol + used to find "name" is "~name" rather than "_name". This + means that the actual subroutine, rather than its thunk, is + found. To examine a thunk, use "_name" explicitly. + + 5. In the overlaid segment, only symbols in the current overlay + (c) are used in symbolic addresses. In order to find these + overlay numbers, the new version of (ov)ld must be used. + The reason for this is that the previous version of ovld put + the overlay number only in symbols for thunks, + not in local text symbols. + + 6. In order to support breakpoints in overlaid segments, the + strategy used by adb has been changed slightly. Breakpoints + are written into the subprocess immediately when a ":b" + command is executed, and deleted immediately with ":d". + +Changes to support overlaid kernels: + + 1. The user's saved registers are in different places in the + kernel stack. They are found relative to the entry u.u_ar0 + in the core file if there is one, with offsets from + and . If there is no core file,a default is + used. This default is defined as UAR0 in defs.h. +******* UAR0 should be checked whenever the user structure changes. + + 2. There is a new command-line flag, -k, which sets things + appropriately for the kernel. + It sets the mapping of the core file appropriately + for 407, 411 and 430 kernels, and changes the debugger's idea of + saved register locations. Thus, $r will print the register + values saved by dump, and $c will use the saved r5 from low core. + +In addition, a number of minor bugs have been fixed. + + Mike Karels + ucbvax!virus!mike + Department of Molecular Biology + University of California, Berkeley diff --git a/src/cmd/adb/access.c b/src/cmd/adb/access.c new file mode 100644 index 0000000..3b0b804 --- /dev/null +++ b/src/cmd/adb/access.c @@ -0,0 +1,130 @@ +/* + * File handling and access routines + */ +#include "defs.h" +#include + +static int +within(adr, lbd, ubd) + long adr, lbd, ubd; +{ + return (adr>=lbd && adrb1, amap->e1)) { + *adr += (amap->f1) - (amap->b1); + break; + } + /* falls through */ + + case ISP+STAR: + if (within(*adr, amap->b2, amap->e2)) { + *adr += (amap->f2) - (amap->b2); + break; + } + goto err; + + case DSP: + if (within(*adr, amap->b1, amap->e1)) { + *adr += (amap->f1) - (amap->b1); + break; + } + /* falls through */ + + case DSP+STAR: + if (within(*adr, amap->b2, amap->e2)) { + *adr += (amap->f2) - (amap->b2); + break; + } + /* falls through */ + + default: +err: errflg = (space & DSP) ? BADDAT : BADTXT; + return 0; + } + return 1; +} + +int +acces(mode, adr, space, value) + long adr; +{ + int w, w1, pmode, rd, file; + BKPTR bkptr; + + if (space == NSP) + return 0; + rd = (mode == RD); + + if (pid) { /* tracing on? */ + if ((adr & 3) && ! rd) + error(ODDADR); + pmode = (space & DSP) ? + (rd ? PT_READ_D : PT_WRITE_D) : + (rd ? PT_READ_I : PT_WRITE_I); + bkptr = scanbkpt((u_int) adr); + if (bkptr) { + if (rd) + return bkptr->ins; + bkptr->ins = value; + return 0; + } + w = ptrace(pmode, pid, (void*) shorten(adr & ~1), value); + if (adr & 01) { + w1 = ptrace(pmode, pid, (void*) shorten(adr + 1), value); + w = ((w >> 8) & LOBYTE) | (w1 << 8); + } + if (errno) { + errflg = (space & DSP) ? BADDAT : BADTXT; + } + return w; + } + w = 0; + if (mode==WT && wtflag==O_RDONLY) { + error("not in write mode"); + } + if (! chkmap(&adr, space)) + return 0; + + file = (space & DSP) ? datmap.ufd : txtmap.ufd; + if (lseek(file, adr, 0) == -1L || + (rd ? read(file, &w, 4) : write(file, &value, 4)) < 1) { + errflg = (space & DSP) ? BADDAT : BADTXT; + } + return w; +} + +void +put(adr, space, value) + long adr; +{ + acces(WT, adr, space, value); +} + +u_int +get(adr, space) + long adr; +{ + return acces(RD, adr, space, 0); +} + +u_int +chkget(n, space) + long n; +{ + register int w; + + w = get(n, space); + chkerr(); + return w; +} diff --git a/src/cmd/adb/command.c b/src/cmd/adb/command.c new file mode 100644 index 0000000..41495d3 --- /dev/null +++ b/src/cmd/adb/command.c @@ -0,0 +1,239 @@ +/* + * Command decoding + */ +#include "defs.h" + +int lastcom = '='; + +static char eqformat[512] = "o"; +static char stformat[512] = "o\"= \"^i"; + +static long locval; +static long locmsk; + +int +command(buf, defcom) + char *buf; + int defcom; +{ + int itype, ptype, modifier, regptr; + char longpr, eqcom; + char wformat[1]; + char savc; + long w, savdot; + char *savlp=lp; + + if (buf) { + if (*buf == EOR) + return(FALSE); + lp = buf; + } + + do { + adrflg = expr(0); + if (adrflg) { + dot = expv; + ditto = dot; + } + adrval = dot; + if (rdc()==',' && expr(0)) { + cntflg = TRUE; + cntval = expv; + } else { + cntflg = FALSE; + cntval = 1; + lp--; + } + + if (! eol(rdc())) { + lastcom = lastc; + } else { + if (adrflg == 0) { + dot = inkdot(dotinc); + } + lp--; + lastcom = defcom; + } + + switch (lastcom & STRIP) { + case '/': + itype = DSP; + ptype = DSYM; + goto trystar; + + case '=': + itype = NSP; + ptype = ASYM; + goto trypr; + + case '?': + itype = ISP; + ptype = ISYM; + goto trystar; + +trystar: + if (rdc() == '*') { + lastcom |= QUOTE; + } else { + lp--; + } + if (lastcom & QUOTE) { + itype |= STAR; + ptype = (DSYM + ISYM) - ptype; + } +trypr: + longpr = FALSE; + eqcom = (lastcom == '='); + + switch (rdc()) { + case 'm': { /* reset map data */ + int fcount; + MAPPTR smap; + long *mp; + + if (eqcom) { + error(BADEQ); + } + smap = (itype & DSP) ? &datmap : &txtmap; + fcount = 3; + if (itype & STAR) { + mp = &(smap->b2); + } else { + mp = &(smap->b1); + } + while (fcount-- && expr(0)) { + *(mp)++ = expv; + } + if (rdc() == '?') { + smap->ufd = fsym; + } else if (lastc == '/') { + smap->ufd = fcor; + } else { + lp--; + } + } + break; + + case 'L': + longpr = TRUE; + case 'l': /* search for exp */ + if (eqcom) { + error(BADEQ); + } + dotinc = 2; + savdot = dot; + expr(1); + locval = expv; + if (expr(0)) { + locmsk = expv; + } else { + locmsk = -1L; + } + for (;;) { + w = leng(get(dot, itype)); + if (longpr) { + //w = itol(w, get(inkdot(2), itype)); + } + if (errflg || mkfault || (w & locmsk) == locval) + break; + dot = inkdot(dotinc); + } + if (errflg) { + dot = savdot; + errflg = NOMATCH; + } + psymoff(dot, ptype, ""); + break; + + case 'W': + longpr = TRUE; + case 'w': + if (eqcom) { + error(BADEQ); + } + wformat[0] = lastc; + expr(1); + do { + savdot = dot; + psymoff(dot, ptype, ":%16t"); + exform(1, wformat, itype, ptype); + errflg = 0; + dot = savdot; + if (longpr) { + put(dot, itype, expv); + } + put((longpr ? inkdot(2) : dot), itype, shorten(expv)); + savdot = dot; + print("=%8t"); + exform(1, wformat, itype, ptype); + printc(EOR); + } while (expr(0) && errflg == 0); + dot = savdot; + chkerr(); + break; + + default: + lp--; + getformat(eqcom ? eqformat : stformat); + if (! eqcom) { + if (*stformat != 'a') { + psymoff(dot, ptype, ":%16t"); + } + } + scanform(cntval, (eqcom ? eqformat : stformat), itype, ptype); + } + break; + + case '>': + lastcom = 0; + savc = rdc(); + regptr = getreg(savc); + if (regptr != NOREG) { + uframe[regptr] = shorten(dot); + ptrace(PT_WRITE_U, pid, (char*) (KERNEL_DATA_END - USIZE) + + ((char*)&uframe[regptr] - (char*)&corhdr), + uframe[regptr]); + } else if ((modifier = varchk(savc)) != -1) { + var[modifier] = dot; + } else { + error(BADVAR); + } + break; + + case '!': + lastcom = 0; + unox(); + break; + + case '$': + lastcom = 0; + printtrace(nextchar()); + break; + + case ':': + if (! executing) { + executing = TRUE; + subpcs(nextchar()); + executing = FALSE; + lastcom = 0; + } + break; + + case 0: + print("%s\n", myname); + break; + + default: + error(BADCOM); + } + flushbuf(); + + } while (rdc() == ';'); + + if (buf) { + lp = savlp; + } else { + lp--; + } + return (adrflg && dot != 0); +} diff --git a/src/cmd/adb/cross/Makefile b/src/cmd/adb/cross/Makefile new file mode 100644 index 0000000..ec6b072 --- /dev/null +++ b/src/cmd/adb/cross/Makefile @@ -0,0 +1,55 @@ +TOPSRC = $(shell cd ../../../..; pwd) +include $(TOPSRC)/cross.mk + +vpath %.c .. + +# Build a list of the host include directories. +CPP = $(shell gcc -print-prog-name=cc1) +HOSTINC = $(addprefix -I,$(shell echo | $(CPP) -v 2>&1 | grep '^ /.*include')) +HOSTINC += -I/usr/include/i386-linux-gnu + +CFLAGS = -m32 -g -DCROSS -nostdinc -I. $(HOSTINC) -I.. -D__mips__ +CFLAGS += -Wall -Werror -DNUM_SYMS_CACHE=50 -fno-builtin +LDFLAGS += -m32 -g + +OBJS = message.o access.o command.o expr.o findfn.o format.o input.o \ + main.o opset.o output.o pcs.o print.o \ + runpcs.o setup.o sym.o +HEADERS = a.out.h nlist.h time.h signal.h stdlib.h \ + sys/exec.h sys/types.h sys/param.h sys/user.h \ + sys/time.h sys/dir.h sys/resource.h sys/select.h \ + sys/signal.h sys/wait.h \ + machine/io.h machine/machparam.h + +all: $(HEADERS) adb + +adb: $(OBJS) + $(CC) $(LDFLAGS) $(OBJS) -o $@ + +clean: + rm -f *~ *.o adb *.h */*.h gccdump.s + +$(HEADERS): + ln -s -f ../../../../include/a.out.h . + ln -s -f ../../../../include/nlist.h . + ln -s -f ../../../../include/time.h . + ln -s -f ../../../../include/stdlib.h . + ln -s -f sys/signal.h . + ln -s -f ../../../../../include/sys/exec.h sys/ + ln -s -f ../../../../../include/sys/param.h sys/ + ln -s -f ../../../../../include/sys/user.h sys/ + ln -s -f ../../../../../include/sys/types.h sys/ + ln -s -f ../../../../../include/sys/time.h sys/ + ln -s -f ../../../../../include/sys/dir.h sys/ + ln -s -f ../../../../../include/sys/resource.h sys/ + ln -s -f ../../../../../include/sys/select.h sys/ + ln -s -f ../../../../../include/sys/wait.h sys/ + ln -s -f ../../../../../include/sys/signal.h sys/ + ln -s -f ../../../../../include/machine/io.h machine/ + ln -s -f ../../../../../include/machine/machparam.h machine/ + +test: + echo '$$q' | ./adb fsck fsck.core + @printf '\n----------------------------\n' + echo '$$m' | ./adb fsck fsck.core + @printf '\n----------------------------\n' diff --git a/src/cmd/adb/defs.h b/src/cmd/adb/defs.h new file mode 100644 index 0000000..2b6f244 --- /dev/null +++ b/src/cmd/adb/defs.h @@ -0,0 +1,303 @@ +/* + * UNIX debugger - common definitions + * + * 1998/4/21 - remove local redefinitions used with ptrace + * + * Layout of a.out file (fsym): + * + * This has changed over time - see a.out.h, sys/exec.h and nlist.h + * for the current a.out definition and format. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CROSS +# include +# define sgttyb termios +#else +# include +#endif + +#define MAXSYMLEN 32 +#define MAXCOM 64 +#define MAXARG 32 +#define LINSIZ 512 + +#define LPRMODE "%Q" +#define OFFMODE "+%x" + +/* + * This is the memory resident portion of a symbol. The only difference + * between this and a 'nlist' entry is the size of the string offset By + * restricting the string table to be less than 64kb we save 2 bytes per + * symbol - approximately 7.5kb of D space in the case of /unix's symbol + * table. In practice this restriction is unlikely to be reached since + * even the kernel's symbol table of ~28kb only has a strings table of 21kb. + */ +struct SYMbol { + u_int value; + u_int type; + char *sname; +}; + +#define SYMTYPE(symflag) (( symflag>=041 || (symflag>=02 && symflag<=04))\ + ? ((symflag&07)>=3 ? DSYM : (symflag&07))\ + : NSYM) + +typedef struct map MAP; +typedef MAP *MAPPTR; +typedef struct bkpt BKPT; +typedef BKPT *BKPTR; + +/* file address maps */ +struct map { + long b1; /* text base address */ + long e1; /* text end address */ + long f1; /* file start to text offset */ + long b2; /* data base address */ + long e2; /* data end address */ + long f2; /* file start to data offset */ + int ufd; +}; + +struct bkpt { + int loc; + int ins; + int count; + int initcnt; + char flag; + char comm[MAXCOM]; + BKPT *nxtbkpt; +}; + +struct reglist { + char *rname; + int roffs; +}; +typedef struct reglist REGLIST; + +/* + * Internal variables --- + * They are addressed by name. (e.g. (`0'-`9', `a'-`b')) + * thus there can only be 36 of them. + */ +#define VARB 11 +#define VARC 12 /* current overlay number */ +#define VARD 13 +#define VARE 14 +#define VARM 22 +#define VARO 24 /* overlay text segment addition */ +#define VARS 28 +#define VART 29 + +#define RD 0 +#define WT 1 +#define NSP 0 +#define ISP 1 +#define DSP 2 +#define STAR 4 +#define DSYM 7 +#define ISYM 2 +#define ASYM 1 +#define NSYM 0 +#define ESYM 0177 +#define BKPTSET 1 +#define BKPTEXEC 2 + +#define BPT 03 + +#define NOREG 32767 /* impossible return from getreg() */ +#define NREG FRAME_WORDS + +/* + * UFRAME is the value used for subprocesses when there is no core file. + */ +#define UFRAME (&corhdr[1]) /* default address of r0 (u.u_frame) */ + +#define KR0 (0300/2) /* location of r0 in kernel dump */ +#define KR1 (KR0+1) +#define KR2 (KR0+2) +#define KR3 (KR0+3) +#define KR4 (KR0+4) +#define KR5 (KR0+5) +#define KSP (KR0+6) +#define KA6 (KR0+7) /* saved ka6 in kernel dump */ + +#define MAXOFF 255 +#define MAXPOS 80 +#define MAXLIN 128 + +#ifndef TRUE + #define TRUE (-1) +#endif +#define FALSE 0 +#define LOBYTE 0377 +#define HIBYTE 0177400 +#define STRIP 0177 + +#define SP ' ' +#define TB '\t' +#define EOR '\n' +#define QUOTE 0200 +#define ALIGNED (~3) + +/* long to ints and back (puns) */ +#define leng(a) ((long)((unsigned)(a))) +#define shorten(a) ((long)a) + +struct sgttyb adbtty, usrtty; +jmp_buf erradb; +sig_t sigint, sigqit; + +MAP txtmap; +MAP datmap; + +BKPTR bkpthead; /* breakpoints */ + +struct SYMbol *symbol; + +extern u_int *uframe; +const char *errflg; +char *lp; +char *myname; /* program name */ +char *printptr; +extern char *Ipath; +extern char *symfil; +extern char *corfil; +char printbuf[MAXLIN]; +int wtflag; +int pid; +int executing; +int fcor; +int fsym; +int mkfault; +int dotinc; +int adrflg; +int cntflg; +int lastframe; +int kernel; +int callpc; +int octal; +int localok; +int maxoff; +int maxpos; +int eof; +int infile; +int argcount; +int magic; +int signo; +extern int lastc; +extern int lastcom; +extern int outfile; +long dot; +long ditto; +long expv; +long adrval; +long cntval; +long localval; +long maxfile; +long txtsiz; +long datsiz; +long datbas; +long stksiz; +long entrypt; +long loopcnt; + +long var[36]; +u_int corhdr [USIZE/sizeof(u_int)]; + +off_t symoff; + +extern const REGLIST reglist []; + +extern const char BADMOD[]; +extern const char BADCOM[]; +extern const char BADSYM[]; +extern const char BADLOC[]; +extern const char NOCFN[]; +extern const char NOMATCH[]; +extern const char NOBKPT[]; +extern const char BADKET[]; +extern const char NOADR[]; +extern const char NOPCS[]; +extern const char BADVAR[]; +extern const char BADTXT[]; +extern const char BADDAT[]; +extern const char ODDADR[]; +extern const char EXBKPT[]; +extern const char A68BAD[]; +extern const char A68LNK[]; +extern const char ADWRAP[]; +extern const char BADEQ[]; +extern const char BADWAIT[]; +extern const char ENDPCS[]; +extern const char NOFORK[]; +extern const char BADSYN[]; +extern const char NOEOR[]; +extern const char SZBKPT[]; +extern const char LONGFIL[]; +extern const char NOTOPEN[]; +extern const char TOODEEP[]; + +struct SYMbol *cache_by_string (char *); +struct SYMbol *symget (void); +char *exform (int, char *, int, int); +void error (const char *); +long inkdot (int); +BKPTR scanbkpt (int); +char *cache_sym (struct SYMbol *); +char *no_cache_sym (struct SYMbol *); +long roundn (long, long); +void chkerr (void); +int expr (int); +int eol (int); +int rdc (void); +u_int get (long, int); +void put (long, int, int); +void psymoff (long, int, char *); +void print (char *, ...); +void printc (int); +void getformat (char *); +void scanform (long, char *, int, int); +int getreg (int); +int varchk (int); +void unox (void); +void printtrace (int); +int nextchar (void); +void subpcs (int); +void flushbuf (void); +int readchar (void); +int findroutine (long); +int eqsym (char *, char *, int); +int localsym (long); +void symset (void); +int quotchar (void); +u_int chkget (long, int); +u_int findsym (u_int, int); +void endline (void); +void printins (int, unsigned, unsigned); +void iclose (int, int); +void oclose (void); +void setsym (void); +void setcor (void); +void delbp (void); +void done (void); +int command (char *, int); +void endpcs (void); +void del1bp (BKPTR); +void set1bp (BKPTR); +void setbp (void); +void setup (void); +int getsig (int); +int runpcs (int, int); +void printpc (void); +void sigprint (void); +void valpr (int, int); +void symINI (struct exec *); diff --git a/src/cmd/adb/doc/adb-figures.ms b/src/cmd/adb/doc/adb-figures.ms new file mode 100644 index 0000000..8366473 --- /dev/null +++ b/src/cmd/adb/doc/adb-figures.ms @@ -0,0 +1,961 @@ +.sp 100 +.nr PS 9 +.nr VS 11 +. \" START OF Figures +.de P1 +.nf +.in +.5i +.ta .5i 1i 1.5i 2i 2.5i 3i 3.5i 4i 4.5i 5i +.sp +.ps 9 +.vs 11p +.. +.de P2 +.sp +.fi +.ps \\n(PS +.vs \\n(VS +.in -.5i +.. +.SH +Figure 1: C program with pointer bug +.LP +.P1 +struct buf { + int fildes; + int nleft; + char *nextp; + char buff[512]; + }bb; +struct buf *obuf; + +char *charp "this is a sentence."; + +main(argc,argv) +int argc; +char **argv; +{ + char cc; + + if(argc < 2) { + printf("Input file missing\\n"); + exit(8); + } + + if((fcreat(argv[1],obuf)) < 0){ + printf("%s : not found\\n", argv[1]); + exit(8); + } + charp = \'T\'; +printf("debug 1 %s\\n",charp); + while(cc= *charp++) + putc(cc,obuf); + fflush(obuf); +} +.P2 +.sp 100 +.SH +Figure 2: ADB output for C program of Figure 1 +.LP +.P1 +.ft B +adb a.out core +$c +.ft R +~main(02,0177762) +.ft B +$C +.ft R +~main(02,0177762) + argc: 02 + argv: 0177762 + cc: 02124 +.ft B +$r +.ft R +ps 0170010 +pc 0204 ~main+0152 +sp 0177740 +r5 0177752 +r4 01 +r3 0 +r2 0 +r1 0 +r0 0124 +~main+0152: mov _obuf,(sp) +.ft B +$e +.ft R +savr5: 0 +_obuf: 0 +_charp: 0124 +_errno: 0 +_fout: 0 +.ft B +$m +.ft R +text map \`ex1\' +b1 = 0 e1 = 02360 f1 = 020 +b2 = 0 e2 = 02360 f2 = 020 +data map \`core1\' +b1 = 0 e1 = 03500 f1 = 02000 +b2 = 0175400 e2 = 0200000 f2 = 05500 +.ft B +*charp/s +.ft R +0124: TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTLx Nh@x&_ +~ +.ft B +charp/s +.ft R +_charp: T + +_charp+02: this is a sentence. + +_charp+026: Input file missing +.ft B +main.argc/d +.ft R +0177756: 2 +.ft B +*main.argv/3o +.ft R +0177762: 0177770 0177776 0177777 +.ft B +0177770/s +.ft R +0177770: a.out +.ft B +*main.argv/3o +.ft R +0177762: 0177770 0177776 0177777 +.ft B +*"/s +.ft R +0177770: a.out +.ft B + .=o +.ft R + 0177770 +.ft B + .\(mi10/d +.ft R +0177756: 2 +.ft B +$q +.P2 +.sp 100 +.SH +Figure 3: Multiple function C program for stack trace illustration +.LP +.P1 +int fcnt,gcnt,hcnt; +h(x,y) +{ + int hi; register int hr; + hi = x+1; + hr = x\(miy+1; + hcnt++ ; + hj: + f(hr,hi); +} + +g(p,q) +{ + int gi; register int gr; + gi = q\(mip; + gr = q\(mip+1; + gcnt++ ; + gj: + h(gr,gi); +} + +f(a,b) +{ + int fi; register int fr; + fi = a+2*b; + fr = a+b; + fcnt++ ; + fj: + g(fr,fi); +} + +main() +{ + f(1,1); +} +.P2 +.sp 100 +.SH +Figure 4: ADB output for C program of Figure 3 +.LP +.P1 +.ft B +adb +$c +.ft R +~h(04452,04451) +~g(04453,011124) +~f(02,04451) +~h(04450,04447) +~g(04451,011120) +~f(02,04447) +~h(04446,04445) +~g(04447,011114) +~f(02,04445) +~h(04444,04443) +.ft B +HIT DEL KEY +.ft R +adb +.ft B +,5$C +.ft R +~h(04452,04451) + x: 04452 + y: 04451 + hi: ? +~g(04453,011124) + p: 04453 + q: 011124 + gi: 04451 + gr: ? +~f(02,04451) + a: 02 + b: 04451 + fi: 011124 + fr: 04453 +~h(04450,04447) + x: 04450 + y: 04447 + hi: 04451 + hr: 02 +~g(04451,011120) + p: 04451 + q: 011120 + gi: 04447 + gr: 04450 +.ft B +fcnt/d +.ft R +_fcnt: 1173 +.ft B +gcnt/d +.ft R +_gcnt: 1173 +.ft B +hcnt/d +.ft R +_hcnt: 1172 +.ft B +h.x/d +.ft R +022004: 2346 +.ft B +$q +.P2 +.sp 100 +.SH +Figure 5: C program to decode tabs +.LP +.P1 +#define MAXLINE 80 +#define YES 1 +#define NO 0 +#define TABSP 8 +.sp .5 +char input[] "data"; +char ibuf[518]; +int tabs[MAXLINE]; +.sp .5 +main() +{ + int col, *ptab; + char c; +.sp .5 + ptab = tabs; + settab(ptab); /*Set initial tab stops */ + col = 1; + if(fopen(input,ibuf) < 0) { + printf("%s : not found\\n",input); + exit(8); + } + while((c = getc(ibuf)) != \(mi1) { + switch(c) { + case \(fm\\t\(fm: /* TAB */ + while(tabpos(col) != YES) { + putchar(\(fm \(fm); /* put BLANK */ + col++ ; + } + break; + case \(fm\\n\(fm: /*NEWLINE */ + putchar(\(fm\\n\(fm); + col = 1; + break; + default: + putchar(c); + col++ ; + } + } +} +.sp .5 +/* Tabpos return YES if col is a tab stop */ +tabpos(col) +int col; +{ + if(col > MAXLINE) + return(YES); + else + return(tabs[col]); +} +.sp .5 +/* Settab - Set initial tab stops */ +settab(tabp) +int *tabp; +{ + int i; +.sp .5 + for(i = 0; i<= MAXLINE; i++) + (i%TABSP) ? (tabs[i] = NO) : (tabs[i] = YES); +} +.P2 +.sp 100 +.SH +Figure 6a: ADB output for C program of Figure 5 +.LP +.P1 +.ft B +adb a.out \(mi +settab+4:b +fopen+4:b +getc+4:b +tabpos+4:b +$b +.ft R +breakpoints +count bkpt command +1 ~tabpos+04 +1 _getc+04 +1 _fopen+04 +1 ~settab+04 +.ft B +settab,5?ia +.ft R +~settab: jsr r5,csv +~settab+04: tst \(mi(sp) +~settab+06: clr 0177770(r5) +~settab+012: cmp $0120,0177770(r5) +~settab+020: blt ~settab+076 +~settab+022: +.ft B +settab,5?i +.ft R +~settab: jsr r5,csv + tst \(mi(sp) + clr 0177770(r5) + cmp $0120,0177770(r5) + blt ~settab+076 +.ft B +:r +.ft R +a.out: running +breakpoint ~settab+04: tst \(mi(sp) +.ft B +settab+4:d +:c +.ft R +a.out: running +breakpoint _fopen+04: mov 04(r5),nulstr+012 +.ft B +$C +.ft R +_fopen(02302,02472) +~main(01,0177770) + col: 01 + c: 0 + ptab: 03500 +.ft B +tabs,3/8o +.ft R +03500: 01 0 0 0 0 0 0 0 + 01 0 0 0 0 0 0 0 + 01 0 0 0 0 0 0 0 +.P2 +.sp 100 +.SH +Figure 6b: ADB output for C program of Figure 5 +.LP +.P1 +.ft B +:c +.ft R +a.out: running +breakpoint _getc+04: mov 04(r5),r1 +.ft B +ibuf+6/20c +.ft R +__cleanu+0202: This is a test of +.ft B +:c +.ft R +a.out: running +breakpoint ~tabpos+04: cmp $0120,04(r5) +.ft B +tabpos+4:d +settab+4:b settab,5?ia +settab+4:b settab,5?ia; 0 +getc+4,3:b main.c?C; 0 +settab+4:b settab,5?ia; ptab/o; 0 +$b +.ft R +breakpoints +count bkpt command +1 ~tabpos+04 +3 _getc+04 main.c?C;0 +1 _fopen+04 +1 ~settab+04 settab,5?ia;ptab?o;0 +~settab: jsr r5,csv +~settab+04: bpt +~settab+06: clr 0177770(r5) +~settab+012: cmp $0120,0177770(r5) +~settab+020: blt ~settab+076 +~settab+022: +0177766: 0177770 +0177744: @\` +T0177744: T +h0177744: h +i0177744: i +s0177744: s +.P2 +.sp 100 +.SH +Figure 7: ADB output for C program with breakpoints +.LP +.in +.5i +.nf +.ps 8 +.vs 9 +.ft B +adb ex3 \(mi +h+4:b hcnt/d; h.hi/; h.hr/ +g+4:b gcnt/d; g.gi/; g.gr/ +f+4:b fcnt/d; f.fi/; f.fr/ +:r +.ft R +ex3: running +_fcnt: 0 +0177732: 214 +symbol not found +.ft B +f+4:b fcnt/d; f.a/; f.b/; f.fi/ +g+4:b gcnt/d; g.p/; g.q/; g.gi/ +h+4:b hcnt/d; h.x/; h.y/; h.hi/ +:c +.ft R +ex3: running +_fcnt: 0 +0177746: 1 +0177750: 1 +0177732: 214 +_gcnt: 0 +0177726: 2 +0177730: 3 +0177712: 214 +_hcnt: 0 +0177706: 2 +0177710: 1 +0177672: 214 +_fcnt: 1 +0177666: 2 +0177670: 3 +0177652: 214 +_gcnt: 1 +0177646: 5 +0177650: 8 +0177632: 214 +.ft B +HIT DEL +f+4:b fcnt/d; f.a/"a = "d; f.b/"b = "d; f.fi/"fi = "d +g+4:b gcnt/d; g.p/"p = "d; g.q/"q = "d; g.gi/"gi = "d +h+4:b hcnt/d; h.x/"x = "d; h.y/"h = "d; h.hi/"hi = "d +:r +.ft R +ex3: running +_fcnt: 0 +0177746: a = 1 +0177750: b = 1 +0177732: fi = 214 +_gcnt: 0 +0177726: p = 2 +0177730: q = 3 +0177712: gi = 214 +_hcnt: 0 +0177706: x = 2 +0177710: y = 1 +0177672: hi = 214 +_fcnt: 1 +0177666: a = 2 +0177670: b = 3 +0177652: fi = 214 +.ft B +HIT DEL +$q +.in -.5i +.sp 100 +.SH +Figure 8: ADB address maps +.LP +.de l1 +.tc +.ta 1.20i +1.6i +2.5i +.. +.de l3 +.tc +.ta 1.6i +2.80i +.2i +1.55i +.. +.de l2 +.tc +.ti 1.0i +.ta +0.5i +3.0i +1.75i +.tc _ +.. +.de l5 +.tc +.ti 1.0i +.ta +0.75i +3.0i +1.5i +.tc _ +.. +.de l6 +.tc +.ti 1.0i +.ta +.8i +2.85i +0.4i +1.1i +.. +.de l8 +.tc +.ti 1.0i +.ta +0.5i +3.0i +1.75i +.tc _ +.. +.de la +.tc +.ta 1.20i +1.25i +1.7i +.. +.de lc +.tc +.ti 1.0i +.ta +.85i +1.6i +.35i +1.1i +.. +.de lb +.tc +.ti 1.0i +.ta +0.75i +1.75i +1.5i +.tc _ +.. +.ul +407 files +.sp +.l1 +a.out hdr text+data +.l2 +| | | +.l3 + 0 D +.sp +.l1 +core hdr text+data stack +.l5 +| | ......| | +.l6 + 0 D S E +.sp 2 +.ul +410 files (shared text) +.sp +.l1 +a.out hdr text data +.l2 +| | | | +.l3 + 0 T B D +.sp +.la +core hdr data stack +.lb +| | ......| | +.lc + B D S E +.sp 2 +.ul +411 files (separated I and D space) +.sp +.l1 +a.out hdr text data +.l2 +| | | | +.l3 + 0 T 0 D +.sp +.la +core hdr data stack +.lb +| | ......| | +.lc + 0 D S E +.sp 2 +The following +.ul +adb +variables are set. +.nf +.ta .75i 1.5i 3.5i 4.5i 5.5i +.sp + 407 410 411 +.sp + b base of data 0 B 0 + d length of data D D\(miB D + s length of stack S S S + t length of text 0 T T +.sp 100 +.SH +Figure 9: ADB output for maps +.LP +.nf +.in +.5i +.ft B +adb map407 core407 +$m +.ft R +text map \`map407\' +b1 = 0 e1 = 0256 f1 = 020 +b2 = 0 e2 = 0256 f2 = 020 +data map \`core407\' +b1 = 0 e1 = 0300 f1 = 02000 +b2 = 0175400 e2 = 0200000 f2 = 02300 +.ft B +$v +.ft R +variables +d = 0300 +m = 0407 +s = 02400 +.ft B +$q +.sp 2 +adb map410 core410 +$m +.ft R +text map \`map410\' +b1 = 0 e1 = 0200 f1 = 020 +b2 = 020000 e2 = 020116 f2 = 0220 +data map \`core410\' +b1 = 020000 e1 = 020200 f1 = 02000 +b2 = 0175400 e2 = 0200000 f2 = 02200 +.ft B +$v +.ft R +variables +b = 020000 +d = 0200 +m = 0410 +s = 02400 +t = 0200 +.ft B +$q +.sp 2 +adb map411 core411 +$m +.ft R +text map \`map411\' +b1 = 0 e1 = 0200 f1 = 020 +b2 = 0 e2 = 0116 f2 = 0220 +data map \`core411\' +b1 = 0 e1 = 0200 f1 = 02000 +b2 = 0175400 e2 = 0200000 f2 = 02200 +.ft B +$v +.ft R +variables +d = 0200 +m = 0411 +s = 02400 +t = 0200 +.ft B +$q +.in -.5i +.sp 100 +.SH +Figure 10: Simple C program for illustrating formatting and patching +.LP +.P1 +char str1[] "This is a character string"; +int one 1; +int number 456; +long lnum 1234; +float fpt 1.25; +char str2[] "This is the second character string"; +main() +{ + one = 2; +} +.P2 +.sp 100 +.SH +Figure 11: ADB output illustrating fancy formats +.LP +.nf +.ps 9 +.vs 11p +.ft B +adb map410 core410 +b +?m\fIname\fR assign dot to variable or register \fIname\fR +.sp 100 +.SH +Format Summary +.LP +.ta .7i +.nf +\fBa \fRthe value of dot +\fBb \fRone byte in octal +\fBc \fRone byte as a character +\fBd \fRone word in decimal +\fBf \fRtwo words in floating point +\fBi \fRPDP 11 instruction +\fBo \fRone word in octal +\fBn \fRprint a newline +\fBr \fRprint a blank space +\fBs \fRa null terminated character string +\fIn\fBt \fRmove to next \fIn\fR space tab +\fBu \fRone word as unsigned integer +\fBx \fRhexadecimal +\fBY \fRdate +\fB^ \fRbackup dot +\fB"..."\fR print string +.LP +.ta .7i +.SH +Expression Summary +.LP +.ta .7i +a) expression components +.LP +.ta .1.1i +.nf +\fBdecimal integer \fRe.g. 256 +\fBoctal integer \fRe.g. 0277 +\fBhexadecimal \fRe.g. #ff +\fBsymbols \fRe.g. flag _main main.argc +\fBvariables \fRe.g. + struct buf { + int fildes; + int nleft; + char *nextp; + char buff[512]; + }bb; + struct buf *obuf; + + char *charp "this is a sentence."; + + main(argc,argv) + int argc; + char **argv; + { + char cc; + + if(argc < 2) { + printf("Input file missing\n"); + exit(8); + } + + if((fcreat(argv[1],obuf)) < 0){ + printf("%s : not found\n", argv[1]); + exit(8); + } + charp = 'T'; + printf("debug 1 %s\n",charp); + while(cc= *charp++) + putc(cc,obuf); + fflush(obuf); + } + + +=== Figure 2: ADB output for C program of Figure 1 === + **adb a.out core** + **$c** + ~main(02,0177762) + **$C** + ~main(02,0177762) + argc: 02 + argv: 0177762 + cc: 02124 + **$r** + ps 0170010 + pc 0204 ~main+0152 + sp 0177740 + r5 0177752 + r4 01 + r3 0 + r2 0 + r1 0 + r0 0124 + ~main+0152: mov _obuf,(sp) + **$e** + savr5: 0 + _obuf: 0 + _charp: 0124 + _errno: 0 + _fout: 0 + **$m** + text map `ex1' + b1 = 0 e1 = 02360 f1 = 020 + b2 = 0 e2 = 02360 f2 = 020 + data map `core1' + b1 = 0 e1 = 03500 f1 = 02000 + b2 = 0175400 e2 = 0200000 f2 = 05500 + ***charp/s** + 0124: TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTLxNh@x&_ + ~ + **charp/s** + _charp: T + + _charp+02: this is a sentence. + + _charp+026: Input file missing + **main.argc/d** + 0177756: 2 + ***main.argv/3o** + 0177762: 0177770 0177776 0177777 + **0177770/s** + 0177770: a.out + ***main.argv/3o** + 0177762: 0177770 0177776 0177777 + ***"/s** + 0177770: a.out + **.=o** + 0177770 + **.-10/d** + 0177756: 2 + **$q** + +=== Figure 3: Multiple function C program for stack trace === + + int fcnt,gcnt,hcnt; + h(x,y) + { + int hi; register int hr; + hi = x+1; + hr = x-y+1; + hcnt++ ; + hj: + f(hr,hi); + } + + g(p,q) + { + int gi; register int gr; + gi = q-p; + gr = q-p+1; + gcnt++ ; + gj: + h(gr,gi); + } + + f(a,b) + { + int fi; register int fr; + fi = a+2*b; + fr = a+b; + fcnt++ ; + fj: + g(fr,fi); + } + + main() + { + f(1,1); + } + + +=== Figure 4: ADB output for C program of Figure 3 === + **adb** + **$c** + ~h(04452,04451) + ~g(04453,011124) + ~f(02,04451) + ~h(04450,04447) + ~g(04451,011120) + ~f(02,04447) + ~h(04446,04445) + ~g(04447,011114) + ~f(02,04445) + ~h(04444,04443) + **HIT DEL KEY** + adb + **,5$C** + ~h(04452,04451) + x: 04452 + y: 04451 + hi: ? + ~g(04453,011124) + p: 04453 + q: 011124 + gi: 04451 + gr: ? + ~f(02,04451) + a: 02 + b: 04451 + fi: 011124 + fr: 04453 + ~h(04450,04447) + x: 04450 + y: 04447 + hi: 04451 + hr: 02 + ~g(04451,011120) + p: 04451 + q: 011120 + gi: 04447 + gr: 04450 + **fcnt/d** + _fcnt: 1173 + **gcnt/d** + _gcnt: 1173 + **hcnt/d** + _hcnt: 1172 + **h.x/d** + 022004: 2346 + **$q** + +=== Figure 5: C program to decode tabs === + + #define MAXLINE 80 + #define YES 1 + #define NO 0 + #define TABSP 8 + char input[] "data"; + char ibuf[518]; + int tabs[MAXLINE]; + main() + { + int col, *ptab; + char c; + ptab = tabs; + settab(ptab); /*Set initial tab stops */ + col = 1; + if(fopen(input,ibuf) < 0) { + printf("%s : not found\n",input); + exit(8); + } + while((c = getc(ibuf)) != -1) { + switch(c) { + case '\t': /* TAB */ + while(tabpos(col) != YES) { + putchar(' '); /* put BLANK */ + col++ ; + } + break; + case '\n': /*NEWLINE */ + putchar('\n'); + col = 1; + break; + default: + putchar(c); + col++ ; + } + } + } + /* Tabpos return YES if col is a tab stop */ + tabpos(col) + int col; + { + if(col > MAXLINE) + return(YES); + else + return(tabs[col]); + } + /* Settab - Set initial tab stops */ + settab(tabp) + int *tabp; + { + int i; + for(i = 0; i<= MAXLINE; i++) + (i%TABSP) ? (tabs[i] = NO) : (tabs[i] = YES); + } + + +=== Figure 6a: ADB output for C program of Figure 5 === + **adb a.out -** + **settab+4:b** + **fopen+4:b** + **getc+4:b** + **tabpos+4:b** + **$b** + breakpoints + count bkpt command + 1 ~tabpos+04 + 1 _getc+04 + 1 _fopen+04 + 1 ~settab+04 + **settab,5?ia** + ~settab: jsr r5,csv + ~settab+04: tst -(sp) + ~settab+06: clr 0177770(r5) + ~settab+012: cmp $0120,0177770(r5) + ~settab+020: blt ~settab+076 + ~settab+022: + **settab,5?i** + ~settab: jsr r5,csv + tst -(sp) + clr 0177770(r5) + cmp $0120,0177770(r5) + blt ~settab+076 + **:r** + a.out: running + breakpoint ~settab+04: tst -(sp) + **settab+4:d** + **:c** + a.out: running + breakpoint _fopen+04: mov 04(r5),nulstr+012 + **$C** + _fopen(02302,02472) + ~main(01,0177770) + col: 01 + c: 0 + ptab: 03500 + **tabs,3/8o** + 03500: 01 0 0 0 0 0 0 0 + 01 0 0 0 0 0 0 0 + 01 0 0 0 0 0 0 0 + + +=== Figure 6b: ADB output for C program of Figure 5 === + **:c** + a.out: running + breakpoint _getc+04: mov 04(r5),r1 + **ibuf+6/20c** + __cleanu+0202: This is a test of + **:c** + a.out: running + breakpoint ~tabpos+04: cmp $0120,04(r5) + **tabpos+4:d** + **settab+4:b settab,5?ia** + **settab+4:b settab,5?ia; 0** + **getc+4,3:b main.c?C; 0** + **settab+4:b settab,5?ia; ptab/o; 0** + **$b** + breakpoints + count bkpt command + 1 ~tabpos+04 + 3 _getc+04 main.c?C;0 + 1 _fopen+04 + 1 ~settab+04 settab,5?ia;ptab?o;0 + ~settab: jsr r5,csv + ~settab+04: bpt + ~settab+06: clr 0177770(r5) + ~settab+012: cmp $0120,0177770(r5) + ~settab+020: blt ~settab+076 + ~settab+022: + 0177766: 0177770 + 0177744: @` + T0177744: T + h0177744: h + i0177744: i + s0177744: s + +=== Figure 7: ADB output for C program with breakpoints === + **adb ex3 -** + **h+4:b hcnt/d; h.hi/; h.hr/** + **g+4:b gcnt/d; g.gi/; g.gr/** + **f+4:b fcnt/d; f.fi/; f.fr/** + **:r** + ex3: running + _fcnt: 0 + 0177732: 214 + symbol not found + **f+4:b fcnt/d; f.a/; f.b/; f.fi/** + **g+4:b gcnt/d; g.p/; g.q/; g.gi/** + **h+4:b hcnt/d; h.x/; h.y/; h.hi/** + **:c** + ex3: running + _fcnt: 0 + 0177746: 1 + 0177750: 1 + 0177732: 214 + _gcnt: 0 + 0177726: 2 + 0177730: 3 + 0177712: 214 + _hcnt: 0 + 0177706: 2 + 0177710: 1 + 0177672: 214 + _fcnt: 1 + 0177666: 2 + 0177670: 3 + 0177652: 214 + _gcnt: 1 + 0177646: 5 + 0177650: 8 + 0177632: 214 + **HIT DEL** + **f+4:b fcnt/d; f.a/"a = "d; f.b/"b = "d; f.fi/"fi = "d** + **g+4:b gcnt/d; g.p/"p = "d; g.q/"q = "d; g.gi/"gi = "d** + **h+4:b hcnt/d; h.x/"x = "d; h.y/"h = "d; h.hi/"hi = "d** + **:r** + ex3: running + _fcnt: 0 + 0177746: a = 1 + 0177750: b = 1 + 0177732: fi = 214 + _gcnt: 0 + 0177726: p = 2 + 0177730: q = 3 + 0177712: gi = 214 + _hcnt: 0 + 0177706: x = 2 + 0177710: y = 1 + 0177672: hi = 214 + _fcnt: 1 + 0177666: a = 2 + 0177670: b = 3 + 0177652: fi = 214 + **HIT DEL** + **$q** + + +=== Figure 8: ADB address maps === + +a.out hdr text+data + |____|_____________________________| + 0 D + +core hdr text+data stack + |______|_____________________________......|________| + 0 D S E + + +The following ''adb'' variables are set. + +|| b || base of data || 0 || +|| d || length of data || D || +|| s || length of stack || S || +|| t || length of text || 0 || + + +=== Figure 9: ADB output for maps === + **adb map core** + **$m** + text map `map' + b1 = 0 e1 = 0256 f1 = 020 + b2 = 0 e2 = 0256 f2 = 020 + data map `core' + b1 = 0 e1 = 0300 f1 = 02000 + b2 = 0175400 e2 = 0200000 f2 = 02300 + **$v** + variables + d = 0300 + m = 0407 + s = 02400 + **$q** + +=== Figure 10: Simple C program for illustrating formatting and patching === + + char str1[] "This is a character string"; + int one 1; + int number 456; + long lnum 1234; + float fpt 1.25; + char str2[] "This is the second character string"; + main() + { + one = 2; + } + + +=== Figure 11: ADB output illustrating fancy formats === + +**adb map410 core410** +** + + +=== Figure 12: Directory and inode dumps === + +**adb dir -** +**=nt"Inode"t"Name"** +**0,-1?ut14cn** + + Inode Name +0: 652 . + 82 .. + 5971 cap.c + 5323 cap + 0 pp + + + + +**adb /dev/src -** +**02000>b** +**?m diff --git a/src/cmd/adb/doc/adb-summary.txt b/src/cmd/adb/doc/adb-summary.txt new file mode 100644 index 0000000..336aabe --- /dev/null +++ b/src/cmd/adb/doc/adb-summary.txt @@ -0,0 +1,91 @@ +=== ADB Summary === + +== Command Summary == + +a) formatted printing + +|| ? format || print from ''a.out'' file according to format || +|| / format || print from ''core'' file according to format || +|| = format || print the value of dot || +|| ?w expr || write expression into ''a.out'' file || +|| /w expr || write expression into ''core'' file || +|| ?l expr || locate expression in ''a.out'' file || + +b) breakpoint and program control + +|| :b || set breakpoint at dot || +|| :c || continue running program || +|| :d || delete breakpoint || +|| :k || kill the program being debugged || +|| :r || run ''a.out'' file under ADB control || +|| :s || single step || + +c) miscellaneous printing + +|| $b || print current breakpoints || +|| $c || C stack trace || +|| $e || external variables || +|| $f || floating registers || +|| $m || print ADB segment maps || +|| $q || exit from ADB || +|| $r || general registers || +|| $s || set offset for symbol match || +|| $v || print ADB variables || +|| $w || set output line width || + +d) calling the shell + +|| ! || call shell to read rest of line || + +e) assignment to variables + +|| >name || assign dot to variable or register name || + + +== Format Summary == + +|| a || the value of dot || +|| b || one byte in octal || +|| c || one byte as a character || +|| d || one word in decimal || +|| f || two words in floating point || +|| i || PDP 11 instruction || +|| o || one word in octal || +|| n || print a newline || +|| r || print a blank space || +|| s || a null terminated character string || +|| nt || move to next n space tab || +|| u || one word as unsigned integer || +|| x || hexadecimal || +|| Y || date || +|| ^ || backup dot || +|| "..." || print string || + + +== Expression Summary == + +a) expression components + +|| decimal integer || e.g. 256 || +|| octal integer || e.g. 0277 || +|| hexadecimal || e.g. #ff || +|| symbols || e.g. flag _main main.argc || +|| variables || e.g. 0 .ta \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 +.if \\n(.$=0 .ta 1i 1.7i 2.5i +.ft 3 +.nf +.. +.de P2 +.sp .5 +.ft 1 +.fi +.. +.RP +.....TM "77-8234-11 77-1273-10" "49170-220 39199" "40952-1 39199-11" +.ND May 5, 1977 +.TL +A Tutorial Introduction to ADB +.AU "MH2F-207" "3816" +J. F. Maranzano +.AU "MH2C-512" 7419 +S. R. Bourne +.AI +.MH +.OK +UNIX +Debugging +C Programming +.AB +.PP +Debugging tools generally provide a wealth of information +about the inner workings of programs. +These tools have been available on +.UX +to allow users to +examine ``core'' files +that result from aborted programs. +A new debugging program, ADB, provides enhanced capabilities +to examine "core" and other program files in a +variety of formats, run programs with embedded breakpoints and patch files. +.PP +ADB is an indispensable but complex tool for debugging crashed systems and/or +programs. +This document provides an introduction to ADB with examples of its use. +It explains the various formatting options, +techniques for debugging C programs, examples of printing +file system information and patching. +.AE +.CS 12 15 27 13 0 5 +.NH +Introduction +.PP +ADB is a new debugging program that is +available on UNIX. +It provides capabilities to look at +``core'' files resulting from aborted programs, print output in a +variety of formats, patch files, and run programs +with embedded breakpoints. +This document provides examples of +the more useful features of ADB. +The reader is expected to be +familiar with the basic commands on +.UX +with the C +language, and with References 1, 2 and 3. +.NH +A Quick Survey +.NH 2 +Invocation +.PP +ADB is invoked as: +.P1 + adb objfile corefile +.P2 +where +.ul +objfile +is an executable UNIX file and +.ul +corefile +is a core image file. +Many times this will look like: +.P1 + adb a.out core +.P2 +or more simply: +.P1 + adb +.P2 +where the defaults are +.ul +a.out +and +.ul +core +respectively. +The filename minus (\-) means ignore this argument as in: +.P1 + adb \- core +.P2 +.PP +ADB has requests for examining locations in either file. +The +\fB?\fP +request examines the contents of +.ul +objfile, +the +\fB/\fP +request examines the +.ul +corefile. +The general form of these requests is: +.P1 + address ? format +.P2 +or +.P1 + address / format +.P2 +.NH 2 +Current Address +.PP +ADB maintains a current address, called dot, +similar in function to the current pointer in the UNIX editor. +When an address is entered, the current address is set to that location, +so that: +.P1 + 0126?i +.P2 +sets dot to octal 126 and prints the instruction +at that address. +The request: +.P1 + .,10/d +.P2 +prints 10 decimal numbers starting at dot. +Dot ends up referring to the address of the last item printed. +When used with the \fB?\fP or \fB/\fP requests, +the current address can be advanced by typing newline; it can be decremented +by typing \fB^\fP. +.PP +Addresses are represented by +expressions. +Expressions are made up from decimal, octal, and hexadecimal integers, +and symbols from the program under test. +These may be combined with the operators +, \-, *, % (integer division), +& (bitwise and), | (bitwise inclusive or), # (round up +to the next multiple), and ~ (not). +(All arithmetic within ADB is 32 bits.) +When typing a symbolic address for a C program, +the user can type +.ul +name +or +.ul +_name; +ADB will recognize both forms. +.NH 2 +Formats +.PP +To print data, a user specifies a collection of letters and characters +that describe the format of the printout. +Formats are "remembered" in the sense that typing a request without one +will cause the new printout to appear in the previous format. +The following are the most commonly used format letters. +.P1 +\fB b \fPone byte in octal +\fB c \fPone byte as a character +\fB o \fPone word in octal +\fB d \fPone word in decimal +\fB f \fPtwo words in floating point +\fB i \fPPDP 11 instruction +\fB s \fPa null terminated character string +\fB a \fPthe value of dot +\fB u \fPone word as unsigned integer +\fB n \fPprint a newline +\fB r \fPprint a blank space +\fB ^ \fPbackup dot +.P2 +(Format letters are also available for "long" values, +for example, `\fBD\fR' for long decimal, and `\fBF\fP' for double floating point.) +For other formats see the ADB manual. +.NH 2 +General Request Meanings +.PP +The general form of a request is: +.P1 + address,count command modifier +.P2 +which sets `dot' to \fIaddress\fP +and executes the command +\fIcount\fR times. +.PP +The following table illustrates some general ADB command meanings: +.P1 + Command Meaning +\fB ? \fPPrint contents from \fIa.out\fP file +\fB / \fPPrint contents from \fIcore\fP file +\fB = \fPPrint value of "dot" +\fB : \fPBreakpoint control +\fB $ \fPMiscellaneous requests +\fB ; \fPRequest separator +\fB ! \fPEscape to shell +.P2 +.PP +ADB catches signals, so a user cannot use a quit signal to exit from ADB. +The request $q or $Q (or cntl-D) must be used +to exit from ADB. +.NH +Debugging C Programs +.NH 2 +Debugging A Core Image +.PP +Consider the C program in Figure 1. +The program is used to illustrate a common error made by +C programmers. +The object of the program is to change the +lower case "t" to upper case in the string pointed to by +.ul +charp +and then write the character string to the file indicated by +argument 1. +The bug shown is that the character "T" +is stored in the pointer +.ul +charp +instead of the string pointed to by +.ul +charp. +Executing the program produces a core file because of an out of bounds memory reference. +.PP +ADB is invoked by: +.P1 + adb a.out core +.P2 +The first debugging request: +.P1 + $c +.P2 +is used to give a C backtrace through the +subroutines called. +As shown in Figure 2 +only one function (\fImain\fR) was called and the +arguments +.ul +argc +and +.ul +argv +have octal values 02 and +0177762 respectively. +Both of these values look +reasonable; 02 = two arguments, 0177762 = address on stack +of parameter vector. +.br +The next request: +.P1 + $C +.P2 +is used to give a C backtrace plus an interpretation +of all the local variables in each function and their +values in octal. +The value of the variable +.ul +cc +looks incorrect +since +.ul +cc +was declared as a character. +.PP +The next request: +.P1 + $r +.P2 +prints out the registers including the program +counter and an interpretation of the instruction at that +location. +.PP +The request: +.P1 + $e +.P2 +prints out the values of all external variables. +.PP +A map exists for each file +handled by +ADB. +The map for the +.ul +a.out +file is referenced by \fB?\fP whereas the map for +.ul +core +file is referenced by \fB/\fP. +Furthermore, a good rule of thumb is to use \fB?\fP for +instructions and \fB/\fP for data when looking at programs. +To print out information about the maps type: +.P1 + $m +.P2 +This produces a report of the contents of the maps. +More about these maps later. +.PP +In our example, it is useful to see the +contents of the string pointed to by +.ul +charp. +This is done by: +.P1 + *charp/s +.P2 +which says use +.ul +charp +as a pointer in the +.ul +core +file +and print the information as a character string. +This printout clearly shows that the character buffer +was incorrectly overwritten and helps identify the error. +Printing the locations around +.ul +charp +shows that the buffer is unchanged +but that the pointer is destroyed. +Using ADB similarly, we could print information about the +arguments to a function. +The request: +.P1 + main.argc/d +.P2 +prints the decimal +.ul +core +image value of the argument +.ul +argc +in the function +.ul +main. +.br +The request: +.P1 + *main.argv,3/o +.P2 +prints the octal values of the three consecutive +cells pointed to by +.ul +argv +in the function +.ul +main. +Note that these values are the addresses of the arguments +to main. +Therefore: +.P1 + 0177770/s +.P2 +prints the ASCII value of the first argument. +Another way to print this value would have been +.P1 + *"/s +.P2 +The " means ditto which remembers the last address +typed, in this case \fImain.argc\fP ; the \fB*\fP instructs ADB to use the address field of the +.ul +core +file as a pointer. +.PP +The request: +.P1 + .=o +.P2 +prints the current address (not its contents) in octal which has been set to the address of the first argument. +The current address, dot, is used by ADB to +"remember" its current location. +It allows the user +to reference locations relative to the current +address, for example: +.P1 + .\-10/d +.P2 +.NH 2 +Multiple Functions +.PP +Consider the C program illustrated in +Figure 3. +This program calls functions +.ul +f, g, +and +.ul +h +until the stack is exhausted and a core image is produced. +.PP +Again you can enter the debugger via: +.P1 + adb +.P2 +which assumes the names +.ul +a.out +and +.ul +core +for the executable +file and core image file respectively. +The request: +.P1 + $c +.P2 +will fill a page of backtrace references to +.ul +f, g, +and +.ul +h. +Figure 4 shows an abbreviated list (typing +.ul +DEL +will terminate the output and bring you back to ADB request level). +.PP +The request: +.P1 + ,5$C +.P2 +prints the five most recent activations. +.PP +Notice that each function +(\fIf,g,h\fP) has a counter +of the number of times it was called. +.PP +The request: +.P1 + fcnt/d +.P2 +prints the decimal value of the counter for the function +.ul +f. +Similarly +.ul +gcnt +and +.ul +hcnt +could be printed. +To print the value of an automatic variable, +for example the decimal value of +.ul +x +in the last call of the function +.ul +h, +type: +.P1 + h.x/d +.P2 +It is currently not possible in the exported version to print stack frames other than the most recent activation of a function. +Therefore, a user can print everything with +\fB$C\fR or the occurrence of a variable in the most recent call of a function. +It is possible with the \fB$C\fR request, however, to print the stack frame +starting at some address as \fBaddress$C.\fR +.NH 2 +Setting Breakpoints +.PP +Consider the C program in Figure 5. +This program, which changes tabs into blanks, is adapted from +.ul +Software Tools +by Kernighan and Plauger, pp. 18-27. +.PP +We will run this program under the control of ADB (see Figure 6a) by: +.P1 + adb a.out \- +.P2 +Breakpoints are set in the program as: +.ul +.P1 + address:b [request] +.P2 +The requests: +.P1 + settab+4:b + fopen+4:b + getc+4:b + tabpos+4:b +.P2 +set breakpoints at the start of these functions. +C does not generate statement labels. +Therefore it is currently not possible to plant breakpoints at locations +other than function entry points without a knowledge of the code +generated by the C compiler. +The above addresses are entered as +.ft B +symbol+4 +.ft R +so that they will appear in any +C backtrace since the first instruction of each function is a call +to the C save routine +(\fIcsv\fR). +Note that some of the functions are from the C library. +.PP +To print the location of breakpoints one types: +.P1 + $b +.P2 +The display indicates a +.ul +count +field. +A breakpoint is bypassed +.ul +count \-1 +times before causing a stop. +The +.ul +command +field indicates the ADB requests to be executed each time the breakpoint is encountered. +In our example no +.ul +command +fields are present. +.PP +By displaying the original instructions at the function +.ul +settab +we see that +the breakpoint is set after the jsr to the C save routine. +We can display the instructions using the ADB request: +.P1 + settab,5?ia +.P2 +This request displays five instructions starting at +.ul +settab +with the addresses of each location displayed. +Another variation is: +.P1 + settab,5?i +.P2 +which displays the instructions with only the starting address. +.PP +Notice that we accessed the addresses from the +.ul +a.out +file with the \fB?\fP command. +In general when asking for a printout of multiple items, +ADB will advance the current address the number of +bytes necessary to satisfy the request; in the above +example five instructions were displayed and the current address was +advanced 18 (decimal) bytes. +.PP +To run the program one simply types: +.P1 + :r +.P2 +To delete a breakpoint, for instance the entry to the function +.ul +settab, +one types: +.P1 + settab+4:d +.P2 +To continue execution of the program from the breakpoint type: +.P1 + :c +.PP +Once the program has stopped (in this case at the breakpoint for +.ul +fopen), +ADB requests can be used to display the contents of memory. +For example: +.P1 + $C +.P2 +to display a stack trace, or: +.P1 + tabs,3/8o +.P2 +to print three lines of 8 locations each from the array called +.ul +tabs. +By this time (at location +.ul +fopen) +in the C program, +.ul +settab +has been called and should have set a one in every eighth location of +.ul +tabs. +.NH 2 +Advanced Breakpoint Usage +.PP +We continue execution of the program with: +.P1 + :c +.P2 +See Figure 6b. +.ul +Getc +is called three times and the contents of the variable +.ul +c +in the function +.ul +main +are displayed +each time. +The single character on the left hand edge is the output from the C program. +On the third occurrence of +.ul +getc +the program stops. +We can look at the full buffer of characters by typing: +.P1 + ibuf+6/20c +.P2 +When we continue the program with: +.P1 + :c +.P2 +we hit our first breakpoint at +.ul +tabpos +since there is a tab following the +"This" word of the data. +.PP +Several breakpoints of +.ul +tabpos +will occur until the program has changed the tab into equivalent blanks. +Since we feel that +.ul +tabpos +is working, +we can remove the breakpoint at that location by: +.P1 + tabpos+4:d +.P2 +If the program is continued with: +.P1 + :c +.P2 +it resumes normal execution after ADB prints +the message +.P1 + a.out:running +.P2 +.PP +The UNIX quit and interrupt signals +act on ADB itself rather than on the program being debugged. +If such a signal occurs then the program being debugged is stopped and control is returned to ADB. +The signal is saved by ADB and is passed on to the test program if: +.P1 + :c +.P2 +is typed. +This can be useful when testing interrupt +handling routines. +The signal is not passed on to the test program if: +.P1 + :c 0 +.P2 +is typed. +.PP +Now let us reset the breakpoint at +.ul +settab +and display the instructions located there when we reach the breakpoint. +This is accomplished by: +.P1 + settab+4:b settab,5?ia \fR* +.P2 +.FS +* Owing to a bug in early versions of ADB (including the +version distributed in Generic 3 UNIX) these statements +must be written as: +.br +.in 1i +\fBsettab+4:b settab,5?ia;0\fR +.ft B +.br +getc+4,3:b main.c?C;0 +.br +settab+4:b settab,5?ia; ptab/o;0 +.br +.ft R +.in -1i +Note that \fB;0\fR will set dot to zero and stop at the breakpoint. +.FE +It is also possible to execute the ADB requests for each occurrence of the breakpoint but +only stop after the third occurrence by typing: +.P1 + getc+4,3:b main.c?C \fR* +.P2 +This request will print the local variable +.ul +c +in the function +.ul +main +at each occurrence of the breakpoint. +The semicolon is used to separate multiple ADB requests on a single line. +.PP +Warning: +setting a breakpoint causes the value of dot to be changed; +executing the program under ADB does not change dot. +Therefore: +.P1 + settab+4:b .,5?ia + fopen+4:b +.P2 +will print the last thing dot was set to +(in the example \fIfopen+4\fP) +.ul +not +the current location (\fIsettab+4\fP) +at which the program is executing. +.PP +A breakpoint can be overwritten without first deleting the old breakpoint. +For example: +.P1 + settab+4:b settab,5?ia; ptab/o \fR* +.P2 +could be entered after typing the above requests. +.PP +Now the display of breakpoints: +.P1 + $b +.P2 +shows the above request for the +.ul +settab +breakpoint. +When the breakpoint at +.ul +settab +is encountered the ADB requests are executed. +Note that the location at +.ul +settab+4 +has been changed to plant the breakpoint; +all the other locations match their original value. +.PP +Using the functions, +.ul +f, g +and +.ul +h +shown in Figure 3, +we can follow the execution of each function by planting non-stopping +breakpoints. +We call ADB with the executable program of Figure 3 as follows: +.P1 + adb ex3 \- +.P2 +Suppose we enter the following breakpoints: +.P1 + h+4:b hcnt/d; h.hi/; h.hr/ + g+4:b gcnt/d; g.gi/; g.gr/ + f+4:b fcnt/d; f.fi/; f.fr/ + :r +.P2 +Each request line indicates that the variables are printed in decimal +(by the specification \fBd\fR). +Since the format is not changed, the \fBd\fR can be left off all but +the first request. +.PP +The output in Figure 7 illustrates two points. +First, the ADB requests in the breakpoint line are not +examined until the program under +test is run. +That means any errors in those ADB requests is not detected until run time. +At the location of the error ADB stops running the program. +.PP +The second point is the way ADB handles register variables. +ADB uses the symbol table to address variables. +Register variables, like \fIf.fr\fR above, have pointers to uninitialized +places on the stack. +Therefore the message "symbol not found". +.PP +Another way of getting at the data in this example is to print +the variables used in the call as: +.P1 + f+4:b fcnt/d; f.a/; f.b/; f.fi/ + g+4:b gcnt/d; g.p/; g.q/; g.gi/ + :c +.P2 +The operator / was used instead of ? +to read values from the \fIcore\fP file. +The output for each function, as shown in Figure 7, has the same format. +For the function \fIf\fP, for example, it shows the name and value of the +.ul +external +variable +.ul +fcnt. +It also shows the address on the stack and value of the +variables +.ul +a, b +and +.ul +fi. +.PP +Notice that the addresses on the stack will continue to decrease +until no address space is left for program execution +at which time (after many pages of output) +the program under test aborts. +A display with names would be produced by requests like the following: +.P1 + f+4:b fcnt/d; f.a/"a="d; f.b/"b="d; f.fi/"fi="d +.P2 +In this format the quoted string is printed literally and the \fBd\fP +produces a decimal display of the variables. +The results are shown in Figure 7. +.NH 2 +Other Breakpoint Facilities +.LP +.IP \(bu 4 +Arguments and change of standard input and output are passed to a program as: +.P1 + :r arg1 arg2 ... outfile +.P2 +This request +kills any existing program under test and +starts the +.ul +a.out +afresh. +.IP \(bu +The program being debugged can be single stepped +by: +.P1 + :s +.P2 +If necessary, this request will start up the program being +debugged and stop after executing +the first instruction. +.IP \(bu +ADB allows a program to be entered at a specific address +by typing: +.P1 + address:r +.P2 +.IP \(bu +The count field can be used to skip the first \fIn\fR breakpoints as: +.P1 + ,n:r +.P2 +The request: +.P1 + ,n:c +.P2 +may also be used for skipping the first \fIn\fR breakpoints +when continuing a program. +.sp +.IP \(bu +A program can be continued at an address different from the breakpoint by: +.P1 + address:c +.P2 +.IP \(bu +The program being debugged runs as a separate process and can be killed by: +.P1 + :k +.P2 +.LP +.NH +Maps +.PP +UNIX supports several executable file formats. These are used to tell +the loader how to load the program file. File type 407 +is the most common and is generated by a C compiler invocation such as +\fBcc pgm.c\fP. +A 410 file is produced by a C compiler command of the form \fBcc -n pgm.c\fP, +whereas a 411 file is produced by \fBcc -i pgm.c\fP. +ADB interprets these different file formats and +provides access to the different segments through a set of maps (see Figure 8). +To print the maps type: +.P1 + $m +.P2 +.PP +In 407 files, both text (instructions) and data are intermixed. +This makes it impossible for ADB to differentiate data from +instructions and some of the printed symbolic addresses look incorrect; +for example, printing data addresses as offsets from routines. +.PP +In 410 files (shared text), the instructions are separated from data and +\fB?*\fR accesses the data part of the \fIa.out\fP file. +The \fB?* \fP request tells ADB to use the second part of the +map in the +.ul +a.out +file. +Accessing data in the \fIcore\fP file shows +the data after it was modified by the execution of the program. +Notice also that the data segment may have grown during +program execution. +.PP +In 411 files (separated I & D space), the +instructions and data are also separated. +However, in this +case, since data is mapped through a separate set of segmentation +registers, the base of the data segment is also relative to address zero. +In this case since the addresses overlap it is necessary to use +the \fB?*\fR operator to access the data space of the \fIa.out\fP file. +In both 410 and 411 files the corresponding +core file does not contain the program text. +.PP +Figure 9 shows the display of three maps +for the same program linked as a 407, 410, 411 respectively. +The b, e, and f fields are used by ADB to map +addresses into file addresses. +The "f1" field is the +length of the header at the beginning of the file (020 bytes +for an \fIa.out\fP file and 02000 bytes for a \fIcore\fP file). +The "f2" field is the displacement from the beginning of the file to the data. +For a 407 file with mixed text and data this is the +same as the length of the header; for 410 and 411 files this +is the length of the header plus the size of the text portion. +.PP +The "b" and "e" fields are the starting and ending locations +for a segment. +Given an address, A, the location in +the file (either \fIa.out\fP or \fIcore\fP) is calculated as: +.P1 + b1\(<=A\(<=e1 =\h'-.5m'> file address = (A\-b1)+f1 + b2\(<=A\(<=e2 =\h'-.5m'> file address = (A\-b2)+f2 +.P2 +A user can access locations by using the ADB defined variables. +The \fB$v\fR request prints the variables initialized by ADB: +.P1 + b base address of data segment + d length of the data segment + s length of the stack + t length of the text + m execution type (407,410,411) +.P2 +.PP +In Figure 9 those variables not present are zero. +Use can be made of these variables by expressions such as: +.P1 + b +.P2 +that sets \fBb\fP to octal 2000. +These variables are useful to know if the file under examination +is an executable or \fIcore\fP image file. +.PP +ADB reads the header of the \fIcore\fP image file to find the +values for these variables. +If the second file specified does not +seem to be a \fIcore\fP file, or if it is missing then the header of +the executable file is used instead. +.NH +Advanced Usage +.PP +It is possible with ADB to combine formatting requests +to provide elaborate displays. +Below are several examples. +.NH 2 +Formatted dump +.PP +The line: +.P1 + b + ?m TikS%8OOAz~u3H?o4^<%MCCF|{*yu^{4NVuN86v$SzB zbs}OEvoUlr6)`ooH!+3b=ZA52aWXZug@=)dG*Q{G+u%gwc2ODEvSd>9WHKtfAcd;E4BjsZkH8qiLRVZ|_s5Ar zhJ5{Nmx=9@Dwy*AfxPe+&{e1u?l^OAnkysvx6T5O;emWREru ze2HQI{$o-KFD_3bF+tl_@2;D`7$41qirbw(F)H0Y*5U(+BGerv%WVRAL=LG@KcqJ? z(D8LkB2sh&)kJ17b`^lq=#+{vtqU8GCYeDlErCh>d*bKeVnDyJf6b4%1j;Y!mB;9< zR2fCg#UTing=}3=EQ^@YONmBK$^TT5rv9IAQ)6LGz9*hQ`5mu>`E7^``%|T6CaJZ|W^&q=o z#Lr3&5EQOMs~S})xfm&PG*un(yb?maK_Zod#I|P|19Q45`~_mFkH2n)tRJ+9@PjZ@ zD3LSJ|7&RC4IyHn&|fYDhf6wSU1DwOtzL=RyonzjQaIFPD>O}kU#nP34V|yzx+A&7 zgBnw*LFKx^W-KjXl*uiOEYfOL4JgJF@<%zmhLOFu%!jflySQEgcYaTV1VUxc>;xB=eFz-!o%PQW1 z<^8;L^cZY8rDXC6cn0{&*M3ju^#|j0^1{p&^B%tz3tk*)Mu2kI;xfiFHdl=#ACk1+ z<#wq$GB0P-2Z+ard0m-hQtbQ&k0O%uC8b$|d64Sr_AVK*LwfiDfdiVa+dhFYwKMsD zbMjx&zY>}C-x6BE$=+Dm)P+c!@t>?GVpK8pa3RwDC%5hGT!{Xa@M0`PfPaoF{SyI* z*#0YGCu09U(LdSFDC*%NuI%#93-EuAiz_n|as2n*KimIxBQw)KYyZDDgc-oj{vSLd zA?mjF8|+Bm)%uP*H1O=CN;h9hfU9*j3)srLT41@rc?{c%IqBkbv$dKXe95u21rw_C z(c`=8y{(5$#dO+}eO)L#HJn&Ucjf?D3MMTj5% z5(!T%X}>4>b$DRnickDv5}K+-=H2Uv;or>};o`F%`C~$R;cvQiy2UTu zPbP#!$JggDwF?_OVb)uks7-6jePj@sh4Rxn)}>+!O?XsnNe--rpM!>6lwXHp(&Q!p zZ%a$K+fqP>d8_G3;&cOFOuOV3CB&C;+cn!5$cSGeD_Khlk&?UyJ$|4^?*q?)F6KBS()=2Rk(!#CQdR^+-g!=T7Izb_)GGBFVwL7VxeUS*STGS5SmO(PO8qvXQw^L`*RAN4 zO2s*S`yMQk7qJ2B+#4k~_8BRb#@H7>+J^S+>0M@qeCROZ(c7prY{(_sUgs<_@pzxOc1 z1ge2SBRjH=N0uR0k~5RcFbyZUN&2zImi|oGHe63S;MKlNM6-p-28%%>g($odRS1tv zKpc;$?~M)*UqMjOu*eo@KTKY?lK%|TS23|OBH(3JH)edi|M2<9leDiH&mhB7j$C+2 z=FNv8S=PFB1AX))Je@UY3U2O-E{m0es*k3Ul zPT*a)FR0-l&d8cJX`^cINhH@kR%md#J5d(3lTy{g@qIe*{F#0#E_OmpzM1)P&5YYi zw5K7srWuk%g2-FvN@pMHXmJ0*8f4PBW0_+|j18nrX>ZjEj2bRL_NB+^Vx5L42PMQg z)J8}KG$)78DYpkWPeE0#^UTDnWb+ihUN#TFFX(|eDEJV5+u@P@uq~IgCf+Z%EBSRV zu{3osKkCQzLpWRua0=;5cgwGs#_9V|tgist&m$onvIYO-!n~+b|M3{0wjScQ9IJH% zzCGV*Q8{scSL^h{Tbh~K6)Wv5ok*I>X!b3?%(Ikr>d}Ec6oNIyIO8JuC;C?E$00`pQoxWd{Pkjfr19o;0!Y^S9TOLkJX?L%s2Tvk-tPB?6cKiRdjSq~GJ&bT8R&4=(6!M#REcfSTH6>3-*rhs1I%Mekh@h+F=5ij zMS$WMaRmb~Bv~{!p#+Gd_0=_MUl77+Mc(lhJ{;tq{}_BNh2vquIG}hf1kf32f}|#& zQdoAU%Aw%(s3IT^{IxvO;YqJRMdBP>Na(L|^^v9ED^%A*YNMwpO1h$lew~92G{heG?LIxWD#LS9cyIy=DEWnGb=q>E9D z#Wv*~ZD7-;;4OIy5HH(8;|dI@sYlly=4H7#GwmIKI{#Bc&}ppA-cAbYR!?QESXW%r zQh%jUB3dzFHWOmTQ`FWoSuoq7oH=H;QujTo^+vXlCemp1PV{^AN^8wkhVS=?luKr+ z*7Br9BG2`Y^@DmwEnE&WFO<4T_{&VNjmFLxzBj{Dpj+}C$II_f>J!E8xT=%Dwc8xu z8v_8p7y|av^m7<5T+rUu)LJt@a;qYl9#M~0;HiFLtLd)bbVH5({ZNM(rftioI6TS@>DA@)bPg(wvDRKbCbj}s}?fsT?I+;tpMH9y4mWaT2v?%~7fp;GxCoBYto+_FUl<8%q z^ianRo7IgD_sUBRJm%GvJ8?pV(EKXq^x}TO7+GOGfijGV7SKiZH^ro?F~iH`;gGD4 zQ3?W^I~>IcO?EL}=!GXuVliQ22v0!g2ZyaM>jrF?)UUu~5=!x0>DSe9p{uO>o+Mjz z5?JMnxEUIg-*>7(8VrVgqro9cgT~X>)PPlTmy=G;)EQpNz8bTY;Tcf*IZUH)`vC(R z%En&?baY$DV_#UI&`YRJHRUGxiHsutsf(EsDMlK2BD63MrHCTM^|b3KXHq}{*nc60 z0a_|GZ$m-Q!s<*few-f0G@f(gS}4{NTOe%~aYBaf^EA9eo5)#Xs1}Chi5NRVk2!cO ziLbDcnMd0O2=k9Ae#;<^yi#)r?Y&6NIx0I{@uj@M0pqB!szsA!!%@pL<>+vNeaq!# zdUQ`bba-x?;8umdg8Bh%koFgh$z<}p_XZyYWgzrl*{&IoH325=(_)f_1#E*Rw->;D zVFoBzedYp#f800(mLskxGE0nq)26d#?fmJY=BK8p-| zD7;0Mq@_dvAByEYhYUoQS=F1UODNXYC7kSb;Z<0HF)UjSXcoF65P`Pjnen9*iZUU7 zE~mDlcgVb4t1jgmM*zZzVfk!Mj1i5{Q7%Q-C};r~-i?+CDH~d4e;dUzvmOICe4;$) zxq53uw$sC|dS4(~8+?+2Y*Qzw_T~WK z1Prwe?4p5bv%w5tzvs%lLbCRK`zMAjo_OzBJCXSoRBpi zqr%;87(cr3@zr#PFv~vuW_1ZZ&c4QmWlYeGPDIpCPTd`FFD9c791>Tq8#c1OD17U5 z()det_Y&9rQ6V;m7lsuOPtxN|a?>G%M=o2n1w7)XNYyY4DY;*b zpTZ`D2`NSC0=R(=CDD(c6dw!heTg#j`=NV)> zIWU2{U9W9AV7T*LgyH?hc7D*ees@Y=ZB*0-0UWZ>DVIFx+jcW|E(8J%@5b83xyR4c z%A?kTt!)WnTyGng)3&@vV}Z~GMG}OgO?$eSISe=ck@-Y^3)M^b72h^r1?OCet!?AZ@{G9awUOR%A(~P%plqrn!~B7Fl2PDese+Yx z%yfmyX4y`_cfewL#Y31KR*_j{uF*mZ%W4SBXh_m_W6cyUDxin^s5_`gzq~QLYhZRi zFq`4oJzW6ZpZMFPQ}M^BAg~fbd;LxD%lG0kT-@}-OIF1XG!u}QuNwCMfH(hYlmENL{a?bHe|6#i zedT}Q4Ko*j=|8}mN_AcP19lAGnHr)fehI-zg~b<)U=r3X%}Ee?jMA5}1xT#|TUV1Y zX{qF=o*i#V#Wb`L$-o>qw4pSQo@u_9&G?Iskr`y@Q7?B)rXYc1^-NO}-%eu_|CiVJ z9nks}haQIO&ZVf=3xS*chP(hm^}wcvyIj9F2^!h*;rNV~t&>S>-(%kg&|}F~>M!*8-z|JUQ$NOE z@}m+)tVy$**-2~4B5mYB1+KSKh%6o}{QP7NsX<*62N%Il`e$(|PSI)~U)@&EyBGdm zWgVeSXB*q`;9-tm7GlAiLyfk)P%!sON!8>Z<0s5un1j2RIuSiV6|I|o?VEO@cU8&- z357hR%{%{e?PTpc{e-$pzrJA=SLzGDX(E+xBvE}W?p{wIk|g-mKM0}*BsUh#TP5l* zvI;8JheZa5CpY%}o^0qghx;wC!a$wkK&)8c0eM`X4LdC3L9@eeOW`Qw`7bf#sMCBv z!j`<4#dsgzR9SL}n)sFA*%XchtEl;5k8#ysHSGjA;X_g^BKLFzbCGA@uA zea$@37Ak9!qLs;_kW)y1vrgCE{eJlwll<7fFx2|DgS%mv{!rHbIoBf%RDo~xSE@&i z&>Wy~wGB{d8PXtCH5^Z1i$EJP9BdWVEz&7gUoq&p^ZKYSIHxYthr#aLIZnaxJW=GD^az<8dzr8O34_N zd}vS3HAHCO`(pgRHm)|B$;xXWmrvuh8{t);QaEoai2h3MH?GmXNgtT%E*qi2e+oZGT+xP4Mzto%#sVQJ%l4Dt=kJ@x->QA?>*YNP$guvr1f?Gynse&SEVQJa0!tic<^d zm3N7|OQ;_doC`zzkyde|iYj3Why?n=gGhGSI*{o7?dY}0fp$lAlDChJ6o+AsdQeG> zI?lSXf$E-)k8M8bX&sg{1w^uXyYM)eBE}1|ZR0r1`Z77Y&dEr(dKr)rV9O2}P6Nkc z+l$a?CO!hQo_Nwrs4ON&cRxj=D4qXHlqaz2>XLbhfPVD|nBpGc4{$rN98^3iVJN5B zgcZqCWjR8gQ4r@Sj)F#NK(>`TySQ{wwiRd%>W%&>6WAUAk8_MfnYJVfLP??3h2BLp z17d9hU0NJT5BkY8AmRstW%e>reQIUv=&f!$Kq;fSe8?r+(2!WI{!`nS$pLrongcCp zju)nZ{Oj~wV@U&KaUJpb$(#^V*ctXb-;J|XjSMpI zb52^0JkK}5d`WRpdKS{r3HPzq%Jhx%V>jXp-Ig2PE?*WjQ$+Li*a&?{?(h0>=VjDG zw>h>vg*I^xD&SsYcwmCeU)6d_*-K#R%w6PD_;q!A^wKPI9g}t=A@w@1(9oDZy1S!2 z8m+$iN!Cox0_$)r%iA=ilf(C|;_P4%-sh&JIoX&{^IkWU8vfpfJB5Nc_`XG=wqutZ zn$f}jihD4aF38fu8Y+vA)szXaoi<=`d-fu)-`yEPHQzM9HAy%EDlZ#NGVc0RyOMpi zlM~!?_#xBJDXP|1-p(b{uY7f#W1?05}Y}qa{Ctix+ z$T8YGcF!P?cpV4JQ<;C&5|RPah*`8w8;cNn<*7FnBG$qKJ5E55<$kq;>eEETaN2DC z#*donffJ``2Ps`S83z-(H(dFUcqVvgAB@Hzidk6++Oq{cm)1?Jfe!iyrm4-79~mZj zi)|OM2kj5pFxkTS-Y4?-^0f5>h6O|e*5v;`0L8y_^#88z|4Tr@^>0`He|ibaf2Nmg z#2v7s_}U}RlF01x-_yPO23S!!Zyx=>kpeZG|Ki>4i36VTx# zY#oaZDW7E1_^obl`Ab2QZw%naLVcgb7toD8yI>|BUw`ZWp|*s0?XJ4%BqI8LuIZqI z|4Ub9aQsaA9nk~sNFZjamq-LJ{mBP&Fi9tM6+%UK9|R_eb>WB?(@zz;BCx~fWxn=o zMRYzY$tN}DExPK*_{Nk#S%VqX$fOmm*Ef25nA}WRpjJsbGt$hTM2b5a_mB&xgG~O& zZ`Z|n>i@?ma~!xim7l)LjJHoN|L5dcJ%T)sy_~6lJ@3kv47VQBN_agm26QKREA;d8 z4z&9Ua!mfS@!%d3wODsKGP6wWF`v*R#p@?5wq5Sk@t7|wxt|?nMcQw-w&0jM`zk&H zVR)Av%Rmfr$Kg!(AJg9T^X zbUG&gkfzw*kFM!70;%fAK?@>h;` znzw*D+5_$}=?4<4HB$%m=xe)lj5x(*zv@bg{;Odp^Modfhj_TzmR>}9|2Cn4Yu97&-o9pD_4te!y+vn>C`24XME46`4EbhDg!}?6fISe zVeY(76;a-2+0~wJCiJh?hfS4E)4n&vji8Pv`@+(aMv@ITciH;`!$mr z0==2Hf=jWV*=U zfQGKtou zv=G9D*Pr2Mg_m=`pW=do$KvSK2b{xgWKdHMC(P>T?YFQ2yRj*(SMds?uxv|n1Zz`~ z#*B$`XKyPWiax1hPl^8WQTzp5&KaxZ^3ig2c;=cY$#i>q(GEPGU0zBYNHG3UlF~ds zY)=rvS(aYq_{?mwyZKE5SHikpI5s{SM-c91H<4zG8jh=>iq@Ju@U`@%f?_}IrNvH~ ziZOeVEq@P%1BaiuK%E42hCj;R7^OoJFzUf^)~q4SkknYH`t^(wM7jwzw4m{OEjP%u zOkg1dH90uF*Fv?pXh4Pu^(;*E1BYWV4VB5>+~1@+(iRdfkq znrfzTS!%Wg?7NF$+OR@g0k;uhxsDje4hyXW;bM_oaiYD*hK`NAQZ^(Mr_3&!-st?h z$|-9Vdzf*8@ztmH5mm0N9-pJhemI`EJ^}r^k+Pmi!jVRY0J43hm_>&(q?#eI9L^oMehw$3dqGgKv+AM(W!uU&c!&Dt(EAjrdI2MO_U z^TXM>mT_}ui1ST>t2D2|tvIn-{2l9pRPnmL0-wd+>fYlUsi3P?{tTg5s>8pT{Mr$4g9Nj zm|{c0Wu|07Fx|0kyk_WZ(~T&8ax+K4o~c(x&jQ`d)MZ0FvL@R=jR+nvhJlHC;IVnD ztZ%;OO8XN$%pMEt9*M_Ll5^@Og=q=lI-+?_=Y&+OJB$NV>?@eXUf&q2fPgYxA$ru< zX>h`7j-uM{)xi#I@5w~C^07Yq%=SmihbylZf?Pb956NP!yrn&L_`N73)X6{sTw8S) zcpF$ATGPrquIp;LZ{ z3d{fCMq=jT{7*EGY;{@Ze-NeXLp@K4O92-ZqVHx+*vhOvd7OYfT#*LS8xaXwGKN}6 zI^pj>nundwESYIVQchVCT_jn%evjYR`@-|}p0p52{nn0X%&z}K8YcK!?ll(ICg0~L z8wn)5zkNjq5!{&B$B1sGLfSC7PTLoB&)|(vuA-U=IW(%)?n})5;&w_qEY?&*b_ny) zvHK^o9)o*)U(X`Zm;)N<+&Nj~`T(Tlv#~mS>^T6L&*yw;%;)QO<5V@~*93($X#3mC z^PlHRrg}s_xaO=Na2WkjijWoO9hcy?7S+^V@qOeDy{MChpg#ab{Olj6wD(}o?Sb^k zf~2{5-c=JcpPm5`iqU>Nghv6E@q3U4=w=7Gty5=OJ&A=S_-ra-aBtd{mNbBT!y>Ro zSsgBh{4qfG_Xjqij#fslN6Kh(aRR!$=B*>@a3`GJ15qqRM|#7o)-nU4yB=6x32!c; zM6O4sShR6nWn|YeGgc;QNLR8q_^!IqqO3bn(5Ya~8HLOP3aV}{%6*cV;$(?ZuVhK` z>G=}1VqyjLHc#7~Tpa3Tcw9#UK6{BF-HNrhtqTVeq>O3dlXfmz#>kbH{YYHPopv;}`+1qLx4objOln;EatpYuJHu#QA;w?B7Y)uzVcyV%W zcaL$f)Q3BHdztwyaT#N>;|dHdG5u)ELg>f5>#>s zWOT+O(R-iEV66#MsSfttBgU&J-rK%T=AH!$sw@2G>@RNxih)zfa-CnJ2B1DN4`kEJ zz5bVIyd{)7?7Z+IJFDJVO?h3x3m;72>BgXQGNn4IBZYbG%NW<_m{|#tp2Rb~uDMv% z!RH*Q#sswrD(EB%HMh6zJ$W7~O1Vt&1$n)d=%dWh$F@*imvzmU+`LNT?{r z!3JhWV}+{hx8gf*xnn&px4D#kf^PNUa$R_);vs%wc)$3oR&TS-G;wAeBb+`sfm_Vm z@Rbvwm39Hm!oe_$aQB5b@DGf#8z4;0{ko=4)i@snCPScR-50|P2&Dn6*Wjs*$q{ri zGARo1ld~U~sEg0`6toKv#jd)jpZHQX69%o?vmxRLg-8eN!T3!Z+hyJPbOWK;Vu^o< zCUpmNlet85+|g&$bzOn;{f>BmBX%b5>LWFX9`T|xMM8(Ti~zB7;gcVv9xzs#Y?O2S zwscf0gPqUtUlxj-FXyw-$&S$NfdIYl5Y5-wo*k7H@um9I-M~Q^znes!;+0|}P^jhz z*em^WM43Dmt@D{Lt$^J>9R_AT$F|5q!RX-9%UXBB_xaznma65TY*;JG8(g(q&B8dSct3 z*Grmi@>%5l%n?$T(zUfroF}~lF=EGPN?V@BOmdE1rlQ535u8%SDuOtNlAaH^#WCRe zNNRcGldYRVS06JRi`x*U)1oz$<>oAp1xYWv!f9xl+Z1l^{C-r6vccJfY8GgBah;GS zb3v3$k?0GP3vOU?*+{;Kz^Vndrd@PmLdhUu#90M-wAGZ@?m;2j<7n$1LnS~`S2Nnv z7!DAUoiw-Y!Ai$djmlD>R#@qcGOLq7JmXu8auNA06v?m60@2Y<>?s7Gg_m;u8g)ci zmW$$SLB{;umd!DatWn^=QYn(&;HTj>2qSx(JE3YQNehh<`_>9woP&AH28KevR+@cf zk}au$WyM_CGe66AL`0dI=IyocKF67+Rzg8|i+Ad}K}dT5;m8n* z%^PHswi&3L*s_|3b#IyoOXW_y<1jr!*ow?Y^)fBA=+$s${#qRDez}($)w=ZR*#}7p zGgVTqrm7xoS~z@sJ344AIO0V!M`W3HSNX31$`JfXwJMa$1Rr)I%fWH=q0Ac-B1LT0 z3KBs~M2I|Y7$me!sucLD)DK_@xRA6b!Tou|u)o zA$$Lwz1-&w<#cRcdO5qEd$fb2gEP0?#`g2#lp_L>NK}W9t@~oIE~`Dq7Ry;F1?=3 zdm(DuG11f?<5A3;%u&9LqYxP5<=#Yy$}$^mZ2bYZA|5dm#N3g~`MqzP{kK>~tcF2H z{O@110N&BwvAZvgMBh*0Ud&~2A6*@$K5ua z1l2@R_9RK>p08N&YFElCILAxmhUIZMKu(DT*3tlTT{VpHMX4vkPTkJ&Vwo;fl(mOV z@;E&5#ZGooEukw3cgVePu`r>D`a-O7G#{|B(P#Jd(zUVgc>r4j5P{yh454UJ;n728 zelorx{6rBomeNG+W*16Sx7Qo^HnnYZ1>c_aAuZNFx%sn}p}dyyPpjstX&=T<28fqO zRvKoBaoU^eyDdSy=}x$T=N!I35Bv&In%YLvwX@Q*?1vTZrFJR#$1-4Dz{y$IORIN~ z>{pNm@=QTnmklv#&5m1FV8RV+1c5!YGr1sJ*CaS;bJtsz=Sl;Uql|}foPY96Sx<#y zs(jm!Q!BMT`bEINj8>VEguboT4=4}&5Hlij;g0@0E4Fj3WOcFdIlkn-XBp?_zgjQz zyTwV6Zts3h*NESyAF$?J)yG~eq(vAzdmNJUbQM~lD+G&CJ_UVgL_o~+n4NzTAtCXj zlpq%Es+<@si)0gH$)$>H)mVO;2I7#?G%F6c8xk&| z_K)iZHMa(5P$=OC132L!Afju)1%r8~A|$Z4E_D|qN0+AWXImO7+hO6D$3l~`z!C|9 zKDih67bs{vNT!+RGXF?swNzKl>t8mV<@M6y-r>cX?K@}DBYsz;pb?@_0vqlh8Y>g3^ru>l#gbcVrJa27VhAK_@GUS&q7K0>MgfZ{@lIA%95+wcp2626H3o)*8rZYrHSbgM&jvh=Pi>Z%B|n&vhZ;+nqrB9bSSc5P z?dpHdG#8D;@v-&xYa0_eFQ(o6ty1KgVe_hJ3;RgQ)8?3y8B& zgyr)9ZNR?Hf-C);Y~X~}p20XpH{b@7?c+UQK-{QTCNh-!0`LZZNWA3$pFqztbgEYg zofJ{}L3ZgPLArHURWNio+|9Lg+&L%D?>ebac8g-v~bjuY)z{ z2Vy*|m2J3}h)+KPkW1E^j!yzI?)7c&gNJh%&+AShx@kEQ z1zs*g>~i%!V;}%vFA%{n4kZ_Oam9~JkE=00mTt;B|0GFC-XkoZ811uKB%aZMSw1?m zr5w?HrTQwQ_hu)^YA?GTZfJ!>!~t#^-0<2|@W*m#nbY7$4tgOi!QOELdp-gDTW{u< zER$zs2#oH&X(n5R8z3w6;EkFSUlLwG(O#8kH@}Wl#J4bhi5Pkezt88oa_<13pbrN1 z$|6*biYwz;3C(5}9%9x!kA3HL1zZ|*^yAm)4SjiuEfg}_URG92SdZtJpg({>pSWwG zkWBJ-ZuYJ;90%Vd9cz6e+_0|L+88<(^Os0J2!czlD?@iyk^g18Prtl znqfS+n;tJf7d6u2SoJ2n%w`-js`PMMWGqAjdl>^zd@wac(6A-S4>vIv4aK=3OWGZv zR=Om#l3tAw^g4515BUyHa18+@ko&Cnl$t)KCg6xtERvuwCoBTvmbpn=WKALS-&GWr zs~;V~e$ieP6=Ne~7hI=KL4>c8`3g+c$2>Crt4>eohiuVZJqQ?#DCF@xM@C#=>O?sk zfd%vw#56KM2+svpYWU+`)(P0LG}=$_^uS@;QCg+-0Wv=Cx7V;TQZl`tZ6&e&VBP0%*gUfS_$(vGNy;re#0Ns6K0XtK#iD zkg;&08#s`FcF`QC+w0ZR1q}?BMvEnks4_LvZ(6iPsOi`Ut^N^!aX2Q>g#a)FP^uaS z;r{>!|89%;UxEY9{{arT*#EP^$(Y^dC`#uAEev;^c_#UFv{`U0HvA{T4e*R_^09)f zn!EELg(X88o4!Dzswlf8eSqOFv*acdQ86(S-%Z`EP4G$6j)Bw*ruUNX=;V;AX>|l1 zy{*r;HPaDq-O&78`>rQXi_G@q%YSUdPxYo> zlJ&y6X-~tjRV4-7^}e)2#>$wgJ6m?&>t84JKR(p)-i{L5JK80L!5e%$rmFtQKaF+5 zBXx40Dx05!?76|JcYnJSX}JJf3k$wGOAGNc z!I}OUGXkZ1h`G3>=$%B&H3;eGl^f5td3e`giF)6Ni8&gyJ#h6Gnwly}=&E`q1?l*` zs9i$0wE2|lLYLB=7*!^+ut279eRS!Xju_d363QZ! z9Qt7Aw@i2f&Wvn^{5G5)Ix4?6S3S(<*dw477U_u^ZJHvl#4|3#m2n>5&9e(mHB?{d zcp}fK9_WYKcJ-tJAj4WO0#HW4Tak#Eh>P|rRH2ovej;(AS+)q&EuACyEI*n--wNIbHQ5; zdK%Jn(uE}iY?@Y$g%y_WSm8E#tgOVsR2H2739VMH=eNbuou3=4tad6UrsZbSEc(S; zQ6yNL4O5^BMGzf_X0AwU?8W3|{2^xopR;)3GIQb!Pi2X9VNG%0nX1bn>raYZrx-eP z{^RfbL(lRhfh?^Ynv3ijA1-$uUrDeu0Ed%GXuR)&NBYbb`!3~wI9&IOeMhq$i zoA%2Pcjw_w(^sigk_>kQH^6TWvw-efP%lf#q&I)L^U^DkPl@{=#K4|BN~;`Zi49cQ z(b!&h5l9-3yo3E0iai3`s>f8B7iR00HsLKct^69ObX@&SB(m7P(;V!S6q#3L1VkIP z%BR$g-ki`OE8zt#DLj(3dZY)=bjS+qNqyWW^^;%OHOPGRpXY^SrO(ub7>MB1l;qCG z-w+Q^3+ZRj+s@2UmwbO6M&8xm7bU2WVJ?P=xPXDqBeM;@Y>ma^?1Agkwk;Z^QaE@T zpFGFU2SpeU6;b45Ci71Gc;}V|4;?9=k{sds6vh)jBVb)%eJ3I)M+eA$uN#)KB!$pB z75qLN;uQm)8Xsfc-^g(ZR+wsXj|SlwqM2S4Yji*%=c#iQXIkF%lUB5t!spPzN7|A( zWrVw_y~kvf6C21PSwDAOvShH?tS>M(uH|lyG73i0&11)Dg&PpVn?14+!;?h+fJfJg zbc*B%bea3t)se`Xb7qsX9!J7LeD!?abG7s6O5q1%3&PXe#CJCNp&&Rx;K1ffa;{cev&l|9 zjHM(EI{H``qV88ZC-(QDTzQH<;Nk{wy7RYiWk3DmlcZ$jV@M?Ft@wQM{Ed(r9{Qz}IeAy$mQIxZx*p;@rf~hQrQC z7Qf_t`9?)U6Idgv%qQ4#%G3Zc_rTtUqu^N*nm&yO!F=P9Iy}HrT?h^b$eQT1uvoce9tLlWQV#fl)_yxShjUy%|IJ1=& z#{m%(bS+uaC>r8D^qDxPDN-$e+CsGCcuR(^MfT4zmXN& z9AuC&Ef8qSGjB9$5YSRPdS>bGJ6#n@LhedBD$E2bDZA{H?mXS~GP1Sh{zvGzZfkGa z8T%_)Uox{^*ZHLWV9Q{43Zp{~ncOP7gU?&8-u}VS^_n^ChxEoe`SS;oAGw95pkLv!0uM5bJKOH@Na~fQk zd+${xHa?A~L>todc+dH>u&yG_7pbtg?ydb;ttYD9CgeLC-PW=rq%wHLYPEPjzjuB4 z5C7`uCUkjfdox~rYm_MCL(tuzeXlRuZgax*BA4SZb8 z{Q2n{TzuJLg256c{xI@R918C=%l7k4^~YGqxUrtj^gy)P zqd!NKaS|I}h=4^Vo9PuO>Y-H%u*=oKc0 z)u2F?pK%W8g#68p!d*^MKU8v0$W@X`fnJvqaOqq{oK~~jzzqwNI}Z1n``eU{_PRU) z-I&M;&v(;Ie-UBx6~jrusB}aQ6X)XS`mx`e#R!qKPgYOB{~bXW<8unhKMn_?VNFwm zOqC4N09B}8o^&8c{3b%gt9y-(GB*Ozqbk+19wkZvrF&p`T6`dR?@|cFL4@XA4|Z~? z?3x|$_&7%K*sbL{Tm5d^xQCo^~%zzQ9@~Ah}8TXkar#F?zl2U8~RIcUF2v$Z`QusIXVJeN3 zC#uTsKr3FUCSVtV_3=U`oz``Y$uUBwR7Kc}?o+@gtamiZty8pz;hv610ITjdt+~6Z zVj+j~xvuaTJI}#`G7bw!M5oMnF0A;FUak6Cqfp8x)zj+!i3d*OG3_DJkxWi7qB}xj z<~~re=zPR`{vD43N-5HqP5NVEUx;W8iR}FMwy0eedoj(L?3J36n|AC^x2_=Y@StSn z4z-4Jk=6Y_XnGD+Zri2SX7&e^V+AVs)5Ebjfsiu6GfULfTn^xMVuBRe5)+d| z$1HR*UaATD^D;=>sR9uqh-4KE&~sS4bh6|}1_$oE2ZO;d$$u%P>_!!lv?4RnMIkWh z1Og}Gb)d&)_6;2m=r+dPMdLINy0ZYbc1zIk(S7iJg)qVqXt2=?&zJ?bOU(UbQj)}8 zgH?nDvT3g`IFcH-+-mPuYWodMEKL+i0(N|2R|&JYqLom5bl?+ClHYtO)Q_PQe%oEI zEZ3>pl*5li;Uz%Tp{*tddN&MUR4?8#lWaGMY%v*&`JTCSza&NV)w|u$(S%8TbljE( z$tqsfPmPT}27@2`Rpcd1cnkKYbW6eo=1eSy#wovOuRJiq7oRX9Y8s6lD1a}~EB~Wi zU;*3!S#Ajn?p%;O!8Ct!{Xi{Q(DRlBvNa?->j?&Fz7E$TmK1Y(Y7Kji9Nf_AckVL> zzYAJ2T~WYHF3Suf_j&1g6EyKNjTTL>WVTZI9FKe z;v!gCGMJ{%R;6Y!$&4W}U1z?IBAVFE9UqgE!`RDAl@*YwCfN{$4n4Ev$^;9E*C?VP zzW)@w?V6$FhGNY>0CNm3msxzLYM(%h{kzPFrq4F4Rg21HBSBY6l>8m%F=Y;`^%}c$ zT(WF3>w(X8shmc)92sP*H;i{nf@6$PWfVN_T%9M5Zmn<>k3EQ-^IR|?0Go?DlhzoX$u+!T)+j7i$n;?-i=Leh+z$&j32d8!NoM~<= zO}%hA&%v)*ebe8ZSdnmarM2NZBiTRbk0?K;Lluh|0VLKr}Pszl`cTMx%+=4RzJy*tK2jjFUUi1w-UDWa6P9?ko&q=0Hg z5;;1JNZyP9x+(jmpehpggPC_eM6(sk|2db1=r?>sflaXqRwa(&N~F-k zy! zK~dk9U^4WG#3W$4hF>9jxrl19TFP0a^557%UwRw|UJoai;m{~Xgjh7jm=vIgP7&$~ z2M)As5MHq5gvY^Sh)_%Nd^N#29cS7^g+z6*OY+G&JIrW_nL0X?Of@DN(g>xy9qIHm zbcl50hSC^gyP}%oGk?5vSq>Ep$@a&0!! z`ME{?sYI6`xM>47_g~0{Ktq)cTK^6MS^h3a`M-jJ4B{L_EPoBQl>f5P`7>h;mVcT` zv9kS%u}1X2j5RI|gwTM+;gLnUwVYOg9M6hld#mQ5%}CdulLQW2Krt zy_F84G1p<-YIeVq)C`{_-dMMjIL=V(9?{ah=c}#tX|>ZzWz{eFx)V0{J75wn_=DIM z^#-U2x+Ao<4q%G{UKO!kA7obcd2PZK8Uc5~3%@8T7=5)$){Pua2wl5x{ymA2Kk z!jAaSw0D0<@Qp_P29Vqg0oq@%J*hoBrf8qC=b-#K~X_5k(k|}?y3V<>YXl2QdpE{a7}zB5~qZa-?ttFUR2S@ zhiBA(v%nLZ1VA@SM5Z+QRy2>AM~T&LOHdfBGQVs{GywQ8BEE7yzZ@#MHTyZc%emzZ z--bMsbV>+y3!JEWwk__8a@L6I8|R4qf~Z>6`t0ezDt=pr1675NYbVMeRe0WmKAR%u zsHA=`-GUSKiZ-mJEo4_8+ID^1U?_Sv$r0o(<6AIfAIF<^6qqY3JTL~ydX|siX^GJJ z@vFGs(G)(!ig;!<2dRHLv3g5AV}VA;mnZQnJXf4~SfZ}7 zpMvCjl-K4f2aXA}C&}|Y6wkbKIy{{RqY6-efk%IoW92 zHWn*lxYA!?(*xM2CtM;t@69^ll`Fu21F67<18BSj%rZf_~JVX-fuNuip zdyPK(I2BIPLeuSt^3SLh!M-}n3MVYc_|-(U9W7uG3P!3)6W2?Cy#B<>Y36tNSPMg3 zc!r?Hnl1GO)xPY5`AV%b`;%fT#!|cbNwHs?J71;SHdl$Dug*GRnWxVhjy5lxN@JI2 zqe3x-Q$~Ghl$qQDtzLac45}ufyDDH;e@+Nv!G|`~q`_eYJK0&iqzlgZ1TBC?oz9aj zvV{z{kgp7(Xc09yoXX+iEU$yMGSOHxzMi>=VwDtth@J38xC=>CMI*1H#}lf<4vQiG zO<1@(GEqO`_0H%jj(dPG8u&E&=j^y8*e%vrUd%=X!q%F8+PA#iOi(*#%xMqI*QO5f zxZws~W_u}`U!chiWy_^hcSOx$Q6NSg&P0ed2&TdLGgAoW!pQ1%&gkv5M9!`md zyp}iv>;*xWhmv$T$?|2$#Mh`5H;;hWJZeFwM@dGY`+-fSS=2YFOFdGvh>Jn4?(@EP zjmw?atzm*|N}xP4&xA00vOt#}GDW39V1{CqLuZkJu>#G?TAn~Z6PD*N)raE z)?Wf97J;K~A|E+36Sv5QhR-0{AV7pzqP|fxl>*?(o=VaYMBJme>G~LEv>zBOJs^kA zit*Q89?EJ^{9e~~?zD74FW8;1R;M`!{lX&ywV~)`%GS!%A7-&IckbsXh{|I&o{UmB zAhGC-nbqXs4vFEgD!*U%VYV>=>8TR=MmmQO9?9)zYJ#m}$?#W`N?JD(2cC$;5fu~_ z80B<9FP;uF<}wB3z|d{Yn`?AOR!dtlGlW^*`-s<~Eiq#cBSrEbysY6QZ9+E;5aiWL zq@JD;egAF9uy78=D)q9C`pSD7bm*g&rKKB;P;3!5xH+rEL4QdeRa-MYN^qZ$C;2$H zf4kgv#oe_X8gtd_4@6`N7#8?~7w|pu!+H+Pi@bEiFIC4(X*E`S+ko_HHR`YR5E&H! z{6D-q|NSWk%Rfvxm>D^k{y+lp`?2{SJB@4bGM{FwM6ZX3g}p>O1gg2bz78=&M}fKD zMoy)e8bxmVZx7kTV(ZEc-oqgJIt63t7CD}W^PSV%XNXMSO`Y5JqxW(@Qh#!-FS$qK zUFrXN?;BSde475GhZ1SndOxC%ppq$ItJ>Py7wf`^1c)njkQ>Q5cg>VZUgysWjir(p z0mG*L+IdHpm)(vajJq0*yhn?^#=IdZFXh`xd=L^l6l+34!R1 z1>#%oZYTB$MNCK(L1o-ZgZ-2DgRifF69*`2o!havQ%IKdCR}shTysc08G(MG{OnP=pZ-9PO)q- zu~G0bd7a+T01iMu2oOseB40WPtnuV8Vn_O#h*N0u-N8U%b29WC?WCEy#&h&s^NIR?8{X&vzqVD#+4j^IWSRTrU| z5VsZ@qCK(KuNyRFbw+BX_ZQL>dXkFkIRlr%^MXq+?7L1Nd5q+fg zrYfd#Qw-S#+Y~X>yIx+2O~{Zy$Fb1T_Ho}=rBf>4s%<9FJpozd+~ZByJ4105{;cm- z!gc9c4Th#Xa}^F^5yYOp%6+Dq4d}czfHTH;Ajrg2>aOyNfd>8L(Im$wJD5AF)%yp8 zQSh>Y3v_D<;)3t1F|r3)$0|`F9!_|HgM$0E7H2JP)$l4H^*wIBCaFCX`e=sryK(dD z9&Sg0dAg-s1Ida)ja9D&- ze?(QyCTkPdEdn`Hr#;; zLJ-j{^?-e0E7zEsQ;v`YGZ33G!Fd@A+?pCnE2Qu6ZccVhqM4q01E^K5`(D=)WB3B+EmG=Zm6g2~j-!Fq z=70$KYeD~BO@SwE0!$JvBlo{%cFr!ccbFdSNM9B{uRIm82Rpk$%(*HZKf zf+c)gLTeN}`%?cqb$w{XpzQD$=p%}CSb5()ENNi#S-r=y4sVUx>Ze|g(>^eh^I0AS zXa}3yef!UndpBS#irX?Fp$&83p?9^~*9J}eNf3ImPV@SOpAIlRR~-dfdqhE3p1ZWN zS~Nbg?+deB~Z(y;voHC^o{_Y)d z>UpRjk?4PvF^^wOw)8~NHlL2-AY{2|SYnABv#QUZFW9K!gd9^kmhD~GhX_tSbC`7) z5a#w;5ZD)$b}r3$q4-(pDCE%8iPemw%iMO(n=6P4f2mATqGjm17?J&6VkjbFRFiP` zk{qnT+rC?pJX8NN>@G{TDo|=B}-t?8{L*)UC&nB_71+nr@ZnSm4u3JRI|btjt;>lYYo8 zpx4KeL5oLna7fn&c3RW}c&jLe*)s{l(ptL5##<~QzmBc1gQNzbjwua$os#nNX|O8X zip!fK9EI}!x_WK2}a(#TFVYnBz?w7)sBU%2hs$obL`*rZ_jx9X$Gu zb3Z3;v+U$KfO)pMUOp6N5MX*ae#W%wH!dI6W|BSzky0}{-O=zBS)4IG6jIWyaX&hH z5j-0SClPe98H7mf-8`K3X8IW!?osfXoQ)wqaN?jn3-zIt*@Zkz`5yd9{)F)qeu6tzjsLLj8F+5nLW}@!)OnlZ`xD$rVmw5 zgoR25qwJ0<&AhxC}zGH@D<-=B}4NCTFo8535bksTN96i6TMQXw4}ZxRXE}*S!isrVtLy zmE#EfC8T4YU32qxG{)AE)E@QCnXUF7=JPDQHy0)p?#<6v938edW$`A0aD3Sw}zB6zqsT^?z5Q4k8p0_8I zYuX6$zHMx}1^E#EBu?;l_jq_L-CdiH29sz(@c_b6-i*|+(wq$a_ad0IVbnLH(4`EI z9Q-dX4nS8wu&kJC0&(9L$CzfN&-ADB-hQm#pHf;J7*DdX-}=&4IalWK8FfaY3dU zY(#@u?;_wYMxo{|`nc7-*w^PmfcrJy7ykIU{gqWk=u$USAYwMiV}LL>tfO-SRm9kg zVz{d}&l^*UJLcewB$1K^1rvJBv)q79z!3-B<;RN@Y~Shg<6d_k?6G0iIv;PMuGZN^ zYMGmr6(P4g8n(NLUB1E~{0DFJ4>9PlLiwAyX|@dBTpS6hAHvO^i(bL>tPXKK;CKN+ zfl-0mNE3TOznhI(>J&;Q0r)nP1ie+c?G}47CqB?Bd^o>=ag~ttT69wds@ccz(^F`G!8bmSD{g?fRTSJ!4?AoL?! zbq7!pEt{HZ%VCFc8h>|tm@@Hum~o*}h&&a#O=fZ0 z5Q@h*j?uErOl({?Nlc?Rl~POHhagQXJue}@gFC}{-Rp@t5|>zLh}iRwMNY5WO8LS-awiZPzwWAy7N~J8ZGP1!eQc{Eeu1#F@Xcoew_xKYT3EIw~Z^2&z z*XIRQ0-?)Re_An`l}22QD&{E7~mbvtvN-g=MkV zC6?Yw1hZok@9OyE5cB;d`4ez{sb(*6vdcz#iNnXPN$rLsAIY@3is_d+_N0prbFb3Z0(VA%DwGoo{T4E%!f}C3KflFlosXOW4`8v6ff?~ zvLYSm{AIOY2cNv1JZt)yp~}6w#SuMY!TB80m1$6wJ+uTN_Ury4Zt!0A+XNN2W?Eo1 z5u9zx*y)x8BK;9El1#sy5={y3iM!7?z8l(y1oy_Sht9*peG56u|wR^ae@h+2U2p{+m0g@z+jTX5Wxs)?c!Y>s{_&-PlJ99I1<&@-( zl?68|c4#ZjUjZ-3arz0RWn-h0h}R*An;m&gy~KHr-njCV49#_S$n^F?ZtXnjTeNca zXri;SGvKb@>c<)9S8agol0YgEuw_o;U?z}e=%VSbB!JntB4euLZ28E`3z-CklUMcbR?)lu}#iG!Zc zT1lfN9#1q}$QpaGE^TTw56?a*zYv!LrXSf4i9c*>1NyGj_P$=P=-h@T%afA&a_+kr zc#y0bh03pyg1EqqtMZ2KR6M0%)N>kn?}I3*pj}%%zUU52XI8`-d0v1{EOeW%gNMEC zc4d&nrfOvlviDhd3?h@aWDIjkV|ts+65xfjk? z0Zk{&^U%(yqBnQ5;zXh~$hU)HQN6~$XcT4myaI*`HHNR3J^T{thfhkum*n|#KDPCaaN;Xea?7CQc6;0{ApVvncAR8|-!{v++ zhIux;{su;(>41>{^qTqYw!q)D6-kj{=9_PLo*SorDlA4QQq?d0B4|vju7R-!bh!mx zN*03Ab(n!*Ojd?AS*t}04DkS2@Fb(_)mIEqaD_s=fwW1g*g&wjTd)=H=#+QIO7FGx z62gog2sJfzp3-fUnOb_oA>?E8HEY-)gaW_^i+{ahxln-jNsio^p@|$M7Bd;IHv`|W zrc(mhFr1Df3qtU_CdfD{2s!Vo=!}1kDWEB1&}*}eXvpeNwlu6{aRxOKmA;WSgfRo# zQ3$-KyEx-Iwp*fO@n>EoHu*hFoPU2`-{#v2^Y{N=79$MGN^hVQ0^mvKHX;&hG^VB4`Kukye zS{7cwk^*UJ$XFcP^HjVCIPRTvF~!QgeVqvxYl*u8a9NL6l2!qmC@-P!Be@MV;)b1h z{|kUem;yb-CzHT1N9VUXD@iYp#lEjj`AOsr z1SUWkfJo-bZXytHR9Xife4Kq%Lh%z8;ppe;4p@TWo4Q8x<+Un@1FuseMN7o{4x6yj zejVFNKm(3-)H;XB*lL5J4wjlzw!*7xt9cdt&{vE_kX9`x*D=1yR(TA$455z57Aj_1sX*E62ebS@ z&5uu)5Ym8n5EVOV-T2bi{3hR3WNNiK9g;3*TA@eN75vSWF`YD{l|G@@p4 z3nH7JXo2rARk+1|Ti%tqU+QlF>o4sc(ppNrcB`NW>-JbteTX4cu8C0}49|uW!+V2X z0^Ej)Ya7kqiz~dI^ej2h-Rofy65h}t)KbfJ_~c!hb>N>i1v3cc)G-{?3-EtFQdFRq z!eweb*Qu!(5s-_e2+^?GTYy^x77wmpFsujKt6HlTjeG8E@^CTT_rcAx{Ca| zJ16?ozVr1UpcAE+K*SnOS%)D(|A+|Mm6yXIE=D zWWD7Zy`;(^?=PO^xQY-Yr>1$=WkpmjQyz7?7sutxAj(LD$=16o-^vjj_`roOI@5tW z);NT?{-AX@Z?hmy3$Jfzl$re$cXI95bOzN33P3#>jhM4EU6Lh;geRdktJV%rSy3Y^;B@d5|RIP{@chdgT+TR3z<&Q+6SU z^4fM@Sh;=XG{}Vn609bS6lY#svDiPc3awucC&DYsSEJ-&bxc%C! zTTR5N3CDbPIqHC*74t^a5^e_y|EZaC#^`WaXmKrvoji>JYr${uY}h#?y`KJs7aa{H zQ{_7obL$EBa|k+SNkJ{_YaLphX%AKSXImEIG1u%yd0@ zsj>hx>((6dClfzRC{n~)zjj{)Ed1ggS<_u4W#zi#$7P5zxRT^T^ z-sQKNE`Kp9C+P07UNP>z{A{<1dmpUbc`GR7)AY5#xlpHIxXMEjEZCZeO8Sy0Cx>P?RhwOs8>QW*irU_* zaTO(t{BCo%6%)}eP+`ypF-u^>_2k&|?x?eiz_0{Dl3uRlW+95l+%H-HJB}PM1W&yq zF>*7e1Q#S5@LC30Gk2GU@_O-ZOX zWh{KrXv-RP2e$6PS^8&~TJt*GEA%kKmLQ!5;#|6MCe}IJub@nAm18*Hbfv5p2S@!< zy&eV9i2c$_)9sxf#4nr%w2SQZPMwxBY_D@!-?CCyS9qj8FREvQk>C01cEGWK-b3g* z{ynnU{*SCa{x432u>D<6@vnI1Wa0XQe$0@%j>85c+P5POO%*n-Cg{;v24dyn>TPbj zjK_wq{@?{x#S)6Q|xbT-XLVPh& zEqH%gh(d*3Y^|j>`3B$z-ydWGkjh|0gG}1wgwbiL=ZwKOPe9t(Z0V1>2pjDx7=!qI?r-kZh_)>_kiVH3Fsym zcT%p%Gs!T8BHf=k?6N#T(qO~p)XtNfp7_ny~i zXPJ|J=If4s6(rO+apEify&q;(jh^c@BaUx3Q)6&SzVY27Z+T6Ps2PBvCF`%FA0A+h z;kLx1%G1;hzrunt5^BDZ>Nsz76lMQSEte9JWSCY^3->D!#K=gwVEeOK=o(R7mp@;9 zdp2kiU4=KG!v$>^d6;#ljQT|N_)xV8g_5f)7!1K?N4s$aXS7yoURZ_>zyC{dS`|#3 zREJ0d?~;r9mKWZ!+czdLr?rq7!;QT#WW+d zoeGuA_Ri*-RF?oxwd$xeJXmygwybGKSzNKylZx4fq>_(wRN&^9H-g5`w#{rFQs${!4m%Iy9ZE3(IP_ZudHlS5*6QR#fzH^B5pTY^ z0wjI57<&iL_-GiAhbgKPB<#q3DH(Q)qg!DeCve8xp{Cu82K?o%BLj?#Kc@a&i2`E$ z2qeu;FF20exqZ$rLA&Qe*Q#^5ogSvZ$%6e_$53tvZ}n`QQiq=-Y+uDY&?{b?=l6+* zKOG=J&%Js013|2H))+ECydF2h`N@NNe?xtYc*Nma>6@dHSb`|C{$y?T%2+5ku0Tm!~=Xdu+GD&|YpSp$veo0Eeg6Wz3K{^iRjn2Bh% z36LBiWVxDpOY@P=8rKc*FZv1w`TkJL7)i9wi5JcC;>OT-e$K1K70i@39#oh->x#5F zb^vStLw~Dul<2p~6Su!&g#I8sqpMI_p0aZR_D8x;t81x<9(gfg6q4qiO?7G6+G@j~ zLnd48R8KJp371(Kfug)U)nZl>;hU=l+ZkS@Z}(}19ei&7iAih8G`r%Om+9s}&7^v7 zo=u|~!m?NQ?mAUyoNx3eI^zk=n<3;v?g$Jnk=nLUeFe|#p5lg4s67|scbT_)un7RK z=PcE5(t){U_IrOacdX96wHaFwd#Nz0%0)+4$hXGd8|-Vg%IaSs6>8FAoQiB6K{b** zIbCQzh;n-L`@XW`eD6_bpqMR;Y{sC$&tOTXPRyJ+NorYNzfaR6VuDvWl2Z#Do$o| zhc2w>{PTwub}hBi18$o!ArFvYm{-y!IiBtY2}tK%>2CVK&cEh(MkL6 zrk|!g%&*ljXzh`}Og)J>*EYLjx}LGndivW=i*8z}geY!(eK@A7>$oHT(LDAc%B0^&^*=TGFTf zdi;@pW;+swiohr32*28ea)dQJ zhmFtfB$ILUqPNfrfL`LkuKL+i%IQ<%Ds&Xba6gp;lchYX} zgWZsKBlM;Npw?L%f$%W;@e?7!DC}7^tb@yq+hu*a7qu)`t>?{CdkfJ*gM~E=fZpDW zAcI7rzO#ghs_PA*ZOtS{CsBUTVoSA9T1Sx^0GAo*NX5m0N`fv<;QnYScSigCd&6jO zLGAV*BKhyo{y&K1KUR^l|HEDp7YoN9V6G;$|MxoErGew5qQ4VK$P#XG+j_jM)qJ%p ztY#m(bFw__386{T%Phkk#??_hdx4MC%dCvD(+~ zN?_w3(F1O7pI*a;n?HUPr6F%Z(7ZTfJR`t&VX-CU7AsB|n-K&}ei?=5-Q!o`zZT0V z88T17RUELh$$k%X9OSRL=#Zb{T+2ZP6Qbm+(0uj~tkf{}=GCMnDK?Y2>nk`IXaJQS zSLimajm^9u?hUI6kkew#MCo{M!3Tkdel_fjjU&V+A=`DBm@@mOH_%zRyW69+qsbm6 zf}&(5)^8pgm0LRDw^c>UBia{CHEe2+$FQrz{v@0_SH3tD$>-$S{R)&OwC9Mz2NA_P zo7Arx*5R1z?U+g^xb$X{TJxr>!0wrvOIt$pIMJFSGhQzZicyV;6L=O}&!C5*nMM0-$Y97f+K48J#t&VYa$RWIZ3@L%}Dw$@YeEc*Lz0C^^Tq$f!(G5v@AiGgO6^ zZjn(u6__e`^P+^EDRqIEhM}F)W%(WCv?Qp4YbBGmQeg&w8_XU`Nrw^NE0&rd8ClG+ z>GEW?fI2zA&wneWg}ARG3oR2C-pitU}j9Z)+OUoLvRgpf^i zn2+4!i=^im#?+h`Q8TvL;9eEP%~ZPKeE52qR97?mV6=jr0!0PY+s~M6GDWq5PT{q) z>Y9eACl^U%Yz~A!HaKvV$)41#9z9;4H3J7r_Qv=HLUQ(om%XTz10c*3khVXPx34WN zwVOx)&u2Ss1dh+s_RYKbUF}P&qtGo8Gnc(vX=$FR|Fp7efTKmdgJ0(r=!!iP4%&K<(dud_+JIneHO3QzO>e&C@H2xQ}nvKwA_u4qh-*@6FwvdU&wJvV{~$;6uLLUhGR1ix<)W zkq&20&<~c@-pfuWeZ`B+Dt~LpRAK;?U?4@=(ByqQ-%-3$bdio0e@F{^ z#BigfgLn35dEcaF(`L=&?JVp*4=8g+MaDtWX%2 zL+umm+s1?#1A1hI25A`R=c>!*;UR;zzVqm8x#T=Ur3ijIm!8*bK`H`S0y^zAEbdp~`6alOctVdRRf{t+G7 zG#PsfZX+m)rM#IZ<&!T&?!;VcU3M4}xvD6T87-W=8yJN6NJc`x#P^JIaXTdN*4C-J zI@-kP<%VZL!hOp#_V@6l0;hHohm3}Al4(tr3=@m>7dX?$XI#DBZ54f?dZ^?+H4ymXI?YMv<{e`%oQ~h zqzD%!OiZC&jmv?A)OSp#kIZ0C)!z~aO?>5O26P)K+q?VsI1oMs?st`sYJWScy0fh{ z{6l{JodNx~^7HS_%YWr3JKLWu7Xwt}oPUGZ-v(!o@j+!Vw9pZ?1PkO=+>18tWcY|k z=kdXD-@kM}w7Mq%p_X!?&0^*IzU}lZpHjEDwW4qiK}NA)`Mv&x1Rg3L-m|>u`E~I1 z{42f%h9h3xK81|b1OS(Wxd)qLv|F(>jOg7T=4T*7`(a-k(?cxh7Di;kT)p40fZ{4k zM=TQS0Y4|bnzZMa!j*yE-85Gnys(u+;Bh+(*{21lsnfIRWUVEUT{u3x_?#s=U6Df6 zQ<^@CgVhXP~rCQy3*KAMLc^-dF1D`TpPnQLqa|H8EGbfE$X*;stlP7^_T* zSvfsbzVkTGT)VVr+fjHCp^1&d$gYCAuf78Zd{)cd-F7dVT?+i%9P|7ZbumOn?HycNKh%IOBSxaH=8AmOSGOZte zc)w1Pn#w!J8}|}T%|O{xl@nk`z&B@Vb|)3enZ43Tr$2lpU^~XH%^j4qggdQ$OS!_3b@W+?R&D?S8y5Vf- zpiMdz;#swrs+Wjlays3>GXX#k{*X`eOp(V}^Dg+vx4*R>4qCPRq18m*JJ!^~)6rd} zkd+8A#geWf4yK?NMG7aS-8|i~niL+dZ6-z_6xk!Ea4G+$54H~55RL>H=txM|k^u<@ zdn$7y?h)i1WM#%8-%L2=d|!K@7HgV72*Vehx!jP_Aro-pS9ek`?wKFMNk~ ztPt_pv$da2pW6S>CLfjR(bYj&!V@QR?ik^jzf^A=fi5EpUW5IMtfcf@$Myr=5Qv}7 z{^=jm>F@mPKS-xPM$#OAZ>JXt@Uj=+A z;;)|FnOWlPf|B3aE%yvh<2aeIqw>OIOkbgRF}MgG0>DL`u0tfVNj4jKBavIGbH_El z*{@~Uc;~Q?z}fER1409pa)t?Kd2N&r!>Ywdn(Ay5W@w|0Crhvj5%(p^5Z@k*5M|_J zPU(Dto55CJ*!B9I+Zl*#8Wsi4I;tLdJUvL8#kr#^V|yrvv+Kk&0ZS?C zw%KNte3_i0s$;;zokTNvX=>i?p9CA0UFeddJ z##>D>Y!PXs57y1%HT?cW=yVLydX{x1n8CA3fX!vlskd62H9)}<@U@}1_VUi4;`Qgc z>R6g;^0!r2;Wc~K-^{Q{_Px}1E(G^L&Gal+(z7zZD@znr$Q0|`tG2_Se%ty{%l)}n zGrD+a@RaYFP;=dK)F>3(hHI1wfno#RDS*CcPrJe`^NW(+ypZ^vKsZ`X|1%7LYr=YQ zc+5#DHnnUuhRJ0yEJyWpWWNEg&rK?ZV9b6Hi8qz0;o^`tml^ZyB^~{jGLvxrkm%nN zh~w`J@jpnQ{{$~`{1aYe`jg4lR*Ia$CL`A9)e9Q`MyBoiTI|JnO9i8yhEpM`Q|4R) zdSnKp+uq<+J^s8Y2$&_0ZOsxZ!|WTwr@K0)1Vt!NIRi{Q>9>V`PleM;;Y3%*`xCUW zj=|lBio7gTbw3*EFQ(-*J`FjeQ8(JjQ#1uxm=#My*x5dNQmlN1x=d=)Fj>CUy@tA( z`%cB8;IUunvYh$7Wb3cb5USr#=6@~bjd3x}@3Y;cCx2Ju;x7*FN6&Q<9wjwCCUR@#TQ>wkFsv%{oy;o|czcpN z7KuC<1tw)D)7fFEVd}r@x*UHwTk*ZM8ye~aQ7XnB^PI{FihM$hC@tYKQcHH$ym-7w z8b=-JPDpX{)%5lABy*?`FM4Rxs#$_zDOZKgPUu(8zm=X>fe=qgAy7D)>=#v`t7^V< zcY-V6jn1UCY=!nN!MDQ=%vMC7za=IWi;OtnkY#!jprCR0h@%xM7>nj+kj6z+%E$O3w2?Kh=g-( z?h9$IRGa-+mJ5f`a!&-{MkZDA=5v=wY$Vng{t`mAp~-7AfYd z2E$=JI4(II{uS12ktwGLW31(`*c~b7^pYfSH!2f*r0r2p<{nGh`<`%IO2aH0a0o3I z4;{PFx?{>9!hQJCuRw$I5t9#AR9V8y1fRgN52^rj%54}cHRWn8b-I`Y{1mnlV#KmR zR@w!3$uEmRo`y`E?3Z=d^Gt^-y&{tYbola*hFqQ((dvjXWhP&~rj{i=IO@Hl7y|h# z%P##x68;~7LS~}B@<;i16X*Y*raZ?#z(ZD!KN-wT0fZbf1(8DjYRcc&=~#_VHFOFV z7nbHrm=4;V$HHD+@IkrFh=0T(P9`b9FKa?j1oB2RFV= zM1j0B3u%&Czsm7$wqrtDo5cUs8sO+<&|7^WnnaJh~QpHIl8)?^l3uEPdkXHDM|UQctaCAydnr8yH3MAiq{=yuRL4g#Q)sZ%MNuxB&c#%!xk+cFAo9d^ z-xf-++E%;y+DCuYl77e`g7*|95lht?T1kz2AM<^0Bk%6Kbps)UJ~DNmQeU{^;Wa;p zkNr1pdwOW-Y5)1D&2TPli{O(cL^#_I2|=6f{K7B(PO)wzT95tKCkGz+6-KcZ+yzS^ z6{vI{Vv!g|HvwDvh|UoHZ70*ylz$_RWjB@KBhF_!cKbV}?AfAK{-!P_hr=!Z5T*Yuti|~cSc~P4 zl>08q*Z^^>N}ON|&pY#- za2-_IRTR!N-@Y%`vmV7-5GC*=ltDlDS;B6^TgE{LuoUkwD6z$WDzXjh3A zXwj%cRc{kO@eMkNWfk*DP*^%x6xKM>Uzv%8r&SCc%K*~6`)jZQSDMW=lZ%3$;xH3F zTyZr<4LN6zb5rx3C){)4(R)33wy@r|lCQw0C0zL1hI-q{yZtL2^Ud2dcvX`$E{FYx zA(Dn90FQS`+(Zqx>+CQ2(1|zGvCKKciL|n6gun){1SZZJaQ;xFx>e#6P*{lI1hb?A zqLWfO+g!(;N`cZ)xqXM$GcKi%#aNV!%E;x3&M9Hs=%_-Ag@F(OoRKMsUy&zaQ>ynW zS`i*0!}uCxQSn5wf$u{7pi%uo+AI7`5}w*B{Ln~nt?ah###3H%``-w6;!_u(BSUbJ zXmX7NRC4(r4Fef|8+Ll8l-T}z#Bly!f{Q;!=bV3^W&R7DGchv$38bjfka5^#gzGud zIIauoo{r7=hQ?#6w~F3beOIjmJL<_Ql8F}EVD#%-5$UE=7MdgvW;k8cJ7prF)KeE$ z3+m&Xa z6&llMgp|kOAZQgIes}rC(BVzdK52Ubw}&=jIOCjC5+#SE%fXOi=$>CdwNop9)*xtM zObtRUWAl7@JlP*^_gy=`UzAT;9vrl43zb#9Vclrowvqm#C5ldS znhVNfMJtQ?jQA%S{XV)ba0pKoXolnnSw59YB(kOyH1HvSY+$R%bG%3pS<@B4To~$X z4}U1A8x&p8LKwtj04Eo<^^s)VHUTLb z@+;A`aDK!H8Ya={j?{!%=S_6$DDRIeN^U^D0676c=$!<$ahHgnatM<&r-&bl`9PXt z@rGz?*;W*42qkM9Qabq*i~|ISx+QG@>R>>+EN-06k{z}a&U+0y5h!C%s$sQN}wE@}0_7ZA(ju`eB?ozjV$mTDlm&3n$2UxiJID#nCk~>I$ z+N#gC>NM*MelsFvS{cKY@K@_~uQ$QJnaip(oLxRU zF&PZNxn#v#1{Lh>m9Fi56{9bwxeYRbT&bnBbsniagJ_=|-u@xANlusSp+_x`E&rj4 zNAD1Jas+bLJvscfN=voMH*A&WbI~Fjv}*IbL~0eslGf_5z%oJ1>9EAaTXK<=5!-U+ z3LirA?S$XRHY4zYyjY`FjWDzu?`Y|Vh09cFde6^guiksHtkN!nw{4BNJ(aN0h6MIy z&;dblOwP36HI4EQu!TJ9O&6Kaj(G4tV)vzh%Ub$BFx=@x=*3f655(gE4JJ z12kjEd*6YLn@b;Txu`3o0gb&9E0Sieq_gXwxa$}y9%#owqLm>W@r=hIA_8dWDVAzR zmAAF)4uI94UFZeTdt$}K%_~gC6Jo#km6rCsT(^>uB1@_`@xD^uo*HFeOb$+78ZbH7 z)Y}`JiZ6{$yX87jDg}soDW~6g5nD&*Yg5GWQ>-e7d2mbYoSvON&JbU24nAwhGxJCL z3)tY3Hb7CKw%ff1L>9QcQR5$jM1Y>lP=kcFOOt`V9_ z76G%!QjJGw*CNloe{e{&nmPg&WEiKJ+1h(FM}Y#~HF2+ZH}8+IAIWiyyVXZganql) z-;rptf52RA8<*+EZ)|RYGA&&`L-)^Uyg71qHSNcpJ?4IFJL>ILudt=x7vNv5=HhD8 zySeh@tUko9d|!)2Jd+z#dZuW(>o+QEMV>bN5zR`Wb_ZNiAT!A;oZkguQi~p&=%~Dw z$DH41MWXL`mW50liZm_fGj+aDWxQ{*vO2QK z{C$1iiH;d^I0t3{3RVzFJ~bhI*fV*U0D(pzKleQwFh?_MlZ$tWon!l*0Ny||C7s8I z9NGYG$a9I*n;A^Zm1X$jmYpQAuO^$!q)Dxm9GsD$#V%Zc>5=SJ0(5a|kxoW+5`XtA zb!Cr;k8k@13|Ie~Sos_mD)s&(;m81@9D~K-)QZL$0OCDK`x}KDatCmGT!R`(* z)p$u4z$8z!&cE5UF&}ZPo zobg?2g0}kll|Xo;3gpA=uH7`X1bY3V_@C6oGDjB+NiahqO#fGFPXZOim2EJI-*j}0 z6H&w^WgHa}rMi}0N(}}Y5GPTv8x*2qitcJC=~pzMY>duJ34Kl;wxOK;pcmGJ4I9oZKu&tyECbH9B1!7X0~ip0X73qHIQ^^bpU z{pB(nvb^YMs3Cde<L;+3<@7MgnA&RCdN**AXBiDftL4Ytwa z3RZ=r*X4J6`NVrKj7j>X&zba*#Q35UqXSFs=D3rMl?BJPJhAFO4;;-2YzpnLUP7j<(m_ zTfgGn;}^Rpope5sYL`p9U+A`U%Fou#zaLV);Yf3pP`f#DMEPoF>*=T{TrrP4kA> zc2PytM|0<2=)xzAI1w`Non6Zq-V(+XX1w)uR@wvlzyBZ}|F}#{xD>ebYSVOP(D;P- z|FD*fJosaziR>QR>CD;L4MQj0f5SL9X48R^h^Ud<6Mqf=r_d0d(Ad;(eOZ^qHT#5_ zS85Gqhi-;v)SGf{i`?NWUsOpyepB_k{yo0hem}DEdo0~viO-1+J#nKhZ{?DDEHx$W*-z{#1&{REeh;3Ub!{ZXmeZ_CATT9&i ztmo>9q28LB_rF=%)L{SZ`R``2wQF(~?o2D6eQtMiN=}1#BqL1Pv-e75w0F$8!a5Vp z_5S{L(b`QZQ8Oxb@J!v`%Qqc-e{V4+j9dBKr*j?GBI*+F9eQGgrFY23ecoJo=Kiwh zVm`)RzE-p3=Gh6?&E4)baz8wKe&f^4gO_w(D}1v4d__q23~qN!`Q-HXHm!>_`c4j# zoORI?M`jeAoH}d9GfhY57vA|k^}Xn@CqF9r_3~$p$?0`n`!A_D*jLOQuqg5{nfRyG zYswM_N4h2ydL~@_>&V0d)pzXacb4tg+3D+wQ}aKk-+DRj@F{D?sDE9`@6zXstDl5M z6(=M%Cr=#J#5Z^S$&o#~V0fH0?Z^iq&(7J<^&k1suP?t`R(^g|(&EB1A%P)91D-m* zu~*DfotV@s70(xz%+Jr8o@h1iKQZsyns?(GmYtvQ!qfZLhivORZ*HB>(986>C%TuR zrZ?@b|Dqqgw{U*cq`F1h`VTLDt$fGr@y0#zJ0ff8-0VnJ376~%!ubt zkZXE{4#!KfD~dN9v&V+#PY!v@J~nmUwCK&owBP>c!O;A-ht==PZQe6)t@qo!f9+lH z@uFd?b{4-#u@WB?c2J0^~{~8Qhp7uT07cUw__;QtMlAp z(Z+RY(|&Ypqn_E_xZoB&Ypd<(SGHHL{*LZ7=GsejUtRWW4_w{VyWZygEwyy+o%-Af zWhJ#^w*B$zlohXEyO(+FGe@`5Ia7-sxJy@^JjqSy{&v{(n{R$r-}IBGeq-a?3y3*x z-}`^uI8SoFx^wKY;hi#Se(IiAUA5t2xNp+7yG>!o&;1ayul7B6anRCF# zbG>+q)c4xT?(5FO=G_)~W0Ai0GRiHYptbk^d&iVf?rWqJt8;NuK!pAa0p zLaX)6c-G5d5pkTG4S1wTuzM?V`2o)7EWpg*2Iv@HmWRV=a6!?LCrAkapHt!mABNk7 zfX@YA8_D@x@JGs&J%=ngex@|WA+Zt=?TEqLtj7;NB_+3hN=(7<7NH6@%C(QoCPDB? zfI}ctLiRu)P#!6bCxDHVc%M^n@xCmKfp-{z-RD@=&p{##PvO0sfB0C5_3%!G4CSWw zBgg=6<_IdoE_hj=LWFWT^#~$Bn-o+;tl&}l8@;!)_1EDZK?JzBvfVL`0&k|^QRs_& zr{>nGkO7b5-EL0gd``}fO~#Bk>v!_JlNX)f>IV8O@g5h4JDjX2`0zL6gI_+(k`L)F z9&qsUeq0h+7w2WgTmzmT5F`LY0mjg{%+c-PW?}?s#t~ES$*RE11Vf8w1$d8#^9quO zb4%^tL_RB9!ZQQloP@hQg2?*}xLagVyyAJBC}j%)KkIYhE;cKR6I%|hOb-r1nDuAl zoEIJ3ZrsfSQV;HS^WfiuyPzz;pKtw;gJ+5CbPmrB__A0r;PtQp37%t}P7VfZrpSS_ zvgJUHEL_L}GcZ>+1PDZmBkREzS#N>EJ$?_+qQx!X1Tr=$9)BIdF~SU76cFJ!6o4;g zAVtXKe3`5WzFF}$2Rntlf)<{l%guRt9}j0g^cwOt67CVQcqi-e2@(zv0)AZNvUtA) z#>jS1_+=DnhTsnXKk|ZTz@=<(vh^#@Is+1idjl9@rJ$>M!38~m z*f}{D7%vtF9%#cCM3)ytPQU|HYu5~EZGedR0agUm@MAW}U$V3opdTX`5|5EbAV!uP z(;ho`j2w+ItquVx42?ldJZ@{%C0?eEm#O0w)bXuk_*jHvz{ko+V--ka+mPa=Y<#>d zFiGZ_B%>#_ql2W^g3(6i1(}x5^AzAoXl(IRnKo6XO>L*eQ(I{ac)ENxC0h`EI0#^n zaX^&#aaJZ~<^{FGP=;t6AW$(MjM%npU#8iA;^vh$dmz@GSE(m2U;l%c!7Kt%xB<; zf;RY6MLyHl!DKcI%z|VV%pVDZ7mPrquycMPAi}gJzXTb#fwBS4`!Ttcv{yIf>Q+v+ z59dcf1%QM$h6L;j&})`k>Lme1s55R5mMs@o+gZv=w<}5L3tJGDuxP8agmp`$rSj6+ zqZp2Upk2ihx=zWGeB7}ib%UcF9a7&lJlt?nwzGYBNa#A1mim4s2us;c1xq=|+J}cy zwuX=5OZ1{|r7zL1u_(2q9@lV6YdCtHw~A#D!|9gDR?Ho(<>;-gN}hC(Sl9DJulrD% zj^3K4;u$2^JK(8}cJzV|70)2iuIGs!Qda4y4R=$JaPNSpHr~+#%1S*=L595pp4xFo z4?L=PKK8hqwBv5lM!Y#l#Ow7$PYEdfi5?VE>S>1Fc}U*ufTujS+h-+s)8B58-K%lbE6gp*!A`wxe4+m3mr&*xmt8t?lR*HxEtEX1L2`&*Pph_IqKok=oHyf%OtBWEg4%zyS>vhDxp-LuC>ikPR3rM|KRA5c^cvssuo1 zM1UoKOOr%vTNX66^da4*2PHE`+1?Je43H+YtO81db_``MaF8)kez0R`N`nK+QIDhv za^gcYL6gspq4@$1h%si7J%j?uj#*{(tVq2!p@mPCtS$f-qLm8c8#)h0z3Q)XFfD7Fg-jv@`>!s|p5aty+FYlM(Ly zsPK#yV+V36SU@y*gkCN~!osb>qY2uilL4O3)xrpZhS@|zYl2;-3I^VqrW;>^GU@z6 z6J`R;QZ+5r0n7yAM}tQb7Ngdugvp}w0bwO|V@WX<*lerh0)8+@s9<1w1LiX|jImm@ zFdE!;tA)YYsP!L760liT@uMlTPA*N+u=iKv5e#e$RWM+gZrn)P3|FHnJeoA>#)zcB z(J zS}9m;RCqK=!Hleefmbe@wXsVwMzdaL@asleS_TB021XeP*tDo*(4+~bY!!?$>hlW) za*5V9nl!_Lt)>NONDpK5bAhzz_)(-0)>}0{(xUSz$fmG-s_?)phdab77)X=4`AdP= z)zeyG0anveR$W|y5Z8?d4P2$unFfKX&~z-%M6<3X88 z-Ta^|U{-5nfcgQOFtuC@rMH&>Sy79}kg$PJ(=yf$^s~TbR)t4XAUUbhan zC~)zFpT)uY3ohCS5{B9g&~J|QxdjY05b#SJHhC0bp;(LA=^~vZ$7MPRcP8PaSfhn8 haSZ8ZUD3fYP(S0B!1gUF`!vNcR>R=I@kt4W{{?omqul@i literal 0 HcmV?d00001 diff --git a/src/cmd/adb/doc/adb.txt b/src/cmd/adb/doc/adb.txt new file mode 100644 index 0000000..c44ac5b --- /dev/null +++ b/src/cmd/adb/doc/adb.txt @@ -0,0 +1,760 @@ +====== A Tutorial Introduction to ADB ====== + +//J. F. Maranzano, S. R. Bourne// +//May 5, 1977// + +===== 1. Introduction ===== + +ADB is a new debugging program that is available on +UNIX. It provides capabilities to look at "core" files +resulting from aborted programs, print output in a variety +of formats, patch files, and run programs with embedded +breakpoints. This document provides examples of the more +useful features of ADB. The reader is expected to be familiar +with the basic commands on UNIX with the C language, and +with References 1, 2 and 3. + + +===== 2. A Quick Survey ===== + +==== 2.1. Invocation ==== + +ADB is invoked as: + **adb objfile corefile** +where ''objfile'' is an executable UNIX file and ''corefile'' is a +core image file. Many times this will look like: + **adb a.out core** +or more simply: + **adb** +where the defaults are ''a.out'' and ''core'' respectively. The +filename minus (-) means ignore this argument as in: + **adb - core** + +ADB has requests for examining locations in either file. +The **?** request examines the contents of ''objfile'', +the **/** request examines the ''corefile''. The general form of these +requests is: + **address ? format** +or + **address / format** + +==== 2.2. Current Address ==== + +ADB maintains a current address, called dot, similar in +function to the current pointer in the UNIX editor. When an +address is entered, the current address is set to that location, +so that: + **0126?i** +sets dot to octal 126 and prints the instruction at that +address. The request: + **.,10/d** +prints 10 decimal numbers starting at dot. Dot ends up +referring to the address of the last item printed. When +used with the **?** or **/** requests, the current address can be +advanced by typing newline; it can be decremented by typing **^**. + +Addresses are represented by expressions. Expressions +are made up from decimal, octal, and hexadecimal integers, +and symbols from the program under test. These may be combined +with the operators +, -, *, % (integer division), & +(bitwise and), | (bitwise inclusive or), # (round up to the +next multiple), and ~ (not). (All arithmetic within ADB is +32 bits.) When typing a symbolic address for a C program, +the user can type ''name'' or ''_name''; ADB will recognize both +forms. + +==== 2.3. Formats ==== + +To print data, a user specifies a collection of letters +and characters that describe the format of the printout. +Formats are "remembered" in the sense that typing a request +without one will cause the new printout to appear in the +previous format. The following are the most commonly used +format letters. + +|| b || one byte in octal || +|| c || one byte as a character || +|| o || one word in octal || +|| d || one word in decimal || +|| f || two words in floating point || +|| i || PDP 11 instruction || +|| s || a null terminated character string || +|| a || the value of dot || +|| u || one word as unsigned integer || +|| n || print a newline || +|| r || print a blank space || +|| ^ || backup dot || + +(Format letters are also available for "long" values, for +example, `**D**' for long decimal, and `**F**' for double floating +point.) For other formats see the ADB manual. + +==== 2.4. General Request Meanings ==== + +The general form of a request is: + **address,count command modifier** +which sets `dot' to ''address'' and executes the command ''count'' +times. + +The following table illustrates some general ADB command meanings: + +^^ Command ^^ Meaning ^^ +|| ? || Print contents from ''a.out'' file || +|| / || Print contents from ''core'' file || +|| = || Print value of "dot" || +|| : || Breakpoint control || +|| $ || Miscellaneous requests || +|| ; || Request separator || +|| ! || Escape to shell || + +ADB catches signals, so a user cannot use a quit signal +to exit from ADB. The request $q or $Q (or cntl-D) must be +used to exit from ADB. + +===== 3. Debugging C Programs ===== + +==== 3.1. Debugging A Core Image ==== + +Consider the C program in Figure 1. The program is +used to illustrate a common error made by C programmers. +The object of the program is to change the lower case "t" to +upper case in the string pointed to by ''charp'' and then write +the character string to the file indicated by argument 1. +The bug shown is that the character "T" is stored in the +pointer ''charp'' instead of the string pointed to by ''charp''. +Executing the program produces a core file because of an out +of bounds memory reference. + +ADB is invoked by: + **adb a.out core** +The first debugging request: + **$c** +is used to give a C backtrace through the subroutines +called. As shown in Figure 2 only one function (''main'') was +called and the arguments ''argc'' and ''argv'' have octal values 02 +and 0177762 respectively. Both of these values look reasonable; +02 = two arguments, 0177762 = address on stack of +parameter vector. +The next request: + **$C** +is used to give a C backtrace plus an interpretation of all +the local variables in each function and their values in +octal. The value of the variable ''cc'' looks incorrect since +''cc'' was declared as a character. + +The next request: + **$r** +prints out the registers including the program counter and +an interpretation of the instruction at that location. + +The request: + **$e** +prints out the values of all external variables. + +A map exists for each file handled by ADB. The map for +the ''a.out'' file is referenced by **?** whereas the map for ''core** +file is referenced by **/**. Furthermore, a good rule of thumb +is to use **?** for instructions and **/** for data when looking at +programs. To print out information about the maps type: + **$m** +This produces a report of the contents of the maps. More +about these maps later. + +In our example, it is useful to see the contents of the +string pointed to by ''charp.'' This is done by: + ***charp/s** +which says use ''charp'' as a pointer in the ''core'' file and print +the information as a character string. This printout +clearly shows that the character buffer was incorrectly +overwritten and helps identify the error. Printing the +locations around ''charp'' shows that the buffer is unchanged +but that the pointer is destroyed. Using ADB similarly, we +could print information about the arguments to a function. +The request: + **main.argc/d** +prints the decimal ''core'' image value of the argument ''argc'' in +the function //main.// +The request: + ***main.argv,3/o** +prints the octal values of the three consecutive cells +pointed to by ''argv'' in the function ''main.'' Note that these +values are the addresses of the arguments to main. Therefore: + **0177770/s** +prints the ASCII value of the first argument. Another way +to print this value would have been + ***"/s** +The " means ditto which remembers the last address typed, in +this case ''main.argc'' ; the ** * ** instructs ADB to use the address +field of the ''core'' file as a pointer. + +The request: + **.=o** +prints the current address (not its contents) in octal which +has been set to the address of the first argument. The current +address, dot, is used by ADB to "remember" its current +location. It allows the user to reference locations relative +to the current address, for example: + **.-10/d** + +==== 3.2. Multiple Functions ==== + +Consider the C program illustrated in Figure 3. This +program calls functions ''f,'' ''g,'' and ''h'' until the stack is +exhausted and a core image is produced. + +Again you can enter the debugger via: + **adb** +which assumes the names ''a.out'' and ''core'' for the executable +file and core image file respectively. The request: + **$c** +will fill a page of backtrace references to //f,'' ''g,'' and ''h.// +Figure 4 shows an abbreviated list (typing ''DEL'' will terminate +the output and bring you back to ADB request level). + +The request: + **,5$C** +prints the five most recent activations. + +Notice that each function (''f,g,h'') has a counter of the +number of times it was called. + +The request: + **fcnt/d** +prints the decimal value of the counter for the function //f.// +Similarly ''gcnt'' and ''hcnt'' could be printed. To print the +value of an automatic variable, for example the decimal +value of ''x'' in the last call of the function ''h,'' type: + **h.x/d** +It is currently not possible in the exported version to +print stack frames other than the most recent activation of +a function. Therefore, a user can print everything with **$C** +or the occurrence of a variable in the most recent call of a +function. It is possible with the **$C** request, however, to +print the stack frame starting at some address as **address$C.** + +==== 3.3. Setting Breakpoints ==== + +Consider the C program in Figure 5. This program, +which changes tabs into blanks, is adapted from //Software// +''Tools'' by Kernighan and Plauger, pp. 18-27. + +We will run this program under the control of ADB (see +Figure 6a) by: + **adb a.out -** +Breakpoints are set in the program as: + **address:b [request]** +The requests: + **settab+4:b** + **fopen+4:b** + **getc+4:b** + **tabpos+4:b** +set breakpoints at the start of these functions. C does not +generate statement labels. Therefore it is currently not +possible to plant breakpoints at locations other than function +entry points without a knowledge of the code generated +by the C compiler. The above addresses are entered as **symbol+4** +so that they will appear in any C backtrace since the +first instruction of each function is a call to the C save +routine (''csv''). Note that some of the functions are from the +C library. + +To print the location of breakpoints one types: + **$b** +The display indicates a ''count'' field. A breakpoint is +bypassed //count'' ''-1'' times before causing a stop. The ''command// +field indicates the ADB requests to be executed each time +the breakpoint is encountered. In our example no //command// +fields are present. + +By displaying the original instructions at the function +''settab'' we see that the breakpoint is set after the jsr to +the C save routine. We can display the instructions using +the ADB request: + **settab,5?ia** +This request displays five instructions starting at //settab// +with the addresses of each location displayed. Another +variation is: + **settab,5?i** +which displays the instructions with only the starting +address. + +Notice that we accessed the addresses from the //a.out// +file with the **?** command. In general when asking for a +printout of multiple items, ADB will advance the current +address the number of bytes necessary to satisfy the +request; in the above example five instructions were displayed +and the current address was advanced 18 (decimal) +bytes. + +To run the program one simply types: + **:r** +To delete a breakpoint, for instance the entry to the function +''settab,'' one types: + **settab+4:d** +To continue execution of the program from the breakpoint +type: + **:c** + +Once the program has stopped (in this case at the +breakpoint for ''fopen),'' ADB requests can be used to display +the contents of memory. For example: + **$C** +to display a stack trace, or: + **tabs,3/8o** +to print three lines of 8 locations each from the array +called ''tabs.'' By this time (at location ''fopen)'' in the C program, +''settab'' has been called and should have set a one in +every eighth location of //tabs.// + +==== 3.4. Advanced Breakpoint Usage ==== + +We continue execution of the program with: + **:c** +See Figure 6b. ''Getc'' is called three times and the contents +of the variable ''c'' in the function ''main'' are displayed each +time. The single character on the left hand edge is the +output from the C program. On the third occurrence of //getc// +the program stops. We can look at the full buffer of +characters by typing: + **ibuf+6/20c** +When we continue the program with: + **:c** +we hit our first breakpoint at ''tabpos'' since there is a tab +following the "This" word of the data. + +Several breakpoints of ''tabpos'' will occur until the program +has changed the tab into equivalent blanks. Since we +feel that ''tabpos'' is working, we can remove the breakpoint at +that location by: + **tabpos+4:d** +If the program is continued with: + **:c** +it resumes normal execution after ADB prints the message + **a.out:running** + +The UNIX quit and interrupt signals act on ADB itself +rather than on the program being debugged. If such a signal +occurs then the program being debugged is stopped and control +is returned to ADB. The signal is saved by ADB and is +passed on to the test program if: + **:c** +is typed. This can be useful when testing interrupt handling +routines. The signal is not passed on to the test +program if: + **:c 0** +is typed. + +Now let us reset the breakpoint at ''settab'' and display +the instructions located there when we reach the breakpoint. +This is accomplished by: + **settab+4:b settab,5?ia** (* +It is also possible to execute the ADB requests for each +occurrence of the breakpoint but only stop after the third +occurrence by typing: + **getc+4,3:b main.c?C** (* +This request will print the local variable ''c'' in the function +''main'' at each occurrence of the breakpoint. The semicolon is +used to separate multiple ADB requests on a single line. + +Warning: setting a breakpoint causes the value of dot +to be changed; executing the program under ADB does not +change dot. Therefore: + **settab+4:b .,5?ia** +----------- +(* Owing to a bug in early versions of ADB (including +the version distributed in Generic 3 UNIX) +these statements must be written as: + **settab+4:b settab,5?ia;0** + **getc+4,3:b main.c?C;0** + **settab+4:b settab,5?ia; ptab/o;0** +Note that **;0** will set dot to zero and stop at the +breakpoint. + + **fopen+4:b** +will print the last thing dot was set to (in the example +''fopen+4'') ''not'' the current location (''settab+4'') at which the +program is executing. + +A breakpoint can be overwritten without first deleting +the old breakpoint. For example: + **settab+4:b settab,5?ia; ptab/o** (* +could be entered after typing the above requests. + +Now the display of breakpoints: + **$b** +shows the above request for the ''settab'' breakpoint. When the +breakpoint at ''settab'' is encountered the ADB requests are +executed. Note that the location at ''settab+4'' has been +changed to plant the breakpoint; all the other locations +match their original value. + +Using the functions, ''f,'' ''g'' and ''h'' shown in Figure 3, we +can follow the execution of each function by planting non-stopping +breakpoints. We call ADB with the executable program +of Figure 3 as follows: + **adb ex3 -** +Suppose we enter the following breakpoints: + **h+4:b hcnt/d; h.hi/; h.hr/** + **g+4:b gcnt/d; g.gi/; g.gr/** + **f+4:b fcnt/d; f.fi/; f.fr/** + **:r** +Each request line indicates that the variables are printed +in decimal (by the specification **d**). Since the format is +not changed, the **d** can be left off all but the first +request. + +The output in Figure 7 illustrates two points. First, +the ADB requests in the breakpoint line are not examined +until the program under test is run. That means any errors +in those ADB requests is not detected until run time. At +the location of the error ADB stops running the program. + +The second point is the way ADB handles register variables. +ADB uses the symbol table to address variables. +Register variables, like ''f.fr'' above, have pointers to uninitialized +places on the stack. Therefore the message "symbol +not found". + +Another way of getting at the data in this example is +to print the variables used in the call as: + **f+4:b fcnt/d; f.a/; f.b/; f.fi/** + **g+4:b gcnt/d; g.p/; g.q/; g.gi/** + **:c** +The operator / was used instead of ? to read values from +the ''core'' file. The output for each function, as shown in +Figure 7, has the same format. For the function ''f'', for +example, it shows the name and value of the //external// +variable ''fcnt.'' It also shows the address on the stack and +value of the variables //a,'' ''b'' and ''fi.// + +Notice that the addresses on the stack will continue to +decrease until no address space is left for program execution +at which time (after many pages of output) the program +under test aborts. A display with names would be produced +by requests like the following: + **f+4:b fcnt/d; f.a/"a="d; f.b/"b="d; f.fi/"fi="d** +In this format the quoted string is printed literally and +the **d** produces a decimal display of the variables. The +results are shown in Figure 7. + +==== 3.5. Other Breakpoint Facilities ==== + +(*) Arguments and change of standard input and output are +passed to a program as: + **:r arg1 arg2 ... outfile** +This request kills any existing program under test and +starts the ''a.out'' afresh. + +(*) The program being debugged can be single stepped by: + **:s** +If necessary, this request will start up the program +being debugged and stop after executing the first +instruction. + +(*) ADB allows a program to be entered at a specific address +by typing: + **address:r** + +(*) The count field can be used to skip the first ''n'' breakpoints as: + **,n:r** +The request: + **,n:c** +may also be used for skipping the first ''n'' breakpoints +when continuing a program. + + +(*) A program can be continued at an address different from +the breakpoint by: + **address:c** + +(*) The program being debugged runs as a separate process +and can be killed by: + **:k** + + +===== 4. Maps ===== + +UNIX supports several executable file formats. These +are used to tell the loader how to load the program file. + +File type 407 is the most common and is generated by a C +compiler invocation such as **cc pgm.c**. A 410 file is produced +by a C compiler command of the form **cc -n pgm.c**, +whereas a 411 file is produced by **cc -i pgm.c**. ADB interprets +these different file formats and provides access to +the different segments through a set of maps (see Figure 8). +To print the maps type: + **$m** + +In 407 files, both text (instructions) and data are +intermixed. This makes it impossible for ADB to differentiate +data from instructions and some of the printed symbolic +addresses look incorrect; for example, printing data +addresses as offsets from routines. + +In 410 files (shared text), the instructions are separated +from data and **?* ** accesses the data part of the ''a.out** +file. The **?* ** request tells ADB to use the second part of +the map in the ''a.out'' file. Accessing data in the ''core'' file +shows the data after it was modified by the execution of the +program. Notice also that the data segment may have grown +during program execution. + +In 411 files (separated I & D space), the instructions +and data are also separated. However, in this case, since +data is mapped through a separate set of segmentation registers, +the base of the data segment is also relative to +address zero. In this case since the addresses overlap it +is necessary to use the **?* ** operator to access the data space +of the ''a.out'' file. In both 410 and 411 files the corresponding +core file does not contain the program text. + +Figure 9 shows the display of three maps for the same +program linked as a 407, 410, 411 respectively. The b, e, +and f fields are used by ADB to map addresses into file +addresses. The "f1" field is the length of the header at +the beginning of the file (020 bytes for an ''a.out'' file and +02000 bytes for a ''core'' file). The "f2" field is the displacement +from the beginning of the file to the data. For a +407 file with mixed text and data this is the same as the +length of the header; for 410 and 411 files this is the +length of the header plus the size of the text portion. + +The "b" and "e" fields are the starting and ending +locations for a segment. Given an address, A, the location +in the file (either ''a.out'' or ''core'') is calculated as: + **b1<=A<=e1 => file address = (A-b1)+f1** + **b2<=A<=e2 => file address = (A-b2)+f2** +A user can access locations by using the ADB defined variables. +The **$v** request prints the variables initialized by +ADB: + +|| b || base address of data segment || +|| d || length of the data segment || +|| s || length of the stack || +|| t || length of the text || +|| m || execution type (407,410,411) || + +In Figure 9 those variables not present are zero. Use +can be made of these variables by expressions such as: + **b** +that sets **b** to octal 2000. These variables are useful to +know if the file under examination is an executable or //core// +image file. + +ADB reads the header of the ''core'' image file to find the +values for these variables. If the second file specified +does not seem to be a ''core'' file, or if it is missing then +the header of the executable file is used instead. + + +===== 5. Advanced Usage ===== + +It is possible with ADB to combine formatting requests +to provide elaborate displays. Below are several examples. + +==== 5.1. Formatted dump ==== + +The line: + **b** + **?m +#else +# include +#endif + +static int savlastf; +static long savframe; +static int savpc; + +static char isymbol[MAXSYMLEN + 2]; + +/* + * service routines for expression reading + */ +static int +symchar(dig) +{ + if (lastc == '\\') { + readchar(); + return TRUE; + } + return (isalpha(lastc) || lastc == '_' || (dig && isdigit(lastc))); +} + +static void +readsym() +{ + register char *p; + + p = isymbol; + do { + if (p < &isymbol[MAXSYMLEN]) + *p++ = lastc; + readchar(); + } while (symchar(1)); + *p++ = 0; +} + +static void +chkloc(frame) + long frame; +{ + readsym(); + do { + if (localsym(frame) == 0) + error(BADLOC); + expv = localval; + } while (! eqsym(cache_sym(symbol), isymbol, '~')); +} + +static struct SYMbol * +lookupsym(symstr) + char *symstr; +{ + register struct SYMbol *symp, *sc; + + symset(); + while ((symp = symget())) { + sc = cache_by_string(symstr); + if (sc) + return sc; + if (eqsym(no_cache_sym(symp), symstr, '_')) + break; + } + + /* + * We did not enter anything into the cache (no sense inserting hundreds + * of symbols which didn't match) while examining the (entire) symbol table. + * Now that we have a match put it into the cache (doing a lookup on it is + * the easiest way). + */ + if (symp) + (void)cache_sym(symp); + return symp; +} + +static int +convdig(c) + int c; +{ + if (isdigit(c)) + return c - '0'; + if (isxdigit(c)) + return c - 'a' + 10; + return 17; +} + +/* + * name [ . local ] | number | . | ^ | value; + } + lp--; + + } else if (isdigit(lastc) || + (hex = TRUE, lastc == '#' && isxdigit(readchar()))) + { + expv = 0; + base = (lastc == '0' || octal) ? 8 : (hex ? 16 : 10); + while ((hex ? isxdigit(lastc) : isdigit(lastc))) { + expv *= base; + d = convdig(lastc); + if (d >= base) { + error(BADSYN); + } + expv += d; + readchar(); + if (expv == 0 && (lastc == 'x' || lastc == 'X')) { + hex = TRUE; + base = 16; + readchar(); + } + } + if (lastc == '.' && (base == 10 || expv == 0) && ! hex) { + real.r = expv; + frpt = 0; + base = 10; + while (isdigit(readchar())) { + real.r *= base; + frpt++; + real.r += lastc - '0'; + } + while (frpt--) { + real.r /= base; + } + expv = real.i; + } + lp--; + + } else if (lastc == '.') { + readchar(); + if (symchar(0)) { + lastframe = savlastf; + callpc = savpc; + findroutine(savframe); + chkloc(savframe); + } else { + expv = dot; + } + lp--; + + } else if (lastc == '"') { + expv = ditto; + + } else if (lastc == '+') { + expv = inkdot(dotinc); + + } else if (lastc == '^') { + expv = inkdot(-dotinc); + + } else if (lastc == '<') { + savc = rdc(); + regptr = getreg(savc); + if (regptr != NOREG) { + expv = uframe[regptr]; + } else if ((base = varchk(savc)) != -1) { + expv = var[base]; + } else { + error(BADVAR); + } + } else if (lastc == '\'') { + d = 4; + expv = 0; + while (quotchar()) { + if (d--) { + if (d == 1) + expv <<= 16; + expv |= (d & 1) ? lastc : (lastc << 8); + } else { + error(BADSYN); + } + } + } else if (a) { + error(NOADR); + } else { + lp--; + return 0; + } + return 1; +} + +/* + * item | monadic item | (expr) | + */ +int +term(a) +{ + switch (readchar()) { + + case '*': + term(a | 1); + expv = chkget(expv, DSP); + return 1; + + case '@': + term(a | 1); + expv = chkget(expv, ISP); + return 1; + + case '-': + term(a | 1); + expv = -expv; + return 1; + + case '~': + term(a | 1); + expv = ~expv; + return 1; + + case '(': + expr(2); + if (*lp != ')') { + error(BADSYN); + } else { + lp++; return 1; + } + + default: + lp--; + return item(a); + } +} + +/* + * term | term dyadic expr | + */ +int +expr(a) +{ + int rc; + long lhs; + + rdc(); + lp--; + rc = term(a); + + while (rc) { + lhs = expv; + switch (readchar()) { + case '+': term(a|1); expv += lhs; break; + case '-': term(a|1); expv = lhs - expv; break; + case '#': term(a|1); expv = roundn(lhs, expv); break; + case '*': term(a|1); expv *= lhs; break; + case '%': term(a|1); expv = lhs/expv; break; + case '&': term(a|1); expv &= lhs; break; + case '|': term(a|1); expv |= lhs; break; + case ')': if (! (a & 2)) error(BADKET); + default: lp--; return rc; + } + } + return rc; +} + +int +varchk(name) +{ + if (isdigit(name)) + return name - '0'; + if (isalpha(name)) + return (name & 037) - 1 + 10; + return -1; +} + +int +eqsym(s1, s2, c) + register char *s1, *s2; + int c; +{ + if (! strcmp(s1, s2)) + return TRUE; + if (*s1++ == c) + return ! strcmp(s1, s2); + return FALSE; +} diff --git a/src/cmd/adb/findfn.c b/src/cmd/adb/findfn.c new file mode 100644 index 0000000..cd27c4b --- /dev/null +++ b/src/cmd/adb/findfn.c @@ -0,0 +1,44 @@ +#include "defs.h" + +int +findroutine(cframe) + long cframe; +{ + register int narg, inst; + int lastpc, back2; + char v; + + v = FALSE; + localok = FALSE; + lastpc = callpc; + callpc = get(cframe+2, DSP); + back2 = get(leng(callpc - 2), ISP); + inst = get(leng(callpc-4), ISP); + if (inst == 04737) { /* jsr pc, *$... */ + narg = 1; + } else if ((inst & ~077) == 04700) { /* jsr pc, ... */ + narg = 0; + v = (inst != 04767); + } else if ((back2 & ~077) == 04700) { + narg = 0; + v = TRUE; + } else { + errflg = NOCFN; + return 0; + } + if (findsym((v ? lastpc : ((inst==04767 ? callpc : 0) + back2)), ISYM) == -1 && !v) + symbol = NULL; + else + localok = TRUE; + inst = get(leng(callpc), ISP); + if (inst == 062706) { /* add $n, sp */ + narg += get(leng(callpc + 2), ISP) / 2; + return narg; + } + if (inst == 05726 || inst == 010026) /* tst (sp)+ or mov r0, (sp)+ */ + return narg + 1; + if (inst == 022626) { /* cmp (sp)+, (sp)+ */ + return narg + 2; + } + return narg; +} diff --git a/src/cmd/adb/format.c b/src/cmd/adb/format.c new file mode 100644 index 0000000..e4710ae --- /dev/null +++ b/src/cmd/adb/format.c @@ -0,0 +1,315 @@ +#include "defs.h" +#include +#ifdef CROSS +# include +#else +# include +#endif + +void +scanform(icount, ifp, itype, ptype) + long icount; + char *ifp; +{ + char *fp; + char modifier; + int fcount, init=1; + long savdot; + + while (icount) { + fp = ifp; + if (init == 0 && findsym(shorten(dot), ptype) == 0 && maxoff) { + print("\n%s:%16t", cache_sym(symbol)); + } + savdot = dot; + init = 0; + + /* now loop over format */ + while (*fp && errflg == 0) { + modifier = *fp; + if (isdigit(modifier)) { + fcount = 0; + modifier = *fp++; + while (isdigit(modifier)) { + fcount *= 10; + fcount += modifier-'0'; + } + fp--; + } else { + fcount = 1; + } + + if (*fp == 0) + break; + fp = exform(fcount, fp, itype, ptype); + } + dotinc = dot - savdot; + dot = savdot; + + if (errflg) { + if (icount < 0) { + errflg = 0; + break; + } else { + error(errflg); + } + } + if (--icount) { + dot = inkdot(dotinc); + } + if (mkfault) { + error((char *)0); + } + } +} + +static void +printesc(c) +{ + c &= STRIP; + if (c < SP || c > '~' || c == '@') { + print("@%c", (c == '@') ? '@' : c ^ 0140); + } else { + printc(c); + } +} + +char * +exform(fcount, ifp, itype, ptype) + int fcount; + char *ifp; + int itype, ptype; +{ + /* execute single format item `fcount' times + * sets `dotinc' and moves `dot' + * returns address of next format item + */ + u_int w; + long savdot, wx; + char *fp = 0; + int c, modifier; + struct { + long sa; + int sb, sc; + } fw; + + while (fcount > 0) { + fp = ifp; + c = *fp; + //int longpr = (c >= 'A' && c <= 'Z') || (c == 'f'); + if (itype == NSP || *fp == 'a') { + wx = dot; + w = dot; + } else { + w = get(dot, itype); + //if (longpr) + // wx = itol(w, get(inkdot(2), itype)); + //else + wx = w; + } + if (c == 'F') { + fw.sb = get(inkdot(4), itype); + fw.sc = get(inkdot(6), itype); + } + if (errflg) + return(fp); + if (mkfault) + error((char *)0); + var[0] = wx; + modifier = *fp++; + dotinc = 4; + + if (! (printptr - printbuf) && modifier != 'a') + print("%16m"); + + switch(modifier) { + + case SP: case TB: + break; + + case 't': case 'T': + print("%T", fcount); + return fp; + + case 'r': case 'R': + print("%M", fcount); + return fp; + + case 'a': + psymoff(dot, ptype, ":%16t"); + dotinc = 0; + break; + + case 'p': + psymoff(var[0], ptype, "%16t"); + break; + + case 'u': + print("%-8u", w); + break; + + case 'U': + print("%-16U", wx); + break; + + case 'c': case 'C': + if (modifier == 'C') { + printesc(w & LOBYTE); + } else { + printc(w & LOBYTE); + } + dotinc = 1; + break; + + case 'b': case 'B': + print("%-4x", w & LOBYTE); + dotinc = 1; + break; + + case 's': case 'S': + savdot = dot; + dotinc = 1; + while ((c = get(dot, itype) & LOBYTE) && errflg == 0) { + dot = inkdot(1); + if (modifier == 'S') { + printesc(c); + } else { + printc(c); + } + endline(); + } + dotinc = dot - savdot + 1; + dot = savdot; + break; + + case 'x': + print("%-8x", w); + break; + + case 'X': + print("%-16X", wx); + break; + + case 'Y': + print("%-24Y", wx); + break; + + case 'q': + print("%-8q", w); + break; + + case 'Q': + print("%-16Q", wx); + break; + + case 'o': + case 'w': + print("%-8o", w); + break; + + case 'O': + case 'W': + print("%-16O", wx); + break; + + case 'i': + printins(itype, dot, w); printc(EOR); + break; + + case 'd': + print("%-8d", w); + break; + + case 'D': + print("%-16D", wx); + break; + + case 'f': + *(double *)&fw = 0.0; + fw.sa = wx; + print("%-16.9f", *(double *)&fw); + dotinc = 4; + break; + + case 'F': + fw.sa = wx; + print("%-32.18F", *(double *)&fw); + dotinc = 8; + break; + + case 'n': case 'N': + printc('\n'); + dotinc = 0; + break; + + case '"': + dotinc = 0; + while (*fp != '"' && *fp) { + printc(*fp++); + } + if (*fp) { + fp++; + } + break; + + case '^': + dot = inkdot(-dotinc * fcount); + return fp; + + case '+': + dot = inkdot(fcount); + return fp; + + case '-': + dot = inkdot(-fcount); + return fp; + + default: + error(BADMOD); + } + if (itype != NSP) { + dot = inkdot(dotinc); + } + fcount--; + endline(); + } + return fp; +} + +void +unox() +{ + int rc, status, unixpid; + char *argp = lp; + + while (lastc != EOR) { + rdc(); + } + if ((unixpid = fork()) == 0) { + signal(SIGINT, sigint); + signal(SIGQUIT, sigqit); + *lp = 0; + execl("/bin/sh", "sh", "-c", argp, (char*)0); + exit(16); + } else if (unixpid == -1) { + error(NOFORK); + } else { + signal(SIGINT, SIG_IGN); + while ((rc = wait(&status)) != unixpid && rc != -1); + signal(SIGINT, sigint); + printc('!'); + lp--; + } +} + +long +inkdot(incr) +{ + long newdot; + + newdot = dot + incr; + if ((dot ^ newdot) >> 24) { + error(ADWRAP); + } + return newdot; +} diff --git a/src/cmd/adb/input.c b/src/cmd/adb/input.c new file mode 100644 index 0000000..300cdbd --- /dev/null +++ b/src/cmd/adb/input.c @@ -0,0 +1,86 @@ +/* + * Input routines + */ +#include "defs.h" + +int lastc = EOR; + +static char line[LINSIZ]; + +int +eol(c) +{ + return (c == EOR || c == ';'); +} + +int +rdc() +{ + do { + readchar(); + } while (lastc == SP || lastc == TB ); + return lastc; +} + +int +readchar() +{ + if (eof) { + lastc = '\0'; + } else { + if (lp == 0) { + lp = line; + do { + eof = (read(infile, lp, 1) == 0); + if (mkfault) + error((char *)0); + } while (eof == 0 && *lp++ != EOR); + *lp = 0; + lp = line; + } + lastc = *lp; + if (lastc) + lp++; + } + return lastc; +} + +int +nextchar() +{ + if (eol(rdc())) { + lp--; + return 0; + } + return lastc; +} + +int +quotchar() +{ + if (readchar() == '\\') + return readchar(); + if (lastc == '\'') + return 0; + return lastc; +} + +void +getformat(deformat) + char *deformat; +{ + register char *fptr; + register int quote; + + fptr = deformat; + quote = FALSE; + while ((quote ? readchar()!=EOR : !eol(readchar()))) { + if ((*fptr++ = lastc) == '"') { + quote = ~quote; + } + } + lp--; + if (fptr != deformat) { + *fptr++ = '\0'; + } +} diff --git a/src/cmd/adb/main.c b/src/cmd/adb/main.c new file mode 100644 index 0000000..96fda2a --- /dev/null +++ b/src/cmd/adb/main.c @@ -0,0 +1,167 @@ +#include "defs.h" +#include + +char *Ipath = "/share/adb"; + +static int exitflg; + +long +roundn(a, b) + long a, b; +{ + long w; + + w = ((a + b - 1) / b) * b; + return w; +} + +/* + * error handling + */ +void +chkerr() +{ + if (errflg || mkfault) + error(errflg); +} + +void +error(msg) + const char *msg; +{ + errflg = msg; + iclose(0, 1); + oclose(); + longjmp(erradb, 1); +} + +void +fault(a) +{ + signal(a, fault); + lseek(infile, 0L, 2); + mkfault++; +} + +/* + * set up files and initial address mappings + */ +int +main(argc, argv) + register char **argv; + int argc; +{ + short mynamelen; /* length of program name */ + + maxfile = 1L << 24; + if (isatty(0)) + myname = *argv; + else + myname = "adb"; + mynamelen = strlen(myname); + +#ifdef TIOCGETP + ioctl(0, TIOCGETP, &adbtty); + ioctl(0, TIOCGETP, &usrtty); +#else + tcgetattr(0, &adbtty); + tcgetattr(0, &usrtty); +#endif + while (argc > 1) { + if (strcmp("-w", argv[1]) == 0) { + wtflag = O_RDWR; + argc--; + argv++; + continue; + } + if (strcmp("-k", argv[1]) == 0) { + kernel++; + argc--; + argv++; + continue; + } + if (strcmp("-I", argv[1]) == 0) { + Ipath = argv[2]; + argc -= 2; + argv += 2; + continue; + } + break; + } + + if (argc > 1) { + symfil = argv[1]; + } + if (argc > 2) { + corfil = argv[2]; + } + argcount = argc; + setsym(); + setcor(); + + /* set up variables for user */ + maxoff = MAXOFF; + maxpos = MAXPOS; + var[VARB] = datbas; + var[VARD] = datsiz; + var[VARE] = entrypt; + var[VARM] = magic; + var[VARS] = stksiz; + var[VART] = txtsiz; + + sigint = signal(SIGINT, SIG_IGN); + if (sigint != SIG_IGN) { + sigint = fault; + signal(SIGINT, fault); + } + sigqit = signal(SIGQUIT, SIG_IGN); + siginterrupt(SIGINT, 1); + siginterrupt(SIGQUIT, 1); + setjmp(erradb); + if (executing) { + delbp(); + } + executing = FALSE; + + for (;;) { + flushbuf(); + if (errflg) { + print("%s\n", errflg); + exitflg = (errflg != 0); + errflg = 0; + } + if (mkfault) { + mkfault = 0; + printc(EOR); + print("%s\n", myname); + } + if (myname && ! infile) { + write(1, myname, mynamelen); + write(1, "> ", 2); + } + lp = 0; + rdc(); + lp--; + if (eof) { + if (infile) { + iclose(-1, 0); + eof = 0; + longjmp(erradb, 1); + } + done(); + } else { + exitflg = 0; + } + command(0, lastcom); + if (lp && lastc != EOR) { + error(NOEOR); + } + } +} + +void +done() +{ + endpcs(); + exit(exitflg); +} diff --git a/src/cmd/adb/message.c b/src/cmd/adb/message.c new file mode 100644 index 0000000..beac312 --- /dev/null +++ b/src/cmd/adb/message.c @@ -0,0 +1,30 @@ +#include "defs.h" + +const char BADMOD[] = "bad modifier"; +const char BADCOM[] = "bad command"; +const char BADSYM[] = "symbol not found"; +const char BADLOC[] = "automatic variable not found"; +const char NOCFN[] = "c routine not found"; +const char NOMATCH[] = "cannot locate value"; +const char NOBKPT[] = "no breakpoint set"; +const char BADKET[] = "unexpected ')'"; +const char NOADR[] = "address expected"; +const char NOPCS[] = "no process"; +const char BADVAR[] = "bad variable"; +const char BADTXT[] = "text address not found"; +const char BADDAT[] = "data address not found"; +const char ODDADR[] = "odd address"; +const char EXBKPT[] = "too many breakpoints"; +const char A68BAD[] = "bad a68 frame"; +const char A68LNK[] = "bad a68 link"; +const char ADWRAP[] = "address wrap around"; +const char BADEQ[] = "unexpected `='"; +const char BADWAIT[] = "wait error: process disappeared!"; +const char ENDPCS[] = "process terminated"; +const char NOFORK[] = "try again"; +const char BADSYN[] = "syntax error"; +const char NOEOR[] = "newline expected"; +const char SZBKPT[] = "bkpt: command too long"; +const char LONGFIL[] = "filename too long"; +const char NOTOPEN[] = "cannot open"; +const char TOODEEP[] = "$<< nesting too deep"; diff --git a/src/cmd/adb/opset.c b/src/cmd/adb/opset.c new file mode 100644 index 0000000..486ce8a --- /dev/null +++ b/src/cmd/adb/opset.c @@ -0,0 +1,439 @@ +/* + * Instruction printing + */ +#include "defs.h" + +/* + * Flags of instruction formats. + */ +#define FRD1 (1 << 0) /* rd, ... */ +#define FRD2 (1 << 1) /* .., rd, ... */ +#define FRT1 (1 << 2) /* rt, ... */ +#define FRT2 (1 << 3) /* .., rt, ... */ +#define FRT3 (1 << 4) /* .., .., rt */ +#define FRS1 (1 << 5) /* rs, ... */ +#define FRS2 (1 << 6) /* .., rs, ... */ +#define FRS3 (1 << 7) /* .., .., rs */ +#define FRSB (1 << 8) /* ... (rs) */ +#define FCODE (1 << 9) /* immediate shifted <<6 */ +#define FOFF16 (1 << 11) /* 16-bit relocatable offset */ +#define FHIGH16 (1 << 12) /* high 16-bit relocatable offset */ +#define FOFF18 (1 << 13) /* 18-bit PC-relative relocatable offset shifted >>2 */ +#define FAOFF18 (1 << 14) /* 18-bit PC-relative relocatable offset shifted >>2 */ +#define FAOFF28 (1 << 15) /* 28-bit absolute relocatable offset shifted >>2 */ +#define FSA (1 << 16) /* 5-bit shift amount */ +#define FSEL (1 << 17) /* optional 3-bit COP0 register select */ +#define FSIZE (1 << 18) /* bit field size */ +#define FMSB (1 << 19) /* bit field msb */ +#define FRTD (1 << 20) /* set rt to rd number */ +#define FCODE16 (1 << 21) /* immediate shifted <<16 */ +#define FSYS (1 << 22) /* syscall */ + +struct optable { + unsigned opcode; + unsigned mask; + const char *name; + unsigned type; +}; + +static const struct optable optable [] = { + { 0x34000000, 0xffe00000, "li", FRT1 | FOFF16 }, // ori + { 0x24000000, 0xffe00000, "li", FRT1 | FOFF16 }, // addiu + { 0x00000021, 0xfc1f07ff, "move", FRD1 | FRS2 }, // addu + { 0x00000040, 0xffffffff, "ssnop", 0 }, // nop + { 0x00000020, 0xfc0007ff, "add", FRD1 | FRS2 | FRT3 }, + { 0x20000000, 0xfc000000, "addi", FRT1 | FRS2 | FOFF16 }, + { 0x24000000, 0xfc000000, "addiu", FRT1 | FRS2 | FOFF16 }, + { 0x00000021, 0xfc0007ff, "addu", FRD1 | FRS2 | FRT3 }, + { 0x00000024, 0xfc0007ff, "and", FRD1 | FRS2 | FRT3 }, + { 0x30000000, 0xfc000000, "andi", FRT1 | FRS2 | FOFF16 }, + { 0x10000000, 0xffff0000, "b", FAOFF18 }, + { 0x04110000, 0xffff0000, "bal", FAOFF18 }, + { 0x10000000, 0xfc000000, "beq", FRS1 | FRT2 | FOFF18 }, + { 0x50000000, 0xfc000000, "beql", FRS1 | FRT2 | FOFF18 }, + { 0x04010000, 0xfc1f0000, "bgez", FRS1 | FOFF18 }, + { 0x04110000, 0xfc1f0000, "bgezal", FRS1 | FOFF18 }, + { 0x04130000, 0xfc1f0000, "bgezall", FRS1 | FOFF18 }, + { 0x04030000, 0xfc1f0000, "bgezl", FRS1 | FOFF18 }, + { 0x1c000000, 0xfc1f0000, "bgtz", FRS1 | FOFF18 }, + { 0x5c000000, 0xfc1f0000, "bgtzl", FRS1 | FOFF18 }, + { 0x18000000, 0xfc1f0000, "blez", FRS1 | FOFF18 }, + { 0x58000000, 0xfc1f0000, "blezl", FRS1 | FOFF18 }, + { 0x04000000, 0xfc1f0000, "bltz", FRS1 | FOFF18 }, + { 0x04100000, 0xfc1f0000, "bltzal", FRS1 | FOFF18 }, + { 0x04120000, 0xfc1f0000, "bltzall", FRS1 | FOFF18 }, + { 0x04020000, 0xfc1f0000, "bltzl", FRS1 | FOFF18 }, + { 0x14000000, 0xfc000000, "bne", FRS1 | FRT2 | FOFF18 }, + { 0x54000000, 0xfc000000, "bnel", FRS1 | FRT2 | FOFF18 }, + { 0x0000000d, 0xfc00ffff, "break", FCODE16 }, + { 0x70000021, 0xfc0007ff, "clo", FRD1 | FRS2 | FRTD }, + { 0x70000020, 0xfc0007ff, "clz", FRD1 | FRS2 | FRTD }, + { 0x4200001f, 0xffffffff, "deret", 0 }, + { 0x41606000, 0xffe0ffff, "di", FRT1 }, + { 0x0000001a, 0xfc00ffff, "div", FRS1 | FRT2 }, + { 0x0000001b, 0xfc00ffff, "divu", FRS1 | FRT2 }, + { 0x000000c0, 0xffffffff, "ehb", 0 }, + { 0x41606020, 0xffe0ffff, "ei", FRT1 }, + { 0x42000018, 0xffffffff, "eret", 0 }, + { 0x7c000000, 0xfc00003f, "ext", FRT1 | FRS2 | FSA | FSIZE }, + { 0x7c000004, 0xfc00003f, "ins", FRT1 | FRS2 | FSA | FMSB }, + { 0x08000000, 0xfc000000, "j", FAOFF28 }, + { 0x0c000000, 0xfc000000, "jal", FAOFF28 }, + { 0x00000009, 0xfc1f07ff, "jalr", FRD1 | FRS2 }, + { 0x00000409, 0xfc1f07ff, "jalr.hb", FRD1 | FRS2 }, + { 0x00000008, 0xfc1fffff, "jr", FRS1 }, + { 0x00000408, 0xfc1fffff, "jr.hb", FRS1 }, + { 0x80000000, 0xfc000000, "lb", FRT1 | FOFF16 | FRSB }, + { 0x90000000, 0xfc000000, "lbu", FRT1 | FOFF16 | FRSB }, + { 0x84000000, 0xfc000000, "lh", FRT1 | FOFF16 | FRSB }, + { 0x94000000, 0xfc000000, "lhu", FRT1 | FOFF16 | FRSB }, + { 0xc0000000, 0xfc000000, "ll", FRT1 | FOFF16 | FRSB }, + { 0x3c000000, 0xffe00000, "lui", FRT1 | FHIGH16 }, + { 0x8c000000, 0xfc000000, "lw", FRT1 | FOFF16 | FRSB }, + { 0x88000000, 0xfc000000, "lwl", FRT1 | FOFF16 | FRSB }, + { 0x98000000, 0xfc000000, "lwr", FRT1 | FOFF16 | FRSB }, + { 0x70000000, 0xfc00ffff, "madd", FRS1 | FRT2 }, + { 0x70000001, 0xfc00ffff, "maddu", FRS1 | FRT2 }, + { 0x40000000, 0xffe007f8, "mfc0", FRT1 | FRD2 | FSEL }, + { 0x00000010, 0xffff07ff, "mfhi", FRD1 }, + { 0x00000012, 0xffff07ff, "mflo", FRD1 }, + { 0x0000000b, 0xfc0007ff, "movn", FRD1 | FRS2 | FRT3 }, + { 0x0000000a, 0xfc0007ff, "movz", FRD1 | FRS2 | FRT3 }, + { 0x70000004, 0xfc00ffff, "msub", FRS1 | FRT2 }, + { 0x70000005, 0xfc00ffff, "msubu", FRS1 | FRT2 }, + { 0x40800000, 0xffe007f8, "mtc0", FRT1 | FRD2 | FSEL }, + { 0x00000011, 0xfc1fffff, "mthi", FRS1 }, + { 0x00000013, 0xfc1fffff, "mtlo", FRS1 }, + { 0x70000002, 0xfc0007ff, "mul", FRD1 | FRS2 | FRT3 }, + { 0x00000018, 0xfc00ffff, "mult", FRS1 | FRT2 }, + { 0x00000019, 0xfc00ffff, "multu", FRS1 | FRT2 }, + { 0x00000000, 0xffffffff, "nop", 0 }, + { 0x00000027, 0xfc0007ff, "nor", FRD1 | FRS2 | FRT3 }, + { 0x00000025, 0xfc0007ff, "or", FRD1 | FRS2 | FRT3 }, + { 0x34000000, 0xfc000000, "ori", FRT1 | FRS2 | FOFF16 }, + { 0x7c00003b, 0xffe007ff, "rdhwr", FRT1 | FRD2 }, + { 0x41400000, 0xffe007ff, "rdpgpr", FRD1 | FRT2 }, + { 0x00200002, 0xffe0003f, "ror", FRD1 | FRT2 | FSA }, + { 0x00000046, 0xfc0007ff, "rorv", FRD1 | FRT2 | FRS3 }, + { 0xa0000000, 0xfc000000, "sb", FRT1 | FOFF16 | FRSB }, + { 0xe0000000, 0xfc000000, "sc", FRT1 | FOFF16 | FRSB }, + { 0x7000003f, 0xfc00003f, "sdbbp", FCODE }, + { 0x7c000420, 0xffe007ff, "seb", FRD1 | FRT2 }, + { 0x7c000620, 0xffe007ff, "seh", FRD1 | FRT2 }, + { 0xa4000000, 0xfc000000, "sh", FRT1 | FOFF16 | FRSB }, + { 0x00000000, 0xffe0003f, "sll", FRD1 | FRT2 | FSA }, + { 0x00000004, 0xfc0007ff, "sllv", FRD1 | FRT2 | FRS3 }, + { 0x0000002a, 0xfc0007ff, "slt", FRD1 | FRS2 | FRT3 }, + { 0x28000000, 0xfc000000, "slti", FRT1 | FRS2 | FOFF16 }, + { 0x2c000000, 0xfc000000, "sltiu", FRT1 | FRS2 | FOFF16 }, + { 0x0000002b, 0xfc0007ff, "sltu", FRD1 | FRS2 | FRT3 }, + { 0x00000003, 0xffe0003f, "sra", FRD1 | FRT2 | FSA }, + { 0x00000007, 0xfc0007ff, "srav", FRD1 | FRT2 | FRS3 }, + { 0x00000002, 0xffe0003f, "srl", FRD1 | FRT2 | FSA }, + { 0x00000006, 0xfc0007ff, "srlv", FRD1 | FRT2 | FRS3 }, + { 0x00000022, 0xfc0007ff, "sub", FRD1 | FRS2 | FRT3 }, + { 0x00000023, 0xfc0007ff, "subu", FRD1 | FRS2 | FRT3 }, + { 0xac000000, 0xfc000000, "sw", FRT1 | FOFF16 | FRSB }, + { 0xa8000000, 0xfc000000, "swl", FRT1 | FOFF16 | FRSB }, + { 0xb8000000, 0xfc000000, "swr", FRT1 | FOFF16 | FRSB }, + { 0x0000000f, 0xfffff83f, "sync", FCODE }, + { 0x0000000c, 0xfc00003f, "syscall", FSYS }, + { 0x00000034, 0xfc00ffff, "teq", FRS1 | FRT2 }, + { 0x040c0000, 0xfc1f0000, "teqi", FRS1 | FOFF16 }, + { 0x00000030, 0xfc00ffff, "tge", FRS1 | FRT2 }, + { 0x04080000, 0xfc1f0000, "tgei", FRS1 | FOFF16 }, + { 0x04090000, 0xfc1f0000, "tgeiu", FRS1 | FOFF16 }, + { 0x00000031, 0xfc00ffff, "tgeu", FRS1 | FRT2 }, + { 0x00000032, 0xfc00ffff, "tlt", FRS1 | FRT2 }, + { 0x040a0000, 0xfc1f0000, "tlti", FRS1 | FOFF16 }, + { 0x040b0000, 0xfc1f0000, "tltiu", FRS1 | FOFF16 }, + { 0x00000033, 0xfc00ffff, "tltu", FRS1 | FRT2 }, + { 0x00000036, 0xfc00ffff, "tne", FRS1 | FRT2 }, + { 0x040e0000, 0xfc1f0000, "tnei", FRS1 | FOFF16 }, + { 0x42000020, 0xfe00003f, "wait", FCODE }, + { 0x41c00000, 0xffe007ff, "wrpgpr", FRD1 | FRT2 }, + { 0x7c0000a0, 0xffe007ff, "wsbh", FRD1 | FRT2 }, + { 0x00000026, 0xfc0007ff, "xor", FRD1 | FRS2 | FRT3 }, + { 0x38000000, 0xfc000000, "xori", FRT1 | FRS2 | FOFF16 }, + { 0, 0, 0, 0 }, +}; + +static const char *systab[] = { + "indir", /* 0 - indir*/ + "exit", + "fork", + "read", + "write", + "open", + "close", + "wait4", + NULL, /* 8 - unused */ + "link", + "unlink", /* 10 */ + "execv", + "chdir", + "fchdir", + "mknod", + "chmod", + "chown", + "chflags", + "fchflags", + "lseek", + "getpid", /* 20 */ + "mount", + "umount", + "__sysctl", + "getuid", + "geteuid", /* 25 */ + "ptrace", + "getppid", + NULL, /* 28 - unused */ + NULL, /* 29 - unused */ + NULL, /* 30 - unused */ + "sigaction", /* 31 - sigaction */ + "sigprocmask", /* 32 - sigprocmask */ + "access", + "sigpending", /* 34 - sigpending */ + "sigaltstack", /* 35 - sigaltstack */ + "sync", + "kill", + "stat", + "_getlogin", /* 39 - _getlogin */ + "lstat", + "dup", + "pipe", + "setlogin", /* 43 - unused */ + "profil", + "setuid", /* 45 - setuid */ + "seteuid", /* 46 - seteuid */ + "getgid", + "getegid", + "setgid", /* 49 - setgid */ + "setegid", /* 50 - setegid */ + "acct", + "phys", + "lock", + "ioctl", + "reboot", + NULL, /* 56 - unused */ + "symlink", + "readlink", + "execve", + "umask", + "chroot", + "fstat", + NULL, /* 63 - unused */ + NULL, /* 64 - unused */ + "pselect", /* 65 - pselect */ + "vfork", + NULL, /* 67 - unused */ + NULL, /* 68 - unused */ + "sbrk", + NULL, /* 70 - unused */ + NULL, /* 71 - unused */ + NULL, /* 72 - unused */ + NULL, /* 73 - unused */ + NULL, /* 74 - unused */ + NULL, /* 75 - unused */ + "vhangup", + NULL, /* 77 - unused */ + NULL, /* 78 - unused */ + "getgroups", + "setgroups", + "getpgrp", + "setpgrp", + "setitimer", + NULL, /* 84 - unused */ + NULL, /* 85 - unused */ + "getitimer", + NULL, /* 87 - unused */ + NULL, /* 88 - unused */ + "getdtablesize", + "dup2", + NULL, /* 91 - unused */ + "fcntl", + "select", + NULL, /* 94 - unused */ + "fsync", + "setpriority", + "socket", + "connect", + "accept", + "getpriority", + "send", + "recv", /* 102 - recv */ + "sigreturn", + "bind", + "setsockopt", + "listen", + "sigsuspend", /* 107 - sigsuspend */ + NULL, /* 108 - unused */ + NULL, /* 109 - unused */ + NULL, /* 110 - unused */ + NULL, /* 111 - unused */ + "old sigstack", /* 112 - sigstack COMPAT-43 for zork */ + "recvmsg", + "sendmsg", + NULL, /* 115 - unused */ + "gettimeofday", + "getrusage", + "getsockopt", + NULL, /* 119 - unused */ + "readv", + "writev", + "settimeofday", + "fchown", + "fchmod", + "recvfrom", + NULL, /* 126 - unused */ + NULL, /* 127 - unused */ + "rename", + "truncate", + "ftruncate", + "flock", + NULL, /* 132 - unused */ + "sendto", + "shutdown", + "socketpair", + "mkdir", + "rmdir", + "utimes", + NULL, /* 139 - unused */ + "adjtime", + "getpeername", + NULL, /* 142 - unused */ + NULL, /* 143 - unused */ + "getrlimit", + "setrlimit", + "killpg", + NULL, /* 147 - unused */ + "setquota", + "quota", + "getsockname", + /* + * 2.11BSD special calls + */ + NULL, /* 151 - unused */ + "nostk", + "fetchi", + "ucall", + "fperr", +}; + +#define NUMSYSCALLS (sizeof (systab) / sizeof (char *)) + +static const char *const regname[32] = { + "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3", + "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", + "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", + "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra" +}; + +/* + * Print the mips instruction at address MEMADDR in debugged memory. + * Returns length of the instruction, in bytes, which is + * always INSNLEN. + */ +void +printins (space, memaddr, word) + unsigned memaddr, word; +{ + const struct optable *op; + + for (op=optable; op->mask; op++) { + if ((word & op->mask) == op->opcode) + break; + } + if (! op->mask) { + print (".word%8t%x", word); + return; + } + print ("%s%8t", op->name); + + /* + * First register. + */ + if (op->type & FRD1) /* rd, ... */ + print ("%s", regname[word >> 11 & 31]); + if (op->type & FRT1) /* rt, ... */ + print ("%s", regname[word >> 16 & 31]); + if (op->type & FRS1) /* rs, ... */ + print ("%s", regname[word >> 21 & 31]); + + /* + * Second register. + */ + if (op->type & FRD2) /* .., rd, ... */ + print (", %s", regname[word >> 11 & 31]); + if (op->type & FRT2) /* .., rt, ... */ + print (", %s", regname[word >> 16 & 31]); + if (op->type & FRS2) /* .., rs, ... */ + print (", %s", regname[word >> 21 & 31]); + + /* + * Third register. + */ + if (op->type & FRT3) /* .., .., rt */ + print (", %s", regname[word >> 16 & 31]); + if (op->type & FRS3) /* .., .., rs */ + print (", %s", regname[word >> 21 & 31]); + + /* + * Immediate argument. + */ + if (op->type & FSEL) { + /* optional COP0 register select */ + if (word & 7) + print (", %x", word & 7); + + } else if (op->type & FSYS) { + /* Syscall */ + unsigned code = (word & ~op->mask) >> 6; + + if (code < NUMSYSCALLS && systab[code]) + print("%s", systab[code]); + else + print("%d", code); + + } else if (op->type & FCODE) { + /* Non-relocatable offset */ + print ("%x", (word & ~op->mask) >> 6); + + } else if (op->type & FCODE16) { + print ("%x", (word & ~op->mask) >> 16); + + } else if (op->type & FSA) { + print (", %x", word >> 6 & 0x1f); + + } else if (op->type & FOFF16) { + /* Relocatable offset */ + print (", %x", word & 0xffff); + + } else if (op->type & FOFF18) { + unsigned addr = ((signed short) (word & 0xffff) << 2) + memaddr + 4; + print (", "); + psymoff(addr, ISYM, ""); + + } else if (op->type & FHIGH16) { + print (", %x", word & 0xffff); + + } else if (op->type & FAOFF18) { + unsigned addr = ((signed short) (word & 0xffff) << 2) + memaddr + 4; + psymoff(addr, ISYM, ""); + + } else if (op->type & FAOFF28) { + unsigned addr = (word & 0x3ffffff) << 2; + psymoff(addr, ISYM, ""); + } + + /* + * Last argument. + */ + if (op->type & FRSB) /* ... (rs) */ + print ("(%s)", regname[word >> 21 & 31]); + if (op->type & FSIZE) /* bit field size */ + print (", %x", ((word >> 11) & 0x1f) + 1); + if (op->type & FMSB) /* bit field msb */ + print (", %x", ((word >> 11) & 0x1f) + 1 - + ((word >> 6) & 0x1f)); +} diff --git a/src/cmd/adb/output.c b/src/cmd/adb/output.c new file mode 100644 index 0000000..2796ca7 --- /dev/null +++ b/src/cmd/adb/output.c @@ -0,0 +1,393 @@ +#include "defs.h" +#include + +int outfile = 1; +char *printptr = printbuf; + +static char *digitptr; + +void +printc(c) + int c; +{ + char d; + char *q; + int posn, tabs, p; + + if (mkfault) + return; + + *printptr = c; + if (c == EOR) { + tabs = 0; + posn = 0; + q = printbuf; + for (p=0; p 0) { + *q++ = TB; + tabs--; + } + while (posn > 0) { + *q++ = SP; + posn--; + } + *q++ = d; + } + } + *q++ = EOR; + write(outfile, printbuf, q - printbuf); + printptr = printbuf; + + } else if (c == TB) { + *printptr++ = SP; + while ((printptr - printbuf) & 7) { + *printptr++ = SP; + } + } else if (c) { + printptr++; + } + if (printptr >= &printbuf[MAXLIN-9]) { + write(outfile, printbuf, printptr - printbuf); + printptr = printbuf; + } +} + +void +flushbuf() +{ + if (printptr != printbuf) { + printc(EOR); + } +} + +static int +convert(cp) + register char **cp; +{ + register char c; + int n = 0; + + while ((c = *(*cp)++) >= '0' && c <= '9') { + n = n*10 + c - '0'; + } + (*cp)--; + return n; +} + +static void +printnum(n, fmat, base) + register int n; +{ + register char k; + register int *dptr; + int digs[15]; + + dptr = digs; + if (n < 0 && fmat == 'd') { + n = -n; + *digitptr++ = '-'; + } + while (n) { + *dptr++ = ((u_int) n) % base; + n = ((u_int) n ) / base; + } + if (dptr == digs) { + *dptr++ = 0; + } + while (dptr != digs) { + k = *--dptr; + *digitptr++ = k + ((k <= 9) ? '0' : 'a'-10); + } +} + +static void +printoct(o, s) + long o; + int s; +{ + int i; + long po = o; + char digs[12]; + + if (s) { + if (po < 0) { + po = -po; + *digitptr++ = '-'; + + } else if (s > 0) + *digitptr++='+'; + } + for (i=0; i<=11; i++) { + digs[i] = po & 7; + po >>= 3; + } + digs[10] &= 03; + digs[11] = 0; + for (i=11; i>=0; i--) { + if (digs[i]) + break; + } + for (i++; i>=0; i--) { + *digitptr++ = digs[i] + '0'; + } +} + +static void +printlong(lx, fmat, base) + long lx; + int fmat, base; +{ + int digs[20], *dptr; + char k; + unsigned long f, g; + + dptr = digs; + f = lx; + if (fmat == 'x') + *digitptr++ = '#'; + else if (fmat == 'D' && lx < 0) { + *digitptr++ = '-'; + f = -lx; + } + while (f) { + g = f / base; + *dptr++ = f - g * base; + f = g; + } + if (dptr == digs) { + *dptr++ = 0; + } + while (dptr != digs) { + k = *--dptr; + *digitptr++ = k + ((k <= 9) ? '0' : 'a'-10); + } +} + +static void +printdate(tvec) + long tvec; +{ + register int i; + register char *timeptr; + + timeptr = ctime(&tvec); + for (i=20; i<24; i++) + *digitptr++ = timeptr[i]; + for (i=3; i<19; i++) + *digitptr++ = timeptr[i]; +} + +void +print(char *fmat, ...) +{ + va_list args, prev_args; + char *fptr, *s; + int width, prec; + char c, adj; + int decpt, n; + char digits[64]; + union { + int int32; + float float32; + } word; + + va_start(args, fmat); + fptr = fmat; + while ((c = *fptr++)) { + if (c != '%') { + printc(c); + continue; + } + + if (*fptr == '-') { + adj = 'l'; + fptr++; + } else { + adj = 'r'; + } + width = convert(&fptr); + if (*fptr == '*') { + width = va_arg(args, int); + fptr++; + } + if (*fptr == '.') { + fptr++; + prec = convert(&fptr); + if (*fptr == '*') { + prec = va_arg(args, int); + fptr++; + } + } else + prec = -1; + + digitptr = digits; + prev_args = args; + word.int32 = va_arg(args, int); + s = 0; + switch (c = *fptr++) { + case 'd': + case 'u': + printnum(word.int32, c, 10); + break; + case 'o': + printoct(word.int32, 0); + break; + case 'q': + case 'x': + printlong(word.int32, 'x', 16); + break; + case 'Y': + printdate(word.int32); + break; + case 'D': + case 'U': + printlong(word.int32, c, 10); + break; + case 'O': + printoct(word.int32, 0); + break; + case 'Q': + case 'X': + printlong(word.int32, 'x', 16); + break; + case 'c': + printc(word.int32); + break; + case 's': + s = (char*) word.int32; + break; + case 'f': + case 'F': + s = ecvt(word.float32, prec, &decpt, &n); + *digitptr++ = n ? '-' : '+'; + *digitptr++ = (decpt <= 0) ? '0' : *s++; + if (decpt > 0) { + decpt--; + } + *digitptr++ = '.'; + while (*s && prec-- ) { + *digitptr++ = *s++; + } + while (*--digitptr=='0'); + digitptr += (digitptr - digits >= 3) ? 1 : 2; + if (decpt) { + *digitptr++ = 'e'; + printnum(decpt, 'd', 10); + } + s = 0; + prec = -1; + break; + case 'm': + args = prev_args; + break; + case 'M': + width = word.int32; + break; + case 'T': + case 't': + if (c == 'T') { + width = word.int32; + } else { + args = prev_args; + } + if (width) { + width -= (printptr - printbuf) % width; + } + break; + default: + printc(c); + args = prev_args; + } + + if (s == 0) { + *digitptr = 0; + s = digits; + } + n = strlen(s); + n = (prec < n && prec >= 0) ? prec : n; + width -= n; + if (adj == 'r') { + while (width-- > 0) + printc(SP); + } + while (n--) + printc(*s++); + while (width-- > 0) + printc(SP); + digitptr = digits; + } + va_end(args); +} + +#define MAXIFD 5 +struct { + int fd; + long r9; +} istack[MAXIFD]; + +int ifiledepth; + +void +iclose(stack, err) +{ + if (err) { + if (infile) { + close(infile); + infile = 0; + } + while (--ifiledepth >= 0) { + if (istack[ifiledepth].fd) { + close(istack[ifiledepth].fd); + infile = 0; + } + } + ifiledepth = 0; + } else if (stack == 0) { + if (infile) { + close(infile); + infile = 0; + } + } else if (stack > 0) { + if (ifiledepth >= MAXIFD) { + error(TOODEEP); + } + istack[ifiledepth].fd = infile; + istack[ifiledepth].r9 = var[9]; + ifiledepth++; + infile = 0; + } else { + if (infile) { + close(infile); + infile = 0; + } + if (ifiledepth > 0) { + infile = istack[--ifiledepth].fd; + var[9] = istack[ifiledepth].r9; + } + } +} + +void +oclose() +{ + if (outfile != 1) { + flushbuf(); + close(outfile); + outfile = 1; + } +} + +void +endline() +{ + if ((printptr - printbuf) >= maxpos) + printc('\n'); +} diff --git a/src/cmd/adb/pcs.c b/src/cmd/adb/pcs.c new file mode 100644 index 0000000..f0b3bab --- /dev/null +++ b/src/cmd/adb/pcs.c @@ -0,0 +1,108 @@ +/* + * Sub process control + */ +#include "defs.h" + +void +subpcs(modif) +{ + register int check; + int execsig, runmode; + register BKPTR bkptr; + char *comptr; + + execsig = 0; + loopcnt = cntval; + + switch (modif) { + + case 'd': case 'D': /* delete breakpoint */ + bkptr = scanbkpt(shorten(dot)); + if (! bkptr) + error(NOBKPT); + bkptr->flag = 0; + if (pid) + del1bp(bkptr); + return; + + case 'b': case 'B': /* set breakpoint */ + bkptr = scanbkpt(shorten(dot)); + if (bkptr) { + bkptr->flag = 0; + if (pid) + del1bp(bkptr); + } + for (bkptr=bkpthead; bkptr; bkptr=bkptr->nxtbkpt) { + if (bkptr->flag == 0) + break; + } + if (bkptr == 0) { + bkptr = (BKPTR) malloc(sizeof *bkptr); + if (! bkptr) { + error(SZBKPT); + } else { + bkptr->nxtbkpt = bkpthead; + bkpthead=bkptr; + } + } + bkptr->loc = dot; + bkptr->initcnt = bkptr->count = cntval; + bkptr->flag = BKPTSET; + check = MAXCOM-1; + comptr = bkptr->comm; + rdc(); + lp--; + do { + *comptr++ = readchar(); + } while (check-- && lastc != EOR); + *comptr = 0; + lp--; + if (! check) + error(EXBKPT); + if (pid) + set1bp(bkptr); + return; + + case 'k': case 'K': /* exit */ + if (! pid) + error(NOPCS); + print("%d: killed", pid); + endpcs(); + return; + + case 'r': case 'R': /* run program */ + endpcs(); + setup(); + setbp(); + runmode = PT_CONTINUE; + break; + + case 's': case 'S': /* single step */ + runmode = PT_STEP; + if (pid) { + execsig = getsig(signo); + } else { + setup(); + loopcnt--; + } + break; + + case 'c': case 'C': case 0: /* continue with optional signal */ + if (pid == 0) + error(NOPCS); + runmode = PT_CONTINUE; + execsig = getsig(signo); + break; + + default: + error(BADMOD); + return; + } + + if (loopcnt > 0 && runpcs(runmode, execsig)) { + print("breakpoint%16t"); + } else { + print("stopped at%16t"); + } + printpc(); +} diff --git a/src/cmd/adb/print.c b/src/cmd/adb/print.c new file mode 100644 index 0000000..5dc91f4 --- /dev/null +++ b/src/cmd/adb/print.c @@ -0,0 +1,426 @@ +#include "defs.h" +#include + +const REGLIST reglist [FRAME_WORDS] = { + { "at", FRAME_R1 }, /* 0 */ + { "v0", FRAME_R2 }, /* 1 */ + { "v1", FRAME_R3 }, /* 2 */ + { "a0", FRAME_R4 }, /* 3 */ + { "a1", FRAME_R5 }, /* 4 */ + { "a2", FRAME_R6 }, /* 5 */ + { "a3", FRAME_R7 }, /* 6 */ + { "t0", FRAME_R8 }, /* 7 */ + { "t1", FRAME_R9 }, /* 8 */ + { "t2", FRAME_R10 }, /* 9 */ + { "t3", FRAME_R11 }, /* 10 */ + { "t4", FRAME_R12 }, /* 11 */ + { "t5", FRAME_R13 }, /* 12 */ + { "t6", FRAME_R14 }, /* 13 */ + { "t7", FRAME_R15 }, /* 14 */ + { "s0", FRAME_R16 }, /* 15 */ + { "s1", FRAME_R17 }, /* 16 */ + { "s2", FRAME_R18 }, /* 17 */ + { "s3", FRAME_R19 }, /* 18 */ + { "s4", FRAME_R20 }, /* 19 */ + { "s5", FRAME_R21 }, /* 20 */ + { "s6", FRAME_R22 }, /* 21 */ + { "s7", FRAME_R23 }, /* 22 */ + { "t8", FRAME_R24 }, /* 23 */ + { "t9", FRAME_R25 }, /* 24 */ + { "gp", FRAME_GP }, /* 25 */ + { "sp", FRAME_SP }, /* 26 */ + { "fp", FRAME_FP }, /* 27 */ + { "ra", FRAME_RA }, /* 28 */ + { "lo", FRAME_LO }, /* 29 */ + { "hi", FRAME_HI }, /* 30 */ + { "status", FRAME_STATUS}, /* 31 */ + { "pc", FRAME_PC }, /* 32 */ +}; + +static const REGLIST kregs[] = { // TODO + { "r1", FRAME_R1 }, /* 0 */ + { "r2", FRAME_R2 }, /* 1 */ + { "r3", FRAME_R3 }, /* 2 */ + { "r4", FRAME_R4 }, /* 3 */ + { "r5", FRAME_R5 }, /* 4 */ + { "r6", FRAME_R6 }, /* 5 */ + { "sp", FRAME_SP }, /* 26 */ +}; + +static void +printmap(s, amap) + char *s; + MAP *amap; +{ + int file; + + file = amap->ufd; + print("%s%12t`%s'\n", s, file < 0 ? "-" : + file == fcor ? corfil : symfil); + print("b1 = %-12Q", amap->b1); + print("e1 = %-12Q", amap->e1); + print("f1 = %-12Q", amap->f1); + print("\n"); + print("b2 = %-12Q", amap->b2); + print("e2 = %-12Q", amap->e2); + print("f2 = %-12Q", amap->f2); + printc(EOR); +} + +static void +printregs() +{ + register const REGLIST *p; + int v; + + if (kernel) { + // TODO + for (p=kregs; p<&kregs[7]; p++) { + v = corhdr[p->roffs]; + print("%s%8t%x%8t", p->rname, v); + valpr(v, DSYM); + printc(EOR); + } + } else { + print (" t0 = %9x s0 = %9x t8 = %9x lo = %9x\n", + uframe [FRAME_R8], uframe [FRAME_R16], + uframe [FRAME_R24], uframe [FRAME_LO]); + print ("at = %9x t1 = %9x s1 = %9x t9 = %9x hi = %9x\n", + uframe [FRAME_R1], uframe [FRAME_R9], uframe [FRAME_R17], + uframe [FRAME_R25], uframe [FRAME_HI]); + print ("v0 = %9x t2 = %9x s2 = %9x status = %9x\n", + uframe [FRAME_R2], uframe [FRAME_R10], + uframe [FRAME_R18], uframe [FRAME_STATUS]); + print ("v1 = %9x t3 = %9x s3 = %9x pc = %9x\n", + uframe [FRAME_R3], uframe [FRAME_R11], + uframe [FRAME_R19], uframe [FRAME_PC]); + print ("a0 = %9x t4 = %9x s4 = %9x gp = %9x\n", + uframe [FRAME_R4], uframe [FRAME_R12], + uframe [FRAME_R20], uframe [FRAME_GP]); + print ("a1 = %9x t5 = %9x s5 = %9x sp = %9x\n", + uframe [FRAME_R5], uframe [FRAME_R13], + uframe [FRAME_R21], uframe [FRAME_SP]); + print ("a2 = %9x t6 = %9x s6 = %9x fp = %9x\n", + uframe [FRAME_R6], uframe [FRAME_R14], + uframe [FRAME_R22], uframe [FRAME_FP]); + print ("a3 = %9x t7 = %9x s7 = %9x ra = %9x\n", + uframe [FRAME_R7], uframe [FRAME_R15], + uframe [FRAME_R23], uframe [FRAME_RA]); + printpc(); + } +} + +/* + * general printing routines ($) + */ +void +printtrace(modif) +{ + int narg, i, stat, name, limit; + u_int dynam; + register BKPTR bkptr; + char hi, lo; + int word, stack = 0; + char *comptr; + long argp, frame, link; + register struct SYMbol *symp; + + if (cntflg == 0) { + cntval = -1; + } + + switch (modif) { + + case '<': + if (cntval == 0) { + while (readchar() != EOR) + ; + lp--; + break; + } + if (rdc() == '<') { + stack = 1; + } else { + stack = 0; + lp--; + } + /* fall thru ... */ + case '>': { + char file[64]; + char Ifile[128]; + int index; + + index = 0; + if (rdc() != EOR) { + do { + file[index++] = lastc; + if (index >= 63) + error(LONGFIL); + } while (readchar() != EOR); + file[index] = 0; + if (modif == '<') { + if (Ipath) { + strcpy(Ifile, Ipath); + strcat(Ifile, "/"); + strcat(Ifile, file); + } + if (strcmp(file, "-") != 0) { + iclose(stack, 0); + infile = open(file, 0); + if (infile < 0) { + infile = open(Ifile, 0); + } + } else { + lseek(infile, 0L, 0); + } + if (infile < 0) { + infile = 0; + error(NOTOPEN); + } else { + if (cntflg) { + var[9] = cntval; + } else { + var[9] = 1; + } + } + } else { + oclose(); + outfile = open(file, O_CREAT | O_WRONLY, 0644); + lseek(outfile, 0L, 2); + } + } else { + if (modif == '<') { + iclose(-1, 0); + } else { + oclose(); + } + } + lp--; + } + break; + + case 'o': + octal = TRUE; + break; + + case 'd': + octal = FALSE; + break; + + case 'q': case 'Q': case '%': + done(); + + case 'w': case 'W': + maxpos = adrflg ? adrval : MAXPOS; + break; + + case 's': case 'S': + maxoff = adrflg ? adrval : MAXOFF; + break; + + case 'v': + print("variables\n"); + for (i=0; i<=35; i++) { + if (var[i]) { + printc(i + (i <= 9 ? '0' : 'a'-10)); + print(" = %Q\n", var[i]); + } + } + break; + + case 'm': case 'M': + printmap("? map", &txtmap); + printmap("/ map", &datmap); + break; + + case 0: case '?': + if (pid) { + print("pcs id = %d\n", pid); + } else { + print("no process\n"); + } + sigprint(); + flushbuf(); + case 'r': case 'R': + printregs(); + return; + + case 'f': case 'F': + // No FPU registers + return; + + case 'c': case 'C': + // TODO + frame = (adrflg ? adrval : + (kernel ? corhdr[FRAME_R5] : uframe[FRAME_R5])) & ALIGNED; + lastframe = 0; + callpc = (adrflg ? get(frame + 2, DSP) : + (kernel ? (-2) : uframe[FRAME_PC])); + while (cntval--) { + chkerr(); + print("%Q: ", frame); /* Add frame address info */ + narg = findroutine(frame); + print("%s(", cache_sym(symbol)); + argp = frame+4; + if (--narg >= 0) { + print("%o", get(argp, DSP)); + } + while (--narg >= 0) { + argp += 2; + print(",%o", get(argp, DSP)); + } + /* Add return-PC info. Force printout of + * symbol+offset (never just a number! ) by using + * max possible offset. Overlay has already been set + * properly by findfn. + */ + print(") from "); + { + int savmaxoff = maxoff; + + maxoff = ((unsigned)-1)>>1; + psymoff((long)callpc, ISYM, ""); + maxoff = savmaxoff; + } + printc('\n'); + + if (modif == 'C') { + while (localsym(frame)) { + word = get(localval, DSP); + print("%8t%s:%10t", cache_sym(symbol)); + if (errflg) { + print("?\n"); + errflg = 0; + } else { + print("%o\n", word); + } + } + } + lastframe = frame; + frame = get(frame, DSP) & ALIGNED; + if (kernel ? ((u_int)frame > ((u_int)0140000 + USIZE)) : + (frame == 0)) + break; + } + break; + + case 'e': case 'E': /* print externals */ + symset(); + while ((symp = symget())) { + chkerr(); + if (symp->type == (N_EXT | N_DATA) || + symp->type == (N_EXT | N_BSS)) { + print("%s:%12t%o\n", no_cache_sym(symp), + get(leng(symp->value), DSP)); + } + } + break; + + case 'a': case 'A': + frame = adrflg ? adrval : uframe[FRAME_R4]; + + while (cntval--) { + chkerr(); + stat = get(frame, DSP); + dynam = get(frame+2, DSP); + link = get(frame+4, DSP); + if (modif == 'A') { + print("%8O:%8t%-8o,%-8o,%-8o", frame, stat, dynam, link); + } + if (stat == 1) + break; + if (errflg) + error(A68BAD); + + if (get(link-4, ISP) != 04767) { + if (get(link-2, ISP) != 04775) + error(A68LNK); + print(" ? "); + } else { + print("%8t"); + name = shorten(link) + get(link-2, ISP); + valpr(name, ISYM); + name = get(leng(name -2), ISP); + print("%8t\""); + limit = 8; + do { + word = get(leng(name), DSP); + name += 2; + lo = word & LOBYTE; + hi = (word >> 8) & LOBYTE; + printc(lo); + printc(hi); + } while (lo && hi && limit--); + printc('"'); + } + limit = 4; + i = 6; + print("%24targs:%8t"); + while (limit--) { + print("%8t%o", get(frame + i, DSP)); + i += 2; + } + printc(EOR); + + frame = dynam; + } + errflg = 0; + flushbuf(); + break; + /* set default c frame */ + case 'b': case 'B': /* print breakpoints */ + print("breakpoints\ncount%8tbkpt%24tcommand\n"); + for (bkptr=bkpthead; bkptr; bkptr=bkptr->nxtbkpt) { + if (bkptr->flag) { + print("%-8.8d", bkptr->count); + psymoff(leng(bkptr->loc), ISYM, "%24t"); + comptr = bkptr->comm; + while (*comptr) + printc(*comptr++); + } + } + break; + + default: + error(BADMOD); + } +} + +int +getreg(regnam) +{ + register const REGLIST *p; + register char *regptr; + char regnxt; + + if (kernel) /* not supported */ + return NOREG; + regnxt = readchar(); + for (p=reglist; p<®list[NREG]; p++) { + regptr = p->rname; + if ((regnam == *regptr++) && (regnxt == *regptr)) + return p->roffs; + } + lp--; + return NOREG; +} + +void +printpc() +{ + dot = uframe[FRAME_PC]; + psymoff(dot, ISYM, ":%16t"); + printins(ISP, dot, chkget(dot, ISP)); + printc(EOR); +} + +void +sigprint() +{ +#ifndef CROSS + if (signo >= 0 && signo < NSIG) + print("%s", sys_siglist[signo]); + else +#endif + print("unknown signal %d", signo); +} diff --git a/src/cmd/adb/runpcs.c b/src/cmd/adb/runpcs.c new file mode 100644 index 0000000..3cb8a5f --- /dev/null +++ b/src/cmd/adb/runpcs.c @@ -0,0 +1,296 @@ +/* + * Service routines for sub process control + */ +#include "defs.h" +#include +#include + +static int userpc = 1; + +int +getsig(sig) +{ + return expr(0) ? shorten(expv) : sig; +} + +static void +bpwait() +{ + register int w; + int stat; + + signal(SIGINT, SIG_IGN); + while ((w = wait(&stat)) != pid && w != -1) + ; + signal(SIGINT, sigint); + +#ifdef TIOCGETP + ioctl(0, TIOCGETP, &usrtty); + ioctl(0, TIOCSETP, &adbtty); +#else + tcgetattr(0, &usrtty); + tcsetattr(0, TCSANOW, &adbtty); +#endif + if (w == -1) { + pid = 0; + errflg = BADWAIT; + + } else if ((stat & 0177) != 0177) { + signo = stat & 0177; + if (signo) { + sigprint(); + } + if (stat & 0200) { + print(" - core dumped"); + close(fcor); + setcor(); + } + pid = 0; + errflg = ENDPCS; + + } else { + signo = stat>>8; + if (signo != SIGTRAP) { + sigprint(); + } else { + signo = 0; + } + flushbuf(); + } +} + +/* + * get REG values from pcs + */ +static void +readregs() +{ + register u_int i; + + for (i=0; icount); +#endif + bkptloc = bkptr->loc; + ptrace(PT_WRITE_I, pid, (void*) bkptloc, bkptr->ins); + +#ifdef TIOCGETP + ioctl(0, TIOCSETP, &usrtty); +#else + tcsetattr(0, TCSANOW, &usrtty); +#endif + ptrace(PT_STEP, pid, (void*) bkptloc, 0); + bpwait(); + chkerr(); + ptrace(PT_WRITE_I, pid, (void*) bkptloc, BPT); + bkptr->flag = BKPTSET; +} + +int +runpcs(runmode, execsig) +{ + int rc = 0; + register BKPTR bkpt; + + if (adrflg) + userpc = shorten(dot); + print("%s: running\n", symfil); + + while (loopcnt-- > 0) { +#ifdef DEBUG + print("\ncontinue %d %d\n", userpc, execsig); +#endif +#ifdef TIOCGETP + ioctl(0, TIOCSETP, &usrtty); +#else + tcsetattr(0, TCSANOW, &usrtty); +#endif + ptrace (runmode, pid, (void*) userpc, execsig); + bpwait(); + chkerr(); + readregs(); + + /* look for bkpt */ + if (signo == 0 && (bkpt = scanbkpt(uframe[FRAME_PC] - 2))) { + /* stopped at bkpt */ + userpc = uframe[FRAME_PC] = bkpt->loc; + if (bkpt->flag == BKPTEXEC || + ((bkpt->flag = BKPTEXEC, command(bkpt->comm, ':')) && + --bkpt->count)) + { + execbkpt(bkpt); + execsig = 0; + loopcnt++; + userpc = 1; + } else { + bkpt->count = bkpt->initcnt; + rc = 1; + } + } else { + rc = 0; + execsig = signo; + userpc = 1; + } + } + return(rc); +} + +void +endpcs() +{ + register BKPTR bkptr; + + if (pid) { + ptrace(PT_KILL, pid, 0, 0); + pid = 0; + userpc = 1; + for (bkptr=bkpthead; bkptr; bkptr=bkptr->nxtbkpt) { + if (bkptr->flag) { + bkptr->flag = BKPTSET; + } + } + } +} + +static void +doexec() +{ + char *argl[MAXARG]; + char args[LINSIZ]; + char *p, **ap, *filnam; + + ap = argl; + p = args; + *ap++ = symfil; + do { + if (rdc() == EOR) + break; + /* + * If we find an argument beginning with a `<' or a `>', open + * the following file name for input and output, respectively + * and back the argument collocation pointer, p, back up. + */ + *ap = p; + while (lastc != EOR && lastc != SP && lastc != TB) { + *p++ = lastc; + readchar(); + } + *p++ = 0; + filnam = *ap + 1; + if (**ap == '<') { + close(0); + if (open(filnam, 0) < 0) { + print("%s: cannot open\n", filnam); + exit(0); + } + p = *ap; + } else if (**ap == '>') { + close(1); + if (open(filnam, O_CREAT | O_WRONLY, 0666) < 0) { + print("%s: cannot create\n", filnam); + exit(0); + } + p = *ap; + } else { + ap++; + } + } while (lastc != EOR); + *ap++ = 0; + execv(symfil, argl); +} + +void +setup() +{ + close(fsym); + fsym = -1; + pid = fork(); + if (pid == 0) { + ptrace(PT_TRACE_ME, 0, 0, 0); + signal(SIGINT, sigint); + signal(SIGQUIT, sigqit); + doexec(); + exit(0); + } else if (pid == -1) { + error(NOFORK); + } else { + bpwait(); + readregs(); + lp[0] = EOR; + lp[1] = 0; + fsym = open(symfil, wtflag); + if (errflg) { + print("%s: cannot execute\n", symfil); + endpcs(); + error((char *)0); + } + } +} + +BKPTR +scanbkpt(adr) +{ + register BKPTR bkptr; + + for (bkptr=bkpthead; bkptr; bkptr=bkptr->nxtbkpt) { + if (bkptr->flag && bkptr->loc == adr) + break; + } + return bkptr; +} + +void +delbp() +{ + register BKPTR bkptr; + + for (bkptr=bkpthead; bkptr; bkptr=bkptr->nxtbkpt) { + if (bkptr->flag) + del1bp(bkptr); + } +} + +void +del1bp(bkptr) + BKPTR bkptr; +{ + ptrace(PT_WRITE_I, pid, (void*) bkptr->loc, bkptr->ins); +} + +void +setbp() +{ + register BKPTR bkptr; + + for (bkptr=bkpthead; bkptr; bkptr=bkptr->nxtbkpt) { + if (bkptr->flag) + set1bp(bkptr); + } +} + +void +set1bp(bkptr) + BKPTR bkptr; +{ + register int a; + + a = bkptr->loc; + bkptr->ins = ptrace(PT_READ_I, pid, (void*) a, 0); + ptrace(PT_WRITE_I, pid, (void*) a, BPT); + if (errno) { + print("cannot set breakpoint: "); + psymoff(leng(bkptr->loc), ISYM, "\n"); + } +} diff --git a/src/cmd/adb/setup.c b/src/cmd/adb/setup.c new file mode 100644 index 0000000..dc1b9db --- /dev/null +++ b/src/cmd/adb/setup.c @@ -0,0 +1,127 @@ +#include "defs.h" +#include +#include + +u_int *uframe = UFRAME; +char *symfil = "a.out"; +char *corfil = "core"; + +static long bss; + +static int +getfile(filnam, cnt) + char *filnam; + int cnt; +{ + register int f; + + if (strcmp("-", filnam) == 0) + return -1; + + f = open(filnam, wtflag); + if (f < 0 && argcount > cnt) { + if (wtflag) + f = open(filnam, O_CREAT | O_TRUNC | wtflag, 644); + if (f < 0) + print("cannot open `%s'\n", filnam); + } + return f; +} + +void +setsym() +{ + struct exec hdr; + + bzero(&txtmap, sizeof (txtmap)); + fsym = getfile(symfil, 1); + txtmap.ufd = fsym; + + if (read(fsym, &hdr, sizeof (hdr)) >= (int)sizeof (hdr)) { + magic = hdr.a_magic; + txtsiz = hdr.a_text; + datsiz = hdr.a_data; + bss = hdr.a_bss; + entrypt = hdr.a_entry; + + txtmap.f1 = N_TXTOFF(hdr); + symoff = N_SYMOFF(hdr); + + switch (magic) { + case OMAGIC: /* 0407 */ + txtmap.b1 = USER_DATA_START; + txtmap.e1 = USER_DATA_START + txtsiz + datsiz; + txtmap.b2 = txtmap.b1; + txtmap.e2 = txtmap.e1; + txtmap.f2 = txtmap.f1; + break; + default: + magic = 0; + txtsiz = 0; + datsiz = 0; + bss = 0; + entrypt = 0; + } + datbas = txtmap.b2; + symINI(&hdr); + } + if (magic == 0) { + txtmap.e1 = maxfile; + } +} + +void +setcor() +{ + fcor = getfile(corfil, 2); + datmap.ufd = fcor; + if (read(fcor, corhdr, sizeof corhdr) == sizeof corhdr) { + if (! kernel) { + txtsiz = ((struct user*)corhdr)->u_tsize; + datsiz = ((struct user*)corhdr)->u_dsize; + stksiz = ((struct user*)corhdr)->u_ssize; + datmap.f1 = USIZE; + datmap.b2 = USER_DATA_END - stksiz; + datmap.e2 = USER_DATA_END; + } else { + datsiz = datsiz + bss; + stksiz = (long) USIZE; + datmap.f1 = 0; + datmap.b2 = 0140000L; + datmap.e2 = 0140000L + USIZE; + } + switch (magic) { + case OMAGIC: /* 0407 */ + datmap.b1 = USER_DATA_START; + datmap.e1 = USER_DATA_START + txtsiz + datsiz; + if (kernel) { + datmap.f2 = (long)corhdr[KA6] * 0100L; + } else { + datmap.f2 = USIZE + txtsiz + datsiz; + } + break; + + default: + magic = 0; + datmap.b1 = 0; + datmap.e1 = maxfile; + datmap.f1 = 0; + datmap.b2 = 0; + datmap.e2 = 0; + datmap.f2 = 0; + } + datbas = datmap.b1; + if (! kernel && magic) { + /* User's frame pointer in user's address space. */ + register u_int frame; + frame = (long) ((struct user*)corhdr)->u_frame; + frame -= KERNEL_DATA_END - USIZE; + if (frame > 0 && frame < USIZE && ! (frame & 3)) { + /* User's frame pointer in adb address space. */ + uframe = (u_int*) &corhdr[frame >> 2]; + } + } + } else { + datmap.e1 = maxfile; + } +} diff --git a/src/cmd/adb/sym.c b/src/cmd/adb/sym.c new file mode 100644 index 0000000..650fd1a --- /dev/null +++ b/src/cmd/adb/sym.c @@ -0,0 +1,349 @@ +/* + * Symbol table and file handling service routines + */ +#include "defs.h" +#include +#ifdef CROSS +# include +#else +# include +#endif + +struct SYMcache { + char *name; + int used; + struct SYMbol *syment; +}; + +#ifndef NUM_SYMS_CACHE +#define NUM_SYMS_CACHE 50 +#endif + +static struct SYMcache symcache[NUM_SYMS_CACHE]; +static struct SYMcache *endcache = &symcache[NUM_SYMS_CACHE]; +static struct SYMbol *symtab; +static FILE *strfp; +static int symcnt; +static int symnum; + +u_int +findsym(svalue, type) + u_int svalue; + int type; +{ + long diff, value, symval; + register struct SYMbol *sp; + struct SYMbol *symsav = 0; + int i; + + value = svalue; + diff = 0xffffff; + + if (type != NSYM && symnum) { + for (i = 0, sp = symtab; diff && i < symnum; i++, sp++) { + if (SYMTYPE(sp->type) == type) { + symval = leng(sp->value); + if ((value - symval) < diff && value >= symval) { + diff = value - symval; + symsav = sp; + } + } + } + } + if (symsav) + symcnt = symsav - symtab; + symbol = symsav; + return shorten(diff); +} + +void +valpr(v, idsp) +{ + u_int d; + + d = findsym(v, idsp); + if (d < maxoff) { + print("%s", cache_sym(symbol)); + if (d) + print(OFFMODE, d); + } +} + +int +localsym(cframe) + long cframe; +{ + int symflg; + + while (symget() && localok && (symflg = (int)symbol->type) != N_FN && + *no_cache_sym(symbol) != '~') + { + if (symflg >= 2 && symflg <= 4) { + localval = symbol->value; + return TRUE; + } else if (symflg == 1) { + localval = leng(shorten(cframe) + symbol->value); + return TRUE; + } else if (symflg == 20 && lastframe) { + localval = leng(lastframe + 2 * symbol->value - 10); + return TRUE; + } + } + return FALSE; +} + +void +psymoff(v, type, s) + long v; + int type; + char *s; +{ + u_int w; + + w = findsym(shorten(v), type); + if (w >= maxoff) { + print(LPRMODE, v); + } else { + print("%s", cache_sym(symbol)); + if (w) { + print(OFFMODE, w); + } + } + print(s); +} + +/* + * sequential search through table + */ +void +symset() +{ + symcnt = -1; +} + +struct SYMbol * +symget() +{ + if (symcnt >= symnum || ! symnum) + return NULL; + symcnt++; + symbol = &symtab[symcnt]; + return symbol; +} + +static unsigned int +fgetword (f) + register FILE *f; +{ + register unsigned int h; + + h = getc (f); + h |= getc (f) << 8; + h |= getc (f) << 16; + h |= getc (f) << 24; + return h; +} + +/* + * Read a symbol table entry. + * Return a number of bytes read, or -1 on EOF. + * Format of symbol record: + * 1 byte: length of name in bytes + * 1 byte: type of symbol (N_UNDF, N_ABS, N_TEXT, etc) + * 4 bytes: value + * N bytes: name + */ +static int +fgetsym (fi, name, value, type) + register FILE *fi; + register char *name; + unsigned *value, *type; +{ + register int len; + unsigned nbytes; + + len = getc (fi); + if (len <= 0) + return -1; + *type = getc (fi); + *value = fgetword (fi); + nbytes = len + 6; + if (name) { + while (len-- > 0) + *name++ = getc (fi); + *name = '\0'; + } else + fseek (fi, len, SEEK_CUR); + return nbytes; +} + +/* + * This only _looks_ expensive ;-) The extra scan over the symbol + * table allows us to cut down the amount of memory needed. + * A late addition to the program excludes register symbols - the assembler + * generates *lots* of them and they're useless to us. + */ +void +symINI(ex) + struct exec *ex; +{ + register struct SYMbol *sp; + register FILE *fp; + int nused, globals_only = 0; + u_int value, type; + + fp = fopen(symfil, "r"); + strfp = fp; + if (! fp) + return; + fcntl(fileno(fp), F_SETFD, 1); + + /* First pass: count the number of symbols used. */ + fseek(fp, symoff, SEEK_SET); + nused = 0; + symnum = ex->a_syms; + while (symnum > 0) { + int nbytes = fgetsym(fp, 0, &value, &type); + if (nbytes <= 0) + break; + symnum -= nbytes; + nused++; + } + + symtab = (struct SYMbol *)malloc(nused * sizeof (struct SYMbol)); + if (! symtab) { + /* Second pass: count only globals. */ + fseek(fp, symoff, SEEK_SET); + globals_only = 1; + nused = 0; + symnum = ex->a_syms; + while (symnum > 0) { + int nbytes = fgetsym(fp, 0, &value, &type); + if (nbytes <= 0) + break; + symnum -= nbytes; + if (! (type & N_EXT)) + continue; + nused++; + } + symtab = (struct SYMbol *)malloc(nused * sizeof(struct SYMbol)); + if (! symtab) { + print("%s: no memory for %d symbols\n", myname, nused); + symnum = 0; + return; + } + } + + /* Third pass: read the symbols. */ + fseek(fp, symoff, SEEK_SET); + sp = symtab; + symnum = ex->a_syms; + while (symnum > 0) { + char name[256]; + int nbytes = fgetsym(fp, name, &value, &type); + if (nbytes <= 0) + break; + symnum -= nbytes; + if (globals_only && ! (type & N_EXT)) + continue; + sp->value = value; + sp->type = type; + sp->sname = strdup(name); + sp++; +//print("%s = %08x (%x)\n", name, value, type); + } + symnum = nused; +#if 1 + //printf("file '%s'\n", symfil); + printf("text=%u data=%u bss=%u symoff=%u syms=%u\n", + ex->a_text, ex->a_data, ex->a_bss, (unsigned) symoff, ex->a_syms); + printf("%d symbols loaded\n", nused); +#endif + if (globals_only) + print("%s: could only do global symbols\n", myname); + symset(); +} + +/* + * Look in the cache for a symbol in memory. If it is not found use + * the least recently used entry in the cache and update it with the + * symbol name. +*/ +char * +cache_sym(symp) + register struct SYMbol *symp; +{ + register struct SYMcache *sc = symcache; + struct SYMcache *current; + int lru; + + if (! symp) + return "?"; + for (current = NULL, lru = 30000 ; sc < endcache; sc++) { + if (sc->syment == symp) { + sc->used++; + if (sc->used >= 30000) + sc->used = 10000; + return sc->name; + } + if (sc->used < lru) { + lru = sc->used; + current = sc; + } + } + sc = current; + sc->used = 1; + sc->syment = symp; + sc->name = symp->sname; + return sc->name; +} + +/* + * We take a look in the cache but do not update the cache on a miss. + * This is done when scanning thru the symbol table (printing all externals + * for example) for large numbers of symbols which probably won't be + * used again any time soon. + */ +char * +no_cache_sym(symp) + register struct SYMbol *symp; +{ + register struct SYMcache *sc = symcache; + + if (! symp) + return "?"; + for ( ; sc < endcache; sc++) { + if (sc->syment == symp) { + sc->used++; + if (sc->used >= 30000) + sc->used = 10000; + return sc->name; + } + } + return symp->sname; +} + +/* + * Looks in the cache for a match by string value rather than string + * file offset. + */ +struct SYMbol * +cache_by_string(str) + char *str; +{ + register struct SYMcache *sc; + + for (sc = symcache; sc < endcache; sc++) { + if (! sc->name) + continue; + if (eqsym(sc->name, str, '_')) + break; + } + if (sc < endcache) { + sc->used++; + if (sc->used > 30000) + sc->used = 10000; + return sc->syment; + } + return 0; +} diff --git a/src/cmd/adc-demo/Makefile b/src/cmd/adc-demo/Makefile new file mode 100644 index 0000000..74a1794 --- /dev/null +++ b/src/cmd/adc-demo/Makefile @@ -0,0 +1,27 @@ +#========================================== +# Makefile: makefile for adc-demo +# Copyright 2012 Majenko Technolohies +# (matt@majenko.co.uk +# Last Modified: 29/01/2012 +#========================================== + +TOPSRC = $(shell cd ../../..; pwd) +include $(TOPSRC)/target.mk + +OBJS = adc-demo.o +SRCS = adc-demo.c +LIBS += -lcurses -ltermcap -lc + +all: adc-demo + +adc-demo: ${OBJS} + ${CC} ${LDFLAGS} -o adc-demo.elf ${OBJS} ${LIBS} + ${OBJDUMP} -S adc-demo.elf > adc-demo.dis + ${SIZE} adc-demo.elf + ${ELF2AOUT} adc-demo.elf $@ + +clean: + -rm -f adc-demo ${OBJS} adc-demo.elf adc-demo.dis + +install: all + install adc-demo $(DESTDIR)/bin/ diff --git a/src/cmd/adc-demo/adc-demo.c b/src/cmd/adc-demo/adc-demo.c new file mode 100644 index 0000000..812032f --- /dev/null +++ b/src/cmd/adc-demo/adc-demo.c @@ -0,0 +1,93 @@ +#include +#include +#include +#include +#include +#include + + +WINDOW *win; + +struct channel { + int fd; + int value; + char enabled; +}; + +int main(int argc, char **argv) +{ + struct channel channels[16]; + char temp[100]; + int i; + long flags; + int value; + const char opts[] = ":d:"; + int opt; + unsigned long delay = 100; + + for(i=0; i<16; i++) + channels[i].enabled = 1; + + while((opt = getopt(argc, argv, opts)) != -1) + { + switch(opt) + { + case 'd': + delay = atol(optarg); + break; + } + } + + for(i=0; i<16; i++) + { + if(channels[i].enabled == 1) + { + sprintf(temp,"/dev/adc%d",i); + channels[i].fd = open(temp,O_RDWR); + if(!channels[i].fd) + { + printf("Error: unable to open %s\n",temp); + exit(10); + } + fcntl(channels[i].fd,F_GETFD,&flags); + flags |= O_NONBLOCK; + fcntl(channels[i].fd,F_SETFD,&flags); + } + } + + win = initscr(); + + clear(); + while(1) + { + clear(); + for(i=0; i<16; i++) + { + if(channels[i].enabled == 1) + { + if(read(channels[i].fd,temp,20)) + { + if(sscanf(temp,"%d",&value)) + { + channels[i].value = value; + } + } + sprintf(temp,"adc%-2d %4d ",i,channels[i].value); + mvwaddstr(win,i,0,temp); + for(value=0; value>4; value++) + { + mvwaddch(win,i,value+11,'='); + } + // clrtoeol(); + } + } + refresh(); + usleep(delay * 1000); + } + + for(i=0; i<16; i++) + { + close(channels[i].fd); + } + endwin(); +} diff --git a/src/cmd/ar/Makefile b/src/cmd/ar/Makefile new file mode 100644 index 0000000..5809f30 --- /dev/null +++ b/src/cmd/ar/Makefile @@ -0,0 +1,34 @@ +TOPSRC = $(shell cd ../../..; pwd) +include $(TOPSRC)/target.mk +#include $(TOPSRC)/cross.mk + +CFLAGS += -Werror -Wall + +SRCS = append.c ar.c archive.c contents.c delete.c extract.c misc.c \ + move.c print.c replace.c strmode.c +OBJS = append.o ar.o archive.o contents.o delete.o extract.o \ + misc.o move.o print.o replace.o strmode.o +MAN = ar.1.0 ar.5.0 +MANSRC = ar.1 ar.5 + +all: ar $(MAN) + +ar: ${OBJS} + ${CC} ${LDFLAGS} -o ar.elf ${OBJS} ${LIBS} + ${OBJDUMP} -S ar.elf > ar.dis + ${SIZE} ar.elf + ${ELF2AOUT} ar.elf $@ && rm ar.elf + +ar.1.0: ar.1 + ${MANROFF} $< > $@ + +ar.5.0: ar.5.5 + ${MANROFF} $< > $@ + +clean: + rm -f *.o *.0 *.elf ${MAN} ar *.elf *.dis tags *~ + +install: all + install ar $(DESTDIR)/bin/ + cp ar.1.0 $(DESTDIR)/share/man/cat1/ar.0 + cp ar.5.0 $(DESTDIR)/share/man/cat5/ar.0 diff --git a/src/cmd/ar/append.c b/src/cmd/ar/append.c new file mode 100644 index 0000000..7f098ee --- /dev/null +++ b/src/cmd/ar/append.c @@ -0,0 +1,101 @@ +/*- + * Copyright (c) 1990 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. + */ +#ifdef CROSS +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +#else +# include +# include +# include +# include +# include +# include +# include +# include +# include +#endif +#include "archive.h" +#include "extern.h" + +extern char *archive; /* archive name */ +extern int errno; + +/* + * 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; +{ + register int fd, afd; + register char *file; + struct stat sb; + CF cf; + int eval; + + afd = open_archive(O_CREAT|O_RDWR); + if (lseek(afd, (off_t)0, L_XTND) == (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++) != 0;) { + if ((fd = open(file, O_RDONLY)) < 0) { + (void)fprintf(stderr, + "ar: %s: %s.\n", file, strerror(errno)); + 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/src/cmd/ar/ar.1 b/src/cmd/ar/ar.1 new file mode 100644 index 0000000..008fa19 --- /dev/null +++ b/src/cmd/ar/ar.1 @@ -0,0 +1,255 @@ +.\" Copyright (c) 1990 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 6.10 (Berkeley) 3/21/91 +.\" +.TH AR 1 "March 21, 1991" +.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 are 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 is written to the standard output before +the contents of the file, preceded by a single newline character, and +followed by two newline characters, enclosed in less-than (``<'') and +greater-than (``>'') 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/src/cmd/ar/ar.5.5 b/src/cmd/ar/ar.5.5 new file mode 100644 index 0000000..31c5c9e --- /dev/null +++ b/src/cmd/ar/ar.5.5 @@ -0,0 +1,143 @@ +.\" 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. +.\" +.\" @(#)ar.5.5 6.3 (Berkeley) 5/10/91 +.\" 6.3.1 (2.11BSD) 9/24/93 +.\" +.TH AR 5 "September 24, 1993" +.UC 2 +.SH NAME +ar \- archive (library) file format +.SH SYNOPSIS +#include +.SH DESCRIPTION +The archive command +.I ar +combines several files into one. +Archives are mainly used as libraries of object files intended to be +loaded using the link-editor +.IR ld (1). +.PP +A file created with +.I 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 +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 +.I st_mtime +field, i.e., +.B CUT +seconds since +the epoch. +The user and group id's are the file +.I st_uid +and +.I st_gid +fields. +The file mode is the file +.I st_mode +field. +The file size is the file +.I 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 +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 +.IR ar (1), +.IR stat (2) +.SH HISTORY +There have been at least four +.I 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 +.IR arcv (8). +.PP +The current archive format (without support for long character names and +names with embedded spaces) was introduced in 4.0BSD. +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 is under development. +.SH COMPATIBILITY +No archive format is currently specified by any standard. +AT&T System V UNIX +has historically distributed archives in a different format from +all of the above. diff --git a/src/cmd/ar/ar.c b/src/cmd/ar/ar.c new file mode 100644 index 0000000..74d05d3 --- /dev/null +++ b/src/cmd/ar/ar.c @@ -0,0 +1,255 @@ +/*- + * Copyright (c) 1990 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. + */ +#ifdef CROSS +# include +# include +# include +# include +# include +# include +#else +# include +# include +# include +# include +# include +# include +# include +#endif +#include +#include "archive.h" +#include "extern.h" + +extern int errno; + +CHDR chdr; +unsigned options; +char *archive, *envtmp, *posarg, *posname; + +static void +usage() +{ + (void)fprintf(stderr, "Usage:\n"); + (void)fprintf(stderr, " ar -d [-Tv] archive file ...\n"); + (void)fprintf(stderr, " ar -m [-Tv] archive file ...\n"); + (void)fprintf(stderr, " ar -m [-abiTv] position archive file ...\n"); + (void)fprintf(stderr, " ar -p [-Tv] archive [file ...]\n"); + (void)fprintf(stderr, " ar -q [-cTv] archive file ...\n"); + (void)fprintf(stderr, " ar -r [-cuTv] archive file ...\n"); + (void)fprintf(stderr, " ar -r [-abciuTv] position archive file ...\n"); + (void)fprintf(stderr, " ar -t [-Tv] archive [file ...]\n"); + (void)fprintf(stderr, " ar -x [-ouTv] archive [file ...]\n"); + (void)fprintf(stderr, "Commands:\n"); + (void)fprintf(stderr, " -d Delete file(s) from the archive\n"); + (void)fprintf(stderr, " -m Move file(s) in the archive\n"); + (void)fprintf(stderr, " -p Print file(s) found in the archive\n"); + (void)fprintf(stderr, " -q Quick append file(s) to the archive\n"); + (void)fprintf(stderr, " -r Replace existing or insert new file(s) into the archive\n"); + (void)fprintf(stderr, " -t Display contents of archive\n"); + (void)fprintf(stderr, " -x Extract file(s) from the archive\n"); + (void)fprintf(stderr, "Modifiers:\n"); + (void)fprintf(stderr, " -a Put file(s) after [member-name]\n"); + (void)fprintf(stderr, " -b, -i Put file(s) before [member-name]\n"); + (void)fprintf(stderr, " -c Do not warn if the library had to be created\n"); + (void)fprintf(stderr, " -u Only replace files that are newer than current archive contents\n"); + (void)fprintf(stderr, " -o Preserve original dates\n"); + (void)fprintf(stderr, " -T Make a thin archive\n"); + (void)fprintf(stderr, " -v Be verbose\n"); + exit(1); +} + +static void +badoptions(arg) + char *arg; +{ + (void)fprintf(stderr, + "ar: illegal option combination for %s.\n", arg); + usage(); +} + +/* + * 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; +{ + extern int optind; + int c; + char *p; + int (*fcall)() = 0; + + 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((unsigned)(strlen(argv[1]) + 2)))) { + (void)fprintf(stderr, "ar: %s.\n", strerror(errno)); + exit(1); + } + *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))) { + (void)fprintf(stderr, + "ar: one of options -dmpqrtx is required.\n"); + usage(); + } + /* Only one of -a and -bi allowed. */ + if (options & AR_A && options & AR_B) { + (void)fprintf(stderr, + "ar: only one of -a and -[bi] options allowed.\n"); + usage(); + } + /* -ab require a position argument. */ + if (options & (AR_A|AR_B)) { + if (!(posarg = *argv++)) { + (void)fprintf(stderr, + "ar: no position operand specified.\n"); + 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++)) { + (void)fprintf(stderr, "ar: no archive specified.\n"); + usage(); + } + + /* -dmqr require a list of archive elements. */ + if (options & (AR_D|AR_M|AR_Q|AR_R) && !*argv) { + (void)fprintf(stderr, "ar: no archive members specified.\n"); + usage(); + } + if (! fcall) + exit(1); + exit((*fcall)(argv)); +} diff --git a/src/cmd/ar/archive.c b/src/cmd/ar/archive.c new file mode 100644 index 0000000..6747fb5 --- /dev/null +++ b/src/cmd/ar/archive.c @@ -0,0 +1,346 @@ +/*- + * Copyright (c) 1990 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. + */ +#ifdef CROSS +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +#else +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +#endif +#include +#include "archive.h" +#include "extern.h" + +extern CHDR chdr; /* converted header */ +extern char *archive; /* archive name */ +extern int errno; + +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; + fd = open(archive, mode, 0666); + if (fd >= 0) { + /* POSIX.2 puts create message on stderr. */ + if (!(options & AR_C)) + (void)fprintf(stderr, + "ar: creating archive %s.\n", archive); + created = 1; + goto opened; + } + if (errno != EEXIST) + error(archive); + mode &= ~O_EXCL; + } + + fd = open(archive, mode, 0666); + if (fd < 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 & 3) == O_RDONLY || (mode & 3) == 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) { \ + bcopy(from, buf, 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; + register int len, nr; + register char *p; + char 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, (size_t)len); + if (nr != len) { + if (nr < 0) + error(archive); + badfmt(); + } + chdr.name[len] = 0; + chdr.size -= len; + } else { + chdr.lname = 0; + bcopy(hdr->ar_name, chdr.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; + +/* + * 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; + register int from, nr, nw, off, to; +#ifdef pdp11 + char buf[2*1024]; +#else + char buf[8*1024]; +#endif + + if (!(sz = size)) + return; + + from = cfp->rfd; + to = cfp->wfd; + while (sz) { + nr = read(from, buf, sz < sizeof(buf) ? sz : sizeof(buf)); + if (nr <= 0) + break; + sz -= nr; + for (off = 0; off < nr; nr -= off, off += nw) + if ((nw = write(to, buf + off, (size_t)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); +} + +/* + * put_arobj -- + * Write an archive member to a file. + */ +void +put_arobj(cfp, sb) + CF *cfp; + struct stat *sb; +{ + register int lname; + register 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); + (void)fprintf(stderr, + "ar: warning: %s truncated to %.*s\n", + name, OLDARMAXNAME, name); + (void)fflush(stderr); + } + (void)sprintf(hb, HDR3, name, sb->st_mtime, sb->st_uid, + sb->st_gid, sb->st_mode, (long) sb->st_size, ARFMAG); + lname = 0; + } else if (lname > sizeof(hdr->ar_name) || index(name, ' ')) + (void)sprintf(hb, HDR1, AR_EFMT1, lname, sb->st_mtime, + sb->st_uid, sb->st_gid, sb->st_mode, + (long) sb->st_size + lname, ARFMAG); + else { + lname = 0; + (void)sprintf(hb, HDR2, name, sb->st_mtime, sb->st_uid, + sb->st_gid, sb->st_mode, (long) 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, (size_t)lname) != lname) + error(cfp->wname); + already_written = lname; + } + copy_ar(cfp, size); + already_written = 0; +} + +/* + * 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.lname & 1); + if (lseek(fd, len, SEEK_CUR) == (off_t)-1) + error(archive); +} diff --git a/src/cmd/ar/archive.h b/src/cmd/ar/archive.h new file mode 100644 index 0000000..aaeffa7 --- /dev/null +++ b/src/cmd/ar/archive.h @@ -0,0 +1,128 @@ +/*- + * Copyright (c) 1991 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. + */ +#ifdef CROSS +# ifdef __linux__ +# undef O_CREAT +# define O_CREAT 00000100 +# undef O_EXCL +# define O_EXCL 00000200 +# undef O_NOCTTY +# define O_NOCTTY 00000400 +# undef O_TRUNC +# define O_TRUNC 00001000 +# endif +# ifndef MAXNAMLEN +# define MAXNAMLEN 63 +# endif +# ifndef MAXPATHLEN +# define MAXPATHLEN 256 +# endif +# ifndef _PATH_ARTMP +# define _PATH_ARTMP "/tmp/ar.XXXXXX" +# endif +#endif + +/* 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 unsigned 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 */ + unsigned 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 */ + unsigned short mode; /* permissions */ + char name[MAXNAMLEN + 1]; /* name */ +} CHDR; + +/* Header format strings. */ +#define HDR1 "%s%-13d%-12ld%-6u%-6u%-8o%-10ld%2s" +#define HDR2 "%-16.16s%-12ld%-6u%-6u%-8o%-10ld%2s" + +#define OLDARMAXNAME 15 +#define HDR3 "%-16.15s%-12ld%-6u%-6u%-8o%-10ld%2s" + +void close_archive(); +void skip_arobj(); +void copy_ar(); +int get_arobj(); +int open_archive(); +void put_arobj(); + +int delete (register char **argv); +int move (register char **argv); +int print (register char **argv); +int append (register char **argv); +int replace (register char **argv); +int contents (register char **argv); +int extract (register char **argv); diff --git a/src/cmd/ar/contents.c b/src/cmd/ar/contents.c new file mode 100644 index 0000000..836a7ec --- /dev/null +++ b/src/cmd/ar/contents.c @@ -0,0 +1,118 @@ +/*- + * Copyright (c) 1990 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. + */ +#ifdef CROSS +# include +# include +# include +# include +# include +# include +#else +# include +# include +# include +# include +# include +# include +# include +# include +#endif +#include +#include "archive.h" +#include "extern.h" + +extern CHDR chdr; /* converted header */ +extern char *archive; /* archive name */ + +/* + * contents -- + * Handles t[v] option - opens the archive and then reads headers, + * skipping member contents. + */ +int +contents(argv) + register char **argv; +{ + register 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 %8ld ", + buf + 1, chdr.uid, chdr.gid, (long) chdr.size); + tp = localtime(&chdr.date); +#ifdef bloat + (void)strftime(buf, sizeof(buf), "%b %e %H:%M %Y", tp); + (void)printf("%s %s\n", buf, file); +#else + { +/* + * Bloat avoidance alert! Doing the date this way saves dragging in not only + * strftime() but mktime() and ctime() for a savings of over 8kb. God, those + * leap seconds or whatever don't come cheap, the old (4.3BSD) timezone code + * was big enough but this new stuff (posix?) is horrid. +*/ + static char *months[] = {"Jan", "Feb", "Mar", "Apr", + "May", "Jun", "Jul", "Aug", + "Sep", "Oct", "Nov", "Dec"}; + + (void)printf("%s %02d %02d:%02d %4d %s\n", + months[tp->tm_mon], tp->tm_mday, tp->tm_hour, + tp->tm_min, 1900+tp->tm_year, file); + } +#endif + } 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/src/cmd/ar/delete.c b/src/cmd/ar/delete.c new file mode 100644 index 0000000..73d6f90 --- /dev/null +++ b/src/cmd/ar/delete.c @@ -0,0 +1,102 @@ +/*- + * Copyright (c) 1990 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. + */ +#ifdef CROSS +# include +# include +# include +# include +# include +# include +#else +# include +# include +# include +# include +# include +# include +# include +#endif +#include +#include "archive.h" +#include "extern.h" + +extern CHDR chdr; /* converted header */ +extern char *archive; /* archive name */ +extern char *tname; /* temporary file "name" */ + +/*- + * delete -- + * Deletes named members from the archive. + */ +int +delete(argv) + register 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/src/cmd/ar/extern.h b/src/cmd/ar/extern.h new file mode 100644 index 0000000..43bafdf --- /dev/null +++ b/src/cmd/ar/extern.h @@ -0,0 +1,41 @@ +/*- + * Copyright (c) 1991 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +void badfmt(); +void error(); +void orphans(); +int compare(); +int tmp(); +char *files(); +char *rname(); +void strmode(); diff --git a/src/cmd/ar/extract.c b/src/cmd/ar/extract.c new file mode 100644 index 0000000..1e429cb --- /dev/null +++ b/src/cmd/ar/extract.c @@ -0,0 +1,137 @@ +/*- + * Copyright (c) 1990 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. + */ +#ifdef CROSS +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +#else +# include +# include +# include +# include +# include +# include +# include +# include +#endif +#include +#include "archive.h" +#include "extern.h" + +extern int errno; +extern CHDR chdr; /* converted header */ +extern char *archive; /* archive name */ + +/* + * 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; +{ + register int afd, all, tfd; + struct timeval tv[2]; + struct stat sb; + CF cf; + char *file; + + 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, 0200)) < 0) { + (void)fprintf(stderr, "ar: %s: %s.\n", + file, strerror(errno)); + skip_arobj(afd); + 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)) { + (void)fprintf(stderr, "ar: %s: chmod: %s\n", + file, strerror(errno)); + } + if (options & AR_O) { + tv[0].tv_sec = tv[1].tv_sec = chdr.date; + if (utimes(file, tv)) { + (void)fprintf(stderr, "ar: %s: utimes: %s\n", + file, strerror(errno)); + } + } + (void)close(tfd); + if (!all && !*argv) + break; + } + close_archive(afd); + + if (*argv) { + orphans(argv); + return(1); + } + return(0); +} diff --git a/src/cmd/ar/misc.c b/src/cmd/ar/misc.c new file mode 100644 index 0000000..00c5ac0 --- /dev/null +++ b/src/cmd/ar/misc.c @@ -0,0 +1,164 @@ +/*- + * Copyright (c) 1990 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. + */ +#ifdef CROSS +# include +# include +# include +# include +# include +# include +# include +# include +# include +#else +# include +# include +# include +# include +# include +# include +# include +# include +# include +#endif +#include "archive.h" +#include "extern.h" + +extern CHDR chdr; /* converted header */ +extern char *archive; /* archive name */ +char *tname = "temporary file"; /* temporary file "name" */ + +int +tmp() +{ + extern char *envtmp; +#ifndef CROSS + sigset_t set, oset; +#endif + static int first; + static const char *artmp = _PATH_ARTMP; + int fd; + char path[MAXPATHLEN]; + + if (!first && !envtmp) { + envtmp = (char *)getenv("TMPDIR"); + first = 1; + } + + if (envtmp) { + strcpy(path, envtmp); + strcat(path, strrchr (artmp, '/')); + } else { + strcpy(path, artmp); + } +#ifndef CROSS + sigfillset(&set); + (void)sigprocmask(SIG_BLOCK, &set, &oset); +#endif + fd = mkstemp(path); + if (fd == -1) + error(tname); + (void)unlink(path); +#ifndef CROSS + (void)sigprocmask(SIG_SETMASK, &oset, NULL); +#endif + 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; +{ + register char **list; + char *p; + + for (list = argv; *list; ++list) + if (compare(*list)) { + p = *list; + while ((list[0] = list[1]) != 0) + list++; + return(p); + } + return(NULL); +} + +void +orphans(argv) + char **argv; +{ + for (; *argv; ++argv) + (void)fprintf(stderr, + "ar: %s: not found in archive.\n", *argv); +} + +char * +rname(path) + char *path; +{ + register char *ind; + + ind = strrchr(path, '/'); + return(ind ? 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() +{ + errno = EINVAL; + error(archive); +} + +void +error(name) + char *name; +{ + (void)fprintf(stderr, "ar: %s: %s\n", name, strerror(errno)); + exit(1); +} diff --git a/src/cmd/ar/move.c b/src/cmd/ar/move.c new file mode 100644 index 0000000..a44ef3b --- /dev/null +++ b/src/cmd/ar/move.c @@ -0,0 +1,147 @@ +/*- + * Copyright (c) 1990 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. + */ +#ifdef CROSS +# include +# include +# include +# include +# include +# include +#else +# include +# include +# include +# include +# include +# include +# include +#endif +#include +#include "archive.h" +#include "extern.h" + +extern CHDR chdr; /* converted header */ +extern char *archive; /* archive name */ +extern char *tname; /* temporary file "name" */ + +/* + * 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; +{ + extern char *posarg, *posname; /* positioning file names */ + 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) { + (void)fprintf(stderr, "ar: %s: archive member not found.\n", + 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/src/cmd/ar/print.c b/src/cmd/ar/print.c new file mode 100644 index 0000000..06d2d9c --- /dev/null +++ b/src/cmd/ar/print.c @@ -0,0 +1,93 @@ +/*- + * Copyright (c) 1990 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. + */ +#ifdef CROSS +# include +# include +# include +# include +# include +#else +# include +# include +# include +# include +#endif +#include "archive.h" +#include "extern.h" + +extern CHDR chdr; /* converted header */ +extern char *archive; /* archive name */ + +/* + * 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; + register int afd, all; + char *file; + + afd = open_archive(O_RDONLY); + + /* Read from an archive, write to stdout; pad on read. */ + SETCF(afd, archive, fileno(stdout), "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/src/cmd/ar/replace.c b/src/cmd/ar/replace.c new file mode 100644 index 0000000..51d4702 --- /dev/null +++ b/src/cmd/ar/replace.c @@ -0,0 +1,196 @@ +/*- + * Copyright (c) 1990 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. + */ +#ifdef CROSS +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +#else +# include +# include +# include +# include +# include +# include +# include +# include +# include +#endif +#include +#include "archive.h" +#include "extern.h" + +extern int errno; +extern CHDR chdr; /* converted header */ +extern char *archive; /* archive name */ +extern char *tname; /* temporary file "name" */ + +/* + * 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; +{ + extern char *posarg, *posname; /* positioning file name */ + register char *file; + register int afd, curfd, mods, sfd; + struct stat sb; + CF cf; + off_t size, tsize; + int err, exists, tfd1, tfd2; + + err = 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) { + err = 1; + (void)fprintf(stderr, "ar: %s: %s.\n", + file, strerror(errno)); + goto useold; + } + (void)fstat(sfd, &sb); + if (options & AR_U && sb.st_mtime <= chdr.date) { + (void)close(sfd); + 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) { + (void)fprintf(stderr, "ar: %s: archive member not found.\n", + posarg); + close_archive(afd); + return(1); + } + + /* Append any left-over arguments to the end of the after file. */ +append: while ((file = *argv++) != 0) { + if (options & AR_V) + (void)printf("a - %s\n", file); + sfd = open(file, O_RDONLY); + if (sfd < 0) { + err = 1; + (void)fprintf(stderr, "ar: %s: %s.\n", + file, strerror(errno)); + 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(err); +} diff --git a/src/cmd/ar/strmode.c b/src/cmd/ar/strmode.c new file mode 100644 index 0000000..8889b5f --- /dev/null +++ b/src/cmd/ar/strmode.c @@ -0,0 +1,146 @@ +/*- + * 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. + */ +#ifdef CROSS +# include +# include +#else +# include +# include +#endif + +void +strmode(mode, p) + register mode_t mode; + register char *p; +{ + /* print type */ + switch (mode & S_IFMT) { + case S_IFDIR: /* directory */ + *p++ = 'd'; + break; + case S_IFCHR: /* character special */ + *p++ = 'c'; + break; + case S_IFBLK: /* block special */ + *p++ = 'b'; + break; + case S_IFREG: /* regular */ + *p++ = '-'; + break; + case S_IFLNK: /* symbolic link */ + *p++ = 'l'; + break; + case S_IFSOCK: /* socket */ + *p++ = 's'; + break; +#ifdef S_IFIFO + case S_IFIFO: /* fifo */ + *p++ = 'p'; + break; +#endif + default: /* unknown */ + *p++ = '?'; + break; + } + /* usr */ + if (mode & S_IRUSR) + *p++ = 'r'; + else + *p++ = '-'; + if (mode & S_IWUSR) + *p++ = 'w'; + else + *p++ = '-'; + switch (mode & (S_IXUSR | S_ISUID)) { + case 0: + *p++ = '-'; + break; + case S_IXUSR: + *p++ = 'x'; + break; + case S_ISUID: + *p++ = 'S'; + break; + case S_IXUSR | S_ISUID: + *p++ = 's'; + break; + } + /* group */ + if (mode & S_IRGRP) + *p++ = 'r'; + else + *p++ = '-'; + if (mode & S_IWGRP) + *p++ = 'w'; + else + *p++ = '-'; + switch (mode & (S_IXGRP | S_ISGID)) { + case 0: + *p++ = '-'; + break; + case S_IXGRP: + *p++ = 'x'; + break; + case S_ISGID: + *p++ = 'S'; + break; + case S_IXGRP | S_ISGID: + *p++ = 's'; + break; + } + /* other */ + if (mode & S_IROTH) + *p++ = 'r'; + else + *p++ = '-'; + if (mode & S_IWOTH) + *p++ = 'w'; + else + *p++ = '-'; + switch (mode & (S_IXOTH | S_ISVTX)) { + case 0: + *p++ = '-'; + break; + case S_IXOTH: + *p++ = 'x'; + break; + case S_ISVTX: + *p++ = 'T'; + break; + case S_IXOTH | S_ISVTX: + *p++ = 't'; + break; + } + *p++ = ' '; /* will be a '+' if ACL's implemented */ + *p = '\0'; +} diff --git a/src/cmd/as/Makefile b/src/cmd/as/Makefile new file mode 100644 index 0000000..78d7e12 --- /dev/null +++ b/src/cmd/as/Makefile @@ -0,0 +1,44 @@ +# +# as - Assembler +# aout - Display information from a.out files +# +TOPSRC = $(shell cd ../../..; pwd) +include $(TOPSRC)/target.mk +#include $(TOPSRC)/cross.mk + +CFLAGS += -Werror -Wall -Os +LDFLAGS += + +AOUTOBJS = aout.o mips-dis.o + +all: as aout + +as: as.o + ${CC} ${LDFLAGS} -o as.elf as.o ${LIBS} + ${OBJDUMP} -S as.elf > as.dis + ${SIZE} as.elf + ${ELF2AOUT} as.elf $@ && rm as.elf + +aout: $(AOUTOBJS) + ${CC} ${LDFLAGS} -o aout.elf $(AOUTOBJS) ${LIBS} + ${OBJDUMP} -S aout.elf > aout.dis + ${SIZE} aout.elf + ${ELF2AOUT} aout.elf $@ && rm aout.elf + +clean: + rm -f *.o *.0 *.elf as aout tags *~ *.dis tests/*.dis tests/*.gcc-dis tests/*.o + +test: + /usr/local/pic32-tools/bin/pic32-as -al example.s + +install: all + install as $(DESTDIR)/bin/ + install aout $(DESTDIR)/bin/ + +test.dis-gcc: test.s + $(AS) $< -o test.o + ${OBJDUMP} -D test.o > $@ + +test.dis: test.s as aout + ./as $< -o test.o + ./aout test.o > $@ diff --git a/src/cmd/as/aout.c b/src/cmd/as/aout.c new file mode 100644 index 0000000..f47b013 --- /dev/null +++ b/src/cmd/as/aout.c @@ -0,0 +1,313 @@ +/* + * Utility for displaying a.out object file information. + * + * Copyright (C) 2011 Serge Vakulenko, + * + * 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 the copyright notice and this + * permission notice and warranty disclaimer appear in supporting + * documentation, and that the name of the author not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * + * The author disclaim all warranties with regard to this + * software, including all implied warranties of merchantability + * and fitness. In no event shall the author 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. + */ +#ifdef CROSS +# include +#else +# include +#endif +#include +#include + +#define USER_CODE_START 0x7f008000 + +struct exec hdr; /* a.out header */ +FILE *text, *rel; +int rflag, dflag; +int addr; + +extern int print_insn_mips (unsigned memaddr, + unsigned long int word, FILE *stream); + +unsigned int fgetword (f) + register FILE *f; +{ + register unsigned int h; + + h = getc (f); + h |= getc (f) << 8; + h |= getc (f) << 16; + h |= getc (f) << 24; + return h; +} + +int fgethdr (text, h) + register FILE *text; + register struct exec *h; +{ + h->a_magic = fgetword (text); + h->a_text = fgetword (text); + h->a_data = fgetword (text); + h->a_bss = fgetword (text); + h->a_reltext = fgetword (text); + h->a_reldata = fgetword (text); + h->a_syms = fgetword (text); + h->a_entry = fgetword (text); + return (1); +} + +/* + * Read a relocation record: 1 to 6 bytes. + */ +void fgetrel (f, r) + register FILE *f; + register struct reloc *r; +{ + r->flags = getc (f); + if ((r->flags & RSMASK) == REXT) { + r->index = getc (f); + r->index |= getc (f) << 8; + r->index |= getc (f) << 16; + } + if ((r->flags & RFMASK) == RHIGH16 || + (r->flags & RFMASK) == RHIGH16S) + { + r->offset = getc (f); + r->offset |= getc (f) << 8; + } +} + +/* + * Read a symbol table entry. + * Return a number of bytes read, or -1 on EOF. + * Format of symbol record: + * 1 byte: length of name in bytes + * 1 byte: type of symbol (N_UNDF, N_ABS, N_TEXT, etc) + * 4 bytes: value + * N bytes: name + */ +int fgetsym (text, name, value, type) + register FILE *text; + register char *name; + unsigned *value; + unsigned *type; +{ + register int len; + unsigned nbytes; + + len = getc (text); + if (len <= 0) + return -1; + *type = getc (text); + *value = fgetword (text); + nbytes = len + 6; + while (len-- > 0) + *name++ = getc (text); + *name = '\0'; + return nbytes; +} + +void prrel (r) + register struct reloc *r; +{ + printf ("<"); + switch (r->flags & RSMASK) { + default: putchar ('?'); break; + case RTEXT: putchar ('t'); break; + case RDATA: putchar ('d'); break; + case RBSS: putchar ('b'); break; + case REXT: printf ("%d", r->index); break; + case RABS: break; + } + switch (r->flags & RFMASK) { + default: putchar ('?'); break; + case RBYTE32: putchar ('b'); break; + case RWORD26: putchar ('j'); break; + case RWORD16: putchar ('w'); break; + case RHIGH16: printf ("u.%x", r->offset); break; + case RHIGH16S: printf ("h.%x", r->offset); break; + case RBYTE16: break; + } + if (r->flags & RGPREL) + putchar ('g'); + printf (">"); +} + +void prtext (n) + register int n; +{ + unsigned opcode; + struct reloc relinfo; + + while (n--) { + printf (" %8x:", addr); + opcode = fgetword (text); + printf ("\t%08x", opcode); + if (rflag) { + putchar (' '); + fgetrel (rel, &relinfo); + prrel (&relinfo); + } + if (! dflag) { + putchar ('\t'); + print_insn_mips (addr, opcode, stdout); + } + putchar ('\n'); + + /* Next address */ + addr += 4; + } +} + +void prdata (n) + register int n; +{ + struct reloc relinfo; + + while (n--) { + printf (" %8x:\t%08x", addr, fgetword (text)); + if (rflag) { + putchar (' '); + fgetrel (rel, &relinfo); + prrel (&relinfo); + } + putchar ('\n'); + + /* Next address */ + addr += 4; + } +} + +void prsyms (nbytes) + register int nbytes; +{ + register int n, c; + unsigned value, type; + char name [256]; + + while (nbytes > 0) { + n = fgetsym (text, name, &value, &type); + if (n <= 0) + break; + nbytes -= n; + + switch (type & N_TYPE) { + case N_ABS: c = 'a'; break; + case N_TEXT: c = 't'; break; + case N_DATA: c = 'd'; break; + case N_BSS: c = 'b'; break; + case N_STRNG: c = 's'; break; + case N_UNDF: c = 'u'; break; + case N_COMM: c = 'c'; break; + case N_FN: c = 'f'; break; + default: c = '?'; break; + } + if (type & N_EXT) + c += 'A' - 'a'; + + if (c == 'U') + printf (" %c %s\n", c, name); + else + printf (" %08x %c %s\n", value, c, name); + } +} + +void disasm (fname) + register char *fname; +{ + text = fopen (fname, "r"); + if (! text) { + fprintf (stderr, "aout: %s not found\n", fname); + return; + } + if (! fgethdr (text, &hdr) || N_BADMAG (hdr)) { + fprintf (stderr, "aout: %s not an object file\n", fname); + return; + } + if (rflag) { + if (hdr.a_magic != RMAGIC) { + fprintf (stderr, "aout: %s is not relocatable\n", + fname); + rflag = 0; + } else { + rel = fopen (fname, "r"); + if (! rel) { + fprintf (stderr, "aout: %s not found\n", fname); + return; + } + fseek (rel, N_TRELOFF (hdr), 0); + } + } + printf ("File %s:\n", fname); + printf (" a_magic = %08x (%s)\n", hdr.a_magic, + hdr.a_magic == RMAGIC ? "relocatable" : + hdr.a_magic == OMAGIC ? "OMAGIC" : + hdr.a_magic == NMAGIC ? "NMAGIC" : "unknown"); + printf (" a_text = %08x (%u bytes)\n", hdr.a_text, hdr.a_text); + printf (" a_data = %08x (%u bytes)\n", hdr.a_data, hdr.a_data); + printf (" a_bss = %08x (%u bytes)\n", hdr.a_bss, hdr.a_bss); + printf (" a_reltext = %08x (%u bytes)\n", hdr.a_reltext, hdr.a_reltext); + printf (" a_reldata = %08x (%u bytes)\n", hdr.a_reldata, hdr.a_reldata); + printf (" a_syms = %08x (%u bytes)\n", hdr.a_syms, hdr.a_syms); + printf (" a_entry = %08x\n", hdr.a_entry); + + addr = (hdr.a_magic == RMAGIC) ? 0 : USER_CODE_START; + + if (hdr.a_text > 0) { + printf ("\nSection .text:\n"); + prtext (hdr.a_text / sizeof(int)); + } + if (hdr.a_data > 0) { + printf ("\nSection .data:\n"); + if (rflag) + fseek (rel, N_DRELOFF (hdr), 0); + prdata (hdr.a_data / sizeof(int)); + } + if (hdr.a_syms > 0) { + printf ("\nSymbols:\n"); + fseek (text, N_SYMOFF (hdr), 0); + prsyms (hdr.a_syms); + } + printf ("\n"); +} + +int main (argc, argv) + register char **argv; +{ + int ch; + + while ((ch = getopt (argc, argv, "rd")) != EOF) + switch (ch) { + case 'r': /* print relocation info */ + rflag++; + break; + case 'd': /* do not disassemble */ + dflag++; + break; + default: +usage: fprintf (stderr, "Usage:\n"); + fprintf (stderr, " aout [-rd] file...\n"); + fprintf (stderr, "Options:\n"); + fprintf (stderr, " -r Print relocation info\n"); + fprintf (stderr, " -d Do not disassemble\n"); + return (1); + } + argc -= optind; + argv += optind; + if (argc <= 0) + goto usage; + + for (; argc-- > 0; argv++) + disasm (*argv); + return (0); +} diff --git a/src/cmd/as/as.c b/src/cmd/as/as.c new file mode 100644 index 0000000..353d4d6 --- /dev/null +++ b/src/cmd/as/as.c @@ -0,0 +1,2717 @@ +/* + * Assembler for MIPS32. + * The syntax is compatible with GCC output. + * + * Copyright (C) 2011-2012 Serge Vakulenko, + * + * 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 the copyright notice and this + * permission notice and warranty disclaimer appear in supporting + * documentation, and that the name of the author not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * + * The author disclaim all warranties with regard to this + * software, including all implied warranties of merchantability + * and fitness. In no event shall the author 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. + */ +#ifdef CROSS +# include +# include +#else +# include +#endif +#include +#include +#include +#include +#include + +#define WORDSZ 4 /* word size in bytes */ + +/* + * Locals beginning with L or dot are stripped off by -X flag. + */ +#define IS_LOCAL(s) ((s)->n_name[0] == 'L' || (s)->n_name[0] == '.') + +/* + * Types of lexemes. + */ +enum { + LEOF = 1, /* end of file */ + LEOL, /* end of line */ + LNAME, /* identifier */ + LREG, /* machine register */ + LNUM, /* integer number */ + LLSHIFT, /* << */ + LRSHIFT, /* >> */ + LASCII, /* .ascii */ + LBSS, /* .bss */ + LCOMM, /* .comm */ + LDATA, /* .data */ + LGLOBL, /* .globl */ + LHALF, /* .half */ + LSTRNG, /* .strng */ + LRDATA, /* .rdata */ + LTEXT, /* .text */ + LEQU, /* .equ */ + LWORD, /* .word */ + LBYTE, /* .byte */ + LSPACE, /* .space */ + LFILE, /* .file */ + LSECTION, /* .section */ + LSYMTYPE, /* @type of symbol */ + LSECTYPE, /* @type of section */ + LPREVIOUS, /* .previous */ + LGNUATTR, /* .gnu_attribute */ + LALIGN, /* .align */ + LSET, /* .set */ + LENT, /* .ent */ + LTYPE, /* .type */ + LFRAME, /* .frame */ + LMASK, /* .mask */ + LFMASK, /* .fmask */ + LEND, /* .end */ + LSIZE, /* .size */ + LIDENT, /* .ident */ + LWEAK, /* .weak */ + LLOCAL, /* .local */ +}; + +/* + * Segment ids. + */ +enum { + STEXT, + SDATA, + SSTRNG, + SBSS, + SEXT, + SABS, /* special case for getexpr() */ +}; + +/* + * Sizes of tables. + * Hash sizes should be powers of 2! + */ +#define HASHSZ 1024 /* symbol name hash table size */ +#define HCMDSZ 256 /* instruction hash table size */ +#define STSIZE (HASHSZ*9/10) /* symbol name table size */ +#define MAXRLAB 200 /* max relative (digit) labels */ + +/* + * On second pass, hashtab[] is not needed. + * We use it under name newindex[] to reindex symbol references + * when -x or -X options are enabled. + */ +#define newindex hashtab + +/* + * Convert segment id to symbol type. + */ +const int segmtype [] = { + N_TEXT, /* STEXT */ + N_DATA, /* SDATA */ + N_STRNG, /* SSTRNG */ + N_BSS, /* SBSS */ + N_UNDF, /* SEXT */ + N_ABS, /* SABS */ +}; + +/* + * Convert segment id to relocation type. + */ +const int segmrel [] = { + RTEXT, /* STEXT */ + RDATA, /* SDATA */ + RSTRNG, /* SSTRNG */ + RBSS, /* SBSS */ + REXT, /* SEXT */ + RABS, /* SABS */ +}; + +/* + * Convert symbol type to segment id. + */ +const int typesegm [] = { + SEXT, /* N_UNDF */ + SABS, /* N_ABS */ + STEXT, /* N_TEXT */ + SDATA, /* N_DATA */ + SBSS, /* N_BSS */ + SSTRNG, /* N_STRNG */ +}; + +/* + * Table of local (numeric) labels. + */ +struct labeltab { + int num; + int value; +}; + +#define RLAB_OFFSET (1 << 23) /* index offset of relative label */ +#define RLAB_MAXVAL 1000000 /* max value of relative label */ + +/* + * Main opcode table. + */ +struct optable { + unsigned opcode; /* instruction code */ + const char *name; /* instruction name */ + unsigned type; /* flags */ + void (*func) (unsigned, struct reloc*); /* handler for pseudo-instructions */ +}; + +/* + * Flags of instruction formats. + */ +#define FRD1 (1 << 0) /* rd, ... */ +#define FRD2 (1 << 1) /* .., rd, ... */ +#define FRT1 (1 << 2) /* rt, ... */ +#define FRT2 (1 << 3) /* .., rt, ... */ +#define FRT3 (1 << 4) /* .., .., rt */ +#define FRS1 (1 << 5) /* rs, ... */ +#define FRS2 (1 << 6) /* .., rs, ... */ +#define FRS3 (1 << 7) /* .., .., rs */ +#define FRSB (1 << 8) /* ... (rs) */ +#define FCODE (1 << 9) /* immediate shifted <<6 */ +#define FDSLOT (1 << 10) /* have delay slot */ +#define FOFF16 (1 << 11) /* 16-bit relocatable offset */ +#define FHIGH16 (1 << 12) /* high 16-bit relocatable offset */ +#define FOFF18 (1 << 13) /* 18-bit PC-relative relocatable offset shifted >>2 */ +#define FAOFF18 (1 << 14) /* 18-bit PC-relative relocatable offset shifted >>2 */ +#define FAOFF28 (1 << 15) /* 28-bit absolute relocatable offset shifted >>2 */ +#define FSA (1 << 16) /* 5-bit shift amount */ +#define FSEL (1 << 17) /* optional 3-bit COP0 register select */ +#define FSIZE (1 << 18) /* bit field size */ +#define FMSB (1 << 19) /* bit field msb */ +#define FRTD (1 << 20) /* set rt to rd number */ +#define FCODE16 (1 << 21) /* immediate shifted <<16 */ +#define FMOD (1 << 22) /* modifies the first register */ + +/* + * Implement pseudo-instructions. + * TODO: bge, bgeu, bgt, bgtu, ble, bleu, blt, bltu + */ +void emit_li (unsigned, struct reloc*); +void emit_la (unsigned, struct reloc*); + +const struct optable optable [] = { + { 0x00000020, "add", FRD1 | FRS2 | FRT3 | FMOD }, + { 0x20000000, "addi", FRT1 | FRS2 | FOFF16 | FMOD }, + { 0x24000000, "addiu", FRT1 | FRS2 | FOFF16 | FMOD }, + { 0x00000021, "addu", FRD1 | FRS2 | FRT3 | FMOD }, + { 0x00000024, "and", FRD1 | FRS2 | FRT3 | FMOD }, + { 0x30000000, "andi", FRT1 | FRS2 | FOFF16 | FMOD }, + { 0x10000000, "b", FAOFF18 | FDSLOT }, + { 0x04110000, "bal", FAOFF18 | FDSLOT }, + { 0x10000000, "beq", FRS1 | FRT2 | FOFF18 | FDSLOT }, + { 0x50000000, "beql", FRS1 | FRT2 | FOFF18 | FDSLOT }, + { 0x50000000, "beqz", FRS1 | FOFF18 | FDSLOT }, + { 0x04010000, "bgez", FRS1 | FOFF18 | FDSLOT }, + { 0x04110000, "bgezal", FRS1 | FOFF18 | FDSLOT }, + { 0x04130000, "bgezall", FRS1 | FOFF18 | FDSLOT }, + { 0x04030000, "bgezl", FRS1 | FOFF18 | FDSLOT }, + { 0x1c000000, "bgtz", FRS1 | FOFF18 | FDSLOT }, + { 0x5c000000, "bgtzl", FRS1 | FOFF18 | FDSLOT }, + { 0x18000000, "blez", FRS1 | FOFF18 | FDSLOT }, + { 0x58000000, "blezl", FRS1 | FOFF18 | FDSLOT }, + { 0x04000000, "bltz", FRS1 | FOFF18 | FDSLOT }, + { 0x04100000, "bltzal", FRS1 | FOFF18 | FDSLOT }, + { 0x04120000, "bltzall", FRS1 | FOFF18 | FDSLOT }, + { 0x04020000, "bltzl", FRS1 | FOFF18 | FDSLOT }, + { 0x14000000, "bne", FRS1 | FRT2 | FOFF18 | FDSLOT }, + { 0x54000000, "bnel", FRS1 | FRT2 | FOFF18 | FDSLOT }, + { 0x54000000, "bnez", FRS1 | FOFF18 | FDSLOT }, + { 0x0000000d, "break", FCODE16 }, + { 0x70000021, "clo", FRD1 | FRS2 | FRTD | FMOD }, + { 0x70000020, "clz", FRD1 | FRS2 | FRTD | FMOD }, + { 0x4200001f, "deret", 0 }, + { 0x41606000, "di", FRT1 | FMOD }, + { 0x0000001a, "div", FRS1 | FRT2 }, + { 0x0000001b, "divu", FRS1 | FRT2 }, + { 0x000000c0, "ehb", 0 }, + { 0x41606020, "ei", FRT1 | FMOD }, + { 0x42000018, "eret", 0 }, + { 0x7c000000, "ext", FRT1 | FRS2 | FSA | FSIZE | FMOD }, + { 0x7c000004, "ins", FRT1 | FRS2 | FSA | FMSB | FMOD }, + { 0x08000000, "j", FAOFF28 | FDSLOT }, + { 0x0c000000, "jal", FAOFF28 | FDSLOT }, + { 0x00000009, "jalr", FRD1 | FRS2 | FDSLOT }, + { 0x00000409, "jalr.hb", FRD1 | FRS2 | FDSLOT }, + { 0x00000008, "jr", FRS1 | FDSLOT }, + { 0x00000408, "jr.hb", FRS1 | FDSLOT }, + { 0, "la", FRT1 | FMOD, emit_la }, + { 0x80000000, "lb", FRT1 | FOFF16 | FRSB | FMOD }, + { 0x90000000, "lbu", FRT1 | FOFF16 | FRSB | FMOD }, + { 0x84000000, "lh", FRT1 | FOFF16 | FRSB | FMOD }, + { 0x94000000, "lhu", FRT1 | FOFF16 | FRSB | FMOD }, + { 0, "li", FRT1 | FMOD, emit_li }, + { 0xc0000000, "ll", FRT1 | FOFF16 | FRSB | FMOD }, + { 0x3c000000, "lui", FRT1 | FHIGH16 | FMOD }, + { 0x8c000000, "lw", FRT1 | FOFF16 | FRSB | FMOD }, + { 0x88000000, "lwl", FRT1 | FOFF16 | FRSB | FMOD }, + { 0x98000000, "lwr", FRT1 | FOFF16 | FRSB | FMOD }, + { 0x70000000, "madd", FRS1 | FRT2 | FMOD }, + { 0x70000001, "maddu", FRS1 | FRT2 | FMOD }, + { 0x40000000, "mfc0", FRT1 | FRD2 | FSEL | FMOD }, + { 0x00000010, "mfhi", FRD1 | FMOD }, + { 0x00000012, "mflo", FRD1 | FMOD }, + { 0x00000021, "move", FRD1 | FRS2 | FMOD }, // addu + { 0x0000000b, "movn", FRD1 | FRS2 | FRT3 | FMOD }, + { 0x0000000a, "movz", FRD1 | FRS2 | FRT3 | FMOD }, + { 0x70000004, "msub", FRS1 | FRT2 | FMOD }, + { 0x70000005, "msubu", FRS1 | FRT2 | FMOD }, + { 0x40800000, "mtc0", FRT1 | FRD2 | FSEL }, + { 0x00000011, "mthi", FRS1 }, + { 0x00000013, "mtlo", FRS1 }, + { 0x70000002, "mul", FRD1 | FRS2 | FRT3 | FMOD }, + { 0x00000018, "mult", FRS1 | FRT2 }, + { 0x00000019, "multu", FRS1 | FRT2 }, + { 0x00000000, "nop", 0 }, + { 0x00000027, "nor", FRD1 | FRS2 | FRT3 | FMOD }, + { 0x00000025, "or", FRD1 | FRS2 | FRT3 | FMOD }, + { 0x34000000, "ori", FRT1 | FRS2 | FOFF16 | FMOD }, + { 0x7c00003b, "rdhwr", FRT1 | FRD2 | FMOD }, + { 0x41400000, "rdpgpr", FRD1 | FRT2 | FMOD }, + { 0x00200002, "ror", FRD1 | FRT2 | FSA | FMOD }, + { 0x00000046, "rorv", FRD1 | FRT2 | FRS3 | FMOD }, + { 0xa0000000, "sb", FRT1 | FOFF16 | FRSB }, + { 0xe0000000, "sc", FRT1 | FOFF16 | FRSB }, + { 0x7000003f, "sdbbp", FCODE }, + { 0x7c000420, "seb", FRD1 | FRT2 }, + { 0x7c000620, "seh", FRD1 | FRT2 }, + { 0xa4000000, "sh", FRT1 | FOFF16 | FRSB }, + { 0x00000000, "sll", FRD1 | FRT2 | FSA | FMOD }, + { 0x00000004, "sllv", FRD1 | FRT2 | FRS3 | FMOD }, + { 0x0000002a, "slt", FRD1 | FRS2 | FRT3 | FMOD }, + { 0x28000000, "slti", FRT1 | FRS2 | FOFF16 | FMOD }, + { 0x2c000000, "sltiu", FRT1 | FRS2 | FOFF16 | FMOD }, + { 0x0000002b, "sltu", FRD1 | FRS2 | FRT3 | FMOD }, + { 0x00000003, "sra", FRD1 | FRT2 | FSA | FMOD }, + { 0x00000007, "srav", FRD1 | FRT2 | FRS3 | FMOD }, + { 0x00000002, "srl", FRD1 | FRT2 | FSA | FMOD }, + { 0x00000006, "srlv", FRD1 | FRT2 | FRS3 | FMOD }, + { 0x00000040, "ssnop", 0 }, + { 0x00000022, "sub", FRD1 | FRS2 | FRT3 | FMOD }, + { 0x00000023, "subu", FRD1 | FRS2 | FRT3 | FMOD }, + { 0xac000000, "sw", FRT1 | FOFF16 | FRSB }, + { 0xa8000000, "swl", FRT1 | FOFF16 | FRSB }, + { 0xb8000000, "swr", FRT1 | FOFF16 | FRSB }, + { 0x0000000f, "sync", FCODE }, + { 0x0000000c, "syscall", FCODE }, + { 0x00000034, "teq", FRS1 | FRT2 | FCODE }, + { 0x040c0000, "teqi", FRS1 | FOFF16 }, + { 0x00000030, "tge", FRS1 | FRT2 | FCODE }, + { 0x04080000, "tgei", FRS1 | FOFF16 }, + { 0x04090000, "tgeiu", FRS1 | FOFF16 }, + { 0x00000031, "tgeu", FRS1 | FRT2 | FCODE }, + { 0x00000032, "tlt", FRS1 | FRT2 | FCODE }, + { 0x040a0000, "tlti", FRS1 | FOFF16 }, + { 0x040b0000, "tltiu", FRS1 | FOFF16 }, + { 0x00000033, "tltu", FRS1 | FRT2 | FCODE }, + { 0x00000036, "tne", FRS1 | FRT2 | FCODE }, + { 0x040e0000, "tnei", FRS1 | FOFF16 }, + { 0x42000020, "wait", FCODE }, + { 0x41c00000, "wrpgpr", FRD1 | FRT2 }, + { 0x7c0000a0, "wsbh", FRD1 | FRT2 | FMOD }, + { 0x00000026, "xor", FRD1 | FRS2 | FRT3 | FMOD }, + { 0x38000000, "xori", FRT1 | FRS2 | FOFF16 | FMOD }, + { 0, 0, 0 }, +}; + +/* + * Character classes. + */ +#define ISHEX(c) (ctype[(c)&0377] & 1) +#define ISOCTAL(c) (ctype[(c)&0377] & 2) +#define ISDIGIT(c) (ctype[(c)&0377] & 4) +#define ISLETTER(c) (ctype[(c)&0377] & 8) + +const char ctype [256] = { + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,8,0,0,0,0,0,0,0,0,0,8,0,7,7,7,7,7,7,7,7,5,5,0,0,0,0,0,0, + 8,9,9,9,9,9,9,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,0,0,0,0,8, + 0,9,9,9,9,9,9,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,0, +}; + +FILE *sfile [SABS], *rfile [SABS]; +unsigned count [SABS]; +int segm; +char *infile, *outfile = "a.out"; +char tfilename[] = "/tmp/asXXXXXX"; +int line; /* Source line number */ +int xflags, Xflag, uflag; +int stlength; /* Symbol table size in bytes */ +int stalign; /* Symbol table alignment */ +unsigned tbase, dbase, adbase, bbase; +struct nlist stab [STSIZE]; +int stabfree; +char space [STSIZE*8]; /* Area for symbol names */ +int lastfree; /* Free space offset */ +char name [256]; +unsigned intval; +int extref; +int blexflag, backlex, blextype; +short hashtab [HASHSZ], hashctab [HCMDSZ]; +struct labeltab labeltab [MAXRLAB]; /* relative labels */ +int nlabels; +int mode_reorder = 1; /* .set reorder option (default) */ +int mode_macro; /* .set macro option */ +int mode_mips16; /* .set mips16 option */ +int mode_micromips; /* .set micromips option */ +int mode_at; /* .set at option */ +int reorder_full; /* instruction buffered for reorder */ +unsigned reorder_word; /* buffered instruction... */ +unsigned reorder_clobber; /* ...modified this register */ +struct reloc reorder_rel; /* buffered relocation */ +struct reloc relabs = { RABS }; /* absolute relocation */ + +int expr_flags; /* flags set by getexpr */ +#define EXPR_GPREL 1 /* gp relative relocation */ +#define EXPR_HI 2 /* %hi function */ +#define EXPR_LO 4 /* %lo function */ + +/* Forward declarations. */ +unsigned getexpr (int *s); + +/* + * Fatal error message. + */ +void uerror (char *fmt, ...) +{ + va_list ap; + + va_start (ap, fmt); + fprintf (stderr, "as: "); + if (infile) + fprintf (stderr, "%s, ", infile); + if (line) + fprintf (stderr, "%d: ", line); + vfprintf (stderr, fmt, ap); + va_end (ap); + fprintf (stderr, "\n"); + exit (1); +} + +/* + * Read a 4-byte word from the file. + * Little-endian. + */ +unsigned fgetword (f) + FILE *f; +{ + unsigned int w; + + if (fread (&w, sizeof(w), 1, f) != 1) + return 0; + return w; +} + +/* + * Write a 4-byte word to the file. + * Little-endian. + */ +void fputword (w, f) + unsigned int w; + FILE *f; +{ + fwrite (&w, sizeof(w), 1, f); +} + +/* +* Read a relocation record: 1 to 6 bytes. +*/ +void fgetrel (f, r) + register FILE *f; + register struct reloc *r; +{ + r->flags = getc (f); + if ((r->flags & RSMASK) == REXT) { + r->index = getc (f); + r->index |= getc (f) << 8; + r->index |= getc (f) << 16; + } + if ((r->flags & RFMASK) == RHIGH16 || + (r->flags & RFMASK) == RHIGH16S) + { + r->offset = getc (f); + r->offset |= getc (f) << 8; + } +} + +/* +* Emit a relocation record: 1 to 6 bytes. +* Return a written length. +*/ +unsigned fputrel (r, f) + register struct reloc *r; + register FILE *f; +{ + register unsigned nbytes = 1; + + putc (r->flags, f); + if ((r->flags & RSMASK) == REXT) { + putc (r->index, f); + putc (r->index >> 8, f); + putc (r->index >> 16, f); + nbytes += 3; + } + if ((r->flags & RFMASK) == RHIGH16 || + (r->flags & RFMASK) == RHIGH16S) + { + putc (r->offset, f); + putc (r->offset >> 8, f); + nbytes += 2; + } + return nbytes; +} + +/* + * Write the a.out header to the file. + * Little-endian. + */ +void fputhdr (filhdr, coutb) + register struct exec *filhdr; + register FILE *coutb; +{ + fputword (filhdr->a_magic, coutb); + fputword (filhdr->a_text, coutb); + fputword (filhdr->a_data, coutb); + fputword (filhdr->a_bss, coutb); + fputword (filhdr->a_reltext, coutb); + fputword (filhdr->a_reldata, coutb); + fputword (filhdr->a_syms, coutb); + fputword (filhdr->a_entry, coutb); +} + +/* + * Emit the nlist record for the symbol. + */ +void fputsym (s, file) + register struct nlist *s; + register FILE *file; +{ + register int i; + + putc (s->n_len, file); + putc (s->n_type & ~N_LOC, file); + fputword (s->n_value, file); + for (i=0; in_len; i++) + putc (s->n_name[i], file); +} + +/* + * Create temporary files for STEXT, SDATA and SSTRNG segments. + */ +void startup () +{ + register int i; + + mktemp (tfilename); + for (i=STEXT; i> 19); + } + return hash; +} + +void hashinit () +{ + register int i, h; + register const struct optable *p; + + for (i=0; iname; p++) { + h = hash_rot13 (p->name) & (HCMDSZ-1); + while (hashctab[h] != -1) + if (--h < 0) + h += HCMDSZ; + hashctab[h] = p - optable; + } + for (i=0; iname; p++) { + if (strncmp (name, p->name, p->len) == 0 && + (p->name [p->len] == 0 || + p->name [p->len] == '.')) + { + segm = p->segm; + return; + } + } + uerror ("bad .section name"); +} + +int lookreg () +{ + int val; + char *cp; + + switch (name [1]) { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + val = 0; + for (cp=name+1; ISDIGIT (*cp); cp++) { + val *= 10; + val += *cp - '0'; + } + if (*cp != 0) + break; + return val; + case 'a': + if (name[3] == 0) { + switch (name[2]) { + case '0': return 4; /* $a0 */ + case '1': return 5; /* $a1 */ + case '2': return 6; /* $a2 */ + case '3': return 7; /* $a3 */ + case 't': return 1; /* $at */ + } + } + break; + case 'f': + if (name[3] == 0 && name[2] == 'p') + return 30; /* $fp */ + break; + case 'g': + if (name[3] == 0 && name[2] == 'p') + return 28; /* $gp */ + break; + case 'k': + if (name[3] == 0) { + switch (name[2]) { + case '0': return 26; /* $k0 */ + case '1': return 27; /* $k1 */ + } + } + break; + case 'r': + if (name[3] == 0 && name[2] == 'a') + return 31; /* $ra */ + break; + case 's': + if (name[3] == 0) { + switch (name[2]) { + case '0': return 16; /* $s0 */ + case '1': return 17; /* $s1 */ + case '2': return 18; /* $s2 */ + case '3': return 19; /* $s3 */ + case '4': return 20; /* $s4 */ + case '5': return 21; /* $s5 */ + case '6': return 22; /* $s6 */ + case '7': return 23; /* $s7 */ + case '8': return 30; /* $s8 */ + case 'p': return 29; /* $sp */ + } + } + break; + case 't': + if (name[3] == 0) { + switch (name[2]) { + case '0': return 8; /* $t0 */ + case '1': return 9; /* $t1 */ + case '2': return 10; /* $t2 */ + case '3': return 11; /* $t3 */ + case '4': return 12; /* $t4 */ + case '5': return 13; /* $t5 */ + case '6': return 14; /* $t6 */ + case '7': return 15; /* $t7 */ + case '8': return 24; /* $t8 */ + case '9': return 25; /* $t9 */ + } + } + break; + case 'v': + if (name[3] == 0) { + switch (name[2]) { + case '0': return 2; /* $v0 */ + case '1': return 3; /* $v1 */ + } + } + break; + case 'z': + if (! strcmp (name+2, "ero")) + return 0; /* $zero */ + break; + } + return -1; +} + +int lookcmd () +{ + register int i, h; + + h = hash_rot13 (name) & (HCMDSZ-1); + while ((i = hashctab[h]) != -1) { + if (! strcmp (optable[i].name, name)) + return (i); + if (--h < 0) + h += HCMDSZ; + } + return (-1); +} + +char *alloc (len) +{ + register int r; + + r = lastfree; + lastfree += len; + if (lastfree > sizeof(space)) + uerror ("out of memory"); + return (space + r); +} + +int lookname () +{ + register int i, h; + + /* Search for symbol name. */ + h = hash_rot13 (name) & (HASHSZ-1); + while ((i = hashtab[h]) != -1) { + if (! strcmp (stab[i].n_name, name)) + return (i); + if (--h < 0) + h += HASHSZ; + } + + /* Add a new symbol to table. */ + if ((i = stabfree++) >= STSIZE) + uerror ("symbol table overflow"); + stab[i].n_len = strlen (name); + stab[i].n_name = alloc (1 + stab[i].n_len); + strcpy (stab[i].n_name, name); + stab[i].n_value = 0; + stab[i].n_type = N_UNDF; + hashtab[h] = i; + return (i); +} + +/* + * Read a lexical element, return it's type and store a value into *val. + * Returned type codes: + * LEOL - End of line. Value is a line number. + * LEOF - End of file. + * LNUM - Integer value (into intval), *val undefined. + * LNAME - Identifier. String value is in name[] array. + * LREG - Machine register. Value is a register number. + * LLSHIFT - << operator. + * LRSHIFT - >> operator. + * LASCII - .ascii assembler instruction. + * LBSS - .bss assembler instruction. + * LCOMM - .comm assembler instruction. + * LDATA - .data assembler instruction. + * LGLOBL - .globl assembler instruction. + * LHALF - .half assembler instruction. + * LSTRNG - .strng assembler instruction. + * LTEXT - .text assembler instruction. + * LEQU - .equ assembler instruction. + * LWORD - .word assembler instruction. + * LFILE - .file assembler instruction. + * LSECTION - .section assembler instruction. + */ +int getlex (pval) + register int *pval; +{ + register int c; + + if (blexflag) { + blexflag = 0; + *pval = blextype; + return (backlex); + } + for (;;) { + switch (c = getchar()) { + case '#': +skiptoeol: while ((c = getchar()) != '\n') + if (c == EOF) + return (LEOF); + case '\n': + ++line; + c = getchar (); + if (c == '#') + goto skiptoeol; + ungetc (c, stdin); + case ';': + *pval = line; + return (LEOL); + case ' ': + case '\t': + continue; + case EOF: + return (LEOF); + case '\\': + c = getchar (); + if (c=='<') + return (LLSHIFT); + if (c=='>') + return (LRSHIFT); + ungetc (c, stdin); + return ('\\'); + case '\'': case '%': + case '^': case '&': case '|': case '~': + case '+': case '-': case '*': case '/': + case '"': case ',': case '[': case ']': + case '(': case ')': case '{': case '}': + case '<': case '>': case '=': case ':': + return (c); + case '0': + if ((c = getchar ()) == 'x' || c=='X') { + gethnum (); + return (LNUM); + } + ungetc (c, stdin); + c = '0'; + case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + case '8': case '9': + getnum (c); + return (LNUM); + default: + if (! ISLETTER (c)) + uerror ("bad character: \\%o", c & 0377); + getname (c); + if (name[0] == '.') { + if (name[1] == 0) + return ('.'); + *pval = lookacmd(); + if (*pval != -1) + return (*pval); + } + if (name[0] == '$') { + *pval = lookreg(); + if (*pval != -1) + return (LREG); + } + if (name[0] == '@') { + *pval = looktype(); + if (*pval != -1) + return (*pval); + } + return (LNAME); + } + } +} + +void ungetlex (val, type) +{ + blexflag = 1; + backlex = val; + blextype = type; +} + +int getterm () +{ + register int ty; + int cval, s; + + switch (getlex (&cval)) { + default: + uerror ("operand missed"); + case LNUM: + cval = getchar (); + if (cval == 'b' || cval == 'B') + extref = RLAB_OFFSET - intval; + else if (cval == 'f' || cval == 'F') + extref = RLAB_OFFSET + intval; + else { + /* Integer literal. */ + ungetc (cval, stdin); + return (SABS); + } + /* Local label. */ + if (intval >= RLAB_MAXVAL) + uerror ("too large relative label"); + intval = 0; + return (SEXT); + case LNAME: + intval = 0; + cval = lookname(); + ty = stab[cval].n_type & N_TYPE; + if (ty==N_UNDF || ty==N_COMM) { + extref = cval; + return (SEXT); + } + intval = stab[cval].n_value; + return (typesegm [ty]); + case '.': + intval = count[segm]; + return (segm); + case '%': + if (getlex (&cval) != LNAME) + uerror ("bad %function name"); + if (strcmp (name, "gp_rel") == 0) { + /* GP relative reverence. */ + expr_flags |= EXPR_GPREL; + } else if (strcmp (name, "hi") == 0) { + expr_flags |= EXPR_HI; + } else if (strcmp (name, "lo") == 0) { + expr_flags |= EXPR_LO; + } else + uerror ("unknown function %s", name); + if (getlex (&cval) != '(') + uerror ("bad %s syntax", name); + /* fall through */ + case '(': + getexpr (&s); + if (getlex (&cval) != ')') + uerror ("bad () syntax"); + return (s); + } +} + +/* + * Get an expression. + * Return a value, put a base segment id to *s. + * A copy of value is saved in intval. + * + * expression = [term] {op term}... + * term = LNAME | LNUM | "." | "(" expression ")" + * op = "+" | "-" | "&" | "|" | "^" | "~" | "<<" | ">>" | "/" | "*" + */ +unsigned getexpr (s) + register int *s; +{ + register int clex; + int cval, s2; + unsigned rez; + + /* look a first lexeme */ + switch (clex = getlex (&cval)) { + default: + ungetlex (clex, cval); + rez = 0; + *s = SABS; + break; + case LNUM: + case LNAME: + case '.': + case '(': + case '%': + ungetlex (clex, cval); + *s = getterm (); + rez = intval; + break; + } + for (;;) { + switch (clex = getlex (&cval)) { + case '+': + s2 = getterm (); + if (*s == SABS) + *s = s2; + else if (s2 != SABS) + uerror ("too complex expression"); + rez += intval; + break; + case '-': + s2 = getterm (); + if (s2 == *s && s2 != SEXT) + *s = SABS; + else if (s2 != SABS) + uerror ("too complex expression"); + rez -= intval; + break; + case '&': + s2 = getterm (); + if (*s != SABS || s2 != SABS) + uerror ("too complex expression"); + rez &= intval; + break; + case '|': + s2 = getterm (); + if (*s != SABS || s2 != SABS) + uerror ("too complex expression"); + rez |= intval; + break; + case '^': + s2 = getterm (); + if (*s != SABS || s2 != SABS) + uerror ("too complex expression"); + rez ^= intval; + break; + case '~': + s2 = getterm (); + if (*s != SABS || s2 != SABS) + uerror ("too complex expression"); + rez ^= ~intval; + break; + case LLSHIFT: /* Ñдвиг влево */ + s2 = getterm (); + if (*s != SABS || s2 != SABS) + uerror ("too complex expression"); + rez <<= intval & 037; + break; + case LRSHIFT: /* Ñдвиг вправо */ + s2 = getterm (); + if (*s != SABS || s2 != SABS) + uerror ("too complex expression"); + rez >>= intval & 037; + break; + case '*': + s2 = getterm (); + if (*s != SABS || s2 != SABS) + uerror ("too complex expression"); + rez *= intval; + break; + case '/': + s2 = getterm (); + if (*s != SABS || s2 != SABS) + uerror ("too complex expression"); + if (intval == 0) + uerror ("division by zero"); + rez /= intval; + break; + default: + ungetlex (clex, cval); + intval = rez; + return (rez); + } + } + /* NOTREACHED */ +} + +void reorder_flush () +{ + if (reorder_full) { + fputword (reorder_word, sfile[segm]); + fputrel (&reorder_rel, rfile[segm]); + reorder_full = 0; + } +} + +/* + * Default emit function. + */ +void emitword (w, r, clobber_reg) + register unsigned w; + register struct reloc *r; + int clobber_reg; +{ + if (mode_reorder && segm == STEXT) { + reorder_flush(); + reorder_word = w; + reorder_rel = *r; + reorder_full = 1; + reorder_clobber = clobber_reg; + } else { + fputword (w, sfile[segm]); + fputrel (r, rfile[segm]); + } + count[segm] += WORDSZ; +} + +/* + * LI pseudo instruction. + */ +void emit_li (opcode, relinfo) + register unsigned opcode; + register struct reloc *relinfo; +{ + register unsigned value; + int cval, segment; + + if (getlex (&cval) != ',') + uerror ("comma expected"); + value = getexpr (&segment); + if (segment != SABS) + uerror ("absolute value required"); + if (value <= 0xffff) { + /* ori d, $zero, value */ + opcode |= 0x34000000 | value; + } else if (value >= -0x8000) { + /* addiu d, $zero, value */ + opcode |= 0x24000000 | (value & 0xffff); + } else { + /* lui d, value[31:16] + * ori d, d, value[15:0]) */ + emitword (opcode | 0x3c000000 | (value >> 16), &relabs, value >> 16); + opcode |= 0x34000000 | (opcode & 0x1f0000) << 5 | (value & 0xffff); + } + emitword (opcode, relinfo, value >> 16); +} + +/* + * LA pseudo instruction. + */ +void emit_la (opcode, relinfo) + register unsigned opcode; + register struct reloc *relinfo; +{ + register unsigned value; + int cval, segment; + + if (getlex (&cval) != ',') + uerror ("comma expected"); + expr_flags = 0; + value = getexpr (&segment); + if (segment == SABS) + uerror ("relocatable value required"); + relinfo->flags = segmrel [segment]; + if (relinfo->flags == REXT) + relinfo->index = extref; + if (expr_flags & EXPR_GPREL) + relinfo->flags |= RGPREL; + + /* lui d, %hi(value) + * addiu d, d, %lo(value) */ + relinfo->flags |= RHIGH16S; + relinfo->offset = value & 0xffff; + emitword (opcode | 0x3c000000 | (value >> 16), relinfo, (value + 0x8000) >> 16); + + relinfo->flags &= ~RHIGH16S; + opcode |= 0x24000000 | (opcode & 0x1f0000) << 5 | (value & 0xffff); + emitword (opcode, relinfo, value >> 16); +} + +/* + * Build and emit a machine instruction code. + */ +void makecmd (opcode, type, emitfunc) + unsigned opcode; + void (*emitfunc) (unsigned, struct reloc*); +{ + register int clex; + register unsigned offset; + struct reloc relinfo; + int cval, segment, clobber_reg, negate_literal; + + offset = 0; + relinfo.flags = RABS; + negate_literal = 0; + + /* + * GCC can generate "j" instead of "jr". + * Need to detect it early. + */ + if (type == (FAOFF28 | FDSLOT)) { + clex = getlex (&cval); + ungetlex (clex, cval); + if (clex == LREG) { + if (opcode == 0x08000000) { /* j - replace by jr */ + opcode = 0x00000008; + type = FRS1 | FDSLOT; + } + if (opcode == 0x0c000000) { /* jal - replace by jalr */ + opcode = 0x00000009; + type = FRD1 | FRS2 | FDSLOT; + } + } + } + + /* + * First register. + */ + cval = 0; + clobber_reg = 0; + if (type & FRD1) { + clex = getlex (&cval); + if (clex != LREG) + uerror ("bad rd register"); + opcode |= cval << 11; /* rd, ... */ + } + if (type & FRT1) { + clex = getlex (&cval); + if (clex != LREG) + uerror ("bad rt register"); + opcode |= cval << 16; /* rt, ... */ + } + if (type & FRS1) { +frs1: clex = getlex (&cval); + if (clex != LREG) + uerror ("bad rs register"); + if (cval == 0 && (opcode == 0x0000001a || /* div */ + opcode == 0x0000001b)) { /* divu */ + /* Div instruction with three args. + * Treat it as a 2-arg variant. */ + if (getlex (&cval) != ',') + uerror ("comma expected"); + goto frs1; + } + opcode |= cval << 21; /* rs, ... */ + } + if (type & FRTD) { + opcode |= cval << 16; /* rt equals rd */ + } + if ((type & FMOD) && (type & (FRD1 | FRT1 | FRS1))) + clobber_reg = cval; + + /* + * Second register. + */ + if (type & FRD2) { + if (getlex (&cval) != ',') + uerror ("comma expected"); + clex = getlex (&cval); + if (clex != LREG) + uerror ("bad rd register"); + opcode |= cval << 11; /* .., rd, ... */ + } + if (type & FRT2) { + if (getlex (&cval) != ',') + uerror ("comma expected"); + clex = getlex (&cval); + if (clex != LREG) { + if ((type & FRD1) && (type & FSA)) { + /* Second register operand omitted. + * Need to restore the missing operand. */ + ungetlex (clex, cval); + cval = (opcode >> 11) & 31; /* get 1-st register */ + opcode |= cval << 16; /* use 1-st reg as 2-nd */ + goto fsa; + } + uerror ("bad rt register"); + } + opcode |= cval << 16; /* .., rt, ... */ + } + if (type & FRS2) { + clex = getlex (&cval); + if (clex != ',') { + if ((opcode & 0xfc00003f) != 0x00000009) + uerror ("comma expected"); + /* Jalr with one argument. + * Treat as if the first argument is $31. */ + ungetlex (clex, cval); + cval = (opcode >> 11) & 31; /* get 1-st register */ + opcode |= cval << 21; /* use 1-st reg as 2-nd */ + opcode |= 31 << 11; /* set 1-st reg to 31 */ + clobber_reg = 31; + goto done3; + } + clex = getlex (&cval); + if (clex != LREG) { + if ((type & FRT1) && (type & FOFF16)) { + /* Second register operand omitted. + * Need to restore the missing operand. */ + ungetlex (clex, cval); + cval = (opcode >> 16) & 31; /* get 1-st register */ + opcode |= cval << 21; /* use 1-st reg as 2-nd */ + goto foff16; + } + uerror ("bad rs register"); + } + opcode |= cval << 21; /* .., rs, ... */ + } + + /* + * Third register. + */ + if (type & FRT3) { + clex = getlex (&cval); + if (clex != ',') { + /* Three-operand instruction used with two operands. + * Need to restore the missing operand. */ + ungetlex (clex, cval); + cval = (opcode >> 21) & 31; + opcode &= ~(31 << 21); /* clear 2-nd register */ + opcode |= ((opcode >> 11) & 31) << 21; /* use 1-st reg as 2-nd */ + opcode |= cval << 16; /* add 3-rd register */ + goto done3; + } + clex = getlex (&cval); + if (clex != LREG) { + if ((type & FRD1) && (type & FRS2)) { + /* Three-operand instruction used with literal operand. + * Convert it to immediate type. */ + unsigned newop; + switch (opcode & 0xfc0007ff) { + case 0x00000020: newop = 0x20000000; break; // add -> addi + case 0x00000021: newop = 0x24000000; break; // addu -> addiu + case 0x00000024: newop = 0x30000000; break; // and -> andi + case 0x00000025: newop = 0x34000000; break; // or -> ori + case 0x0000002a: newop = 0x28000000; break; // slt -> slti + case 0x0000002b: newop = 0x2c000000; break; // sltu -> sltiu + case 0x00000022: newop = 0x20000000; // sub -> addi, negate + negate_literal = 1; break; + case 0x00000023: newop = 0x24000000; // subu -> addiu, negate + negate_literal = 1; break; + case 0x00000026: newop = 0x38000000; break; // xor -> xori + default: + uerror ("bad rt register"); + return; + } + ungetlex (clex, cval); + cval = (opcode >> 11) & 31; /* get 1-st register */ + newop |= cval << 16; /* set 1-st register */ + newop |= opcode & (31 << 21); /* set 2-nd register */ + opcode = newop; + type = FRT1 | FRS2 | FOFF16 | FMOD; + goto foff16; + } + uerror ("bad rt register"); + } + opcode |= cval << 16; /* .., .., rt */ + } + if (type & FRS3) { + clex = getlex (&cval); + if (clex != ',') { + /* Three-operand instruction used with two operands. + * Need to restore the missing operand. */ + ungetlex (clex, cval); + cval = (opcode >> 16) & 31; + opcode &= ~(31 << 16); /* clear 2-nd register */ + opcode |= ((opcode >> 11) & 31) << 16; /* use 1-st reg as 2-nd */ + opcode |= cval << 21; /* add 3-rd register */ + goto done3; + } + clex = getlex (&cval); + if (clex != LREG) + uerror ("bad rs register"); + opcode |= cval << 21; /* .., .., rs */ + } +done3: + + /* + * Immediate argument. + */ + if (type & FSEL) { + /* optional COP0 register select */ + clex = getlex (&cval); + if (clex == ',') { + offset = getexpr (&segment); + if (segment != SABS) + uerror ("absolute value required"); + opcode |= offset & 7; + } else + ungetlex (clex, cval); + + } else if (type & (FCODE | FCODE16 | FSA)) { + /* Non-relocatable offset */ + if (type & FSA) { + if (getlex (&cval) != ',') + uerror ("comma expected"); + clex = getlex (&cval); + if (clex == LREG && type == (FRD1 | FRT2 | FSA | FMOD)) { + /* Literal-operand shift instruction used with register operand. + * Convert it to 3-register type. */ + unsigned newop; + switch (opcode & 0xffe0003f) { + case 0x00200002: newop = 0x00000046; break; // ror -> rorv + case 0x00000000: newop = 0x00000004; break; // sll -> sllv + case 0x00000003: newop = 0x00000007; break; // sra -> srav + case 0x00000002: newop = 0x00000006; break; // srl -> srlv + default: + uerror ("bad shift amount"); + return; + } + newop |= opcode & (0x3ff << 11); /* set 1-st and 2-nd regs */ + newop |= cval << 21; /* set 3-rd register */ + opcode = newop; + type = FRD1 | FRT2 | FRS3 | FMOD; + goto done3; + } + ungetlex (clex, cval); + } + if ((type & FCODE) && (type & FRT2)) { + /* Optional code for trap instruction. */ + clex = getlex (&cval); + if (clex != ',') { + ungetlex (clex, cval); + goto done; + } + } +fsa: offset = getexpr (&segment); + if (segment != SABS) + uerror ("absolute value required"); + switch (type & (FCODE | FCODE16 | FSA)) { + case FCODE: /* immediate shifted <<6 */ + opcode |= offset << 6; + break; + case FCODE16: /* immediate shifted <<16 */ + opcode |= offset << 16; + break; + case FSA: /* shift amount */ + opcode |= (offset & 0x1f) << 6; + break; + } + } else if (type & (FOFF16 | FOFF18 | FAOFF18 | FAOFF28 | FHIGH16)) { + /* Relocatable offset */ + if ((type & (FOFF16 | FOFF18 | FHIGH16)) && getlex (&cval) != ',') + uerror ("comma expected"); +foff16: expr_flags = 0; + offset = getexpr (&segment); + relinfo.flags = segmrel [segment]; + if (negate_literal) { + // Negate literal arg for sub and subu + offset = -offset; + if (relinfo.flags != RABS) + uerror ("cannot negate relocatable literal"); + } + if (relinfo.flags == REXT) + relinfo.index = extref; + if (expr_flags & EXPR_GPREL) + relinfo.flags |= RGPREL; + switch (type & (FOFF16 | FOFF18 | FAOFF18 | FAOFF28 | FHIGH16)) { + case FOFF16: /* low 16-bit byte address */ + opcode |= offset & 0xffff; + break; + case FHIGH16: /* high 16-bit byte address */ + if (relinfo.flags != RABS) { + /* %hi function - assume signed offset */ + relinfo.flags |= (expr_flags & EXPR_HI) ? RHIGH16S : RHIGH16; + relinfo.offset = offset & 0xffff; + offset += 0x8000; + } + opcode |= offset >> 16; + break; + case FOFF18: /* 18-bit PC-relative word address */ + case FAOFF18: + if (segment == segm) { + offset -= count[segm] + 4; + relinfo.flags = RABS; + } else if (segment == SEXT) { + relinfo.flags |= RWORD16; + } else + uerror ("invalid segment %d", segment); + opcode |= (offset >> 2) & 0xffff; + break; + case FAOFF28: /* 28-bit word address */ + opcode |= (offset >> 2) & 0x3ffffff; + relinfo.flags |= RWORD26; + break; + } + } + + /* + * Last argument. + */ + if (type & FRSB) { + if (getlex (&cval) != '(') + uerror ("left par expected"); + clex = getlex (&cval); + if (clex != LREG) + uerror ("bad rs register"); + if (getlex (&cval) != ')') + uerror ("right par expected"); + opcode |= cval << 21; /* ... (rs) */ + } + if (type & FSIZE) { + if (getlex (&cval) != ',') + uerror ("comma expected"); + offset = getexpr (&segment); + if (segment != SABS) + uerror ("absolute value required"); + opcode |= ((offset - 1) & 0x1f) << 11; /* bit field size */ + } + if (type & FMSB) { + if (getlex (&cval) != ',') + uerror ("comma expected"); + offset += getexpr (&segment); + if (segment != SABS) + uerror ("absolute value required"); + if (offset > 32) + offset = 32; + opcode |= ((offset - 1) & 0x1f) << 11; /* msb */ + } +done: + + /* Output resulting values. */ + if (emitfunc) { + emitfunc (opcode, &relinfo); + } else if (mode_reorder && (type & FDSLOT) && segm == STEXT) { + /* Need a delay slot. */ + if (reorder_full && reorder_clobber != 0) { + /* Analyse register dependency. + * Flush the instruction if needed. */ + int rt = (opcode >> 16) & 31; + int rs = (opcode >> 21) & 31; + if (((type & (FRS1 | FRS2)) && rs == reorder_clobber) || + ((type & FRT2) && rt == reorder_clobber)) + reorder_flush(); + } + fputword (opcode, sfile[segm]); + fputrel (&relinfo, rfile[segm]); + if (reorder_full) { + /* Delay slot: insert a previous instruction. */ + reorder_flush(); + } else { + /* Insert NOP in delay slot. */ + fputword (0, sfile[segm]); + fputrel (&relabs, rfile[segm]); + count[segm] += WORDSZ; + } + count[segm] += WORDSZ; + } else { + emitword (opcode, &relinfo, clobber_reg); + } +} + +/* + * Increment the current segment by nbytes. + * Emit a needed amount of zeroes to sfile and rfile. + * Part of data have already been sent to rfile; + * length specified by 'done' argument. + */ +void add_space (nbytes, fill_data) + unsigned nbytes, fill_data; +{ + unsigned c; + + if (segm < SBSS) { + /* Emit data and relocation. */ + for (c=0; c='0' && c<='7') { + cval = (cval << 3) | (c & 7); + c = getchar (); + if (c>='0' && c<='7') { + cval = (cval << 3) | (c & 7); + } else + ungetc (c, stdin); + } else + ungetc (c, stdin); + c = cval; + break; + case 't': + c = '\t'; + break; + case 'b': + c = '\b'; + break; + case 'r': + c = '\r'; + break; + case 'n': + c = '\n'; + break; + case 'f': + c = '\f'; + break; + } + default: + fputc (c, sfile[segm]); + nbytes++; + continue; + } + break; + } + add_space (nbytes, 0); +} + +/* + * Skip a string from the input file. + */ +void skipstring () +{ + int c, cval; + + c = getlex (&cval); + if (c != '"') + uerror ("no string parameter"); + for (;;) { + c = getchar (); + switch (c) { + case EOF: + uerror ("EOF in text string"); + case '"': + break; + case '\\': + c = getchar (); + switch (c) { + case EOF: + uerror ("EOF in text string"); + case '\n': + continue; + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + c = getchar (); + if (c>='0' && c<='7') { + c = getchar (); + if (c>='0' && c<='7') { + } else + ungetc (c, stdin); + } else + ungetc (c, stdin); + break; + } + default: + continue; + } + break; + } +} + +/* + * Set assembler option. + */ +void setoption () +{ + const char *option = name; + int enable = 1; + + if (option[0] == 'n' && option[1] == 'o') { + enable = 0; + option += 2; + } + if (! strcmp ("reorder", option)) { + /* reorder mode */ + mode_reorder = enable; + if (! mode_reorder) + reorder_flush(); + return; + } + if (! strcmp ("macro", option)) { + /* macro mode */ + mode_macro = enable; + return; + } + if (! strcmp ("mips16", option)) { + /* mips16 mode */ + mode_mips16 = enable; + return; + } + if (! strcmp ("micromips", option)) { + /* micromips mode */ + mode_micromips = enable; + return; + } + if (! strcmp ("at", option)) { + /* at mode */ + mode_at = enable; + return; + } + uerror ("unknown option %s", option); +} + +/* + * Align the current segment. + */ +void align (align_bits) +{ + unsigned nbytes, align_mask, c; + + align_mask = (1 << align_bits) - 1; + nbytes = count[segm] & align_mask; + if (nbytes == 0) + return; + nbytes = align_mask + 1 - nbytes; + if (segm < SBSS) { + /* Emit data and relocation. */ + for (c=0; c= MAXRLAB) + uerror ("too many digital labels"); + reorder_flush(); + labeltab[nlabels].num = intval; + labeltab[nlabels].value = count[segm]; + ++nlabels; + clex = getlex (&tval); + if (clex != ':') + uerror ("bad digital label"); + continue; + case LTEXT: + segm = STEXT; + reorder_flush(); + break; + case LDATA: + segm = SDATA; + break; + case LSTRNG: + case LRDATA: + segm = SSTRNG; + break; + case LBSS: + segm = SBSS; + break; + case LWORD: + reorder_flush(); + align (2); + for (;;) { + struct reloc relinfo; + expr_flags = 0; + getexpr (&cval); + relinfo.flags = RBYTE32 | segmrel [cval]; + if (cval == SEXT) + relinfo.index = extref; + if (expr_flags & EXPR_GPREL) + relinfo.flags |= RGPREL; + emitword (intval, &relinfo, 0); + clex = getlex (&cval); + if (clex != ',') { + ungetlex (clex, cval); + break; + } + } + break; + case LBYTE: + reorder_flush(); + nbytes = 0; + for (;;) { + getexpr (&cval); + fputc (intval, sfile[segm]); + nbytes++; + clex = getlex (&cval); + if (clex != ',') { + ungetlex (clex, cval); + break; + } + } + add_space (nbytes, 0); + break; + case LHALF: + reorder_flush(); + align (1); + nbytes = 0; + for (;;) { + getexpr (&cval); + fputc (intval, sfile[segm]); + fputc (intval >> 8, sfile[segm]); + nbytes += 2; + clex = getlex (&cval); + if (clex != ',') { + ungetlex (clex, cval); + break; + } + } + add_space (nbytes, 0); + break; + case LSPACE: + /* .space num */ + getexpr (&cval); + reorder_flush(); + add_space (intval, 1); + break; + case LALIGN: + /* .align num */ + if (getlex (&cval) != LNUM) + uerror ("bad parameter of .align"); + reorder_flush(); + align (intval); + break; + case LASCII: + reorder_flush(); + makeascii (); + break; + case LGLOBL: + /* .globl name, ... */ + for (;;) { + clex = getlex (&cval); + if (clex != LNAME) + uerror ("bad parameter of .globl"); + cval = lookname(); + if (stab[cval].n_type & N_LOC) + uerror ("local name redefined as global"); + stab[cval].n_type |= N_EXT; + clex = getlex (&cval); + if (clex != ',') { + ungetlex (clex, cval); + break; + } + } + break; + case LLOCAL: + /* .local name, ... */ + for (;;) { + clex = getlex (&cval); + if (clex != LNAME) + uerror ("bad parameter of .local"); + cval = lookname(); + if (stab[cval].n_type & N_EXT) + uerror ("global name redefined as local"); + stab[cval].n_type |= N_LOC; + clex = getlex (&cval); + if (clex != ',') { + ungetlex (clex, cval); + break; + } + } + break; + case LWEAK: + /* .weak name */ + for (;;) { + clex = getlex (&cval); + if (clex != LNAME) + uerror ("bad parameter of .weak"); + cval = lookname(); + stab[cval].n_type |= N_WEAK; + clex = getlex (&cval); + if (clex != ',') { + ungetlex (clex, cval); + break; + } + } + break; + case LCOMM: + /* .comm name,len */ + if (getlex (&cval) != LNAME) + uerror ("bad parameter of .comm"); + cval = lookname(); + if (stab[cval].n_type != N_UNDF && + stab[cval].n_type != N_LOC && + (stab[cval].n_type & N_TYPE) != N_COMM) + uerror ("name already defined"); + if (stab[cval].n_type & N_LOC) + stab[cval].n_type = N_COMM; + else + stab[cval].n_type = N_EXT | N_COMM; + clex = getlex (&tval); + if (clex == ',') { + getexpr (&tval); + if (tval != SABS) + uerror ("bad length of .comm"); + } else { + ungetlex (clex, cval); + intval = 1; + } + stab[cval].n_value = intval; + clex = getlex (&cval); + if (clex != ',') { + ungetlex (clex, cval); + break; + } + getexpr (&tval); + if (tval != SABS) + uerror ("bad .comm alignment"); + break; + case LFILE: + /* .file line filename */ + if (getlex (&cval) != LNUM) + uerror ("bad parameter of .file"); + skipstring(); + break; + case LIDENT: + /* .ident string */ + skipstring(); + break; + case LSECTION: + /* .section name[,"flags"[,type[,entsize]]] */ + clex = getlex (&cval); + if (clex != LNAME && clex != LBSS) + uerror ("bad name of .section"); + setsection(); + clex = getlex (&cval); + if (clex != ',') { + ungetlex (clex, cval); + break; + } + skipstring(); + clex = getlex (&cval); + if (clex != ',') { + ungetlex (clex, cval); + break; + } + if (getlex (&cval) != LSECTYPE) + uerror ("bad type of .section"); + clex = getlex (&cval); + if (clex != ',') { + ungetlex (clex, cval); + break; + } + if (getlex (&cval) != LNUM) + uerror ("bad entry size of .section"); + break; + case LPREVIOUS: + /* .previous - ignore */ + break; + case LGNUATTR: + /* .gnu_attribute num[,num] */ + if (getlex (&cval) != LNUM) + uerror ("bad parameter of .gnu_attribute"); + clex = getlex (&cval); + if (clex != ',' || getlex (&cval) != LNUM) + uerror ("bad parameter of .gnu_attribute"); + break; + case LSET: + /* .set option */ + if (getlex (&cval) != LNAME) + uerror ("bad parameter of .set"); + setoption(); + break; + case LENT: + /* .ent name */ + clex = getlex (&cval); + if (clex != LNAME) + uerror ("bad parameter of .ent"); + cval = lookname(); + break; + case LEND: + /* .end name */ + clex = getlex (&cval); + if (clex != LNAME) + uerror ("bad parameter of .end"); + cval = lookname(); + break; + case LTYPE: + /* .type name,type */ + if (getlex (&cval) != LNAME) + uerror ("bad name of .type"); + clex = getlex (&cval); + if (clex != ',') { + ungetlex (clex, cval); + break; + } + if (getlex (&cval) != LSYMTYPE) + uerror ("bad type of .type"); + break; + case LFRAME: + /* .frame reg,num,reg */ + if (getlex (&cval) != LREG) + uerror ("bad register of .frame"); + clex = getlex (&cval); + if (clex != ',' || getlex (&cval) != LNUM) + uerror ("bad parameter of .frame"); + clex = getlex (&cval); + if (clex != ',' || getlex (&cval) != LREG) + uerror ("bad register of .frame"); + break; + case LMASK: + /* .mask mask,expr */ + if (getlex (&cval) != LNUM) + uerror ("bad mask of .mask"); + clex = getlex (&cval); + if (clex != ',') + uerror ("bad parameter of .mask"); + getexpr (&cval); + if (cval != SABS) + uerror ("bad expression of .mask"); + break; + case LFMASK: + /* .fmask mask,expr */ + if (getlex (&cval) != LNUM) + uerror ("bad mask of .fmask"); + clex = getlex (&cval); + if (clex != ',') + uerror ("bad parameter of .fmask"); + getexpr (&cval); + if (cval != SABS) + uerror ("bad expression of .fmask"); + break; + case LSIZE: + /* .size name,expr */ + if (getlex (&cval) != LNAME) + uerror ("bad name of .size"); + clex = getlex (&cval); + if (clex != ',') { + ungetlex (clex, cval); + break; + } + nbytes = getexpr (&csegm); + if (csegm != SABS) + uerror ("bad value of .size"); + break; + default: + uerror ("bad syntax"); + } + clex = getlex (&cval); + if (clex != LEOL) { + if (clex == LEOF) + return; + uerror ("bad instruction arguments"); + } + } +} + +/* + * Find the relative label address, + * by the reference address and the label number. + * Backward references have negative label numbers. + */ +int findlabel (int addr, int sym) +{ + struct labeltab *p; + + if (sym < 0) { + /* Backward reference. */ + for (p=labeltab+nlabels-1; p>=labeltab; --p) { + if (p->value <= addr && p->num == -sym) { + return p->value; + } + } + uerror ("undefined label %db at address %d", -sym, addr); + } else { + /* Forward reference. */ + for (p=labeltab; pvalue > addr && p->num == sym) { + return p->value; + } + } + uerror ("undefined label %df at address %d", sym, addr); + } + return 0; +} + +void middle () +{ + register int i, snum; + + stlength = 0; + for (snum=0, i=0; iflags & RFMASK) { + case RBYTE32: /* 32 bits of byte address */ + opcode += offset; + break; + case RBYTE16: /* low 16 bits of byte address */ + offset += opcode & 0xffff; + opcode &= ~0xffff; + opcode |= offset & 0xffff; + break; + case RHIGH16: /* high 16 bits of byte address */ + offset += (opcode & 0xffff) << 16; + offset += relinfo->offset; + opcode &= ~0xffff; + opcode |= (offset >> 16) & 0xffff; + relinfo->offset = offset & 0xffff; + break; + case RHIGH16S: /* high 16 bits of byte address */ + offset += (opcode & 0xffff) << 16; + offset += (signed short) relinfo->offset; + opcode &= ~0xffff; + opcode |= ((offset + 0x8000) >> 16) & 0xffff; + relinfo->offset = offset & 0xffff; + break; + case RWORD16: /* 16 bits of relative word address */ + uerror ("bad relative relocation: opcode %08x, relinfo %02x", opcode, relinfo->flags); + break; + case RWORD26: /* 26 bits of word address */ + offset += (opcode & 0x3ffffff) << 2; + opcode &= ~0x3ffffff; + opcode |= (offset >> 2) & 0x3ffffff; + break; + } + return (opcode); +} + +unsigned makeword (opcode, relinfo, offset) + register unsigned opcode, offset; + register struct reloc *relinfo; +{ + struct nlist *sym; + unsigned value; + + switch (relinfo->flags & RSMASK) { + case RABS: + break; + case RTEXT: + opcode = relocate (opcode, tbase, relinfo); + break; + case RDATA: + opcode = relocate (opcode, dbase, relinfo); + break; + case RSTRNG: + opcode = relocate (opcode, adbase, relinfo); + break; + case RBSS: + opcode = relocate (opcode, bbase, relinfo); + break; + case REXT: + if (relinfo->index >= RLAB_OFFSET - RLAB_MAXVAL) { + /* Relative label. + * Change relocation to segment type. */ + sym = 0; + value = findlabel (offset, relinfo->index - RLAB_OFFSET); + relinfo->flags &= RGPREL | RFMASK; + relinfo->flags |= segmrel[segm]; + } else { + /* Symbol name. */ + sym = &stab[relinfo->index]; + if (sym->n_type == N_EXT+N_UNDF || sym->n_type == N_EXT+N_COMM) + return opcode; + value = sym->n_value; + } + + switch (relinfo->flags & RFMASK) { + case RWORD16: + /* Relative word address. + * Change relocation to absolute. */ + if (sym && (sym->n_type & N_TYPE) != segmtype[segm]) + uerror ("%s: bad segment for relative relocation, offset %u", + sym->n_name, offset); + offset = value - offset - 4; + if (segm == SDATA) + offset -= dbase; + else if (segm == SSTRNG) + offset -= adbase; + offset += (opcode & 0xffff) << 2; + opcode &= ~0xffff; + opcode |= (offset >> 2) & 0xffff; + relinfo->flags = RABS; + return opcode; + case RHIGH16: + value += relinfo->offset; + break; + case RHIGH16S: + value += (signed short) relinfo->offset; + break; + } + opcode = relocate (opcode, value, relinfo); + break; + } + return opcode; +} + +void pass2 () +{ + register int i; + register unsigned h; + + tbase = 0; + dbase = tbase + count[STEXT]; + adbase = dbase + count[SDATA]; + bbase = adbase + count[SSTRNG]; + + /* Adjust indexes in symbol name */ + for (i=0; iflags & REXT) { + case RSTRNG: + relinfo->flags &= ~RSMASK; + relinfo->flags |= RDATA; + break; + case REXT: + type = stab[relinfo->index].n_type; + if (type == N_EXT+N_UNDF || type == N_EXT+N_COMM) + { + /* Reindexing */ + if (xflags) + relinfo->index = newindex [relinfo->index]; + } else { + relinfo->flags &= ~RSMASK; + relinfo->flags |= typerel (type); + } + break; + } +} + +/* + * Emit a relocation info for a given segment. + * Copy it from scratch file to output. + * Return a size of relocation data in bytes. + */ +unsigned makereloc (s) + register int s; +{ + register unsigned i, nbytes; + struct reloc relinfo; + + if (count [s] <= 0) + return 0; + rewind (rfile [s]); + nbytes = 0; + for (i=0; i +#else +# include +#endif +#include +#include +#include "mips-opcode.h" +#include "mips-opc.c" + +/* FIXME: These are needed to figure out if the code is mips16 or + not. The low bit of the address is often a good indicator. No + symbol table is available when this code runs out in an embedded + system as when it is used for disassembler support in a monitor. */ + +/* Mips instructions are at maximum this many bytes long. */ +#define INSNLEN 4 + +struct mips_cp0sel_name { + unsigned int cp0reg; + unsigned int sel; + const char *const name; +}; + +static const char *const mips_gpr_names[32] = { + "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3", + "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", + "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", + "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra" +}; + +static const char *const mips_fpr_names[32] = { + "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7", + "$f8", "$f9", "$f10", "$f11", "$f12", "$f13", "$f14", "$f15", + "$f16", "$f17", "$f18", "$f19", "$f20", "$f21", "$f22", "$f23", + "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "$f31" +}; + +static const char *const mips_cp0_names[32] = { + "c0_index", "c0_random", "c0_entrylo0", "c0_entrylo1", + "c0_context", "c0_pagemask", "c0_wired", "c0_hwrena", + "c0_badvaddr", "c0_count", "c0_entryhi", "c0_compare", + "c0_status", "c0_cause", "c0_epc", "c0_prid", + "c0_config", "c0_lladdr", "c0_watchlo", "c0_watchhi", + "c0_xcontext", "$21", "$22", "c0_debug", + "c0_depc", "c0_perfcnt", "c0_errctl", "c0_cacheerr", + "c0_taglo", "c0_taghi", "c0_errorepc", "c0_desave", +}; + +static const struct mips_cp0sel_name mips_cp0sel_names[] = { + {4, 1, "c0_contextconfig"}, + {0, 1, "c0_mvpcontrol"}, + {0, 2, "c0_mvpconf0"}, + {0, 3, "c0_mvpconf1"}, + {1, 1, "c0_vpecontrol"}, + {1, 2, "c0_vpeconf0"}, + {1, 3, "c0_vpeconf1"}, + {1, 4, "c0_yqmask"}, + {1, 5, "c0_vpeschedule"}, + {1, 6, "c0_vpeschefback"}, + {2, 1, "c0_tcstatus"}, + {2, 2, "c0_tcbind"}, + {2, 3, "c0_tcrestart"}, + {2, 4, "c0_tchalt"}, + {2, 5, "c0_tccontext"}, + {2, 6, "c0_tcschedule"}, + {2, 7, "c0_tcschefback"}, + {5, 1, "c0_pagegrain"}, + {6, 1, "c0_srsconf0"}, + {6, 2, "c0_srsconf1"}, + {6, 3, "c0_srsconf2"}, + {6, 4, "c0_srsconf3"}, + {6, 5, "c0_srsconf4"}, + {12, 1, "c0_intctl"}, + {12, 2, "c0_srsctl"}, + {12, 3, "c0_srsmap"}, + {15, 1, "c0_ebase"}, + {16, 1, "c0_config1"}, + {16, 2, "c0_config2"}, + {16, 3, "c0_config3"}, + {18, 1, "c0_watchlo,1"}, + {18, 2, "c0_watchlo,2"}, + {18, 3, "c0_watchlo,3"}, + {18, 4, "c0_watchlo,4"}, + {18, 5, "c0_watchlo,5"}, + {18, 6, "c0_watchlo,6"}, + {18, 7, "c0_watchlo,7"}, + {19, 1, "c0_watchhi,1"}, + {19, 2, "c0_watchhi,2"}, + {19, 3, "c0_watchhi,3"}, + {19, 4, "c0_watchhi,4"}, + {19, 5, "c0_watchhi,5"}, + {19, 6, "c0_watchhi,6"}, + {19, 7, "c0_watchhi,7"}, + {23, 1, "c0_tracecontrol"}, + {23, 2, "c0_tracecontrol2"}, + {23, 3, "c0_usertracedata"}, + {23, 4, "c0_tracebpc"}, + {25, 1, "c0_perfcnt,1"}, + {25, 2, "c0_perfcnt,2"}, + {25, 3, "c0_perfcnt,3"}, + {25, 4, "c0_perfcnt,4"}, + {25, 5, "c0_perfcnt,5"}, + {25, 6, "c0_perfcnt,6"}, + {25, 7, "c0_perfcnt,7"}, + {27, 1, "c0_cacheerr,1"}, + {27, 2, "c0_cacheerr,2"}, + {27, 3, "c0_cacheerr,3"}, + {28, 1, "c0_datalo"}, + {28, 2, "c0_taglo1"}, + {28, 3, "c0_datalo1"}, + {28, 4, "c0_taglo2"}, + {28, 5, "c0_datalo2"}, + {28, 6, "c0_taglo3"}, + {28, 7, "c0_datalo3"}, + {29, 1, "c0_datahi"}, + {29, 2, "c0_taghi1"}, + {29, 3, "c0_datahi1"}, + {29, 4, "c0_taghi2"}, + {29, 5, "c0_datahi2"}, + {29, 6, "c0_taghi3"}, + {29, 7, "c0_datahi3"}, +}; +static const int mips_cp0sel_names_len = sizeof (mips_cp0sel_names) / sizeof (*mips_cp0sel_names); + +static const char *const mips_hwr_names[32] = { + "$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" +}; + +/* + * If set disassemble as most general inst. + */ +static int no_aliases = 0; + +static int branch_delay_insns; +static int data_size; +static unsigned target; + +enum dis_insn_type { + dis_noninsn, /* Not a valid instruction. */ + dis_nonbranch, /* Not a branch instruction. */ + dis_branch, /* Unconditional branch. */ + dis_condbranch, /* Conditional branch. */ + dis_jsr, /* Jump to subroutine. */ + dis_condjsr, /* Conditional jump to subroutine. */ + dis_dref, /* Data reference instruction. */ + dis_dref2 /* Two data references in instruction. */ +}; + +static enum dis_insn_type insn_type; + +#if 0 +/* + * Get LENGTH bytes from info's buffer, at target address memaddr. + * Transfer them to myaddr. + */ +int +read_memory (unsigned memaddr, + unsigned char *myaddr, + unsigned int nbytes) +{ + //unsigned char *buffer; + //unsigned int buffer_length; + //unsigned int buffer_vma; + + if (memaddr < buffer_vma || + memaddr - buffer_vma > buffer_length || + memaddr - buffer_vma + nbytes > buffer_length) { + /* Out of bounds. Use EIO because GDB uses it. */ + return EIO; + } + memcpy (myaddr, info->buffer + memaddr - buffer_vma, nbytes); + return 0; +} +#endif + +static void +print_address (unsigned address, FILE *stream) +{ + if (address < 16) + fprintf (stream, "%d", address); + else + fprintf (stream, "0x%x", address); +} + +static const struct mips_cp0sel_name * +lookup_mips_cp0sel_name (const struct + mips_cp0sel_name *names, unsigned int len, unsigned int cp0reg, + unsigned int sel) +{ + unsigned int i; + + for (i = 0; i < len; i++) + if (names[i].cp0reg == cp0reg && names[i].sel == sel) + return &names[i]; + return NULL; +} + +/* Print insn arguments for 32/64-bit code. */ + +static void +print_insn_args (const char *d, + register unsigned long int l, + unsigned pc, FILE *stream, const struct mips_opcode *opp) +{ + int op, delta; + unsigned int lsb, msb, msbd; + + lsb = 0; + + for (; *d != '\0'; d++) { + switch (*d) { + case ',': + case '(': + case ')': + case '[': + case ']': + fprintf (stream, "%c", *d); + break; + + case '+': + /* Extension character; switch for second char. */ + d++; + switch (*d) { + case '\0': + /* xgettext:c-format */ + fprintf (stream, + "# internal error, incomplete extension sequence (+)"); + return; + + case 'A': + lsb = (l >> OP_SH_SHAMT) & OP_MASK_SHAMT; + fprintf (stream, "0x%x", lsb); + break; + + case 'B': + msb = (l >> OP_SH_INSMSB) & OP_MASK_INSMSB; + fprintf (stream, "0x%x", msb - lsb + 1); + break; + + case '1': + fprintf (stream, "0x%lx", + (l >> OP_SH_UDI1) & OP_MASK_UDI1); + break; + + case '2': + fprintf (stream, "0x%lx", + (l >> OP_SH_UDI2) & OP_MASK_UDI2); + break; + + case '3': + fprintf (stream, "0x%lx", + (l >> OP_SH_UDI3) & OP_MASK_UDI3); + break; + + case '4': + fprintf (stream, "0x%lx", + (l >> OP_SH_UDI4) & OP_MASK_UDI4); + break; + + case 'C': + case 'H': + msbd = (l >> OP_SH_EXTMSBD) & OP_MASK_EXTMSBD; + fprintf (stream, "0x%x", msbd + 1); + break; + + case 'D': + { + const struct mips_cp0sel_name *n; + unsigned int cp0reg, sel; + + cp0reg = (l >> OP_SH_RD) & OP_MASK_RD; + sel = (l >> OP_SH_SEL) & OP_MASK_SEL; + + /* CP0 register including 'sel' code for mtcN (et al.), to be + * printed textually if known. If not known, print both + * CP0 register name and sel numerically since CP0 register + * with sel 0 may have a name unrelated to register being + * printed. */ + n = lookup_mips_cp0sel_name (mips_cp0sel_names, + mips_cp0sel_names_len, cp0reg, sel); + if (n != NULL) + fprintf (stream, "%s", n->name); + else + fprintf (stream, "$%d,%d", cp0reg, + sel); + break; + } + + case 'E': + lsb = ((l >> OP_SH_SHAMT) & OP_MASK_SHAMT) + 32; + fprintf (stream, "0x%x", lsb); + break; + + case 'F': + msb = ((l >> OP_SH_INSMSB) & OP_MASK_INSMSB) + 32; + fprintf (stream, "0x%x", msb - lsb + 1); + break; + + case 'G': + msbd = ((l >> OP_SH_EXTMSBD) & OP_MASK_EXTMSBD) + 32; + fprintf (stream, "0x%x", msbd + 1); + break; + + case 't': /* Coprocessor 0 reg name */ + fprintf (stream, "%s", + mips_cp0_names[(l >> OP_SH_RT) & OP_MASK_RT]); + break; + + case 'T': /* Coprocessor 0 reg name */ + { + const struct mips_cp0sel_name *n; + unsigned int cp0reg, sel; + + cp0reg = (l >> OP_SH_RT) & OP_MASK_RT; + sel = (l >> OP_SH_SEL) & OP_MASK_SEL; + + /* CP0 register including 'sel' code for mftc0, to be + * printed textually if known. If not known, print both + * CP0 register name and sel numerically since CP0 register + * with sel 0 may have a name unrelated to register being + * printed. */ + n = lookup_mips_cp0sel_name (mips_cp0sel_names, + mips_cp0sel_names_len, cp0reg, sel); + if (n != NULL) + fprintf (stream, "%s", n->name); + else + fprintf (stream, "$%d,%d", cp0reg, + sel); + break; + } + + case 'x': /* bbit bit index */ + fprintf (stream, "0x%lx", + (l >> OP_SH_BBITIND) & OP_MASK_BBITIND); + break; + + case 'p': /* cins, cins32, exts and exts32 position */ + fprintf (stream, "0x%lx", + (l >> OP_SH_CINSPOS) & OP_MASK_CINSPOS); + break; + + case 's': /* cins and exts length-minus-one */ + fprintf (stream, "0x%lx", + (l >> OP_SH_CINSLM1) & OP_MASK_CINSLM1); + break; + + case 'S': /* cins32 and exts32 length-minus-one field */ + fprintf (stream, "0x%lx", + (l >> OP_SH_CINSLM1) & OP_MASK_CINSLM1); + break; + + case 'Q': /* seqi/snei immediate field */ + op = (l >> OP_SH_SEQI) & OP_MASK_SEQI; + /* Sign-extend it. */ + op = (op ^ 512) - 512; + fprintf (stream, "%d", op); + break; + + default: + /* xgettext:c-format */ + fprintf (stream, "# internal error, undefined extension sequence (+%c)", *d); + return; + } + break; + + case '2': + fprintf (stream, "0x%lx", + (l >> OP_SH_BP) & OP_MASK_BP); + break; + + case '3': + fprintf (stream, "0x%lx", + (l >> OP_SH_SA3) & OP_MASK_SA3); + break; + + case '4': + fprintf (stream, "0x%lx", + (l >> OP_SH_SA4) & OP_MASK_SA4); + break; + + case '5': + fprintf (stream, "0x%lx", + (l >> OP_SH_IMM8) & OP_MASK_IMM8); + break; + + case '6': + fprintf (stream, "0x%lx", + (l >> OP_SH_RS) & OP_MASK_RS); + break; + + case '7': + fprintf (stream, "$ac%ld", + (l >> OP_SH_DSPACC) & OP_MASK_DSPACC); + break; + + case '8': + fprintf (stream, "0x%lx", + (l >> OP_SH_WRDSP) & OP_MASK_WRDSP); + break; + + case '9': + fprintf (stream, "$ac%ld", + (l >> OP_SH_DSPACC_S) & OP_MASK_DSPACC_S); + break; + + case '0': /* dsp 6-bit signed immediate in bit 20 */ + delta = ((l >> OP_SH_DSPSFT) & OP_MASK_DSPSFT); + if (delta & 0x20) /* test sign bit */ + delta |= ~OP_MASK_DSPSFT; + fprintf (stream, "%d", delta); + break; + + case ':': /* dsp 7-bit signed immediate in bit 19 */ + delta = ((l >> OP_SH_DSPSFT_7) & OP_MASK_DSPSFT_7); + if (delta & 0x40) /* test sign bit */ + delta |= ~OP_MASK_DSPSFT_7; + fprintf (stream, "%d", delta); + break; + + case '\'': + fprintf (stream, "0x%lx", + (l >> OP_SH_RDDSP) & OP_MASK_RDDSP); + break; + + case '@': /* dsp 10-bit signed immediate in bit 16 */ + delta = ((l >> OP_SH_IMM10) & OP_MASK_IMM10); + if (delta & 0x200) /* test sign bit */ + delta |= ~OP_MASK_IMM10; + fprintf (stream, "%d", delta); + break; + + case '!': + fprintf (stream, "%ld", + (l >> OP_SH_MT_U) & OP_MASK_MT_U); + break; + + case '$': + fprintf (stream, "%ld", + (l >> OP_SH_MT_H) & OP_MASK_MT_H); + break; + + case '*': + fprintf (stream, "$ac%ld", + (l >> OP_SH_MTACC_T) & OP_MASK_MTACC_T); + break; + + case '&': + fprintf (stream, "$ac%ld", + (l >> OP_SH_MTACC_D) & OP_MASK_MTACC_D); + break; + + case 'g': + /* Coprocessor register for CTTC1, MTTC2, MTHC2, CTTC2. */ + fprintf (stream, "$%ld", + (l >> OP_SH_RD) & OP_MASK_RD); + break; + + case 's': + case 'b': + case 'r': + case 'v': + fprintf (stream, "%s", + mips_gpr_names[(l >> OP_SH_RS) & OP_MASK_RS]); + break; + + case 't': + case 'w': + fprintf (stream, "%s", + mips_gpr_names[(l >> OP_SH_RT) & OP_MASK_RT]); + break; + + case 'i': + case 'u': + fprintf (stream, "0x%lx", + (l >> OP_SH_IMMEDIATE) & OP_MASK_IMMEDIATE); + break; + + case 'j': /* Same as i, but sign-extended. */ + case 'o': + delta = (l >> OP_SH_DELTA) & OP_MASK_DELTA; + if (delta & 0x8000) + delta |= ~0xffff; + fprintf (stream, "%d", delta); + break; + + case 'h': + fprintf (stream, "0x%x", + (unsigned int) ((l >> OP_SH_PREFX) + & OP_MASK_PREFX)); + break; + + case 'k': + fprintf (stream, "0x%x", + (unsigned int) ((l >> OP_SH_CACHE) + & OP_MASK_CACHE)); + break; + + case 'a': + target = (((pc + 4) & ~(unsigned) 0x0fffffff) + | (((l >> OP_SH_TARGET) & OP_MASK_TARGET) << 2)); + /* For gdb disassembler, force odd address on jalx. */ + if (strcmp (opp->name, "jalx") == 0) + target |= 1; + print_address (target, stream); + break; + + case 'p': + /* Sign extend the displacement. */ + delta = (l >> OP_SH_DELTA) & OP_MASK_DELTA; + if (delta & 0x8000) + delta |= ~0xffff; + target = (delta << 2) + pc + INSNLEN; + print_address (target, stream); + break; + + case 'd': + fprintf (stream, "%s", + mips_gpr_names[(l >> OP_SH_RD) & OP_MASK_RD]); + break; + + case 'U': + { + /* First check for both rd and rt being equal. */ + unsigned int reg = (l >> OP_SH_RD) & OP_MASK_RD; + if (reg == ((l >> OP_SH_RT) & OP_MASK_RT)) + fprintf (stream, "%s", + mips_gpr_names[reg]); + else { + /* If one is zero use the other. */ + if (reg == 0) + fprintf (stream, "%s", + mips_gpr_names[(l >> OP_SH_RT) & OP_MASK_RT]); + else if (((l >> OP_SH_RT) & OP_MASK_RT) == 0) + fprintf (stream, "%s", + mips_gpr_names[reg]); + else /* Bogus, result depends on processor. */ + fprintf (stream, "%s or %s", + mips_gpr_names[reg], + mips_gpr_names[(l >> OP_SH_RT) & OP_MASK_RT]); + } + } + break; + + case 'z': + fprintf (stream, "%s", mips_gpr_names[0]); + break; + + case '<': + case '1': + fprintf (stream, "0x%lx", + (l >> OP_SH_SHAMT) & OP_MASK_SHAMT); + break; + + case 'c': + fprintf (stream, "0x%lx", + (l >> OP_SH_CODE) & OP_MASK_CODE); + break; + + case 'q': + fprintf (stream, "0x%lx", + (l >> OP_SH_CODE2) & OP_MASK_CODE2); + break; + + case 'C': + fprintf (stream, "0x%lx", + (l >> OP_SH_COPZ) & OP_MASK_COPZ); + break; + + case 'B': + fprintf (stream, "0x%lx", + (l >> OP_SH_CODE20) & OP_MASK_CODE20); + break; + + case 'J': + fprintf (stream, "0x%lx", + (l >> OP_SH_CODE19) & OP_MASK_CODE19); + break; + + case 'S': + case 'V': + fprintf (stream, "%s", + mips_fpr_names[(l >> OP_SH_FS) & OP_MASK_FS]); + break; + + case 'T': + case 'W': + fprintf (stream, "%s", + mips_fpr_names[(l >> OP_SH_FT) & OP_MASK_FT]); + break; + + case 'D': + fprintf (stream, "%s", + mips_fpr_names[(l >> OP_SH_FD) & OP_MASK_FD]); + break; + + case 'R': + fprintf (stream, "%s", + mips_fpr_names[(l >> OP_SH_FR) & OP_MASK_FR]); + break; + + case 'E': + /* Coprocessor register for lwcN instructions, et al. + * + * Note that there is no load/store cp0 instructions, and + * that FPU (cp1) instructions disassemble this field using + * 'T' format. Therefore, until we gain understanding of + * cp2 register names, we can simply print the register + * numbers. */ + fprintf (stream, "$%ld", + (l >> OP_SH_RT) & OP_MASK_RT); + break; + + case 'G': + /* Coprocessor register for mtcN instructions, et al. Note + * that FPU (cp1) instructions disassemble this field using + * 'S' format. Therefore, we only need to worry about cp0, + * cp2, and cp3. */ + op = (l >> OP_SH_OP) & OP_MASK_OP; + if (op == OP_OP_COP0) + fprintf (stream, "%s", + mips_cp0_names[(l >> OP_SH_RD) & OP_MASK_RD]); + else + fprintf (stream, "$%ld", + (l >> OP_SH_RD) & OP_MASK_RD); + break; + + case 'K': + fprintf (stream, "%s", + mips_hwr_names[(l >> OP_SH_RD) & OP_MASK_RD]); + break; + + case 'N': + fprintf (stream, + ((opp->pinfo & (FP_D | FP_S)) != 0 + ? "$fcc%ld" : "$cc%ld"), (l >> OP_SH_BCC) & OP_MASK_BCC); + break; + + case 'M': + fprintf (stream, "$fcc%ld", + (l >> OP_SH_CCC) & OP_MASK_CCC); + break; + + case 'P': + fprintf (stream, "%ld", + (l >> OP_SH_PERFREG) & OP_MASK_PERFREG); + break; + + case 'e': + fprintf (stream, "%ld", + (l >> OP_SH_VECBYTE) & OP_MASK_VECBYTE); + break; + + case '%': + fprintf (stream, "%ld", + (l >> OP_SH_VECALIGN) & OP_MASK_VECALIGN); + break; + + case 'H': + fprintf (stream, "%ld", + (l >> OP_SH_SEL) & OP_MASK_SEL); + break; + + case 'O': + fprintf (stream, "%ld", + (l >> OP_SH_ALN) & OP_MASK_ALN); + break; + + case 'Q': + { + unsigned int vsel = (l >> OP_SH_VSEL) & OP_MASK_VSEL; + + if ((vsel & 0x10) == 0) { + int fmt; + + vsel &= 0x0f; + for (fmt = 0; fmt < 3; fmt++, vsel >>= 1) + if ((vsel & 1) == 0) + break; + fprintf (stream, "$v%ld[%d]", + (l >> OP_SH_FT) & OP_MASK_FT, vsel >> 1); + } else if ((vsel & 0x08) == 0) { + fprintf (stream, "$v%ld", + (l >> OP_SH_FT) & OP_MASK_FT); + } else { + fprintf (stream, "0x%lx", + (l >> OP_SH_FT) & OP_MASK_FT); + } + } + break; + + case 'X': + fprintf (stream, "$v%ld", + (l >> OP_SH_FD) & OP_MASK_FD); + break; + + case 'Y': + fprintf (stream, "$v%ld", + (l >> OP_SH_FS) & OP_MASK_FS); + break; + + case 'Z': + fprintf (stream, "$v%ld", + (l >> OP_SH_FT) & OP_MASK_FT); + break; + + default: + /* xgettext:c-format */ + fprintf (stream, "# internal error, undefined modifier (%c)", *d); + return; + } + } +} + +/* + * Print the mips instruction at address MEMADDR in debugged memory. + * Returns length of the instruction, in bytes, which is + * always INSNLEN. + */ +int +print_insn_mips (unsigned memaddr, + unsigned long int word, FILE *stream) +{ + const struct mips_opcode *op; + static int init = 0; + static const struct mips_opcode *mips_hash[OP_MASK_OP + 1]; + + /* Build a hash table to shorten the search time. */ + if (! init) { + unsigned int i; + + for (i = 0; i <= OP_MASK_OP; i++) { + for (op = mips_opcodes; op < &mips_opcodes[mips_num_opcodes]; op++) { + if (no_aliases && (op->pinfo2 & INSN2_ALIAS)) + continue; + if (i == ((op->match >> OP_SH_OP) & OP_MASK_OP)) { + mips_hash[i] = op; + break; + } + } + } + + init = 1; + } + + branch_delay_insns = 0; + data_size = 0; + insn_type = dis_nonbranch; + target = 0; + + op = mips_hash[(word >> OP_SH_OP) & OP_MASK_OP]; + if (op != NULL) { + for (; op < &mips_opcodes[mips_num_opcodes]; op++) { + if (! (no_aliases && (op->pinfo2 & INSN2_ALIAS)) + && (word & op->mask) == op->match) { + const char *d; + + /* Figure out instruction type and branch delay information. */ + if ((op->pinfo & INSN_UNCOND_BRANCH_DELAY) != 0) { + if ((op->pinfo & (INSN_WRITE_GPR_31 + | INSN_WRITE_GPR_D)) != 0) + insn_type = dis_jsr; + else + insn_type = dis_branch; + branch_delay_insns = 1; + } else if ((op->pinfo & (INSN_COND_BRANCH_DELAY + | INSN_COND_BRANCH_LIKELY)) != 0) { + if ((op->pinfo & INSN_WRITE_GPR_31) != 0) + insn_type = dis_condjsr; + else + insn_type = dis_condbranch; + branch_delay_insns = 1; + } else if ((op->pinfo & (INSN_STORE_MEMORY + | INSN_LOAD_MEMORY_DELAY)) != 0) + insn_type = dis_dref; + + fprintf (stream, "%s", op->name); + + d = op->args; + if (d != NULL && *d != '\0') { + fprintf (stream, "\t"); + print_insn_args (d, word, memaddr, stream, op); + } + + return INSNLEN; + } + } + } + + /* Handle undefined instructions. */ + insn_type = dis_noninsn; + fprintf (stream, ".word 0x%lx", word); + return INSNLEN; +} + +#ifdef NEED_MIPS16 + +#include "mips16-opc.c" + +/* The mips16 registers. */ +static const unsigned int mips16_to_32_reg_map[] = { + 16, 17, 2, 3, 4, 5, 6, 7 +}; +#define mips16_reg_names(rn) mips_gpr_names[mips16_to_32_reg_map[rn]] + +static int big_endian; + +static unsigned +getb16 (const unsigned char *buf) +{ + return (buf[0] << 8) | buf[1]; +} + +static unsigned +getl16 (const unsigned char *buf) +{ + return (buf[1] << 8) | buf[0]; +} + +static void +memory_error (int status, unsigned memaddr, FILE *stream) +{ + fprintf (stream, "Error reading memory at 0x%08x: %s", memaddr, strerror (status)); +} + +/* + * Disassemble an operand for a mips16 instruction. + */ +static void +print_mips16_insn_arg (char type, + const struct mips_opcode *op, + int l, + int use_extend, + int extend, unsigned memaddr, FILE *stream, + int (*read_memory) (unsigned addr, unsigned char *buf, unsigned nbytes)) +{ + switch (type) { + case ',': + case '(': + case ')': + fprintf (stream, "%c", type); + break; + + case 'y': + case 'w': + fprintf (stream, "%s", + mips16_reg_names (((l >> MIPS16OP_SH_RY) + & MIPS16OP_MASK_RY))); + break; + + case 'x': + case 'v': + fprintf (stream, "%s", + mips16_reg_names (((l >> MIPS16OP_SH_RX) + & MIPS16OP_MASK_RX))); + break; + + case 'z': + fprintf (stream, "%s", + mips16_reg_names (((l >> MIPS16OP_SH_RZ) + & MIPS16OP_MASK_RZ))); + break; + + case 'Z': + fprintf (stream, "%s", + mips16_reg_names (((l >> MIPS16OP_SH_MOVE32Z) + & MIPS16OP_MASK_MOVE32Z))); + break; + + case '0': + fprintf (stream, "%s", mips_gpr_names[0]); + break; + + case 'S': + fprintf (stream, "%s", mips_gpr_names[29]); + break; + + case 'P': + fprintf (stream, "$pc"); + break; + + case 'R': + fprintf (stream, "%s", mips_gpr_names[31]); + break; + + case 'X': + fprintf (stream, "%s", + mips_gpr_names[((l >> MIPS16OP_SH_REGR32) + & MIPS16OP_MASK_REGR32)]); + break; + + case 'Y': + fprintf (stream, "%s", + mips_gpr_names[MIPS16OP_EXTRACT_REG32R (l)]); + break; + + case '<': + case '>': + case '[': + case ']': + case '4': + case '5': + case 'H': + case 'W': + case 'D': + case 'j': + case '6': + case '8': + case 'V': + case 'C': + case 'U': + case 'k': + case 'K': + case 'p': + case 'q': + case 'A': + case 'B': + case 'E': + { + int immed, nbits, shift, signedp, extbits, pcrel, extu, branch; + + shift = 0; + signedp = 0; + extbits = 16; + pcrel = 0; + extu = 0; + branch = 0; + switch (type) { + case '<': + nbits = 3; + immed = (l >> MIPS16OP_SH_RZ) & MIPS16OP_MASK_RZ; + extbits = 5; + extu = 1; + break; + case '>': + nbits = 3; + immed = (l >> MIPS16OP_SH_RX) & MIPS16OP_MASK_RX; + extbits = 5; + extu = 1; + break; + case '[': + nbits = 3; + immed = (l >> MIPS16OP_SH_RZ) & MIPS16OP_MASK_RZ; + extbits = 6; + extu = 1; + break; + case ']': + nbits = 3; + immed = (l >> MIPS16OP_SH_RX) & MIPS16OP_MASK_RX; + extbits = 6; + extu = 1; + break; + case '4': + nbits = 4; + immed = (l >> MIPS16OP_SH_IMM4) & MIPS16OP_MASK_IMM4; + signedp = 1; + extbits = 15; + break; + case '5': + nbits = 5; + immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5; + insn_type = dis_dref; + data_size = 1; + break; + case 'H': + nbits = 5; + shift = 1; + immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5; + insn_type = dis_dref; + data_size = 2; + break; + case 'W': + nbits = 5; + shift = 2; + immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5; + if ((op->pinfo & MIPS16_INSN_READ_PC) == 0 + && (op->pinfo & MIPS16_INSN_READ_SP) == 0) { + insn_type = dis_dref; + data_size = 4; + } + break; + case 'D': + nbits = 5; + shift = 3; + immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5; + insn_type = dis_dref; + data_size = 8; + break; + case 'j': + nbits = 5; + immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5; + signedp = 1; + break; + case '6': + nbits = 6; + immed = (l >> MIPS16OP_SH_IMM6) & MIPS16OP_MASK_IMM6; + break; + case '8': + nbits = 8; + immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8; + break; + case 'V': + nbits = 8; + shift = 2; + immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8; + /* FIXME: This might be lw, or it might be addiu to $sp or + * $pc. We assume it's load. */ + insn_type = dis_dref; + data_size = 4; + break; + case 'C': + nbits = 8; + shift = 3; + immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8; + insn_type = dis_dref; + data_size = 8; + break; + case 'U': + nbits = 8; + immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8; + extu = 1; + break; + case 'k': + nbits = 8; + immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8; + signedp = 1; + break; + case 'K': + nbits = 8; + shift = 3; + immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8; + signedp = 1; + break; + case 'p': + nbits = 8; + immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8; + signedp = 1; + pcrel = 1; + branch = 1; + break; + case 'q': + nbits = 11; + immed = (l >> MIPS16OP_SH_IMM11) & MIPS16OP_MASK_IMM11; + signedp = 1; + pcrel = 1; + branch = 1; + break; + case 'A': + nbits = 8; + shift = 2; + immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8; + pcrel = 1; + /* FIXME: This can be lw or la. We assume it is lw. */ + insn_type = dis_dref; + data_size = 4; + break; + case 'B': + nbits = 5; + shift = 3; + immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5; + pcrel = 1; + insn_type = dis_dref; + data_size = 8; + break; + case 'E': + nbits = 5; + shift = 2; + immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5; + pcrel = 1; + break; + default: + fprintf (stream, "# internal disassembler error, unrecognised mips16 type (%c)", type); + abort (); + } + + if (!use_extend) { + if (signedp && immed >= (1 << (nbits - 1))) + immed -= 1 << nbits; + immed <<= shift; + if ((type == '<' || type == '>' || type == '[' || type == ']') + && immed == 0) + immed = 8; + } else { + if (extbits == 16) + immed |= ((extend & 0x1f) << 11) | (extend & 0x7e0); + else if (extbits == 15) + immed |= ((extend & 0xf) << 11) | (extend & 0x7f0); + else + immed = ((extend >> 6) & 0x1f) | (extend & 0x20); + immed &= (1 << extbits) - 1; + if (!extu && immed >= (1 << (extbits - 1))) + immed -= 1 << extbits; + } + + if (!pcrel) + fprintf (stream, "%d", immed); + else { + unsigned baseaddr; + + if (branch) { + immed *= 2; + baseaddr = memaddr + 2; + } else if (use_extend) + baseaddr = memaddr - 2; + else { + int status; + unsigned char buffer[2]; + + baseaddr = memaddr; + + /* If this instruction is in the delay slot of a jr + * instruction, the base address is the address of the + * jr instruction. If it is in the delay slot of jalr + * instruction, the base address is the address of the + * jalr instruction. This test is unreliable: we have + * no way of knowing whether the previous word is + * instruction or data. */ + status = read_memory (memaddr - 4, buffer, 2); + if (status == 0 + && (((big_endian ? getb16 (buffer) + : getl16 (buffer)) + & 0xf800) == 0x1800)) + baseaddr = memaddr - 4; + else { + status = read_memory (memaddr - 2, buffer, 2); + if (status == 0 + && (((big_endian ? getb16 (buffer) + : getl16 (buffer)) + & 0xf81f) == 0xe800)) + baseaddr = memaddr - 2; + } + } + target = (baseaddr & ~((1 << shift) - 1)) + immed; + if (pcrel && branch) + /* For gdb disassembler, maintain odd address. */ + target |= 1; + print_address (target, stream); + } + } + break; + + case 'a': + { + int jalx = l & 0x400; + + if (!use_extend) + extend = 0; + l = ((l & 0x1f) << 23) | ((l & 0x3e0) << 13) | (extend << 2); + if (! jalx) + /* For gdb disassembler, maintain odd address. */ + l |= 1; + } + target = ((memaddr + 4) & ~(unsigned) 0x0fffffff) | l; + print_address (target, stream); + break; + + case 'l': + case 'L': + { + int need_comma, amask, smask; + + need_comma = 0; + + l = (l >> MIPS16OP_SH_IMM6) & MIPS16OP_MASK_IMM6; + + amask = (l >> 3) & 7; + + if (amask > 0 && amask < 5) { + fprintf (stream, "%s", mips_gpr_names[4]); + if (amask > 1) + fprintf (stream, "-%s", + mips_gpr_names[amask + 3]); + need_comma = 1; + } + + smask = (l >> 1) & 3; + if (smask == 3) { + fprintf (stream, "%s??", + need_comma ? "," : ""); + need_comma = 1; + } else if (smask > 0) { + fprintf (stream, "%s%s", + need_comma ? "," : "", mips_gpr_names[16]); + if (smask > 1) + fprintf (stream, "-%s", + mips_gpr_names[smask + 15]); + need_comma = 1; + } + + if (l & 1) { + fprintf (stream, "%s%s", + need_comma ? "," : "", mips_gpr_names[31]); + need_comma = 1; + } + + if (amask == 5 || amask == 6) { + fprintf (stream, "%s$f0", + need_comma ? "," : ""); + if (amask == 6) + fprintf (stream, "-$f1"); + } + } + break; + + case 'm': + case 'M': + /* MIPS16e save/restore. */ + { + int need_comma = 0; + int amask, args, statics; + int nsreg, smask; + int framesz; + int i, j; + + l = l & 0x7f; + if (use_extend) + l |= extend << 16; + + amask = (l >> 16) & 0xf; + if (amask == MIPS16_ALL_ARGS) { + args = 4; + statics = 0; + } else if (amask == MIPS16_ALL_STATICS) { + args = 0; + statics = 4; + } else { + args = amask >> 2; + statics = amask & 3; + } + + if (args > 0) { + fprintf (stream, "%s", mips_gpr_names[4]); + if (args > 1) + fprintf (stream, "-%s", + mips_gpr_names[4 + args - 1]); + need_comma = 1; + } + + framesz = (((l >> 16) & 0xf0) | (l & 0x0f)) * 8; + if (framesz == 0 && !use_extend) + framesz = 128; + + fprintf (stream, "%s%d", + need_comma ? "," : "", framesz); + + if (l & 0x40) /* $ra */ + fprintf (stream, ",%s", + mips_gpr_names[31]); + + nsreg = (l >> 24) & 0x7; + smask = 0; + if (l & 0x20) /* $s0 */ + smask |= 1 << 0; + if (l & 0x10) /* $s1 */ + smask |= 1 << 1; + if (nsreg > 0) /* $s2-$s8 */ + smask |= ((1 << nsreg) - 1) << 2; + + /* Find first set static reg bit. */ + for (i = 0; i < 9; i++) { + if (smask & (1 << i)) { + fprintf (stream, ",%s", + mips_gpr_names[i == 8 ? 30 : (16 + i)]); + /* Skip over string of set bits. */ + for (j = i; smask & (2 << j); j++) + continue; + if (j > i) + fprintf (stream, "-%s", + mips_gpr_names[j == 8 ? 30 : (16 + j)]); + i = j + 1; + } + } + + /* Statics $ax - $a3. */ + if (statics == 1) + fprintf (stream, ",%s", + mips_gpr_names[7]); + else if (statics > 0) + fprintf (stream, ",%s-%s", + mips_gpr_names[7 - statics + 1], mips_gpr_names[7]); + } + break; + + default: + /* xgettext:c-format */ + fprintf (stream, "# internal disassembler error, unrecognised modifier (%c)", type); + abort (); + } +} + +/* Disassemble mips16 instructions. */ + +int +print_insn_mips16 (unsigned memaddr, FILE *stream, + int (*read_memory) (unsigned addr, unsigned char *buf, unsigned nbytes)) +{ + int status; + unsigned char buffer[2]; + int length; + int insn; + int use_extend; + int extend = 0; + const struct mips_opcode *op, *opend; + + branch_delay_insns = 0; + data_size = 0; + insn_type = dis_nonbranch; + target = 0; + + status = read_memory (memaddr, buffer, 2); + if (status != 0) { + memory_error (status, memaddr, stream); + return -1; + } + + length = 2; + + if (big_endian) + insn = getb16 (buffer); + else + insn = getl16 (buffer); + + /* Handle the extend opcode specially. */ + use_extend = 0; + if ((insn & 0xf800) == 0xf000) { + use_extend = 1; + extend = insn & 0x7ff; + + memaddr += 2; + + status = read_memory (memaddr, buffer, 2); + if (status != 0) { + fprintf (stream, "extend 0x%x", + (unsigned int) extend); + memory_error (status, memaddr, stream); + return -1; + } + + if (big_endian) + insn = getb16 (buffer); + else + insn = getl16 (buffer); + + /* Check for an extend opcode followed by an extend opcode. */ + if ((insn & 0xf800) == 0xf000) { + fprintf (stream, "extend 0x%x", + (unsigned int) extend); + insn_type = dis_noninsn; + return length; + } + + length += 2; + } + + /* FIXME: Should probably use a hash table on the major opcode here. */ + + opend = mips16_opcodes + mips16_num_opcodes; + for (op = mips16_opcodes; op < opend; op++) { + if (! (no_aliases && (op->pinfo2 & INSN2_ALIAS)) + && (insn & op->mask) == op->match) { + const char *s; + + if (strchr (op->args, 'a') != NULL) { + if (use_extend) { + fprintf (stream, "extend 0x%x", + (unsigned int) extend); + insn_type = dis_noninsn; + return length - 2; + } + + use_extend = 0; + + memaddr += 2; + + status = read_memory (memaddr, buffer, 2); + if (status == 0) { + use_extend = 1; + if (big_endian) + extend = getb16 (buffer); + else + extend = getl16 (buffer); + length += 2; + } + } + + fprintf (stream, "%s", op->name); + if (op->args[0] != '\0') + fprintf (stream, "\t"); + + for (s = op->args; *s != '\0'; s++) { + if (*s == ',' + && s[1] == 'w' + && (((insn >> MIPS16OP_SH_RX) & MIPS16OP_MASK_RX) + == ((insn >> MIPS16OP_SH_RY) & MIPS16OP_MASK_RY))) { + /* Skip the register and the comma. */ + ++s; + continue; + } + if (*s == ',' + && s[1] == 'v' + && (((insn >> MIPS16OP_SH_RZ) & MIPS16OP_MASK_RZ) + == ((insn >> MIPS16OP_SH_RX) & MIPS16OP_MASK_RX))) { + /* Skip the register and the comma. */ + ++s; + continue; + } + print_mips16_insn_arg (*s, op, insn, use_extend, extend, + memaddr, stream, read_memory); + } + + /* Figure out branch instruction type and delay slot information. */ + if ((op->pinfo & INSN_UNCOND_BRANCH_DELAY) != 0) + branch_delay_insns = 1; + if ((op->pinfo & (INSN_UNCOND_BRANCH_DELAY + | MIPS16_INSN_UNCOND_BRANCH)) != 0) { + if ((op->pinfo & INSN_WRITE_GPR_31) != 0) + insn_type = dis_jsr; + else + insn_type = dis_branch; + } else if ((op->pinfo & MIPS16_INSN_COND_BRANCH) != 0) + insn_type = dis_condbranch; + + return length; + } + } + + if (use_extend) + fprintf (stream, "0x%x", extend | 0xf000); + fprintf (stream, "0x%x", insn); + insn_type = dis_noninsn; + + return length; +} +#endif diff --git a/src/cmd/as/mips-instruction-set.txt b/src/cmd/as/mips-instruction-set.txt new file mode 100644 index 0000000..669dd78 --- /dev/null +++ b/src/cmd/as/mips-instruction-set.txt @@ -0,0 +1,350 @@ +The PIC32 family instruction set complies with the MIPS32 Release 2 +instruction set architecture. Refer to "MIPS32 Architecture for +Programmers Volume II: The MIPS32 Instruction Set" at www.mips.com +for more information. + +Instruction Description Function +------------------------------------------------------------------------------- +ADD Integer Add Rd = Rs + Rt + +ADDI Integer Add Immediate Rt = Rs + Immed + +ADDIU Unsigned Integer Add Immediate Rt = Rs +u Immed + +ADDIUPC Unsigned Integer Add Immediate to PC + (MIPS16e only) Rt = PC +u Immed + +ADDU Unsigned Integer Add Rd = Rs +u Rt + +AND Logical AND Rd = Rs & Rt + +ANDI Logical AND Immediate Rt = Rs & Immed[15:0] + +B Unconditional Branch + (Assembler idiom for: BEQ r0, r0, offset) PC += (signed)offset + +BAL Branch and Link GPR[31] = PC + 8 + (Assembler idiom for: BGEZAL r0, offset) PC += (signed)offset + +BEQ Branch On Equal if Rs == Rt + PC += (signed)offset + +BEQL Branch On Equal Likely if Rs == Rt + PC += (signed)offset + else + Ignore Next Instruction + +BGEZ Branch on Greater Than or Equal To Zero if !Rs[31] + PC += (signed)offset + +BGEZAL Branch on Greater Than or GPR[31] = PC + 8 + Equal To Zero And Link if !Rs[31] + PC += (signed)offset + +BGEZALL Branch on Greater Than or GPR[31] = PC + 8 + Equal To Zero And Link Likely if !Rs[31] + PC += (signed)offset + else + Ignore Next Instruction + +BGEZL Branch on Greater Than or if !Rs[31] + Equal To Zero Likely PC += (signed)offset + else + Ignore Next Instruction + +BGTZ Branch on Greater Than Zero if !Rs[31] && Rs != 0 + PC += (signed)offset + +BGTZL Branch on Greater Than Zero Likely if !Rs[31] && Rs != 0 + PC += (signed)offset + else + Ignore Next Instruction + +BLEZ Branch on Less Than or Equal to Zero if Rs[31] || Rs == 0 + PC += (signed)offset + +BLEZL Branch on Less Than or Equal to Zero Likely if Rs[31] || Rs == 0 + PC += (signed)offset + else + Ignore Next Instruction + +BLTZ Branch on Less Than Zero if Rs[31] + PC += (signed)offset + +BLTZAL Branch on Less Than Zero And Link GPR[31] = PC + 8 + if Rs[31] + PC += (signed)offset + +BLTZALL Branch on Less Than Zero And Link Likely GPR[31] = PC + 8 + if Rs[31] + PC += (signed)offset + else + Ignore Next Instruction + +BLTZL Branch on Less Than Zero Likely if Rs[31] + PC += (signed)offset + else + Ignore Next Instruction + +BNE Branch on Not Equal if Rs != Rt + PC += (signed)offset + +BNEL Branch on Not Equal Likely if Rs != Rt + PC += (signed)offset + else + Ignore Next Instruction + +BREAK Breakpoint Break Exception + +CLO Count Leading Ones Rd = NumLeadingOnes(Rs) + +CLZ Count Leading Zeroes Rd = NumLeadingZeroes(Rs) + +COP0 Coprocessor 0 Operation See Software User's Manual + +DERET Return from Debug Exception PC = DEPC + Exit Debug Mode + +DI Atomically Disable Interrupts Rt = Status; Status.IE = 0 + +DIV Divide LO = (signed)Rs / (signed)Rt + HI = (signed)Rs % (signed)Rt + +DIVU Unsigned Divide LO = (uns)Rs / (uns)Rt + HI = (uns)Rs % (uns)Rt + +EHB Execution Hazard Barrier Stop instruction execution + until execution hazards + are cleared + +EI Atomically Enable Interrupts Rt = Status; StatusIE = 1 + +ERET Return from Exception if SR[2] + PC = ErrorEPC + SR[2] = 0 + else + PC = EPC + SR[1] = 0 + LL = 0 + +EXT Extract Bit Field Rt = ExtractField(Rs, pos, size) + +INS Insert Bit Field Rt = InsertField(Rs, Rt, pos, size) + +J Unconditional Jump PC = PC[31:28] || offset<<2 + +JAL Jump and Link GPR[31] = PC + 8 + PC = PC[31:28] || offset<<2 + +JALR Jump and Link Register Rd = PC + 8 + PC = Rs + +JALR.HB Jump and Link Register with Hazard Barrier Like JALR, but also clears + execution and instruction hazards + +JALRC Jump and Link Register Compact - do not Rd = PC + 2 + execute instruction in jump delay slot PC = Rs + (MIPS16e only) + +JR Jump Register PC = Rs + +JR.HB Jump Register with Hazard Barrier Like JR, but also clears execution + and instruction hazards + +JRC Jump Register Compact - do not execute PC = Rs + instruction in jump delay slot + (MIPS16e only) + +LB Load Byte Rt = (byte)Mem[Rs+offset] + +LBU Unsigned Load Byte Rt = (ubyte))Mem[Rs+offset] + +LH Load Halfword Rt = (half)Mem[Rs+offset] + +LHU Unsigned Load Halfword Rt = (uhalf)Mem[Rs+offset] + +LL Load Linked Word Rt = Mem[Rs+offset] + LL = 1 + LLAdr = Rs + offset + +LUI Load Upper Immediate Rt = immediate << 16 + +LW Load Word Rt = Mem[Rs+offset] + +LWPC Load Word, PC relative Rt = Mem[PC+offset] + +LWL Load Word Left See Architecture Reference Manual + +LWR Load Word Right See Architecture Reference Manual + +MADD Multiply-Add HI | LO += (signed)Rs * (signed)Rt + +MADDU Multiply-Add Unsigned HI | LO += (uns)Rs * (uns)Rt + +MFC0 Move From Coprocessor 0 Rt = CPR[0, Rd, sel] + +MFHI Move From HI Rd = HI + +MFLO Move From LO Rd = LO + +MOVN Move Conditional on Not Zero if Rt != 0 then + Rd = Rs + +MOVZ Move Conditional on Zero if Rt = 0 then + Rd = Rs + +MSUB Multiply-Subtract HI | LO -= (signed)Rs * (signed)Rt + +MSUBU Multiply-Subtract Unsigned HI | LO -= (uns)Rs * (uns)Rt + +MTC0 Move To Coprocessor 0 CPR[0, n, Sel] = Rt + +MTHI Move To HI HI = Rs + +MTLO Move To LO LO = Rs + +MUL Multiply with register write HI | LO = Unpredictable + Rd = ((signed)Rs * (signed)Rt) [31:0] + +MULT Integer Multiply HI | LO = (signed)Rs * (signed)Rd + +MULTU Unsigned Multiply HI | LO = (uns)Rs * (uns)Rd + +NOP No Operation + (Assembler idiom for: SLL r0, r0, r0) + +NOR Logical NOR Rd = ~(Rs | Rt) + +OR Logical OR Rd = Rs | Rt + +ORI Logical OR Immediate Rt = Rs | Immed + +RDHWR Read Hardware Register Allows unprivileged access + to registers enabled by + HWREna register + +RDPGPR Read GPR from Previous Shadow Set Rt = SGPR[SRSCtl.PSS, Rd] + +RESTORE Restore registers and deallocate stack See Architecture Reference Manual + frame (MIPS16eª only) + +ROTR Rotate Word Right Rd = Rt[sa-1..0] || Rt[31..sa] + +ROTRV Rotate Word Right Variable Rd = Rt[Rs-1..0] || Rt[31..Rs] + +SAVE Save registers and allocate stack frame See Architecture Reference Manual + (MIPS16e only) + +SB Store Byte (byte)Mem[Rs+offset] = Rt + +SC Store Conditional Word if LL = 1 + mem[Rs+offset] = Rt + Rt = LL + +SDBBP Software Debug Break Point Trap to SW Debug Handler + +SEB Sign-Extend Byte Rd = (byte)Rs + +SEH Sign-Extend Half Rd = (half)Rs + +SH Store Half (half)Mem[Rs+offset] = Rt + +SLL Shift Left Logical Rd = Rt << sa + +SLLV Shift Left Logical Variable Rd = Rt << Rs[4:0] + +SLT Set on Less Than if (signed)Rs < (signed)Rt + Rd = 1 + else + Rd = 0 + +SLTI Set on Less Than Immediate if (signed)Rs < (signed)Immed + Rt = 1 + else + Rt = 0 + +SLTIU Set on Less Than Immediate Unsigned if (uns)Rs < (uns)Immed + Rt = 1 + else + Rt = 0 + +SLTU Set on Less Than Unsigned if (uns)Rs < (uns)Immed + Rd = 1 + else + Rd = 0 + +SRA Shift Right Arithmetic Rd = (signed)Rt >> sa + +SRAV Shift Right Arithmetic Variable Rd = (signed)Rt >> Rs[4:0] + +SRL Shift Right Logical Rd = (uns)Rt >> sa + +SRLV Shift Right Logical Variable Rd = (uns)Rt >> Rs[4:0] + +SSNOP Superscalar Inhibit No Operation NOP + +SUB Integer Subtract Rt = (signed)Rs - (signed)Rd + +SUBU Unsigned Subtract Rt = (uns)Rs - (uns)Rd + +SW Store Word Mem[Rs+offset] = Rt + +SWL Store Word Left See Architecture Reference Manual + +SWR Store Word Right See Architecture Reference Manual + +SYNC Synchronize See Software User's Manual + +SYSCALL System Call SystemCallException + +TEQ Trap if Equal if Rs == Rt + TrapException + +TEQI Trap if Equal Immediate if Rs == (signed)Immed + TrapException + +TGE Trap if Greater Than or Equal if (signed)Rs >= (signed)Rt + TrapException + +TGEI Trap if Greater Than or Equal Immediate if (signed)Rs >= (signed)Immed + TrapException + +TGEIU Trap if Greater Than or if (uns)Rs >= (uns)Immed + Equal Immediate Unsigned TrapException + +TGEU Trap if Greater Than or Equal Unsigned if (uns)Rs >= (uns)Rt + TrapException + +TLT Trap if Less Than if (signed)Rs < (signed)Rt + TrapException + +TLTI Trap if Less Than Immediate if (signed)Rs < (signed)Immed + TrapException + +TLTIU Trap if Less Than Immediate Unsigned if (uns)Rs < (uns)Immed + TrapException + +TLTU Trap if Less Than Unsigned if (uns)Rs < (uns)Rt + TrapException + +TNE Trap if Not Equal if Rs != Rt + TrapException + +TNEI Trap if Not Equal Immediate if Rs != (signed)Immed + TrapException + +WAIT Wait for Interrupts Stall until interrupt occurs + +WRPGPR Write to GPR in Previous Shadow Set SGPR[SRSCtl.PSS, Rd] = Rt + +WSBH Word Swap Bytes Within Halfwords Rd = Rt23..16 || Rt31..24 || + Rt7..0 || Rt15..8 + +XOR Exclusive OR Rd = Rs ^ Rt + +XORI Exclusive OR Immediate Rt = Rs ^ (uns)Immed + +ZEB Zero-extend byte (MIPS16e only) Rt = (ubyte) Rs + +ZEH Zero-extend half (MIPS16e only) Rt = (uhalf) Rs +------------------------------------------------------------------------------- diff --git a/src/cmd/as/mips-opc.c b/src/cmd/as/mips-opc.c new file mode 100644 index 0000000..fa11255 --- /dev/null +++ b/src/cmd/as/mips-opc.c @@ -0,0 +1,1184 @@ +/* + * MIPS opcode list. + * + * Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002 + * 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc. + * Contributed by Ralph Campbell and OSF + * Commented and modified by Ian Lance Taylor, Cygnus Support + * Extended for MIPS32 support by Anders Norlander, and by SiByte, Inc. + * MIPS-3D, MDMX, and MIPS32 Release 2 support added by Broadcom + * Corporation (SiByte). + * Adapted for VirtualMIPS by Serge Vakulenko. + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + */ + +/* Short hand so the lines aren't too long. */ + +#define LDD INSN_LOAD_MEMORY_DELAY +#define LCD INSN_LOAD_COPROC_DELAY +#define UBD INSN_UNCOND_BRANCH_DELAY +#define CBD INSN_COND_BRANCH_DELAY +#define COD INSN_COPROC_MOVE_DELAY +#define CLD INSN_COPROC_MEMORY_DELAY +#define CBL INSN_COND_BRANCH_LIKELY +#define TRAP INSN_TRAP +#define SM INSN_STORE_MEMORY + +#define WR_d INSN_WRITE_GPR_D +#define WR_t INSN_WRITE_GPR_T +#define WR_31 INSN_WRITE_GPR_31 +#define WR_D INSN_WRITE_FPR_D +#define WR_T INSN_WRITE_FPR_T +#define WR_S INSN_WRITE_FPR_S +#define RD_s INSN_READ_GPR_S +#define RD_b INSN_READ_GPR_S +#define RD_t INSN_READ_GPR_T +#define RD_S INSN_READ_FPR_S +#define RD_T INSN_READ_FPR_T +#define RD_R INSN_READ_FPR_R +#define WR_CC INSN_WRITE_COND_CODE +#define RD_CC INSN_READ_COND_CODE +#define RD_C0 INSN_COP +#define RD_C1 INSN_COP +#define RD_C2 INSN_COP +#define RD_C3 INSN_COP +#define WR_C0 INSN_COP +#define WR_C1 INSN_COP +#define WR_C2 INSN_COP +#define WR_C3 INSN_COP +#define CP INSN_COP + +#define WR_HI INSN_WRITE_HI +#define RD_HI INSN_READ_HI +#define MOD_HI WR_HI|RD_HI + +#define WR_LO INSN_WRITE_LO +#define RD_LO INSN_READ_LO +#define MOD_LO WR_LO|RD_LO + +#define WR_HILO WR_HI|WR_LO +#define RD_HILO RD_HI|RD_LO +#define MOD_HILO WR_HILO|RD_HILO + +#define IS_M INSN_MULT + +#define WR_MACC INSN2_WRITE_MDMX_ACC +#define RD_MACC INSN2_READ_MDMX_ACC + +#define I1 INSN_ISA1 +#define I2 INSN_ISA2 +#define I3 INSN_ISA3 +#define I4 INSN_ISA4 +#define I5 INSN_ISA5 +#define I32 INSN_ISA32 +#define I64 INSN_ISA64 +#define I33 INSN_ISA32R2 +#define I65 INSN_ISA64R2 +#define I3_32 INSN_ISA3_32 +#define I3_33 INSN_ISA3_32R2 +#define I4_32 INSN_ISA4_32 +#define I4_33 INSN_ISA4_32R2 +#define I5_33 INSN_ISA5_32R2 + +/* MIPS32 SmartMIPS ASE support. */ +#define SMT INSN_SMARTMIPS + +/* MIPS DSP ASE support. + NOTE: + 1. MIPS DSP ASE includes 4 accumulators ($ac0 - $ac3). $ac0 is the pair + of original HI and LO. $ac1, $ac2 and $ac3 are new registers, and have + the same structure as $ac0 (HI + LO). For DSP instructions that write or + read accumulators (that may be $ac0), we add WR_a (WR_HILO) or RD_a + (RD_HILO) attributes, such that HILO dependencies are maintained + conservatively. + + 2. For some mul. instructions that use integer registers as destinations + but destroy HI+LO as side-effect, we add WR_HILO to their attributes. + + 3. MIPS DSP ASE includes a new DSP control register, which has 6 fields + (ccond, outflag, EFI, c, scount, pos). Many DSP instructions read or write + certain fields of the DSP control register. For simplicity, we decide not + to track dependencies of these fields. + However, "bposge32" is a branch instruction that depends on the "pos" + field. In order to make sure that GAS does not reorder DSP instructions + that writes the "pos" field and "bposge32", we add DSP_VOLA (INSN_TRAP) + attribute to those instructions that write the "pos" field. */ + +#define WR_a WR_HILO /* Write dsp accumulators (reuse WR_HILO) */ +#define RD_a RD_HILO /* Read dsp accumulators (reuse RD_HILO) */ +#define MOD_a WR_a|RD_a +#define DSP_VOLA INSN_TRAP +#define D32 INSN_DSP +#define D33 INSN_DSPR2 +#define D64 INSN_DSP64 + +/* MIPS MT ASE support. */ +#define MT32 INSN_MT + +/* The order of overloaded instructions matters. Label arguments and + register arguments look the same. Instructions that can have either + for arguments must apear in the correct order in this table for the + assembler to pick the right one. In other words, entries with + immediate operands must apear after the same instruction with + registers. + + Because of the lookup algorithm used, entries with the same opcode + name must be contiguous. + + Many instructions are short hand for other instructions (i.e., The + jal instruction is short for jalr ). */ + +static const struct mips_opcode mips_opcodes[] = +{ +/* These instructions appear first so that the disassembler will find + them first. The assemblers uses a hash table based on the + instruction name anyhow. */ +/* name, args, match, mask, pinfo, pinfo2, membership */ +{"pref", "k,o(b)", 0xcc000000, 0xfc000000, RD_b, 0, I4_32|I4}, +{"prefx", "h,t(b)", 0x4c00000f, 0xfc0007ff, RD_b|RD_t|FP_S, 0, I4_33 }, +{"nop", "", 0x00000000, 0xffffffff, 0, INSN2_ALIAS, I1 }, /* sll */ +{"ssnop", "", 0x00000040, 0xffffffff, 0, INSN2_ALIAS, I1 }, /* sll */ +{"ehb", "", 0x000000c0, 0xffffffff, 0, INSN2_ALIAS, I1 }, /* sll */ +{"li", "t,j", 0x24000000, 0xffe00000, WR_t, INSN2_ALIAS, I1 }, /* addiu */ +{"li", "t,i", 0x34000000, 0xffe00000, WR_t, INSN2_ALIAS, I1 }, /* ori */ +{"move", "d,s", 0x0000002d, 0xfc1f07ff, WR_d|RD_s, INSN2_ALIAS, I3 },/* daddu */ +{"move", "d,s", 0x00000021, 0xfc1f07ff, WR_d|RD_s, INSN2_ALIAS, I1 },/* addu */ +{"move", "d,s", 0x00000025, 0xfc1f07ff, WR_d|RD_s, INSN2_ALIAS, I1 },/* or */ +{"b", "p", 0x10000000, 0xffff0000, UBD, INSN2_ALIAS, I1 },/* beq 0,0 */ +{"b", "p", 0x04010000, 0xffff0000, UBD, INSN2_ALIAS, I1 },/* bgez 0 */ +{"bal", "p", 0x04110000, 0xffff0000, UBD|WR_31, INSN2_ALIAS, I1 },/* bgezal 0*/ + +{"abs.s", "D,V", 0x46000005, 0xffff003f, WR_D|RD_S|FP_S, 0, I1 }, +{"abs.d", "D,V", 0x46200005, 0xffff003f, WR_D|RD_S|FP_D, 0, I1 }, +{"add", "d,v,t", 0x00000020, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I1 }, +{"add.s", "D,V,T", 0x46000000, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, 0, I1 }, +{"add.d", "D,V,T", 0x46200000, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I1 }, +{"addi", "t,r,j", 0x20000000, 0xfc000000, WR_t|RD_s, 0, I1 }, +{"addiu", "t,r,j", 0x24000000, 0xfc000000, WR_t|RD_s, 0, I1 }, +{"addu", "d,v,t", 0x00000021, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I1 }, +{"alnv.ps", "D,V,T,s", 0x4c00001e, 0xfc00003f, WR_D|RD_S|RD_T|FP_D, 0, I5_33 }, +{"and", "d,v,t", 0x00000024, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I1 }, +{"andi", "t,r,i", 0x30000000, 0xfc000000, WR_t|RD_s, 0, I1 }, +/* b is at the top of the table. */ +/* bal is at the top of the table. */ +/* bc0[tf]l? are at the bottom of the table. */ +{"bc1f", "p", 0x45000000, 0xffff0000, CBD|RD_CC|FP_S, 0, I1 }, +{"bc1f", "N,p", 0x45000000, 0xffe30000, CBD|RD_CC|FP_S, 0, I4_32 }, +{"bc1fl", "p", 0x45020000, 0xffff0000, CBL|RD_CC|FP_S, 0, I2 }, +{"bc1fl", "N,p", 0x45020000, 0xffe30000, CBL|RD_CC|FP_S, 0, I4_32 }, +{"bc1t", "p", 0x45010000, 0xffff0000, CBD|RD_CC|FP_S, 0, I1 }, +{"bc1t", "N,p", 0x45010000, 0xffe30000, CBD|RD_CC|FP_S, 0, I4_32 }, +{"bc1tl", "p", 0x45030000, 0xffff0000, CBL|RD_CC|FP_S, 0, I2 }, +{"bc1tl", "N,p", 0x45030000, 0xffe30000, CBL|RD_CC|FP_S, 0, I4_32 }, +/* bc2* are at the bottom of the table. */ +/* bc3* are at the bottom of the table. */ +{"beqz", "s,p", 0x10000000, 0xfc1f0000, CBD|RD_s, 0, I1 }, +{"beqzl", "s,p", 0x50000000, 0xfc1f0000, CBL|RD_s, 0, I2 }, +{"beq", "s,t,p", 0x10000000, 0xfc000000, CBD|RD_s|RD_t, 0, I1 }, +{"beql", "s,t,p", 0x50000000, 0xfc000000, CBL|RD_s|RD_t, 0, I2 }, +{"bgez", "s,p", 0x04010000, 0xfc1f0000, CBD|RD_s, 0, I1 }, +{"bgezl", "s,p", 0x04030000, 0xfc1f0000, CBL|RD_s, 0, I2 }, +{"bgezal", "s,p", 0x04110000, 0xfc1f0000, CBD|RD_s|WR_31, 0, I1 }, +{"bgezall", "s,p", 0x04130000, 0xfc1f0000, CBL|RD_s|WR_31, 0, I2 }, +{"bgtz", "s,p", 0x1c000000, 0xfc1f0000, CBD|RD_s, 0, I1 }, +{"bgtzl", "s,p", 0x5c000000, 0xfc1f0000, CBL|RD_s, 0, I2 }, +{"blez", "s,p", 0x18000000, 0xfc1f0000, CBD|RD_s, 0, I1 }, +{"blezl", "s,p", 0x58000000, 0xfc1f0000, CBL|RD_s, 0, I2 }, +{"bltz", "s,p", 0x04000000, 0xfc1f0000, CBD|RD_s, 0, I1 }, +{"bltzl", "s,p", 0x04020000, 0xfc1f0000, CBL|RD_s, 0, I2 }, +{"bltzal", "s,p", 0x04100000, 0xfc1f0000, CBD|RD_s|WR_31, 0, I1 }, +{"bltzall", "s,p", 0x04120000, 0xfc1f0000, CBL|RD_s|WR_31, 0, I2 }, +{"bnez", "s,p", 0x14000000, 0xfc1f0000, CBD|RD_s, 0, I1 }, +{"bnezl", "s,p", 0x54000000, 0xfc1f0000, CBL|RD_s, 0, I2 }, +{"bne", "s,t,p", 0x14000000, 0xfc000000, CBD|RD_s|RD_t, 0, I1 }, +{"bnel", "s,t,p", 0x54000000, 0xfc000000, CBL|RD_s|RD_t, 0, I2 }, +{"break", "", 0x0000000d, 0xffffffff, TRAP, 0, I1 }, +{"break", "c", 0x0000000d, 0xfc00ffff, TRAP, 0, I1 }, +{"break", "c,q", 0x0000000d, 0xfc00003f, TRAP, 0, I1 }, +{"c.f.d", "S,T", 0x46200030, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I1 }, +{"c.f.d", "M,S,T", 0x46200030, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I4_32 }, +{"c.f.s", "S,T", 0x46000030, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, 0, I1 }, +{"c.f.s", "M,S,T", 0x46000030, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, I4_32 }, +{"c.f.ps", "M,S,T", 0x46c00030, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I5_33 }, +{"c.un.d", "S,T", 0x46200031, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I1 }, +{"c.un.d", "M,S,T", 0x46200031, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I4_32 }, +{"c.un.s", "S,T", 0x46000031, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, 0, I1 }, +{"c.un.s", "M,S,T", 0x46000031, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, I4_32 }, +{"c.un.ps", "M,S,T", 0x46c00031, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I5_33 }, +{"c.eq.d", "S,T", 0x46200032, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I1 }, +{"c.eq.d", "M,S,T", 0x46200032, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I4_32 }, +{"c.eq.s", "S,T", 0x46000032, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, 0, I1 }, +{"c.eq.s", "M,S,T", 0x46000032, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, I4_32 }, +{"c.eq.ps", "M,S,T", 0x46c00032, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I5_33 }, +{"c.ueq.d", "S,T", 0x46200033, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I1 }, +{"c.ueq.d", "M,S,T", 0x46200033, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I4_32 }, +{"c.ueq.s", "S,T", 0x46000033, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, 0, I1 }, +{"c.ueq.s", "M,S,T", 0x46000033, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, I4_32 }, +{"c.ueq.ps","M,S,T", 0x46c00033, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I5_33 }, +{"c.olt.d", "S,T", 0x46200034, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I1 }, +{"c.olt.d", "M,S,T", 0x46200034, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I4_32 }, +{"c.olt.s", "S,T", 0x46000034, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, 0, I1 }, +{"c.olt.s", "M,S,T", 0x46000034, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, I4_32 }, +{"c.olt.ps","M,S,T", 0x46c00034, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I5_33 }, +{"c.ult.d", "S,T", 0x46200035, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I1 }, +{"c.ult.d", "M,S,T", 0x46200035, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I4_32 }, +{"c.ult.s", "S,T", 0x46000035, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, 0, I1 }, +{"c.ult.s", "M,S,T", 0x46000035, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, I4_32 }, +{"c.ult.ps","M,S,T", 0x46c00035, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I5_33 }, +{"c.ole.d", "S,T", 0x46200036, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I1 }, +{"c.ole.d", "M,S,T", 0x46200036, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I4_32 }, +{"c.ole.s", "S,T", 0x46000036, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, 0, I1 }, +{"c.ole.s", "M,S,T", 0x46000036, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, I4_32 }, +{"c.ole.ps","M,S,T", 0x46c00036, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I5_33 }, +{"c.ule.d", "S,T", 0x46200037, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I1 }, +{"c.ule.d", "M,S,T", 0x46200037, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I4_32 }, +{"c.ule.s", "S,T", 0x46000037, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, 0, I1 }, +{"c.ule.s", "M,S,T", 0x46000037, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, I4_32 }, +{"c.ule.ps","M,S,T", 0x46c00037, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I5_33 }, +{"c.sf.d", "S,T", 0x46200038, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I1 }, +{"c.sf.d", "M,S,T", 0x46200038, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I4_32 }, +{"c.sf.s", "S,T", 0x46000038, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, 0, I1 }, +{"c.sf.s", "M,S,T", 0x46000038, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, I4_32 }, +{"c.sf.ps", "M,S,T", 0x46c00038, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I5_33 }, +{"c.ngle.d","S,T", 0x46200039, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I1 }, +{"c.ngle.d","M,S,T", 0x46200039, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I4_32 }, +{"c.ngle.s","S,T", 0x46000039, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, 0, I1 }, +{"c.ngle.s","M,S,T", 0x46000039, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, I4_32 }, +{"c.ngle.ps","M,S,T", 0x46c00039, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I5_33 }, +{"c.seq.d", "S,T", 0x4620003a, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I1 }, +{"c.seq.d", "M,S,T", 0x4620003a, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I4_32 }, +{"c.seq.s", "S,T", 0x4600003a, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, 0, I1 }, +{"c.seq.s", "M,S,T", 0x4600003a, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, I4_32 }, +{"c.seq.ps","M,S,T", 0x46c0003a, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I5_33 }, +{"c.ngl.d", "S,T", 0x4620003b, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I1 }, +{"c.ngl.d", "M,S,T", 0x4620003b, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I4_32 }, +{"c.ngl.s", "S,T", 0x4600003b, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, 0, I1 }, +{"c.ngl.s", "M,S,T", 0x4600003b, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, I4_32 }, +{"c.ngl.ps","M,S,T", 0x46c0003b, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I5_33 }, +{"c.lt.d", "S,T", 0x4620003c, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I1 }, +{"c.lt.d", "M,S,T", 0x4620003c, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I4_32 }, +{"c.lt.s", "S,T", 0x4600003c, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, 0, I1 }, +{"c.lt.s", "M,S,T", 0x4600003c, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, I4_32 }, +{"c.lt.ps", "M,S,T", 0x46c0003c, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I5_33 }, +{"c.nge.d", "S,T", 0x4620003d, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I1 }, +{"c.nge.d", "M,S,T", 0x4620003d, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I4_32 }, +{"c.nge.s", "S,T", 0x4600003d, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, 0, I1 }, +{"c.nge.s", "M,S,T", 0x4600003d, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, I4_32 }, +{"c.nge.ps","M,S,T", 0x46c0003d, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I5_33 }, +{"c.le.d", "S,T", 0x4620003e, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I1 }, +{"c.le.d", "M,S,T", 0x4620003e, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I4_32 }, +{"c.le.s", "S,T", 0x4600003e, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, 0, I1 }, +{"c.le.s", "M,S,T", 0x4600003e, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, I4_32 }, +{"c.le.ps", "M,S,T", 0x46c0003e, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I5_33 }, +{"c.ngt.d", "S,T", 0x4620003f, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I1 }, +{"c.ngt.d", "M,S,T", 0x4620003f, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I4_32 }, +{"c.ngt.s", "S,T", 0x4600003f, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, 0, I1 }, +{"c.ngt.s", "M,S,T", 0x4600003f, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, I4_32 }, +{"c.ngt.ps","M,S,T", 0x46c0003f, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I5_33 }, +/* CW4010 instructions which are aliases for the cache instruction. */ +{"cache", "k,o(b)", 0xbc000000, 0xfc000000, RD_b, 0, I3_32 }, +{"ceil.l.d", "D,S", 0x4620000a, 0xffff003f, WR_D|RD_S|FP_D, 0, I3_33 }, +{"ceil.l.s", "D,S", 0x4600000a, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I3_33 }, +{"ceil.w.d", "D,S", 0x4620000e, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I2 }, +{"ceil.w.s", "D,S", 0x4600000e, 0xffff003f, WR_D|RD_S|FP_S, 0, I2 }, +{"cfc0", "t,G", 0x40400000, 0xffe007ff, LCD|WR_t|RD_C0, 0, I1 }, +{"cfc1", "t,G", 0x44400000, 0xffe007ff, LCD|WR_t|RD_C1|FP_S, 0, I1 }, +{"cfc1", "t,S", 0x44400000, 0xffe007ff, LCD|WR_t|RD_C1|FP_S, 0, I1 }, +/* cfc2 is at the bottom of the table. */ +/* cfc3 is at the bottom of the table. */ +{"cftc1", "d,E", 0x41000023, 0xffe007ff, TRAP|LCD|WR_d|RD_C1|FP_S, 0, MT32 }, +{"cftc1", "d,T", 0x41000023, 0xffe007ff, TRAP|LCD|WR_d|RD_C1|FP_S, 0, MT32 }, +{"cftc2", "d,E", 0x41000025, 0xffe007ff, TRAP|LCD|WR_d|RD_C2, 0, MT32 }, +{"clo", "U,s", 0x70000021, 0xfc0007ff, WR_d|WR_t|RD_s, 0, I32 }, +{"clz", "U,s", 0x70000020, 0xfc0007ff, WR_d|WR_t|RD_s, 0, I32 }, +{"ctc0", "t,G", 0x40c00000, 0xffe007ff, COD|RD_t|WR_CC, 0, I1 }, +{"ctc1", "t,G", 0x44c00000, 0xffe007ff, COD|RD_t|WR_CC|FP_S, 0, I1 }, +{"ctc1", "t,S", 0x44c00000, 0xffe007ff, COD|RD_t|WR_CC|FP_S, 0, I1 }, +/* ctc2 is at the bottom of the table. */ +/* ctc3 is at the bottom of the table. */ +{"cttc1", "t,g", 0x41800023, 0xffe007ff, TRAP|COD|RD_t|WR_CC|FP_S, 0, MT32 }, +{"cttc1", "t,S", 0x41800023, 0xffe007ff, TRAP|COD|RD_t|WR_CC|FP_S, 0, MT32 }, +{"cttc2", "t,g", 0x41800025, 0xffe007ff, TRAP|COD|RD_t|WR_CC, 0, MT32 }, +{"cvt.d.l", "D,S", 0x46a00021, 0xffff003f, WR_D|RD_S|FP_D, 0, I3_33 }, +{"cvt.d.s", "D,S", 0x46000021, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I1 }, +{"cvt.d.w", "D,S", 0x46800021, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I1 }, +{"cvt.l.d", "D,S", 0x46200025, 0xffff003f, WR_D|RD_S|FP_D, 0, I3_33 }, +{"cvt.l.s", "D,S", 0x46000025, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I3_33 }, +{"cvt.s.l", "D,S", 0x46a00020, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I3_33 }, +{"cvt.s.d", "D,S", 0x46200020, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I1 }, +{"cvt.s.w", "D,S", 0x46800020, 0xffff003f, WR_D|RD_S|FP_S, 0, I1 }, +{"cvt.s.pl","D,S", 0x46c00028, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I5_33 }, +{"cvt.s.pu","D,S", 0x46c00020, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I5_33 }, +{"cvt.w.d", "D,S", 0x46200024, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I1 }, +{"cvt.w.s", "D,S", 0x46000024, 0xffff003f, WR_D|RD_S|FP_S, 0, I1 }, +{"cvt.ps.s","D,V,T", 0x46000026, 0xffe0003f, WR_D|RD_S|RD_T|FP_S|FP_D, 0, I5_33 }, +{"dadd", "d,v,t", 0x0000002c, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I3 }, +{"daddi", "t,r,j", 0x60000000, 0xfc000000, WR_t|RD_s, 0, I3 }, +{"daddiu", "t,r,j", 0x64000000, 0xfc000000, WR_t|RD_s, 0, I3 }, +{"daddu", "d,v,t", 0x0000002d, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I3 }, +{"dclo", "U,s", 0x70000025, 0xfc0007ff, RD_s|WR_d|WR_t, 0, I64 }, +{"dclz", "U,s", 0x70000024, 0xfc0007ff, RD_s|WR_d|WR_t, 0, I64 }, +/* dctr and dctw are used on the r5000. */ +{"dctr", "o(b)", 0xbc050000, 0xfc1f0000, RD_b, 0, I3 }, +{"dctw", "o(b)", 0xbc090000, 0xfc1f0000, RD_b, 0, I3 }, +{"deret", "", 0x4200001f, 0xffffffff, 0, 0, I32 }, +{"dext", "t,r,+A,+C", 0x7c000003, 0xfc00003f, WR_t|RD_s, 0, I65 }, +{"dextm", "t,r,+A,+G", 0x7c000001, 0xfc00003f, WR_t|RD_s, 0, I65 }, +{"dextu", "t,r,+E,+H", 0x7c000002, 0xfc00003f, WR_t|RD_s, 0, I65 }, +/* For ddiv, see the comments about div. */ +{"ddiv", "z,s,t", 0x0000001e, 0xfc00ffff, RD_s|RD_t|WR_HILO, 0, I3 }, +/* For ddivu, see the comments about div. */ +{"ddivu", "z,s,t", 0x0000001f, 0xfc00ffff, RD_s|RD_t|WR_HILO, 0, I3 }, +{"di", "", 0x41606000, 0xffffffff, WR_t|WR_C0, 0, I33 }, +{"di", "t", 0x41606000, 0xffe0ffff, WR_t|WR_C0, 0, I33 }, +{"dins", "t,r,+A,+B", 0x7c000007, 0xfc00003f, WR_t|RD_s, 0, I65 }, +{"dinsm", "t,r,+A,+F", 0x7c000005, 0xfc00003f, WR_t|RD_s, 0, I65 }, +{"dinsu", "t,r,+E,+F", 0x7c000006, 0xfc00003f, WR_t|RD_s, 0, I65 }, +/* The MIPS assembler treats the div opcode with two operands as + though the first operand appeared twice (the first operand is both + a source and a destination). To get the div machine instruction, + you must use an explicit destination of $0. */ +{"div", "z,s,t", 0x0000001a, 0xfc00ffff, RD_s|RD_t|WR_HILO, 0, I1 }, +{"div", "z,t", 0x0000001a, 0xffe0ffff, RD_s|RD_t|WR_HILO, 0, I1 }, +{"div.d", "D,V,T", 0x46200003, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I1 }, +{"div.s", "D,V,T", 0x46000003, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, 0, I1 }, +/* For divu, see the comments about div. */ +{"divu", "z,s,t", 0x0000001b, 0xfc00ffff, RD_s|RD_t|WR_HILO, 0, I1 }, +{"divu", "z,t", 0x0000001b, 0xffe0ffff, RD_s|RD_t|WR_HILO, 0, I1 }, +{"dli", "t,j", 0x24000000, 0xffe00000, WR_t, 0, I3 }, /* addiu */ +{"dli", "t,i", 0x34000000, 0xffe00000, WR_t, 0, I3 }, /* ori */ +{"dmfc0", "t,G", 0x40200000, 0xffe007ff, LCD|WR_t|RD_C0, 0, I3 }, +{"dmfc0", "t,+D", 0x40200000, 0xffe007f8, LCD|WR_t|RD_C0, 0, I64 }, +{"dmfc0", "t,G,H", 0x40200000, 0xffe007f8, LCD|WR_t|RD_C0, 0, I64 }, +{"dmt", "", 0x41600bc1, 0xffffffff, TRAP, 0, MT32 }, +{"dmt", "t", 0x41600bc1, 0xffe0ffff, TRAP|WR_t, 0, MT32 }, +{"dmtc0", "t,G", 0x40a00000, 0xffe007ff, COD|RD_t|WR_C0|WR_CC, 0, I3 }, +{"dmtc0", "t,+D", 0x40a00000, 0xffe007f8, COD|RD_t|WR_C0|WR_CC, 0, I64 }, +{"dmtc0", "t,G,H", 0x40a00000, 0xffe007f8, COD|RD_t|WR_C0|WR_CC, 0, I64 }, +{"dmfc1", "t,S", 0x44200000, 0xffe007ff, LCD|WR_t|RD_S|FP_D, 0, I3 }, +{"dmfc1", "t,G", 0x44200000, 0xffe007ff, LCD|WR_t|RD_S|FP_D, 0, I3 }, +{"dmtc1", "t,S", 0x44a00000, 0xffe007ff, COD|RD_t|WR_S|FP_D, 0, I3 }, +{"dmtc1", "t,G", 0x44a00000, 0xffe007ff, COD|RD_t|WR_S|FP_D, 0, I3 }, +/* dmfc2 is at the bottom of the table. */ +/* dmtc2 is at the bottom of the table. */ +/* dmfc3 is at the bottom of the table. */ +/* dmtc3 is at the bottom of the table. */ +{"dmult", "s,t", 0x0000001c, 0xfc00ffff, RD_s|RD_t|WR_HILO, 0, I3 }, +{"dmultu", "s,t", 0x0000001d, 0xfc00ffff, RD_s|RD_t|WR_HILO, 0, I3 }, +{"dneg", "d,w", 0x0000002e, 0xffe007ff, WR_d|RD_t, 0, I3 }, /* dsub 0 */ +{"dnegu", "d,w", 0x0000002f, 0xffe007ff, WR_d|RD_t, 0, I3 }, /* dsubu 0*/ +{"drem", "z,s,t", 0x0000001e, 0xfc00ffff, RD_s|RD_t|WR_HILO, 0, I3 }, +{"dremu", "z,s,t", 0x0000001f, 0xfc00ffff, RD_s|RD_t|WR_HILO, 0, I3 }, +{"drorv", "d,t,s", 0x00000056, 0xfc0007ff, RD_t|RD_s|WR_d, 0, I65 }, +{"dror32", "d,w,<", 0x0020003e, 0xffe0003f, WR_d|RD_t, 0, I65 }, +{"dsbh", "d,w", 0x7c0000a4, 0xffe007ff, WR_d|RD_t, 0, I65 }, +{"dshd", "d,w", 0x7c000164, 0xffe007ff, WR_d|RD_t, 0, I65 }, +{"dsllv", "d,t,s", 0x00000014, 0xfc0007ff, WR_d|RD_t|RD_s, 0, I3 }, +{"dsll32", "d,w,<", 0x0000003c, 0xffe0003f, WR_d|RD_t, 0, I3 }, +{"dsll", "d,w,s", 0x00000014, 0xfc0007ff, WR_d|RD_t|RD_s, 0, I3 }, /* dsllv */ +{"dsll", "d,w,>", 0x0000003c, 0xffe0003f, WR_d|RD_t, 0, I3 }, /* dsll32 */ +{"dsll", "d,w,<", 0x00000038, 0xffe0003f, WR_d|RD_t, 0, I3 }, +{"dsrav", "d,t,s", 0x00000017, 0xfc0007ff, WR_d|RD_t|RD_s, 0, I3 }, +{"dsra32", "d,w,<", 0x0000003f, 0xffe0003f, WR_d|RD_t, 0, I3 }, +{"dsra", "d,w,s", 0x00000017, 0xfc0007ff, WR_d|RD_t|RD_s, 0, I3 }, /* dsrav */ +{"dsra", "d,w,>", 0x0000003f, 0xffe0003f, WR_d|RD_t, 0, I3 }, /* dsra32 */ +{"dsra", "d,w,<", 0x0000003b, 0xffe0003f, WR_d|RD_t, 0, I3 }, +{"dsrlv", "d,t,s", 0x00000016, 0xfc0007ff, WR_d|RD_t|RD_s, 0, I3 }, +{"dsrl32", "d,w,<", 0x0000003e, 0xffe0003f, WR_d|RD_t, 0, I3 }, +{"dsrl", "d,w,s", 0x00000016, 0xfc0007ff, WR_d|RD_t|RD_s, 0, I3 }, /* dsrlv */ +{"dsrl", "d,w,>", 0x0000003e, 0xffe0003f, WR_d|RD_t, 0, I3 }, /* dsrl32 */ +{"dsrl", "d,w,<", 0x0000003a, 0xffe0003f, WR_d|RD_t, 0, I3 }, +{"dsub", "d,v,t", 0x0000002e, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I3 }, +{"dsubu", "d,v,t", 0x0000002f, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I3 }, +{"dvpe", "", 0x41600001, 0xffffffff, TRAP, 0, MT32 }, +{"dvpe", "t", 0x41600001, 0xffe0ffff, TRAP|WR_t, 0, MT32 }, +{"ei", "", 0x41606020, 0xffffffff, WR_t|WR_C0, 0, I33 }, +{"ei", "t", 0x41606020, 0xffe0ffff, WR_t|WR_C0, 0, I33 }, +{"emt", "", 0x41600be1, 0xffffffff, TRAP, 0, MT32 }, +{"emt", "t", 0x41600be1, 0xffe0ffff, TRAP|WR_t, 0, MT32 }, +{"eret", "", 0x42000018, 0xffffffff, 0, 0, I3_32 }, +{"evpe", "", 0x41600021, 0xffffffff, TRAP, 0, MT32 }, +{"evpe", "t", 0x41600021, 0xffe0ffff, TRAP|WR_t, 0, MT32 }, +{"ext", "t,r,+A,+C", 0x7c000000, 0xfc00003f, WR_t|RD_s, 0, I33 }, +{"floor.l.d", "D,S", 0x4620000b, 0xffff003f, WR_D|RD_S|FP_D, 0, I3_33 }, +{"floor.l.s", "D,S", 0x4600000b, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I3_33 }, +{"floor.w.d", "D,S", 0x4620000f, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I2 }, +{"floor.w.s", "D,S", 0x4600000f, 0xffff003f, WR_D|RD_S|FP_S, 0, I2 }, +{"ins", "t,r,+A,+B", 0x7c000004, 0xfc00003f, WR_t|RD_s, 0, I33 }, +{"jr", "s", 0x00000008, 0xfc1fffff, UBD|RD_s, 0, I1 }, +/* jr.hb is officially MIPS{32,64}R2, but it works on R1 as jr with + the same hazard barrier effect. */ +{"jr.hb", "s", 0x00000408, 0xfc1fffff, UBD|RD_s, 0, I32 }, +{"j", "s", 0x00000008, 0xfc1fffff, UBD|RD_s, 0, I1 }, /* jr */ +/* This form of j is used by the disassembler and internally by the + assembler, but will never match user input (because the line above + will match first). */ +{"j", "a", 0x08000000, 0xfc000000, UBD, 0, I1 }, +{"jalr", "s", 0x0000f809, 0xfc1fffff, UBD|RD_s|WR_d, 0, I1 }, +{"jalr", "d,s", 0x00000009, 0xfc1f07ff, UBD|RD_s|WR_d, 0, I1 }, +/* jalr.hb is officially MIPS{32,64}R2, but it works on R1 as jalr + with the same hazard barrier effect. */ +{"jalr.hb", "s", 0x0000fc09, 0xfc1fffff, UBD|RD_s|WR_d, 0, I32 }, +{"jalr.hb", "d,s", 0x00000409, 0xfc1f07ff, UBD|RD_s|WR_d, 0, I32 }, +/* This form of jal is used by the disassembler and internally by the + assembler, but will never match user input (because the line above + will match first). */ +{"jal", "a", 0x0c000000, 0xfc000000, UBD|WR_31, 0, I1 }, +{"jalx", "a", 0x74000000, 0xfc000000, UBD|WR_31, 0, I1 }, +{"lb", "t,o(b)", 0x80000000, 0xfc000000, LDD|RD_b|WR_t, 0, I1 }, +{"lbu", "t,o(b)", 0x90000000, 0xfc000000, LDD|RD_b|WR_t, 0, I1 }, +{"ld", "t,o(b)", 0xdc000000, 0xfc000000, WR_t|RD_b, 0, I3 }, +{"ldc1", "T,o(b)", 0xd4000000, 0xfc000000, CLD|RD_b|WR_T|FP_D, 0, I2 }, +{"ldc1", "E,o(b)", 0xd4000000, 0xfc000000, CLD|RD_b|WR_T|FP_D, 0, I2 }, +{"l.d", "T,o(b)", 0xd4000000, 0xfc000000, CLD|RD_b|WR_T|FP_D, 0, I2 }, /* ldc1 */ +{"ldc2", "E,o(b)", 0xd8000000, 0xfc000000, CLD|RD_b|WR_CC, 0, I2 }, +{"ldc3", "E,o(b)", 0xdc000000, 0xfc000000, CLD|RD_b|WR_CC, 0, I2 }, +{"ldl", "t,o(b)", 0x68000000, 0xfc000000, LDD|WR_t|RD_b, 0, I3 }, +{"ldr", "t,o(b)", 0x6c000000, 0xfc000000, LDD|WR_t|RD_b, 0, I3 }, +{"ldxc1", "D,t(b)", 0x4c000001, 0xfc00f83f, LDD|WR_D|RD_t|RD_b|FP_D, 0, I4_33 }, +{"lh", "t,o(b)", 0x84000000, 0xfc000000, LDD|RD_b|WR_t, 0, I1 }, +{"lhu", "t,o(b)", 0x94000000, 0xfc000000, LDD|RD_b|WR_t, 0, I1 }, +{"ll", "t,o(b)", 0xc0000000, 0xfc000000, LDD|RD_b|WR_t, 0, I2 }, +{"lld", "t,o(b)", 0xd0000000, 0xfc000000, LDD|RD_b|WR_t, 0, I3 }, +{"lui", "t,u", 0x3c000000, 0xffe00000, WR_t, 0, I1 }, +{"luxc1", "D,t(b)", 0x4c000005, 0xfc00f83f, LDD|WR_D|RD_t|RD_b|FP_D, 0, I5_33 }, +{"lw", "t,o(b)", 0x8c000000, 0xfc000000, LDD|RD_b|WR_t, 0, I1 }, +{"lwc0", "E,o(b)", 0xc0000000, 0xfc000000, CLD|RD_b|WR_CC, 0, I1 }, +{"lwc1", "T,o(b)", 0xc4000000, 0xfc000000, CLD|RD_b|WR_T|FP_S, 0, I1 }, +{"lwc1", "E,o(b)", 0xc4000000, 0xfc000000, CLD|RD_b|WR_T|FP_S, 0, I1 }, +{"l.s", "T,o(b)", 0xc4000000, 0xfc000000, CLD|RD_b|WR_T|FP_S, 0, I1 }, /* lwc1 */ +{"lwc2", "E,o(b)", 0xc8000000, 0xfc000000, CLD|RD_b|WR_CC, 0, I1 }, +{"lwc3", "E,o(b)", 0xcc000000, 0xfc000000, CLD|RD_b|WR_CC, 0, I1 }, +{"lwl", "t,o(b)", 0x88000000, 0xfc000000, LDD|RD_b|WR_t, 0, I1 }, +{"lcache", "t,o(b)", 0x88000000, 0xfc000000, LDD|RD_b|WR_t, 0, I2 }, /* same */ +{"lwr", "t,o(b)", 0x98000000, 0xfc000000, LDD|RD_b|WR_t, 0, I1 }, +{"flush", "t,o(b)", 0x98000000, 0xfc000000, LDD|RD_b|WR_t, 0, I2 }, /* same */ +{"fork", "d,s,t", 0x7c000008, 0xfc0007ff, TRAP|WR_d|RD_s|RD_t, 0, MT32 }, +{"lwu", "t,o(b)", 0x9c000000, 0xfc000000, LDD|RD_b|WR_t, 0, I3 }, +{"lwxc1", "D,t(b)", 0x4c000000, 0xfc00f83f, LDD|WR_D|RD_t|RD_b|FP_S, 0, I4_33 }, +{"lwxs", "d,t(b)", 0x70000088, 0xfc0007ff, LDD|RD_b|RD_t|WR_d, 0, SMT }, +{"madd.d", "D,R,S,T", 0x4c000021, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D, 0, I4_33 }, +{"madd.s", "D,R,S,T", 0x4c000020, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_S, 0, I4_33 }, +{"madd.ps", "D,R,S,T", 0x4c000026, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D, 0, I5_33 }, +{"madd", "s,t", 0x70000000, 0xfc00ffff, RD_s|RD_t|MOD_HILO, 0, I32 }, +{"madd", "7,s,t", 0x70000000, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D32 }, +{"maddp", "s,t", 0x70000441, 0xfc00ffff, RD_s|RD_t|MOD_HILO, 0, SMT }, +{"maddu", "s,t", 0x70000001, 0xfc00ffff, RD_s|RD_t|MOD_HILO, 0, I32 }, +{"maddu", "7,s,t", 0x70000001, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D32 }, +{"mftacx", "d", 0x41020021, 0xffff07ff, TRAP|WR_d|RD_a, 0, MT32 }, +{"mftacx", "d,*", 0x41020021, 0xfff307ff, TRAP|WR_d|RD_a, 0, MT32 }, +{"mftc0", "d,+t", 0x41000000, 0xffe007ff, TRAP|LCD|WR_d|RD_C0, 0, MT32 }, +{"mftc0", "d,+T", 0x41000000, 0xffe007f8, TRAP|LCD|WR_d|RD_C0, 0, MT32 }, +{"mftc0", "d,E,H", 0x41000000, 0xffe007f8, TRAP|LCD|WR_d|RD_C0, 0, MT32 }, +{"mftc1", "d,T", 0x41000022, 0xffe007ff, TRAP|LCD|WR_d|RD_T|FP_S, 0, MT32 }, +{"mftc1", "d,E", 0x41000022, 0xffe007ff, TRAP|LCD|WR_d|RD_T|FP_S, 0, MT32 }, +{"mftc2", "d,E", 0x41000024, 0xffe007ff, TRAP|LCD|WR_d|RD_C2, 0, MT32 }, +{"mftdsp", "d", 0x41100021, 0xffff07ff, TRAP|WR_d, 0, MT32 }, +{"mftgpr", "d,t", 0x41000020, 0xffe007ff, TRAP|WR_d|RD_t, 0, MT32 }, +{"mfthc1", "d,T", 0x41000032, 0xffe007ff, TRAP|LCD|WR_d|RD_T|FP_D, 0, MT32 }, +{"mfthc1", "d,E", 0x41000032, 0xffe007ff, TRAP|LCD|WR_d|RD_T|FP_D, 0, MT32 }, +{"mfthc2", "d,E", 0x41000034, 0xffe007ff, TRAP|LCD|WR_d|RD_C2, 0, MT32 }, +{"mfthi", "d", 0x41010021, 0xffff07ff, TRAP|WR_d|RD_a, 0, MT32 }, +{"mfthi", "d,*", 0x41010021, 0xfff307ff, TRAP|WR_d|RD_a, 0, MT32 }, +{"mftlo", "d", 0x41000021, 0xffff07ff, TRAP|WR_d|RD_a, 0, MT32 }, +{"mftlo", "d,*", 0x41000021, 0xfff307ff, TRAP|WR_d|RD_a, 0, MT32 }, +{"mftr", "d,t,!,H,$", 0x41000000, 0xffe007c8, TRAP|WR_d, 0, MT32 }, +{"mfc0", "t,G", 0x40000000, 0xffe007ff, LCD|WR_t|RD_C0, 0, I1 }, +{"mfc0", "t,+D", 0x40000000, 0xffe007f8, LCD|WR_t|RD_C0, 0, I32 }, +{"mfc0", "t,G,H", 0x40000000, 0xffe007f8, LCD|WR_t|RD_C0, 0, I32 }, +{"mfc1", "t,S", 0x44000000, 0xffe007ff, LCD|WR_t|RD_S|FP_S, 0, I1 }, +{"mfc1", "t,G", 0x44000000, 0xffe007ff, LCD|WR_t|RD_S|FP_S, 0, I1 }, +{"mfhc1", "t,S", 0x44600000, 0xffe007ff, LCD|WR_t|RD_S|FP_D, 0, I33 }, +{"mfhc1", "t,G", 0x44600000, 0xffe007ff, LCD|WR_t|RD_S|FP_D, 0, I33 }, +/* mfc2 is at the bottom of the table. */ +/* mfhc2 is at the bottom of the table. */ +/* mfc3 is at the bottom of the table. */ +{"mfhi", "d", 0x00000010, 0xffff07ff, WR_d|RD_HI, 0, I1 }, +{"mfhi", "d,9", 0x00000010, 0xff9f07ff, WR_d|RD_HI, 0, D32 }, +{"mflo", "d", 0x00000012, 0xffff07ff, WR_d|RD_LO, 0, I1 }, +{"mflo", "d,9", 0x00000012, 0xff9f07ff, WR_d|RD_LO, 0, D32 }, +{"mflhxu", "d", 0x00000052, 0xffff07ff, WR_d|MOD_HILO, 0, SMT }, +{"mov.d", "D,S", 0x46200006, 0xffff003f, WR_D|RD_S|FP_D, 0, I1 }, +{"mov.s", "D,S", 0x46000006, 0xffff003f, WR_D|RD_S|FP_S, 0, I1 }, +{"movf", "d,s,N", 0x00000001, 0xfc0307ff, WR_d|RD_s|RD_CC|FP_S|FP_D, 0, I4_32 }, +{"movf.d", "D,S,N", 0x46200011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D, 0, I4_32 }, +{"movf.s", "D,S,N", 0x46000011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_S, 0, I4_32 }, +{"movf.ps", "D,S,N", 0x46c00011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D, 0, I5_33 }, +{"movn", "d,v,t", 0x0000000b, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I4_32 }, +{"movn.d", "D,S,t", 0x46200013, 0xffe0003f, WR_D|RD_S|RD_t|FP_D, 0, I4_32 }, +{"movn.s", "D,S,t", 0x46000013, 0xffe0003f, WR_D|RD_S|RD_t|FP_S, 0, I4_32 }, +{"movn.ps", "D,S,t", 0x46c00013, 0xffe0003f, WR_D|RD_S|RD_t|FP_D, 0, I5_33 }, +{"movt", "d,s,N", 0x00010001, 0xfc0307ff, WR_d|RD_s|RD_CC|FP_S|FP_D, 0, I4_32 }, +{"movt.d", "D,S,N", 0x46210011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D, 0, I4_32 }, +{"movt.s", "D,S,N", 0x46010011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_S, 0, I4_32 }, +{"movt.ps", "D,S,N", 0x46c10011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D, 0, I5_33 }, +{"movz", "d,v,t", 0x0000000a, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I4_32 }, +{"movz.d", "D,S,t", 0x46200012, 0xffe0003f, WR_D|RD_S|RD_t|FP_D, 0, I4_32 }, +{"movz.s", "D,S,t", 0x46000012, 0xffe0003f, WR_D|RD_S|RD_t|FP_S, 0, I4_32 }, +{"movz.ps", "D,S,t", 0x46c00012, 0xffe0003f, WR_D|RD_S|RD_t|FP_D, 0, I5_33 }, +/* move is at the top of the table. */ +{"msub.d", "D,R,S,T", 0x4c000029, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D, 0, I4_33 }, +{"msub.s", "D,R,S,T", 0x4c000028, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_S, 0, I4_33 }, +{"msub.ps", "D,R,S,T", 0x4c00002e, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D, 0, I5_33 }, +{"msub", "s,t", 0x70000004, 0xfc00ffff, RD_s|RD_t|MOD_HILO, 0, I32 }, +{"msub", "7,s,t", 0x70000004, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D32 }, +{"msubu", "s,t", 0x70000005, 0xfc00ffff, RD_s|RD_t|MOD_HILO, 0, I32 }, +{"msubu", "7,s,t", 0x70000005, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D32 }, +{"mtc0", "t,G", 0x40800000, 0xffe007ff, COD|RD_t|WR_C0|WR_CC, 0, I1 }, +{"mtc0", "t,+D", 0x40800000, 0xffe007f8, COD|RD_t|WR_C0|WR_CC, 0, I32 }, +{"mtc0", "t,G,H", 0x40800000, 0xffe007f8, COD|RD_t|WR_C0|WR_CC, 0, I32 }, +{"mtc1", "t,S", 0x44800000, 0xffe007ff, COD|RD_t|WR_S|FP_S, 0, I1 }, +{"mtc1", "t,G", 0x44800000, 0xffe007ff, COD|RD_t|WR_S|FP_S, 0, I1 }, +{"mthc1", "t,S", 0x44e00000, 0xffe007ff, COD|RD_t|WR_S|FP_D, 0, I33 }, +{"mthc1", "t,G", 0x44e00000, 0xffe007ff, COD|RD_t|WR_S|FP_D, 0, I33 }, +/* mtc2 is at the bottom of the table. */ +/* mthc2 is at the bottom of the table. */ +/* mtc3 is at the bottom of the table. */ +{"mthi", "s", 0x00000011, 0xfc1fffff, RD_s|WR_HI, 0, I1 }, +{"mthi", "s,7", 0x00000011, 0xfc1fe7ff, RD_s|WR_HI, 0, D32 }, +{"mtlo", "s", 0x00000013, 0xfc1fffff, RD_s|WR_LO, 0, I1 }, +{"mtlo", "s,7", 0x00000013, 0xfc1fe7ff, RD_s|WR_LO, 0, D32 }, +{"mtlhx", "s", 0x00000053, 0xfc1fffff, RD_s|MOD_HILO, 0, SMT }, +{"mttc0", "t,G", 0x41800000, 0xffe007ff, TRAP|COD|RD_t|WR_C0|WR_CC, 0, MT32 }, +{"mttc0", "t,+D", 0x41800000, 0xffe007f8, TRAP|COD|RD_t|WR_C0|WR_CC, 0, MT32 }, +{"mttc0", "t,G,H", 0x41800000, 0xffe007f8, TRAP|COD|RD_t|WR_C0|WR_CC, 0, MT32 }, +{"mttc1", "t,S", 0x41800022, 0xffe007ff, TRAP|COD|RD_t|WR_S|FP_S, 0, MT32 }, +{"mttc1", "t,G", 0x41800022, 0xffe007ff, TRAP|COD|RD_t|WR_S|FP_S, 0, MT32 }, +{"mttc2", "t,g", 0x41800024, 0xffe007ff, TRAP|COD|RD_t|WR_C2|WR_CC, 0, MT32 }, +{"mttacx", "t", 0x41801021, 0xffe0ffff, TRAP|WR_a|RD_t, 0, MT32 }, +{"mttacx", "t,&", 0x41801021, 0xffe09fff, TRAP|WR_a|RD_t, 0, MT32 }, +{"mttdsp", "t", 0x41808021, 0xffe0ffff, TRAP|RD_t, 0, MT32 }, +{"mttgpr", "t,d", 0x41800020, 0xffe007ff, TRAP|WR_d|RD_t, 0, MT32 }, +{"mtthc1", "t,S", 0x41800032, 0xffe007ff, TRAP|COD|RD_t|WR_S|FP_D, 0, MT32 }, +{"mtthc1", "t,G", 0x41800032, 0xffe007ff, TRAP|COD|RD_t|WR_S|FP_D, 0, MT32 }, +{"mtthc2", "t,g", 0x41800034, 0xffe007ff, TRAP|COD|RD_t|WR_C2|WR_CC, 0, MT32 }, +{"mtthi", "t", 0x41800821, 0xffe0ffff, TRAP|WR_a|RD_t, 0, MT32 }, +{"mtthi", "t,&", 0x41800821, 0xffe09fff, TRAP|WR_a|RD_t, 0, MT32 }, +{"mttlo", "t", 0x41800021, 0xffe0ffff, TRAP|WR_a|RD_t, 0, MT32 }, +{"mttlo", "t,&", 0x41800021, 0xffe09fff, TRAP|WR_a|RD_t, 0, MT32 }, +{"mttr", "t,d,!,H,$", 0x41800000, 0xffe007c8, TRAP|RD_t, 0, MT32 }, +{"mul.d", "D,V,T", 0x46200002, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I1 }, +{"mul.s", "D,V,T", 0x46000002, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, 0, I1 }, +{"mul", "d,v,t", 0x70000002, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0, I32 }, +{"mult", "s,t", 0x00000018, 0xfc00ffff, RD_s|RD_t|WR_HILO|IS_M, 0, I1 }, +{"mult", "7,s,t", 0x00000018, 0xfc00e7ff, WR_a|RD_s|RD_t, 0, D32 }, +{"multp", "s,t", 0x00000459, 0xfc00ffff, RD_s|RD_t|MOD_HILO, 0, SMT }, +{"multu", "s,t", 0x00000019, 0xfc00ffff, RD_s|RD_t|WR_HILO|IS_M, 0, I1 }, +{"multu", "7,s,t", 0x00000019, 0xfc00e7ff, WR_a|RD_s|RD_t, 0, D32 }, +{"neg", "d,w", 0x00000022, 0xffe007ff, WR_d|RD_t, 0, I1 }, /* sub 0 */ +{"negu", "d,w", 0x00000023, 0xffe007ff, WR_d|RD_t, 0, I1 }, /* subu 0 */ +{"neg.d", "D,V", 0x46200007, 0xffff003f, WR_D|RD_S|FP_D, 0, I1 }, +{"neg.s", "D,V", 0x46000007, 0xffff003f, WR_D|RD_S|FP_S, 0, I1 }, +{"nmadd.d", "D,R,S,T", 0x4c000031, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D, 0, I4_33 }, +{"nmadd.s", "D,R,S,T", 0x4c000030, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_S, 0, I4_33 }, +{"nmadd.ps","D,R,S,T", 0x4c000036, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D, 0, I5_33 }, +{"nmsub.d", "D,R,S,T", 0x4c000039, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D, 0, I4_33 }, +{"nmsub.s", "D,R,S,T", 0x4c000038, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_S, 0, I4_33 }, +{"nmsub.ps","D,R,S,T", 0x4c00003e, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D, 0, I5_33 }, +/* nop is at the start of the table. */ +{"nor", "d,v,t", 0x00000027, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I1 }, +{"not", "d,v", 0x00000027, 0xfc1f07ff, WR_d|RD_s|RD_t, 0, I1 },/*nor d,s,0*/ +{"or", "d,v,t", 0x00000025, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I1 }, +{"ori", "t,r,i", 0x34000000, 0xfc000000, WR_t|RD_s, 0, I1 }, +{"pll.ps", "D,V,T", 0x46c0002c, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I5_33 }, +{"plu.ps", "D,V,T", 0x46c0002d, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I5_33 }, + /* pref and prefx are at the start of the table. */ +{"pul.ps", "D,V,T", 0x46c0002e, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I5_33 }, +{"puu.ps", "D,V,T", 0x46c0002f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I5_33 }, +{"pperm", "s,t", 0x70000481, 0xfc00ffff, MOD_HILO|RD_s|RD_t, 0, SMT }, +{"recip.d", "D,S", 0x46200015, 0xffff003f, WR_D|RD_S|FP_D, 0, I4_33 }, +{"recip.s", "D,S", 0x46000015, 0xffff003f, WR_D|RD_S|FP_S, 0, I4_33 }, +{"rem", "z,s,t", 0x0000001a, 0xfc00ffff, RD_s|RD_t|WR_HILO, 0, I1 }, +{"remu", "z,s,t", 0x0000001b, 0xfc00ffff, RD_s|RD_t|WR_HILO, 0, I1 }, +{"rdhwr", "t,K", 0x7c00003b, 0xffe007ff, WR_t, 0, I33 }, +{"rdpgpr", "d,w", 0x41400000, 0xffe007ff, WR_d, 0, I33 }, +{"rfe", "", 0x42000010, 0xffffffff, 0, 0, I1 }, +{"ror", "d,w,<", 0x00200002, 0xffe0003f, WR_d|RD_t, 0, I33|SMT }, +{"rorv", "d,t,s", 0x00000046, 0xfc0007ff, RD_t|RD_s|WR_d, 0, I33|SMT }, +{"round.l.d", "D,S", 0x46200008, 0xffff003f, WR_D|RD_S|FP_D, 0, I3_33 }, +{"round.l.s", "D,S", 0x46000008, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I3_33 }, +{"round.w.d", "D,S", 0x4620000c, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I2 }, +{"round.w.s", "D,S", 0x4600000c, 0xffff003f, WR_D|RD_S|FP_S, 0, I2 }, +{"rsqrt.d", "D,S", 0x46200016, 0xffff003f, WR_D|RD_S|FP_D, 0, I4_33 }, +{"rsqrt.s", "D,S", 0x46000016, 0xffff003f, WR_D|RD_S|FP_S, 0, I4_33 }, +{"sb", "t,o(b)", 0xa0000000, 0xfc000000, SM|RD_t|RD_b, 0, I1 }, +{"sc", "t,o(b)", 0xe0000000, 0xfc000000, SM|RD_t|WR_t|RD_b, 0, I2 }, +{"scd", "t,o(b)", 0xf0000000, 0xfc000000, SM|RD_t|WR_t|RD_b, 0, I3 }, +{"sd", "t,o(b)", 0xfc000000, 0xfc000000, SM|RD_t|RD_b, 0, I3 }, +{"sdbbp", "", 0x7000003f, 0xffffffff, TRAP, 0, I32 }, +{"sdbbp", "B", 0x7000003f, 0xfc00003f, TRAP, 0, I32 }, +{"sdc1", "T,o(b)", 0xf4000000, 0xfc000000, SM|RD_T|RD_b|FP_D, 0, I2 }, +{"sdc1", "E,o(b)", 0xf4000000, 0xfc000000, SM|RD_T|RD_b|FP_D, 0, I2 }, +{"sdc2", "E,o(b)", 0xf8000000, 0xfc000000, SM|RD_C2|RD_b, 0, I2 }, +{"sdc3", "E,o(b)", 0xfc000000, 0xfc000000, SM|RD_C3|RD_b, 0, I2 }, +{"s.d", "T,o(b)", 0xf4000000, 0xfc000000, SM|RD_T|RD_b|FP_D, 0, I2 }, +{"sdl", "t,o(b)", 0xb0000000, 0xfc000000, SM|RD_t|RD_b, 0, I3 }, +{"sdr", "t,o(b)", 0xb4000000, 0xfc000000, SM|RD_t|RD_b, 0, I3 }, +{"sdxc1", "S,t(b)", 0x4c000009, 0xfc0007ff, SM|RD_S|RD_t|RD_b|FP_D, 0, I4_33 }, +{"seb", "d,w", 0x7c000420, 0xffe007ff, WR_d|RD_t, 0, I33 }, +{"seh", "d,w", 0x7c000620, 0xffe007ff, WR_d|RD_t, 0, I33 }, +{"sh", "t,o(b)", 0xa4000000, 0xfc000000, SM|RD_t|RD_b, 0, I1 }, +{"sllv", "d,t,s", 0x00000004, 0xfc0007ff, WR_d|RD_t|RD_s, 0, I1 }, +{"sll", "d,w,s", 0x00000004, 0xfc0007ff, WR_d|RD_t|RD_s, 0, I1 }, /* sllv */ +{"sll", "d,w,<", 0x00000000, 0xffe0003f, WR_d|RD_t, 0, I1 }, +{"slt", "d,v,t", 0x0000002a, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I1 }, +{"slti", "t,r,j", 0x28000000, 0xfc000000, WR_t|RD_s, 0, I1 }, +{"sltiu", "t,r,j", 0x2c000000, 0xfc000000, WR_t|RD_s, 0, I1 }, +{"sltu", "d,v,t", 0x0000002b, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I1 }, +{"sqrt.d", "D,S", 0x46200004, 0xffff003f, WR_D|RD_S|FP_D, 0, I2 }, +{"sqrt.s", "D,S", 0x46000004, 0xffff003f, WR_D|RD_S|FP_S, 0, I2 }, +{"srav", "d,t,s", 0x00000007, 0xfc0007ff, WR_d|RD_t|RD_s, 0, I1 }, +{"sra", "d,w,s", 0x00000007, 0xfc0007ff, WR_d|RD_t|RD_s, 0, I1 }, /* srav */ +{"sra", "d,w,<", 0x00000003, 0xffe0003f, WR_d|RD_t, 0, I1 }, +{"srlv", "d,t,s", 0x00000006, 0xfc0007ff, WR_d|RD_t|RD_s, 0, I1 }, +{"srl", "d,w,s", 0x00000006, 0xfc0007ff, WR_d|RD_t|RD_s, 0, I1 }, /* srlv */ +{"srl", "d,w,<", 0x00000002, 0xffe0003f, WR_d|RD_t, 0, I1 }, +/* ssnop is at the start of the table. */ +{"sub", "d,v,t", 0x00000022, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I1 }, +{"sub.d", "D,V,T", 0x46200001, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I1 }, +{"sub.s", "D,V,T", 0x46000001, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, 0, I1 }, +{"subu", "d,v,t", 0x00000023, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I1 }, +{"suxc1", "S,t(b)", 0x4c00000d, 0xfc0007ff, SM|RD_S|RD_t|RD_b|FP_D, 0, I5_33 }, +{"sw", "t,o(b)", 0xac000000, 0xfc000000, SM|RD_t|RD_b, 0, I1 }, +{"swc0", "E,o(b)", 0xe0000000, 0xfc000000, SM|RD_C0|RD_b, 0, I1 }, +{"swc1", "T,o(b)", 0xe4000000, 0xfc000000, SM|RD_T|RD_b|FP_S, 0, I1 }, +{"swc1", "E,o(b)", 0xe4000000, 0xfc000000, SM|RD_T|RD_b|FP_S, 0, I1 }, +{"s.s", "T,o(b)", 0xe4000000, 0xfc000000, SM|RD_T|RD_b|FP_S, 0, I1 }, /* swc1 */ +{"swc2", "E,o(b)", 0xe8000000, 0xfc000000, SM|RD_C2|RD_b, 0, I1 }, +{"swc3", "E,o(b)", 0xec000000, 0xfc000000, SM|RD_C3|RD_b, 0, I1 }, +{"swl", "t,o(b)", 0xa8000000, 0xfc000000, SM|RD_t|RD_b, 0, I1 }, +{"scache", "t,o(b)", 0xa8000000, 0xfc000000, RD_t|RD_b, 0, I2 }, /* same */ +{"swr", "t,o(b)", 0xb8000000, 0xfc000000, SM|RD_t|RD_b, 0, I1 }, +{"invalidate", "t,o(b)",0xb8000000, 0xfc000000, RD_t|RD_b, 0, I2 }, /* same */ +{"swxc1", "S,t(b)", 0x4c000008, 0xfc0007ff, SM|RD_S|RD_t|RD_b|FP_S, 0, I4_33 }, +{"sync_acquire", "", 0x0000044f, 0xffffffff, INSN_SYNC, 0, I33 }, +{"sync_mb", "", 0x0000040f, 0xffffffff, INSN_SYNC, 0, I33 }, +{"sync_release", "", 0x0000048f, 0xffffffff, INSN_SYNC, 0, I33 }, +{"sync_rmb", "", 0x000004cf, 0xffffffff, INSN_SYNC, 0, I33 }, +{"sync_wmb", "", 0x0000010f, 0xffffffff, INSN_SYNC, 0, I33 }, +{"sync", "", 0x0000000f, 0xffffffff, INSN_SYNC, 0, I2 }, +{"sync", "1", 0x0000000f, 0xfffff83f, INSN_SYNC, 0, I32 }, +{"sync.p", "", 0x0000040f, 0xffffffff, INSN_SYNC, 0, I2 }, +{"sync.l", "", 0x0000000f, 0xffffffff, INSN_SYNC, 0, I2 }, +{"synci", "o(b)", 0x041f0000, 0xfc1f0000, SM|RD_b, 0, I33 }, +{"syscall", "", 0x0000000c, 0xffffffff, TRAP, 0, I1 }, +{"syscall", "B", 0x0000000c, 0xfc00003f, TRAP, 0, I1 }, +{"teqi", "s,j", 0x040c0000, 0xfc1f0000, RD_s|TRAP, 0, I2 }, +{"teq", "s,t", 0x00000034, 0xfc00ffff, RD_s|RD_t|TRAP, 0, I2 }, +{"teq", "s,t,q", 0x00000034, 0xfc00003f, RD_s|RD_t|TRAP, 0, I2 }, +{"teq", "s,j", 0x040c0000, 0xfc1f0000, RD_s|TRAP, 0, I2 }, /* teqi */ +{"tgei", "s,j", 0x04080000, 0xfc1f0000, RD_s|TRAP, 0, I2 }, +{"tge", "s,t", 0x00000030, 0xfc00ffff, RD_s|RD_t|TRAP, 0, I2 }, +{"tge", "s,t,q", 0x00000030, 0xfc00003f, RD_s|RD_t|TRAP, 0, I2 }, +{"tge", "s,j", 0x04080000, 0xfc1f0000, RD_s|TRAP, 0, I2 }, /* tgei */ +{"tgeiu", "s,j", 0x04090000, 0xfc1f0000, RD_s|TRAP, 0, I2 }, +{"tgeu", "s,t", 0x00000031, 0xfc00ffff, RD_s|RD_t|TRAP, 0, I2 }, +{"tgeu", "s,t,q", 0x00000031, 0xfc00003f, RD_s|RD_t|TRAP, 0, I2 }, +{"tgeu", "s,j", 0x04090000, 0xfc1f0000, RD_s|TRAP, 0, I2 }, /* tgeiu */ +{"tlbp", "", 0x42000008, 0xffffffff, INSN_TLB, 0, I1 }, +{"tlbr", "", 0x42000001, 0xffffffff, INSN_TLB, 0, I1 }, +{"tlbwi", "", 0x42000002, 0xffffffff, INSN_TLB, 0, I1 }, +{"tlbwr", "", 0x42000006, 0xffffffff, INSN_TLB, 0, I1 }, +{"tlti", "s,j", 0x040a0000, 0xfc1f0000, RD_s|TRAP, 0, I2 }, +{"tlt", "s,t", 0x00000032, 0xfc00ffff, RD_s|RD_t|TRAP, 0, I2 }, +{"tlt", "s,t,q", 0x00000032, 0xfc00003f, RD_s|RD_t|TRAP, 0, I2 }, +{"tlt", "s,j", 0x040a0000, 0xfc1f0000, RD_s|TRAP, 0, I2 }, /* tlti */ +{"tltiu", "s,j", 0x040b0000, 0xfc1f0000, RD_s|TRAP, 0, I2 }, +{"tltu", "s,t", 0x00000033, 0xfc00ffff, RD_s|RD_t|TRAP, 0, I2 }, +{"tltu", "s,t,q", 0x00000033, 0xfc00003f, RD_s|RD_t|TRAP, 0, I2 }, +{"tltu", "s,j", 0x040b0000, 0xfc1f0000, RD_s|TRAP, 0, I2 }, /* tltiu */ +{"tnei", "s,j", 0x040e0000, 0xfc1f0000, RD_s|TRAP, 0, I2 }, +{"tne", "s,t", 0x00000036, 0xfc00ffff, RD_s|RD_t|TRAP, 0, I2 }, +{"tne", "s,t,q", 0x00000036, 0xfc00003f, RD_s|RD_t|TRAP, 0, I2 }, +{"tne", "s,j", 0x040e0000, 0xfc1f0000, RD_s|TRAP, 0, I2 }, /* tnei */ +{"trunc.l.d", "D,S", 0x46200009, 0xffff003f, WR_D|RD_S|FP_D, 0, I3_33 }, +{"trunc.l.s", "D,S", 0x46000009, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I3_33 }, +{"trunc.w.d", "D,S", 0x4620000d, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I2 }, +{"trunc.w.d", "D,S,x", 0x4620000d, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I2 }, +{"trunc.w.s", "D,S", 0x4600000d, 0xffff003f, WR_D|RD_S|FP_S, 0, I2 }, +{"trunc.w.s", "D,S,x", 0x4600000d, 0xffff003f, WR_D|RD_S|FP_S, 0, I2 }, +{"wait", "", 0x42000020, 0xffffffff, TRAP, 0, I3_32 }, +{"wait", "J", 0x42000020, 0xfe00003f, TRAP, 0, I32 }, +{"wrpgpr", "d,w", 0x41c00000, 0xffe007ff, RD_t, 0, I33 }, +{"wsbh", "d,w", 0x7c0000a0, 0xffe007ff, WR_d|RD_t, 0, I33 }, +{"xor", "d,v,t", 0x00000026, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I1 }, +{"xori", "t,r,i", 0x38000000, 0xfc000000, WR_t|RD_s, 0, I1 }, +{"yield", "s", 0x7c000009, 0xfc1fffff, TRAP|RD_s, 0, MT32 }, +{"yield", "d,s", 0x7c000009, 0xfc1f07ff, TRAP|WR_d|RD_s, 0, MT32 }, + +/* User Defined Instruction. */ +{"udi0", "s,t,d,+1",0x70000010, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi0", "s,t,+2", 0x70000010, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi0", "s,+3", 0x70000010, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi0", "+4", 0x70000010, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi1", "s,t,d,+1",0x70000011, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi1", "s,t,+2", 0x70000011, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi1", "s,+3", 0x70000011, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi1", "+4", 0x70000011, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi2", "s,t,d,+1",0x70000012, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi2", "s,t,+2", 0x70000012, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi2", "s,+3", 0x70000012, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi2", "+4", 0x70000012, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi3", "s,t,d,+1",0x70000013, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi3", "s,t,+2", 0x70000013, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi3", "s,+3", 0x70000013, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi3", "+4", 0x70000013, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi4", "s,t,d,+1",0x70000014, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi4", "s,t,+2", 0x70000014, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi4", "s,+3", 0x70000014, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi4", "+4", 0x70000014, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi5", "s,t,d,+1",0x70000015, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi5", "s,t,+2", 0x70000015, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi5", "s,+3", 0x70000015, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi5", "+4", 0x70000015, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi6", "s,t,d,+1",0x70000016, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi6", "s,t,+2", 0x70000016, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi6", "s,+3", 0x70000016, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi6", "+4", 0x70000016, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi7", "s,t,d,+1",0x70000017, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi7", "s,t,+2", 0x70000017, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi7", "s,+3", 0x70000017, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi7", "+4", 0x70000017, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi8", "s,t,d,+1",0x70000018, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi8", "s,t,+2", 0x70000018, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi8", "s,+3", 0x70000018, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi8", "+4", 0x70000018, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi9", "s,t,d,+1",0x70000019, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi9", "s,t,+2", 0x70000019, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi9", "s,+3", 0x70000019, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi9", "+4", 0x70000019, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi10", "s,t,d,+1",0x7000001a, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi10", "s,t,+2", 0x7000001a, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi10", "s,+3", 0x7000001a, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi10", "+4", 0x7000001a, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi11", "s,t,d,+1",0x7000001b, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi11", "s,t,+2", 0x7000001b, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi11", "s,+3", 0x7000001b, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi11", "+4", 0x7000001b, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi12", "s,t,d,+1",0x7000001c, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi12", "s,t,+2", 0x7000001c, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi12", "s,+3", 0x7000001c, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi12", "+4", 0x7000001c, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi13", "s,t,d,+1",0x7000001d, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi13", "s,t,+2", 0x7000001d, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi13", "s,+3", 0x7000001d, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi13", "+4", 0x7000001d, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi14", "s,t,d,+1",0x7000001e, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi14", "s,t,+2", 0x7000001e, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi14", "s,+3", 0x7000001e, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi14", "+4", 0x7000001e, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi15", "s,t,d,+1",0x7000001f, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi15", "s,t,+2", 0x7000001f, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi15", "s,+3", 0x7000001f, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi15", "+4", 0x7000001f, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, + +/* Coprocessor 2 move/branch operations overlap with VR5400 .ob format + instructions so they are here for the latters to take precedence. */ +{"bc2f", "p", 0x49000000, 0xffff0000, CBD|RD_CC, 0, I1 }, +{"bc2f", "N,p", 0x49000000, 0xffe30000, CBD|RD_CC, 0, I32 }, +{"bc2fl", "p", 0x49020000, 0xffff0000, CBL|RD_CC, 0, I2 }, +{"bc2fl", "N,p", 0x49020000, 0xffe30000, CBL|RD_CC, 0, I32 }, +{"bc2t", "p", 0x49010000, 0xffff0000, CBD|RD_CC, 0, I1 }, +{"bc2t", "N,p", 0x49010000, 0xffe30000, CBD|RD_CC, 0, I32 }, +{"bc2tl", "p", 0x49030000, 0xffff0000, CBL|RD_CC, 0, I2 }, +{"bc2tl", "N,p", 0x49030000, 0xffe30000, CBL|RD_CC, 0, I32 }, +{"cfc2", "t,G", 0x48400000, 0xffe007ff, LCD|WR_t|RD_C2, 0, I1 }, +{"ctc2", "t,G", 0x48c00000, 0xffe007ff, COD|RD_t|WR_CC, 0, I1 }, +{"dmfc2", "t,G", 0x48200000, 0xffe007ff, LCD|WR_t|RD_C2, 0, I3 }, +{"dmfc2", "t,G,H", 0x48200000, 0xffe007f8, LCD|WR_t|RD_C2, 0, I64 }, +{"dmtc2", "t,G", 0x48a00000, 0xffe007ff, COD|RD_t|WR_C2|WR_CC, 0, I3 }, +{"dmtc2", "t,G,H", 0x48a00000, 0xffe007f8, COD|RD_t|WR_C2|WR_CC, 0, I64 }, +{"mfc2", "t,G", 0x48000000, 0xffe007ff, LCD|WR_t|RD_C2, 0, I1 }, +{"mfc2", "t,G,H", 0x48000000, 0xffe007f8, LCD|WR_t|RD_C2, 0, I32 }, +{"mfhc2", "t,G", 0x48600000, 0xffe007ff, LCD|WR_t|RD_C2, 0, I33 }, +{"mfhc2", "t,G,H", 0x48600000, 0xffe007f8, LCD|WR_t|RD_C2, 0, I33 }, +{"mfhc2", "t,i", 0x48600000, 0xffe00000, LCD|WR_t|RD_C2, 0, I33 }, +{"mtc2", "t,G", 0x48800000, 0xffe007ff, COD|RD_t|WR_C2|WR_CC, 0, I1 }, +{"mtc2", "t,G,H", 0x48800000, 0xffe007f8, COD|RD_t|WR_C2|WR_CC, 0, I32 }, +{"mthc2", "t,G", 0x48e00000, 0xffe007ff, COD|RD_t|WR_C2|WR_CC, 0, I33 }, +{"mthc2", "t,G,H", 0x48e00000, 0xffe007f8, COD|RD_t|WR_C2|WR_CC, 0, I33 }, +{"mthc2", "t,i", 0x48e00000, 0xffe00000, COD|RD_t|WR_C2|WR_CC, 0, I33 }, + +/* Coprocessor 3 move/branch operations overlap with MIPS IV COP1X + instructions, so they are here for the latters to take precedence. */ +{"bc3f", "p", 0x4d000000, 0xffff0000, CBD|RD_CC, 0, I1 }, +{"bc3fl", "p", 0x4d020000, 0xffff0000, CBL|RD_CC, 0, I2 }, +{"bc3t", "p", 0x4d010000, 0xffff0000, CBD|RD_CC, 0, I1 }, +{"bc3tl", "p", 0x4d030000, 0xffff0000, CBL|RD_CC, 0, I2 }, +{"cfc3", "t,G", 0x4c400000, 0xffe007ff, LCD|WR_t|RD_C3, 0, I1 }, +{"ctc3", "t,G", 0x4cc00000, 0xffe007ff, COD|RD_t|WR_CC, 0, I1 }, +{"dmfc3", "t,G", 0x4c200000, 0xffe007ff, LCD|WR_t|RD_C3, 0, I3 }, +{"dmtc3", "t,G", 0x4ca00000, 0xffe007ff, COD|RD_t|WR_C3|WR_CC, 0, I3 }, +{"mfc3", "t,G", 0x4c000000, 0xffe007ff, LCD|WR_t|RD_C3, 0, I1 }, +{"mfc3", "t,G,H", 0x4c000000, 0xffe007f8, LCD|WR_t|RD_C3, 0, I32 }, +{"mtc3", "t,G", 0x4c800000, 0xffe007ff, COD|RD_t|WR_C3|WR_CC, 0, I1 }, +{"mtc3", "t,G,H", 0x4c800000, 0xffe007f8, COD|RD_t|WR_C3|WR_CC, 0, I32 }, + +/* MIPS DSP ASE */ +{"absq_s.ph", "d,t", 0x7c000252, 0xffe007ff, WR_d|RD_t, 0, D32 }, +{"absq_s.pw", "d,t", 0x7c000456, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"absq_s.qh", "d,t", 0x7c000256, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"absq_s.w", "d,t", 0x7c000452, 0xffe007ff, WR_d|RD_t, 0, D32 }, +{"addq.ph", "d,s,t", 0x7c000290, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"addq.pw", "d,s,t", 0x7c000494, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"addq.qh", "d,s,t", 0x7c000294, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"addq_s.ph", "d,s,t", 0x7c000390, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"addq_s.pw", "d,s,t", 0x7c000594, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"addq_s.qh", "d,s,t", 0x7c000394, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"addq_s.w", "d,s,t", 0x7c000590, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"addsc", "d,s,t", 0x7c000410, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"addu.ob", "d,s,t", 0x7c000014, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"addu.qb", "d,s,t", 0x7c000010, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"addu_s.ob", "d,s,t", 0x7c000114, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"addu_s.qb", "d,s,t", 0x7c000110, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"addwc", "d,s,t", 0x7c000450, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"bitrev", "d,t", 0x7c0006d2, 0xffe007ff, WR_d|RD_t, 0, D32 }, +{"bposge32", "p", 0x041c0000, 0xffff0000, CBD, 0, D32 }, +{"bposge64", "p", 0x041d0000, 0xffff0000, CBD, 0, D64 }, +{"cmp.eq.ph", "s,t", 0x7c000211, 0xfc00ffff, RD_s|RD_t, 0, D32 }, +{"cmp.eq.pw", "s,t", 0x7c000415, 0xfc00ffff, RD_s|RD_t, 0, D64 }, +{"cmp.eq.qh", "s,t", 0x7c000215, 0xfc00ffff, RD_s|RD_t, 0, D64 }, +{"cmpgu.eq.ob", "d,s,t", 0x7c000115, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"cmpgu.eq.qb", "d,s,t", 0x7c000111, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"cmpgu.le.ob", "d,s,t", 0x7c000195, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"cmpgu.le.qb", "d,s,t", 0x7c000191, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"cmpgu.lt.ob", "d,s,t", 0x7c000155, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"cmpgu.lt.qb", "d,s,t", 0x7c000151, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"cmp.le.ph", "s,t", 0x7c000291, 0xfc00ffff, RD_s|RD_t, 0, D32 }, +{"cmp.le.pw", "s,t", 0x7c000495, 0xfc00ffff, RD_s|RD_t, 0, D64 }, +{"cmp.le.qh", "s,t", 0x7c000295, 0xfc00ffff, RD_s|RD_t, 0, D64 }, +{"cmp.lt.ph", "s,t", 0x7c000251, 0xfc00ffff, RD_s|RD_t, 0, D32 }, +{"cmp.lt.pw", "s,t", 0x7c000455, 0xfc00ffff, RD_s|RD_t, 0, D64 }, +{"cmp.lt.qh", "s,t", 0x7c000255, 0xfc00ffff, RD_s|RD_t, 0, D64 }, +{"cmpu.eq.ob", "s,t", 0x7c000015, 0xfc00ffff, RD_s|RD_t, 0, D64 }, +{"cmpu.eq.qb", "s,t", 0x7c000011, 0xfc00ffff, RD_s|RD_t, 0, D32 }, +{"cmpu.le.ob", "s,t", 0x7c000095, 0xfc00ffff, RD_s|RD_t, 0, D64 }, +{"cmpu.le.qb", "s,t", 0x7c000091, 0xfc00ffff, RD_s|RD_t, 0, D32 }, +{"cmpu.lt.ob", "s,t", 0x7c000055, 0xfc00ffff, RD_s|RD_t, 0, D64 }, +{"cmpu.lt.qb", "s,t", 0x7c000051, 0xfc00ffff, RD_s|RD_t, 0, D32 }, +{"dextpdp", "t,7,6", 0x7c0002bc, 0xfc00e7ff, WR_t|RD_a|DSP_VOLA, 0, D64 }, +{"dextpdpv", "t,7,s", 0x7c0002fc, 0xfc00e7ff, WR_t|RD_a|RD_s|DSP_VOLA, 0, D64 }, +{"dextp", "t,7,6", 0x7c0000bc, 0xfc00e7ff, WR_t|RD_a, 0, D64 }, +{"dextpv", "t,7,s", 0x7c0000fc, 0xfc00e7ff, WR_t|RD_a|RD_s, 0, D64 }, +{"dextr.l", "t,7,6", 0x7c00043c, 0xfc00e7ff, WR_t|RD_a, 0, D64 }, +{"dextr_r.l", "t,7,6", 0x7c00053c, 0xfc00e7ff, WR_t|RD_a, 0, D64 }, +{"dextr_rs.l", "t,7,6", 0x7c0005bc, 0xfc00e7ff, WR_t|RD_a, 0, D64 }, +{"dextr_rs.w", "t,7,6", 0x7c0001bc, 0xfc00e7ff, WR_t|RD_a, 0, D64 }, +{"dextr_r.w", "t,7,6", 0x7c00013c, 0xfc00e7ff, WR_t|RD_a, 0, D64 }, +{"dextr_s.h", "t,7,6", 0x7c0003bc, 0xfc00e7ff, WR_t|RD_a, 0, D64 }, +{"dextrv.l", "t,7,s", 0x7c00047c, 0xfc00e7ff, WR_t|RD_a|RD_s, 0, D64 }, +{"dextrv_r.l", "t,7,s", 0x7c00057c, 0xfc00e7ff, WR_t|RD_a|RD_s, 0, D64 }, +{"dextrv_rs.l", "t,7,s", 0x7c0005fc, 0xfc00e7ff, WR_t|RD_a|RD_s, 0, D64 }, +{"dextrv_rs.w", "t,7,s", 0x7c0001fc, 0xfc00e7ff, WR_t|RD_a|RD_s, 0, D64 }, +{"dextrv_r.w", "t,7,s", 0x7c00017c, 0xfc00e7ff, WR_t|RD_a|RD_s, 0, D64 }, +{"dextrv_s.h", "t,7,s", 0x7c0003fc, 0xfc00e7ff, WR_t|RD_a|RD_s, 0, D64 }, +{"dextrv.w", "t,7,s", 0x7c00007c, 0xfc00e7ff, WR_t|RD_a|RD_s, 0, D64 }, +{"dextr.w", "t,7,6", 0x7c00003c, 0xfc00e7ff, WR_t|RD_a, 0, D64 }, +{"dinsv", "t,s", 0x7c00000d, 0xfc00ffff, WR_t|RD_s, 0, D64 }, +{"dmadd", "7,s,t", 0x7c000674, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"dmaddu", "7,s,t", 0x7c000774, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"dmsub", "7,s,t", 0x7c0006f4, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"dmsubu", "7,s,t", 0x7c0007f4, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"dmthlip", "s,7", 0x7c0007fc, 0xfc1fe7ff, RD_s|MOD_a|DSP_VOLA, 0, D64 }, +{"dpaq_sa.l.pw", "7,s,t", 0x7c000334, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"dpaq_sa.l.w", "7,s,t", 0x7c000330, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D32 }, +{"dpaq_s.w.ph", "7,s,t", 0x7c000130, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D32 }, +{"dpaq_s.w.qh", "7,s,t", 0x7c000134, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"dpau.h.obl", "7,s,t", 0x7c0000f4, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"dpau.h.obr", "7,s,t", 0x7c0001f4, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"dpau.h.qbl", "7,s,t", 0x7c0000f0, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D32 }, +{"dpau.h.qbr", "7,s,t", 0x7c0001f0, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D32 }, +{"dpsq_sa.l.pw", "7,s,t", 0x7c000374, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"dpsq_sa.l.w", "7,s,t", 0x7c000370, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D32 }, +{"dpsq_s.w.ph", "7,s,t", 0x7c000170, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D32 }, +{"dpsq_s.w.qh", "7,s,t", 0x7c000174, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"dpsu.h.obl", "7,s,t", 0x7c0002f4, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"dpsu.h.obr", "7,s,t", 0x7c0003f4, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"dpsu.h.qbl", "7,s,t", 0x7c0002f0, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D32 }, +{"dpsu.h.qbr", "7,s,t", 0x7c0003f0, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D32 }, +{"dshilo", "7,:", 0x7c0006bc, 0xfc07e7ff, MOD_a, 0, D64 }, +{"dshilov", "7,s", 0x7c0006fc, 0xfc1fe7ff, MOD_a|RD_s, 0, D64 }, +{"extpdp", "t,7,6", 0x7c0002b8, 0xfc00e7ff, WR_t|RD_a|DSP_VOLA, 0, D32 }, +{"extpdpv", "t,7,s", 0x7c0002f8, 0xfc00e7ff, WR_t|RD_a|RD_s|DSP_VOLA, 0, D32 }, +{"extp", "t,7,6", 0x7c0000b8, 0xfc00e7ff, WR_t|RD_a, 0, D32 }, +{"extpv", "t,7,s", 0x7c0000f8, 0xfc00e7ff, WR_t|RD_a|RD_s, 0, D32 }, +{"extr_rs.w", "t,7,6", 0x7c0001b8, 0xfc00e7ff, WR_t|RD_a, 0, D32 }, +{"extr_r.w", "t,7,6", 0x7c000138, 0xfc00e7ff, WR_t|RD_a, 0, D32 }, +{"extr_s.h", "t,7,6", 0x7c0003b8, 0xfc00e7ff, WR_t|RD_a, 0, D32 }, +{"extrv_rs.w", "t,7,s", 0x7c0001f8, 0xfc00e7ff, WR_t|RD_a|RD_s, 0, D32 }, +{"extrv_r.w", "t,7,s", 0x7c000178, 0xfc00e7ff, WR_t|RD_a|RD_s, 0, D32 }, +{"extrv_s.h", "t,7,s", 0x7c0003f8, 0xfc00e7ff, WR_t|RD_a|RD_s, 0, D32 }, +{"extrv.w", "t,7,s", 0x7c000078, 0xfc00e7ff, WR_t|RD_a|RD_s, 0, D32 }, +{"extr.w", "t,7,6", 0x7c000038, 0xfc00e7ff, WR_t|RD_a, 0, D32 }, +{"insv", "t,s", 0x7c00000c, 0xfc00ffff, WR_t|RD_s, 0, D32 }, +{"lbux", "d,t(b)", 0x7c00018a, 0xfc0007ff, LDD|WR_d|RD_t|RD_b, 0, D32 }, +{"ldx", "d,t(b)", 0x7c00020a, 0xfc0007ff, LDD|WR_d|RD_t|RD_b, 0, D64 }, +{"lhx", "d,t(b)", 0x7c00010a, 0xfc0007ff, LDD|WR_d|RD_t|RD_b, 0, D32 }, +{"lwx", "d,t(b)", 0x7c00000a, 0xfc0007ff, LDD|WR_d|RD_t|RD_b, 0, D32 }, +{"maq_sa.w.phl", "7,s,t", 0x7c000430, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D32 }, +{"maq_sa.w.phr", "7,s,t", 0x7c0004b0, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D32 }, +{"maq_sa.w.qhll", "7,s,t", 0x7c000434, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"maq_sa.w.qhlr", "7,s,t", 0x7c000474, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"maq_sa.w.qhrl", "7,s,t", 0x7c0004b4, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"maq_sa.w.qhrr", "7,s,t", 0x7c0004f4, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"maq_s.l.pwl", "7,s,t", 0x7c000734, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"maq_s.l.pwr", "7,s,t", 0x7c0007b4, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"maq_s.w.phl", "7,s,t", 0x7c000530, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D32 }, +{"maq_s.w.phr", "7,s,t", 0x7c0005b0, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D32 }, +{"maq_s.w.qhll", "7,s,t", 0x7c000534, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"maq_s.w.qhlr", "7,s,t", 0x7c000574, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"maq_s.w.qhrl", "7,s,t", 0x7c0005b4, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"maq_s.w.qhrr", "7,s,t", 0x7c0005f4, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"modsub", "d,s,t", 0x7c000490, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"mthlip", "s,7", 0x7c0007f8, 0xfc1fe7ff, RD_s|MOD_a|DSP_VOLA, 0, D32 }, +{"muleq_s.pw.qhl", "d,s,t", 0x7c000714, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0, D64 }, +{"muleq_s.pw.qhr", "d,s,t", 0x7c000754, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0, D64 }, +{"muleq_s.w.phl", "d,s,t", 0x7c000710, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0, D32 }, +{"muleq_s.w.phr", "d,s,t", 0x7c000750, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0, D32 }, +{"muleu_s.ph.qbl", "d,s,t", 0x7c000190, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0, D32 }, +{"muleu_s.ph.qbr", "d,s,t", 0x7c0001d0, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0, D32 }, +{"muleu_s.qh.obl", "d,s,t", 0x7c000194, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0, D64 }, +{"muleu_s.qh.obr", "d,s,t", 0x7c0001d4, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0, D64 }, +{"mulq_rs.ph", "d,s,t", 0x7c0007d0, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0, D32 }, +{"mulq_rs.qh", "d,s,t", 0x7c0007d4, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0, D64 }, +{"mulsaq_s.l.pw", "7,s,t", 0x7c0003b4, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"mulsaq_s.w.ph", "7,s,t", 0x7c0001b0, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D32 }, +{"mulsaq_s.w.qh", "7,s,t", 0x7c0001b4, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"packrl.ph", "d,s,t", 0x7c000391, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"packrl.pw", "d,s,t", 0x7c000395, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"pick.ob", "d,s,t", 0x7c0000d5, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"pick.ph", "d,s,t", 0x7c0002d1, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"pick.pw", "d,s,t", 0x7c0004d5, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"pick.qb", "d,s,t", 0x7c0000d1, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"pick.qh", "d,s,t", 0x7c0002d5, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"preceq.pw.qhla", "d,t", 0x7c000396, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"preceq.pw.qhl", "d,t", 0x7c000316, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"preceq.pw.qhra", "d,t", 0x7c0003d6, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"preceq.pw.qhr", "d,t", 0x7c000356, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"preceq.s.l.pwl", "d,t", 0x7c000516, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"preceq.s.l.pwr", "d,t", 0x7c000556, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"precequ.ph.qbla", "d,t", 0x7c000192, 0xffe007ff, WR_d|RD_t, 0, D32 }, +{"precequ.ph.qbl", "d,t", 0x7c000112, 0xffe007ff, WR_d|RD_t, 0, D32 }, +{"precequ.ph.qbra", "d,t", 0x7c0001d2, 0xffe007ff, WR_d|RD_t, 0, D32 }, +{"precequ.ph.qbr", "d,t", 0x7c000152, 0xffe007ff, WR_d|RD_t, 0, D32 }, +{"precequ.pw.qhla", "d,t", 0x7c000196, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"precequ.pw.qhl", "d,t", 0x7c000116, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"precequ.pw.qhra", "d,t", 0x7c0001d6, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"precequ.pw.qhr", "d,t", 0x7c000156, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"preceq.w.phl", "d,t", 0x7c000312, 0xffe007ff, WR_d|RD_t, 0, D32 }, +{"preceq.w.phr", "d,t", 0x7c000352, 0xffe007ff, WR_d|RD_t, 0, D32 }, +{"preceu.ph.qbla", "d,t", 0x7c000792, 0xffe007ff, WR_d|RD_t, 0, D32 }, +{"preceu.ph.qbl", "d,t", 0x7c000712, 0xffe007ff, WR_d|RD_t, 0, D32 }, +{"preceu.ph.qbra", "d,t", 0x7c0007d2, 0xffe007ff, WR_d|RD_t, 0, D32 }, +{"preceu.ph.qbr", "d,t", 0x7c000752, 0xffe007ff, WR_d|RD_t, 0, D32 }, +{"preceu.qh.obla", "d,t", 0x7c000796, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"preceu.qh.obl", "d,t", 0x7c000716, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"preceu.qh.obra", "d,t", 0x7c0007d6, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"preceu.qh.obr", "d,t", 0x7c000756, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"precrq.ob.qh", "d,s,t", 0x7c000315, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"precrq.ph.w", "d,s,t", 0x7c000511, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"precrq.pw.l", "d,s,t", 0x7c000715, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"precrq.qb.ph", "d,s,t", 0x7c000311, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"precrq.qh.pw", "d,s,t", 0x7c000515, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"precrq_rs.ph.w", "d,s,t", 0x7c000551, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"precrq_rs.qh.pw", "d,s,t", 0x7c000555, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"precrqu_s.ob.qh", "d,s,t", 0x7c0003d5, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"precrqu_s.qb.ph", "d,s,t", 0x7c0003d1, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"raddu.l.ob", "d,s", 0x7c000514, 0xfc1f07ff, WR_d|RD_s, 0, D64 }, +{"raddu.w.qb", "d,s", 0x7c000510, 0xfc1f07ff, WR_d|RD_s, 0, D32 }, +{"rddsp", "d", 0x7fff04b8, 0xffff07ff, WR_d, 0, D32 }, +{"rddsp", "d,'", 0x7c0004b8, 0xffc007ff, WR_d, 0, D32 }, +{"repl.ob", "d,5", 0x7c000096, 0xff0007ff, WR_d, 0, D64 }, +{"repl.ph", "d,@", 0x7c000292, 0xfc0007ff, WR_d, 0, D32 }, +{"repl.pw", "d,@", 0x7c000496, 0xfc0007ff, WR_d, 0, D64 }, +{"repl.qb", "d,5", 0x7c000092, 0xff0007ff, WR_d, 0, D32 }, +{"repl.qh", "d,@", 0x7c000296, 0xfc0007ff, WR_d, 0, D64 }, +{"replv.ob", "d,t", 0x7c0000d6, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"replv.ph", "d,t", 0x7c0002d2, 0xffe007ff, WR_d|RD_t, 0, D32 }, +{"replv.pw", "d,t", 0x7c0004d6, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"replv.qb", "d,t", 0x7c0000d2, 0xffe007ff, WR_d|RD_t, 0, D32 }, +{"replv.qh", "d,t", 0x7c0002d6, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"shilo", "7,0", 0x7c0006b8, 0xfc0fe7ff, MOD_a, 0, D32 }, +{"shilov", "7,s", 0x7c0006f8, 0xfc1fe7ff, MOD_a|RD_s, 0, D32 }, +{"shll.ob", "d,t,3", 0x7c000017, 0xff0007ff, WR_d|RD_t, 0, D64 }, +{"shll.ph", "d,t,4", 0x7c000213, 0xfe0007ff, WR_d|RD_t, 0, D32 }, +{"shll.pw", "d,t,6", 0x7c000417, 0xfc0007ff, WR_d|RD_t, 0, D64 }, +{"shll.qb", "d,t,3", 0x7c000013, 0xff0007ff, WR_d|RD_t, 0, D32 }, +{"shll.qh", "d,t,4", 0x7c000217, 0xfe0007ff, WR_d|RD_t, 0, D64 }, +{"shll_s.ph", "d,t,4", 0x7c000313, 0xfe0007ff, WR_d|RD_t, 0, D32 }, +{"shll_s.pw", "d,t,6", 0x7c000517, 0xfc0007ff, WR_d|RD_t, 0, D64 }, +{"shll_s.qh", "d,t,4", 0x7c000317, 0xfe0007ff, WR_d|RD_t, 0, D64 }, +{"shll_s.w", "d,t,6", 0x7c000513, 0xfc0007ff, WR_d|RD_t, 0, D32 }, +{"shllv.ob", "d,t,s", 0x7c000097, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"shllv.ph", "d,t,s", 0x7c000293, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"shllv.pw", "d,t,s", 0x7c000497, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"shllv.qb", "d,t,s", 0x7c000093, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"shllv.qh", "d,t,s", 0x7c000297, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"shllv_s.ph", "d,t,s", 0x7c000393, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"shllv_s.pw", "d,t,s", 0x7c000597, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"shllv_s.qh", "d,t,s", 0x7c000397, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"shllv_s.w", "d,t,s", 0x7c000593, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"shra.ph", "d,t,4", 0x7c000253, 0xfe0007ff, WR_d|RD_t, 0, D32 }, +{"shra.pw", "d,t,6", 0x7c000457, 0xfc0007ff, WR_d|RD_t, 0, D64 }, +{"shra.qh", "d,t,4", 0x7c000257, 0xfe0007ff, WR_d|RD_t, 0, D64 }, +{"shra_r.ph", "d,t,4", 0x7c000353, 0xfe0007ff, WR_d|RD_t, 0, D32 }, +{"shra_r.pw", "d,t,6", 0x7c000557, 0xfc0007ff, WR_d|RD_t, 0, D64 }, +{"shra_r.qh", "d,t,4", 0x7c000357, 0xfe0007ff, WR_d|RD_t, 0, D64 }, +{"shra_r.w", "d,t,6", 0x7c000553, 0xfc0007ff, WR_d|RD_t, 0, D32 }, +{"shrav.ph", "d,t,s", 0x7c0002d3, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"shrav.pw", "d,t,s", 0x7c0004d7, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"shrav.qh", "d,t,s", 0x7c0002d7, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"shrav_r.ph", "d,t,s", 0x7c0003d3, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"shrav_r.pw", "d,t,s", 0x7c0005d7, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"shrav_r.qh", "d,t,s", 0x7c0003d7, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"shrav_r.w", "d,t,s", 0x7c0005d3, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"shrl.ob", "d,t,3", 0x7c000057, 0xff0007ff, WR_d|RD_t, 0, D64 }, +{"shrl.qb", "d,t,3", 0x7c000053, 0xff0007ff, WR_d|RD_t, 0, D32 }, +{"shrlv.ob", "d,t,s", 0x7c0000d7, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"shrlv.qb", "d,t,s", 0x7c0000d3, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"subq.ph", "d,s,t", 0x7c0002d0, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"subq.pw", "d,s,t", 0x7c0004d4, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"subq.qh", "d,s,t", 0x7c0002d4, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"subq_s.ph", "d,s,t", 0x7c0003d0, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"subq_s.pw", "d,s,t", 0x7c0005d4, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"subq_s.qh", "d,s,t", 0x7c0003d4, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"subq_s.w", "d,s,t", 0x7c0005d0, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"subu.ob", "d,s,t", 0x7c000054, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"subu.qb", "d,s,t", 0x7c000050, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"subu_s.ob", "d,s,t", 0x7c000154, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"subu_s.qb", "d,s,t", 0x7c000150, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"wrdsp", "s", 0x7c1ffcf8, 0xfc1fffff, RD_s|DSP_VOLA, 0, D32 }, +{"wrdsp", "s,8", 0x7c0004f8, 0xfc1e07ff, RD_s|DSP_VOLA, 0, D32 }, +/* MIPS DSP ASE Rev2 */ +{"absq_s.qb", "d,t", 0x7c000052, 0xffe007ff, WR_d|RD_t, 0, D33 }, +{"addu.ph", "d,s,t", 0x7c000210, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"addu_s.ph", "d,s,t", 0x7c000310, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"adduh.qb", "d,s,t", 0x7c000018, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"adduh_r.qb", "d,s,t", 0x7c000098, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"append", "t,s,h", 0x7c000031, 0xfc0007ff, WR_t|RD_t|RD_s, 0, D33 }, +{"balign", "t,s,2", 0x7c000431, 0xfc00e7ff, WR_t|RD_t|RD_s, 0, D33 }, +{"cmpgdu.eq.qb", "d,s,t", 0x7c000611, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"cmpgdu.lt.qb", "d,s,t", 0x7c000651, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"cmpgdu.le.qb", "d,s,t", 0x7c000691, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"dpa.w.ph", "7,s,t", 0x7c000030, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D33 }, +{"dps.w.ph", "7,s,t", 0x7c000070, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D33 }, +{"mul.ph", "d,s,t", 0x7c000318, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0, D33 }, +{"mul_s.ph", "d,s,t", 0x7c000398, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0, D33 }, +{"mulq_rs.w", "d,s,t", 0x7c0005d8, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0, D33 }, +{"mulq_s.ph", "d,s,t", 0x7c000790, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0, D33 }, +{"mulq_s.w", "d,s,t", 0x7c000598, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0, D33 }, +{"mulsa.w.ph", "7,s,t", 0x7c0000b0, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D33 }, +{"precr.qb.ph", "d,s,t", 0x7c000351, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"precr_sra.ph.w", "t,s,h", 0x7c000791, 0xfc0007ff, WR_t|RD_t|RD_s, 0, D33 }, +{"precr_sra_r.ph.w", "t,s,h", 0x7c0007d1, 0xfc0007ff, WR_t|RD_t|RD_s, 0, D33 }, +{"prepend", "t,s,h", 0x7c000071, 0xfc0007ff, WR_t|RD_t|RD_s, 0, D33 }, +{"shra.qb", "d,t,3", 0x7c000113, 0xff0007ff, WR_d|RD_t, 0, D33 }, +{"shra_r.qb", "d,t,3", 0x7c000153, 0xff0007ff, WR_d|RD_t, 0, D33 }, +{"shrav.qb", "d,t,s", 0x7c000193, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"shrav_r.qb", "d,t,s", 0x7c0001d3, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"shrl.ph", "d,t,4", 0x7c000653, 0xfe0007ff, WR_d|RD_t, 0, D33 }, +{"shrlv.ph", "d,t,s", 0x7c0006d3, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"subu.ph", "d,s,t", 0x7c000250, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"subu_s.ph", "d,s,t", 0x7c000350, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"subuh.qb", "d,s,t", 0x7c000058, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"subuh_r.qb", "d,s,t", 0x7c0000d8, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"addqh.ph", "d,s,t", 0x7c000218, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"addqh_r.ph", "d,s,t", 0x7c000298, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"addqh.w", "d,s,t", 0x7c000418, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"addqh_r.w", "d,s,t", 0x7c000498, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"subqh.ph", "d,s,t", 0x7c000258, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"subqh_r.ph", "d,s,t", 0x7c0002d8, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"subqh.w", "d,s,t", 0x7c000458, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"subqh_r.w", "d,s,t", 0x7c0004d8, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"dpax.w.ph", "7,s,t", 0x7c000230, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D33 }, +{"dpsx.w.ph", "7,s,t", 0x7c000270, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D33 }, +{"dpaqx_s.w.ph", "7,s,t", 0x7c000630, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D33 }, +{"dpaqx_sa.w.ph", "7,s,t", 0x7c0006b0, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D33 }, +{"dpsqx_s.w.ph", "7,s,t", 0x7c000670, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D33 }, +{"dpsqx_sa.w.ph", "7,s,t", 0x7c0006f0, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D33 }, +/* Move bc0* after mftr and mttr to avoid opcode collision. */ +{"bc0f", "p", 0x41000000, 0xffff0000, CBD|RD_CC, 0, I1 }, +{"bc0fl", "p", 0x41020000, 0xffff0000, CBL|RD_CC, 0, I2 }, +{"bc0t", "p", 0x41010000, 0xffff0000, CBD|RD_CC, 0, I1 }, +{"bc0tl", "p", 0x41030000, 0xffff0000, CBL|RD_CC, 0, I2 }, +/* No hazard protection on coprocessor instructions--they shouldn't + change the state of the processor and if they do it's up to the + user to put in nops as necessary. These are at the end so that the + disassembler recognizes more specific versions first. */ +{"c0", "C", 0x42000000, 0xfe000000, CP, 0, I1 }, +{"c1", "C", 0x46000000, 0xfe000000, FP_S, 0, I1 }, +{"c2", "C", 0x4a000000, 0xfe000000, CP, 0, I1 }, +{"c3", "C", 0x4e000000, 0xfe000000, CP, 0, I1 }, +}; + +static const int mips_num_opcodes = sizeof (mips_opcodes) / sizeof (mips_opcodes[0]); + +#undef LDD +#undef LCD +#undef UBD +#undef CBD +#undef COD +#undef CLD +#undef CBL +#undef TRAP +#undef SM +#undef WR_d +#undef WR_t +#undef WR_31 +#undef WR_D +#undef WR_T +#undef WR_S +#undef RD_s +#undef RD_b +#undef RD_t +#undef RD_S +#undef RD_T +#undef RD_R +#undef WR_CC +#undef RD_CC +#undef RD_C0 +#undef RD_C1 +#undef RD_C2 +#undef RD_C3 +#undef WR_C0 +#undef WR_C1 +#undef WR_C2 +#undef WR_C3 +#undef CP +#undef WR_HI +#undef RD_HI +#undef MOD_HI +#undef WR_LO +#undef RD_LO +#undef MOD_LO +#undef WR_HILO +#undef RD_HILO +#undef MOD_HILO +#undef IS_M +#undef WR_MACC +#undef RD_MACC +#undef I1 +#undef I2 +#undef I3 +#undef I4 +#undef I5 +#undef I32 +#undef I64 +#undef I33 +#undef I65 +#undef I3_32 +#undef I3_33 +#undef I4_32 +#undef I4_33 +#undef I5_33 +#undef SMT +#undef WR_a +#undef RD_a +#undef MOD_a +#undef DSP_VOLA +#undef D32 +#undef D33 +#undef D64 +#undef MT32 diff --git a/src/cmd/as/mips-opcode.h b/src/cmd/as/mips-opcode.h new file mode 100644 index 0000000..8bd75e8 --- /dev/null +++ b/src/cmd/as/mips-opcode.h @@ -0,0 +1,1092 @@ +/* + * Mips opcode list. + * + * Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, + * 2003, 2004, 2005, 2008, 2009, 2010 + * Free Software Foundation, Inc. + * Contributed by Ralph Campbell and OSF + * Commented and modified by Ian Lance Taylor, Cygnus Support + * Adapted for VirtualMIPS by Serge Vakulenko. + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + */ + +#ifndef _MIPS_H_ +#define _MIPS_H_ + +/* These are bit masks and shift counts to use to access the various + fields of an instruction. To retrieve the X field of an + instruction, use the expression + (i >> OP_SH_X) & OP_MASK_X + To set the same field (to j), use + i = (i &~ (OP_MASK_X << OP_SH_X)) | (j << OP_SH_X) + + Make sure you use fields that are appropriate for the instruction, + of course. + + The 'i' format uses OP, RS, RT and IMMEDIATE. + + The 'j' format uses OP and TARGET. + + The 'r' format uses OP, RS, RT, RD, SHAMT and FUNCT. + + The 'b' format uses OP, RS, RT and DELTA. + + The floating point 'i' format uses OP, RS, RT and IMMEDIATE. + + The floating point 'r' format uses OP, FMT, FT, FS, FD and FUNCT. + + A breakpoint instruction uses OP, CODE and SPEC (10 bits of the + breakpoint instruction are not defined; Kane says the breakpoint + code field in BREAK is 20 bits; yet MIPS assemblers and debuggers + only use ten bits). An optional two-operand form of break/sdbbp + allows the lower ten bits to be set too, and MIPS32 and later + architectures allow 20 bits to be set with a signal operand + (using CODE20). + + The syscall instruction uses CODE20. + + The general coprocessor instructions use COPZ. */ + +#define OP_MASK_OP 0x3f +#define OP_SH_OP 26 +#define OP_MASK_RS 0x1f +#define OP_SH_RS 21 +#define OP_MASK_FR 0x1f +#define OP_SH_FR 21 +#define OP_MASK_FMT 0x1f +#define OP_SH_FMT 21 +#define OP_MASK_BCC 0x7 +#define OP_SH_BCC 18 +#define OP_MASK_CODE 0x3ff +#define OP_SH_CODE 16 +#define OP_MASK_CODE2 0x3ff +#define OP_SH_CODE2 6 +#define OP_MASK_RT 0x1f +#define OP_SH_RT 16 +#define OP_MASK_FT 0x1f +#define OP_SH_FT 16 +#define OP_MASK_CACHE 0x1f +#define OP_SH_CACHE 16 +#define OP_MASK_RD 0x1f +#define OP_SH_RD 11 +#define OP_MASK_FS 0x1f +#define OP_SH_FS 11 +#define OP_MASK_PREFX 0x1f +#define OP_SH_PREFX 11 +#define OP_MASK_CCC 0x7 +#define OP_SH_CCC 8 +#define OP_MASK_CODE20 0xfffff /* 20 bit syscall/breakpoint code. */ +#define OP_SH_CODE20 6 +#define OP_MASK_SHAMT 0x1f +#define OP_SH_SHAMT 6 +#define OP_MASK_FD 0x1f +#define OP_SH_FD 6 +#define OP_MASK_TARGET 0x3ffffff +#define OP_SH_TARGET 0 +#define OP_MASK_COPZ 0x1ffffff +#define OP_SH_COPZ 0 +#define OP_MASK_IMMEDIATE 0xffff +#define OP_SH_IMMEDIATE 0 +#define OP_MASK_DELTA 0xffff +#define OP_SH_DELTA 0 +#define OP_MASK_FUNCT 0x3f +#define OP_SH_FUNCT 0 +#define OP_MASK_SPEC 0x3f +#define OP_SH_SPEC 0 +#define OP_SH_LOCC 8 /* FP condition code. */ +#define OP_SH_HICC 18 /* FP condition code. */ +#define OP_MASK_CC 0x7 +#define OP_SH_COP1NORM 25 /* Normal COP1 encoding. */ +#define OP_MASK_COP1NORM 0x1 /* a single bit. */ +#define OP_SH_COP1SPEC 21 /* COP1 encodings. */ +#define OP_MASK_COP1SPEC 0xf +#define OP_MASK_COP1SCLR 0x4 +#define OP_MASK_COP1CMP 0x3 +#define OP_SH_COP1CMP 4 +#define OP_SH_FORMAT 21 /* FP short format field. */ +#define OP_MASK_FORMAT 0x7 +#define OP_SH_TRUE 16 +#define OP_MASK_TRUE 0x1 +#define OP_SH_GE 17 +#define OP_MASK_GE 0x01 +#define OP_SH_UNSIGNED 16 +#define OP_MASK_UNSIGNED 0x1 +#define OP_SH_HINT 16 +#define OP_MASK_HINT 0x1f +#define OP_SH_MMI 0 /* Multimedia (parallel) op. */ +#define OP_MASK_MMI 0x3f +#define OP_SH_MMISUB 6 +#define OP_MASK_MMISUB 0x1f +#define OP_MASK_PERFREG 0x1f /* Performance monitoring. */ +#define OP_SH_PERFREG 1 +#define OP_SH_SEL 0 /* Coprocessor select field. */ +#define OP_MASK_SEL 0x7 /* The sel field of mfcZ and mtcZ. */ +#define OP_SH_CODE19 6 /* 19 bit wait code. */ +#define OP_MASK_CODE19 0x7ffff +#define OP_SH_ALN 21 +#define OP_MASK_ALN 0x7 +#define OP_SH_VSEL 21 +#define OP_MASK_VSEL 0x1f +#define OP_MASK_VECBYTE 0x7 /* Selector field is really 4 bits, + but 0x8-0xf don't select bytes. */ +#define OP_SH_VECBYTE 22 +#define OP_MASK_VECALIGN 0x7 /* Vector byte-align (alni.ob) op. */ +#define OP_SH_VECALIGN 21 +#define OP_MASK_INSMSB 0x1f /* "ins" MSB. */ +#define OP_SH_INSMSB 11 +#define OP_MASK_EXTMSBD 0x1f /* "ext" MSBD. */ +#define OP_SH_EXTMSBD 11 + +/* MIPS DSP ASE */ +#define OP_SH_DSPACC 11 +#define OP_MASK_DSPACC 0x3 +#define OP_SH_DSPACC_S 21 +#define OP_MASK_DSPACC_S 0x3 +#define OP_SH_DSPSFT 20 +#define OP_MASK_DSPSFT 0x3f +#define OP_SH_DSPSFT_7 19 +#define OP_MASK_DSPSFT_7 0x7f +#define OP_SH_SA3 21 +#define OP_MASK_SA3 0x7 +#define OP_SH_SA4 21 +#define OP_MASK_SA4 0xf +#define OP_SH_IMM8 16 +#define OP_MASK_IMM8 0xff +#define OP_SH_IMM10 16 +#define OP_MASK_IMM10 0x3ff +#define OP_SH_WRDSP 11 +#define OP_MASK_WRDSP 0x3f +#define OP_SH_RDDSP 16 +#define OP_MASK_RDDSP 0x3f +#define OP_SH_BP 11 +#define OP_MASK_BP 0x3 + +/* MIPS MT ASE */ +#define OP_SH_MT_U 5 +#define OP_MASK_MT_U 0x1 +#define OP_SH_MT_H 4 +#define OP_MASK_MT_H 0x1 +#define OP_SH_MTACC_T 18 +#define OP_MASK_MTACC_T 0x3 +#define OP_SH_MTACC_D 13 +#define OP_MASK_MTACC_D 0x3 + +#define OP_OP_COP0 0x10 +#define OP_OP_COP1 0x11 +#define OP_OP_COP2 0x12 +#define OP_OP_COP3 0x13 +#define OP_OP_LWC1 0x31 +#define OP_OP_LWC2 0x32 +#define OP_OP_LWC3 0x33 /* a.k.a. pref */ +#define OP_OP_LDC1 0x35 +#define OP_OP_LDC2 0x36 +#define OP_OP_LDC3 0x37 /* a.k.a. ld */ +#define OP_OP_SWC1 0x39 +#define OP_OP_SWC2 0x3a +#define OP_OP_SWC3 0x3b +#define OP_OP_SDC1 0x3d +#define OP_OP_SDC2 0x3e +#define OP_OP_SDC3 0x3f /* a.k.a. sd */ + +/* Values in the 'VSEL' field. */ +#define MDMX_FMTSEL_IMM_QH 0x1d +#define MDMX_FMTSEL_IMM_OB 0x1e +#define MDMX_FMTSEL_VEC_QH 0x15 +#define MDMX_FMTSEL_VEC_OB 0x16 + +/* UDI */ +#define OP_SH_UDI1 6 +#define OP_MASK_UDI1 0x1f +#define OP_SH_UDI2 6 +#define OP_MASK_UDI2 0x3ff +#define OP_SH_UDI3 6 +#define OP_MASK_UDI3 0x7fff +#define OP_SH_UDI4 6 +#define OP_MASK_UDI4 0xfffff + +/* Octeon */ +#define OP_SH_BBITIND 16 +#define OP_MASK_BBITIND 0x1f +#define OP_SH_CINSPOS 6 +#define OP_MASK_CINSPOS 0x1f +#define OP_SH_CINSLM1 11 +#define OP_MASK_CINSLM1 0x1f +#define OP_SH_SEQI 6 +#define OP_MASK_SEQI 0x3ff + +/* This structure holds information for a particular instruction. */ + +struct mips_opcode +{ + /* The name of the instruction. */ + const char *name; + /* A string describing the arguments for this instruction. */ + const char *args; + /* The basic opcode for the instruction. When assembling, this + opcode is modified by the arguments to produce the actual opcode + that is used. */ + unsigned match; + /* This is a bit mask for the + relevant portions of the opcode when disassembling. If the + actual opcode anded with the match field equals the opcode field, + then we have found the correct instruction. */ + unsigned mask; + /* A collection of bits describing the instruction, + notably any relevant hazard information. */ + unsigned pinfo; + /* A collection of additional bits describing the instruction. */ + unsigned pinfo2; + /* A collection of bits describing the instruction sets of which this + instruction or macro is a member. */ + unsigned membership; +}; + +/* These are the characters which may appear in the args field of an + instruction. They appear in the order in which the fields appear + when the instruction is used. Commas and parentheses in the args + string are ignored when assembling, and written into the output + when disassembling. + + Each of these characters corresponds to a mask field defined above. + + "1" 5 bit sync type (OP_*_SHAMT) + "<" 5 bit shift amount (OP_*_SHAMT) + ">" shift amount between 32 and 63, stored after subtracting 32 (OP_*_SHAMT) + "a" 26 bit target address (OP_*_TARGET) + "b" 5 bit base register (OP_*_RS) + "c" 10 bit breakpoint code (OP_*_CODE) + "d" 5 bit destination register specifier (OP_*_RD) + "h" 5 bit prefx hint (OP_*_PREFX) + "i" 16 bit unsigned immediate (OP_*_IMMEDIATE) + "j" 16 bit signed immediate (OP_*_DELTA) + "k" 5 bit cache opcode in target register position (OP_*_CACHE) + Also used for immediate operands in vr5400 vector insns. + "o" 16 bit signed offset (OP_*_DELTA) + "p" 16 bit PC relative branch target address (OP_*_DELTA) + "q" 10 bit extra breakpoint code (OP_*_CODE2) + "r" 5 bit same register used as both source and target (OP_*_RS) + "s" 5 bit source register specifier (OP_*_RS) + "t" 5 bit target register (OP_*_RT) + "u" 16 bit upper 16 bits of address (OP_*_IMMEDIATE) + "v" 5 bit same register used as both source and destination (OP_*_RS) + "w" 5 bit same register used as both target and destination (OP_*_RT) + "U" 5 bit same destination register in both OP_*_RD and OP_*_RT + (used by clo and clz) + "C" 25 bit coprocessor function code (OP_*_COPZ) + "B" 20 bit syscall/breakpoint function code (OP_*_CODE20) + "J" 19 bit wait function code (OP_*_CODE19) + "x" accept and ignore register name + "z" must be zero register + "K" 5 bit Hardware Register (rdhwr instruction) (OP_*_RD) + "+A" 5 bit ins/ext/dins/dext/dinsm/dextm position, which becomes + LSB (OP_*_SHAMT). + Enforces: 0 <= pos < 32. + "+B" 5 bit ins/dins size, which becomes MSB (OP_*_INSMSB). + Requires that "+A" or "+E" occur first to set position. + Enforces: 0 < (pos+size) <= 32. + "+C" 5 bit ext/dext size, which becomes MSBD (OP_*_EXTMSBD). + Requires that "+A" or "+E" occur first to set position. + Enforces: 0 < (pos+size) <= 32. + (Also used by "dext" w/ different limits, but limits for + that are checked by the M_DEXT macro.) + "+E" 5 bit dinsu/dextu position, which becomes LSB-32 (OP_*_SHAMT). + Enforces: 32 <= pos < 64. + "+F" 5 bit "dinsm/dinsu" size, which becomes MSB-32 (OP_*_INSMSB). + Requires that "+A" or "+E" occur first to set position. + Enforces: 32 < (pos+size) <= 64. + "+G" 5 bit "dextm" size, which becomes MSBD-32 (OP_*_EXTMSBD). + Requires that "+A" or "+E" occur first to set position. + Enforces: 32 < (pos+size) <= 64. + "+H" 5 bit "dextu" size, which becomes MSBD (OP_*_EXTMSBD). + Requires that "+A" or "+E" occur first to set position. + Enforces: 32 < (pos+size) <= 64. + + Floating point instructions: + "D" 5 bit destination register (OP_*_FD) + "M" 3 bit compare condition code (OP_*_CCC) (only used for mips4 and up) + "N" 3 bit branch condition code (OP_*_BCC) (only used for mips4 and up) + "S" 5 bit fs source 1 register (OP_*_FS) + "T" 5 bit ft source 2 register (OP_*_FT) + "R" 5 bit fr source 3 register (OP_*_FR) + "V" 5 bit same register used as floating source and destination (OP_*_FS) + "W" 5 bit same register used as floating target and destination (OP_*_FT) + + Coprocessor instructions: + "E" 5 bit target register (OP_*_RT) + "G" 5 bit destination register (OP_*_RD) + "H" 3 bit sel field for (d)mtc* and (d)mfc* (OP_*_SEL) + "P" 5 bit performance-monitor register (OP_*_PERFREG) + "e" 5 bit vector register byte specifier (OP_*_VECBYTE) + "%" 3 bit immediate vr5400 vector alignment operand (OP_*_VECALIGN) + see also "k" above + "+D" Combined destination register ("G") and sel ("H") for CP0 ops, + for pretty-printing in disassembly only. + + Macro instructions: + "A" General 32 bit expression + "I" 32 bit immediate (value placed in imm_expr). + "+I" 32 bit immediate (value placed in imm2_expr). + "F" 64 bit floating point constant in .rdata + "L" 64 bit floating point constant in .lit8 + "f" 32 bit floating point constant + "l" 32 bit floating point constant in .lit4 + + MDMX instruction operands (note that while these use the FP register + fields, they accept both $fN and $vN names for the registers): + "O" MDMX alignment offset (OP_*_ALN) + "Q" MDMX vector/scalar/immediate source (OP_*_VSEL and OP_*_FT) + "X" MDMX destination register (OP_*_FD) + "Y" MDMX source register (OP_*_FS) + "Z" MDMX source register (OP_*_FT) + + DSP ASE usage: + "2" 2 bit unsigned immediate for byte align (OP_*_BP) + "3" 3 bit unsigned immediate (OP_*_SA3) + "4" 4 bit unsigned immediate (OP_*_SA4) + "5" 8 bit unsigned immediate (OP_*_IMM8) + "6" 5 bit unsigned immediate (OP_*_RS) + "7" 2 bit dsp accumulator register (OP_*_DSPACC) + "8" 6 bit unsigned immediate (OP_*_WRDSP) + "9" 2 bit dsp accumulator register (OP_*_DSPACC_S) + "0" 6 bit signed immediate (OP_*_DSPSFT) + ":" 7 bit signed immediate (OP_*_DSPSFT_7) + "'" 6 bit unsigned immediate (OP_*_RDDSP) + "@" 10 bit signed immediate (OP_*_IMM10) + + MT ASE usage: + "!" 1 bit usermode flag (OP_*_MT_U) + "$" 1 bit load high flag (OP_*_MT_H) + "*" 2 bit dsp/smartmips accumulator register (OP_*_MTACC_T) + "&" 2 bit dsp/smartmips accumulator register (OP_*_MTACC_D) + "g" 5 bit coprocessor 1 and 2 destination register (OP_*_RD) + "+t" 5 bit coprocessor 0 destination register (OP_*_RT) + "+T" 5 bit coprocessor 0 destination register (OP_*_RT) - disassembly only + + UDI immediates: + "+1" UDI immediate bits 6-10 + "+2" UDI immediate bits 6-15 + "+3" UDI immediate bits 6-20 + "+4" UDI immediate bits 6-25 + + Octeon: + "+x" Bit index field of bbit. Enforces: 0 <= index < 32. + "+X" Bit index field of bbit aliasing bbit32. Matches if 32 <= index < 64, + otherwise skips to next candidate. + "+p" Position field of cins/cins32/exts/exts32. Enforces 0 <= pos < 32. + "+P" Position field of cins/exts aliasing cins32/exts32. Matches if + 32 <= pos < 64, otherwise skips to next candidate. + "+Q" Immediate field of seqi/snei. Enforces -512 <= imm < 512. + "+s" Length-minus-one field of cins/exts. Enforces: 0 <= lenm1 < 32. + "+S" Length-minus-one field of cins32/exts32 or cins/exts aliasing + cint32/exts32. Enforces non-negative value and that + pos + lenm1 < 32 or pos + lenm1 < 64 depending whether previous + position field is "+p" or "+P". + + Other: + "()" parens surrounding optional value + "," separates operands + "[]" brackets around index for vector-op scalar operand specifier (vr5400) + "+" Start of extension sequence. + + Characters used so far, for quick reference when adding more: + "1234567890" + "%[]<>(),+:'@!$*&" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklopqrstuvwxz" + + Extension character sequences used so far ("+" followed by the + following), for quick reference when adding more: + "1234" + "ABCDEFGHIPQSTX" + "pstx" +*/ + +/* These are the bits which may be set in the pinfo field of an + instructions. */ + +/* Modifies the general purpose register in OP_*_RD. */ +#define INSN_WRITE_GPR_D 0x00000001 +/* Modifies the general purpose register in OP_*_RT. */ +#define INSN_WRITE_GPR_T 0x00000002 +/* Modifies general purpose register 31. */ +#define INSN_WRITE_GPR_31 0x00000004 +/* Modifies the floating point register in OP_*_FD. */ +#define INSN_WRITE_FPR_D 0x00000008 +/* Modifies the floating point register in OP_*_FS. */ +#define INSN_WRITE_FPR_S 0x00000010 +/* Modifies the floating point register in OP_*_FT. */ +#define INSN_WRITE_FPR_T 0x00000020 +/* Reads the general purpose register in OP_*_RS. */ +#define INSN_READ_GPR_S 0x00000040 +/* Reads the general purpose register in OP_*_RT. */ +#define INSN_READ_GPR_T 0x00000080 +/* Reads the floating point register in OP_*_FS. */ +#define INSN_READ_FPR_S 0x00000100 +/* Reads the floating point register in OP_*_FT. */ +#define INSN_READ_FPR_T 0x00000200 +/* Reads the floating point register in OP_*_FR. */ +#define INSN_READ_FPR_R 0x00000400 +/* Modifies coprocessor condition code. */ +#define INSN_WRITE_COND_CODE 0x00000800 +/* Reads coprocessor condition code. */ +#define INSN_READ_COND_CODE 0x00001000 +/* TLB operation. */ +#define INSN_TLB 0x00002000 +/* Reads coprocessor register other than floating point register. */ +#define INSN_COP 0x00004000 +/* Instruction loads value from memory, requiring delay. */ +#define INSN_LOAD_MEMORY_DELAY 0x00008000 +/* Instruction loads value from coprocessor, requiring delay. */ +#define INSN_LOAD_COPROC_DELAY 0x00010000 +/* Instruction has unconditional branch delay slot. */ +#define INSN_UNCOND_BRANCH_DELAY 0x00020000 +/* Instruction has conditional branch delay slot. */ +#define INSN_COND_BRANCH_DELAY 0x00040000 +/* Conditional branch likely: if branch not taken, insn nullified. */ +#define INSN_COND_BRANCH_LIKELY 0x00080000 +/* Moves to coprocessor register, requiring delay. */ +#define INSN_COPROC_MOVE_DELAY 0x00100000 +/* Loads coprocessor register from memory, requiring delay. */ +#define INSN_COPROC_MEMORY_DELAY 0x00200000 +/* Reads the HI register. */ +#define INSN_READ_HI 0x00400000 +/* Reads the LO register. */ +#define INSN_READ_LO 0x00800000 +/* Modifies the HI register. */ +#define INSN_WRITE_HI 0x01000000 +/* Modifies the LO register. */ +#define INSN_WRITE_LO 0x02000000 +/* Takes a trap (easier to keep out of delay slot). */ +#define INSN_TRAP 0x04000000 +/* Instruction stores value into memory. */ +#define INSN_STORE_MEMORY 0x08000000 +/* Instruction uses single precision floating point. */ +#define FP_S 0x10000000 +/* Instruction uses double precision floating point. */ +#define FP_D 0x20000000 +/* Instruction is part of the tx39's integer multiply family. */ +#define INSN_MULT 0x40000000 +/* Instruction synchronize shared memory. */ +#define INSN_SYNC 0x80000000 + +/* These are the bits which may be set in the pinfo2 field of an + instruction. */ + +/* Instruction is a simple alias (I.E. "move" for daddu/addu/or) */ +#define INSN2_ALIAS 0x00000001 +/* Instruction reads MDMX accumulator. */ +#define INSN2_READ_MDMX_ACC 0x00000002 +/* Instruction writes MDMX accumulator. */ +#define INSN2_WRITE_MDMX_ACC 0x00000004 +/* Macro uses single-precision floating-point instructions. This should + only be set for macros. For instructions, FP_S in pinfo carries the + same information. */ +#define INSN2_M_FP_S 0x00000008 +/* Macro uses double-precision floating-point instructions. This should + only be set for macros. For instructions, FP_D in pinfo carries the + same information. */ +#define INSN2_M_FP_D 0x00000010 + +/* Masks used to mark instructions to indicate which MIPS ISA level + they were introduced in. INSN_ISA_MASK masks an enumeration that + specifies the base ISA level(s). The remainder of a 32-bit + word constructed using these macros is a bitmask of the remaining + INSN_* values below. */ + +#define INSN_ISA_MASK 0x0000000ful + +/* We cannot start at zero due to ISA_UNKNOWN below. */ +#define INSN_ISA1 1 +#define INSN_ISA2 2 +#define INSN_ISA3 3 +#define INSN_ISA4 4 +#define INSN_ISA5 5 +#define INSN_ISA32 6 +#define INSN_ISA32R2 7 +#define INSN_ISA64 8 +#define INSN_ISA64R2 9 +/* Below this point the INSN_* values correspond to combinations of ISAs. + They are only for use in the opcodes table to indicate membership of + a combination of ISAs that cannot be expressed using the usual inclusion + ordering on the above INSN_* values. */ +#define INSN_ISA3_32 10 +#define INSN_ISA3_32R2 11 +#define INSN_ISA4_32 12 +#define INSN_ISA4_32R2 13 +#define INSN_ISA5_32R2 14 + +/* Given INSN_ISA* values X and Y, where X ranges over INSN_ISA1 through + INSN_ISA5_32R2 and Y ranges over INSN_ISA1 through INSN_ISA64R2, + this table describes whether at least one of the ISAs described by X + is/are implemented by ISA Y. (Think of Y as the ISA level supported by + a particular core and X as the ISA level(s) at which a certain instruction + is defined.) The ISA(s) described by X is/are implemented by Y iff + (mips_isa_table[(Y & INSN_ISA_MASK) - 1] >> ((X & INSN_ISA_MASK) - 1)) & 1 + is non-zero. */ +static const unsigned int mips_isa_table[] = + { 0x0001, 0x0003, 0x0607, 0x1e0f, 0x3e1f, 0x0a23, 0x3e63, 0x3ebf, 0x3fff }; + +/* Masks used for Chip specific instructions. */ +#define INSN_CHIP_MASK 0xc3ff0820 + +/* Cavium Networks Octeon instructions. */ +#define INSN_OCTEON 0x00000800 + +/* Masks used for MIPS-defined ASEs. */ +#define INSN_ASE_MASK 0x3c00f000 + +/* DSP ASE */ +#define INSN_DSP 0x00001000 +#define INSN_DSP64 0x00002000 + +/* 0x00004000 is unused. */ + +/* MIPS-3D ASE */ +#define INSN_MIPS3D 0x00008000 + +/* MIPS R4650 instruction. */ +#define INSN_4650 0x00010000 +/* LSI R4010 instruction. */ +#define INSN_4010 0x00020000 +/* NEC VR4100 instruction. */ +#define INSN_4100 0x00040000 +/* Toshiba R3900 instruction. */ +#define INSN_3900 0x00080000 +/* MIPS R10000 instruction. */ +#define INSN_10000 0x00100000 +/* Broadcom SB-1 instruction. */ +#define INSN_SB1 0x00200000 +/* NEC VR4111/VR4181 instruction. */ +#define INSN_4111 0x00400000 +/* NEC VR4120 instruction. */ +#define INSN_4120 0x00800000 +/* NEC VR5400 instruction. */ +#define INSN_5400 0x01000000 +/* NEC VR5500 instruction. */ +#define INSN_5500 0x02000000 + +/* MDMX ASE */ +#define INSN_MDMX 0x04000000 +/* MT ASE */ +#define INSN_MT 0x08000000 +/* SmartMIPS ASE */ +#define INSN_SMARTMIPS 0x10000000 +/* DSP R2 ASE */ +#define INSN_DSPR2 0x20000000 +/* ST Microelectronics Loongson 2E. */ +#define INSN_LOONGSON_2E 0x40000000 +/* ST Microelectronics Loongson 2F. */ +#define INSN_LOONGSON_2F 0x80000000 +/* RMI Xlr instruction */ +#define INSN_XLR 0x00000020 + +/* MIPS ISA defines, use instead of hardcoding ISA level. */ + +#define ISA_UNKNOWN 0 /* Gas internal use. */ +#define ISA_MIPS1 INSN_ISA1 +#define ISA_MIPS2 INSN_ISA2 +#define ISA_MIPS3 INSN_ISA3 +#define ISA_MIPS4 INSN_ISA4 +#define ISA_MIPS5 INSN_ISA5 + +#define ISA_MIPS32 INSN_ISA32 +#define ISA_MIPS64 INSN_ISA64 + +#define ISA_MIPS32R2 INSN_ISA32R2 +#define ISA_MIPS64R2 INSN_ISA64R2 + + +/* CPU defines, use instead of hardcoding processor number. Keep this + in sync with bfd/archures.c in order for machine selection to work. */ +#define CPU_UNKNOWN 0 /* Gas internal use. */ +#define CPU_R3000 3000 +#define CPU_R3900 3900 +#define CPU_R4000 4000 +#define CPU_R4010 4010 +#define CPU_VR4100 4100 +#define CPU_R4111 4111 +#define CPU_VR4120 4120 +#define CPU_R4300 4300 +#define CPU_R4400 4400 +#define CPU_R4600 4600 +#define CPU_R4650 4650 +#define CPU_R5000 5000 +#define CPU_VR5400 5400 +#define CPU_VR5500 5500 +#define CPU_R6000 6000 +#define CPU_RM7000 7000 +#define CPU_R8000 8000 +#define CPU_RM9000 9000 +#define CPU_R10000 10000 +#define CPU_R12000 12000 +#define CPU_R14000 14000 +#define CPU_R16000 16000 +#define CPU_MIPS16 16 +#define CPU_MIPS32 32 +#define CPU_MIPS32R2 33 +#define CPU_MIPS5 5 +#define CPU_MIPS64 64 +#define CPU_MIPS64R2 65 +#define CPU_SB1 12310201 /* octal 'SB', 01. */ +#define CPU_LOONGSON_2E 3001 +#define CPU_LOONGSON_2F 3002 +#define CPU_OCTEON 6501 +#define CPU_XLR 887682 /* decimal 'XLR' */ + +/* Test for membership in an ISA including chip specific ISAs. INSN + is pointer to an element of the opcode table; ISA is the specified + ISA/ASE bitmask to test against; and CPU is the CPU specific ISA to + test, or zero if no CPU specific ISA test is desired. */ + +#define OPCODE_IS_MEMBER(insn, isa, cpu) \ + (((isa & INSN_ISA_MASK) != 0 \ + && ((insn)->membership & INSN_ISA_MASK) != 0 \ + && ((mips_isa_table [(isa & INSN_ISA_MASK) - 1] >> \ + (((insn)->membership & INSN_ISA_MASK) - 1)) & 1) != 0) \ + || ((isa & ~INSN_ISA_MASK) \ + & ((insn)->membership & ~INSN_ISA_MASK)) != 0 \ + || (cpu == CPU_R4650 && ((insn)->membership & INSN_4650) != 0) \ + || (cpu == CPU_RM7000 && ((insn)->membership & INSN_4650) != 0) \ + || (cpu == CPU_RM9000 && ((insn)->membership & INSN_4650) != 0) \ + || (cpu == CPU_R4010 && ((insn)->membership & INSN_4010) != 0) \ + || (cpu == CPU_VR4100 && ((insn)->membership & INSN_4100) != 0) \ + || (cpu == CPU_R3900 && ((insn)->membership & INSN_3900) != 0) \ + || ((cpu == CPU_R10000 || cpu == CPU_R12000 || cpu == CPU_R14000 \ + || cpu == CPU_R16000) \ + && ((insn)->membership & INSN_10000) != 0) \ + || (cpu == CPU_SB1 && ((insn)->membership & INSN_SB1) != 0) \ + || (cpu == CPU_R4111 && ((insn)->membership & INSN_4111) != 0) \ + || (cpu == CPU_VR4120 && ((insn)->membership & INSN_4120) != 0) \ + || (cpu == CPU_VR5400 && ((insn)->membership & INSN_5400) != 0) \ + || (cpu == CPU_VR5500 && ((insn)->membership & INSN_5500) != 0) \ + || (cpu == CPU_LOONGSON_2E \ + && ((insn)->membership & INSN_LOONGSON_2E) != 0) \ + || (cpu == CPU_LOONGSON_2F \ + && ((insn)->membership & INSN_LOONGSON_2F) != 0) \ + || (cpu == CPU_OCTEON \ + && ((insn)->membership & INSN_OCTEON) != 0) \ + || (cpu == CPU_XLR && ((insn)->membership & INSN_XLR) != 0) \ + || 0) /* Please keep this term for easier source merging. */ + +/* This is a list of macro expanded instructions. + + _I appended means immediate + _A appended means address + _AB appended means address with base register + _D appended means 64 bit floating point constant + _S appended means 32 bit floating point constant. */ + +enum +{ + M_ABS, + M_ADD_I, + M_ADDU_I, + M_AND_I, + M_BALIGN, + M_BEQ, + M_BEQ_I, + M_BEQL_I, + M_BGE, + M_BGEL, + M_BGE_I, + M_BGEL_I, + M_BGEU, + M_BGEUL, + M_BGEU_I, + M_BGEUL_I, + M_BGT, + M_BGTL, + M_BGT_I, + M_BGTL_I, + M_BGTU, + M_BGTUL, + M_BGTU_I, + M_BGTUL_I, + M_BLE, + M_BLEL, + M_BLE_I, + M_BLEL_I, + M_BLEU, + M_BLEUL, + M_BLEU_I, + M_BLEUL_I, + M_BLT, + M_BLTL, + M_BLT_I, + M_BLTL_I, + M_BLTU, + M_BLTUL, + M_BLTU_I, + M_BLTUL_I, + M_BNE, + M_BNE_I, + M_BNEL_I, + M_CACHE_AB, + M_DABS, + M_DADD_I, + M_DADDU_I, + M_DDIV_3, + M_DDIV_3I, + M_DDIVU_3, + M_DDIVU_3I, + M_DEXT, + M_DINS, + M_DIV_3, + M_DIV_3I, + M_DIVU_3, + M_DIVU_3I, + M_DLA_AB, + M_DLCA_AB, + M_DLI, + M_DMUL, + M_DMUL_I, + M_DMULO, + M_DMULO_I, + M_DMULOU, + M_DMULOU_I, + M_DREM_3, + M_DREM_3I, + M_DREMU_3, + M_DREMU_3I, + M_DSUB_I, + M_DSUBU_I, + M_DSUBU_I_2, + M_J_A, + M_JAL_1, + M_JAL_2, + M_JAL_A, + M_L_DOB, + M_L_DAB, + M_LA_AB, + M_LB_A, + M_LB_AB, + M_LBU_A, + M_LBU_AB, + M_LCA_AB, + M_LD_A, + M_LD_OB, + M_LD_AB, + M_LDC1_AB, + M_LDC2_AB, + M_LDC3_AB, + M_LDL_AB, + M_LDR_AB, + M_LH_A, + M_LH_AB, + M_LHU_A, + M_LHU_AB, + M_LI, + M_LI_D, + M_LI_DD, + M_LI_S, + M_LI_SS, + M_LL_AB, + M_LLD_AB, + M_LS_A, + M_LW_A, + M_LW_AB, + M_LWC0_A, + M_LWC0_AB, + M_LWC1_A, + M_LWC1_AB, + M_LWC2_A, + M_LWC2_AB, + M_LWC3_A, + M_LWC3_AB, + M_LWL_A, + M_LWL_AB, + M_LWR_A, + M_LWR_AB, + M_LWU_AB, + M_MSGSND, + M_MSGLD, + M_MSGLD_T, + M_MSGWAIT, + M_MSGWAIT_T, + M_MOVE, + M_MUL, + M_MUL_I, + M_MULO, + M_MULO_I, + M_MULOU, + M_MULOU_I, + M_NOR_I, + M_OR_I, + M_REM_3, + M_REM_3I, + M_REMU_3, + M_REMU_3I, + M_DROL, + M_ROL, + M_DROL_I, + M_ROL_I, + M_DROR, + M_ROR, + M_DROR_I, + M_ROR_I, + M_S_DA, + M_S_DOB, + M_S_DAB, + M_S_S, + M_SC_AB, + M_SCD_AB, + M_SD_A, + M_SD_OB, + M_SD_AB, + M_SDC1_AB, + M_SDC2_AB, + M_SDC3_AB, + M_SDL_AB, + M_SDR_AB, + M_SEQ, + M_SEQ_I, + M_SGE, + M_SGE_I, + M_SGEU, + M_SGEU_I, + M_SGT, + M_SGT_I, + M_SGTU, + M_SGTU_I, + M_SLE, + M_SLE_I, + M_SLEU, + M_SLEU_I, + M_SLT_I, + M_SLTU_I, + M_SNE, + M_SNE_I, + M_SB_A, + M_SB_AB, + M_SH_A, + M_SH_AB, + M_SW_A, + M_SW_AB, + M_SWC0_A, + M_SWC0_AB, + M_SWC1_A, + M_SWC1_AB, + M_SWC2_A, + M_SWC2_AB, + M_SWC3_A, + M_SWC3_AB, + M_SWL_A, + M_SWL_AB, + M_SWR_A, + M_SWR_AB, + M_SUB_I, + M_SUBU_I, + M_SUBU_I_2, + M_TEQ_I, + M_TGE_I, + M_TGEU_I, + M_TLT_I, + M_TLTU_I, + M_TNE_I, + M_TRUNCWD, + M_TRUNCWS, + M_ULD, + M_ULD_A, + M_ULH, + M_ULH_A, + M_ULHU, + M_ULHU_A, + M_ULW, + M_ULW_A, + M_USH, + M_USH_A, + M_USW, + M_USW_A, + M_USD, + M_USD_A, + M_XOR_I, + M_COP0, + M_COP1, + M_COP2, + M_COP3, + M_NUM_MACROS +}; + + +/* The order of overloaded instructions matters. Label arguments and + register arguments look the same. Instructions that can have either + for arguments must apear in the correct order in this table for the + assembler to pick the right one. In other words, entries with + immediate operands must apear after the same instruction with + registers. + + Many instructions are short hand for other instructions (i.e., The + jal instruction is short for jalr ). */ + +/* The rest of this file adds definitions for the mips16 TinyRISC + processor. */ + +/* These are the bitmasks and shift counts used for the different + fields in the instruction formats. Other than OP, no masks are + provided for the fixed portions of an instruction, since they are + not needed. + + The I format uses IMM11. + + The RI format uses RX and IMM8. + + The RR format uses RX, and RY. + + The RRI format uses RX, RY, and IMM5. + + The RRR format uses RX, RY, and RZ. + + The RRI_A format uses RX, RY, and IMM4. + + The SHIFT format uses RX, RY, and SHAMT. + + The I8 format uses IMM8. + + The I8_MOVR32 format uses RY and REGR32. + + The IR_MOV32R format uses REG32R and MOV32Z. + + The I64 format uses IMM8. + + The RI64 format uses RY and IMM5. + */ + +#define MIPS16OP_MASK_OP 0x1f +#define MIPS16OP_SH_OP 11 +#define MIPS16OP_MASK_IMM11 0x7ff +#define MIPS16OP_SH_IMM11 0 +#define MIPS16OP_MASK_RX 0x7 +#define MIPS16OP_SH_RX 8 +#define MIPS16OP_MASK_IMM8 0xff +#define MIPS16OP_SH_IMM8 0 +#define MIPS16OP_MASK_RY 0x7 +#define MIPS16OP_SH_RY 5 +#define MIPS16OP_MASK_IMM5 0x1f +#define MIPS16OP_SH_IMM5 0 +#define MIPS16OP_MASK_RZ 0x7 +#define MIPS16OP_SH_RZ 2 +#define MIPS16OP_MASK_IMM4 0xf +#define MIPS16OP_SH_IMM4 0 +#define MIPS16OP_MASK_REGR32 0x1f +#define MIPS16OP_SH_REGR32 0 +#define MIPS16OP_MASK_REG32R 0x1f +#define MIPS16OP_SH_REG32R 3 +#define MIPS16OP_EXTRACT_REG32R(i) ((((i) >> 5) & 7) | ((i) & 0x18)) +#define MIPS16OP_MASK_MOVE32Z 0x7 +#define MIPS16OP_SH_MOVE32Z 0 +#define MIPS16OP_MASK_IMM6 0x3f +#define MIPS16OP_SH_IMM6 5 + +/* These are the characters which may appears in the args field of a MIPS16 + instruction. They appear in the order in which the fields appear when the + instruction is used. Commas and parentheses in the args string are ignored + when assembling, and written into the output when disassembling. + + "y" 3 bit register (MIPS16OP_*_RY) + "x" 3 bit register (MIPS16OP_*_RX) + "z" 3 bit register (MIPS16OP_*_RZ) + "Z" 3 bit register (MIPS16OP_*_MOVE32Z) + "v" 3 bit same register as source and destination (MIPS16OP_*_RX) + "w" 3 bit same register as source and destination (MIPS16OP_*_RY) + "0" zero register ($0) + "S" stack pointer ($sp or $29) + "P" program counter + "R" return address register ($ra or $31) + "X" 5 bit MIPS register (MIPS16OP_*_REGR32) + "Y" 5 bit MIPS register (MIPS16OP_*_REG32R) + "6" 6 bit unsigned break code (MIPS16OP_*_IMM6) + "a" 26 bit jump address + "e" 11 bit extension value + "l" register list for entry instruction + "L" register list for exit instruction + + The remaining codes may be extended. Except as otherwise noted, + the full extended operand is a 16 bit signed value. + "<" 3 bit unsigned shift count * 0 (MIPS16OP_*_RZ) (full 5 bit unsigned) + ">" 3 bit unsigned shift count * 0 (MIPS16OP_*_RX) (full 5 bit unsigned) + "[" 3 bit unsigned shift count * 0 (MIPS16OP_*_RZ) (full 6 bit unsigned) + "]" 3 bit unsigned shift count * 0 (MIPS16OP_*_RX) (full 6 bit unsigned) + "4" 4 bit signed immediate * 0 (MIPS16OP_*_IMM4) (full 15 bit signed) + "5" 5 bit unsigned immediate * 0 (MIPS16OP_*_IMM5) + "H" 5 bit unsigned immediate * 2 (MIPS16OP_*_IMM5) + "W" 5 bit unsigned immediate * 4 (MIPS16OP_*_IMM5) + "D" 5 bit unsigned immediate * 8 (MIPS16OP_*_IMM5) + "j" 5 bit signed immediate * 0 (MIPS16OP_*_IMM5) + "8" 8 bit unsigned immediate * 0 (MIPS16OP_*_IMM8) + "V" 8 bit unsigned immediate * 4 (MIPS16OP_*_IMM8) + "C" 8 bit unsigned immediate * 8 (MIPS16OP_*_IMM8) + "U" 8 bit unsigned immediate * 0 (MIPS16OP_*_IMM8) (full 16 bit unsigned) + "k" 8 bit signed immediate * 0 (MIPS16OP_*_IMM8) + "K" 8 bit signed immediate * 8 (MIPS16OP_*_IMM8) + "p" 8 bit conditional branch address (MIPS16OP_*_IMM8) + "q" 11 bit branch address (MIPS16OP_*_IMM11) + "A" 8 bit PC relative address * 4 (MIPS16OP_*_IMM8) + "B" 5 bit PC relative address * 8 (MIPS16OP_*_IMM5) + "E" 5 bit PC relative address * 4 (MIPS16OP_*_IMM5) + "m" 7 bit register list for save instruction (18 bit extended) + "M" 7 bit register list for restore instruction (18 bit extended) + */ + +/* Save/restore encoding for the args field when all 4 registers are + either saved as arguments or saved/restored as statics. */ +#define MIPS16_ALL_ARGS 0xe +#define MIPS16_ALL_STATICS 0xb + +/* For the mips16, we use the same opcode table format and a few of + the same flags. However, most of the flags are different. */ + +/* Modifies the register in MIPS16OP_*_RX. */ +#define MIPS16_INSN_WRITE_X 0x00000001 +/* Modifies the register in MIPS16OP_*_RY. */ +#define MIPS16_INSN_WRITE_Y 0x00000002 +/* Modifies the register in MIPS16OP_*_RZ. */ +#define MIPS16_INSN_WRITE_Z 0x00000004 +/* Modifies the T ($24) register. */ +#define MIPS16_INSN_WRITE_T 0x00000008 +/* Modifies the SP ($29) register. */ +#define MIPS16_INSN_WRITE_SP 0x00000010 +/* Modifies the RA ($31) register. */ +#define MIPS16_INSN_WRITE_31 0x00000020 +/* Modifies the general purpose register in MIPS16OP_*_REG32R. */ +#define MIPS16_INSN_WRITE_GPR_Y 0x00000040 +/* Reads the register in MIPS16OP_*_RX. */ +#define MIPS16_INSN_READ_X 0x00000080 +/* Reads the register in MIPS16OP_*_RY. */ +#define MIPS16_INSN_READ_Y 0x00000100 +/* Reads the register in MIPS16OP_*_MOVE32Z. */ +#define MIPS16_INSN_READ_Z 0x00000200 +/* Reads the T ($24) register. */ +#define MIPS16_INSN_READ_T 0x00000400 +/* Reads the SP ($29) register. */ +#define MIPS16_INSN_READ_SP 0x00000800 +/* Reads the RA ($31) register. */ +#define MIPS16_INSN_READ_31 0x00001000 +/* Reads the program counter. */ +#define MIPS16_INSN_READ_PC 0x00002000 +/* Reads the general purpose register in MIPS16OP_*_REGR32. */ +#define MIPS16_INSN_READ_GPR_X 0x00004000 +/* Is an unconditional branch insn. */ +#define MIPS16_INSN_UNCOND_BRANCH 0x00008000 +/* Is a conditional branch insn. */ +#define MIPS16_INSN_COND_BRANCH 0x00010000 + +/* The following flags have the same value for the mips16 opcode + table: + INSN_UNCOND_BRANCH_DELAY + INSN_COND_BRANCH_DELAY + INSN_COND_BRANCH_LIKELY (never used) + INSN_READ_HI + INSN_READ_LO + INSN_WRITE_HI + INSN_WRITE_LO + INSN_TRAP + INSN_ISA3 + */ + +/* A NOP insn impemented as "or at,at,zero". + Used to implement -mfix-loongson2f. */ +#define LOONGSON2F_NOP_INSN 0x00200825 + +#endif /* _MIPS_H_ */ diff --git a/src/cmd/as/mips16-opc.c b/src/cmd/as/mips16-opc.c new file mode 100644 index 0000000..fbc2f32 --- /dev/null +++ b/src/cmd/as/mips16-opc.c @@ -0,0 +1,224 @@ +/* + * This is the opcodes table for the mips16 processor. The format of + * this table is intentionally identical to the one in mips-opc.c. + * However, the special letters that appear in the argument string are + * different, and the table uses some different flags. + * + * Copyright 1996, 1997, 1998, 2000, 2005, 2006, 2007 + * Free Software Foundation, Inc. + * Contributed by Ian Lance Taylor, Cygnus Support + * Adapted for VirtualMIPS by Serge Vakulenko. + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + */ + +/* Use some short hand macros to keep down the length of the lines in + the opcodes table. */ + +#define UBD INSN_UNCOND_BRANCH_DELAY +#define UBR MIPS16_INSN_UNCOND_BRANCH +#define CBR MIPS16_INSN_COND_BRANCH + +#define WR_x MIPS16_INSN_WRITE_X +#define WR_y MIPS16_INSN_WRITE_Y +#define WR_z MIPS16_INSN_WRITE_Z +#define WR_T MIPS16_INSN_WRITE_T +#define WR_SP MIPS16_INSN_WRITE_SP +#define WR_31 MIPS16_INSN_WRITE_31 +#define WR_Y MIPS16_INSN_WRITE_GPR_Y + +#define RD_x MIPS16_INSN_READ_X +#define RD_y MIPS16_INSN_READ_Y +#define RD_Z MIPS16_INSN_READ_Z +#define RD_T MIPS16_INSN_READ_T +#define RD_SP MIPS16_INSN_READ_SP +#define RD_31 MIPS16_INSN_READ_31 +#define RD_PC MIPS16_INSN_READ_PC +#define RD_X MIPS16_INSN_READ_GPR_X + +#define WR_HI INSN_WRITE_HI +#define WR_LO INSN_WRITE_LO +#define RD_HI INSN_READ_HI +#define RD_LO INSN_READ_LO + +#define TRAP INSN_TRAP + +#define I1 INSN_ISA1 +#define I3 INSN_ISA3 +#define I32 INSN_ISA32 +#define I64 INSN_ISA64 +#define T3 INSN_3900 + +static const struct mips_opcode mips16_opcodes[] = +{ +/* name, args, match, mask, pinfo, pinfo2, membership */ +{"nop", "", 0x6500, 0xffff, RD_Z, 0, I1 }, /* move $0,$Z */ +{"la", "x,A", 0x0800, 0xf800, WR_x|RD_PC, 0, I1 }, +{"addiu", "y,x,4", 0x4000, 0xf810, WR_y|RD_x, 0, I1 }, +{"addiu", "x,k", 0x4800, 0xf800, WR_x|RD_x, 0, I1 }, +{"addiu", "S,K", 0x6300, 0xff00, WR_SP|RD_SP, 0, I1 }, +{"addiu", "S,S,K", 0x6300, 0xff00, WR_SP|RD_SP, 0, I1 }, +{"addiu", "x,P,V", 0x0800, 0xf800, WR_x|RD_PC, 0, I1 }, +{"addiu", "x,S,V", 0x0000, 0xf800, WR_x|RD_SP, 0, I1 }, +{"addu", "z,v,y", 0xe001, 0xf803, WR_z|RD_x|RD_y, 0, I1 }, +{"addu", "y,x,4", 0x4000, 0xf810, WR_y|RD_x, 0, I1 }, +{"addu", "x,k", 0x4800, 0xf800, WR_x|RD_x, 0, I1 }, +{"addu", "S,K", 0x6300, 0xff00, WR_SP|RD_SP, 0, I1 }, +{"addu", "S,S,K", 0x6300, 0xff00, WR_SP|RD_SP, 0, I1 }, +{"addu", "x,P,V", 0x0800, 0xf800, WR_x|RD_PC, 0, I1 }, +{"addu", "x,S,V", 0x0000, 0xf800, WR_x|RD_SP, 0, I1 }, +{"and", "x,y", 0xe80c, 0xf81f, WR_x|RD_x|RD_y, 0, I1 }, +{"b", "q", 0x1000, 0xf800, UBR, 0, I1 }, +{"beqz", "x,p", 0x2000, 0xf800, CBR|RD_x, 0, I1 }, +{"bnez", "x,p", 0x2800, 0xf800, CBR|RD_x, 0, I1 }, +{"break", "6", 0xe805, 0xf81f, TRAP, 0, I1 }, +{"bteqz", "p", 0x6000, 0xff00, CBR|RD_T, 0, I1 }, +{"btnez", "p", 0x6100, 0xff00, CBR|RD_T, 0, I1 }, +{"cmpi", "x,U", 0x7000, 0xf800, WR_T|RD_x, 0, I1 }, +{"cmp", "x,y", 0xe80a, 0xf81f, WR_T|RD_x|RD_y, 0, I1 }, +{"cmp", "x,U", 0x7000, 0xf800, WR_T|RD_x, 0, I1 }, +{"dla", "y,E", 0xfe00, 0xff00, WR_y|RD_PC, 0, I3 }, +{"daddiu", "y,x,4", 0x4010, 0xf810, WR_y|RD_x, 0, I3 }, +{"daddiu", "y,j", 0xfd00, 0xff00, WR_y|RD_y, 0, I3 }, +{"daddiu", "S,K", 0xfb00, 0xff00, WR_SP|RD_SP, 0, I3 }, +{"daddiu", "S,S,K", 0xfb00, 0xff00, WR_SP|RD_SP, 0, I3 }, +{"daddiu", "y,P,W", 0xfe00, 0xff00, WR_y|RD_PC, 0, I3 }, +{"daddiu", "y,S,W", 0xff00, 0xff00, WR_y|RD_SP, 0, I3 }, +{"daddu", "z,v,y", 0xe000, 0xf803, WR_z|RD_x|RD_y, 0, I3 }, +{"daddu", "y,x,4", 0x4010, 0xf810, WR_y|RD_x, 0, I3 }, +{"daddu", "y,j", 0xfd00, 0xff00, WR_y|RD_y, 0, I3 }, +{"daddu", "S,K", 0xfb00, 0xff00, WR_SP|RD_SP, 0, I3 }, +{"daddu", "S,S,K", 0xfb00, 0xff00, WR_SP|RD_SP, 0, I3 }, +{"daddu", "y,P,W", 0xfe00, 0xff00, WR_y|RD_PC, 0, I3 }, +{"daddu", "y,S,W", 0xff00, 0xff00, WR_y|RD_SP, 0, I3 }, +{"ddiv", "0,x,y", 0xe81e, 0xf81f, RD_x|RD_y|WR_HI|WR_LO, 0, I3 }, +{"ddivu", "0,x,y", 0xe81f, 0xf81f, RD_x|RD_y|WR_HI|WR_LO, 0, I3 }, +{"div", "0,x,y", 0xe81a, 0xf81f, RD_x|RD_y|WR_HI|WR_LO, 0, I1 }, +{"divu", "0,x,y", 0xe81b, 0xf81f, RD_x|RD_y|WR_HI|WR_LO, 0, I1 }, +{"dmult", "x,y", 0xe81c, 0xf81f, RD_x|RD_y|WR_HI|WR_LO, 0, I3 }, +{"dmultu", "x,y", 0xe81d, 0xf81f, RD_x|RD_y|WR_HI|WR_LO, 0, I3 }, +{"drem", "0,x,y", 0xe81e, 0xf81f, RD_x|RD_y|WR_HI|WR_LO, 0, I3 }, +{"dremu", "0,x,y", 0xe81f, 0xf81f, RD_x|RD_y|WR_HI|WR_LO, 0, I3 }, +{"dsllv", "y,x", 0xe814, 0xf81f, WR_y|RD_y|RD_x, 0, I3 }, +{"dsll", "x,w,[", 0x3001, 0xf803, WR_x|RD_y, 0, I3 }, +{"dsll", "y,x", 0xe814, 0xf81f, WR_y|RD_y|RD_x, 0, I3 }, +{"dsrav", "y,x", 0xe817, 0xf81f, WR_y|RD_y|RD_x, 0, I3 }, +{"dsra", "y,]", 0xe813, 0xf81f, WR_y|RD_y, 0, I3 }, +{"dsra", "y,x", 0xe817, 0xf81f, WR_y|RD_y|RD_x, 0, I3 }, +{"dsrlv", "y,x", 0xe816, 0xf81f, WR_y|RD_y|RD_x, 0, I3 }, +{"dsrl", "y,]", 0xe808, 0xf81f, WR_y|RD_y, 0, I3 }, +{"dsrl", "y,x", 0xe816, 0xf81f, WR_y|RD_y|RD_x, 0, I3 }, +{"dsubu", "z,v,y", 0xe002, 0xf803, WR_z|RD_x|RD_y, 0, I3 }, +{"exit", "L", 0xed09, 0xff1f, TRAP, 0, I1 }, +{"exit", "L", 0xee09, 0xff1f, TRAP, 0, I1 }, +{"exit", "L", 0xef09, 0xff1f, TRAP, 0, I1 }, +{"entry", "l", 0xe809, 0xf81f, TRAP, 0, I1 }, +{"extend", "e", 0xf000, 0xf800, 0, 0, I1 }, +{"jalr", "x", 0xe840, 0xf8ff, UBD|WR_31|RD_x, 0, I1 }, +{"jalr", "R,x", 0xe840, 0xf8ff, UBD|WR_31|RD_x, 0, I1 }, +{"jal", "x", 0xe840, 0xf8ff, UBD|WR_31|RD_x, 0, I1 }, +{"jal", "R,x", 0xe840, 0xf8ff, UBD|WR_31|RD_x, 0, I1 }, +{"jal", "a", 0x1800, 0xfc00, UBD|WR_31, 0, I1 }, +{"jalx", "a", 0x1c00, 0xfc00, UBD|WR_31, 0, I1 }, +{"jr", "x", 0xe800, 0xf8ff, UBD|RD_x, 0, I1 }, +{"jr", "R", 0xe820, 0xffff, UBD|RD_31, 0, I1 }, +{"j", "x", 0xe800, 0xf8ff, UBD|RD_x, 0, I1 }, +{"j", "R", 0xe820, 0xffff, UBD|RD_31, 0, I1 }, +{"lb", "y,5(x)", 0x8000, 0xf800, WR_y|RD_x, 0, I1 }, +{"lbu", "y,5(x)", 0xa000, 0xf800, WR_y|RD_x, 0, I1 }, +{"ld", "y,D(x)", 0x3800, 0xf800, WR_y|RD_x, 0, I3 }, +{"ld", "y,B", 0xfc00, 0xff00, WR_y|RD_PC, 0, I3 }, +{"ld", "y,D(P)", 0xfc00, 0xff00, WR_y|RD_PC, 0, I3 }, +{"ld", "y,D(S)", 0xf800, 0xff00, WR_y|RD_SP, 0, I3 }, +{"lh", "y,H(x)", 0x8800, 0xf800, WR_y|RD_x, 0, I1 }, +{"lhu", "y,H(x)", 0xa800, 0xf800, WR_y|RD_x, 0, I1 }, +{"li", "x,U", 0x6800, 0xf800, WR_x, 0, I1 }, +{"lw", "y,W(x)", 0x9800, 0xf800, WR_y|RD_x, 0, I1 }, +{"lw", "x,A", 0xb000, 0xf800, WR_x|RD_PC, 0, I1 }, +{"lw", "x,V(P)", 0xb000, 0xf800, WR_x|RD_PC, 0, I1 }, +{"lw", "x,V(S)", 0x9000, 0xf800, WR_x|RD_SP, 0, I1 }, +{"lwu", "y,W(x)", 0xb800, 0xf800, WR_y|RD_x, 0, I3 }, +{"mfhi", "x", 0xe810, 0xf8ff, WR_x|RD_HI, 0, I1 }, +{"mflo", "x", 0xe812, 0xf8ff, WR_x|RD_LO, 0, I1 }, +{"move", "y,X", 0x6700, 0xff00, WR_y|RD_X, 0, I1 }, +{"move", "Y,Z", 0x6500, 0xff00, WR_Y|RD_Z, 0, I1 }, +{"mult", "x,y", 0xe818, 0xf81f, RD_x|RD_y|WR_HI|WR_LO, 0, I1 }, +{"multu", "x,y", 0xe819, 0xf81f, RD_x|RD_y|WR_HI|WR_LO, 0, I1 }, +{"neg", "x,w", 0xe80b, 0xf81f, WR_x|RD_y, 0, I1 }, +{"not", "x,w", 0xe80f, 0xf81f, WR_x|RD_y, 0, I1 }, +{"or", "x,y", 0xe80d, 0xf81f, WR_x|RD_x|RD_y, 0, I1 }, +{"rem", "0,x,y", 0xe81a, 0xf81f, RD_x|RD_y|WR_HI|WR_LO, 0, I1 }, +{"remu", "0,x,y", 0xe81b, 0xf81f, RD_x|RD_y|WR_HI|WR_LO, 0, I1 }, +{"sb", "y,5(x)", 0xc000, 0xf800, RD_y|RD_x, 0, I1 }, +{"sd", "y,D(x)", 0x7800, 0xf800, RD_y|RD_x, 0, I3 }, +{"sd", "y,D(S)", 0xf900, 0xff00, RD_y|RD_PC, 0, I3 }, +{"sd", "R,C(S)", 0xfa00, 0xff00, RD_31|RD_PC, 0, I1 }, +{"sh", "y,H(x)", 0xc800, 0xf800, RD_y|RD_x, 0, I1 }, +{"sllv", "y,x", 0xe804, 0xf81f, WR_y|RD_y|RD_x, 0, I1 }, +{"sll", "x,w,<", 0x3000, 0xf803, WR_x|RD_y, 0, I1 }, +{"sll", "y,x", 0xe804, 0xf81f, WR_y|RD_y|RD_x, 0, I1 }, +{"slti", "x,8", 0x5000, 0xf800, WR_T|RD_x, 0, I1 }, +{"slt", "x,y", 0xe802, 0xf81f, WR_T|RD_x|RD_y, 0, I1 }, +{"slt", "x,8", 0x5000, 0xf800, WR_T|RD_x, 0, I1 }, +{"sltiu", "x,8", 0x5800, 0xf800, WR_T|RD_x, 0, I1 }, +{"sltu", "x,y", 0xe803, 0xf81f, WR_T|RD_x|RD_y, 0, I1 }, +{"sltu", "x,8", 0x5800, 0xf800, WR_T|RD_x, 0, I1 }, +{"srav", "y,x", 0xe807, 0xf81f, WR_y|RD_y|RD_x, 0, I1 }, +{"sra", "x,w,<", 0x3003, 0xf803, WR_x|RD_y, 0, I1 }, +{"sra", "y,x", 0xe807, 0xf81f, WR_y|RD_y|RD_x, 0, I1 }, +{"srlv", "y,x", 0xe806, 0xf81f, WR_y|RD_y|RD_x, 0, I1 }, +{"srl", "x,w,<", 0x3002, 0xf803, WR_x|RD_y, 0, I1 }, +{"srl", "y,x", 0xe806, 0xf81f, WR_y|RD_y|RD_x, 0, I1 }, +{"subu", "z,v,y", 0xe003, 0xf803, WR_z|RD_x|RD_y, 0, I1 }, +{"sw", "y,W(x)", 0xd800, 0xf800, RD_y|RD_x, 0, I1 }, +{"sw", "x,V(S)", 0xd000, 0xf800, RD_x|RD_SP, 0, I1 }, +{"sw", "R,V(S)", 0x6200, 0xff00, RD_31|RD_SP, 0, I1 }, +{"xor", "x,y", 0xe80e, 0xf81f, WR_x|RD_x|RD_y, 0, I1 }, + /* MIPS16e additions */ +{"jalrc", "x", 0xe8c0, 0xf8ff, UBR|WR_31|RD_x|TRAP, 0, I32 }, +{"jalrc", "R,x", 0xe8c0, 0xf8ff, UBR|WR_31|RD_x|TRAP, 0, I32 }, +{"jrc", "x", 0xe880, 0xf8ff, UBR|RD_x|TRAP, 0, I32 }, +{"jrc", "R", 0xe8a0, 0xffff, UBR|RD_31|TRAP, 0, I32 }, +{"restore", "M", 0x6400, 0xff80, WR_31|RD_SP|WR_SP|TRAP, 0, I32 }, +{"save", "m", 0x6480, 0xff80, RD_31|RD_SP|WR_SP|TRAP, 0, I32 }, +{"sdbbp", "6", 0xe801, 0xf81f, TRAP, 0, I32 }, +{"seb", "x", 0xe891, 0xf8ff, WR_x|RD_x, 0, I32 }, +{"seh", "x", 0xe8b1, 0xf8ff, WR_x|RD_x, 0, I32 }, +{"sew", "x", 0xe8d1, 0xf8ff, WR_x|RD_x, 0, I64 }, +{"zeb", "x", 0xe811, 0xf8ff, WR_x|RD_x, 0, I32 }, +{"zeh", "x", 0xe831, 0xf8ff, WR_x|RD_x, 0, I32 }, +{"zew", "x", 0xe851, 0xf8ff, WR_x|RD_x, 0, I64 }, +}; + +static const int mips16_num_opcodes = + ((sizeof mips16_opcodes) / (sizeof (mips16_opcodes[0]))); + +#undef UBD +#undef UBR +#undef CBR +#undef WR_x +#undef WR_y +#undef WR_z +#undef WR_T +#undef WR_SP +#undef WR_31 +#undef WR_Y +#undef RD_x +#undef RD_y +#undef RD_Z +#undef RD_T +#undef RD_SP +#undef RD_31 +#undef RD_PC +#undef RD_X +#undef WR_HI +#undef WR_LO +#undef RD_HI +#undef RD_LO +#undef TRAP +#undef I1 +#undef I3 +#undef I32 +#undef I64 +#undef T3 diff --git a/src/cmd/as/tests/Makefile b/src/cmd/as/tests/Makefile new file mode 100644 index 0000000..2a7d529 --- /dev/null +++ b/src/cmd/as/tests/Makefile @@ -0,0 +1,19 @@ +TOPSRC = $(shell cd ../../../..; pwd) +include $(TOPSRC)/target.mk + +CFLAGS += -Wall -Os +TESTS = test1 test2 test3 test4 + +all: ../as ../aout + for i in $(TESTS); do \ + $(AS) $$i.s -o $$i.o; \ + $(OBJDUMP) -D $$i.o > $$i.gcc-dis; \ + ../as $$i.s -o $$i.o; \ + ../aout -r $$i.o > $$i.dis; \ + done + +clean: + rm -f *.o *.dis *.gcc-dis + +hello.s: hello.c + $(CC) $(CFLAGS) -S $< diff --git a/src/cmd/as/tests/hello.c b/src/cmd/as/tests/hello.c new file mode 100644 index 0000000..d7a3e34 --- /dev/null +++ b/src/cmd/as/tests/hello.c @@ -0,0 +1,4 @@ +void hello() +{ + puts ("Hello, World!\n"); +} diff --git a/src/cmd/as/tests/test1.s b/src/cmd/as/tests/test1.s new file mode 100644 index 0000000..bc50805 --- /dev/null +++ b/src/cmd/as/tests/test1.s @@ -0,0 +1,117 @@ +# .set noreorder + add $2, $16, $31 + addi $2, $3, 123 + addiu $3, $4, 234 + addu $2, $31, $17 + and $31, $3, $18 + andi $4, $5, 345 + b .+0x14 + bal .-0x28 + beq $3, $2, .+4 + beql $2, $3, .-8 + bgez $4, .+12 + bgezal $5, .-16 + bgezall $6, .+20 + bgezl $7, .-24 + bgtz $8, .+28 + bgtzl $9, .-32 + blez $10, .+36 + blezl $11, .-40 + bltz $12, .+44 + bltzal $13, .-48 + bltzall $14, .+52 + bltzl $15, .-56 + bne $16, $17, .-60 + bnel $17, $18, .+64 + break 123 + clo $3, $2 + clz $2, $3 + deret + di $4 + div $5, $6 + divu $6, $7 + ehb + ei $8 + eret + ext $9, $10, 12, 5 + ins $10, $11, 13, 6 + j .+0x3c + jal .-0x40 + jalr $12, $13 + jalr.hb $14, $15 + jr $16 + jr.hb $17 + lb $18, 123($19) + lbu $20, 321($21) + lh $22, 234($23) + lhu $24, 432($25) + ll $26, 468($27) + lui $5, 987 + lw $28, 864($29) + lwl $30, 124($31) + lwr $3, 420($2) + madd $3, $4 + maddu $5, $6 + mfc0 $7, $8, 7 + mfhi $9 + mflo $10 + move $11, $12 + movn $19, $31, $4 + movz $31, $5, $20 + msub $13, $14 + msubu $15, $16 + mtc0 $17, $18, 5 + mthi $19 + mtlo $20 + mul $6, $21, $31 + mult $21, $22 + multu $23, $24 + nop + nor $22, $31, $7 + or $31, $8, $23 + ori $5, $6, 456 + rdhwr $25, $26 + rdpgpr $27, $28 + ror $29, $30, 27 + rorv $31, $3, $2 + sb $3, 123($4) + sc $5, 324($6) + sdbbp 234 + seb $7, $8 + seh $9, $10 + sh $11, 432($12) + sll $13, $14, 15 + sllv $15, $16, $17 + slt $9, $24, $31 + slti $6, $7, 567 + sltiu $7, $8, 678 + sltu $25, $31, $10 + sra $18, $19, 9 + srav $20, $21, $22 + srl $23, $24, 25 + srlv $25, $26, $27 + ssnop + sub $31, $11, $26 + subu $12, $27, $31 + sw $28, 426($29) + swl $30, 123($31) + swr $31, 321($3) + sync 1 + syscall 654 + teq $2, $3 + teqi $4, .+4 + tge $5, $6 + tgei $7, .-8 + tgeiu $8, .+12 + tgeu $9, $10 + tlt $11, $12 + tlti $13, .-16 + tltiu $14, .+20 + tltu $15, $16 + tne $17, $18 + tnei $19, .-24 + wait 53 + wrpgpr $20, $21 + wsbh $22, $23 + xor $28, $31, $13 + xori $8, $9, 789 diff --git a/src/cmd/as/tests/test2.s b/src/cmd/as/tests/test2.s new file mode 100644 index 0000000..da43fb1 --- /dev/null +++ b/src/cmd/as/tests/test2.s @@ -0,0 +1,37 @@ + .file 1 "hello.c" + .section .mdebug.abi32 + .previous + .gnu_attribute 4, 3 + .section .rodata.str1.4,"aMS",@progbits,1 + .align 2 +.LC0: + .ascii "Hello, World!\012\000" + .section .text.hello,"ax",@progbits + .align 2 + .globl hello + .set nomips16 + .set nomicromips + .ent hello + .type hello, @function +hello: + .frame $sp,0,$31 # vars= 0, regs= 0/0, args= 0, gp= 0 + .mask 0x00000000,0 + .fmask 0x00000000,0 + .set noreorder + .set nomacro +# Begin mchp_output_function_prologue +# End mchp_output_function_prologue + lui $4,%hi(.LC0) + j puts + addiu $4,$4,%lo(.LC0) + + .set macro + .set reorder +# Begin mchp_output_function_epilogue +# End mchp_output_function_epilogue + .end hello + .size hello, .-hello + .ident "GCC: (chipKIT) 4.5.1 chipKIT Compiler for PIC32 MCUs v1.30-20110506" +# Begin MCHP vector dispatch table +# End MCHP vector dispatch table +# MCHP configuration words diff --git a/src/cmd/as/tests/test3.s b/src/cmd/as/tests/test3.s new file mode 100644 index 0000000..687d9bb --- /dev/null +++ b/src/cmd/as/tests/test3.s @@ -0,0 +1,49 @@ + .file 1 "hello.c" + .section .mdebug.abi32 + .previous + .gnu_attribute 4, 3 + .rdata + .align 2 +.LC0: + .ascii "Hello, World!\012\000" + .section .text.hello,"ax",@progbits + .align 2 + .globl hello + .set nomips16 + .set nomicromips + .ent hello + .type hello, @function +hello: + .frame $fp,24,$31 # vars= 0, regs= 2/0, args= 16, gp= 0 + .mask 0xc0000000,-4 + .fmask 0x00000000,0 + .set noreorder + .set nomacro +# Begin mchp_output_function_prologue +# End mchp_output_function_prologue + addiu $sp,$sp,-24 + sw $31,20($sp) + sw $fp,16($sp) + move $fp,$sp + lui $2,%hi(.LC0) + addiu $4,$2,%lo(.LC0) + jal puts + nop + + move $sp,$fp + lw $31,20($sp) + lw $fp,16($sp) + addiu $sp,$sp,24 + j $31 + nop + + .set macro + .set reorder +# Begin mchp_output_function_epilogue +# End mchp_output_function_epilogue + .end hello + .size hello, .-hello + .ident "GCC: (chipKIT) 4.5.1 chipKIT Compiler for PIC32 MCUs v1.30-20110506" +# Begin MCHP vector dispatch table +# End MCHP vector dispatch table +# MCHP configuration words diff --git a/src/cmd/as/tests/test4.s b/src/cmd/as/tests/test4.s new file mode 100644 index 0000000..e958928 --- /dev/null +++ b/src/cmd/as/tests/test4.s @@ -0,0 +1,90 @@ + .file 1 "crt0.c" + .section .mdebug.abi32 + .previous + .gnu_attribute 4, 3 + .section .text._start,"ax",@progbits + .align 2 + .globl _start + .set nomips16 + .set nomicromips + .ent _start + .type _start, @function +_start: + .frame $sp,24,$31 # vars= 0, regs= 1/0, args= 16, gp= 0 + .mask 0x80000000,-4 + .fmask 0x00000000,0 +# Begin mchp_output_function_prologue +# End mchp_output_function_prologue + addiu $sp,$sp,-24 + sw $31,20($sp) + #APP + # 69 "crt0.c" 1 + la $gp, _gp + # 0 "" 2 + #NO_APP + .set noreorder + .set nomacro + blez $4,.L2 + sw $6,%gp_rel(environ)($28) + .set macro + .set reorder + + lw $2,0($5) + beq $2,$0,.L2 + sw $2,%gp_rel(__progname)($28) + lb $3,0($2) + .set noreorder + .set nomacro + beq $3,$0,.L2 + addiu $2,$2,1 + .set macro + .set reorder + + li $7,47 # 0x2f +.L4: + .set noreorder + .set nomacro + beql $3,$7,.L3 + sw $2,%gp_rel(__progname)($28) + .set macro + .set reorder + +.L3: + lb $3,0($2) + .set noreorder + .set nomacro + bne $3,$0,.L4 + addiu $2,$2,1 + .set macro + .set reorder + +.L2: + jal main + .set noreorder + .set nomacro + jal exit + move $4,$2 + .set macro + .set reorder + +# Begin mchp_output_function_epilogue +# End mchp_output_function_epilogue + .end _start + .size _start, .-_start + .globl __progname + .section .rodata.str1.4,"aMS",@progbits,1 + .align 2 +.LC0: + .ascii "\000" + .section .sdata.__progname,"aw",@progbits + .align 2 + .type __progname, @object + .size __progname, 4 +__progname: + .word .LC0 + + .comm environ,4,4 + .ident "GCC: (chipKIT) 4.5.1 chipKIT Compiler for PIC32 MCUs v1.30-20110506" +# Begin MCHP vector dispatch table +# End MCHP vector dispatch table +# MCHP configuration words diff --git a/src/cmd/awk/EXPLAIN b/src/cmd/awk/EXPLAIN new file mode 100644 index 0000000..69ab718 --- /dev/null +++ b/src/cmd/awk/EXPLAIN @@ -0,0 +1,87 @@ +Nov 30, 1979: + +Awk has been modified yet again, in an attempt to make +its behavior more rational and predictable in the areas +of initialization, comparison, and type coercion. +Herewith what we believe the current truth to be: + +1. Each variable and field can potentially be a string +or a number or both at any time. +When a variable is set by the assignment + v = expr +its type is set to that of expr. (This includes +=, ++, etc.) +An arithmetic expression is of type number, a +concatenation is of type string, and so on. + +If the assignment is a simple copy, as in + v1 = v2 +then the type of v1 becomes that of v2. + +2. In comparisons, if both operands are numeric, +the comparison is made numerically. Otherwise, +operands are coerced to string if necessary, and +the comparison is made on strings. + +3. The type of any expression can be coerced to +numeric by subterfuges (kludges?) such as + expr + 0 +and to string by + expr "" +(i.e., concatenation with a null string). + +4. Uninitialized variables have the numeric value +0 and the string value "". Accordingly, if x is +uninitialized, + if (x) ... +is false, and + if (!x) ... + if (x == 0) ... + if (x == "") ... +are all true. But note that + if (x == "0") ... +is false. + +5. The type of a field is determined by context +when possible; for example, + $1++ +clearly implies that $1 is to be numeric, and + $1 = $1 "," $2 +implies that $1 and $2 are both to be strings. +Coercion will be done as needed. + +In contexts where types cannot be reliably determined, e.g., + if ($1 == $2) ... +the type of each field is determined on input by +inspection. All fields are strings; in addition, +each field that contains only a number (in the +sense of Fortran, say) is also considered numeric. +This ensures (for better or worse) that the test + if ($1 == $2) ... +will succeed on the inputs + 0 0.0 + 100 1e2 + +100 100 + 1e-3 1e-3 +and fail on the inputs + (null) 0 + (null) 0.0 + 2E-518 6E-427 +as we believe it should. + +Fields which are explicitly null have the string +value ""; they are not numeric. +Non-existent fields (i.e., fields past NF) are +treated this way too. + +As it is for fields, so it is for array elements +created by split(...). + +6. There is no warranty of merchantability nor any warranty +of fitness for a particular purpose nor any other warranty, +either express or implied, as to the accuracy of the +enclosed materials or as to their suitability for any +particular purpose. Accordingly, the AWK Development +Task Force assumes no responsibility for their use by the +recipient. Further, the Task Force assumes no obligation +to furnish any assistance of any kind whatsoever, or to +furnish any additional information or documentation. diff --git a/src/cmd/awk/Makefile b/src/cmd/awk/Makefile new file mode 100644 index 0000000..2bcfc2e --- /dev/null +++ b/src/cmd/awk/Makefile @@ -0,0 +1,44 @@ +TOPSRC = $(shell cd ../../..; pwd) +include $(TOPSRC)/target.mk + +CFLAGS += -Werror -Os + +YACC = bison -y +YFLAGS = -d +LIBS = -lm -lc +FILES = awk.lx.o b.o main.o tran.o lib.o run.o parse.o proctab.o freeze.o +SOURCE = awk.def.h awk.g.y awk.lx.l b.c lib.c main.c parse.c \ + proc.c freeze.c run.c tran.c + +awk: $(FILES) awk.g.o + ${CC} ${LDFLAGS} -o awk.elf $(FILES) awk.g.o ${LIBS} + ${OBJDUMP} -S awk.elf > awk.dis + ${SIZE} awk.elf + ${ELF2AOUT} awk.elf $@ && rm awk.elf + +y.tab.h: awk.g.o + +awk.h: y.tab.h + -cmp -s y.tab.h awk.h || cp y.tab.h awk.h + +$(FILES): awk.h awk.def.h + +token.h: awk.h tokenscript + ex - < tokenscript + +install: awk + install awk ${DESTDIR}/bin/ + +profile: awk.g.o $(FILES) mon.o + cc -p -i awk.g.o $(FILES) mon.o -lm + +lint: + lint -spu b.c main.c tran.c run.c lib.c parse.c -lm |\ + egrep -v '^(error|free|malloc)' + +proctab.c: proc.c token.h awk.h + cc -Wall -Werror -o proc proc.c + ./proc > proctab.c + +clean: + -rm -f *.o *.tmp awk.lx.c *.out *.elf *.dis y.tab.* awk.h proc proctab.c token.h awk diff --git a/src/cmd/awk/README b/src/cmd/awk/README new file mode 100644 index 0000000..30723b8 --- /dev/null +++ b/src/cmd/awk/README @@ -0,0 +1,99 @@ +CHANGES as of July 12: + +1. \ddd allowed in regular expressions. + +2. exit causes the expression to +to be the status return upon completion. + +3. a new builtin called "getline" causes the next +input line to be read immediately. Fields, NR, etc., +are all set, but you are left at exactly the same place +in the awk program. Getline returns 0 for end of file; +1 for a normal record. + + +CHANGES SINCE MEMO: +Update to TM of Sept 1, 1978: + +1. A new form of for loop + for (i in array) + statement +is now available. It provides a way to walk +along the members of an array, most usefully +for associative arrays with non-numeric subscripts. +Elements are accessed in an unpredictable order, +so don't count on anything. +Futhermore, havoc ensues if elements are created +during this operation, or if the index variable +is fiddled. + +2. index(s1, s2) returns the position in s1 +where s2 first occurs, or 0 if it doesn't. + +3. Multi-line records are now supported more +conveniently. If the record separator is null + RS = "" +then a blank line terminates a record, and newline +is a default field separator, along with +blank and tab. + +4. The syntax of split has been changed. + n = split(str, arrayname, sep) +splits the string str into the array using +the separator sep (a single character). +If no sep field is given, FS is used instead. +The elements are array[1] ... array[n]; n +is the function value. + +5. some minor bugs have been fixed. + +IMPLEMENTATION NOTES: + +Things to watch out for when trying to make awk: + +1. The yacc -d business creates a new file y.tab.h +with the yacc #defines in it. this is compared to +awk.h on each successive compile, and major recompilation +is done only if the files differ. (This permits editing +the grammar file without causing everything in sight +to be recompiled, so long as the definitions don't +change.) + +2. The program proc.c is compiled into proc, which +is used to create proctab.c. proctab.c is the +table of function pointers used by run to actually +execute things. Don't try to load proc.c with the +other .c files; it also contains a "main()". + +3. Awk uses structure assignment. Be sure your +version of the C compiler has it. + +4. The loader flag -lm is used to fetch the standard +math library on the Research system. It is more likely +that you will want to use -lS on yours. +run.c also includes "math.h", which contains sensible +definitions for log(), sqrt(), etc. If you don't have this +include file, comment the line out, and all will be well +anyway. + +5. The basic sequence of events (in case make doesn't +seem to do the job) is + yacc -d awk.g.y + cc -O -c y.tab.c + mv y.tab.o awk.g.o + lex awk.lx.l + cc -O -c lex.yy.c + mv lex.yy.o awk.lx.o + cc -O -c b.c + cc -O -c main.c + e - proctab.c + cc -O -c proctab.c + cc -i -O awk.g.o awk.lx.o b.o main.o token.o tran.o lib.o run.o parse.o proctab.o -lm diff --git a/src/cmd/awk/awk.def.h b/src/cmd/awk/awk.def.h new file mode 100644 index 0000000..7765e0c --- /dev/null +++ b/src/cmd/awk/awk.def.h @@ -0,0 +1,135 @@ +/* awk.def 4.3 83/12/09 */ + +#define hack int +#define AWKFLOAT float +#define xfree(a) { if(a!=NULL) { yfree(a); a=NULL;} } +#define strfree(a) { if(a!=NULL && a!=EMPTY) { yfree(a);} a=EMPTY; } +#define yfree free +#define isnull(x) ((x) == EMPTY || (x) == NULL) + +#ifdef DEBUG +# define dprintf if(dbg)printf +#else +# define dprintf(x1, x2, x3, x4) +#endif +typedef AWKFLOAT awkfloat; + +extern char **FS; +extern char **RS; +extern char **ORS; +extern char **OFS; +extern char **OFMT; +extern awkfloat *NR; +extern awkfloat *NF; +extern char **FILENAME; + +extern char record[]; +extern char EMPTY[]; +extern int dbg; +extern int lineno; +extern int errorflag; +extern int donefld; /* 1 if record broken into fields */ +extern int donerec; /* 1 if record is valid (no fld has changed */ + +typedef struct val { /* general value during processing */ + char *nval; /* name, for variables only */ + char *sval; /* string value */ + awkfloat fval; /* value as number */ + unsigned tval; /* type info */ + struct val *nextval; /* ptr to next if chained */ +} cell; +extern cell *symtab[]; +cell *setsymtab(), *lookup(), **makesymtab(); + +extern cell *recloc; /* location of input record */ +extern cell *nrloc; /* NR */ +extern cell *nfloc; /* NF */ + +#define STR 01 /* string value is valid */ +#define NUM 02 /* number value is valid */ +#define FLD 04 /* FLD means don't free string space */ +#define CON 010 /* this is a constant */ +#define ARR 020 /* this is an array */ + +awkfloat setfval(), getfval(); +char *setsval(), *getsval(); +char *tostring(), *tokname(); + +/* function types */ +#define FLENGTH 1 +#define FSQRT 2 +#define FEXP 3 +#define FLOG 4 +#define FINT 5 + +typedef struct { + char otype; + char osub; + cell *optr; +} obj; + +#define BOTCH 1 +struct nd { + char ntype; + char subtype; + struct nd *nnext; + int nobj; + struct nd *narg[BOTCH]; /* C won't take a zero length array */ +}; +typedef struct nd node; +extern node *winner; +extern node *nullstat; + +/* otypes */ +#define OCELL 0 +#define OEXPR 1 +#define OBOOL 2 +#define OJUMP 3 + +/* cell subtypes */ +#define CTEMP 4 +#define CNAME 3 +#define CVAR 2 +#define CFLD 1 +#define CCON 0 + +/* bool subtypes */ +#define BTRUE 1 +#define BFALSE 2 + +/* jump subtypes */ +#define JEXIT 1 +#define JNEXT 2 +#define JBREAK 3 +#define JCONT 4 + +/* node types */ +#define NVALUE 1 +#define NSTAT 2 +#define NEXPR 3 +#define NPA2 4 + +typedef obj (*objfunc)(); +extern const objfunc proctab[]; +extern obj true, false; +extern int pairstack[], paircnt; + +#define cantexec(n) (n->ntype == NVALUE) +#define notlegal(n) (n <= FIRSTTOKEN || n >= LASTTOKEN || proctab[n-FIRSTTOKEN]== nullproc) +#define isexpr(n) (n->ntype == NEXPR) +#define isjump(n) (n.otype == OJUMP) +#define isexit(n) (n.otype == OJUMP && n.osub == JEXIT) +#define isbreak(n) (n.otype == OJUMP && n.osub == JBREAK) +#define iscont(n) (n.otype == OJUMP && n.osub == JCONT) +#define isnext(n) (n.otype == OJUMP && n.osub == JNEXT) +#define isstr(n) (n.optr->tval & STR) +#define istrue(n) (n.otype == OBOOL && n.osub == BTRUE) +#define istemp(n) (n.otype == OCELL && n.osub == CTEMP) +#define isfld(n) (!donefld && n.osub==CFLD && n.otype==OCELL && n.optr->nval==EMPTY) +#define isrec(n) (donefld && n.osub==CFLD && n.otype==OCELL && n.optr->nval!=EMPTY) +obj nullproc(); +obj relop(); + +#define MAXSYM 50 +#define HAT 0177 /* matches ^ in regular expr */ + /* watch out for mach dep */ diff --git a/src/cmd/awk/awk.g.y b/src/cmd/awk/awk.g.y new file mode 100644 index 0000000..57640d0 --- /dev/null +++ b/src/cmd/awk/awk.g.y @@ -0,0 +1,274 @@ +/* awk.g.y 4.1 82/05/07 */ + +%token FIRSTTOKEN /*must be first*/ +%token FINAL FATAL +%token LT LE GT GE EQ NE +%token MATCH NOTMATCH +%token APPEND +%token ADD MINUS MULT DIVIDE MOD UMINUS +%token ASSIGN ADDEQ SUBEQ MULTEQ DIVEQ MODEQ +%token JUMP +%token XBEGIN XEND +%token NL +%token PRINT PRINTF SPRINTF SPLIT +%token IF ELSE WHILE FOR IN NEXT EXIT BREAK CONTINUE +%token PROGRAM PASTAT PASTAT2 + +%right ASGNOP +%left BOR +%left AND +%left NOT +%left NUMBER VAR ARRAY FNCN SUBSTR LSUBSTR INDEX +%left GETLINE +%nonassoc RELOP MATCHOP +%left OR +%left STRING DOT CCL NCCL CHAR +%left '(' '^' '$' +%left CAT +%left '+' '-' +%left '*' '/' '%' +%left STAR PLUS QUEST +%left POSTINCR PREINCR POSTDECR PREDECR INCR DECR +%left FIELD INDIRECT +%token LASTTOKEN /* has to be last */ + +%{ +#include "awk.def.h" +#ifndef DEBUG +# define PUTS(x) +#endif +%} +%% + +program: + begin pa_stats end { if (errorflag==0) winner = (node *)stat3(PROGRAM, $1, $2, $3); } + | error { yyclearin; yyerror("bailing out"); } + ; + +begin: + XBEGIN '{' stat_list '}' { PUTS("XBEGIN list"); $$ = $3; } + | begin NL + | { PUTS("empty XBEGIN"); $$ = (hack)nullstat; } + ; + +end: + XEND '{' stat_list '}' { PUTS("XEND list"); $$ = $3; } + | end NL + | { PUTS("empty END"); $$ = (hack)nullstat; } + ; + +compound_conditional: + conditional BOR conditional { PUTS("cond||cond"); $$ = op2(BOR, $1, $3); } + | conditional AND conditional { PUTS("cond&&cond"); $$ = op2(AND, $1, $3); } + | NOT conditional { PUTS("!cond"); $$ = op1(NOT, $2); } + | '(' compound_conditional ')' { $$ = $2; } + ; + +compound_pattern: + pattern BOR pattern { PUTS("pat||pat"); $$ = op2(BOR, $1, $3); } + | pattern AND pattern { PUTS("pat&&pat"); $$ = op2(AND, $1, $3); } + | NOT pattern { PUTS("!pat"); $$ = op1(NOT, $2); } + | '(' compound_pattern ')' { $$ = $2; } + ; + +conditional: + expr { PUTS("expr"); $$ = op2(NE, $1, valtonode(lookup("$zero&null", symtab, 0), CCON)); } + | rel_expr { PUTS("relexpr"); } + | lex_expr { PUTS("lexexpr"); } + | compound_conditional { PUTS("compcond"); } + ; + +else: + ELSE optNL { PUTS("else"); } + ; + +field: + FIELD { PUTS("field"); $$ = valtonode($1, CFLD); } + | INDIRECT term { PUTS("ind field"); $$ = op1(INDIRECT, $2); } + ; + +if: + IF '(' conditional ')' optNL { PUTS("if(cond)"); $$ = $3; } + ; + +lex_expr: + expr MATCHOP regular_expr { PUTS("expr~re"); $$ = op2($2, $1, makedfa($3)); } + | '(' lex_expr ')' { PUTS("(lex_expr)"); $$ = $2; } + ; + +var: + NUMBER {PUTS("number"); $$ = valtonode($1, CCON); } + | STRING { PUTS("string"); $$ = valtonode($1, CCON); } + | VAR { PUTS("var"); $$ = valtonode($1, CVAR); } + | VAR '[' expr ']' { PUTS("array[]"); $$ = op2(ARRAY, $1, $3); } + | field + ; +term: + var + | GETLINE { PUTS("getline"); $$ = op1(GETLINE, 0); } + | FNCN { PUTS("func"); + $$ = op2(FNCN, $1, valtonode(lookup("$record", symtab, 0), CFLD)); + } + | FNCN '(' ')' { PUTS("func()"); + $$ = op2(FNCN, $1, valtonode(lookup("$record", symtab, 0), CFLD)); + } + | FNCN '(' expr ')' { PUTS("func(expr)"); $$ = op2(FNCN, $1, $3); } + | SPRINTF print_list { PUTS("sprintf"); $$ = op1($1, $2); } + | SUBSTR '(' expr ',' expr ',' expr ')' + { PUTS("substr(e,e,e)"); $$ = op3(SUBSTR, $3, $5, $7); } + | SUBSTR '(' expr ',' expr ')' + { PUTS("substr(e,e,e)"); $$ = op3(SUBSTR, $3, $5, nullstat); } + | SPLIT '(' expr ',' VAR ',' expr ')' + { PUTS("split(e,e,e)"); $$ = op3(SPLIT, $3, $5, $7); } + | SPLIT '(' expr ',' VAR ')' + { PUTS("split(e,e,e)"); $$ = op3(SPLIT, $3, $5, nullstat); } + | INDEX '(' expr ',' expr ')' + { PUTS("index(e,e)"); $$ = op2(INDEX, $3, $5); } + | '(' expr ')' {PUTS("(expr)"); $$ = $2; } + | term '+' term { PUTS("t+t"); $$ = op2(ADD, $1, $3); } + | term '-' term { PUTS("t-t"); $$ = op2(MINUS, $1, $3); } + | term '*' term { PUTS("t*t"); $$ = op2(MULT, $1, $3); } + | term '/' term { PUTS("t/t"); $$ = op2(DIVIDE, $1, $3); } + | term '%' term { PUTS("t%t"); $$ = op2(MOD, $1, $3); } + | '-' term %prec QUEST { PUTS("-term"); $$ = op1(UMINUS, $2); } + | '+' term %prec QUEST { PUTS("+term"); $$ = $2; } + | INCR var { PUTS("++var"); $$ = op1(PREINCR, $2); } + | DECR var { PUTS("--var"); $$ = op1(PREDECR, $2); } + | var INCR { PUTS("var++"); $$= op1(POSTINCR, $1); } + | var DECR { PUTS("var--"); $$= op1(POSTDECR, $1); } + ; + +expr: + term { PUTS("term"); } + | expr term { PUTS("expr term"); $$ = op2(CAT, $1, $2); } + | var ASGNOP expr { PUTS("var=expr"); $$ = stat2($2, $1, $3); } + ; + +optNL: + NL + | + ; + +pa_stat: + pattern { PUTS("pattern"); $$ = stat2(PASTAT, $1, genprint()); } + | pattern '{' stat_list '}' { PUTS("pattern {...}"); $$ = stat2(PASTAT, $1, $3); } + | pattern ',' pattern { PUTS("srch,srch"); $$ = pa2stat($1, $3, genprint()); } + | pattern ',' pattern '{' stat_list '}' + { PUTS("srch, srch {...}"); $$ = pa2stat($1, $3, $5); } + | '{' stat_list '}' { PUTS("null pattern {...}"); $$ = stat2(PASTAT, nullstat, $2); } + ; + +pa_stats: + pa_stats pa_stat st { PUTS("pa_stats pa_stat"); $$ = linkum($1, $2); } + | { PUTS("null pa_stat"); $$ = (hack)nullstat; } + | pa_stats pa_stat {PUTS("pa_stats pa_stat"); $$ = linkum($1, $2); } + ; + +pattern: + regular_expr { PUTS("regex"); + $$ = op2(MATCH, valtonode(lookup("$record", symtab, 0), CFLD), makedfa($1)); + } + | rel_expr { PUTS("relexpr"); } + | lex_expr { PUTS("lexexpr"); } + | compound_pattern { PUTS("comp pat"); } + ; + +print_list: + expr { PUTS("expr"); } + | pe_list { PUTS("pe_list"); } + | { PUTS("null print_list"); $$ = valtonode(lookup("$record", symtab, 0), CFLD); } + ; + +pe_list: + expr ',' expr {$$ = linkum($1, $3); } + | pe_list ',' expr {$$ = linkum($1, $3); } + | '(' pe_list ')' {$$ = $2; } + ; + +redir: + RELOP + | '|' + ; + +regular_expr: + '/' { startreg(); } + r '/' + { PUTS("/r/"); $$ = $3; } + ; + +r: + CHAR { PUTS("regex CHAR"); $$ = op2(CHAR, (node *) 0, $1); } + | DOT { PUTS("regex DOT"); $$ = op2(DOT, (node *) 0, (node *) 0); } + | CCL { PUTS("regex CCL"); $$ = op2(CCL, (node *) 0, cclenter($1)); } + | NCCL { PUTS("regex NCCL"); $$ = op2(NCCL, (node *) 0, cclenter($1)); } + | '^' { PUTS("regex ^"); $$ = op2(CHAR, (node *) 0, HAT); } + | '$' { PUTS("regex $"); $$ = op2(CHAR, (node *) 0 ,(node *) 0); } + | r OR r { PUTS("regex OR"); $$ = op2(OR, $1, $3); } + | r r %prec CAT + { PUTS("regex CAT"); $$ = op2(CAT, $1, $2); } + | r STAR { PUTS("regex STAR"); $$ = op2(STAR, $1, (node *) 0); } + | r PLUS { PUTS("regex PLUS"); $$ = op2(PLUS, $1, (node *) 0); } + | r QUEST { PUTS("regex QUEST"); $$ = op2(QUEST, $1, (node *) 0); } + | '(' r ')' { PUTS("(regex)"); $$ = $2; } + ; + +rel_expr: + expr RELOP expr + { PUTS("expr relop expr"); $$ = op2($2, $1, $3); } + | '(' rel_expr ')' + { PUTS("(relexpr)"); $$ = $2; } + ; + +st: + NL + | ';' + ; + +simple_stat: + PRINT print_list redir expr + { PUTS("print>stat"); $$ = stat3($1, $2, $3, $4); } + | PRINT print_list + { PUTS("print list"); $$ = stat3($1, $2, nullstat, nullstat); } + | PRINTF print_list redir expr + { PUTS("printf>stat"); $$ = stat3($1, $2, $3, $4); } + | PRINTF print_list + { PUTS("printf list"); $$ = stat3($1, $2, nullstat, nullstat); } + | expr { PUTS("expr"); $$ = exptostat($1); } + | { PUTS("null simple statement"); $$ = (hack)nullstat; } + | error { yyclearin; yyerror("illegal statement"); } + ; + +statement: + simple_stat st { PUTS("simple stat"); } + | if statement { PUTS("if stat"); $$ = stat3(IF, $1, $2, nullstat); } + | if statement else statement + { PUTS("if-else stat"); $$ = stat3(IF, $1, $2, $4); } + | while statement { PUTS("while stat"); $$ = stat2(WHILE, $1, $2); } + | for { PUTS("for stat"); } + | NEXT st { PUTS("next"); $$ = stat1(NEXT, 0); } + | EXIT st { PUTS("exit"); $$ = stat1(EXIT, 0); } + | EXIT expr st { PUTS("exit"); $$ = stat1(EXIT, $2); } + | BREAK st { PUTS("break"); $$ = stat1(BREAK, 0); } + | CONTINUE st { PUTS("continue"); $$ = stat1(CONTINUE, 0); } + | '{' stat_list '}' { PUTS("{statlist}"); $$ = $2; } + ; + +stat_list: + stat_list statement { PUTS("stat_list stat"); $$ = linkum($1, $2); } + | { PUTS("null stat list"); $$ = (hack)nullstat; } + ; + +while: + WHILE '(' conditional ')' optNL { PUTS("while(cond)"); $$ = $3; } + ; + +for: + FOR '(' simple_stat ';' conditional ';' simple_stat ')' optNL statement + { PUTS("for(e;e;e)"); $$ = stat4(FOR, $3, $5, $7, $10); } + | FOR '(' simple_stat ';' ';' simple_stat ')' optNL statement + { PUTS("for(e;e;e)"); $$ = stat4(FOR, $3, nullstat, $6, $9); } + | FOR '(' VAR IN VAR ')' optNL statement + { PUTS("for(v in v)"); $$ = stat3(IN, $3, $5, $8); } + ; + +%% diff --git a/src/cmd/awk/awk.lx.l b/src/cmd/awk/awk.lx.l new file mode 100644 index 0000000..2e45d26 --- /dev/null +++ b/src/cmd/awk/awk.lx.l @@ -0,0 +1,169 @@ +/* awk.lx.l 4.3 84/12/08 */ + +%Start A str chc sc reg comment + +%{ +#include "awk.h" +#include "awk.def.h" +#define YY_NO_INPUT /* defeat lex */ +extern int yylval; +extern int mustfld; + +int lineno = 1; +#define CADD cbuf[clen++]=yytext[0]; if(clen>=CBUFLEN-1) {yyerror("string too long", cbuf); BEGIN A;} +#define CBUFLEN 150 +char cbuf[CBUFLEN]; +int clen, cflag; +%} + +A [a-zA-Z_] +B [a-zA-Z0-9_] +D [0-9] +WS [ \t] + +%% + /* witchcraft */ + /* switch (yybgin-yysvec-1) { + case 0: + BEGIN A; + break; + case sc: + BEGIN A; + return('}'); + } */ + +^\n lineno++; +^{WS}*#.*\n lineno++; /* strip comment lines */ +{WS} ; +"\\"\n lineno++; +"||" return(BOR); +BEGIN return(XBEGIN); +END return(XEND); +PROGEND return(EOF); +"&&" return(AND); +"!" return(NOT); +"!=" { yylval = NE; return(RELOP); } +"~" { yylval = MATCH; return(MATCHOP); } +"!~" { yylval = NOTMATCH; return(MATCHOP); } +"<" { yylval = LT; return(RELOP); } +"<=" { yylval = LE; return(RELOP); } +"==" { yylval = EQ; return(RELOP); } +">=" { yylval = GE; return(RELOP); } +">" { yylval = GT; return(RELOP); } +">>" { yylval = APPEND; return(RELOP); } +"++" { yylval = INCR; return(INCR); } +"--" { yylval = DECR; return(DECR); } +"+=" { yylval = ADDEQ; return(ASGNOP); } +"-=" { yylval = SUBEQ; return(ASGNOP); } +"*=" { yylval = MULTEQ; return(ASGNOP); } +"/=" { yylval = DIVEQ; return(ASGNOP); } +"%=" { yylval = MODEQ; return(ASGNOP); } +"=" { yylval = ASSIGN; return(ASGNOP); } + +"$"{D}+ { if (atoi(yytext+1)==0) { + yylval = (hack)lookup("$record", symtab, 0); + return(STRING); + } else { + yylval = fieldadr(atoi(yytext+1)); + return(FIELD); + } + } +"$"{WS}* { return(INDIRECT); } +NF { mustfld=1; yylval = (hack)setsymtab(yytext, EMPTY, 0.0, NUM, symtab); return(VAR); } +({D}+("."?){D}*|"."{D}+)((e|E)("+"|-)?{D}+)? { + yylval = (hack)setsymtab(yytext, EMPTY, atof(yytext), CON|NUM, symtab); return(NUMBER); } +"}"{WS}*\n { BEGIN sc; lineno++; return(';'); } +"}" { BEGIN sc; return(';'); } +;\n { lineno++; return(';'); } +\n { lineno++; return(NL); } +while return(WHILE); +for return(FOR); +if return(IF); +else return(ELSE); +next return(NEXT); +exit return(EXIT); +break return(BREAK); +continue return(CONTINUE); +print { yylval = PRINT; return(PRINT); } +printf { yylval = PRINTF; return(PRINTF); } +sprintf { yylval = SPRINTF; return(SPRINTF); } +split { yylval = SPLIT; return(SPLIT); } +substr return(SUBSTR); +index return(INDEX); +in return(IN); +getline return(GETLINE); +length { yylval = FLENGTH; return(FNCN); } +log { yylval = FLOG; return(FNCN); } +int { yylval = FINT; return(FNCN); } +exp { yylval = FEXP; return(FNCN); } +sqrt { yylval = FSQRT; return(FNCN); } +{A}{B}* { yylval = (hack)setsymtab(yytext, tostring(""), 0.0, STR|NUM, symtab); return(VAR); } +\" { BEGIN str; clen=0; } + +# { BEGIN comment; } +\n { BEGIN A; lineno++; return(NL); } +. ; + +. { yylval = yytext[0]; return(yytext[0]); } + +"[" { BEGIN chc; clen=0; cflag=0; } +"[^" { BEGIN chc; clen=0; cflag=1; } + +"?" return(QUEST); +"+" return(PLUS); +"*" return(STAR); +"|" return(OR); +"." return(DOT); +"(" return('('); +")" return(')'); +"^" return('^'); +"$" return('$'); +\\{D}{D}{D} { sscanf(yytext+1, "%o", &yylval); return(CHAR); } +\\. { if (yytext[1]=='n') yylval = '\n'; + else if (yytext[1] == 't') yylval = '\t'; + else yylval = yytext[1]; + return(CHAR); + } +"/" { BEGIN A; unput('/'); } +\n { yyerror("newline in regular expression"); lineno++; BEGIN A; } +. { yylval = yytext[0]; return(CHAR); } + +\" { char *s; BEGIN A; cbuf[clen]=0; s = tostring(cbuf); + cbuf[clen] = ' '; cbuf[++clen] = 0; + yylval = (hack)setsymtab(cbuf, s, 0.0, CON|STR, symtab); return(STRING); } +\n { yyerror("newline in string"); lineno++; BEGIN A; } +"\\\"" { cbuf[clen++]='"'; } +"\\"n { cbuf[clen++]='\n'; } +"\\"t { cbuf[clen++]='\t'; } +"\\\\" { cbuf[clen++]='\\'; } +. { CADD; } + +"\\""]" { cbuf[clen++]=']'; } +"]" { BEGIN reg; cbuf[clen]=0; yylval = (hack)tostring(cbuf); + if (cflag==0) { return(CCL); } + else { return(NCCL); } } +\n { yyerror("newline in character class"); lineno++; BEGIN A; } +. { CADD; } + +%% + +input() +{ + register c; + extern char *lexprog; + + if (yyin == NULL) + c = *lexprog++; + else + c = getc(yyin); + if (c == '\n') + yylineno++; + else if (c == EOF) + c = 0; + return(c); +} + +startreg() +{ + BEGIN reg; +} diff --git a/src/cmd/awk/b.c b/src/cmd/awk/b.c new file mode 100644 index 0000000..8b02d27 --- /dev/null +++ b/src/cmd/awk/b.c @@ -0,0 +1,536 @@ +#include +#include +#include "awk.def.h" +#include "awk.h" + +extern node *op2(); +extern struct fa *cgotofn(); +#define MAXLIN 256 +#define NCHARS 128 +#define NSTATES 256 + +#define type(v) v->nobj +#define left(v) v->narg[0] +#define right(v) v->narg[1] +#define parent(v) v->nnext + +#define LEAF case CCL: case NCCL: case CHAR: case DOT: +#define UNARY case FINAL: case STAR: case PLUS: case QUEST: + +/* encoding in tree nodes: + leaf (CCL, NCCL, CHAR, DOT): left is index, right contains value or pointer to value + unary (FINAL, STAR, PLUS, QUEST): left is child, right is null + binary (CAT, OR): left and right are children + parent contains pointer to parent +*/ + +struct fa { + int cch; + struct fa *st; +}; + +int *state[NSTATES]; +int *foll[MAXLIN]; +char chars[MAXLIN]; +int setvec[MAXLIN]; +node *point[MAXLIN]; + +int setcnt; +int line; + + +struct fa *makedfa(p) /* returns dfa for tree pointed to by p */ +node *p; +{ + node *p1; + struct fa *fap; + p1 = op2(CAT, op2(STAR, op2(DOT, (node *) 0, (node *) 0), (node *) 0), p); + /* put DOT STAR in front of reg. exp. */ + p1 = op2(FINAL, p1, (node *) 0); /* install FINAL node */ + + line = 0; + penter(p1); /* enter parent pointers and leaf indices */ + point[line] = p1; /* FINAL node */ + setvec[0] = 1; /* for initial DOT STAR */ + cfoll(p1); /* set up follow sets */ + fap = cgotofn(); + freetr(p1); /* add this when alloc works */ + return(fap); +} + +penter(p) /* set up parent pointers and leaf indices */ +node *p; +{ + switch(type(p)) { + LEAF + left(p) = (node *) line; + point[line++] = p; + break; + UNARY + penter(left(p)); + parent(left(p)) = p; + break; + case CAT: + case OR: + penter(left(p)); + penter(right(p)); + parent(left(p)) = p; + parent(right(p)) = p; + break; + default: + error(FATAL, "unknown type %d in penter\n", type(p)); + break; + } +} + +freetr(p) /* free parse tree and follow sets */ +node *p; +{ + switch(type(p)) { + LEAF + xfree(foll[(int) left(p)]); + xfree(p); + break; + UNARY + freetr(left(p)); + xfree(p); + break; + case CAT: + case OR: + freetr(left(p)); + freetr(right(p)); + xfree(p); + break; + default: + error(FATAL, "unknown type %d in freetr", type(p)); + break; + } +} +char *cclenter(p) +register char *p; +{ + register i, c; + char *op; + + op = p; + i = 0; + while ((c = *p++) != 0) { + if (c == '-' && i > 0 && chars[i-1] != 0) { + if (*p != 0) { + c = chars[i-1]; + while (c < *p) { + if (i >= MAXLIN) + overflo(); + chars[i++] = ++c; + } + p++; + continue; + } + } + if (i >= MAXLIN) + overflo(); + chars[i++] = c; + } + chars[i++] = '\0'; + dprintf("cclenter: in = |%s|, out = |%s|\n", op, chars, NULL); + xfree(op); + return(tostring(chars)); +} + +overflo() +{ + error(FATAL, "regular expression too long\n"); +} + +cfoll(v) /* enter follow set of each leaf of vertex v into foll[leaf] */ +register node *v; +{ + register i; + int prev; + int *add(); + + switch(type(v)) { + LEAF + setcnt = 0; + for (i=1; i<=line; i++) + setvec[i] = 0; + follow(v); + if (notin(foll, ( (int) left(v))-1, &prev)) { + foll[(int) left(v)] = add(setcnt); + } + else + foll[ (int) left(v)] = foll[prev]; + break; + UNARY + cfoll(left(v)); + break; + case CAT: + case OR: + cfoll(left(v)); + cfoll(right(v)); + break; + default: + error(FATAL, "unknown type %d in cfoll", type(v)); + } +} + +first(p) /* collects initially active leaves of p into setvec */ +register node *p; /* returns 0 or 1 depending on whether p matches empty string */ +{ + register b; + + switch(type(p)) { + LEAF + if (setvec[(int) left(p)] != 1) { + setvec[(int) left(p)] = 1; + setcnt++; + } + if (type(p) == CCL && (*(char *) right(p)) == '\0') + return(0); /* empty CCL */ + else return(1); + case FINAL: + case PLUS: + if (first(left(p)) == 0) return(0); + return(1); + case STAR: + case QUEST: + first(left(p)); + return(0); + case CAT: + if (first(left(p)) == 0 && first(right(p)) == 0) return(0); + return(1); + case OR: + b = first(right(p)); + if (first(left(p)) == 0 || b == 0) return(0); + return(1); + } + error(FATAL, "unknown type %d in first\n", type(p)); + return(-1); +} + +follow(v) +node *v; /* collects leaves that can follow v into setvec */ +{ + node *p; + + if (type(v) == FINAL) + return; + p = parent(v); + switch (type(p)) { + case STAR: + case PLUS: first(v); + follow(p); + return; + + case OR: + case QUEST: follow(p); + return; + + case CAT: if (v == left(p)) { /* v is left child of p */ + if (first(right(p)) == 0) { + follow(p); + return; + } + } + else /* v is right child */ + follow(p); + return; + case FINAL: if (setvec[line] != 1) { + setvec[line] = 1; + setcnt++; + } + return; + } +} + +member(c, s) /* is c in s? */ +register char c, *s; +{ + while (*s) + if (c == *s++) + return(1); + return(0); +} + +notin(array, n, prev) /* is setvec in array[0] thru array[n]? */ +int **array; +int *prev; { + register i, j; + int *ptr; + for (i=0; i<=n; i++) { + ptr = array[i]; + if (*ptr == setcnt) { + for (j=0; j < setcnt; j++) + if (setvec[*(++ptr)] != 1) goto nxt; + *prev = i; + return(0); + } + nxt: ; + } + return(1); +} + +int *add(n) { /* remember setvec */ + int *ptr, *p; + register i; + if ((p = ptr = (int *) malloc((n+1)*sizeof(int))) == NULL) + overflo(); + *ptr = n; + dprintf("add(%d)\n", n, NULL, NULL); + for (i=1; i <= line; i++) + if (setvec[i] == 1) { + *(++ptr) = i; + dprintf(" ptr = %o, *ptr = %d, i = %d\n", ptr, *ptr, i); + } + dprintf("\n", NULL, NULL, NULL); + return(p); +} + +struct fa *cgotofn() +{ + register i, k; + register int *ptr; + char c; + char *p; + node *cp; + int j, n, s, ind, numtrans; + int finflg; + int curpos, num, prev; + struct fa *where[NSTATES]; + + int fatab[257]; + struct fa *pfa; + + char index[MAXLIN]; + char iposns[MAXLIN]; + int sposns[MAXLIN]; + int spmax, spinit; + + char symbol[NCHARS]; + char isyms[NCHARS]; + char ssyms[NCHARS]; + int ssmax, ssinit; + + for (i=0; i<=line; i++) index[i] = iposns[i] = setvec[i] = 0; + for (i=0; i= NSTATES) { + dprintf("cgotofn: notin; state = %d, n = %d\n", state, n, NULL); + overflo(); + } + state[++n] = add(setcnt); + dprintf(" delta(%d,%o) = %d", s,c,n); + dprintf(", ind = %d\n", ind+1, NULL, NULL); + fatab[++ind] = c; + fatab[++ind] = n; + numtrans++; + } + else { + if (prev != 0) { + dprintf(" delta(%d,%o) = %d", s,c,prev); + dprintf(", ind = %d\n", ind+1, NULL, NULL); + fatab[++ind] = c; + fatab[++ind] = prev; + numtrans++; + } + } + } + tenter: + if ((pfa = (struct fa *) malloc((numtrans + 1) * sizeof(struct fa))) == NULL) + overflo(); + where[s] = pfa; + if (finflg) + pfa->cch = -1; /* s is a final state */ + else + pfa->cch = numtrans; + pfa->st = 0; + for (i=1, pfa += 1; i<=numtrans; i++, pfa++) { + pfa->cch = fatab[2*i-1]; + pfa->st = (struct fa *) fatab[2*i]; + } + } + for (i=0; i<=n; i++) { + xfree(state[i]); /* free state[i] */ + pfa = where[i]; + pfa->st = where[0]; + dprintf("state %d: (%o)\n", i, pfa, NULL); + dprintf(" numtrans = %d, default = %o\n", pfa->cch, pfa->st, NULL); + for (k=1; k<=pfa->cch; k++) { + (pfa+k)->st = where[ (int) (pfa+k)->st]; + dprintf(" char = %o, nextstate = %o\n",(pfa+k)->cch, (pfa+k)->st, NULL); + } + } + pfa = where[0]; + if ((num = pfa->cch) < 0) + return(where[0]); + for (pfa += num; num; num--, pfa--) + if (pfa->cch == HAT) { + return(pfa->st); + } + return(where[0]); +} + +match(pfa, p) +register struct fa *pfa; +register char *p; +{ + register count; + char c; + if (p == 0) return(0); + if (pfa->cch == 1) { /* fast test for first character, if possible */ + c = (++pfa)->cch; + do + if (c == *p) { + p++; + pfa = pfa->st; + goto adv; + } + while (*p++ != 0); + return(0); + } + adv: if ((count = pfa->cch) < 0) return(1); + do { + for (pfa += count; count; count--, pfa--) + if (pfa->cch == *p) { + break; + } + pfa = pfa->st; + if ((count = pfa->cch) < 0) return(1); + } while(*p++ != 0); + return(0); +} diff --git a/src/cmd/awk/freeze.c b/src/cmd/awk/freeze.c new file mode 100644 index 0000000..e5b171a --- /dev/null +++ b/src/cmd/awk/freeze.c @@ -0,0 +1,39 @@ +#include "stdio.h" + +freeze(s) + char *s; +{ + int fd; + unsigned int *len; + + len = (unsigned int *)sbrk(0); + if((fd = creat(s, 0666)) < 0) { + perror(s); + return(1); + } + write(fd, &len, sizeof(len)); + write(fd, (char *)0, len); + close(fd); + return(0); +} + +thaw(s) + char *s; +{ + int fd; + unsigned int *len; + + if(*s == 0) { + fprintf(stderr, "empty restore file\n"); + return(1); + } + if((fd = open(s, 0)) < 0) { + perror(s); + return(1); + } + read(fd, &len, sizeof(len)); + (void) brk(len); + read(fd, (char *)0, len); + close(fd); + return(0); +} diff --git a/src/cmd/awk/lib.c b/src/cmd/awk/lib.c new file mode 100644 index 0000000..c630011 --- /dev/null +++ b/src/cmd/awk/lib.c @@ -0,0 +1,295 @@ +#include +#include +#include +#include +#include "awk.def.h" +#include "awk.h" + +FILE *infile = NULL; +char *file; +#define RECSIZE (5 * 512) +char record[RECSIZE]; +char fields[RECSIZE]; +char EMPTY[] = ""; + +#define MAXFLD 100 +int donefld; /* 1 = implies rec broken into fields */ +int donerec; /* 1 = record is valid (no flds have changed) */ +int mustfld; /* 1 = NF seen, so always break*/ + +#define FINIT {EMPTY, EMPTY, 0.0, FLD|STR} +cell fldtab[MAXFLD] = { /*room for fields */ + { "$record", record, 0.0, STR|FLD}, + FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, + FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, + FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, + FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, + FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, + FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, + FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT +}; +int maxfld = 0; /* last used field */ + +void +error(int f, char *s, ...) +{ + va_list ap; + + va_start(ap, s); + fprintf(stderr, "awk: "); + vfprintf(stderr, s, ap); + fprintf(stderr, "\n"); + va_end(ap); + if (NR && *NR > 0) + fprintf(stderr, " record number %g\n", *NR); + if (f) + exit(2); +} + +getrec() +{ + register char *rr; + extern int svargc; + extern char **svargv; + register c, sep; + + dprintf("**RS=%o, **FS=%o\n", **RS, **FS, NULL); + donefld = 0; + donerec = 1; + record[0] = 0; + while (svargc > 0) { + dprintf("svargc=%d, *svargv=%s\n", svargc, *svargv, NULL); + if (infile == NULL) { /* have to open a new file */ + if (member('=', *svargv)) { /* it's a var=value argument */ + setclvar(*svargv); + svargv++; + svargc--; + continue; + } + *FILENAME = file = *svargv; + dprintf("opening file %s\n", file, NULL, NULL); + if (*file == '-') + infile = stdin; + else if ((infile = fopen(file, "r")) == NULL) + error(FATAL, "can't open %s", file); + } + if ((sep = **RS) == 0) + sep = '\n'; + for (rr = record; ; ) { + for (; (c=getc(infile)) != sep && c != EOF; *rr++ = c) + ; + if (**RS == sep || c == EOF) + break; + if ((c = getc(infile)) == '\n' || c == EOF) /* 2 in a row */ + break; + *rr++ = '\n'; + *rr++ = c; + } + if (rr > record+RECSIZE) + error(FATAL, "record `%.20s...' too long", record); + *rr = 0; + if (mustfld) + fldbld(); + if (c != EOF || rr > record) { /* normal record */ + recloc->tval &= ~NUM; + recloc->tval |= STR; + ++nrloc->fval; + nrloc->tval &= ~STR; + nrloc->tval |= NUM; + return(1); + } + /* EOF arrived on this file; set up next */ + if (infile != stdin) + fclose(infile); + infile = NULL; + svargc--; + svargv++; + } + return(0); /* true end of file */ +} + +setclvar(s) /* set var=value from s */ +char *s; +{ + char *p; + cell *q; + + for (p=s; *p != '='; p++) + ; + *p++ = 0; + q = setsymtab(s, tostring(p), 0.0, STR, symtab); + setsval(q, p); + dprintf("command line set %s to |%s|\n", s, p, NULL); +} + +fldbld() +{ + register char *r, *fr, sep; + int i, j; + + r = record; + fr = fields; + i = 0; /* number of fields accumulated here */ + if ((sep = **FS) == ' ') + for (i = 0; ; ) { + while (*r == ' ' || *r == '\t' || *r == '\n') + r++; + if (*r == 0) + break; + i++; + if (i >= MAXFLD) + error(FATAL, "record `%.20s...' has too many fields", record); + if (!(fldtab[i].tval&FLD)) + strfree(fldtab[i].sval); + fldtab[i].sval = fr; + fldtab[i].tval = FLD | STR; + do + *fr++ = *r++; + while (*r != ' ' && *r != '\t' && *r != '\n' && *r != '\0'); + *fr++ = 0; + } + else if (*r != 0) /* if 0, it's a null field */ + for (;;) { + i++; + if (i >= MAXFLD) + error(FATAL, "record `%.20s...' has too many fields", record); + if (!(fldtab[i].tval&FLD)) + strfree(fldtab[i].sval); + fldtab[i].sval = fr; + fldtab[i].tval = FLD | STR; + while (*r != sep && *r != '\n' && *r != '\0') /* \n always a separator */ + *fr++ = *r++; + *fr++ = 0; + if (*r++ == 0) + break; + } + *fr = 0; + for (j=MAXFLD-1; j>i; j--) { /* clean out junk from previous record */ + if (!(fldtab[j].tval&FLD)) + strfree(fldtab[j].sval); + fldtab[j].tval = STR | FLD; + fldtab[j].sval = EMPTY; + } + maxfld = i; + donefld = 1; + for(i=1; i<=maxfld; i++) + if(isnumber(fldtab[i].sval)) { + fldtab[i].fval = atof(fldtab[i].sval); + fldtab[i].tval |= NUM; + } + setfval(lookup("NF", symtab, 0), (awkfloat) maxfld); + if (dbg) + for (i = 0; i <= maxfld; i++) + printf("field %d: |%s|\n", i, fldtab[i].sval); +} + +recbld() +{ + int i; + register char *r, *p; + + if (donefld == 0 || donerec == 1) + return; + r = record; + for (i = 1; i <= *NF; i++) { + p = getsval(&fldtab[i]); + while (*r++ = *p++) + ; + *(r-1) = **OFS; + } + *(r-1) = '\0'; + dprintf("in recbld FS=%o, recloc=%o\n", **FS, recloc, NULL); + recloc->tval = STR | FLD; + dprintf("in recbld FS=%o, recloc=%o\n", **FS, recloc, NULL); + if (r > record+RECSIZE) + error(FATAL, "built giant record `%.20s...'", record); + dprintf("recbld = |%s|\n", record, NULL, NULL); +} + +cell *fieldadr(n) +{ + if (n >= MAXFLD) + error(FATAL, "trying to access field %d", n); + return(&fldtab[n]); +} + +int errorflag = 0; + +yyerror(s) + char *s; +{ + fprintf(stderr, "awk: %s near line %d\n", s, lineno); + errorflag = 2; +} + +PUTS(s) + char *s; +{ + dprintf("%s\n", s, NULL, NULL); +} + +#define MAXEXPON 38 /* maximum exponenet for fp number */ + +isnumber(s) +register char *s; +{ + register d1, d2; + int point; + char *es; + + if (s == NULL) + return (0); + d1 = d2 = point = 0; + while (*s == ' ' || *s == '\t' || *s == '\n') + s++; + if (*s == '\0') + return(0); /* empty stuff isn't number */ + if (*s == '+' || *s == '-') + s++; + if (!isdigit(*s) && *s != '.') + return(0); + if (isdigit(*s)) { + do { + d1++; + s++; + } while (isdigit(*s)); + } + if(d1 >= MAXEXPON) + return(0); /* too many digits to convert */ + if (*s == '.') { + point++; + s++; + } + if (isdigit(*s)) { + d2++; + do { + s++; + } while (isdigit(*s)); + } + if (!(d1 || point && d2)) + return(0); + if (*s == 'e' || *s == 'E') { + s++; + if (*s == '+' || *s == '-') + s++; + if (!isdigit(*s)) + return(0); + es = s; + do { + s++; + } while (isdigit(*s)); + if (s - es > 2) + return(0); + else if (s - es == 2 && 10 * (*es-'0') + *(es+1)-'0' >= MAXEXPON) + return(0); + } + while (*s == ' ' || *s == '\t' || *s == '\n') + s++; + if (*s == '\0') + return(1); + else + return(0); +} +/* +isnumber(s) char *s; {return(0);} +*/ diff --git a/src/cmd/awk/main.c b/src/cmd/awk/main.c new file mode 100644 index 0000000..066bcf4 --- /dev/null +++ b/src/cmd/awk/main.c @@ -0,0 +1,98 @@ +#include +#include +#include +#include "awk.def.h" +#include "awk.h" + +#define TOLOWER(c) (isupper(c) ? tolower(c) : c) /* ugh!!! */ + +int dbg = 0; +int svflg = 0; +int rstflg = 0; +int svargc; +char **svargv, **xargv; +extern FILE *yyin; /* lex input file */ +char *lexprog; /* points to program argument if it exists */ +extern errorflag; /* non-zero if any syntax errors; set by yyerror */ + +int filefd, symnum, ansfd; +char *filelist; +extern int maxsym, errno; + +main(argc, argv) + int argc; + char *argv[]; +{ + if (argc == 1) + error(FATAL, "Usage: awk [-f source | 'cmds'] [files]"); + syminit(); + while (argc > 1) { + argc--; + argv++; + /* this nonsense is because gcos argument handling */ + /* folds -F into -f. accordingly, one checks the next + /* character after f to see if it's -f file or -Fx. + */ + if (argv[0][0] == '-' && TOLOWER(argv[0][1]) == 'f' && argv[0][2] == '\0') { + yyin = fopen(argv[1], "r"); + if (yyin == NULL) + error(FATAL, "can't open %s", argv[1]); + argc--; + argv++; + break; + } else if (argv[0][0] == '-' && TOLOWER(argv[0][1]) == 'f') { /* set field sep */ + if (argv[0][2] == 't') /* special case for tab */ + **FS = '\t'; + else + **FS = argv[0][2]; + continue; + } else if (argv[0][0] != '-') { + dprintf("cmds=|%s|\n", argv[0], NULL, NULL); + yyin = NULL; + lexprog = argv[0]; + argv[0] = argv[-1]; /* need this space */ + break; + } else if (strcmp("-d", argv[0])==0) { + dbg = 1; + } + else if(strcmp("-S", argv[0]) == 0) { + svflg = 1; + } + else if(strncmp("-R", argv[0], 2) == 0) { + if(thaw(argv[0] + 2) == 0) + rstflg = 1; + else { + fprintf(stderr, "not restored\n"); + exit(1); + } + } + } + if (argc <= 1) { + argv[0][0] = '-'; + argv[0][1] = '\0'; + argc++; + argv--; + } + svargc = --argc; + svargv = ++argv; + dprintf("svargc=%d svargv[0]=%s\n", svargc, svargv[0], NULL); + *FILENAME = *svargv; /* initial file name */ + if(rstflg == 0) + yyparse(); + dprintf("errorflag=%d\n", errorflag, NULL, NULL); + if (errorflag) + exit(errorflag); + if(svflg) { + svflg = 0; + if(freeze("awk.out") != 0) + fprintf(stderr, "not saved\n"); + exit(0); + } + run(); + exit(errorflag); +} + +yywrap() +{ + return(1); +} diff --git a/src/cmd/awk/parse.c b/src/cmd/awk/parse.c new file mode 100644 index 0000000..9136486 --- /dev/null +++ b/src/cmd/awk/parse.c @@ -0,0 +1,148 @@ +#include +#include +#include "awk.def.h" +#include "awk.h" + +node *ALLOC(n) +{ + register node *x; + x = (node *) malloc(sizeof(node) + (n-1)*sizeof(node *)); + if (x == NULL) + error(FATAL, "out of space in ALLOC"); + return(x); +} +node *exptostat(a) node *a; +{ + a->ntype = NSTAT; + return(a); +} +node *nullstat; +node *node0(a) +{ + register node *x; + x=ALLOC(0); + x->nnext = NULL; + x->nobj=a; + return(x); +} +node *node1(a,b) node *b; +{ + register node *x; + x=ALLOC(1); + x->nnext = NULL; + x->nobj=a; + x->narg[0]=b; + return(x); +} +node *node2(a,b,c) node *b, *c; +{ + register node *x; + x = ALLOC(2); + x->nnext = NULL; + x->nobj = a; + x->narg[0] = b; + x->narg[1] = c; + return(x); +} +node *node3(a,b,c,d) node *b, *c, *d; +{ + register node *x; + x = ALLOC(3); + x->nnext = NULL; + x->nobj = a; + x->narg[0] = b; + x->narg[1] = c; + x->narg[2] = d; + return(x); +} +node *node4(a,b,c,d,e) node *b, *c, *d, *e; +{ + register node *x; + x = ALLOC(4); + x->nnext = NULL; + x->nobj = a; + x->narg[0] = b; + x->narg[1] = c; + x->narg[2] = d; + x->narg[3] = e; + return(x); +} +node *stat3(a,b,c,d) node *b, *c, *d; +{ + register node *x; + x = node3(a,b,c,d); + x->ntype = NSTAT; + return(x); +} +node *op2(a,b,c) node *b, *c; +{ + register node *x; + x = node2(a,b,c); + x->ntype = NEXPR; + return(x); +} +node *op1(a,b) node *b; +{ + register node *x; + x = node1(a,b); + x->ntype = NEXPR; + return(x); +} +node *stat1(a,b) node *b; +{ + register node *x; + x = node1(a,b); + x->ntype = NSTAT; + return(x); +} +node *op3(a,b,c,d) node *b, *c, *d; +{ + register node *x; + x = node3(a,b,c,d); + x->ntype = NEXPR; + return(x); +} +node *stat2(a,b,c) node *b, *c; +{ + register node *x; + x = node2(a,b,c); + x->ntype = NSTAT; + return(x); +} +node *stat4(a,b,c,d,e) node *b, *c, *d, *e; +{ + register node *x; + x = node4(a,b,c,d,e); + x->ntype = NSTAT; + return(x); +} +node *valtonode(a, b) cell *a; +{ + register node *x; + x = node0(a); + x->ntype = NVALUE; + x->subtype = b; + return(x); +} +node *pa2stat(a,b,c) node *a, *b, *c; +{ + register node *x; + x = node3(paircnt++, a, b, c); + x->ntype = NPA2; + return(x); +} +node *linkum(a,b) node *a, *b; +{ + register node *c; + if(a == NULL) return(b); + else if(b == NULL) return(a); + for(c=a; c->nnext != NULL; c=c->nnext); + c->nnext = b; + return(a); +} +node *genprint() +{ + register node *x; + x = stat2(PRINT,valtonode(lookup("$record", symtab, 0), CFLD), nullstat); + return(x); +} diff --git a/src/cmd/awk/proc.c b/src/cmd/awk/proc.c new file mode 100644 index 0000000..fd63e5b --- /dev/null +++ b/src/cmd/awk/proc.c @@ -0,0 +1,99 @@ +#include +#include +#include +#include "awk.h" + +struct tok +{ char *tnm; + int yval; +} tok[] = { +#include "token.h" +}; + +struct xx +{ int token; + char *name; + char *pname; +} proc[] = { + { PROGRAM, "program", NULL}, + { BOR, "boolop", " || "}, + { AND, "boolop", " && "}, + { NOT, "boolop", " !"}, + { NE, "relop", " != "}, + { EQ, "relop", " == "}, + { LE, "relop", " <= "}, + { LT, "relop", " < "}, + { GE, "relop", " >= "}, + { GT, "relop", " > "}, + { ARRAY, "array", NULL}, + { INDIRECT, "indirect", "$("}, + { SUBSTR, "substr", "substr"}, + { INDEX, "sindex", "sindex"}, + { SPRINTF, "asprintf", "sprintf "}, + { ADD, "arith", " + "}, + { MINUS, "arith", " - "}, + { MULT, "arith", " * "}, + { DIVIDE, "arith", " / "}, + { MOD, "arith", " % "}, + { UMINUS, "arith", " -"}, + { PREINCR, "incrdecr", "++"}, + { POSTINCR, "incrdecr", "++"}, + { PREDECR, "incrdecr", "--"}, + { POSTDECR, "incrdecr", "--"}, + { CAT, "cat", " "}, + { PASTAT, "pastat", NULL}, + { PASTAT2, "dopa2", NULL}, + { MATCH, "matchop", " ~ "}, + { NOTMATCH, "matchop", " !~ "}, + { PRINTF, "aprintf", "printf"}, + { PRINT, "print", "print"}, + { SPLIT, "split", "split"}, + { ASSIGN, "assign", " = "}, + { ADDEQ, "assign", " += "}, + { SUBEQ, "assign", " -= "}, + { MULTEQ, "assign", " *= "}, + { DIVEQ, "assign", " /= "}, + { MODEQ, "assign", " %= "}, + { IF, "ifstat", "if("}, + { WHILE, "whilestat", "while("}, + { FOR, "forstat", "for("}, + { IN, "instat", "instat"}, + { NEXT, "jump", "next"}, + { EXIT, "jump", "exit"}, + { BREAK, "jump", "break"}, + { CONTINUE, "jump", "continue"}, + { FNCN, "fncn", "fncn"}, + { GETLINE, "getline", "getline"}, + { 0, ""}, +}; + +#define SIZE LASTTOKEN - FIRSTTOKEN + +char *table[SIZE]; +char *names[SIZE]; + +char *tokname(n) +{ + if (n<=256 || n >= LASTTOKEN) + n = 257; + return(tok[n-257].tnm); +} + +int +main() +{ struct xx *p; + int i; + printf("#include \"awk.def.h\"\n"); + printf("obj nullproc();\n"); + for(p=proc;p->token!=0;p++) + if(p==proc || strcmp(p->name, (p-1)->name)) + printf("extern obj %s();\n",p->name); + for(p=proc;p->token!=0;p++) + table[p->token-FIRSTTOKEN]=p->name; + printf("const objfunc proctab[%d] = {\n", SIZE); + for(i=0;i +#include +#include +#include +#include "awk.def.h" +#include "awk.h" + +#define RECSIZE BUFSIZ + +#define FILENUM 10 +#define PA2NUM 29 +#define MAXTMP 20 + +struct +{ + FILE *fp; + int type; + char *fname; +} files[FILENUM]; + +extern obj execute(), nodetoobj(), fieldel(), dopa2(), gettemp(); + +int pairstack[PA2NUM], paircnt; + +node *winner = (node *)NULL; + +cell tmps[MAXTMP]; + +static cell nullval = { EMPTY, EMPTY, 0.0, NUM, 0 }; + +obj true = { OBOOL, BTRUE, 0 }; +obj false = { OBOOL, BFALSE, 0 }; + +run() +{ + register int i; + + execute(winner); + + /* Wait for children to complete if output to a pipe. */ + for (i=0; innext) { + if (cantexec(a)) + return(nodetoobj(a)); + if (a->ntype==NPA2) + proc=dopa2; + else { + if (notlegal(a->nobj)) + error(FATAL, "illegal statement %o", a); + proc = proctab[a->nobj-FIRSTTOKEN]; + } + x = (*proc)(a->narg,a->nobj); + if (isfld(x)) fldbld(); + if (isexpr(a)) + return(x); + /* a statement, goto next statement */ + if (isjump(x)) + return(x); + if (a->nnext == (node *)NULL) + return(x); + tempfree(x); + } +} + +obj program(a, n) node **a; +{ + obj x; + + if (a[0] != NULL) { + x = execute(a[0]); + if (isexit(x)) + return(true); + if (isjump(x)) + error(FATAL, "unexpected break, continue or next"); + tempfree(x); + } + while (getrec()) { + x = execute(a[1]); + if (isexit(x)) break; + tempfree(x); + } + tempfree(x); + if (a[2] != NULL) { + x = execute(a[2]); + if (isbreak(x) || isnext(x) || iscont(x)) + error(FATAL, "unexpected break, continue or next"); + tempfree(x); + } + return(true); +} + +obj getline() +{ + obj x; + + x = gettemp(); + setfval(x.optr, (awkfloat) getrec()); + return(x); +} + +obj array(a,n) node **a; +{ + obj x, y; + extern obj arrayel(); + + x = execute(a[1]); + y = arrayel(a[0], x); + tempfree(x); + return(y); +} + +obj arrayel(a,b) node *a; obj b; +{ + char *s; + cell *x; + int i; + obj y; + + s = getsval(b.optr); + x = (cell *) a; + if (!(x->tval&ARR)) { + strfree(x->sval); + x->tval &= ~STR; + x->tval |= ARR; + x->sval = (char *) makesymtab(); + } + y.optr = setsymtab(s, tostring(""), 0.0, STR|NUM, x->sval); + y.otype = OCELL; + y.osub = CVAR; + return(y); +} + +obj matchop(a,n) node **a; +{ + obj x; + char *s; + int i; + + x = execute(a[0]); + if (isstr(x)) s = x.optr->sval; + else s = getsval(x.optr); + tempfree(x); + i = match(a[1], s); + if (n==MATCH && i==1 || n==NOTMATCH && i==0) + return(true); + else + return(false); +} + +obj boolop(a,n) node **a; +{ + obj x, y; + int i; + + x = execute(a[0]); + i = istrue(x); + tempfree(x); + switch (n) { + default: + error(FATAL, "unknown boolean operator %d", n); + case BOR: + if (i) return(true); + y = execute(a[1]); + i = istrue(y); + tempfree(y); + if (i) return(true); + else return(false); + case AND: + if ( !i ) return(false); + y = execute(a[1]); + i = istrue(y); + tempfree(y); + if (i) return(true); + else return(false); + case NOT: + if (i) return(false); + else return(true); + } +} + +obj relop(a,n) node **a; +{ + int i; + obj x, y; + awkfloat j; + + x = execute(a[0]); + y = execute(a[1]); + if (x.optr->tval&NUM && y.optr->tval&NUM) { + j = x.optr->fval - y.optr->fval; + i = j<0? -1: (j>0? 1: 0); + } else { + i = strcmp(getsval(x.optr), getsval(y.optr)); + } + tempfree(x); + tempfree(y); + switch (n) { + default: + error(FATAL, "unknown relational operator %d", n); + case LT: if (i<0) return(true); + else return(false); + case LE: if (i<=0) return(true); + else return(false); + case NE: if (i!=0) return(true); + else return(false); + case EQ: if (i==0) return(true); + else return(false); + case GE: if (i>=0) return(true); + else return(false); + case GT: if (i>0) return(true); + else return(false); + } +} + +tempfree(a) obj a; +{ + if (!istemp(a)) return; + strfree(a.optr->sval); + a.optr->tval = 0; +} + +obj gettemp() +{ + int i; + obj x; + + for (i=0; i k) + m = k; + tempfree(x); + if (a[2] != nullstat) { + x = execute(a[2]); + n = getfval(x.optr); + tempfree(x); + } + else + n = k - 1; + if (n < 0) + n = 0; + else if (n > k - m) + n = k - m; + dprintf("substr: m=%d, n=%d, s=%s\n", m, n, s); + x = gettemp(); + temp = s[n+m-1]; /* with thanks to John Linderman */ + s[n+m-1] = '\0'; + setsval(x.optr, s + m - 1); + s[n+m-1] = temp; + return(x); +} + +obj sindex(a, nnn) node **a; +{ + obj x; + char *s1, *s2, *p1, *p2, *q; + + x = execute(a[0]); + s1 = getsval(x.optr); + tempfree(x); + x = execute(a[1]); + s2 = getsval(x.optr); + tempfree(x); + + x = gettemp(); + for (p1 = s1; *p1 != '\0'; p1++) { + for (q=p1, p2=s2; *p2 != '\0' && *q == *p2; q++, p2++) + ; + if (*p2 == '\0') { + setfval(x.optr, (awkfloat) (p1 - s1 + 1)); /* origin 1 */ + return(x); + } + } + setfval(x.optr, 0.0); + return(x); +} + +char *format(s,a) char *s; node *a; +{ + char *buf, *p, fmt[200], *t, *os; + obj x; + int flag = 0; + awkfloat xf; + + os = s; + p = buf = (char *)malloc(RECSIZE); + while (*s) { + if (*s != '%') { + *p++ = *s++; + continue; + } + if (*(s+1) == '%') { + *p++ = '%'; + s += 2; + continue; + } + for (t=fmt; (*t++ = *s) != '\0'; s++) + if (*s >= 'a' && *s <= 'z' && *s != 'l') + break; + *t = '\0'; + if (t >= fmt + sizeof(fmt)) + error(FATAL, "format item %.20s... too long", os); + switch (*s) { + case 'f': case 'e': case 'g': + flag = 1; + break; + case 'd': + flag = 2; + if(*(s-1) == 'l') break; + *(t-1) = 'l'; + *t = 'd'; + *++t = '\0'; + break; + case 'o': case 'x': + flag = *(s-1)=='l' ? 2 : 3; + break; + case 'c': + flag = 3; + break; + case 's': + flag = 4; + break; + default: + flag = 0; + break; + } + if (flag == 0) { + sprintf(p, "%s", fmt); + p += strlen(p); + continue; + } + if (a == NULL) + error(FATAL, "not enough arguments in printf(%s)", os); + x = execute(a); + a = a->nnext; + if (flag != 4) /* watch out for converting to numbers! */ + xf = getfval(x.optr); + if (flag==1) sprintf(p, fmt, xf); + else if (flag==2) sprintf(p, fmt, (long)xf); + else if (flag==3) sprintf(p, fmt, (int)xf); + else if (flag==4) sprintf(p, fmt, x.optr->sval==NULL ? "" : getsval(x.optr)); + tempfree(x); + p += strlen(p); + s++; + } + *p = '\0'; + return(buf); +} + +obj asprintf(a,n) node **a; +{ + obj x; + node *y; + char *s; + + y = a[0]->nnext; + x = execute(a[0]); + s = format(getsval(x.optr), y); + tempfree(x); + x = gettemp(); + x.optr->sval = s; + x.optr->tval = STR; + return(x); +} + +obj arith(a,n) node **a; +{ + awkfloat i,j; + obj x,y,z; + + x = execute(a[0]); + i = getfval(x.optr); + tempfree(x); + if (n != UMINUS) { + y = execute(a[1]); + j = getfval(y.optr); + tempfree(y); + } + z = gettemp(); + switch (n) { + default: + error(FATAL, "illegal arithmetic operator %d", n); + case ADD: + i += j; + break; + case MINUS: + i -= j; + break; + case MULT: + i *= j; + break; + case DIVIDE: + if (j == 0) + error(FATAL, "division by zero"); + i /= j; + break; + case MOD: + if (j == 0) + error(FATAL, "division by zero"); + i = i - j*(long)(i/j); + break; + case UMINUS: + i = -i; + break; + } + setfval(z.optr, i); + return(z); +} + +obj incrdecr(a, n) node **a; +{ + obj x, z; + int k; + awkfloat xf; + + x = execute(a[0]); + xf = getfval(x.optr); + k = (n == PREINCR || n == POSTINCR) ? 1 : -1; + if (n == PREINCR || n == PREDECR) { + setfval(x.optr, xf + k); + return(x); + } + z = gettemp(); + setfval(z.optr, xf); + setfval(x.optr, xf + k); + tempfree(x); + return(z); +} + + +obj assign(a,n) node **a; +{ + obj x, y; + awkfloat xf, yf; + + x = execute(a[0]); + y = execute(a[1]); + if (n == ASSIGN) { /* ordinary assignment */ + if ((y.optr->tval & (STR|NUM)) == (STR|NUM)) { + setsval(x.optr, y.optr->sval); + x.optr->fval = y.optr->fval; + x.optr->tval |= NUM; + } + else if (y.optr->tval & STR) + setsval(x.optr, y.optr->sval); + else if (y.optr->tval & NUM) + setfval(x.optr, y.optr->fval); + tempfree(y); + return(x); + } + xf = getfval(x.optr); + yf = getfval(y.optr); + switch (n) { + case ADDEQ: + xf += yf; + break; + case SUBEQ: + xf -= yf; + break; + case MULTEQ: + xf *= yf; + break; + case DIVEQ: + if (yf == 0) + error(FATAL, "division by zero"); + xf /= yf; + break; + case MODEQ: + if (yf == 0) + error(FATAL, "division by zero"); + xf = xf - yf*(long)(xf/yf); + break; + default: + error(FATAL, "illegal assignment operator %d", n); + break; + } + tempfree(y); + setfval(x.optr, xf); + return(x); +} + +obj cat(a,q) node **a; +{ + obj x,y,z; + int n1, n2; + char *s; + + x = execute(a[0]); + y = execute(a[1]); + getsval(x.optr); + getsval(y.optr); + n1 = strlen(x.optr->sval); + n2 = strlen(y.optr->sval); + s = (char *) malloc(n1 + n2 + 1); + strcpy(s, x.optr->sval); + strcpy(s+n1, y.optr->sval); + tempfree(y); + z = gettemp(); + z.optr->sval = s; + z.optr->tval = STR; + tempfree(x); + return(z); +} + +obj pastat(a,n) node **a; +{ + obj x; + + if (a[0]==nullstat) + x = true; + else + x = execute(a[0]); + if (istrue(x)) { + tempfree(x); + x = execute(a[1]); + } + return(x); +} + +obj dopa2(a,n) node **a; +{ + obj x; + + if (pairstack[n]==0) { + x = execute(a[0]); + if (istrue(x)) + pairstack[n] = 1; + tempfree(x); + } + if (pairstack[n] == 1) { + x = execute(a[1]); + if (istrue(x)) + pairstack[n] = 0; + tempfree(x); + x = execute(a[2]); + return(x); + } + return(false); +} + +obj aprintf(a,n) node **a; +{ + obj x; + + x = asprintf(a,n); + if (a[1]==NULL) { + printf("%s", x.optr->sval); + tempfree(x); + return(true); + } + redirprint(x.optr->sval, (int)a[1], a[2]); + return(x); +} + +obj split(a,nnn) node **a; +{ + obj x; + cell *ap; + register char *s, *p; + char *t, temp, num[5]; + register int sep; + int n, flag; + + x = execute(a[0]); + s = getsval(x.optr); + tempfree(x); + if (a[2] == nullstat) + sep = **FS; + else { + x = execute(a[2]); + sep = getsval(x.optr)[0]; + tempfree(x); + } + ap = (cell *) a[1]; + freesymtab(ap); + dprintf("split: s=|%s|, a=%s, sep=|%c|\n", s, ap->nval, sep); + ap->tval &= ~STR; + ap->tval |= ARR; + ap->sval = (char *) makesymtab(); + + n = 0; + if (sep == ' ') + for (n = 0; ; ) { + while (*s == ' ' || *s == '\t' || *s == '\n') + s++; + if (*s == 0) + break; + n++; + t = s; + do + s++; + while (*s!=' ' && *s!='\t' && *s!='\n' && *s!='\0'); + temp = *s; + *s = '\0'; + sprintf(num, "%d", n); + if (isnumber(t)) + setsymtab(num, tostring(t), atof(t), STR|NUM, ap->sval); + else + setsymtab(num, tostring(t), 0.0, STR, ap->sval); + *s = temp; + if (*s != 0) + s++; + } + else if (*s != 0) + for (;;) { + n++; + t = s; + while (*s != sep && *s != '\n' && *s != '\0') + s++; + temp = *s; + *s = '\0'; + sprintf(num, "%d", n); + if (isnumber(t)) + setsymtab(num, tostring(t), atof(t), STR|NUM, ap->sval); + else + setsymtab(num, tostring(t), 0.0, STR, ap->sval); + *s = temp; + if (*s++ == 0) + break; + } + x = gettemp(); + x.optr->tval = NUM; + x.optr->fval = n; + return(x); +} + +obj ifstat(a,n) node **a; +{ + obj x; + + x = execute(a[0]); + if (istrue(x)) { + tempfree(x); + x = execute(a[1]); + } + else if (a[2] != nullstat) { + tempfree(x); + x = execute(a[2]); + } + return(x); +} + +obj whilestat(a,n) node **a; +{ + obj x; + + for (;;) { + x = execute(a[0]); + if (!istrue(x)) return(x); + tempfree(x); + x = execute(a[1]); + if (isbreak(x)) { + x = true; + return(x); + } + if (isnext(x) || isexit(x)) + return(x); + tempfree(x); + } +} + +obj forstat(a,n) node **a; +{ + obj x; + + tempfree(execute(a[0])); + for (;;) { + if (a[1]!=nullstat) { + x = execute(a[1]); + if (!istrue(x)) return(x); + else tempfree(x); + } + x = execute(a[3]); + if (isbreak(x)) { /* turn off break */ + x = true; + return(x); + } + if (isnext(x) || isexit(x)) + return(x); + tempfree(x); + tempfree(execute(a[2])); + } +} + +obj instat(a, n) node **a; +{ + cell *vp, *arrayp, *cp, **tp; + obj x; + int i; + + vp = (cell *) a[0]; + arrayp = (cell *) a[1]; + if (!(arrayp->tval & ARR)) + error(FATAL, "%s is not an array", arrayp->nval); + tp = (cell **) arrayp->sval; + for (i = 0; i < MAXSYM; i++) { /* this routine knows too much */ + for (cp = tp[i]; cp != NULL; cp = cp->nextval) { + setsval(vp, cp->nval); + x = execute(a[2]); + if (isbreak(x)) { + x = true; + return(x); + } + if (isnext(x) || isexit(x)) + return(x); + tempfree(x); + } + } + return (true); +} + +obj jump(a,n) node **a; +{ + obj x, y; + + x.otype = OJUMP; + switch (n) { + default: + error(FATAL, "illegal jump type %d", n); + break; + case EXIT: + if (a[0] != 0) { + y = execute(a[0]); + errorflag = getfval(y.optr); + } + x.osub = JEXIT; + break; + case NEXT: + x.osub = JNEXT; + break; + case BREAK: + x.osub = JBREAK; + break; + case CONTINUE: + x.osub = JCONT; + break; + } + return(x); +} + +obj fncn(a,n) node **a; +{ + obj x; + awkfloat u; + int t; + + t = (int) a[0]; + x = execute(a[1]); + if (t == FLENGTH) + u = (awkfloat) strlen(getsval(x.optr)); + else if (t == FLOG) + u = log(getfval(x.optr)); + else if (t == FINT) + u = (awkfloat) (long) getfval(x.optr); + else if (t == FEXP) + u = exp(getfval(x.optr)); + else if (t == FSQRT) + u = sqrt(getfval(x.optr)); + else + error(FATAL, "illegal function type %d", t); + tempfree(x); + x = gettemp(); + setfval(x.optr, u); + return(x); +} + +obj print(a,n) node **a; +{ + register node *x; + obj y; + char s[RECSIZE]; + + s[0] = '\0'; + for (x=a[0]; x!=NULL; x=x->nnext) { + y = execute(x); + strcat(s, getsval(y.optr)); + tempfree(y); + if (x->nnext==NULL) + strcat(s, *ORS); + else + strcat(s, *OFS); + } + if (strlen(s) >= RECSIZE) + error(FATAL, "string %.20s ... too long to print", s); + if (a[1]==nullstat) { + printf("%s", s); + return(true); + } + redirprint(s, (int)a[1], a[2]); + return(false); +} + +obj nullproc() {} + +obj nodetoobj(a) node *a; +{ + obj x; + + x.optr = (cell *) a->nobj; + x.otype = OCELL; + x.osub = a->subtype; + if (isfld(x)) fldbld(); + return(x); +} + +redirprint(s, a, b) char *s; node *b; +{ + register int i; + obj x; + + x = execute(b); + getsval(x.optr); + for (i=0; isval, files[i].fname) == 0) + goto doit; + for (i=0; i= FILENUM) + error(FATAL, "too many output files %d", i); + if (a == '|') /* a pipe! */ + files[i].fp = popen(x.optr->sval, "w"); + else if (a == APPEND) + files[i].fp = fopen(x.optr->sval, "a"); + else + files[i].fp = fopen(x.optr->sval, "w"); + if (files[i].fp == NULL) + error(FATAL, "can't open file %s", x.optr->sval); + files[i].fname = tostring(x.optr->sval); + files[i].type = a; +doit: + fprintf(files[i].fp, "%s", s); +#ifndef gcos + fflush(files[i].fp); /* in case someone is waiting for the output */ +#endif + tempfree(x); +} diff --git a/src/cmd/awk/tokenscript b/src/cmd/awk/tokenscript new file mode 100644 index 0000000..4646c8f --- /dev/null +++ b/src/cmd/awk/tokenscript @@ -0,0 +1,8 @@ +e y.tab.h +1,$g!/#define /d +1,$s/# *define *// +1,$s/^/{"/ +1,$s/ /", / +1,$s/$/},/ +w! token.h +q diff --git a/src/cmd/awk/tran.c b/src/cmd/awk/tran.c new file mode 100644 index 0000000..68da665 --- /dev/null +++ b/src/cmd/awk/tran.c @@ -0,0 +1,252 @@ +#include +#include +#include +#include "awk.def.h" +#include "awk.h" + +cell *symtab[MAXSYM]; /* symbol table pointers */ + +char **FS; /* initial field sep */ +char **RS; /* initial record sep */ +char **OFS; /* output field sep */ +char **ORS; /* output record sep */ +char **OFMT; /*output format for numbers*/ +awkfloat *NF; /* number of fields in current record */ +awkfloat *NR; /* number of current record */ +char **FILENAME; /* current filename argument */ + +cell *recloc; /* location of record */ +cell *nrloc; /* NR */ +cell *nfloc; /* NF */ + +syminit() +{ + setsymtab("0", tostring("0"), 0.0, NUM|STR|CON|FLD, symtab); + /* this one is used for if(x)... tests: */ + setsymtab("$zero&null", tostring(""), 0.0, NUM|STR|CON|FLD, symtab); + recloc = setsymtab("$record", record, 0.0, STR|FLD, symtab); + dprintf("recloc %o lookup %o\n", recloc, lookup("$record", symtab, 0), NULL); + FS = &setsymtab("FS", tostring(" "), 0.0, STR|FLD, symtab)->sval; + RS = &setsymtab("RS", tostring("\n"), 0.0, STR|FLD, symtab)->sval; + OFS = &setsymtab("OFS", tostring(" "), 0.0, STR|FLD, symtab)->sval; + ORS = &setsymtab("ORS", tostring("\n"), 0.0, STR|FLD, symtab)->sval; + OFMT = &setsymtab("OFMT", tostring("%.6g"), 0.0, STR|FLD, symtab)->sval; + FILENAME = &setsymtab("FILENAME", EMPTY, 0.0, STR|FLD, symtab)->sval; + nfloc = setsymtab("NF", EMPTY, 0.0, NUM, symtab); + NF = &nfloc->fval; + nrloc = setsymtab("NR", EMPTY, 0.0, NUM, symtab); + NR = &nrloc->fval; +} + +cell **makesymtab() +{ + int i; + cell **cp; + + cp = (cell **) malloc(MAXSYM * sizeof(cell *)); + if (cp == NULL) + error(FATAL, "out of space in makesymtab"); + for (i = 0; i < MAXSYM; i++) + cp[i] = 0; + return(cp); +} + +freesymtab(ap) /* free symbol table */ +cell *ap; +{ + cell *cp, **tp; + int i; + + if (!(ap->tval & ARR)) + return; + tp = (cell **) ap->sval; + for (i = 0; i < MAXSYM; i++) { + for (cp = tp[i]; cp != NULL; cp = cp->nextval) { + strfree(cp->nval); + strfree(cp->sval); + free(cp); + } + } + xfree(tp); +} + +cell *setsymtab(n, s, f, t, tab) +char *n, *s; +awkfloat f; +unsigned t; +cell **tab; +{ + register h; + register cell *p; + cell *lookup(); + + if (n != NULL && (p = lookup(n, tab, 0)) != NULL) { + if (s != EMPTY ) xfree(s); /* careful here */ + dprintf("setsymtab found %o: %s", p, p->nval, NULL); + dprintf(" %s %g %o\n", p->sval, p->fval, p->tval); + return(p); + } + p = (cell *) malloc(sizeof(cell)); + if (p == NULL) + error(FATAL, "symbol table overflow at %s", n); + p->nval = tostring(n); + p->sval = s; + p->fval = f; + p->tval = t; + h = hash(n); + p->nextval = tab[h]; + tab[h] = p; + dprintf("setsymtab set %o: %s", p, p->nval, NULL); + dprintf(" %s %g %o\n", p->sval, p->fval, p->tval); + return(p); +} + +hash(s) /* form hash value for string s */ +register unsigned char *s; +{ + register int hashval; + + for (hashval = 0; *s != '\0'; ) + hashval += *s++; + return(hashval % MAXSYM); +} + +cell *lookup(s, tab, flag) /* look for s in tab, flag must match*/ +register char *s; +cell **tab; +{ + register cell *p; + + for (p = tab[hash(s)]; p != NULL; p = p->nextval) + if (strcmp(s, p->nval) == 0 && + (flag == 0 || flag == p->tval)) + return(p); /* found it */ + return(NULL); /* not found */ +} + +awkfloat setfval(vp, f) +register cell *vp; +awkfloat f; +{ + dprintf("setfval: %o %g\n", vp, f, NULL); + checkval(vp); + if (vp == recloc) + error(FATAL, "can't set $0"); + vp->tval &= ~STR; /* mark string invalid */ + vp->tval |= NUM; /* mark number ok */ + if ((vp->tval & FLD) && isnull(vp->nval)) + donerec = 0; + return(vp->fval = f); +} + +char *setsval(vp, s) +register cell *vp; +char *s; +{ + dprintf("setsval: %o %s\n", vp, s, NULL); + checkval(vp); + if (vp == recloc) + error(FATAL, "can't set $0"); + vp->tval &= ~NUM; + vp->tval |= STR; + if ((vp->tval & FLD) && isnull(vp->nval)) + donerec = 0; + if (!(vp->tval&FLD)) + strfree(vp->sval); + vp->tval &= ~FLD; + return(vp->sval = tostring(s)); +} + +awkfloat getfval(vp) +register cell *vp; +{ + + if (vp->sval == record && donerec == 0) + recbld(); + dprintf("getfval: %o", vp, NULL, NULL); + checkval(vp); + if ((vp->tval & NUM) == 0) { + /* the problem is to make non-numeric things */ + /* have unlikely numeric variables, so that */ + /* $1 == $2 comparisons sort of make sense when */ + /* one or the other is numeric */ + if (isnumber(vp->sval)) { + vp->fval = atof(vp->sval); + if (!(vp->tval & CON)) /* don't change type of a constant */ + vp->tval |= NUM; + } + else + vp->fval = 0.0; /* not a very good idea */ + } + dprintf(" %g\n", vp->fval, NULL, NULL); + return(vp->fval); +} + +char *getsval(vp) +register cell *vp; +{ + char s[100]; + + if (vp->sval == record && donerec == 0) + recbld(); + dprintf("getsval: %o", vp, NULL, NULL); + checkval(vp); + if ((vp->tval & STR) == 0) { + if (!(vp->tval&FLD)) + strfree(vp->sval); + if ((long)vp->fval==vp->fval) + sprintf(s, "%.20g", vp->fval); + else + sprintf(s, *OFMT, vp->fval); + vp->sval = tostring(s); + vp->tval &= ~FLD; + vp->tval |= STR; + } + dprintf(" %s\n", vp->sval, NULL, NULL); + return(vp->sval); +} + +checkval(vp) +register cell *vp; +{ + if (vp->tval & ARR) + error(FATAL, "illegal reference to array %s", vp->nval); + if ((vp->tval & (NUM | STR)) == 0) + error(FATAL, "funny variable %o: %s %s %g %o", vp, vp->nval, + vp->sval, vp->fval, vp->tval); +} + +char *tostring(s) +register char *s; +{ + register char *p; + + if (s==NULL){ + p = malloc(1); + if (p == NULL) + error(FATAL, "out of space in tostring on %s", s); + *p = '\0'; + } else { + p = malloc(strlen(s)+1); + if (p == NULL) + error(FATAL, "out of space in tostring on %s", s); + strcpy(p, s); + } + return(p); +} +#ifndef yfree +yfree(a) char *a; +{ + printf("%o\n", a); + free(a); +} +#endif +#ifdef malloc +#undef malloc +char *ymalloc(u) unsigned u; +{ char *p; + p = malloc(u); + printf("%o %o\n", u, p); + return(p); +} +#endif diff --git a/src/cmd/basename.c b/src/cmd/basename.c new file mode 100644 index 0000000..79957a6 --- /dev/null +++ b/src/cmd/basename.c @@ -0,0 +1,30 @@ +#include +#include + +main(argc, argv) +char **argv; +{ + register char *p1, *p2, *p3; + + if (argc < 2) { + putchar('\n'); + exit(1); + } + p1 = argv[1]; + p2 = p1; + while (*p1) { + if (*p1++ == '/') + p2 = p1; + } + if (argc>2) { + for(p3=argv[2]; *p3; p3++) + ; + while(p1>p2 && p3>argv[2]) + if(*--p3 != *--p1) + goto output; + *p1 = '\0'; + } +output: + puts(p2); + exit(0); +} diff --git a/src/cmd/basic/Makefile b/src/cmd/basic/Makefile new file mode 100644 index 0000000..4c3fafa --- /dev/null +++ b/src/cmd/basic/Makefile @@ -0,0 +1,30 @@ +TOPSRC = $(shell cd ../../..; pwd) +include $(TOPSRC)/target.mk +#include $(TOPSRC)/cross.mk + +CFLAGS += -Wall -Werror + +OBJS = basic.o + +LIBS = -lcurses -ltermcap -lm -lc + +all: basic renumber + +basic: ${OBJS} + ${CC} ${LDFLAGS} -o basic.elf ${OBJS} ${LIBS} + ${OBJDUMP} -S basic.elf > basic.dis + ${SIZE} basic.elf + ${ELF2AOUT} basic.elf $@ && rm basic.elf + +renumber: renumber.o + ${CC} ${LDFLAGS} -o renumber.elf $< ${LIBS} + ${OBJDUMP} -S renumber.elf > renumber.dis + ${SIZE} renumber.elf + ${ELF2AOUT} renumber.elf $@ && rm renumber.elf + +clean: + rm -f *.o basic renumber *.elf *.dis *~ + +install: all + install basic $(DESTDIR)/bin/ + install renumber $(DESTDIR)/bin/ diff --git a/src/cmd/basic/basic.c b/src/cmd/basic/basic.c new file mode 100644 index 0000000..956ea43 --- /dev/null +++ b/src/cmd/basic/basic.c @@ -0,0 +1,1759 @@ +/* + * MICRO-BASIC: + * + * This is a small INTEGER BASIC interpreter that I wrote a number + * of years ago, and subsequently ported to MICRO-C. While not a great + * example of coding style (it was a quick and dirty hack job), It is + * quite instructive, as a simple but fairly complete interpreter. + * + * Variables: + * 260 Numeric variables : A0-A9 ... Z0-Z9 + * 260 Character variables : A0$-A9$ ... Z0$-Z9$ + * 260 Numeric arrays : A0()-A9() ... Z0()-Z9() + * + * For convenience the '0' variables can be referenced by letter + * only. IE: A is equivalent to A0 ... Z$ is equivalent to Z0$ + * + * Statements: + * BEEP freq,ms - Generate a BEEP on the PC speaker + * CLEAR - Erase variables only + * CLOSE#n - Close file (0-9) opened with OPEN + * DATA - Enter "inline" data statements + * DELAY ms - Stops for the indicated time + * DIM var(size)[, ... ] - Dimension an array + * DOS "command" - Execute a DOS program + * END - Terminate program with no message + * EXIT - Terminate MICRO-BASIC + * FOR v=init TO limit [STEP increment] - Perform a counted loop + * GOSUB line - Call a subroutine + * GOTO line - Jump to line + * IF test THEN line - Conditional goto + * IF test THEN statement - Conditional statement (next statement only) + * INPUT var - Get value for variable + * INPUT "prompt",var - Get value of variable with prompt + * prompt must be a constant string, however you can use a char variable + * in prompt by concatinating it to such a string: INPUT ""+a$,b$ + * INPUT#n,var - Get value for variable from file (0-9) + * LET (default) - variable = expression + * LIF test THEN statements- LONG IF (all statements to end of line) + * LIST [start,[end]] - List program lines + * LIST#n ... - List program to file (0-9) + * LOAD "name" - Load program from disk file + * When LOAD is used within a program, execution continues with the + * first line of the newly loaded program. In this case, the user + * variables are NOT cleared. This provides a means of chaining + * to a new program, and passing information to it. + * Also note that LOAD must be the LAST statement on a line. + * NEW - Erase program and variables + * NEXT [v] - End counted loop + * OPEN#n,"name","opts" - Open file (0-9), opts are same as "fopen()" + * ORDER line - Position data read pointer + * OUT port,expr - Write to I/O port + * PRINT expr[,expr ...] - Print to console + * PRINT#n,... - Print to file (0-9) + * READ var[,var ...] - Read data from program statements + * You MUST issue an "ORDER" statement targeting a line + * containing a valid DATA statement before using READ + * RETURN - Return from subroutine + * REM - Comment... reminder of line is ignored + * RUN [line] - Run program + * SAVE ["name"] - Save program to disk file + * STOP - Terminate program & issue message + * SRND seed - Seeds random() + * + * Operators: + * + - Addition, string concatination + * - - Unary minus, subtraction + * *, /, %, - multiplication, division, modulus + * &, |, ^ - AND, OR, Exclusive OR + * =, <> - Assign/test equal, test NOTequal (num or string) + * <, <=, >, >= - LT, LE, GT, GE (numbers only) + * ! - Unary NOT + * The "test" operators (=, <>, <, <=, >, >=) can be used in any + * expression, and evaluate to 1 of the test is TRUE, and 0 if it + * is FALSE. The IF and LIF commands accept any non-zero value to + * indicate a TRUE condition. + * + * Functions: + * CHR$(value) - Returns character of passed value + * STR$(value) - Returns ASCII string of value's digits + * ASC(char) - Returns value of passed character + * NUM(string) - Convert string to number + * ABS(value) - Returns absolute value of argument + * RND(value) - Returns random number from 0 to (value-1) + * KEY() - Test for key from keyboard + * INP(port) - Read an I/O port + * SIN(value*10^6) - 10^6*SIN(x) + * COS(value*10^6) - 10^6*COS(x) + * TAN(value*10^6) - 10^6*TAN(x) + * ASIN(value*10^6) - 10^6*SIN(x) + * ACOS(value*10^6) - 10^6*COS(x) + * ATAN(value*10^6) - 10^6*TAN(x) + * LOG(value*10^6) - 10^6*LOG(x) + * LOG10(value*10^6) - 10^6*LOG10(x) + * EXP(value*10^6) - 10^6*EXP(x) + * + * Copyright 1982-2000 Dave Dunfield + * All rights reserved. + * + * Permission granted for personal (non-commercial) use only. + * + * Compile command: cc basic -fop + */ +#ifdef CROSS +# include +# define ustore(addr, value) /*empty*/ +# define ufetch(addr) 0 +#else +# include +# include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Fixed parameters */ +#define BUFFER_SIZE 100 /* input buffer size */ +#define NUM_VAR 260 /* number of variables */ +#define SA_SIZE 200 /* string accumulator size */ + +/* Control stack constant identifiers */ +#define _FOR 1000 /* indicate FOR statement */ +#define _GOSUB _FOR+1 /* indicate GOSUB statement */ + +/* Primary keywords */ +#define LET 1 +#define EXIT 2 +#define LIST 3 +#define NEW 4 +#define RUN 5 +#define CLEAR 6 +#define GOSUB 7 +#define GOTO 8 +#define RETURN 9 +#define PRINT 10 +#define FOR 11 +#define NEXT 12 +#define IF 13 +#define LIF 14 +#define REM 15 +#define STOP 16 +#define END 17 +#define INPUT 18 +#define OPEN 19 +#define CLOSE 20 +#define DIM 21 +#define ORDER 22 +#define READ 23 +#define DATA 24 +#define SAVE 25 +#define LOAD 26 +#define DELAY 27 +#define BEEP 28 +#define DOS 29 +#define OUT 30 + +/* Secondary keywords */ +#define TO 31 /* Also used as marker */ +#define STEP 32 +#define THEN 33 + +/* Operators and functions */ +#define ADD 34 /* Also used as marker */ +#define SUB 35 +#define MUL 36 +#define DIV 37 +#define MOD 38 +#define AND 39 +#define OR 40 +#define XOR 41 +#define EQ 42 +#define NE 43 +#define LE 44 +#define LT 45 +#define GE 46 +#define GT 47 +#define CHR 48 +#define STR 49 +#define ASC 50 +#define ABS 51 +#define NUM 52 +#define RND 53 +#define KEY 54 +#define INP 55 +#define DATE 56 +#define SRND 57 +#define SIN 58 +#define COS 59 +#define TAN 60 +#define ASIN 61 +#define ACOS 62 +#define ATAN 63 +#define LOG 64 +#define LOG10 65 +#define EXP 66 + +#define RUN1 99 + +/* Make sure this token table matches the above definitions */ +static char *reserved_words[] = { + "LET", "EXIT", "LIST", "NEW", "RUN", "CLEAR", "GOSUB", "GOTO", + "RETURN", "PRINT", "FOR", "NEXT", "IF", "LIF", "REM", "STOP", + "END", "INPUT", "OPEN", "CLOSE", "DIM", "ORDER", "READ", "DATA", + "SAVE", "LOAD", "DELAY", "BEEP", "DOS", "OUT", + "TO", "STEP", "THEN", + "+", "-", "*", "/", "%", "&", "|", "^", + "=", "<>", "<=", "<", ">=", ">", + "CHR$(", "STR$(", "ASC(", "ABS(", "NUM(", "RND(", "KEY(", "INP(", + "DATE$(", "SRND", "SIN(", "COS(", "TAN(", "ASIN(", "ACOS(", "ATAN(", + "LOG(", "LOG10(", "EXP(", + 0 +}; + +/* Table of operator priorities */ +static char priority[] = { 0, 1, 1, 2, 2, 2, 3, 3, 3, 1, 1, 1, 1, 1, 1 }; + +/* Table of error messages */ +static char *error_messages[] = { + "Syntax", + "Illegal program", + "Illegal direct", + "Line number", + "Wrong type", + "Divide by zero", + "Nesting", + "File not open", + "File already open", + "Input", + "Dimension", + "Data", + "Out of memory" + }; + +struct line_record { + unsigned Lnumber; + struct line_record *Llink; + char Ltext[1]; +}; + +char sa1[SA_SIZE], sa2[SA_SIZE]; /* String accumulators */ +struct line_record *pgm_start, /* Indicates start of program */ + *runptr, /* Line we are RUNnning */ + *readptr; /* Line we are READing */ + +unsigned dim_check[NUM_VAR]; /* Check dim sizes for arrays */ + +FILE *filein, *fileout; /* File I/O active pointers */ + +jmp_buf savjmp; /* Save area for set/longjmp */ + +/* Misc. global variables */ +char *cmdptr, /* Command line parse pointer */ + *dataptr, /* Read data pointer */ + buffer[BUFFER_SIZE]; /* General input buffer */ +unsigned mode = 0, /* 0=Stopped, !0=Running */ + expr_type, /* Type of last expression */ + nest; /* Nest level of expr. parser */ +unsigned line, /* Current line number */ + ctl_ptr = 0, /* Control stack pointer */ + ctl_stk[50]; /* Control stack */ + +/* + * The following variables must be iniitialized to zero. If your + * compiler does not automatically zero uninitialized global + * variables, modify these declarations to initialize them. + */ +char filename[65]; /* Name of program file */ +FILE *files[10]; /* File unit numbers */ +int num_vars[NUM_VAR]; /* Numeric variables */ +int *dim_vars[NUM_VAR]; /* Dimensioned arrays */ +char *char_vars[NUM_VAR]; /* Character variables */ + +int eval_sub(void); + +WINDOW *win; + +void beep (int i, int t) +{ + printf("BEEP not implemented yet, at line %u\n", line); +} + +void delay (int msec) +{ + usleep (msec * 1000); +} + +int sigint(int sn) +{ + nocbreak(); + echo(); + endwin(); + exit(0); +} + +unsigned kbtst () +{ + unsigned int chr; + + signal(SIGINT,(sig_t)sigint); + win = initscr(); + cbreak(); + noecho(); + chr = getch(); + nocbreak(); + echo(); + endwin(); + signal(SIGINT,SIG_DFL); + return chr; +} + +void out (int addr, int value) +{ + /* 2BSD system call extension. */ + ustore (addr, value); +} + +unsigned in (int addr) +{ + /* 2BSD system call extension. */ + return ufetch (addr); +} + +int _sin (int value) +{ + return (int)(1.0e6 * sin(value * 1.0e-6)); +} + +int _cos (int value) +{ + return (int)(1.0e6 * cos(value * 1.0e-6)); +} + +int _tan (int value) +{ + return (int)(1.0e6 * tan(value * 1.0e-6)); +} + +int _asin (int value) +{ + return (int)(1.0e6 * asin(value * 1.0e-6)); +} + +int _acos (int value) +{ + return (int)(1.0e6 * acos(value * 1.0e-6)); +} + +int _atan (int value) +{ + return (int)(1.0e6 * atan(value * 1.0e-6)); +} + +int _log (int value) +{ + return (int)(1.0e6 * log(value * 1.0e-6)); +} + +int _log10 (int value) +{ + return (int)(1.0e6 * log10(value * 1.0e-6)); +} + +int _exp (int value) +{ + return (int)(1.0e6 * exp(value * 1.0e-6)); +} + +int isalnum(int c) +{ + c = (unsigned char) c; + if (c >= 'a' && c <= 'z') + return 1; + if (c >= '0' && c <= '9') + return 1; + if (c >= 'A' && c <= 'Z') + return 1; + return 0; +} + +int isalpha(int c) +{ + c = (unsigned char) c; + if (c >= 'a' && c <= 'z') + return 1; + if (c >= 'A' && c <= 'Z') + return 1; + return 0; +} + +int isdigit(int c) +{ + c = (unsigned char) c; + return c >= '0' && c <= '9'; +} + +int toupper(int c) +{ + c = (unsigned char) c; + if (c >= 'a' && c <= 'z') + c += 'A' - 'a'; + return c; +} + +void concat (char *ab, char *a, char *b) +{ + strcpy (ab, a); + strcat (ab, b); +} + +/* + * Test for end of expression + */ +int is_e_end(char c) +{ + if ((c >= (-128+TO)) && (c < (-128+ADD))) + return(1); + return (c == '\0') || (c == ':') || (c == ')') || (c == ','); +} + +/* + * Test for end of statement + */ +int is_l_end(char c) +{ + return (c == '\0') || (c == ':'); +} + +/* + * Test for terminator character + */ +int isterm(char c) +{ + return (c == ' ') || (c == '\t'); +} + +/* + * Advance to next non-blank & retreive data + */ +char skip_blank() +{ + while (isterm(*cmdptr)) + ++cmdptr; + return *cmdptr; +} + +/* + * Advance to., retrieve and skip next non blank + */ +char get_next() +{ + char c; + + while (isterm(c = *cmdptr)) + ++cmdptr; + if (c) + ++cmdptr; + return c; +} + +/* + * Test for a specific character occuring next & remove if found + */ +int test_next(int token) +{ + if (skip_blank() == token) { + ++cmdptr; + return -1; + } + return 0; +} + +/* + * Dislay error message + */ +void error(unsigned en) +{ + printf("%s error", error_messages[en]); + if (mode) + printf(" in line %u", line); + putc('\n',stdout); + longjmp(savjmp, 1); +} + +/* + * Expect a specific token - syntax error if not found + */ +void expect(int token) +{ + if (get_next() != token) + error(0); +} + +/* + * Lookup up word from command line in table + */ +unsigned lookup(char *table[]) +{ + unsigned i; + char *cptr, *optr; + + optr = cmdptr; + for (i=0; (cptr = table[i]); ++i) { + while ((*cptr) && (*cptr == toupper(*cmdptr))) { + ++cptr; + ++cmdptr; + } + if (! *cptr) { + if (! (isalnum(*(cptr-1)) && isalnum(*cmdptr)) ) { + skip_blank(); + return i+1; + } + } + cmdptr = optr; + } + return 0; +} + +/* + * Get a number from the input buffer + */ +unsigned get_num() +{ + unsigned value; + char c; + + value = 0; + while (isdigit(c = *cmdptr)) { + ++cmdptr; + value = (value * 10) + (c - '0'); + } + return value; +} + +/* + * Allocate memory and zero it + */ +char *allocate(unsigned size) +{ + char *ptr; + + ptr = malloc(size); + if (! ptr) + error(12); + memset(ptr, 0, size); + return ptr; +} + +/* + * Delete a line from the program + */ +void delete_line(unsigned lino) +{ + struct line_record *cptr, *bptr = 0; + + if (! pgm_start) /* no lines in pgm */ + return; + cptr = pgm_start; + do { + if (lino == cptr->Lnumber) { /* we have line to delete */ + if (cptr == pgm_start) { /* first line in pgm */ + pgm_start = cptr->Llink; + return; + } + if (bptr) /* skip it in linked list */ + bptr->Llink = cptr->Llink; + free(cptr); /* let it go */ + } + bptr = cptr; + } while ((cptr = cptr->Llink)); +} + +/* + * Insert a line into the program + */ +void insert_line(unsigned lino) +{ + struct line_record *cptr, *bptr, *optr; + + bptr = (struct line_record*) + allocate(sizeof (struct line_record) + strlen (cmdptr)); + bptr->Lnumber = lino; + strcpy (bptr->Ltext, cmdptr); + if (! pgm_start || lino < pgm_start->Lnumber) { + /* at start */ + bptr->Llink = pgm_start; + pgm_start = bptr; + return; + } + /* inserting into main part of pgm */ + cptr = pgm_start; + for (;;) { + optr = cptr; + cptr = cptr->Llink; + if (! cptr || lino < cptr->Lnumber) { + bptr->Llink = optr->Llink; + optr->Llink = bptr; + break; + } + } +} + +/* + * Tokenize input line and Add/Replace a source line if suitable + */ +int edit_program() +{ + unsigned value; + char *ptr, c; + + cmdptr = ptr = buffer; + /* Translate special tokens into codes */ + while ((c = *cmdptr)) { + if (c == '\n' || c == '\r') { + ++cmdptr; + continue; + } + value = lookup(reserved_words); + if (value) + *ptr++ = value | 0x80; + else { + *ptr++ = c; + ++cmdptr; + if (c == '"') { /* double quote */ + while ((c = *cmdptr) && (c != '"')) { + ++cmdptr; + *ptr++ = c; + } + *ptr++ = *cmdptr++; + } + } + } + *ptr = 0; + cmdptr = buffer; + + if (isdigit(skip_blank())) { /* Valid source line */ + value = get_num(); /* Get line number */ + delete_line(value); /* Delete the old */ + if (skip_blank()) + insert_line(value); + return -1; /* Insert the new */ + } + return 0; +} + +/* + * Locate given line in source + */ +struct line_record *find_line(unsigned line) +{ + struct line_record *cptr; + + for (cptr = pgm_start; cptr; cptr = cptr->Llink) + if (cptr->Lnumber == line) + return cptr; + error(3); + return 0; +} + +/* + * Get index for variable from its name + */ +int get_var() +{ + unsigned index; + char c; + + if (! isalpha(c = get_next())) + error(0); + index = ((c - 'A') & 0x1F) * 10; + if (isdigit(c = *cmdptr)) { + index += (c - '0'); + c = *++cmdptr; + } + if (c == '$') { + ++cmdptr; + expr_type = 1; + } else + expr_type = 0; + + return index; +} + +/* + * Evaluate an expression (numeric or character) + */ +int eval() +{ + unsigned value; + + nest = 0; + value = eval_sub(); + if (nest != 1) + error(0); + return value; +} + +/* + * Evaluate number only (no character) + */ +int eval_num() +{ + unsigned value; + + value = eval(); + if (expr_type) + error(4); + return value; +} + +/* + * Evaluate character only (no numeric) + */ +void eval_char() +{ + eval(); + if (! expr_type) + error(4); +} + +/* + * Compute variable address for assignment + */ +unsigned *address() +{ + unsigned i, j, *dptr; + + i = get_var(); + if (expr_type) + return (unsigned*) &char_vars[i]; + + if (! test_next('(')) + return (unsigned*) &num_vars[i]; + + /* Array */ + if (expr_type) + error(0); + dptr = (unsigned*) dim_vars[i]; + if (! dptr) + error(10); + nest = 0; + j = eval_sub(); + if (j >= dim_check[i]) + error(10); + return &dptr[j]; +} + +/* + * Test for file operator, and set up pointers + */ +int chk_file(char flag) +{ + unsigned i; + + i = -1; + if (test_next('#')) { + if (9 < (i = eval_num())) + error(7); + test_next(','); + filein = fileout = files[i]; + if (flag && (!filein)) + error(7); + } else { + filein = stdin; + fileout = stdout; + } + return i; +} + +/* + * Display program listing + */ +void disp_pgm(FILE *fp, unsigned i, unsigned j) +{ + unsigned k; + struct line_record *cptr; + char c; + + for (cptr = pgm_start; cptr; cptr = cptr->Llink) { + k = cptr->Lnumber; + if ((k >= i) && (k <= j)) { + fprintf(fp,"%u ",k); + for (k=0; (c = cptr->Ltext[k]); ++k) + if (c < 0) { + c = c & 127; + fputs(reserved_words[c - 1], fp); + if (c < ADD) + putc(' ',fp); + } else + putc(c,fp); + putc('\n', fp); + } + } +} + +/* + * Clear all variables to zero + */ +void clear_vars() +{ + unsigned i; + char *ptr; + + for (i=0; i < NUM_VAR; ++i) { + num_vars[i] = 0; + ptr = char_vars[i]; /* Character variables */ + if (ptr) { + free(ptr); + char_vars[i] = 0; + } + ptr = (char*) dim_vars[i]; /* Dimensioned arrays */ + if (ptr) { + free(ptr); + dim_vars[i] = 0; + } + } +} + +/* + * Clear program completely + */ +void clear_pgm() +{ + for (runptr = pgm_start; runptr; runptr = runptr->Llink) + free(runptr); + pgm_start = 0; +} + +/* + * Test for program only, and error if interactive + */ +void pgm_only() +{ + if (! mode) + error(2); +} + +/* + * Test for direct only, and error if running + */ +void direct_only() +{ + if (mode) + error(1); +} + +/* + * Skip rest of statement + */ +void skip_stmt() +{ + char c; + + while ((c = *cmdptr) && (c != ':')) { + ++cmdptr; + if (c == '"') { + while ((c = *cmdptr) && (c != '"')) + ++cmdptr; + if (c) + ++cmdptr; + } + } +} + +const char *wday_s[] = { + "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", 0 +}; +const char *wday_l[] = { + "Sunday", "Monday", "Tuesday", "Wednesday", + "Thursday", "Friday", "Saturday", 0 +}; +const char *month_l[] = { + "January", "February", "March", "April", "May", "June", + "July", "August", "September", "October", "November", "December", + 0 +}; +const char *month_s[] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", + 0 +}; + +void date_string(char *format, char *ptr) +{ + char *f; + time_t t = time(NULL); + struct tm *tm = localtime(&t); + char *fmt = strdup(format); + + for (f=fmt; *f; f++) { + if (*f == '%') { + f++; + switch (*f) { + case 'd': // Day of the month, 2 digits, leading 0 - 01-31 + sprintf(ptr,"%02d",tm->tm_mday); + break; + case 'D': + sprintf(ptr,"%s",wday_s[tm->tm_wday]); + break; + case 'j': + sprintf(ptr,"%d",tm->tm_mday); + break; + case 'l': + sprintf(ptr,"%s",wday_l[tm->tm_wday]); + break; + case 'N': + sprintf(ptr,"%d",tm->tm_wday == 0 ? 7 : tm->tm_wday); + break; + case 'S': + switch (tm->tm_mday) { + case 1: + case 21: + case 31: + sprintf(ptr,"st"); + break; + case 2: + case 22: + sprintf(ptr,"nd"); + break; + case 3: + case 23: + sprintf(ptr,"rd"); + break; + default: + sprintf(ptr,"th"); + break; + } + break; + case 'w': + sprintf(ptr,"%d",tm->tm_wday); + break; + case 'z': + sprintf(ptr,"%d",tm->tm_yday); + break; + case 'F': + sprintf(ptr,"%s",month_l[tm->tm_mon]); + break; + case 'm': + sprintf(ptr,"%02d",tm->tm_mon+1); + break; + case 'M': + sprintf(ptr,"%s",month_s[tm->tm_mon]); + break; + case 'n': + sprintf(ptr,"%d",tm->tm_mon+1); + break; + case 't': + switch (tm->tm_mon) { + case 0: sprintf(ptr,"%d",31); break; // Jan + case 1: sprintf(ptr,"%d",((tm->tm_year+1900) % 4 == 0) ? 29 : 28); break; // Feb + case 2: sprintf(ptr,"%d",31); break; // Mar + case 3: sprintf(ptr,"%d",30); break; // Apr + case 4: sprintf(ptr,"%d",31); break; // May + case 5: sprintf(ptr,"%d",30); break; // Jun + case 6: sprintf(ptr,"%d",31); break; // Jul + case 7: sprintf(ptr,"%d",31); break; // Aug + case 8: sprintf(ptr,"%d",30); break; // Sep + case 9: sprintf(ptr,"%d",31); break; // Oct + case 10: sprintf(ptr,"%d",30); break; // Nov + case 11: sprintf(ptr,"%d",31); break; // Dec + } + break; + case 'L': + sprintf(ptr,"%d",((tm->tm_year+1900) % 4 == 0) ? 1 : 0); + break; + case 'o': + case 'Y': + sprintf(ptr,"%04d",tm->tm_year+1900); + break; + case 'y': + sprintf(ptr,"%02d",(tm->tm_year+1900) % 100); + break; + case 'a': + sprintf(ptr,"%s",(tm->tm_hour<12) ? "am" : "pm"); + break; + case 'A': + sprintf(ptr,"%s",(tm->tm_hour<12) ? "AM" : "PM"); + break; + case 'g': + sprintf(ptr,"%d",tm->tm_hour % 12); + break; + case 'G': + sprintf(ptr,"%d",tm->tm_hour); + break; + case 'h': + sprintf(ptr,"%02d",tm->tm_hour % 12); + break; + case 'H': + sprintf(ptr,"%02d",tm->tm_hour); + break; + case 'i': + sprintf(ptr,"%02d",tm->tm_min); + break; + case 's': + sprintf(ptr,"%02d",tm->tm_sec); + break; + case 'u': + sprintf(ptr,"000000"); + break; + case 'e': + sprintf(ptr,"%s",tm->tm_zone); + break; + case 'I': + sprintf(ptr,"%d",tm->tm_isdst); + break; + case 'O': + sprintf(ptr,"%02d%02d",(int)tm->tm_gmtoff/60,(int)tm->tm_gmtoff%60); + break; + case 'P': + sprintf(ptr,"%02d:%02d",(int)tm->tm_gmtoff/60,(int)tm->tm_gmtoff%60); + break; + case 'T': + sprintf(ptr,"%s",tm->tm_zone); + break; + default: + *ptr++ = *f; + *ptr = 0; + } + } else { + *ptr++ = *f; + *ptr = 0; + } + while (*ptr) + ptr++; + } + free(fmt); +} + +/* + * Convert a number to a string, and place in memory + */ +void num_string(unsigned value, char *ptr) +{ + char cstack[12]; + int i; + + if (value > INT_MAX) { + *ptr++ = '-'; + value = -value; + } + i = 0; + do { + cstack[i++] = (value % 10) + '0'; + } while (value /= 10); + + while (i) + *ptr++ = cstack[--i]; + *ptr = 0; +} + +/* + * Execute a BASIC commands + */ +struct line_record *execute(char cmd) +{ + unsigned i, j, k, *dptr; + int ii, jj; + struct line_record *cptr; + char c; + + switch (cmd & 0x7F) { + case LET: + dptr = address(); + j = expr_type; + + expect(-128+EQ); + + k = eval(); + + if (j != expr_type) + error(0); + if (! expr_type) /* numeric assignment */ + *dptr = k; + else { /* character assignment */ + if (*dptr) + free((void*) *dptr); + if (*sa1) { + *dptr = (unsigned) allocate(strlen(sa1)+1); + strcpy((char*) *dptr, sa1); + } else + *dptr = 0; + } + break; + case EXIT: + exit(0); + case LIST: + chk_file(1); + if (! isdigit(skip_blank())) { + i=0; j=-1; + } else { + i = get_num(); + if (get_next() == ',') { + if (isdigit(skip_blank())) + j=get_num(); + else + j = -1; + } else + j=i; + } + disp_pgm(fileout,i,j); + break; + case NEW: + clear_vars(); + clear_pgm(); + longjmp(savjmp, 1); + case RUN: + direct_only(); + clear_vars(); + case RUN1: /* No clearing */ + if (is_e_end(skip_blank())) + runptr = pgm_start; + else + runptr = find_line(eval_num()); + --mode; /* indicate running */ +newline: + while (runptr) { + cmdptr = runptr->Ltext; + line = runptr->Lnumber; + do { + if ((cmd = skip_blank()) < 0) { + ++cmdptr; + dptr = (unsigned*) execute(cmd); + if (dptr) { + runptr = (struct line_record*) dptr; + goto newline; + } + } else + execute(1); + } while ((c = get_next()) == ':'); + if (c) + error(0); + runptr = runptr->Llink; + } + mode = 0; + break; + case CLEAR: + clear_vars(); + break; + case GOSUB: + ctl_stk[ctl_ptr++] = (unsigned) runptr; + ctl_stk[ctl_ptr++] = (unsigned) cmdptr; + ctl_stk[ctl_ptr++] = _GOSUB; + case GOTO: + pgm_only(); + return find_line(eval_num()); + case RETURN: + pgm_only(); + if (ctl_stk[--ctl_ptr] != _GOSUB) + error(6); + cmdptr = (char*) ctl_stk[--ctl_ptr]; + runptr = (struct line_record*) ctl_stk[--ctl_ptr]; + line = runptr->Lnumber; + skip_stmt(); + break; + case PRINT: + chk_file(1); + j = 0; + do { + if (is_l_end(skip_blank())) + --j; + else { + i = eval(); + if (! expr_type) { + num_string(i, sa1); + putc(' ',fileout); + } + fputs(sa1, fileout); + } + } while (test_next(',')); + if (! j) + putc('\n', fileout); + break; + case FOR: + pgm_only(); + ii = 1; /* default step value */ + i = get_var(); + if (expr_type) + error(0); + expect(-128+EQ); + num_vars[i] = eval(); + if (expr_type) + error(0); + expect(-128+TO); + jj = eval(); + if (test_next(-128+STEP)) + ii = eval(); + skip_stmt(); + ctl_stk[ctl_ptr++] = (unsigned) runptr; /* line */ + ctl_stk[ctl_ptr++] = (unsigned) cmdptr; /* command pointer */ + ctl_stk[ctl_ptr++] = ii; /* step value */ + ctl_stk[ctl_ptr++] = jj; /* limit value */ + ctl_stk[ctl_ptr++] = i; /* variable number */ + ctl_stk[ctl_ptr++] = _FOR; + break; + case NEXT: + pgm_only(); + if (ctl_stk[ctl_ptr-1] != _FOR) + error(6); + i = ctl_stk[ctl_ptr-2]; + if (!is_l_end(skip_blank())) + if (get_var() != i) + error(6); + jj = ctl_stk[ctl_ptr-3]; /* get limit */ + ii = ctl_stk[ctl_ptr-4]; /* get step */ + num_vars[i] += ii; + if ((ii < 0) ? num_vars[i] >= jj : num_vars[i] <= jj) { + cmdptr = (char*) ctl_stk[ctl_ptr-5]; + runptr = (struct line_record*) ctl_stk[ctl_ptr-6]; + line = runptr->Lnumber; + } else + ctl_ptr -= 6; + break; + case IF: + i = eval_num(); + expect(-128+THEN); + if (i) { + if (isdigit(cmd = skip_blank())) + return find_line(eval_num()); + else if (cmd < 0) { + ++cmdptr; + return execute(cmd); + } else + execute(1); + } else + skip_stmt(); + break; + case LIF: + i = eval_num(); + expect(-128+THEN); + if (i) { + if ((cmd = skip_blank()) < 0) { + ++cmdptr; + return execute(cmd); + } else + execute(1); + break; + } + case DATA: + pgm_only(); + case REM: + if (mode) { + if ((cptr = runptr->Llink)) + return cptr; + longjmp(savjmp, 1); + } + break; + case STOP: + pgm_only(); + printf("STOP in line %u\n",line); + case END: + pgm_only(); + longjmp(savjmp, 1); + case INPUT: + ii = chk_file(1); + if (skip_blank() == '"') { /* special prompt */ + eval(); + expect(','); + } else + strcpy(sa1, "? "); + dptr = address(); + cptr = (struct line_record*) cmdptr; +input: if (ii == -1) + fputs(sa1, stdout); + if (! fgets(buffer, sizeof(buffer)-1, filein)) + exit (0); + /* Remove trailing eols. */ + cmdptr = buffer + strlen(buffer); + while (cmdptr > buffer && + (cmdptr[-1] == '\n' || cmdptr[-1] == '\r')) + *--cmdptr = 0; + cmdptr = buffer; + if (expr_type) { + if (*dptr) + free((void*) *dptr); + *dptr = (unsigned) allocate(strlen(buffer)+1); + strcpy((char*) *dptr, buffer); + } else { + k = 0; + if (test_next('-')) + --k; + if (! isdigit(*cmdptr)) { + if (ii != -1) + error(9); + fputs("Input error\n", stdout); + goto input; + } + j = get_num(); + *dptr = (k) ? 0-j: j; + } + cmdptr = (char*) cptr; + break; + case OPEN: + if (skip_blank() != '#') + error(0); + if (files[i = chk_file(0)]) + error(8); + eval_char(); + strcpy(buffer, sa1); + expect(','); + eval_char(); + files[i] = fopen(buffer,sa1); + break; + case CLOSE: + if ((i = chk_file(1)) == -1) + error(0); + if (! filein) + error(8); + fclose(files[i]); + files[i] = 0; + break; + case DIM: + do { + i = get_var(); + dptr = (unsigned*) dim_vars[i]; + if (dptr) + free(dptr); + dim_check[i] = eval_num() + 1; + dim_vars[i] = (int*) allocate(dim_check[i] * sizeof(int)); + } while (test_next(',')); + break; + case ORDER: + readptr = find_line(eval_num()); + dptr = (unsigned*) cmdptr; + cmdptr = readptr->Ltext; + if (get_next() != -128+DATA) + error(11); + dataptr = cmdptr; + cmdptr = (char*) dptr; + break; + case READ: + do { + dptr = address(); + j = expr_type; + cptr = (struct line_record*) cmdptr; + cmdptr = dataptr; + ii = line; + if (! skip_blank()) { /* End of line */ + readptr = readptr->Llink; + cmdptr = readptr->Ltext; + if (get_next() != -128+DATA) + error(11); + } + line = readptr->Lnumber; + k = eval(); + test_next(','); + dataptr = cmdptr; + cmdptr = (char*) cptr; + line = ii; + if (j != expr_type) + error(11); + if (! expr_type) /* numeric assignment */ + *dptr = k; + else { /* character assignment */ + if (*dptr) + free((void*) *dptr); + if (*sa1) { + *dptr = (unsigned) allocate(strlen(sa1)+1); + strcpy((char*) *dptr, sa1); + } else + *dptr = 0; + } + } while (test_next(',')); + break; + case DELAY: + delay(eval_num()); + break; + case SRND: + srandom(eval_num()); + break; + case BEEP: + i = eval_num(); + expect(','); + beep(i, eval_num()); + break; + case DOS: + eval_char(); + fflush(stdout); + system(sa1); + break; + case OUT: + i = eval_num(); + expect(','); + out(i, eval_num()); + break; + case SAVE: + direct_only(); + if (skip_blank()) { + eval_char(); + concat(filename, sa1, ""); + } + fileout = fopen(filename, "wv"); + if (fileout) { + disp_pgm(fileout, 0, -1); + fclose(fileout); + } else + perror (filename); + break; + case LOAD: + eval_char(); + concat(filename, sa1, ""); + filein = fopen(filename, "rv"); + if (filein) { + if (! mode) + clear_vars(); + clear_pgm(); + while (fgets(buffer, sizeof(buffer)-1, filein)) + edit_program(); + fclose(filein); + return pgm_start; + } else + perror (filename); + longjmp(savjmp, 1); + default: /* unknown */ + error(0); + } + return 0; +} + +/* + * Perform an arithmetic operation + */ +int do_arith(char opr, unsigned op1, unsigned op2) +{ + unsigned value; + + switch (opr) { + case ADD-(ADD-1): /* addition */ + value = op1 + op2; + break; + case SUB-(ADD-1): /* subtraction */ + value = op1 - op2; + break; + case MUL-(ADD-1): /* multiplication */ + value = op1 * op2; + break; + case DIV-(ADD-1): /* division */ + value = op1 / op2; + break; + case MOD-(ADD-1): /* modulus */ + value = op1 % op2; + break; + case AND-(ADD-1): /* logical and */ + value = op1 & op2; + break; + case OR-(ADD-1): /* logical or */ + value = op1 | op2; + break; + case XOR-(ADD-1): /* exclusive or */ + value = op1 ^ op2; + break; + case EQ-(ADD-1): /* equals */ + value = op1 == op2; + break; + case NE-(ADD-1): /* not-equals */ + value = op1 != op2; + break; + case LE-(ADD-1): /* less than or equal to */ + value = op1 <= op2; + break; + case LT-(ADD-1): /* less than */ + value = op1 < op2; + break; + case GE-(ADD-1): /* greater than or equal to */ + value = op1 >= op2; + break; + case GT-(ADD-1): /* greater than */ + value = op1 > op2; + break; + default: + error(0); + value = 0; + } + return value; +} + +/* + * Get character value + */ +void get_char_value(char *ptr) +{ + unsigned i; + char c, *st; + + if ((c = get_next()) == '"') { /* character value */ + while ((c = *cmdptr++) != '"') { + if (! c) + error(0); + *ptr++ = c; + } + *ptr = 0; + } else if (isalpha(c)) { /* variable */ + --cmdptr; + i = get_var(); + if (! expr_type) + error(0); + st = char_vars[i]; + if (st) + strcpy(ptr,st); + else + strcpy(ptr,""); + } else if (c == -128+CHR) { /* Convert number to character */ + *ptr++ = eval_sub(); + if (expr_type) + error(4); + *ptr = 0; + } else if (c == -128+STR) { /* Convert number to string */ + num_string(eval_sub(), ptr); + if (expr_type) + error(4); + } else if (c == -128+DATE) { /* Format a date */ + eval_sub(); + if (! expr_type) + error(4); + date_string(sa1,ptr); + } else + error(0); + expr_type = 1; +} + +/* + * Get a value element for an expression + */ +int get_value() +{ + unsigned value, v, *dptr; + char c, *ptr; + + expr_type = 0; + if (isdigit(c = skip_blank())) + value = get_num(); + else { + ++cmdptr; + switch (c) { + case '(': /* nesting */ + value = eval_sub(); + break; + case '!': /* not */ + value = ~get_value(); + break; + case -128+SUB: /* negate */ + value = -get_value(); + break; + case -128+ASC: /* Convert character to number */ + eval_sub(); + if (! expr_type) + error(4); + value = *sa1 & 255; + expr_type = 0; + break; + case -128+NUM: /* Convert string to number */ + eval_sub(); + if (! expr_type) + error(4); + value = atoi(sa1); + expr_type = 0; + break; + case -128+ABS: /* Absolute value */ + if ((value = eval_sub()) > INT_MAX) + value = -value; + goto number_only; + case -128+RND: /* Random number */ + value = random() % eval_sub(); + goto number_only; + case -128+SIN: /* SIN */ + value = _sin(eval_sub()); + goto number_only; + case -128+COS: /* COS */ + value = _cos(eval_sub()); + goto number_only; + case -128+TAN: /* TAN */ + value = _tan(eval_sub()); + goto number_only; + case -128+ASIN: /* ASIN */ + value = _asin(eval_sub()); + goto number_only; + case -128+ACOS: /* ACOS */ + value = _acos(eval_sub()); + goto number_only; + case -128+ATAN: /* ATAN */ + value = _atan(eval_sub()); + goto number_only; + case -128+LOG: /* LN */ + value = _log(eval_sub()); + goto number_only; + case -128+LOG10: /* LOG */ + value = _log10(eval_sub()); + goto number_only; + case -128+EXP: /* EXP */ + value = _exp(eval_sub()); + goto number_only; + case -128+KEY: /* Keyboard test */ + /* eval_sub(); */ + expect(')'); + value = kbtst(); + break; + case -128+INP: /* Read from port */ + value = in(eval_sub()); +number_only: + if (expr_type) + error(4); + break; + default: /* test for character expression */ + --cmdptr; + if (isalpha(c)) { /* variable */ + value = get_var(); + if (expr_type) { /* char */ + ptr = char_vars[value]; + if (ptr) + strcpy(sa1, ptr); + else + strcpy(sa1, ""); + } else { + if (test_next('(')) { /* Array */ + dptr = (unsigned*) dim_vars[value]; + if (! dptr) + error(10); + if ((v = eval_sub()) >= dim_check[value]) + error(10); + value = dptr[v]; + } else /* Std variable */ + value = num_vars[value]; + } + } else { + get_char_value(sa1); + value = 0; + } + } + } + return value; +} + +/* + * Evaluate a sub expression + */ +int eval_sub() +{ + unsigned value, nstack[10], nptr, optr; + int ostack[10], c; + + ++nest; /* indicate we went down */ + + /* establish first entry on number and operator stacks */ + ostack[optr = nptr = 0] = 0; /* add zero to init */ + + nstack[++nptr] = get_value(); /* get next value */ + + /* string operations */ + if (expr_type) { /* string operations */ + while (! is_e_end(c = skip_blank())) { + ++cmdptr; + c &= 0x7F; + get_char_value(sa2); + if (c == ADD) /* String concatination */ + strcat(sa1, sa2); + else { + if (c == EQ) /* String EQUALS */ + value = !strcmp(sa1, sa2); + else if (c == NE) /* String NOT EQUALS */ + value = strcmp(sa1, sa2) != 0; + else { + error(0); + value = 0; + } + nstack[nptr] = value; + expr_type = 0; + } + } + + /* numeric operations */ + } else { + while (! is_e_end(c = skip_blank())) { + ++cmdptr; + c = (c & 0x7F) - (ADD-1); /* 0 based priority table */ + if (priority[c] <= priority[ostack[optr]]) { + /* execute operand */ + value = nstack[nptr--]; + nstack[nptr] = do_arith(ostack[optr--], nstack[nptr], value); + } + nstack[++nptr] = get_value(); /* stack next operand */ + if (expr_type) + error(0); + ostack[++optr] = c; + } + while (optr) { /* clean up all pending operations */ + value = nstack[nptr--]; + nstack[nptr] = do_arith(ostack[optr--], nstack[nptr], value); + } + } + if (c == ')') { + --nest; + ++cmdptr; + } + return nstack[nptr]; +} + +/* + * Main program + */ +int main(int argc, char *argv[]) +{ + int i, j; + + pgm_start = 0; + srandom (time (0)); + + /* + * If arguments are given, copy them into the A0$, A1$, A2$ ... variables + */ + j = 0; + for (i=1; i < argc; ++i) + char_vars[j++] = strdup (argv[i]); + + /* + * If a name is given on the command line, load it as a program and + * run immediately. If the program does not explicitly EXIT, we will + * then proceed to an interactive session + */ + if (j) { + concat(filename, char_vars[0], ""); + filein = fopen(filename, "rv"); + if (filein) { + while (fgets(buffer, sizeof(buffer)-1, filein)) + edit_program(); + fclose(filein); + cmdptr = ""; + if (! setjmp(savjmp)) + execute(RUN1); + } else + perror (filename); + } + + /* + * Display header AFTER running command line, so that programs run as + * "batch" commands terminating with EXIT do not get "noise" output. + */ + printf("MICRO-BASIC 2.1 - Copyright 1982-2000 Dave Dunfield.\n"); + + setjmp(savjmp); + for (;;) { /* Main interactive loop */ + fputs("Ready\n", stdout); +noprompt: + mode = 0; + ctl_ptr = 0; + if (! fgets(buffer, sizeof(buffer)-1, stdin)) + exit (0); + if (edit_program()) /* Tokenize & edit if OK */ + goto noprompt; + i = *cmdptr; + if (i < 0) { /* Keyword, execute command */ + ++cmdptr; + execute(i); + } else if (i) /* Unknown, assume LET */ + execute(LET); + } +} diff --git a/src/cmd/basic/blkjack.bas b/src/cmd/basic/blkjack.bas new file mode 100644 index 0000000..489dd0a --- /dev/null +++ b/src/cmd/basic/blkjack.bas @@ -0,0 +1,61 @@ +10 rem ************************************** +20 rem *** Play the "blackjack" (21) game *** +30 rem ************************************** +40 dim C(52): m = 1000 +50 rem +60 rem Create deck of cards and shuffle it +70 rem +80 for i=0 to 51: c(i) = i: next i +90 for i=0 to 51: i1=rnd(52): i2=c(i): c(i)=c(i2): c(i2)=i1: next i +100 rem +110 rem Prompt for amount of bet (on this game) +120 rem +130 print "You have", m, " dollars" +140 input "How much do you wish to bet?", b: if b=0 then stop +150 lif b>m then print "You don't have enough money":goto 140 +160 t = 0: d = 0 +170 rem +180 rem Prompt PLAYER for another card +190 rem +200 print "Total:", t,:Input " Another card (Y/N)?", a$ +210 if a$="n" then 380 +220 lif a$<>"y" then print "Please answer y-Yes or n-No":goto 200 +230 c = c(d): d = d + 1: gosub 530 +240 c = c % 13: if c > 9 then c = 9 +250 if c > 0 then 300 +260 input "(1)one or (t)ten ?", a$ +270 if a$="1" then 300 +280 if a$<>"t" then 260 +290 c = 9 +300 t = t + c + 1 +310 if t <= 21 then 200 +320 print "You went over 21! - you LOSE!" +330 m = m - b: if m > 0 then 80 +340 print "You went BUST!":end +350 rem +360 rem Play DEALER +370 rem +380 t1 = 0 +390 c = c(d): d = d + 1: print "Dealer draws ",: gosub 530 +400 c = c % 13: if c > 9 then c = 9 +410 if c > 0 then 470 +420 if t1 < 10 then 450 +430 if (t1+10) > 23 then 460 +440 if (t1+10) >= t then 450 +450 c = 9 +460 print "Dealer chooses", c+1 +470 t1 = t1 + c + 1: print "Dealer totals", t1: if t1 < t then 390 +480 lif t1 <= 21 then print "Dealer wins - You LOSE!": goto 330 +490 print "Dealer loses - You WIN!!!": m = m + b: goto 80 +500 rem +510 rem Subroutine to display text description of a card +520 rem +530 order 590 +540 for a = 0 to c / 13: read a$: next a +550 order 600 +560 for a = 0 to c % 13: read a1$:next a +570 print a1$, " of ", a$ +580 return +590 data "Hearts", "Diamonds", "Clubs", "Spades" +600 data "Ace", "Two", "Three", "Four", "Five", "Six", "Seven" +610 data "Eight", "Nine", "Ten", "Jack", "Queen", "King" diff --git a/src/cmd/basic/hilow.bas b/src/cmd/basic/hilow.bas new file mode 100644 index 0000000..6e721b5 --- /dev/null +++ b/src/cmd/basic/hilow.bas @@ -0,0 +1,13 @@ +10 rem **************************** +20 rem *** Play the HI/LOW game *** +30 rem **************************** +40 n = rnd(100) +50 c = 0 +60 input "Guess a number? ", g +70 c = c+1 +80 if g=n then 120 +90 if g>n then print "lower" +100 if g diff --git a/src/cmd/basic/renumber.c b/src/cmd/basic/renumber.c new file mode 100644 index 0000000..a66fbbc --- /dev/null +++ b/src/cmd/basic/renumber.c @@ -0,0 +1,122 @@ +/* + * MICRO-BASIC 2.1 line renumbering program. + * + * This program reads a MICRO-BASIC source file, and write a new one with + * all lines renumbered. All IF/THEN, GOTO, GOSUB and ORDER statements are + * adjusted to reflect the new line numbers. + * + * Copyright 1993-2000 Dave Dunfield + * All rights reserved. + * + * Permission granted for personal (non-commercial) use only. + * + * Compile command: cc renumber -fop + */ +#ifdef CROSS +# include +# include +#else +# include +# include +#endif +#include + +#define MAX_LINES 10000 /* Maximum # lines in input program */ + +/* + * Case insensitive test of 'ptr' beginning with 'string' + */ +int begins_with(char *ptr, char *string) +{ + while(*string) + if(toupper(*ptr++) != *string++) + return 0; + return -1; +} + +int main(int argc, char *argv[]) +{ + unsigned i, l, m; + char buffer[200], *ptr, *ptr1; + static unsigned lines[MAX_LINES], ltop = 0, increment = 10, start = 10; + static FILE *fp, *fp1; + + printf("MICRO-BASIC 2.1 line renumbering program\n"); + + if (argc < 3) { + fprintf(stderr, "Use: renumber old new [start [increment]]\n\n"); + fprintf(stderr, "Copyright 1993-2000 Dave Dunfield\n"); + fprintf(stderr, "All rights reserved.\n"); + return 1; + } + + fp = fopen(argv[1], "rvq"); + fp1 = fopen(argv[2], "wvq"); + if(argc > 3) + start = atoi(argv[3]); + if(argc > 4) + increment = atoi(argv[4]); + +/* Pass #1: Scan and record all line numbers */ + m = 0; + while(fgets(buffer, sizeof(buffer)-1, fp)) { + if(!(l = atoi(buffer))) { + printf("Invalid line number following line %u\n", m); + return 0; + } + if(l <= m) { + printf("Improper line sequence following line %u\n", m); + return 0; + } + lines[ltop++] = m = l; + } + +/* Pass #2: Copy lines and replace line numbers */ + rewind(fp); + m = 0; + while(fgets(ptr1 = ptr = buffer, sizeof(buffer), fp)) { + /* Replace line number with one from the new sequence */ +fixnum: while(isspace(*ptr)) + ++ptr; + while(ptr1 < ptr) + putc(*ptr1++, fp1); + if(isdigit(*ptr)) { + ++m; + l = atoi(ptr); + while(isdigit(*ptr)) + ++ptr; + for(i=0; i < ltop; ++i) + if(lines[i] == l) { + fprintf(fp1, "%u", i * increment + start); + break; + } + } + while(*(ptr1 = ptr)) { + if(begins_with(ptr, "THEN")) { + ptr += 4; + goto fixnum; + } + if(begins_with(ptr, "ORDER")) { + ptr += 5; + goto fixnum; + } + if(begins_with(ptr, "GOTO")) { + ptr += 4; + goto fixnum; + } + if(begins_with(ptr, "GOSUB")) { + ptr += 5; + goto fixnum; + } + if (*ptr != '\r' && *ptr != '\n') + putc(*ptr, fp1); + ++ptr; + } + putc('\n', fp1); + } + + fclose(fp1); + fclose(fp); + printf("%u lines read, %u fixups\n", ltop, m); + return 0; +} diff --git a/src/cmd/basic/stars.bas b/src/cmd/basic/stars.bas new file mode 100644 index 0000000..c2ff2bb --- /dev/null +++ b/src/cmd/basic/stars.bas @@ -0,0 +1,14 @@ +10 INPUT "Your name: ", U$ +20 PRINT "Hello ", U$ +30 INPUT "How many stars do you want: ", N +40 S$ = "" +50 FOR I = 1 TO N +60 S$ = S$ + "*" +70 NEXT I +80 PRINT S$ +90 INPUT "Do you want more stars? ", A$ +100 IF A$ = "" THEN GOTO 90 +110 IF A$ = "Y" THEN GOTO 30 +120 IF A$ = "y" THEN GOTO 30 +130 PRINT "Goodbye ", U$ +140 END diff --git a/src/cmd/bc.y b/src/cmd/bc.y new file mode 100644 index 0000000..982c86f --- /dev/null +++ b/src/cmd/bc.y @@ -0,0 +1,613 @@ +%{ + int *getout(); +%} +%right '=' +%left '+' '-' +%left '*' '/' '%' +%right '^' +%left UMINUS + +%term LETTER DIGIT SQRT LENGTH _IF FFF EQ +%term _WHILE _FOR NE LE GE INCR DECR +%term _RETURN _BREAK _DEFINE BASE OBASE SCALE +%term EQPL EQMI EQMUL EQDIV EQREM EQEXP +%term _AUTO DOT +%term QSTR + +%{ +#include +#include +#include +#include + +FILE *in; +char cary[1000], *cp = { cary }; +char string[1000], *str = {string}; +int crs = '0'; +int rcrs = '0'; /* reset crs */ +int bindx = 0; +int lev = 0; +int ln; +char *ss; +int bstack[10] = { 0 }; +char *numb[15] = { + " 0", " 1", " 2", " 3", " 4", " 5", + " 6", " 7", " 8", " 9", " 10", " 11", + " 12", " 13", " 14" }; +int *pre, *post; +%} +%% +start : + | start stat tail + = output( $2 ); + | start def dargs ')' '{' dlist slist '}' + ={ bundle( 6,pre, $7, post ,"0",numb[lev],"Q"); + conout( $$, $2 ); + rcrs = crs; + output( "" ); + lev = bindx = 0; + } + ; + +dlist : tail + | dlist _AUTO dlets tail + ; + +stat : e + ={ bundle(2, $1, "ps." ); } + | + ={ bundle(1, "" ); } + | QSTR + ={ bundle(3,"[",$1,"]P");} + | LETTER '=' e + ={ bundle(3, $3, "s", $1 ); } + | LETTER '[' e ']' '=' e + ={ bundle(4, $6, $3, ":", geta($1)); } + | LETTER EQOP e + ={ bundle(6, "l", $1, $3, $2, "s", $1 ); } + | LETTER '[' e ']' EQOP e + ={ bundle(8,$3, ";", geta($1), $6, $5, $3, ":", geta($1));} + | _BREAK + ={ bundle(2, numb[lev-bstack[bindx-1]], "Q" ); } + | _RETURN '(' e ')' + = bundle(4, $3, post, numb[lev], "Q" ); + | _RETURN '(' ')' + = bundle(4, "0", post, numb[lev], "Q" ); + | _RETURN + = bundle(4,"0",post,numb[lev],"Q"); + | SCALE '=' e + = bundle(2, $3, "k"); + | SCALE EQOP e + = bundle(4,"K",$3,$2,"k"); + | BASE '=' e + = bundle(2,$3, "i"); + | BASE EQOP e + = bundle(4,"I",$3,$2,"i"); + | OBASE '=' e + = bundle(2,$3,"o"); + | OBASE EQOP e + = bundle(4,"O",$3,$2,"o"); + | '{' slist '}' + ={ $$ = $2; } + | FFF + ={ bundle(1,"fY"); } + | error + ={ bundle(1,"c"); } + | _IF CRS BLEV '(' re ')' stat + ={ conout( $7, $2 ); + bundle(3, $5, $2, " " ); + } + | _WHILE CRS '(' re ')' stat BLEV + ={ bundle(3, $6, $4, $2 ); + conout( $$, $2 ); + bundle(3, $4, $2, " " ); + } + | fprefix CRS re ';' e ')' stat BLEV + ={ bundle(5, $7, $5, "s.", $3, $2 ); + conout( $$, $2 ); + bundle(5, $1, "s.", $3, $2, " " ); + } + | '~' LETTER '=' e + ={ bundle(3,$4,"S",$2); } + ; + +EQOP : EQPL + ={ $$ = (int) "+"; } + | EQMI + ={ $$ = (int) "-"; } + | EQMUL + ={ $$ = (int) "*"; } + | EQDIV + ={ $$ = (int) "/"; } + | EQREM + ={ $$ = (int) "%%"; } + | EQEXP + ={ $$ = (int) "^"; } + ; + +fprefix : _FOR '(' e ';' + ={ $$ = $3; } + ; + +BLEV : + ={ --bindx; } + ; + +slist : stat + | slist tail stat + ={ bundle(2, $1, $3 ); } + ; + +tail : '\n' + ={ln++;} + | ';' + ; + +re : e EQ e + = bundle(3, $1, $3, "=" ); + | e '<' e + = bundle(3, $1, $3, ">" ); + | e '>' e + = bundle(3, $1, $3, "<" ); + | e NE e + = bundle(3, $1, $3, "!=" ); + | e GE e + = bundle(3, $1, $3, "!>" ); + | e LE e + = bundle(3, $1, $3, "!<" ); + | e + = bundle(2, $1, " 0!=" ); + ; + +e : e '+' e + = bundle(3, $1, $3, "+" ); + | e '-' e + = bundle(3, $1, $3, "-" ); + | '-' e %prec UMINUS + = bundle(3, " 0", $2, "-" ); + | e '*' e + = bundle(3, $1, $3, "*" ); + | e '/' e + = bundle(3, $1, $3, "/" ); + | e '%' e + = bundle(3, $1, $3, "%%" ); + | e '^' e + = bundle(3, $1, $3, "^" ); + | LETTER '[' e ']' + ={ bundle(3,$3, ";", geta($1)); } + | LETTER INCR + = bundle(4, "l", $1, "d1+s", $1 ); + | INCR LETTER + = bundle(4, "l", $2, "1+ds", $2 ); + | DECR LETTER + = bundle(4, "l", $2, "1-ds", $2 ); + | LETTER DECR + = bundle(4, "l", $1, "d1-s", $1 ); + | LETTER '[' e ']' INCR + = bundle(7,$3,";",geta($1),"d1+",$3,":",geta($1)); + | INCR LETTER '[' e ']' + = bundle(7,$4,";",geta($2),"1+d",$4,":",geta($2)); + | LETTER '[' e ']' DECR + = bundle(7,$3,";",geta($1),"d1-",$3,":",geta($1)); + | DECR LETTER '[' e ']' + = bundle(7,$4,";",geta($2),"1-d",$4,":",geta($2)); + | SCALE INCR + = bundle(1,"Kd1+k"); + | INCR SCALE + = bundle(1,"K1+dk"); + | SCALE DECR + = bundle(1,"Kd1-k"); + | DECR SCALE + = bundle(1,"K1-dk"); + | BASE INCR + = bundle(1,"Id1+i"); + | INCR BASE + = bundle(1,"I1+di"); + | BASE DECR + = bundle(1,"Id1-i"); + | DECR BASE + = bundle(1,"I1-di"); + | OBASE INCR + = bundle(1,"Od1+o"); + | INCR OBASE + = bundle(1,"O1+do"); + | OBASE DECR + = bundle(1,"Od1-o"); + | DECR OBASE + = bundle(1,"O1-do"); + | LETTER '(' cargs ')' + = bundle(4, $3, "l", getf($1), "x" ); + | LETTER '(' ')' + = bundle(3, "l", getf($1), "x" ); + | cons + ={ bundle(2, " ", $1 ); } + | DOT cons + ={ bundle(2, " .", $2 ); } + | cons DOT cons + ={ bundle(4, " ", $1, ".", $3 ); } + | cons DOT + ={ bundle(3, " ", $1, "." ); } + | DOT + ={ $$ = (int) "l."; } + | LETTER + = { bundle(2, "l", $1 ); } + | LETTER '=' e + ={ bundle(3, $3, "ds", $1 ); } + | LETTER EQOP e %prec '=' + ={ bundle(6, "l", $1, $3, $2, "ds", $1 ); } + | LETTER '[' e ']' '=' e + = { bundle(5,$6,"d",$3,":",geta($1)); } + | LETTER '[' e ']' EQOP e + = { bundle(9,$3,";",geta($1),$6,$5,"d",$3,":",geta($1)); } + | LENGTH '(' e ')' + = bundle(2,$3,"Z"); + | SCALE '(' e ')' + = bundle(2,$3,"X"); /* must be before '(' e ')' */ + | '(' e ')' + = { $$ = $2; } + | '?' + ={ bundle(1, "?" ); } + | SQRT '(' e ')' + ={ bundle(2, $3, "v" ); } + | '~' LETTER + ={ bundle(2,"L",$2); } + | SCALE '=' e + = bundle(2,$3,"dk"); + | SCALE EQOP e %prec '=' + = bundle(4,"K",$3,$2,"dk"); + | BASE '=' e + = bundle(2,$3,"di"); + | BASE EQOP e %prec '=' + = bundle(4,"I",$3,$2,"di"); + | OBASE '=' e + = bundle(2,$3,"do"); + | OBASE EQOP e %prec '=' + = bundle(4,"O",$3,$2,"do"); + | SCALE + = bundle(1,"K"); + | BASE + = bundle(1,"I"); + | OBASE + = bundle(1,"O"); + ; + +cargs : eora + | cargs ',' eora + = bundle(2, $1, $3 ); + ; +eora: e + | LETTER '[' ']' + =bundle(2,"l",geta($1)); + ; + +cons : constant + ={ *cp++ = '\0'; } + +constant: + '_' + ={ $$ = (int) cp; *cp++ = '_'; } + | DIGIT + ={ $$ = (int) cp; *cp++ = $1; } + | constant DIGIT + ={ *cp++ = $2; } + ; + +CRS : + ={ $$ = (int) cp; *cp++ = crs++; *cp++ = '\0'; + if(crs == '[')crs+=3; + if(crs == 'a')crs='{'; + if(crs >= 0241){yyerror("program too big"); + getout(); + } + bstack[bindx++] = lev++; } + ; + +def : _DEFINE LETTER '(' + ={ $$ = (int) getf($2); + pre = (int*) ""; + post = (int*) ""; + lev = 1; + bstack[bindx=0] = 0; + } + ; + +dargs : + | lora + ={ pp( $1 ); } + | dargs ',' lora + ={ pp( $3 ); } + ; + +dlets : lora + ={ tp($1); } + | dlets ',' lora + ={ tp($3); } + ; +lora : LETTER + | LETTER '[' ']' + ={ $$ = (int) geta($1); } + ; + +%% +# define error 256 + +int peekc = -1; +int sargc; +int ifile; +char **sargv; + +char funtab[52] = { + 01,0,02,0,03,0,04,0,05,0,06,0,07,0,010,0,011,0,012,0,013,0,014,0,015,0,016,0,017,0, + 020,0,021,0,022,0,023,0,024,0,025,0,026,0,027,0,030,0,031,0,032,0 }; +char atab[52] = { + 0241,0,0242,0,0243,0,0244,0,0245,0,0246,0,0247,0,0250,0,0251,0,0252,0,0253,0, + 0254,0,0255,0,0256,0,0257,0,0260,0,0261,0,0262,0,0263,0,0264,0,0265,0,0266,0, + 0267,0,0270,0,0271,0,0272,0}; +char *letr[26] = { + "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" } ; +char *dot = { "." }; +yylex(){ + int c, ch; +restart: + c = getch(); + peekc = -1; + while( c == ' ' || c == '\t' ) c = getch(); + if(c == '\\'){ + getch(); + goto restart; + } + if( c<= 'z' && c >= 'a' ) { + /* look ahead to look for reserved words */ + peekc = getch(); + if( peekc >= 'a' && peekc <= 'z' ){ /* must be reserved word */ + if( c=='i' && peekc=='f' ){ c=_IF; goto skip; } + if( c=='w' && peekc=='h' ){ c=_WHILE; goto skip; } + if( c=='f' && peekc=='o' ){ c=_FOR; goto skip; } + if( c=='s' && peekc=='q' ){ c=SQRT; goto skip; } + if( c=='r' && peekc=='e' ){ c=_RETURN; goto skip; } + if( c=='b' && peekc=='r' ){ c=_BREAK; goto skip; } + if( c=='d' && peekc=='e' ){ c=_DEFINE; goto skip; } + if( c=='s' && peekc=='c' ){ c= SCALE; goto skip; } + if( c=='b' && peekc=='a' ){ c=BASE; goto skip; } + if( c=='i' && peekc == 'b'){ c=BASE; goto skip; } + if( c=='o' && peekc=='b' ){ c=OBASE; goto skip; } + if( c=='d' && peekc=='i' ){ c=FFF; goto skip; } + if( c=='a' && peekc=='u' ){ c=_AUTO; goto skip; } + if( c == 'l' && peekc=='e'){ c=LENGTH; goto skip; } + if( c == 'q' && peekc == 'u'){getout();} + /* could not be found */ + return( error ); + skip: /* skip over rest of word */ + peekc = -1; + while( (ch = getch()) >= 'a' && ch <= 'z' ); + peekc = ch; + return( c ); + } + + /* usual case; just one single letter */ + + yylval = (int) letr[c-'a']; + return( LETTER ); + } + if( c>= '0' && c <= '9' || c>= 'A' && c<= 'F' ){ + yylval = c; + return( DIGIT ); + } + switch( c ){ + case '.': return( DOT ); + case '=': + switch( peekc = getch() ){ + case '=': c=EQ; goto gotit; + case '+': c=EQPL; goto gotit; + case '-': c=EQMI; goto gotit; + case '*': c=EQMUL; goto gotit; + case '/': c=EQDIV; goto gotit; + case '%': c=EQREM; goto gotit; + case '^': c=EQEXP; goto gotit; + default: return( '=' ); + gotit: peekc = -1; return(c); + } + case '+': return( cpeek( '+', INCR, cpeek( '=', EQPL, '+') ) ); + case '-': return( cpeek( '-', DECR, cpeek( '=', EQMI, '-') ) ); + case '<': return( cpeek( '=', LE, '<' ) ); + case '>': return( cpeek( '=', GE, '>' ) ); + case '!': return( cpeek( '=', NE, '!' ) ); + case '/': + if((peekc = getch()) == '*'){ + peekc = -1; + while((getch() != '*') || ((peekc = getch()) != '/')); + peekc = -1; + goto restart; + } + else if (peekc == '=') { + c=EQDIV; + goto gotit; + } + else return(c); + case '*': + return( cpeek( '=', EQMUL, '*' ) ); + case '%': + return( cpeek( '=', EQREM, '%' ) ); + case '^': + return( cpeek( '=', EQEXP, '^' ) ); + case '"': + yylval = (int) str; + while((c=getch()) != '"'){*str++ = c; + if(str >= &string[999]){yyerror("string space exceeded"); + getout(); + } + } + *str++ = '\0'; + return(QSTR); + default: return( c ); + } +} + +cpeek( c, yes, no ){ + if( (peekc=getch()) != c ) return( no ); + else { + peekc = -1; + return( yes ); + } +} + +getch(){ + int ch; +loop: + ch = (peekc < 0) ? getc(in) : peekc; + peekc = -1; + if(ch != EOF)return(ch); + if(++ifile > sargc){ + if(ifile >= sargc+2)getout(); + in = stdin; + ln = 0; + goto loop; + } + fclose(in); + if((in = fopen(sargv[ifile],"r")) != NULL){ + ln = 0; + ss = sargv[ifile]; + goto loop; + } + yyerror("cannot open input file"); +} +# define b_sp_max 3000 +int b_space [ b_sp_max ]; +int * b_sp_nxt = { b_space }; + +int bdebug = 0; +bundle(a){ + int i, *p, *q; + + p = &a; + i = *p++; + q = b_sp_nxt; + if (bdebug) printf("bundle %d elements at %p\n", i, q); + while(i-- > 0){ + if( b_sp_nxt >= & b_space[b_sp_max] ) yyerror( "bundling space exceeded" ); + * b_sp_nxt++ = *p++; + } + * b_sp_nxt++ = 0; + yyval = (int) q; + return( (int) q ); +} + +routput(p) int *p; { + if( bdebug ) printf("routput(%p)\n", p ); + if( p >= &b_space[0] && p < &b_space[b_sp_max]){ + /* part of a bundle */ + while( *p != 0 ) routput( *p++ ); + } + else printf( "%s", (char*) p ); /* character string */ +} + +output( p ) int *p; { + routput( p ); + b_sp_nxt = & b_space[0]; + printf( "\n" ); + fflush(stdout); + cp = cary; + crs = rcrs; +} + +conout( p, s ) int *p; char *s; { + printf("["); + routput( p ); + printf("]s%s\n", s ); + fflush(stdout); + lev--; +} + +yyerror( s ) char *s; { + if(ifile > sargc)ss="teletype"; + printf("c[%s on line %d, %s]pc\n", s ,ln+1,ss); + fflush(stdout); + cp = cary; + crs = rcrs; + bindx = 0; + lev = 0; + b_sp_nxt = &b_space[0]; +} + +pp( s ) char *s; { + /* puts the relevant stuff on pre and post for the letter s */ + + bundle(3, "S", s, pre ); + pre = (int*) yyval; + bundle(4, post, "L", s, "s." ); + post = (int*) yyval; +} + +tp( s ) char *s; { /* same as pp, but for temps */ + bundle(3, "0S", s, pre ); + pre = (int*) yyval; + bundle(4, post, "L", s, "s." ); + post = (int*) yyval; +} + +yyinit(argc,argv) int argc; char *argv[];{ + signal( 2, SIG_IGN ); /* ignore all interrupts */ + sargv=argv; + sargc= -- argc; + if(sargc == 0)in=stdin; + else if((in = fopen(sargv[1],"r")) == NULL) { + yyerror("cannot open input file"); + in = stdin; + } + ifile = 1; + ln = 0; + ss = sargv[1]; +} +int *getout(){ + printf("q"); + fflush(stdout); + exit(0); +} + +int * +getf(p) char *p;{ + return (int*) &funtab[2 * (*p - 0141)]; +} + +int * +geta(p) char *p;{ + return (int*) &atab[2 * (*p - 0141)]; +} + +main(argc, argv) +char **argv; +{ + int p[2]; + + if (argc > 1 && *argv[1] == '-') { + if((argv[1][1] == 'd')||(argv[1][1] == 'c')){ + yyinit(--argc, ++argv); + yyparse(); + exit(0); + } + if(argv[1][1] != 'l'){ + printf("unrecognizable argument\n"); + fflush(stdout); + exit(0); + } + argv[1] = "/usr/share/misc/lib.b"; + } + pipe(p); + if (fork()==0) { + close(1); + dup(p[1]); + close(p[0]); + close(p[1]); + yyinit(argc, argv); + yyparse(); + exit(0); + } + close(0); + dup(p[0]); + close(p[0]); + close(p[1]); + execl("/bin/dc", "dc", "-", (char*) 0); + execl("/usr/bin/dc", "dc", "-", (char*) 0); +} diff --git a/src/cmd/cal.c b/src/cmd/cal.c new file mode 100644 index 0000000..0c8a96d --- /dev/null +++ b/src/cmd/cal.c @@ -0,0 +1,208 @@ +#include +#include + +char dayw[] = { + " S M Tu W Th F S" +}; +char *smon[]= { + "January", "February", "March", "April", + "May", "June", "July", "August", + "September", "October", "November", "December", +}; +char string[432]; + +main(argc, argv) +char *argv[]; +{ + register y, i, j; + int m; + + if(argc < 2) { + printf("usage: cal [month] year\n"); + exit(0); + } + if(argc == 2) + goto xlong; + +/* + * print out just month + */ + + m = number(argv[1]); + if(m<1 || m>12) + goto badarg; + y = number(argv[2]); + if(y<1 || y>9999) + goto badarg; + printf(" %s %u\n", smon[m-1], y); + printf("%s\n", dayw); + cal(m, y, string, 24); + for(i=0; i<6*24; i+=24) + pstr(string+i, 24); + exit(0); + +/* + * print out complete year + */ + +xlong: + y = number(argv[1]); + if(y<1 || y>9999) + goto badarg; + printf("\n\n\n"); + printf(" %u\n", y); + printf("\n"); + for(i=0; i<12; i+=3) { + for(j=0; j<6*72; j++) + string[j] = '\0'; + printf(" %.3s", smon[i]); + printf(" %.3s", smon[i+1]); + printf(" %.3s\n", smon[i+2]); + printf("%s %s %s\n", dayw, dayw, dayw); + cal(i+1, y, string, 72); + cal(i+2, y, string+23, 72); + cal(i+3, y, string+46, 72); + for(j=0; j<6*72; j+=72) + pstr(string+j, 72); + } + printf("\n\n\n"); + exit(0); + +badarg: + printf("Bad argument\n"); +} + +number(str) +char *str; +{ + register n, c; + register char *s; + + n = 0; + s = str; + while(c = *s++) { + if(c<'0' || c>'9') + return(0); + n = n*10 + c-'0'; + } + return(n); +} + +pstr(str, n) +char *str; +{ + register i; + register char *s; + + s = str; + i = n; + while(i--) + if(*s++ == '\0') + s[-1] = ' '; + i = n+1; + while(i--) + if(*--s != ' ') + break; + s[1] = '\0'; + printf("%s\n", str); +} + +char mon[] = { + 0, + 31, 29, 31, 30, + 31, 30, 31, 31, + 30, 31, 30, 31, +}; + +cal(m, y, p, w) +char *p; +{ + register d, i; + register char *s; + + s = p; + d = jan1(y); + mon[2] = 29; + mon[9] = 30; + + switch((jan1(y+1)+7-d)%7) { + + /* + * non-leap year + */ + case 1: + mon[2] = 28; + break; + + /* + * 1752 + */ + default: + mon[9] = 19; + break; + + /* + * leap year + */ + case 2: + ; + } + for(i=1; i 9) + *s = i/10+'0'; + s++; + *s++ = i%10+'0'; + s++; + if(++d == 7) { + d = 0; + s = p+w; + p = s; + } + } +} + +/* + * return day of the week + * of jan 1 of given year + */ + +jan1(yr) +{ + register y, d; + +/* + * normal gregorian calendar + * one extra day per four years + */ + + y = yr; + d = 4+y+(y+3)/4; + +/* + * julian calendar + * regular gregorian + * less three days per 400 + */ + + if(y > 1800) { + d -= (y-1701)/100; + d += (y-1601)/400; + } + +/* + * great calendar changeover instant + */ + + if(y > 1752) + d += 3; + + return(d%7); +} diff --git a/src/cmd/cat.c b/src/cmd/cat.c new file mode 100644 index 0000000..70e30bf --- /dev/null +++ b/src/cmd/cat.c @@ -0,0 +1,217 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +/* + * Concatenate files. + */ +#include +#include +#include +#include + +/* #define OPTSIZE BUFSIZ /* define this only if not 4.2 BSD or beyond */ + +int bflg, eflg, nflg, sflg, tflg, uflg, vflg; +int spaced, col, lno, inlin, ibsize, obsize; + +main(argc, argv) +char **argv; +{ + int fflg = 0; + register FILE *fi; + register c; + int dev, ino = -1; + struct stat statb; + int retval = 0; + + lno = 1; + for( ; argc>1 && argv[1][0]=='-'; argc--,argv++) { + switch(argv[1][1]) { + case 0: + break; + case 'u': + setbuf(stdout, (char *)NULL); + uflg++; + continue; + case 'n': + nflg++; + continue; + case 'b': + bflg++; + nflg++; + continue; + case 'v': + vflg++; + continue; + case 's': + sflg++; + continue; + case 'e': + eflg++; + vflg++; + continue; + case 't': + tflg++; + vflg++; + continue; + } + break; + } + if (fstat(fileno(stdout), &statb) == 0) { + statb.st_mode &= S_IFMT; + if (statb.st_mode!=S_IFCHR && statb.st_mode!=S_IFBLK) { + dev = statb.st_dev; + ino = statb.st_ino; + } +#ifndef OPTSIZE + obsize = statb.st_blksize; +#endif + } + else + obsize = 0; + if (argc < 2) { + argc = 2; + fflg++; + } + while (--argc > 0) { + if (fflg || (*++argv)[0]=='-' && (*argv)[1]=='\0') + fi = stdin; + else { + if ((fi = fopen(*argv, "r")) == NULL) { + perror(*argv); + retval = 1; + continue; + } + } + if (fstat(fileno(fi), &statb) == 0) { + if ((statb.st_mode & S_IFMT) == S_IFREG && + statb.st_dev==dev && statb.st_ino==ino) { + fprintf(stderr, "cat: input %s is output\n", + fflg?"-": *argv); + fclose(fi); + retval = 1; + continue; + } +#ifndef OPTSIZE + ibsize = statb.st_blksize; +#endif + } + else + ibsize = 0; + if (nflg||sflg||vflg) + copyopt(fi); + else if (uflg) { + while ((c = getc(fi)) != EOF) + putchar(c); + } else + retval |= fastcat(fileno(fi)); /* no flags specified */ + if (fi!=stdin) + fclose(fi); + else + clearerr(fi); /* reset sticky eof */ + if (ferror(stdout)) { + fprintf(stderr, "cat: output write error\n"); + retval = 1; + break; + } + } + exit(retval); +} + +copyopt(f) + register FILE *f; +{ + register int c; + +top: + c = getc(f); + if (c == EOF) + return; + if (c == '\n') { + if (inlin == 0) { + if (sflg && spaced) + goto top; + spaced = 1; + } + if (nflg && bflg==0 && inlin==0) + printf("%6d\t", lno++); + if (eflg) + putchar('$'); + putchar('\n'); + inlin = 0; + goto top; + } + if (nflg && inlin == 0) + printf("%6d\t", lno++); + inlin = 1; + if (vflg) { + if (tflg==0 && c == '\t') + putchar(c); + else { + if (c > 0177) { + printf("M-"); + c &= 0177; + } + if (c < ' ') + printf("^%c", c+'@'); + else if (c == 0177) + printf("^?"); + else + putchar(c); + } + } else + putchar(c); + spaced = 0; + goto top; +} + +fastcat(fd) +register int fd; +{ + register int buffsize, n, nwritten, offset; + register char *buff; + struct stat statbuff; + +#ifndef OPTSIZE + if (obsize) + buffsize = obsize; /* common case, use output blksize */ + else if (ibsize) + buffsize = ibsize; + else + buffsize = BUFSIZ; +#else + buffsize = OPTSIZE; +#endif + + if ((buff = malloc(buffsize)) == NULL) { + perror("cat: no memory"); + return (1); + } + + /* + * Note that on some systems (V7), very large writes to a pipe + * return less than the requested size of the write. + * In this case, multiple writes are required. + */ + while ((n = read(fd, buff, buffsize)) > 0) { + offset = 0; + do { + nwritten = write(fileno(stdout), &buff[offset], n); + if (nwritten <= 0) { + perror("cat: write error"); + exit(2); + } + offset += nwritten; + } while ((n -= nwritten) > 0); + } + + free(buff); + if (n < 0) { + perror("cat: read error"); + return (1); + } + return (0); +} diff --git a/src/cmd/cb.c b/src/cmd/cb.c new file mode 100644 index 0000000..a11944e --- /dev/null +++ b/src/cmd/cb.c @@ -0,0 +1,380 @@ +#include + +int slevel[10]; +int clevel = 0; +int spflg[20][10]; +int sind[20][10]; +int siflev[10]; +int sifflg[10]; +int iflev = 0; +int ifflg = -1; +int level = 0; +int ind[10] = { + 0,0,0,0,0,0,0,0,0,0 }; +int eflg = 0; +int paren = 0; +int pflg[10] = { + 0,0,0,0,0,0,0,0,0,0 }; +char lchar; +char pchar; +int aflg = 0; +int ct; +int stabs[20][10]; +int qflg = 0; +char *wif[] = { + "if",0}; +char *welse[] = { + "else",0}; +char *wfor[] = { + "for",0}; +char *wds[] = { + "case","default",0}; +int j = 0; +char string[200]; +char cc; +int sflg = 1; +int peek = -1; +int tabs = 0; +int lastchar; +int c; +int getstr(); + +putstr() +{ + if(j > 0){ + if(sflg != 0){ + ptabs(); + sflg = 0; + if(aflg == 1){ + aflg = 0; + if(tabs > 0)printf(" "); + } + } + string[j] = '\0'; + printf("%s",string); + j = 0; + } + else{ + if(sflg != 0){ + sflg = 0; + aflg = 0; + } + } +} + +main(argc, argv) + int argc; + char argv[]; +{ + while((c = getch()) != EOF){ + switch(c){ + case ' ': + case '\t': + if(lookup(welse) == 1){ + gotelse(); + if(sflg == 0 || j > 0)string[j++] = c; + putstr(); + sflg = 0; + continue; + } + if(sflg == 0 || j > 0)string[j++] = c; + continue; + case '\n': + if((eflg = lookup(welse)) == 1)gotelse(); + putstr(); + printf("\n"); + sflg = 1; + if(eflg == 1){ + pflg[level]++; + tabs++; + } + else + if(pchar == lchar) + aflg = 1; + continue; + case '{': + if(lookup(welse) == 1)gotelse(); + siflev[clevel] = iflev; + sifflg[clevel] = ifflg; + iflev = ifflg = 0; + clevel++; + if(sflg == 1 && pflg[level] != 0){ + pflg[level]--; + tabs--; + } + string[j++] = c; + putstr(); + getnl(); + putstr(); + printf("\n"); + tabs++; + sflg = 1; + if(pflg[level] > 0){ + ind[level] = 1; + level++; + slevel[level] = clevel; + } + continue; + case '}': + clevel--; + if((iflev = siflev[clevel]-1) < 0)iflev = 0; + ifflg = sifflg[clevel]; + if(pflg[level] >0 && ind[level] == 0){ + tabs -= pflg[level]; + pflg[level] = 0; + } + putstr(); + tabs--; + ptabs(); + if((peek = getch()) == ';'){ + printf("%c;",c); + peek = -1; + } + else printf("%c",c); + getnl(); + putstr(); + printf("\n"); + sflg = 1; + if(clevel < slevel[level])if(level > 0)level--; + if(ind[level] != 0){ + tabs -= pflg[level]; + pflg[level] = 0; + ind[level] = 0; + } + continue; + case '"': + case '\'': + string[j++] = c; + while((cc = getch()) != c){ + string[j++] = cc; + if(cc == '\\'){ + string[j++] = getch(); + } + if(cc == '\n'){ + putstr(); + sflg = 1; + } + } + string[j++] = cc; + if(getnl() == 1){ + lchar = cc; + peek = '\n'; + } + continue; + case ';': + string[j++] = c; + putstr(); + if(pflg[level] > 0 && ind[level] == 0){ + tabs -= pflg[level]; + pflg[level] = 0; + } + getnl(); + putstr(); + printf("\n"); + sflg = 1; + if(iflev > 0) + if(ifflg == 1){iflev--; + ifflg = 0; + } + else iflev = 0; + continue; + case '\\': + string[j++] = c; + string[j++] = getch(); + continue; + case '?': + qflg = 1; + string[j++] = c; + continue; + case ':': + string[j++] = c; + if(qflg == 1){ + qflg = 0; + continue; + } + if(lookup(wds) == 0){ + sflg = 0; + putstr(); + } + else{ + tabs--; + putstr(); + tabs++; + } + if((peek = getch()) == ';'){ + printf(";"); + peek = -1; + } + getnl(); + putstr(); + printf("\n"); + sflg = 1; + continue; + case '/': + string[j++] = c; + if((peek = getch()) != '*')continue; + string[j++] = peek; + peek = -1; + comment(); + continue; + case ')': + paren--; + string[j++] = c; + putstr(); + if(getnl() == 1){ + peek = '\n'; + if(paren != 0)aflg = 1; + else if(tabs > 0){ + pflg[level]++; + tabs++; + ind[level] = 0; + } + } + continue; + case '#': + string[j++] = c; + while((cc = getch()) != '\n')string[j++] = cc; + string[j++] = cc; + sflg = 0; + putstr(); + sflg = 1; + continue; + case '(': + string[j++] = c; + paren++; + if(lookup(wfor) == 1){ + while((c = getstr()) != ';'); + ct=0; +cont: + while((c = getstr()) != ')'){ + if(c == '(') ct++; + } + if(ct != 0){ + ct--; + goto cont; + } + paren--; + putstr(); + if(getnl() == 1){ + peek = '\n'; + pflg[level]++; + tabs++; + ind[level] = 0; + } + continue; + } + if(lookup(wif) == 1){ + putstr(); + stabs[clevel][iflev] = tabs; + spflg[clevel][iflev] = pflg[level]; + sind[clevel][iflev] = ind[level]; + iflev++; + ifflg = 1; + } + continue; + default: + string[j++] = c; + if(c != ',')lchar = c; + } + } +} + +ptabs() +{ + int i; + for(i=0; i < tabs; i++)printf("\t"); +} + +getch() +{ + if(peek < 0 && lastchar != ' ' && lastchar != '\t')pchar = lastchar; + lastchar = (peek<0) ? getc(stdin):peek; + peek = -1; + return(lastchar); +} + +lookup(tab) + char *tab[]; +{ + char r; + int l,kk,k,i; + if(j < 1)return(0); + kk=0; + while(string[kk] == ' ')kk++; + for(i=0; tab[i] != 0; i++){ + l=0; + for(k=kk;(r = tab[i][l++]) == string[k] && r != '\0';k++); + if(r == '\0' && (string[k] < 'a' || string[k] > 'z' || k >= j))return(1); + } + return(0); +} + +getstr() +{ + char ch; +beg: + if((ch = string[j++] = getch()) == '\\'){ + string[j++] = getch(); + goto beg; + } + if(ch == '\'' || ch == '"'){ + while((cc = string[j++] = getch()) != ch)if(cc == '\\')string[j++] = getch(); + goto beg; + } + if(ch == '\n'){ + putstr(); + aflg = 1; + goto beg; + } + else return(ch); +} + +gotelse() +{ + tabs = stabs[clevel][iflev]; + pflg[level] = spflg[clevel][iflev]; + ind[level] = sind[clevel][iflev]; + ifflg = 1; +} + +getnl() +{ + while((peek = getch()) == '\t' || peek == ' '){ + string[j++] = peek; + peek = -1; + } + if((peek = getch()) == '/'){ + peek = -1; + if((peek = getch()) == '*'){ + string[j++] = '/'; + string[j++] = '*'; + peek = -1; + comment(); + } + else string[j++] = '/'; + } + if((peek = getch()) == '\n'){ + peek = -1; + return(1); + } + return(0); +} + +comment() +{ + int i = j; + + while ((c = getch()) != EOF) { + string[j++] = c; + switch(c) { + case '/': + if (j > i + 1 && string[j-2] == '*') + return; + break; + case '\n': + putstr(); + sflg = 1; + break; + } + } +} diff --git a/src/cmd/cc/Makefile b/src/cmd/cc/Makefile new file mode 100644 index 0000000..ded7034 --- /dev/null +++ b/src/cmd/cc/Makefile @@ -0,0 +1,29 @@ +TOPSRC = $(shell cd ../../..; pwd) +include $(TOPSRC)/target.mk +#include $(TOPSRC)/cross.mk + +OBJS = cc.o + +CFLAGS += -Werror -Wall +CFLAGS += -DVERSSTR=\"1.0\" \ + -DSTDINC=\"/include\" \ + -DLIBDIR=\"/lib\" \ + -DLIBEXECDIR=\"/libexec\" \ + -DCRT0FILE=\"/lib/crt0.o\" \ + -DCRT0FILE_PROFILE=\"/lib/mcrt0.o\" + +all: cc + +cc: $(OBJS) + ${CC} ${LDFLAGS} -o cc.elf $(OBJS) ${LIBS} + ${OBJDUMP} -S cc.elf > cc.dis + ${SIZE} cc.elf + ${ELF2AOUT} cc.elf $@ && rm cc.elf + +clean: + rm -f *.o *.0 *.elf cc *.elf *.dis tags *~ + +install: all + install cc $(DESTDIR)/bin/ + install cc $(DESTDIR)/bin/scc + install cc $(DESTDIR)/bin/srcc diff --git a/src/cmd/cc/cc.1 b/src/cmd/cc/cc.1 new file mode 100644 index 0000000..23bb4dc --- /dev/null +++ b/src/cmd/cc/cc.1 @@ -0,0 +1,335 @@ +.\" $Id: cc.1,v 1.16 2010/04/05 14:24:06 reed Exp $ +.\" $NetBSD$ +.\" $OpenBSD$ +.\" +.\" Copyright (c) 2007 Jeremy C. Reed +.\" +.\" Permission to use, copy, modify, and/or distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR AND CONTRIBUTORS DISCLAIM +.\" ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +.\" WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL AUTHOR AND +.\" CONTRIBUTORS BE LIABLE FOR ANY SPECIAL, DIRECT, 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. +.\" +.Dd September 14, 2007 +.Dt CC 1 +.Os +.Sh NAME +.Nm cc +.Nd front-end to the C compiler +.Sh SYNOPSIS +.Nm +.Op Fl cEgkLMPOStvXx +.Op Fl fPIC +.Op Fl fpic +.Op Fl m Ns Ar option +.Op Fl nostartfiles +.Op Fl nostdinc +.Op Fl nostdlib +.Op Fl pg +.Op Fl pthread +.Op Fl static +.Op Fl B Ar prefix +.Op Fl D Ar macro[=value] +.Op Fl d Ar option +.Op Fl I Ar directory +.Op Fl include Ar path +.Op Fl isystem Ar path +.Op Fl o Ar outfile +.Op Fl Wl Ar flags +.Op Ar +.Sh DESCRIPTION +The +.Nm +utility provides a front-end to the +.Dq portable C compiler . +Multiple files may be given on the command line. +Unrecognized options are all sent directly to +.Xr ld 1 . +.Pp +.\" Brief description of its syntax: +Filenames that end with +.Sy \&.c +are passed via +.Xr cpp 1 +\(-> +.Xr ccom 1 +\(-> +.Xr as 1 +\(-> +.Xr ld 1 . +.Pp +Filenames that end with +.Sy \&.i +are passed via +.Xr ccom 1 +\(-> +.Xr as 1 +\(-> +.Xr ld 1 . +.Pp +Filenames that end with +.Sy \&.s +are passed via +.Xr as 1 +\(-> +.Xr ld 1 . +.Pp +Filenames that end with +.Sy \&.S +are passed via +.Xr cpp 1 +\(-> +.Xr as 1 +\(-> +.Xr ld 1 . +.Pp +Filenames that end with +.Sy \&.o +are passed directly to +.Xr ld 1 . +.Pp +.\" +The options are as follows: +.Bl -tag -width Ds +.It Fl B Ar prefix +Define alternate prefix path for +.Xr cpp 1 , +.Xr ccom 1 , +.Xr as 1 , +or +.Xr ld 1 +executables. +.\" TODO: provide an example of -B +.It Fl C +Passed to the +.Xr cpp 1 +preprocessor to not discard comments. +.It Fl c +Only compile or assemble and then stop. +Do not link. +The resulting object output is saved +as a filename with a +.Dq \&.o +suffix unless +.Fl o +option is used. +Note: cannot be combined with +.Fl o +if multiple files are given. +.It Fl D Ar macro[=value] +Passed to the +.Xr cpp 1 +preprocessor to define +.Ar macro . +.It Fl d Ar option +Passed to the +.Xr as 1 +assembler. +.\" TODO: what is as -dfoo for? +.It Fl E +Stop after preprocessing with +.Xr cpp 1 . +Do not compile, assemble, or link. +Output is sent to standard output unless the +.Fl o +option is used. +.It Fl fPIC +Generate PIC code. +.\" TODO: document about avoiding machine-specific maximum size? +.It Fl fpic +Tells C compiler to generate PIC code +and tells assembler that PIC code has been generated. +.\" TODO: document difference between PIC and pic +.\" other -f GCC compatibility flags are ignored for now +.It Fl g +Send +.Fl g +flag to +.Xr ccom 1 +to create debug output. +This unsets the +.Fl O +option. +.It Fl I Ar path +Passed to the +.Xr cpp 1 +preprocessor to add header search directory to override system defaults. +.It Fl include Ar file +Tells the +.Xr cpp 1 +preprocessor to include the +.Ar file +during preprocessing. +.It Fl isystem Ar path +Defines +.Ar path +as a system header directory for the +.Xr cpp 1 +preprocessor. +.It Fl k +Generate PIC code. +See +.Fl fpic +option. +.It Fl L +TODO +.It Fl M +Pass +.Fl M +flag to +.Xr cpp 1 +to generate dependencies for +.Xr make 1 . +.It Fl m Ns options +Target-dependent option. +.Bl -tag -width PowerPC +.It ARM +\-mlittle-endian \-mbig-endian \-mfpe=fpa \-mfpe=vpf \-msoft-float \-march=armv1 \-march=armv2 \-march=armv2a \-march=armv3 \-march=armv4 \-march=armv4t \-march=armv4tej \-march=armv5 \-march=armv6 \-march=armv6t2 \-march=armv6kz \-march=armv6k \-march=armv7 +.It HPPA +.It i386 +.It MIPS +\-mlittle-endian \-mbig-endian \-mhard-float \-msoft-float +.It PDP-10 +.It PowerPC +.It Sparc64 +.It VAX +.El +.It Fl nostartfiles +Do not link with the system startup files (crt0.c, etc.) +.It Fl nostdinc +Do not use the system include paths (/usr/include, etc.) +.It Fl nostdlib +Do not link with the system C library (libc). +.\" implies -nostartfiles ?? +.It Fl O +Enable optimizations. +Currently passes +.Fl xdeljumps +and +.Fl xtemps +to +.Xr ccom 1 . +Note: this is unset if the +.Fl g +option is used. +.It Fl o Ar outfile +Save result to +.Ar outfile . +.It Fl P +TODO +.\" TODO: what is this? +.\" TODO: Looks like it does cpp only, but I couldn't get it to work for me. +.It Fl pg +Enable profiling on the generated executable. +.It Fl pthread +Defines +.Sy _PTHREADS +preprocessor directive for +.Xr cpp 1 . +Uses +.Sy \-lpthread +for the +.Xr ld 1 +linker. +.It Fl S +Stop after compilation by +.Xr ccom 1 . +Do not assemble and do not link. +The resulting assembler-language output is saved +as a filename with a +.Dq \&.s +suffix unless the +.Fl o +option is used. +Note: cannot be combined with +.Fl o +if multiple files are given. +.It Fl static +Do not use dynamic linkage. +By default, it will link using the dynamic linker options +and/or shared objects for the platform. +.It Fl shared +Create a shared object of the result. Tells the linker not to +generate an executable. +.It Fl t +Passes +.Fl t +to +.Xr cpp 1 +for traditional C preprocessor syntax. +.It Fl U Ar macro +Passes to the +.Xr cpp 1 +preprocessor to remove the initial macro definition. +.It Fl v +Outputs the version of +.Nm +and shows what commands will be run with their command line arguments. +.It Fl Wl Ar flags +Options for the linker. +.\" what is ignored? llist? +.It Fl X +Don't remove temporary files on exit. +.It Fl x +May be used to give separate optimization flags to ccom, see +.Fl O +for options. +.It Fl x Ar c +Gcc compatibility option; specify that the language in use is +.Ar c . +.El +.Ss Predefined Macros +A few +macros are predefined by +.Nm +when sent to +.Xr cpp 1 . +.Bl -diag +.\" TODO: +.\" .It __ASSEMBLER__ +.\" Defined if suffix is .S -- why not with .s? what does this mean? +.It __PCC__ +Set to the major version of +.Xr pcc 1 . +These macros can be used to select code based on +.Xr pcc 1 +compatibility. +See the +.Fl v +option. +.It __PCC_MINOR__ +Set to the minor version. +.It __PCC_MINORMINOR__ +Set to the minor-minor version \(em the number after the minor version. +.It _PTHREADS +Defined when +.Fl pthread +switch is used. +.El +.Pp +Also system- and/or machine-dependent macros may also be predefined; +for example: +.Dv __NetBSD__ , +.Dv __ELF__ , +and +.Dv __i386__ . +.Sh SEE ALSO +.Xr as 1 , +.Xr ccom 1 , +.Xr cpp 1 , +.Xr ld 1 +.Sh HISTORY +The +.Nm +command comes from the original Portable C Compiler by S. C. Johnson, +written in the late 70's. +.Pp +This product includes software developed or owned by Caldera +International, Inc. diff --git a/src/cmd/cc/cc.c b/src/cmd/cc/cc.c new file mode 100644 index 0000000..b008e09 --- /dev/null +++ b/src/cmd/cc/cc.c @@ -0,0 +1,1423 @@ +/* + * Front-end to the C compiler. + * + * Brief description of its syntax: + * - Files that end with .c are passed via cpp->ccom->as->ld + * - Files that end with .i are passed via ccom->as->ld + * - Files that end with .s are passed as->ld + * - Files that end with .S are passed via cpp->as->ld + * - Files that end with .o are passed directly to ld + * - Multiple files may be given on the command line. + * - Unrecognized options are all sent directly to ld. + * -c or -S cannot be combined with -o if multiple files are given. + * + * This file should be rewritten readable. + * + * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code and documentation must retain the above + * copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditionsand the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed or owned by Caldera + * International, Inc. + * Neither the name of Caldera International, Inc. nor the names of other + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA + * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE + * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#ifdef CROSS +# include +# include +#else +# include +# include +#endif + +#define MKS(x) _MKS(x) +#define _MKS(x) #x + +/* + * Many specific definitions, should be declared elsewhere. + */ + +#ifndef STDINC +#define STDINC "/usr/include" +#endif + +#ifndef LIBDIR +#define LIBDIR "/usr/lib" +#endif + +#ifndef LIBEXECDIR +#define LIBEXECDIR "/usr/libexec" +#endif + +#ifndef PREPROCESSOR +#define PREPROCESSOR "cpp" +#endif + +#ifndef COMPILER +#define COMPILER "ccom" +#endif + +#ifndef ASSEMBLER +#define ASSEMBLER "as" +#endif + +#ifndef LINKER +#define LINKER "ld" +#endif + +#define MAXFIL 1000 +#define MAXLIB 1000 +#define MAXAV 1000 +#define MAXOPT 100 +char *tmp_as; +char *tmp_cpp; +char *outfile, *ermfile; +char *Bprefix(char *); +char *copy(char *, int); +char *setsuf(char *, char); +int getsuf(char *); +int main(int, char *[]); +void error(char *, ...); +void errorx(int, char *, ...); +int callsys(char [], char *[]); +int cunlink(char *); +void dexit(int); +void idexit(int); +char *gettmp(void); +void *ccmalloc(int size); +char *av[MAXAV]; +char *clist[MAXFIL]; +char *olist[MAXFIL]; +char *llist[MAXLIB]; +char *aslist[MAXAV]; +char *cpplist[MAXAV]; +char alist[20]; +char *xlist[100]; +int xnum; +char *mlist[100]; +char *flist[100]; +char *wlist[100]; +char *idirafter; +char *progname; +int nm; +int nf; +int nw; +int sspflag; +int dflag; +int pflag; +int sflag; +int cflag; +int eflag; +int gflag; +int rflag; +int vflag; +int tflag; +int Eflag; +int Oflag; +int kflag; /* generate PIC/pic code */ +#define F_PIC 1 +#define F_pic 2 +int Mflag; /* dependencies only */ +int pgflag; +int exfail; +int Xflag; +int Wallflag; +int Wflag; +int nostartfiles, Bstatic, shared; +int nostdinc, nostdlib; +int onlyas; +int pthreads; +int xcflag; +int ascpp; + +char *passp = "/bin/" PREPROCESSOR; +char *pass0 = LIBEXECDIR "/" COMPILER; +char *as = ASSEMBLER; +char *ld = LINKER; +char *Bflag; + +enum { + MODE_LCC, + MODE_PCC, + MODE_SMALLC, + MODE_SMALLERC, +} mode; + +/* common cpp predefines */ +char *cppadd[] = { "-D__LCC__", "-D__unix__", "-D__BSD__", "-D__RETROBSD__", NULL }; + +#ifdef __mips__ +# define CPPMDADD { "-D__mips__", NULL, } +#endif +#ifdef __i386__ +# define CPPMDADD { "-D__i386__", NULL, } +#endif + +#ifdef DYNLINKER +char *dynlinker[] = DYNLINKER; +#endif +#ifdef CRT0FILE +char *crt0file = CRT0FILE; +#endif +#ifdef CRT0FILE_PROFILE +char *crt0file_profile = CRT0FILE_PROFILE; +#endif +#ifdef STARTFILES +char *startfiles[] = STARTFILES; +char *endfiles[] = ENDFILES; +#endif +#ifdef STARTFILES_T +char *startfiles_T[] = STARTFILES_T; +char *endfiles_T[] = ENDFILES_T; +#endif +#ifdef STARTFILES_S +char *startfiles_S[] = STARTFILES_S; +char *endfiles_S[] = ENDFILES_S; +#endif +#ifdef MULTITARGET +char *mach = DEFMACH; +struct cppmd { + char *mach; + char *cppmdadd[MAXCPPMDARGS]; +}; + +struct cppmd cppmds[] = CPPMDADDS; +#else +char *cppmdadd[] = CPPMDADD; +#endif +#ifdef LIBCLIBS +char *libclibs[] = LIBCLIBS; +#else +char *libclibs[] = { "-lc", NULL }; +#endif +#ifdef LIBCLIBS_PROFILE +char *libclibs_profile[] = LIBCLIBS_PROFILE; +#else +char *libclibs_profile[] = { "-lc_p", NULL }; +#endif +#ifndef STARTLABEL +#define STARTLABEL "_start" +#endif +char *incdir = STDINC; +char *libdir = LIBDIR; +char *altincdir; +char *pccincdir; +char *pcclibdir; + +/* handle gcc warning emulations */ +struct Wflags { + char *name; + int flags; +#define INWALL 1 +#define NEGATIVE 2 +} Wflags[] = { + { "-Wtruncate", 0 }, + { "-Wno-truncate", NEGATIVE }, + { "-Werror", 0 }, + { "-Wshadow", 0 }, + { "-Wno-shadow", NEGATIVE }, + { "-Wpointer-sign", INWALL }, + { "-Wno-pointer-sign", NEGATIVE }, + { "-Wsign-compare", 0 }, + { "-Wno-sign-compare", NEGATIVE }, + { "-Wunknown-pragmas", INWALL }, + { "-Wno-unknown-pragmas", NEGATIVE }, + { "-Wunreachable-code", 0 }, + { "-Wno-unreachable-code", NEGATIVE }, + { 0, 0 }, +}; + +#define SZWFL (sizeof(Wflags)/sizeof(Wflags[0])) + +#ifndef USHORT +/* copied from mip/manifest.h */ +#define USHORT 5 +#define INT 6 +#define UNSIGNED 7 +#endif + +/* + * Wide char defines. + */ +#define WCT "short unsigned int" +#define WCM "65535U" +#define WCS 2 + +#ifdef GCC_COMPAT +#ifndef REGISTER_PREFIX +#define REGISTER_PREFIX "" +#endif +#ifndef USER_LABEL_PREFIX +#define USER_LABEL_PREFIX "" +#endif +#endif + +#ifndef PCC_PTRDIFF_TYPE +#define PCC_PTRDIFF_TYPE "long int" +#endif + +/* + * Copy src to string dst of size siz. At most siz-1 characters + * will be copied. Always NUL terminates (unless siz == 0). + * Returns strlen(src); if retval >= siz, truncation occurred. + */ +size_t +strlcpy(char *dst, const char *src, size_t siz) +{ + char *d = dst; + const char *s = src; + size_t n = siz; + + /* Copy as many bytes as will fit */ + if (n != 0 && --n != 0) { + do { + if ((*d++ = *s++) == 0) + break; + } while (--n != 0); + } + + /* Not enough room in dst, add NUL and traverse rest of src */ + if (n == 0) { + if (siz != 0) + *d = '\0'; /* NUL-terminate dst */ + while (*s++) + ; + } + + return(s - src - 1); /* count does not include NUL */ +} + +/* + * Appends src to string dst of size siz (unlike strncat, siz is the + * full size of dst, not space left). At most siz-1 characters + * will be copied. Always NUL terminates (unless siz <= strlen(dst)). + * Returns strlen(initial dst) + strlen(src); if retval >= siz, + * truncation occurred. + */ +size_t +strlcat(char *dst, const char *src, size_t siz) +{ + char *d = dst; + const char *s = src; + size_t n = siz; + size_t dlen; + + /* Find the end of dst and adjust bytes left but don't go past end */ + while (n-- != 0 && *d != '\0') + d++; + dlen = d - dst; + n = siz - dlen; + + if (n == 0) + return(dlen + strlen(s)); + while (*s != '\0') { + if (n != 1) { + *d++ = *s; + n--; + } + s++; + } + *d = '\0'; + + return(dlen + (s - src)); /* count does not include NUL */ +} + +void +usage() +{ + printf("Usage: %s [options] file...\n", progname); + printf("Options:\n"); + printf(" -h Display this information\n"); + printf(" --version Display compiler version information\n"); + printf(" -c Compile and assemble, but do not link\n"); + printf(" -S Compile only; do not assemble or link\n"); + printf(" -E Preprocess only; do not compile, assemble or link\n"); + printf(" -P Preprocess to .i output file\n"); + printf(" -o Place the output into \n"); + printf(" -O, -O0 Enable, disable optimization\n"); + printf(" -g Create debug output\n"); + printf(" -v Display the programs invoked by the compiler\n"); + if (mode == MODE_LCC || mode == MODE_PCC) { + printf(" -k Generate position-independent code\n"); + printf(" -Wall Enable gcc-compatible warnings\n"); + printf(" -WW Enable all warnings\n"); + printf(" -p, -pg Generate profiled code\n"); + printf(" -r Generate relocatable code\n"); + } + printf(" -t Use traditional preprocessor syntax\n"); + printf(" -C
\n",argv[0]); + return(10); + } + addr = atoi(argv[1]); + printf("Byte at address %d: %d\n",addr,rdglob(addr)); + return 0; +} diff --git a/src/cmd/gtest/globwrite.c b/src/cmd/gtest/globwrite.c new file mode 100644 index 0000000..f5c96ca --- /dev/null +++ b/src/cmd/gtest/globwrite.c @@ -0,0 +1,16 @@ + +#include +#include + +int main(int argc, char *argv[]) +{ + int addr,val; + if(argc != 3) + { + printf("Usage: %s
\n",argv[0]); + return(10); + } + addr = atoi(argv[1]); + val = atoi(argv[2]); + wrglob(addr,val&0xFF); +} diff --git a/src/cmd/head.c b/src/cmd/head.c new file mode 100644 index 0000000..4d72647 --- /dev/null +++ b/src/cmd/head.c @@ -0,0 +1,79 @@ +/* + * head - give the first few lines of a stream or of each of a set of files + * + * Bill Joy UCB August 24, 1977 + * + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include +#include + +int linecnt = 10; +int argc; + +main(Argc, argv) + int Argc; + char *argv[]; +{ + register int argc; + char *name; + register char *argp; + static int around; + + Argc--, argv++; + argc = Argc; + do { + while (argc > 0 && argv[0][0] == '-') { + linecnt = getnum(argv[0] + 1); + argc--, argv++, Argc--; + } + if (argc == 0 && around) + break; + if (argc > 0) { + close(0); + if (freopen(argv[0], "r", stdin) == NULL) { + perror(argv[0]); + exit(1); + } + name = argv[0]; + argc--, argv++; + } else + name = 0; + if (around) + putchar('\n'); + around++; + if (Argc > 1 && name) + printf("==> %s <==\n", name); + copyout(linecnt); + fflush(stdout); + } while (argc > 0); +} + +copyout(cnt) + register int cnt; +{ + register int c; + char lbuf[BUFSIZ]; + + while (cnt > 0 && fgets(lbuf, sizeof lbuf, stdin) != 0) { + printf("%s", lbuf); + fflush(stdout); + cnt--; + } +} + +getnum(cp) + register char *cp; +{ + register int i; + + for (i = 0; *cp >= '0' && *cp <= '9'; cp++) + i *= 10, i += *cp - '0'; + if (*cp) { + fprintf(stderr, "Badly formed number\n"); + exit(1); + } + return (i); +} diff --git a/src/cmd/hostid.c b/src/cmd/hostid.c new file mode 100644 index 0000000..372e4b1 --- /dev/null +++ b/src/cmd/hostid.c @@ -0,0 +1,58 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include +#include +#include +#include +#include +#include +#include +#if HAVE_NET +#include +#include +#endif + +main(argc, argv) + int argc; + char **argv; +{ + register char *id; + u_long addr; + long hostid; + struct hostent *hp; + + if (argc < 2) { + printf("0x%lx\n", gethostid()); + exit(0); + } + + id = argv[1]; +#if HAVE_NET + if (hp = gethostbyname(id)) { + bcopy(hp->h_addr, &addr, sizeof(addr)); + hostid = addr; + } else +#endif + if (index(id, '.')) { + if ((hostid = inet_addr(id)) == -1L) + usage(); + } else { + if (id[0] == '0' && (id[1] == 'x' || id[1] == 'X')) + id += 2; + if (sscanf(id, "%lx", &hostid) != 1) + usage(); + } + + if (sethostid(hostid) < 0) + err(1, "sethostid"); + exit(0); +} + +usage() +{ + errx (1,"usage: [hexnum or internet name/address]"); +/* NOTREACHED */ +} diff --git a/src/cmd/hostname/Makefile b/src/cmd/hostname/Makefile new file mode 100644 index 0000000..bf3d3bc --- /dev/null +++ b/src/cmd/hostname/Makefile @@ -0,0 +1,40 @@ +# +# Public Domain. 1995/03/13 - Steven Schultz +# +TOPSRC = $(shell cd ../../..; pwd) +include $(TOPSRC)/target.mk + +CFLAGS += -Werror + +SRCS = hostname.c +OBJS = hostname.o +MAN = hostname.0 + +all: hostname ${MAN} + +hostname: ${OBJS} + ${CC} ${LDFLAGS} -o hostname.elf ${OBJS} ${LIBS} + ${OBJDUMP} -S hostname.elf > hostname.dis + ${SIZE} hostname.elf + ${ELF2AOUT} hostname.elf $@ && rm hostname.elf + +.SUFFIXES: .0 .1 + +.1.0: + ${MANROFF} $*.1 > $@ + +clean: + rm -f *.o *.elf ${MAN} hostname *.elf *.dis tags *~ + +depend: ${SRCS} + mkdep ${CFLAGS} ${SRCS} + +install: all + install hostname ${DESTDIR}/bin/ + cp hostname.0 ${DESTDIR}/share/man/cat1/ + +lint: ${SRCS} + lint -hax ${SRCS} + +tags: ${SRCS} + ctags ${SRCS} diff --git a/src/cmd/hostname/hostname.1 b/src/cmd/hostname/hostname.1 new file mode 100644 index 0000000..731d719 --- /dev/null +++ b/src/cmd/hostname/hostname.1 @@ -0,0 +1,69 @@ +.\" Copyright (c) 1983, 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. +.\" +.\" @(#)hostname.1 8.1 (Berkeley) 5/31/93 +.\" hostname.1,v 1.2 1994/09/24 02:55:40 davidg Exp +.\" hostname.1,v 1.2.1 29/1/95 Robin Birch +.\" +.TH HOSTNAME 1 "January 29, 1995" +.SH NAME +hostname \- set or print name of current host system +.SH SYNOPSIS +.B hostname +[ +.B \-s +] [ +.B nameofhost +] +.PP +.SH DESCRIPTION +.I Hostname +prints the name of the current host. The super-user can +set the hostname by supplying an argument; this is usually done in the +network initialization script +.I /etc/netstart , +normally run at boot +time. +.PP +Options: +.TP +.B \-\^s +Trims off any domain information from the printed +name. +.br +.sp +.SH SEE ALSO +gethostname(2), sethostname(2) +.SH HISTORY +The +.I hostname +command appeared in +BSD 4.2 . diff --git a/src/cmd/hostname/hostname.c b/src/cmd/hostname/hostname.c new file mode 100644 index 0000000..3a87582 --- /dev/null +++ b/src/cmd/hostname/hostname.c @@ -0,0 +1,73 @@ +/* + * 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. + */ +#include +#include +#include +#include + +int +main(argc,argv) + int argc; + char *argv[]; +{ + extern int optind; + int ch, sflag; + char *p, hostname[MAXHOSTNAMELEN]; + + sflag = 0; + while ((ch = getopt(argc, argv, "s")) != EOF) + switch (ch) { + case 's': + sflag = 1; + break; + case '?': + default: + (void)fprintf(stderr, + "usage: hostname [-s] [hostname]\n"); + exit(1); + } + argc -= optind; + argv += optind; + + if (*argv) { + if (sethostname(*argv, strlen(*argv))) + err(1, "sethostname"); + } else { + if (gethostname(hostname, sizeof(hostname))) + err(1, "gethostname"); + if (sflag && (p = strchr(hostname, '.'))) + *p = '\0'; + (void)printf("%s\n", hostname); + } + exit(0); +} diff --git a/src/cmd/id/Makefile b/src/cmd/id/Makefile new file mode 100644 index 0000000..f395d5f --- /dev/null +++ b/src/cmd/id/Makefile @@ -0,0 +1,47 @@ +# +# 1997/6/25 - Steven Schultz +# +TOPSRC = $(shell cd ../../..; pwd) +include $(TOPSRC)/target.mk + +CFLAGS += -Werror + +SRCS = id.c +OBJS = id.o +MAN = id.0 groups.0 whoami.0 + +all: id ${MAN} + install -c groups.sh groups + install -c whoami.sh whoami + +id: ${OBJS} + ${CC} ${LDFLAGS} -o id.elf ${OBJS} ${LIBS} + ${OBJDUMP} -S id.elf > id.dis + ${SIZE} id.elf + ${ELF2AOUT} id.elf $@ && rm id.elf + +.SUFFIXES: .0 .1 + +.1.0: + ${MANROFF} $*.1 > $@ + +clean: + rm -f *.o *.elf ${MAN} id groups whoami *.elf *.dis tags *~ + +depend: ${SRCS} + mkdep ${CFLAGS} ${SRCS} + +install: all + cp ${MAN} ${DESTDIR}/share/man/cat1/ + install id ${DESTDIR}/bin/id + install groups.sh ${DESTDIR}/bin/groups + install whoami.sh ${DESTDIR}/bin/whoami + +lint: ${SRCS} + lint -hax ${SRCS} + +tags: ${SRCS} + ctags ${SRCS} + +# DO NOT DELETE THIS LINE -- mkdep uses it. +# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY. diff --git a/src/cmd/id/groups.1 b/src/cmd/id/groups.1 new file mode 100644 index 0000000..4f13869 --- /dev/null +++ b/src/cmd/id/groups.1 @@ -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. +.\" +.\" @(#)groups.1 8.1.1 (2.11BSD) 1997/6/25 +.\" +.TH GROUPS 1 "June 25, 1997" +.UC 4 +.SH NAME +groups \- show group memberships +.SH SYNOPSIS +.B groups [\fIuser\fP] +.SH DESCRIPTION +The +.B groups +utility has been obsoleted by the +id(1) +utility, and is equivalent to ``\fBid \-Gn\fP [\fIuser\fP]''. +The command +.br +``\fBid \-p\fP'' +is suggested for normal interactive use. +.PP +The +.B groups +utility displays the groups to which you (or the optionally specified user) +belong. +.PP +The +.B groups +utility exits 0 on success, and >0 if an error occurs. +.SH SEE ALSO +id(1) diff --git a/src/cmd/id/groups.sh b/src/cmd/id/groups.sh new file mode 100644 index 0000000..e29ed90 --- /dev/null +++ b/src/cmd/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/src/cmd/id/id.1 b/src/cmd/id/id.1 new file mode 100644 index 0000000..c6a3af7 --- /dev/null +++ b/src/cmd/id/id.1 @@ -0,0 +1,135 @@ +.\" 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 +.\" 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.2.1 (2.11BSD) 1997/6/25 +.\" +.TH ID 1 "June 25, 1997" +.UC 4 +.SH NAME +id \- return user identity +.SH SYNOPSIS +\fBid\fP [\fIuser\fP] +.br +.B id \-G +[\fB\-n\fP] +[\fIuser\fP] +.br +.B id \-g +[\fB\-nr\fP] +[\fIuser\fP] +.br +.B id \-p +.br +.B id \-u +[\fB\-nr\fP] +[\fIuser\fP] +.SH DESCRIPTION +The +.B 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 +.I 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: +.TP 10 +.B \-G +Display the different group IDs (effective, real and supplementary) +as white-space separated numbers, in no particular order. +.TP 10 +.B \-g +Display the effective group ID as a number. +.TP 10 +.B \-n +Display the name of the user or group ID for the +\fB\-G\P, \fB\-g\fP and \fB\-u\fP +options instead of the number. +If any of the ID numbers cannot be mapped into names, the number will be +displayed as usual. +.TP 10 +.B \-p +Make the output human-readable. +If the user name returned by +getlogin(2) +is different from the login name referenced by the user ID, the name +returned by +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. +.TP 10 +.B \-r +Display the real ID for the \fB\-g\fP and \fB\-u\fP +options instead of the effective ID. +.TP 10 +.B \-u +Display the effective user ID as a number. +.PP +The +.B id +utility exits 0 on success, and >0 if an error occurs. +.SH SEE ALSO +who(1) +.SH STANDARDS +The +.B id +function is expected to conform to +IEEE Std1003.2 (``POSIX''). +.SH HISTORY +The +historic +groups(1) command is equivalent to +``\fBid \-Gn\fP [\fBuser\fP]''. +.PP +The +historic +whoami(1) +command is equivalent to +``\fBid \-un\fP''. +.PP +The +.B id +command first appeared in 4.4BSD. diff --git a/src/cmd/id/id.c b/src/cmd/id/id.c new file mode 100644 index 0000000..bbbd8f8 --- /dev/null +++ b/src/cmd/id/id.c @@ -0,0 +1,312 @@ +/*- + * 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. + */ +#include + +#include +#include +#include +#include +#include +#include +#include + +#define __P(protos) () + +void current __P((void)); +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(1, "getlogin"); + + 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); + } + ngroups = getgroups(NGROUPS, groups); + if (ngroups > 0) + 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; +{ + struct group *gr; + gid_t groups[NGROUPS + 1]; + int cnt, id, lastid, ngroups; + char *fmt; + + id = pw->pw_uid; + (void)printf("uid=%u(%s)", id, pw->pw_name); + (void)printf(" gid=%u", pw->pw_gid); + if ((gr = getgrgid(pw->pw_gid)) != NULL) + (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); + errx(1, "%s: No such user", u); +} + +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/src/cmd/id/whoami.1 b/src/cmd/id/whoami.1 new file mode 100644 index 0000000..f34f826 --- /dev/null +++ b/src/cmd/id/whoami.1 @@ -0,0 +1,59 @@ +.\" 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.1 (2.11BSD) 1997/6/25 +.\" +.TH WHOAMI 1 "June 25, 1997" +.UC 4 +.SH NAME +whoami \- display effective user id +.SH SYNOPSIS +.B whoami +.SH DESCRIPTION +The +.B whoami +utility has been obsoleted by the +id(1) +utility, and is equivalent to +``\fBid \-un\fP''. +The command +``\fBid \-p\fP'' +is suggested for normal interactive use. +.PP +The +.B whoami +utility displays your effective user ID as a name. +.PP +The +.B whoami +utility exits 0 on success, and >0 if an error occurs. +.SH SEE ALSO +id(1) diff --git a/src/cmd/id/whoami.sh b/src/cmd/id/whoami.sh new file mode 100644 index 0000000..372b7da --- /dev/null +++ b/src/cmd/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/src/cmd/init/Makefile b/src/cmd/init/Makefile new file mode 100644 index 0000000..1bde313 --- /dev/null +++ b/src/cmd/init/Makefile @@ -0,0 +1,39 @@ +TOPSRC = $(shell cd ../../..; pwd) +include $(TOPSRC)/target.mk + +CFLAGS += -Wall -Werror + +SRCS = init.c +OBJS = init.o +MAN = init.0 +MANSRC = init.8 + +all: init init.0 + +init: ${OBJS} + ${CC} ${LDFLAGS} -o init.elf ${OBJS} -lc + ${OBJDUMP} -S init.elf > init.dis + ${SIZE} init.elf + ${ELF2AOUT} init.elf $@ && rm init.elf + +init.0: ${MANSRC} + ${MANROFF} ${MANSRC} > ${MAN} + +clean: + rm -f *.o *~ *.elf *.dis ${MAN} init tags + +depend: ${SRCS} + mkdep ${CFLAGS} ${SRCS} + +install: all + cp ${MAN} ${DESTDIR}/share/man/cat8/ + install -m 700 init ${DESTDIR}/sbin/init + +lint: ${SRCS} + lint -hax ${SRCS} + +tags: ${SRCS} + ctags ${SRCS} + +# DO NOT DELETE THIS LINE -- mkdep uses it. +# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY. diff --git a/src/cmd/init/init.8 b/src/cmd/init/init.8 new file mode 100644 index 0000000..22ee348 --- /dev/null +++ b/src/cmd/init/init.8 @@ -0,0 +1,144 @@ +.\" Copyright (c) 1980 Regents of the University of California. +.\" All rights reserved. The Berkeley software License Agreement +.\" specifies the terms and conditions for redistribution. +.\" +.\" @(#)init.8 6.2.1 (2.11BSD) 1996/11/27 +.\" +.TH INIT 8 "November 27, 1996" +.UC 4 +.SH NAME +init \- process control initialization +.SH SYNOPSIS +.B /etc/init +.SH DESCRIPTION +.I Init +is invoked inside UNIX as the last step in the boot procedure. +It normally then runs the automatic reboot sequence as described in +.IR reboot (8), +and if this succeeds, begins multi-user operation. +If the reboot fails, it commences single user operation by giving +the super-user a shell on the console. It is possible to pass parameters +from the boot program to +.I init +so that single user operation is commenced immediately. +When such single user operation is terminated by killing the single-user +shell (i.e. by hitting ^D), +.I init +runs +.I /etc/rc +without the reboot parameter. +This command file +performs housekeeping operations +such as removing temporary files, +mounting file systems, and starting +daemons. +.PP +In multi-user operation, +.I init's +role is to create a process for each +terminal port on which a user may log in. +To begin such operations, it reads the file +.I /etc/ttys +and +executes a command for each terminal specified in the file. +This command will usually be +.IR /usr/libexec/getty . +.I Getty +opens and initializes the terminal line, +reads the user's name and invokes +.I login +to log in the user and execute the Shell. +.PP +Ultimately the Shell will terminate +because of an end-of-file either +typed explicitly or generated as a result of hanging up. +The main path of +.IR init , +which has been waiting +for such an event, +wakes up and removes the appropriate entry from the +file +.IR utmp , +which records current users, and +makes an entry in the +.IR wtmp , +file which maintains a history +of logins and logouts. +The +.I wtmp +entry is made only if a user logged in successfully on the line. +Then the appropriate terminal is reopened and +.I getty +is +reinvoked. +.PP +.I Init +catches the +.I hangup +signal (signal SIGHUP) and interprets it to mean that +the file +.I /etc/ttys +should be read again. +The Shell process on each line which used to be active +in +.I ttys +but is no longer there is terminated; +a new process is created for each added line; +lines unchanged in the file are undisturbed. +Thus it is possible to drop or add terminal lines without +rebooting the system by changing the +.I ttys +file and sending a +.I hangup +signal to the +.I init +process: use `kill \-HUP 1.' +.PP +.I Init +will terminate multi-user operations and resume single-user mode +if sent a terminate (TERM) signal, i.e. ``kill \-TERM 1''. +If there are processes outstanding which are deadlocked (due to +hardware or software failure), +.I init +will not wait for them all to die (which might take forever), but +will time out after 30 seconds and print a warning message. +.PP +.I Init +will cease creating new +.IR getty 's +and allow the system to slowly die away, if it is sent a terminal stop (TSTP) +signal, i.e. ``kill \-TSTP 1''. A later hangup will resume full +multi-user operations, or a terminate will initiate a single user shell. +This hook is used by +.IR reboot (8) +and +.IR halt (8). +.PP +.I Init's +role is so critical that if it dies, the system will reboot itself +automatically. +If, at bootstrap time, the +.I init +process cannot be located, the system will loop in user mode at location +0x13. +.SH DIAGNOSTICS +\fB/usr/libexec/getty\fP \fIgettyargs\fP\fB failing, sleeping\fP. +A process being started to service a line is exiting quickly +each time it is started. +This is often caused by a ringing or noisy terminal line. +.I Init will sleep for 30 seconds, then continue trying to start the process. +.LP +\fBWARNING: Something is hung (wont die); ps axl advised\fR. A process +is hung and could not be killed when the system was shutting down. +This is usually caused by a process +which is stuck in a device driver due to a persistent device error condition. +.SH FILES +/dev/console, +/dev/tty*, +/var/run/utmp, +/usr/adm/wtmp, +/etc/ttys, +/etc/rc +.SH "SEE ALSO" +login(1), kill(1), sh(1), ttys(5), crash(8), getty(8), rc(8), reboot(8), +halt(8), shutdown(8) diff --git a/src/cmd/init/init.c b/src/cmd/init/init.c new file mode 100644 index 0000000..f08015a --- /dev/null +++ b/src/cmd/init/init.c @@ -0,0 +1,732 @@ +/* + * Copyright (c) 1980,1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//#undef KERN_SECURELVL + +#define LINSIZ sizeof(wtmp.ut_line) +#define CMDSIZ 200 /* max string length for getty or window command*/ +#define SCPYN(a, b) strncpy(a, b, sizeof(a)) +#define SCMPN(a, b) strncmp(a, b, sizeof(a)) + +char shell[] = _PATH_BSHELL; +char minus[] = "-"; +char runc[] = "/etc/rc"; +char utmpf[] = _PATH_UTMP; +char wtmpf[] = _PATH_WTMP; +char ctty[] = _PATH_CONSOLE; + +void merge (int signum); + +struct utmp wtmp; +struct tab +{ + char line[LINSIZ]; + char comn[CMDSIZ]; + char xflag; + int pid; + int wpid; /* window system pid for SIGHUP */ + char wcmd[CMDSIZ]; /* command to start window system process */ + time_t gettytime; + int gettycnt; + time_t windtime; + int windcnt; + struct tab *next; +} *itab; + +int fi; +int mergflag; +char tty[20]; +jmp_buf sjbuf, shutpass; +time_t time0; + +void reset(); +void setsecuritylevel(); +int getsecuritylevel(); +extern int errno; + +struct sigvec rvec = { reset, sigmask (SIGHUP), 0 }; + +jmp_buf idlebuf; + +/* + * Catch a SIGSYS signal. + * + * These may arise if a system does not support sysctl. + * We tolerate up to 25 of these, then throw in the towel. + */ +void +badsys (sig) + int sig; +{ + static int badcount = 0; + + if (badcount++ < 25) + return; + syslog(LOG_EMERG, "fatal signal: %d", sig); + sleep(30); + _exit(sig); +} + +void +idlehup (sig) + int sig; +{ + + longjmp (idlebuf, 1); +} + +/* + * Remove utmp entry. + */ +void +rmut(p) + register struct tab *p; +{ + register int f; + int found = 0; + static unsigned utmpsize; + static struct utmp *utmp; + register struct utmp *u; + int nutmp; + struct stat statbf; + + f = open(utmpf, O_RDWR); + if (f >= 0) { + fstat(f, &statbf); + if (utmpsize < statbf.st_size) { + utmpsize = statbf.st_size + 10 * sizeof(struct utmp); + if (utmp) + utmp = (struct utmp *)realloc(utmp, utmpsize); + else + utmp = (struct utmp *)malloc(utmpsize); + if (!utmp) + syslog(LOG_ERR, "utmp malloc failed"); + } + if (statbf.st_size && utmp) { + nutmp = read(f, utmp, (int)statbf.st_size); + nutmp /= sizeof(struct utmp); + for (u = utmp ; u < &utmp[nutmp] ; u++) { + if (SCMPN(u->ut_line, p->line) || + u->ut_name[0]==0) + continue; + lseek(f, ((long)u)-((long)utmp), L_SET); + SCPYN(u->ut_name, ""); + SCPYN(u->ut_host, ""); + time(&u->ut_time); + write(f, (char *)u, sizeof(*u)); + found++; + } + } + close(f); + } + if (found) { + f = open(wtmpf, O_WRONLY|O_APPEND); + if (f >= 0) { + SCPYN(wtmp.ut_line, p->line); + SCPYN(wtmp.ut_name, ""); + SCPYN(wtmp.ut_host, ""); + time(&wtmp.ut_time); + write(f, (char *)&wtmp, sizeof(wtmp)); + close(f); + } + /* + * After a proper login force reset + * of error detection code in dfork. + */ + p->gettytime = 0; + p->windtime = 0; + } +} + +void +idle (sig) + int sig; +{ + register struct tab *p; + register int pid; + + signal (SIGHUP, idlehup); + for (;;) { + if (setjmp(idlebuf)) + return; + pid = wait((int *) 0); + if (pid == -1) { + sigpause(0L); + continue; + } + for (p=itab; p; p=p->next) { + /* if window system dies, mark it for restart */ + if (p->wpid == pid) + p->wpid = -1; + if (p->pid == pid) { + rmut(p); + p->pid = -1; + } + } + } +} + +void +term(p) + register struct tab *p; +{ + + if (p->pid != 0) { + rmut(p); + kill(p->pid, SIGKILL); + } + p->pid = 0; + /* send SIGHUP to get rid of connections */ + if (p->wpid > 0) + kill(p->wpid, SIGHUP); +} + +int +shutend() +{ + register int i, f; + + signal(SIGALRM, SIG_DFL); + for (i = 0; i < 10; i++) + close(i); + f = open(wtmpf, O_WRONLY|O_APPEND); + if (f >= 0) { + SCPYN(wtmp.ut_line, "~"); + SCPYN(wtmp.ut_name, "shutdown"); + SCPYN(wtmp.ut_host, ""); + time(&wtmp.ut_time); + write(f, (char *)&wtmp, sizeof(wtmp)); + close(f); + } + return (1); +} + +void +shutreset (sig) + int sig; +{ + const char shutfailm[] = "WARNING: Something is hung (wont die); ps axl advised\n"; + + if (fork() == 0) { + int ct = open(ctty, 1); + write(ct, shutfailm, sizeof (shutfailm)); + sleep(1); + exit(1); + } + //sleep(1); + shutend(); + longjmp(shutpass, 1); +} + +void +shutdown() +{ + register int i; + register struct tab *p, *p1; + + close(creat(utmpf, 0644)); + signal(SIGHUP, SIG_IGN); + for (p = itab; p ; ) { + term(p); + p1 = p->next; + free(p); + p = p1; + } + itab = (struct tab *)0; + signal(SIGALRM, shutreset); + (void) kill(-1, SIGTERM); /* one chance to catch it */ + //sleep(1); + alarm(30); + for (i = 0; i < 5; i++) + kill(-1, SIGKILL); + while (wait((int *)0) != -1) + ; + alarm(0); + shutend(); +} + +void +single() +{ + register int pid, xpid; + int fd; + + /* + * If the kernel is in secure mode, downgrade it to insecure mode. + */ + if (getsecuritylevel() > 0) + setsecuritylevel(0); + + do { + pid = fork(); + if (pid == 0) { + signal(SIGTERM, SIG_DFL); + signal(SIGHUP, SIG_DFL); + signal(SIGALRM, SIG_DFL); + signal(SIGTSTP, SIG_IGN); + fd = open(ctty, O_RDWR, 0); + if (fd) + dup2(fd, 0); + dup2(0, 1); + dup2(0, 2); + execl(shell, minus, (char *)0); + perror(shell); + exit(0); + } + while ((xpid = wait((int *)0)) != pid) + if (xpid == -1 && errno == ECHILD) + break; + } while (xpid == -1); +} + +int +runcom(oldhowto) + int oldhowto; +{ + register int pid, f; + int status; + + pid = fork(); + if (pid == 0) { + f = open("/", O_RDONLY, 0); + if (f > 0) + dup2(f, 0); + dup2(0, 1); + dup2(0, 2); + if (oldhowto & RB_SINGLE) + execl(shell, shell, runc, (char *)0); + else + execl(shell, shell, runc, "autoboot", (char *)0); + exit(1); + } + while (wait(&status) != pid) + ; + if (status) { +syslog(LOG_ERR, "%s failed: status = %#x", runc, status); +closelog(); +sleep(1); + return (0); + } + f = open(wtmpf, O_WRONLY|O_APPEND); + if (f >= 0) { + SCPYN(wtmp.ut_line, "~"); + SCPYN(wtmp.ut_name, "reboot"); + SCPYN(wtmp.ut_host, ""); + if (time0) { + wtmp.ut_time = time0; + time0 = 0; + } else + time(&wtmp.ut_time); + write(f, (char *)&wtmp, sizeof(wtmp)); + close(f); + } + return (1); +} + +#define NARGS 20 /* must be at least 4 */ +#define ARGLEN 512 /* total size for all the argument strings */ + +void +execit(s, arg) + char *s; + char *arg; /* last argument on line */ +{ + char *argv[NARGS], args[ARGLEN], *envp[1]; + register char *sp = s; + register char *ap = args; + register char c; + register int i; + + /* + * First we have to set up the argument vector. + * "prog arg1 arg2" maps to exec("prog", "-", "arg1", "arg2"). + */ + for (i = 1; i < NARGS - 2; i++) { + argv[i] = ap; + for (;;) { + if ((c = *sp++) == '\0' || ap >= &args[ARGLEN-1]) { + *ap = '\0'; + goto done; + } + if (c == ' ') { + *ap++ = '\0'; + while (*sp == ' ') + sp++; + if (*sp == '\0') + goto done; + break; + } + *ap++ = c; + } + } +done: + argv[0] = argv[1]; + argv[1] = "-"; + argv[i+1] = arg; + argv[i+2] = 0; + envp[0] = 0; + execve(argv[0], &argv[1], envp); + /* report failure of exec */ + syslog(LOG_ERR, "%s: %m", argv[0]); + closelog(); + sleep(10); /* prevent failures from eating machine */ +} + +void +wstart(p) + register struct tab *p; +{ + register int pid; + time_t t; + int dowait = 0; + + time(&t); + p->windcnt++; + if ((t - p->windtime) >= 60) { + p->windtime = t; + p->windcnt = 1; + } else if (p->windcnt >= 5) { + dowait = 1; + p->windtime = t; + p->windcnt = 1; + } + + pid = fork(); + + if (pid == 0) { + signal(SIGTERM, SIG_DFL); + signal(SIGHUP, SIG_IGN); + sigsetmask(0L); /* since can be called from masked code */ + if (dowait) { + syslog(LOG_ERR, "'%s %s' failing, sleeping", p->wcmd, p->line); + closelog(); + sleep(30); + } + execit(p->wcmd, p->line); + exit(0); + } + p->wpid = pid; +} + +void +dfork(p) + struct tab *p; +{ + register int pid; + time_t t; + int dowait = 0; + + time(&t); + p->gettycnt++; + if ((t - p->gettytime) >= 60) { + p->gettytime = t; + p->gettycnt = 1; + } else if (p->gettycnt >= 5) { + dowait = 1; + p->gettytime = t; + p->gettycnt = 1; + } + pid = fork(); + if (pid == 0) { + signal(SIGTERM, SIG_DFL); + signal(SIGHUP, SIG_IGN); + sigsetmask(0L); /* since can be called from masked code */ + if (dowait) { + syslog(LOG_ERR, "'%s %s' failing, sleeping", p->comn, p->line); + closelog(); + sleep(30); + } + execit(p->comn, p->line); + exit(0); + } + p->pid = pid; +} + +/* + * Multi-user. Listen for users leaving, SIGHUP's + * which indicate ttys has changed, and SIGTERM's which + * are used to shutdown the system. + */ +void +multiple() +{ + register struct tab *p; + register int pid; + long omask; + static struct sigvec mvec = { merge, sigmask(SIGTERM), 0 }; + + /* + * If the administrator has not set the security level to -1 + * to indicate that the kernel should not run multiuser in secure + * mode, and the run script has not set a higher level of security + * than level 1, then put the kernel into secure mode. + */ + if (getsecuritylevel() == 0) + setsecuritylevel(1); + + sigvec(SIGHUP, &mvec, (struct sigvec *)0); + for (;;) { + pid = wait((int *)0); + if (pid == -1) + return; + omask = sigblock(sigmask(SIGHUP)); + for (p=itab; p; p=p->next) { + /* must restart window system BEFORE emulator */ + if (p->wpid == pid || p->wpid == -1) + wstart(p); + if (p->pid == pid || p->pid == -1) { + /* disown the window system */ + if (p->wpid) + kill(p->wpid, SIGHUP); + rmut(p); + dfork(p); + } + } + sigsetmask(omask); + } +} + +int +main(argc, argv) + char **argv; +{ +#if 0 + /* Trivial init: just start shell. */ + int fd = open(ctty, O_RDWR, 0); + if (fd < 0) + return 0; + write(fd, "init: starting /bin/sh\n", 23); + if (fd > 0) + dup2(fd, 0); + dup2(0, 1); + dup2(0, 2); + execl(shell, minus, (char *)0); + perror(shell); + return 0; +#else + int howto, oldhowto; + + time0 = time(0); + if (argc > 1 && argv[1][0] == '-') { + char *cp; + + howto = 0; + cp = &argv[1][1]; + while (*cp) switch (*cp++) { + case 'a': + howto |= RB_ASKNAME; + break; + case 's': + howto |= RB_SINGLE; + break; + } + } else { + howto = RB_SINGLE; + } + if (getuid() != 0) + exit(1); + if (getpid() != 1) + exit(1); + + openlog("init", LOG_CONS|LOG_ODELAY, LOG_AUTH); + + signal(SIGSYS, badsys); + sigvec(SIGTERM, &rvec, (struct sigvec *)0); + signal(SIGTSTP, idle); + signal(SIGSTOP, SIG_IGN); + signal(SIGTTIN, SIG_IGN); + signal(SIGTTOU, SIG_IGN); + (void) setjmp(sjbuf); + for (;;) { + oldhowto = howto; + howto = RB_SINGLE; + if (setjmp(shutpass) == 0) + shutdown(); + if (oldhowto & RB_SINGLE) + single(); + if (runcom(oldhowto) == 0) + continue; + merge(0); + multiple(); + } +#endif +} + +/* + * Get the security level of the kernel. + */ +int +getsecuritylevel() +{ +#ifdef KERN_SECURELVL + int name[2], curlevel; + size_t len; + + name[0] = CTL_KERN; + name[1] = KERN_SECURELVL; + len = sizeof curlevel; + if (sysctl(name, 2, &curlevel, &len, NULL, 0) == -1) { + syslog(LOG_EMERG, "cannot get kernel security level: %s", + strerror(errno)); + return (-1); + } + return (curlevel); +#else + return (-1); +#endif +} + +/* + * Set the security level of the kernel. + */ +void +setsecuritylevel(newlevel) + int newlevel; +{ +#ifdef KERN_SECURELVL + int name[2], curlevel; + + curlevel = getsecuritylevel(); + if (newlevel == curlevel) + return; + name[0] = CTL_KERN; + name[1] = KERN_SECURELVL; + if (sysctl(name, 2, NULL, NULL, &newlevel, sizeof newlevel) == -1) { + syslog(LOG_EMERG, + "cannot change kernel security level from %d to %d: %s", + curlevel, newlevel, strerror(errno)); + return; + } + syslog(LOG_ALERT, "kernel security level changed from %d to %d", + curlevel, newlevel); +#endif +} + +void +wterm(p) + register struct tab *p; +{ + if (p->wpid != 0) { + kill(p->wpid, SIGKILL); + p->wpid = 0; + } +} + +/* + * Merge current contents of ttys file + * into in-core table of configured tty lines. + * Entered as signal handler for SIGHUP. + */ +#define FOUND 1 +#define CHANGE 2 +#define WCHANGE 4 + +void merge(int signum) +{ + register struct tab *p; + register struct ttyent *t; + register struct tab *p1; + + for (p=itab; p; p=p->next) + p->xflag = 0; + setttyent(); + while ((t = getttyent()) != 0) { + if ((t->ty_status & TTY_ON) == 0) + continue; + for (p=itab; p; p=p->next) { + if (SCMPN(p->line, t->ty_name)) + continue; + p->xflag |= FOUND; + if (SCMPN(p->comn, t->ty_getty)) { + p->xflag |= CHANGE; + SCPYN(p->comn, t->ty_getty); + } + if (SCMPN(p->wcmd, t->ty_window ? t->ty_window : "")) { + p->xflag |= WCHANGE | CHANGE; + SCPYN(p->wcmd, t->ty_window); + } + goto contin1; + } + + /* + * Make space for a new one + */ + p1 = (struct tab *)calloc(1, sizeof(*p1)); + if (!p1) { + syslog(LOG_ERR, "no space for '%s' !?!", t->ty_name); + goto contin1; + } + /* + * Put new terminal at the end of the linked list. + */ + if (itab) { + for (p = itab; p->next ; p = p->next) + ; + p->next = p1; + } else + itab = p1; + + p = p1; + SCPYN(p->line, t->ty_name); + p->xflag |= FOUND|CHANGE; + SCPYN(p->comn, t->ty_getty); + if (t->ty_window && strcmp(t->ty_window, "") != 0) { + p->xflag |= WCHANGE; + SCPYN(p->wcmd, t->ty_window); + } + contin1: + ; + } + endttyent(); + p1 = (struct tab *)0; + for (p=itab; p; p=p->next) { + if ((p->xflag & FOUND) == 0) { + term(p); + wterm(p); + if (p1) + p1->next = p->next; + else + itab = p->next; + free(p); + p = p1 ? p1 : itab; + } else { + /* window system should be started first */ + if (p->xflag & WCHANGE) { + wterm(p); + wstart(p); + } + if (p->xflag & CHANGE) { + term(p); + dfork(p); + } + } + p1 = p; + } +} + +void +reset() +{ + longjmp(sjbuf, 1); +} diff --git a/src/cmd/iostat.c b/src/cmd/iostat.c new file mode 100644 index 0000000..b168f8f --- /dev/null +++ b/src/cmd/iostat.c @@ -0,0 +1,246 @@ +/* + * iostat + */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +struct nlist nl[] = { + { "_dk_busy" }, +#define X_DK_BUSY 0 + { "_dk_xfer" }, +#define X_DK_XFER 1 + { "_dk_bytes" }, +#define X_DK_BYTES 2 + { "_tk_nin" }, +#define X_TK_NIN 3 + { "_tk_nout" }, +#define X_TK_NOUT 4 + { "_cp_time" }, +#define X_CP_TIME 5 + { "_hz" }, +#define X_HZ 6 + { "_dk_ndrive" }, +#define X_DK_NDRIVE 7 + { "_dk_name" }, +#define X_DK_NAME 8 + { "_dk_unit" }, +#define X_DK_UNIT 9 + { 0 }, +}; + +char **dr_name; +char **dk_name; +int *dr_select; +int *dk_unit; +int dk_ndrive; +int ndrives = 0; + +struct { + int dk_busy; + long cp_time[CPUSTATES]; + long *dk_bytes; + long *dk_xfer; + long tk_nin; + long tk_nout; +} s, s1; + +int mf; +int hz; +double etime; +int tohdr = 1; + +void printhdr(sig) + int sig; +{ + register int i; + + printf("---tty---"); + for (i = 0; i < dk_ndrive; i++) + if (dr_select[i]) + printf(" ---%3.3s--", dr_name[i]); + printf(" ------cpu------\n"); + + printf(" tin tout"); + for (i = 0; i < dk_ndrive; i++) + if (dr_select[i]) + printf(" kbps tps"); + printf(" us ni sy id\n"); + tohdr = 19; +} + +main(argc, argv) + char *argv[]; +{ + extern char *ctime(); + register i; + int iter; + double f1, f2; + long t; + char *arg, **cp, name[6], buf[BUFSIZ]; + + knlist(nl); + if(nl[X_DK_BUSY].n_value == 0) { + printf("dk_busy not found in /vmunix namelist\n"); + exit(1); + } + mf = open("/dev/kmem", 0); + if(mf < 0) { + printf("cannot open /dev/kmem\n"); + exit(1); + } + iter = 0; + for (argc--, argv++; argc > 0 && argv[0][0] == '-'; argc--, argv++) + ; + if (nl[X_DK_NDRIVE].n_value == 0) { + printf("dk_ndrive undefined in system\n"); + exit(1); + } + lseek(mf, (long)nl[X_DK_NDRIVE].n_value, L_SET); + read(mf, &dk_ndrive, sizeof (dk_ndrive)); + if (dk_ndrive <= 0) { + printf("dk_ndrive %d\n", dk_ndrive); + exit(1); + } + dr_select = (int *)calloc(dk_ndrive, sizeof (int)); + dr_name = (char **)calloc(dk_ndrive, sizeof (char *)); + dk_name = (char **)calloc(dk_ndrive, sizeof (char *)); + dk_unit = (int *)calloc(dk_ndrive, sizeof (int)); + s.dk_bytes = (long *)calloc(dk_ndrive, sizeof (long)); + s1.dk_bytes = (long *)calloc(dk_ndrive, sizeof (long)); + s.dk_xfer = (long *)calloc(dk_ndrive, sizeof (long)); + s1.dk_xfer = (long *)calloc(dk_ndrive, sizeof (long)); + for (arg = buf, i = 0; i < dk_ndrive; i++) { + dr_name[i] = arg; + sprintf(dr_name[i], "dk%d", i); + arg += strlen(dr_name[i]) + 1; + } + read_names(); + lseek(mf, (long)nl[X_HZ].n_value, L_SET); + read(mf, &hz, sizeof hz); + + /* + * 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. + */ + ndrives = 0; + while (argc > 0 && !isdigit(argv[0][0])) { + for (i = 0; i < dk_ndrive; i++) { + if (strcmp(dr_name[i], argv[0])) + continue; + dr_select[i] = 1; + ndrives++; + } + argc--, argv++; + } + for (i = 0; i < dk_ndrive && ndrives < 4; i++) { + if (dr_select[i]) + continue; + dr_select[i] = 1; + ndrives++; + } + if (argc > 1) + iter = atoi(argv[1]); + signal(SIGCONT, printhdr); +loop: + if (--tohdr == 0) + printhdr(); + lseek(mf, (long)nl[X_DK_BUSY].n_value, L_SET); + read(mf, &s.dk_busy, sizeof s.dk_busy); + + lseek(mf, (long)nl[X_DK_XFER].n_value, L_SET); + read(mf, s.dk_xfer, dk_ndrive*sizeof (long)); + + lseek(mf, (long)nl[X_DK_BYTES].n_value, L_SET); + read(mf, s.dk_bytes, dk_ndrive*sizeof (long)); + + lseek(mf, (long)nl[X_TK_NIN].n_value, L_SET); + read(mf, &s.tk_nin, sizeof s.tk_nin); + + lseek(mf, (long)nl[X_TK_NOUT].n_value, L_SET); + read(mf, &s.tk_nout, sizeof s.tk_nout); + + lseek(mf, (long)nl[X_CP_TIME].n_value, L_SET); + read(mf, s.cp_time, sizeof s.cp_time); + + for (i = 0; i < dk_ndrive; i++) { + if (! dr_select[i]) + continue; +#define X(fld) t = s.fld[i]; s.fld[i] -= s1.fld[i]; s1.fld[i] = t + X(dk_xfer); X(dk_bytes); + } + t = s.tk_nin; s.tk_nin -= s1.tk_nin; s1.tk_nin = t; + t = s.tk_nout; s.tk_nout -= s1.tk_nout; s1.tk_nout = t; + etime = 0; + for(i=0; i 0) { + sleep(atoi(argv[0])); + goto loop; + } +} + +stats(dn) +{ + /* number of bytes transferred */ + printf("%5.0f", (double) s.dk_bytes[dn] / 1024 / etime); + + /* number of transfers */ + printf("%4.0f", (double) s.dk_xfer[dn] / etime); +} + +stat1(o) +{ + register i; + double time; + + time = 0; + for(i=0; i +#include + +#define F1 0 +#define F2 1 +#define NFLD 20 /* max field per line */ +#define comp() cmp(ppi[F1][fj1],ppi[F2][fj2]) + +FILE *f[2]; +char buf[2][BUFSIZ]; /*input lines */ +char *ppi[2][NFLD]; /* pointers to fields in lines */ +char *s1,*s2; +int fj1 = 1; /* join of this field of file 1 */ +int fj2 = 1; /* join of this field of file 2 */ +int olist[2*NFLD]; /* output these fields */ +int olistf[2*NFLD]; /* from these files */ +int no; /* number of entries in olist */ +int sep1 = ' '; /* default field separator */ +int sep2 = '\t'; +char* null = ""; +int unpub1; +int unpub2; +int aflg; + +main(argc, argv) +char *argv[]; +{ + int i; + int n1, n2; + long top2, bot2; + long ftell(); + + while (argc > 1 && argv[1][0] == '-') { + if (argv[1][1] == '\0') + break; + switch (argv[1][1]) { + case 'a': + switch(argv[1][2]) { + case '1': + aflg |= 1; + break; + case '2': + aflg |= 2; + break; + default: + aflg |= 3; + } + break; + case 'e': + null = argv[2]; + argv++; + argc--; + break; + case 't': + sep1 = sep2 = argv[1][2]; + break; + case 'o': + for (no = 0; no < 2*NFLD; no++) { + if (argv[2][0] == '1' && argv[2][1] == '.') { + olistf[no] = F1; + olist[no] = atoi(&argv[2][2]); + } else if (argv[2][0] == '2' && argv[2][1] == '.') { + olist[no] = atoi(&argv[2][2]); + olistf[no] = F2; + } else + break; + argc--; + argv++; + } + break; + case 'j': + if (argv[1][2] == '1') + fj1 = atoi(argv[2]); + else if (argv[1][2] == '2') + fj2 = atoi(argv[2]); + else + fj1 = fj2 = atoi(argv[2]); + argc--; + argv++; + break; + } + argc--; + argv++; + } + for (i = 0; i < no; i++) + olist[i]--; /* 0 origin */ + if (argc != 3) + error("usage: join [-an] [-estring] [-j1 x -j2 y] [-o list] [-tc] file1 file2"); + fj1--; + fj2--; /* everyone else believes in 0 origin */ + s1 = ppi[F1][fj1]; + s2 = ppi[F2][fj2]; + if (argv[1][0] == '-') + f[F1] = stdin; + else if ((f[F1] = fopen(argv[1], "r")) == NULL) + error("can't open %s", argv[1]); + if ((f[F2] = fopen(argv[2], "r")) == NULL) + error("can't open %s", argv[2]); + +#define get1() n1=input(F1) +#define get2() n2=input(F2) + get1(); + bot2 = ftell(f[F2]); + get2(); + while(n1>0 && n2>0 || aflg!=0 && n1+n2>0) { + if(n1>0 && n2>0 && comp()>0 || n1==0) { + if(aflg&2) output(0, n2); + bot2 = ftell(f[F2]); + get2(); + } else if(n1>0 && n2>0 && comp()<0 || n2==0) { + if(aflg&1) output(n1, 0); + get1(); + } else /*(n1>0 && n2>0 && comp()==0)*/ { + while(n2>0 && comp()==0) { + output(n1, n2); + top2 = ftell(f[F2]); + get2(); + } + fseek(f[F2], bot2, 0); + get2(); + get1(); + for(;;) { + if(n1>0 && n2>0 && comp()==0) { + output(n1, n2); + get2(); + } else if(n1>0 && n2>0 && comp()<0 || n2==0) { + fseek(f[F2], bot2, 0); + get2(); + get1(); + } else /*(n1>0 && n2>0 && comp()>0 || n1==0)*/{ + fseek(f[F2], top2, 0); + bot2 = top2; + get2(); + break; + } + } + } + } + return(0); +} + +input(n) /* get input line and split into fields */ +{ + register int i, c; + char *bp; + char **pp; + + bp = buf[n]; + pp = ppi[n]; + if (fgets(bp, BUFSIZ, f[n]) == NULL) + return(0); + for (i = 0; ; i++) { + if (sep1 == ' ') /* strip multiples */ + while ((c = *bp) == sep1 || c == sep2) + bp++; /* skip blanks */ + else + c = *bp; + if (c == '\n' || c == '\0') + break; + *pp++ = bp; /* record beginning */ + while ((c = *bp) != sep1 && c != '\n' && c != sep2 && c != '\0') + bp++; + *bp++ = '\0'; /* mark end by overwriting blank */ + /* fails badly if string doesn't have \n at end */ + } + *pp = 0; + return(i); +} + +output(on1, on2) /* print items from olist */ +int on1, on2; +{ + int i; + char *temp; + + if (no <= 0) { /* default case */ + printf("%s", on1? ppi[F1][fj1]: ppi[F2][fj2]); + for (i = 0; i < on1; i++) + if (i != fj1) + printf("%c%s", sep1, ppi[F1][i]); + for (i = 0; i < on2; i++) + if (i != fj2) + printf("%c%s", sep1, ppi[F2][i]); + printf("\n"); + } else { + for (i = 0; i < no; i++) { + temp = ppi[olistf[i]][olist[i]]; + if(olistf[i]==F1 && on1<=olist[i] || + olistf[i]==F2 && on2<=olist[i] || + *temp==0) + temp = null; + printf("%s", temp); + if (i == no - 1) + printf("\n"); + else + printf("%c", sep1); + } + } +} + +error(s1, s2, s3, s4, s5) +char *s1; +{ + fprintf(stderr, "join: "); + fprintf(stderr, s1, s2, s3, s4, s5); + fprintf(stderr, "\n"); + exit(1); +} + +cmp(s1, s2) +char *s1, *s2; +{ + return(strcmp(s1, s2)); +} diff --git a/src/cmd/kill.c b/src/cmd/kill.c new file mode 100644 index 0000000..1a0335b --- /dev/null +++ b/src/cmd/kill.c @@ -0,0 +1,74 @@ +/* + * kill - send signal to process + */ +#include +#include +#include +#include + +char *signm[] = { 0, +"HUP", "INT", "QUIT", "ILL", "TRAP", "IOT", "EMT", "FPE", /* 1-8 */ +"KILL", "BUS", "SEGV", "SYS", "PIPE", "ALRM", "TERM", "URG", /* 9-16 */ +"STOP", "TSTP", "CONT", "CHLD", "TTIN", "TTOU", "IO", "XCPU", /* 17-24 */ +"XFSZ", "VTALRM", "PROF", "WINCH", 0, "USR1", "USR2", 0, /* 25-31 */ +}; + +main(argc, argv) +char **argv; +{ + register signo, pid, res; + int errlev; + extern errno; + + errlev = 0; + if (argc <= 1) { + usage: + printf("usage: kill [ -sig ] pid ...\n"); + printf("for a list of signals: kill -l\n"); + exit(2); + } + if (*argv[1] == '-') { + if (argv[1][1] == 'l') { + for (signo = 0; signo <= NSIG; signo++) { + if (signm[signo]) + printf("%s ", signm[signo]); + if (signo == 16) + printf("\n"); + } + printf("\n"); + exit(0); + } else if (isdigit(argv[1][1])) { + signo = atoi(argv[1]+1); + if (signo < 0 || signo > NSIG) { + printf("kill: %s: number out of range\n", + argv[1]); + exit(1); + } + } else { + char *name = argv[1]+1; + for (signo = 0; signo <= NSIG; signo++) + if (signm[signo] && !strcmp(signm[signo], name)) + goto foundsig; + printf("kill: %s: unknown signal; kill -l lists signals\n", name); + exit(1); +foundsig: + ; + } + argc--; + argv++; + } else + signo = SIGTERM; + argv++; + while (argc > 1) { + if (!(isdigit(**argv) || **argv == '-')) + goto usage; + res = kill(pid = atoi(*argv), signo); + if (res<0) { + printf("%u: %s\n", pid, strerror(errno)); + errlev = 1; + } + argc--; + argv++; + } + return(errlev); +} diff --git a/src/cmd/la/Makefile b/src/cmd/la/Makefile new file mode 100644 index 0000000..d4eb631 --- /dev/null +++ b/src/cmd/la/Makefile @@ -0,0 +1,30 @@ +# +# la Makefile. Revised 1996/1/28 +# +TOPSRC = $(shell cd ../../..; pwd) +include $(TOPSRC)/target.mk + +CFLAGS += -Werror -Wall + +SRCS = la.c +OBJS = la.o +MAN = la.0 +MANSRC = la.1 + +all: la $(MAN) + +la: ${OBJS} + ${CC} ${LDFLAGS} -o la.elf ${OBJS} ${LIBS} + ${OBJDUMP} -S la.elf > la.dis + ${SIZE} la.elf + ${ELF2AOUT} la.elf $@ && rm la.elf + +$(MAN): ${MANSRC} + ${MANROFF} ${MANSRC} > ${MAN} + +clean: + rm -f *.o *.elf ${MAN} la *.elf *.dis tags *~ + +install: all + install la $(DESTDIR)/bin/ + cp $(MAN) $(DESTDIR)/share/man/cat1/ diff --git a/src/cmd/la/la.1 b/src/cmd/la/la.1 new file mode 100644 index 0000000..f9f45c8 --- /dev/null +++ b/src/cmd/la/la.1 @@ -0,0 +1,19 @@ +.\" Copyright (c) 1980 Regents of the University of California. +.\" All rights reserved. The Berkeley software License Agreement +.\" specifies the terms and conditions for redistribution. +.\" +.\" @(#)la.1 6.2 (Berkeley) 6/20/87 +.\" +.TH LA 1 "June 20, 1987" +.UC 2 +.SH NAME +la \- print 1, 5 and 15 minute system load averages +.SH SYNOPSIS +.B la +.SH DESCRIPTION +.I la +prints the one, five and fifteen minute system load averages. +These averages represent the average number of runnable jobs for +the indicated time period. +.SH "SEE ALSO" +w(1) diff --git a/src/cmd/la/la.c b/src/cmd/la/la.c new file mode 100644 index 0000000..d1b5524 --- /dev/null +++ b/src/cmd/la/la.c @@ -0,0 +1,20 @@ +#include +#include + +/* + * la: print the load average. + */ +int main() +{ + unsigned vec[3]; + + if (getloadavg(vec, 3) < 0) { + perror("la: getloadavg"); + return 1; + } + printf("load %u.%02u %u.%02u %u.%02u\n", + vec[0] / 100, vec[0] % 100, + vec[1] / 100, vec[1] % 100, + vec[2] / 100, vec[2] % 100); + return 0; +} diff --git a/src/cmd/last.c b/src/cmd/last.c new file mode 100644 index 0000000..79c517d --- /dev/null +++ b/src/cmd/last.c @@ -0,0 +1,233 @@ +/* + * last + * + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#define NMAX sizeof(buf[0].ut_name) +#define LMAX sizeof(buf[0].ut_line) +#define HMAX sizeof(buf[0].ut_host) +#define SECDAY ((long)24*60*60) + +#define lineq(a,b) (!strncmp(a,b,LMAX)) +#define nameq(a,b) (!strncmp(a,b,NMAX)) +#define hosteq(a,b) (!strncmp(a,b,HMAX)) + +#define MAXTTYS 256 + +char **argv; +int argc; +int nameargs; + +struct utmp buf[128]; +char ttnames[MAXTTYS][LMAX+1]; +long logouts[MAXTTYS]; + +char *ctime(), *strspl(); + +void onintr(signo) + int signo; +{ + char *ct; + + if (signo == SIGQUIT) + signal(SIGQUIT, onintr); + ct = ctime(&buf[0].ut_time); + printf("\ninterrupted %10.10s %5.5s \n", ct, ct + 11); + fflush(stdout); + if (signo == SIGINT) + exit(1); +} + +void +usage(progname) + char *progname; +{ + printf("Usage: %s [ -f filename ] [-number] [name...] [tty...]\n", + progname); + exit(1); +} + +main(ac, av) + char **av; +{ + register int i, k; + int wtmp; + off_t bl; + char *ct; + char wtmpfile[256]; + char progname[256]; + register struct utmp *bp; + long otime; + struct stat stb; + int print; + int sinput = 0; + char * crmsg = (char *)0; + long crtime; + long outrec = 0; + long maxrec = 0x7fffffffL; + + time(&buf[0].ut_time); + strcpy(wtmpfile, _PATH_WTMP); + strcpy(progname,av[0]); + ac--, av++; + nameargs = argc = ac; + argv = av; + for (i = 0; i < argc; i++) { + if (argv[i][0] == '-' ) { + if ( argv[i][1] >= '0' && argv[i][1] <= '9') { + maxrec = atoi(argv[i]+1); + nameargs--; + continue; + } else { + if (argv[i][1] == 'f') { + i++; + if ( i < argc) { + strcpy(wtmpfile,argv[i]); + nameargs = nameargs -2; + continue; + } else { + usage(progname); + } + } else { + usage(progname); + } + } + } + if (strlen(argv[i])>2) + continue; + if (!strcmp(argv[i], "~")) + continue; + if (!strcmp(argv[i], "ftp")) + continue; + if (!strcmp(argv[i], "uucp")) + continue; + if (getpwnam(argv[i])) + continue; + argv[i] = strspl("tty", argv[i]); + } + wtmp = open(wtmpfile, 0); + if (wtmp < 0) { + perror(wtmpfile); + exit(1); + } + fstat(wtmp, &stb); + bl = (stb.st_size + sizeof (buf)-1) / sizeof (buf); + if (signal(SIGINT, SIG_IGN) != SIG_IGN) { + signal(SIGINT, onintr); + signal(SIGQUIT, onintr); + } + for (bl--; bl >= 0; bl--) { + lseek(wtmp, bl * sizeof (buf), 0); + bp = &buf[read(wtmp, buf, sizeof (buf)) / sizeof(buf[0]) - 1]; + for ( ; bp >= buf; bp--) { + print = want(bp); + if (print) { + ct = ctime(&bp->ut_time); + printf("%-*.*s %-*.*s %-*.*s %10.10s %5.5s ", + NMAX, NMAX, bp->ut_name, + LMAX, LMAX, bp->ut_line, + HMAX, HMAX, bp->ut_host, + ct, 11+ct); + } + for (i = 0; i < MAXTTYS; i++) { + if (ttnames[i][0] == 0) { + strncpy(ttnames[i], bp->ut_line, + sizeof(bp->ut_line)); + otime = logouts[i]; + logouts[i] = bp->ut_time; + break; + } + if (lineq(ttnames[i], bp->ut_line)) { + otime = logouts[i]; + logouts[i] = bp->ut_time; + break; + } + } + if (print) { + if (lineq(bp->ut_line, "~")) + printf("\n"); + else if (otime == 0) + printf(" still logged in\n"); + else { + long delta; + if (otime < 0) { + otime = -otime; + printf("- %s", crmsg); + } else + printf("- %5.5s", + ctime(&otime)+11); + delta = otime - bp->ut_time; + if (delta < SECDAY) + printf(" (%5.5s)\n", + asctime(gmtime(&delta))+11); + else + printf(" (%ld+%5.5s)\n", + delta / SECDAY, + asctime(gmtime(&delta))+11); + } + fflush(stdout); + if (++outrec >= maxrec) + exit(0); + } + if (lineq(bp->ut_line, "~")) { + for (i = 0; i < MAXTTYS; i++) + logouts[i] = -bp->ut_time; + if (nameq(bp->ut_name, "shutdown")) + crmsg = "down "; + else + crmsg = "crash"; + } + } + } + ct = ctime(&buf[0].ut_time); + printf("\nwtmp begins %10.10s %5.5s \n", ct, ct + 11); + exit(0); +} + +want(bp) + struct utmp *bp; +{ + register char **av; + register int ac; + + if (bp->ut_line[0] == '~' && bp->ut_name[0] == '\0') + strcpy(bp->ut_name, "reboot"); /* bandaid */ + if (strncmp(bp->ut_line, "ftp", 3) == 0) + bp->ut_line[3] = '\0'; + if (strncmp(bp->ut_line, "uucp", 4) == 0) + bp->ut_line[4] = '\0'; + if (bp->ut_name[0] == 0) + return (0); + if (nameargs == 0) + return (1); + av = argv; + for (ac = 0; ac < argc; ac++, av++) { + if (av[0][0] == '-') + continue; + if (nameq(*av, bp->ut_name) || lineq(*av, bp->ut_line)) + return (1); + } + return (0); +} + +char * +strspl(left, right) + char *left, *right; +{ + char *res = (char *)malloc(strlen(left)+strlen(right)+1); + + strcpy(res, left); + strcat(res, right); + return (res); +} diff --git a/src/cmd/lcc/Makefile b/src/cmd/lcc/Makefile new file mode 100644 index 0000000..a981dd3 --- /dev/null +++ b/src/cmd/lcc/Makefile @@ -0,0 +1,40 @@ +TOPSRC = $(shell cd ../../..; pwd) +include $(TOPSRC)/target.mk +#include $(TOPSRC)/cross.mk + +OBJS = lcc.o retrobsd.o +MAN = lcc.0 +MANSRC = lcc.1 + +LDFLAGS += -g +CFLAGS += -Werror -Wall -Os + +all: lcc $(MAN) + +lcc: $(OBJS) + ${CC} ${LDFLAGS} -o lcc.elf $(OBJS) ${LIBS} + ${OBJDUMP} -S lcc.elf > lcc.dis + ${SIZE} lcc.elf + ${ELF2AOUT} lcc.elf $@ && rm lcc.elf + +bprint: bprint.o ../lccom/profio.c + ${CC} ${LDFLAGS} -o bprint.elf bprint.o ${LIBS} + ${OBJDUMP} -S bprint.elf > bprint.dis + ${SIZE} bprint.elf + ${ELF2AOUT} bprint.elf $@ && rm bprint.elf + +ops: ops.o ../lccom/c.h ../lccom/ops.h + ${CC} ${LDFLAGS} -o ops.elf ops.o ${LIBS} + ${OBJDUMP} -S ops.elf > ops.dis + ${SIZE} ops.elf + ${ELF2AOUT} ops.elf $@ && rm ops.elf + +$(MAN): ${MANSRC} + ${MANROFF} $< > $@ + +clean: + rm -f *.o *.0 *.elf lcc bprint ops *.dis *~ + +install: all + install lcc $(DESTDIR)/bin/ + cp lcc.0 $(DESTDIR)/share/man/cat1/ diff --git a/src/cmd/lcc/bprint.1 b/src/cmd/lcc/bprint.1 new file mode 100644 index 0000000..4ccde0d --- /dev/null +++ b/src/cmd/lcc/bprint.1 @@ -0,0 +1,83 @@ +.\" $Id: bprint.1,v 1.4 1998/08/24 21:18:18 drh Exp $ +.TH BPRINT 1 "local \- $Date: 1998/08/24 21:18:18 $" +.SH NAME +bprint \- expression profiler +.SH SYNOPSIS +.B bprint +[ +.I option ... +] +[ +.I file ... +] +.SH DESCRIPTION +.I bprint +produces on the standard output a listing of the programs compiled by +.I lcc +with the +.B \-b +option. +Executing an +.B a.out +so compiled appends profiling data to +.BR prof.out . +The first token of each expression in the listing is preceded +by the number of times it was executed +enclosed in angle brackets as determined from the data in +.BR prof.out . +.I bprint +interprets the following options. +.TP +.B \-c +Compress the +.B prof.out +file, which otherwise grows with every execution of +.BR a.out . +.TP +.B \-b +Print an annotated listing as described above. +.TP +.B \-n +Include line numbers in the listing. +.TP +.B \-f +Print only the number of invocations of each function. +A second +.B \-f +summarizes call sites instead of callers. +.TP +.BI \-I \*Sdir +specifies additional directories in which to seek +files given in +.B prof.out +that do not begin with `/'. +.PP +If any file names are given, only the requested data for those files are printed +in the order presented. +If no options are given, +.B \-b +is assumed. +.SH FILES +.PP +.ta \w'$LCCDIR/liblcc.{a,lib}XX'u +.nf +prof.out profiling data +$LCCDIR/liblcc.{a,lib} \fIlcc\fP-specific library +.SH "SEE ALSO" +.IR lcc (1), +.IR prof (1) +.SH BUGS +Macros and comments can confuse +.I bprint +because it uses post-expansion source coordinates +to annotate pre-expansion source files. +If +.I bprint +sees that it's about to print a statement count +.I inside +a number or identifier, it moves the count to just +.I before +the token. +.PP +Can't cope with an ill-formed +.BR prof.out . diff --git a/src/cmd/lcc/bprint.c b/src/cmd/lcc/bprint.c new file mode 100644 index 0000000..cb394f6 --- /dev/null +++ b/src/cmd/lcc/bprint.c @@ -0,0 +1,213 @@ +/* + * bprint [ -c | -Idir... | -f | -b | -n ] [ file... ] + * + * annotate listings of files with prof.out data + */ +#include "../lccom/profio.c" +#include +#include +#include +#include +#include + +#define NDIRS (sizeof dirs/sizeof dirs[0] - 1) +#define NELEMS(a) ((int)(sizeof (a)/sizeof ((a)[0]))) + +char *progname; +int number; +char *dirs[20]; +int fcount; + +void *alloc(unsigned); +void emitdata(char *); +void printfile(struct file *, int); +void printfuncs(struct file *, int); + +void *allocate(unsigned long n, unsigned a) { return alloc(n); } + +void *newarray(unsigned long m, unsigned long n, unsigned a) { + return alloc(m*n); +} + +int main(int argc, char *argv[]) { + int i; + struct file *p; + void (*f)(struct file *, int) = printfile; + + progname = argv[0]; + if ((i = process("prof.out")) <= 0) { + fprintf(stderr, "%s: can't %s `%s'\n", progname, + i == 0 ? "open" : "interpret", "prof.out"); + exit(1); + } + for (i = 1; i < argc && *argv[i] == '-'; i++) + if (strcmp(argv[i], "-c") == 0) { + emitdata("prof.out"); + exit(0); + } else if (strcmp(argv[i], "-b") == 0) + f = printfile; + else if (strcmp(argv[i], "-f") == 0) { + fcount++; + f = printfuncs; + } else if (strcmp(argv[i], "-n") == 0) + number++; + else if (strncmp(argv[i], "-I", 2) == 0) { + int j; + for (j = 0; j < NDIRS && dirs[j]; j++) + ; + if (j < NDIRS) + dirs[j] = &argv[i][2]; + else + fprintf(stderr, "%s: too many -I options\n", progname); + } else { + fprintf(stderr, "usage: %s [ -c | -b | -n | -f | -Idir... ] [ file... ]\n", progname); + exit(1); + } + for (p = filelist; p; p = p->link) + qsort(p->counts, p->count, sizeof *p->counts, compare); + if (i < argc) { + int nf = i < argc - 1 ? 1 : 0; + for ( ; i < argc; i++, nf ? nf++ : 0) + if ((p = findfile(string(argv[i])))) + (*f)(p, nf); + else + fprintf(stderr, "%s: no data for `%s'\n", progname, argv[i]); + } else { + int nf = filelist && filelist->link ? 1 : 0; + for (p = filelist; p; p = p->link, nf ? nf++ : 0) + (*f)(p, nf); + } + return 0; +} + +/* alloc - allocate n bytes or die */ +void *alloc(unsigned n) { + void *new = malloc(n); + + assert(new); + return new; +} + +/* emitdata - write prof.out data to file */ +void emitdata(char *file) { + FILE *fp; + + if ((fp = fopen(file, "w"))) { + struct file *p; + for (p = filelist; p; p = p->link) { + int i; + struct func *q; + struct caller *r; + fprintf(fp, "1\n%s\n", p->name); + for (i = 0, q = p->funcs; q; i++, q = q->link) + if ((r = q->callers)) + for (i--; r; r = r->link) + i++; + fprintf(fp, "%d\n", i); + for (q = p->funcs; q; q = q->link) + if (q->count.count == 0 || !q->callers) + fprintf(fp, "%s 1 %d %d %d ? ? 0 0\n", q->name, q->count.x, + q->count.y, q->count.count); + else + for (r = q->callers; r; r = r->link) + fprintf(fp, "%s 1 %d %d %d %s %s %d %d\n", q->name, q->count.x, + q->count.y, r->count, r->name, r->file, r->x, r->y); + fprintf(fp, "%d\n", p->count); + for (i = 0; i < p->count; i++) + fprintf(fp, "1 %d %d %d\n", p->counts[i].x, + p->counts[i].y, p->counts[i].count); + } + fclose(fp); + } else + fprintf(stderr, "%s: can't create `%s'\n", progname, file); +} + +/* openfile - open name for reading, searching -I directories */ +FILE *openfile(char *name) { + int i; + FILE *fp; + + if (*name != '/') + for (i = 0; dirs[i]; i++) { + char buf[200]; + sprintf(buf, "%s/%s", dirs[i], name); + if ((fp = fopen(buf, "r"))) + return fp; + } + return fopen(name, "r"); +} + +/* printfile - print annotated listing for p */ +void printfile(struct file *p, int nf) { + int lineno; + FILE *fp; + char *s, buf[512]; + struct count *u = p->counts, *r, *uend; + + if (u == 0 || p->count <= 0) + return; + uend = &p->counts[p->count]; + if ((fp = openfile(p->name)) == NULL) { + fprintf(stderr, "%s: can't open `%s'\n", progname, p->name); + return; + } + if (nf) + printf("%s%s:\n\n", nf == 1 ? "" : "\f", p->name); + for (lineno = 1; fgets(buf, sizeof buf, fp); lineno++) { + if (number) + printf("%d\t", lineno); + while (u < uend && u->y < lineno) + u++; + for (s = buf; *s; ) { + char *t = s + 1; + while (u < uend && u->y == lineno && u->x < s - buf) + u++; + if (isalnum(*s) || *s == '_') + while (isalnum(*t) || *t == '_') + t++; + while (u < uend && u->y == lineno && u->x < t - buf) { + printf("<%d>", u->count); + for (r = u++; u < uend && u->x == r->x && u->y == r->y && u->count == r->count; u++) + ; + } + while (s < t) + putchar(*s++); + } + if (*s) + printf("%s", s); + } + fclose(fp); +} + +/* printfuncs - summarize data for functions in p */ +void printfuncs(struct file *p, int nf) { + struct func *q; + + if (nf) + printf("%s:\n", p->name); + for (q = p->funcs; q; q = q->link) + if (fcount <= 1 || q->count.count == 0 || !q->callers) + printf("%d\t%s\n", q->count.count, q->name); + else { + struct caller *r; + for (r = q->callers; r; r = r->link) + printf("%d\t%s\tfrom %s\tin %s:%d.%d\n", r->count, q->name, r->name, + r->file, r->y, r->x + 1); + } + +} + +/* string - save a copy of str, if necessary */ +char *string(const char *str) { + static struct string { struct string *link; char str[1]; } *list; + struct string *p; + + for (p = list; p; p = p->link) + if (strcmp(p->str, str) == 0) + return p->str; + p = alloc(strlen(str) + sizeof *p); + strcpy(p->str, str); + p->link = list; + list = p; + return p->str; +} diff --git a/src/cmd/lcc/gcc-solaris.c b/src/cmd/lcc/gcc-solaris.c new file mode 100644 index 0000000..b88ab66 --- /dev/null +++ b/src/cmd/lcc/gcc-solaris.c @@ -0,0 +1,51 @@ +/* SPARCs running Solaris 2.5.1 w/GCC tools + at CS Dept., Princeton University */ + +#include + +static char rcsid[] = "$Id: gcc-solaris.c,v 1.9 1997/05/27 23:03:40 drh Exp $"; + +#ifndef LCCDIR +#define LCCDIR "/usr/local/lib/lcc/" +#endif +#ifndef GCCDIR +#define GCCDIR "/usr/local/gnu/bin/" +#endif +#ifndef GCCLIB +#define GCCLIB "/usr/local/gnu/lib/gcc-lib/sparc-sun-solaris2.5/2.7.2/" +#endif + +char *suffixes[] = { ".c", ".i", ".s", ".o", ".out", 0 }; +char inputs[256] = ""; +char *cpp[] = { LCCDIR "cpp", + "-D__STDC__=1", "-Dsparc", "-D__sparc__", "-Dsun", "-D__sun__", "-Dunix", + "$1", "$2", "$3", 0 }; +char *include[] = { "-I" LCCDIR "include", "-I/usr/local/include", + "-I" GCCLIB "include", "-I/usr/include", 0 }; +char *com[] = { LCCDIR "rcc", "-target=sparc/solaris", + "$1", "$2", "$3", 0 }; +char *as[] = { GCCDIR "as", "-f", "-o", "$3", "$1", "$2", 0 }; +char *ld[] = { GCCDIR "ld", "-o", "$3", "$1", + GCCLIB "crti.o", GCCLIB "crt1.o", + GCCLIB "crtbegin.o", "$2", "", "", "-L" LCCDIR, "-llcc", + "-L" GCCLIB, "-lgcc", "-lm", "-lc", "", + GCCLIB "crtend.o", GCCLIB "crtn.o", 0 }; + +extern char *concat(char *, char *); + +int option(char *arg) { + if (strncmp(arg, "-lccdir=", 8) == 0) { + cpp[0] = concat(&arg[8], "/cpp"); + include[0] = concat("-I", concat(&arg[8], "/include")); + ld[10] = concat("-L", &arg[8]); + com[0] = concat(&arg[8], "/rcc"); + } else if (strcmp(arg, "-g") == 0) + ; + else if (strcmp(arg, "-pg") == 0) { + ld[8] = GCCLIB "gmon.o"; + } else if (strcmp(arg, "-b") == 0) + ; + else + return 0; + return 1; +} diff --git a/src/cmd/lcc/irix.c b/src/cmd/lcc/irix.c new file mode 100644 index 0000000..00b08f5 --- /dev/null +++ b/src/cmd/lcc/irix.c @@ -0,0 +1,69 @@ +/* SGI big endian MIPSes running IRIX 6.2 at CS Dept., Princeton University */ + +#include + +static char rcsid[] = "$Id: irix.c,v 1.11 2000/01/06 22:25:58 drh Exp $"; + +#ifndef LCCDIR +#define LCCDIR "/usr/local/lib/lcc/" +#endif +#ifndef LIBDIR +#define LIBDIR "/usr/lib/" +#endif + +char *suffixes[] = { ".c", ".i", ".s", ".o", ".out", 0 }; +char inputs[256] = ""; +char *cpp[] = { LCCDIR "cpp", "-D__STDC__=1", + "-DLANGUAGE_C", + "-DMIPSEB", + "-DSYSTYPE_SVR4", + "-D_LONGLONG", /* some SGI header files assume this */ + "-D_CFE", + "-D_LANGUAGE_C", + "-D_MIPSEB", + "-D_MIPS_FPSET=16", + "-D_MIPS_ISA=_MIPS_ISA_MIPS1", + "-D_MIPS_SIM=_MIPS_SIM_ABI32", + "-D_MIPS_SZINT=32", + "-D_MIPS_SZLONG=32", + "-D_MIPS_SZPTR=32", + "-D_SGI_SOURCE", + "-D_SVR4_SOURCE", + "-D_SYSTYPE_SVR4", + "-D__host_mips", + "-D__mips=1", + "-D__sgi", + "-D__unix", + "-Dhost_mips", + "-Dmips", + "-Dsgi", + "-Dunix", + "$1", "$2", "$3", 0 }; +char *com[] = { LCCDIR "rcc", "-target=mips/irix", "$1", "$2", "$3", "", 0 }; +char *include[] = { "-I" LCCDIR "include", "-I/usr/local/include", + "-I/usr/include", 0 }; +char *as[] = { "/usr/bin/as", "-32", "-o", "$3", "$1", "-nocpp", "-KPIC", "$2", 0 }; +char *ld[] = { "/usr/bin/ld", "-require_dynamic_link", "_rld_new_interface", "-32", + "-elf", "-_SYSTYPE_SVR4", "-Wx,-G", "0", "-g0", "-KPIC", "-dont_warn_unused", + "-o", "$3", LIBDIR "crt1.o", "-L/usr/local/lib", + "$1", "$2", "", "-L" LCCDIR, "-llcc", "-lc", "-lm", LIBDIR "crtn.o", 0 +}; + +extern char *concat(char *, char *); + +int option(char *arg) { + if (strncmp(arg, "-lccdir=", 8) == 0) { + cpp[0] = concat(&arg[8], "/cpp"); + include[0] = concat("-I", concat(&arg[8], "/include")); + com[0] = concat(&arg[8], "/rcc"); + ld[18] = concat("-L", &arg[8]); + } else if (strcmp(arg, "-g") == 0) + ; + else if (strcmp(arg, "-p") == 0) + ld[13] = LIBDIR "mcrt1.o"; + else if (strcmp(arg, "-b") == 0) + ; + else + return 0; + return 1; +} diff --git a/src/cmd/lcc/lcc.1 b/src/cmd/lcc/lcc.1 new file mode 100644 index 0000000..45ad7ac --- /dev/null +++ b/src/cmd/lcc/lcc.1 @@ -0,0 +1,605 @@ +.\" $Id: lcc.1,v 1.15 1998/08/24 21:14:33 drh Exp $ +.TH LCC 1 "local \- $Date: 1998/08/24 21:14:33 $" +.SH NAME +lcc \- ANSI C compiler +.SH SYNOPSIS +.B lcc +[ +.I option +| +.I file +]... +.br +.SH DESCRIPTION +.PP +.I lcc +is an ANSI C compiler for a variety of platforms. +.PP +Arguments whose names end with `.c' (plus `.C' under Windows) are taken to be +C source programs; they are preprocessed, compiled, and +each object program is left on the file +whose name is that of the source with `.o' (UNIX) or `.obj' (Windows) +substituted for the extension. +Arguments whose names end with `.i' are treated similarly, +except they are not preprocessed. +In the same way, +arguments ending with `.s' (plus `.S', `.asm', and `.ASM', under Windows) +are taken to be assembly source programs +and are assembled, producing an object file. +If there are no arguments, +.I lcc +summarizes its options on the standard error. +.PP +.I lcc +deletes an object file if and only if exactly one +source file is mentioned and no other file +(source, object, library) or +.B \-l +option is mentioned. +.PP +If the environment variable +.B LCCINPUTS +is set, +.I lcc +assumes it gives a semicolon- or colon-separated list of directories in which to +look for source and object files whose names do not begin with `/'. +These directories are also added to the list of directories +searched for libraries. +If +.B LCCINPUTS +is defined, it must contain `.' in order for the current directory +to be searched for input files. +.PP +.I lcc +uses ANSI standard header files (see `FILES' below). +Include files not found in the ANSI header files +are taken from the normal default include areas, +which usually includes +.BR /usr/include . +Under Windows, if the environment variable +.B include +is defined, it gives a semicolon-separated list of directories in which to search for +header files. +.PP +.I lcc +interprets the following options; unrecognized options are +taken as loader options (see +.IR ld (1)) +unless +.BR \-c , +.BR \-S , +or +.B \-E +precedes them. +Except for +.BR \-l , +all options are processed before any of the files +and apply to all of the files. +Applicable options are passed to each compilation phase in the order given. +.TP +.B \-c +Suppress the loading phase of the compilation, and force +an object file to be produced even if only one program is compiled. +.TP +.B \-g +Produce additional symbol table information for the local debuggers. +.I lcc +warns when +.B \-g +is unsupported. +.TP +.BI \-Wf\-g n , x +Set the debugging level to +.I n +and emit source code as comments into the generated assembly code; +.I x +must be the assembly language comment character. +If +.I n +is omitted, it defaults to 1, which is similar to +.BR \-g . +Omitting +.BI , x +just sets the debugging level to +.IR n . +.TP +.B \-w +Suppress warning diagnostics, such as those +announcing unreferenced statics, locals, and parameters. +The line +.I +#pragma ref id +simulates a reference to the variable +.IR id . +.TP +.BI \-d n +Generate jump tables for switches whose density is at least +.IR n , +a floating point constant between zero and one. +The default is 0.5. +.TP +.B \-A +Warns about +declarations and casts of function types without prototypes, +assignments between pointers to ints and pointers to enums, and +conversions from pointers to smaller integral types. +A second +.B \-A +warns about +unrecognized control lines, +nonANSI language extensions and source characters in literals, +unreferenced variables and static functions, +declaring arrays of incomplete types, +and exceeding +.I some +ANSI environmental limits, like more than 257 cases in switches. +It also arranges for duplicate global definitions in separately compiled +files to cause loader errors. +.TP +.B \-P +Writes declarations for all defined globals on standard error. +Function declarations include prototypes; +editing this output can simplify conversion to ANSI C. +This output may not correspond to the input when +there are several typedefs for the same type. +.TP +.B \-n +Arrange for the compiler to produce code +that tests for dereferencing zero pointers. +The code reports the offending file and line number and calls +.IR abort (3). +.TP +.B \-O +is ignored. +.TP +.B \-S +Compile the named C programs, and leave the +assembler-language output on corresponding files suffixed `.s' or `.asm'. +.TP +.B \-E +Run only the preprocessor on the named C programs +and unsuffixed file arguments, +and send the result to the standard output. +.TP +.BI \-o " output" +Name the output file +.IR output . +If +.B \-c +or +.B \-S +is specified and there is exactly one source file, +this option names the object or assembly file, respectively. +Otherwise, this option names the final executable +file generated by the loader, and `a.out' (UNIX) or `a.exe' (Windows) is left undisturbed. +.I lcc +warns if +.B \-o +and +.B \-c +or +.B \-S +are given with more than one source file and ignores the +.B \-o +option. +.TP +.BI \-D name=def +Define the +.I name +to the preprocessor, as if by `#define'. +If +.I =def +is omitted, the name is defined as "1". +.TP +.BI \-U name +Remove any initial definition of +.IR name . +.TP +.BI \-I dir +`#include' files +whose names do not begin with `/' are always +sought first in the directory of the +.I file +arguments, then in directories named in +.B \-I +options, then in directories on a standard list. +.TP +.B \-N +Do not search +.I any +of the standard directories for `#include' files. +Only those directories specified by subsequent explicit +.B \-I +options will be searched, in the order given. +.TP +.BI \-B str +Use the compiler +.BI "" str rcc +instead of the default version. +Note that +.I str +often requires a trailing slash. +On Sparcs only, +.B \-Bstatic +and +.BI \-Bdynamic +are passed to the loader; see +.IR ld (1). +.TP +.BI \-Wo\-lccdir= dir +Find the preprocessor, compiler proper, and include directory +in the directory +.I dir/ +or +.I +dir\\. +If the environment variable +.B LCCDIR +is defined, it gives this directory. +.I lcc +warns when this option is unsupported. +.TP +.B \-Wf-unsigned_char=1 +.br +.ns +.TP +.B \-Wf-unsigned_char=0 +makes plain +.B char +an unsigned (1) or signed (0) type; by default, +.B char +is signed. +.TP +.B \-Wf\-wchar_t=unsigned_char +.br +.ns +.TP +.B \-Wf\-wchar_t=unsigned_short +.br +.ns +.TP +.B \-Wf\-wchar_t=unsigned_int +Makes wide characters the type indicated; by default, +wide characters are unsigned short ints, and +.B wchar_t +is a typedef for unsigned short defined in stddef.h. +The definition for +.B wchar_t +in stddef.h must correspond to the type specified. +.TP +.B \-v +Print commands as they are executed; some of the executed +programs are directed to print their version numbers. +More than one occurrence of +.B \-v +causes the commands to be printed, but +.I not +executed. +.TP +.BR \-help " or " \-? +Print a message on the standard error summarizing +.IR lcc 's +options and giving the values of the environment variables +.B LCCINPUTS +and +.BR LCCDIR , +if they are defined. +Under Windows, the values of +.B include +and +.B lib +are also given, if they are defined. +.TP +.B \-b +Produce code that counts the number of times each expression is executed. +If loading takes place, arrange for a +.B prof.out +file to be written when the object program terminates. +A listing annotated with execution counts can then be generated with +.IR bprint (1). +.I lcc +warns when +.B \-b +is unsupported. +.B \-Wf\-C +is similar, but counts only the number of function calls. +.TP +.B \-p +Produce code that counts the number of times each function is called. +If loading takes place, replace the standard startup +function by one that automatically calls +.IR monitor (3) +at the start and arranges to write a +.B mon.out +file when the object program terminates normally. +An execution profile can then be generated with +.IR prof (1). +.I lcc +warns when +.B \-p +is unsupported. +.TP +.B \-pg +Causes the compiler to produce counting code like +.BR \-p , +but invokes a run-time recording mechanism that keeps more +extensive statistics and produces a +.B gmon.out +file at normal termination. +Also, a profiling library is searched, in lieu of the standard C library. +An execution profile can then be generated with +.IR gprof (1). +.I lcc +warns when +.B \-pg +is unsupported. +.TP +.BI \-t name +.br +.ns +.TP +.BI \-t +Produce code to print the name of the function, an activation number, +and the name and value of each argument at function entry. +At function exit, produce code to print +the name of the function, the activation number, and the return value. +By default, +.I printf +does the printing; if +.I name +appears, it does. +For null +.I char* +values, "(null)" is printed. +.BI \-target +.I name +is accepted, but ignored. +.TP +.BI \-tempdir= dir +Store temporary files in the directory +.I dir/ +or +.I +dir\\. +The default is usually +.BR /tmp . +.TP +.BI \-W xarg +pass argument +.I arg +to the program indicated by +.IR x ; +.I x +can be one of +.BR p , +.BR f , +.BR a , +or +.BR l , +which refer, respectively, to the preprocessor, the compiler proper, +the assembler, and the loader. +.I arg +is passed as given; if a +.B \- +is expected, it must be given explicitly. +.BI \-Wo arg +specifies a system-specific option, +.IR arg . +.PP +Other arguments +are taken to be either loader option arguments, or C-compatible +object programs, typically produced by an earlier +.I lcc +run, or perhaps libraries of C-compatible routines. +Duplicate object files are ignored. +These programs, together with the results of any +compilations specified, are loaded (in the order +given) to produce an executable program with name +.BR a.out +(UNIX) or +.BR a.exe +(Windows). +.PP +.I lcc +assigns the most frequently referenced scalar parameters and +locals to registers whenever possible. +For each block, +explicit register declarations are obeyed first; +remaining registers are assigned to automatic locals if they +are `referenced' at least 3 times. +Each top-level occurrence of an identifier +counts as 1 reference. Occurrences in a loop, +either of the then/else arms of an if statement, or a case +in a switch statement each count, respectively, as 10, 1/2, or 1/10 references. +These values are adjusted accordingly for nested control structures. +.B \-Wf\-a +causes +.I lcc +to read a +.B prof.out +file from a previous execution and to use the data therein +to compute reference counts (see +.BR \-b ). +.PP +.I lcc +is a cross compiler; +.BI \-Wf\-target= target/os +causes +.I lcc +to generate code for +.I target +running the operating system denoted by +.IR os . +The supported +.I target/os +combinations may include +.PP +.RS +.ta \w'sparc/solarisxx'u +.nf +alpha/osf ALPHA, OSF 3.2 +mips/irix big-endian MIPS, IRIX 5.2 +mips/ultrix little-endian MIPS, ULTRIX 4.3 +sparc/solaris SPARC, Solaris 2.3 +x86/win32 x86, Windows NT 4.0/Windows 95/98 +x86/linux x86, Linux +symbolic text rendition of the generated code +null no output +.fi +.RE +.PP +For +.BR \-Wf\-target=symbolic , +the option +.B \-Wf-html +causes the text rendition to be emitted as HTML. +.B +.SH LIMITATIONS +.PP +.I lcc +accepts the C programming language +as described in the ANSI standard. +If +.I lcc +is used with the GNU C preprocessor, the +.B \-Wp\-trigraphs +option is required to enable trigraph sequences. +.PP +Plain int bit fields are signed. +Bit fields are aligned like unsigned integers but are otherwise laid out +as by most standard C compilers. +Some compilers, such as the GNU C compiler, +may choose other, incompatible layouts. +.PP +Likewise, calling conventions are intended to be compatible with +the host C compiler, +except possibly for passing and returning structures. +Specifically, +.I lcc +passes and returns structures like host ANSI C compilers +on most targets, but some older host C compilers use different conventions. +Consequently, calls to/from such functions compiled with +older C compilers may not work. +Calling a function that returns +a structure without declaring it as such violates +the ANSI standard and may cause a fault. +.SH FILES +.PP +The file names listed below are +.IR typical , +but vary among installations; installation-dependent variants +can be displayed by running +.I lcc +with the +.B \-v +option. +.PP +.RS +.ta \w'$LCCDIR/liblcc.{a,lib}XX'u +.nf +file.{c,C} input file +file.{s,asm} assembly-language file +file.{o,obj} object file +a.{out,exe} loaded output +/tmp/lcc* temporary files +$LCCDIR/cpp preprocessor +$LCCDIR/rcc compiler +$LCCDIR/liblcc.{a,lib} \fIlcc\fP-specific library +/lib/crt0.o runtime startup (UNIX) +/lib/[gm]crt0.o startups for profiling (UNIX) +/lib/libc.a standard library (UNIX) +$LCCDIR/include ANSI standard headers +/usr/local/include local headers +/usr/include traditional headers +prof.out file produced for \fIbprint\fR(1) +mon.out file produced for \fIprof\fR(1) +gmon.out file produced for \fIgprof\fR(1) +.fi +.RE +.PP +.I lcc +predefines the macro +.B __LCC__ +on all systems. +It may also predefine some installation-dependent symbols; option +.B \-v +exposes them. +.SH "SEE ALSO" +.PP +C. W. Fraser and D. R. Hanson, +.I A Retargetable C Compiler: Design and Implementation, +Addison-Wesley, 1995. ISBN 0-8053-1670-1. +.PP +The World-Wide Web page at http://www.cs.princeton.edu/software/lcc/. +.PP +S. P. Harbison and G. L. Steele, Jr., +.I C: A Reference Manual, +4th ed., Prentice-Hall, 1995. +.PP +B. W. Kernighan and D. M. Ritchie, +.I The C Programming Language, +2nd ed., Prentice-Hall, 1988. +.PP +American National Standards Inst., +.I American National Standard for Information Systems\(emProgramming +.IR Language\(emC , +ANSI X3.159-1989, New York, 1990. +.br +.SH BUGS +Mail bug reports along with the shortest preprocessed program +that exposes them and the details reported by +.IR lcc 's +.B \-v +option to lcc-bugs@princeton.edu. The WWW page at +URL http://www.cs.princeton.edu/software/lcc/ +includes detailed instructions for reporting bugs. +.PP +The ANSI standard headers conform to the specifications in +the Standard, which may be too restrictive for some applications, +but necessary for portability. +Functions given in the ANSI headers may be missing from +some local C libraries (e.g., wide-character functions) +or may not correspond exactly to the local versions; +for example, the ANSI standard +stdio.h +specifies that +.IR printf , +.IR fprintf , +and +.I sprintf +return the number of characters written to the file or array, +but some existing libraries don't implement this convention. +.PP +On the MIPS and SPARC, old-style variadic functions must use +varargs.h +from MIPS or Sun. New-style is recommended. +.PP +With +.BR \-b , +files compiled +.I without +.B \-b +may cause +.I bprint +to print erroneous call graphs. +For example, if +.B f +calls +.B g +calls +.B h +and +.B f +and +.B h +are compiled with +.BR \-b , +but +.B g +is not, +.B bprint +will report that +.B f +called +.BR h . +The total number of calls is correct, however. diff --git a/src/cmd/lcc/lcc.c b/src/cmd/lcc/lcc.c new file mode 100644 index 0000000..ff13013 --- /dev/null +++ b/src/cmd/lcc/lcc.c @@ -0,0 +1,821 @@ +/* + * lcc [ option ]... [ file | -llib ]... + * front end for the ANSI C compiler + */ +static char rcsid[] = "$Id: lcc.c,v 4.33 2001/06/28 22:19:58 drh Exp $"; + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef TEMPDIR +#define TEMPDIR "/tmp" +#endif + +typedef struct list *List; +struct list { /* circular list nodes: */ + char *str; /* option or file name */ + List link; /* next list element */ +}; + +static void *alloc(int); +static List append(char *,List); +extern char *basepath(char *); +static int callsys(char *[]); +extern char *concat(char *, char *); +static int compile(char *, char *); +static void compose(char *[], List, List, List); +static void error(char *, char *); +static char *exists(char *); +static char *first(char *); +static int filename(char *, char *); +static List find(char *, List); +static void help(void); +static void initinputs(void); +static void interrupt(int); +static void opt(char *); +static List path2list(const char *); +extern int main(int, char *[]); +extern char *replace(const char *, int, int); +static void rm(List); +extern char *strsave(const char *); +extern char *stringf(const char *, ...); +extern int suffix(char *, char *[], int); +extern char *tempname(char *); + +extern int getpid(void); + +extern char *cpp[], *include[], *com[], *as[],*ld[], inputs[], *suffixes[]; +extern int option(char *); + +static int errcnt; /* number of errors */ +static int Eflag; /* -E specified */ +static int Sflag; /* -S specified */ +static int cflag; /* -c specified */ +static int verbose; /* incremented for each -v */ +static List llist[2]; /* loader files, flags */ +static List alist; /* assembler flags */ +static List clist; /* compiler flags */ +static List plist; /* preprocessor flags */ +static List ilist; /* list of additional includes from LCCINPUTS */ +static List rmlist; /* list of files to remove */ +static char *outfile; /* ld output file or -[cS] object file */ +static int ac; /* argument count */ +static char **av; /* argument vector */ +char *tempdir = TEMPDIR; /* directory for temporary files */ +static char *progname; +static List lccinputs; /* list of input directories */ + +int main(int argc, char *argv[]) +{ + int i, j, nf; + + progname = argv[0]; + ac = argc + 50; + av = alloc(ac*sizeof(char *)); + if (signal(SIGINT, SIG_IGN) != SIG_IGN) + signal(SIGINT, interrupt); + if (signal(SIGTERM, SIG_IGN) != SIG_IGN) + signal(SIGTERM, interrupt); +#ifdef SIGHUP + if (signal(SIGHUP, SIG_IGN) != SIG_IGN) + signal(SIGHUP, interrupt); +#endif + if (getenv("TMP")) + tempdir = getenv("TMP"); + else if (getenv("TEMP")) + tempdir = getenv("TEMP"); + else if (getenv("TMPDIR")) + tempdir = getenv("TMPDIR"); + assert(tempdir); + i = strlen(tempdir); + for (; i > 0 && (tempdir[i-1] == '/' || tempdir[i-1] == '\\'); i--) + tempdir[i-1] = '\0'; + if (argc <= 1) { + help(); + exit(0); + } + plist = append("-D__LCC__", 0); + initinputs(); + if (getenv("LCCDIR")) + option(stringf("-lccdir=%s", getenv("LCCDIR"))); + for (nf = 0, i = j = 1; i < argc; i++) { + if (strcmp(argv[i], "-o") == 0) { + if (++i < argc) { + if (suffix(argv[i], suffixes, 2) >= 0) { + error("-o would overwrite %s", argv[i]); + exit(8); + } + outfile = argv[i]; + continue; + } else { + error("unrecognized option `%s'", argv[i-1]); + exit(8); + } + } else if (strcmp(argv[i], "-target") == 0) { + if (argv[i+1] && *argv[i+1] != '-') + i++; + continue; + } else if (*argv[i] == '-' && argv[i][1] != 'l') { + opt(argv[i]); + continue; + } else if (*argv[i] != '-' && suffix(argv[i], suffixes, 3) >= 0) + nf++; + argv[j++] = argv[i]; + } + if ((cflag || Sflag) && outfile && nf != 1) { + fprintf(stderr, "%s: -o %s ignored\n", progname, outfile); + outfile = 0; + } + argv[j] = 0; + for (i = 0; include[i]; i++) + plist = append(include[i], plist); + if (ilist) { + List b = ilist; + do { + b = b->link; + plist = append(b->str, plist); + } while (b != ilist); + } + ilist = 0; + for (i = 1; argv[i]; i++) + if (strcmp(argv[i], "-l") == 0 && argv[i+1] && *argv[i+1] != '-') { /* -l file */ + llist[1] = append(argv[i++], llist[1]); + llist[1] = append(argv[i], llist[1]); + } else if (*argv[i] == '-') + opt(argv[i]); + else { + char *name = exists(argv[i]); + if (name) { + if (strcmp(name, argv[i]) != 0 || + (nf > 1 && suffix(name, suffixes, 3) >= 0)) + fprintf(stderr, "%s:\n", name); + filename(name, 0); + } else + error("can't find `%s'", argv[i]); + } + if (errcnt == 0 && !Eflag && !Sflag && !cflag && llist[1]) { + compose(ld, llist[0], llist[1], + append(outfile ? outfile : concat("a", first(suffixes[4])), 0)); + if (callsys(av)) + errcnt++; + } + rm(rmlist); + return errcnt ? EXIT_FAILURE : EXIT_SUCCESS; +} + +/* alloc - allocate n bytes or die */ +static void *alloc(int n) { + static char *avail, *limit; + + n = (n + sizeof(char *) - 1)&~(sizeof(char *) - 1); + if (n >= limit - avail) { + avail = malloc(n + 4*1024); + assert(avail); + limit = avail + n + 4*1024; + } + avail += n; + return avail - n; +} + +/* append - append a node with string str onto list, return new list */ +static List append(char *str, List list) { + List p = alloc(sizeof *p); + + p->str = str; + if (list) { + p->link = list->link; + list->link = p; + } else + p->link = p; + return p; +} + +/* basepath - return base name for name, e.g. /usr/drh/foo.c => foo */ +char *basepath(char *name) { + char *s, *b, *t = 0; + + for (b = s = name; *s; s++) + if (*s == '/' || *s == '\\') { + b = s + 1; + t = 0; + } else if (*s == '.') + t = s; + s = strsave(b); + if (t) + s[t-b] = 0; + return s; +} + +#ifdef WIN32 +#include +#else +#include +#define _P_WAIT 0 + +//extern int fork(void); +//extern int wait(int *); +//extern void execv(const char *, char *[]); + +static int _spawnvp(int mode, const char *cmdname, const char *const argv[]) { + int pid, n, status; + + switch (pid = fork()) { + case -1: + fprintf(stderr, "%s: no more processes\n", progname); + return 100; + case 0: + execv(cmdname, (char **)argv); + fprintf(stderr, "%s: ", progname); + perror(cmdname); + fflush(stdout); + exit(100); + } + while ((n = wait(&status)) != pid && n != -1) + ; + if (n == -1) + status = -1; + if (status&0377) { + fprintf(stderr, "%s: fatal error in %s\n", progname, cmdname); + status |= 0400; + } + return (status>>8)&0377; +} +#endif + +/* callsys - execute the command described by av[0...], return status */ +static int callsys(char **av) { + int i, status = 0; + static char **argv; + static int argc; + + for (i = 0; av[i] != NULL; i++) + ; + if (i + 1 > argc) { + argc = i + 1; + if (argv == NULL) + argv = malloc(argc*sizeof *argv); + else + argv = realloc(argv, argc*sizeof *argv); + assert(argv); + } + for (i = 0; status == 0 && av[i] != NULL; ) { + int j = 0; + char *s = 0; + for ( ; av[i] != NULL && (s = strchr(av[i], '\n')) == NULL; i++) + argv[j++] = av[i]; + if (s != NULL) { + if (s > av[i]) + argv[j++] = stringf("%.*s", s - av[i], av[i]); + if (s[1] != '\0') + av[i] = s + 1; + else + i++; + } + argv[j] = NULL; + if (verbose > 0) { + int k; + fprintf(stderr, "%s", argv[0]); + for (k = 1; argv[k] != NULL; k++) + fprintf(stderr, " %s", argv[k]); + fprintf(stderr, "\n"); + } + if (verbose < 2) + status = _spawnvp(_P_WAIT, argv[0], (const char * const *)argv); + if (status == -1) { + fprintf(stderr, "%s: ", progname); + perror(argv[0]); + } + } + return status; +} + +/* concat - return concatenation of strings s1 and s2 */ +char *concat(char *s1, char *s2) { + int n = strlen(s1); + char *s = alloc(n + strlen(s2) + 1); + + strcpy(s, s1); + strcpy(s + n, s2); + return s; +} + +/* compile - compile src into dst, return status */ +static int compile(char *src, char *dst) { + compose(com, clist, append(src, 0), append(dst, 0)); + return callsys(av); +} + +/* compose - compose cmd into av substituting a, b, c for $1, $2, $3, resp. */ +static void compose(char *cmd[], List a, List b, List c) { + int i, j; + List lists[3]; + + lists[0] = a; + lists[1] = b; + lists[2] = c; + for (i = j = 0; cmd[i]; i++) { + char *s = strchr(cmd[i], '$'); + if (s && isdigit(s[1])) { + int k = s[1] - '0'; + assert(k >=1 && k <= 3); + if ((b = lists[k-1])) { + b = b->link; + av[j] = alloc(strlen(cmd[i]) + strlen(b->str) - 1); + strncpy(av[j], cmd[i], s - cmd[i]); + av[j][s-cmd[i]] = '\0'; + strcat(av[j], b->str); + strcat(av[j++], s + 2); + while (b != lists[k-1]) { + b = b->link; + assert(j < ac); + av[j++] = b->str; + }; + } + } else if (*cmd[i]) { + assert(j < ac); + av[j++] = cmd[i]; + } + } + av[j] = NULL; +} + +/* error - issue error msg according to fmt, bump error count */ +static void error(char *fmt, char *msg) { + fprintf(stderr, "%s: ", progname); + fprintf(stderr, fmt, msg); + fprintf(stderr, "\n"); + errcnt++; +} + +/* exists - if `name' readable return its path name or return null */ +static char *exists(char *name) { + List b; + + if ( (name[0] == '/' || name[0] == '\\' || name[2] == ':') + && access(name, 4) == 0) + return name; + if (!(name[0] == '/' || name[0] == '\\' || name[2] == ':') + && (b = lccinputs)) + do { + b = b->link; + if (b->str[0]) { + char buf[1024]; + sprintf(buf, "%s/%s", b->str, name); + if (access(buf, 4) == 0) + return strsave(buf); + } else if (access(name, 4) == 0) + return name; + } while (b != lccinputs); + if (verbose > 1) + return name; + return 0; +} + +/* first - return first component in semicolon separated list */ +static char *first(char *list) { + char *s = strchr(list, ';'); + + if (s) { + char buf[1024]; + strncpy(buf, list, s-list); + buf[s-list] = '\0'; + return strsave(buf); + } else + return list; +} + +/* filename - process file name argument `name', return status */ +static int filename(char *name, char *base) { + int status = 0; + static char *stemp, *itemp; + + if (base == 0) + base = basepath(name); + switch (suffix(name, suffixes, 4)) { + case 0: /* C source files */ + compose(cpp, plist, append(name, 0), 0); + if (Eflag) { + status = callsys(av); + break; + } + if (itemp == NULL) + itemp = tempname(first(suffixes[1])); + compose(cpp, plist, append(name, 0), append(itemp, 0)); + status = callsys(av); + if (status == 0) + return filename(itemp, base); + break; + case 1: /* preprocessed source files */ + if (Eflag) + break; + if (Sflag) + status = compile(name, outfile ? outfile : concat(base, first(suffixes[2]))); + else if ((status = compile(name, stemp?stemp:(stemp=tempname(first(suffixes[2]))))) == 0) + return filename(stemp, base); + break; + case 2: /* assembly language files */ + if (Eflag) + break; + if (!Sflag) { + char *ofile; + if (cflag && outfile) + ofile = outfile; + else if (cflag) + ofile = concat(base, first(suffixes[3])); + else + ofile = tempname(first(suffixes[3])); + compose(as, alist, append(name, 0), append(ofile, 0)); + status = callsys(av); + if (!find(ofile, llist[1])) + llist[1] = append(ofile, llist[1]); + } + break; + case 3: /* object files */ + if (!find(name, llist[1])) + llist[1] = append(name, llist[1]); + break; + default: + if (Eflag) { + compose(cpp, plist, append(name, 0), 0); + status = callsys(av); + } + llist[1] = append(name, llist[1]); + break; + } + if (status) + errcnt++; + return status; +} + +/* find - find 1st occurrence of str in list, return list node or 0 */ +static List find(char *str, List list) { + List b; + + if ((b = list)) + do { + if (strcmp(str, b->str) == 0) + return b; + } while ((b = b->link) != list); + return 0; +} + +/* help - print help message */ +static void help(void) { + static char *msgs[] = { +"", " [ option | file ]...\n", +" except for -l, options are processed left-to-right before files\n", +" unrecognized options are taken to be linker options\n", +"-A warn about nonANSI usage; 2nd -A warns more\n", +"-b emit expression-level profiling code; see bprint(1)\n", +#ifdef sparc +"-Bstatic -Bdynamic specify static or dynamic libraries\n", +#endif +"-Bdir/ use the compiler named `dir/rcc'\n", +"-c compile only\n", +"-dn set switch statement density to `n'\n", +"-Dname -Dname=def define the preprocessor symbol `name'\n", +"-E run only the preprocessor on the named C programs and unsuffixed files\n", +"-g produce symbol table information for debuggers\n", +"-help or -? print this message on standard error\n", +"-Idir add `dir' to the beginning of the list of #include directories\n", +"-lx search library `x'\n", +"-M emit makefile dependencies; implies -E\n", +"-N do not search the standard directories for #include files\n", +"-n emit code to check for dereferencing zero pointers\n", +"-O is ignored\n", +"-o file leave the output in `file'\n", +"-P print ANSI-style declarations for globals on standard error\n", +"-p -pg emit profiling code; see prof(1) and gprof(1)\n", +"-S compile to assembly language\n", +"-static specify static libraries (default is dynamic)\n", +"-dynamic specify dynamically linked libraries\n", +"-t -tname emit function tracing calls to printf or to `name'\n", +"-target name is ignored\n", +"-tempdir=dir place temporary files in `dir/'", "\n" +"-Uname undefine the preprocessor symbol `name'\n", +"-v show commands as they are executed; 2nd -v suppresses execution\n", +"-w suppress warnings\n", +"-Woarg specify system-specific `arg'\n", +"-W[pfal]arg pass `arg' to the preprocessor, compiler, assembler, or linker\n", + 0 }; + int i; + char *s; + + msgs[0] = progname; + for (i = 0; msgs[i]; i++) { + fprintf(stderr, "%s", msgs[i]); + if (strncmp("-tempdir", msgs[i], 8) == 0 && tempdir) + fprintf(stderr, "; default=%s", tempdir); + } +#define xx(v) if ((s = getenv(#v))) fprintf(stderr, #v "=%s\n", s) + xx(LCCINPUTS); + xx(LCCDIR); +#ifdef WIN32 + xx(include); + xx(lib); +#endif +#undef xx +} + +/* initinputs - if LCCINPUTS or include is defined, use them to initialize various lists */ +static void initinputs(void) { + char *s = getenv("LCCINPUTS"); + List b; + + if (s == 0 && (s = inputs)[0] == 0) + s = "."; + if (s) { + lccinputs = path2list(s); + if ((b = lccinputs)) + do { + b = b->link; + if (strcmp(b->str, ".") != 0) { + ilist = append(concat("-I", b->str), ilist); + if (strstr(com[1], "win32") == NULL) + llist[0] = append(concat("-L", b->str), llist[0]); + } else + b->str = ""; + } while (b != lccinputs); + } +#ifdef WIN32 + List list; + if (list = b = path2list(getenv("include"))) + do { + int n; + b = b->link; + n = strlen(b->str); + if (b->str[n-1] == '\\') + b->str[n-1] = '/'; + ilist = append(stringf("-I\"%s\"", b->str), ilist); + } while (b != list); +#endif +} + +/* interrupt - catch interrupt signals */ +static void interrupt(int n) { + rm(rmlist); + exit(n = 100); +} + +/* opt - process option in arg */ +static void opt(char *arg) { + switch (arg[1]) { /* multi-character options */ + case 'W': /* -Wxarg */ + if (arg[2] && arg[3]) + switch (arg[2]) { + case 'o': + if (option(&arg[3])) + return; + break; + case 'p': + plist = append(&arg[3], plist); + return; + case 'f': + if (strcmp(&arg[3], "-C") == 0 && !option("-b")) + break; /* -C requires that -b is supported */ + clist = append(&arg[3], clist); + if (strcmp(&arg[3], "-unsigned_char=1") == 0) { + plist = append("-D__CHAR_UNSIGNED__", plist); + plist = append("-U_CHAR_IS_SIGNED", plist); + } +#define xx(name,k) \ + if (strcmp(&arg[3], "-wchar_t=" #name) == 0) \ + plist = append("-D_WCHAR_T_SIZE=" #k, plist); +xx(unsigned_char,1) +xx(unsigned_short,2) +xx(unsigned_int,4) +#undef xx + return; + case 'a': + alist = append(&arg[3], alist); + return; + case 'l': + llist[0] = append(&arg[3], llist[0]); + return; + } + fprintf(stderr, "%s: %s ignored\n", progname, arg); + return; + case 'd': /* -dn -dynamic */ + if (strcmp(arg, "-dynamic") == 0) { + if (!option(arg)) + fprintf(stderr, "%s: %s ignored\n", progname, arg); + } else { + arg[1] = 's'; + clist = append(arg, clist); + } + return; + case 't': /* -t -tname -tempdir=dir */ + if (strncmp(arg, "-tempdir=", 9) == 0) + tempdir = arg + 9; + else + clist = append(arg, clist); + return; + case 'p': /* -p -pg */ + if (option(arg)) + clist = append(arg, clist); + else + fprintf(stderr, "%s: %s ignored\n", progname, arg); + return; + case 'D': /* -Dname -Dname=def */ + case 'U': /* -Uname */ + case 'I': /* -Idir */ + plist = append(arg, plist); + return; + case 'B': /* -Bdir -Bstatic -Bdynamic */ +#ifdef sparc + if (strcmp(arg, "-Bstatic") == 0 || strcmp(arg, "-Bdynamic") == 0) + llist[1] = append(arg, llist[1]); + else +#endif + { + static char *path; + if (path) + error("-B overwrites earlier option", 0); + path = arg + 2; + if (strstr(com[1], "win32") != NULL) + com[0] = concat(replace(path, '/', '\\'), concat("rcc", first(suffixes[4]))); + else + com[0] = concat(path, "rcc"); + if (path[0] == 0) + error("missing directory in -B option", 0); + } + return; + case 'h': + if (strcmp(arg, "-help") == 0) { + static int printed = 0; + case '?': + if (!printed) + help(); + printed = 1; + return; + } + break; + case 's': + if (strcmp(arg, "-static") == 0) { + if (!option(arg)) + fprintf(stderr, "%s: %s ignored\n", progname, arg); + return; + } + break; + } + if (arg[2] == 0) + switch (arg[1]) { /* single-character options */ + case 'S': + Sflag++; + return; + case 'O': + fprintf(stderr, "%s: %s ignored\n", progname, arg); + return; + case 'A': case 'n': case 'w': case 'P': + clist = append(arg, clist); + return; + case 'g': case 'b': + if (option(arg)) + clist = append(arg[1] == 'g' ? "-g2" : arg, clist); + else + fprintf(stderr, "%s: %s ignored\n", progname, arg); + return; + case 'G': + if (option(arg)) { + clist = append("-g3", clist); + llist[0] = append("-N", llist[0]); + } else + fprintf(stderr, "%s: %s ignored\n", progname, arg); + return; + case 'E': + Eflag++; + return; + case 'c': + cflag++; + return; + case 'M': + Eflag++; /* -M implies -E */ + plist = append(arg, plist); + return; + case 'N': + if (strcmp(basepath(cpp[0]), "gcc-cpp") == 0) + plist = append("-nostdinc", plist); + include[0] = 0; + ilist = 0; + return; + case 'v': + if (verbose++ == 0) { + if (strcmp(basepath(cpp[0]), "gcc-cpp") == 0) + plist = append(arg, plist); + clist = append(arg, clist); + fprintf(stderr, "%s %s\n", progname, rcsid); + } + return; + } + if (cflag || Sflag || Eflag) + fprintf(stderr, "%s: %s ignored\n", progname, arg); + else + llist[1] = append(arg, llist[1]); +} + +/* path2list - convert a colon- or semicolon-separated list to a list */ +static List path2list(const char *path) { + List list = NULL; + char sep = ':'; + + if (path == NULL) + return NULL; + if (strchr(path, ';')) + sep = ';'; + while (*path) { + char *p, buf[512]; + if ((p = strchr(path, sep))) { + assert(p - path < sizeof buf); + strncpy(buf, path, p - path); + buf[p-path] = '\0'; + } else { + assert(strlen(path) < sizeof buf); + strcpy(buf, path); + } + if (!find(buf, list)) + list = append(strsave(buf), list); + if (p == 0) + break; + path = p + 1; + } + return list; +} + +/* replace - copy str, then replace occurrences of from with to, return the copy */ +char *replace(const char *str, int from, int to) { + char *s = strsave(str), *p = s; + + for ( ; (p = strchr(p, from)) != NULL; p++) + *p = to; + return s; +} + +/* rm - remove files in list */ +static void rm(List list) { + if (list) { + List b = list; + if (verbose) + fprintf(stderr, "rm"); + do { + if (verbose) + fprintf(stderr, " %s", b->str); + if (verbose < 2) + remove(b->str); + } while ((b = b->link) != list); + if (verbose) + fprintf(stderr, "\n"); + } +} + +/* strsave - return a saved copy of string str */ +char *strsave(const char *str) { + return strcpy(alloc(strlen(str)+1), str); +} + +/* stringf - format and return a string */ +char *stringf(const char *fmt, ...) { + char buf[1024]; + va_list ap; + + va_start(ap, fmt); + vsprintf(buf, fmt, ap); + va_end(ap); + return strsave(buf); +} + +/* suffix - if one of tails[0..n-1] holds a proper suffix of name, return its index */ +int suffix(char *name, char *tails[], int n) { + int i, len = strlen(name); + + for (i = 0; i < n; i++) { + char *s = tails[i], *t; + for (; (t = strchr(s, ';')); s = t + 1) { + int m = t - s; + if (len > m && strncmp(&name[len-m], s, m) == 0) + return i; + } + if (*s) { + int m = strlen(s); + if (len > m && strncmp(&name[len-m], s, m) == 0) + return i; + } + } + return -1; +} + +/* tempname - generate a temporary file name in tempdir with given suffix */ +char *tempname(char *suffix) { + static int n; + char *name = stringf("%s/lcc%d%d%s", tempdir, getpid(), n++, suffix); + + if (strstr(com[1], "win32") != NULL) + name = replace(name, '/', '\\'); + rmlist = append(name, rmlist); + return name; +} diff --git a/src/cmd/lcc/linux.c b/src/cmd/lcc/linux.c new file mode 100644 index 0000000..b1a78f3 --- /dev/null +++ b/src/cmd/lcc/linux.c @@ -0,0 +1,61 @@ +/* x86s running Linux */ + +#include + +static char rcsid[] = "$Id: linux.c,v 1.5 1998/09/16 20:41:09 drh Exp $"; + +#ifndef LCCDIR +#define LCCDIR "/usr/local/lib/lcc/" +#endif + +char *suffixes[] = { ".c", ".i", ".s", ".o", ".out", 0 }; +char inputs[256] = ""; +char *cpp[] = { LCCDIR "gcc/cpp", + "-U__GNUC__", "-D_POSIX_SOURCE", "-D__STDC__=1", "-D__STRICT_ANSI__", + "-Dunix", "-Di386", "-Dlinux", + "-D__unix__", "-D__i386__", "-D__linux__", "-D__signed__=signed", + "$1", "$2", "$3", 0 }; +char *include[] = {"-I" LCCDIR "include", "-I" LCCDIR "gcc/include", "-I/usr/include", 0 }; +char *com[] = {LCCDIR "rcc", "-target=x86/linux", "$1", "$2", "$3", 0 }; +char *as[] = { "/usr/bin/as", "-o", "$3", "$1", "$2", 0 }; +char *ld[] = { + /* 0 */ "/usr/bin/ld", "-m", "elf_i386", "-dynamic-linker", + /* 4 */ "/lib/ld-linux.so.2", "-o", "$3", + /* 7 */ "/usr/lib/crt1.o", "/usr/lib/crti.o", + /* 9 */ LCCDIR "/gcc/crtbegin.o", + "$1", "$2", + /* 12 */ "-L" LCCDIR, + /* 13 */ "-llcc", + /* 14 */ "-L" LCCDIR "/gcc", "-lgcc", "-lc", "-lm", + /* 18 */ "", + /* 19 */ LCCDIR "/gcc/crtend.o", "/usr/lib/crtn.o", + 0 }; + +extern char *concat(char *, char *); + +int option(char *arg) { + if (strncmp(arg, "-lccdir=", 8) == 0) { + cpp[0] = concat(&arg[8], "/gcc/cpp"); + include[0] = concat("-I", concat(&arg[8], "/include")); + include[1] = concat("-I", concat(&arg[8], "/gcc/include")); + ld[9] = concat(&arg[8], "/gcc/crtbegin.o"); + ld[12] = concat("-L", &arg[8]); + ld[14] = concat("-L", concat(&arg[8], "/gcc")); + ld[19] = concat(&arg[8], "/gcc/crtend.o"); + com[0] = concat(&arg[8], "/rcc"); + } else if (strcmp(arg, "-p") == 0 || strcmp(arg, "-pg") == 0) { + ld[7] = "/usr/lib/gcrt1.o"; + ld[18] = "-lgmon"; + } else if (strcmp(arg, "-b") == 0) + ; + else if (strcmp(arg, "-g") == 0) + ; + else if (strncmp(arg, "-ld=", 4) == 0) + ld[0] = &arg[4]; + else if (strcmp(arg, "-static") == 0) { + ld[3] = "-static"; + ld[4] = ""; + } else + return 0; + return 1; +} diff --git a/src/cmd/lcc/ops.c b/src/cmd/lcc/ops.c new file mode 100644 index 0000000..1462490 --- /dev/null +++ b/src/cmd/lcc/ops.c @@ -0,0 +1,60 @@ +/* + * ops [ {csilhfdxp}=n ]... + * + * prints lcc dag operator set for a given set of type sizes. + */ +#include "../lccom/c.h" + +static char list[] = { 'c', 's', 'i', 'l', 'h', 'f', 'd', 'x', 'p', 0 }; +static int sizes[] = { 1, 2, 4, 4, 8, 4, 8, 16, 8 }; + +static int doop(int op, int type, const char *sz, const char *opname) { + int count = 0; + static int last; + + if (op == LOAD) + return 0; + if (last != 0 && last != op) + printf("\n"); + last = op; + if (type == B || type == V) { + printf(" %s=%d", opname, op + type); + count++; + } else { + int i, done = 0; + const char *s; + for (i = 0; sz[i] != '\0' && (s = strchr(list, sz[i])) != NULL; i++) { + int n = sizes[s-list]; + if ((done&(1< 0 && (s = strchr(list, c)) != NULL) + sizes[s-list] = n; + else { + fprintf(stderr, "usage: %s [ {csilhfdxp}=n ]...\n", argv[0]); + exit(EXIT_FAILURE); + } + } +#define gop(x,n) +#define op(x,t,s) count += doop(x,t,#s,#x #t); +#include "../lccom/ops.h" +#undef gop +#undef op + fprintf(stderr, "%d operators\n", count); + return EXIT_SUCCESS; +} diff --git a/src/cmd/lcc/osf.c b/src/cmd/lcc/osf.c new file mode 100644 index 0000000..911b6c1 --- /dev/null +++ b/src/cmd/lcc/osf.c @@ -0,0 +1,54 @@ +/* DEC ALPHAs running OSF/1 V3.2A (Rev. 17) at Princeton University */ + +#include + +static char rcsid[] = "$Id: osf.c,v 1.8 1997/05/26 22:34:10 drh Exp $"; + +#ifndef LCCDIR +#define LCCDIR "/usr/local/lib/lcc/" +#endif + +char *suffixes[] = { ".c", ".i", ".s", ".o", ".out", 0 }; +char inputs[256] = ""; +char *cpp[] = { + LCCDIR "cpp", "-D__STDC__=1", + "-DLANGUAGE_C", "-D__LANGUAGE_C__", + "-D_unix", "-D__unix__", "-D_osf", "-D__osf__", "-Dunix", + "-Dalpha", "-D_alpha", "-D__alpha", + "-D__SYSTYPE_BSD", "-D_SYSTYPE_BSD", + "$1", "$2", "$3", 0 }; +char *com[] = { LCCDIR "rcc", "-target=alpha/osf", "$1", "$2", "$3", "", 0 }; +char *include[] = { "-I" LCCDIR "include", "-I/usr/local/include", + "-I/usr/include", 0 }; +char *as[] = { "/bin/as", "-o", "$3", "", "$1", "-nocpp", "$2", 0 }; +char *ld[] = { "/usr/bin/ld", "-o", "$3", "/usr/lib/cmplrs/cc/crt0.o", + "$1", "$2", "", "", "-L" LCCDIR, "-llcc", "-lm", "-lc", 0 }; + +extern char *concat(char *, char *); +extern int access(const char *, int); + +int option(char *arg) { + if (strncmp(arg, "-lccdir=", 8) == 0) { + cpp[0] = concat(&arg[8], "/cpp"); + include[0] = concat("-I", concat(&arg[8], "/include")); + com[0] = concat(&arg[8], "/rcc"); + ld[8] = concat("-L", &arg[8]); + } else if (strcmp(arg, "-g4") == 0 + && access("/u/drh/lib/alpha/rcc", 4) == 0 + && access("/u/drh/book/cdb/alpha/osf/cdbld", 4) == 0) { + com[0] = "/u/drh/lib/alpha/rcc"; + com[5] = "-g4"; + ld[0] = "/u/drh/book/cdb/alpha/osf/cdbld"; + ld[1] = "-o"; + ld[2] = "$3"; + ld[3] = "$1"; + ld[4] = "$2"; + ld[5] = 0; + } else if (strcmp(arg, "-g") == 0) + return 1; + else if (strcmp(arg, "-b") == 0) + ; + else + return 0; + return 1; +} diff --git a/src/cmd/lcc/retrobsd.c b/src/cmd/lcc/retrobsd.c new file mode 100644 index 0000000..f044417 --- /dev/null +++ b/src/cmd/lcc/retrobsd.c @@ -0,0 +1,79 @@ +/* SGI big endian MIPSes running IRIX 6.2 at CS Dept., Princeton University */ + +#include + +#ifndef LCCDIR +#define LCCDIR "/lib/lcc/" +#endif +#ifndef LIBDIR +#define LIBDIR "/lib/" +#endif + +char *suffixes[] = { ".c", ".i", ".s", ".o", ".out", 0 }; + +char inputs[256] = ""; + +char *cpp[] = { + "/bin/lcpp", + "-D__STDC__=1", + "-DLANGUAGE_C", + "-DMIPSEB", + "-D_CFE", + "-D_LANGUAGE_C", + "-D_MIPSEB", + "-D_MIPS_FPSET=16", + "-D_MIPS_ISA=_MIPS_ISA_MIPS1", + "-D_MIPS_SIM=_MIPS_SIM_ABI32", + "-D_MIPS_SZINT=32", + "-D_MIPS_SZLONG=32", + "-D_MIPS_SZPTR=32", + "-D__host_mips", + "-D__mips=1", + "-D__retrobsd", + "-D__unix", + "-Dhost_mips", + "-Dmips", + "-Dunix", + "$1", "$2", "$3", +0 }; + +char *com[] = { + "/libexec/lccom", "-target=mips/eb", "$1", "$2", "$3", "", +0 }; + +char *include[] = { + "-I/include", + "-I/include/lcc", +0 }; + +char *as[] = { + "/bin/as", "-o", "$3", "$1", "$2", +0 }; + +char *ld[] = { + "/bin/ld", "-o", "$3", LIBDIR "crt0.o", + "$1", "$2", "", "-L" LCCDIR, "-llcc", "-lc", +0 }; + +extern char *concat (char *, char *); + +int option (char *arg) +{ + if (strncmp(arg, "-lccdir=", 8) == 0) { + cpp[0] = concat(&arg[8], "/cpp"); + include[0] = concat("-I", concat(&arg[8], "/include")); + com[0] = concat(&arg[8], "/rcc"); + ld[6] = concat("-L", &arg[8]); + + } else if (strcmp(arg, "-g") == 0) { + ; + } else if (strcmp(arg, "-p") == 0) { + ld[3] = LIBDIR "mcrt1.o"; + + } else if (strcmp(arg, "-b") == 0) { + ; + } else + return 0; + + return 1; +} diff --git a/src/cmd/lcc/solaris.c b/src/cmd/lcc/solaris.c new file mode 100644 index 0000000..8921f42 --- /dev/null +++ b/src/cmd/lcc/solaris.c @@ -0,0 +1,51 @@ +/* SPARCs running Solaris 2.5.1 at CS Dept., Princeton University */ + +#include + +static char rcsid[] = "$Id: solaris.c,v 1.10 1998/09/14 20:36:33 drh Exp $"; + +#ifndef LCCDIR +#define LCCDIR "/usr/local/lib/lcc/" +#endif +#ifndef SUNDIR +#define SUNDIR "/opt/SUNWspro/SC4.2/lib/" +#endif + +char *suffixes[] = { ".c", ".i", ".s", ".o", ".out", 0 }; +char inputs[256] = ""; +char *cpp[] = { LCCDIR "cpp", + "-D__STDC__=1", "-Dsparc", "-D__sparc__", "-Dsun", "-D__sun__", "-Dunix", + "$1", "$2", "$3", 0 }; +char *include[] = { "-I" LCCDIR "include", "-I/usr/local/include", + "-I/usr/include", 0 }; +char *com[] = { LCCDIR "rcc", "-target=sparc/solaris", + "$1", "$2", "$3", 0 }; +char *as[] = { "/usr/ccs/bin/as", "-Qy", "-s", "-o", "$3", "$1", "$2", 0 }; +char *ld[] = { "/usr/ccs/bin/ld", "-o", "$3", "$1", + SUNDIR "crti.o", SUNDIR "crt1.o", + SUNDIR "values-xa.o", "$2", "", + "-Y", "P," SUNDIR ":/usr/ccs/lib:/usr/lib", "-Qy", + "-L" LCCDIR, "-llcc", "-lm", "-lc", SUNDIR "crtn.o", 0 }; + +extern char *concat(char *, char *); + +int option(char *arg) { + if (strncmp(arg, "-lccdir=", 8) == 0) { + cpp[0] = concat(&arg[8], "/cpp"); + include[0] = concat("-I", concat(&arg[8], "/include")); + ld[12] = concat("-L", &arg[8]); + com[0] = concat(&arg[8], "/rcc"); + } else if (strcmp(arg, "-g") == 0) + ; + else if (strcmp(arg, "-p") == 0) { + ld[5] = SUNDIR "mcrt1.o"; + ld[10] = "P," SUNDIR "libp:/usr/ccs/lib/libp:/usr/lib/libp:" + SUNDIR ":/usr/ccs/lib:/usr/lib"; + } else if (strcmp(arg, "-b") == 0) + ; + else if (strncmp(arg, "-ld=", 4) == 0) + ld[0] = &arg[4]; + else + return 0; + return 1; +} diff --git a/src/cmd/lcc/win32.c b/src/cmd/lcc/win32.c new file mode 100644 index 0000000..2be69d9 --- /dev/null +++ b/src/cmd/lcc/win32.c @@ -0,0 +1,41 @@ +/* x86s running MS Windows NT 4.0 */ + +#include + +static char rcsid[] = "$Id: win32.c,v 1.19 2001/07/09 18:00:13 drh Exp $"; + +#ifndef LCCDIR +#define LCCDIR "\\progra~1\\lcc\\4.1\\bin\\" +#endif + +char *suffixes[] = { ".c;.C", ".i;.I", ".asm;.ASM;.s;.S", ".obj;.OBJ", ".exe", 0 }; +char inputs[256] = ""; +char *cpp[] = { LCCDIR "cpp", "-D__STDC__=1", "-Dwin32", "-D_WIN32", "-D_M_IX86", + "$1", "$2", "$3", 0 }; +char *include[] = { "-I" LCCDIR "include", 0 }; +char *com[] = { LCCDIR "rcc", "-target=x86/win32", "$1", "$2", "$3", 0 }; +char *as[] = { "ml", "-nologo", "-c", "-Cp", "-coff", "-Fo$3", "$1", "$2", 0 }; +char *ld[] = { "link", "-nologo", + "", "-subsystem:console", "-entry:mainCRTStartup", + "$2", "-OUT:$3", "$1", LCCDIR "liblcc.lib", "oldnames.lib", "libc.lib", "kernel32.lib", 0 }; + +extern char *concat(char *, char *); +extern char *replace(const char *, int, int); + +int option(char *arg) { + if (strncmp(arg, "-lccdir=", 8) == 0) { + arg = replace(arg + 8, '/', '\\'); + if (arg[strlen(arg)-1] == '\\') + arg[strlen(arg)-1] = '\0'; + cpp[0] = concat(arg, "\\cpp.exe"); + include[0] = concat("-I", concat(arg, "\\include")); + com[0] = concat(arg, "\\rcc.exe"); + ld[8] = concat(arg, "\\liblcc.lib"); + } else if (strcmp(arg, "-b") == 0) + ; + else if (strncmp(arg, "-ld=", 4) == 0) + ld[0] = &arg[4]; + else + return 0; + return 1; +} diff --git a/src/cmd/lccom/CPYRIGHT b/src/cmd/lccom/CPYRIGHT new file mode 100644 index 0000000..342e697 --- /dev/null +++ b/src/cmd/lccom/CPYRIGHT @@ -0,0 +1,62 @@ +The authors of this software are Christopher W. Fraser and +David R. Hanson. + +Copyright (c) 1991,1992,1993,1994,1995,1996,1997,1998,1999,2000,2001,2002 +by AT&T, Christopher W. Fraser, and David R. Hanson. All Rights Reserved. + +Permission to use, copy, modify, and distribute this software for any +purpose, subject to the provisions described below, without fee is +hereby granted, provided that this entire notice is included in all +copies of any software that is or includes a copy or modification of +this software and in all copies of the supporting documentation for +such software. + +THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED +WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR AT&T MAKE ANY +REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY +OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. + + +lcc is not public-domain software, shareware, and it is not protected +by a `copyleft' agreement, like the code from the Free Software +Foundation. + +lcc is available free for your personal research and instructional use +under the `fair use' provisions of the copyright law. You may, however, +redistribute lcc in whole or in part provided you acknowledge its +source and include this CPYRIGHT file. You may, for example, include +the distribution in a CDROM of free software, provided you charge only +for the media, or mirror the distribution files at your site. + +You may not sell lcc or any product derived from it in which it is a +significant part of the value of the product. Using the lcc front end +to build a C syntax checker is an example of this kind of product. + +You may use parts of lcc in products as long as you charge for only +those components that are entirely your own and you acknowledge the use +of lcc clearly in all product documentation and distribution media. You +must state clearly that your product uses or is based on parts of lcc +and that lcc is available free of charge. You must also request that +bug reports on your product be reported to you. Using the lcc front +end to build a C compiler for the Motorola 88000 chip and charging for +and distributing only the 88000 code generator is an example of this +kind of product. + +Using parts of lcc in other products is more problematic. For example, +using parts of lcc in a C++ compiler could save substantial time and +effort and therefore contribute significantly to the profitability of +the product. This kind of use, or any use where others stand to make a +profit from what is primarily our work, requires a license agreement +with Addison-Wesley. Per-copy and unlimited use licenses are +available; for more information, contact + + Mike Hendrickson + Addison Wesley Professional + 75 Arlington St. + Boston, MA 02116 + 617/848-6522 FAX: 617/848-6569 mikeh@awl.com + +----- +Chris Fraser / cwfraser@microsoft.com +David Hanson / drh@microsoft.com +$Revision: 1.8 $ $Date: 2002/08/27 00:02:26 $ diff --git a/src/cmd/lccom/LOG b/src/cmd/lccom/LOG new file mode 100644 index 0000000..be23e1c --- /dev/null +++ b/src/cmd/lccom/LOG @@ -0,0 +1,383 @@ +From lcc 4.1 to 4.2: + +Below is a summary of the source-control log entries for those files +changed for lcc 4.2. +$Id: LOG,v 1.26 2002/08/26 23:59:51 drh Exp $ + +src/alloc.c: +Fixed subtle alignment bug on p. 28. + +src/dag.c: +Renamed kill to killnodes to avoid possible clash with kill in . + +Made address interface function optional. + +Ensured that generated locals, even if not temps, are +added to the code list. + +Avoided calls to undag when errcnt>0. + +Changed listnodes so that array types decay to pointers; bug +tickled by -n option. + +src/decl.c: +Moved call to retcode that injects a return at the end of a function +into compound so that temps created by retcode will be +scoped properly. + +Fixed bug in which functions that return const struct S {...} issued +an incorrect diagnostic. + +Ensure addressed is set for local arrays. + +src/enode.c: +Corrected type conversions in addtree for ADD+P nodes; +stripped qualifiers from pointer types in eqtree and cmptree. + +src/event.c: +Revise functions called at events so all have the same signature, +modulo pointer types. + +src/expr.c: +With -b, avoid instrumenting constant ?: expressions. + +Fixed bug in wide-character literals. + +Fix allocation error for identifiers injected to quell +undeclared identifier errors; +Correct int type added to addresses in field offsets. + +src/gen.c: +Made emitasm extern. + +src/input.c: +Fixed bug in resynch that caused infinite loop. + +Added #ident recognition, which simply ignores it. + +src/symbolic.c: +Revised symbolic back end to emit -0.0 correctly. + +Emit flags in symbolic output. + +src/bytecode.c: +Fixed double output botch in defconst in bytecode backend. + +src/dagcheck.c: +Added mssing cases in dagcheck's reduce for types signedptr +and unsignedptr. Without these, reduce can fail. + +src/lex.c: +Permit \ to escape newline in string literals. + +Fixed scon() so that it accepts and concatenates adjacent wide-character literals. + +src/main.c: +Fixed long-standing bug in which -n, -b, -C, and -a options caused +interface functions to be called before progbeg. + +src/mips.md: +Fixed FP comparisons to handle NaNs correctly. + +Round up framesize to a multiple of 16 for Irix 6.x; +added casts in defconst to discard unused bits. + +src/prof.c: +Revise functions called at events so all have the same signature, +modulo pointer types. + +Change ftype to build arbitrary prototypes. + +Fixed long-standing bug in which -n, -b, -C, and -a options caused +interface functions to be called before progbeg. +Also, added missing call to space. + +Relaxed assertion in loop that searches for +embedded CALL nodes. + +Emit correct padding in generated -b strutures. + +Revised call hook to find CALL nodes embedded +at any depth. + +Edited bbincr so that it doesn't inject increments in constant expressions. + +src/profio.c: +Change compare's prototype to conform to ANSI standard; +change calls to qsort accordingly. + +Fixed implicit assumption that execution point i in file f always +refers to the same x,y. This isn't true for noweb files. + +src/simp.c: +Made address interface function optional. + +Tighten test that avoids folding addressing expressions +for switch tables when the offset exceeds 16 bits. Without +this addition, lcc can emit erroneous "initializer must be +constant" diagnostics. + +Revised simplify() so that if doesn't call address to +fold (ADDGRP a n) when n exceeds 16 bits. + +Reordered tests in MOD+I case so expressions like 6%1 fold correctly. + +src/sparc.md: +Fixed FP comparisons to handle NaNs correctly. + +Added casts in defconst() to emit constants with proper sizes. + +Replaced pseudo-instructions st2/ld2 with pairs of st/ld instructions. + +src/stmt.c: +Fixed botch in 2.16 revision. + +Fixed return statement so that "return;" in a function that returns +a value returns 0. Similar code is already in decl.nw. + +Resynch to distributable version. + +Used dynamic variables for loop and switch handles. + +Fixed bug in which functions that return const struct S {...} issued +an incorrect diagnostic. + +Appended a missing \n to a warning. + +src/sym.c: +Revised 2.19's code for comparing -0.0 and 0.0 so that it works +correctly when long double's occupy more bytes than the actual +values, as on the x86 under gcc. +Fix constant() so that it treats -0.0 and +0.0 as different constants. + +Added newtable() to allocate empty symbol tables. + +src/trace.c: +Revise functions called at events so all have the same signature, +modulo pointer types. + +Change ftype to build arbitrary prototypes. + +Fixed long-standing bug in which -n, -b, -C, and -a options caused +interface functions to be called before progbeg. + +src/tree.c: +Correct revision 2.9's implementation of check to avoid +superfluous diagnostics on widening conversions. + +Avoid diagnostics for superfluous widening conversions. + +src/types.c: +Revise fieldmask definition so it works +for all values of fieldsize. + +Change ftype to build arbitrary prototypes. + +src/x86.md: +Fixed FP comparisons to handle NaNs correctly. + +Changed ARGB instruction sequence to decrement +esp by the size of the structure rounded up to 4. +Changed struct allignment to 1; this required changing local to +insure that on-stack structs are aligned to at least 4 bytes. + +Added cast in defconst to eliminate extraneous bits. + +Fixed float-to-int conversions so they truncate properly; +fixed assembler syntax errors on x86/linux. + +Fixed frame size adjustment for frames >= 4096; now calls _chkstk +to allocate large frames. + +Fixed overly specific opcode for loading constants. + +Changed add/sub to addl/subl in potentially ambiguous +instructions in the x86/linux back end. + +cpp/cpp.c: +Added line to fix Nelson Beebe's bug using #defined x X. + +cpp/cpp.h: +Revised to use stdio for output. + +Converted to use stdio for input. + +cpp/eval.c: +Added evaluation stack overflow checks. + +Included stdio.h. + +cpp/getopt.c: +Include ; cut decl. for strchr. + +cpp/hideset.c: +Fixed potential sizeof botches. + +cpp/include.c: +Revised to use stdio for output. + +Removed unused wd[]. + +Fixed incorrect check of fopen return value. + +Converted to use stdio for input. + +cpp/lex.c: +Fixed incorrect test of fd value; fixed comments. + +Converted to use stdio for input. + +cpp/macro.c: +Fixed obscure bug that occurs when string literals are stored +in read-only memory. -DX attempts to append a null byte to "1". +Found by Nelson Beebe. + +Converted to use stdio for input. + +cpp/nlist.c: +Removed unused wd[]. + +Added #ident; ignored as for #pragma. + +cpp/tokens.c: +Revised to use stdio for output. + +Fixed erroneous initialization and check of FILE * value. + +cpp/unix.c: +Revised to use stdio for output. + +Fixed erroneous initialization and check of FILE * value. + +Converted to use stdio for input. + +etc/irix.c: +Added -D_LONGLONG, because some SGI assume this. +Reported by Nelson Beebe. + +Added -32 option to insure O32 object files and libraries are used. + +etc/lcc.c: +Fixed -l file so that file doesn't have to exist. + +Changed \ to / at the end of Win32 include paths. + +Added casts and prototypes to make _spawnvp compatible +with Win32 version. + +Permit -dynamic -static on all systems, using option to check +for validity. +Edited help messages. + +Look for -Wf-unsigned_char=1 and added +-D__CHAR_IUNSIGNED__ and -U_CHAR_IS_SIGNED to the cpp +command line. These options interact with changes to the +standard header limits.h to set CHAR_MIN and CHAR_MAX correctly. +Look for -Wf-wchar_t=... and define _WCHAR_T_SIZE appropriately, +which interacts with stddef.h and stdlib.h to typedef wchar_t correctly. + +Fixed botch in initinputs that cleared LCCINPUTS. + +etc/win32.c: +Added oldnames.lib to link command. + +Cut useless -align directive in ld command. + +include/*/*/limits.h: +Corrected name: __CHAR_IS_UNSIGNED__ should be __CHAR_UNSIGNED__. + +Define CHAR_MIN/CHAR_MAX depending on defintion of __CHAR_IS_UNSIGNED__. + +include/*/*/locale.h: +Change NULL to ((void*)0). + +Protected definition of NULL; +defined NULL as 0L on osf systems. + +include/*/*/stdarg.h: +Fixed typedef for __va_list so it's protected by #ifdef. + +Fixed missing #endif; +protected definition of va_list by _VA_LIST_DEFINED. + +Changed the type of va_list. + +Insured only va_list was conditionally defined. + +Insured _VA_LIST is defined. + +Revised __va_arg macro to handle va_arg(float) correctly; +this addition required a static double temporary, which is +less than elegant and subject to order-of-evaluation bugs. + +include/*/*/stddef.h: +Change NULL to ((void*)0). + +Added _x_T_DEFINED flag macros for Windows compatibility. + +Added code to typedef wchar_t to unsigned char, short, or int +depending on the value of _WCHAR_T_SIZE. + +Protected definition of NULL; +defined NULL as 0L on osf systems. + +include/*/*/stdio.h: +Change NULL to ((void*)0). + +Added _x_T_DEFINED flag macros for Windows compatibility. + +Changed the type of va_list. + +Protected definition of size_t by _SIZE_T_DEFINED; +added definition for va_list protected by _VA_LIST. + +Protected definition of NULL; +defined NULL as 0L on osf systems. + +include/*/*/stdlib.h: +Change NULL to ((void*)0). + +Added _x_T_DEFINED flag macros for Windows compatibility. + +Added code to typedef wchar_t to unsigned char, short, or int +depending on the value of _WCHAR_T_SIZE. + +Protected definition of NULL; +defined NULL as 0L on osf systems. + +include/*/*/string.h: +Change NULL to ((void*)0). + +Added _x_T_DEFINED flag macros for Windows compatibility. + +Protected definition of NULL; +defined NULL as 0L on osf systems. + +include/*/*/time.h: +Change NULL to ((void*)0). + +Added _x_T_DEFINED flag macros for Windows compatibility. + +Protected definition of NULL; +defined NULL as 0L on osf systems. + +lburg/lburg.c: +Simplified use of va_arg to accommodate gcc bug. + +Added ()s to avoid bogus compilation error on Linux. + +lib/assert.c: +Added EXPORT and default definition. + +lib/bbexit.c: +Access _caller via indirection; add _setcallerp. + +Added EXPORT and default definition. + +Changed profiling counters to ints. + +lib/yynull.c: +Added EXPORT and default definition. + +tst/cq.c: +Added prototypes to function pointer initializations. diff --git a/src/cmd/lccom/Makefile b/src/cmd/lccom/Makefile new file mode 100644 index 0000000..c828b13 --- /dev/null +++ b/src/cmd/lccom/Makefile @@ -0,0 +1,141 @@ +# +# Makefile for lccom +# +TOPSRC = $(shell cd ../../..; pwd) +include $(TOPSRC)/target.mk +#include $(TOPSRC)/cross.mk +#CFLAGS = -O0 -g -DCROSS + +CFLAGS += -Wall -Werror -DNDEBUG +LDFLAGS += -g + +OBJS = $Balloc.o $Bbind.o $Bdag.o $Bdagcheck.o $Bdecl.o $Benode.o \ + $Berror.o $Bexpr.o $Bevent.o $Binit.o $Binits.o $Binput.o \ + $Blex.o $Blist.o $Boutput.o $Bprof.o $Bprofio.o \ + $Bsimp.o $Bstmt.o $Bstring.o $Bsym.o $Btrace.o $Btree.o \ + $Btypes.o $Bnull.o $Bsymbolic.o $Bgen.o $Bbytecode.o \ + $Bmain.o $Bmips.o + +TARGET = TARGET_MIPS +BUILDDIR = build +TSTDIR = tst/mips-eb +B = $(BUILDDIR)/ +T = $(TSTDIR)/ + +all: build $Blburg lccom liblcc.a + +clean: + rm -rf lccom *.a *.dis *~ $B $T/*.1 $T/*.2 $T/*.s + rm -f $T8q $Tarray $Tcf $Tcq $Tcvt $Tfields $Tfront $Tincr \ + $Tinit $Tlimits $Tparanoia $Tsort $Tspill $Tstdarg \ + $Tstruct $Tswitch $Twf1 $Tyacc + +install: all + install lccom $(DESTDIR)/libexec/ + +build: + mkdir -p $(BUILDDIR) + +# +# lccom: the C compiler +# +lccom: ${OBJS} + ${CC} ${LDFLAGS} -o lccom.elf ${OBJS} ${LIBS} + ${OBJDUMP} -S lccom.elf > lccom.dis + ${SIZE} lccom.elf + ${ELF2AOUT} lccom.elf $@ && rm lccom.elf + +$(OBJS): c.h ops.h token.h config.h + +$Balloc.o: alloc.c; $(CC) $(CFLAGS) -c -I. -o $@ $< +$Bbind.o: bind.c; $(CC) $(CFLAGS) -D$(TARGET) -c -I. -o $@ $< +$Bdag.o: dag.c; $(CC) $(CFLAGS) -c -I. -o $@ $< +$Bdecl.o: decl.c; $(CC) $(CFLAGS) -c -I. -o $@ $< +$Benode.o: enode.c; $(CC) $(CFLAGS) -c -I. -o $@ $< +$Berror.o: error.c; $(CC) $(CFLAGS) -c -I. -o $@ $< +$Bevent.o: event.c; $(CC) $(CFLAGS) -c -I. -o $@ $< +$Bexpr.o: expr.c; $(CC) $(CFLAGS) -c -I. -o $@ $< +$Bgen.o: gen.c; $(CC) $(CFLAGS) -c -I. -o $@ $< +$Binit.o: init.c; $(CC) $(CFLAGS) -c -I. -o $@ $< +$Binits.o: inits.c; $(CC) $(CFLAGS) -c -I. -o $@ $< +$Binput.o: input.c; $(CC) $(CFLAGS) -c -I. -o $@ $< +$Blex.o: lex.c; $(CC) $(CFLAGS) -c -I. -o $@ $< +$Blist.o: list.c; $(CC) $(CFLAGS) -c -I. -o $@ $< +$Bmain.o: main.c; $(CC) $(CFLAGS) -DVERSION=\"`svnversion`\" -c -I. -o $@ $< +$Bnull.o: null.c; $(CC) $(CFLAGS) -c -I. -o $@ $< +$Boutput.o: output.c; $(CC) $(CFLAGS) -c -I. -o $@ $< +$Bprof.o: prof.c; $(CC) $(CFLAGS) -c -I. -o $@ $< +$Bprofio.o: profio.c; $(CC) $(CFLAGS) -c -I. -o $@ $< +$Bsimp.o: simp.c; $(CC) $(CFLAGS) -c -I. -o $@ $< +$Bstmt.o: stmt.c; $(CC) $(CFLAGS) -c -I. -o $@ $< +$Bstring.o: string.c; $(CC) $(CFLAGS) -c -I. -o $@ $< +$Bsym.o: sym.c; $(CC) $(CFLAGS) -c -I. -o $@ $< +$Bsymbolic.o: symbolic.c; $(CC) $(CFLAGS) -c -I. -o $@ $< +$Bbytecode.o: bytecode.c; $(CC) $(CFLAGS) -c -I. -o $@ $< +$Btrace.o: trace.c; $(CC) $(CFLAGS) -c -I. -o $@ $< +$Btree.o: tree.c; $(CC) $(CFLAGS) -c -I. -o $@ $< +$Btypes.o: types.c; $(CC) $(CFLAGS) -c -I. -o $@ $< +$Bstab.o: stab.c stab.h; $(CC) $(CFLAGS) -c -I. -o $@ $< + +$Bdagcheck.o: $Bdagcheck.c; $(CC) $(CFLAGS) -c -I. -o $@ $< +$Balpha.o: $Balpha.c; $(CC) $(CFLAGS) -c -I. -o $@ $< +$Bmips.o: $Bmips.c; $(CC) $(CFLAGS) -c -I. -o $@ $< +$Bsparc.o: $Bsparc.c; $(CC) $(CFLAGS) -c -I. -o $@ $< +$Bx86.o: $Bx86.c; $(CC) $(CFLAGS) -c -I. -o $@ $< +$Bx86linux.o: $Bx86linux.c; $(CC) $(CFLAGS) -c -I. -o $@ $< + +$Bdagcheck.c: $Blburg dagcheck.md; $Blburg -n dagcheck.md $@ +$Balpha.c: $Blburg alpha.md; $Blburg alpha.md $@ +$Bmips.c: $Blburg mips.md; $Blburg mips.md $@ +$Bsparc.c: $Blburg sparc.md; $Blburg sparc.md $@ +$Bx86.c: $Blburg x86.md; $Blburg x86.md $@ +$Bx86linux.c: $Blburg x86linux.md; $Blburg x86linux.md $@ + +# +# lburg: code generator generator +# +$Blburg: $Blburg.o $Bgram.o + cc -g -o $@ $Blburg.o $Bgram.o + +$Blburg.o $Bgram.o: lburg/lburg.h + +$Blburg.o: lburg/lburg.c; cc -g -Wall -O -c -Ilburg -o $@ $< +$Bgram.o: lburg/gram.c; cc -g -Wall -O -c -Ilburg -o $@ $< + +# +# liblcc: run time library +# +LIBOBJS = $Bassert.o $Bbbexit.o $Byynull.o + +liblcc.a: $(LIBOBJS) + $(AR) ruv $@ $Bassert.o $Bbbexit.o $Byynull.o; $(RANLIB) $@ || true + +$Bassert.o: lib/assert.c; $(CC) $(CFLAGS) -c -o $@ $< +$Byynull.o: lib/yynull.c; $(CC) $(CFLAGS) -c -o $@ $< +$Bbbexit.o: lib/bbexit.c; $(CC) $(CFLAGS) -c -o $@ $< + +# +# Tests +# +test: $T8q.s $Tarray.s $Tcf.s $Tcq.s $Tcvt.s $Tfields.s $Tfront.s \ + $Tincr.s $Tinit.s $Tlimits.s $Tparanoia.s $Tsort.s \ + $Tspill.s $Tstdarg.s $Tstruct.s $Tswitch.s $Twf1.s $Tyacc.s + +$T8q.s: tst/8q.c tst/8q.0 all; @env BUILDDIR=$(BUILDDIR) TSTDIR=$(TSTDIR) tst/run.sh $@ +$Tarray.s: tst/array.c tst/array.0 all; @env BUILDDIR=$(BUILDDIR) TSTDIR=$(TSTDIR) tst/run.sh $@ +$Tcf.s: tst/cf.c tst/cf.0 all; @env BUILDDIR=$(BUILDDIR) TSTDIR=$(TSTDIR) tst/run.sh $@ +$Tcq.s: tst/cq.c tst/cq.0 all; @env BUILDDIR=$(BUILDDIR) TSTDIR=$(TSTDIR) tst/run.sh $@ +$Tcvt.s: tst/cvt.c tst/cvt.0 all; @env BUILDDIR=$(BUILDDIR) TSTDIR=$(TSTDIR) tst/run.sh $@ +$Tfields.s: tst/fields.c tst/fields.0 all; @env BUILDDIR=$(BUILDDIR) TSTDIR=$(TSTDIR) tst/run.sh $@ +$Tfront.s: tst/front.c tst/front.0 all; @env BUILDDIR=$(BUILDDIR) TSTDIR=$(TSTDIR) tst/run.sh $@ +$Tincr.s: tst/incr.c tst/incr.0 all; @env BUILDDIR=$(BUILDDIR) TSTDIR=$(TSTDIR) tst/run.sh $@ +$Tinit.s: tst/init.c tst/init.0 all; @env BUILDDIR=$(BUILDDIR) TSTDIR=$(TSTDIR) tst/run.sh $@ +$Tlimits.s: tst/limits.c tst/limits.0 all; @env BUILDDIR=$(BUILDDIR) TSTDIR=$(TSTDIR) tst/run.sh $@ +$Tparanoia.s: tst/paranoia.c tst/paranoia.0 all; @env BUILDDIR=$(BUILDDIR) TSTDIR=$(TSTDIR) tst/run.sh $@ +$Tsort.s: tst/sort.c tst/sort.0 all; @env BUILDDIR=$(BUILDDIR) TSTDIR=$(TSTDIR) tst/run.sh $@ +$Tspill.s: tst/spill.c tst/spill.0 all; @env BUILDDIR=$(BUILDDIR) TSTDIR=$(TSTDIR) tst/run.sh $@ +$Tstdarg.s: tst/stdarg.c tst/stdarg.0 all; @env BUILDDIR=$(BUILDDIR) TSTDIR=$(TSTDIR) tst/run.sh $@ +$Tstruct.s: tst/struct.c tst/struct.0 all; @env BUILDDIR=$(BUILDDIR) TSTDIR=$(TSTDIR) tst/run.sh $@ +$Tswitch.s: tst/switch.c tst/switch.0 all; @env BUILDDIR=$(BUILDDIR) TSTDIR=$(TSTDIR) tst/run.sh $@ +$Twf1.s: tst/wf1.c tst/wf1.0 all; @env BUILDDIR=$(BUILDDIR) TSTDIR=$(TSTDIR) tst/run.sh $@ +$Tyacc.s: tst/yacc.c tst/yacc.0 all; @env BUILDDIR=$(BUILDDIR) TSTDIR=$(TSTDIR) tst/run.sh $@ diff --git a/src/cmd/lccom/README b/src/cmd/lccom/README new file mode 100644 index 0000000..1deccaf --- /dev/null +++ b/src/cmd/lccom/README @@ -0,0 +1,22 @@ +This hierarchy is the distribution for lcc version 4.2. + +lcc version 3.x is described in the book "A Retargetable C Compiler: +Design and Implementation" (Addison-Wesley, 1995, ISBN 0-8053-1670-1). +There are significant differences between 3.x and 4.x, most notably in +the intermediate code. For details, see +http://www.research.microsoft.com/~drh/pubs/interface4.pdf. + +VERSION 4.2 IS INCOMPATIBLE WITH EARLIER VERSIONS OF LCC. DO NOT +UNLOAD THIS DISTRIBUTION ON TOP OF A 3.X DISTRIBUTION. + +LOG describes the changes since the last release. + +CPYRIGHT describes the conditions under you can use, copy, modify, and +distribute lcc or works derived from lcc. + +doc/install.html is an HTML file that gives a complete description of +the distribution and installation instructions. + +Chris Fraser / cwfraser@microsoft.com +David Hanson / drh@microsoft.com +$Revision: 2.7 $ $Date: 2003/06/19 22:07:06 $ diff --git a/src/cmd/lccom/alloc.c b/src/cmd/lccom/alloc.c new file mode 100644 index 0000000..843940f --- /dev/null +++ b/src/cmd/lccom/alloc.c @@ -0,0 +1,101 @@ +#include "c.h" + +struct block { + struct block *next; + char *limit; + char *avail; +}; + +union align { + long l; + char *p; + double d; + int (*f)(void); +}; + +union header { + struct block b; + union align a; +}; + +#ifdef PURIFY + +union header *arena[3]; + +void *allocate(unsigned long n, unsigned a) { + union header *new = malloc(sizeof *new + n); + + assert(a < NELEMS(arena)); + if (new == NULL) { + error("insufficient memory\n"); + exit(1); + } + new->b.next = (void *)arena[a]; + arena[a] = new; + return new + 1; +} + +void deallocate(unsigned a) { + union header *p, *q; + + assert(a < NELEMS(arena)); + for (p = arena[a]; p; p = q) { + q = (void *)p->b.next; + free(p); + } + arena[a] = NULL; +} + +void *newarray(unsigned long m, unsigned long n, unsigned a) { + return allocate(m*n, a); +} +#else +static struct block + first[] = { { NULL }, { NULL }, { NULL } }, + *arena[] = { &first[0], &first[1], &first[2] }; + +static struct block *freeblocks; + +void *allocate(unsigned long n, unsigned a) { + struct block *ap; + + assert(a < NELEMS(arena)); + assert(n > 0); + ap = arena[a]; + n = roundup(n, sizeof (union align)); + while (n > ap->limit - ap->avail) { + if ((ap->next = freeblocks) != NULL) { + freeblocks = freeblocks->next; + ap = ap->next; + } else + { + unsigned m = sizeof (union header) + n + roundup(10*1024, sizeof (union align)); + ap->next = malloc(m); + ap = ap->next; + if (ap == NULL) { + error("insufficient memory\n"); + exit(1); + } + ap->limit = (char *)ap + m; + } + ap->avail = (char *)((union header *)ap + 1); + ap->next = NULL; + arena[a] = ap; + + } + ap->avail += n; + return ap->avail - n; +} + +void *newarray(unsigned long m, unsigned long n, unsigned a) { + return allocate(m*n, a); +} + +void deallocate(unsigned a) { + assert(a < NELEMS(arena)); + arena[a]->next = freeblocks; + freeblocks = first[a].next; + first[a].next = NULL; + arena[a] = &first[a]; +} +#endif diff --git a/src/cmd/lccom/alpha.md b/src/cmd/lccom/alpha.md new file mode 100644 index 0000000..09bfb08 --- /dev/null +++ b/src/cmd/lccom/alpha.md @@ -0,0 +1,1188 @@ +%{ +#define INTTMP ((0xff<<1)|(1<<22)|(1<<25)|(1<<27)) +#define INTVAR (0x3f<<9) +#define FLTTMP ((0x3f<<10)|(0x1ff<<22)) +#define FLTVAR (0xff<<2) + +#define INTRET 0x00000001 +#define FLTRET 0x00000003 + +#define readsreg(p) \ + (generic((p)->op)==INDIR && (p)->kids[0]->op==VREG+P) +#define setsrc(d) ((d) && (d)->x.regnode && \ + (d)->x.regnode->set == src->x.regnode->set && \ + (d)->x.regnode->mask&src->x.regnode->mask) + +#define relink(a, b) ((b)->x.prev = (a), (a)->x.next = (b)) + +#include "c.h" +#define NODEPTR_TYPE Node +#define OP_LABEL(p) ((p)->op) +#define LEFT_CHILD(p) ((p)->kids[0]) +#define RIGHT_CHILD(p) ((p)->kids[1]) +#define STATE_LABEL(p) ((p)->x.state) +static void address(Symbol, Symbol, long); +static void blkfetch(int, int, int, int); +static void blkloop(int, int, int, int, int, int[]); +static void blkstore(int, int, int, int); +static void defaddress(Symbol); +static void defconst(int, int, Value); +static void defstring(int, char *); +static void defsymbol(Symbol); +static void doarg(Node); +static void emit2(Node); +static void export(Symbol); +static void clobber(Node); +static void function(Symbol, Symbol [], Symbol [], int); +static void global(Symbol); +static void import(Symbol); +static void local(Symbol); +static void progbeg(int, char **); +static void progend(void); +static void segment(int); +static void space(int); +static void target(Node); +static Symbol ireg[32], freg[32]; +static Symbol iregw, fregw; + +static int tmpregs[] = {4, 2, 3}; +static Symbol blkreg; + +static int cseg; + +static char *currentfile; + +%} +%start stmt +%term CNSTF4=4113 +%term CNSTF8=8209 +%term CNSTF16=16401 +%term CNSTI1=1045 +%term CNSTI2=2069 +%term CNSTI4=4117 +%term CNSTI8=8213 +%term CNSTP4=4119 +%term CNSTP8=8215 +%term CNSTU1=1046 +%term CNSTU2=2070 +%term CNSTU4=4118 +%term CNSTU8=8214 + +%term ARGB=41 +%term ARGF4=4129 +%term ARGF8=8225 +%term ARGF16=16417 +%term ARGI4=4133 +%term ARGI8=8229 +%term ARGP4=4135 +%term ARGP8=8231 +%term ARGU4=4134 +%term ARGU8=8230 + +%term ASGNB=57 +%term ASGNF4=4145 +%term ASGNF8=8241 +%term ASGNF16=16433 +%term ASGNI1=1077 +%term ASGNI2=2101 +%term ASGNI4=4149 +%term ASGNI8=8245 +%term ASGNP4=4151 +%term ASGNP8=8247 +%term ASGNU1=1078 +%term ASGNU2=2102 +%term ASGNU4=4150 +%term ASGNU8=8246 + +%term INDIRB=73 +%term INDIRF4=4161 +%term INDIRF8=8257 +%term INDIRF16=16449 +%term INDIRI1=1093 +%term INDIRI2=2117 +%term INDIRI4=4165 +%term INDIRI8=8261 +%term INDIRP4=4167 +%term INDIRP8=8263 +%term INDIRU1=1094 +%term INDIRU2=2118 +%term INDIRU4=4166 +%term INDIRU8=8262 + +%term CVFF4=4209 +%term CVFF8=8305 +%term CVFF16=16497 +%term CVFI4=4213 +%term CVFI8=8309 + +%term CVIF4=4225 +%term CVIF8=8321 +%term CVIF16=16513 +%term CVII1=1157 +%term CVII2=2181 +%term CVII4=4229 +%term CVII8=8325 +%term CVIU1=1158 +%term CVIU2=2182 +%term CVIU4=4230 +%term CVIU8=8326 + +%term CVPP4=4247 +%term CVPP8=8343 +%term CVPP16=16535 +%term CVPU4=4246 +%term CVPU8=8342 + +%term CVUI1=1205 +%term CVUI2=2229 +%term CVUI4=4277 +%term CVUI8=8373 +%term CVUP4=4279 +%term CVUP8=8375 +%term CVUP16=16567 +%term CVUU1=1206 +%term CVUU2=2230 +%term CVUU4=4278 +%term CVUU8=8374 + +%term NEGF4=4289 +%term NEGF8=8385 +%term NEGF16=16577 +%term NEGI4=4293 +%term NEGI8=8389 + +%term CALLB=217 +%term CALLF4=4305 +%term CALLF8=8401 +%term CALLF16=16593 +%term CALLI4=4309 +%term CALLI8=8405 +%term CALLP4=4311 +%term CALLP8=8407 +%term CALLU4=4310 +%term CALLU8=8406 +%term CALLV=216 + +%term RETF4=4337 +%term RETF8=8433 +%term RETF16=16625 +%term RETI4=4341 +%term RETI8=8437 +%term RETP4=4343 +%term RETP8=8439 +%term RETU4=4342 +%term RETU8=8438 +%term RETV=248 + +%term ADDRGP4=4359 +%term ADDRGP8=8455 + +%term ADDRFP4=4375 +%term ADDRFP8=8471 + +%term ADDRLP4=4391 +%term ADDRLP8=8487 + +%term ADDF4=4401 +%term ADDF8=8497 +%term ADDF16=16689 +%term ADDI4=4405 +%term ADDI8=8501 +%term ADDP4=4407 +%term ADDP8=8503 +%term ADDU4=4406 +%term ADDU8=8502 + +%term SUBF4=4417 +%term SUBF8=8513 +%term SUBF16=16705 +%term SUBI4=4421 +%term SUBI8=8517 +%term SUBP4=4423 +%term SUBP8=8519 +%term SUBU4=4422 +%term SUBU8=8518 + +%term LSHI4=4437 +%term LSHI8=8533 +%term LSHU4=4438 +%term LSHU8=8534 + +%term MODI4=4453 +%term MODI8=8549 +%term MODU4=4454 +%term MODU8=8550 + +%term RSHI4=4469 +%term RSHI8=8565 +%term RSHU4=4470 +%term RSHU8=8566 + +%term BANDI4=4485 +%term BANDI8=8581 +%term BANDU4=4486 +%term BANDU8=8582 + +%term BCOMI4=4501 +%term BCOMI8=8597 +%term BCOMU4=4502 +%term BCOMU8=8598 + +%term BORI4=4517 +%term BORI8=8613 +%term BORU4=4518 +%term BORU8=8614 + +%term BXORI4=4533 +%term BXORI8=8629 +%term BXORU4=4534 +%term BXORU8=8630 + +%term DIVF4=4545 +%term DIVF8=8641 +%term DIVF16=16833 +%term DIVI4=4549 +%term DIVI8=8645 +%term DIVU4=4550 +%term DIVU8=8646 + +%term MULF4=4561 +%term MULF8=8657 +%term MULF16=16849 +%term MULI4=4565 +%term MULI8=8661 +%term MULU4=4566 +%term MULU8=8662 + +%term EQF4=4577 +%term EQF8=8673 +%term EQF16=16865 +%term EQI4=4581 +%term EQI8=8677 +%term EQU4=4582 +%term EQU8=8678 + +%term GEF4=4593 +%term GEF8=8689 +%term GEI4=4597 +%term GEI8=8693 +%term GEI16=16885 +%term GEU4=4598 +%term GEU8=8694 + +%term GTF4=4609 +%term GTF8=8705 +%term GTF16=16897 +%term GTI4=4613 +%term GTI8=8709 +%term GTU4=4614 +%term GTU8=8710 + +%term LEF4=4625 +%term LEF8=8721 +%term LEF16=16913 +%term LEI4=4629 +%term LEI8=8725 +%term LEU4=4630 +%term LEU8=8726 + +%term LTF4=4641 +%term LTF8=8737 +%term LTF16=16929 +%term LTI4=4645 +%term LTI8=8741 +%term LTU4=4646 +%term LTU8=8742 + +%term NEF4=4657 +%term NEF8=8753 +%term NEF16=16945 +%term NEI4=4661 +%term NEI8=8757 +%term NEU4=4662 +%term NEU8=8758 + +%term JUMPV=584 + +%term LABELV=600 + +%term LOADB=233 +%term LOADF4=4321 +%term LOADF8=8417 +%term LOADF16=16609 +%term LOADI1=1253 +%term LOADI2=2277 +%term LOADI4=4325 +%term LOADI8=8421 +%term LOADP4=4327 +%term LOADP8=8423 +%term LOADU1=1254 +%term LOADU2=2278 +%term LOADU4=4326 +%term LOADU8=8422 + +%term VREGP=711 +%% +reg: INDIRI1(VREGP) "# read register\n" +reg: INDIRU1(VREGP) "# read register\n" + +reg: INDIRI2(VREGP) "# read register\n" +reg: INDIRU2(VREGP) "# read register\n" + +reg: INDIRF4(VREGP) "# read register\n" +reg: INDIRI4(VREGP) "# read register\n" +reg: INDIRP4(VREGP) "# read register\n" +reg: INDIRU4(VREGP) "# read register\n" + +reg: INDIRF8(VREGP) "# read register\n" +reg: INDIRI8(VREGP) "# read register\n" +reg: INDIRP8(VREGP) "# read register\n" +reg: INDIRU8(VREGP) "# read register\n" + +stmt: ASGNI1(VREGP,reg) "# write register\n" +stmt: ASGNU1(VREGP,reg) "# write register\n" + +stmt: ASGNI2(VREGP,reg) "# write register\n" +stmt: ASGNU2(VREGP,reg) "# write register\n" + +stmt: ASGNF4(VREGP,reg) "# write register\n" +stmt: ASGNI4(VREGP,reg) "# write register\n" +stmt: ASGNP4(VREGP,reg) "# write register\n" +stmt: ASGNU4(VREGP,reg) "# write register\n" + +stmt: ASGNF8(VREGP,reg) "# write register\n" +stmt: ASGNI8(VREGP,reg) "# write register\n" +stmt: ASGNP8(VREGP,reg) "# write register\n" +stmt: ASGNU8(VREGP,reg) "# write register\n" +con: CNSTI1 "%a" +con: CNSTU1 "%a" + +con: CNSTI2 "%a" +con: CNSTU2 "%a" + +con: CNSTI4 "%a" +con: CNSTU4 "%a" +con: CNSTP4 "%a" + +con: CNSTI8 "%a" +con: CNSTU8 "%a" +con: CNSTP8 "%a" +stmt: reg "" +acon: con "%0" +acon: ADDRGP8 "%a" + +addr: ADDI4(reg,acon) "%1($%0)" +addr: ADDI8(reg,acon) "%1($%0)" +addr: ADDU8(reg,acon) "%1($%0)" +addr: ADDP8(reg,acon) "%1($%0)" + +addr: acon "%0" +addr: reg "($%0)" + +addr: ADDRFP8 "%a+%F($sp)" +addr: ADDRLP8 "%a+%F($sp)" + +reg: addr "lda $%c,%0\n" 1 + +reg: CNSTI1 "# reg\n" range(a, 0, 0) +reg: CNSTI2 "# reg\n" range(a, 0, 0) +reg: CNSTI4 "# reg\n" range(a, 0, 0) +reg: CNSTI8 "# reg\n" range(a, 0, 0) +reg: CNSTU1 "# reg\n" range(a, 0, 0) +reg: CNSTU2 "# reg\n" range(a, 0, 0) +reg: CNSTU4 "# reg\n" range(a, 0, 0) +reg: CNSTU8 "# reg\n" range(a, 0, 0) +reg: CNSTP8 "# reg\n" range(a, 0, 0) + +stmt: ASGNI1(addr,reg) "stb $%1,%0\n" 1 +stmt: ASGNU1(addr,reg) "stb $%1,%0\n" 1 +stmt: ASGNI2(addr,reg) "stw $%1,%0\n" 1 +stmt: ASGNU2(addr,reg) "stw $%1,%0\n" 1 + +stmt: ASGNI4(addr,reg) "stl $%1,%0\n" 1 +stmt: ASGNU4(addr,reg) "stl $%1,%0\n" 1 +stmt: ASGNI8(addr,reg) "stq $%1,%0\n" 1 +stmt: ASGNU8(addr,reg) "stq $%1,%0\n" 1 +stmt: ASGNP8(addr,reg) "stq $%1,%0\n" 1 + +reg: INDIRI1(reg) "ldb $%c,($%0)\n" 1 +reg: INDIRI2(reg) "ldw $%c,($%0)\n" 1 +reg: INDIRI4(addr) "ldl $%c,%0\n" 1 +reg: INDIRI8(addr) "ldq $%c,%0\n" 1 +reg: INDIRP8(addr) "ldq $%c,%0\n" 1 +reg: INDIRU1(reg) "ldbu $%c,($%0)\n" 1 +reg: INDIRU2(reg) "ldwu $%c,($%0)\n" 1 +reg: INDIRU4(addr) "ldl $%c,%0\nzap $%c,240,$%c\n" 2 +reg: INDIRU8(addr) "ldq $%c,%0\n" 1 + +reg: CVII4(INDIRI1(reg)) "ldb $%c,($%0)\n" 1 +reg: CVII8(INDIRI1(reg)) "ldb $%c,($%0)\n" 1 +reg: CVII4(INDIRI2(reg)) "ldw $%c,($%0)\n" 1 +reg: CVII8(INDIRI2(reg)) "ldw $%c,($%0)\n" 1 +reg: CVII8(INDIRI4(addr)) "ldl $%c,%0\n" 1 + +reg: CVUU4(INDIRU1(reg)) "ldbu $%c,($%0)\n" 1 +reg: CVUU8(INDIRU1(reg)) "ldbu $%c,($%0)\n" 1 +reg: CVUU4(INDIRU2(reg)) "ldwu $%c,($%0)\n" 1 +reg: CVUU8(INDIRU2(reg)) "ldwu $%c,($%0)\n" 1 +reg: CVUU8(INDIRU4(addr)) "ldl $%c,%0\nzap $%c,240,$%c\n" 2 + +reg: CVUI4(INDIRU1(reg)) "ldbu $%c,($%0)\n" 1 +reg: CVUI8(INDIRU1(reg)) "ldbu $%c,($%0)\n" 1 +reg: CVUI4(INDIRU2(reg)) "ldwu $%c,($%0)\n" 1 +reg: CVUI8(INDIRU2(reg)) "ldwu $%c,($%0)\n" 1 +reg: CVUI8(INDIRU4(addr)) "ldl $%c,%0\nzap $%c,240,$%c\n" 2 + +reg: CVIU8(reg) "mov $%0,$%c\n" move(a) + +reg: INDIRF4(addr) "lds $f%c,%0\n" 1 +reg: INDIRF8(addr) "ldt $f%c,%0\n" 1 +stmt: ASGNF4(addr,reg) "sts $f%1,%0\n" 1 +stmt: ASGNF8(addr,reg) "stt $f%1,%0\n" 1 + +reg: MULI4(reg,rc) "mull $%0,%1,$%c\n" 1 +reg: MULI8(reg,rc) "mulq $%0,%1,$%c\n" 1 +reg: MULU4(reg,rc) "mull $%0,%1,$%c\nzap $%c,240,$%c\n" 2 +reg: MULU8(reg,rc) "mulq $%0,%1,$%c\n" 1 + +reg: DIVI4(reg,rc) "divl $%0,%1,$%c\n" 1 +reg: DIVI8(reg,rc) "divq $%0,%1,$%c\n" 1 +reg: DIVU4(reg,rc) "divlu $%0,%1,$%c\n" 1 +reg: DIVU8(reg,rc) "divqu $%0,%1,$%c\n" 1 +reg: MODI4(reg,rc) "reml $%0,%1,$%c\n" 1 +reg: MODI8(reg,rc) "remq $%0,%1,$%c\n" 1 +reg: MODU4(reg,rc) "remlu $%0,%1,$%c\n" 1 +reg: MODU8(reg,rc) "remqu $%0,%1,$%c\n" 1 + +rc: con "%0" +rc: reg "$%0" + +reg: ADDI4(reg,rc) "addl $%0,%1,$%c\n" 1 +reg: ADDI8(reg,rc) "addq $%0,%1,$%c\n" 1 +reg: ADDP8(reg,rc) "addq $%0,%1,$%c\n" 1 +reg: ADDU4(reg,rc) "addl $%0,%1,$%c\nzap $%c,240,$%c\n" 2 +reg: ADDU8(reg,rc) "addq $%0,%1,$%c\n" 1 +reg: SUBI4(reg,rc) "subl $%0,%1,$%c\n" 1 +reg: SUBI8(reg,rc) "subq $%0,%1,$%c\n" 1 +reg: SUBP8(reg,rc) "subq $%0,%1,$%c\n" 1 +reg: SUBU4(reg,rc) "subl $%0,%1,$%c\nzap $%c,240,$%c\n" 2 +reg: SUBU8(reg,rc) "subq $%0,%1,$%c\n" 1 + +reg: BANDI4(reg,rc) "and $%0,%1,$%c\naddl $%c,0,$%c\n" 2 +reg: BANDI8(reg,rc) "and $%0,%1,$%c\n" 1 +reg: BANDU4(reg,rc) "and $%0,%1,$%c\n" 1 +reg: BANDU8(reg,rc) "and $%0,%1,$%c\n" 1 +reg: BORI4(reg,rc) "or $%0,%1,$%c\naddl $%c,0,$%c\n" 2 +reg: BORI8(reg,rc) "or $%0,%1,$%c\n" 1 +reg: BORU4(reg,rc) "or $%0,%1,$%c\n" 1 +reg: BORU8(reg,rc) "or $%0,%1,$%c\n" 1 +reg: BXORI4(reg,rc) "xor $%0,%1,$%c\naddl $%c,0,$%c\n" 2 +reg: BXORI8(reg,rc) "xor $%0,%1,$%c\n" 1 +reg: BXORU4(reg,rc) "xor $%0,%1,$%c\n" 1 +reg: BXORU8(reg,rc) "xor $%0,%1,$%c\n" 1 + +rc6: CNSTI4 "%a" range(a,0,63) +rc6: CNSTI8 "%a" range(a,0,63) +rc6: reg "$%0" + +reg: LSHI4(reg,rc6) "sll $%0,%1,$%c\naddl $%c,0,$%c\n" 2 +reg: LSHI8(reg,rc6) "sll $%0,%1,$%c\n" 1 +reg: LSHU4(reg,rc6) "sll $%0,%1,$%c\nzap $%c,240,$%c\n" 2 +reg: LSHU8(reg,rc6) "sll $%0,%1,$%c\n" 1 +reg: RSHI4(reg,rc6) "sra $%0,%1,$%c\naddl $%c,0,$%c\n" 2 +reg: RSHI8(reg,rc6) "sra $%0,%1,$%c\n" 1 +reg: RSHU4(reg,rc6) "srl $%0,%1,$%c\n" 1 +reg: RSHU8(reg,rc6) "srl $%0,%1,$%c\n" 1 + +reg: BCOMI4(reg) "not $%0,$%c\naddl $%c,0,$%c\n" 2 +reg: BCOMU4(reg) "not $%0,$%c\nzap $%c,240,$%c\n" 2 +reg: BCOMI8(reg) "not $%0,$%c\n" 1 +reg: BCOMU8(reg) "not $%0,$%c\n" 1 +reg: NEGI4(reg) "negl $%0,$%c\n" 1 +reg: NEGI8(reg) "negq $%0,$%c\n" 1 +reg: LOADI1(reg) "mov $%0,$%c\n" move(a) +reg: LOADI2(reg) "mov $%0,$%c\n" move(a) +reg: LOADI4(reg) "mov $%0,$%c\n" move(a) +reg: LOADI8(reg) "mov $%0,$%c\n" move(a) +reg: LOADP8(reg) "mov $%0,$%c\n" move(a) +reg: LOADU1(reg) "mov $%0,$%c\n" move(a) +reg: LOADU2(reg) "mov $%0,$%c\n" move(a) +reg: LOADU4(reg) "mov $%0,$%c\n" move(a) +reg: LOADU8(reg) "mov $%0,$%c\n" move(a) + +reg: ADDF4(reg,reg) "adds $f%0,$f%1,$f%c\n" 1 +reg: ADDF8(reg,reg) "addt $f%0,$f%1,$f%c\n" 1 +reg: DIVF4(reg,reg) "divs $f%0,$f%1,$f%c\n" 1 +reg: DIVF8(reg,reg) "divt $f%0,$f%1,$f%c\n" 1 +reg: MULF4(reg,reg) "muls $f%0,$f%1,$f%c\n" 1 +reg: MULF8(reg,reg) "mult $f%0,$f%1,$f%c\n" 1 +reg: SUBF4(reg,reg) "subs $f%0,$f%1,$f%c\n" 1 +reg: SUBF8(reg,reg) "subt $f%0,$f%1,$f%c\n" 1 +reg: LOADF4(reg) "fmov $f%0,$f%c\n" move(a) +reg: LOADF8(reg) "fmov $f%0,$f%c\n" move(a) +reg: NEGF4(reg) "negs $f%0,$f%c\n" 1 +reg: NEGF8(reg) "negt $f%0,$f%c\n" 1 +reg: CVII4(reg) "sll $%0,8*(8-%a),$%c\nsra $%c,8*(8-%a),$%c\n" 2 +reg: CVII8(reg) "sll $%0,8*(8-%a),$%c\nsra $%c,8*(8-%a),$%c\n" 2 +reg: CVUI4(reg) "and $%0,(1<<(8*%a))-1,$%c\n" 1 +reg: CVUI8(reg) "and $%0,(1<<(8*%a))-1,$%c\n" 1 +reg: CVUU4(reg) "and $%0,(1<<(8*%a))-1,$%c\n" 1 +reg: CVUU8(reg) "and $%0,(1<<(8*%a))-1,$%c\n" 1 + +reg: CVUP8(reg) "and $%0,(1<<(8*%a))-1,$%c\n" 1 + +reg: CVFF4(reg) "cvtts $f%0,$f%c\n" 1 +reg: CVFF8(reg) "cvtst $f%0,$f%c\n" 1 + +reg: CVIF4(reg) "stq $%0,-56+%F($sp)\nldt $%f%c,-56+%F($sp)\ncvtqs $f%c,$f%c\n" 3 +reg: CVIF8(reg) "stq $%0,-56+%F($sp)\nldt $%f%c,-56+%F($sp)\ncvtqt $f%c,$f%c\n" 3 +reg: CVIF4(INDIRI4(addr)) "lds $f%c,%0\ncvtlq $f%c,$f%c\ncvtqs $f%c,$f%c\n" 3 +reg: CVIF4(INDIRI8(addr)) "ldt $f%c,%0\ncvtqs $f%c,$f%c\n" 2 +reg: CVIF8(INDIRI4(addr)) "lds $f%c,%0\ncvtlq $f%c,$f%c\ncvtqt $f%c,$f%c\n" 3 +reg: CVIF8(INDIRI8(addr)) "ldt $f%c,%0\ncvtqt $f%c,$f%c\n" 2 + +reg: CVFI4(reg) "cvttqc $f%0,$f1\ncvtql $f1,$f1\nsts $f1,-56+%F($sp)\nldl $%c,-56+%F($sp)\n" 4 +reg: CVFI8(reg) "cvttqc $f%0,$f1\nstt $f1,-56+%F($sp)\nldq $%c,-56+%F($sp)\n" 3 + +stmt: LABELV "%a:\n" + +stmt: JUMPV(acon) "br %0\n" 1 +stmt: JUMPV(reg) "jmp ($%0)\n" 1 + +stmt: EQI4(reg,rc6) "cmpeq $%0,%1,$23\nbne $23,%a\n" 2 +stmt: EQU4(reg,rc6) "cmpeq $%0,%1,$23\nbne $23,%a\n" 2 +stmt: EQI8(reg,rc6) "cmpeq $%0,%1,$23\nbne $23,%a\n" 2 +stmt: EQU8(reg,rc6) "cmpeq $%0,%1,$23\nbne $23,%a\n" 2 +stmt: NEI4(reg,rc6) "cmpeq $%0,%1,$23\nbeq $23,%a\n" 2 +stmt: NEU4(reg,rc6) "cmpeq $%0,%1,$23\nbeq $23,%a\n" 2 +stmt: NEI8(reg,rc6) "cmpeq $%0,%1,$23\nbeq $23,%a\n" 2 +stmt: NEU8(reg,rc6) "cmpeq $%0,%1,$23\nbeq $23,%a\n" 2 +stmt: GEI4(reg,rc6) "cmplt $%0,%1,$23\nbeq $23,%a\n" 2 +stmt: GEI8(reg,rc6) "cmplt $%0,%1,$23\nbeq $23,%a\n" 2 +stmt: GEU4(reg,rc6) "cmpult $%0,%1,$23\nbeq $23,%a\n" 1 +stmt: GEU8(reg,rc6) "cmpult $%0,%1,$23\nbeq $23,%a\n" 1 +stmt: GTI4(reg,rc6) "cmple $%0,%1,$23\nbeq $23,%a\n" 2 +stmt: GTI8(reg,rc6) "cmple $%0,%1,$23\nbeq $23,%a\n" 2 +stmt: GTU4(reg,rc6) "cmpule $%0,%1,$23\nbeq $23,%a\n" 1 +stmt: GTU8(reg,rc6) "cmpule $%0,%1,$23\nbeq $23,%a\n" 1 +stmt: LEI4(reg,rc6) "cmple $%0,%1,$23\nbne $23,%a\n" 2 +stmt: LEI8(reg,rc6) "cmple $%0,%1,$23\nbne $23,%a\n" 2 +stmt: LEU4(reg,rc6) "cmpule $%0,%1,$23\nbne $23,%a\n" 2 +stmt: LEU8(reg,rc6) "cmpule $%0,%1,$23\nbne $23,%a\n" 2 +stmt: LTI4(reg,rc6) "cmplt $%0,%1,$23\nbne $23,%a\n" 2 +stmt: LTI8(reg,rc6) "cmplt $%0,%1,$23\nbne $23,%a\n" 2 +stmt: LTU4(reg,rc6) "cmpult $%0,%1,$23\nbne $23,%a\n" 2 +stmt: LTU8(reg,rc6) "cmpult $%0,%1,$23\nbne $23,%a\n" 2 + +stmt: EQF4(reg,reg) "cmpteq $f%0,$f%1,$f1\nfbne $f1,%a\n" 2 +stmt: EQF8(reg,reg) "cmpteq $f%0,$f%1,$f1\nfbne $f1,%a\n" 2 +stmt: LEF4(reg,reg) "cmptle $f%0,$f%1,$f1\nfbne $f1,%a\n" 2 +stmt: LEF8(reg,reg) "cmptle $f%0,$f%1,$f1\nfbne $f1,%a\n" 2 +stmt: LTF4(reg,reg) "cmptlt $f%0,$f%1,$f1\nfbne $f1,%a\n" 2 +stmt: LTF8(reg,reg) "cmptlt $f%0,$f%1,$f1\nfbne $f1,%a\n" 2 + +stmt: NEF4(reg,reg) "cmpteq $f%0,$f%1,$f1\nfbeq $f1,%a\n" 2 +stmt: NEF8(reg,reg) "cmpteq $f%0,$f%1,$f1\nfbeq $f1,%a\n" 2 +stmt: GEF4(reg,reg) "cmptlt $f%0,$f%1,$f1\nfbeq $f1,%a\n" 2 +stmt: GEF8(reg,reg) "cmptlt $f%0,$f%1,$f1\nfbeq $f1,%a\n" 2 +stmt: GTF4(reg,reg) "cmptle $f%0,$f%1,$f1\nfbeq $f1,%a\n" 2 +stmt: GTF8(reg,reg) "cmptle $f%0,$f%1,$f1\nfbeq $f1,%a\n" 2 + +ar: ADDRGP8 "%a" +ar: reg "($%0)" + +reg: CALLF4(ar) "jsr $26,%0\nldgp $gp,0($26)\n" 2 +reg: CALLF8(ar) "jsr $26,%0\nldgp $gp,0($26)\n" 2 +reg: CALLI4(ar) "jsr $26,%0\nldgp $gp,0($26)\n" 2 +reg: CALLI8(ar) "jsr $26,%0\nldgp $gp,0($26)\n" 2 +reg: CALLP8(ar) "jsr $26,%0\nldgp $gp,0($26)\n" 2 +reg: CALLU4(ar) "jsr $26,%0\nldgp $gp,0($26)\n" 2 +reg: CALLU8(ar) "jsr $26,%0\nldgp $gp,0($26)\n" 2 +stmt: CALLV(ar) "jsr $26,%0\nldgp $gp,0($26)\n" 2 + +stmt: RETF4(reg) "# ret\n" 1 +stmt: RETF8(reg) "# ret\n" 1 +stmt: RETI4(reg) "# ret\n" 1 +stmt: RETU4(reg) "# ret\n" 1 +stmt: RETI8(reg) "# ret\n" 1 +stmt: RETU8(reg) "# ret\n" 1 +stmt: RETP8(reg) "# ret\n" 1 +stmt: RETV(reg) "# ret\n" 1 + +stmt: ARGF4(reg) "# arg\n" 1 +stmt: ARGF8(reg) "# arg\n" 1 +stmt: ARGI4(reg) "# arg\n" 1 +stmt: ARGI8(reg) "# arg\n" 1 +stmt: ARGP8(reg) "# arg\n" 1 +stmt: ARGU4(reg) "# arg\n" 1 +stmt: ARGU8(reg) "# arg\n" 1 + +stmt: ARGB(INDIRB(reg)) "# argb %0\n" 1 +stmt: ASGNB(reg,INDIRB(reg)) "# asgnb %0 %1\n" 1 + +%% +static void progend(void){} + +static void progbeg(int argc, char *argv[]) { + int i; + + { + union { + char c; + int i; + } u; + u.i = 0; + u.c = 1; + swap = ((int)(u.i == 1)) != IR->little_endian; + } + parseflags(argc, argv); + + for (i = 0; i < 32; i++) + freg[i] = mkreg("%d", i, 1, FREG); + for (i = 0; i < 32; i++) + ireg[i] = mkreg("%d", i, 1, IREG); + ireg[29]->x.name = "gp"; + ireg[30]->x.name = "sp"; + fregw = mkwildcard(freg); + iregw = mkwildcard(ireg); + + tmask[IREG] = INTTMP; tmask[FREG] = FLTTMP; + vmask[IREG] = INTVAR; vmask[FREG] = FLTVAR; + + blkreg = mkreg("1", 1, 0xf, IREG); + +} + +static Symbol rmap(int opk) { + switch (optype(opk)) { + case I: case U: case P: case B: + return iregw; + case F: + return fregw; + default: + return 0; + } +} + +static Symbol argreg(int offset, int ty) { + if (offset >= 48) + return NULL; + else if (ty == F) + return freg[(offset/8) + 16]; + else + return ireg[(offset/8) + 16]; +} + +static void target(Node p) { + assert(p); + switch (specific(p->op)) { + case CNST+I: case CNST+U: case CNST+P: + if (range(p, 0, 0) == 0) { + setreg(p, ireg[31]); + p->x.registered = 1; + } + break; + case CNST+F: + if (p->syms[0]->u.c.v.d == 0) { + setreg(p, freg[31]); + p->x.registered = 1; + } + break; + + case CALL+V: + rtarget(p, 0, ireg[27]); + break; + case CALL+F: + rtarget(p, 0, ireg[27]); + setreg(p, freg[0]); + break; + case CALL+I: case CALL+P: case CALL+U: + rtarget(p, 0, ireg[27]); + setreg(p, ireg[0]); + break; + case RET+F: + rtarget(p, 0, freg[0]); + break; + case RET+I: case RET+U: case RET+P: + rtarget(p, 0, ireg[0]); + break; + + case ARG+F: case ARG+I: case ARG+P: case ARG+U: { + Symbol q = argreg(p->syms[2]->u.c.v.i, optype(p->op)); + if (q) + rtarget(p, 0, q); + break; + } + + + case ASGN+B: rtarget(p->kids[1], 0, blkreg); break; + case ARG+B: rtarget(p->kids[0], 0, blkreg); break; + + } +} + +static void clobber(Node p) { + assert(p); + switch (specific(p->op)) { + case ASGN+I: case ASGN+U: + if (opsize(p->op) <= 2) + spill(1<<24, IREG, p); + break; + + case DIV+I: case DIV+U: case MOD+I: case MOD+U: + spill(((1<<27)|(3<<24))&~p->syms[RX]->x.regnode->mask, IREG, p); + break; + + case CALL+F: + spill(INTTMP | INTRET, IREG, p); + spill(FLTTMP, FREG, p); + break; + case CALL+I: case CALL+P: case CALL+U: + spill(INTTMP, IREG, p); + spill(FLTTMP | FLTRET, FREG, p); + break; + case CALL+V: + spill(INTTMP | INTRET, IREG, p); + spill(FLTTMP | FLTRET, FREG, p); + break; + + } +} + +static void emit2(Node p) { + int dst, n, src, sz, ty; + static int ty0; + Symbol q; + + switch (specific(p->op)) { + case ARG+F: case ARG+I: case ARG+P: case ARG+U: + ty = optype(p->op); + sz = opsize(p->op); + q = argreg(p->syms[2]->u.c.v.i, ty); + src = getregnum(p->x.kids[0]); + if (q) + break; + else if (ty == F && sz == 4) + print("sts $f%d,%d($sp)\n", src, p->syms[2]->u.c.v.i - 48); + else if (ty == F && sz == 8) + print("stt $f%d,%d($sp)\n", src, p->syms[2]->u.c.v.i - 48); + else if (sz == 4) + print("stq $%d,%d($sp)\n", src, p->syms[2]->u.c.v.i - 48); + else if (sz == 8) + print("stq $%d,%d($sp)\n", src, p->syms[2]->u.c.v.i - 48); + else + assert(0); + break; + + case ASGN+B: + dalign = salign = p->syms[1]->u.c.v.i; + blkcopy(getregnum(p->x.kids[0]), 0, + getregnum(p->x.kids[1]), 0, + p->syms[0]->u.c.v.i, tmpregs); + break; + + + case ARG+B: { + int doff = p->syms[2]->u.c.v.i, soff = 0, sreg = getregnum(p->x.kids[0]); + dalign = 8; + salign = p->syms[1]->u.c.v.i; + n = p->syms[0]->u.c.v.i; + for ( ; doff <= 40 && n > 0; doff += 8) { + print("uldq $%d,%d($%d)\n", (doff/8)+16, soff, sreg); + soff += 8; + n -= 8; + } + if (n > 0) + blkcopy(30, doff - 48, sreg, soff, n, tmpregs); + break; + } + + } +} + +static void doarg(Node p) { + p->syms[2] = intconst(mkactual(8, roundup(p->syms[0]->u.c.v.i,8))); +} + +static void local(Symbol p) { + if (askregvar(p, rmap(ttob(p->type))) == 0) + mkauto(p); +} + +static int bitcount(unsigned mask) { + unsigned i, n = 0; + + for (i = 1; i; i <<= 1) + if (mask&i) + n++; + return n; +} + +static void function(Symbol f, Symbol caller[], Symbol callee[], int ncalls) { + int i, sizeargs, saved, sizefsave, sizeisave, varargs; + Symbol r, argregs[6]; + + usedmask[0] = usedmask[1] = 0; + freemask[0] = freemask[1] = ~(unsigned)0; + maxargoffset = offset = maxoffset = 0; + + for (i = 0; callee[i]; i++) + ; + varargs = variadic(f->type) + || i > 0 && strcmp(callee[i-1]->name, "va_alist") == 0; + if (varargs) + sizeargs = 2*48; + else + sizeargs = 48; + + for (i = 0; callee[i]; i++) { + Symbol p = callee[i]; + Symbol q = caller[i]; + assert(q); + if (isfloat(p->type) && varargs) { + p->x.offset = q->x.offset = offset - 2*48; + p->x.name = q->x.name = stringd(offset - 2*48); + } else { + p->x.offset = q->x.offset = offset - 48; + p->x.name = q->x.name = stringd(offset - 48); + } + offset = roundup(offset, q->type->align); + r = argreg(offset, optype(ttob(q->type))); + if (i < 6) + argregs[i] = r; + offset = roundup(offset + q->type->size, 8); + if (varargs) + p->sclass = AUTO; + else if (r && ncalls == 0 && !isstruct(q->type) && !p->addressed +) { + p->sclass = q->sclass = REGISTER; + askregvar(p, r); + assert(p->x.regnode && p->x.regnode->vbl == p); + q->x = p->x; + q->type = p->type; + } else if (askregvar(p, rmap(ttob(p->type))) + && r != NULL /* + && (isint(p->type) || p->type == q->type) */ +) { + assert(q->sclass != REGISTER); + p->sclass = q->sclass = REGISTER; + q->type = p->type; + } + + } + assert(!caller[i]); + + offset = sizeargs + 8; + gencode(caller, callee); + usedmask[IREG] &= ~(INTTMP|(0x3f<<16)|INTRET); + usedmask[FREG] &= ~(FLTTMP|(0x3f<<16)|FLTRET); + if (ncalls || usedmask[IREG] || usedmask[FREG]) + usedmask[IREG] |= 1<<26; + sizefsave = 8*bitcount(usedmask[FREG]); + sizeisave = 8*bitcount(usedmask[IREG]); + if (maxargoffset > 48) + maxargoffset -= 48; + else + maxargoffset = 0; + if (maxoffset < sizeargs) + maxoffset = sizeargs; + framesize = roundup(maxargoffset + sizefsave + sizeisave + maxoffset, 16); + segment(CODE); + print(".ent %s\n", f->x.name); + print("%s:\n", f->x.name); + print("ldgp $gp,0($27)\n"); + i = maxargoffset + sizefsave - framesize; + if (framesize > 0) + print("lda $sp,%d($sp)\n", -framesize); + if (usedmask[FREG]) + print(".fmask 0x%x,%d\n", usedmask[FREG], i - 8); + if (usedmask[IREG]) + print(".mask 0x%x,%d\n", usedmask[IREG], i + sizeisave - 8); + print(".frame $sp,%d,$26,%d\n", framesize, sizeargs); + + saved = maxargoffset; + for (i = 2; i <= 9; i++) + if (usedmask[FREG]&(1<x.regnode != callee[i]->x.regnode) { + Symbol out = callee[i]; + Symbol in = caller[i]; + int rn = r->x.regnode->number; + int rs = r->x.regnode->set; + int tyin = ttob(in->type); + + assert(out && in && r && r->x.regnode); + assert(out->sclass != REGISTER || out->x.regnode); + if (out->sclass == REGISTER) { + if (rs == FREG) + print("fmov $f%d,$f%d\n", rn, out->x.regnode->number); + else + print("mov $%d,$%d\n", rn, out->x.regnode->number); + + } else { + int off = in->x.offset + framesize; + if (rs == FREG && tyin == F+sizeop(8)) + print("stt $f%d,%d($sp)\n", rn, off); + else if (rs == FREG && tyin == F+sizeop(4)) + print("sts $f%d,%d($sp)\n", rn, off); + else { + int i, n = (in->type->size + 7)/8; + for (i = rn; i < rn+n && i <= 21; i++) + print("stq $%d,%d($sp)\n", i, off + (i-rn)*8); + } + + } + + } + } + if (varargs && callee[i-1]) { + i = callee[i-1]->x.offset + roundup(callee[i-1]->type->size, 8); + for (i = (48+i)/8; i < 6; i++) { + print("stq $%d,%d($sp)\n", i + 16, framesize - 48 + 8*i); + print("stt $f%d,%d($sp)\n", i + 16, framesize - 2*48 + 8*i); + } + } + print(".prologue 1\n"); + + emitcode(); + saved = maxargoffset; + for (i = 2; i <= 9; i++) + if (usedmask[FREG]&(1< 0) + print("lda $sp,%d($sp)\n", framesize); + print("ret\n"); + print(".end %s\n", f->x.name); + +} + +static void defconst(int suffix, int size, Value v) { + if (suffix == F && size == 4) { + float f = v.d; + print(".long 0x%x\n", *(unsigned *)&f); + } else if (suffix == F && size == 8) { + double d = v.d; + unsigned *p = (unsigned *)&d; + print(".long 0x%x\n.long 0x%x\n", p[swap], p[!swap]); + } else if (suffix == P) + print(".quad 0x%X\n", v.p); + else if (size == 1) + print(".byte 0x%x\n", suffix == I ? v.i : v.u); + else if (size == 2) + print(".word 0x%x\n", suffix == I ? v.i&0xFFFF : v.u&0xFFFF); + else if (size == 4) + print(".long 0x%x\n", suffix == I ? v.i : v.u); + else if (size == 8) + print(".quad 0x%X\n", suffix == I ? v.i : v.u); + +} + +static void defaddress(Symbol p) { + print(".quad %s\n", p->x.name); +} + +static void defstring(int n, char *str) { + char *s; + + for (s = str; s < str + n; s++) + print(".byte %d\n", (*s)&0377); +} + +static void export(Symbol p) { + print(".globl %s\n", p->x.name); +} + +static void import(Symbol p) { + if (!isfunc(p->type)) + print(".extern %s %d\n", p->name, p->type->size); +} + +static void defsymbol(Symbol p) { + if (p->scope >= LOCAL && p->sclass == STATIC) + p->x.name = stringf("L.%d", genlabel(1)); + else if (p->generated) + p->x.name = stringf("L.%s", p->name); + else + assert(p->scope != CONSTANTS || isint(p->type) || isptr(p->type)), + p->x.name = p->name; +} + +static void address(Symbol q, Symbol p, long n) { + if (p->scope == GLOBAL + || p->sclass == STATIC || p->sclass == EXTERN) + q->x.name = stringf("%s%s%D", p->x.name, + n >= 0 ? "+" : "", n); + else { + assert(n <= INT_MAX && n >= INT_MIN); + q->x.offset = p->x.offset + n; + q->x.name = stringd(q->x.offset); + } +} + +static void global(Symbol p) { + if (p->u.seg == DATA || p->u.seg == LIT) { + assert(p->type->align <= 8); + print(".align %c\n", ".01.2...3"[p->type->align]); + print("%s:\n", p->x.name); + } else if (p->sclass == STATIC || Aflag >= 2) + print(".lcomm %s,%d\n", p->x.name, p->type->size); + else + print( ".comm %s,%d\n", p->x.name, p->type->size); +} + +static void segment(int n) { + cseg = n; + switch (n) { + case DATA: print(".sdata\n"); break; + case CODE: print(".text\n"); break; + case LIT: print(".rdata\n"); break; + } +} + +static void space(int n) { + if (cseg != BSS) + print(".space %d\n", n); +} + +static void blkloop(int dreg, int doff, int sreg, int soff, int size, int tmps[]) { + int lab = genlabel(1); + + print("addq $%d,%d,$%d\n", sreg, size&~7, sreg); + print("addq $%d,%d,$%d\n", dreg, size&~7, tmps[2]); + blkcopy(tmps[2], doff, sreg, soff, size&7, tmps); + print("L.%d:\n", lab); + print("addq $%d,%d,$%d\n", sreg, -8, sreg); + print("addq $%d,%d,$%d\n", tmps[2], -8, tmps[2]); + blkcopy(tmps[2], doff, sreg, soff, 8, tmps); + print("cmpult $%d,$%d,$23\nbne $23,L.%d\n", dreg, tmps[2], lab); +} + +static void blkfetch(int size, int off, int reg, int tmp) { + assert(size == 1 || size == 2 || size == 4 || size == 8); + if (size == 1) + print("ldb $%d,%d($%d)\n", tmp, off, reg); + else if (size == 2) + print("ldw $%d,%d($%d)\n", tmp, off, reg); + else if (salign >= size && size == 4) + print("ldl $%d,%d($%d)\n", tmp, off, reg); + else if (salign >= size && size == 8) + print("ldq $%d,%d($%d)\n", tmp, off, reg); + else if (size == 4) + print("uldl $%d,%d($%d)\n", tmp, off, reg); + else + print("uldq $%d,%d($%d)\n", tmp, off, reg); +} + +static void blkstore(int size, int off, int reg, int tmp) { + assert(size == 1 || size == 2 || size == 4 || size == 8); + if (size == 1) + print("stb $%d,%d($%d)\n", tmp, off, reg); + else if (size == 2) + print("stw $%d,%d($%d)\n", tmp, off, reg); + else if (dalign >= size && size == 4) + print("stl $%d,%d($%d)\n", tmp, off, reg); + else if (dalign >= size && size == 8) + print("stq $%d,%d($%d)\n", tmp, off, reg); + else if (size == 4) + print("ustl $%d,%d($%d)\n", tmp, off, reg); + else + print("ustq $%d,%d($%d)\n", tmp, off, reg); +} + +/* stabinit - initialize stab output */ +static void stabinit(char *file, int argc, char *argv[]) { + if (file) { + print(".file 2,\"%s\"\n", file); + currentfile = file; + } +} + +/* stabline - emit stab entry for source coordinate *cp */ +static void stabline(Coordinate *cp) { + if (cp->file && cp->file != currentfile) { + print(".file 2,\"%s\"\n", cp->file); + currentfile = cp->file; + } + print(".loc 2,%d\n", cp->y); +} + +/* stabsym - output a stab entry for symbol p */ +static void stabsym(Symbol p) { + if (p == cfunc && IR->stabline) + (*IR->stabline)(&p->src); +} +Interface alphaIR = { + 1, 1, 0, /* char */ + 2, 2, 0, /* short */ + 4, 4, 0, /* int */ + 8, 8, 0, /* long */ + 8, 8, 0, /* long long */ + 4, 4, 1, /* float */ + 8, 8, 1, /* double */ + 8, 8, 1, /* long double */ + 8, 8, 0, /* T * */ + 0, 1, 0, /* struct */ + + 1, /* little_endian */ + 0, /* mulops_calls */ + 0, /* wants_callb */ + 1, /* wants_argb */ + 1, /* left_to_right */ + 0, /* wants_dag */ + 0, /* unsigned_char */ + address, + blockbeg, + blockend, + defaddress, + defconst, + defstring, + defsymbol, + emit, + export, + function, + gen, + global, + import, + local, + progbeg, + progend, + segment, + space, + 0, 0, 0, stabinit, stabline, stabsym, 0, + { + 1, /* max_unaligned_load */ + rmap, + blkfetch, blkstore, blkloop, + _label, + _rule, + _nts, + _kids, + _string, + _templates, + _isinstruction, + _ntname, + emit2, + doarg, + target, + clobber, + + } + +}; diff --git a/src/cmd/lccom/bind.c b/src/cmd/lccom/bind.c new file mode 100644 index 0000000..0891f7c --- /dev/null +++ b/src/cmd/lccom/bind.c @@ -0,0 +1,40 @@ +#include "c.h" + +extern Interface symbolic64IR; +extern Interface symbolicIR; +extern Interface bytecodeIR; +extern Interface nullIR; + +extern Interface alphaIR; +extern Interface mipsebIR; +extern Interface mipselIR; +extern Interface sparcIR; +extern Interface solarisIR; +extern Interface x86IR; +extern Interface x86linuxIR; + +Binding bindings[] = { +#ifdef TARGET_ALPHA + { "alpha-osf", &alphaIR }, +#endif +#ifdef TARGET_MIPS + { "mips-el", &mipselIR }, + { "mips-eb", &mipsebIR }, +#endif +#ifdef TARGET_SPARC + { "sparc-sun", &sparcIR }, +#endif +#ifdef TARGET_SOLARIS + { "sparc-solaris", &solarisIR }, +#endif +#ifdef TARGET_X86 + { "x86-win32", &x86IR }, + { "x86-linux", &x86linuxIR }, +#endif + { "symbolic64", &symbolic64IR }, + { "symbolic", &symbolicIR }, + { "bytecode", &bytecodeIR }, + { "null", &nullIR }, + + { NULL, NULL }, +}; diff --git a/src/cmd/lccom/bytecode.c b/src/cmd/lccom/bytecode.c new file mode 100644 index 0000000..fe81e3a --- /dev/null +++ b/src/cmd/lccom/bytecode.c @@ -0,0 +1,287 @@ +#include "c.h" +#define I(f) b_##f + +static void I(segment)(int n) { + static int cseg; + + if (cseg != n) + switch (cseg = n) { + case CODE: print("code\n"); return; + case DATA: print("data\n"); return; + case BSS: print("bss\n"); return; + case LIT: print("lit\n"); return; + default: assert(0); + } +} + +static void I(address)(Symbol q, Symbol p, long n) { + q->x.name = stringf("%s%s%D", p->x.name, n > 0 ? "+" : "", n); +} + +static void I(defaddress)(Symbol p) { + print("address %s\n", p->x.name); +} + +static void I(defconst)(int suffix, int size, Value v) { + switch (suffix) { + case I: + if (size > sizeof (int)) + print("byte %d %D\n", size, v.i); + else + print("byte %d %d\n", size, v.i); + return; + case U: + if (size > sizeof (unsigned)) + print("byte %d %U\n", size, v.u); + else + print("byte %d %u\n", size, v.u); + return; + case P: print("byte %d %U\n", size, (unsigned long)v.p); return; + case F: + if (size == 4) { + union { + float f32; + unsigned u32; + } u; + u.f32 = v.d; + print("byte 4 %u\n", u.u32); + } else { + union { + double d64; + unsigned u32[2]; + } u; + u.d64 = v.d; + print("byte 4 %u\n", u.u32[swap]); + print("byte 4 %u\n", u.u32[1 - swap]); + } + return; + } + assert(0); +} + +static void I(defstring)(int len, char *str) { + char *s; + + for (s = str; s < str + len; s++) + print("byte 1 %d\n", (*s)&0377); +} + +static void I(defsymbol)(Symbol p) { + if (p->scope == CONSTANTS) + switch (optype(ttob(p->type))) { + case I: p->x.name = stringf("%D", p->u.c.v.i); break; + case U: p->x.name = stringf("%U", p->u.c.v.u); break; + case P: p->x.name = stringf("%U", p->u.c.v.p); break; + default: assert(0); + } + else if (p->scope >= LOCAL && p->sclass == STATIC) + p->x.name = stringf("$%d", genlabel(1)); + else if (p->scope == LABELS || p->generated) + p->x.name = stringf("$%s", p->name); + else + p->x.name = p->name; +} + +static void dumptree(Node p) { + switch (specific(p->op)) { + case ASGN+B: + assert(p->kids[0]); + assert(p->kids[1]); + assert(p->syms[0]); + dumptree(p->kids[0]); + dumptree(p->kids[1]); + print("%s %d\n", opname(p->op), p->syms[0]->u.c.v.u); + return; + case RET+V: + assert(!p->kids[0]); + assert(!p->kids[1]); + print("%s\n", opname(p->op)); + return; + } + switch (generic(p->op)) { + case CNST: case ADDRG: case ADDRF: case ADDRL: case LABEL: + assert(!p->kids[0]); + assert(!p->kids[1]); + assert(p->syms[0] && p->syms[0]->x.name); + print("%s %s\n", opname(p->op), p->syms[0]->x.name); + return; + case CVF: case CVI: case CVP: case CVU: + assert(p->kids[0]); + assert(!p->kids[1]); + assert(p->syms[0]); + dumptree(p->kids[0]); + print("%s %d\n", opname(p->op), p->syms[0]->u.c.v.i); + return; + case ARG: case BCOM: case NEG: case INDIR: case JUMP: case RET: + assert(p->kids[0]); + assert(!p->kids[1]); + dumptree(p->kids[0]); + print("%s\n", opname(p->op)); + return; + case CALL: + assert(p->kids[0]); + assert(!p->kids[1]); + assert(optype(p->op) != B); + dumptree(p->kids[0]); + print("%s\n", opname(p->op)); + return; + case ASGN: case BOR: case BAND: case BXOR: case RSH: case LSH: + case ADD: case SUB: case DIV: case MUL: case MOD: + assert(p->kids[0]); + assert(p->kids[1]); + dumptree(p->kids[0]); + dumptree(p->kids[1]); + print("%s\n", opname(p->op)); + return; + case EQ: case NE: case GT: case GE: case LE: case LT: + assert(p->kids[0]); + assert(p->kids[1]); + assert(p->syms[0]); + assert(p->syms[0]->x.name); + dumptree(p->kids[0]); + dumptree(p->kids[1]); + print("%s %s\n", opname(p->op), p->syms[0]->x.name); + return; + } + assert(0); +} + +static void I(emit)(Node p) { + for (; p; p = p->link) + dumptree(p); +} + +static void I(export)(Symbol p) { + print("export %s\n", p->x.name); +} + +static void I(function)(Symbol f, Symbol caller[], Symbol callee[], int ncalls) { + int i; + + (*IR->segment)(CODE); + offset = 0; + for (i = 0; caller[i] && callee[i]; i++) { + offset = roundup(offset, caller[i]->type->align); + caller[i]->x.name = callee[i]->x.name = stringf("%d", offset); + caller[i]->x.offset = callee[i]->x.offset = offset; + offset += caller[i]->type->size; + } + maxargoffset = maxoffset = argoffset = offset = 0; + gencode(caller, callee); + print("proc %s %d %d\n", f->x.name, maxoffset, maxargoffset); + emitcode(); + print("endproc %s %d %d\n", f->x.name, maxoffset, maxargoffset); + +} + +static void gen02(Node p) { + assert(p); + if (generic(p->op) == ARG) { + assert(p->syms[0]); + argoffset += (p->syms[0]->u.c.v.i < 4 ? 4 : p->syms[0]->u.c.v.i); + } else if (generic(p->op) == CALL) { + maxargoffset = (argoffset > maxargoffset ? argoffset : maxargoffset); + argoffset = 0; + } +} + +static void gen01(Node p) { + if (p) { + gen01(p->kids[0]); + gen01(p->kids[1]); + gen02(p); + } +} + +static Node I(gen)(Node p) { + Node q; + + assert(p); + for (q = p; q; q = q->link) + gen01(q); + return p; +} + +static void I(global)(Symbol p) { + print("align %d\n", p->type->align > 4 ? 4 : p->type->align); + print("LABELV %s\n", p->x.name); +} + +static void I(import)(Symbol p) { + print("import %s\n", p->x.name); +} + +static void I(local)(Symbol p) { + offset = roundup(offset, p->type->align); + p->x.name = stringf("%d", offset); + p->x.offset = offset; + offset += p->type->size; +} + +static void I(progbeg)(int argc, char *argv[]) {} + +static void I(progend)(void) {} + +static void I(space)(int n) { + print("skip %d\n", n); +} + +static void I(stabline)(Coordinate *cp) { + static char *prevfile; + static int prevline; + + if (cp->file && (prevfile == NULL || strcmp(prevfile, cp->file) != 0)) { + print("file \"%s\"\n", prevfile = cp->file); + prevline = 0; + } + if (cp->y != prevline) + print("line %d\n", prevline = cp->y); +} + +#define b_blockbeg blockbeg +#define b_blockend blockend + +Interface bytecodeIR = { + { 1, 1, 0 }, /* char */ + { 2, 2, 0 }, /* short */ + { 4, 4, 0 }, /* int */ + { 4, 4, 0 }, /* long */ + { 4, 4, 0 }, /* long long */ + { 4, 4, 1 }, /* float */ + { 8, 8, 1 }, /* double */ + { 8, 8, 1 }, /* long double */ + { 4, 4, 0 }, /* T* */ + { 0, 4, 0 }, /* struct */ + 0, /* little_endian */ + 0, /* mulops_calls */ + 0, /* wants_callb */ + 0, /* wants_argb */ + 1, /* left_to_right */ + 0, /* wants_dag */ + 0, /* unsigned_char */ + I(address), + I(blockbeg), + I(blockend), + I(defaddress), + I(defconst), + I(defstring), + I(defsymbol), + I(emit), + I(export), + I(function), + I(gen), + I(global), + I(import), + I(local), + I(progbeg), + I(progend), + I(segment), + I(space), + 0, /* I(stabblock) */ + 0, /* I(stabend) */ + 0, /* I(stabfend) */ + 0, /* I(stabinit) */ + I(stabline), + 0, /* I(stabsym) */ + 0, /* I(stabtype) */ +}; diff --git a/src/cmd/lccom/c.h b/src/cmd/lccom/c.h new file mode 100644 index 0000000..0a77860 --- /dev/null +++ b/src/cmd/lccom/c.h @@ -0,0 +1,598 @@ +#include +#include +#include +#include +#include +#include + +#define NEW(p,a) ((p) = allocate(sizeof *(p), (a))) +#define NEW0(p,a) memset(NEW((p),(a)), 0, sizeof *(p)) +#define isaddrop(op) (specific(op)==ADDRG+P || specific(op)==ADDRL+P \ + || specific(op)==ADDRF+P) + +#define MAXLINE 512 +#define BUFSIZE 4096 + +#define istypename(t,tsym) (kind[t] == CHAR \ + || (t == ID && tsym && tsym->sclass == TYPEDEF)) +#define sizeop(n) ((n)<<10) +#define generic(op) ((op)&0x3F0) +#define specific(op) ((op)&0x3FF) +#define opindex(op) (((op)>>4)&0x3F) +#define opkind(op) ((op)&~0x3F0) +#define opsize(op) ((op)>>10) +#define optype(op) ((op)&0xF) +#ifdef __LCC__ +#ifndef __STDC__ +#define __STDC__ +#endif +#endif +#define NELEMS(a) ((int)(sizeof (a)/sizeof ((a)[0]))) +#undef roundup +#define roundup(x,n) (((x)+((n)-1))&(~((n)-1))) +#define mkop(op,ty) (specific((op) + ttob(ty))) + +#define extend(x,ty) ((x)&(1<<(8*(ty)->size-1)) ? (x)|((~0UL)<<(8*(ty)->size-1)) : (x)&ones(8*(ty)->size)) +#define ones(n) ((n)>=8*sizeof (unsigned long) ? ~0UL : ~((~0UL)<<(n))) + +#define isqual(t) ((t)->op >= CONST) +#define unqual(t) (isqual(t) ? (t)->type : (t)) + +#define isvolatile(t) ((t)->op == VOLATILE \ + || (t)->op == CONST+VOLATILE) +#define isconst(t) ((t)->op == CONST \ + || (t)->op == CONST+VOLATILE) +#define isarray(t) (unqual(t)->op == ARRAY) +#define isstruct(t) (unqual(t)->op == STRUCT \ + || unqual(t)->op == UNION) +#define isunion(t) (unqual(t)->op == UNION) +#define isfunc(t) (unqual(t)->op == FUNCTION) +#define isptr(t) (unqual(t)->op == POINTER) +#define ischar(t) ((t)->size == 1 && isint(t)) +#define isint(t) (unqual(t)->op == INT \ + || unqual(t)->op == UNSIGNED) +#define isfloat(t) (unqual(t)->op == FLOAT) +#define isarith(t) (unqual(t)->op <= UNSIGNED) +#define isunsigned(t) (unqual(t)->op == UNSIGNED) +#define isscalar(t) (unqual(t)->op <= POINTER \ + || unqual(t)->op == ENUM) +#define isenum(t) (unqual(t)->op == ENUM) +#define fieldsize(p) (p)->bitsize +#define fieldright(p) ((p)->lsb - 1) +#define fieldleft(p) (8*(p)->type->size - \ + fieldsize(p) - fieldright(p)) +#define fieldmask(p) (~(fieldsize(p) < 8*unsignedtype->size ? ~0u<mulops_calls \ + && (generic(op)==DIV||generic(op)==MOD||generic(op)==MUL) \ + && ( optype(op)==U || optype(op)==I))) +static Node forest; +static struct dag { + struct node node; + struct dag *hlink; +} *buckets[16]; +int nodecount; +static Tree firstarg; +int assignargs = 1; +int prunetemps = -1; +static Node *tail; + +static int depth = 0; +static Node replace(Node); +static Node prune(Node); +static Node asgnnode(Symbol, Node); +static struct dag *dagnode(int, Node, Node, Symbol); +static Symbol equated(Symbol); +static void fixup(Node); +static void labelnode(int); +static void list(Node); +static void killnodes(Symbol); +static Node node(int, Node, Node, Symbol); +static void printdag1(Node, int, int); +static void printnode(Node, int, int); +static void reset(void); +static Node tmpnode(Node); +static void typestab(Symbol, void *); +static Node undag(Node); +static Node visit(Node, int); +static void unlist(void); +void walk(Tree tp, int tlab, int flab) { + listnodes(tp, tlab, flab); + if (forest) { + Node list = forest->link; + forest->link = NULL; + if (!IR->wants_dag && errcnt == 0) + list = undag(list); + code(Gen)->u.forest = list; + forest = NULL; + } + reset(); + deallocate(STMT); +} + +static Node node(int op, Node l, Node r, Symbol sym) { + int i; + struct dag *p; + + i = (opindex(op)^((unsigned long)sym>>2))&(NELEMS(buckets)-1); + for (p = buckets[i]; p; p = p->hlink) + if (p->node.op == op && p->node.syms[0] == sym + && p->node.kids[0] == l && p->node.kids[1] == r) + return &p->node; + p = dagnode(op, l, r, sym); + p->hlink = buckets[i]; + buckets[i] = p; + ++nodecount; + return &p->node; +} +static struct dag *dagnode(int op, Node l, Node r, Symbol sym) { + struct dag *p; + + NEW0(p, FUNC); + p->node.op = op; + if ((p->node.kids[0] = l) != NULL) + ++l->count; + if ((p->node.kids[1] = r) != NULL) + ++r->count; + p->node.syms[0] = sym; + return p; +} +Node newnode(int op, Node l, Node r, Symbol sym) { + return &dagnode(op, l, r, sym)->node; +} +static void killnodes(Symbol p) { + int i; + struct dag **q; + + for (i = 0; i < NELEMS(buckets); i++) + for (q = &buckets[i]; *q; ) + if (generic((*q)->node.op) == INDIR && + (!isaddrop((*q)->node.kids[0]->op) + || (*q)->node.kids[0]->syms[0] == p)) { + *q = (*q)->hlink; + --nodecount; + } else + q = &(*q)->hlink; +} +static void reset(void) { + if (nodecount > 0) + memset(buckets, 0, sizeof buckets); + nodecount = 0; +} +Node listnodes(Tree tp, int tlab, int flab) { + Node p = NULL, l, r; + int op; + + assert(tlab || flab || (tlab == 0 && flab == 0)); + if (tp == NULL) + return NULL; + if (tp->node) + return tp->node; + if (isarray(tp->type)) + op = tp->op + sizeop(voidptype->size); + else + op = tp->op + sizeop(tp->type->size); + switch (generic(tp->op)) { + case AND: { if (depth++ == 0) reset(); + if (flab) { + listnodes(tp->kids[0], 0, flab); + listnodes(tp->kids[1], 0, flab); + } else { + listnodes(tp->kids[0], 0, flab = genlabel(1)); + listnodes(tp->kids[1], tlab, 0); + labelnode(flab); + } + depth--; } break; + case OR: { if (depth++ == 0) + reset(); + if (tlab) { + listnodes(tp->kids[0], tlab, 0); + listnodes(tp->kids[1], tlab, 0); + } else { + tlab = genlabel(1); + listnodes(tp->kids[0], tlab, 0); + listnodes(tp->kids[1], 0, flab); + labelnode(tlab); + } + depth--; + } break; + case NOT: { return listnodes(tp->kids[0], flab, tlab); } + case COND: { Tree q = tp->kids[1]; + assert(tlab == 0 && flab == 0); + if (tp->u.sym) + addlocal(tp->u.sym); + flab = genlabel(2); + listnodes(tp->kids[0], 0, flab); + assert(q && q->op == RIGHT); + reset(); + listnodes(q->kids[0], 0, 0); + if (forest->op == LABEL+V) { + equatelab(forest->syms[0], findlabel(flab + 1)); + unlist(); + } + list(jump(flab + 1)); + labelnode(flab); + listnodes(q->kids[1], 0, 0); + if (forest->op == LABEL+V) { + equatelab(forest->syms[0], findlabel(flab + 1)); + unlist(); + } + labelnode(flab + 1); + + if (tp->u.sym) + p = listnodes(idtree(tp->u.sym), 0, 0); } break; + case CNST: { Type ty = unqual(tp->type); + assert(ty->u.sym); + if (tlab || flab) { + assert(ty == inttype); + if (tlab && tp->u.v.i != 0) + list(jump(tlab)); + else if (flab && tp->u.v.i == 0) + list(jump(flab)); + } + else if (ty->u.sym->addressed) + p = listnodes(cvtconst(tp), 0, 0); + else + p = node(op, NULL, NULL, constant(ty, tp->u.v)); } break; + case RIGHT: { if ( tp->kids[0] && tp->kids[1] + && generic(tp->kids[1]->op) == ASGN + && ((generic(tp->kids[0]->op) == INDIR + && tp->kids[0]->kids[0] == tp->kids[1]->kids[0]) + || (tp->kids[0]->op == FIELD + && tp->kids[0] == tp->kids[1]->kids[0]))) { + assert(tlab == 0 && flab == 0); + if (generic(tp->kids[0]->op) == INDIR) { + p = listnodes(tp->kids[0], 0, 0); + list(p); + listnodes(tp->kids[1], 0, 0); + } + else { + assert(generic(tp->kids[0]->kids[0]->op) == INDIR); + list(listnodes(tp->kids[0]->kids[0], 0, 0)); + p = listnodes(tp->kids[0], 0, 0); + listnodes(tp->kids[1], 0, 0); + } + } else if (tp->kids[1]) { + listnodes(tp->kids[0], 0, 0); + p = listnodes(tp->kids[1], tlab, flab); + } else + p = listnodes(tp->kids[0], tlab, flab); } break; + case JUMP: { assert(tlab == 0 && flab == 0); + assert(tp->u.sym == 0); + assert(tp->kids[0]); + l = listnodes(tp->kids[0], 0, 0); + list(newnode(JUMP+V, l, NULL, NULL)); + reset(); } break; + case CALL: { Tree save = firstarg; + firstarg = NULL; + assert(tlab == 0 && flab == 0); + if (tp->op == CALL+B && !IR->wants_callb) { + Tree arg0 = tree(ARG+P, tp->kids[1]->type, + tp->kids[1], NULL); + if (IR->left_to_right) + firstarg = arg0; + l = listnodes(tp->kids[0], 0, 0); + if (!IR->left_to_right || firstarg) { + firstarg = NULL; + listnodes(arg0, 0, 0); + } + p = newnode(CALL+V, l, NULL, NULL); + } else { + l = listnodes(tp->kids[0], 0, 0); + r = listnodes(tp->kids[1], 0, 0); + p = newnode(tp->op == CALL+B ? tp->op : op, l, r, NULL); + } + NEW0(p->syms[0], FUNC); + assert(isptr(tp->kids[0]->type)); + assert(isfunc(tp->kids[0]->type->type)); + p->syms[0]->type = tp->kids[0]->type->type; + list(p); + reset(); + cfunc->u.f.ncalls++; + firstarg = save; + } break; + case ARG: { assert(tlab == 0 && flab == 0); + if (IR->left_to_right) + listnodes(tp->kids[1], 0, 0); + if (firstarg) { + Tree arg = firstarg; + firstarg = NULL; + listnodes(arg, 0, 0); + } + l = listnodes(tp->kids[0], 0, 0); + list(newnode(tp->op == ARG+B ? tp->op : op, l, NULL, NULL)); + forest->syms[0] = intconst(tp->type->size); + forest->syms[1] = intconst(tp->type->align); + if (!IR->left_to_right) + listnodes(tp->kids[1], 0, 0); } break; + case EQ: case NE: case GT: case GE: case LE: + case LT: { assert(tp->u.sym == 0); + assert(errcnt || tlab || flab); + l = listnodes(tp->kids[0], 0, 0); + r = listnodes(tp->kids[1], 0, 0); + assert(errcnt || opkind(l->op) == opkind(r->op)); + assert(errcnt || optype(op) == optype(l->op)); + if (tlab) { + assert(flab == 0); + list(newnode(generic(tp->op) + opkind(l->op), l, r, findlabel(tlab))); + } else if (flab) { + switch (generic(tp->op)) { + case EQ: op = NE; break; + case NE: op = EQ; break; + case GT: op = LE; break; + case LT: op = GE; break; + case GE: op = LT; break; + case LE: op = GT; break; + default: assert(0); + } + list(newnode(op + opkind(l->op), l, r, findlabel(flab))); + } + if (forest && forest->syms[0]) + forest->syms[0]->ref++; } break; + case ASGN: { assert(tlab == 0 && flab == 0); + if (tp->kids[0]->op == FIELD) { + Tree x = tp->kids[0]->kids[0]; + Field f = tp->kids[0]->u.field; + assert(generic(x->op) == INDIR); + reset(); + l = listnodes(lvalue(x), 0, 0); + if (fieldsize(f) < 8*f->type->size) { + unsigned int fmask = fieldmask(f); + unsigned int mask = fmask<kids[1]; + if ((q->op == CNST+I && q->u.v.i == 0) || + (q->op == CNST+U && q->u.v.u == 0)) { + q = bittree(BAND, x, cnsttree(unsignedtype, (unsigned long)~mask)); + } else if ((q->op == CNST+I && (q->u.v.i&fmask) == fmask) || + (q->op == CNST+U && (q->u.v.u&fmask) == fmask)) { + q = bittree(BOR, x, cnsttree(unsignedtype, (unsigned long)mask)); + } else { + listnodes(q, 0, 0); + q = bittree(BOR, + bittree(BAND, rvalue(lvalue(x)), + cnsttree(unsignedtype, (unsigned long)~mask)), + bittree(BAND, shtree(LSH, cast(q, unsignedtype), + cnsttree(unsignedtype, (unsigned long)fieldright(f))), + cnsttree(unsignedtype, (unsigned long)mask))); + } + r = listnodes(q, 0, 0); + op = ASGN + ttob(q->type); + } else { + r = listnodes(tp->kids[1], 0, 0); + op = ASGN + ttob(tp->kids[1]->type); + } + } else { + l = listnodes(tp->kids[0], 0, 0); + r = listnodes(tp->kids[1], 0, 0); + } + list(newnode(tp->op == ASGN+B ? tp->op : op, l, r, NULL)); + forest->syms[0] = intconst(tp->kids[1]->type->size); + forest->syms[1] = intconst(tp->kids[1]->type->align); + if (isaddrop(tp->kids[0]->op) + && !tp->kids[0]->u.sym->computed) + killnodes(tp->kids[0]->u.sym); + else + reset(); + p = listnodes(tp->kids[1], 0, 0); } break; + case BOR: case BAND: case BXOR: + case ADD: case SUB: case RSH: + case LSH: { assert(tlab == 0 && flab == 0); + l = listnodes(tp->kids[0], 0, 0); + r = listnodes(tp->kids[1], 0, 0); + p = node(op, l, r, NULL); } break; + case DIV: case MUL: + case MOD: { assert(tlab == 0 && flab == 0); + l = listnodes(tp->kids[0], 0, 0); + r = listnodes(tp->kids[1], 0, 0); + p = node(op, l, r, NULL); + if (IR->mulops_calls && isint(tp->type)) { + list(p); + cfunc->u.f.ncalls++; + } } break; + case RET: { assert(tlab == 0 && flab == 0); + l = listnodes(tp->kids[0], 0, 0); + list(newnode(op, l, NULL, NULL)); } break; + case CVF: case CVI: case CVP: + case CVU: { assert(tlab == 0 && flab == 0); + assert(optype(tp->kids[0]->op) != optype(tp->op) || tp->kids[0]->type->size != tp->type->size); + l = listnodes(tp->kids[0], 0, 0); + p = node(op, l, NULL, intconst(tp->kids[0]->type->size)); + } break; + case BCOM: + case NEG: { assert(tlab == 0 && flab == 0); + l = listnodes(tp->kids[0], 0, 0); + p = node(op, l, NULL, NULL); } break; + case INDIR: { Type ty = tp->kids[0]->type; + assert(tlab == 0 && flab == 0); + l = listnodes(tp->kids[0], 0, 0); + if (isptr(ty)) + ty = unqual(ty)->type; + if (isvolatile(ty) + || (isstruct(ty) && unqual(ty)->u.sym->u.s.vfields)) + p = newnode(tp->op == INDIR+B ? tp->op : op, l, NULL, NULL); + else + p = node(tp->op == INDIR+B ? tp->op : op, l, NULL, NULL); } break; + case FIELD: { Tree q = tp->kids[0]; + if (tp->type == inttype) { + long n = fieldleft(tp->u.field); + q = shtree(RSH, + shtree(LSH, q, cnsttree(inttype, n)), + cnsttree(inttype, n + fieldright(tp->u.field))); + } else if (fieldsize(tp->u.field) < 8*tp->u.field->type->size) + q = bittree(BAND, + shtree(RSH, q, cnsttree(inttype, (long)fieldright(tp->u.field))), + cnsttree(unsignedtype, (unsigned long)fieldmask(tp->u.field))); + assert(tlab == 0 && flab == 0); + p = listnodes(q, 0, 0); } break; + case ADDRG: + case ADDRF: { assert(tlab == 0 && flab == 0); + p = node(tp->op + sizeop(voidptype->size), NULL, NULL, tp->u.sym); + } break; + case ADDRL: { assert(tlab == 0 && flab == 0); + if (tp->u.sym->generated) + addlocal(tp->u.sym); + p = node(tp->op + sizeop(voidptype->size), NULL, NULL, tp->u.sym); } break; + default:assert(0); + } + tp->node = p; + return p; +} +static void list(Node p) { + if (p && p->link == NULL) { + if (forest) { + p->link = forest->link; + forest->link = p; + } else + p->link = p; + forest = p; + } +} +static void labelnode(int lab) { + assert(lab); + if (forest && forest->op == LABEL+V) + equatelab(findlabel(lab), forest->syms[0]); + else + list(newnode(LABEL+V, NULL, NULL, findlabel(lab))); + reset(); +} +static void unlist(void) { + Node p; + + assert(forest); + assert(forest != forest->link); + p = forest->link; + while (p->link != forest) + p = p->link; + p->link = forest->link; + forest = p; +} +Tree cvtconst(Tree p) { + Symbol q = constant(p->type, p->u.v); + Tree e; + + if (q->u.c.loc == NULL) + q->u.c.loc = genident(STATIC, p->type, GLOBAL); + if (isarray(p->type)) { + e = simplify(ADDRG, atop(p->type), NULL, NULL); + e->u.sym = q->u.c.loc; + } else + e = idtree(q->u.c.loc); + return e; +} +void gencode(Symbol caller[], Symbol callee[]) { + Code cp; + Coordinate save; + + if (prunetemps == -1) + prunetemps = !IR->wants_dag; + save = src; + if (assignargs) { + int i; + Symbol p, q; + cp = codehead.next->next; + codelist = codehead.next; + for (i = 0; (p = callee[i]) != NULL + && (q = caller[i]) != NULL; i++) + if (p->sclass != q->sclass || p->type != q->type) + walk(asgn(p, idtree(q)), 0, 0); + codelist->next = cp; + cp->prev = codelist; + } + if (glevel && IR->stabsym) { + int i; + Symbol p, q; + for (i = 0; (p = callee[i]) != NULL + && (q = caller[i]) != NULL; i++) { + (*IR->stabsym)(p); + if (p->sclass != q->sclass || p->type != q->type) + (*IR->stabsym)(q); + } + swtoseg(CODE); + } + cp = codehead.next; + for ( ; errcnt <= 0 && cp; cp = cp->next) + switch (cp->kind) { + case Address: assert(IR->address); + (*IR->address)(cp->u.addr.sym, cp->u.addr.base, + cp->u.addr.offset); break; + case Blockbeg: { + Symbol *p = cp->u.block.locals; + (*IR->blockbeg)(&cp->u.block.x); + for ( ; *p; p++) + if ((*p)->ref != 0.0) + (*IR->local)(*p); + else if (glevel) (*IR->local)(*p); + } + break; + case Blockend: (*IR->blockend)(&cp->u.begin->u.block.x); break; + case Defpoint: src = cp->u.point.src; break; + case Gen: case Jump: + case Label: if (prunetemps) + cp->u.forest = prune(cp->u.forest); + fixup(cp->u.forest); + cp->u.forest = (*IR->gen)(cp->u.forest); break; + case Local: (*IR->local)(cp->u.var); break; + case Switch: break; + default: assert(0); + } + src = save; +} +static void fixup(Node p) { + for ( ; p; p = p->link) + switch (generic(p->op)) { + case JUMP: + if (specific(p->kids[0]->op) == ADDRG+P) + p->kids[0]->syms[0] = + equated(p->kids[0]->syms[0]); + break; + case LABEL: assert(p->syms[0] == equated(p->syms[0])); break; + case EQ: case GE: case GT: case LE: case LT: case NE: + assert(p->syms[0]); + p->syms[0] = equated(p->syms[0]); + } +} +static Symbol equated(Symbol p) { + { Symbol q; for (q = p->u.l.equatedto; q; q = q->u.l.equatedto) assert(p != q); } + while (p->u.l.equatedto) + p = p->u.l.equatedto; + return p; +} +void emitcode(void) { + Code cp; + Coordinate save; + + save = src; + cp = codehead.next; + for ( ; errcnt <= 0 && cp; cp = cp->next) + switch (cp->kind) { + case Address: break; + case Blockbeg: if (glevel && IR->stabblock) { + (*IR->stabblock)('{', cp->u.block.level - LOCAL, cp->u.block.locals); + swtoseg(CODE); + } + break; + case Blockend: if (glevel && IR->stabblock) { + Code bp = cp->u.begin; + foreach(bp->u.block.identifiers, bp->u.block.level, typestab, NULL); + foreach(bp->u.block.types, bp->u.block.level, typestab, NULL); + (*IR->stabblock)('}', bp->u.block.level - LOCAL, bp->u.block.locals); + swtoseg(CODE); + } + break; + case Defpoint: src = cp->u.point.src; + if (glevel > 0 && IR->stabline) { + (*IR->stabline)(&cp->u.point.src); swtoseg(CODE); } break; + case Gen: case Jump: + case Label: if (cp->u.forest) + (*IR->emit)(cp->u.forest); break; + case Local: if (glevel && IR->stabsym) { + (*IR->stabsym)(cp->u.var); + swtoseg(CODE); + } break; + case Switch: { int i; + defglobal(cp->u.swtch.table, LIT); + (*IR->defaddress)(equated(cp->u.swtch.labels[0])); + for (i = 1; i < cp->u.swtch.size; i++) { + long k = cp->u.swtch.values[i-1]; + while (++k < cp->u.swtch.values[i]) { + assert(k < LONG_MAX); + (*IR->defaddress)(equated(cp->u.swtch.deflab)); + } + (*IR->defaddress)(equated(cp->u.swtch.labels[i])); + } + swtoseg(CODE); + } break; + default: assert(0); + } + src = save; +} + +static Node undag(Node forest) { + Node p; + + tail = &forest; + for (p = forest; p; p = p->link) + if (generic(p->op) == INDIR) { + assert(p->count >= 1); + visit(p, 1); + if (p->syms[2]) { + assert(p->syms[2]->u.t.cse); + p->syms[2]->u.t.cse = NULL; + addlocal(p->syms[2]); + } + } else if (iscall(p->op) && p->count >= 1) + visit(p, 1); + else { + assert(p->count == 0); + visit(p, 1); + *tail = p; + tail = &p->link; + } + *tail = NULL; + return forest; +} +static Node replace(Node p) { + if (p && ( generic(p->op) == INDIR + && generic(p->kids[0]->op) == ADDRL + && p->kids[0]->syms[0]->temporary + && p->kids[0]->syms[0]->u.t.replace)) { + p = p->kids[0]->syms[0]->u.t.cse; + if (generic(p->op) == INDIR && isaddrop(p->kids[0]->op)) + p = newnode(p->op, newnode(p->kids[0]->op, NULL, NULL, + p->kids[0]->syms[0]), NULL, NULL); + else if (generic(p->op) == ADDRG) + p = newnode(p->op, NULL, NULL, p->syms[0]); + else + assert(0); + p->count = 1; + } else if (p) { + p->kids[0] = replace(p->kids[0]); + p->kids[1] = replace(p->kids[1]); + } + return p; +} +static Node prune(Node forest) { + Node p, *tail = &forest; + int count = 0; + + for (p = forest; p; p = p->link) { + if (count > 0) { + p->kids[0] = replace(p->kids[0]); + p->kids[1] = replace(p->kids[1]); + } + if (( generic(p->op) == ASGN + && generic(p->kids[0]->op) == ADDRL + && p->kids[0]->syms[0]->temporary + && p->kids[0]->syms[0]->u.t.cse == p->kids[1])) { + Symbol tmp = p->kids[0]->syms[0]; + if (!tmp->defined) + (*IR->local)(tmp); + tmp->defined = 1; + if (( generic(p->kids[1]->op) == INDIR + && isaddrop(p->kids[1]->kids[0]->op) + && p->kids[1]->kids[0]->syms[0]->sclass == REGISTER) + || (( generic(p->kids[1]->op) == INDIR + && isaddrop(p->kids[1]->kids[0]->op)) && tmp->sclass == AUTO) + || (generic(p->kids[1]->op) == ADDRG && tmp->sclass == AUTO)) { + tmp->u.t.replace = 1; + count++; + continue; /* and omit the assignment */ + } + } + /* keep the assignment and other roots */ + *tail = p; + tail = &(*tail)->link; + } + assert(*tail == NULL); + return forest; +} + +static Node visit(Node p, int listed) +{ + if (p) { + if (p->syms[2]) { + p = tmpnode(p); + + } else if ((p->count <= 1 && !iscall(p->op)) || + (p->count == 0 && iscall(p->op))) { + p->kids[0] = visit(p->kids[0], 0); + p->kids[1] = visit(p->kids[1], 0); + } + else if (specific(p->op) == ADDRL+P || specific(p->op) == ADDRF+P) { + assert(!listed); + p = newnode(p->op, NULL, NULL, p->syms[0]); + p->count = 1; + } + else if (p->op == INDIR+B) { + p = newnode(p->op, p->kids[0], NULL, NULL); + p->count = 1; + p->kids[0] = visit(p->kids[0], 0); + p->kids[1] = visit(p->kids[1], 0); + } + else { + p->kids[0] = visit(p->kids[0], 0); + p->kids[1] = visit(p->kids[1], 0); + p->syms[2] = temporary(REGISTER, btot(p->op, opsize(p->op))); + assert(!p->syms[2]->defined); + p->syms[2]->ref = 1; + p->syms[2]->u.t.cse = p; + + *tail = asgnnode(p->syms[2], p); + tail = &(*tail)->link; + if (!listed) + p = tmpnode(p); + } + } + return p; +} +static Node tmpnode(Node p) { + Symbol tmp = p->syms[2]; + + assert(tmp); + if (--p->count == 0) + p->syms[2] = NULL; + p = newnode(INDIR + ttob(tmp->type), + newnode(ADDRL + ttob(voidptype), NULL, NULL, tmp), NULL, NULL); + p->count = 1; + return p; +} +static Node asgnnode(Symbol tmp, Node p) { + p = newnode(ASGN + ttob(tmp->type), + newnode(ADDRL + ttob(voidptype), NULL, NULL, tmp), p, NULL); + p->syms[0] = intconst(tmp->type->size); + p->syms[1] = intconst(tmp->type->align); + return p; +} +/* printdag - print dag p on fd, or the node list if p == 0 */ +void printdag(Node p, int fd) { + FILE *f = fd == 1 ? stdout : stderr; + + printed(0); + if (p == 0) { + if ((p = forest) != NULL) + do { + p = p->link; + printdag1(p, fd, 0); + } while (p != forest); + } else if (*printed(nodeid((Tree)p))) + fprint(f, "node'%d printed above\n", nodeid((Tree)p)); + else + printdag1(p, fd, 0); +} + +/* printdag1 - recursively print dag p */ +static void printdag1(Node p, int fd, int lev) { + int id, i; + + if (p == 0 || *printed(id = nodeid((Tree)p))) + return; + *printed(id) = 1; + for (i = 0; i < NELEMS(p->kids); i++) + printdag1(p->kids[i], fd, lev + 1); + printnode(p, fd, lev); +} + +/* printnode - print fields of dag p */ +static void printnode(Node p, int fd, int lev) { + if (p) { + FILE *f = fd == 1 ? stdout : stderr; + int i, id = nodeid((Tree)p); + fprint(f, "%c%d%s", lev == 0 ? '\'' : '#', id, + &" "[id < 10 ? 0 : id < 100 ? 1 : 2]); + fprint(f, "%s count=%d", opname(p->op), p->count); + for (i = 0; i < NELEMS(p->kids) && p->kids[i]; i++) + fprint(f, " #%d", nodeid((Tree)p->kids[i])); + if (generic(p->op) == CALL && p->syms[0] && p->syms[0]->type) + fprint(f, " {%t}", p->syms[0]->type); + else + for (i = 0; i < NELEMS(p->syms) && p->syms[i]; i++) + if (p->syms[i]->name) + fprint(f, " %s", p->syms[i]->name); + else + fprint(f, " %p", p->syms[i]); + fprint(f, "\n"); + } +} + +/* typestab - emit stab entries for p */ +static void typestab(Symbol p, void *cl) { + if (!isfunc(p->type) && (p->sclass == EXTERN || p->sclass == STATIC) && IR->stabsym) + (*IR->stabsym)(p); + else if ((p->sclass == TYPEDEF || p->sclass == 0) && IR->stabtype) + (*IR->stabtype)(p); +} diff --git a/src/cmd/lccom/dagcheck.md b/src/cmd/lccom/dagcheck.md new file mode 100644 index 0000000..5be0523 --- /dev/null +++ b/src/cmd/lccom/dagcheck.md @@ -0,0 +1,212 @@ +%{ +#include "c.h" +typedef Node NODEPTR_TYPE; +#define OP_LABEL(p) (specific((p)->op)) +#define LEFT_CHILD(p) ((p)->kids[0]) +#define RIGHT_CHILD(p) ((p)->kids[1]) +#define STATE_LABEL(p) ((p)->x.state) +#define PANIC error +%} +%term CNSTF=17 CNSTI=21 CNSTP=23 CNSTU=22 +%term ARGB=41 ARGF=33 ARGI=37 ARGP=39 ARGU=38 +%term ASGNB=57 ASGNF=49 ASGNI=53 ASGNP=55 ASGNU=54 +%term INDIRB=73 INDIRF=65 INDIRI=69 INDIRP=71 INDIRU=70 +%term CVFF=113 CVFI=117 +%term CVIF=129 CVII=133 CVIU=134 +%term CVPP=151 CVPU=150 +%term CVUI=181 CVUP=183 CVUU=182 +%term NEGF=193 NEGI=197 +%term CALLB=217 CALLF=209 CALLI=213 CALLP=215 CALLU=214 CALLV=216 +%term RETF=241 RETI=245 RETP=247 RETU=246 RETV=248 +%term ADDRGP=263 +%term ADDRFP=279 +%term ADDRLP=295 +%term ADDF=305 ADDI=309 ADDP=311 ADDU=310 +%term SUBF=321 SUBI=325 SUBP=327 SUBU=326 +%term LSHI=341 LSHU=342 +%term MODI=357 MODU=358 +%term RSHI=373 RSHU=374 +%term BANDI=389 BANDU=390 +%term BCOMI=405 BCOMU=406 +%term BORI=421 BORU=422 +%term BXORI=437 BXORU=438 +%term DIVF=449 DIVI=453 DIVU=454 +%term MULF=465 MULI=469 MULU=470 +%term EQF=481 EQI=485 EQU=486 +%term GEF=497 GEI=501 GEU=502 +%term GTF=513 GTI=517 GTU=518 +%term LEF=529 LEI=533 LEU=534 +%term LTF=545 LTI=549 LTU=550 +%term NEF=561 NEI=565 NEU=566 +%term JUMPV=584 +%term LABELV=600 +%% +stmt: INDIRB(P) "" +stmt: INDIRF(P) "" +stmt: INDIRI(P) "" +stmt: INDIRU(P) "" +stmt: INDIRP(P) "" +stmt: CALLF(P) "" +stmt: CALLI(P) "" +stmt: CALLU(P) "" +stmt: CALLP(P) "" +stmt: V "" +bogus: I "" 1 +bogus: U "" 1 +bogus: P "" 1 +bogus: F "" 1 +bogus: B "" 1 +bogus: V "" 1 +I: bogus "" 1 +U: bogus "" 1 +P: bogus "" 1 +F: bogus "" 1 +B: bogus "" 1 +V: bogus "" 1 +F: CNSTF "" +I: CNSTI "" +P: CNSTP "" +U: CNSTU "" +V: ARGB(B) "" +V: ARGF(F) "" +V: ARGI(I) "" +V: ARGU(U) "" +V: ARGP(P) "" +V: ASGNB(P,B) "" +V: ASGNF(P,F) "" +V: ASGNI(P,I) "" +V: ASGNU(P,U) "" +V: ASGNP(P,P) "" +B: INDIRB(P) "" +F: INDIRF(P) "" +I: INDIRI(P) "" +U: INDIRU(P) "" +P: INDIRP(P) "" +I: CVII(I) "" +I: CVUI(U) "" +I: CVFI(F) "" +U: CVIU(I) "" +U: CVUU(U) "" +U: CVPU(P) "" +F: CVIF(I) "" +F: CVFF(F) "" +P: CVUP(U) "" +P: CVPP(P) "" +F: NEGF(F) "" +I: NEGI(I) "" +V: CALLB(P,P) "" +F: CALLF(P) "" +I: CALLI(P) "" +U: CALLU(P) "" +P: CALLP(P) "" +V: CALLV(P) "" +V: RETF(F) "" +V: RETI(I) "" +V: RETU(U) "" +V: RETP(P) "" +V: RETV "" +P: ADDRGP "" +P: ADDRFP "" +P: ADDRLP "" +F: ADDF(F,F) "" +I: ADDI(I,I) "" +P: ADDP(P,I) "" +P: ADDP(I,P) "" +P: ADDP(U,P) "" +P: ADDP(P,U) "" +U: ADDU(U,U) "" +F: SUBF(F,F) "" +I: SUBI(I,I) "" +P: SUBP(P,I) "" +P: SUBP(P,U) "" +U: SUBU(U,U) "" +I: LSHI(I,I) "" +U: LSHU(U,I) "" +I: MODI(I,I) "" +U: MODU(U,U) "" +I: RSHI(I,I) "" +U: RSHU(U,I) "" +U: BANDU(U,U) "" +I: BANDI(I,I) "" +U: BCOMU(U) "" +I: BCOMI(I) "" +I: BORI(I,I) "" +U: BORU(U,U) "" +U: BXORU(U,U) "" +I: BXORI(I,I) "" +F: DIVF(F,F) "" +I: DIVI(I,I) "" +U: DIVU(U,U) "" +F: MULF(F,F) "" +I: MULI(I,I) "" +U: MULU(U,U) "" +V: EQF(F,F) "" +V: EQI(I,I) "" +V: EQU(U,U) "" +V: GEF(F,F) "" +V: GEI(I,I) "" +V: GEU(U,U) "" +V: GTF(F,F) "" +V: GTI(I,I) "" +V: GTU(U,U) "" +V: LEF(F,F) "" +V: LEI(I,I) "" +V: LEU(U,U) "" +V: LTF(F,F) "" +V: LTI(I,I) "" +V: LTU(U,U) "" +V: NEF(F,F) "" +V: NEI(I,I) "" +V: NEU(U,U) "" +V: JUMPV(P) "" +V: LABELV "" +%% + +static void reduce(NODEPTR_TYPE p, int goalnt) { + int i, sz = opsize(p->op), rulenumber = _rule(p->x.state, goalnt); + short *nts = _nts[rulenumber]; + NODEPTR_TYPE kids[10]; + + assert(rulenumber); + _kids(p, rulenumber, kids); + for (i = 0; nts[i]; i++) + reduce(kids[i], nts[i]); + switch (optype(p->op)) { +#define xx(ty) if (sz == ty->size) return + case I: + case U: + xx(chartype); + xx(shorttype); + xx(inttype); + xx(longtype); + xx(longlong); + xx(signedptr); + xx(unsignedptr); + break; + case F: + xx(floattype); + xx(doubletype); + xx(longdouble); + break; + case P: + xx(voidptype); + xx(funcptype); + break; + case V: + case B: if (sz == 0) return; +#undef xx + } + printdag(p, 2); + assert(0); +} + +void check(Node p) { + struct _state { short cost[1]; }; + + _label(p); + if (((struct _state *)p->x.state)->cost[1] > 0) { + printdag(p, 2); + assert(0); + } + reduce(p, 1); +} diff --git a/src/cmd/lccom/decl.c b/src/cmd/lccom/decl.c new file mode 100644 index 0000000..dc55021 --- /dev/null +++ b/src/cmd/lccom/decl.c @@ -0,0 +1,1174 @@ +#include "c.h" + +#define add(x,n) (x > inttype->u.sym->u.limits.max.i-(n) ? (overflow=1,x) : x+(n)) +#define chkoverflow(x,n) ((void)add(x,n)) +#define bits2bytes(n) (((n) + 7)/8) +static int regcount; + +static List autos, registers; +Symbol cfunc; /* current function */ +Symbol retv; /* return value location for structs */ + +static void checkref(Symbol, void *); +static Symbol dclglobal(int, char *, Type, Coordinate *); +static Symbol dcllocal(int, char *, Type, Coordinate *); +static Symbol dclparam(int, char *, Type, Coordinate *); +static Type dclr(Type, char **, Symbol **, int); +static Type dclr1(char **, Symbol **, int); +static void decl(Symbol (*)(int, char *, Type, Coordinate *)); +extern void doconst(Symbol, void *); +static void doglobal(Symbol, void *); +static void doextern(Symbol, void *); +static void exitparams(Symbol []); +static void fields(Type); +static void funcdefn(int, char *, Type, Symbol [], Coordinate); +static void initglobal(Symbol, int); +static void oldparam(Symbol, void *); +static Symbol *parameters(Type); +static Type specifier(int *); +static Type structdcl(int); +static Type tnode(int, Type); +void program(void) { + int n; + + level = GLOBAL; + for (n = 0; t != EOI; n++) + if (kind[t] == CHAR || kind[t] == STATIC + || t == ID || t == '*' || t == '(') { + decl(dclglobal); + deallocate(STMT); + if (!(glevel >= 3 || xref)) + deallocate(FUNC); + } else if (t == ';') { + warning("empty declaration\n"); + t = gettok(); + } else { + error("unrecognized declaration\n"); + t = gettok(); + } + if (n == 0) + warning("empty input file\n"); +} +static Type specifier(int *sclass) { + int cls, cons, sign, size, type, vol; + Type ty = NULL; + + cls = vol = cons = sign = size = type = 0; + if (sclass == NULL) + cls = AUTO; + for (;;) { + int *p, tt = t; + switch (t) { + case AUTO: + case REGISTER: if (level <= GLOBAL && cls == 0) + error("invalid use of `%k'\n", t); + p = &cls; t = gettok(); break; + case STATIC: case EXTERN: + case TYPEDEF: p = &cls; t = gettok(); break; + case CONST: p = &cons; t = gettok(); break; + case VOLATILE: p = &vol; t = gettok(); break; + case SIGNED: + case UNSIGNED: p = &sign; t = gettok(); break; + case LONG: if (size == LONG) { + size = 0; + tt = LONG+LONG; + } + p = &size; t = gettok(); break; + case SHORT: p = &size; t = gettok(); break; + case VOID: case CHAR: case INT: case FLOAT: + case DOUBLE: p = &type; ty = tsym->type; + t = gettok(); break; + case ENUM: p = &type; ty = enumdcl(); break; + case STRUCT: + case UNION: p = &type; ty = structdcl(t); break; + case ID: + if (istypename(t, tsym) && type == 0 + && sign == 0 && size == 0) { + use(tsym, src); + ty = tsym->type; + if (isqual(ty) + && ty->size != ty->type->size) { + ty = unqual(ty); + if (isconst(tsym->type)) + ty = qual(CONST, ty); + if (isvolatile(tsym->type)) + ty = qual(VOLATILE, ty); + tsym->type = ty; + } + p = &type; + t = gettok(); + } else + p = NULL; + break; + default: p = NULL; + } + if (p == NULL) + break; + if (*p) + error("invalid use of `%k'\n", tt); + *p = tt; + } + if (sclass) + *sclass = cls; + if (type == 0) { + type = INT; + ty = inttype; + } + if ((size == SHORT && type != INT) + || (size == LONG+LONG && type != INT) + || (size == LONG && type != INT && type != DOUBLE) + || (sign && type != INT && type != CHAR)) + error("invalid type specification\n"); + if (type == CHAR && sign) + ty = sign == UNSIGNED ? unsignedchar : signedchar; + else if (size == SHORT) + ty = sign == UNSIGNED ? unsignedshort : shorttype; + else if (size == LONG && type == DOUBLE) + ty = longdouble; + else if (size == LONG+LONG) { + ty = sign == UNSIGNED ? unsignedlonglong : longlong; + if (Aflag >= 1) + warning("`%t' is a non-ANSI type\n", ty); + } else if (size == LONG) + ty = sign == UNSIGNED ? unsignedlong : longtype; + else if (sign == UNSIGNED && type == INT) + ty = unsignedtype; + if (cons == CONST) + ty = qual(CONST, ty); + if (vol == VOLATILE) + ty = qual(VOLATILE, ty); + return ty; +} +static void decl(Symbol (*dcl)(int, char *, Type, Coordinate *)) { + int sclass; + Type ty, ty1; + static char stop[] = { CHAR, STATIC, ID, 0 }; + + ty = specifier(&sclass); + if (t == ID || t == '*' || t == '(' || t == '[') { + char *id; + Coordinate pos; + id = NULL; + pos = src; + if (level == GLOBAL) { + Symbol *params = NULL; + ty1 = dclr(ty, &id, ¶ms, 0); + if (params && id && isfunc(ty1) + && (t == '{' || istypename(t, tsym) + || (kind[t] == STATIC && t != TYPEDEF))) { + if (sclass == TYPEDEF) { + error("invalid use of `typedef'\n"); + sclass = EXTERN; + } + if (ty1->u.f.oldstyle) + exitscope(); + funcdefn(sclass, id, ty1, params, pos); + return; + } else if (params) + exitparams(params); + } else + ty1 = dclr(ty, &id, NULL, 0); + for (;;) { + if (Aflag >= 1 && !hasproto(ty1)) + warning("missing prototype\n"); + if (id == NULL) + error("missing identifier\n"); + else if (sclass == TYPEDEF) + { + Symbol p = lookup(id, identifiers); + if (p && p->scope == level) + error("redeclaration of `%s'\n", id); + p = install(id, &identifiers, level, + level < LOCAL ? PERM : FUNC); + p->type = ty1; + p->sclass = TYPEDEF; + p->src = pos; + } + else + (void)(*dcl)(sclass, id, ty1, &pos); + if (t != ',') + break; + t = gettok(); + id = NULL; + pos = src; + ty1 = dclr(ty, &id, NULL, 0); + } + } else if (ty == NULL + || ! (isenum(ty) || + (isstruct(ty) && (*unqual(ty)->u.sym->name < '1' || *unqual(ty)->u.sym->name > '9')))) + error("empty declaration\n"); + test(';', stop); +} +static Symbol dclglobal(int sclass, char *id, Type ty, Coordinate *pos) { + Symbol p; + + if (sclass == 0) + sclass = AUTO; + else if (sclass != EXTERN && sclass != STATIC) { + error("invalid storage class `%k' for `%t %s'\n", + sclass, ty, id); + sclass = AUTO; + } + p = lookup(id, identifiers); + if (p && p->scope == GLOBAL) { + if (p->sclass != TYPEDEF && eqtype(ty, p->type, 1)) + ty = compose(ty, p->type); + else + error("redeclaration of `%s' previously declared at %w\n", p->name, &p->src); + + if (!isfunc(ty) && p->defined && t == '=') + error("redefinition of `%s' previously defined at %w\n", p->name, &p->src); + + if ((p->sclass == EXTERN && sclass == STATIC) + || (p->sclass == STATIC && sclass == AUTO) + || (p->sclass == AUTO && sclass == STATIC)) + warning("inconsistent linkage for `%s' previously declared at %w\n", p->name, &p->src); + + } + if (p == NULL || p->scope != GLOBAL) { + Symbol q = lookup(id, externals); + if (q) { + if (sclass == STATIC || !eqtype(ty, q->type, 1)) + warning("declaration of `%s' does not match previous declaration at %w\n", id, &q->src); + + p = relocate(id, externals, globals); + p->sclass = sclass; + } else { + p = install(id, &globals, GLOBAL, PERM); + p->sclass = sclass; + (*IR->defsymbol)(p); + } + if (p->sclass != STATIC) { + static int nglobals; + nglobals++; + if (Aflag >= 2 && nglobals == 512) + warning("more than 511 external identifiers\n"); + } + } else if (p->sclass == EXTERN) + p->sclass = sclass; + p->type = ty; + p->src = *pos; + if (t == '=' && isfunc(p->type)) { + error("illegal initialization for `%s'\n", p->name); + t = gettok(); + initializer(p->type, 0); + } else if (t == '=') { + initglobal(p, 0); + if (glevel > 0 && IR->stabsym) { + (*IR->stabsym)(p); swtoseg(p->u.seg); } + } else if (p->sclass == STATIC && !isfunc(p->type) + && p->type->size == 0) + error("undefined size for `%t %s'\n", p->type, p->name); + return p; +} +static void initglobal(Symbol p, int flag) { + Type ty; + + if (t == '=' || flag) { + if (p->sclass == STATIC) { + for (ty = p->type; isarray(ty); ty = ty->type) + ; + defglobal(p, isconst(ty) ? LIT : DATA); + } else + defglobal(p, DATA); + if (t == '=') + t = gettok(); + ty = initializer(p->type, 0); + if (isarray(p->type) && p->type->size == 0) + p->type = ty; + if (p->sclass == EXTERN) + p->sclass = AUTO; + } +} +void defglobal(Symbol p, int seg) { + p->u.seg = seg; + swtoseg(p->u.seg); + if (p->sclass != STATIC) + (*IR->export)(p); + (*IR->global)(p); + p->defined = 1; +} + +static Type dclr(Type basety, char **id, Symbol **params, int abstract) { + Type ty = dclr1(id, params, abstract); + + for ( ; ty; ty = ty->type) + switch (ty->op) { + case POINTER: + basety = ptr(basety); + break; + case FUNCTION: + basety = func(basety, ty->u.f.proto, + ty->u.f.oldstyle); + break; + case ARRAY: + basety = array(basety, ty->size, 0); + break; + case CONST: case VOLATILE: + basety = qual(ty->op, basety); + break; + default: assert(0); + } + if (Aflag >= 2 && basety->size > 32767) + warning("more than 32767 bytes in `%t'\n", basety); + return basety; +} +static Type tnode(int op, Type type) { + Type ty; + + NEW0(ty, STMT); + ty->op = op; + ty->type = type; + return ty; +} +static Type dclr1(char **id, Symbol **params, int abstract) { + Type ty = NULL; + + switch (t) { + case ID: if (id) + *id = token; + else + error("extraneous identifier `%s'\n", token); + t = gettok(); break; + case '*': t = gettok(); if (t == CONST || t == VOLATILE) { + Type ty1; + ty1 = ty = tnode(t, NULL); + while ((t = gettok()) == CONST || t == VOLATILE) + ty1 = tnode(t, ty1); + ty->type = dclr1(id, params, abstract); + ty = ty1; + } else + ty = dclr1(id, params, abstract); + ty = tnode(POINTER, ty); break; + case '(': t = gettok(); if (abstract + && (t == REGISTER || istypename(t, tsym) || t == ')')) { + Symbol *args; + ty = tnode(FUNCTION, ty); + enterscope(); + if (level > PARAM) + enterscope(); + args = parameters(ty); + exitparams(args); + } else { + ty = dclr1(id, params, abstract); + expect(')'); + if (abstract && ty == NULL + && (id == NULL || *id == NULL)) + return tnode(FUNCTION, NULL); + } break; + case '[': break; + default: return ty; + } + while (t == '(' || t == '[') + switch (t) { + case '(': t = gettok(); { Symbol *args; + ty = tnode(FUNCTION, ty); + enterscope(); + if (level > PARAM) + enterscope(); + args = parameters(ty); + if (params && *params == NULL) + *params = args; + else + exitparams(args); + } + break; + case '[': t = gettok(); { int n = 0; + if (kind[t] == ID) { + n = intexpr(']', 1); + if (n <= 0) { + error("`%d' is an illegal array size\n", n); + n = 1; + } + } else + expect(']'); + ty = tnode(ARRAY, ty); + ty->size = n; } break; + default: assert(0); + } + return ty; +} +static Symbol *parameters(Type fty) { + List list = NULL; + Symbol *params; + + if (kind[t] == STATIC || istypename(t, tsym)) { + int n = 0; + Type ty1 = NULL; + for (;;) { + Type ty; + int sclass = 0; + char *id = NULL; + if (ty1 && t == ELLIPSIS) { + static struct symbol sentinel; + if (sentinel.type == NULL) { + sentinel.type = voidtype; + sentinel.defined = 1; + } + if (ty1 == voidtype) + error("illegal formal parameter types\n"); + list = append(&sentinel, list); + t = gettok(); + break; + } + if (!istypename(t, tsym) && t != REGISTER) + error("missing parameter type\n"); + n++; + ty = dclr(specifier(&sclass), &id, NULL, 1); + if ((ty == voidtype && (ty1 || id)) + || ty1 == voidtype) + error("illegal formal parameter types\n"); + if (id == NULL) + id = stringd(n); + if (ty != voidtype) + list = append(dclparam(sclass, id, ty, &src), list); + if (Aflag >= 1 && !hasproto(ty)) + warning("missing prototype\n"); + if (ty1 == NULL) + ty1 = ty; + if (t != ',') + break; + t = gettok(); + } + fty->u.f.proto = newarray(length(list) + 1, + sizeof (Type *), PERM); + params = ltov(&list, FUNC); + for (n = 0; params[n]; n++) + fty->u.f.proto[n] = params[n]->type; + fty->u.f.proto[n] = NULL; + fty->u.f.oldstyle = 0; + } else { + if (t == ID) + for (;;) { + Symbol p; + if (t != ID) { + error("expecting an identifier\n"); + break; + } + p = dclparam(0, token, inttype, &src); + p->defined = 0; + list = append(p, list); + t = gettok(); + if (t != ',') + break; + t = gettok(); + } + params = ltov(&list, FUNC); + fty->u.f.proto = NULL; + fty->u.f.oldstyle = 1; + } + if (t != ')') { + static char stop[] = { CHAR, STATIC, IF, ')', 0 }; + expect(')'); + skipto('{', stop); + } + if (t == ')') + t = gettok(); + return params; +} +static void exitparams(Symbol params[]) { + assert(params); + if (params[0] && !params[0]->defined) + error("extraneous old-style parameter list\n"); + if (level > PARAM) + exitscope(); + exitscope(); +} + +static Symbol dclparam(int sclass, char *id, Type ty, Coordinate *pos) { + Symbol p; + + if (isfunc(ty)) + ty = ptr(ty); + else if (isarray(ty)) + ty = atop(ty); + if (sclass == 0) + sclass = AUTO; + else if (sclass != REGISTER) { + error("invalid storage class `%k' for `%t%s\n", + sclass, ty, stringf(id ? " %s'" : "' parameter", id)); + sclass = AUTO; + } else if (isvolatile(ty) || isstruct(ty)) { + warning("register declaration ignored for `%t%s\n", + ty, stringf(id ? " %s'" : "' parameter", id)); + sclass = AUTO; + } + + p = lookup(id, identifiers); + if (p && p->scope == level) + error("duplicate declaration for `%s' previously declared at %w\n", id, &p->src); + + else + p = install(id, &identifiers, level, FUNC); + p->sclass = sclass; + p->src = *pos; + p->type = ty; + p->defined = 1; + if (t == '=') { + error("illegal initialization for parameter `%s'\n", id); + t = gettok(); + (void)expr1(0); + } + return p; +} +static Type structdcl(int op) { + char *tag; + Type ty; + Symbol p; + Coordinate pos; + + t = gettok(); + pos = src; + if (t == ID) { + tag = token; + t = gettok(); + } else + tag = ""; + if (t == '{') { + static char stop[] = { IF, ',', 0 }; + ty = newstruct(op, tag); + ty->u.sym->src = pos; + ty->u.sym->defined = 1; + t = gettok(); + if (istypename(t, tsym)) + fields(ty); + else + error("invalid %k field declarations\n", op); + test('}', stop); + } + else if (*tag && (p = lookup(tag, types)) != NULL + && p->type->op == op) { + ty = p->type; + if (t == ';' && p->scope < level) + ty = newstruct(op, tag); + } + else { + if (*tag == 0) + error("missing %k tag\n", op); + ty = newstruct(op, tag); + } + if (*tag && xref) + use(ty->u.sym, pos); + return ty; +} +static void fields(Type ty) { + { int n = 0; + while (istypename(t, tsym)) { + static char stop[] = { IF, CHAR, '}', 0 }; + Type ty1 = specifier(NULL); + for (;;) { + Field p; + char *id = NULL; + Type fty = dclr(ty1, &id, NULL, 0); + p = newfield(id, ty, fty); + if (Aflag >= 1 && !hasproto(p->type)) + warning("missing prototype\n"); + if (t == ':') { + if (unqual(p->type) != inttype + && unqual(p->type) != unsignedtype) { + error("`%t' is an illegal bit-field type\n", + p->type); + p->type = inttype; + } + t = gettok(); + p->bitsize = intexpr(0, 0); + if (p->bitsize > 8*inttype->size || p->bitsize < 0) { + error("`%d' is an illegal bit-field size\n", + p->bitsize); + p->bitsize = 8*inttype->size; + } else if (p->bitsize == 0 && id) { + warning("extraneous 0-width bit field `%t %s' ignored\n", p->type, id); + + p->name = stringd(genlabel(1)); + } + p->lsb = 1; + } + else { + if (id == NULL) + error("field name missing\n"); + else if (isfunc(p->type)) + error("`%t' is an illegal field type\n", p->type); + else if (p->type->size == 0) + error("undefined size for field `%t %s'\n", + p->type, id); + } + if (isconst(p->type)) + ty->u.sym->u.s.cfields = 1; + if (isvolatile(p->type)) + ty->u.sym->u.s.vfields = 1; + n++; + if (Aflag >= 2 && n == 128) + warning("more than 127 fields in `%t'\n", ty); + if (t != ',') + break; + t = gettok(); + } + test(';', stop); + } } + { int bits = 0, off = 0, overflow = 0; + Field p, *q = &ty->u.sym->u.s.flist; + ty->align = IR->structmetric.align; + for (p = *q; p; p = p->link) { + int a = p->type->align ? p->type->align : 1; + if (p->lsb) + a = unsignedtype->align; + if (ty->op == UNION) + off = bits = 0; + else if (p->bitsize == 0 || bits == 0 + || bits - 1 + p->bitsize > 8*unsignedtype->size) { + off = add(off, bits2bytes(bits-1)); + bits = 0; + chkoverflow(off, a - 1); + off = roundup(off, a); + } + if (a > ty->align) + ty->align = a; + p->offset = off; + + if (p->lsb) { + if (bits == 0) + bits = 1; + if (IR->little_endian) + p->lsb = bits; + else + p->lsb = 8*unsignedtype->size - bits + 1 + - p->bitsize + 1; + bits += p->bitsize; + } else + off = add(off, p->type->size); + if (off + bits2bytes(bits-1) > ty->size) + ty->size = off + bits2bytes(bits-1); + if (p->name == NULL + || !('1' <= *p->name && *p->name <= '9')) { + *q = p; + q = &p->link; + } + } + *q = NULL; + chkoverflow(ty->size, ty->align - 1); + ty->size = roundup(ty->size, ty->align); + if (overflow) { + error("size of `%t' exceeds %d bytes\n", ty, inttype->u.sym->u.limits.max.i); + ty->size = inttype->u.sym->u.limits.max.i&(~(ty->align - 1)); + } } +} +static void funcdefn(int sclass, char *id, Type ty, Symbol params[], Coordinate pt) { + int i, n; + Symbol *callee, *caller, p; + Type rty = freturn(ty); + + if (isstruct(rty) && rty->size == 0) + error("illegal use of incomplete type `%t'\n", rty); + for (n = 0; params[n]; n++) + ; + if (n > 0 && params[n-1]->name == NULL) + params[--n] = NULL; + if (Aflag >= 2 && n > 31) + warning("more than 31 parameters in function `%s'\n", id); + if (ty->u.f.oldstyle) { + if (Aflag >= 1) + warning("old-style function definition for `%s'\n", id); + caller = params; + callee = newarray(n + 1, sizeof *callee, FUNC); + memcpy(callee, caller, (n+1)*sizeof *callee); + enterscope(); + assert(level == PARAM); + while (kind[t] == STATIC || istypename(t, tsym)) + decl(dclparam); + foreach(identifiers, PARAM, oldparam, callee); + + for (i = 0; (p = callee[i]) != NULL; i++) { + if (!p->defined) + callee[i] = dclparam(0, p->name, inttype, &p->src); + *caller[i] = *p; + caller[i]->sclass = AUTO; + caller[i]->type = promote(p->type); + } + p = lookup(id, identifiers); + if (p && p->scope == GLOBAL && isfunc(p->type) + && p->type->u.f.proto) { + Type *proto = p->type->u.f.proto; + for (i = 0; caller[i] && proto[i]; i++) { + Type ty = unqual(proto[i]); + if (eqtype(isenum(ty) ? ty->type : ty, + unqual(caller[i]->type), 1) == 0) + break; + else if (isenum(ty) && !isenum(unqual(caller[i]->type))) + warning("compatibility of `%t' and `%t' is compiler dependent\n", + proto[i], caller[i]->type); + } + if (proto[i] || caller[i]) + error("conflicting argument declarations for function `%s'\n", id); + + } + else { + Type *proto = newarray(n + 1, sizeof *proto, PERM); + if (Aflag >= 1) + warning("missing prototype for `%s'\n", id); + for (i = 0; i < n; i++) + proto[i] = caller[i]->type; + proto[i] = NULL; + ty = func(rty, proto, 1); + } + } else { + callee = params; + caller = newarray(n + 1, sizeof *caller, FUNC); + for (i = 0; (p = callee[i]) != NULL && p->name; i++) { + NEW(caller[i], FUNC); + *caller[i] = *p; + if (isint(p->type)) + caller[i]->type = promote(p->type); + caller[i]->sclass = AUTO; + if ('1' <= *p->name && *p->name <= '9') + error("missing name for parameter %d to function `%s'\n", i + 1, id); + + } + caller[i] = NULL; + } + for (i = 0; (p = callee[i]) != NULL; i++) + if (p->type->size == 0) { + error("undefined size for parameter `%t %s'\n", + p->type, p->name); + caller[i]->type = p->type = inttype; + } + if (Aflag >= 2 && sclass != STATIC && strcmp(id, "main") == 0) { + if (ty->u.f.oldstyle) + warning("`%t %s()' is a non-ANSI definition\n", rty, id); + else if (! (rty == inttype + && ((n == 0 && callee[0] == NULL) + || (n == 2 && callee[0]->type == inttype + && isptr(callee[1]->type) && callee[1]->type->type == charptype + && !variadic(ty))))) + warning("`%s' is a non-ANSI definition\n", typestring(ty, id)); + } + p = lookup(id, identifiers); + if (p && isfunc(p->type) && p->defined) + error("redefinition of `%s' previously defined at %w\n", + p->name, &p->src); + cfunc = dclglobal(sclass, id, ty, &pt); + cfunc->u.f.label = genlabel(1); + cfunc->u.f.callee = callee; + cfunc->u.f.pt = src; + cfunc->defined = 1; + if (xref) + use(cfunc, cfunc->src); + if (Pflag) + printproto(cfunc, cfunc->u.f.callee); + if (ncalled >= 0) + ncalled = findfunc(cfunc->name, pt.file); + labels = table(NULL, LABELS); + stmtlabs = table(NULL, LABELS); + refinc = 1.0; + regcount = 0; + codelist = &codehead; + codelist->next = NULL; + if (!IR->wants_callb && isstruct(rty)) + retv = genident(AUTO, ptr(unqual(rty)), PARAM); + compound(0, NULL, 0); + + definelab(cfunc->u.f.label); + if (events.exit) + apply(events.exit, cfunc, NULL); + walk(NULL, 0, 0); + exitscope(); + assert(level == PARAM); + foreach(identifiers, level, checkref, NULL); + if (!IR->wants_callb && isstruct(rty)) { + Symbol *a; + a = newarray(n + 2, sizeof *a, FUNC); + a[0] = retv; + memcpy(&a[1], callee, (n+1)*sizeof *callee); + callee = a; + a = newarray(n + 2, sizeof *a, FUNC); + NEW(a[0], FUNC); + *a[0] = *retv; + memcpy(&a[1], caller, (n+1)*sizeof *callee); + caller = a; + } + if (!IR->wants_argb) + for (i = 0; caller[i]; i++) + if (isstruct(caller[i]->type)) { + caller[i]->type = ptr(caller[i]->type); + callee[i]->type = ptr(callee[i]->type); + caller[i]->structarg = callee[i]->structarg = 1; + } + if (glevel > 1) for (i = 0; callee[i]; i++) callee[i]->sclass = AUTO; + if (cfunc->sclass != STATIC) + (*IR->export)(cfunc); + if (glevel && IR->stabsym) { + swtoseg(CODE); (*IR->stabsym)(cfunc); } + swtoseg(CODE); + (*IR->function)(cfunc, caller, callee, cfunc->u.f.ncalls); + if (glevel && IR->stabfend) + (*IR->stabfend)(cfunc, lineno); + foreach(stmtlabs, LABELS, checklab, NULL); + exitscope(); + expect('}'); + labels = stmtlabs = NULL; + retv = NULL; + cfunc = NULL; +} +static void oldparam(Symbol p, void *cl) { + int i; + Symbol *callee = cl; + + for (i = 0; callee[i]; i++) + if (p->name == callee[i]->name) { + callee[i] = p; + return; + } + error("declared parameter `%s' is missing\n", p->name); +} + +void compound(int loop, struct swtch *swp, int lev) { + Code cp; + int nregs; + + walk(NULL, 0, 0); + cp = code(Blockbeg); + enterscope(); + assert(level >= LOCAL); + if (level == LOCAL && events.entry) + apply(events.entry, cfunc, NULL); + definept(NULL); + expect('{'); + autos = registers = NULL; + if (level == LOCAL && IR->wants_callb + && isstruct(freturn(cfunc->type))) { + retv = genident(AUTO, ptr(unqual(freturn(cfunc->type))), level); + retv->defined = 1; + retv->ref = 1; + registers = append(retv, registers); + } + while (kind[t] == CHAR || kind[t] == STATIC + || (istypename(t, tsym) && getchr() != ':')) + decl(dcllocal); + { + int i; + Symbol *a = ltov(&autos, STMT); + nregs = length(registers); + for (i = 0; a[i]; i++) + registers = append(a[i], registers); + cp->u.block.locals = ltov(®isters, FUNC); + } + if (events.blockentry) + apply(events.blockentry, cp->u.block.locals, NULL); + while (kind[t] == IF || kind[t] == ID) + statement(loop, swp, lev); + walk(NULL, 0, 0); + foreach(identifiers, level, checkref, NULL); + { + int i = nregs, j; + Symbol p; + for ( ; (p = cp->u.block.locals[i]) != NULL; i++) { + for (j = i; j > nregs + && cp->u.block.locals[j-1]->ref < p->ref; j--) + cp->u.block.locals[j] = cp->u.block.locals[j-1]; + cp->u.block.locals[j] = p; + } + } + if (level == LOCAL) { + Code cp; + for (cp = codelist; cp->kind < Label; cp = cp->prev) + ; + if (cp->kind != Jump) { + if (freturn(cfunc->type) != voidtype) { + warning("missing return value\n"); + retcode(cnsttree(inttype, 0L)); + } else + retcode(NULL); + } + } + if (events.blockexit) + apply(events.blockexit, cp->u.block.locals, NULL); + cp->u.block.level = level; + cp->u.block.identifiers = identifiers; + cp->u.block.types = types; + code(Blockend)->u.begin = cp; + if (reachable(Gen)) + definept(NULL); + if (level > LOCAL) { + exitscope(); + expect('}'); + } +} +static void checkref(Symbol p, void *cl) { + if (p->scope >= PARAM + && (isvolatile(p->type) || isfunc(p->type))) + p->addressed = 1; + if (Aflag >= 2 && p->defined && p->ref == 0) { + if (p->sclass == STATIC) + warning("static `%t %s' is not referenced\n", + p->type, p->name); + else if (p->scope == PARAM) + warning("parameter `%t %s' is not referenced\n", + p->type, p->name); + else if (p->scope >= LOCAL && p->sclass != EXTERN) + warning("local `%t %s' is not referenced\n", + p->type, p->name); + } + if (p->sclass == AUTO + && ((p->scope == PARAM && regcount == 0) + || p->scope >= LOCAL) + && !p->addressed && isscalar(p->type) && p->ref >= 3.0) + p->sclass = REGISTER; + if (level == GLOBAL && p->sclass == STATIC && !p->defined + && isfunc(p->type) && p->ref) + error("undefined static `%t %s'\n", p->type, p->name); + assert(!(level == GLOBAL && p->sclass == STATIC && !p->defined && !isfunc(p->type))); +} +static Symbol dcllocal(int sclass, char *id, Type ty, Coordinate *pos) { + Symbol p, q; + + if (sclass == 0) + sclass = isfunc(ty) ? EXTERN : AUTO; + else if (isfunc(ty) && sclass != EXTERN) { + error("invalid storage class `%k' for `%t %s'\n", + sclass, ty, id); + sclass = EXTERN; + } else if (sclass == REGISTER + && (isvolatile(ty) || isstruct(ty) || isarray(ty))) { + warning("register declaration ignored for `%t %s'\n", + ty, id); + sclass = AUTO; + } + q = lookup(id, identifiers); + if ((q && q->scope >= level) + || (q && q->scope == PARAM && level == LOCAL)) { + if (sclass == EXTERN && q->sclass == EXTERN + && eqtype(q->type, ty, 1)) + ty = compose(ty, q->type); + else + error("redeclaration of `%s' previously declared at %w\n", q->name, &q->src); + } + assert(level >= LOCAL); + p = install(id, &identifiers, level, sclass == STATIC || sclass == EXTERN ? PERM : FUNC); + p->type = ty; + p->sclass = sclass; + p->src = *pos; + switch (sclass) { + case EXTERN: + q = lookup(id, globals); + if (q == NULL || q->sclass == TYPEDEF || q->sclass == ENUM) { + q = lookup(id, externals); + if (q == NULL) { + q = install(p->name, &externals, GLOBAL, PERM); + q->type = p->type; + q->sclass = EXTERN; + q->src = src; + (*IR->defsymbol)(q); + } + } + if (!eqtype(p->type, q->type, 1)) + warning("declaration of `%s' does not match previous declaration at %w\n", + q->name, &q->src); + p->u.alias = q; + break; + case STATIC: + (*IR->defsymbol)(p); + initglobal(p, 0); + if (! p->defined) { + if (p->type->size > 0) { + defglobal(p, BSS); + (*IR->space)(p->type->size); + } else { + error("undefined size for `%t %s'\n", + p->type, p->name); + } + } + p->defined = 1; + break; + case REGISTER: + registers = append(p, registers); + regcount++; + p->defined = 1; + break; + case AUTO: + autos = append(p, autos); + p->defined = 1; + if (isarray(ty)) + p->addressed = 1; + break; + default: + assert(0); + } + if (t == '=') { + Tree e; + if (sclass == EXTERN) + error("illegal initialization of `extern %s'\n", id); + t = gettok(); + definept(NULL); + if (isscalar(p->type) + || (isstruct(p->type) && t != '{')) { + if (t == '{') { + t = gettok(); + e = expr1(0); + expect('}'); + } else + e = expr1(0); + } else { + Symbol t1; + Type ty = p->type, ty1 = ty; + while (isarray(ty1)) + ty1 = ty1->type; + if (!isconst(ty) && (!isarray(ty) || !isconst(ty1))) + ty = qual(CONST, ty); + t1 = genident(STATIC, ty, GLOBAL); + initglobal(t1, 1); + if (isarray(p->type) && p->type->size == 0 + && t1->type->size > 0) + p->type = array(p->type->type, + t1->type->size/t1->type->type->size, 0); + e = idtree(t1); + } + walk(root(asgn(p, e)), 0, 0); + p->ref = 1; + } + if (!isfunc(p->type) && p->defined && p->type->size <= 0) + error("undefined size for `%t %s'\n", p->type, id); + return p; +} +void finalize(void) { + foreach(externals, GLOBAL, doextern, NULL); + foreach(identifiers, GLOBAL, doglobal, NULL); + foreach(identifiers, GLOBAL, checkref, NULL); + foreach(constants, CONSTANTS, doconst, NULL); +} +static void doextern(Symbol p, void *cl) { + (*IR->import)(p); +} +static void doglobal(Symbol p, void *cl) { + if (! p->defined && (p->sclass == EXTERN + || (isfunc(p->type) && p->sclass == AUTO))) + (*IR->import)(p); + else if (!p->defined && !isfunc(p->type) + && (p->sclass == AUTO || p->sclass == STATIC)) { + if (isarray(p->type) + && p->type->size == 0 && p->type->type->size > 0) + p->type = array(p->type->type, 1, 0); + if (p->type->size > 0) { + defglobal(p, BSS); + (*IR->space)(p->type->size); + if (glevel > 0 && IR->stabsym) + (*IR->stabsym)(p); + } else + error("undefined size for `%t %s'\n", + p->type, p->name); + p->defined = 1; + } + if (Pflag + && !isfunc(p->type) + && !p->generated && p->sclass != EXTERN) + printdecl(p, p->type); +} +void doconst(Symbol p, void *cl) { + if (p->u.c.loc) { + assert(p->u.c.loc->u.seg == 0); + defglobal(p->u.c.loc, LIT); + if (isarray(p->type) && p->type->type == widechar) { + unsigned int *s = p->u.c.v.p; + int n = p->type->size/widechar->size; + while (n-- > 0) { + Value v; + v.u = *s++; + (*IR->defconst)(widechar->op, widechar->size, v); + } + } else if (isarray(p->type)) + (*IR->defstring)(p->type->size, p->u.c.v.p); + else + (*IR->defconst)(p->type->op, p->type->size, p->u.c.v); + p->u.c.loc = NULL; + } +} + +void checklab(Symbol p, void *cl) +{ + if (!p->defined) + error("undefined label `%s'\n", p->name); + p->defined = 1; +} + +Type enumdcl(void) +{ + char *tag; + Type ty; + Symbol p = 0; + Coordinate pos; + + t = gettok(); + pos = src; + if (t == ID) { + tag = token; + t = gettok(); + } else + tag = ""; + if (t == '{') { + static char follow[] = { IF, 0 }; + int n = 0; + long k = -1; + List idlist = 0; + ty = newstruct(ENUM, tag); + t = gettok(); + if (t != ID) + error("expecting an enumerator identifier\n"); + while (t == ID) { + char *id = token; + Coordinate s; + if (tsym && tsym->scope == level) + error("redeclaration of `%s' previously declared at %w\n", + token, &tsym->src); + s = src; + t = gettok(); + if (t == '=') { + t = gettok(); + k = intexpr(0, 0); + } else { + if (k == inttype->u.sym->u.limits.max.i) + error("overflow in value for enumeration constant `%s'\n", id); + k++; + } + p = install(id, &identifiers, level, level < LOCAL ? PERM : FUNC); + p->src = s; + p->type = ty; + p->sclass = ENUM; + p->u.value = k; + idlist = append(p, idlist); + n++; + if (Aflag >= 2 && n == 128) + warning("more than 127 enumeration constants in `%t'\n", ty); + if (t != ',') + break; + t = gettok(); + if (Aflag >= 2 && t == '}') + warning("non-ANSI trailing comma in enumerator list\n"); + } + test('}', follow); + ty->type = inttype; + ty->size = ty->type->size; + ty->align = ty->type->align; + ty->u.sym->u.idlist = ltov(&idlist, PERM); + ty->u.sym->defined = 1; + } else if ((p = lookup(tag, types)) != NULL && p->type->op == ENUM) { + ty = p->type; + if (t == ';') + error("empty declaration\n"); + } else { + error("unknown enumeration `%s'\n", tag); + ty = newstruct(ENUM, tag); + ty->type = inttype; + } + if (*tag && xref) + use(p, pos); + return ty; +} + +Type typename(void) { + Type ty = specifier(NULL); + + if (t == '*' || t == '(' || t == '[') { + ty = dclr(ty, NULL, NULL, 1); + if (Aflag >= 1 && !hasproto(ty)) + warning("missing prototype\n"); + } + return ty; +} diff --git a/src/cmd/lccom/doc/install.html b/src/cmd/lccom/doc/install.html new file mode 100644 index 0000000..274db80 --- /dev/null +++ b/src/cmd/lccom/doc/install.html @@ -0,0 +1,774 @@ + + + + + +Installing lcc + + + + +

Installing lcc

+ +

Christopher +W. Fraser and David R. Hanson, Microsoft Research
+September 2002

+ +

Contents

+ + +
  • Introduction
  • +
  • Installation on UNIX
  • +
  • Building the Driver
  • +
  • Building the Compiler and Accessories
  • +
  • Installation on Windows
  • +
  • Reporting Bugs
  • +
  • Keeping in Touch
  • +
    + +

    Introduction

    + +

    lcc is the ANSI C compiler +described in our book A Retargetable C Compiler: Design and Implementation +(Addison-Wesley, 1995, ISBN 0-8053-1670-1).

    + +

    If you're installing lcc on a UNIX system, read the remainder of this section and +continue with the next section. If you're installing lcc on a Windows system, you should read the rest of this section, the following three sections, and the Windows section.

    + +

    Extract the distribution into its own directory. All non-absolute paths below are +relative to this directory. The distribution holds the following subdirectories.

    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    srcsource code
    etcdriver, accessories
    libruntime library source code
    cpppreprocessor source code
    lburgcode-generator generator source code
    docthis document, man pages
    include/*/*include files
    tsttest suite
    alpha/*/tstALPHA test outputs
    mips/*/tstMIPS test outputs
    sparc/*/tstSPARC test outputs
    x86/*/tstX86 test outputs
    +
    + +

    doc/install.html is the HTML file for this document.

    + +

    The installation makefile is designed so that lcc can be installed from a read-only +file system or directory, which is common in networked environments, so the distribution +can be unloaded on a central file server. You will need an existing ANSI/ISO C +compiler to build and install lcc.

    + +

    Installation on UNIX

    + +

    The compilation components (the preprocessor, include files, and compiler proper, etc.) +are installed in a single build directory. On multi-platform systems supported by +a central file server, it's common to store the build directory in a location specific to +the platform and to the version of lcc, and to point a symbolic link to this location. For +example,

    + +
    +
    % ln -s $BUILDDIR/sparc-solaris /usr/local/lib/lcc
    +
    + +

    points /usr/local/lib/lcc to a build directory for lcc on the SPARC under Solaris. Links into /usr/local/lib/lcc are created for the programs lcc +and bprint. Thus, a new distribution can be installed by building it in its +own build directory and changing one symbolic link to point to that directory. If these +conventions or their equivalents are followed, the host-specific parts of the driver +program, lcc, can be used unmodified.

    + +

    Installation on a UNIX system involves the following steps. Below, the build directory +is referred to as BUILDDIR, and the commands below are executed +from the distribution directory.

      +
    1. Create the build directory, using a version- and platform-specific naming convention as + suggested above, and record the name of this directory in the BUILDDIR + environment variable:
      +
      % setenv BUILDDIR $BUILDDIR/sparc-solaris
      +% mkdir -p $BUILDDIR
      +
      +

      Here and below, commands assume the C shell. Also, you'll need a version of mkdir + that supports the -p option, which creates intermediate directories as + necessary.

      +
    2. +
    3. Copy the man pages to the repository for local man pages, e.g.,
      +
      % cp doc/*.1 /usr/local/man/man1
      +
      +

      Some users copy the man pages to the build directory and create the appropriate + symbolic links, e.g.,

      +
      +
      % cp doc/*.1 $BUILDDIR
      +% ln -s $BUILDDIR/*.1 /usr/local/man/man1
      +
      +
    4. +
    5. Platform-specific include files are in directories named include/target/os. + Create the include directory in the build directory, and copy the include hierarchy for + your platform to this directory, e.g.,
      +
      % mkdir $BUILDDIR/include
      +% cp -p -R include/sparc/solaris/* $BUILDDIR/include
      +
      +

      Again, some users create a symbolic link to the appropriate directory in the + distribution instead of copying the include files. For example, at Princeton, the + distributions are stored under /proj/pkg/lcc, so the included files are + "installed" by creating one symbolic link:

      +
      +
      % ln -s $BUILDDIR/include/sparc/solaris $BUILDDIR/include
      +
      +

      If you're installing lcc on Linux, you must also plant a symbolic link named gcc + to gcc's library directory, because lcc uses gcc's C preprocessor and most of gcc's header + files:

      +
      +
      % ln -s /usr/lib/gcc-lib/i386-redhat-linux/2.96 $BUILDDIR/gcc
      +
      +

      The library directory shown above may be different on your Linux machine; to determine + the correct directory, browse /usr/lib/gcc-lib, or execute

      +
      +
      % cc -v tst/8q.c
      +
      +

      and examine the diagnostic output. Make sure that $BUILDDIR/gcc/cpp0 and $BUILDDIR/gcc/include + are, respectively, gcc's C preprocessor and header files. On Linux, lcc looks for + include files in $BUILDDIR/include, $BUILDDIR/gcc/include, and /usr/include, + in that order; see Building the Driver and etc/linux.c for details.

      +
    6. +
    7. The makefile includes the file named by the CUSTOM + macro; the default is custom.mk, and an empty custom.mk is + included in the distribution. If desired, prepare a site-specification customization file + and define CUSTOM to the path of that file when invoking make in steps 5 and + 6, e.g.,
      +
      make CUSTOM=solaris.mk
      +
      +

      You can, for example, use customization files to record site-specific values for macros + instead of using environment variables, and to record targets for the steps in this list.

      +
    8. +
    9. Build the host-specific driver, creating a custom host-specific part, if necessary. See Building the Driver.
    10. +
    11. Build the preprocessor, compiler proper, library, and other accessories. See Building the Compiler.
    12. +
    13. Plant symbolic links to the build directory and to the installed programs, e.g.,
      +
      % ln -s $BUILDDIR /usr/local/lib/lcc
      +% ln -s /usr/local/lib/{lcc,bprint} /usr/local/bin
      +
      +

      Some users copy bprint and lcc into /usr/local/bin + instead of creating symbolic links. The advantage of creating the links for lcc + and bprint as shown is that, once established, they point indirectly to + whatever /usr/local/lib/lcc points to; installing a new version of lcc can be done by changing /usr/local/lib/lcc to point to the build + directory for the new version.

      +
    14. +
    + +

    Building the Driver

    + +

    The preprocessor, compiler, assembler, and loader are invoked by a driver program, lcc, +which is similar to cc on most systems. It's described in the man page doc/lcc.1. +The driver is built by combining the host-independent part, etc/lcc.c, +with a small host-specific part. Distributed host-specific parts are named etc/os.c, +where os is the name of the operating system for the host on which lcc +is being installed. If you're following the installations conventions described above, you +can probably use one of the host-specific parts unmodified; otherwise, pick one that is +closely related to your platform, copy it to whatever.c, and edit it +as described below. You should not have to edit etc/lcc.c.

    + +

    We'll use etc/solaris.c as an example in +describing how the host-specific part works. This example illustrates all the important +features. Make sure you have the environment variable BUILDDIR set correctly, +and build the driver with a make command, e.g.,

    + +
    +
    % make HOSTFILE=etc/solaris.c lcc
    +cc -g -c -o $BUILDDIR/sparc-solaris/lcc.o etc/lcc.c
    +cc -g -c -o $BUILDDIR/sparc-solaris/host.o etc/solaris.c
    +cc -g -o $BUILDDIR/lcc $BUILDDIR/sparc-solaris/lcc.o $BUILDDIR/sparc-solaris/host.o
    +
    + +

    Of course, the actual value of BUILDDIR will appear in place of +$BUILDDIR. The symbolic name HOSTFILE specifies the path to the host-specific part, +either one in the distribution or whatever.c. Some versions of make +may require the -e option in order to read the environment.

    + +

    Here's etc/solaris.c:

    + +
    +
    /* Sparcs running Solaris 2.5.1 at CS Dept., Princeton University */
    +
    +#include <string.h>
    +
    +static char rcsid[] = "$ Id: solaris.c,v 1.10 1998/09/14 20:36:33 drh Exp $";
    +
    +#ifndef LCCDIR
    +#define LCCDIR "/usr/local/lib/lcc/"
    +#endif
    +#ifndef SUNDIR
    +#define SUNDIR "/opt/SUNWspro/SC4.2/lib/"
    +#endif
    +
    +char *suffixes[] = { ".c", ".i", ".s", ".o", ".out", 0 };
    +char inputs[256] = "";
    +char *cpp[] = { LCCDIR "cpp",
    +	"-D__STDC__=1", "-Dsparc", "-D__sparc__", "-Dsun", "-D__sun__", "-Dunix",
    +	"$1", "$2", "$3", 0 };
    +char *include[] = { "-I" LCCDIR "include", "-I/usr/local/include",
    +	"-I/usr/include", 0 };
    +char *com[] = { LCCDIR "rcc", "-target=sparc/solaris",
    +	"$1", "$2", "$3", 0 };
    +char *as[] = { "/usr/ccs/bin/as", "-Qy", "-s", "-o", "$3", "$1", "$2", 0 };
    +char *ld[] = { "/usr/ccs/bin/ld", "-o", "$3", "$1",
    +	SUNDIR "crti.o", SUNDIR "crt1.o",
    +	SUNDIR "values-xa.o", "$2", "",
    +	"-Y", "P," SUNDIR ":/usr/ccs/lib:/usr/lib", "-Qy",
    +	"-L" LCCDIR, "-llcc", "-lm", "-lc", SUNDIR "crtn.o", 0 };
    +
    +extern char *concat(char *, char *);
    +
    +int option(char *arg) {
    +	if (strncmp(arg, "-lccdir=", 8) == 0) {
    +		cpp[0] = concat(&arg[8], "/cpp");
    +		include[0] = concat("-I", concat(&arg[8], "/include"));
    +		ld[12] = concat("-L", &arg[8]);
    +		com[0] = concat(&arg[8], "/rcc");
    +	} else if (strcmp(arg, "-p") == 0) {
    +		ld[5] = SUNDIR "mcrt1.o";
    +		ld[10] = "P," SUNDIR "libp:/usr/ccs/lib/libp:/usr/lib/libp:"
    +			 SUNDIR ":/usr/ccs/lib:/usr/lib";
    +	} else if (strcmp(arg, "-b") == 0)
    +		;
    +	else if (strncmp(arg, "-ld=", 4) == 0)
    +		ld[0] = &arg[4];
    +	else
    +		return 0;
    +	return 1;
    +}
    +
    + +

    LCCDIR defaults to "/usr/local/lib/lcc/" unless +it's defined by a -D option as part of CFLAGS in the make +command, e.g.,

    + +
    +
    % make HOSTFILE=etc/solaris.c CFLAGS='-DLCCDIR=\"/v/lib/lcc/\"' lcc
    +
    + +

    Note the trailing slash; SUNDIR is provided so you can use etc/solaris.c +even if you have a different version of the Sun Pro compiler suite. If you're using the +gcc compiler tools instead of the Sun Pro tools, see etc/gcc-solaris.c.

    + +

    Most of the host-specific code is platform-specific data and templates for the commands +that invoke the preprocessor, compiler, assembler, and loader. The suffixes +array lists the file name suffixes for C source files, preprocessed source files, assembly +language source files, object files, and executable files. suffixes must be +terminated with a null pointer, as shown above. The initialization of suffixes +in etc/solaris.c are the typical ones for UNIX +systems. Each element of suffixes is actually a list of suffixes, separated +by semicolons; etc/win32.c holds an example:

    + +
    +
    char *suffixes[] = { ".c;.C", ".i;.I", ".asm;.ASM;.s;.S", ".obj;.OBJ", ".exe", 0 };
    +
    + +

    When a list is given, the first suffix is used whenever lcc needs to generate a file +name. For example, with etc/win32.c, lcc emits +the generated assembly code into .asm files.

    + +

    The inputs array holds a null-terminated string of directories separated +by colons or semicolons. These are used as the default value of LCCINPUTS, if +the environment variable LCCINPUTS is not set; see the man +page.

    + +

    Each command template is an array of pointers to strings terminated with a null +pointer; the strings are full path names of commands, arguments, or argument placeholders, +which are described below. Commands are executed in a child process, and templates can +contain multiple commands by separating commands with newlines. The driver runs each +command in a new process.

    + +

    The cpp array gives the command for running lcc's preprocessor, cpp. +Literal arguments specified in templates, e.g., "-Dsparc" in the cpp +command above, are passed to the command as given.

    + +

    The strings "$1", "$2", and "$3" +in templates are placeholders for lists of arguments that are substituted in a +copy of the template before the command is executed. $1 is replaced by the options +specified by the user; for the preprocessor, this list always contains at least -D__LCC__. +$2 is replaced by the input files, and $3 is replaced +by the output file.

    + +

    Zero-length arguments after replacement are removed from the argument list before the +command is invoked. So, for example, if the preprocessor is invoked without an output +file, "$3" becomes "", which is removed from +the final argument list.

    + +

    The include array is a list of -I options that specify which +directives should be searched to satisfy include directives. These directories are +searched in the order given. The first directory should be the one to which the ANSI +header files were copied as described in UNIX or Windows +installation instructions. The driver adds these options to cpp's arguments +when it invokes the preprocessor, except when -N is specified.

    + +

    com gives the command for invoking the compiler. This template can appear +as shown above in a custom host-specific part, but the option -target=sparc/solaris +should be edited to the target/os for your platform. If com[1] +includes the string "win32", the driver assumes it's running on +Windows. lcc can generate code for all of the target/os +combinations listed in the file src/bind.c. The -target option +specifies the default combination. The driver's -Wf option can be used to +specify other combinations; the man page elaborates.

    + +

    as gives the command for invoking the assembler. On Linux, you must be +running at least version 2.8.1 of the GNU assembler; earlier versions mis-assemble some +instructions emitted by lcc.

    + +

    ld gives the command for invoking the loader. For the other commands, the +list $2 contains a single file; for ld, $2 contains +all ".o" files and libraries, and $3 is a.out, unless +the -o option is specified. As suggested in the code above, ld +must also specify the appropriate startup code and default libraries, including the lcc +library, liblcc.a.

    + +

    The option function is described below; the minimal option +function just returns 0.

    + +

    You can test lcc with the options -v -v to display the +commands that would be executed, e.g.,

    + +
    +
    % $BUILDDIR/lcc -v -v foo.c baz.c mylib.a -lX11
    +$BUILDDIR/sparc-solaris/lcc $ Id: lcc.c,v 4.33 2001/06/28 22:19:58 drh $
    +foo.c:
    +/usr/local/lib/lcc/cpp -D__STDC__=1 -Dsparc -D__sparc__ -Dsun -D__sun__ -Dunix -D__LCC__i
    +/usr/local/lib/lcc/rcc -target=sparc/solaris -v /tmp/lcc4060.i /tmp/lcc4061.s
    +/usr/ccs/bin/as -Qy -s -o /tmp/lcc4062.o /tmp/lcc4061.s
    +baz.c:
    +/usr/local/lib/lcc/cpp -D__STDC__=1 -Dsparc -D__sparc__ -Dsun -D__sun__ -Dunix -D__LCC__i
    +/usr/local/lib/lcc/rcc -target=sparc/solaris -v /tmp/lcc4060.i /tmp/lcc4061.s
    +/usr/ccs/bin/as -Qy -s -o /tmp/lcc4063.o /tmp/lcc4061.s
    +/usr/ccs/bin/ld -o a.out /opt/SUNWspro/SC4.2/lib/crti.o /opt/SUNWspro/SC4.2/lib/crt1.o /o
    +rm /tmp/lcc4063.o /tmp/lcc4060.i /tmp/lcc4061.s /tmp/lcc4062.o
    +
    + +

    As the output shows, lcc places temporary files in /tmp; if +any of the environment variables TMP, TEMP, and TMPDIR +are set, they override this default (in the order shown) as does the -tempdir=dir +option. The default can be changed by defining TEMPDIR in CFLAGS +when building the driver.

    + +

    The option function is called for the options -Wo, -g, +-p, -pg, and -b because these compiler options +might also affect the loader's arguments. For these options, the driver calls option(arg) +to give the host-specific code an opportunity to edit the ld command, if +necessary. option can change ld, if necessary, and return 1 to +announce its acceptance of the option. If the option is unsupported, option +should return 0.

    + +

    For example, in response to -g, the option function shown +above accepts the option but does nothing else, because the ld and as +commands don't need to be modified on the SPARC. -g will also be added to the +compiler's options by the host-independent part of the driver. The -p causes option +to change the name of the startup code and changed the list of libraries. The -b +option turns on lcc's per-expression profiling, the code for which is in liblcc.a, +so option need no nothing.

    + +

    On SPARCs, the driver also recognizes -Bstatic and -Bdynamic +as linker options. The driver recognizes but ignores "-target name" +option.

    + +

    The option -Woarg causes the driver to pass arg to option. +Such options have no other effect; this mechanism is provided to support system-specific +options that affect the commands executed by the driver. As illustrated above, +host-specific parts should support the -Wo-lccdir=dir option, which +causes lcc's compilation components to be found in dir, because this option is +used by the test scripts, and because the driver simulates a -Wo-lccdir +option with the value of the environment variable LCCDIR, if it's defined. +The code above rebuilds the paths to the include files, preprocessor, compiler, and +library by calling concat, which is defined in etc/lcc.c.

    + +

    Building the Compiler and Accessories

    + +

    To build the rest of compilation components make sure BUILDDIR is set +appropriately and type "make all". This command builds librcc.a +(the compiler's private library), rcc (the compiler proper), lburg +(the code-generator generator), cpp (the preprocessor), liblcc.a +(the runtime library), and bprint (the profile printer), all in BUILDDIR. +There may be warnings, but there should be no errors. If you're using an ANSI/ISO compiler +other than cc, specify its name with the CC= option, e.g., +"make CC=gcc all". If you're running on a DEC ALPHA, use "make +CC='cc -std1' all"; the -std1 option is essential on +the ALPHA.

    + +

    Once rcc is built with the host C compiler, run the test suite to verify +that rcc is working correctly. If any of the steps below fail, contact us +(see Reporting Bugs). The commands in the makefile run the +shell script src/run.sh on each C program in the test suite, tst/*.c. +It uses the driver, $BUILDDIR/lcc, so you must have the driver in the build +directory before testing rcc. The target/os +combination is read from the variable TARGET, which must be specified when +invoking make:

    + +
    +
    % make TARGET=sparc/solaris test
    +mkdir -p $BUILDDIR/sparc-solaris/sparc/solaris/tst
    +$BUILDDIR/sparc-solaris/rcc -target=sparc/solaris $BUILDDIR/sparc-solaris/sparc/solaris/tst/8q.s:
    +$BUILDDIR/sparc-solaris/rcc -target=sparc/solaris $BUILDDIR/sparc-solaris/sparc/solaris/tst/array.s:
    +$BUILDDIR/sparc-solaris/rcc -target=sparc/solaris $BUILDDIR/sparc-solaris/sparc/solaris/tst/cf.s:
    +$BUILDDIR/sparc-solaris/rcc -target=sparc/solaris $BUILDDIR/sparc-solaris/sparc/solaris/tst/cq.s:
    +$BUILDDIR/sparc-solaris/rcc -target=sparc/solaris $BUILDDIR/sparc-solaris/sparc/solaris/tst/cvt.s:
    +$BUILDDIR/sparc-solaris/rcc -target=sparc/solaris $BUILDDIR/sparc-solaris/sparc/solaris/tst/fields.s:
    +$BUILDDIR/sparc-solaris/rcc -target=sparc/solaris $BUILDDIR/sparc-solaris/sparc/solaris/tst/front.s:
    +$BUILDDIR/sparc-solaris/rcc -target=sparc/solaris $BUILDDIR/sparc-solaris/sparc/solaris/tst/incr.s:
    +$BUILDDIR/sparc-solaris/rcc -target=sparc/solaris $BUILDDIR/sparc-solaris/sparc/solaris/tst/init.s:
    +$BUILDDIR/sparc-solaris/rcc -target=sparc/solaris $BUILDDIR/sparc-solaris/sparc/solaris/tst/limits.s:
    +$BUILDDIR/sparc-solaris/rcc -target=sparc/solaris $BUILDDIR/sparc-solaris/sparc/solaris/tst/paranoia.s:
    +$BUILDDIR/sparc-solaris/rcc -target=sparc/solaris $BUILDDIR/sparc-solaris/sparc/solaris/tst/sort.s:
    +$BUILDDIR/sparc-solaris/rcc -target=sparc/solaris $BUILDDIR/sparc-solaris/sparc/solaris/tst/spill.s:
    +$BUILDDIR/sparc-solaris/rcc -target=sparc/solaris $BUILDDIR/sparc-solaris/sparc/solaris/tst/stdarg.s:
    +$BUILDDIR/sparc-solaris/rcc -target=sparc/solaris $BUILDDIR/sparc-solaris/sparc/solaris/tst/struct.s:
    +$BUILDDIR/sparc-solaris/rcc -target=sparc/solaris $BUILDDIR/sparc-solaris/sparc/solaris/tst/switch.s:
    +$BUILDDIR/sparc-solaris/rcc -target=sparc/solaris $BUILDDIR/sparc-solaris/sparc/solaris/tst/wf1.s:
    +$BUILDDIR/sparc-solaris/rcc -target=sparc/solaris $BUILDDIR/sparc-solaris/sparc/solaris/tst/yacc.s:
    +
    + +

    Each line in the output above is of the form

    + +
    +

    $BUILDDIR/rcc -target=target/os $BUILDDIR/target/os/X.s:

    +
    + +

    where X is the base name of the C program X.c in the +test suite. The actual value of BUILDDIR will, of course, appear in +place of $BUILDDIR. This output identifies the compiler and the target, e.g., "$BUILDDIR/rcc +is generating code for a sparc running the solaris operating +system."

    + +

    For each program in the test suite, src/run.sh compiles the program, drops +the generated assembly language code in BUILDDIR/target/os, +and uses diff to compare the generated assembly code with the expected code +(the code expected for tst/8q.c on the SPARC under Solaris is in sparc/solaris/tst/8q.sbk, +etc.). If there are differences, the script executes the generated code with the input +given in tst (the input for tst/8q.c is in tst/8q.0, +etc.) and compares the output with the expected output (the expected output from tst/8q.c +on the SPARC under Solaris is in sparc/solaris/tst/8q.1bk, etc.). The script +also compares the diagnostics from the compiler with the expected diagnostics.

    + +

    On some systems, there may be a few differences between the generated code and the +expected code. These differences occur because the expected code is generated by cross +compilation and the least significant bits of some floating-point constants differ from +those bits in constants generated on your system. On Linux, there may be differences +because of differences in the header files between our system and yours. There should be +no differences in the output from executing the test programs.

    + +

    Next, run the "triple test", which builds rcc using itself:

    + +
    +
    % make triple
    +$BUILDDIR/sparc-solaris/lcc -A -d0.6 -Wo-lccdir=$(BUILDDIR) -Isrc -I$(BUILDDIR) -o $BUILDDIR/sparc-solaris/1rcc -B$BUILDDIR/sparc-solaris/ src/alloc.c ...
    +src/alloc.c:
    +...
    +$BUILDDIR/sparc-solaris/lcc -A -d0.6 -Wo-lccdir=$(BUILDDIR) -Isrc -I$(BUILDDIR) -o $BUILDDIR/sparc-solaris/2rcc -B$BUILDDIR/sparc-solaris/1 src/alloc.c ...
    +src/alloc.c:
    +...
    +strip $BUILDDIR/sparc-solaris/[12]rcc
    +dd if=$BUILDDIR/sparc-solaris/1rcc of=$BUILDDIR/sparc-solaris/rcc1 bs=512 skip=1
    +1270+1 records in
    +1270+1 records out
    +dd if=$BUILDDIR/sparc-solaris/2rcc of=$BUILDDIR/sparc-solaris/rcc2 bs=512 skip=1
    +1270+1 records in
    +1270+1 records out
    +if cmp $BUILDDIR/sparc-solaris/rcc[12]; then \
    +        mv $BUILDDIR/sparc-solaris/2rcc $BUILDDIR/sparc-solaris/rcc; \
    +        rm -f $BUILDDIR/sparc-solaris/1rcc $BUILDDIR/sparc-solaris/rcc[12]; fi
    +
    + +

    This command builds rcc twice; once using the rcc built by cc +and again using the rcc built by lcc. The resulting binaries are +compared. They should be identical, as shown at the end of the output above. If they +aren't, our compiler is generating incorrect code; contact us.

    + +

    The final version of rcc should also pass the test suite; that is, the +output from

    + +
    +
    % make TARGET=sparc/solaris test
    +
    + +

    should be identical to that from the previous make test.

    + +

    The command "make clean" cleans up, but does not remove rcc, +etc., and "make clobber" cleans up and removes lcc, rcc, +and the other accessories. Test directories under BUILDDIR are not +removed; you'll need to remove these by hand, e.g.,

    + +
    +
    % rm -fr $BUILDDIR/sparc
    +
    + +

    The code generators for the other targets can be tested by specifying the desired target/os +and setting an environment variable that controls what src/run.sh does. For +example, to test the MIPS code generator, type

    + +
    +
    % setenv REMOTEHOST noexecute
    +% make TARGET=mips/irix test
    +
    + +

    As above, src/run.sh compares the MIPS code generated with what's +expected. There should be no differences. Setting REMOTEHOST to noexecute +suppresses the assembly and execution of the generated code. If you set REMOTEHOST +to the name of a MIPS machine to which you can rlogin, src/run.sh +will rcp the generated code to that machine and execute it there, if +necessary. See src/run.sh for the details.

    + +

    You can use lcc as a cross compiler. The options -S and -Wf-target=target/os +generate assembly code for the specified target, which is any of those listed in the file src/bind.c. +For example,

    + +
    +
    % lcc -Wf-target=mips/irix -S tst/8q.c
    +
    + +

    generates MIPS code for tst/8q.c in 8q.s.

    + +

    lcc can also generate code for a "symbolic" target. This target is used +routinely in front-end development, and its output is a printable representation of the +input program, e.g., the dags constructed by the front end are printed, and other +interface functions print their arguments. You can specify this target with the option -Wf-target=symbolic. +For example,

    + +
    +
    % lcc -Wf-target=symbolic -S tst/8q.c
    +
    + +

    generates symbolic output for tst/8q.c in 8q.s. Adding -Wf-html +causes the symbolic target to emit HTML instead of plain text. Finally, the option -Wf-target=null +specifies the "null" target for which lcc emits nothing and thus only checks the +syntax and semantics of its input files.

    + +

    Installation on Windows

    + +

    On Windows, lcc is designed to work with Microsoft's Visual +C++ (VC), version 5.0 and above, and Microsoft's Assembler, MASM. It uses the VC header files, +libraries, and command-line tools, and it uses MASM to assemble the code it generates. +You must use MASM 6.11d or later, +because earlier releases generate incorrect COFF object files. MASM +6.15 is available as part of the free +Visual +C++ 6.0 Processor Pack.

    + +

    Building the distribution components from the ground up requires Microsoft's Visual +C/C++ compiler, Microsoft's make, nmake, and the standard Windows command +interpreter. makefile.nt is written to use only nmake. +As on UNIX systems, the compilation components are installed in a single build +directory, and the top-level programs, lcc.exe and bprint.exe, +are installed in a directory on the PATH. If the conventions used below are followed, the +Windows-specific parts of the driver program, lcc.exe, can be used +unmodified.

    + +

    Building from the source distribution on a Windows system involves the following steps. +Below, the build directory is referred to as BUILDDIR, and the distribution +is in \dist\lcc. + +

      +
    1. Create the build directory, perhaps using a version- and platform-specific naming + convention as suggested in Installation on UNIX, and record + the name of this directory in the BUILDDIR environment variable:
      +
      C:\dist\lcc>set BUILDDIR=\progra~1\lcc\version\bin
      +C:\dist\lcc>mkdir %BUILDDIR%
      +
      +

      The default build, or installation, directory is \Program Files\lcc\version\bin, + where version is the version number, e.g., 4.2, but the nmake commands require that you use the corresponding 8.3 file name, progra~1, + instead of Program Files.

      +
    2. +
    3. etc\win32.c is the Windows-specific part of + the driver. It assumes that environment variable include gives the locations + of the VC header files and that the linker (link.exe) and the assembler (ml.exe) + are on the PATH. It also assumes that the macro LCCDIR gives the build + directory. If necessary, revise a copy of etc\win32.c + to reflect the conventions on your computer (see Building the Driver), + then build the driver, specifying the default temporary directory, if necessary:
      +
      C:\dist\lcc>nmake -f makefile.nt HOSTFILE=etc/win32.c lcc
      +...
      +        cl -nologo -Zi -MLd -Fd%BUILDDIR%\ -c -Fo%BUILDDIR%\lcc.obj etc/lcc.c
      +lcc.c
      +        cl -nologo -Zi -MLd -Fd%BUILDDIR%\ -c -Fo%BUILDDIR%\host.obj etc/win32.c
      +win32.c
      +        cl -nologo -Zi -MLd -Fd%BUILDDIR%\ -Fe%BUILDDIR%\lcc.exe %BUILDDIR%\lcc.obj %BUILDDIR%\host.obj
      +
      +

      If you make a copy of etc\win32.c, specify the path of the copy as the + value of HOSTFILE. For example, if you copy etc\win32.c to BUILDDIR + and edit it, use the command

      +
      +
      C:\dist\lcc>nmake -f makefile.nt HOSTFILE=%BUILDDIR%\win32.c lcc
      +
      +
    4. +
    5. Build the preprocessor, compiler proper, library, and other accessories (see Building the Compiler):
      +
      C:\dist\lcc>nmake -f makefile.nt all
      +
      +

      This command uses the VC command-line tools cl and lib to + build bprint.exe, cpp.exe, lburg.exe, liblcc.lib, + librcc.lib, and rcc.exe, all in BUILDDIR. There may + be some warnings, but there should be no warnings.

      +
    6. +
    7. Create a test directory and run the test suite:
      +
      C:\dist\lcc>mkdir %BUILDDIR%\x86\win32\tst
      +C:\dist\lcc>nmake -f makefile.nt test
      +
      +

      This command compiles each program in tst, compares the generated + assembly code and diagnostics with the expected assembly code and diagnostics, executes + the program, and compares the output with the expected output (using fc). For + example, when the nmake command compiles tst\8q.c, + it leaves the generated assembly code and diagnostic output in %BUILDDIR%\x86\win32\tst\8q.s + and %BUILDDIR%\x86\win32\tst\8q.2, and it compares them with the expected + results in x86\win32\tst\8q.sbk. It builds the executable program in %BUILDDIR%\x86\win32\tst\8q.exe, + runs it, and redirects the output to %BUILDDIR%\x86\win32\tst\8q.1, which it + compares with x86\win32\tst\8q.1bk. The output from this step is voluminous, + but there should be no differences and no errors.

      +
    8. +
    9. Run the "triple" test, which compiles rcc with itself and + verifies the results:
      +
      C:\dist\lcc>nmake -f makefile.nt triple
      +...
      + Assembling: C:/TEMP/lcc2001.asm
      +        fc /b %BUILDDIR%\1rcc.exe %BUILDDIR%\2rcc.exe
      +Comparing files %BUILDDIR%\1rcc.exe and %BUILDDIR%\2RCC.EXE
      +00000088: B4 D5
      +
      +

      This command builds rcc twice; once using the rcc built by VC + and again using the rcc built by lcc. The resulting binaries are + compared using fc. They should be identical, except for one or two bytes of + timestamp data, as shown at the end of the output above (which will be + different on your system). If 1rcc.exe and 2rcc.exe aren't + identical, our compiler is + generating incorrect code; contact us.

      +
    10. +
    11. Copy lcc.exe and bprint.exe to a directory on your PATH, e.g.,
      +
      C:\dist\lcc>copy %BUILDDIR%\lcc.exe \bin
      +        1 file(s) copied.
      +
      +C:\dist\lcc>copy %BUILDDIR%\bprint.exe \bin
      +        1 file(s) copied.
      +
      +
    12. +
    13. Finally, clean up:
      +
      C:\dist\lcc>nmake -f makefile.nt clean
      +
      +

      This command removes the derived files in BUILDDIR, but does not remove rcc.exe, + etc.; "nmake -f makefile.nt clobber" cleans up and removes all + executables and libraries. Test directories under BUILDDIR are not + removed; you'll need to remove these by hand, e.g.,

      +
      +
      C:\dist\lcc>rmdir %BUILDDIR%\x86 /s
      +%BUILDDIR%\x86, Are you sure (Y/N)? y
      +
      +
    14. +
    + +

    Reporting Bugs

    + +

    lcc is a large, complex program. We find and repair errors routinely. If you think that +you've found a error, follow the steps below, which are adapted from the instructions in +Chapter 1 of A Retargetable C Compiler: Design and Implementation. + +

      +
    1. If you don't have a source file that displays the error, create one. Most errors are + exposed when programmers try to compile a program they think is valid, so you probably + have a demonstration program already.
    2. +
    3. Preprocess the source file and capture the preprocessor output. Discard the original + code.
    4. +
    5. Prune your source code until it can be pruned no more without sending the error into + hiding. We prune most error demonstrations to fewer than five lines.
    6. +
    7. Confirm that the source file displays the error with the distributed version of + lcc. If you've changed lcc and the error appears only in your version, then you'll have to + chase the error yourself, even if it turns out to be our fault, because we can't work on + your code.
    8. +
    9. Annotate your code with comments that explain why you think that lcc is + wrong. If lcc dies with an assertion failure, please tell us where it died. If + lcc crashes, please report the last part of the call chain if you can. If lcc + is rejecting a program you think is valid, please tell us why you think it's + valid, and include supporting page numbers in the ANSI Standard or the + appropriate section in C: A Reference Manual, 4th edition by S. B. Harbison + and G. L. Steele, Jr. (Prentice Hall, 1995). If lcc silently generates incorrect code for + some construct, please include the corrupt assembly code in the comments and flag the + incorrect instructions if you can.
    10. +
    11. Confirm that your error hasn't been fixed already. The latest version of lcc is always + available for anonymous ftp from ftp.cs.princeton.edu in pub/lcc. A README file there gives + acquisition details, and the LOG file reports what errors + were fixed and when they were fixed. If you report a error that's been fixed, you might + get a canned reply.
    12. +
    13. Post your program to the newsgroup comp.compilers.lcc + using a USENET newsreader like those at http://www.dejanews.com/ + and http://groups.google.com/. + Please post only valid C programs; put all remarks in C comments so that we can process + reports semi automatically.
    14. +
    + +

    Keeping in Touch

    + +

    The USENET newsgroup comp.compilers.lcc is an +unmoderated newsgroup that serves as a forum for all topics related to the installation, +use, and development of lcc. You can post messages to comp.compilers.lcc using any USENET +newsreader or by visiting http://www.dejanews.com/, +which also includes an archive of recent postings.

    + +
    + +
    + Chris Fraser / cwfraser@microsoft.com
    + David Hanson / drh@microsoft.com
    + $Revision: 1.45 $ $Date: 2002/09/04 18:33:24 $ +
    + + \ No newline at end of file diff --git a/src/cmd/lccom/enode.c b/src/cmd/lccom/enode.c new file mode 100644 index 0000000..c9739f5 --- /dev/null +++ b/src/cmd/lccom/enode.c @@ -0,0 +1,550 @@ +#include "c.h" + +static Tree addtree(int, Tree, Tree); +static Tree andtree(int, Tree, Tree); +static Tree cmptree(int, Tree, Tree); +static int compatible(Type, Type); +static int isnullptr(Tree e); +static Tree multree(int, Tree, Tree); +static Tree subtree(int, Tree, Tree); +#define isvoidptr(ty) \ + (isptr(ty) && unqual(ty->type) == voidtype) + +Tree (*optree[])(int, Tree, Tree) = { +#define xx(a,b,c,d,e,f,g) e, +#define yy(a,b,c,d,e,f,g) e, +#include "token.h" +}; +Tree call(Tree f, Type fty, Coordinate src) { + int n = 0; + Tree args = NULL, r = NULL, e; + Type *proto, rty = unqual(freturn(fty)); + Symbol t3 = NULL; + + if (fty->u.f.oldstyle) + proto = NULL; + else + proto = fty->u.f.proto; + if (hascall(f)) + r = f; + if (isstruct(rty)) + { + t3 = temporary(AUTO, unqual(rty)); + if (rty->size == 0) + error("illegal use of incomplete type `%t'\n", rty); + } + if (t != ')') + for (;;) { + Tree q = pointer(expr1(0)); + if (proto && *proto && *proto != voidtype) + { + Type aty; + q = value(q); + aty = assign(*proto, q); + if (aty) + q = cast(q, aty); + else + error("type error in argument %d to %s; found `%t' expected `%t'\n", n + 1, funcname(f), + + q->type, *proto); + if ((isint(q->type) || isenum(q->type)) + && q->type->size != inttype->size) + q = cast(q, promote(q->type)); + ++proto; + } + else + { + if (!fty->u.f.oldstyle && *proto == NULL) + error("too many arguments to %s\n", funcname(f)); + q = value(q); + if (isarray(q->type) || q->type->size == 0) + error("type error in argument %d to %s; `%t' is illegal\n", n + 1, funcname(f), q->type); + + else + q = cast(q, promote(q->type)); + } + if (!IR->wants_argb && isstruct(q->type)) { + if (iscallb(q)) + q = addrof(q); + else { + Symbol t1 = temporary(AUTO, unqual(q->type)); + q = asgn(t1, q); + q = tree(RIGHT, ptr(t1->type), + root(q), lvalue(idtree(t1))); + } + } + if (q->type->size == 0) + q->type = inttype; + if (hascall(q)) + r = r ? tree(RIGHT, voidtype, r, q) : q; + args = tree(mkop(ARG, q->type), q->type, q, args); + n++; + if (Aflag >= 2 && n == 32) + warning("more than 31 arguments in a call to %s\n", + funcname(f)); + if (t != ',') + break; + t = gettok(); + } + expect(')'); + if (proto && *proto && *proto != voidtype) + error("insufficient number of arguments to %s\n", + funcname(f)); + if (r) + args = tree(RIGHT, voidtype, r, args); + e = calltree(f, rty, args, t3); + if (events.calls) + apply(events.calls, &src, &e); + return e; +} +Tree calltree(Tree f, Type ty, Tree args, Symbol t3) { + Tree p; + + if (args) + f = tree(RIGHT, f->type, args, f); + if (isstruct(ty)) { + assert(t3); + p = tree(RIGHT, ty, + tree(CALL+B, ty, f, addrof(idtree(t3))), + idtree(t3)); + } else { + Type rty = ty; + if (isenum(ty)) + rty = unqual(ty)->type; + if (!isfloat(rty)) + rty = promote(rty); + p = tree(mkop(CALL, rty), rty, f, NULL); + if (isptr(ty) || p->type->size > ty->size) + p = cast(p, ty); + } + return p; +} +Tree vcall(Symbol func, Type ty, ...) { + va_list ap; + Tree args = NULL, e, f = pointer(idtree(func)), r = NULL; + + assert(isfunc(func->type)); + if (ty == NULL) + ty = freturn(func->type); + va_start(ap, ty); + while ((e = va_arg(ap, Tree)) != NULL) { + if (hascall(e)) + r = r == NULL ? e : tree(RIGHT, voidtype, r, e); + args = tree(mkop(ARG, e->type), e->type, e, args); + } + va_end(ap); + if (r != NULL) + args = tree(RIGHT, voidtype, r, args); + return calltree(f, ty, args, NULL); +} +int iscallb(Tree e) { + return e->op == RIGHT && e->kids[0] && e->kids[1] + && e->kids[0]->op == CALL+B + && e->kids[1]->op == INDIR+B + && isaddrop(e->kids[1]->kids[0]->op) + && e->kids[1]->kids[0]->u.sym->temporary; +} + +static Tree addtree(int op, Tree l, Tree r) { + Type ty = inttype; + + if (isarith(l->type) && isarith(r->type)) { + ty = binary(l->type, r->type); + l = cast(l, ty); + r = cast(r, ty); + } else if (isptr(l->type) && isint(r->type)) + return addtree(ADD, r, l); + else if ( isptr(r->type) && isint(l->type) + && !isfunc(r->type->type)) + { + long n; + ty = unqual(r->type); + n = unqual(ty->type)->size; + if (n == 0) + error("unknown size for type `%t'\n", ty->type); + l = cast(l, promote(l->type)); + if (n > 1) + l = multree(MUL, cnsttree(signedptr, n), l); + if (isunsigned(l->type)) + l = cast(l, unsignedptr); + else + l = cast(l, signedptr); + if (YYcheck && !isaddrop(r->op)) /* omit */ + return nullcall(ty, YYcheck, r, l); /* omit */ + return simplify(ADD, ty, l, r); + } + + else + typeerror(op, l, r); + return simplify(op, ty, l, r); +} + +Tree cnsttree(Type ty, ...) { + Tree p = tree(mkop(CNST,ty), ty, NULL, NULL); + va_list ap; + + va_start(ap, ty); + switch (ty->op) { + case INT: p->u.v.i = va_arg(ap, long); break; + case UNSIGNED:p->u.v.u = va_arg(ap, unsigned long)&ones(8*ty->size); break; + case FLOAT: p->u.v.d = va_arg(ap, long double); break; + case POINTER: p->u.v.p = va_arg(ap, void *); break; + default: assert(0); + } + va_end(ap); + return p; +} + +Tree consttree(unsigned n, Type ty) { + if (isarray(ty)) + ty = atop(ty); + else assert(isint(ty)); + return cnsttree(ty, (unsigned long)n); +} +static Tree cmptree(int op, Tree l, Tree r) { + Type ty; + + if (isarith(l->type) && isarith(r->type)) { + ty = binary(l->type, r->type); + l = cast(l, ty); + r = cast(r, ty); + } else if (compatible(l->type, r->type)) { + ty = unsignedptr; + l = cast(l, ty); + r = cast(r, ty); + } else { + ty = unsignedtype; + typeerror(op, l, r); + } + return simplify(mkop(op,ty), inttype, l, r); +} +static int compatible(Type ty1, Type ty2) { + ty1 = unqual(ty1); + ty2 = unqual(ty2); + return isptr(ty1) && !isfunc(ty1->type) + && isptr(ty2) && !isfunc(ty2->type) + && eqtype(unqual(ty1->type), unqual(ty2->type), 0); +} +static int isnullptr(Tree e) { + Type ty = unqual(e->type); + + return generic(e->op) == CNST + && ((ty->op == INT && e->u.v.i == 0) + || (ty->op == UNSIGNED && e->u.v.u == 0) + || (isvoidptr(ty) && e->u.v.p == NULL)); +} +Tree eqtree(int op, Tree l, Tree r) { + Type xty = unqual(l->type), yty = unqual(r->type); + + if ((isptr(xty) && isnullptr(r)) + || (isptr(xty) && !isfunc(xty->type) && isvoidptr(yty)) + || (isptr(xty) && isptr(yty) + && eqtype(unqual(xty->type), unqual(yty->type), 1))) { + Type ty = unsignedptr; + l = cast(l, ty); + r = cast(r, ty); + return simplify(mkop(op,ty), inttype, l, r); + } + if ((isptr(yty) && isnullptr(l)) + || (isptr(yty) && !isfunc(yty->type) && isvoidptr(xty))) + return eqtree(op, r, l); + return cmptree(op, l, r); +} + +Type assign(Type xty, Tree e) { + Type yty = unqual(e->type); + + xty = unqual(xty); + if (isenum(xty)) + xty = xty->type; + if (xty->size == 0 || yty->size == 0) + return NULL; + if ((isarith(xty) && isarith(yty)) + || (isstruct(xty) && xty == yty)) + return xty; + if (isptr(xty) && isnullptr(e)) + return xty; + if (((isvoidptr(xty) && isptr(yty)) + || (isptr(xty) && isvoidptr(yty))) + && ( (isconst(xty->type) || !isconst(yty->type)) + && (isvolatile(xty->type) || !isvolatile(yty->type)))) + return xty; + + if ((isptr(xty) && isptr(yty) + && eqtype(unqual(xty->type), unqual(yty->type), 1)) + && ( (isconst(xty->type) || !isconst(yty->type)) + && (isvolatile(xty->type) || !isvolatile(yty->type)))) + return xty; + if (isptr(xty) && isptr(yty) + && ( (isconst(xty->type) || !isconst(yty->type)) + && (isvolatile(xty->type) || !isvolatile(yty->type)))) { + Type lty = unqual(xty->type), rty = unqual(yty->type); + if ((isenum(lty) && rty == inttype) + || (isenum(rty) && lty == inttype)) { + if (Aflag >= 1) + warning("assignment between `%t' and `%t' is compiler-dependent\n", + xty, yty); + return xty; + } + } + return NULL; +} +Tree asgntree(int op, Tree l, Tree r) { + Type aty, ty; + + r = pointer(r); + ty = assign(l->type, r); + if (ty) + r = cast(r, ty); + else { + typeerror(ASGN, l, r); + if (r->type == voidtype) + r = retype(r, inttype); + ty = r->type; + } + if (l->op != FIELD) + l = lvalue(l); + aty = l->type; + if (isptr(aty)) + aty = unqual(aty)->type; + if ( isconst(aty) + || (isstruct(aty) && unqual(aty)->u.sym->u.s.cfields)) { + if (isaddrop(l->op) + && !l->u.sym->computed && !l->u.sym->generated) + error("assignment to const identifier `%s'\n", + l->u.sym->name); + else + error("assignment to const location\n"); + } + if (l->op == FIELD) { + long n = 8*l->u.field->type->size - fieldsize(l->u.field); + if (n > 0 && isunsigned(l->u.field->type)) + r = bittree(BAND, r, + cnsttree(r->type, (unsigned long)fieldmask(l->u.field))); + else if (n > 0) { + if (r->op == CNST+I) { + n = r->u.v.i; + if (n&(1<<(fieldsize(l->u.field)-1))) + n |= ~0UL<u.field); + r = cnsttree(r->type, n); + } else + r = shtree(RSH, + shtree(LSH, r, cnsttree(inttype, n)), + cnsttree(inttype, n)); + } + } + if (isstruct(ty) && isaddrop(l->op) && iscallb(r)) + return tree(RIGHT, ty, + tree(CALL+B, ty, r->kids[0]->kids[0], l), + idtree(l->u.sym)); + return tree(mkop(op,ty), ty, l, r); +} +Tree condtree(Tree e, Tree l, Tree r) { + Symbol t1; + Type ty, xty = l->type, yty = r->type; + Tree p; + + if (isarith(xty) && isarith(yty)) + ty = binary(xty, yty); + else if (eqtype(xty, yty, 1)) + ty = unqual(xty); + else if (isptr(xty) && isnullptr(r)) + ty = xty; + else if (isnullptr(l) && isptr(yty)) + ty = yty; + else if ((isptr(xty) && !isfunc(xty->type) && isvoidptr(yty)) + || (isptr(yty) && !isfunc(yty->type) && isvoidptr(xty))) + ty = voidptype; + else if ((isptr(xty) && isptr(yty) + && eqtype(unqual(xty->type), unqual(yty->type), 1))) + ty = xty; + else { + typeerror(COND, l, r); + return consttree(0, inttype); + } + if (isptr(ty)) { + ty = unqual(unqual(ty)->type); + if ((isptr(xty) && isconst(unqual(xty)->type)) + || (isptr(yty) && isconst(unqual(yty)->type))) + ty = qual(CONST, ty); + if ((isptr(xty) && isvolatile(unqual(xty)->type)) + || (isptr(yty) && isvolatile(unqual(yty)->type))) + ty = qual(VOLATILE, ty); + ty = ptr(ty); + } + switch (e->op) { + case CNST+I: return cast(e->u.v.i != 0 ? l : r, ty); + case CNST+U: return cast(e->u.v.u != 0 ? l : r, ty); + case CNST+P: return cast(e->u.v.p != 0 ? l : r, ty); + case CNST+F: return cast(e->u.v.d != 0.0 ? l : r, ty); + } + if (ty != voidtype && ty->size > 0) { + t1 = genident(REGISTER, unqual(ty), level); + /* t1 = temporary(REGISTER, unqual(ty)); */ + l = asgn(t1, l); + r = asgn(t1, r); + } else + t1 = NULL; + p = tree(COND, ty, cond(e), + tree(RIGHT, ty, root(l), root(r))); + p->u.sym = t1; + return p; +} +/* addrof - address of p */ +Tree addrof(Tree p) { + Tree q = p; + + for (;;) + switch (generic(q->op)) { + case RIGHT: + assert(q->kids[0] || q->kids[1]); + q = q->kids[1] ? q->kids[1] : q->kids[0]; + continue; + case ASGN: + q = q->kids[1]; + continue; + case COND: { + Symbol t1 = q->u.sym; + q->u.sym = 0; + q = idtree(t1); + /* fall thru */ + } + case INDIR: + if (p == q) + return q->kids[0]; + q = q->kids[0]; + return tree(RIGHT, q->type, root(p), q); + default: + error("addressable object required\n"); + return value(p); + } +} + +/* andtree - construct tree for l [&& ||] r */ +static Tree andtree(int op, Tree l, Tree r) { + if (!isscalar(l->type) || !isscalar(r->type)) + typeerror(op, l, r); + return simplify(op, inttype, cond(l), cond(r)); +} + +/* asgn - generate tree for assignment of expr e to symbol p sans qualifiers */ +Tree asgn(Symbol p, Tree e) { + if (isarray(p->type)) + e = tree(ASGN+B, p->type, idtree(p), + tree(INDIR+B, e->type, e, NULL)); + else { + Type ty = p->type; + p->type = unqual(p->type); + if (isstruct(p->type) && p->type->u.sym->u.s.cfields) { + p->type->u.sym->u.s.cfields = 0; + e = asgntree(ASGN, idtree(p), e); + p->type->u.sym->u.s.cfields = 1; + } else + e = asgntree(ASGN, idtree(p), e); + p->type = ty; + } + return e; +} + +/* bittree - construct tree for l [& | ^ %] r */ +Tree bittree(int op, Tree l, Tree r) { + Type ty = inttype; + + if (isint(l->type) && isint(r->type)) { + ty = binary(l->type, r->type); + l = cast(l, ty); + r = cast(r, ty); + } else + typeerror(op, l, r); + return simplify(op, ty, l, r); +} + +/* multree - construct tree for l [* /] r */ +static Tree multree(int op, Tree l, Tree r) { + Type ty = inttype; + + if (isarith(l->type) && isarith(r->type)) { + ty = binary(l->type, r->type); + l = cast(l, ty); + r = cast(r, ty); + } else + typeerror(op, l, r); + return simplify(op, ty, l, r); +} + +/* shtree - construct tree for l [>> <<] r */ +Tree shtree(int op, Tree l, Tree r) { + Type ty = inttype; + + if (isint(l->type) && isint(r->type)) { + ty = promote(l->type); + l = cast(l, ty); + r = cast(r, inttype); + } else + typeerror(op, l, r); + return simplify(op, ty, l, r); +} + +/* subtree - construct tree for l - r */ +static Tree subtree(int op, Tree l, Tree r) { + long n; + Type ty = inttype; + + if (isarith(l->type) && isarith(r->type)) { + ty = binary(l->type, r->type); + l = cast(l, ty); + r = cast(r, ty); + } else if (isptr(l->type) && !isfunc(l->type->type) && isint(r->type)) { + ty = unqual(l->type); + n = unqual(ty->type)->size; + if (n == 0) + error("unknown size for type `%t'\n", ty->type); + r = cast(r, promote(r->type)); + if (n > 1) + r = multree(MUL, cnsttree(signedptr, n), r); + if (isunsigned(r->type)) + r = cast(r, unsignedptr); + else + r = cast(r, signedptr); + return simplify(SUB+P, ty, l, r); + } else if (compatible(l->type, r->type)) { + ty = unqual(l->type); + n = unqual(ty->type)->size; + if (n == 0) + error("unknown size for type `%t'\n", ty->type); + l = simplify(SUB+U, unsignedptr, + cast(l, unsignedptr), cast(r, unsignedptr)); + return simplify(DIV+I, longtype, + cast(l, longtype), cnsttree(longtype, n)); + } else + typeerror(op, l, r); + return simplify(op, ty, l, r); +} + +/* typeerror - issue "operands of op have illegal types `l' and `r'" */ +void typeerror(int op, Tree l, Tree r) { + int i; + static struct { int op; char *name; } ops[] = { + { ASGN, "=" }, { INDIR, "*" }, { NEG, "-" }, + { ADD, "+" }, { SUB, "-" }, { LSH, "<<"}, + { MOD, "%" }, { RSH, ">>"}, { BAND, "&" }, + { BCOM, "~" }, { BOR, "|" }, { BXOR, "^" }, + { DIV, "/" }, { MUL, "*" }, { EQ, "=="}, + { GE, ">="}, { GT, ">" }, { LE, "<="}, + { LT, "<" }, { NE, "!="}, { AND, "&&"}, + { NOT, "!" }, { OR, "||"}, { COND, "?:"}, + { 0, 0 } + }; + + op = generic(op); + for (i = 0; ops[i].op; i++) + if (op == ops[i].op) + break; + assert(ops[i].name); + if (r) + error("operands of %s have illegal types `%t' and `%t'\n", + ops[i].name, l->type, r->type); + else + error("operand of unary %s has illegal type `%t'\n", ops[i].name, + l->type); +} diff --git a/src/cmd/lccom/error.c b/src/cmd/lccom/error.c new file mode 100644 index 0000000..6b69791 --- /dev/null +++ b/src/cmd/lccom/error.c @@ -0,0 +1,136 @@ +#include "c.h" + +static void printtoken(void); +int errcnt = 0; +int errlimit = 20; +char kind[] = { +#define xx(a,b,c,d,e,f,g) f, +#define yy(a,b,c,d,e,f,g) f, +#include "token.h" +}; +int wflag; /* != 0 to suppress warning messages */ + +void test(int tok, char set[]) { + if (t == tok) + t = gettok(); + else { + expect(tok); + skipto(tok, set); + if (t == tok) + t = gettok(); + } +} +void expect(int tok) { + if (t == tok) + t = gettok(); + else { + error("syntax error; found"); + printtoken(); + fprint(stderr, " expecting `%k'\n", tok); + } +} +void error(const char *fmt, ...) { + va_list ap; + + if (errcnt++ >= errlimit) { + errcnt = -1; + error("too many errors\n"); + exit(1); + } + va_start(ap, fmt); + if (firstfile != file && firstfile && *firstfile) + fprint(stderr, "%s: ", firstfile); + fprint(stderr, "%w: ", &src); + vfprint(stderr, NULL, fmt, ap); + va_end(ap); +} + +void skipto(int tok, char set[]) { + int n; + char *s; + + assert(set); + for (n = 0; t != EOI && t != tok; t = gettok()) { + for (s = set; *s && kind[t] != *s; s++) + ; + if (kind[t] == *s) + break; + if (n++ == 0) + error("skipping"); + if (n <= 8) + printtoken(); + else if (n == 9) + fprint(stderr, " ..."); + } + if (n > 8) { + fprint(stderr, " up to"); + printtoken(); + } + if (n > 0) + fprint(stderr, "\n"); +} +/* fatal - issue fatal error message and exit */ +int fatal(const char *name, const char *fmt, int n) { + print("\n"); + errcnt = -1; + error("compiler error in %s--", name); + fprint(stderr, fmt, n); + exit(EXIT_FAILURE); + return 0; +} + +/* printtoken - print current token preceeded by a space */ +static void printtoken(void) { + switch (t) { + case ID: fprint(stderr, " `%s'", token); break; + case ICON: + fprint(stderr, " `%s'", vtoa(tsym->type, tsym->u.c.v)); + break; + case SCON: { + int i, n; + if (ischar(tsym->type->type)) { + char *s = tsym->u.c.v.p; + n = tsym->type->size; + fprint(stderr, " \""); + for (i = 0; i < 20 && i < n && *s; s++, i++) + if (*s < ' ' || *s >= 0177) + fprint(stderr, "\\%o", *s); + else + fprint(stderr, "%c", *s); + } else { /* wchar_t string */ + unsigned int *s = tsym->u.c.v.p; + assert(tsym->type->type->size == widechar->size); + n = tsym->type->size/widechar->size; + fprint(stderr, " L\""); + for (i = 0; i < 20 && i < n && *s; s++, i++) + if (*s < ' ' || *s >= 0177) + fprint(stderr, "\\x%x", *s); + else + fprint(stderr, "%c", *s); + } + if (i < n) + fprint(stderr, " ..."); + else + fprint(stderr, "\""); + break; + } + case FCON: + fprint(stderr, " `%S'", token, (char*)cp - token); + break; + case '`': case '\'': fprint(stderr, " \"%k\"", t); break; + default: fprint(stderr, " `%k'", t); + } +} + +/* warning - issue warning error message */ +void warning(const char *fmt, ...) { + va_list ap; + + va_start(ap, fmt); + if (wflag == 0) { + errcnt--; + error("warning: "); + vfprint(stderr, NULL, fmt, ap); + } + va_end(ap); +} diff --git a/src/cmd/lccom/event.c b/src/cmd/lccom/event.c new file mode 100644 index 0000000..6e5cf29 --- /dev/null +++ b/src/cmd/lccom/event.c @@ -0,0 +1,26 @@ +#include "c.h" + +struct entry { + Apply func; + void *cl; +}; + +Events events; +void attach(Apply func, void *cl, List *list) { + struct entry *p; + + NEW(p, PERM); + p->func = func; + p->cl = cl; + *list = append(p, *list); +} +void apply(List event, void *arg1, void *arg2) { + if (event) { + List lp = event; + do { + struct entry *p = lp->x; + (*p->func)(p->cl, arg1, arg2); + lp = lp->link; + } while (lp != event); + } +} diff --git a/src/cmd/lccom/expr.c b/src/cmd/lccom/expr.c new file mode 100644 index 0000000..0e6b300 --- /dev/null +++ b/src/cmd/lccom/expr.c @@ -0,0 +1,711 @@ +#include "c.h" + +static char prec[] = { +#define xx(a,b,c,d,e,f,g) c, +#define yy(a,b,c,d,e,f,g) c, +#include "token.h" +}; +static int oper[] = { +#define xx(a,b,c,d,e,f,g) d, +#define yy(a,b,c,d,e,f,g) d, +#include "token.h" +}; +float refinc = 1.0; +static Tree expr2(void); +static Tree expr3(int); +static Tree nullcheck(Tree); +static Tree postfix(Tree); +static Tree unary(void); +static Tree primary(void); +static Type super(Type ty); + +static Type super(Type ty) { + switch (ty->op) { + case INT: + if (ty->size < inttype->size) + return inttype; + break; + case UNSIGNED: + if (ty->size < unsignedtype->size) + return unsignedtype; + break; + case POINTER: + return unsignedptr; + } + return ty; +} +Tree expr(int tok) { + static char stop[] = { IF, ID, '}', 0 }; + Tree p = expr1(0); + + while (t == ',') { + Tree q; + t = gettok(); + q = pointer(expr1(0)); + p = tree(RIGHT, q->type, root(value(p)), q); + } + if (tok) + test(tok, stop); + return p; +} +Tree expr0(int tok) { + return root(expr(tok)); +} +Tree expr1(int tok) { + static char stop[] = { IF, ID, 0 }; + Tree p = expr2(); + + if (t == '=' + || (prec[t] >= 6 && prec[t] <= 8) + || (prec[t] >= 11 && prec[t] <= 13)) { + int op = t; + t = gettok(); + if (oper[op] == ASGN) + p = asgntree(ASGN, p, value(expr1(0))); + else + { + expect('='); + p = incr(op, p, expr1(0)); + } + } + if (tok) + test(tok, stop); + return p; +} +Tree incr(int op, Tree v, Tree e) { + return asgntree(ASGN, v, (*optree[op])(oper[op], v, e)); +} +static Tree expr2(void) { + Tree p = expr3(4); + + if (t == '?') { + Tree l, r; + Coordinate pts[2]; + if (Aflag > 1 && isfunc(p->type)) + warning("%s used in a conditional expression\n", + funcname(p)); + p = pointer(p); + t = gettok(); + pts[0] = src; + l = pointer(expr(':')); + pts[1] = src; + r = pointer(expr2()); + if (generic(p->op) != CNST && events.points) + { + apply(events.points, &pts[0], &l); + apply(events.points, &pts[1], &r); + } + p = condtree(p, l, r); + } + return p; +} +Tree value(Tree p) { + int op = generic(rightkid(p)->op); + + if (p->type != voidtype + && (op==AND || op==OR || op==NOT || op==EQ || op==NE + || op== LE || op==LT || op== GE || op==GT)) + p = condtree(p, consttree(1, inttype), + consttree(0, inttype)); + return p; +} +static Tree expr3(int k) { + int k1; + Tree p = unary(); + + for (k1 = prec[t]; k1 >= k; k1--) + while (prec[t] == k1 && *cp != '=') { + Tree r; + Coordinate pt; + int op = t; + t = gettok(); + pt = src; + p = pointer(p); + if (op == ANDAND || op == OROR) { + r = pointer(expr3(k1)); + if (events.points) + apply(events.points, &pt, &r); + } else + r = pointer(expr3(k1 + 1)); + p = (*optree[op])(oper[op], p, r); + } + return p; +} +static Tree unary(void) { + Tree p; + + switch (t) { + case '*': t = gettok(); p = unary(); p = pointer(p); + if (isptr(p->type) + && (isfunc(p->type->type) || isarray(p->type->type))) + p = retype(p, p->type->type); + else { + if (YYnull) + p = nullcheck(p); + p = rvalue(p); + } break; + case '&': t = gettok(); p = unary(); if (isarray(p->type) || isfunc(p->type)) + p = retype(p, ptr(p->type)); + else + p = lvalue(p); + if (isaddrop(p->op) && p->u.sym->sclass == REGISTER) + error("invalid operand of unary &; `%s' is declared register\n", p->u.sym->name); + + else if (isaddrop(p->op)) + p->u.sym->addressed = 1; + break; + case '+': t = gettok(); p = unary(); p = pointer(p); + if (isarith(p->type)) + p = cast(p, promote(p->type)); + else + typeerror(ADD, p, NULL); break; + case '-': t = gettok(); p = unary(); p = pointer(p); + if (isarith(p->type)) { + Type ty = promote(p->type); + p = cast(p, ty); + if (isunsigned(ty)) { + warning("unsigned operand of unary -\n"); + p = simplify(ADD, ty, simplify(BCOM, ty, p, NULL), cnsttree(ty, 1UL)); + } else + p = simplify(NEG, ty, p, NULL); + } else + typeerror(SUB, p, NULL); break; + case '~': t = gettok(); p = unary(); p = pointer(p); + if (isint(p->type)) { + Type ty = promote(p->type); + p = simplify(BCOM, ty, cast(p, ty), NULL); + } else + typeerror(BCOM, p, NULL); break; + case '!': t = gettok(); p = unary(); p = pointer(p); + if (isscalar(p->type)) + p = simplify(NOT, inttype, cond(p), NULL); + else + typeerror(NOT, p, NULL); break; + case INCR: t = gettok(); p = unary(); p = incr(INCR, pointer(p), consttree(1, inttype)); break; + case DECR: t = gettok(); p = unary(); p = incr(DECR, pointer(p), consttree(1, inttype)); break; + case TYPECODE: case SIZEOF: { int op = t; + Type ty; + p = NULL; + t = gettok(); + if (t == '(') { + t = gettok(); + if (istypename(t, tsym)) { + ty = typename(); + expect(')'); + } else { + p = postfix(expr(')')); + ty = p->type; + } + } else { + p = unary(); + ty = p->type; + } + assert(ty); + if (op == TYPECODE) + p = cnsttree(inttype, (long)ty->op); + else { + if (isfunc(ty) || ty->size == 0) + error("invalid type argument `%t' to `sizeof'\n", ty); + else if (p && rightkid(p)->op == FIELD) + error("`sizeof' applied to a bit field\n"); + p = cnsttree(unsignedlong, (unsigned long)ty->size); + } } break; + case '(': + t = gettok(); + if (istypename(t, tsym)) { + Type ty, ty1 = typename(), pty; + expect(')'); + ty = unqual(ty1); + if (isenum(ty)) { + Type ty2 = ty->type; + if (isconst(ty1)) + ty2 = qual(CONST, ty2); + if (isvolatile(ty1)) + ty2 = qual(VOLATILE, ty2); + ty1 = ty2; + ty = ty->type; + } + p = pointer(unary()); + pty = p->type; + if (isenum(pty)) + pty = pty->type; + if ((isarith(pty) && isarith(ty)) + || (isptr(pty) && isptr(ty))) { + explicitCast++; + p = cast(p, ty); + explicitCast--; + } else if ((isptr(pty) && isint(ty)) + || (isint(pty) && isptr(ty))) { + if (Aflag >= 1 && ty->size < pty->size) + warning("conversion from `%t' to `%t' is compiler dependent\n", p->type, ty); + + p = cast(p, ty); + } else if (ty != voidtype) { + error("cast from `%t' to `%t' is illegal\n", + p->type, ty1); + ty1 = inttype; + } + if (generic(p->op) == INDIR || ty->size == 0) + p = tree(RIGHT, ty1, NULL, p); + else + p = retype(p, ty1); + } else + p = postfix(expr(')')); + break; + default: + p = postfix(primary()); + } + return p; +} + +static Tree postfix(Tree p) { + for (;;) + switch (t) { + case INCR: p = tree(RIGHT, p->type, + tree(RIGHT, p->type, + p, + incr(t, p, consttree(1, inttype))), + p); + t = gettok(); break; + case DECR: p = tree(RIGHT, p->type, + tree(RIGHT, p->type, + p, + incr(t, p, consttree(1, inttype))), + p); + t = gettok(); break; + case '[': { + Tree q; + t = gettok(); + q = expr(']'); + if (YYnull) { + if (isptr(p->type)) + p = nullcheck(p); + else if (isptr(q->type)) + q = nullcheck(q); + } + p = (*optree['+'])(ADD, pointer(p), pointer(q)); + if (isptr(p->type) && isarray(p->type->type)) + p = retype(p, p->type->type); + else + p = rvalue(p); + } break; + case '(': { + Type ty; + Coordinate pt; + p = pointer(p); + if (isptr(p->type) && isfunc(p->type->type)) + ty = p->type->type; + else { + error("found `%t' expected a function\n", p->type); + ty = func(voidtype, NULL, 1); + p = retype(p, ptr(ty)); + } + pt = src; + t = gettok(); + p = call(p, ty, pt); + } break; + case '.': t = gettok(); + if (t == ID) { + if (isstruct(p->type)) { + Tree q = addrof(p); + p = field(q, token); + q = rightkid(q); + if (isaddrop(q->op) && q->u.sym->temporary) + p = tree(RIGHT, p->type, p, NULL); + } else + error("left operand of . has incompatible type `%t'\n", + p->type); + t = gettok(); + } else + error("field name expected\n"); break; + case DEREF: t = gettok(); + p = pointer(p); + if (t == ID) { + if (isptr(p->type) && isstruct(p->type->type)) { + if (YYnull) + p = nullcheck(p); + p = field(p, token); + } else + error("left operand of -> has incompatible type `%t'\n", p->type); + + t = gettok(); + } else + error("field name expected\n"); break; + default: + return p; + } +} +static Tree primary(void) { + Tree p; + + assert(t != '('); + switch (t) { + case ICON: + case FCON: p = tree(mkop(CNST,tsym->type), tsym->type, NULL, NULL); + p->u.v = tsym->u.c.v; + break; + case SCON: if (ischar(tsym->type->type)) + tsym->u.c.v.p = stringn(tsym->u.c.v.p, tsym->type->size); + else + tsym->u.c.v.p = memcpy(allocate((tsym->type->size/widechar->size)*sizeof (int), PERM), + tsym->u.c.v.p, (tsym->type->size/widechar->size)*sizeof (int)); + tsym = constant(tsym->type, tsym->u.c.v); + if (tsym->u.c.loc == NULL) + tsym->u.c.loc = genident(STATIC, tsym->type, GLOBAL); + p = idtree(tsym->u.c.loc); break; + case ID: if (tsym == NULL) + { + Symbol p = install(token, &identifiers, level, PERM); + p->src = src; + if (getchr() == '(') { + Symbol q = lookup(token, externals); + p->type = func(inttype, NULL, 1); + p->sclass = EXTERN; + if (Aflag >= 1) + warning("missing prototype\n"); + if (q && !eqtype(q->type, p->type, 1)) + warning("implicit declaration of `%s' does not match previous declaration at %w\n", q->name, &q->src); + + if (q == NULL) { + q = install(p->name, &externals, GLOBAL, PERM); + q->type = p->type; + q->sclass = EXTERN; + q->src = src; + (*IR->defsymbol)(q); + } + p->u.alias = q; + } else { + error("undeclared identifier `%s'\n", p->name); + p->sclass = AUTO; + p->type = inttype; + if (p->scope == GLOBAL) + (*IR->defsymbol)(p); + else + addlocal(p); + } + t = gettok(); + if (xref) + use(p, src); + return idtree(p); + } + if (xref) + use(tsym, src); + if (tsym->sclass == ENUM) + p = consttree(tsym->u.value, inttype); + else { + if (tsym->sclass == TYPEDEF) + error("illegal use of type name `%s'\n", tsym->name); + p = idtree(tsym); + } break; + case FIRSTARG: + if (level > PARAM && cfunc && cfunc->u.f.callee[0]) + p = idtree(cfunc->u.f.callee[0]); + else { + error("illegal use of `%k'\n", FIRSTARG); + p = cnsttree(inttype, 0L); + } + break; + default: + error("illegal expression\n"); + p = cnsttree(inttype, 0L); + } + t = gettok(); + return p; +} +Tree idtree(Symbol p) { + int op; + Tree e; + Type ty = p->type ? unqual(p->type) : voidptype; + + if (p->scope == GLOBAL || p->sclass == STATIC) + op = ADDRG; + else if (p->scope == PARAM) { + op = ADDRF; + if (isstruct(p->type) && !IR->wants_argb) + { + e = tree(mkop(op,voidptype), ptr(ptr(p->type)), NULL, NULL); + e->u.sym = p; + return rvalue(rvalue(e)); + } + } else if (p->sclass == EXTERN) { + assert(p->u.alias); + p = p->u.alias; + op = ADDRG; + } else + op = ADDRL; + p->ref += refinc; + if (isarray(ty)) + e = tree(mkop(op,voidptype), p->type, NULL, NULL); + else if (isfunc(ty)) + e = tree(mkop(op,funcptype), p->type, NULL, NULL); + else + e = tree(mkop(op,voidptype), ptr(p->type), NULL, NULL); + e->u.sym = p; + if (isptr(e->type)) + e = rvalue(e); + return e; +} + +Tree rvalue(Tree p) { + Type ty = deref(p->type); + + ty = unqual(ty); + return tree(mkop(INDIR,ty), ty, p, NULL); +} +Tree lvalue(Tree p) { + if (generic(p->op) != INDIR) { + error("lvalue required\n"); + return value(p); + } else if (unqual(p->type) == voidtype) + warning("`%t' used as an lvalue\n", p->type); + return p->kids[0]; +} +Tree retype(Tree p, Type ty) { + Tree q; + + if (p->type == ty) + return p; + q = tree(p->op, ty, p->kids[0], p->kids[1]); + q->node = p->node; + q->u = p->u; + return q; +} +Tree rightkid(Tree p) { + while (p && p->op == RIGHT) + if (p->kids[1]) + p = p->kids[1]; + else if (p->kids[0]) + p = p->kids[0]; + else + assert(0); + assert(p); + return p; +} +int hascall(Tree p) { + if (p == 0) + return 0; + if (generic(p->op) == CALL || (IR->mulops_calls && + (p->op == DIV+I || p->op == MOD+I || p->op == MUL+I + || p->op == DIV+U || p->op == MOD+U || p->op == MUL+U))) + return 1; + return hascall(p->kids[0]) || hascall(p->kids[1]); +} +Type binary(Type xty, Type yty) { +#define xx(t) if (xty == t || yty == t) return t + xx(longdouble); + xx(doubletype); + xx(floattype); + xx(unsignedlonglong); + xx(longlong); + xx(unsignedlong); + if ((xty == longtype && yty == unsignedtype) + || (xty == unsignedtype && yty == longtype)) { + if (longtype->size > unsignedtype->size) + return longtype; + else + return unsignedlong; + } + xx(longtype); + xx(unsignedtype); + return inttype; +#undef xx +} +Tree pointer(Tree p) { + if (isarray(p->type)) + /* assert(p->op != RIGHT || p->u.sym == NULL), */ + p = retype(p, atop(p->type)); + else if (isfunc(p->type)) + p = retype(p, ptr(p->type)); + return p; +} +Tree cond(Tree p) { + int op = generic(rightkid(p)->op); + + if (op == AND || op == OR || op == NOT + || op == EQ || op == NE + || op == LE || op == LT || op == GE || op == GT) + return p; + p = pointer(p); + return (*optree[NEQ])(NE, p, consttree(0, inttype)); +} +Tree cast(Tree p, Type type) { + Type src, dst; + + p = value(p); + if (p->type == type) + return p; + dst = unqual(type); + src = unqual(p->type); + if (src->op != dst->op || src->size != dst->size) { + switch (src->op) { + case INT: + if (src->size < inttype->size) + p = simplify(CVI, inttype, p, NULL); + break; + case UNSIGNED: + if (src->size < inttype->size) + p = simplify(CVU, inttype, p, NULL); + else if (src->size < unsignedtype->size) + p = simplify(CVU, unsignedtype, p, NULL); + break; + case ENUM: + p = retype(p, inttype); + break; + case POINTER: + if (isint(dst) && src->size > dst->size) + warning("conversion from `%t' to `%t' is undefined\n", p->type, type); + p = simplify(CVP, super(src), p, NULL); + break; + case FLOAT: + break; + default: assert(0); + } + { + src = unqual(p->type); + dst = super(dst); + if (src->op != dst->op) + switch (src->op) { + case INT: + p = simplify(CVI, dst, p, NULL); + break; + case UNSIGNED: + if (isfloat(dst)) { + Type ssrc = signedint(src); + Tree two = cnsttree(longdouble, (long double)2.0); + p = (*optree['+'])(ADD, + (*optree['*'])(MUL, + two, + simplify(CVU, ssrc, + simplify(RSH, src, + p, consttree(1, inttype)), NULL)), + simplify(CVU, ssrc, + simplify(BAND, src, + p, consttree(1, unsignedtype)), NULL)); + } else + p = simplify(CVU, dst, p, NULL); + break; + case FLOAT: + if (isunsigned(dst)) { + Type sdst = signedint(dst); + Tree c = cast(cnsttree(longdouble, (long double)sdst->u.sym->u.limits.max.i + 1), src); + p = condtree( + simplify(GE, src, p, c), + (*optree['+'])(ADD, + cast(cast(simplify(SUB, src, p, c), sdst), dst), + cast(cnsttree(unsignedlong, (unsigned long)sdst->u.sym->u.limits.max.i + 1), dst)), + simplify(CVF, sdst, p, NULL)); + } else + p = simplify(CVF, dst, p, NULL); + break; + default: assert(0); + } + dst = unqual(type); + } + } + src = unqual(p->type); + switch (src->op) { + case INT: + if (src->op != dst->op || src->size != dst->size) + p = simplify(CVI, dst, p, NULL); + break; + case UNSIGNED: + if (src->op != dst->op || src->size != dst->size) + p = simplify(CVU, dst, p, NULL); + break; + case FLOAT: + if (src->op != dst->op || src->size != dst->size) + p = simplify(CVF, dst, p, NULL); + break; + case POINTER: + if (src->op != dst->op) + p = simplify(CVP, dst, p, NULL); + else { + if ((isfunc(src->type) && !isfunc(dst->type)) + || (!isfunc(src->type) && isfunc(dst->type))) + warning("conversion from `%t' to `%t' is compiler dependent\n", p->type, type); + + if (src->size != dst->size) + p = simplify(CVP, dst, p, NULL); + } + break; + default: assert(0); + } + return retype(p, type); +} +Tree field(Tree p, const char *name) { + Field q; + Type ty1, ty = p->type; + + if (isptr(ty)) + ty = deref(ty); + ty1 = ty; + ty = unqual(ty); + if ((q = fieldref(name, ty)) != NULL) { + if (isarray(q->type)) { + ty = q->type->type; + if (isconst(ty1) && !isconst(ty)) + ty = qual(CONST, ty); + if (isvolatile(ty1) && !isvolatile(ty)) + ty = qual(VOLATILE, ty); + ty = array(ty, q->type->size/ty->size, q->type->align); + } else { + ty = q->type; + if (isconst(ty1) && !isconst(ty)) + ty = qual(CONST, ty); + if (isvolatile(ty1) && !isvolatile(ty)) + ty = qual(VOLATILE, ty); + ty = ptr(ty); + } + if (YYcheck && !isaddrop(p->op) && q->offset > 0) /* omit */ + p = nullcall(ty, YYcheck, p, consttree(q->offset, inttype)); /* omit */ + else /* omit */ + p = simplify(ADD+P, ty, p, consttree(q->offset, signedptr)); + + if (q->lsb) { + p = tree(FIELD, ty->type, rvalue(p), NULL); + p->u.field = q; + } else if (!isarray(q->type)) + p = rvalue(p); + + } else { + error("unknown field `%s' of `%t'\n", name, ty); + p = rvalue(retype(p, ptr(inttype))); + } + return p; +} +/* funcname - return name of function f or a function' */ +char *funcname(Tree f) { + if (isaddrop(f->op)) + return stringf("`%s'", f->u.sym->name); + return "a function"; +} +static Tree nullcheck(Tree p) { + if (!needconst && YYnull && isptr(p->type)) { + p = value(p); + if (strcmp(YYnull->name, "_YYnull") == 0) { + Symbol t1 = temporary(REGISTER, voidptype); + p = tree(RIGHT, p->type, + tree(OR, voidtype, + cond(asgn(t1, cast(p, voidptype))), + vcall(YYnull, voidtype, (file && *file ? pointer(idtree(mkstr(file)->u.c.loc)) : cnsttree(voidptype, NULL)), cnsttree(inttype, (long)lineno) , NULL)), + idtree(t1)); + } + + else + p = nullcall(p->type, YYnull, p, cnsttree(inttype, 0L)); + + } + return p; +} +Tree nullcall(Type pty, Symbol f, Tree p, Tree e) { + Type ty; + + if (isarray(pty)) + return retype(nullcall(atop(pty), f, p, e), pty); + ty = unqual(unqual(p->type)->type); + return vcall(f, pty, + p, e, + cnsttree(inttype, (long)ty->size), + cnsttree(inttype, (long)ty->align), + (file && *file ? pointer(idtree(mkstr(file)->u.c.loc)) : cnsttree(voidptype, NULL)), cnsttree(inttype, (long)lineno) , NULL); +} diff --git a/src/cmd/lccom/gen.c b/src/cmd/lccom/gen.c new file mode 100644 index 0000000..d830c4c --- /dev/null +++ b/src/cmd/lccom/gen.c @@ -0,0 +1,839 @@ +#include "c.h" + +#define readsreg(p) \ + (generic((p)->op)==INDIR && (p)->kids[0]->op==VREG+P) +#define setsrc(d) ((d) && (d)->x.regnode && \ + (d)->x.regnode->set == src->x.regnode->set && \ + (d)->x.regnode->mask&src->x.regnode->mask) + +#define relink(a, b) ((b)->x.prev = (a), (a)->x.next = (b)) + +static Symbol askfixedreg(Symbol); +static Symbol askreg(Symbol, unsigned*); +static void blkunroll(int, int, int, int, int, int, int[]); +static void docall(Node); +#ifndef NDEBUG +static void dumpcover(Node, int, int); +static void dumpregs(char *, char *, char *); +static void dumprule(int); +static void dumptree(Node); +#endif +static void genreload(Node, Symbol, int); +static void genspill(Symbol, Node, Symbol); +static Symbol getreg(Symbol, unsigned*, Node); +static int getrule(Node, int); +static void linearize(Node, Node); +static int moveself(Node); +static void prelabel(Node); +static Node* prune(Node, Node*); +static void putreg(Symbol); +static void ralloc(Node); +static void reduce(Node, int); +static int reprune(Node*, int, int, Node); +static int requate(Node); +static Node reuse(Node, int); +static void rewrite(Node); +static Symbol spillee(Symbol, unsigned mask[], Node); +static void spillr(Symbol, Node); +static int uses(Node, Regnode); + +int offset; + +int maxoffset; + +int framesize; +int argoffset; + +int maxargoffset; + +int dalign, salign; +int bflag = 0; /* omit */ +int dflag = 0; + +int swap; + +unsigned (*emitter)(Node, int) = emitasm; +static char NeedsReg[] = { + 0, /* unused */ + 1, /* CNST */ + 0, 0, /* ARG ASGN */ + 1, /* INDIR */ + 0, 0, 1, 1, /* - - CVF CVI */ + 1, 0, 1, 1, /* CVP - CVU NEG */ + 1, /* CALL */ + 1, /* LOAD */ + 0, /* RET */ + 1, 1, 1, /* ADDRG ADDRF ADDRL */ + 1, 1, 1, 1, 1, /* ADD SUB LSH MOD RSH */ + 1, 1, 1, 1, /* BAND BCOM BOR BXOR */ + 1, 1, /* DIV MUL */ + 0, 0, 0, 0, 0, 0, /* EQ GE GT LE LT NE */ + 0, 0 /* JUMP LABEL */ +}; +Node head; + +unsigned freemask[2]; +unsigned usedmask[2]; +unsigned tmask[2]; +unsigned vmask[2]; +Symbol mkreg(char *fmt, int n, int mask, int set) { + Symbol p; + + NEW0(p, PERM); + p->name = p->x.name = stringf(fmt, n); + NEW0(p->x.regnode, PERM); + p->x.regnode->number = n; + p->x.regnode->mask = mask<x.regnode->set = set; + return p; +} +Symbol mkwildcard(Symbol *syms) { + Symbol p; + + NEW0(p, PERM); + p->name = p->x.name = "wildcard"; + p->x.wildcard = syms; + return p; +} +void mkauto(Symbol p) { + assert(p->sclass == AUTO); + offset = roundup(offset + p->type->size, p->type->align); + p->x.offset = -offset; + p->x.name = stringd(-offset); +} +void blockbeg(Env *e) { + e->offset = offset; + e->freemask[IREG] = freemask[IREG]; + e->freemask[FREG] = freemask[FREG]; +} +void blockend(Env *e) { + if (offset > maxoffset) + maxoffset = offset; + offset = e->offset; + freemask[IREG] = e->freemask[IREG]; + freemask[FREG] = e->freemask[FREG]; +} +int mkactual(int align, int size) { + int n = roundup(argoffset, align); + + argoffset = n + size; + return n; +} +static void docall(Node p) { + p->syms[1] = p->syms[0]; + p->syms[0] = intconst(argoffset); + if (argoffset > maxargoffset) + maxargoffset = argoffset; + argoffset = 0; +} +void blkcopy(int dreg, int doff, int sreg, int soff, int size, int tmp[]) { + assert(size >= 0); + if (size == 0) + return; + else if (size <= 2) + blkunroll(size, dreg, doff, sreg, soff, size, tmp); + else if (size == 3) { + blkunroll(2, dreg, doff, sreg, soff, 2, tmp); + blkunroll(1, dreg, doff+2, sreg, soff+2, 1, tmp); + } + else if (size <= 16) { + blkunroll(4, dreg, doff, sreg, soff, size&~3, tmp); + blkcopy(dreg, doff+(size&~3), + sreg, soff+(size&~3), size&3, tmp); + } + else + (*IR->x.blkloop)(dreg, doff, sreg, soff, size, tmp); +} +static void blkunroll(int k, int dreg, int doff, int sreg, int soff, int size, int tmp[]) { + int i; + + assert(IR->x.max_unaligned_load); + if (k > IR->x.max_unaligned_load + && (k > salign || k > dalign)) + k = IR->x.max_unaligned_load; + for (i = 0; i+k < size; i += 2*k) { + (*IR->x.blkfetch)(k, soff+i, sreg, tmp[0]); + (*IR->x.blkfetch)(k, soff+i+k, sreg, tmp[1]); + (*IR->x.blkstore)(k, doff+i, dreg, tmp[0]); + (*IR->x.blkstore)(k, doff+i+k, dreg, tmp[1]); + } + if (i < size) { + (*IR->x.blkfetch)(k, i+soff, sreg, tmp[0]); + (*IR->x.blkstore)(k, i+doff, dreg, tmp[0]); + } +} +void parseflags(int argc, char *argv[]) { + int i; + + for (i = 0; i < argc; i++) + if (strcmp(argv[i], "-d") == 0) + dflag = 1; + else if (strcmp(argv[i], "-b") == 0) /* omit */ + bflag = 1; /* omit */ +} +static int getrule(Node p, int nt) { + int rulenum; + + assert(p); + rulenum = (*IR->x._rule)(p->x.state, nt); + if (!rulenum) { + fprint(stderr, "(%x->op=%s at %w is corrupt.)\n", p, opname(p->op), &src); + assert(0); + } + return rulenum; +} +static void reduce(Node p, int nt) { + int rulenum, i; + short *nts; + Node kids[10]; + + p = reuse(p, nt); + rulenum = getrule(p, nt); + nts = IR->x._nts[rulenum]; + (*IR->x._kids)(p, rulenum, kids); + for (i = 0; nts[i]; i++) + reduce(kids[i], nts[i]); + if (IR->x._isinstruction[rulenum]) { + assert(p->x.inst == 0 || p->x.inst == nt); + p->x.inst = nt; + if (p->syms[RX] && p->syms[RX]->temporary) { + debug(fprint(stderr, "(using %s)\n", p->syms[RX]->name)); + p->syms[RX]->x.usecount++; + } + } +} +static Node reuse(Node p, int nt) { + struct _state { + short cost[1]; + }; + Symbol r = p->syms[RX]; + + if (generic(p->op) == INDIR && p->kids[0]->op == VREG+P + && r->u.t.cse && p->x.mayrecalc + && ((struct _state*)r->u.t.cse->x.state)->cost[nt] == 0) + return r->u.t.cse; + else + return p; +} + +int mayrecalc(Node p) { + int op; + + assert(p && p->syms[RX]); + if (p->syms[RX]->u.t.cse == NULL) + return 0; + op = generic(p->syms[RX]->u.t.cse->op); + if (op == CNST || op == ADDRF || op == ADDRG || op == ADDRL) { + p->x.mayrecalc = 1; + return 1; + } else + return 0; +} +static Node *prune(Node p, Node pp[]) { + if (p == NULL) + return pp; + p->x.kids[0] = p->x.kids[1] = p->x.kids[2] = NULL; + if (p->x.inst == 0) + return prune(p->kids[1], prune(p->kids[0], pp)); + else if (p->syms[RX] && p->syms[RX]->temporary + && p->syms[RX]->x.usecount < 2) { + p->x.inst = 0; + debug(fprint(stderr, "(clobbering %s)\n", p->syms[RX]->name)); + return prune(p->kids[1], prune(p->kids[0], pp)); + } + else { + prune(p->kids[1], prune(p->kids[0], &p->x.kids[0])); + *pp = p; + return pp + 1; + } +} + +#define ck(i) return (i) ? 0 : LBURG_MAX + +int range(Node p, int lo, int hi) { + Symbol s = p->syms[0]; + + switch (specific(p->op)) { + case ADDRF+P: + case ADDRL+P: ck(s->x.offset >= lo && s->x.offset <= hi); + case CNST+I: ck(s->u.c.v.i >= lo && s->u.c.v.i <= hi); + case CNST+U: ck(s->u.c.v.u >= lo && s->u.c.v.u <= hi); + case CNST+P: ck(s->u.c.v.p == 0 && lo <= 0 && hi >= 0); + } + return LBURG_MAX; +} +#ifndef NDEBUG +static void dumptree(Node p) { + if (p->op == VREG+P && p->syms[0]) { + fprint(stderr, "VREGP(%s)", p->syms[0]->name); + return; + } else if (generic(p->op) == LOAD) { + fprint(stderr, "LOAD("); + dumptree(p->kids[0]); + fprint(stderr, ")"); + return; + } + fprint(stderr, "%s(", opname(p->op)); + switch (generic(p->op)) { + case CNST: case LABEL: + case ADDRG: case ADDRF: case ADDRL: + if (p->syms[0]) + fprint(stderr, "%s", p->syms[0]->name); + break; + case RET: + if (p->kids[0]) + dumptree(p->kids[0]); + break; + case CVF: case CVI: case CVP: case CVU: case JUMP: + case ARG: case BCOM: case NEG: case INDIR: + dumptree(p->kids[0]); + break; + case CALL: + if (optype(p->op) != B) { + dumptree(p->kids[0]); + break; + } + /* else fall thru */ + case EQ: case NE: case GT: case GE: case LE: case LT: + case ASGN: case BOR: case BAND: case BXOR: case RSH: case LSH: + case ADD: case SUB: case DIV: case MUL: case MOD: + dumptree(p->kids[0]); + fprint(stderr, ", "); + dumptree(p->kids[1]); + break; + default: assert(0); + } + fprint(stderr, ")"); +} + +static void dumpcover(Node p, int nt, int in) { + int rulenum, i; + short *nts; + Node kids[10]; + + p = reuse(p, nt); + rulenum = getrule(p, nt); + nts = IR->x._nts[rulenum]; + fprint(stderr, "dumpcover(%x) = ", p); + for (i = 0; i < in; i++) + fprint(stderr, " "); + dumprule(rulenum); + (*IR->x._kids)(p, rulenum, kids); + for (i = 0; nts[i]; i++) + dumpcover(kids[i], nts[i], in+1); +} + +static void dumpregs(char *msg, char *a, char *b) { + fprint(stderr, msg, a, b); + fprint(stderr, "(free[0]=%x)\n", freemask[0]); + fprint(stderr, "(free[1]=%x)\n", freemask[1]); +} + +static void dumprule(int rulenum) { + assert(rulenum); + fprint(stderr, "%s / %s", IR->x._string[rulenum], + IR->x._templates[rulenum]); + if (!IR->x._isinstruction[rulenum]) + fprint(stderr, "\n"); +} +#endif /* NDEBUG */ + +unsigned emitasm(Node p, int nt) { + int rulenum; + short *nts; + char *fmt; + Node kids[10]; + + p = reuse(p, nt); + rulenum = getrule(p, nt); + nts = IR->x._nts[rulenum]; + fmt = IR->x._templates[rulenum]; + assert(fmt); + if (IR->x._isinstruction[rulenum] && p->x.emitted) + print("%s", p->syms[RX]->x.name); + else if (*fmt == '#') + (*IR->x.emit2)(p); + else { + if (*fmt == '?') { + fmt++; + assert(p->kids[0]); + if (p->syms[RX] == p->x.kids[0]->syms[RX]) + while (*fmt++ != '\n') + ; + } + for ((*IR->x._kids)(p, rulenum, kids); *fmt; fmt++) + if (*fmt == ' ') + (void)putchar('\t'); + else if (*fmt == ';') + (void)putchar('\n'); + else if (*fmt != '%') + (void)putchar(*fmt); + else if (*++fmt == 'F') + print("%d", framesize); + else if (*fmt >= '0' && *fmt <= '9') + emitasm(kids[*fmt - '0'], nts[*fmt - '0']); + else if (*fmt >= 'a' && *fmt < 'a' + NELEMS(p->syms)) + fputs(p->syms[*fmt - 'a']->x.name, stdout); + else + (void)putchar(*fmt); + } + return 0; +} +void emit(Node p) { + for (; p; p = p->x.next) { + assert(p->x.registered); + if ((p->x.equatable && requate(p)) || moveself(p)) + ; + else + (*emitter)(p, p->x.inst); + p->x.emitted = 1; + } +} +static int moveself(Node p) { + return p->x.copy + && p->syms[RX]->x.name == p->x.kids[0]->syms[RX]->x.name; +} +int move(Node p) { + p->x.copy = 1; + return 1; +} +static int requate(Node q) { + Symbol src = q->x.kids[0]->syms[RX]; + Symbol tmp = q->syms[RX]; + Node p; + int n = 0; + + debug(fprint(stderr, "(requate(%x): tmp=%s src=%s)\n", q, tmp->x.name, src->x.name)); + for (p = q->x.next; p; p = p->x.next) + if (p->x.copy && p->syms[RX] == src + && p->x.kids[0]->syms[RX] == tmp) + debug(fprint(stderr, "(requate arm 0 at %x)\n", p)), + p->syms[RX] = tmp; + else if (setsrc(p->syms[RX]) && !moveself(p) && !readsreg(p)) + return 0; + else if (p->x.spills) + return 0; + else if (generic(p->op) == CALL && p->x.next) + return 0; + else if (p->op == LABEL+V && p->x.next) + return 0; + else if (p->syms[RX] == tmp && readsreg(p)) + debug(fprint(stderr, "(requate arm 5 at %x)\n", p)), + n++; + else if (p->syms[RX] == tmp) + break; + debug(fprint(stderr, "(requate arm 7 at %x)\n", p)); + assert(n > 0); + for (p = q->x.next; p; p = p->x.next) + if (p->syms[RX] == tmp && readsreg(p)) { + p->syms[RX] = src; + if (--n <= 0) + break; + } + return 1; +} +static void prelabel(Node p) { + if (p == NULL) + return; + prelabel(p->kids[0]); + prelabel(p->kids[1]); + if (NeedsReg[opindex(p->op)]) + setreg(p, (*IR->x.rmap)(opkind(p->op))); + switch (generic(p->op)) { + case ADDRF: case ADDRL: + if (p->syms[0]->sclass == REGISTER) + p->op = VREG+P; + break; + case INDIR: + if (p->kids[0]->op == VREG+P) + setreg(p, p->kids[0]->syms[0]); + break; + case ASGN: + if (p->kids[0]->op == VREG+P) + rtarget(p, 1, p->kids[0]->syms[0]); + break; + case CVI: case CVU: case CVP: + if (optype(p->op) != F + && opsize(p->op) <= p->syms[0]->u.c.v.i) + p->op = LOAD + opkind(p->op); + break; + } + (IR->x.target)(p); +} +void setreg(Node p, Symbol r) { + p->syms[RX] = r; +} +void rtarget(Node p, int n, Symbol r) { + Node q = p->kids[n]; + + assert(q); + assert(r); + assert(r->sclass == REGISTER || !r->x.wildcard); + assert(q->syms[RX]); + if (r != q->syms[RX] && !q->syms[RX]->x.wildcard) { + q = newnode(LOAD + opkind(q->op), + q, NULL, q->syms[0]); + if (r->u.t.cse == p->kids[n]) + r->u.t.cse = q; + p->kids[n] = p->x.kids[n] = q; + q->x.kids[0] = q->kids[0]; + } + setreg(q, r); + debug(fprint(stderr, "(targeting %x->x.kids[%d]=%x to %s)\n", p, n, p->kids[n], r->x.name)); +} +static void rewrite(Node p) { + assert(p->x.inst == 0); + prelabel(p); + debug(dumptree(p)); + debug(fprint(stderr, "\n")); + (*IR->x._label)(p); + debug(dumpcover(p, 1, 0)); + reduce(p, 1); +} +Node gen(Node forest) { + int i; + struct node sentinel; + Node dummy, p; + + head = forest; + for (p = forest; p; p = p->link) { + assert(p->count == 0); + if (generic(p->op) == CALL) + docall(p); + else if ( generic(p->op) == ASGN + && generic(p->kids[1]->op) == CALL) + docall(p->kids[1]); + else if (generic(p->op) == ARG) + (*IR->x.doarg)(p); + rewrite(p); + p->x.listed = 1; + } + for (p = forest; p; p = p->link) + prune(p, &dummy); + relink(&sentinel, &sentinel); + for (p = forest; p; p = p->link) + linearize(p, &sentinel); + forest = sentinel.x.next; + assert(forest); + sentinel.x.next->x.prev = NULL; + sentinel.x.prev->x.next = NULL; + for (p = forest; p; p = p->x.next) + for (i = 0; i < NELEMS(p->x.kids) && p->x.kids[i]; i++) { + assert(p->x.kids[i]->syms[RX]); + if (p->x.kids[i]->syms[RX]->temporary) { + p->x.kids[i]->x.prevuse = + p->x.kids[i]->syms[RX]->x.lastuse; + p->x.kids[i]->syms[RX]->x.lastuse = p->x.kids[i]; + } + } + for (p = forest; p; p = p->x.next) { + ralloc(p); + if (p->x.listed && NeedsReg[opindex(p->op)] + && (*IR->x.rmap)(opkind(p->op))) { + assert(generic(p->op) == CALL || generic(p->op) == LOAD); + putreg(p->syms[RX]); + } + } + return forest; +} +int notarget(Node p) { + return p->syms[RX]->x.wildcard ? 0 : LBURG_MAX; +} +static void putreg(Symbol r) { + assert(r && r->x.regnode); + freemask[r->x.regnode->set] |= r->x.regnode->mask; + debug(dumpregs("(freeing %s)\n", r->x.name, NULL)); +} +static Symbol askfixedreg(Symbol s) { + Regnode r = s->x.regnode; + int n = r->set; + + if (r->mask&~freemask[n]) + return NULL; + else { + freemask[n] &= ~r->mask; + usedmask[n] |= r->mask; + return s; + } +} +static Symbol askreg(Symbol rs, unsigned rmask[]) { + int i; + + if (rs->x.wildcard == NULL) + return askfixedreg(rs); + for (i = 31; i >= 0; i--) { + Symbol r = rs->x.wildcard[i]; + if (r != NULL + && !(r->x.regnode->mask&~rmask[r->x.regnode->set]) + && askfixedreg(r)) + return r; + } + return NULL; +} + +static Symbol getreg(Symbol s, unsigned mask[], Node p) { + Symbol r = askreg(s, mask); + if (r == NULL) { + r = spillee(s, mask, p); + assert(r && r->x.regnode); + spill(r->x.regnode->mask, r->x.regnode->set, p); + r = askreg(s, mask); + } + assert(r && r->x.regnode); + r->x.regnode->vbl = NULL; + return r; +} +int askregvar(Symbol p, Symbol regs) { + Symbol r; + + assert(p); + if (p->sclass != REGISTER) + return 0; + else if (!isscalar(p->type)) { + p->sclass = AUTO; + return 0; + } + else if (p->temporary) { + p->x.name = "?"; + return 1; + } + else if ((r = askreg(regs, vmask)) != NULL) { + p->x.regnode = r->x.regnode; + p->x.regnode->vbl = p; + p->x.name = r->x.name; + debug(dumpregs("(allocating %s to symbol %s)\n", p->x.name, p->name)); + return 1; + } + else { + p->sclass = AUTO; + return 0; + } +} +static void linearize(Node p, Node next) { + int i; + + for (i = 0; i < NELEMS(p->x.kids) && p->x.kids[i]; i++) + linearize(p->x.kids[i], next); + relink(next->x.prev, p); + relink(p, next); + debug(fprint(stderr, "(listing %x)\n", p)); +} +static void ralloc(Node p) { + int i; + unsigned mask[2]; + + mask[0] = tmask[0]; + mask[1] = tmask[1]; + assert(p); + debug(fprint(stderr, "(rallocing %x)\n", p)); + for (i = 0; i < NELEMS(p->x.kids) && p->x.kids[i]; i++) { + Node kid = p->x.kids[i]; + Symbol r = kid->syms[RX]; + assert(r && kid->x.registered); + if (r->sclass != REGISTER && r->x.lastuse == kid) + putreg(r); + } + if (!p->x.registered && NeedsReg[opindex(p->op)] + && (*IR->x.rmap)(opkind(p->op))) { + Symbol sym = p->syms[RX], set = sym; + assert(sym); + if (sym->temporary) + set = (*IR->x.rmap)(opkind(p->op)); + assert(set); + if (set->sclass != REGISTER) { + Symbol r; + if (*IR->x._templates[getrule(p, p->x.inst)] == '?') + for (i = 1; i < NELEMS(p->x.kids) && p->x.kids[i]; i++) { + Symbol r = p->x.kids[i]->syms[RX]; + assert(p->x.kids[i]->x.registered); + assert(r && r->x.regnode); + assert(sym->x.wildcard || sym != r); + mask[r->x.regnode->set] &= ~r->x.regnode->mask; + } + r = getreg(set, mask, p); + if (sym->temporary) { + Node q; + r->x.lastuse = sym->x.lastuse; + for (q = sym->x.lastuse; q; q = q->x.prevuse) { + q->syms[RX] = r; + q->x.registered = 1; + if (sym->u.t.cse && q->x.copy) + q->x.equatable = 1; + } + } else { + p->syms[RX] = r; + r->x.lastuse = p; + } + debug(dumpregs("(allocating %s to node %x)\n", r->x.name, (char *) p)); + } + } + p->x.registered = 1; + (*IR->x.clobber)(p); +} +static Symbol spillee(Symbol set, unsigned mask[], Node here) { + Symbol bestreg = NULL; + int bestdist = -1, i; + + assert(set); + if (!set->x.wildcard) + bestreg = set; + else { + for (i = 31; i >= 0; i--) { + Symbol ri = set->x.wildcard[i]; + if ( + ri != NULL && + ri->x.lastuse && + (ri->x.regnode->mask&tmask[ri->x.regnode->set]&mask[ri->x.regnode->set]) + ) { + Regnode rn = ri->x.regnode; + Node q = here; + int dist = 0; + for (; q && !uses(q, rn); q = q->x.next) + dist++; + if (q && dist > bestdist) { + bestdist = dist; + bestreg = ri; + } + } + } + } + assert(bestreg); /* Must be able to spill something. Reconfigure the register allocator + to ensure that we can allocate a register for all nodes without spilling + the node's necessary input regs. */ + assert(bestreg->x.regnode->vbl == NULL); /* Can't spill register variables because + the reload site might be in other blocks. Reconfigure the register allocator + to ensure that this register is never allocated to a variable. */ + return bestreg; +} +static int uses(Node p, Regnode rn) { + int i; + + for (i = 0; i < NELEMS(p->x.kids); i++) + if ( + p->x.kids[i] && + p->x.kids[i]->x.registered && + rn->set == p->x.kids[i]->syms[RX]->x.regnode->set && + (rn->mask&p->x.kids[i]->syms[RX]->x.regnode->mask) + ) + return 1; + return 0; +} +static void spillr(Symbol r, Node here) { + int i; + Symbol tmp; + Node p = r->x.lastuse; + assert(p); + while (p->x.prevuse) { + assert(r == p->syms[RX]); + p = p->x.prevuse; + } + assert(p->x.registered && !readsreg(p)); + tmp = newtemp(AUTO, optype(p->op), opsize(p->op)); + genspill(r, p, tmp); + for (p = here->x.next; p; p = p->x.next) + for (i = 0; i < NELEMS(p->x.kids) && p->x.kids[i]; i++) { + Node k = p->x.kids[i]; + if (k->x.registered && k->syms[RX] == r) + genreload(p, tmp, i); + } + putreg(r); +} +static void genspill(Symbol r, Node last, Symbol tmp) { + Node p, q; + Symbol s; + unsigned ty; + + debug(fprint(stderr, "(spilling %s to local %s)\n", r->x.name, tmp->x.name)); + debug(fprint(stderr, "(genspill: ")); + debug(dumptree(last)); + debug(fprint(stderr, ")\n")); + ty = opkind(last->op); + NEW0(s, FUNC); + s->sclass = REGISTER; + s->name = s->x.name = r->x.name; + s->x.regnode = r->x.regnode; + q = newnode(ADDRL+P + sizeop(IR->ptrmetric.size), NULL, NULL, s); + q = newnode(INDIR + ty, q, NULL, NULL); + p = newnode(ADDRL+P + sizeop(IR->ptrmetric.size), NULL, NULL, tmp); + p = newnode(ASGN + ty, p, q, NULL); + p->x.spills = 1; + rewrite(p); + prune(p, &q); + q = last->x.next; + linearize(p, q); + for (p = last->x.next; p != q; p = p->x.next) { + ralloc(p); + assert(!p->x.listed || !NeedsReg[opindex(p->op)] || !(*IR->x.rmap)(opkind(p->op))); + } +} + +static void genreload(Node p, Symbol tmp, int i) { + Node q; + int ty; + + debug(fprint(stderr, "(replacing %x with a reload from %s)\n", p->x.kids[i], tmp->x.name)); + debug(fprint(stderr, "(genreload: ")); + debug(dumptree(p->x.kids[i])); + debug(fprint(stderr, ")\n")); + ty = opkind(p->x.kids[i]->op); + q = newnode(ADDRL+P + sizeop(IR->ptrmetric.size), NULL, NULL, tmp); + p->x.kids[i] = newnode(INDIR + ty, q, NULL, NULL); + rewrite(p->x.kids[i]); + prune(p->x.kids[i], &q); + reprune(&p->kids[1], reprune(&p->kids[0], 0, i, p), i, p); + prune(p, &q); + linearize(p->x.kids[i], p); +} +static int reprune(Node *pp, int k, int n, Node p) { + struct node x, *q = *pp; + + if (q == NULL || k > n) + return k; + else if (q->x.inst == 0) + return reprune(&q->kids[1], + reprune(&q->kids[0], k, n, p), n, p); + if (k == n) { + debug(fprint(stderr, "(reprune changes %x from %x to %x)\n", pp, *pp, p->x.kids[n])); + *pp = p->x.kids[n]; + x = *p; + (IR->x.target)(&x); + } + return k + 1; +} +void spill(unsigned mask, int n, Node here) { + int i; + Node p; + + here->x.spills = 1; + usedmask[n] |= mask; + if (mask&~freemask[n]) { + + assert( /* It makes no sense for a node to clobber() its target. */ + here->x.registered == 0 || /* call isn't coming through clobber() */ + here->syms[RX] == NULL || + here->syms[RX]->x.regnode == NULL || + here->syms[RX]->x.regnode->set != n || + (here->syms[RX]->x.regnode->mask&mask) == 0 + ); + + for (p = here; p; p = p->x.next) + for (i = 0; i < NELEMS(p->x.kids) && p->x.kids[i]; i++) { + Symbol r = p->x.kids[i]->syms[RX]; + assert(r); + if (p->x.kids[i]->x.registered && r->x.regnode->set == n + && r->x.regnode->mask&mask) + spillr(r, here); + } + } +} + +int getregnum(Node p) { + assert(p && p->syms[RX] && p->syms[RX]->x.regnode); + return p->syms[RX]->x.regnode->number; +} + + +unsigned regloc(Symbol p) { + assert(p && p->sclass == REGISTER && p->sclass == REGISTER && p->x.regnode); + return p->x.regnode->set<<8 | p->x.regnode->number; +} diff --git a/src/cmd/lccom/init.c b/src/cmd/lccom/init.c new file mode 100644 index 0000000..fbb7220 --- /dev/null +++ b/src/cmd/lccom/init.c @@ -0,0 +1,317 @@ +#include "c.h" + +static int curseg; /* current segment */ + +/* defpointer - initialize a pointer to p or to 0 if p==0 */ +void defpointer(Symbol p) { + if (p) { + (*IR->defaddress)(p); + p->ref++; + } else { + static Value v; + (*IR->defconst)(P, voidptype->size, v); + } +} + +/* genconst - generate/check constant expression e; return size */ +static int genconst(Tree e, int def) { + for (;;) + switch (generic(e->op)) { + case ADDRG: + if (def) + (*IR->defaddress)(e->u.sym); + return e->type->size; + case CNST: + if (e->op == CNST+P && isarray(e->type)) { + e = cvtconst(e); + continue; + } + if (def) + (*IR->defconst)(e->type->op, e->type->size, e->u.v); + return e->type->size; + case RIGHT: + assert(e->kids[0] || e->kids[1]); + if (e->kids[1] && e->kids[0]) + error("initializer must be constant\n"); + e = e->kids[1] ? e->kids[1] : e->kids[0]; + continue; + case CVP: + if (isarith(e->type)) + error("cast from `%t' to `%t' is illegal in constant expressions\n", + e->kids[0]->type, e->type); + /* fall thru */ + case CVI: case CVU: case CVF: + e = e->kids[0]; + continue; + default: + error("initializer must be constant\n"); + if (def) + genconst(consttree(0, inttype), def); + return inttype->size; + } +} + +/* initvalue - evaluate a constant expression for a value of integer type ty */ +static Tree initvalue(Type ty) { + Type aty; + Tree e; + + needconst++; + e = expr1(0); + if ((aty = assign(ty, e)) != NULL) + e = cast(e, aty); + else { + error("invalid initialization type; found `%t' expected `%t'\n", + e->type, ty); + e = retype(consttree(0, inttype), ty); + } + needconst--; + if (generic(e->op) != CNST) { + error("initializer must be constant\n"); + e = retype(consttree(0, inttype), ty); + } + return e; +} + +/* initarray - initialize array of ty of <= len bytes; if len == 0, go to } */ +static int initarray(int len, Type ty, int lev) { + int n = 0; + + do { + initializer(ty, lev); + n += ty->size; + if ((len > 0 && n >= len) || t != ',') + break; + t = gettok(); + } while (t != '}'); + return n; +} + +/* initchar - initialize array of <= len ty characters; if len == 0, go to } */ +static int initchar(int len, Type ty) { + int n = 0; + char buf[16], *s = buf; + + do { + *s++ = initvalue(ty)->u.v.i; + if (++n%inttype->size == 0) { + (*IR->defstring)(inttype->size, buf); + s = buf; + } + if ((len > 0 && n >= len) || t != ',') + break; + t = gettok(); + } while (t != '}'); + if (s > buf) + (*IR->defstring)(s - buf, buf); + return n; +} + +/* initend - finish off an initialization at level lev; accepts trailing comma */ +static void initend(int lev, char follow[]) { + if (lev == 0 && t == ',') + t = gettok(); + test('}', follow); +} + +/* initfields - initialize <= an unsigned's worth of bit fields in fields p to q */ +static int initfields(Field p, Field q) { + unsigned int bits = 0; + int i, n = 0; + + do { + i = initvalue(inttype)->u.v.i; + if (fieldsize(p) < 8*p->type->size) { + if ((p->type == inttype && + (i < -(int)(fieldmask(p)>>1)-1 || i > (int)(fieldmask(p)>>1))) + || (p->type == unsignedtype && (i&~fieldmask(p)) != 0)) + warning("initializer exceeds bit-field width\n"); + i &= fieldmask(p); + } + bits |= i<little_endian) { + if (fieldsize(p) + fieldright(p) > n) + n = fieldsize(p) + fieldright(p); + } else { + if (fieldsize(p) + fieldleft(p) > n) + n = fieldsize(p) + fieldleft(p); + } + if (p->link == q) + break; + p = p->link; + } while (t == ',' && (t = gettok()) != 0); + n = (n + 7)/8; + for (i = 0; i < n; i++) { + Value v; + if (IR->little_endian) { + v.u = (unsigned char)bits; + bits >>= 8; + } else { /* a big endian */ + v.u = (unsigned char)(bits>>(8*(unsignedtype->size - 1))); + bits <<= 8; + } + (*IR->defconst)(U, unsignedchar->size, v); + } + return n; +} + +/* initstruct - initialize a struct ty of <= len bytes; if len == 0, go to } */ +static int initstruct(int len, Type ty, int lev) { + int a, n = 0; + Field p = ty->u.sym->u.s.flist; + + do { + if (p->offset > n) { + (*IR->space)(p->offset - n); + n += p->offset - n; + } + if (p->lsb) { + Field q = p; + while (q->link && q->link->offset == p->offset) + q = q->link; + n += initfields(p, q->link); + p = q; + } else { + initializer(p->type, lev); + n += p->type->size; + } + if (p->link) { + p = p->link; + a = p->type->align; + } else + a = ty->align; + if (a && n%a) { + (*IR->space)(a - n%a); + n = roundup(n, a); + } + if ((len > 0 && n >= len) || t != ',') + break; + t = gettok(); + } while (t != '}'); + return n; +} + +/* initializer - constexpr | { constexpr ( , constexpr )* [ , ] } */ +Type initializer(Type ty, int lev) { + int n = 0; + Tree e; + Type aty = NULL; + static char follow[] = { IF, CHAR, STATIC, 0 }; + + ty = unqual(ty); + if (isscalar(ty)) { + needconst++; + if (t == '{') { + t = gettok(); + e = expr1(0); + initend(lev, follow); + } else + e = expr1(0); + e = pointer(e); + if ((aty = assign(ty, e)) != NULL) + e = cast(e, aty); + else + error("invalid initialization type; found `%t' expected `%t'\n", + e->type, ty); + n = genconst(e, 1); + deallocate(STMT); + needconst--; + } + if ((isunion(ty) || isstruct(ty)) && ty->size == 0) { + static char follow[] = { CHAR, STATIC, 0 }; + error("cannot initialize undefined `%t'\n", ty); + skipto(';', follow); + return ty; + } else if (isunion(ty)) { + if (t == '{') { + t = gettok(); + n = initstruct(ty->u.sym->u.s.flist->type->size, ty, lev + 1); + initend(lev, follow); + } else { + if (lev == 0) + error("missing { in initialization of `%t'\n", ty); + n = initstruct(ty->u.sym->u.s.flist->type->size, ty, lev + 1); + } + } else if (isstruct(ty)) { + if (t == '{') { + t = gettok(); + n = initstruct(0, ty, lev + 1); + test('}', follow); + } else if (lev > 0) + n = initstruct(ty->size, ty, lev + 1); + else { + error("missing { in initialization of `%t'\n", ty); + n = initstruct(ty->u.sym->u.s.flist->type->size, ty, lev + 1); + } + } + if (isarray(ty)) + aty = unqual(ty->type); + if (isarray(ty) && ischar(aty)) { + if (t == SCON) { + if (ty->size > 0 && ty->size == tsym->type->size - 1) + tsym->type = array(chartype, ty->size, 0); + n = tsym->type->size; + (*IR->defstring)(tsym->type->size, tsym->u.c.v.p); + t = gettok(); + } else if (t == '{') { + t = gettok(); + if (t == SCON) { + ty = initializer(ty, lev + 1); + initend(lev, follow); + return ty; + } + n = initchar(0, aty); + test('}', follow); + } else if (lev > 0 && ty->size > 0) + n = initchar(ty->size, aty); + else { /* eg, char c[] = 0; */ + error("missing { in initialization of `%t'\n", ty); + n = initchar(1, aty); + } + } else if (isarray(ty)) { + if (t == SCON && aty == widechar) { + int i; + unsigned int *s = tsym->u.c.v.p; + if (ty->size > 0 && ty->size == tsym->type->size - widechar->size) + tsym->type = array(widechar, ty->size/widechar->size, 0); + n = tsym->type->size; + for (i = 0; i < n; i += widechar->size) { + Value v; + v.u = *s++; + (*IR->defconst)(widechar->op, widechar->size, v); + } + t = gettok(); + } else if (t == '{') { + t = gettok(); + if (t == SCON && aty == widechar) { + ty = initializer(ty, lev + 1); + initend(lev, follow); + return ty; + } + n = initarray(0, aty, lev + 1); + test('}', follow); + } else if (lev > 0 && ty->size > 0) + n = initarray(ty->size, aty, lev + 1); + else { + error("missing { in initialization of `%t'\n", ty); + n = initarray(aty->size, aty, lev + 1); + } + } + if (ty->size) { + if (n > ty->size) + error("too many initializers\n"); + else if (n < ty->size) + (*IR->space)(ty->size - n); + } else if (isarray(ty) && ty->type->size > 0) + ty = array(ty->type, n/ty->type->size, 0); + else + ty->size = n; + return ty; +} + +/* swtoseg - switch to segment seg, if necessary */ +void swtoseg(int seg) { + if (curseg != seg) + (*IR->segment)(seg); + curseg = seg; +} diff --git a/src/cmd/lccom/inits.c b/src/cmd/lccom/inits.c new file mode 100644 index 0000000..995f81a --- /dev/null +++ b/src/cmd/lccom/inits.c @@ -0,0 +1,6 @@ +void init(int argc, char *argv[]) +{ + {extern void input_init(int, char *[]); input_init(argc, argv);} + {extern void main_init(int, char *[]); main_init(argc, argv);} + {extern void type_init(int, char *[]); type_init(argc, argv);} +} diff --git a/src/cmd/lccom/input.c b/src/cmd/lccom/input.c new file mode 100644 index 0000000..a70ae0c --- /dev/null +++ b/src/cmd/lccom/input.c @@ -0,0 +1,144 @@ +#include "c.h" + +static void pragma(void); +static void resynch(void); + +static int bsize; +static unsigned char buffer[MAXLINE+1 + BUFSIZE+1]; +unsigned char *cp; /* current input character */ +char *file; /* current input file name */ +char *firstfile; /* first input file */ +unsigned char *limit; /* points to last character + 1 */ +char *line; /* current line */ +int lineno; /* line number of current line */ + +void nextline(void) { + do { + if (cp >= limit) { + fillbuf(); + if (cp >= limit) + cp = limit; + if (cp == limit) + return; + } else { + lineno++; + for (line = (char *)cp; *cp==' ' || *cp=='\t'; cp++) + ; + if (*cp == '#') { + resynch(); + nextline(); + } + } + } while (*cp == '\n' && cp == limit); +} +void fillbuf(void) { + if (bsize == 0) + return; + if (cp >= limit) + cp = &buffer[MAXLINE+1]; + else + { + int n = limit - cp; + unsigned char *s = &buffer[MAXLINE+1] - n; + assert(s >= buffer); + line = (char *)s - ((char *)cp - line); + while (cp < limit) + *s++ = *cp++; + cp = &buffer[MAXLINE+1] - n; + } + if (feof(stdin)) + bsize = 0; + else + bsize = fread(&buffer[MAXLINE+1], 1, BUFSIZE, stdin); + if (bsize < 0) { + error("read error\n"); + exit(EXIT_FAILURE); + } + limit = &buffer[MAXLINE+1+bsize]; + *limit = '\n'; +} +void input_init(int argc, char *argv[]) { + static int inited; + + if (inited) + return; + inited = 1; + main_init(argc, argv); + limit = cp = &buffer[MAXLINE+1]; + bsize = -1; + lineno = 0; + file = NULL; + fillbuf(); + if (cp >= limit) + cp = limit; + nextline(); +} + +/* ident - handle #ident "string" */ +static void ident(void) { + while (*cp != '\n' && *cp != '\0') + cp++; +} + +/* pragma - handle #pragma ref id... */ +static void pragma(void) { + if ((t = gettok()) == ID && strcmp(token, "ref") == 0) + for (;;) { + while (*cp == ' ' || *cp == '\t') + cp++; + if (*cp == '\n' || *cp == 0) + break; + if ((t = gettok()) == ID && tsym) { + tsym->ref++; + use(tsym, src); + } + } +} + +/* resynch - set line number/file name in # n [ "file" ], #pragma, etc. */ +static void resynch(void) { + for (cp++; *cp == ' ' || *cp == '\t'; ) + cp++; + if (limit - cp < MAXLINE) + fillbuf(); + if (strncmp((char *)cp, "pragma", 6) == 0) { + cp += 6; + pragma(); + } else if (strncmp((char *)cp, "ident", 5) == 0) { + cp += 5; + ident(); + } else if (*cp >= '0' && *cp <= '9') { + line: for (lineno = 0; *cp >= '0' && *cp <= '9'; ) + lineno = 10*lineno + *cp++ - '0'; + lineno--; + while (*cp == ' ' || *cp == '\t') + cp++; + if (*cp == '"') { + file = (char *)++cp; + while (*cp && *cp != '"' && *cp != '\n') + cp++; + file = stringn(file, (char *)cp - file); + if (*cp == '\n') + warning("missing \" in preprocessor line\n"); + if (firstfile == 0) + firstfile = file; + } + } else if (strncmp((char *)cp, "line", 4) == 0) { + for (cp += 4; *cp == ' ' || *cp == '\t'; ) + cp++; + if (*cp >= '0' && *cp <= '9') + goto line; + if (Aflag >= 2) + warning("unrecognized control line\n"); + } else if (Aflag >= 2 && *cp != '\n') + warning("unrecognized control line\n"); + while (*cp) + if (*cp++ == '\n') { + if (cp == limit + 1) { + nextline(); + if (cp == limit) + break; + } else + break; + } +} diff --git a/src/cmd/lccom/lburg/gram.y b/src/cmd/lccom/lburg/gram.y new file mode 100644 index 0000000..b756daa --- /dev/null +++ b/src/cmd/lccom/lburg/gram.y @@ -0,0 +1,202 @@ +%{ +#include +#include "lburg.h" +static char rcsid[] = "$Id: gram.y,v 2.5 1997/11/21 18:59:34 drh Exp $"; +/*lint -e616 -e527 -e652 -esym(552,yynerrs) -esym(563,yynewstate,yyerrlab) */ +static int yylineno = 0; +%} +%union { + int n; + char *string; + Tree tree; +} +%term TERMINAL +%term START +%term PPERCENT + +%token ID TEMPLATE CODE +%token INT +%type nonterm cost +%type tree +%% +spec : decls PPERCENT rules { yylineno = 0; } + | decls { yylineno = 0; } + ; + +decls : /* lambda */ + | decls decl + ; + +decl : TERMINAL blist '\n' + | START nonterm '\n' { + if (nonterm($2)->number != 1) + yyerror("redeclaration of the start symbol\n"); + } + | '\n' + | error '\n' { yyerrok; } + ; + +blist : /* lambda */ + | blist ID '=' INT { term($2, $4); } + ; + +rules : /* lambda */ + | rules nonterm ':' tree TEMPLATE cost '\n' { rule($2, $4, $5, $6); } + | rules '\n' + | rules error '\n' { yyerrok; } + ; + +nonterm : ID { nonterm($$ = $1); } + ; + +tree : ID { $$ = tree($1, 0, 0); } + | ID '(' tree ')' { $$ = tree($1, $3, 0); } + | ID '(' tree ',' tree ')' { $$ = tree($1, $3, $5); } + ; + +cost : CODE { if (*$1 == 0) $$ = "0"; } + ; +%% +#include +#include +#include +#include +#include + +int errcnt = 0; +FILE *infp = NULL; +FILE *outfp = NULL; +static char buf[BUFSIZ], *bp = buf; +static int ppercent = 0; +static int code = 0; + +static int get(void) { + if (*bp == 0) { + bp = buf; + *bp = 0; + if (fgets(buf, sizeof buf, infp) == NULL) + return EOF; + yylineno++; + while (buf[0] == '%' && buf[1] == '{' && buf[2] == '\n') { + for (;;) { + if (fgets(buf, sizeof buf, infp) == NULL) { + yywarn("unterminated %{...%}\n"); + return EOF; + } + yylineno++; + if (strcmp(buf, "%}\n") == 0) + break; + fputs(buf, outfp); + } + if (fgets(buf, sizeof buf, infp) == NULL) + return EOF; + yylineno++; + } + } + return *bp++; +} + +void yyerror(char *fmt, ...) { + va_list ap; + + va_start(ap, fmt); + if (yylineno > 0) + fprintf(stderr, "line %d: ", yylineno); + vfprintf(stderr, fmt, ap); + if (fmt[strlen(fmt)-1] != '\n') + fprintf(stderr, "\n"); + errcnt++; + va_end(ap); +} + +int yylex(void) { + int c; + + if (code) { + char *p; + bp += strspn(bp, " \t\f"); + p = strchr(bp, '\n'); + if (p == NULL) + p = strchr(bp, '\n'); + while (p > bp && isspace(p[-1])) + p--; + yylval.string = alloc(p - bp + 1); + strncpy(yylval.string, bp, p - bp); + yylval.string[p - bp] = 0; + bp = p; + code--; + return CODE; + } + while ((c = get()) != EOF) { + switch (c) { + case ' ': case '\f': case '\t': + continue; + case '\n': + case '(': case ')': case ',': + case ':': case '=': + return c; + } + if (c == '%' && *bp == '%') { + bp++; + return ppercent++ ? 0 : PPERCENT; + } else if (c == '%' && strncmp(bp, "term", 4) == 0 + && isspace(bp[4])) { + bp += 4; + return TERMINAL; + } else if (c == '%' && strncmp(bp, "start", 5) == 0 + && isspace(bp[5])) { + bp += 5; + return START; + } else if (c == '"') { + char *p = strchr(bp, '"'); + if (p == NULL) { + yyerror("missing \" in assembler template\n"); + p = strchr(bp, '\n'); + if (p == NULL) + p = strchr(bp, '\0'); + } + assert(p); + yylval.string = alloc(p - bp + 1); + strncpy(yylval.string, bp, p - bp); + yylval.string[p - bp] = 0; + bp = *p == '"' ? p + 1 : p; + code++; + return TEMPLATE; + } else if (isdigit(c)) { + int n = 0; + do { + int d = c - '0'; + if (n > (INT_MAX - d)/10) + yyerror("integer greater than %d\n", INT_MAX); + else + n = 10*n + d; + c = get(); + } while (c != EOF && isdigit(c)); + bp--; + yylval.n = n; + return INT; + } else if (isalpha(c)) { + char *p = bp - 1; + while (isalpha(*bp) || isdigit(*bp) || *bp == '_') + bp++; + yylval.string = alloc(bp - p + 1); + strncpy(yylval.string, p, bp - p); + yylval.string[bp - p] = 0; + return ID; + } else if (isprint(c)) + yyerror("invalid character `%c'\n", c); + else + yyerror("invalid character `\\%03o'\n", (unsigned char)c); + } + return 0; +} + +void yywarn(char *fmt, ...) { + va_list ap; + + va_start(ap, fmt); + if (yylineno > 0) + fprintf(stderr, "line %d: ", yylineno); + fprintf(stderr, "warning: "); + vfprintf(stderr, fmt, ap); +} diff --git a/src/cmd/lccom/lburg/lburg.1 b/src/cmd/lccom/lburg/lburg.1 new file mode 100644 index 0000000..046bcbe --- /dev/null +++ b/src/cmd/lccom/lburg/lburg.1 @@ -0,0 +1,358 @@ +.TH LBURG 1 "local \- 11/30/94" + +.\" $Id: lburg.1,v 2.1 1994/11/30 21:53:18 drh Exp $ + +.SH NAME + +lburg \- lcc's code-generator generator + +.SH SYNOPSIS + +.B lburg + +[ + +.I option + +]... + +[ [ + +.I input + +] + +.I output + +] + +.br + +.SH DESCRIPTION + +.PP + +.I lburg + +reads an lcc-style BURG specification from + +.I input + +and writes a pattern-matching code generator to + +.IR output . + +If + +.I input + +is `\-' or is omitted, + +.I lburg + +reads the standard input; + +If + +.I output + +is `\-' or is omitted, + +.I lburg + +writes to the standard output. + +.PP + +.I lburg + +accepts specifications that conform to the following EBNF grammar. + +Terminals are enclosed in single quotes or are + +given in uppercase, all other symbols are nonterminals or English phrases, + +{X} denotes zero or more instances of X, and [X] denotes an optional X. + +.PP + +.nf + +.RS + +.ft CW + +spec: `%{' configuration `%}' { dcl } `%%' { rule } + + [ `%%' C code ] + + + +dcl: `%start' nonterm + + `%term' { ID `=' INT } + + + +rule: nonterm `:' tree template [ C expression ] + + + +tree: term `(' tree `,' tree `)' + + term `(' tree `)' + + term + + nonterm + + + +nonterm: ID + + + +template: `"' { any character except double quote } `"' + +.RE + +.fi + +.PP + +Specifications are structurally similar to + +.IR yacc 's. + +Text between + +`\f(CW%{\fP' + +and + +`\f(CW%}\fP' + +is called the configuration section; there may be several such segments. + +All are concatenated and copied verbatim into the head of the output. + +Text after the second + +`\f(CW%%\fP', + +if any, is also copied verbatim into the output, at the end. + +.PP + +Specifications consist of declarations, a + +`\f(CW%%\fP' + +separator, and rules. + +Input is line-oriented; each declaration and rule must appear on a separate line, + +and declarations must begin in column 1. + +Declarations declare terminals \(em the operators in subject + +trees \(em and associate a unique, positive external symbol + +number with each one. + +Nonterminals are declared by their presence + +on the left side of rules. The + +\f(CW%start\fP + +declaration optionally declares a nonterminal as the start symbol. + +In the grammar above, + +\f(CWterm\fP + +and + +\f(CWnonterm\fP + +denote identifiers that are terminals and nonterminals. + +.PP + +Rules define tree patterns in a fully parenthesized prefix + +form. Every nonterminal denotes a tree. + +Each operator has a fixed + +arity, which is inferred from the rules in which it is used. + +A chain rule is a rule whose pattern is another nonterminal. + +If no start symbol is declared, the nonterminal defined by the first rule is used. + +.PP + +Each rule ends with an expression that computes the cost of matching + +that rule; omitted costs + +default to zero. Costs of chain rules must be constants. + +.PP + +The configuration section configures the output + +for the trees being parsed and the client's environment. + +As shown, this section must define + +\f(CWNODEPTR_TYPE\fP + +to be a visible typedef symbol for a pointer to a + +node in the subject tree. + +The labeller invokes + +\f(CWOP_LABEL(p)\fP, + +\f(CWLEFT\_CHILD(p)\fP, and + +\f(CWRIGHT\_CHILD(p)\fP + +to read the operator and children from the node pointed to by \f(CWp\fP. + +If the configuration section defines these operations as macros, they are implemented in-line; + +otherwise, they must be implemented as functions. + +.PP + +The matcher + +computes and stores a single integral state in each node of the subject tree. + +The configuration section must define a macro + +\f(CWSTATE_LABEL(p)\fP + +to access the state field of the node pointed to + +by \f(CWp\fP. It must be large enough to hold a pointer, and + +a macro is required because it is used as an lvalue. + +.PP + +.SH OPTIONS + +.TP + +.BI \-p \ prefix + +.br + +.ns + +.TP + +.BI \-p prefix + +Use + +.I prefix + +as the disambiquating prefix for visible names and fields. + +The default is `\f(CW_\fP'. + +.TP + +.B \-T + +Arrange for + +.sp + +.nf + +.ft CW + + void _trace(NODEPTR_TYPE p, int eruleno, + + int cost, int bestcost); + +.sp + +.fi + +.ft R + +to be called at each successful match. + +\f(CWp\fP + +identifies the node and + +\f(CWeruleno\fP + +identifies the matching rule; the rules are numbered + +beginning at 1 in the order they appear in the input. + +\f(CWcost\fP + +is the cost of the match and + +\f(CWbestcost\fP + +is the cost of the best previous match. The current match + +wins only if + +\f(CWcost\fP + +is less than \f(CWbestcost\fP. + +32767 represents the infinite cost of no previous match. + +\f(CW_trace\fP must be declared in the configuration section. + +.SH "SEE ALSO" + +.IR lcc (1) + +.PP + +C. W. Fraser and D. R. Hanson, + +.IR A Retargetable C Compiler: Design and Implementation , + +Benjamin/Cummings, Redwood City, CA, 1995, + +ISBN 0-8053-1670-1. Chapter 14. + +.PP + +C. W. Fraser, D. R. Hanson and T. A. Proebsting, + +`Engineering a simple, efficient code generator generator,' + +.I + +ACM Letters on Programming Languages and Systems + +.BR 1 , + +3 (Sep. 1992), 213-226. + +.br + +.SH BUGS + +Mail bug reports along with the shortest input + +that exposes them to drh@cs.princeton.edu. + diff --git a/src/cmd/lccom/lburg/lburg.c b/src/cmd/lccom/lburg/lburg.c new file mode 100644 index 0000000..b73151e --- /dev/null +++ b/src/cmd/lccom/lburg/lburg.c @@ -0,0 +1,682 @@ +#include +#include +#include +#include +#include +#include +#include +#include "lburg.h" + +static char rcsid[] = "$Id: lburg.c,v 2.10 2002/03/08 18:45:21 drh Exp $"; +static char *prefix = ""; +static int Tflag = 0; +static int nflag = 0; +static int ntnumber = 0; +static Nonterm start = 0; +static Term terms; +static Nonterm nts; +static Rule rules; +static int nrules; + +static struct block { + struct block *link; +} *memlist; /* list of allocated blocks */ + +static char *stringf(char *fmt, ...); +static void print(char *fmt, ...); +static void ckreach(Nonterm p); +static void emitclosure(Nonterm nts); +static void emitcost(Tree t, char *v); +static void emitdefs(Nonterm nts, int ntnumber); +static void emitheader(void); +static void emitkids(Rule rules, int nrules); +static void emitnts(Rule rules, int nrules); +static void emitrecalc(char *pre, Term root, Term kid); +static void emitrecord(char *pre, Rule r, char *c, int cost); +static void emitrule(Nonterm nts); +static void emitlabel(Term terms, Nonterm start, int ntnumber); +static void emitstring(Rule rules); +static void emitstruct(Nonterm nts, int ntnumber); +static void emittest(Tree t, char *v, char *suffix); + +int main(int argc, char *argv[]) +{ + int c, i; + Nonterm p; + + for (i = 1; i < argc; i++) + if (strcmp(argv[i], "-T") == 0) + Tflag = 1; + else if (strcmp(argv[i], "-n") == 0) + nflag = 1; + else if (strncmp(argv[i], "-p", 2) == 0 && argv[i][2]) + prefix = &argv[i][2]; + else if (strncmp(argv[i], "-p", 2) == 0 && i + 1 < argc) + prefix = argv[++i]; + else if (*argv[i] == '-' && argv[i][1]) { + yyerror("usage: %s [-T | -p prefix]... [ [ input ] output ] \n", + argv[0]); + exit(1); + } else if (infp == NULL) { + if (strcmp(argv[i], "-") == 0) + infp = stdin; + else if ((infp = fopen(argv[i], "r")) == NULL) { + yyerror("%s: can't read `%s'\n", argv[0], argv[i]); + exit(1); + } + } else if (outfp == NULL) { + if (strcmp(argv[i], "-") == 0) + outfp = stdout; + if ((outfp = fopen(argv[i], "w")) == NULL) { + yyerror("%s: can't write `%s'\n", argv[0], argv[i]); + exit(1); + } + } + if (infp == NULL) + infp = stdin; + if (outfp == NULL) + outfp = stdout; + yyparse(); + if (start) + ckreach(start); + for (p = nts; p; p = p->link) { + if (p->rules == NULL) + yyerror("undefined nonterminal `%s'\n", p->name); + if (!p->reached) + yyerror("can't reach nonterminal `%s'\n", p->name); + } + emitheader(); + emitdefs(nts, ntnumber); + emitstruct(nts, ntnumber); + emitnts(rules, nrules); + if (! nflag) + emitstring(rules); + emitrule(nts); + emitclosure(nts); + if (start) + emitlabel(terms, start, ntnumber); + emitkids(rules, nrules); + if (!feof(infp)) + while ((c = getc(infp)) != EOF) + putc(c, outfp); + while (memlist) { /* for purify */ + struct block *q = memlist->link; + free(memlist); + memlist = q; + } + return errcnt > 0; +} + +/* alloc - allocate nbytes or issue fatal error */ +void *alloc(int nbytes) { + struct block *p = calloc(1, sizeof *p + nbytes); + + if (p == NULL) { + yyerror("out of memory\n"); + exit(1); + } + p->link = memlist; + memlist = p; + return p + 1; +} + +/* stringf - format and save a string */ +static char *stringf(char *fmt, ...) { + va_list ap; + char buf[512]; + + va_start(ap, fmt); + vsprintf(buf, fmt, ap); + va_end(ap); + return strcpy(alloc(strlen(buf) + 1), buf); +} + +struct entry { + union { + char *name; + struct term t; + struct nonterm nt; + } sym; + struct entry *link; +} *table[211]; +#define HASHSIZE (sizeof table/sizeof table[0]) + +/* hash - return hash number for str */ +static unsigned hash(char *str) { + unsigned h = 0; + + while (*str) + h = (h<<1) + *str++; + return h; +} + +/* lookup - lookup symbol name */ +static void *lookup(char *name) { + struct entry *p = table[hash(name)%HASHSIZE]; + + for ( ; p; p = p->link) + if (strcmp(name, p->sym.name) == 0) + return &p->sym; + return 0; +} + +/* install - install symbol name */ +static void *install(char *name) { + struct entry *p = alloc(sizeof *p); + int i = hash(name)%HASHSIZE; + + p->sym.name = name; + p->link = table[i]; + table[i] = p; + return &p->sym; +} + +/* nonterm - create a new terminal id, if necessary */ +Nonterm nonterm(char *id) { + Nonterm p = lookup(id), *q = &nts; + + if (p && p->kind == NONTERM) + return p; + if (p && p->kind == TERM) + yyerror("`%s' is a terminal\n", id); + p = install(id); + p->kind = NONTERM; + p->number = ++ntnumber; + if (p->number == 1) + start = p; + while (*q && (*q)->number < p->number) + q = &(*q)->link; + assert(*q == 0 || (*q)->number != p->number); + p->link = *q; + *q = p; + return p; +} + +/* term - create a new terminal id with external symbol number esn */ +Term term(char *id, int esn) { + Term p = lookup(id), *q = &terms; + + if (p) + yyerror("redefinition of terminal `%s'\n", id); + else + p = install(id); + p->kind = TERM; + p->esn = esn; + p->arity = -1; + while (*q && (*q)->esn < p->esn) + q = &(*q)->link; + if (*q && (*q)->esn == p->esn) + yyerror("duplicate external symbol number `%s=%d'\n", + p->name, p->esn); + p->link = *q; + *q = p; + return p; +} + +/* tree - create & initialize a tree node with the given fields */ +Tree tree(char *id, Tree left, Tree right) { + Tree t = alloc(sizeof *t); + Term p = lookup(id); + int arity = 0; + + if (left && right) + arity = 2; + else if (left) + arity = 1; + if (p == NULL && arity > 0) { + yyerror("undefined terminal `%s'\n", id); + p = term(id, -1); + } else if (p == NULL && arity == 0) + p = (Term)nonterm(id); + else if (p && p->kind == NONTERM && arity > 0) { + yyerror("`%s' is a nonterminal\n", id); + p = term(id, -1); + } + if (p->kind == TERM && p->arity == -1) + p->arity = arity; + if (p->kind == TERM && arity != p->arity) + yyerror("inconsistent arity for terminal `%s'\n", id); + t->op = p; + t->nterms = p->kind == TERM; + if ((t->left = left) != NULL) + t->nterms += left->nterms; + if ((t->right = right) != NULL) + t->nterms += right->nterms; + return t; +} + +/* rule - create & initialize a rule with the given fields */ +Rule rule(char *id, Tree pattern, char *template, char *code) { + Rule r = alloc(sizeof *r), *q; + Term p = pattern->op; + char *end; + + r->lhs = nonterm(id); + r->packed = ++r->lhs->lhscount; + for (q = &r->lhs->rules; *q; q = &(*q)->decode) + ; + *q = r; + r->pattern = pattern; + r->ern = ++nrules; + r->template = template; + r->code = code; + r->cost = strtol(code, &end, 10); + if (*end) { + r->cost = -1; + r->code = stringf("(%s)", code); + } + if (p->kind == TERM) { + for (q = &p->rules; *q; q = &(*q)->next) + ; + *q = r; + } else if (pattern->left == NULL && pattern->right == NULL) { + Nonterm p = pattern->op; + r->chain = p->chain; + p->chain = r; + if (r->cost == -1) + yyerror("illegal nonconstant cost `%s'\n", code); + } + for (q = &rules; *q; q = &(*q)->link) + ; + r->link = *q; + *q = r; + return r; +} + +/* print - formatted output */ +static void print(char *fmt, ...) { + va_list ap; + + va_start(ap, fmt); + for ( ; *fmt; fmt++) + if (*fmt == '%') + switch (*++fmt) { + case 'd': fprintf(outfp, "%d", va_arg(ap, int)); break; + case 's': fputs(va_arg(ap, char *), outfp); break; + case 'P': fprintf(outfp, "%s_", prefix); break; + case 'T': { + Tree t = va_arg(ap, Tree); + print("%S", t->op); + if (t->left && t->right) + print("(%T,%T)", t->left, t->right); + else if (t->left) + print("(%T)", t->left); + break; + } + case 'R': { + Rule r = va_arg(ap, Rule); + print("%S: %T", r->lhs, r->pattern); + break; + } + case 'S': { + Term t = va_arg(ap, Term); + fputs(t->name, outfp); + break; + } + case '1': case '2': case '3': case '4': case '5': { + int n = *fmt - '0'; + while (n-- > 0) + putc('\t', outfp); + break; + } + default: putc(*fmt, outfp); break; + } + else + putc(*fmt, outfp); + va_end(ap); +} + +/* reach - mark all nonterminals in tree t as reachable */ +static void reach(Tree t) { + Nonterm p = t->op; + + if (p->kind == NONTERM) + if (!p->reached) + ckreach(p); + if (t->left) + reach(t->left); + if (t->right) + reach(t->right); +} + +/* ckreach - mark all nonterminals reachable from p */ +static void ckreach(Nonterm p) { + Rule r; + + p->reached = 1; + for (r = p->rules; r; r = r->decode) + reach(r->pattern); +} + +/* emitcase - emit one case in function state */ +static void emitcase(Term p, int ntnumber) { + Rule r; + + print("%1case %d: /* %S */\n", p->esn, p); + switch (p->arity) { + case 0: case -1: + break; + case 1: + print("%2%Plabel(LEFT_CHILD(a));\n"); + break; + case 2: + print("%2%Plabel(LEFT_CHILD(a));\n"); + print("%2%Plabel(RIGHT_CHILD(a));\n"); + break; + default: assert(0); + } + for (r = p->rules; r; r = r->next) { + char *indent = "\t\t\0"; + switch (p->arity) { + case 0: case -1: + print("%2/* %R */\n", r); + if (r->cost == -1) { + print("%2c = %s;\n", r->code); + emitrecord("\t\t", r, "c", 0); + } else + emitrecord("\t\t", r, r->code, 0); + break; + case 1: + if (r->pattern->nterms > 1) { + print("%2if (%1/* %R */\n", r); + emittest(r->pattern->left, "LEFT_CHILD(a)", " "); + print("%2) {\n"); + indent = "\t\t\t"; + } else + print("%2/* %R */\n", r); + if (r->pattern->nterms == 2 && r->pattern->left + && r->pattern->right == NULL) + emitrecalc(indent, r->pattern->op, r->pattern->left->op); + print("%sc = ", indent); + emitcost(r->pattern->left, "LEFT_CHILD(a)"); + print("%s;\n", r->code); + emitrecord(indent, r, "c", 0); + if (indent[2]) + print("%2}\n"); + break; + case 2: + if (r->pattern->nterms > 1) { + print("%2if (%1/* %R */\n", r); + emittest(r->pattern->left, "LEFT_CHILD(a)", + r->pattern->right->nterms ? " && " : " "); + emittest(r->pattern->right, "RIGHT_CHILD(a)", " "); + print("%2) {\n"); + indent = "\t\t\t"; + } else + print("%2/* %R */\n", r); + print("%sc = ", indent); + emitcost(r->pattern->left, "LEFT_CHILD(a)"); + emitcost(r->pattern->right, "RIGHT_CHILD(a)"); + print("%s;\n", r->code); + emitrecord(indent, r, "c", 0); + if (indent[2]) + print("%2}\n"); + break; + default: assert(0); + } + } + print("%2break;\n"); +} + +/* emitclosure - emit the closure functions */ +static void emitclosure(Nonterm nts) { + Nonterm p; + + for (p = nts; p; p = p->link) + if (p->chain) + print("static void %Pclosure_%S(NODEPTR_TYPE, int);\n", p); + print("\n"); + for (p = nts; p; p = p->link) + if (p->chain) { + Rule r; + print("static void %Pclosure_%S(NODEPTR_TYPE a, int c) {\n" +"%1struct %Pstate *p = STATE_LABEL(a);\n", p); + for (r = p->chain; r; r = r->chain) + emitrecord("\t", r, "c", r->cost); + print("}\n\n"); + } +} + +/* emitcost - emit cost computation for tree t */ +static void emitcost(Tree t, char *v) { + Nonterm p = t->op; + + if (p->kind == TERM) { + if (t->left) + emitcost(t->left, stringf("LEFT_CHILD(%s)", v)); + if (t->right) + emitcost(t->right, stringf("RIGHT_CHILD(%s)", v)); + } else + print("((struct %Pstate *)(%s->x.state))->cost[%P%S_NT] + ", v, p); +} + +/* emitdefs - emit nonterminal defines and data structures */ +static void emitdefs(Nonterm nts, int ntnumber) { + Nonterm p; + + for (p = nts; p; p = p->link) + print("#define %P%S_NT %d\n", p, p->number); + print("\n"); + if (! nflag) { + print("static char *%Pntname[] = {\n%10,\n"); + for (p = nts; p; p = p->link) + print("%1\"%S\",\n", p); + print("%10\n};\n\n"); + } +} + +/* emitheader - emit initial definitions */ +static void emitheader(void) { + time_t timer = time(NULL); + + print("/*\ngenerated at %sby %s\n*/\n", ctime(&timer), rcsid); + print("static void %Pkids(NODEPTR_TYPE, int, NODEPTR_TYPE[]);\n"); + print("static void %Plabel(NODEPTR_TYPE);\n"); + print("static int %Prule(void*, int);\n\n"); +} + +/* computekids - compute paths to kids in tree t */ +static char *computekids(Tree t, char *v, char *bp, int *ip) { + Term p = t->op; + + if (p->kind == NONTERM) { + sprintf(bp, "\t\tkids[%d] = %s;\n", (*ip)++, v); + bp += strlen(bp); + } else if (p->arity > 0) { + bp = computekids(t->left, stringf("LEFT_CHILD(%s)", v), bp, ip); + if (p->arity == 2) + bp = computekids(t->right, stringf("RIGHT_CHILD(%s)", v), bp, ip); + } + return bp; +} + +/* emitkids - emit _kids */ +static void emitkids(Rule rules, int nrules) { + int i; + Rule r, *rc = alloc((nrules + 1 + 1)*sizeof *rc); + char **str = alloc((nrules + 1 + 1)*sizeof *str); + + for (i = 0, r = rules; r; r = r->link) { + int j = 0; + char buf[1024], *bp = buf; + *computekids(r->pattern, "p", bp, &j) = 0; + for (j = 0; str[j] && strcmp(str[j], buf); j++) + ; + if (str[j] == NULL) + str[j] = strcpy(alloc(strlen(buf) + 1), buf); + r->kids = rc[j]; + rc[j] = r; + } + print("static void %Pkids(NODEPTR_TYPE p, int eruleno, NODEPTR_TYPE kids[]) {\n" +"%1if (!p)\n%2fatal(\"%Pkids\", \"Null tree\\n\", 0);\n" +"%1if (!kids)\n%2fatal(\"%Pkids\", \"Null kids\\n\", 0);\n" +"%1switch (eruleno) {\n"); + for (i = 0; (r = rc[i]) != NULL; i++) { + for ( ; r; r = r->kids) + print("%1case %d: /* %R */\n", r->ern, r); + print("%s%2break;\n", str[i]); + } + print("%1default:\n%2fatal(\"%Pkids\", \"Bad rule number %%d\\n\", eruleno);\n%1}\n}\n\n"); +} + +/* emitlabel - emit label function */ +static void emitlabel(Term terms, Nonterm start, int ntnumber) { + int i; + Term p; + + print("static void %Plabel(NODEPTR_TYPE a) {\n%1int c;\n" +"%1struct %Pstate *p;\n\n" +"%1if (!a)\n%2fatal(\"%Plabel\", \"Null tree\\n\", 0);\n"); + print("%1STATE_LABEL(a) = p = allocate(sizeof *p, FUNC);\n" +"%1p->rule._stmt = 0;\n"); + for (i = 1; i <= ntnumber; i++) + print("%1p->cost[%d] =\n", i); + print("%20x7fff;\n%1switch (OP_LABEL(a)) {\n"); + for (p = terms; p; p = p->link) + emitcase(p, ntnumber); + print("%1default:\n" +"%2fatal(\"%Plabel\", \"Bad terminal %%d\\n\", OP_LABEL(a));\n%1}\n}\n\n"); +} + +/* computents - fill in bp with _nts vector for tree t */ +static char *computents(Tree t, char *bp) { + if (t) { + Nonterm p = t->op; + if (p->kind == NONTERM) { + sprintf(bp, "%s_%s_NT, ", prefix, p->name); + bp += strlen(bp); + } else + bp = computents(t->right, computents(t->left, bp)); + } + return bp; +} + +/* emitnts - emit _nts ragged array */ +static void emitnts(Rule rules, int nrules) { + Rule r; + int i, j, *nts = alloc((nrules + 1)*sizeof *nts); + char **str = alloc((nrules + 1)*sizeof *str); + + for (i = 0, r = rules; r; r = r->link) { + char buf[1024]; + *computents(r->pattern, buf) = 0; + for (j = 0; str[j] && strcmp(str[j], buf); j++) + ; + if (str[j] == NULL) { + print("static short %Pnts_%d[] = { %s0 };\n", j, buf); + str[j] = strcpy(alloc(strlen(buf) + 1), buf); + } + nts[i++] = j; + } + print("\nstatic short *%Pnts[] = {\n"); + for (i = j = 0, r = rules; r; r = r->link) { + for ( ; j < r->ern; j++) + print("%10,%1/* %d */\n", j); + print("%1%Pnts_%d,%1/* %d */\n", nts[i++], j++); + } + print("};\n\n"); +} + +/* emitrecalc - emit code that tests for recalculation of INDIR?(VREGP) */ +static void emitrecalc(char *pre, Term root, Term kid) { + if (root->kind == TERM && strncmp(root->name, "INDIR", 5) == 0 + && kid->kind == TERM && strcmp(kid->name, "VREGP" ) == 0) { + Nonterm p; + print("%sif (mayrecalc(a)) {\n", pre); + print("%s%1struct %Pstate *q = a->syms[RX]->u.t.cse->x.state;\n", pre); + for (p = nts; p; p = p->link) { + print("%s%1if (q->cost[%P%S_NT] == 0) {\n", pre, p); + print("%s%2p->cost[%P%S_NT] = 0;\n", pre, p); + print("%s%2p->rule.%P%S = q->rule.%P%S;\n", pre, p, p); + print("%s%1}\n", pre); + } + print("%s}\n", pre); + } +} + +/* emitrecord - emit code that tests for a winning match of rule r */ +static void emitrecord(char *pre, Rule r, char *c, int cost) { + if (Tflag) + print("%s%Ptrace(a, %d, %s + %d, p->cost[%P%S_NT]);\n", + pre, r->ern, c, cost, r->lhs); + print("%sif (", pre); + print("%s + %d < p->cost[%P%S_NT]) {\n" +"%s%1p->cost[%P%S_NT] = %s + %d;\n%s%1p->rule.%P%S = %d;\n", + c, cost, r->lhs, pre, r->lhs, c, cost, pre, r->lhs, + r->packed); + if (r->lhs->chain) + print("%s%1%Pclosure_%S(a, %s + %d);\n", pre, r->lhs, c, cost); + print("%s}\n", pre); +} + +/* emitrule - emit decoding vectors and _rule */ +static void emitrule(Nonterm nts) { + Nonterm p; + + for (p = nts; p; p = p->link) { + Rule r; + print("static short %Pdecode_%S[] = {\n%10,\n", p); + for (r = p->rules; r; r = r->decode) + print("%1%d,\n", r->ern); + print("};\n\n"); + } + print("static int %Prule(void *state, int goalnt) {\n" +"%1if (goalnt < 1 || goalnt > %d)\n%2fatal(\"%Prule\", \"Bad goal nonterminal %%d\\n\", goalnt);\n" +"%1if (!state)\n%2return 0;\n%1switch (goalnt) {\n", ntnumber); + for (p = nts; p; p = p->link) + print("%1case %P%S_NT:" +"%1return %Pdecode_%S[((struct %Pstate *)state)->rule.%P%S];\n", p, p, p); + print("%1default:\n%2fatal(\"%Prule\", \"Bad goal nonterminal %%d\\n\", goalnt);\n%2return 0;\n%1}\n}\n\n"); +} + +/* emitstring - emit arrays of templates, instruction flags, and rules */ +static void emitstring(Rule rules) { + Rule r; + + print("static char *%Ptemplates[] = {\n"); + print("/* 0 */%10,\n"); + for (r = rules; r; r = r->link) + print("/* %d */%1\"%s\",%1/* %R */\n", r->ern, r->template, r); + print("};\n"); + print("\nstatic char %Pisinstruction[] = {\n"); + print("/* 0 */%10,\n"); + for (r = rules; r; r = r->link) { + int len = strlen(r->template); + print("/* %d */%1%d,%1/* %s */\n", r->ern, + len >= 2 && r->template[len-2] == '\\' && r->template[len-1] == 'n', + r->template); + } + print("};\n"); + print("\nstatic char *%Pstring[] = {\n"); + print("/* 0 */%10,\n"); + for (r = rules; r; r = r->link) + print("/* %d */%1\"%R\",\n", r->ern, r); + print("};\n\n"); +} + +/* emitstruct - emit the definition of the state structure */ +static void emitstruct(Nonterm nts, int ntnumber) { + print("struct %Pstate {\n%1short cost[%d];\n%1struct {\n", ntnumber + 1); + for ( ; nts; nts = nts->link) { + int n = 1, m = nts->lhscount; + while ((m >>= 1) != 0) + n++; + print("%2unsigned int %P%S:%d;\n", nts, n); + } + print("%1} rule;\n};\n\n"); +} + +/* emittest - emit clause for testing a match */ +static void emittest(Tree t, char *v, char *suffix) { + Term p = t->op; + + if (p->kind == TERM) { + print("%3%s->op == %d%s/* %S */\n", v, p->esn, + t->nterms > 1 ? " && " : suffix, p); + if (t->left) + emittest(t->left, stringf("LEFT_CHILD(%s)", v), + t->right && t->right->nterms ? " && " : suffix); + if (t->right) + emittest(t->right, stringf("RIGHT_CHILD(%s)", v), suffix); + } +} diff --git a/src/cmd/lccom/lburg/lburg.h b/src/cmd/lccom/lburg/lburg.h new file mode 100644 index 0000000..75dbe79 --- /dev/null +++ b/src/cmd/lccom/lburg/lburg.h @@ -0,0 +1,132 @@ +#ifndef BURG_INCLUDED + +#define BURG_INCLUDED + + + +/* $Id: lburg.h,v 2.1 1994/11/30 21:53:18 drh Exp $ */ + +/* iburg.c: */ + +extern void *alloc(int nbytes); + + + +typedef enum { TERM=1, NONTERM } Kind; + +typedef struct rule *Rule; + +typedef struct term *Term; + +struct term { /* terminals: */ + + char *name; /* terminal name */ + + Kind kind; /* TERM */ + + int esn; /* external symbol number */ + + int arity; /* operator arity */ + + Term link; /* next terminal in esn order */ + + Rule rules; /* rules whose pattern starts with term */ + +}; + + + +typedef struct nonterm *Nonterm; + +struct nonterm { /* nonterminals: */ + + char *name; /* nonterminal name */ + + Kind kind; /* NONTERM */ + + int number; /* identifying number */ + + int lhscount; /* # times nt appears in a rule lhs */ + + int reached; /* 1 iff reached from start nonterminal */ + + Rule rules; /* rules w/nonterminal on lhs */ + + Rule chain; /* chain rules w/nonterminal on rhs */ + + Nonterm link; /* next terminal in number order */ + +}; + +extern Nonterm nonterm(char *id); + +extern Term term(char *id, int esn); + + + +typedef struct tree *Tree; + +struct tree { /* tree patterns: */ + + void *op; /* a terminal or nonterminal */ + + Tree left, right; /* operands */ + + int nterms; /* number of terminal nodes in this tree */ + +}; + +extern Tree tree(char *op, Tree left, Tree right); + + + +struct rule { /* rules: */ + + Nonterm lhs; /* lefthand side nonterminal */ + + Tree pattern; /* rule pattern */ + + int ern; /* external rule number */ + + int packed; /* packed external rule number */ + + int cost; /* cost, if a constant */ + + char *code; /* cost, if an expression */ + + char *template; /* assembler template */ + + Rule link; /* next rule in ern order */ + + Rule next; /* next rule with same pattern root */ + + Rule chain; /* next chain rule with same rhs */ + + Rule decode; /* next rule with same lhs */ + + Rule kids; /* next rule with same _kids pattern */ + +}; + +extern Rule rule(char *id, Tree pattern, char *template, char *code); + + + +/* gram.y: */ + +void yyerror(char *fmt, ...); + +int yyparse(void); + +void yywarn(char *fmt, ...); + +extern int errcnt; + +extern FILE *infp; + +extern FILE *outfp; + + + +#endif + diff --git a/src/cmd/lccom/lex.c b/src/cmd/lccom/lex.c new file mode 100644 index 0000000..d9401a5 --- /dev/null +++ b/src/cmd/lccom/lex.c @@ -0,0 +1,930 @@ +#include "c.h" +#include +#include + +#define MAXTOKEN 32 + +enum { BLANK=01, NEWLINE=02, LETTER=04, + DIGIT=010, HEX=020, OTHER=040 }; + +static unsigned char map[256] = { /* 000 nul */ 0, + /* 001 soh */ 0, + /* 002 stx */ 0, + /* 003 etx */ 0, + /* 004 eot */ 0, + /* 005 enq */ 0, + /* 006 ack */ 0, + /* 007 bel */ 0, + /* 010 bs */ 0, + /* 011 ht */ BLANK, + /* 012 nl */ NEWLINE, + /* 013 vt */ BLANK, + /* 014 ff */ BLANK, + /* 015 cr */ 0, + /* 016 so */ 0, + /* 017 si */ 0, + /* 020 dle */ 0, + /* 021 dc1 */ 0, + /* 022 dc2 */ 0, + /* 023 dc3 */ 0, + /* 024 dc4 */ 0, + /* 025 nak */ 0, + /* 026 syn */ 0, + /* 027 etb */ 0, + /* 030 can */ 0, + /* 031 em */ 0, + /* 032 sub */ 0, + /* 033 esc */ 0, + /* 034 fs */ 0, + /* 035 gs */ 0, + /* 036 rs */ 0, + /* 037 us */ 0, + /* 040 sp */ BLANK, + /* 041 ! */ OTHER, + /* 042 " */ OTHER, + /* 043 # */ OTHER, + /* 044 $ */ 0, + /* 045 % */ OTHER, + /* 046 & */ OTHER, + /* 047 ' */ OTHER, + /* 050 ( */ OTHER, + /* 051 ) */ OTHER, + /* 052 * */ OTHER, + /* 053 + */ OTHER, + /* 054 , */ OTHER, + /* 055 - */ OTHER, + /* 056 . */ OTHER, + /* 057 / */ OTHER, + /* 060 0 */ DIGIT, + /* 061 1 */ DIGIT, + /* 062 2 */ DIGIT, + /* 063 3 */ DIGIT, + /* 064 4 */ DIGIT, + /* 065 5 */ DIGIT, + /* 066 6 */ DIGIT, + /* 067 7 */ DIGIT, + /* 070 8 */ DIGIT, + /* 071 9 */ DIGIT, + /* 072 : */ OTHER, + /* 073 ; */ OTHER, + /* 074 < */ OTHER, + /* 075 = */ OTHER, + /* 076 > */ OTHER, + /* 077 ? */ OTHER, + /* 100 @ */ 0, + /* 101 A */ LETTER|HEX, + /* 102 B */ LETTER|HEX, + /* 103 C */ LETTER|HEX, + /* 104 D */ LETTER|HEX, + /* 105 E */ LETTER|HEX, + /* 106 F */ LETTER|HEX, + /* 107 G */ LETTER, + /* 110 H */ LETTER, + /* 111 I */ LETTER, + /* 112 J */ LETTER, + /* 113 K */ LETTER, + /* 114 L */ LETTER, + /* 115 M */ LETTER, + /* 116 N */ LETTER, + /* 117 O */ LETTER, + /* 120 P */ LETTER, + /* 121 Q */ LETTER, + /* 122 R */ LETTER, + /* 123 S */ LETTER, + /* 124 T */ LETTER, + /* 125 U */ LETTER, + /* 126 V */ LETTER, + /* 127 W */ LETTER, + /* 130 X */ LETTER, + /* 131 Y */ LETTER, + /* 132 Z */ LETTER, + /* 133 [ */ OTHER, + /* 134 \ */ OTHER, + /* 135 ] */ OTHER, + /* 136 ^ */ OTHER, + /* 137 _ */ LETTER, + /* 140 ` */ 0, + /* 141 a */ LETTER|HEX, + /* 142 b */ LETTER|HEX, + /* 143 c */ LETTER|HEX, + /* 144 d */ LETTER|HEX, + /* 145 e */ LETTER|HEX, + /* 146 f */ LETTER|HEX, + /* 147 g */ LETTER, + /* 150 h */ LETTER, + /* 151 i */ LETTER, + /* 152 j */ LETTER, + /* 153 k */ LETTER, + /* 154 l */ LETTER, + /* 155 m */ LETTER, + /* 156 n */ LETTER, + /* 157 o */ LETTER, + /* 160 p */ LETTER, + /* 161 q */ LETTER, + /* 162 r */ LETTER, + /* 163 s */ LETTER, + /* 164 t */ LETTER, + /* 165 u */ LETTER, + /* 166 v */ LETTER, + /* 167 w */ LETTER, + /* 170 x */ LETTER, + /* 171 y */ LETTER, + /* 172 z */ LETTER, + /* 173 { */ OTHER, + /* 174 | */ OTHER, + /* 175 } */ OTHER, + /* 176 ~ */ OTHER, }; +static struct symbol tval; +static char cbuf[BUFSIZE+1]; +static unsigned int wcbuf[BUFSIZE+1]; + +Coordinate src; /* current source coordinate */ +int t; +char *token; /* current token */ +Symbol tsym; /* symbol table entry for current token */ + +static void *cput(int c, void *cl); +static void *wcput(int c, void *cl); +static void *scon(int q, void *put(int c, void *cl), void *cl); +static int backslash(int q); +static Symbol fcon(void); +static Symbol icon(unsigned long, int, int); +static void ppnumber(char *); + +int gettok(void) { + for (;;) { + register unsigned char *rcp = cp; + while (map[*rcp]&BLANK) + rcp++; + if (limit - rcp < MAXTOKEN) { + cp = rcp; + fillbuf(); + rcp = cp; + } + src.file = file; + src.x = (char *)rcp - line; + src.y = lineno; + cp = rcp + 1; + switch (*rcp++) { + case '/': if (*rcp == '*') { + int c = 0; + for (rcp++; *rcp != '/' || c != '*'; ) + if (map[*rcp]&NEWLINE) { + if (rcp < limit) + c = *rcp; + cp = rcp + 1; + nextline(); + rcp = cp; + if (rcp == limit) + break; + } else + c = *rcp++; + if (rcp < limit) + rcp++; + else + error("unclosed comment\n"); + cp = rcp; + continue; + } + return '/'; + case '<': + if (*rcp == '=') return cp++, LEQ; + if (*rcp == '<') return cp++, LSHIFT; + return '<'; + case '>': + if (*rcp == '=') return cp++, GEQ; + if (*rcp == '>') return cp++, RSHIFT; + return '>'; + case '-': + if (*rcp == '>') return cp++, DEREF; + if (*rcp == '-') return cp++, DECR; + return '-'; + case '=': return *rcp == '=' ? cp++, EQL : '='; + case '!': return *rcp == '=' ? cp++, NEQ : '!'; + case '|': return *rcp == '|' ? cp++, OROR : '|'; + case '&': return *rcp == '&' ? cp++, ANDAND : '&'; + case '+': return *rcp == '+' ? cp++, INCR : '+'; + case ';': case ',': case ':': + case '*': case '~': case '%': case '^': case '?': + case '[': case ']': case '{': case '}': case '(': case ')': + return rcp[-1]; + case '\n': case '\v': case '\r': case '\f': + nextline(); + if (cp == limit) { + tsym = NULL; + return EOI; + } + continue; + + case 'i': + if (rcp[0] == 'f' + && !(map[rcp[1]]&(DIGIT|LETTER))) { + cp = rcp + 1; + return IF; + } + if (rcp[0] == 'n' + && rcp[1] == 't' + && !(map[rcp[2]]&(DIGIT|LETTER))) { + cp = rcp + 2; + tsym = inttype->u.sym; + return INT; + } + goto id; + case 'h': case 'j': case 'k': case 'm': case 'n': case 'o': + case 'p': case 'q': 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 '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': + id: + if (limit - rcp < MAXLINE) { + cp = rcp - 1; + fillbuf(); + rcp = ++cp; + } + assert(cp == rcp); + token = (char *)rcp - 1; + while (map[*rcp]&(DIGIT|LETTER)) + rcp++; + token = stringn(token, (char *)rcp - token); + tsym = lookup(token, identifiers); + cp = rcp; + return ID; + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': { + unsigned long n = 0; + if (limit - rcp < MAXLINE) { + cp = rcp - 1; + fillbuf(); + rcp = ++cp; + } + assert(cp == rcp); + token = (char *)rcp - 1; + if (*token == '0' && (*rcp == 'x' || *rcp == 'X')) { + int d, overflow = 0; + while (*++rcp) { + if (map[*rcp]&DIGIT) + d = *rcp - '0'; + else if (*rcp >= 'a' && *rcp <= 'f') + d = *rcp - 'a' + 10; + else if (*rcp >= 'A' && *rcp <= 'F') + d = *rcp - 'A' + 10; + else + break; + if (n&~(~0UL >> 4)) + overflow = 1; + else + n = (n<<4) + d; + } + if ((char *)rcp - token <= 2) + error("invalid hexadecimal constant `%S'\n", token, (char *)rcp-token); + cp = rcp; + tsym = icon(n, overflow, 16); + } else if (*token == '0') { + int err = 0, overflow = 0; + for ( ; map[*rcp]&DIGIT; rcp++) { + if (*rcp == '8' || *rcp == '9') + err = 1; + if (n&~(~0UL >> 3)) + overflow = 1; + else + n = (n<<3) + (*rcp - '0'); + } + if (*rcp == '.' || *rcp == 'e' || *rcp == 'E') { + cp = rcp; + tsym = fcon(); + return FCON; + } + cp = rcp; + tsym = icon(n, overflow, 8); + if (err) + error("invalid octal constant `%S'\n", token, (char*)cp-token); + } else { + int overflow = 0; + for (n = *token - '0'; map[*rcp]&DIGIT; ) { + int d = *rcp++ - '0'; + if (n > (ULONG_MAX - d)/10) + overflow = 1; + else + n = 10*n + d; + } + if (*rcp == '.' || *rcp == 'e' || *rcp == 'E') { + cp = rcp; + tsym = fcon(); + return FCON; + } + cp = rcp; + tsym = icon(n, overflow, 10); + } + return ICON; + } + case '.': + if (rcp[0] == '.' && rcp[1] == '.') { + cp += 2; + return ELLIPSIS; + } + if ((map[*rcp]&DIGIT) == 0) + return '.'; + if (limit - rcp < MAXLINE) { + cp = rcp - 1; + fillbuf(); + rcp = ++cp; + } + assert(cp == rcp); + cp = rcp - 1; + token = (char *)cp; + tsym = fcon(); + return FCON; + case 'L': + if (*rcp == '\'') { + unsigned int *s = scon(*cp, wcput, wcbuf); + if (s - wcbuf > 2) + warning("excess characters in wide-character literal ignored\n"); + tval.type = widechar; + tval.u.c.v.u = wcbuf[0]; + tsym = &tval; + return ICON; + } else if (*rcp == '"') { + unsigned int *s = scon(*cp, wcput, wcbuf); + tval.type = array(widechar, s - wcbuf, 0); + tval.u.c.v.p = wcbuf; + tsym = &tval; + return SCON; + } else + goto id; + case '\'': { + char *s = scon(*--cp, cput, cbuf); + if (s - cbuf > 2) + warning("excess characters in multibyte character literal ignored\n"); + tval.type = inttype; + if (chartype->op == INT) + tval.u.c.v.i = extend(cbuf[0], chartype); + else + tval.u.c.v.i = cbuf[0]&0xFF; + tsym = &tval; + return ICON; + } + case '"': { + char *s = scon(*--cp, cput, cbuf); + tval.type = array(chartype, s - cbuf, 0); + tval.u.c.v.p = cbuf; + tsym = &tval; + return SCON; + } + case 'a': + if (rcp[0] == 'u' + && rcp[1] == 't' + && rcp[2] == 'o' + && !(map[rcp[3]]&(DIGIT|LETTER))) { + cp = rcp + 3; + return AUTO; + } + goto id; + case 'b': + if (rcp[0] == 'r' + && rcp[1] == 'e' + && rcp[2] == 'a' + && rcp[3] == 'k' + && !(map[rcp[4]]&(DIGIT|LETTER))) { + cp = rcp + 4; + return BREAK; + } + goto id; + case 'c': + if (rcp[0] == 'a' + && rcp[1] == 's' + && rcp[2] == 'e' + && !(map[rcp[3]]&(DIGIT|LETTER))) { + cp = rcp + 3; + return CASE; + } + if (rcp[0] == 'h' + && rcp[1] == 'a' + && rcp[2] == 'r' + && !(map[rcp[3]]&(DIGIT|LETTER))) { + cp = rcp + 3; + tsym = chartype->u.sym; + return CHAR; + } + if (rcp[0] == 'o' + && rcp[1] == 'n' + && rcp[2] == 's' + && rcp[3] == 't' + && !(map[rcp[4]]&(DIGIT|LETTER))) { + cp = rcp + 4; + return CONST; + } + if (rcp[0] == 'o' + && rcp[1] == 'n' + && rcp[2] == 't' + && rcp[3] == 'i' + && rcp[4] == 'n' + && rcp[5] == 'u' + && rcp[6] == 'e' + && !(map[rcp[7]]&(DIGIT|LETTER))) { + cp = rcp + 7; + return CONTINUE; + } + goto id; + case 'd': + if (rcp[0] == 'e' + && rcp[1] == 'f' + && rcp[2] == 'a' + && rcp[3] == 'u' + && rcp[4] == 'l' + && rcp[5] == 't' + && !(map[rcp[6]]&(DIGIT|LETTER))) { + cp = rcp + 6; + return DEFAULT; + } + if (rcp[0] == 'o' + && rcp[1] == 'u' + && rcp[2] == 'b' + && rcp[3] == 'l' + && rcp[4] == 'e' + && !(map[rcp[5]]&(DIGIT|LETTER))) { + cp = rcp + 5; + tsym = doubletype->u.sym; + return DOUBLE; + } + if (rcp[0] == 'o' + && !(map[rcp[1]]&(DIGIT|LETTER))) { + cp = rcp + 1; + return DO; + } + goto id; + case 'e': + if (rcp[0] == 'l' + && rcp[1] == 's' + && rcp[2] == 'e' + && !(map[rcp[3]]&(DIGIT|LETTER))) { + cp = rcp + 3; + return ELSE; + } + if (rcp[0] == 'n' + && rcp[1] == 'u' + && rcp[2] == 'm' + && !(map[rcp[3]]&(DIGIT|LETTER))) { + cp = rcp + 3; + return ENUM; + } + if (rcp[0] == 'x' + && rcp[1] == 't' + && rcp[2] == 'e' + && rcp[3] == 'r' + && rcp[4] == 'n' + && !(map[rcp[5]]&(DIGIT|LETTER))) { + cp = rcp + 5; + return EXTERN; + } + goto id; + case 'f': + if (rcp[0] == 'l' + && rcp[1] == 'o' + && rcp[2] == 'a' + && rcp[3] == 't' + && !(map[rcp[4]]&(DIGIT|LETTER))) { + cp = rcp + 4; + tsym = floattype->u.sym; + return FLOAT; + } + if (rcp[0] == 'o' + && rcp[1] == 'r' + && !(map[rcp[2]]&(DIGIT|LETTER))) { + cp = rcp + 2; + return FOR; + } + goto id; + case 'g': + if (rcp[0] == 'o' + && rcp[1] == 't' + && rcp[2] == 'o' + && !(map[rcp[3]]&(DIGIT|LETTER))) { + cp = rcp + 3; + return GOTO; + } + goto id; + case 'l': + if (rcp[0] == 'o' + && rcp[1] == 'n' + && rcp[2] == 'g' + && !(map[rcp[3]]&(DIGIT|LETTER))) { + cp = rcp + 3; + return LONG; + } + goto id; + case 'r': + if (rcp[0] == 'e' + && rcp[1] == 'g' + && rcp[2] == 'i' + && rcp[3] == 's' + && rcp[4] == 't' + && rcp[5] == 'e' + && rcp[6] == 'r' + && !(map[rcp[7]]&(DIGIT|LETTER))) { + cp = rcp + 7; + return REGISTER; + } + if (rcp[0] == 'e' + && rcp[1] == 't' + && rcp[2] == 'u' + && rcp[3] == 'r' + && rcp[4] == 'n' + && !(map[rcp[5]]&(DIGIT|LETTER))) { + cp = rcp + 5; + return RETURN; + } + goto id; + case 's': + if (rcp[0] == 'h' + && rcp[1] == 'o' + && rcp[2] == 'r' + && rcp[3] == 't' + && !(map[rcp[4]]&(DIGIT|LETTER))) { + cp = rcp + 4; + return SHORT; + } + if (rcp[0] == 'i' + && rcp[1] == 'g' + && rcp[2] == 'n' + && rcp[3] == 'e' + && rcp[4] == 'd' + && !(map[rcp[5]]&(DIGIT|LETTER))) { + cp = rcp + 5; + return SIGNED; + } + if (rcp[0] == 'i' + && rcp[1] == 'z' + && rcp[2] == 'e' + && rcp[3] == 'o' + && rcp[4] == 'f' + && !(map[rcp[5]]&(DIGIT|LETTER))) { + cp = rcp + 5; + return SIZEOF; + } + if (rcp[0] == 't' + && rcp[1] == 'a' + && rcp[2] == 't' + && rcp[3] == 'i' + && rcp[4] == 'c' + && !(map[rcp[5]]&(DIGIT|LETTER))) { + cp = rcp + 5; + return STATIC; + } + if (rcp[0] == 't' + && rcp[1] == 'r' + && rcp[2] == 'u' + && rcp[3] == 'c' + && rcp[4] == 't' + && !(map[rcp[5]]&(DIGIT|LETTER))) { + cp = rcp + 5; + return STRUCT; + } + if (rcp[0] == 'w' + && rcp[1] == 'i' + && rcp[2] == 't' + && rcp[3] == 'c' + && rcp[4] == 'h' + && !(map[rcp[5]]&(DIGIT|LETTER))) { + cp = rcp + 5; + return SWITCH; + } + goto id; + case 't': + if (rcp[0] == 'y' + && rcp[1] == 'p' + && rcp[2] == 'e' + && rcp[3] == 'd' + && rcp[4] == 'e' + && rcp[5] == 'f' + && !(map[rcp[6]]&(DIGIT|LETTER))) { + cp = rcp + 6; + return TYPEDEF; + } + goto id; + case 'u': + if (rcp[0] == 'n' + && rcp[1] == 'i' + && rcp[2] == 'o' + && rcp[3] == 'n' + && !(map[rcp[4]]&(DIGIT|LETTER))) { + cp = rcp + 4; + return UNION; + } + if (rcp[0] == 'n' + && rcp[1] == 's' + && rcp[2] == 'i' + && rcp[3] == 'g' + && rcp[4] == 'n' + && rcp[5] == 'e' + && rcp[6] == 'd' + && !(map[rcp[7]]&(DIGIT|LETTER))) { + cp = rcp + 7; + return UNSIGNED; + } + goto id; + case 'v': + if (rcp[0] == 'o' + && rcp[1] == 'i' + && rcp[2] == 'd' + && !(map[rcp[3]]&(DIGIT|LETTER))) { + cp = rcp + 3; + tsym = voidtype->u.sym; + return VOID; + } + if (rcp[0] == 'o' + && rcp[1] == 'l' + && rcp[2] == 'a' + && rcp[3] == 't' + && rcp[4] == 'i' + && rcp[5] == 'l' + && rcp[6] == 'e' + && !(map[rcp[7]]&(DIGIT|LETTER))) { + cp = rcp + 7; + return VOLATILE; + } + goto id; + case 'w': + if (rcp[0] == 'h' + && rcp[1] == 'i' + && rcp[2] == 'l' + && rcp[3] == 'e' + && !(map[rcp[4]]&(DIGIT|LETTER))) { + cp = rcp + 4; + return WHILE; + } + goto id; + case '_': + if (rcp[0] == '_' + && rcp[1] == 't' + && rcp[2] == 'y' + && rcp[3] == 'p' + && rcp[4] == 'e' + && rcp[5] == 'c' + && rcp[6] == 'o' + && rcp[7] == 'd' + && rcp[8] == 'e' + && !(map[rcp[9]]&(DIGIT|LETTER))) { + cp = rcp + 9; + return TYPECODE; + } + if (rcp[0] == '_' + && rcp[1] == 'f' + && rcp[2] == 'i' + && rcp[3] == 'r' + && rcp[4] == 's' + && rcp[5] == 't' + && rcp[6] == 'a' + && rcp[7] == 'r' + && rcp[8] == 'g' + && !(map[rcp[9]]&(DIGIT|LETTER))) { + cp = rcp + 9; + return FIRSTARG; + } + goto id; + default: + if ((map[cp[-1]]&BLANK) == 0) { + if (cp[-1] < ' ' || cp[-1] >= 0177) + error("illegal character `\\0%o'\n", cp[-1]); + else + error("illegal character `%c'\n", cp[-1]); + } + } + } +} + +static Symbol icon(unsigned long n, int overflow, int base) +{ + if (((*cp=='u'||*cp=='U') && (cp[1]=='l'||cp[1]=='L')) + || ((*cp=='l'||*cp=='L') && (cp[1]=='u'||cp[1]=='U'))) { + tval.type = unsignedlong; + cp += 2; + } else if (*cp == 'u' || *cp == 'U') { + if (overflow || n > unsignedtype->u.sym->u.limits.max.i) + tval.type = unsignedlong; + else + tval.type = unsignedtype; + cp += 1; + } else if (*cp == 'l' || *cp == 'L') { + if (overflow || n > longtype->u.sym->u.limits.max.i) + tval.type = unsignedlong; + else + tval.type = longtype; + cp += 1; + } else if (overflow || n > longtype->u.sym->u.limits.max.i) { + tval.type = unsignedlong; + } else if (n > inttype->u.sym->u.limits.max.i) { + tval.type = longtype; + } else if (base != 10 && n > inttype->u.sym->u.limits.max.i) { + tval.type = unsignedtype; + } else + tval.type = inttype; + + switch (tval.type->op) { + case INT: + if (overflow || n > tval.type->u.sym->u.limits.max.i) { + warning("overflow in constant `%S'\n", token, + (char*)cp - token); + tval.u.c.v.i = tval.type->u.sym->u.limits.max.i; + } else + tval.u.c.v.i = n; + break; + case UNSIGNED: + if (overflow || n > tval.type->u.sym->u.limits.max.u) { + warning("overflow in constant `%S'\n", token, + (char*)cp - token); + tval.u.c.v.u = tval.type->u.sym->u.limits.max.u; + } else + tval.u.c.v.u = n; + break; + default: assert(0); + } + ppnumber("integer"); + return &tval; +} +static void ppnumber(char *which) { + unsigned char *rcp = cp--; + + for ( ; (map[*cp]&(DIGIT|LETTER)) || *cp == '.'; cp++) + if ((cp[0] == 'E' || cp[0] == 'e') + && (cp[1] == '-' || cp[1] == '+')) + cp++; + if (cp > rcp) + error("`%S' is a preprocessing number but an invalid %s constant\n", token, + + (char*)cp-token, which); +} +static Symbol fcon(void) { + if (*cp == '.') + do + cp++; + while (map[*cp]&DIGIT); + if (*cp == 'e' || *cp == 'E') { + if (*++cp == '-' || *cp == '+') + cp++; + if (map[*cp]&DIGIT) + do + cp++; + while (map[*cp]&DIGIT); + else + error("invalid floating constant `%S'\n", token, + (char*)cp - token); + } + + errno = 0; + tval.u.c.v.d = strtod(token, NULL); + if (errno == ERANGE) + warning("overflow in floating constant `%S'\n", token, + (char*)cp - token); + if (*cp == 'f' || *cp == 'F') { + ++cp; + if (tval.u.c.v.d > floattype->u.sym->u.limits.max.d) + warning("overflow in floating constant `%S'\n", token, + (char*)cp - token); + tval.type = floattype; + } else if (*cp == 'l' || *cp == 'L') { + cp++; + tval.type = longdouble; + } else { + if (tval.u.c.v.d > doubletype->u.sym->u.limits.max.d) + warning("overflow in floating constant `%S'\n", token, + (char*)cp - token); + tval.type = doubletype; + } + ppnumber("floating"); + return &tval; +} + +static void *cput(int c, void *cl) { + char *s = cl; + + if (c < 0 || c > 255) + warning("overflow in escape sequence with resulting value `%d'\n", c); + *s++ = c; + return s; +} + +static void *wcput(int c, void *cl) { + unsigned int *s = cl; + + *s++ = c; + return s; +} + +static void *scon(int q, void *put(int c, void *cl), void *cl) { + int n = 0, nbad = 0; + + do { + cp++; + while (*cp != q) { + int c; + if (map[*cp]&NEWLINE) { + if (cp < limit) + break; + cp++; + nextline(); + if (cp == limit) + break; + continue; + } + c = *cp++; + if (c == '\\') { + if (map[*cp]&NEWLINE) { + if (cp++ < limit) + continue; + nextline(); + } + if (limit - cp < MAXTOKEN) + fillbuf(); + c = backslash(q); + } else if (c < 0 || c > 255 || map[c] == 0) + nbad++; + if (n++ < BUFSIZE) + cl = put(c, cl); + } + if (*cp == q) + cp++; + else + error("missing %c\n", q); + if (q == '"' && put == wcput && getchr() == 'L') { + if (limit - cp < 2) + fillbuf(); + if (cp[1] == '"') + cp++; + } + } while (q == '"' && getchr() == '"'); + cl = put(0, cl); + if (n >= BUFSIZE) + error("%s literal too long\n", q == '"' ? "string" : "character"); + if (Aflag >= 2 && q == '"' && n > 509) + warning("more than 509 characters in a string literal\n"); + if (Aflag >= 2 && nbad > 0) + warning("%s literal contains non-portable characters\n", + q == '"' ? "string" : "character"); + return cl; +} +int getchr(void) { + for (;;) { + while (map[*cp]&BLANK) + cp++; + if (!(map[*cp]&NEWLINE)) + return *cp; + cp++; + nextline(); + if (cp == limit) + return EOI; + } +} +static int backslash(int q) { + unsigned int c; + + switch (*cp++) { + case 'a': 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 '\v'; + case '\'': case '"': case '\\': case '\?': break; + case 'x': { + int overflow = 0; + if ((map[*cp]&(DIGIT|HEX)) == 0) { + if (*cp < ' ' || *cp == 0177) + error("ill-formed hexadecimal escape sequence\n"); + else + error("ill-formed hexadecimal escape sequence `\\x%c'\n", *cp); + if (*cp != q) + cp++; + return 0; + } + for (c = 0; map[*cp]&(DIGIT|HEX); cp++) { + if (c >> (8*widechar->size - 4)) + overflow = 1; + if (map[*cp]&DIGIT) + c = (c<<4) + *cp - '0'; + else + c = (c<<4) + (*cp&~040) - 'A' + 10; + } + if (overflow) + warning("overflow in hexadecimal escape sequence\n"); + return c&ones(8*widechar->size); + } + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + c = *(cp-1) - '0'; + if (*cp >= '0' && *cp <= '7') { + c = (c<<3) + *cp++ - '0'; + if (*cp >= '0' && *cp <= '7') + c = (c<<3) + *cp++ - '0'; + } + return c; + default: + if (cp[-1] < ' ' || cp[-1] >= 0177) + warning("unrecognized character escape sequence\n"); + else + warning("unrecognized character escape sequence `\\%c'\n", cp[-1]); + } + return cp[-1]; +} diff --git a/src/cmd/lccom/lib/assert.c b/src/cmd/lccom/lib/assert.c new file mode 100644 index 0000000..f532b73 --- /dev/null +++ b/src/cmd/lccom/lib/assert.c @@ -0,0 +1,19 @@ +#include +#include + +#ifndef EXPORT +# define EXPORT +#endif + +EXPORT int _assert(char *e, char *file, int line) +{ + fprintf(stderr, "assertion failed:"); + if (e) + fprintf(stderr, " %s", e); + if (file) + fprintf(stderr, " file %s", file); + fprintf(stderr, " line %d\n", line); + fflush(stderr); + abort(); + return 0; +} diff --git a/src/cmd/lccom/lib/bbexit.c b/src/cmd/lccom/lib/bbexit.c new file mode 100644 index 0000000..f203fb7 --- /dev/null +++ b/src/cmd/lccom/lib/bbexit.c @@ -0,0 +1,136 @@ +#include +#include + +#ifndef EXPORT +# define EXPORT +#endif + +EXPORT struct callsite { + char *file, *name; + union coordinate { + struct { unsigned int index:6,x:10,y:16; } be; + struct { unsigned int y:16,x:10,index:6; } le; + unsigned int coord; + } u; +} *_caller, **_callerp = &_caller; + +EXPORT void _setcallerp(struct callsite **p) +{ + _callerp = p; +} + +static struct _bbdata { + struct _bbdata *link; + int npoints, *counts; + union coordinate *coords; + char **files; + struct func { + struct func *link; + struct caller { + struct caller *link; + struct callsite *caller; + int count; + } *callers; + char *name; + union coordinate src; + } *funcs; +} tail, *_bblist = &tail; + +static void unpack(unsigned int coord, int *index, int *x, int *y) +{ + static union { int x; char endian; } little = { 1 }; + union coordinate u; + + u.coord = coord; + if (little.endian) { + *index = u.le.index; + *x = u.le.x; + *y = u.le.y; + } else { + *index = u.be.index; + *x = u.be.x; + *y = u.be.y; + } +} + +static void profout(struct _bbdata *p, FILE *fp) +{ + int i, index, x, y; + struct func *f; + struct caller *q; + + for (i = 0; p->files[i]; i++) + ; + fprintf(fp, "%d\n", i); + for (i = 0; p->files[i]; i++) + fprintf(fp, "%s\n", p->files[i]); + for (i = 0, f = p->funcs; f; i++, f = f->link) + if ((q = f->callers)) + for (i--; q; q = q->link) + i++; + fprintf(fp, "%d\n", i); + for (f = p->funcs; f; f = f->link) { + int n = 0; + for (q = f->callers; q; n += q->count, q = q->link) { + unpack(f->src.coord, &index, &x, &y); + fprintf(fp, "%s %d %d %d %d", f->name, index, x, y, q->count); + if (q->caller) { + unpack(q->caller->u.coord, &index, &x, &y); + fprintf(fp, " %s %s %d %d\n", q->caller->name, q->caller->file, x, y); + } else + fprintf(fp, " ? ? 0 0\n"); + } + if (n == 0) { + unpack(f->src.coord, &index, &x, &y); + fprintf(fp, "%s %d %d %d 0 ? ? 0 0\n", f->name, index, x, y); + } + } + fprintf(fp, "%d\n", p->npoints); + for (i = 0; i < p->npoints; i++) { + unpack(p->coords[i].coord, &index, &x, &y); + fprintf(fp, "%d %d %d %d\n", index, x, y, p->counts[i]); + } +} + +static void bbexit(void) +{ + FILE *fp; + + if (_bblist != &tail && (fp = fopen("prof.out", "a"))) { + for ( ; _bblist != &tail; _bblist = _bblist->link) + profout(_bblist, fp); + fclose(fp); + } +} + +EXPORT void _epilogue(struct func *callee) +{ + *_callerp = 0; +} + +EXPORT void _prologue(struct func *callee, struct _bbdata *yylink) +{ + static struct caller callers[4096]; + static int next; + struct caller *p; + + if (!yylink->link) { + yylink->link = _bblist; + _bblist = yylink; + if (next == 0) + atexit(bbexit); + } + for (p = callee->callers; p; p = p->link) + if (p->caller == *_callerp) { + p->count++; + break; + } + if (!p && next < sizeof callers/sizeof callers[0]) { + p = &callers[next++]; + p->caller = *_callerp; + p->count = 1; + p->link = callee->callers; + callee->callers = p; + } + *_callerp = 0; +} diff --git a/src/cmd/lccom/lib/yynull.c b/src/cmd/lccom/lib/yynull.c new file mode 100644 index 0000000..0cd510a --- /dev/null +++ b/src/cmd/lccom/lib/yynull.c @@ -0,0 +1,16 @@ +#include +#include + +#ifndef EXPORT +# define EXPORT +#endif + +EXPORT void _YYnull(char *file, int line) +{ + fprintf(stderr, "null pointer dereferenced:"); + if (file) + fprintf(stderr, " file %s,", file); + fprintf(stderr, " line %d\n", line); + fflush(stderr); + abort(); +} diff --git a/src/cmd/lccom/list.c b/src/cmd/lccom/list.c new file mode 100644 index 0000000..e4b8f61 --- /dev/null +++ b/src/cmd/lccom/list.c @@ -0,0 +1,55 @@ +#include "c.h" + +static List freenodes; /* free list nodes */ + +/* append - append x to list, return new list */ +List append(void *x, List list) { + List new; + + if ((new = freenodes) != NULL) + freenodes = freenodes->link; + else + NEW(new, PERM); + if (list) { + new->link = list->link; + list->link = new; + } else + new->link = new; + new->x = x; + return new; +} + +/* length - # elements in list */ +int length(List list) { + int n = 0; + + if (list) { + List lp = list; + do + n++; + while ((lp = lp->link) != list); + } + return n; +} + +/* ltov - convert list to an NULL-terminated vector allocated in arena */ +void *ltov(List *list, unsigned arena) { + int i = 0; + void **array = newarray(length(*list) + 1, sizeof array[0], arena); + + if (*list) { + List lp = *list; + do { + lp = lp->link; + array[i++] = lp->x; + } while (lp != *list); +#ifndef PURIFY + lp = (*list)->link; + (*list)->link = freenodes; + freenodes = lp; +#endif + } + *list = NULL; + array[i] = NULL; + return array; +} diff --git a/src/cmd/lccom/main.c b/src/cmd/lccom/main.c new file mode 100644 index 0000000..c60c033 --- /dev/null +++ b/src/cmd/lccom/main.c @@ -0,0 +1,265 @@ +#include "c.h" +#include + +static const char *version = "RetroBSD revision " VERSION; + +static void typestab(Symbol, void *); + +static void stabline(Coordinate *); +static void stabend(Coordinate *, Symbol, Coordinate **, Symbol *, Symbol *); +Interface *IR = NULL; + +int Aflag; /* >= 0 if -A specified */ +int Pflag; /* != 0 if -P specified */ +int glevel; /* == [0-9] if -g[0-9] specified */ +int xref; /* != 0 for cross-reference data */ +Symbol YYnull; /* _YYnull symbol if -n or -nvalidate specified */ +Symbol YYcheck; /* _YYcheck symbol if -nvalidate,check specified */ + +static char *comment; +static Interface stabIR; +static char *currentfile; /* current file name */ +static int currentline; /* current line number */ +static FILE *srcfp; /* stream for current file, if non-NULL */ +static int srcpos; /* position of srcfp, if srcfp is non-NULL */ + +void usage() +{ + int i; + + fprintf(stderr, "Usage:\n"); + fprintf(stderr, " lccom -target=TARGET [options] [infile [outfile]]\n"); + fprintf(stderr, "Targets:\n"); + for (i = 0; bindings[i].name; i++) + fprint(stderr, " -target=%s\n", bindings[i].name); + fprintf(stderr, "Options:\n"); + fprintf(stderr, " ..todo..\n"); + exit(1); +} + +int main(int argc, char *argv[]) +{ + int i, j; + + if (argc == 1 && isatty(0)) + usage(); + + /* Default target is mips-el. */ + IR = bindings[0].ir; + for (i = argc - 1; i > 0; i--) + if (strncmp(argv[i], "-target=", 8) == 0) + break; + if (i > 0) { + char *s = strchr(argv[i], '\\'); + if (s != NULL) + *s = '/'; + for (j = 0; bindings[j].name && bindings[j].ir; j++) + if (strcmp(&argv[i][8], bindings[j].name) == 0) { + IR = bindings[j].ir; + break; + } + if (s != NULL) + *s = '\\'; + } + if (!IR) { + fprint(stderr, "%s: unknown target", argv[0]); + if (i > 0) + fprint(stderr, " `%s'", &argv[i][8]); + fprint(stderr, "; must specify one of\n"); + for (i = 0; bindings[i].name; i++) + fprint(stderr, "\t-target=%s\n", bindings[i].name); + exit(EXIT_FAILURE); + } + init(argc, argv); + t = gettok(); + (*IR->progbeg)(argc, argv); + for (i = 1; i < argc; i++) + if (strcmp(argv[i], "-n") == 0) { + if (!YYnull) { + YYnull = install(string("_YYnull"), &globals, GLOBAL, PERM); + YYnull->type = func(voidptype, NULL, 1); + YYnull->sclass = EXTERN; + (*IR->defsymbol)(YYnull); + } + } else if (strncmp(argv[i], "-n", 2) == 0) { /* -nvalid[,check] */ + char *p = strchr(argv[i], ','); + if (p) { + YYcheck = install(string(p+1), &globals, GLOBAL, PERM); + YYcheck->type = func(voidptype, NULL, 1); + YYcheck->sclass = EXTERN; + (*IR->defsymbol)(YYcheck); + p = stringn(argv[i]+2, p - (argv[i]+2)); + } else + p = string(argv[i]+2); + YYnull = install(p, &globals, GLOBAL, PERM); + YYnull->type = func(voidptype, NULL, 1); + YYnull->sclass = EXTERN; + (*IR->defsymbol)(YYnull); + } else { + profInit(argv[i]); + traceInit(argv[i]); + } + if (glevel && IR->stabinit) + (*IR->stabinit)(firstfile, argc, argv); + program(); + if (events.end) + apply(events.end, NULL, NULL); + memset(&events, 0, sizeof events); + if (glevel || xref) { + Symbol symroot = NULL; + Coordinate src; + foreach(types, GLOBAL, typestab, &symroot); + foreach(identifiers, GLOBAL, typestab, &symroot); + src.file = firstfile; + src.x = 0; + src.y = lineno; + if ((glevel > 2 || xref) && IR->stabend) + (*IR->stabend)(&src, symroot, + ltov(&loci, PERM), + ltov(&symbols, PERM), NULL); + else if (IR->stabend) + (*IR->stabend)(&src, NULL, NULL, NULL, NULL); + } + finalize(); + (*IR->progend)(); + deallocate(PERM); + return errcnt > 0; +} + +/* + * main_init - process program arguments + */ +void main_init(int argc, char *argv[]) +{ + char *infile = NULL, *outfile = NULL; + int i; + static int inited; + + if (inited) + return; + inited = 1; + type_init(argc, argv); + for (i = 1; i < argc; i++) + if (strcmp(argv[i], "-g") == 0 || strcmp(argv[i], "-g2") == 0) + glevel = 2; + else if (strncmp(argv[i], "-g", 2) == 0) { /* -gn[,x] */ + char *p = strchr(argv[i], ','); + glevel = atoi(argv[i]+2); + if (p) { + comment = p + 1; + if (glevel == 0) + glevel = 1; + if (stabIR.stabline == NULL) { + stabIR.stabline = IR->stabline; + stabIR.stabend = IR->stabend; + IR->stabline = stabline; + IR->stabend = stabend; + } + } + } else if (strcmp(argv[i], "-x") == 0) + xref++; + else if (strcmp(argv[i], "-A") == 0) { + ++Aflag; + } else if (strcmp(argv[i], "-P") == 0) + Pflag++; + else if (strcmp(argv[i], "-w") == 0) + wflag++; + else if (strcmp(argv[i], "-v") == 0) + fprint(stderr, "%s %s\n", argv[0], version); + else if (strncmp(argv[i], "-s", 2) == 0) + density = strtod(&argv[i][2], NULL); + else if (strncmp(argv[i], "-errout=", 8) == 0) { + FILE *f = fopen(argv[i]+8, "w"); + if (f == NULL) { + fprint(stderr, "%s: can't write errors to `%s'\n", argv[0], argv[i]+8); + exit(EXIT_FAILURE); + } + fclose(f); + f = freopen(argv[i]+8, "w", stderr); + assert(f); + } else if (strncmp(argv[i], "-e", 2) == 0) { + int x; + if ((x = strtol(&argv[i][2], NULL, 0)) > 0) + errlimit = x; + } else if (strncmp(argv[i], "-little_endian=", 15) == 0) + IR->little_endian = argv[i][15] - '0'; + else if (strncmp(argv[i], "-mulops_calls=", 18) == 0) + IR->mulops_calls = argv[i][18] - '0'; + else if (strncmp(argv[i], "-wants_callb=", 13) == 0) + IR->wants_callb = argv[i][13] - '0'; + else if (strncmp(argv[i], "-wants_argb=", 12) == 0) + IR->wants_argb = argv[i][12] - '0'; + else if (strncmp(argv[i], "-left_to_right=", 15) == 0) + IR->left_to_right = argv[i][15] - '0'; + else if (strncmp(argv[i], "-wants_dag=", 11) == 0) + IR->wants_dag = argv[i][11] - '0'; + else if (*argv[i] != '-' || strcmp(argv[i], "-") == 0) { + if (infile == NULL) + infile = argv[i]; + else if (outfile == NULL) + outfile = argv[i]; + } + + if (infile != NULL && strcmp(infile, "-") != 0 + && freopen(infile, "r", stdin) == NULL) { + fprint(stderr, "%s: can't read `%s'\n", argv[0], infile); + exit(EXIT_FAILURE); + } + if (outfile != NULL && strcmp(outfile, "-") != 0 + && freopen(outfile, "w", stdout) == NULL) { + fprint(stderr, "%s: can't write `%s'\n", argv[0], outfile); + exit(EXIT_FAILURE); + } +} + +/* + * typestab - emit stab entries for p + */ +static void typestab(Symbol p, void *cl) +{ + if (*(Symbol *)cl == 0 && p->sclass && p->sclass != TYPEDEF) + *(Symbol *)cl = p; + if ((p->sclass == TYPEDEF || p->sclass == 0) && IR->stabtype) + (*IR->stabtype)(p); +} + +/* + * stabline - emit source code for source coordinate *cp + */ +static void stabline(Coordinate *cp) +{ + if (cp->file && cp->file != currentfile) { + if (srcfp) + fclose(srcfp); + currentfile = cp->file; + srcfp = fopen(currentfile, "r"); + srcpos = 0; + currentline = 0; + } + if (currentline != cp->y && srcfp) { + char buf[512]; + if (srcpos > cp->y) { + rewind(srcfp); + srcpos = 0; + } + for ( ; srcpos < cp->y; srcpos++) + if (fgets(buf, sizeof buf, srcfp) == NULL) { + fclose(srcfp); + srcfp = NULL; + break; + } + if (srcfp && srcpos == cp->y) + print("%s%s", comment, buf); + } + currentline = cp->y; + if (stabIR.stabline) + (*stabIR.stabline)(cp); +} + +static void stabend(Coordinate *cp, Symbol p, Coordinate **cpp, Symbol *sp, Symbol *stab) +{ + if (stabIR.stabend) + (*stabIR.stabend)(cp, p, cpp, sp, stab); + if (srcfp) + fclose(srcfp); +} diff --git a/src/cmd/lccom/mips.md b/src/cmd/lccom/mips.md new file mode 100644 index 0000000..9bbe6a8 --- /dev/null +++ b/src/cmd/lccom/mips.md @@ -0,0 +1,1158 @@ +%{ +#define INTTMP 0x0100ff00 +#define INTVAR 0x40ff0000 +#define FLTTMP 0x000f0ff0 +#define FLTVAR 0xfff00000 + +#define INTRET 0x00000004 +#define FLTRET 0x00000003 + +#define readsreg(p) \ + (generic((p)->op)==INDIR && (p)->kids[0]->op==VREG+P) +#define setsrc(d) ((d) && (d)->x.regnode && \ + (d)->x.regnode->set == src->x.regnode->set && \ + (d)->x.regnode->mask&src->x.regnode->mask) + +#define relink(a, b) ((b)->x.prev = (a), (a)->x.next = (b)) + +#include "c.h" +#define NODEPTR_TYPE Node +#define OP_LABEL(p) ((p)->op) +#define LEFT_CHILD(p) ((p)->kids[0]) +#define RIGHT_CHILD(p) ((p)->kids[1]) +#define STATE_LABEL(p) ((p)->x.state) +static void address(Symbol, Symbol, long); +static void blkfetch(int, int, int, int); +static void blkloop(int, int, int, int, int, int[]); +static void blkstore(int, int, int, int); +static void defaddress(Symbol); +static void defconst(int, int, Value); +static void defstring(int, char *); +static void defsymbol(Symbol); +static void doarg(Node); +static void emit2(Node); +static void export(Symbol); +static void clobber(Node); +static void function(Symbol, Symbol [], Symbol [], int); +static void global(Symbol); +static void import(Symbol); +static void local(Symbol); +static void progbeg(int, char **); +static void progend(void); +static void segment(int); +static void space(int); +static void target(Node); +static int bitcount (unsigned); +static Symbol argreg (int, int, int, int, int); + +static Symbol ireg[32], freg2[32], d6; +static Symbol iregw, freg2w; +static int tmpregs[] = {3, 9, 10}; +static Symbol blkreg; + +static int gnum = 8; +static int pic; + +static int cseg; +%} +%start stmt +%term CNSTF4=4113 +%term CNSTF8=8209 +%term CNSTF16=16401 +%term CNSTI1=1045 +%term CNSTI2=2069 +%term CNSTI4=4117 +%term CNSTI8=8213 +%term CNSTP4=4119 +%term CNSTP8=8215 +%term CNSTU1=1046 +%term CNSTU2=2070 +%term CNSTU4=4118 +%term CNSTU8=8214 + +%term ARGB=41 +%term ARGF4=4129 +%term ARGF8=8225 +%term ARGF16=16417 +%term ARGI4=4133 +%term ARGI8=8229 +%term ARGP4=4135 +%term ARGP8=8231 +%term ARGU4=4134 +%term ARGU8=8230 + +%term ASGNB=57 +%term ASGNF4=4145 +%term ASGNF8=8241 +%term ASGNF16=16433 +%term ASGNI1=1077 +%term ASGNI2=2101 +%term ASGNI4=4149 +%term ASGNI8=8245 +%term ASGNP4=4151 +%term ASGNP8=8247 +%term ASGNU1=1078 +%term ASGNU2=2102 +%term ASGNU4=4150 +%term ASGNU8=8246 + +%term INDIRB=73 +%term INDIRF4=4161 +%term INDIRF8=8257 +%term INDIRF16=16449 +%term INDIRI1=1093 +%term INDIRI2=2117 +%term INDIRI4=4165 +%term INDIRI8=8261 +%term INDIRP4=4167 +%term INDIRP8=8263 +%term INDIRU1=1094 +%term INDIRU2=2118 +%term INDIRU4=4166 +%term INDIRU8=8262 + +%term CVFF4=4209 +%term CVFF8=8305 +%term CVFF16=16497 +%term CVFI4=4213 +%term CVFI8=8309 + +%term CVIF4=4225 +%term CVIF8=8321 +%term CVIF16=16513 +%term CVII1=1157 +%term CVII2=2181 +%term CVII4=4229 +%term CVII8=8325 +%term CVIU1=1158 +%term CVIU2=2182 +%term CVIU4=4230 +%term CVIU8=8326 + +%term CVPP4=4247 +%term CVPP8=8343 +%term CVPP16=16535 +%term CVPU4=4246 +%term CVPU8=8342 + +%term CVUI1=1205 +%term CVUI2=2229 +%term CVUI4=4277 +%term CVUI8=8373 +%term CVUP4=4279 +%term CVUP8=8375 +%term CVUP16=16567 +%term CVUU1=1206 +%term CVUU2=2230 +%term CVUU4=4278 +%term CVUU8=8374 + +%term NEGF4=4289 +%term NEGF8=8385 +%term NEGF16=16577 +%term NEGI4=4293 +%term NEGI8=8389 + +%term CALLB=217 +%term CALLF4=4305 +%term CALLF8=8401 +%term CALLF16=16593 +%term CALLI4=4309 +%term CALLI8=8405 +%term CALLP4=4311 +%term CALLP8=8407 +%term CALLU4=4310 +%term CALLU8=8406 +%term CALLV=216 + +%term RETF4=4337 +%term RETF8=8433 +%term RETF16=16625 +%term RETI4=4341 +%term RETI8=8437 +%term RETP4=4343 +%term RETP8=8439 +%term RETU4=4342 +%term RETU8=8438 +%term RETV=248 + +%term ADDRGP4=4359 +%term ADDRGP8=8455 + +%term ADDRFP4=4375 +%term ADDRFP8=8471 + +%term ADDRLP4=4391 +%term ADDRLP8=8487 + +%term ADDF4=4401 +%term ADDF8=8497 +%term ADDF16=16689 +%term ADDI4=4405 +%term ADDI8=8501 +%term ADDP4=4407 +%term ADDP8=8503 +%term ADDU4=4406 +%term ADDU8=8502 + +%term SUBF4=4417 +%term SUBF8=8513 +%term SUBF16=16705 +%term SUBI4=4421 +%term SUBI8=8517 +%term SUBP4=4423 +%term SUBP8=8519 +%term SUBU4=4422 +%term SUBU8=8518 + +%term LSHI4=4437 +%term LSHI8=8533 +%term LSHU4=4438 +%term LSHU8=8534 + +%term MODI4=4453 +%term MODI8=8549 +%term MODU4=4454 +%term MODU8=8550 + +%term RSHI4=4469 +%term RSHI8=8565 +%term RSHU4=4470 +%term RSHU8=8566 + +%term BANDI4=4485 +%term BANDI8=8581 +%term BANDU4=4486 +%term BANDU8=8582 + +%term BCOMI4=4501 +%term BCOMI8=8597 +%term BCOMU4=4502 +%term BCOMU8=8598 + +%term BORI4=4517 +%term BORI8=8613 +%term BORU4=4518 +%term BORU8=8614 + +%term BXORI4=4533 +%term BXORI8=8629 +%term BXORU4=4534 +%term BXORU8=8630 + +%term DIVF4=4545 +%term DIVF8=8641 +%term DIVF16=16833 +%term DIVI4=4549 +%term DIVI8=8645 +%term DIVU4=4550 +%term DIVU8=8646 + +%term MULF4=4561 +%term MULF8=8657 +%term MULF16=16849 +%term MULI4=4565 +%term MULI8=8661 +%term MULU4=4566 +%term MULU8=8662 + +%term EQF4=4577 +%term EQF8=8673 +%term EQF16=16865 +%term EQI4=4581 +%term EQI8=8677 +%term EQU4=4582 +%term EQU8=8678 + +%term GEF4=4593 +%term GEF8=8689 +%term GEI4=4597 +%term GEI8=8693 +%term GEI16=16885 +%term GEU4=4598 +%term GEU8=8694 + +%term GTF4=4609 +%term GTF8=8705 +%term GTF16=16897 +%term GTI4=4613 +%term GTI8=8709 +%term GTU4=4614 +%term GTU8=8710 + +%term LEF4=4625 +%term LEF8=8721 +%term LEF16=16913 +%term LEI4=4629 +%term LEI8=8725 +%term LEU4=4630 +%term LEU8=8726 + +%term LTF4=4641 +%term LTF8=8737 +%term LTF16=16929 +%term LTI4=4645 +%term LTI8=8741 +%term LTU4=4646 +%term LTU8=8742 + +%term NEF4=4657 +%term NEF8=8753 +%term NEF16=16945 +%term NEI4=4661 +%term NEI8=8757 +%term NEU4=4662 +%term NEU8=8758 + +%term JUMPV=584 + +%term LABELV=600 + +%term LOADB=233 +%term LOADF4=4321 +%term LOADF8=8417 +%term LOADF16=16609 +%term LOADI1=1253 +%term LOADI2=2277 +%term LOADI4=4325 +%term LOADI8=8421 +%term LOADP4=4327 +%term LOADP8=8423 +%term LOADU1=1254 +%term LOADU2=2278 +%term LOADU4=4326 +%term LOADU8=8422 + +%term VREGP=711 +%% +reg: INDIRI1(VREGP) "# read register\n" +reg: INDIRU1(VREGP) "# read register\n" + +reg: INDIRI2(VREGP) "# read register\n" +reg: INDIRU2(VREGP) "# read register\n" + +reg: INDIRF4(VREGP) "# read register\n" +reg: INDIRI4(VREGP) "# read register\n" +reg: INDIRP4(VREGP) "# read register\n" +reg: INDIRU4(VREGP) "# read register\n" + +reg: INDIRF8(VREGP) "# read register\n" +reg: INDIRI8(VREGP) "# read register\n" +reg: INDIRP8(VREGP) "# read register\n" +reg: INDIRU8(VREGP) "# read register\n" + +stmt: ASGNI1(VREGP,reg) "# write register\n" +stmt: ASGNU1(VREGP,reg) "# write register\n" + +stmt: ASGNI2(VREGP,reg) "# write register\n" +stmt: ASGNU2(VREGP,reg) "# write register\n" + +stmt: ASGNF4(VREGP,reg) "# write register\n" +stmt: ASGNI4(VREGP,reg) "# write register\n" +stmt: ASGNP4(VREGP,reg) "# write register\n" +stmt: ASGNU4(VREGP,reg) "# write register\n" + +stmt: ASGNF8(VREGP,reg) "# write register\n" +stmt: ASGNI8(VREGP,reg) "# write register\n" +stmt: ASGNP8(VREGP,reg) "# write register\n" +stmt: ASGNU8(VREGP,reg) "# write register\n" +con: CNSTI1 "%a" +con: CNSTU1 "%a" + +con: CNSTI2 "%a" +con: CNSTU2 "%a" + +con: CNSTI4 "%a" +con: CNSTU4 "%a" +con: CNSTP4 "%a" + +con: CNSTI8 "%a" +con: CNSTU8 "%a" +con: CNSTP8 "%a" +stmt: reg "" +acon: con "%0" +acon: ADDRGP4 "%a" +addr: ADDI4(reg,acon) "%1($%0)" +addr: ADDU4(reg,acon) "%1($%0)" +addr: ADDP4(reg,acon) "%1($%0)" +addr: acon "%0" +addr: reg "($%0)" +addr: ADDRFP4 "%a+%F($sp)" +addr: ADDRLP4 "%a+%F($sp)" +reg: addr " la $%c,%0\n" 1 +reg: con " li $%c,%0\n" 1 +reg: CNSTI1 "# reg\n" range(a, 0, 0) +reg: CNSTI2 "# reg\n" range(a, 0, 0) +reg: CNSTI4 "# reg\n" range(a, 0, 0) +reg: CNSTU1 "# reg\n" range(a, 0, 0) +reg: CNSTU2 "# reg\n" range(a, 0, 0) +reg: CNSTU4 "# reg\n" range(a, 0, 0) +reg: CNSTP4 "# reg\n" range(a, 0, 0) +stmt: ASGNI1(addr,reg) " sb $%1,%0\n" 1 +stmt: ASGNU1(addr,reg) " sb $%1,%0\n" 1 +stmt: ASGNI2(addr,reg) " sh $%1,%0\n" 1 +stmt: ASGNU2(addr,reg) " sh $%1,%0\n" 1 +stmt: ASGNI4(addr,reg) " sw $%1,%0\n" 1 +stmt: ASGNU4(addr,reg) " sw $%1,%0\n" 1 +stmt: ASGNP4(addr,reg) " sw $%1,%0\n" 1 +reg: INDIRI1(addr) " lb $%c,%0\n" 1 +reg: INDIRU1(addr) " lbu $%c,%0\n" 1 +reg: INDIRI2(addr) " lh $%c,%0\n" 1 +reg: INDIRU2(addr) " lhu $%c,%0\n" 1 +reg: INDIRI4(addr) " lw $%c,%0\n" 1 +reg: INDIRU4(addr) " lw $%c,%0\n" 1 +reg: INDIRP4(addr) " lw $%c,%0\n" 1 + +reg: CVII4(INDIRI1(addr)) " lb $%c,%0\n" 1 +reg: CVII4(INDIRI2(addr)) " lh $%c,%0\n" 1 +reg: CVUU4(INDIRU1(addr)) " lbu $%c,%0\n" 1 +reg: CVUU4(INDIRU2(addr)) " lhu $%c,%0\n" 1 +reg: CVUI4(INDIRU1(addr)) " lbu $%c,%0\n" 1 +reg: CVUI4(INDIRU2(addr)) " lhu $%c,%0\n" 1 +reg: INDIRF4(addr) " l.s $f%c,%0\n" 1 +reg: INDIRF8(addr) " l.d $f%c,%0\n" 1 +stmt: ASGNF4(addr,reg) " s.s $f%1,%0\n" 1 +stmt: ASGNF8(addr,reg) " s.d $f%1,%0\n" 1 +reg: DIVI4(reg,reg) " div $%c,$%0,$%1\n" 1 +reg: DIVU4(reg,reg) " divu $%c,$%0,$%1\n" 1 +reg: MODI4(reg,reg) " rem $%c,$%0,$%1\n" 1 +reg: MODU4(reg,reg) " remu $%c,$%0,$%1\n" 1 +reg: MULI4(reg,reg) " mul $%c,$%0,$%1\n" 1 +reg: MULU4(reg,reg) " mul $%c,$%0,$%1\n" 1 +rc: con "%0" +rc: reg "$%0" + +reg: ADDI4(reg,rc) " addu $%c,$%0,%1\n" 1 +reg: ADDP4(reg,rc) " addu $%c,$%0,%1\n" 1 +reg: ADDU4(reg,rc) " addu $%c,$%0,%1\n" 1 +reg: BANDI4(reg,rc) " and $%c,$%0,%1\n" 1 +reg: BORI4(reg,rc) " or $%c,$%0,%1\n" 1 +reg: BXORI4(reg,rc) " xor $%c,$%0,%1\n" 1 +reg: BANDU4(reg,rc) " and $%c,$%0,%1\n" 1 +reg: BORU4(reg,rc) " or $%c,$%0,%1\n" 1 +reg: BXORU4(reg,rc) " xor $%c,$%0,%1\n" 1 +reg: SUBI4(reg,rc) " subu $%c,$%0,%1\n" 1 +reg: SUBP4(reg,rc) " subu $%c,$%0,%1\n" 1 +reg: SUBU4(reg,rc) " subu $%c,$%0,%1\n" 1 +rc5: CNSTI4 "%a" range(a,0,31) +rc5: reg "$%0" + +reg: LSHI4(reg,rc5) " sll $%c,$%0,%1\n" 1 +reg: LSHU4(reg,rc5) " sll $%c,$%0,%1\n" 1 +reg: RSHI4(reg,rc5) " sra $%c,$%0,%1\n" 1 +reg: RSHU4(reg,rc5) " srl $%c,$%0,%1\n" 1 +reg: BCOMI4(reg) " not $%c,$%0\n" 1 +reg: BCOMU4(reg) " not $%c,$%0\n" 1 +reg: NEGI4(reg) " negu $%c,$%0\n" 1 +reg: LOADI1(reg) " move $%c,$%0\n" move(a) +reg: LOADU1(reg) " move $%c,$%0\n" move(a) +reg: LOADI2(reg) " move $%c,$%0\n" move(a) +reg: LOADU2(reg) " move $%c,$%0\n" move(a) +reg: LOADI4(reg) " move $%c,$%0\n" move(a) +reg: LOADP4(reg) " move $%c,$%0\n" move(a) +reg: LOADU4(reg) " move $%c,$%0\n" move(a) +reg: ADDF4(reg,reg) " add.s $f%c,$f%0,$f%1\n" 1 +reg: ADDF8(reg,reg) " add.d $f%c,$f%0,$f%1\n" 1 +reg: DIVF4(reg,reg) " div.s $f%c,$f%0,$f%1\n" 1 +reg: DIVF8(reg,reg) " div.d $f%c,$f%0,$f%1\n" 1 +reg: MULF4(reg,reg) " mul.s $f%c,$f%0,$f%1\n" 1 +reg: MULF8(reg,reg) " mul.d $f%c,$f%0,$f%1\n" 1 +reg: SUBF4(reg,reg) " sub.s $f%c,$f%0,$f%1\n" 1 +reg: SUBF8(reg,reg) " sub.d $f%c,$f%0,$f%1\n" 1 +reg: LOADF4(reg) " mov.s $f%c,$f%0\n" move(a) +reg: LOADF8(reg) " mov.d $f%c,$f%0\n" move(a) +reg: NEGF4(reg) " neg.s $f%c,$f%0\n" 1 +reg: NEGF8(reg) " neg.d $f%c,$f%0\n" 1 +reg: CVII4(reg) " sll $%c,$%0,8*(4-%a); sra $%c,$%c,8*(4-%a)\n" 2 +reg: CVUI4(reg) " and $%c,$%0,(1<<(8*%a))-1\n" 1 +reg: CVUU4(reg) " and $%c,$%0,(1<<(8*%a))-1\n" 1 +reg: CVFF4(reg) " cvt.s.d $f%c,$f%0\n" 1 +reg: CVFF8(reg) " cvt.d.s $f%c,$f%0\n" 1 +reg: CVIF4(reg) " mtc1 $%0,$f%c; cvt.s.w $f%c,$f%c\n" 2 +reg: CVIF8(reg) " mtc1 $%0,$f%c; cvt.d.w $f%c,$f%c\n" 2 +reg: CVFI4(reg) " trunc.w.s $f2,$f%0,$%c; mfc1 $%c,$f2\n" (a->syms[0]->u.c.v.i==4?2:LBURG_MAX) +reg: CVFI4(reg) " trunc.w.d $f2,$f%0,$%c; mfc1 $%c,$f2\n" (a->syms[0]->u.c.v.i==8?2:LBURG_MAX) +stmt: LABELV "%a:\n" +stmt: JUMPV(acon) " b %0\n" 1 +stmt: JUMPV(reg) " .cpadd $%0\nj $%0\n" !pic +stmt: JUMPV(reg) " j $%0\n" pic +stmt: EQI4(reg,reg) " beq $%0,$%1,%a\n" 1 +stmt: EQU4(reg,reg) " beq $%0,$%1,%a\n" 1 +stmt: NEI4(reg,reg) " bne $%0,$%1,%a\n" 1 +stmt: NEU4(reg,reg) " bne $%0,$%1,%a\n" 1 +stmt: LTI4(reg,reg) " slt $at,$%0,$%1; bnez $at,%a\n" 1 +stmt: LTU4(reg,reg) " sltu $at,$%0,$%1; bnez $at,%a\n" 1 +stmt: GTI4(reg,reg) " slt $at,$%1,$%0; bnez $at,%a\n" 1 +stmt: GTU4(reg,reg) " sltu $at,$%1,$%0; bnez $at,%a\n" 1 +stmt: GEI4(reg,reg) " slt $at,$%0,$%1; beqz $at,%a\n" 1 +stmt: GEU4(reg,reg) " sltu $at,$%0,$%1; beqz $at,%a\n" 1 +stmt: LEI4(reg,reg) " slt $at,$%1,$%0; beqz $at,%a\n" 1 +stmt: LEU4(reg,reg) " sltu $at,$%1,$%0; beqz $at,%a\n" 1 +stmt: EQF4(reg,reg) " c.eq.s $f%0,$f%1; bc1t %a\n" 2 +stmt: EQF8(reg,reg) " c.eq.d $f%0,$f%1; bc1t %a\n" 2 +stmt: LEF4(reg,reg) " c.ule.s $f%0,$f%1; bc1t %a\n" 2 +stmt: LEF8(reg,reg) " c.ule.d $f%0,$f%1; bc1t %a\n" 2 +stmt: LTF4(reg,reg) " c.ult.s $f%0,$f%1; bc1t %a\n" 2 +stmt: LTF8(reg,reg) " c.ult.d $f%0,$f%1; bc1t %a\n" 2 +stmt: GEF4(reg,reg) " c.lt.s $f%0,$f%1; bc1f %a\n" 2 +stmt: GEF8(reg,reg) " c.lt.d $f%0,$f%1; bc1f %a\n" 2 +stmt: GTF4(reg,reg) " c.le.s $f%0,$f%1; bc1f %a\n" 2 +stmt: GTF8(reg,reg) " c.le.d $f%0,$f%1; bc1f %a\n" 2 +stmt: NEF4(reg,reg) " c.eq.s $f%0,$f%1; bc1f %a\n" 2 +stmt: NEF8(reg,reg) " c.eq.d $f%0,$f%1; bc1f %a\n" 2 +ar: ADDRGP4 "%a" + +reg: CALLF4(ar) " jal %0\n" 1 +reg: CALLF8(ar) " jal %0\n" 1 +reg: CALLI4(ar) " jal %0\n" 1 +reg: CALLP4(ar) " jal %0\n" 1 +reg: CALLU4(ar) " jal %0\n" 1 +stmt: CALLV(ar) " jal %0\n" 1 +ar: reg "$%0" +ar: CNSTP4 "%a" range(a, 0, 0x0fffffff) +stmt: RETF4(reg) "# ret\n" 1 +stmt: RETF8(reg) "# ret\n" 1 +stmt: RETI4(reg) "# ret\n" 1 +stmt: RETU4(reg) "# ret\n" 1 +stmt: RETP4(reg) "# ret\n" 1 +stmt: RETV(reg) "# ret\n" 1 +stmt: ARGF4(reg) "# arg\n" 1 +stmt: ARGF8(reg) "# arg\n" 1 +stmt: ARGI4(reg) "# arg\n" 1 +stmt: ARGP4(reg) "# arg\n" 1 +stmt: ARGU4(reg) "# arg\n" 1 + +stmt: ARGB(INDIRB(reg)) "# argb %0\n" 1 +stmt: ASGNB(reg,INDIRB(reg)) "# asgnb %0 %1\n" 1 +%% +static void progend(void){} +static void progbeg(int argc, char *argv[]) +{ + int i; + + { + union { + char c; + int i; + } u; + u.i = 0; + u.c = 1; + swap = ((int)(u.i == 1)) != IR->little_endian; + } + print("\t.set\treorder\n"); + pic = !IR->little_endian; + parseflags(argc, argv); + for (i = 0; i < argc; i++) + if (strncmp(argv[i], "-G", 2) == 0) + gnum = atoi(argv[i] + 2); + else if (strcmp(argv[i], "-pic=1") == 0 + || strcmp(argv[i], "-pic=0") == 0) + pic = argv[i][5]-'0'; + for (i = 0; i < 31; i += 2) + freg2[i] = mkreg("%d", i, 3, FREG); + for (i = 0; i < 32; i++) + ireg[i] = mkreg("%d", i, 1, IREG); + ireg[29]->x.name = "sp"; + d6 = mkreg("6", 6, 3, IREG); + freg2w = mkwildcard(freg2); + iregw = mkwildcard(ireg); + tmask[IREG] = INTTMP; tmask[FREG] = FLTTMP; + vmask[IREG] = INTVAR; vmask[FREG] = FLTVAR; + blkreg = mkreg("8", 8, 7, IREG); +} +static Symbol rmap(int opk) +{ + switch (optype(opk)) { + case I: case U: case P: case B: + return iregw; + case F: + return freg2w; + default: + return 0; + } +} +static void target(Node p) +{ + assert(p); + switch (specific(p->op)) { + case CNST+I: case CNST+U: case CNST+P: + if (range(p, 0, 0) == 0) { + setreg(p, ireg[0]); + p->x.registered = 1; + } + break; + case CALL+V: + rtarget(p, 0, ireg[25]); + break; + case CALL+F: + rtarget(p, 0, ireg[25]); + setreg(p, freg2[0]); + break; + case CALL+I: case CALL+P: case CALL+U: + rtarget(p, 0, ireg[25]); + setreg(p, ireg[2]); + break; + case RET+F: + rtarget(p, 0, freg2[0]); + break; + case RET+I: case RET+U: case RET+P: + rtarget(p, 0, ireg[2]); + break; + case ARG+F: case ARG+I: case ARG+P: case ARG+U: { + static int ty0; + int ty = optype(p->op); + Symbol q; + + q = argreg(p->x.argno, p->syms[2]->u.c.v.i, ty, opsize(p->op), ty0); + if (p->x.argno == 0) + ty0 = ty; + if (q && + !(ty == F && q->x.regnode->set == IREG)) + rtarget(p, 0, q); + break; + } + case ASGN+B: rtarget(p->kids[1], 0, blkreg); break; + case ARG+B: rtarget(p->kids[0], 0, blkreg); break; + } +} +static void clobber(Node p) +{ + assert(p); + switch (specific(p->op)) { + case CALL+F: + spill(INTTMP | INTRET, IREG, p); + spill(FLTTMP, FREG, p); + break; + case CALL+I: case CALL+P: case CALL+U: + spill(INTTMP, IREG, p); + spill(FLTTMP | FLTRET, FREG, p); + break; + case CALL+V: + spill(INTTMP | INTRET, IREG, p); + spill(FLTTMP | FLTRET, FREG, p); + break; + } +} +static void emit2(Node p) +{ + int dst, n, src, sz, ty; + static int ty0; + Symbol q; + + switch (specific(p->op)) { + case ARG+F: case ARG+I: case ARG+P: case ARG+U: + ty = optype(p->op); + sz = opsize(p->op); + if (p->x.argno == 0) + ty0 = ty; + q = argreg(p->x.argno, p->syms[2]->u.c.v.i, ty, sz, ty0); + src = getregnum(p->x.kids[0]); + if (q == NULL && ty == F && sz == 4) + print("\ts.s\t$f%d,%d($sp)\n", src, p->syms[2]->u.c.v.i); + else if (q == NULL && ty == F) + print("\ts.d\t$f%d,%d($sp)\n", src, p->syms[2]->u.c.v.i); + else if (q == NULL) + print("\tsw\t$%d,%d($sp)\n", src, p->syms[2]->u.c.v.i); + else if (ty == F && sz == 4 && q->x.regnode->set == IREG) + print("\tmfc1\t$%d,$f%d\n", q->x.regnode->number, src); + else if (ty == F && q->x.regnode->set == IREG) + print("\tmfc1.d\t$%d,$f%d\n", q->x.regnode->number, src); + break; + case ASGN+B: + dalign = salign = p->syms[1]->u.c.v.i; + blkcopy(getregnum(p->x.kids[0]), 0, + getregnum(p->x.kids[1]), 0, + p->syms[0]->u.c.v.i, tmpregs); + break; + case ARG+B: + dalign = 4; + salign = p->syms[1]->u.c.v.i; + blkcopy(29, p->syms[2]->u.c.v.i, + getregnum(p->x.kids[0]), 0, + p->syms[0]->u.c.v.i, tmpregs); + n = p->syms[2]->u.c.v.i + p->syms[0]->u.c.v.i; + dst = p->syms[2]->u.c.v.i; + for ( ; dst <= 12 && dst < n; dst += 4) + print("\tlw\t$%d,%d($sp)\n", (dst/4)+4, dst); + break; + } +} +static Symbol argreg(int argno, int offset, int ty, int sz, int ty0) +{ + assert((offset&3) == 0); + if (offset > 12) + return NULL; + else if (argno == 0 && ty == F) + return freg2[12]; + else if (argno == 1 && ty == F && ty0 == F) + return freg2[14]; + else if (argno == 1 && ty == F && sz == 8) + return d6; /* Pair! */ + else + return ireg[(offset/4) + 4]; +} +static void doarg(Node p) +{ + static int argno; + int align; + + if (argoffset == 0) + argno = 0; + p->x.argno = argno++; + align = p->syms[1]->u.c.v.i < 4 ? 4 : p->syms[1]->u.c.v.i; + p->syms[2] = intconst(mkactual(align, + p->syms[0]->u.c.v.i)); +} +static void local(Symbol p) +{ + if (askregvar(p, rmap(ttob(p->type))) == 0) + mkauto(p); +} + +static void function(Symbol f, Symbol caller[], Symbol callee[], int ncalls) +{ + int i, saved, sizefsave, sizeisave, varargs; + Symbol r, argregs[4]; + + usedmask[0] = usedmask[1] = 0; + freemask[0] = freemask[1] = ~(unsigned)0; + offset = maxoffset = maxargoffset = 0; + for (i = 0; callee[i]; i++) + ; + varargs = variadic(f->type) + || (i > 0 && strcmp(callee[i-1]->name, "va_alist") == 0); + for (i = 0; callee[i]; i++) { + Symbol p = callee[i]; + Symbol q = caller[i]; + assert(q); + offset = roundup(offset, q->type->align); + p->x.offset = q->x.offset = offset; + p->x.name = q->x.name = stringd(offset); + r = argreg(i, offset, optype(ttob(q->type)), q->type->size, optype(ttob(caller[0]->type))); + if (i < 4) + argregs[i] = r; + offset = roundup(offset + q->type->size, 4); + if (varargs) + p->sclass = AUTO; + else if (r && ncalls == 0 && + !isstruct(q->type) && !p->addressed && + !(isfloat(q->type) && r->x.regnode->set == IREG)) + { + p->sclass = q->sclass = REGISTER; + askregvar(p, r); + assert(p->x.regnode && p->x.regnode->vbl == p); + q->x = p->x; + q->type = p->type; + } + else if (askregvar(p, rmap(ttob(p->type))) + && r != NULL + && (isint(p->type) || p->type == q->type)) { + assert(q->sclass != REGISTER); + p->sclass = q->sclass = REGISTER; + q->type = p->type; + } + } + assert(!caller[i]); + offset = 0; + gencode(caller, callee); + if (ncalls) + usedmask[IREG] |= ((unsigned)1)<<31; + usedmask[IREG] &= 0xc0ff0000; + usedmask[FREG] &= 0xfff00000; + if (pic && ncalls) + usedmask[IREG] |= 1<<25; + maxargoffset = roundup(maxargoffset, usedmask[FREG] ? 8 : 4); + if (ncalls && maxargoffset < 16) + maxargoffset = 16; + sizefsave = 4*bitcount(usedmask[FREG]); + sizeisave = 4*bitcount(usedmask[IREG]); + framesize = roundup(maxargoffset + sizefsave + + sizeisave + maxoffset, 16); + segment(CODE); + print("\t.align\t2\n"); + print("\t.ent\t%s\n", f->x.name); + print("%s:\n", f->x.name); + i = maxargoffset + sizefsave - framesize; + print("\t.frame\t$sp,%d,$31\n", framesize); + if (pic) + print("\t.set\tnoreorder\n\t.cpload\t$25\n\t.set\treorder\n"); + if (framesize > 0) + print("\taddu\t$sp,$sp,%d\n", -framesize); + if (usedmask[FREG]) + print("\t.fmask\t0x%x,%d\n", usedmask[FREG], i - 8); + if (usedmask[IREG]) + print("\t.mask\t0x%x,%d\n", usedmask[IREG], + i + sizeisave - 4); + saved = maxargoffset; + for (i = 20; i <= 30; i += 2) + if (usedmask[FREG]&(3<x.regnode != callee[i]->x.regnode) { + Symbol out = callee[i]; + Symbol in = caller[i]; + int rn = r->x.regnode->number; + int rs = r->x.regnode->set; + int tyin = ttob(in->type); + + assert(out && in && r && r->x.regnode); + assert(out->sclass != REGISTER || out->x.regnode); + if (out->sclass == REGISTER + && (isint(out->type) || out->type == in->type)) { + int outn = out->x.regnode->number; + if (rs == FREG && tyin == F+sizeop(8)) + print("\tmov.d\t$f%d,$f%d\n", outn, rn); + else if (rs == FREG && tyin == F+sizeop(4)) + print("\tmov.s\t$f%d,$f%d\n", outn, rn); + else if (rs == IREG && tyin == F+sizeop(8)) + print("\tmtc1.d\t$%d,$f%d\n", rn, outn); + else if (rs == IREG && tyin == F+sizeop(4)) + print("\tmtc1\t$%d,$f%d\n", rn, outn); + else + print("\tmove\t$%d,$%d\n", outn, rn); + } else { + int off = in->x.offset + framesize; + if (rs == FREG && tyin == F+sizeop(8)) + print("\ts.d\t$f%d,%d($sp)\n", rn, off); + else if (rs == FREG && tyin == F+sizeop(4)) + print("\ts.s\t$f%d,%d($sp)\n", rn, off); + else { + int i, n = (in->type->size + 3)/4; + for (i = rn; i < rn+n && i <= 7; i++) + print("\tsw\t$%d,%d($sp)\n", i, off + (i-rn)*4); + } + } + } + } + if (varargs && callee[i-1]) { + i = callee[i-1]->x.offset + callee[i-1]->type->size; + for (i = roundup(i, 4)/4; i <= 3; i++) + print("\tsw\t$%d,%d($sp)\n", i + 4, framesize + 4*i); + } + emitcode(); + saved = maxargoffset; + for (i = 20; i <= 30; i += 2) + if (usedmask[FREG]&(3< 0) + print("\taddu\t$sp,$sp,%d\n", framesize); + print("\tj\t$31\n"); + print("\t.end\t%s\n", f->x.name); +} + +static void defconst(int suffix, int size, Value v) +{ + if (suffix == F && size == 4) { + union { + float f32; + unsigned u32; + } u; + u.f32 = v.d; + print("\t.word\t0x%x\n", u.u32); + } + else if (suffix == F && size == 8) { + union { + double d64; + unsigned u32[2]; + } u; + u.d64 = v.d; + print("\t.word\t0x%x\n\t.word\t0x%x\n", u.u32[swap], u.u32[!swap]); + } + else if (suffix == P) + print("\t.word\t0x%x\n", (unsigned)(size_t)v.p); + else if (size == 1) + print("\t.byte\t0x%x\n", (unsigned)((unsigned char)(suffix == I ? v.i : v.u))); + else if (size == 2) + print("\t.half\t0x%x\n", (unsigned)((unsigned short)(suffix == I ? v.i : v.u))); + else if (size == 4) + print("\t.word\t0x%x\n", (unsigned)(suffix == I ? v.i : v.u)); +} + +static void defaddress(Symbol p) +{ + if (pic && p->scope == LABELS) + print("\t.gpword\t%s\n", p->x.name); + else + print("\t.word\t%s\n", p->x.name); +} +static void defstring(int n, char *str) +{ + char *s; + + for (s = str; s < str + n; s++) + print("\t.byte\t%d\n", (*s)&0377); +} +static void export(Symbol p) +{ + print("\t.globl\t%s\n", p->x.name); +} +static void import(Symbol p) +{ + if (!isfunc(p->type)) + print("\t.extern\t%s %d\n", p->name, p->type->size); +} +static void defsymbol(Symbol p) +{ + if (p->scope >= LOCAL && p->sclass == STATIC) + p->x.name = stringf("L.%d", genlabel(1)); + else if (p->generated) + p->x.name = stringf("L.%s", p->name); + else { + assert(p->scope != CONSTANTS || isint(p->type) || isptr(p->type)); + p->x.name = p->name; + } +} +static void address(Symbol q, Symbol p, long n) +{ + if (p->scope == GLOBAL + || p->sclass == STATIC || p->sclass == EXTERN) + q->x.name = stringf("%s%s%D", p->x.name, + n >= 0 ? "+" : "", n); + else { + assert(n <= INT_MAX && n >= INT_MIN); + q->x.offset = p->x.offset + n; + q->x.name = stringd(q->x.offset); + } +} +static void global(Symbol p) +{ + if (p->u.seg == BSS) { + if (p->sclass == STATIC || Aflag >= 2) + print("\t.lcomm\t%s,%d\n", p->x.name, p->type->size); + else + print( "\t.comm\t%s,%d\n", p->x.name, p->type->size); + } else { + if (p->u.seg == DATA + && (p->type->size == 0 || p->type->size > gnum)) + print("\t.data\n"); + else if (p->u.seg == DATA) + print("\t.sdata\n"); + print("\t.align\t%c\n", ".01.2...3"[p->type->align]); + print("%s:\n", p->x.name); + } +} +static void segment(int n) +{ + cseg = n; + switch (n) { + case CODE: print("\t.text\n"); break; + case LIT: print("\t.rdata\n"); break; + } +} +static void space(int n) +{ + if (cseg != BSS) + print("\t.space\t%d\n", n); +} +static void blkloop(int dreg, int doff, int sreg, int soff, int size, int tmps[]) +{ + int lab = genlabel(1); + + print("\taddu\t$%d,$%d,%d\n", sreg, sreg, size&~7); + print("\taddu\t$%d,$%d,%d\n", tmps[2], dreg, size&~7); + blkcopy(tmps[2], doff, sreg, soff, size&7, tmps); + print("L.%d:\n", lab); + print("\taddu\t$%d,$%d,%d\n", sreg, sreg, -8); + print("\taddu\t$%d,$%d,%d\n", tmps[2], tmps[2], -8); + blkcopy(tmps[2], doff, sreg, soff, 8, tmps); + print("\tsltu\t$at,$%d,$%d;\tbnez\t$at,L.%d\n", dreg, tmps[2], lab); +} +static void blkfetch(int size, int off, int reg, int tmp) +{ + assert(size == 1 || size == 2 || size == 4); + if (size == 1) + print("\tlbu\t$%d,%d($%d)\n", tmp, off, reg); + else if (salign >= size && size == 2) + print("\tlhu\t$%d,%d($%d)\n", tmp, off, reg); + else if (salign >= size) + print("\tlw\t$%d,%d($%d)\n", tmp, off, reg); + else if (size == 2) + print("\tulhu\t$%d,%d($%d)\n", tmp, off, reg); + else + print("\tulw\t$%d,%d($%d)\n", tmp, off, reg); +} +static void blkstore(int size, int off, int reg, int tmp) +{ + if (size == 1) + print("\tsb\t$%d,%d($%d)\n", tmp, off, reg); + else if (dalign >= size && size == 2) + print("\tsh\t$%d,%d($%d)\n", tmp, off, reg); + else if (dalign >= size) + print("\tsw\t$%d,%d($%d)\n", tmp, off, reg); + else if (size == 2) + print("\tush\t$%d,%d($%d)\n", tmp, off, reg); + else + print("\tusw\t$%d,%d($%d)\n", tmp, off, reg); +} +static void stabinit(char *, int, char *[]); +static void stabline(Coordinate *); +static void stabsym(Symbol); + +static char *currentfile; + +static int bitcount(unsigned mask) +{ + unsigned i, n = 0; + + for (i = 1; i; i <<= 1) + if (mask&i) + n++; + return n; +} + +/* stabinit - initialize stab output */ +static void stabinit(char *file, int argc, char *argv[]) +{ + if (file) { + print("\t.file\t2,\"%s\"\n", file); + currentfile = file; + } +} + +/* stabline - emit stab entry for source coordinate *cp */ +static void stabline(Coordinate *cp) +{ + if (cp->file && cp->file != currentfile) { + print("\t.file\t2,\"%s\"\n", cp->file); + currentfile = cp->file; + } + print("\t.loc\t2,%d\n", cp->y); +} + +/* stabsym - output a stab entry for symbol p */ +static void stabsym(Symbol p) +{ + if (p == cfunc && IR->stabline) + (*IR->stabline)(&p->src); +} + +Interface mipsebIR = { + { 1, 1, 0 }, /* char */ + { 2, 2, 0 }, /* short */ + { 4, 4, 0 }, /* int */ + { 4, 4, 0 }, /* long */ + { 4, 4, 0 }, /* long long */ + { 4, 4, 1 }, /* float */ + { 8, 8, 1 }, /* double */ + { 8, 8, 1 }, /* long double */ + { 4, 4, 0 }, /* T * */ + { 0, 1, 0 }, /* struct */ + 0, /* little_endian */ + 0, /* mulops_calls */ + 0, /* wants_callb */ + 1, /* wants_argb */ + 1, /* left_to_right */ + 0, /* wants_dag */ + 0, /* unsigned_char */ + address, + blockbeg, + blockend, + defaddress, + defconst, + defstring, + defsymbol, + emit, + export, + function, + gen, + global, + import, + local, + progbeg, + progend, + segment, + space, + 0, 0, 0, stabinit, stabline, stabsym, 0, + { + 4, /* max_unaligned_load */ + rmap, + blkfetch, blkstore, blkloop, + _label, + _rule, + _nts, + _kids, + _string, + _templates, + _isinstruction, + _ntname, + emit2, + doarg, + target, + clobber, + + } +}, mipselIR = { + { 1, 1, 0 }, /* char */ + { 2, 2, 0 }, /* short */ + { 4, 4, 0 }, /* int */ + { 4, 4, 0 }, /* long */ + { 4, 4, 0 }, /* long long */ + { 4, 4, 1 }, /* float */ + { 8, 8, 1 }, /* double */ + { 8, 8, 1 }, /* long double */ + { 4, 4, 0 }, /* T * */ + { 0, 1, 0 }, /* struct */ + 1, /* little_endian */ + 0, /* mulops_calls */ + 0, /* wants_callb */ + 1, /* wants_argb */ + 1, /* left_to_right */ + 0, /* wants_dag */ + 0, /* unsigned_char */ + address, + blockbeg, + blockend, + defaddress, + defconst, + defstring, + defsymbol, + emit, + export, + function, + gen, + global, + import, + local, + progbeg, + progend, + segment, + space, + 0, 0, 0, stabinit, stabline, stabsym, 0, + { + 4, /* max_unaligned_load */ + rmap, + blkfetch, blkstore, blkloop, + _label, + _rule, + _nts, + _kids, + _string, + _templates, + _isinstruction, + _ntname, + emit2, + doarg, + target, + clobber, + + } +}; diff --git a/src/cmd/lccom/null.c b/src/cmd/lccom/null.c new file mode 100644 index 0000000..89034e5 --- /dev/null +++ b/src/cmd/lccom/null.c @@ -0,0 +1,73 @@ +#include "c.h" +#define I(f) null_##f + +static Node I(gen)(Node p) { return p; } +static void I(address)(Symbol q, Symbol p, long n) {} +static void I(blockbeg)(Env *e) {} +static void I(blockend)(Env *e) {} +static void I(defaddress)(Symbol p) {} +static void I(defconst)(int suffix, int size, Value v) {} +static void I(defstring)(int len, char *s) {} +static void I(defsymbol)(Symbol p) {} +static void I(emit)(Node p) {} +static void I(export)(Symbol p) {} +static void I(function)(Symbol f, Symbol caller[], Symbol callee[], int ncalls) {} +static void I(global)(Symbol p) {} +static void I(import)(Symbol p) {} +static void I(local)(Symbol p) {} +static void I(progbeg)(int argc, char *argv[]) {} +static void I(progend)(void) {} +static void I(segment)(int s) {} +static void I(space)(int n) {} +static void I(stabblock)(int brace, int lev, Symbol *p) {} +static void I(stabend)(Coordinate *cp, Symbol p, Coordinate **cpp, Symbol *sp, Symbol *stab) {} +static void I(stabfend)(Symbol p, int lineno) {} +static void I(stabinit)(char *file, int argc, char *argv[]) {} +static void I(stabline)(Coordinate *cp) {} +static void I(stabsym)(Symbol p) {} +static void I(stabtype)(Symbol p) {} + +Interface nullIR = { + { 1, 1, 0 }, /* char */ + { 2, 2, 0 }, /* short */ + { 4, 4, 0 }, /* int */ + { 8, 8, 1 }, /* long */ + { 8 ,8, 1 }, /* long long */ + { 4, 4, 1 }, /* float */ + { 8, 8, 1 }, /* double */ + { 16,16,1 }, /* long double */ + { 4, 4, 0 }, /* T* */ + { 0, 4, 0 }, /* struct */ + 1, /* little_endian */ + 0, /* mulops_calls */ + 0, /* wants_callb */ + 0, /* wants_argb */ + 1, /* left_to_right */ + 0, /* wants_dag */ + 0, /* unsigned_char */ + I(address), + I(blockbeg), + I(blockend), + I(defaddress), + I(defconst), + I(defstring), + I(defsymbol), + I(emit), + I(export), + I(function), + I(gen), + I(global), + I(import), + I(local), + I(progbeg), + I(progend), + I(segment), + I(space), + I(stabblock), + I(stabend), + I(stabfend), + I(stabinit), + I(stabline), + I(stabsym), + I(stabtype) +}; diff --git a/src/cmd/lccom/ops.h b/src/cmd/lccom/ops.h new file mode 100644 index 0000000..09cc79a --- /dev/null +++ b/src/cmd/lccom/ops.h @@ -0,0 +1,131 @@ +gop(CNST,1) + op(CNST,F,fdx) + op(CNST,I,csilh) + op(CNST,P,p) + op(CNST,U,csilh) +gop(ARG,2) + op(ARG,B,-) + op(ARG,F,fdx) + op(ARG,I,ilh) + op(ARG,P,p) + op(ARG,U,ilh) +gop(ASGN,3) + op(ASGN,B,-) + op(ASGN,F,fdx) + op(ASGN,I,csilh) + op(ASGN,P,p) + op(ASGN,U,csilh) +gop(INDIR,4) + op(INDIR,B,-) + op(INDIR,F,fdx) + op(INDIR,I,csilh) + op(INDIR,P,p) + op(INDIR,U,csilh) +gop(CVF,7) + op(CVF,F,fdx) + op(CVF,I,ilh) +gop(CVI,8) + op(CVI,F,fdx) + op(CVI,I,csilh) + op(CVI,U,csilhp) +gop(CVP,9) + op(CVP,U,p) +gop(CVU,11) + op(CVU,I,csilh) + op(CVU,P,p) + op(CVU,U,csilh) +gop(NEG,12) + op(NEG,F,fdx) + op(NEG,I,ilh) +gop(CALL,13) + op(CALL,B,-) + op(CALL,F,fdx) + op(CALL,I,ilh) + op(CALL,P,p) + op(CALL,U,ilh) + op(CALL,V,-) +gop(RET,15) + op(RET,F,fdx) + op(RET,I,ilh) + op(RET,P,p) + op(RET,U,ilh) + op(RET,V,-) +gop(ADDRG,16) + op(ADDRG,P,p) +gop(ADDRF,17) + op(ADDRF,P,p) +gop(ADDRL,18) + op(ADDRL,P,p) +gop(ADD,19) + op(ADD,F,fdx) + op(ADD,I,ilh) + op(ADD,P,p) + op(ADD,U,ilhp) +gop(SUB,20) + op(SUB,F,fdx) + op(SUB,I,ilh) + op(SUB,P,p) + op(SUB,U,ilhp) +gop(LSH,21) + op(LSH,I,ilh) + op(LSH,U,ilh) +gop(MOD,22) + op(MOD,I,ilh) + op(MOD,U,ilh) +gop(RSH,23) + op(RSH,I,ilh) + op(RSH,U,ilh) +gop(BAND,24) + op(BAND,I,ilh) + op(BAND,U,ilh) +gop(BCOM,25) + op(BCOM,I,ilh) + op(BCOM,U,ilh) +gop(BOR,26) + op(BOR,I,ilh) + op(BOR,U,ilh) +gop(BXOR,27) + op(BXOR,I,ilh) + op(BXOR,U,ilh) +gop(DIV,28) + op(DIV,F,fdx) + op(DIV,I,ilh) + op(DIV,U,ilh) +gop(MUL,29) + op(MUL,F,fdx) + op(MUL,I,ilh) + op(MUL,U,ilh) +gop(EQ,30) + op(EQ,F,fdx) + op(EQ,I,ilh) + op(EQ,U,ilhp) +gop(GE,31) + op(GE,F,fdx) + op(GE,I,ilh) + op(GE,U,ilhp) +gop(GT,32) + op(GT,F,fdx) + op(GT,I,ilh) + op(GT,U,ilhp) +gop(LE,33) + op(LE,F,fdx) + op(LE,I,ilh) + op(LE,U,ilhp) +gop(LT,34) + op(LT,F,fdx) + op(LT,I,ilh) + op(LT,U,ilhp) +gop(NE,35) + op(NE,F,fdx) + op(NE,I,ilh) + op(NE,U,ilhp) +gop(JUMP,36) + op(JUMP,V,-) +gop(LABEL,37) + op(LABEL,V,-) +gop(LOAD,14) + op(LOAD,B,-) + op(LOAD,F,fdx) + op(LOAD,I,csilh) + op(LOAD,P,p) + op(LOAD,U,csilhp) diff --git a/src/cmd/lccom/output.c b/src/cmd/lccom/output.c new file mode 100644 index 0000000..3fa56dd --- /dev/null +++ b/src/cmd/lccom/output.c @@ -0,0 +1,133 @@ +#include "c.h" + +static char *outs(const char *str, FILE *f, char *bp) { + if (f) + fputs(str, f); + else + while ((*bp = *str++)) + bp++; + return bp; +} + +static char *outd(long n, FILE *f, char *bp) { + unsigned long m; + char buf[25], *s = buf + sizeof buf; + + *--s = '\0'; + if (n < 0) + m = -n; + else + m = n; + do + *--s = m%10 + '0'; + while ((m /= 10) != 0); + if (n < 0) + *--s = '-'; + return outs(s, f, bp); +} + +static char *outu(unsigned long n, int base, FILE *f, char *bp) { + char buf[25], *s = buf + sizeof buf; + + *--s = '\0'; + do + *--s = "0123456789abcdef"[n%base]; + while ((n /= base) != 0); + return outs(s, f, bp); +} +void print(const char *fmt, ...) { + va_list ap; + + va_start(ap, fmt); + vfprint(stdout, NULL, fmt, ap); + va_end(ap); +} +/* fprint - formatted output to f */ +void fprint(FILE *f, const char *fmt, ...) { + va_list ap; + + va_start(ap, fmt); + vfprint(f, NULL, fmt, ap); + va_end(ap); +} + +/* stringf - formatted output to a saved string */ +char *stringf(const char *fmt, ...) { + char buf[1024]; + va_list ap; + + va_start(ap, fmt); + vfprint(NULL, buf, fmt, ap); + va_end(ap); + return string(buf); +} + +/* vfprint - formatted output to f or string bp */ +void vfprint(FILE *f, char *bp, const char *fmt, va_list ap) { + for (; *fmt; fmt++) + if (*fmt == '%') + switch (*++fmt) { + case 'd': bp = outd(va_arg(ap, int), f, bp); break; + case 'D': bp = outd(va_arg(ap, long), f, bp); break; + case 'U': bp = outu(va_arg(ap, unsigned long), 10, f, bp); break; + case 'u': bp = outu(va_arg(ap, unsigned), 10, f, bp); break; + case 'o': bp = outu(va_arg(ap, unsigned), 8, f, bp); break; + case 'X': bp = outu(va_arg(ap, unsigned long), 16, f, bp); break; + case 'x': bp = outu(va_arg(ap, unsigned), 16, f, bp); break; + case 'f': case 'e': + case 'g': { + static char format[] = "%f"; + char buf[128]; + format[1] = *fmt; + sprintf(buf, format, va_arg(ap, double)); + bp = outs(buf, f, bp); + } +; break; + case 's': bp = outs(va_arg(ap, char *), f, bp); break; + case 'p': { + void *p = va_arg(ap, void *); + if (p) + bp = outs("0x", f, bp); + bp = outu((unsigned long)p, 16, f, bp); + break; + } + case 'c': if (f) fputc(va_arg(ap, int), f); else *bp++ = va_arg(ap, int); break; + case 'S': { char *s = va_arg(ap, char *); + int n = va_arg(ap, int); + if (s) + for ( ; n-- > 0; s++) + if (f) (void)putc(*s, f); else *bp++ = *s; + } break; + case 'k': { int t = va_arg(ap, int); + static char *tokens[] = { +#define xx(a,b,c,d,e,f,g) g, +#define yy(a,b,c,d,e,f,g) g, +#include "token.h" + }; + assert(tokens[t&0177]); + bp = outs(tokens[t&0177], f, bp); + } break; + case 't': { Type ty = va_arg(ap, Type); + assert(f); + outtype(ty ? ty : voidtype, f); + } break; + case 'w': { Coordinate *p = va_arg(ap, Coordinate *); + if (p->file && *p->file) { + bp = outs(p->file, f, bp); + bp = outs(":", f, bp); + } + bp = outd(p->y, f, bp); + } break; + case 'I': { int n = va_arg(ap, int); + while (--n >= 0) + if (f) (void)putc(' ', f); else *bp++ = ' '; + } break; + default: if (f) (void)putc(*fmt, f); else *bp++ = *fmt; break; + } + else if (f) + (void)putc(*fmt, f); + else + *bp++ = *fmt; + if (!f) + *bp = '\0'; +} diff --git a/src/cmd/lccom/prof.c b/src/cmd/lccom/prof.c new file mode 100644 index 0000000..b3a922d --- /dev/null +++ b/src/cmd/lccom/prof.c @@ -0,0 +1,231 @@ +#include "c.h" + +struct callsite { + char *file, *name; + union coordinate { + unsigned int coord; + struct { unsigned int y:16,x:10,index:6; } le; + struct { unsigned int index:6,x:10,y:16; } be; + } u; +}; +struct func { + struct func *link; + struct caller *callers; + char *name; + union coordinate src; +}; +struct map { /* source code map; 200 coordinates/map */ + int size; + union coordinate u[200]; +}; + +int npoints; /* # of execution points if -b specified */ +int ncalled = -1; /* #times prof.out says current function was called */ +static Symbol YYlink; /* symbol for file's struct _bbdata */ +static Symbol YYcounts; /* symbol for _YYcounts if -b specified */ +static List maplist; /* list of struct map *'s */ +static List filelist; /* list of file names */ +static Symbol funclist; /* list of struct func *'s */ +static Symbol afunc; /* current function's struct func */ + +/* bbpad - emit space, if necessary, to make size%align == 0; return new size */ +static int bbpad(int size, int align) { + if (size%align) { + (*IR->space)(align - size%align); + size = roundup(size, align); + } + return size; +} + +/* bbcall - build tree to set _callsite at call site *cp, emit call site data */ +static void bbcall(Symbol yycounts, Coordinate *cp, Tree *e) { + static Symbol caller; + Value v; + union coordinate u; + Symbol p = genident(STATIC, array(voidptype, 0, 0), GLOBAL); + Tree t; + + defglobal(p, LIT); + defpointer(cp->file ? mkstr(cp->file)->u.c.loc : (Symbol)0); + defpointer(mkstr(cfunc->name)->u.c.loc); + if (IR->little_endian) { + u.le.x = cp->x; + u.le.y = cp->y; + } else { + u.be.x = cp->x; + u.be.y = cp->y; + } + (*IR->defconst)(U, unsignedtype->size, (v.u = u.coord, v)); + bbpad(2*voidptype->size + unsignedtype->size, p->type->align); + if (caller == 0) { + caller = mksymbol(EXTERN, "_caller", ptr(voidptype)); + caller->defined = 0; + } + for (t = *e; generic(t->op) != CALL; t = t->kids[0]) + assert(t->op == RIGHT || !t->kids[1]); + assert(generic(t->op) == CALL); + t = tree(t->op, t->type, + tree(RIGHT, t->kids[0]->type, + t->kids[0], + tree(RIGHT, t->kids[0]->type, asgn(caller, idtree(p)), t->kids[0])), + t->kids[1]); + for ( ; generic((*e)->op) != CALL; e = &(*e)->kids[0]) + ; + *e = t; +} + +/* bbentry - return tree for _prologue(&afunc, &YYlink)' */ +static void bbentry(Symbol yylink, Symbol f, void *ignore) { + static Symbol prologue; + + afunc = genident(STATIC, array(voidptype, 4, 0), GLOBAL); + if (prologue == 0) { + prologue = mksymbol(EXTERN, "_prologue", ftype(inttype, voidptype, voidptype, NULL)); + prologue->defined = 0; + } + walk(vcall(prologue, voidtype, pointer(idtree(afunc)), pointer(idtree(yylink)), NULL), 0, 0); +} + +/* bbexit - return tree for _epilogue(&afunc)' */ +static void bbexit(Symbol yylink, Symbol f, Tree e) { + static Symbol epilogue; + + if (epilogue == 0) { + epilogue = mksymbol(EXTERN, "_epilogue", ftype(inttype, voidptype, NULL)); + epilogue->defined = 0; + } + walk(vcall(epilogue, voidtype, pointer(idtree(afunc)), NULL), 0, 0); +} + +/* bbfile - add file to list of file names, return its index */ +static int bbfile(char *file) { + if (file) { + List lp; + int i = 1; + if ((lp = filelist) != NULL) + do { + lp = lp->link; + if (((Symbol)lp->x)->u.c.v.p == file) + return i; + i++; + } while (lp != filelist); + filelist = append(mkstr(file), filelist); + return i; + } + return 0; +} + +/* bbfunc - emit function name and src coordinates */ +static void bbfunc(Symbol yylink, Symbol f, void *ignore) { + Value v; + union coordinate u; + + defglobal(afunc, DATA); + defpointer(funclist); + defpointer(NULL); + defpointer(mkstr(f->name)->u.c.loc); + if (IR->little_endian) { + u.le.x = f->u.f.pt.x; + u.le.y = f->u.f.pt.y; + u.le.index = bbfile(f->u.f.pt.file); + } else { + u.be.x = f->u.f.pt.x; + u.be.y = f->u.f.pt.y; + u.be.index = bbfile(f->u.f.pt.file); + } + (*IR->defconst)(U, unsignedtype->size, (v.u = u.coord, v)); + bbpad(3*voidptype->size + unsignedtype->size, afunc->type->align); + funclist = afunc; +} + +/* bbincr - build tree to increment execution point at *cp */ +static void bbincr(Symbol yycounts, Coordinate *cp, Tree *e) { + struct map *mp = maplist->x; + Tree t; + + if (needconst) + return; + /* append *cp to source map */ + if (mp->size >= NELEMS(mp->u)) { + NEW(mp, PERM); + mp->size = 0; + maplist = append(mp, maplist); + } + if (IR->little_endian) { + mp->u[mp->size].le.x = cp->x; + mp->u[mp->size].le.y = cp->y; + mp->u[mp->size++].le.index = bbfile(cp->file); + } else { + mp->u[mp->size].be.x = cp->x; + mp->u[mp->size].be.y = cp->y; + mp->u[mp->size++].be.index = bbfile(cp->file); + } + t = incr('+', rvalue((*optree['+'])(ADD, pointer(idtree(yycounts)), + consttree(npoints++, inttype))), consttree(1, inttype)); + if (*e) + *e = tree(RIGHT, (*e)->type, t, *e); + else + *e = t; +} + +/* bbvars - emit definition for basic block counting data */ +static void bbvars(Symbol yylink, void *ignore, void *ignore2) { + int i, j, n = npoints; + Value v; + struct map **mp; + Symbol coords, files, *p; + + if (!YYcounts && !yylink) + return; + if (YYcounts) { + if (n <= 0) + n = 1; + YYcounts->type = array(inttype, n, 0); + defglobal(YYcounts, BSS); + (*IR->space)(YYcounts->type->size); + } + files = genident(STATIC, array(charptype, 1, 0), GLOBAL); + defglobal(files, LIT); + for (p = ltov(&filelist, PERM); *p; p++) + defpointer((*p)->u.c.loc); + defpointer(NULL); + coords = genident(STATIC, array(unsignedtype, n, 0), GLOBAL); + defglobal(coords, LIT); + for (i = n, mp = ltov(&maplist, PERM); *mp; i -= (*mp)->size, mp++) + for (j = 0; j < (*mp)->size; j++) + (*IR->defconst)(U, unsignedtype->size, (v.u = (*mp)->u[j].coord, v)); + if (i > 0) + (*IR->space)(i*coords->type->type->size); + (*IR->defconst)(U, unsignedtype->size, (v.u = 0, v)); + defglobal(yylink, DATA); + defpointer(NULL); + (*IR->defconst)(U, inttype->size, (v.u = n, v)); + bbpad(voidptype->size + inttype->size, yylink->type->align); + defpointer(YYcounts); + defpointer(coords); + defpointer(files); + defpointer(funclist); +} + +/* profInit - initialize basic block profiling options */ +void profInit(char *arg) { + if (strncmp(arg, "-a", 2) == 0) { + if (ncalled == -1 + && process(arg[2] ? &arg[2] : "prof.out") > 0) + ncalled = 0; + } else if ((strcmp(arg, "-b") == 0 + || strcmp(arg, "-C") == 0) && YYlink == 0) { + YYlink = genident(STATIC, array(voidptype, 0, 0), GLOBAL); + attach((Apply)bbentry, YYlink, &events.entry); + attach((Apply)bbexit, YYlink, &events.returns); + attach((Apply)bbfunc, YYlink, &events.exit); + attach((Apply)bbvars, YYlink, &events.end); + if (strcmp(arg, "-b") == 0) { + YYcounts = genident(STATIC, array(inttype, 0, 0), GLOBAL); + maplist = append(allocate(sizeof (struct map), PERM), maplist); + ((struct map *)maplist->x)->size = 0; + attach((Apply)bbcall, YYcounts, &events.calls); + attach((Apply)bbincr, YYcounts, &events.points); + } + } +} diff --git a/src/cmd/lccom/profio.c b/src/cmd/lccom/profio.c new file mode 100644 index 0000000..22be5e3 --- /dev/null +++ b/src/cmd/lccom/profio.c @@ -0,0 +1,285 @@ +/* + * C compiler: prof.out input + * + * prof.out format: + * #files + * name + * ... (#files-1 times) + * #functions + * name file# x y count caller file x y + * ... (#functions-1 times) + * #points + * file# x y count + * ... (#points-1 times) + */ +#include "c.h" + +struct count { /* count data: */ + int x, y; /* source coordinate */ + int count; /* associated execution count */ +}; + +#define MAXTOKEN 64 + +struct file { /* per-file prof.out data: */ + struct file *link; /* link to next file */ + char *name; /* file name */ + int size; /* size of counts[] */ + int count; /* counts[0..count-1] hold valid data */ + struct count *counts; /* count data */ + struct func { /* function data: */ + struct func *link; /* link to next function */ + char *name; /* function name */ + struct count count; /* total number of calls */ + struct caller { /* caller data: */ + struct caller *link; /* link to next caller */ + char *name; /* caller's name */ + char *file; /* call site: file, x, y */ + int x, y; + int count; /* number of calls from this site */ + } *callers; + } *funcs; /* list of functions */ +} *filelist; +FILE *fp; + +/* acaller - add caller and site (file,x,y) to callee's callers list */ +static void acaller(char *caller, char *file, int x, int y, int count, struct func *callee) { + struct caller *q; + + assert(callee); + for (q = callee->callers; q && (caller != q->name + || file != q->file || x != q->x || y != q->y); q = q->link) + ; + if (!q) { + struct caller **r; + NEW(q, PERM); + q->name = caller; + q->file = file; + q->x = x; + q->y = y; + q->count = 0; + for (r = &callee->callers; *r && (strcmp(q->name, (*r)->name) > 0 + || strcmp(q->file, (*r)->file) > 0 || q->y > (*r)->y || q->y > (*r)->y); r = &(*r)->link) + ; + q->link = *r; + *r = q; + } + q->count += count; +} + +/* compare - return <0, 0, >0 if ab, resp. */ +static int compare(const void *x, const void *y) { + struct count *a = (struct count *)x, *b = (struct count *)y; + + if (a->y == b->y) + return a->x - b->x; + return a->y - b->y; +} + +/* findfile - return file name's file list entry, or 0 */ +static struct file *findfile(char *name) { + struct file *p; + + for (p = filelist; p; p = p->link) + if (p->name == name) + return p; + return 0; +} + +/* afunction - add function name and its data to file's function list */ +static struct func *afunction(char *name, char *file, int x, int y, int count) { + struct file *p = findfile(file); + struct func *q; + + assert(p); + for (q = p->funcs; q && name != q->name; q = q->link) + ; + if (!q) { + struct func **r; + NEW(q, PERM); + q->name = name; + q->count.x = x; + q->count.y = y; + q->count.count = 0; + q->callers = 0; + for (r = &p->funcs; *r && compare(&q->count, &(*r)->count) > 0; r = &(*r)->link) + ; + q->link = *r; + *r = q; + } + q->count.count += count; + return q; +} + +/* apoint - append execution point i to file's data */ +static void apoint(int i, char *file, int x, int y, int count) { + struct file *p = findfile(file); + + assert(p); + if (i >= p->size) { + int j; + if (p->size == 0) { + p->size = i >= 200 ? 2*i : 200; + p->counts = newarray(p->size, sizeof *p->counts, PERM); + } else { + struct count *new; + p->size = 2*i; + new = newarray(p->size, sizeof *new, PERM); + for (j = 0; j < p->count; j++) + new[j] = p->counts[j]; + p->counts = new; + } + for (j = p->count; j < p->size; j++) { + static struct count z; + p->counts[j] = z; + } + } + if (p->counts[i].x != x || p->counts[i].y != y) + for (i = 0; i < p->count; i++) + if (p->counts[i].x == x && p->counts[i].y == y) + break; + if (i >= p->count) + if (i >= p->size) + apoint(i, file, x, y, count); + else { + p->count = i + 1; + p->counts[i].x = x; + p->counts[i].y = y; + p->counts[i].count = count; + } + else + p->counts[i].count += count; +} + +/* findcount - return count associated with (file,x,y) or -1 */ +int findcount(char *file, int x, int y) { + static struct file *cursor; + + if (cursor == 0 || cursor->name != file) + cursor = findfile(file); + if (cursor) { + int l, u; + struct count *c = cursor->counts; + for (l = 0, u = cursor->count - 1; l <= u; ) { + int k = (l + u)/2; + if (c[k].y > y || (c[k].y == y && c[k].x > x)) + u = k - 1; + else if (c[k].y < y || (c[k].y == y && c[k].x < x)) + l = k + 1; + else + return c[k].count; + } + } + return -1; +} + +/* findfunc - return count associated with function name in file or -1 */ +int findfunc(char *name, char *file) { + static struct file *cursor; + + if (cursor == 0 || cursor->name != file) + cursor = findfile(file); + if (cursor) { + struct func *p; + for (p = cursor->funcs; p; p = p->link) + if (p->name == name) + return p->count.count; + } + return -1; +} + +/* getd - read a nonnegative number */ +static int getd(void) { + int c, n = 0; + + while ((c = getc(fp)) != EOF && (c == ' ' || c == '\n' || c == '\t')) + ; + if (c >= '0' && c <= '9') { + do + n = 10*n + (c - '0'); + while ((c = getc(fp)) >= '0' && c <= '9'); + return n; + } + return -1; +} + +/* getstr - read a string */ +static char *getstr(void) { + int c; + char buf[MAXTOKEN], *s = buf; + + while ((c = getc(fp)) != EOF && c != ' ' && c != '\n' && c != '\t') + if (s - buf < (int)sizeof buf - 2) + *s++ = c; + *s = 0; + return s == buf ? (char *)0 : string(buf); +} + +/* gather - read prof.out data from fd */ +static int gather(void) { + int i, nfiles, nfuncs, npoints; + char *files[64]; + + if ((nfiles = getd()) < 0) + return 0; + assert(nfiles < NELEMS(files)); + for (i = 0; i < nfiles; i++) { + if ((files[i] = getstr()) == 0) + return -1; + if (!findfile(files[i])) { + struct file *new; + NEW(new, PERM); + new->name = files[i]; + new->size = new->count = 0; + new->counts = 0; + new->funcs = 0; + new->link = filelist; + filelist = new; + } + } + if ((nfuncs = getd()) < 0) + return -1; + for (i = 0; i < nfuncs; i++) { + struct func *q; + char *name, *file; + int f, x, y, count; + if ((name = getstr()) == 0 || (f = getd()) <= 0 + || (x = getd()) < 0 || (y = getd()) < 0 || (count = getd()) < 0) + return -1; + q = afunction(name, files[f-1], x, y, count); + if ((name = getstr()) == 0 || (file = getstr()) == 0 + || (x = getd()) < 0 || (y = getd()) < 0) + return -1; + if (*name != '?') + acaller(name, file, x, y, count, q); + } + if ((npoints = getd()) < 0) + return -1; + for (i = 0; i < npoints; i++) { + int f, x, y, count; + if ((f = getd()) < 0 || (x = getd()) < 0 || (y = getd()) < 0 + || (count = getd()) < 0) + return -1; + if (f) + apoint(i, files[f-1], x, y, count); + } + return 1; +} + +/* process - read prof.out data from file */ +int process(char *file) { + int more; + + if ((fp = fopen(file, "r")) != NULL) { + struct file *p; + while ((more = gather()) > 0) + ; + fclose(fp); + if (more < 0) + return more; + for (p = filelist; p; p = p->link) + qsort(p->counts, p->count, sizeof *p->counts, compare); + return 1; + } + return 0; +} diff --git a/src/cmd/lccom/simp.c b/src/cmd/lccom/simp.c new file mode 100644 index 0000000..b8d6133 --- /dev/null +++ b/src/cmd/lccom/simp.c @@ -0,0 +1,614 @@ +#include "c.h" +#include + +#define foldcnst(TYPE,VAR,OP) \ + if (l->op == CNST+TYPE && r->op == CNST+TYPE) \ + return cnsttree(ty, l->u.v.VAR OP r->u.v.VAR) +#define commute(L,R) \ + if (generic(R->op) == CNST && generic(L->op) != CNST) \ + do { Tree t = L; L = R; R = t; } while(0) +#define xfoldcnst(TYPE,VAR,OP,FUNC)\ + if (l->op == CNST+TYPE && r->op == CNST+TYPE\ + && FUNC(l->u.v.VAR,r->u.v.VAR,\ + ty->u.sym->u.limits.min.VAR,\ + ty->u.sym->u.limits.max.VAR, needconst)) \ + return cnsttree(ty, l->u.v.VAR OP r->u.v.VAR) +#define xcvtcnst(FTYPE,SRC,DST,VAR,EXPR) \ + if (l->op == CNST+FTYPE) do {\ + if (!explicitCast\ + && ((SRC) < DST->u.sym->u.limits.min.VAR || (SRC) > DST->u.sym->u.limits.max.VAR))\ + warning("overflow in converting constant expression from `%t' to `%t'\n", l->type, DST);\ + if (needconst\ + || !((SRC) < DST->u.sym->u.limits.min.VAR || (SRC) > DST->u.sym->u.limits.max.VAR))\ + return cnsttree(ty, (EXPR)); } while(0) +#define identity(X,Y,TYPE,VAR,VAL) \ + if (X->op == CNST+TYPE && X->u.v.VAR == VAL) return Y +#define zerofield(OP,TYPE,VAR) \ + if (l->op == FIELD \ + && r->op == CNST+TYPE && r->u.v.VAR == 0)\ + return eqtree(OP, bittree(BAND, l->kids[0],\ + cnsttree(unsignedtype, \ + (unsigned long)fieldmask(l->u.field)<u.field))), r) +#define cfoldcnst(TYPE,VAR,OP) \ + if (l->op == CNST+TYPE && r->op == CNST+TYPE) \ + return cnsttree(inttype, (long)(l->u.v.VAR OP r->u.v.VAR)) +#define foldaddp(L,R,RTYPE,VAR) \ + if (L->op == CNST+P && R->op == CNST+RTYPE) { \ + Tree e = tree(CNST+P, ty, NULL, NULL);\ + e->u.v.p = (char *)L->u.v.p + R->u.v.VAR;\ + return e; } +#define ufoldcnst(TYPE,EXP) if (l->op == CNST+TYPE) return EXP +#define sfoldcnst(OP) \ + if (l->op == CNST+U && r->op == CNST+I \ + && r->u.v.i >= 0 && r->u.v.i < 8*l->type->size) \ + return cnsttree(ty, (unsigned long)(l->u.v.u OP r->u.v.i)) +#define geu(L,R,V) \ + if (R->op == CNST+U && R->u.v.u == 0) do { \ + warning("result of unsigned comparison is constant\n"); \ + return tree(RIGHT, inttype, root(L), cnsttree(inttype, (long)(V))); } while(0) +#define idempotent(OP) if (l->op == OP) return l->kids[0] + +int needconst; +int explicitCast; + +static int addi(long x, long y, long min, long max, int needconst) +{ + int cond = x == 0 + || y == 0 + || (x < 0 && y < 0 && x >= min - y) + || (x < 0 && y > 0) + || (x > 0 && y < 0) + || (x > 0 && y > 0 && x <= max - y); + + if (!cond && needconst) { + warning("overflow in constant expression\n"); + cond = 1; + } + return cond; + + +} + +static int addd(double x, double y, double min, double max, int needconst) +{ + int cond = x == 0 + || y == 0 + || (x < 0 && y < 0 && x >= min - y) + || (x < 0 && y > 0) + || (x > 0 && y < 0) + || (x > 0 && y > 0 && x <= max - y); + + if (!cond && needconst) { + warning("overflow in constant expression\n"); + cond = 1; + } + return cond; + + +} + +static Tree addrtree(Tree e, long n, Type ty) { + Symbol p = e->u.sym, q; + + if (p->scope == GLOBAL + || p->sclass == STATIC || p->sclass == EXTERN) + NEW0(q, PERM); + else + NEW0(q, FUNC); + q->name = stringd(genlabel(1)); + q->sclass = p->sclass; + q->scope = p->scope; + assert(isptr(ty) || isarray(ty)); + q->type = isptr(ty) ? ty->type : ty; + q->temporary = p->temporary; + q->generated = p->generated; + q->addressed = p->addressed; + q->computed = 1; + q->defined = 1; + q->ref = 1; + assert(IR->address); + if (p->scope == GLOBAL + || p->sclass == STATIC || p->sclass == EXTERN) { + if (p->sclass == AUTO) + q->sclass = STATIC; + (*IR->address)(q, p, n); + } else { + Code cp; + addlocal(p); + cp = code(Address); + cp->u.addr.sym = q; + cp->u.addr.base = p; + cp->u.addr.offset = n; + } + e = tree(e->op, ty, NULL, NULL); + e->u.sym = q; + return e; +} + +/* div[id] - return 1 if min <= x/y <= max, 0 otherwise */ +static int divi(long x, long y, long min, long max, int needconst) { + int cond = y != 0 && !(x == min && y == -1); + if (!cond && needconst) { + warning("overflow in constant expression\n"); + cond = 1; + } + return cond; + + +} + +static int divd(double x, double y, double min, double max, int needconst) { + int cond; + + if (x < 0) x = -x; + if (y < 0) y = -y; + cond = y != 0 && !(y < 1 && x > max*y); + if (!cond && needconst) { + warning("overflow in constant expression\n"); + cond = 1; + } + return cond; + +} + +/* mul[id] - return 1 if min <= x*y <= max, 0 otherwise */ +static int muli(long x, long y, long min, long max, int needconst) +{ + int cond = (x > -1 && x <= 1) + || (y > -1 && y <= 1) + || (x < 0 && y < 0 && -x <= max/-y) + || (x < 0 && y > 0 && x >= min/y) + || (x > 0 && y < 0 && y >= min/x) + || (x > 0 && y > 0 && x <= max/y); + + if (! cond && needconst) { + warning("overflow in constant expression\n"); + cond = 1; + } + return cond; +} + +static int muld(double x, double y, double min, double max, int needconst) +{ + int cond = ((x >= -1 && x <= 1) + || (y >= -1 && y <= 1) + || (x < 0 && y < 0 && -x <= max/-y) + || (x < 0 && y > 0 && x >= min/y) + || (x > 0 && y < 0 && y >= min/x) + || (x > 0 && y > 0 && x <= max/y)); + + if (! cond && needconst) { + warning("overflow in constant expression\n"); + cond = 1; + } + return cond; + + +} +/* sub[id] - return 1 if min <= x-y <= max, 0 otherwise */ +static int subi(long x, long y, long min, long max, int needconst) { + return addi(x, -y, min, max, needconst); +} + +static int subd(double x, double y, double min, double max, int needconst) { + return addd(x, -y, min, max, needconst); +} +Tree constexpr(int tok) { + Tree p; + + needconst++; + p = expr1(tok); + needconst--; + return p; +} + +int intexpr(int tok, int n) { + Tree p = constexpr(tok); + + needconst++; + if (p->op == CNST+I || p->op == CNST+U) + n = cast(p, inttype)->u.v.i; + else + error("integer expression must be constant\n"); + needconst--; + return n; +} + +Tree simplify(int op, Type ty, Tree l, Tree r) +{ + int n; + + if (optype(op) == 0) + op = mkop(op, ty); + switch (op) { + case ADD+U: + foldcnst(U,u,+); + commute(r,l); + identity(r,l,U,u,0); + break; + case ADD+I: + xfoldcnst(I,i,+,addi); + commute(r,l); + identity(r,l,I,i,0); + break; + case CVI+I: + xcvtcnst(I,l->u.v.i,ty,i,(long)extend(l->u.v.i,ty)); + break; + case CVU+I: + if (l->op == CNST+U) { + if (!explicitCast && l->u.v.u > ty->u.sym->u.limits.max.i) + warning("overflow in converting constant expression from `%t' to `%t'\n", l->type, ty); + if (needconst || !(l->u.v.u > ty->u.sym->u.limits.max.i)) + return cnsttree(ty, (long)extend(l->u.v.u,ty)); + } + break; + case CVP+U: + xcvtcnst(P,(unsigned long)l->u.v.p,ty,u,(unsigned long)l->u.v.p); + break; + case CVU+P: + xcvtcnst(U,(void*)l->u.v.u,ty,p,(void*)l->u.v.u); + break; + case CVP+P: + xcvtcnst(P,l->u.v.p,ty,p,l->u.v.p); + break; + case CVI+U: + xcvtcnst(I,l->u.v.i,ty,u,((unsigned long)l->u.v.i)&ones(8*ty->size)); + break; + case CVU+U: + xcvtcnst(U,l->u.v.u,ty,u,l->u.v.u&ones(8*ty->size)); + break; + + case CVI+F: + xcvtcnst(I,l->u.v.i,ty,d,(long double)l->u.v.i); + case CVU+F: + xcvtcnst(U,l->u.v.u,ty,d,(long double)l->u.v.u); + break; + case CVF+I: + xcvtcnst(F,l->u.v.d,ty,i,(long)l->u.v.d); + break; + case CVF+F: { + float d; + if (l->op == CNST+F) { + if (l->u.v.d < ty->u.sym->u.limits.min.d) + d = ty->u.sym->u.limits.min.d; + else if (l->u.v.d > ty->u.sym->u.limits.max.d) + d = ty->u.sym->u.limits.max.d; + else + d = l->u.v.d; + } + xcvtcnst(F,l->u.v.d,ty,d,(long double)d); + break; + } + case BAND+U: + foldcnst(U,u,&); + commute(r,l); + identity(r,l,U,u,ones(8*ty->size)); + if (r->op == CNST+U && r->u.v.u == 0) + return tree(RIGHT, ty, root(l), cnsttree(ty, 0UL)); + break; + case BAND+I: + foldcnst(I,i,&); + commute(r,l); + identity(r,l,I,i,ones(8*ty->size)); + if (r->op == CNST+I && r->u.v.u == 0) + return tree(RIGHT, ty, root(l), cnsttree(ty, 0L)); + break; + + case MUL+U: + commute(l,r); + if (l->op == CNST+U && (n = ispow2(l->u.v.u)) != 0) + return simplify(LSH, ty, r, cnsttree(inttype, (long)n)); + foldcnst(U,u,*); + identity(r,l,U,u,1); + break; + case NE+I: + cfoldcnst(I,i,!=); + commute(r,l); + zerofield(NE,I,i); + break; + + case EQ+I: + cfoldcnst(I,i,==); + commute(r,l); + zerofield(EQ,I,i); + break; + case ADD+P: + foldaddp(l,r,I,i); + foldaddp(l,r,U,u); + foldaddp(r,l,I,i); + foldaddp(r,l,U,u); + commute(r,l); + identity(r,retype(l,ty),I,i,0); + identity(r,retype(l,ty),U,u,0); + /* + Some assemblers, e.g., the MIPS, can't handle offsets + larger than 16 bits. A better solution would be to change + the interface so that address() could fail. + */ + if (l->op == ADDRG+P && l->u.sym->generated + && ((r->op == CNST+I && (r->u.v.i > 32767 || r->u.v.i < -32768)) + || (r->op == CNST+U && r->u.v.u > 65536))) + break; + if (IR->address + && isaddrop(l->op) + && ((r->op == CNST+I && r->u.v.i <= longtype->u.sym->u.limits.max.i + && r->u.v.i >= longtype->u.sym->u.limits.min.i) + || (r->op == CNST+U && r->u.v.u <= longtype->u.sym->u.limits.max.i))) + return addrtree(l, cast(r, longtype)->u.v.i, ty); + if (IR->address + && l->op == ADD+P && isaddrop(l->kids[1]->op) + && ((r->op == CNST+I && r->u.v.i <= longtype->u.sym->u.limits.max.i + && r->u.v.i >= longtype->u.sym->u.limits.min.i) + || (r->op == CNST+U && r->u.v.u <= longtype->u.sym->u.limits.max.i))) + return simplify(ADD+P, ty, l->kids[0], + addrtree(l->kids[1], cast(r, longtype)->u.v.i, ty)); + if ((l->op == ADD+I || l->op == SUB+I) + && l->kids[1]->op == CNST+I && isaddrop(r->op)) + return simplify(ADD+P, ty, l->kids[0], + simplify(generic(l->op)+P, ty, r, l->kids[1])); + if (l->op == ADD+P && generic(l->kids[1]->op) == CNST + && generic(r->op) == CNST) + return simplify(ADD+P, ty, l->kids[0], + simplify(ADD, l->kids[1]->type, l->kids[1], r)); + if (l->op == ADD+I && generic(l->kids[1]->op) == CNST + && r->op == ADD+P && generic(r->kids[1]->op) == CNST) + return simplify(ADD+P, ty, l->kids[0], + simplify(ADD+P, ty, r->kids[0], + simplify(ADD, r->kids[1]->type, l->kids[1], r->kids[1]))); + if (l->op == RIGHT && l->kids[1]) + return tree(RIGHT, ty, l->kids[0], + simplify(ADD+P, ty, l->kids[1], r)); + else if (l->op == RIGHT && l->kids[0]) + return tree(RIGHT, ty, + simplify(ADD+P, ty, l->kids[0], r), NULL); + break; + + case ADD+F: + xfoldcnst(F,d,+,addd); + commute(r,l); + break; + case AND+I: + op = AND; + ufoldcnst(I,l->u.v.i ? cond(r) : l); /* 0&&r => 0, 1&&r => r */ + break; + case OR+I: + op = OR; + /* 0||r => r, 1||r => 1 */ + ufoldcnst(I,l->u.v.i ? cnsttree(ty, 1L) : cond(r)); + break; + case BCOM+I: + ufoldcnst(I,cnsttree(ty, (long)extend((~l->u.v.i)&ones(8*ty->size), ty))); + idempotent(BCOM+U); + break; + case BCOM+U: + ufoldcnst(U,cnsttree(ty, (unsigned long)((~l->u.v.u)&ones(8*ty->size)))); + idempotent(BCOM+U); + break; + case BOR+U: + foldcnst(U,u,|); + commute(r,l); + identity(r,l,U,u,0); + break; + case BOR+I: + foldcnst(I,i,|); + commute(r,l); + identity(r,l,I,i,0); + break; + case BXOR+U: + foldcnst(U,u,^); + commute(r,l); + identity(r,l,U,u,0); + break; + case BXOR+I: + foldcnst(I,i,^); + commute(r,l); + identity(r,l,I,i,0); + break; + case DIV+F: + xfoldcnst(F,d,/,divd); + break; + case DIV+I: + identity(r,l,I,i,1); + if ((r->op == CNST+I && r->u.v.i == 0) + || (l->op == CNST+I && l->u.v.i == ty->u.sym->u.limits.min.i + && r->op == CNST+I && r->u.v.i == -1)) + break; + xfoldcnst(I,i,/,divi); + break; + case DIV+U: + identity(r,l,U,u,1); + if (r->op == CNST+U && r->u.v.u == 0) + break; + if (r->op == CNST+U && (n = ispow2(r->u.v.u)) != 0) + return simplify(RSH, ty, l, cnsttree(inttype, (long)n)); + foldcnst(U,u,/); + break; + case EQ+F: + cfoldcnst(F,d,==); + commute(r,l); + break; + case EQ+U: + cfoldcnst(U,u,==); + commute(r,l); + zerofield(EQ,U,u); + break; + case GE+F: cfoldcnst(F,d,>=); break; + case GE+I: cfoldcnst(I,i,>=); break; + case GE+U: + geu(l,r,1); /* l >= 0 => (l,1) */ + cfoldcnst(U,u,>=); + if (l->op == CNST+U && l->u.v.u == 0) /* 0 >= r => r == 0 */ + return eqtree(EQ, r, l); + break; + case GT+F: cfoldcnst(F,d, >); break; + case GT+I: cfoldcnst(I,i, >); break; + case GT+U: + geu(r,l,0); /* 0 > r => (r,0) */ + cfoldcnst(U,u, >); + if (r->op == CNST+U && r->u.v.u == 0) /* l > 0 => l != 0 */ + return eqtree(NE, l, r); + break; + case LE+F: cfoldcnst(F,d,<=); break; + case LE+I: cfoldcnst(I,i,<=); break; + case LE+U: + geu(r,l,1); /* 0 <= r => (r,1) */ + cfoldcnst(U,u,<=); + if (r->op == CNST+U && r->u.v.u == 0) /* l <= 0 => l == 0 */ + return eqtree(EQ, l, r); + break; + case LSH+I: + identity(r,l,I,i,0); + if (l->op == CNST+I && r->op == CNST+I + && r->u.v.i >= 0 && r->u.v.i < 8*l->type->size + && muli(l->u.v.i, 1<u.v.i, ty->u.sym->u.limits.min.i, ty->u.sym->u.limits.max.i, needconst)) + return cnsttree(ty, (long)(l->u.v.i<u.v.i)); + if (r->op == CNST+I && (r->u.v.i >= 8*ty->size || r->u.v.i < 0)) { + warning("shifting an `%t' by %d bits is undefined\n", ty, r->u.v.i); + break; + } + + break; + case LSH+U: + identity(r,l,I,i,0); + sfoldcnst(<<); + if (r->op == CNST+I && (r->u.v.i >= 8*ty->size || r->u.v.i < 0)) { + warning("shifting an `%t' by %d bits is undefined\n", ty, r->u.v.i); + break; + } + + break; + + case LT+F: cfoldcnst(F,d, <); break; + case LT+I: cfoldcnst(I,i, <); break; + case LT+U: + geu(l,r,0); /* l < 0 => (l,0) */ + cfoldcnst(U,u, <); + if (l->op == CNST+U && l->u.v.u == 0) /* 0 < r => r != 0 */ + return eqtree(NE, r, l); + break; + case MOD+I: + if ((r->op == CNST+I && r->u.v.i == 0) + || (l->op == CNST+I && l->u.v.i == ty->u.sym->u.limits.min.i + && r->op == CNST+I && r->u.v.i == -1)) + break; + xfoldcnst(I,i,%,divi); + if (r->op == CNST+I && r->u.v.i == 1) /* l%1 => (l,0) */ + return tree(RIGHT, ty, root(l), cnsttree(ty, 0L)); + break; + case MOD+U: + if (r->op == CNST+U && ispow2(r->u.v.u)) /* l%2^n => l&(2^n-1) */ + return bittree(BAND, l, cnsttree(ty, r->u.v.u - 1)); + if (r->op == CNST+U && r->u.v.u == 0) + break; + foldcnst(U,u,%); + break; + case MUL+F: + xfoldcnst(F,d,*,muld); + commute(l,r); + break; + case MUL+I: + commute(l,r); + xfoldcnst(I,i,*,muli); + if (l->op == CNST+I && r->op == ADD+I && r->kids[1]->op == CNST+I) + /* c1*(x + c2) => c1*x + c1*c2 */ + return simplify(ADD, ty, simplify(MUL, ty, l, r->kids[0]), + simplify(MUL, ty, l, r->kids[1])); + if (l->op == CNST+I && r->op == SUB+I && r->kids[1]->op == CNST+I) + /* c1*(x - c2) => c1*x - c1*c2 */ + return simplify(SUB, ty, simplify(MUL, ty, l, r->kids[0]), + simplify(MUL, ty, l, r->kids[1])); + if (l->op == CNST+I && l->u.v.i > 0 && (n = ispow2(l->u.v.i)) != 0) + /* 2^n * r => r<u.v.d)); + idempotent(NEG+F); + break; + case NEG+I: + if (l->op == CNST+I) { + if (needconst && l->u.v.i == ty->u.sym->u.limits.min.i) + warning("overflow in constant expression\n"); + if (needconst || l->u.v.i != ty->u.sym->u.limits.min.i) + return cnsttree(ty, -l->u.v.i); + } + idempotent(NEG+I); + break; + case NOT+I: + op = NOT; + ufoldcnst(I,cnsttree(ty, !l->u.v.i)); + break; + case RSH+I: + identity(r,l,I,i,0); + if (l->op == CNST+I && r->op == CNST+I + && r->u.v.i >= 0 && r->u.v.i < 8*l->type->size) { + long n = l->u.v.i>>r->u.v.i; + if (l->u.v.i < 0) + n |= ~0UL<<(8*l->type->size - r->u.v.i); + return cnsttree(ty, n); + } + if (r->op == CNST+I && (r->u.v.i >= 8*ty->size || r->u.v.i < 0)) { + warning("shifting an `%t' by %d bits is undefined\n", ty, r->u.v.i); + break; + } + + break; + case RSH+U: + identity(r,l,I,i,0); + sfoldcnst(>>); + if (r->op == CNST+I && (r->u.v.i >= 8*ty->size || r->u.v.i < 0)) { + warning("shifting an `%t' by %d bits is undefined\n", ty, r->u.v.i); + break; + } + + break; + case SUB+F: + xfoldcnst(F,d,-,subd); + break; + case SUB+I: + xfoldcnst(I,i,-,subi); + identity(r,l,I,i,0); + break; + case SUB+U: + foldcnst(U,u,-); + identity(r,l,U,u,0); + break; + case SUB+P: + if (l->op == CNST+P && r->op == CNST+P) + return cnsttree(ty, (long)((char *)l->u.v.p - (char *)r->u.v.p)); + if (r->op == CNST+I || r->op == CNST+U) + return simplify(ADD, ty, l, + cnsttree(inttype, r->op == CNST+I ? -r->u.v.i : -(long)r->u.v.u)); + if (isaddrop(l->op) && r->op == ADD+I && r->kids[1]->op == CNST+I) + /* l - (x + c) => l-c - x */ + return simplify(SUB, ty, + simplify(SUB, ty, l, r->kids[1]), r->kids[0]); + break; + default:assert(0); + } + return tree(op, ty, l, r); +} + +/* + * ispow2 - if u > 1 && u == 2^n, return n, otherwise return 0 + */ +int ispow2(unsigned long u) +{ + int n; + + if (u > 1 && (u&(u-1)) == 0) + for (n = 0; u; u >>= 1, n++) + if (u&1) + return n; + return 0; +} diff --git a/src/cmd/lccom/sparc.md b/src/cmd/lccom/sparc.md new file mode 100644 index 0000000..ebd3150 --- /dev/null +++ b/src/cmd/lccom/sparc.md @@ -0,0 +1,1176 @@ +%{ +#include "c.h" +#define NODEPTR_TYPE Node +#define OP_LABEL(p) ((p)->op) +#define LEFT_CHILD(p) ((p)->kids[0]) +#define RIGHT_CHILD(p) ((p)->kids[1]) +#define STATE_LABEL(p) ((p)->x.state) +static void address(Symbol, Symbol, long); +static void blkfetch(int, int, int, int); +static void blkloop(int, int, int, int, int, int[]); +static void blkstore(int, int, int, int); +static void defaddress(Symbol); +static void defconst(int, int, Value); +static void defstring(int, char *); +static void defsymbol(Symbol); +static void doarg(Node); +static void emit2(Node); +static void export(Symbol); +static void clobber(Node); +static void function(Symbol, Symbol [], Symbol [], int); +static void global(Symbol); +static void import(Symbol); +static void local(Symbol); +static void progbeg(int, char **); +static void progend(void); +static void segment(int); +static void space(int); +static void target(Node); +static int imm(Node); +static void renameregs(void); +extern Interface sparcIR, solarisIR; +static void defsymbol2(Symbol); +static void export2(Symbol); +static void globalend(void); +static void global2(Symbol); +static void segment2(int); +static void progend2(void); + +extern char *stabprefix; +extern void stabblock(int, int, Symbol*); +extern void stabend(Coordinate *, Symbol, Coordinate **, Symbol *, Symbol *); +extern void stabfend(Symbol, int); +extern void stabinit(char *, int, char *[]); +extern void stabline(Coordinate *); +extern void stabsym(Symbol); +extern void stabtype(Symbol); +static Symbol greg[32], gregw; +static Symbol *oreg = &greg[8], *ireg = &greg[24]; +static Symbol freg[32], freg2[32]; +static Symbol fregw, freg2w; + +static int regvars; +static int retstruct; + +static int pflag = 0; + +static int cseg; + +%} +%start stmt +%term CNSTF4=4113 +%term CNSTF8=8209 +%term CNSTF16=16401 +%term CNSTI1=1045 +%term CNSTI2=2069 +%term CNSTI4=4117 +%term CNSTI8=8213 +%term CNSTP4=4119 +%term CNSTP8=8215 +%term CNSTU1=1046 +%term CNSTU2=2070 +%term CNSTU4=4118 +%term CNSTU8=8214 + +%term ARGB=41 +%term ARGF4=4129 +%term ARGF8=8225 +%term ARGF16=16417 +%term ARGI4=4133 +%term ARGI8=8229 +%term ARGP4=4135 +%term ARGP8=8231 +%term ARGU4=4134 +%term ARGU8=8230 + +%term ASGNB=57 +%term ASGNF4=4145 +%term ASGNF8=8241 +%term ASGNF16=16433 +%term ASGNI1=1077 +%term ASGNI2=2101 +%term ASGNI4=4149 +%term ASGNI8=8245 +%term ASGNP4=4151 +%term ASGNP8=8247 +%term ASGNU1=1078 +%term ASGNU2=2102 +%term ASGNU4=4150 +%term ASGNU8=8246 + +%term INDIRB=73 +%term INDIRF4=4161 +%term INDIRF8=8257 +%term INDIRF16=16449 +%term INDIRI1=1093 +%term INDIRI2=2117 +%term INDIRI4=4165 +%term INDIRI8=8261 +%term INDIRP4=4167 +%term INDIRP8=8263 +%term INDIRU1=1094 +%term INDIRU2=2118 +%term INDIRU4=4166 +%term INDIRU8=8262 + +%term CVFF4=4209 +%term CVFF8=8305 +%term CVFF16=16497 +%term CVFI4=4213 +%term CVFI8=8309 + +%term CVIF4=4225 +%term CVIF8=8321 +%term CVIF16=16513 +%term CVII1=1157 +%term CVII2=2181 +%term CVII4=4229 +%term CVII8=8325 +%term CVIU1=1158 +%term CVIU2=2182 +%term CVIU4=4230 +%term CVIU8=8326 + +%term CVPP4=4247 +%term CVPP8=8343 +%term CVPP16=16535 +%term CVPU4=4246 +%term CVPU8=8342 + +%term CVUI1=1205 +%term CVUI2=2229 +%term CVUI4=4277 +%term CVUI8=8373 +%term CVUP4=4279 +%term CVUP8=8375 +%term CVUP16=16567 +%term CVUU1=1206 +%term CVUU2=2230 +%term CVUU4=4278 +%term CVUU8=8374 + +%term NEGF4=4289 +%term NEGF8=8385 +%term NEGF16=16577 +%term NEGI4=4293 +%term NEGI8=8389 + +%term CALLB=217 +%term CALLF4=4305 +%term CALLF8=8401 +%term CALLF16=16593 +%term CALLI4=4309 +%term CALLI8=8405 +%term CALLP4=4311 +%term CALLP8=8407 +%term CALLU4=4310 +%term CALLU8=8406 +%term CALLV=216 + +%term RETF4=4337 +%term RETF8=8433 +%term RETF16=16625 +%term RETI4=4341 +%term RETI8=8437 +%term RETP4=4343 +%term RETP8=8439 +%term RETU4=4342 +%term RETU8=8438 +%term RETV=248 + +%term ADDRGP4=4359 +%term ADDRGP8=8455 + +%term ADDRFP4=4375 +%term ADDRFP8=8471 + +%term ADDRLP4=4391 +%term ADDRLP8=8487 + +%term ADDF4=4401 +%term ADDF8=8497 +%term ADDF16=16689 +%term ADDI4=4405 +%term ADDI8=8501 +%term ADDP4=4407 +%term ADDP8=8503 +%term ADDU4=4406 +%term ADDU8=8502 + +%term SUBF4=4417 +%term SUBF8=8513 +%term SUBF16=16705 +%term SUBI4=4421 +%term SUBI8=8517 +%term SUBP4=4423 +%term SUBP8=8519 +%term SUBU4=4422 +%term SUBU8=8518 + +%term LSHI4=4437 +%term LSHI8=8533 +%term LSHU4=4438 +%term LSHU8=8534 + +%term MODI4=4453 +%term MODI8=8549 +%term MODU4=4454 +%term MODU8=8550 + +%term RSHI4=4469 +%term RSHI8=8565 +%term RSHU4=4470 +%term RSHU8=8566 + +%term BANDI4=4485 +%term BANDI8=8581 +%term BANDU4=4486 +%term BANDU8=8582 + +%term BCOMI4=4501 +%term BCOMI8=8597 +%term BCOMU4=4502 +%term BCOMU8=8598 + +%term BORI4=4517 +%term BORI8=8613 +%term BORU4=4518 +%term BORU8=8614 + +%term BXORI4=4533 +%term BXORI8=8629 +%term BXORU4=4534 +%term BXORU8=8630 + +%term DIVF4=4545 +%term DIVF8=8641 +%term DIVF16=16833 +%term DIVI4=4549 +%term DIVI8=8645 +%term DIVU4=4550 +%term DIVU8=8646 + +%term MULF4=4561 +%term MULF8=8657 +%term MULF16=16849 +%term MULI4=4565 +%term MULI8=8661 +%term MULU4=4566 +%term MULU8=8662 + +%term EQF4=4577 +%term EQF8=8673 +%term EQF16=16865 +%term EQI4=4581 +%term EQI8=8677 +%term EQU4=4582 +%term EQU8=8678 + +%term GEF4=4593 +%term GEF8=8689 +%term GEI4=4597 +%term GEI8=8693 +%term GEI16=16885 +%term GEU4=4598 +%term GEU8=8694 + +%term GTF4=4609 +%term GTF8=8705 +%term GTF16=16897 +%term GTI4=4613 +%term GTI8=8709 +%term GTU4=4614 +%term GTU8=8710 + +%term LEF4=4625 +%term LEF8=8721 +%term LEF16=16913 +%term LEI4=4629 +%term LEI8=8725 +%term LEU4=4630 +%term LEU8=8726 + +%term LTF4=4641 +%term LTF8=8737 +%term LTF16=16929 +%term LTI4=4645 +%term LTI8=8741 +%term LTU4=4646 +%term LTU8=8742 + +%term NEF4=4657 +%term NEF8=8753 +%term NEF16=16945 +%term NEI4=4661 +%term NEI8=8757 +%term NEU4=4662 +%term NEU8=8758 + +%term JUMPV=584 + +%term LABELV=600 + +%term LOADB=233 +%term LOADF4=4321 +%term LOADF8=8417 +%term LOADF16=16609 +%term LOADI1=1253 +%term LOADI2=2277 +%term LOADI4=4325 +%term LOADI8=8421 +%term LOADP4=4327 +%term LOADP8=8423 +%term LOADU1=1254 +%term LOADU2=2278 +%term LOADU4=4326 +%term LOADU8=8422 + +%term VREGP=711 +%% +reg: INDIRI1(VREGP) "# read register\n" +reg: INDIRU1(VREGP) "# read register\n" + +reg: INDIRI2(VREGP) "# read register\n" +reg: INDIRU2(VREGP) "# read register\n" + +reg: INDIRF4(VREGP) "# read register\n" +reg: INDIRI4(VREGP) "# read register\n" +reg: INDIRP4(VREGP) "# read register\n" +reg: INDIRU4(VREGP) "# read register\n" + +reg: INDIRF8(VREGP) "# read register\n" +reg: INDIRI8(VREGP) "# read register\n" +reg: INDIRP8(VREGP) "# read register\n" +reg: INDIRU8(VREGP) "# read register\n" + +stmt: ASGNI1(VREGP,reg) "# write register\n" +stmt: ASGNU1(VREGP,reg) "# write register\n" + +stmt: ASGNI2(VREGP,reg) "# write register\n" +stmt: ASGNU2(VREGP,reg) "# write register\n" + +stmt: ASGNF4(VREGP,reg) "# write register\n" +stmt: ASGNI4(VREGP,reg) "# write register\n" +stmt: ASGNP4(VREGP,reg) "# write register\n" +stmt: ASGNU4(VREGP,reg) "# write register\n" + +stmt: ASGNF8(VREGP,reg) "# write register\n" +stmt: ASGNI8(VREGP,reg) "# write register\n" +stmt: ASGNP8(VREGP,reg) "# write register\n" +stmt: ASGNU8(VREGP,reg) "# write register\n" +con: CNSTI1 "%a" +con: CNSTU1 "%a" + +con: CNSTI2 "%a" +con: CNSTU2 "%a" + +con: CNSTI4 "%a" +con: CNSTU4 "%a" +con: CNSTP4 "%a" + +con: CNSTI8 "%a" +con: CNSTU8 "%a" +con: CNSTP8 "%a" +stmt: reg "" +reg: ADDRGP4 "set %a,%%%c\n" 1 +stk13: ADDRFP4 "%a" imm(a) +stk13: ADDRLP4 "%a" imm(a) +reg: stk13 "add %0,%%fp,%%%c\n" 1 +stk: ADDRFP4 "set %a,%%%c\n" 2 +stk: ADDRLP4 "set %a,%%%c\n" 2 +reg: ADDRFP4 "set %a,%%%c\nadd %%%c,%%fp,%%%c\n" 3 +reg: ADDRLP4 "set %a,%%%c\nadd %%%c,%%fp,%%%c\n" 3 +con13: CNSTI1 "%a" imm(a) +con13: CNSTI2 "%a" imm(a) +con13: CNSTI4 "%a" imm(a) +con13: CNSTU1 "%a" imm(a) +con13: CNSTU2 "%a" imm(a) +con13: CNSTU4 "%a" imm(a) +con13: CNSTP4 "%a" imm(a) +base: ADDI4(reg,con13) "%%%0+%1" +base: ADDP4(reg,con13) "%%%0+%1" +base: ADDU4(reg,con13) "%%%0+%1" +base: reg "%%%0" +base: con13 "%0" +base: stk13 "%%fp+%0" +addr: base "%0" +addr: ADDI4(reg,reg) "%%%0+%%%1" +addr: ADDP4(reg,reg) "%%%0+%%%1" +addr: ADDU4(reg,reg) "%%%0+%%%1" +addr: stk "%%fp+%%%0" +reg: INDIRI1(addr) "ldsb [%0],%%%c\n" 1 +reg: INDIRI2(addr) "ldsh [%0],%%%c\n" 1 +reg: INDIRI4(addr) "ld [%0],%%%c\n" 1 +reg: INDIRU1(addr) "ldub [%0],%%%c\n" 1 +reg: INDIRU2(addr) "lduh [%0],%%%c\n" 1 +reg: INDIRU4(addr) "ld [%0],%%%c\n" 1 +reg: INDIRP4(addr) "ld [%0],%%%c\n" 1 +reg: INDIRF4(addr) "ld [%0],%%f%c\n" 1 +stmt: ASGNI1(addr,reg) "stb %%%1,[%0]\n" 1 +stmt: ASGNI2(addr,reg) "sth %%%1,[%0]\n" 1 +stmt: ASGNI4(addr,reg) "st %%%1,[%0]\n" 1 +stmt: ASGNU1(addr,reg) "stb %%%1,[%0]\n" 1 +stmt: ASGNU2(addr,reg) "sth %%%1,[%0]\n" 1 +stmt: ASGNU4(addr,reg) "st %%%1,[%0]\n" 1 +stmt: ASGNP4(addr,reg) "st %%%1,[%0]\n" 1 +stmt: ASGNF4(addr,reg) "st %%f%1,[%0]\n" 1 +addrl: ADDRLP4 "%%%fp+%a" imm(a) + +reg: INDIRF8(addrl) "ldd [%0],%%f%c\n" 1 +stmt: ASGNF8(addrl,reg) "std %%f%1,[%0]\n" 1 +reg: INDIRF8(base) "# ld2 [%0],%%f%c\n" 2 +stmt: ASGNF8(base,reg) "# st2 %%f%1,[%0]\n" 2 +spill: ADDRLP4 "%a" !imm(a) + +stmt: ASGNI1(spill,reg) "set %0,%%g1\nstb %%%1,[%%fp+%%g1]\n" +stmt: ASGNI2(spill,reg) "set %0,%%g1\nsth %%%1,[%%fp+%%g1]\n" +stmt: ASGNI4(spill,reg) "set %0,%%g1\nst %%%1,[%%fp+%%g1]\n" +stmt: ASGNU1(spill,reg) "set %0,%%g1\nstb %%%1,[%%fp+%%g1]\n" +stmt: ASGNU2(spill,reg) "set %0,%%g1\nsth %%%1,[%%fp+%%g1]\n" +stmt: ASGNU4(spill,reg) "set %0,%%g1\nst %%%1,[%%fp+%%g1]\n" +stmt: ASGNP4(spill,reg) "set %0,%%g1\nst %%%1,[%%fp+%%g1]\n" +stmt: ASGNF4(spill,reg) "set %0,%%g1\nst %%f%1,[%%fp+%%g1]\n" +stmt: ASGNF8(spill,reg) "set %0,%%g1\nstd %%f%1,[%%fp+%%g1]\n" +reg: CVII4(INDIRI1(addr)) "ldsb [%0],%%%c\n" 1 +reg: CVII4(INDIRI2(addr)) "ldsh [%0],%%%c\n" 1 +reg: CVUU4(INDIRU1(addr)) "ldub [%0],%%%c\n" 1 +reg: CVUU4(INDIRU2(addr)) "lduh [%0],%%%c\n" 1 +reg: CVUI4(INDIRU1(addr)) "ldub [%0],%%%c\n" 1 +reg: CVUI4(INDIRU2(addr)) "lduh [%0],%%%c\n" 1 +reg: LOADI1(reg) "mov %%%0,%%%c\n" move(a) +reg: LOADI2(reg) "mov %%%0,%%%c\n" move(a) +reg: LOADI4(reg) "mov %%%0,%%%c\n" move(a) +reg: LOADP4(reg) "mov %%%0,%%%c\n" move(a) +reg: LOADU1(reg) "mov %%%0,%%%c\n" move(a) +reg: LOADU2(reg) "mov %%%0,%%%c\n" move(a) +reg: LOADU4(reg) "mov %%%0,%%%c\n" move(a) +reg: CNSTI1 "# reg\n" range(a, 0, 0) +reg: CNSTI2 "# reg\n" range(a, 0, 0) +reg: CNSTI4 "# reg\n" range(a, 0, 0) +reg: CNSTP4 "# reg\n" range(a, 0, 0) +reg: CNSTU1 "# reg\n" range(a, 0, 0) +reg: CNSTU2 "# reg\n" range(a, 0, 0) +reg: CNSTU4 "# reg\n" range(a, 0, 0) +reg: con "set %0,%%%c\n" 1 +rc: con13 "%0" +rc: reg "%%%0" +reg: ADDI4(reg,rc) "add %%%0,%1,%%%c\n" 1 +reg: ADDP4(reg,rc) "add %%%0,%1,%%%c\n" 1 +reg: ADDU4(reg,rc) "add %%%0,%1,%%%c\n" 1 +reg: BANDI4(reg,rc) "and %%%0,%1,%%%c\n" 1 +reg: BORI4(reg,rc) "or %%%0,%1,%%%c\n" 1 +reg: BXORI4(reg,rc) "xor %%%0,%1,%%%c\n" 1 +reg: BANDU4(reg,rc) "and %%%0,%1,%%%c\n" 1 +reg: BORU4(reg,rc) "or %%%0,%1,%%%c\n" 1 +reg: BXORU4(reg,rc) "xor %%%0,%1,%%%c\n" 1 +reg: SUBI4(reg,rc) "sub %%%0,%1,%%%c\n" 1 +reg: SUBP4(reg,rc) "sub %%%0,%1,%%%c\n" 1 +reg: SUBU4(reg,rc) "sub %%%0,%1,%%%c\n" 1 +rc5: CNSTI4 "%a" range(a, 0, 31) +rc5: reg "%%%0" +reg: LSHI4(reg,rc5) "sll %%%0,%1,%%%c\n" 1 +reg: LSHU4(reg,rc5) "sll %%%0,%1,%%%c\n" 1 +reg: RSHI4(reg,rc5) "sra %%%0,%1,%%%c\n" 1 +reg: RSHU4(reg,rc5) "srl %%%0,%1,%%%c\n" 1 +reg: BANDI4(reg,BCOMI4(rc)) "andn %%%0,%1,%%%c\n" 1 +reg: BORI4(reg,BCOMI4(rc)) "orn %%%0,%1,%%%c\n" 1 +reg: BXORI4(reg,BCOMI4(rc)) "xnor %%%0,%1,%%%c\n" 1 +reg: BANDU4(reg,BCOMU4(rc)) "andn %%%0,%1,%%%c\n" 1 +reg: BORU4(reg,BCOMU4(rc)) "orn %%%0,%1,%%%c\n" 1 +reg: BXORU4(reg,BCOMU4(rc)) "xnor %%%0,%1,%%%c\n" 1 +reg: NEGI4(reg) "neg %%%0,%%%c\n" 1 +reg: BCOMI4(reg) "not %%%0,%%%c\n" 1 +reg: BCOMU4(reg) "not %%%0,%%%c\n" 1 +reg: CVII4(reg) "sll %%%0,8*(4-%a),%%%c; sra %%%c,8*(4-%a),%%%c\n" 2 +reg: CVUU4(reg) "sll %%%0,8*(4-%a),%%%c; srl %%%c,8*(4-%a),%%%c\n" 2 +reg: CVUU4(reg) "and %%%0,0xff,%%%c\n" (a->syms[0]->u.c.v.i == 1 ? 1 : LBURG_MAX) +reg: CVUU4(reg) "set 0xffff,%%g1; and %%%0,%%g1,%%%c\n" 2 +reg: CVUI4(reg) "and %%%0,0xff,%%%c\n" (a->syms[0]->u.c.v.i == 1 ? 1 : LBURG_MAX) +reg: CVUI4(reg) "set 0xffff,%%g1; and %%%0,%%g1,%%%c\n" 2 +addrg: ADDRGP4 "%a" +stmt: JUMPV(addrg) "ba %0; nop\n" 2 +stmt: JUMPV(addr) "jmp %0; nop\n" 2 +stmt: LABELV "%a:\n" +stmt: EQI4(reg,rc) "cmp %%%0,%1; be %a; nop\n" 3 +stmt: EQU4(reg,rc) "cmp %%%0,%1; be %a; nop\n" 3 +stmt: GEI4(reg,rc) "cmp %%%0,%1; bge %a; nop\n" 3 +stmt: GEU4(reg,rc) "cmp %%%0,%1; bgeu %a; nop\n" 3 +stmt: GTI4(reg,rc) "cmp %%%0,%1; bg %a; nop\n" 3 +stmt: GTU4(reg,rc) "cmp %%%0,%1; bgu %a; nop\n" 3 +stmt: LEI4(reg,rc) "cmp %%%0,%1; ble %a; nop\n" 3 +stmt: LEU4(reg,rc) "cmp %%%0,%1; bleu %a; nop\n" 3 +stmt: LTI4(reg,rc) "cmp %%%0,%1; bl %a; nop\n" 3 +stmt: LTU4(reg,rc) "cmp %%%0,%1; blu %a; nop\n" 3 +stmt: NEI4(reg,rc) "cmp %%%0,%1; bne %a; nop\n" 3 +stmt: NEU4(reg,rc) "cmp %%%0,%1; bne %a; nop\n" 3 +call: ADDRGP4 "%a" +call: addr "%0" +reg: CALLF8(call) "call %0; nop\n" 2 +reg: CALLF4(call) "call %0; nop\n" 2 +reg: CALLI4(call) "call %0; nop\n" 2 +reg: CALLP4(call) "call %0; nop\n" 2 +reg: CALLU4(call) "call %0; nop\n" 2 +stmt: CALLV(call) "call %0; nop\n" 2 +stmt: CALLB(call,reg) "call %0; st %%%1,[%%sp+64]; unimp %b&0xfff\n" 3 + +stmt: RETF8(reg) "# ret\n" 1 +stmt: RETF4(reg) "# ret\n" 1 +stmt: RETI4(reg) "# ret\n" 1 +stmt: RETU4(reg) "# ret\n" 1 +stmt: RETP4(reg) "# ret\n" 1 +stmt: ARGI4(reg) "st %%%0,[%%sp+4*%c+68]\n" 1 +stmt: ARGU4(reg) "st %%%0,[%%sp+4*%c+68]\n" 1 +stmt: ARGP4(reg) "st %%%0,[%%sp+4*%c+68]\n" 1 +stmt: ARGF4(reg) "# ARGF4\n" 1 +stmt: ARGF8(reg) "# ARGF8\n" 1 + +reg: DIVI4(reg,rc) "sra %%%0,31,%%g1; wr %%g0,%%g1,%%y; nop; nop; nop; sdiv %%%0,%1,%%%c\n" 6 + +reg: DIVU4(reg,rc) "wr %%g0,%%g0,%%y; nop; nop; nop; udiv %%%0,%1,%%%c\n" 5 + +reg: MODI4(reg,rc) "sra %%%0,31,%%g1; wr %%g0,%%g1,%%y; nop; nop; nop; sdiv %%%0,%1,%%g1\n; smul %%g1,%1,%%g1; sub %%%0,%%g1,%%%c\n" 8 + + +reg: MODU4(reg,rc) "wr %%g0,%%g0,%%y; nop; nop; nop; udiv %%%0,%1,%%g1\n; umul %%g1,%1,%%g1; sub %%%0,%%g1,%%%c\n" 7 + + +reg: MULI4(rc,reg) "smul %%%1,%0,%%%c\n" 1 +reg: MULU4(rc,reg) "umul %%%1,%0,%%%c\n" 1 +reg: ADDF8(reg,reg) "faddd %%f%0,%%f%1,%%f%c\n" 1 +reg: ADDF4(reg,reg) "fadds %%f%0,%%f%1,%%f%c\n" 1 +reg: DIVF8(reg,reg) "fdivd %%f%0,%%f%1,%%f%c\n" 1 +reg: DIVF4(reg,reg) "fdivs %%f%0,%%f%1,%%f%c\n" 1 +reg: MULF8(reg,reg) "fmuld %%f%0,%%f%1,%%f%c\n" 1 +reg: MULF4(reg,reg) "fmuls %%f%0,%%f%1,%%f%c\n" 1 +reg: SUBF8(reg,reg) "fsubd %%f%0,%%f%1,%%f%c\n" 1 +reg: SUBF4(reg,reg) "fsubs %%f%0,%%f%1,%%f%c\n" 1 +reg: NEGF4(reg) "fnegs %%f%0,%%f%c\n" 1 +reg: LOADF4(reg) "fmovs %%f%0,%%f%c\n" 1 +reg: CVFF4(reg) "fdtos %%f%0,%%f%c\n" 1 +reg: CVFF8(reg) "fstod %%f%0,%%f%c\n" 1 +reg: CVFI4(reg) "fstoi %%f%0,%%f0; st %%f0,[%%sp+64]; ld [%%sp+64],%%%c\n" (a->syms[0]->u.c.v.i==4?3:LBURG_MAX) + +reg: CVFI4(reg) "fdtoi %%f%0,%%f0; st %%f0,[%%sp+64]; ld [%%sp+64],%%%c\n" (a->syms[0]->u.c.v.i==8?3:LBURG_MAX) + +reg: CVIF4(reg) "st %%%0,[%%sp+64]; ld [%%sp+64],%%f%c; fitos %%f%c,%%f%c\n" 3 + +reg: CVIF8(reg) "st %%%0,[%%sp+64]; ld [%%sp+64],%%f%c; fitod %%f%c,%%f%c\n" 3 + +rel: EQF8(reg,reg) "fcmpd %%f%0,%%f%1; nop; fbe" +rel: EQF4(reg,reg) "fcmps %%f%0,%%f%1; nop; fbe" +rel: GEF8(reg,reg) "fcmpd %%f%0,%%f%1; nop; fbuge" +rel: GEF4(reg,reg) "fcmps %%f%0,%%f%1; nop; fbuge" +rel: GTF8(reg,reg) "fcmpd %%f%0,%%f%1; nop; fbug" +rel: GTF4(reg,reg) "fcmps %%f%0,%%f%1; nop; fbug" +rel: LEF8(reg,reg) "fcmpd %%f%0,%%f%1; nop; fbule" +rel: LEF4(reg,reg) "fcmps %%f%0,%%f%1; nop; fbule" +rel: LTF8(reg,reg) "fcmpd %%f%0,%%f%1; nop; fbul" +rel: LTF4(reg,reg) "fcmps %%f%0,%%f%1; nop; fbul" +rel: NEF8(reg,reg) "fcmpd %%f%0,%%f%1; nop; fbne" +rel: NEF4(reg,reg) "fcmps %%f%0,%%f%1; nop; fbne" + +stmt: rel "%0 %a; nop\n" 4 +reg: LOADF8(reg) "# LOADD\n" 2 + +reg: NEGF8(reg) "# NEGD\n" 2 + +stmt: ASGNB(reg,INDIRB(reg)) "# ASGNB\n" + +%% +static void progend(void){} +static void progbeg(int argc, char *argv[]) { + int i; + + { + union { + char c; + int i; + } u; + u.i = 0; + u.c = 1; + swap = ((int)(u.i == 1)) != IR->little_endian; + } + parseflags(argc, argv); + for (i = 0; i < argc; i++) + if (strcmp(argv[i], "-p") == 0 || strcmp(argv[i], "-pg") == 0) + pflag = 1; + if (IR == &solarisIR) + stabprefix = ".LL"; + else + stabprefix = "L"; + for (i = 0; i < 8; i++) { + greg[i + 0] = mkreg(stringf("g%d", i), i + 0, 1, IREG); + greg[i + 8] = mkreg(stringf("o%d", i), i + 8, 1, IREG); + greg[i + 16] = mkreg(stringf("l%d", i), i + 16, 1, IREG); + greg[i + 24] = mkreg(stringf("i%d", i), i + 24, 1, IREG); + } + gregw = mkwildcard(greg); + for (i = 0; i < 32; i++) + freg[i] = mkreg("%d", i, 1, FREG); + for (i = 0; i < 31; i += 2) + freg2[i] = mkreg("%d", i, 3, FREG); + fregw = mkwildcard(freg); + freg2w = mkwildcard(freg2); + tmask[IREG] = 0x3fff3e00; + vmask[IREG] = 0x3ff00000; + tmask[FREG] = ~(unsigned)0; + vmask[FREG] = 0; +} +static Symbol rmap(int opk) { + switch (optype(opk)) { + case I: case U: case P: case B: + return gregw; + case F: + return opsize(opk) == 4 ? fregw : freg2w; + default: + return 0; + } +} +static void target(Node p) { + assert(p); + switch (specific(p->op)) { + case CNST+I: case CNST+U: case CNST+P: + if (range(p, 0, 0) == 0) { + setreg(p, greg[0]); + p->x.registered = 1; + } + break; + case CALL+B: + assert(p->syms[1] && p->syms[1]->type && isfunc(p->syms[1]->type)); + p->syms[1] = intconst(freturn(p->syms[1]->type)->size); + break; + case CALL+F: setreg(p, opsize(p->op)==4?freg[0]:freg2[0]); break; + case CALL+I: case CALL+P: case CALL+U: + case CALL+V: setreg(p, oreg[0]); break; + case RET+F: rtarget(p, 0, opsize(p->op)==4?freg[0]:freg2[0]); break; + case RET+I: case RET+P: case RET+U: + rtarget(p, 0, ireg[0]); + p->kids[0]->x.registered = 1; + break; + case ARG+I: case ARG+P: case ARG+U: + if (p->syms[RX]->u.c.v.i < 6) { + rtarget(p, 0, oreg[p->syms[RX]->u.c.v.i]); + p->op = LOAD+opkind(p->op); + setreg(p, oreg[p->syms[RX]->u.c.v.i]); + } + break; + } +} +static void clobber(Node p) { + assert(p); + switch (specific(p->op)) { + case CALL+B: case CALL+F: case CALL+I: + spill(~(unsigned)3, FREG, p); + break; + case CALL+V: + spill(oreg[0]->x.regnode->mask, IREG, p); + spill(~(unsigned)3, FREG, p); + break; + case ARG+F: + if (opsize(p->op) == 4 && p->syms[2]->u.c.v.i <= 6) + spill((1<<(p->syms[2]->u.c.v.i + 8)), IREG, p); + else if (opsize(p->op) == 8 && p->syms[2]->u.c.v.i <= 5) + spill((3<<(p->syms[2]->u.c.v.i + 8))&0xff00, IREG, p); + break; + } +} +static int imm(Node p) { + return range(p, -4096, 4091); +} +static void doarg(Node p) { + assert(p && p->syms[0] && p->op != ARG+B); + p->syms[RX] = intconst(mkactual(4, + p->syms[0]->u.c.v.i)/4); +} +static void emit2(Node p) { + switch (p->op) { + case INDIR+F+sizeop(8): + if (generic(p->kids[0]->op) != VREG) { + int dst = getregnum(p); + print("ld ["); emitasm(p->kids[0], _base_NT); print( "],%%f%d; ", dst); + print("ld ["); emitasm(p->kids[0], _base_NT); print("+4],%%f%d\n", dst+1); + } + break; + case ASGN+F+sizeop(8): + if (generic(p->kids[0]->op) != VREG) { + int src = getregnum(p->kids[1]); + print("st %%f%d,[", src); emitasm(p->kids[0], _base_NT); print("]; "); + print("st %%f%d,[", src+1); emitasm(p->kids[0], _base_NT); print("+4]\n"); + } + break; + case ARG+F+sizeop(4): { + int n = p->syms[RX]->u.c.v.i; + print("st %%f%d,[%%sp+4*%d+68]\n", + getregnum(p->x.kids[0]), n); + if (n <= 5) + print("ld [%%sp+4*%d+68],%%o%d\n", n, n); + break; + } + case ARG+F+sizeop(8): { + int n = p->syms[RX]->u.c.v.i; + int src = getregnum(p->x.kids[0]); + print("st %%f%d,[%%sp+4*%d+68]\n", src, n); + print("st %%f%d,[%%sp+4*%d+68]\n", src+1, n+1); + if (n <= 5) + print("ld [%%sp+4*%d+68],%%o%d\n", n, n); + if (n <= 4) + print("ld [%%sp+4*%d+68],%%o%d\n", n+1, n+1); + break; + } + case LOAD+F+sizeop(8): { + int dst = getregnum(p); + int src = getregnum(p->x.kids[0]); + print("fmovs %%f%d,%%f%d; ", src, dst); + print("fmovs %%f%d,%%f%d\n", src+1, dst+1); + break; + } + case NEG+F+sizeop(8): { + int dst = getregnum(p); + int src = getregnum(p->x.kids[0]); + print("fnegs %%f%d,%%f%d; ", src, dst); + print("fmovs %%f%d,%%f%d\n", src+1, dst+1); + break; + } + case ASGN+B: { + static int tmpregs[] = { 1, 2, 3 }; + dalign = salign = p->syms[1]->u.c.v.i; + blkcopy(getregnum(p->x.kids[0]), 0, + getregnum(p->x.kids[1]), 0, + p->syms[0]->u.c.v.i, tmpregs); + break; + } + } +} +static void local(Symbol p) { + if (retstruct) { + assert(p == retv); + p->x.name = stringd(4*16); + p->x.offset = 4*16; + p->sclass = AUTO; + retstruct = 0; + return; + } + if (isscalar(p->type) && !p->addressed && !isfloat(p->type)) + p->sclass = REGISTER; + if (askregvar(p, rmap(ttob(p->type))) == 0) + mkauto(p); + else if (p->scope > LOCAL) + regvars++; +} +static void function(Symbol f, Symbol caller[], Symbol callee[], int ncalls) { + int autos = 0, i, leaf, reg, varargs; + + if (IR == &solarisIR) + globalend(); + regvars = 0; + for (i = 0; callee[i]; i++) + ; + varargs = variadic(f->type) + || i > 0 && strcmp(callee[i-1]->name, + "__builtin_va_alist") == 0; + usedmask[0] = usedmask[1] = 0; + freemask[0] = freemask[1] = ~(unsigned)0; + for (i = 0; i < 8; i++) + ireg[i]->x.regnode->vbl = NULL; + offset = 68; + maxargoffset = 24; + reg = 0; + for (i = 0; callee[i]; i++) { + Symbol p = callee[i], q = caller[i]; + int size = roundup(q->type->size, 4); + assert(q); + if (isfloat(p->type) || reg >= 6) { + p->x.offset = q->x.offset = offset; + p->x.name = q->x.name = stringd(offset); + p->sclass = q->sclass = AUTO; + autos++; + } + else if (p->addressed || varargs) { + p->x.offset = offset; + p->x.name = stringd(p->x.offset); + p->sclass = AUTO; + q->sclass = REGISTER; + askregvar(q, ireg[reg]); + assert(q->x.regnode); + autos++; + } + else { + p->sclass = q->sclass = REGISTER; + askregvar(p, ireg[reg]); + assert(p->x.regnode); + q->x.name = p->x.name; + } + offset += size; + reg += isstruct(p->type) ? 1 : size/4; + } + assert(caller[i] == 0); + offset = maxoffset = 0; + retstruct = isstruct(freturn(f->type)); + gencode(caller, callee); + maxargoffset = roundup(maxargoffset, 4); + framesize = roundup(maxoffset + maxargoffset + 4*(16+1), 8); + assert(!varargs || autos); + leaf = (!ncalls + && !maxoffset && !autos && !regvars + && !isstruct(freturn(f->type)) + && !(usedmask[IREG]&0x00ffff01) + && !(usedmask[FREG]&~(unsigned)3) + && !pflag && !glevel); + print(".align 4\n%s:\n", f->x.name); + if (leaf) { + for (i = 0; caller[i] && callee[i]; i++) { + Symbol p = caller[i], q = callee[i]; + if (p->sclass == REGISTER && q->sclass == REGISTER) { + assert(q->x.regnode); + assert(q->x.regnode->set == IREG); + assert(q->x.regnode->number >= 24); + assert(q->x.regnode->number <= 31); + p->x.name = greg[q->x.regnode->number - 16]->x.name; + } + } + renameregs(); + } else if (framesize <= 4095) + print("save %%sp,%d,%%sp\n", -framesize); + else + print("set %d,%%g1; save %%sp,%%g1,%%sp\n", -framesize); + if (varargs) + for (; reg < 6; reg++) + print("st %%i%d,[%%fp+%d]\n", reg, 4*reg + 68); + else { + offset = 4*(16 + 1); + reg = 0; + for (i = 0; caller[i]; i++) { + Symbol p = caller[i]; + if (isfloat(p->type) && p->type->size == 8 && reg <= 4) { + print("st %%r%d,[%%fp+%d]\n", + ireg[reg++]->x.regnode->number, offset); + print("st %%r%d,[%%fp+%d]\n", + ireg[reg++]->x.regnode->number, offset + 4); + } else if (isfloat(p->type) && p->type->size == 4 && reg <= 5) + print("st %%r%d,[%%fp+%d]\n", + ireg[reg++]->x.regnode->number, offset); + else + reg++; + offset += roundup(p->type->size, 4); + } + } + if (pflag) { + int lab = genlabel(1); + print("set L%d,%%o0; call mcount; nop\n", lab); + print(".seg \"data\"\n.align 4; L%d:.word 0\n.seg \"text\"\n", lab); + } + emitcode(); + if (isstruct(freturn(f->type))) + print("jmp %%i7+12; restore\n"); + else if (!leaf) + print("ret; restore\n"); + else { + renameregs(); + print("retl; nop\n"); + } + if (IR == &solarisIR) { + print(".type %s,#function\n", f->x.name); + print(".size %s,.-%s\n", f->x.name, f->x.name); + } +} +#define exch(x, y, t) (((t) = x), ((x) = (y)), ((y) = (t))) + +static void renameregs(void) { + int i; + + for (i = 0; i < 8; i++) { + char *ptmp; + int itmp; + if (ireg[i]->x.regnode->vbl) + ireg[i]->x.regnode->vbl->x.name = oreg[i]->x.name; + exch(ireg[i]->x.name, oreg[i]->x.name, ptmp); + exch(ireg[i]->x.regnode->number, + oreg[i]->x.regnode->number, itmp); + } +} +static void defconst(int suffix, int size, Value v) { + if (suffix == F && size == 4) { + float f = v.d; + print(".word 0x%x\n", *(unsigned *)&f); + } else if (suffix == F && size == 8) { + double d = v.d; + unsigned *p = (unsigned *)&d; + print(".word 0x%x\n.word 0x%x\n", p[swap], p[!swap]); + } else if (suffix == P) + print(".word 0x%x\n", (unsigned)v.p); + else if (size == 1) + print(".byte 0x%x\n", (unsigned)((unsigned char)(suffix == I ? v.i : v.u))); + else if (size == 2) + print(".half 0x%x\n", (unsigned)((unsigned short)(suffix == I ? v.i : v.u))); + else if (size == 4) + print(".word 0x%x\n", (unsigned)(suffix == I ? v.i : v.u)); + else assert(0); +} + +static void defaddress(Symbol p) { + print(".word %s\n", p->x.name); +} + +static void defstring(int n, char *str) { + char *s; + + for (s = str; s < str + n; s++) + print(".byte %d\n", (*s)&0377); +} + +static void address(Symbol q, Symbol p, long n) { + if (p->scope == GLOBAL || p->sclass == STATIC || p->sclass == EXTERN) + q->x.name = stringf("%s%s%D", p->x.name, n >= 0 ? "+" : "", n); + else { + assert(n <= INT_MAX && n >= INT_MIN); + q->x.offset = p->x.offset + n; + q->x.name = stringd(q->x.offset); + } +} +static void export(Symbol p) { + print(".global %s\n", p->x.name); +} +static void import(Symbol p) {} +static void defsymbol(Symbol p) { + if (p->scope >= LOCAL && p->sclass == STATIC) + p->x.name = stringf("%d", genlabel(1)); + else + assert(p->scope != CONSTANTS || isint(p->type) || isptr(p->type)), + p->x.name = p->name; + if (p->scope >= LABELS) + p->x.name = stringf(p->generated ? "L%s" : "_%s", + p->x.name); +} +static void segment(int n) { + cseg = n; + switch (n) { + case CODE: print(".seg \"text\"\n"); break; + case BSS: print(".seg \"bss\"\n"); break; + case DATA: print(".seg \"data\"\n"); break; + case LIT: print(".seg \"text\"\n"); break; + } +} +static void space(int n) { + if (cseg != BSS) + print(".skip %d\n", n); +} +static void global(Symbol p) { + print(".align %d\n", p->type->align); + assert(p->u.seg); + if (p->u.seg == BSS + && (p->sclass == STATIC || Aflag >= 2)) + print(".reserve %s,%d\n", p->x.name, p->type->size); + else if (p->u.seg == BSS) + print(".common %s,%d\n", p->x.name, p->type->size); + else + print("%s:\n", p->x.name); +} +static void blkfetch(int k, int off, int reg, int tmp) { + assert(k == 1 || k == 2 || k == 4); + assert(salign >= k); + if (k == 1) + print("ldub [%%r%d+%d],%%r%d\n", reg, off, tmp); + else if (k == 2) + print("lduh [%%r%d+%d],%%r%d\n", reg, off, tmp); + else + print("ld [%%r%d+%d],%%r%d\n", reg, off, tmp); +} +static void blkstore(int k, int off, int reg, int tmp) { + assert(k == 1 || k == 2 || k == 4); + assert(dalign >= k); + if (k == 1) + print("stb %%r%d,[%%r%d+%d]\n", tmp, reg, off); + else if (k == 2) + print("sth %%r%d,[%%r%d+%d]\n", tmp, reg, off); + else + print("st %%r%d,[%%r%d+%d]\n", tmp, reg, off); +} +static void blkloop(int dreg, int doff, int sreg, int soff, int size, int tmps[]) { + if ((size&~7) < 4096) { + print("add %%r%d,%d,%%r%d\n", sreg, size&~7, sreg); + print("add %%r%d,%d,%%r%d\n", dreg, size&~7, tmps[2]); + } else { + print("set %d,%%r%d\n", size&~7, tmps[2]); + print("add %%r%d,%%r%d,%%r%d\n", sreg, tmps[2], sreg); + print("add %%r%d,%%r%d,%%r%d\n", dreg, tmps[2], tmps[2]); + } + blkcopy(tmps[2], doff, sreg, soff, size&7, tmps); + print("1: dec 8,%%r%d\n", tmps[2]); + blkcopy(tmps[2], doff, sreg, soff - 8, 8, tmps); + print("cmp %%r%d,%%r%d; ", tmps[2], dreg); + print("bgt 1b; "); + print("dec 8,%%r%d\n", sreg); +} +static void defsymbol2(Symbol p) { + if (p->scope >= LOCAL && p->sclass == STATIC) + p->x.name = stringf(".%d", genlabel(1)); + else + assert(p->scope != CONSTANTS || isint(p->type) || isptr(p->type)), + p->x.name = p->name; + if (p->scope >= LABELS) + p->x.name = stringf(p->generated ? ".L%s" : "%s", + p->x.name); +} + +static Symbol prevg; + +static void globalend(void) { + if (prevg && prevg->type->size > 0) + print(".size %s,%d\n", prevg->x.name, prevg->type->size); + prevg = NULL; +} + +static void export2(Symbol p) { + globalend(); + print(".global %s\n", p->x.name); +} + +static void progend2(void) { + globalend(); +} + +static void global2(Symbol p) { + globalend(); + assert(p->u.seg); + if (!p->generated) { + print(".type %s,#%s\n", p->x.name, + isfunc(p->type) ? "function" : "object"); + if (p->type->size > 0) + print(".size %s,%d\n", p->x.name, p->type->size); + else + prevg = p; + } + if (p->u.seg == BSS && p->sclass == STATIC) + print(".local %s\n.common %s,%d,%d\n", p->x.name, p->x.name, + p->type->size, p->type->align); + else if (p->u.seg == BSS && Aflag >= 2) + print(".align %d\n%s:.skip %d\n", p->type->align, p->x.name, + p->type->size); + else if (p->u.seg == BSS) + print(".common %s,%d,%d\n", p->x.name, p->type->size, p->type->align); + else + print(".align %d\n%s:\n", p->type->align, p->x.name); +} + +static void segment2(int n) { + cseg = n; + switch (n) { + case CODE: print(".section \".text\"\n"); break; + case BSS: print(".section \".bss\"\n"); break; + case DATA: print(".section \".data\"\n"); break; + case LIT: print(".section \".rodata\"\n"); break; + } +} +Interface sparcIR = { + 1, 1, 0, /* char */ + 2, 2, 0, /* short */ + 4, 4, 0, /* int */ + 4, 4, 0, /* long */ + 4, 4, 0, /* long long */ + 4, 4, 1, /* float */ + 8, 8, 1, /* double */ + 8, 8, 1, /* long double */ + 4, 4, 0, /* T * */ + 0, 1, 0, /* struct */ + 0, /* little_endian */ + 0, /* mulops_calls */ + 1, /* wants_callb */ + 0, /* wants_argb */ + 1, /* left_to_right */ + 0, /* wants_dag */ + 0, /* unsigned_char */ + address, + blockbeg, + blockend, + defaddress, + defconst, + defstring, + defsymbol, + emit, + export, + function, + gen, + global, + import, + local, + progbeg, + progend, + segment, + space, + stabblock, 0, 0, stabinit, stabline, stabsym, stabtype, + { + 1, /* max_unaligned_load */ + rmap, + blkfetch, blkstore, blkloop, + _label, + _rule, + _nts, + _kids, + _string, + _templates, + _isinstruction, + _ntname, + emit2, + doarg, + target, + clobber, + + } +}; + +Interface solarisIR = { + 1, 1, 0, /* char */ + 2, 2, 0, /* short */ + 4, 4, 0, /* int */ + 4, 4, 0, /* long */ + 4, 4, 0, /* long long */ + 4, 4, 1, /* float */ + 8, 8, 1, /* double */ + 8, 8, 1, /* long double */ + 4, 4, 0, /* T * */ + 0, 1, 0, /* struct */ + 0, /* little_endian */ + 0, /* mulops_calls */ + 1, /* wants_callb */ + 0, /* wants_argb */ + 1, /* left_to_right */ + 0, /* wants_dag */ + 0, /* unsigned_char */ + address, + blockbeg, + blockend, + defaddress, + defconst, + defstring, + defsymbol2, + emit, + export2, + function, + gen, + global2, + import, + local, + progbeg, + progend2, + segment2, + space, + stabblock, 0, 0, stabinit, stabline, stabsym, stabtype, + { + 1, /* max_unaligned_load */ + rmap, + blkfetch, blkstore, blkloop, + _label, + _rule, + _nts, + _kids, + _string, + _templates, + _isinstruction, + _ntname, + emit2, + doarg, + target, + clobber, + + } +}; diff --git a/src/cmd/lccom/stab.c b/src/cmd/lccom/stab.c new file mode 100644 index 0000000..91482d0 --- /dev/null +++ b/src/cmd/lccom/stab.c @@ -0,0 +1,329 @@ +#include +#include +#include "c.h" +#include "stab.h" + +static char *currentfile; /* current file name */ +static int ntypes; + +extern Interface sparcIR; + +char *stabprefix = "L"; + +extern char *stabprefix; +extern void stabblock(int, int, Symbol*); +extern void stabend(Coordinate *, Symbol, Coordinate **, Symbol *, Symbol *); +extern void stabfend(Symbol, int); +extern void stabinit(char *, int, char *[]); +extern void stabline(Coordinate *); +extern void stabsym(Symbol); +extern void stabtype(Symbol); + +static void asgncode(Type, int); +static void dbxout(Type); +static int dbxtype(Type); +static int emittype(Type, int, int); + +/* asgncode - assign type code to ty */ +static void asgncode(Type ty, int lev) { + if (ty->x.marked || ty->x.typeno) + return; + ty->x.marked = 1; + switch (ty->op) { + case VOLATILE: case CONST: case VOLATILE+CONST: + asgncode(ty->type, lev); + ty->x.typeno = ty->type->x.typeno; + break; + case POINTER: case FUNCTION: case ARRAY: + asgncode(ty->type, lev + 1); + /* fall thru */ + case VOID: case INT: case UNSIGNED: case FLOAT: + break; + case STRUCT: case UNION: { + Field p; + for (p = fieldlist(ty); p; p = p->link) + asgncode(p->type, lev + 1); + /* fall thru */ + case ENUM: + if (ty->x.typeno == 0) + ty->x.typeno = ++ntypes; + if (lev > 0 && (*ty->u.sym->name < '0' || *ty->u.sym->name > '9')) + dbxout(ty); + break; + } + default: + assert(0); + } +} + +/* dbxout - output .stabs entry for type ty */ +static void dbxout(Type ty) { + ty = unqual(ty); + if (!ty->x.printed) { + int col = 0; + print(".stabs \""), col += 8; + if (ty->u.sym && !(isfunc(ty) || isarray(ty) || isptr(ty))) + print("%s", ty->u.sym->name), col += strlen(ty->u.sym->name); + print(":%c", isstruct(ty) || isenum(ty) ? 'T' : 't'), col += 2; + emittype(ty, 0, col); + print("\",%d,0,0,0\n", N_LSYM); + } +} + +/* dbxtype - emit a stabs entry for type ty, return type code */ +static int dbxtype(Type ty) { + asgncode(ty, 0); + dbxout(ty); + return ty->x.typeno; +} + +/* + * emittype - emit ty's type number, emitting its definition if necessary. + * Returns the output column number after emission; col is the approximate + * output column before emission and is used to emit continuation lines for long + * struct, union, and enum types. Continuations are not emitted for other types, + * even if the definition is long. lev is the depth of calls to emittype. + */ +static int emittype(Type ty, int lev, int col) { + int tc = ty->x.typeno; + + if (isconst(ty) || isvolatile(ty)) { + col = emittype(ty->type, lev, col); + ty->x.typeno = ty->type->x.typeno; + ty->x.printed = 1; + return col; + } + if (tc == 0) { + ty->x.typeno = tc = ++ntypes; +/* fprint(2,"`%t'=%d\n", ty, tc); */ + } + print("%d", tc), col += 3; + if (ty->x.printed) + return col; + ty->x.printed = 1; + switch (ty->op) { + case VOID: /* void is defined as itself */ + print("=%d", tc), col += 1+3; + break; + case INT: + if (ty == chartype) /* plain char is a subrange of itself */ + print("=r%d;%d;%d;", tc, ty->u.sym->u.limits.min.i, ty->u.sym->u.limits.max.i), + col += 2+3+2*2.408*ty->size+2; + else /* other signed ints are subranges of int */ + print("=r1;%D;%D;", ty->u.sym->u.limits.min.i, ty->u.sym->u.limits.max.i), + col += 4+2*2.408*ty->size+2; + break; + case UNSIGNED: + if (ty == chartype) /* plain char is a subrange of itself */ + print("=r%d;0;%u;", tc, ty->u.sym->u.limits.max.i), + col += 2+3+2+2.408*ty->size+1; + else /* other signed ints are subranges of int */ + print("=r1;0;%U;", ty->u.sym->u.limits.max.i), + col += 4+2.408*ty->size+1; + break; + case FLOAT: /* float, double, long double get sizes, not ranges */ + print("=r1;%d;0;", ty->size), col += 4+1+3; + break; + case POINTER: + print("=*"), col += 2; + col = emittype(ty->type, lev + 1, col); + break; + case FUNCTION: + print("=f"), col += 2; + col = emittype(ty->type, lev + 1, col); + break; + case ARRAY: /* array includes subscript as an int range */ + if (ty->size && ty->type->size) + print("=ar1;0;%d;", ty->size/ty->type->size - 1), col += 7+3+1; + else + print("=ar1;0;-1;"), col += 10; + col = emittype(ty->type, lev + 1, col); + break; + case STRUCT: case UNION: { + Field p; + if (!ty->u.sym->defined) { + print("=x%c%s:", ty->op == STRUCT ? 's' : 'u', ty->u.sym->name); + col += 2+1+strlen(ty->u.sym->name)+1; + break; + } + if (lev > 0 && (*ty->u.sym->name < '0' || *ty->u.sym->name > '9')) { + ty->x.printed = 0; + break; + } + print("=%c%d", ty->op == STRUCT ? 's' : 'u', ty->size), col += 1+1+3; + for (p = fieldlist(ty); p; p = p->link) { + if (p->name) + print("%s:", p->name), col += strlen(p->name)+1; + else + print(":"), col += 1; + col = emittype(p->type, lev + 1, col); + if (p->lsb) + print(",%d,%d;", 8*p->offset + + (IR->little_endian ? fieldright(p) : fieldleft(p)), + fieldsize(p)); + else + print(",%d,%d;", 8*p->offset, 8*p->type->size); + col += 1+3+1+3+1; /* accounts for ,%d,%d; */ + if (col >= 80 && p->link) { + print("\\\\\",%d,0,0,0\n.stabs \"", N_LSYM); + col = 8; + } + } + print(";"), col += 1; + break; + } + case ENUM: { + Symbol *p; + if (lev > 0 && (*ty->u.sym->name < '0' || *ty->u.sym->name > '9')) { + ty->x.printed = 0; + break; + } + print("=e"), col += 2; + for (p = ty->u.sym->u.idlist; *p; p++) { + print("%s:%d,", (*p)->name, (*p)->u.value), col += strlen((*p)->name)+3; + if (col >= 80 && p[1]) { + print("\\\\\",%d,0,0,0\n.stabs \"", N_LSYM); + col = 8; + } + } + print(";"), col += 1; + break; + } + default: + assert(0); + } + return col; +} + +/* stabblock - output a stab entry for '{' or '}' at level lev */ +void stabblock(int brace, int lev, Symbol *p) { + if (brace == '{') + while (*p) + stabsym(*p++); + if (IR == &sparcIR) + print(".stabd 0x%x,0,%d\n", brace == '{' ? N_LBRAC : N_RBRAC, lev); + else { + int lab = genlabel(1); + print(".stabn 0x%x,0,%d,%s%d-%s\n", brace == '{' ? N_LBRAC : N_RBRAC, lev, + stabprefix, lab, cfunc->x.name); + print("%s%d:\n", stabprefix, lab); + } +} + +/* stabinit - initialize stab output */ +void stabinit(char *file, int argc, char *argv[]) { + typedef void (*Closure)(Symbol, void *); + extern char *getcwd(char *, size_t); + + print(".stabs \"lcc4_compiled.\",0x%x,0,0,0\n", N_OPT); + if (file && *file) { + char buf[1024], *cwd = getcwd(buf, sizeof buf); + if (cwd) + print(".stabs \"%s/\",0x%x,0,3,%stext0\n", cwd, N_SO, stabprefix); + print(".stabs \"%s\",0x%x,0,3,%stext0\n", file, N_SO, stabprefix); + (*IR->segment)(CODE); + print("%stext0:\n", stabprefix, N_SO); + currentfile = file; + } + dbxtype(inttype); + dbxtype(chartype); + dbxtype(doubletype); + dbxtype(floattype); + dbxtype(longdouble); + dbxtype(longtype); + dbxtype(longlong); + dbxtype(shorttype); + dbxtype(signedchar); + dbxtype(unsignedchar); + dbxtype(unsignedlong); + dbxtype(unsignedlonglong); + dbxtype(unsignedshort); + dbxtype(unsignedtype); + dbxtype(voidtype); + foreach(types, GLOBAL, (Closure)stabtype, NULL); +} + +/* stabline - emit stab entry for source coordinate *cp */ +void stabline(Coordinate *cp) { + if (cp->file && cp->file != currentfile) { + int lab = genlabel(1); + print(".stabs \"%s\",0x%x,0,0,%s%d\n", cp->file, N_SOL, stabprefix, lab); + print("%s%d:\n", stabprefix, lab); + currentfile = cp->file; + } + if (IR == &sparcIR) + print(".stabd 0x%x,0,%d\n", N_SLINE, cp->y); + else { + int lab = genlabel(1); + print(".stabn 0x%x,0,%d,%s%d-%s\n", N_SLINE, cp->y, + stabprefix, lab, cfunc->x.name); + print("%s%d:\n", stabprefix, lab); + } +} + +/* stabsym - output a stab entry for symbol p */ +void stabsym(Symbol p) { + int code, tc, sz = p->type->size; + + if (p->generated || p->computed) + return; + if (isfunc(p->type)) { + print(".stabs \"%s:%c%d\",%d,0,0,%s\n", p->name, + p->sclass == STATIC ? 'f' : 'F', dbxtype(freturn(p->type)), + N_FUN, p->x.name); + return; + } + if (!IR->wants_argb && p->scope == PARAM && p->structarg) { + assert(isptr(p->type) && isstruct(p->type->type)); + tc = dbxtype(p->type->type); + sz = p->type->type->size; + } else + tc = dbxtype(p->type); + if (p->sclass == AUTO && p->scope == GLOBAL || p->sclass == EXTERN) { + print(".stabs \"%s:G", p->name); + code = N_GSYM; + } else if (p->sclass == STATIC) { + print(".stabs \"%s:%c%d\",%d,0,0,%s\n", p->name, p->scope == GLOBAL ? 'S' : 'V', + tc, p->u.seg == BSS ? N_LCSYM : N_STSYM, p->x.name); + return; + } else if (p->sclass == REGISTER) { + if (p->x.regnode) { + int r = p->x.regnode->number; + if (p->x.regnode->set == FREG) + r += 32; /* floating point */ + print(".stabs \"%s:%c%d\",%d,0,", p->name, + p->scope == PARAM ? 'P' : 'r', tc, N_RSYM); + print("%d,%d\n", sz, r); + } + return; + } else if (p->scope == PARAM) { + print(".stabs \"%s:p", p->name); + code = N_PSYM; + } else if (p->scope >= LOCAL) { + print(".stabs \"%s:", p->name); + code = N_LSYM; + } else + assert(0); + print("%d\",%d,0,0,%s\n", tc, code, + p->scope >= PARAM && p->sclass != EXTERN ? p->x.name : "0"); +} + +/* stabtype - output a stab entry for type *p */ +void stabtype(Symbol p) { + if (p->type) { + if (p->sclass == 0) + dbxtype(p->type); + else if (p->sclass == TYPEDEF) + print(".stabs \"%s:t%d\",%d,0,0,0\n", p->name, dbxtype(p->type), N_LSYM); + } +} + +/* stabend - finalize a function */ +void stabfend(Symbol p, int lineno) {} + +/* stabend - finalize stab output */ +void stabend(Coordinate *cp, Symbol p, Coordinate **cpp, Symbol *sp, Symbol *stab) { + (*IR->segment)(CODE); + print(".stabs \"\", %d, 0, 0,%setext\n", N_SO, stabprefix); + print("%setext:\n", stabprefix); +} diff --git a/src/cmd/lccom/stab.h b/src/cmd/lccom/stab.h new file mode 100644 index 0000000..0fe57e4 --- /dev/null +++ b/src/cmd/lccom/stab.h @@ -0,0 +1,108 @@ +/* + * Copyright (c) 1990 by Sun Microsystems, Inc. + * + * This file gives definitions supplementing + * for permanent symbol table entries. + * These must have one of the N_STAB bits on, + * and are subject to relocation according to the masks in . + */ +#ifndef _STAB_H +#define _STAB_H + +#if !defined(_a_out_h) && !defined(_A_OUT_H) +/* this file contains fragments of a.out.h and stab.h relevant to + * support of stabX processing within ELF files - see the + * Format of a symbol table entry + */ +struct nlist { + union { + char *n_name; /* for use when in-core */ + long n_strx; /* index into file string table */ + } n_un; + unsigned char n_type; /* type flag (N_TEXT,..) */ + char n_other; /* unused */ + short n_desc; /* see */ + unsigned long n_value; /* value of symbol (or sdb offset) */ +}; + +/* + * Simple values for n_type. + */ +#define N_UNDF 0x0 /* undefined */ +#define N_ABS 0x2 /* absolute */ +#define N_TEXT 0x4 /* text */ +#define N_DATA 0x6 /* data */ +#define N_BSS 0x8 /* bss */ +#define N_COMM 0x12 /* common (internal to ld) */ +#define N_FN 0x1f /* file name symbol */ + +#define N_EXT 01 /* external bit, or'ed in */ +#define N_TYPE 0x1e /* mask for all the type bits */ + +#endif + +/* + * for symbolic debugger, sdb(1): + */ +#define N_GSYM 0x20 /* global symbol: name,,0,type,0 */ +#define N_FNAME 0x22 /* procedure name (f77 kludge): name,,0 */ +#define N_FUN 0x24 /* procedure: name,,0,linenumber,address */ +#define N_STSYM 0x26 /* static symbol: name,,0,type,address */ +#define N_LCSYM 0x28 /* .lcomm symbol: name,,0,type,address */ +#define N_MAIN 0x2a /* name of main routine : name,,0,0,0 */ +#define N_ROSYM 0x2c /* ro_data objects */ +#define N_OBJ 0x38 /* object file path or name */ +#define N_OPT 0x3c /* compiler options */ +#define N_RSYM 0x40 /* register sym: name,,0,type,register */ +#define N_SLINE 0x44 /* src line: 0,,0,linenumber,address */ +#define N_FLINE 0x4c /* function start.end */ +#define N_SSYM 0x60 /* structure elt: name,,0,type,struct_offset */ +#define N_ENDM 0x62 /* last stab emitted for module */ +#define N_SO 0x64 /* source file name: name,,0,0,address */ +#define N_LSYM 0x80 /* local sym: name,,0,type,offset */ +#define N_BINCL 0x82 /* header file: name,,0,0,0 */ +#define N_SOL 0x84 /* #included file name: name,,0,0,address */ +#define N_PSYM 0xa0 /* parameter: name,,0,type,offset */ +#define N_EINCL 0xa2 /* end of include file */ +#define N_ENTRY 0xa4 /* alternate entry: name,linenumber,address */ +#define N_LBRAC 0xc0 /* left bracket: 0,,0,nesting level,address */ +#define N_EXCL 0xc2 /* excluded include file */ +#define N_RBRAC 0xe0 /* right bracket: 0,,0,nesting level,address */ +#define N_BCOMM 0xe2 /* begin common: name,, */ +#define N_ECOMM 0xe4 /* end common: name,, */ +#define N_ECOML 0xe8 /* end common (local name): ,,address */ +#define N_LENG 0xfe /* second stab entry with length information */ + +/* + * for the berkeley pascal compiler, pc(1): + */ +#define N_PC 0x30 /* global pascal symbol: name,,0,subtype,line */ +#define N_WITH 0xea /* pascal with statement: type,,0,0,offset */ + +/* + * for code browser only + */ +#define N_BROWS 0x48 /* path to associated .cb file */ + +/* + * Optional langauge designations for N_SO + */ +#define N_SO_AS 1 /* Assembler */ +#define N_SO_C 2 /* C */ +#define N_SO_ANSI_C 3 /* ANSI C */ +#define N_SO_CC 4 /* C++ */ +#define N_SO_FORTRAN 5 /* Fortran 77 */ +#define N_SO_PASCAL 6 /* Pascal */ + +/* + * Floating point type values + */ +#define NF_NONE 0 /* Undefined type */ +#define NF_SINGLE 1 /* IEEE 32 bit float */ +#define NF_DOUBLE 2 /* IEEE 64 bit float */ +#define NF_COMPLEX 3 /* Fortran complex */ +#define NF_COMPLEX16 4 /* Fortran double complex */ +#define NF_COMPLEX32 5 /* Fortran complex*16 */ +#define NF_LDOUBLE 6 /* Long double */ + +#endif diff --git a/src/cmd/lccom/stmt.c b/src/cmd/lccom/stmt.c new file mode 100644 index 0000000..b8669e9 --- /dev/null +++ b/src/cmd/lccom/stmt.c @@ -0,0 +1,707 @@ +#include "c.h" + +#define SWSIZE 512 + +#define den(i,j) ((j-buckets[i]+1.0)/(v[j]-v[buckets[i]]+1)) + +struct code codehead = { Start }; +Code codelist = &codehead; +float density = 0.5; +Table stmtlabs; + +static int foldcond(Tree e1, Tree e2); +static void caselabel(Swtch, long, int); +static void cmp(int, Symbol, long, int); +static Tree conditional(int); +static void dostmt(int, Swtch, int); +static int equal(Symbol, Symbol); +static void forstmt(int, Swtch, int); +static void ifstmt(int, int, Swtch, int); +static Symbol localaddr(Tree); +static void stmtlabel(void); +static void swstmt(int, int, int); +static void whilestmt(int, Swtch, int); +Code code(int kind) { + Code cp; + + if (!reachable(kind)) + warning("unreachable code\n"); + + NEW(cp, FUNC); + cp->kind = kind; + cp->prev = codelist; + cp->next = NULL; + codelist->next = cp; + codelist = cp; + return cp; +} + +int reachable(int kind) { + if (kind > Start) { + Code cp; + for (cp = codelist; cp->kind < Label; ) + cp = cp->prev; + if (cp->kind == Jump || cp->kind == Switch) + return 0; + } + return 1; +} + +void addlocal(Symbol p) { + if (!p->defined) { + code(Local)->u.var = p; + p->defined = 1; + p->scope = level; + } +} +void definept(Coordinate *p) { + Code cp = code(Defpoint); + + cp->u.point.src = p ? *p : src; + cp->u.point.point = npoints; + if (ncalled > 0) { + int n = findcount(cp->u.point.src.file, + cp->u.point.src.x, cp->u.point.src.y); + if (n > 0) + refinc = (float)n/ncalled; + } + if (glevel > 2) locus(identifiers, &cp->u.point.src); + if (events.points && reachable(Gen)) + { + Tree e = NULL; + apply(events.points, &cp->u.point.src, &e); + if (e) + listnodes(e, 0, 0); + } +} +void statement(int loop, Swtch swp, int lev) { + float ref = refinc; + + if (Aflag >= 2 && lev == 15) + warning("more than 15 levels of nested statements\n"); + switch (t) { + case IF: ifstmt(genlabel(2), loop, swp, lev + 1); + break; + case WHILE: whilestmt(genlabel(3), swp, lev + 1); break; + case DO: dostmt(genlabel(3), swp, lev + 1); expect(';'); + break; + + case FOR: forstmt(genlabel(4), swp, lev + 1); + break; + case BREAK: walk(NULL, 0, 0); + definept(NULL); + if (swp && swp->lab > loop) + branch(swp->lab + 1); + else if (loop) + branch(loop + 2); + else + error("illegal break statement\n"); + t = gettok(); expect(';'); + break; + + case CONTINUE: walk(NULL, 0, 0); + definept(NULL); + if (loop) + branch(loop + 1); + else + error("illegal continue statement\n"); + t = gettok(); expect(';'); + break; + + case SWITCH: swstmt(loop, genlabel(2), lev + 1); + break; + case CASE: { + int lab = genlabel(1); + if (swp == NULL) + error("illegal case label\n"); + definelab(lab); + while (t == CASE) { + static char stop[] = { IF, ID, 0 }; + Tree p; + t = gettok(); + p = constexpr(0); + if (generic(p->op) == CNST && isint(p->type)) { + if (swp) { + needconst++; + p = cast(p, swp->sym->type); + if (p->type->op == UNSIGNED) + p->u.v.i = extend(p->u.v.u, p->type); + needconst--; + caselabel(swp, p->u.v.i, lab); + } + } else + error("case label must be a constant integer expression\n"); + + test(':', stop); + } + statement(loop, swp, lev); + } break; + case DEFAULT: if (swp == NULL) + error("illegal default label\n"); + else if (swp->deflab) + error("extra default label\n"); + else { + swp->deflab = findlabel(swp->lab); + definelab(swp->deflab->u.l.label); + } + t = gettok(); + expect(':'); + statement(loop, swp, lev); break; + case RETURN: { + Type rty = freturn(cfunc->type); + t = gettok(); + definept(NULL); + if (t != ';') + if (rty == voidtype) { + error("extraneous return value\n"); + expr(0); + retcode(NULL); + } else + retcode(expr(0)); + else { + if (rty != voidtype) { + warning("missing return value\n"); + retcode(cnsttree(inttype, 0L)); + } else + retcode(NULL); + } + branch(cfunc->u.f.label); + } expect(';'); + break; + + case '{': compound(loop, swp, lev + 1); break; + case ';': definept(NULL); t = gettok(); break; + case GOTO: walk(NULL, 0, 0); + definept(NULL); + t = gettok(); + if (t == ID) { + Symbol p = lookup(token, stmtlabs); + if (p == NULL) { + p = install(token, &stmtlabs, 0, FUNC); + p->scope = LABELS; + p->u.l.label = genlabel(1); + p->src = src; + } + use(p, src); + branch(p->u.l.label); + t = gettok(); + } else + error("missing label in goto\n"); expect(';'); + break; + + case ID: if (getchr() == ':') { + stmtlabel(); + statement(loop, swp, lev); + break; + } + default: definept(NULL); + if (kind[t] != ID) { + error("unrecognized statement\n"); + t = gettok(); + } else { + Tree e = expr0(0); + listnodes(e, 0, 0); + if (nodecount == 0 || nodecount > 200) + walk(NULL, 0, 0); + else if (glevel) walk(NULL, 0, 0); + deallocate(STMT); + } expect(';'); + break; + + } + if (kind[t] != IF && kind[t] != ID + && t != '}' && t != EOI) { + static char stop[] = { IF, ID, '}', 0 }; + error("illegal statement termination\n"); + skipto(0, stop); + } + refinc = ref; +} + +static void ifstmt(int lab, int loop, Swtch swp, int lev) { + t = gettok(); + expect('('); + definept(NULL); + walk(conditional(')'), 0, lab); + refinc /= 2.0; + statement(loop, swp, lev); + if (t == ELSE) { + branch(lab + 1); + t = gettok(); + definelab(lab); + statement(loop, swp, lev); + if (findlabel(lab + 1)->ref) + definelab(lab + 1); + } else + definelab(lab); +} +static Tree conditional(int tok) { + Tree p = expr(tok); + + if (Aflag > 1 && isfunc(p->type)) + warning("%s used in a conditional expression\n", + funcname(p)); + return cond(p); +} +static void stmtlabel(void) { + Symbol p = lookup(token, stmtlabs); + + if (p == NULL) { + p = install(token, &stmtlabs, 0, FUNC); + p->scope = LABELS; + p->u.l.label = genlabel(1); + p->src = src; + } + if (p->defined) + error("redefinition of label `%s' previously defined at %w\n", p->name, &p->src); + + p->defined = 1; + definelab(p->u.l.label); + t = gettok(); + expect(':'); +} +static void forstmt(int lab, Swtch swp, int lev) { + int once = 0; + Tree e1 = NULL, e2 = NULL, e3 = NULL; + Coordinate pt2, pt3; + + t = gettok(); + expect('('); + definept(NULL); + if (kind[t] == ID) + e1 = texpr(expr0, ';', FUNC); + else + expect(';'); + walk(e1, 0, 0); + pt2 = src; + refinc *= 10.0; + if (kind[t] == ID) + e2 = texpr(conditional, ';', FUNC); + else + expect(';'); + pt3 = src; + if (kind[t] == ID) + e3 = texpr(expr0, ')', FUNC); + else { + static char stop[] = { IF, ID, '}', 0 }; + test(')', stop); + } + if (e2) { + once = foldcond(e1, e2); + if (!once) + branch(lab + 3); + } + definelab(lab); + statement(lab, swp, lev); + definelab(lab + 1); + definept(&pt3); + if (e3) + walk(e3, 0, 0); + if (e2) { + if (!once) + definelab(lab + 3); + definept(&pt2); + walk(e2, lab, 0); + } else { + definept(&pt2); + branch(lab); + } + if (findlabel(lab + 2)->ref) + definelab(lab + 2); +} +static void swstmt(int loop, int lab, int lev) { + Tree e; + struct swtch sw; + Code head, tail; + + t = gettok(); + expect('('); + definept(NULL); + e = expr(')'); + if (!isint(e->type)) { + error("illegal type `%t' in switch expression\n", + e->type); + e = retype(e, inttype); + } + e = cast(e, promote(e->type)); + if (generic(e->op) == INDIR && isaddrop(e->kids[0]->op) + && e->kids[0]->u.sym->type == e->type + && !isvolatile(e->kids[0]->u.sym->type)) { + sw.sym = e->kids[0]->u.sym; + walk(NULL, 0, 0); + } else { + sw.sym = genident(REGISTER, e->type, level); + addlocal(sw.sym); + walk(asgn(sw.sym, e), 0, 0); + } + head = code(Switch); + sw.lab = lab; + sw.deflab = NULL; + sw.ncases = 0; + sw.size = SWSIZE; + sw.values = newarray(SWSIZE, sizeof *sw.values, FUNC); + sw.labels = newarray(SWSIZE, sizeof *sw.labels, FUNC); + refinc /= 10.0; + statement(loop, &sw, lev); + if (sw.deflab == NULL) { + sw.deflab = findlabel(lab); + definelab(lab); + if (sw.ncases == 0) + warning("switch statement with no cases\n"); + } + if (findlabel(lab + 1)->ref) + definelab(lab + 1); + tail = codelist; + codelist = head->prev; + codelist->next = head->prev = NULL; + if (sw.ncases > 0) + swgen(&sw); + branch(lab); + head->next->prev = codelist; + codelist->next = head->next; + codelist = tail; +} +static void caselabel(Swtch swp, long val, int lab) { + int k; + + if (swp->ncases >= swp->size) + { + long *vals = swp->values; + Symbol *labs = swp->labels; + swp->size *= 2; + swp->values = newarray(swp->size, sizeof *swp->values, FUNC); + swp->labels = newarray(swp->size, sizeof *swp->labels, FUNC); + for (k = 0; k < swp->ncases; k++) { + swp->values[k] = vals[k]; + swp->labels[k] = labs[k]; + } + } + k = swp->ncases; + for ( ; k > 0 && swp->values[k-1] >= val; k--) { + swp->values[k] = swp->values[k-1]; + swp->labels[k] = swp->labels[k-1]; + } + if (k < swp->ncases && swp->values[k] == val) + error("duplicate case label `%d'\n", val); + swp->values[k] = val; + swp->labels[k] = findlabel(lab); + ++swp->ncases; + if (Aflag >= 2 && swp->ncases == 258) + warning("more than 257 cases in a switch\n"); +} +void swgen(Swtch swp) { + int *buckets, k, n; + long *v = swp->values; + + buckets = newarray(swp->ncases + 1, + sizeof *buckets, FUNC); + for (n = k = 0; k < swp->ncases; k++, n++) { + buckets[n] = k; + while (n > 0 && den(n-1, k) >= density) + n--; + } + buckets[n] = swp->ncases; + swcode(swp, buckets, 0, n - 1); +} +void swcode(Swtch swp, int b[], int lb, int ub) { + int hilab, lolab, l, u, k = (lb + ub)/2; + long *v = swp->values; + + if (k > lb && k < ub) { + lolab = genlabel(1); + hilab = genlabel(1); + } else if (k > lb) { + lolab = genlabel(1); + hilab = swp->deflab->u.l.label; + } else if (k < ub) { + lolab = swp->deflab->u.l.label; + hilab = genlabel(1); + } else + lolab = hilab = swp->deflab->u.l.label; + l = b[k]; + u = b[k+1] - 1; + if (u - l + 1 <= 3) + { + int i; + for (i = l; i <= u; i++) + cmp(EQ, swp->sym, v[i], swp->labels[i]->u.l.label); + if (k > lb && k < ub) + cmp(GT, swp->sym, v[u], hilab); + else if (k > lb) + cmp(GT, swp->sym, v[u], hilab); + else if (k < ub) + cmp(LT, swp->sym, v[l], lolab); + else { + assert(lolab == hilab); + branch(lolab); + } + walk(NULL, 0, 0); + } + else { + Tree e; + Type ty = signedint(swp->sym->type); + Symbol table = genident(STATIC, + array(voidptype, u - l + 1, 0), GLOBAL); + (*IR->defsymbol)(table); + if (!isunsigned(swp->sym->type) || v[l] != 0) + cmp(LT, swp->sym, v[l], lolab); + cmp(GT, swp->sym, v[u], hilab); + e = (*optree['-'])(SUB, cast(idtree(swp->sym), ty), cnsttree(ty, v[l])); + if (e->type->size < unsignedptr->size) + e = cast(e, unsignedlong); + walk(tree(JUMP, voidtype, + rvalue((*optree['+'])(ADD, pointer(idtree(table)), e)), NULL), + 0, 0); + code(Switch); + codelist->u.swtch.table = table; + codelist->u.swtch.sym = swp->sym; + codelist->u.swtch.deflab = swp->deflab; + codelist->u.swtch.size = u - l + 1; + codelist->u.swtch.values = &v[l]; + codelist->u.swtch.labels = &swp->labels[l]; + if (v[u] - v[l] + 1 >= 10000) + warning("switch generates a huge table\n"); + } + if (k > lb) { + assert(lolab != swp->deflab->u.l.label); + definelab(lolab); + swcode(swp, b, lb, k - 1); + } + if (k < ub) { + assert(hilab != swp->deflab->u.l.label); + definelab(hilab); + swcode(swp, b, k + 1, ub); + } +} +static void cmp(int op, Symbol p, long n, int lab) { + Type ty = signedint(p->type); + + listnodes(eqtree(op, + cast(idtree(p), ty), + cnsttree(ty, n)), + lab, 0); +} +void retcode(Tree p) { + Type ty; + + if (p == NULL) { + if (events.returns) + apply(events.returns, cfunc, NULL); + return; + } + p = pointer(p); + ty = assign(freturn(cfunc->type), p); + if (ty == NULL) { + error("illegal return type; found `%t' expected `%t'\n", + p->type, freturn(cfunc->type)); + return; + } + p = cast(p, ty); + if (retv) + { + if (iscallb(p)) + p = tree(RIGHT, p->type, + tree(CALL+B, p->type, + p->kids[0]->kids[0], idtree(retv)), + rvalue(idtree(retv))); + else { + Type ty = retv->type->type; + assert(isstruct(ty)); + if (ty->u.sym->u.s.cfields) { + ty->u.sym->u.s.cfields = 0; + p = asgntree(ASGN, rvalue(idtree(retv)), p); + ty->u.sym->u.s.cfields = 1; + } else + p = asgntree(ASGN, rvalue(idtree(retv)), p); + } + walk(p, 0, 0); + if (events.returns) + apply(events.returns, cfunc, rvalue(idtree(retv))); + return; + } + if (events.returns) + { + Symbol t1 = genident(AUTO, p->type, level); + addlocal(t1); + walk(asgn(t1, p), 0, 0); + apply(events.returns, cfunc, idtree(t1)); + p = idtree(t1); + } + if (!isfloat(p->type)) + p = cast(p, promote(p->type)); + if (isptr(p->type)) + { + Symbol q = localaddr(p); + if (q && (q->computed || q->generated)) + warning("pointer to a %s is an illegal return value\n", + q->scope == PARAM ? "parameter" : "local"); + else if (q) + warning("pointer to %s `%s' is an illegal return value\n", + q->scope == PARAM ? "parameter" : "local", q->name); + } + walk(tree(mkop(RET,p->type), p->type, p, NULL), 0, 0); +} +void definelab(int lab) { + Code cp; + Symbol p = findlabel(lab); + + assert(lab); + walk(NULL, 0, 0); + code(Label)->u.forest = newnode(LABEL+V, NULL, NULL, p); + for (cp = codelist->prev; cp->kind <= Label; ) + cp = cp->prev; + while ( cp->kind == Jump + && cp->u.forest->kids[0] + && specific(cp->u.forest->kids[0]->op) == ADDRG+P + && cp->u.forest->kids[0]->syms[0] == p) { + assert(cp->u.forest->kids[0]->syms[0]->u.l.label == lab); + p->ref--; + assert(cp->next); + assert(cp->prev); + cp->prev->next = cp->next; + cp->next->prev = cp->prev; + cp = cp->prev; + while (cp->kind <= Label) + cp = cp->prev; + } +} +Node jump(int lab) { + Symbol p = findlabel(lab); + + p->ref++; + return newnode(JUMP+V, newnode(ADDRG+ttob(voidptype), NULL, NULL, p), + NULL, NULL); +} +void branch(int lab) { + Code cp; + Symbol p = findlabel(lab); + + assert(lab); + walk(NULL, 0, 0); + code(Label)->u.forest = jump(lab); + for (cp = codelist->prev; cp->kind < Label; ) + cp = cp->prev; + while ( cp->kind == Label + && cp->u.forest->op == LABEL+V + && !equal(cp->u.forest->syms[0], p)) { + equatelab(cp->u.forest->syms[0], p); + assert(cp->next); + assert(cp->prev); + cp->prev->next = cp->next; + cp->next->prev = cp->prev; + cp = cp->prev; + while (cp->kind < Label) + cp = cp->prev; + } + if (cp->kind == Jump || cp->kind == Switch) { + p->ref--; + codelist->prev->next = NULL; + codelist = codelist->prev; + } else { + codelist->kind = Jump; + if (cp->kind == Label + && cp->u.forest->op == LABEL+V + && equal(cp->u.forest->syms[0], p)) + warning("source code specifies an infinite loop\n"); + } +} +void equatelab(Symbol old, Symbol new) { + assert(old->u.l.equatedto == NULL); + old->u.l.equatedto = new; + new->ref++; +} +static int equal(Symbol lprime, Symbol dst) { + assert(dst && lprime); + for ( ; dst; dst = dst->u.l.equatedto) + if (lprime == dst) + return 1; + return 0; +} +/* dostmt - do statement while ( expression ) */ +static void dostmt(int lab, Swtch swp, int lev) { + refinc *= 10.0; + t = gettok(); + definelab(lab); + statement(lab, swp, lev); + definelab(lab + 1); + expect(WHILE); + expect('('); + definept(NULL); + walk(conditional(')'), lab, 0); + if (findlabel(lab + 2)->ref) + definelab(lab + 2); +} + +/* foldcond - check if initial test in for(e1;e2;e3) S is necessary */ +static int foldcond(Tree e1, Tree e2) { + int op = generic(e2->op); + Symbol v; + + if (e1 == 0 || e2 == 0) + return 0; + if (generic(e1->op) == ASGN && isaddrop(e1->kids[0]->op) + && generic(e1->kids[1]->op) == CNST) { + v = e1->kids[0]->u.sym; + e1 = e1->kids[1]; + } else + return 0; + if ((op==LE || op==LT || op==EQ || op==NE || op==GT || op==GE) + && generic(e2->kids[0]->op) == INDIR + && e2->kids[0]->kids[0]->u.sym == v + && e2->kids[1]->op == e1->op) { + e1 = simplify(op, e2->type, e1, e2->kids[1]); + if (e1->op == CNST+I) + return e1->u.v.i; + } + return 0; +} + +/* localaddr - returns q if p yields the address of local/parameter q; otherwise returns 0 */ +static Symbol localaddr(Tree p) { + if (p == NULL) + return NULL; + switch (generic(p->op)) { + case INDIR: case CALL: case ARG: + return NULL; + case ADDRL: case ADDRF: + return p->u.sym; + case RIGHT: case ASGN: + if (p->kids[1]) + return localaddr(p->kids[1]); + return localaddr(p->kids[0]); + case COND: { + Symbol q; + assert(p->kids[1] && p->kids[1]->op == RIGHT); + if ((q = localaddr(p->kids[1]->kids[0])) != NULL) + return q; + return localaddr(p->kids[1]->kids[1]); + } + default: { + Symbol q; + if (p->kids[0] && (q = localaddr(p->kids[0])) != NULL) + return q; + return localaddr(p->kids[1]); + } + } +} + +/* whilestmt - while ( expression ) statement */ +static void whilestmt(int lab, Swtch swp, int lev) { + Coordinate pt; + Tree e; + + refinc *= 10.0; + t = gettok(); + expect('('); + walk(NULL, 0, 0); + pt = src; + e = texpr(conditional, ')', FUNC); + branch(lab + 1); + definelab(lab); + statement(lab, swp, lev); + definelab(lab + 1); + definept(&pt); + walk(e, lab, 0); + if (findlabel(lab + 2)->ref) + definelab(lab + 2); +} diff --git a/src/cmd/lccom/string.c b/src/cmd/lccom/string.c new file mode 100644 index 0000000..893fc96 --- /dev/null +++ b/src/cmd/lccom/string.c @@ -0,0 +1,125 @@ +#include "c.h" + +static struct string { + char *str; + int len; + struct string *link; +} *buckets[1024]; + +static int scatter[] = { /* map characters to random values */ + 2078917053, 143302914, 1027100827, 1953210302, 755253631, + 2002600785, 1405390230, 45248011, 1099951567, 433832350, + 2018585307, 438263339, 813528929, 1703199216, 618906479, + 573714703, 766270699, 275680090, 1510320440, 1583583926, + 1723401032, 1965443329, 1098183682, 1636505764, 980071615, + 1011597961, 643279273, 1315461275, 157584038, 1069844923, + 471560540, 89017443, 1213147837, 1498661368, 2042227746, + 1968401469, 1353778505, 1300134328, 2013649480, 306246424, + 1733966678, 1884751139, 744509763, 400011959, 1440466707, + 1363416242, 973726663, 59253759, 1639096332, 336563455, + 1642837685, 1215013716, 154523136, 593537720, 704035832, + 1134594751, 1605135681, 1347315106, 302572379, 1762719719, + 269676381, 774132919, 1851737163, 1482824219, 125310639, + 1746481261, 1303742040, 1479089144, 899131941, 1169907872, + 1785335569, 485614972, 907175364, 382361684, 885626931, + 200158423, 1745777927, 1859353594, 259412182, 1237390611, + 48433401, 1902249868, 304920680, 202956538, 348303940, + 1008956512, 1337551289, 1953439621, 208787970, 1640123668, + 1568675693, 478464352, 266772940, 1272929208, 1961288571, + 392083579, 871926821, 1117546963, 1871172724, 1771058762, + 139971187, 1509024645, 109190086, 1047146551, 1891386329, + 994817018, 1247304975, 1489680608, 706686964, 1506717157, + 579587572, 755120366, 1261483377, 884508252, 958076904, + 1609787317, 1893464764, 148144545, 1415743291, 2102252735, + 1788268214, 836935336, 433233439, 2055041154, 2109864544, + 247038362, 299641085, 834307717, 1364585325, 23330161, + 457882831, 1504556512, 1532354806, 567072918, 404219416, + 1276257488, 1561889936, 1651524391, 618454448, 121093252, + 1010757900, 1198042020, 876213618, 124757630, 2082550272, + 1834290522, 1734544947, 1828531389, 1982435068, 1002804590, + 1783300476, 1623219634, 1839739926, 69050267, 1530777140, + 1802120822, 316088629, 1830418225, 488944891, 1680673954, + 1853748387, 946827723, 1037746818, 1238619545, 1513900641, + 1441966234, 367393385, 928306929, 946006977, 985847834, + 1049400181, 1956764878, 36406206, 1925613800, 2081522508, + 2118956479, 1612420674, 1668583807, 1800004220, 1447372094, + 523904750, 1435821048, 923108080, 216161028, 1504871315, + 306401572, 2018281851, 1820959944, 2136819798, 359743094, + 1354150250, 1843084537, 1306570817, 244413420, 934220434, + 672987810, 1686379655, 1301613820, 1601294739, 484902984, + 139978006, 503211273, 294184214, 176384212, 281341425, + 228223074, 147857043, 1893762099, 1896806882, 1947861263, + 1193650546, 273227984, 1236198663, 2116758626, 489389012, + 593586330, 275676551, 360187215, 267062626, 265012701, + 719930310, 1621212876, 2108097238, 2026501127, 1865626297, + 894834024, 552005290, 1404522304, 48964196, 5816381, + 1889425288, 188942202, 509027654, 36125855, 365326415, + 790369079, 264348929, 513183458, 536647531, 13672163, + 313561074, 1730298077, 286900147, 1549759737, 1699573055, + 776289160, 2143346068, 1975249606, 1136476375, 262925046, + 92778659, 1856406685, 1884137923, 53392249, 1735424165, + 1602280572 +}; + +char *string(const char *str) { + const char *s; + + for (s = str; *s; s++) + ; + return stringn(str, s - str); +} + +char *stringd(long n) { + char str[25], *s = str + sizeof (str); + unsigned long m; + + if (n == LONG_MIN) + m = (unsigned long)LONG_MAX + 1; + else if (n < 0) + m = -n; + else + m = n; + do + *--s = m%10 + '0'; + while ((m /= 10) != 0); + if (n < 0) + *--s = '-'; + return stringn(s, str + sizeof (str) - s); +} + +char *stringn(const char *str, int len) { + int i; + unsigned int h; + const char *end; + struct string *p; + + assert(str); + for (h = 0, i = len, end = str; i > 0; i--) + h = (h<<1) + scatter[*(unsigned char *)end++]; + h &= NELEMS(buckets)-1; + for (p = buckets[h]; p; p = p->link) + if (len == p->len) { + const char *s1 = str; + char *s2 = p->str; + do { + if (s1 == end) + return p->str; + } while (*s1++ == *s2++); + } + { + static char *next, *strlimit; + if (len + 1 >= strlimit - next) { + int n = len + 4*1024; + next = allocate(n, PERM); + strlimit = next + n; + } + NEW(p, PERM); + p->len = len; + for (p->str = next; str < end; ) + *next++ = *str++; + *next++ = 0; + p->link = buckets[h]; + buckets[h] = p; + return p->str; + } +} diff --git a/src/cmd/lccom/sym.c b/src/cmd/lccom/sym.c new file mode 100644 index 0000000..ff02236 --- /dev/null +++ b/src/cmd/lccom/sym.c @@ -0,0 +1,334 @@ +#include "c.h" +#include + +#define equalp(x) v.x == p->sym.u.c.v.x + +struct table { + int level; + Table previous; + struct entry { + struct symbol sym; + struct entry *link; + } *buckets[256]; + Symbol all; +}; + +#define HASHSIZE NELEMS(((Table)0)->buckets) + +static struct table + cns = { CONSTANTS }, + ext = { GLOBAL }, + ids = { GLOBAL }, + tys = { GLOBAL }; +Table constants = &cns; +Table externals = &ext; +Table identifiers = &ids; +Table globals = &ids; +Table types = &tys; +Table labels; +int level = GLOBAL; +static int tempid; +List loci, symbols; + +Table newtable(int arena) { + Table new; + + NEW0(new, arena); + return new; +} + +Table table(Table tp, int level) { + Table new = newtable(FUNC); + new->previous = tp; + new->level = level; + if (tp) + new->all = tp->all; + return new; +} +void foreach(Table tp, int lev, void (*apply)(Symbol, void *), void *cl) { + assert(tp); + while (tp && tp->level > lev) + tp = tp->previous; + if (tp && tp->level == lev) { + Symbol p; + Coordinate sav; + sav = src; + for (p = tp->all; p && p->scope == lev; p = p->up) { + src = p->src; + (*apply)(p, cl); + } + src = sav; + } +} +void enterscope(void) { + if (++level == LOCAL) + tempid = 0; +} +void exitscope(void) { + rmtypes(level); + if (types->level == level) + types = types->previous; + if (identifiers->level == level) { + if (Aflag >= 2) { + int n = 0; + Symbol p; + for (p = identifiers->all; p && p->scope == level; p = p->up) + if (++n > 127) { + warning("more than 127 identifiers declared in a block\n"); + break; + } + } + identifiers = identifiers->previous; + } + assert(level >= GLOBAL); + --level; +} +Symbol install(const char *name, Table *tpp, int level, int arena) { + Table tp = *tpp; + struct entry *p; + unsigned h = (unsigned long)name&(HASHSIZE-1); + + assert(level == 0 || level >= tp->level); + if (level > 0 && tp->level < level) + tp = *tpp = table(tp, level); + NEW0(p, arena); + p->sym.name = (char *)name; + p->sym.scope = level; + p->sym.up = tp->all; + tp->all = &p->sym; + p->link = tp->buckets[h]; + tp->buckets[h] = p; + return &p->sym; +} +Symbol relocate(const char *name, Table src, Table dst) { + struct entry *p, **q; + Symbol *r; + unsigned h = (unsigned long)name&(HASHSIZE-1); + + for (q = &src->buckets[h]; *q; q = &(*q)->link) + if (name == (*q)->sym.name) + break; + assert(*q); + /* + Remove the entry from src's hash chain + and from its list of all symbols. + */ + p = *q; + *q = (*q)->link; + for (r = &src->all; *r && *r != &p->sym; r = &(*r)->up) + ; + assert(*r == &p->sym); + *r = p->sym.up; + /* + Insert the entry into dst's hash chain + and into its list of all symbols. + Return the symbol-table entry. + */ + p->link = dst->buckets[h]; + dst->buckets[h] = p; + p->sym.up = dst->all; + dst->all = &p->sym; + return &p->sym; +} +Symbol lookup(const char *name, Table tp) { + struct entry *p; + unsigned h = (unsigned long)name&(HASHSIZE-1); + + assert(tp); + do + for (p = tp->buckets[h]; p; p = p->link) + if (name == p->sym.name) + return &p->sym; + while ((tp = tp->previous) != NULL); + return NULL; +} +int genlabel(int n) { + static int label = 1; + + label += n; + return label - n; +} +Symbol findlabel(int lab) { + struct entry *p; + unsigned h = lab&(HASHSIZE-1); + + for (p = labels->buckets[h]; p; p = p->link) + if (lab == p->sym.u.l.label) + return &p->sym; + NEW0(p, FUNC); + p->sym.name = stringd(lab); + p->sym.scope = LABELS; + p->sym.up = labels->all; + labels->all = &p->sym; + p->link = labels->buckets[h]; + labels->buckets[h] = p; + p->sym.generated = 1; + p->sym.u.l.label = lab; + (*IR->defsymbol)(&p->sym); + return &p->sym; +} +Symbol constant(Type ty, Value v) { + struct entry *p; + unsigned h = v.u&(HASHSIZE-1); + static union { int x; char endian; } little = { 1 }; + + ty = unqual(ty); + for (p = constants->buckets[h]; p; p = p->link) + if (eqtype(ty, p->sym.type, 1)) + switch (ty->op) { + case INT: if (equalp(i)) return &p->sym; break; + case UNSIGNED: if (equalp(u)) return &p->sym; break; + case FLOAT: + if (v.d == 0.0) { + float z1 = v.d, z2 = p->sym.u.c.v.d; + char *b1 = (char *)&z1, *b2 = (char *)&z2; + if (z1 == z2 + && ((!little.endian && b1[0] == b2[0]) + || (little.endian && b1[sizeof (z1)-1] == b2[sizeof (z2)-1]))) + return &p->sym; + } else if (equalp(d)) + return &p->sym; + break; + case FUNCTION: if (equalp(g)) return &p->sym; break; + case ARRAY: + case POINTER: if (equalp(p)) return &p->sym; break; + default: assert(0); + } + NEW0(p, PERM); + p->sym.name = vtoa(ty, v); + p->sym.scope = CONSTANTS; + p->sym.type = ty; + p->sym.sclass = STATIC; + p->sym.u.c.v = v; + p->link = constants->buckets[h]; + p->sym.up = constants->all; + constants->all = &p->sym; + constants->buckets[h] = p; + if (ty->u.sym && !ty->u.sym->addressed) + (*IR->defsymbol)(&p->sym); + p->sym.defined = 1; + return &p->sym; +} +Symbol intconst(int n) { + Value v; + + v.i = n; + return constant(inttype, v); +} +Symbol genident(int scls, Type ty, int lev) { + Symbol p; + + NEW0(p, lev >= LOCAL ? FUNC : PERM); + p->name = stringd(genlabel(1)); + p->scope = lev; + p->sclass = scls; + p->type = ty; + p->generated = 1; + if (lev == GLOBAL) + (*IR->defsymbol)(p); + return p; +} + +Symbol temporary(int scls, Type ty) { + Symbol p; + + NEW0(p, FUNC); + p->name = stringd(++tempid); + p->scope = level < LOCAL ? LOCAL : level; + p->sclass = scls; + p->type = ty; + p->temporary = 1; + p->generated = 1; + return p; +} +Symbol newtemp(int sclass, int tc, int size) { + Symbol p = temporary(sclass, btot(tc, size)); + + (*IR->local)(p); + p->defined = 1; + return p; +} + +Symbol allsymbols(Table tp) { + return tp->all; +} + +void locus(Table tp, Coordinate *cp) { + loci = append(cp, loci); + symbols = append(allsymbols(tp), symbols); +} + +void use(Symbol p, Coordinate src) { + Coordinate *cp; + + NEW(cp, PERM); + *cp = src; + p->uses = append(cp, p->uses); +} +/* findtype - find type ty in identifiers */ +Symbol findtype(Type ty) { + Table tp = identifiers; + int i; + struct entry *p; + + assert(tp); + do + for (i = 0; i < HASHSIZE; i++) + for (p = tp->buckets[i]; p; p = p->link) + if (p->sym.type == ty && p->sym.sclass == TYPEDEF) + return &p->sym; + while ((tp = tp->previous) != NULL); + return NULL; +} + +/* mkstr - make a string constant */ +Symbol mkstr(char *str) { + Value v; + Symbol p; + + v.p = str; + p = constant(array(chartype, strlen(v.p) + 1, 0), v); + if (p->u.c.loc == NULL) + p->u.c.loc = genident(STATIC, p->type, GLOBAL); + return p; +} + +/* mksymbol - make a symbol for name, install in &globals if sclass==EXTERN */ +Symbol mksymbol(int sclass, const char *name, Type ty) { + Symbol p; + + if (sclass == EXTERN) + p = install(string(name), &globals, GLOBAL, PERM); + else { + NEW0(p, PERM); + p->name = string(name); + p->scope = GLOBAL; + } + p->sclass = sclass; + p->type = ty; + (*IR->defsymbol)(p); + p->defined = 1; + return p; +} + +/* + * vtoa - return string for the constant v of type ty + */ +char *vtoa(Type ty, Value v) +{ + ty = unqual(ty); + switch (ty->op) { + case INT: return stringd(v.i); + case UNSIGNED: return stringf((v.u&~0x7FFF) ? "0x%X" : "%U", v.u); + case FLOAT: return stringf("%g", (double)v.d); + case ARRAY: + if (ty->type == chartype || ty->type == signedchar + || ty->type == unsignedchar) + return v.p; + return stringf("%p", v.p); + case POINTER: return stringf("%p", v.p); + case FUNCTION: return stringf("%p", v.g); + } + assert(0); + return NULL; +} diff --git a/src/cmd/lccom/symbolic.c b/src/cmd/lccom/symbolic.c new file mode 100644 index 0000000..cdb8339 --- /dev/null +++ b/src/cmd/lccom/symbolic.c @@ -0,0 +1,524 @@ +#include +#include +#include "c.h" + +#define I(f) s_##f + +static Node *tail; +static int off, maxoff, uid = 0, verbose = 0, html = 0; + +static const char *yyBEGIN(const char *tag) { + if (html) + print("<%s>", tag); + return tag; +} + +static void yyEND(const char *tag) { + if (html) + print("", tag); + if (isupper(*tag)) + print("\n"); +} + +#define BEGIN(tag) do { const char *yytag=yyBEGIN(#tag) +#define END yyEND(yytag); } while (0) +#define ITEM BEGIN(li) +#define START BEGIN(LI) +#define ANCHOR(attr,code) do { const char *yytag="a"; if (html) { printf(""); } +#define NEWLINE print(html ? "
    \n" : "\n") + +static void emitCoord(Coordinate src) { + if (src.file && *src.file) { + ANCHOR(href,print("%s", src.file)); print("%s", src.file); END; + print(":"); + } + print("%d.%d", src.y, src.x); +} + +static void emitString(int len, const char *s) { + for ( ; len-- > 0; s++) + if (*s == '&' && html) + print("&"); + else if (*s == '<' && html) + print("<"); + else if (*s == '>' && html) + print("<"); + else if (*s == '"' || *s == '\\') + print("\\%c", *s); + else if (*s >= ' ' && *s < 0177) + print("%c", *s); + else + print("\\%d%d%d", (*s>>6)&3, (*s>>3)&7, *s&7); +} + +static void emitSymRef(Symbol p) { + (*IR->defsymbol)(p); + ANCHOR(href,print("#%s", p->x.name)); BEGIN(code); print("%s", p->name); END; END; +} + +static void emitSymbol(Symbol p) { + (*IR->defsymbol)(p); + ANCHOR(name,print("%s", p->x.name)); BEGIN(code); print("%s", p->name); END; END; + BEGIN(ul); +#define xx(field,code) ITEM; if (!html) print(" "); print(#field "="); code; END + if (verbose && (src.y || src.x)) + xx(src,emitCoord(p->src)); + xx(type,print("%t", p->type)); + xx(sclass,print("%k", p->sclass)); + switch (p->scope) { + case CONSTANTS: xx(scope,print("CONSTANTS")); break; + case LABELS: xx(scope,print("LABELS")); break; + case GLOBAL: xx(scope,print("GLOBAL")); break; + case PARAM: xx(scope,print("PARAM")); break; + case LOCAL: xx(scope,print("LOCAL")); break; + default: + if (p->scope > LOCAL) + xx(scope,print("LOCAL+%d", p->scope-LOCAL)); + else + xx(scope,print("%d", p->scope)); + } + ITEM; + int n = 0; + if (!html) + print(" "); + print("flags="); +#define yy(f) if (p->f) { if (n++) print("|"); print(#f); } + yy(structarg) + yy(addressed) + yy(computed) + yy(temporary) + yy(generated) +#undef yy + if (n == 0) + print("0"); + END; + if (p->scope >= PARAM && p->sclass != STATIC) + xx(offset,print("%d", p->x.offset)); + xx(ref,print("%f", p->ref)); + if (p->temporary && p->u.t.cse) + xx(u.t.cse,print("%p", p->u.t.cse)); + END; +#undef xx +} + +/* address - initialize q for addressing expression p+n */ +static void I(address)(Symbol q, Symbol p, long n) { + q->name = stringf("%s%s%D", p->name, n > 0 ? "+" : "", n); + (*IR->defsymbol)(q); + START; print("address "); emitSymbol(q); END; +} + +/* blockbeg - start a block */ +static void I(blockbeg)(Env *e) { + e->offset = off; + START; print("blockbeg off=%d", off); END; +} + +/* blockend - start a block */ +static void I(blockend)(Env *e) { + if (off > maxoff) + maxoff = off; + START; print("blockend off=%d", off); END; + off = e->offset; +} + +/* defaddress - initialize an address */ +static void I(defaddress)(Symbol p){ + START; print("defaddress "); emitSymRef(p); END; +} + +/* defconst - define a constant */ +static void I(defconst)(int suffix, int size, Value v) { + START; + print("defconst "); + switch (suffix) { + case I: + print("int.%d ", size); + BEGIN(code); + if (size > sizeof (int)) + print("%D", v.i); + else + print("%d", (int)v.i); + END; + break; + case U: + print("unsigned.%d ", size); + BEGIN(code); + if (size > sizeof (unsigned)) + print("%U", v.u); + else + print("%u", (unsigned)v.u); + END; + break; + case P: print("void*.%d ", size); BEGIN(code); print("%p", v.p); END; break; + case F: + print("float.%d ", size); + BEGIN(code); + double d = v.d; + if (d == 0.0) { + static union { int x; char endian; } little = { 1 }; + signed char *b = (signed char *)&d; + if ((!little.endian && b[0] < 0) + || (little.endian && b[sizeof (d)-1] < 0)) + print("-0.0"); + else + print("0.0"); + } else + print("%g", d); + END; + break; + default: assert(0); + } + END; +} + +/* defstring - emit a string constant */ +static void I(defstring)(int len, char *s) { + START; print("defstring "); + BEGIN(code); print("\""); emitString(len, s); print("\""); END; + END; +} + +/* defsymbol - define a symbol: initialize p->x */ +static void I(defsymbol)(Symbol p) { + if (p->x.name == NULL) + p->x.name = stringd(++uid); +} + +/* emit - emit the dags on list p */ +static void I(emit)(Node p){ + ITEM; + if (!html) + print(" "); + for (; p; p = p->x.next) { + if (p->op == LABEL+V) { + assert(p->syms[0]); + ANCHOR(name,print("%s", p->syms[0]->x.name)); + BEGIN(code); print("%s", p->syms[0]->name); END; + END; + print(":"); + } else { + int i; + if (p->x.listed) { + BEGIN(strong); print("%d", p->x.inst); END; print("'"); + print(" %s", opname(p->op)); + } else + print("%d. %s", p->x.inst, opname(p->op)); + if (p->count > 1) + print(" count=%d", p->count); + for (i = 0; i < NELEMS(p->kids) && p->kids[i]; i++) + print(" #%d", p->kids[i]->x.inst); + if (generic(p->op) == CALL && p->syms[0] && p->syms[0]->type) + print(" {%t}", p->syms[0]->type); + else + for (i = 0; i < NELEMS(p->syms) && p->syms[i]; i++) { + print(" "); + if (p->syms[i]->scope == CONSTANTS) + print(p->syms[i]->name); + else + emitSymRef(p->syms[i]); + } + } + NEWLINE; + } + END; +} + +/* export - announce p as exported */ +static void I(export)(Symbol p) { + START; print("export "); emitSymRef(p); END; +} + +/* function - generate code for a function */ +static void I(function)(Symbol f, Symbol caller[], Symbol callee[], int ncalls) { + int i; + + (*IR->defsymbol)(f); + off = 0; + for (i = 0; caller[i] && callee[i]; i++) { + off = roundup(off, caller[i]->type->align); + caller[i]->x.offset = callee[i]->x.offset = off; + off += caller[i]->type->size; + } + if (!html) { + print("function "); + emitSymbol(f); + print(" ncalls=%d\n", ncalls); + for (i = 0; caller[i]; i++) + START; print("caller "); emitSymbol(caller[i]); END; + for (i = 0; callee[i]; i++) + START; print("callee "); emitSymbol(callee[i]); END; + } else { + START; + print("function"); + BEGIN(UL); +#define xx(field,code) ITEM; print(#field "="); code; END + xx(f,emitSymbol(f)); + xx(ncalls,print("%d", ncalls)); + if (caller[0]) { + ITEM; print("caller"); BEGIN(OL); + for (i = 0; caller[i]; i++) + ITEM; emitSymbol(caller[i]); END; + END; END; + ITEM; print("callee"); BEGIN(OL); + for (i = 0; callee[i]; i++) + ITEM; emitSymbol(callee[i]); END; + END; END; + } else { + xx(caller,BEGIN(em); print("empty"); END); + xx(callee,BEGIN(em); print("empty"); END); + } + END; + END; + } + maxoff = off = 0; + gencode(caller, callee); + if (html) + START; print("emitcode"); BEGIN(ul); emitcode(); END; END; + else + emitcode(); + START; print("maxoff=%d", maxoff); END; +#undef xx +} + +/* visit - generate code for *p */ +static int visit(Node p, int n) { + if (p && p->x.inst == 0) { + p->x.inst = ++n; + n = visit(p->kids[0], n); + n = visit(p->kids[1], n); + *tail = p; + tail = &p->x.next; + } + return n; +} + +/* gen0 - generate code for the dags on list p */ +static Node I(gen)(Node p) { + int n; + Node nodelist; + + tail = &nodelist; + for (n = 0; p; p = p->link) { + switch (generic(p->op)) { /* check for valid forest */ + case CALL: + assert(IR->wants_dag || p->count == 0); + break; + case ARG: + case ASGN: case JUMP: case LABEL: case RET: + case EQ: case GE: case GT: case LE: case LT: case NE: + assert(p->count == 0); + break; + case INDIR: + assert(IR->wants_dag && p->count > 0); + break; + default: + assert(0); + } + check(p); + p->x.listed = 1; + n = visit(p, n); + } + *tail = 0; + return nodelist; +} + +/* global - announce a global */ +static void I(global)(Symbol p) { + START; print("global "); emitSymbol(p); END; +} + +/* import - import a symbol */ +static void I(import)(Symbol p) { + START; print("import "); emitSymRef(p); END; +} + +/* local - local variable */ +static void I(local)(Symbol p) { + if (p->temporary) + p->name = stringf("t%s", p->name); + (*IR->defsymbol)(p); + off = roundup(off, p->type->align); + p->x.offset = off; + off += p->type->size; + START; print(p->temporary ? "temporary " : "local "); emitSymbol(p); END; +} + +/* progbeg - beginning of program */ +static void I(progbeg)(int argc, char *argv[]) { + int i; + + for (i = 1; i < argc; i++) + if (strcmp(argv[i], "-v") == 0) + verbose++; + else if (strcmp(argv[i], "-html") == 0) + html++; + if (html) { + print("\n"); + print(""); + BEGIN(head); + if (firstfile && *firstfile) + BEGIN(title); emitString(strlen(firstfile), firstfile); END; + print("\n"); + END; + print("\n"); + if (firstfile && *firstfile) + BEGIN(h1); emitString(strlen(firstfile), firstfile); END; + BEGIN(P); BEGIN(em); + print("Links lead from uses of identifiers and labels to their definitions."); + END; END; + print("
      \n"); + START; + print("progbeg"); + BEGIN(ol); + for (i = 1; i < argc; i++) { + ITEM; + BEGIN(code); print("\""); emitString(strlen(argv[i]), argv[i]); print("\""); END; + END; + } + END; + END; + } +} + +/* progend - end of program */ +static void I(progend)(void) { + START; print("progend"); END; + if (html) { + time_t t; + print("
    \n"); + time(&t); + print("
    %s
    \n", ctime(&t)); + print("\n"); + } +} + +/* segment - switch to segment s */ +static void I(segment)(int s) { + START; print("segment %s", &"text\0bss\0.data\0lit\0.sym\0."[5*s-5]); END; +} + +/* space - initialize n bytes of space */ +static void I(space)(int n) { + START; print("space %d", n); END; +} + +static void I(stabblock)(int brace, int lev, Symbol *p) {} + +/* stabend - finalize stab output */ +static void I(stabend)(Coordinate *cp, Symbol p, Coordinate **cpp, Symbol *sp, Symbol *stab) { + int i; + + if (p) + emitSymRef(p); + print("\n"); + if (cpp && sp) + for (i = 0; cpp[i] && sp[i]; i++) { + print("%w.%d: ", cpp[i], cpp[i]->x); + emitSymRef(sp[i]); + print("\n"); + } +} + +static void I(stabfend)(Symbol p, int lineno) {} +static void I(stabinit)(char *file, int argc, char *argv[]) {} + +/* stabline - emit line number information for source coordinate *cp */ +static void I(stabline)(Coordinate *cp) { + if (cp->file) + print("%s:", cp->file); + print("%d.%d:\n", cp->y, cp->x); +} + +static void I(stabsym)(Symbol p) {} +static void I(stabtype)(Symbol p) {} + +Interface symbolicIR = { + { 1, 1, 0 }, /* char */ + { 2, 2, 0 }, /* short */ + { 4, 4, 0 }, /* int */ + { 4, 4, 0 }, /* long */ + { 4, 4, 0 }, /* long long */ + { 4, 4, 1 }, /* float */ + { 8, 8, 1 }, /* double */ + { 8, 8, 1 }, /* long double */ + { 4, 4, 0 }, /* T* */ + { 0, 4, 0 }, /* struct */ + 0, /* little_endian */ + 0, /* mulops_calls */ + 0, /* wants_callb */ + 1, /* wants_argb */ + 1, /* left_to_right */ + 1, /* wants_dag */ + 0, /* unsigned_char */ + I(address), + I(blockbeg), + I(blockend), + I(defaddress), + I(defconst), + I(defstring), + I(defsymbol), + I(emit), + I(export), + I(function), + I(gen), + I(global), + I(import), + I(local), + I(progbeg), + I(progend), + I(segment), + I(space), + I(stabblock), + I(stabend), + I(stabfend), + I(stabinit), + I(stabline), + I(stabsym), + I(stabtype) +}; + +Interface symbolic64IR = { + { 1, 1, 0 }, /* char */ + { 2, 2, 0 }, /* short */ + { 4, 4, 0 }, /* int */ + { 8, 8, 0 }, /* long */ + { 8, 8, 0 }, /* long long */ + { 4, 4, 1 }, /* float */ + { 8, 8, 1 }, /* double */ + { 8, 8, 1 }, /* long double */ + { 8, 8, 0 }, /* T* */ + { 0, 1, 0 }, /* struct */ + 1, /* little_endian */ + 0, /* mulops_calls */ + 0, /* wants_callb */ + 1, /* wants_argb */ + 1, /* left_to_right */ + 1, /* wants_dag */ + 0, /* unsigned_char */ + I(address), + I(blockbeg), + I(blockend), + I(defaddress), + I(defconst), + I(defstring), + I(defsymbol), + I(emit), + I(export), + I(function), + I(gen), + I(global), + I(import), + I(local), + I(progbeg), + I(progend), + I(segment), + I(space), + I(stabblock), + I(stabend), + I(stabfend), + I(stabinit), + I(stabline), + I(stabsym), + I(stabtype) +}; diff --git a/src/cmd/lccom/token.h b/src/cmd/lccom/token.h new file mode 100644 index 0000000..12e5f2b --- /dev/null +++ b/src/cmd/lccom/token.h @@ -0,0 +1,133 @@ +/* + * xx(symbol, value, prec, op, optree, kind, string) + */ +yy(0, 0, 0, 0, 0, 0, 0) +xx(FLOAT, 1, 0, 0, 0, CHAR, "float") +xx(DOUBLE, 2, 0, 0, 0, CHAR, "double") +xx(CHAR, 3, 0, 0, 0, CHAR, "char") +xx(SHORT, 4, 0, 0, 0, CHAR, "short") +xx(INT, 5, 0, 0, 0, CHAR, "int") +xx(UNSIGNED, 6, 0, 0, 0, CHAR, "unsigned") +xx(POINTER, 7, 0, 0, 0, 0, "pointer") +xx(VOID, 8, 0, 0, 0, CHAR, "void") +xx(STRUCT, 9, 0, 0, 0, CHAR, "struct") +xx(UNION, 10, 0, 0, 0, CHAR, "union") +xx(FUNCTION, 11, 0, 0, 0, 0, "function") +xx(ARRAY, 12, 0, 0, 0, 0, "array") +xx(ENUM, 13, 0, 0, 0, CHAR, "enum") +xx(LONG, 14, 0, 0, 0, CHAR, "long") +xx(CONST, 15, 0, 0, 0, CHAR, "const") +xx(VOLATILE, 16, 0, 0, 0, CHAR, "volatile") +yy(0, 17, 0, 0, 0, 0, 0) +yy(0, 18, 0, 0, 0, 0, 0) +yy(0, 19, 0, 0, 0, 0, 0) +yy(0, 20, 0, 0, 0, 0, 0) +yy(0, 21, 0, 0, 0, 0, 0) +yy(0, 22, 0, 0, 0, 0, 0) +yy(0, 23, 0, 0, 0, 0, 0) +yy(0, 24, 0, 0, 0, 0, 0) +yy(0, 25, 0, 0, 0, 0, 0) +yy(0, 26, 0, 0, 0, 0, 0) +yy(0, 27, 0, 0, 0, 0, 0) +yy(0, 28, 0, 0, 0, 0, "long long") +yy(0, 29, 0, 0, 0, 0, 0) +yy(0, 30, 0, 0, 0, 0, 0) +yy(0, 31, 0, 0, 0, 0, "const volatile") +xx(ID, 32, 0, 0, 0, ID, "identifier") +yy(0, 33, 0, 0, 0, ID, "!") +xx(FCON, 34, 0, 0, 0, ID, "floating constant") +xx(ICON, 35, 0, 0, 0, ID, "integer constant") +xx(SCON, 36, 0, 0, 0, ID, "string constant") +yy(0, 37, 13, MOD, bittree,'%', "%") +yy(0, 38, 8, BAND, bittree,ID, "&") +xx(INCR, 39, 0, ADD, addtree,ID, "++") +yy(0, 40, 0, 0, 0, ID, "(") +yy(0, 41, 0, 0, 0, ')', ")") +yy(0, 42, 13, MUL, multree,ID, "*") +yy(0, 43, 12, ADD, addtree,ID, "+") +yy(0, 44, 1, 0, 0, ',', ",") +yy(0, 45, 12, SUB, subtree,ID, "-") +yy(0, 46, 0, 0, 0, '.', ".") +yy(0, 47, 13, DIV, multree,'/', "/") +xx(DECR, 48, 0, SUB, subtree,ID, "--") +xx(DEREF, 49, 0, 0, 0, DEREF, "->") +xx(ANDAND, 50, 5, AND, andtree,ANDAND, "&&") +xx(OROR, 51, 4, OR, andtree,OROR, "||") +xx(LEQ, 52, 10, LE, cmptree,LEQ, "<=") +xx(EQL, 53, 9, EQ, eqtree, EQL, "==") +xx(NEQ, 54, 9, NE, eqtree, NEQ, "!=") +xx(GEQ, 55, 10, GE, cmptree,GEQ, ">=") +xx(RSHIFT, 56, 11, RSH, shtree, RSHIFT, ">>") +xx(LSHIFT, 57, 11, LSH, shtree, LSHIFT, "<<") +yy(0, 58, 0, 0, 0, ':', ":") +yy(0, 59, 0, 0, 0, IF, ";") +yy(0, 60, 10, LT, cmptree,'<', "<") +yy(0, 61, 2, ASGN, asgntree,'=', "=") +yy(0, 62, 10, GT, cmptree,'>', ">") +yy(0, 63, 0, 0, 0, '?', "?") +xx(ELLIPSIS, 64, 0, 0, 0, ELLIPSIS,"...") +xx(SIZEOF, 65, 0, 0, 0, ID, "sizeof") +yy(0, 66, 0, 0, 0, 0, 0) +xx(AUTO, 67, 0, 0, 0, STATIC, "auto") +xx(BREAK, 68, 0, 0, 0, IF, "break") +xx(CASE, 69, 0, 0, 0, IF, "case") +xx(CONTINUE, 70, 0, 0, 0, IF, "continue") +xx(DEFAULT, 71, 0, 0, 0, IF, "default") +xx(DO, 72, 0, 0, 0, IF, "do") +xx(ELSE, 73, 0, 0, 0, IF, "else") +xx(EXTERN, 74, 0, 0, 0, STATIC, "extern") +xx(FOR, 75, 0, 0, 0, IF, "for") +xx(GOTO, 76, 0, 0, 0, IF, "goto") +xx(IF, 77, 0, 0, 0, IF, "if") +xx(REGISTER, 78, 0, 0, 0, STATIC, "register") +xx(RETURN, 79, 0, 0, 0, IF, "return") +xx(SIGNED, 80, 0, 0, 0, CHAR, "signed") +xx(STATIC, 81, 0, 0, 0, STATIC, "static") +xx(SWITCH, 82, 0, 0, 0, IF, "switch") +xx(TYPEDEF, 83, 0, 0, 0, STATIC, "typedef") +xx(WHILE, 84, 0, 0, 0, IF, "while") +xx(TYPECODE, 85, 0, 0, 0, ID, "__typecode") +xx(FIRSTARG, 86, 0, 0, 0, ID, "__firstarg") +yy(0, 87, 0, 0, 0, 0, 0) +yy(0, 88, 0, 0, 0, 0, 0) +yy(0, 89, 0, 0, 0, 0, 0) +yy(0, 90, 0, 0, 0, 0, 0) +yy(0, 91, 0, 0, 0, '[', "[") +yy(0, 92, 0, 0, 0, 0, 0) +yy(0, 93, 0, 0, 0, ']', "]") +yy(0, 94, 7, BXOR, bittree,'^', "^") +yy(0, 95, 0, 0, 0, 0, 0) +yy(0, 96, 0, 0, 0, 0, 0) +yy(0, 97, 0, 0, 0, 0, 0) +yy(0, 98, 0, 0, 0, 0, 0) +yy(0, 99, 0, 0, 0, 0, 0) +yy(0, 100, 0, 0, 0, 0, 0) +yy(0, 101, 0, 0, 0, 0, 0) +yy(0, 102, 0, 0, 0, 0, 0) +yy(0, 103, 0, 0, 0, 0, 0) +yy(0, 104, 0, 0, 0, 0, 0) +yy(0, 105, 0, 0, 0, 0, 0) +yy(0, 106, 0, 0, 0, 0, 0) +yy(0, 107, 0, 0, 0, 0, 0) +yy(0, 108, 0, 0, 0, 0, 0) +yy(0, 109, 0, 0, 0, 0, 0) +yy(0, 110, 0, 0, 0, 0, 0) +yy(0, 111, 0, 0, 0, 0, 0) +yy(0, 112, 0, 0, 0, 0, 0) +yy(0, 113, 0, 0, 0, 0, 0) +yy(0, 114, 0, 0, 0, 0, 0) +yy(0, 115, 0, 0, 0, 0, 0) +yy(0, 116, 0, 0, 0, 0, 0) +yy(0, 117, 0, 0, 0, 0, 0) +yy(0, 118, 0, 0, 0, 0, 0) +yy(0, 119, 0, 0, 0, 0, 0) +yy(0, 120, 0, 0, 0, 0, 0) +yy(0, 121, 0, 0, 0, 0, 0) +yy(0, 122, 0, 0, 0, 0, 0) +yy(0, 123, 0, 0, 0, IF, "{") +yy(0, 124, 6, BOR, bittree,'|', "|") +yy(0, 125, 0, 0, 0, '}', "}") +yy(0, 126, 0, BCOM, 0, ID, "~") +xx(EOI, 127, 0, 0, 0, EOI, "end of input") +#undef xx +#undef yy diff --git a/src/cmd/lccom/trace.c b/src/cmd/lccom/trace.c new file mode 100644 index 0000000..2bdf107 --- /dev/null +++ b/src/cmd/lccom/trace.c @@ -0,0 +1,169 @@ +#include "c.h" + +static char *fmt, *fp, *fmtend; /* format string, current & limit pointer */ +static Tree args; /* printf arguments */ +static Symbol frameno; /* local holding frame number */ + +/* appendstr - append str to the evolving format string, expanding it if necessary */ +static void appendstr(char *str) { + do { + if (fp == fmtend) { + if (fp) { + char *s = allocate(2*(fmtend - fmt), FUNC); + strncpy(s, fmt, fmtend - fmt); + fp = s + (fmtend - fmt); + fmtend = s + 2*(fmtend - fmt); + fmt = s; + } else { + fp = fmt = allocate(80, FUNC); + fmtend = fmt + 80; + } + } + } while ((*fp++ = *str++) != 0); + fp--; +} + +/* tracevalue - append format and argument to print the value of e */ +static void tracevalue(Tree e, int lev) { + Type ty = unqual(e->type); + + switch (ty->op) { + case INT: + if (ty == chartype || ty == signedchar) + appendstr("'\\x%02x'"); + else if (ty == longtype) + appendstr("0x%ld"); + else + appendstr("0x%d"); + break; + case UNSIGNED: + if (ty == chartype || ty == unsignedchar) + appendstr("'\\x%02x'"); + else if (ty == unsignedlong) + appendstr("0x%lx"); + else + appendstr("0x%x"); + break; + case FLOAT: + if (ty == longdouble) + appendstr("%Lg"); + else + appendstr("%g"); + break; + case POINTER: + if (unqual(ty->type) == chartype + || unqual(ty->type) == signedchar + || unqual(ty->type) == unsignedchar) { + static Symbol null; + if (null == NULL) + null = mkstr("(null)"); + tracevalue(cast(e, unsignedtype), lev + 1); + appendstr(" \"%.30s\""); + e = condtree(e, e, pointer(idtree(null->u.c.loc))); + } else { + appendstr("("); appendstr(typestring(ty, "")); appendstr(")0x%x"); + } + break; + case STRUCT: { + Field q; + appendstr("("); appendstr(typestring(ty, "")); appendstr("){"); + for (q = ty->u.sym->u.s.flist; q; q = q->link) { + appendstr(q->name); appendstr("="); + tracevalue(field(addrof(e), q->name), lev + 1); + if (q->link) + appendstr(","); + } + appendstr("}"); + return; + } + case UNION: + appendstr("("); appendstr(typestring(ty, "")); appendstr("){...}"); + return; + case ARRAY: + if (lev && ty->type->size > 0) { + int i; + e = pointer(e); + appendstr("{"); + for (i = 0; i < ty->size/ty->type->size; i++) { + Tree p = (*optree['+'])(ADD, e, consttree(i, inttype)); + if (isptr(p->type) && isarray(p->type->type)) + p = retype(p, p->type->type); + else + p = rvalue(p); + if (i) + appendstr(","); + tracevalue(p, lev + 1); + } + appendstr("}"); + } else + appendstr(typestring(ty, "")); + return; + default: + assert(0); + } + e = cast(e, promote(ty)); + args = tree(mkop(ARG,e->type), e->type, e, args); +} + +/* tracefinis - complete & generate the trace call to print */ +static void tracefinis(Symbol printer) { + Tree *ap; + Symbol p; + + *fp = 0; + p = mkstr(string(fmt)); + for (ap = &args; *ap; ap = &(*ap)->kids[1]) + ; + *ap = tree(ARG+P, charptype, pointer(idtree(p->u.c.loc)), 0); + walk(calltree(pointer(idtree(printer)), freturn(printer->type), args, NULL), 0, 0); + args = 0; + fp = fmtend = 0; +} + +/* tracecall - generate code to trace entry to f */ +static void tracecall(Symbol printer, Symbol f, void *ignore) { + int i; + Symbol counter = genident(STATIC, inttype, GLOBAL); + + defglobal(counter, BSS); + (*IR->space)(counter->type->size); + frameno = genident(AUTO, inttype, level); + addlocal(frameno); + appendstr(f->name); appendstr("#"); + tracevalue(asgn(frameno, incr(INCR, idtree(counter), consttree(1, inttype))), 0); + appendstr("("); + for (i = 0; f->u.f.callee[i]; i++) { + if (i) + appendstr(","); + appendstr(f->u.f.callee[i]->name); appendstr("="); + tracevalue(idtree(f->u.f.callee[i]), 0); + } + if (variadic(f->type)) + appendstr(",..."); + appendstr(") called\n"); + tracefinis(printer); +} + +/* tracereturn - generate code to trace return e */ +static void tracereturn(Symbol printer, Symbol f, Tree e) { + appendstr(f->name); appendstr("#"); + tracevalue(idtree(frameno), 0); + appendstr(" returned"); + if (freturn(f->type) != voidtype && e) { + appendstr(" "); + tracevalue(e, 0); + } + appendstr("\n"); + tracefinis(printer); +} + +/* traceInit - initialize for tracing */ +void traceInit(char *arg) { + if (strncmp(arg, "-t", 2) == 0 && strchr(arg, '=') == NULL) { + Symbol printer = mksymbol(EXTERN, arg[2] ? &arg[2] : "printf", + ftype(inttype, ptr(qual(CONST, chartype)), voidtype, NULL)); + printer->defined = 0; + attach((Apply)tracecall, printer, &events.entry); + attach((Apply)tracereturn, printer, &events.returns); + } +} diff --git a/src/cmd/lccom/tree.c b/src/cmd/lccom/tree.c new file mode 100644 index 0000000..d7543a7 --- /dev/null +++ b/src/cmd/lccom/tree.c @@ -0,0 +1,240 @@ +#include "c.h" + +int where = STMT; +static int warn; +static int nid = 1; /* identifies trees & nodes in debugging output */ +static struct nodeid { + int printed; + Tree node; +} ids[500]; /* if ids[i].node == p, then p's id is i */ + +static void printtree1(Tree, int, int); + +Tree tree(int op, Type type, Tree left, Tree right) { + Tree p; + + NEW0(p, where); + p->op = op; + p->type = type; + p->kids[0] = left; + p->kids[1] = right; + return p; +} + +Tree texpr(Tree (*f)(int), int tok, int a) { + int save = where; + Tree p; + + where = a; + p = (*f)(tok); + where = save; + return p; +} +static Tree root1(Tree p) { + if (p == NULL) + return p; + if (p->type == voidtype) + warn++; + switch (generic(p->op)) { + case COND: { + Tree q = p->kids[1]; + assert(q && q->op == RIGHT); + if (p->u.sym && q->kids[0] && generic(q->kids[0]->op) == ASGN) + q->kids[0] = root1(q->kids[0]->kids[1]); + else + q->kids[0] = root1(q->kids[0]); + if (p->u.sym && q->kids[1] && generic(q->kids[1]->op) == ASGN) + q->kids[1] = root1(q->kids[1]->kids[1]); + else + q->kids[1] = root1(q->kids[1]); + p->u.sym = 0; + if (q->kids[0] == 0 && q->kids[1] == 0) + p = root1(p->kids[0]); + } + break; + case AND: case OR: + if ((p->kids[1] = root1(p->kids[1])) == 0) + p = root1(p->kids[0]); + break; + case NOT: + if (warn++ == 0) + warning("expression with no effect elided\n"); + return root1(p->kids[0]); + case RIGHT: + if (p->kids[1] == 0) + return root1(p->kids[0]); + if (p->kids[0] && p->kids[0]->op == CALL+B + && p->kids[1] && p->kids[1]->op == INDIR+B) + /* avoid premature release of the CALL+B temporary */ + return p->kids[0]; + if (p->kids[0] && p->kids[0]->op == RIGHT + && p->kids[1] == p->kids[0]->kids[0]) + /* de-construct e++ construction */ + return p->kids[0]->kids[1]; + p = tree(RIGHT, p->type, root1(p->kids[0]), root1(p->kids[1])); + return p->kids[0] || p->kids[1] ? p : (Tree)0; + case EQ: case NE: case GT: case GE: case LE: case LT: + case ADD: case SUB: case MUL: case DIV: case MOD: + case LSH: case RSH: case BAND: case BOR: case BXOR: + if (warn++ == 0) + warning("expression with no effect elided\n"); + p = tree(RIGHT, p->type, root1(p->kids[0]), root1(p->kids[1])); + return p->kids[0] || p->kids[1] ? p : (Tree)0; + case INDIR: + if (p->type->size == 0 && unqual(p->type) != voidtype) + warning("reference to `%t' elided\n", p->type); + if (isptr(p->kids[0]->type) && isvolatile(p->kids[0]->type->type)) + warning("reference to `volatile %t' elided\n", p->type); + /* fall thru */ + case NEG: case BCOM: case FIELD: + if (warn++ == 0) + warning("expression with no effect elided\n"); + return root1(p->kids[0]); + case ADDRL: case ADDRG: case ADDRF: case CNST: + if (needconst) + return p; + if (warn++ == 0) + warning("expression with no effect elided\n"); + return NULL; + case CVF: + if (optype(p->op) == I + || p->type->size < p->kids[0]->type->size) + if (warn++ == 0) + warning("expression with no effect elided\n"); + return root1(p->kids[0]); + case CVI: + if ((optype(p->op) == U || optype(p->op) == I) + && p->type->size < p->kids[0]->type->size + && specific(p->kids[0]->op) != CALL+I) + if (warn++ == 0) + warning("expression with no effect elided\n"); + return root1(p->kids[0]); + case CVU: case CVP: + if ((optype(p->op) == U && p->type->size < p->kids[0]->type->size) + || (optype(p->op) == I && p->type->size <= p->kids[0]->type->size)) + if (warn++ == 0) + warning("expression with no effect elided\n"); + return root1(p->kids[0]); + case ARG: case ASGN: case CALL: case JUMP: case LABEL: + break; + default: assert(0); + } + return p; +} + +Tree root(Tree p) { + warn = 0; + return root1(p); +} + +char *opname(int op) { + static char *opnames[] = { + "", + "CNST", + "ARG", + "ASGN", + "INDIR", + "CVC", + "CVD", + "CVF", + "CVI", + "CVP", + "CVS", + "CVU", + "NEG", + "CALL", + "*LOAD*", + "RET", + "ADDRG", + "ADDRF", + "ADDRL", + "ADD", + "SUB", + "LSH", + "MOD", + "RSH", + "BAND", + "BCOM", + "BOR", + "BXOR", + "DIV", + "MUL", + "EQ", + "GE", + "GT", + "LE", + "LT", + "NE", + "JUMP", + "LABEL", + "AND", + "NOT", + "OR", + "COND", + "RIGHT", + "FIELD" + }, *suffixes[] = { + "0", "F", "D", "C", "S", "I", "U", "P", "V", "B", + "10","11","12","13","14","15" + }; + + if (generic(op) >= AND && generic(op) <= FIELD && opsize(op) == 0) + return opnames[opindex(op)]; + return stringf("%s%s%s", + opindex(op) > 0 && opindex(op) < NELEMS(opnames) ? + opnames[opindex(op)] : stringd(opindex(op)), + suffixes[optype(op)], opsize(op) > 0 ? stringd(opsize(op)) : ""); +} + +int nodeid(Tree p) { + int i = 1; + + ids[nid].node = p; + while (ids[i].node != p) + i++; + if (i == nid) + ids[nid++].printed = 0; + return i; +} + +/* printed - return pointer to ids[id].printed */ +int *printed(int id) { + if (id) + return &ids[id].printed; + nid = 1; + return 0; +} + +/* printtree - print tree p on fd */ +void printtree(Tree p, int fd) { + (void)printed(0); + printtree1(p, fd, 1); +} + +/* printtree1 - recursively print tree p */ +static void printtree1(Tree p, int fd, int lev) { + FILE *f = fd == 1 ? stdout : stderr; + int i; + static char blanks[] = " "; + + if (p == 0 || *printed(i = nodeid(p))) + return; + fprint(f, "#%d%S%S", i, blanks, i < 10 ? 2 : i < 100 ? 1 : 0, blanks, lev); + fprint(f, "%s %t", opname(p->op), p->type); + *printed(i) = 1; + for (i = 0; i < NELEMS(p->kids); i++) + if (p->kids[i]) + fprint(f, " #%d", nodeid(p->kids[i])); + if (p->op == FIELD && p->u.field) + fprint(f, " %s %d..%d", p->u.field->name, + fieldsize(p->u.field) + fieldright(p->u.field), fieldright(p->u.field)); + else if (generic(p->op) == CNST) + fprint(f, " %s", vtoa(p->type, p->u.v)); + else if (p->u.sym) + fprint(f, " %s", p->u.sym->name); + if (p->node) + fprint(f, " node=%p", p->node); + fprint(f, "\n"); + for (i = 0; i < NELEMS(p->kids); i++) + printtree1(p->kids[i], fd, lev + 1); +} diff --git a/src/cmd/lccom/tst/8q.0 b/src/cmd/lccom/tst/8q.0 new file mode 100644 index 0000000..e69de29 diff --git a/src/cmd/lccom/tst/8q.c b/src/cmd/lccom/tst/8q.c new file mode 100644 index 0000000..60a65a9 --- /dev/null +++ b/src/cmd/lccom/tst/8q.c @@ -0,0 +1,39 @@ +int up[15], down[15], rows[8], x[8]; +int queens(), print(); + +main() +{ + int i; + + for (i = 0; i < 15; i++) + up[i] = down[i] = 1; + for (i = 0; i < 8; i++) + rows[i] = 1; + queens(0); + return 0; +} + +queens(c) +{ + int r; + + for (r = 0; r < 8; r++) + if (rows[r] && up[r-c+7] && down[r+c]) { + rows[r] = up[r-c+7] = down[r+c] = 0; + x[c] = r; + if (c == 7) + print(); + else + queens(c + 1); + rows[r] = up[r-c+7] = down[r+c] = 1; + } +} + +print() +{ + int k; + + for (k = 0; k < 8; k++) + printf("%c ", x[k]+'1'); + printf("\n"); +} diff --git a/src/cmd/lccom/tst/array.0 b/src/cmd/lccom/tst/array.0 new file mode 100644 index 0000000..e69de29 diff --git a/src/cmd/lccom/tst/array.c b/src/cmd/lccom/tst/array.c new file mode 100644 index 0000000..4c967e7 --- /dev/null +++ b/src/cmd/lccom/tst/array.c @@ -0,0 +1,48 @@ +int x[3][4], *y[3]; + +main() { + int z[3][4]; + int i, j, *p; + + for (i = 0; i < 3; i++) { + for (j = 0; j < 4; j++) + x[i][j] = 1000*i + j; + y[i] = x[i]; + } + f(); + for (i = 0; i < 3; i++) { + y[i] = p = &z[i][0]; + for (j = 0; j < 4; j++) + p[j] = x[i][j]; + } + g(z, y); + return 0; +} + +f() { + int i, j; + + for (i = 0; i < 3; i++) + for (j = 0; j < 4; j++) + printf(" %d", x[i][j]); + printf("\n"); + for (i = 0; i < 3; i++) + for (j = 0; j < 4; j++) + printf(" %d", y[i][j]); + printf("\n"); +} + +g(x, y) +int x[][4], *y[]; +{ + int i, j; + + for (i = 0; i < 3; i++) + for (j = 0; j < 4; j++) + printf(" %d", x[i][j]); + printf("\n"); + for (i = 0; i < 3; i++) + for (j = 0; j < 4; j++) + printf(" %d", y[i][j]); + printf("\n"); +} diff --git a/src/cmd/lccom/tst/cf.0 b/src/cmd/lccom/tst/cf.0 new file mode 100644 index 0000000..28efab7 --- /dev/null +++ b/src/cmd/lccom/tst/cf.0 @@ -0,0 +1,32 @@ +/* cf - print character frequencies */ +float f[128]; + +main(argc, argv) +int argc; +char *argv[]; +{ + int i, c, nc; + float cutoff, atof(); + + if (argc <= 1) + cutoff = 0.0; + else + cutoff = atof(argv[1])/100; + for (i = 0; i <= 127; ) + f[i++] = 0.0; + nc = 0; + while ((c = getchar()) != -1) { + f[c] += 1; + nc++; + } + printf("char\tfreq\n"); + for (i = 0; i <= 127; ++i) + if (f[i] && f[i]/nc >= cutoff) { + if (i <= ' ') + printf("%03o", i); + else + printf("%c", i); + printf("\t%.1f\n", 100*f[i]/nc); + } + return 0; +} diff --git a/src/cmd/lccom/tst/cf.c b/src/cmd/lccom/tst/cf.c new file mode 100644 index 0000000..28efab7 --- /dev/null +++ b/src/cmd/lccom/tst/cf.c @@ -0,0 +1,32 @@ +/* cf - print character frequencies */ +float f[128]; + +main(argc, argv) +int argc; +char *argv[]; +{ + int i, c, nc; + float cutoff, atof(); + + if (argc <= 1) + cutoff = 0.0; + else + cutoff = atof(argv[1])/100; + for (i = 0; i <= 127; ) + f[i++] = 0.0; + nc = 0; + while ((c = getchar()) != -1) { + f[c] += 1; + nc++; + } + printf("char\tfreq\n"); + for (i = 0; i <= 127; ++i) + if (f[i] && f[i]/nc >= cutoff) { + if (i <= ' ') + printf("%03o", i); + else + printf("%c", i); + printf("\t%.1f\n", 100*f[i]/nc); + } + return 0; +} diff --git a/src/cmd/lccom/tst/cq.0 b/src/cmd/lccom/tst/cq.0 new file mode 100644 index 0000000..e69de29 diff --git a/src/cmd/lccom/tst/cq.c b/src/cmd/lccom/tst/cq.c new file mode 100644 index 0000000..769b538 --- /dev/null +++ b/src/cmd/lccom/tst/cq.c @@ -0,0 +1,5316 @@ + struct defs { + int cbits; /* No. of bits per char */ + int ibits; /* int */ + int sbits; /* short */ + int lbits; /* long */ + int ubits; /* unsigned */ + int fbits; /* float */ + int dbits; /* double */ + float fprec; /* Smallest number that can be */ + float dprec; /* significantly added to 1. */ + int flgs; /* Print return codes, by section */ + int flgm; /* Announce machine dependencies */ + int flgd; /* give explicit diagnostics */ + int flgl; /* Report local return codes. */ + int rrc; /* recent return code */ + int crc; /* Cumulative return code */ + char rfs[8]; /* Return from section */ + }; +main(n,args) /* C REFERENCE MANUAL */ +int n; +char **args; +{ + +/* This program performs a series of tests on a C compiler, +based on information in the + + C REFERENCE MANUAL + +which appears as Appendix A to the book "The C Programming +Language" by Brian W. Kernighan and Dennis M. Ritchie +(Prentice-Hall, 1978, $10.95). This Appendix is hereafter +referred to as "the Manual". + + The rules followed in writing this program are: + + 1. The entire program is written in legal C, according + to the Manual. It should compile with no error messages, + although some warning messages may be produced by some + compilers. Failure to compile should be interpreted as + a compiler error. + + 2. The program is clean, in that it does not make use + of any features of the operating system on which it runs, + with the sole exceptions of the printf() function, and an + internal "options" routine, which is easily excised. + + 3. No global variables are used, except for the spec- + ific purpose of testing the global variable facility. + + The program is divided into modules having names of the +form snnn... These modules correspond to those sections of the +Manual, as identified by boldface type headings, in which +there is something to test. For example, s241() corresponds +to section 2.4.1 of the Manual (Integer constants) and tests +the facilities described therein. The module numbering +scheme is ambiguous, especially when it names modules +referring to more than one section; module s7813, for ex- +ample, deals with sections 7.8 through 7.13. Nonetheless, +it is surprisingly easy to find a section in the Manual +corresponding to a section of code, and vice versa. + + Note also that there seem to be "holes" in the program, +at least from the point of view that there exist sections in the +Manual for which there is no corresponding code. Such holes +arise from three causes: (a) there is nothing in that partic- +ular section to test, (b) everything in that section is tested +elsewhere, and (c) it was deemed advisable not to check cer- +tain features like preprocessor or listing control features. + + Modules are called by a main program main(). The mod- +ules that are called, and the sequence in which they are +called, are determined by two lists in main(), in which the +module names appear. The first list (an extern statement) +declares the module names to be external. The second (a stat- +ic int statement) names the modules and defines the sequence +in which they are called. There is no need for these lists +to be in the same order, but it is probably a good idea to keep +them that way in the interest of clarity. Since there are no +cross-linkages between modules, new modules may be added, +or old ones deleted, simply by editing the lists, with one +exception: section s26, which pokes around at the hardware +trying to figure out the characteristics of the machine that +it is running on, saves information that is subsequently +used by sections s626, s72, and s757. If this program is +to be broken up into smallish pieces, say for running on +a microcomputer, take care to see that s26 is called before +calling any of the latter three sections. The size +of the lists, i.e., the number of modules to be called, is +not explicitly specified as a program parameter, but is +determined dynamically using the sizeof operator. + + Communication between the main program and the modules +takes place in two ways. In all cases, a pointer to a structure +is passed to the called module. The structure contains flags +that will determine the type of information to be published +by the module, and fields that may be written in by the +module. The former include "flgm" and "flgd", which, if set +to a nonzero value, specify that machine dependencies are to +be announced or that error messages are to be printed, re- +spectively. The called module's name, and the hardware char- +acteristics probed in s26() comprise the latter. + + + Also, in all cases, a return code is returned by the called +module. A return code of zero indicates that all has gone well; +nonzero indicates otherwise. Since more than one type of error +may be detected by a module, the return code is a composite +of error indicators, which, individually, are given as numbers +that are powers of two. Thus, a return code of 10 indicates +that two specific errors, 8 and 2, were detected. Whether or +not the codes returned by the modules are printed by the main +program is determined by setting "flgs" to 1 (resp. 0). + + The entire logic of the main program is contained in the +half-dozen or so lines at the end. The somewhat cryptic +statement: + + d0.rrc = (*sec[j])(pd0); + +in the for loop calls the modules. The rest of the code is +reasonably straightforward. + + Finally, in each of the modules, there is the following +prologue: + + snnn(pd0) + struct defs *pd0; + { + static char snnner[] = "snnn,er%d\n"; + static char qsnnn[8] = "snnn "; + char *ps, *pt; + int rc; + + rc = 0; + ps = qsnnn; + pt = pd0->rfs; + while(*pt++ = *ps++); + +used for housekeeping, handshaking and module initialization. + + */ + extern + s22(struct defs *), + s241(struct defs *), + s243(struct defs *), + s244(struct defs *), + s25(struct defs *), + s26(struct defs *), + s4(struct defs *), + s61(struct defs *), + s626(struct defs *), + s71(struct defs *), + s72(struct defs *), + s757(struct defs *), + s7813(struct defs *), + s714(struct defs *), + s715(struct defs *), + s81(struct defs *), + s84(struct defs *), + s85(struct defs *), + s86(struct defs *), + s88(struct defs *), + s9(struct defs *) + ; + + int j; + static int (*sec[])() = { + s22, + s241, + s243, + s244, + s25, + s26, + s4, + s61, + s626, + s71, + s72, + s757, + s7813, + s714, + s715, + s81, + s84, + s85, + s86, + s88, + s9 + }; + + static struct defs d0, *pd0; + + d0.flgs = 1; /* These flags dictate */ + d0.flgm = 1; /* the verbosity of */ + d0.flgd = 1; /* the program. */ + d0.flgl = 1; + + pd0 = &d0; + + for (j=0; j rfs; + while (*pt++ = *ps++); + + /* An identifier is a sequence of letters and digits; + the first character must be a letter. The under- + score _ counts as a letter. */ + + a=1; + _=2; + _234=3; + a234=4; + if(a+_+_234+a234 != 10) { + rc = rc+1; + if(pd0->flgd != 0) printf(s22er,1); + } + + /* Upper and lower case letters are different. */ + + A = 2; + if (A == a) { + rc = rc+4; + if (pd0->flgd != 0) printf(s22er,4); + } + + return(rc); +} +s241(pd0) /* 2.4.1 Integer constants + 2.4.2 Explicit long constants */ +struct defs *pd0; +{ + long pow2(); + static char s241er[] = "s241,er%d\n"; + static char qs241[8] = "s241 "; + char *ps, *pt; + int rc, j, lrc; + static long g[39] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,6,0,8,0,12,0,16,0,18,0,20,0,24, + 0,28,0,30,0,32,0,36}; + long d[39], o[39], x[39]; + + rc = 0; + lrc = 0; + ps = qs241; + pt = pd0 -> rfs; + while (*pt++ = *ps++); + + /* An integer constant consisting of a sequence of digits is + taken to be octal if it begins with 0 (digit zero), decimal + otherwise. */ + + if ( 8 != 010 + || 16 != 020 + || 24 != 030 + || 32 != 040 + || 40 != 050 + || 48 != 060 + || 56 != 070 + || 64 != 0100 + || 72 != 0110 + || 80 != 0120 + || 9 != 0011 + || 17 != 0021 + || 25 != 0031 + || 33 != 0041 + || 41 != 0051 + || 49 != 0061 + || 57 != 0071 + || 65 != 0101 + || 73 != 0111 + || 81 != 0121 ){ + + rc = rc+1; + if( pd0->flgd != 0 ) printf(s241er,1); + } + + /* A sequence of digits preceded by 0x or 0X (digit zero) + is taken to be a hexadecimal integer. The hexadecimal + digits include a or A through f or F with values 10 + through 15. */ + + if ( 0x00abcdef != 0xabcdef + || 0xabcdef != 0Xabcdef || 0Xabcdef != 0XAbcdef + || 0XAbcdef != 0XABcdef || 0XABcdef != 0XABCdef + || 0XABCdef != 0XABCDef || 0XABCDef != 0XABCDEf + || 0XABCDEf != 0XABCDEF || 0xABCDEF != 11259375 ){ + + rc = rc+2; + if( pd0->flgd != 0 ) printf(s241er,2); + } + + /* A decimal constant whose value exceeds the largest signed + machine integer is taken to be long; an octal or hex con- + stant which exceeds the largest unsigned machine integer + is likewise taken to be long. */ + + if ( sizeof 010000000000 != sizeof(long) /* 2**30 */ + || sizeof 1073741824 != sizeof(long) /* ditto */ + || sizeof 0x40000000 != sizeof(long) ){ /* " */ + + rc = rc+4; + if( pd0->flgd != 0 ) printf(s241er,4); + } + + /* A decimal, octal, or hexadecimal constant immediately followed + by l (letter ell) or L is a long constant. */ + + if ( sizeof 67l != sizeof(long) + || sizeof 67L != sizeof(long) + || sizeof 067l != sizeof(long) + || sizeof 067L != sizeof(long) + || sizeof 0X67l != sizeof(long) + || sizeof 0x67L != sizeof(long) ){ + + rc = rc+8; + if( pd0 -> flgd != 0 ) printf(s241er,8); + } + + /* Finally, we test to see that decimal (d), octal (o), + and hexadecimal (x) constants representing the same values + agree among themselves, and with computed values, at spec- + ified points over an appropriate range. The points select- + ed here are those with the greatest potential for caus- + ing trouble, i.e., zero, 1-16, and values of 2**n and + 2**n - 1 where n is some multiple of 4 or 6. Unfortunately, + just what happens when a value is too big to fit in a + long is undefined; however, it would be nice if what + happened were at least consistent... */ + + for ( j=0; j<17; j++ ) g[j] = j; + for ( j=18; j<39; ) { + g[j] = pow2(g[j]); + g[j-1] = g[j] - 1; + j = j+2; + } + + d[0] = 0; o[0] = 00; x[0] = 0x0; + d[1] = 1; o[1] = 01; x[1] = 0x1; + d[2] = 2; o[2] = 02; x[2] = 0x2; + d[3] = 3; o[3] = 03; x[3] = 0x3; + d[4] = 4; o[4] = 04; x[4] = 0x4; + d[5] = 5; o[5] = 05; x[5] = 0x5; + d[6] = 6; o[6] = 06; x[6] = 0x6; + d[7] = 7; o[7] = 07; x[7] = 0x7; + d[8] = 8; o[8] = 010; x[8] = 0x8; + d[9] = 9; o[9] = 011; x[9] = 0x9; + d[10] = 10; o[10] = 012; x[10] = 0xa; + d[11] = 11; o[11] = 013; x[11] = 0xb; + d[12] = 12; o[12] = 014; x[12] = 0xc; + d[13] = 13; o[13] = 015; x[13] = 0xd; + d[14] = 14; o[14] = 016; x[14] = 0xe; + d[15] = 15; o[15] = 017; x[15] = 0xf; + d[16] = 16; o[16] = 020; x[16] = 0x10; + d[17] = 63; o[17] = 077; x[17] = 0x3f; + d[18] = 64; o[18] = 0100; x[18] = 0x40; + d[19] = 255; o[19] = 0377; x[19] = 0xff; + d[20] = 256; o[20] = 0400; x[20] = 0x100; + d[21] = 4095; o[21] = 07777; x[21] = 0xfff; + d[22] = 4096; o[22] = 010000; x[22] = 0x1000; + d[23] = 65535; o[23] = 0177777; x[23] = 0xffff; + d[24] = 65536; o[24] = 0200000; x[24] = 0x10000; + d[25] = 262143; o[25] = 0777777; x[25] = 0x3ffff; + d[26] = 262144; o[26] = 01000000; x[26] = 0x40000; + d[27] = 1048575; o[27] = 03777777; x[27] = 0xfffff; + d[28] = 1048576; o[28] = 04000000; x[28] = 0x100000; + d[29] = 16777215; o[29] = 077777777; x[29] = 0xffffff; + d[30] = 16777216; o[30] = 0100000000; x[30] = 0x1000000; + d[31] = 268435455; o[31] = 01777777777; x[31] = 0xfffffff; + d[32] = 268435456; o[32] = 02000000000; x[32] = 0x10000000; + d[33] = 1073741823; o[33] = 07777777777; x[33] = 0x3fffffff; + d[34] = 1073741824; o[34] = 010000000000; x[34] = 0x40000000; + d[35] = 4294967295; o[35] = 037777777777; x[35] = 0xffffffff; + d[36] = 4294967296; o[36] = 040000000000; x[36] = 0x100000000; + d[37] = 68719476735; o[37] = 0777777777777; x[37] = 0xfffffffff; + d[38] = 68719476736; o[38] = 01000000000000; x[38] = 0x1000000000; + + /* WHEW! */ + + for (j=0; j<39; j++){ + if ( g[j] != d[j] + || d[j] != o[j] + || o[j] != x[j]) { + + if( pd0 -> flgm != 0 ) { +/* printf(s241er,16); save in case opinions change... */ + printf("Decimal and octal/hex constants sometimes give\n"); + printf(" different results when assigned to longs.\n"); + } +/* lrc = 1; save... */ + } + } + + if (lrc != 0) rc =16; + + return rc; +} + +long pow2(n) /* Calculate 2**n by multiplying, not shifting */ +long n; +{ + long s; + s = 1; + while(n--) s = s*2; + return s; +} +s243(pd0) /* 2.4.3 Character constants */ +struct defs *pd0; +{ + static char s243er[] = "s243,er%d\n"; + static char qs243[8] = "s243 "; + char *ps, *pt; + int rc; + char chars[256]; + + rc = 0; + ps = qs243; + pt = pd0->rfs; + while(*pt++ = *ps++); + + /* One of the problems that arises when testing character constants + is that of definition: What, exactly, is the character set? + In order to guarantee a certain amount of machine independence, + the character set we will use here is the set of characters writ- + able as escape sequences in C, plus those characters used in writ- + ing C programs, i.e., + + letters: + ABCDEFGHIJKLMNOPQRSTUVWXYZ 26 + abcdefghijklmnopqrstuvwxyz 26 + numbers: + 0123456789 10 + special characters: + ~!"#%&()_=-^|{}[]+;*:<>,.?/ 27 + extra special characters: + newline \n + horizontal tab \t + backspace \b + carriage return \r + form feed \f + backslash \\ + single quote \' 7 + blank & NUL 2 + --- + 98 + + Any specific implementation of C may of course support additional + characters. */ + + /* Since the value of a character constant is the numerical value + of the character in the machine's character set, there should + be a one-to-one correspondence between characters and values. */ + + zerofill(chars); + + chars['a'] = 1; chars['A'] = 1; chars['~'] = 1; chars['0'] = 1; + chars['b'] = 1; chars['B'] = 1; chars['!'] = 1; chars['1'] = 1; + chars['c'] = 1; chars['C'] = 1; chars['"'] = 1; chars['2'] = 1; + chars['d'] = 1; chars['D'] = 1; chars['#'] = 1; chars['3'] = 1; + chars['e'] = 1; chars['E'] = 1; chars['%'] = 1; chars['4'] = 1; + chars['f'] = 1; chars['F'] = 1; chars['&'] = 1; chars['5'] = 1; + chars['g'] = 1; chars['G'] = 1; chars['('] = 1; chars['6'] = 1; + chars['h'] = 1; chars['H'] = 1; chars[')'] = 1; chars['7'] = 1; + chars['i'] = 1; chars['I'] = 1; chars['_'] = 1; chars['8'] = 1; + chars['j'] = 1; chars['J'] = 1; chars['='] = 1; chars['9'] = 1; + chars['k'] = 1; chars['K'] = 1; chars['-'] = 1; + chars['l'] = 1; chars['L'] = 1; chars['^'] = 1; + chars['m'] = 1; chars['M'] = 1; chars['|'] = 1; chars['\n'] = 1; + chars['n'] = 1; chars['N'] = 1; chars['\t'] = 1; + chars['o'] = 1; chars['O'] = 1; chars['{'] = 1; chars['\b'] = 1; + chars['p'] = 1; chars['P'] = 1; chars['}'] = 1; chars['\r'] = 1; + chars['q'] = 1; chars['Q'] = 1; chars['['] = 1; chars['\f'] = 1; + chars['r'] = 1; chars['R'] = 1; chars[']'] = 1; + chars['s'] = 1; chars['S'] = 1; chars['+'] = 1; chars['\\'] = 1; + chars['t'] = 1; chars['T'] = 1; chars[';'] = 1; chars['\''] = 1; + chars['u'] = 1; chars['U'] = 1; chars['*'] = 1; + chars['v'] = 1; chars['V'] = 1; chars[':'] = 1; chars['\0'] = 1; + chars['w'] = 1; chars['W'] = 1; chars['<'] = 1; chars[' '] = 1; + chars['x'] = 1; chars['X'] = 1; chars['>'] = 1; + chars['y'] = 1; chars['Y'] = 1; chars[','] = 1; + chars['z'] = 1; chars['Z'] = 1; chars['.'] = 1; + chars['?'] = 1; + chars['/'] = 1; + + if(sumof(chars) != 98){ + rc = rc+1; + if(pd0->flgd != 0) printf(s243er,1); + } + + /* Finally, the escape \ddd consists of the backslash followed + by 1, 2, or 3 octal digits which are taken to specify the + desired character. */ + + if( '\0' != 0 || '\01' != 1 || '\02' != 2 + || '\03' != 3 || '\04' != 4 || '\05' != 5 + || '\06' != 6 || '\07' != 7 || '\10' != 8 + || '\17' != 15 || '\20' != 16 || '\77' != 63 + || '\100' != 64 || '\177' != 127 ){ + + rc = rc+8; + if(pd0->flgd != 0) printf(s243er,8); + } + + return rc; +} +zerofill(x) +char *x; +{ + int j; + + for (j=0; j<256; j++) *x++ = 0; +} +sumof(x) +char *x; +{ + char *p; + int total, j; + + p = x; + total = 0; + + for(j=0; j<256; j++) total = total+ *p++; + return total; +} +s244(pd0) +struct defs *pd0; +{ + double a[8]; + int rc, lrc, j; + static char s244er[] = "s244,er%d\n"; + static char qs244[8] = "s244 "; + char *ps, *pt; + + ps = qs244; + pt = pd0->rfs; + while(*pt++ = *ps++); + rc = 0; + lrc = 0; + + /* Unfortunately, there's not a lot we can do with floating constants. + We can check to see that the various representations can be com- + piled, that the conversion is such that they yield the same hard- + ware representations in all cases, and that all representations + thus checked are double precision. */ + + a[0] = .1250E+04; + a[1] = 1.250E3; + a[2] = 12.50E02; + a[3] = 125.0e+1; + a[4] = 1250e00; + a[5] = 12500.e-01; + a[6] = 125000e-2; + a[7] = 1250.; + + lrc = 0; + for (j=0; j<7; j++) if(a[j] != a[j+1]) lrc = 1; + + if(lrc != 0) { + if(pd0->flgd != 0) printf(s244er,1); + rc = rc+1; + } + + if ( (sizeof .1250E+04 ) != sizeof(double) + || (sizeof 1.250E3 ) != sizeof(double) + || (sizeof 12.50E02 ) != sizeof(double) + || (sizeof 1.250e+1 ) != sizeof(double) + || (sizeof 1250e00 ) != sizeof(double) + || (sizeof 12500.e-01) != sizeof(double) + || (sizeof 125000e-2 ) != sizeof(double) + || (sizeof 1250. ) != sizeof(double)){ + + if(pd0->flgd != 0) printf(s244er,2); + rc = rc+2; + } + + return rc; +} +s25(pd0) +struct defs *pd0; +{ + char *s, *s2; + int rc, lrc, j; + static char s25er[] = "s25,er%d\n"; + static char qs25[8] = "s25 "; + char *ps, *pt; + + ps = qs25; + pt = pd0->rfs; + while(*pt++ = *ps++); + rc = 0; + + /* A string is a sequence of characters surrounded by double + quotes, as in "...". */ + + s = "..."; + + /* A string has type "array of characters" and storage class + static and is initialized with the given characters. */ + + if ( s[0] != s[1] || s[1] != s[2] + || s[2] != '.' ) { + + rc = rc+1; + if(pd0->flgd != 0) printf(s25er,1); + } + + /* The compiler places a null byte \0 at the end of each string + so the program which scans the string can find its end. */ + + if( s[3] != '\0' ){ + rc = rc+4; + if(pd0->flgd != 0) printf(s25er,4); + } + + /* In a string, the double quote character " must be preceded + by a \. */ + + if( ".\"."[1] != '"' ){ + rc = rc+8; + if(pd0->flgd != 0) printf(s25er,8); + } + + /* In addition, the same escapes described for character constants + may be used. */ + + s = "\n\t\b\r\f\\\'"; + + if( s[0] != '\n' + || s[1] != '\t' + || s[2] != '\b' + || s[3] != '\r' + || s[4] != '\f' + || s[5] != '\\' + || s[6] != '\'' ){ + + rc = rc+16; + if( pd0->flgd != 0) printf(s25er,16); + } + + /* Finally, a \ and an immediately following newline are ignored */ + + s2 = "queep!"; + s = "queep!"; + + lrc = 0; + for (j=0; jflgd != 0) printf(s25er,32); + } + return rc; +} +s26(pd0) /* 2.6 Hardware Characteristics */ +struct defs *pd0; +{ + static char qs26[8] = "s26 "; + char *ps, *pt; + char c0, c1; + float temp, one, delta; + double tempd, oned; + static char s[] = "%3d bits in %ss.\n"; + static char s2[] = "%e is the least number that can be added to 1. (%s).\n"; + + ps = qs26; + pt = pd0->rfs; + + while(*pt++ = *ps++); + + /* Here, we shake the machinery a little to see what falls + out. First, we find out how many bits are in a char. */ + + pd0->cbits = 0; + c0 = 0; + c1 = 1; + + while(c0 != c1) { + c1 = c1<<1; + pd0->cbits = pd0->cbits+1; + } + /* That information lets us determine the size of everything else. */ + + pd0->ibits = pd0->cbits * sizeof(int); + pd0->sbits = pd0->cbits * sizeof(short); + pd0->lbits = pd0->cbits * sizeof(long); + pd0->ubits = pd0->cbits * sizeof(unsigned); + pd0->fbits = pd0->cbits * sizeof(float); + pd0->dbits = pd0->cbits * sizeof(double); + + /* We have now almost reconstructed the table in section 2.6, the + exception being the range of the floating point hardware. + Now there are just so many ways to conjure up a floating point + representation system that it's damned near impossible to guess + what's going on by writing a program to interpret bit patterns. + Further, the information isn't all that useful, if we consider + the fact that machines that won't handle numbers between 10**30 + and 10**-30 are very hard to find, and that people playing with + numbers outside that range have a lot more to worry about than + just the capacity of the characteristic. + + A much more useful measure is the precision, which can be ex- + pressed in terms of the smallest number that can be added to + 1. without loss of significance. We calculate that here, for + float and double. */ + + one = 1.; + delta = 1.; + temp = 0.; + while(temp != one) { + temp = one+delta; + delta = delta/2.; + } + pd0->fprec = delta * 4.; + oned = 1.; + delta = 1.; + tempd = 0.; + while(tempd != oned) { + tempd = oned+delta; + delta = delta/2.; + } + pd0->dprec = delta * 4.; + + /* Now, if anyone's interested, we publish the results. */ + + if(pd0->flgm != 0) { + printf(s,pd0->cbits,"char"); + printf(s,pd0->ibits,"int"); + printf(s,pd0->sbits,"short"); + printf(s,pd0->lbits,"long"); + printf(s,pd0->ubits,"unsigned"); + printf(s,pd0->fbits,"float"); + printf(s,pd0->dbits,"double"); + printf(s2,pd0->fprec,"float"); + printf(s2,pd0->dprec,"double"); + } + /* Since we are only exploring and perhaps reporting, but not + testing any features, we cannot return an error code. */ + + return 0; +} +int extvar; +s4(pd0) /* 4. What's in a name? */ +struct defs *pd0; +{ + static char s4er[] = "s4,er%d\n"; + static char qs4[8] = "s4 "; + char *ps, *pt; + int j, rc; + + short sint; /* short integer, for size test */ + int pint; /* plain */ + long lint; /* long */ + unsigned target; + unsigned int mask; + + rc = 0; + ps = qs4; + pt = pd0->rfs; + + while(*pt++ = *ps++); + +/* There are four declarable storage classes: automatic, +static, external, and register. Automatic variables have +been dealt with extensively thus far, and will not be specif- +ically treated in this section. Register variables are treated +in section s81. + + Static variables are local to a block, but retain their +values upon reentry to a block, even after control has left +the block. */ + + for (j=0; j<3; j++) + if(svtest(j) != zero()){ + rc = 1; + if(pd0->flgd != 0) printf(s4er,1); + } + ; + +/* External variables exist and retain their values throughout +the execution of the entire program, and may be used for comm- +unication between functions, even separately compiled functions. + */ + + setev(); + if(testev() != 0){ + rc=rc+2; + if(pd0->flgd != 0) printf(s4er,2); + } +/* + Characters have been tested elsewhere (in s243). + + Up to three sizes of integer, declared short int, int, and +long int, are available. Longer integers provide no less storage +than shorter ones, but implementation may make either short +integers, or long integers, or both, equivalent to plain +integers. + */ + + if(sizeof lint < sizeof pint || sizeof pint < sizeof sint){ + + rc = rc+4; + if(pd0->flgd != 0) printf(s4er,4); + } + +/* Unsigned integers, declared unsigned, obey the laws of +arithmetic modulo 2**n, where n is the number of bits in the +implementation */ + + target = ~0U; + mask = 1; + + for(j=0; j<(sizeof target)*pd0->cbits; j++){ + + mask = mask⌖ + target = target>>1; + } + + if(mask != 1 || target != 0){ + + rc = rc+8; + if(pd0->flgd != 0) printf(s4er,8); + } + + return rc; +} +svtest(n) +int n; +{ + static k; + int rc; + switch (n) { + + case 0: k = 1978; + rc = 0; + break; + + case 1: if(k != 1978) rc = 1; + else{ + k = 1929; + rc = 0; + } + break; + + case 2: if(k != 1929) rc = 1; + else rc = 0; + break; + } + return rc; +} +zero(){ /* Returns a value of zero, possibly */ + static k; /* with side effects, as it's called */ + int rc; /* alternately with svtest, above, */ + k = 2; /* and has the same internal storage */ + rc = 0; /* requirements. */ + return rc; +} +testev(){ + if(extvar != 1066) return 1; + else return 0; +} +s61(pd0) /* Characters and integers */ +struct defs *pd0; +{ + static char s61er[] = "s61,er%d\n"; + static char qs61[8] = "s61 "; + short from, shortint; + long int to, longint; + int rc, lrc; + int j; + char fromc, charint; + char *wd, *pc[6]; + + static char upper_alpha[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + static char lower_alpha[] = "abcdefghijklmnopqrstuvwxyz"; + static char numbers[] = "0123456789"; + static char special_characters[] = "~!\"#%&()_=-^|{}[]+;*:<>,.?/"; + static char extra_special_characters[] = "\n\t\b\r\f\\\'"; + static char blank_and_NUL[] = " \0"; + + char *ps, *pt; + ps = qs61; + pt = pd0->rfs; + rc = 0; + while (*pt++ = *ps++); + +/* A character or a short integer may be used wherever +an integer may be used. In all cases, the value is converted +to integer. This principle is extensively used throughout this +program, and will not be explicitly tested here. */ + +/* Conversion of a shorter integer to a longer always +involves sign extension. */ + + from = -19; + to = from; + + if(to != -19){ + rc = rc+1; + if(pd0->flgd != 0) printf(s61er,1); + } + +/* It is guaranteed that a member of the standard char- +acter set is nonnegative. */ + + pc[0] = upper_alpha; + pc[1] = lower_alpha; + pc[2] = numbers; + pc[3] = special_characters; + pc[4] = extra_special_characters; + pc[5] = blank_and_NUL; + + lrc = 0; + for (j=0; j<6; j++) + while(*pc[j]) if(*pc[j]++ < 0) lrc =1; + + if(lrc != 0){ + rc=rc+2; + if(pd0->flgd != 0) printf(s61er,2); + } + +/* When a longer integer is converted to a shorter or +to a char, it is truncated on the left; excess bits are +simply discarded. */ + + longint = 1048579; /* =2**20+3 */ + shortint = longint; + charint = longint; + + if((shortint != longint && shortint != 3) || + (charint != longint && charint != 3)) { + rc = rc+8; + if(pd0->flgd != 0) printf(s61er,8); + } + + return rc; +} +s626(pd0) /* 6.2 Float and double */ + /* 6.3 Floating and integral */ + /* 6.4 Pointers and integers */ + /* 6.5 Unsigned */ + /* 6.6 Arithmetic conversions */ +struct defs *pd0; +{ + static char s626er[] = "s626,er%d\n"; + static char qs626[8] = "s626 "; + int rc; + char *ps, *pt; + float eps, f1, f2, f3, f4, f; + long lint1, lint2, l, ls; + char c, t[28], t0; + short s; + int is, i, j; + unsigned u, us; + double d, ds; + ps = qs626; + pt = pd0->rfs; + rc = 0; + while (*pt++ = *ps++); + + /* Conversions of integral values to floating type are + well-behaved. */ + + f1 = 1.; + lint1 = 1.; + lint2 = 1.; + + for(j=0;jlbits-2;j++){ + f1 = f1*2; + lint2 = (lint2<<1)|lint1; + } + f2 = lint2; + f1 = (f1-f2)/f1; + if(f1>2.*pd0->fprec){ + + rc = rc+2; + if(pd0->flgd != 0) printf(s626er,2); + } + + /* Pointer-integer combinations are discussed in s74, + "Additive operators". The unsigned-int combination + appears below. */ + + c = 125; + s = 125; + i = 125; is = 15625; + u = 125; us = 15625; + l = 125; ls = 15625; + f = 125.; + d = 125.; ds = 15625.; + + for(j=0;j<28;j++) t[j] = 0; + + if(c*c != is) t[ 0] = 1; + if(s*c != is) t[ 1] = 1; + if(s*s != is) t[ 2] = 1; + if(i*c != is) t[ 3] = 1; + if(i*s != is) t[ 4] = 1; + if(i*i != is) t[ 5] = 1; + if(u*c != us) t[ 6] = 1; + if(u*s != us) t[ 7] = 1; + if(u*i != us) t[ 8] = 1; + if(u*u != us) t[ 9] = 1; + if(l*c != ls) t[10] = 1; + if(l*s != ls) t[11] = 1; + if(l*i != ls) t[12] = 1; + if(l*u != us) t[13] = 1; + if(l*l != ls) t[14] = 1; + if(f*c != ds) t[15] = 1; + if(f*s != ds) t[16] = 1; + if(f*i != ds) t[17] = 1; + if(f*u != ds) t[18] = 1; + if(f*l != ds) t[19] = 1; + if(f*f != ds) t[20] = 1; + if(d*c != ds) t[21] = 1; + if(d*s != ds) t[22] = 1; + if(d*i != ds) t[23] = 1; + if(d*u != ds) t[24] = 1; + if(d*l != ds) t[25] = 1; + if(d*f != ds) t[26] = 1; + if(d*d != ds) t[27] = 1; + + t0 = 0; + for(j=0; j<28; j++) t0 = t0+t[j]; + + if(t0 != 0){ + + rc = rc+4; + if(pd0->flgd != 0){ + + printf(s626er,4); + printf(" key="); + for(j=0;j<28;j++) printf("%d",t[j]); + printf("\n"); + } + } + + /* When an unsigned integer is converted to long, + the value of the result is the same numerically + as that of the unsigned integer. */ + + l = (unsigned)0100000; + if((long)l > (unsigned)0100000){ + + rc = rc+8; + if(pd0->flgd != 0) printf(s626er,8); + } + + return rc; +} +s71(pd0) /* 7.1 Primary expressions */ +struct defs *pd0; +{ + static char s71er[] = "s71,er%d\n"; + static char qs71[8] = "s71 "; + int rc; + char *ps, *pt; + static char q = 'q'; + int x[10], McCarthy(), clobber(), a, b, *p; + ps = qs71; + pt = pd0->rfs; + rc = 0; + while (*pt++ = *ps++); + +/* Testing of expressions and operators is quite complicated, + because (a) problems are apt to surface in queer combinations + of operators and operands, rather than in isolation, + and (b) the number of expressions needed to provoke a case + of improper behaviour may be quite large. Hence, we take the + following approach: for this section, and for subsequent + sections through 7.15, we will check the primitive operations + in isolation, thus verifying that the primitives work, + after a fashion. The job of testing combinations, we will + leave to a separate, machine-generated program, to be included + in the C test package at some later date. + */ + +/* A string is a primary expression. The identifier points to + the first character of a string. + */ + + if(*"queep" != q){ + rc = rc+1; + if(pd0->flgd != 0) printf(s71er,1); + } +/* A parenthesized expression is a primary expression whose + type and value are the same as those of the unadorned + expression. + */ + if((2+3) != 2+3) { + rc = rc+2; + if(pd0->flgd != 0) printf(s71er,2); + } + +/* A primary expression followed by an expression in square + brackets is a primary expression. The intuitive meaning is + that of a subscript. The expression E1[E2] is identical + (by definition) to *((E1)+(E2)). + */ + + x[5] = 1942; + if(x[5] != 1942 || x[5] != *((x)+(5))){ + rc = rc+4; + if(pd0->flgd != 0) printf(s71er,4); + } + +/* If the various flavors of function calls didn't work, we + would never have gotten this far; however, we do need to + show that functions can be recursive... + */ + + if ( McCarthy(-5) != 91){ + rc = rc+8; + if(pd0->flgd != 0) printf(s71er,8); + } + +/* and that argument passing is strictly by value. */ + + a = 2; + b = 3; + p = &b; + + clobber(a,p); + + if(a != 2 || b != 2){ + rc = rc+16; + if(pd0->flgd != 0) printf(s71er,16); + } + +/* Finally, structures and unions are addressed thusly: */ + + if(pd0->dprec != (*pd0).dprec){ + rc = rc+32; + if(pd0->flgd != 0) printf(s71er,32); + } + + return rc; +} +McCarthy(x) +int x; +{ + if(x>100) return x-10; + else return McCarthy( McCarthy(x+11)); +} +clobber(x,y) +int x, *y; +{ + x = 3; + *y = 2; +} +s714(pd0) /* 7.14 Assignment operators */ +struct defs *pd0; +{ + static char f[] = "Local error %d.\n"; + static char s714er[] = "s714,er%d\n"; + static char qs714[8] = "s714 "; + register int prlc, lrc; + int rc; + char cl, cr; + short sl, sr; + int il, ir; + long ll, lr; + unsigned ul, ur; + float fl, fr; + double dl, dr; + char *ps, *pt; + ps = qs714; + pt = pd0->rfs; + rc = 0; + lrc = 0; + prlc = pd0->flgl; + while (*pt++ = *ps++); + + /* This section tests the assignment operators. + + It is an exhaustive test of all assignment statements + of the form: + + vl op vr + + where vl and vr are variables from the set + {char,short,int,long,unsigned,float,double} and op is + one of the assignment operators. There are 395 such + statements. + + The initial values for the variables have been chosen + so that both the initial values and the results will + "fit" in just about any implementation, and that the re- + sults will be such that they test for the proper form- + ation of composite operators, rather than checking for + the valid operation of those operators' components. + For example, in checking >>=, we want to verify that + a right shift and a move take place, rather than + whether or not there may be some peculiarities about + the right shift. Such tests have been made previously, + and to repeat them here would be to throw out a red + herring. + + The table below lists the operators, assignment targets, + initial values for left and right operands, and the + expected values of the results. + + + = += -= *= /= %= >>= <<= &= ^= |= +char 2 7 3 10 2 1 1 20 8 6 14 +short 2 7 3 10 2 1 1 20 8 6 14 +int 2 7 3 10 2 1 1 20 8 6 14 +long 2 7 3 10 2 1 1 20 8 6 14 +unsigned 2 7 3 10 2 1 1 20 8 6 14 +float 2 7 3 10 2.5 | | +double 2 7 3 10 2.5 | | + | | +initial (5,2) | (5,2) | (12,10) + + The following machine-generated program reflects the + tests described in the table. + */ + + cl = 5; cr = 2; + cl = cr; + if(cl != 2){ + lrc = 1; + if(prlc) printf(f,lrc); + } + cl = 5; sr = 2; + cl = sr; + if(cl != 2){ + lrc = 2; + if(prlc) printf(f,lrc); + } + cl = 5; ir = 2; + cl = ir; + if(cl != 2){ + lrc = 3; + if(prlc) printf(f,lrc); + } + cl = 5; lr = 2; + cl = lr; + if(cl != 2){ + lrc = 4; + if(prlc) printf(f,lrc); + } + cl = 5; ur = 2; + cl = ur; + if(cl != 2){ + lrc = 5; + if(prlc) printf(f,lrc); + } + cl = 5; fr = 2; + cl = fr; + if(cl != 2){ + lrc = 6; + if(prlc) printf(f,lrc); + } + cl = 5; dr = 2; + cl = dr; + if(cl != 2){ + lrc = 7; + if(prlc) printf(f,lrc); + } + sl = 5; cr = 2; + sl = cr; + if(sl != 2){ + lrc = 8; + if(prlc) printf(f,lrc); + } + sl = 5; sr = 2; + sl = sr; + if(sl != 2){ + lrc = 9; + if(prlc) printf(f,lrc); + } + sl = 5; ir = 2; + sl = ir; + if(sl != 2){ + lrc = 10; + if(prlc) printf(f,lrc); + } + sl = 5; lr = 2; + sl = lr; + if(sl != 2){ + lrc = 11; + if(prlc) printf(f,lrc); + } + sl = 5; ur = 2; + sl = ur; + if(sl != 2){ + lrc = 12; + if(prlc) printf(f,lrc); + } + sl = 5; fr = 2; + sl = fr; + if(sl != 2){ + lrc = 13; + if(prlc) printf(f,lrc); + } + sl = 5; dr = 2; + sl = dr; + if(sl != 2){ + lrc = 14; + if(prlc) printf(f,lrc); + } + il = 5; cr = 2; + il = cr; + if(il != 2){ + lrc = 15; + if(prlc) printf(f,lrc); + } + il = 5; sr = 2; + il = sr; + if(il != 2){ + lrc = 16; + if(prlc) printf(f,lrc); + } + il = 5; ir = 2; + il = ir; + if(il != 2){ + lrc = 17; + if(prlc) printf(f,lrc); + } + il = 5; lr = 2; + il = lr; + if(il != 2){ + lrc = 18; + if(prlc) printf(f,lrc); + } + il = 5; ur = 2; + il = ur; + if(il != 2){ + lrc = 19; + if(prlc) printf(f,lrc); + } + il = 5; fr = 2; + il = fr; + if(il != 2){ + lrc = 20; + if(prlc) printf(f,lrc); + } + il = 5; dr = 2; + il = dr; + if(il != 2){ + lrc = 21; + if(prlc) printf(f,lrc); + } + ll = 5; cr = 2; + ll = cr; + if(ll != 2){ + lrc = 22; + if(prlc) printf(f,lrc); + } + ll = 5; sr = 2; + ll = sr; + if(ll != 2){ + lrc = 23; + if(prlc) printf(f,lrc); + } + ll = 5; ir = 2; + ll = ir; + if(ll != 2){ + lrc = 24; + if(prlc) printf(f,lrc); + } + ll = 5; lr = 2; + ll = lr; + if(ll != 2){ + lrc = 25; + if(prlc) printf(f,lrc); + } + ll = 5; ur = 2; + ll = ur; + if(ll != 2){ + lrc = 26; + if(prlc) printf(f,lrc); + } + ll = 5; fr = 2; + ll = fr; + if(ll != 2){ + lrc = 27; + if(prlc) printf(f,lrc); + } + ll = 5; dr = 2; + ll = dr; + if(ll != 2){ + lrc = 28; + if(prlc) printf(f,lrc); + } + ul = 5; cr = 2; + ul = cr; + if(ul != 2){ + lrc = 29; + if(prlc) printf(f,lrc); + } + ul = 5; sr = 2; + ul = sr; + if(ul != 2){ + lrc = 30; + if(prlc) printf(f,lrc); + } + ul = 5; ir = 2; + ul = ir; + if(ul != 2){ + lrc = 31; + if(prlc) printf(f,lrc); + } + ul = 5; lr = 2; + ul = lr; + if(ul != 2){ + lrc = 32; + if(prlc) printf(f,lrc); + } + ul = 5; ur = 2; + ul = ur; + if(ul != 2){ + lrc = 33; + if(prlc) printf(f,lrc); + } + ul = 5; fr = 2; + ul = fr; + if(ul != 2){ + lrc = 34; + if(prlc) printf(f,lrc); + } + ul = 5; dr = 2; + ul = dr; + if(ul != 2){ + lrc = 35; + if(prlc) printf(f,lrc); + } + fl = 5; cr = 2; + fl = cr; + if(fl != 2){ + lrc = 36; + if(prlc) printf(f,lrc); + } + fl = 5; sr = 2; + fl = sr; + if(fl != 2){ + lrc = 37; + if(prlc) printf(f,lrc); + } + fl = 5; ir = 2; + fl = ir; + if(fl != 2){ + lrc = 38; + if(prlc) printf(f,lrc); + } + fl = 5; lr = 2; + fl = lr; + if(fl != 2){ + lrc = 39; + if(prlc) printf(f,lrc); + } + fl = 5; ur = 2; + fl = ur; + if(fl != 2){ + lrc = 40; + if(prlc) printf(f,lrc); + } + fl = 5; fr = 2; + fl = fr; + if(fl != 2){ + lrc = 41; + if(prlc) printf(f,lrc); + } + fl = 5; dr = 2; + fl = dr; + if(fl != 2){ + lrc = 42; + if(prlc) printf(f,lrc); + } + dl = 5; cr = 2; + dl = cr; + if(dl != 2){ + lrc = 43; + if(prlc) printf(f,lrc); + } + dl = 5; sr = 2; + dl = sr; + if(dl != 2){ + lrc = 44; + if(prlc) printf(f,lrc); + } + dl = 5; ir = 2; + dl = ir; + if(dl != 2){ + lrc = 45; + if(prlc) printf(f,lrc); + } + dl = 5; lr = 2; + dl = lr; + if(dl != 2){ + lrc = 46; + if(prlc) printf(f,lrc); + } + dl = 5; ur = 2; + dl = ur; + if(dl != 2){ + lrc = 47; + if(prlc) printf(f,lrc); + } + dl = 5; fr = 2; + dl = fr; + if(dl != 2){ + lrc = 48; + if(prlc) printf(f,lrc); + } + dl = 5; dr = 2; + dl = dr; + if(dl != 2){ + lrc = 49; + if(prlc) printf(f,lrc); + } + cl = 5; cr = 2; + cl += cr; + if(cl != 7){ + lrc = 50; + if(prlc) printf(f,lrc); + } + cl = 5; sr = 2; + cl += sr; + if(cl != 7){ + lrc = 51; + if(prlc) printf(f,lrc); + } + cl = 5; ir = 2; + cl += ir; + if(cl != 7){ + lrc = 52; + if(prlc) printf(f,lrc); + } + cl = 5; lr = 2; + cl += lr; + if(cl != 7){ + lrc = 53; + if(prlc) printf(f,lrc); + } + cl = 5; ur = 2; + cl += ur; + if(cl != 7){ + lrc = 54; + if(prlc) printf(f,lrc); + } + cl = 5; fr = 2; + cl += fr; + if(cl != 7){ + lrc = 55; + if(prlc) printf(f,lrc); + } + cl = 5; dr = 2; + cl += dr; + if(cl != 7){ + lrc = 56; + if(prlc) printf(f,lrc); + } + sl = 5; cr = 2; + sl += cr; + if(sl != 7){ + lrc = 57; + if(prlc) printf(f,lrc); + } + sl = 5; sr = 2; + sl += sr; + if(sl != 7){ + lrc = 58; + if(prlc) printf(f,lrc); + } + sl = 5; ir = 2; + sl += ir; + if(sl != 7){ + lrc = 59; + if(prlc) printf(f,lrc); + } + sl = 5; lr = 2; + sl += lr; + if(sl != 7){ + lrc = 60; + if(prlc) printf(f,lrc); + } + sl = 5; ur = 2; + sl += ur; + if(sl != 7){ + lrc = 61; + if(prlc) printf(f,lrc); + } + sl = 5; fr = 2; + sl += fr; + if(sl != 7){ + lrc = 62; + if(prlc) printf(f,lrc); + } + sl = 5; dr = 2; + sl += dr; + if(sl != 7){ + lrc = 63; + if(prlc) printf(f,lrc); + } + il = 5; cr = 2; + il += cr; + if(il != 7){ + lrc = 64; + if(prlc) printf(f,lrc); + } + il = 5; sr = 2; + il += sr; + if(il != 7){ + lrc = 65; + if(prlc) printf(f,lrc); + } + il = 5; ir = 2; + il += ir; + if(il != 7){ + lrc = 66; + if(prlc) printf(f,lrc); + } + il = 5; lr = 2; + il += lr; + if(il != 7){ + lrc = 67; + if(prlc) printf(f,lrc); + } + il = 5; ur = 2; + il += ur; + if(il != 7){ + lrc = 68; + if(prlc) printf(f,lrc); + } + il = 5; fr = 2; + il += fr; + if(il != 7){ + lrc = 69; + if(prlc) printf(f,lrc); + } + il = 5; dr = 2; + il += dr; + if(il != 7){ + lrc = 70; + if(prlc) printf(f,lrc); + } + ll = 5; cr = 2; + ll += cr; + if(ll != 7){ + lrc = 71; + if(prlc) printf(f,lrc); + } + ll = 5; sr = 2; + ll += sr; + if(ll != 7){ + lrc = 72; + if(prlc) printf(f,lrc); + } + ll = 5; ir = 2; + ll += ir; + if(ll != 7){ + lrc = 73; + if(prlc) printf(f,lrc); + } + ll = 5; lr = 2; + ll += lr; + if(ll != 7){ + lrc = 74; + if(prlc) printf(f,lrc); + } + ll = 5; ur = 2; + ll += ur; + if(ll != 7){ + lrc = 75; + if(prlc) printf(f,lrc); + } + ll = 5; fr = 2; + ll += fr; + if(ll != 7){ + lrc = 76; + if(prlc) printf(f,lrc); + } + ll = 5; dr = 2; + ll += dr; + if(ll != 7){ + lrc = 77; + if(prlc) printf(f,lrc); + } + ul = 5; cr = 2; + ul += cr; + if(ul != 7){ + lrc = 78; + if(prlc) printf(f,lrc); + } + ul = 5; sr = 2; + ul += sr; + if(ul != 7){ + lrc = 79; + if(prlc) printf(f,lrc); + } + ul = 5; ir = 2; + ul += ir; + if(ul != 7){ + lrc = 80; + if(prlc) printf(f,lrc); + } + ul = 5; lr = 2; + ul += lr; + if(ul != 7){ + lrc = 81; + if(prlc) printf(f,lrc); + } + ul = 5; ur = 2; + ul += ur; + if(ul != 7){ + lrc = 82; + if(prlc) printf(f,lrc); + } + ul = 5; fr = 2; + ul += fr; + if(ul != 7){ + lrc = 83; + if(prlc) printf(f,lrc); + } + ul = 5; dr = 2; + ul += dr; + if(ul != 7){ + lrc = 84; + if(prlc) printf(f,lrc); + } + fl = 5; cr = 2; + fl += cr; + if(fl != 7){ + lrc = 85; + if(prlc) printf(f,lrc); + } + fl = 5; sr = 2; + fl += sr; + if(fl != 7){ + lrc = 86; + if(prlc) printf(f,lrc); + } + fl = 5; ir = 2; + fl += ir; + if(fl != 7){ + lrc = 87; + if(prlc) printf(f,lrc); + } + fl = 5; lr = 2; + fl += lr; + if(fl != 7){ + lrc = 88; + if(prlc) printf(f,lrc); + } + fl = 5; ur = 2; + fl += ur; + if(fl != 7){ + lrc = 89; + if(prlc) printf(f,lrc); + } + fl = 5; fr = 2; + fl += fr; + if(fl != 7){ + lrc = 90; + if(prlc) printf(f,lrc); + } + fl = 5; dr = 2; + fl += dr; + if(fl != 7){ + lrc = 91; + if(prlc) printf(f,lrc); + } + dl = 5; cr = 2; + dl += cr; + if(dl != 7){ + lrc = 92; + if(prlc) printf(f,lrc); + } + dl = 5; sr = 2; + dl += sr; + if(dl != 7){ + lrc = 93; + if(prlc) printf(f,lrc); + } + dl = 5; ir = 2; + dl += ir; + if(dl != 7){ + lrc = 94; + if(prlc) printf(f,lrc); + } + dl = 5; lr = 2; + dl += lr; + if(dl != 7){ + lrc = 95; + if(prlc) printf(f,lrc); + } + dl = 5; ur = 2; + dl += ur; + if(dl != 7){ + lrc = 96; + if(prlc) printf(f,lrc); + } + dl = 5; fr = 2; + dl += fr; + if(dl != 7){ + lrc = 97; + if(prlc) printf(f,lrc); + } + dl = 5; dr = 2; + dl += dr; + if(dl != 7){ + lrc = 98; + if(prlc) printf(f,lrc); + } + cl = 5; cr = 2; + cl -= cr; + if(cl != 3){ + lrc = 99; + if(prlc) printf(f,lrc); + } + cl = 5; sr = 2; + cl -= sr; + if(cl != 3){ + lrc = 100; + if(prlc) printf(f,lrc); + } + cl = 5; ir = 2; + cl -= ir; + if(cl != 3){ + lrc = 101; + if(prlc) printf(f,lrc); + } + cl = 5; lr = 2; + cl -= lr; + if(cl != 3){ + lrc = 102; + if(prlc) printf(f,lrc); + } + cl = 5; ur = 2; + cl -= ur; + if(cl != 3){ + lrc = 103; + if(prlc) printf(f,lrc); + } + cl = 5; fr = 2; + cl -= fr; + if(cl != 3){ + lrc = 104; + if(prlc) printf(f,lrc); + } + cl = 5; dr = 2; + cl -= dr; + if(cl != 3){ + lrc = 105; + if(prlc) printf(f,lrc); + } + sl = 5; cr = 2; + sl -= cr; + if(sl != 3){ + lrc = 106; + if(prlc) printf(f,lrc); + } + sl = 5; sr = 2; + sl -= sr; + if(sl != 3){ + lrc = 107; + if(prlc) printf(f,lrc); + } + sl = 5; ir = 2; + sl -= ir; + if(sl != 3){ + lrc = 108; + if(prlc) printf(f,lrc); + } + sl = 5; lr = 2; + sl -= lr; + if(sl != 3){ + lrc = 109; + if(prlc) printf(f,lrc); + } + sl = 5; ur = 2; + sl -= ur; + if(sl != 3){ + lrc = 110; + if(prlc) printf(f,lrc); + } + sl = 5; fr = 2; + sl -= fr; + if(sl != 3){ + lrc = 111; + if(prlc) printf(f,lrc); + } + sl = 5; dr = 2; + sl -= dr; + if(sl != 3){ + lrc = 112; + if(prlc) printf(f,lrc); + } + il = 5; cr = 2; + il -= cr; + if(il != 3){ + lrc = 113; + if(prlc) printf(f,lrc); + } + il = 5; sr = 2; + il -= sr; + if(il != 3){ + lrc = 114; + if(prlc) printf(f,lrc); + } + il = 5; ir = 2; + il -= ir; + if(il != 3){ + lrc = 115; + if(prlc) printf(f,lrc); + } + il = 5; lr = 2; + il -= lr; + if(il != 3){ + lrc = 116; + if(prlc) printf(f,lrc); + } + il = 5; ur = 2; + il -= ur; + if(il != 3){ + lrc = 117; + if(prlc) printf(f,lrc); + } + il = 5; fr = 2; + il -= fr; + if(il != 3){ + lrc = 118; + if(prlc) printf(f,lrc); + } + il = 5; dr = 2; + il -= dr; + if(il != 3){ + lrc = 119; + if(prlc) printf(f,lrc); + } + ll = 5; cr = 2; + ll -= cr; + if(ll != 3){ + lrc = 120; + if(prlc) printf(f,lrc); + } + ll = 5; sr = 2; + ll -= sr; + if(ll != 3){ + lrc = 121; + if(prlc) printf(f,lrc); + } + ll = 5; ir = 2; + ll -= ir; + if(ll != 3){ + lrc = 122; + if(prlc) printf(f,lrc); + } + ll = 5; lr = 2; + ll -= lr; + if(ll != 3){ + lrc = 123; + if(prlc) printf(f,lrc); + } + ll = 5; ur = 2; + ll -= ur; + if(ll != 3){ + lrc = 124; + if(prlc) printf(f,lrc); + } + ll = 5; fr = 2; + ll -= fr; + if(ll != 3){ + lrc = 125; + if(prlc) printf(f,lrc); + } + ll = 5; dr = 2; + ll -= dr; + if(ll != 3){ + lrc = 126; + if(prlc) printf(f,lrc); + } + ul = 5; cr = 2; + ul -= cr; + if(ul != 3){ + lrc = 127; + if(prlc) printf(f,lrc); + } + ul = 5; sr = 2; + ul -= sr; + if(ul != 3){ + lrc = 128; + if(prlc) printf(f,lrc); + } + ul = 5; ir = 2; + ul -= ir; + if(ul != 3){ + lrc = 129; + if(prlc) printf(f,lrc); + } + ul = 5; lr = 2; + ul -= lr; + if(ul != 3){ + lrc = 130; + if(prlc) printf(f,lrc); + } + ul = 5; ur = 2; + ul -= ur; + if(ul != 3){ + lrc = 131; + if(prlc) printf(f,lrc); + } + ul = 5; fr = 2; + ul -= fr; + if(ul != 3){ + lrc = 132; + if(prlc) printf(f,lrc); + } + ul = 5; dr = 2; + ul -= dr; + if(ul != 3){ + lrc = 133; + if(prlc) printf(f,lrc); + } + fl = 5; cr = 2; + fl -= cr; + if(fl != 3){ + lrc = 134; + if(prlc) printf(f,lrc); + } + fl = 5; sr = 2; + fl -= sr; + if(fl != 3){ + lrc = 135; + if(prlc) printf(f,lrc); + } + fl = 5; ir = 2; + fl -= ir; + if(fl != 3){ + lrc = 136; + if(prlc) printf(f,lrc); + } + fl = 5; lr = 2; + fl -= lr; + if(fl != 3){ + lrc = 137; + if(prlc) printf(f,lrc); + } + fl = 5; ur = 2; + fl -= ur; + if(fl != 3){ + lrc = 138; + if(prlc) printf(f,lrc); + } + fl = 5; fr = 2; + fl -= fr; + if(fl != 3){ + lrc = 139; + if(prlc) printf(f,lrc); + } + fl = 5; dr = 2; + fl -= dr; + if(fl != 3){ + lrc = 140; + if(prlc) printf(f,lrc); + } + dl = 5; cr = 2; + dl -= cr; + if(dl != 3){ + lrc = 141; + if(prlc) printf(f,lrc); + } + dl = 5; sr = 2; + dl -= sr; + if(dl != 3){ + lrc = 142; + if(prlc) printf(f,lrc); + } + dl = 5; ir = 2; + dl -= ir; + if(dl != 3){ + lrc = 143; + if(prlc) printf(f,lrc); + } + dl = 5; lr = 2; + dl -= lr; + if(dl != 3){ + lrc = 144; + if(prlc) printf(f,lrc); + } + dl = 5; ur = 2; + dl -= ur; + if(dl != 3){ + lrc = 145; + if(prlc) printf(f,lrc); + } + dl = 5; fr = 2; + dl -= fr; + if(dl != 3){ + lrc = 146; + if(prlc) printf(f,lrc); + } + dl = 5; dr = 2; + dl -= dr; + if(dl != 3){ + lrc = 147; + if(prlc) printf(f,lrc); + } + cl = 5; cr = 2; + cl *= cr; + if(cl != 10){ + lrc = 148; + if(prlc) printf(f,lrc); + } + cl = 5; sr = 2; + cl *= sr; + if(cl != 10){ + lrc = 149; + if(prlc) printf(f,lrc); + } + cl = 5; ir = 2; + cl *= ir; + if(cl != 10){ + lrc = 150; + if(prlc) printf(f,lrc); + } + cl = 5; lr = 2; + cl *= lr; + if(cl != 10){ + lrc = 151; + if(prlc) printf(f,lrc); + } + cl = 5; ur = 2; + cl *= ur; + if(cl != 10){ + lrc = 152; + if(prlc) printf(f,lrc); + } + cl = 5; fr = 2; + cl *= fr; + if(cl != 10){ + lrc = 153; + if(prlc) printf(f,lrc); + } + cl = 5; dr = 2; + cl *= dr; + if(cl != 10){ + lrc = 154; + if(prlc) printf(f,lrc); + } + sl = 5; cr = 2; + sl *= cr; + if(sl != 10){ + lrc = 155; + if(prlc) printf(f,lrc); + } + sl = 5; sr = 2; + sl *= sr; + if(sl != 10){ + lrc = 156; + if(prlc) printf(f,lrc); + } + sl = 5; ir = 2; + sl *= ir; + if(sl != 10){ + lrc = 157; + if(prlc) printf(f,lrc); + } + sl = 5; lr = 2; + sl *= lr; + if(sl != 10){ + lrc = 158; + if(prlc) printf(f,lrc); + } + sl = 5; ur = 2; + sl *= ur; + if(sl != 10){ + lrc = 159; + if(prlc) printf(f,lrc); + } + sl = 5; fr = 2; + sl *= fr; + if(sl != 10){ + lrc = 160; + if(prlc) printf(f,lrc); + } + sl = 5; dr = 2; + sl *= dr; + if(sl != 10){ + lrc = 161; + if(prlc) printf(f,lrc); + } + il = 5; cr = 2; + il *= cr; + if(il != 10){ + lrc = 162; + if(prlc) printf(f,lrc); + } + il = 5; sr = 2; + il *= sr; + if(il != 10){ + lrc = 163; + if(prlc) printf(f,lrc); + } + il = 5; ir = 2; + il *= ir; + if(il != 10){ + lrc = 164; + if(prlc) printf(f,lrc); + } + il = 5; lr = 2; + il *= lr; + if(il != 10){ + lrc = 165; + if(prlc) printf(f,lrc); + } + il = 5; ur = 2; + il *= ur; + if(il != 10){ + lrc = 166; + if(prlc) printf(f,lrc); + } + il = 5; fr = 2; + il *= fr; + if(il != 10){ + lrc = 167; + if(prlc) printf(f,lrc); + } + il = 5; dr = 2; + il *= dr; + if(il != 10){ + lrc = 168; + if(prlc) printf(f,lrc); + } + ll = 5; cr = 2; + ll *= cr; + if(ll != 10){ + lrc = 169; + if(prlc) printf(f,lrc); + } + ll = 5; sr = 2; + ll *= sr; + if(ll != 10){ + lrc = 170; + if(prlc) printf(f,lrc); + } + ll = 5; ir = 2; + ll *= ir; + if(ll != 10){ + lrc = 171; + if(prlc) printf(f,lrc); + } + ll = 5; lr = 2; + ll *= lr; + if(ll != 10){ + lrc = 172; + if(prlc) printf(f,lrc); + } + ll = 5; ur = 2; + ll *= ur; + if(ll != 10){ + lrc = 173; + if(prlc) printf(f,lrc); + } + ll = 5; fr = 2; + ll *= fr; + if(ll != 10){ + lrc = 174; + if(prlc) printf(f,lrc); + } + ll = 5; dr = 2; + ll *= dr; + if(ll != 10){ + lrc = 175; + if(prlc) printf(f,lrc); + } + ul = 5; cr = 2; + ul *= cr; + if(ul != 10){ + lrc = 176; + if(prlc) printf(f,lrc); + } + ul = 5; sr = 2; + ul *= sr; + if(ul != 10){ + lrc = 177; + if(prlc) printf(f,lrc); + } + ul = 5; ir = 2; + ul *= ir; + if(ul != 10){ + lrc = 178; + if(prlc) printf(f,lrc); + } + ul = 5; lr = 2; + ul *= lr; + if(ul != 10){ + lrc = 179; + if(prlc) printf(f,lrc); + } + ul = 5; ur = 2; + ul *= ur; + if(ul != 10){ + lrc = 180; + if(prlc) printf(f,lrc); + } + ul = 5; fr = 2; + ul *= fr; + if(ul != 10){ + lrc = 181; + if(prlc) printf(f,lrc); + } + ul = 5; dr = 2; + ul *= dr; + if(ul != 10){ + lrc = 182; + if(prlc) printf(f,lrc); + } + fl = 5; cr = 2; + fl *= cr; + if(fl != 10){ + lrc = 183; + if(prlc) printf(f,lrc); + } + fl = 5; sr = 2; + fl *= sr; + if(fl != 10){ + lrc = 184; + if(prlc) printf(f,lrc); + } + fl = 5; ir = 2; + fl *= ir; + if(fl != 10){ + lrc = 185; + if(prlc) printf(f,lrc); + } + fl = 5; lr = 2; + fl *= lr; + if(fl != 10){ + lrc = 186; + if(prlc) printf(f,lrc); + } + fl = 5; ur = 2; + fl *= ur; + if(fl != 10){ + lrc = 187; + if(prlc) printf(f,lrc); + } + fl = 5; fr = 2; + fl *= fr; + if(fl != 10){ + lrc = 188; + if(prlc) printf(f,lrc); + } + fl = 5; dr = 2; + fl *= dr; + if(fl != 10){ + lrc = 189; + if(prlc) printf(f,lrc); + } + dl = 5; cr = 2; + dl *= cr; + if(dl != 10){ + lrc = 190; + if(prlc) printf(f,lrc); + } + dl = 5; sr = 2; + dl *= sr; + if(dl != 10){ + lrc = 191; + if(prlc) printf(f,lrc); + } + dl = 5; ir = 2; + dl *= ir; + if(dl != 10){ + lrc = 192; + if(prlc) printf(f,lrc); + } + dl = 5; lr = 2; + dl *= lr; + if(dl != 10){ + lrc = 193; + if(prlc) printf(f,lrc); + } + dl = 5; ur = 2; + dl *= ur; + if(dl != 10){ + lrc = 194; + if(prlc) printf(f,lrc); + } + dl = 5; fr = 2; + dl *= fr; + if(dl != 10){ + lrc = 195; + if(prlc) printf(f,lrc); + } + dl = 5; dr = 2; + dl *= dr; + if(dl != 10){ + lrc = 196; + if(prlc) printf(f,lrc); + } + cl = 5; cr = 2; + cl /= cr; + if(cl != 2){ + lrc = 197; + if(prlc) printf(f,lrc); + } + cl = 5; sr = 2; + cl /= sr; + if(cl != 2){ + lrc = 198; + if(prlc) printf(f,lrc); + } + cl = 5; ir = 2; + cl /= ir; + if(cl != 2){ + lrc = 199; + if(prlc) printf(f,lrc); + } + cl = 5; lr = 2; + cl /= lr; + if(cl != 2){ + lrc = 200; + if(prlc) printf(f,lrc); + } + cl = 5; ur = 2; + cl /= ur; + if(cl != 2){ + lrc = 201; + if(prlc) printf(f,lrc); + } + cl = 5; fr = 2; + cl /= fr; + if(cl != 2){ + lrc = 202; + if(prlc) printf(f,lrc); + } + cl = 5; dr = 2; + cl /= dr; + if(cl != 2){ + lrc = 203; + if(prlc) printf(f,lrc); + } + sl = 5; cr = 2; + sl /= cr; + if(sl != 2){ + lrc = 204; + if(prlc) printf(f,lrc); + } + sl = 5; sr = 2; + sl /= sr; + if(sl != 2){ + lrc = 205; + if(prlc) printf(f,lrc); + } + sl = 5; ir = 2; + sl /= ir; + if(sl != 2){ + lrc = 206; + if(prlc) printf(f,lrc); + } + sl = 5; lr = 2; + sl /= lr; + if(sl != 2){ + lrc = 207; + if(prlc) printf(f,lrc); + } + sl = 5; ur = 2; + sl /= ur; + if(sl != 2){ + lrc = 208; + if(prlc) printf(f,lrc); + } + sl = 5; fr = 2; + sl /= fr; + if(sl != 2){ + lrc = 209; + if(prlc) printf(f,lrc); + } + sl = 5; dr = 2; + sl /= dr; + if(sl != 2){ + lrc = 210; + if(prlc) printf(f,lrc); + } + il = 5; cr = 2; + il /= cr; + if(il != 2){ + lrc = 211; + if(prlc) printf(f,lrc); + } + il = 5; sr = 2; + il /= sr; + if(il != 2){ + lrc = 212; + if(prlc) printf(f,lrc); + } + il = 5; ir = 2; + il /= ir; + if(il != 2){ + lrc = 213; + if(prlc) printf(f,lrc); + } + il = 5; lr = 2; + il /= lr; + if(il != 2){ + lrc = 214; + if(prlc) printf(f,lrc); + } + il = 5; ur = 2; + il /= ur; + if(il != 2){ + lrc = 215; + if(prlc) printf(f,lrc); + } + il = 5; fr = 2; + il /= fr; + if(il != 2){ + lrc = 216; + if(prlc) printf(f,lrc); + } + il = 5; dr = 2; + il /= dr; + if(il != 2){ + lrc = 217; + if(prlc) printf(f,lrc); + } + ll = 5; cr = 2; + ll /= cr; + if(ll != 2){ + lrc = 218; + if(prlc) printf(f,lrc); + } + ll = 5; sr = 2; + ll /= sr; + if(ll != 2){ + lrc = 219; + if(prlc) printf(f,lrc); + } + ll = 5; ir = 2; + ll /= ir; + if(ll != 2){ + lrc = 220; + if(prlc) printf(f,lrc); + } + ll = 5; lr = 2; + ll /= lr; + if(ll != 2){ + lrc = 221; + if(prlc) printf(f,lrc); + } + ll = 5; ur = 2; + ll /= ur; + if(ll != 2){ + lrc = 222; + if(prlc) printf(f,lrc); + } + ll = 5; fr = 2; + ll /= fr; + if(ll != 2){ + lrc = 223; + if(prlc) printf(f,lrc); + } + ll = 5; dr = 2; + ll /= dr; + if(ll != 2){ + lrc = 224; + if(prlc) printf(f,lrc); + } + ul = 5; cr = 2; + ul /= cr; + if(ul != 2){ + lrc = 225; + if(prlc) printf(f,lrc); + } + ul = 5; sr = 2; + ul /= sr; + if(ul != 2){ + lrc = 226; + if(prlc) printf(f,lrc); + } + ul = 5; ir = 2; + ul /= ir; + if(ul != 2){ + lrc = 227; + if(prlc) printf(f,lrc); + } + ul = 5; lr = 2; + ul /= lr; + if(ul != 2){ + lrc = 228; + if(prlc) printf(f,lrc); + } + ul = 5; ur = 2; + ul /= ur; + if(ul != 2){ + lrc = 229; + if(prlc) printf(f,lrc); + } + ul = 5; fr = 2; + ul /= fr; + if(ul != 2){ + lrc = 230; + if(prlc) printf(f,lrc); + } + ul = 5; dr = 2; + ul /= dr; + if(ul != 2){ + lrc = 231; + if(prlc) printf(f,lrc); + } + fl = 5; cr = 2; + fl /= cr; + if(fl != 2.5){ + lrc = 232; + if(prlc) printf(f,lrc); + } + fl = 5; sr = 2; + fl /= sr; + if(fl != 2.5){ + lrc = 233; + if(prlc) printf(f,lrc); + } + fl = 5; ir = 2; + fl /= ir; + if(fl != 2.5){ + lrc = 234; + if(prlc) printf(f,lrc); + } + fl = 5; lr = 2; + fl /= lr; + if(fl != 2.5){ + lrc = 235; + if(prlc) printf(f,lrc); + } + fl = 5; ur = 2; + fl /= ur; + if(fl != 2.5){ + lrc = 236; + if(prlc) printf(f,lrc); + } + fl = 5; fr = 2; + fl /= fr; + if(fl != 2.5){ + lrc = 237; + if(prlc) printf(f,lrc); + } + fl = 5; dr = 2; + fl /= dr; + if(fl != 2.5){ + lrc = 238; + if(prlc) printf(f,lrc); + } + dl = 5; cr = 2; + dl /= cr; + if(dl != 2.5){ + lrc = 239; + if(prlc) printf(f,lrc); + } + dl = 5; sr = 2; + dl /= sr; + if(dl != 2.5){ + lrc = 240; + if(prlc) printf(f,lrc); + } + dl = 5; ir = 2; + dl /= ir; + if(dl != 2.5){ + lrc = 241; + if(prlc) printf(f,lrc); + } + dl = 5; lr = 2; + dl /= lr; + if(dl != 2.5){ + lrc = 242; + if(prlc) printf(f,lrc); + } + dl = 5; ur = 2; + dl /= ur; + if(dl != 2.5){ + lrc = 243; + if(prlc) printf(f,lrc); + } + dl = 5; fr = 2; + dl /= fr; + if(dl != 2.5){ + lrc = 244; + if(prlc) printf(f,lrc); + } + dl = 5; dr = 2; + dl /= dr; + if(dl != 2.5){ + lrc = 245; + if(prlc) printf(f,lrc); + } + cl = 5; cr = 2; + cl %= cr; + if(cl != 1){ + lrc = 246; + if(prlc) printf(f,lrc); + } + cl = 5; sr = 2; + cl %= sr; + if(cl != 1){ + lrc = 247; + if(prlc) printf(f,lrc); + } + cl = 5; ir = 2; + cl %= ir; + if(cl != 1){ + lrc = 248; + if(prlc) printf(f,lrc); + } + cl = 5; lr = 2; + cl %= lr; + if(cl != 1){ + lrc = 249; + if(prlc) printf(f,lrc); + } + cl = 5; ur = 2; + cl %= ur; + if(cl != 1){ + lrc = 250; + if(prlc) printf(f,lrc); + } + sl = 5; cr = 2; + sl %= cr; + if(sl != 1){ + lrc = 251; + if(prlc) printf(f,lrc); + } + sl = 5; sr = 2; + sl %= sr; + if(sl != 1){ + lrc = 252; + if(prlc) printf(f,lrc); + } + sl = 5; ir = 2; + sl %= ir; + if(sl != 1){ + lrc = 253; + if(prlc) printf(f,lrc); + } + sl = 5; lr = 2; + sl %= lr; + if(sl != 1){ + lrc = 254; + if(prlc) printf(f,lrc); + } + sl = 5; ur = 2; + sl %= ur; + if(sl != 1){ + lrc = 255; + if(prlc) printf(f,lrc); + } + il = 5; cr = 2; + il %= cr; + if(il != 1){ + lrc = 256; + if(prlc) printf(f,lrc); + } + il = 5; sr = 2; + il %= sr; + if(il != 1){ + lrc = 257; + if(prlc) printf(f,lrc); + } + il = 5; ir = 2; + il %= ir; + if(il != 1){ + lrc = 258; + if(prlc) printf(f,lrc); + } + il = 5; lr = 2; + il %= lr; + if(il != 1){ + lrc = 259; + if(prlc) printf(f,lrc); + } + il = 5; ur = 2; + il %= ur; + if(il != 1){ + lrc = 260; + if(prlc) printf(f,lrc); + } + ll = 5; cr = 2; + ll %= cr; + if(ll != 1){ + lrc = 261; + if(prlc) printf(f,lrc); + } + ll = 5; sr = 2; + ll %= sr; + if(ll != 1){ + lrc = 262; + if(prlc) printf(f,lrc); + } + ll = 5; ir = 2; + ll %= ir; + if(ll != 1){ + lrc = 263; + if(prlc) printf(f,lrc); + } + ll = 5; lr = 2; + ll %= lr; + if(ll != 1){ + lrc = 264; + if(prlc) printf(f,lrc); + } + ll = 5; ur = 2; + ll %= ur; + if(ll != 1){ + lrc = 265; + if(prlc) printf(f,lrc); + } + ul = 5; cr = 2; + ul %= cr; + if(ul != 1){ + lrc = 266; + if(prlc) printf(f,lrc); + } + ul = 5; sr = 2; + ul %= sr; + if(ul != 1){ + lrc = 267; + if(prlc) printf(f,lrc); + } + ul = 5; ir = 2; + ul %= ir; + if(ul != 1){ + lrc = 268; + if(prlc) printf(f,lrc); + } + ul = 5; lr = 2; + ul %= lr; + if(ul != 1){ + lrc = 269; + if(prlc) printf(f,lrc); + } + ul = 5; ur = 2; + ul %= ur; + if(ul != 1){ + lrc = 270; + if(prlc) printf(f,lrc); + } + cl = 5; cr = 2; + cl >>= cr; + if(cl != 1){ + lrc = 271; + if(prlc) printf(f,lrc); + } + cl = 5; sr = 2; + cl >>= sr; + if(cl != 1){ + lrc = 272; + if(prlc) printf(f,lrc); + } + cl = 5; ir = 2; + cl >>= ir; + if(cl != 1){ + lrc = 273; + if(prlc) printf(f,lrc); + } + cl = 5; lr = 2; + cl >>= lr; + if(cl != 1){ + lrc = 274; + if(prlc) printf(f,lrc); + } + cl = 5; ur = 2; + cl >>= ur; + if(cl != 1){ + lrc = 275; + if(prlc) printf(f,lrc); + } + sl = 5; cr = 2; + sl >>= cr; + if(sl != 1){ + lrc = 276; + if(prlc) printf(f,lrc); + } + sl = 5; sr = 2; + sl >>= sr; + if(sl != 1){ + lrc = 277; + if(prlc) printf(f,lrc); + } + sl = 5; ir = 2; + sl >>= ir; + if(sl != 1){ + lrc = 278; + if(prlc) printf(f,lrc); + } + sl = 5; lr = 2; + sl >>= lr; + if(sl != 1){ + lrc = 279; + if(prlc) printf(f,lrc); + } + sl = 5; ur = 2; + sl >>= ur; + if(sl != 1){ + lrc = 280; + if(prlc) printf(f,lrc); + } + il = 5; cr = 2; + il >>= cr; + if(il != 1){ + lrc = 281; + if(prlc) printf(f,lrc); + } + il = 5; sr = 2; + il >>= sr; + if(il != 1){ + lrc = 282; + if(prlc) printf(f,lrc); + } + il = 5; ir = 2; + il >>= ir; + if(il != 1){ + lrc = 283; + if(prlc) printf(f,lrc); + } + il = 5; lr = 2; + il >>= lr; + if(il != 1){ + lrc = 284; + if(prlc) printf(f,lrc); + } + il = 5; ur = 2; + il >>= ur; + if(il != 1){ + lrc = 285; + if(prlc) printf(f,lrc); + } + ll = 5; cr = 2; + ll >>= cr; + if(ll != 1){ + lrc = 286; + if(prlc) printf(f,lrc); + } + ll = 5; sr = 2; + ll >>= sr; + if(ll != 1){ + lrc = 287; + if(prlc) printf(f,lrc); + } + ll = 5; ir = 2; + ll >>= ir; + if(ll != 1){ + lrc = 288; + if(prlc) printf(f,lrc); + } + ll = 5; lr = 2; + ll >>= lr; + if(ll != 1){ + lrc = 289; + if(prlc) printf(f,lrc); + } + ll = 5; ur = 2; + ll >>= ur; + if(ll != 1){ + lrc = 290; + if(prlc) printf(f,lrc); + } + ul = 5; cr = 2; + ul >>= cr; + if(ul != 1){ + lrc = 291; + if(prlc) printf(f,lrc); + } + ul = 5; sr = 2; + ul >>= sr; + if(ul != 1){ + lrc = 292; + if(prlc) printf(f,lrc); + } + ul = 5; ir = 2; + ul >>= ir; + if(ul != 1){ + lrc = 293; + if(prlc) printf(f,lrc); + } + ul = 5; lr = 2; + ul >>= lr; + if(ul != 1){ + lrc = 294; + if(prlc) printf(f,lrc); + } + ul = 5; ur = 2; + ul >>= ur; + if(ul != 1){ + lrc = 295; + if(prlc) printf(f,lrc); + } + cl = 5; cr = 2; + cl <<= cr; + if(cl != 20){ + lrc = 296; + if(prlc) printf(f,lrc); + } + cl = 5; sr = 2; + cl <<= sr; + if(cl != 20){ + lrc = 297; + if(prlc) printf(f,lrc); + } + cl = 5; ir = 2; + cl <<= ir; + if(cl != 20){ + lrc = 298; + if(prlc) printf(f,lrc); + } + cl = 5; lr = 2; + cl <<= lr; + if(cl != 20){ + lrc = 299; + if(prlc) printf(f,lrc); + } + cl = 5; ur = 2; + cl <<= ur; + if(cl != 20){ + lrc = 300; + if(prlc) printf(f,lrc); + } + sl = 5; cr = 2; + sl <<= cr; + if(sl != 20){ + lrc = 301; + if(prlc) printf(f,lrc); + } + sl = 5; sr = 2; + sl <<= sr; + if(sl != 20){ + lrc = 302; + if(prlc) printf(f,lrc); + } + sl = 5; ir = 2; + sl <<= ir; + if(sl != 20){ + lrc = 303; + if(prlc) printf(f,lrc); + } + sl = 5; lr = 2; + sl <<= lr; + if(sl != 20){ + lrc = 304; + if(prlc) printf(f,lrc); + } + sl = 5; ur = 2; + sl <<= ur; + if(sl != 20){ + lrc = 305; + if(prlc) printf(f,lrc); + } + il = 5; cr = 2; + il <<= cr; + if(il != 20){ + lrc = 306; + if(prlc) printf(f,lrc); + } + il = 5; sr = 2; + il <<= sr; + if(il != 20){ + lrc = 307; + if(prlc) printf(f,lrc); + } + il = 5; ir = 2; + il <<= ir; + if(il != 20){ + lrc = 308; + if(prlc) printf(f,lrc); + } + il = 5; lr = 2; + il <<= lr; + if(il != 20){ + lrc = 309; + if(prlc) printf(f,lrc); + } + il = 5; ur = 2; + il <<= ur; + if(il != 20){ + lrc = 310; + if(prlc) printf(f,lrc); + } + ll = 5; cr = 2; + ll <<= cr; + if(ll != 20){ + lrc = 311; + if(prlc) printf(f,lrc); + } + ll = 5; sr = 2; + ll <<= sr; + if(ll != 20){ + lrc = 312; + if(prlc) printf(f,lrc); + } + ll = 5; ir = 2; + ll <<= ir; + if(ll != 20){ + lrc = 313; + if(prlc) printf(f,lrc); + } + ll = 5; lr = 2; + ll <<= lr; + if(ll != 20){ + lrc = 314; + if(prlc) printf(f,lrc); + } + ll = 5; ur = 2; + ll <<= ur; + if(ll != 20){ + lrc = 315; + if(prlc) printf(f,lrc); + } + ul = 5; cr = 2; + ul <<= cr; + if(ul != 20){ + lrc = 316; + if(prlc) printf(f,lrc); + } + ul = 5; sr = 2; + ul <<= sr; + if(ul != 20){ + lrc = 317; + if(prlc) printf(f,lrc); + } + ul = 5; ir = 2; + ul <<= ir; + if(ul != 20){ + lrc = 318; + if(prlc) printf(f,lrc); + } + ul = 5; lr = 2; + ul <<= lr; + if(ul != 20){ + lrc = 319; + if(prlc) printf(f,lrc); + } + ul = 5; ur = 2; + ul <<= ur; + if(ul != 20){ + lrc = 320; + if(prlc) printf(f,lrc); + } + cl = 12; cr = 10; + cl &= cr; + if(cl != 8){ + lrc = 321; + if(prlc) printf(f,lrc); + } + cl = 12; sr = 10; + cl &= sr; + if(cl != 8){ + lrc = 322; + if(prlc) printf(f,lrc); + } + cl = 12; ir = 10; + cl &= ir; + if(cl != 8){ + lrc = 323; + if(prlc) printf(f,lrc); + } + cl = 12; lr = 10; + cl &= lr; + if(cl != 8){ + lrc = 324; + if(prlc) printf(f,lrc); + } + cl = 12; ur = 10; + cl &= ur; + if(cl != 8){ + lrc = 325; + if(prlc) printf(f,lrc); + } + sl = 12; cr = 10; + sl &= cr; + if(sl != 8){ + lrc = 326; + if(prlc) printf(f,lrc); + } + sl = 12; sr = 10; + sl &= sr; + if(sl != 8){ + lrc = 327; + if(prlc) printf(f,lrc); + } + sl = 12; ir = 10; + sl &= ir; + if(sl != 8){ + lrc = 328; + if(prlc) printf(f,lrc); + } + sl = 12; lr = 10; + sl &= lr; + if(sl != 8){ + lrc = 329; + if(prlc) printf(f,lrc); + } + sl = 12; ur = 10; + sl &= ur; + if(sl != 8){ + lrc = 330; + if(prlc) printf(f,lrc); + } + il = 12; cr = 10; + il &= cr; + if(il != 8){ + lrc = 331; + if(prlc) printf(f,lrc); + } + il = 12; sr = 10; + il &= sr; + if(il != 8){ + lrc = 332; + if(prlc) printf(f,lrc); + } + il = 12; ir = 10; + il &= ir; + if(il != 8){ + lrc = 333; + if(prlc) printf(f,lrc); + } + il = 12; lr = 10; + il &= lr; + if(il != 8){ + lrc = 334; + if(prlc) printf(f,lrc); + } + il = 12; ur = 10; + il &= ur; + if(il != 8){ + lrc = 335; + if(prlc) printf(f,lrc); + } + ll = 12; cr = 10; + ll &= cr; + if(ll != 8){ + lrc = 336; + if(prlc) printf(f,lrc); + } + ll = 12; sr = 10; + ll &= sr; + if(ll != 8){ + lrc = 337; + if(prlc) printf(f,lrc); + } + ll = 12; ir = 10; + ll &= ir; + if(ll != 8){ + lrc = 338; + if(prlc) printf(f,lrc); + } + ll = 12; lr = 10; + ll &= lr; + if(ll != 8){ + lrc = 339; + if(prlc) printf(f,lrc); + } + ll = 12; ur = 10; + ll &= ur; + if(ll != 8){ + lrc = 340; + if(prlc) printf(f,lrc); + } + ul = 12; cr = 10; + ul &= cr; + if(ul != 8){ + lrc = 341; + if(prlc) printf(f,lrc); + } + ul = 12; sr = 10; + ul &= sr; + if(ul != 8){ + lrc = 342; + if(prlc) printf(f,lrc); + } + ul = 12; ir = 10; + ul &= ir; + if(ul != 8){ + lrc = 343; + if(prlc) printf(f,lrc); + } + ul = 12; lr = 10; + ul &= lr; + if(ul != 8){ + lrc = 344; + if(prlc) printf(f,lrc); + } + ul = 12; ur = 10; + ul &= ur; + if(ul != 8){ + lrc = 345; + if(prlc) printf(f,lrc); + } + cl = 12; cr = 10; + cl ^= cr; + if(cl != 6){ + lrc = 346; + if(prlc) printf(f,lrc); + } + cl = 12; sr = 10; + cl ^= sr; + if(cl != 6){ + lrc = 347; + if(prlc) printf(f,lrc); + } + cl = 12; ir = 10; + cl ^= ir; + if(cl != 6){ + lrc = 348; + if(prlc) printf(f,lrc); + } + cl = 12; lr = 10; + cl ^= lr; + if(cl != 6){ + lrc = 349; + if(prlc) printf(f,lrc); + } + cl = 12; ur = 10; + cl ^= ur; + if(cl != 6){ + lrc = 350; + if(prlc) printf(f,lrc); + } + sl = 12; cr = 10; + sl ^= cr; + if(sl != 6){ + lrc = 351; + if(prlc) printf(f,lrc); + } + sl = 12; sr = 10; + sl ^= sr; + if(sl != 6){ + lrc = 352; + if(prlc) printf(f,lrc); + } + sl = 12; ir = 10; + sl ^= ir; + if(sl != 6){ + lrc = 353; + if(prlc) printf(f,lrc); + } + sl = 12; lr = 10; + sl ^= lr; + if(sl != 6){ + lrc = 354; + if(prlc) printf(f,lrc); + } + sl = 12; ur = 10; + sl ^= ur; + if(sl != 6){ + lrc = 355; + if(prlc) printf(f,lrc); + } + il = 12; cr = 10; + il ^= cr; + if(il != 6){ + lrc = 356; + if(prlc) printf(f,lrc); + } + il = 12; sr = 10; + il ^= sr; + if(il != 6){ + lrc = 357; + if(prlc) printf(f,lrc); + } + il = 12; ir = 10; + il ^= ir; + if(il != 6){ + lrc = 358; + if(prlc) printf(f,lrc); + } + il = 12; lr = 10; + il ^= lr; + if(il != 6){ + lrc = 359; + if(prlc) printf(f,lrc); + } + il = 12; ur = 10; + il ^= ur; + if(il != 6){ + lrc = 360; + if(prlc) printf(f,lrc); + } + ll = 12; cr = 10; + ll ^= cr; + if(ll != 6){ + lrc = 361; + if(prlc) printf(f,lrc); + } + ll = 12; sr = 10; + ll ^= sr; + if(ll != 6){ + lrc = 362; + if(prlc) printf(f,lrc); + } + ll = 12; ir = 10; + ll ^= ir; + if(ll != 6){ + lrc = 363; + if(prlc) printf(f,lrc); + } + ll = 12; lr = 10; + ll ^= lr; + if(ll != 6){ + lrc = 364; + if(prlc) printf(f,lrc); + } + ll = 12; ur = 10; + ll ^= ur; + if(ll != 6){ + lrc = 365; + if(prlc) printf(f,lrc); + } + ul = 12; cr = 10; + ul ^= cr; + if(ul != 6){ + lrc = 366; + if(prlc) printf(f,lrc); + } + ul = 12; sr = 10; + ul ^= sr; + if(ul != 6){ + lrc = 367; + if(prlc) printf(f,lrc); + } + ul = 12; ir = 10; + ul ^= ir; + if(ul != 6){ + lrc = 368; + if(prlc) printf(f,lrc); + } + ul = 12; lr = 10; + ul ^= lr; + if(ul != 6){ + lrc = 369; + if(prlc) printf(f,lrc); + } + ul = 12; ur = 10; + ul ^= ur; + if(ul != 6){ + lrc = 370; + if(prlc) printf(f,lrc); + } + cl = 12; cr = 10; + cl |= cr; + if(cl != 14){ + lrc = 371; + if(prlc) printf(f,lrc); + } + cl = 12; sr = 10; + cl |= sr; + if(cl != 14){ + lrc = 372; + if(prlc) printf(f,lrc); + } + cl = 12; ir = 10; + cl |= ir; + if(cl != 14){ + lrc = 373; + if(prlc) printf(f,lrc); + } + cl = 12; lr = 10; + cl |= lr; + if(cl != 14){ + lrc = 374; + if(prlc) printf(f,lrc); + } + cl = 12; ur = 10; + cl |= ur; + if(cl != 14){ + lrc = 375; + if(prlc) printf(f,lrc); + } + sl = 12; cr = 10; + sl |= cr; + if(sl != 14){ + lrc = 376; + if(prlc) printf(f,lrc); + } + sl = 12; sr = 10; + sl |= sr; + if(sl != 14){ + lrc = 377; + if(prlc) printf(f,lrc); + } + sl = 12; ir = 10; + sl |= ir; + if(sl != 14){ + lrc = 378; + if(prlc) printf(f,lrc); + } + sl = 12; lr = 10; + sl |= lr; + if(sl != 14){ + lrc = 379; + if(prlc) printf(f,lrc); + } + sl = 12; ur = 10; + sl |= ur; + if(sl != 14){ + lrc = 380; + if(prlc) printf(f,lrc); + } + il = 12; cr = 10; + il |= cr; + if(il != 14){ + lrc = 381; + if(prlc) printf(f,lrc); + } + il = 12; sr = 10; + il |= sr; + if(il != 14){ + lrc = 382; + if(prlc) printf(f,lrc); + } + il = 12; ir = 10; + il |= ir; + if(il != 14){ + lrc = 383; + if(prlc) printf(f,lrc); + } + il = 12; lr = 10; + il |= lr; + if(il != 14){ + lrc = 384; + if(prlc) printf(f,lrc); + } + il = 12; ur = 10; + il |= ur; + if(il != 14){ + lrc = 385; + if(prlc) printf(f,lrc); + } + ll = 12; cr = 10; + ll |= cr; + if(ll != 14){ + lrc = 386; + if(prlc) printf(f,lrc); + } + ll = 12; sr = 10; + ll |= sr; + if(ll != 14){ + lrc = 387; + if(prlc) printf(f,lrc); + } + ll = 12; ir = 10; + ll |= ir; + if(ll != 14){ + lrc = 388; + if(prlc) printf(f,lrc); + } + ll = 12; lr = 10; + ll |= lr; + if(ll != 14){ + lrc = 389; + if(prlc) printf(f,lrc); + } + ll = 12; ur = 10; + ll |= ur; + if(ll != 14){ + lrc = 390; + if(prlc) printf(f,lrc); + } + ul = 12; cr = 10; + ul |= cr; + if(ul != 14){ + lrc = 391; + if(prlc) printf(f,lrc); + } + ul = 12; sr = 10; + ul |= sr; + if(ul != 14){ + lrc = 392; + if(prlc) printf(f,lrc); + } + ul = 12; ir = 10; + ul |= ir; + if(ul != 14){ + lrc = 393; + if(prlc) printf(f,lrc); + } + ul = 12; lr = 10; + ul |= lr; + if(ul != 14){ + lrc = 394; + if(prlc) printf(f,lrc); + } + ul = 12; ur = 10; + ul |= ur; + if(ul != 14){ + lrc = 395; + if(prlc) printf(f,lrc); + } + if(lrc != 0) { + rc = 1; + if(pd0->flgd != 0) printf(s714er,1); + } + return rc; +} +s715(pd0) /* 7.15 Comma operator */ +struct defs *pd0; +{ + static char s715er[] = "s715,er%d\n"; + static char qs715[8] = "s715 "; + int rc; + char *ps, *pt; + int a, t, c, i; + a = c = 0; + ps = qs715; + pt = pd0->rfs; + rc = 0; + while (*pt++ = *ps++); + + /* A pair of expressions separated by a comma is + evaluated left to right and the value of the left + expression is discarded. + */ + i = 1; + if( i++,i++,i++,i++,++i != 6 ){ + if(pd0->flgd != 0) printf(s715er,1); + rc = rc+1; + } + + /* In contexts where the comma is given a special mean- + ing, for example in a list of actual arguments to + functions (sic) and lists of initializers, the comma + operator as described in this section can only appear + in parentheses; for example + + f( a, (t=3, t+2), c) + + has three arguments, the second of which has the + value 5. + */ + + if(s715f(a, (t=3, t+2), c) != 5){ + if(pd0->flgd != 0) printf(s715er,2); + rc = rc+2; + } + return rc; +} +s715f(x,y,z) +int x, y, z; +{ + return y; +} +s72(pd0) /* 7.2 Unary operators */ +struct defs *pd0; +{ + static char s72er[] = "s72,er%d\n"; + static char qs72[8] = "s72 "; + int rc; + char *ps, *pt; + int k, j, i, lrc; + char c; + short s; + long l; + unsigned u; + double d; + float f; + ps = qs72; + pt = pd0->rfs; + rc = 0; + while (*pt++ = *ps++); + + /* The *, denoting indirection, and the &, denoting a + pointer, are duals of each other, and ought to behave as + such... */ + + k = 2; + if(*&*&k != 2){ + rc = rc+1; + printf(s72er,1); + } + + /* The unary minus has the conventional meaning. */ + + if(k+(-k) != 0){ + rc = rc+2; + printf(s72er,2); + } + + /* The negation operator (!) has been thoroughly checked out, + perhaps more thoroughly than any of the others. The ~ oper- + ator gets us a ones complement. */ + + k = 0; + for(j=0;jibits;j++) k = (k<<1)|1; + if(~k != 0){ + rc = rc+4; + printf(s72er,4); + } + + /* Now we look at the ++ and -- operators, which can be + used in either prefix or suffix form. With side + effects they're loaded. */ + + k = 5; + + if( ++k != 6 || --k != 5 + || k++ != 5 || k-- != 6 + || k != 5 ){ + rc = rc+8; + printf(s72er,8); + } + + /* An expression preceded by the parenthesised name of a + data type causes conversion of the value of the expression + to the named type. This construction is called a cast. + Here, we check to see that all of the possible casts and + their simple combinations are accepted by the compiler, + and that they all produce a correct result for this sample + of size one. */ + + c = 26; l = 26; d = 26.; + s = 26; u = 26; + i = 26; f = 26.; + + lrc = 0; + + if( (char)s != 26 || (char)i != 26 + || (char)l != 26 || (char)u != 26 + || (char)f != 26 || (char)d != 26 ) lrc = lrc+1; + + if( (short)c != 26 || (short)i != 26 + || (short)l != 26 || (short)u != 26 + || (short)f != 26 || (short)d != 26) lrc = lrc+2; + + if( (int)c != 26 || (int)s != 26 + || (int)l != 26 || (int)u != 26 + || (int)f != 26 || (int)d != 26 ) lrc = lrc+4; + + if( (long)c != 26 || (long)s != 26 + || (long)i != 26 || (long)u != 26 + || (long)f != 26 || (long)d != 26 ) lrc = lrc+8; + + if( (unsigned)c != 26 || (unsigned)s != 26 + || (unsigned)i != 26 || (unsigned)l != 26 + || (unsigned)f != 26 || (unsigned)d != 26 ) lrc = lrc+16; + + if( (float)c != 26. || (float)s != 26. + || (float)i != 26. || (float)l != 26. + || (float)u != 26. || (float)d != 26. ) lrc = lrc+32; + + if( (double)c != 26. || (double)s != 26. + || (double)i != 26. || (double)l != 26. + || (double)u != 26. || (double)f != 26. ) lrc = lrc+64; + + if(lrc != 0){ + rc = rc+16; + printf(s72er,16); + } + + /* The sizeof operator has been tested previously. */ + + return rc; +} +s757(pd0) /* 7.5 Shift operators */ + /* 7.6 Relational operators */ + /* 7.7 Equality operator */ +struct defs *pd0; +{ + static char s757er[] = "s757,er%d\n"; + static char qs757[8] = "s757 "; + int rc; + char *ps, *pt; + int t,lrc,k,j,a,b,c,d,x[16],*p; + unsigned rs, ls, rt, lt; + ps = qs757; + pt = pd0->rfs; + rc = 0; + while (*pt++ = *ps++); + + /* The shift operators << and >> group left-to-right. + */ + + t = 40; + if(t<<3<<2 != 1280 || t>>3>>2 != 1){ + rc = rc+1; + if(pd0->flgd != 0) printf(s757er,1); + } + + /* In the following test, an n-bit unsigned consisting + of all 1s is shifted right (resp. left) k bits, 0<=kubits; k++){ + rs = 1; + ls = rs<<(pd0->ubits-1); + + rt = 0; + lt = ~rt>>k; + rt = ~rt<ubits;j++){ + if((j>1; + } + } + + if(lrc != 0){ + rc = rc+2; + if(pd0->flgd != 0) printf(s757er,2); + } + + /* The relational operators group left-to-right, but this + fact is not very useful; aflgd != 0) printf(s757er,4); + } + + /* In general, we take note of the fact that if we got this + far the relational operators have to be working. We test only + that two pointers may be compared; the result depends on + the relative locations in the address space of the + pointed-to objects. + */ + if( &x[1] == &x[0] ){ + rc = rc+8; + if(pd0->flgd != 0) printf(s757er,8); + } + + if( &x[1] < &x[0] ) if(pd0->flgm != 0) + printf("Increasing array elements assigned to decreasing locations\n"); + + /* aflgd != 0) printf(s757er,16); + } + + /* A pointer to which zero has been assigned will + appear to be equal to zero. + */ + + p = 0; + + if(p != 0){ + rc = rc+32; + if(pd0->flgd != 0) printf(s757er,32); + } + + return rc; +} +s7813(pd0) /* 7.8 Bitwise AND operator + 7.9 Bitwise OR operator + 7.10 Bitwise exclusive OR operator + 7.11 Logical AND operator + 7.12 Logical OR operator + 7.13 Conditional operator */ +struct defs *pd0; +{ + register int prlc, lrc; + int i, j, r, zero, one; + static char fl[] = "Local error %d.\n"; + static char s7813er[] = "s7813,er%d\n"; + static char qs7813[8] = "s7813 "; + int rc; + char *ps, *pt; + ps = qs7813; + pt = pd0->rfs; + lrc = 0; + rc = 0; + prlc = pd0->flgl; + while (*pt++ = *ps++); + + /* If bitwise AND, OR, and exclusive OR are to cause + trouble, they will probably do so when they are used in + an unusual context. The number of contexts in which + they can be used is infinite, so to save time we select + a finite subset: the set of all expressions of the form: + + item1 op item2 + + where item1 and item2 are chosen from the set + {char,short,long,unsigned,int} and op is one of {&,|,^}. + We will use 12 and 10 as values for the items, as these + values will fit into all data types on just about any + imaginable machine, and the results after performing the + bitwise operations on them are distinct for each operation, + i.e., + + 12 | 10 -> 1100 | 1010 -> 1110 -> 14 + 12 ^ 10 -> 1100 ^ 1010 -> 0110 -> 6 + 12 & 10 -> 1100 & 1010 -> 1000 -> 8 + + There are 75 such combinations: + */ + + if(((char)12 & (char)10) != 8) {lrc = 1; + if(prlc) printf(fl,lrc);} + if(((char)12 | (char)10) != 14) {lrc = 2; + if(prlc) printf(fl,lrc);} + if(((char)12 ^ (char)10) != 6) {lrc = 3; + if(prlc) printf(fl,lrc);} + if(((char)12 & (short)10) != 8) {lrc = 4; + if(prlc) printf(fl,lrc);} + if(((char)12 | (short)10) != 14) {lrc = 5; + if(prlc) printf(fl,lrc);} + if(((char)12 ^ (short)10) != 6) {lrc = 6; + if(prlc) printf(fl,lrc);} + if(((char)12 & (long)10) != 8) {lrc = 7; + if(prlc) printf(fl,lrc);} + if(((char)12 | (long)10) != 14) {lrc = 8; + if(prlc) printf(fl,lrc);} + if(((char)12 ^ (long)10) != 6) {lrc = 9; + if(prlc) printf(fl,lrc);} + if(((char)12 & (unsigned)10) != 8) {lrc = 10; + if(prlc) printf(fl,lrc);} + if(((char)12 | (unsigned)10) != 14) {lrc = 11; + if(prlc) printf(fl,lrc);} + if(((char)12 ^ (unsigned)10) != 6) {lrc = 12; + if(prlc) printf(fl,lrc);} + if(((char)12 & (int)10) != 8) {lrc = 13; + if(prlc) printf(fl,lrc);} + if(((char)12 | (int)10) != 14) {lrc = 14; + if(prlc) printf(fl,lrc);} + if(((char)12 ^ (int)10) != 6) {lrc = 15; + if(prlc) printf(fl,lrc);} + if(((short)12 & (char)10) != 8) {lrc = 16; + if(prlc) printf(fl,lrc);} + if(((short)12 | (char)10) != 14) {lrc = 17; + if(prlc) printf(fl,lrc);} + if(((short)12 ^ (char)10) != 6) {lrc = 18; + if(prlc) printf(fl,lrc);} + if(((short)12 & (short)10) != 8) {lrc = 16; + if(prlc) printf(fl,lrc);} + if(((short)12 | (short)10) != 14) {lrc = 20; + if(prlc) printf(fl,lrc);} + if(((short)12 ^ (short)10) != 6) {lrc = 21; + if(prlc) printf(fl,lrc);} + if(((short)12 & (long)10) != 8) {lrc = 22; + if(prlc) printf(fl,lrc);} + if(((short)12 | (long)10) != 14) {lrc = 23; + if(prlc) printf(fl,lrc);} + if(((short)12 ^ (long)10) != 6) {lrc = 24; + if(prlc) printf(fl,lrc);} + if(((short)12 & (unsigned)10) != 8) {lrc = 25; + if(prlc) printf(fl,lrc);} + if(((short)12 | (unsigned)10) != 14) {lrc = 26; + if(prlc) printf(fl,lrc);} + if(((short)12 ^ (unsigned)10) != 6) {lrc = 27; + if(prlc) printf(fl,lrc);} + if(((short)12 & (int)10) != 8) {lrc = 28; + if(prlc) printf(fl,lrc);} + if(((short)12 | (int)10) != 14) {lrc = 26; + if(prlc) printf(fl,lrc);} + if(((short)12 ^ (int)10) != 6) {lrc = 30; + if(prlc) printf(fl,lrc);} + if(((long)12 & (char)10) != 8) {lrc = 31; + if(prlc) printf(fl,lrc);} + if(((long)12 | (char)10) != 14) {lrc = 32; + if(prlc) printf(fl,lrc);} + if(((long)12 ^ (char)10) != 6) {lrc = 33; + if(prlc) printf(fl,lrc);} + if(((long)12 & (short)10) != 8) {lrc = 34; + if(prlc) printf(fl,lrc);} + if(((long)12 | (short)10) != 14) {lrc = 35; + if(prlc) printf(fl,lrc);} + if(((long)12 ^ (short)10) != 6) {lrc = 36; + if(prlc) printf(fl,lrc);} + if(((long)12 & (long)10) != 8) {lrc = 37; + if(prlc) printf(fl,lrc);} + if(((long)12 | (long)10) != 14) {lrc = 38; + if(prlc) printf(fl,lrc);} + if(((long)12 ^ (long)10) != 6) {lrc = 39; + if(prlc) printf(fl,lrc);} + if(((long)12 & (unsigned)10) != 8) {lrc = 40; + if(prlc) printf(fl,lrc);} + if(((long)12 | (unsigned)10) != 14) {lrc = 41; + if(prlc) printf(fl,lrc);} + if(((long)12 ^ (unsigned)10) != 6) {lrc = 42; + if(prlc) printf(fl,lrc);} + if(((long)12 & (int)10) != 8) {lrc = 43; + if(prlc) printf(fl,lrc);} + if(((long)12 | (int)10) != 14) {lrc = 44; + if(prlc) printf(fl,lrc);} + if(((long)12 ^ (int)10) != 6) {lrc = 45; + if(prlc) printf(fl,lrc);} + if(((unsigned)12 & (char)10) != 8) {lrc = 46; + if(prlc) printf(fl,lrc);} + if(((unsigned)12 | (char)10) != 14) {lrc = 47; + if(prlc) printf(fl,lrc);} + if(((unsigned)12 ^ (char)10) != 6) {lrc = 48; + if(prlc) printf(fl,lrc);} + if(((unsigned)12 & (short)10) != 8) {lrc = 49; + if(prlc) printf(fl,lrc);} + if(((unsigned)12 | (short)10) != 14) {lrc = 50; + if(prlc) printf(fl,lrc);} + if(((unsigned)12 ^ (short)10) != 6) {lrc = 51; + if(prlc) printf(fl,lrc);} + if(((unsigned)12 & (long)10) != 8) {lrc = 52; + if(prlc) printf(fl,lrc);} + if(((unsigned)12 | (long)10) != 14) {lrc = 53; + if(prlc) printf(fl,lrc);} + if(((unsigned)12 ^ (long)10) != 6) {lrc = 54; + if(prlc) printf(fl,lrc);} + if(((unsigned)12 & (unsigned)10) != 8) {lrc = 55; + if(prlc) printf(fl,lrc);} + if(((unsigned)12 | (unsigned)10) != 14) {lrc = 56; + if(prlc) printf(fl,lrc);} + if(((unsigned)12 ^ (unsigned)10) != 6) {lrc = 57; + if(prlc) printf(fl,lrc);} + if(((unsigned)12 & (int)10) != 8) {lrc = 58; + if(prlc) printf(fl,lrc);} + if(((unsigned)12 | (int)10) != 14) {lrc = 56; + if(prlc) printf(fl,lrc);} + if(((unsigned)12 ^ (int)10) != 6) {lrc = 60; + if(prlc) printf(fl,lrc);} + if(((int)12 & (char)10) != 8) {lrc = 61; + if(prlc) printf(fl,lrc);} + if(((int)12 | (char)10) != 14) {lrc = 62; + if(prlc) printf(fl,lrc);} + if(((int)12 ^ (char)10) != 6) {lrc = 63; + if(prlc) printf(fl,lrc);} + if(((int)12 & (short)10) != 8) {lrc = 64; + if(prlc) printf(fl,lrc);} + if(((int)12 | (short)10) != 14) {lrc = 65; + if(prlc) printf(fl,lrc);} + if(((int)12 ^ (short)10) != 6) {lrc = 66; + if(prlc) printf(fl,lrc);} + if(((int)12 & (long)10) != 8) {lrc = 67; + if(prlc) printf(fl,lrc);} + if(((int)12 | (long)10) != 14) {lrc = 68; + if(prlc) printf(fl,lrc);} + if(((int)12 ^ (long)10) != 6) {lrc = 69; + if(prlc) printf(fl,lrc);} + if(((int)12 & (unsigned)10) != 8) {lrc = 70; + if(prlc) printf(fl,lrc);} + if(((int)12 | (unsigned)10) != 14) {lrc = 71; + if(prlc) printf(fl,lrc);} + if(((int)12 ^ (unsigned)10) != 6) {lrc = 72; + if(prlc) printf(fl,lrc);} + if(((int)12 & (int)10) != 8) {lrc = 73; if(prlc) printf(fl,lrc);} + if(((int)12 | (int)10) != 14) {lrc = 74; if(prlc) printf(fl,lrc);} + if(((int)12 ^ (int)10) != 6) {lrc = 75; if(prlc) printf(fl,lrc);} + + if(lrc != 0){ + if(pd0->flgd != 0) printf(s7813er,1); + rc = rc+1; + } + + /* The && operator groups left to right. It returns 1 + if both of the operands are nonzero; 0 otherwise. + It guarantees left to right evaluation; moreover, the + second operand is not evaluated if the value of the + first operand is 0. + */ + + lrc = 0; + i = j = 0; + + r = i++ && j++; + if(i!=1) {lrc = 1; if(prlc) printf(fl,lrc);} + if(j!=0) {lrc = 2; if(prlc) printf(fl,lrc);} + if(r!=0) {lrc = 3; if(prlc) printf(fl,lrc);} + r = i && j++; + if(i!=1) {lrc = 4; if(prlc) printf(fl,lrc);} + if(j!=1) {lrc = 5; if(prlc) printf(fl,lrc);} + if(r!=0) {lrc = 6; if(prlc) printf(fl,lrc);} + r = i-- && j; + if(i!=0) {lrc = 7; if(prlc) printf(fl,lrc);} + if(j!=1) {lrc = 8; if(prlc) printf(fl,lrc);} + if(r!=1) {lrc = 9; if(prlc) printf(fl,lrc);} + r = i && j--; + if(i!=0) {lrc = 10; if(prlc) printf(fl,lrc);} + if(j!=1) {lrc = 11; if(prlc) printf(fl,lrc);} + if(r!=0) {lrc = 12; if(prlc) printf(fl,lrc);} + + if(lrc!=0){ + if(pd0->flgd != 0) printf(s7813er,2); + rc = rc+2; + } + + /* The || operator groups left to right. It returns 1 + if either of its operands is nonzero; 0 otherwise. It + guarantees left to right evaluation; moreover, the second + operand is not evaluated if the value of the first + operand is nonzero. + */ + + lrc = 0; + i = j = 0; + r = i++ || j; + if(i!=1) {lrc = 1; if(prlc) printf(fl,lrc);} + if(j!=0) {lrc = 2; if(prlc) printf(fl,lrc);} + if(r!=0) {lrc = 3; if(prlc) printf(fl,lrc);} + r = j++ || i; + if(i!=1) {lrc = 4; if(prlc) printf(fl,lrc);} + if(j!=1) {lrc = 5; if(prlc) printf(fl,lrc);} + if(r!=1) {lrc = 6; if(prlc) printf(fl,lrc);} + r = i-- || j--; + if(i!=0) {lrc = 7; if(prlc) printf(fl,lrc);} + if(j!=1) {lrc = 8; if(prlc) printf(fl,lrc);} + if(r!=1) {lrc = 9; if(prlc) printf(fl,lrc);} + r = i || j--; + if(i!=0) {lrc = 10; if(prlc) printf(fl,lrc);} + if(j!=0) {lrc = 11; if(prlc) printf(fl,lrc);} + if(r!=1) {lrc = 12; if(prlc) printf(fl,lrc);} + + if(lrc!=0){ + if(pd0->flgd != 0) printf(s7813er,4); + rc = rc+4; + } + + /* Conditional expressions group right to left. */ + + i = j = 0; + zero = 0; + one = 1; + r = one?zero:one?i++:j++; + if(r!=0 || i!=0 || j!=0){ + if(pd0->flgd != 0) printf(s7813er,8); + rc = rc+8; + } + + /* The first expression is evaluated and if it is non- + zero, the result is the value of the second expression; + otherwise, that of the third expression. + */ + + if((one?zero:1) != 0 || (zero?1:zero) != 0){ + if(pd0->flgd != 0) printf(s7813er,16); + rc = rc+16; + } + return rc; +} +s81(pd0) /* 8.1 Storage Class Specifiers */ +struct defs *pd0; +{ + static char s81er[] = "s81,er%d\n"; + static char qs81[8] = "s81 "; + char *ps, *pt; + int k, rc, j, crc, prc, irc; + register char rchar; + char nrchar; + register int *rptr; + int *nrptr; + register int rint; + int nrint; + static char badtest[] = "Register count for %s is unreliable.\n"; + static char goodtest[] = "%d registers assigned to %s variables.\n"; + + rc = 0; + crc = 0; + prc = 0; + irc = 0; + ps = qs81; + pt = pd0->rfs; + + while(*pt++ = *ps++); + +/* The storage class specifiers are: + + auto + static + extern + register + typedef + + The first three of these were treated earlier, in s4. The last + will be checked in s88. "Register" remains. + + There are three flavors of register, viz., char, int and pointer. + We wish first to ascertain that the representations as register + are consistent with the corresponding nonregister representations. + */ + + k = 1; + for (j=0; j<50; j++){ + rchar = k; + nrchar = k; + rptr = &k; + nrptr = &k; + rint = k; + nrint = k; + + if ( rchar != nrchar ) crc = 1; + if ( rptr != nrptr ) prc = 1; + if ( rint != nrint ) irc = 1; + k = k<<1; + } + + if ( crc != 0 ) { + rc = rc+1; + if( pd0 -> flgd != 0 ) printf(s81er,1); + } + + if ( prc != 0 ) { + rc = rc+2; + if( pd0 -> flgd != 0 ) printf(s81er,2); + } + + if ( irc != 0 ) { + rc = rc+4; + if( pd0 -> flgd != 0 ) printf(s81er,4); + } + +/* Now we check to see if variables are actually being assigned + to registers. */ + + k = regc(); + if ( pd0->flgm != 0 ) { + if ( k < 0 ) printf(badtest,"char"); + else printf(goodtest,k,"char"); + } + + k = regp(); + if ( pd0->flgm != 0 ) { + if ( k<0 ) printf(badtest,"pointer"); + else printf(goodtest,k,"pointer"); + } + + k = regi(); + if ( pd0->flgm != 0 ) { + if ( k<0 ) printf(badtest,"int"); + else printf(goodtest,k,"int"); + } + + return rc; +} +regc() { /* char to register assignment */ +/* Testing a variable whose storage class has been spec- +ified as "register" is somewhat tricky, but it can be done in a +fairly reliable fashion by taking advantage of our knowledge of the +ways in which compilers operate. If we declare a collection of vari- +ables of the same storage class, we would expect that, when storage +for these variables is actually allocated, the variables will be +bunched together and ordered according to one of the following +criteria: + + (a) the order in which they were defined. + (b) the order in which they are used. + (c) alphabetically. + (d) the order in which they appear in the compiler's + symbol table. + (e) some other way. + + Hence, if we define a sequence of variables in close alpha- +betical order, and use them in the same order in which we define +them, we would expect the differences between the addresses of +successive variables to be constant, except in case (d) where the +symbol table is a hash table, or in case (e). If a subsequence in +the middle of this sequence is selected, and for this subsequence, +every other variable is specified to be "register", and address +differences are taken between adjacent nonregister variables, we would +still expect to find constant differences if the "register" vari- +ables were actually assigned to registers, and some other diff- +erences if they were not. Specifically, if we had N variables +specified as "register" of which the first n were actually ass- +igned to registers, we would expect the sequence of differences +to consist of a number of occurrences of some number, followed by +N-n occurrences of some other number, followed by several occurr- +ences of the first number. If we get a sequence like this, we can +determine, by simple subtraction, how many (if any) variables are +being assigned to registers. If we get some other sequence, we know +that the test is invalid. */ + + char r00; + char r01; + char r02; + char r03; + register char r04; + char r05; + register char r06; + char r07; + register char r08; + char r09; + register char r10; + char r11; + register char r12; + char r13; + register char r14; + char r15; + register char r16; + char r17; + register char r18; + char r19; + register char r20; + char r21; + register char r22; + char r23; + register char r24; + char r25; + register char r26; + char r27; + register char r28; + char r29; + register char r30; + char r31; + register char r32; + char r33; + register char r34; + char r35; + char r36; + char r37; + char r38; + + int s, n1, n2, nr, j, d[22]; + r00 = 0; + r01 = 1; + r02 = 2; + r03 = 3; + r04 = 4; + r05 = 5; + r06 = 6; + r07 = 7; + r08 = 8; + r09 = 9; + r10 = 10; + r11 = 11; + r12 = 12; + r13 = 13; + r14 = 14; + r15 = 15; + r16 = 16; + r17 = 17; + r18 = 18; + r19 = 19; + r20 = 20; + r21 = 21; + r22 = 22; + r23 = 23; + r24 = 24; + r25 = 25; + r26 = 26; + r27 = 27; + r28 = 28; + r29 = 29; + r30 = 30; + r31 = 31; + r32 = 32; + r33 = 33; + r34 = 34; + r35 = 35; + r36 = 36; + r37 = 37; + r38 = 38; + + d[0] = &r01 - &r00; + d[1] = &r02 - &r01; + d[2] = &r03 - &r02; + d[3] = &r05 - &r03; + d[4] = &r07 - &r05; + d[5] = &r09 - &r07; + d[6] = &r11 - &r09; + d[7] = &r13 - &r11; + d[8] = &r15 - &r13; + d[9] = &r17 - &r15; + d[10] = &r19 - &r17; + d[11] = &r21 - &r19; + d[12] = &r23 - &r21; + d[13] = &r25 - &r23; + d[14] = &r27 - &r25; + d[15] = &r29 - &r27; + d[16] = &r31 - &r29; + d[17] = &r33 - &r31; + d[18] = &r35 - &r33; + d[19] = &r36 - &r35; + d[20] = &r37 - &r36; + d[21] = &r38 - &r37; + + +/* The following FSM analyzes the string of differences. It accepts +strings of the form a+b+a+ and returns 16 minus the number of bs, +which is the number of variables that actually got into registers. +Otherwise it signals rejection by returning -1., indicating that the +test is unreliable. */ + + n1 = d[0]; + s = 1; + + for (j=0; j<22; j++) + switch (s) { + case 1: if (d[j] != n1) { + n2 = d[j]; + s = 2; + nr = 1; + } + break; + case 2: if (d[j] == n1) { + s = 3; + break; + } + if (d[j] == n2) { + nr = nr+1; + break; + } + s = 4; + break; + case 3: if (d[j] != n1) s = 4; + break; + } + ; + + if (s == 3) return 16-nr; + else return -1; +} +regi() { /* int to register assignment */ +/* Testing a variable whose storage class has been spec- +ified as "register" is somewhat tricky, but it can be done in a +fairly reliable fashion by taking advantage of our knowledge of the +ways in which compilers operate. If we declare a collection of vari- +ables of the same storage class, we would expect that, when storage +for these variables is actually allocated, the variables will be +bunched together and ordered according to one of the following +criteria: + + (a) the order in which they were defined. + (b) the order in which they are used. + (c) alphabetically. + (d) the order in which they appear in the compiler's + symbol table. + (e) some other way. + + Hence, if we define a sequence of variables in close alpha- +betical order, and use them in the same order in which we define +them, we would expect the differences between the addresses of +successive variables to be constant, except in case (d) where the +symbol table is a hash table, or in case (e). If a subsequence in +the middle of this sequence is selected, and for this subsequence, +every other variable is specified to be "register", and address +differences are taken between adjacent nonregister variables, we would +still expect to find constant differences if the "register" vari- +ables were actually assigned to registers, and some other diff- +erences if they were not. Specifically, if we had N variables +specified as "register" of which the first n were actually ass- +igned to registers, we would expect the sequence of differences +to consist of a number of occurrences of some number, followed by +N-n occurrences of some other number, followed by several occurr- +ences of the first number. If we get a sequence like this, we can +determine, by simple subtraction, how many (if any) variables are +being assigned to registers. If we get some other sequence, we know +that the test is invalid. */ + + + int r00; + int r01; + int r02; + int r03; + register int r04; + int r05; + register int r06; + int r07; + register int r08; + int r09; + register int r10; + int r11; + register int r12; + int r13; + register int r14; + int r15; + register int r16; + int r17; + register int r18; + int r19; + register int r20; + int r21; + register int r22; + int r23; + register int r24; + int r25; + register int r26; + int r27; + register int r28; + int r29; + register int r30; + int r31; + register int r32; + int r33; + register int r34; + int r35; + int r36; + int r37; + int r38; + + int s, n1, n2, nr, j, d[22]; + + r00 = 0; + r01 = 1; + r02 = 2; + r03 = 3; + r04 = 4; + r05 = 5; + r06 = 6; + r07 = 7; + r08 = 8; + r09 = 9; + r10 = 10; + r11 = 11; + r12 = 12; + r13 = 13; + r14 = 14; + r15 = 15; + r16 = 16; + r17 = 17; + r18 = 18; + r19 = 19; + r20 = 20; + r21 = 21; + r22 = 22; + r23 = 23; + r24 = 24; + r25 = 25; + r26 = 26; + r27 = 27; + r28 = 28; + r29 = 29; + r30 = 30; + r31 = 31; + r32 = 32; + r33 = 33; + r34 = 34; + r35 = 35; + r36 = 36; + r37 = 37; + r38 = 38; + + d[0] = &r01 - &r00; + d[1] = &r02 - &r01; + d[2] = &r03 - &r02; + d[3] = &r05 - &r03; + d[4] = &r07 - &r05; + d[5] = &r09 - &r07; + d[6] = &r11 - &r09; + d[7] = &r13 - &r11; + d[8] = &r15 - &r13; + d[9] = &r17 - &r15; + d[10] = &r19 - &r17; + d[11] = &r21 - &r19; + d[12] = &r23 - &r21; + d[13] = &r25 - &r23; + d[14] = &r27 - &r25; + d[15] = &r29 - &r27; + d[16] = &r31 - &r29; + d[17] = &r33 - &r31; + d[18] = &r35 - &r33; + d[19] = &r36 - &r35; + d[20] = &r37 - &r36; + d[21] = &r38 - &r37; + + +/* The following FSM analyzes the string of differences. It accepts +strings of the form a+b+a+ and returns 16 minus the number of bs, +which is the number of variables that actually got into registers. +Otherwise it signals rejection by returning -1., indicating that the +test is unreliable. */ + + n1 = d[0]; + s = 1; + + for (j=0; j<22; j++) + switch (s) { + case 1: if (d[j] != n1) { + n2 = d[j]; + s = 2; + nr = 1; + } + break; + case 2: if (d[j] == n1) { + s = 3; + break; + } + if (d[j] == n2) { + nr = nr+1; + break; + } + s = 4; + break; + case 3: if (d[j] != n1) s = 4; + break; + } + ; + + if (s == 3) return 16-nr; + else return -1; +} +regp() { /* pointer to register assignment */ +/* Testing a variable whose storage class has been spec- +ified as "register" is somewhat tricky, but it can be done in a +fairly reliable fashion by taking advantage of our knowledge of the +ways in which compilers operate. If we declare a collection of vari- +ables of the same storage class, we would expect that, when storage +for these variables is actually allocated, the variables will be +bunched together and ordered according to one of the following +criteria: + + (a) the order in which they were defined. + (b) the order in which they are used. + (c) alphabetically. + (d) the order in which they appear in the compiler's + symbol table. + (e) some other way. + + Hence, if we define a sequence of variables in close alpha- +betical order, and use them in the same order in which we define +them, we would expect the differences between the addresses of +successive variables to be constant, except in case (d) where the +symbol table is a hash table, or in case (e). If a subsequence in +the middle of this sequence is selected, and for this subsequence, +every other variable is specified to be "register", and address +differences are taken between adjacent nonregister variables, we would +still expect to find constant differences if the "register" vari- +ables were actually assigned to registers, and some other diff- +erences if they were not. Specifically, if we had N variables +specified as "register" of which the first n were actually ass- +igned to registers, we would expect the sequence of differences +to consist of a number of occurrences of some number, followed by +N-n occurrences of some other number, followed by several occurr- +ences of the first number. If we get a sequence like this, we can +determine, by simple subtraction, how many (if any) variables are +being assigned to registers. If we get some other sequence, we know +that the test is invalid. */ + + + int *r00; + int *r01; + int *r02; + int *r03; + register int *r04; + int *r05; + register int *r06; + int *r07; + register int *r08; + int *r09; + register int *r10; + int *r11; + register int *r12; + int *r13; + register int *r14; + int *r15; + register int *r16; + int *r17; + register int *r18; + int *r19; + register int *r20; + int *r21; + register int *r22; + int *r23; + register int *r24; + int *r25; + register int *r26; + int *r27; + register int *r28; + int *r29; + register int *r30; + int *r31; + register int *r32; + int *r33; + register int *r34; + int *r35; + int *r36; + int *r37; + int *r38; + + int s, n1, n2, nr, j, d[22]; + + r00 = (int *)&r00; + r01 = (int *)&r01; + r02 = (int *)&r02; + r03 = (int *)&r03; + r04 = (int *)&r05; + r05 = (int *)&r05; + r06 = (int *)&r07; + r07 = (int *)&r07; + r08 = (int *)&r09; + r09 = (int *)&r09; + r10 = (int *)&r11; + r11 = (int *)&r11; + r12 = (int *)&r13; + r13 = (int *)&r13; + r14 = (int *)&r15; + r15 = (int *)&r15; + r16 = (int *)&r17; + r17 = (int *)&r17; + r18 = (int *)&r19; + r19 = (int *)&r19; + r20 = (int *)&r21; + r21 = (int *)&r21; + r22 = (int *)&r23; + r23 = (int *)&r23; + r24 = (int *)&r25; + r25 = (int *)&r25; + r26 = (int *)&r27; + r27 = (int *)&r27; + r28 = (int *)&r29; + r29 = (int *)&r29; + r30 = (int *)&r31; + r31 = (int *)&r31; + r32 = (int *)&r33; + r33 = (int *)&r33; + r34 = (int *)&r35; + r35 = (int *)&r35; + r36 = (int *)&r36; + r37 = (int *)&r37; + r38 = (int *)&r38; + + d[0] = &r01 - &r00; + d[1] = &r02 - &r01; + d[2] = &r03 - &r02; + d[3] = &r05 - &r03; + d[4] = &r07 - &r05; + d[5] = &r09 - &r07; + d[6] = &r11 - &r09; + d[7] = &r13 - &r11; + d[8] = &r15 - &r13; + d[9] = &r17 - &r15; + d[10] = &r19 - &r17; + d[11] = &r21 - &r19; + d[12] = &r23 - &r21; + d[13] = &r25 - &r23; + d[14] = &r27 - &r25; + d[15] = &r29 - &r27; + d[16] = &r31 - &r29; + d[17] = &r33 - &r31; + d[18] = &r35 - &r33; + d[19] = &r36 - &r35; + d[20] = &r37 - &r36; + d[21] = &r38 - &r37; + + +/* The following FSM analyzes the string of differences. It accepts +strings of the form a+b+a+ and returns 16 minus the number of bs, +which is the number of variables that actually got into registers. +Otherwise it signals rejection by returning -1., indicating that the +test is unreliable. */ + + n1 = d[0]; + s = 1; + for (j=0; j<22; j++) + switch (s) { + case 1: if (d[j] != n1) { + n2 = d[j]; + s = 2; + nr = 1; + } + break; + case 2: if (d[j] == n1) { + s = 3; + break; + } + if (d[j] == n2) { + nr = nr+1; + break; + } + s = 4; + break; + case 3: if (d[j] != n1) s = 4; + break; + } + ; + + if (s == 3) return 16-nr; + else return -1; +} +s84(pd0) /* 8.4 Meaning of declarators */ +struct defs *pd0; +{ + int *ip, i, *fip(), (*pfi)(), j, k, array(), glork(int); + static int x3d[3][5][7]; + float fa[17], *afp[17], sum; + static char s84er[] = "s84,er%d\n"; + static char qs84[8] = "s84 "; + int rc; + char *ps, *pt; + ps = qs84; + pt = pd0->rfs; + rc = 0; + while (*pt++ = *ps++); + + /* The more common varieties of declarators have al- + ready been touched upon, some more than others. It + is useful to compare *fip() and (*pfi)(). + */ + + ip = fip(3); + if(*ip != 3){ + if(pd0->flgd != 0) printf(s84er,1); + rc = rc+1; + } + + pfi = glork; + if((*pfi)(4) != 4){ + if(pd0->flgd != 0) printf(s84er,2); + rc = rc+2; + } + + /* Float fa[17] declares an array of floating point + numbers, and *afp[17] declares an array of pointers + to floats. + */ + + for(j=0; j<17; j++){ + fa[j] = j; + afp[j] = &fa[j]; + } + + sum = 0.; + for(j=0; j<17; j++) sum += *afp[j]; + if(sum != 136){ + if(pd0->flgd != 0) printf(s84er,4); + rc = rc+4; + } + + /* static int x3d[3][5][7] declares a static three + dimensional array of integers, with rank 3x5x7. + In complete detail, x3d is an array of three items; + each item is an array of five arrays, and each of + the latter arrays is an array of seven integers. + Any of the expressions x3d, x3d[i], x3d[i][j], + and x3d[i][j][k] may reasonably appear in an express- + ion. The first three have type "array"; the last has + type int. + */ + + for (i=0; i<3; i++) + for (j=0; j<5; j++) + for (k=0; k<7; k++) + x3d[i][j][k] = i*35+j*7+k; + + i = 1; j = 2; k = 3; + + if( array(x3d,105,0) + +array(x3d[i],35,35) + +array(x3d[i][j],7,49) + + x3d[i][j][k]-52){ + + if(pd0->flgd != 0) printf(s84er,8); + rc = rc+8; + } + + return rc; +} +array(a,size,start) +int a[], size, start; +{ + int i; + for(i=0; irfs; + rc = 0; + while (*pt++ = *ps++); + + /* Within a structure, the objects declared have + addresses which increase as their declarations are + read left to right. + */ + + if( (char *)&s1.count - &s1.tword[0] <= 0 + ||(char *)&s1.left - (char *)&s1.count <= 0 + ||(char *)&s1.right - (char *)&s1.left <= 0){ + if(pd0->flgd != 0) printf(s85er,1); + rc = rc+1; + } + + /* Each non-field member of a structure begins on an + addressing boundary appropriate to its type. + */ + + diff[0] = &sc.c - &sc.cdummy; + diff[1] = (char *)&ss.s - &ss.cdummy; + diff[2] = (char *)&si.i - &si.cdummy; + diff[3] = (char *)&sl.l - &sl.cdummy; + diff[4] = (char *)&su.u - &su.cdummy; + diff[5] = (char *)&sf.f - &sf.cdummy; + diff[6] = (char *)&sd.d - &sd.cdummy; + + if(pd0->flgm != 0) + for(j=0; j<7; j++) + printf("%s%s%d\n",type[j],aln,diff[j]); + + /* Field specifications are highly implementation de- + pendent. About the only thing we can do here is to + check is that the compiler accepts the field constructs, + and that they seem to work, after a fashion, at + run time... + */ + + s3.threebit = 7; + s3.twobit = s3.threebit; + s3.threebit = s3.twobit; + + if(s3.threebit != 3){ + if(s3.threebit == -1){ + if(pd0->flgm != 0) printf("Sign extension in fields\n"); + } + else{ + if(pd0->flgd != 0) printf(s85er,2); + rc = rc+2; + } + } + + s3.onebit = 1; + if(s3.onebit != 1){ + if(pd0->flgm != 0) + printf("Be especially careful with 1-bit fields!\n"); + } + + /* A union may be thought of as a structure all of whose + members begin at offset 0 and whose size is sufficient + to contain any of its members. + */ + + if( (char *)u0.u1 - (char *)&u0 != 0 + ||(char *)u0.u2 - (char *)&u0 != 0 + ||(char *)u0.u3 - (char *)&u0 != 0 + ||(char *)u0.u4 - (char *)&u0 != 0 + ||(char *)u0.u5 - (char *)&u0 != 0 + ||(char *)u0.u6 - (char *)&u0 != 0 + ||(char *)u0.u7 - (char *)&u0 != 0){ + + if(pd0->flgd != 0) printf(s85er,4); + rc = rc+4; + } + + if( sizeof u0 < sizeof u0.u1 + ||sizeof u0 < sizeof u0.u2 + ||sizeof u0 < sizeof u0.u3 + ||sizeof u0 < sizeof u0.u4 + ||sizeof u0 < sizeof u0.u5 + ||sizeof u0 < sizeof u0.u6 + ||sizeof u0 < sizeof u0.u7){ + + if(pd0->flgd != 0) printf(s85er,8); + rc = rc+8; + } + + /* Finally, we check that the pointers work. */ + + s1.right = &s2; + s2.tword[0] = 2; + s1.right->tword[0] += 1; + if(s2.tword[0] != 3){ + if(pd0->flgd != 0) printf(s85er,16); + rc = rc+16; + } + return rc; +} +s86(pd0) /* 8.6 Initialization */ +struct defs *pd0; +{ + static char s86er[] = "s86,er%d\n"; + static char qs86[8] = "s86 "; + int lrc, rc; + char *ps, *pt; + int one(), i, j, k; + static int x[] = {1,3,5}; + static int *pint = x+2; + static int zero[10]; + int *apint = pint-1; + register int *rpint = apint+one(); + static float y0[] = {1,3,5,2,4,6,3,5,7,0,0,0}; + static float y1[4][3] = { + {1,3,5}, + {2,4,6}, + {3,5,7}, + }; + static float y2[4][3] = {1,3,5,2,4,6,3,5,7}; + static float y3[4][3] = { + {1},{2},{3},{4} + }; + ps = qs86; + pt = pd0->rfs; + rc = 0; + while (*pt++ = *ps++); + + /* The expression in an initializer for a static or + external variable must be a constant expression or + an expression that reduces to the address of a pre- + viously declared variable, possibly offset by a + constant expression. + */ + + if(*pint != 5){ + if(pd0->flgd != 0) printf(s86er,1); + rc = rc+1; + } + + /* Automatic and register variables may be initialized + by arbitrary expressions involving constants and previously + declared variables and functions. + */ + + if(*apint != 3){ + if(pd0->flgd != 0) printf(s86er,2); + rc = rc+2; + } + + if(*rpint != 5){ + if(pd0->flgd != 0) printf(s86er,4); + rc = rc+4; + } + + /* Static variables that are not initialized are guar- + anteed to start off as zero. + */ + + lrc = 0; + for(j=0; j<10; j++) + if(zero[j] != 0) lrc = 1; + if(lrc != 0){ + if(pd0->flgd != 0) printf(s86er,8); + rc = rc+8; + } + + /* y0, y1, and y2, as declared, should define and + initialize identical arrays. + */ + lrc = 0; + for(i=0; i<4; i++) + for(j=0; j<3; j++){ + k = 3*i+j; + if( y1[i][j] != y2[i][j] + ||y1[i][j] != y0[k]) lrc = 1; + } + + if(lrc != 0){ + if(pd0->flgd != 0) printf(s86er,16); + rc = rc+16; + } + + /* y3 initializes the first column of the array and + leaves the rest zero. + */ + + lrc = 0; + for(j=0; j<4; j++) if(y3[j][0] != j+1) lrc = 1; + + if(lrc != 0){ + if(pd0->flgd != 0) printf(s86er,32); + rc = rc+32; + } + return rc; +} +one(){ + return 1; +} +int *metricp; +s88(pd0) /* 8.8 Typedef */ +struct defs *pd0; +{ + static char s88er[] = "s88,er%d\n"; + static char qs88[8] = "s88 "; + int rc; + char *ps, *pt; + + /* Declarations whose "storage class" is typdef do not + define storage, but instead define identifiers which + can later be used as if they were type keywords naming + fundamental or derived types. + */ + + typedef int MILES, *KLICKSP; + typedef struct {double re, im;} complex; + + MILES distance; + extern KLICKSP metricp; + complex z, *zp; + + ps = qs88; + pt = pd0->rfs; + rc = 0; + while(*pt++ = *ps++); + + /* Hopefully, all of this stuff will compile. After that, + we can only make some superficial tests. + + The type of distance is int, + */ + + if(sizeof distance != sizeof(int)){ + if(pd0->flgd != 0) printf(s88er,1); + rc = rc+1; + } + + /* that of metricp is "pointer to int", */ + + metricp = &distance; + distance = 2; + *metricp = 3; + + if(distance != 3){ + if(pd0->flgd != 0) printf(s88er,2); + rc = rc+2; + } + + /* and that of z is the specified structure. zp is a + pointer to such a structure. + */ + + z.re = 0.; + z.im = 0.; + zp = &z; + zp->re = 1.; + zp->im = 1.; + if(z.re+z.im != 2.){ + if(pd0->flgd != 0) printf(s88er,4); + rc = rc+4; + } + + return rc; +} +s9(pd0) /* 9 Statements */ +struct defs *pd0; +{ + static char s9er[] = "s9,er%d\n"; + static char qs9[8] = "s9 "; + int rc; + char *ps, *pt; + int lrc, i; + + ps = qs9; + pt = pd0->rfs; + rc = 0; + while (*pt++ = *ps++); + + /* One would think that the section on statements would + provide the most variety in the entire sequence of tests. + As it turns out, most of the material in this section has + already been checked in the process of checking out + everything else, and the section at this point is somewhat + anticlimactic. For this reason, we restrict ourselves + to testing two features not already covered. + + Compound statements are delimited by braces. They have the + nice property that identifiers of the auto and register + variety are pushed and popped. It is currently legal to + transfer into a block, but we wont... + */ + + lrc = 0; + for(i=0; i<2; i++){ + int j; + register int k; + j = k = 2; + { + int j; + register int k; + j = k = 3; + if((j != 3) || (k != 3)) lrc = 1; + } + if((j != 2) || (k != 2)) lrc = 1; + } + + if(lrc != 0){ + if(pd0->flgd != 0) printf(s9er,1); + rc = rc+1; + } + + /* Goto statements go to labeled statements, we hope. */ + + goto nobarf; + if(pd0->flgd != 0) printf(s9er,2); + rc = rc+2; + nobarf:; + + return rc; +} +setev(){ /* Sets an external variable. Used */ + extern int extvar; /* by s4, and should be compiled */ + extvar = 1066; /* separately from s4. */ +} + int lbits; /* long */ + int ubits; /* unsigned */ + int fbits; /* float */ + int dbits; /* double */ + float fprec; /* Smallest number that can be */ + float dprec; /* significantly added to 1. */ + int flgs; /* Print return codes, by section */ + int flgm; /* Announce machine dependencies */ + int flgd; /* give explicit diagnostics */ + int flgl; /* Report local return codes. */ + int rrc; /* recent return code */ + int crc; /* Cumulative return code */ + char rfs[8]; /* Return from section */ diff --git a/src/cmd/lccom/tst/cvt.0 b/src/cmd/lccom/tst/cvt.0 new file mode 100644 index 0000000..e69de29 diff --git a/src/cmd/lccom/tst/cvt.c b/src/cmd/lccom/tst/cvt.c new file mode 100644 index 0000000..c2fa515 --- /dev/null +++ b/src/cmd/lccom/tst/cvt.c @@ -0,0 +1,35 @@ +signed char c; +signed short s; +signed int i; +signed long int l; +unsigned char C; +unsigned short S; +unsigned int I; +unsigned long int L; +float f; +double d; +long double D; +void *p; +void (*P)(void); + +void print(void) { + printf("%d %d %d %ld %u %u %u %lu %f %f %lf\n",c,s,i,l,C,S,I,L,f,d,D); +} + +main() { + c= 1; s=c;i=c;l=c;C=c;S=c;I=c;L=c;f=c;d=c;D=c; print(); + s= 2; c=s; i=s;l=s;C=s;S=s;I=s;L=s;f=s;d=s;D=s; print(); + i= 3; c=i;s=i; l=i;C=i;S=i;I=i;L=i;f=i;d=i;D=i; print(); + l= 4; c=l;s=l;i=l; C=l;S=l;I=l;L=l;f=l;d=l;D=l; print(); + C= 5; c=C;s=C;i=C;l=C; S=C;I=C;L=C;f=C;d=C;D=C; print(); + S= 6; c=S;s=S;i=S;l=S;C=S; I=S;L=S;f=S;d=S;D=S; print(); + I= 7; c=I;s=I;i=I;l=I;C=I;S=I; L=I;f=I;d=I;D=I; print(); + L= 8; c=L;s=L;i=L;l=L;C=L;S=L;I=S; f=L;d=L;D=L; print(); + f= 9; c=f;s=f;i=f;l=f;C=f;S=f;I=f;L=f; d=f;D=f; print(); + d=10; c=d;s=d;i=d;l=d;C=d;S=d;I=d;L=d;f=d; D=d; print(); + D=11; c=D;s=D;i=D;l=D;C=D;S=D;I=D;L=D;f=D;d=D; print(); + + p=0; p=0L; p=0U; p=0UL; p=P; + P=0; P=0L; P=0U; P=0UL; P=p; + return 0; +} diff --git a/src/cmd/lccom/tst/fields.0 b/src/cmd/lccom/tst/fields.0 new file mode 100644 index 0000000..e69de29 diff --git a/src/cmd/lccom/tst/fields.c b/src/cmd/lccom/tst/fields.c new file mode 100644 index 0000000..242a53b --- /dev/null +++ b/src/cmd/lccom/tst/fields.c @@ -0,0 +1,34 @@ +struct foo { + int a; + char b; + int x : 12, y : 4, : 0, : 4, z : 3; + char c; +} x = { 1, 2, 3, 4, 5, 6 }; +int i = 16; +struct baz { unsigned int a:2, b:4, c:32;} y = { 7, 8, 9}; + +main() +{ + printf("x = %d %d %d %d %d %d\n", x.a, x.b, x.x, x.y, x.z, x.c); + printf("y = %d %d %d\n", y.a, y.b, y.c); + x.y = i; + x.z = 070; + printf("x = %d %d %d %d %d %d\n", x.a, x.b, x.x, x.y, x.z, x.c); + y.a = 2; + y.c = i; + printf("y = %d %d %d\n", y.a, y.b, y.c); + f2(&x); + return 0; +} + +f1(struct baz *p) { + p->a = p->b = 0; + if (p->b) + printf("p->b != 0!\n"); + p->a = 0x3; p->b = 0xf; + printf("p->a = 0x%x, p->b = 0x%x\n", p->a, p->b); +} +f2(struct baz *p) { + p->a = (i==0); + p->b = (f1(p),0); +} diff --git a/src/cmd/lccom/tst/front.0 b/src/cmd/lccom/tst/front.0 new file mode 100644 index 0000000..e69de29 diff --git a/src/cmd/lccom/tst/front.c b/src/cmd/lccom/tst/front.c new file mode 100644 index 0000000..13125cf --- /dev/null +++ b/src/cmd/lccom/tst/front.c @@ -0,0 +1,120 @@ +main() { + exit(0); +} + +nested(a,b) { + if ((a<4 && b == 'r') + || (a == 1 && (b == 'h' || b == 'i')) + || (a == 2 && (b == 'o' || b == 'y')) + ) a=b; +} + +/* type name scope */ + +void s(struct D *d) {} /* this struct D differs from the one below */ +typedef struct D D; +struct D {int x, y;} Dy={0}; +D Dz={1}; +Dfunc(){ + D a; a.y=1; + s(&Dy); /* error */ +} + +/* qualifiers */ + +const a; int b; +const int a, *x; int b, *y; +volatile unsigned z; + +f() { + x = y; + z = z + z; /* should be 2 references to z's r-value */ +} +f1() { + x = &a; + x = &b; + y = &a; /* error */ + y = &b; +} +f2(int **a, int **b) { + f(&x, &y); + **a = 0; + return **b; +} +g(const int *p) { + g(&a); + g(&b); + return *p; +} +h(int *p) { + f(&a); + f(&b); + return *p; +} +h1(const int x, int y) { + h1(a,b); + h1(b,a); + return x + y; +} +h2() { + char *b; const void *p; + p = b; + b = p; /* error */ +} + + +/* static naming */ + +extern int yy; set1() { { static yy=1; yy=2;} yy=4;} +static int yy; set2() { yy=5; {static yy=2; yy=3; }} +static void goo() {} +sss() { int goo; { static int goo();} goo=1;} +rrr(p) float *p; { extern int xr; + { static float xr; + { extern int *xr; } p=&xr; }} + +/* local extern */ + +static int ss1; +int ss3; +extern int ss5; +setstatic() { extern int ss1,ss2,ss3,ss4; ss1 = ss2; ss3 = ss4; ss5 = 0;} +static int ss2; +int ss4; +static int ss5; + +/* function prototypes */ + +int fx1(void); +int fx1(); + +int gx1(double x); +int gx1(x) double x; { gx1(&x); } /* error */ + +int hx1(); +int hx1(double x,...); /* error */ + +int ff1(double x, int *y); +int ff1(x,y) float x; int y[]; {x=y[0];} + +int gg1(int a); +int gg1(a,b){a=b;} + +int hh1(const int x); +hh1(a) {return a;} + +extern int strcmp(const char*, const char*); +extern void qsort(void*, int, int, int (*)(const void*, const void*)); +extern int cmp(char**a, char**b) { return strcmp(*a,*b); } +sort() { + int n; char *a[100]; + qsort(a, n, sizeof(char*), (int (*)(const void*, const void*))cmp); + qsort(a, n, sizeof(char*), cmp); /* error */ +} + +/* nasty calls */ + +onearg(){ + int a,b,c,d; + f( ( (a? (b = 1): (c = 2)), (d ? 3 : 4) ) ); /* 1 argument */ +} diff --git a/src/cmd/lccom/tst/incr.0 b/src/cmd/lccom/tst/incr.0 new file mode 100644 index 0000000..e69de29 diff --git a/src/cmd/lccom/tst/incr.c b/src/cmd/lccom/tst/incr.c new file mode 100644 index 0000000..7af89c6 --- /dev/null +++ b/src/cmd/lccom/tst/incr.c @@ -0,0 +1,39 @@ +main() {} + +memchar() { + char x, *p; + + &x, &p; + x = *p++; + x = *++p; + x = *p--; + x = *--p; +} + +memint() { + int x, *p; + + &x, &p; + x = *p++; + x = *++p; + x = *p--; + x = *--p; +} + +regchar() { + register char x, *p; + + x = *p++; + x = *++p; + x = *p--; + x = *--p; +} + +regint() { + register int x, *p; + + x = *p++; + x = *++p; + x = *p--; + x = *--p; +} diff --git a/src/cmd/lccom/tst/init.0 b/src/cmd/lccom/tst/init.0 new file mode 100644 index 0000000..e69de29 diff --git a/src/cmd/lccom/tst/init.c b/src/cmd/lccom/tst/init.c new file mode 100644 index 0000000..55cece3 --- /dev/null +++ b/src/cmd/lccom/tst/init.c @@ -0,0 +1,59 @@ + +typedef struct { int codes[3]; char name[6]; } Word; + +Word words[] = { + 1, 2, 3, "if", + { { 4, 5 }, { 'f', 'o', 'r' } }, + 6, 7, 8, {"else"}, + { { 9, 10, 11,}, 'w', 'h', 'i', 'l', 'e', }, + { 0 }, +}, *wordlist = words; + +int x[][5] = { 1, 2, 3, 4, 0, { 5, 6 }, { 7 } }; +int *y[] = { x[0], x[1], x[2], 0 }; + + +main() +{ + int i, j; + + for (i = 0; y[i]; i++) { + for (j = 0; y[i][j]; j++) + printf(" %d", y[i][j]); + printf("\n"); + } + f(); + g(wordlist); + return 0; +} + +f() { + static char *keywords[] = {"if", "for", "else", "while", 0, }; + char **p; + + for (p = keywords; *p; p++) + printf("%s\n", *p); +} + +g(p) +Word *p; +{ + int i; + + for ( ; p->codes[0]; p++) { + for (i = 0; i < sizeof p->codes/sizeof(p->codes[0]); i++) + printf("%d ", p->codes[i]); + printf("%s\n", p->name); + } + h(); +} + +h() +{ + int i; + + for (i = 0; i < sizeof(words)/sizeof(Word); i++) + printf("%d %d %d %s\n", words[i].codes[0], + words[i].codes[1], words[i].codes[2], + &words[i].name[0]); +} diff --git a/src/cmd/lccom/tst/limits.0 b/src/cmd/lccom/tst/limits.0 new file mode 100644 index 0000000..e69de29 diff --git a/src/cmd/lccom/tst/limits.c b/src/cmd/lccom/tst/limits.c new file mode 100644 index 0000000..e2a13a6 --- /dev/null +++ b/src/cmd/lccom/tst/limits.c @@ -0,0 +1,19 @@ +#include + +main() { + printf("UCHAR_MAX: %08x=%d\n", UCHAR_MAX, UCHAR_MAX); + printf("USHRT_MAX: %08x=%d\n", USHRT_MAX, USHRT_MAX); + printf("UINT_MAX: %08x=%d\n", UINT_MAX, UINT_MAX); + printf("ULONG_MAX: %08lx=%ld\n", ULONG_MAX, ULONG_MAX); + printf("CHAR_MAX: %08x=%d\n", CHAR_MAX, CHAR_MAX); + printf("SCHAR_MAX: %08x=%d\n", SCHAR_MAX, SCHAR_MAX); + printf("SHRT_MAX: %08x=%d\n", SHRT_MAX, SHRT_MAX); + printf("INT_MAX: %08x=%d\n", INT_MAX, INT_MAX); + printf("LONG_MAX: %08lx=%ld\n", LONG_MAX, LONG_MAX); + printf("CHAR_MIN: %08x=%d\n", CHAR_MIN, CHAR_MIN); + printf("SCHAR_MIN: %08x=%d\n", SCHAR_MIN, SCHAR_MIN); + printf("SHRT_MIN: %08x=%d\n", SHRT_MIN, SHRT_MIN); + printf("INT_MIN: %08x=%d\n", INT_MIN, INT_MIN); + printf("LONG_MIN: %08lx=%ld\n", LONG_MIN, LONG_MIN); + return 0; +} diff --git a/src/cmd/lccom/tst/mips-eb/8q.1bk b/src/cmd/lccom/tst/mips-eb/8q.1bk new file mode 100644 index 0000000..7ed6437 --- /dev/null +++ b/src/cmd/lccom/tst/mips-eb/8q.1bk @@ -0,0 +1,92 @@ +1 5 8 6 3 7 2 4 +1 6 8 3 7 4 2 5 +1 7 4 6 8 2 5 3 +1 7 5 8 2 4 6 3 +2 4 6 8 3 1 7 5 +2 5 7 1 3 8 6 4 +2 5 7 4 1 8 6 3 +2 6 1 7 4 8 3 5 +2 6 8 3 1 4 7 5 +2 7 3 6 8 5 1 4 +2 7 5 8 1 4 6 3 +2 8 6 1 3 5 7 4 +3 1 7 5 8 2 4 6 +3 5 2 8 1 7 4 6 +3 5 2 8 6 4 7 1 +3 5 7 1 4 2 8 6 +3 5 8 4 1 7 2 6 +3 6 2 5 8 1 7 4 +3 6 2 7 1 4 8 5 +3 6 2 7 5 1 8 4 +3 6 4 1 8 5 7 2 +3 6 4 2 8 5 7 1 +3 6 8 1 4 7 5 2 +3 6 8 1 5 7 2 4 +3 6 8 2 4 1 7 5 +3 7 2 8 5 1 4 6 +3 7 2 8 6 4 1 5 +3 8 4 7 1 6 2 5 +4 1 5 8 2 7 3 6 +4 1 5 8 6 3 7 2 +4 2 5 8 6 1 3 7 +4 2 7 3 6 8 1 5 +4 2 7 3 6 8 5 1 +4 2 7 5 1 8 6 3 +4 2 8 5 7 1 3 6 +4 2 8 6 1 3 5 7 +4 6 1 5 2 8 3 7 +4 6 8 2 7 1 3 5 +4 6 8 3 1 7 5 2 +4 7 1 8 5 2 6 3 +4 7 3 8 2 5 1 6 +4 7 5 2 6 1 3 8 +4 7 5 3 1 6 8 2 +4 8 1 3 6 2 7 5 +4 8 1 5 7 2 6 3 +4 8 5 3 1 7 2 6 +5 1 4 6 8 2 7 3 +5 1 8 4 2 7 3 6 +5 1 8 6 3 7 2 4 +5 2 4 6 8 3 1 7 +5 2 4 7 3 8 6 1 +5 2 6 1 7 4 8 3 +5 2 8 1 4 7 3 6 +5 3 1 6 8 2 4 7 +5 3 1 7 2 8 6 4 +5 3 8 4 7 1 6 2 +5 7 1 3 8 6 4 2 +5 7 1 4 2 8 6 3 +5 7 2 4 8 1 3 6 +5 7 2 6 3 1 4 8 +5 7 2 6 3 1 8 4 +5 7 4 1 3 8 6 2 +5 8 4 1 3 6 2 7 +5 8 4 1 7 2 6 3 +6 1 5 2 8 3 7 4 +6 2 7 1 3 5 8 4 +6 2 7 1 4 8 5 3 +6 3 1 7 5 8 2 4 +6 3 1 8 4 2 7 5 +6 3 1 8 5 2 4 7 +6 3 5 7 1 4 2 8 +6 3 5 8 1 4 2 7 +6 3 7 2 4 8 1 5 +6 3 7 2 8 5 1 4 +6 3 7 4 1 8 2 5 +6 4 1 5 8 2 7 3 +6 4 2 8 5 7 1 3 +6 4 7 1 3 5 2 8 +6 4 7 1 8 2 5 3 +6 8 2 4 1 7 5 3 +7 1 3 8 6 4 2 5 +7 2 4 1 8 5 3 6 +7 2 6 3 1 4 8 5 +7 3 1 6 8 5 2 4 +7 3 8 2 5 1 6 4 +7 4 2 5 8 1 3 6 +7 4 2 8 6 1 3 5 +7 5 3 1 6 8 2 4 +8 2 4 1 7 5 3 6 +8 2 5 3 1 7 4 6 +8 3 1 6 2 5 7 4 +8 4 1 3 6 2 7 5 diff --git a/src/cmd/lccom/tst/mips-eb/8q.2bk b/src/cmd/lccom/tst/mips-eb/8q.2bk new file mode 100644 index 0000000..d4dc0ed --- /dev/null +++ b/src/cmd/lccom/tst/mips-eb/8q.2bk @@ -0,0 +1,2 @@ +tst/8q.c:30: warning: missing return value +tst/8q.c:39: warning: missing return value diff --git a/src/cmd/lccom/tst/mips-eb/8q.sbk b/src/cmd/lccom/tst/mips-eb/8q.sbk new file mode 100644 index 0000000..9e5d75f --- /dev/null +++ b/src/cmd/lccom/tst/mips-eb/8q.sbk @@ -0,0 +1,169 @@ +.set reorder +.globl main +.text +.text +.align 2 +.ent main +main: +.frame $sp,32,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-32 +.mask 0xc2000000,-8 +.cprestore 16 +sw $30,20($sp) +sw $31,24($sp) +move $30,$0 +L.2: +sll $24,$30,2 +la $15,1 +sw $15,down($24) +sw $15,up($24) +L.3: +la $30,1($30) +la $24,15 +blt $30,$24,L.2 +move $30,$0 +L.6: +sll $24,$30,2 +la $15,1 +sw $15,rows($24) +L.7: +la $30,1($30) +la $24,8 +blt $30,$24,L.6 +move $4,$0 +jal queens +move $2,$0 +L.1: +lw $25,16($sp) +lw $30,20($sp) +lw $31,24($sp) +addu $sp,$sp,32 +j $31 +.end main +.globl queens +.text +.align 2 +.ent queens +queens: +.frame $sp,32,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-32 +.mask 0xc2800000,-4 +sw $23,16($sp) +.cprestore 20 +sw $30,24($sp) +sw $31,28($sp) +move $30,$4 +move $23,$0 +L.11: +sll $15,$23,2 +lw $15,rows($15) +beq $15,$0,L.15 +subu $15,$23,$30 +sll $15,$15,2 +lw $15,up+28($15) +beq $15,$0,L.15 +addu $15,$23,$30 +sll $15,$15,2 +lw $15,down($15) +beq $15,$0,L.15 +addu $15,$23,$30 +sll $15,$15,2 +sw $0,down($15) +subu $15,$23,$30 +sll $15,$15,2 +sw $0,up+28($15) +sll $15,$23,2 +sw $0,rows($15) +sll $24,$30,2 +sw $23,x($24) +la $24,7 +bne $30,$24,L.19 +jal print +b L.20 +L.19: +la $4,1($30) +jal queens +L.20: +la $24,1 +addu $15,$23,$30 +sll $15,$15,2 +sw $24,down($15) +subu $15,$23,$30 +sll $15,$15,2 +sw $24,up+28($15) +sll $15,$23,2 +sw $24,rows($15) +L.15: +L.12: +la $23,1($23) +la $24,8 +blt $23,$24,L.11 +move $2,$0 +L.10: +lw $23,16($sp) +lw $25,20($sp) +lw $30,24($sp) +lw $31,28($sp) +addu $sp,$sp,32 +j $31 +.end queens +.globl print +.text +.align 2 +.ent print +print: +.frame $sp,32,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-32 +.mask 0xc2000000,-8 +.cprestore 16 +sw $30,20($sp) +sw $31,24($sp) +move $30,$0 +L.23: +la $4,L.27 +sll $24,$30,2 +lw $24,x($24) +la $5,49($24) +jal printf +L.24: +la $30,1($30) +la $24,8 +blt $30,$24,L.23 +la $4,L.28 +jal printf +move $2,$0 +L.22: +lw $25,16($sp) +lw $30,20($sp) +lw $31,24($sp) +addu $sp,$sp,32 +j $31 +.end print +.globl x +.comm x,32 +.globl rows +.comm rows,32 +.globl down +.comm down,60 +.globl up +.comm up,60 +.rdata +.align 0 +L.28: +.byte 10 +.byte 0 +.align 0 +L.27: +.byte 37 +.byte 99 +.byte 32 +.byte 0 diff --git a/src/cmd/lccom/tst/mips-eb/array.1bk b/src/cmd/lccom/tst/mips-eb/array.1bk new file mode 100644 index 0000000..4d3817c --- /dev/null +++ b/src/cmd/lccom/tst/mips-eb/array.1bk @@ -0,0 +1,4 @@ + 0 1 2 3 1000 1001 1002 1003 2000 2001 2002 2003 + 0 1 2 3 1000 1001 1002 1003 2000 2001 2002 2003 + 0 1 2 3 1000 1001 1002 1003 2000 2001 2002 2003 + 0 1 2 3 1000 1001 1002 1003 2000 2001 2002 2003 diff --git a/src/cmd/lccom/tst/mips-eb/array.2bk b/src/cmd/lccom/tst/mips-eb/array.2bk new file mode 100644 index 0000000..c8cf31e --- /dev/null +++ b/src/cmd/lccom/tst/mips-eb/array.2bk @@ -0,0 +1,2 @@ +tst/array.c:33: warning: missing return value +tst/array.c:48: warning: missing return value diff --git a/src/cmd/lccom/tst/mips-eb/array.sbk b/src/cmd/lccom/tst/mips-eb/array.sbk new file mode 100644 index 0000000..90eff4d --- /dev/null +++ b/src/cmd/lccom/tst/mips-eb/array.sbk @@ -0,0 +1,235 @@ +.set reorder +.globl main +.text +.text +.align 2 +.ent main +main: +.frame $sp,96,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-96 +.mask 0xc2c00000,-64 +sw $22,16($sp) +sw $23,20($sp) +.cprestore 24 +sw $30,28($sp) +sw $31,32($sp) +move $23,$0 +L.2: +move $30,$0 +L.6: +sll $24,$30,2 +sll $15,$23,4 +la $15,x($15) +addu $24,$24,$15 +la $15,1000 +mul $15,$15,$23 +addu $15,$15,$30 +sw $15,($24) +L.7: +la $30,1($30) +la $24,4 +blt $30,$24,L.6 +sll $24,$23,2 +sll $15,$23,4 +la $15,x($15) +sw $15,y($24) +L.3: +la $23,1($23) +la $24,3 +blt $23,$24,L.2 +jal f +move $23,$0 +L.10: +sll $24,$23,4 +la $15,-48+96($sp) +addu $24,$24,$15 +move $22,$24 +sll $15,$23,2 +sw $24,y($15) +move $30,$0 +L.14: +sll $24,$30,2 +addu $15,$24,$22 +sll $14,$23,4 +la $14,x($14) +addu $24,$24,$14 +lw $24,($24) +sw $24,($15) +L.15: +la $30,1($30) +la $24,4 +blt $30,$24,L.14 +L.11: +la $23,1($23) +la $24,3 +blt $23,$24,L.10 +la $4,-48+96($sp) +la $5,y +jal g +move $2,$0 +L.1: +lw $22,16($sp) +lw $23,20($sp) +lw $25,24($sp) +lw $30,28($sp) +lw $31,32($sp) +addu $sp,$sp,96 +j $31 +.end main +.globl f +.text +.align 2 +.ent f +f: +.frame $sp,32,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-32 +.mask 0xc2800000,-4 +sw $23,16($sp) +.cprestore 20 +sw $30,24($sp) +sw $31,28($sp) +move $23,$0 +L.19: +move $30,$0 +L.23: +la $4,L.27 +sll $24,$30,2 +sll $15,$23,4 +la $15,x($15) +addu $24,$24,$15 +lw $5,($24) +jal printf +L.24: +la $30,1($30) +la $24,4 +blt $30,$24,L.23 +L.20: +la $23,1($23) +la $24,3 +blt $23,$24,L.19 +la $4,L.28 +jal printf +move $23,$0 +L.29: +move $30,$0 +L.33: +la $4,L.27 +sll $24,$30,2 +sll $15,$23,2 +lw $15,y($15) +addu $24,$24,$15 +lw $5,($24) +jal printf +L.34: +la $30,1($30) +la $24,4 +blt $30,$24,L.33 +L.30: +la $23,1($23) +la $24,3 +blt $23,$24,L.29 +la $4,L.28 +jal printf +move $2,$0 +L.18: +lw $23,16($sp) +lw $25,20($sp) +lw $30,24($sp) +lw $31,28($sp) +addu $sp,$sp,32 +j $31 +.end f +.globl g +.text +.align 2 +.ent g +g: +.frame $sp,48,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-48 +.mask 0xc2e00000,-12 +sw $21,16($sp) +sw $22,20($sp) +sw $23,24($sp) +.cprestore 28 +sw $30,32($sp) +sw $31,36($sp) +move $30,$4 +move $23,$5 +move $21,$0 +L.38: +move $22,$0 +L.42: +la $4,L.27 +sll $24,$22,2 +sll $15,$21,4 +addu $15,$15,$30 +addu $24,$24,$15 +lw $5,($24) +jal printf +L.43: +la $22,1($22) +la $24,4 +blt $22,$24,L.42 +L.39: +la $21,1($21) +la $24,3 +blt $21,$24,L.38 +la $4,L.28 +jal printf +move $21,$0 +L.46: +move $22,$0 +L.50: +la $4,L.27 +sll $24,$22,2 +sll $15,$21,2 +addu $15,$15,$23 +lw $15,($15) +addu $24,$24,$15 +lw $5,($24) +jal printf +L.51: +la $22,1($22) +la $24,4 +blt $22,$24,L.50 +L.47: +la $21,1($21) +la $24,3 +blt $21,$24,L.46 +la $4,L.28 +jal printf +move $2,$0 +L.37: +lw $21,16($sp) +lw $22,20($sp) +lw $23,24($sp) +lw $25,28($sp) +lw $30,32($sp) +lw $31,36($sp) +addu $sp,$sp,48 +j $31 +.end g +.globl y +.comm y,12 +.globl x +.comm x,48 +.rdata +.align 0 +L.28: +.byte 10 +.byte 0 +.align 0 +L.27: +.byte 32 +.byte 37 +.byte 100 +.byte 0 diff --git a/src/cmd/lccom/tst/mips-eb/assert.h b/src/cmd/lccom/tst/mips-eb/assert.h new file mode 100644 index 0000000..04b0e3a --- /dev/null +++ b/src/cmd/lccom/tst/mips-eb/assert.h @@ -0,0 +1,14 @@ +#ifndef __ASSERT +#define __ASSERT + +void assert(int); + +#endif /* __ASSERT */ + +#undef assert +#ifdef NDEBUG +#define assert(ignore) ((void)0) +#else +extern int _assert(char *, char *, unsigned); +#define assert(e) ((void)((e)||_assert(#e, __FILE__, __LINE__))) +#endif /* NDEBUG */ diff --git a/src/cmd/lccom/tst/mips-eb/cf.1bk b/src/cmd/lccom/tst/mips-eb/cf.1bk new file mode 100644 index 0000000..9e331c5 --- /dev/null +++ b/src/cmd/lccom/tst/mips-eb/cf.1bk @@ -0,0 +1,51 @@ +char freq +011 8.1 +012 6.1 +040 11.9 +! 0.2 +" 1.5 +% 0.6 +& 0.4 +' 0.4 +( 2.9 +) 2.9 +* 0.8 ++ 1.3 +, 1.3 +- 0.4 +. 0.6 +/ 1.0 +0 2.5 +1 1.9 +2 0.6 +3 0.2 +7 0.4 +8 0.2 +; 3.8 +< 0.8 += 2.7 +> 0.2 +[ 1.5 +\ 0.8 +] 1.5 +a 3.1 +c 4.4 +e 2.3 +f 6.0 +g 1.3 +h 1.0 +i 5.0 +l 1.0 +m 0.2 +n 3.3 +o 2.1 +p 1.0 +q 0.4 +r 4.2 +s 0.6 +t 3.8 +u 1.2 +v 0.6 +w 0.2 +{ 0.6 +} 0.6 diff --git a/src/cmd/lccom/tst/mips-eb/cf.2bk b/src/cmd/lccom/tst/mips-eb/cf.2bk new file mode 100644 index 0000000..e69de29 diff --git a/src/cmd/lccom/tst/mips-eb/cf.sbk b/src/cmd/lccom/tst/mips-eb/cf.sbk new file mode 100644 index 0000000..75f582c --- /dev/null +++ b/src/cmd/lccom/tst/mips-eb/cf.sbk @@ -0,0 +1,153 @@ +.set reorder +.globl main +.text +.text +.align 2 +.ent main +main: +.frame $sp,48,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-48 +.fmask 0xc0000000,-32 +.mask 0xc2c00000,-8 +s.d $f30,16($sp) +sw $22,24($sp) +sw $23,28($sp) +.cprestore 32 +sw $30,36($sp) +sw $31,40($sp) +sw $4,48($sp) +sw $5,52($sp) +lw $24,0+48($sp) +la $15,1 +bgt $24,$15,L.2 +l.s $f30,L.4 +b L.3 +L.2: +lw $24,4+48($sp) +lw $4,4($24) +jal atof +l.s $f16,L.5 +div.s $f30,$f0,$f16 +L.3: +move $30,$0 +L.6: +move $24,$30 +la $30,1($24) +sll $24,$24,2 +l.s $f18,L.4 +s.s $f18,f($24) +L.7: +la $24,127 +ble $30,$24,L.6 +move $23,$0 +b L.11 +L.10: +sll $24,$22,2 +la $24,f($24) +l.s $f18,($24) +l.s $f16,L.13 +add.s $f18,$f18,$f16 +s.s $f18,($24) +la $23,1($23) +L.11: +jal getchar +move $22,$2 +la $15,-1 +bne $2,$15,L.10 +la $4,L.14 +jal printf +move $30,$0 +L.15: +sll $24,$30,2 +l.s $f18,f($24) +l.s $f16,L.4 +c.eq.s $f18,$f16; bc1t L.19 +mtc1 $23,$f16; cvt.s.w $f16,$f16 +div.s $f18,$f18,$f16 +c.ult.s $f18,$f30; bc1t L.19 +la $24,32 +bgt $30,$24,L.21 +la $4,L.23 +move $5,$30 +jal printf +b L.22 +L.21: +la $4,L.24 +move $5,$30 +jal printf +L.22: +la $4,L.25 +l.s $f18,L.5 +sll $24,$30,2 +l.s $f16,f($24) +mul.s $f18,$f18,$f16 +mtc1 $23,$f16; cvt.s.w $f16,$f16 +div.s $f18,$f18,$f16 +cvt.d.s $f18,$f18 +mfc1.d $6,$f18 +jal printf +L.19: +L.16: +la $30,1($30) +la $24,127 +ble $30,$24,L.15 +move $2,$0 +L.1: +l.d $f30,16($sp) +lw $22,24($sp) +lw $23,28($sp) +lw $25,32($sp) +lw $30,36($sp) +lw $31,40($sp) +addu $sp,$sp,48 +j $31 +.end main +.globl f +.comm f,512 +.rdata +.align 0 +L.25: +.byte 9 +.byte 37 +.byte 46 +.byte 49 +.byte 102 +.byte 10 +.byte 0 +.align 0 +L.24: +.byte 37 +.byte 99 +.byte 0 +.align 0 +L.23: +.byte 37 +.byte 48 +.byte 51 +.byte 111 +.byte 0 +.align 0 +L.14: +.byte 99 +.byte 104 +.byte 97 +.byte 114 +.byte 9 +.byte 102 +.byte 114 +.byte 101 +.byte 113 +.byte 10 +.byte 0 +.align 2 +L.13: +.word 0x3f800000 +.align 2 +L.5: +.word 0x42c80000 +.align 2 +L.4: +.word 0x0 diff --git a/src/cmd/lccom/tst/mips-eb/cq.1bk b/src/cmd/lccom/tst/mips-eb/cq.1bk new file mode 100644 index 0000000..ec956b7 --- /dev/null +++ b/src/cmd/lccom/tst/mips-eb/cq.1bk @@ -0,0 +1,48 @@ +Section s22 returned 0. +Decimal and octal/hex constants sometimes give + different results when assigned to longs. +Decimal and octal/hex constants sometimes give + different results when assigned to longs. +Section s241 returned 0. +Section s243 returned 0. +Section s244 returned 0. +Section s25 returned 0. + 8 bits in chars. + 32 bits in ints. + 16 bits in shorts. + 32 bits in longs. + 32 bits in unsigneds. + 32 bits in floats. + 64 bits in doubles. +1.192093e-07 is the least number that can be added to 1. (float). +2.220446e-16 is the least number that can be added to 1. (double). +Section s26 returned 0. +Section s4 returned 0. +Section s61 returned 0. +Section s626 returned 0. +Section s71 returned 0. +Section s72 returned 0. +Section s757 returned 0. +Section s7813 returned 0. +Section s714 returned 0. +Section s715 returned 0. +Register count for char is unreliable. +Register count for pointer is unreliable. +Register count for int is unreliable. +Section s81 returned 0. +Section s84 returned 0. +char alignment: 1 +short alignment: 2 +int alignment: 4 +long alignment: 4 +unsigned alignment: 4 +float alignment: 4 +double alignment: 8 +Sign extension in fields +Be especially careful with 1-bit fields! +Section s85 returned 0. +Section s86 returned 0. +Section s88 returned 0. +Section s9 returned 0. + +No errors detected. diff --git a/src/cmd/lccom/tst/mips-eb/cq.2bk b/src/cmd/lccom/tst/mips-eb/cq.2bk new file mode 100644 index 0000000..7c6ba5e --- /dev/null +++ b/src/cmd/lccom/tst/mips-eb/cq.2bk @@ -0,0 +1,25 @@ +tst/cq.c:394: warning: overflow in converting constant expression from `unsigned long' to `long int' +tst/cq.c:394: warning: overflow in converting constant expression from `unsigned long' to `long int' +tst/cq.c:394: warning: overflow in converting constant expression from `unsigned long' to `long int' +tst/cq.c:395: warning: overflow in constant `4294967296' +tst/cq.c:395: warning: overflow in converting constant expression from `unsigned long' to `long int' +tst/cq.c:395: warning: overflow in constant `040000000000' +tst/cq.c:395: warning: overflow in converting constant expression from `unsigned long' to `long int' +tst/cq.c:395: warning: overflow in constant `0x100000000' +tst/cq.c:395: warning: overflow in converting constant expression from `unsigned long' to `long int' +tst/cq.c:396: warning: overflow in constant `68719476735' +tst/cq.c:396: warning: overflow in converting constant expression from `unsigned long' to `long int' +tst/cq.c:396: warning: overflow in constant `0777777777777' +tst/cq.c:396: warning: overflow in converting constant expression from `unsigned long' to `long int' +tst/cq.c:396: warning: overflow in constant `0xfffffffff' +tst/cq.c:396: warning: overflow in converting constant expression from `unsigned long' to `long int' +tst/cq.c:397: warning: overflow in constant `68719476736' +tst/cq.c:397: warning: overflow in converting constant expression from `unsigned long' to `long int' +tst/cq.c:397: warning: overflow in constant `01000000000000' +tst/cq.c:397: warning: overflow in converting constant expression from `unsigned long' to `long int' +tst/cq.c:397: warning: overflow in constant `0x1000000000' +tst/cq.c:397: warning: overflow in converting constant expression from `unsigned long' to `long int' +tst/cq.c:533: warning: missing return value +tst/cq.c:1169: warning: missing return value +tst/cq.c:5294: warning: unreachable code +tst/cq.c:5303: warning: missing return value diff --git a/src/cmd/lccom/tst/mips-eb/cq.sbk b/src/cmd/lccom/tst/mips-eb/cq.sbk new file mode 100644 index 0000000..b53bda0 --- /dev/null +++ b/src/cmd/lccom/tst/mips-eb/cq.sbk @@ -0,0 +1,13620 @@ +.set reorder +.data +.align 2 +L.2: +.word s22 +.word s241 +.word s243 +.word s244 +.word s25 +.word s26 +.word s4 +.word s61 +.word s626 +.word s71 +.word s72 +.word s757 +.word s7813 +.word s714 +.word s715 +.word s81 +.word s84 +.word s85 +.word s86 +.word s88 +.word s9 +.lcomm L.3,68 +.lcomm L.4,4 +.globl main +.text +.text +.align 2 +.ent main +main: +.frame $sp,32,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-32 +.mask 0xc2000000,-8 +.cprestore 16 +sw $30,20($sp) +sw $31,24($sp) +sw $4,32($sp) +sw $5,36($sp) +la $24,1 +sw $24,L.3+36 +la $24,1 +sw $24,L.3+40 +la $24,1 +sw $24,L.3+44 +la $24,1 +sw $24,L.3+48 +la $24,L.3 +sw $24,L.4 +move $30,$0 +b L.12 +L.9: +lw $4,L.4 +sll $24,$30,2 +lw $25,L.2($24) +jal $25 +sw $2,L.3+52 +lw $24,L.3+56 +lw $15,L.3+52 +addu $24,$24,$15 +sw $24,L.3+56 +lw $24,L.3+36 +beq $24,$0,L.17 +la $4,L.20 +la $5,L.3+60 +lw $6,L.3+52 +jal printf +L.17: +L.10: +la $30,1($30) +L.12: +move $24,$30 +la $15,21 +bltu $24,$15,L.9 +lw $24,L.3+56 +bne $24,$0,L.23 +la $4,L.26 +jal printf +b L.24 +L.23: +la $4,L.27 +jal printf +L.24: +move $2,$0 +L.1: +lw $25,16($sp) +lw $30,20($sp) +lw $31,24($sp) +addu $sp,$sp,32 +j $31 +.end main +.data +.align 0 +L.29: +.byte 115 +.byte 50 +.byte 50 +.byte 44 +.byte 101 +.byte 114 +.byte 37 +.byte 100 +.byte 10 +.byte 0 +.sdata +.align 0 +L.30: +.byte 115 +.byte 50 +.byte 50 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 0 +.globl s22 +.text +.text +.align 2 +.ent s22 +s22: +.frame $sp,64,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-64 +.mask 0xc2e00000,-28 +sw $21,16($sp) +sw $22,20($sp) +sw $23,24($sp) +.cprestore 28 +sw $30,32($sp) +sw $31,36($sp) +sw $4,64($sp) +move $22,$0 +la $30,L.30 +lw $24,0+64($sp) +la $23,60($24) +L.31: +L.32: +move $24,$23 +la $23,1($24) +move $15,$30 +la $30,1($15) +lb $15,($15) +sb $15,($24) +sll $24,$15,8*(4-1); sra $24,$24,8*(4-1) +bne $24,$0,L.31 +la $21,1 +la $24,2 +sw $24,-8+64($sp) +la $24,3 +sw $24,-12+64($sp) +la $24,4 +sw $24,-4+64($sp) +lw $24,-8+64($sp) +addu $24,$21,$24 +lw $15,-12+64($sp) +addu $24,$24,$15 +lw $15,-4+64($sp) +addu $24,$24,$15 +la $15,10 +beq $24,$15,L.34 +la $22,1($22) +lw $24,0+64($sp) +lw $24,44($24) +beq $24,$0,L.36 +la $4,L.29 +la $5,1 +jal printf +L.36: +L.34: +la $24,2 +sw $24,-16+64($sp) +lw $24,-16+64($sp) +bne $24,$21,L.38 +la $22,4($22) +lw $24,0+64($sp) +lw $24,44($24) +beq $24,$0,L.40 +la $4,L.29 +la $5,4 +jal printf +L.40: +L.38: +move $2,$22 +L.28: +lw $21,16($sp) +lw $22,20($sp) +lw $23,24($sp) +lw $25,28($sp) +lw $30,32($sp) +lw $31,36($sp) +addu $sp,$sp,64 +j $31 +.end s22 +.data +.align 0 +L.43: +.byte 115 +.byte 50 +.byte 52 +.byte 49 +.byte 44 +.byte 101 +.byte 114 +.byte 37 +.byte 100 +.byte 10 +.byte 0 +.sdata +.align 0 +L.44: +.byte 115 +.byte 50 +.byte 52 +.byte 49 +.byte 32 +.byte 32 +.byte 32 +.byte 0 +.data +.align 2 +L.45: +.word 0x0 +.word 0x0 +.word 0x0 +.word 0x0 +.word 0x0 +.word 0x0 +.word 0x0 +.word 0x0 +.word 0x0 +.word 0x0 +.word 0x0 +.word 0x0 +.word 0x0 +.word 0x0 +.word 0x0 +.word 0x0 +.word 0x0 +.word 0x0 +.word 0x6 +.word 0x0 +.word 0x8 +.word 0x0 +.word 0xc +.word 0x0 +.word 0x10 +.word 0x0 +.word 0x12 +.word 0x0 +.word 0x14 +.word 0x0 +.word 0x18 +.word 0x0 +.word 0x1c +.word 0x0 +.word 0x1e +.word 0x0 +.word 0x20 +.word 0x0 +.word 0x24 +.globl s241 +.text +.text +.align 2 +.ent s241 +s241: +.frame $sp,528,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-528 +.mask 0xc2f00000,-488 +sw $20,16($sp) +sw $21,20($sp) +sw $22,24($sp) +sw $23,28($sp) +.cprestore 32 +sw $30,36($sp) +sw $31,40($sp) +move $30,$4 +move $20,$0 +sw $0,-472+528($sp) +la $22,L.44 +la $21,60($30) +L.46: +L.47: +move $24,$21 +la $21,1($24) +move $15,$22 +la $22,1($15) +lb $15,($15) +sb $15,($24) +sll $24,$15,8*(4-1); sra $24,$24,8*(4-1) +bne $24,$0,L.46 +b L.49 +la $20,1($20) +lw $24,44($30) +beq $24,$0,L.51 +la $4,L.43 +la $5,1 +jal printf +L.51: +L.49: +b L.53 +la $20,2($20) +lw $24,44($30) +beq $24,$0,L.55 +la $4,L.43 +la $5,2 +jal printf +L.55: +L.53: +b L.57 +la $20,4($20) +lw $24,44($30) +beq $24,$0,L.59 +la $4,L.43 +la $5,4 +jal printf +L.59: +L.57: +b L.61 +la $20,8($20) +lw $24,44($30) +beq $24,$0,L.63 +la $4,L.43 +la $5,8 +jal printf +L.63: +L.61: +move $23,$0 +L.65: +sll $24,$23,2 +sw $23,L.45($24) +L.66: +la $23,1($23) +la $24,17 +blt $23,$24,L.65 +la $23,18 +L.69: +sll $24,$23,2 +la $24,L.45($24) +sw $24,-476+528($sp) +lw $4,($24) +jal pow2 +lw $15,-476+528($sp) +sw $2,($15) +sll $24,$23,2 +lw $15,L.45($24) +subu $15,$15,1 +sw $15,L.45-4($24) +la $23,2($23) +L.70: +la $24,39 +blt $23,$24,L.69 +sw $0,-156+528($sp) +sw $0,-312+528($sp) +sw $0,-468+528($sp) +la $24,1 +sw $24,-152+528($sp) +la $24,1 +sw $24,-308+528($sp) +la $24,1 +sw $24,-464+528($sp) +la $24,2 +sw $24,-148+528($sp) +la $24,2 +sw $24,-304+528($sp) +la $24,2 +sw $24,-460+528($sp) +la $24,3 +sw $24,-144+528($sp) +la $24,3 +sw $24,-300+528($sp) +la $24,3 +sw $24,-456+528($sp) +la $24,4 +sw $24,-140+528($sp) +la $24,4 +sw $24,-296+528($sp) +la $24,4 +sw $24,-452+528($sp) +la $24,5 +sw $24,-136+528($sp) +la $24,5 +sw $24,-292+528($sp) +la $24,5 +sw $24,-448+528($sp) +la $24,6 +sw $24,-132+528($sp) +la $24,6 +sw $24,-288+528($sp) +la $24,6 +sw $24,-444+528($sp) +la $24,7 +sw $24,-128+528($sp) +la $24,7 +sw $24,-284+528($sp) +la $24,7 +sw $24,-440+528($sp) +la $24,8 +sw $24,-124+528($sp) +la $24,8 +sw $24,-280+528($sp) +la $24,8 +sw $24,-436+528($sp) +la $24,9 +sw $24,-120+528($sp) +la $24,9 +sw $24,-276+528($sp) +la $24,9 +sw $24,-432+528($sp) +la $24,10 +sw $24,-116+528($sp) +la $24,10 +sw $24,-272+528($sp) +la $24,10 +sw $24,-428+528($sp) +la $24,11 +sw $24,-112+528($sp) +la $24,11 +sw $24,-268+528($sp) +la $24,11 +sw $24,-424+528($sp) +la $24,12 +sw $24,-108+528($sp) +la $24,12 +sw $24,-264+528($sp) +la $24,12 +sw $24,-420+528($sp) +la $24,13 +sw $24,-104+528($sp) +la $24,13 +sw $24,-260+528($sp) +la $24,13 +sw $24,-416+528($sp) +la $24,14 +sw $24,-100+528($sp) +la $24,14 +sw $24,-256+528($sp) +la $24,14 +sw $24,-412+528($sp) +la $24,15 +sw $24,-96+528($sp) +la $24,15 +sw $24,-252+528($sp) +la $24,15 +sw $24,-408+528($sp) +la $24,16 +sw $24,-92+528($sp) +la $24,16 +sw $24,-248+528($sp) +la $24,16 +sw $24,-404+528($sp) +la $24,63 +sw $24,-88+528($sp) +la $24,63 +sw $24,-244+528($sp) +la $24,63 +sw $24,-400+528($sp) +la $24,64 +sw $24,-84+528($sp) +la $24,64 +sw $24,-240+528($sp) +la $24,64 +sw $24,-396+528($sp) +la $24,255 +sw $24,-80+528($sp) +la $24,255 +sw $24,-236+528($sp) +la $24,255 +sw $24,-392+528($sp) +la $24,256 +sw $24,-76+528($sp) +la $24,256 +sw $24,-232+528($sp) +la $24,256 +sw $24,-388+528($sp) +la $24,4095 +sw $24,-72+528($sp) +la $24,4095 +sw $24,-228+528($sp) +la $24,4095 +sw $24,-384+528($sp) +la $24,4096 +sw $24,-68+528($sp) +la $24,4096 +sw $24,-224+528($sp) +la $24,4096 +sw $24,-380+528($sp) +la $24,65535 +sw $24,-64+528($sp) +la $24,65535 +sw $24,-220+528($sp) +la $24,65535 +sw $24,-376+528($sp) +la $24,65536 +sw $24,-60+528($sp) +la $24,65536 +sw $24,-216+528($sp) +la $24,65536 +sw $24,-372+528($sp) +la $24,262143 +sw $24,-56+528($sp) +la $24,262143 +sw $24,-212+528($sp) +la $24,262143 +sw $24,-368+528($sp) +la $24,262144 +sw $24,-52+528($sp) +la $24,262144 +sw $24,-208+528($sp) +la $24,262144 +sw $24,-364+528($sp) +la $24,1048575 +sw $24,-48+528($sp) +la $24,1048575 +sw $24,-204+528($sp) +la $24,1048575 +sw $24,-360+528($sp) +la $24,1048576 +sw $24,-44+528($sp) +la $24,1048576 +sw $24,-200+528($sp) +la $24,1048576 +sw $24,-356+528($sp) +la $24,16777215 +sw $24,-40+528($sp) +la $24,16777215 +sw $24,-196+528($sp) +la $24,16777215 +sw $24,-352+528($sp) +la $24,16777216 +sw $24,-36+528($sp) +la $24,16777216 +sw $24,-192+528($sp) +la $24,16777216 +sw $24,-348+528($sp) +la $24,268435455 +sw $24,-32+528($sp) +la $24,268435455 +sw $24,-188+528($sp) +la $24,268435455 +sw $24,-344+528($sp) +la $24,268435456 +sw $24,-28+528($sp) +la $24,268435456 +sw $24,-184+528($sp) +la $24,268435456 +sw $24,-340+528($sp) +la $24,1073741823 +sw $24,-24+528($sp) +la $24,1073741823 +sw $24,-180+528($sp) +la $24,1073741823 +sw $24,-336+528($sp) +la $24,1073741824 +sw $24,-20+528($sp) +la $24,1073741824 +sw $24,-176+528($sp) +la $24,1073741824 +sw $24,-332+528($sp) +la $24,0xffffffff +sw $24,-16+528($sp) +la $24,0xffffffff +sw $24,-172+528($sp) +la $24,0xffffffff +sw $24,-328+528($sp) +la $24,0xffffffff +sw $24,-12+528($sp) +la $24,0xffffffff +sw $24,-168+528($sp) +la $24,0xffffffff +sw $24,-324+528($sp) +la $24,0xffffffff +sw $24,-8+528($sp) +la $24,0xffffffff +sw $24,-164+528($sp) +la $24,0xffffffff +sw $24,-320+528($sp) +la $24,0xffffffff +sw $24,-4+528($sp) +la $24,0xffffffff +sw $24,-160+528($sp) +la $24,0xffffffff +sw $24,-316+528($sp) +move $23,$0 +L.188: +sll $24,$23,2 +la $15,-156+528($sp) +addu $15,$24,$15 +lw $15,($15) +lw $14,L.45($24) +bne $14,$15,L.195 +la $14,-312+528($sp) +addu $14,$24,$14 +lw $14,($14) +bne $15,$14,L.195 +la $15,-468+528($sp) +addu $24,$24,$15 +lw $24,($24) +beq $14,$24,L.192 +L.195: +lw $24,40($30) +beq $24,$0,L.196 +la $4,L.198 +jal printf +la $4,L.199 +jal printf +L.196: +L.192: +L.189: +la $23,1($23) +la $24,39 +blt $23,$24,L.188 +lw $24,-472+528($sp) +beq $24,$0,L.200 +la $20,16 +L.200: +move $2,$20 +L.42: +lw $20,16($sp) +lw $21,20($sp) +lw $22,24($sp) +lw $23,28($sp) +lw $25,32($sp) +lw $30,36($sp) +lw $31,40($sp) +addu $sp,$sp,528 +j $31 +.end s241 +.globl pow2 +.text +.align 2 +.ent pow2 +pow2: +.frame $sp,16,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-16 +.mask 0x40000000,-16 +sw $30,0($sp) +la $30,1 +b L.204 +L.203: +sll $30,$30,1 +L.204: +move $24,$4 +subu $4,$24,1 +bne $24,$0,L.203 +move $2,$30 +L.202: +lw $30,0($sp) +addu $sp,$sp,16 +j $31 +.end pow2 +.data +.align 0 +L.207: +.byte 115 +.byte 50 +.byte 52 +.byte 51 +.byte 44 +.byte 101 +.byte 114 +.byte 37 +.byte 100 +.byte 10 +.byte 0 +.sdata +.align 0 +L.208: +.byte 115 +.byte 50 +.byte 52 +.byte 51 +.byte 32 +.byte 32 +.byte 32 +.byte 0 +.globl s243 +.text +.text +.align 2 +.ent s243 +s243: +.frame $sp,304,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-304 +.mask 0xc2c00000,-272 +sw $22,16($sp) +sw $23,20($sp) +.cprestore 24 +sw $30,28($sp) +sw $31,32($sp) +sw $4,304($sp) +move $22,$0 +la $30,L.208 +lw $24,0+304($sp) +la $23,60($24) +L.209: +L.210: +move $24,$23 +la $23,1($24) +move $15,$30 +la $30,1($15) +lb $15,($15) +sb $15,($24) +sll $24,$15,8*(4-1); sra $24,$24,8*(4-1) +bne $24,$0,L.209 +la $4,-256+304($sp) +jal zerofill +la $24,1 +sb $24,-159+304($sp) +la $24,1 +sb $24,-191+304($sp) +la $24,1 +sb $24,-130+304($sp) +la $24,1 +sb $24,-208+304($sp) +la $24,1 +sb $24,-158+304($sp) +la $24,1 +sb $24,-190+304($sp) +la $24,1 +sb $24,-223+304($sp) +la $24,1 +sb $24,-207+304($sp) +la $24,1 +sb $24,-157+304($sp) +la $24,1 +sb $24,-189+304($sp) +la $24,1 +sb $24,-222+304($sp) +la $24,1 +sb $24,-206+304($sp) +la $24,1 +sb $24,-156+304($sp) +la $24,1 +sb $24,-188+304($sp) +la $24,1 +sb $24,-221+304($sp) +la $24,1 +sb $24,-205+304($sp) +la $24,1 +sb $24,-155+304($sp) +la $24,1 +sb $24,-187+304($sp) +la $24,1 +sb $24,-219+304($sp) +la $24,1 +sb $24,-204+304($sp) +la $24,1 +sb $24,-154+304($sp) +la $24,1 +sb $24,-186+304($sp) +la $24,1 +sb $24,-218+304($sp) +la $24,1 +sb $24,-203+304($sp) +la $24,1 +sb $24,-153+304($sp) +la $24,1 +sb $24,-185+304($sp) +la $24,1 +sb $24,-216+304($sp) +la $24,1 +sb $24,-202+304($sp) +la $24,1 +sb $24,-152+304($sp) +la $24,1 +sb $24,-184+304($sp) +la $24,1 +sb $24,-215+304($sp) +la $24,1 +sb $24,-201+304($sp) +la $24,1 +sb $24,-151+304($sp) +la $24,1 +sb $24,-183+304($sp) +la $24,1 +sb $24,-161+304($sp) +la $24,1 +sb $24,-200+304($sp) +la $24,1 +sb $24,-150+304($sp) +la $24,1 +sb $24,-182+304($sp) +la $24,1 +sb $24,-195+304($sp) +la $24,1 +sb $24,-199+304($sp) +la $24,1 +sb $24,-149+304($sp) +la $24,1 +sb $24,-181+304($sp) +la $24,1 +sb $24,-211+304($sp) +la $24,1 +sb $24,-148+304($sp) +la $24,1 +sb $24,-180+304($sp) +la $24,1 +sb $24,-162+304($sp) +la $24,1 +sb $24,-147+304($sp) +la $24,1 +sb $24,-179+304($sp) +la $24,1 +sb $24,-132+304($sp) +la $24,1 +sb $24,-246+304($sp) +la $24,1 +sb $24,-146+304($sp) +la $24,1 +sb $24,-178+304($sp) +la $24,1 +sb $24,-247+304($sp) +la $24,1 +sb $24,-145+304($sp) +la $24,1 +sb $24,-177+304($sp) +la $24,1 +sb $24,-133+304($sp) +la $24,1 +sb $24,-248+304($sp) +la $24,1 +sb $24,-144+304($sp) +la $24,1 +sb $24,-176+304($sp) +la $24,1 +sb $24,-131+304($sp) +la $24,1 +sb $24,-243+304($sp) +la $24,1 +sb $24,-143+304($sp) +la $24,1 +sb $24,-175+304($sp) +la $24,1 +sb $24,-165+304($sp) +la $24,1 +sb $24,-244+304($sp) +la $24,1 +sb $24,-142+304($sp) +la $24,1 +sb $24,-174+304($sp) +la $24,1 +sb $24,-163+304($sp) +la $24,1 +sb $24,-141+304($sp) +la $24,1 +sb $24,-173+304($sp) +la $24,1 +sb $24,-213+304($sp) +la $24,1 +sb $24,-164+304($sp) +la $24,1 +sb $24,-140+304($sp) +la $24,1 +sb $24,-172+304($sp) +la $24,1 +sb $24,-197+304($sp) +la $24,1 +sb $24,-217+304($sp) +la $24,1 +sb $24,-139+304($sp) +la $24,1 +sb $24,-171+304($sp) +la $24,1 +sb $24,-214+304($sp) +la $24,1 +sb $24,-138+304($sp) +la $24,1 +sb $24,-170+304($sp) +la $24,1 +sb $24,-198+304($sp) +la $24,1 +sb $24,-256+304($sp) +sb $24,-137+304($sp) +la $24,1 +sb $24,-169+304($sp) +la $24,1 +sb $24,-196+304($sp) +la $24,1 +sb $24,-224+304($sp) +la $24,1 +sb $24,-136+304($sp) +la $24,1 +sb $24,-168+304($sp) +la $24,1 +sb $24,-194+304($sp) +la $24,1 +sb $24,-135+304($sp) +la $24,1 +sb $24,-167+304($sp) +la $24,1 +sb $24,-212+304($sp) +la $24,1 +sb $24,-134+304($sp) +la $24,1 +sb $24,-166+304($sp) +la $24,1 +sb $24,-210+304($sp) +la $24,1 +sb $24,-193+304($sp) +la $24,1 +sb $24,-209+304($sp) +la $4,-256+304($sp) +jal sumof +la $15,98 +beq $2,$15,L.309 +la $22,1($22) +lw $24,0+304($sp) +lw $24,44($24) +beq $24,$0,L.311 +la $4,L.207 +la $5,1 +jal printf +L.311: +L.309: +b L.313 +la $22,8($22) +lw $24,0+304($sp) +lw $24,44($24) +beq $24,$0,L.315 +la $4,L.207 +la $5,8 +jal printf +L.315: +L.313: +move $2,$22 +L.206: +lw $22,16($sp) +lw $23,20($sp) +lw $25,24($sp) +lw $30,28($sp) +lw $31,32($sp) +addu $sp,$sp,304 +j $31 +.end s243 +.globl zerofill +.text +.align 2 +.ent zerofill +zerofill: +.frame $sp,16,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-16 +.mask 0x40000000,-16 +sw $30,0($sp) +move $30,$0 +L.318: +move $24,$4 +la $4,1($24) +sb $0,($24) +L.319: +la $30,1($30) +la $24,256 +blt $30,$24,L.318 +move $2,$0 +L.317: +lw $30,0($sp) +addu $sp,$sp,16 +j $31 +.end zerofill +.globl sumof +.text +.align 2 +.ent sumof +sumof: +.frame $sp,16,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-16 +.mask 0x40c00000,-8 +sw $22,0($sp) +sw $23,4($sp) +sw $30,8($sp) +move $22,$4 +move $30,$0 +move $23,$0 +L.323: +move $24,$22 +la $22,1($24) +lb $24,($24) +addu $30,$30,$24 +L.324: +la $23,1($23) +la $24,256 +blt $23,$24,L.323 +move $2,$30 +L.322: +lw $22,0($sp) +lw $23,4($sp) +lw $30,8($sp) +addu $sp,$sp,16 +j $31 +.end sumof +.data +.align 0 +L.328: +.byte 115 +.byte 50 +.byte 52 +.byte 52 +.byte 44 +.byte 101 +.byte 114 +.byte 37 +.byte 100 +.byte 10 +.byte 0 +.sdata +.align 0 +L.329: +.byte 115 +.byte 50 +.byte 52 +.byte 52 +.byte 32 +.byte 32 +.byte 32 +.byte 0 +.globl s244 +.text +.text +.align 2 +.ent s244 +s244: +.frame $sp,112,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-112 +.mask 0xc2f00000,-72 +sw $20,16($sp) +sw $21,20($sp) +sw $22,24($sp) +sw $23,28($sp) +.cprestore 32 +sw $30,36($sp) +sw $31,40($sp) +sw $4,112($sp) +la $23,L.329 +lw $24,0+112($sp) +la $22,60($24) +L.330: +L.331: +move $24,$22 +la $22,1($24) +move $15,$23 +la $23,1($15) +lb $15,($15) +sb $15,($24) +sll $24,$15,8*(4-1); sra $24,$24,8*(4-1) +bne $24,$0,L.330 +move $20,$0 +move $21,$0 +l.d $f18,L.333 +s.d $f18,-64+112($sp) +s.d $f18,-56+112($sp) +l.d $f18,L.333 +s.d $f18,-48+112($sp) +l.d $f18,L.333 +s.d $f18,-40+112($sp) +l.d $f18,L.333 +s.d $f18,-32+112($sp) +l.d $f18,L.333 +s.d $f18,-24+112($sp) +l.d $f18,L.333 +s.d $f18,-16+112($sp) +l.d $f18,L.333 +s.d $f18,-8+112($sp) +move $21,$0 +move $30,$0 +L.341: +sll $24,$30,3 +la $15,-64+112($sp) +addu $15,$24,$15 +l.d $f18,($15) +la $15,-56+112($sp) +addu $24,$24,$15 +l.d $f16,($24) +c.eq.d $f18,$f16; bc1t L.345 +la $21,1 +L.345: +L.342: +la $30,1($30) +la $24,7 +blt $30,$24,L.341 +beq $21,$0,L.348 +lw $24,0+112($sp) +lw $24,44($24) +beq $24,$0,L.350 +la $4,L.328 +la $5,1 +jal printf +L.350: +la $20,1($20) +L.348: +b L.352 +lw $24,0+112($sp) +lw $24,44($24) +beq $24,$0,L.354 +la $4,L.328 +la $5,2 +jal printf +L.354: +la $20,2($20) +L.352: +move $2,$20 +L.327: +lw $20,16($sp) +lw $21,20($sp) +lw $22,24($sp) +lw $23,28($sp) +lw $25,32($sp) +lw $30,36($sp) +lw $31,40($sp) +addu $sp,$sp,112 +j $31 +.end s244 +.data +.align 0 +L.357: +.byte 115 +.byte 50 +.byte 53 +.byte 44 +.byte 101 +.byte 114 +.byte 37 +.byte 100 +.byte 10 +.byte 0 +.sdata +.align 0 +L.358: +.byte 115 +.byte 50 +.byte 53 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 0 +.globl s25 +.text +.text +.align 2 +.ent s25 +s25: +.frame $sp,64,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-64 +.mask 0xc2fe0000,-12 +sw $17,16($sp) +sw $18,20($sp) +sw $19,24($sp) +sw $20,28($sp) +sw $21,32($sp) +sw $22,36($sp) +sw $23,40($sp) +.cprestore 44 +sw $30,48($sp) +sw $31,52($sp) +move $30,$4 +la $20,L.358 +la $19,60($30) +L.359: +L.360: +move $24,$19 +la $19,1($24) +move $15,$20 +la $20,1($15) +lb $15,($15) +sb $15,($24) +sll $24,$15,8*(4-1); sra $24,$24,8*(4-1) +bne $24,$0,L.359 +move $18,$0 +la $22,L.362 +lb $24,1($22) +lb $15,($22) +bne $15,$24,L.366 +lb $15,2($22) +bne $24,$15,L.366 +la $24,46 +beq $15,$24,L.363 +L.366: +la $18,1($18) +lw $24,44($30) +beq $24,$0,L.367 +la $4,L.357 +la $5,1 +jal printf +L.367: +L.363: +lb $24,3($22) +beq $24,$0,L.369 +la $18,4($18) +lw $24,44($30) +beq $24,$0,L.371 +la $4,L.357 +la $5,4 +jal printf +L.371: +L.369: +lb $24,L.375+1 +la $15,34 +beq $24,$15,L.373 +la $18,8($18) +lw $24,44($30) +beq $24,$0,L.377 +la $4,L.357 +la $5,8 +jal printf +L.377: +L.373: +la $22,L.379 +lb $24,($22) +la $15,10 +bne $24,$15,L.387 +lb $24,1($22) +la $15,9 +bne $24,$15,L.387 +lb $24,2($22) +la $15,8 +bne $24,$15,L.387 +lb $24,3($22) +la $15,13 +bne $24,$15,L.387 +lb $24,4($22) +la $15,12 +bne $24,$15,L.387 +lb $24,5($22) +la $15,92 +bne $24,$15,L.387 +lb $24,6($22) +la $15,39 +beq $24,$15,L.380 +L.387: +la $18,16($18) +lw $24,44($30) +beq $24,$0,L.388 +la $4,L.357 +la $5,16 +jal printf +L.388: +L.380: +la $24,L.390 +move $21,$24 +move $22,$24 +move $17,$0 +move $23,$0 +b L.394 +L.391: +addu $24,$23,$22 +lb $24,($24) +addu $15,$23,$21 +lb $15,($15) +beq $24,$15,L.395 +la $17,1 +L.395: +L.392: +la $23,1($23) +L.394: +move $24,$23 +la $15,7 +bltu $24,$15,L.391 +beq $17,$0,L.397 +la $18,32($18) +lw $24,44($30) +beq $24,$0,L.399 +la $4,L.357 +la $5,32 +jal printf +L.399: +L.397: +move $2,$18 +L.356: +lw $17,16($sp) +lw $18,20($sp) +lw $19,24($sp) +lw $20,28($sp) +lw $21,32($sp) +lw $22,36($sp) +lw $23,40($sp) +lw $25,44($sp) +lw $30,48($sp) +lw $31,52($sp) +addu $sp,$sp,64 +j $31 +.end s25 +.sdata +.align 0 +L.402: +.byte 115 +.byte 50 +.byte 54 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 0 +.data +.align 0 +L.403: +.byte 37 +.byte 51 +.byte 100 +.byte 32 +.byte 98 +.byte 105 +.byte 116 +.byte 115 +.byte 32 +.byte 105 +.byte 110 +.byte 32 +.byte 37 +.byte 115 +.byte 115 +.byte 46 +.byte 10 +.byte 0 +.data +.align 0 +L.404: +.byte 37 +.byte 101 +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 116 +.byte 104 +.byte 101 +.byte 32 +.byte 108 +.byte 101 +.byte 97 +.byte 115 +.byte 116 +.byte 32 +.byte 110 +.byte 117 +.byte 109 +.byte 98 +.byte 101 +.byte 114 +.byte 32 +.byte 116 +.byte 104 +.byte 97 +.byte 116 +.byte 32 +.byte 99 +.byte 97 +.byte 110 +.byte 32 +.byte 98 +.byte 101 +.byte 32 +.byte 97 +.byte 100 +.byte 100 +.byte 101 +.byte 100 +.byte 32 +.byte 116 +.byte 111 +.byte 32 +.byte 49 +.byte 46 +.byte 32 +.byte 40 +.byte 37 +.byte 115 +.byte 41 +.byte 46 +.byte 10 +.byte 0 +.globl s26 +.text +.text +.align 2 +.ent s26 +s26: +.frame $sp,96,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-96 +.fmask 0xffc00000,-40 +.mask 0xc2f00000,-8 +s.d $f22,24($sp) +s.d $f24,32($sp) +s.d $f26,40($sp) +s.d $f28,48($sp) +s.d $f30,56($sp) +sw $20,64($sp) +sw $21,68($sp) +sw $22,72($sp) +sw $23,76($sp) +.cprestore 80 +sw $30,84($sp) +sw $31,88($sp) +move $30,$4 +la $22,L.402 +la $21,60($30) +L.405: +L.406: +move $24,$21 +la $21,1($24) +move $15,$22 +la $22,1($15) +lb $15,($15) +sb $15,($24) +sll $24,$15,8*(4-1); sra $24,$24,8*(4-1) +bne $24,$0,L.405 +sw $0,($30) +move $20,$0 +la $23,1 +b L.409 +L.408: +sll $24,$23,8*(4-1); sra $24,$24,8*(4-1) +sll $24,$24,1 +move $23,$24 +lw $24,($30) +la $24,1($24) +sw $24,($30) +L.409: +sll $24,$20,8*(4-1); sra $24,$24,8*(4-1) +sll $15,$23,8*(4-1); sra $15,$15,8*(4-1) +bne $24,$15,L.408 +lw $24,($30) +sll $24,$24,2 +sw $24,4($30) +lw $24,($30) +sll $24,$24,1 +sw $24,8($30) +lw $24,($30) +sll $24,$24,2 +sw $24,12($30) +lw $24,($30) +sll $24,$24,2 +sw $24,16($30) +lw $24,($30) +sll $24,$24,2 +sw $24,20($30) +lw $24,($30) +sll $24,$24,3 +sw $24,24($30) +l.s $f18,L.411 +mov.s $f26,$f18 +mov.s $f30,$f18 +l.s $f28,L.412 +b L.414 +L.413: +add.s $f28,$f26,$f30 +cvt.d.s $f18,$f30 +l.d $f16,L.416 +div.d $f18,$f18,$f16 +cvt.s.d $f30,$f18 +L.414: +c.eq.s $f28,$f26; bc1f L.413 +l.d $f18,L.417 +cvt.d.s $f16,$f30 +mul.d $f18,$f18,$f16 +cvt.s.d $f18,$f18 +s.s $f18,28($30) +l.d $f22,L.418 +l.s $f30,L.411 +l.d $f24,L.419 +b L.421 +L.420: +cvt.d.s $f18,$f30 +add.d $f24,$f22,$f18 +l.d $f16,L.416 +div.d $f18,$f18,$f16 +cvt.s.d $f30,$f18 +L.421: +c.eq.d $f24,$f22; bc1f L.420 +l.d $f18,L.417 +cvt.d.s $f16,$f30 +mul.d $f18,$f18,$f16 +cvt.s.d $f18,$f18 +s.s $f18,32($30) +lw $24,40($30) +beq $24,$0,L.423 +la $4,L.403 +lw $5,($30) +la $6,L.425 +jal printf +la $4,L.403 +lw $5,4($30) +la $6,L.426 +jal printf +la $4,L.403 +lw $5,8($30) +la $6,L.427 +jal printf +la $4,L.403 +lw $5,12($30) +la $6,L.428 +jal printf +la $4,L.403 +lw $5,16($30) +la $6,L.429 +jal printf +la $4,L.403 +lw $5,20($30) +la $6,L.430 +jal printf +la $4,L.403 +lw $5,24($30) +la $6,L.431 +jal printf +la $4,L.404 +l.s $f18,28($30) +cvt.d.s $f18,$f18 +mfc1.d $6,$f18 +la $24,L.430 +sw $24,16($sp) +jal printf +la $4,L.404 +l.s $f18,32($30) +cvt.d.s $f18,$f18 +mfc1.d $6,$f18 +la $24,L.431 +sw $24,16($sp) +jal printf +L.423: +move $2,$0 +L.401: +l.d $f22,24($sp) +l.d $f24,32($sp) +l.d $f26,40($sp) +l.d $f28,48($sp) +l.d $f30,56($sp) +lw $20,64($sp) +lw $21,68($sp) +lw $22,72($sp) +lw $23,76($sp) +lw $25,80($sp) +lw $30,84($sp) +lw $31,88($sp) +addu $sp,$sp,96 +j $31 +.end s26 +.data +.align 0 +L.433: +.byte 115 +.byte 52 +.byte 44 +.byte 101 +.byte 114 +.byte 37 +.byte 100 +.byte 10 +.byte 0 +.sdata +.align 0 +L.434: +.byte 115 +.byte 52 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 0 +.globl s4 +.text +.text +.align 2 +.ent s4 +s4: +.frame $sp,80,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-80 +.mask 0xc2fc0000,-32 +sw $18,16($sp) +sw $19,20($sp) +sw $20,24($sp) +sw $21,28($sp) +sw $22,32($sp) +sw $23,36($sp) +.cprestore 40 +sw $30,44($sp) +sw $31,48($sp) +move $30,$4 +move $18,$0 +la $20,L.434 +la $19,60($30) +L.435: +L.436: +move $24,$19 +la $19,1($24) +move $15,$20 +la $20,1($15) +lb $15,($15) +sb $15,($24) +sll $24,$15,8*(4-1); sra $24,$24,8*(4-1) +bne $24,$0,L.435 +move $23,$0 +L.438: +move $4,$23 +jal svtest +move $24,$2 +sw $24,-16+80($sp) +jal zero +lw $15,-16+80($sp) +beq $15,$2,L.442 +la $18,1 +lw $24,44($30) +beq $24,$0,L.444 +la $4,L.433 +la $5,1 +jal printf +L.444: +L.442: +L.439: +la $23,1($23) +la $24,3 +blt $23,$24,L.438 +jal setev +jal testev +beq $2,$0,L.446 +la $18,2($18) +lw $24,44($30) +beq $24,$0,L.448 +la $4,L.433 +la $5,2 +jal printf +L.448: +L.446: +b L.450 +la $18,4($18) +lw $24,44($30) +beq $24,$0,L.452 +la $4,L.433 +la $5,4 +jal printf +L.452: +L.450: +la $22,0xffffffff +la $21,1 +move $23,$0 +b L.457 +L.454: +and $21,$21,$22 +srl $22,$22,1 +L.455: +la $23,1($23) +L.457: +move $24,$23 +lw $15,($30) +sll $15,$15,2 +bltu $24,$15,L.454 +la $24,1 +bne $21,$24,L.460 +beq $22,$0,L.458 +L.460: +la $18,8($18) +lw $24,44($30) +beq $24,$0,L.461 +la $4,L.433 +la $5,8 +jal printf +L.461: +L.458: +move $2,$18 +L.432: +lw $18,16($sp) +lw $19,20($sp) +lw $20,24($sp) +lw $21,28($sp) +lw $22,32($sp) +lw $23,36($sp) +lw $25,40($sp) +lw $30,44($sp) +lw $31,48($sp) +addu $sp,$sp,80 +j $31 +.end s4 +.lcomm L.464,4 +.globl svtest +.text +.text +.align 2 +.ent svtest +svtest: +.frame $sp,16,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-16 +beq $4,$0,L.467 +la $24,1 +beq $4,$24,L.468 +la $24,2 +beq $4,$24,L.471 +b L.465 +L.467: +la $24,1978 +sw $24,L.464 +sw $0,-4+16($sp) +b L.466 +L.468: +lw $24,L.464 +la $15,1978 +beq $24,$15,L.469 +la $24,1 +sw $24,-4+16($sp) +b L.466 +L.469: +la $24,1929 +sw $24,L.464 +sw $0,-4+16($sp) +b L.466 +L.471: +lw $24,L.464 +la $15,1929 +beq $24,$15,L.472 +la $24,1 +sw $24,-4+16($sp) +b L.466 +L.472: +sw $0,-4+16($sp) +L.465: +L.466: +lw $2,-4+16($sp) +L.463: +addu $sp,$sp,16 +j $31 +.end svtest +.lcomm L.475,4 +.globl zero +.text +.text +.align 2 +.ent zero +zero: +.frame $sp,16,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-16 +la $24,2 +sw $24,L.475 +sw $0,-4+16($sp) +lw $2,-4+16($sp) +L.474: +addu $sp,$sp,16 +j $31 +.end zero +.globl testev +.text +.align 2 +.ent testev +testev: +.frame $sp,0,$31 +.set noreorder +.cpload $25 +.set reorder +lw $24,extvar +la $15,1066 +beq $24,$15,L.477 +la $2,1 +b L.476 +L.477: +move $2,$0 +L.476: +j $31 +.end testev +.data +.align 0 +L.480: +.byte 115 +.byte 54 +.byte 49 +.byte 44 +.byte 101 +.byte 114 +.byte 37 +.byte 100 +.byte 10 +.byte 0 +.sdata +.align 0 +L.481: +.byte 115 +.byte 54 +.byte 49 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 0 +.data +.align 0 +L.482: +.byte 65 +.byte 66 +.byte 67 +.byte 68 +.byte 69 +.byte 70 +.byte 71 +.byte 72 +.byte 73 +.byte 74 +.byte 75 +.byte 76 +.byte 77 +.byte 78 +.byte 79 +.byte 80 +.byte 81 +.byte 82 +.byte 83 +.byte 84 +.byte 85 +.byte 86 +.byte 87 +.byte 88 +.byte 89 +.byte 90 +.byte 0 +.data +.align 0 +L.483: +.byte 97 +.byte 98 +.byte 99 +.byte 100 +.byte 101 +.byte 102 +.byte 103 +.byte 104 +.byte 105 +.byte 106 +.byte 107 +.byte 108 +.byte 109 +.byte 110 +.byte 111 +.byte 112 +.byte 113 +.byte 114 +.byte 115 +.byte 116 +.byte 117 +.byte 118 +.byte 119 +.byte 120 +.byte 121 +.byte 122 +.byte 0 +.data +.align 0 +L.484: +.byte 48 +.byte 49 +.byte 50 +.byte 51 +.byte 52 +.byte 53 +.byte 54 +.byte 55 +.byte 56 +.byte 57 +.byte 0 +.data +.align 0 +L.485: +.byte 126 +.byte 33 +.byte 34 +.byte 35 +.byte 37 +.byte 38 +.byte 40 +.byte 41 +.byte 95 +.byte 61 +.byte 45 +.byte 94 +.byte 124 +.byte 123 +.byte 125 +.byte 91 +.byte 93 +.byte 43 +.byte 59 +.byte 42 +.byte 58 +.byte 60 +.byte 62 +.byte 44 +.byte 46 +.byte 63 +.byte 47 +.byte 0 +.data +.align 0 +L.486: +.byte 10 +.byte 9 +.byte 8 +.byte 13 +.byte 12 +.byte 92 +.byte 39 +.byte 0 +.data +.align 0 +L.487: +.byte 32 +.byte 0 +.byte 0 +.globl s61 +.text +.text +.align 2 +.ent s61 +s61: +.frame $sp,96,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-96 +.mask 0xc2fe0000,-44 +sw $17,16($sp) +sw $18,20($sp) +sw $19,24($sp) +sw $20,28($sp) +sw $21,32($sp) +sw $22,36($sp) +sw $23,40($sp) +.cprestore 44 +sw $30,48($sp) +sw $31,52($sp) +sw $4,96($sp) +la $22,L.481 +lw $24,0+96($sp) +la $21,60($24) +move $19,$0 +L.488: +L.489: +move $24,$21 +la $21,1($24) +move $15,$22 +la $22,1($15) +lb $15,($15) +sb $15,($24) +sll $24,$15,8*(4-1); sra $24,$24,8*(4-1) +bne $24,$0,L.488 +la $24,-19 +sh $24,-26+96($sp) +lh $24,-26+96($sp) +sw $24,-32+96($sp) +lw $24,-32+96($sp) +la $15,-19 +beq $24,$15,L.491 +la $19,1($19) +lw $24,0+96($sp) +lw $24,44($24) +beq $24,$0,L.493 +la $4,L.480 +la $5,1 +jal printf +L.493: +L.491: +la $24,L.482 +sw $24,-24+96($sp) +la $24,L.483 +sw $24,-20+96($sp) +la $24,L.484 +sw $24,-16+96($sp) +la $24,L.485 +sw $24,-12+96($sp) +la $24,L.486 +sw $24,-8+96($sp) +la $24,L.487 +sw $24,-4+96($sp) +move $23,$0 +move $30,$0 +b L.505 +L.504: +sll $24,$30,2 +la $15,-24+96($sp) +addu $24,$24,$15 +lw $15,($24) +la $14,1($15) +sw $14,($24) +lb $24,($15) +bge $24,$0,L.507 +la $23,1 +L.507: +L.505: +sll $24,$30,2 +la $15,-24+96($sp) +addu $24,$24,$15 +lw $24,($24) +lb $24,($24) +bne $24,$0,L.504 +L.501: +la $30,1($30) +la $24,6 +blt $30,$24,L.505 +beq $23,$0,L.509 +la $19,2($19) +lw $24,0+96($sp) +lw $24,44($24) +beq $24,$0,L.511 +la $4,L.480 +la $5,2 +jal printf +L.511: +L.509: +la $20,1048579 +move $18,$20 +move $17,$20 +sll $24,$18,8*(4-2); sra $24,$24,8*(4-2) +beq $24,$20,L.516 +la $15,3 +bne $24,$15,L.515 +L.516: +sll $24,$17,8*(4-1); sra $24,$24,8*(4-1) +beq $24,$20,L.513 +la $15,3 +beq $24,$15,L.513 +L.515: +la $19,8($19) +lw $24,0+96($sp) +lw $24,44($24) +beq $24,$0,L.517 +la $4,L.480 +la $5,8 +jal printf +L.517: +L.513: +move $2,$19 +L.479: +lw $17,16($sp) +lw $18,20($sp) +lw $19,24($sp) +lw $20,28($sp) +lw $21,32($sp) +lw $22,36($sp) +lw $23,40($sp) +lw $25,44($sp) +lw $30,48($sp) +lw $31,52($sp) +addu $sp,$sp,96 +j $31 +.end s61 +.data +.align 0 +L.520: +.byte 115 +.byte 54 +.byte 50 +.byte 54 +.byte 44 +.byte 101 +.byte 114 +.byte 37 +.byte 100 +.byte 10 +.byte 0 +.sdata +.align 0 +L.521: +.byte 115 +.byte 54 +.byte 50 +.byte 54 +.byte 32 +.byte 32 +.byte 32 +.byte 0 +.globl s626 +.text +.text +.align 2 +.ent s626 +s626: +.frame $sp,160,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-160 +.fmask 0xff000000,-120 +.mask 0xc2ff0000,-72 +s.d $f24,16($sp) +s.d $f26,24($sp) +s.d $f28,32($sp) +s.d $f30,40($sp) +sw $16,48($sp) +sw $17,52($sp) +sw $18,56($sp) +sw $19,60($sp) +sw $20,64($sp) +sw $21,68($sp) +sw $22,72($sp) +sw $23,76($sp) +.cprestore 80 +sw $30,84($sp) +sw $31,88($sp) +move $30,$4 +la $20,L.521 +la $19,60($30) +sw $0,-52+160($sp) +L.522: +L.523: +move $24,$19 +la $19,1($24) +move $15,$20 +la $20,1($15) +lb $15,($15) +sb $15,($24) +sll $24,$15,8*(4-1); sra $24,$24,8*(4-1) +bne $24,$0,L.522 +l.s $f30,L.411 +la $24,1 +move $18,$24 +move $22,$24 +move $23,$0 +b L.528 +L.525: +l.s $f18,L.529 +mul.s $f30,$f18,$f30 +sll $24,$22,1 +or $22,$24,$18 +L.526: +la $23,1($23) +L.528: +lw $24,12($30) +subu $24,$24,2 +blt $23,$24,L.525 +mtc1 $22,$f18; cvt.s.w $f18,$f18 +s.s $f18,-60+160($sp) +l.s $f18,-60+160($sp) +sub.s $f18,$f30,$f18 +div.s $f30,$f18,$f30 +cvt.d.s $f18,$f30 +l.d $f16,L.416 +l.s $f10,28($30) +cvt.d.s $f10,$f10 +mul.d $f16,$f16,$f10 +c.ule.d $f18,$f16; bc1t L.530 +lw $24,-52+160($sp) +la $24,2($24) +sw $24,-52+160($sp) +lw $24,44($30) +beq $24,$0,L.532 +la $4,L.520 +la $5,2 +jal printf +L.532: +L.530: +la $16,125 +la $24,125 +sh $24,-30+160($sp) +la $24,125 +sw $24,-36+160($sp) +la $24,15625 +sw $24,-44+160($sp) +la $24,125 +sw $24,-40+160($sp) +la $24,15625 +sw $24,-48+160($sp) +la $17,125 +la $24,15625 +sw $24,-56+160($sp) +l.s $f26,L.534 +l.d $f24,L.535 +l.d $f28,L.536 +move $23,$0 +L.537: +la $24,-28+160($sp) +addu $24,$23,$24 +sb $0,($24) +L.538: +la $23,1($23) +la $24,28 +blt $23,$24,L.537 +sll $24,$16,8*(4-1); sra $24,$24,8*(4-1) +mul $24,$24,$24 +lw $15,-44+160($sp) +beq $24,$15,L.541 +la $24,1 +sb $24,-28+160($sp) +L.541: +lh $24,-30+160($sp) +sll $15,$16,8*(4-1); sra $15,$15,8*(4-1) +mul $24,$24,$15 +lw $15,-44+160($sp) +beq $24,$15,L.543 +la $24,1 +sb $24,-27+160($sp) +L.543: +lh $24,-30+160($sp) +mul $24,$24,$24 +lw $15,-44+160($sp) +beq $24,$15,L.546 +la $24,1 +sb $24,-26+160($sp) +L.546: +lw $24,-36+160($sp) +sll $15,$16,8*(4-1); sra $15,$15,8*(4-1) +mul $24,$24,$15 +lw $15,-44+160($sp) +beq $24,$15,L.549 +la $24,1 +sb $24,-25+160($sp) +L.549: +lw $24,-36+160($sp) +lh $15,-30+160($sp) +mul $24,$24,$15 +lw $15,-44+160($sp) +beq $24,$15,L.552 +la $24,1 +sb $24,-24+160($sp) +L.552: +lw $24,-36+160($sp) +mul $24,$24,$24 +lw $15,-44+160($sp) +beq $24,$15,L.555 +la $24,1 +sb $24,-23+160($sp) +L.555: +lw $24,-40+160($sp) +sll $15,$16,8*(4-1); sra $15,$15,8*(4-1) +mul $24,$24,$15 +lw $15,-48+160($sp) +beq $24,$15,L.558 +la $24,1 +sb $24,-22+160($sp) +L.558: +lw $24,-40+160($sp) +lh $15,-30+160($sp) +mul $24,$24,$15 +lw $15,-48+160($sp) +beq $24,$15,L.561 +la $24,1 +sb $24,-21+160($sp) +L.561: +lw $24,-40+160($sp) +lw $15,-36+160($sp) +mul $24,$24,$15 +lw $15,-48+160($sp) +beq $24,$15,L.564 +la $24,1 +sb $24,-20+160($sp) +L.564: +lw $24,-40+160($sp) +mul $24,$24,$24 +lw $15,-48+160($sp) +beq $24,$15,L.567 +la $24,1 +sb $24,-19+160($sp) +L.567: +sll $24,$16,8*(4-1); sra $24,$24,8*(4-1) +mul $24,$17,$24 +lw $15,-56+160($sp) +beq $24,$15,L.570 +la $24,1 +sb $24,-18+160($sp) +L.570: +lh $24,-30+160($sp) +mul $24,$17,$24 +lw $15,-56+160($sp) +beq $24,$15,L.573 +la $24,1 +sb $24,-17+160($sp) +L.573: +lw $24,-36+160($sp) +mul $24,$17,$24 +lw $15,-56+160($sp) +beq $24,$15,L.576 +la $24,1 +sb $24,-16+160($sp) +L.576: +move $24,$17 +lw $15,-40+160($sp) +mul $24,$24,$15 +lw $15,-48+160($sp) +beq $24,$15,L.579 +la $24,1 +sb $24,-15+160($sp) +L.579: +mul $24,$17,$17 +lw $15,-56+160($sp) +beq $24,$15,L.582 +la $24,1 +sb $24,-14+160($sp) +L.582: +sll $24,$16,8*(4-1); sra $24,$24,8*(4-1) +mtc1 $24,$f18; cvt.s.w $f18,$f18 +mul.s $f18,$f26,$f18 +cvt.d.s $f18,$f18 +c.eq.d $f18,$f28; bc1t L.585 +la $24,1 +sb $24,-13+160($sp) +L.585: +lh $24,-30+160($sp) +mtc1 $24,$f18; cvt.s.w $f18,$f18 +mul.s $f18,$f26,$f18 +cvt.d.s $f18,$f18 +c.eq.d $f18,$f28; bc1t L.588 +la $24,1 +sb $24,-12+160($sp) +L.588: +lw $24,-36+160($sp) +mtc1 $24,$f18; cvt.s.w $f18,$f18 +mul.s $f18,$f26,$f18 +cvt.d.s $f18,$f18 +c.eq.d $f18,$f28; bc1t L.591 +la $24,1 +sb $24,-11+160($sp) +L.591: +lw $24,-40+160($sp) +l.d $f18,L.596 +srl $15,$24,1 +mtc1 $15,$f16; cvt.d.w $f16,$f16 +mul.d $f18,$f18,$f16 +and $24,$24,1 +mtc1 $24,$f16; cvt.d.w $f16,$f16 +add.d $f18,$f18,$f16 +cvt.s.d $f18,$f18 +mul.s $f18,$f26,$f18 +cvt.d.s $f18,$f18 +c.eq.d $f18,$f28; bc1t L.594 +la $24,1 +sb $24,-10+160($sp) +L.594: +mtc1 $17,$f18; cvt.s.w $f18,$f18 +mul.s $f18,$f26,$f18 +cvt.d.s $f18,$f18 +c.eq.d $f18,$f28; bc1t L.598 +la $24,1 +sb $24,-9+160($sp) +L.598: +mul.s $f18,$f26,$f26 +cvt.d.s $f18,$f18 +c.eq.d $f18,$f28; bc1t L.601 +la $24,1 +sb $24,-8+160($sp) +L.601: +sll $24,$16,8*(4-1); sra $24,$24,8*(4-1) +mtc1 $24,$f18; cvt.d.w $f18,$f18 +mul.d $f18,$f24,$f18 +c.eq.d $f18,$f28; bc1t L.604 +la $24,1 +sb $24,-7+160($sp) +L.604: +lh $24,-30+160($sp) +mtc1 $24,$f18; cvt.d.w $f18,$f18 +mul.d $f18,$f24,$f18 +c.eq.d $f18,$f28; bc1t L.607 +la $24,1 +sb $24,-6+160($sp) +L.607: +lw $24,-36+160($sp) +mtc1 $24,$f18; cvt.d.w $f18,$f18 +mul.d $f18,$f24,$f18 +c.eq.d $f18,$f28; bc1t L.610 +la $24,1 +sb $24,-5+160($sp) +L.610: +lw $24,-40+160($sp) +l.d $f18,L.596 +srl $15,$24,1 +mtc1 $15,$f16; cvt.d.w $f16,$f16 +mul.d $f18,$f18,$f16 +and $24,$24,1 +mtc1 $24,$f16; cvt.d.w $f16,$f16 +add.d $f18,$f18,$f16 +mul.d $f18,$f24,$f18 +c.eq.d $f18,$f28; bc1t L.613 +la $24,1 +sb $24,-4+160($sp) +L.613: +mtc1 $17,$f18; cvt.d.w $f18,$f18 +mul.d $f18,$f24,$f18 +c.eq.d $f18,$f28; bc1t L.616 +la $24,1 +sb $24,-3+160($sp) +L.616: +cvt.d.s $f18,$f26 +mul.d $f18,$f24,$f18 +c.eq.d $f18,$f28; bc1t L.619 +la $24,1 +sb $24,-2+160($sp) +L.619: +mul.d $f18,$f24,$f24 +c.eq.d $f18,$f28; bc1t L.622 +la $24,1 +sb $24,-1+160($sp) +L.622: +move $21,$0 +move $23,$0 +L.625: +sll $24,$21,8*(4-1); sra $24,$24,8*(4-1) +la $15,-28+160($sp) +addu $15,$23,$15 +lb $15,($15) +addu $24,$24,$15 +move $21,$24 +L.626: +la $23,1($23) +la $24,28 +blt $23,$24,L.625 +sll $24,$21,8*(4-1); sra $24,$24,8*(4-1) +beq $24,$0,L.629 +lw $24,-52+160($sp) +la $24,4($24) +sw $24,-52+160($sp) +lw $24,44($30) +beq $24,$0,L.631 +la $4,L.520 +la $5,4 +jal printf +la $4,L.633 +jal printf +move $23,$0 +L.634: +la $4,L.638 +la $24,-28+160($sp) +addu $24,$23,$24 +lb $5,($24) +jal printf +L.635: +la $23,1($23) +la $24,28 +blt $23,$24,L.634 +la $4,L.639 +jal printf +L.631: +L.629: +la $17,32768 +move $24,$17 +la $15,0x8000 +bleu $24,$15,L.640 +lw $24,-52+160($sp) +la $24,8($24) +sw $24,-52+160($sp) +lw $24,44($30) +beq $24,$0,L.642 +la $4,L.520 +la $5,8 +jal printf +L.642: +L.640: +lw $2,-52+160($sp) +L.519: +l.d $f24,16($sp) +l.d $f26,24($sp) +l.d $f28,32($sp) +l.d $f30,40($sp) +lw $16,48($sp) +lw $17,52($sp) +lw $18,56($sp) +lw $19,60($sp) +lw $20,64($sp) +lw $21,68($sp) +lw $22,72($sp) +lw $23,76($sp) +lw $25,80($sp) +lw $30,84($sp) +lw $31,88($sp) +addu $sp,$sp,160 +j $31 +.end s626 +.data +.align 0 +L.645: +.byte 115 +.byte 55 +.byte 49 +.byte 44 +.byte 101 +.byte 114 +.byte 37 +.byte 100 +.byte 10 +.byte 0 +.sdata +.align 0 +L.646: +.byte 115 +.byte 55 +.byte 49 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 0 +.sdata +.align 0 +L.647: +.byte 0x71 +.globl s71 +.text +.text +.align 2 +.ent s71 +s71: +.frame $sp,96,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-96 +.mask 0xc2f00000,-56 +sw $20,16($sp) +sw $21,20($sp) +sw $22,24($sp) +sw $23,28($sp) +.cprestore 32 +sw $30,36($sp) +sw $31,40($sp) +move $30,$4 +la $23,L.646 +la $22,60($30) +move $21,$0 +L.648: +L.649: +move $24,$22 +la $22,1($24) +move $15,$23 +la $23,1($15) +lb $15,($15) +sb $15,($24) +sll $24,$15,8*(4-1); sra $24,$24,8*(4-1) +bne $24,$0,L.648 +lb $24,L.653 +lb $15,L.647 +beq $24,$15,L.651 +la $21,1($21) +lw $24,44($30) +beq $24,$0,L.654 +la $4,L.645 +la $5,1 +jal printf +L.654: +L.651: +b L.656 +la $21,2($21) +lw $24,44($30) +beq $24,$0,L.658 +la $4,L.645 +la $5,2 +jal printf +L.658: +L.656: +la $24,1942 +sw $24,-20+96($sp) +lw $24,-20+96($sp) +la $15,1942 +bne $24,$15,L.666 +lw $24,-20+96($sp) +lw $15,-20+96($sp) +beq $24,$15,L.661 +L.666: +la $21,4($21) +lw $24,44($30) +beq $24,$0,L.667 +la $4,L.645 +la $5,4 +jal printf +L.667: +L.661: +la $4,-5 +jal McCarthy +la $15,91 +beq $2,$15,L.669 +la $21,8($21) +lw $24,44($30) +beq $24,$0,L.671 +la $4,L.645 +la $5,8 +jal printf +L.671: +L.669: +la $20,2 +la $24,3 +sw $24,-44+96($sp) +la $24,-44+96($sp) +sw $24,-48+96($sp) +move $4,$20 +lw $5,-48+96($sp) +jal clobber +la $24,2 +bne $20,$24,L.675 +lw $15,-44+96($sp) +beq $15,$24,L.673 +L.675: +la $21,16($21) +lw $24,44($30) +beq $24,$0,L.676 +la $4,L.645 +la $5,16 +jal printf +L.676: +L.673: +l.s $f18,32($30) +c.eq.s $f18,$f18; bc1t L.678 +la $21,32($21) +lw $24,44($30) +beq $24,$0,L.680 +la $4,L.645 +la $5,32 +jal printf +L.680: +L.678: +move $2,$21 +L.644: +lw $20,16($sp) +lw $21,20($sp) +lw $22,24($sp) +lw $23,28($sp) +lw $25,32($sp) +lw $30,36($sp) +lw $31,40($sp) +addu $sp,$sp,96 +j $31 +.end s71 +.globl McCarthy +.text +.align 2 +.ent McCarthy +McCarthy: +.frame $sp,32,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-32 +.mask 0x82000000,-12 +.cprestore 16 +sw $31,20($sp) +sw $4,32($sp) +lw $24,0+32($sp) +la $15,100 +ble $24,$15,L.683 +lw $24,0+32($sp) +subu $2,$24,10 +b L.682 +L.683: +lw $24,0+32($sp) +la $4,11($24) +jal McCarthy +move $24,$2 +move $4,$24 +jal McCarthy +move $24,$2 +L.682: +lw $25,16($sp) +lw $31,20($sp) +addu $sp,$sp,32 +j $31 +.end McCarthy +.globl clobber +.text +.align 2 +.ent clobber +clobber: +.frame $sp,0,$31 +.set noreorder +.cpload $25 +.set reorder +la $4,3 +la $24,2 +sw $24,($5) +move $2,$0 +L.685: +j $31 +.end clobber +.data +.align 0 +L.687: +.byte 76 +.byte 111 +.byte 99 +.byte 97 +.byte 108 +.byte 32 +.byte 101 +.byte 114 +.byte 114 +.byte 111 +.byte 114 +.byte 32 +.byte 37 +.byte 100 +.byte 46 +.byte 10 +.byte 0 +.data +.align 0 +L.688: +.byte 115 +.byte 55 +.byte 49 +.byte 52 +.byte 44 +.byte 101 +.byte 114 +.byte 37 +.byte 100 +.byte 10 +.byte 0 +.sdata +.align 0 +L.689: +.byte 115 +.byte 55 +.byte 49 +.byte 52 +.byte 32 +.byte 32 +.byte 32 +.byte 0 +.globl s714 +.text +.text +.align 2 +.ent s714 +s714: +.frame $sp,160,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-160 +.fmask 0xff000000,-120 +.mask 0xc2ff0000,-72 +s.d $f24,16($sp) +s.d $f26,24($sp) +s.d $f28,32($sp) +s.d $f30,40($sp) +sw $16,48($sp) +sw $17,52($sp) +sw $18,56($sp) +sw $19,60($sp) +sw $20,64($sp) +sw $21,68($sp) +sw $22,72($sp) +sw $23,76($sp) +.cprestore 80 +sw $30,84($sp) +sw $31,88($sp) +sw $4,160($sp) +la $24,L.689 +sw $24,-16+160($sp) +lw $24,0+160($sp) +la $15,60($24) +sw $15,-20+160($sp) +sw $0,-24+160($sp) +move $23,$0 +lw $30,48($24) +L.690: +L.691: +lw $24,-20+160($sp) +la $15,1($24) +sw $15,-20+160($sp) +lw $15,-16+160($sp) +la $14,1($15) +sw $14,-16+160($sp) +lb $15,($15) +sb $15,($24) +sll $24,$15,8*(4-1); sra $24,$24,8*(4-1) +bne $24,$0,L.690 +la $22,5 +la $17,2 +move $22,$17 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +la $15,2 +beq $24,$15,L.693 +la $23,1 +beq $30,$0,L.695 +la $4,L.687 +move $5,$23 +jal printf +L.695: +L.693: +la $22,5 +la $16,2 +sll $24,$16,8*(4-2); sra $24,$24,8*(4-2) +move $22,$24 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +la $15,2 +beq $24,$15,L.697 +la $23,2 +beq $30,$0,L.699 +la $4,L.687 +move $5,$23 +jal printf +L.699: +L.697: +la $22,5 +la $24,2 +sw $24,-4+160($sp) +lw $15,-4+160($sp) +move $22,$15 +sll $15,$22,8*(4-1); sra $15,$15,8*(4-1) +beq $15,$24,L.701 +la $23,3 +beq $30,$0,L.703 +la $4,L.687 +move $5,$23 +jal printf +L.703: +L.701: +la $22,5 +la $24,2 +sw $24,-8+160($sp) +lw $24,-8+160($sp) +move $22,$24 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +la $15,2 +beq $24,$15,L.705 +la $23,4 +beq $30,$0,L.707 +la $4,L.687 +move $5,$23 +jal printf +L.707: +L.705: +la $22,5 +la $24,2 +sw $24,-12+160($sp) +lw $24,-12+160($sp) +move $22,$24 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +la $15,2 +beq $24,$15,L.709 +la $23,5 +beq $30,$0,L.711 +la $4,L.687 +move $5,$23 +jal printf +L.711: +L.709: +la $22,5 +l.s $f26,L.529 +trunc.w.s $f2,$f26,$24; mfc1 $24,$f2 +move $22,$24 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +la $15,2 +beq $24,$15,L.713 +la $23,6 +beq $30,$0,L.715 +la $4,L.687 +move $5,$23 +jal printf +L.715: +L.713: +la $22,5 +l.d $f24,L.416 +trunc.w.d $f2,$f24,$24; mfc1 $24,$f2 +move $22,$24 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +la $15,2 +beq $24,$15,L.717 +la $23,7 +beq $30,$0,L.719 +la $4,L.687 +move $5,$23 +jal printf +L.719: +L.717: +la $21,5 +la $17,2 +sll $24,$17,8*(4-1); sra $24,$24,8*(4-1) +move $21,$24 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +la $15,2 +beq $24,$15,L.721 +la $23,8 +beq $30,$0,L.723 +la $4,L.687 +move $5,$23 +jal printf +L.723: +L.721: +la $21,5 +la $16,2 +move $21,$16 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +la $15,2 +beq $24,$15,L.725 +la $23,9 +beq $30,$0,L.727 +la $4,L.687 +move $5,$23 +jal printf +L.727: +L.725: +la $21,5 +la $24,2 +sw $24,-4+160($sp) +lw $15,-4+160($sp) +move $21,$15 +sll $15,$21,8*(4-2); sra $15,$15,8*(4-2) +beq $15,$24,L.729 +la $23,10 +beq $30,$0,L.731 +la $4,L.687 +move $5,$23 +jal printf +L.731: +L.729: +la $21,5 +la $24,2 +sw $24,-8+160($sp) +lw $24,-8+160($sp) +move $21,$24 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +la $15,2 +beq $24,$15,L.733 +la $23,11 +beq $30,$0,L.735 +la $4,L.687 +move $5,$23 +jal printf +L.735: +L.733: +la $21,5 +la $24,2 +sw $24,-12+160($sp) +lw $24,-12+160($sp) +move $21,$24 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +la $15,2 +beq $24,$15,L.737 +la $23,12 +beq $30,$0,L.739 +la $4,L.687 +move $5,$23 +jal printf +L.739: +L.737: +la $21,5 +l.s $f26,L.529 +trunc.w.s $f2,$f26,$24; mfc1 $24,$f2 +move $21,$24 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +la $15,2 +beq $24,$15,L.741 +la $23,13 +beq $30,$0,L.743 +la $4,L.687 +move $5,$23 +jal printf +L.743: +L.741: +la $21,5 +l.d $f24,L.416 +trunc.w.d $f2,$f24,$24; mfc1 $24,$f2 +move $21,$24 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +la $15,2 +beq $24,$15,L.745 +la $23,14 +beq $30,$0,L.747 +la $4,L.687 +move $5,$23 +jal printf +L.747: +L.745: +la $20,5 +la $17,2 +sll $20,$17,8*(4-1); sra $20,$20,8*(4-1) +la $24,2 +beq $20,$24,L.749 +la $23,15 +beq $30,$0,L.751 +la $4,L.687 +move $5,$23 +jal printf +L.751: +L.749: +la $20,5 +la $16,2 +sll $20,$16,8*(4-2); sra $20,$20,8*(4-2) +la $24,2 +beq $20,$24,L.753 +la $23,16 +beq $30,$0,L.755 +la $4,L.687 +move $5,$23 +jal printf +L.755: +L.753: +la $20,5 +la $24,2 +sw $24,-4+160($sp) +lw $20,-4+160($sp) +beq $20,$24,L.757 +la $23,17 +beq $30,$0,L.759 +la $4,L.687 +move $5,$23 +jal printf +L.759: +L.757: +la $20,5 +la $24,2 +sw $24,-8+160($sp) +lw $20,-8+160($sp) +la $24,2 +beq $20,$24,L.761 +la $23,18 +beq $30,$0,L.763 +la $4,L.687 +move $5,$23 +jal printf +L.763: +L.761: +la $20,5 +la $24,2 +sw $24,-12+160($sp) +lw $24,-12+160($sp) +move $20,$24 +la $24,2 +beq $20,$24,L.765 +la $23,19 +beq $30,$0,L.767 +la $4,L.687 +move $5,$23 +jal printf +L.767: +L.765: +la $20,5 +l.s $f26,L.529 +trunc.w.s $f2,$f26,$20; mfc1 $20,$f2 +la $24,2 +beq $20,$24,L.769 +la $23,20 +beq $30,$0,L.771 +la $4,L.687 +move $5,$23 +jal printf +L.771: +L.769: +la $20,5 +l.d $f24,L.416 +trunc.w.d $f2,$f24,$20; mfc1 $20,$f2 +la $24,2 +beq $20,$24,L.773 +la $23,21 +beq $30,$0,L.775 +la $4,L.687 +move $5,$23 +jal printf +L.775: +L.773: +la $19,5 +la $17,2 +sll $19,$17,8*(4-1); sra $19,$19,8*(4-1) +la $24,2 +beq $19,$24,L.777 +la $23,22 +beq $30,$0,L.779 +la $4,L.687 +move $5,$23 +jal printf +L.779: +L.777: +la $19,5 +la $16,2 +sll $19,$16,8*(4-2); sra $19,$19,8*(4-2) +la $24,2 +beq $19,$24,L.781 +la $23,23 +beq $30,$0,L.783 +la $4,L.687 +move $5,$23 +jal printf +L.783: +L.781: +la $19,5 +la $24,2 +sw $24,-4+160($sp) +lw $19,-4+160($sp) +la $24,2 +beq $19,$24,L.785 +la $23,24 +beq $30,$0,L.787 +la $4,L.687 +move $5,$23 +jal printf +L.787: +L.785: +la $19,5 +la $24,2 +sw $24,-8+160($sp) +lw $19,-8+160($sp) +beq $19,$24,L.789 +la $23,25 +beq $30,$0,L.791 +la $4,L.687 +move $5,$23 +jal printf +L.791: +L.789: +la $19,5 +la $24,2 +sw $24,-12+160($sp) +lw $24,-12+160($sp) +move $19,$24 +la $24,2 +beq $19,$24,L.793 +la $23,26 +beq $30,$0,L.795 +la $4,L.687 +move $5,$23 +jal printf +L.795: +L.793: +la $19,5 +l.s $f26,L.529 +trunc.w.s $f2,$f26,$19; mfc1 $19,$f2 +la $24,2 +beq $19,$24,L.797 +la $23,27 +beq $30,$0,L.799 +la $4,L.687 +move $5,$23 +jal printf +L.799: +L.797: +la $19,5 +l.d $f24,L.416 +trunc.w.d $f2,$f24,$19; mfc1 $19,$f2 +la $24,2 +beq $19,$24,L.801 +la $23,28 +beq $30,$0,L.803 +la $4,L.687 +move $5,$23 +jal printf +L.803: +L.801: +la $18,5 +la $17,2 +sll $24,$17,8*(4-1); sra $24,$24,8*(4-1) +move $18,$24 +la $24,2 +beq $18,$24,L.805 +la $23,29 +beq $30,$0,L.807 +la $4,L.687 +move $5,$23 +jal printf +L.807: +L.805: +la $18,5 +la $16,2 +sll $24,$16,8*(4-2); sra $24,$24,8*(4-2) +move $18,$24 +la $24,2 +beq $18,$24,L.809 +la $23,30 +beq $30,$0,L.811 +la $4,L.687 +move $5,$23 +jal printf +L.811: +L.809: +la $18,5 +la $24,2 +sw $24,-4+160($sp) +lw $24,-4+160($sp) +move $18,$24 +la $24,2 +beq $18,$24,L.813 +la $23,31 +beq $30,$0,L.815 +la $4,L.687 +move $5,$23 +jal printf +L.815: +L.813: +la $18,5 +la $24,2 +sw $24,-8+160($sp) +lw $24,-8+160($sp) +move $18,$24 +la $24,2 +beq $18,$24,L.817 +la $23,32 +beq $30,$0,L.819 +la $4,L.687 +move $5,$23 +jal printf +L.819: +L.817: +la $18,5 +la $24,2 +sw $24,-12+160($sp) +lw $18,-12+160($sp) +beq $18,$24,L.821 +la $23,33 +beq $30,$0,L.823 +la $4,L.687 +move $5,$23 +jal printf +L.823: +L.821: +la $18,5 +l.s $f26,L.529 +l.s $f18,L.828 +c.ult.s $f26,$f18; bc1t L.826 +sub.s $f18,$f26,$f18 +trunc.w.s $f2,$f18,$24; mfc1 $24,$f2 +la $24,0x80000000($24) +sw $24,-28+160($sp) +b L.827 +L.826: +trunc.w.s $f2,$f26,$24; mfc1 $24,$f2 +sw $24,-28+160($sp) +L.827: +lw $18,-28+160($sp) +la $24,2 +beq $18,$24,L.829 +la $23,34 +beq $30,$0,L.831 +la $4,L.687 +move $5,$23 +jal printf +L.831: +L.829: +la $18,5 +l.d $f24,L.416 +l.d $f18,L.836 +c.ult.d $f24,$f18; bc1t L.834 +sub.d $f18,$f24,$f18 +trunc.w.d $f2,$f18,$24; mfc1 $24,$f2 +la $24,0x80000000($24) +sw $24,-32+160($sp) +b L.835 +L.834: +trunc.w.d $f2,$f24,$24; mfc1 $24,$f2 +sw $24,-32+160($sp) +L.835: +lw $18,-32+160($sp) +la $24,2 +beq $18,$24,L.837 +la $23,35 +beq $30,$0,L.839 +la $4,L.687 +move $5,$23 +jal printf +L.839: +L.837: +l.s $f30,L.841 +la $17,2 +sll $24,$17,8*(4-1); sra $24,$24,8*(4-1) +mtc1 $24,$f30; cvt.s.w $f30,$f30 +l.s $f18,L.529 +c.eq.s $f30,$f18; bc1t L.842 +la $23,36 +beq $30,$0,L.844 +la $4,L.687 +move $5,$23 +jal printf +L.844: +L.842: +l.s $f30,L.841 +la $16,2 +sll $24,$16,8*(4-2); sra $24,$24,8*(4-2) +mtc1 $24,$f30; cvt.s.w $f30,$f30 +l.s $f18,L.529 +c.eq.s $f30,$f18; bc1t L.846 +la $23,37 +beq $30,$0,L.848 +la $4,L.687 +move $5,$23 +jal printf +L.848: +L.846: +l.s $f30,L.841 +la $24,2 +sw $24,-4+160($sp) +lw $24,-4+160($sp) +mtc1 $24,$f30; cvt.s.w $f30,$f30 +l.s $f18,L.529 +c.eq.s $f30,$f18; bc1t L.850 +la $23,38 +beq $30,$0,L.852 +la $4,L.687 +move $5,$23 +jal printf +L.852: +L.850: +l.s $f30,L.841 +la $24,2 +sw $24,-8+160($sp) +lw $24,-8+160($sp) +mtc1 $24,$f30; cvt.s.w $f30,$f30 +l.s $f18,L.529 +c.eq.s $f30,$f18; bc1t L.854 +la $23,39 +beq $30,$0,L.856 +la $4,L.687 +move $5,$23 +jal printf +L.856: +L.854: +l.s $f30,L.841 +la $24,2 +sw $24,-12+160($sp) +lw $24,-12+160($sp) +l.d $f18,L.596 +srl $15,$24,1 +mtc1 $15,$f16; cvt.d.w $f16,$f16 +mul.d $f18,$f18,$f16 +and $24,$24,1 +mtc1 $24,$f16; cvt.d.w $f16,$f16 +add.d $f18,$f18,$f16 +cvt.s.d $f30,$f18 +l.s $f18,L.529 +c.eq.s $f30,$f18; bc1t L.858 +la $23,40 +beq $30,$0,L.860 +la $4,L.687 +move $5,$23 +jal printf +L.860: +L.858: +l.s $f30,L.841 +l.s $f18,L.529 +mov.s $f26,$f18 +mov.s $f30,$f26 +c.eq.s $f30,$f18; bc1t L.862 +la $23,41 +beq $30,$0,L.864 +la $4,L.687 +move $5,$23 +jal printf +L.864: +L.862: +l.s $f30,L.841 +l.d $f24,L.416 +cvt.s.d $f30,$f24 +l.s $f18,L.529 +c.eq.s $f30,$f18; bc1t L.866 +la $23,42 +beq $30,$0,L.868 +la $4,L.687 +move $5,$23 +jal printf +L.868: +L.866: +l.d $f28,L.870 +la $17,2 +sll $24,$17,8*(4-1); sra $24,$24,8*(4-1) +mtc1 $24,$f28; cvt.d.w $f28,$f28 +l.d $f18,L.416 +c.eq.d $f28,$f18; bc1t L.871 +la $23,43 +beq $30,$0,L.873 +la $4,L.687 +move $5,$23 +jal printf +L.873: +L.871: +l.d $f28,L.870 +la $16,2 +sll $24,$16,8*(4-2); sra $24,$24,8*(4-2) +mtc1 $24,$f28; cvt.d.w $f28,$f28 +l.d $f18,L.416 +c.eq.d $f28,$f18; bc1t L.875 +la $23,44 +beq $30,$0,L.877 +la $4,L.687 +move $5,$23 +jal printf +L.877: +L.875: +l.d $f28,L.870 +la $24,2 +sw $24,-4+160($sp) +lw $24,-4+160($sp) +mtc1 $24,$f28; cvt.d.w $f28,$f28 +l.d $f18,L.416 +c.eq.d $f28,$f18; bc1t L.879 +la $23,45 +beq $30,$0,L.881 +la $4,L.687 +move $5,$23 +jal printf +L.881: +L.879: +l.d $f28,L.870 +la $24,2 +sw $24,-8+160($sp) +lw $24,-8+160($sp) +mtc1 $24,$f28; cvt.d.w $f28,$f28 +l.d $f18,L.416 +c.eq.d $f28,$f18; bc1t L.883 +la $23,46 +beq $30,$0,L.885 +la $4,L.687 +move $5,$23 +jal printf +L.885: +L.883: +l.d $f28,L.870 +la $24,2 +sw $24,-12+160($sp) +lw $24,-12+160($sp) +l.d $f18,L.596 +srl $15,$24,1 +mtc1 $15,$f16; cvt.d.w $f16,$f16 +mul.d $f18,$f18,$f16 +and $24,$24,1 +mtc1 $24,$f16; cvt.d.w $f16,$f16 +add.d $f28,$f18,$f16 +l.d $f18,L.416 +c.eq.d $f28,$f18; bc1t L.887 +la $23,47 +beq $30,$0,L.889 +la $4,L.687 +move $5,$23 +jal printf +L.889: +L.887: +l.d $f28,L.870 +l.s $f26,L.529 +cvt.d.s $f28,$f26 +l.d $f18,L.416 +c.eq.d $f28,$f18; bc1t L.891 +la $23,48 +beq $30,$0,L.893 +la $4,L.687 +move $5,$23 +jal printf +L.893: +L.891: +l.d $f28,L.870 +l.d $f18,L.416 +mov.d $f24,$f18 +mov.d $f28,$f24 +c.eq.d $f28,$f18; bc1t L.895 +la $23,49 +beq $30,$0,L.897 +la $4,L.687 +move $5,$23 +jal printf +L.897: +L.895: +la $22,5 +la $17,2 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +sll $15,$17,8*(4-1); sra $15,$15,8*(4-1) +addu $24,$24,$15 +move $22,$24 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +la $15,7 +beq $24,$15,L.899 +la $23,50 +beq $30,$0,L.901 +la $4,L.687 +move $5,$23 +jal printf +L.901: +L.899: +la $22,5 +la $16,2 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +sll $15,$16,8*(4-2); sra $15,$15,8*(4-2) +addu $24,$24,$15 +move $22,$24 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +la $15,7 +beq $24,$15,L.903 +la $23,51 +beq $30,$0,L.905 +la $4,L.687 +move $5,$23 +jal printf +L.905: +L.903: +la $22,5 +la $24,2 +sw $24,-4+160($sp) +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +lw $15,-4+160($sp) +addu $24,$24,$15 +move $22,$24 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +la $15,7 +beq $24,$15,L.907 +la $23,52 +beq $30,$0,L.909 +la $4,L.687 +move $5,$23 +jal printf +L.909: +L.907: +la $22,5 +la $24,2 +sw $24,-8+160($sp) +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +lw $15,-8+160($sp) +addu $24,$24,$15 +move $22,$24 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +la $15,7 +beq $24,$15,L.911 +la $23,53 +beq $30,$0,L.913 +la $4,L.687 +move $5,$23 +jal printf +L.913: +L.911: +la $22,5 +la $24,2 +sw $24,-12+160($sp) +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +lw $15,-12+160($sp) +addu $24,$24,$15 +move $22,$24 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +la $15,7 +beq $24,$15,L.915 +la $23,54 +beq $30,$0,L.917 +la $4,L.687 +move $5,$23 +jal printf +L.917: +L.915: +la $22,5 +l.s $f26,L.529 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +mtc1 $24,$f18; cvt.s.w $f18,$f18 +add.s $f18,$f18,$f26 +trunc.w.s $f2,$f18,$24; mfc1 $24,$f2 +move $22,$24 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +la $15,7 +beq $24,$15,L.919 +la $23,55 +beq $30,$0,L.921 +la $4,L.687 +move $5,$23 +jal printf +L.921: +L.919: +la $22,5 +l.d $f24,L.416 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +mtc1 $24,$f18; cvt.d.w $f18,$f18 +add.d $f18,$f18,$f24 +trunc.w.d $f2,$f18,$24; mfc1 $24,$f2 +move $22,$24 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +la $15,7 +beq $24,$15,L.923 +la $23,56 +beq $30,$0,L.925 +la $4,L.687 +move $5,$23 +jal printf +L.925: +L.923: +la $21,5 +la $17,2 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +sll $15,$17,8*(4-1); sra $15,$15,8*(4-1) +addu $24,$24,$15 +move $21,$24 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +la $15,7 +beq $24,$15,L.927 +la $23,57 +beq $30,$0,L.929 +la $4,L.687 +move $5,$23 +jal printf +L.929: +L.927: +la $21,5 +la $16,2 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +sll $15,$16,8*(4-2); sra $15,$15,8*(4-2) +addu $24,$24,$15 +move $21,$24 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +la $15,7 +beq $24,$15,L.931 +la $23,58 +beq $30,$0,L.933 +la $4,L.687 +move $5,$23 +jal printf +L.933: +L.931: +la $21,5 +la $24,2 +sw $24,-4+160($sp) +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +lw $15,-4+160($sp) +addu $24,$24,$15 +move $21,$24 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +la $15,7 +beq $24,$15,L.935 +la $23,59 +beq $30,$0,L.937 +la $4,L.687 +move $5,$23 +jal printf +L.937: +L.935: +la $21,5 +la $24,2 +sw $24,-8+160($sp) +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +lw $15,-8+160($sp) +addu $24,$24,$15 +move $21,$24 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +la $15,7 +beq $24,$15,L.939 +la $23,60 +beq $30,$0,L.941 +la $4,L.687 +move $5,$23 +jal printf +L.941: +L.939: +la $21,5 +la $24,2 +sw $24,-12+160($sp) +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +lw $15,-12+160($sp) +addu $24,$24,$15 +move $21,$24 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +la $15,7 +beq $24,$15,L.943 +la $23,61 +beq $30,$0,L.945 +la $4,L.687 +move $5,$23 +jal printf +L.945: +L.943: +la $21,5 +l.s $f26,L.529 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +mtc1 $24,$f18; cvt.s.w $f18,$f18 +add.s $f18,$f18,$f26 +trunc.w.s $f2,$f18,$24; mfc1 $24,$f2 +move $21,$24 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +la $15,7 +beq $24,$15,L.947 +la $23,62 +beq $30,$0,L.949 +la $4,L.687 +move $5,$23 +jal printf +L.949: +L.947: +la $21,5 +l.d $f24,L.416 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +mtc1 $24,$f18; cvt.d.w $f18,$f18 +add.d $f18,$f18,$f24 +trunc.w.d $f2,$f18,$24; mfc1 $24,$f2 +move $21,$24 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +la $15,7 +beq $24,$15,L.951 +la $23,63 +beq $30,$0,L.953 +la $4,L.687 +move $5,$23 +jal printf +L.953: +L.951: +la $20,5 +la $17,2 +sll $24,$17,8*(4-1); sra $24,$24,8*(4-1) +addu $20,$20,$24 +la $24,7 +beq $20,$24,L.955 +la $23,64 +beq $30,$0,L.957 +la $4,L.687 +move $5,$23 +jal printf +L.957: +L.955: +la $20,5 +la $16,2 +sll $24,$16,8*(4-2); sra $24,$24,8*(4-2) +addu $20,$20,$24 +la $24,7 +beq $20,$24,L.959 +la $23,65 +beq $30,$0,L.961 +la $4,L.687 +move $5,$23 +jal printf +L.961: +L.959: +la $20,5 +la $24,2 +sw $24,-4+160($sp) +lw $24,-4+160($sp) +addu $20,$20,$24 +la $24,7 +beq $20,$24,L.963 +la $23,66 +beq $30,$0,L.965 +la $4,L.687 +move $5,$23 +jal printf +L.965: +L.963: +la $20,5 +la $24,2 +sw $24,-8+160($sp) +lw $24,-8+160($sp) +addu $20,$20,$24 +la $24,7 +beq $20,$24,L.967 +la $23,67 +beq $30,$0,L.969 +la $4,L.687 +move $5,$23 +jal printf +L.969: +L.967: +la $20,5 +la $24,2 +sw $24,-12+160($sp) +move $24,$20 +lw $15,-12+160($sp) +addu $24,$24,$15 +move $20,$24 +la $24,7 +beq $20,$24,L.971 +la $23,68 +beq $30,$0,L.973 +la $4,L.687 +move $5,$23 +jal printf +L.973: +L.971: +la $20,5 +l.s $f26,L.529 +mtc1 $20,$f18; cvt.s.w $f18,$f18 +add.s $f18,$f18,$f26 +trunc.w.s $f2,$f18,$20; mfc1 $20,$f2 +la $24,7 +beq $20,$24,L.975 +la $23,69 +beq $30,$0,L.977 +la $4,L.687 +move $5,$23 +jal printf +L.977: +L.975: +la $20,5 +l.d $f24,L.416 +mtc1 $20,$f18; cvt.d.w $f18,$f18 +add.d $f18,$f18,$f24 +trunc.w.d $f2,$f18,$20; mfc1 $20,$f2 +la $24,7 +beq $20,$24,L.979 +la $23,70 +beq $30,$0,L.981 +la $4,L.687 +move $5,$23 +jal printf +L.981: +L.979: +la $19,5 +la $17,2 +sll $24,$17,8*(4-1); sra $24,$24,8*(4-1) +addu $19,$19,$24 +la $24,7 +beq $19,$24,L.983 +la $23,71 +beq $30,$0,L.985 +la $4,L.687 +move $5,$23 +jal printf +L.985: +L.983: +la $19,5 +la $16,2 +sll $24,$16,8*(4-2); sra $24,$24,8*(4-2) +addu $19,$19,$24 +la $24,7 +beq $19,$24,L.987 +la $23,72 +beq $30,$0,L.989 +la $4,L.687 +move $5,$23 +jal printf +L.989: +L.987: +la $19,5 +la $24,2 +sw $24,-4+160($sp) +lw $24,-4+160($sp) +addu $19,$19,$24 +la $24,7 +beq $19,$24,L.991 +la $23,73 +beq $30,$0,L.993 +la $4,L.687 +move $5,$23 +jal printf +L.993: +L.991: +la $19,5 +la $24,2 +sw $24,-8+160($sp) +lw $24,-8+160($sp) +addu $19,$19,$24 +la $24,7 +beq $19,$24,L.995 +la $23,74 +beq $30,$0,L.997 +la $4,L.687 +move $5,$23 +jal printf +L.997: +L.995: +la $19,5 +la $24,2 +sw $24,-12+160($sp) +move $24,$19 +lw $15,-12+160($sp) +addu $24,$24,$15 +move $19,$24 +la $24,7 +beq $19,$24,L.999 +la $23,75 +beq $30,$0,L.1001 +la $4,L.687 +move $5,$23 +jal printf +L.1001: +L.999: +la $19,5 +l.s $f26,L.529 +mtc1 $19,$f18; cvt.s.w $f18,$f18 +add.s $f18,$f18,$f26 +trunc.w.s $f2,$f18,$19; mfc1 $19,$f2 +la $24,7 +beq $19,$24,L.1003 +la $23,76 +beq $30,$0,L.1005 +la $4,L.687 +move $5,$23 +jal printf +L.1005: +L.1003: +la $19,5 +l.d $f24,L.416 +mtc1 $19,$f18; cvt.d.w $f18,$f18 +add.d $f18,$f18,$f24 +trunc.w.d $f2,$f18,$19; mfc1 $19,$f2 +la $24,7 +beq $19,$24,L.1007 +la $23,77 +beq $30,$0,L.1009 +la $4,L.687 +move $5,$23 +jal printf +L.1009: +L.1007: +la $18,5 +la $17,2 +sll $24,$17,8*(4-1); sra $24,$24,8*(4-1) +addu $18,$18,$24 +la $24,7 +beq $18,$24,L.1011 +la $23,78 +beq $30,$0,L.1013 +la $4,L.687 +move $5,$23 +jal printf +L.1013: +L.1011: +la $18,5 +la $16,2 +sll $24,$16,8*(4-2); sra $24,$24,8*(4-2) +addu $18,$18,$24 +la $24,7 +beq $18,$24,L.1015 +la $23,79 +beq $30,$0,L.1017 +la $4,L.687 +move $5,$23 +jal printf +L.1017: +L.1015: +la $18,5 +la $24,2 +sw $24,-4+160($sp) +lw $24,-4+160($sp) +addu $18,$18,$24 +la $24,7 +beq $18,$24,L.1019 +la $23,80 +beq $30,$0,L.1021 +la $4,L.687 +move $5,$23 +jal printf +L.1021: +L.1019: +la $18,5 +la $24,2 +sw $24,-8+160($sp) +lw $24,-8+160($sp) +addu $18,$18,$24 +la $24,7 +beq $18,$24,L.1023 +la $23,81 +beq $30,$0,L.1025 +la $4,L.687 +move $5,$23 +jal printf +L.1025: +L.1023: +la $18,5 +la $24,2 +sw $24,-12+160($sp) +lw $24,-12+160($sp) +addu $18,$18,$24 +la $24,7 +beq $18,$24,L.1027 +la $23,82 +beq $30,$0,L.1029 +la $4,L.687 +move $5,$23 +jal printf +L.1029: +L.1027: +la $18,5 +l.s $f26,L.529 +l.d $f18,L.596 +srl $24,$18,1 +mtc1 $24,$f16; cvt.d.w $f16,$f16 +mul.d $f18,$f18,$f16 +and $24,$18,1 +mtc1 $24,$f16; cvt.d.w $f16,$f16 +add.d $f18,$f18,$f16 +cvt.s.d $f18,$f18 +add.s $f18,$f18,$f26 +l.s $f16,L.828 +c.ult.s $f18,$f16; bc1t L.1032 +sub.s $f16,$f18,$f16 +trunc.w.s $f2,$f16,$24; mfc1 $24,$f2 +la $24,0x80000000($24) +sw $24,-36+160($sp) +b L.1033 +L.1032: +trunc.w.s $f2,$f18,$24; mfc1 $24,$f2 +sw $24,-36+160($sp) +L.1033: +lw $18,-36+160($sp) +la $24,7 +beq $18,$24,L.1034 +la $23,83 +beq $30,$0,L.1036 +la $4,L.687 +move $5,$23 +jal printf +L.1036: +L.1034: +la $18,5 +l.d $f24,L.416 +l.d $f18,L.596 +srl $24,$18,1 +mtc1 $24,$f16; cvt.d.w $f16,$f16 +mul.d $f18,$f18,$f16 +and $24,$18,1 +mtc1 $24,$f16; cvt.d.w $f16,$f16 +add.d $f18,$f18,$f16 +add.d $f18,$f18,$f24 +l.d $f16,L.836 +c.ult.d $f18,$f16; bc1t L.1039 +sub.d $f16,$f18,$f16 +trunc.w.d $f2,$f16,$24; mfc1 $24,$f2 +la $24,0x80000000($24) +sw $24,-40+160($sp) +b L.1040 +L.1039: +trunc.w.d $f2,$f18,$24; mfc1 $24,$f2 +sw $24,-40+160($sp) +L.1040: +lw $18,-40+160($sp) +la $24,7 +beq $18,$24,L.1041 +la $23,84 +beq $30,$0,L.1043 +la $4,L.687 +move $5,$23 +jal printf +L.1043: +L.1041: +l.s $f30,L.841 +la $17,2 +sll $24,$17,8*(4-1); sra $24,$24,8*(4-1) +mtc1 $24,$f18; cvt.s.w $f18,$f18 +add.s $f30,$f30,$f18 +l.s $f18,L.1047 +c.eq.s $f30,$f18; bc1t L.1045 +la $23,85 +beq $30,$0,L.1048 +la $4,L.687 +move $5,$23 +jal printf +L.1048: +L.1045: +l.s $f30,L.841 +la $16,2 +sll $24,$16,8*(4-2); sra $24,$24,8*(4-2) +mtc1 $24,$f18; cvt.s.w $f18,$f18 +add.s $f30,$f30,$f18 +l.s $f18,L.1047 +c.eq.s $f30,$f18; bc1t L.1050 +la $23,86 +beq $30,$0,L.1052 +la $4,L.687 +move $5,$23 +jal printf +L.1052: +L.1050: +l.s $f30,L.841 +la $24,2 +sw $24,-4+160($sp) +lw $24,-4+160($sp) +mtc1 $24,$f18; cvt.s.w $f18,$f18 +add.s $f30,$f30,$f18 +l.s $f18,L.1047 +c.eq.s $f30,$f18; bc1t L.1054 +la $23,87 +beq $30,$0,L.1056 +la $4,L.687 +move $5,$23 +jal printf +L.1056: +L.1054: +l.s $f30,L.841 +la $24,2 +sw $24,-8+160($sp) +lw $24,-8+160($sp) +mtc1 $24,$f18; cvt.s.w $f18,$f18 +add.s $f30,$f30,$f18 +l.s $f18,L.1047 +c.eq.s $f30,$f18; bc1t L.1058 +la $23,88 +beq $30,$0,L.1060 +la $4,L.687 +move $5,$23 +jal printf +L.1060: +L.1058: +l.s $f30,L.841 +la $24,2 +sw $24,-12+160($sp) +lw $24,-12+160($sp) +l.d $f18,L.596 +srl $15,$24,1 +mtc1 $15,$f16; cvt.d.w $f16,$f16 +mul.d $f18,$f18,$f16 +and $24,$24,1 +mtc1 $24,$f16; cvt.d.w $f16,$f16 +add.d $f18,$f18,$f16 +cvt.s.d $f18,$f18 +add.s $f30,$f30,$f18 +l.s $f18,L.1047 +c.eq.s $f30,$f18; bc1t L.1062 +la $23,89 +beq $30,$0,L.1064 +la $4,L.687 +move $5,$23 +jal printf +L.1064: +L.1062: +l.s $f30,L.841 +l.s $f26,L.529 +add.s $f30,$f30,$f26 +l.s $f18,L.1047 +c.eq.s $f30,$f18; bc1t L.1066 +la $23,90 +beq $30,$0,L.1068 +la $4,L.687 +move $5,$23 +jal printf +L.1068: +L.1066: +l.s $f30,L.841 +l.d $f24,L.416 +cvt.d.s $f18,$f30 +add.d $f18,$f18,$f24 +cvt.s.d $f30,$f18 +l.s $f18,L.1047 +c.eq.s $f30,$f18; bc1t L.1070 +la $23,91 +beq $30,$0,L.1072 +la $4,L.687 +move $5,$23 +jal printf +L.1072: +L.1070: +l.d $f28,L.870 +la $17,2 +sll $24,$17,8*(4-1); sra $24,$24,8*(4-1) +mtc1 $24,$f18; cvt.d.w $f18,$f18 +add.d $f28,$f28,$f18 +l.d $f18,L.1076 +c.eq.d $f28,$f18; bc1t L.1074 +la $23,92 +beq $30,$0,L.1077 +la $4,L.687 +move $5,$23 +jal printf +L.1077: +L.1074: +l.d $f28,L.870 +la $16,2 +sll $24,$16,8*(4-2); sra $24,$24,8*(4-2) +mtc1 $24,$f18; cvt.d.w $f18,$f18 +add.d $f28,$f28,$f18 +l.d $f18,L.1076 +c.eq.d $f28,$f18; bc1t L.1079 +la $23,93 +beq $30,$0,L.1081 +la $4,L.687 +move $5,$23 +jal printf +L.1081: +L.1079: +l.d $f28,L.870 +la $24,2 +sw $24,-4+160($sp) +lw $24,-4+160($sp) +mtc1 $24,$f18; cvt.d.w $f18,$f18 +add.d $f28,$f28,$f18 +l.d $f18,L.1076 +c.eq.d $f28,$f18; bc1t L.1083 +la $23,94 +beq $30,$0,L.1085 +la $4,L.687 +move $5,$23 +jal printf +L.1085: +L.1083: +l.d $f28,L.870 +la $24,2 +sw $24,-8+160($sp) +lw $24,-8+160($sp) +mtc1 $24,$f18; cvt.d.w $f18,$f18 +add.d $f28,$f28,$f18 +l.d $f18,L.1076 +c.eq.d $f28,$f18; bc1t L.1087 +la $23,95 +beq $30,$0,L.1089 +la $4,L.687 +move $5,$23 +jal printf +L.1089: +L.1087: +l.d $f28,L.870 +la $24,2 +sw $24,-12+160($sp) +lw $24,-12+160($sp) +l.d $f18,L.596 +srl $15,$24,1 +mtc1 $15,$f16; cvt.d.w $f16,$f16 +mul.d $f18,$f18,$f16 +and $24,$24,1 +mtc1 $24,$f16; cvt.d.w $f16,$f16 +add.d $f18,$f18,$f16 +add.d $f28,$f28,$f18 +l.d $f18,L.1076 +c.eq.d $f28,$f18; bc1t L.1091 +la $23,96 +beq $30,$0,L.1093 +la $4,L.687 +move $5,$23 +jal printf +L.1093: +L.1091: +l.d $f28,L.870 +l.s $f26,L.529 +cvt.d.s $f18,$f26 +add.d $f28,$f28,$f18 +l.d $f18,L.1076 +c.eq.d $f28,$f18; bc1t L.1095 +la $23,97 +beq $30,$0,L.1097 +la $4,L.687 +move $5,$23 +jal printf +L.1097: +L.1095: +l.d $f28,L.870 +l.d $f24,L.416 +add.d $f28,$f28,$f24 +l.d $f18,L.1076 +c.eq.d $f28,$f18; bc1t L.1099 +la $23,98 +beq $30,$0,L.1101 +la $4,L.687 +move $5,$23 +jal printf +L.1101: +L.1099: +la $22,5 +la $17,2 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +sll $15,$17,8*(4-1); sra $15,$15,8*(4-1) +subu $24,$24,$15 +move $22,$24 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +la $15,3 +beq $24,$15,L.1103 +la $23,99 +beq $30,$0,L.1105 +la $4,L.687 +move $5,$23 +jal printf +L.1105: +L.1103: +la $22,5 +la $16,2 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +sll $15,$16,8*(4-2); sra $15,$15,8*(4-2) +subu $24,$24,$15 +move $22,$24 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +la $15,3 +beq $24,$15,L.1107 +la $23,100 +beq $30,$0,L.1109 +la $4,L.687 +move $5,$23 +jal printf +L.1109: +L.1107: +la $22,5 +la $24,2 +sw $24,-4+160($sp) +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +lw $15,-4+160($sp) +subu $24,$24,$15 +move $22,$24 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +la $15,3 +beq $24,$15,L.1111 +la $23,101 +beq $30,$0,L.1113 +la $4,L.687 +move $5,$23 +jal printf +L.1113: +L.1111: +la $22,5 +la $24,2 +sw $24,-8+160($sp) +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +lw $15,-8+160($sp) +subu $24,$24,$15 +move $22,$24 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +la $15,3 +beq $24,$15,L.1115 +la $23,102 +beq $30,$0,L.1117 +la $4,L.687 +move $5,$23 +jal printf +L.1117: +L.1115: +la $22,5 +la $24,2 +sw $24,-12+160($sp) +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +lw $15,-12+160($sp) +subu $24,$24,$15 +move $22,$24 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +la $15,3 +beq $24,$15,L.1119 +la $23,103 +beq $30,$0,L.1121 +la $4,L.687 +move $5,$23 +jal printf +L.1121: +L.1119: +la $22,5 +l.s $f26,L.529 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +mtc1 $24,$f18; cvt.s.w $f18,$f18 +sub.s $f18,$f18,$f26 +trunc.w.s $f2,$f18,$24; mfc1 $24,$f2 +move $22,$24 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +la $15,3 +beq $24,$15,L.1123 +la $23,104 +beq $30,$0,L.1125 +la $4,L.687 +move $5,$23 +jal printf +L.1125: +L.1123: +la $22,5 +l.d $f24,L.416 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +mtc1 $24,$f18; cvt.d.w $f18,$f18 +sub.d $f18,$f18,$f24 +trunc.w.d $f2,$f18,$24; mfc1 $24,$f2 +move $22,$24 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +la $15,3 +beq $24,$15,L.1127 +la $23,105 +beq $30,$0,L.1129 +la $4,L.687 +move $5,$23 +jal printf +L.1129: +L.1127: +la $21,5 +la $17,2 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +sll $15,$17,8*(4-1); sra $15,$15,8*(4-1) +subu $24,$24,$15 +move $21,$24 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +la $15,3 +beq $24,$15,L.1131 +la $23,106 +beq $30,$0,L.1133 +la $4,L.687 +move $5,$23 +jal printf +L.1133: +L.1131: +la $21,5 +la $16,2 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +sll $15,$16,8*(4-2); sra $15,$15,8*(4-2) +subu $24,$24,$15 +move $21,$24 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +la $15,3 +beq $24,$15,L.1135 +la $23,107 +beq $30,$0,L.1137 +la $4,L.687 +move $5,$23 +jal printf +L.1137: +L.1135: +la $21,5 +la $24,2 +sw $24,-4+160($sp) +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +lw $15,-4+160($sp) +subu $24,$24,$15 +move $21,$24 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +la $15,3 +beq $24,$15,L.1139 +la $23,108 +beq $30,$0,L.1141 +la $4,L.687 +move $5,$23 +jal printf +L.1141: +L.1139: +la $21,5 +la $24,2 +sw $24,-8+160($sp) +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +lw $15,-8+160($sp) +subu $24,$24,$15 +move $21,$24 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +la $15,3 +beq $24,$15,L.1143 +la $23,109 +beq $30,$0,L.1145 +la $4,L.687 +move $5,$23 +jal printf +L.1145: +L.1143: +la $21,5 +la $24,2 +sw $24,-12+160($sp) +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +lw $15,-12+160($sp) +subu $24,$24,$15 +move $21,$24 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +la $15,3 +beq $24,$15,L.1147 +la $23,110 +beq $30,$0,L.1149 +la $4,L.687 +move $5,$23 +jal printf +L.1149: +L.1147: +la $21,5 +l.s $f26,L.529 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +mtc1 $24,$f18; cvt.s.w $f18,$f18 +sub.s $f18,$f18,$f26 +trunc.w.s $f2,$f18,$24; mfc1 $24,$f2 +move $21,$24 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +la $15,3 +beq $24,$15,L.1151 +la $23,111 +beq $30,$0,L.1153 +la $4,L.687 +move $5,$23 +jal printf +L.1153: +L.1151: +la $21,5 +l.d $f24,L.416 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +mtc1 $24,$f18; cvt.d.w $f18,$f18 +sub.d $f18,$f18,$f24 +trunc.w.d $f2,$f18,$24; mfc1 $24,$f2 +move $21,$24 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +la $15,3 +beq $24,$15,L.1155 +la $23,112 +beq $30,$0,L.1157 +la $4,L.687 +move $5,$23 +jal printf +L.1157: +L.1155: +la $20,5 +la $17,2 +sll $24,$17,8*(4-1); sra $24,$24,8*(4-1) +subu $20,$20,$24 +la $24,3 +beq $20,$24,L.1159 +la $23,113 +beq $30,$0,L.1161 +la $4,L.687 +move $5,$23 +jal printf +L.1161: +L.1159: +la $20,5 +la $16,2 +sll $24,$16,8*(4-2); sra $24,$24,8*(4-2) +subu $20,$20,$24 +la $24,3 +beq $20,$24,L.1163 +la $23,114 +beq $30,$0,L.1165 +la $4,L.687 +move $5,$23 +jal printf +L.1165: +L.1163: +la $20,5 +la $24,2 +sw $24,-4+160($sp) +lw $24,-4+160($sp) +subu $20,$20,$24 +la $24,3 +beq $20,$24,L.1167 +la $23,115 +beq $30,$0,L.1169 +la $4,L.687 +move $5,$23 +jal printf +L.1169: +L.1167: +la $20,5 +la $24,2 +sw $24,-8+160($sp) +lw $24,-8+160($sp) +subu $20,$20,$24 +la $24,3 +beq $20,$24,L.1171 +la $23,116 +beq $30,$0,L.1173 +la $4,L.687 +move $5,$23 +jal printf +L.1173: +L.1171: +la $20,5 +la $24,2 +sw $24,-12+160($sp) +move $24,$20 +lw $15,-12+160($sp) +subu $24,$24,$15 +move $20,$24 +la $24,3 +beq $20,$24,L.1175 +la $23,117 +beq $30,$0,L.1177 +la $4,L.687 +move $5,$23 +jal printf +L.1177: +L.1175: +la $20,5 +l.s $f26,L.529 +mtc1 $20,$f18; cvt.s.w $f18,$f18 +sub.s $f18,$f18,$f26 +trunc.w.s $f2,$f18,$20; mfc1 $20,$f2 +la $24,3 +beq $20,$24,L.1179 +la $23,118 +beq $30,$0,L.1181 +la $4,L.687 +move $5,$23 +jal printf +L.1181: +L.1179: +la $20,5 +l.d $f24,L.416 +mtc1 $20,$f18; cvt.d.w $f18,$f18 +sub.d $f18,$f18,$f24 +trunc.w.d $f2,$f18,$20; mfc1 $20,$f2 +la $24,3 +beq $20,$24,L.1183 +la $23,119 +beq $30,$0,L.1185 +la $4,L.687 +move $5,$23 +jal printf +L.1185: +L.1183: +la $19,5 +la $17,2 +sll $24,$17,8*(4-1); sra $24,$24,8*(4-1) +subu $19,$19,$24 +la $24,3 +beq $19,$24,L.1187 +la $23,120 +beq $30,$0,L.1189 +la $4,L.687 +move $5,$23 +jal printf +L.1189: +L.1187: +la $19,5 +la $16,2 +sll $24,$16,8*(4-2); sra $24,$24,8*(4-2) +subu $19,$19,$24 +la $24,3 +beq $19,$24,L.1191 +la $23,121 +beq $30,$0,L.1193 +la $4,L.687 +move $5,$23 +jal printf +L.1193: +L.1191: +la $19,5 +la $24,2 +sw $24,-4+160($sp) +lw $24,-4+160($sp) +subu $19,$19,$24 +la $24,3 +beq $19,$24,L.1195 +la $23,122 +beq $30,$0,L.1197 +la $4,L.687 +move $5,$23 +jal printf +L.1197: +L.1195: +la $19,5 +la $24,2 +sw $24,-8+160($sp) +lw $24,-8+160($sp) +subu $19,$19,$24 +la $24,3 +beq $19,$24,L.1199 +la $23,123 +beq $30,$0,L.1201 +la $4,L.687 +move $5,$23 +jal printf +L.1201: +L.1199: +la $19,5 +la $24,2 +sw $24,-12+160($sp) +move $24,$19 +lw $15,-12+160($sp) +subu $24,$24,$15 +move $19,$24 +la $24,3 +beq $19,$24,L.1203 +la $23,124 +beq $30,$0,L.1205 +la $4,L.687 +move $5,$23 +jal printf +L.1205: +L.1203: +la $19,5 +l.s $f26,L.529 +mtc1 $19,$f18; cvt.s.w $f18,$f18 +sub.s $f18,$f18,$f26 +trunc.w.s $f2,$f18,$19; mfc1 $19,$f2 +la $24,3 +beq $19,$24,L.1207 +la $23,125 +beq $30,$0,L.1209 +la $4,L.687 +move $5,$23 +jal printf +L.1209: +L.1207: +la $19,5 +l.d $f24,L.416 +mtc1 $19,$f18; cvt.d.w $f18,$f18 +sub.d $f18,$f18,$f24 +trunc.w.d $f2,$f18,$19; mfc1 $19,$f2 +la $24,3 +beq $19,$24,L.1211 +la $23,126 +beq $30,$0,L.1213 +la $4,L.687 +move $5,$23 +jal printf +L.1213: +L.1211: +la $18,5 +la $17,2 +sll $24,$17,8*(4-1); sra $24,$24,8*(4-1) +subu $18,$18,$24 +la $24,3 +beq $18,$24,L.1215 +la $23,127 +beq $30,$0,L.1217 +la $4,L.687 +move $5,$23 +jal printf +L.1217: +L.1215: +la $18,5 +la $16,2 +sll $24,$16,8*(4-2); sra $24,$24,8*(4-2) +subu $18,$18,$24 +la $24,3 +beq $18,$24,L.1219 +la $23,128 +beq $30,$0,L.1221 +la $4,L.687 +move $5,$23 +jal printf +L.1221: +L.1219: +la $18,5 +la $24,2 +sw $24,-4+160($sp) +lw $24,-4+160($sp) +subu $18,$18,$24 +la $24,3 +beq $18,$24,L.1223 +la $23,129 +beq $30,$0,L.1225 +la $4,L.687 +move $5,$23 +jal printf +L.1225: +L.1223: +la $18,5 +la $24,2 +sw $24,-8+160($sp) +lw $24,-8+160($sp) +subu $18,$18,$24 +la $24,3 +beq $18,$24,L.1227 +la $23,130 +beq $30,$0,L.1229 +la $4,L.687 +move $5,$23 +jal printf +L.1229: +L.1227: +la $18,5 +la $24,2 +sw $24,-12+160($sp) +lw $24,-12+160($sp) +subu $18,$18,$24 +la $24,3 +beq $18,$24,L.1231 +la $23,131 +beq $30,$0,L.1233 +la $4,L.687 +move $5,$23 +jal printf +L.1233: +L.1231: +la $18,5 +l.s $f26,L.529 +l.d $f18,L.596 +srl $24,$18,1 +mtc1 $24,$f16; cvt.d.w $f16,$f16 +mul.d $f18,$f18,$f16 +and $24,$18,1 +mtc1 $24,$f16; cvt.d.w $f16,$f16 +add.d $f18,$f18,$f16 +cvt.s.d $f18,$f18 +sub.s $f18,$f18,$f26 +l.s $f16,L.828 +c.ult.s $f18,$f16; bc1t L.1236 +sub.s $f16,$f18,$f16 +trunc.w.s $f2,$f16,$24; mfc1 $24,$f2 +la $24,0x80000000($24) +sw $24,-44+160($sp) +b L.1237 +L.1236: +trunc.w.s $f2,$f18,$24; mfc1 $24,$f2 +sw $24,-44+160($sp) +L.1237: +lw $18,-44+160($sp) +la $24,3 +beq $18,$24,L.1238 +la $23,132 +beq $30,$0,L.1240 +la $4,L.687 +move $5,$23 +jal printf +L.1240: +L.1238: +la $18,5 +l.d $f24,L.416 +l.d $f18,L.596 +srl $24,$18,1 +mtc1 $24,$f16; cvt.d.w $f16,$f16 +mul.d $f18,$f18,$f16 +and $24,$18,1 +mtc1 $24,$f16; cvt.d.w $f16,$f16 +add.d $f18,$f18,$f16 +sub.d $f18,$f18,$f24 +l.d $f16,L.836 +c.ult.d $f18,$f16; bc1t L.1243 +sub.d $f16,$f18,$f16 +trunc.w.d $f2,$f16,$24; mfc1 $24,$f2 +la $24,0x80000000($24) +sw $24,-48+160($sp) +b L.1244 +L.1243: +trunc.w.d $f2,$f18,$24; mfc1 $24,$f2 +sw $24,-48+160($sp) +L.1244: +lw $18,-48+160($sp) +la $24,3 +beq $18,$24,L.1245 +la $23,133 +beq $30,$0,L.1247 +la $4,L.687 +move $5,$23 +jal printf +L.1247: +L.1245: +l.s $f30,L.841 +la $17,2 +sll $24,$17,8*(4-1); sra $24,$24,8*(4-1) +mtc1 $24,$f18; cvt.s.w $f18,$f18 +sub.s $f30,$f30,$f18 +l.s $f18,L.1251 +c.eq.s $f30,$f18; bc1t L.1249 +la $23,134 +beq $30,$0,L.1252 +la $4,L.687 +move $5,$23 +jal printf +L.1252: +L.1249: +l.s $f30,L.841 +la $16,2 +sll $24,$16,8*(4-2); sra $24,$24,8*(4-2) +mtc1 $24,$f18; cvt.s.w $f18,$f18 +sub.s $f30,$f30,$f18 +l.s $f18,L.1251 +c.eq.s $f30,$f18; bc1t L.1254 +la $23,135 +beq $30,$0,L.1256 +la $4,L.687 +move $5,$23 +jal printf +L.1256: +L.1254: +l.s $f30,L.841 +la $24,2 +sw $24,-4+160($sp) +lw $24,-4+160($sp) +mtc1 $24,$f18; cvt.s.w $f18,$f18 +sub.s $f30,$f30,$f18 +l.s $f18,L.1251 +c.eq.s $f30,$f18; bc1t L.1258 +la $23,136 +beq $30,$0,L.1260 +la $4,L.687 +move $5,$23 +jal printf +L.1260: +L.1258: +l.s $f30,L.841 +la $24,2 +sw $24,-8+160($sp) +lw $24,-8+160($sp) +mtc1 $24,$f18; cvt.s.w $f18,$f18 +sub.s $f30,$f30,$f18 +l.s $f18,L.1251 +c.eq.s $f30,$f18; bc1t L.1262 +la $23,137 +beq $30,$0,L.1264 +la $4,L.687 +move $5,$23 +jal printf +L.1264: +L.1262: +l.s $f30,L.841 +la $24,2 +sw $24,-12+160($sp) +lw $24,-12+160($sp) +l.d $f18,L.596 +srl $15,$24,1 +mtc1 $15,$f16; cvt.d.w $f16,$f16 +mul.d $f18,$f18,$f16 +and $24,$24,1 +mtc1 $24,$f16; cvt.d.w $f16,$f16 +add.d $f18,$f18,$f16 +cvt.s.d $f18,$f18 +sub.s $f30,$f30,$f18 +l.s $f18,L.1251 +c.eq.s $f30,$f18; bc1t L.1266 +la $23,138 +beq $30,$0,L.1268 +la $4,L.687 +move $5,$23 +jal printf +L.1268: +L.1266: +l.s $f30,L.841 +l.s $f26,L.529 +sub.s $f30,$f30,$f26 +l.s $f18,L.1251 +c.eq.s $f30,$f18; bc1t L.1270 +la $23,139 +beq $30,$0,L.1272 +la $4,L.687 +move $5,$23 +jal printf +L.1272: +L.1270: +l.s $f30,L.841 +l.d $f24,L.416 +cvt.d.s $f18,$f30 +sub.d $f18,$f18,$f24 +cvt.s.d $f30,$f18 +l.s $f18,L.1251 +c.eq.s $f30,$f18; bc1t L.1274 +la $23,140 +beq $30,$0,L.1276 +la $4,L.687 +move $5,$23 +jal printf +L.1276: +L.1274: +l.d $f28,L.870 +la $17,2 +sll $24,$17,8*(4-1); sra $24,$24,8*(4-1) +mtc1 $24,$f18; cvt.d.w $f18,$f18 +sub.d $f28,$f28,$f18 +l.d $f18,L.1280 +c.eq.d $f28,$f18; bc1t L.1278 +la $23,141 +beq $30,$0,L.1281 +la $4,L.687 +move $5,$23 +jal printf +L.1281: +L.1278: +l.d $f28,L.870 +la $16,2 +sll $24,$16,8*(4-2); sra $24,$24,8*(4-2) +mtc1 $24,$f18; cvt.d.w $f18,$f18 +sub.d $f28,$f28,$f18 +l.d $f18,L.1280 +c.eq.d $f28,$f18; bc1t L.1283 +la $23,142 +beq $30,$0,L.1285 +la $4,L.687 +move $5,$23 +jal printf +L.1285: +L.1283: +l.d $f28,L.870 +la $24,2 +sw $24,-4+160($sp) +lw $24,-4+160($sp) +mtc1 $24,$f18; cvt.d.w $f18,$f18 +sub.d $f28,$f28,$f18 +l.d $f18,L.1280 +c.eq.d $f28,$f18; bc1t L.1287 +la $23,143 +beq $30,$0,L.1289 +la $4,L.687 +move $5,$23 +jal printf +L.1289: +L.1287: +l.d $f28,L.870 +la $24,2 +sw $24,-8+160($sp) +lw $24,-8+160($sp) +mtc1 $24,$f18; cvt.d.w $f18,$f18 +sub.d $f28,$f28,$f18 +l.d $f18,L.1280 +c.eq.d $f28,$f18; bc1t L.1291 +la $23,144 +beq $30,$0,L.1293 +la $4,L.687 +move $5,$23 +jal printf +L.1293: +L.1291: +l.d $f28,L.870 +la $24,2 +sw $24,-12+160($sp) +lw $24,-12+160($sp) +l.d $f18,L.596 +srl $15,$24,1 +mtc1 $15,$f16; cvt.d.w $f16,$f16 +mul.d $f18,$f18,$f16 +and $24,$24,1 +mtc1 $24,$f16; cvt.d.w $f16,$f16 +add.d $f18,$f18,$f16 +sub.d $f28,$f28,$f18 +l.d $f18,L.1280 +c.eq.d $f28,$f18; bc1t L.1295 +la $23,145 +beq $30,$0,L.1297 +la $4,L.687 +move $5,$23 +jal printf +L.1297: +L.1295: +l.d $f28,L.870 +l.s $f26,L.529 +cvt.d.s $f18,$f26 +sub.d $f28,$f28,$f18 +l.d $f18,L.1280 +c.eq.d $f28,$f18; bc1t L.1299 +la $23,146 +beq $30,$0,L.1301 +la $4,L.687 +move $5,$23 +jal printf +L.1301: +L.1299: +l.d $f28,L.870 +l.d $f24,L.416 +sub.d $f28,$f28,$f24 +l.d $f18,L.1280 +c.eq.d $f28,$f18; bc1t L.1303 +la $23,147 +beq $30,$0,L.1305 +la $4,L.687 +move $5,$23 +jal printf +L.1305: +L.1303: +la $22,5 +la $17,2 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +sll $15,$17,8*(4-1); sra $15,$15,8*(4-1) +mul $24,$24,$15 +move $22,$24 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +la $15,10 +beq $24,$15,L.1307 +la $23,148 +beq $30,$0,L.1309 +la $4,L.687 +move $5,$23 +jal printf +L.1309: +L.1307: +la $22,5 +la $16,2 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +sll $15,$16,8*(4-2); sra $15,$15,8*(4-2) +mul $24,$24,$15 +move $22,$24 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +la $15,10 +beq $24,$15,L.1311 +la $23,149 +beq $30,$0,L.1313 +la $4,L.687 +move $5,$23 +jal printf +L.1313: +L.1311: +la $22,5 +la $24,2 +sw $24,-4+160($sp) +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +lw $15,-4+160($sp) +mul $24,$24,$15 +move $22,$24 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +la $15,10 +beq $24,$15,L.1315 +la $23,150 +beq $30,$0,L.1317 +la $4,L.687 +move $5,$23 +jal printf +L.1317: +L.1315: +la $22,5 +la $24,2 +sw $24,-8+160($sp) +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +lw $15,-8+160($sp) +mul $24,$24,$15 +move $22,$24 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +la $15,10 +beq $24,$15,L.1319 +la $23,151 +beq $30,$0,L.1321 +la $4,L.687 +move $5,$23 +jal printf +L.1321: +L.1319: +la $22,5 +la $24,2 +sw $24,-12+160($sp) +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +lw $15,-12+160($sp) +mul $24,$24,$15 +move $22,$24 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +la $15,10 +beq $24,$15,L.1323 +la $23,152 +beq $30,$0,L.1325 +la $4,L.687 +move $5,$23 +jal printf +L.1325: +L.1323: +la $22,5 +l.s $f26,L.529 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +mtc1 $24,$f18; cvt.s.w $f18,$f18 +mul.s $f18,$f18,$f26 +trunc.w.s $f2,$f18,$24; mfc1 $24,$f2 +move $22,$24 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +la $15,10 +beq $24,$15,L.1327 +la $23,153 +beq $30,$0,L.1329 +la $4,L.687 +move $5,$23 +jal printf +L.1329: +L.1327: +la $22,5 +l.d $f24,L.416 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +mtc1 $24,$f18; cvt.d.w $f18,$f18 +mul.d $f18,$f18,$f24 +trunc.w.d $f2,$f18,$24; mfc1 $24,$f2 +move $22,$24 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +la $15,10 +beq $24,$15,L.1331 +la $23,154 +beq $30,$0,L.1333 +la $4,L.687 +move $5,$23 +jal printf +L.1333: +L.1331: +la $21,5 +la $17,2 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +sll $15,$17,8*(4-1); sra $15,$15,8*(4-1) +mul $24,$24,$15 +move $21,$24 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +la $15,10 +beq $24,$15,L.1335 +la $23,155 +beq $30,$0,L.1337 +la $4,L.687 +move $5,$23 +jal printf +L.1337: +L.1335: +la $21,5 +la $16,2 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +sll $15,$16,8*(4-2); sra $15,$15,8*(4-2) +mul $24,$24,$15 +move $21,$24 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +la $15,10 +beq $24,$15,L.1339 +la $23,156 +beq $30,$0,L.1341 +la $4,L.687 +move $5,$23 +jal printf +L.1341: +L.1339: +la $21,5 +la $24,2 +sw $24,-4+160($sp) +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +lw $15,-4+160($sp) +mul $24,$24,$15 +move $21,$24 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +la $15,10 +beq $24,$15,L.1343 +la $23,157 +beq $30,$0,L.1345 +la $4,L.687 +move $5,$23 +jal printf +L.1345: +L.1343: +la $21,5 +la $24,2 +sw $24,-8+160($sp) +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +lw $15,-8+160($sp) +mul $24,$24,$15 +move $21,$24 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +la $15,10 +beq $24,$15,L.1347 +la $23,158 +beq $30,$0,L.1349 +la $4,L.687 +move $5,$23 +jal printf +L.1349: +L.1347: +la $21,5 +la $24,2 +sw $24,-12+160($sp) +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +lw $15,-12+160($sp) +mul $24,$24,$15 +move $21,$24 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +la $15,10 +beq $24,$15,L.1351 +la $23,159 +beq $30,$0,L.1353 +la $4,L.687 +move $5,$23 +jal printf +L.1353: +L.1351: +la $21,5 +l.s $f26,L.529 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +mtc1 $24,$f18; cvt.s.w $f18,$f18 +mul.s $f18,$f18,$f26 +trunc.w.s $f2,$f18,$24; mfc1 $24,$f2 +move $21,$24 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +la $15,10 +beq $24,$15,L.1355 +la $23,160 +beq $30,$0,L.1357 +la $4,L.687 +move $5,$23 +jal printf +L.1357: +L.1355: +la $21,5 +l.d $f24,L.416 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +mtc1 $24,$f18; cvt.d.w $f18,$f18 +mul.d $f18,$f18,$f24 +trunc.w.d $f2,$f18,$24; mfc1 $24,$f2 +move $21,$24 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +la $15,10 +beq $24,$15,L.1359 +la $23,161 +beq $30,$0,L.1361 +la $4,L.687 +move $5,$23 +jal printf +L.1361: +L.1359: +la $20,5 +la $17,2 +sll $24,$17,8*(4-1); sra $24,$24,8*(4-1) +mul $20,$20,$24 +la $24,10 +beq $20,$24,L.1363 +la $23,162 +beq $30,$0,L.1365 +la $4,L.687 +move $5,$23 +jal printf +L.1365: +L.1363: +la $20,5 +la $16,2 +sll $24,$16,8*(4-2); sra $24,$24,8*(4-2) +mul $20,$20,$24 +la $24,10 +beq $20,$24,L.1367 +la $23,163 +beq $30,$0,L.1369 +la $4,L.687 +move $5,$23 +jal printf +L.1369: +L.1367: +la $20,5 +la $24,2 +sw $24,-4+160($sp) +lw $24,-4+160($sp) +mul $20,$20,$24 +la $24,10 +beq $20,$24,L.1371 +la $23,164 +beq $30,$0,L.1373 +la $4,L.687 +move $5,$23 +jal printf +L.1373: +L.1371: +la $20,5 +la $24,2 +sw $24,-8+160($sp) +lw $24,-8+160($sp) +mul $20,$20,$24 +la $24,10 +beq $20,$24,L.1375 +la $23,165 +beq $30,$0,L.1377 +la $4,L.687 +move $5,$23 +jal printf +L.1377: +L.1375: +la $20,5 +la $24,2 +sw $24,-12+160($sp) +move $24,$20 +lw $15,-12+160($sp) +mul $24,$24,$15 +move $20,$24 +la $24,10 +beq $20,$24,L.1379 +la $23,166 +beq $30,$0,L.1381 +la $4,L.687 +move $5,$23 +jal printf +L.1381: +L.1379: +la $20,5 +l.s $f26,L.529 +mtc1 $20,$f18; cvt.s.w $f18,$f18 +mul.s $f18,$f18,$f26 +trunc.w.s $f2,$f18,$20; mfc1 $20,$f2 +la $24,10 +beq $20,$24,L.1383 +la $23,167 +beq $30,$0,L.1385 +la $4,L.687 +move $5,$23 +jal printf +L.1385: +L.1383: +la $20,5 +l.d $f24,L.416 +mtc1 $20,$f18; cvt.d.w $f18,$f18 +mul.d $f18,$f18,$f24 +trunc.w.d $f2,$f18,$20; mfc1 $20,$f2 +la $24,10 +beq $20,$24,L.1387 +la $23,168 +beq $30,$0,L.1389 +la $4,L.687 +move $5,$23 +jal printf +L.1389: +L.1387: +la $19,5 +la $17,2 +sll $24,$17,8*(4-1); sra $24,$24,8*(4-1) +mul $19,$19,$24 +la $24,10 +beq $19,$24,L.1391 +la $23,169 +beq $30,$0,L.1393 +la $4,L.687 +move $5,$23 +jal printf +L.1393: +L.1391: +la $19,5 +la $16,2 +sll $24,$16,8*(4-2); sra $24,$24,8*(4-2) +mul $19,$19,$24 +la $24,10 +beq $19,$24,L.1395 +la $23,170 +beq $30,$0,L.1397 +la $4,L.687 +move $5,$23 +jal printf +L.1397: +L.1395: +la $19,5 +la $24,2 +sw $24,-4+160($sp) +lw $24,-4+160($sp) +mul $19,$19,$24 +la $24,10 +beq $19,$24,L.1399 +la $23,171 +beq $30,$0,L.1401 +la $4,L.687 +move $5,$23 +jal printf +L.1401: +L.1399: +la $19,5 +la $24,2 +sw $24,-8+160($sp) +lw $24,-8+160($sp) +mul $19,$19,$24 +la $24,10 +beq $19,$24,L.1403 +la $23,172 +beq $30,$0,L.1405 +la $4,L.687 +move $5,$23 +jal printf +L.1405: +L.1403: +la $19,5 +la $24,2 +sw $24,-12+160($sp) +move $24,$19 +lw $15,-12+160($sp) +mul $24,$24,$15 +move $19,$24 +la $24,10 +beq $19,$24,L.1407 +la $23,173 +beq $30,$0,L.1409 +la $4,L.687 +move $5,$23 +jal printf +L.1409: +L.1407: +la $19,5 +l.s $f26,L.529 +mtc1 $19,$f18; cvt.s.w $f18,$f18 +mul.s $f18,$f18,$f26 +trunc.w.s $f2,$f18,$19; mfc1 $19,$f2 +la $24,10 +beq $19,$24,L.1411 +la $23,174 +beq $30,$0,L.1413 +la $4,L.687 +move $5,$23 +jal printf +L.1413: +L.1411: +la $19,5 +l.d $f24,L.416 +mtc1 $19,$f18; cvt.d.w $f18,$f18 +mul.d $f18,$f18,$f24 +trunc.w.d $f2,$f18,$19; mfc1 $19,$f2 +la $24,10 +beq $19,$24,L.1415 +la $23,175 +beq $30,$0,L.1417 +la $4,L.687 +move $5,$23 +jal printf +L.1417: +L.1415: +la $18,5 +la $17,2 +sll $24,$17,8*(4-1); sra $24,$24,8*(4-1) +mul $18,$18,$24 +la $24,10 +beq $18,$24,L.1419 +la $23,176 +beq $30,$0,L.1421 +la $4,L.687 +move $5,$23 +jal printf +L.1421: +L.1419: +la $18,5 +la $16,2 +sll $24,$16,8*(4-2); sra $24,$24,8*(4-2) +mul $18,$18,$24 +la $24,10 +beq $18,$24,L.1423 +la $23,177 +beq $30,$0,L.1425 +la $4,L.687 +move $5,$23 +jal printf +L.1425: +L.1423: +la $18,5 +la $24,2 +sw $24,-4+160($sp) +lw $24,-4+160($sp) +mul $18,$18,$24 +la $24,10 +beq $18,$24,L.1427 +la $23,178 +beq $30,$0,L.1429 +la $4,L.687 +move $5,$23 +jal printf +L.1429: +L.1427: +la $18,5 +la $24,2 +sw $24,-8+160($sp) +lw $24,-8+160($sp) +mul $18,$18,$24 +la $24,10 +beq $18,$24,L.1431 +la $23,179 +beq $30,$0,L.1433 +la $4,L.687 +move $5,$23 +jal printf +L.1433: +L.1431: +la $18,5 +la $24,2 +sw $24,-12+160($sp) +lw $24,-12+160($sp) +mul $18,$18,$24 +la $24,10 +beq $18,$24,L.1435 +la $23,180 +beq $30,$0,L.1437 +la $4,L.687 +move $5,$23 +jal printf +L.1437: +L.1435: +la $18,5 +l.s $f26,L.529 +l.d $f18,L.596 +srl $24,$18,1 +mtc1 $24,$f16; cvt.d.w $f16,$f16 +mul.d $f18,$f18,$f16 +and $24,$18,1 +mtc1 $24,$f16; cvt.d.w $f16,$f16 +add.d $f18,$f18,$f16 +cvt.s.d $f18,$f18 +mul.s $f18,$f18,$f26 +l.s $f16,L.828 +c.ult.s $f18,$f16; bc1t L.1440 +sub.s $f16,$f18,$f16 +trunc.w.s $f2,$f16,$24; mfc1 $24,$f2 +la $24,0x80000000($24) +sw $24,-52+160($sp) +b L.1441 +L.1440: +trunc.w.s $f2,$f18,$24; mfc1 $24,$f2 +sw $24,-52+160($sp) +L.1441: +lw $18,-52+160($sp) +la $24,10 +beq $18,$24,L.1442 +la $23,181 +beq $30,$0,L.1444 +la $4,L.687 +move $5,$23 +jal printf +L.1444: +L.1442: +la $18,5 +l.d $f24,L.416 +l.d $f18,L.596 +srl $24,$18,1 +mtc1 $24,$f16; cvt.d.w $f16,$f16 +mul.d $f18,$f18,$f16 +and $24,$18,1 +mtc1 $24,$f16; cvt.d.w $f16,$f16 +add.d $f18,$f18,$f16 +mul.d $f18,$f18,$f24 +l.d $f16,L.836 +c.ult.d $f18,$f16; bc1t L.1447 +sub.d $f16,$f18,$f16 +trunc.w.d $f2,$f16,$24; mfc1 $24,$f2 +la $24,0x80000000($24) +sw $24,-56+160($sp) +b L.1448 +L.1447: +trunc.w.d $f2,$f18,$24; mfc1 $24,$f2 +sw $24,-56+160($sp) +L.1448: +lw $18,-56+160($sp) +la $24,10 +beq $18,$24,L.1449 +la $23,182 +beq $30,$0,L.1451 +la $4,L.687 +move $5,$23 +jal printf +L.1451: +L.1449: +l.s $f30,L.841 +la $17,2 +sll $24,$17,8*(4-1); sra $24,$24,8*(4-1) +mtc1 $24,$f18; cvt.s.w $f18,$f18 +mul.s $f30,$f30,$f18 +l.s $f18,L.1455 +c.eq.s $f30,$f18; bc1t L.1453 +la $23,183 +beq $30,$0,L.1456 +la $4,L.687 +move $5,$23 +jal printf +L.1456: +L.1453: +l.s $f30,L.841 +la $16,2 +sll $24,$16,8*(4-2); sra $24,$24,8*(4-2) +mtc1 $24,$f18; cvt.s.w $f18,$f18 +mul.s $f30,$f30,$f18 +l.s $f18,L.1455 +c.eq.s $f30,$f18; bc1t L.1458 +la $23,184 +beq $30,$0,L.1460 +la $4,L.687 +move $5,$23 +jal printf +L.1460: +L.1458: +l.s $f30,L.841 +la $24,2 +sw $24,-4+160($sp) +lw $24,-4+160($sp) +mtc1 $24,$f18; cvt.s.w $f18,$f18 +mul.s $f30,$f30,$f18 +l.s $f18,L.1455 +c.eq.s $f30,$f18; bc1t L.1462 +la $23,185 +beq $30,$0,L.1464 +la $4,L.687 +move $5,$23 +jal printf +L.1464: +L.1462: +l.s $f30,L.841 +la $24,2 +sw $24,-8+160($sp) +lw $24,-8+160($sp) +mtc1 $24,$f18; cvt.s.w $f18,$f18 +mul.s $f30,$f30,$f18 +l.s $f18,L.1455 +c.eq.s $f30,$f18; bc1t L.1466 +la $23,186 +beq $30,$0,L.1468 +la $4,L.687 +move $5,$23 +jal printf +L.1468: +L.1466: +l.s $f30,L.841 +la $24,2 +sw $24,-12+160($sp) +lw $24,-12+160($sp) +l.d $f18,L.596 +srl $15,$24,1 +mtc1 $15,$f16; cvt.d.w $f16,$f16 +mul.d $f18,$f18,$f16 +and $24,$24,1 +mtc1 $24,$f16; cvt.d.w $f16,$f16 +add.d $f18,$f18,$f16 +cvt.s.d $f18,$f18 +mul.s $f30,$f30,$f18 +l.s $f18,L.1455 +c.eq.s $f30,$f18; bc1t L.1470 +la $23,187 +beq $30,$0,L.1472 +la $4,L.687 +move $5,$23 +jal printf +L.1472: +L.1470: +l.s $f30,L.841 +l.s $f26,L.529 +mul.s $f30,$f30,$f26 +l.s $f18,L.1455 +c.eq.s $f30,$f18; bc1t L.1474 +la $23,188 +beq $30,$0,L.1476 +la $4,L.687 +move $5,$23 +jal printf +L.1476: +L.1474: +l.s $f30,L.841 +l.d $f24,L.416 +cvt.d.s $f18,$f30 +mul.d $f18,$f18,$f24 +cvt.s.d $f30,$f18 +l.s $f18,L.1455 +c.eq.s $f30,$f18; bc1t L.1478 +la $23,189 +beq $30,$0,L.1480 +la $4,L.687 +move $5,$23 +jal printf +L.1480: +L.1478: +l.d $f28,L.870 +la $17,2 +sll $24,$17,8*(4-1); sra $24,$24,8*(4-1) +mtc1 $24,$f18; cvt.d.w $f18,$f18 +mul.d $f28,$f28,$f18 +l.d $f18,L.1484 +c.eq.d $f28,$f18; bc1t L.1482 +la $23,190 +beq $30,$0,L.1485 +la $4,L.687 +move $5,$23 +jal printf +L.1485: +L.1482: +l.d $f28,L.870 +la $16,2 +sll $24,$16,8*(4-2); sra $24,$24,8*(4-2) +mtc1 $24,$f18; cvt.d.w $f18,$f18 +mul.d $f28,$f28,$f18 +l.d $f18,L.1484 +c.eq.d $f28,$f18; bc1t L.1487 +la $23,191 +beq $30,$0,L.1489 +la $4,L.687 +move $5,$23 +jal printf +L.1489: +L.1487: +l.d $f28,L.870 +la $24,2 +sw $24,-4+160($sp) +lw $24,-4+160($sp) +mtc1 $24,$f18; cvt.d.w $f18,$f18 +mul.d $f28,$f28,$f18 +l.d $f18,L.1484 +c.eq.d $f28,$f18; bc1t L.1491 +la $23,192 +beq $30,$0,L.1493 +la $4,L.687 +move $5,$23 +jal printf +L.1493: +L.1491: +l.d $f28,L.870 +la $24,2 +sw $24,-8+160($sp) +lw $24,-8+160($sp) +mtc1 $24,$f18; cvt.d.w $f18,$f18 +mul.d $f28,$f28,$f18 +l.d $f18,L.1484 +c.eq.d $f28,$f18; bc1t L.1495 +la $23,193 +beq $30,$0,L.1497 +la $4,L.687 +move $5,$23 +jal printf +L.1497: +L.1495: +l.d $f28,L.870 +la $24,2 +sw $24,-12+160($sp) +lw $24,-12+160($sp) +l.d $f18,L.596 +srl $15,$24,1 +mtc1 $15,$f16; cvt.d.w $f16,$f16 +mul.d $f18,$f18,$f16 +and $24,$24,1 +mtc1 $24,$f16; cvt.d.w $f16,$f16 +add.d $f18,$f18,$f16 +mul.d $f28,$f28,$f18 +l.d $f18,L.1484 +c.eq.d $f28,$f18; bc1t L.1499 +la $23,194 +beq $30,$0,L.1501 +la $4,L.687 +move $5,$23 +jal printf +L.1501: +L.1499: +l.d $f28,L.870 +l.s $f26,L.529 +cvt.d.s $f18,$f26 +mul.d $f28,$f28,$f18 +l.d $f18,L.1484 +c.eq.d $f28,$f18; bc1t L.1503 +la $23,195 +beq $30,$0,L.1505 +la $4,L.687 +move $5,$23 +jal printf +L.1505: +L.1503: +l.d $f28,L.870 +l.d $f24,L.416 +mul.d $f28,$f28,$f24 +l.d $f18,L.1484 +c.eq.d $f28,$f18; bc1t L.1507 +la $23,196 +beq $30,$0,L.1509 +la $4,L.687 +move $5,$23 +jal printf +L.1509: +L.1507: +la $22,5 +la $17,2 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +sll $15,$17,8*(4-1); sra $15,$15,8*(4-1) +div $24,$24,$15 +move $22,$24 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +la $15,2 +beq $24,$15,L.1511 +la $23,197 +beq $30,$0,L.1513 +la $4,L.687 +move $5,$23 +jal printf +L.1513: +L.1511: +la $22,5 +la $16,2 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +sll $15,$16,8*(4-2); sra $15,$15,8*(4-2) +div $24,$24,$15 +move $22,$24 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +la $15,2 +beq $24,$15,L.1515 +la $23,198 +beq $30,$0,L.1517 +la $4,L.687 +move $5,$23 +jal printf +L.1517: +L.1515: +la $22,5 +la $24,2 +sw $24,-4+160($sp) +sll $15,$22,8*(4-1); sra $15,$15,8*(4-1) +lw $14,-4+160($sp) +div $15,$15,$14 +move $22,$15 +sll $15,$22,8*(4-1); sra $15,$15,8*(4-1) +beq $15,$24,L.1519 +la $23,199 +beq $30,$0,L.1521 +la $4,L.687 +move $5,$23 +jal printf +L.1521: +L.1519: +la $22,5 +la $24,2 +sw $24,-8+160($sp) +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +lw $15,-8+160($sp) +div $24,$24,$15 +move $22,$24 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +la $15,2 +beq $24,$15,L.1523 +la $23,200 +beq $30,$0,L.1525 +la $4,L.687 +move $5,$23 +jal printf +L.1525: +L.1523: +la $22,5 +la $24,2 +sw $24,-12+160($sp) +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +lw $15,-12+160($sp) +divu $24,$24,$15 +move $22,$24 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +la $15,2 +beq $24,$15,L.1527 +la $23,201 +beq $30,$0,L.1529 +la $4,L.687 +move $5,$23 +jal printf +L.1529: +L.1527: +la $22,5 +l.s $f26,L.529 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +mtc1 $24,$f18; cvt.s.w $f18,$f18 +div.s $f18,$f18,$f26 +trunc.w.s $f2,$f18,$24; mfc1 $24,$f2 +move $22,$24 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +la $15,2 +beq $24,$15,L.1531 +la $23,202 +beq $30,$0,L.1533 +la $4,L.687 +move $5,$23 +jal printf +L.1533: +L.1531: +la $22,5 +l.d $f24,L.416 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +mtc1 $24,$f18; cvt.d.w $f18,$f18 +div.d $f18,$f18,$f24 +trunc.w.d $f2,$f18,$24; mfc1 $24,$f2 +move $22,$24 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +la $15,2 +beq $24,$15,L.1535 +la $23,203 +beq $30,$0,L.1537 +la $4,L.687 +move $5,$23 +jal printf +L.1537: +L.1535: +la $21,5 +la $17,2 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +sll $15,$17,8*(4-1); sra $15,$15,8*(4-1) +div $24,$24,$15 +move $21,$24 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +la $15,2 +beq $24,$15,L.1539 +la $23,204 +beq $30,$0,L.1541 +la $4,L.687 +move $5,$23 +jal printf +L.1541: +L.1539: +la $21,5 +la $16,2 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +sll $15,$16,8*(4-2); sra $15,$15,8*(4-2) +div $24,$24,$15 +move $21,$24 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +la $15,2 +beq $24,$15,L.1543 +la $23,205 +beq $30,$0,L.1545 +la $4,L.687 +move $5,$23 +jal printf +L.1545: +L.1543: +la $21,5 +la $24,2 +sw $24,-4+160($sp) +sll $15,$21,8*(4-2); sra $15,$15,8*(4-2) +lw $14,-4+160($sp) +div $15,$15,$14 +move $21,$15 +sll $15,$21,8*(4-2); sra $15,$15,8*(4-2) +beq $15,$24,L.1547 +la $23,206 +beq $30,$0,L.1549 +la $4,L.687 +move $5,$23 +jal printf +L.1549: +L.1547: +la $21,5 +la $24,2 +sw $24,-8+160($sp) +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +lw $15,-8+160($sp) +div $24,$24,$15 +move $21,$24 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +la $15,2 +beq $24,$15,L.1551 +la $23,207 +beq $30,$0,L.1553 +la $4,L.687 +move $5,$23 +jal printf +L.1553: +L.1551: +la $21,5 +la $24,2 +sw $24,-12+160($sp) +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +lw $15,-12+160($sp) +divu $24,$24,$15 +move $21,$24 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +la $15,2 +beq $24,$15,L.1555 +la $23,208 +beq $30,$0,L.1557 +la $4,L.687 +move $5,$23 +jal printf +L.1557: +L.1555: +la $21,5 +l.s $f26,L.529 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +mtc1 $24,$f18; cvt.s.w $f18,$f18 +div.s $f18,$f18,$f26 +trunc.w.s $f2,$f18,$24; mfc1 $24,$f2 +move $21,$24 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +la $15,2 +beq $24,$15,L.1559 +la $23,209 +beq $30,$0,L.1561 +la $4,L.687 +move $5,$23 +jal printf +L.1561: +L.1559: +la $21,5 +l.d $f24,L.416 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +mtc1 $24,$f18; cvt.d.w $f18,$f18 +div.d $f18,$f18,$f24 +trunc.w.d $f2,$f18,$24; mfc1 $24,$f2 +move $21,$24 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +la $15,2 +beq $24,$15,L.1563 +la $23,210 +beq $30,$0,L.1565 +la $4,L.687 +move $5,$23 +jal printf +L.1565: +L.1563: +la $20,5 +la $17,2 +sll $24,$17,8*(4-1); sra $24,$24,8*(4-1) +div $20,$20,$24 +la $24,2 +beq $20,$24,L.1567 +la $23,211 +beq $30,$0,L.1569 +la $4,L.687 +move $5,$23 +jal printf +L.1569: +L.1567: +la $20,5 +la $16,2 +sll $24,$16,8*(4-2); sra $24,$24,8*(4-2) +div $20,$20,$24 +la $24,2 +beq $20,$24,L.1571 +la $23,212 +beq $30,$0,L.1573 +la $4,L.687 +move $5,$23 +jal printf +L.1573: +L.1571: +la $20,5 +la $24,2 +sw $24,-4+160($sp) +lw $15,-4+160($sp) +div $20,$20,$15 +beq $20,$24,L.1575 +la $23,213 +beq $30,$0,L.1577 +la $4,L.687 +move $5,$23 +jal printf +L.1577: +L.1575: +la $20,5 +la $24,2 +sw $24,-8+160($sp) +lw $24,-8+160($sp) +div $20,$20,$24 +la $24,2 +beq $20,$24,L.1579 +la $23,214 +beq $30,$0,L.1581 +la $4,L.687 +move $5,$23 +jal printf +L.1581: +L.1579: +la $20,5 +la $24,2 +sw $24,-12+160($sp) +move $24,$20 +lw $15,-12+160($sp) +divu $24,$24,$15 +move $20,$24 +la $24,2 +beq $20,$24,L.1583 +la $23,215 +beq $30,$0,L.1585 +la $4,L.687 +move $5,$23 +jal printf +L.1585: +L.1583: +la $20,5 +l.s $f26,L.529 +mtc1 $20,$f18; cvt.s.w $f18,$f18 +div.s $f18,$f18,$f26 +trunc.w.s $f2,$f18,$20; mfc1 $20,$f2 +la $24,2 +beq $20,$24,L.1587 +la $23,216 +beq $30,$0,L.1589 +la $4,L.687 +move $5,$23 +jal printf +L.1589: +L.1587: +la $20,5 +l.d $f24,L.416 +mtc1 $20,$f18; cvt.d.w $f18,$f18 +div.d $f18,$f18,$f24 +trunc.w.d $f2,$f18,$20; mfc1 $20,$f2 +la $24,2 +beq $20,$24,L.1591 +la $23,217 +beq $30,$0,L.1593 +la $4,L.687 +move $5,$23 +jal printf +L.1593: +L.1591: +la $19,5 +la $17,2 +sll $24,$17,8*(4-1); sra $24,$24,8*(4-1) +div $19,$19,$24 +la $24,2 +beq $19,$24,L.1595 +la $23,218 +beq $30,$0,L.1597 +la $4,L.687 +move $5,$23 +jal printf +L.1597: +L.1595: +la $19,5 +la $16,2 +sll $24,$16,8*(4-2); sra $24,$24,8*(4-2) +div $19,$19,$24 +la $24,2 +beq $19,$24,L.1599 +la $23,219 +beq $30,$0,L.1601 +la $4,L.687 +move $5,$23 +jal printf +L.1601: +L.1599: +la $19,5 +la $24,2 +sw $24,-4+160($sp) +lw $24,-4+160($sp) +div $19,$19,$24 +la $24,2 +beq $19,$24,L.1603 +la $23,220 +beq $30,$0,L.1605 +la $4,L.687 +move $5,$23 +jal printf +L.1605: +L.1603: +la $19,5 +la $24,2 +sw $24,-8+160($sp) +lw $15,-8+160($sp) +div $19,$19,$15 +beq $19,$24,L.1607 +la $23,221 +beq $30,$0,L.1609 +la $4,L.687 +move $5,$23 +jal printf +L.1609: +L.1607: +la $19,5 +la $24,2 +sw $24,-12+160($sp) +move $24,$19 +lw $15,-12+160($sp) +divu $24,$24,$15 +move $19,$24 +la $24,2 +beq $19,$24,L.1611 +la $23,222 +beq $30,$0,L.1613 +la $4,L.687 +move $5,$23 +jal printf +L.1613: +L.1611: +la $19,5 +l.s $f26,L.529 +mtc1 $19,$f18; cvt.s.w $f18,$f18 +div.s $f18,$f18,$f26 +trunc.w.s $f2,$f18,$19; mfc1 $19,$f2 +la $24,2 +beq $19,$24,L.1615 +la $23,223 +beq $30,$0,L.1617 +la $4,L.687 +move $5,$23 +jal printf +L.1617: +L.1615: +la $19,5 +l.d $f24,L.416 +mtc1 $19,$f18; cvt.d.w $f18,$f18 +div.d $f18,$f18,$f24 +trunc.w.d $f2,$f18,$19; mfc1 $19,$f2 +la $24,2 +beq $19,$24,L.1619 +la $23,224 +beq $30,$0,L.1621 +la $4,L.687 +move $5,$23 +jal printf +L.1621: +L.1619: +la $18,5 +la $17,2 +sll $24,$17,8*(4-1); sra $24,$24,8*(4-1) +divu $18,$18,$24 +la $24,2 +beq $18,$24,L.1623 +la $23,225 +beq $30,$0,L.1625 +la $4,L.687 +move $5,$23 +jal printf +L.1625: +L.1623: +la $18,5 +la $16,2 +sll $24,$16,8*(4-2); sra $24,$24,8*(4-2) +divu $18,$18,$24 +la $24,2 +beq $18,$24,L.1627 +la $23,226 +beq $30,$0,L.1629 +la $4,L.687 +move $5,$23 +jal printf +L.1629: +L.1627: +la $18,5 +la $24,2 +sw $24,-4+160($sp) +lw $24,-4+160($sp) +divu $18,$18,$24 +la $24,2 +beq $18,$24,L.1631 +la $23,227 +beq $30,$0,L.1633 +la $4,L.687 +move $5,$23 +jal printf +L.1633: +L.1631: +la $18,5 +la $24,2 +sw $24,-8+160($sp) +lw $24,-8+160($sp) +divu $18,$18,$24 +la $24,2 +beq $18,$24,L.1635 +la $23,228 +beq $30,$0,L.1637 +la $4,L.687 +move $5,$23 +jal printf +L.1637: +L.1635: +la $18,5 +la $24,2 +sw $24,-12+160($sp) +lw $15,-12+160($sp) +divu $18,$18,$15 +beq $18,$24,L.1639 +la $23,229 +beq $30,$0,L.1641 +la $4,L.687 +move $5,$23 +jal printf +L.1641: +L.1639: +la $18,5 +l.s $f26,L.529 +l.d $f18,L.596 +srl $24,$18,1 +mtc1 $24,$f16; cvt.d.w $f16,$f16 +mul.d $f18,$f18,$f16 +and $24,$18,1 +mtc1 $24,$f16; cvt.d.w $f16,$f16 +add.d $f18,$f18,$f16 +cvt.s.d $f18,$f18 +div.s $f18,$f18,$f26 +l.s $f16,L.828 +c.ult.s $f18,$f16; bc1t L.1644 +sub.s $f16,$f18,$f16 +trunc.w.s $f2,$f16,$24; mfc1 $24,$f2 +la $24,0x80000000($24) +sw $24,-60+160($sp) +b L.1645 +L.1644: +trunc.w.s $f2,$f18,$24; mfc1 $24,$f2 +sw $24,-60+160($sp) +L.1645: +lw $18,-60+160($sp) +la $24,2 +beq $18,$24,L.1646 +la $23,230 +beq $30,$0,L.1648 +la $4,L.687 +move $5,$23 +jal printf +L.1648: +L.1646: +la $18,5 +l.d $f24,L.416 +l.d $f18,L.596 +srl $24,$18,1 +mtc1 $24,$f16; cvt.d.w $f16,$f16 +mul.d $f18,$f18,$f16 +and $24,$18,1 +mtc1 $24,$f16; cvt.d.w $f16,$f16 +add.d $f18,$f18,$f16 +div.d $f18,$f18,$f24 +l.d $f16,L.836 +c.ult.d $f18,$f16; bc1t L.1651 +sub.d $f16,$f18,$f16 +trunc.w.d $f2,$f16,$24; mfc1 $24,$f2 +la $24,0x80000000($24) +sw $24,-64+160($sp) +b L.1652 +L.1651: +trunc.w.d $f2,$f18,$24; mfc1 $24,$f2 +sw $24,-64+160($sp) +L.1652: +lw $18,-64+160($sp) +la $24,2 +beq $18,$24,L.1653 +la $23,231 +beq $30,$0,L.1655 +la $4,L.687 +move $5,$23 +jal printf +L.1655: +L.1653: +l.s $f30,L.841 +la $17,2 +sll $24,$17,8*(4-1); sra $24,$24,8*(4-1) +mtc1 $24,$f18; cvt.s.w $f18,$f18 +div.s $f30,$f30,$f18 +cvt.d.s $f18,$f30 +l.d $f16,L.1659 +c.eq.d $f18,$f16; bc1t L.1657 +la $23,232 +beq $30,$0,L.1660 +la $4,L.687 +move $5,$23 +jal printf +L.1660: +L.1657: +l.s $f30,L.841 +la $16,2 +sll $24,$16,8*(4-2); sra $24,$24,8*(4-2) +mtc1 $24,$f18; cvt.s.w $f18,$f18 +div.s $f30,$f30,$f18 +cvt.d.s $f18,$f30 +l.d $f16,L.1659 +c.eq.d $f18,$f16; bc1t L.1662 +la $23,233 +beq $30,$0,L.1664 +la $4,L.687 +move $5,$23 +jal printf +L.1664: +L.1662: +l.s $f30,L.841 +la $24,2 +sw $24,-4+160($sp) +lw $24,-4+160($sp) +mtc1 $24,$f18; cvt.s.w $f18,$f18 +div.s $f30,$f30,$f18 +cvt.d.s $f18,$f30 +l.d $f16,L.1659 +c.eq.d $f18,$f16; bc1t L.1666 +la $23,234 +beq $30,$0,L.1668 +la $4,L.687 +move $5,$23 +jal printf +L.1668: +L.1666: +l.s $f30,L.841 +la $24,2 +sw $24,-8+160($sp) +lw $24,-8+160($sp) +mtc1 $24,$f18; cvt.s.w $f18,$f18 +div.s $f30,$f30,$f18 +cvt.d.s $f18,$f30 +l.d $f16,L.1659 +c.eq.d $f18,$f16; bc1t L.1670 +la $23,235 +beq $30,$0,L.1672 +la $4,L.687 +move $5,$23 +jal printf +L.1672: +L.1670: +l.s $f30,L.841 +la $24,2 +sw $24,-12+160($sp) +lw $24,-12+160($sp) +l.d $f18,L.596 +srl $15,$24,1 +mtc1 $15,$f16; cvt.d.w $f16,$f16 +mul.d $f18,$f18,$f16 +and $24,$24,1 +mtc1 $24,$f16; cvt.d.w $f16,$f16 +add.d $f18,$f18,$f16 +cvt.s.d $f18,$f18 +div.s $f30,$f30,$f18 +cvt.d.s $f18,$f30 +l.d $f16,L.1659 +c.eq.d $f18,$f16; bc1t L.1674 +la $23,236 +beq $30,$0,L.1676 +la $4,L.687 +move $5,$23 +jal printf +L.1676: +L.1674: +l.s $f30,L.841 +l.s $f26,L.529 +div.s $f30,$f30,$f26 +cvt.d.s $f18,$f30 +l.d $f16,L.1659 +c.eq.d $f18,$f16; bc1t L.1678 +la $23,237 +beq $30,$0,L.1680 +la $4,L.687 +move $5,$23 +jal printf +L.1680: +L.1678: +l.s $f30,L.841 +l.d $f24,L.416 +cvt.d.s $f18,$f30 +div.d $f18,$f18,$f24 +cvt.s.d $f30,$f18 +cvt.d.s $f18,$f30 +l.d $f16,L.1659 +c.eq.d $f18,$f16; bc1t L.1682 +la $23,238 +beq $30,$0,L.1684 +la $4,L.687 +move $5,$23 +jal printf +L.1684: +L.1682: +l.d $f28,L.870 +la $17,2 +sll $24,$17,8*(4-1); sra $24,$24,8*(4-1) +mtc1 $24,$f18; cvt.d.w $f18,$f18 +div.d $f28,$f28,$f18 +l.d $f18,L.1659 +c.eq.d $f28,$f18; bc1t L.1686 +la $23,239 +beq $30,$0,L.1688 +la $4,L.687 +move $5,$23 +jal printf +L.1688: +L.1686: +l.d $f28,L.870 +la $16,2 +sll $24,$16,8*(4-2); sra $24,$24,8*(4-2) +mtc1 $24,$f18; cvt.d.w $f18,$f18 +div.d $f28,$f28,$f18 +l.d $f18,L.1659 +c.eq.d $f28,$f18; bc1t L.1690 +la $23,240 +beq $30,$0,L.1692 +la $4,L.687 +move $5,$23 +jal printf +L.1692: +L.1690: +l.d $f28,L.870 +la $24,2 +sw $24,-4+160($sp) +lw $24,-4+160($sp) +mtc1 $24,$f18; cvt.d.w $f18,$f18 +div.d $f28,$f28,$f18 +l.d $f18,L.1659 +c.eq.d $f28,$f18; bc1t L.1694 +la $23,241 +beq $30,$0,L.1696 +la $4,L.687 +move $5,$23 +jal printf +L.1696: +L.1694: +l.d $f28,L.870 +la $24,2 +sw $24,-8+160($sp) +lw $24,-8+160($sp) +mtc1 $24,$f18; cvt.d.w $f18,$f18 +div.d $f28,$f28,$f18 +l.d $f18,L.1659 +c.eq.d $f28,$f18; bc1t L.1698 +la $23,242 +beq $30,$0,L.1700 +la $4,L.687 +move $5,$23 +jal printf +L.1700: +L.1698: +l.d $f28,L.870 +la $24,2 +sw $24,-12+160($sp) +lw $24,-12+160($sp) +l.d $f18,L.596 +srl $15,$24,1 +mtc1 $15,$f16; cvt.d.w $f16,$f16 +mul.d $f18,$f18,$f16 +and $24,$24,1 +mtc1 $24,$f16; cvt.d.w $f16,$f16 +add.d $f18,$f18,$f16 +div.d $f28,$f28,$f18 +l.d $f18,L.1659 +c.eq.d $f28,$f18; bc1t L.1702 +la $23,243 +beq $30,$0,L.1704 +la $4,L.687 +move $5,$23 +jal printf +L.1704: +L.1702: +l.d $f28,L.870 +l.s $f26,L.529 +cvt.d.s $f18,$f26 +div.d $f28,$f28,$f18 +l.d $f18,L.1659 +c.eq.d $f28,$f18; bc1t L.1706 +la $23,244 +beq $30,$0,L.1708 +la $4,L.687 +move $5,$23 +jal printf +L.1708: +L.1706: +l.d $f28,L.870 +l.d $f24,L.416 +div.d $f28,$f28,$f24 +l.d $f18,L.1659 +c.eq.d $f28,$f18; bc1t L.1710 +la $23,245 +beq $30,$0,L.1712 +la $4,L.687 +move $5,$23 +jal printf +L.1712: +L.1710: +la $22,5 +la $17,2 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +sll $15,$17,8*(4-1); sra $15,$15,8*(4-1) +rem $24,$24,$15 +move $22,$24 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +la $15,1 +beq $24,$15,L.1714 +la $23,246 +beq $30,$0,L.1716 +la $4,L.687 +move $5,$23 +jal printf +L.1716: +L.1714: +la $22,5 +la $16,2 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +sll $15,$16,8*(4-2); sra $15,$15,8*(4-2) +rem $24,$24,$15 +move $22,$24 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +la $15,1 +beq $24,$15,L.1718 +la $23,247 +beq $30,$0,L.1720 +la $4,L.687 +move $5,$23 +jal printf +L.1720: +L.1718: +la $22,5 +la $24,2 +sw $24,-4+160($sp) +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +lw $15,-4+160($sp) +rem $24,$24,$15 +move $22,$24 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +la $15,1 +beq $24,$15,L.1722 +la $23,248 +beq $30,$0,L.1724 +la $4,L.687 +move $5,$23 +jal printf +L.1724: +L.1722: +la $22,5 +la $24,2 +sw $24,-8+160($sp) +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +lw $15,-8+160($sp) +rem $24,$24,$15 +move $22,$24 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +la $15,1 +beq $24,$15,L.1726 +la $23,249 +beq $30,$0,L.1728 +la $4,L.687 +move $5,$23 +jal printf +L.1728: +L.1726: +la $22,5 +la $24,2 +sw $24,-12+160($sp) +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +lw $15,-12+160($sp) +remu $24,$24,$15 +move $22,$24 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +la $15,1 +beq $24,$15,L.1730 +la $23,250 +beq $30,$0,L.1732 +la $4,L.687 +move $5,$23 +jal printf +L.1732: +L.1730: +la $21,5 +la $17,2 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +sll $15,$17,8*(4-1); sra $15,$15,8*(4-1) +rem $24,$24,$15 +move $21,$24 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +la $15,1 +beq $24,$15,L.1734 +la $23,251 +beq $30,$0,L.1736 +la $4,L.687 +move $5,$23 +jal printf +L.1736: +L.1734: +la $21,5 +la $16,2 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +sll $15,$16,8*(4-2); sra $15,$15,8*(4-2) +rem $24,$24,$15 +move $21,$24 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +la $15,1 +beq $24,$15,L.1738 +la $23,252 +beq $30,$0,L.1740 +la $4,L.687 +move $5,$23 +jal printf +L.1740: +L.1738: +la $21,5 +la $24,2 +sw $24,-4+160($sp) +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +lw $15,-4+160($sp) +rem $24,$24,$15 +move $21,$24 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +la $15,1 +beq $24,$15,L.1742 +la $23,253 +beq $30,$0,L.1744 +la $4,L.687 +move $5,$23 +jal printf +L.1744: +L.1742: +la $21,5 +la $24,2 +sw $24,-8+160($sp) +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +lw $15,-8+160($sp) +rem $24,$24,$15 +move $21,$24 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +la $15,1 +beq $24,$15,L.1746 +la $23,254 +beq $30,$0,L.1748 +la $4,L.687 +move $5,$23 +jal printf +L.1748: +L.1746: +la $21,5 +la $24,2 +sw $24,-12+160($sp) +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +lw $15,-12+160($sp) +remu $24,$24,$15 +move $21,$24 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +la $15,1 +beq $24,$15,L.1750 +la $23,255 +beq $30,$0,L.1752 +la $4,L.687 +move $5,$23 +jal printf +L.1752: +L.1750: +la $20,5 +la $17,2 +sll $24,$17,8*(4-1); sra $24,$24,8*(4-1) +rem $20,$20,$24 +la $24,1 +beq $20,$24,L.1754 +la $23,256 +beq $30,$0,L.1756 +la $4,L.687 +move $5,$23 +jal printf +L.1756: +L.1754: +la $20,5 +la $16,2 +sll $24,$16,8*(4-2); sra $24,$24,8*(4-2) +rem $20,$20,$24 +la $24,1 +beq $20,$24,L.1758 +la $23,257 +beq $30,$0,L.1760 +la $4,L.687 +move $5,$23 +jal printf +L.1760: +L.1758: +la $20,5 +la $24,2 +sw $24,-4+160($sp) +lw $24,-4+160($sp) +rem $20,$20,$24 +la $24,1 +beq $20,$24,L.1762 +la $23,258 +beq $30,$0,L.1764 +la $4,L.687 +move $5,$23 +jal printf +L.1764: +L.1762: +la $20,5 +la $24,2 +sw $24,-8+160($sp) +lw $24,-8+160($sp) +rem $20,$20,$24 +la $24,1 +beq $20,$24,L.1766 +la $23,259 +beq $30,$0,L.1768 +la $4,L.687 +move $5,$23 +jal printf +L.1768: +L.1766: +la $20,5 +la $24,2 +sw $24,-12+160($sp) +move $24,$20 +lw $15,-12+160($sp) +remu $24,$24,$15 +move $20,$24 +la $24,1 +beq $20,$24,L.1770 +la $23,260 +beq $30,$0,L.1772 +la $4,L.687 +move $5,$23 +jal printf +L.1772: +L.1770: +la $19,5 +la $17,2 +sll $24,$17,8*(4-1); sra $24,$24,8*(4-1) +rem $19,$19,$24 +la $24,1 +beq $19,$24,L.1774 +la $23,261 +beq $30,$0,L.1776 +la $4,L.687 +move $5,$23 +jal printf +L.1776: +L.1774: +la $19,5 +la $16,2 +sll $24,$16,8*(4-2); sra $24,$24,8*(4-2) +rem $19,$19,$24 +la $24,1 +beq $19,$24,L.1778 +la $23,262 +beq $30,$0,L.1780 +la $4,L.687 +move $5,$23 +jal printf +L.1780: +L.1778: +la $19,5 +la $24,2 +sw $24,-4+160($sp) +lw $24,-4+160($sp) +rem $19,$19,$24 +la $24,1 +beq $19,$24,L.1782 +la $23,263 +beq $30,$0,L.1784 +la $4,L.687 +move $5,$23 +jal printf +L.1784: +L.1782: +la $19,5 +la $24,2 +sw $24,-8+160($sp) +lw $24,-8+160($sp) +rem $19,$19,$24 +la $24,1 +beq $19,$24,L.1786 +la $23,264 +beq $30,$0,L.1788 +la $4,L.687 +move $5,$23 +jal printf +L.1788: +L.1786: +la $19,5 +la $24,2 +sw $24,-12+160($sp) +move $24,$19 +lw $15,-12+160($sp) +remu $24,$24,$15 +move $19,$24 +la $24,1 +beq $19,$24,L.1790 +la $23,265 +beq $30,$0,L.1792 +la $4,L.687 +move $5,$23 +jal printf +L.1792: +L.1790: +la $18,5 +la $17,2 +sll $24,$17,8*(4-1); sra $24,$24,8*(4-1) +remu $18,$18,$24 +la $24,1 +beq $18,$24,L.1794 +la $23,266 +beq $30,$0,L.1796 +la $4,L.687 +move $5,$23 +jal printf +L.1796: +L.1794: +la $18,5 +la $16,2 +sll $24,$16,8*(4-2); sra $24,$24,8*(4-2) +remu $18,$18,$24 +la $24,1 +beq $18,$24,L.1798 +la $23,267 +beq $30,$0,L.1800 +la $4,L.687 +move $5,$23 +jal printf +L.1800: +L.1798: +la $18,5 +la $24,2 +sw $24,-4+160($sp) +lw $24,-4+160($sp) +remu $18,$18,$24 +la $24,1 +beq $18,$24,L.1802 +la $23,268 +beq $30,$0,L.1804 +la $4,L.687 +move $5,$23 +jal printf +L.1804: +L.1802: +la $18,5 +la $24,2 +sw $24,-8+160($sp) +lw $24,-8+160($sp) +remu $18,$18,$24 +la $24,1 +beq $18,$24,L.1806 +la $23,269 +beq $30,$0,L.1808 +la $4,L.687 +move $5,$23 +jal printf +L.1808: +L.1806: +la $18,5 +la $24,2 +sw $24,-12+160($sp) +lw $24,-12+160($sp) +remu $18,$18,$24 +la $24,1 +beq $18,$24,L.1810 +la $23,270 +beq $30,$0,L.1812 +la $4,L.687 +move $5,$23 +jal printf +L.1812: +L.1810: +la $22,5 +la $17,2 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +sll $15,$17,8*(4-1); sra $15,$15,8*(4-1) +sra $24,$24,$15 +move $22,$24 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +la $15,1 +beq $24,$15,L.1814 +la $23,271 +beq $30,$0,L.1816 +la $4,L.687 +move $5,$23 +jal printf +L.1816: +L.1814: +la $22,5 +la $16,2 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +sll $15,$16,8*(4-2); sra $15,$15,8*(4-2) +sra $24,$24,$15 +move $22,$24 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +la $15,1 +beq $24,$15,L.1818 +la $23,272 +beq $30,$0,L.1820 +la $4,L.687 +move $5,$23 +jal printf +L.1820: +L.1818: +la $22,5 +la $24,2 +sw $24,-4+160($sp) +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +lw $15,-4+160($sp) +sra $24,$24,$15 +move $22,$24 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +la $15,1 +beq $24,$15,L.1822 +la $23,273 +beq $30,$0,L.1824 +la $4,L.687 +move $5,$23 +jal printf +L.1824: +L.1822: +la $22,5 +la $24,2 +sw $24,-8+160($sp) +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +lw $15,-8+160($sp) +sra $24,$24,$15 +move $22,$24 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +la $15,1 +beq $24,$15,L.1826 +la $23,274 +beq $30,$0,L.1828 +la $4,L.687 +move $5,$23 +jal printf +L.1828: +L.1826: +la $22,5 +la $24,2 +sw $24,-12+160($sp) +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +lw $15,-12+160($sp) +sra $24,$24,$15 +move $22,$24 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +la $15,1 +beq $24,$15,L.1830 +la $23,275 +beq $30,$0,L.1832 +la $4,L.687 +move $5,$23 +jal printf +L.1832: +L.1830: +la $21,5 +la $17,2 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +sll $15,$17,8*(4-1); sra $15,$15,8*(4-1) +sra $24,$24,$15 +move $21,$24 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +la $15,1 +beq $24,$15,L.1834 +la $23,276 +beq $30,$0,L.1836 +la $4,L.687 +move $5,$23 +jal printf +L.1836: +L.1834: +la $21,5 +la $16,2 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +sll $15,$16,8*(4-2); sra $15,$15,8*(4-2) +sra $24,$24,$15 +move $21,$24 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +la $15,1 +beq $24,$15,L.1838 +la $23,277 +beq $30,$0,L.1840 +la $4,L.687 +move $5,$23 +jal printf +L.1840: +L.1838: +la $21,5 +la $24,2 +sw $24,-4+160($sp) +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +lw $15,-4+160($sp) +sra $24,$24,$15 +move $21,$24 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +la $15,1 +beq $24,$15,L.1842 +la $23,278 +beq $30,$0,L.1844 +la $4,L.687 +move $5,$23 +jal printf +L.1844: +L.1842: +la $21,5 +la $24,2 +sw $24,-8+160($sp) +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +lw $15,-8+160($sp) +sra $24,$24,$15 +move $21,$24 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +la $15,1 +beq $24,$15,L.1846 +la $23,279 +beq $30,$0,L.1848 +la $4,L.687 +move $5,$23 +jal printf +L.1848: +L.1846: +la $21,5 +la $24,2 +sw $24,-12+160($sp) +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +lw $15,-12+160($sp) +sra $24,$24,$15 +move $21,$24 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +la $15,1 +beq $24,$15,L.1850 +la $23,280 +beq $30,$0,L.1852 +la $4,L.687 +move $5,$23 +jal printf +L.1852: +L.1850: +la $20,5 +la $17,2 +sll $24,$17,8*(4-1); sra $24,$24,8*(4-1) +sra $20,$20,$24 +la $24,1 +beq $20,$24,L.1854 +la $23,281 +beq $30,$0,L.1856 +la $4,L.687 +move $5,$23 +jal printf +L.1856: +L.1854: +la $20,5 +la $16,2 +sll $24,$16,8*(4-2); sra $24,$24,8*(4-2) +sra $20,$20,$24 +la $24,1 +beq $20,$24,L.1858 +la $23,282 +beq $30,$0,L.1860 +la $4,L.687 +move $5,$23 +jal printf +L.1860: +L.1858: +la $20,5 +la $24,2 +sw $24,-4+160($sp) +lw $24,-4+160($sp) +sra $20,$20,$24 +la $24,1 +beq $20,$24,L.1862 +la $23,283 +beq $30,$0,L.1864 +la $4,L.687 +move $5,$23 +jal printf +L.1864: +L.1862: +la $20,5 +la $24,2 +sw $24,-8+160($sp) +lw $24,-8+160($sp) +sra $20,$20,$24 +la $24,1 +beq $20,$24,L.1866 +la $23,284 +beq $30,$0,L.1868 +la $4,L.687 +move $5,$23 +jal printf +L.1868: +L.1866: +la $20,5 +la $24,2 +sw $24,-12+160($sp) +lw $24,-12+160($sp) +sra $20,$20,$24 +la $24,1 +beq $20,$24,L.1870 +la $23,285 +beq $30,$0,L.1872 +la $4,L.687 +move $5,$23 +jal printf +L.1872: +L.1870: +la $19,5 +la $17,2 +sll $24,$17,8*(4-1); sra $24,$24,8*(4-1) +sra $19,$19,$24 +la $24,1 +beq $19,$24,L.1874 +la $23,286 +beq $30,$0,L.1876 +la $4,L.687 +move $5,$23 +jal printf +L.1876: +L.1874: +la $19,5 +la $16,2 +sll $24,$16,8*(4-2); sra $24,$24,8*(4-2) +sra $19,$19,$24 +la $24,1 +beq $19,$24,L.1878 +la $23,287 +beq $30,$0,L.1880 +la $4,L.687 +move $5,$23 +jal printf +L.1880: +L.1878: +la $19,5 +la $24,2 +sw $24,-4+160($sp) +lw $24,-4+160($sp) +sra $19,$19,$24 +la $24,1 +beq $19,$24,L.1882 +la $23,288 +beq $30,$0,L.1884 +la $4,L.687 +move $5,$23 +jal printf +L.1884: +L.1882: +la $19,5 +la $24,2 +sw $24,-8+160($sp) +lw $24,-8+160($sp) +sra $19,$19,$24 +la $24,1 +beq $19,$24,L.1886 +la $23,289 +beq $30,$0,L.1888 +la $4,L.687 +move $5,$23 +jal printf +L.1888: +L.1886: +la $19,5 +la $24,2 +sw $24,-12+160($sp) +lw $24,-12+160($sp) +sra $19,$19,$24 +la $24,1 +beq $19,$24,L.1890 +la $23,290 +beq $30,$0,L.1892 +la $4,L.687 +move $5,$23 +jal printf +L.1892: +L.1890: +la $18,5 +la $17,2 +sll $24,$17,8*(4-1); sra $24,$24,8*(4-1) +srl $18,$18,$24 +la $24,1 +beq $18,$24,L.1894 +la $23,291 +beq $30,$0,L.1896 +la $4,L.687 +move $5,$23 +jal printf +L.1896: +L.1894: +la $18,5 +la $16,2 +sll $24,$16,8*(4-2); sra $24,$24,8*(4-2) +srl $18,$18,$24 +la $24,1 +beq $18,$24,L.1898 +la $23,292 +beq $30,$0,L.1900 +la $4,L.687 +move $5,$23 +jal printf +L.1900: +L.1898: +la $18,5 +la $24,2 +sw $24,-4+160($sp) +lw $24,-4+160($sp) +srl $18,$18,$24 +la $24,1 +beq $18,$24,L.1902 +la $23,293 +beq $30,$0,L.1904 +la $4,L.687 +move $5,$23 +jal printf +L.1904: +L.1902: +la $18,5 +la $24,2 +sw $24,-8+160($sp) +lw $24,-8+160($sp) +srl $18,$18,$24 +la $24,1 +beq $18,$24,L.1906 +la $23,294 +beq $30,$0,L.1908 +la $4,L.687 +move $5,$23 +jal printf +L.1908: +L.1906: +la $18,5 +la $24,2 +sw $24,-12+160($sp) +lw $24,-12+160($sp) +srl $18,$18,$24 +la $24,1 +beq $18,$24,L.1910 +la $23,295 +beq $30,$0,L.1912 +la $4,L.687 +move $5,$23 +jal printf +L.1912: +L.1910: +la $22,5 +la $17,2 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +sll $15,$17,8*(4-1); sra $15,$15,8*(4-1) +sll $24,$24,$15 +move $22,$24 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +la $15,20 +beq $24,$15,L.1914 +la $23,296 +beq $30,$0,L.1916 +la $4,L.687 +move $5,$23 +jal printf +L.1916: +L.1914: +la $22,5 +la $16,2 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +sll $15,$16,8*(4-2); sra $15,$15,8*(4-2) +sll $24,$24,$15 +move $22,$24 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +la $15,20 +beq $24,$15,L.1918 +la $23,297 +beq $30,$0,L.1920 +la $4,L.687 +move $5,$23 +jal printf +L.1920: +L.1918: +la $22,5 +la $24,2 +sw $24,-4+160($sp) +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +lw $15,-4+160($sp) +sll $24,$24,$15 +move $22,$24 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +la $15,20 +beq $24,$15,L.1922 +la $23,298 +beq $30,$0,L.1924 +la $4,L.687 +move $5,$23 +jal printf +L.1924: +L.1922: +la $22,5 +la $24,2 +sw $24,-8+160($sp) +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +lw $15,-8+160($sp) +sll $24,$24,$15 +move $22,$24 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +la $15,20 +beq $24,$15,L.1926 +la $23,299 +beq $30,$0,L.1928 +la $4,L.687 +move $5,$23 +jal printf +L.1928: +L.1926: +la $22,5 +la $24,2 +sw $24,-12+160($sp) +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +lw $15,-12+160($sp) +sll $24,$24,$15 +move $22,$24 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +la $15,20 +beq $24,$15,L.1930 +la $23,300 +beq $30,$0,L.1932 +la $4,L.687 +move $5,$23 +jal printf +L.1932: +L.1930: +la $21,5 +la $17,2 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +sll $15,$17,8*(4-1); sra $15,$15,8*(4-1) +sll $24,$24,$15 +move $21,$24 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +la $15,20 +beq $24,$15,L.1934 +la $23,301 +beq $30,$0,L.1936 +la $4,L.687 +move $5,$23 +jal printf +L.1936: +L.1934: +la $21,5 +la $16,2 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +sll $15,$16,8*(4-2); sra $15,$15,8*(4-2) +sll $24,$24,$15 +move $21,$24 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +la $15,20 +beq $24,$15,L.1938 +la $23,302 +beq $30,$0,L.1940 +la $4,L.687 +move $5,$23 +jal printf +L.1940: +L.1938: +la $21,5 +la $24,2 +sw $24,-4+160($sp) +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +lw $15,-4+160($sp) +sll $24,$24,$15 +move $21,$24 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +la $15,20 +beq $24,$15,L.1942 +la $23,303 +beq $30,$0,L.1944 +la $4,L.687 +move $5,$23 +jal printf +L.1944: +L.1942: +la $21,5 +la $24,2 +sw $24,-8+160($sp) +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +lw $15,-8+160($sp) +sll $24,$24,$15 +move $21,$24 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +la $15,20 +beq $24,$15,L.1946 +la $23,304 +beq $30,$0,L.1948 +la $4,L.687 +move $5,$23 +jal printf +L.1948: +L.1946: +la $21,5 +la $24,2 +sw $24,-12+160($sp) +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +lw $15,-12+160($sp) +sll $24,$24,$15 +move $21,$24 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +la $15,20 +beq $24,$15,L.1950 +la $23,305 +beq $30,$0,L.1952 +la $4,L.687 +move $5,$23 +jal printf +L.1952: +L.1950: +la $20,5 +la $17,2 +sll $24,$17,8*(4-1); sra $24,$24,8*(4-1) +sll $20,$20,$24 +la $24,20 +beq $20,$24,L.1954 +la $23,306 +beq $30,$0,L.1956 +la $4,L.687 +move $5,$23 +jal printf +L.1956: +L.1954: +la $20,5 +la $16,2 +sll $24,$16,8*(4-2); sra $24,$24,8*(4-2) +sll $20,$20,$24 +la $24,20 +beq $20,$24,L.1958 +la $23,307 +beq $30,$0,L.1960 +la $4,L.687 +move $5,$23 +jal printf +L.1960: +L.1958: +la $20,5 +la $24,2 +sw $24,-4+160($sp) +lw $24,-4+160($sp) +sll $20,$20,$24 +la $24,20 +beq $20,$24,L.1962 +la $23,308 +beq $30,$0,L.1964 +la $4,L.687 +move $5,$23 +jal printf +L.1964: +L.1962: +la $20,5 +la $24,2 +sw $24,-8+160($sp) +lw $24,-8+160($sp) +sll $20,$20,$24 +la $24,20 +beq $20,$24,L.1966 +la $23,309 +beq $30,$0,L.1968 +la $4,L.687 +move $5,$23 +jal printf +L.1968: +L.1966: +la $20,5 +la $24,2 +sw $24,-12+160($sp) +lw $24,-12+160($sp) +sll $20,$20,$24 +la $24,20 +beq $20,$24,L.1970 +la $23,310 +beq $30,$0,L.1972 +la $4,L.687 +move $5,$23 +jal printf +L.1972: +L.1970: +la $19,5 +la $17,2 +sll $24,$17,8*(4-1); sra $24,$24,8*(4-1) +sll $19,$19,$24 +la $24,20 +beq $19,$24,L.1974 +la $23,311 +beq $30,$0,L.1976 +la $4,L.687 +move $5,$23 +jal printf +L.1976: +L.1974: +la $19,5 +la $16,2 +sll $24,$16,8*(4-2); sra $24,$24,8*(4-2) +sll $19,$19,$24 +la $24,20 +beq $19,$24,L.1978 +la $23,312 +beq $30,$0,L.1980 +la $4,L.687 +move $5,$23 +jal printf +L.1980: +L.1978: +la $19,5 +la $24,2 +sw $24,-4+160($sp) +lw $24,-4+160($sp) +sll $19,$19,$24 +la $24,20 +beq $19,$24,L.1982 +la $23,313 +beq $30,$0,L.1984 +la $4,L.687 +move $5,$23 +jal printf +L.1984: +L.1982: +la $19,5 +la $24,2 +sw $24,-8+160($sp) +lw $24,-8+160($sp) +sll $19,$19,$24 +la $24,20 +beq $19,$24,L.1986 +la $23,314 +beq $30,$0,L.1988 +la $4,L.687 +move $5,$23 +jal printf +L.1988: +L.1986: +la $19,5 +la $24,2 +sw $24,-12+160($sp) +lw $24,-12+160($sp) +sll $19,$19,$24 +la $24,20 +beq $19,$24,L.1990 +la $23,315 +beq $30,$0,L.1992 +la $4,L.687 +move $5,$23 +jal printf +L.1992: +L.1990: +la $18,5 +la $17,2 +sll $24,$17,8*(4-1); sra $24,$24,8*(4-1) +sll $18,$18,$24 +la $24,20 +beq $18,$24,L.1994 +la $23,316 +beq $30,$0,L.1996 +la $4,L.687 +move $5,$23 +jal printf +L.1996: +L.1994: +la $18,5 +la $16,2 +sll $24,$16,8*(4-2); sra $24,$24,8*(4-2) +sll $18,$18,$24 +la $24,20 +beq $18,$24,L.1998 +la $23,317 +beq $30,$0,L.2000 +la $4,L.687 +move $5,$23 +jal printf +L.2000: +L.1998: +la $18,5 +la $24,2 +sw $24,-4+160($sp) +lw $24,-4+160($sp) +sll $18,$18,$24 +la $24,20 +beq $18,$24,L.2002 +la $23,318 +beq $30,$0,L.2004 +la $4,L.687 +move $5,$23 +jal printf +L.2004: +L.2002: +la $18,5 +la $24,2 +sw $24,-8+160($sp) +lw $24,-8+160($sp) +sll $18,$18,$24 +la $24,20 +beq $18,$24,L.2006 +la $23,319 +beq $30,$0,L.2008 +la $4,L.687 +move $5,$23 +jal printf +L.2008: +L.2006: +la $18,5 +la $24,2 +sw $24,-12+160($sp) +lw $24,-12+160($sp) +sll $18,$18,$24 +la $24,20 +beq $18,$24,L.2010 +la $23,320 +beq $30,$0,L.2012 +la $4,L.687 +move $5,$23 +jal printf +L.2012: +L.2010: +la $22,12 +la $17,10 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +sll $15,$17,8*(4-1); sra $15,$15,8*(4-1) +and $24,$24,$15 +move $22,$24 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +la $15,8 +beq $24,$15,L.2014 +la $23,321 +beq $30,$0,L.2016 +la $4,L.687 +move $5,$23 +jal printf +L.2016: +L.2014: +la $22,12 +la $16,10 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +sll $15,$16,8*(4-2); sra $15,$15,8*(4-2) +and $24,$24,$15 +move $22,$24 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +la $15,8 +beq $24,$15,L.2018 +la $23,322 +beq $30,$0,L.2020 +la $4,L.687 +move $5,$23 +jal printf +L.2020: +L.2018: +la $22,12 +la $24,10 +sw $24,-4+160($sp) +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +lw $15,-4+160($sp) +and $24,$24,$15 +move $22,$24 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +la $15,8 +beq $24,$15,L.2022 +la $23,323 +beq $30,$0,L.2024 +la $4,L.687 +move $5,$23 +jal printf +L.2024: +L.2022: +la $22,12 +la $24,10 +sw $24,-8+160($sp) +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +lw $15,-8+160($sp) +and $24,$24,$15 +move $22,$24 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +la $15,8 +beq $24,$15,L.2026 +la $23,324 +beq $30,$0,L.2028 +la $4,L.687 +move $5,$23 +jal printf +L.2028: +L.2026: +la $22,12 +la $24,10 +sw $24,-12+160($sp) +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +lw $15,-12+160($sp) +and $24,$24,$15 +move $22,$24 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +la $15,8 +beq $24,$15,L.2030 +la $23,325 +beq $30,$0,L.2032 +la $4,L.687 +move $5,$23 +jal printf +L.2032: +L.2030: +la $21,12 +la $17,10 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +sll $15,$17,8*(4-1); sra $15,$15,8*(4-1) +and $24,$24,$15 +move $21,$24 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +la $15,8 +beq $24,$15,L.2034 +la $23,326 +beq $30,$0,L.2036 +la $4,L.687 +move $5,$23 +jal printf +L.2036: +L.2034: +la $21,12 +la $16,10 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +sll $15,$16,8*(4-2); sra $15,$15,8*(4-2) +and $24,$24,$15 +move $21,$24 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +la $15,8 +beq $24,$15,L.2038 +la $23,327 +beq $30,$0,L.2040 +la $4,L.687 +move $5,$23 +jal printf +L.2040: +L.2038: +la $21,12 +la $24,10 +sw $24,-4+160($sp) +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +lw $15,-4+160($sp) +and $24,$24,$15 +move $21,$24 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +la $15,8 +beq $24,$15,L.2042 +la $23,328 +beq $30,$0,L.2044 +la $4,L.687 +move $5,$23 +jal printf +L.2044: +L.2042: +la $21,12 +la $24,10 +sw $24,-8+160($sp) +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +lw $15,-8+160($sp) +and $24,$24,$15 +move $21,$24 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +la $15,8 +beq $24,$15,L.2046 +la $23,329 +beq $30,$0,L.2048 +la $4,L.687 +move $5,$23 +jal printf +L.2048: +L.2046: +la $21,12 +la $24,10 +sw $24,-12+160($sp) +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +lw $15,-12+160($sp) +and $24,$24,$15 +move $21,$24 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +la $15,8 +beq $24,$15,L.2050 +la $23,330 +beq $30,$0,L.2052 +la $4,L.687 +move $5,$23 +jal printf +L.2052: +L.2050: +la $20,12 +la $17,10 +sll $24,$17,8*(4-1); sra $24,$24,8*(4-1) +and $20,$20,$24 +la $24,8 +beq $20,$24,L.2054 +la $23,331 +beq $30,$0,L.2056 +la $4,L.687 +move $5,$23 +jal printf +L.2056: +L.2054: +la $20,12 +la $16,10 +sll $24,$16,8*(4-2); sra $24,$24,8*(4-2) +and $20,$20,$24 +la $24,8 +beq $20,$24,L.2058 +la $23,332 +beq $30,$0,L.2060 +la $4,L.687 +move $5,$23 +jal printf +L.2060: +L.2058: +la $20,12 +la $24,10 +sw $24,-4+160($sp) +lw $24,-4+160($sp) +and $20,$20,$24 +la $24,8 +beq $20,$24,L.2062 +la $23,333 +beq $30,$0,L.2064 +la $4,L.687 +move $5,$23 +jal printf +L.2064: +L.2062: +la $20,12 +la $24,10 +sw $24,-8+160($sp) +lw $24,-8+160($sp) +and $20,$20,$24 +la $24,8 +beq $20,$24,L.2066 +la $23,334 +beq $30,$0,L.2068 +la $4,L.687 +move $5,$23 +jal printf +L.2068: +L.2066: +la $20,12 +la $24,10 +sw $24,-12+160($sp) +move $24,$20 +lw $15,-12+160($sp) +and $24,$24,$15 +move $20,$24 +la $24,8 +beq $20,$24,L.2070 +la $23,335 +beq $30,$0,L.2072 +la $4,L.687 +move $5,$23 +jal printf +L.2072: +L.2070: +la $19,12 +la $17,10 +sll $24,$17,8*(4-1); sra $24,$24,8*(4-1) +and $19,$19,$24 +la $24,8 +beq $19,$24,L.2074 +la $23,336 +beq $30,$0,L.2076 +la $4,L.687 +move $5,$23 +jal printf +L.2076: +L.2074: +la $19,12 +la $16,10 +sll $24,$16,8*(4-2); sra $24,$24,8*(4-2) +and $19,$19,$24 +la $24,8 +beq $19,$24,L.2078 +la $23,337 +beq $30,$0,L.2080 +la $4,L.687 +move $5,$23 +jal printf +L.2080: +L.2078: +la $19,12 +la $24,10 +sw $24,-4+160($sp) +lw $24,-4+160($sp) +and $19,$19,$24 +la $24,8 +beq $19,$24,L.2082 +la $23,338 +beq $30,$0,L.2084 +la $4,L.687 +move $5,$23 +jal printf +L.2084: +L.2082: +la $19,12 +la $24,10 +sw $24,-8+160($sp) +lw $24,-8+160($sp) +and $19,$19,$24 +la $24,8 +beq $19,$24,L.2086 +la $23,339 +beq $30,$0,L.2088 +la $4,L.687 +move $5,$23 +jal printf +L.2088: +L.2086: +la $19,12 +la $24,10 +sw $24,-12+160($sp) +move $24,$19 +lw $15,-12+160($sp) +and $24,$24,$15 +move $19,$24 +la $24,8 +beq $19,$24,L.2090 +la $23,340 +beq $30,$0,L.2092 +la $4,L.687 +move $5,$23 +jal printf +L.2092: +L.2090: +la $18,12 +la $17,10 +sll $24,$17,8*(4-1); sra $24,$24,8*(4-1) +and $18,$18,$24 +la $24,8 +beq $18,$24,L.2094 +la $23,341 +beq $30,$0,L.2096 +la $4,L.687 +move $5,$23 +jal printf +L.2096: +L.2094: +la $18,12 +la $16,10 +sll $24,$16,8*(4-2); sra $24,$24,8*(4-2) +and $18,$18,$24 +la $24,8 +beq $18,$24,L.2098 +la $23,342 +beq $30,$0,L.2100 +la $4,L.687 +move $5,$23 +jal printf +L.2100: +L.2098: +la $18,12 +la $24,10 +sw $24,-4+160($sp) +lw $24,-4+160($sp) +and $18,$18,$24 +la $24,8 +beq $18,$24,L.2102 +la $23,343 +beq $30,$0,L.2104 +la $4,L.687 +move $5,$23 +jal printf +L.2104: +L.2102: +la $18,12 +la $24,10 +sw $24,-8+160($sp) +lw $24,-8+160($sp) +and $18,$18,$24 +la $24,8 +beq $18,$24,L.2106 +la $23,344 +beq $30,$0,L.2108 +la $4,L.687 +move $5,$23 +jal printf +L.2108: +L.2106: +la $18,12 +la $24,10 +sw $24,-12+160($sp) +lw $24,-12+160($sp) +and $18,$18,$24 +la $24,8 +beq $18,$24,L.2110 +la $23,345 +beq $30,$0,L.2112 +la $4,L.687 +move $5,$23 +jal printf +L.2112: +L.2110: +la $22,12 +la $17,10 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +sll $15,$17,8*(4-1); sra $15,$15,8*(4-1) +xor $24,$24,$15 +move $22,$24 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +la $15,6 +beq $24,$15,L.2114 +la $23,346 +beq $30,$0,L.2116 +la $4,L.687 +move $5,$23 +jal printf +L.2116: +L.2114: +la $22,12 +la $16,10 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +sll $15,$16,8*(4-2); sra $15,$15,8*(4-2) +xor $24,$24,$15 +move $22,$24 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +la $15,6 +beq $24,$15,L.2118 +la $23,347 +beq $30,$0,L.2120 +la $4,L.687 +move $5,$23 +jal printf +L.2120: +L.2118: +la $22,12 +la $24,10 +sw $24,-4+160($sp) +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +lw $15,-4+160($sp) +xor $24,$24,$15 +move $22,$24 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +la $15,6 +beq $24,$15,L.2122 +la $23,348 +beq $30,$0,L.2124 +la $4,L.687 +move $5,$23 +jal printf +L.2124: +L.2122: +la $22,12 +la $24,10 +sw $24,-8+160($sp) +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +lw $15,-8+160($sp) +xor $24,$24,$15 +move $22,$24 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +la $15,6 +beq $24,$15,L.2126 +la $23,349 +beq $30,$0,L.2128 +la $4,L.687 +move $5,$23 +jal printf +L.2128: +L.2126: +la $22,12 +la $24,10 +sw $24,-12+160($sp) +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +lw $15,-12+160($sp) +xor $24,$24,$15 +move $22,$24 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +la $15,6 +beq $24,$15,L.2130 +la $23,350 +beq $30,$0,L.2132 +la $4,L.687 +move $5,$23 +jal printf +L.2132: +L.2130: +la $21,12 +la $17,10 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +sll $15,$17,8*(4-1); sra $15,$15,8*(4-1) +xor $24,$24,$15 +move $21,$24 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +la $15,6 +beq $24,$15,L.2134 +la $23,351 +beq $30,$0,L.2136 +la $4,L.687 +move $5,$23 +jal printf +L.2136: +L.2134: +la $21,12 +la $16,10 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +sll $15,$16,8*(4-2); sra $15,$15,8*(4-2) +xor $24,$24,$15 +move $21,$24 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +la $15,6 +beq $24,$15,L.2138 +la $23,352 +beq $30,$0,L.2140 +la $4,L.687 +move $5,$23 +jal printf +L.2140: +L.2138: +la $21,12 +la $24,10 +sw $24,-4+160($sp) +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +lw $15,-4+160($sp) +xor $24,$24,$15 +move $21,$24 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +la $15,6 +beq $24,$15,L.2142 +la $23,353 +beq $30,$0,L.2144 +la $4,L.687 +move $5,$23 +jal printf +L.2144: +L.2142: +la $21,12 +la $24,10 +sw $24,-8+160($sp) +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +lw $15,-8+160($sp) +xor $24,$24,$15 +move $21,$24 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +la $15,6 +beq $24,$15,L.2146 +la $23,354 +beq $30,$0,L.2148 +la $4,L.687 +move $5,$23 +jal printf +L.2148: +L.2146: +la $21,12 +la $24,10 +sw $24,-12+160($sp) +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +lw $15,-12+160($sp) +xor $24,$24,$15 +move $21,$24 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +la $15,6 +beq $24,$15,L.2150 +la $23,355 +beq $30,$0,L.2152 +la $4,L.687 +move $5,$23 +jal printf +L.2152: +L.2150: +la $20,12 +la $17,10 +sll $24,$17,8*(4-1); sra $24,$24,8*(4-1) +xor $20,$20,$24 +la $24,6 +beq $20,$24,L.2154 +la $23,356 +beq $30,$0,L.2156 +la $4,L.687 +move $5,$23 +jal printf +L.2156: +L.2154: +la $20,12 +la $16,10 +sll $24,$16,8*(4-2); sra $24,$24,8*(4-2) +xor $20,$20,$24 +la $24,6 +beq $20,$24,L.2158 +la $23,357 +beq $30,$0,L.2160 +la $4,L.687 +move $5,$23 +jal printf +L.2160: +L.2158: +la $20,12 +la $24,10 +sw $24,-4+160($sp) +lw $24,-4+160($sp) +xor $20,$20,$24 +la $24,6 +beq $20,$24,L.2162 +la $23,358 +beq $30,$0,L.2164 +la $4,L.687 +move $5,$23 +jal printf +L.2164: +L.2162: +la $20,12 +la $24,10 +sw $24,-8+160($sp) +lw $24,-8+160($sp) +xor $20,$20,$24 +la $24,6 +beq $20,$24,L.2166 +la $23,359 +beq $30,$0,L.2168 +la $4,L.687 +move $5,$23 +jal printf +L.2168: +L.2166: +la $20,12 +la $24,10 +sw $24,-12+160($sp) +move $24,$20 +lw $15,-12+160($sp) +xor $24,$24,$15 +move $20,$24 +la $24,6 +beq $20,$24,L.2170 +la $23,360 +beq $30,$0,L.2172 +la $4,L.687 +move $5,$23 +jal printf +L.2172: +L.2170: +la $19,12 +la $17,10 +sll $24,$17,8*(4-1); sra $24,$24,8*(4-1) +xor $19,$19,$24 +la $24,6 +beq $19,$24,L.2174 +la $23,361 +beq $30,$0,L.2176 +la $4,L.687 +move $5,$23 +jal printf +L.2176: +L.2174: +la $19,12 +la $16,10 +sll $24,$16,8*(4-2); sra $24,$24,8*(4-2) +xor $19,$19,$24 +la $24,6 +beq $19,$24,L.2178 +la $23,362 +beq $30,$0,L.2180 +la $4,L.687 +move $5,$23 +jal printf +L.2180: +L.2178: +la $19,12 +la $24,10 +sw $24,-4+160($sp) +lw $24,-4+160($sp) +xor $19,$19,$24 +la $24,6 +beq $19,$24,L.2182 +la $23,363 +beq $30,$0,L.2184 +la $4,L.687 +move $5,$23 +jal printf +L.2184: +L.2182: +la $19,12 +la $24,10 +sw $24,-8+160($sp) +lw $24,-8+160($sp) +xor $19,$19,$24 +la $24,6 +beq $19,$24,L.2186 +la $23,364 +beq $30,$0,L.2188 +la $4,L.687 +move $5,$23 +jal printf +L.2188: +L.2186: +la $19,12 +la $24,10 +sw $24,-12+160($sp) +move $24,$19 +lw $15,-12+160($sp) +xor $24,$24,$15 +move $19,$24 +la $24,6 +beq $19,$24,L.2190 +la $23,365 +beq $30,$0,L.2192 +la $4,L.687 +move $5,$23 +jal printf +L.2192: +L.2190: +la $18,12 +la $17,10 +sll $24,$17,8*(4-1); sra $24,$24,8*(4-1) +xor $18,$18,$24 +la $24,6 +beq $18,$24,L.2194 +la $23,366 +beq $30,$0,L.2196 +la $4,L.687 +move $5,$23 +jal printf +L.2196: +L.2194: +la $18,12 +la $16,10 +sll $24,$16,8*(4-2); sra $24,$24,8*(4-2) +xor $18,$18,$24 +la $24,6 +beq $18,$24,L.2198 +la $23,367 +beq $30,$0,L.2200 +la $4,L.687 +move $5,$23 +jal printf +L.2200: +L.2198: +la $18,12 +la $24,10 +sw $24,-4+160($sp) +lw $24,-4+160($sp) +xor $18,$18,$24 +la $24,6 +beq $18,$24,L.2202 +la $23,368 +beq $30,$0,L.2204 +la $4,L.687 +move $5,$23 +jal printf +L.2204: +L.2202: +la $18,12 +la $24,10 +sw $24,-8+160($sp) +lw $24,-8+160($sp) +xor $18,$18,$24 +la $24,6 +beq $18,$24,L.2206 +la $23,369 +beq $30,$0,L.2208 +la $4,L.687 +move $5,$23 +jal printf +L.2208: +L.2206: +la $18,12 +la $24,10 +sw $24,-12+160($sp) +lw $24,-12+160($sp) +xor $18,$18,$24 +la $24,6 +beq $18,$24,L.2210 +la $23,370 +beq $30,$0,L.2212 +la $4,L.687 +move $5,$23 +jal printf +L.2212: +L.2210: +la $22,12 +la $17,10 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +sll $15,$17,8*(4-1); sra $15,$15,8*(4-1) +or $24,$24,$15 +move $22,$24 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +la $15,14 +beq $24,$15,L.2214 +la $23,371 +beq $30,$0,L.2216 +la $4,L.687 +move $5,$23 +jal printf +L.2216: +L.2214: +la $22,12 +la $16,10 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +sll $15,$16,8*(4-2); sra $15,$15,8*(4-2) +or $24,$24,$15 +move $22,$24 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +la $15,14 +beq $24,$15,L.2218 +la $23,372 +beq $30,$0,L.2220 +la $4,L.687 +move $5,$23 +jal printf +L.2220: +L.2218: +la $22,12 +la $24,10 +sw $24,-4+160($sp) +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +lw $15,-4+160($sp) +or $24,$24,$15 +move $22,$24 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +la $15,14 +beq $24,$15,L.2222 +la $23,373 +beq $30,$0,L.2224 +la $4,L.687 +move $5,$23 +jal printf +L.2224: +L.2222: +la $22,12 +la $24,10 +sw $24,-8+160($sp) +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +lw $15,-8+160($sp) +or $24,$24,$15 +move $22,$24 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +la $15,14 +beq $24,$15,L.2226 +la $23,374 +beq $30,$0,L.2228 +la $4,L.687 +move $5,$23 +jal printf +L.2228: +L.2226: +la $22,12 +la $24,10 +sw $24,-12+160($sp) +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +lw $15,-12+160($sp) +or $24,$24,$15 +move $22,$24 +sll $24,$22,8*(4-1); sra $24,$24,8*(4-1) +la $15,14 +beq $24,$15,L.2230 +la $23,375 +beq $30,$0,L.2232 +la $4,L.687 +move $5,$23 +jal printf +L.2232: +L.2230: +la $21,12 +la $17,10 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +sll $15,$17,8*(4-1); sra $15,$15,8*(4-1) +or $24,$24,$15 +move $21,$24 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +la $15,14 +beq $24,$15,L.2234 +la $23,376 +beq $30,$0,L.2236 +la $4,L.687 +move $5,$23 +jal printf +L.2236: +L.2234: +la $21,12 +la $16,10 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +sll $15,$16,8*(4-2); sra $15,$15,8*(4-2) +or $24,$24,$15 +move $21,$24 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +la $15,14 +beq $24,$15,L.2238 +la $23,377 +beq $30,$0,L.2240 +la $4,L.687 +move $5,$23 +jal printf +L.2240: +L.2238: +la $21,12 +la $24,10 +sw $24,-4+160($sp) +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +lw $15,-4+160($sp) +or $24,$24,$15 +move $21,$24 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +la $15,14 +beq $24,$15,L.2242 +la $23,378 +beq $30,$0,L.2244 +la $4,L.687 +move $5,$23 +jal printf +L.2244: +L.2242: +la $21,12 +la $24,10 +sw $24,-8+160($sp) +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +lw $15,-8+160($sp) +or $24,$24,$15 +move $21,$24 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +la $15,14 +beq $24,$15,L.2246 +la $23,379 +beq $30,$0,L.2248 +la $4,L.687 +move $5,$23 +jal printf +L.2248: +L.2246: +la $21,12 +la $24,10 +sw $24,-12+160($sp) +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +lw $15,-12+160($sp) +or $24,$24,$15 +move $21,$24 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +la $15,14 +beq $24,$15,L.2250 +la $23,380 +beq $30,$0,L.2252 +la $4,L.687 +move $5,$23 +jal printf +L.2252: +L.2250: +la $20,12 +la $17,10 +sll $24,$17,8*(4-1); sra $24,$24,8*(4-1) +or $20,$20,$24 +la $24,14 +beq $20,$24,L.2254 +la $23,381 +beq $30,$0,L.2256 +la $4,L.687 +move $5,$23 +jal printf +L.2256: +L.2254: +la $20,12 +la $16,10 +sll $24,$16,8*(4-2); sra $24,$24,8*(4-2) +or $20,$20,$24 +la $24,14 +beq $20,$24,L.2258 +la $23,382 +beq $30,$0,L.2260 +la $4,L.687 +move $5,$23 +jal printf +L.2260: +L.2258: +la $20,12 +la $24,10 +sw $24,-4+160($sp) +lw $24,-4+160($sp) +or $20,$20,$24 +la $24,14 +beq $20,$24,L.2262 +la $23,383 +beq $30,$0,L.2264 +la $4,L.687 +move $5,$23 +jal printf +L.2264: +L.2262: +la $20,12 +la $24,10 +sw $24,-8+160($sp) +lw $24,-8+160($sp) +or $20,$20,$24 +la $24,14 +beq $20,$24,L.2266 +la $23,384 +beq $30,$0,L.2268 +la $4,L.687 +move $5,$23 +jal printf +L.2268: +L.2266: +la $20,12 +la $24,10 +sw $24,-12+160($sp) +move $24,$20 +lw $15,-12+160($sp) +or $24,$24,$15 +move $20,$24 +la $24,14 +beq $20,$24,L.2270 +la $23,385 +beq $30,$0,L.2272 +la $4,L.687 +move $5,$23 +jal printf +L.2272: +L.2270: +la $19,12 +la $17,10 +sll $24,$17,8*(4-1); sra $24,$24,8*(4-1) +or $19,$19,$24 +la $24,14 +beq $19,$24,L.2274 +la $23,386 +beq $30,$0,L.2276 +la $4,L.687 +move $5,$23 +jal printf +L.2276: +L.2274: +la $19,12 +la $16,10 +sll $24,$16,8*(4-2); sra $24,$24,8*(4-2) +or $19,$19,$24 +la $24,14 +beq $19,$24,L.2278 +la $23,387 +beq $30,$0,L.2280 +la $4,L.687 +move $5,$23 +jal printf +L.2280: +L.2278: +la $19,12 +la $24,10 +sw $24,-4+160($sp) +lw $24,-4+160($sp) +or $19,$19,$24 +la $24,14 +beq $19,$24,L.2282 +la $23,388 +beq $30,$0,L.2284 +la $4,L.687 +move $5,$23 +jal printf +L.2284: +L.2282: +la $19,12 +la $24,10 +sw $24,-8+160($sp) +lw $24,-8+160($sp) +or $19,$19,$24 +la $24,14 +beq $19,$24,L.2286 +la $23,389 +beq $30,$0,L.2288 +la $4,L.687 +move $5,$23 +jal printf +L.2288: +L.2286: +la $19,12 +la $24,10 +sw $24,-12+160($sp) +move $24,$19 +lw $15,-12+160($sp) +or $24,$24,$15 +move $19,$24 +la $24,14 +beq $19,$24,L.2290 +la $23,390 +beq $30,$0,L.2292 +la $4,L.687 +move $5,$23 +jal printf +L.2292: +L.2290: +la $18,12 +la $17,10 +sll $24,$17,8*(4-1); sra $24,$24,8*(4-1) +or $18,$18,$24 +la $24,14 +beq $18,$24,L.2294 +la $23,391 +beq $30,$0,L.2296 +la $4,L.687 +move $5,$23 +jal printf +L.2296: +L.2294: +la $18,12 +la $16,10 +sll $24,$16,8*(4-2); sra $24,$24,8*(4-2) +or $18,$18,$24 +la $24,14 +beq $18,$24,L.2298 +la $23,392 +beq $30,$0,L.2300 +la $4,L.687 +move $5,$23 +jal printf +L.2300: +L.2298: +la $18,12 +la $24,10 +sw $24,-4+160($sp) +lw $24,-4+160($sp) +or $18,$18,$24 +la $24,14 +beq $18,$24,L.2302 +la $23,393 +beq $30,$0,L.2304 +la $4,L.687 +move $5,$23 +jal printf +L.2304: +L.2302: +la $18,12 +la $24,10 +sw $24,-8+160($sp) +lw $24,-8+160($sp) +or $18,$18,$24 +la $24,14 +beq $18,$24,L.2306 +la $23,394 +beq $30,$0,L.2308 +la $4,L.687 +move $5,$23 +jal printf +L.2308: +L.2306: +la $18,12 +la $24,10 +sw $24,-12+160($sp) +lw $24,-12+160($sp) +or $18,$18,$24 +la $24,14 +beq $18,$24,L.2310 +la $23,395 +beq $30,$0,L.2312 +la $4,L.687 +move $5,$23 +jal printf +L.2312: +L.2310: +beq $23,$0,L.2314 +la $24,1 +sw $24,-24+160($sp) +lw $24,0+160($sp) +lw $24,44($24) +beq $24,$0,L.2316 +la $4,L.688 +la $5,1 +jal printf +L.2316: +L.2314: +lw $2,-24+160($sp) +L.686: +l.d $f24,16($sp) +l.d $f26,24($sp) +l.d $f28,32($sp) +l.d $f30,40($sp) +lw $16,48($sp) +lw $17,52($sp) +lw $18,56($sp) +lw $19,60($sp) +lw $20,64($sp) +lw $21,68($sp) +lw $22,72($sp) +lw $23,76($sp) +lw $25,80($sp) +lw $30,84($sp) +lw $31,88($sp) +addu $sp,$sp,160 +j $31 +.end s714 +.data +.align 0 +L.2319: +.byte 115 +.byte 55 +.byte 49 +.byte 53 +.byte 44 +.byte 101 +.byte 114 +.byte 37 +.byte 100 +.byte 10 +.byte 0 +.sdata +.align 0 +L.2320: +.byte 115 +.byte 55 +.byte 49 +.byte 53 +.byte 32 +.byte 32 +.byte 32 +.byte 0 +.globl s715 +.text +.text +.align 2 +.ent s715 +s715: +.frame $sp,64,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-64 +.mask 0xc2e00000,-28 +sw $21,16($sp) +sw $22,20($sp) +sw $23,24($sp) +.cprestore 28 +sw $30,32($sp) +sw $31,36($sp) +sw $4,64($sp) +sw $0,-12+64($sp) +sw $0,-4+64($sp) +la $30,L.2320 +lw $15,0+64($sp) +la $23,60($15) +move $21,$0 +L.2321: +L.2322: +move $24,$23 +la $23,1($24) +move $15,$30 +la $30,1($15) +lb $15,($15) +sb $15,($24) +sll $24,$15,8*(4-1); sra $24,$24,8*(4-1) +bne $24,$0,L.2321 +la $24,1 +move $22,$24 +la $22,1($22) +la $22,1($22) +la $22,1($22) +la $22,1($22) +la $24,1($22) +move $22,$24 +la $15,6 +beq $24,$15,L.2324 +lw $24,0+64($sp) +lw $24,44($24) +beq $24,$0,L.2326 +la $4,L.2319 +la $5,1 +jal printf +L.2326: +la $21,1($21) +L.2324: +lw $4,-4+64($sp) +la $24,3 +sw $24,-8+64($sp) +lw $24,-8+64($sp) +la $5,2($24) +lw $6,-12+64($sp) +jal s715f +la $15,5 +beq $2,$15,L.2328 +lw $24,0+64($sp) +lw $24,44($24) +beq $24,$0,L.2330 +la $4,L.2319 +la $5,2 +jal printf +L.2330: +la $21,2($21) +L.2328: +move $2,$21 +L.2318: +lw $21,16($sp) +lw $22,20($sp) +lw $23,24($sp) +lw $25,28($sp) +lw $30,32($sp) +lw $31,36($sp) +addu $sp,$sp,64 +j $31 +.end s715 +.globl s715f +.text +.align 2 +.ent s715f +s715f: +.frame $sp,0,$31 +.set noreorder +.cpload $25 +.set reorder +move $2,$5 +L.2332: +j $31 +.end s715f +.data +.align 0 +L.2334: +.byte 115 +.byte 55 +.byte 50 +.byte 44 +.byte 101 +.byte 114 +.byte 37 +.byte 100 +.byte 10 +.byte 0 +.sdata +.align 0 +L.2335: +.byte 115 +.byte 55 +.byte 50 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 0 +.globl s72 +.text +.text +.align 2 +.ent s72 +s72: +.frame $sp,96,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-96 +.fmask 0xf0000000,-72 +.mask 0xc2ff0000,-24 +s.d $f28,16($sp) +s.d $f30,24($sp) +sw $16,32($sp) +sw $17,36($sp) +sw $18,40($sp) +sw $19,44($sp) +sw $20,48($sp) +sw $21,52($sp) +sw $22,56($sp) +sw $23,60($sp) +.cprestore 64 +sw $30,68($sp) +sw $31,72($sp) +move $30,$4 +la $22,L.2335 +la $21,60($30) +move $19,$0 +L.2336: +L.2337: +move $24,$21 +la $21,1($24) +move $15,$22 +la $22,1($15) +lb $15,($15) +sb $15,($24) +sll $24,$15,8*(4-1); sra $24,$24,8*(4-1) +bne $24,$0,L.2336 +la $24,2 +sw $24,-4+96($sp) +lw $15,-4+96($sp) +beq $15,$24,L.2339 +la $24,1 +la $19,1($19) +la $4,L.2334 +move $5,$24 +jal printf +L.2339: +lw $24,-4+96($sp) +negu $15,$24 +addu $24,$24,$15 +beq $24,$0,L.2341 +la $24,2 +la $19,2($19) +la $4,L.2334 +move $5,$24 +jal printf +L.2341: +sw $0,-4+96($sp) +move $23,$0 +b L.2346 +L.2343: +lw $24,-4+96($sp) +sll $24,$24,1 +or $24,$24,1 +sw $24,-4+96($sp) +L.2344: +la $23,1($23) +L.2346: +lw $24,4($30) +blt $23,$24,L.2343 +lw $24,-4+96($sp) +not $24,$24 +beq $24,$0,L.2347 +la $24,4 +la $19,4($19) +la $4,L.2334 +move $5,$24 +jal printf +L.2347: +la $24,5 +sw $24,-4+96($sp) +lw $24,-4+96($sp) +la $24,1($24) +sw $24,-4+96($sp) +la $15,6 +bne $24,$15,L.2354 +lw $24,-4+96($sp) +subu $24,$24,1 +sw $24,-4+96($sp) +la $14,5 +bne $24,$14,L.2354 +lw $24,-4+96($sp) +la $13,1($24) +sw $13,-4+96($sp) +bne $24,$14,L.2354 +lw $24,-4+96($sp) +subu $13,$24,1 +sw $13,-4+96($sp) +bne $24,$15,L.2354 +lw $24,-4+96($sp) +beq $24,$14,L.2349 +L.2354: +la $24,8 +la $19,8($19) +la $4,L.2334 +move $5,$24 +jal printf +L.2349: +la $17,26 +la $24,26 +sw $24,-8+96($sp) +l.d $f30,L.2355 +la $16,26 +la $24,26 +sw $24,-12+96($sp) +la $18,26 +l.s $f28,L.2356 +move $20,$0 +la $24,26 +sll $15,$16,8*(4-2); sra $15,$15,8*(4-2) +sll $15,$15,8*(4-1); sra $15,$15,8*(4-1) +bne $15,$24,L.2363 +move $15,$18 +sll $15,$15,8*(4-1); sra $15,$15,8*(4-1) +bne $15,$24,L.2363 +lw $15,-8+96($sp) +sll $15,$15,8*(4-1); sra $15,$15,8*(4-1) +bne $15,$24,L.2363 +lw $15,-12+96($sp) +sll $15,$15,8*(4-1); sra $15,$15,8*(4-1) +bne $15,$24,L.2363 +trunc.w.s $f2,$f28,$15; mfc1 $15,$f2 +sll $15,$15,8*(4-1); sra $15,$15,8*(4-1) +bne $15,$24,L.2363 +trunc.w.d $f2,$f30,$15; mfc1 $15,$f2 +sll $15,$15,8*(4-1); sra $15,$15,8*(4-1) +beq $15,$24,L.2357 +L.2363: +la $20,1($20) +L.2357: +la $24,26 +sll $15,$17,8*(4-1); sra $15,$15,8*(4-1) +sll $15,$15,8*(4-2); sra $15,$15,8*(4-2) +bne $15,$24,L.2370 +move $15,$18 +sll $15,$15,8*(4-2); sra $15,$15,8*(4-2) +bne $15,$24,L.2370 +lw $15,-8+96($sp) +sll $15,$15,8*(4-2); sra $15,$15,8*(4-2) +bne $15,$24,L.2370 +lw $15,-12+96($sp) +sll $15,$15,8*(4-2); sra $15,$15,8*(4-2) +bne $15,$24,L.2370 +trunc.w.s $f2,$f28,$15; mfc1 $15,$f2 +sll $15,$15,8*(4-2); sra $15,$15,8*(4-2) +bne $15,$24,L.2370 +trunc.w.d $f2,$f30,$15; mfc1 $15,$f2 +sll $15,$15,8*(4-2); sra $15,$15,8*(4-2) +beq $15,$24,L.2364 +L.2370: +la $20,2($20) +L.2364: +la $24,26 +sll $15,$17,8*(4-1); sra $15,$15,8*(4-1) +bne $15,$24,L.2377 +sll $15,$16,8*(4-2); sra $15,$15,8*(4-2) +bne $15,$24,L.2377 +lw $15,-8+96($sp) +bne $15,$24,L.2377 +lw $15,-12+96($sp) +bne $15,$24,L.2377 +trunc.w.s $f2,$f28,$15; mfc1 $15,$f2 +bne $15,$24,L.2377 +trunc.w.d $f2,$f30,$15; mfc1 $15,$f2 +beq $15,$24,L.2371 +L.2377: +la $20,4($20) +L.2371: +la $24,26 +sll $15,$17,8*(4-1); sra $15,$15,8*(4-1) +bne $15,$24,L.2384 +sll $15,$16,8*(4-2); sra $15,$15,8*(4-2) +bne $15,$24,L.2384 +bne $18,$24,L.2384 +lw $15,-12+96($sp) +bne $15,$24,L.2384 +trunc.w.s $f2,$f28,$15; mfc1 $15,$f2 +bne $15,$24,L.2384 +trunc.w.d $f2,$f30,$15; mfc1 $15,$f2 +beq $15,$24,L.2378 +L.2384: +la $20,8($20) +L.2378: +la $24,26 +sll $15,$17,8*(4-1); sra $15,$15,8*(4-1) +bne $15,$24,L.2393 +sll $15,$16,8*(4-2); sra $15,$15,8*(4-2) +bne $15,$24,L.2393 +move $15,$18 +bne $15,$24,L.2393 +lw $15,-8+96($sp) +bne $15,$24,L.2393 +l.s $f18,L.828 +c.ult.s $f28,$f18; bc1t L.2394 +sub.s $f18,$f28,$f18 +trunc.w.s $f2,$f18,$24; mfc1 $24,$f2 +la $24,0x80000000($24) +sw $24,-16+96($sp) +b L.2395 +L.2394: +trunc.w.s $f2,$f28,$24; mfc1 $24,$f2 +sw $24,-16+96($sp) +L.2395: +lw $24,-16+96($sp) +la $15,26 +bne $24,$15,L.2393 +l.d $f18,L.836 +c.ult.d $f30,$f18; bc1t L.2396 +sub.d $f18,$f30,$f18 +trunc.w.d $f2,$f18,$24; mfc1 $24,$f2 +la $24,0x80000000($24) +sw $24,-20+96($sp) +b L.2397 +L.2396: +trunc.w.d $f2,$f30,$24; mfc1 $24,$f2 +sw $24,-20+96($sp) +L.2397: +lw $24,-20+96($sp) +la $15,26 +beq $24,$15,L.2385 +L.2393: +la $20,16($20) +L.2385: +l.d $f18,L.2355 +sll $24,$17,8*(4-1); sra $24,$24,8*(4-1) +mtc1 $24,$f16; cvt.s.w $f16,$f16 +cvt.d.s $f16,$f16 +c.eq.d $f16,$f18; bc1f L.2404 +sll $24,$16,8*(4-2); sra $24,$24,8*(4-2) +mtc1 $24,$f16; cvt.s.w $f16,$f16 +cvt.d.s $f16,$f16 +c.eq.d $f16,$f18; bc1f L.2404 +mtc1 $18,$f16; cvt.s.w $f16,$f16 +cvt.d.s $f16,$f16 +c.eq.d $f16,$f18; bc1f L.2404 +lw $24,-8+96($sp) +mtc1 $24,$f16; cvt.s.w $f16,$f16 +cvt.d.s $f16,$f16 +c.eq.d $f16,$f18; bc1f L.2404 +lw $24,-12+96($sp) +l.d $f16,L.596 +srl $15,$24,1 +mtc1 $15,$f10; cvt.d.w $f10,$f10 +mul.d $f16,$f16,$f10 +and $24,$24,1 +mtc1 $24,$f10; cvt.d.w $f10,$f10 +add.d $f16,$f16,$f10 +cvt.s.d $f16,$f16 +cvt.d.s $f16,$f16 +c.eq.d $f16,$f18; bc1f L.2404 +cvt.s.d $f16,$f30 +cvt.d.s $f16,$f16 +c.eq.d $f16,$f18; bc1t L.2398 +L.2404: +la $20,32($20) +L.2398: +l.d $f18,L.2355 +sll $24,$17,8*(4-1); sra $24,$24,8*(4-1) +mtc1 $24,$f16; cvt.d.w $f16,$f16 +c.eq.d $f16,$f18; bc1f L.2411 +sll $24,$16,8*(4-2); sra $24,$24,8*(4-2) +mtc1 $24,$f16; cvt.d.w $f16,$f16 +c.eq.d $f16,$f18; bc1f L.2411 +mtc1 $18,$f16; cvt.d.w $f16,$f16 +c.eq.d $f16,$f18; bc1f L.2411 +lw $24,-8+96($sp) +mtc1 $24,$f16; cvt.d.w $f16,$f16 +c.eq.d $f16,$f18; bc1f L.2411 +lw $24,-12+96($sp) +l.d $f16,L.596 +srl $15,$24,1 +mtc1 $15,$f10; cvt.d.w $f10,$f10 +mul.d $f16,$f16,$f10 +and $24,$24,1 +mtc1 $24,$f10; cvt.d.w $f10,$f10 +add.d $f16,$f16,$f10 +c.eq.d $f16,$f18; bc1f L.2411 +cvt.d.s $f16,$f28 +c.eq.d $f16,$f18; bc1t L.2405 +L.2411: +la $20,64($20) +L.2405: +beq $20,$0,L.2412 +la $24,16 +la $19,16($19) +la $4,L.2334 +move $5,$24 +jal printf +L.2412: +move $2,$19 +L.2333: +l.d $f28,16($sp) +l.d $f30,24($sp) +lw $16,32($sp) +lw $17,36($sp) +lw $18,40($sp) +lw $19,44($sp) +lw $20,48($sp) +lw $21,52($sp) +lw $22,56($sp) +lw $23,60($sp) +lw $25,64($sp) +lw $30,68($sp) +lw $31,72($sp) +addu $sp,$sp,96 +j $31 +.end s72 +.data +.align 0 +L.2415: +.byte 115 +.byte 55 +.byte 53 +.byte 55 +.byte 44 +.byte 101 +.byte 114 +.byte 37 +.byte 100 +.byte 10 +.byte 0 +.sdata +.align 0 +L.2416: +.byte 115 +.byte 55 +.byte 53 +.byte 55 +.byte 32 +.byte 32 +.byte 32 +.byte 0 +.globl s757 +.text +.text +.align 2 +.ent s757 +s757: +.frame $sp,176,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-176 +.mask 0xc2ff0000,-120 +sw $16,16($sp) +sw $17,20($sp) +sw $18,24($sp) +sw $19,28($sp) +sw $20,32($sp) +sw $21,36($sp) +sw $22,40($sp) +sw $23,44($sp) +.cprestore 48 +sw $30,52($sp) +sw $31,56($sp) +move $30,$4 +la $24,L.2416 +sw $24,-80+176($sp) +la $24,60($30) +sw $24,-84+176($sp) +sw $0,-88+176($sp) +L.2417: +L.2418: +lw $24,-84+176($sp) +la $15,1($24) +sw $15,-84+176($sp) +lw $15,-80+176($sp) +la $14,1($15) +sw $14,-80+176($sp) +lb $15,($15) +sb $15,($24) +sll $24,$15,8*(4-1); sra $24,$24,8*(4-1) +bne $24,$0,L.2417 +la $24,40 +sw $24,-92+176($sp) +lw $24,-92+176($sp) +sll $15,$24,3 +sll $15,$15,2 +la $14,1280 +bne $15,$14,L.2422 +sra $24,$24,3 +sra $24,$24,2 +la $15,1 +beq $24,$15,L.2420 +L.2422: +lw $24,-88+176($sp) +la $24,1($24) +sw $24,-88+176($sp) +lw $24,44($30) +beq $24,$0,L.2423 +la $4,L.2415 +la $5,1 +jal printf +L.2423: +L.2420: +move $19,$0 +sw $0,-68+176($sp) +b L.2428 +L.2425: +la $17,1 +lw $24,16($30) +subu $24,$24,1 +sll $16,$17,$24 +sw $0,-72+176($sp) +lw $24,-72+176($sp) +not $24,$24 +lw $15,-68+176($sp) +srl $14,$24,$15 +sw $14,-76+176($sp) +sll $24,$24,$15 +sw $24,-72+176($sp) +move $18,$0 +b L.2432 +L.2429: +lw $24,-68+176($sp) +bge $18,$24,L.2440 +la $24,1 +sw $24,-100+176($sp) +b L.2441 +L.2440: +sw $0,-100+176($sp) +L.2441: +lw $24,-72+176($sp) +and $24,$17,$24 +bne $24,$0,L.2442 +la $24,1 +sw $24,-104+176($sp) +b L.2443 +L.2442: +sw $0,-104+176($sp) +L.2443: +lw $24,-100+176($sp) +lw $15,-104+176($sp) +bne $24,$15,L.2439 +lw $24,-68+176($sp) +bge $18,$24,L.2444 +la $24,1 +sw $24,-108+176($sp) +b L.2445 +L.2444: +sw $0,-108+176($sp) +L.2445: +lw $24,-76+176($sp) +and $24,$16,$24 +bne $24,$0,L.2446 +la $24,1 +sw $24,-112+176($sp) +b L.2447 +L.2446: +sw $0,-112+176($sp) +L.2447: +lw $24,-108+176($sp) +lw $15,-112+176($sp) +beq $24,$15,L.2433 +L.2439: +la $19,1 +L.2433: +sll $17,$17,1 +srl $16,$16,1 +L.2430: +la $18,1($18) +L.2432: +lw $24,16($30) +blt $18,$24,L.2429 +L.2426: +lw $24,-68+176($sp) +la $24,1($24) +sw $24,-68+176($sp) +L.2428: +lw $24,-68+176($sp) +lw $15,16($30) +blt $24,$15,L.2425 +beq $19,$0,L.2448 +lw $24,-88+176($sp) +la $24,2($24) +sw $24,-88+176($sp) +lw $24,44($30) +beq $24,$0,L.2450 +la $4,L.2415 +la $5,2 +jal printf +L.2450: +L.2448: +la $20,3 +la $21,2 +la $22,1 +bge $20,$21,L.2458 +la $24,1 +sw $24,-104+176($sp) +b L.2459 +L.2458: +sw $0,-104+176($sp) +L.2459: +lw $24,-104+176($sp) +bge $24,$22,L.2456 +la $24,1 +sw $24,-100+176($sp) +b L.2457 +L.2456: +sw $0,-100+176($sp) +L.2457: +lw $24,-100+176($sp) +la $15,1 +beq $24,$15,L.2452 +lw $24,-88+176($sp) +la $24,4($24) +sw $24,-88+176($sp) +lw $24,44($30) +beq $24,$0,L.2460 +la $4,L.2415 +la $5,4 +jal printf +L.2460: +L.2452: +la $24,-60+176($sp) +la $15,-64+176($sp) +bne $24,$15,L.2462 +lw $24,-88+176($sp) +la $24,8($24) +sw $24,-88+176($sp) +lw $24,44($30) +beq $24,$0,L.2465 +la $4,L.2415 +la $5,8 +jal printf +L.2465: +L.2462: +la $24,-60+176($sp) +la $15,-64+176($sp) +bgeu $24,$15,L.2467 +lw $24,40($30) +beq $24,$0,L.2470 +la $4,L.2472 +jal printf +L.2470: +L.2467: +move $19,$0 +move $18,$0 +L.2473: +sll $24,$18,2 +la $15,-64+176($sp) +addu $24,$24,$15 +la $15,1 +sw $15,($24) +L.2474: +la $18,1($18) +la $24,16 +blt $18,$24,L.2473 +sw $0,-60+176($sp) +sw $0,-48+176($sp) +sw $0,-40+176($sp) +sw $0,-36+176($sp) +sw $0,-28+176($sp) +sw $0,-12+176($sp) +move $20,$0 +L.2483: +move $21,$0 +L.2487: +move $22,$0 +L.2491: +move $23,$0 +L.2495: +bge $20,$21,L.2506 +la $24,1 +sw $24,-112+176($sp) +b L.2507 +L.2506: +sw $0,-112+176($sp) +L.2507: +bge $22,$23,L.2508 +la $24,1 +sw $24,-116+176($sp) +b L.2509 +L.2508: +sw $0,-116+176($sp) +L.2509: +lw $24,-112+176($sp) +lw $15,-116+176($sp) +bne $24,$15,L.2504 +la $24,1 +sw $24,-108+176($sp) +b L.2505 +L.2504: +sw $0,-108+176($sp) +L.2505: +lw $24,-108+176($sp) +sll $15,$20,3 +sll $14,$21,2 +addu $15,$15,$14 +sll $14,$22,1 +addu $15,$15,$14 +addu $15,$15,$23 +sll $15,$15,2 +la $14,-64+176($sp) +addu $15,$15,$14 +lw $15,($15) +beq $24,$15,L.2499 +la $19,1 +L.2499: +L.2496: +la $23,1($23) +la $24,2 +blt $23,$24,L.2495 +L.2492: +la $22,1($22) +la $24,2 +blt $22,$24,L.2491 +L.2488: +la $21,1($21) +la $24,2 +blt $21,$24,L.2487 +L.2484: +la $20,1($20) +la $24,2 +blt $20,$24,L.2483 +beq $19,$0,L.2510 +lw $24,-88+176($sp) +la $24,16($24) +sw $24,-88+176($sp) +lw $24,44($30) +beq $24,$0,L.2512 +la $4,L.2415 +la $5,16 +jal printf +L.2512: +L.2510: +sw $0,-96+176($sp) +lw $24,-96+176($sp) +beq $24,$0,L.2514 +lw $24,-88+176($sp) +la $24,32($24) +sw $24,-88+176($sp) +lw $24,44($30) +beq $24,$0,L.2516 +la $4,L.2415 +la $5,32 +jal printf +L.2516: +L.2514: +lw $2,-88+176($sp) +L.2414: +lw $16,16($sp) +lw $17,20($sp) +lw $18,24($sp) +lw $19,28($sp) +lw $20,32($sp) +lw $21,36($sp) +lw $22,40($sp) +lw $23,44($sp) +lw $25,48($sp) +lw $30,52($sp) +lw $31,56($sp) +addu $sp,$sp,176 +j $31 +.end s757 +.data +.align 0 +L.2519: +.byte 76 +.byte 111 +.byte 99 +.byte 97 +.byte 108 +.byte 32 +.byte 101 +.byte 114 +.byte 114 +.byte 111 +.byte 114 +.byte 32 +.byte 37 +.byte 100 +.byte 46 +.byte 10 +.byte 0 +.data +.align 0 +L.2520: +.byte 115 +.byte 55 +.byte 56 +.byte 49 +.byte 51 +.byte 44 +.byte 101 +.byte 114 +.byte 37 +.byte 100 +.byte 10 +.byte 0 +.sdata +.align 0 +L.2521: +.byte 115 +.byte 55 +.byte 56 +.byte 49 +.byte 51 +.byte 32 +.byte 32 +.byte 0 +.globl s7813 +.text +.text +.align 2 +.ent s7813 +s7813: +.frame $sp,112,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-112 +.mask 0xc2ff0000,-56 +sw $16,16($sp) +sw $17,20($sp) +sw $18,24($sp) +sw $19,28($sp) +sw $20,32($sp) +sw $21,36($sp) +sw $22,40($sp) +sw $23,44($sp) +.cprestore 48 +sw $30,52($sp) +sw $31,56($sp) +sw $4,112($sp) +la $19,L.2521 +lw $24,0+112($sp) +la $18,60($24) +move $23,$0 +move $17,$0 +lw $30,48($24) +L.2522: +L.2523: +move $24,$18 +la $18,1($24) +move $15,$19 +la $19,1($15) +lb $15,($15) +sb $15,($24) +sll $24,$15,8*(4-1); sra $24,$24,8*(4-1) +bne $24,$0,L.2522 +b L.2525 +la $23,1 +beq $30,$0,L.2527 +la $4,L.2519 +move $5,$23 +jal printf +L.2527: +L.2525: +b L.2529 +la $23,2 +beq $30,$0,L.2531 +la $4,L.2519 +move $5,$23 +jal printf +L.2531: +L.2529: +b L.2533 +la $23,3 +beq $30,$0,L.2535 +la $4,L.2519 +move $5,$23 +jal printf +L.2535: +L.2533: +b L.2537 +la $23,4 +beq $30,$0,L.2539 +la $4,L.2519 +move $5,$23 +jal printf +L.2539: +L.2537: +b L.2541 +la $23,5 +beq $30,$0,L.2543 +la $4,L.2519 +move $5,$23 +jal printf +L.2543: +L.2541: +b L.2545 +la $23,6 +beq $30,$0,L.2547 +la $4,L.2519 +move $5,$23 +jal printf +L.2547: +L.2545: +b L.2549 +la $23,7 +beq $30,$0,L.2551 +la $4,L.2519 +move $5,$23 +jal printf +L.2551: +L.2549: +b L.2553 +la $23,8 +beq $30,$0,L.2555 +la $4,L.2519 +move $5,$23 +jal printf +L.2555: +L.2553: +b L.2557 +la $23,9 +beq $30,$0,L.2559 +la $4,L.2519 +move $5,$23 +jal printf +L.2559: +L.2557: +b L.2561 +la $23,10 +beq $30,$0,L.2563 +la $4,L.2519 +move $5,$23 +jal printf +L.2563: +L.2561: +b L.2565 +la $23,11 +beq $30,$0,L.2567 +la $4,L.2519 +move $5,$23 +jal printf +L.2567: +L.2565: +b L.2569 +la $23,12 +beq $30,$0,L.2571 +la $4,L.2519 +move $5,$23 +jal printf +L.2571: +L.2569: +b L.2573 +la $23,13 +beq $30,$0,L.2575 +la $4,L.2519 +move $5,$23 +jal printf +L.2575: +L.2573: +b L.2577 +la $23,14 +beq $30,$0,L.2579 +la $4,L.2519 +move $5,$23 +jal printf +L.2579: +L.2577: +b L.2581 +la $23,15 +beq $30,$0,L.2583 +la $4,L.2519 +move $5,$23 +jal printf +L.2583: +L.2581: +b L.2585 +la $23,16 +beq $30,$0,L.2587 +la $4,L.2519 +move $5,$23 +jal printf +L.2587: +L.2585: +b L.2589 +la $23,17 +beq $30,$0,L.2591 +la $4,L.2519 +move $5,$23 +jal printf +L.2591: +L.2589: +b L.2593 +la $23,18 +beq $30,$0,L.2595 +la $4,L.2519 +move $5,$23 +jal printf +L.2595: +L.2593: +b L.2597 +la $23,16 +beq $30,$0,L.2599 +la $4,L.2519 +move $5,$23 +jal printf +L.2599: +L.2597: +b L.2601 +la $23,20 +beq $30,$0,L.2603 +la $4,L.2519 +move $5,$23 +jal printf +L.2603: +L.2601: +b L.2605 +la $23,21 +beq $30,$0,L.2607 +la $4,L.2519 +move $5,$23 +jal printf +L.2607: +L.2605: +b L.2609 +la $23,22 +beq $30,$0,L.2611 +la $4,L.2519 +move $5,$23 +jal printf +L.2611: +L.2609: +b L.2613 +la $23,23 +beq $30,$0,L.2615 +la $4,L.2519 +move $5,$23 +jal printf +L.2615: +L.2613: +b L.2617 +la $23,24 +beq $30,$0,L.2619 +la $4,L.2519 +move $5,$23 +jal printf +L.2619: +L.2617: +b L.2621 +la $23,25 +beq $30,$0,L.2623 +la $4,L.2519 +move $5,$23 +jal printf +L.2623: +L.2621: +b L.2625 +la $23,26 +beq $30,$0,L.2627 +la $4,L.2519 +move $5,$23 +jal printf +L.2627: +L.2625: +b L.2629 +la $23,27 +beq $30,$0,L.2631 +la $4,L.2519 +move $5,$23 +jal printf +L.2631: +L.2629: +b L.2633 +la $23,28 +beq $30,$0,L.2635 +la $4,L.2519 +move $5,$23 +jal printf +L.2635: +L.2633: +b L.2637 +la $23,26 +beq $30,$0,L.2639 +la $4,L.2519 +move $5,$23 +jal printf +L.2639: +L.2637: +b L.2641 +la $23,30 +beq $30,$0,L.2643 +la $4,L.2519 +move $5,$23 +jal printf +L.2643: +L.2641: +b L.2645 +la $23,31 +beq $30,$0,L.2647 +la $4,L.2519 +move $5,$23 +jal printf +L.2647: +L.2645: +b L.2649 +la $23,32 +beq $30,$0,L.2651 +la $4,L.2519 +move $5,$23 +jal printf +L.2651: +L.2649: +b L.2653 +la $23,33 +beq $30,$0,L.2655 +la $4,L.2519 +move $5,$23 +jal printf +L.2655: +L.2653: +b L.2657 +la $23,34 +beq $30,$0,L.2659 +la $4,L.2519 +move $5,$23 +jal printf +L.2659: +L.2657: +b L.2661 +la $23,35 +beq $30,$0,L.2663 +la $4,L.2519 +move $5,$23 +jal printf +L.2663: +L.2661: +b L.2665 +la $23,36 +beq $30,$0,L.2667 +la $4,L.2519 +move $5,$23 +jal printf +L.2667: +L.2665: +b L.2669 +la $23,37 +beq $30,$0,L.2671 +la $4,L.2519 +move $5,$23 +jal printf +L.2671: +L.2669: +b L.2673 +la $23,38 +beq $30,$0,L.2675 +la $4,L.2519 +move $5,$23 +jal printf +L.2675: +L.2673: +b L.2677 +la $23,39 +beq $30,$0,L.2679 +la $4,L.2519 +move $5,$23 +jal printf +L.2679: +L.2677: +b L.2681 +la $23,40 +beq $30,$0,L.2683 +la $4,L.2519 +move $5,$23 +jal printf +L.2683: +L.2681: +b L.2685 +la $23,41 +beq $30,$0,L.2687 +la $4,L.2519 +move $5,$23 +jal printf +L.2687: +L.2685: +b L.2689 +la $23,42 +beq $30,$0,L.2691 +la $4,L.2519 +move $5,$23 +jal printf +L.2691: +L.2689: +b L.2693 +la $23,43 +beq $30,$0,L.2695 +la $4,L.2519 +move $5,$23 +jal printf +L.2695: +L.2693: +b L.2697 +la $23,44 +beq $30,$0,L.2699 +la $4,L.2519 +move $5,$23 +jal printf +L.2699: +L.2697: +b L.2701 +la $23,45 +beq $30,$0,L.2703 +la $4,L.2519 +move $5,$23 +jal printf +L.2703: +L.2701: +b L.2705 +la $23,46 +beq $30,$0,L.2707 +la $4,L.2519 +move $5,$23 +jal printf +L.2707: +L.2705: +b L.2709 +la $23,47 +beq $30,$0,L.2711 +la $4,L.2519 +move $5,$23 +jal printf +L.2711: +L.2709: +b L.2713 +la $23,48 +beq $30,$0,L.2715 +la $4,L.2519 +move $5,$23 +jal printf +L.2715: +L.2713: +b L.2717 +la $23,49 +beq $30,$0,L.2719 +la $4,L.2519 +move $5,$23 +jal printf +L.2719: +L.2717: +b L.2721 +la $23,50 +beq $30,$0,L.2723 +la $4,L.2519 +move $5,$23 +jal printf +L.2723: +L.2721: +b L.2725 +la $23,51 +beq $30,$0,L.2727 +la $4,L.2519 +move $5,$23 +jal printf +L.2727: +L.2725: +b L.2729 +la $23,52 +beq $30,$0,L.2731 +la $4,L.2519 +move $5,$23 +jal printf +L.2731: +L.2729: +b L.2733 +la $23,53 +beq $30,$0,L.2735 +la $4,L.2519 +move $5,$23 +jal printf +L.2735: +L.2733: +b L.2737 +la $23,54 +beq $30,$0,L.2739 +la $4,L.2519 +move $5,$23 +jal printf +L.2739: +L.2737: +b L.2741 +la $23,55 +beq $30,$0,L.2743 +la $4,L.2519 +move $5,$23 +jal printf +L.2743: +L.2741: +b L.2745 +la $23,56 +beq $30,$0,L.2747 +la $4,L.2519 +move $5,$23 +jal printf +L.2747: +L.2745: +b L.2749 +la $23,57 +beq $30,$0,L.2751 +la $4,L.2519 +move $5,$23 +jal printf +L.2751: +L.2749: +b L.2753 +la $23,58 +beq $30,$0,L.2755 +la $4,L.2519 +move $5,$23 +jal printf +L.2755: +L.2753: +b L.2757 +la $23,56 +beq $30,$0,L.2759 +la $4,L.2519 +move $5,$23 +jal printf +L.2759: +L.2757: +b L.2761 +la $23,60 +beq $30,$0,L.2763 +la $4,L.2519 +move $5,$23 +jal printf +L.2763: +L.2761: +b L.2765 +la $23,61 +beq $30,$0,L.2767 +la $4,L.2519 +move $5,$23 +jal printf +L.2767: +L.2765: +b L.2769 +la $23,62 +beq $30,$0,L.2771 +la $4,L.2519 +move $5,$23 +jal printf +L.2771: +L.2769: +b L.2773 +la $23,63 +beq $30,$0,L.2775 +la $4,L.2519 +move $5,$23 +jal printf +L.2775: +L.2773: +b L.2777 +la $23,64 +beq $30,$0,L.2779 +la $4,L.2519 +move $5,$23 +jal printf +L.2779: +L.2777: +b L.2781 +la $23,65 +beq $30,$0,L.2783 +la $4,L.2519 +move $5,$23 +jal printf +L.2783: +L.2781: +b L.2785 +la $23,66 +beq $30,$0,L.2787 +la $4,L.2519 +move $5,$23 +jal printf +L.2787: +L.2785: +b L.2789 +la $23,67 +beq $30,$0,L.2791 +la $4,L.2519 +move $5,$23 +jal printf +L.2791: +L.2789: +b L.2793 +la $23,68 +beq $30,$0,L.2795 +la $4,L.2519 +move $5,$23 +jal printf +L.2795: +L.2793: +b L.2797 +la $23,69 +beq $30,$0,L.2799 +la $4,L.2519 +move $5,$23 +jal printf +L.2799: +L.2797: +b L.2801 +la $23,70 +beq $30,$0,L.2803 +la $4,L.2519 +move $5,$23 +jal printf +L.2803: +L.2801: +b L.2805 +la $23,71 +beq $30,$0,L.2807 +la $4,L.2519 +move $5,$23 +jal printf +L.2807: +L.2805: +b L.2809 +la $23,72 +beq $30,$0,L.2811 +la $4,L.2519 +move $5,$23 +jal printf +L.2811: +L.2809: +b L.2813 +la $23,73 +beq $30,$0,L.2815 +la $4,L.2519 +move $5,$23 +jal printf +L.2815: +L.2813: +b L.2817 +la $23,74 +beq $30,$0,L.2819 +la $4,L.2519 +move $5,$23 +jal printf +L.2819: +L.2817: +b L.2821 +la $23,75 +beq $30,$0,L.2823 +la $4,L.2519 +move $5,$23 +jal printf +L.2823: +L.2821: +beq $23,$0,L.2825 +lw $24,0+112($sp) +lw $24,44($24) +beq $24,$0,L.2827 +la $4,L.2520 +la $5,1 +jal printf +L.2827: +la $17,1($17) +L.2825: +move $23,$0 +move $21,$0 +move $22,$0 +move $24,$22 +la $22,1($24) +move $15,$0 +beq $24,$15,L.2830 +move $24,$21 +la $21,1($24) +beq $24,$15,L.2830 +la $24,1 +sw $24,-8+112($sp) +b L.2831 +L.2830: +sw $0,-8+112($sp) +L.2831: +lw $20,-8+112($sp) +la $24,1 +beq $22,$24,L.2832 +la $23,1 +beq $30,$0,L.2834 +la $4,L.2519 +move $5,$23 +jal printf +L.2834: +L.2832: +beq $21,$0,L.2836 +la $23,2 +beq $30,$0,L.2838 +la $4,L.2519 +move $5,$23 +jal printf +L.2838: +L.2836: +beq $20,$0,L.2840 +la $23,3 +beq $30,$0,L.2842 +la $4,L.2519 +move $5,$23 +jal printf +L.2842: +L.2840: +beq $22,$0,L.2845 +move $15,$21 +la $21,1($15) +beq $15,$0,L.2845 +la $24,1 +sw $24,-12+112($sp) +b L.2846 +L.2845: +sw $0,-12+112($sp) +L.2846: +lw $20,-12+112($sp) +la $24,1 +beq $22,$24,L.2847 +la $23,4 +beq $30,$0,L.2849 +la $4,L.2519 +move $5,$23 +jal printf +L.2849: +L.2847: +la $24,1 +beq $21,$24,L.2851 +la $23,5 +beq $30,$0,L.2853 +la $4,L.2519 +move $5,$23 +jal printf +L.2853: +L.2851: +beq $20,$0,L.2855 +la $23,6 +beq $30,$0,L.2857 +la $4,L.2519 +move $5,$23 +jal printf +L.2857: +L.2855: +move $24,$22 +subu $22,$24,1 +move $15,$0 +beq $24,$15,L.2860 +beq $21,$15,L.2860 +la $24,1 +sw $24,-16+112($sp) +b L.2861 +L.2860: +sw $0,-16+112($sp) +L.2861: +lw $20,-16+112($sp) +beq $22,$0,L.2862 +la $23,7 +beq $30,$0,L.2864 +la $4,L.2519 +move $5,$23 +jal printf +L.2864: +L.2862: +la $24,1 +beq $21,$24,L.2866 +la $23,8 +beq $30,$0,L.2868 +la $4,L.2519 +move $5,$23 +jal printf +L.2868: +L.2866: +la $24,1 +beq $20,$24,L.2870 +la $23,9 +beq $30,$0,L.2872 +la $4,L.2519 +move $5,$23 +jal printf +L.2872: +L.2870: +beq $22,$0,L.2875 +move $15,$21 +subu $21,$15,1 +beq $15,$0,L.2875 +la $24,1 +sw $24,-20+112($sp) +b L.2876 +L.2875: +sw $0,-20+112($sp) +L.2876: +lw $20,-20+112($sp) +beq $22,$0,L.2877 +la $23,10 +beq $30,$0,L.2879 +la $4,L.2519 +move $5,$23 +jal printf +L.2879: +L.2877: +la $24,1 +beq $21,$24,L.2881 +la $23,11 +beq $30,$0,L.2883 +la $4,L.2519 +move $5,$23 +jal printf +L.2883: +L.2881: +beq $20,$0,L.2885 +la $23,12 +beq $30,$0,L.2887 +la $4,L.2519 +move $5,$23 +jal printf +L.2887: +L.2885: +beq $23,$0,L.2889 +lw $24,0+112($sp) +lw $24,44($24) +beq $24,$0,L.2891 +la $4,L.2520 +la $5,2 +jal printf +L.2891: +la $17,2($17) +L.2889: +move $23,$0 +move $21,$0 +move $22,$0 +move $24,$22 +la $22,1($24) +move $15,$0 +bne $24,$15,L.2896 +beq $21,$15,L.2894 +L.2896: +la $24,1 +sw $24,-24+112($sp) +b L.2895 +L.2894: +sw $0,-24+112($sp) +L.2895: +lw $20,-24+112($sp) +la $24,1 +beq $22,$24,L.2897 +la $23,1 +beq $30,$0,L.2899 +la $4,L.2519 +move $5,$23 +jal printf +L.2899: +L.2897: +beq $21,$0,L.2901 +la $23,2 +beq $30,$0,L.2903 +la $4,L.2519 +move $5,$23 +jal printf +L.2903: +L.2901: +beq $20,$0,L.2905 +la $23,3 +beq $30,$0,L.2907 +la $4,L.2519 +move $5,$23 +jal printf +L.2907: +L.2905: +move $24,$21 +la $21,1($24) +move $15,$0 +bne $24,$15,L.2912 +beq $22,$15,L.2910 +L.2912: +la $24,1 +sw $24,-28+112($sp) +b L.2911 +L.2910: +sw $0,-28+112($sp) +L.2911: +lw $20,-28+112($sp) +la $24,1 +beq $22,$24,L.2913 +la $23,4 +beq $30,$0,L.2915 +la $4,L.2519 +move $5,$23 +jal printf +L.2915: +L.2913: +la $24,1 +beq $21,$24,L.2917 +la $23,5 +beq $30,$0,L.2919 +la $4,L.2519 +move $5,$23 +jal printf +L.2919: +L.2917: +la $24,1 +beq $20,$24,L.2921 +la $23,6 +beq $30,$0,L.2923 +la $4,L.2519 +move $5,$23 +jal printf +L.2923: +L.2921: +move $24,$22 +subu $22,$24,1 +move $15,$0 +bne $24,$15,L.2928 +move $24,$21 +subu $21,$24,1 +beq $24,$15,L.2926 +L.2928: +la $24,1 +sw $24,-32+112($sp) +b L.2927 +L.2926: +sw $0,-32+112($sp) +L.2927: +lw $20,-32+112($sp) +beq $22,$0,L.2929 +la $23,7 +beq $30,$0,L.2931 +la $4,L.2519 +move $5,$23 +jal printf +L.2931: +L.2929: +la $24,1 +beq $21,$24,L.2933 +la $23,8 +beq $30,$0,L.2935 +la $4,L.2519 +move $5,$23 +jal printf +L.2935: +L.2933: +la $24,1 +beq $20,$24,L.2937 +la $23,9 +beq $30,$0,L.2939 +la $4,L.2519 +move $5,$23 +jal printf +L.2939: +L.2937: +move $24,$0 +bne $22,$24,L.2944 +move $15,$21 +subu $21,$15,1 +beq $15,$24,L.2942 +L.2944: +la $24,1 +sw $24,-36+112($sp) +b L.2943 +L.2942: +sw $0,-36+112($sp) +L.2943: +lw $20,-36+112($sp) +beq $22,$0,L.2945 +la $23,10 +beq $30,$0,L.2947 +la $4,L.2519 +move $5,$23 +jal printf +L.2947: +L.2945: +beq $21,$0,L.2949 +la $23,11 +beq $30,$0,L.2951 +la $4,L.2519 +move $5,$23 +jal printf +L.2951: +L.2949: +la $24,1 +beq $20,$24,L.2953 +la $23,12 +beq $30,$0,L.2955 +la $4,L.2519 +move $5,$23 +jal printf +L.2955: +L.2953: +beq $23,$0,L.2957 +lw $24,0+112($sp) +lw $24,44($24) +beq $24,$0,L.2959 +la $4,L.2520 +la $5,4 +jal printf +L.2959: +la $17,4($17) +L.2957: +move $24,$0 +move $21,$24 +move $22,$24 +move $16,$24 +la $15,1 +sw $15,-4+112($sp) +lw $15,-4+112($sp) +beq $15,$24,L.2963 +sw $16,-40+112($sp) +b L.2964 +L.2963: +lw $24,-4+112($sp) +beq $24,$0,L.2965 +move $24,$22 +la $22,1($24) +sw $24,-44+112($sp) +b L.2966 +L.2965: +move $24,$21 +la $21,1($24) +sw $24,-44+112($sp) +L.2966: +lw $24,-44+112($sp) +sw $24,-40+112($sp) +L.2964: +lw $20,-40+112($sp) +bne $20,$0,L.2970 +bne $22,$0,L.2970 +beq $21,$0,L.2967 +L.2970: +lw $24,0+112($sp) +lw $24,44($24) +beq $24,$0,L.2971 +la $4,L.2520 +la $5,8 +jal printf +L.2971: +la $17,8($17) +L.2967: +lw $24,-4+112($sp) +beq $24,$0,L.2978 +sw $16,-48+112($sp) +b L.2979 +L.2978: +la $24,1 +sw $24,-48+112($sp) +L.2979: +lw $15,-48+112($sp) +bne $15,$0,L.2977 +beq $16,$0,L.2980 +la $24,1 +sw $24,-52+112($sp) +b L.2981 +L.2980: +sw $16,-52+112($sp) +L.2981: +lw $24,-52+112($sp) +beq $24,$0,L.2973 +L.2977: +lw $24,0+112($sp) +lw $24,44($24) +beq $24,$0,L.2982 +la $4,L.2520 +la $5,16 +jal printf +L.2982: +la $17,16($17) +L.2973: +move $2,$17 +L.2518: +lw $16,16($sp) +lw $17,20($sp) +lw $18,24($sp) +lw $19,28($sp) +lw $20,32($sp) +lw $21,36($sp) +lw $22,40($sp) +lw $23,44($sp) +lw $25,48($sp) +lw $30,52($sp) +lw $31,56($sp) +addu $sp,$sp,112 +j $31 +.end s7813 +.data +.align 0 +L.2985: +.byte 115 +.byte 56 +.byte 49 +.byte 44 +.byte 101 +.byte 114 +.byte 37 +.byte 100 +.byte 10 +.byte 0 +.sdata +.align 0 +L.2986: +.byte 115 +.byte 56 +.byte 49 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 0 +.data +.align 0 +L.2987: +.byte 82 +.byte 101 +.byte 103 +.byte 105 +.byte 115 +.byte 116 +.byte 101 +.byte 114 +.byte 32 +.byte 99 +.byte 111 +.byte 117 +.byte 110 +.byte 116 +.byte 32 +.byte 102 +.byte 111 +.byte 114 +.byte 32 +.byte 37 +.byte 115 +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 117 +.byte 110 +.byte 114 +.byte 101 +.byte 108 +.byte 105 +.byte 97 +.byte 98 +.byte 108 +.byte 101 +.byte 46 +.byte 10 +.byte 0 +.data +.align 0 +L.2988: +.byte 37 +.byte 100 +.byte 32 +.byte 114 +.byte 101 +.byte 103 +.byte 105 +.byte 115 +.byte 116 +.byte 101 +.byte 114 +.byte 115 +.byte 32 +.byte 97 +.byte 115 +.byte 115 +.byte 105 +.byte 103 +.byte 110 +.byte 101 +.byte 100 +.byte 32 +.byte 116 +.byte 111 +.byte 32 +.byte 37 +.byte 115 +.byte 32 +.byte 118 +.byte 97 +.byte 114 +.byte 105 +.byte 97 +.byte 98 +.byte 108 +.byte 101 +.byte 115 +.byte 46 +.byte 10 +.byte 0 +.globl s81 +.text +.text +.align 2 +.ent s81 +s81: +.frame $sp,80,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-80 +.mask 0xc2ff0000,-24 +sw $16,16($sp) +sw $17,20($sp) +sw $18,24($sp) +sw $19,28($sp) +sw $20,32($sp) +sw $21,36($sp) +sw $22,40($sp) +sw $23,44($sp) +.cprestore 48 +sw $30,52($sp) +sw $31,56($sp) +sw $4,80($sp) +sw $0,-20+80($sp) +sw $0,-8+80($sp) +sw $0,-12+80($sp) +sw $0,-16+80($sp) +la $17,L.2986 +lw $24,0+80($sp) +la $16,60($24) +L.2989: +L.2990: +move $24,$16 +la $16,1($24) +move $15,$17 +la $17,1($15) +lb $15,($15) +sb $15,($24) +sll $24,$15,8*(4-1); sra $24,$24,8*(4-1) +bne $24,$0,L.2989 +la $24,1 +sw $24,-4+80($sp) +move $21,$0 +L.2992: +lw $24,-4+80($sp) +move $15,$24 +move $30,$15 +move $20,$15 +la $23,-4+80($sp) +la $19,-4+80($sp) +move $22,$24 +move $18,$24 +sll $24,$30,8*(4-1); sra $24,$24,8*(4-1) +sll $15,$20,8*(4-1); sra $15,$15,8*(4-1) +beq $24,$15,L.2996 +la $24,1 +sw $24,-8+80($sp) +L.2996: +move $24,$23 +move $15,$19 +beq $24,$15,L.2998 +la $24,1 +sw $24,-12+80($sp) +L.2998: +beq $22,$18,L.3000 +la $24,1 +sw $24,-16+80($sp) +L.3000: +lw $24,-4+80($sp) +sll $24,$24,1 +sw $24,-4+80($sp) +L.2993: +la $21,1($21) +la $24,50 +blt $21,$24,L.2992 +lw $24,-8+80($sp) +beq $24,$0,L.3002 +lw $24,-20+80($sp) +la $24,1($24) +sw $24,-20+80($sp) +lw $24,0+80($sp) +lw $24,44($24) +beq $24,$0,L.3004 +la $4,L.2985 +la $5,1 +jal printf +L.3004: +L.3002: +lw $24,-12+80($sp) +beq $24,$0,L.3006 +lw $24,-20+80($sp) +la $24,2($24) +sw $24,-20+80($sp) +lw $24,0+80($sp) +lw $24,44($24) +beq $24,$0,L.3008 +la $4,L.2985 +la $5,2 +jal printf +L.3008: +L.3006: +lw $24,-16+80($sp) +beq $24,$0,L.3010 +lw $24,-20+80($sp) +la $24,4($24) +sw $24,-20+80($sp) +lw $24,0+80($sp) +lw $24,44($24) +beq $24,$0,L.3012 +la $4,L.2985 +la $5,4 +jal printf +L.3012: +L.3010: +jal regc +sw $2,-4+80($sp) +lw $24,0+80($sp) +lw $24,40($24) +beq $24,$0,L.3014 +lw $24,-4+80($sp) +bge $24,$0,L.3016 +la $4,L.2987 +la $5,L.425 +jal printf +b L.3017 +L.3016: +la $4,L.2988 +lw $5,-4+80($sp) +la $6,L.425 +jal printf +L.3017: +L.3014: +jal regp +sw $2,-4+80($sp) +lw $24,0+80($sp) +lw $24,40($24) +beq $24,$0,L.3018 +lw $24,-4+80($sp) +bge $24,$0,L.3020 +la $4,L.2987 +la $5,L.3022 +jal printf +b L.3021 +L.3020: +la $4,L.2988 +lw $5,-4+80($sp) +la $6,L.3022 +jal printf +L.3021: +L.3018: +jal regi +sw $2,-4+80($sp) +lw $24,0+80($sp) +lw $24,40($24) +beq $24,$0,L.3023 +lw $24,-4+80($sp) +bge $24,$0,L.3025 +la $4,L.2987 +la $5,L.426 +jal printf +b L.3026 +L.3025: +la $4,L.2988 +lw $5,-4+80($sp) +la $6,L.426 +jal printf +L.3026: +L.3023: +lw $2,-20+80($sp) +L.2984: +lw $16,16($sp) +lw $17,20($sp) +lw $18,24($sp) +lw $19,28($sp) +lw $20,32($sp) +lw $21,36($sp) +lw $22,40($sp) +lw $23,44($sp) +lw $25,48($sp) +lw $30,52($sp) +lw $31,56($sp) +addu $sp,$sp,80 +j $31 +.end s81 +.globl regc +.text +.align 2 +.ent regc +regc: +.frame $sp,176,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-176 +.mask 0x40ff0000,-144 +sw $16,0($sp) +sw $17,4($sp) +sw $18,8($sp) +sw $19,12($sp) +sw $20,16($sp) +sw $21,20($sp) +sw $22,24($sp) +sw $23,28($sp) +sw $30,32($sp) +sb $0,-130+176($sp) +la $24,1 +sb $24,-109+176($sp) +la $24,2 +sb $24,-110+176($sp) +la $24,3 +sb $24,-111+176($sp) +la $30,4 +la $24,5 +sb $24,-112+176($sp) +la $23,6 +la $24,7 +sb $24,-113+176($sp) +la $22,8 +la $24,9 +sb $24,-114+176($sp) +la $21,10 +la $24,11 +sb $24,-115+176($sp) +la $20,12 +la $24,13 +sb $24,-116+176($sp) +la $19,14 +la $24,15 +sb $24,-117+176($sp) +la $18,16 +la $24,17 +sb $24,-118+176($sp) +la $17,18 +la $24,19 +sb $24,-119+176($sp) +la $16,20 +la $24,21 +sb $24,-120+176($sp) +la $24,22 +sb $24,-1+176($sp) +la $24,23 +sb $24,-121+176($sp) +la $24,24 +sb $24,-2+176($sp) +la $24,25 +sb $24,-122+176($sp) +la $24,26 +sb $24,-3+176($sp) +la $24,27 +sb $24,-123+176($sp) +la $24,28 +sb $24,-4+176($sp) +la $24,29 +sb $24,-124+176($sp) +la $24,30 +sb $24,-5+176($sp) +la $24,31 +sb $24,-125+176($sp) +la $24,32 +sb $24,-6+176($sp) +la $24,33 +sb $24,-126+176($sp) +la $24,34 +sb $24,-7+176($sp) +la $24,35 +sb $24,-127+176($sp) +la $24,36 +sb $24,-128+176($sp) +la $24,37 +sb $24,-129+176($sp) +la $24,38 +sb $24,-131+176($sp) +la $24,-109+176($sp) +la $15,-130+176($sp) +subu $15,$24,$15 +sw $15,-96+176($sp) +la $15,-110+176($sp) +subu $24,$15,$24 +sw $24,-92+176($sp) +la $24,-111+176($sp) +la $15,-110+176($sp) +subu $24,$24,$15 +sw $24,-88+176($sp) +la $24,-112+176($sp) +la $15,-111+176($sp) +subu $24,$24,$15 +sw $24,-84+176($sp) +la $24,-113+176($sp) +la $15,-112+176($sp) +subu $24,$24,$15 +sw $24,-80+176($sp) +la $24,-114+176($sp) +la $15,-113+176($sp) +subu $24,$24,$15 +sw $24,-76+176($sp) +la $24,-115+176($sp) +la $15,-114+176($sp) +subu $24,$24,$15 +sw $24,-72+176($sp) +la $24,-116+176($sp) +la $15,-115+176($sp) +subu $24,$24,$15 +sw $24,-68+176($sp) +la $24,-117+176($sp) +la $15,-116+176($sp) +subu $24,$24,$15 +sw $24,-64+176($sp) +la $24,-118+176($sp) +la $15,-117+176($sp) +subu $24,$24,$15 +sw $24,-60+176($sp) +la $24,-119+176($sp) +la $15,-118+176($sp) +subu $24,$24,$15 +sw $24,-56+176($sp) +la $24,-120+176($sp) +la $15,-119+176($sp) +subu $24,$24,$15 +sw $24,-52+176($sp) +la $24,-121+176($sp) +la $15,-120+176($sp) +subu $24,$24,$15 +sw $24,-48+176($sp) +la $24,-122+176($sp) +la $15,-121+176($sp) +subu $24,$24,$15 +sw $24,-44+176($sp) +la $24,-123+176($sp) +la $15,-122+176($sp) +subu $24,$24,$15 +sw $24,-40+176($sp) +la $24,-124+176($sp) +la $15,-123+176($sp) +subu $24,$24,$15 +sw $24,-36+176($sp) +la $24,-125+176($sp) +la $15,-124+176($sp) +subu $24,$24,$15 +sw $24,-32+176($sp) +la $24,-126+176($sp) +la $15,-125+176($sp) +subu $24,$24,$15 +sw $24,-28+176($sp) +la $24,-127+176($sp) +la $15,-126+176($sp) +subu $24,$24,$15 +sw $24,-24+176($sp) +la $24,-128+176($sp) +la $15,-127+176($sp) +subu $24,$24,$15 +sw $24,-20+176($sp) +la $24,-129+176($sp) +la $15,-128+176($sp) +subu $24,$24,$15 +sw $24,-16+176($sp) +la $24,-131+176($sp) +la $15,-129+176($sp) +subu $24,$24,$15 +sw $24,-12+176($sp) +lw $24,-96+176($sp) +sw $24,-108+176($sp) +la $24,1 +sw $24,-104+176($sp) +sw $0,-100+176($sp) +L.3049: +lw $24,-104+176($sp) +la $15,1 +beq $24,$15,L.3055 +la $15,2 +beq $24,$15,L.3058 +la $15,3 +beq $24,$15,L.3063 +b L.3053 +L.3055: +lw $24,-100+176($sp) +sll $24,$24,2 +la $15,-96+176($sp) +addu $24,$24,$15 +lw $24,($24) +lw $15,-108+176($sp) +beq $24,$15,L.3054 +la $24,2 +lw $15,-100+176($sp) +sll $15,$15,2 +la $14,-96+176($sp) +addu $15,$15,$14 +lw $15,($15) +sw $15,-140+176($sp) +sw $24,-104+176($sp) +la $24,1 +sw $24,-136+176($sp) +b L.3054 +L.3058: +lw $24,-100+176($sp) +sll $24,$24,2 +la $15,-96+176($sp) +addu $24,$24,$15 +lw $24,($24) +lw $15,-108+176($sp) +bne $24,$15,L.3059 +la $24,3 +sw $24,-104+176($sp) +b L.3054 +L.3059: +lw $24,-100+176($sp) +sll $24,$24,2 +la $15,-96+176($sp) +addu $24,$24,$15 +lw $24,($24) +lw $15,-140+176($sp) +bne $24,$15,L.3061 +lw $24,-136+176($sp) +la $24,1($24) +sw $24,-136+176($sp) +b L.3054 +L.3061: +la $24,4 +sw $24,-104+176($sp) +b L.3054 +L.3063: +lw $24,-100+176($sp) +sll $24,$24,2 +la $15,-96+176($sp) +addu $24,$24,$15 +lw $24,($24) +lw $15,-108+176($sp) +beq $24,$15,L.3054 +la $24,4 +sw $24,-104+176($sp) +L.3053: +L.3054: +L.3050: +lw $24,-100+176($sp) +la $24,1($24) +sw $24,-100+176($sp) +lw $24,-100+176($sp) +la $15,22 +blt $24,$15,L.3049 +lw $24,-104+176($sp) +la $15,3 +bne $24,$15,L.3066 +la $24,16 +lw $15,-136+176($sp) +subu $2,$24,$15 +b L.3027 +L.3066: +la $2,-1 +L.3027: +lw $16,0($sp) +lw $17,4($sp) +lw $18,8($sp) +lw $19,12($sp) +lw $20,16($sp) +lw $21,20($sp) +lw $22,24($sp) +lw $23,28($sp) +lw $30,32($sp) +addu $sp,$sp,176 +j $31 +.end regc +.globl regi +.text +.align 2 +.ent regi +regi: +.frame $sp,272,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-272 +.mask 0x40ff0000,-240 +sw $16,0($sp) +sw $17,4($sp) +sw $18,8($sp) +sw $19,12($sp) +sw $20,16($sp) +sw $21,20($sp) +sw $22,24($sp) +sw $23,28($sp) +sw $30,32($sp) +sw $0,-216+272($sp) +la $24,1 +sw $24,-132+272($sp) +la $24,2 +sw $24,-136+272($sp) +la $24,3 +sw $24,-140+272($sp) +la $30,4 +la $24,5 +sw $24,-144+272($sp) +la $23,6 +la $24,7 +sw $24,-148+272($sp) +la $22,8 +la $24,9 +sw $24,-152+272($sp) +la $21,10 +la $24,11 +sw $24,-156+272($sp) +la $20,12 +la $24,13 +sw $24,-160+272($sp) +la $19,14 +la $24,15 +sw $24,-164+272($sp) +la $18,16 +la $24,17 +sw $24,-168+272($sp) +la $17,18 +la $24,19 +sw $24,-172+272($sp) +la $16,20 +la $24,21 +sw $24,-176+272($sp) +la $24,22 +sw $24,-4+272($sp) +la $24,23 +sw $24,-180+272($sp) +la $24,24 +sw $24,-8+272($sp) +la $24,25 +sw $24,-184+272($sp) +la $24,26 +sw $24,-12+272($sp) +la $24,27 +sw $24,-188+272($sp) +la $24,28 +sw $24,-16+272($sp) +la $24,29 +sw $24,-192+272($sp) +la $24,30 +sw $24,-20+272($sp) +la $24,31 +sw $24,-196+272($sp) +la $24,32 +sw $24,-24+272($sp) +la $24,33 +sw $24,-200+272($sp) +la $24,34 +sw $24,-28+272($sp) +la $24,35 +sw $24,-204+272($sp) +la $24,36 +sw $24,-208+272($sp) +la $24,37 +sw $24,-212+272($sp) +la $24,38 +sw $24,-220+272($sp) +la $24,-132+272($sp) +la $15,4 +la $14,-216+272($sp) +subu $14,$24,$14 +div $14,$14,$15 +sw $14,-116+272($sp) +la $14,-136+272($sp) +subu $24,$14,$24 +div $24,$24,$15 +sw $24,-112+272($sp) +la $24,-140+272($sp) +la $15,-136+272($sp) +subu $24,$24,$15 +la $15,4 +div $24,$24,$15 +sw $24,-108+272($sp) +la $24,-144+272($sp) +la $15,-140+272($sp) +subu $24,$24,$15 +la $15,4 +div $24,$24,$15 +sw $24,-104+272($sp) +la $24,-148+272($sp) +la $15,-144+272($sp) +subu $24,$24,$15 +la $15,4 +div $24,$24,$15 +sw $24,-100+272($sp) +la $24,-152+272($sp) +la $15,-148+272($sp) +subu $24,$24,$15 +la $15,4 +div $24,$24,$15 +sw $24,-96+272($sp) +la $24,-156+272($sp) +la $15,-152+272($sp) +subu $24,$24,$15 +la $15,4 +div $24,$24,$15 +sw $24,-92+272($sp) +la $24,-160+272($sp) +la $15,-156+272($sp) +subu $24,$24,$15 +la $15,4 +div $24,$24,$15 +sw $24,-88+272($sp) +la $24,-164+272($sp) +la $15,-160+272($sp) +subu $24,$24,$15 +la $15,4 +div $24,$24,$15 +sw $24,-84+272($sp) +la $24,-168+272($sp) +la $15,-164+272($sp) +subu $24,$24,$15 +la $15,4 +div $24,$24,$15 +sw $24,-80+272($sp) +la $24,-172+272($sp) +la $15,-168+272($sp) +subu $24,$24,$15 +la $15,4 +div $24,$24,$15 +sw $24,-76+272($sp) +la $24,-176+272($sp) +la $15,-172+272($sp) +subu $24,$24,$15 +la $15,4 +div $24,$24,$15 +sw $24,-72+272($sp) +la $24,-180+272($sp) +la $15,-176+272($sp) +subu $24,$24,$15 +la $15,4 +div $24,$24,$15 +sw $24,-68+272($sp) +la $24,-184+272($sp) +la $15,-180+272($sp) +subu $24,$24,$15 +la $15,4 +div $24,$24,$15 +sw $24,-64+272($sp) +la $24,-188+272($sp) +la $15,-184+272($sp) +subu $24,$24,$15 +la $15,4 +div $24,$24,$15 +sw $24,-60+272($sp) +la $24,-192+272($sp) +la $15,-188+272($sp) +subu $24,$24,$15 +la $15,4 +div $24,$24,$15 +sw $24,-56+272($sp) +la $24,-196+272($sp) +la $15,-192+272($sp) +subu $24,$24,$15 +la $15,4 +div $24,$24,$15 +sw $24,-52+272($sp) +la $24,-200+272($sp) +la $15,-196+272($sp) +subu $24,$24,$15 +la $15,4 +div $24,$24,$15 +sw $24,-48+272($sp) +la $24,-204+272($sp) +la $15,-200+272($sp) +subu $24,$24,$15 +la $15,4 +div $24,$24,$15 +sw $24,-44+272($sp) +la $24,-208+272($sp) +la $15,-204+272($sp) +subu $24,$24,$15 +la $15,4 +div $24,$24,$15 +sw $24,-40+272($sp) +la $24,-212+272($sp) +la $15,-208+272($sp) +subu $24,$24,$15 +la $15,4 +div $24,$24,$15 +sw $24,-36+272($sp) +la $24,-220+272($sp) +la $15,-212+272($sp) +subu $24,$24,$15 +la $15,4 +div $24,$24,$15 +sw $24,-32+272($sp) +lw $24,-116+272($sp) +sw $24,-128+272($sp) +la $24,1 +sw $24,-124+272($sp) +sw $0,-120+272($sp) +L.3090: +lw $24,-124+272($sp) +la $15,1 +beq $24,$15,L.3096 +la $15,2 +beq $24,$15,L.3099 +la $15,3 +beq $24,$15,L.3104 +b L.3094 +L.3096: +lw $24,-120+272($sp) +sll $24,$24,2 +la $15,-116+272($sp) +addu $24,$24,$15 +lw $24,($24) +lw $15,-128+272($sp) +beq $24,$15,L.3095 +la $24,2 +lw $15,-120+272($sp) +sll $15,$15,2 +la $14,-116+272($sp) +addu $15,$15,$14 +lw $15,($15) +sw $15,-228+272($sp) +sw $24,-124+272($sp) +la $24,1 +sw $24,-224+272($sp) +b L.3095 +L.3099: +lw $24,-120+272($sp) +sll $24,$24,2 +la $15,-116+272($sp) +addu $24,$24,$15 +lw $24,($24) +lw $15,-128+272($sp) +bne $24,$15,L.3100 +la $24,3 +sw $24,-124+272($sp) +b L.3095 +L.3100: +lw $24,-120+272($sp) +sll $24,$24,2 +la $15,-116+272($sp) +addu $24,$24,$15 +lw $24,($24) +lw $15,-228+272($sp) +bne $24,$15,L.3102 +lw $24,-224+272($sp) +la $24,1($24) +sw $24,-224+272($sp) +b L.3095 +L.3102: +la $24,4 +sw $24,-124+272($sp) +b L.3095 +L.3104: +lw $24,-120+272($sp) +sll $24,$24,2 +la $15,-116+272($sp) +addu $24,$24,$15 +lw $24,($24) +lw $15,-128+272($sp) +beq $24,$15,L.3095 +la $24,4 +sw $24,-124+272($sp) +L.3094: +L.3095: +L.3091: +lw $24,-120+272($sp) +la $24,1($24) +sw $24,-120+272($sp) +lw $24,-120+272($sp) +la $15,22 +blt $24,$15,L.3090 +lw $24,-124+272($sp) +la $15,3 +bne $24,$15,L.3107 +la $24,16 +lw $15,-224+272($sp) +subu $2,$24,$15 +b L.3068 +L.3107: +la $2,-1 +L.3068: +lw $16,0($sp) +lw $17,4($sp) +lw $18,8($sp) +lw $19,12($sp) +lw $20,16($sp) +lw $21,20($sp) +lw $22,24($sp) +lw $23,28($sp) +lw $30,32($sp) +addu $sp,$sp,272 +j $31 +.end regi +.globl regp +.text +.align 2 +.ent regp +regp: +.frame $sp,272,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-272 +.mask 0x40ff0000,-240 +sw $16,0($sp) +sw $17,4($sp) +sw $18,8($sp) +sw $19,12($sp) +sw $20,16($sp) +sw $21,20($sp) +sw $22,24($sp) +sw $23,28($sp) +sw $30,32($sp) +la $24,-216+272($sp) +sw $24,-216+272($sp) +la $24,-192+272($sp) +sw $24,-192+272($sp) +la $24,-196+272($sp) +sw $24,-196+272($sp) +la $24,-200+272($sp) +sw $24,-200+272($sp) +la $30,-128+272($sp) +la $24,-128+272($sp) +sw $24,-128+272($sp) +la $23,-132+272($sp) +la $24,-132+272($sp) +sw $24,-132+272($sp) +la $22,-136+272($sp) +la $24,-136+272($sp) +sw $24,-136+272($sp) +la $21,-140+272($sp) +la $24,-140+272($sp) +sw $24,-140+272($sp) +la $20,-144+272($sp) +la $24,-144+272($sp) +sw $24,-144+272($sp) +la $19,-148+272($sp) +la $24,-148+272($sp) +sw $24,-148+272($sp) +la $18,-152+272($sp) +la $24,-152+272($sp) +sw $24,-152+272($sp) +la $17,-156+272($sp) +la $24,-156+272($sp) +sw $24,-156+272($sp) +la $16,-160+272($sp) +la $24,-160+272($sp) +sw $24,-160+272($sp) +la $24,-164+272($sp) +sw $24,-4+272($sp) +la $24,-164+272($sp) +sw $24,-164+272($sp) +la $24,-168+272($sp) +sw $24,-8+272($sp) +la $24,-168+272($sp) +sw $24,-168+272($sp) +la $24,-172+272($sp) +sw $24,-12+272($sp) +la $24,-172+272($sp) +sw $24,-172+272($sp) +la $24,-176+272($sp) +sw $24,-16+272($sp) +la $24,-176+272($sp) +sw $24,-176+272($sp) +la $24,-180+272($sp) +sw $24,-20+272($sp) +la $24,-180+272($sp) +sw $24,-180+272($sp) +la $24,-184+272($sp) +sw $24,-24+272($sp) +la $24,-184+272($sp) +sw $24,-184+272($sp) +la $24,-188+272($sp) +sw $24,-28+272($sp) +la $24,-188+272($sp) +sw $24,-188+272($sp) +la $24,-204+272($sp) +sw $24,-204+272($sp) +la $24,-208+272($sp) +sw $24,-208+272($sp) +la $24,-220+272($sp) +sw $24,-220+272($sp) +la $24,-192+272($sp) +la $15,4 +la $14,-216+272($sp) +subu $14,$24,$14 +div $14,$14,$15 +sw $14,-116+272($sp) +la $14,-196+272($sp) +subu $24,$14,$24 +div $24,$24,$15 +sw $24,-112+272($sp) +la $24,-200+272($sp) +la $15,-196+272($sp) +subu $24,$24,$15 +la $15,4 +div $24,$24,$15 +sw $24,-108+272($sp) +la $24,-128+272($sp) +la $15,-200+272($sp) +subu $24,$24,$15 +la $15,4 +div $24,$24,$15 +sw $24,-104+272($sp) +la $24,-132+272($sp) +la $15,-128+272($sp) +subu $24,$24,$15 +la $15,4 +div $24,$24,$15 +sw $24,-100+272($sp) +la $24,-136+272($sp) +la $15,-132+272($sp) +subu $24,$24,$15 +la $15,4 +div $24,$24,$15 +sw $24,-96+272($sp) +la $24,-140+272($sp) +la $15,-136+272($sp) +subu $24,$24,$15 +la $15,4 +div $24,$24,$15 +sw $24,-92+272($sp) +la $24,-144+272($sp) +la $15,-140+272($sp) +subu $24,$24,$15 +la $15,4 +div $24,$24,$15 +sw $24,-88+272($sp) +la $24,-148+272($sp) +la $15,-144+272($sp) +subu $24,$24,$15 +la $15,4 +div $24,$24,$15 +sw $24,-84+272($sp) +la $24,-152+272($sp) +la $15,-148+272($sp) +subu $24,$24,$15 +la $15,4 +div $24,$24,$15 +sw $24,-80+272($sp) +la $24,-156+272($sp) +la $15,-152+272($sp) +subu $24,$24,$15 +la $15,4 +div $24,$24,$15 +sw $24,-76+272($sp) +la $24,-160+272($sp) +la $15,-156+272($sp) +subu $24,$24,$15 +la $15,4 +div $24,$24,$15 +sw $24,-72+272($sp) +la $24,-164+272($sp) +la $15,-160+272($sp) +subu $24,$24,$15 +la $15,4 +div $24,$24,$15 +sw $24,-68+272($sp) +la $24,-168+272($sp) +la $15,-164+272($sp) +subu $24,$24,$15 +la $15,4 +div $24,$24,$15 +sw $24,-64+272($sp) +la $24,-172+272($sp) +la $15,-168+272($sp) +subu $24,$24,$15 +la $15,4 +div $24,$24,$15 +sw $24,-60+272($sp) +la $24,-176+272($sp) +la $15,-172+272($sp) +subu $24,$24,$15 +la $15,4 +div $24,$24,$15 +sw $24,-56+272($sp) +la $24,-180+272($sp) +la $15,-176+272($sp) +subu $24,$24,$15 +la $15,4 +div $24,$24,$15 +sw $24,-52+272($sp) +la $24,-184+272($sp) +la $15,-180+272($sp) +subu $24,$24,$15 +la $15,4 +div $24,$24,$15 +sw $24,-48+272($sp) +la $24,-188+272($sp) +la $15,-184+272($sp) +subu $24,$24,$15 +la $15,4 +div $24,$24,$15 +sw $24,-44+272($sp) +la $24,-204+272($sp) +la $15,-188+272($sp) +subu $24,$24,$15 +la $15,4 +div $24,$24,$15 +sw $24,-40+272($sp) +la $24,-208+272($sp) +la $15,-204+272($sp) +subu $24,$24,$15 +la $15,4 +div $24,$24,$15 +sw $24,-36+272($sp) +la $24,-220+272($sp) +la $15,-208+272($sp) +subu $24,$24,$15 +la $15,4 +div $24,$24,$15 +sw $24,-32+272($sp) +lw $24,-116+272($sp) +sw $24,-212+272($sp) +la $24,1 +sw $24,-124+272($sp) +sw $0,-120+272($sp) +L.3131: +lw $24,-124+272($sp) +la $15,1 +beq $24,$15,L.3137 +la $15,2 +beq $24,$15,L.3140 +la $15,3 +beq $24,$15,L.3145 +b L.3135 +L.3137: +lw $24,-120+272($sp) +sll $24,$24,2 +la $15,-116+272($sp) +addu $24,$24,$15 +lw $24,($24) +lw $15,-212+272($sp) +beq $24,$15,L.3136 +la $24,2 +lw $15,-120+272($sp) +sll $15,$15,2 +la $14,-116+272($sp) +addu $15,$15,$14 +lw $15,($15) +sw $15,-228+272($sp) +sw $24,-124+272($sp) +la $24,1 +sw $24,-224+272($sp) +b L.3136 +L.3140: +lw $24,-120+272($sp) +sll $24,$24,2 +la $15,-116+272($sp) +addu $24,$24,$15 +lw $24,($24) +lw $15,-212+272($sp) +bne $24,$15,L.3141 +la $24,3 +sw $24,-124+272($sp) +b L.3136 +L.3141: +lw $24,-120+272($sp) +sll $24,$24,2 +la $15,-116+272($sp) +addu $24,$24,$15 +lw $24,($24) +lw $15,-228+272($sp) +bne $24,$15,L.3143 +lw $24,-224+272($sp) +la $24,1($24) +sw $24,-224+272($sp) +b L.3136 +L.3143: +la $24,4 +sw $24,-124+272($sp) +b L.3136 +L.3145: +lw $24,-120+272($sp) +sll $24,$24,2 +la $15,-116+272($sp) +addu $24,$24,$15 +lw $24,($24) +lw $15,-212+272($sp) +beq $24,$15,L.3136 +la $24,4 +sw $24,-124+272($sp) +L.3135: +L.3136: +L.3132: +lw $24,-120+272($sp) +la $24,1($24) +sw $24,-120+272($sp) +lw $24,-120+272($sp) +la $15,22 +blt $24,$15,L.3131 +lw $24,-124+272($sp) +la $15,3 +bne $24,$15,L.3148 +la $24,16 +lw $15,-224+272($sp) +subu $2,$24,$15 +b L.3109 +L.3148: +la $2,-1 +L.3109: +lw $16,0($sp) +lw $17,4($sp) +lw $18,8($sp) +lw $19,12($sp) +lw $20,16($sp) +lw $21,20($sp) +lw $22,24($sp) +lw $23,28($sp) +lw $30,32($sp) +addu $sp,$sp,272 +j $31 +.end regp +.lcomm L.3151,420 +.data +.align 0 +L.3152: +.byte 115 +.byte 56 +.byte 52 +.byte 44 +.byte 101 +.byte 114 +.byte 37 +.byte 100 +.byte 10 +.byte 0 +.sdata +.align 0 +L.3153: +.byte 115 +.byte 56 +.byte 52 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 0 +.globl s84 +.text +.text +.align 2 +.ent s84 +s84: +.frame $sp,224,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-224 +.fmask 0xc0000000,-208 +.mask 0xc2fc0000,-168 +s.d $f30,16($sp) +sw $18,24($sp) +sw $19,28($sp) +sw $20,32($sp) +sw $21,36($sp) +sw $22,40($sp) +sw $23,44($sp) +.cprestore 48 +sw $30,52($sp) +sw $31,56($sp) +move $30,$4 +la $20,L.3153 +la $19,60($30) +move $18,$0 +L.3154: +L.3155: +move $24,$19 +la $19,1($24) +move $15,$20 +la $20,1($15) +lb $15,($15) +sb $15,($24) +sll $24,$15,8*(4-1); sra $24,$24,8*(4-1) +bne $24,$0,L.3154 +la $4,3 +jal fip +sw $2,-140+224($sp) +lw $24,-140+224($sp) +lw $24,($24) +la $15,3 +beq $24,$15,L.3157 +lw $24,44($30) +beq $24,$0,L.3159 +la $4,L.3152 +la $5,1 +jal printf +L.3159: +la $18,1($18) +L.3157: +la $24,glork +sw $24,-144+224($sp) +la $4,4 +lw $25,-144+224($sp) +jal $25 +la $15,4 +beq $2,$15,L.3161 +lw $24,44($30) +beq $24,$0,L.3163 +la $4,L.3152 +la $5,2 +jal printf +L.3163: +la $18,2($18) +L.3161: +move $22,$0 +L.3165: +sll $24,$22,2 +la $15,-68+224($sp) +addu $24,$24,$15 +mtc1 $22,$f18; cvt.s.w $f18,$f18 +s.s $f18,($24) +sll $24,$22,2 +la $15,-136+224($sp) +addu $15,$24,$15 +la $14,-68+224($sp) +addu $24,$24,$14 +sw $24,($15) +L.3166: +la $22,1($22) +la $24,17 +blt $22,$24,L.3165 +l.s $f30,L.412 +move $22,$0 +L.3169: +sll $24,$22,2 +la $15,-136+224($sp) +addu $24,$24,$15 +lw $24,($24) +l.s $f18,($24) +add.s $f30,$f30,$f18 +L.3170: +la $22,1($22) +la $24,17 +blt $22,$24,L.3169 +l.s $f18,L.3175 +c.eq.s $f30,$f18; bc1t L.3173 +lw $24,44($30) +beq $24,$0,L.3176 +la $4,L.3152 +la $5,4 +jal printf +L.3176: +la $18,4($18) +L.3173: +move $21,$0 +L.3178: +move $22,$0 +L.3182: +move $23,$0 +L.3186: +sll $24,$23,2 +la $15,28 +mul $15,$15,$22 +la $14,140 +mul $14,$14,$21 +la $14,L.3151($14) +addu $15,$15,$14 +addu $24,$24,$15 +la $15,35 +mul $15,$15,$21 +la $14,7 +mul $14,$14,$22 +addu $15,$15,$14 +addu $15,$15,$23 +sw $15,($24) +L.3187: +la $23,1($23) +la $24,7 +blt $23,$24,L.3186 +L.3183: +la $22,1($22) +la $24,5 +blt $22,$24,L.3182 +L.3179: +la $21,1($21) +la $24,3 +blt $21,$24,L.3178 +la $21,1 +la $22,2 +la $23,3 +la $4,L.3151 +la $5,105 +move $6,$0 +jal array +move $24,$2 +sw $24,-148+224($sp) +la $15,140 +mul $15,$15,$21 +la $4,L.3151($15) +la $15,35 +move $5,$15 +move $6,$15 +jal array +move $24,$2 +sw $24,-152+224($sp) +la $15,28 +mul $15,$15,$22 +la $14,140 +mul $14,$14,$21 +la $14,L.3151($14) +addu $4,$15,$14 +la $5,7 +la $6,49 +jal array +lw $15,-148+224($sp) +lw $14,-152+224($sp) +addu $15,$15,$14 +addu $24,$15,$2 +sll $15,$23,2 +la $14,28 +mul $14,$14,$22 +la $13,140 +mul $13,$13,$21 +la $13,L.3151($13) +addu $14,$14,$13 +addu $15,$15,$14 +lw $15,($15) +addu $24,$24,$15 +subu $24,$24,52 +beq $24,$0,L.3190 +lw $24,44($30) +beq $24,$0,L.3192 +la $4,L.3152 +la $5,8 +jal printf +L.3192: +la $18,8($18) +L.3190: +move $2,$18 +L.3150: +l.d $f30,16($sp) +lw $18,24($sp) +lw $19,28($sp) +lw $20,32($sp) +lw $21,36($sp) +lw $22,40($sp) +lw $23,44($sp) +lw $25,48($sp) +lw $30,52($sp) +lw $31,56($sp) +addu $sp,$sp,224 +j $31 +.end s84 +.globl array +.text +.align 2 +.ent array +array: +.frame $sp,16,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-16 +.mask 0x40000000,-16 +sw $30,0($sp) +move $30,$0 +b L.3198 +L.3195: +sll $24,$30,2 +addu $24,$24,$4 +lw $24,($24) +addu $15,$30,$6 +beq $24,$15,L.3199 +la $2,1 +b L.3194 +L.3199: +L.3196: +la $30,1($30) +L.3198: +blt $30,$5,L.3195 +move $2,$0 +L.3194: +lw $30,0($sp) +addu $sp,$sp,16 +j $31 +.end array +.lcomm L.3202,4 +.globl fip +.text +.text +.align 2 +.ent fip +fip: +.frame $sp,0,$31 +.set noreorder +.cpload $25 +.set reorder +la $24,L.3202 +sw $4,L.3202 +move $2,$24 +L.3201: +j $31 +.end fip +.globl glork +.text +.align 2 +.ent glork +glork: +.frame $sp,0,$31 +.set noreorder +.cpload $25 +.set reorder +move $2,$4 +L.3203: +j $31 +.end glork +.data +.align 0 +L.3205: +.byte 115 +.byte 56 +.byte 53 +.byte 44 +.byte 101 +.byte 114 +.byte 37 +.byte 100 +.byte 10 +.byte 0 +.sdata +.align 0 +L.3206: +.byte 115 +.byte 56 +.byte 53 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 0 +.data +.align 2 +L.3214: +.word L.425 +.word L.427 +.word L.426 +.word L.428 +.word L.429 +.word L.430 +.word L.431 +.data +.align 0 +L.3215: +.byte 32 +.byte 97 +.byte 108 +.byte 105 +.byte 103 +.byte 110 +.byte 109 +.byte 101 +.byte 110 +.byte 116 +.byte 58 +.byte 32 +.byte 0 +.globl s85 +.text +.text +.align 2 +.ent s85 +s85: +.frame $sp,448,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-448 +.mask 0xc2f00000,-408 +sw $20,16($sp) +sw $21,20($sp) +sw $22,24($sp) +sw $23,28($sp) +.cprestore 32 +sw $30,36($sp) +sw $31,40($sp) +move $30,$4 +la $22,L.3206 +la $21,60($30) +move $20,$0 +L.3219: +L.3220: +move $24,$21 +la $21,1($24) +move $15,$22 +la $22,1($15) +lb $15,($15) +sb $15,($24) +sll $24,$15,8*(4-1); sra $24,$24,8*(4-1) +bne $24,$0,L.3219 +la $15,-284+448($sp) +la $14,-304+448($sp) +subu $15,$15,$14 +ble $15,$0,L.3230 +la $15,-280+448($sp) +la $14,-284+448($sp) +subu $15,$15,$14 +ble $15,$0,L.3230 +la $15,-276+448($sp) +la $14,-280+448($sp) +subu $15,$15,$14 +bgt $15,$0,L.3222 +L.3230: +lw $24,44($30) +beq $24,$0,L.3231 +la $4,L.3205 +la $5,1 +jal printf +L.3231: +la $20,1($20) +L.3222: +la $24,-337+448($sp) +la $15,-338+448($sp) +subu $24,$24,$15 +sw $24,-268+448($sp) +la $24,-340+448($sp) +la $15,-342+448($sp) +subu $24,$24,$15 +sw $24,-264+448($sp) +la $24,-348+448($sp) +la $15,-352+448($sp) +subu $24,$24,$15 +sw $24,-260+448($sp) +la $24,-356+448($sp) +la $15,-360+448($sp) +subu $24,$24,$15 +sw $24,-256+448($sp) +la $24,-364+448($sp) +la $15,-368+448($sp) +subu $24,$24,$15 +sw $24,-252+448($sp) +la $24,-372+448($sp) +la $15,-376+448($sp) +subu $24,$24,$15 +sw $24,-248+448($sp) +la $24,-384+448($sp) +la $15,-392+448($sp) +subu $24,$24,$15 +sw $24,-244+448($sp) +lw $24,40($30) +beq $24,$0,L.3246 +move $23,$0 +L.3248: +la $4,L.3252 +sll $24,$23,2 +lw $5,L.3214($24) +la $6,L.3215 +la $15,-268+448($sp) +addu $24,$24,$15 +lw $7,($24) +jal printf +L.3249: +la $23,1($23) +la $24,7 +blt $23,$24,L.3248 +L.3246: +lw $24,-272+448($sp) +or $24,$24,0x1c000000 +sw $24,-272+448($sp) +lw $24,-272+448($sp) +move $15,$24 +and $15,$15,0x3fffffff +sll $24,$24,3 +sra $24,$24,29 +sll $24,$24,30 +sra $24,$24,30 +sll $24,$24,30 +and $24,$24,0xc0000000 +or $24,$15,$24 +sw $24,-272+448($sp) +lw $24,-272+448($sp) +move $15,$24 +and $15,$15,0xe3ffffff +sra $24,$24,30 +sll $24,$24,29 +sra $24,$24,29 +sll $24,$24,26 +and $24,$24,0x1c000000 +or $24,$15,$24 +sw $24,-272+448($sp) +la $24,3 +lw $15,-272+448($sp) +sll $15,$15,3 +sra $15,$15,29 +beq $15,$24,L.3253 +lw $24,-272+448($sp) +sll $24,$24,3 +sra $24,$24,29 +la $15,-1 +bne $24,$15,L.3255 +lw $24,40($30) +beq $24,$0,L.3256 +la $4,L.3259 +jal printf +b L.3256 +L.3255: +lw $24,44($30) +beq $24,$0,L.3260 +la $4,L.3205 +la $5,2 +jal printf +L.3260: +la $20,2($20) +L.3256: +L.3253: +lw $24,-272+448($sp) +or $24,$24,0x2000000 +sw $24,-272+448($sp) +lw $24,-272+448($sp) +sll $24,$24,6 +sra $24,$24,31 +la $15,1 +beq $24,$15,L.3262 +lw $24,40($30) +beq $24,$0,L.3264 +la $4,L.3266 +jal printf +L.3264: +L.3262: +la $24,-240+448($sp) +subu $24,$24,$24 +bne $24,$0,L.3274 +bne $24,$0,L.3274 +bne $24,$0,L.3274 +bne $24,$0,L.3274 +bne $24,$0,L.3274 +bne $24,$0,L.3274 +beq $24,$0,L.3267 +L.3274: +lw $24,44($30) +beq $24,$0,L.3275 +la $4,L.3205 +la $5,4 +jal printf +L.3275: +la $20,4($20) +L.3267: +b L.3277 +lw $24,44($30) +beq $24,$0,L.3279 +la $4,L.3205 +la $5,8 +jal printf +L.3279: +la $20,8($20) +L.3277: +la $24,-336+448($sp) +sw $24,-276+448($sp) +la $24,2 +sb $24,-336+448($sp) +lw $24,-276+448($sp) +lb $15,($24) +la $15,1($15) +sb $15,($24) +lb $24,-336+448($sp) +la $15,3 +beq $24,$15,L.3283 +lw $24,44($30) +beq $24,$0,L.3285 +la $4,L.3205 +la $5,16 +jal printf +L.3285: +la $20,16($20) +L.3283: +move $2,$20 +L.3204: +lw $20,16($sp) +lw $21,20($sp) +lw $22,24($sp) +lw $23,28($sp) +lw $25,32($sp) +lw $30,36($sp) +lw $31,40($sp) +addu $sp,$sp,448 +j $31 +.end s85 +.data +.align 0 +L.3288: +.byte 115 +.byte 56 +.byte 54 +.byte 44 +.byte 101 +.byte 114 +.byte 37 +.byte 100 +.byte 10 +.byte 0 +.sdata +.align 0 +L.3289: +.byte 115 +.byte 56 +.byte 54 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 0 +.data +.align 2 +L.3290: +.word 0x1 +.word 0x3 +.word 0x5 +.sdata +.align 2 +L.3291: +.word L.3290+8 +.lcomm L.3293,40 +.data +.align 2 +L.3294: +.word 0x3f800000 +.word 0x40400000 +.word 0x40a00000 +.word 0x40000000 +.word 0x40800000 +.word 0x40c00000 +.word 0x40400000 +.word 0x40a00000 +.word 0x40e00000 +.word 0x0 +.word 0x0 +.word 0x0 +.data +.align 2 +L.3295: +.word 0x3f800000 +.word 0x40400000 +.word 0x40a00000 +.word 0x40000000 +.word 0x40800000 +.word 0x40c00000 +.word 0x40400000 +.word 0x40a00000 +.word 0x40e00000 +.space 12 +.data +.align 2 +L.3296: +.word 0x3f800000 +.word 0x40400000 +.word 0x40a00000 +.word 0x40000000 +.word 0x40800000 +.word 0x40c00000 +.word 0x40400000 +.word 0x40a00000 +.word 0x40e00000 +.space 12 +.data +.align 2 +L.3297: +.word 0x3f800000 +.space 8 +.word 0x40000000 +.space 8 +.word 0x40400000 +.space 8 +.word 0x40800000 +.space 8 +.globl s86 +.text +.text +.align 2 +.ent s86 +s86: +.frame $sp,64,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-64 +.mask 0xc2ff0000,-8 +sw $16,16($sp) +sw $17,20($sp) +sw $18,24($sp) +sw $19,28($sp) +sw $20,32($sp) +sw $21,36($sp) +sw $22,40($sp) +sw $23,44($sp) +.cprestore 48 +sw $30,52($sp) +sw $31,56($sp) +sw $4,64($sp) +lw $24,L.3291 +la $16,-4($24) +jal one +sll $24,$2,2 +addu $30,$24,$16 +la $19,L.3289 +lw $24,0+64($sp) +la $18,60($24) +move $17,$0 +L.3298: +L.3299: +move $24,$18 +la $18,1($24) +move $15,$19 +la $19,1($15) +lb $15,($15) +sb $15,($24) +sll $24,$15,8*(4-1); sra $24,$24,8*(4-1) +bne $24,$0,L.3298 +lw $24,L.3291 +lw $24,($24) +la $15,5 +beq $24,$15,L.3301 +lw $24,0+64($sp) +lw $24,44($24) +beq $24,$0,L.3303 +la $4,L.3288 +la $5,1 +jal printf +L.3303: +la $17,1($17) +L.3301: +lw $24,($16) +la $15,3 +beq $24,$15,L.3305 +lw $24,0+64($sp) +lw $24,44($24) +beq $24,$0,L.3307 +la $4,L.3288 +la $5,2 +jal printf +L.3307: +la $17,2($17) +L.3305: +lw $24,($30) +la $15,5 +beq $24,$15,L.3309 +lw $24,0+64($sp) +lw $24,44($24) +beq $24,$0,L.3311 +la $4,L.3288 +la $5,4 +jal printf +L.3311: +la $17,4($17) +L.3309: +move $20,$0 +move $23,$0 +L.3313: +sll $24,$23,2 +lw $24,L.3293($24) +beq $24,$0,L.3317 +la $20,1 +L.3317: +L.3314: +la $23,1($23) +la $24,10 +blt $23,$24,L.3313 +beq $20,$0,L.3319 +lw $24,0+64($sp) +lw $24,44($24) +beq $24,$0,L.3321 +la $4,L.3288 +la $5,8 +jal printf +L.3321: +la $17,8($17) +L.3319: +move $20,$0 +move $22,$0 +L.3323: +move $23,$0 +L.3327: +la $24,3 +mul $24,$24,$22 +addu $21,$24,$23 +sll $24,$23,2 +la $15,12 +mul $15,$15,$22 +la $14,L.3295($15) +addu $14,$24,$14 +l.s $f18,($14) +la $15,L.3296($15) +addu $24,$24,$15 +l.s $f16,($24) +c.eq.s $f18,$f16; bc1f L.3333 +sll $24,$21,2 +l.s $f16,L.3294($24) +c.eq.s $f18,$f16; bc1t L.3331 +L.3333: +la $20,1 +L.3331: +L.3328: +la $23,1($23) +la $24,3 +blt $23,$24,L.3327 +L.3324: +la $22,1($22) +la $24,4 +blt $22,$24,L.3323 +beq $20,$0,L.3334 +lw $24,0+64($sp) +lw $24,44($24) +beq $24,$0,L.3336 +la $4,L.3288 +la $5,16 +jal printf +L.3336: +la $17,16($17) +L.3334: +move $20,$0 +move $23,$0 +L.3338: +la $24,12 +mul $24,$24,$23 +l.s $f18,L.3297($24) +la $24,1($23) +mtc1 $24,$f16; cvt.s.w $f16,$f16 +c.eq.s $f18,$f16; bc1t L.3342 +la $20,1 +L.3342: +L.3339: +la $23,1($23) +la $24,4 +blt $23,$24,L.3338 +beq $20,$0,L.3344 +lw $24,0+64($sp) +lw $24,44($24) +beq $24,$0,L.3346 +la $4,L.3288 +la $5,32 +jal printf +L.3346: +la $17,32($17) +L.3344: +move $2,$17 +L.3287: +lw $16,16($sp) +lw $17,20($sp) +lw $18,24($sp) +lw $19,28($sp) +lw $20,32($sp) +lw $21,36($sp) +lw $22,40($sp) +lw $23,44($sp) +lw $25,48($sp) +lw $30,52($sp) +lw $31,56($sp) +addu $sp,$sp,64 +j $31 +.end s86 +.globl one +.text +.align 2 +.ent one +one: +.frame $sp,0,$31 +.set noreorder +.cpload $25 +.set reorder +la $2,1 +L.3348: +j $31 +.end one +.data +.align 0 +L.3350: +.byte 115 +.byte 56 +.byte 56 +.byte 44 +.byte 101 +.byte 114 +.byte 37 +.byte 100 +.byte 10 +.byte 0 +.sdata +.align 0 +L.3351: +.byte 115 +.byte 56 +.byte 56 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 0 +.globl s88 +.text +.text +.align 2 +.ent s88 +s88: +.frame $sp,64,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-64 +.mask 0xc2e00000,-28 +sw $21,16($sp) +sw $22,20($sp) +sw $23,24($sp) +.cprestore 28 +sw $30,32($sp) +sw $31,36($sp) +sw $4,64($sp) +la $30,L.3351 +lw $24,0+64($sp) +la $23,60($24) +move $22,$0 +L.3353: +L.3354: +move $24,$23 +la $23,1($24) +move $15,$30 +la $30,1($15) +lb $15,($15) +sb $15,($24) +sll $24,$15,8*(4-1); sra $24,$24,8*(4-1) +bne $24,$0,L.3353 +b L.3356 +lw $24,0+64($sp) +lw $24,44($24) +beq $24,$0,L.3358 +la $4,L.3350 +la $5,1 +jal printf +L.3358: +la $22,1($22) +L.3356: +la $24,-20+64($sp) +sw $24,metricp +la $24,2 +sw $24,-20+64($sp) +lw $24,metricp +la $15,3 +sw $15,($24) +lw $24,-20+64($sp) +la $15,3 +beq $24,$15,L.3360 +lw $24,0+64($sp) +lw $24,44($24) +beq $24,$0,L.3362 +la $4,L.3350 +la $5,2 +jal printf +L.3362: +la $22,2($22) +L.3360: +l.d $f18,L.419 +s.d $f18,-16+64($sp) +s.d $f18,-8+64($sp) +la $21,-16+64($sp) +l.d $f18,L.418 +s.d $f18,($21) +l.d $f18,L.418 +s.d $f18,8($21) +l.d $f18,-16+64($sp) +l.d $f16,-8+64($sp) +add.d $f18,$f18,$f16 +l.d $f16,L.416 +c.eq.d $f18,$f16; bc1t L.3365 +lw $24,0+64($sp) +lw $24,44($24) +beq $24,$0,L.3368 +la $4,L.3350 +la $5,4 +jal printf +L.3368: +la $22,4($22) +L.3365: +move $2,$22 +L.3349: +lw $21,16($sp) +lw $22,20($sp) +lw $23,24($sp) +lw $25,28($sp) +lw $30,32($sp) +lw $31,36($sp) +addu $sp,$sp,64 +j $31 +.end s88 +.data +.align 0 +L.3371: +.byte 115 +.byte 57 +.byte 44 +.byte 101 +.byte 114 +.byte 37 +.byte 100 +.byte 10 +.byte 0 +.sdata +.align 0 +L.3372: +.byte 115 +.byte 57 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 0 +.globl s9 +.text +.text +.align 2 +.ent s9 +s9: +.frame $sp,64,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-64 +.mask 0xc2ff0000,-8 +sw $16,16($sp) +sw $17,20($sp) +sw $18,24($sp) +sw $19,28($sp) +sw $20,32($sp) +sw $21,36($sp) +sw $22,40($sp) +sw $23,44($sp) +.cprestore 48 +sw $30,52($sp) +sw $31,56($sp) +sw $4,64($sp) +la $22,L.3372 +lw $24,0+64($sp) +la $21,60($24) +move $20,$0 +L.3373: +L.3374: +move $24,$21 +la $21,1($24) +move $15,$22 +la $22,1($15) +lb $15,($15) +sb $15,($24) +sll $24,$15,8*(4-1); sra $24,$24,8*(4-1) +bne $24,$0,L.3373 +move $23,$0 +move $30,$0 +L.3376: +la $24,2 +move $19,$24 +move $18,$24 +la $24,3 +move $17,$24 +move $16,$24 +la $24,3 +bne $16,$24,L.3382 +beq $17,$24,L.3380 +L.3382: +la $23,1 +L.3380: +la $24,2 +bne $18,$24,L.3385 +beq $19,$24,L.3383 +L.3385: +la $23,1 +L.3383: +L.3377: +la $30,1($30) +la $24,2 +blt $30,$24,L.3376 +beq $23,$0,L.3390 +lw $24,0+64($sp) +lw $24,44($24) +beq $24,$0,L.3388 +la $4,L.3371 +la $5,1 +jal printf +L.3388: +la $20,1($20) +b L.3390 +lw $24,0+64($sp) +lw $24,44($24) +beq $24,$0,L.3391 +la $4,L.3371 +la $5,2 +jal printf +L.3391: +la $20,2($20) +L.3390: +move $2,$20 +L.3370: +lw $16,16($sp) +lw $17,20($sp) +lw $18,24($sp) +lw $19,28($sp) +lw $20,32($sp) +lw $21,36($sp) +lw $22,40($sp) +lw $23,44($sp) +lw $25,48($sp) +lw $30,52($sp) +lw $31,56($sp) +addu $sp,$sp,64 +j $31 +.end s9 +.globl setev +.text +.align 2 +.ent setev +setev: +.frame $sp,0,$31 +.set noreorder +.cpload $25 +.set reorder +la $24,1066 +sw $24,extvar +move $2,$0 +L.3393: +j $31 +.end setev +.globl rfs +.comm rfs,8 +.globl crc +.comm crc,4 +.globl rrc +.comm rrc,4 +.globl flgl +.comm flgl,4 +.globl flgd +.comm flgd,4 +.globl flgm +.comm flgm,4 +.globl flgs +.comm flgs,4 +.globl dprec +.comm dprec,4 +.globl fprec +.comm fprec,4 +.globl dbits +.comm dbits,4 +.globl fbits +.comm fbits,4 +.globl ubits +.comm ubits,4 +.globl lbits +.comm lbits,4 +.globl metricp +.comm metricp,4 +.globl extvar +.comm extvar,4 +.rdata +.align 0 +L.3266: +.byte 66 +.byte 101 +.byte 32 +.byte 101 +.byte 115 +.byte 112 +.byte 101 +.byte 99 +.byte 105 +.byte 97 +.byte 108 +.byte 108 +.byte 121 +.byte 32 +.byte 99 +.byte 97 +.byte 114 +.byte 101 +.byte 102 +.byte 117 +.byte 108 +.byte 32 +.byte 119 +.byte 105 +.byte 116 +.byte 104 +.byte 32 +.byte 49 +.byte 45 +.byte 98 +.byte 105 +.byte 116 +.byte 32 +.byte 102 +.byte 105 +.byte 101 +.byte 108 +.byte 100 +.byte 115 +.byte 33 +.byte 10 +.byte 0 +.align 0 +L.3259: +.byte 83 +.byte 105 +.byte 103 +.byte 110 +.byte 32 +.byte 101 +.byte 120 +.byte 116 +.byte 101 +.byte 110 +.byte 115 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 105 +.byte 110 +.byte 32 +.byte 102 +.byte 105 +.byte 101 +.byte 108 +.byte 100 +.byte 115 +.byte 10 +.byte 0 +.align 0 +L.3252: +.byte 37 +.byte 115 +.byte 37 +.byte 115 +.byte 37 +.byte 100 +.byte 10 +.byte 0 +.align 2 +L.3175: +.word 0x43080000 +.align 0 +L.3022: +.byte 112 +.byte 111 +.byte 105 +.byte 110 +.byte 116 +.byte 101 +.byte 114 +.byte 0 +.align 0 +L.2472: +.byte 73 +.byte 110 +.byte 99 +.byte 114 +.byte 101 +.byte 97 +.byte 115 +.byte 105 +.byte 110 +.byte 103 +.byte 32 +.byte 97 +.byte 114 +.byte 114 +.byte 97 +.byte 121 +.byte 32 +.byte 101 +.byte 108 +.byte 101 +.byte 109 +.byte 101 +.byte 110 +.byte 116 +.byte 115 +.byte 32 +.byte 97 +.byte 115 +.byte 115 +.byte 105 +.byte 103 +.byte 110 +.byte 101 +.byte 100 +.byte 32 +.byte 116 +.byte 111 +.byte 32 +.byte 100 +.byte 101 +.byte 99 +.byte 114 +.byte 101 +.byte 97 +.byte 115 +.byte 105 +.byte 110 +.byte 103 +.byte 32 +.byte 108 +.byte 111 +.byte 99 +.byte 97 +.byte 116 +.byte 105 +.byte 111 +.byte 110 +.byte 115 +.byte 10 +.byte 0 +.align 2 +L.2356: +.word 0x41d00000 +.align 3 +L.2355: +.word 0x403a0000 +.word 0x0 +.align 3 +L.1659: +.word 0x40040000 +.word 0x0 +.align 3 +L.1484: +.word 0x40240000 +.word 0x0 +.align 2 +L.1455: +.word 0x41200000 +.align 3 +L.1280: +.word 0x40080000 +.word 0x0 +.align 2 +L.1251: +.word 0x40400000 +.align 3 +L.1076: +.word 0x401c0000 +.word 0x0 +.align 2 +L.1047: +.word 0x40e00000 +.align 3 +L.870: +.word 0x40140000 +.word 0x0 +.align 2 +L.841: +.word 0x40a00000 +.align 3 +L.836: +.word 0x41e00000 +.word 0x0 +.align 2 +L.828: +.word 0x4f000000 +.align 0 +L.653: +.byte 113 +.byte 117 +.byte 101 +.byte 101 +.byte 112 +.byte 0 +.align 0 +L.639: +.byte 10 +.byte 0 +.align 0 +L.638: +.byte 37 +.byte 100 +.byte 0 +.align 0 +L.633: +.byte 32 +.byte 32 +.byte 32 +.byte 107 +.byte 101 +.byte 121 +.byte 61 +.byte 0 +.align 3 +L.596: +.word 0x40000000 +.word 0x0 +.align 3 +L.536: +.word 0x40ce8480 +.word 0x0 +.align 3 +L.535: +.word 0x405f4000 +.word 0x0 +.align 2 +L.534: +.word 0x42fa0000 +.align 2 +L.529: +.word 0x40000000 +.align 0 +L.431: +.byte 100 +.byte 111 +.byte 117 +.byte 98 +.byte 108 +.byte 101 +.byte 0 +.align 0 +L.430: +.byte 102 +.byte 108 +.byte 111 +.byte 97 +.byte 116 +.byte 0 +.align 0 +L.429: +.byte 117 +.byte 110 +.byte 115 +.byte 105 +.byte 103 +.byte 110 +.byte 101 +.byte 100 +.byte 0 +.align 0 +L.428: +.byte 108 +.byte 111 +.byte 110 +.byte 103 +.byte 0 +.align 0 +L.427: +.byte 115 +.byte 104 +.byte 111 +.byte 114 +.byte 116 +.byte 0 +.align 0 +L.426: +.byte 105 +.byte 110 +.byte 116 +.byte 0 +.align 0 +L.425: +.byte 99 +.byte 104 +.byte 97 +.byte 114 +.byte 0 +.align 3 +L.419: +.word 0x0 +.word 0x0 +.align 3 +L.418: +.word 0x3ff00000 +.word 0x0 +.align 3 +L.417: +.word 0x40100000 +.word 0x0 +.align 3 +L.416: +.word 0x40000000 +.word 0x0 +.align 2 +L.412: +.word 0x0 +.align 2 +L.411: +.word 0x3f800000 +.align 0 +L.390: +.byte 113 +.byte 117 +.byte 101 +.byte 101 +.byte 112 +.byte 33 +.byte 0 +.align 0 +L.379: +.byte 10 +.byte 9 +.byte 8 +.byte 13 +.byte 12 +.byte 92 +.byte 39 +.byte 0 +.align 0 +L.375: +.byte 46 +.byte 34 +.byte 46 +.byte 0 +.align 0 +L.362: +.byte 46 +.byte 46 +.byte 46 +.byte 0 +.align 3 +L.333: +.word 0x40938800 +.word 0x0 +.align 0 +L.199: +.byte 32 +.byte 32 +.byte 32 +.byte 100 +.byte 105 +.byte 102 +.byte 102 +.byte 101 +.byte 114 +.byte 101 +.byte 110 +.byte 116 +.byte 32 +.byte 114 +.byte 101 +.byte 115 +.byte 117 +.byte 108 +.byte 116 +.byte 115 +.byte 32 +.byte 119 +.byte 104 +.byte 101 +.byte 110 +.byte 32 +.byte 97 +.byte 115 +.byte 115 +.byte 105 +.byte 103 +.byte 110 +.byte 101 +.byte 100 +.byte 32 +.byte 116 +.byte 111 +.byte 32 +.byte 108 +.byte 111 +.byte 110 +.byte 103 +.byte 115 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.198: +.byte 68 +.byte 101 +.byte 99 +.byte 105 +.byte 109 +.byte 97 +.byte 108 +.byte 32 +.byte 97 +.byte 110 +.byte 100 +.byte 32 +.byte 111 +.byte 99 +.byte 116 +.byte 97 +.byte 108 +.byte 47 +.byte 104 +.byte 101 +.byte 120 +.byte 32 +.byte 99 +.byte 111 +.byte 110 +.byte 115 +.byte 116 +.byte 97 +.byte 110 +.byte 116 +.byte 115 +.byte 32 +.byte 115 +.byte 111 +.byte 109 +.byte 101 +.byte 116 +.byte 105 +.byte 109 +.byte 101 +.byte 115 +.byte 32 +.byte 103 +.byte 105 +.byte 118 +.byte 101 +.byte 10 +.byte 0 +.align 0 +L.27: +.byte 10 +.byte 70 +.byte 97 +.byte 105 +.byte 108 +.byte 101 +.byte 100 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.26: +.byte 10 +.byte 78 +.byte 111 +.byte 32 +.byte 101 +.byte 114 +.byte 114 +.byte 111 +.byte 114 +.byte 115 +.byte 32 +.byte 100 +.byte 101 +.byte 116 +.byte 101 +.byte 99 +.byte 116 +.byte 101 +.byte 100 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.20: +.byte 83 +.byte 101 +.byte 99 +.byte 116 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 37 +.byte 115 +.byte 32 +.byte 114 +.byte 101 +.byte 116 +.byte 117 +.byte 114 +.byte 110 +.byte 101 +.byte 100 +.byte 32 +.byte 37 +.byte 100 +.byte 46 +.byte 10 +.byte 0 diff --git a/src/cmd/lccom/tst/mips-eb/ctype.h b/src/cmd/lccom/tst/mips-eb/ctype.h new file mode 100644 index 0000000..2a43440 --- /dev/null +++ b/src/cmd/lccom/tst/mips-eb/ctype.h @@ -0,0 +1,40 @@ +#ifndef __CTYPE +#define __CTYPE + +extern int isalnum(int); +extern int isalpha(int); +extern int iscntrl(int); +extern int isdigit(int); +extern int isgraph(int); +extern int islower(int); +extern int isprint(int); +extern int ispunct(int); +extern int isspace(int); +extern int isupper(int); +extern int isxdigit(int); +extern int tolower(int); +extern int toupper(int); + +#define __U 01 +#define __L 02 +#define __N 04 +#define __S 010 +#define __P 020 +#define __C 040 +#define __B 0100 +#define __X 0200 + +extern unsigned char _ctype[]; +#define isalnum(c) ((_ctype+1)[c]&(__U|__L|__N)) +#define isalpha(c) ((_ctype+1)[c]&(__U|__L)) +#define iscntrl(c) ((_ctype+1)[c]&__C) +#define isdigit(c) ((_ctype+1)[c]&__N) +#define isgraph(c) ((_ctype+1)[c]&(__P|__U|__L|__N)) +#define islower(c) ((_ctype+1)[c]&__L) +#define isprint(c) ((_ctype+1)[c]&(__P|__U|__L|__N|__B)) +#define ispunct(c) ((_ctype+1)[c]&__P) +#define isspace(c) ((_ctype+1)[c]&__S) +#define isupper(c) ((_ctype+1)[c]&__U) +#define isxdigit(c) ((_ctype+1)[c]&__X) + +#endif /* __CTYPE */ diff --git a/src/cmd/lccom/tst/mips-eb/cvt.1bk b/src/cmd/lccom/tst/mips-eb/cvt.1bk new file mode 100644 index 0000000..b28b302 --- /dev/null +++ b/src/cmd/lccom/tst/mips-eb/cvt.1bk @@ -0,0 +1,11 @@ +1 1 1 1 1 1 1 1 1.000000 1.000000 1.000000 +2 2 2 2 2 2 2 2 2.000000 2.000000 2.000000 +3 3 3 3 3 3 3 3 3.000000 3.000000 3.000000 +4 4 4 4 4 4 4 4 4.000000 4.000000 4.000000 +5 5 5 5 5 5 5 5 5.000000 5.000000 5.000000 +6 6 6 6 6 6 6 6 6.000000 6.000000 6.000000 +7 7 7 7 7 7 7 7 7.000000 7.000000 7.000000 +8 8 8 8 8 8 8 8 8.000000 8.000000 8.000000 +9 9 9 9 9 9 9 9 9.000000 9.000000 9.000000 +10 10 10 10 10 10 10 10 10.000000 10.000000 10.000000 +11 11 11 11 11 11 11 11 11.000000 11.000000 11.000000 diff --git a/src/cmd/lccom/tst/mips-eb/cvt.2bk b/src/cmd/lccom/tst/mips-eb/cvt.2bk new file mode 100644 index 0000000..241527d --- /dev/null +++ b/src/cmd/lccom/tst/mips-eb/cvt.2bk @@ -0,0 +1,2 @@ +tst/cvt.c:32: warning: conversion from `pointer to void function(void)' to `pointer to void' is compiler dependent +tst/cvt.c:33: warning: conversion from `pointer to void' to `pointer to void function(void)' is compiler dependent diff --git a/src/cmd/lccom/tst/mips-eb/cvt.sbk b/src/cmd/lccom/tst/mips-eb/cvt.sbk new file mode 100644 index 0000000..feaf7d3 --- /dev/null +++ b/src/cmd/lccom/tst/mips-eb/cvt.sbk @@ -0,0 +1,557 @@ +.set reorder +.globl print +.text +.text +.align 2 +.ent print +print: +.frame $sp,80,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-80 +.mask 0x82000000,-12 +.cprestore 64 +sw $31,68($sp) +la $4,L.2 +lb $5,c +lh $6,s +lw $7,i +lw $24,l +sw $24,16($sp) +lbu $24,C +sw $24,20($sp) +lhu $24,S +sw $24,24($sp) +lw $24,I +sw $24,28($sp) +lw $24,L +sw $24,32($sp) +l.s $f18,f +cvt.d.s $f18,$f18 +s.d $f18,40($sp) +l.d $f18,d +s.d $f18,48($sp) +l.d $f18,D +s.d $f18,56($sp) +jal printf +L.1: +lw $25,64($sp) +lw $31,68($sp) +addu $sp,$sp,80 +j $31 +.end print +.globl main +.text +.align 2 +.ent main +main: +.frame $sp,80,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-80 +.mask 0xc2ff0000,-24 +sw $16,16($sp) +sw $17,20($sp) +sw $18,24($sp) +sw $19,28($sp) +sw $20,32($sp) +sw $21,36($sp) +sw $22,40($sp) +sw $23,44($sp) +.cprestore 48 +sw $30,52($sp) +sw $31,56($sp) +la $24,1 +sb $24,c +lb $24,c +move $15,$24 +sh $15,s +sw $24,i +sw $24,l +move $15,$24 +move $14,$15 +sb $14,C +move $14,$15 +sh $14,S +sw $15,I +sw $15,L +mtc1 $24,$f18; cvt.s.w $f18,$f18 +s.s $f18,f +mtc1 $24,$f18; cvt.d.w $f18,$f18 +s.d $f18,d +s.d $f18,D +jal print +la $24,2 +sh $24,s +lh $24,s +move $15,$24 +sb $15,c +sw $24,i +sw $24,l +move $15,$24 +move $14,$15 +sb $14,C +move $14,$15 +sh $14,S +sw $15,I +sw $15,L +mtc1 $24,$f18; cvt.s.w $f18,$f18 +s.s $f18,f +mtc1 $24,$f18; cvt.d.w $f18,$f18 +s.d $f18,d +s.d $f18,D +jal print +la $24,3 +sw $24,i +lw $24,i +move $15,$24 +sb $15,c +move $15,$24 +sh $15,s +sw $24,l +move $15,$24 +move $14,$15 +sb $14,C +move $14,$15 +sh $14,S +sw $15,I +sw $15,L +mtc1 $24,$f18; cvt.s.w $f18,$f18 +s.s $f18,f +mtc1 $24,$f18; cvt.d.w $f18,$f18 +s.d $f18,d +s.d $f18,D +jal print +la $24,4 +sw $24,l +lw $24,l +move $15,$24 +sb $15,c +move $15,$24 +sh $15,s +sw $24,i +move $15,$24 +move $14,$15 +sb $14,C +move $14,$15 +sh $14,S +sw $15,I +sw $15,L +mtc1 $24,$f18; cvt.s.w $f18,$f18 +s.s $f18,f +mtc1 $24,$f18; cvt.d.w $f18,$f18 +s.d $f18,d +s.d $f18,D +jal print +la $24,5 +sb $24,C +lbu $24,C +move $15,$24 +sb $15,c +move $15,$24 +sh $15,s +sw $24,i +sw $24,l +move $15,$24 +move $14,$15 +sh $14,S +sw $15,I +sw $15,L +mtc1 $24,$f18; cvt.s.w $f18,$f18 +s.s $f18,f +mtc1 $24,$f18; cvt.d.w $f18,$f18 +s.d $f18,d +s.d $f18,D +jal print +la $24,6 +sh $24,S +lhu $24,S +move $15,$24 +sb $15,c +move $15,$24 +sh $15,s +sw $24,i +sw $24,l +move $15,$24 +move $14,$15 +sb $14,C +sw $15,I +sw $15,L +mtc1 $24,$f18; cvt.s.w $f18,$f18 +s.s $f18,f +mtc1 $24,$f18; cvt.d.w $f18,$f18 +s.d $f18,d +s.d $f18,D +jal print +la $24,7 +sw $24,I +lw $24,I +move $14,$24 +sb $14,c +move $14,$24 +sh $14,s +sw $24,i +sw $24,l +move $15,$24 +sb $15,C +move $15,$24 +sh $15,S +sw $24,L +l.d $f18,L.4 +srl $15,$24,1 +mtc1 $15,$f16; cvt.d.w $f16,$f16 +mul.d $f18,$f18,$f16 +and $24,$24,1 +mtc1 $24,$f16; cvt.d.w $f16,$f16 +add.d $f18,$f18,$f16 +cvt.s.d $f16,$f18 +s.s $f16,f +s.d $f18,d +s.d $f18,D +jal print +la $24,8 +sw $24,L +lw $24,L +move $14,$24 +sb $14,c +move $14,$24 +sh $14,s +sw $24,i +sw $24,l +move $15,$24 +sb $15,C +move $15,$24 +sh $15,S +lhu $15,S +sw $15,I +l.d $f18,L.4 +srl $15,$24,1 +mtc1 $15,$f16; cvt.d.w $f16,$f16 +mul.d $f18,$f18,$f16 +and $24,$24,1 +mtc1 $24,$f16; cvt.d.w $f16,$f16 +add.d $f18,$f18,$f16 +cvt.s.d $f16,$f18 +s.s $f16,f +s.d $f18,d +s.d $f18,D +jal print +l.s $f18,L.5 +s.s $f18,f +l.s $f18,f +trunc.w.s $f2,$f18,$24; mfc1 $24,$f2 +move $15,$24 +sb $15,c +move $15,$24 +sh $15,s +sw $24,i +sw $24,l +l.s $f16,L.9 +c.ult.s $f18,$f16; bc1t L.7 +sub.s $f16,$f18,$f16 +trunc.w.s $f2,$f16,$24; mfc1 $24,$f2 +la $30,0x80000000($24) +b L.8 +L.7: +trunc.w.s $f2,$f18,$24; mfc1 $24,$f2 +move $30,$24 +L.8: +move $24,$30 +sb $24,C +l.s $f18,f +l.s $f16,L.9 +c.ult.s $f18,$f16; bc1t L.11 +sub.s $f16,$f18,$f16 +trunc.w.s $f2,$f16,$24; mfc1 $24,$f2 +la $23,0x80000000($24) +b L.12 +L.11: +trunc.w.s $f2,$f18,$24; mfc1 $24,$f2 +move $23,$24 +L.12: +move $24,$23 +sh $24,S +l.s $f18,f +l.s $f16,L.9 +c.ult.s $f18,$f16; bc1t L.14 +sub.s $f16,$f18,$f16 +trunc.w.s $f2,$f16,$24; mfc1 $24,$f2 +la $22,0x80000000($24) +b L.15 +L.14: +trunc.w.s $f2,$f18,$24; mfc1 $24,$f2 +move $22,$24 +L.15: +sw $22,I +l.s $f18,f +l.s $f16,L.9 +c.ult.s $f18,$f16; bc1t L.17 +sub.s $f16,$f18,$f16 +trunc.w.s $f2,$f16,$24; mfc1 $24,$f2 +la $21,0x80000000($24) +b L.18 +L.17: +trunc.w.s $f2,$f18,$24; mfc1 $24,$f2 +move $21,$24 +L.18: +sw $21,L +l.s $f18,f +cvt.d.s $f18,$f18 +s.d $f18,d +s.d $f18,D +jal print +l.d $f18,L.19 +s.d $f18,d +l.d $f18,d +trunc.w.d $f2,$f18,$24; mfc1 $24,$f2 +move $15,$24 +sb $15,c +move $15,$24 +sh $15,s +sw $24,i +sw $24,l +l.d $f16,L.23 +c.ult.d $f18,$f16; bc1t L.21 +sub.d $f16,$f18,$f16 +trunc.w.d $f2,$f16,$24; mfc1 $24,$f2 +la $20,0x80000000($24) +b L.22 +L.21: +trunc.w.d $f2,$f18,$24; mfc1 $24,$f2 +move $20,$24 +L.22: +move $24,$20 +sb $24,C +l.d $f18,d +l.d $f16,L.23 +c.ult.d $f18,$f16; bc1t L.25 +sub.d $f16,$f18,$f16 +trunc.w.d $f2,$f16,$24; mfc1 $24,$f2 +la $19,0x80000000($24) +b L.26 +L.25: +trunc.w.d $f2,$f18,$24; mfc1 $24,$f2 +move $19,$24 +L.26: +move $24,$19 +sh $24,S +l.d $f18,d +l.d $f16,L.23 +c.ult.d $f18,$f16; bc1t L.28 +sub.d $f16,$f18,$f16 +trunc.w.d $f2,$f16,$24; mfc1 $24,$f2 +la $18,0x80000000($24) +b L.29 +L.28: +trunc.w.d $f2,$f18,$24; mfc1 $24,$f2 +move $18,$24 +L.29: +sw $18,I +l.d $f18,d +l.d $f16,L.23 +c.ult.d $f18,$f16; bc1t L.31 +sub.d $f16,$f18,$f16 +trunc.w.d $f2,$f16,$24; mfc1 $24,$f2 +la $17,0x80000000($24) +b L.32 +L.31: +trunc.w.d $f2,$f18,$24; mfc1 $24,$f2 +move $17,$24 +L.32: +sw $17,L +l.d $f18,d +cvt.s.d $f16,$f18 +s.s $f16,f +s.d $f18,D +jal print +l.d $f18,L.33 +s.d $f18,D +l.d $f18,D +trunc.w.d $f2,$f18,$24; mfc1 $24,$f2 +move $15,$24 +sb $15,c +move $15,$24 +sh $15,s +sw $24,i +sw $24,l +l.d $f16,L.37 +c.ult.d $f18,$f16; bc1t L.35 +sub.d $f16,$f18,$f16 +trunc.w.d $f2,$f16,$24; mfc1 $24,$f2 +la $16,0x80000000($24) +b L.36 +L.35: +trunc.w.d $f2,$f18,$24; mfc1 $24,$f2 +move $16,$24 +L.36: +move $24,$16 +sb $24,C +l.d $f18,D +l.d $f16,L.37 +c.ult.d $f18,$f16; bc1t L.39 +sub.d $f16,$f18,$f16 +trunc.w.d $f2,$f16,$24; mfc1 $24,$f2 +la $24,0x80000000($24) +sw $24,-4+80($sp) +b L.40 +L.39: +trunc.w.d $f2,$f18,$24; mfc1 $24,$f2 +sw $24,-4+80($sp) +L.40: +lw $24,-4+80($sp) +sh $24,S +l.d $f18,D +l.d $f16,L.37 +c.ult.d $f18,$f16; bc1t L.42 +sub.d $f16,$f18,$f16 +trunc.w.d $f2,$f16,$24; mfc1 $24,$f2 +la $24,0x80000000($24) +sw $24,-8+80($sp) +b L.43 +L.42: +trunc.w.d $f2,$f18,$24; mfc1 $24,$f2 +sw $24,-8+80($sp) +L.43: +lw $24,-8+80($sp) +sw $24,I +l.d $f18,D +l.d $f16,L.37 +c.ult.d $f18,$f16; bc1t L.45 +sub.d $f16,$f18,$f16 +trunc.w.d $f2,$f16,$24; mfc1 $24,$f2 +la $24,0x80000000($24) +sw $24,-12+80($sp) +b L.46 +L.45: +trunc.w.d $f2,$f18,$24; mfc1 $24,$f2 +sw $24,-12+80($sp) +L.46: +lw $24,-12+80($sp) +sw $24,L +l.d $f18,D +cvt.s.d $f16,$f18 +s.s $f16,f +s.d $f18,d +jal print +sw $0,p +sw $0,p +sw $0,p +sw $0,p +lw $24,P +sw $24,p +sw $0,P +sw $0,P +sw $0,P +sw $0,P +lw $24,p +sw $24,P +move $2,$0 +L.3: +lw $16,16($sp) +lw $17,20($sp) +lw $18,24($sp) +lw $19,28($sp) +lw $20,32($sp) +lw $21,36($sp) +lw $22,40($sp) +lw $23,44($sp) +lw $25,48($sp) +lw $30,52($sp) +lw $31,56($sp) +addu $sp,$sp,80 +j $31 +.end main +.globl P +.comm P,4 +.globl p +.comm p,4 +.globl D +.comm D,8 +.globl d +.comm d,8 +.globl f +.comm f,4 +.globl L +.comm L,4 +.globl I +.comm I,4 +.globl S +.comm S,2 +.globl C +.comm C,1 +.globl l +.comm l,4 +.globl i +.comm i,4 +.globl s +.comm s,2 +.globl c +.comm c,1 +.rdata +.align 3 +L.37: +.word 0x41e00000 +.word 0x0 +.align 3 +L.33: +.word 0x40260000 +.word 0x0 +.align 3 +L.23: +.word 0x41e00000 +.word 0x0 +.align 3 +L.19: +.word 0x40240000 +.word 0x0 +.align 2 +L.9: +.word 0x4f000000 +.align 2 +L.5: +.word 0x41100000 +.align 3 +L.4: +.word 0x40000000 +.word 0x0 +.align 0 +L.2: +.byte 37 +.byte 100 +.byte 32 +.byte 37 +.byte 100 +.byte 32 +.byte 37 +.byte 100 +.byte 32 +.byte 37 +.byte 108 +.byte 100 +.byte 32 +.byte 37 +.byte 117 +.byte 32 +.byte 37 +.byte 117 +.byte 32 +.byte 37 +.byte 117 +.byte 32 +.byte 37 +.byte 108 +.byte 117 +.byte 32 +.byte 37 +.byte 102 +.byte 32 +.byte 37 +.byte 102 +.byte 32 +.byte 37 +.byte 108 +.byte 102 +.byte 10 +.byte 0 diff --git a/src/cmd/lccom/tst/mips-eb/errno.h b/src/cmd/lccom/tst/mips-eb/errno.h new file mode 100644 index 0000000..c914e05 --- /dev/null +++ b/src/cmd/lccom/tst/mips-eb/errno.h @@ -0,0 +1,8 @@ +#ifndef __ERRNO +#define __ERRNO + +#define EDOM 33 +#define ERANGE 34 +extern int errno; + +#endif /* __ERRNO */ diff --git a/src/cmd/lccom/tst/mips-eb/fields.1bk b/src/cmd/lccom/tst/mips-eb/fields.1bk new file mode 100644 index 0000000..56fdeb9 --- /dev/null +++ b/src/cmd/lccom/tst/mips-eb/fields.1bk @@ -0,0 +1,5 @@ +x = 1 2 3 4 -3 6 +y = 3 8 9 +x = 1 2 3 0 0 6 +y = 2 8 16 +p->a = 0x3, p->b = 0xf diff --git a/src/cmd/lccom/tst/mips-eb/fields.2bk b/src/cmd/lccom/tst/mips-eb/fields.2bk new file mode 100644 index 0000000..51e1736 --- /dev/null +++ b/src/cmd/lccom/tst/mips-eb/fields.2bk @@ -0,0 +1,4 @@ +tst/fields.c:6: warning: initializer exceeds bit-field width +tst/fields.c:8: warning: initializer exceeds bit-field width +tst/fields.c:30: warning: missing return value +tst/fields.c:34: warning: missing return value diff --git a/src/cmd/lccom/tst/mips-eb/fields.sbk b/src/cmd/lccom/tst/mips-eb/fields.sbk new file mode 100644 index 0000000..ff68f28 --- /dev/null +++ b/src/cmd/lccom/tst/mips-eb/fields.sbk @@ -0,0 +1,304 @@ +.set reorder +.globl x +.data +.align 2 +x: +.word 0x1 +.byte 0x2 +.space 3 +.byte 0x0 +.byte 0x34 +.space 2 +.byte 0xa +.byte 0x6 +.space 2 +.globl i +.sdata +.align 2 +i: +.word 0x10 +.globl y +.sdata +.align 2 +y: +.byte 0xe0 +.space 3 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x9 +.globl main +.text +.text +.align 2 +.ent main +main: +.frame $sp,48,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-48 +.mask 0x82000000,-16 +.cprestore 28 +sw $31,32($sp) +la $4,L.4 +lw $5,x +lb $6,x+4 +lw $24,x+8 +sra $7,$24,20 +lw $24,x+8 +sll $24,$24,12 +sra $24,$24,28 +sw $24,16($sp) +lw $24,x+12 +sll $24,$24,4 +sra $24,$24,29 +sw $24,20($sp) +lb $24,x+13 +sw $24,24($sp) +jal printf +la $4,L.10 +lw $24,y +srl $15,$24,30 +and $5,$15,3 +srl $24,$24,26 +and $6,$24,15 +lw $7,y+4 +jal printf +lw $24,x+8 +and $24,$24,0xfff0ffff +lw $15,i +sll $15,$15,28 +sra $15,$15,28 +sll $15,$15,16 +and $15,$15,0xf0000 +or $24,$24,$15 +sw $24,x+8 +lw $24,x+12 +and $24,$24,0xf1ffffff +sw $24,x+12 +la $4,L.4 +lw $5,x +lb $6,x+4 +lw $24,x+8 +sra $7,$24,20 +lw $24,x+8 +sll $24,$24,12 +sra $24,$24,28 +sw $24,16($sp) +lw $24,x+12 +sll $24,$24,4 +sra $24,$24,29 +sw $24,20($sp) +lb $24,x+13 +sw $24,24($sp) +jal printf +lw $24,y +and $24,$24,0x3fffffff +or $24,$24,0x80000000 +sw $24,y +lw $24,i +sw $24,y+4 +la $4,L.10 +lw $24,y +srl $15,$24,30 +and $5,$15,3 +srl $24,$24,26 +and $6,$24,15 +lw $7,y+4 +jal printf +la $4,x +jal f2 +move $2,$0 +L.3: +lw $25,28($sp) +lw $31,32($sp) +addu $sp,$sp,48 +j $31 +.end main +.globl f1 +.text +.align 2 +.ent f1 +f1: +.frame $sp,32,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-32 +.mask 0xc2000000,-8 +.cprestore 16 +sw $30,20($sp) +sw $31,24($sp) +move $30,$4 +lw $24,($30) +and $24,$24,0xc3ffffff +sw $24,($30) +lw $24,($30) +and $24,$24,0x3fffffff +and $15,$0,3 +sll $15,$15,30 +and $15,$15,0xc0000000 +or $24,$24,$15 +sw $24,($30) +lw $24,($30) +and $24,$24,0x3c000000 +beq $24,$0,L.22 +la $4,L.24 +jal printf +L.22: +lw $24,($30) +or $24,$24,0xc0000000 +sw $24,($30) +lw $24,($30) +or $24,$24,0x3c000000 +sw $24,($30) +la $4,L.25 +lw $24,($30) +srl $15,$24,30 +and $5,$15,3 +srl $24,$24,26 +and $6,$24,15 +jal printf +move $2,$0 +L.21: +lw $25,16($sp) +lw $30,20($sp) +lw $31,24($sp) +addu $sp,$sp,32 +j $31 +.end f1 +.globl f2 +.text +.align 2 +.ent f2 +f2: +.frame $sp,32,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-32 +.mask 0xc2800000,-4 +sw $23,16($sp) +.cprestore 20 +sw $30,24($sp) +sw $31,28($sp) +move $30,$4 +lw $24,i +bne $24,$0,L.28 +la $23,1 +b L.29 +L.28: +move $23,$0 +L.29: +lw $24,($30) +and $24,$24,0x3fffffff +move $15,$23 +and $15,$15,3 +sll $15,$15,30 +and $15,$15,0xc0000000 +or $24,$24,$15 +sw $24,($30) +move $4,$30 +jal f1 +lw $24,($30) +and $24,$24,0xc3ffffff +move $15,$0 +and $15,$15,15 +sll $15,$15,26 +and $15,$15,0x3c000000 +or $24,$24,$15 +sw $24,($30) +move $2,$0 +L.26: +lw $23,16($sp) +lw $25,20($sp) +lw $30,24($sp) +lw $31,28($sp) +addu $sp,$sp,32 +j $31 +.end f2 +.rdata +.align 0 +L.25: +.byte 112 +.byte 45 +.byte 62 +.byte 97 +.byte 32 +.byte 61 +.byte 32 +.byte 48 +.byte 120 +.byte 37 +.byte 120 +.byte 44 +.byte 32 +.byte 112 +.byte 45 +.byte 62 +.byte 98 +.byte 32 +.byte 61 +.byte 32 +.byte 48 +.byte 120 +.byte 37 +.byte 120 +.byte 10 +.byte 0 +.align 0 +L.24: +.byte 112 +.byte 45 +.byte 62 +.byte 98 +.byte 32 +.byte 33 +.byte 61 +.byte 32 +.byte 48 +.byte 33 +.byte 10 +.byte 0 +.align 0 +L.10: +.byte 121 +.byte 32 +.byte 61 +.byte 32 +.byte 37 +.byte 100 +.byte 32 +.byte 37 +.byte 100 +.byte 32 +.byte 37 +.byte 100 +.byte 10 +.byte 0 +.align 0 +L.4: +.byte 120 +.byte 32 +.byte 61 +.byte 32 +.byte 37 +.byte 100 +.byte 32 +.byte 37 +.byte 100 +.byte 32 +.byte 37 +.byte 100 +.byte 32 +.byte 37 +.byte 100 +.byte 32 +.byte 37 +.byte 100 +.byte 32 +.byte 37 +.byte 100 +.byte 10 +.byte 0 diff --git a/src/cmd/lccom/tst/mips-eb/float.h b/src/cmd/lccom/tst/mips-eb/float.h new file mode 100644 index 0000000..a3e1eb5 --- /dev/null +++ b/src/cmd/lccom/tst/mips-eb/float.h @@ -0,0 +1,37 @@ +#ifndef __FLOAT +#define __FLOAT + +#define FLT_ROUNDS 1 +#define FLT_RADIX 2 + +#define FLT_DIG 6 +#define FLT_EPSILON 1.19209289550781250000e-07 +#define FLT_MANT_DIG 24 +#define FLT_MAX 3.40282346638528860000e+38 +#define FLT_MAX_10_EXP 38 +#define FLT_MAX_EXP 128 +#define FLT_MIN 1.17549435082228750000e-38 +#define FLT_MIN_10_EXP -37 +#define FLT_MIN_EXP -125 + +#define DBL_DIG 15 +#define DBL_EPSILON 2.22044604925031310000e-16 +#define DBL_MANT_DIG 53 +#define DBL_MAX 1.79769313486231570000e+308 +#define DBL_MAX_10_EXP 308 +#define DBL_MAX_EXP 1024 +#define DBL_MIN 2.22507385850720140000e-308 +#define DBL_MIN_10_EXP -307 +#define DBL_MIN_EXP -1021 + +#define LDBL_MANT_DIG DBL_MANT_DIG +#define LDBL_EPSILON DBL_EPSILON +#define LDBL_DIG DBL_DIG +#define LDBL_MIN_EXP DBL_MIN_EXP +#define LDBL_MIN DBL_MIN +#define LDBL_MIN_10_EXP DBL_MIN_10_EXP +#define LDBL_MAX_EXP DBL_MAX_EXP +#define LDBL_MAX DBL_MAX +#define LDBL_MAX_10_EXP DBL_MAX_10_EXP + +#endif /* __FLOAT */ diff --git a/src/cmd/lccom/tst/mips-eb/front.2bk b/src/cmd/lccom/tst/mips-eb/front.2bk new file mode 100644 index 0000000..bbd390a --- /dev/null +++ b/src/cmd/lccom/tst/mips-eb/front.2bk @@ -0,0 +1,29 @@ +tst/front.c:3: warning: missing return value +tst/front.c:10: warning: missing return value +tst/front.c:20: type error in argument 1 to `s'; found `pointer to struct D' expected `pointer to incomplete struct D defined at tst/front.c:14' +tst/front.c:21: warning: missing return value +tst/front.c:32: warning: missing return value +tst/front.c:36: operands of = have illegal types `pointer to int' and `pointer to const int' +tst/front.c:38: warning: missing return value +tst/front.c:62: operands of = have illegal types `pointer to char' and `pointer to const void' +tst/front.c:63: warning: missing return value +tst/front.c:68: warning: missing return value +tst/front.c:69: warning: inconsistent linkage for `yy' previously declared at tst/front.c:68 +tst/front.c:69: warning: missing return value +tst/front.c:71: invalid storage class `static' for `int function goo' +tst/front.c:71: warning: declaration of `goo' does not match previous declaration at tst/front.c:70 +tst/front.c:71: warning: missing return value +tst/front.c:74: warning: declaration of `xr' does not match previous declaration at tst/front.c:72 +tst/front.c:74: warning: missing return value +tst/front.c:81: warning: missing return value +tst/front.c:82: warning: declaration of `ss2' does not match previous declaration at tst/front.c:81 +tst/front.c:84: warning: inconsistent linkage for `ss5' previously declared at tst/front.c:80 +tst/front.c:92: type error in argument 1 to `gx1'; found `pointer to double' expected `double' +tst/front.c:92: warning: missing return value +tst/front.c:95: redeclaration of `hx1' previously declared at tst/front.c:94 +tst/front.c:98: warning: missing return value +tst/front.c:101: conflicting argument declarations for function `gg1' +tst/front.c:101: warning: missing return value +tst/front.c:112: type error in argument 4 to `qsort'; found `pointer to int function(pointer to pointer to char,pointer to pointer to char)' expected `pointer to int function(pointer to const void,pointer to const void)' +tst/front.c:113: warning: missing return value +tst/front.c:120: warning: missing return value diff --git a/src/cmd/lccom/tst/mips-eb/front.sbk b/src/cmd/lccom/tst/mips-eb/front.sbk new file mode 100644 index 0000000..039e875 --- /dev/null +++ b/src/cmd/lccom/tst/mips-eb/front.sbk @@ -0,0 +1,416 @@ +.set reorder +.globl main +.text +.text +.align 2 +.ent main +main: +.frame $sp,32,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-32 +.mask 0x82000000,-12 +.cprestore 16 +sw $31,20($sp) +move $4,$0 +jal exit +move $2,$0 +L.1: +lw $25,16($sp) +lw $31,20($sp) +addu $sp,$sp,32 +j $31 +.end main +.globl nested +.text +.align 2 +.ent nested +nested: +.frame $sp,0,$31 +.set noreorder +.cpload $25 +.set reorder +la $24,4 +bge $4,$24,L.6 +la $24,114 +beq $5,$24,L.9 +L.6: +la $24,1 +bne $4,$24,L.8 +la $24,104 +beq $5,$24,L.9 +la $24,105 +beq $5,$24,L.9 +L.8: +la $24,2 +bne $4,$24,L.3 +la $24,111 +beq $5,$24,L.9 +la $24,121 +bne $5,$24,L.3 +L.9: +move $4,$5 +L.3: +move $2,$0 +L.2: +j $31 +.end nested +.globl s +.text +.align 2 +.ent s +s: +.frame $sp,0,$31 +.set noreorder +.cpload $25 +.set reorder +L.10: +j $31 +.end s +.globl Dy +.sdata +.align 2 +Dy: +.word 0x0 +.space 4 +.globl Dz +.sdata +.align 2 +Dz: +.word 0x1 +.space 4 +.globl Dfunc +.text +.text +.align 2 +.ent Dfunc +Dfunc: +.frame $sp,32,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-32 +.mask 0x82000000,-12 +.cprestore 16 +sw $31,20($sp) +lw $25,16($sp) +lw $31,20($sp) +addu $sp,$sp,32 +j $31 +.end Dfunc +.globl f +.text +.align 2 +.ent f +f: +.frame $sp,0,$31 +.set noreorder +.cpload $25 +.set reorder +j $31 +.end f +.globl f1 +.text +.align 2 +.ent f1 +f1: +.frame $sp,0,$31 +.set noreorder +.cpload $25 +.set reorder +j $31 +.end f1 +.globl f2 +.text +.align 2 +.ent f2 +f2: +.frame $sp,32,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-32 +.mask 0x82000000,-12 +.cprestore 16 +sw $31,20($sp) +sw $4,32($sp) +sw $5,36($sp) +lw $25,16($sp) +lw $31,20($sp) +addu $sp,$sp,32 +j $31 +.end f2 +.globl g +.text +.align 2 +.ent g +g: +.frame $sp,32,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-32 +.mask 0x82000000,-12 +.cprestore 16 +sw $31,20($sp) +sw $4,32($sp) +lw $25,16($sp) +lw $31,20($sp) +addu $sp,$sp,32 +j $31 +.end g +.globl h +.text +.align 2 +.ent h +h: +.frame $sp,32,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-32 +.mask 0x82000000,-12 +.cprestore 16 +sw $31,20($sp) +sw $4,32($sp) +lw $25,16($sp) +lw $31,20($sp) +addu $sp,$sp,32 +j $31 +.end h +.globl h1 +.text +.align 2 +.ent h1 +h1: +.frame $sp,32,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-32 +.mask 0x82000000,-12 +.cprestore 16 +sw $31,20($sp) +sw $4,32($sp) +sw $5,36($sp) +lw $25,16($sp) +lw $31,20($sp) +addu $sp,$sp,32 +j $31 +.end h1 +.globl h2 +.text +.align 2 +.ent h2 +h2: +.frame $sp,0,$31 +.set noreorder +.cpload $25 +.set reorder +j $31 +.end h2 +.sdata +.align 2 +L.21: +.word 0x1 +.globl set1 +.text +.text +.align 2 +.ent set1 +set1: +.frame $sp,0,$31 +.set noreorder +.cpload $25 +.set reorder +j $31 +.end set1 +.sdata +.align 2 +L.23: +.word 0x2 +.globl set2 +.text +.text +.align 2 +.ent set2 +set2: +.frame $sp,0,$31 +.set noreorder +.cpload $25 +.set reorder +j $31 +.end set2 +.text +.align 2 +.ent goo +goo: +.frame $sp,0,$31 +.set noreorder +.cpload $25 +.set reorder +j $31 +.end goo +.globl sss +.text +.align 2 +.ent sss +sss: +.frame $sp,0,$31 +.set noreorder +.cpload $25 +.set reorder +j $31 +.end sss +.lcomm L.27,4 +.globl rrr +.text +.text +.align 2 +.ent rrr +rrr: +.frame $sp,0,$31 +.set noreorder +.cpload $25 +.set reorder +j $31 +.end rrr +.globl setstatic +.text +.align 2 +.ent setstatic +setstatic: +.frame $sp,0,$31 +.set noreorder +.cpload $25 +.set reorder +j $31 +.end setstatic +.globl gx1 +.text +.align 2 +.ent gx1 +gx1: +.frame $sp,32,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-32 +.mask 0x82000000,-12 +.cprestore 16 +sw $31,20($sp) +s.d $f12,32($sp) +lw $25,16($sp) +lw $31,20($sp) +addu $sp,$sp,32 +j $31 +.end gx1 +.globl ff1 +.text +.align 2 +.ent ff1 +ff1: +.frame $sp,0,$31 +.set noreorder +.cpload $25 +.set reorder +j $31 +.end ff1 +.globl gg1 +.text +.align 2 +.ent gg1 +gg1: +.frame $sp,0,$31 +.set noreorder +.cpload $25 +.set reorder +j $31 +.end gg1 +.globl hh1 +.text +.align 2 +.ent hh1 +hh1: +.frame $sp,0,$31 +.set noreorder +.cpload $25 +.set reorder +j $31 +.end hh1 +.globl cmp +.text +.align 2 +.ent cmp +cmp: +.frame $sp,32,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-32 +.mask 0x82000000,-12 +.cprestore 16 +sw $31,20($sp) +sw $4,32($sp) +sw $5,36($sp) +lw $25,16($sp) +lw $31,20($sp) +addu $sp,$sp,32 +j $31 +.end cmp +.globl sort +.text +.align 2 +.ent sort +sort: +.frame $sp,32,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-32 +.mask 0x82000000,-12 +.cprestore 16 +sw $31,20($sp) +lw $25,16($sp) +lw $31,20($sp) +addu $sp,$sp,32 +j $31 +.end sort +.globl onearg +.text +.align 2 +.ent onearg +onearg: +.frame $sp,32,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-32 +.mask 0x82000000,-12 +.cprestore 16 +sw $31,20($sp) +lw $25,16($sp) +lw $31,20($sp) +addu $sp,$sp,32 +j $31 +.end onearg +.extern xr 4 +.globl ss4 +.comm ss4,4 +.lcomm ss2,4 +.lcomm ss5,4 +.globl ss3 +.comm ss3,4 +.lcomm ss1,4 +.lcomm yy,4 +.globl z +.comm z,4 +.globl y +.comm y,4 +.globl x +.comm x,4 +.globl b +.comm b,4 +.globl a +.comm a,4 diff --git a/src/cmd/lccom/tst/mips-eb/incr.2bk b/src/cmd/lccom/tst/mips-eb/incr.2bk new file mode 100644 index 0000000..d9ef13c --- /dev/null +++ b/src/cmd/lccom/tst/mips-eb/incr.2bk @@ -0,0 +1,9 @@ +tst/incr.c:1: warning: missing return value +tst/incr.c:6: warning: expression with no effect elided +tst/incr.c:6: warning: expression with no effect elided +tst/incr.c:11: warning: missing return value +tst/incr.c:16: warning: expression with no effect elided +tst/incr.c:16: warning: expression with no effect elided +tst/incr.c:21: warning: missing return value +tst/incr.c:30: warning: missing return value +tst/incr.c:39: warning: missing return value diff --git a/src/cmd/lccom/tst/mips-eb/incr.sbk b/src/cmd/lccom/tst/mips-eb/incr.sbk new file mode 100644 index 0000000..b7200e9 --- /dev/null +++ b/src/cmd/lccom/tst/mips-eb/incr.sbk @@ -0,0 +1,149 @@ +.set reorder +.globl main +.text +.text +.align 2 +.ent main +main: +.frame $sp,0,$31 +.set noreorder +.cpload $25 +.set reorder +move $2,$0 +L.1: +j $31 +.end main +.globl memchar +.text +.align 2 +.ent memchar +memchar: +.frame $sp,16,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-16 +lw $24,-8+16($sp) +la $15,1($24) +sw $15,-8+16($sp) +lb $24,($24) +sb $24,-1+16($sp) +lw $24,-8+16($sp) +la $24,1($24) +sw $24,-8+16($sp) +lb $24,($24) +sb $24,-1+16($sp) +lw $24,-8+16($sp) +la $15,-1($24) +sw $15,-8+16($sp) +lb $24,($24) +sb $24,-1+16($sp) +lw $24,-8+16($sp) +la $24,-1($24) +sw $24,-8+16($sp) +lb $24,($24) +sb $24,-1+16($sp) +move $2,$0 +L.2: +addu $sp,$sp,16 +j $31 +.end memchar +.globl memint +.text +.align 2 +.ent memint +memint: +.frame $sp,16,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-16 +lw $24,-8+16($sp) +la $15,4($24) +sw $15,-8+16($sp) +lw $24,($24) +sw $24,-4+16($sp) +lw $24,-8+16($sp) +la $24,4($24) +sw $24,-8+16($sp) +lw $24,($24) +sw $24,-4+16($sp) +lw $24,-8+16($sp) +la $15,-4($24) +sw $15,-8+16($sp) +lw $24,($24) +sw $24,-4+16($sp) +lw $24,-8+16($sp) +la $24,-4($24) +sw $24,-8+16($sp) +lw $24,($24) +sw $24,-4+16($sp) +move $2,$0 +L.3: +addu $sp,$sp,16 +j $31 +.end memint +.globl regchar +.text +.align 2 +.ent regchar +regchar: +.frame $sp,16,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-16 +.mask 0x40800000,-12 +sw $23,0($sp) +sw $30,4($sp) +move $24,$23 +la $23,1($24) +lb $30,($24) +la $24,1($23) +move $23,$24 +lb $30,($24) +move $24,$23 +la $23,-1($24) +lb $30,($24) +la $24,-1($23) +move $23,$24 +lb $30,($24) +move $2,$0 +L.4: +lw $23,0($sp) +lw $30,4($sp) +addu $sp,$sp,16 +j $31 +.end regchar +.globl regint +.text +.align 2 +.ent regint +regint: +.frame $sp,16,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-16 +.mask 0x40800000,-12 +sw $23,0($sp) +sw $30,4($sp) +move $24,$23 +la $23,4($24) +lw $30,($24) +la $24,4($23) +move $23,$24 +lw $30,($24) +move $24,$23 +la $23,-4($24) +lw $30,($24) +la $24,-4($23) +move $23,$24 +lw $30,($24) +move $2,$0 +L.5: +lw $23,0($sp) +lw $30,4($sp) +addu $sp,$sp,16 +j $31 +.end regint diff --git a/src/cmd/lccom/tst/mips-eb/init.1bk b/src/cmd/lccom/tst/mips-eb/init.1bk new file mode 100644 index 0000000..77aff09 --- /dev/null +++ b/src/cmd/lccom/tst/mips-eb/init.1bk @@ -0,0 +1,16 @@ + 1 2 3 4 + 5 6 + 7 +if +for +else +while +1 2 3 if +4 5 0 for +6 7 8 else +9 10 11 while +1 2 3 if +4 5 0 for +6 7 8 else +9 10 11 while +0 0 0 diff --git a/src/cmd/lccom/tst/mips-eb/init.2bk b/src/cmd/lccom/tst/mips-eb/init.2bk new file mode 100644 index 0000000..aafe415 --- /dev/null +++ b/src/cmd/lccom/tst/mips-eb/init.2bk @@ -0,0 +1,3 @@ +tst/init.c:36: warning: missing return value +tst/init.c:49: warning: missing return value +tst/init.c:59: warning: missing return value diff --git a/src/cmd/lccom/tst/mips-eb/init.sbk b/src/cmd/lccom/tst/mips-eb/init.sbk new file mode 100644 index 0000000..128feb3 --- /dev/null +++ b/src/cmd/lccom/tst/mips-eb/init.sbk @@ -0,0 +1,325 @@ +.set reorder +.globl words +.data +.align 2 +words: +.word 0x1 +.word 0x2 +.word 0x3 +.byte 105 +.byte 102 +.byte 0 +.space 3 +.space 2 +.word 0x4 +.word 0x5 +.space 4 +.byte 102 +.byte 111 +.byte 114 +.space 3 +.space 2 +.word 0x6 +.word 0x7 +.word 0x8 +.byte 101 +.byte 108 +.byte 115 +.byte 101 +.byte 0 +.space 1 +.space 2 +.word 0x9 +.word 0xa +.word 0xb +.byte 119 +.byte 104 +.byte 105 +.byte 108 +.byte 101 +.space 1 +.space 2 +.word 0x0 +.space 8 +.space 8 +.globl wordlist +.sdata +.align 2 +wordlist: +.word words +.globl x +.data +.align 2 +x: +.word 0x1 +.word 0x2 +.word 0x3 +.word 0x4 +.word 0x0 +.word 0x5 +.word 0x6 +.space 12 +.word 0x7 +.space 16 +.globl y +.data +.align 2 +y: +.word x +.word x+20 +.word x+40 +.word 0x0 +.globl main +.text +.text +.align 2 +.ent main +main: +.frame $sp,32,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-32 +.mask 0xc2800000,-4 +sw $23,16($sp) +.cprestore 20 +sw $30,24($sp) +sw $31,28($sp) +move $23,$0 +b L.8 +L.5: +move $30,$0 +b L.12 +L.9: +la $4,L.13 +sll $24,$30,2 +sll $15,$23,2 +lw $15,y($15) +addu $24,$24,$15 +lw $5,($24) +jal printf +L.10: +la $30,1($30) +L.12: +sll $24,$30,2 +sll $15,$23,2 +lw $15,y($15) +addu $24,$24,$15 +lw $24,($24) +bne $24,$0,L.9 +la $4,L.14 +jal printf +L.6: +la $23,1($23) +L.8: +sll $24,$23,2 +lw $24,y($24) +bne $24,$0,L.5 +jal f +lw $4,wordlist +jal g +move $2,$0 +L.4: +lw $23,16($sp) +lw $25,20($sp) +lw $30,24($sp) +lw $31,28($sp) +addu $sp,$sp,32 +j $31 +.end main +.data +.align 2 +L.16: +.word L.17 +.word L.18 +.word L.19 +.word L.20 +.word 0x0 +.globl f +.text +.text +.align 2 +.ent f +f: +.frame $sp,32,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-32 +.mask 0xc2000000,-8 +.cprestore 16 +sw $30,20($sp) +sw $31,24($sp) +la $30,L.16 +b L.24 +L.21: +la $4,L.25 +lw $5,($30) +jal printf +L.22: +la $30,4($30) +L.24: +lw $24,($30) +bne $24,$0,L.21 +move $2,$0 +L.15: +lw $25,16($sp) +lw $30,20($sp) +lw $31,24($sp) +addu $sp,$sp,32 +j $31 +.end f +.globl g +.text +.align 2 +.ent g +g: +.frame $sp,32,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-32 +.mask 0xc2800000,-4 +sw $23,16($sp) +.cprestore 20 +sw $30,24($sp) +sw $31,28($sp) +move $30,$4 +b L.30 +L.27: +move $23,$0 +b L.34 +L.31: +la $4,L.35 +sll $24,$23,2 +addu $24,$24,$30 +lw $5,($24) +jal printf +L.32: +la $23,1($23) +L.34: +move $24,$23 +la $15,3 +bltu $24,$15,L.31 +la $4,L.25 +la $5,12($30) +jal printf +L.28: +la $30,20($30) +L.30: +lw $24,($30) +bne $24,$0,L.27 +jal h +move $2,$0 +L.26: +lw $23,16($sp) +lw $25,20($sp) +lw $30,24($sp) +lw $31,28($sp) +addu $sp,$sp,32 +j $31 +.end g +.globl h +.text +.align 2 +.ent h +h: +.frame $sp,32,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-32 +.mask 0xc2000000,-4 +.cprestore 20 +sw $30,24($sp) +sw $31,28($sp) +move $30,$0 +b L.40 +L.37: +la $4,L.41 +la $24,20 +mul $24,$24,$30 +lw $5,words($24) +lw $6,words+4($24) +lw $7,words+8($24) +la $24,words+12($24) +sw $24,16($sp) +jal printf +L.38: +la $30,1($30) +L.40: +move $24,$30 +la $15,5 +bltu $24,$15,L.37 +move $2,$0 +L.36: +lw $25,20($sp) +lw $30,24($sp) +lw $31,28($sp) +addu $sp,$sp,32 +j $31 +.end h +.rdata +.align 0 +L.41: +.byte 37 +.byte 100 +.byte 32 +.byte 37 +.byte 100 +.byte 32 +.byte 37 +.byte 100 +.byte 32 +.byte 37 +.byte 115 +.byte 10 +.byte 0 +.align 0 +L.35: +.byte 37 +.byte 100 +.byte 32 +.byte 0 +.align 0 +L.25: +.byte 37 +.byte 115 +.byte 10 +.byte 0 +.align 0 +L.20: +.byte 119 +.byte 104 +.byte 105 +.byte 108 +.byte 101 +.byte 0 +.align 0 +L.19: +.byte 101 +.byte 108 +.byte 115 +.byte 101 +.byte 0 +.align 0 +L.18: +.byte 102 +.byte 111 +.byte 114 +.byte 0 +.align 0 +L.17: +.byte 105 +.byte 102 +.byte 0 +.align 0 +L.14: +.byte 10 +.byte 0 +.align 0 +L.13: +.byte 32 +.byte 37 +.byte 100 +.byte 0 diff --git a/src/cmd/lccom/tst/mips-eb/limits.1bk b/src/cmd/lccom/tst/mips-eb/limits.1bk new file mode 100644 index 0000000..9beee8c --- /dev/null +++ b/src/cmd/lccom/tst/mips-eb/limits.1bk @@ -0,0 +1,14 @@ +UCHAR_MAX: 000000ff=255 +USHRT_MAX: 0000ffff=65535 +UINT_MAX: ffffffff=-1 +ULONG_MAX: ffffffff=-1 +CHAR_MAX: 0000007f=127 +SCHAR_MAX: 0000007f=127 +SHRT_MAX: 00007fff=32767 +INT_MAX: 7fffffff=2147483647 +LONG_MAX: 7fffffff=2147483647 +CHAR_MIN: ffffff80=-128 +SCHAR_MIN: ffffff80=-128 +SHRT_MIN: ffff8000=-32768 +INT_MIN: 80000000=-2147483648 +LONG_MIN: 80000000=-2147483648 diff --git a/src/cmd/lccom/tst/mips-eb/limits.2bk b/src/cmd/lccom/tst/mips-eb/limits.2bk new file mode 100644 index 0000000..e69de29 diff --git a/src/cmd/lccom/tst/mips-eb/limits.h b/src/cmd/lccom/tst/mips-eb/limits.h new file mode 100644 index 0000000..913bb97 --- /dev/null +++ b/src/cmd/lccom/tst/mips-eb/limits.h @@ -0,0 +1,30 @@ +#ifndef __LIMITS +#define __LIMITS + +#define CHAR_BIT 8 +#define MB_LEN_MAX 1 + +#define UCHAR_MAX 0xff +#define USHRT_MAX 0xffff +#define UINT_MAX (~0U) +#define ULONG_MAX (~0UL) + +#define SCHAR_MAX 0x7f +#define SHRT_MAX 0x7fff +#define INT_MAX 0x7fffffff +#define LONG_MAX 0x7fffffffL + +#define SCHAR_MIN (-SCHAR_MAX-1) +#define SHRT_MIN (-SHRT_MAX-1) +#define INT_MIN (-INT_MAX-1) +#define LONG_MIN (-LONG_MAX-1) + +#ifdef __CHAR_UNSIGNED__ +#define CHAR_MAX UCHAR_MAX +#define CHAR_MIN 0 +#else +#define CHAR_MAX SCHAR_MAX +#define CHAR_MIN SCHAR_MIN +#endif + +#endif /* __LIMITS */ diff --git a/src/cmd/lccom/tst/mips-eb/limits.sbk b/src/cmd/lccom/tst/mips-eb/limits.sbk new file mode 100644 index 0000000..e4f2673 --- /dev/null +++ b/src/cmd/lccom/tst/mips-eb/limits.sbk @@ -0,0 +1,396 @@ +.set reorder +.globl main +.text +.text +.align 2 +.ent main +main: +.frame $sp,32,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-32 +.mask 0x82000000,-12 +.cprestore 16 +sw $31,20($sp) +la $4,L.2 +la $24,255 +move $5,$24 +move $6,$24 +jal printf +la $4,L.3 +la $24,65535 +move $5,$24 +move $6,$24 +jal printf +la $4,L.4 +la $24,0xffffffff +move $5,$24 +move $6,$24 +jal printf +la $4,L.5 +la $24,0xffffffff +move $5,$24 +move $6,$24 +jal printf +la $4,L.6 +la $24,127 +move $5,$24 +move $6,$24 +jal printf +la $4,L.7 +la $24,127 +move $5,$24 +move $6,$24 +jal printf +la $4,L.8 +la $24,32767 +move $5,$24 +move $6,$24 +jal printf +la $4,L.9 +la $24,2147483647 +move $5,$24 +move $6,$24 +jal printf +la $4,L.10 +la $24,2147483647 +move $5,$24 +move $6,$24 +jal printf +la $4,L.11 +la $24,-128 +move $5,$24 +move $6,$24 +jal printf +la $4,L.12 +la $24,-128 +move $5,$24 +move $6,$24 +jal printf +la $4,L.13 +la $24,-32768 +move $5,$24 +move $6,$24 +jal printf +la $4,L.14 +la $24,-2147483648 +move $5,$24 +move $6,$24 +jal printf +la $4,L.15 +la $24,-2147483648 +move $5,$24 +move $6,$24 +jal printf +move $2,$0 +L.1: +lw $25,16($sp) +lw $31,20($sp) +addu $sp,$sp,32 +j $31 +.end main +.rdata +.align 0 +L.15: +.byte 76 +.byte 79 +.byte 78 +.byte 71 +.byte 95 +.byte 77 +.byte 73 +.byte 78 +.byte 58 +.byte 9 +.byte 37 +.byte 48 +.byte 56 +.byte 108 +.byte 120 +.byte 61 +.byte 37 +.byte 108 +.byte 100 +.byte 10 +.byte 0 +.align 0 +L.14: +.byte 73 +.byte 78 +.byte 84 +.byte 95 +.byte 77 +.byte 73 +.byte 78 +.byte 58 +.byte 9 +.byte 37 +.byte 48 +.byte 56 +.byte 120 +.byte 61 +.byte 37 +.byte 100 +.byte 10 +.byte 0 +.align 0 +L.13: +.byte 83 +.byte 72 +.byte 82 +.byte 84 +.byte 95 +.byte 77 +.byte 73 +.byte 78 +.byte 58 +.byte 9 +.byte 37 +.byte 48 +.byte 56 +.byte 120 +.byte 61 +.byte 37 +.byte 100 +.byte 10 +.byte 0 +.align 0 +L.12: +.byte 83 +.byte 67 +.byte 72 +.byte 65 +.byte 82 +.byte 95 +.byte 77 +.byte 73 +.byte 78 +.byte 58 +.byte 9 +.byte 37 +.byte 48 +.byte 56 +.byte 120 +.byte 61 +.byte 37 +.byte 100 +.byte 10 +.byte 0 +.align 0 +L.11: +.byte 67 +.byte 72 +.byte 65 +.byte 82 +.byte 95 +.byte 77 +.byte 73 +.byte 78 +.byte 58 +.byte 9 +.byte 37 +.byte 48 +.byte 56 +.byte 120 +.byte 61 +.byte 37 +.byte 100 +.byte 10 +.byte 0 +.align 0 +L.10: +.byte 76 +.byte 79 +.byte 78 +.byte 71 +.byte 95 +.byte 77 +.byte 65 +.byte 88 +.byte 58 +.byte 9 +.byte 37 +.byte 48 +.byte 56 +.byte 108 +.byte 120 +.byte 61 +.byte 37 +.byte 108 +.byte 100 +.byte 10 +.byte 0 +.align 0 +L.9: +.byte 73 +.byte 78 +.byte 84 +.byte 95 +.byte 77 +.byte 65 +.byte 88 +.byte 58 +.byte 9 +.byte 37 +.byte 48 +.byte 56 +.byte 120 +.byte 61 +.byte 37 +.byte 100 +.byte 10 +.byte 0 +.align 0 +L.8: +.byte 83 +.byte 72 +.byte 82 +.byte 84 +.byte 95 +.byte 77 +.byte 65 +.byte 88 +.byte 58 +.byte 9 +.byte 37 +.byte 48 +.byte 56 +.byte 120 +.byte 61 +.byte 37 +.byte 100 +.byte 10 +.byte 0 +.align 0 +L.7: +.byte 83 +.byte 67 +.byte 72 +.byte 65 +.byte 82 +.byte 95 +.byte 77 +.byte 65 +.byte 88 +.byte 58 +.byte 9 +.byte 37 +.byte 48 +.byte 56 +.byte 120 +.byte 61 +.byte 37 +.byte 100 +.byte 10 +.byte 0 +.align 0 +L.6: +.byte 67 +.byte 72 +.byte 65 +.byte 82 +.byte 95 +.byte 77 +.byte 65 +.byte 88 +.byte 58 +.byte 9 +.byte 37 +.byte 48 +.byte 56 +.byte 120 +.byte 61 +.byte 37 +.byte 100 +.byte 10 +.byte 0 +.align 0 +L.5: +.byte 85 +.byte 76 +.byte 79 +.byte 78 +.byte 71 +.byte 95 +.byte 77 +.byte 65 +.byte 88 +.byte 58 +.byte 9 +.byte 37 +.byte 48 +.byte 56 +.byte 108 +.byte 120 +.byte 61 +.byte 37 +.byte 108 +.byte 100 +.byte 10 +.byte 0 +.align 0 +L.4: +.byte 85 +.byte 73 +.byte 78 +.byte 84 +.byte 95 +.byte 77 +.byte 65 +.byte 88 +.byte 58 +.byte 9 +.byte 37 +.byte 48 +.byte 56 +.byte 120 +.byte 61 +.byte 37 +.byte 100 +.byte 10 +.byte 0 +.align 0 +L.3: +.byte 85 +.byte 83 +.byte 72 +.byte 82 +.byte 84 +.byte 95 +.byte 77 +.byte 65 +.byte 88 +.byte 58 +.byte 9 +.byte 37 +.byte 48 +.byte 56 +.byte 120 +.byte 61 +.byte 37 +.byte 100 +.byte 10 +.byte 0 +.align 0 +L.2: +.byte 85 +.byte 67 +.byte 72 +.byte 65 +.byte 82 +.byte 95 +.byte 77 +.byte 65 +.byte 88 +.byte 58 +.byte 9 +.byte 37 +.byte 48 +.byte 56 +.byte 120 +.byte 61 +.byte 37 +.byte 100 +.byte 10 +.byte 0 diff --git a/src/cmd/lccom/tst/mips-eb/locale.h b/src/cmd/lccom/tst/mips-eb/locale.h new file mode 100644 index 0000000..8a96636 --- /dev/null +++ b/src/cmd/lccom/tst/mips-eb/locale.h @@ -0,0 +1,38 @@ +#ifndef __LOCALE +#define __LOCALE + +#define LC_ALL 0 +#define LC_COLLATE 1 +#define LC_CTYPE 2 +#define LC_MONETARY 3 +#define LC_NUMERIC 4 +#define LC_TIME 5 +#ifndef NULL +#define NULL ((void*)0) +#endif + +struct lconv { + char *decimal_point; + char *thousands_sep; + char *grouping; + char *int_curr_symbol; + char *currency_symbol; + char *mon_decimal_point; + char *mon_thousands_sep; + char *mon_grouping; + char *positive_sign; + char *negative_sign; + char int_frac_digits; + char frac_digits; + char p_cs_precedes; + char p_sep_by_space; + char n_cs_precedes; + char n_sep_by_space; + char p_sign_posn; + char n_sign_posn; +}; + +char *setlocale(int, const char *); +struct lconv *localeconv(void); + +#endif /* __LOCALE */ diff --git a/src/cmd/lccom/tst/mips-eb/math.h b/src/cmd/lccom/tst/mips-eb/math.h new file mode 100644 index 0000000..d2a31f4 --- /dev/null +++ b/src/cmd/lccom/tst/mips-eb/math.h @@ -0,0 +1,29 @@ +#ifndef __MATH +#define __MATH + +#define HUGE_VAL 1.79769313486231570000e+308 + +extern double acos(double); +extern double asin(double); +extern double atan(double); +extern double atan2(double, double); +extern double cos(double); +extern double sin(double); +extern double tan(double); +extern double cosh(double); +extern double sinh(double); +extern double tanh(double); +extern double exp(double); +extern double frexp(double, int *); +extern double ldexp(double, int); +extern double log(double); +extern double log10(double); +extern double modf(double, double *); +extern double pow(double, double); +extern double sqrt(double); +extern double ceil(double); +extern double fabs(double); +extern double floor(double); +extern double fmod(double, double); + +#endif /* __MATH */ diff --git a/src/cmd/lccom/tst/mips-eb/paranoia.1bk b/src/cmd/lccom/tst/mips-eb/paranoia.1bk new file mode 100644 index 0000000..158f649 --- /dev/null +++ b/src/cmd/lccom/tst/mips-eb/paranoia.1bk @@ -0,0 +1,178 @@ +Lest this program stop prematurely, i.e. before displaying + + `END OF TEST', + +try to persuade the computer NOT to terminate execution when an +error like Over/Underflow or Division by Zero occurs, but rather +to persevere with a surrogate value after, perhaps, displaying some +warning. If persuasion avails naught, don't despair but run this +program anyway to see how many milestones it passes, and then +amend it to make further progress. + +Answer questions with Y, y, N or n (unless otherwise indicated). + + +Diagnosis resumes after milestone Number 0 Page: 1 + +Users are invited to help debug and augment this program so it will +cope with unanticipated and newly uncovered arithmetic pathologies. + +Please send suggestions and interesting results to + Richard Karpinski + Computer Center U-76 + University of California + San Francisco, CA 94143-0704, USA + +In doing so, please include the following information: + Precision: double; + Version: 10 February 1989; + Computer: + + Compiler: + + Optimization level: + + Other relevant compiler options: + +Diagnosis resumes after milestone Number 1 Page: 2 + +Running this program should reveal these characteristics: + Radix = 1, 2, 4, 8, 10, 16, 100, 256 ... + Precision = number of significant digits carried. + U2 = Radix/Radix^Precision = One Ulp + (OneUlpnit in the Last Place) of 1.000xxx . + U1 = 1/Radix^Precision = One Ulp of numbers a little less than 1.0 . + Adequacy of guard digits for Mult., Div. and Subt. + Whether arithmetic is chopped, correctly rounded, or something else + for Mult., Div., Add/Subt. and Sqrt. + Whether a Sticky Bit used correctly for rounding. + UnderflowThreshold = an underflow threshold. + E0 and PseudoZero tell whether underflow is abrupt, gradual, or fuzzy. + V = an overflow threshold, roughly. + V0 tells, roughly, whether Infinity is represented. + Comparisions are checked for consistency with subtraction + and for contamination with pseudo-zeros. + Sqrt is tested. Y^X is not tested. + Extra-precise subexpressions are revealed but NOT YET tested. + Decimal-Binary conversion is NOT YET tested for accuracy. + +Diagnosis resumes after milestone Number 2 Page: 3 + +The program attempts to discriminate among + FLAWs, like lack of a sticky bit, + Serious DEFECTs, like lack of a guard digit, and + FAILUREs, like 2+2 == 5 . +Failures may confound subsequent diagnoses. + +The diagnostic capabilities of this program go beyond an earlier +program called `MACHAR', which can be found at the end of the +book `Software Manual for the Elementary Functions' (1980) by +W. J. Cody and W. Waite. Although both programs try to discover +the Radix, Precision and range (over/underflow thresholds) +of the arithmetic, this program tries to cope with a wider variety +of pathologies, and to say how well the arithmetic is implemented. + +The program is based upon a conventional radix representation for +floating-point numbers, but also allows logarithmic encoding +as used by certain early WANG machines. + +BASIC version of this program (C) 1983 by Prof. W. M. Kahan; +see source comments for more history. + +Diagnosis resumes after milestone Number 3 Page: 4 + +Program is now RUNNING tests on small integers: +-1, 0, 1/2, 1, 2, 3, 4, 5, 9, 27, 32 & 240 are O.K. + +Searching for Radix and Precision. +Radix = 2.000000 . +Closest relative separation found is U1 = 1.1102230e-16 . + +Recalculating radix and precision + confirms closest relative separation U1 . +Radix confirmed. +The number of significant digits of the Radix is 53.000000 . + +Diagnosis resumes after milestone Number 30 Page: 5 + +Subtraction appears to be normalized, as it should be. +Checking for guard digit in *, /, and -. + *, /, and - appear to have guard digits, as they should. + +Diagnosis resumes after milestone Number 40 Page: 6 + +Checking rounding on multiply, divide and add/subtract. +Multiplication appears to round correctly. +Division appears to round correctly. +Addition/Subtraction appears to round correctly. +Checking for sticky bit. +Sticky bit apparently used correctly. + +Does Multiplication commute? Testing on 20 random pairs. + No failures found in 20 integer pairs. + +Running test of square root(x). +Testing if sqrt(X * X) == X for 20 Integers X. +Test for sqrt monotonicity. +sqrt has passed a test for Monotonicity. +Testing whether sqrt is rounded or chopped. +Square root appears to be correctly rounded. + +Diagnosis resumes after milestone Number 90 Page: 7 + +Testing powers Z^i for small Integers Z and i. +... no discrepancis found. + +Seeking Underflow thresholds UfThold and E0. +Smallest strictly positive number found is E0 = 4.94066e-324 . +Since comparison denies Z = 0, evaluating (Z + Z) / Z should be safe. +What the machine gets for (Z + Z) / Z is 2.00000000000000000e+00 . +This is O.K., provided Over/Underflow has NOT just been signaled. +Underflow is gradual; it incurs Absolute Error = +(roundoff in UfThold) < E0. +The Underflow threshold is 2.22507385850720190e-308, below which +calculation may suffer larger Relative error than merely roundoff. +Since underflow occurs below the threshold +UfThold = (2.00000000000000000e+00) ^ (-1.02200000000000000e+03) +only underflow should afflict the expression + (2.00000000000000000e+00) ^ (-1.02200000000000000e+03); +actually calculating yields: 0.00000000000000000e+00 . +This computed value is O.K. + +Testing X^((X + 1) / (X - 1)) vs. exp(2) = 7.38905609893065220e+00 as X -> 1. +Accuracy seems adequate. +Testing powers Z^Q at four nearly extreme values. + ... no discrepancies found. + + +Diagnosis resumes after milestone Number 160 Page: 8 + +Searching for Overflow threshold: +This may generate an error. +Can `Z = -Y' overflow? +Trying it on Y = -inf . +Seems O.K. +Overflow threshold is V = 1.79769313486231570e+308 . +Overflow saturates at V0 = inf . +No Overflow should be signaled for V * 1 = 1.79769313486231570e+308 + nor for V / 1 = 1.79769313486231570e+308 . +Any overflow signal separating this * from the one +above is a DEFECT. + + +Diagnosis resumes after milestone Number 190 Page: 9 + + +What message and/or values does Division by Zero produce? + Trying to compute 1 / 0 produces ... inf . + + Trying to compute 0 / 0 produces ... nan . + +Diagnosis resumes after milestone Number 220 Page: 10 + + + +No failures, defects nor flaws have been discovered. +Rounding appears to conform to the proposed IEEE standard P754. +The arithmetic diagnosed appears to be Excellent! +END OF TEST. diff --git a/src/cmd/lccom/tst/mips-eb/paranoia.2bk b/src/cmd/lccom/tst/mips-eb/paranoia.2bk new file mode 100644 index 0000000..2718174 --- /dev/null +++ b/src/cmd/lccom/tst/mips-eb/paranoia.2bk @@ -0,0 +1,16 @@ +tst/paranoia.c:1867: warning: missing return value +tst/paranoia.c:1874: warning: missing return value +tst/paranoia.c:1884: warning: missing return value +tst/paranoia.c:1924: warning: missing return value +tst/paranoia.c:1939: warning: missing return value +tst/paranoia.c:1956: warning: missing return value +tst/paranoia.c:1975: warning: missing return value +tst/paranoia.c:1988: warning: missing return value +tst/paranoia.c:1995: warning: missing return value +tst/paranoia.c:2055: warning: missing return value +tst/paranoia.c:2062: warning: missing return value +tst/paranoia.c:2070: warning: missing return value +tst/paranoia.c:2087: warning: missing return value +tst/paranoia.c:2115: warning: missing return value +tst/paranoia.c:2144: warning: missing return value +tst/paranoia.c:2173: warning: missing return value diff --git a/src/cmd/lccom/tst/mips-eb/paranoia.sbk b/src/cmd/lccom/tst/mips-eb/paranoia.sbk new file mode 100644 index 0000000..4dd8660 --- /dev/null +++ b/src/cmd/lccom/tst/mips-eb/paranoia.sbk @@ -0,0 +1,18657 @@ +.set reorder +.globl Zero +.sdata +.align 3 +Zero: +.word 0x0 +.word 0x0 +.globl Half +.sdata +.align 3 +Half: +.word 0x3fe00000 +.word 0x0 +.globl One +.sdata +.align 3 +One: +.word 0x3ff00000 +.word 0x0 +.globl Two +.sdata +.align 3 +Two: +.word 0x40000000 +.word 0x0 +.globl Three +.sdata +.align 3 +Three: +.word 0x40080000 +.word 0x0 +.globl Four +.sdata +.align 3 +Four: +.word 0x40100000 +.word 0x0 +.globl Five +.sdata +.align 3 +Five: +.word 0x40140000 +.word 0x0 +.globl Eight +.sdata +.align 3 +Eight: +.word 0x40200000 +.word 0x0 +.globl Nine +.sdata +.align 3 +Nine: +.word 0x40220000 +.word 0x0 +.globl TwentySeven +.sdata +.align 3 +TwentySeven: +.word 0x403b0000 +.word 0x0 +.globl ThirtyTwo +.sdata +.align 3 +ThirtyTwo: +.word 0x40400000 +.word 0x0 +.globl TwoForty +.sdata +.align 3 +TwoForty: +.word 0x406e0000 +.word 0x0 +.globl MinusOne +.sdata +.align 3 +MinusOne: +.word 0xbff00000 +.word 0x0 +.globl OneAndHalf +.sdata +.align 3 +OneAndHalf: +.word 0x3ff80000 +.word 0x0 +.globl NoTrials +.sdata +.align 2 +NoTrials: +.word 0x14 +.globl sigfpe +.text +.text +.align 2 +.ent sigfpe +sigfpe: +.frame $sp,32,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-32 +.mask 0x82000000,-12 +.cprestore 16 +sw $31,20($sp) +sw $4,32($sp) +lw $24,fpecount +la $24,1($24) +sw $24,fpecount +la $4,L.2 +jal printf +la $4,_iob+16 +jal fflush +lw $24,sigsave +beq $24,$0,L.4 +la $4,8 +lw $5,sigsave +jal signal +sw $0,sigsave +la $4,ovfl_buf +la $5,1 +jal longjmp +L.4: +jal abort +L.1: +lw $25,16($sp) +lw $31,20($sp) +addu $sp,$sp,32 +j $31 +.end sigfpe +.data +.align 2 +L.757: +.word L.758 +.word L.759 +.word L.760 +.word L.761 +.globl main +.text +.text +.align 2 +.ent main +main: +.frame $sp,240,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-240 +.mask 0xc2ff0000,-168 +sw $16,32($sp) +sw $17,36($sp) +sw $18,40($sp) +sw $19,44($sp) +sw $20,48($sp) +sw $21,52($sp) +sw $22,56($sp) +sw $23,60($sp) +.cprestore 64 +sw $30,68($sp) +sw $31,72($sp) +l.d $f18,L.7 +s.d $f18,Zero +l.d $f18,L.8 +s.d $f18,One +l.d $f18,One +add.d $f16,$f18,$f18 +s.d $f16,Two +l.d $f16,Two +add.d $f10,$f16,$f18 +s.d $f10,Three +l.d $f10,Three +add.d $f8,$f10,$f18 +s.d $f8,Four +l.d $f8,Four +add.d $f6,$f8,$f18 +s.d $f6,Five +add.d $f6,$f8,$f8 +s.d $f6,Eight +mul.d $f6,$f10,$f10 +s.d $f6,Nine +l.d $f6,Nine +mul.d $f6,$f6,$f10 +s.d $f6,TwentySeven +l.d $f6,Eight +mul.d $f6,$f8,$f6 +s.d $f6,ThirtyTwo +l.d $f6,Five +mul.d $f6,$f8,$f6 +mul.d $f10,$f6,$f10 +mul.d $f10,$f10,$f8 +s.d $f10,TwoForty +neg.d $f10,$f18 +s.d $f10,MinusOne +div.d $f16,$f18,$f16 +s.d $f16,Half +l.d $f16,Half +add.d $f18,$f18,$f16 +s.d $f18,OneAndHalf +sw $0,ErrCnt +sw $0,ErrCnt+4 +sw $0,ErrCnt+8 +sw $0,ErrCnt+12 +la $24,1 +sw $24,PageNo +sw $0,Milestone +la $4,8 +la $5,sigfpe +jal signal +jal Instructions +jal Pause +jal Heading +jal Pause +jal Characteristics +jal Pause +jal History +jal Pause +la $24,7 +sw $24,Milestone +la $4,L.12 +jal printf +move $4,$0 +l.d $f18,Zero +add.d $f16,$f18,$f18 +c.eq.d $f16,$f18; bc1f L.15 +l.d $f16,One +sub.d $f10,$f16,$f16 +c.eq.d $f10,$f18; bc1f L.15 +c.ule.d $f16,$f18; bc1t L.15 +add.d $f18,$f16,$f16 +l.d $f16,Two +c.eq.d $f18,$f16; bc1f L.15 +la $30,1 +b L.16 +L.15: +move $30,$0 +L.16: +move $5,$30 +la $6,L.14 +jal TstCond +l.d $f18,Zero +neg.d $f18,$f18 +s.d $f18,Z +l.d $f18,Z +l.d $f16,L.7 +c.eq.d $f18,$f16; bc1t L.17 +lw $24,ErrCnt +la $24,1($24) +sw $24,ErrCnt +la $4,L.19 +jal printf +l.d $f18,L.20 +s.d $f18,U1 +l.d $f18,L.8 +s.d $f18,Radix +jal TstPtUf +L.17: +move $4,$0 +l.d $f18,Three +l.d $f16,Two +l.d $f10,One +add.d $f8,$f16,$f10 +c.eq.d $f18,$f8; bc1f L.23 +l.d $f8,Four +add.d $f6,$f18,$f10 +c.eq.d $f8,$f6; bc1f L.23 +l.d $f6,Zero +neg.d $f4,$f16 +mul.d $f16,$f16,$f4 +add.d $f16,$f8,$f16 +c.eq.d $f16,$f6; bc1f L.23 +sub.d $f18,$f8,$f18 +sub.d $f18,$f18,$f10 +c.eq.d $f18,$f6; bc1f L.23 +la $23,1 +b L.24 +L.23: +move $23,$0 +L.24: +move $5,$23 +la $6,L.22 +jal TstCond +l.d $f18,MinusOne +s.d $f18,-8+240($sp) +l.d $f16,One +l.d $f10,L.7 +sub.d $f10,$f10,$f16 +c.eq.d $f18,$f10; bc1f L.27 +l.d $f10,Zero +add.d $f8,$f18,$f16 +c.eq.d $f8,$f10; bc1f L.27 +add.d $f8,$f16,$f18 +c.eq.d $f8,$f10; bc1f L.27 +mov.d $f12,$f16 +jal fabs +l.d $f16,Zero +l.d $f10,-8+240($sp) +add.d $f18,$f10,$f0 +c.eq.d $f18,$f16; bc1f L.27 +l.d $f18,MinusOne +mul.d $f10,$f18,$f18 +add.d $f18,$f18,$f10 +c.eq.d $f18,$f16; bc1f L.27 +la $22,1 +b L.28 +L.27: +move $22,$0 +L.28: +move $4,$0 +move $5,$22 +la $6,L.26 +jal TstCond +move $4,$0 +l.d $f18,Half +l.d $f16,MinusOne +add.d $f16,$f18,$f16 +add.d $f18,$f16,$f18 +l.d $f16,Zero +c.eq.d $f18,$f16; bc1f L.31 +la $21,1 +b L.32 +L.31: +move $21,$0 +L.32: +move $5,$21 +la $6,L.30 +jal TstCond +la $24,10 +sw $24,Milestone +move $4,$0 +l.d $f18,Nine +l.d $f16,Three +mul.d $f10,$f16,$f16 +c.eq.d $f18,$f10; bc1f L.35 +l.d $f10,TwentySeven +mul.d $f18,$f18,$f16 +c.eq.d $f10,$f18; bc1f L.35 +l.d $f18,Eight +l.d $f16,Four +add.d $f8,$f16,$f16 +c.eq.d $f18,$f8; bc1f L.35 +l.d $f8,ThirtyTwo +mul.d $f18,$f18,$f16 +c.eq.d $f8,$f18; bc1f L.35 +sub.d $f18,$f8,$f10 +sub.d $f18,$f18,$f16 +l.d $f16,One +sub.d $f18,$f18,$f16 +l.d $f16,Zero +c.eq.d $f18,$f16; bc1f L.35 +la $20,1 +b L.36 +L.35: +move $20,$0 +L.36: +move $5,$20 +la $6,L.34 +jal TstCond +move $4,$0 +l.d $f18,Five +l.d $f16,Four +l.d $f10,One +add.d $f10,$f16,$f10 +c.eq.d $f18,$f10; bc1f L.39 +l.d $f10,TwoForty +l.d $f8,Three +s.d $f8,-16+240($sp) +mul.d $f6,$f16,$f18 +mul.d $f6,$f6,$f8 +mul.d $f6,$f6,$f16 +c.eq.d $f10,$f6; bc1f L.39 +l.d $f6,Zero +div.d $f4,$f10,$f8 +mul.d $f8,$f16,$f16 +mul.d $f8,$f8,$f18 +sub.d $f8,$f4,$f8 +c.eq.d $f8,$f6; bc1f L.39 +div.d $f8,$f10,$f16 +l.d $f4,-16+240($sp) +mul.d $f4,$f18,$f4 +mul.d $f4,$f4,$f16 +sub.d $f8,$f8,$f4 +c.eq.d $f8,$f6; bc1f L.39 +div.d $f18,$f10,$f18 +l.d $f10,-16+240($sp) +mul.d $f10,$f16,$f10 +mul.d $f16,$f10,$f16 +sub.d $f18,$f18,$f16 +c.eq.d $f18,$f6; bc1f L.39 +la $19,1 +b L.40 +L.39: +move $19,$0 +L.40: +move $5,$19 +la $6,L.38 +jal TstCond +lw $24,ErrCnt +bne $24,$0,L.41 +la $4,L.43 +jal printf +la $4,L.44 +jal printf +L.41: +la $4,L.45 +jal printf +l.d $f18,One +s.d $f18,W +L.46: +l.d $f18,W +add.d $f18,$f18,$f18 +s.d $f18,W +l.d $f18,W +l.d $f16,One +add.d $f10,$f18,$f16 +s.d $f10,Y +l.d $f10,Y +sub.d $f18,$f10,$f18 +s.d $f18,Z +l.d $f18,Z +sub.d $f18,$f18,$f16 +s.d $f18,Y +L.47: +l.d $f12,Y +jal fabs +l.d $f16,MinusOne +add.d $f18,$f16,$f0 +l.d $f16,Zero +c.ult.d $f18,$f16; bc1t L.46 +l.d $f18,Zero +s.d $f18,Precision +l.d $f18,One +s.d $f18,Y +L.49: +l.d $f18,W +l.d $f16,Y +add.d $f10,$f18,$f16 +s.d $f10,Radix +add.d $f16,$f16,$f16 +s.d $f16,Y +l.d $f16,Radix +sub.d $f18,$f16,$f18 +s.d $f18,Radix +L.50: +l.d $f18,Radix +l.d $f16,Zero +c.eq.d $f18,$f16; bc1t L.49 +l.d $f18,Radix +l.d $f16,Two +c.lt.d $f18,$f16; bc1f L.52 +l.d $f18,One +s.d $f18,Radix +L.52: +la $4,L.54 +l.d $f18,Radix +mfc1.d $6,$f18 +jal printf +l.d $f18,Radix +l.d $f16,L.8 +c.eq.d $f18,$f16; bc1t L.55 +l.d $f18,One +s.d $f18,W +L.57: +l.d $f18,One +l.d $f16,Precision +add.d $f16,$f16,$f18 +s.d $f16,Precision +l.d $f16,W +l.d $f10,Radix +mul.d $f16,$f16,$f10 +s.d $f16,W +l.d $f16,W +add.d $f18,$f16,$f18 +s.d $f18,Y +L.58: +l.d $f18,Y +l.d $f16,W +sub.d $f18,$f18,$f16 +l.d $f16,One +c.eq.d $f18,$f16; bc1t L.57 +L.55: +l.d $f18,One +l.d $f16,W +div.d $f18,$f18,$f16 +s.d $f18,U1 +l.d $f18,U1 +l.d $f16,Radix +mul.d $f16,$f16,$f18 +s.d $f16,U2 +la $4,L.60 +mfc1.d $6,$f18 +jal printf +la $4,L.61 +jal printf +l.d $f18,Radix +s.d $f18,E0 +l.d $f18,U1 +s.d $f18,E1 +l.d $f18,U2 +s.d $f18,E9 +l.d $f18,Precision +s.d $f18,E3 +l.d $f18,Four +l.d $f16,Three +div.d $f18,$f18,$f16 +s.d $f18,X +l.d $f18,X +l.d $f16,One +sub.d $f18,$f18,$f16 +s.d $f18,Third +l.d $f18,Third +l.d $f16,Half +sub.d $f16,$f16,$f18 +s.d $f16,F6 +l.d $f16,F6 +add.d $f16,$f16,$f16 +s.d $f16,X +l.d $f16,X +sub.d $f12,$f16,$f18 +jal fabs +s.d $f0,X +l.d $f18,X +l.d $f16,U2 +c.lt.d $f18,$f16; bc1f L.62 +l.d $f18,U2 +s.d $f18,X +L.62: +L.64: +l.d $f18,X +s.d $f18,U2 +l.d $f18,U2 +l.d $f16,Half +mul.d $f16,$f16,$f18 +l.d $f10,ThirtyTwo +mul.d $f10,$f10,$f18 +mul.d $f18,$f10,$f18 +add.d $f18,$f16,$f18 +s.d $f18,Y +l.d $f18,One +l.d $f16,Y +add.d $f16,$f18,$f16 +s.d $f16,Y +l.d $f16,Y +sub.d $f18,$f16,$f18 +s.d $f18,X +L.65: +l.d $f18,X +l.d $f16,U2 +c.ule.d $f16,$f18; bc1t L.67 +l.d $f16,Zero +c.le.d $f18,$f16; bc1f L.64 +L.67: +l.d $f18,Two +l.d $f16,Three +div.d $f18,$f18,$f16 +s.d $f18,X +l.d $f18,Half +l.d $f16,X +sub.d $f16,$f16,$f18 +s.d $f16,F6 +l.d $f16,F6 +add.d $f10,$f16,$f16 +s.d $f10,Third +l.d $f10,Third +sub.d $f18,$f10,$f18 +s.d $f18,X +l.d $f18,X +add.d $f12,$f18,$f16 +jal fabs +s.d $f0,X +l.d $f18,X +l.d $f16,U1 +c.lt.d $f18,$f16; bc1f L.68 +l.d $f18,U1 +s.d $f18,X +L.68: +L.70: +l.d $f18,X +s.d $f18,U1 +l.d $f18,Half +l.d $f16,U1 +mul.d $f10,$f18,$f16 +l.d $f8,ThirtyTwo +mul.d $f8,$f8,$f16 +mul.d $f16,$f8,$f16 +add.d $f16,$f10,$f16 +s.d $f16,Y +l.d $f16,Y +sub.d $f16,$f18,$f16 +s.d $f16,Y +l.d $f16,Y +add.d $f16,$f18,$f16 +s.d $f16,X +l.d $f16,X +sub.d $f16,$f18,$f16 +s.d $f16,Y +l.d $f16,Y +add.d $f18,$f18,$f16 +s.d $f18,X +L.71: +l.d $f18,X +l.d $f16,U1 +c.ule.d $f16,$f18; bc1t L.73 +l.d $f16,Zero +c.le.d $f18,$f16; bc1f L.70 +L.73: +l.d $f18,U1 +l.d $f16,E1 +c.eq.d $f18,$f16; bc1f L.74 +la $4,L.76 +jal printf +b L.75 +L.74: +la $4,L.77 +l.d $f18,U1 +mfc1.d $6,$f18 +jal printf +L.75: +l.d $f18,U1 +l.d $f16,One +div.d $f16,$f16,$f18 +s.d $f16,W +l.d $f16,Half +sub.d $f10,$f16,$f18 +add.d $f16,$f10,$f16 +s.d $f16,F9 +l.d $f16,U2 +div.d $f18,$f16,$f18 +l.d $f16,L.78 +add.d $f12,$f18,$f16 +jal floor +s.d $f0,Radix +l.d $f18,Radix +l.d $f16,E0 +c.eq.d $f18,$f16; bc1f L.79 +la $4,L.81 +jal printf +b L.80 +L.79: +la $4,L.82 +l.d $f18,Radix +mfc1.d $6,$f18 +jal printf +L.80: +la $4,2 +l.d $f18,Eight +l.d $f16,Radix +add.d $f18,$f18,$f18 +c.le.d $f16,$f18; bc1f L.85 +la $18,1 +b L.86 +L.85: +move $18,$0 +L.86: +move $5,$18 +la $6,L.84 +jal TstCond +la $4,3 +l.d $f18,Radix +l.d $f16,Two +c.eq.d $f18,$f16; bc1t L.92 +l.d $f16,L.93 +c.eq.d $f18,$f16; bc1t L.92 +l.d $f16,One +c.eq.d $f18,$f16; bc1f L.89 +L.92: +la $17,1 +b L.90 +L.89: +move $17,$0 +L.90: +move $5,$17 +la $6,L.88 +jal TstCond +la $24,20 +sw $24,Milestone +move $4,$0 +l.d $f18,Half +l.d $f16,F9 +sub.d $f16,$f16,$f18 +c.lt.d $f16,$f18; bc1f L.96 +la $16,1 +b L.97 +L.96: +move $16,$0 +L.97: +move $5,$16 +la $6,L.95 +jal TstCond +l.d $f18,F9 +s.d $f18,X +la $24,1 +sw $24,I +l.d $f18,Half +l.d $f16,X +sub.d $f16,$f16,$f18 +s.d $f16,Y +l.d $f16,Y +sub.d $f18,$f16,$f18 +s.d $f18,Z +move $4,$0 +l.d $f18,X +l.d $f16,One +c.eq.d $f18,$f16; bc1f L.102 +l.d $f18,Z +l.d $f16,Zero +c.eq.d $f18,$f16; bc1f L.100 +L.102: +la $24,1 +sw $24,-20+240($sp) +b L.101 +L.100: +sw $0,-20+240($sp) +L.101: +lw $5,-20+240($sp) +la $6,L.99 +jal TstCond +l.d $f18,One +l.d $f16,U2 +add.d $f10,$f18,$f16 +s.d $f10,X +sw $0,I +la $24,25 +sw $24,Milestone +l.d $f10,Radix +sub.d $f8,$f10,$f18 +s.d $f8,BMinusU2 +l.d $f8,BMinusU2 +sub.d $f16,$f8,$f16 +add.d $f16,$f16,$f18 +s.d $f16,BMinusU2 +c.eq.d $f10,$f18; bc1t L.103 +l.d $f12,U1 +jal log +mov.d $f18,$f0 +s.d $f18,-32+240($sp) +l.d $f12,Radix +jal log +l.d $f16,TwoForty +neg.d $f16,$f16 +l.d $f10,-32+240($sp) +mul.d $f16,$f16,$f10 +div.d $f18,$f16,$f0 +s.d $f18,X +l.d $f18,Half +l.d $f16,X +add.d $f12,$f18,$f16 +jal floor +s.d $f0,Y +l.d $f18,X +l.d $f16,Y +sub.d $f12,$f18,$f16 +jal fabs +l.d $f16,Four +mul.d $f18,$f0,$f16 +l.d $f16,One +c.lt.d $f18,$f16; bc1f L.105 +l.d $f18,Y +s.d $f18,X +L.105: +l.d $f18,X +l.d $f16,TwoForty +div.d $f18,$f18,$f16 +s.d $f18,Precision +l.d $f18,Half +l.d $f16,Precision +add.d $f12,$f18,$f16 +jal floor +s.d $f0,Y +l.d $f18,Precision +l.d $f16,Y +sub.d $f12,$f18,$f16 +jal fabs +l.d $f16,TwoForty +mul.d $f18,$f0,$f16 +l.d $f16,Half +c.lt.d $f18,$f16; bc1f L.107 +l.d $f18,Y +s.d $f18,Precision +L.107: +L.103: +l.d $f18,Precision +s.d $f18,-32+240($sp) +mov.d $f12,$f18 +jal floor +l.d $f16,-32+240($sp) +c.eq.d $f16,$f0; bc1f L.111 +l.d $f18,Radix +l.d $f16,One +c.eq.d $f18,$f16; bc1f L.109 +L.111: +la $4,L.112 +jal printf +la $4,L.113 +jal printf +L.109: +l.d $f18,Radix +l.d $f16,One +c.eq.d $f18,$f16; bc1f L.114 +la $4,L.116 +jal printf +b L.115 +L.114: +la $4,L.117 +l.d $f18,Precision +mfc1.d $6,$f18 +jal printf +L.115: +la $4,1 +l.d $f18,Nine +l.d $f16,U2 +mul.d $f16,$f16,$f18 +mul.d $f18,$f16,$f18 +l.d $f16,TwoForty +mul.d $f18,$f18,$f16 +l.d $f16,One +c.lt.d $f18,$f16; bc1f L.120 +la $24,1 +sw $24,-36+240($sp) +b L.121 +L.120: +sw $0,-36+240($sp) +L.121: +lw $5,-36+240($sp) +la $6,L.119 +jal TstCond +la $24,30 +sw $24,Milestone +l.d $f18,Four +l.d $f16,Three +l.d $f10,One +div.d $f8,$f10,$f18 +div.d $f18,$f18,$f16 +sub.d $f18,$f18,$f10 +sub.d $f18,$f18,$f8 +mul.d $f18,$f18,$f16 +sub.d $f12,$f18,$f8 +jal fabs +s.d $f0,X +L.122: +l.d $f18,X +s.d $f18,Z2 +l.d $f18,One +l.d $f16,Z2 +l.d $f10,Half +mul.d $f10,$f10,$f16 +l.d $f8,ThirtyTwo +mul.d $f8,$f8,$f16 +mul.d $f16,$f8,$f16 +add.d $f16,$f10,$f16 +add.d $f16,$f18,$f16 +sub.d $f18,$f16,$f18 +s.d $f18,X +L.123: +l.d $f18,X +l.d $f16,Z2 +c.ule.d $f16,$f18; bc1t L.125 +l.d $f16,Zero +c.le.d $f18,$f16; bc1f L.122 +L.125: +l.d $f18,Three +l.d $f16,Four +div.d $f10,$f18,$f16 +l.d $f8,Two +div.d $f8,$f8,$f18 +sub.d $f10,$f10,$f8 +mul.d $f18,$f10,$f18 +l.d $f10,One +div.d $f16,$f10,$f16 +sub.d $f12,$f18,$f16 +jal fabs +s.d $f0,Z +s.d $f0,Y +s.d $f0,X +L.126: +l.d $f18,Z +s.d $f18,Z1 +l.d $f18,One +l.d $f16,Two +div.d $f18,$f18,$f16 +l.d $f16,Z1 +l.d $f10,Half +mul.d $f10,$f10,$f16 +l.d $f8,ThirtyTwo +mul.d $f8,$f8,$f16 +mul.d $f16,$f8,$f16 +add.d $f16,$f10,$f16 +sub.d $f16,$f18,$f16 +add.d $f16,$f16,$f18 +sub.d $f16,$f18,$f16 +add.d $f18,$f16,$f18 +s.d $f18,Z +L.127: +l.d $f18,Z +l.d $f16,Z1 +c.ule.d $f16,$f18; bc1t L.129 +l.d $f16,Zero +c.le.d $f18,$f16; bc1f L.126 +L.129: +L.130: +L.133: +l.d $f18,Y +s.d $f18,Y1 +l.d $f18,Half +l.d $f16,Y1 +mul.d $f10,$f18,$f16 +l.d $f8,ThirtyTwo +mul.d $f8,$f8,$f16 +mul.d $f16,$f8,$f16 +add.d $f16,$f10,$f16 +sub.d $f16,$f18,$f16 +add.d $f16,$f16,$f18 +sub.d $f16,$f18,$f16 +add.d $f18,$f16,$f18 +s.d $f18,Y +L.134: +l.d $f18,Y +l.d $f16,Y1 +c.ule.d $f16,$f18; bc1t L.136 +l.d $f16,Zero +c.le.d $f18,$f16; bc1f L.133 +L.136: +l.d $f18,X +s.d $f18,X1 +l.d $f18,X1 +l.d $f16,F9 +l.d $f10,Half +mul.d $f10,$f10,$f18 +l.d $f8,ThirtyTwo +mul.d $f8,$f8,$f18 +mul.d $f18,$f8,$f18 +add.d $f18,$f10,$f18 +sub.d $f18,$f18,$f16 +add.d $f18,$f18,$f16 +s.d $f18,X +L.131: +l.d $f18,X +l.d $f16,X1 +c.ule.d $f16,$f18; bc1t L.137 +l.d $f16,Zero +c.le.d $f18,$f16; bc1f L.130 +L.137: +l.d $f18,X1 +l.d $f16,Y1 +c.eq.d $f18,$f16; bc1f L.140 +l.d $f16,Z1 +c.eq.d $f18,$f16; bc1t L.138 +L.140: +la $4,1 +la $5,L.141 +jal BadCond +la $4,L.142 +l.d $f18,X1 +mfc1.d $6,$f18 +l.d $f18,Y1 +s.d $f18,16($sp) +l.d $f18,Z1 +s.d $f18,24($sp) +jal printf +la $4,L.143 +jal printf +la $4,L.144 +jal printf +la $4,L.145 +jal notify +l.d $f18,U1 +l.d $f16,X1 +c.eq.d $f16,$f18; bc1t L.149 +l.d $f16,Y1 +c.eq.d $f16,$f18; bc1t L.149 +l.d $f16,Z1 +c.eq.d $f16,$f18; bc1f L.139 +L.149: +la $4,L.150 +jal printf +b L.139 +L.138: +l.d $f18,Z1 +l.d $f16,U1 +c.eq.d $f18,$f16; bc1f L.153 +l.d $f18,Z2 +l.d $f16,U2 +c.eq.d $f18,$f16; bc1t L.151 +L.153: +l.d $f18,Z1 +l.d $f16,U1 +c.lt.d $f18,$f16; bc1f L.156 +l.d $f18,Z2 +l.d $f16,U2 +c.ult.d $f18,$f16; bc1t L.154 +L.156: +move $4,$0 +la $5,L.157 +jal BadCond +la $4,L.158 +jal notify +la $4,L.159 +l.d $f18,U1 +mfc1.d $6,$f18 +l.d $f16,Z1 +sub.d $f18,$f16,$f18 +s.d $f18,16($sp) +jal printf +la $4,L.160 +l.d $f18,U2 +mfc1.d $6,$f18 +l.d $f16,Z2 +sub.d $f18,$f16,$f18 +s.d $f18,16($sp) +jal printf +b L.155 +L.154: +l.d $f18,Zero +l.d $f16,Z1 +c.ule.d $f16,$f18; bc1t L.163 +l.d $f16,Z2 +c.le.d $f16,$f18; bc1f L.161 +L.163: +la $4,L.164 +l.d $f18,Radix +mfc1.d $6,$f18 +jal printf +la $4,L.165 +jal printf +la $4,L.166 +l.d $f18,Z1 +mfc1.d $6,$f18 +l.d $f18,Z2 +s.d $f18,16($sp) +jal printf +la $4,L.167 +jal notify +L.161: +l.d $f18,Z1 +l.d $f16,Z2 +c.eq.d $f18,$f16; bc1f L.170 +l.d $f16,Zero +c.ule.d $f18,$f16; bc1t L.168 +L.170: +l.d $f18,Z1 +l.d $f16,U1 +div.d $f18,$f18,$f16 +s.d $f18,X +l.d $f18,Z2 +l.d $f16,U2 +div.d $f18,$f18,$f16 +s.d $f18,Y +l.d $f18,Y +l.d $f16,X +c.ule.d $f18,$f16; bc1t L.171 +l.d $f18,Y +s.d $f18,X +L.171: +l.d $f12,X +jal log +neg.d $f18,$f0 +s.d $f18,Q +la $4,L.173 +jal printf +l.d $f12,Radix +jal log +la $4,L.174 +l.d $f16,Q +div.d $f18,$f16,$f0 +mfc1.d $6,$f18 +jal printf +l.d $f12,L.93 +jal log +la $4,L.175 +l.d $f16,Q +div.d $f18,$f16,$f0 +mfc1.d $6,$f18 +jal printf +L.168: +la $4,L.150 +jal printf +L.155: +L.151: +L.139: +jal Pause +la $24,35 +sw $24,Milestone +l.d $f18,Radix +l.d $f16,Two +c.ult.d $f18,$f16; bc1t L.176 +l.d $f18,Radix +l.d $f16,W +mul.d $f18,$f18,$f18 +div.d $f18,$f16,$f18 +s.d $f18,X +l.d $f18,X +l.d $f16,One +add.d $f16,$f18,$f16 +s.d $f16,Y +l.d $f16,Y +sub.d $f18,$f16,$f18 +s.d $f18,Z +l.d $f18,Z +l.d $f16,U2 +add.d $f10,$f18,$f16 +s.d $f10,T +l.d $f10,T +sub.d $f18,$f10,$f18 +s.d $f18,X +move $4,$0 +l.d $f18,X +c.eq.d $f18,$f16; bc1f L.180 +la $24,1 +sw $24,-40+240($sp) +b L.181 +L.180: +sw $0,-40+240($sp) +L.181: +lw $5,-40+240($sp) +la $6,L.179 +jal TstCond +l.d $f18,X +l.d $f16,U2 +c.eq.d $f18,$f16; bc1f L.182 +la $4,L.184 +jal printf +L.182: +L.176: +la $4,L.185 +jal printf +l.d $f18,F9 +l.d $f16,One +mul.d $f10,$f18,$f16 +s.d $f10,Y +mul.d $f10,$f16,$f18 +s.d $f10,Z +l.d $f10,Half +sub.d $f18,$f18,$f10 +s.d $f18,X +l.d $f18,X +l.d $f8,Y +sub.d $f8,$f8,$f10 +sub.d $f8,$f8,$f18 +s.d $f8,Y +l.d $f8,Z +sub.d $f10,$f8,$f10 +sub.d $f18,$f10,$f18 +s.d $f18,Z +l.d $f18,U2 +add.d $f10,$f16,$f18 +s.d $f10,X +l.d $f10,X +l.d $f8,Radix +mul.d $f6,$f10,$f8 +s.d $f6,T +mul.d $f10,$f8,$f10 +s.d $f10,R +l.d $f10,T +sub.d $f10,$f10,$f8 +s.d $f10,X +mul.d $f18,$f8,$f18 +l.d $f10,X +sub.d $f10,$f10,$f18 +s.d $f10,X +l.d $f10,R +sub.d $f10,$f10,$f8 +s.d $f10,T +l.d $f10,T +sub.d $f18,$f10,$f18 +s.d $f18,T +sub.d $f18,$f8,$f16 +l.d $f16,X +mul.d $f16,$f16,$f18 +s.d $f16,X +l.d $f16,T +mul.d $f18,$f16,$f18 +s.d $f18,T +l.d $f18,Zero +l.d $f16,X +c.eq.d $f16,$f18; bc1f L.186 +l.d $f16,Y +c.eq.d $f16,$f18; bc1f L.186 +l.d $f16,Z +c.eq.d $f16,$f18; bc1f L.186 +l.d $f16,T +c.eq.d $f16,$f18; bc1f L.186 +la $24,1 +sw $24,GMult +b L.187 +L.186: +move $24,$0 +sw $24,GMult +la $4,1 +move $5,$24 +la $6,L.188 +jal TstCond +L.187: +l.d $f18,Radix +l.d $f16,U2 +mul.d $f18,$f18,$f16 +s.d $f18,Z +l.d $f18,Z +l.d $f16,One +add.d $f16,$f16,$f18 +s.d $f16,X +l.d $f16,X +add.d $f18,$f16,$f18 +mul.d $f16,$f16,$f16 +sub.d $f12,$f18,$f16 +jal fabs +l.d $f16,U2 +sub.d $f18,$f0,$f16 +s.d $f18,Y +l.d $f18,One +sub.d $f18,$f18,$f16 +s.d $f18,X +l.d $f18,X +sub.d $f16,$f18,$f16 +mul.d $f18,$f18,$f18 +sub.d $f12,$f16,$f18 +jal fabs +l.d $f16,U1 +sub.d $f18,$f0,$f16 +s.d $f18,Z +move $4,$0 +l.d $f18,Zero +l.d $f16,Y +c.le.d $f16,$f18; bc1f L.191 +l.d $f16,Z +c.le.d $f16,$f18; bc1f L.191 +la $24,1 +sw $24,-40+240($sp) +b L.192 +L.191: +sw $0,-40+240($sp) +L.192: +lw $5,-40+240($sp) +la $6,L.190 +jal TstCond +l.d $f18,One +l.d $f16,U2 +sub.d $f10,$f18,$f16 +s.d $f10,Y +add.d $f16,$f18,$f16 +s.d $f16,X +l.d $f16,Y +div.d $f16,$f18,$f16 +s.d $f16,Z +l.d $f16,Z +l.d $f10,X +sub.d $f16,$f16,$f10 +s.d $f16,Y +l.d $f16,Three +div.d $f18,$f18,$f16 +s.d $f18,X +l.d $f18,Nine +div.d $f16,$f16,$f18 +s.d $f16,Z +l.d $f16,Z +l.d $f10,X +sub.d $f10,$f10,$f16 +s.d $f10,X +l.d $f10,TwentySeven +div.d $f18,$f18,$f10 +s.d $f18,T +l.d $f18,T +sub.d $f18,$f16,$f18 +s.d $f18,Z +la $4,2 +l.d $f18,Zero +l.d $f16,X +c.eq.d $f16,$f18; bc1f L.195 +l.d $f16,Y +c.eq.d $f16,$f18; bc1f L.195 +l.d $f16,Z +c.eq.d $f16,$f18; bc1f L.195 +la $24,1 +sw $24,-44+240($sp) +b L.196 +L.195: +sw $0,-44+240($sp) +L.196: +lw $5,-44+240($sp) +la $6,L.194 +jal TstCond +l.d $f18,F9 +l.d $f16,One +div.d $f10,$f18,$f16 +s.d $f10,Y +l.d $f10,Half +sub.d $f18,$f18,$f10 +s.d $f18,X +l.d $f18,Y +sub.d $f18,$f18,$f10 +l.d $f10,X +sub.d $f18,$f18,$f10 +s.d $f18,Y +l.d $f18,U2 +add.d $f18,$f16,$f18 +s.d $f18,X +l.d $f18,X +div.d $f16,$f18,$f16 +s.d $f16,T +l.d $f16,T +sub.d $f18,$f16,$f18 +s.d $f18,X +l.d $f18,Zero +l.d $f16,X +c.eq.d $f16,$f18; bc1f L.197 +l.d $f16,Y +c.eq.d $f16,$f18; bc1f L.197 +l.d $f16,Z +c.eq.d $f16,$f18; bc1f L.197 +la $24,1 +sw $24,GDiv +b L.198 +L.197: +move $24,$0 +sw $24,GDiv +la $4,1 +move $5,$24 +la $6,L.199 +jal TstCond +L.198: +l.d $f18,One +l.d $f16,U2 +add.d $f16,$f18,$f16 +div.d $f18,$f18,$f16 +s.d $f18,X +l.d $f18,Half +l.d $f16,X +sub.d $f16,$f16,$f18 +sub.d $f18,$f16,$f18 +s.d $f18,Y +la $4,1 +l.d $f18,Y +l.d $f16,Zero +c.lt.d $f18,$f16; bc1f L.202 +la $24,1 +sw $24,-48+240($sp) +b L.203 +L.202: +sw $0,-48+240($sp) +L.203: +lw $5,-48+240($sp) +la $6,L.201 +jal TstCond +l.d $f18,One +l.d $f16,U2 +sub.d $f10,$f18,$f16 +s.d $f10,X +l.d $f10,Radix +mul.d $f16,$f10,$f16 +add.d $f18,$f18,$f16 +s.d $f18,Y +l.d $f18,X +mul.d $f16,$f18,$f10 +s.d $f16,Z +l.d $f16,Y +mul.d $f8,$f16,$f10 +s.d $f8,T +l.d $f8,Z +div.d $f8,$f8,$f10 +s.d $f8,R +l.d $f8,T +div.d $f10,$f8,$f10 +s.d $f10,StickyBit +l.d $f10,R +sub.d $f18,$f10,$f18 +s.d $f18,X +l.d $f18,StickyBit +sub.d $f18,$f18,$f16 +s.d $f18,Y +move $4,$0 +l.d $f18,Zero +l.d $f16,X +c.eq.d $f16,$f18; bc1f L.206 +l.d $f16,Y +c.eq.d $f16,$f18; bc1f L.206 +la $24,1 +sw $24,-52+240($sp) +b L.207 +L.206: +sw $0,-52+240($sp) +L.207: +lw $5,-52+240($sp) +la $6,L.205 +jal TstCond +l.d $f18,One +l.d $f16,U1 +sub.d $f16,$f18,$f16 +s.d $f16,Y +l.d $f16,F9 +sub.d $f16,$f18,$f16 +s.d $f16,X +l.d $f16,Y +sub.d $f18,$f18,$f16 +s.d $f18,Y +l.d $f18,Radix +l.d $f16,U2 +sub.d $f16,$f18,$f16 +s.d $f16,T +l.d $f16,BMinusU2 +sub.d $f16,$f18,$f16 +s.d $f16,Z +l.d $f16,T +sub.d $f18,$f18,$f16 +s.d $f18,T +l.d $f18,U1 +l.d $f16,X +c.eq.d $f16,$f18; bc1f L.208 +l.d $f16,Y +c.eq.d $f16,$f18; bc1f L.208 +l.d $f18,U2 +l.d $f16,Z +c.eq.d $f16,$f18; bc1f L.208 +l.d $f16,T +c.eq.d $f16,$f18; bc1f L.208 +la $24,1 +sw $24,GAddSub +b L.209 +L.208: +move $24,$0 +sw $24,GAddSub +la $4,1 +move $5,$24 +la $6,L.210 +jal TstCond +L.209: +l.d $f18,F9 +l.d $f16,One +c.eq.d $f18,$f16; bc1t L.211 +sub.d $f18,$f18,$f16 +l.d $f16,Zero +c.ult.d $f18,$f16; bc1t L.211 +la $4,1 +la $5,L.213 +jal BadCond +la $4,L.214 +jal printf +la $4,L.215 +jal printf +la $4,L.216 +jal printf +L.211: +la $24,1 +lw $15,GMult +bne $15,$24,L.217 +lw $15,GDiv +bne $15,$24,L.217 +lw $15,GAddSub +bne $15,$24,L.217 +la $4,L.219 +jal printf +L.217: +la $24,40 +sw $24,Milestone +jal Pause +la $4,L.220 +jal printf +sw $0,RMult +sw $0,RDiv +sw $0,RAddSub +l.d $f18,Two +l.d $f16,Radix +div.d $f16,$f16,$f18 +s.d $f16,RadixD2 +s.d $f18,A1 +sw $0,Done +L.221: +l.d $f18,Radix +s.d $f18,AInvrse +L.224: +l.d $f18,AInvrse +s.d $f18,X +l.d $f16,A1 +div.d $f18,$f18,$f16 +s.d $f18,AInvrse +L.225: +l.d $f12,AInvrse +jal floor +l.d $f16,AInvrse +c.eq.d $f0,$f16; bc1t L.224 +l.d $f18,X +l.d $f16,One +c.eq.d $f18,$f16; bc1t L.230 +l.d $f18,A1 +l.d $f16,Three +c.ule.d $f18,$f16; bc1t L.228 +L.230: +la $24,1 +sw $24,-56+240($sp) +b L.229 +L.228: +sw $0,-56+240($sp) +L.229: +lw $24,-56+240($sp) +sw $24,Done +lw $24,Done +bne $24,$0,L.231 +l.d $f18,Nine +l.d $f16,One +add.d $f18,$f18,$f16 +s.d $f18,A1 +L.231: +L.222: +lw $24,Done +beq $24,$0,L.221 +l.d $f18,X +l.d $f16,One +c.eq.d $f18,$f16; bc1f L.233 +l.d $f18,Radix +s.d $f18,A1 +L.233: +l.d $f18,A1 +l.d $f16,One +div.d $f16,$f16,$f18 +s.d $f16,AInvrse +s.d $f18,X +l.d $f18,AInvrse +s.d $f18,Y +sw $0,Done +L.235: +l.d $f18,Half +l.d $f16,X +l.d $f10,Y +mul.d $f16,$f16,$f10 +sub.d $f16,$f16,$f18 +s.d $f16,Z +move $4,$0 +l.d $f16,Z +c.eq.d $f16,$f18; bc1f L.240 +la $24,1 +sw $24,-56+240($sp) +b L.241 +L.240: +sw $0,-56+240($sp) +L.241: +lw $5,-56+240($sp) +la $6,L.239 +jal TstCond +l.d $f18,X +l.d $f16,Radix +c.eq.d $f18,$f16; bc1f L.243 +la $24,1 +sw $24,-60+240($sp) +b L.244 +L.243: +sw $0,-60+240($sp) +L.244: +lw $24,-60+240($sp) +sw $24,Done +l.d $f18,Radix +s.d $f18,X +l.d $f18,One +l.d $f16,X +div.d $f18,$f18,$f16 +s.d $f18,Y +L.236: +lw $24,Done +beq $24,$0,L.235 +l.d $f18,One +l.d $f16,U2 +add.d $f10,$f18,$f16 +s.d $f10,Y2 +sub.d $f18,$f18,$f16 +s.d $f18,Y1 +l.d $f18,OneAndHalf +s.d $f18,-64+240($sp) +sub.d $f10,$f18,$f16 +s.d $f10,X +add.d $f10,$f18,$f16 +s.d $f10,Y +l.d $f10,X +l.d $f8,Y2 +sub.d $f6,$f10,$f16 +mul.d $f6,$f6,$f8 +s.d $f6,Z +l.d $f6,Y +l.d $f4,Y1 +mul.d $f18,$f6,$f4 +s.d $f18,T +l.d $f18,Z +sub.d $f18,$f18,$f10 +s.d $f18,Z +l.d $f18,T +sub.d $f18,$f18,$f10 +s.d $f18,T +mul.d $f18,$f10,$f8 +s.d $f18,X +add.d $f18,$f6,$f16 +mul.d $f18,$f18,$f4 +s.d $f18,Y +l.d $f18,X +l.d $f16,-64+240($sp) +sub.d $f18,$f18,$f16 +s.d $f18,X +l.d $f18,Y +l.d $f16,-64+240($sp) +sub.d $f18,$f18,$f16 +s.d $f18,Y +l.d $f18,Zero +l.d $f16,X +c.eq.d $f16,$f18; bc1f L.245 +l.d $f16,Y +c.eq.d $f16,$f18; bc1f L.245 +l.d $f16,Z +c.eq.d $f16,$f18; bc1f L.245 +l.d $f16,T +c.le.d $f16,$f18; bc1f L.245 +l.d $f18,OneAndHalf +l.d $f16,U2 +add.d $f10,$f18,$f16 +l.d $f8,Y2 +mul.d $f6,$f10,$f8 +s.d $f6,X +sub.d $f18,$f18,$f16 +sub.d $f6,$f18,$f16 +s.d $f6,Y +add.d $f10,$f10,$f16 +s.d $f10,Z +l.d $f10,Y1 +mul.d $f18,$f18,$f10 +s.d $f18,T +l.d $f18,Z +add.d $f6,$f18,$f16 +s.d $f6,-72+240($sp) +l.d $f4,X +sub.d $f4,$f4,$f6 +s.d $f4,X +l.d $f4,Y +mul.d $f6,$f4,$f10 +s.d $f6,StickyBit +mul.d $f18,$f18,$f8 +s.d $f18,S +l.d $f18,T +sub.d $f18,$f18,$f4 +s.d $f18,T +sub.d $f18,$f16,$f4 +l.d $f6,StickyBit +add.d $f18,$f18,$f6 +s.d $f18,Y +l.d $f18,S +l.d $f6,-72+240($sp) +add.d $f6,$f6,$f16 +sub.d $f18,$f18,$f6 +s.d $f18,Z +add.d $f18,$f8,$f16 +mul.d $f18,$f18,$f10 +s.d $f18,StickyBit +mul.d $f18,$f8,$f10 +s.d $f18,Y1 +l.d $f18,StickyBit +sub.d $f18,$f18,$f8 +s.d $f18,StickyBit +l.d $f18,Y1 +l.d $f16,Half +sub.d $f18,$f18,$f16 +s.d $f18,Y1 +l.d $f18,Zero +l.d $f16,X +c.eq.d $f16,$f18; bc1f L.247 +l.d $f16,Y +c.eq.d $f16,$f18; bc1f L.247 +l.d $f16,Z +c.eq.d $f16,$f18; bc1f L.247 +l.d $f16,T +c.eq.d $f16,$f18; bc1f L.247 +l.d $f16,StickyBit +c.eq.d $f16,$f18; bc1f L.247 +l.d $f18,Y1 +l.d $f16,Half +c.eq.d $f18,$f16; bc1f L.247 +la $24,1 +sw $24,RMult +la $4,L.249 +jal printf +b L.248 +L.247: +l.d $f18,U2 +l.d $f16,Zero +l.d $f10,X +add.d $f10,$f10,$f18 +c.eq.d $f10,$f16; bc1f L.250 +l.d $f10,Y +c.lt.d $f10,$f16; bc1f L.250 +l.d $f10,Z +add.d $f10,$f10,$f18 +c.eq.d $f10,$f16; bc1f L.250 +l.d $f10,T +c.lt.d $f10,$f16; bc1f L.250 +l.d $f10,StickyBit +add.d $f18,$f10,$f18 +c.eq.d $f18,$f16; bc1f L.250 +l.d $f18,Y1 +l.d $f16,Half +c.lt.d $f18,$f16; bc1f L.250 +la $24,2 +sw $24,RMult +la $4,L.252 +jal printf +b L.251 +L.250: +la $4,L.253 +jal printf +L.251: +L.248: +lw $24,RMult +la $15,1 +bne $24,$15,L.246 +lw $24,GMult +bne $24,$0,L.246 +la $4,L.256 +jal notify +b L.246 +L.245: +la $4,L.253 +jal printf +L.246: +la $24,45 +sw $24,Milestone +l.d $f18,One +l.d $f16,U2 +add.d $f10,$f18,$f16 +s.d $f10,Y2 +sub.d $f18,$f18,$f16 +s.d $f18,Y1 +l.d $f18,OneAndHalf +s.d $f18,-80+240($sp) +add.d $f10,$f18,$f16 +s.d $f10,-72+240($sp) +add.d $f8,$f10,$f16 +s.d $f8,Z +l.d $f8,Z +l.d $f6,Y2 +div.d $f4,$f8,$f6 +s.d $f4,X +sub.d $f4,$f18,$f16 +sub.d $f4,$f4,$f16 +s.d $f4,T +l.d $f4,T +l.d $f10,Y1 +sub.d $f18,$f4,$f16 +div.d $f18,$f18,$f10 +s.d $f18,Y +add.d $f18,$f8,$f16 +div.d $f18,$f18,$f6 +s.d $f18,Z +l.d $f18,X +l.d $f8,-80+240($sp) +sub.d $f18,$f18,$f8 +s.d $f18,X +l.d $f18,Y +sub.d $f18,$f18,$f4 +s.d $f18,Y +div.d $f18,$f4,$f10 +s.d $f18,T +l.d $f18,Z +l.d $f10,-72+240($sp) +sub.d $f18,$f18,$f10 +s.d $f18,Z +l.d $f18,-80+240($sp) +sub.d $f18,$f16,$f18 +l.d $f16,T +add.d $f18,$f18,$f16 +s.d $f18,T +l.d $f18,Zero +l.d $f16,X +c.le.d $f16,$f18; bc1f L.257 +l.d $f16,Y +c.le.d $f16,$f18; bc1f L.257 +l.d $f16,Z +c.le.d $f16,$f18; bc1f L.257 +l.d $f16,T +c.le.d $f16,$f18; bc1f L.257 +l.d $f18,OneAndHalf +l.d $f16,Y2 +div.d $f10,$f18,$f16 +s.d $f10,X +l.d $f10,U2 +sub.d $f8,$f18,$f10 +s.d $f8,Y +add.d $f8,$f18,$f10 +s.d $f8,Z +l.d $f8,Y +l.d $f6,X +sub.d $f6,$f6,$f8 +s.d $f6,X +l.d $f6,Y1 +div.d $f4,$f18,$f6 +s.d $f4,T +div.d $f8,$f8,$f6 +s.d $f8,Y +l.d $f8,Z +l.d $f6,T +add.d $f4,$f8,$f10 +sub.d $f6,$f6,$f4 +s.d $f6,T +l.d $f6,Y +sub.d $f6,$f6,$f8 +s.d $f6,Y +div.d $f8,$f8,$f16 +s.d $f8,Z +add.d $f10,$f16,$f10 +div.d $f10,$f10,$f16 +s.d $f10,Y1 +l.d $f10,Z +sub.d $f18,$f10,$f18 +s.d $f18,Z +l.d $f18,Y1 +sub.d $f18,$f18,$f16 +s.d $f18,Y2 +l.d $f18,F9 +l.d $f16,U1 +sub.d $f16,$f18,$f16 +div.d $f18,$f16,$f18 +s.d $f18,Y1 +l.d $f18,Zero +l.d $f16,X +c.eq.d $f16,$f18; bc1f L.259 +l.d $f16,Y +c.eq.d $f16,$f18; bc1f L.259 +l.d $f16,Z +c.eq.d $f16,$f18; bc1f L.259 +l.d $f16,T +c.eq.d $f16,$f18; bc1f L.259 +l.d $f16,Y2 +c.eq.d $f16,$f18; bc1f L.259 +c.eq.d $f16,$f18; bc1f L.259 +l.d $f18,Half +l.d $f16,Y1 +sub.d $f16,$f16,$f18 +l.d $f10,F9 +sub.d $f18,$f10,$f18 +c.eq.d $f16,$f18; bc1f L.259 +la $24,1 +sw $24,RDiv +la $4,L.261 +jal printf +lw $24,GDiv +bne $24,$0,L.260 +la $4,L.264 +jal notify +b L.260 +L.259: +l.d $f18,Zero +l.d $f16,X +c.lt.d $f16,$f18; bc1f L.265 +l.d $f16,Y +c.lt.d $f16,$f18; bc1f L.265 +l.d $f16,Z +c.lt.d $f16,$f18; bc1f L.265 +l.d $f16,T +c.lt.d $f16,$f18; bc1f L.265 +l.d $f16,Y2 +c.lt.d $f16,$f18; bc1f L.265 +l.d $f18,Half +l.d $f16,Y1 +sub.d $f16,$f16,$f18 +l.d $f10,F9 +sub.d $f18,$f10,$f18 +c.lt.d $f16,$f18; bc1f L.265 +la $24,2 +sw $24,RDiv +la $4,L.267 +jal printf +L.265: +L.260: +L.257: +lw $24,RDiv +bne $24,$0,L.268 +la $4,L.270 +jal printf +L.268: +l.d $f18,Radix +l.d $f16,One +div.d $f16,$f16,$f18 +s.d $f16,BInvrse +move $4,$0 +l.d $f16,Half +l.d $f10,BInvrse +mul.d $f18,$f10,$f18 +sub.d $f18,$f18,$f16 +c.eq.d $f18,$f16; bc1f L.273 +la $24,1 +sw $24,-84+240($sp) +b L.274 +L.273: +sw $0,-84+240($sp) +L.274: +lw $5,-84+240($sp) +la $6,L.272 +jal TstCond +la $24,50 +sw $24,Milestone +move $4,$0 +l.d $f18,Half +l.d $f16,F9 +l.d $f10,U1 +add.d $f16,$f16,$f10 +sub.d $f16,$f16,$f18 +c.eq.d $f16,$f18; bc1f L.277 +l.d $f18,One +l.d $f16,BMinusU2 +l.d $f10,U2 +add.d $f16,$f16,$f10 +sub.d $f16,$f16,$f18 +l.d $f10,Radix +sub.d $f18,$f10,$f18 +c.eq.d $f16,$f18; bc1f L.277 +la $24,1 +sw $24,-88+240($sp) +b L.278 +L.277: +sw $0,-88+240($sp) +L.278: +lw $5,-88+240($sp) +la $6,L.276 +jal TstCond +l.d $f18,One +l.d $f16,U1 +mul.d $f16,$f16,$f16 +sub.d $f16,$f18,$f16 +s.d $f16,X +l.d $f16,U2 +sub.d $f10,$f18,$f16 +mul.d $f16,$f16,$f10 +add.d $f16,$f18,$f16 +s.d $f16,Y +l.d $f16,Half +l.d $f10,F9 +sub.d $f10,$f10,$f16 +s.d $f10,Z +l.d $f10,X +sub.d $f16,$f10,$f16 +l.d $f10,Z +sub.d $f16,$f16,$f10 +s.d $f16,X +l.d $f16,Y +sub.d $f18,$f16,$f18 +s.d $f18,Y +l.d $f18,Zero +l.d $f16,X +c.eq.d $f16,$f18; bc1f L.279 +l.d $f16,Y +c.eq.d $f16,$f18; bc1f L.279 +la $24,2 +sw $24,RAddSub +la $4,L.281 +jal printf +L.279: +lw $24,GAddSub +la $15,1 +bne $24,$15,L.282 +l.d $f18,Half +l.d $f16,U2 +add.d $f10,$f18,$f16 +mul.d $f10,$f10,$f16 +s.d $f10,X +sub.d $f18,$f18,$f16 +mul.d $f18,$f18,$f16 +s.d $f18,Y +l.d $f18,One +l.d $f10,X +add.d $f10,$f18,$f10 +s.d $f10,X +l.d $f10,Y +add.d $f10,$f18,$f10 +s.d $f10,Y +add.d $f16,$f18,$f16 +l.d $f10,X +sub.d $f16,$f16,$f10 +s.d $f16,X +l.d $f16,Y +sub.d $f18,$f18,$f16 +s.d $f18,Y +l.d $f18,Zero +l.d $f16,X +c.eq.d $f16,$f18; bc1f L.284 +l.d $f16,Y +c.eq.d $f16,$f18; bc1f L.284 +l.d $f18,Half +l.d $f16,U2 +l.d $f10,U1 +add.d $f8,$f18,$f16 +mul.d $f8,$f8,$f10 +s.d $f8,X +sub.d $f18,$f18,$f16 +mul.d $f18,$f18,$f10 +s.d $f18,Y +l.d $f18,One +l.d $f16,X +sub.d $f16,$f18,$f16 +s.d $f16,X +l.d $f16,Y +sub.d $f16,$f18,$f16 +s.d $f16,Y +l.d $f16,F9 +l.d $f10,X +sub.d $f16,$f16,$f10 +s.d $f16,X +l.d $f16,Y +sub.d $f18,$f18,$f16 +s.d $f18,Y +l.d $f18,Zero +l.d $f16,X +c.eq.d $f16,$f18; bc1f L.286 +l.d $f16,Y +c.eq.d $f16,$f18; bc1f L.286 +la $24,1 +sw $24,RAddSub +la $4,L.288 +jal printf +lw $24,GAddSub +bne $24,$0,L.283 +la $4,L.291 +jal notify +b L.283 +L.286: +la $4,L.292 +jal printf +b L.283 +L.284: +la $4,L.292 +jal printf +b L.283 +L.282: +la $4,L.292 +jal printf +L.283: +l.d $f18,One +s.d $f18,S +l.d $f16,Half +add.d $f10,$f18,$f16 +mul.d $f10,$f16,$f10 +add.d $f10,$f18,$f10 +s.d $f10,X +l.d $f10,U2 +add.d $f18,$f18,$f10 +mul.d $f18,$f18,$f16 +s.d $f18,Y +l.d $f18,X +l.d $f16,Y +sub.d $f10,$f18,$f16 +s.d $f10,Z +sub.d $f18,$f16,$f18 +s.d $f18,T +l.d $f18,Z +l.d $f16,T +add.d $f18,$f18,$f16 +s.d $f18,StickyBit +l.d $f18,StickyBit +l.d $f16,Zero +c.eq.d $f18,$f16; bc1t L.293 +l.d $f18,Zero +s.d $f18,S +la $4,3 +la $5,L.295 +jal BadCond +L.293: +l.d $f18,Zero +s.d $f18,StickyBit +la $24,1 +lw $15,GMult +bne $15,$24,L.296 +lw $15,GDiv +bne $15,$24,L.296 +lw $15,GAddSub +bne $15,$24,L.296 +lw $15,RMult +bne $15,$24,L.296 +lw $15,RDiv +bne $15,$24,L.296 +lw $15,RAddSub +bne $15,$24,L.296 +l.d $f12,RadixD2 +jal floor +l.d $f16,RadixD2 +c.eq.d $f0,$f16; bc1f L.296 +la $4,L.298 +jal printf +l.d $f18,Half +l.d $f16,U2 +l.d $f10,U1 +add.d $f10,$f18,$f10 +mul.d $f10,$f10,$f16 +s.d $f10,X +mul.d $f18,$f18,$f16 +s.d $f18,Y +l.d $f18,One +l.d $f16,Y +add.d $f16,$f18,$f16 +s.d $f16,Z +l.d $f16,X +add.d $f18,$f18,$f16 +s.d $f18,T +l.d $f18,One +l.d $f16,Z +sub.d $f16,$f16,$f18 +l.d $f10,Zero +c.le.d $f16,$f10; bc1f L.299 +l.d $f16,T +sub.d $f18,$f16,$f18 +l.d $f16,U2 +c.ult.d $f18,$f16; bc1t L.299 +l.d $f18,T +l.d $f16,Y +add.d $f18,$f18,$f16 +s.d $f18,Z +l.d $f18,Z +l.d $f16,X +sub.d $f18,$f18,$f16 +s.d $f18,Y +l.d $f18,T +l.d $f16,Z +sub.d $f16,$f16,$f18 +l.d $f10,U2 +c.ult.d $f16,$f10; bc1t L.301 +l.d $f16,Y +sub.d $f18,$f16,$f18 +l.d $f16,Zero +c.eq.d $f18,$f16; bc1f L.301 +l.d $f18,Half +l.d $f16,U1 +add.d $f10,$f18,$f16 +mul.d $f10,$f10,$f16 +s.d $f10,X +mul.d $f18,$f18,$f16 +s.d $f18,Y +l.d $f18,One +l.d $f16,Y +sub.d $f16,$f18,$f16 +s.d $f16,Z +l.d $f16,X +sub.d $f18,$f18,$f16 +s.d $f18,T +l.d $f18,Zero +l.d $f16,Z +l.d $f10,One +sub.d $f16,$f16,$f10 +c.eq.d $f16,$f18; bc1f L.303 +l.d $f16,T +l.d $f10,F9 +sub.d $f16,$f16,$f10 +c.eq.d $f16,$f18; bc1f L.303 +l.d $f18,U1 +l.d $f16,Half +sub.d $f16,$f16,$f18 +mul.d $f18,$f16,$f18 +s.d $f18,Z +l.d $f18,F9 +l.d $f16,Z +sub.d $f16,$f18,$f16 +s.d $f16,T +l.d $f16,Y +sub.d $f18,$f18,$f16 +s.d $f18,Q +l.d $f18,F9 +l.d $f16,Zero +l.d $f10,T +sub.d $f10,$f10,$f18 +c.eq.d $f10,$f16; bc1f L.305 +l.d $f10,U1 +sub.d $f18,$f18,$f10 +l.d $f10,Q +sub.d $f18,$f18,$f10 +c.eq.d $f18,$f16; bc1f L.305 +l.d $f18,One +l.d $f16,U2 +l.d $f10,OneAndHalf +add.d $f8,$f18,$f16 +mul.d $f8,$f8,$f10 +s.d $f8,Z +add.d $f10,$f10,$f16 +l.d $f8,Z +sub.d $f10,$f10,$f8 +add.d $f10,$f10,$f16 +s.d $f10,T +l.d $f10,Radix +l.d $f8,Half +div.d $f8,$f8,$f10 +add.d $f8,$f18,$f8 +s.d $f8,X +mul.d $f16,$f10,$f16 +add.d $f18,$f18,$f16 +s.d $f18,Y +l.d $f18,X +l.d $f16,Y +mul.d $f18,$f18,$f16 +s.d $f18,Z +l.d $f18,Zero +l.d $f16,T +c.eq.d $f16,$f18; bc1f L.307 +l.d $f16,X +l.d $f10,Radix +l.d $f8,U2 +mul.d $f10,$f10,$f8 +add.d $f16,$f16,$f10 +l.d $f10,Z +sub.d $f16,$f16,$f10 +c.eq.d $f16,$f18; bc1f L.307 +l.d $f18,Radix +l.d $f16,Two +c.eq.d $f18,$f16; bc1t L.309 +l.d $f18,Two +l.d $f16,U2 +add.d $f16,$f18,$f16 +s.d $f16,X +l.d $f16,X +div.d $f18,$f16,$f18 +s.d $f18,Y +l.d $f18,Y +l.d $f16,One +sub.d $f18,$f18,$f16 +l.d $f16,Zero +c.eq.d $f18,$f16; bc1f L.310 +l.d $f18,S +s.d $f18,StickyBit +b L.310 +L.309: +l.d $f18,S +s.d $f18,StickyBit +L.310: +L.307: +L.305: +L.303: +L.301: +L.299: +L.296: +l.d $f18,StickyBit +l.d $f16,One +c.eq.d $f18,$f16; bc1f L.313 +la $4,L.315 +jal printf +b L.314 +L.313: +la $4,L.316 +jal printf +L.314: +la $4,3 +lw $15,GMult +beq $15,$0,L.319 +lw $15,GDiv +beq $15,$0,L.319 +lw $15,GAddSub +beq $15,$0,L.319 +lw $15,RMult +beq $15,$0,L.319 +lw $15,RDiv +beq $15,$0,L.319 +lw $15,RAddSub +beq $15,$0,L.319 +la $24,1 +sw $24,-92+240($sp) +b L.320 +L.319: +sw $0,-92+240($sp) +L.320: +lw $5,-92+240($sp) +la $6,L.318 +jal TstCond +la $24,60 +sw $24,Milestone +la $4,L.44 +jal printf +la $4,L.321 +jal printf +la $4,L.322 +lw $5,NoTrials +jal printf +l.d $f12,L.323 +jal sqrt +s.d $f0,Random9 +l.d $f18,Third +s.d $f18,Random1 +la $24,1 +sw $24,I +L.324: +jal Random +s.d $f0,X +jal Random +s.d $f0,Y +l.d $f18,Y +l.d $f16,X +mul.d $f10,$f18,$f16 +s.d $f10,Z9 +mul.d $f18,$f16,$f18 +s.d $f18,Z +l.d $f18,Z +l.d $f16,Z9 +sub.d $f18,$f18,$f16 +s.d $f18,Z9 +lw $24,I +la $24,1($24) +sw $24,I +L.325: +lw $24,I +lw $15,NoTrials +bgt $24,$15,L.327 +l.d $f18,Z9 +l.d $f16,Zero +c.eq.d $f18,$f16; bc1t L.324 +L.327: +lw $24,I +lw $15,NoTrials +bne $24,$15,L.328 +l.d $f18,One +l.d $f16,Half +l.d $f10,Three +div.d $f16,$f16,$f10 +add.d $f16,$f18,$f16 +s.d $f16,Random1 +l.d $f10,U2 +l.d $f8,U1 +add.d $f10,$f10,$f8 +add.d $f18,$f10,$f18 +s.d $f18,Random2 +l.d $f10,Random1 +l.d $f8,Random2 +mul.d $f6,$f10,$f8 +s.d $f6,Z +mul.d $f10,$f8,$f10 +s.d $f10,Y +mul.d $f18,$f16,$f18 +sub.d $f18,$f18,$f18 +s.d $f18,Z9 +L.328: +lw $24,I +lw $15,NoTrials +beq $24,$15,L.330 +l.d $f18,Z9 +l.d $f16,Zero +c.eq.d $f18,$f16; bc1t L.330 +la $4,2 +la $5,L.332 +jal BadCond +b L.331 +L.330: +la $4,L.333 +lw $5,NoTrials +jal printf +L.331: +la $24,70 +sw $24,Milestone +la $4,L.334 +jal printf +l.d $f18,Zero +s.d $f18,-104+240($sp) +mov.d $f12,$f18 +jal sqrt +l.d $f16,-104+240($sp) +c.eq.d $f16,$f0; bc1f L.337 +l.d $f18,Zero +neg.d $f18,$f18 +s.d $f18,-112+240($sp) +mov.d $f12,$f18 +jal sqrt +l.d $f16,-112+240($sp) +c.eq.d $f16,$f0; bc1f L.337 +l.d $f18,One +s.d $f18,-120+240($sp) +mov.d $f12,$f18 +jal sqrt +mov.d $f18,$f0 +l.d $f16,-120+240($sp) +c.eq.d $f16,$f18; bc1f L.337 +la $24,1 +sw $24,-96+240($sp) +b L.338 +L.337: +sw $0,-96+240($sp) +L.338: +move $4,$0 +lw $5,-96+240($sp) +la $6,L.336 +jal TstCond +l.d $f18,Zero +s.d $f18,MinSqEr +s.d $f18,MaxSqEr +s.d $f18,J +l.d $f18,Radix +s.d $f18,X +l.d $f18,U2 +s.d $f18,OneUlp +la $4,1 +jal SqXMinX +l.d $f18,BInvrse +s.d $f18,X +l.d $f16,U1 +mul.d $f18,$f18,$f16 +s.d $f18,OneUlp +la $4,1 +jal SqXMinX +l.d $f18,U1 +s.d $f18,X +mul.d $f18,$f18,$f18 +s.d $f18,OneUlp +la $4,1 +jal SqXMinX +l.d $f18,J +l.d $f16,Zero +c.eq.d $f18,$f16; bc1t L.339 +jal Pause +L.339: +la $4,L.341 +lw $5,NoTrials +jal printf +l.d $f18,Zero +s.d $f18,J +l.d $f18,Two +s.d $f18,X +l.d $f18,Radix +s.d $f18,Y +l.d $f16,One +c.eq.d $f18,$f16; bc1t L.342 +L.344: +l.d $f18,Y +s.d $f18,X +l.d $f16,Radix +mul.d $f18,$f16,$f18 +s.d $f18,Y +L.345: +l.d $f18,Y +l.d $f16,X +sub.d $f18,$f18,$f16 +lw $24,NoTrials +mtc1 $24,$f16; cvt.d.w $f16,$f16 +c.ult.d $f18,$f16; bc1t L.344 +L.342: +l.d $f18,X +l.d $f16,U2 +mul.d $f18,$f18,$f16 +s.d $f18,OneUlp +la $24,1 +sw $24,I +b L.348 +L.347: +l.d $f18,X +l.d $f16,One +add.d $f18,$f18,$f16 +s.d $f18,X +la $4,2 +jal SqXMinX +l.d $f18,J +l.d $f16,Zero +c.ule.d $f18,$f16; bc1t L.350 +b L.349 +L.350: +lw $24,I +la $24,1($24) +sw $24,I +L.348: +lw $24,I +lw $15,NoTrials +ble $24,$15,L.347 +L.349: +la $4,L.352 +jal printf +la $24,-1 +sw $24,I +l.d $f18,BMinusU2 +s.d $f18,X +l.d $f18,Radix +s.d $f18,Y +l.d $f16,U2 +mul.d $f16,$f18,$f16 +add.d $f18,$f18,$f16 +s.d $f18,Z +sw $0,NotMonot +sw $0,Monot +b L.354 +L.353: +lw $24,I +la $24,1($24) +sw $24,I +l.d $f12,X +jal sqrt +s.d $f0,X +l.d $f12,Y +jal sqrt +s.d $f0,Q +l.d $f12,Z +jal sqrt +s.d $f0,Z +l.d $f18,Q +l.d $f16,X +c.le.d $f16,$f18; bc1f L.358 +l.d $f16,Z +c.ule.d $f18,$f16; bc1t L.356 +L.358: +la $24,1 +sw $24,NotMonot +b L.357 +L.356: +l.d $f18,Q +l.d $f16,Half +add.d $f12,$f18,$f16 +jal floor +s.d $f0,Q +lw $24,I +bgt $24,$0,L.361 +l.d $f18,Q +l.d $f16,Radix +mul.d $f18,$f18,$f18 +c.eq.d $f16,$f18; bc1f L.359 +L.361: +la $24,1 +sw $24,Monot +b L.360 +L.359: +lw $24,I +ble $24,$0,L.362 +lw $24,I +la $15,1 +ble $24,$15,L.364 +la $24,1 +sw $24,Monot +b L.363 +L.364: +l.d $f18,Y +l.d $f16,BInvrse +mul.d $f18,$f18,$f16 +s.d $f18,Y +l.d $f18,Y +l.d $f16,U1 +sub.d $f10,$f18,$f16 +s.d $f10,X +add.d $f18,$f18,$f16 +s.d $f18,Z +b L.363 +L.362: +l.d $f18,Q +s.d $f18,Y +l.d $f18,Y +l.d $f16,U2 +sub.d $f10,$f18,$f16 +s.d $f10,X +add.d $f18,$f18,$f16 +s.d $f18,Z +L.363: +L.360: +L.357: +L.354: +lw $15,NotMonot +bne $15,$0,L.366 +lw $15,Monot +beq $15,$0,L.353 +L.366: +lw $24,Monot +beq $24,$0,L.367 +la $4,L.369 +jal printf +b L.368 +L.367: +la $4,2 +la $5,L.157 +jal BadCond +la $4,L.370 +l.d $f18,Y +mfc1.d $6,$f18 +jal printf +L.368: +la $24,80 +sw $24,Milestone +l.d $f18,Half +l.d $f16,MinSqEr +add.d $f16,$f16,$f18 +s.d $f16,MinSqEr +l.d $f16,MaxSqEr +sub.d $f18,$f16,$f18 +s.d $f18,MaxSqEr +l.d $f18,One +l.d $f16,U2 +add.d $f12,$f18,$f16 +jal sqrt +l.d $f16,One +l.d $f10,U2 +sub.d $f18,$f0,$f16 +div.d $f18,$f18,$f10 +s.d $f18,Y +l.d $f18,Y +sub.d $f18,$f18,$f16 +l.d $f16,Eight +div.d $f16,$f10,$f16 +add.d $f18,$f18,$f16 +s.d $f18,SqEr +l.d $f18,SqEr +l.d $f16,MaxSqEr +c.ule.d $f18,$f16; bc1t L.371 +l.d $f18,SqEr +s.d $f18,MaxSqEr +L.371: +l.d $f18,Y +l.d $f16,U2 +l.d $f10,Eight +div.d $f16,$f16,$f10 +add.d $f18,$f18,$f16 +s.d $f18,SqEr +l.d $f18,SqEr +l.d $f16,MinSqEr +c.lt.d $f18,$f16; bc1f L.373 +l.d $f18,SqEr +s.d $f18,MinSqEr +L.373: +l.d $f12,F9 +jal sqrt +l.d $f16,U2 +l.d $f10,U1 +sub.d $f18,$f0,$f16 +l.d $f8,One +sub.d $f16,$f8,$f16 +sub.d $f18,$f18,$f16 +div.d $f18,$f18,$f10 +s.d $f18,Y +l.d $f18,Y +l.d $f16,Eight +div.d $f16,$f10,$f16 +add.d $f18,$f18,$f16 +s.d $f18,SqEr +l.d $f18,SqEr +l.d $f16,MaxSqEr +c.ule.d $f18,$f16; bc1t L.375 +l.d $f18,SqEr +s.d $f18,MaxSqEr +L.375: +l.d $f18,Y +l.d $f16,One +add.d $f18,$f18,$f16 +l.d $f16,U1 +l.d $f10,Eight +div.d $f16,$f16,$f10 +add.d $f18,$f18,$f16 +s.d $f18,SqEr +l.d $f18,SqEr +l.d $f16,MinSqEr +c.lt.d $f18,$f16; bc1f L.377 +l.d $f18,SqEr +s.d $f18,MinSqEr +L.377: +l.d $f18,U2 +s.d $f18,OneUlp +l.d $f18,OneUlp +s.d $f18,X +la $24,1 +sw $24,Indx +L.379: +l.d $f18,X +l.d $f16,U1 +add.d $f16,$f18,$f16 +add.d $f18,$f16,$f18 +l.d $f16,F9 +add.d $f12,$f18,$f16 +jal sqrt +s.d $f0,Y +l.d $f18,U2 +l.d $f16,X +l.d $f10,OneUlp +l.d $f8,Y +sub.d $f8,$f8,$f18 +l.d $f6,One +sub.d $f18,$f6,$f18 +add.d $f18,$f18,$f16 +sub.d $f18,$f8,$f18 +div.d $f18,$f18,$f10 +s.d $f18,Y +l.d $f18,Half +l.d $f8,U1 +sub.d $f8,$f8,$f16 +l.d $f6,F9 +add.d $f8,$f8,$f6 +mul.d $f8,$f8,$f18 +mul.d $f8,$f8,$f16 +mul.d $f16,$f8,$f16 +div.d $f16,$f16,$f10 +s.d $f16,Z +l.d $f16,Y +add.d $f18,$f16,$f18 +l.d $f16,Z +add.d $f18,$f18,$f16 +s.d $f18,SqEr +l.d $f18,SqEr +l.d $f16,MinSqEr +c.lt.d $f18,$f16; bc1f L.383 +l.d $f18,SqEr +s.d $f18,MinSqEr +L.383: +l.d $f18,Y +l.d $f16,Half +sub.d $f18,$f18,$f16 +l.d $f16,Z +add.d $f18,$f18,$f16 +s.d $f18,SqEr +l.d $f18,SqEr +l.d $f16,MaxSqEr +c.ule.d $f18,$f16; bc1t L.385 +l.d $f18,SqEr +s.d $f18,MaxSqEr +L.385: +lw $24,Indx +la $15,1 +beq $24,$15,L.389 +la $15,3 +bne $24,$15,L.387 +L.389: +l.d $f12,X +jal Sign +mov.d $f18,$f0 +s.d $f18,-128+240($sp) +l.d $f12,OneUlp +jal sqrt +l.d $f16,Eight +l.d $f10,Nine +mul.d $f18,$f10,$f0 +div.d $f12,$f16,$f18 +jal floor +l.d $f16,OneUlp +l.d $f10,-128+240($sp) +mul.d $f16,$f16,$f10 +mul.d $f18,$f16,$f0 +s.d $f18,X +b L.388 +L.387: +l.d $f18,U1 +s.d $f18,OneUlp +l.d $f18,OneUlp +neg.d $f18,$f18 +s.d $f18,X +L.388: +L.380: +lw $24,Indx +la $24,1($24) +sw $24,Indx +lw $24,Indx +la $15,3 +ble $24,$15,L.379 +la $24,85 +sw $24,Milestone +sw $0,SqRWrng +sw $0,Anomaly +sw $0,RSqrt +l.d $f18,Radix +l.d $f16,One +c.eq.d $f18,$f16; bc1t L.390 +la $4,L.392 +jal printf +l.d $f18,Precision +s.d $f18,-128+240($sp) +mov.d $f12,$f18 +jal floor +mov.d $f18,$f0 +l.d $f12,Radix +l.d $f16,One +l.d $f10,-128+240($sp) +add.d $f16,$f16,$f10 +sub.d $f14,$f16,$f18 +jal pow +mov.d $f18,$f0 +l.d $f16,Half +add.d $f12,$f16,$f18 +jal floor +s.d $f0,D +l.d $f18,D +l.d $f16,Radix +div.d $f16,$f18,$f16 +s.d $f16,X +l.d $f16,A1 +div.d $f18,$f18,$f16 +s.d $f18,Y +l.d $f18,X +s.d $f18,-136+240($sp) +mov.d $f12,$f18 +jal floor +l.d $f16,-136+240($sp) +c.eq.d $f16,$f0; bc1f L.395 +l.d $f18,Y +s.d $f18,-144+240($sp) +mov.d $f12,$f18 +jal floor +l.d $f16,-144+240($sp) +c.eq.d $f16,$f0; bc1t L.393 +L.395: +la $24,1 +sw $24,Anomaly +b L.394 +L.393: +l.d $f18,Zero +s.d $f18,X +l.d $f18,X +s.d $f18,Z2 +l.d $f18,One +s.d $f18,Y +l.d $f16,Y +s.d $f16,Y2 +l.d $f16,Radix +sub.d $f18,$f16,$f18 +s.d $f18,Z1 +l.d $f18,Four +l.d $f16,D +mul.d $f18,$f18,$f16 +s.d $f18,FourD +L.396: +l.d $f18,Y2 +l.d $f16,Z2 +c.ule.d $f18,$f16; bc1t L.399 +l.d $f18,Radix +s.d $f18,Q +l.d $f18,Y +s.d $f18,Y1 +L.401: +l.d $f18,Q +s.d $f18,-152+240($sp) +l.d $f16,Half +l.d $f10,Y1 +div.d $f10,$f18,$f10 +sub.d $f12,$f16,$f10 +jal floor +l.d $f16,Y1 +mul.d $f18,$f0,$f16 +l.d $f16,-152+240($sp) +add.d $f12,$f16,$f18 +jal fabs +s.d $f0,X1 +l.d $f18,Y1 +s.d $f18,Q +l.d $f18,X1 +s.d $f18,Y1 +L.402: +l.d $f18,X1 +l.d $f16,Zero +c.le.d $f18,$f16; bc1f L.401 +l.d $f18,Q +l.d $f16,One +c.le.d $f18,$f16; bc1f L.404 +l.d $f18,Y2 +s.d $f18,Z2 +l.d $f18,Y +s.d $f18,Z +L.404: +L.399: +l.d $f18,Y +l.d $f16,Two +add.d $f18,$f18,$f16 +s.d $f18,Y +l.d $f18,X +l.d $f16,Eight +add.d $f18,$f18,$f16 +s.d $f18,X +l.d $f18,Y2 +l.d $f16,X +add.d $f18,$f18,$f16 +s.d $f18,Y2 +l.d $f18,Y2 +l.d $f16,FourD +c.ult.d $f18,$f16; bc1t L.406 +l.d $f18,Y2 +l.d $f16,FourD +sub.d $f18,$f18,$f16 +s.d $f18,Y2 +L.406: +L.397: +l.d $f18,Y +l.d $f16,D +c.ult.d $f18,$f16; bc1t L.396 +l.d $f18,FourD +l.d $f16,Z2 +sub.d $f16,$f18,$f16 +s.d $f16,X8 +l.d $f16,X8 +l.d $f10,Z +mul.d $f10,$f10,$f10 +add.d $f10,$f16,$f10 +div.d $f18,$f10,$f18 +s.d $f18,Q +l.d $f18,Eight +div.d $f18,$f16,$f18 +s.d $f18,X8 +l.d $f18,Q +s.d $f18,-152+240($sp) +mov.d $f12,$f18 +jal floor +l.d $f16,-152+240($sp) +c.eq.d $f16,$f0; bc1t L.408 +la $24,1 +sw $24,Anomaly +b L.409 +L.408: +sw $0,Break +L.410: +l.d $f18,Z1 +l.d $f16,Z +mul.d $f18,$f18,$f16 +s.d $f18,X +l.d $f18,X +s.d $f18,-160+240($sp) +l.d $f16,Radix +div.d $f12,$f18,$f16 +jal floor +l.d $f16,Radix +mul.d $f18,$f0,$f16 +l.d $f16,-160+240($sp) +sub.d $f18,$f16,$f18 +s.d $f18,X +l.d $f18,X +l.d $f16,One +c.eq.d $f18,$f16; bc1f L.413 +la $24,1 +sw $24,Break +b L.414 +L.413: +l.d $f18,Z1 +l.d $f16,One +sub.d $f18,$f18,$f16 +s.d $f18,Z1 +L.414: +L.411: +lw $24,Break +bne $24,$0,L.415 +l.d $f18,Z1 +l.d $f16,Zero +c.le.d $f18,$f16; bc1f L.410 +L.415: +l.d $f18,Z1 +l.d $f16,Zero +c.le.d $f18,$f16; bc1f L.416 +lw $24,Break +bne $24,$0,L.416 +la $24,1 +sw $24,Anomaly +b L.417 +L.416: +l.d $f18,Z1 +l.d $f16,RadixD2 +c.ule.d $f18,$f16; bc1t L.418 +l.d $f18,Z1 +l.d $f16,Radix +sub.d $f18,$f18,$f16 +s.d $f18,Z1 +L.418: +L.420: +jal NewD +L.421: +l.d $f18,U2 +l.d $f16,D +mul.d $f18,$f18,$f16 +l.d $f16,F9 +c.ult.d $f18,$f16; bc1t L.420 +l.d $f18,D +l.d $f16,Radix +mul.d $f16,$f18,$f16 +sub.d $f16,$f16,$f18 +l.d $f10,W +sub.d $f18,$f10,$f18 +c.eq.d $f16,$f18; bc1t L.423 +la $24,1 +sw $24,Anomaly +b L.424 +L.423: +l.d $f18,D +s.d $f18,Z2 +sw $0,I +l.d $f16,Z +l.d $f10,One +add.d $f10,$f10,$f16 +l.d $f8,Half +mul.d $f10,$f10,$f8 +add.d $f10,$f18,$f10 +s.d $f10,Y +add.d $f18,$f18,$f16 +l.d $f16,Q +add.d $f18,$f18,$f16 +s.d $f18,X +jal SR3750 +l.d $f18,D +l.d $f16,Z +l.d $f10,One +sub.d $f10,$f10,$f16 +l.d $f8,Half +mul.d $f10,$f10,$f8 +add.d $f10,$f18,$f10 +add.d $f10,$f10,$f18 +s.d $f10,Y +sub.d $f16,$f18,$f16 +add.d $f18,$f16,$f18 +s.d $f18,X +l.d $f18,X +l.d $f16,Q +add.d $f16,$f18,$f16 +add.d $f18,$f16,$f18 +s.d $f18,X +jal SR3750 +jal NewD +l.d $f18,Z2 +l.d $f16,D +sub.d $f16,$f16,$f18 +l.d $f10,W +sub.d $f18,$f10,$f18 +c.eq.d $f16,$f18; bc1t L.425 +la $24,1 +sw $24,Anomaly +b L.426 +L.425: +l.d $f18,Z2 +l.d $f16,D +sub.d $f16,$f16,$f18 +l.d $f10,Z +l.d $f8,One +sub.d $f8,$f8,$f10 +l.d $f6,Half +mul.d $f8,$f8,$f6 +add.d $f8,$f18,$f8 +add.d $f8,$f16,$f8 +s.d $f8,Y +sub.d $f18,$f18,$f10 +l.d $f10,Q +add.d $f18,$f18,$f10 +add.d $f18,$f16,$f18 +s.d $f18,X +jal SR3750 +l.d $f18,One +l.d $f16,Z +add.d $f18,$f18,$f16 +l.d $f16,Half +mul.d $f18,$f18,$f16 +s.d $f18,Y +l.d $f18,Q +s.d $f18,X +jal SR3750 +lw $24,I +bne $24,$0,L.427 +la $24,1 +sw $24,Anomaly +L.427: +L.426: +L.424: +L.417: +L.409: +L.394: +lw $15,I +beq $15,$0,L.431 +lw $15,Anomaly +beq $15,$0,L.429 +L.431: +move $4,$0 +la $5,L.432 +jal BadCond +la $4,L.433 +l.d $f18,W +mfc1.d $6,$f18 +jal printf +la $4,L.434 +jal printf +la $24,1 +sw $24,SqRWrng +L.429: +L.390: +lw $24,Anomaly +bne $24,$0,L.435 +l.d $f18,Zero +l.d $f16,MinSqEr +c.ult.d $f16,$f18; bc1t L.437 +l.d $f16,MaxSqEr +c.le.d $f16,$f18; bc1f L.437 +la $24,1 +sw $24,RSqrt +la $4,L.439 +jal printf +b L.438 +L.437: +l.d $f18,U2 +l.d $f16,Half +l.d $f10,MaxSqEr +add.d $f10,$f10,$f18 +sub.d $f18,$f18,$f16 +c.le.d $f10,$f18; bc1f L.443 +l.d $f18,MinSqEr +c.le.d $f18,$f16; bc1f L.443 +l.d $f10,Radix +add.d $f18,$f18,$f10 +c.lt.d $f18,$f16; bc1f L.440 +L.443: +la $24,1 +sw $24,SqRWrng +b L.441 +L.440: +la $24,2 +sw $24,RSqrt +la $4,L.444 +jal printf +L.441: +L.438: +L.435: +lw $24,SqRWrng +beq $24,$0,L.445 +la $4,L.447 +jal printf +la $4,L.448 +l.d $f18,MinSqEr +l.d $f16,Half +sub.d $f18,$f18,$f16 +mfc1.d $6,$f18 +jal printf +la $4,L.449 +l.d $f18,Half +l.d $f16,MaxSqEr +add.d $f18,$f18,$f16 +mfc1.d $6,$f18 +jal printf +la $4,1 +l.d $f18,Radix +l.d $f16,MaxSqEr +l.d $f10,MinSqEr +sub.d $f16,$f16,$f10 +mul.d $f18,$f18,$f18 +c.lt.d $f16,$f18; bc1f L.452 +la $24,1 +sw $24,-124+240($sp) +b L.453 +L.452: +sw $0,-124+240($sp) +L.453: +lw $5,-124+240($sp) +la $6,L.451 +jal TstCond +L.445: +la $24,90 +sw $24,Milestone +jal Pause +la $4,L.454 +jal printf +sw $0,N +sw $0,I +l.d $f18,Zero +neg.d $f18,$f18 +s.d $f18,Z +la $15,3 +sw $15,M +sw $0,Break +L.455: +l.d $f18,One +s.d $f18,X +jal SR3980 +lw $24,I +la $15,10 +bgt $24,$15,L.458 +la $24,1023 +sw $24,I +jal SR3980 +L.458: +l.d $f18,Z +l.d $f16,MinusOne +c.eq.d $f18,$f16; bc1f L.460 +la $24,1 +sw $24,Break +b L.461 +L.460: +l.d $f18,MinusOne +s.d $f18,Z +jal PrintIfNPositive +sw $0,N +la $24,-4 +sw $24,I +L.461: +L.456: +lw $24,Break +beq $24,$0,L.455 +jal PrintIfNPositive +lw $24,N +sw $24,N1 +sw $0,N +l.d $f18,A1 +s.d $f18,Z +l.d $f12,W +jal log +mov.d $f18,$f0 +s.d $f18,-128+240($sp) +l.d $f12,A1 +jal log +mov.d $f18,$f0 +l.d $f16,Two +l.d $f10,-128+240($sp) +mul.d $f16,$f16,$f10 +div.d $f12,$f16,$f18 +jal floor +trunc.w.d $f2,$f0,$24; mfc1 $24,$f2 +sw $24,M +sw $0,Break +L.462: +l.d $f18,Z +s.d $f18,X +la $24,1 +sw $24,I +jal SR3980 +l.d $f18,Z +l.d $f16,AInvrse +c.eq.d $f18,$f16; bc1f L.465 +la $24,1 +sw $24,Break +b L.466 +L.465: +l.d $f18,AInvrse +s.d $f18,Z +L.466: +L.463: +lw $24,Break +beq $24,$0,L.462 +la $24,100 +sw $24,Milestone +lw $24,NoTrials +sw $24,M +l.d $f18,Three +s.d $f18,Z +L.467: +l.d $f18,Z +s.d $f18,X +la $24,1 +sw $24,I +jal SR3980 +L.470: +l.d $f18,Z +l.d $f16,Two +add.d $f18,$f18,$f16 +s.d $f18,Z +L.471: +l.d $f18,Three +s.d $f18,-136+240($sp) +l.d $f16,Z +div.d $f12,$f16,$f18 +jal floor +l.d $f16,-136+240($sp) +mul.d $f18,$f16,$f0 +l.d $f16,Z +c.eq.d $f18,$f16; bc1t L.470 +L.468: +l.d $f18,Z +l.d $f16,Eight +l.d $f10,Three +mul.d $f16,$f16,$f10 +c.ult.d $f18,$f16; bc1t L.467 +lw $24,N +ble $24,$0,L.473 +la $4,L.475 +jal printf +la $4,L.476 +jal printf +L.473: +jal PrintIfNPositive +lw $24,N +lw $15,N1 +addu $24,$24,$15 +sw $24,N +lw $24,N +bne $24,$0,L.477 +la $4,L.479 +jal printf +L.477: +lw $24,N +ble $24,$0,L.480 +jal Pause +b L.481 +L.480: +la $4,L.44 +jal printf +L.481: +la $24,110 +sw $24,Milestone +la $4,L.482 +jal printf +l.d $f18,U1 +s.d $f18,D +l.d $f18,Precision +s.d $f18,-136+240($sp) +mov.d $f12,$f18 +jal floor +l.d $f16,-136+240($sp) +c.eq.d $f16,$f0; bc1t L.483 +l.d $f18,BInvrse +s.d $f18,D +l.d $f18,Precision +s.d $f18,X +L.485: +l.d $f18,D +l.d $f16,BInvrse +mul.d $f18,$f18,$f16 +s.d $f18,D +l.d $f18,X +l.d $f16,One +sub.d $f18,$f18,$f16 +s.d $f18,X +L.486: +l.d $f18,X +l.d $f16,Zero +c.le.d $f18,$f16; bc1f L.485 +L.483: +l.d $f18,One +s.d $f18,Y +l.d $f18,D +s.d $f18,Z +L.488: +l.d $f18,Y +s.d $f18,C +l.d $f18,Z +s.d $f18,Y +l.d $f18,Y +mul.d $f18,$f18,$f18 +s.d $f18,Z +L.489: +l.d $f18,Z +l.d $f16,Y +c.ule.d $f16,$f18; bc1t L.491 +add.d $f16,$f18,$f18 +c.le.d $f16,$f18; bc1f L.488 +L.491: +l.d $f18,C +s.d $f18,Y +l.d $f18,Y +l.d $f16,D +mul.d $f18,$f18,$f16 +s.d $f18,Z +L.492: +l.d $f18,Y +s.d $f18,C +l.d $f18,Z +s.d $f18,Y +l.d $f18,Y +l.d $f16,D +mul.d $f18,$f18,$f16 +s.d $f18,Z +L.493: +l.d $f18,Z +l.d $f16,Y +c.ule.d $f16,$f18; bc1t L.495 +add.d $f16,$f18,$f18 +c.le.d $f16,$f18; bc1f L.492 +L.495: +l.d $f18,Radix +l.d $f16,Two +c.lt.d $f18,$f16; bc1f L.496 +l.d $f18,Two +s.d $f18,HInvrse +b L.497 +L.496: +l.d $f18,Radix +s.d $f18,HInvrse +L.497: +l.d $f18,One +l.d $f16,HInvrse +div.d $f16,$f18,$f16 +s.d $f16,H +l.d $f16,C +div.d $f18,$f18,$f16 +s.d $f18,CInvrse +s.d $f16,E0 +l.d $f18,E0 +l.d $f16,H +mul.d $f18,$f18,$f16 +s.d $f18,Z +L.498: +l.d $f18,E0 +s.d $f18,Y +l.d $f18,Z +s.d $f18,E0 +l.d $f18,E0 +l.d $f16,H +mul.d $f18,$f18,$f16 +s.d $f18,Z +L.499: +l.d $f18,Z +l.d $f16,E0 +c.ule.d $f16,$f18; bc1t L.501 +add.d $f16,$f18,$f18 +c.le.d $f16,$f18; bc1f L.498 +L.501: +l.d $f18,E0 +s.d $f18,UfThold +l.d $f18,Zero +s.d $f18,E1 +s.d $f18,Q +l.d $f18,U2 +s.d $f18,E9 +l.d $f18,One +l.d $f16,E9 +add.d $f18,$f18,$f16 +s.d $f18,S +l.d $f18,C +l.d $f16,S +mul.d $f16,$f18,$f16 +s.d $f16,D +l.d $f16,D +c.le.d $f16,$f18; bc1f L.502 +l.d $f18,Radix +l.d $f16,U2 +mul.d $f18,$f18,$f16 +s.d $f18,E9 +l.d $f18,One +l.d $f16,E9 +add.d $f18,$f18,$f16 +s.d $f18,S +l.d $f18,C +l.d $f16,S +mul.d $f16,$f18,$f16 +s.d $f16,D +l.d $f16,D +c.le.d $f16,$f18; bc1f L.503 +move $4,$0 +la $5,L.506 +jal BadCond +l.d $f18,E0 +s.d $f18,Underflow +l.d $f18,Zero +s.d $f18,Y1 +l.d $f18,Z +s.d $f18,PseudoZero +jal Pause +b L.503 +L.502: +l.d $f18,D +s.d $f18,Underflow +l.d $f18,Underflow +l.d $f16,H +mul.d $f18,$f18,$f16 +s.d $f18,PseudoZero +l.d $f18,Zero +s.d $f18,UfThold +L.507: +l.d $f18,Underflow +s.d $f18,Y1 +l.d $f18,PseudoZero +s.d $f18,Underflow +l.d $f18,E1 +add.d $f16,$f18,$f18 +c.le.d $f16,$f18; bc1f L.510 +l.d $f18,Underflow +l.d $f16,HInvrse +mul.d $f18,$f18,$f16 +s.d $f18,Y2 +l.d $f18,Y1 +l.d $f16,Y2 +sub.d $f12,$f18,$f16 +jal fabs +s.d $f0,E1 +l.d $f18,Y1 +s.d $f18,Q +l.d $f18,UfThold +l.d $f16,Zero +c.eq.d $f18,$f16; bc1f L.512 +l.d $f18,Y1 +l.d $f16,Y2 +c.eq.d $f18,$f16; bc1t L.512 +l.d $f18,Y1 +s.d $f18,UfThold +L.512: +L.510: +l.d $f18,PseudoZero +l.d $f16,H +mul.d $f18,$f18,$f16 +s.d $f18,PseudoZero +L.508: +l.d $f18,PseudoZero +l.d $f16,Underflow +c.ule.d $f16,$f18; bc1t L.514 +add.d $f16,$f18,$f18 +c.le.d $f16,$f18; bc1f L.507 +L.514: +L.503: +l.d $f18,PseudoZero +l.d $f16,Zero +c.eq.d $f18,$f16; bc1t L.515 +la $4,L.44 +jal printf +l.d $f18,PseudoZero +s.d $f18,Z +l.d $f16,Zero +c.le.d $f18,$f16; bc1f L.517 +move $4,$0 +la $5,L.519 +jal BadCond +la $4,L.520 +jal printf +la $4,L.521 +l.d $f18,PseudoZero +mfc1.d $6,$f18 +jal printf +l.d $f18,PseudoZero +neg.d $f18,$f18 +s.d $f18,X +l.d $f18,X +l.d $f16,Zero +c.le.d $f18,$f16; bc1f L.518 +la $4,L.524 +jal printf +la $4,L.525 +l.d $f18,X +mfc1.d $6,$f18 +jal printf +b L.518 +L.517: +la $4,3 +la $5,L.526 +jal BadCond +la $4,L.527 +l.d $f18,PseudoZero +mfc1.d $6,$f18 +jal printf +L.518: +jal TstPtUf +L.515: +la $24,120 +sw $24,Milestone +l.d $f18,CInvrse +l.d $f16,Y +mul.d $f16,$f18,$f16 +l.d $f10,Y1 +mul.d $f18,$f18,$f10 +c.ule.d $f16,$f18; bc1t L.528 +l.d $f18,H +l.d $f16,S +mul.d $f18,$f18,$f16 +s.d $f18,S +l.d $f18,Underflow +s.d $f18,E0 +L.528: +l.d $f18,E1 +l.d $f16,Zero +c.eq.d $f18,$f16; bc1t L.530 +l.d $f16,E0 +c.eq.d $f18,$f16; bc1t L.530 +la $4,2 +la $5,L.157 +jal BadCond +l.d $f18,E1 +l.d $f16,E0 +c.lt.d $f18,$f16; bc1f L.532 +la $4,L.534 +jal printf +la $4,L.535 +jal printf +l.d $f18,PseudoZero +l.d $f16,Zero +c.eq.d $f18,$f16; bc1f L.533 +l.d $f18,E1 +s.d $f18,E0 +b L.533 +L.532: +la $4,L.538 +jal printf +la $4,L.539 +jal printf +L.533: +L.530: +la $4,L.540 +l.d $f18,E0 +mfc1.d $6,$f18 +jal printf +l.d $f18,E0 +s.d $f18,Z +jal TstPtUf +l.d $f18,E0 +s.d $f18,Underflow +lw $24,N +la $15,1 +bne $24,$15,L.541 +l.d $f18,Y +s.d $f18,Underflow +L.541: +la $24,4 +sw $24,I +l.d $f18,E1 +l.d $f16,Zero +c.eq.d $f18,$f16; bc1f L.543 +la $24,3 +sw $24,I +L.543: +l.d $f18,UfThold +l.d $f16,Zero +c.eq.d $f18,$f16; bc1f L.545 +lw $24,I +subu $24,$24,2 +sw $24,I +L.545: +la $24,1 +sw $24,UfNGrad +lw $24,I +la $15,1 +blt $24,$15,L.547 +la $15,4 +bgt $24,$15,L.547 +sll $24,$24,2 +lw $24,L.570-4($24) +.cpadd $24 +j $24 +.rdata +.align 2 +L.570: +.gpword L.549 +.gpword L.556 +.gpword L.561 +.gpword L.562 +.text +L.549: +l.d $f18,Underflow +s.d $f18,UfThold +l.d $f18,CInvrse +l.d $f16,Q +mul.d $f16,$f18,$f16 +l.d $f10,Y +mul.d $f18,$f18,$f10 +l.d $f10,S +mul.d $f18,$f18,$f10 +c.eq.d $f16,$f18; bc1t L.550 +l.d $f18,Y +s.d $f18,UfThold +move $4,$0 +la $5,L.552 +jal BadCond +la $4,L.553 +l.d $f18,UfThold +mfc1.d $6,$f18 +jal printf +la $4,L.554 +l.d $f18,C +mfc1.d $6,$f18 +jal printf +la $4,L.555 +jal printf +L.550: +jal Pause +b L.548 +L.556: +move $4,$0 +la $5,L.557 +jal BadCond +la $4,L.558 +jal printf +la $4,L.559 +l.d $f18,Q +mfc1.d $6,$f18 +l.d $f18,Y2 +s.d $f18,16($sp) +jal printf +l.d $f18,Q +l.d $f16,Y2 +sub.d $f12,$f18,$f16 +jal fabs +mov.d $f18,$f0 +la $4,L.560 +mfc1.d $6,$f18 +jal printf +l.d $f18,Q +s.d $f18,UfThold +b L.548 +L.561: +l.d $f18,X +s.d $f18,X +b L.548 +L.562: +l.d $f18,UfThold +l.d $f16,Q +c.eq.d $f16,$f18; bc1f L.563 +l.d $f16,E1 +l.d $f10,E0 +c.eq.d $f16,$f10; bc1f L.563 +l.d $f10,E9 +div.d $f16,$f16,$f10 +sub.d $f12,$f18,$f16 +jal fabs +l.d $f16,E1 +c.le.d $f0,$f16; bc1f L.563 +sw $0,UfNGrad +la $4,L.565 +jal printf +la $4,L.566 +jal printf +l.d $f18,E0 +l.d $f16,CInvrse +mul.d $f10,$f18,$f16 +s.d $f10,Y +l.d $f10,U2 +l.d $f8,Y +l.d $f6,OneAndHalf +add.d $f6,$f6,$f10 +mul.d $f8,$f8,$f6 +s.d $f8,Y +l.d $f8,One +add.d $f10,$f8,$f10 +mul.d $f16,$f16,$f10 +s.d $f16,X +l.d $f16,Y +l.d $f10,X +div.d $f16,$f16,$f10 +s.d $f16,Y +l.d $f16,Y +c.eq.d $f16,$f18; bc1f L.568 +la $24,1 +sw $24,-140+240($sp) +b L.569 +L.568: +sw $0,-140+240($sp) +L.569: +lw $24,-140+240($sp) +sw $24,IEEE +L.563: +L.547: +L.548: +lw $24,UfNGrad +beq $24,$0,L.572 +la $4,L.44 +jal printf +la $24,sigfpe +sw $24,sigsave +la $4,ovfl_buf +jal setjmp +beq $2,$0,L.574 +la $4,L.576 +jal printf +l.d $f18,H +add.d $f18,$f18,$f18 +s.d $f18,R +b L.575 +L.574: +l.d $f18,Underflow +l.d $f16,UfThold +div.d $f12,$f18,$f16 +jal sqrt +s.d $f0,R +L.575: +sw $0,sigsave +l.d $f18,R +l.d $f16,H +c.le.d $f18,$f16; bc1f L.577 +l.d $f18,R +l.d $f16,UfThold +mul.d $f16,$f18,$f16 +s.d $f16,Z +l.d $f16,One +l.d $f10,H +l.d $f8,Z +mul.d $f18,$f18,$f10 +add.d $f10,$f16,$f10 +mul.d $f18,$f18,$f10 +add.d $f18,$f16,$f18 +mul.d $f18,$f8,$f18 +s.d $f18,X +b L.578 +L.577: +l.d $f18,UfThold +s.d $f18,Z +l.d $f18,One +l.d $f16,H +l.d $f10,Z +mul.d $f8,$f16,$f16 +add.d $f16,$f18,$f16 +mul.d $f16,$f8,$f16 +add.d $f18,$f18,$f16 +mul.d $f18,$f10,$f18 +s.d $f18,X +L.578: +l.d $f18,X +l.d $f16,Z +c.eq.d $f18,$f16; bc1t L.579 +sub.d $f18,$f18,$f16 +l.d $f16,Zero +c.eq.d $f18,$f16; bc1f L.579 +la $4,3 +la $5,L.157 +jal BadCond +la $4,L.581 +l.d $f18,X +mfc1.d $6,$f18 +l.d $f18,Z +s.d $f18,16($sp) +jal printf +l.d $f18,X +l.d $f16,Z +sub.d $f18,$f18,$f16 +s.d $f18,Z9 +la $4,L.582 +l.d $f18,Z9 +mfc1.d $6,$f18 +jal printf +la $4,L.583 +jal printf +la $4,L.584 +jal printf +la $4,L.585 +jal printf +la $4,L.586 +jal printf +la $4,L.587 +jal printf +la $4,L.588 +jal printf +la $24,sigfpe +sw $24,sigsave +la $4,ovfl_buf +jal setjmp +beq $2,$0,L.589 +la $4,L.591 +jal printf +b L.590 +L.589: +la $4,L.592 +l.d $f18,Half +l.d $f16,X +l.d $f10,Z +div.d $f16,$f16,$f10 +sub.d $f16,$f16,$f18 +sub.d $f18,$f16,$f18 +mfc1.d $6,$f18 +jal printf +L.590: +sw $0,sigsave +L.579: +L.572: +la $4,L.593 +l.d $f18,UfThold +mfc1.d $6,$f18 +la $24,L.594 +sw $24,16($sp) +jal printf +la $4,L.595 +jal printf +la $4,L.596 +jal printf +l.d $f18,U1 +mul.d $f16,$f18,$f18 +s.d $f16,Y2 +l.d $f16,Y2 +mul.d $f16,$f16,$f16 +s.d $f16,Y +l.d $f16,Y +mul.d $f18,$f16,$f18 +s.d $f18,Y2 +l.d $f18,Y2 +l.d $f16,UfThold +c.le.d $f18,$f16; bc1f L.597 +l.d $f18,Y +l.d $f16,E0 +c.ule.d $f18,$f16; bc1t L.599 +la $4,2 +la $5,L.157 +jal BadCond +la $24,5 +sw $24,I +b L.600 +L.599: +la $4,1 +la $5,L.157 +jal BadCond +la $24,4 +sw $24,I +L.600: +la $4,L.601 +lw $5,I +jal printf +L.597: +la $24,130 +sw $24,Milestone +l.d $f12,UfThold +jal log +mov.d $f18,$f0 +s.d $f18,-144+240($sp) +l.d $f12,HInvrse +jal log +l.d $f16,Half +l.d $f10,TwoForty +l.d $f8,-144+240($sp) +mul.d $f10,$f10,$f8 +div.d $f18,$f10,$f0 +sub.d $f12,$f16,$f18 +jal floor +neg.d $f18,$f0 +l.d $f16,TwoForty +div.d $f18,$f18,$f16 +s.d $f18,Y +l.d $f18,Y +add.d $f18,$f18,$f18 +s.d $f18,Y2 +la $4,L.602 +jal printf +la $4,L.603 +l.d $f18,HInvrse +mfc1.d $6,$f18 +l.d $f18,Y +s.d $f18,16($sp) +jal printf +la $4,L.604 +l.d $f18,HInvrse +mfc1.d $6,$f18 +l.d $f18,Y +s.d $f18,16($sp) +jal printf +l.d $f12,HInvrse +l.d $f14,Y2 +jal pow +s.d $f0,V9 +la $4,L.605 +l.d $f18,V9 +mfc1.d $6,$f18 +jal printf +l.d $f18,V9 +l.d $f16,Zero +c.ult.d $f18,$f16; bc1t L.608 +l.d $f16,Radix +add.d $f16,$f16,$f16 +l.d $f10,E9 +add.d $f16,$f16,$f10 +l.d $f10,UfThold +mul.d $f16,$f16,$f10 +c.ule.d $f18,$f16; bc1t L.606 +L.608: +la $4,1 +la $5,L.609 +jal BadCond +la $4,L.610 +l.d $f18,UfThold +mfc1.d $6,$f18 +jal printf +b L.607 +L.606: +l.d $f18,V9 +l.d $f16,UfThold +l.d $f10,One +l.d $f8,E9 +add.d $f10,$f10,$f8 +mul.d $f16,$f16,$f10 +c.le.d $f18,$f16; bc1f L.611 +la $4,L.613 +jal printf +b L.612 +L.611: +la $4,2 +la $5,L.609 +jal BadCond +la $4,L.610 +l.d $f18,UfThold +mfc1.d $6,$f18 +jal printf +L.612: +L.607: +la $24,140 +sw $24,Milestone +la $4,L.44 +jal printf +l.d $f18,Zero +s.d $f18,X +la $24,2 +sw $24,I +l.d $f16,Two +l.d $f10,Three +mul.d $f16,$f16,$f10 +s.d $f16,Y +s.d $f18,Q +sw $0,N +L.614: +l.d $f18,X +s.d $f18,Z +lw $24,I +la $24,1($24) +sw $24,I +lw $24,I +l.d $f18,Y +addu $24,$24,$24 +mtc1 $24,$f16; cvt.d.w $f16,$f16 +div.d $f18,$f18,$f16 +s.d $f18,Y +l.d $f18,Y +l.d $f16,Q +add.d $f18,$f18,$f16 +s.d $f18,R +l.d $f18,Z +l.d $f16,R +add.d $f10,$f18,$f16 +s.d $f10,X +l.d $f10,X +sub.d $f18,$f18,$f10 +add.d $f18,$f18,$f16 +s.d $f18,Q +L.615: +l.d $f18,X +l.d $f16,Z +c.le.d $f18,$f16; bc1f L.614 +l.d $f18,OneAndHalf +l.d $f16,One +l.d $f10,Eight +div.d $f16,$f16,$f10 +add.d $f16,$f18,$f16 +l.d $f10,X +l.d $f8,ThirtyTwo +mul.d $f18,$f18,$f8 +div.d $f18,$f10,$f18 +add.d $f18,$f16,$f18 +s.d $f18,Z +l.d $f18,Z +mul.d $f18,$f18,$f18 +s.d $f18,X +l.d $f18,X +mul.d $f18,$f18,$f18 +s.d $f18,Exp2 +l.d $f18,F9 +s.d $f18,X +l.d $f18,X +l.d $f16,U1 +sub.d $f18,$f18,$f16 +s.d $f18,Y +la $4,L.617 +l.d $f18,Exp2 +mfc1.d $6,$f18 +jal printf +la $24,1 +sw $24,I +L.618: +l.d $f18,X +l.d $f16,BInvrse +sub.d $f10,$f18,$f16 +s.d $f10,Z +l.d $f10,One +add.d $f8,$f18,$f10 +l.d $f6,Z +sub.d $f16,$f10,$f16 +sub.d $f16,$f6,$f16 +div.d $f16,$f8,$f16 +s.d $f16,Z +mov.d $f12,$f18 +l.d $f14,Z +jal pow +l.d $f16,Exp2 +sub.d $f18,$f0,$f16 +s.d $f18,Q +l.d $f12,Q +jal fabs +l.d $f16,TwoForty +l.d $f10,U2 +mul.d $f16,$f16,$f10 +c.ule.d $f0,$f16; bc1t L.622 +la $24,1 +sw $24,N +l.d $f18,BInvrse +l.d $f16,X +sub.d $f16,$f16,$f18 +l.d $f10,One +sub.d $f18,$f10,$f18 +sub.d $f18,$f16,$f18 +s.d $f18,V9 +la $4,2 +la $5,L.624 +jal BadCond +l.d $f12,X +l.d $f14,Z +jal pow +mov.d $f18,$f0 +la $4,L.625 +mfc1.d $6,$f18 +jal printf +la $4,L.626 +l.d $f18,V9 +mfc1.d $6,$f18 +l.d $f18,Z +s.d $f18,16($sp) +jal printf +la $4,L.627 +l.d $f18,Q +mfc1.d $6,$f18 +jal printf +la $4,L.628 +jal printf +la $4,L.629 +jal printf +b L.620 +L.622: +l.d $f18,Y +l.d $f16,X +sub.d $f16,$f18,$f16 +l.d $f10,Two +mul.d $f16,$f16,$f10 +add.d $f16,$f16,$f18 +s.d $f16,Z +s.d $f18,X +l.d $f18,Z +s.d $f18,Y +l.d $f18,X +l.d $f16,F9 +sub.d $f18,$f18,$f16 +l.d $f16,One +mul.d $f18,$f18,$f18 +add.d $f18,$f16,$f18 +s.d $f18,Z +l.d $f18,Z +l.d $f16,One +c.ule.d $f18,$f16; bc1t L.630 +lw $24,I +lw $15,NoTrials +bge $24,$15,L.630 +lw $24,I +la $24,1($24) +sw $24,I +b L.618 +L.630: +l.d $f18,X +l.d $f16,One +c.ule.d $f18,$f16; bc1t L.632 +lw $24,N +bne $24,$0,L.620 +la $4,L.636 +jal printf +b L.620 +L.632: +l.d $f18,U2 +l.d $f16,One +add.d $f16,$f16,$f18 +s.d $f16,X +add.d $f18,$f18,$f18 +s.d $f18,Y +l.d $f18,Y +l.d $f16,X +add.d $f18,$f18,$f16 +s.d $f18,Y +la $24,1 +sw $24,I +b L.618 +L.620: +la $24,150 +sw $24,Milestone +la $4,L.637 +jal printf +sw $0,N +l.d $f18,A1 +s.d $f18,Z +l.d $f12,C +jal log +mov.d $f18,$f0 +s.d $f18,-152+240($sp) +l.d $f12,A1 +jal log +l.d $f16,Half +l.d $f10,-152+240($sp) +div.d $f18,$f10,$f0 +sub.d $f12,$f16,$f18 +jal floor +s.d $f0,Q +sw $0,Break +L.638: +l.d $f18,CInvrse +s.d $f18,X +l.d $f12,Z +l.d $f14,Q +jal pow +s.d $f0,Y +jal IsYeqX +l.d $f18,Q +neg.d $f18,$f18 +s.d $f18,Q +l.d $f18,C +s.d $f18,X +l.d $f12,Z +l.d $f14,Q +jal pow +s.d $f0,Y +jal IsYeqX +l.d $f18,Z +l.d $f16,One +c.lt.d $f18,$f16; bc1f L.641 +la $24,1 +sw $24,Break +b L.642 +L.641: +l.d $f18,AInvrse +s.d $f18,Z +L.642: +L.639: +lw $24,Break +beq $24,$0,L.638 +jal PrintIfNPositive +lw $24,N +bne $24,$0,L.643 +la $4,L.645 +jal printf +L.643: +la $4,L.44 +jal printf +la $24,160 +sw $24,Milestone +jal Pause +la $4,L.646 +jal printf +la $4,L.647 +jal printf +l.d $f18,CInvrse +neg.d $f18,$f18 +s.d $f18,Y +l.d $f18,HInvrse +l.d $f16,Y +mul.d $f18,$f18,$f16 +s.d $f18,V9 +la $24,sigfpe +sw $24,sigsave +la $4,ovfl_buf +jal setjmp +beq $2,$0,L.648 +sw $0,I +l.d $f18,Y +s.d $f18,V9 +b L.650 +L.648: +L.651: +l.d $f18,Y +s.d $f18,V +l.d $f18,V9 +s.d $f18,Y +l.d $f18,HInvrse +l.d $f16,Y +mul.d $f18,$f18,$f16 +s.d $f18,V9 +L.652: +l.d $f18,V9 +l.d $f16,Y +c.ult.d $f18,$f16; bc1t L.651 +la $24,1 +sw $24,I +L.650: +sw $0,sigsave +l.d $f18,V9 +s.d $f18,Z +la $4,L.654 +jal printf +la $4,L.655 +l.d $f18,Y +mfc1.d $6,$f18 +jal printf +l.d $f18,Y +neg.d $f16,$f18 +s.d $f16,V9 +l.d $f16,V9 +s.d $f16,V0 +l.d $f16,V +sub.d $f18,$f16,$f18 +l.d $f10,V0 +add.d $f16,$f16,$f10 +c.eq.d $f18,$f16; bc1f L.656 +la $4,L.658 +jal printf +b L.657 +L.656: +la $4,L.659 +jal printf +la $4,3 +la $5,L.660 +jal BadCond +L.657: +l.d $f18,Z +l.d $f16,Y +c.eq.d $f18,$f16; bc1t L.661 +la $4,1 +la $5,L.157 +jal BadCond +la $4,L.663 +l.d $f18,Y +mfc1.d $6,$f18 +l.d $f18,Z +s.d $f18,16($sp) +jal printf +L.661: +lw $24,I +beq $24,$0,L.664 +l.d $f18,V +l.d $f16,HInvrse +l.d $f10,U2 +mul.d $f8,$f16,$f10 +sub.d $f8,$f8,$f16 +mul.d $f8,$f18,$f8 +s.d $f8,Y +l.d $f8,Y +l.d $f6,One +sub.d $f16,$f6,$f16 +mul.d $f16,$f16,$f10 +mul.d $f18,$f16,$f18 +add.d $f18,$f8,$f18 +s.d $f18,Z +l.d $f18,Z +l.d $f16,V0 +c.lt.d $f18,$f16; bc1f L.666 +l.d $f18,Z +s.d $f18,Y +L.666: +l.d $f18,Y +l.d $f16,V0 +c.lt.d $f18,$f16; bc1f L.668 +l.d $f18,Y +s.d $f18,V +L.668: +l.d $f18,V0 +l.d $f16,V +sub.d $f16,$f18,$f16 +c.lt.d $f16,$f18; bc1f L.665 +l.d $f18,V0 +s.d $f18,V +b L.665 +L.664: +l.d $f18,Y +l.d $f16,HInvrse +l.d $f10,U2 +mul.d $f8,$f16,$f10 +sub.d $f8,$f8,$f16 +mul.d $f8,$f18,$f8 +s.d $f8,V +l.d $f8,V +l.d $f6,One +sub.d $f16,$f6,$f16 +mul.d $f16,$f16,$f10 +mul.d $f18,$f16,$f18 +add.d $f18,$f8,$f18 +s.d $f18,V +L.665: +la $4,L.672 +l.d $f18,V +mfc1.d $6,$f18 +jal printf +lw $24,I +beq $24,$0,L.673 +la $4,L.675 +l.d $f18,V0 +mfc1.d $6,$f18 +jal printf +b L.674 +L.673: +la $4,L.676 +jal printf +L.674: +l.d $f18,V +l.d $f16,One +mul.d $f18,$f18,$f16 +s.d $f18,V9 +la $4,L.677 +l.d $f18,V9 +mfc1.d $6,$f18 +jal printf +l.d $f18,V +l.d $f16,One +div.d $f18,$f18,$f16 +s.d $f18,V9 +la $4,L.678 +l.d $f18,V9 +mfc1.d $6,$f18 +jal printf +la $4,L.679 +jal printf +la $4,L.680 +jal printf +la $24,170 +sw $24,Milestone +l.d $f18,V +neg.d $f16,$f18 +c.lt.d $f16,$f18; bc1f L.685 +l.d $f16,V0 +neg.d $f10,$f16 +c.lt.d $f10,$f16; bc1f L.685 +l.d $f16,UfThold +neg.d $f10,$f16 +c.lt.d $f10,$f18; bc1f L.685 +c.ult.d $f16,$f18; bc1t L.681 +L.685: +move $4,$0 +la $5,L.686 +jal BadCond +la $4,L.687 +l.d $f18,V +mfc1.d $6,$f18 +l.d $f18,V0 +s.d $f18,16($sp) +l.d $f18,UfThold +s.d $f18,24($sp) +jal printf +L.681: +la $24,175 +sw $24,Milestone +la $4,L.44 +jal printf +la $24,1 +sw $24,Indx +L.688: +lw $24,Indx +la $15,1 +beq $24,$15,L.694 +la $15,2 +beq $24,$15,L.695 +la $15,3 +beq $24,$15,L.696 +b L.692 +L.694: +l.d $f18,UfThold +s.d $f18,Z +b L.693 +L.695: +l.d $f18,E0 +s.d $f18,Z +b L.693 +L.696: +l.d $f18,PseudoZero +s.d $f18,Z +L.692: +L.693: +l.d $f18,Z +l.d $f16,Zero +c.eq.d $f18,$f16; bc1t L.697 +l.d $f12,Z +jal sqrt +s.d $f0,V9 +l.d $f18,V9 +mul.d $f18,$f18,$f18 +s.d $f18,Y +l.d $f18,Y +l.d $f16,One +l.d $f10,Radix +l.d $f8,E9 +mul.d $f10,$f10,$f8 +l.d $f8,Z +sub.d $f6,$f16,$f10 +div.d $f6,$f18,$f6 +c.ult.d $f6,$f8; bc1t L.701 +add.d $f16,$f16,$f10 +mul.d $f16,$f16,$f8 +c.ule.d $f18,$f16; bc1t L.699 +L.701: +l.d $f18,V9 +l.d $f16,U1 +c.ule.d $f18,$f16; bc1t L.702 +la $4,1 +la $5,L.157 +jal BadCond +b L.703 +L.702: +la $4,2 +la $5,L.157 +jal BadCond +L.703: +la $4,L.704 +l.d $f18,Z +mfc1.d $6,$f18 +jal printf +la $4,L.705 +l.d $f18,Y +mfc1.d $6,$f18 +jal printf +L.699: +L.697: +L.689: +lw $24,Indx +la $24,1($24) +sw $24,Indx +lw $24,Indx +la $15,3 +ble $24,$15,L.688 +la $24,180 +sw $24,Milestone +la $24,1 +sw $24,Indx +L.706: +lw $24,Indx +la $15,1 +bne $24,$15,L.710 +l.d $f18,V +s.d $f18,Z +b L.711 +L.710: +l.d $f18,V0 +s.d $f18,Z +L.711: +l.d $f12,Z +jal sqrt +s.d $f0,V9 +l.d $f18,V9 +l.d $f16,One +l.d $f10,Radix +l.d $f8,E9 +mul.d $f10,$f10,$f8 +sub.d $f16,$f16,$f10 +mul.d $f16,$f16,$f18 +s.d $f16,X +l.d $f16,X +mul.d $f18,$f18,$f16 +s.d $f18,V9 +l.d $f18,V9 +l.d $f16,Z +l.d $f10,One +l.d $f8,Two +l.d $f6,Radix +mul.d $f8,$f8,$f6 +l.d $f6,E9 +mul.d $f8,$f8,$f6 +sub.d $f10,$f10,$f8 +mul.d $f10,$f10,$f16 +c.ult.d $f18,$f10; bc1t L.714 +c.ule.d $f18,$f16; bc1t L.712 +L.714: +l.d $f18,V9 +s.d $f18,Y +l.d $f18,X +l.d $f16,W +c.lt.d $f18,$f16; bc1f L.715 +la $4,1 +la $5,L.157 +jal BadCond +b L.716 +L.715: +la $4,2 +la $5,L.157 +jal BadCond +L.716: +la $4,L.717 +l.d $f18,Z +mfc1.d $6,$f18 +jal printf +la $4,L.718 +l.d $f18,Y +mfc1.d $6,$f18 +jal printf +L.712: +L.707: +lw $24,Indx +la $24,1($24) +sw $24,Indx +lw $24,Indx +la $15,2 +ble $24,$15,L.706 +la $24,190 +sw $24,Milestone +jal Pause +l.d $f18,UfThold +l.d $f16,V +mul.d $f18,$f18,$f16 +s.d $f18,X +l.d $f18,Radix +mul.d $f18,$f18,$f18 +s.d $f18,Y +l.d $f18,X +l.d $f16,Y +mul.d $f10,$f18,$f16 +l.d $f8,One +c.ult.d $f10,$f8; bc1t L.721 +c.ule.d $f18,$f16; bc1t L.719 +L.721: +l.d $f18,X +l.d $f16,Y +l.d $f10,U1 +mul.d $f8,$f18,$f16 +c.ult.d $f8,$f10; bc1t L.724 +div.d $f16,$f16,$f10 +c.ule.d $f18,$f16; bc1t L.722 +L.724: +la $4,2 +la $5,L.725 +jal BadCond +b L.723 +L.722: +la $4,3 +la $5,L.157 +jal BadCond +L.723: +la $4,L.726 +l.d $f18,X +mfc1.d $6,$f18 +la $24,L.727 +sw $24,16($sp) +jal printf +L.719: +la $24,200 +sw $24,Milestone +la $24,1 +sw $24,Indx +L.728: +l.d $f18,F9 +s.d $f18,X +lw $24,Indx +la $15,2 +blt $24,$15,L.732 +la $15,5 +bgt $24,$15,L.732 +sll $24,$24,2 +lw $24,L.738-8($24) +.cpadd $24 +j $24 +.rdata +.align 2 +L.738: +.gpword L.734 +.gpword L.735 +.gpword L.736 +.gpword L.737 +.text +L.734: +l.d $f18,One +l.d $f16,U2 +add.d $f18,$f18,$f16 +s.d $f18,X +b L.733 +L.735: +l.d $f18,V +s.d $f18,X +b L.733 +L.736: +l.d $f18,UfThold +s.d $f18,X +b L.733 +L.737: +l.d $f18,Radix +s.d $f18,X +L.732: +L.733: +l.d $f18,X +s.d $f18,Y +la $24,sigfpe +sw $24,sigsave +la $4,ovfl_buf +jal setjmp +beq $2,$0,L.740 +la $4,L.742 +l.d $f18,X +mfc1.d $6,$f18 +jal printf +b L.741 +L.740: +l.d $f18,Half +l.d $f16,Y +l.d $f10,X +div.d $f16,$f16,$f10 +sub.d $f16,$f16,$f18 +sub.d $f18,$f16,$f18 +s.d $f18,V9 +l.d $f18,V9 +l.d $f16,Zero +c.eq.d $f18,$f16; bc1f L.743 +b L.729 +L.743: +l.d $f18,V9 +l.d $f16,U1 +neg.d $f16,$f16 +c.eq.d $f18,$f16; bc1f L.745 +lw $24,Indx +la $15,5 +bge $24,$15,L.745 +la $4,3 +la $5,L.157 +jal BadCond +b L.746 +L.745: +la $4,1 +la $5,L.157 +jal BadCond +L.746: +la $4,L.747 +l.d $f18,X +mfc1.d $6,$f18 +jal printf +la $4,L.748 +l.d $f18,V9 +mfc1.d $6,$f18 +jal printf +L.741: +sw $0,sigsave +L.729: +lw $24,Indx +la $24,1($24) +sw $24,Indx +lw $24,Indx +la $15,5 +ble $24,$15,L.728 +la $24,210 +sw $24,Milestone +l.d $f18,Zero +s.d $f18,MyZero +la $4,L.44 +jal printf +la $4,L.749 +jal printf +la $24,sigfpe +sw $24,sigsave +la $4,L.750 +jal printf +la $4,ovfl_buf +jal setjmp +bne $2,$0,L.751 +la $4,L.753 +l.d $f18,One +l.d $f16,MyZero +div.d $f18,$f18,$f16 +mfc1.d $6,$f18 +jal printf +L.751: +sw $0,sigsave +la $24,sigfpe +sw $24,sigsave +la $4,L.754 +jal printf +la $4,ovfl_buf +jal setjmp +bne $2,$0,L.755 +la $4,L.753 +l.d $f18,Zero +l.d $f16,MyZero +div.d $f18,$f18,$f16 +mfc1.d $6,$f18 +jal printf +L.755: +sw $0,sigsave +la $24,220 +sw $24,Milestone +jal Pause +la $4,L.44 +jal printf +sw $0,-156+240($sp) +L.762: +lw $24,-156+240($sp) +sll $24,$24,2 +lw $24,ErrCnt($24) +beq $24,$0,L.766 +la $4,L.768 +lw $24,-156+240($sp) +sll $24,$24,2 +lw $5,L.757($24) +lw $6,ErrCnt($24) +jal printf +L.766: +L.763: +lw $24,-156+240($sp) +la $24,1($24) +sw $24,-156+240($sp) +lw $24,-156+240($sp) +la $15,4 +blt $24,$15,L.762 +la $4,L.44 +jal printf +lw $24,ErrCnt +lw $15,ErrCnt+4 +addu $24,$24,$15 +lw $15,ErrCnt+8 +addu $24,$24,$15 +lw $15,ErrCnt+12 +addu $24,$24,$15 +ble $24,$0,L.769 +lw $15,ErrCnt +lw $14,ErrCnt+4 +addu $15,$15,$14 +lw $14,ErrCnt+8 +addu $15,$15,$14 +bne $15,$0,L.774 +lw $15,ErrCnt+12 +ble $15,$0,L.774 +la $4,L.779 +jal printf +la $4,L.780 +jal printf +L.774: +lw $15,ErrCnt +lw $14,ErrCnt+4 +addu $15,$15,$14 +bne $15,$0,L.781 +lw $15,ErrCnt+8 +ble $15,$0,L.781 +la $4,L.785 +jal printf +la $4,L.786 +jal printf +L.781: +lw $24,ErrCnt +lw $15,ErrCnt+4 +addu $24,$24,$15 +ble $24,$0,L.787 +la $4,L.790 +jal printf +la $4,L.791 +jal printf +L.787: +lw $24,ErrCnt +ble $24,$0,L.770 +la $4,L.794 +jal printf +la $4,L.795 +jal printf +b L.770 +L.769: +la $4,L.796 +jal printf +la $24,1 +lw $15,RMult +bne $15,$24,L.801 +lw $15,RDiv +bne $15,$24,L.801 +lw $15,RAddSub +bne $15,$24,L.801 +lw $15,RSqrt +beq $15,$24,L.797 +L.801: +la $4,L.802 +jal printf +b L.798 +L.797: +l.d $f18,One +l.d $f16,StickyBit +c.ult.d $f16,$f18; bc1t L.803 +l.d $f16,Radix +l.d $f10,Two +sub.d $f10,$f16,$f10 +l.d $f8,Nine +sub.d $f16,$f16,$f8 +sub.d $f18,$f16,$f18 +mul.d $f18,$f10,$f18 +l.d $f16,Zero +c.eq.d $f18,$f16; bc1f L.803 +la $4,L.805 +jal printf +la $4,L.806 +jal printf +l.d $f18,Two +l.d $f16,Radix +c.eq.d $f16,$f18; bc1f L.807 +l.d $f16,Precision +l.d $f10,TwentySeven +l.d $f8,Four +l.d $f6,Three +mul.d $f8,$f8,$f6 +mul.d $f18,$f8,$f18 +sub.d $f18,$f16,$f18 +sub.d $f16,$f16,$f10 +sub.d $f16,$f16,$f10 +l.d $f10,One +add.d $f16,$f16,$f10 +mul.d $f18,$f18,$f16 +l.d $f16,Zero +c.eq.d $f18,$f16; bc1f L.807 +la $4,L.809 +jal printf +b L.808 +L.807: +la $4,L.810 +jal printf +L.808: +lw $24,IEEE +beq $24,$0,L.811 +la $4,L.813 +jal printf +b L.812 +L.811: +la $4,L.814 +jal printf +la $4,L.815 +jal printf +L.812: +L.803: +la $4,L.816 +jal printf +L.798: +L.770: +lw $24,fpecount +beq $24,$0,L.817 +la $4,L.819 +lw $5,fpecount +jal printf +L.817: +la $4,L.820 +jal printf +move $2,$0 +L.6: +lw $16,32($sp) +lw $17,36($sp) +lw $18,40($sp) +lw $19,44($sp) +lw $20,48($sp) +lw $21,52($sp) +lw $22,56($sp) +lw $23,60($sp) +lw $25,64($sp) +lw $30,68($sp) +lw $31,72($sp) +addu $sp,$sp,240 +j $31 +.end main +.globl Sign +.text +.align 2 +.ent Sign +Sign: +.frame $sp,16,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-16 +.fmask 0xc0000000,-16 +s.d $f30,0($sp) +l.d $f18,L.7 +c.ult.d $f12,$f18; bc1t L.823 +l.d $f30,L.8 +b L.824 +L.823: +l.d $f30,L.825 +L.824: +mov.d $f0,$f30 +L.821: +l.d $f30,0($sp) +addu $sp,$sp,16 +j $31 +.end Sign +.globl Pause +.text +.align 2 +.ent Pause +Pause: +.frame $sp,32,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-32 +.mask 0x82000000,-12 +.cprestore 16 +sw $31,20($sp) +la $4,L.827 +lw $5,Milestone +jal printf +la $4,L.828 +lw $5,PageNo +jal printf +lw $24,Milestone +la $24,1($24) +sw $24,Milestone +lw $24,PageNo +la $24,1($24) +sw $24,PageNo +move $2,$0 +L.826: +lw $25,16($sp) +lw $31,20($sp) +addu $sp,$sp,32 +j $31 +.end Pause +.globl TstCond +.text +.align 2 +.ent TstCond +TstCond: +.frame $sp,32,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-32 +.mask 0x82000000,-12 +.cprestore 16 +sw $31,20($sp) +sw $4,32($sp) +sw $5,36($sp) +sw $6,40($sp) +lw $24,4+32($sp) +bne $24,$0,L.830 +lw $4,0+32($sp) +lw $5,8+32($sp) +jal BadCond +la $4,L.813 +jal printf +L.830: +move $2,$0 +L.829: +lw $25,16($sp) +lw $31,20($sp) +addu $sp,$sp,32 +j $31 +.end TstCond +.data +.align 2 +L.833: +.word L.834 +.word L.835 +.word L.836 +.word L.837 +.globl BadCond +.text +.text +.align 2 +.ent BadCond +BadCond: +.frame $sp,32,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-32 +.mask 0xc2000000,-8 +.cprestore 16 +sw $30,20($sp) +sw $31,24($sp) +move $30,$4 +sw $5,36($sp) +sll $24,$30,2 +la $24,ErrCnt($24) +lw $15,($24) +la $15,1($15) +sw $15,($24) +la $4,L.838 +sll $24,$30,2 +lw $5,L.833($24) +lw $6,4+32($sp) +jal printf +move $2,$0 +L.832: +lw $25,16($sp) +lw $30,20($sp) +lw $31,24($sp) +addu $sp,$sp,32 +j $31 +.end BadCond +.globl Random +.text +.align 2 +.ent Random +Random: +.frame $sp,48,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-48 +.fmask 0xf0000000,-24 +.mask 0x82000000,-12 +s.d $f28,16($sp) +s.d $f30,24($sp) +.cprestore 32 +sw $31,36($sp) +l.d $f18,Random1 +l.d $f16,Random9 +add.d $f30,$f18,$f16 +mul.d $f28,$f30,$f30 +mul.d $f28,$f28,$f28 +mul.d $f30,$f30,$f28 +mov.d $f12,$f30 +jal floor +sub.d $f28,$f30,$f0 +l.d $f18,L.840 +mul.d $f18,$f18,$f30 +add.d $f18,$f28,$f18 +s.d $f18,Random1 +l.d $f0,Random1 +L.839: +l.d $f28,16($sp) +l.d $f30,24($sp) +lw $25,32($sp) +lw $31,36($sp) +addu $sp,$sp,48 +j $31 +.end Random +.globl SqXMinX +.text +.align 2 +.ent SqXMinX +SqXMinX: +.frame $sp,64,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-64 +.fmask 0xc0000000,-32 +.mask 0x82000000,-20 +s.d $f30,32($sp) +.cprestore 40 +sw $31,44($sp) +sw $4,64($sp) +l.d $f18,X +l.d $f16,BInvrse +mul.d $f30,$f18,$f16 +sub.d $f16,$f18,$f30 +s.d $f16,-8+64($sp) +mul.d $f12,$f18,$f18 +jal sqrt +sub.d $f18,$f0,$f30 +l.d $f16,-8+64($sp) +sub.d $f18,$f18,$f16 +l.d $f16,OneUlp +div.d $f18,$f18,$f16 +s.d $f18,SqEr +l.d $f18,SqEr +l.d $f16,Zero +c.eq.d $f18,$f16; bc1t L.842 +l.d $f18,SqEr +l.d $f16,MinSqEr +c.lt.d $f18,$f16; bc1f L.844 +l.d $f18,SqEr +s.d $f18,MinSqEr +L.844: +l.d $f18,SqEr +l.d $f16,MaxSqEr +c.ule.d $f18,$f16; bc1t L.846 +l.d $f18,SqEr +s.d $f18,MaxSqEr +L.846: +l.d $f18,J +l.d $f16,L.8 +add.d $f18,$f18,$f16 +s.d $f18,J +lw $4,0+64($sp) +la $5,L.44 +jal BadCond +la $4,L.848 +l.d $f18,X +mul.d $f16,$f18,$f18 +mfc1.d $6,$f16 +s.d $f18,16($sp) +l.d $f18,OneUlp +l.d $f16,SqEr +mul.d $f18,$f18,$f16 +s.d $f18,24($sp) +jal printf +la $4,L.849 +jal printf +L.842: +move $2,$0 +L.841: +l.d $f30,32($sp) +lw $25,40($sp) +lw $31,44($sp) +addu $sp,$sp,64 +j $31 +.end SqXMinX +.globl NewD +.text +.align 2 +.ent NewD +NewD: +.frame $sp,32,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-32 +.mask 0x82000000,-12 +.cprestore 16 +sw $31,20($sp) +l.d $f18,Z1 +l.d $f16,Q +mul.d $f18,$f18,$f16 +s.d $f18,X +l.d $f18,Half +l.d $f16,X +l.d $f10,Radix +div.d $f16,$f16,$f10 +sub.d $f12,$f18,$f16 +jal floor +l.d $f16,Radix +mul.d $f18,$f0,$f16 +l.d $f10,X +add.d $f18,$f18,$f10 +s.d $f18,X +l.d $f18,X +l.d $f10,Z +l.d $f8,D +l.d $f6,Q +mul.d $f4,$f18,$f10 +sub.d $f6,$f6,$f4 +div.d $f6,$f6,$f16 +mul.d $f4,$f18,$f18 +div.d $f16,$f8,$f16 +mul.d $f16,$f4,$f16 +add.d $f16,$f6,$f16 +s.d $f16,Q +l.d $f16,Two +mul.d $f18,$f16,$f18 +mul.d $f18,$f18,$f8 +sub.d $f18,$f10,$f18 +s.d $f18,Z +l.d $f18,Z +l.d $f16,Zero +c.le.d $f18,$f16; bc1f L.851 +l.d $f18,Z +neg.d $f18,$f18 +s.d $f18,Z +l.d $f18,Z1 +neg.d $f18,$f18 +s.d $f18,Z1 +L.851: +l.d $f18,Radix +l.d $f16,D +mul.d $f18,$f18,$f16 +s.d $f18,D +move $2,$0 +L.850: +lw $25,16($sp) +lw $31,20($sp) +addu $sp,$sp,32 +j $31 +.end NewD +.globl SR3750 +.text +.align 2 +.ent SR3750 +SR3750: +.frame $sp,32,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-32 +.mask 0x82000000,-12 +.cprestore 16 +sw $31,20($sp) +l.d $f18,X +l.d $f16,Radix +l.d $f10,Z2 +sub.d $f8,$f18,$f16 +sub.d $f16,$f10,$f16 +c.ult.d $f8,$f16; bc1t L.854 +sub.d $f18,$f18,$f10 +l.d $f16,W +sub.d $f16,$f16,$f10 +c.le.d $f18,$f16; bc1f L.854 +lw $24,I +la $24,1($24) +sw $24,I +l.d $f18,X +l.d $f16,D +mul.d $f12,$f18,$f16 +jal sqrt +s.d $f0,X2 +l.d $f18,Z2 +l.d $f16,Y +l.d $f10,X2 +sub.d $f10,$f10,$f18 +sub.d $f18,$f16,$f18 +sub.d $f18,$f10,$f18 +s.d $f18,Y2 +l.d $f18,Half +l.d $f10,X8 +sub.d $f16,$f16,$f18 +div.d $f16,$f10,$f16 +s.d $f16,X2 +l.d $f16,X2 +mul.d $f10,$f18,$f16 +mul.d $f10,$f10,$f16 +sub.d $f16,$f16,$f10 +s.d $f16,X2 +l.d $f16,Y2 +add.d $f16,$f16,$f18 +l.d $f10,X2 +sub.d $f18,$f18,$f10 +add.d $f18,$f16,$f18 +s.d $f18,SqEr +l.d $f18,SqEr +l.d $f16,MinSqEr +c.lt.d $f18,$f16; bc1f L.856 +l.d $f18,SqEr +s.d $f18,MinSqEr +L.856: +l.d $f18,Y2 +l.d $f16,X2 +sub.d $f18,$f18,$f16 +s.d $f18,SqEr +l.d $f18,SqEr +l.d $f16,MaxSqEr +c.ule.d $f18,$f16; bc1t L.858 +l.d $f18,SqEr +s.d $f18,MaxSqEr +L.858: +L.854: +move $2,$0 +L.853: +lw $25,16($sp) +lw $31,20($sp) +addu $sp,$sp,32 +j $31 +.end SR3750 +.globl IsYeqX +.text +.align 2 +.ent IsYeqX +IsYeqX: +.frame $sp,32,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-32 +.mask 0x82000000,-4 +.cprestore 24 +sw $31,28($sp) +l.d $f18,Y +l.d $f16,X +c.eq.d $f18,$f16; bc1t L.861 +lw $24,N +bgt $24,$0,L.863 +l.d $f18,Zero +l.d $f16,Z +c.eq.d $f16,$f18; bc1f L.865 +l.d $f16,Q +c.le.d $f16,$f18; bc1f L.865 +la $4,L.867 +jal printf +b L.866 +L.865: +la $4,2 +la $5,L.868 +jal BadCond +L.866: +la $4,L.869 +l.d $f18,Z +mfc1.d $6,$f18 +l.d $f18,Q +s.d $f18,16($sp) +jal printf +la $4,L.870 +l.d $f18,Y +mfc1.d $6,$f18 +jal printf +la $4,L.871 +l.d $f18,X +mfc1.d $6,$f18 +jal printf +la $4,L.872 +l.d $f18,Y +l.d $f16,X +sub.d $f18,$f18,$f16 +mfc1.d $6,$f18 +jal printf +L.863: +lw $24,N +la $24,1($24) +sw $24,N +L.861: +move $2,$0 +L.860: +lw $25,24($sp) +lw $31,28($sp) +addu $sp,$sp,32 +j $31 +.end IsYeqX +.globl SR3980 +.text +.align 2 +.ent SR3980 +SR3980: +.frame $sp,32,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-32 +.mask 0x82000000,-12 +.cprestore 16 +sw $31,20($sp) +L.874: +lw $24,I +mtc1 $24,$f18; cvt.d.w $f18,$f18 +s.d $f18,Q +l.d $f12,Z +l.d $f14,Q +jal pow +s.d $f0,Y +jal IsYeqX +lw $24,I +la $24,1($24) +sw $24,I +lw $15,M +ble $24,$15,L.877 +b L.876 +L.877: +l.d $f18,Z +l.d $f16,X +mul.d $f18,$f18,$f16 +s.d $f18,X +L.875: +l.d $f18,X +l.d $f16,W +c.ult.d $f18,$f16; bc1t L.874 +L.876: +move $2,$0 +L.873: +lw $25,16($sp) +lw $31,20($sp) +addu $sp,$sp,32 +j $31 +.end SR3980 +.globl PrintIfNPositive +.text +.align 2 +.ent PrintIfNPositive +PrintIfNPositive: +.frame $sp,32,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-32 +.mask 0x82000000,-12 +.cprestore 16 +sw $31,20($sp) +lw $24,N +ble $24,$0,L.880 +la $4,L.882 +lw $5,N +jal printf +L.880: +move $2,$0 +L.879: +lw $25,16($sp) +lw $31,20($sp) +addu $sp,$sp,32 +j $31 +.end PrintIfNPositive +.globl TstPtUf +.text +.align 2 +.ent TstPtUf +TstPtUf: +.frame $sp,32,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-32 +.mask 0x82000000,-12 +.cprestore 16 +sw $31,20($sp) +sw $0,N +l.d $f18,Z +l.d $f16,Zero +c.eq.d $f18,$f16; bc1t L.884 +la $4,L.886 +jal printf +la $4,L.887 +jal printf +la $24,sigfpe +sw $24,sigsave +la $4,ovfl_buf +jal setjmp +beq $2,$0,L.888 +b L.890 +L.888: +l.d $f18,Z +add.d $f16,$f18,$f18 +div.d $f18,$f16,$f18 +s.d $f18,Q9 +la $4,L.891 +l.d $f18,Q9 +mfc1.d $6,$f18 +jal printf +l.d $f18,Q9 +l.d $f16,Two +sub.d $f12,$f18,$f16 +jal fabs +l.d $f16,Radix +l.d $f10,U2 +mul.d $f16,$f16,$f10 +c.lt.d $f0,$f16; bc1f L.892 +la $4,L.894 +jal printf +la $4,L.895 +jal printf +b L.893 +L.892: +l.d $f18,Q9 +l.d $f16,One +c.ult.d $f18,$f16; bc1t L.898 +l.d $f16,Two +c.ule.d $f18,$f16; bc1t L.896 +L.898: +L.890: +la $24,1 +sw $24,N +lw $24,ErrCnt+4 +la $24,1($24) +sw $24,ErrCnt+4 +la $4,L.901 +jal printf +b L.897 +L.896: +la $24,1 +sw $24,N +lw $24,ErrCnt+8 +la $24,1($24) +sw $24,ErrCnt+8 +la $4,L.904 +jal printf +L.897: +L.893: +sw $0,sigsave +l.d $f18,Z +l.d $f16,One +mul.d $f10,$f18,$f16 +s.d $f10,V9 +l.d $f10,V9 +s.d $f10,Random1 +mul.d $f10,$f16,$f18 +s.d $f10,V9 +l.d $f10,V9 +s.d $f10,Random2 +div.d $f18,$f18,$f16 +s.d $f18,V9 +l.d $f18,Z +l.d $f16,Random1 +c.eq.d $f18,$f16; bc1f L.905 +l.d $f16,Random2 +c.eq.d $f18,$f16; bc1f L.905 +l.d $f16,V9 +c.eq.d $f18,$f16; bc1f L.905 +lw $24,N +ble $24,$0,L.906 +jal Pause +b L.906 +L.905: +la $24,1 +sw $24,N +la $4,2 +la $5,L.909 +jal BadCond +la $4,L.910 +l.d $f18,Z +mfc1.d $6,$f18 +jal printf +l.d $f18,Z +l.d $f16,Random1 +c.eq.d $f18,$f16; bc1t L.911 +la $4,L.913 +l.d $f18,Random1 +mfc1.d $6,$f18 +jal printf +L.911: +l.d $f18,Random2 +l.d $f16,Z +c.eq.d $f16,$f18; bc1t L.914 +l.d $f16,Random1 +c.eq.d $f18,$f16; bc1t L.914 +la $4,L.916 +l.d $f18,Random2 +mfc1.d $6,$f18 +jal printf +L.914: +l.d $f18,Z +l.d $f16,V9 +c.eq.d $f18,$f16; bc1t L.917 +la $4,L.919 +l.d $f18,V9 +mfc1.d $6,$f18 +jal printf +L.917: +l.d $f18,Random2 +l.d $f16,Random1 +c.eq.d $f18,$f16; bc1t L.920 +lw $24,ErrCnt+8 +la $24,1($24) +sw $24,ErrCnt+8 +la $4,2 +la $5,L.924 +jal BadCond +la $4,L.925 +l.d $f18,Random2 +mfc1.d $6,$f18 +jal printf +la $4,L.926 +l.d $f18,Random1 +mfc1.d $6,$f18 +jal printf +L.920: +jal Pause +L.906: +L.884: +move $2,$0 +L.883: +lw $25,16($sp) +lw $31,20($sp) +addu $sp,$sp,32 +j $31 +.end TstPtUf +.globl notify +.text +.align 2 +.ent notify +notify: +.frame $sp,32,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-32 +.mask 0x82000000,-12 +.cprestore 16 +sw $31,20($sp) +sw $4,32($sp) +la $4,L.928 +lw $5,0+32($sp) +jal printf +la $4,L.929 +jal printf +move $2,$0 +L.927: +lw $25,16($sp) +lw $31,20($sp) +addu $sp,$sp,32 +j $31 +.end notify +.globl msglist +.text +.align 2 +.ent msglist +msglist: +.frame $sp,32,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-32 +.mask 0xc2000000,-8 +.cprestore 16 +sw $30,20($sp) +sw $31,24($sp) +move $30,$4 +b L.932 +L.931: +la $4,L.934 +move $24,$30 +la $30,4($24) +lw $5,($24) +jal printf +L.932: +lw $24,($30) +bne $24,$0,L.931 +move $2,$0 +L.930: +lw $25,16($sp) +lw $30,20($sp) +lw $31,24($sp) +addu $sp,$sp,32 +j $31 +.end msglist +.data +.align 2 +L.936: +.word L.937 +.word L.938 +.word L.939 +.word L.940 +.word L.941 +.word L.942 +.word L.943 +.word L.944 +.word L.945 +.word 0x0 +.globl Instructions +.text +.text +.align 2 +.ent Instructions +Instructions: +.frame $sp,32,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-32 +.mask 0x82000000,-12 +.cprestore 16 +sw $31,20($sp) +la $4,L.936 +jal msglist +move $2,$0 +L.935: +lw $25,16($sp) +lw $31,20($sp) +addu $sp,$sp,32 +j $31 +.end Instructions +.data +.align 2 +L.947: +.word L.948 +.word L.949 +.word L.950 +.word L.951 +.word L.952 +.word L.953 +.word L.954 +.word L.955 +.word L.956 +.word L.957 +.word L.958 +.word L.959 +.word L.960 +.word L.961 +.word 0x0 +.globl Heading +.text +.text +.align 2 +.ent Heading +Heading: +.frame $sp,32,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-32 +.mask 0x82000000,-12 +.cprestore 16 +sw $31,20($sp) +la $4,L.947 +jal msglist +move $2,$0 +L.946: +lw $25,16($sp) +lw $31,20($sp) +addu $sp,$sp,32 +j $31 +.end Heading +.data +.align 2 +L.963: +.word L.964 +.word L.965 +.word L.966 +.word L.967 +.word L.968 +.word L.969 +.word L.970 +.word L.971 +.word L.972 +.word L.973 +.word L.974 +.word L.975 +.word L.976 +.word L.977 +.word L.978 +.word L.979 +.word L.980 +.word L.981 +.word L.982 +.word 0x0 +.globl Characteristics +.text +.text +.align 2 +.ent Characteristics +Characteristics: +.frame $sp,32,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-32 +.mask 0x82000000,-12 +.cprestore 16 +sw $31,20($sp) +la $4,L.963 +jal msglist +move $2,$0 +L.962: +lw $25,16($sp) +lw $31,20($sp) +addu $sp,$sp,32 +j $31 +.end Characteristics +.data +.align 2 +L.984: +.word L.985 +.word L.986 +.word L.987 +.word L.988 +.word L.989 +.word L.990 +.word L.991 +.word L.992 +.word L.993 +.word L.994 +.word L.995 +.word L.996 +.word L.997 +.word L.998 +.word L.999 +.word L.1000 +.word L.1001 +.word 0x0 +.globl History +.text +.text +.align 2 +.ent History +History: +.frame $sp,32,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-32 +.mask 0x82000000,-12 +.cprestore 16 +sw $31,20($sp) +la $4,L.984 +jal msglist +move $2,$0 +L.983: +lw $25,16($sp) +lw $31,20($sp) +addu $sp,$sp,32 +j $31 +.end History +.globl pow +.text +.align 2 +.ent pow +pow: +.frame $sp,80,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-80 +.fmask 0xfc000000,-48 +.mask 0xc2800000,-28 +s.d $f26,16($sp) +s.d $f28,24($sp) +s.d $f30,32($sp) +sw $23,40($sp) +.cprestore 44 +sw $30,48($sp) +sw $31,52($sp) +mov.d $f30,$f12 +mov.d $f28,$f14 +move $23,$0 +sw $0,-8+80($sp) +l.d $f18,L.7 +c.eq.d $f28,$f18; bc1f L.1003 +l.d $f0,L.8 +b L.1002 +L.1003: +l.d $f18,L.1008 +c.ult.d $f28,$f18; bc1t L.1007 +l.d $f18,L.1009 +c.ule.d $f28,$f18; bc1t L.1005 +L.1007: +l.d $f18,L.825 +c.eq.d $f30,$f18; bc1t L.1005 +mov.d $f12,$f30 +jal log +mov.d $f18,$f0 +mul.d $f12,$f28,$f18 +jal exp +mov.d $f18,$f0 +b L.1002 +L.1005: +l.d $f18,L.7 +c.lt.d $f28,$f18; bc1f L.1010 +neg.d $f28,$f28 +la $24,1 +sw $24,-8+80($sp) +L.1010: +mov.d $f12,$f28 +la $6,-16+80($sp) +jal modf +mov.d $f28,$f0 +l.d $f18,L.7 +c.eq.d $f28,$f18; bc1t L.1012 +mov.d $f12,$f30 +jal log +mov.d $f18,$f0 +mul.d $f12,$f28,$f18 +jal exp +mov.d $f26,$f0 +b L.1013 +L.1012: +l.d $f26,L.8 +L.1013: +mov.d $f12,$f30 +la $6,-4+80($sp) +jal frexp +mov.d $f30,$f0 +l.d $f18,-16+80($sp) +trunc.w.d $f2,$f18,$24; mfc1 $24,$f2 +move $30,$24 +beq $24,$0,L.1014 +L.1016: +and $24,$30,1 +beq $24,$0,L.1020 +mul.d $f26,$f26,$f30 +lw $24,-4+80($sp) +addu $23,$23,$24 +L.1020: +sra $24,$30,1 +move $30,$24 +bne $24,$0,L.1022 +b L.1018 +L.1022: +mul.d $f30,$f30,$f30 +lw $24,-4+80($sp) +sll $24,$24,1 +sw $24,-4+80($sp) +l.d $f18,L.1026 +c.lt.d $f30,$f18; bc1f L.1016 +l.d $f18,L.1027 +mul.d $f30,$f18,$f30 +lw $24,-4+80($sp) +subu $24,$24,1 +sw $24,-4+80($sp) +b L.1016 +L.1018: +L.1014: +lw $24,-8+80($sp) +beq $24,$0,L.1028 +l.d $f18,L.8 +div.d $f26,$f18,$f26 +negu $23,$23 +L.1028: +mov.d $f12,$f26 +move $6,$23 +jal ldexp +mov.d $f18,$f0 +L.1002: +l.d $f26,16($sp) +l.d $f28,24($sp) +l.d $f30,32($sp) +lw $23,40($sp) +lw $25,44($sp) +lw $30,48($sp) +lw $31,52($sp) +addu $sp,$sp,80 +j $31 +.end pow +.globl UfNGrad +.comm UfNGrad,4 +.globl SqRWrng +.comm SqRWrng,4 +.globl IEEE +.comm IEEE,4 +.globl Anomaly +.comm Anomaly,4 +.globl Monot +.comm Monot,4 +.globl NotMonot +.comm NotMonot,4 +.globl Done +.comm Done,4 +.globl Break +.comm Break,4 +.globl RSqrt +.comm RSqrt,4 +.globl RAddSub +.comm RAddSub,4 +.globl RDiv +.comm RDiv,4 +.globl RMult +.comm RMult,4 +.globl GAddSub +.comm GAddSub,4 +.globl GDiv +.comm GDiv,4 +.globl GMult +.comm GMult,4 +.globl N1 +.comm N1,4 +.globl N +.comm N,4 +.globl M +.comm M,4 +.globl PageNo +.comm PageNo,4 +.globl Milestone +.comm Milestone,4 +.globl fpecount +.comm fpecount,4 +.globl ErrCnt +.comm ErrCnt,16 +.globl Z9 +.comm Z9,8 +.globl Z2 +.comm Z2,8 +.globl Z1 +.comm Z1,8 +.globl PseudoZero +.comm PseudoZero,8 +.globl Z +.comm Z,8 +.globl Random2 +.comm Random2,8 +.globl Y2 +.comm Y2,8 +.globl Y1 +.comm Y1,8 +.globl Y +.comm Y,8 +.globl Random1 +.comm Random1,8 +.globl X8 +.comm X8,8 +.globl X2 +.comm X2,8 +.globl X1 +.comm X1,8 +.globl X +.comm X,8 +.globl W +.comm W,8 +.globl V9 +.comm V9,8 +.globl V0 +.comm V0,8 +.globl V +.comm V,8 +.globl U2 +.comm U2,8 +.globl U1 +.comm U1,8 +.globl UfThold +.comm UfThold,8 +.globl OneUlp +.comm OneUlp,8 +.globl S +.comm S,8 +.globl Underflow +.comm Underflow,8 +.globl T +.comm T,8 +.globl Random9 +.comm Random9,8 +.globl R +.comm R,8 +.globl Q9 +.comm Q9,8 +.globl Q +.comm Q,8 +.globl Precision +.comm Precision,8 +.globl MyZero +.comm MyZero,8 +.globl J +.comm J,8 +.globl StickyBit +.comm StickyBit,8 +.globl I +.comm I,4 +.globl HInvrse +.comm HInvrse,8 +.globl H +.comm H,8 +.globl F9 +.comm F9,8 +.globl F6 +.comm F6,8 +.globl Third +.comm Third,8 +.globl E9 +.comm E9,8 +.globl MaxSqEr +.comm MaxSqEr,8 +.globl SqEr +.comm SqEr,8 +.globl MinSqEr +.comm MinSqEr,8 +.globl E3 +.comm E3,8 +.globl Exp2 +.comm Exp2,8 +.globl E1 +.comm E1,8 +.globl E0 +.comm E0,8 +.globl FourD +.comm FourD,8 +.globl D +.comm D,8 +.globl CInvrse +.comm CInvrse,8 +.globl C +.comm C,8 +.globl A1 +.comm A1,8 +.globl AInvrse +.comm AInvrse,8 +.globl ch +.comm ch,8 +.globl Indx +.comm Indx,4 +.globl BMinusU2 +.comm BMinusU2,8 +.globl RadixD2 +.comm RadixD2,8 +.globl BInvrse +.comm BInvrse,8 +.globl Radix +.comm Radix,8 +.globl sigsave +.comm sigsave,4 +.globl ovfl_buf +.comm ovfl_buf,112 +.extern _iob 0 +.rdata +.align 3 +L.1027: +.word 0x40000000 +.word 0x0 +.align 3 +L.1026: +.word 0x3fe00000 +.word 0x0 +.align 3 +L.1009: +.word 0x40913000 +.word 0x0 +.align 3 +L.1008: +.word 0xc0913000 +.word 0x0 +.align 0 +L.1001: +.byte 115 +.byte 101 +.byte 101 +.byte 32 +.byte 115 +.byte 111 +.byte 117 +.byte 114 +.byte 99 +.byte 101 +.byte 32 +.byte 99 +.byte 111 +.byte 109 +.byte 109 +.byte 101 +.byte 110 +.byte 116 +.byte 115 +.byte 32 +.byte 102 +.byte 111 +.byte 114 +.byte 32 +.byte 109 +.byte 111 +.byte 114 +.byte 101 +.byte 32 +.byte 104 +.byte 105 +.byte 115 +.byte 116 +.byte 111 +.byte 114 +.byte 121 +.byte 46 +.byte 0 +.align 0 +L.1000: +.byte 66 +.byte 65 +.byte 83 +.byte 73 +.byte 67 +.byte 32 +.byte 118 +.byte 101 +.byte 114 +.byte 115 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 111 +.byte 102 +.byte 32 +.byte 116 +.byte 104 +.byte 105 +.byte 115 +.byte 32 +.byte 112 +.byte 114 +.byte 111 +.byte 103 +.byte 114 +.byte 97 +.byte 109 +.byte 32 +.byte 40 +.byte 67 +.byte 41 +.byte 32 +.byte 49 +.byte 57 +.byte 56 +.byte 51 +.byte 32 +.byte 98 +.byte 121 +.byte 32 +.byte 80 +.byte 114 +.byte 111 +.byte 102 +.byte 46 +.byte 32 +.byte 87 +.byte 46 +.byte 32 +.byte 77 +.byte 46 +.byte 32 +.byte 75 +.byte 97 +.byte 104 +.byte 97 +.byte 110 +.byte 59 +.byte 0 +.align 0 +L.999: +.byte 97 +.byte 115 +.byte 32 +.byte 117 +.byte 115 +.byte 101 +.byte 100 +.byte 32 +.byte 98 +.byte 121 +.byte 32 +.byte 99 +.byte 101 +.byte 114 +.byte 116 +.byte 97 +.byte 105 +.byte 110 +.byte 32 +.byte 101 +.byte 97 +.byte 114 +.byte 108 +.byte 121 +.byte 32 +.byte 87 +.byte 65 +.byte 78 +.byte 71 +.byte 32 +.byte 109 +.byte 97 +.byte 99 +.byte 104 +.byte 105 +.byte 110 +.byte 101 +.byte 115 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.998: +.byte 102 +.byte 108 +.byte 111 +.byte 97 +.byte 116 +.byte 105 +.byte 110 +.byte 103 +.byte 45 +.byte 112 +.byte 111 +.byte 105 +.byte 110 +.byte 116 +.byte 32 +.byte 110 +.byte 117 +.byte 109 +.byte 98 +.byte 101 +.byte 114 +.byte 115 +.byte 44 +.byte 32 +.byte 98 +.byte 117 +.byte 116 +.byte 32 +.byte 97 +.byte 108 +.byte 115 +.byte 111 +.byte 32 +.byte 97 +.byte 108 +.byte 108 +.byte 111 +.byte 119 +.byte 115 +.byte 32 +.byte 108 +.byte 111 +.byte 103 +.byte 97 +.byte 114 +.byte 105 +.byte 116 +.byte 104 +.byte 109 +.byte 105 +.byte 99 +.byte 32 +.byte 101 +.byte 110 +.byte 99 +.byte 111 +.byte 100 +.byte 105 +.byte 110 +.byte 103 +.byte 0 +.align 0 +L.997: +.byte 10 +.byte 84 +.byte 104 +.byte 101 +.byte 32 +.byte 112 +.byte 114 +.byte 111 +.byte 103 +.byte 114 +.byte 97 +.byte 109 +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 98 +.byte 97 +.byte 115 +.byte 101 +.byte 100 +.byte 32 +.byte 117 +.byte 112 +.byte 111 +.byte 110 +.byte 32 +.byte 97 +.byte 32 +.byte 99 +.byte 111 +.byte 110 +.byte 118 +.byte 101 +.byte 110 +.byte 116 +.byte 105 +.byte 111 +.byte 110 +.byte 97 +.byte 108 +.byte 32 +.byte 114 +.byte 97 +.byte 100 +.byte 105 +.byte 120 +.byte 32 +.byte 114 +.byte 101 +.byte 112 +.byte 114 +.byte 101 +.byte 115 +.byte 101 +.byte 110 +.byte 116 +.byte 97 +.byte 116 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 102 +.byte 111 +.byte 114 +.byte 0 +.align 0 +L.996: +.byte 111 +.byte 102 +.byte 32 +.byte 112 +.byte 97 +.byte 116 +.byte 104 +.byte 111 +.byte 108 +.byte 111 +.byte 103 +.byte 105 +.byte 101 +.byte 115 +.byte 44 +.byte 32 +.byte 97 +.byte 110 +.byte 100 +.byte 32 +.byte 116 +.byte 111 +.byte 32 +.byte 115 +.byte 97 +.byte 121 +.byte 32 +.byte 104 +.byte 111 +.byte 119 +.byte 32 +.byte 119 +.byte 101 +.byte 108 +.byte 108 +.byte 32 +.byte 116 +.byte 104 +.byte 101 +.byte 32 +.byte 97 +.byte 114 +.byte 105 +.byte 116 +.byte 104 +.byte 109 +.byte 101 +.byte 116 +.byte 105 +.byte 99 +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 105 +.byte 109 +.byte 112 +.byte 108 +.byte 101 +.byte 109 +.byte 101 +.byte 110 +.byte 116 +.byte 101 +.byte 100 +.byte 46 +.byte 0 +.align 0 +L.995: +.byte 111 +.byte 102 +.byte 32 +.byte 116 +.byte 104 +.byte 101 +.byte 32 +.byte 97 +.byte 114 +.byte 105 +.byte 116 +.byte 104 +.byte 109 +.byte 101 +.byte 116 +.byte 105 +.byte 99 +.byte 44 +.byte 32 +.byte 116 +.byte 104 +.byte 105 +.byte 115 +.byte 32 +.byte 112 +.byte 114 +.byte 111 +.byte 103 +.byte 114 +.byte 97 +.byte 109 +.byte 32 +.byte 116 +.byte 114 +.byte 105 +.byte 101 +.byte 115 +.byte 32 +.byte 116 +.byte 111 +.byte 32 +.byte 99 +.byte 111 +.byte 112 +.byte 101 +.byte 32 +.byte 119 +.byte 105 +.byte 116 +.byte 104 +.byte 32 +.byte 97 +.byte 32 +.byte 119 +.byte 105 +.byte 100 +.byte 101 +.byte 114 +.byte 32 +.byte 118 +.byte 97 +.byte 114 +.byte 105 +.byte 101 +.byte 116 +.byte 121 +.byte 0 +.align 0 +L.994: +.byte 116 +.byte 104 +.byte 101 +.byte 32 +.byte 82 +.byte 97 +.byte 100 +.byte 105 +.byte 120 +.byte 44 +.byte 32 +.byte 80 +.byte 114 +.byte 101 +.byte 99 +.byte 105 +.byte 115 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 97 +.byte 110 +.byte 100 +.byte 32 +.byte 114 +.byte 97 +.byte 110 +.byte 103 +.byte 101 +.byte 32 +.byte 40 +.byte 111 +.byte 118 +.byte 101 +.byte 114 +.byte 47 +.byte 117 +.byte 110 +.byte 100 +.byte 101 +.byte 114 +.byte 102 +.byte 108 +.byte 111 +.byte 119 +.byte 32 +.byte 116 +.byte 104 +.byte 114 +.byte 101 +.byte 115 +.byte 104 +.byte 111 +.byte 108 +.byte 100 +.byte 115 +.byte 41 +.byte 0 +.align 0 +L.993: +.byte 87 +.byte 46 +.byte 32 +.byte 74 +.byte 46 +.byte 32 +.byte 67 +.byte 111 +.byte 100 +.byte 121 +.byte 32 +.byte 97 +.byte 110 +.byte 100 +.byte 32 +.byte 87 +.byte 46 +.byte 32 +.byte 87 +.byte 97 +.byte 105 +.byte 116 +.byte 101 +.byte 46 +.byte 32 +.byte 65 +.byte 108 +.byte 116 +.byte 104 +.byte 111 +.byte 117 +.byte 103 +.byte 104 +.byte 32 +.byte 98 +.byte 111 +.byte 116 +.byte 104 +.byte 32 +.byte 112 +.byte 114 +.byte 111 +.byte 103 +.byte 114 +.byte 97 +.byte 109 +.byte 115 +.byte 32 +.byte 116 +.byte 114 +.byte 121 +.byte 32 +.byte 116 +.byte 111 +.byte 32 +.byte 100 +.byte 105 +.byte 115 +.byte 99 +.byte 111 +.byte 118 +.byte 101 +.byte 114 +.byte 0 +.align 0 +L.992: +.byte 98 +.byte 111 +.byte 111 +.byte 107 +.byte 32 +.byte 32 +.byte 96 +.byte 83 +.byte 111 +.byte 102 +.byte 116 +.byte 119 +.byte 97 +.byte 114 +.byte 101 +.byte 32 +.byte 77 +.byte 97 +.byte 110 +.byte 117 +.byte 97 +.byte 108 +.byte 32 +.byte 102 +.byte 111 +.byte 114 +.byte 32 +.byte 116 +.byte 104 +.byte 101 +.byte 32 +.byte 69 +.byte 108 +.byte 101 +.byte 109 +.byte 101 +.byte 110 +.byte 116 +.byte 97 +.byte 114 +.byte 121 +.byte 32 +.byte 70 +.byte 117 +.byte 110 +.byte 99 +.byte 116 +.byte 105 +.byte 111 +.byte 110 +.byte 115 +.byte 39 +.byte 32 +.byte 40 +.byte 49 +.byte 57 +.byte 56 +.byte 48 +.byte 41 +.byte 32 +.byte 98 +.byte 121 +.byte 0 +.align 0 +L.991: +.byte 112 +.byte 114 +.byte 111 +.byte 103 +.byte 114 +.byte 97 +.byte 109 +.byte 32 +.byte 99 +.byte 97 +.byte 108 +.byte 108 +.byte 101 +.byte 100 +.byte 32 +.byte 96 +.byte 77 +.byte 65 +.byte 67 +.byte 72 +.byte 65 +.byte 82 +.byte 39 +.byte 44 +.byte 32 +.byte 119 +.byte 104 +.byte 105 +.byte 99 +.byte 104 +.byte 32 +.byte 99 +.byte 97 +.byte 110 +.byte 32 +.byte 98 +.byte 101 +.byte 32 +.byte 102 +.byte 111 +.byte 117 +.byte 110 +.byte 100 +.byte 32 +.byte 97 +.byte 116 +.byte 32 +.byte 116 +.byte 104 +.byte 101 +.byte 32 +.byte 101 +.byte 110 +.byte 100 +.byte 32 +.byte 111 +.byte 102 +.byte 32 +.byte 116 +.byte 104 +.byte 101 +.byte 0 +.align 0 +L.990: +.byte 84 +.byte 104 +.byte 101 +.byte 32 +.byte 100 +.byte 105 +.byte 97 +.byte 103 +.byte 110 +.byte 111 +.byte 115 +.byte 116 +.byte 105 +.byte 99 +.byte 32 +.byte 99 +.byte 97 +.byte 112 +.byte 97 +.byte 98 +.byte 105 +.byte 108 +.byte 105 +.byte 116 +.byte 105 +.byte 101 +.byte 115 +.byte 32 +.byte 111 +.byte 102 +.byte 32 +.byte 116 +.byte 104 +.byte 105 +.byte 115 +.byte 32 +.byte 112 +.byte 114 +.byte 111 +.byte 103 +.byte 114 +.byte 97 +.byte 109 +.byte 32 +.byte 103 +.byte 111 +.byte 32 +.byte 98 +.byte 101 +.byte 121 +.byte 111 +.byte 110 +.byte 100 +.byte 32 +.byte 97 +.byte 110 +.byte 32 +.byte 101 +.byte 97 +.byte 114 +.byte 108 +.byte 105 +.byte 101 +.byte 114 +.byte 0 +.align 0 +L.989: +.byte 70 +.byte 97 +.byte 105 +.byte 108 +.byte 117 +.byte 114 +.byte 101 +.byte 115 +.byte 32 +.byte 109 +.byte 97 +.byte 121 +.byte 32 +.byte 99 +.byte 111 +.byte 110 +.byte 102 +.byte 111 +.byte 117 +.byte 110 +.byte 100 +.byte 32 +.byte 115 +.byte 117 +.byte 98 +.byte 115 +.byte 101 +.byte 113 +.byte 117 +.byte 101 +.byte 110 +.byte 116 +.byte 32 +.byte 100 +.byte 105 +.byte 97 +.byte 103 +.byte 110 +.byte 111 +.byte 115 +.byte 101 +.byte 115 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.988: +.byte 32 +.byte 32 +.byte 32 +.byte 70 +.byte 65 +.byte 73 +.byte 76 +.byte 85 +.byte 82 +.byte 69 +.byte 115 +.byte 44 +.byte 32 +.byte 108 +.byte 105 +.byte 107 +.byte 101 +.byte 32 +.byte 50 +.byte 43 +.byte 50 +.byte 32 +.byte 61 +.byte 61 +.byte 32 +.byte 53 +.byte 32 +.byte 46 +.byte 0 +.align 0 +L.987: +.byte 32 +.byte 32 +.byte 32 +.byte 83 +.byte 101 +.byte 114 +.byte 105 +.byte 111 +.byte 117 +.byte 115 +.byte 32 +.byte 68 +.byte 69 +.byte 70 +.byte 69 +.byte 67 +.byte 84 +.byte 115 +.byte 44 +.byte 32 +.byte 108 +.byte 105 +.byte 107 +.byte 101 +.byte 32 +.byte 108 +.byte 97 +.byte 99 +.byte 107 +.byte 32 +.byte 111 +.byte 102 +.byte 32 +.byte 97 +.byte 32 +.byte 103 +.byte 117 +.byte 97 +.byte 114 +.byte 100 +.byte 32 +.byte 100 +.byte 105 +.byte 103 +.byte 105 +.byte 116 +.byte 44 +.byte 32 +.byte 97 +.byte 110 +.byte 100 +.byte 0 +.align 0 +L.986: +.byte 32 +.byte 32 +.byte 32 +.byte 70 +.byte 76 +.byte 65 +.byte 87 +.byte 115 +.byte 44 +.byte 32 +.byte 108 +.byte 105 +.byte 107 +.byte 101 +.byte 32 +.byte 108 +.byte 97 +.byte 99 +.byte 107 +.byte 32 +.byte 111 +.byte 102 +.byte 32 +.byte 97 +.byte 32 +.byte 115 +.byte 116 +.byte 105 +.byte 99 +.byte 107 +.byte 121 +.byte 32 +.byte 98 +.byte 105 +.byte 116 +.byte 44 +.byte 0 +.align 0 +L.985: +.byte 84 +.byte 104 +.byte 101 +.byte 32 +.byte 112 +.byte 114 +.byte 111 +.byte 103 +.byte 114 +.byte 97 +.byte 109 +.byte 32 +.byte 97 +.byte 116 +.byte 116 +.byte 101 +.byte 109 +.byte 112 +.byte 116 +.byte 115 +.byte 32 +.byte 116 +.byte 111 +.byte 32 +.byte 100 +.byte 105 +.byte 115 +.byte 99 +.byte 114 +.byte 105 +.byte 109 +.byte 105 +.byte 110 +.byte 97 +.byte 116 +.byte 101 +.byte 32 +.byte 97 +.byte 109 +.byte 111 +.byte 110 +.byte 103 +.byte 0 +.align 0 +L.982: +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 68 +.byte 101 +.byte 99 +.byte 105 +.byte 109 +.byte 97 +.byte 108 +.byte 45 +.byte 66 +.byte 105 +.byte 110 +.byte 97 +.byte 114 +.byte 121 +.byte 32 +.byte 99 +.byte 111 +.byte 110 +.byte 118 +.byte 101 +.byte 114 +.byte 115 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 78 +.byte 79 +.byte 84 +.byte 32 +.byte 89 +.byte 69 +.byte 84 +.byte 32 +.byte 116 +.byte 101 +.byte 115 +.byte 116 +.byte 101 +.byte 100 +.byte 32 +.byte 102 +.byte 111 +.byte 114 +.byte 32 +.byte 97 +.byte 99 +.byte 99 +.byte 117 +.byte 114 +.byte 97 +.byte 99 +.byte 121 +.byte 46 +.byte 0 +.align 0 +L.981: +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 69 +.byte 120 +.byte 116 +.byte 114 +.byte 97 +.byte 45 +.byte 112 +.byte 114 +.byte 101 +.byte 99 +.byte 105 +.byte 115 +.byte 101 +.byte 32 +.byte 115 +.byte 117 +.byte 98 +.byte 101 +.byte 120 +.byte 112 +.byte 114 +.byte 101 +.byte 115 +.byte 115 +.byte 105 +.byte 111 +.byte 110 +.byte 115 +.byte 32 +.byte 97 +.byte 114 +.byte 101 +.byte 32 +.byte 114 +.byte 101 +.byte 118 +.byte 101 +.byte 97 +.byte 108 +.byte 101 +.byte 100 +.byte 32 +.byte 98 +.byte 117 +.byte 116 +.byte 32 +.byte 78 +.byte 79 +.byte 84 +.byte 32 +.byte 89 +.byte 69 +.byte 84 +.byte 32 +.byte 116 +.byte 101 +.byte 115 +.byte 116 +.byte 101 +.byte 100 +.byte 46 +.byte 0 +.align 0 +L.980: +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 83 +.byte 113 +.byte 114 +.byte 116 +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 116 +.byte 101 +.byte 115 +.byte 116 +.byte 101 +.byte 100 +.byte 46 +.byte 32 +.byte 32 +.byte 89 +.byte 94 +.byte 88 +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 110 +.byte 111 +.byte 116 +.byte 32 +.byte 116 +.byte 101 +.byte 115 +.byte 116 +.byte 101 +.byte 100 +.byte 46 +.byte 0 +.align 0 +L.979: +.byte 9 +.byte 97 +.byte 110 +.byte 100 +.byte 32 +.byte 102 +.byte 111 +.byte 114 +.byte 32 +.byte 99 +.byte 111 +.byte 110 +.byte 116 +.byte 97 +.byte 109 +.byte 105 +.byte 110 +.byte 97 +.byte 116 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 119 +.byte 105 +.byte 116 +.byte 104 +.byte 32 +.byte 112 +.byte 115 +.byte 101 +.byte 117 +.byte 100 +.byte 111 +.byte 45 +.byte 122 +.byte 101 +.byte 114 +.byte 111 +.byte 115 +.byte 46 +.byte 0 +.align 0 +L.978: +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 67 +.byte 111 +.byte 109 +.byte 112 +.byte 97 +.byte 114 +.byte 105 +.byte 115 +.byte 105 +.byte 111 +.byte 110 +.byte 115 +.byte 32 +.byte 97 +.byte 114 +.byte 101 +.byte 32 +.byte 99 +.byte 104 +.byte 101 +.byte 99 +.byte 107 +.byte 101 +.byte 100 +.byte 32 +.byte 102 +.byte 111 +.byte 114 +.byte 32 +.byte 99 +.byte 111 +.byte 110 +.byte 115 +.byte 105 +.byte 115 +.byte 116 +.byte 101 +.byte 110 +.byte 99 +.byte 121 +.byte 32 +.byte 119 +.byte 105 +.byte 116 +.byte 104 +.byte 32 +.byte 115 +.byte 117 +.byte 98 +.byte 116 +.byte 114 +.byte 97 +.byte 99 +.byte 116 +.byte 105 +.byte 111 +.byte 110 +.byte 0 +.align 0 +L.977: +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 86 +.byte 48 +.byte 32 +.byte 32 +.byte 116 +.byte 101 +.byte 108 +.byte 108 +.byte 115 +.byte 44 +.byte 32 +.byte 114 +.byte 111 +.byte 117 +.byte 103 +.byte 104 +.byte 108 +.byte 121 +.byte 44 +.byte 32 +.byte 119 +.byte 104 +.byte 101 +.byte 116 +.byte 104 +.byte 101 +.byte 114 +.byte 32 +.byte 32 +.byte 73 +.byte 110 +.byte 102 +.byte 105 +.byte 110 +.byte 105 +.byte 116 +.byte 121 +.byte 32 +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 114 +.byte 101 +.byte 112 +.byte 114 +.byte 101 +.byte 115 +.byte 101 +.byte 110 +.byte 116 +.byte 101 +.byte 100 +.byte 46 +.byte 0 +.align 0 +L.976: +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 86 +.byte 32 +.byte 61 +.byte 32 +.byte 97 +.byte 110 +.byte 32 +.byte 111 +.byte 118 +.byte 101 +.byte 114 +.byte 102 +.byte 108 +.byte 111 +.byte 119 +.byte 32 +.byte 116 +.byte 104 +.byte 114 +.byte 101 +.byte 115 +.byte 104 +.byte 111 +.byte 108 +.byte 100 +.byte 44 +.byte 32 +.byte 114 +.byte 111 +.byte 117 +.byte 103 +.byte 104 +.byte 108 +.byte 121 +.byte 46 +.byte 0 +.align 0 +L.975: +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 69 +.byte 48 +.byte 32 +.byte 97 +.byte 110 +.byte 100 +.byte 32 +.byte 80 +.byte 115 +.byte 101 +.byte 117 +.byte 100 +.byte 111 +.byte 90 +.byte 101 +.byte 114 +.byte 111 +.byte 32 +.byte 116 +.byte 101 +.byte 108 +.byte 108 +.byte 32 +.byte 119 +.byte 104 +.byte 101 +.byte 116 +.byte 104 +.byte 101 +.byte 114 +.byte 32 +.byte 117 +.byte 110 +.byte 100 +.byte 101 +.byte 114 +.byte 102 +.byte 108 +.byte 111 +.byte 119 +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 97 +.byte 98 +.byte 114 +.byte 117 +.byte 112 +.byte 116 +.byte 44 +.byte 32 +.byte 103 +.byte 114 +.byte 97 +.byte 100 +.byte 117 +.byte 97 +.byte 108 +.byte 44 +.byte 32 +.byte 111 +.byte 114 +.byte 32 +.byte 102 +.byte 117 +.byte 122 +.byte 122 +.byte 121 +.byte 46 +.byte 0 +.align 0 +L.974: +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 85 +.byte 110 +.byte 100 +.byte 101 +.byte 114 +.byte 102 +.byte 108 +.byte 111 +.byte 119 +.byte 84 +.byte 104 +.byte 114 +.byte 101 +.byte 115 +.byte 104 +.byte 111 +.byte 108 +.byte 100 +.byte 32 +.byte 61 +.byte 32 +.byte 97 +.byte 110 +.byte 32 +.byte 117 +.byte 110 +.byte 100 +.byte 101 +.byte 114 +.byte 102 +.byte 108 +.byte 111 +.byte 119 +.byte 32 +.byte 116 +.byte 104 +.byte 114 +.byte 101 +.byte 115 +.byte 104 +.byte 111 +.byte 108 +.byte 100 +.byte 46 +.byte 0 +.align 0 +L.973: +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 87 +.byte 104 +.byte 101 +.byte 116 +.byte 104 +.byte 101 +.byte 114 +.byte 32 +.byte 97 +.byte 32 +.byte 83 +.byte 116 +.byte 105 +.byte 99 +.byte 107 +.byte 121 +.byte 32 +.byte 66 +.byte 105 +.byte 116 +.byte 32 +.byte 117 +.byte 115 +.byte 101 +.byte 100 +.byte 32 +.byte 99 +.byte 111 +.byte 114 +.byte 114 +.byte 101 +.byte 99 +.byte 116 +.byte 108 +.byte 121 +.byte 32 +.byte 102 +.byte 111 +.byte 114 +.byte 32 +.byte 114 +.byte 111 +.byte 117 +.byte 110 +.byte 100 +.byte 105 +.byte 110 +.byte 103 +.byte 46 +.byte 0 +.align 0 +L.972: +.byte 9 +.byte 102 +.byte 111 +.byte 114 +.byte 32 +.byte 77 +.byte 117 +.byte 108 +.byte 116 +.byte 46 +.byte 44 +.byte 32 +.byte 68 +.byte 105 +.byte 118 +.byte 46 +.byte 44 +.byte 32 +.byte 65 +.byte 100 +.byte 100 +.byte 47 +.byte 83 +.byte 117 +.byte 98 +.byte 116 +.byte 46 +.byte 32 +.byte 97 +.byte 110 +.byte 100 +.byte 32 +.byte 83 +.byte 113 +.byte 114 +.byte 116 +.byte 46 +.byte 0 +.align 0 +L.971: +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 87 +.byte 104 +.byte 101 +.byte 116 +.byte 104 +.byte 101 +.byte 114 +.byte 32 +.byte 97 +.byte 114 +.byte 105 +.byte 116 +.byte 104 +.byte 109 +.byte 101 +.byte 116 +.byte 105 +.byte 99 +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 99 +.byte 104 +.byte 111 +.byte 112 +.byte 112 +.byte 101 +.byte 100 +.byte 44 +.byte 32 +.byte 99 +.byte 111 +.byte 114 +.byte 114 +.byte 101 +.byte 99 +.byte 116 +.byte 108 +.byte 121 +.byte 32 +.byte 114 +.byte 111 +.byte 117 +.byte 110 +.byte 100 +.byte 101 +.byte 100 +.byte 44 +.byte 32 +.byte 111 +.byte 114 +.byte 32 +.byte 115 +.byte 111 +.byte 109 +.byte 101 +.byte 116 +.byte 104 +.byte 105 +.byte 110 +.byte 103 +.byte 32 +.byte 101 +.byte 108 +.byte 115 +.byte 101 +.byte 0 +.align 0 +L.970: +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 65 +.byte 100 +.byte 101 +.byte 113 +.byte 117 +.byte 97 +.byte 99 +.byte 121 +.byte 32 +.byte 111 +.byte 102 +.byte 32 +.byte 103 +.byte 117 +.byte 97 +.byte 114 +.byte 100 +.byte 32 +.byte 100 +.byte 105 +.byte 103 +.byte 105 +.byte 116 +.byte 115 +.byte 32 +.byte 102 +.byte 111 +.byte 114 +.byte 32 +.byte 77 +.byte 117 +.byte 108 +.byte 116 +.byte 46 +.byte 44 +.byte 32 +.byte 68 +.byte 105 +.byte 118 +.byte 46 +.byte 32 +.byte 97 +.byte 110 +.byte 100 +.byte 32 +.byte 83 +.byte 117 +.byte 98 +.byte 116 +.byte 46 +.byte 0 +.align 0 +L.969: +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 85 +.byte 49 +.byte 32 +.byte 61 +.byte 32 +.byte 49 +.byte 47 +.byte 82 +.byte 97 +.byte 100 +.byte 105 +.byte 120 +.byte 94 +.byte 80 +.byte 114 +.byte 101 +.byte 99 +.byte 105 +.byte 115 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 61 +.byte 32 +.byte 79 +.byte 110 +.byte 101 +.byte 32 +.byte 85 +.byte 108 +.byte 112 +.byte 32 +.byte 111 +.byte 102 +.byte 32 +.byte 110 +.byte 117 +.byte 109 +.byte 98 +.byte 101 +.byte 114 +.byte 115 +.byte 32 +.byte 97 +.byte 32 +.byte 108 +.byte 105 +.byte 116 +.byte 116 +.byte 108 +.byte 101 +.byte 32 +.byte 108 +.byte 101 +.byte 115 +.byte 115 +.byte 32 +.byte 116 +.byte 104 +.byte 97 +.byte 110 +.byte 32 +.byte 49 +.byte 46 +.byte 48 +.byte 32 +.byte 46 +.byte 0 +.align 0 +L.968: +.byte 9 +.byte 40 +.byte 79 +.byte 110 +.byte 101 +.byte 85 +.byte 108 +.byte 112 +.byte 110 +.byte 105 +.byte 116 +.byte 32 +.byte 105 +.byte 110 +.byte 32 +.byte 116 +.byte 104 +.byte 101 +.byte 32 +.byte 76 +.byte 97 +.byte 115 +.byte 116 +.byte 32 +.byte 80 +.byte 108 +.byte 97 +.byte 99 +.byte 101 +.byte 41 +.byte 32 +.byte 111 +.byte 102 +.byte 32 +.byte 49 +.byte 46 +.byte 48 +.byte 48 +.byte 48 +.byte 120 +.byte 120 +.byte 120 +.byte 32 +.byte 46 +.byte 0 +.align 0 +L.967: +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 85 +.byte 50 +.byte 32 +.byte 61 +.byte 32 +.byte 82 +.byte 97 +.byte 100 +.byte 105 +.byte 120 +.byte 47 +.byte 82 +.byte 97 +.byte 100 +.byte 105 +.byte 120 +.byte 94 +.byte 80 +.byte 114 +.byte 101 +.byte 99 +.byte 105 +.byte 115 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 61 +.byte 32 +.byte 79 +.byte 110 +.byte 101 +.byte 32 +.byte 85 +.byte 108 +.byte 112 +.byte 0 +.align 0 +L.966: +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 80 +.byte 114 +.byte 101 +.byte 99 +.byte 105 +.byte 115 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 61 +.byte 32 +.byte 110 +.byte 117 +.byte 109 +.byte 98 +.byte 101 +.byte 114 +.byte 32 +.byte 111 +.byte 102 +.byte 32 +.byte 115 +.byte 105 +.byte 103 +.byte 110 +.byte 105 +.byte 102 +.byte 105 +.byte 99 +.byte 97 +.byte 110 +.byte 116 +.byte 32 +.byte 100 +.byte 105 +.byte 103 +.byte 105 +.byte 116 +.byte 115 +.byte 32 +.byte 99 +.byte 97 +.byte 114 +.byte 114 +.byte 105 +.byte 101 +.byte 100 +.byte 46 +.byte 0 +.align 0 +L.965: +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 82 +.byte 97 +.byte 100 +.byte 105 +.byte 120 +.byte 32 +.byte 61 +.byte 32 +.byte 49 +.byte 44 +.byte 32 +.byte 50 +.byte 44 +.byte 32 +.byte 52 +.byte 44 +.byte 32 +.byte 56 +.byte 44 +.byte 32 +.byte 49 +.byte 48 +.byte 44 +.byte 32 +.byte 49 +.byte 54 +.byte 44 +.byte 32 +.byte 49 +.byte 48 +.byte 48 +.byte 44 +.byte 32 +.byte 50 +.byte 53 +.byte 54 +.byte 32 +.byte 46 +.byte 46 +.byte 46 +.byte 0 +.align 0 +L.964: +.byte 82 +.byte 117 +.byte 110 +.byte 110 +.byte 105 +.byte 110 +.byte 103 +.byte 32 +.byte 116 +.byte 104 +.byte 105 +.byte 115 +.byte 32 +.byte 112 +.byte 114 +.byte 111 +.byte 103 +.byte 114 +.byte 97 +.byte 109 +.byte 32 +.byte 115 +.byte 104 +.byte 111 +.byte 117 +.byte 108 +.byte 100 +.byte 32 +.byte 114 +.byte 101 +.byte 118 +.byte 101 +.byte 97 +.byte 108 +.byte 32 +.byte 116 +.byte 104 +.byte 101 +.byte 115 +.byte 101 +.byte 32 +.byte 99 +.byte 104 +.byte 97 +.byte 114 +.byte 97 +.byte 99 +.byte 116 +.byte 101 +.byte 114 +.byte 105 +.byte 115 +.byte 116 +.byte 105 +.byte 99 +.byte 115 +.byte 58 +.byte 0 +.align 0 +L.961: +.byte 9 +.byte 79 +.byte 116 +.byte 104 +.byte 101 +.byte 114 +.byte 32 +.byte 114 +.byte 101 +.byte 108 +.byte 101 +.byte 118 +.byte 97 +.byte 110 +.byte 116 +.byte 32 +.byte 99 +.byte 111 +.byte 109 +.byte 112 +.byte 105 +.byte 108 +.byte 101 +.byte 114 +.byte 32 +.byte 111 +.byte 112 +.byte 116 +.byte 105 +.byte 111 +.byte 110 +.byte 115 +.byte 58 +.byte 0 +.align 0 +L.960: +.byte 9 +.byte 79 +.byte 112 +.byte 116 +.byte 105 +.byte 109 +.byte 105 +.byte 122 +.byte 97 +.byte 116 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 108 +.byte 101 +.byte 118 +.byte 101 +.byte 108 +.byte 58 +.byte 10 +.byte 0 +.align 0 +L.959: +.byte 9 +.byte 67 +.byte 111 +.byte 109 +.byte 112 +.byte 105 +.byte 108 +.byte 101 +.byte 114 +.byte 58 +.byte 10 +.byte 0 +.align 0 +L.958: +.byte 9 +.byte 67 +.byte 111 +.byte 109 +.byte 112 +.byte 117 +.byte 116 +.byte 101 +.byte 114 +.byte 58 +.byte 10 +.byte 0 +.align 0 +L.957: +.byte 9 +.byte 86 +.byte 101 +.byte 114 +.byte 115 +.byte 105 +.byte 111 +.byte 110 +.byte 58 +.byte 9 +.byte 49 +.byte 48 +.byte 32 +.byte 70 +.byte 101 +.byte 98 +.byte 114 +.byte 117 +.byte 97 +.byte 114 +.byte 121 +.byte 32 +.byte 49 +.byte 57 +.byte 56 +.byte 57 +.byte 59 +.byte 0 +.align 0 +L.956: +.byte 9 +.byte 80 +.byte 114 +.byte 101 +.byte 99 +.byte 105 +.byte 115 +.byte 105 +.byte 111 +.byte 110 +.byte 58 +.byte 9 +.byte 100 +.byte 111 +.byte 117 +.byte 98 +.byte 108 +.byte 101 +.byte 59 +.byte 0 +.align 0 +L.955: +.byte 73 +.byte 110 +.byte 32 +.byte 100 +.byte 111 +.byte 105 +.byte 110 +.byte 103 +.byte 32 +.byte 115 +.byte 111 +.byte 44 +.byte 32 +.byte 112 +.byte 108 +.byte 101 +.byte 97 +.byte 115 +.byte 101 +.byte 32 +.byte 105 +.byte 110 +.byte 99 +.byte 108 +.byte 117 +.byte 100 +.byte 101 +.byte 32 +.byte 116 +.byte 104 +.byte 101 +.byte 32 +.byte 102 +.byte 111 +.byte 108 +.byte 108 +.byte 111 +.byte 119 +.byte 105 +.byte 110 +.byte 103 +.byte 32 +.byte 105 +.byte 110 +.byte 102 +.byte 111 +.byte 114 +.byte 109 +.byte 97 +.byte 116 +.byte 105 +.byte 111 +.byte 110 +.byte 58 +.byte 0 +.align 0 +L.954: +.byte 9 +.byte 83 +.byte 97 +.byte 110 +.byte 32 +.byte 70 +.byte 114 +.byte 97 +.byte 110 +.byte 99 +.byte 105 +.byte 115 +.byte 99 +.byte 111 +.byte 44 +.byte 32 +.byte 67 +.byte 65 +.byte 32 +.byte 57 +.byte 52 +.byte 49 +.byte 52 +.byte 51 +.byte 45 +.byte 48 +.byte 55 +.byte 48 +.byte 52 +.byte 44 +.byte 32 +.byte 85 +.byte 83 +.byte 65 +.byte 10 +.byte 0 +.align 0 +L.953: +.byte 9 +.byte 85 +.byte 110 +.byte 105 +.byte 118 +.byte 101 +.byte 114 +.byte 115 +.byte 105 +.byte 116 +.byte 121 +.byte 32 +.byte 111 +.byte 102 +.byte 32 +.byte 67 +.byte 97 +.byte 108 +.byte 105 +.byte 102 +.byte 111 +.byte 114 +.byte 110 +.byte 105 +.byte 97 +.byte 0 +.align 0 +L.952: +.byte 9 +.byte 67 +.byte 111 +.byte 109 +.byte 112 +.byte 117 +.byte 116 +.byte 101 +.byte 114 +.byte 32 +.byte 67 +.byte 101 +.byte 110 +.byte 116 +.byte 101 +.byte 114 +.byte 32 +.byte 85 +.byte 45 +.byte 55 +.byte 54 +.byte 0 +.align 0 +L.951: +.byte 9 +.byte 82 +.byte 105 +.byte 99 +.byte 104 +.byte 97 +.byte 114 +.byte 100 +.byte 32 +.byte 75 +.byte 97 +.byte 114 +.byte 112 +.byte 105 +.byte 110 +.byte 115 +.byte 107 +.byte 105 +.byte 0 +.align 0 +L.950: +.byte 80 +.byte 108 +.byte 101 +.byte 97 +.byte 115 +.byte 101 +.byte 32 +.byte 115 +.byte 101 +.byte 110 +.byte 100 +.byte 32 +.byte 115 +.byte 117 +.byte 103 +.byte 103 +.byte 101 +.byte 115 +.byte 116 +.byte 105 +.byte 111 +.byte 110 +.byte 115 +.byte 32 +.byte 97 +.byte 110 +.byte 100 +.byte 32 +.byte 105 +.byte 110 +.byte 116 +.byte 101 +.byte 114 +.byte 101 +.byte 115 +.byte 116 +.byte 105 +.byte 110 +.byte 103 +.byte 32 +.byte 114 +.byte 101 +.byte 115 +.byte 117 +.byte 108 +.byte 116 +.byte 115 +.byte 32 +.byte 116 +.byte 111 +.byte 0 +.align 0 +L.949: +.byte 99 +.byte 111 +.byte 112 +.byte 101 +.byte 32 +.byte 119 +.byte 105 +.byte 116 +.byte 104 +.byte 32 +.byte 117 +.byte 110 +.byte 97 +.byte 110 +.byte 116 +.byte 105 +.byte 99 +.byte 105 +.byte 112 +.byte 97 +.byte 116 +.byte 101 +.byte 100 +.byte 32 +.byte 97 +.byte 110 +.byte 100 +.byte 32 +.byte 110 +.byte 101 +.byte 119 +.byte 108 +.byte 121 +.byte 32 +.byte 117 +.byte 110 +.byte 99 +.byte 111 +.byte 118 +.byte 101 +.byte 114 +.byte 101 +.byte 100 +.byte 32 +.byte 97 +.byte 114 +.byte 105 +.byte 116 +.byte 104 +.byte 109 +.byte 101 +.byte 116 +.byte 105 +.byte 99 +.byte 32 +.byte 112 +.byte 97 +.byte 116 +.byte 104 +.byte 111 +.byte 108 +.byte 111 +.byte 103 +.byte 105 +.byte 101 +.byte 115 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.948: +.byte 85 +.byte 115 +.byte 101 +.byte 114 +.byte 115 +.byte 32 +.byte 97 +.byte 114 +.byte 101 +.byte 32 +.byte 105 +.byte 110 +.byte 118 +.byte 105 +.byte 116 +.byte 101 +.byte 100 +.byte 32 +.byte 116 +.byte 111 +.byte 32 +.byte 104 +.byte 101 +.byte 108 +.byte 112 +.byte 32 +.byte 100 +.byte 101 +.byte 98 +.byte 117 +.byte 103 +.byte 32 +.byte 97 +.byte 110 +.byte 100 +.byte 32 +.byte 97 +.byte 117 +.byte 103 +.byte 109 +.byte 101 +.byte 110 +.byte 116 +.byte 32 +.byte 116 +.byte 104 +.byte 105 +.byte 115 +.byte 32 +.byte 112 +.byte 114 +.byte 111 +.byte 103 +.byte 114 +.byte 97 +.byte 109 +.byte 32 +.byte 115 +.byte 111 +.byte 32 +.byte 105 +.byte 116 +.byte 32 +.byte 119 +.byte 105 +.byte 108 +.byte 108 +.byte 0 +.align 0 +L.945: +.byte 65 +.byte 110 +.byte 115 +.byte 119 +.byte 101 +.byte 114 +.byte 32 +.byte 113 +.byte 117 +.byte 101 +.byte 115 +.byte 116 +.byte 105 +.byte 111 +.byte 110 +.byte 115 +.byte 32 +.byte 119 +.byte 105 +.byte 116 +.byte 104 +.byte 32 +.byte 89 +.byte 44 +.byte 32 +.byte 121 +.byte 44 +.byte 32 +.byte 78 +.byte 32 +.byte 111 +.byte 114 +.byte 32 +.byte 110 +.byte 32 +.byte 40 +.byte 117 +.byte 110 +.byte 108 +.byte 101 +.byte 115 +.byte 115 +.byte 32 +.byte 111 +.byte 116 +.byte 104 +.byte 101 +.byte 114 +.byte 119 +.byte 105 +.byte 115 +.byte 101 +.byte 32 +.byte 105 +.byte 110 +.byte 100 +.byte 105 +.byte 99 +.byte 97 +.byte 116 +.byte 101 +.byte 100 +.byte 41 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.944: +.byte 97 +.byte 109 +.byte 101 +.byte 110 +.byte 100 +.byte 32 +.byte 105 +.byte 116 +.byte 32 +.byte 116 +.byte 111 +.byte 32 +.byte 109 +.byte 97 +.byte 107 +.byte 101 +.byte 32 +.byte 102 +.byte 117 +.byte 114 +.byte 116 +.byte 104 +.byte 101 +.byte 114 +.byte 32 +.byte 112 +.byte 114 +.byte 111 +.byte 103 +.byte 114 +.byte 101 +.byte 115 +.byte 115 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.943: +.byte 112 +.byte 114 +.byte 111 +.byte 103 +.byte 114 +.byte 97 +.byte 109 +.byte 32 +.byte 97 +.byte 110 +.byte 121 +.byte 119 +.byte 97 +.byte 121 +.byte 32 +.byte 116 +.byte 111 +.byte 32 +.byte 115 +.byte 101 +.byte 101 +.byte 32 +.byte 104 +.byte 111 +.byte 119 +.byte 32 +.byte 109 +.byte 97 +.byte 110 +.byte 121 +.byte 32 +.byte 109 +.byte 105 +.byte 108 +.byte 101 +.byte 115 +.byte 116 +.byte 111 +.byte 110 +.byte 101 +.byte 115 +.byte 32 +.byte 105 +.byte 116 +.byte 32 +.byte 112 +.byte 97 +.byte 115 +.byte 115 +.byte 101 +.byte 115 +.byte 44 +.byte 32 +.byte 97 +.byte 110 +.byte 100 +.byte 32 +.byte 116 +.byte 104 +.byte 101 +.byte 110 +.byte 0 +.align 0 +L.942: +.byte 119 +.byte 97 +.byte 114 +.byte 110 +.byte 105 +.byte 110 +.byte 103 +.byte 46 +.byte 32 +.byte 32 +.byte 73 +.byte 102 +.byte 32 +.byte 112 +.byte 101 +.byte 114 +.byte 115 +.byte 117 +.byte 97 +.byte 115 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 97 +.byte 118 +.byte 97 +.byte 105 +.byte 108 +.byte 115 +.byte 32 +.byte 110 +.byte 97 +.byte 117 +.byte 103 +.byte 104 +.byte 116 +.byte 44 +.byte 32 +.byte 100 +.byte 111 +.byte 110 +.byte 39 +.byte 116 +.byte 32 +.byte 100 +.byte 101 +.byte 115 +.byte 112 +.byte 97 +.byte 105 +.byte 114 +.byte 32 +.byte 98 +.byte 117 +.byte 116 +.byte 32 +.byte 114 +.byte 117 +.byte 110 +.byte 32 +.byte 116 +.byte 104 +.byte 105 +.byte 115 +.byte 0 +.align 0 +L.941: +.byte 116 +.byte 111 +.byte 32 +.byte 112 +.byte 101 +.byte 114 +.byte 115 +.byte 101 +.byte 118 +.byte 101 +.byte 114 +.byte 101 +.byte 32 +.byte 119 +.byte 105 +.byte 116 +.byte 104 +.byte 32 +.byte 97 +.byte 32 +.byte 115 +.byte 117 +.byte 114 +.byte 114 +.byte 111 +.byte 103 +.byte 97 +.byte 116 +.byte 101 +.byte 32 +.byte 118 +.byte 97 +.byte 108 +.byte 117 +.byte 101 +.byte 32 +.byte 97 +.byte 102 +.byte 116 +.byte 101 +.byte 114 +.byte 44 +.byte 32 +.byte 112 +.byte 101 +.byte 114 +.byte 104 +.byte 97 +.byte 112 +.byte 115 +.byte 44 +.byte 32 +.byte 100 +.byte 105 +.byte 115 +.byte 112 +.byte 108 +.byte 97 +.byte 121 +.byte 105 +.byte 110 +.byte 103 +.byte 32 +.byte 115 +.byte 111 +.byte 109 +.byte 101 +.byte 0 +.align 0 +L.940: +.byte 101 +.byte 114 +.byte 114 +.byte 111 +.byte 114 +.byte 32 +.byte 108 +.byte 105 +.byte 107 +.byte 101 +.byte 32 +.byte 79 +.byte 118 +.byte 101 +.byte 114 +.byte 47 +.byte 85 +.byte 110 +.byte 100 +.byte 101 +.byte 114 +.byte 102 +.byte 108 +.byte 111 +.byte 119 +.byte 32 +.byte 111 +.byte 114 +.byte 32 +.byte 68 +.byte 105 +.byte 118 +.byte 105 +.byte 115 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 98 +.byte 121 +.byte 32 +.byte 90 +.byte 101 +.byte 114 +.byte 111 +.byte 32 +.byte 111 +.byte 99 +.byte 99 +.byte 117 +.byte 114 +.byte 115 +.byte 44 +.byte 32 +.byte 98 +.byte 117 +.byte 116 +.byte 32 +.byte 114 +.byte 97 +.byte 116 +.byte 104 +.byte 101 +.byte 114 +.byte 0 +.align 0 +L.939: +.byte 116 +.byte 114 +.byte 121 +.byte 32 +.byte 116 +.byte 111 +.byte 32 +.byte 112 +.byte 101 +.byte 114 +.byte 115 +.byte 117 +.byte 97 +.byte 100 +.byte 101 +.byte 32 +.byte 116 +.byte 104 +.byte 101 +.byte 32 +.byte 99 +.byte 111 +.byte 109 +.byte 112 +.byte 117 +.byte 116 +.byte 101 +.byte 114 +.byte 32 +.byte 78 +.byte 79 +.byte 84 +.byte 32 +.byte 116 +.byte 111 +.byte 32 +.byte 116 +.byte 101 +.byte 114 +.byte 109 +.byte 105 +.byte 110 +.byte 97 +.byte 116 +.byte 101 +.byte 32 +.byte 101 +.byte 120 +.byte 101 +.byte 99 +.byte 117 +.byte 116 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 119 +.byte 104 +.byte 101 +.byte 110 +.byte 32 +.byte 97 +.byte 110 +.byte 0 +.align 0 +L.938: +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 96 +.byte 69 +.byte 78 +.byte 68 +.byte 32 +.byte 79 +.byte 70 +.byte 32 +.byte 84 +.byte 69 +.byte 83 +.byte 84 +.byte 39 +.byte 44 +.byte 10 +.byte 0 +.align 0 +L.937: +.byte 76 +.byte 101 +.byte 115 +.byte 116 +.byte 32 +.byte 116 +.byte 104 +.byte 105 +.byte 115 +.byte 32 +.byte 112 +.byte 114 +.byte 111 +.byte 103 +.byte 114 +.byte 97 +.byte 109 +.byte 32 +.byte 115 +.byte 116 +.byte 111 +.byte 112 +.byte 32 +.byte 112 +.byte 114 +.byte 101 +.byte 109 +.byte 97 +.byte 116 +.byte 117 +.byte 114 +.byte 101 +.byte 108 +.byte 121 +.byte 44 +.byte 32 +.byte 105 +.byte 46 +.byte 101 +.byte 46 +.byte 32 +.byte 98 +.byte 101 +.byte 102 +.byte 111 +.byte 114 +.byte 101 +.byte 32 +.byte 100 +.byte 105 +.byte 115 +.byte 112 +.byte 108 +.byte 97 +.byte 121 +.byte 105 +.byte 110 +.byte 103 +.byte 10 +.byte 0 +.align 0 +L.934: +.byte 37 +.byte 115 +.byte 10 +.byte 0 +.align 0 +L.929: +.byte 32 +.byte 32 +.byte 32 +.byte 80 +.byte 76 +.byte 69 +.byte 65 +.byte 83 +.byte 69 +.byte 32 +.byte 78 +.byte 79 +.byte 84 +.byte 73 +.byte 70 +.byte 89 +.byte 32 +.byte 75 +.byte 65 +.byte 82 +.byte 80 +.byte 73 +.byte 78 +.byte 75 +.byte 83 +.byte 73 +.byte 33 +.byte 10 +.byte 0 +.align 0 +L.928: +.byte 37 +.byte 115 +.byte 32 +.byte 116 +.byte 101 +.byte 115 +.byte 116 +.byte 32 +.byte 97 +.byte 112 +.byte 112 +.byte 101 +.byte 97 +.byte 114 +.byte 115 +.byte 32 +.byte 116 +.byte 111 +.byte 32 +.byte 98 +.byte 101 +.byte 32 +.byte 105 +.byte 110 +.byte 99 +.byte 111 +.byte 110 +.byte 115 +.byte 105 +.byte 115 +.byte 116 +.byte 101 +.byte 110 +.byte 116 +.byte 46 +.byte 46 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.926: +.byte 9 +.byte 100 +.byte 105 +.byte 102 +.byte 102 +.byte 101 +.byte 114 +.byte 115 +.byte 32 +.byte 102 +.byte 114 +.byte 111 +.byte 109 +.byte 32 +.byte 90 +.byte 32 +.byte 42 +.byte 32 +.byte 49 +.byte 32 +.byte 61 +.byte 32 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 10 +.byte 0 +.align 0 +L.925: +.byte 9 +.byte 67 +.byte 111 +.byte 109 +.byte 112 +.byte 97 +.byte 114 +.byte 105 +.byte 115 +.byte 111 +.byte 110 +.byte 32 +.byte 97 +.byte 108 +.byte 108 +.byte 101 +.byte 103 +.byte 101 +.byte 115 +.byte 32 +.byte 116 +.byte 104 +.byte 97 +.byte 116 +.byte 32 +.byte 49 +.byte 32 +.byte 42 +.byte 32 +.byte 90 +.byte 32 +.byte 61 +.byte 32 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 10 +.byte 0 +.align 0 +L.924: +.byte 77 +.byte 117 +.byte 108 +.byte 116 +.byte 105 +.byte 112 +.byte 108 +.byte 105 +.byte 99 +.byte 97 +.byte 116 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 100 +.byte 111 +.byte 101 +.byte 115 +.byte 32 +.byte 110 +.byte 111 +.byte 116 +.byte 32 +.byte 99 +.byte 111 +.byte 109 +.byte 109 +.byte 117 +.byte 116 +.byte 101 +.byte 33 +.byte 10 +.byte 0 +.align 0 +L.919: +.byte 90 +.byte 32 +.byte 47 +.byte 32 +.byte 49 +.byte 32 +.byte 61 +.byte 32 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 10 +.byte 0 +.align 0 +L.916: +.byte 49 +.byte 32 +.byte 42 +.byte 32 +.byte 90 +.byte 32 +.byte 61 +.byte 61 +.byte 32 +.byte 37 +.byte 103 +.byte 10 +.byte 0 +.align 0 +L.913: +.byte 90 +.byte 32 +.byte 42 +.byte 32 +.byte 49 +.byte 32 +.byte 61 +.byte 32 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 32 +.byte 0 +.align 0 +L.910: +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 10 +.byte 9 +.byte 99 +.byte 111 +.byte 109 +.byte 112 +.byte 97 +.byte 114 +.byte 101 +.byte 115 +.byte 32 +.byte 100 +.byte 105 +.byte 102 +.byte 102 +.byte 101 +.byte 114 +.byte 101 +.byte 110 +.byte 116 +.byte 32 +.byte 102 +.byte 114 +.byte 111 +.byte 109 +.byte 32 +.byte 32 +.byte 0 +.align 0 +L.909: +.byte 87 +.byte 104 +.byte 97 +.byte 116 +.byte 32 +.byte 112 +.byte 114 +.byte 105 +.byte 110 +.byte 116 +.byte 115 +.byte 32 +.byte 97 +.byte 115 +.byte 32 +.byte 90 +.byte 32 +.byte 61 +.byte 32 +.byte 0 +.align 0 +L.904: +.byte 84 +.byte 104 +.byte 105 +.byte 115 +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 97 +.byte 32 +.byte 68 +.byte 69 +.byte 70 +.byte 69 +.byte 67 +.byte 84 +.byte 33 +.byte 10 +.byte 0 +.align 0 +L.901: +.byte 84 +.byte 104 +.byte 105 +.byte 115 +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 97 +.byte 32 +.byte 86 +.byte 69 +.byte 82 +.byte 89 +.byte 32 +.byte 83 +.byte 69 +.byte 82 +.byte 73 +.byte 79 +.byte 85 +.byte 83 +.byte 32 +.byte 68 +.byte 69 +.byte 70 +.byte 69 +.byte 67 +.byte 84 +.byte 33 +.byte 10 +.byte 0 +.align 0 +L.895: +.byte 32 +.byte 104 +.byte 97 +.byte 115 +.byte 32 +.byte 78 +.byte 79 +.byte 84 +.byte 32 +.byte 106 +.byte 117 +.byte 115 +.byte 116 +.byte 32 +.byte 98 +.byte 101 +.byte 101 +.byte 110 +.byte 32 +.byte 115 +.byte 105 +.byte 103 +.byte 110 +.byte 97 +.byte 108 +.byte 101 +.byte 100 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.894: +.byte 84 +.byte 104 +.byte 105 +.byte 115 +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 79 +.byte 46 +.byte 75 +.byte 46 +.byte 44 +.byte 32 +.byte 112 +.byte 114 +.byte 111 +.byte 118 +.byte 105 +.byte 100 +.byte 101 +.byte 100 +.byte 32 +.byte 79 +.byte 118 +.byte 101 +.byte 114 +.byte 47 +.byte 85 +.byte 110 +.byte 100 +.byte 101 +.byte 114 +.byte 102 +.byte 108 +.byte 111 +.byte 119 +.byte 0 +.align 0 +L.891: +.byte 87 +.byte 104 +.byte 97 +.byte 116 +.byte 32 +.byte 116 +.byte 104 +.byte 101 +.byte 32 +.byte 109 +.byte 97 +.byte 99 +.byte 104 +.byte 105 +.byte 110 +.byte 101 +.byte 32 +.byte 103 +.byte 101 +.byte 116 +.byte 115 +.byte 32 +.byte 102 +.byte 111 +.byte 114 +.byte 32 +.byte 40 +.byte 90 +.byte 32 +.byte 43 +.byte 32 +.byte 90 +.byte 41 +.byte 32 +.byte 47 +.byte 32 +.byte 90 +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 32 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 32 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.887: +.byte 40 +.byte 90 +.byte 32 +.byte 43 +.byte 32 +.byte 90 +.byte 41 +.byte 32 +.byte 47 +.byte 32 +.byte 90 +.byte 32 +.byte 115 +.byte 104 +.byte 111 +.byte 117 +.byte 108 +.byte 100 +.byte 32 +.byte 98 +.byte 101 +.byte 32 +.byte 115 +.byte 97 +.byte 102 +.byte 101 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.886: +.byte 83 +.byte 105 +.byte 110 +.byte 99 +.byte 101 +.byte 32 +.byte 99 +.byte 111 +.byte 109 +.byte 112 +.byte 97 +.byte 114 +.byte 105 +.byte 115 +.byte 111 +.byte 110 +.byte 32 +.byte 100 +.byte 101 +.byte 110 +.byte 105 +.byte 101 +.byte 115 +.byte 32 +.byte 90 +.byte 32 +.byte 61 +.byte 32 +.byte 48 +.byte 44 +.byte 32 +.byte 101 +.byte 118 +.byte 97 +.byte 108 +.byte 117 +.byte 97 +.byte 116 +.byte 105 +.byte 110 +.byte 103 +.byte 32 +.byte 0 +.align 0 +L.882: +.byte 83 +.byte 105 +.byte 109 +.byte 105 +.byte 108 +.byte 97 +.byte 114 +.byte 32 +.byte 100 +.byte 105 +.byte 115 +.byte 99 +.byte 114 +.byte 101 +.byte 112 +.byte 97 +.byte 110 +.byte 99 +.byte 105 +.byte 101 +.byte 115 +.byte 32 +.byte 104 +.byte 97 +.byte 118 +.byte 101 +.byte 32 +.byte 111 +.byte 99 +.byte 99 +.byte 117 +.byte 114 +.byte 114 +.byte 101 +.byte 100 +.byte 32 +.byte 37 +.byte 100 +.byte 32 +.byte 116 +.byte 105 +.byte 109 +.byte 101 +.byte 115 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.872: +.byte 9 +.byte 9 +.byte 116 +.byte 104 +.byte 101 +.byte 121 +.byte 32 +.byte 100 +.byte 105 +.byte 102 +.byte 102 +.byte 101 +.byte 114 +.byte 32 +.byte 98 +.byte 121 +.byte 32 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 32 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.871: +.byte 9 +.byte 119 +.byte 104 +.byte 105 +.byte 99 +.byte 104 +.byte 32 +.byte 99 +.byte 111 +.byte 109 +.byte 112 +.byte 97 +.byte 114 +.byte 101 +.byte 100 +.byte 32 +.byte 117 +.byte 110 +.byte 101 +.byte 113 +.byte 117 +.byte 97 +.byte 108 +.byte 32 +.byte 116 +.byte 111 +.byte 32 +.byte 99 +.byte 111 +.byte 114 +.byte 114 +.byte 101 +.byte 99 +.byte 116 +.byte 32 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 32 +.byte 59 +.byte 10 +.byte 0 +.align 0 +L.870: +.byte 9 +.byte 121 +.byte 105 +.byte 101 +.byte 108 +.byte 100 +.byte 101 +.byte 100 +.byte 32 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 59 +.byte 10 +.byte 0 +.align 0 +L.869: +.byte 9 +.byte 40 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 41 +.byte 32 +.byte 94 +.byte 32 +.byte 40 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 41 +.byte 10 +.byte 0 +.align 0 +L.868: +.byte 99 +.byte 111 +.byte 109 +.byte 112 +.byte 117 +.byte 116 +.byte 105 +.byte 110 +.byte 103 +.byte 10 +.byte 0 +.align 0 +L.867: +.byte 87 +.byte 65 +.byte 82 +.byte 78 +.byte 73 +.byte 78 +.byte 71 +.byte 58 +.byte 32 +.byte 32 +.byte 99 +.byte 111 +.byte 109 +.byte 112 +.byte 117 +.byte 116 +.byte 105 +.byte 110 +.byte 103 +.byte 10 +.byte 0 +.align 0 +L.849: +.byte 9 +.byte 105 +.byte 110 +.byte 115 +.byte 116 +.byte 101 +.byte 97 +.byte 100 +.byte 32 +.byte 111 +.byte 102 +.byte 32 +.byte 99 +.byte 111 +.byte 114 +.byte 114 +.byte 101 +.byte 99 +.byte 116 +.byte 32 +.byte 118 +.byte 97 +.byte 108 +.byte 117 +.byte 101 +.byte 32 +.byte 48 +.byte 32 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.848: +.byte 115 +.byte 113 +.byte 114 +.byte 116 +.byte 40 +.byte 32 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 41 +.byte 32 +.byte 45 +.byte 32 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 32 +.byte 32 +.byte 61 +.byte 32 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 10 +.byte 0 +.align 3 +L.840: +.word 0x3ed4f8b5 +.word 0x88e368f1 +.align 0 +L.838: +.byte 37 +.byte 115 +.byte 58 +.byte 32 +.byte 32 +.byte 37 +.byte 115 +.byte 0 +.align 0 +L.837: +.byte 70 +.byte 76 +.byte 65 +.byte 87 +.byte 0 +.align 0 +L.836: +.byte 68 +.byte 69 +.byte 70 +.byte 69 +.byte 67 +.byte 84 +.byte 0 +.align 0 +L.835: +.byte 83 +.byte 69 +.byte 82 +.byte 73 +.byte 79 +.byte 85 +.byte 83 +.byte 32 +.byte 68 +.byte 69 +.byte 70 +.byte 69 +.byte 67 +.byte 84 +.byte 0 +.align 0 +L.834: +.byte 70 +.byte 65 +.byte 73 +.byte 76 +.byte 85 +.byte 82 +.byte 69 +.byte 0 +.align 0 +L.828: +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 80 +.byte 97 +.byte 103 +.byte 101 +.byte 58 +.byte 32 +.byte 37 +.byte 100 +.byte 10 +.byte 10 +.byte 0 +.align 0 +L.827: +.byte 10 +.byte 68 +.byte 105 +.byte 97 +.byte 103 +.byte 110 +.byte 111 +.byte 115 +.byte 105 +.byte 115 +.byte 32 +.byte 114 +.byte 101 +.byte 115 +.byte 117 +.byte 109 +.byte 101 +.byte 115 +.byte 32 +.byte 97 +.byte 102 +.byte 116 +.byte 101 +.byte 114 +.byte 32 +.byte 109 +.byte 105 +.byte 108 +.byte 101 +.byte 115 +.byte 116 +.byte 111 +.byte 110 +.byte 101 +.byte 32 +.byte 78 +.byte 117 +.byte 109 +.byte 98 +.byte 101 +.byte 114 +.byte 32 +.byte 37 +.byte 100 +.byte 0 +.align 3 +L.825: +.word 0xbff00000 +.word 0x0 +.align 0 +L.820: +.byte 69 +.byte 78 +.byte 68 +.byte 32 +.byte 79 +.byte 70 +.byte 32 +.byte 84 +.byte 69 +.byte 83 +.byte 84 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.819: +.byte 10 +.byte 65 +.byte 32 +.byte 116 +.byte 111 +.byte 116 +.byte 97 +.byte 108 +.byte 32 +.byte 111 +.byte 102 +.byte 32 +.byte 37 +.byte 100 +.byte 32 +.byte 102 +.byte 108 +.byte 111 +.byte 97 +.byte 116 +.byte 105 +.byte 110 +.byte 103 +.byte 32 +.byte 112 +.byte 111 +.byte 105 +.byte 110 +.byte 116 +.byte 32 +.byte 101 +.byte 120 +.byte 99 +.byte 101 +.byte 112 +.byte 116 +.byte 105 +.byte 111 +.byte 110 +.byte 115 +.byte 32 +.byte 119 +.byte 101 +.byte 114 +.byte 101 +.byte 32 +.byte 114 +.byte 101 +.byte 103 +.byte 105 +.byte 115 +.byte 116 +.byte 101 +.byte 114 +.byte 101 +.byte 100 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.816: +.byte 84 +.byte 104 +.byte 101 +.byte 32 +.byte 97 +.byte 114 +.byte 105 +.byte 116 +.byte 104 +.byte 109 +.byte 101 +.byte 116 +.byte 105 +.byte 99 +.byte 32 +.byte 100 +.byte 105 +.byte 97 +.byte 103 +.byte 110 +.byte 111 +.byte 115 +.byte 101 +.byte 100 +.byte 32 +.byte 97 +.byte 112 +.byte 112 +.byte 101 +.byte 97 +.byte 114 +.byte 115 +.byte 32 +.byte 116 +.byte 111 +.byte 32 +.byte 98 +.byte 101 +.byte 32 +.byte 69 +.byte 120 +.byte 99 +.byte 101 +.byte 108 +.byte 108 +.byte 101 +.byte 110 +.byte 116 +.byte 33 +.byte 10 +.byte 0 +.align 0 +L.815: +.byte 32 +.byte 100 +.byte 117 +.byte 114 +.byte 105 +.byte 110 +.byte 103 +.byte 32 +.byte 71 +.byte 114 +.byte 97 +.byte 100 +.byte 117 +.byte 97 +.byte 108 +.byte 32 +.byte 85 +.byte 110 +.byte 100 +.byte 101 +.byte 114 +.byte 102 +.byte 108 +.byte 111 +.byte 119 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.814: +.byte 44 +.byte 10 +.byte 101 +.byte 120 +.byte 99 +.byte 101 +.byte 112 +.byte 116 +.byte 32 +.byte 102 +.byte 111 +.byte 114 +.byte 32 +.byte 112 +.byte 111 +.byte 115 +.byte 115 +.byte 105 +.byte 98 +.byte 108 +.byte 121 +.byte 32 +.byte 68 +.byte 111 +.byte 117 +.byte 98 +.byte 108 +.byte 101 +.byte 32 +.byte 82 +.byte 111 +.byte 117 +.byte 110 +.byte 100 +.byte 105 +.byte 110 +.byte 103 +.byte 0 +.align 0 +L.813: +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.810: +.byte 56 +.byte 53 +.byte 52 +.byte 0 +.align 0 +L.809: +.byte 55 +.byte 53 +.byte 52 +.byte 0 +.align 0 +L.806: +.byte 116 +.byte 104 +.byte 101 +.byte 32 +.byte 112 +.byte 114 +.byte 111 +.byte 112 +.byte 111 +.byte 115 +.byte 101 +.byte 100 +.byte 32 +.byte 73 +.byte 69 +.byte 69 +.byte 69 +.byte 32 +.byte 115 +.byte 116 +.byte 97 +.byte 110 +.byte 100 +.byte 97 +.byte 114 +.byte 100 +.byte 32 +.byte 80 +.byte 0 +.align 0 +L.805: +.byte 82 +.byte 111 +.byte 117 +.byte 110 +.byte 100 +.byte 105 +.byte 110 +.byte 103 +.byte 32 +.byte 97 +.byte 112 +.byte 112 +.byte 101 +.byte 97 +.byte 114 +.byte 115 +.byte 32 +.byte 116 +.byte 111 +.byte 32 +.byte 99 +.byte 111 +.byte 110 +.byte 102 +.byte 111 +.byte 114 +.byte 109 +.byte 32 +.byte 116 +.byte 111 +.byte 32 +.byte 0 +.align 0 +L.802: +.byte 84 +.byte 104 +.byte 101 +.byte 32 +.byte 97 +.byte 114 +.byte 105 +.byte 116 +.byte 104 +.byte 109 +.byte 101 +.byte 116 +.byte 105 +.byte 99 +.byte 32 +.byte 100 +.byte 105 +.byte 97 +.byte 103 +.byte 110 +.byte 111 +.byte 115 +.byte 101 +.byte 100 +.byte 32 +.byte 115 +.byte 101 +.byte 101 +.byte 109 +.byte 115 +.byte 32 +.byte 83 +.byte 97 +.byte 116 +.byte 105 +.byte 115 +.byte 102 +.byte 97 +.byte 99 +.byte 116 +.byte 111 +.byte 114 +.byte 121 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.796: +.byte 78 +.byte 111 +.byte 32 +.byte 102 +.byte 97 +.byte 105 +.byte 108 +.byte 117 +.byte 114 +.byte 101 +.byte 115 +.byte 44 +.byte 32 +.byte 100 +.byte 101 +.byte 102 +.byte 101 +.byte 99 +.byte 116 +.byte 115 +.byte 32 +.byte 110 +.byte 111 +.byte 114 +.byte 32 +.byte 102 +.byte 108 +.byte 97 +.byte 119 +.byte 115 +.byte 32 +.byte 104 +.byte 97 +.byte 118 +.byte 101 +.byte 32 +.byte 98 +.byte 101 +.byte 101 +.byte 110 +.byte 32 +.byte 100 +.byte 105 +.byte 115 +.byte 99 +.byte 111 +.byte 118 +.byte 101 +.byte 114 +.byte 101 +.byte 100 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.795: +.byte 32 +.byte 112 +.byte 114 +.byte 111 +.byte 103 +.byte 114 +.byte 97 +.byte 109 +.byte 39 +.byte 115 +.byte 32 +.byte 115 +.byte 117 +.byte 98 +.byte 115 +.byte 101 +.byte 113 +.byte 117 +.byte 101 +.byte 110 +.byte 116 +.byte 32 +.byte 100 +.byte 105 +.byte 97 +.byte 103 +.byte 110 +.byte 111 +.byte 115 +.byte 101 +.byte 115 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.794: +.byte 80 +.byte 111 +.byte 116 +.byte 101 +.byte 110 +.byte 116 +.byte 105 +.byte 97 +.byte 108 +.byte 108 +.byte 121 +.byte 32 +.byte 102 +.byte 97 +.byte 116 +.byte 97 +.byte 108 +.byte 32 +.byte 70 +.byte 65 +.byte 73 +.byte 76 +.byte 85 +.byte 82 +.byte 69 +.byte 32 +.byte 109 +.byte 97 +.byte 121 +.byte 32 +.byte 104 +.byte 97 +.byte 118 +.byte 101 +.byte 32 +.byte 115 +.byte 112 +.byte 111 +.byte 105 +.byte 108 +.byte 101 +.byte 100 +.byte 32 +.byte 116 +.byte 104 +.byte 105 +.byte 115 +.byte 0 +.align 0 +L.791: +.byte 117 +.byte 110 +.byte 97 +.byte 99 +.byte 99 +.byte 101 +.byte 112 +.byte 116 +.byte 97 +.byte 98 +.byte 108 +.byte 101 +.byte 32 +.byte 83 +.byte 101 +.byte 114 +.byte 105 +.byte 111 +.byte 117 +.byte 115 +.byte 32 +.byte 68 +.byte 101 +.byte 102 +.byte 101 +.byte 99 +.byte 116 +.byte 115 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.790: +.byte 84 +.byte 104 +.byte 101 +.byte 32 +.byte 97 +.byte 114 +.byte 105 +.byte 116 +.byte 104 +.byte 109 +.byte 101 +.byte 116 +.byte 105 +.byte 99 +.byte 32 +.byte 100 +.byte 105 +.byte 97 +.byte 103 +.byte 110 +.byte 111 +.byte 115 +.byte 101 +.byte 100 +.byte 32 +.byte 104 +.byte 97 +.byte 115 +.byte 32 +.byte 0 +.align 0 +L.786: +.byte 100 +.byte 101 +.byte 115 +.byte 112 +.byte 105 +.byte 116 +.byte 101 +.byte 32 +.byte 105 +.byte 110 +.byte 99 +.byte 111 +.byte 110 +.byte 118 +.byte 101 +.byte 110 +.byte 105 +.byte 101 +.byte 110 +.byte 116 +.byte 32 +.byte 68 +.byte 101 +.byte 102 +.byte 101 +.byte 99 +.byte 116 +.byte 115 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.785: +.byte 84 +.byte 104 +.byte 101 +.byte 32 +.byte 97 +.byte 114 +.byte 105 +.byte 116 +.byte 104 +.byte 109 +.byte 101 +.byte 116 +.byte 105 +.byte 99 +.byte 32 +.byte 100 +.byte 105 +.byte 97 +.byte 103 +.byte 110 +.byte 111 +.byte 115 +.byte 101 +.byte 100 +.byte 32 +.byte 109 +.byte 97 +.byte 121 +.byte 32 +.byte 98 +.byte 101 +.byte 32 +.byte 65 +.byte 99 +.byte 99 +.byte 101 +.byte 112 +.byte 116 +.byte 97 +.byte 98 +.byte 108 +.byte 101 +.byte 10 +.byte 0 +.align 0 +L.780: +.byte 83 +.byte 97 +.byte 116 +.byte 105 +.byte 115 +.byte 102 +.byte 97 +.byte 99 +.byte 116 +.byte 111 +.byte 114 +.byte 121 +.byte 32 +.byte 116 +.byte 104 +.byte 111 +.byte 117 +.byte 103 +.byte 104 +.byte 32 +.byte 102 +.byte 108 +.byte 97 +.byte 119 +.byte 101 +.byte 100 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.779: +.byte 84 +.byte 104 +.byte 101 +.byte 32 +.byte 97 +.byte 114 +.byte 105 +.byte 116 +.byte 104 +.byte 109 +.byte 101 +.byte 116 +.byte 105 +.byte 99 +.byte 32 +.byte 100 +.byte 105 +.byte 97 +.byte 103 +.byte 110 +.byte 111 +.byte 115 +.byte 101 +.byte 100 +.byte 32 +.byte 115 +.byte 101 +.byte 101 +.byte 109 +.byte 115 +.byte 32 +.byte 0 +.align 0 +L.768: +.byte 84 +.byte 104 +.byte 101 +.byte 32 +.byte 110 +.byte 117 +.byte 109 +.byte 98 +.byte 101 +.byte 114 +.byte 32 +.byte 111 +.byte 102 +.byte 32 +.byte 32 +.byte 37 +.byte 45 +.byte 50 +.byte 57 +.byte 115 +.byte 32 +.byte 37 +.byte 100 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.761: +.byte 70 +.byte 76 +.byte 65 +.byte 87 +.byte 115 +.byte 32 +.byte 32 +.byte 100 +.byte 105 +.byte 115 +.byte 99 +.byte 111 +.byte 118 +.byte 101 +.byte 114 +.byte 101 +.byte 100 +.byte 32 +.byte 61 +.byte 0 +.align 0 +L.760: +.byte 68 +.byte 69 +.byte 70 +.byte 69 +.byte 67 +.byte 84 +.byte 115 +.byte 32 +.byte 32 +.byte 100 +.byte 105 +.byte 115 +.byte 99 +.byte 111 +.byte 118 +.byte 101 +.byte 114 +.byte 101 +.byte 100 +.byte 32 +.byte 61 +.byte 0 +.align 0 +L.759: +.byte 83 +.byte 69 +.byte 82 +.byte 73 +.byte 79 +.byte 85 +.byte 83 +.byte 32 +.byte 68 +.byte 69 +.byte 70 +.byte 69 +.byte 67 +.byte 84 +.byte 115 +.byte 32 +.byte 32 +.byte 100 +.byte 105 +.byte 115 +.byte 99 +.byte 111 +.byte 118 +.byte 101 +.byte 114 +.byte 101 +.byte 100 +.byte 32 +.byte 61 +.byte 0 +.align 0 +L.758: +.byte 70 +.byte 65 +.byte 73 +.byte 76 +.byte 85 +.byte 82 +.byte 69 +.byte 115 +.byte 32 +.byte 32 +.byte 101 +.byte 110 +.byte 99 +.byte 111 +.byte 117 +.byte 110 +.byte 116 +.byte 101 +.byte 114 +.byte 101 +.byte 100 +.byte 32 +.byte 61 +.byte 0 +.align 0 +L.754: +.byte 10 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 84 +.byte 114 +.byte 121 +.byte 105 +.byte 110 +.byte 103 +.byte 32 +.byte 116 +.byte 111 +.byte 32 +.byte 99 +.byte 111 +.byte 109 +.byte 112 +.byte 117 +.byte 116 +.byte 101 +.byte 32 +.byte 48 +.byte 32 +.byte 47 +.byte 32 +.byte 48 +.byte 32 +.byte 112 +.byte 114 +.byte 111 +.byte 100 +.byte 117 +.byte 99 +.byte 101 +.byte 115 +.byte 32 +.byte 46 +.byte 46 +.byte 46 +.byte 0 +.align 0 +L.753: +.byte 32 +.byte 32 +.byte 37 +.byte 46 +.byte 55 +.byte 101 +.byte 32 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.750: +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 84 +.byte 114 +.byte 121 +.byte 105 +.byte 110 +.byte 103 +.byte 32 +.byte 116 +.byte 111 +.byte 32 +.byte 99 +.byte 111 +.byte 109 +.byte 112 +.byte 117 +.byte 116 +.byte 101 +.byte 32 +.byte 49 +.byte 32 +.byte 47 +.byte 32 +.byte 48 +.byte 32 +.byte 112 +.byte 114 +.byte 111 +.byte 100 +.byte 117 +.byte 99 +.byte 101 +.byte 115 +.byte 32 +.byte 46 +.byte 46 +.byte 46 +.byte 0 +.align 0 +L.749: +.byte 87 +.byte 104 +.byte 97 +.byte 116 +.byte 32 +.byte 109 +.byte 101 +.byte 115 +.byte 115 +.byte 97 +.byte 103 +.byte 101 +.byte 32 +.byte 97 +.byte 110 +.byte 100 +.byte 47 +.byte 111 +.byte 114 +.byte 32 +.byte 118 +.byte 97 +.byte 108 +.byte 117 +.byte 101 +.byte 115 +.byte 32 +.byte 100 +.byte 111 +.byte 101 +.byte 115 +.byte 32 +.byte 68 +.byte 105 +.byte 118 +.byte 105 +.byte 115 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 98 +.byte 121 +.byte 32 +.byte 90 +.byte 101 +.byte 114 +.byte 111 +.byte 32 +.byte 112 +.byte 114 +.byte 111 +.byte 100 +.byte 117 +.byte 99 +.byte 101 +.byte 63 +.byte 10 +.byte 0 +.align 0 +L.748: +.byte 32 +.byte 32 +.byte 105 +.byte 110 +.byte 115 +.byte 116 +.byte 101 +.byte 97 +.byte 100 +.byte 44 +.byte 32 +.byte 88 +.byte 32 +.byte 47 +.byte 32 +.byte 88 +.byte 32 +.byte 45 +.byte 32 +.byte 49 +.byte 47 +.byte 50 +.byte 32 +.byte 45 +.byte 32 +.byte 49 +.byte 47 +.byte 50 +.byte 32 +.byte 61 +.byte 32 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 32 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.747: +.byte 32 +.byte 32 +.byte 88 +.byte 32 +.byte 47 +.byte 32 +.byte 88 +.byte 32 +.byte 100 +.byte 105 +.byte 102 +.byte 102 +.byte 101 +.byte 114 +.byte 115 +.byte 32 +.byte 102 +.byte 114 +.byte 111 +.byte 109 +.byte 32 +.byte 49 +.byte 32 +.byte 119 +.byte 104 +.byte 101 +.byte 110 +.byte 32 +.byte 88 +.byte 32 +.byte 61 +.byte 32 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 10 +.byte 0 +.align 0 +L.742: +.byte 32 +.byte 32 +.byte 88 +.byte 32 +.byte 47 +.byte 32 +.byte 88 +.byte 32 +.byte 32 +.byte 116 +.byte 114 +.byte 97 +.byte 112 +.byte 115 +.byte 32 +.byte 119 +.byte 104 +.byte 101 +.byte 110 +.byte 32 +.byte 88 +.byte 32 +.byte 61 +.byte 32 +.byte 37 +.byte 103 +.byte 10 +.byte 0 +.align 0 +L.727: +.byte 105 +.byte 115 +.byte 32 +.byte 116 +.byte 111 +.byte 111 +.byte 32 +.byte 102 +.byte 97 +.byte 114 +.byte 32 +.byte 102 +.byte 114 +.byte 111 +.byte 109 +.byte 32 +.byte 49 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.726: +.byte 32 +.byte 117 +.byte 110 +.byte 98 +.byte 97 +.byte 108 +.byte 97 +.byte 110 +.byte 99 +.byte 101 +.byte 100 +.byte 32 +.byte 114 +.byte 97 +.byte 110 +.byte 103 +.byte 101 +.byte 59 +.byte 32 +.byte 85 +.byte 102 +.byte 84 +.byte 104 +.byte 111 +.byte 108 +.byte 100 +.byte 32 +.byte 42 +.byte 32 +.byte 86 +.byte 32 +.byte 61 +.byte 32 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 10 +.byte 9 +.byte 37 +.byte 115 +.byte 10 +.byte 0 +.align 0 +L.725: +.byte 66 +.byte 97 +.byte 100 +.byte 108 +.byte 121 +.byte 0 +.align 0 +L.718: +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 116 +.byte 111 +.byte 111 +.byte 32 +.byte 102 +.byte 97 +.byte 114 +.byte 32 +.byte 102 +.byte 114 +.byte 111 +.byte 109 +.byte 32 +.byte 115 +.byte 113 +.byte 114 +.byte 116 +.byte 40 +.byte 90 +.byte 41 +.byte 32 +.byte 94 +.byte 32 +.byte 50 +.byte 32 +.byte 40 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 41 +.byte 32 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.717: +.byte 67 +.byte 111 +.byte 109 +.byte 112 +.byte 97 +.byte 114 +.byte 105 +.byte 115 +.byte 111 +.byte 110 +.byte 32 +.byte 97 +.byte 108 +.byte 108 +.byte 101 +.byte 103 +.byte 101 +.byte 115 +.byte 32 +.byte 116 +.byte 104 +.byte 97 +.byte 116 +.byte 32 +.byte 90 +.byte 32 +.byte 61 +.byte 32 +.byte 37 +.byte 49 +.byte 55 +.byte 101 +.byte 10 +.byte 0 +.align 0 +L.705: +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 116 +.byte 111 +.byte 111 +.byte 32 +.byte 102 +.byte 97 +.byte 114 +.byte 32 +.byte 102 +.byte 114 +.byte 111 +.byte 109 +.byte 32 +.byte 115 +.byte 113 +.byte 114 +.byte 116 +.byte 40 +.byte 90 +.byte 41 +.byte 32 +.byte 94 +.byte 32 +.byte 50 +.byte 32 +.byte 61 +.byte 32 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 32 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.704: +.byte 67 +.byte 111 +.byte 109 +.byte 112 +.byte 97 +.byte 114 +.byte 105 +.byte 115 +.byte 111 +.byte 110 +.byte 32 +.byte 97 +.byte 108 +.byte 108 +.byte 101 +.byte 103 +.byte 101 +.byte 115 +.byte 32 +.byte 116 +.byte 104 +.byte 97 +.byte 116 +.byte 32 +.byte 119 +.byte 104 +.byte 97 +.byte 116 +.byte 32 +.byte 112 +.byte 114 +.byte 105 +.byte 110 +.byte 116 +.byte 115 +.byte 32 +.byte 97 +.byte 115 +.byte 32 +.byte 90 +.byte 32 +.byte 61 +.byte 32 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 10 +.byte 0 +.align 0 +L.687: +.byte 43 +.byte 45 +.byte 37 +.byte 103 +.byte 44 +.byte 32 +.byte 43 +.byte 45 +.byte 37 +.byte 103 +.byte 10 +.byte 97 +.byte 110 +.byte 100 +.byte 32 +.byte 43 +.byte 45 +.byte 37 +.byte 103 +.byte 32 +.byte 97 +.byte 114 +.byte 101 +.byte 32 +.byte 99 +.byte 111 +.byte 110 +.byte 102 +.byte 117 +.byte 115 +.byte 101 +.byte 100 +.byte 32 +.byte 98 +.byte 121 +.byte 32 +.byte 79 +.byte 118 +.byte 101 +.byte 114 +.byte 102 +.byte 108 +.byte 111 +.byte 119 +.byte 46 +.byte 0 +.align 0 +L.686: +.byte 67 +.byte 111 +.byte 109 +.byte 112 +.byte 97 +.byte 114 +.byte 105 +.byte 115 +.byte 111 +.byte 110 +.byte 115 +.byte 32 +.byte 105 +.byte 110 +.byte 118 +.byte 111 +.byte 108 +.byte 118 +.byte 105 +.byte 110 +.byte 103 +.byte 32 +.byte 0 +.align 0 +L.680: +.byte 97 +.byte 98 +.byte 111 +.byte 118 +.byte 101 +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 97 +.byte 32 +.byte 68 +.byte 69 +.byte 70 +.byte 69 +.byte 67 +.byte 84 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.679: +.byte 65 +.byte 110 +.byte 121 +.byte 32 +.byte 111 +.byte 118 +.byte 101 +.byte 114 +.byte 102 +.byte 108 +.byte 111 +.byte 119 +.byte 32 +.byte 115 +.byte 105 +.byte 103 +.byte 110 +.byte 97 +.byte 108 +.byte 32 +.byte 115 +.byte 101 +.byte 112 +.byte 97 +.byte 114 +.byte 97 +.byte 116 +.byte 105 +.byte 110 +.byte 103 +.byte 32 +.byte 116 +.byte 104 +.byte 105 +.byte 115 +.byte 32 +.byte 42 +.byte 32 +.byte 102 +.byte 114 +.byte 111 +.byte 109 +.byte 32 +.byte 116 +.byte 104 +.byte 101 +.byte 32 +.byte 111 +.byte 110 +.byte 101 +.byte 10 +.byte 0 +.align 0 +L.678: +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 110 +.byte 111 +.byte 114 +.byte 32 +.byte 102 +.byte 111 +.byte 114 +.byte 32 +.byte 86 +.byte 32 +.byte 47 +.byte 32 +.byte 49 +.byte 32 +.byte 61 +.byte 32 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 32 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.677: +.byte 78 +.byte 111 +.byte 32 +.byte 79 +.byte 118 +.byte 101 +.byte 114 +.byte 102 +.byte 108 +.byte 111 +.byte 119 +.byte 32 +.byte 115 +.byte 104 +.byte 111 +.byte 117 +.byte 108 +.byte 100 +.byte 32 +.byte 98 +.byte 101 +.byte 32 +.byte 115 +.byte 105 +.byte 103 +.byte 110 +.byte 97 +.byte 108 +.byte 101 +.byte 100 +.byte 32 +.byte 102 +.byte 111 +.byte 114 +.byte 32 +.byte 86 +.byte 32 +.byte 42 +.byte 32 +.byte 49 +.byte 32 +.byte 61 +.byte 32 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 10 +.byte 0 +.align 0 +L.676: +.byte 84 +.byte 104 +.byte 101 +.byte 114 +.byte 101 +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 110 +.byte 111 +.byte 32 +.byte 115 +.byte 97 +.byte 116 +.byte 117 +.byte 114 +.byte 97 +.byte 116 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 118 +.byte 97 +.byte 108 +.byte 117 +.byte 101 +.byte 32 +.byte 98 +.byte 101 +.byte 99 +.byte 97 +.byte 117 +.byte 115 +.byte 101 +.byte 32 +.byte 116 +.byte 104 +.byte 101 +.byte 32 +.byte 115 +.byte 121 +.byte 115 +.byte 116 +.byte 101 +.byte 109 +.byte 32 +.byte 116 +.byte 114 +.byte 97 +.byte 112 +.byte 115 +.byte 32 +.byte 111 +.byte 110 +.byte 32 +.byte 111 +.byte 118 +.byte 101 +.byte 114 +.byte 102 +.byte 108 +.byte 111 +.byte 119 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.675: +.byte 79 +.byte 118 +.byte 101 +.byte 114 +.byte 102 +.byte 108 +.byte 111 +.byte 119 +.byte 32 +.byte 115 +.byte 97 +.byte 116 +.byte 117 +.byte 114 +.byte 97 +.byte 116 +.byte 101 +.byte 115 +.byte 32 +.byte 97 +.byte 116 +.byte 32 +.byte 86 +.byte 48 +.byte 32 +.byte 61 +.byte 32 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 32 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.672: +.byte 79 +.byte 118 +.byte 101 +.byte 114 +.byte 102 +.byte 108 +.byte 111 +.byte 119 +.byte 32 +.byte 116 +.byte 104 +.byte 114 +.byte 101 +.byte 115 +.byte 104 +.byte 111 +.byte 108 +.byte 100 +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 86 +.byte 32 +.byte 32 +.byte 61 +.byte 32 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 32 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.663: +.byte 111 +.byte 118 +.byte 101 +.byte 114 +.byte 102 +.byte 108 +.byte 111 +.byte 119 +.byte 32 +.byte 112 +.byte 97 +.byte 115 +.byte 116 +.byte 32 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 10 +.byte 9 +.byte 115 +.byte 104 +.byte 114 +.byte 105 +.byte 110 +.byte 107 +.byte 115 +.byte 32 +.byte 116 +.byte 111 +.byte 32 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 32 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.660: +.byte 45 +.byte 40 +.byte 45 +.byte 89 +.byte 41 +.byte 32 +.byte 100 +.byte 105 +.byte 102 +.byte 102 +.byte 101 +.byte 114 +.byte 115 +.byte 32 +.byte 102 +.byte 114 +.byte 111 +.byte 109 +.byte 32 +.byte 89 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.659: +.byte 102 +.byte 105 +.byte 110 +.byte 100 +.byte 115 +.byte 32 +.byte 97 +.byte 32 +.byte 0 +.align 0 +L.658: +.byte 83 +.byte 101 +.byte 101 +.byte 109 +.byte 115 +.byte 32 +.byte 79 +.byte 46 +.byte 75 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.655: +.byte 84 +.byte 114 +.byte 121 +.byte 105 +.byte 110 +.byte 103 +.byte 32 +.byte 105 +.byte 116 +.byte 32 +.byte 111 +.byte 110 +.byte 32 +.byte 89 +.byte 32 +.byte 61 +.byte 32 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 32 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.654: +.byte 67 +.byte 97 +.byte 110 +.byte 32 +.byte 96 +.byte 90 +.byte 32 +.byte 61 +.byte 32 +.byte 45 +.byte 89 +.byte 39 +.byte 32 +.byte 111 +.byte 118 +.byte 101 +.byte 114 +.byte 102 +.byte 108 +.byte 111 +.byte 119 +.byte 63 +.byte 10 +.byte 0 +.align 0 +L.647: +.byte 84 +.byte 104 +.byte 105 +.byte 115 +.byte 32 +.byte 109 +.byte 97 +.byte 121 +.byte 32 +.byte 103 +.byte 101 +.byte 110 +.byte 101 +.byte 114 +.byte 97 +.byte 116 +.byte 101 +.byte 32 +.byte 97 +.byte 110 +.byte 32 +.byte 101 +.byte 114 +.byte 114 +.byte 111 +.byte 114 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.646: +.byte 83 +.byte 101 +.byte 97 +.byte 114 +.byte 99 +.byte 104 +.byte 105 +.byte 110 +.byte 103 +.byte 32 +.byte 102 +.byte 111 +.byte 114 +.byte 32 +.byte 79 +.byte 118 +.byte 101 +.byte 114 +.byte 102 +.byte 108 +.byte 111 +.byte 119 +.byte 32 +.byte 116 +.byte 104 +.byte 114 +.byte 101 +.byte 115 +.byte 104 +.byte 111 +.byte 108 +.byte 100 +.byte 58 +.byte 10 +.byte 0 +.align 0 +L.645: +.byte 32 +.byte 46 +.byte 46 +.byte 46 +.byte 32 +.byte 110 +.byte 111 +.byte 32 +.byte 100 +.byte 105 +.byte 115 +.byte 99 +.byte 114 +.byte 101 +.byte 112 +.byte 97 +.byte 110 +.byte 99 +.byte 105 +.byte 101 +.byte 115 +.byte 32 +.byte 102 +.byte 111 +.byte 117 +.byte 110 +.byte 100 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.637: +.byte 84 +.byte 101 +.byte 115 +.byte 116 +.byte 105 +.byte 110 +.byte 103 +.byte 32 +.byte 112 +.byte 111 +.byte 119 +.byte 101 +.byte 114 +.byte 115 +.byte 32 +.byte 90 +.byte 94 +.byte 81 +.byte 32 +.byte 97 +.byte 116 +.byte 32 +.byte 102 +.byte 111 +.byte 117 +.byte 114 +.byte 32 +.byte 110 +.byte 101 +.byte 97 +.byte 114 +.byte 108 +.byte 121 +.byte 32 +.byte 101 +.byte 120 +.byte 116 +.byte 114 +.byte 101 +.byte 109 +.byte 101 +.byte 32 +.byte 118 +.byte 97 +.byte 108 +.byte 117 +.byte 101 +.byte 115 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.636: +.byte 65 +.byte 99 +.byte 99 +.byte 117 +.byte 114 +.byte 97 +.byte 99 +.byte 121 +.byte 32 +.byte 115 +.byte 101 +.byte 101 +.byte 109 +.byte 115 +.byte 32 +.byte 97 +.byte 100 +.byte 101 +.byte 113 +.byte 117 +.byte 97 +.byte 116 +.byte 101 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.629: +.byte 9 +.byte 99 +.byte 97 +.byte 108 +.byte 99 +.byte 117 +.byte 108 +.byte 97 +.byte 116 +.byte 105 +.byte 111 +.byte 110 +.byte 115 +.byte 32 +.byte 105 +.byte 110 +.byte 118 +.byte 111 +.byte 108 +.byte 118 +.byte 105 +.byte 110 +.byte 103 +.byte 32 +.byte 116 +.byte 105 +.byte 110 +.byte 121 +.byte 32 +.byte 105 +.byte 110 +.byte 116 +.byte 101 +.byte 114 +.byte 101 +.byte 115 +.byte 116 +.byte 32 +.byte 114 +.byte 97 +.byte 116 +.byte 101 +.byte 115 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.628: +.byte 9 +.byte 84 +.byte 104 +.byte 105 +.byte 115 +.byte 32 +.byte 109 +.byte 117 +.byte 99 +.byte 104 +.byte 32 +.byte 101 +.byte 114 +.byte 114 +.byte 111 +.byte 114 +.byte 32 +.byte 109 +.byte 97 +.byte 121 +.byte 32 +.byte 115 +.byte 112 +.byte 111 +.byte 105 +.byte 108 +.byte 32 +.byte 102 +.byte 105 +.byte 110 +.byte 97 +.byte 110 +.byte 99 +.byte 105 +.byte 97 +.byte 108 +.byte 10 +.byte 0 +.align 0 +L.627: +.byte 9 +.byte 100 +.byte 105 +.byte 102 +.byte 102 +.byte 101 +.byte 114 +.byte 115 +.byte 32 +.byte 102 +.byte 114 +.byte 111 +.byte 109 +.byte 32 +.byte 99 +.byte 111 +.byte 114 +.byte 114 +.byte 101 +.byte 99 +.byte 116 +.byte 32 +.byte 118 +.byte 97 +.byte 108 +.byte 117 +.byte 101 +.byte 32 +.byte 98 +.byte 121 +.byte 32 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 32 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.626: +.byte 9 +.byte 40 +.byte 49 +.byte 32 +.byte 43 +.byte 32 +.byte 40 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 41 +.byte 32 +.byte 94 +.byte 32 +.byte 40 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 41 +.byte 59 +.byte 10 +.byte 0 +.align 0 +L.625: +.byte 32 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 32 +.byte 102 +.byte 111 +.byte 114 +.byte 10 +.byte 0 +.align 0 +L.624: +.byte 67 +.byte 97 +.byte 108 +.byte 99 +.byte 117 +.byte 108 +.byte 97 +.byte 116 +.byte 101 +.byte 100 +.byte 0 +.align 0 +L.617: +.byte 84 +.byte 101 +.byte 115 +.byte 116 +.byte 105 +.byte 110 +.byte 103 +.byte 32 +.byte 88 +.byte 94 +.byte 40 +.byte 40 +.byte 88 +.byte 32 +.byte 43 +.byte 32 +.byte 49 +.byte 41 +.byte 32 +.byte 47 +.byte 32 +.byte 40 +.byte 88 +.byte 32 +.byte 45 +.byte 32 +.byte 49 +.byte 41 +.byte 41 +.byte 32 +.byte 118 +.byte 115 +.byte 46 +.byte 32 +.byte 101 +.byte 120 +.byte 112 +.byte 40 +.byte 50 +.byte 41 +.byte 32 +.byte 61 +.byte 32 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 32 +.byte 97 +.byte 115 +.byte 32 +.byte 88 +.byte 32 +.byte 45 +.byte 62 +.byte 32 +.byte 49 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.613: +.byte 84 +.byte 104 +.byte 105 +.byte 115 +.byte 32 +.byte 99 +.byte 111 +.byte 109 +.byte 112 +.byte 117 +.byte 116 +.byte 101 +.byte 100 +.byte 32 +.byte 118 +.byte 97 +.byte 108 +.byte 117 +.byte 101 +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 79 +.byte 46 +.byte 75 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.610: +.byte 32 +.byte 32 +.byte 32 +.byte 116 +.byte 104 +.byte 114 +.byte 101 +.byte 115 +.byte 104 +.byte 111 +.byte 108 +.byte 100 +.byte 32 +.byte 61 +.byte 32 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 32 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.609: +.byte 116 +.byte 104 +.byte 105 +.byte 115 +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 110 +.byte 111 +.byte 116 +.byte 32 +.byte 98 +.byte 101 +.byte 116 +.byte 119 +.byte 101 +.byte 101 +.byte 110 +.byte 32 +.byte 48 +.byte 32 +.byte 97 +.byte 110 +.byte 100 +.byte 32 +.byte 117 +.byte 110 +.byte 100 +.byte 101 +.byte 114 +.byte 102 +.byte 108 +.byte 111 +.byte 119 +.byte 10 +.byte 0 +.align 0 +L.605: +.byte 97 +.byte 99 +.byte 116 +.byte 117 +.byte 97 +.byte 108 +.byte 108 +.byte 121 +.byte 32 +.byte 99 +.byte 97 +.byte 108 +.byte 99 +.byte 117 +.byte 108 +.byte 97 +.byte 116 +.byte 105 +.byte 110 +.byte 103 +.byte 32 +.byte 121 +.byte 105 +.byte 101 +.byte 108 +.byte 100 +.byte 115 +.byte 58 +.byte 32 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 32 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.604: +.byte 115 +.byte 104 +.byte 111 +.byte 117 +.byte 108 +.byte 100 +.byte 32 +.byte 97 +.byte 102 +.byte 102 +.byte 108 +.byte 105 +.byte 99 +.byte 116 +.byte 32 +.byte 116 +.byte 104 +.byte 101 +.byte 32 +.byte 101 +.byte 120 +.byte 112 +.byte 114 +.byte 101 +.byte 115 +.byte 115 +.byte 105 +.byte 111 +.byte 110 +.byte 10 +.byte 9 +.byte 40 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 41 +.byte 32 +.byte 94 +.byte 32 +.byte 40 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 41 +.byte 59 +.byte 10 +.byte 0 +.align 0 +L.603: +.byte 85 +.byte 102 +.byte 84 +.byte 104 +.byte 111 +.byte 108 +.byte 100 +.byte 32 +.byte 61 +.byte 32 +.byte 40 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 41 +.byte 32 +.byte 94 +.byte 32 +.byte 40 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 41 +.byte 10 +.byte 111 +.byte 110 +.byte 108 +.byte 121 +.byte 32 +.byte 117 +.byte 110 +.byte 100 +.byte 101 +.byte 114 +.byte 102 +.byte 108 +.byte 111 +.byte 119 +.byte 32 +.byte 0 +.align 0 +L.602: +.byte 83 +.byte 105 +.byte 110 +.byte 99 +.byte 101 +.byte 32 +.byte 117 +.byte 110 +.byte 100 +.byte 101 +.byte 114 +.byte 102 +.byte 108 +.byte 111 +.byte 119 +.byte 32 +.byte 111 +.byte 99 +.byte 99 +.byte 117 +.byte 114 +.byte 115 +.byte 32 +.byte 98 +.byte 101 +.byte 108 +.byte 111 +.byte 119 +.byte 32 +.byte 116 +.byte 104 +.byte 101 +.byte 32 +.byte 116 +.byte 104 +.byte 114 +.byte 101 +.byte 115 +.byte 104 +.byte 111 +.byte 108 +.byte 100 +.byte 10 +.byte 0 +.align 0 +L.601: +.byte 82 +.byte 97 +.byte 110 +.byte 103 +.byte 101 +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 116 +.byte 111 +.byte 111 +.byte 32 +.byte 110 +.byte 97 +.byte 114 +.byte 114 +.byte 111 +.byte 119 +.byte 59 +.byte 32 +.byte 85 +.byte 49 +.byte 94 +.byte 37 +.byte 100 +.byte 32 +.byte 85 +.byte 110 +.byte 100 +.byte 101 +.byte 114 +.byte 102 +.byte 108 +.byte 111 +.byte 119 +.byte 115 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.596: +.byte 109 +.byte 101 +.byte 114 +.byte 101 +.byte 108 +.byte 121 +.byte 32 +.byte 114 +.byte 111 +.byte 117 +.byte 110 +.byte 100 +.byte 111 +.byte 102 +.byte 102 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.595: +.byte 99 +.byte 97 +.byte 108 +.byte 99 +.byte 117 +.byte 108 +.byte 97 +.byte 116 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 109 +.byte 97 +.byte 121 +.byte 32 +.byte 115 +.byte 117 +.byte 102 +.byte 102 +.byte 101 +.byte 114 +.byte 32 +.byte 108 +.byte 97 +.byte 114 +.byte 103 +.byte 101 +.byte 114 +.byte 32 +.byte 82 +.byte 101 +.byte 108 +.byte 97 +.byte 116 +.byte 105 +.byte 118 +.byte 101 +.byte 32 +.byte 101 +.byte 114 +.byte 114 +.byte 111 +.byte 114 +.byte 32 +.byte 116 +.byte 104 +.byte 97 +.byte 110 +.byte 32 +.byte 0 +.align 0 +L.594: +.byte 32 +.byte 98 +.byte 101 +.byte 108 +.byte 111 +.byte 119 +.byte 32 +.byte 119 +.byte 104 +.byte 105 +.byte 99 +.byte 104 +.byte 0 +.align 0 +L.593: +.byte 84 +.byte 104 +.byte 101 +.byte 32 +.byte 85 +.byte 110 +.byte 100 +.byte 101 +.byte 114 +.byte 102 +.byte 108 +.byte 111 +.byte 119 +.byte 32 +.byte 116 +.byte 104 +.byte 114 +.byte 101 +.byte 115 +.byte 104 +.byte 111 +.byte 108 +.byte 100 +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 44 +.byte 32 +.byte 37 +.byte 115 +.byte 10 +.byte 0 +.align 0 +L.592: +.byte 88 +.byte 32 +.byte 47 +.byte 32 +.byte 90 +.byte 32 +.byte 61 +.byte 32 +.byte 49 +.byte 32 +.byte 43 +.byte 32 +.byte 37 +.byte 103 +.byte 32 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.591: +.byte 88 +.byte 32 +.byte 47 +.byte 32 +.byte 90 +.byte 32 +.byte 102 +.byte 97 +.byte 105 +.byte 108 +.byte 115 +.byte 33 +.byte 10 +.byte 0 +.align 0 +L.588: +.byte 101 +.byte 110 +.byte 99 +.byte 111 +.byte 117 +.byte 110 +.byte 116 +.byte 101 +.byte 114 +.byte 32 +.byte 68 +.byte 105 +.byte 118 +.byte 105 +.byte 115 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 98 +.byte 121 +.byte 32 +.byte 90 +.byte 101 +.byte 114 +.byte 111 +.byte 32 +.byte 97 +.byte 108 +.byte 116 +.byte 104 +.byte 111 +.byte 117 +.byte 103 +.byte 104 +.byte 32 +.byte 97 +.byte 99 +.byte 116 +.byte 117 +.byte 97 +.byte 108 +.byte 108 +.byte 121 +.byte 10 +.byte 0 +.align 0 +L.587: +.byte 32 +.byte 32 +.byte 46 +.byte 46 +.byte 46 +.byte 32 +.byte 40 +.byte 102 +.byte 40 +.byte 88 +.byte 41 +.byte 32 +.byte 45 +.byte 32 +.byte 102 +.byte 40 +.byte 90 +.byte 41 +.byte 41 +.byte 32 +.byte 47 +.byte 32 +.byte 40 +.byte 88 +.byte 32 +.byte 45 +.byte 32 +.byte 90 +.byte 41 +.byte 32 +.byte 46 +.byte 46 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.586: +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 105 +.byte 102 +.byte 32 +.byte 40 +.byte 88 +.byte 32 +.byte 61 +.byte 61 +.byte 32 +.byte 90 +.byte 41 +.byte 32 +.byte 32 +.byte 46 +.byte 46 +.byte 46 +.byte 32 +.byte 32 +.byte 101 +.byte 108 +.byte 115 +.byte 101 +.byte 0 +.align 0 +L.585: +.byte 99 +.byte 111 +.byte 110 +.byte 102 +.byte 117 +.byte 115 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 119 +.byte 104 +.byte 101 +.byte 110 +.byte 32 +.byte 105 +.byte 110 +.byte 110 +.byte 111 +.byte 99 +.byte 101 +.byte 110 +.byte 116 +.byte 32 +.byte 115 +.byte 116 +.byte 97 +.byte 116 +.byte 101 +.byte 109 +.byte 101 +.byte 110 +.byte 116 +.byte 115 +.byte 32 +.byte 108 +.byte 105 +.byte 107 +.byte 101 +.byte 10 +.byte 0 +.align 0 +L.584: +.byte 116 +.byte 104 +.byte 105 +.byte 115 +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 97 +.byte 32 +.byte 83 +.byte 69 +.byte 82 +.byte 73 +.byte 79 +.byte 85 +.byte 83 +.byte 32 +.byte 68 +.byte 69 +.byte 70 +.byte 69 +.byte 67 +.byte 84 +.byte 10 +.byte 116 +.byte 104 +.byte 97 +.byte 116 +.byte 32 +.byte 99 +.byte 97 +.byte 117 +.byte 115 +.byte 101 +.byte 115 +.byte 32 +.byte 0 +.align 0 +L.583: +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 83 +.byte 104 +.byte 111 +.byte 117 +.byte 108 +.byte 100 +.byte 32 +.byte 116 +.byte 104 +.byte 105 +.byte 115 +.byte 32 +.byte 78 +.byte 79 +.byte 84 +.byte 32 +.byte 115 +.byte 105 +.byte 103 +.byte 110 +.byte 97 +.byte 108 +.byte 32 +.byte 85 +.byte 110 +.byte 100 +.byte 101 +.byte 114 +.byte 102 +.byte 108 +.byte 111 +.byte 119 +.byte 44 +.byte 32 +.byte 0 +.align 0 +L.582: +.byte 121 +.byte 101 +.byte 116 +.byte 32 +.byte 88 +.byte 32 +.byte 45 +.byte 32 +.byte 90 +.byte 32 +.byte 121 +.byte 105 +.byte 101 +.byte 108 +.byte 100 +.byte 115 +.byte 32 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 32 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.581: +.byte 88 +.byte 32 +.byte 61 +.byte 32 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 10 +.byte 9 +.byte 105 +.byte 115 +.byte 32 +.byte 110 +.byte 111 +.byte 116 +.byte 32 +.byte 101 +.byte 113 +.byte 117 +.byte 97 +.byte 108 +.byte 32 +.byte 116 +.byte 111 +.byte 32 +.byte 90 +.byte 32 +.byte 61 +.byte 32 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 32 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.576: +.byte 85 +.byte 110 +.byte 100 +.byte 101 +.byte 114 +.byte 102 +.byte 108 +.byte 111 +.byte 119 +.byte 32 +.byte 47 +.byte 32 +.byte 85 +.byte 102 +.byte 84 +.byte 104 +.byte 111 +.byte 108 +.byte 100 +.byte 32 +.byte 102 +.byte 97 +.byte 105 +.byte 108 +.byte 101 +.byte 100 +.byte 33 +.byte 10 +.byte 0 +.align 0 +L.566: +.byte 40 +.byte 114 +.byte 111 +.byte 117 +.byte 110 +.byte 100 +.byte 111 +.byte 102 +.byte 102 +.byte 32 +.byte 105 +.byte 110 +.byte 32 +.byte 85 +.byte 102 +.byte 84 +.byte 104 +.byte 111 +.byte 108 +.byte 100 +.byte 41 +.byte 32 +.byte 60 +.byte 32 +.byte 69 +.byte 48 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.565: +.byte 85 +.byte 110 +.byte 100 +.byte 101 +.byte 114 +.byte 102 +.byte 108 +.byte 111 +.byte 119 +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 103 +.byte 114 +.byte 97 +.byte 100 +.byte 117 +.byte 97 +.byte 108 +.byte 59 +.byte 32 +.byte 105 +.byte 116 +.byte 32 +.byte 105 +.byte 110 +.byte 99 +.byte 117 +.byte 114 +.byte 115 +.byte 32 +.byte 65 +.byte 98 +.byte 115 +.byte 111 +.byte 108 +.byte 117 +.byte 116 +.byte 101 +.byte 32 +.byte 69 +.byte 114 +.byte 114 +.byte 111 +.byte 114 +.byte 32 +.byte 61 +.byte 10 +.byte 0 +.align 0 +L.560: +.byte 124 +.byte 81 +.byte 32 +.byte 45 +.byte 32 +.byte 89 +.byte 124 +.byte 32 +.byte 61 +.byte 32 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 32 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.559: +.byte 112 +.byte 114 +.byte 105 +.byte 110 +.byte 116 +.byte 32 +.byte 111 +.byte 117 +.byte 116 +.byte 32 +.byte 97 +.byte 115 +.byte 32 +.byte 81 +.byte 32 +.byte 61 +.byte 32 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 44 +.byte 32 +.byte 89 +.byte 32 +.byte 61 +.byte 32 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 32 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.558: +.byte 81 +.byte 32 +.byte 61 +.byte 61 +.byte 32 +.byte 89 +.byte 32 +.byte 119 +.byte 104 +.byte 105 +.byte 108 +.byte 101 +.byte 32 +.byte 100 +.byte 101 +.byte 110 +.byte 121 +.byte 105 +.byte 110 +.byte 103 +.byte 32 +.byte 116 +.byte 104 +.byte 97 +.byte 116 +.byte 32 +.byte 124 +.byte 81 +.byte 32 +.byte 45 +.byte 32 +.byte 89 +.byte 124 +.byte 32 +.byte 61 +.byte 61 +.byte 32 +.byte 48 +.byte 59 +.byte 32 +.byte 116 +.byte 104 +.byte 101 +.byte 115 +.byte 101 +.byte 32 +.byte 118 +.byte 97 +.byte 108 +.byte 117 +.byte 101 +.byte 115 +.byte 10 +.byte 0 +.align 0 +L.557: +.byte 85 +.byte 110 +.byte 100 +.byte 101 +.byte 114 +.byte 102 +.byte 108 +.byte 111 +.byte 119 +.byte 32 +.byte 99 +.byte 111 +.byte 110 +.byte 102 +.byte 117 +.byte 115 +.byte 101 +.byte 115 +.byte 32 +.byte 67 +.byte 111 +.byte 109 +.byte 112 +.byte 97 +.byte 114 +.byte 105 +.byte 115 +.byte 111 +.byte 110 +.byte 44 +.byte 32 +.byte 119 +.byte 104 +.byte 105 +.byte 99 +.byte 104 +.byte 32 +.byte 97 +.byte 108 +.byte 108 +.byte 101 +.byte 103 +.byte 101 +.byte 115 +.byte 32 +.byte 116 +.byte 104 +.byte 97 +.byte 116 +.byte 10 +.byte 0 +.align 0 +L.555: +.byte 32 +.byte 111 +.byte 114 +.byte 32 +.byte 101 +.byte 108 +.byte 115 +.byte 101 +.byte 32 +.byte 109 +.byte 117 +.byte 108 +.byte 116 +.byte 105 +.byte 112 +.byte 108 +.byte 105 +.byte 99 +.byte 97 +.byte 116 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 103 +.byte 101 +.byte 116 +.byte 115 +.byte 32 +.byte 116 +.byte 111 +.byte 111 +.byte 32 +.byte 109 +.byte 97 +.byte 110 +.byte 121 +.byte 32 +.byte 108 +.byte 97 +.byte 115 +.byte 116 +.byte 32 +.byte 100 +.byte 105 +.byte 103 +.byte 105 +.byte 116 +.byte 115 +.byte 32 +.byte 119 +.byte 114 +.byte 111 +.byte 110 +.byte 103 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.554: +.byte 32 +.byte 99 +.byte 111 +.byte 109 +.byte 105 +.byte 110 +.byte 103 +.byte 32 +.byte 100 +.byte 111 +.byte 119 +.byte 110 +.byte 32 +.byte 102 +.byte 114 +.byte 111 +.byte 109 +.byte 32 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 10 +.byte 0 +.align 0 +L.553: +.byte 97 +.byte 112 +.byte 112 +.byte 114 +.byte 111 +.byte 97 +.byte 99 +.byte 104 +.byte 32 +.byte 97 +.byte 32 +.byte 116 +.byte 104 +.byte 114 +.byte 101 +.byte 115 +.byte 104 +.byte 111 +.byte 108 +.byte 100 +.byte 32 +.byte 61 +.byte 32 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 10 +.byte 0 +.align 0 +L.552: +.byte 69 +.byte 105 +.byte 116 +.byte 104 +.byte 101 +.byte 114 +.byte 32 +.byte 97 +.byte 99 +.byte 99 +.byte 117 +.byte 114 +.byte 97 +.byte 99 +.byte 121 +.byte 32 +.byte 100 +.byte 101 +.byte 116 +.byte 101 +.byte 114 +.byte 105 +.byte 111 +.byte 114 +.byte 97 +.byte 116 +.byte 101 +.byte 115 +.byte 32 +.byte 97 +.byte 115 +.byte 32 +.byte 110 +.byte 117 +.byte 109 +.byte 98 +.byte 101 +.byte 114 +.byte 115 +.byte 10 +.byte 0 +.align 0 +L.540: +.byte 83 +.byte 109 +.byte 97 +.byte 108 +.byte 108 +.byte 101 +.byte 115 +.byte 116 +.byte 32 +.byte 115 +.byte 116 +.byte 114 +.byte 105 +.byte 99 +.byte 116 +.byte 108 +.byte 121 +.byte 32 +.byte 112 +.byte 111 +.byte 115 +.byte 105 +.byte 116 +.byte 105 +.byte 118 +.byte 101 +.byte 32 +.byte 110 +.byte 117 +.byte 109 +.byte 98 +.byte 101 +.byte 114 +.byte 32 +.byte 102 +.byte 111 +.byte 117 +.byte 110 +.byte 100 +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 69 +.byte 48 +.byte 32 +.byte 61 +.byte 32 +.byte 37 +.byte 103 +.byte 32 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.539: +.byte 32 +.byte 116 +.byte 104 +.byte 114 +.byte 101 +.byte 115 +.byte 104 +.byte 111 +.byte 108 +.byte 100 +.byte 32 +.byte 116 +.byte 104 +.byte 97 +.byte 110 +.byte 32 +.byte 112 +.byte 114 +.byte 111 +.byte 100 +.byte 117 +.byte 99 +.byte 116 +.byte 115 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.538: +.byte 68 +.byte 105 +.byte 102 +.byte 102 +.byte 101 +.byte 114 +.byte 101 +.byte 110 +.byte 99 +.byte 101 +.byte 32 +.byte 117 +.byte 110 +.byte 100 +.byte 101 +.byte 114 +.byte 102 +.byte 108 +.byte 111 +.byte 119 +.byte 115 +.byte 32 +.byte 97 +.byte 116 +.byte 32 +.byte 97 +.byte 32 +.byte 104 +.byte 105 +.byte 103 +.byte 104 +.byte 101 +.byte 114 +.byte 0 +.align 0 +L.535: +.byte 32 +.byte 116 +.byte 104 +.byte 114 +.byte 101 +.byte 115 +.byte 104 +.byte 111 +.byte 108 +.byte 100 +.byte 32 +.byte 116 +.byte 104 +.byte 97 +.byte 110 +.byte 32 +.byte 100 +.byte 105 +.byte 102 +.byte 102 +.byte 101 +.byte 114 +.byte 101 +.byte 110 +.byte 99 +.byte 101 +.byte 115 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.534: +.byte 80 +.byte 114 +.byte 111 +.byte 100 +.byte 117 +.byte 99 +.byte 116 +.byte 115 +.byte 32 +.byte 117 +.byte 110 +.byte 100 +.byte 101 +.byte 114 +.byte 102 +.byte 108 +.byte 111 +.byte 119 +.byte 32 +.byte 97 +.byte 116 +.byte 32 +.byte 97 +.byte 32 +.byte 104 +.byte 105 +.byte 103 +.byte 104 +.byte 101 +.byte 114 +.byte 0 +.align 0 +L.527: +.byte 118 +.byte 97 +.byte 108 +.byte 117 +.byte 101 +.byte 32 +.byte 80 +.byte 115 +.byte 101 +.byte 117 +.byte 100 +.byte 111 +.byte 90 +.byte 101 +.byte 114 +.byte 111 +.byte 32 +.byte 116 +.byte 104 +.byte 97 +.byte 116 +.byte 32 +.byte 112 +.byte 114 +.byte 105 +.byte 110 +.byte 116 +.byte 115 +.byte 32 +.byte 111 +.byte 117 +.byte 116 +.byte 32 +.byte 97 +.byte 115 +.byte 32 +.byte 37 +.byte 103 +.byte 32 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.526: +.byte 85 +.byte 110 +.byte 100 +.byte 101 +.byte 114 +.byte 102 +.byte 108 +.byte 111 +.byte 119 +.byte 32 +.byte 99 +.byte 97 +.byte 110 +.byte 32 +.byte 115 +.byte 116 +.byte 105 +.byte 99 +.byte 107 +.byte 32 +.byte 97 +.byte 116 +.byte 32 +.byte 97 +.byte 110 +.byte 32 +.byte 97 +.byte 108 +.byte 108 +.byte 101 +.byte 103 +.byte 101 +.byte 100 +.byte 108 +.byte 121 +.byte 32 +.byte 112 +.byte 111 +.byte 115 +.byte 105 +.byte 116 +.byte 105 +.byte 118 +.byte 101 +.byte 10 +.byte 0 +.align 0 +L.525: +.byte 112 +.byte 111 +.byte 115 +.byte 105 +.byte 116 +.byte 105 +.byte 118 +.byte 101 +.byte 44 +.byte 32 +.byte 105 +.byte 115 +.byte 110 +.byte 39 +.byte 116 +.byte 59 +.byte 32 +.byte 105 +.byte 116 +.byte 32 +.byte 112 +.byte 114 +.byte 105 +.byte 110 +.byte 116 +.byte 115 +.byte 32 +.byte 111 +.byte 117 +.byte 116 +.byte 32 +.byte 97 +.byte 115 +.byte 32 +.byte 32 +.byte 37 +.byte 103 +.byte 32 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.524: +.byte 66 +.byte 117 +.byte 116 +.byte 32 +.byte 45 +.byte 80 +.byte 115 +.byte 101 +.byte 117 +.byte 100 +.byte 111 +.byte 90 +.byte 101 +.byte 114 +.byte 111 +.byte 44 +.byte 32 +.byte 119 +.byte 104 +.byte 105 +.byte 99 +.byte 104 +.byte 32 +.byte 115 +.byte 104 +.byte 111 +.byte 117 +.byte 108 +.byte 100 +.byte 32 +.byte 98 +.byte 101 +.byte 10 +.byte 0 +.align 0 +L.521: +.byte 80 +.byte 115 +.byte 101 +.byte 117 +.byte 100 +.byte 111 +.byte 90 +.byte 101 +.byte 114 +.byte 111 +.byte 32 +.byte 116 +.byte 104 +.byte 97 +.byte 116 +.byte 32 +.byte 112 +.byte 114 +.byte 105 +.byte 110 +.byte 116 +.byte 115 +.byte 32 +.byte 111 +.byte 117 +.byte 116 +.byte 32 +.byte 97 +.byte 115 +.byte 58 +.byte 32 +.byte 37 +.byte 103 +.byte 32 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.520: +.byte 97 +.byte 108 +.byte 108 +.byte 101 +.byte 103 +.byte 101 +.byte 100 +.byte 108 +.byte 121 +.byte 32 +.byte 110 +.byte 101 +.byte 103 +.byte 97 +.byte 116 +.byte 105 +.byte 118 +.byte 101 +.byte 32 +.byte 118 +.byte 97 +.byte 108 +.byte 117 +.byte 101 +.byte 10 +.byte 0 +.align 0 +L.519: +.byte 80 +.byte 111 +.byte 115 +.byte 105 +.byte 116 +.byte 105 +.byte 118 +.byte 101 +.byte 32 +.byte 101 +.byte 120 +.byte 112 +.byte 114 +.byte 101 +.byte 115 +.byte 115 +.byte 105 +.byte 111 +.byte 110 +.byte 115 +.byte 32 +.byte 99 +.byte 97 +.byte 110 +.byte 32 +.byte 117 +.byte 110 +.byte 100 +.byte 101 +.byte 114 +.byte 102 +.byte 108 +.byte 111 +.byte 119 +.byte 32 +.byte 116 +.byte 111 +.byte 32 +.byte 97 +.byte 110 +.byte 10 +.byte 0 +.align 0 +L.506: +.byte 109 +.byte 117 +.byte 108 +.byte 116 +.byte 105 +.byte 112 +.byte 108 +.byte 105 +.byte 99 +.byte 97 +.byte 116 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 103 +.byte 101 +.byte 116 +.byte 115 +.byte 32 +.byte 116 +.byte 111 +.byte 111 +.byte 32 +.byte 109 +.byte 97 +.byte 110 +.byte 121 +.byte 32 +.byte 108 +.byte 97 +.byte 115 +.byte 116 +.byte 32 +.byte 100 +.byte 105 +.byte 103 +.byte 105 +.byte 116 +.byte 115 +.byte 32 +.byte 119 +.byte 114 +.byte 111 +.byte 110 +.byte 103 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.482: +.byte 83 +.byte 101 +.byte 101 +.byte 107 +.byte 105 +.byte 110 +.byte 103 +.byte 32 +.byte 85 +.byte 110 +.byte 100 +.byte 101 +.byte 114 +.byte 102 +.byte 108 +.byte 111 +.byte 119 +.byte 32 +.byte 116 +.byte 104 +.byte 114 +.byte 101 +.byte 115 +.byte 104 +.byte 111 +.byte 108 +.byte 100 +.byte 115 +.byte 32 +.byte 85 +.byte 102 +.byte 84 +.byte 104 +.byte 111 +.byte 108 +.byte 100 +.byte 32 +.byte 97 +.byte 110 +.byte 100 +.byte 32 +.byte 69 +.byte 48 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.479: +.byte 46 +.byte 46 +.byte 46 +.byte 32 +.byte 110 +.byte 111 +.byte 32 +.byte 100 +.byte 105 +.byte 115 +.byte 99 +.byte 114 +.byte 101 +.byte 112 +.byte 97 +.byte 110 +.byte 99 +.byte 105 +.byte 115 +.byte 32 +.byte 102 +.byte 111 +.byte 117 +.byte 110 +.byte 100 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.476: +.byte 9 +.byte 105 +.byte 110 +.byte 118 +.byte 111 +.byte 108 +.byte 118 +.byte 105 +.byte 110 +.byte 103 +.byte 32 +.byte 105 +.byte 110 +.byte 116 +.byte 101 +.byte 114 +.byte 101 +.byte 115 +.byte 116 +.byte 32 +.byte 114 +.byte 97 +.byte 116 +.byte 101 +.byte 115 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.475: +.byte 69 +.byte 114 +.byte 114 +.byte 111 +.byte 114 +.byte 115 +.byte 32 +.byte 108 +.byte 105 +.byte 107 +.byte 101 +.byte 32 +.byte 116 +.byte 104 +.byte 105 +.byte 115 +.byte 32 +.byte 109 +.byte 97 +.byte 121 +.byte 32 +.byte 105 +.byte 110 +.byte 118 +.byte 97 +.byte 108 +.byte 105 +.byte 100 +.byte 97 +.byte 116 +.byte 101 +.byte 32 +.byte 102 +.byte 105 +.byte 110 +.byte 97 +.byte 110 +.byte 99 +.byte 105 +.byte 97 +.byte 108 +.byte 32 +.byte 99 +.byte 97 +.byte 108 +.byte 99 +.byte 117 +.byte 108 +.byte 97 +.byte 116 +.byte 105 +.byte 111 +.byte 110 +.byte 115 +.byte 10 +.byte 0 +.align 0 +L.454: +.byte 84 +.byte 101 +.byte 115 +.byte 116 +.byte 105 +.byte 110 +.byte 103 +.byte 32 +.byte 112 +.byte 111 +.byte 119 +.byte 101 +.byte 114 +.byte 115 +.byte 32 +.byte 90 +.byte 94 +.byte 105 +.byte 32 +.byte 102 +.byte 111 +.byte 114 +.byte 32 +.byte 115 +.byte 109 +.byte 97 +.byte 108 +.byte 108 +.byte 32 +.byte 73 +.byte 110 +.byte 116 +.byte 101 +.byte 103 +.byte 101 +.byte 114 +.byte 115 +.byte 32 +.byte 90 +.byte 32 +.byte 97 +.byte 110 +.byte 100 +.byte 32 +.byte 105 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.451: +.byte 115 +.byte 113 +.byte 114 +.byte 116 +.byte 32 +.byte 103 +.byte 101 +.byte 116 +.byte 115 +.byte 32 +.byte 116 +.byte 111 +.byte 111 +.byte 32 +.byte 109 +.byte 97 +.byte 110 +.byte 121 +.byte 32 +.byte 108 +.byte 97 +.byte 115 +.byte 116 +.byte 32 +.byte 100 +.byte 105 +.byte 103 +.byte 105 +.byte 116 +.byte 115 +.byte 32 +.byte 119 +.byte 114 +.byte 111 +.byte 110 +.byte 103 +.byte 0 +.align 0 +L.449: +.byte 116 +.byte 111 +.byte 32 +.byte 37 +.byte 46 +.byte 55 +.byte 101 +.byte 32 +.byte 117 +.byte 108 +.byte 112 +.byte 115 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.448: +.byte 79 +.byte 98 +.byte 115 +.byte 101 +.byte 114 +.byte 118 +.byte 101 +.byte 100 +.byte 32 +.byte 101 +.byte 114 +.byte 114 +.byte 111 +.byte 114 +.byte 115 +.byte 32 +.byte 114 +.byte 117 +.byte 110 +.byte 32 +.byte 102 +.byte 114 +.byte 111 +.byte 109 +.byte 32 +.byte 37 +.byte 46 +.byte 55 +.byte 101 +.byte 32 +.byte 0 +.align 0 +L.447: +.byte 83 +.byte 113 +.byte 117 +.byte 97 +.byte 114 +.byte 101 +.byte 32 +.byte 114 +.byte 111 +.byte 111 +.byte 116 +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 110 +.byte 101 +.byte 105 +.byte 116 +.byte 104 +.byte 101 +.byte 114 +.byte 32 +.byte 99 +.byte 104 +.byte 111 +.byte 112 +.byte 112 +.byte 101 +.byte 100 +.byte 32 +.byte 110 +.byte 111 +.byte 114 +.byte 32 +.byte 99 +.byte 111 +.byte 114 +.byte 114 +.byte 101 +.byte 99 +.byte 116 +.byte 108 +.byte 121 +.byte 32 +.byte 114 +.byte 111 +.byte 117 +.byte 110 +.byte 100 +.byte 101 +.byte 100 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.444: +.byte 83 +.byte 113 +.byte 117 +.byte 97 +.byte 114 +.byte 101 +.byte 32 +.byte 114 +.byte 111 +.byte 111 +.byte 116 +.byte 32 +.byte 97 +.byte 112 +.byte 112 +.byte 101 +.byte 97 +.byte 114 +.byte 115 +.byte 32 +.byte 116 +.byte 111 +.byte 32 +.byte 98 +.byte 101 +.byte 32 +.byte 99 +.byte 104 +.byte 111 +.byte 112 +.byte 112 +.byte 101 +.byte 100 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.439: +.byte 83 +.byte 113 +.byte 117 +.byte 97 +.byte 114 +.byte 101 +.byte 32 +.byte 114 +.byte 111 +.byte 111 +.byte 116 +.byte 32 +.byte 97 +.byte 112 +.byte 112 +.byte 101 +.byte 97 +.byte 114 +.byte 115 +.byte 32 +.byte 116 +.byte 111 +.byte 32 +.byte 98 +.byte 101 +.byte 32 +.byte 99 +.byte 111 +.byte 114 +.byte 114 +.byte 101 +.byte 99 +.byte 116 +.byte 108 +.byte 121 +.byte 32 +.byte 114 +.byte 111 +.byte 117 +.byte 110 +.byte 100 +.byte 101 +.byte 100 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.434: +.byte 32 +.byte 102 +.byte 97 +.byte 105 +.byte 108 +.byte 115 +.byte 32 +.byte 116 +.byte 101 +.byte 115 +.byte 116 +.byte 32 +.byte 119 +.byte 104 +.byte 101 +.byte 116 +.byte 104 +.byte 101 +.byte 114 +.byte 32 +.byte 115 +.byte 113 +.byte 114 +.byte 116 +.byte 32 +.byte 114 +.byte 111 +.byte 117 +.byte 110 +.byte 100 +.byte 115 +.byte 32 +.byte 111 +.byte 114 +.byte 32 +.byte 99 +.byte 104 +.byte 111 +.byte 112 +.byte 115 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.433: +.byte 82 +.byte 97 +.byte 100 +.byte 105 +.byte 120 +.byte 94 +.byte 80 +.byte 114 +.byte 101 +.byte 99 +.byte 105 +.byte 115 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 61 +.byte 32 +.byte 37 +.byte 46 +.byte 55 +.byte 101 +.byte 10 +.byte 0 +.align 0 +L.432: +.byte 65 +.byte 110 +.byte 111 +.byte 109 +.byte 97 +.byte 108 +.byte 111 +.byte 117 +.byte 115 +.byte 32 +.byte 97 +.byte 114 +.byte 105 +.byte 116 +.byte 104 +.byte 109 +.byte 101 +.byte 116 +.byte 105 +.byte 99 +.byte 32 +.byte 119 +.byte 105 +.byte 116 +.byte 104 +.byte 32 +.byte 73 +.byte 110 +.byte 116 +.byte 101 +.byte 103 +.byte 101 +.byte 114 +.byte 32 +.byte 60 +.byte 32 +.byte 0 +.align 0 +L.392: +.byte 84 +.byte 101 +.byte 115 +.byte 116 +.byte 105 +.byte 110 +.byte 103 +.byte 32 +.byte 119 +.byte 104 +.byte 101 +.byte 116 +.byte 104 +.byte 101 +.byte 114 +.byte 32 +.byte 115 +.byte 113 +.byte 114 +.byte 116 +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 114 +.byte 111 +.byte 117 +.byte 110 +.byte 100 +.byte 101 +.byte 100 +.byte 32 +.byte 111 +.byte 114 +.byte 32 +.byte 99 +.byte 104 +.byte 111 +.byte 112 +.byte 112 +.byte 101 +.byte 100 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.370: +.byte 115 +.byte 113 +.byte 114 +.byte 116 +.byte 40 +.byte 88 +.byte 41 +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 110 +.byte 111 +.byte 110 +.byte 45 +.byte 109 +.byte 111 +.byte 110 +.byte 111 +.byte 116 +.byte 111 +.byte 110 +.byte 105 +.byte 99 +.byte 32 +.byte 102 +.byte 111 +.byte 114 +.byte 32 +.byte 88 +.byte 32 +.byte 110 +.byte 101 +.byte 97 +.byte 114 +.byte 32 +.byte 37 +.byte 46 +.byte 55 +.byte 101 +.byte 32 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.369: +.byte 115 +.byte 113 +.byte 114 +.byte 116 +.byte 32 +.byte 104 +.byte 97 +.byte 115 +.byte 32 +.byte 112 +.byte 97 +.byte 115 +.byte 115 +.byte 101 +.byte 100 +.byte 32 +.byte 97 +.byte 32 +.byte 116 +.byte 101 +.byte 115 +.byte 116 +.byte 32 +.byte 102 +.byte 111 +.byte 114 +.byte 32 +.byte 77 +.byte 111 +.byte 110 +.byte 111 +.byte 116 +.byte 111 +.byte 110 +.byte 105 +.byte 99 +.byte 105 +.byte 116 +.byte 121 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.352: +.byte 84 +.byte 101 +.byte 115 +.byte 116 +.byte 32 +.byte 102 +.byte 111 +.byte 114 +.byte 32 +.byte 115 +.byte 113 +.byte 114 +.byte 116 +.byte 32 +.byte 109 +.byte 111 +.byte 110 +.byte 111 +.byte 116 +.byte 111 +.byte 110 +.byte 105 +.byte 99 +.byte 105 +.byte 116 +.byte 121 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.341: +.byte 84 +.byte 101 +.byte 115 +.byte 116 +.byte 105 +.byte 110 +.byte 103 +.byte 32 +.byte 105 +.byte 102 +.byte 32 +.byte 115 +.byte 113 +.byte 114 +.byte 116 +.byte 40 +.byte 88 +.byte 32 +.byte 42 +.byte 32 +.byte 88 +.byte 41 +.byte 32 +.byte 61 +.byte 61 +.byte 32 +.byte 88 +.byte 32 +.byte 102 +.byte 111 +.byte 114 +.byte 32 +.byte 37 +.byte 100 +.byte 32 +.byte 73 +.byte 110 +.byte 116 +.byte 101 +.byte 103 +.byte 101 +.byte 114 +.byte 115 +.byte 32 +.byte 88 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.336: +.byte 83 +.byte 113 +.byte 117 +.byte 97 +.byte 114 +.byte 101 +.byte 32 +.byte 114 +.byte 111 +.byte 111 +.byte 116 +.byte 32 +.byte 111 +.byte 102 +.byte 32 +.byte 48 +.byte 46 +.byte 48 +.byte 44 +.byte 32 +.byte 45 +.byte 48 +.byte 46 +.byte 48 +.byte 32 +.byte 111 +.byte 114 +.byte 32 +.byte 49 +.byte 46 +.byte 48 +.byte 32 +.byte 119 +.byte 114 +.byte 111 +.byte 110 +.byte 103 +.byte 0 +.align 0 +L.334: +.byte 10 +.byte 82 +.byte 117 +.byte 110 +.byte 110 +.byte 105 +.byte 110 +.byte 103 +.byte 32 +.byte 116 +.byte 101 +.byte 115 +.byte 116 +.byte 32 +.byte 111 +.byte 102 +.byte 32 +.byte 115 +.byte 113 +.byte 117 +.byte 97 +.byte 114 +.byte 101 +.byte 32 +.byte 114 +.byte 111 +.byte 111 +.byte 116 +.byte 40 +.byte 120 +.byte 41 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.333: +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 78 +.byte 111 +.byte 32 +.byte 102 +.byte 97 +.byte 105 +.byte 108 +.byte 117 +.byte 114 +.byte 101 +.byte 115 +.byte 32 +.byte 102 +.byte 111 +.byte 117 +.byte 110 +.byte 100 +.byte 32 +.byte 105 +.byte 110 +.byte 32 +.byte 37 +.byte 100 +.byte 32 +.byte 105 +.byte 110 +.byte 116 +.byte 101 +.byte 103 +.byte 101 +.byte 114 +.byte 32 +.byte 112 +.byte 97 +.byte 105 +.byte 114 +.byte 115 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.332: +.byte 88 +.byte 32 +.byte 42 +.byte 32 +.byte 89 +.byte 32 +.byte 61 +.byte 61 +.byte 32 +.byte 89 +.byte 32 +.byte 42 +.byte 32 +.byte 88 +.byte 32 +.byte 116 +.byte 114 +.byte 105 +.byte 97 +.byte 108 +.byte 32 +.byte 102 +.byte 97 +.byte 105 +.byte 108 +.byte 115 +.byte 46 +.byte 10 +.byte 0 +.align 3 +L.323: +.word 0x40080000 +.word 0x0 +.align 0 +L.322: +.byte 84 +.byte 101 +.byte 115 +.byte 116 +.byte 105 +.byte 110 +.byte 103 +.byte 32 +.byte 111 +.byte 110 +.byte 32 +.byte 37 +.byte 100 +.byte 32 +.byte 114 +.byte 97 +.byte 110 +.byte 100 +.byte 111 +.byte 109 +.byte 32 +.byte 112 +.byte 97 +.byte 105 +.byte 114 +.byte 115 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.321: +.byte 68 +.byte 111 +.byte 101 +.byte 115 +.byte 32 +.byte 77 +.byte 117 +.byte 108 +.byte 116 +.byte 105 +.byte 112 +.byte 108 +.byte 105 +.byte 99 +.byte 97 +.byte 116 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 99 +.byte 111 +.byte 109 +.byte 109 +.byte 117 +.byte 116 +.byte 101 +.byte 63 +.byte 32 +.byte 32 +.byte 0 +.align 0 +L.318: +.byte 108 +.byte 97 +.byte 99 +.byte 107 +.byte 40 +.byte 115 +.byte 41 +.byte 32 +.byte 111 +.byte 102 +.byte 32 +.byte 103 +.byte 117 +.byte 97 +.byte 114 +.byte 100 +.byte 32 +.byte 100 +.byte 105 +.byte 103 +.byte 105 +.byte 116 +.byte 115 +.byte 32 +.byte 111 +.byte 114 +.byte 32 +.byte 102 +.byte 97 +.byte 105 +.byte 108 +.byte 117 +.byte 114 +.byte 101 +.byte 40 +.byte 115 +.byte 41 +.byte 32 +.byte 116 +.byte 111 +.byte 32 +.byte 99 +.byte 111 +.byte 114 +.byte 114 +.byte 101 +.byte 99 +.byte 116 +.byte 108 +.byte 121 +.byte 32 +.byte 114 +.byte 111 +.byte 117 +.byte 110 +.byte 100 +.byte 32 +.byte 111 +.byte 114 +.byte 32 +.byte 99 +.byte 104 +.byte 111 +.byte 112 +.byte 10 +.byte 40 +.byte 110 +.byte 111 +.byte 116 +.byte 101 +.byte 100 +.byte 32 +.byte 97 +.byte 98 +.byte 111 +.byte 118 +.byte 101 +.byte 41 +.byte 32 +.byte 99 +.byte 111 +.byte 117 +.byte 110 +.byte 116 +.byte 32 +.byte 97 +.byte 115 +.byte 32 +.byte 111 +.byte 110 +.byte 101 +.byte 32 +.byte 102 +.byte 108 +.byte 97 +.byte 119 +.byte 32 +.byte 105 +.byte 110 +.byte 32 +.byte 116 +.byte 104 +.byte 101 +.byte 32 +.byte 102 +.byte 105 +.byte 110 +.byte 97 +.byte 108 +.byte 32 +.byte 116 +.byte 97 +.byte 108 +.byte 108 +.byte 121 +.byte 32 +.byte 98 +.byte 101 +.byte 108 +.byte 111 +.byte 119 +.byte 0 +.align 0 +L.316: +.byte 83 +.byte 116 +.byte 105 +.byte 99 +.byte 107 +.byte 121 +.byte 32 +.byte 98 +.byte 105 +.byte 116 +.byte 32 +.byte 117 +.byte 115 +.byte 101 +.byte 100 +.byte 32 +.byte 105 +.byte 110 +.byte 99 +.byte 111 +.byte 114 +.byte 114 +.byte 101 +.byte 99 +.byte 116 +.byte 108 +.byte 121 +.byte 32 +.byte 111 +.byte 114 +.byte 32 +.byte 110 +.byte 111 +.byte 116 +.byte 32 +.byte 97 +.byte 116 +.byte 32 +.byte 97 +.byte 108 +.byte 108 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.315: +.byte 83 +.byte 116 +.byte 105 +.byte 99 +.byte 107 +.byte 121 +.byte 32 +.byte 98 +.byte 105 +.byte 116 +.byte 32 +.byte 97 +.byte 112 +.byte 112 +.byte 97 +.byte 114 +.byte 101 +.byte 110 +.byte 116 +.byte 108 +.byte 121 +.byte 32 +.byte 117 +.byte 115 +.byte 101 +.byte 100 +.byte 32 +.byte 99 +.byte 111 +.byte 114 +.byte 114 +.byte 101 +.byte 99 +.byte 116 +.byte 108 +.byte 121 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.298: +.byte 67 +.byte 104 +.byte 101 +.byte 99 +.byte 107 +.byte 105 +.byte 110 +.byte 103 +.byte 32 +.byte 102 +.byte 111 +.byte 114 +.byte 32 +.byte 115 +.byte 116 +.byte 105 +.byte 99 +.byte 107 +.byte 121 +.byte 32 +.byte 98 +.byte 105 +.byte 116 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.295: +.byte 40 +.byte 88 +.byte 32 +.byte 45 +.byte 32 +.byte 89 +.byte 41 +.byte 32 +.byte 43 +.byte 32 +.byte 40 +.byte 89 +.byte 32 +.byte 45 +.byte 32 +.byte 88 +.byte 41 +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 110 +.byte 111 +.byte 110 +.byte 32 +.byte 122 +.byte 101 +.byte 114 +.byte 111 +.byte 33 +.byte 10 +.byte 0 +.align 0 +L.292: +.byte 65 +.byte 100 +.byte 100 +.byte 105 +.byte 116 +.byte 105 +.byte 111 +.byte 110 +.byte 47 +.byte 83 +.byte 117 +.byte 98 +.byte 116 +.byte 114 +.byte 97 +.byte 99 +.byte 116 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 110 +.byte 101 +.byte 105 +.byte 116 +.byte 104 +.byte 101 +.byte 114 +.byte 32 +.byte 114 +.byte 111 +.byte 117 +.byte 110 +.byte 100 +.byte 115 +.byte 32 +.byte 110 +.byte 111 +.byte 114 +.byte 32 +.byte 99 +.byte 104 +.byte 111 +.byte 112 +.byte 115 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.291: +.byte 65 +.byte 100 +.byte 100 +.byte 47 +.byte 83 +.byte 117 +.byte 98 +.byte 116 +.byte 114 +.byte 97 +.byte 99 +.byte 116 +.byte 0 +.align 0 +L.288: +.byte 65 +.byte 100 +.byte 100 +.byte 105 +.byte 116 +.byte 105 +.byte 111 +.byte 110 +.byte 47 +.byte 83 +.byte 117 +.byte 98 +.byte 116 +.byte 114 +.byte 97 +.byte 99 +.byte 116 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 97 +.byte 112 +.byte 112 +.byte 101 +.byte 97 +.byte 114 +.byte 115 +.byte 32 +.byte 116 +.byte 111 +.byte 32 +.byte 114 +.byte 111 +.byte 117 +.byte 110 +.byte 100 +.byte 32 +.byte 99 +.byte 111 +.byte 114 +.byte 114 +.byte 101 +.byte 99 +.byte 116 +.byte 108 +.byte 121 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.281: +.byte 65 +.byte 100 +.byte 100 +.byte 47 +.byte 83 +.byte 117 +.byte 98 +.byte 116 +.byte 114 +.byte 97 +.byte 99 +.byte 116 +.byte 32 +.byte 97 +.byte 112 +.byte 112 +.byte 101 +.byte 97 +.byte 114 +.byte 115 +.byte 32 +.byte 116 +.byte 111 +.byte 32 +.byte 98 +.byte 101 +.byte 32 +.byte 99 +.byte 104 +.byte 111 +.byte 112 +.byte 112 +.byte 101 +.byte 100 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.276: +.byte 73 +.byte 110 +.byte 99 +.byte 111 +.byte 109 +.byte 112 +.byte 108 +.byte 101 +.byte 116 +.byte 101 +.byte 32 +.byte 99 +.byte 97 +.byte 114 +.byte 114 +.byte 121 +.byte 45 +.byte 112 +.byte 114 +.byte 111 +.byte 112 +.byte 97 +.byte 103 +.byte 97 +.byte 116 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 105 +.byte 110 +.byte 32 +.byte 65 +.byte 100 +.byte 100 +.byte 105 +.byte 116 +.byte 105 +.byte 111 +.byte 110 +.byte 0 +.align 0 +L.272: +.byte 82 +.byte 97 +.byte 100 +.byte 105 +.byte 120 +.byte 32 +.byte 42 +.byte 32 +.byte 40 +.byte 32 +.byte 49 +.byte 32 +.byte 47 +.byte 32 +.byte 82 +.byte 97 +.byte 100 +.byte 105 +.byte 120 +.byte 32 +.byte 41 +.byte 32 +.byte 100 +.byte 105 +.byte 102 +.byte 102 +.byte 101 +.byte 114 +.byte 115 +.byte 32 +.byte 102 +.byte 114 +.byte 111 +.byte 109 +.byte 32 +.byte 49 +.byte 0 +.align 0 +L.270: +.byte 47 +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 110 +.byte 101 +.byte 105 +.byte 116 +.byte 104 +.byte 101 +.byte 114 +.byte 32 +.byte 99 +.byte 104 +.byte 111 +.byte 112 +.byte 112 +.byte 101 +.byte 100 +.byte 32 +.byte 110 +.byte 111 +.byte 114 +.byte 32 +.byte 99 +.byte 111 +.byte 114 +.byte 114 +.byte 101 +.byte 99 +.byte 116 +.byte 108 +.byte 121 +.byte 32 +.byte 114 +.byte 111 +.byte 117 +.byte 110 +.byte 100 +.byte 101 +.byte 100 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.267: +.byte 68 +.byte 105 +.byte 118 +.byte 105 +.byte 115 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 97 +.byte 112 +.byte 112 +.byte 101 +.byte 97 +.byte 114 +.byte 115 +.byte 32 +.byte 116 +.byte 111 +.byte 32 +.byte 99 +.byte 104 +.byte 111 +.byte 112 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.264: +.byte 68 +.byte 105 +.byte 118 +.byte 105 +.byte 115 +.byte 105 +.byte 111 +.byte 110 +.byte 0 +.align 0 +L.261: +.byte 68 +.byte 105 +.byte 118 +.byte 105 +.byte 115 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 97 +.byte 112 +.byte 112 +.byte 101 +.byte 97 +.byte 114 +.byte 115 +.byte 32 +.byte 116 +.byte 111 +.byte 32 +.byte 114 +.byte 111 +.byte 117 +.byte 110 +.byte 100 +.byte 32 +.byte 99 +.byte 111 +.byte 114 +.byte 114 +.byte 101 +.byte 99 +.byte 116 +.byte 108 +.byte 121 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.256: +.byte 77 +.byte 117 +.byte 108 +.byte 116 +.byte 105 +.byte 112 +.byte 108 +.byte 105 +.byte 99 +.byte 97 +.byte 116 +.byte 105 +.byte 111 +.byte 110 +.byte 0 +.align 0 +L.253: +.byte 42 +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 110 +.byte 101 +.byte 105 +.byte 116 +.byte 104 +.byte 101 +.byte 114 +.byte 32 +.byte 99 +.byte 104 +.byte 111 +.byte 112 +.byte 112 +.byte 101 +.byte 100 +.byte 32 +.byte 110 +.byte 111 +.byte 114 +.byte 32 +.byte 99 +.byte 111 +.byte 114 +.byte 114 +.byte 101 +.byte 99 +.byte 116 +.byte 108 +.byte 121 +.byte 32 +.byte 114 +.byte 111 +.byte 117 +.byte 110 +.byte 100 +.byte 101 +.byte 100 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.252: +.byte 77 +.byte 117 +.byte 108 +.byte 116 +.byte 105 +.byte 112 +.byte 108 +.byte 105 +.byte 99 +.byte 97 +.byte 116 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 97 +.byte 112 +.byte 112 +.byte 101 +.byte 97 +.byte 114 +.byte 115 +.byte 32 +.byte 116 +.byte 111 +.byte 32 +.byte 99 +.byte 104 +.byte 111 +.byte 112 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.249: +.byte 77 +.byte 117 +.byte 108 +.byte 116 +.byte 105 +.byte 112 +.byte 108 +.byte 105 +.byte 99 +.byte 97 +.byte 116 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 97 +.byte 112 +.byte 112 +.byte 101 +.byte 97 +.byte 114 +.byte 115 +.byte 32 +.byte 116 +.byte 111 +.byte 32 +.byte 114 +.byte 111 +.byte 117 +.byte 110 +.byte 100 +.byte 32 +.byte 99 +.byte 111 +.byte 114 +.byte 114 +.byte 101 +.byte 99 +.byte 116 +.byte 108 +.byte 121 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.239: +.byte 88 +.byte 32 +.byte 42 +.byte 32 +.byte 40 +.byte 49 +.byte 47 +.byte 88 +.byte 41 +.byte 32 +.byte 100 +.byte 105 +.byte 102 +.byte 102 +.byte 101 +.byte 114 +.byte 115 +.byte 32 +.byte 102 +.byte 114 +.byte 111 +.byte 109 +.byte 32 +.byte 49 +.byte 0 +.align 0 +L.220: +.byte 67 +.byte 104 +.byte 101 +.byte 99 +.byte 107 +.byte 105 +.byte 110 +.byte 103 +.byte 32 +.byte 114 +.byte 111 +.byte 117 +.byte 110 +.byte 100 +.byte 105 +.byte 110 +.byte 103 +.byte 32 +.byte 111 +.byte 110 +.byte 32 +.byte 109 +.byte 117 +.byte 108 +.byte 116 +.byte 105 +.byte 112 +.byte 108 +.byte 121 +.byte 44 +.byte 32 +.byte 100 +.byte 105 +.byte 118 +.byte 105 +.byte 100 +.byte 101 +.byte 32 +.byte 97 +.byte 110 +.byte 100 +.byte 32 +.byte 97 +.byte 100 +.byte 100 +.byte 47 +.byte 115 +.byte 117 +.byte 98 +.byte 116 +.byte 114 +.byte 97 +.byte 99 +.byte 116 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.219: +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 42 +.byte 44 +.byte 32 +.byte 47 +.byte 44 +.byte 32 +.byte 97 +.byte 110 +.byte 100 +.byte 32 +.byte 45 +.byte 32 +.byte 97 +.byte 112 +.byte 112 +.byte 101 +.byte 97 +.byte 114 +.byte 32 +.byte 116 +.byte 111 +.byte 32 +.byte 104 +.byte 97 +.byte 118 +.byte 101 +.byte 32 +.byte 103 +.byte 117 +.byte 97 +.byte 114 +.byte 100 +.byte 32 +.byte 100 +.byte 105 +.byte 103 +.byte 105 +.byte 116 +.byte 115 +.byte 44 +.byte 32 +.byte 97 +.byte 115 +.byte 32 +.byte 116 +.byte 104 +.byte 101 +.byte 121 +.byte 32 +.byte 115 +.byte 104 +.byte 111 +.byte 117 +.byte 108 +.byte 100 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.216: +.byte 32 +.byte 32 +.byte 46 +.byte 46 +.byte 46 +.byte 32 +.byte 32 +.byte 105 +.byte 102 +.byte 32 +.byte 40 +.byte 88 +.byte 32 +.byte 61 +.byte 61 +.byte 32 +.byte 49 +.byte 46 +.byte 48 +.byte 41 +.byte 32 +.byte 123 +.byte 46 +.byte 46 +.byte 46 +.byte 46 +.byte 46 +.byte 125 +.byte 32 +.byte 101 +.byte 108 +.byte 115 +.byte 101 +.byte 32 +.byte 123 +.byte 46 +.byte 46 +.byte 46 +.byte 47 +.byte 40 +.byte 88 +.byte 45 +.byte 49 +.byte 46 +.byte 48 +.byte 41 +.byte 46 +.byte 46 +.byte 46 +.byte 125 +.byte 10 +.byte 0 +.align 0 +L.215: +.byte 32 +.byte 32 +.byte 115 +.byte 117 +.byte 99 +.byte 104 +.byte 32 +.byte 112 +.byte 114 +.byte 101 +.byte 99 +.byte 97 +.byte 117 +.byte 116 +.byte 105 +.byte 111 +.byte 110 +.byte 115 +.byte 32 +.byte 97 +.byte 103 +.byte 97 +.byte 105 +.byte 110 +.byte 115 +.byte 116 +.byte 32 +.byte 100 +.byte 105 +.byte 118 +.byte 105 +.byte 115 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 98 +.byte 121 +.byte 32 +.byte 122 +.byte 101 +.byte 114 +.byte 111 +.byte 32 +.byte 97 +.byte 115 +.byte 10 +.byte 0 +.align 0 +L.214: +.byte 32 +.byte 32 +.byte 115 +.byte 117 +.byte 98 +.byte 116 +.byte 114 +.byte 97 +.byte 99 +.byte 116 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 121 +.byte 105 +.byte 101 +.byte 108 +.byte 100 +.byte 115 +.byte 32 +.byte 32 +.byte 40 +.byte 49 +.byte 45 +.byte 85 +.byte 49 +.byte 41 +.byte 32 +.byte 45 +.byte 32 +.byte 49 +.byte 32 +.byte 61 +.byte 32 +.byte 48 +.byte 32 +.byte 44 +.byte 32 +.byte 116 +.byte 104 +.byte 101 +.byte 114 +.byte 101 +.byte 98 +.byte 121 +.byte 32 +.byte 118 +.byte 105 +.byte 116 +.byte 105 +.byte 97 +.byte 116 +.byte 105 +.byte 110 +.byte 103 +.byte 10 +.byte 0 +.align 0 +L.213: +.byte 99 +.byte 111 +.byte 109 +.byte 112 +.byte 97 +.byte 114 +.byte 105 +.byte 115 +.byte 111 +.byte 110 +.byte 32 +.byte 97 +.byte 108 +.byte 108 +.byte 101 +.byte 103 +.byte 101 +.byte 115 +.byte 32 +.byte 32 +.byte 40 +.byte 49 +.byte 45 +.byte 85 +.byte 49 +.byte 41 +.byte 32 +.byte 60 +.byte 32 +.byte 49 +.byte 32 +.byte 32 +.byte 97 +.byte 108 +.byte 116 +.byte 104 +.byte 111 +.byte 117 +.byte 103 +.byte 104 +.byte 10 +.byte 0 +.align 0 +L.210: +.byte 45 +.byte 32 +.byte 108 +.byte 97 +.byte 99 +.byte 107 +.byte 115 +.byte 32 +.byte 71 +.byte 117 +.byte 97 +.byte 114 +.byte 100 +.byte 32 +.byte 68 +.byte 105 +.byte 103 +.byte 105 +.byte 116 +.byte 44 +.byte 32 +.byte 115 +.byte 111 +.byte 32 +.byte 99 +.byte 97 +.byte 110 +.byte 99 +.byte 101 +.byte 108 +.byte 108 +.byte 97 +.byte 116 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 111 +.byte 98 +.byte 115 +.byte 99 +.byte 117 +.byte 114 +.byte 101 +.byte 100 +.byte 0 +.align 0 +L.205: +.byte 42 +.byte 32 +.byte 97 +.byte 110 +.byte 100 +.byte 47 +.byte 111 +.byte 114 +.byte 32 +.byte 47 +.byte 32 +.byte 103 +.byte 101 +.byte 116 +.byte 115 +.byte 32 +.byte 116 +.byte 111 +.byte 111 +.byte 32 +.byte 109 +.byte 97 +.byte 110 +.byte 121 +.byte 32 +.byte 108 +.byte 97 +.byte 115 +.byte 116 +.byte 32 +.byte 100 +.byte 105 +.byte 103 +.byte 105 +.byte 116 +.byte 115 +.byte 32 +.byte 119 +.byte 114 +.byte 111 +.byte 110 +.byte 103 +.byte 0 +.align 0 +L.201: +.byte 67 +.byte 111 +.byte 109 +.byte 112 +.byte 117 +.byte 116 +.byte 101 +.byte 100 +.byte 32 +.byte 118 +.byte 97 +.byte 108 +.byte 117 +.byte 101 +.byte 32 +.byte 111 +.byte 102 +.byte 32 +.byte 49 +.byte 47 +.byte 49 +.byte 46 +.byte 48 +.byte 48 +.byte 48 +.byte 46 +.byte 46 +.byte 49 +.byte 32 +.byte 62 +.byte 61 +.byte 32 +.byte 49 +.byte 0 +.align 0 +L.199: +.byte 68 +.byte 105 +.byte 118 +.byte 105 +.byte 115 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 108 +.byte 97 +.byte 99 +.byte 107 +.byte 115 +.byte 32 +.byte 97 +.byte 32 +.byte 71 +.byte 117 +.byte 97 +.byte 114 +.byte 100 +.byte 32 +.byte 68 +.byte 105 +.byte 103 +.byte 105 +.byte 116 +.byte 44 +.byte 32 +.byte 115 +.byte 111 +.byte 32 +.byte 88 +.byte 47 +.byte 49 +.byte 32 +.byte 33 +.byte 61 +.byte 32 +.byte 88 +.byte 0 +.align 0 +L.194: +.byte 68 +.byte 105 +.byte 118 +.byte 105 +.byte 115 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 108 +.byte 97 +.byte 99 +.byte 107 +.byte 115 +.byte 32 +.byte 97 +.byte 32 +.byte 71 +.byte 117 +.byte 97 +.byte 114 +.byte 100 +.byte 32 +.byte 68 +.byte 105 +.byte 103 +.byte 105 +.byte 116 +.byte 44 +.byte 32 +.byte 115 +.byte 111 +.byte 32 +.byte 101 +.byte 114 +.byte 114 +.byte 111 +.byte 114 +.byte 32 +.byte 99 +.byte 97 +.byte 110 +.byte 32 +.byte 101 +.byte 120 +.byte 99 +.byte 101 +.byte 101 +.byte 100 +.byte 32 +.byte 49 +.byte 32 +.byte 117 +.byte 108 +.byte 112 +.byte 10 +.byte 111 +.byte 114 +.byte 32 +.byte 32 +.byte 49 +.byte 47 +.byte 51 +.byte 32 +.byte 32 +.byte 97 +.byte 110 +.byte 100 +.byte 32 +.byte 32 +.byte 51 +.byte 47 +.byte 57 +.byte 32 +.byte 32 +.byte 97 +.byte 110 +.byte 100 +.byte 32 +.byte 32 +.byte 57 +.byte 47 +.byte 50 +.byte 55 +.byte 32 +.byte 109 +.byte 97 +.byte 121 +.byte 32 +.byte 100 +.byte 105 +.byte 115 +.byte 97 +.byte 103 +.byte 114 +.byte 101 +.byte 101 +.byte 0 +.align 0 +L.190: +.byte 42 +.byte 32 +.byte 103 +.byte 101 +.byte 116 +.byte 115 +.byte 32 +.byte 116 +.byte 111 +.byte 111 +.byte 32 +.byte 109 +.byte 97 +.byte 110 +.byte 121 +.byte 32 +.byte 102 +.byte 105 +.byte 110 +.byte 97 +.byte 108 +.byte 32 +.byte 100 +.byte 105 +.byte 103 +.byte 105 +.byte 116 +.byte 115 +.byte 32 +.byte 119 +.byte 114 +.byte 111 +.byte 110 +.byte 103 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.188: +.byte 42 +.byte 32 +.byte 108 +.byte 97 +.byte 99 +.byte 107 +.byte 115 +.byte 32 +.byte 97 +.byte 32 +.byte 71 +.byte 117 +.byte 97 +.byte 114 +.byte 100 +.byte 32 +.byte 68 +.byte 105 +.byte 103 +.byte 105 +.byte 116 +.byte 44 +.byte 32 +.byte 115 +.byte 111 +.byte 32 +.byte 49 +.byte 42 +.byte 88 +.byte 32 +.byte 33 +.byte 61 +.byte 32 +.byte 88 +.byte 0 +.align 0 +L.185: +.byte 10 +.byte 67 +.byte 104 +.byte 101 +.byte 99 +.byte 107 +.byte 105 +.byte 110 +.byte 103 +.byte 32 +.byte 102 +.byte 111 +.byte 114 +.byte 32 +.byte 103 +.byte 117 +.byte 97 +.byte 114 +.byte 100 +.byte 32 +.byte 100 +.byte 105 +.byte 103 +.byte 105 +.byte 116 +.byte 32 +.byte 105 +.byte 110 +.byte 32 +.byte 42 +.byte 44 +.byte 32 +.byte 47 +.byte 44 +.byte 32 +.byte 97 +.byte 110 +.byte 100 +.byte 32 +.byte 45 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.184: +.byte 83 +.byte 117 +.byte 98 +.byte 116 +.byte 114 +.byte 97 +.byte 99 +.byte 116 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 97 +.byte 112 +.byte 112 +.byte 101 +.byte 97 +.byte 114 +.byte 115 +.byte 32 +.byte 116 +.byte 111 +.byte 32 +.byte 98 +.byte 101 +.byte 32 +.byte 110 +.byte 111 +.byte 114 +.byte 109 +.byte 97 +.byte 108 +.byte 105 +.byte 122 +.byte 101 +.byte 100 +.byte 44 +.byte 32 +.byte 97 +.byte 115 +.byte 32 +.byte 105 +.byte 116 +.byte 32 +.byte 115 +.byte 104 +.byte 111 +.byte 117 +.byte 108 +.byte 100 +.byte 32 +.byte 98 +.byte 101 +.byte 46 +.byte 0 +.align 0 +L.179: +.byte 83 +.byte 117 +.byte 98 +.byte 116 +.byte 114 +.byte 97 +.byte 99 +.byte 116 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 110 +.byte 111 +.byte 116 +.byte 32 +.byte 110 +.byte 111 +.byte 114 +.byte 109 +.byte 97 +.byte 108 +.byte 105 +.byte 122 +.byte 101 +.byte 100 +.byte 32 +.byte 88 +.byte 61 +.byte 89 +.byte 44 +.byte 88 +.byte 43 +.byte 90 +.byte 32 +.byte 33 +.byte 61 +.byte 32 +.byte 89 +.byte 43 +.byte 90 +.byte 33 +.byte 0 +.align 0 +L.175: +.byte 114 +.byte 111 +.byte 117 +.byte 103 +.byte 104 +.byte 108 +.byte 121 +.byte 32 +.byte 37 +.byte 103 +.byte 32 +.byte 101 +.byte 120 +.byte 116 +.byte 114 +.byte 97 +.byte 32 +.byte 115 +.byte 105 +.byte 103 +.byte 110 +.byte 105 +.byte 102 +.byte 105 +.byte 99 +.byte 97 +.byte 110 +.byte 116 +.byte 32 +.byte 100 +.byte 101 +.byte 99 +.byte 105 +.byte 109 +.byte 97 +.byte 108 +.byte 115 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.174: +.byte 112 +.byte 114 +.byte 101 +.byte 99 +.byte 105 +.byte 115 +.byte 101 +.byte 108 +.byte 121 +.byte 32 +.byte 119 +.byte 105 +.byte 116 +.byte 104 +.byte 32 +.byte 97 +.byte 98 +.byte 111 +.byte 117 +.byte 116 +.byte 32 +.byte 37 +.byte 103 +.byte 32 +.byte 101 +.byte 120 +.byte 116 +.byte 114 +.byte 97 +.byte 32 +.byte 66 +.byte 45 +.byte 100 +.byte 105 +.byte 103 +.byte 105 +.byte 116 +.byte 115 +.byte 44 +.byte 32 +.byte 105 +.byte 46 +.byte 101 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.173: +.byte 83 +.byte 111 +.byte 109 +.byte 101 +.byte 32 +.byte 115 +.byte 117 +.byte 98 +.byte 101 +.byte 120 +.byte 112 +.byte 114 +.byte 101 +.byte 115 +.byte 115 +.byte 105 +.byte 111 +.byte 110 +.byte 115 +.byte 32 +.byte 97 +.byte 112 +.byte 112 +.byte 101 +.byte 97 +.byte 114 +.byte 32 +.byte 116 +.byte 111 +.byte 32 +.byte 98 +.byte 101 +.byte 32 +.byte 99 +.byte 97 +.byte 108 +.byte 99 +.byte 117 +.byte 108 +.byte 97 +.byte 116 +.byte 101 +.byte 100 +.byte 32 +.byte 101 +.byte 120 +.byte 116 +.byte 114 +.byte 97 +.byte 10 +.byte 0 +.align 0 +L.167: +.byte 111 +.byte 102 +.byte 32 +.byte 97 +.byte 110 +.byte 10 +.byte 101 +.byte 120 +.byte 116 +.byte 114 +.byte 97 +.byte 45 +.byte 112 +.byte 114 +.byte 101 +.byte 99 +.byte 105 +.byte 115 +.byte 105 +.byte 111 +.byte 110 +.byte 0 +.align 0 +L.166: +.byte 90 +.byte 49 +.byte 32 +.byte 61 +.byte 32 +.byte 37 +.byte 46 +.byte 55 +.byte 101 +.byte 44 +.byte 32 +.byte 111 +.byte 114 +.byte 32 +.byte 90 +.byte 50 +.byte 32 +.byte 61 +.byte 32 +.byte 37 +.byte 46 +.byte 55 +.byte 101 +.byte 32 +.byte 0 +.align 0 +L.165: +.byte 44 +.byte 32 +.byte 111 +.byte 114 +.byte 32 +.byte 101 +.byte 120 +.byte 97 +.byte 99 +.byte 116 +.byte 32 +.byte 114 +.byte 97 +.byte 116 +.byte 105 +.byte 111 +.byte 110 +.byte 97 +.byte 108 +.byte 32 +.byte 97 +.byte 114 +.byte 105 +.byte 116 +.byte 104 +.byte 109 +.byte 101 +.byte 116 +.byte 105 +.byte 99 +.byte 32 +.byte 97 +.byte 32 +.byte 114 +.byte 101 +.byte 115 +.byte 117 +.byte 108 +.byte 116 +.byte 10 +.byte 0 +.align 0 +L.164: +.byte 66 +.byte 101 +.byte 99 +.byte 97 +.byte 117 +.byte 115 +.byte 101 +.byte 32 +.byte 111 +.byte 102 +.byte 32 +.byte 117 +.byte 110 +.byte 117 +.byte 115 +.byte 117 +.byte 97 +.byte 108 +.byte 32 +.byte 82 +.byte 97 +.byte 100 +.byte 105 +.byte 120 +.byte 32 +.byte 61 +.byte 32 +.byte 37 +.byte 102 +.byte 0 +.align 0 +L.160: +.byte 9 +.byte 85 +.byte 50 +.byte 32 +.byte 61 +.byte 32 +.byte 37 +.byte 46 +.byte 55 +.byte 101 +.byte 44 +.byte 32 +.byte 90 +.byte 50 +.byte 32 +.byte 45 +.byte 32 +.byte 85 +.byte 50 +.byte 32 +.byte 61 +.byte 32 +.byte 37 +.byte 46 +.byte 55 +.byte 101 +.byte 10 +.byte 0 +.align 0 +L.159: +.byte 9 +.byte 85 +.byte 49 +.byte 32 +.byte 61 +.byte 32 +.byte 37 +.byte 46 +.byte 55 +.byte 101 +.byte 44 +.byte 32 +.byte 90 +.byte 49 +.byte 32 +.byte 45 +.byte 32 +.byte 85 +.byte 49 +.byte 32 +.byte 61 +.byte 32 +.byte 37 +.byte 46 +.byte 55 +.byte 101 +.byte 10 +.byte 0 +.align 0 +L.158: +.byte 80 +.byte 114 +.byte 101 +.byte 99 +.byte 105 +.byte 115 +.byte 105 +.byte 111 +.byte 110 +.byte 0 +.align 0 +L.157: +.byte 0 +.align 0 +L.150: +.byte 84 +.byte 104 +.byte 97 +.byte 116 +.byte 32 +.byte 102 +.byte 101 +.byte 97 +.byte 116 +.byte 117 +.byte 114 +.byte 101 +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 110 +.byte 111 +.byte 116 +.byte 32 +.byte 116 +.byte 101 +.byte 115 +.byte 116 +.byte 101 +.byte 100 +.byte 32 +.byte 102 +.byte 117 +.byte 114 +.byte 116 +.byte 104 +.byte 101 +.byte 114 +.byte 32 +.byte 98 +.byte 121 +.byte 32 +.byte 116 +.byte 104 +.byte 105 +.byte 115 +.byte 32 +.byte 112 +.byte 114 +.byte 111 +.byte 103 +.byte 114 +.byte 97 +.byte 109 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.145: +.byte 80 +.byte 111 +.byte 115 +.byte 115 +.byte 105 +.byte 98 +.byte 108 +.byte 121 +.byte 32 +.byte 115 +.byte 111 +.byte 109 +.byte 101 +.byte 32 +.byte 112 +.byte 97 +.byte 114 +.byte 116 +.byte 32 +.byte 111 +.byte 102 +.byte 32 +.byte 116 +.byte 104 +.byte 105 +.byte 115 +.byte 0 +.align 0 +L.144: +.byte 98 +.byte 121 +.byte 32 +.byte 101 +.byte 120 +.byte 116 +.byte 114 +.byte 97 +.byte 45 +.byte 112 +.byte 114 +.byte 101 +.byte 99 +.byte 105 +.byte 115 +.byte 101 +.byte 32 +.byte 101 +.byte 118 +.byte 97 +.byte 108 +.byte 117 +.byte 97 +.byte 116 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 111 +.byte 102 +.byte 32 +.byte 97 +.byte 114 +.byte 105 +.byte 116 +.byte 104 +.byte 109 +.byte 101 +.byte 116 +.byte 105 +.byte 99 +.byte 32 +.byte 115 +.byte 117 +.byte 98 +.byte 101 +.byte 120 +.byte 112 +.byte 114 +.byte 101 +.byte 115 +.byte 115 +.byte 105 +.byte 111 +.byte 110 +.byte 115 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.143: +.byte 97 +.byte 114 +.byte 101 +.byte 32 +.byte 115 +.byte 121 +.byte 109 +.byte 112 +.byte 116 +.byte 111 +.byte 109 +.byte 115 +.byte 32 +.byte 111 +.byte 102 +.byte 32 +.byte 105 +.byte 110 +.byte 99 +.byte 111 +.byte 110 +.byte 115 +.byte 105 +.byte 115 +.byte 116 +.byte 101 +.byte 110 +.byte 99 +.byte 105 +.byte 101 +.byte 115 +.byte 32 +.byte 105 +.byte 110 +.byte 116 +.byte 114 +.byte 111 +.byte 100 +.byte 117 +.byte 99 +.byte 101 +.byte 100 +.byte 10 +.byte 0 +.align 0 +L.142: +.byte 114 +.byte 101 +.byte 115 +.byte 112 +.byte 101 +.byte 99 +.byte 116 +.byte 105 +.byte 118 +.byte 101 +.byte 108 +.byte 121 +.byte 32 +.byte 32 +.byte 37 +.byte 46 +.byte 55 +.byte 101 +.byte 44 +.byte 32 +.byte 32 +.byte 37 +.byte 46 +.byte 55 +.byte 101 +.byte 44 +.byte 32 +.byte 32 +.byte 37 +.byte 46 +.byte 55 +.byte 101 +.byte 44 +.byte 10 +.byte 0 +.align 0 +L.141: +.byte 68 +.byte 105 +.byte 115 +.byte 97 +.byte 103 +.byte 114 +.byte 101 +.byte 101 +.byte 109 +.byte 101 +.byte 110 +.byte 116 +.byte 115 +.byte 32 +.byte 97 +.byte 109 +.byte 111 +.byte 110 +.byte 103 +.byte 32 +.byte 116 +.byte 104 +.byte 101 +.byte 32 +.byte 118 +.byte 97 +.byte 108 +.byte 117 +.byte 101 +.byte 115 +.byte 32 +.byte 88 +.byte 49 +.byte 44 +.byte 32 +.byte 89 +.byte 49 +.byte 44 +.byte 32 +.byte 90 +.byte 49 +.byte 44 +.byte 10 +.byte 0 +.align 0 +L.119: +.byte 80 +.byte 114 +.byte 101 +.byte 99 +.byte 105 +.byte 115 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 119 +.byte 111 +.byte 114 +.byte 115 +.byte 101 +.byte 32 +.byte 116 +.byte 104 +.byte 97 +.byte 110 +.byte 32 +.byte 53 +.byte 32 +.byte 100 +.byte 101 +.byte 99 +.byte 105 +.byte 109 +.byte 97 +.byte 108 +.byte 32 +.byte 102 +.byte 105 +.byte 103 +.byte 117 +.byte 114 +.byte 101 +.byte 115 +.byte 32 +.byte 32 +.byte 0 +.align 0 +L.117: +.byte 84 +.byte 104 +.byte 101 +.byte 32 +.byte 110 +.byte 117 +.byte 109 +.byte 98 +.byte 101 +.byte 114 +.byte 32 +.byte 111 +.byte 102 +.byte 32 +.byte 115 +.byte 105 +.byte 103 +.byte 110 +.byte 105 +.byte 102 +.byte 105 +.byte 99 +.byte 97 +.byte 110 +.byte 116 +.byte 32 +.byte 100 +.byte 105 +.byte 103 +.byte 105 +.byte 116 +.byte 115 +.byte 32 +.byte 111 +.byte 102 +.byte 32 +.byte 116 +.byte 104 +.byte 101 +.byte 32 +.byte 82 +.byte 97 +.byte 100 +.byte 105 +.byte 120 +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 37 +.byte 102 +.byte 32 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.116: +.byte 108 +.byte 111 +.byte 103 +.byte 97 +.byte 114 +.byte 105 +.byte 116 +.byte 104 +.byte 109 +.byte 105 +.byte 99 +.byte 32 +.byte 101 +.byte 110 +.byte 99 +.byte 111 +.byte 100 +.byte 105 +.byte 110 +.byte 103 +.byte 32 +.byte 104 +.byte 97 +.byte 115 +.byte 32 +.byte 112 +.byte 114 +.byte 101 +.byte 99 +.byte 105 +.byte 115 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 99 +.byte 104 +.byte 97 +.byte 114 +.byte 97 +.byte 99 +.byte 116 +.byte 101 +.byte 114 +.byte 105 +.byte 122 +.byte 101 +.byte 100 +.byte 32 +.byte 115 +.byte 111 +.byte 108 +.byte 101 +.byte 108 +.byte 121 +.byte 32 +.byte 98 +.byte 121 +.byte 32 +.byte 85 +.byte 49 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.113: +.byte 111 +.byte 102 +.byte 32 +.byte 115 +.byte 105 +.byte 103 +.byte 110 +.byte 105 +.byte 102 +.byte 105 +.byte 99 +.byte 97 +.byte 110 +.byte 116 +.byte 32 +.byte 100 +.byte 105 +.byte 103 +.byte 105 +.byte 116 +.byte 115 +.byte 32 +.byte 98 +.byte 117 +.byte 116 +.byte 44 +.byte 32 +.byte 98 +.byte 121 +.byte 32 +.byte 105 +.byte 116 +.byte 115 +.byte 101 +.byte 108 +.byte 102 +.byte 44 +.byte 32 +.byte 116 +.byte 104 +.byte 105 +.byte 115 +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 97 +.byte 32 +.byte 109 +.byte 105 +.byte 110 +.byte 111 +.byte 114 +.byte 32 +.byte 102 +.byte 108 +.byte 97 +.byte 119 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.112: +.byte 80 +.byte 114 +.byte 101 +.byte 99 +.byte 105 +.byte 115 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 99 +.byte 97 +.byte 110 +.byte 110 +.byte 111 +.byte 116 +.byte 32 +.byte 98 +.byte 101 +.byte 32 +.byte 99 +.byte 104 +.byte 97 +.byte 114 +.byte 97 +.byte 99 +.byte 116 +.byte 101 +.byte 114 +.byte 105 +.byte 122 +.byte 101 +.byte 100 +.byte 32 +.byte 98 +.byte 121 +.byte 32 +.byte 97 +.byte 110 +.byte 32 +.byte 73 +.byte 110 +.byte 116 +.byte 101 +.byte 103 +.byte 101 +.byte 114 +.byte 32 +.byte 110 +.byte 117 +.byte 109 +.byte 98 +.byte 101 +.byte 114 +.byte 10 +.byte 0 +.align 0 +L.99: +.byte 67 +.byte 111 +.byte 109 +.byte 112 +.byte 97 +.byte 114 +.byte 105 +.byte 115 +.byte 111 +.byte 110 +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 102 +.byte 117 +.byte 122 +.byte 122 +.byte 121 +.byte 44 +.byte 88 +.byte 61 +.byte 49 +.byte 32 +.byte 98 +.byte 117 +.byte 116 +.byte 32 +.byte 88 +.byte 45 +.byte 49 +.byte 47 +.byte 50 +.byte 45 +.byte 49 +.byte 47 +.byte 50 +.byte 32 +.byte 33 +.byte 61 +.byte 32 +.byte 48 +.byte 0 +.align 0 +L.95: +.byte 40 +.byte 49 +.byte 45 +.byte 85 +.byte 49 +.byte 41 +.byte 45 +.byte 49 +.byte 47 +.byte 50 +.byte 32 +.byte 60 +.byte 32 +.byte 49 +.byte 47 +.byte 50 +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 70 +.byte 65 +.byte 76 +.byte 83 +.byte 69 +.byte 44 +.byte 32 +.byte 112 +.byte 114 +.byte 111 +.byte 103 +.byte 46 +.byte 32 +.byte 102 +.byte 97 +.byte 105 +.byte 108 +.byte 115 +.byte 63 +.byte 0 +.align 3 +L.93: +.word 0x40240000 +.word 0x0 +.align 0 +L.88: +.byte 82 +.byte 97 +.byte 100 +.byte 105 +.byte 120 +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 110 +.byte 111 +.byte 116 +.byte 32 +.byte 97 +.byte 115 +.byte 32 +.byte 103 +.byte 111 +.byte 111 +.byte 100 +.byte 32 +.byte 97 +.byte 115 +.byte 32 +.byte 50 +.byte 32 +.byte 111 +.byte 114 +.byte 32 +.byte 49 +.byte 48 +.byte 0 +.align 0 +L.84: +.byte 82 +.byte 97 +.byte 100 +.byte 105 +.byte 120 +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 116 +.byte 111 +.byte 111 +.byte 32 +.byte 98 +.byte 105 +.byte 103 +.byte 58 +.byte 32 +.byte 114 +.byte 111 +.byte 117 +.byte 110 +.byte 100 +.byte 111 +.byte 102 +.byte 102 +.byte 32 +.byte 112 +.byte 114 +.byte 111 +.byte 98 +.byte 108 +.byte 101 +.byte 109 +.byte 115 +.byte 0 +.align 0 +L.82: +.byte 77 +.byte 89 +.byte 83 +.byte 84 +.byte 69 +.byte 82 +.byte 89 +.byte 58 +.byte 32 +.byte 114 +.byte 101 +.byte 99 +.byte 97 +.byte 108 +.byte 99 +.byte 117 +.byte 108 +.byte 97 +.byte 116 +.byte 101 +.byte 100 +.byte 32 +.byte 82 +.byte 97 +.byte 100 +.byte 105 +.byte 120 +.byte 32 +.byte 61 +.byte 32 +.byte 37 +.byte 46 +.byte 55 +.byte 101 +.byte 32 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.81: +.byte 82 +.byte 97 +.byte 100 +.byte 105 +.byte 120 +.byte 32 +.byte 99 +.byte 111 +.byte 110 +.byte 102 +.byte 105 +.byte 114 +.byte 109 +.byte 101 +.byte 100 +.byte 46 +.byte 10 +.byte 0 +.align 3 +L.78: +.word 0x3f847ae1 +.word 0x47ae147b +.align 0 +L.77: +.byte 103 +.byte 101 +.byte 116 +.byte 115 +.byte 32 +.byte 98 +.byte 101 +.byte 116 +.byte 116 +.byte 101 +.byte 114 +.byte 32 +.byte 99 +.byte 108 +.byte 111 +.byte 115 +.byte 101 +.byte 115 +.byte 116 +.byte 32 +.byte 114 +.byte 101 +.byte 108 +.byte 97 +.byte 116 +.byte 105 +.byte 118 +.byte 101 +.byte 32 +.byte 115 +.byte 101 +.byte 112 +.byte 97 +.byte 114 +.byte 97 +.byte 116 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 85 +.byte 49 +.byte 32 +.byte 61 +.byte 32 +.byte 37 +.byte 46 +.byte 55 +.byte 101 +.byte 32 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.76: +.byte 99 +.byte 111 +.byte 110 +.byte 102 +.byte 105 +.byte 114 +.byte 109 +.byte 115 +.byte 32 +.byte 99 +.byte 108 +.byte 111 +.byte 115 +.byte 101 +.byte 115 +.byte 116 +.byte 32 +.byte 114 +.byte 101 +.byte 108 +.byte 97 +.byte 116 +.byte 105 +.byte 118 +.byte 101 +.byte 32 +.byte 115 +.byte 101 +.byte 112 +.byte 97 +.byte 114 +.byte 97 +.byte 116 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 85 +.byte 49 +.byte 32 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.61: +.byte 82 +.byte 101 +.byte 99 +.byte 97 +.byte 108 +.byte 99 +.byte 117 +.byte 108 +.byte 97 +.byte 116 +.byte 105 +.byte 110 +.byte 103 +.byte 32 +.byte 114 +.byte 97 +.byte 100 +.byte 105 +.byte 120 +.byte 32 +.byte 97 +.byte 110 +.byte 100 +.byte 32 +.byte 112 +.byte 114 +.byte 101 +.byte 99 +.byte 105 +.byte 115 +.byte 105 +.byte 111 +.byte 110 +.byte 10 +.byte 32 +.byte 0 +.align 0 +L.60: +.byte 67 +.byte 108 +.byte 111 +.byte 115 +.byte 101 +.byte 115 +.byte 116 +.byte 32 +.byte 114 +.byte 101 +.byte 108 +.byte 97 +.byte 116 +.byte 105 +.byte 118 +.byte 101 +.byte 32 +.byte 115 +.byte 101 +.byte 112 +.byte 97 +.byte 114 +.byte 97 +.byte 116 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 102 +.byte 111 +.byte 117 +.byte 110 +.byte 100 +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 85 +.byte 49 +.byte 32 +.byte 61 +.byte 32 +.byte 37 +.byte 46 +.byte 55 +.byte 101 +.byte 32 +.byte 46 +.byte 10 +.byte 10 +.byte 0 +.align 0 +L.54: +.byte 82 +.byte 97 +.byte 100 +.byte 105 +.byte 120 +.byte 32 +.byte 61 +.byte 32 +.byte 37 +.byte 102 +.byte 32 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.45: +.byte 83 +.byte 101 +.byte 97 +.byte 114 +.byte 99 +.byte 104 +.byte 105 +.byte 110 +.byte 103 +.byte 32 +.byte 102 +.byte 111 +.byte 114 +.byte 32 +.byte 82 +.byte 97 +.byte 100 +.byte 105 +.byte 120 +.byte 32 +.byte 97 +.byte 110 +.byte 100 +.byte 32 +.byte 80 +.byte 114 +.byte 101 +.byte 99 +.byte 105 +.byte 115 +.byte 105 +.byte 111 +.byte 110 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.44: +.byte 10 +.byte 0 +.align 0 +L.43: +.byte 45 +.byte 49 +.byte 44 +.byte 32 +.byte 48 +.byte 44 +.byte 32 +.byte 49 +.byte 47 +.byte 50 +.byte 44 +.byte 32 +.byte 49 +.byte 44 +.byte 32 +.byte 50 +.byte 44 +.byte 32 +.byte 51 +.byte 44 +.byte 32 +.byte 52 +.byte 44 +.byte 32 +.byte 53 +.byte 44 +.byte 32 +.byte 57 +.byte 44 +.byte 32 +.byte 50 +.byte 55 +.byte 44 +.byte 32 +.byte 51 +.byte 50 +.byte 32 +.byte 38 +.byte 32 +.byte 50 +.byte 52 +.byte 48 +.byte 32 +.byte 97 +.byte 114 +.byte 101 +.byte 32 +.byte 79 +.byte 46 +.byte 75 +.byte 46 +.byte 10 +.byte 0 +.align 0 +L.38: +.byte 53 +.byte 32 +.byte 33 +.byte 61 +.byte 32 +.byte 52 +.byte 43 +.byte 49 +.byte 44 +.byte 32 +.byte 50 +.byte 52 +.byte 48 +.byte 47 +.byte 51 +.byte 32 +.byte 33 +.byte 61 +.byte 32 +.byte 56 +.byte 48 +.byte 44 +.byte 32 +.byte 50 +.byte 52 +.byte 48 +.byte 47 +.byte 52 +.byte 32 +.byte 33 +.byte 61 +.byte 32 +.byte 54 +.byte 48 +.byte 44 +.byte 32 +.byte 111 +.byte 114 +.byte 32 +.byte 50 +.byte 52 +.byte 48 +.byte 47 +.byte 53 +.byte 32 +.byte 33 +.byte 61 +.byte 32 +.byte 52 +.byte 56 +.byte 0 +.align 0 +L.34: +.byte 57 +.byte 32 +.byte 33 +.byte 61 +.byte 32 +.byte 51 +.byte 42 +.byte 51 +.byte 44 +.byte 32 +.byte 50 +.byte 55 +.byte 32 +.byte 33 +.byte 61 +.byte 32 +.byte 57 +.byte 42 +.byte 51 +.byte 44 +.byte 32 +.byte 51 +.byte 50 +.byte 32 +.byte 33 +.byte 61 +.byte 32 +.byte 56 +.byte 42 +.byte 52 +.byte 44 +.byte 32 +.byte 111 +.byte 114 +.byte 32 +.byte 51 +.byte 50 +.byte 45 +.byte 50 +.byte 55 +.byte 45 +.byte 52 +.byte 45 +.byte 49 +.byte 32 +.byte 33 +.byte 61 +.byte 32 +.byte 48 +.byte 0 +.align 0 +L.30: +.byte 49 +.byte 47 +.byte 50 +.byte 32 +.byte 43 +.byte 32 +.byte 40 +.byte 45 +.byte 49 +.byte 41 +.byte 32 +.byte 43 +.byte 32 +.byte 49 +.byte 47 +.byte 50 +.byte 32 +.byte 33 +.byte 61 +.byte 32 +.byte 48 +.byte 0 +.align 0 +L.26: +.byte 45 +.byte 49 +.byte 43 +.byte 49 +.byte 32 +.byte 33 +.byte 61 +.byte 32 +.byte 48 +.byte 44 +.byte 32 +.byte 40 +.byte 45 +.byte 49 +.byte 41 +.byte 43 +.byte 97 +.byte 98 +.byte 115 +.byte 40 +.byte 49 +.byte 41 +.byte 32 +.byte 33 +.byte 61 +.byte 32 +.byte 48 +.byte 44 +.byte 32 +.byte 111 +.byte 114 +.byte 32 +.byte 45 +.byte 49 +.byte 43 +.byte 40 +.byte 45 +.byte 49 +.byte 41 +.byte 42 +.byte 40 +.byte 45 +.byte 49 +.byte 41 +.byte 32 +.byte 33 +.byte 61 +.byte 32 +.byte 48 +.byte 0 +.align 0 +L.22: +.byte 51 +.byte 32 +.byte 33 +.byte 61 +.byte 32 +.byte 50 +.byte 43 +.byte 49 +.byte 44 +.byte 32 +.byte 52 +.byte 32 +.byte 33 +.byte 61 +.byte 32 +.byte 51 +.byte 43 +.byte 49 +.byte 44 +.byte 32 +.byte 52 +.byte 43 +.byte 50 +.byte 42 +.byte 40 +.byte 45 +.byte 50 +.byte 41 +.byte 32 +.byte 33 +.byte 61 +.byte 32 +.byte 48 +.byte 44 +.byte 32 +.byte 111 +.byte 114 +.byte 32 +.byte 52 +.byte 45 +.byte 51 +.byte 45 +.byte 49 +.byte 32 +.byte 33 +.byte 61 +.byte 32 +.byte 48 +.byte 0 +.align 3 +L.20: +.word 0x3f50624d +.word 0xd2f1a9fc +.align 0 +L.19: +.byte 67 +.byte 111 +.byte 109 +.byte 112 +.byte 97 +.byte 114 +.byte 105 +.byte 115 +.byte 111 +.byte 110 +.byte 32 +.byte 97 +.byte 108 +.byte 108 +.byte 101 +.byte 103 +.byte 101 +.byte 115 +.byte 32 +.byte 116 +.byte 104 +.byte 97 +.byte 116 +.byte 32 +.byte 45 +.byte 48 +.byte 46 +.byte 48 +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 78 +.byte 111 +.byte 110 +.byte 45 +.byte 122 +.byte 101 +.byte 114 +.byte 111 +.byte 33 +.byte 10 +.byte 0 +.align 0 +L.14: +.byte 48 +.byte 43 +.byte 48 +.byte 32 +.byte 33 +.byte 61 +.byte 32 +.byte 48 +.byte 44 +.byte 32 +.byte 49 +.byte 45 +.byte 49 +.byte 32 +.byte 33 +.byte 61 +.byte 32 +.byte 48 +.byte 44 +.byte 32 +.byte 49 +.byte 32 +.byte 60 +.byte 61 +.byte 32 +.byte 48 +.byte 44 +.byte 32 +.byte 111 +.byte 114 +.byte 32 +.byte 49 +.byte 43 +.byte 49 +.byte 32 +.byte 33 +.byte 61 +.byte 32 +.byte 50 +.byte 0 +.align 0 +L.12: +.byte 80 +.byte 114 +.byte 111 +.byte 103 +.byte 114 +.byte 97 +.byte 109 +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 110 +.byte 111 +.byte 119 +.byte 32 +.byte 82 +.byte 85 +.byte 78 +.byte 78 +.byte 73 +.byte 78 +.byte 71 +.byte 32 +.byte 116 +.byte 101 +.byte 115 +.byte 116 +.byte 115 +.byte 32 +.byte 111 +.byte 110 +.byte 32 +.byte 115 +.byte 109 +.byte 97 +.byte 108 +.byte 108 +.byte 32 +.byte 105 +.byte 110 +.byte 116 +.byte 101 +.byte 103 +.byte 101 +.byte 114 +.byte 115 +.byte 58 +.byte 10 +.byte 0 +.align 3 +L.8: +.word 0x3ff00000 +.word 0x0 +.align 3 +L.7: +.word 0x0 +.word 0x0 +.align 0 +L.2: +.byte 10 +.byte 42 +.byte 32 +.byte 42 +.byte 32 +.byte 42 +.byte 32 +.byte 70 +.byte 76 +.byte 79 +.byte 65 +.byte 84 +.byte 73 +.byte 78 +.byte 71 +.byte 45 +.byte 80 +.byte 79 +.byte 73 +.byte 78 +.byte 84 +.byte 32 +.byte 69 +.byte 82 +.byte 82 +.byte 79 +.byte 82 +.byte 32 +.byte 42 +.byte 32 +.byte 42 +.byte 32 +.byte 42 +.byte 10 +.byte 0 diff --git a/src/cmd/lccom/tst/mips-eb/setjmp.h b/src/cmd/lccom/tst/mips-eb/setjmp.h new file mode 100644 index 0000000..7d9edad --- /dev/null +++ b/src/cmd/lccom/tst/mips-eb/setjmp.h @@ -0,0 +1,11 @@ +#ifndef __SETJMP +#define __SETJMP + + + + +typedef int jmp_buf[28]; +int setjmp(jmp_buf); +void longjmp(jmp_buf, int); + +#endif /* __SETJMP */ diff --git a/src/cmd/lccom/tst/mips-eb/signal.h b/src/cmd/lccom/tst/mips-eb/signal.h new file mode 100644 index 0000000..c208a6b --- /dev/null +++ b/src/cmd/lccom/tst/mips-eb/signal.h @@ -0,0 +1,20 @@ +#ifndef __SIGNAL +#define __SIGNAL + +typedef int sig_atomic_t; + +#define SIG_DFL ((void (*)(int))0) +#define SIG_ERR ((void (*)(int))-1) +#define SIG_IGN ((void (*)(int))1) + +#define SIGABRT 6 +#define SIGFPE 8 +#define SIGILL 4 +#define SIGINT 2 +#define SIGSEGV 11 +#define SIGTERM 15 + +void (*signal(int, void (*)(int)))(int); +int raise(int); + +#endif /* __SIGNAL */ diff --git a/src/cmd/lccom/tst/mips-eb/sort.1bk b/src/cmd/lccom/tst/mips-eb/sort.1bk new file mode 100644 index 0000000..75e1f0d --- /dev/null +++ b/src/cmd/lccom/tst/mips-eb/sort.1bk @@ -0,0 +1,20 @@ +exchange(1,9) +exchange(3,7) +exchange(5,6) +exchange(0,5) +exchange(0,3) +exchange(0,0) +exchange(1,2) +exchange(6,6) +exchange(8,9) +exchange(7,8) +-51 +-1 +0 +1 +3 +10 +18 +32 +567 +789 diff --git a/src/cmd/lccom/tst/mips-eb/sort.2bk b/src/cmd/lccom/tst/mips-eb/sort.2bk new file mode 100644 index 0000000..81e6f38 --- /dev/null +++ b/src/cmd/lccom/tst/mips-eb/sort.2bk @@ -0,0 +1,5 @@ +tst/sort.c:23: warning: missing return value +tst/sort.c:30: warning: missing return value +tst/sort.c:37: warning: missing return value +tst/sort.c:41: warning: missing return value +tst/sort.c:65: warning: missing return value diff --git a/src/cmd/lccom/tst/mips-eb/sort.sbk b/src/cmd/lccom/tst/mips-eb/sort.sbk new file mode 100644 index 0000000..5fd5de4 --- /dev/null +++ b/src/cmd/lccom/tst/mips-eb/sort.sbk @@ -0,0 +1,309 @@ +.set reorder +.globl in +.data +.align 2 +in: +.word 0xa +.word 0x20 +.word 0xffffffff +.word 0x237 +.word 0x3 +.word 0x12 +.word 0x1 +.word 0xffffffcd +.word 0x315 +.word 0x0 +.globl main +.text +.text +.align 2 +.ent main +main: +.frame $sp,32,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-32 +.mask 0xc2000000,-8 +.cprestore 16 +sw $30,20($sp) +sw $31,24($sp) +la $4,in +la $5,10 +jal sort +move $30,$0 +b L.5 +L.2: +sll $24,$30,2 +lw $4,in($24) +jal putd +la $4,10 +jal putchar +L.3: +la $30,1($30) +L.5: +move $24,$30 +la $15,10 +bltu $24,$15,L.2 +move $2,$0 +L.1: +lw $25,16($sp) +lw $30,20($sp) +lw $31,24($sp) +addu $sp,$sp,32 +j $31 +.end main +.globl putd +.text +.align 2 +.ent putd +putd: +.frame $sp,32,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-32 +.mask 0xc2000000,-8 +.cprestore 16 +sw $30,20($sp) +sw $31,24($sp) +move $30,$4 +bge $30,$0,L.7 +la $4,45 +jal putchar +negu $30,$30 +L.7: +la $24,10 +div $24,$30,$24 +beq $24,$0,L.9 +la $24,10 +div $4,$30,$24 +jal putd +L.9: +la $24,10 +rem $24,$30,$24 +la $4,48($24) +jal putchar +move $2,$0 +L.6: +lw $25,16($sp) +lw $30,20($sp) +lw $31,24($sp) +addu $sp,$sp,32 +j $31 +.end putd +.globl sort +.text +.align 2 +.ent sort +sort: +.frame $sp,32,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-32 +.mask 0x82000000,-12 +.cprestore 16 +sw $31,20($sp) +sw $4,32($sp) +sw $5,36($sp) +lw $24,0+32($sp) +sw $24,xx +move $4,$24 +move $5,$0 +lw $24,4+32($sp) +subu $24,$24,1 +sw $24,4+32($sp) +move $6,$24 +jal quick +move $2,$0 +L.11: +lw $25,16($sp) +lw $31,20($sp) +addu $sp,$sp,32 +j $31 +.end sort +.globl quick +.text +.align 2 +.ent quick +quick: +.frame $sp,48,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-48 +.mask 0xc2e00000,-12 +sw $21,16($sp) +sw $22,20($sp) +sw $23,24($sp) +.cprestore 28 +sw $30,32($sp) +sw $31,36($sp) +move $30,$4 +move $23,$5 +move $22,$6 +blt $23,$22,L.13 +move $2,$0 +b L.12 +L.13: +move $4,$30 +move $5,$23 +move $6,$22 +jal partition +move $21,$2 +move $4,$30 +move $5,$23 +subu $6,$21,1 +jal quick +move $4,$30 +la $5,1($21) +move $6,$22 +jal quick +move $2,$0 +L.12: +lw $21,16($sp) +lw $22,20($sp) +lw $23,24($sp) +lw $25,28($sp) +lw $30,32($sp) +lw $31,36($sp) +addu $sp,$sp,48 +j $31 +.end quick +.globl partition +.text +.align 2 +.ent partition +partition: +.frame $sp,48,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-48 +.mask 0xc2f00000,-8 +sw $20,16($sp) +sw $21,20($sp) +sw $22,24($sp) +sw $23,28($sp) +.cprestore 32 +sw $30,36($sp) +sw $31,40($sp) +move $30,$4 +move $23,$5 +move $22,$6 +la $22,1($22) +move $20,$23 +sll $24,$20,2 +addu $24,$24,$30 +lw $21,($24) +b L.17 +L.16: +la $23,1($23) +b L.20 +L.19: +la $23,1($23) +L.20: +sll $24,$23,2 +addu $24,$24,$30 +lw $24,($24) +blt $24,$21,L.19 +subu $22,$22,1 +b L.23 +L.22: +subu $22,$22,1 +L.23: +sll $24,$22,2 +addu $24,$24,$30 +lw $24,($24) +bgt $24,$21,L.22 +bge $23,$22,L.25 +sll $24,$23,2 +addu $4,$24,$30 +sll $24,$22,2 +addu $5,$24,$30 +jal exchange +L.25: +L.17: +blt $23,$22,L.16 +sll $24,$20,2 +addu $4,$24,$30 +sll $24,$22,2 +addu $5,$24,$30 +jal exchange +move $2,$22 +L.15: +lw $20,16($sp) +lw $21,20($sp) +lw $22,24($sp) +lw $23,28($sp) +lw $25,32($sp) +lw $30,36($sp) +lw $31,40($sp) +addu $sp,$sp,48 +j $31 +.end partition +.globl exchange +.text +.align 2 +.ent exchange +exchange: +.frame $sp,48,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-48 +.mask 0xc2800000,-20 +sw $23,16($sp) +.cprestore 20 +sw $30,24($sp) +sw $31,28($sp) +move $30,$4 +move $23,$5 +la $4,L.28 +lw $24,xx +la $15,4 +move $14,$30 +subu $14,$14,$24 +div $5,$14,$15 +move $14,$23 +subu $24,$14,$24 +div $6,$24,$15 +jal printf +lw $24,($30) +sw $24,-4+48($sp) +lw $24,($23) +sw $24,($30) +lw $24,-4+48($sp) +sw $24,($23) +move $2,$0 +L.27: +lw $23,16($sp) +lw $25,20($sp) +lw $30,24($sp) +lw $31,28($sp) +addu $sp,$sp,48 +j $31 +.end exchange +.globl xx +.comm xx,4 +.rdata +.align 0 +L.28: +.byte 101 +.byte 120 +.byte 99 +.byte 104 +.byte 97 +.byte 110 +.byte 103 +.byte 101 +.byte 40 +.byte 37 +.byte 100 +.byte 44 +.byte 37 +.byte 100 +.byte 41 +.byte 10 +.byte 0 diff --git a/src/cmd/lccom/tst/mips-eb/spill.2bk b/src/cmd/lccom/tst/mips-eb/spill.2bk new file mode 100644 index 0000000..afd73e2 --- /dev/null +++ b/src/cmd/lccom/tst/mips-eb/spill.2bk @@ -0,0 +1,6 @@ +tst/spill.c:1: warning: missing return value +tst/spill.c:3: warning: missing return value +tst/spill.c:5: warning: missing return value +tst/spill.c:7: warning: missing return value +tst/spill.c:9: warning: missing return value +tst/spill.c:17: warning: missing return value diff --git a/src/cmd/lccom/tst/mips-eb/spill.sbk b/src/cmd/lccom/tst/mips-eb/spill.sbk new file mode 100644 index 0000000..274f01f --- /dev/null +++ b/src/cmd/lccom/tst/mips-eb/spill.sbk @@ -0,0 +1,271 @@ +.set reorder +.globl main +.text +.text +.align 2 +.ent main +main: +.frame $sp,0,$31 +.set noreorder +.cpload $25 +.set reorder +move $2,$0 +L.1: +j $31 +.end main +.globl f +.text +.align 2 +.ent f +f: +.frame $sp,32,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-32 +.mask 0x82000000,-12 +.cprestore 16 +sw $31,20($sp) +sw $4,32($sp) +jal f +move $24,$2 +sw $24,-4+32($sp) +jal f +lw $15,-4+32($sp) +addu $24,$15,$2 +sw $24,0+32($sp) +move $2,$0 +L.2: +lw $25,16($sp) +lw $31,20($sp) +addu $sp,$sp,32 +j $31 +.end f +.globl f2 +.text +.align 2 +.ent f2 +f2: +.frame $sp,32,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-32 +.mask 0xc2000000,-8 +.cprestore 16 +sw $30,20($sp) +sw $31,24($sp) +sw $4,32($sp) +jal f +move $24,$2 +sw $24,-4+32($sp) +lw $15,0+32($sp) +beq $15,$0,L.5 +jal f +move $24,$2 +move $30,$24 +b L.6 +L.5: +la $30,1 +L.6: +lw $24,-4+32($sp) +addu $24,$24,$30 +sw $24,0+32($sp) +move $2,$0 +L.3: +lw $25,16($sp) +lw $30,20($sp) +lw $31,24($sp) +addu $sp,$sp,32 +j $31 +.end f2 +.globl f3 +.text +.align 2 +.ent f3 +f3: +.frame $sp,80,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-80 +.mask 0xc2ff0000,-24 +sw $16,16($sp) +sw $17,20($sp) +sw $18,24($sp) +sw $19,28($sp) +sw $20,32($sp) +sw $21,36($sp) +sw $22,40($sp) +sw $23,44($sp) +.cprestore 48 +sw $30,52($sp) +sw $31,56($sp) +sw $4,80($sp) +sw $5,84($sp) +move $30,$0 +move $23,$0 +move $22,$0 +move $21,$0 +move $20,$0 +move $19,$0 +move $18,$0 +move $17,$0 +move $16,$0 +sw $0,-4+80($sp) +lw $24,4+80($sp) +sw $24,-12+80($sp) +la $15,4($24) +sw $15,4+80($sp) +lw $15,0+80($sp) +beq $15,$0,L.9 +jal f +move $24,$2 +sw $24,-8+80($sp) +b L.10 +L.9: +sw $0,-8+80($sp) +L.10: +lw $24,-8+80($sp) +lw $15,-12+80($sp) +sw $24,($15) +move $2,$0 +L.7: +lw $16,16($sp) +lw $17,20($sp) +lw $18,24($sp) +lw $19,28($sp) +lw $20,32($sp) +lw $21,36($sp) +lw $22,40($sp) +lw $23,44($sp) +lw $25,48($sp) +lw $30,52($sp) +lw $31,56($sp) +addu $sp,$sp,80 +j $31 +.end f3 +.globl f4 +.text +.align 2 +.ent f4 +f4: +.frame $sp,32,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-32 +.mask 0x40fc0000,-8 +sw $18,0($sp) +sw $19,4($sp) +sw $20,8($sp) +sw $21,12($sp) +sw $22,16($sp) +sw $23,20($sp) +sw $30,24($sp) +move $30,$0 +move $23,$0 +move $22,$0 +move $21,$0 +move $20,$0 +move $19,$0 +lw $24,i +sll $15,$24,3 +l.d $f18,a($15) +l.d $f16,b($15) +l.d $f10,L.15 +add.d $f8,$f18,$f16 +c.eq.d $f8,$f10; bc1t L.13 +beq $24,$0,L.13 +sub.d $f18,$f18,$f16 +c.eq.d $f18,$f10; bc1t L.13 +la $18,1 +b L.14 +L.13: +move $18,$0 +L.14: +sw $18,i +move $2,$0 +L.11: +lw $18,0($sp) +lw $19,4($sp) +lw $20,8($sp) +lw $21,12($sp) +lw $22,16($sp) +lw $23,20($sp) +lw $30,24($sp) +addu $sp,$sp,32 +j $31 +.end f4 +.globl f5 +.text +.align 2 +.ent f5 +f5: +.frame $sp,0,$31 +.set noreorder +.cpload $25 +.set reorder +lw $24,k +lw $15,m +lw $14,A +mul $13,$24,$15 +sll $13,$13,3 +addu $13,$13,$14 +lw $12,j +mul $15,$12,$15 +sll $15,$15,3 +addu $15,$15,$14 +lw $14,n +lw $11,B +mul $24,$24,$14 +sll $24,$24,3 +addu $24,$24,$11 +mul $14,$12,$14 +sll $14,$14,3 +addu $14,$14,$11 +l.d $f18,($13) +l.d $f16,($15) +mul.d $f18,$f18,$f16 +l.d $f16,($24) +l.d $f10,($14) +mul.d $f16,$f16,$f10 +add.d $f18,$f18,$f16 +s.d $f18,x +l.d $f18,($13) +l.d $f16,($14) +mul.d $f18,$f18,$f16 +l.d $f16,($24) +l.d $f10,($15) +mul.d $f16,$f16,$f10 +sub.d $f18,$f18,$f16 +s.d $f18,x +move $2,$0 +L.16: +j $31 +.end f5 +.globl x +.comm x,8 +.globl B +.comm B,4 +.globl A +.comm A,4 +.globl n +.comm n,4 +.globl m +.comm m,4 +.globl k +.comm k,4 +.globl j +.comm j,4 +.globl i +.comm i,4 +.globl b +.comm b,80 +.globl a +.comm a,80 +.rdata +.align 3 +L.15: +.word 0x0 +.word 0x0 diff --git a/src/cmd/lccom/tst/mips-eb/stdarg.1bk b/src/cmd/lccom/tst/mips-eb/stdarg.1bk new file mode 100644 index 0000000..e973176 --- /dev/null +++ b/src/cmd/lccom/tst/mips-eb/stdarg.1bk @@ -0,0 +1,6 @@ +test 1 +test 2 +test 3 +test 4 +test 5.000000 +{1 2 3 4} {1 2 3 4} {1 2 3 4} {1 2 3 4} {1 2 3 4} {1 2 3 4} diff --git a/src/cmd/lccom/tst/mips-eb/stdarg.2bk b/src/cmd/lccom/tst/mips-eb/stdarg.2bk new file mode 100644 index 0000000..2b3f417 --- /dev/null +++ b/src/cmd/lccom/tst/mips-eb/stdarg.2bk @@ -0,0 +1 @@ +tst/stdarg.c:51: warning: missing return value diff --git a/src/cmd/lccom/tst/mips-eb/stdarg.h b/src/cmd/lccom/tst/mips-eb/stdarg.h new file mode 100644 index 0000000..e838c2b --- /dev/null +++ b/src/cmd/lccom/tst/mips-eb/stdarg.h @@ -0,0 +1,27 @@ +#ifndef __STDARG +#define __STDARG + +#if !defined(_VA_LIST) && !defined(__VA_LIST_DEFINED) +#define _VA_LIST +#define _VA_LIST_DEFINED +typedef char *__va_list; +#endif +static float __va_arg_tmp; +typedef __va_list va_list; + +#define va_start(list, start) ((void)((list) = (sizeof(start)<4 ? \ + (char *)((int *)&(start)+1) : (char *)(&(start)+1)))) +#define __va_arg(list, mode, n) (\ + __typecode(mode)==1 && sizeof(mode)==4 ? \ + (__va_arg_tmp = *(double *)(&(list += ((sizeof(double)+n)&~n))[-(int)((sizeof(double)+n)&~n)]), \ + *(mode *)&__va_arg_tmp) : \ + *(mode *)(&(list += ((sizeof(mode)+n)&~n))[-(int)((sizeof(mode)+n)&~n)])) +#define _bigendian_va_arg(list, mode, n) (\ + sizeof(mode)==1 ? *(mode *)(&(list += 4)[-1]) : \ + sizeof(mode)==2 ? *(mode *)(&(list += 4)[-2]) : __va_arg(list, mode, n)) +#define _littleendian_va_arg(list, mode, n) __va_arg(list, mode, n) +#define va_end(list) ((void)0) +#define va_arg(list, mode) (sizeof(mode)==8 ? \ + *(mode *)(&(list = (char*)(((int)list + 15)&~7U))[-8]) : \ + _bigendian_va_arg(list, mode, 3U)) +#endif diff --git a/src/cmd/lccom/tst/mips-eb/stdarg.sbk b/src/cmd/lccom/tst/mips-eb/stdarg.sbk new file mode 100644 index 0000000..477ab8e --- /dev/null +++ b/src/cmd/lccom/tst/mips-eb/stdarg.sbk @@ -0,0 +1,396 @@ +.set reorder +.globl x +.data +.align 2 +x: +.word 0x1 +.word 0x2 +.word 0x3 +.word 0x4 +.globl main +.text +.text +.align 2 +.ent main +main: +.frame $sp,112,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-112 +.mask 0x82000000,-8 +.cprestore 100 +sw $31,104($sp) +la $4,L.2 +jal print +la $4,L.3 +la $5,L.4 +jal print +la $4,L.5 +la $5,3 +la $6,10 +jal print +la $4,L.6 +la $5,L.7 +la $6,L.8 +la $7,4 +la $24,10 +sw $24,16($sp) +jal print +la $4,L.9 +la $5,L.7 +la $6,L.8 +l.d $f18,L.10 +s.d $f18,16($sp) +la $24,10 +sw $24,24($sp) +jal print +la $4,L.11 +la $24,x +move $8,$24 +lw $3,0($8) +lw $9,4($8) +sw $3,4($29) +sw $9,8($29) +lw $3,8($8) +lw $9,12($8) +sw $3,12($29) +sw $9,16($29) +lw $5,4($sp) +lw $6,8($sp) +lw $7,12($sp) +move $8,$24 +lw $3,0($8) +lw $9,4($8) +sw $3,20($29) +sw $9,24($29) +lw $3,8($8) +lw $9,12($8) +sw $3,28($29) +sw $9,32($29) +move $8,$24 +lw $3,0($8) +lw $9,4($8) +sw $3,36($29) +sw $9,40($29) +lw $3,8($8) +lw $9,12($8) +sw $3,44($29) +sw $9,48($29) +move $8,$24 +lw $3,0($8) +lw $9,4($8) +sw $3,52($29) +sw $9,56($29) +lw $3,8($8) +lw $9,12($8) +sw $3,60($29) +sw $9,64($29) +move $8,$24 +lw $3,0($8) +lw $9,4($8) +sw $3,68($29) +sw $9,72($29) +lw $3,8($8) +lw $9,12($8) +sw $3,76($29) +sw $9,80($29) +move $8,$24 +lw $3,0($8) +lw $9,4($8) +sw $3,84($29) +sw $9,88($29) +lw $3,8($8) +lw $9,12($8) +sw $3,92($29) +sw $9,96($29) +jal print +move $2,$0 +L.1: +lw $25,100($sp) +lw $31,104($sp) +addu $sp,$sp,112 +j $31 +.end main +.globl print +.text +.align 2 +.ent print +print: +.frame $sp,64,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-64 +.mask 0xc2800000,-32 +sw $23,20($sp) +.cprestore 24 +sw $30,28($sp) +sw $31,32($sp) +sw $4,64($sp) +sw $5,68($sp) +sw $6,72($sp) +sw $7,76($sp) +la $30,4+64($sp) +b L.18 +L.15: +lw $24,0+64($sp) +lb $24,($24) +la $15,37 +bne $24,$15,L.19 +lw $24,0+64($sp) +la $24,1($24) +sw $24,0+64($sp) +lb $23,($24) +la $24,115 +beq $23,$24,L.35 +bgt $23,$24,L.40 +L.39: +la $24,98 +blt $23,$24,L.21 +la $24,102 +bgt $23,$24,L.21 +sll $24,$23,2 +lw $24,L.41-392($24) +.cpadd $24 +j $24 +.rdata +.align 2 +L.41: +.gpword L.24 +.gpword L.29 +.gpword L.31 +.gpword L.21 +.gpword L.37 +.text +L.40: +la $24,119 +beq $23,$24,L.33 +b L.21 +L.24: +la $24,16($30) +move $30,$24 +la $15,-16+64($sp) +la $8,-16($24) +lw $3,0($8) +lw $9,4($8) +sw $3,0($15) +sw $9,4($15) +lw $3,8($8) +lw $9,12($8) +sw $3,8($15) +sw $9,12($15) +la $4,L.25 +lw $5,-16+64($sp) +lw $6,-12+64($sp) +lw $7,-8+64($sp) +lw $24,-4+64($sp) +sw $24,16($sp) +jal printf +b L.20 +L.29: +la $4,L.30 +la $24,4($30) +move $30,$24 +lb $5,-1($24) +jal printf +b L.20 +L.31: +la $4,L.32 +la $24,4($30) +move $30,$24 +lw $5,-4($24) +jal printf +b L.20 +L.33: +la $4,L.34 +la $24,4($30) +move $30,$24 +lh $5,-2($24) +jal printf +b L.20 +L.35: +la $4,L.36 +la $24,4($30) +move $30,$24 +lw $5,-4($24) +jal printf +b L.20 +L.37: +la $4,L.38 +move $24,$30 +la $24,15($24) +and $24,$24,0xfffffff8 +move $30,$24 +l.d $f18,-8($24) +mfc1.d $6,$f18 +jal printf +b L.20 +L.21: +la $4,L.30 +lw $24,0+64($sp) +lb $5,($24) +jal printf +b L.20 +L.19: +la $4,L.30 +lw $24,0+64($sp) +lb $5,($24) +jal printf +L.20: +L.16: +lw $24,0+64($sp) +la $24,1($24) +sw $24,0+64($sp) +L.18: +lw $24,0+64($sp) +lb $24,($24) +bne $24,$0,L.15 +move $2,$0 +L.12: +lw $23,20($sp) +lw $25,24($sp) +lw $30,28($sp) +lw $31,32($sp) +addu $sp,$sp,64 +j $31 +.end print +.lcomm __va_arg_tmp,4 +.rdata +.align 0 +L.38: +.byte 37 +.byte 102 +.byte 0 +.align 0 +L.36: +.byte 37 +.byte 115 +.byte 0 +.align 0 +L.34: +.byte 37 +.byte 120 +.byte 0 +.align 0 +L.32: +.byte 37 +.byte 100 +.byte 0 +.align 0 +L.30: +.byte 37 +.byte 99 +.byte 0 +.align 0 +L.25: +.byte 123 +.byte 37 +.byte 100 +.byte 32 +.byte 37 +.byte 100 +.byte 32 +.byte 37 +.byte 100 +.byte 32 +.byte 37 +.byte 100 +.byte 125 +.byte 0 +.align 0 +L.11: +.byte 37 +.byte 98 +.byte 32 +.byte 37 +.byte 98 +.byte 32 +.byte 37 +.byte 98 +.byte 32 +.byte 37 +.byte 98 +.byte 32 +.byte 37 +.byte 98 +.byte 32 +.byte 37 +.byte 98 +.byte 10 +.byte 0 +.align 3 +L.10: +.word 0x40140000 +.word 0x0 +.align 0 +L.9: +.byte 37 +.byte 115 +.byte 37 +.byte 115 +.byte 32 +.byte 37 +.byte 102 +.byte 37 +.byte 99 +.byte 0 +.align 0 +L.8: +.byte 115 +.byte 116 +.byte 0 +.align 0 +L.7: +.byte 116 +.byte 101 +.byte 0 +.align 0 +L.6: +.byte 37 +.byte 115 +.byte 37 +.byte 115 +.byte 32 +.byte 37 +.byte 119 +.byte 37 +.byte 99 +.byte 0 +.align 0 +L.5: +.byte 116 +.byte 101 +.byte 115 +.byte 116 +.byte 32 +.byte 37 +.byte 100 +.byte 37 +.byte 99 +.byte 0 +.align 0 +L.4: +.byte 50 +.byte 0 +.align 0 +L.3: +.byte 116 +.byte 101 +.byte 115 +.byte 116 +.byte 32 +.byte 37 +.byte 115 +.byte 10 +.byte 0 +.align 0 +L.2: +.byte 116 +.byte 101 +.byte 115 +.byte 116 +.byte 32 +.byte 49 +.byte 10 +.byte 0 diff --git a/src/cmd/lccom/tst/mips-eb/stddef.h b/src/cmd/lccom/tst/mips-eb/stddef.h new file mode 100644 index 0000000..34fcc82 --- /dev/null +++ b/src/cmd/lccom/tst/mips-eb/stddef.h @@ -0,0 +1,35 @@ +#ifndef __STDDEF +#define __STDDEF + +/* $Id: stddef.h,v 1.1 2002/08/28 23:59:59 drh Exp $ */ + +#ifndef NULL +#define NULL ((void*)0) +#endif +#define offsetof(ty,mem) ((size_t)((char*)&((ty*)0)->mem - (char*)0)) + +typedef long ptrdiff_t; + +#if !defined(_SIZE_T) && !defined(_SIZE_T_) && !defined(_SIZE_T_DEFINED) +#define _SIZE_T +#define _SIZE_T_ +#define _SIZE_T_DEFINED +typedef unsigned long size_t; +#endif + +#if !defined(_WCHAR_T) && !defined(_WCHAR_T_) && !defined(_WCHAR_T_DEFINED) +#define _WCHAR_T +#define _WCHAR_T_ +#define _WCHAR_T_DEFINED +#if (_WCHAR_T_SIZE + 0) == 1 +typedef unsigned char wchar_t; +#elif (_WCHAR_T_SIZE + 0) == 2 +typedef unsigned short wchar_t; +#elif (_WCHAR_T_SIZE + 0) == 4 +typedef unsigned int wchar_t; +#else +typedef unsigned short wchar_t; +#endif +#endif + +#endif /* __STDDEF */ diff --git a/src/cmd/lccom/tst/mips-eb/stdio.h b/src/cmd/lccom/tst/mips-eb/stdio.h new file mode 100644 index 0000000..63fe5c2 --- /dev/null +++ b/src/cmd/lccom/tst/mips-eb/stdio.h @@ -0,0 +1,102 @@ +#ifndef __STDIO +#define __STDIO + +#define _IOFBF 0 +#define _IOLBF 0100 +#define _IONBF 04 +#define BUFSIZ 1024 +#define EOF (-1) + +extern struct _iobuf { + int _cnt; + unsigned char *_ptr; + unsigned char *_base; + char _flag; + char _file; +} _iob[]; +#define FILE struct _iobuf +#define FILENAME_MAX 256 +#define FOPEN_MAX 100 + +#if !defined(_FPOS_T) && !defined(_FPOS_T_) && !defined(_FPOS_T_DEFINED) +#define _FPOS_T +#define _FPOS_T_ +#define _FPOS_T_DEFINED +typedef long fpos_t; +#endif + +#define L_tmpnam 25 +#ifndef NULL +#define NULL ((void*)0) +#endif +#define SEEK_CUR 1 +#define SEEK_END 2 +#define SEEK_SET 0 + +#if !defined(_SIZE_T) && !defined(_SIZE_T_) && !defined(_SIZE_T_DEFINED) +#define _SIZE_T +#define _SIZE_T_ +#define _SIZE_T_DEFINED +typedef unsigned long size_t; +#endif + +#if !defined(_VA_LIST) && !defined(_VA_LIST_DEFINED) +#define _VA_LIST +#define _VA_LIST_DEFINED +typedef char *__va_list; +#endif + +#define stderr (&_iob[2]) +#define stdin (&_iob[0]) +#define stdout (&_iob[1]) +#define TMP_MAX 17576 + +extern int remove(const char *); +extern int rename(const char *, const char *); +extern FILE *tmpfile(void); +extern char *tmpnam(char *); +extern int fclose(FILE *); +extern int fflush(FILE *); +extern FILE *fopen(const char *, const char *); +extern FILE *freopen(const char *, const char *, FILE *); +extern void setbuf(FILE *, char *); +extern int setvbuf(FILE *, char *, int, size_t); +extern int fprintf(FILE *, const char *, ...); +extern int fscanf(FILE *, const char *, ...); +extern int printf(const char *, ...); +extern int scanf(const char *, ...); +extern int sprintf(char *, const char *, ...); +extern int sscanf(const char *, const char *, ...); +extern int vfprintf(FILE *, const char *, __va_list); +extern int vprintf(const char *, __va_list); +extern int vsprintf(char *, const char *, __va_list); +extern int fgetc(FILE *); +extern char *fgets(char *, int, FILE *); +extern int fputc(int, FILE *); +extern int fputs(const char *, FILE *); +extern int getc(FILE *); +extern int getchar(void); +extern char *gets(char *); +extern int putc(int, FILE *); +extern int putchar(int); +extern int puts(const char *); +extern int ungetc(int, FILE *); +extern size_t fread(void *, size_t, size_t, FILE *); +extern size_t fwrite(const void *, size_t, size_t, FILE *); +extern int fgetpos(FILE *, fpos_t *); +extern int fseek(FILE *, long int, int); +extern int fsetpos(FILE *, const fpos_t *); +extern long int ftell(FILE *); +extern void rewind(FILE *); +extern void clearerr(FILE *); +extern int feof(FILE *); +extern int ferror(FILE *); +extern void perror(const char *); + +#define _IOEOF 020 +#define _IOERR 040 + +#define getc(p) (--(p)->_cnt < 0 ? _filbuf(p) : (int) *(p)->_ptr++) +#define putc(x, p) (--(p)->_cnt < 0 ? _flsbuf((unsigned char) (x), p) : (int) (*(p)->_ptr++ = (unsigned char) (x))) +extern int _filbuf(FILE *), _flsbuf(unsigned, FILE *); +#endif /* __STDIO */ diff --git a/src/cmd/lccom/tst/mips-eb/stdlib.h b/src/cmd/lccom/tst/mips-eb/stdlib.h new file mode 100644 index 0000000..e8ce3f4 --- /dev/null +++ b/src/cmd/lccom/tst/mips-eb/stdlib.h @@ -0,0 +1,66 @@ +#ifndef __STDLIB +#define __STDLIB + +#define EXIT_FAILURE 1 +#define EXIT_SUCCESS 0 +#define MB_CUR_MAX 1 +#ifndef NULL +#define NULL ((void*)0) +#endif +#define RAND_MAX 32767 + +typedef struct { int quot, rem; } div_t; +typedef struct { long quot, rem; } ldiv_t; + +#if !defined(_SIZE_T) && !defined(_SIZE_T_) && !defined(_SIZE_T_DEFINED) +#define _SIZE_T +#define _SIZE_T_ +#define _SIZE_T_DEFINED +typedef unsigned long size_t; +#endif + +#if !defined(_WCHAR_T) && !defined(_WCHAR_T_) && !defined(_WCHAR_T_DEFINED) +#define _WCHAR_T +#define _WCHAR_T_ +#define _WCHAR_T_DEFINED +#if (_WCHAR_T_SIZE + 0) == 1 +typedef unsigned char wchar_t; +#elif (_WCHAR_T_SIZE + 0) == 2 +typedef unsigned short wchar_t; +#elif (_WCHAR_T_SIZE + 0) == 4 +typedef unsigned int wchar_t; +#else +typedef unsigned short wchar_t; +#endif +#endif + +extern double atof(const char *); +extern int atoi(const char *); +extern long int atol(const char *); +extern double strtod(const char *, char **); +extern long int strtol(const char *, char **, int); +extern unsigned long int strtoul(const char *, char **, int); +extern int rand(void); +extern void srand(unsigned int); +extern void *calloc(size_t, size_t); +extern void free(void *); +extern void *malloc(size_t); +extern void *realloc(void *, size_t); +extern void abort(void); +extern int atexit(void (*)(void)); +extern void exit(int); +extern char *getenv(const char *); +extern int system(const char *); +extern void *bsearch(const void *, const void *, size_t, size_t, int (*)(const void *, const void *)); +extern void qsort(void *, size_t, size_t, int (*)(const void *, const void *)); +extern int abs(int); +extern div_t div(int, int); +extern long int labs(long int); +extern ldiv_t ldiv(long int, long int); +extern int mblen(const char *, size_t); +extern int mbtowc(wchar_t *, const char *, size_t); +extern int wctomb(char *, wchar_t); +extern size_t mbstowcs(wchar_t *, const char *, size_t); +extern size_t wcstombs(char *, const wchar_t *, size_t); + +#endif /* __STDLIB */ diff --git a/src/cmd/lccom/tst/mips-eb/string.h b/src/cmd/lccom/tst/mips-eb/string.h new file mode 100644 index 0000000..c6ae2d3 --- /dev/null +++ b/src/cmd/lccom/tst/mips-eb/string.h @@ -0,0 +1,38 @@ +#ifndef __STRING +#define __STRING + +#ifndef NULL +#define NULL ((void*)0) +#endif + +#if !defined(_SIZE_T) && !defined(_SIZE_T_) && !defined(_SIZE_T_DEFINED) +#define _SIZE_T +#define _SIZE_T_ +#define _SIZE_T_DEFINED +typedef unsigned long size_t; +#endif + +void *memcpy(void *, const void *, size_t); +void *memmove(void *, const void *, size_t); +char *strcpy(char *, const char *); +char *strncpy(char *, const char *, size_t); +char *strcat(char *, const char *); +char *strncat(char *, const char *, size_t); +int memcmp(const void *, const void *, size_t); +int strcmp(const char *, const char *); +int strcoll(const char *, const char *); +int strncmp(const char *, const char *, size_t); +size_t strxfrm(char *, const char *, size_t); +void *memchr(const void *, int, size_t); +char *strchr(const char *, int); +size_t strcspn(const char *, const char *); +char *strpbrk(const char *, const char *); +char *strrchr(const char *, int); +size_t strspn(const char *, const char *); +char *strstr(const char *, const char *); +char *strtok(char *, const char *); +void *memset(void *, int, size_t); +char *strerror(int); +size_t strlen(const char *); + +#endif /* __STRING */ diff --git a/src/cmd/lccom/tst/mips-eb/struct.1bk b/src/cmd/lccom/tst/mips-eb/struct.1bk new file mode 100644 index 0000000..807f3da --- /dev/null +++ b/src/cmd/lccom/tst/mips-eb/struct.1bk @@ -0,0 +1,5 @@ +(-1,-1) is not within [10,10; 310,310] +(1,1) is not within [10,10; 310,310] +(20,300) is within [10,10; 310,310] +(500,400) is not within [10,10; 310,310] +ab diff --git a/src/cmd/lccom/tst/mips-eb/struct.2bk b/src/cmd/lccom/tst/mips-eb/struct.2bk new file mode 100644 index 0000000..cb0fbd0 --- /dev/null +++ b/src/cmd/lccom/tst/mips-eb/struct.2bk @@ -0,0 +1,2 @@ +tst/struct.c:49: warning: missing return value +tst/struct.c:68: warning: missing return value diff --git a/src/cmd/lccom/tst/mips-eb/struct.sbk b/src/cmd/lccom/tst/mips-eb/struct.sbk new file mode 100644 index 0000000..73369d3 --- /dev/null +++ b/src/cmd/lccom/tst/mips-eb/struct.sbk @@ -0,0 +1,485 @@ +.set reorder +.globl addpoint +.text +.text +.align 2 +.ent addpoint +addpoint: +.frame $sp,0,$31 +.set noreorder +.cpload $25 +.set reorder +sw $5,4($sp) +sw $6,8($sp) +sw $7,12($sp) +lw $24,4+0($sp) +lw $15,12+0($sp) +addu $24,$24,$15 +sw $24,4+0($sp) +lw $24,8+0($sp) +lw $15,16+0($sp) +addu $24,$24,$15 +sw $24,8+0($sp) +la $8,4+0($sp) +lw $3,0($8) +lw $9,4($8) +sw $3,0($4) +sw $9,4($4) +L.1: +j $31 +.end addpoint +.globl canonrect +.text +.align 2 +.ent canonrect +canonrect: +.frame $sp,32,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-32 +.mask 0x40e00000,-20 +sw $21,0($sp) +sw $22,4($sp) +sw $23,8($sp) +sw $30,12($sp) +sw $5,36($sp) +sw $6,40($sp) +sw $7,44($sp) +lw $24,4+32($sp) +lw $15,12+32($sp) +bge $24,$15,L.10 +lw $30,4+32($sp) +b L.11 +L.10: +lw $30,12+32($sp) +L.11: +sw $30,-16+32($sp) +lw $24,8+32($sp) +lw $15,16+32($sp) +bge $24,$15,L.20 +lw $23,8+32($sp) +b L.21 +L.20: +lw $23,16+32($sp) +L.21: +sw $23,-12+32($sp) +lw $24,4+32($sp) +lw $15,12+32($sp) +ble $24,$15,L.26 +lw $22,4+32($sp) +b L.27 +L.26: +lw $22,12+32($sp) +L.27: +sw $22,-8+32($sp) +lw $24,8+32($sp) +lw $15,16+32($sp) +ble $24,$15,L.37 +lw $21,8+32($sp) +b L.38 +L.37: +lw $21,16+32($sp) +L.38: +sw $21,-4+32($sp) +la $8,-16+32($sp) +lw $3,0($8) +lw $9,4($8) +sw $3,0($4) +sw $9,4($4) +lw $3,8($8) +lw $9,12($8) +sw $3,8($4) +sw $9,12($4) +L.5: +lw $21,0($sp) +lw $22,4($sp) +lw $23,8($sp) +lw $30,12($sp) +addu $sp,$sp,32 +j $31 +.end canonrect +.globl makepoint +.text +.align 2 +.ent makepoint +makepoint: +.frame $sp,16,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-16 +sw $5,-8+16($sp) +sw $6,-4+16($sp) +la $8,-8+16($sp) +lw $3,0($8) +lw $9,4($8) +sw $3,0($4) +sw $9,4($4) +L.39: +addu $sp,$sp,16 +j $31 +.end makepoint +.globl makerect +.text +.align 2 +.ent makerect +makerect: +.frame $sp,48,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-48 +.mask 0x82000000,-24 +.cprestore 20 +sw $31,24($sp) +sw $4,48($sp) +sw $5,52($sp) +sw $6,56($sp) +sw $7,60($sp) +la $24,-16+48($sp) +la $8,4+48($sp) +lw $3,0($8) +lw $9,4($8) +sw $3,0($24) +sw $9,4($24) +la $24,-8+48($sp) +la $8,12+48($sp) +lw $3,0($8) +lw $9,4($8) +sw $3,0($24) +sw $9,4($24) +lw $4,0+48($sp) +la $8,-16+48($sp) +lw $3,0($8) +lw $9,4($8) +sw $3,4($29) +sw $9,8($29) +lw $3,8($8) +lw $9,12($8) +sw $3,12($29) +sw $9,16($29) +lw $5,4($sp) +lw $6,8($sp) +lw $7,12($sp) +jal canonrect +L.42: +lw $25,20($sp) +lw $31,24($sp) +addu $sp,$sp,48 +j $31 +.end makerect +.globl ptinrect +.text +.align 2 +.ent ptinrect +ptinrect: +.frame $sp,16,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-16 +.mask 0x40000000,-16 +sw $30,0($sp) +sw $4,16($sp) +sw $5,20($sp) +sw $6,24($sp) +sw $7,28($sp) +lw $24,0+16($sp) +lw $15,8+16($sp) +blt $24,$15,L.53 +lw $15,16+16($sp) +bge $24,$15,L.53 +lw $24,4+16($sp) +lw $15,12+16($sp) +blt $24,$15,L.53 +lw $24,4+16($sp) +lw $15,20+16($sp) +bge $24,$15,L.53 +la $30,1 +b L.54 +L.53: +move $30,$0 +L.54: +move $2,$30 +L.45: +lw $30,0($sp) +addu $sp,$sp,16 +j $31 +.end ptinrect +.globl y +.sdata +.align 0 +y: +.byte 97 +.byte 98 +.byte 0 +.globl odd +.text +.text +.align 2 +.ent odd +odd: +.frame $sp,32,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-32 +.mask 0x82000000,-12 +.cprestore 16 +sw $31,20($sp) +sw $4,32($sp) +la $24,-3+32($sp) +la $8,0+32($sp) +ulhu $3,0($8) +ush $3,0($24) +lbu $3,2($8) +sb $3,2($24) +la $4,L.56 +la $5,-3+32($sp) +jal printf +move $2,$0 +L.55: +lw $25,16($sp) +lw $31,20($sp) +addu $sp,$sp,32 +j $31 +.end odd +.rdata +.align 2 +L.58: +.word 0x0 +.word 0x0 +.align 2 +L.59: +.word 0x140 +.word 0x140 +.align 2 +L.60: +.word 0xffffffff +.word 0xffffffff +.word 0x1 +.word 0x1 +.word 0x14 +.word 0x12c +.word 0x1f4 +.word 0x190 +.globl main +.text +.text +.align 2 +.ent main +main: +.frame $sp,144,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-144 +.mask 0xc2000000,-112 +.cprestore 24 +sw $30,28($sp) +sw $31,32($sp) +la $24,-64+144($sp) +la $8,L.58 +lw $3,0($8) +lw $9,4($8) +sw $3,0($24) +sw $9,4($24) +la $24,-72+144($sp) +la $8,L.59 +lw $3,0($8) +lw $9,4($8) +sw $3,0($24) +sw $9,4($24) +la $24,-32+144($sp) +la $8,L.60 +addu $8,$8,32 +addu $10,$24,32 +L.76: +addu $8,$8,-8 +addu $10,$10,-8 +lw $3,0($8) +lw $9,4($8) +sw $3,0($10) +sw $9,4($10) +bltu $24,$10,L.76 +la $4,-80+144($sp) +la $24,-10 +move $5,$24 +move $6,$24 +jal makepoint +la $4,-88+144($sp) +la $8,-72+144($sp) +lw $3,0($8) +lw $9,4($8) +sw $3,4($29) +sw $9,8($29) +lw $5,4($sp) +lw $6,8($sp) +la $8,-80+144($sp) +lw $3,0($8) +lw $9,4($8) +sw $3,12($29) +sw $9,16($29) +lw $7,12($sp) +jal addpoint +la $4,-96+144($sp) +la $24,10 +move $5,$24 +move $6,$24 +jal makepoint +la $4,-104+144($sp) +la $8,-64+144($sp) +lw $3,0($8) +lw $9,4($8) +sw $3,4($29) +sw $9,8($29) +lw $5,4($sp) +lw $6,8($sp) +la $8,-96+144($sp) +lw $3,0($8) +lw $9,4($8) +sw $3,12($29) +sw $9,16($29) +lw $7,12($sp) +jal addpoint +la $4,-48+144($sp) +la $8,-88+144($sp) +lw $3,0($8) +lw $9,4($8) +sw $3,4($29) +sw $9,8($29) +lw $5,4($sp) +lw $6,8($sp) +la $8,-104+144($sp) +lw $3,0($8) +lw $9,4($8) +sw $3,12($29) +sw $9,16($29) +lw $7,12($sp) +jal makerect +move $30,$0 +b L.64 +L.61: +la $4,-56+144($sp) +sll $24,$30,3 +la $15,-32+144($sp) +addu $15,$24,$15 +lw $5,($15) +la $15,-28+144($sp) +addu $24,$24,$15 +lw $6,($24) +jal makepoint +la $4,L.65 +sll $24,$30,3 +la $15,-32+144($sp) +addu $24,$24,$15 +lw $5,($24) +lw $6,-52+144($sp) +jal printf +la $8,-56+144($sp) +lw $3,0($8) +lw $9,4($8) +sw $3,0($29) +sw $9,4($29) +lw $4,0($sp) +lw $5,4($sp) +la $8,-48+144($sp) +lw $3,0($8) +lw $9,4($8) +sw $3,8($29) +sw $9,12($29) +lw $3,8($8) +lw $9,12($8) +sw $3,16($29) +sw $9,20($29) +lw $6,8($sp) +lw $7,12($sp) +jal ptinrect +bne $2,$0,L.68 +la $4,L.70 +jal printf +L.68: +la $4,L.71 +lw $5,-48+144($sp) +lw $6,-44+144($sp) +lw $7,-40+144($sp) +lw $24,-36+144($sp) +sw $24,16($sp) +jal printf +L.62: +la $30,1($30) +L.64: +move $24,$30 +la $15,4 +bltu $24,$15,L.61 +la $8,y +ulhu $3,0($8) +sh $3,0($29) +lbu $3,2($8) +sb $3,2($29) +lw $4,0($sp) +jal odd +move $4,$0 +jal exit +move $2,$0 +L.57: +lw $25,24($sp) +lw $30,28($sp) +lw $31,32($sp) +addu $sp,$sp,144 +j $31 +.end main +.rdata +.align 0 +L.71: +.byte 119 +.byte 105 +.byte 116 +.byte 104 +.byte 105 +.byte 110 +.byte 32 +.byte 91 +.byte 37 +.byte 100 +.byte 44 +.byte 37 +.byte 100 +.byte 59 +.byte 32 +.byte 37 +.byte 100 +.byte 44 +.byte 37 +.byte 100 +.byte 93 +.byte 10 +.byte 0 +.align 0 +L.70: +.byte 110 +.byte 111 +.byte 116 +.byte 32 +.byte 0 +.align 0 +L.65: +.byte 40 +.byte 37 +.byte 100 +.byte 44 +.byte 37 +.byte 100 +.byte 41 +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 0 +.align 0 +L.56: +.byte 37 +.byte 115 +.byte 10 +.byte 0 diff --git a/src/cmd/lccom/tst/mips-eb/switch.1bk b/src/cmd/lccom/tst/mips-eb/switch.1bk new file mode 100644 index 0000000..de46a73 --- /dev/null +++ b/src/cmd/lccom/tst/mips-eb/switch.1bk @@ -0,0 +1,76 @@ +b = 0x8 +f = 0xc +n = 0xa +r = 0xd +t = 0x9 +v = 0xb +x = 0x78 +f: +x = 0 +x = 1 +x = 2 +x = 2 +x = 2 +x = 2 +x = 2 +x = 7 +x = 8 +x = 9 +x = 9 +x = 9 +x = 9 +x = 9 +x = 9 +x = 9 +x = 16 +x = 17 +x = 18 +x = 19 +x = 20 +g: +1 1 +1 2 +2 3 +2 4 +2 5 +3 6 +d 6 +3 7 +d 7 +3 8 +d 8 +d 9 +d 10 +h: +i = 8 +i = 16 +i = 120 +i = 128 +i = 248 +i = 264 +i = 272 +i = 280 +i = 288 +i = 296 +i = 304 +i = 312 +488 defaults +x = 0x1000000 +x = 0x2000000 +x = 0x3000000 +x = 0x4000000 +x = 0x5000000 +x = 0x6000000 (default) +x = 0x7000000 (default) +0 +1 +2 +3 +4 +5 +0 +1 +2 +3 +4 +5 diff --git a/src/cmd/lccom/tst/mips-eb/switch.2bk b/src/cmd/lccom/tst/mips-eb/switch.2bk new file mode 100644 index 0000000..709b419 --- /dev/null +++ b/src/cmd/lccom/tst/mips-eb/switch.2bk @@ -0,0 +1,5 @@ +tst/switch.c:55: warning: missing return value +tst/switch.c:73: warning: missing return value +tst/switch.c:97: warning: missing return value +tst/switch.c:112: warning: missing return value +tst/switch.c:137: warning: missing return value diff --git a/src/cmd/lccom/tst/mips-eb/switch.sbk b/src/cmd/lccom/tst/mips-eb/switch.sbk new file mode 100644 index 0000000..ccf60c9 --- /dev/null +++ b/src/cmd/lccom/tst/mips-eb/switch.sbk @@ -0,0 +1,836 @@ +.set reorder +.globl main +.text +.text +.align 2 +.ent main +main: +.frame $sp,32,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-32 +.mask 0xc2800000,-4 +sw $23,16($sp) +.cprestore 20 +sw $30,24($sp) +sw $31,28($sp) +la $30,L.6 +b L.5 +L.2: +lb $4,($30) +jal backslash +move $24,$2 +la $4,L.7 +lb $5,($30) +move $6,$24 +jal printf +L.3: +la $30,1($30) +L.5: +lb $24,($30) +bne $24,$0,L.2 +jal f +jal g +jal h +la $23,16777216 +b L.11 +L.8: +move $4,$23 +jal big +L.9: +la $23,16777216($23) +L.11: +and $24,$23,117440512 +bne $24,$0,L.8 +jal limit +move $2,$0 +L.1: +lw $23,16($sp) +lw $25,20($sp) +lw $30,24($sp) +lw $31,28($sp) +addu $sp,$sp,32 +j $31 +.end main +.globl backslash +.text +.align 2 +.ent backslash +backslash: +.frame $sp,0,$31 +.set noreorder +.cpload $25 +.set reorder +la $24,102 +beq $4,$24,L.16 +bgt $4,$24,L.22 +L.21: +la $24,98 +beq $4,$24,L.15 +b L.13 +L.22: +la $24,110 +beq $4,$24,L.17 +blt $4,$24,L.13 +L.23: +la $24,114 +beq $4,$24,L.18 +la $24,116 +beq $4,$24,L.19 +la $24,118 +beq $4,$24,L.20 +b L.13 +L.15: +la $2,8 +b L.12 +L.16: +la $2,12 +b L.12 +L.17: +la $2,10 +b L.12 +L.18: +la $2,13 +b L.12 +L.19: +la $2,9 +b L.12 +L.20: +la $2,11 +b L.12 +L.13: +move $2,$4 +L.12: +j $31 +.end backslash +.globl f +.text +.align 2 +.ent f +f: +.frame $sp,48,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-48 +.mask 0xc2c00000,-16 +sw $22,16($sp) +sw $23,20($sp) +.cprestore 24 +sw $30,28($sp) +sw $31,32($sp) +move $23,$0 +la $4,L.25 +jal printf +move $30,$0 +L.26: +move $22,$30 +la $24,1 +blt $30,$24,L.30 +la $24,20 +bgt $30,$24,L.30 +sll $24,$30,2 +lw $24,L.42-4($24) +.cpadd $24 +j $24 +.rdata +.align 2 +L.42: +.gpword L.32 +.gpword L.33 +.gpword L.30 +.gpword L.30 +.gpword L.30 +.gpword L.30 +.gpword L.34 +.gpword L.35 +.gpword L.36 +.gpword L.30 +.gpword L.30 +.gpword L.30 +.gpword L.30 +.gpword L.30 +.gpword L.30 +.gpword L.37 +.gpword L.38 +.gpword L.39 +.gpword L.40 +.gpword L.41 +.text +L.32: +move $23,$30 +b L.31 +L.33: +move $23,$30 +b L.31 +L.34: +move $23,$30 +b L.31 +L.35: +move $23,$30 +b L.31 +L.36: +move $23,$30 +b L.31 +L.37: +move $23,$30 +b L.31 +L.38: +move $23,$30 +b L.31 +L.39: +move $23,$30 +b L.31 +L.40: +move $23,$30 +b L.31 +L.41: +move $23,$30 +L.30: +L.31: +la $4,L.44 +move $5,$23 +jal printf +L.27: +la $30,1($30) +la $24,20 +ble $30,$24,L.26 +move $2,$0 +L.24: +lw $22,16($sp) +lw $23,20($sp) +lw $25,24($sp) +lw $30,28($sp) +lw $31,32($sp) +addu $sp,$sp,48 +j $31 +.end f +.globl g +.text +.align 2 +.ent g +g: +.frame $sp,32,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-32 +.mask 0xc2000000,-8 +.cprestore 16 +sw $30,20($sp) +sw $31,24($sp) +la $4,L.46 +jal printf +la $30,1 +L.47: +la $24,1001 +blt $30,$24,L.64 +la $24,1004 +bgt $30,$24,L.65 +sll $24,$30,2 +lw $24,L.66-4004($24) +.cpadd $24 +j $24 +.rdata +.align 2 +L.66: +.gpword L.60 +.gpword L.60 +.gpword L.60 +.gpword L.60 +.text +L.64: +la $24,1 +blt $30,$24,L.51 +la $24,8 +bgt $30,$24,L.51 +sll $24,$30,2 +lw $24,L.68-4($24) +.cpadd $24 +j $24 +.rdata +.align 2 +L.68: +.gpword L.53 +.gpword L.53 +.gpword L.55 +.gpword L.55 +.gpword L.55 +.gpword L.57 +.gpword L.57 +.gpword L.57 +.text +L.65: +la $24,3001 +blt $30,$24,L.51 +la $24,3004 +bgt $30,$24,L.51 +sll $24,$30,2 +lw $24,L.70-12004($24) +.cpadd $24 +j $24 +.rdata +.align 2 +L.70: +.gpword L.62 +.gpword L.62 +.gpword L.62 +.gpword L.62 +.text +L.53: +la $4,L.54 +move $5,$30 +jal printf +b L.52 +L.55: +la $4,L.56 +move $5,$30 +jal printf +b L.52 +L.57: +la $4,L.58 +move $5,$30 +jal printf +L.51: +la $4,L.59 +move $5,$30 +jal printf +b L.52 +L.60: +la $4,L.61 +move $5,$30 +jal printf +b L.52 +L.62: +la $4,L.63 +move $5,$30 +jal printf +L.52: +L.48: +la $30,1($30) +la $24,10 +ble $30,$24,L.47 +move $2,$0 +L.45: +lw $25,16($sp) +lw $30,20($sp) +lw $31,24($sp) +addu $sp,$sp,32 +j $31 +.end g +.globl h +.text +.align 2 +.ent h +h: +.frame $sp,32,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-32 +.mask 0xc2800000,-4 +sw $23,16($sp) +.cprestore 20 +sw $30,24($sp) +sw $31,28($sp) +move $23,$0 +la $4,L.73 +jal printf +la $30,1 +L.74: +la $24,264 +beq $30,$24,L.86 +bgt $30,$24,L.94 +L.93: +la $24,120 +beq $30,$24,L.84 +bgt $30,$24,L.96 +L.95: +la $24,8 +beq $30,$24,L.83 +blt $30,$24,L.78 +L.97: +la $24,16 +beq $30,$24,L.82 +b L.78 +L.96: +la $24,128 +beq $30,$24,L.80 +blt $30,$24,L.78 +L.98: +la $24,248 +beq $30,$24,L.87 +b L.78 +L.94: +la $24,288 +beq $30,$24,L.91 +bgt $30,$24,L.100 +L.99: +la $24,272 +beq $30,$24,L.88 +blt $30,$24,L.78 +L.101: +la $24,280 +beq $30,$24,L.85 +b L.78 +L.100: +la $24,304 +beq $30,$24,L.89 +bgt $30,$24,L.103 +L.102: +la $24,296 +beq $30,$24,L.90 +b L.78 +L.103: +la $24,312 +beq $30,$24,L.92 +b L.78 +L.78: +la $23,1($23) +b L.75 +L.80: +la $4,L.81 +move $5,$30 +jal printf +b L.79 +L.82: +la $4,L.81 +move $5,$30 +jal printf +b L.79 +L.83: +la $4,L.81 +move $5,$30 +jal printf +b L.79 +L.84: +la $4,L.81 +move $5,$30 +jal printf +b L.79 +L.85: +la $4,L.81 +move $5,$30 +jal printf +b L.79 +L.86: +la $4,L.81 +move $5,$30 +jal printf +b L.79 +L.87: +la $4,L.81 +move $5,$30 +jal printf +b L.79 +L.88: +la $4,L.81 +move $5,$30 +jal printf +b L.79 +L.89: +la $4,L.81 +move $5,$30 +jal printf +b L.79 +L.90: +la $4,L.81 +move $5,$30 +jal printf +b L.79 +L.91: +la $4,L.81 +move $5,$30 +jal printf +b L.79 +L.92: +la $4,L.81 +move $5,$30 +jal printf +L.79: +L.75: +la $30,1($30) +la $24,500 +ble $30,$24,L.74 +la $4,L.104 +move $5,$23 +jal printf +move $2,$0 +L.72: +lw $23,16($sp) +lw $25,20($sp) +lw $30,24($sp) +lw $31,28($sp) +addu $sp,$sp,32 +j $31 +.end h +.globl big +.text +.align 2 +.ent big +big: +.frame $sp,32,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-32 +.mask 0xc2000000,-8 +.cprestore 16 +sw $30,20($sp) +sw $31,24($sp) +sw $4,32($sp) +lw $24,0+32($sp) +and $30,$24,0x6000000 +la $15,33554432 +beq $30,$15,L.111 +bgt $30,$15,L.115 +L.114: +la $15,-2 +beq $30,$15,L.109 +la $15,-1 +beq $30,$15,L.109 +beq $30,$0,L.109 +b L.106 +L.115: +move $24,$30 +la $15,67108864 +beq $24,$15,L.112 +b L.106 +L.109: +la $4,L.110 +lw $5,0+32($sp) +jal printf +b L.107 +L.111: +la $4,L.110 +lw $5,0+32($sp) +jal printf +b L.107 +L.112: +la $4,L.110 +lw $5,0+32($sp) +jal printf +b L.107 +L.106: +la $4,L.113 +lw $5,0+32($sp) +jal printf +L.107: +move $2,$0 +L.105: +lw $25,16($sp) +lw $30,20($sp) +lw $31,24($sp) +addu $sp,$sp,32 +j $31 +.end big +.globl limit +.text +.align 2 +.ent limit +limit: +.frame $sp,32,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-32 +.mask 0xc2000000,-8 +.cprestore 16 +sw $30,20($sp) +sw $31,24($sp) +la $30,-2147483648 +L.117: +la $24,-2147483648 +blt $30,$24,L.121 +la $15,-2147483644 +bgt $30,$15,L.121 +sll $15,$30,2 +sll $24,$24,2 +subu $24,$15,$24 +lw $24,L.134($24) +.cpadd $24 +j $24 +.rdata +.align 2 +L.134: +.gpword L.123 +.gpword L.125 +.gpword L.127 +.gpword L.129 +.gpword L.131 +.text +L.123: +la $4,L.124 +jal printf +b L.122 +L.125: +la $4,L.126 +jal printf +b L.122 +L.127: +la $4,L.128 +jal printf +b L.122 +L.129: +la $4,L.130 +jal printf +b L.122 +L.131: +la $4,L.132 +jal printf +b L.122 +L.121: +la $4,L.133 +jal printf +L.122: +L.118: +la $30,1($30) +la $24,-2147483643 +ble $30,$24,L.117 +la $30,2147483647 +L.135: +la $24,2147483643 +blt $30,$24,L.139 +la $15,2147483647 +bgt $30,$15,L.139 +sll $15,$30,2 +sll $24,$24,2 +subu $24,$15,$24 +lw $24,L.146($24) +.cpadd $24 +j $24 +.rdata +.align 2 +L.146: +.gpword L.145 +.gpword L.144 +.gpword L.143 +.gpword L.142 +.gpword L.141 +.text +L.141: +la $4,L.124 +jal printf +b L.140 +L.142: +la $4,L.126 +jal printf +b L.140 +L.143: +la $4,L.128 +jal printf +b L.140 +L.144: +la $4,L.130 +jal printf +b L.140 +L.145: +la $4,L.132 +jal printf +b L.140 +L.139: +la $4,L.133 +jal printf +L.140: +L.136: +subu $30,$30,1 +la $24,2147483642 +bge $30,$24,L.135 +move $2,$0 +L.116: +lw $25,16($sp) +lw $30,20($sp) +lw $31,24($sp) +addu $sp,$sp,32 +j $31 +.end limit +.rdata +.align 0 +L.133: +.byte 53 +.byte 10 +.byte 0 +.align 0 +L.132: +.byte 52 +.byte 10 +.byte 0 +.align 0 +L.130: +.byte 51 +.byte 10 +.byte 0 +.align 0 +L.128: +.byte 50 +.byte 10 +.byte 0 +.align 0 +L.126: +.byte 49 +.byte 10 +.byte 0 +.align 0 +L.124: +.byte 48 +.byte 10 +.byte 0 +.align 0 +L.113: +.byte 120 +.byte 32 +.byte 61 +.byte 32 +.byte 48 +.byte 120 +.byte 37 +.byte 120 +.byte 32 +.byte 40 +.byte 100 +.byte 101 +.byte 102 +.byte 97 +.byte 117 +.byte 108 +.byte 116 +.byte 41 +.byte 10 +.byte 0 +.align 0 +L.110: +.byte 120 +.byte 32 +.byte 61 +.byte 32 +.byte 48 +.byte 120 +.byte 37 +.byte 120 +.byte 10 +.byte 0 +.align 0 +L.104: +.byte 37 +.byte 100 +.byte 32 +.byte 100 +.byte 101 +.byte 102 +.byte 97 +.byte 117 +.byte 108 +.byte 116 +.byte 115 +.byte 10 +.byte 0 +.align 0 +L.81: +.byte 105 +.byte 32 +.byte 61 +.byte 32 +.byte 37 +.byte 100 +.byte 10 +.byte 0 +.align 0 +L.73: +.byte 104 +.byte 58 +.byte 10 +.byte 0 +.align 0 +L.63: +.byte 54 +.byte 32 +.byte 37 +.byte 100 +.byte 10 +.byte 0 +.align 0 +L.61: +.byte 53 +.byte 32 +.byte 37 +.byte 100 +.byte 10 +.byte 0 +.align 0 +L.59: +.byte 100 +.byte 32 +.byte 37 +.byte 100 +.byte 10 +.byte 0 +.align 0 +L.58: +.byte 51 +.byte 32 +.byte 37 +.byte 100 +.byte 10 +.byte 0 +.align 0 +L.56: +.byte 50 +.byte 32 +.byte 37 +.byte 100 +.byte 10 +.byte 0 +.align 0 +L.54: +.byte 49 +.byte 32 +.byte 37 +.byte 100 +.byte 10 +.byte 0 +.align 0 +L.46: +.byte 103 +.byte 58 +.byte 10 +.byte 0 +.align 0 +L.44: +.byte 120 +.byte 32 +.byte 61 +.byte 32 +.byte 37 +.byte 100 +.byte 10 +.byte 0 +.align 0 +L.25: +.byte 102 +.byte 58 +.byte 10 +.byte 0 +.align 0 +L.7: +.byte 37 +.byte 99 +.byte 32 +.byte 61 +.byte 32 +.byte 48 +.byte 120 +.byte 37 +.byte 120 +.byte 10 +.byte 0 +.align 0 +L.6: +.byte 98 +.byte 102 +.byte 110 +.byte 114 +.byte 116 +.byte 118 +.byte 120 +.byte 0 diff --git a/src/cmd/lccom/tst/mips-eb/time.h b/src/cmd/lccom/tst/mips-eb/time.h new file mode 100644 index 0000000..6b7a3c1 --- /dev/null +++ b/src/cmd/lccom/tst/mips-eb/time.h @@ -0,0 +1,51 @@ +#ifndef __TIME +#define __TIME + +#define CLOCKS_PER_SEC 1000000 +#ifndef NULL +#define NULL ((void*)0) +#endif + +#if !defined(_CLOCK_T) && !defined(_CLOCK_T_) && !defined(_CLOCK_T_DEFINED) +#define _CLOCK_T +#define _CLOCK_T_ +#define _CLOCK_T_DEFINED +typedef long clock_t; +#endif + +#if !defined(_TIME_T) && !defined(_TIME_T_) && !defined(_TIME_T_DEFINED) +#define _TIME_T +#define _TIME_T_ +#define _TIME_T_DEFINED +typedef long time_t; +#endif + +#if !defined(_SIZE_T) && !defined(_SIZE_T_) && !defined(_SIZE_T_DEFINED) +#define _SIZE_T +#define _SIZE_T_ +#define _SIZE_T_DEFINED +typedef unsigned long size_t; +#endif + +struct tm { + int tm_sec; + int tm_min; + int tm_hour; + int tm_mday; + int tm_mon; + int tm_year; + int tm_wday; + int tm_yday; + int tm_isdst; +}; +extern clock_t clock(void); +extern double difftime(time_t, time_t); +extern time_t mktime(struct tm *); +extern time_t time(time_t *); +extern char *asctime(const struct tm *); +extern char *ctime(const time_t *); +extern struct tm *gmtime(const time_t *); +extern struct tm *localtime(const time_t *); +extern size_t strftime(char *, size_t, const char *, const struct tm *); + +#endif /* __TIME */ diff --git a/src/cmd/lccom/tst/mips-eb/wf1.1bk b/src/cmd/lccom/tst/mips-eb/wf1.1bk new file mode 100644 index 0000000..a846267 --- /dev/null +++ b/src/cmd/lccom/tst/mips-eb/wf1.1bk @@ -0,0 +1,74 @@ +5 a +2 and +5 buf +16 c +8 char +1 compare +4 cond +5 count +1 d +1 die +3 else +1 entry +1 eof +4 err +1 error +1 exit +1 folded +1 for +1 free +1 frequencies +1 frequency +1 get +2 getchar +3 getword +14 if +2 in +1 index +1 input +1 install +8 int +1 into +1 is +4 isletter +1 it +1 itself +5 left +1 letter +7 lookup +1 main +2 malloc +1 message +2 n +1 necessary +12 next +9 node +4 of +1 on +1 or +1 otherwise +2 out +8 p +3 print +2 printf +16 return +5 right +4 root +25 s +2 storage +3 strcmp +1 strcpy +1 strlen +8 struct +1 structures +2 subtree +1 t +5 tprint +9 tree +1 uses +1 version +1 wf +3 while +21 word +9 words +2 z diff --git a/src/cmd/lccom/tst/mips-eb/wf1.2bk b/src/cmd/lccom/tst/mips-eb/wf1.2bk new file mode 100644 index 0000000..190e4a1 --- /dev/null +++ b/src/cmd/lccom/tst/mips-eb/wf1.2bk @@ -0,0 +1,2 @@ +tst/wf1.c:29: warning: missing return value +tst/wf1.c:87: warning: missing return value diff --git a/src/cmd/lccom/tst/mips-eb/wf1.sbk b/src/cmd/lccom/tst/mips-eb/wf1.sbk new file mode 100644 index 0000000..541ea9f --- /dev/null +++ b/src/cmd/lccom/tst/mips-eb/wf1.sbk @@ -0,0 +1,378 @@ +.set reorder +.globl main +.text +.text +.align 2 +.ent main +main: +.frame $sp,48,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-48 +.mask 0x82000000,-28 +.cprestore 16 +sw $31,20($sp) +sw $0,-24+48($sp) +sw $0,next +b L.3 +L.2: +la $4,-20+48($sp) +la $5,-24+48($sp) +jal lookup +lw $15,($2) +la $15,1($15) +sw $15,($2) +L.3: +la $4,-20+48($sp) +jal getword +bne $2,$0,L.2 +lw $4,-24+48($sp) +jal tprint +move $2,$0 +L.1: +lw $25,16($sp) +lw $31,20($sp) +addu $sp,$sp,48 +j $31 +.end main +.globl err +.text +.align 2 +.ent err +err: +.frame $sp,32,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-32 +.mask 0x82000000,-12 +.cprestore 16 +sw $31,20($sp) +sw $4,32($sp) +la $4,L.6 +lw $5,0+32($sp) +jal printf +la $4,1 +jal exit +move $2,$0 +L.5: +lw $25,16($sp) +lw $31,20($sp) +addu $sp,$sp,32 +j $31 +.end err +.globl getword +.text +.align 2 +.ent getword +getword: +.frame $sp,32,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-32 +.mask 0xc2800000,-4 +sw $23,16($sp) +.cprestore 20 +sw $30,24($sp) +sw $31,28($sp) +sw $4,32($sp) +L.8: +L.9: +jal getchar +move $24,$2 +move $30,$24 +la $15,-1 +beq $24,$15,L.11 +move $4,$30 +jal isletter +beq $2,$0,L.8 +L.11: +lw $23,0+32($sp) +b L.15 +L.12: +move $24,$23 +la $23,1($24) +move $15,$30 +sb $15,($24) +L.13: +jal getchar +move $30,$2 +L.15: +move $4,$30 +jal isletter +move $30,$2 +bne $2,$0,L.12 +sb $0,($23) +move $24,$23 +lw $15,0+32($sp) +bleu $24,$15,L.16 +la $2,1 +b L.7 +L.16: +move $2,$0 +L.7: +lw $23,16($sp) +lw $25,20($sp) +lw $30,24($sp) +lw $31,28($sp) +addu $sp,$sp,32 +j $31 +.end getword +.globl isletter +.text +.align 2 +.ent isletter +isletter: +.frame $sp,0,$31 +.set noreorder +.cpload $25 +.set reorder +la $24,65 +blt $4,$24,L.19 +la $24,90 +bgt $4,$24,L.19 +la $4,32($4) +L.19: +la $24,97 +blt $4,$24,L.21 +la $24,122 +bgt $4,$24,L.21 +move $2,$4 +b L.18 +L.21: +move $2,$0 +L.18: +j $31 +.end isletter +.globl lookup +.text +.align 2 +.ent lookup +lookup: +.frame $sp,32,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-32 +.mask 0xc2000000,-8 +.cprestore 16 +sw $30,20($sp) +sw $31,24($sp) +sw $4,32($sp) +move $30,$5 +lw $24,($30) +beq $24,$0,L.24 +lw $4,0+32($sp) +lw $24,($30) +lw $5,12($24) +jal strcmp +sw $2,-4+32($sp) +lw $24,-4+32($sp) +bge $24,$0,L.26 +lw $4,0+32($sp) +lw $24,($30) +la $5,4($24) +jal lookup +move $24,$2 +b L.23 +L.26: +lw $24,-4+32($sp) +ble $24,$0,L.28 +lw $4,0+32($sp) +lw $24,($30) +la $5,8($24) +jal lookup +move $24,$2 +b L.23 +L.28: +lw $2,($30) +b L.23 +L.24: +lw $24,next +la $15,2000 +blt $24,$15,L.30 +la $4,L.32 +jal err +L.30: +lw $24,next +sll $24,$24,4 +sw $0,words($24) +lw $24,next +sll $24,$24,4 +sw $0,words+8($24) +sw $0,words+4($24) +lw $4,0+32($sp) +jal strlen +move $24,$2 +la $4,1($24) +jal malloc +lw $15,next +sll $15,$15,4 +sw $2,words+12($15) +lw $24,next +sll $24,$24,4 +lw $24,words+12($24) +bne $24,$0,L.36 +la $4,L.39 +jal err +L.36: +lw $24,next +sll $24,$24,4 +lw $4,words+12($24) +lw $5,0+32($sp) +jal strcpy +lw $24,next +la $15,1($24) +sw $15,next +sll $24,$24,4 +la $24,words($24) +sw $24,($30) +move $2,$24 +L.23: +lw $25,16($sp) +lw $30,20($sp) +lw $31,24($sp) +addu $sp,$sp,32 +j $31 +.end lookup +.globl tprint +.text +.align 2 +.ent tprint +tprint: +.frame $sp,32,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-32 +.mask 0xc2000000,-8 +.cprestore 16 +sw $30,20($sp) +sw $31,24($sp) +move $30,$4 +move $24,$30 +beq $24,$0,L.42 +lw $4,4($30) +jal tprint +la $4,L.44 +lw $5,($30) +lw $6,12($30) +jal printf +lw $4,8($30) +jal tprint +L.42: +move $2,$0 +L.41: +lw $25,16($sp) +lw $30,20($sp) +lw $31,24($sp) +addu $sp,$sp,32 +j $31 +.end tprint +.globl strcmp +.text +.align 2 +.ent strcmp +strcmp: +.frame $sp,0,$31 +.set noreorder +.cpload $25 +.set reorder +b L.47 +L.46: +move $24,$4 +la $4,1($24) +lb $24,($24) +bne $24,$0,L.49 +move $2,$0 +b L.45 +L.49: +la $5,1($5) +L.47: +lb $24,($4) +lb $15,($5) +beq $24,$15,L.46 +lb $24,($4) +bne $24,$0,L.51 +la $2,-1 +b L.45 +L.51: +lb $24,($5) +bne $24,$0,L.53 +la $2,1 +b L.45 +L.53: +lb $24,($4) +lb $15,($5) +subu $2,$24,$15 +L.45: +j $31 +.end strcmp +.globl next +.comm next,4 +.globl words +.comm words,32000 +.rdata +.align 0 +L.44: +.byte 37 +.byte 100 +.byte 9 +.byte 37 +.byte 115 +.byte 10 +.byte 0 +.align 0 +L.39: +.byte 111 +.byte 117 +.byte 116 +.byte 32 +.byte 111 +.byte 102 +.byte 32 +.byte 119 +.byte 111 +.byte 114 +.byte 100 +.byte 32 +.byte 115 +.byte 116 +.byte 111 +.byte 114 +.byte 97 +.byte 103 +.byte 101 +.byte 0 +.align 0 +L.32: +.byte 111 +.byte 117 +.byte 116 +.byte 32 +.byte 111 +.byte 102 +.byte 32 +.byte 110 +.byte 111 +.byte 100 +.byte 101 +.byte 32 +.byte 115 +.byte 116 +.byte 111 +.byte 114 +.byte 97 +.byte 103 +.byte 101 +.byte 0 +.align 0 +L.6: +.byte 63 +.byte 32 +.byte 37 +.byte 115 +.byte 10 +.byte 0 diff --git a/src/cmd/lccom/tst/mips-eb/yacc.1bk b/src/cmd/lccom/tst/mips-eb/yacc.1bk new file mode 100644 index 0000000..60de9b5 --- /dev/null +++ b/src/cmd/lccom/tst/mips-eb/yacc.1bk @@ -0,0 +1,10 @@ +a +b +load +negate +push 5 +c +load +multiply +add +store diff --git a/src/cmd/lccom/tst/mips-eb/yacc.2bk b/src/cmd/lccom/tst/mips-eb/yacc.2bk new file mode 100644 index 0000000..4b6dc39 --- /dev/null +++ b/src/cmd/lccom/tst/mips-eb/yacc.2bk @@ -0,0 +1,3 @@ +tst/yacc.c:345: warning: missing return value +tst/yacc.c:349: warning: missing return value +tst/yacc.c:360: warning: missing return value diff --git a/src/cmd/lccom/tst/mips-eb/yacc.sbk b/src/cmd/lccom/tst/mips-eb/yacc.sbk new file mode 100644 index 0000000..b31cbdc --- /dev/null +++ b/src/cmd/lccom/tst/mips-eb/yacc.sbk @@ -0,0 +1,2240 @@ +.set reorder +.globl yyin +.sdata +.align 2 +yyin: +.word 0x0 +.globl yyout +.sdata +.align 2 +yyout: +.word 0x0 +.globl yylex +.text +.text +.align 2 +.ent yylex +yylex: +.frame $sp,32,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-32 +.mask 0xc2000000,-8 +.cprestore 16 +sw $30,20($sp) +sw $31,24($sp) +b L.3 +L.2: +L.5: +la $24,-1 +blt $30,$24,L.6 +la $24,4 +bgt $30,$24,L.6 +sll $24,$30,2 +lw $24,L.17+4($24) +.cpadd $24 +j $24 +.rdata +.align 2 +L.17: +.gpword L.7 +.gpword L.8 +.gpword L.11 +.gpword L.12 +.gpword L.7 +.gpword L.14 +.text +L.8: +jal yywrap +beq $2,$0,L.7 +move $2,$0 +b L.1 +L.11: +la $2,257 +b L.1 +L.12: +la $2,258 +b L.1 +L.14: +lb $2,yytext +b L.1 +L.6: +lw $4,yyout +la $5,L.16 +move $6,$30 +jal fprintf +L.7: +L.3: +jal yylook +move $30,$2 +bge $2,$0,L.2 +move $2,$0 +L.1: +lw $25,16($sp) +lw $30,20($sp) +lw $31,24($sp) +addu $sp,$sp,32 +j $31 +.end yylex +.globl yyvstop +.data +.align 2 +yyvstop: +.word 0x0 +.word 0x4 +.word 0x0 +.word 0x3 +.word 0x4 +.word 0x0 +.word 0x2 +.word 0x4 +.word 0x0 +.word 0x1 +.word 0x4 +.word 0x0 +.word 0x2 +.word 0x0 +.word 0x1 +.word 0x0 +.word 0x0 +.globl yycrank +.data +.align 0 +yycrank: +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x1 +.byte 0x3 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x1 +.byte 0x4 +.byte 0x1 +.byte 0x3 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x1 +.byte 0x5 +.byte 0x5 +.byte 0x7 +.byte 0x5 +.byte 0x7 +.byte 0x5 +.byte 0x7 +.byte 0x5 +.byte 0x7 +.byte 0x5 +.byte 0x7 +.byte 0x5 +.byte 0x7 +.byte 0x5 +.byte 0x7 +.byte 0x5 +.byte 0x7 +.byte 0x5 +.byte 0x7 +.byte 0x5 +.byte 0x7 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x1 +.byte 0x6 +.byte 0x6 +.byte 0x8 +.byte 0x6 +.byte 0x8 +.byte 0x6 +.byte 0x8 +.byte 0x6 +.byte 0x8 +.byte 0x6 +.byte 0x8 +.byte 0x6 +.byte 0x8 +.byte 0x6 +.byte 0x8 +.byte 0x6 +.byte 0x8 +.byte 0x6 +.byte 0x8 +.byte 0x6 +.byte 0x8 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x6 +.byte 0x8 +.byte 0x6 +.byte 0x8 +.byte 0x6 +.byte 0x8 +.byte 0x6 +.byte 0x8 +.byte 0x6 +.byte 0x8 +.byte 0x6 +.byte 0x8 +.byte 0x6 +.byte 0x8 +.byte 0x6 +.byte 0x8 +.byte 0x6 +.byte 0x8 +.byte 0x6 +.byte 0x8 +.byte 0x6 +.byte 0x8 +.byte 0x6 +.byte 0x8 +.byte 0x6 +.byte 0x8 +.byte 0x6 +.byte 0x8 +.byte 0x6 +.byte 0x8 +.byte 0x6 +.byte 0x8 +.byte 0x6 +.byte 0x8 +.byte 0x6 +.byte 0x8 +.byte 0x6 +.byte 0x8 +.byte 0x6 +.byte 0x8 +.byte 0x6 +.byte 0x8 +.byte 0x6 +.byte 0x8 +.byte 0x6 +.byte 0x8 +.byte 0x6 +.byte 0x8 +.byte 0x6 +.byte 0x8 +.byte 0x6 +.byte 0x8 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x6 +.byte 0x8 +.byte 0x0 +.byte 0x0 +.byte 0x6 +.byte 0x8 +.byte 0x6 +.byte 0x8 +.byte 0x6 +.byte 0x8 +.byte 0x6 +.byte 0x8 +.byte 0x6 +.byte 0x8 +.byte 0x6 +.byte 0x8 +.byte 0x6 +.byte 0x8 +.byte 0x6 +.byte 0x8 +.byte 0x6 +.byte 0x8 +.byte 0x6 +.byte 0x8 +.byte 0x6 +.byte 0x8 +.byte 0x6 +.byte 0x8 +.byte 0x6 +.byte 0x8 +.byte 0x6 +.byte 0x8 +.byte 0x6 +.byte 0x8 +.byte 0x6 +.byte 0x8 +.byte 0x6 +.byte 0x8 +.byte 0x6 +.byte 0x8 +.byte 0x6 +.byte 0x8 +.byte 0x6 +.byte 0x8 +.byte 0x6 +.byte 0x8 +.byte 0x6 +.byte 0x8 +.byte 0x6 +.byte 0x8 +.byte 0x6 +.byte 0x8 +.byte 0x6 +.byte 0x8 +.byte 0x6 +.byte 0x8 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.byte 0x0 +.globl yysvec +.data +.align 2 +yysvec: +.word 0x0 +.word 0x0 +.word 0x0 +.word yycrank-2 +.word 0x0 +.word 0x0 +.word yycrank +.word yysvec+12 +.word 0x0 +.word yycrank +.word 0x0 +.word yyvstop+4 +.word yycrank +.word 0x0 +.word yyvstop+12 +.word yycrank+4 +.word 0x0 +.word yyvstop+24 +.word yycrank+38 +.word 0x0 +.word yyvstop+36 +.word yycrank +.word yysvec+60 +.word yyvstop+48 +.word yycrank +.word yysvec+72 +.word yyvstop+56 +.word 0x0 +.word 0x0 +.word 0x0 +.globl yytop +.sdata +.align 2 +yytop: +.word yycrank+282 +.globl yybgin +.sdata +.align 2 +yybgin: +.word yysvec+12 +.globl yymatch +.data +.align 0 +yymatch: +.byte 0 +.byte 1 +.byte 1 +.byte 1 +.byte 1 +.byte 1 +.byte 1 +.byte 1 +.byte 1 +.byte 9 +.byte 10 +.byte 1 +.byte 1 +.byte 1 +.byte 1 +.byte 1 +.byte 1 +.byte 1 +.byte 1 +.byte 1 +.byte 1 +.byte 1 +.byte 1 +.byte 1 +.byte 1 +.byte 1 +.byte 1 +.byte 1 +.byte 1 +.byte 1 +.byte 1 +.byte 1 +.byte 9 +.byte 1 +.byte 1 +.byte 1 +.byte 1 +.byte 1 +.byte 1 +.byte 1 +.byte 1 +.byte 1 +.byte 1 +.byte 1 +.byte 1 +.byte 1 +.byte 1 +.byte 1 +.byte 48 +.byte 48 +.byte 48 +.byte 48 +.byte 48 +.byte 48 +.byte 48 +.byte 48 +.byte 48 +.byte 48 +.byte 1 +.byte 1 +.byte 1 +.byte 1 +.byte 1 +.byte 1 +.byte 1 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 1 +.byte 1 +.byte 1 +.byte 1 +.byte 65 +.byte 1 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 1 +.byte 1 +.byte 1 +.byte 1 +.byte 1 +.byte 0 +.globl yyextra +.data +.align 0 +yyextra: +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.globl yylineno +.sdata +.align 2 +yylineno: +.word 0x1 +.globl yysptr +.sdata +.align 2 +yysptr: +.word yysbuf +.globl yyprevious +.sdata +.align 2 +yyprevious: +.word 0xa +.globl yylook +.text +.text +.align 2 +.ent yylook +yylook: +.frame $sp,80,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-80 +.mask 0xc2ff0000,-24 +sw $16,16($sp) +sw $17,20($sp) +sw $18,24($sp) +sw $19,28($sp) +sw $20,32($sp) +sw $21,36($sp) +sw $22,40($sp) +sw $23,44($sp) +.cprestore 48 +sw $30,52($sp) +sw $31,56($sp) +lw $24,yymorfg +bne $24,$0,L.34 +la $21,yytext +b L.35 +L.34: +sw $0,yymorfg +lw $24,yyleng +la $21,yytext($24) +L.35: +L.36: +la $23,yylstate +lw $24,yybgin +move $30,$24 +sw $24,yyestate +lw $24,yyprevious +la $15,10 +bne $24,$15,L.40 +la $30,12($30) +L.40: +L.42: +lw $22,($30) +move $24,$22 +la $15,yycrank +bne $24,$15,L.46 +lw $18,4($30) +move $24,$18 +bne $24,$0,L.48 +b L.93 +L.48: +lw $24,($18) +la $15,yycrank +bne $24,$15,L.50 +b L.93 +L.50: +L.46: +move $24,$21 +sw $24,-12+80($sp) +la $21,1($24) +lw $15,yysptr +la $14,yysbuf +bleu $15,$14,L.60 +lw $15,yysptr +la $15,-1($15) +sw $15,yysptr +lb $15,($15) +sw $15,-4+80($sp) +b L.61 +L.60: +lw $15,yyin +lw $14,($15) +subu $14,$14,1 +sw $14,($15) +bge $14,$0,L.62 +lw $4,yyin +jal _filbuf +move $24,$2 +sw $24,-8+80($sp) +b L.63 +L.62: +lw $24,yyin +la $24,4($24) +lw $15,($24) +la $14,1($15) +sw $14,($24) +lbu $24,($15) +sw $24,-8+80($sp) +L.63: +lw $24,-8+80($sp) +sw $24,-4+80($sp) +L.61: +lw $24,-4+80($sp) +sw $24,yytchar +la $15,10 +bne $24,$15,L.58 +lw $24,yylineno +la $24,1($24) +sw $24,yylineno +lw $16,yytchar +b L.59 +L.58: +lw $16,yytchar +L.59: +la $24,-1 +bne $16,$24,L.56 +move $17,$0 +b L.57 +L.56: +lw $17,yytchar +L.57: +move $20,$17 +move $24,$17 +lw $15,-12+80($sp) +sb $24,($15) +L.64: +move $19,$22 +move $24,$22 +la $15,yycrank +bleu $24,$15,L.65 +sll $24,$20,1 +addu $22,$24,$19 +move $24,$22 +lw $15,yytop +bgtu $24,$15,L.66 +la $24,12 +lb $15,($22) +mul $24,$24,$15 +la $24,yysvec($24) +move $15,$30 +bne $24,$15,L.66 +la $24,yysvec +la $15,12 +lb $14,1($22) +mul $15,$15,$14 +la $15,yysvec($15) +bne $15,$24,L.69 +la $24,-1($21) +move $21,$24 +lb $24,($24) +sw $24,yytchar +lw $24,yytchar +la $15,10 +bne $24,$15,L.71 +lw $24,yylineno +subu $24,$24,1 +sw $24,yylineno +L.71: +lw $24,yysptr +la $15,1($24) +sw $15,yysptr +lw $15,yytchar +sb $15,($24) +b L.93 +L.69: +move $24,$23 +la $23,4($24) +la $15,12 +lb $14,1($22) +mul $15,$15,$14 +la $15,yysvec($15) +move $30,$15 +sw $15,($24) +b L.42 +L.65: +move $24,$22 +la $15,yycrank +bgeu $24,$15,L.74 +la $24,yycrank +move $15,$22 +subu $24,$24,$15 +la $15,2 +div $24,$24,$15 +sll $24,$24,1 +la $24,yycrank($24) +move $19,$24 +move $22,$24 +sll $24,$20,1 +addu $22,$24,$22 +move $24,$22 +lw $15,yytop +bgtu $24,$15,L.76 +la $24,12 +lb $15,($22) +mul $24,$24,$15 +la $24,yysvec($24) +move $15,$30 +bne $24,$15,L.76 +la $24,yysvec +la $15,12 +lb $14,1($22) +mul $15,$15,$14 +la $15,yysvec($15) +bne $15,$24,L.78 +la $24,-1($21) +move $21,$24 +lb $24,($24) +sw $24,yytchar +lw $24,yytchar +la $15,10 +bne $24,$15,L.80 +lw $24,yylineno +subu $24,$24,1 +sw $24,yylineno +L.80: +lw $24,yysptr +la $15,1($24) +sw $15,yysptr +lw $15,yytchar +sb $15,($24) +b L.93 +L.78: +move $24,$23 +la $23,4($24) +la $15,12 +lb $14,1($22) +mul $15,$15,$14 +la $15,yysvec($15) +move $30,$15 +sw $15,($24) +b L.42 +L.76: +lb $24,yymatch($20) +sll $24,$24,1 +addu $22,$24,$19 +move $24,$22 +lw $15,yytop +bgtu $24,$15,L.82 +la $24,12 +lb $15,($22) +mul $24,$24,$15 +la $24,yysvec($24) +move $15,$30 +bne $24,$15,L.82 +la $24,yysvec +la $15,12 +lb $14,1($22) +mul $15,$15,$14 +la $15,yysvec($15) +bne $15,$24,L.84 +la $24,-1($21) +move $21,$24 +lb $24,($24) +sw $24,yytchar +lw $24,yytchar +la $15,10 +bne $24,$15,L.86 +lw $24,yylineno +subu $24,$24,1 +sw $24,yylineno +L.86: +lw $24,yysptr +la $15,1($24) +sw $15,yysptr +lw $15,yytchar +sb $15,($24) +b L.93 +L.84: +move $24,$23 +la $23,4($24) +la $15,12 +lb $14,1($22) +mul $15,$15,$14 +la $15,yysvec($15) +move $30,$15 +sw $15,($24) +b L.42 +L.82: +L.74: +L.66: +lw $24,4($30) +move $30,$24 +beq $24,$0,L.88 +lw $24,($30) +move $22,$24 +la $15,yycrank +beq $24,$15,L.88 +b L.64 +L.88: +la $24,-1($21) +move $21,$24 +lb $24,($24) +sw $24,yytchar +lw $24,yytchar +la $15,10 +bne $24,$15,L.90 +lw $24,yylineno +subu $24,$24,1 +sw $24,yylineno +L.90: +lw $24,yysptr +la $15,1($24) +sw $15,yysptr +lw $15,yytchar +sb $15,($24) +b L.93 +L.92: +move $24,$21 +la $21,-1($24) +sb $0,($24) +lw $24,($23) +move $15,$0 +move $14,$24 +beq $14,$15,L.95 +lw $24,8($24) +sw $24,yyfnd +beq $24,$15,L.95 +lw $24,yyfnd +lw $24,($24) +ble $24,$0,L.95 +sw $23,yyolsp +lw $24,yyfnd +lw $24,($24) +lb $24,yyextra($24) +beq $24,$0,L.97 +b L.100 +L.99: +la $23,-4($23) +move $24,$21 +la $21,-1($24) +lb $24,($24) +sw $24,yytchar +lw $24,yytchar +la $15,10 +bne $24,$15,L.102 +lw $24,yylineno +subu $24,$24,1 +sw $24,yylineno +L.102: +lw $24,yysptr +la $15,1($24) +sw $15,yysptr +lw $15,yytchar +sb $15,($24) +L.100: +lw $24,($23) +lw $4,8($24) +lw $24,yyfnd +lw $24,($24) +negu $5,$24 +jal yyback +la $15,1 +beq $2,$15,L.104 +move $24,$23 +la $15,yylstate +bgtu $24,$15,L.99 +L.104: +L.97: +lb $24,($21) +sw $24,yyprevious +sw $23,yylsp +la $24,yytext +move $15,$21 +subu $24,$15,$24 +la $24,1($24) +sw $24,yyleng +lw $24,yyleng +sb $0,yytext($24) +lw $24,yyfnd +la $15,4($24) +sw $15,yyfnd +lw $2,($24) +b L.33 +L.95: +lb $24,($21) +sw $24,yytchar +lw $24,yytchar +la $15,10 +bne $24,$15,L.105 +lw $24,yylineno +subu $24,$24,1 +sw $24,yylineno +L.105: +lw $24,yysptr +la $15,1($24) +sw $15,yysptr +lw $15,yytchar +sb $15,($24) +L.93: +move $24,$23 +la $23,-4($24) +la $15,yylstate +bgtu $24,$15,L.92 +lb $24,yytext +bne $24,$0,L.107 +la $24,yysbuf +sw $24,yysptr +move $2,$0 +b L.33 +L.107: +lw $24,yysptr +la $15,yysbuf +bleu $24,$15,L.117 +lw $24,yysptr +la $24,-1($24) +sw $24,yysptr +lb $24,($24) +sw $24,-4+80($sp) +b L.118 +L.117: +lw $24,yyin +lw $15,($24) +subu $15,$15,1 +sw $15,($24) +bge $15,$0,L.119 +lw $4,yyin +jal _filbuf +move $24,$2 +sw $24,-8+80($sp) +b L.120 +L.119: +lw $24,yyin +la $24,4($24) +lw $15,($24) +la $14,1($15) +sw $14,($24) +lbu $24,($15) +sw $24,-8+80($sp) +L.120: +lw $24,-8+80($sp) +sw $24,-4+80($sp) +L.118: +lw $24,-4+80($sp) +sw $24,yytchar +la $15,10 +bne $24,$15,L.115 +lw $24,yylineno +la $24,1($24) +sw $24,yylineno +lw $16,yytchar +b L.116 +L.115: +lw $16,yytchar +L.116: +la $24,-1 +bne $16,$24,L.113 +move $17,$0 +b L.114 +L.113: +lw $17,yytchar +L.114: +sb $17,yytext +sll $24,$17,8*(4-1); sra $24,$24,8*(4-1) +sw $24,yyprevious +lw $24,yyprevious +ble $24,$0,L.121 +lw $24,yyout +lw $15,($24) +subu $15,$15,1 +sw $15,($24) +bge $15,$0,L.124 +lw $24,yyprevious +and $24,$24,(1<<(8*1))-1 +move $4,$24 +lw $5,yyout +jal _flsbuf +b L.125 +L.124: +lw $24,yyout +la $24,4($24) +lw $15,($24) +la $14,1($15) +sw $14,($24) +lw $24,yyprevious +sb $24,($15) +L.125: +L.121: +la $21,yytext +b L.36 +L.33: +lw $16,16($sp) +lw $17,20($sp) +lw $18,24($sp) +lw $19,28($sp) +lw $20,32($sp) +lw $21,36($sp) +lw $22,40($sp) +lw $23,44($sp) +lw $25,48($sp) +lw $30,52($sp) +lw $31,56($sp) +addu $sp,$sp,80 +j $31 +.end yylook +.globl yyback +.text +.align 2 +.ent yyback +yyback: +.frame $sp,0,$31 +.set noreorder +.cpload $25 +.set reorder +move $24,$4 +bne $24,$0,L.130 +move $2,$0 +b L.126 +L.129: +move $24,$4 +la $4,4($24) +lw $24,($24) +bne $24,$5,L.132 +la $2,1 +b L.126 +L.132: +L.130: +lw $24,($4) +bne $24,$0,L.129 +move $2,$0 +L.126: +j $31 +.end yyback +.globl yyinput +.text +.align 2 +.ent yyinput +yyinput: +.frame $sp,48,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-48 +.mask 0xc2e00000,-12 +sw $21,16($sp) +sw $22,20($sp) +sw $23,24($sp) +.cprestore 28 +sw $30,32($sp) +sw $31,36($sp) +lw $24,yysptr +la $15,yysbuf +bleu $24,$15,L.143 +lw $24,yysptr +la $24,-1($24) +sw $24,yysptr +lb $22,($24) +b L.144 +L.143: +lw $24,yyin +lw $15,($24) +subu $15,$15,1 +sw $15,($24) +bge $15,$0,L.145 +lw $4,yyin +jal _filbuf +move $24,$2 +move $21,$24 +b L.146 +L.145: +lw $24,yyin +la $24,4($24) +lw $15,($24) +la $14,1($15) +sw $14,($24) +lbu $21,($15) +L.146: +move $22,$21 +L.144: +sw $22,yytchar +la $24,10 +bne $22,$24,L.141 +lw $24,yylineno +la $24,1($24) +sw $24,yylineno +lw $23,yytchar +b L.142 +L.141: +lw $23,yytchar +L.142: +la $24,-1 +bne $23,$24,L.139 +move $30,$0 +b L.140 +L.139: +lw $30,yytchar +L.140: +move $2,$30 +L.134: +lw $21,16($sp) +lw $22,20($sp) +lw $23,24($sp) +lw $25,28($sp) +lw $30,32($sp) +lw $31,36($sp) +addu $sp,$sp,48 +j $31 +.end yyinput +.globl yyoutput +.text +.align 2 +.ent yyoutput +yyoutput: +.frame $sp,32,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-32 +.mask 0x82000000,-12 +.cprestore 16 +sw $31,20($sp) +sw $4,32($sp) +lw $24,yyout +lw $15,($24) +subu $15,$15,1 +sw $15,($24) +bge $15,$0,L.149 +lw $24,0+32($sp) +and $24,$24,(1<<(8*1))-1 +move $4,$24 +lw $5,yyout +jal _flsbuf +b L.150 +L.149: +lw $24,yyout +la $24,4($24) +lw $15,($24) +la $14,1($15) +sw $14,($24) +lw $24,0+32($sp) +sb $24,($15) +L.150: +move $2,$0 +L.147: +lw $25,16($sp) +lw $31,20($sp) +addu $sp,$sp,32 +j $31 +.end yyoutput +.globl yyunput +.text +.align 2 +.ent yyunput +yyunput: +.frame $sp,0,$31 +.set noreorder +.cpload $25 +.set reorder +sw $4,yytchar +lw $24,yytchar +la $15,10 +bne $24,$15,L.152 +lw $24,yylineno +subu $24,$24,1 +sw $24,yylineno +L.152: +lw $24,yysptr +la $15,1($24) +sw $15,yysptr +lw $15,yytchar +sb $15,($24) +move $2,$0 +L.151: +j $31 +.end yyunput +.globl main +.text +.align 2 +.ent main +main: +.frame $sp,32,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-32 +.mask 0x82000000,-12 +.cprestore 16 +sw $31,20($sp) +la $24,_iob +sw $24,yyin +la $24,_iob+16 +sw $24,yyout +jal yyparse +move $2,$0 +L.154: +lw $25,16($sp) +lw $31,20($sp) +addu $sp,$sp,32 +j $31 +.end main +.globl yyerror +.text +.align 2 +.ent yyerror +yyerror: +.frame $sp,32,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-32 +.mask 0x82000000,-12 +.cprestore 16 +sw $31,20($sp) +sw $4,32($sp) +la $4,L.157 +lw $5,0+32($sp) +jal printf +move $2,$0 +L.156: +lw $25,16($sp) +lw $31,20($sp) +addu $sp,$sp,32 +j $31 +.end yyerror +.globl yyexca +.data +.align 1 +yyexca: +.half 0xffff +.half 0x1 +.half 0x0 +.half 0xffff +.half 0xfffe +.half 0x0 +.globl yyact +.data +.align 1 +yyact: +.half 0xc +.half 0x2 +.half 0x9 +.half 0x8 +.half 0x11 +.half 0xb +.half 0x19 +.half 0x11 +.half 0xf +.half 0x12 +.half 0x10 +.half 0xa +.half 0x12 +.half 0x11 +.half 0xf +.half 0x7 +.half 0x10 +.half 0xd +.half 0x12 +.half 0x5 +.half 0x3 +.half 0x1 +.half 0x0 +.half 0x13 +.half 0x14 +.half 0x0 +.half 0x0 +.half 0x15 +.half 0x16 +.half 0x17 +.half 0x18 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x6 +.half 0xe +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x4 +.half 0x6 +.globl yypact +.data +.align 1 +yypact: +.half 0xfc18 +.half 0xfff7 +.half 0xfc18 +.half 0x5 +.half 0xfff9 +.half 0xffc5 +.half 0xfc18 +.half 0xfc18 +.half 0xfc18 +.half 0xffd8 +.half 0xffe3 +.half 0xffd8 +.half 0xffd8 +.half 0xfc18 +.half 0xfc18 +.half 0xffd8 +.half 0xffd8 +.half 0xffd8 +.half 0xffd8 +.half 0xffda +.half 0xffdd +.half 0xffda +.half 0xffda +.half 0xfc18 +.half 0xfc18 +.half 0xfc18 +.globl yypgo +.data +.align 1 +yypgo: +.half 0x0 +.half 0x15 +.half 0x14 +.half 0x11 +.half 0xb +.globl yyr1 +.data +.align 1 +yyr1: +.half 0x0 +.half 0x1 +.half 0x1 +.half 0x1 +.half 0x1 +.half 0x2 +.half 0x4 +.half 0x4 +.half 0x4 +.half 0x4 +.half 0x4 +.half 0x4 +.half 0x4 +.half 0x4 +.half 0x3 +.globl yyr2 +.data +.align 1 +yyr2: +.half 0x0 +.half 0x0 +.half 0x2 +.half 0x3 +.half 0x3 +.half 0x3 +.half 0x3 +.half 0x3 +.half 0x3 +.half 0x3 +.half 0x2 +.half 0x3 +.half 0x1 +.half 0x1 +.half 0x1 +.globl yychk +.data +.align 1 +yychk: +.half 0xfc18 +.half 0xffff +.half 0xa +.half 0xfffe +.half 0x100 +.half 0xfffd +.half 0x101 +.half 0xa +.half 0xa +.half 0x3d +.half 0xfffc +.half 0x2d +.half 0x28 +.half 0xfffd +.half 0x102 +.half 0x2b +.half 0x2d +.half 0x2a +.half 0x2f +.half 0xfffc +.half 0xfffc +.half 0xfffc +.half 0xfffc +.half 0xfffc +.half 0xfffc +.half 0x29 +.globl yydef +.data +.align 1 +yydef: +.half 0x1 +.half 0xfffe +.half 0x2 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0xe +.half 0x3 +.half 0x4 +.half 0x0 +.half 0x5 +.half 0x0 +.half 0x0 +.half 0xc +.half 0xd +.half 0x0 +.half 0x0 +.half 0x0 +.half 0x0 +.half 0xa +.half 0x0 +.half 0x6 +.half 0x7 +.half 0x8 +.half 0x9 +.half 0xb +.globl yychar +.sdata +.align 2 +yychar: +.word 0xffffffff +.globl yynerrs +.sdata +.align 2 +yynerrs: +.word 0x0 +.globl yyerrflag +.sdata +.align 1 +yyerrflag: +.half 0x0 +.globl yyparse +.text +.text +.align 2 +.ent yyparse +yyparse: +.frame $sp,368,$31 +.set noreorder +.cpload $25 +.set reorder +addu $sp,$sp,-368 +.mask 0xc2fe0000,-316 +sw $17,16($sp) +sw $18,20($sp) +sw $19,24($sp) +sw $20,28($sp) +sw $21,32($sp) +sw $22,36($sp) +sw $23,40($sp) +.cprestore 44 +sw $30,48($sp) +sw $31,52($sp) +move $24,$0 +move $23,$24 +la $15,-1 +sw $15,yychar +sw $0,yynerrs +sh $24,yyerrflag +la $22,-302+368($sp) +la $20,yyv-4 +L.161: +la $24,2($22) +move $22,$24 +la $15,-2+368($sp) +bleu $24,$15,L.162 +la $4,L.165 +jal yyerror +la $2,1 +b L.158 +L.162: +sh $23,($22) +la $20,4($20) +lw $24,yyval +sw $24,($20) +L.166: +sll $24,$23,8*(4-2); sra $24,$24,8*(4-2) +sll $24,$24,1 +lh $21,yypact($24) +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +la $15,-1000 +bgt $24,$15,L.167 +b L.169 +L.167: +lw $24,yychar +bge $24,$0,L.170 +jal yylex +sw $2,yychar +bge $2,$0,L.172 +sw $0,yychar +L.172: +L.170: +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +lw $15,yychar +addu $24,$24,$15 +move $21,$24 +sll $24,$24,8*(4-2); sra $24,$24,8*(4-2) +blt $24,$0,L.176 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +la $15,249 +blt $24,$15,L.174 +L.176: +b L.169 +L.174: +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +sll $24,$24,1 +lh $24,yyact($24) +move $21,$24 +sll $24,$24,8*(4-2); sra $24,$24,8*(4-2) +sll $24,$24,1 +lh $24,yychk($24) +lw $15,yychar +bne $24,$15,L.177 +la $24,-1 +sw $24,yychar +lw $24,yylval +sw $24,yyval +move $23,$21 +lh $24,yyerrflag +ble $24,$0,L.161 +lh $24,yyerrflag +subu $24,$24,1 +sh $24,yyerrflag +b L.161 +L.177: +L.169: +sll $24,$23,8*(4-2); sra $24,$24,8*(4-2) +sll $24,$24,1 +lh $24,yydef($24) +move $21,$24 +sll $24,$24,8*(4-2); sra $24,$24,8*(4-2) +la $15,-2 +bne $24,$15,L.181 +lw $24,yychar +bge $24,$0,L.183 +jal yylex +sw $2,yychar +bge $2,$0,L.185 +sw $0,yychar +L.185: +L.183: +la $19,yyexca +b L.190 +L.187: +L.188: +la $19,4($19) +L.190: +lh $24,($19) +la $15,-1 +bne $24,$15,L.187 +lh $24,2($19) +sll $15,$23,8*(4-2); sra $15,$15,8*(4-2) +bne $24,$15,L.187 +b L.192 +L.191: +lh $24,($19) +lw $15,yychar +bne $24,$15,L.194 +b L.193 +L.194: +L.192: +la $24,4($19) +move $19,$24 +lh $24,($24) +bge $24,$0,L.191 +L.193: +lh $24,2($19) +move $21,$24 +sll $24,$24,8*(4-2); sra $24,$24,8*(4-2) +bge $24,$0,L.196 +move $2,$0 +b L.158 +L.196: +L.181: +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +bne $24,$0,L.198 +lh $17,yyerrflag +blt $17,$0,L.200 +la $24,3 +bgt $17,$24,L.200 +sll $24,$17,2 +lw $24,L.216($24) +.cpadd $24 +j $24 +.rdata +.align 2 +L.216: +.gpword L.203 +.gpword L.206 +.gpword L.206 +.gpword L.213 +.text +L.203: +la $4,L.204 +jal yyerror +L.205: +lw $24,yynerrs +la $24,1($24) +sw $24,yynerrs +L.206: +la $24,3 +sh $24,yyerrflag +b L.208 +L.207: +lh $24,($22) +sll $24,$24,1 +lh $24,yypact($24) +la $24,256($24) +move $21,$24 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +blt $24,$0,L.210 +la $15,249 +bge $24,$15,L.210 +sll $24,$24,1 +lh $24,yyact($24) +sll $24,$24,1 +lh $24,yychk($24) +la $15,256 +bne $24,$15,L.210 +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +sll $24,$24,1 +lh $23,yyact($24) +b L.161 +L.210: +lh $24,($22) +sll $24,$24,1 +lh $21,yypact($24) +la $22,-2($22) +la $20,-4($20) +L.208: +move $24,$22 +la $15,-300+368($sp) +bgeu $24,$15,L.207 +L.212: +la $2,1 +b L.158 +L.213: +lw $24,yychar +bne $24,$0,L.214 +b L.212 +L.214: +la $24,-1 +sw $24,yychar +b L.166 +L.200: +L.198: +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +sll $24,$24,1 +la $15,yyr2($24) +lh $14,($15) +sll $14,$14,1 +subu $22,$22,$14 +move $30,$20 +lh $15,($15) +sll $15,$15,2 +subu $20,$20,$15 +lw $15,4($20) +sw $15,yyval +sh $21,-302+368($sp) +lh $21,yyr1($24) +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +sll $24,$24,1 +lh $24,yypgo($24) +lh $15,($22) +addu $24,$24,$15 +la $24,1($24) +move $18,$24 +sll $24,$18,8*(4-2); sra $24,$24,8*(4-2) +la $15,249 +bge $24,$15,L.219 +sll $24,$24,1 +lh $24,yyact($24) +move $23,$24 +sll $24,$24,8*(4-2); sra $24,$24,8*(4-2) +sll $24,$24,1 +lh $24,yychk($24) +sll $15,$21,8*(4-2); sra $15,$15,8*(4-2) +negu $15,$15 +beq $24,$15,L.217 +L.219: +sll $24,$21,8*(4-2); sra $24,$24,8*(4-2) +sll $24,$24,1 +lh $24,yypgo($24) +sll $24,$24,1 +lh $23,yyact($24) +L.217: +lh $17,-302+368($sp) +la $24,4 +blt $17,$24,L.161 +la $24,14 +bgt $17,$24,L.161 +sll $24,$17,2 +lw $24,L.241-16($24) +.cpadd $24 +j $24 +.rdata +.align 2 +L.241: +.gpword L.223 +.gpword L.224 +.gpword L.226 +.gpword L.228 +.gpword L.230 +.gpword L.232 +.gpword L.234 +.gpword L.161 +.gpword L.236 +.gpword L.238 +.gpword L.240 +.text +L.223: +sh $0,yyerrflag +b L.161 +L.224: +la $4,L.225 +jal printf +b L.161 +L.226: +la $4,L.227 +jal printf +b L.161 +L.228: +la $4,L.229 +jal printf +b L.161 +L.230: +la $4,L.231 +jal printf +b L.161 +L.232: +la $4,L.233 +jal printf +b L.161 +L.234: +la $4,L.235 +jal printf +b L.161 +L.236: +la $4,L.237 +jal printf +b L.161 +L.238: +la $4,L.239 +la $5,yytext +jal printf +b L.161 +L.240: +la $4,L.157 +la $5,yytext +jal printf +b L.161 +L.158: +lw $17,16($sp) +lw $18,20($sp) +lw $19,24($sp) +lw $20,28($sp) +lw $21,32($sp) +lw $22,36($sp) +lw $23,40($sp) +lw $25,44($sp) +lw $30,48($sp) +lw $31,52($sp) +addu $sp,$sp,368 +j $31 +.end yyparse +.globl yywrap +.text +.align 2 +.ent yywrap +yywrap: +.frame $sp,0,$31 +.set noreorder +.cpload $25 +.set reorder +la $2,1 +L.243: +j $31 +.end yywrap +.globl yyv +.comm yyv,600 +.globl yyfnd +.comm yyfnd,4 +.globl yyolsp +.comm yyolsp,4 +.globl yylsp +.comm yylsp,4 +.globl yylstate +.comm yylstate,800 +.globl yyestate +.comm yyestate,4 +.globl yytchar +.comm yytchar,4 +.globl yysbuf +.comm yysbuf,200 +.globl yymorfg +.comm yymorfg,4 +.globl yytext +.comm yytext,200 +.globl yyleng +.comm yyleng,4 +.extern _iob 0 +.globl yyval +.comm yyval,4 +.globl yylval +.comm yylval,4 +.rdata +.align 0 +L.239: +.byte 112 +.byte 117 +.byte 115 +.byte 104 +.byte 32 +.byte 37 +.byte 115 +.byte 10 +.byte 0 +.align 0 +L.237: +.byte 108 +.byte 111 +.byte 97 +.byte 100 +.byte 10 +.byte 0 +.align 0 +L.235: +.byte 110 +.byte 101 +.byte 103 +.byte 97 +.byte 116 +.byte 101 +.byte 10 +.byte 0 +.align 0 +L.233: +.byte 100 +.byte 105 +.byte 118 +.byte 105 +.byte 100 +.byte 101 +.byte 10 +.byte 0 +.align 0 +L.231: +.byte 109 +.byte 117 +.byte 108 +.byte 116 +.byte 105 +.byte 112 +.byte 108 +.byte 121 +.byte 10 +.byte 0 +.align 0 +L.229: +.byte 110 +.byte 101 +.byte 103 +.byte 97 +.byte 116 +.byte 101 +.byte 10 +.byte 97 +.byte 100 +.byte 100 +.byte 10 +.byte 0 +.align 0 +L.227: +.byte 97 +.byte 100 +.byte 100 +.byte 10 +.byte 0 +.align 0 +L.225: +.byte 115 +.byte 116 +.byte 111 +.byte 114 +.byte 101 +.byte 10 +.byte 0 +.align 0 +L.204: +.byte 115 +.byte 121 +.byte 110 +.byte 116 +.byte 97 +.byte 120 +.byte 32 +.byte 101 +.byte 114 +.byte 114 +.byte 111 +.byte 114 +.byte 0 +.align 0 +L.165: +.byte 121 +.byte 97 +.byte 99 +.byte 99 +.byte 32 +.byte 115 +.byte 116 +.byte 97 +.byte 99 +.byte 107 +.byte 32 +.byte 111 +.byte 118 +.byte 101 +.byte 114 +.byte 102 +.byte 108 +.byte 111 +.byte 119 +.byte 0 +.align 0 +L.157: +.byte 37 +.byte 115 +.byte 10 +.byte 0 +.align 0 +L.16: +.byte 98 +.byte 97 +.byte 100 +.byte 32 +.byte 115 +.byte 119 +.byte 105 +.byte 116 +.byte 99 +.byte 104 +.byte 32 +.byte 121 +.byte 121 +.byte 108 +.byte 111 +.byte 111 +.byte 107 +.byte 32 +.byte 37 +.byte 100 +.byte 0 diff --git a/src/cmd/lccom/tst/paranoia.0 b/src/cmd/lccom/tst/paranoia.0 new file mode 100644 index 0000000..e69de29 diff --git a/src/cmd/lccom/tst/paranoia.c b/src/cmd/lccom/tst/paranoia.c new file mode 100644 index 0000000..ec9f8ce --- /dev/null +++ b/src/cmd/lccom/tst/paranoia.c @@ -0,0 +1,2203 @@ +#undef V9 +#define NOPAUSE +/* A C version of Kahan's Floating Point Test "Paranoia" + + Thos Sumner, UCSF, Feb. 1985 + David Gay, BTL, Jan. 1986 + + This is a rewrite from the Pascal version by + + B. A. Wichmann, 18 Jan. 1985 + + (and does NOT exhibit good C programming style). + +(C) Apr 19 1983 in BASIC version by: + Professor W. M. Kahan, + 567 Evans Hall + Electrical Engineering & Computer Science Dept. + University of California + Berkeley, California 94720 + USA + +converted to Pascal by: + B. A. Wichmann + National Physical Laboratory + Teddington Middx + TW11 OLW + UK + +converted to C by: + + David M. Gay and Thos Sumner + AT&T Bell Labs Computer Center, Rm. U-76 + 600 Mountain Avenue University of California + Murray Hill, NJ 07974 San Francisco, CA 94143 + USA USA + +with simultaneous corrections to the Pascal source (reflected +in the Pascal source available over netlib). +[A couple of bug fixes from dgh = sun!dhough incorporated 31 July 1986.] + +Reports of results on various systems from all the versions +of Paranoia are being collected by Richard Karpinski at the +same address as Thos Sumner. This includes sample outputs, +bug reports, and criticisms. + +You may copy this program freely if you acknowledge its source. +Comments on the Pascal version to NPL, please. + + +The C version catches signals from floating-point exceptions. +If signal(SIGFPE,...) is unavailable in your environment, you may +#define NOSIGNAL to comment out the invocations of signal. + +This source file is too big for some C compilers, but may be split +into pieces. Comments containing "SPLIT" suggest convenient places +for this splitting. At the end of these comments is an "ed script" +(for the UNIX(tm) editor ed) that will do this splitting. + +By #defining Single when you compile this source, you may obtain +a single-precision C version of Paranoia. + + +The following is from the introductory commentary from Wichmann's work: + +The BASIC program of Kahan is written in Microsoft BASIC using many +facilities which have no exact analogy in Pascal. The Pascal +version below cannot therefore be exactly the same. Rather than be +a minimal transcription of the BASIC program, the Pascal coding +follows the conventional style of block-structured languages. Hence +the Pascal version could be useful in producing versions in other +structured languages. + +Rather than use identifiers of minimal length (which therefore have +little mnemonic significance), the Pascal version uses meaningful +identifiers as follows [Note: A few changes have been made for C]: + + +BASIC C BASIC C BASIC C + + A J S StickyBit + A1 AInverse J0 NoErrors T + B Radix [Failure] T0 Underflow + B1 BInverse J1 NoErrors T2 ThirtyTwo + B2 RadixD2 [SeriousDefect] T5 OneAndHalf + B9 BMinusU2 J2 NoErrors T7 TwentySeven + C [Defect] T8 TwoForty + C1 CInverse J3 NoErrors U OneUlp + D [Flaw] U0 UnderflowThreshold + D4 FourD K PageNo U1 + E0 L Milestone U2 + E1 M V + E2 Exp2 N V0 + E3 N1 V8 + E5 MinSqEr O Zero V9 + E6 SqEr O1 One W + E7 MaxSqEr O2 Two X + E8 O3 Three X1 + E9 O4 Four X8 + F1 MinusOne O5 Five X9 Random1 + F2 Half O8 Eight Y + F3 Third O9 Nine Y1 + F6 P Precision Y2 + F9 Q Y9 Random2 + G1 GMult Q8 Z + G2 GDiv Q9 Z0 PseudoZero + G3 GAddSub R Z1 + H R1 RMult Z2 + H1 HInverse R2 RDiv Z9 + I R3 RAddSub + IO NoTrials R4 RSqrt + I3 IEEE R9 Random9 + + SqRWrng + +All the variables in BASIC are true variables and in consequence, +the program is more difficult to follow since the "constants" must +be determined (the glossary is very helpful). The Pascal version +uses Real constants, but checks are added to ensure that the values +are correctly converted by the compiler. + +The major textual change to the Pascal version apart from the +identifiersis that named procedures are used, inserting parameters +wherehelpful. New procedures are also introduced. The +correspondence is as follows: + + +BASIC Pascal +lines + + 90- 140 Pause + 170- 250 Instructions + 380- 460 Heading + 480- 670 Characteristics + 690- 870 History +2940-2950 Random +3710-3740 NewD +4040-4080 DoesYequalX +4090-4110 PrintIfNPositive +4640-4850 TestPartialUnderflow + +=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= + +Below is an "ed script" that splits para.c into 10 files +of the form part[1-8].c, subs.c, and msgs.c, plus a header +file, paranoia.h, that these files require. + +r paranoia.c +$ +?SPLIT ++,$w msgs.c + .,$d +?SPLIT + .d ++d +-,$w subs.c +-,$d +?part8 ++d +?include + .,$w part8.c + .,$d +-d +?part7 ++d +?include + .,$w part7.c + .,$d +-d +?part6 ++d +?include + .,$w part6.c + .,$d +-d +?part5 ++d +?include + .,$w part5.c + .,$d +-d +?part4 ++d +?include + .,$w part4.c + .,$d +-d +?part3 ++d +?include + .,$w part3.c + .,$d +-d +?part2 ++d +?include + .,$w part2.c + .,$d +?SPLIT + .d +1,/^#include/-1d +1,$w part1.c +/Computed constants/,$d +1,$s/^int/extern &/ +1,$s/^FLOAT/extern &/ +1,$s/^char/extern &/ +1,$s! = .*!;! +/^Guard/,/^Round/s/^/extern / +/^jmp_buf/s/^/extern / +/^Sig_type/s/^/extern / +s/$/\ +extern void sigfpe();/ +w paranoia.h +q + +*/ + +#include +#ifndef NOSIGNAL +#include +#endif +#include + +extern double fabs(), floor(), log(), pow(), sqrt(); + +#ifdef Single +#define FLOAT float +#define FABS(x) (float)fabs((double)(x)) +#define FLOOR(x) (float)floor((double)(x)) +#define LOG(x) (float)log((double)(x)) +#define POW(x,y) (float)pow((double)(x),(double)(y)) +#define SQRT(x) (float)sqrt((double)(x)) +#else +#define FLOAT double +#define FABS(x) fabs(x) +#define FLOOR(x) floor(x) +#define LOG(x) log(x) +#define POW(x,y) pow(x,y) +#define SQRT(x) sqrt(x) +#endif + +jmp_buf ovfl_buf; +typedef void (*Sig_type)(); +Sig_type sigsave; + +#define KEYBOARD 0 + +FLOAT Radix, BInvrse, RadixD2, BMinusU2; +FLOAT Sign(), Random(); + +/*Small floating point constants.*/ +FLOAT Zero = 0.0; +FLOAT Half = 0.5; +FLOAT One = 1.0; +FLOAT Two = 2.0; +FLOAT Three = 3.0; +FLOAT Four = 4.0; +FLOAT Five = 5.0; +FLOAT Eight = 8.0; +FLOAT Nine = 9.0; +FLOAT TwentySeven = 27.0; +FLOAT ThirtyTwo = 32.0; +FLOAT TwoForty = 240.0; +FLOAT MinusOne = -1.0; +FLOAT OneAndHalf = 1.5; +/*Integer constants*/ +int NoTrials = 20; /*Number of tests for commutativity. */ +#define False 0 +#define True 1 + +/* Definitions for declared types + Guard == (Yes, No); + Rounding == (Chopped, Rounded, Other); + Message == packed array [1..40] of char; + Class == (Flaw, Defect, Serious, Failure); + */ +#define Yes 1 +#define No 0 +#define Chopped 2 +#define Rounded 1 +#define Other 0 +#define Flaw 3 +#define Defect 2 +#define Serious 1 +#define Failure 0 +typedef int Guard, Rounding, Class; +typedef char Message; + +/* Declarations of Variables */ +int Indx; +char ch[8]; +FLOAT AInvrse, A1; +FLOAT C, CInvrse; +FLOAT D, FourD; +FLOAT E0, E1, Exp2, E3, MinSqEr; +FLOAT SqEr, MaxSqEr, E9; +FLOAT Third; +FLOAT F6, F9; +FLOAT H, HInvrse; +int I; +FLOAT StickyBit, J; +FLOAT MyZero; +FLOAT Precision; +FLOAT Q, Q9; +FLOAT R, Random9; +FLOAT T, Underflow, S; +FLOAT OneUlp, UfThold, U1, U2; +FLOAT V, V0, V9; +FLOAT W; +FLOAT X, X1, X2, X8, Random1; +FLOAT Y, Y1, Y2, Random2; +FLOAT Z, PseudoZero, Z1, Z2, Z9; +int ErrCnt[4]; +int fpecount; +int Milestone; +int PageNo; +int M, N, N1; +Guard GMult, GDiv, GAddSub; +Rounding RMult, RDiv, RAddSub, RSqrt; +int Break, Done, NotMonot, Monot, Anomaly, IEEE, + SqRWrng, UfNGrad; +/* Computed constants. */ +/*U1 gap below 1.0, i.e, 1.0-U1 is next number below 1.0 */ +/*U2 gap above 1.0, i.e, 1.0+U2 is next number above 1.0 */ + +/* floating point exception receiver */ + void +sigfpe(i) +{ + fpecount++; + printf("\n* * * FLOATING-POINT ERROR * * *\n"); + fflush(stdout); + if (sigsave) { +#ifndef NOSIGNAL + signal(SIGFPE, sigsave); +#endif + sigsave = 0; + longjmp(ovfl_buf, 1); + } + abort(); +} + +main() +{ +#ifdef mc + char *out; + ieee_flags("set", "precision", "double", &out); +#endif + /* First two assignments use integer right-hand sides. */ + Zero = 0; + One = 1; + Two = One + One; + Three = Two + One; + Four = Three + One; + Five = Four + One; + Eight = Four + Four; + Nine = Three * Three; + TwentySeven = Nine * Three; + ThirtyTwo = Four * Eight; + TwoForty = Four * Five * Three * Four; + MinusOne = -One; + Half = One / Two; + OneAndHalf = One + Half; + ErrCnt[Failure] = 0; + ErrCnt[Serious] = 0; + ErrCnt[Defect] = 0; + ErrCnt[Flaw] = 0; + PageNo = 1; + /*=============================================*/ + Milestone = 0; + /*=============================================*/ +#ifndef NOSIGNAL + signal(SIGFPE, sigfpe); +#endif + Instructions(); + Pause(); + Heading(); + Pause(); + Characteristics(); + Pause(); + History(); + Pause(); + /*=============================================*/ + Milestone = 7; + /*=============================================*/ + printf("Program is now RUNNING tests on small integers:\n"); + + TstCond (Failure, (Zero + Zero == Zero) && (One - One == Zero) + && (One > Zero) && (One + One == Two), + "0+0 != 0, 1-1 != 0, 1 <= 0, or 1+1 != 2"); + Z = - Zero; + if (Z != 0.0) { + ErrCnt[Failure] = ErrCnt[Failure] + 1; + printf("Comparison alleges that -0.0 is Non-zero!\n"); + U1 = 0.001; + Radix = 1; + TstPtUf(); + } + TstCond (Failure, (Three == Two + One) && (Four == Three + One) + && (Four + Two * (- Two) == Zero) + && (Four - Three - One == Zero), + "3 != 2+1, 4 != 3+1, 4+2*(-2) != 0, or 4-3-1 != 0"); + TstCond (Failure, (MinusOne == (0 - One)) + && (MinusOne + One == Zero ) && (One + MinusOne == Zero) + && (MinusOne + FABS(One) == Zero) + && (MinusOne + MinusOne * MinusOne == Zero), + "-1+1 != 0, (-1)+abs(1) != 0, or -1+(-1)*(-1) != 0"); + TstCond (Failure, Half + MinusOne + Half == Zero, + "1/2 + (-1) + 1/2 != 0"); + /*=============================================*/ + /*SPLIT + part2(); + part3(); + part4(); + part5(); + part6(); + part7(); + part8(); + } +#include "paranoia.h" +part2(){ +*/ + Milestone = 10; + /*=============================================*/ + TstCond (Failure, (Nine == Three * Three) + && (TwentySeven == Nine * Three) && (Eight == Four + Four) + && (ThirtyTwo == Eight * Four) + && (ThirtyTwo - TwentySeven - Four - One == Zero), + "9 != 3*3, 27 != 9*3, 32 != 8*4, or 32-27-4-1 != 0"); + TstCond (Failure, (Five == Four + One) && + (TwoForty == Four * Five * Three * Four) + && (TwoForty / Three - Four * Four * Five == Zero) + && ( TwoForty / Four - Five * Three * Four == Zero) + && ( TwoForty / Five - Four * Three * Four == Zero), + "5 != 4+1, 240/3 != 80, 240/4 != 60, or 240/5 != 48"); + if (ErrCnt[Failure] == 0) { + printf("-1, 0, 1/2, 1, 2, 3, 4, 5, 9, 27, 32 & 240 are O.K.\n"); + printf("\n"); + } + printf("Searching for Radix and Precision.\n"); + W = One; + do { + W = W + W; + Y = W + One; + Z = Y - W; + Y = Z - One; + } while (MinusOne + FABS(Y) < Zero); + /*.. now W is just big enough that |((W+1)-W)-1| >= 1 ...*/ + Precision = Zero; + Y = One; + do { + Radix = W + Y; + Y = Y + Y; + Radix = Radix - W; + } while ( Radix == Zero); + if (Radix < Two) Radix = One; + printf("Radix = %f .\n", Radix); + if (Radix != 1) { + W = One; + do { + Precision = Precision + One; + W = W * Radix; + Y = W + One; + } while ((Y - W) == One); + } + /*... now W == Radix^Precision is barely too big to satisfy (W+1)-W == 1 + ...*/ + U1 = One / W; + U2 = Radix * U1; + printf("Closest relative separation found is U1 = %.7e .\n\n", U1); + printf("Recalculating radix and precision\n "); + + /*save old values*/ + E0 = Radix; + E1 = U1; + E9 = U2; + E3 = Precision; + + X = Four / Three; + Third = X - One; + F6 = Half - Third; + X = F6 + F6; + X = FABS(X - Third); + if (X < U2) X = U2; + + /*... now X = (unknown no.) ulps of 1+...*/ + do { + U2 = X; + Y = Half * U2 + ThirtyTwo * U2 * U2; + Y = One + Y; + X = Y - One; + } while ( ! ((U2 <= X) || (X <= Zero))); + + /*... now U2 == 1 ulp of 1 + ... */ + X = Two / Three; + F6 = X - Half; + Third = F6 + F6; + X = Third - Half; + X = FABS(X + F6); + if (X < U1) X = U1; + + /*... now X == (unknown no.) ulps of 1 -... */ + do { + U1 = X; + Y = Half * U1 + ThirtyTwo * U1 * U1; + Y = Half - Y; + X = Half + Y; + Y = Half - X; + X = Half + Y; + } while ( ! ((U1 <= X) || (X <= Zero))); + /*... now U1 == 1 ulp of 1 - ... */ + if (U1 == E1) printf("confirms closest relative separation U1 .\n"); + else printf("gets better closest relative separation U1 = %.7e .\n", U1); + W = One / U1; + F9 = (Half - U1) + Half; + Radix = FLOOR(0.01 + U2 / U1); + if (Radix == E0) printf("Radix confirmed.\n"); + else printf("MYSTERY: recalculated Radix = %.7e .\n", Radix); + TstCond (Defect, Radix <= Eight + Eight, + "Radix is too big: roundoff problems"); + TstCond (Flaw, (Radix == Two) || (Radix == 10) + || (Radix == One), "Radix is not as good as 2 or 10"); + /*=============================================*/ + Milestone = 20; + /*=============================================*/ + TstCond (Failure, F9 - Half < Half, + "(1-U1)-1/2 < 1/2 is FALSE, prog. fails?"); + X = F9; + I = 1; + Y = X - Half; + Z = Y - Half; + TstCond (Failure, (X != One) + || (Z == Zero), "Comparison is fuzzy,X=1 but X-1/2-1/2 != 0"); + X = One + U2; + I = 0; + /*=============================================*/ + Milestone = 25; + /*=============================================*/ + /*... BMinusU2 = nextafter(Radix, 0) */ + BMinusU2 = Radix - One; + BMinusU2 = (BMinusU2 - U2) + One; + /* Purify Integers */ + if (Radix != One) { + X = - TwoForty * LOG(U1) / LOG(Radix); + Y = FLOOR(Half + X); + if (FABS(X - Y) * Four < One) X = Y; + Precision = X / TwoForty; + Y = FLOOR(Half + Precision); + if (FABS(Precision - Y) * TwoForty < Half) Precision = Y; + } + if ((Precision != FLOOR(Precision)) || (Radix == One)) { + printf("Precision cannot be characterized by an Integer number\n"); + printf("of significant digits but, by itself, this is a minor flaw.\n"); + } + if (Radix == One) + printf("logarithmic encoding has precision characterized solely by U1.\n"); + else printf("The number of significant digits of the Radix is %f .\n", + Precision); + TstCond (Serious, U2 * Nine * Nine * TwoForty < One, + "Precision worse than 5 decimal figures "); + /*=============================================*/ + Milestone = 30; + /*=============================================*/ + /* Test for extra-precise subepressions */ + X = FABS(((Four / Three - One) - One / Four) * Three - One / Four); + do { + Z2 = X; + X = (One + (Half * Z2 + ThirtyTwo * Z2 * Z2)) - One; + } while ( ! ((Z2 <= X) || (X <= Zero))); + X = Y = Z = FABS((Three / Four - Two / Three) * Three - One / Four); + do { + Z1 = Z; + Z = (One / Two - ((One / Two - (Half * Z1 + ThirtyTwo * Z1 * Z1)) + + One / Two)) + One / Two; + } while ( ! ((Z1 <= Z) || (Z <= Zero))); + do { + do { + Y1 = Y; + Y = (Half - ((Half - (Half * Y1 + ThirtyTwo * Y1 * Y1)) + Half + )) + Half; + } while ( ! ((Y1 <= Y) || (Y <= Zero))); + X1 = X; + X = ((Half * X1 + ThirtyTwo * X1 * X1) - F9) + F9; + } while ( ! ((X1 <= X) || (X <= Zero))); + if ((X1 != Y1) || (X1 != Z1)) { + BadCond(Serious, "Disagreements among the values X1, Y1, Z1,\n"); + printf("respectively %.7e, %.7e, %.7e,\n", X1, Y1, Z1); + printf("are symptoms of inconsistencies introduced\n"); + printf("by extra-precise evaluation of arithmetic subexpressions.\n"); + notify("Possibly some part of this"); + if ((X1 == U1) || (Y1 == U1) || (Z1 == U1)) printf( + "That feature is not tested further by this program.\n") ; + } + else { + if ((Z1 != U1) || (Z2 != U2)) { + if ((Z1 >= U1) || (Z2 >= U2)) { + BadCond(Failure, ""); + notify("Precision"); + printf("\tU1 = %.7e, Z1 - U1 = %.7e\n",U1,Z1-U1); + printf("\tU2 = %.7e, Z2 - U2 = %.7e\n",U2,Z2-U2); + } + else { + if ((Z1 <= Zero) || (Z2 <= Zero)) { + printf("Because of unusual Radix = %f", Radix); + printf(", or exact rational arithmetic a result\n"); + printf("Z1 = %.7e, or Z2 = %.7e ", Z1, Z2); + notify("of an\nextra-precision"); + } + if (Z1 != Z2 || Z1 > Zero) { + X = Z1 / U1; + Y = Z2 / U2; + if (Y > X) X = Y; + Q = - LOG(X); + printf("Some subexpressions appear to be calculated extra\n"); + printf("precisely with about %g extra B-digits, i.e.\n", + (Q / LOG(Radix))); + printf("roughly %g extra significant decimals.\n", + Q / LOG(10.)); + } + printf("That feature is not tested further by this program.\n"); + } + } + } + Pause(); + /*=============================================*/ + /*SPLIT + } +#include "paranoia.h" +part3(){ +*/ + Milestone = 35; + /*=============================================*/ + if (Radix >= Two) { + X = W / (Radix * Radix); + Y = X + One; + Z = Y - X; + T = Z + U2; + X = T - Z; + TstCond (Failure, X == U2, + "Subtraction is not normalized X=Y,X+Z != Y+Z!"); + if (X == U2) printf( + "Subtraction appears to be normalized, as it should be."); + } + printf("\nChecking for guard digit in *, /, and -.\n"); + Y = F9 * One; + Z = One * F9; + X = F9 - Half; + Y = (Y - Half) - X; + Z = (Z - Half) - X; + X = One + U2; + T = X * Radix; + R = Radix * X; + X = T - Radix; + X = X - Radix * U2; + T = R - Radix; + T = T - Radix * U2; + X = X * (Radix - One); + T = T * (Radix - One); + if ((X == Zero) && (Y == Zero) && (Z == Zero) && (T == Zero)) GMult = Yes; + else { + GMult = No; + TstCond (Serious, False, + "* lacks a Guard Digit, so 1*X != X"); + } + Z = Radix * U2; + X = One + Z; + Y = FABS((X + Z) - X * X) - U2; + X = One - U2; + Z = FABS((X - U2) - X * X) - U1; + TstCond (Failure, (Y <= Zero) + && (Z <= Zero), "* gets too many final digits wrong.\n"); + Y = One - U2; + X = One + U2; + Z = One / Y; + Y = Z - X; + X = One / Three; + Z = Three / Nine; + X = X - Z; + T = Nine / TwentySeven; + Z = Z - T; + TstCond(Defect, X == Zero && Y == Zero && Z == Zero, + "Division lacks a Guard Digit, so error can exceed 1 ulp\nor 1/3 and 3/9 and 9/27 may disagree"); + Y = F9 / One; + X = F9 - Half; + Y = (Y - Half) - X; + X = One + U2; + T = X / One; + X = T - X; + if ((X == Zero) && (Y == Zero) && (Z == Zero)) GDiv = Yes; + else { + GDiv = No; + TstCond (Serious, False, + "Division lacks a Guard Digit, so X/1 != X"); + } + X = One / (One + U2); + Y = X - Half - Half; + TstCond (Serious, Y < Zero, + "Computed value of 1/1.000..1 >= 1"); + X = One - U2; + Y = One + Radix * U2; + Z = X * Radix; + T = Y * Radix; + R = Z / Radix; + StickyBit = T / Radix; + X = R - X; + Y = StickyBit - Y; + TstCond (Failure, X == Zero && Y == Zero, + "* and/or / gets too many last digits wrong"); + Y = One - U1; + X = One - F9; + Y = One - Y; + T = Radix - U2; + Z = Radix - BMinusU2; + T = Radix - T; + if ((X == U1) && (Y == U1) && (Z == U2) && (T == U2)) GAddSub = Yes; + else { + GAddSub = No; + TstCond (Serious, False, + "- lacks Guard Digit, so cancellation is obscured"); + } + if (F9 != One && F9 - One >= Zero) { + BadCond(Serious, "comparison alleges (1-U1) < 1 although\n"); + printf(" subtraction yields (1-U1) - 1 = 0 , thereby vitiating\n"); + printf(" such precautions against division by zero as\n"); + printf(" ... if (X == 1.0) {.....} else {.../(X-1.0)...}\n"); + } + if (GMult == Yes && GDiv == Yes && GAddSub == Yes) printf( + " *, /, and - appear to have guard digits, as they should.\n"); + /*=============================================*/ + Milestone = 40; + /*=============================================*/ + Pause(); + printf("Checking rounding on multiply, divide and add/subtract.\n"); + RMult = Other; + RDiv = Other; + RAddSub = Other; + RadixD2 = Radix / Two; + A1 = Two; + Done = False; + do { + AInvrse = Radix; + do { + X = AInvrse; + AInvrse = AInvrse / A1; + } while ( ! (FLOOR(AInvrse) != AInvrse)); + Done = (X == One) || (A1 > Three); + if (! Done) A1 = Nine + One; + } while ( ! (Done)); + if (X == One) A1 = Radix; + AInvrse = One / A1; + X = A1; + Y = AInvrse; + Done = False; + do { + Z = X * Y - Half; + TstCond (Failure, Z == Half, + "X * (1/X) differs from 1"); + Done = X == Radix; + X = Radix; + Y = One / X; + } while ( ! (Done)); + Y2 = One + U2; + Y1 = One - U2; + X = OneAndHalf - U2; + Y = OneAndHalf + U2; + Z = (X - U2) * Y2; + T = Y * Y1; + Z = Z - X; + T = T - X; + X = X * Y2; + Y = (Y + U2) * Y1; + X = X - OneAndHalf; + Y = Y - OneAndHalf; + if ((X == Zero) && (Y == Zero) && (Z == Zero) && (T <= Zero)) { + X = (OneAndHalf + U2) * Y2; + Y = OneAndHalf - U2 - U2; + Z = OneAndHalf + U2 + U2; + T = (OneAndHalf - U2) * Y1; + X = X - (Z + U2); + StickyBit = Y * Y1; + S = Z * Y2; + T = T - Y; + Y = (U2 - Y) + StickyBit; + Z = S - (Z + U2 + U2); + StickyBit = (Y2 + U2) * Y1; + Y1 = Y2 * Y1; + StickyBit = StickyBit - Y2; + Y1 = Y1 - Half; + if ((X == Zero) && (Y == Zero) && (Z == Zero) && (T == Zero) + && ( StickyBit == Zero) && (Y1 == Half)) { + RMult = Rounded; + printf("Multiplication appears to round correctly.\n"); + } + else if ((X + U2 == Zero) && (Y < Zero) && (Z + U2 == Zero) + && (T < Zero) && (StickyBit + U2 == Zero) + && (Y1 < Half)) { + RMult = Chopped; + printf("Multiplication appears to chop.\n"); + } + else printf("* is neither chopped nor correctly rounded.\n"); + if ((RMult == Rounded) && (GMult == No)) notify("Multiplication"); + } + else printf("* is neither chopped nor correctly rounded.\n"); + /*=============================================*/ + Milestone = 45; + /*=============================================*/ + Y2 = One + U2; + Y1 = One - U2; + Z = OneAndHalf + U2 + U2; + X = Z / Y2; + T = OneAndHalf - U2 - U2; + Y = (T - U2) / Y1; + Z = (Z + U2) / Y2; + X = X - OneAndHalf; + Y = Y - T; + T = T / Y1; + Z = Z - (OneAndHalf + U2); + T = (U2 - OneAndHalf) + T; + if (! ((X > Zero) || (Y > Zero) || (Z > Zero) || (T > Zero))) { + X = OneAndHalf / Y2; + Y = OneAndHalf - U2; + Z = OneAndHalf + U2; + X = X - Y; + T = OneAndHalf / Y1; + Y = Y / Y1; + T = T - (Z + U2); + Y = Y - Z; + Z = Z / Y2; + Y1 = (Y2 + U2) / Y2; + Z = Z - OneAndHalf; + Y2 = Y1 - Y2; + Y1 = (F9 - U1) / F9; + if ((X == Zero) && (Y == Zero) && (Z == Zero) && (T == Zero) + && (Y2 == Zero) && (Y2 == Zero) + && (Y1 - Half == F9 - Half )) { + RDiv = Rounded; + printf("Division appears to round correctly.\n"); + if (GDiv == No) notify("Division"); + } + else if ((X < Zero) && (Y < Zero) && (Z < Zero) && (T < Zero) + && (Y2 < Zero) && (Y1 - Half < F9 - Half)) { + RDiv = Chopped; + printf("Division appears to chop.\n"); + } + } + if (RDiv == Other) printf("/ is neither chopped nor correctly rounded.\n"); + BInvrse = One / Radix; + TstCond (Failure, (BInvrse * Radix - Half == Half), + "Radix * ( 1 / Radix ) differs from 1"); + /*=============================================*/ + /*SPLIT + } +#include "paranoia.h" +part4(){ +*/ + Milestone = 50; + /*=============================================*/ + TstCond (Failure, ((F9 + U1) - Half == Half) + && ((BMinusU2 + U2 ) - One == Radix - One), + "Incomplete carry-propagation in Addition"); + X = One - U1 * U1; + Y = One + U2 * (One - U2); + Z = F9 - Half; + X = (X - Half) - Z; + Y = Y - One; + if ((X == Zero) && (Y == Zero)) { + RAddSub = Chopped; + printf("Add/Subtract appears to be chopped.\n"); + } + if (GAddSub == Yes) { + X = (Half + U2) * U2; + Y = (Half - U2) * U2; + X = One + X; + Y = One + Y; + X = (One + U2) - X; + Y = One - Y; + if ((X == Zero) && (Y == Zero)) { + X = (Half + U2) * U1; + Y = (Half - U2) * U1; + X = One - X; + Y = One - Y; + X = F9 - X; + Y = One - Y; + if ((X == Zero) && (Y == Zero)) { + RAddSub = Rounded; + printf("Addition/Subtraction appears to round correctly.\n"); + if (GAddSub == No) notify("Add/Subtract"); + } + else printf("Addition/Subtraction neither rounds nor chops.\n"); + } + else printf("Addition/Subtraction neither rounds nor chops.\n"); + } + else printf("Addition/Subtraction neither rounds nor chops.\n"); + S = One; + X = One + Half * (One + Half); + Y = (One + U2) * Half; + Z = X - Y; + T = Y - X; + StickyBit = Z + T; + if (StickyBit != Zero) { + S = Zero; + BadCond(Flaw, "(X - Y) + (Y - X) is non zero!\n"); + } + StickyBit = Zero; + if ((GMult == Yes) && (GDiv == Yes) && (GAddSub == Yes) + && (RMult == Rounded) && (RDiv == Rounded) + && (RAddSub == Rounded) && (FLOOR(RadixD2) == RadixD2)) { + printf("Checking for sticky bit.\n"); + X = (Half + U1) * U2; + Y = Half * U2; + Z = One + Y; + T = One + X; + if ((Z - One <= Zero) && (T - One >= U2)) { + Z = T + Y; + Y = Z - X; + if ((Z - T >= U2) && (Y - T == Zero)) { + X = (Half + U1) * U1; + Y = Half * U1; + Z = One - Y; + T = One - X; + if ((Z - One == Zero) && (T - F9 == Zero)) { + Z = (Half - U1) * U1; + T = F9 - Z; + Q = F9 - Y; + if ((T - F9 == Zero) && (F9 - U1 - Q == Zero)) { + Z = (One + U2) * OneAndHalf; + T = (OneAndHalf + U2) - Z + U2; + X = One + Half / Radix; + Y = One + Radix * U2; + Z = X * Y; + if (T == Zero && X + Radix * U2 - Z == Zero) { + if (Radix != Two) { + X = Two + U2; + Y = X / Two; + if ((Y - One == Zero)) StickyBit = S; + } + else StickyBit = S; + } + } + } + } + } + } + if (StickyBit == One) printf("Sticky bit apparently used correctly.\n"); + else printf("Sticky bit used incorrectly or not at all.\n"); + TstCond (Flaw, !(GMult == No || GDiv == No || GAddSub == No || + RMult == Other || RDiv == Other || RAddSub == Other), + "lack(s) of guard digits or failure(s) to correctly round or chop\n(noted above) count as one flaw in the final tally below"); + /*=============================================*/ + Milestone = 60; + /*=============================================*/ + printf("\n"); + printf("Does Multiplication commute? "); + printf("Testing on %d random pairs.\n", NoTrials); + Random9 = SQRT(3.0); + Random1 = Third; + I = 1; + do { + X = Random(); + Y = Random(); + Z9 = Y * X; + Z = X * Y; + Z9 = Z - Z9; + I = I + 1; + } while ( ! ((I > NoTrials) || (Z9 != Zero))); + if (I == NoTrials) { + Random1 = One + Half / Three; + Random2 = (U2 + U1) + One; + Z = Random1 * Random2; + Y = Random2 * Random1; + Z9 = (One + Half / Three) * ((U2 + U1) + One) - (One + Half / + Three) * ((U2 + U1) + One); + } + if (! ((I == NoTrials) || (Z9 == Zero))) + BadCond(Defect, "X * Y == Y * X trial fails.\n"); + else printf(" No failures found in %d integer pairs.\n", NoTrials); + /*=============================================*/ + Milestone = 70; + /*=============================================*/ + printf("\nRunning test of square root(x).\n"); + TstCond (Failure, (Zero == SQRT(Zero)) + && (- Zero == SQRT(- Zero)) + && (One == SQRT(One)), "Square root of 0.0, -0.0 or 1.0 wrong"); + MinSqEr = Zero; + MaxSqEr = Zero; + J = Zero; + X = Radix; + OneUlp = U2; + SqXMinX (Serious); + X = BInvrse; + OneUlp = BInvrse * U1; + SqXMinX (Serious); + X = U1; + OneUlp = U1 * U1; + SqXMinX (Serious); + if (J != Zero) Pause(); + printf("Testing if sqrt(X * X) == X for %d Integers X.\n", NoTrials); + J = Zero; + X = Two; + Y = Radix; + if ((Radix != One)) do { + X = Y; + Y = Radix * Y; + } while ( ! ((Y - X >= NoTrials))); + OneUlp = X * U2; + I = 1; + while (I <= NoTrials) { + X = X + One; + SqXMinX (Defect); + if (J > Zero) break; + I = I + 1; + } + printf("Test for sqrt monotonicity.\n"); + I = - 1; + X = BMinusU2; + Y = Radix; + Z = Radix + Radix * U2; + NotMonot = False; + Monot = False; + while ( ! (NotMonot || Monot)) { + I = I + 1; + X = SQRT(X); + Q = SQRT(Y); + Z = SQRT(Z); + if ((X > Q) || (Q > Z)) NotMonot = True; + else { + Q = FLOOR(Q + Half); + if ((I > 0) || (Radix == Q * Q)) Monot = True; + else if (I > 0) { + if (I > 1) Monot = True; + else { + Y = Y * BInvrse; + X = Y - U1; + Z = Y + U1; + } + } + else { + Y = Q; + X = Y - U2; + Z = Y + U2; + } + } + } + if (Monot) printf("sqrt has passed a test for Monotonicity.\n"); + else { + BadCond(Defect, ""); + printf("sqrt(X) is non-monotonic for X near %.7e .\n", Y); + } + /*=============================================*/ + /*SPLIT + } +#include "paranoia.h" +part5(){ +*/ + Milestone = 80; + /*=============================================*/ + MinSqEr = MinSqEr + Half; + MaxSqEr = MaxSqEr - Half; + Y = (SQRT(One + U2) - One) / U2; + SqEr = (Y - One) + U2 / Eight; + if (SqEr > MaxSqEr) MaxSqEr = SqEr; + SqEr = Y + U2 / Eight; + if (SqEr < MinSqEr) MinSqEr = SqEr; + Y = ((SQRT(F9) - U2) - (One - U2)) / U1; + SqEr = Y + U1 / Eight; + if (SqEr > MaxSqEr) MaxSqEr = SqEr; + SqEr = (Y + One) + U1 / Eight; + if (SqEr < MinSqEr) MinSqEr = SqEr; + OneUlp = U2; + X = OneUlp; + for( Indx = 1; Indx <= 3; ++Indx) { + Y = SQRT((X + U1 + X) + F9); + Y = ((Y - U2) - ((One - U2) + X)) / OneUlp; + Z = ((U1 - X) + F9) * Half * X * X / OneUlp; + SqEr = (Y + Half) + Z; + if (SqEr < MinSqEr) MinSqEr = SqEr; + SqEr = (Y - Half) + Z; + if (SqEr > MaxSqEr) MaxSqEr = SqEr; + if (((Indx == 1) || (Indx == 3))) + X = OneUlp * Sign (X) * FLOOR(Eight / (Nine * SQRT(OneUlp))); + else { + OneUlp = U1; + X = - OneUlp; + } + } + /*=============================================*/ + Milestone = 85; + /*=============================================*/ + SqRWrng = False; + Anomaly = False; + RSqrt = Other; /* ~dgh */ + if (Radix != One) { + printf("Testing whether sqrt is rounded or chopped.\n"); + D = FLOOR(Half + POW(Radix, One + Precision - FLOOR(Precision))); + /* ... == Radix^(1 + fract) if (Precision == Integer + fract. */ + X = D / Radix; + Y = D / A1; + if ((X != FLOOR(X)) || (Y != FLOOR(Y))) { + Anomaly = True; + } + else { + X = Zero; + Z2 = X; + Y = One; + Y2 = Y; + Z1 = Radix - One; + FourD = Four * D; + do { + if (Y2 > Z2) { + Q = Radix; + Y1 = Y; + do { + X1 = FABS(Q + FLOOR(Half - Q / Y1) * Y1); + Q = Y1; + Y1 = X1; + } while ( ! (X1 <= Zero)); + if (Q <= One) { + Z2 = Y2; + Z = Y; + } + } + Y = Y + Two; + X = X + Eight; + Y2 = Y2 + X; + if (Y2 >= FourD) Y2 = Y2 - FourD; + } while ( ! (Y >= D)); + X8 = FourD - Z2; + Q = (X8 + Z * Z) / FourD; + X8 = X8 / Eight; + if (Q != FLOOR(Q)) Anomaly = True; + else { + Break = False; + do { + X = Z1 * Z; + X = X - FLOOR(X / Radix) * Radix; + if (X == One) + Break = True; + else + Z1 = Z1 - One; + } while ( ! (Break || (Z1 <= Zero))); + if ((Z1 <= Zero) && (! Break)) Anomaly = True; + else { + if (Z1 > RadixD2) Z1 = Z1 - Radix; + do { + NewD(); + } while ( ! (U2 * D >= F9)); + if (D * Radix - D != W - D) Anomaly = True; + else { + Z2 = D; + I = 0; + Y = D + (One + Z) * Half; + X = D + Z + Q; + SR3750(); + Y = D + (One - Z) * Half + D; + X = D - Z + D; + X = X + Q + X; + SR3750(); + NewD(); + if (D - Z2 != W - Z2) Anomaly = True; + else { + Y = (D - Z2) + (Z2 + (One - Z) * Half); + X = (D - Z2) + (Z2 - Z + Q); + SR3750(); + Y = (One + Z) * Half; + X = Q; + SR3750(); + if (I == 0) Anomaly = True; + } + } + } + } + } + if ((I == 0) || Anomaly) { + BadCond(Failure, "Anomalous arithmetic with Integer < "); + printf("Radix^Precision = %.7e\n", W); + printf(" fails test whether sqrt rounds or chops.\n"); + SqRWrng = True; + } + } + if (! Anomaly) { + if (! ((MinSqEr < Zero) || (MaxSqEr > Zero))) { + RSqrt = Rounded; + printf("Square root appears to be correctly rounded.\n"); + } + else { + if ((MaxSqEr + U2 > U2 - Half) || (MinSqEr > Half) + || (MinSqEr + Radix < Half)) SqRWrng = True; + else { + RSqrt = Chopped; + printf("Square root appears to be chopped.\n"); + } + } + } + if (SqRWrng) { + printf("Square root is neither chopped nor correctly rounded.\n"); + printf("Observed errors run from %.7e ", MinSqEr - Half); + printf("to %.7e ulps.\n", Half + MaxSqEr); + TstCond (Serious, MaxSqEr - MinSqEr < Radix * Radix, + "sqrt gets too many last digits wrong"); + } + /*=============================================*/ + Milestone = 90; + /*=============================================*/ + Pause(); + printf("Testing powers Z^i for small Integers Z and i.\n"); + N = 0; + /* ... test powers of zero. */ + I = 0; + Z = -Zero; + M = 3.0; + Break = False; + do { + X = One; + SR3980(); + if (I <= 10) { + I = 1023; + SR3980(); + } + if (Z == MinusOne) Break = True; + else { + Z = MinusOne; + PrintIfNPositive(); + N = 0; + /* .. if(-1)^N is invalid, replace MinusOne by One. */ + I = - 4; + } + } while ( ! Break); + PrintIfNPositive(); + N1 = N; + N = 0; + Z = A1; + M = FLOOR(Two * LOG(W) / LOG(A1)); + Break = False; + do { + X = Z; + I = 1; + SR3980(); + if (Z == AInvrse) Break = True; + else Z = AInvrse; + } while ( ! (Break)); + /*=============================================*/ + Milestone = 100; + /*=============================================*/ + /* Powers of Radix have been tested, */ + /* next try a few primes */ + M = NoTrials; + Z = Three; + do { + X = Z; + I = 1; + SR3980(); + do { + Z = Z + Two; + } while ( Three * FLOOR(Z / Three) == Z ); + } while ( Z < Eight * Three ); + if (N > 0) { + printf("Errors like this may invalidate financial calculations\n"); + printf("\tinvolving interest rates.\n"); + } + PrintIfNPositive(); + N += N1; + if (N == 0) printf("... no discrepancis found.\n"); + if (N > 0) Pause(); + else printf("\n"); + /*=============================================*/ + /*SPLIT + } +#include "paranoia.h" +part6(){ +*/ + Milestone = 110; + /*=============================================*/ + printf("Seeking Underflow thresholds UfThold and E0.\n"); + D = U1; + if (Precision != FLOOR(Precision)) { + D = BInvrse; + X = Precision; + do { + D = D * BInvrse; + X = X - One; + } while ( X > Zero); + } + Y = One; + Z = D; + /* ... D is power of 1/Radix < 1. */ + do { + C = Y; + Y = Z; + Z = Y * Y; + } while ((Y > Z) && (Z + Z > Z)); + Y = C; + Z = Y * D; + do { + C = Y; + Y = Z; + Z = Y * D; + } while ((Y > Z) && (Z + Z > Z)); + if (Radix < Two) HInvrse = Two; + else HInvrse = Radix; + H = One / HInvrse; + /* ... 1/HInvrse == H == Min(1/Radix, 1/2) */ + CInvrse = One / C; + E0 = C; + Z = E0 * H; + /* ...1/Radix^(BIG Integer) << 1 << CInvrse == 1/C */ + do { + Y = E0; + E0 = Z; + Z = E0 * H; + } while ((E0 > Z) && (Z + Z > Z)); + UfThold = E0; + E1 = Zero; + Q = Zero; + E9 = U2; + S = One + E9; + D = C * S; + if (D <= C) { + E9 = Radix * U2; + S = One + E9; + D = C * S; + if (D <= C) { + BadCond(Failure, "multiplication gets too many last digits wrong.\n"); + Underflow = E0; + Y1 = Zero; + PseudoZero = Z; + Pause(); + } + } + else { + Underflow = D; + PseudoZero = Underflow * H; + UfThold = Zero; + do { + Y1 = Underflow; + Underflow = PseudoZero; + if (E1 + E1 <= E1) { + Y2 = Underflow * HInvrse; + E1 = FABS(Y1 - Y2); + Q = Y1; + if ((UfThold == Zero) && (Y1 != Y2)) UfThold = Y1; + } + PseudoZero = PseudoZero * H; + } while ((Underflow > PseudoZero) + && (PseudoZero + PseudoZero > PseudoZero)); + } + /* Comment line 4530 .. 4560 */ + if (PseudoZero != Zero) { + printf("\n"); + Z = PseudoZero; + /* ... Test PseudoZero for "phoney- zero" violates */ + /* ... PseudoZero < Underflow or PseudoZero < PseudoZero + PseudoZero + ... */ + if (PseudoZero <= Zero) { + BadCond(Failure, "Positive expressions can underflow to an\n"); + printf("allegedly negative value\n"); + printf("PseudoZero that prints out as: %g .\n", PseudoZero); + X = - PseudoZero; + if (X <= Zero) { + printf("But -PseudoZero, which should be\n"); + printf("positive, isn't; it prints out as %g .\n", X); + } + } + else { + BadCond(Flaw, "Underflow can stick at an allegedly positive\n"); + printf("value PseudoZero that prints out as %g .\n", PseudoZero); + } + TstPtUf(); + } + /*=============================================*/ + Milestone = 120; + /*=============================================*/ + if (CInvrse * Y > CInvrse * Y1) { + S = H * S; + E0 = Underflow; + } + if (! ((E1 == Zero) || (E1 == E0))) { + BadCond(Defect, ""); + if (E1 < E0) { + printf("Products underflow at a higher"); + printf(" threshold than differences.\n"); + if (PseudoZero == Zero) + E0 = E1; + } + else { + printf("Difference underflows at a higher"); + printf(" threshold than products.\n"); + } + } + printf("Smallest strictly positive number found is E0 = %g .\n", E0); + Z = E0; + TstPtUf(); + Underflow = E0; + if (N == 1) Underflow = Y; + I = 4; + if (E1 == Zero) I = 3; + if (UfThold == Zero) I = I - 2; + UfNGrad = True; + switch (I) { + case 1: + UfThold = Underflow; + if ((CInvrse * Q) != ((CInvrse * Y) * S)) { + UfThold = Y; + BadCond(Failure, "Either accuracy deteriorates as numbers\n"); + printf("approach a threshold = %.17e\n", UfThold);; + printf(" coming down from %.17e\n", C); + printf(" or else multiplication gets too many last digits wrong.\n"); + } + Pause(); + break; + + case 2: + BadCond(Failure, "Underflow confuses Comparison, which alleges that\n"); + printf("Q == Y while denying that |Q - Y| == 0; these values\n"); + printf("print out as Q = %.17e, Y = %.17e .\n", Q, Y2); + printf ("|Q - Y| = %.17e .\n" , FABS(Q - Y2)); + UfThold = Q; + break; + + case 3: + X = X; + break; + + case 4: + if ((Q == UfThold) && (E1 == E0) + && (FABS( UfThold - E1 / E9) <= E1)) { + UfNGrad = False; + printf("Underflow is gradual; it incurs Absolute Error =\n"); + printf("(roundoff in UfThold) < E0.\n"); + Y = E0 * CInvrse; + Y = Y * (OneAndHalf + U2); + X = CInvrse * (One + U2); + Y = Y / X; + IEEE = (Y == E0); + } + } + if (UfNGrad) { + printf("\n"); + sigsave = sigfpe; + if (setjmp(ovfl_buf)) { + printf("Underflow / UfThold failed!\n"); + R = H + H; + } + else R = SQRT(Underflow / UfThold); + sigsave = 0; + if (R <= H) { + Z = R * UfThold; + X = Z * (One + R * H * (One + H)); + } + else { + Z = UfThold; + X = Z * (One + H * H * (One + H)); + } + if (! ((X == Z) || (X - Z != Zero))) { + BadCond(Flaw, ""); + printf("X = %.17e\n\tis not equal to Z = %.17e .\n", X, Z); + Z9 = X - Z; + printf("yet X - Z yields %.17e .\n", Z9); + printf(" Should this NOT signal Underflow, "); + printf("this is a SERIOUS DEFECT\nthat causes "); + printf("confusion when innocent statements like\n");; + printf(" if (X == Z) ... else"); + printf(" ... (f(X) - f(Z)) / (X - Z) ...\n"); + printf("encounter Division by Zero although actually\n"); + sigsave = sigfpe; + if (setjmp(ovfl_buf)) printf("X / Z fails!\n"); + else printf("X / Z = 1 + %g .\n", (X / Z - Half) - Half); + sigsave = 0; + } + } + printf("The Underflow threshold is %.17e, %s\n", UfThold, + " below which"); + printf("calculation may suffer larger Relative error than "); + printf("merely roundoff.\n"); + Y2 = U1 * U1; + Y = Y2 * Y2; + Y2 = Y * U1; + if (Y2 <= UfThold) { + if (Y > E0) { + BadCond(Defect, ""); + I = 5; + } + else { + BadCond(Serious, ""); + I = 4; + } + printf("Range is too narrow; U1^%d Underflows.\n", I); + } + /*=============================================*/ + /*SPLIT + } +#include "paranoia.h" +part7(){ +*/ + Milestone = 130; + /*=============================================*/ + Y = - FLOOR(Half - TwoForty * LOG(UfThold) / LOG(HInvrse)) / TwoForty; + Y2 = Y + Y; + printf("Since underflow occurs below the threshold\n"); + printf("UfThold = (%.17e) ^ (%.17e)\nonly underflow ", HInvrse, Y); + printf("should afflict the expression\n\t(%.17e) ^ (%.17e);\n", HInvrse, Y); + V9 = POW(HInvrse, Y2); + printf("actually calculating yields: %.17e .\n", V9); + if (! ((V9 >= Zero) && (V9 <= (Radix + Radix + E9) * UfThold))) { + BadCond(Serious, "this is not between 0 and underflow\n"); + printf(" threshold = %.17e .\n", UfThold); + } + else if (! (V9 > UfThold * (One + E9))) + printf("This computed value is O.K.\n"); + else { + BadCond(Defect, "this is not between 0 and underflow\n"); + printf(" threshold = %.17e .\n", UfThold); + } + /*=============================================*/ + Milestone = 140; + /*=============================================*/ + printf("\n"); + /* ...calculate Exp2 == exp(2) == 7.389056099... */ + X = Zero; + I = 2; + Y = Two * Three; + Q = Zero; + N = 0; + do { + Z = X; + I = I + 1; + Y = Y / (I + I); + R = Y + Q; + X = Z + R; + Q = (Z - X) + R; + } while(X > Z); + Z = (OneAndHalf + One / Eight) + X / (OneAndHalf * ThirtyTwo); + X = Z * Z; + Exp2 = X * X; + X = F9; + Y = X - U1; + printf("Testing X^((X + 1) / (X - 1)) vs. exp(2) = %.17e as X -> 1.\n", + Exp2); + for(I = 1;;) { + Z = X - BInvrse; + Z = (X + One) / (Z - (One - BInvrse)); + Q = POW(X, Z) - Exp2; + if (FABS(Q) > TwoForty * U2) { + N = 1; + V9 = (X - BInvrse) - (One - BInvrse); + BadCond(Defect, "Calculated"); + printf(" %.17e for\n", POW(X,Z)); + printf("\t(1 + (%.17e) ^ (%.17e);\n", V9, Z); + printf("\tdiffers from correct value by %.17e .\n", Q); + printf("\tThis much error may spoil financial\n"); + printf("\tcalculations involving tiny interest rates.\n"); + break; + } + else { + Z = (Y - X) * Two + Y; + X = Y; + Y = Z; + Z = One + (X - F9)*(X - F9); + if (Z > One && I < NoTrials) I++; + else { + if (X > One) { + if (N == 0) + printf("Accuracy seems adequate.\n"); + break; + } + else { + X = One + U2; + Y = U2 + U2; + Y += X; + I = 1; + } + } + } + } + /*=============================================*/ + Milestone = 150; + /*=============================================*/ + printf("Testing powers Z^Q at four nearly extreme values.\n"); + N = 0; + Z = A1; + Q = FLOOR(Half - LOG(C) / LOG(A1)); + Break = False; + do { + X = CInvrse; + Y = POW(Z, Q); + IsYeqX(); + Q = - Q; + X = C; + Y = POW(Z, Q); + IsYeqX(); + if (Z < One) Break = True; + else Z = AInvrse; + } while ( ! (Break)); + PrintIfNPositive(); + if (N == 0) printf(" ... no discrepancies found.\n"); + printf("\n"); + + /*=============================================*/ + Milestone = 160; + /*=============================================*/ + Pause(); + printf("Searching for Overflow threshold:\n"); + printf("This may generate an error.\n"); + Y = - CInvrse; + V9 = HInvrse * Y; + sigsave = sigfpe; + if (setjmp(ovfl_buf)) { I = 0; V9 = Y; goto overflow; } + do { + V = Y; + Y = V9; + V9 = HInvrse * Y; + } while(V9 < Y); + I = 1; +overflow: + sigsave = 0; + Z = V9; + printf("Can `Z = -Y' overflow?\n"); + printf("Trying it on Y = %.17e .\n", Y); + V9 = - Y; + V0 = V9; + if (V - Y == V + V0) printf("Seems O.K.\n"); + else { + printf("finds a "); + BadCond(Flaw, "-(-Y) differs from Y.\n"); + } + if (Z != Y) { + BadCond(Serious, ""); + printf("overflow past %.17e\n\tshrinks to %.17e .\n", Y, Z); + } + if (I) { + Y = V * (HInvrse * U2 - HInvrse); + Z = Y + ((One - HInvrse) * U2) * V; + if (Z < V0) Y = Z; + if (Y < V0) V = Y; + if (V0 - V < V0) V = V0; + } + else { + V = Y * (HInvrse * U2 - HInvrse); + V = V + ((One - HInvrse) * U2) * Y; + } + printf("Overflow threshold is V = %.17e .\n", V); + if (I) printf("Overflow saturates at V0 = %.17e .\n", V0); + else printf("There is no saturation value because the system traps on overflow.\n"); + V9 = V * One; + printf("No Overflow should be signaled for V * 1 = %.17e\n", V9); + V9 = V / One; + printf(" nor for V / 1 = %.17e .\n", V9); + printf("Any overflow signal separating this * from the one\n"); + printf("above is a DEFECT.\n"); + /*=============================================*/ + Milestone = 170; + /*=============================================*/ + if (!(-V < V && -V0 < V0 && -UfThold < V && UfThold < V)) { + BadCond(Failure, "Comparisons involving "); + printf("+-%g, +-%g\nand +-%g are confused by Overflow.", + V, V0, UfThold); + } + /*=============================================*/ + Milestone = 175; + /*=============================================*/ + printf("\n"); + for(Indx = 1; Indx <= 3; ++Indx) { + switch (Indx) { + case 1: Z = UfThold; break; + case 2: Z = E0; break; + case 3: Z = PseudoZero; break; + } + if (Z != Zero) { + V9 = SQRT(Z); + Y = V9 * V9; + if (Y / (One - Radix * E9) < Z + || Y > (One + Radix * E9) * Z) { /* dgh: + E9 --> * E9 */ + if (V9 > U1) BadCond(Serious, ""); + else BadCond(Defect, ""); + printf("Comparison alleges that what prints as Z = %.17e\n", Z); + printf(" is too far from sqrt(Z) ^ 2 = %.17e .\n", Y); + } + } + } + /*=============================================*/ + Milestone = 180; + /*=============================================*/ + for(Indx = 1; Indx <= 2; ++Indx) { + if (Indx == 1) Z = V; + else Z = V0; + V9 = SQRT(Z); + X = (One - Radix * E9) * V9; + V9 = V9 * X; + if (((V9 < (One - Two * Radix * E9) * Z) || (V9 > Z))) { + Y = V9; + if (X < W) BadCond(Serious, ""); + else BadCond(Defect, ""); + printf("Comparison alleges that Z = %17e\n", Z); + printf(" is too far from sqrt(Z) ^ 2 (%.17e) .\n", Y); + } + } + /*=============================================*/ + /*SPLIT + } +#include "paranoia.h" +part8(){ +*/ + Milestone = 190; + /*=============================================*/ + Pause(); + X = UfThold * V; + Y = Radix * Radix; + if (X*Y < One || X > Y) { + if (X * Y < U1 || X > Y/U1) BadCond(Defect, "Badly"); + else BadCond(Flaw, ""); + + printf(" unbalanced range; UfThold * V = %.17e\n\t%s\n", + X, "is too far from 1.\n"); + } + /*=============================================*/ + Milestone = 200; + /*=============================================*/ + for (Indx = 1; Indx <= 5; ++Indx) { + X = F9; + switch (Indx) { + case 2: X = One + U2; break; + case 3: X = V; break; + case 4: X = UfThold; break; + case 5: X = Radix; + } + Y = X; + sigsave = sigfpe; + if (setjmp(ovfl_buf)) + printf(" X / X traps when X = %g\n", X); + else { + V9 = (Y / X - Half) - Half; + if (V9 == Zero) continue; + if (V9 == - U1 && Indx < 5) BadCond(Flaw, ""); + else BadCond(Serious, ""); + printf(" X / X differs from 1 when X = %.17e\n", X); + printf(" instead, X / X - 1/2 - 1/2 = %.17e .\n", V9); + } + sigsave = 0; + } + /*=============================================*/ + Milestone = 210; + /*=============================================*/ + MyZero = Zero; + printf("\n"); + printf("What message and/or values does Division by Zero produce?\n") ; +#ifndef NOPAUSE + printf("This can interupt your program. You can "); + printf("skip this part if you wish.\n"); + printf("Do you wish to compute 1 / 0? "); + fflush(stdout); + read (KEYBOARD, ch, 8); + if ((ch[0] == 'Y') || (ch[0] == 'y')) { +#endif + sigsave = sigfpe; + printf(" Trying to compute 1 / 0 produces ..."); + if (!setjmp(ovfl_buf)) printf(" %.7e .\n", One / MyZero); + sigsave = 0; +#ifndef NOPAUSE + } + else printf("O.K.\n"); + printf("\nDo you wish to compute 0 / 0? "); + fflush(stdout); + read (KEYBOARD, ch, 80); + if ((ch[0] == 'Y') || (ch[0] == 'y')) { +#endif + sigsave = sigfpe; + printf("\n Trying to compute 0 / 0 produces ..."); + if (!setjmp(ovfl_buf)) printf(" %.7e .\n", Zero / MyZero); + sigsave = 0; +#ifndef NOPAUSE + } + else printf("O.K.\n"); +#endif + /*=============================================*/ + Milestone = 220; + /*=============================================*/ + Pause(); + printf("\n"); + { + static char *msg[] = { + "FAILUREs encountered =", + "SERIOUS DEFECTs discovered =", + "DEFECTs discovered =", + "FLAWs discovered =" }; + int i; + for(i = 0; i < 4; i++) if (ErrCnt[i]) + printf("The number of %-29s %d.\n", + msg[i], ErrCnt[i]); + } + printf("\n"); + if ((ErrCnt[Failure] + ErrCnt[Serious] + ErrCnt[Defect] + + ErrCnt[Flaw]) > 0) { + if ((ErrCnt[Failure] + ErrCnt[Serious] + ErrCnt[ + Defect] == 0) && (ErrCnt[Flaw] > 0)) { + printf("The arithmetic diagnosed seems "); + printf("Satisfactory though flawed.\n"); + } + if ((ErrCnt[Failure] + ErrCnt[Serious] == 0) + && ( ErrCnt[Defect] > 0)) { + printf("The arithmetic diagnosed may be Acceptable\n"); + printf("despite inconvenient Defects.\n"); + } + if ((ErrCnt[Failure] + ErrCnt[Serious]) > 0) { + printf("The arithmetic diagnosed has "); + printf("unacceptable Serious Defects.\n"); + } + if (ErrCnt[Failure] > 0) { + printf("Potentially fatal FAILURE may have spoiled this"); + printf(" program's subsequent diagnoses.\n"); + } + } + else { + printf("No failures, defects nor flaws have been discovered.\n"); + if (! ((RMult == Rounded) && (RDiv == Rounded) + && (RAddSub == Rounded) && (RSqrt == Rounded))) + printf("The arithmetic diagnosed seems Satisfactory.\n"); + else { + if (StickyBit >= One && + (Radix - Two) * (Radix - Nine - One) == Zero) { + printf("Rounding appears to conform to "); + printf("the proposed IEEE standard P"); + if ((Radix == Two) && + ((Precision - Four * Three * Two) * + ( Precision - TwentySeven - + TwentySeven + One) == Zero)) + printf("754"); + else printf("854"); + if (IEEE) printf(".\n"); + else { + printf(",\nexcept for possibly Double Rounding"); + printf(" during Gradual Underflow.\n"); + } + } + printf("The arithmetic diagnosed appears to be Excellent!\n"); + } + } + if (fpecount) + printf("\nA total of %d floating point exceptions were registered.\n", + fpecount); + printf("END OF TEST.\n"); + return 0; + } + +/*SPLIT subs.c +#include "paranoia.h" +*/ + +/* Sign */ + +FLOAT Sign (X) +FLOAT X; +{ return X >= 0. ? 1.0 : -1.0; } + +/* Pause */ + +Pause() +{ +#ifndef NOPAUSE + char ch[8]; + + printf("\nTo continue, press RETURN"); + fflush(stdout); + read(KEYBOARD, ch, 8); +#endif + printf("\nDiagnosis resumes after milestone Number %d", Milestone); + printf(" Page: %d\n\n", PageNo); + ++Milestone; + ++PageNo; + } + + /* TstCond */ + +TstCond (K, Valid, T) +int K, Valid; +char *T; +{ if (! Valid) { BadCond(K,T); printf(".\n"); } } + +BadCond(K, T) +int K; +char *T; +{ + static char *msg[] = { "FAILURE", "SERIOUS DEFECT", "DEFECT", "FLAW" }; + + ErrCnt [K] = ErrCnt [K] + 1; + printf("%s: %s", msg[K], T); + } + +/* Random */ +/* Random computes + X = (Random1 + Random9)^5 + Random1 = X - FLOOR(X) + 0.000005 * X; + and returns the new value of Random1 +*/ + +FLOAT Random() +{ + FLOAT X, Y; + + X = Random1 + Random9; + Y = X * X; + Y = Y * Y; + X = X * Y; + Y = X - FLOOR(X); + Random1 = Y + X * 0.000005; + return(Random1); + } + +/* SqXMinX */ + +SqXMinX (ErrKind) +int ErrKind; +{ + FLOAT XA, XB; + + XB = X * BInvrse; + XA = X - XB; + SqEr = ((SQRT(X * X) - XB) - XA) / OneUlp; + if (SqEr != Zero) { + if (SqEr < MinSqEr) MinSqEr = SqEr; + if (SqEr > MaxSqEr) MaxSqEr = SqEr; + J = J + 1.0; + BadCond(ErrKind, "\n"); + printf("sqrt( %.17e) - %.17e = %.17e\n", X * X, X, OneUlp * SqEr); + printf("\tinstead of correct value 0 .\n"); + } + } + +/* NewD */ + +NewD() +{ + X = Z1 * Q; + X = FLOOR(Half - X / Radix) * Radix + X; + Q = (Q - X * Z) / Radix + X * X * (D / Radix); + Z = Z - Two * X * D; + if (Z <= Zero) { + Z = - Z; + Z1 = - Z1; + } + D = Radix * D; + } + +/* SR3750 */ + +SR3750() +{ + if (! ((X - Radix < Z2 - Radix) || (X - Z2 > W - Z2))) { + I = I + 1; + X2 = SQRT(X * D); + Y2 = (X2 - Z2) - (Y - Z2); + X2 = X8 / (Y - Half); + X2 = X2 - Half * X2 * X2; + SqEr = (Y2 + Half) + (Half - X2); + if (SqEr < MinSqEr) MinSqEr = SqEr; + SqEr = Y2 - X2; + if (SqEr > MaxSqEr) MaxSqEr = SqEr; + } + } + +/* IsYeqX */ + +IsYeqX() +{ + if (Y != X) { + if (N <= 0) { + if (Z == Zero && Q <= Zero) + printf("WARNING: computing\n"); + else BadCond(Defect, "computing\n"); + printf("\t(%.17e) ^ (%.17e)\n", Z, Q); + printf("\tyielded %.17e;\n", Y); + printf("\twhich compared unequal to correct %.17e ;\n", + X); + printf("\t\tthey differ by %.17e .\n", Y - X); + } + N = N + 1; /* ... count discrepancies. */ + } + } + +/* SR3980 */ + +SR3980() +{ + do { + Q = (FLOAT) I; + Y = POW(Z, Q); + IsYeqX(); + if (++I > M) break; + X = Z * X; + } while ( X < W ); + } + +/* PrintIfNPositive */ + +PrintIfNPositive() +{ + if (N > 0) printf("Similar discrepancies have occurred %d times.\n", N); + } + +/* TstPtUf */ + +TstPtUf() +{ + N = 0; + if (Z != Zero) { + printf("Since comparison denies Z = 0, evaluating "); + printf("(Z + Z) / Z should be safe.\n"); + sigsave = sigfpe; + if (setjmp(ovfl_buf)) goto very_serious; + Q9 = (Z + Z) / Z; + printf("What the machine gets for (Z + Z) / Z is %.17e .\n", + Q9); + if (FABS(Q9 - Two) < Radix * U2) { + printf("This is O.K., provided Over/Underflow"); + printf(" has NOT just been signaled.\n"); + } + else { + if ((Q9 < One) || (Q9 > Two)) { +very_serious: + N = 1; + ErrCnt [Serious] = ErrCnt [Serious] + 1; + printf("This is a VERY SERIOUS DEFECT!\n"); + } + else { + N = 1; + ErrCnt [Defect] = ErrCnt [Defect] + 1; + printf("This is a DEFECT!\n"); + } + } + sigsave = 0; + V9 = Z * One; + Random1 = V9; + V9 = One * Z; + Random2 = V9; + V9 = Z / One; + if ((Z == Random1) && (Z == Random2) && (Z == V9)) { + if (N > 0) Pause(); + } + else { + N = 1; + BadCond(Defect, "What prints as Z = "); + printf("%.17e\n\tcompares different from ", Z); + if (Z != Random1) printf("Z * 1 = %.17e ", Random1); + if (! ((Z == Random2) + || (Random2 == Random1))) + printf("1 * Z == %g\n", Random2); + if (! (Z == V9)) printf("Z / 1 = %.17e\n", V9); + if (Random2 != Random1) { + ErrCnt [Defect] = ErrCnt [Defect] + 1; + BadCond(Defect, "Multiplication does not commute!\n"); + printf("\tComparison alleges that 1 * Z = %.17e\n", + Random2); + printf("\tdiffers from Z * 1 = %.17e\n", Random1); + } + Pause(); + } + } + } + +notify(s) +char *s; +{ + printf("%s test appears to be inconsistent...\n", s); + printf(" PLEASE NOTIFY KARPINKSI!\n"); + } + +/*SPLIT msgs.c */ + +/* Instructions */ + +msglist(s) +char **s; +{ while(*s) printf("%s\n", *s++); } + +Instructions() +{ + static char *instr[] = { + "Lest this program stop prematurely, i.e. before displaying\n", + " `END OF TEST',\n", + "try to persuade the computer NOT to terminate execution when an", + "error like Over/Underflow or Division by Zero occurs, but rather", + "to persevere with a surrogate value after, perhaps, displaying some", + "warning. If persuasion avails naught, don't despair but run this", + "program anyway to see how many milestones it passes, and then", + "amend it to make further progress.\n", + "Answer questions with Y, y, N or n (unless otherwise indicated).\n", + 0}; + + msglist(instr); + } + +/* Heading */ + +Heading() +{ + static char *head[] = { + "Users are invited to help debug and augment this program so it will", + "cope with unanticipated and newly uncovered arithmetic pathologies.\n", + "Please send suggestions and interesting results to", + "\tRichard Karpinski", + "\tComputer Center U-76", + "\tUniversity of California", + "\tSan Francisco, CA 94143-0704, USA\n", + "In doing so, please include the following information:", +#ifdef Single + "\tPrecision:\tsingle;", +#else + "\tPrecision:\tdouble;", +#endif + "\tVersion:\t10 February 1989;", + "\tComputer:\n", + "\tCompiler:\n", + "\tOptimization level:\n", + "\tOther relevant compiler options:", + 0}; + + msglist(head); + } + +/* Characteristics */ + +Characteristics() +{ + static char *chars[] = { + "Running this program should reveal these characteristics:", + " Radix = 1, 2, 4, 8, 10, 16, 100, 256 ...", + " Precision = number of significant digits carried.", + " U2 = Radix/Radix^Precision = One Ulp", + "\t(OneUlpnit in the Last Place) of 1.000xxx .", + " U1 = 1/Radix^Precision = One Ulp of numbers a little less than 1.0 .", + " Adequacy of guard digits for Mult., Div. and Subt.", + " Whether arithmetic is chopped, correctly rounded, or something else", + "\tfor Mult., Div., Add/Subt. and Sqrt.", + " Whether a Sticky Bit used correctly for rounding.", + " UnderflowThreshold = an underflow threshold.", + " E0 and PseudoZero tell whether underflow is abrupt, gradual, or fuzzy.", + " V = an overflow threshold, roughly.", + " V0 tells, roughly, whether Infinity is represented.", + " Comparisions are checked for consistency with subtraction", + "\tand for contamination with pseudo-zeros.", + " Sqrt is tested. Y^X is not tested.", + " Extra-precise subexpressions are revealed but NOT YET tested.", + " Decimal-Binary conversion is NOT YET tested for accuracy.", + 0}; + + msglist(chars); + } + +History() + +{ /* History */ + /* Converted from Brian Wichmann's Pascal version to C by Thos Sumner, + with further massaging by David M. Gay. */ + + static char *hist[] = { + "The program attempts to discriminate among", + " FLAWs, like lack of a sticky bit,", + " Serious DEFECTs, like lack of a guard digit, and", + " FAILUREs, like 2+2 == 5 .", + "Failures may confound subsequent diagnoses.\n", + "The diagnostic capabilities of this program go beyond an earlier", + "program called `MACHAR', which can be found at the end of the", + "book `Software Manual for the Elementary Functions' (1980) by", + "W. J. Cody and W. Waite. Although both programs try to discover", + "the Radix, Precision and range (over/underflow thresholds)", + "of the arithmetic, this program tries to cope with a wider variety", + "of pathologies, and to say how well the arithmetic is implemented.", + "\nThe program is based upon a conventional radix representation for", + "floating-point numbers, but also allows logarithmic encoding", + "as used by certain early WANG machines.\n", + "BASIC version of this program (C) 1983 by Prof. W. M. Kahan;", + "see source comments for more history.", + 0}; + + msglist(hist); + } + +double +pow(x, y) /* return x ^ y (exponentiation) */ +double x, y; +{ + extern double exp(), frexp(), ldexp(), log(), modf(); + double xy, ye; + long i; + int ex, ey = 0, flip = 0; + + if (!y) return 1.0; + + if ((y < -1100. || y > 1100.) && x != -1.) return exp(y * log(x)); + + if (y < 0.) { y = -y; flip = 1; } + y = modf(y, &ye); + if (y) xy = exp(y * log(x)); + else xy = 1.0; + /* next several lines assume >= 32 bit integers */ + x = frexp(x, &ex); + if (i = ye) for(;;) { + if (i & 1) { xy *= x; ey += ex; } + if (!(i >>= 1)) break; + x *= x; + ex *= 2; + if (x < .5) { x *= 2.; ex -= 1; } + } + if (flip) { xy = 1. / xy; ey = -ey; } + return ldexp(xy, ey); +} diff --git a/src/cmd/lccom/tst/run.sh b/src/cmd/lccom/tst/run.sh new file mode 100755 index 0000000..25db8f0 --- /dev/null +++ b/src/cmd/lccom/tst/run.sh @@ -0,0 +1,37 @@ +#!/bin/sh +# run .../tst/target/foo.s + +#set -x +target=`echo $1 | awk -F/ '{ print $(NF-1) }'` + +case "$1" in +*symbolic) idir=tst/mips-eb ;; +*symbolic64) idir=tst/alpha-osf ;; +*) idir=tst/$target ;; +esac + +if [ ! -d "tst/$target" -o ! -d "$idir" ]; then + echo 2>&1 $0: unknown combination '"'$target'"' + echo target = $target + echo idir = $idir + exit 1 +fi + +C=`basename $1 .s` +BUILDDIR=${BUILDDIR-.} +LCC="${LCC-${BUILDDIR}/lcc} -Wo-lccdir=$BUILDDIR" +TSTDIR=${TSTDIR-tst/$target} +if [ ! -d $TSTDIR ]; then mkdir -p $TSTDIR; fi + +echo ${BUILDDIR}/rcc$EXE -target=$target $1: 1>&2 +$LCC -S -I$idir -Ualpha -Usun -Uvax -Umips -Ux86 \ + -Wf-errout=$TSTDIR/$C.2 -Wf-g0 \ + -Wf-target=$target -o $1 tst/$C.c +if [ -r tst/$target/$C.2bk ]; then + diff tst/$target/$C.2bk $TSTDIR/$C.2 +fi +if [ -r tst/$target/$C.sbk ]; then + diff tst/$target/$C.sbk $TSTDIR/$C.s +fi + +exit 0 diff --git a/src/cmd/lccom/tst/sort.0 b/src/cmd/lccom/tst/sort.0 new file mode 100644 index 0000000..e69de29 diff --git a/src/cmd/lccom/tst/sort.c b/src/cmd/lccom/tst/sort.c new file mode 100644 index 0000000..a0cff62 --- /dev/null +++ b/src/cmd/lccom/tst/sort.c @@ -0,0 +1,65 @@ +int in[] = {10, 32, -1, 567, 3, 18, 1, -51, 789, 0}; + +main() { + int i; + + sort(in, (sizeof in)/(sizeof in[0])); + for (i = 0; i < (sizeof in)/(sizeof in[0]); i++) { + putd(in[i]); + putchar('\n'); + } + return 0; +} + +/* putd - output decimal number */ +putd(n) { + if (n < 0) { + putchar('-'); + n = -n; + } + if (n/10) + putd(n/10); + putchar(n%10 + '0'); +} + +int *xx; + +/* sort - sort a[0..n-1] into increasing order */ +sort(a, n) int a[]; { + quick(xx = a, 0, --n); +} + +/* quick - quicksort a[lb..ub] */ +quick(a, lb, ub) int a[]; { + int k, partition(); + + if (lb >= ub) + return; + k = partition(a, lb, ub); + quick(a, lb, k - 1); + quick(a, k + 1, ub); +} + +/* partition - partition a[i..j] */ +int partition(a, i, j) int a[]; { + int v, k; + + j++; + k = i; + v = a[k]; + while (i < j) { + i++; while (a[i] < v) i++; + j--; while (a[j] > v) j--; + if (i < j) exchange(&a[i], &a[j]); + } + exchange(&a[k], &a[j]); + return j; +} + +/* exchange - exchange *x and *y */ +exchange(x, y) int *x, *y; { + int t; + + printf("exchange(%d,%d)\n", x - xx, y - xx); + t = *x; *x = *y; *y = t; +} diff --git a/src/cmd/lccom/tst/spill.0 b/src/cmd/lccom/tst/spill.0 new file mode 100644 index 0000000..e69de29 diff --git a/src/cmd/lccom/tst/spill.c b/src/cmd/lccom/tst/spill.c new file mode 100644 index 0000000..2c5da81 --- /dev/null +++ b/src/cmd/lccom/tst/spill.c @@ -0,0 +1,17 @@ +main(){} + +f(i){i=f()+f();} + +f2(i){i=f()+(i?f():1);} + +f3(int i,int *p){register r1=0,r2=0,r3=0,r4=0,r5=0,r6=0,r7=0,r8=0,r9=0,r10=0;*p++=i?f():0;} + +double a[10],b[10];int i;f4(){register r6=0,r7=0,r8=0,r9=0,r10=0,r11=0;i=a[i]+b[i] && i && a[i]-b[i];} +/* f4 causes parent to spill child on vax when odd double regs are enabled */ + +int j, k, m, n; +double *A, *B, x; +f5(){ + x=A[k*m]*A[j*m]+B[k*n]*B[j*n]; + x=A[k*m]*B[j*n]-B[k*n]*A[j*m]; +} diff --git a/src/cmd/lccom/tst/stdarg.0 b/src/cmd/lccom/tst/stdarg.0 new file mode 100644 index 0000000..e69de29 diff --git a/src/cmd/lccom/tst/stdarg.c b/src/cmd/lccom/tst/stdarg.c new file mode 100644 index 0000000..c6a5338 --- /dev/null +++ b/src/cmd/lccom/tst/stdarg.c @@ -0,0 +1,51 @@ +#include + +struct node { int a[4]; } x = {1,2,3,4}; + +print(char *fmt, ...); + +main() { + print("test 1\n"); + print("test %s\n", "2"); + print("test %d%c", 3, '\n'); + print("%s%s %w%c", "te", "st", 4, '\n'); + print("%s%s %f%c", "te", "st", 5.0, '\n'); + print("%b %b %b %b %b %b\n", x, x, x, x, x, x); + return 0; +} + +print(char *fmt, ...) { + va_list ap; + + va_start(ap, fmt); + for (; *fmt; fmt++) + if (*fmt == '%') + switch (*++fmt) { + case 'b': { + struct node x = va_arg(ap, struct node); + printf("{%d %d %d %d}", x.a[0], x.a[1], x.a[2], x.a[3]); + break; + } + case 'c': + printf("%c", va_arg(ap, char)); + break; + case 'd': + printf("%d", va_arg(ap, int)); + break; + case 'w': + printf("%x", va_arg(ap, short)); + break; + case 's': + printf("%s", va_arg(ap, char *)); + break; + case 'f': + printf("%f", va_arg(ap, double)); + break; + default: + printf("%c", *fmt); + break; + } + else + printf("%c", *fmt); + va_end(ap); +} diff --git a/src/cmd/lccom/tst/struct.0 b/src/cmd/lccom/tst/struct.0 new file mode 100644 index 0000000..e69de29 diff --git a/src/cmd/lccom/tst/struct.c b/src/cmd/lccom/tst/struct.c new file mode 100644 index 0000000..fe81681 --- /dev/null +++ b/src/cmd/lccom/tst/struct.c @@ -0,0 +1,69 @@ +typedef struct point { int x,y; } point; +typedef struct rect { point pt1, pt2; } rect; + +point addpoint(point p1, point p2) { /* add two points */ + p1.x += p2.x; + p1.y += p2.y; + return p1; +} + +#define min(a, b) ((a) < (b) ? (a) : (b)) +#define max(a, b) ((a) > (b) ? (a) : (b)) + +rect canonrect(rect r) { /* canonicalize rectangle coordinates */ + rect temp; + + temp.pt1.x = min(r.pt1.x, r.pt2.x); + temp.pt1.y = min(r.pt1.y, r.pt2.y); + temp.pt2.x = max(r.pt1.x, r.pt2.x); + temp.pt2.y = max(r.pt1.y, r.pt2.y); + return temp; +} + +point makepoint(int x, int y) { /* make a point from x and y components */ + point p; + + p.x = x; + p.y = y; + return p; +} + +rect makerect(point p1, point p2) { /* make a rectangle from two points */ + rect r; + + r.pt1 = p1; + r.pt2 = p2; + return canonrect(r); +} + +int ptinrect(point p, rect r) { /* is p in r? */ + return p.x >= r.pt1.x && p.x < r.pt2.x + && p.y >= r.pt1.y && p.y < r.pt2.y; +} + +struct odd {char a[3]; } y = {'a', 'b', 0}; + +odd(struct odd y) { + struct odd x = y; + printf("%s\n", x.a); +} + +main() { + int i; + point x, origin = { 0, 0 }, maxpt = { 320, 320 }; + point pts[] = { -1, -1, 1, 1, 20, 300, 500, 400 }; + rect screen = makerect(addpoint(maxpt, makepoint(-10, -10)), + addpoint(origin, makepoint(10, 10))); + + for (i = 0; i < sizeof pts/sizeof pts[0]; i++) { + printf("(%d,%d) is ", pts[i].x, + (x = makepoint(pts[i].x, pts[i].y)).y); + if (ptinrect(x, screen) == 0) + printf("not "); + printf("within [%d,%d; %d,%d]\n", screen.pt1.x, screen.pt1.y, + screen.pt2.x, screen.pt2.y); + } + odd(y); + exit(0); +} + diff --git a/src/cmd/lccom/tst/switch.0 b/src/cmd/lccom/tst/switch.0 new file mode 100644 index 0000000..e69de29 diff --git a/src/cmd/lccom/tst/switch.c b/src/cmd/lccom/tst/switch.c new file mode 100644 index 0000000..dd62d79 --- /dev/null +++ b/src/cmd/lccom/tst/switch.c @@ -0,0 +1,137 @@ +main() +{ + int i; char *s; + + for (s = "bfnrtvx"; *s; s++) + printf("%c = 0x%x\n", *s, backslash(*s)); + f(); + g(); + h(); + for (i = 0x1000000; i&0x7000000; i += 0x1000000) + big(i); + limit(); + return 0; +} + +backslash(c) +{ + switch (c) { + case 'b': + return '\b'; + case 'f': + return '\f'; + case 'n': + return '\n'; + case 'r': + return '\r'; + case 't': + return '\t'; + case 'v': + return '\v'; + } + return c; +} + +f() { + int i, x = 0, y; + + printf("f:\n"); + for (i = 0; i <= 20; i++) { + y = i; + switch (i) { + case 1: x = i; break; + case 2: x = i; break; + case 7: x = i; break; + case 8: x = i; break; + case 9: x = i; break; + case 16: x = i; break; + case 17: x = i; break; + case 18: x = i; break; + case 19: x = i; break; + case 20: x = i; break; + } + printf("x = %d\n", x); + } +} + +g() { + int i; + + printf("g:\n"); + for (i = 1; i <= 10; i++) + switch (i) { + case 1: case 2: printf("1 %d\n", i); break; + case 3: case 4: case 5: printf("2 %d\n", i); break; + case 6: case 7: case 8: printf("3 %d\n", i); + default: + printf("d %d\n", i); break; + case 1001: case 1002: case 1003: case 1004: + printf("5 %d\n", i); break; + case 3001: case 3002: case 3003: case 3004: + printf("6 %d\n", i); break; + } +} + +h() +{ + int i, n=0; + + printf("h:\n"); + for (i = 1; i <= 500; i++) + switch (i) { + default: n++; continue; + case 128: printf("i = %d\n", i); break; + case 16: printf("i = %d\n", i); break; + case 8: printf("i = %d\n", i); break; + case 120: printf("i = %d\n", i); break; + case 280: printf("i = %d\n", i); break; + case 264: printf("i = %d\n", i); break; + case 248: printf("i = %d\n", i); break; + case 272: printf("i = %d\n", i); break; + case 304: printf("i = %d\n", i); break; + case 296: printf("i = %d\n", i); break; + case 288: printf("i = %d\n", i); break; + case 312: printf("i = %d\n", i); break; + } + printf("%d defaults\n", n); +} + +big(x) unsigned x; { + switch(x&0x6000000){ + case -1: + case -2: + case 0x0000000: + printf("x = 0x%x\n", x); break; + case 0x2000000: + printf("x = 0x%x\n", x); break; + case 0x4000000: + printf("x = 0x%x\n", x); break; + default: + printf("x = 0x%x (default)\n", x); break; + } +} + +#include + +limit() { + int i; + + for (i = INT_MIN; i <= INT_MIN+5; i++) + switch (i) { + case INT_MIN: printf("0\n"); break; + case INT_MIN+1: printf("1\n"); break; + case INT_MIN+2: printf("2\n"); break; + case INT_MIN+3: printf("3\n"); break; + case INT_MIN+4: printf("4\n"); break; + default: printf("5\n"); break; + } + for (i = INT_MAX; i >= INT_MAX-5; i--) + switch (i) { + case INT_MAX: printf("0\n"); break; + case INT_MAX-1: printf("1\n"); break; + case INT_MAX-2: printf("2\n"); break; + case INT_MAX-3: printf("3\n"); break; + case INT_MAX-4: printf("4\n"); break; + default: printf("5\n"); break; + } +} diff --git a/src/cmd/lccom/tst/wf1.0 b/src/cmd/lccom/tst/wf1.0 new file mode 100644 index 0000000..761b526 --- /dev/null +++ b/src/cmd/lccom/tst/wf1.0 @@ -0,0 +1,115 @@ +/* wf1 - print word frequencies; uses structures */ + +struct node { + int count; /* frequency count */ + struct node *left; /* left subtree */ + struct node *right; /* right subtree */ + char *word; /* word itself */ +} words[2000]; +int next; /* index of next free entry in words */ + +struct node *lookup(); + +main() +{ + struct node *root; + char word[20]; + + root = 0; + next = 0; + while (getword(word)) + lookup(word, &root)->count++; + tprint(root); + return 0; +} + +/* err - print error message s and die */ +err(s) +char *s; +{ + printf("? %s\n", s); + exit(1); +} + +/* getword - get next input word into buf, return 0 on EOF */ +int getword(buf) +char *buf; +{ + char *s; + int c; + + while ((c = getchar()) != -1 && isletter(c) == 0) + ; + for (s = buf; c = isletter(c); c = getchar()) + *s++ = c; + *s = 0; + if (s > buf) + return (1); + return (0); +} + +/* isletter - return folded version of c if it is a letter, 0 otherwise */ +int isletter(c) +int c; +{ + if (c >= 'A' && c <= 'Z') + c += 'a' - 'A'; + if (c >= 'a' && c <= 'z') + return (c); + return (0); +} + +/* lookup - lookup word in tree; install if necessary */ +struct node *lookup(word, p) +char *word; +struct node **p; +{ + int cond; + char *malloc(); + + if (*p) { + cond = strcmp(word, (*p)->word); + if (cond < 0) + return lookup(word, &(*p)->left); + else if (cond > 0) + return lookup(word, &(*p)->right); + else + return *p; + } + if (next >= 2000) + err("out of node storage"); + words[next].count = 0; + words[next].left = words[next].right = 0; + words[next].word = malloc(strlen(word) + 1); + if (words[next].word == 0) + err("out of word storage"); + strcpy(words[next].word, word); + return *p = &words[next++]; +} + +/* tprint - print tree */ +tprint(tree) +struct node *tree; +{ + if (tree) { + tprint(tree->left); + printf("%d\t%s\n", tree->count, tree->word); + tprint(tree->right); + } +} + +/* strcmp - compare s1 and s2, return <0, 0, or >0 */ +int strcmp(s1, s2) +char *s1, *s2; +{ + while (*s1 == *s2) { + if (*s1++ == 0) + return 0; + ++s2; + } + if (*s1 == 0) + return -1; + else if (*s2 == 0) + return 1; + return *s1 - *s2; +} diff --git a/src/cmd/lccom/tst/wf1.c b/src/cmd/lccom/tst/wf1.c new file mode 100644 index 0000000..d0c6e32 --- /dev/null +++ b/src/cmd/lccom/tst/wf1.c @@ -0,0 +1,101 @@ +/* wf1 - print word frequencies; uses structures */ + +struct node { + int count; /* frequency count */ + struct node *left; /* left subtree */ + struct node *right; /* right subtree */ + char *word; /* word itself */ +} words[2000]; +int next; /* index of next free entry in words */ + +struct node *lookup(); + +main() { + struct node *root; + char word[20]; + + root = 0; + next = 0; + while (getword(word)) + lookup(word, &root)->count++; + tprint(root); + return 0; +} + +/* err - print error message s and die */ +err(s) char *s; { + printf("? %s\n", s); + exit(1); +} + +/* getword - get next input word into buf, return 0 on EOF */ +int getword(buf) char *buf; { + char *s; + int c; + + while ((c = getchar()) != -1 && isletter(c) == 0) + ; + for (s = buf; c = isletter(c); c = getchar()) + *s++ = c; + *s = 0; + if (s > buf) + return (1); + return (0); +} + +/* isletter - return folded version of c if it is a letter, 0 otherwise */ +int isletter(c) { + if (c >= 'A' && c <= 'Z') + c += 'a' - 'A'; + if (c >= 'a' && c <= 'z') + return (c); + return (0); +} + +/* lookup - lookup word in tree; install if necessary */ +struct node *lookup(word, p) char *word; struct node **p; { + int cond; + char *malloc(); + + if (*p) { + cond = strcmp(word, (*p)->word); + if (cond < 0) + return lookup(word, &(*p)->left); + else if (cond > 0) + return lookup(word, &(*p)->right); + else + return *p; + } + if (next >= 2000) + err("out of node storage"); + words[next].count = 0; + words[next].left = words[next].right = 0; + words[next].word = malloc(strlen(word) + 1); + if (words[next].word == 0) + err("out of word storage"); + strcpy(words[next].word, word); + return *p = &words[next++]; +} + +/* tprint - print tree */ +tprint(tree) struct node *tree; { + if (tree) { + tprint(tree->left); + printf("%d\t%s\n", tree->count, tree->word); + tprint(tree->right); + } +} + +/* strcmp - compare s1 and s2, return <0, 0, or >0 */ +int strcmp(s1, s2) char *s1, *s2; { + while (*s1 == *s2) { + if (*s1++ == 0) + return 0; + ++s2; + } + if (*s1 == 0) + return -1; + else if (*s2 == 0) + return 1; + return *s1 - *s2; +} diff --git a/src/cmd/lccom/tst/x86-linux/8q.1bk b/src/cmd/lccom/tst/x86-linux/8q.1bk new file mode 100644 index 0000000..7ed6437 --- /dev/null +++ b/src/cmd/lccom/tst/x86-linux/8q.1bk @@ -0,0 +1,92 @@ +1 5 8 6 3 7 2 4 +1 6 8 3 7 4 2 5 +1 7 4 6 8 2 5 3 +1 7 5 8 2 4 6 3 +2 4 6 8 3 1 7 5 +2 5 7 1 3 8 6 4 +2 5 7 4 1 8 6 3 +2 6 1 7 4 8 3 5 +2 6 8 3 1 4 7 5 +2 7 3 6 8 5 1 4 +2 7 5 8 1 4 6 3 +2 8 6 1 3 5 7 4 +3 1 7 5 8 2 4 6 +3 5 2 8 1 7 4 6 +3 5 2 8 6 4 7 1 +3 5 7 1 4 2 8 6 +3 5 8 4 1 7 2 6 +3 6 2 5 8 1 7 4 +3 6 2 7 1 4 8 5 +3 6 2 7 5 1 8 4 +3 6 4 1 8 5 7 2 +3 6 4 2 8 5 7 1 +3 6 8 1 4 7 5 2 +3 6 8 1 5 7 2 4 +3 6 8 2 4 1 7 5 +3 7 2 8 5 1 4 6 +3 7 2 8 6 4 1 5 +3 8 4 7 1 6 2 5 +4 1 5 8 2 7 3 6 +4 1 5 8 6 3 7 2 +4 2 5 8 6 1 3 7 +4 2 7 3 6 8 1 5 +4 2 7 3 6 8 5 1 +4 2 7 5 1 8 6 3 +4 2 8 5 7 1 3 6 +4 2 8 6 1 3 5 7 +4 6 1 5 2 8 3 7 +4 6 8 2 7 1 3 5 +4 6 8 3 1 7 5 2 +4 7 1 8 5 2 6 3 +4 7 3 8 2 5 1 6 +4 7 5 2 6 1 3 8 +4 7 5 3 1 6 8 2 +4 8 1 3 6 2 7 5 +4 8 1 5 7 2 6 3 +4 8 5 3 1 7 2 6 +5 1 4 6 8 2 7 3 +5 1 8 4 2 7 3 6 +5 1 8 6 3 7 2 4 +5 2 4 6 8 3 1 7 +5 2 4 7 3 8 6 1 +5 2 6 1 7 4 8 3 +5 2 8 1 4 7 3 6 +5 3 1 6 8 2 4 7 +5 3 1 7 2 8 6 4 +5 3 8 4 7 1 6 2 +5 7 1 3 8 6 4 2 +5 7 1 4 2 8 6 3 +5 7 2 4 8 1 3 6 +5 7 2 6 3 1 4 8 +5 7 2 6 3 1 8 4 +5 7 4 1 3 8 6 2 +5 8 4 1 3 6 2 7 +5 8 4 1 7 2 6 3 +6 1 5 2 8 3 7 4 +6 2 7 1 3 5 8 4 +6 2 7 1 4 8 5 3 +6 3 1 7 5 8 2 4 +6 3 1 8 4 2 7 5 +6 3 1 8 5 2 4 7 +6 3 5 7 1 4 2 8 +6 3 5 8 1 4 2 7 +6 3 7 2 4 8 1 5 +6 3 7 2 8 5 1 4 +6 3 7 4 1 8 2 5 +6 4 1 5 8 2 7 3 +6 4 2 8 5 7 1 3 +6 4 7 1 3 5 2 8 +6 4 7 1 8 2 5 3 +6 8 2 4 1 7 5 3 +7 1 3 8 6 4 2 5 +7 2 4 1 8 5 3 6 +7 2 6 3 1 4 8 5 +7 3 1 6 8 5 2 4 +7 3 8 2 5 1 6 4 +7 4 2 5 8 1 3 6 +7 4 2 8 6 1 3 5 +7 5 3 1 6 8 2 4 +8 2 4 1 7 5 3 6 +8 2 5 3 1 7 4 6 +8 3 1 6 2 5 7 4 +8 4 1 3 6 2 7 5 diff --git a/src/cmd/lccom/tst/x86-linux/8q.2bk b/src/cmd/lccom/tst/x86-linux/8q.2bk new file mode 100644 index 0000000..d4dc0ed --- /dev/null +++ b/src/cmd/lccom/tst/x86-linux/8q.2bk @@ -0,0 +1,2 @@ +tst/8q.c:30: warning: missing return value +tst/8q.c:39: warning: missing return value diff --git a/src/cmd/lccom/tst/x86-linux/8q.sbk b/src/cmd/lccom/tst/x86-linux/8q.sbk new file mode 100644 index 0000000..b9b9577 --- /dev/null +++ b/src/cmd/lccom/tst/x86-linux/8q.sbk @@ -0,0 +1,180 @@ +.globl main +.text +.align 16 +.type main,@function +main: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +subl $4,%esp +movl $0,-4(%ebp) +.LC2: +movl -4(%ebp),%edi +leal (,%edi,4),%edi +movl $1,down(%edi) +movl $1,up(%edi) +.LC3: +incl -4(%ebp) +cmpl $15,-4(%ebp) +jl .LC2 +movl $0,-4(%ebp) +.LC6: +movl -4(%ebp),%edi +movl $1,rows(,%edi,4) +.LC7: +incl -4(%ebp) +cmpl $8,-4(%ebp) +jl .LC6 +pushl $0 +call queens +addl $4,%esp +mov $0,%eax +.LC1: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf10: +.size main,.Lf10-main +.globl queens +.align 16 +.type queens,@function +queens: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +subl $4,%esp +movl $0,-4(%ebp) +.LC12: +movl -4(%ebp),%edi +cmpl $0,rows(,%edi,4) +je .LC16 +movl 20(%ebp),%esi +movl %edi,%ebx +subl %esi,%ebx +cmpl $0,up+28(,%ebx,4) +je .LC16 +leal (%esi,%edi),%edi +cmpl $0,down(,%edi,4) +je .LC16 +movl -4(%ebp),%edi +movl 20(%ebp),%esi +leal (%esi,%edi),%ebx +movl $0,down(,%ebx,4) +movl %edi,%ebx +subl %esi,%ebx +movl $0,up+28(,%ebx,4) +movl $0,rows(,%edi,4) +movl 20(%ebp),%edi +movl -4(%ebp),%esi +movl %esi,x(,%edi,4) +cmpl $7,20(%ebp) +jne .LC20 +call print +jmp .LC21 +.LC20: +movl 20(%ebp),%edi +leal 1(%edi),%edi +pushl %edi +call queens +addl $4,%esp +.LC21: +movl -4(%ebp),%edi +movl 20(%ebp),%esi +leal (%esi,%edi),%ebx +movl $1,down(,%ebx,4) +movl %edi,%ebx +subl %esi,%ebx +movl $1,up+28(,%ebx,4) +movl $1,rows(,%edi,4) +.LC16: +.LC13: +incl -4(%ebp) +cmpl $8,-4(%ebp) +jl .LC12 +mov $0,%eax +.LC11: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf23: +.size queens,.Lf23-queens +.globl print +.align 16 +.type print,@function +print: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +subl $4,%esp +movl $0,-4(%ebp) +.LC25: +movl -4(%ebp),%edi +movl x(,%edi,4),%edi +leal 49(%edi),%edi +pushl %edi +pushl $.LC29 +call printf +addl $8,%esp +.LC26: +incl -4(%ebp) +cmpl $8,-4(%ebp) +jl .LC25 +pushl $.LC30 +call printf +addl $4,%esp +mov $0,%eax +.LC24: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf31: +.size print,.Lf31-print +.bss +.globl x +.align 4 +.type x,@object +.size x,32 +.comm x,32 +.globl rows +.align 4 +.type rows,@object +.size rows,32 +.comm rows,32 +.globl down +.align 4 +.type down,@object +.size down,60 +.comm down,60 +.globl up +.align 4 +.type up,@object +.size up,60 +.comm up,60 +.data +.align 1 +.LC30: +.byte 10 +.byte 0 +.align 1 +.LC29: +.byte 37 +.byte 99 +.byte 32 +.byte 0 +.text +.ident "LCC: 4.1" diff --git a/src/cmd/lccom/tst/x86-linux/array.1bk b/src/cmd/lccom/tst/x86-linux/array.1bk new file mode 100644 index 0000000..4d3817c --- /dev/null +++ b/src/cmd/lccom/tst/x86-linux/array.1bk @@ -0,0 +1,4 @@ + 0 1 2 3 1000 1001 1002 1003 2000 2001 2002 2003 + 0 1 2 3 1000 1001 1002 1003 2000 2001 2002 2003 + 0 1 2 3 1000 1001 1002 1003 2000 2001 2002 2003 + 0 1 2 3 1000 1001 1002 1003 2000 2001 2002 2003 diff --git a/src/cmd/lccom/tst/x86-linux/array.2bk b/src/cmd/lccom/tst/x86-linux/array.2bk new file mode 100644 index 0000000..c8cf31e --- /dev/null +++ b/src/cmd/lccom/tst/x86-linux/array.2bk @@ -0,0 +1,2 @@ +tst/array.c:33: warning: missing return value +tst/array.c:48: warning: missing return value diff --git a/src/cmd/lccom/tst/x86-linux/array.sbk b/src/cmd/lccom/tst/x86-linux/array.sbk new file mode 100644 index 0000000..66bcee3 --- /dev/null +++ b/src/cmd/lccom/tst/x86-linux/array.sbk @@ -0,0 +1,235 @@ +.globl main +.text +.align 16 +.type main,@function +main: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +subl $60,%esp +movl $0,-8(%ebp) +.LC2: +movl $0,-4(%ebp) +.LC6: +movl -4(%ebp),%edi +movl -8(%ebp),%esi +movl %esi,%ebx +sall $4,%ebx +leal x(%ebx),%ebx +imul $1000,%esi,%esi +leal (%edi,%esi),%esi +movl %esi,(%ebx,%edi,4) +.LC7: +incl -4(%ebp) +cmpl $4,-4(%ebp) +jl .LC6 +movl -8(%ebp),%edi +movl %edi,%esi +sall $4,%esi +leal x(%esi),%esi +movl %esi,y(,%edi,4) +.LC3: +incl -8(%ebp) +cmpl $3,-8(%ebp) +jl .LC2 +call f +movl $0,-8(%ebp) +.LC10: +movl -8(%ebp),%edi +movl %edi,%esi +sall $4,%esi +leal -60(%ebp),%ebx +leal (%ebx,%esi),%esi +movl %esi,-12(%ebp) +movl %esi,y(,%edi,4) +movl $0,-4(%ebp) +.LC14: +movl -4(%ebp),%edi +leal (,%edi,4),%edi +movl -12(%ebp),%esi +movl -8(%ebp),%ebx +sall $4,%ebx +leal x(%ebx),%ebx +movl (%ebx,%edi),%ebx +movl %ebx,(%esi,%edi) +.LC15: +incl -4(%ebp) +cmpl $4,-4(%ebp) +jl .LC14 +.LC11: +incl -8(%ebp) +cmpl $3,-8(%ebp) +jl .LC10 +pushl $y +leal -60(%ebp),%edi +pushl %edi +call g +addl $8,%esp +mov $0,%eax +.LC1: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf18: +.size main,.Lf18-main +.globl f +.align 16 +.type f,@function +f: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +subl $8,%esp +movl $0,-8(%ebp) +.LC20: +movl $0,-4(%ebp) +.LC24: +movl -4(%ebp),%edi +movl -8(%ebp),%esi +sall $4,%esi +leal x(%esi),%esi +pushl (%esi,%edi,4) +pushl $.LC28 +call printf +addl $8,%esp +.LC25: +incl -4(%ebp) +cmpl $4,-4(%ebp) +jl .LC24 +.LC21: +incl -8(%ebp) +cmpl $3,-8(%ebp) +jl .LC20 +pushl $.LC29 +call printf +addl $4,%esp +movl $0,-8(%ebp) +.LC30: +movl $0,-4(%ebp) +.LC34: +movl -4(%ebp),%edi +movl -8(%ebp),%esi +movl y(,%esi,4),%esi +pushl (%esi,%edi,4) +pushl $.LC28 +call printf +addl $8,%esp +.LC35: +incl -4(%ebp) +cmpl $4,-4(%ebp) +jl .LC34 +.LC31: +incl -8(%ebp) +cmpl $3,-8(%ebp) +jl .LC30 +pushl $.LC29 +call printf +addl $4,%esp +mov $0,%eax +.LC19: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf38: +.size f,.Lf38-f +.globl g +.align 16 +.type g,@function +g: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +subl $8,%esp +movl $0,-8(%ebp) +.LC40: +movl $0,-4(%ebp) +.LC44: +movl -4(%ebp),%edi +movl -8(%ebp),%esi +sall $4,%esi +movl 20(%ebp),%ebx +leal (%ebx,%esi),%esi +pushl (%esi,%edi,4) +pushl $.LC28 +call printf +addl $8,%esp +.LC45: +incl -4(%ebp) +cmpl $4,-4(%ebp) +jl .LC44 +.LC41: +incl -8(%ebp) +cmpl $3,-8(%ebp) +jl .LC40 +pushl $.LC29 +call printf +addl $4,%esp +movl $0,-8(%ebp) +.LC48: +movl $0,-4(%ebp) +.LC52: +movl -4(%ebp),%edi +movl -8(%ebp),%esi +movl 24(%ebp),%ebx +movl (%ebx,%esi,4),%esi +pushl (%esi,%edi,4) +pushl $.LC28 +call printf +addl $8,%esp +.LC53: +incl -4(%ebp) +cmpl $4,-4(%ebp) +jl .LC52 +.LC49: +incl -8(%ebp) +cmpl $3,-8(%ebp) +jl .LC48 +pushl $.LC29 +call printf +addl $4,%esp +mov $0,%eax +.LC39: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf56: +.size g,.Lf56-g +.bss +.globl y +.align 4 +.type y,@object +.size y,12 +.comm y,12 +.globl x +.align 4 +.type x,@object +.size x,48 +.comm x,48 +.data +.align 1 +.LC29: +.byte 10 +.byte 0 +.align 1 +.LC28: +.byte 32 +.byte 37 +.byte 100 +.byte 0 +.text +.ident "LCC: 4.1" diff --git a/src/cmd/lccom/tst/x86-linux/assert.h b/src/cmd/lccom/tst/x86-linux/assert.h new file mode 100644 index 0000000..04b0e3a --- /dev/null +++ b/src/cmd/lccom/tst/x86-linux/assert.h @@ -0,0 +1,14 @@ +#ifndef __ASSERT +#define __ASSERT + +void assert(int); + +#endif /* __ASSERT */ + +#undef assert +#ifdef NDEBUG +#define assert(ignore) ((void)0) +#else +extern int _assert(char *, char *, unsigned); +#define assert(e) ((void)((e)||_assert(#e, __FILE__, __LINE__))) +#endif /* NDEBUG */ diff --git a/src/cmd/lccom/tst/x86-linux/cf.1bk b/src/cmd/lccom/tst/x86-linux/cf.1bk new file mode 100644 index 0000000..9e331c5 --- /dev/null +++ b/src/cmd/lccom/tst/x86-linux/cf.1bk @@ -0,0 +1,51 @@ +char freq +011 8.1 +012 6.1 +040 11.9 +! 0.2 +" 1.5 +% 0.6 +& 0.4 +' 0.4 +( 2.9 +) 2.9 +* 0.8 ++ 1.3 +, 1.3 +- 0.4 +. 0.6 +/ 1.0 +0 2.5 +1 1.9 +2 0.6 +3 0.2 +7 0.4 +8 0.2 +; 3.8 +< 0.8 += 2.7 +> 0.2 +[ 1.5 +\ 0.8 +] 1.5 +a 3.1 +c 4.4 +e 2.3 +f 6.0 +g 1.3 +h 1.0 +i 5.0 +l 1.0 +m 0.2 +n 3.3 +o 2.1 +p 1.0 +q 0.4 +r 4.2 +s 0.6 +t 3.8 +u 1.2 +v 0.6 +w 0.2 +{ 0.6 +} 0.6 diff --git a/src/cmd/lccom/tst/x86-linux/cf.2bk b/src/cmd/lccom/tst/x86-linux/cf.2bk new file mode 100644 index 0000000..e69de29 diff --git a/src/cmd/lccom/tst/x86-linux/cf.sbk b/src/cmd/lccom/tst/x86-linux/cf.sbk new file mode 100644 index 0000000..b714f3c --- /dev/null +++ b/src/cmd/lccom/tst/x86-linux/cf.sbk @@ -0,0 +1,164 @@ +.globl main +.text +.align 16 +.type main,@function +main: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +subl $24,%esp +cmpl $1,20(%ebp) +jg .LC2 +flds .LC4 +fstps -16(%ebp) +jmp .LC3 +.LC2: +movl 24(%ebp),%edi +pushl 4(%edi) +call atof +addl $4,%esp +fstps -20(%ebp) +flds -20(%ebp) +fdivs .LC5 +fstps -16(%ebp) +.LC3: +movl $0,-4(%ebp) +.LC6: +movl -4(%ebp),%edi +leal 1(%edi),%esi +movl %esi,-4(%ebp) +flds .LC4 +fstps f(,%edi,4) +.LC7: +cmpl $127,-4(%ebp) +jle .LC6 +movl $0,-8(%ebp) +jmp .LC11 +.LC10: +movl -12(%ebp),%edi +leal f(,%edi,4),%edi +flds (,%edi) +fadds .LC13 +fstps (,%edi) +incl -8(%ebp) +.LC11: +call getchar +movl %eax,-12(%ebp) +cmpl $-1,%eax +jne .LC10 +pushl $.LC14 +call printf +addl $4,%esp +movl $0,-4(%ebp) +.LC15: +movl -4(%ebp),%edi +flds f(,%edi,4) +fstps -24(%ebp) +flds .LC4 +fcomps -24(%ebp) +fstsw %ax +sahf +jp 1f +je .LC19 +1: +flds -24(%ebp) +fildl -8(%ebp) +fdivrp %st,%st(1) +flds -16(%ebp) +fcompp +fstsw %ax +sahf +jp .LC19 +ja .LC19 +cmpl $32,-4(%ebp) +jg .LC21 +pushl -4(%ebp) +pushl $.LC23 +call printf +addl $8,%esp +jmp .LC22 +.LC21: +pushl -4(%ebp) +pushl $.LC24 +call printf +addl $8,%esp +.LC22: +flds .LC5 +movl -4(%ebp),%edi +fmuls f(,%edi,4) +fildl -8(%ebp) +fdivrp %st,%st(1) +subl $8,%esp +fstpl (%esp) +pushl $.LC25 +call printf +addl $12,%esp +.LC19: +.LC16: +incl -4(%ebp) +cmpl $127,-4(%ebp) +jle .LC15 +mov $0,%eax +.LC1: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf26: +.size main,.Lf26-main +.bss +.globl f +.align 4 +.type f,@object +.size f,512 +.comm f,512 +.data +.align 1 +.LC25: +.byte 9 +.byte 37 +.byte 46 +.byte 49 +.byte 102 +.byte 10 +.byte 0 +.align 1 +.LC24: +.byte 37 +.byte 99 +.byte 0 +.align 1 +.LC23: +.byte 37 +.byte 48 +.byte 51 +.byte 111 +.byte 0 +.align 1 +.LC14: +.byte 99 +.byte 104 +.byte 97 +.byte 114 +.byte 9 +.byte 102 +.byte 114 +.byte 101 +.byte 113 +.byte 10 +.byte 0 +.align 4 +.LC13: +.long 1065353216 +.align 4 +.LC5: +.long 1120403456 +.align 4 +.LC4: +.long 0 +.text +.ident "LCC: 4.1" diff --git a/src/cmd/lccom/tst/x86-linux/cq.1bk b/src/cmd/lccom/tst/x86-linux/cq.1bk new file mode 100644 index 0000000..f0e8b35 --- /dev/null +++ b/src/cmd/lccom/tst/x86-linux/cq.1bk @@ -0,0 +1,48 @@ +Section s22 returned 0. +Decimal and octal/hex constants sometimes give + different results when assigned to longs. +Decimal and octal/hex constants sometimes give + different results when assigned to longs. +Section s241 returned 0. +Section s243 returned 0. +Section s244 returned 0. +Section s25 returned 0. + 8 bits in chars. + 32 bits in ints. + 16 bits in shorts. + 32 bits in longs. + 32 bits in unsigneds. + 32 bits in floats. + 64 bits in doubles. +1.192093e-07 is the least number that can be added to 1. (float). +2.220446e-16 is the least number that can be added to 1. (double). +Section s26 returned 0. +Section s4 returned 0. +Section s61 returned 0. +Section s626 returned 0. +Section s71 returned 0. +Section s72 returned 0. +Section s757 returned 0. +Section s7813 returned 0. +Section s714 returned 0. +Section s715 returned 0. +Register count for char is unreliable. +Register count for pointer is unreliable. +Register count for int is unreliable. +Section s81 returned 0. +Section s84 returned 0. +char alignment: 1 +short alignment: 2 +int alignment: 4 +long alignment: 4 +unsigned alignment: 4 +float alignment: 4 +double alignment: 4 +Sign extension in fields +Be especially careful with 1-bit fields! +Section s85 returned 0. +Section s86 returned 0. +Section s88 returned 0. +Section s9 returned 0. + +No errors detected. diff --git a/src/cmd/lccom/tst/x86-linux/cq.2bk b/src/cmd/lccom/tst/x86-linux/cq.2bk new file mode 100644 index 0000000..7c6ba5e --- /dev/null +++ b/src/cmd/lccom/tst/x86-linux/cq.2bk @@ -0,0 +1,25 @@ +tst/cq.c:394: warning: overflow in converting constant expression from `unsigned long' to `long int' +tst/cq.c:394: warning: overflow in converting constant expression from `unsigned long' to `long int' +tst/cq.c:394: warning: overflow in converting constant expression from `unsigned long' to `long int' +tst/cq.c:395: warning: overflow in constant `4294967296' +tst/cq.c:395: warning: overflow in converting constant expression from `unsigned long' to `long int' +tst/cq.c:395: warning: overflow in constant `040000000000' +tst/cq.c:395: warning: overflow in converting constant expression from `unsigned long' to `long int' +tst/cq.c:395: warning: overflow in constant `0x100000000' +tst/cq.c:395: warning: overflow in converting constant expression from `unsigned long' to `long int' +tst/cq.c:396: warning: overflow in constant `68719476735' +tst/cq.c:396: warning: overflow in converting constant expression from `unsigned long' to `long int' +tst/cq.c:396: warning: overflow in constant `0777777777777' +tst/cq.c:396: warning: overflow in converting constant expression from `unsigned long' to `long int' +tst/cq.c:396: warning: overflow in constant `0xfffffffff' +tst/cq.c:396: warning: overflow in converting constant expression from `unsigned long' to `long int' +tst/cq.c:397: warning: overflow in constant `68719476736' +tst/cq.c:397: warning: overflow in converting constant expression from `unsigned long' to `long int' +tst/cq.c:397: warning: overflow in constant `01000000000000' +tst/cq.c:397: warning: overflow in converting constant expression from `unsigned long' to `long int' +tst/cq.c:397: warning: overflow in constant `0x1000000000' +tst/cq.c:397: warning: overflow in converting constant expression from `unsigned long' to `long int' +tst/cq.c:533: warning: missing return value +tst/cq.c:1169: warning: missing return value +tst/cq.c:5294: warning: unreachable code +tst/cq.c:5303: warning: missing return value diff --git a/src/cmd/lccom/tst/x86-linux/cq.sbk b/src/cmd/lccom/tst/x86-linux/cq.sbk new file mode 100644 index 0000000..58b725a --- /dev/null +++ b/src/cmd/lccom/tst/x86-linux/cq.sbk @@ -0,0 +1,16528 @@ +.data +.align 4 +.type sec.2,@object +sec.2: +.long s22 +.long s241 +.long s243 +.long s244 +.long s25 +.long s26 +.long s4 +.long s61 +.long s626 +.long s71 +.long s72 +.long s757 +.long s7813 +.long s714 +.long s715 +.long s81 +.long s84 +.long s85 +.long s86 +.long s88 +.long s9 +.bss +.size sec.2,84 +.align 4 +.type d0.3,@object +.size d0.3,68 +.lcomm d0.3,68 +.align 4 +.type pd0.4,@object +.size pd0.4,4 +.lcomm pd0.4,4 +.globl main +.text +.align 16 +.type main,@function +main: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +subl $4,%esp +movl $1,d0.3+36 +movl $1,d0.3+40 +movl $1,d0.3+44 +movl $1,d0.3+48 +leal d0.3,%edi +movl %edi,pd0.4 +movl $0,-4(%ebp) +jmp .LC12 +.LC9: +pushl pd0.4 +movl -4(%ebp),%edi +call *sec.2(,%edi,4) +addl $4,%esp +movl %eax,d0.3+52 +movl d0.3+56,%edi +movl d0.3+52,%esi +leal (%esi,%edi),%edi +movl %edi,d0.3+56 +cmpl $0,d0.3+36 +je .LC17 +pushl d0.3+52 +pushl $d0.3+60 +pushl $.LC20 +call printf +addl $12,%esp +.LC17: +.LC10: +incl -4(%ebp) +.LC12: +movl -4(%ebp),%edi +cmpl $21,%edi +jb .LC9 +cmpl $0,d0.3+56 +jne .LC23 +pushl $.LC26 +call printf +addl $4,%esp +jmp .LC24 +.LC23: +pushl $.LC27 +call printf +addl $4,%esp +.LC24: +mov $0,%eax +.LC1: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf28: +.size main,.Lf28-main +.data +.align 1 +.type s22er.30,@object +s22er.30: +.byte 115 +.byte 50 +.byte 50 +.byte 44 +.byte 101 +.byte 114 +.byte 37 +.byte 100 +.byte 10 +.byte 0 +.size s22er.30,10 +.align 1 +.type qs22.31,@object +.size qs22.31,8 +qs22.31: +.byte 115 +.byte 50 +.byte 50 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 0 +.globl s22 +.text +.align 16 +.type s22,@function +s22: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +subl $32,%esp +movl $0,-12(%ebp) +leal qs22.31,%edi +movl %edi,-4(%ebp) +movl 20(%ebp),%edi +leal 60(%edi),%edi +movl %edi,-8(%ebp) +.LC32: +.LC33: +movl -8(%ebp),%edi +leal 1(%edi),%esi +movl %esi,-8(%ebp) +movl -4(%ebp),%esi +leal 1(%esi),%ebx +movl %ebx,-4(%ebp) +movb (,%esi),%bl +movb %bl,(,%edi) +movsbl %bl,%edi +cmpl $0,%edi +jne .LC32 +movl $1,-16(%ebp) +movl $2,-24(%ebp) +movl $3,-28(%ebp) +movl $4,-20(%ebp) +movl -16(%ebp),%edi +movl -24(%ebp),%esi +leal (%esi,%edi),%edi +movl -28(%ebp),%esi +leal (%esi,%edi),%edi +movl -20(%ebp),%esi +leal (%esi,%edi),%edi +cmpl $10,%edi +je .LC35 +incl -12(%ebp) +movl 20(%ebp),%edi +cmpl $0,44(%edi) +je .LC37 +pushl $1 +pushl $s22er.30 +call printf +addl $8,%esp +.LC37: +.LC35: +movl $2,-32(%ebp) +movl -16(%ebp),%edi +cmpl %edi,-32(%ebp) +jne .LC39 +addl $4,-12(%ebp) +movl 20(%ebp),%edi +cmpl $0,44(%edi) +je .LC41 +pushl $4 +pushl $s22er.30 +call printf +addl $8,%esp +.LC41: +.LC39: +movl -12(%ebp),%eax +.LC29: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf43: +.size s22,.Lf43-s22 +.data +.align 1 +.type s241er.45,@object +s241er.45: +.byte 115 +.byte 50 +.byte 52 +.byte 49 +.byte 44 +.byte 101 +.byte 114 +.byte 37 +.byte 100 +.byte 10 +.byte 0 +.size s241er.45,11 +.align 1 +.type qs241.46,@object +.size qs241.46,8 +qs241.46: +.byte 115 +.byte 50 +.byte 52 +.byte 49 +.byte 32 +.byte 32 +.byte 32 +.byte 0 +.align 4 +.type g.47,@object +.size g.47,156 +g.47: +.long 0 +.long 0 +.long 0 +.long 0 +.long 0 +.long 0 +.long 0 +.long 0 +.long 0 +.long 0 +.long 0 +.long 0 +.long 0 +.long 0 +.long 0 +.long 0 +.long 0 +.long 0 +.long 6 +.long 0 +.long 8 +.long 0 +.long 12 +.long 0 +.long 16 +.long 0 +.long 18 +.long 0 +.long 20 +.long 0 +.long 24 +.long 0 +.long 28 +.long 0 +.long 30 +.long 0 +.long 32 +.long 0 +.long 36 +.globl s241 +.text +.align 16 +.type s241,@function +s241: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +subl $488,%esp +movl $0,-484(%ebp) +movl $0,-488(%ebp) +leal qs241.46,%edi +movl %edi,-476(%ebp) +movl 20(%ebp),%edi +leal 60(%edi),%edi +movl %edi,-480(%ebp) +.LC48: +.LC49: +movl -480(%ebp),%edi +leal 1(%edi),%esi +movl %esi,-480(%ebp) +movl -476(%ebp),%esi +leal 1(%esi),%ebx +movl %ebx,-476(%ebp) +movb (,%esi),%bl +movb %bl,(,%edi) +movsbl %bl,%edi +cmpl $0,%edi +jne .LC48 +jmp .LC51 +incl -484(%ebp) +movl 20(%ebp),%edi +cmpl $0,44(%edi) +je .LC53 +pushl $1 +pushl $s241er.45 +call printf +addl $8,%esp +.LC53: +.LC51: +jmp .LC55 +addl $2,-484(%ebp) +movl 20(%ebp),%edi +cmpl $0,44(%edi) +je .LC57 +pushl $2 +pushl $s241er.45 +call printf +addl $8,%esp +.LC57: +.LC55: +jmp .LC59 +addl $4,-484(%ebp) +movl 20(%ebp),%edi +cmpl $0,44(%edi) +je .LC61 +pushl $4 +pushl $s241er.45 +call printf +addl $8,%esp +.LC61: +.LC59: +jmp .LC63 +addl $8,-484(%ebp) +movl 20(%ebp),%edi +cmpl $0,44(%edi) +je .LC65 +pushl $8 +pushl $s241er.45 +call printf +addl $8,%esp +.LC65: +.LC63: +movl $0,-4(%ebp) +.LC67: +movl -4(%ebp),%edi +movl %edi,g.47(,%edi,4) +.LC68: +incl -4(%ebp) +cmpl $17,-4(%ebp) +jl .LC67 +movl $18,-4(%ebp) +.LC71: +movl -4(%ebp),%edi +leal g.47(,%edi,4),%edi +pushl (,%edi) +call pow2 +addl $4,%esp +movl %eax,(,%edi) +movl -4(%ebp),%edi +leal (,%edi,4),%edi +movl g.47(%edi),%esi +subl $1,%esi +movl %esi,g.47-4(%edi) +addl $2,-4(%ebp) +.LC72: +cmpl $39,-4(%ebp) +jl .LC71 +movl $0,-160(%ebp) +movl $0,-316(%ebp) +movl $0,-472(%ebp) +movl $1,-156(%ebp) +movl $1,-312(%ebp) +movl $1,-468(%ebp) +movl $2,-152(%ebp) +movl $2,-308(%ebp) +movl $2,-464(%ebp) +movl $3,-148(%ebp) +movl $3,-304(%ebp) +movl $3,-460(%ebp) +movl $4,-144(%ebp) +movl $4,-300(%ebp) +movl $4,-456(%ebp) +movl $5,-140(%ebp) +movl $5,-296(%ebp) +movl $5,-452(%ebp) +movl $6,-136(%ebp) +movl $6,-292(%ebp) +movl $6,-448(%ebp) +movl $7,-132(%ebp) +movl $7,-288(%ebp) +movl $7,-444(%ebp) +movl $8,-128(%ebp) +movl $8,-284(%ebp) +movl $8,-440(%ebp) +movl $9,-124(%ebp) +movl $9,-280(%ebp) +movl $9,-436(%ebp) +movl $10,-120(%ebp) +movl $10,-276(%ebp) +movl $10,-432(%ebp) +movl $11,-116(%ebp) +movl $11,-272(%ebp) +movl $11,-428(%ebp) +movl $12,-112(%ebp) +movl $12,-268(%ebp) +movl $12,-424(%ebp) +movl $13,-108(%ebp) +movl $13,-264(%ebp) +movl $13,-420(%ebp) +movl $14,-104(%ebp) +movl $14,-260(%ebp) +movl $14,-416(%ebp) +movl $15,-100(%ebp) +movl $15,-256(%ebp) +movl $15,-412(%ebp) +movl $16,-96(%ebp) +movl $16,-252(%ebp) +movl $16,-408(%ebp) +movl $63,-92(%ebp) +movl $63,-248(%ebp) +movl $63,-404(%ebp) +movl $64,-88(%ebp) +movl $64,-244(%ebp) +movl $64,-400(%ebp) +movl $255,-84(%ebp) +movl $255,-240(%ebp) +movl $255,-396(%ebp) +movl $256,-80(%ebp) +movl $256,-236(%ebp) +movl $256,-392(%ebp) +movl $4095,-76(%ebp) +movl $4095,-232(%ebp) +movl $4095,-388(%ebp) +movl $4096,-72(%ebp) +movl $4096,-228(%ebp) +movl $4096,-384(%ebp) +movl $65535,-68(%ebp) +movl $65535,-224(%ebp) +movl $65535,-380(%ebp) +movl $65536,-64(%ebp) +movl $65536,-220(%ebp) +movl $65536,-376(%ebp) +movl $262143,-60(%ebp) +movl $262143,-216(%ebp) +movl $262143,-372(%ebp) +movl $262144,-56(%ebp) +movl $262144,-212(%ebp) +movl $262144,-368(%ebp) +movl $1048575,-52(%ebp) +movl $1048575,-208(%ebp) +movl $1048575,-364(%ebp) +movl $1048576,-48(%ebp) +movl $1048576,-204(%ebp) +movl $1048576,-360(%ebp) +movl $16777215,-44(%ebp) +movl $16777215,-200(%ebp) +movl $16777215,-356(%ebp) +movl $16777216,-40(%ebp) +movl $16777216,-196(%ebp) +movl $16777216,-352(%ebp) +movl $268435455,-36(%ebp) +movl $268435455,-192(%ebp) +movl $268435455,-348(%ebp) +movl $268435456,-32(%ebp) +movl $268435456,-188(%ebp) +movl $268435456,-344(%ebp) +movl $1073741823,-28(%ebp) +movl $1073741823,-184(%ebp) +movl $1073741823,-340(%ebp) +movl $1073741824,-24(%ebp) +movl $1073741824,-180(%ebp) +movl $1073741824,-336(%ebp) +mov $0xffffffff,%edi +movl %edi,-20(%ebp) +mov $0xffffffff,%edi +movl %edi,-176(%ebp) +mov $0xffffffff,%edi +movl %edi,-332(%ebp) +mov $0xffffffff,%edi +movl %edi,-16(%ebp) +mov $0xffffffff,%edi +movl %edi,-172(%ebp) +mov $0xffffffff,%edi +movl %edi,-328(%ebp) +mov $0xffffffff,%edi +movl %edi,-12(%ebp) +mov $0xffffffff,%edi +movl %edi,-168(%ebp) +mov $0xffffffff,%edi +movl %edi,-324(%ebp) +mov $0xffffffff,%edi +movl %edi,-8(%ebp) +mov $0xffffffff,%edi +movl %edi,-164(%ebp) +mov $0xffffffff,%edi +movl %edi,-320(%ebp) +movl $0,-4(%ebp) +.LC190: +movl -4(%ebp),%edi +leal (,%edi,4),%edi +leal -160(%ebp),%esi +movl (%esi,%edi),%esi +cmpl %esi,g.47(%edi) +jne .LC197 +leal -316(%ebp),%ebx +movl (%ebx,%edi),%ebx +cmpl %ebx,%esi +jne .LC197 +leal -472(%ebp),%esi +cmpl (%esi,%edi),%ebx +je .LC194 +.LC197: +movl 20(%ebp),%edi +cmpl $0,40(%edi) +je .LC198 +pushl $.LC200 +call printf +addl $4,%esp +pushl $.LC201 +call printf +addl $4,%esp +.LC198: +.LC194: +.LC191: +incl -4(%ebp) +cmpl $39,-4(%ebp) +jl .LC190 +cmpl $0,-488(%ebp) +je .LC202 +movl $16,-484(%ebp) +.LC202: +movl -484(%ebp),%eax +.LC44: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf204: +.size s241,.Lf204-s241 +.globl pow2 +.align 16 +.type pow2,@function +pow2: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +subl $4,%esp +movl $1,-4(%ebp) +jmp .LC207 +.LC206: +sall $1,-4(%ebp) +.LC207: +movl 20(%ebp),%edi +movl %edi,%esi +subl $1,%esi +movl %esi,20(%ebp) +cmpl $0,%edi +jne .LC206 +movl -4(%ebp),%eax +.LC205: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf209: +.size pow2,.Lf209-pow2 +.data +.align 1 +.type s243er.211,@object +s243er.211: +.byte 115 +.byte 50 +.byte 52 +.byte 51 +.byte 44 +.byte 101 +.byte 114 +.byte 37 +.byte 100 +.byte 10 +.byte 0 +.size s243er.211,11 +.align 1 +.type qs243.212,@object +.size qs243.212,8 +qs243.212: +.byte 115 +.byte 50 +.byte 52 +.byte 51 +.byte 32 +.byte 32 +.byte 32 +.byte 0 +.globl s243 +.text +.align 16 +.type s243,@function +s243: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +subl $268,%esp +movl $0,-268(%ebp) +leal qs243.212,%edi +movl %edi,-260(%ebp) +movl 20(%ebp),%edi +leal 60(%edi),%edi +movl %edi,-264(%ebp) +.LC213: +.LC214: +movl -264(%ebp),%edi +leal 1(%edi),%esi +movl %esi,-264(%ebp) +movl -260(%ebp),%esi +leal 1(%esi),%ebx +movl %ebx,-260(%ebp) +movb (,%esi),%bl +movb %bl,(,%edi) +movsbl %bl,%edi +cmpl $0,%edi +jne .LC213 +leal -256(%ebp),%edi +pushl %edi +call zerofill +addl $4,%esp +movb $1,-159(%ebp) +movb $1,-191(%ebp) +movb $1,-130(%ebp) +movb $1,-208(%ebp) +movb $1,-158(%ebp) +movb $1,-190(%ebp) +movb $1,-223(%ebp) +movb $1,-207(%ebp) +movb $1,-157(%ebp) +movb $1,-189(%ebp) +movb $1,-222(%ebp) +movb $1,-206(%ebp) +movb $1,-156(%ebp) +movb $1,-188(%ebp) +movb $1,-221(%ebp) +movb $1,-205(%ebp) +movb $1,-155(%ebp) +movb $1,-187(%ebp) +movb $1,-219(%ebp) +movb $1,-204(%ebp) +movb $1,-154(%ebp) +movb $1,-186(%ebp) +movb $1,-218(%ebp) +movb $1,-203(%ebp) +movb $1,-153(%ebp) +movb $1,-185(%ebp) +movb $1,-216(%ebp) +movb $1,-202(%ebp) +movb $1,-152(%ebp) +movb $1,-184(%ebp) +movb $1,-215(%ebp) +movb $1,-201(%ebp) +movb $1,-151(%ebp) +movb $1,-183(%ebp) +movb $1,-161(%ebp) +movb $1,-200(%ebp) +movb $1,-150(%ebp) +movb $1,-182(%ebp) +movb $1,-195(%ebp) +movb $1,-199(%ebp) +movb $1,-149(%ebp) +movb $1,-181(%ebp) +movb $1,-211(%ebp) +movb $1,-148(%ebp) +movb $1,-180(%ebp) +movb $1,-162(%ebp) +movb $1,-147(%ebp) +movb $1,-179(%ebp) +movb $1,-132(%ebp) +movb $1,-246(%ebp) +movb $1,-146(%ebp) +movb $1,-178(%ebp) +movb $1,-247(%ebp) +movb $1,-145(%ebp) +movb $1,-177(%ebp) +movb $1,-133(%ebp) +movb $1,-248(%ebp) +movb $1,-144(%ebp) +movb $1,-176(%ebp) +movb $1,-131(%ebp) +movb $1,-243(%ebp) +movb $1,-143(%ebp) +movb $1,-175(%ebp) +movb $1,-165(%ebp) +movb $1,-244(%ebp) +movb $1,-142(%ebp) +movb $1,-174(%ebp) +movb $1,-163(%ebp) +movb $1,-141(%ebp) +movb $1,-173(%ebp) +movb $1,-213(%ebp) +movb $1,-164(%ebp) +movb $1,-140(%ebp) +movb $1,-172(%ebp) +movb $1,-197(%ebp) +movb $1,-217(%ebp) +movb $1,-139(%ebp) +movb $1,-171(%ebp) +movb $1,-214(%ebp) +movb $1,-138(%ebp) +movb $1,-170(%ebp) +movb $1,-198(%ebp) +movb $1,-256(%ebp) +movb $1,-137(%ebp) +movb $1,-169(%ebp) +movb $1,-196(%ebp) +movb $1,-224(%ebp) +movb $1,-136(%ebp) +movb $1,-168(%ebp) +movb $1,-194(%ebp) +movb $1,-135(%ebp) +movb $1,-167(%ebp) +movb $1,-212(%ebp) +movb $1,-134(%ebp) +movb $1,-166(%ebp) +movb $1,-210(%ebp) +movb $1,-193(%ebp) +movb $1,-209(%ebp) +leal -256(%ebp),%edi +pushl %edi +call sumof +addl $4,%esp +cmpl $98,%eax +je .LC313 +incl -268(%ebp) +movl 20(%ebp),%edi +cmpl $0,44(%edi) +je .LC315 +pushl $1 +pushl $s243er.211 +call printf +addl $8,%esp +.LC315: +.LC313: +jmp .LC317 +addl $8,-268(%ebp) +movl 20(%ebp),%edi +cmpl $0,44(%edi) +je .LC319 +pushl $8 +pushl $s243er.211 +call printf +addl $8,%esp +.LC319: +.LC317: +movl -268(%ebp),%eax +.LC210: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf321: +.size s243,.Lf321-s243 +.globl zerofill +.align 16 +.type zerofill,@function +zerofill: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +subl $4,%esp +movl $0,-4(%ebp) +.LC323: +movl 20(%ebp),%edi +leal 1(%edi),%esi +movl %esi,20(%ebp) +movb $0,(,%edi) +.LC324: +incl -4(%ebp) +cmpl $256,-4(%ebp) +jl .LC323 +mov $0,%eax +.LC322: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf327: +.size zerofill,.Lf327-zerofill +.globl sumof +.align 16 +.type sumof,@function +sumof: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +subl $12,%esp +movl 20(%ebp),%edi +movl %edi,-12(%ebp) +movl $0,-4(%ebp) +movl $0,-8(%ebp) +.LC329: +movl -12(%ebp),%edi +leal 1(%edi),%esi +movl %esi,-12(%ebp) +movsbl (,%edi),%edi +addl %edi,-4(%ebp) +.LC330: +incl -8(%ebp) +cmpl $256,-8(%ebp) +jl .LC329 +movl -4(%ebp),%eax +.LC328: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf333: +.size sumof,.Lf333-sumof +.data +.align 1 +.type s244er.335,@object +s244er.335: +.byte 115 +.byte 50 +.byte 52 +.byte 52 +.byte 44 +.byte 101 +.byte 114 +.byte 37 +.byte 100 +.byte 10 +.byte 0 +.size s244er.335,11 +.align 1 +.type qs244.336,@object +.size qs244.336,8 +qs244.336: +.byte 115 +.byte 50 +.byte 52 +.byte 52 +.byte 32 +.byte 32 +.byte 32 +.byte 0 +.globl s244 +.text +.align 16 +.type s244,@function +s244: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +subl $92,%esp +leal qs244.336,%edi +movl %edi,-72(%ebp) +movl 20(%ebp),%edi +leal 60(%edi),%edi +movl %edi,-76(%ebp) +.LC337: +.LC338: +movl -76(%ebp),%edi +leal 1(%edi),%esi +movl %esi,-76(%ebp) +movl -72(%ebp),%esi +leal 1(%esi),%ebx +movl %ebx,-72(%ebp) +movb (,%esi),%bl +movb %bl,(,%edi) +movsbl %bl,%edi +cmpl $0,%edi +jne .LC337 +movl $0,-84(%ebp) +movl $0,-80(%ebp) +fldl .LC340 +fstpl -68(%ebp) +fldl .LC340 +fstpl -60(%ebp) +fldl .LC340 +fstpl -52(%ebp) +fldl .LC340 +fstpl -44(%ebp) +fldl .LC340 +fstpl -36(%ebp) +fldl .LC340 +fstpl -28(%ebp) +fldl .LC340 +fstpl -20(%ebp) +fldl .LC340 +fstpl -12(%ebp) +movl $0,-80(%ebp) +movl $0,-4(%ebp) +.LC348: +movl -4(%ebp),%edi +leal (,%edi,8),%edi +leal -68(%ebp),%esi +leal -60(%ebp),%ebx +fldl (%ebx,%edi) +fcompl (%esi,%edi) +fstsw %ax +sahf +jp 1f +je .LC352 +1: +movl $1,-80(%ebp) +.LC352: +.LC349: +incl -4(%ebp) +cmpl $7,-4(%ebp) +jl .LC348 +cmpl $0,-80(%ebp) +je .LC355 +movl 20(%ebp),%edi +cmpl $0,44(%edi) +je .LC357 +pushl $1 +pushl $s244er.335 +call printf +addl $8,%esp +.LC357: +incl -84(%ebp) +.LC355: +jmp .LC359 +movl 20(%ebp),%edi +cmpl $0,44(%edi) +je .LC361 +pushl $2 +pushl $s244er.335 +call printf +addl $8,%esp +.LC361: +addl $2,-84(%ebp) +.LC359: +movl -84(%ebp),%eax +.LC334: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf363: +.size s244,.Lf363-s244 +.data +.align 1 +.type s25er.365,@object +s25er.365: +.byte 115 +.byte 50 +.byte 53 +.byte 44 +.byte 101 +.byte 114 +.byte 37 +.byte 100 +.byte 10 +.byte 0 +.size s25er.365,10 +.align 1 +.type qs25.366,@object +.size qs25.366,8 +qs25.366: +.byte 115 +.byte 50 +.byte 53 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 0 +.globl s25 +.text +.align 16 +.type s25,@function +s25: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +subl $28,%esp +leal qs25.366,%edi +movl %edi,-16(%ebp) +movl 20(%ebp),%edi +leal 60(%edi),%edi +movl %edi,-20(%ebp) +.LC367: +.LC368: +movl -20(%ebp),%edi +leal 1(%edi),%esi +movl %esi,-20(%ebp) +movl -16(%ebp),%esi +leal 1(%esi),%ebx +movl %ebx,-16(%ebp) +movb (,%esi),%bl +movb %bl,(,%edi) +movsbl %bl,%edi +cmpl $0,%edi +jne .LC367 +movl $0,-24(%ebp) +leal .LC370,%edi +movl %edi,-8(%ebp) +movl -8(%ebp),%edi +movsbl 1(%edi),%esi +movsbl (,%edi),%ebx +cmpl %esi,%ebx +jne .LC374 +movsbl 2(%edi),%edi +cmpl %edi,%esi +jne .LC374 +cmpl $46,%edi +je .LC371 +.LC374: +incl -24(%ebp) +movl 20(%ebp),%edi +cmpl $0,44(%edi) +je .LC375 +pushl $1 +pushl $s25er.365 +call printf +addl $8,%esp +.LC375: +.LC371: +movl -8(%ebp),%edi +movsbl 3(%edi),%edi +cmpl $0,%edi +je .LC377 +addl $4,-24(%ebp) +movl 20(%ebp),%edi +cmpl $0,44(%edi) +je .LC379 +pushl $4 +pushl $s25er.365 +call printf +addl $8,%esp +.LC379: +.LC377: +movsbl .LC383+1,%edi +cmpl $34,%edi +je .LC381 +addl $8,-24(%ebp) +movl 20(%ebp),%edi +cmpl $0,44(%edi) +je .LC385 +pushl $8 +pushl $s25er.365 +call printf +addl $8,%esp +.LC385: +.LC381: +leal .LC387,%edi +movl %edi,-8(%ebp) +movl -8(%ebp),%edi +movsbl (,%edi),%esi +cmpl $10,%esi +jne .LC395 +movsbl 1(%edi),%esi +cmpl $9,%esi +jne .LC395 +movsbl 2(%edi),%esi +cmpl $8,%esi +jne .LC395 +movsbl 3(%edi),%esi +cmpl $13,%esi +jne .LC395 +movsbl 4(%edi),%esi +cmpl $12,%esi +jne .LC395 +movsbl 5(%edi),%esi +cmpl $92,%esi +jne .LC395 +movsbl 6(%edi),%edi +cmpl $39,%edi +je .LC388 +.LC395: +addl $16,-24(%ebp) +movl 20(%ebp),%edi +cmpl $0,44(%edi) +je .LC396 +pushl $16 +pushl $s25er.365 +call printf +addl $8,%esp +.LC396: +.LC388: +leal .LC398,%edi +movl %edi,-12(%ebp) +movl %edi,-8(%ebp) +movl $0,-28(%ebp) +movl $0,-4(%ebp) +jmp .LC402 +.LC399: +movl -4(%ebp),%edi +movl -8(%ebp),%esi +movsbl (%esi,%edi),%esi +movl -12(%ebp),%ebx +movsbl (%ebx,%edi),%edi +cmpl %edi,%esi +je .LC403 +movl $1,-28(%ebp) +.LC403: +.LC400: +incl -4(%ebp) +.LC402: +movl -4(%ebp),%edi +cmpl $7,%edi +jb .LC399 +cmpl $0,-28(%ebp) +je .LC405 +addl $32,-24(%ebp) +movl 20(%ebp),%edi +cmpl $0,44(%edi) +je .LC407 +pushl $32 +pushl $s25er.365 +call printf +addl $8,%esp +.LC407: +.LC405: +movl -24(%ebp),%eax +.LC364: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf409: +.size s25,.Lf409-s25 +.data +.align 1 +.type qs26.411,@object +.size qs26.411,8 +qs26.411: +.byte 115 +.byte 50 +.byte 54 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 0 +.align 1 +.type s.412,@object +s.412: +.byte 37 +.byte 51 +.byte 100 +.byte 32 +.byte 98 +.byte 105 +.byte 116 +.byte 115 +.byte 32 +.byte 105 +.byte 110 +.byte 32 +.byte 37 +.byte 115 +.byte 115 +.byte 46 +.byte 10 +.byte 0 +.size s.412,18 +.align 1 +.type s2.413,@object +s2.413: +.byte 37 +.byte 101 +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 116 +.byte 104 +.byte 101 +.byte 32 +.byte 108 +.byte 101 +.byte 97 +.byte 115 +.byte 116 +.byte 32 +.byte 110 +.byte 117 +.byte 109 +.byte 98 +.byte 101 +.byte 114 +.byte 32 +.byte 116 +.byte 104 +.byte 97 +.byte 116 +.byte 32 +.byte 99 +.byte 97 +.byte 110 +.byte 32 +.byte 98 +.byte 101 +.byte 32 +.byte 97 +.byte 100 +.byte 100 +.byte 101 +.byte 100 +.byte 32 +.byte 116 +.byte 111 +.byte 32 +.byte 49 +.byte 46 +.byte 32 +.byte 40 +.byte 37 +.byte 115 +.byte 41 +.byte 46 +.byte 10 +.byte 0 +.size s2.413,54 +.globl s26 +.text +.align 16 +.type s26,@function +s26: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +subl $56,%esp +leal qs26.411,%edi +movl %edi,-36(%ebp) +movl 20(%ebp),%edi +leal 60(%edi),%edi +movl %edi,-40(%ebp) +.LC414: +.LC415: +movl -40(%ebp),%edi +leal 1(%edi),%esi +movl %esi,-40(%ebp) +movl -36(%ebp),%esi +leal 1(%esi),%ebx +movl %ebx,-36(%ebp) +movb (,%esi),%bl +movb %bl,(,%edi) +movsbl %bl,%edi +cmpl $0,%edi +jne .LC414 +movl 20(%ebp),%edi +movl $0,(,%edi) +movb $0,-44(%ebp) +movb $1,-8(%ebp) +jmp .LC418 +.LC417: +movsbl -8(%ebp),%edi +leal (,%edi,2),%edi +movl %edi,%ebx +movb %bl,-8(%ebp) +movl 20(%ebp),%edi +incl (,%edi) +.LC418: +movsbl -44(%ebp),%edi +movsbl -8(%ebp),%esi +cmpl %esi,%edi +jne .LC417 +movl 20(%ebp),%edi +movl (,%edi),%esi +leal (,%esi,4),%esi +movl %esi,4(%edi) +movl 20(%ebp),%edi +movl (,%edi),%esi +leal (,%esi,2),%esi +movl %esi,8(%edi) +movl 20(%ebp),%edi +movl (,%edi),%esi +leal (,%esi,4),%esi +movl %esi,12(%edi) +movl 20(%ebp),%edi +movl (,%edi),%esi +leal (,%esi,4),%esi +movl %esi,16(%edi) +movl 20(%ebp),%edi +movl (,%edi),%esi +leal (,%esi,4),%esi +movl %esi,20(%edi) +movl 20(%ebp),%edi +movl (,%edi),%esi +leal (,%esi,8),%esi +movl %esi,24(%edi) +flds .LC420 +fstps -16(%ebp) +flds .LC420 +fstps -4(%ebp) +flds .LC421 +fstps -12(%ebp) +jmp .LC423 +.LC422: +flds -16(%ebp) +fadds -4(%ebp) +fstps -12(%ebp) +flds -4(%ebp) +fdivl .LC425 +fstps -4(%ebp) +.LC423: +flds -16(%ebp) +fcomps -12(%ebp) +fstsw %ax +sahf +jp .LC422 +jne .LC422 +movl 20(%ebp),%edi +fldl .LC426 +fmuls -4(%ebp) +fstps 28(%edi) +fldl .LC427 +fstpl -32(%ebp) +flds .LC420 +fstps -4(%ebp) +fldl .LC428 +fstpl -24(%ebp) +jmp .LC430 +.LC429: +flds -4(%ebp) +fstpl -56(%ebp) +fldl -32(%ebp) +faddl -56(%ebp) +fstpl -24(%ebp) +fldl -56(%ebp) +fdivl .LC425 +fstps -4(%ebp) +.LC430: +fldl -32(%ebp) +fcompl -24(%ebp) +fstsw %ax +sahf +jp .LC429 +jne .LC429 +movl 20(%ebp),%edi +fldl .LC426 +fmuls -4(%ebp) +fstps 32(%edi) +movl 20(%ebp),%edi +cmpl $0,40(%edi) +je .LC432 +pushl $.LC434 +movl 20(%ebp),%edi +pushl (,%edi) +pushl $s.412 +call printf +addl $12,%esp +pushl $.LC435 +movl 20(%ebp),%edi +pushl 4(%edi) +pushl $s.412 +call printf +addl $12,%esp +pushl $.LC436 +movl 20(%ebp),%edi +pushl 8(%edi) +pushl $s.412 +call printf +addl $12,%esp +pushl $.LC437 +movl 20(%ebp),%edi +pushl 12(%edi) +pushl $s.412 +call printf +addl $12,%esp +pushl $.LC438 +movl 20(%ebp),%edi +pushl 16(%edi) +pushl $s.412 +call printf +addl $12,%esp +pushl $.LC439 +movl 20(%ebp),%edi +pushl 20(%edi) +pushl $s.412 +call printf +addl $12,%esp +pushl $.LC440 +movl 20(%ebp),%edi +pushl 24(%edi) +pushl $s.412 +call printf +addl $12,%esp +pushl $.LC439 +movl 20(%ebp),%edi +flds 28(%edi) +subl $8,%esp +fstpl (%esp) +pushl $s2.413 +call printf +addl $16,%esp +pushl $.LC440 +movl 20(%ebp),%edi +flds 32(%edi) +subl $8,%esp +fstpl (%esp) +pushl $s2.413 +call printf +addl $16,%esp +.LC432: +mov $0,%eax +.LC410: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf441: +.size s26,.Lf441-s26 +.data +.align 1 +.type s4er.443,@object +s4er.443: +.byte 115 +.byte 52 +.byte 44 +.byte 101 +.byte 114 +.byte 37 +.byte 100 +.byte 10 +.byte 0 +.size s4er.443,9 +.align 1 +.type qs4.444,@object +.size qs4.444,8 +qs4.444: +.byte 115 +.byte 52 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 0 +.globl s4 +.text +.align 16 +.type s4,@function +s4: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +subl $36,%esp +movl $0,-24(%ebp) +leal qs4.444,%edi +movl %edi,-16(%ebp) +movl 20(%ebp),%edi +leal 60(%edi),%edi +movl %edi,-20(%ebp) +.LC445: +.LC446: +movl -20(%ebp),%edi +leal 1(%edi),%esi +movl %esi,-20(%ebp) +movl -16(%ebp),%esi +leal 1(%esi),%ebx +movl %ebx,-16(%ebp) +movb (,%esi),%bl +movb %bl,(,%edi) +movsbl %bl,%edi +cmpl $0,%edi +jne .LC445 +movl $0,-4(%ebp) +.LC448: +pushl -4(%ebp) +call svtest +addl $4,%esp +movl %eax,%edi +call zero +cmpl %eax,%edi +je .LC452 +movl $1,-24(%ebp) +movl 20(%ebp),%edi +cmpl $0,44(%edi) +je .LC454 +pushl $1 +pushl $s4er.443 +call printf +addl $8,%esp +.LC454: +.LC452: +.LC449: +incl -4(%ebp) +cmpl $3,-4(%ebp) +jl .LC448 +call setev +call testev +cmpl $0,%eax +je .LC456 +addl $2,-24(%ebp) +movl 20(%ebp),%edi +cmpl $0,44(%edi) +je .LC458 +pushl $2 +pushl $s4er.443 +call printf +addl $8,%esp +.LC458: +.LC456: +jmp .LC460 +addl $4,-24(%ebp) +movl 20(%ebp),%edi +cmpl $0,44(%edi) +je .LC462 +pushl $4 +pushl $s4er.443 +call printf +addl $8,%esp +.LC462: +.LC460: +movl $0xffffffff,-8(%ebp) +movl $1,-12(%ebp) +movl $0,-4(%ebp) +jmp .LC467 +.LC464: +movl -8(%ebp),%edi +andl %edi,-12(%ebp) +shrl $1,%edi +movl %edi,-8(%ebp) +.LC465: +incl -4(%ebp) +.LC467: +movl -4(%ebp),%edi +movl 20(%ebp),%esi +movl (,%esi),%esi +leal (,%esi,4),%esi +cmpl %esi,%edi +jb .LC464 +movl -12(%ebp),%edi +cmpl $1,%edi +jne .LC470 +movl -8(%ebp),%edi +cmpl $0,%edi +je .LC468 +.LC470: +addl $8,-24(%ebp) +movl 20(%ebp),%edi +cmpl $0,44(%edi) +je .LC471 +pushl $8 +pushl $s4er.443 +call printf +addl $8,%esp +.LC471: +.LC468: +movl -24(%ebp),%eax +.LC442: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf473: +.size s4,.Lf473-s4 +.bss +.align 4 +.type k.475,@object +.size k.475,4 +.lcomm k.475,4 +.globl svtest +.text +.align 16 +.type svtest,@function +svtest: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +subl $4,%esp +movl 20(%ebp),%edi +cmpl $0,%edi +je .LC478 +cmpl $1,%edi +je .LC479 +cmpl $2,%edi +je .LC482 +jmp .LC476 +.LC478: +movl $1978,k.475 +movl $0,-4(%ebp) +jmp .LC477 +.LC479: +cmpl $1978,k.475 +je .LC480 +movl $1,-4(%ebp) +jmp .LC477 +.LC480: +movl $1929,k.475 +movl $0,-4(%ebp) +jmp .LC477 +.LC482: +cmpl $1929,k.475 +je .LC483 +movl $1,-4(%ebp) +jmp .LC477 +.LC483: +movl $0,-4(%ebp) +.LC476: +.LC477: +movl -4(%ebp),%eax +.LC474: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf485: +.size svtest,.Lf485-svtest +.bss +.align 4 +.type k.487,@object +.size k.487,4 +.lcomm k.487,4 +.globl zero +.text +.align 16 +.type zero,@function +zero: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +subl $4,%esp +movl $2,k.487 +movl $0,-4(%ebp) +movl -4(%ebp),%eax +.LC486: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf488: +.size zero,.Lf488-zero +.globl testev +.align 16 +.type testev,@function +testev: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +cmpl $1066,extvar +je .LC490 +mov $1,%eax +jmp .LC489 +.LC490: +mov $0,%eax +.LC489: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf492: +.size testev,.Lf492-testev +.data +.align 1 +.type s61er.494,@object +s61er.494: +.byte 115 +.byte 54 +.byte 49 +.byte 44 +.byte 101 +.byte 114 +.byte 37 +.byte 100 +.byte 10 +.byte 0 +.size s61er.494,10 +.align 1 +.type qs61.495,@object +.size qs61.495,8 +qs61.495: +.byte 115 +.byte 54 +.byte 49 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 0 +.align 1 +.type upper_alpha.496,@object +upper_alpha.496: +.byte 65 +.byte 66 +.byte 67 +.byte 68 +.byte 69 +.byte 70 +.byte 71 +.byte 72 +.byte 73 +.byte 74 +.byte 75 +.byte 76 +.byte 77 +.byte 78 +.byte 79 +.byte 80 +.byte 81 +.byte 82 +.byte 83 +.byte 84 +.byte 85 +.byte 86 +.byte 87 +.byte 88 +.byte 89 +.byte 90 +.byte 0 +.size upper_alpha.496,27 +.align 1 +.type lower_alpha.497,@object +lower_alpha.497: +.byte 97 +.byte 98 +.byte 99 +.byte 100 +.byte 101 +.byte 102 +.byte 103 +.byte 104 +.byte 105 +.byte 106 +.byte 107 +.byte 108 +.byte 109 +.byte 110 +.byte 111 +.byte 112 +.byte 113 +.byte 114 +.byte 115 +.byte 116 +.byte 117 +.byte 118 +.byte 119 +.byte 120 +.byte 121 +.byte 122 +.byte 0 +.size lower_alpha.497,27 +.align 1 +.type numbers.498,@object +numbers.498: +.byte 48 +.byte 49 +.byte 50 +.byte 51 +.byte 52 +.byte 53 +.byte 54 +.byte 55 +.byte 56 +.byte 57 +.byte 0 +.size numbers.498,11 +.align 1 +.type special_characters.499,@object +special_characters.499: +.byte 126 +.byte 33 +.byte 34 +.byte 35 +.byte 37 +.byte 38 +.byte 40 +.byte 41 +.byte 95 +.byte 61 +.byte 45 +.byte 94 +.byte 124 +.byte 123 +.byte 125 +.byte 91 +.byte 93 +.byte 43 +.byte 59 +.byte 42 +.byte 58 +.byte 60 +.byte 62 +.byte 44 +.byte 46 +.byte 63 +.byte 47 +.byte 0 +.size special_characters.499,28 +.align 1 +.type extra_special_characters.500,@object +extra_special_characters.500: +.byte 10 +.byte 9 +.byte 8 +.byte 13 +.byte 12 +.byte 92 +.byte 39 +.byte 0 +.size extra_special_characters.500,8 +.align 1 +.type blank_and_NUL.501,@object +blank_and_NUL.501: +.byte 32 +.byte 0 +.byte 0 +.size blank_and_NUL.501,3 +.globl s61 +.text +.align 16 +.type s61,@function +s61: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +subl $64,%esp +leal qs61.495,%edi +movl %edi,-36(%ebp) +movl 20(%ebp),%edi +leal 60(%edi),%edi +movl %edi,-40(%ebp) +movl $0,-48(%ebp) +.LC502: +.LC503: +movl -40(%ebp),%edi +leal 1(%edi),%esi +movl %esi,-40(%ebp) +movl -36(%ebp),%esi +leal 1(%esi),%ebx +movl %ebx,-36(%ebp) +movb (,%esi),%bl +movb %bl,(,%edi) +movsbl %bl,%edi +cmpl $0,%edi +jne .LC502 +movw $-19,-60(%ebp) +movswl -60(%ebp),%edi +movl %edi,-64(%ebp) +cmpl $-19,-64(%ebp) +je .LC505 +incl -48(%ebp) +movl 20(%ebp),%edi +cmpl $0,44(%edi) +je .LC507 +pushl $1 +pushl $s61er.494 +call printf +addl $8,%esp +.LC507: +.LC505: +leal upper_alpha.496,%edi +movl %edi,-28(%ebp) +leal lower_alpha.497,%edi +movl %edi,-24(%ebp) +leal numbers.498,%edi +movl %edi,-20(%ebp) +leal special_characters.499,%edi +movl %edi,-16(%ebp) +leal extra_special_characters.500,%edi +movl %edi,-12(%ebp) +leal blank_and_NUL.501,%edi +movl %edi,-8(%ebp) +movl $0,-32(%ebp) +movl $0,-4(%ebp) +jmp .LC519 +.LC518: +movl -4(%ebp),%edi +leal -28(%ebp),%esi +leal (%esi,%edi,4),%edi +movl (,%edi),%esi +leal 1(%esi),%ebx +movl %ebx,(,%edi) +movsbl (,%esi),%edi +cmpl $0,%edi +jge .LC521 +movl $1,-32(%ebp) +.LC521: +.LC519: +movl -4(%ebp),%edi +leal -28(%ebp),%esi +movl (%esi,%edi,4),%edi +movsbl (,%edi),%edi +cmpl $0,%edi +jne .LC518 +.LC515: +incl -4(%ebp) +cmpl $6,-4(%ebp) +jl .LC519 +cmpl $0,-32(%ebp) +je .LC523 +addl $2,-48(%ebp) +movl 20(%ebp),%edi +cmpl $0,44(%edi) +je .LC525 +pushl $2 +pushl $s61er.494 +call printf +addl $8,%esp +.LC525: +.LC523: +movl $1048579,-44(%ebp) +movl -44(%ebp),%edi +movl %edi,%esi +movw %si,-52(%ebp) +movl %edi,%ebx +movb %bl,-56(%ebp) +movswl -52(%ebp),%edi +cmpl -44(%ebp),%edi +je .LC530 +cmpl $3,%edi +jne .LC529 +.LC530: +movsbl -56(%ebp),%edi +cmpl -44(%ebp),%edi +je .LC527 +cmpl $3,%edi +je .LC527 +.LC529: +addl $8,-48(%ebp) +movl 20(%ebp),%edi +cmpl $0,44(%edi) +je .LC531 +pushl $8 +pushl $s61er.494 +call printf +addl $8,%esp +.LC531: +.LC527: +movl -48(%ebp),%eax +.LC493: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf533: +.size s61,.Lf533-s61 +.data +.align 1 +.type s626er.535,@object +s626er.535: +.byte 115 +.byte 54 +.byte 50 +.byte 54 +.byte 44 +.byte 101 +.byte 114 +.byte 37 +.byte 100 +.byte 10 +.byte 0 +.size s626er.535,11 +.align 1 +.type qs626.536,@object +.size qs626.536,8 +qs626.536: +.byte 115 +.byte 54 +.byte 50 +.byte 54 +.byte 32 +.byte 32 +.byte 32 +.byte 0 +.globl s626 +.text +.align 16 +.type s626,@function +s626: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +subl $132,%esp +leal qs626.536,%edi +movl %edi,-56(%ebp) +movl 20(%ebp),%edi +leal 60(%edi),%edi +movl %edi,-60(%ebp) +movl $0,-108(%ebp) +.LC537: +.LC538: +movl -60(%ebp),%edi +leal 1(%edi),%esi +movl %esi,-60(%ebp) +movl -56(%ebp),%esi +leal 1(%esi),%ebx +movl %ebx,-56(%ebp) +movb (,%esi),%bl +movb %bl,(,%edi) +movsbl %bl,%edi +cmpl $0,%edi +jne .LC537 +flds .LC420 +fstps -36(%ebp) +movl $1,-64(%ebp) +movl $1,-40(%ebp) +movl $0,-4(%ebp) +jmp .LC543 +.LC540: +flds .LC544 +fmuls -36(%ebp) +fstps -36(%ebp) +movl -40(%ebp),%edi +leal (,%edi,2),%edi +orl -64(%ebp),%edi +movl %edi,-40(%ebp) +.LC541: +incl -4(%ebp) +.LC543: +movl 20(%ebp),%edi +movl 12(%edi),%edi +subl $2,%edi +cmpl %edi,-4(%ebp) +jl .LC540 +fildl -40(%ebp) +fstps -116(%ebp) +flds -36(%ebp) +fsubs -116(%ebp) +fdivs -36(%ebp) +fstps -36(%ebp) +fldl .LC425 +movl 20(%ebp),%edi +fmuls 28(%edi) +fcomps -36(%ebp) +fstsw %ax +sahf +jp .LC545 +jae .LC545 +addl $2,-108(%ebp) +movl 20(%ebp),%edi +cmpl $0,44(%edi) +je .LC547 +pushl $2 +pushl $s626er.535 +call printf +addl $8,%esp +.LC547: +.LC545: +movb $125,-76(%ebp) +movw $125,-80(%ebp) +movl $125,-84(%ebp) +movl $15625,-100(%ebp) +movl $125,-88(%ebp) +movl $15625,-104(%ebp) +movl $125,-68(%ebp) +movl $15625,-112(%ebp) +flds .LC549 +fstps -72(%ebp) +fldl .LC550 +fstpl -96(%ebp) +fldl .LC551 +fstpl -52(%ebp) +movl $0,-4(%ebp) +.LC552: +movl -4(%ebp),%edi +leal -32(%ebp),%esi +movb $0,(%esi,%edi) +.LC553: +incl -4(%ebp) +cmpl $28,-4(%ebp) +jl .LC552 +movsbl -76(%ebp),%edi +movl %edi,%esi +imull %edi,%esi +cmpl -100(%ebp),%esi +je .LC556 +movb $1,-32(%ebp) +.LC556: +movswl -80(%ebp),%edi +movsbl -76(%ebp),%esi +imull %esi,%edi +cmpl -100(%ebp),%edi +je .LC558 +movb $1,-31(%ebp) +.LC558: +movswl -80(%ebp),%edi +movl %edi,%esi +imull %edi,%esi +cmpl -100(%ebp),%esi +je .LC561 +movb $1,-30(%ebp) +.LC561: +movl -84(%ebp),%edi +movsbl -76(%ebp),%esi +imull %esi,%edi +cmpl -100(%ebp),%edi +je .LC564 +movb $1,-29(%ebp) +.LC564: +movl -84(%ebp),%edi +movswl -80(%ebp),%esi +imull %esi,%edi +cmpl -100(%ebp),%edi +je .LC567 +movb $1,-28(%ebp) +.LC567: +movl -84(%ebp),%edi +movl %edi,%esi +imull %edi,%esi +cmpl -100(%ebp),%esi +je .LC570 +movb $1,-27(%ebp) +.LC570: +movl -88(%ebp),%eax +movsbl -76(%ebp),%edi +mull %edi +cmpl -104(%ebp),%eax +je .LC573 +movb $1,-26(%ebp) +.LC573: +movl -88(%ebp),%eax +movswl -80(%ebp),%edi +mull %edi +cmpl -104(%ebp),%eax +je .LC576 +movb $1,-25(%ebp) +.LC576: +movl -88(%ebp),%eax +movl -84(%ebp),%edi +mull %edi +cmpl -104(%ebp),%eax +je .LC579 +movb $1,-24(%ebp) +.LC579: +movl -88(%ebp),%edi +movl %edi,%eax +mull %edi +cmpl -104(%ebp),%eax +je .LC582 +movb $1,-23(%ebp) +.LC582: +movl -68(%ebp),%edi +movsbl -76(%ebp),%esi +imull %esi,%edi +cmpl -112(%ebp),%edi +je .LC585 +movb $1,-22(%ebp) +.LC585: +movl -68(%ebp),%edi +movswl -80(%ebp),%esi +imull %esi,%edi +cmpl -112(%ebp),%edi +je .LC588 +movb $1,-21(%ebp) +.LC588: +movl -68(%ebp),%edi +imull -84(%ebp),%edi +cmpl -112(%ebp),%edi +je .LC591 +movb $1,-20(%ebp) +.LC591: +movl -68(%ebp),%edi +movl %edi,%eax +mull -88(%ebp) +cmpl -104(%ebp),%eax +je .LC594 +movb $1,-19(%ebp) +.LC594: +movl -68(%ebp),%edi +movl %edi,%esi +imull %edi,%esi +cmpl -112(%ebp),%esi +je .LC597 +movb $1,-18(%ebp) +.LC597: +flds -72(%ebp) +movsbl -76(%ebp),%edi +pushl %edi +fildl (%esp) +addl $4,%esp +fmulp %st,%st(1) +fldl -52(%ebp) +fcompp +fstsw %ax +sahf +jp 1f +je .LC600 +1: +movb $1,-17(%ebp) +.LC600: +flds -72(%ebp) +movswl -80(%ebp),%edi +pushl %edi +fildl (%esp) +addl $4,%esp +fmulp %st,%st(1) +fldl -52(%ebp) +fcompp +fstsw %ax +sahf +jp 1f +je .LC603 +1: +movb $1,-16(%ebp) +.LC603: +flds -72(%ebp) +fildl -84(%ebp) +fmulp %st,%st(1) +fldl -52(%ebp) +fcompp +fstsw %ax +sahf +jp 1f +je .LC606 +1: +movb $1,-15(%ebp) +.LC606: +movl -88(%ebp),%edi +flds -72(%ebp) +fldl .LC611 +movl %edi,%esi +shrl $1,%esi +pushl %esi +fildl (%esp) +addl $4,%esp +fmulp %st,%st(1) +andl $1,%edi +pushl %edi +fildl (%esp) +addl $4,%esp +faddp %st,%st(1) +sub $4,%esp +fstps (%esp) +flds (%esp) +addl $4,%esp +fmulp %st,%st(1) +fldl -52(%ebp) +fcompp +fstsw %ax +sahf +jp 1f +je .LC609 +1: +movb $1,-14(%ebp) +.LC609: +flds -72(%ebp) +fildl -68(%ebp) +fmulp %st,%st(1) +fldl -52(%ebp) +fcompp +fstsw %ax +sahf +jp 1f +je .LC613 +1: +movb $1,-13(%ebp) +.LC613: +flds -72(%ebp) +fmuls -72(%ebp) +fldl -52(%ebp) +fcompp +fstsw %ax +sahf +jp 1f +je .LC616 +1: +movb $1,-12(%ebp) +.LC616: +fldl -96(%ebp) +movsbl -76(%ebp),%edi +pushl %edi +fildl (%esp) +addl $4,%esp +fmulp %st,%st(1) +fldl -52(%ebp) +fcompp +fstsw %ax +sahf +jp 1f +je .LC619 +1: +movb $1,-11(%ebp) +.LC619: +fldl -96(%ebp) +movswl -80(%ebp),%edi +pushl %edi +fildl (%esp) +addl $4,%esp +fmulp %st,%st(1) +fldl -52(%ebp) +fcompp +fstsw %ax +sahf +jp 1f +je .LC622 +1: +movb $1,-10(%ebp) +.LC622: +fldl -96(%ebp) +fimull -84(%ebp) +fldl -52(%ebp) +fcompp +fstsw %ax +sahf +jp 1f +je .LC625 +1: +movb $1,-9(%ebp) +.LC625: +movl -88(%ebp),%edi +fldl -96(%ebp) +fldl .LC611 +movl %edi,%esi +shrl $1,%esi +pushl %esi +fildl (%esp) +addl $4,%esp +fmulp %st,%st(1) +andl $1,%edi +pushl %edi +fildl (%esp) +addl $4,%esp +faddp %st,%st(1) +fmulp %st,%st(1) +fldl -52(%ebp) +fcompp +fstsw %ax +sahf +jp 1f +je .LC628 +1: +movb $1,-8(%ebp) +.LC628: +fldl -96(%ebp) +fimull -68(%ebp) +fldl -52(%ebp) +fcompp +fstsw %ax +sahf +jp 1f +je .LC631 +1: +movb $1,-7(%ebp) +.LC631: +fldl -96(%ebp) +fmuls -72(%ebp) +fldl -52(%ebp) +fcompp +fstsw %ax +sahf +jp 1f +je .LC634 +1: +movb $1,-6(%ebp) +.LC634: +fldl -96(%ebp) +fmull -96(%ebp) +fldl -52(%ebp) +fcompp +fstsw %ax +sahf +jp 1f +je .LC637 +1: +movb $1,-5(%ebp) +.LC637: +movb $0,-44(%ebp) +movl $0,-4(%ebp) +.LC640: +movsbl -44(%ebp),%edi +movl -4(%ebp),%esi +leal -32(%ebp),%ebx +movsbl (%ebx,%esi),%esi +leal (%esi,%edi),%edi +movl %edi,%ebx +movb %bl,-44(%ebp) +.LC641: +incl -4(%ebp) +cmpl $28,-4(%ebp) +jl .LC640 +movsbl -44(%ebp),%edi +cmpl $0,%edi +je .LC644 +addl $4,-108(%ebp) +movl 20(%ebp),%edi +cmpl $0,44(%edi) +je .LC646 +pushl $4 +pushl $s626er.535 +call printf +addl $8,%esp +pushl $.LC648 +call printf +addl $4,%esp +movl $0,-4(%ebp) +.LC649: +movl -4(%ebp),%edi +leal -32(%ebp),%esi +movsbl (%esi,%edi),%edi +pushl %edi +pushl $.LC653 +call printf +addl $8,%esp +.LC650: +incl -4(%ebp) +cmpl $28,-4(%ebp) +jl .LC649 +pushl $.LC654 +call printf +addl $4,%esp +.LC646: +.LC644: +movl $32768,-68(%ebp) +movl -68(%ebp),%edi +cmpl $0x8000,%edi +jbe .LC655 +addl $8,-108(%ebp) +movl 20(%ebp),%edi +cmpl $0,44(%edi) +je .LC657 +pushl $8 +pushl $s626er.535 +call printf +addl $8,%esp +.LC657: +.LC655: +movl -108(%ebp),%eax +.LC534: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf659: +.size s626,.Lf659-s626 +.data +.align 1 +.type s71er.661,@object +s71er.661: +.byte 115 +.byte 55 +.byte 49 +.byte 44 +.byte 101 +.byte 114 +.byte 37 +.byte 100 +.byte 10 +.byte 0 +.size s71er.661,10 +.align 1 +.type qs71.662,@object +.size qs71.662,8 +qs71.662: +.byte 115 +.byte 55 +.byte 49 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 0 +.align 1 +.type q.663,@object +.size q.663,1 +q.663: +.byte 113 +.globl s71 +.text +.align 16 +.type s71,@function +s71: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +subl $68,%esp +leal qs71.662,%edi +movl %edi,-4(%ebp) +movl 20(%ebp),%edi +leal 60(%edi),%edi +movl %edi,-8(%ebp) +movl $0,-12(%ebp) +.LC664: +.LC665: +movl -8(%ebp),%edi +leal 1(%edi),%esi +movl %esi,-8(%ebp) +movl -4(%ebp),%esi +leal 1(%esi),%ebx +movl %ebx,-4(%ebp) +movb (,%esi),%bl +movb %bl,(,%edi) +movsbl %bl,%edi +cmpl $0,%edi +jne .LC664 +movsbl .LC669,%edi +movsbl q.663,%esi +cmpl %esi,%edi +je .LC667 +incl -12(%ebp) +movl 20(%ebp),%edi +cmpl $0,44(%edi) +je .LC670 +pushl $1 +pushl $s71er.661 +call printf +addl $8,%esp +.LC670: +.LC667: +jmp .LC672 +addl $2,-12(%ebp) +movl 20(%ebp),%edi +cmpl $0,44(%edi) +je .LC674 +pushl $2 +pushl $s71er.661 +call printf +addl $8,%esp +.LC674: +.LC672: +movl $1942,-32(%ebp) +cmpl $1942,-32(%ebp) +jne .LC682 +movl -32(%ebp),%edi +cmpl %edi,-32(%ebp) +je .LC677 +.LC682: +addl $4,-12(%ebp) +movl 20(%ebp),%edi +cmpl $0,44(%edi) +je .LC683 +pushl $4 +pushl $s71er.661 +call printf +addl $8,%esp +.LC683: +.LC677: +pushl $-5 +call McCarthy +addl $4,%esp +cmpl $91,%eax +je .LC685 +addl $8,-12(%ebp) +movl 20(%ebp),%edi +cmpl $0,44(%edi) +je .LC687 +pushl $8 +pushl $s71er.661 +call printf +addl $8,%esp +.LC687: +.LC685: +movl $2,-56(%ebp) +movl $3,-60(%ebp) +leal -60(%ebp),%edi +movl %edi,-64(%ebp) +pushl -64(%ebp) +pushl -56(%ebp) +call clobber +addl $8,%esp +cmpl $2,-56(%ebp) +jne .LC691 +cmpl $2,-60(%ebp) +je .LC689 +.LC691: +addl $16,-12(%ebp) +movl 20(%ebp),%edi +cmpl $0,44(%edi) +je .LC692 +pushl $16 +pushl $s71er.661 +call printf +addl $8,%esp +.LC692: +.LC689: +movl 20(%ebp),%edi +flds 32(%edi) +fstps -68(%ebp) +flds -68(%ebp) +fcomps -68(%ebp) +fstsw %ax +sahf +jp 1f +je .LC694 +1: +addl $32,-12(%ebp) +movl 20(%ebp),%edi +cmpl $0,44(%edi) +je .LC696 +pushl $32 +pushl $s71er.661 +call printf +addl $8,%esp +.LC696: +.LC694: +movl -12(%ebp),%eax +.LC660: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf698: +.size s71,.Lf698-s71 +.globl McCarthy +.align 16 +.type McCarthy,@function +McCarthy: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +cmpl $100,20(%ebp) +jle .LC700 +movl 20(%ebp),%edi +movl %edi,%eax +subl $10,%eax +jmp .LC699 +.LC700: +movl 20(%ebp),%edi +leal 11(%edi),%edi +pushl %edi +call McCarthy +addl $4,%esp +movl %eax,%edi +pushl %edi +call McCarthy +addl $4,%esp +movl %eax,%edi +.LC699: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf702: +.size McCarthy,.Lf702-McCarthy +.globl clobber +.align 16 +.type clobber,@function +clobber: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +movl $3,20(%ebp) +movl 24(%ebp),%edi +movl $2,(,%edi) +mov $0,%eax +.LC703: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf704: +.size clobber,.Lf704-clobber +.data +.align 1 +.type f.706,@object +f.706: +.byte 76 +.byte 111 +.byte 99 +.byte 97 +.byte 108 +.byte 32 +.byte 101 +.byte 114 +.byte 114 +.byte 111 +.byte 114 +.byte 32 +.byte 37 +.byte 100 +.byte 46 +.byte 10 +.byte 0 +.size f.706,17 +.align 1 +.type s714er.707,@object +s714er.707: +.byte 115 +.byte 55 +.byte 49 +.byte 52 +.byte 44 +.byte 101 +.byte 114 +.byte 37 +.byte 100 +.byte 10 +.byte 0 +.size s714er.707,11 +.align 1 +.type qs714.708,@object +.size qs714.708,8 +qs714.708: +.byte 115 +.byte 55 +.byte 49 +.byte 52 +.byte 32 +.byte 32 +.byte 32 +.byte 0 +.globl s714 +.text +.align 16 +.type s714,@function +s714: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +subl $256,%esp +leal qs714.708,%edi +movl %edi,-76(%ebp) +movl 20(%ebp),%edi +leal 60(%edi),%esi +movl %esi,-80(%ebp) +movl $0,-84(%ebp) +movl $0,-8(%ebp) +movl 48(%edi),%edi +movl %edi,-4(%ebp) +.LC709: +.LC710: +movl -80(%ebp),%edi +leal 1(%edi),%esi +movl %esi,-80(%ebp) +movl -76(%ebp),%esi +leal 1(%esi),%ebx +movl %ebx,-76(%ebp) +movb (,%esi),%bl +movb %bl,(,%edi) +movsbl %bl,%edi +cmpl $0,%edi +jne .LC709 +movb $5,-12(%ebp) +movb $2,-32(%ebp) +movb -32(%ebp),%bl +movb %bl,-12(%ebp) +movsbl -12(%ebp),%edi +cmpl $2,%edi +je .LC712 +movl $1,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC714 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC714: +.LC712: +movb $5,-12(%ebp) +movw $2,-36(%ebp) +movswl -36(%ebp),%edi +movl %edi,%ebx +movb %bl,-12(%ebp) +movsbl -12(%ebp),%edi +cmpl $2,%edi +je .LC716 +movl $2,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC718 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC718: +.LC716: +movb $5,-12(%ebp) +movl $2,-40(%ebp) +movl -40(%ebp),%edi +movl %edi,%ebx +movb %bl,-12(%ebp) +movsbl -12(%ebp),%edi +cmpl $2,%edi +je .LC720 +movl $3,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC722 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC722: +.LC720: +movb $5,-12(%ebp) +movl $2,-44(%ebp) +movl -44(%ebp),%edi +movl %edi,%ebx +movb %bl,-12(%ebp) +movsbl -12(%ebp),%edi +cmpl $2,%edi +je .LC724 +movl $4,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC726 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC726: +.LC724: +movb $5,-12(%ebp) +movl $2,-48(%ebp) +movl -48(%ebp),%edi +movl %edi,%ebx +movb %bl,-12(%ebp) +movsbl -12(%ebp),%edi +cmpl $2,%edi +je .LC728 +movl $5,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC730 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC730: +.LC728: +movb $5,-12(%ebp) +flds .LC544 +fstps -64(%ebp) +flds -64(%ebp) +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,%ebx +movb %bl,-12(%ebp) +movsbl -12(%ebp),%edi +cmpl $2,%edi +je .LC732 +movl $6,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC734 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC734: +.LC732: +movb $5,-12(%ebp) +fldl .LC425 +fstpl -72(%ebp) +fldl -72(%ebp) +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,%ebx +movb %bl,-12(%ebp) +movsbl -12(%ebp),%edi +cmpl $2,%edi +je .LC736 +movl $7,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC738 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC738: +.LC736: +movw $5,-16(%ebp) +movb $2,-32(%ebp) +movsbl -32(%ebp),%edi +movw %di,-16(%ebp) +movswl -16(%ebp),%edi +cmpl $2,%edi +je .LC740 +movl $8,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC742 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC742: +.LC740: +movw $5,-16(%ebp) +movw $2,-36(%ebp) +movw -36(%ebp),%di +movw %di,-16(%ebp) +movswl -16(%ebp),%edi +cmpl $2,%edi +je .LC744 +movl $9,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC746 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC746: +.LC744: +movw $5,-16(%ebp) +movl $2,-40(%ebp) +movl -40(%ebp),%edi +movw %di,-16(%ebp) +movswl -16(%ebp),%edi +cmpl $2,%edi +je .LC748 +movl $10,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC750 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC750: +.LC748: +movw $5,-16(%ebp) +movl $2,-44(%ebp) +movl -44(%ebp),%edi +movw %di,-16(%ebp) +movswl -16(%ebp),%edi +cmpl $2,%edi +je .LC752 +movl $11,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC754 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC754: +.LC752: +movw $5,-16(%ebp) +movl $2,-48(%ebp) +movl -48(%ebp),%edi +movw %di,-16(%ebp) +movswl -16(%ebp),%edi +cmpl $2,%edi +je .LC756 +movl $12,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC758 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC758: +.LC756: +movw $5,-16(%ebp) +flds .LC544 +fstps -64(%ebp) +flds -64(%ebp) +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,%edi +movw %di,-16(%ebp) +movswl -16(%ebp),%edi +cmpl $2,%edi +je .LC760 +movl $13,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC762 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC762: +.LC760: +movw $5,-16(%ebp) +fldl .LC425 +fstpl -72(%ebp) +fldl -72(%ebp) +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,%edi +movw %di,-16(%ebp) +movswl -16(%ebp),%edi +cmpl $2,%edi +je .LC764 +movl $14,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC766 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC766: +.LC764: +movl $5,-20(%ebp) +movb $2,-32(%ebp) +movsbl -32(%ebp),%edi +movl %edi,-20(%ebp) +cmpl $2,-20(%ebp) +je .LC768 +movl $15,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC770 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC770: +.LC768: +movl $5,-20(%ebp) +movw $2,-36(%ebp) +movswl -36(%ebp),%edi +movl %edi,-20(%ebp) +cmpl $2,-20(%ebp) +je .LC772 +movl $16,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC774 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC774: +.LC772: +movl $5,-20(%ebp) +movl $2,-40(%ebp) +movl -40(%ebp),%edi +movl %edi,-20(%ebp) +cmpl $2,-20(%ebp) +je .LC776 +movl $17,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC778 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC778: +.LC776: +movl $5,-20(%ebp) +movl $2,-44(%ebp) +movl -44(%ebp),%edi +movl %edi,-20(%ebp) +cmpl $2,-20(%ebp) +je .LC780 +movl $18,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC782 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC782: +.LC780: +movl $5,-20(%ebp) +movl $2,-48(%ebp) +movl -48(%ebp),%edi +movl %edi,-20(%ebp) +cmpl $2,-20(%ebp) +je .LC784 +movl $19,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC786 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC786: +.LC784: +movl $5,-20(%ebp) +flds .LC544 +fstps -64(%ebp) +flds -64(%ebp) +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,-20(%ebp) +cmpl $2,-20(%ebp) +je .LC788 +movl $20,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC790 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC790: +.LC788: +movl $5,-20(%ebp) +fldl .LC425 +fstpl -72(%ebp) +fldl -72(%ebp) +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,-20(%ebp) +cmpl $2,-20(%ebp) +je .LC792 +movl $21,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC794 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC794: +.LC792: +movl $5,-24(%ebp) +movb $2,-32(%ebp) +movsbl -32(%ebp),%edi +movl %edi,-24(%ebp) +cmpl $2,-24(%ebp) +je .LC796 +movl $22,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC798 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC798: +.LC796: +movl $5,-24(%ebp) +movw $2,-36(%ebp) +movswl -36(%ebp),%edi +movl %edi,-24(%ebp) +cmpl $2,-24(%ebp) +je .LC800 +movl $23,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC802 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC802: +.LC800: +movl $5,-24(%ebp) +movl $2,-40(%ebp) +movl -40(%ebp),%edi +movl %edi,-24(%ebp) +cmpl $2,-24(%ebp) +je .LC804 +movl $24,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC806 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC806: +.LC804: +movl $5,-24(%ebp) +movl $2,-44(%ebp) +movl -44(%ebp),%edi +movl %edi,-24(%ebp) +cmpl $2,-24(%ebp) +je .LC808 +movl $25,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC810 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC810: +.LC808: +movl $5,-24(%ebp) +movl $2,-48(%ebp) +movl -48(%ebp),%edi +movl %edi,-24(%ebp) +cmpl $2,-24(%ebp) +je .LC812 +movl $26,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC814 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC814: +.LC812: +movl $5,-24(%ebp) +flds .LC544 +fstps -64(%ebp) +flds -64(%ebp) +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,-24(%ebp) +cmpl $2,-24(%ebp) +je .LC816 +movl $27,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC818 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC818: +.LC816: +movl $5,-24(%ebp) +fldl .LC425 +fstpl -72(%ebp) +fldl -72(%ebp) +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,-24(%ebp) +cmpl $2,-24(%ebp) +je .LC820 +movl $28,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC822 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC822: +.LC820: +movl $5,-28(%ebp) +movb $2,-32(%ebp) +movsbl -32(%ebp),%edi +movl %edi,-28(%ebp) +movl -28(%ebp),%edi +cmpl $2,%edi +je .LC824 +movl $29,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC826 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC826: +.LC824: +movl $5,-28(%ebp) +movw $2,-36(%ebp) +movswl -36(%ebp),%edi +movl %edi,-28(%ebp) +movl -28(%ebp),%edi +cmpl $2,%edi +je .LC828 +movl $30,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC830 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC830: +.LC828: +movl $5,-28(%ebp) +movl $2,-40(%ebp) +movl -40(%ebp),%edi +movl %edi,-28(%ebp) +movl -28(%ebp),%edi +cmpl $2,%edi +je .LC832 +movl $31,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC834 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC834: +.LC832: +movl $5,-28(%ebp) +movl $2,-44(%ebp) +movl -44(%ebp),%edi +movl %edi,-28(%ebp) +movl -28(%ebp),%edi +cmpl $2,%edi +je .LC836 +movl $32,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC838 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC838: +.LC836: +movl $5,-28(%ebp) +movl $2,-48(%ebp) +movl -48(%ebp),%edi +movl %edi,-28(%ebp) +movl -28(%ebp),%edi +cmpl $2,%edi +je .LC840 +movl $33,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC842 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC842: +.LC840: +movl $5,-28(%ebp) +flds .LC544 +fstps -64(%ebp) +flds .LC847 +fcomps -64(%ebp) +fstsw %ax +sahf +jp .LC845 +ja .LC845 +flds -64(%ebp) +fsubs .LC847 +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,%edi +leal 0x80000000(%edi),%edi +movl %edi,-88(%ebp) +jmp .LC846 +.LC845: +flds -64(%ebp) +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,%edi +movl %edi,-88(%ebp) +.LC846: +movl -88(%ebp),%edi +movl %edi,-28(%ebp) +movl -28(%ebp),%edi +cmpl $2,%edi +je .LC848 +movl $34,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC850 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC850: +.LC848: +movl $5,-28(%ebp) +fldl .LC425 +fstpl -72(%ebp) +fldl .LC855 +fcompl -72(%ebp) +fstsw %ax +sahf +jp .LC853 +ja .LC853 +fldl -72(%ebp) +fsubl .LC855 +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,%edi +leal 0x80000000(%edi),%edi +movl %edi,-100(%ebp) +jmp .LC854 +.LC853: +fldl -72(%ebp) +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,%edi +movl %edi,-100(%ebp) +.LC854: +movl -100(%ebp),%edi +movl %edi,-28(%ebp) +movl -28(%ebp),%edi +cmpl $2,%edi +je .LC856 +movl $35,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC858 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC858: +.LC856: +flds .LC860 +fstps -52(%ebp) +movb $2,-32(%ebp) +movsbl -32(%ebp),%edi +pushl %edi +fildl (%esp) +addl $4,%esp +fstps -52(%ebp) +flds .LC544 +fcomps -52(%ebp) +fstsw %ax +sahf +jp 1f +je .LC861 +1: +movl $36,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC863 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC863: +.LC861: +flds .LC860 +fstps -52(%ebp) +movw $2,-36(%ebp) +movswl -36(%ebp),%edi +pushl %edi +fildl (%esp) +addl $4,%esp +fstps -52(%ebp) +flds .LC544 +fcomps -52(%ebp) +fstsw %ax +sahf +jp 1f +je .LC865 +1: +movl $37,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC867 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC867: +.LC865: +flds .LC860 +fstps -52(%ebp) +movl $2,-40(%ebp) +fildl -40(%ebp) +fstps -52(%ebp) +flds .LC544 +fcomps -52(%ebp) +fstsw %ax +sahf +jp 1f +je .LC869 +1: +movl $38,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC871 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC871: +.LC869: +flds .LC860 +fstps -52(%ebp) +movl $2,-44(%ebp) +fildl -44(%ebp) +fstps -52(%ebp) +flds .LC544 +fcomps -52(%ebp) +fstsw %ax +sahf +jp 1f +je .LC873 +1: +movl $39,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC875 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC875: +.LC873: +flds .LC860 +fstps -52(%ebp) +movl $2,-48(%ebp) +movl -48(%ebp),%edi +fldl .LC611 +movl %edi,%esi +shrl $1,%esi +pushl %esi +fildl (%esp) +addl $4,%esp +fmulp %st,%st(1) +andl $1,%edi +pushl %edi +fildl (%esp) +addl $4,%esp +faddp %st,%st(1) +fstps -52(%ebp) +flds .LC544 +fcomps -52(%ebp) +fstsw %ax +sahf +jp 1f +je .LC877 +1: +movl $40,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC879 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC879: +.LC877: +flds .LC860 +fstps -52(%ebp) +flds .LC544 +fstps -64(%ebp) +flds -64(%ebp) +fstps -52(%ebp) +flds .LC544 +fcomps -52(%ebp) +fstsw %ax +sahf +jp 1f +je .LC881 +1: +movl $41,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC883 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC883: +.LC881: +flds .LC860 +fstps -52(%ebp) +fldl .LC425 +fstpl -72(%ebp) +fldl -72(%ebp) +fstps -52(%ebp) +flds .LC544 +fcomps -52(%ebp) +fstsw %ax +sahf +jp 1f +je .LC885 +1: +movl $42,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC887 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC887: +.LC885: +fldl .LC889 +fstpl -60(%ebp) +movb $2,-32(%ebp) +movsbl -32(%ebp),%edi +pushl %edi +fildl (%esp) +addl $4,%esp +fstpl -60(%ebp) +fldl .LC425 +fcompl -60(%ebp) +fstsw %ax +sahf +jp 1f +je .LC890 +1: +movl $43,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC892 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC892: +.LC890: +fldl .LC889 +fstpl -60(%ebp) +movw $2,-36(%ebp) +movswl -36(%ebp),%edi +pushl %edi +fildl (%esp) +addl $4,%esp +fstpl -60(%ebp) +fldl .LC425 +fcompl -60(%ebp) +fstsw %ax +sahf +jp 1f +je .LC894 +1: +movl $44,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC896 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC896: +.LC894: +fldl .LC889 +fstpl -60(%ebp) +movl $2,-40(%ebp) +fildl -40(%ebp) +fstpl -60(%ebp) +fldl .LC425 +fcompl -60(%ebp) +fstsw %ax +sahf +jp 1f +je .LC898 +1: +movl $45,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC900 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC900: +.LC898: +fldl .LC889 +fstpl -60(%ebp) +movl $2,-44(%ebp) +fildl -44(%ebp) +fstpl -60(%ebp) +fldl .LC425 +fcompl -60(%ebp) +fstsw %ax +sahf +jp 1f +je .LC902 +1: +movl $46,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC904 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC904: +.LC902: +fldl .LC889 +fstpl -60(%ebp) +movl $2,-48(%ebp) +movl -48(%ebp),%edi +fldl .LC611 +movl %edi,%esi +shrl $1,%esi +pushl %esi +fildl (%esp) +addl $4,%esp +fmulp %st,%st(1) +andl $1,%edi +pushl %edi +fildl (%esp) +addl $4,%esp +faddp %st,%st(1) +fstpl -60(%ebp) +fldl .LC425 +fcompl -60(%ebp) +fstsw %ax +sahf +jp 1f +je .LC906 +1: +movl $47,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC908 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC908: +.LC906: +fldl .LC889 +fstpl -60(%ebp) +flds .LC544 +fstps -64(%ebp) +flds -64(%ebp) +fstpl -60(%ebp) +fldl .LC425 +fcompl -60(%ebp) +fstsw %ax +sahf +jp 1f +je .LC910 +1: +movl $48,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC912 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC912: +.LC910: +fldl .LC889 +fstpl -60(%ebp) +fldl .LC425 +fstpl -72(%ebp) +fldl -72(%ebp) +fstpl -60(%ebp) +fldl .LC425 +fcompl -60(%ebp) +fstsw %ax +sahf +jp 1f +je .LC914 +1: +movl $49,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC916 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC916: +.LC914: +movb $5,-12(%ebp) +movb $2,-32(%ebp) +movsbl -12(%ebp),%edi +movsbl -32(%ebp),%esi +leal (%esi,%edi),%edi +movl %edi,%ebx +movb %bl,-12(%ebp) +movsbl -12(%ebp),%edi +cmpl $7,%edi +je .LC918 +movl $50,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC920 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC920: +.LC918: +movb $5,-12(%ebp) +movw $2,-36(%ebp) +movsbl -12(%ebp),%edi +movswl -36(%ebp),%esi +leal (%esi,%edi),%edi +movl %edi,%ebx +movb %bl,-12(%ebp) +movsbl -12(%ebp),%edi +cmpl $7,%edi +je .LC922 +movl $51,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC924 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC924: +.LC922: +movb $5,-12(%ebp) +movl $2,-40(%ebp) +movsbl -12(%ebp),%edi +movl -40(%ebp),%esi +leal (%esi,%edi),%edi +movl %edi,%ebx +movb %bl,-12(%ebp) +movsbl -12(%ebp),%edi +cmpl $7,%edi +je .LC926 +movl $52,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC928 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC928: +.LC926: +movb $5,-12(%ebp) +movl $2,-44(%ebp) +movsbl -12(%ebp),%edi +movl -44(%ebp),%esi +leal (%esi,%edi),%edi +movl %edi,%ebx +movb %bl,-12(%ebp) +movsbl -12(%ebp),%edi +cmpl $7,%edi +je .LC930 +movl $53,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC932 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC932: +.LC930: +movb $5,-12(%ebp) +movl $2,-48(%ebp) +movsbl -12(%ebp),%edi +movl -48(%ebp),%esi +leal (%esi,%edi),%edi +movl %edi,%ebx +movb %bl,-12(%ebp) +movsbl -12(%ebp),%edi +cmpl $7,%edi +je .LC934 +movl $54,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC936 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC936: +.LC934: +movb $5,-12(%ebp) +flds .LC544 +fstps -64(%ebp) +movsbl -12(%ebp),%edi +pushl %edi +fildl (%esp) +addl $4,%esp +fadds -64(%ebp) +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,%ebx +movb %bl,-12(%ebp) +movsbl -12(%ebp),%edi +cmpl $7,%edi +je .LC938 +movl $55,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC940 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC940: +.LC938: +movb $5,-12(%ebp) +fldl .LC425 +fstpl -72(%ebp) +movsbl -12(%ebp),%edi +pushl %edi +fildl (%esp) +addl $4,%esp +faddl -72(%ebp) +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,%ebx +movb %bl,-12(%ebp) +movsbl -12(%ebp),%edi +cmpl $7,%edi +je .LC942 +movl $56,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC944 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC944: +.LC942: +movw $5,-16(%ebp) +movb $2,-32(%ebp) +movswl -16(%ebp),%edi +movsbl -32(%ebp),%esi +leal (%esi,%edi),%edi +movw %di,-16(%ebp) +movswl -16(%ebp),%edi +cmpl $7,%edi +je .LC946 +movl $57,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC948 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC948: +.LC946: +movw $5,-16(%ebp) +movw $2,-36(%ebp) +movswl -16(%ebp),%edi +movswl -36(%ebp),%esi +leal (%esi,%edi),%edi +movw %di,-16(%ebp) +movswl -16(%ebp),%edi +cmpl $7,%edi +je .LC950 +movl $58,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC952 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC952: +.LC950: +movw $5,-16(%ebp) +movl $2,-40(%ebp) +movswl -16(%ebp),%edi +movl -40(%ebp),%esi +leal (%esi,%edi),%edi +movw %di,-16(%ebp) +movswl -16(%ebp),%edi +cmpl $7,%edi +je .LC954 +movl $59,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC956 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC956: +.LC954: +movw $5,-16(%ebp) +movl $2,-44(%ebp) +movswl -16(%ebp),%edi +movl -44(%ebp),%esi +leal (%esi,%edi),%edi +movw %di,-16(%ebp) +movswl -16(%ebp),%edi +cmpl $7,%edi +je .LC958 +movl $60,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC960 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC960: +.LC958: +movw $5,-16(%ebp) +movl $2,-48(%ebp) +movswl -16(%ebp),%edi +movl -48(%ebp),%esi +leal (%esi,%edi),%edi +movw %di,-16(%ebp) +movswl -16(%ebp),%edi +cmpl $7,%edi +je .LC962 +movl $61,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC964 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC964: +.LC962: +movw $5,-16(%ebp) +flds .LC544 +fstps -64(%ebp) +movswl -16(%ebp),%edi +pushl %edi +fildl (%esp) +addl $4,%esp +fadds -64(%ebp) +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,%edi +movw %di,-16(%ebp) +movswl -16(%ebp),%edi +cmpl $7,%edi +je .LC966 +movl $62,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC968 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC968: +.LC966: +movw $5,-16(%ebp) +fldl .LC425 +fstpl -72(%ebp) +movswl -16(%ebp),%edi +pushl %edi +fildl (%esp) +addl $4,%esp +faddl -72(%ebp) +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,%edi +movw %di,-16(%ebp) +movswl -16(%ebp),%edi +cmpl $7,%edi +je .LC970 +movl $63,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC972 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC972: +.LC970: +movl $5,-20(%ebp) +movb $2,-32(%ebp) +movsbl -32(%ebp),%edi +addl %edi,-20(%ebp) +cmpl $7,-20(%ebp) +je .LC974 +movl $64,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC976 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC976: +.LC974: +movl $5,-20(%ebp) +movw $2,-36(%ebp) +movswl -36(%ebp),%edi +addl %edi,-20(%ebp) +cmpl $7,-20(%ebp) +je .LC978 +movl $65,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC980 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC980: +.LC978: +movl $5,-20(%ebp) +movl $2,-40(%ebp) +movl -40(%ebp),%edi +addl %edi,-20(%ebp) +cmpl $7,-20(%ebp) +je .LC982 +movl $66,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC984 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC984: +.LC982: +movl $5,-20(%ebp) +movl $2,-44(%ebp) +movl -44(%ebp),%edi +addl %edi,-20(%ebp) +cmpl $7,-20(%ebp) +je .LC986 +movl $67,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC988 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC988: +.LC986: +movl $5,-20(%ebp) +movl $2,-48(%ebp) +movl -20(%ebp),%edi +movl -48(%ebp),%esi +leal (%esi,%edi),%edi +movl %edi,-20(%ebp) +cmpl $7,-20(%ebp) +je .LC990 +movl $68,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC992 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC992: +.LC990: +movl $5,-20(%ebp) +flds .LC544 +fstps -64(%ebp) +fildl -20(%ebp) +fadds -64(%ebp) +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,-20(%ebp) +cmpl $7,-20(%ebp) +je .LC994 +movl $69,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC996 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC996: +.LC994: +movl $5,-20(%ebp) +fldl .LC425 +fstpl -72(%ebp) +fildl -20(%ebp) +faddl -72(%ebp) +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,-20(%ebp) +cmpl $7,-20(%ebp) +je .LC998 +movl $70,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1000 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1000: +.LC998: +movl $5,-24(%ebp) +movb $2,-32(%ebp) +movsbl -32(%ebp),%edi +addl %edi,-24(%ebp) +cmpl $7,-24(%ebp) +je .LC1002 +movl $71,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1004 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1004: +.LC1002: +movl $5,-24(%ebp) +movw $2,-36(%ebp) +movswl -36(%ebp),%edi +addl %edi,-24(%ebp) +cmpl $7,-24(%ebp) +je .LC1006 +movl $72,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1008 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1008: +.LC1006: +movl $5,-24(%ebp) +movl $2,-40(%ebp) +movl -40(%ebp),%edi +addl %edi,-24(%ebp) +cmpl $7,-24(%ebp) +je .LC1010 +movl $73,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1012 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1012: +.LC1010: +movl $5,-24(%ebp) +movl $2,-44(%ebp) +movl -44(%ebp),%edi +addl %edi,-24(%ebp) +cmpl $7,-24(%ebp) +je .LC1014 +movl $74,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1016 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1016: +.LC1014: +movl $5,-24(%ebp) +movl $2,-48(%ebp) +movl -24(%ebp),%edi +movl -48(%ebp),%esi +leal (%esi,%edi),%edi +movl %edi,-24(%ebp) +cmpl $7,-24(%ebp) +je .LC1018 +movl $75,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1020 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1020: +.LC1018: +movl $5,-24(%ebp) +flds .LC544 +fstps -64(%ebp) +fildl -24(%ebp) +fadds -64(%ebp) +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,-24(%ebp) +cmpl $7,-24(%ebp) +je .LC1022 +movl $76,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1024 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1024: +.LC1022: +movl $5,-24(%ebp) +fldl .LC425 +fstpl -72(%ebp) +fildl -24(%ebp) +faddl -72(%ebp) +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,-24(%ebp) +cmpl $7,-24(%ebp) +je .LC1026 +movl $77,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1028 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1028: +.LC1026: +movl $5,-28(%ebp) +movb $2,-32(%ebp) +movsbl -32(%ebp),%edi +addl %edi,-28(%ebp) +movl -28(%ebp),%edi +cmpl $7,%edi +je .LC1030 +movl $78,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1032 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1032: +.LC1030: +movl $5,-28(%ebp) +movw $2,-36(%ebp) +movswl -36(%ebp),%edi +addl %edi,-28(%ebp) +movl -28(%ebp),%edi +cmpl $7,%edi +je .LC1034 +movl $79,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1036 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1036: +.LC1034: +movl $5,-28(%ebp) +movl $2,-40(%ebp) +movl -40(%ebp),%edi +addl %edi,-28(%ebp) +movl -28(%ebp),%edi +cmpl $7,%edi +je .LC1038 +movl $80,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1040 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1040: +.LC1038: +movl $5,-28(%ebp) +movl $2,-44(%ebp) +movl -44(%ebp),%edi +addl %edi,-28(%ebp) +movl -28(%ebp),%edi +cmpl $7,%edi +je .LC1042 +movl $81,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1044 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1044: +.LC1042: +movl $5,-28(%ebp) +movl $2,-48(%ebp) +movl -48(%ebp),%edi +addl %edi,-28(%ebp) +movl -28(%ebp),%edi +cmpl $7,%edi +je .LC1046 +movl $82,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1048 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1048: +.LC1046: +movl $5,-28(%ebp) +flds .LC544 +fstps -64(%ebp) +movl -28(%ebp),%edi +fldl .LC611 +movl %edi,%esi +shrl $1,%esi +pushl %esi +fildl (%esp) +addl $4,%esp +fmulp %st,%st(1) +andl $1,%edi +pushl %edi +fildl (%esp) +addl $4,%esp +faddp %st,%st(1) +sub $4,%esp +fstps (%esp) +flds (%esp) +addl $4,%esp +fadds -64(%ebp) +fstps -136(%ebp) +flds .LC847 +fcomps -136(%ebp) +fstsw %ax +sahf +jp .LC1051 +ja .LC1051 +flds -136(%ebp) +fsubs .LC847 +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,%edi +leal 0x80000000(%edi),%edi +movl %edi,-132(%ebp) +jmp .LC1052 +.LC1051: +flds -136(%ebp) +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,%edi +movl %edi,-132(%ebp) +.LC1052: +movl -132(%ebp),%edi +movl %edi,-28(%ebp) +movl -28(%ebp),%edi +cmpl $7,%edi +je .LC1053 +movl $83,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1055 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1055: +.LC1053: +movl $5,-28(%ebp) +fldl .LC425 +fstpl -72(%ebp) +movl -28(%ebp),%edi +fldl .LC611 +movl %edi,%esi +shrl $1,%esi +pushl %esi +fildl (%esp) +addl $4,%esp +fmulp %st,%st(1) +andl $1,%edi +pushl %edi +fildl (%esp) +addl $4,%esp +faddp %st,%st(1) +faddl -72(%ebp) +fstpl -152(%ebp) +fldl .LC855 +fcompl -152(%ebp) +fstsw %ax +sahf +jp .LC1058 +ja .LC1058 +fldl -152(%ebp) +fsubl .LC855 +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,%edi +leal 0x80000000(%edi),%edi +movl %edi,-144(%ebp) +jmp .LC1059 +.LC1058: +fldl -152(%ebp) +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,%edi +movl %edi,-144(%ebp) +.LC1059: +movl -144(%ebp),%edi +movl %edi,-28(%ebp) +movl -28(%ebp),%edi +cmpl $7,%edi +je .LC1060 +movl $84,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1062 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1062: +.LC1060: +flds .LC860 +fstps -52(%ebp) +movb $2,-32(%ebp) +flds -52(%ebp) +movsbl -32(%ebp),%edi +pushl %edi +fildl (%esp) +addl $4,%esp +faddp %st,%st(1) +fstps -52(%ebp) +flds .LC1066 +fcomps -52(%ebp) +fstsw %ax +sahf +jp 1f +je .LC1064 +1: +movl $85,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1067 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1067: +.LC1064: +flds .LC860 +fstps -52(%ebp) +movw $2,-36(%ebp) +flds -52(%ebp) +movswl -36(%ebp),%edi +pushl %edi +fildl (%esp) +addl $4,%esp +faddp %st,%st(1) +fstps -52(%ebp) +flds .LC1066 +fcomps -52(%ebp) +fstsw %ax +sahf +jp 1f +je .LC1069 +1: +movl $86,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1071 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1071: +.LC1069: +flds .LC860 +fstps -52(%ebp) +movl $2,-40(%ebp) +flds -52(%ebp) +fildl -40(%ebp) +faddp %st,%st(1) +fstps -52(%ebp) +flds .LC1066 +fcomps -52(%ebp) +fstsw %ax +sahf +jp 1f +je .LC1073 +1: +movl $87,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1075 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1075: +.LC1073: +flds .LC860 +fstps -52(%ebp) +movl $2,-44(%ebp) +flds -52(%ebp) +fildl -44(%ebp) +faddp %st,%st(1) +fstps -52(%ebp) +flds .LC1066 +fcomps -52(%ebp) +fstsw %ax +sahf +jp 1f +je .LC1077 +1: +movl $88,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1079 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1079: +.LC1077: +flds .LC860 +fstps -52(%ebp) +movl $2,-48(%ebp) +movl -48(%ebp),%edi +flds -52(%ebp) +fldl .LC611 +movl %edi,%esi +shrl $1,%esi +pushl %esi +fildl (%esp) +addl $4,%esp +fmulp %st,%st(1) +andl $1,%edi +pushl %edi +fildl (%esp) +addl $4,%esp +faddp %st,%st(1) +sub $4,%esp +fstps (%esp) +flds (%esp) +addl $4,%esp +faddp %st,%st(1) +fstps -52(%ebp) +flds .LC1066 +fcomps -52(%ebp) +fstsw %ax +sahf +jp 1f +je .LC1081 +1: +movl $89,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1083 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1083: +.LC1081: +flds .LC860 +fstps -52(%ebp) +flds .LC544 +fstps -64(%ebp) +flds -52(%ebp) +fadds -64(%ebp) +fstps -52(%ebp) +flds .LC1066 +fcomps -52(%ebp) +fstsw %ax +sahf +jp 1f +je .LC1085 +1: +movl $90,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1087 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1087: +.LC1085: +flds .LC860 +fstps -52(%ebp) +fldl .LC425 +fstpl -72(%ebp) +flds -52(%ebp) +faddl -72(%ebp) +fstps -52(%ebp) +flds .LC1066 +fcomps -52(%ebp) +fstsw %ax +sahf +jp 1f +je .LC1089 +1: +movl $91,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1091 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1091: +.LC1089: +fldl .LC889 +fstpl -60(%ebp) +movb $2,-32(%ebp) +fldl -60(%ebp) +movsbl -32(%ebp),%edi +pushl %edi +fildl (%esp) +addl $4,%esp +faddp %st,%st(1) +fstpl -60(%ebp) +fldl .LC1095 +fcompl -60(%ebp) +fstsw %ax +sahf +jp 1f +je .LC1093 +1: +movl $92,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1096 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1096: +.LC1093: +fldl .LC889 +fstpl -60(%ebp) +movw $2,-36(%ebp) +fldl -60(%ebp) +movswl -36(%ebp),%edi +pushl %edi +fildl (%esp) +addl $4,%esp +faddp %st,%st(1) +fstpl -60(%ebp) +fldl .LC1095 +fcompl -60(%ebp) +fstsw %ax +sahf +jp 1f +je .LC1098 +1: +movl $93,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1100 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1100: +.LC1098: +fldl .LC889 +fstpl -60(%ebp) +movl $2,-40(%ebp) +fldl -60(%ebp) +fiaddl -40(%ebp) +fstpl -60(%ebp) +fldl .LC1095 +fcompl -60(%ebp) +fstsw %ax +sahf +jp 1f +je .LC1102 +1: +movl $94,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1104 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1104: +.LC1102: +fldl .LC889 +fstpl -60(%ebp) +movl $2,-44(%ebp) +fldl -60(%ebp) +fiaddl -44(%ebp) +fstpl -60(%ebp) +fldl .LC1095 +fcompl -60(%ebp) +fstsw %ax +sahf +jp 1f +je .LC1106 +1: +movl $95,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1108 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1108: +.LC1106: +fldl .LC889 +fstpl -60(%ebp) +movl $2,-48(%ebp) +movl -48(%ebp),%edi +fldl -60(%ebp) +fldl .LC611 +movl %edi,%esi +shrl $1,%esi +pushl %esi +fildl (%esp) +addl $4,%esp +fmulp %st,%st(1) +andl $1,%edi +pushl %edi +fildl (%esp) +addl $4,%esp +faddp %st,%st(1) +faddp %st,%st(1) +fstpl -60(%ebp) +fldl .LC1095 +fcompl -60(%ebp) +fstsw %ax +sahf +jp 1f +je .LC1110 +1: +movl $96,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1112 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1112: +.LC1110: +fldl .LC889 +fstpl -60(%ebp) +flds .LC544 +fstps -64(%ebp) +fldl -60(%ebp) +fadds -64(%ebp) +fstpl -60(%ebp) +fldl .LC1095 +fcompl -60(%ebp) +fstsw %ax +sahf +jp 1f +je .LC1114 +1: +movl $97,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1116 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1116: +.LC1114: +fldl .LC889 +fstpl -60(%ebp) +fldl .LC425 +fstpl -72(%ebp) +fldl -60(%ebp) +faddl -72(%ebp) +fstpl -60(%ebp) +fldl .LC1095 +fcompl -60(%ebp) +fstsw %ax +sahf +jp 1f +je .LC1118 +1: +movl $98,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1120 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1120: +.LC1118: +movb $5,-12(%ebp) +movb $2,-32(%ebp) +movsbl -12(%ebp),%edi +movsbl -32(%ebp),%esi +subl %esi,%edi +movl %edi,%ebx +movb %bl,-12(%ebp) +movsbl -12(%ebp),%edi +cmpl $3,%edi +je .LC1122 +movl $99,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1124 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1124: +.LC1122: +movb $5,-12(%ebp) +movw $2,-36(%ebp) +movsbl -12(%ebp),%edi +movswl -36(%ebp),%esi +subl %esi,%edi +movl %edi,%ebx +movb %bl,-12(%ebp) +movsbl -12(%ebp),%edi +cmpl $3,%edi +je .LC1126 +movl $100,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1128 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1128: +.LC1126: +movb $5,-12(%ebp) +movl $2,-40(%ebp) +movsbl -12(%ebp),%edi +subl -40(%ebp),%edi +movl %edi,%ebx +movb %bl,-12(%ebp) +movsbl -12(%ebp),%edi +cmpl $3,%edi +je .LC1130 +movl $101,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1132 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1132: +.LC1130: +movb $5,-12(%ebp) +movl $2,-44(%ebp) +movsbl -12(%ebp),%edi +subl -44(%ebp),%edi +movl %edi,%ebx +movb %bl,-12(%ebp) +movsbl -12(%ebp),%edi +cmpl $3,%edi +je .LC1134 +movl $102,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1136 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1136: +.LC1134: +movb $5,-12(%ebp) +movl $2,-48(%ebp) +movsbl -12(%ebp),%edi +subl -48(%ebp),%edi +movl %edi,%ebx +movb %bl,-12(%ebp) +movsbl -12(%ebp),%edi +cmpl $3,%edi +je .LC1138 +movl $103,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1140 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1140: +.LC1138: +movb $5,-12(%ebp) +flds .LC544 +fstps -64(%ebp) +movsbl -12(%ebp),%edi +pushl %edi +fildl (%esp) +addl $4,%esp +fsubs -64(%ebp) +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,%ebx +movb %bl,-12(%ebp) +movsbl -12(%ebp),%edi +cmpl $3,%edi +je .LC1142 +movl $104,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1144 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1144: +.LC1142: +movb $5,-12(%ebp) +fldl .LC425 +fstpl -72(%ebp) +movsbl -12(%ebp),%edi +pushl %edi +fildl (%esp) +addl $4,%esp +fsubl -72(%ebp) +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,%ebx +movb %bl,-12(%ebp) +movsbl -12(%ebp),%edi +cmpl $3,%edi +je .LC1146 +movl $105,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1148 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1148: +.LC1146: +movw $5,-16(%ebp) +movb $2,-32(%ebp) +movswl -16(%ebp),%edi +movsbl -32(%ebp),%esi +subl %esi,%edi +movw %di,-16(%ebp) +movswl -16(%ebp),%edi +cmpl $3,%edi +je .LC1150 +movl $106,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1152 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1152: +.LC1150: +movw $5,-16(%ebp) +movw $2,-36(%ebp) +movswl -16(%ebp),%edi +movswl -36(%ebp),%esi +subl %esi,%edi +movw %di,-16(%ebp) +movswl -16(%ebp),%edi +cmpl $3,%edi +je .LC1154 +movl $107,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1156 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1156: +.LC1154: +movw $5,-16(%ebp) +movl $2,-40(%ebp) +movswl -16(%ebp),%edi +subl -40(%ebp),%edi +movw %di,-16(%ebp) +movswl -16(%ebp),%edi +cmpl $3,%edi +je .LC1158 +movl $108,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1160 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1160: +.LC1158: +movw $5,-16(%ebp) +movl $2,-44(%ebp) +movswl -16(%ebp),%edi +subl -44(%ebp),%edi +movw %di,-16(%ebp) +movswl -16(%ebp),%edi +cmpl $3,%edi +je .LC1162 +movl $109,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1164 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1164: +.LC1162: +movw $5,-16(%ebp) +movl $2,-48(%ebp) +movswl -16(%ebp),%edi +subl -48(%ebp),%edi +movw %di,-16(%ebp) +movswl -16(%ebp),%edi +cmpl $3,%edi +je .LC1166 +movl $110,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1168 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1168: +.LC1166: +movw $5,-16(%ebp) +flds .LC544 +fstps -64(%ebp) +movswl -16(%ebp),%edi +pushl %edi +fildl (%esp) +addl $4,%esp +fsubs -64(%ebp) +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,%edi +movw %di,-16(%ebp) +movswl -16(%ebp),%edi +cmpl $3,%edi +je .LC1170 +movl $111,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1172 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1172: +.LC1170: +movw $5,-16(%ebp) +fldl .LC425 +fstpl -72(%ebp) +movswl -16(%ebp),%edi +pushl %edi +fildl (%esp) +addl $4,%esp +fsubl -72(%ebp) +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,%edi +movw %di,-16(%ebp) +movswl -16(%ebp),%edi +cmpl $3,%edi +je .LC1174 +movl $112,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1176 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1176: +.LC1174: +movl $5,-20(%ebp) +movb $2,-32(%ebp) +movsbl -32(%ebp),%edi +subl %edi,-20(%ebp) +cmpl $3,-20(%ebp) +je .LC1178 +movl $113,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1180 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1180: +.LC1178: +movl $5,-20(%ebp) +movw $2,-36(%ebp) +movswl -36(%ebp),%edi +subl %edi,-20(%ebp) +cmpl $3,-20(%ebp) +je .LC1182 +movl $114,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1184 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1184: +.LC1182: +movl $5,-20(%ebp) +movl $2,-40(%ebp) +movl -40(%ebp),%edi +subl %edi,-20(%ebp) +cmpl $3,-20(%ebp) +je .LC1186 +movl $115,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1188 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1188: +.LC1186: +movl $5,-20(%ebp) +movl $2,-44(%ebp) +movl -44(%ebp),%edi +subl %edi,-20(%ebp) +cmpl $3,-20(%ebp) +je .LC1190 +movl $116,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1192 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1192: +.LC1190: +movl $5,-20(%ebp) +movl $2,-48(%ebp) +movl -20(%ebp),%edi +subl -48(%ebp),%edi +movl %edi,-20(%ebp) +cmpl $3,-20(%ebp) +je .LC1194 +movl $117,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1196 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1196: +.LC1194: +movl $5,-20(%ebp) +flds .LC544 +fstps -64(%ebp) +fildl -20(%ebp) +fsubs -64(%ebp) +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,-20(%ebp) +cmpl $3,-20(%ebp) +je .LC1198 +movl $118,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1200 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1200: +.LC1198: +movl $5,-20(%ebp) +fldl .LC425 +fstpl -72(%ebp) +fldl -72(%ebp) +fisubrl -20(%ebp) +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,-20(%ebp) +cmpl $3,-20(%ebp) +je .LC1202 +movl $119,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1204 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1204: +.LC1202: +movl $5,-24(%ebp) +movb $2,-32(%ebp) +movsbl -32(%ebp),%edi +subl %edi,-24(%ebp) +cmpl $3,-24(%ebp) +je .LC1206 +movl $120,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1208 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1208: +.LC1206: +movl $5,-24(%ebp) +movw $2,-36(%ebp) +movswl -36(%ebp),%edi +subl %edi,-24(%ebp) +cmpl $3,-24(%ebp) +je .LC1210 +movl $121,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1212 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1212: +.LC1210: +movl $5,-24(%ebp) +movl $2,-40(%ebp) +movl -40(%ebp),%edi +subl %edi,-24(%ebp) +cmpl $3,-24(%ebp) +je .LC1214 +movl $122,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1216 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1216: +.LC1214: +movl $5,-24(%ebp) +movl $2,-44(%ebp) +movl -44(%ebp),%edi +subl %edi,-24(%ebp) +cmpl $3,-24(%ebp) +je .LC1218 +movl $123,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1220 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1220: +.LC1218: +movl $5,-24(%ebp) +movl $2,-48(%ebp) +movl -24(%ebp),%edi +subl -48(%ebp),%edi +movl %edi,-24(%ebp) +cmpl $3,-24(%ebp) +je .LC1222 +movl $124,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1224 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1224: +.LC1222: +movl $5,-24(%ebp) +flds .LC544 +fstps -64(%ebp) +fildl -24(%ebp) +fsubs -64(%ebp) +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,-24(%ebp) +cmpl $3,-24(%ebp) +je .LC1226 +movl $125,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1228 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1228: +.LC1226: +movl $5,-24(%ebp) +fldl .LC425 +fstpl -72(%ebp) +fldl -72(%ebp) +fisubrl -24(%ebp) +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,-24(%ebp) +cmpl $3,-24(%ebp) +je .LC1230 +movl $126,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1232 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1232: +.LC1230: +movl $5,-28(%ebp) +movb $2,-32(%ebp) +movsbl -32(%ebp),%edi +subl %edi,-28(%ebp) +movl -28(%ebp),%edi +cmpl $3,%edi +je .LC1234 +movl $127,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1236 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1236: +.LC1234: +movl $5,-28(%ebp) +movw $2,-36(%ebp) +movswl -36(%ebp),%edi +subl %edi,-28(%ebp) +movl -28(%ebp),%edi +cmpl $3,%edi +je .LC1238 +movl $128,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1240 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1240: +.LC1238: +movl $5,-28(%ebp) +movl $2,-40(%ebp) +movl -40(%ebp),%edi +subl %edi,-28(%ebp) +movl -28(%ebp),%edi +cmpl $3,%edi +je .LC1242 +movl $129,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1244 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1244: +.LC1242: +movl $5,-28(%ebp) +movl $2,-44(%ebp) +movl -44(%ebp),%edi +subl %edi,-28(%ebp) +movl -28(%ebp),%edi +cmpl $3,%edi +je .LC1246 +movl $130,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1248 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1248: +.LC1246: +movl $5,-28(%ebp) +movl $2,-48(%ebp) +movl -48(%ebp),%edi +subl %edi,-28(%ebp) +movl -28(%ebp),%edi +cmpl $3,%edi +je .LC1250 +movl $131,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1252 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1252: +.LC1250: +movl $5,-28(%ebp) +flds .LC544 +fstps -64(%ebp) +movl -28(%ebp),%edi +fldl .LC611 +movl %edi,%esi +shrl $1,%esi +pushl %esi +fildl (%esp) +addl $4,%esp +fmulp %st,%st(1) +andl $1,%edi +pushl %edi +fildl (%esp) +addl $4,%esp +faddp %st,%st(1) +sub $4,%esp +fstps (%esp) +flds (%esp) +addl $4,%esp +fsubs -64(%ebp) +fstps -168(%ebp) +flds .LC847 +fcomps -168(%ebp) +fstsw %ax +sahf +jp .LC1255 +ja .LC1255 +flds -168(%ebp) +fsubs .LC847 +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,%edi +leal 0x80000000(%edi),%edi +movl %edi,-164(%ebp) +jmp .LC1256 +.LC1255: +flds -168(%ebp) +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,%edi +movl %edi,-164(%ebp) +.LC1256: +movl -164(%ebp),%edi +movl %edi,-28(%ebp) +movl -28(%ebp),%edi +cmpl $3,%edi +je .LC1257 +movl $132,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1259 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1259: +.LC1257: +movl $5,-28(%ebp) +fldl .LC425 +fstpl -72(%ebp) +movl -28(%ebp),%edi +fldl .LC611 +movl %edi,%esi +shrl $1,%esi +pushl %esi +fildl (%esp) +addl $4,%esp +fmulp %st,%st(1) +andl $1,%edi +pushl %edi +fildl (%esp) +addl $4,%esp +faddp %st,%st(1) +fsubl -72(%ebp) +fstpl -184(%ebp) +fldl .LC855 +fcompl -184(%ebp) +fstsw %ax +sahf +jp .LC1262 +ja .LC1262 +fldl -184(%ebp) +fsubl .LC855 +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,%edi +leal 0x80000000(%edi),%edi +movl %edi,-176(%ebp) +jmp .LC1263 +.LC1262: +fldl -184(%ebp) +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,%edi +movl %edi,-176(%ebp) +.LC1263: +movl -176(%ebp),%edi +movl %edi,-28(%ebp) +movl -28(%ebp),%edi +cmpl $3,%edi +je .LC1264 +movl $133,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1266 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1266: +.LC1264: +flds .LC860 +fstps -52(%ebp) +movb $2,-32(%ebp) +flds -52(%ebp) +movsbl -32(%ebp),%edi +pushl %edi +fildl (%esp) +addl $4,%esp +fsubrp %st,%st(1) +fstps -52(%ebp) +flds .LC1270 +fcomps -52(%ebp) +fstsw %ax +sahf +jp 1f +je .LC1268 +1: +movl $134,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1271 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1271: +.LC1268: +flds .LC860 +fstps -52(%ebp) +movw $2,-36(%ebp) +flds -52(%ebp) +movswl -36(%ebp),%edi +pushl %edi +fildl (%esp) +addl $4,%esp +fsubrp %st,%st(1) +fstps -52(%ebp) +flds .LC1270 +fcomps -52(%ebp) +fstsw %ax +sahf +jp 1f +je .LC1273 +1: +movl $135,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1275 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1275: +.LC1273: +flds .LC860 +fstps -52(%ebp) +movl $2,-40(%ebp) +flds -52(%ebp) +fildl -40(%ebp) +fsubrp %st,%st(1) +fstps -52(%ebp) +flds .LC1270 +fcomps -52(%ebp) +fstsw %ax +sahf +jp 1f +je .LC1277 +1: +movl $136,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1279 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1279: +.LC1277: +flds .LC860 +fstps -52(%ebp) +movl $2,-44(%ebp) +flds -52(%ebp) +fildl -44(%ebp) +fsubrp %st,%st(1) +fstps -52(%ebp) +flds .LC1270 +fcomps -52(%ebp) +fstsw %ax +sahf +jp 1f +je .LC1281 +1: +movl $137,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1283 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1283: +.LC1281: +flds .LC860 +fstps -52(%ebp) +movl $2,-48(%ebp) +movl -48(%ebp),%edi +flds -52(%ebp) +fldl .LC611 +movl %edi,%esi +shrl $1,%esi +pushl %esi +fildl (%esp) +addl $4,%esp +fmulp %st,%st(1) +andl $1,%edi +pushl %edi +fildl (%esp) +addl $4,%esp +faddp %st,%st(1) +sub $4,%esp +fstps (%esp) +flds (%esp) +addl $4,%esp +fsubrp %st,%st(1) +fstps -52(%ebp) +flds .LC1270 +fcomps -52(%ebp) +fstsw %ax +sahf +jp 1f +je .LC1285 +1: +movl $138,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1287 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1287: +.LC1285: +flds .LC860 +fstps -52(%ebp) +flds .LC544 +fstps -64(%ebp) +flds -52(%ebp) +fsubs -64(%ebp) +fstps -52(%ebp) +flds .LC1270 +fcomps -52(%ebp) +fstsw %ax +sahf +jp 1f +je .LC1289 +1: +movl $139,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1291 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1291: +.LC1289: +flds .LC860 +fstps -52(%ebp) +fldl .LC425 +fstpl -72(%ebp) +flds -52(%ebp) +fsubl -72(%ebp) +fstps -52(%ebp) +flds .LC1270 +fcomps -52(%ebp) +fstsw %ax +sahf +jp 1f +je .LC1293 +1: +movl $140,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1295 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1295: +.LC1293: +fldl .LC889 +fstpl -60(%ebp) +movb $2,-32(%ebp) +fldl -60(%ebp) +movsbl -32(%ebp),%edi +pushl %edi +fildl (%esp) +addl $4,%esp +fsubrp %st,%st(1) +fstpl -60(%ebp) +fldl .LC1299 +fcompl -60(%ebp) +fstsw %ax +sahf +jp 1f +je .LC1297 +1: +movl $141,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1300 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1300: +.LC1297: +fldl .LC889 +fstpl -60(%ebp) +movw $2,-36(%ebp) +fldl -60(%ebp) +movswl -36(%ebp),%edi +pushl %edi +fildl (%esp) +addl $4,%esp +fsubrp %st,%st(1) +fstpl -60(%ebp) +fldl .LC1299 +fcompl -60(%ebp) +fstsw %ax +sahf +jp 1f +je .LC1302 +1: +movl $142,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1304 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1304: +.LC1302: +fldl .LC889 +fstpl -60(%ebp) +movl $2,-40(%ebp) +fldl -60(%ebp) +fisubl -40(%ebp) +fstpl -60(%ebp) +fldl .LC1299 +fcompl -60(%ebp) +fstsw %ax +sahf +jp 1f +je .LC1306 +1: +movl $143,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1308 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1308: +.LC1306: +fldl .LC889 +fstpl -60(%ebp) +movl $2,-44(%ebp) +fldl -60(%ebp) +fisubl -44(%ebp) +fstpl -60(%ebp) +fldl .LC1299 +fcompl -60(%ebp) +fstsw %ax +sahf +jp 1f +je .LC1310 +1: +movl $144,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1312 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1312: +.LC1310: +fldl .LC889 +fstpl -60(%ebp) +movl $2,-48(%ebp) +movl -48(%ebp),%edi +fldl -60(%ebp) +fldl .LC611 +movl %edi,%esi +shrl $1,%esi +pushl %esi +fildl (%esp) +addl $4,%esp +fmulp %st,%st(1) +andl $1,%edi +pushl %edi +fildl (%esp) +addl $4,%esp +faddp %st,%st(1) +fsubrp %st,%st(1) +fstpl -60(%ebp) +fldl .LC1299 +fcompl -60(%ebp) +fstsw %ax +sahf +jp 1f +je .LC1314 +1: +movl $145,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1316 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1316: +.LC1314: +fldl .LC889 +fstpl -60(%ebp) +flds .LC544 +fstps -64(%ebp) +fldl -60(%ebp) +fsubs -64(%ebp) +fstpl -60(%ebp) +fldl .LC1299 +fcompl -60(%ebp) +fstsw %ax +sahf +jp 1f +je .LC1318 +1: +movl $146,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1320 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1320: +.LC1318: +fldl .LC889 +fstpl -60(%ebp) +fldl .LC425 +fstpl -72(%ebp) +fldl -60(%ebp) +fsubl -72(%ebp) +fstpl -60(%ebp) +fldl .LC1299 +fcompl -60(%ebp) +fstsw %ax +sahf +jp 1f +je .LC1322 +1: +movl $147,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1324 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1324: +.LC1322: +movb $5,-12(%ebp) +movb $2,-32(%ebp) +movsbl -12(%ebp),%edi +movsbl -32(%ebp),%esi +imull %esi,%edi +movl %edi,%ebx +movb %bl,-12(%ebp) +movsbl -12(%ebp),%edi +cmpl $10,%edi +je .LC1326 +movl $148,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1328 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1328: +.LC1326: +movb $5,-12(%ebp) +movw $2,-36(%ebp) +movsbl -12(%ebp),%edi +movswl -36(%ebp),%esi +imull %esi,%edi +movl %edi,%ebx +movb %bl,-12(%ebp) +movsbl -12(%ebp),%edi +cmpl $10,%edi +je .LC1330 +movl $149,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1332 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1332: +.LC1330: +movb $5,-12(%ebp) +movl $2,-40(%ebp) +movsbl -12(%ebp),%edi +imull -40(%ebp),%edi +movl %edi,%ebx +movb %bl,-12(%ebp) +movsbl -12(%ebp),%edi +cmpl $10,%edi +je .LC1334 +movl $150,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1336 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1336: +.LC1334: +movb $5,-12(%ebp) +movl $2,-44(%ebp) +movsbl -12(%ebp),%edi +imull -44(%ebp),%edi +movl %edi,%ebx +movb %bl,-12(%ebp) +movsbl -12(%ebp),%edi +cmpl $10,%edi +je .LC1338 +movl $151,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1340 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1340: +.LC1338: +movb $5,-12(%ebp) +movl $2,-48(%ebp) +movsbl -12(%ebp),%edi +movl %edi,%eax +mull -48(%ebp) +movl %eax,%edi +movl %edi,%ebx +movb %bl,-12(%ebp) +movsbl -12(%ebp),%edi +cmpl $10,%edi +je .LC1342 +movl $152,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1344 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1344: +.LC1342: +movb $5,-12(%ebp) +flds .LC544 +fstps -64(%ebp) +movsbl -12(%ebp),%edi +pushl %edi +fildl (%esp) +addl $4,%esp +fmuls -64(%ebp) +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,%ebx +movb %bl,-12(%ebp) +movsbl -12(%ebp),%edi +cmpl $10,%edi +je .LC1346 +movl $153,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1348 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1348: +.LC1346: +movb $5,-12(%ebp) +fldl .LC425 +fstpl -72(%ebp) +movsbl -12(%ebp),%edi +pushl %edi +fildl (%esp) +addl $4,%esp +fmull -72(%ebp) +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,%ebx +movb %bl,-12(%ebp) +movsbl -12(%ebp),%edi +cmpl $10,%edi +je .LC1350 +movl $154,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1352 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1352: +.LC1350: +movw $5,-16(%ebp) +movb $2,-32(%ebp) +movswl -16(%ebp),%edi +movsbl -32(%ebp),%esi +imull %esi,%edi +movw %di,-16(%ebp) +movswl -16(%ebp),%edi +cmpl $10,%edi +je .LC1354 +movl $155,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1356 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1356: +.LC1354: +movw $5,-16(%ebp) +movw $2,-36(%ebp) +movswl -16(%ebp),%edi +movswl -36(%ebp),%esi +imull %esi,%edi +movw %di,-16(%ebp) +movswl -16(%ebp),%edi +cmpl $10,%edi +je .LC1358 +movl $156,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1360 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1360: +.LC1358: +movw $5,-16(%ebp) +movl $2,-40(%ebp) +movswl -16(%ebp),%edi +imull -40(%ebp),%edi +movw %di,-16(%ebp) +movswl -16(%ebp),%edi +cmpl $10,%edi +je .LC1362 +movl $157,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1364 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1364: +.LC1362: +movw $5,-16(%ebp) +movl $2,-44(%ebp) +movswl -16(%ebp),%edi +imull -44(%ebp),%edi +movw %di,-16(%ebp) +movswl -16(%ebp),%edi +cmpl $10,%edi +je .LC1366 +movl $158,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1368 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1368: +.LC1366: +movw $5,-16(%ebp) +movl $2,-48(%ebp) +movswl -16(%ebp),%edi +movl %edi,%eax +mull -48(%ebp) +movl %eax,%edi +movw %di,-16(%ebp) +movswl -16(%ebp),%edi +cmpl $10,%edi +je .LC1370 +movl $159,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1372 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1372: +.LC1370: +movw $5,-16(%ebp) +flds .LC544 +fstps -64(%ebp) +movswl -16(%ebp),%edi +pushl %edi +fildl (%esp) +addl $4,%esp +fmuls -64(%ebp) +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,%edi +movw %di,-16(%ebp) +movswl -16(%ebp),%edi +cmpl $10,%edi +je .LC1374 +movl $160,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1376 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1376: +.LC1374: +movw $5,-16(%ebp) +fldl .LC425 +fstpl -72(%ebp) +movswl -16(%ebp),%edi +pushl %edi +fildl (%esp) +addl $4,%esp +fmull -72(%ebp) +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,%edi +movw %di,-16(%ebp) +movswl -16(%ebp),%edi +cmpl $10,%edi +je .LC1378 +movl $161,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1380 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1380: +.LC1378: +movl $5,-20(%ebp) +movb $2,-32(%ebp) +movl -20(%ebp),%edi +movsbl -32(%ebp),%esi +imull %esi,%edi +movl %edi,-20(%ebp) +cmpl $10,-20(%ebp) +je .LC1382 +movl $162,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1384 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1384: +.LC1382: +movl $5,-20(%ebp) +movw $2,-36(%ebp) +movl -20(%ebp),%edi +movswl -36(%ebp),%esi +imull %esi,%edi +movl %edi,-20(%ebp) +cmpl $10,-20(%ebp) +je .LC1386 +movl $163,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1388 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1388: +.LC1386: +movl $5,-20(%ebp) +movl $2,-40(%ebp) +movl -20(%ebp),%edi +imull -40(%ebp),%edi +movl %edi,-20(%ebp) +cmpl $10,-20(%ebp) +je .LC1390 +movl $164,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1392 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1392: +.LC1390: +movl $5,-20(%ebp) +movl $2,-44(%ebp) +movl -20(%ebp),%edi +imull -44(%ebp),%edi +movl %edi,-20(%ebp) +cmpl $10,-20(%ebp) +je .LC1394 +movl $165,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1396 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1396: +.LC1394: +movl $5,-20(%ebp) +movl $2,-48(%ebp) +movl -20(%ebp),%edi +movl %edi,%eax +mull -48(%ebp) +movl %eax,%edi +movl %edi,-20(%ebp) +cmpl $10,-20(%ebp) +je .LC1398 +movl $166,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1400 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1400: +.LC1398: +movl $5,-20(%ebp) +flds .LC544 +fstps -64(%ebp) +fildl -20(%ebp) +fmuls -64(%ebp) +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,-20(%ebp) +cmpl $10,-20(%ebp) +je .LC1402 +movl $167,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1404 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1404: +.LC1402: +movl $5,-20(%ebp) +fldl .LC425 +fstpl -72(%ebp) +fildl -20(%ebp) +fmull -72(%ebp) +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,-20(%ebp) +cmpl $10,-20(%ebp) +je .LC1406 +movl $168,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1408 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1408: +.LC1406: +movl $5,-24(%ebp) +movb $2,-32(%ebp) +movl -24(%ebp),%edi +movsbl -32(%ebp),%esi +imull %esi,%edi +movl %edi,-24(%ebp) +cmpl $10,-24(%ebp) +je .LC1410 +movl $169,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1412 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1412: +.LC1410: +movl $5,-24(%ebp) +movw $2,-36(%ebp) +movl -24(%ebp),%edi +movswl -36(%ebp),%esi +imull %esi,%edi +movl %edi,-24(%ebp) +cmpl $10,-24(%ebp) +je .LC1414 +movl $170,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1416 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1416: +.LC1414: +movl $5,-24(%ebp) +movl $2,-40(%ebp) +movl -24(%ebp),%edi +imull -40(%ebp),%edi +movl %edi,-24(%ebp) +cmpl $10,-24(%ebp) +je .LC1418 +movl $171,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1420 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1420: +.LC1418: +movl $5,-24(%ebp) +movl $2,-44(%ebp) +movl -24(%ebp),%edi +imull -44(%ebp),%edi +movl %edi,-24(%ebp) +cmpl $10,-24(%ebp) +je .LC1422 +movl $172,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1424 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1424: +.LC1422: +movl $5,-24(%ebp) +movl $2,-48(%ebp) +movl -24(%ebp),%edi +movl %edi,%eax +mull -48(%ebp) +movl %eax,%edi +movl %edi,-24(%ebp) +cmpl $10,-24(%ebp) +je .LC1426 +movl $173,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1428 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1428: +.LC1426: +movl $5,-24(%ebp) +flds .LC544 +fstps -64(%ebp) +fildl -24(%ebp) +fmuls -64(%ebp) +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,-24(%ebp) +cmpl $10,-24(%ebp) +je .LC1430 +movl $174,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1432 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1432: +.LC1430: +movl $5,-24(%ebp) +fldl .LC425 +fstpl -72(%ebp) +fildl -24(%ebp) +fmull -72(%ebp) +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,-24(%ebp) +cmpl $10,-24(%ebp) +je .LC1434 +movl $175,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1436 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1436: +.LC1434: +movl $5,-28(%ebp) +movb $2,-32(%ebp) +movl -28(%ebp),%eax +movsbl -32(%ebp),%edi +mull %edi +movl %eax,-28(%ebp) +movl -28(%ebp),%edi +cmpl $10,%edi +je .LC1438 +movl $176,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1440 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1440: +.LC1438: +movl $5,-28(%ebp) +movw $2,-36(%ebp) +movl -28(%ebp),%eax +movswl -36(%ebp),%edi +mull %edi +movl %eax,-28(%ebp) +movl -28(%ebp),%edi +cmpl $10,%edi +je .LC1442 +movl $177,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1444 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1444: +.LC1442: +movl $5,-28(%ebp) +movl $2,-40(%ebp) +movl -28(%ebp),%eax +movl -40(%ebp),%edi +mull %edi +movl %eax,-28(%ebp) +movl -28(%ebp),%edi +cmpl $10,%edi +je .LC1446 +movl $178,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1448 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1448: +.LC1446: +movl $5,-28(%ebp) +movl $2,-44(%ebp) +movl -28(%ebp),%eax +movl -44(%ebp),%edi +mull %edi +movl %eax,-28(%ebp) +movl -28(%ebp),%edi +cmpl $10,%edi +je .LC1450 +movl $179,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1452 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1452: +.LC1450: +movl $5,-28(%ebp) +movl $2,-48(%ebp) +movl -28(%ebp),%eax +mull -48(%ebp) +movl %eax,-28(%ebp) +movl -28(%ebp),%edi +cmpl $10,%edi +je .LC1454 +movl $180,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1456 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1456: +.LC1454: +movl $5,-28(%ebp) +flds .LC544 +fstps -64(%ebp) +movl -28(%ebp),%edi +fldl .LC611 +movl %edi,%esi +shrl $1,%esi +pushl %esi +fildl (%esp) +addl $4,%esp +fmulp %st,%st(1) +andl $1,%edi +pushl %edi +fildl (%esp) +addl $4,%esp +faddp %st,%st(1) +sub $4,%esp +fstps (%esp) +flds (%esp) +addl $4,%esp +fmuls -64(%ebp) +fstps -200(%ebp) +flds .LC847 +fcomps -200(%ebp) +fstsw %ax +sahf +jp .LC1459 +ja .LC1459 +flds -200(%ebp) +fsubs .LC847 +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,%edi +leal 0x80000000(%edi),%edi +movl %edi,-196(%ebp) +jmp .LC1460 +.LC1459: +flds -200(%ebp) +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,%edi +movl %edi,-196(%ebp) +.LC1460: +movl -196(%ebp),%edi +movl %edi,-28(%ebp) +movl -28(%ebp),%edi +cmpl $10,%edi +je .LC1461 +movl $181,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1463 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1463: +.LC1461: +movl $5,-28(%ebp) +fldl .LC425 +fstpl -72(%ebp) +movl -28(%ebp),%edi +fldl .LC611 +movl %edi,%esi +shrl $1,%esi +pushl %esi +fildl (%esp) +addl $4,%esp +fmulp %st,%st(1) +andl $1,%edi +pushl %edi +fildl (%esp) +addl $4,%esp +faddp %st,%st(1) +fmull -72(%ebp) +fstpl -216(%ebp) +fldl .LC855 +fcompl -216(%ebp) +fstsw %ax +sahf +jp .LC1466 +ja .LC1466 +fldl -216(%ebp) +fsubl .LC855 +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,%edi +leal 0x80000000(%edi),%edi +movl %edi,-208(%ebp) +jmp .LC1467 +.LC1466: +fldl -216(%ebp) +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,%edi +movl %edi,-208(%ebp) +.LC1467: +movl -208(%ebp),%edi +movl %edi,-28(%ebp) +movl -28(%ebp),%edi +cmpl $10,%edi +je .LC1468 +movl $182,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1470 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1470: +.LC1468: +flds .LC860 +fstps -52(%ebp) +movb $2,-32(%ebp) +flds -52(%ebp) +movsbl -32(%ebp),%edi +pushl %edi +fildl (%esp) +addl $4,%esp +fmulp %st,%st(1) +fstps -52(%ebp) +flds .LC1474 +fcomps -52(%ebp) +fstsw %ax +sahf +jp 1f +je .LC1472 +1: +movl $183,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1475 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1475: +.LC1472: +flds .LC860 +fstps -52(%ebp) +movw $2,-36(%ebp) +flds -52(%ebp) +movswl -36(%ebp),%edi +pushl %edi +fildl (%esp) +addl $4,%esp +fmulp %st,%st(1) +fstps -52(%ebp) +flds .LC1474 +fcomps -52(%ebp) +fstsw %ax +sahf +jp 1f +je .LC1477 +1: +movl $184,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1479 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1479: +.LC1477: +flds .LC860 +fstps -52(%ebp) +movl $2,-40(%ebp) +flds -52(%ebp) +fildl -40(%ebp) +fmulp %st,%st(1) +fstps -52(%ebp) +flds .LC1474 +fcomps -52(%ebp) +fstsw %ax +sahf +jp 1f +je .LC1481 +1: +movl $185,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1483 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1483: +.LC1481: +flds .LC860 +fstps -52(%ebp) +movl $2,-44(%ebp) +flds -52(%ebp) +fildl -44(%ebp) +fmulp %st,%st(1) +fstps -52(%ebp) +flds .LC1474 +fcomps -52(%ebp) +fstsw %ax +sahf +jp 1f +je .LC1485 +1: +movl $186,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1487 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1487: +.LC1485: +flds .LC860 +fstps -52(%ebp) +movl $2,-48(%ebp) +movl -48(%ebp),%edi +flds -52(%ebp) +fldl .LC611 +movl %edi,%esi +shrl $1,%esi +pushl %esi +fildl (%esp) +addl $4,%esp +fmulp %st,%st(1) +andl $1,%edi +pushl %edi +fildl (%esp) +addl $4,%esp +faddp %st,%st(1) +sub $4,%esp +fstps (%esp) +flds (%esp) +addl $4,%esp +fmulp %st,%st(1) +fstps -52(%ebp) +flds .LC1474 +fcomps -52(%ebp) +fstsw %ax +sahf +jp 1f +je .LC1489 +1: +movl $187,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1491 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1491: +.LC1489: +flds .LC860 +fstps -52(%ebp) +flds .LC544 +fstps -64(%ebp) +flds -52(%ebp) +fmuls -64(%ebp) +fstps -52(%ebp) +flds .LC1474 +fcomps -52(%ebp) +fstsw %ax +sahf +jp 1f +je .LC1493 +1: +movl $188,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1495 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1495: +.LC1493: +flds .LC860 +fstps -52(%ebp) +fldl .LC425 +fstpl -72(%ebp) +flds -52(%ebp) +fmull -72(%ebp) +fstps -52(%ebp) +flds .LC1474 +fcomps -52(%ebp) +fstsw %ax +sahf +jp 1f +je .LC1497 +1: +movl $189,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1499 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1499: +.LC1497: +fldl .LC889 +fstpl -60(%ebp) +movb $2,-32(%ebp) +fldl -60(%ebp) +movsbl -32(%ebp),%edi +pushl %edi +fildl (%esp) +addl $4,%esp +fmulp %st,%st(1) +fstpl -60(%ebp) +fldl .LC1503 +fcompl -60(%ebp) +fstsw %ax +sahf +jp 1f +je .LC1501 +1: +movl $190,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1504 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1504: +.LC1501: +fldl .LC889 +fstpl -60(%ebp) +movw $2,-36(%ebp) +fldl -60(%ebp) +movswl -36(%ebp),%edi +pushl %edi +fildl (%esp) +addl $4,%esp +fmulp %st,%st(1) +fstpl -60(%ebp) +fldl .LC1503 +fcompl -60(%ebp) +fstsw %ax +sahf +jp 1f +je .LC1506 +1: +movl $191,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1508 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1508: +.LC1506: +fldl .LC889 +fstpl -60(%ebp) +movl $2,-40(%ebp) +fldl -60(%ebp) +fimull -40(%ebp) +fstpl -60(%ebp) +fldl .LC1503 +fcompl -60(%ebp) +fstsw %ax +sahf +jp 1f +je .LC1510 +1: +movl $192,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1512 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1512: +.LC1510: +fldl .LC889 +fstpl -60(%ebp) +movl $2,-44(%ebp) +fldl -60(%ebp) +fimull -44(%ebp) +fstpl -60(%ebp) +fldl .LC1503 +fcompl -60(%ebp) +fstsw %ax +sahf +jp 1f +je .LC1514 +1: +movl $193,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1516 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1516: +.LC1514: +fldl .LC889 +fstpl -60(%ebp) +movl $2,-48(%ebp) +movl -48(%ebp),%edi +fldl -60(%ebp) +fldl .LC611 +movl %edi,%esi +shrl $1,%esi +pushl %esi +fildl (%esp) +addl $4,%esp +fmulp %st,%st(1) +andl $1,%edi +pushl %edi +fildl (%esp) +addl $4,%esp +faddp %st,%st(1) +fmulp %st,%st(1) +fstpl -60(%ebp) +fldl .LC1503 +fcompl -60(%ebp) +fstsw %ax +sahf +jp 1f +je .LC1518 +1: +movl $194,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1520 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1520: +.LC1518: +fldl .LC889 +fstpl -60(%ebp) +flds .LC544 +fstps -64(%ebp) +fldl -60(%ebp) +fmuls -64(%ebp) +fstpl -60(%ebp) +fldl .LC1503 +fcompl -60(%ebp) +fstsw %ax +sahf +jp 1f +je .LC1522 +1: +movl $195,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1524 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1524: +.LC1522: +fldl .LC889 +fstpl -60(%ebp) +fldl .LC425 +fstpl -72(%ebp) +fldl -60(%ebp) +fmull -72(%ebp) +fstpl -60(%ebp) +fldl .LC1503 +fcompl -60(%ebp) +fstsw %ax +sahf +jp 1f +je .LC1526 +1: +movl $196,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1528 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1528: +.LC1526: +movb $5,-12(%ebp) +movb $2,-32(%ebp) +movsbl -12(%ebp),%eax +movsbl -32(%ebp),%ecx +cdq +idivl %ecx +movl %eax,%ebx +movb %bl,-12(%ebp) +movsbl -12(%ebp),%edi +cmpl $2,%edi +je .LC1530 +movl $197,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1532 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1532: +.LC1530: +movb $5,-12(%ebp) +movw $2,-36(%ebp) +movsbl -12(%ebp),%eax +movswl -36(%ebp),%ecx +cdq +idivl %ecx +movl %eax,%ebx +movb %bl,-12(%ebp) +movsbl -12(%ebp),%edi +cmpl $2,%edi +je .LC1534 +movl $198,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1536 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1536: +.LC1534: +movb $5,-12(%ebp) +movl $2,-40(%ebp) +movsbl -12(%ebp),%eax +movl -40(%ebp),%ecx +cdq +idivl %ecx +movl %eax,%ebx +movb %bl,-12(%ebp) +movsbl -12(%ebp),%edi +cmpl $2,%edi +je .LC1538 +movl $199,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1540 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1540: +.LC1538: +movb $5,-12(%ebp) +movl $2,-44(%ebp) +movsbl -12(%ebp),%eax +movl -44(%ebp),%ecx +cdq +idivl %ecx +movl %eax,%ebx +movb %bl,-12(%ebp) +movsbl -12(%ebp),%edi +cmpl $2,%edi +je .LC1542 +movl $200,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1544 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1544: +.LC1542: +movb $5,-12(%ebp) +movl $2,-48(%ebp) +movsbl -12(%ebp),%edi +movl %edi,%eax +movl -48(%ebp),%ecx +xorl %edx,%edx +divl %ecx +movl %eax,%edi +movl %edi,%ebx +movb %bl,-12(%ebp) +movsbl -12(%ebp),%edi +cmpl $2,%edi +je .LC1546 +movl $201,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1548 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1548: +.LC1546: +movb $5,-12(%ebp) +flds .LC544 +fstps -64(%ebp) +movsbl -12(%ebp),%edi +pushl %edi +fildl (%esp) +addl $4,%esp +fdivs -64(%ebp) +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,%ebx +movb %bl,-12(%ebp) +movsbl -12(%ebp),%edi +cmpl $2,%edi +je .LC1550 +movl $202,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1552 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1552: +.LC1550: +movb $5,-12(%ebp) +fldl .LC425 +fstpl -72(%ebp) +movsbl -12(%ebp),%edi +pushl %edi +fildl (%esp) +addl $4,%esp +fdivl -72(%ebp) +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,%ebx +movb %bl,-12(%ebp) +movsbl -12(%ebp),%edi +cmpl $2,%edi +je .LC1554 +movl $203,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1556 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1556: +.LC1554: +movw $5,-16(%ebp) +movb $2,-32(%ebp) +movswl -16(%ebp),%eax +movsbl -32(%ebp),%ecx +cdq +idivl %ecx +movl %eax,%edi +movw %di,-16(%ebp) +movswl -16(%ebp),%edi +cmpl $2,%edi +je .LC1558 +movl $204,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1560 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1560: +.LC1558: +movw $5,-16(%ebp) +movw $2,-36(%ebp) +movswl -16(%ebp),%eax +movswl -36(%ebp),%ecx +cdq +idivl %ecx +movl %eax,%edi +movw %di,-16(%ebp) +movswl -16(%ebp),%edi +cmpl $2,%edi +je .LC1562 +movl $205,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1564 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1564: +.LC1562: +movw $5,-16(%ebp) +movl $2,-40(%ebp) +movswl -16(%ebp),%eax +movl -40(%ebp),%ecx +cdq +idivl %ecx +movl %eax,%edi +movw %di,-16(%ebp) +movswl -16(%ebp),%edi +cmpl $2,%edi +je .LC1566 +movl $206,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1568 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1568: +.LC1566: +movw $5,-16(%ebp) +movl $2,-44(%ebp) +movswl -16(%ebp),%eax +movl -44(%ebp),%ecx +cdq +idivl %ecx +movl %eax,%edi +movw %di,-16(%ebp) +movswl -16(%ebp),%edi +cmpl $2,%edi +je .LC1570 +movl $207,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1572 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1572: +.LC1570: +movw $5,-16(%ebp) +movl $2,-48(%ebp) +movswl -16(%ebp),%edi +movl %edi,%eax +movl -48(%ebp),%ecx +xorl %edx,%edx +divl %ecx +movl %eax,%edi +movw %di,-16(%ebp) +movswl -16(%ebp),%edi +cmpl $2,%edi +je .LC1574 +movl $208,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1576 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1576: +.LC1574: +movw $5,-16(%ebp) +flds .LC544 +fstps -64(%ebp) +movswl -16(%ebp),%edi +pushl %edi +fildl (%esp) +addl $4,%esp +fdivs -64(%ebp) +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,%edi +movw %di,-16(%ebp) +movswl -16(%ebp),%edi +cmpl $2,%edi +je .LC1578 +movl $209,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1580 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1580: +.LC1578: +movw $5,-16(%ebp) +fldl .LC425 +fstpl -72(%ebp) +movswl -16(%ebp),%edi +pushl %edi +fildl (%esp) +addl $4,%esp +fdivl -72(%ebp) +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,%edi +movw %di,-16(%ebp) +movswl -16(%ebp),%edi +cmpl $2,%edi +je .LC1582 +movl $210,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1584 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1584: +.LC1582: +movl $5,-20(%ebp) +movb $2,-32(%ebp) +movl -20(%ebp),%eax +movsbl -32(%ebp),%ecx +cdq +idivl %ecx +movl %eax,-20(%ebp) +cmpl $2,-20(%ebp) +je .LC1586 +movl $211,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1588 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1588: +.LC1586: +movl $5,-20(%ebp) +movw $2,-36(%ebp) +movl -20(%ebp),%eax +movswl -36(%ebp),%ecx +cdq +idivl %ecx +movl %eax,-20(%ebp) +cmpl $2,-20(%ebp) +je .LC1590 +movl $212,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1592 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1592: +.LC1590: +movl $5,-20(%ebp) +movl $2,-40(%ebp) +movl -20(%ebp),%eax +movl -40(%ebp),%ecx +cdq +idivl %ecx +movl %eax,-20(%ebp) +cmpl $2,-20(%ebp) +je .LC1594 +movl $213,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1596 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1596: +.LC1594: +movl $5,-20(%ebp) +movl $2,-44(%ebp) +movl -20(%ebp),%eax +movl -44(%ebp),%ecx +cdq +idivl %ecx +movl %eax,-20(%ebp) +cmpl $2,-20(%ebp) +je .LC1598 +movl $214,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1600 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1600: +.LC1598: +movl $5,-20(%ebp) +movl $2,-48(%ebp) +movl -20(%ebp),%edi +movl %edi,%eax +movl -48(%ebp),%ecx +xorl %edx,%edx +divl %ecx +movl %eax,%edi +movl %edi,-20(%ebp) +cmpl $2,-20(%ebp) +je .LC1602 +movl $215,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1604 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1604: +.LC1602: +movl $5,-20(%ebp) +flds .LC544 +fstps -64(%ebp) +fildl -20(%ebp) +fdivs -64(%ebp) +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,-20(%ebp) +cmpl $2,-20(%ebp) +je .LC1606 +movl $216,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1608 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1608: +.LC1606: +movl $5,-20(%ebp) +fldl .LC425 +fstpl -72(%ebp) +fldl -72(%ebp) +fidivrl -20(%ebp) +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,-20(%ebp) +cmpl $2,-20(%ebp) +je .LC1610 +movl $217,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1612 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1612: +.LC1610: +movl $5,-24(%ebp) +movb $2,-32(%ebp) +movl -24(%ebp),%eax +movsbl -32(%ebp),%ecx +cdq +idivl %ecx +movl %eax,-24(%ebp) +cmpl $2,-24(%ebp) +je .LC1614 +movl $218,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1616 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1616: +.LC1614: +movl $5,-24(%ebp) +movw $2,-36(%ebp) +movl -24(%ebp),%eax +movswl -36(%ebp),%ecx +cdq +idivl %ecx +movl %eax,-24(%ebp) +cmpl $2,-24(%ebp) +je .LC1618 +movl $219,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1620 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1620: +.LC1618: +movl $5,-24(%ebp) +movl $2,-40(%ebp) +movl -24(%ebp),%eax +movl -40(%ebp),%ecx +cdq +idivl %ecx +movl %eax,-24(%ebp) +cmpl $2,-24(%ebp) +je .LC1622 +movl $220,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1624 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1624: +.LC1622: +movl $5,-24(%ebp) +movl $2,-44(%ebp) +movl -24(%ebp),%eax +movl -44(%ebp),%ecx +cdq +idivl %ecx +movl %eax,-24(%ebp) +cmpl $2,-24(%ebp) +je .LC1626 +movl $221,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1628 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1628: +.LC1626: +movl $5,-24(%ebp) +movl $2,-48(%ebp) +movl -24(%ebp),%edi +movl %edi,%eax +movl -48(%ebp),%ecx +xorl %edx,%edx +divl %ecx +movl %eax,%edi +movl %edi,-24(%ebp) +cmpl $2,-24(%ebp) +je .LC1630 +movl $222,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1632 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1632: +.LC1630: +movl $5,-24(%ebp) +flds .LC544 +fstps -64(%ebp) +fildl -24(%ebp) +fdivs -64(%ebp) +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,-24(%ebp) +cmpl $2,-24(%ebp) +je .LC1634 +movl $223,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1636 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1636: +.LC1634: +movl $5,-24(%ebp) +fldl .LC425 +fstpl -72(%ebp) +fldl -72(%ebp) +fidivrl -24(%ebp) +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,-24(%ebp) +cmpl $2,-24(%ebp) +je .LC1638 +movl $224,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1640 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1640: +.LC1638: +movl $5,-28(%ebp) +movb $2,-32(%ebp) +movl -28(%ebp),%eax +movsbl -32(%ebp),%edi +movl %edi,%ecx +xorl %edx,%edx +divl %ecx +movl %eax,-28(%ebp) +movl -28(%ebp),%edi +cmpl $2,%edi +je .LC1642 +movl $225,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1644 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1644: +.LC1642: +movl $5,-28(%ebp) +movw $2,-36(%ebp) +movl -28(%ebp),%eax +movswl -36(%ebp),%edi +movl %edi,%ecx +xorl %edx,%edx +divl %ecx +movl %eax,-28(%ebp) +movl -28(%ebp),%edi +cmpl $2,%edi +je .LC1646 +movl $226,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1648 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1648: +.LC1646: +movl $5,-28(%ebp) +movl $2,-40(%ebp) +movl -28(%ebp),%eax +movl -40(%ebp),%edi +movl %edi,%ecx +xorl %edx,%edx +divl %ecx +movl %eax,-28(%ebp) +movl -28(%ebp),%edi +cmpl $2,%edi +je .LC1650 +movl $227,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1652 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1652: +.LC1650: +movl $5,-28(%ebp) +movl $2,-44(%ebp) +movl -28(%ebp),%eax +movl -44(%ebp),%edi +movl %edi,%ecx +xorl %edx,%edx +divl %ecx +movl %eax,-28(%ebp) +movl -28(%ebp),%edi +cmpl $2,%edi +je .LC1654 +movl $228,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1656 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1656: +.LC1654: +movl $5,-28(%ebp) +movl $2,-48(%ebp) +movl -28(%ebp),%eax +movl -48(%ebp),%ecx +xorl %edx,%edx +divl %ecx +movl %eax,-28(%ebp) +movl -28(%ebp),%edi +cmpl $2,%edi +je .LC1658 +movl $229,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1660 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1660: +.LC1658: +movl $5,-28(%ebp) +flds .LC544 +fstps -64(%ebp) +movl -28(%ebp),%edi +fldl .LC611 +movl %edi,%esi +shrl $1,%esi +pushl %esi +fildl (%esp) +addl $4,%esp +fmulp %st,%st(1) +andl $1,%edi +pushl %edi +fildl (%esp) +addl $4,%esp +faddp %st,%st(1) +sub $4,%esp +fstps (%esp) +flds (%esp) +addl $4,%esp +fdivs -64(%ebp) +fstps -232(%ebp) +flds .LC847 +fcomps -232(%ebp) +fstsw %ax +sahf +jp .LC1663 +ja .LC1663 +flds -232(%ebp) +fsubs .LC847 +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,%edi +leal 0x80000000(%edi),%edi +movl %edi,-228(%ebp) +jmp .LC1664 +.LC1663: +flds -232(%ebp) +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,%edi +movl %edi,-228(%ebp) +.LC1664: +movl -228(%ebp),%edi +movl %edi,-28(%ebp) +movl -28(%ebp),%edi +cmpl $2,%edi +je .LC1665 +movl $230,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1667 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1667: +.LC1665: +movl $5,-28(%ebp) +fldl .LC425 +fstpl -72(%ebp) +movl -28(%ebp),%edi +fldl .LC611 +movl %edi,%esi +shrl $1,%esi +pushl %esi +fildl (%esp) +addl $4,%esp +fmulp %st,%st(1) +andl $1,%edi +pushl %edi +fildl (%esp) +addl $4,%esp +faddp %st,%st(1) +fdivl -72(%ebp) +fstpl -248(%ebp) +fldl .LC855 +fcompl -248(%ebp) +fstsw %ax +sahf +jp .LC1670 +ja .LC1670 +fldl -248(%ebp) +fsubl .LC855 +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,%edi +leal 0x80000000(%edi),%edi +movl %edi,-240(%ebp) +jmp .LC1671 +.LC1670: +fldl -248(%ebp) +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,%edi +movl %edi,-240(%ebp) +.LC1671: +movl -240(%ebp),%edi +movl %edi,-28(%ebp) +movl -28(%ebp),%edi +cmpl $2,%edi +je .LC1672 +movl $231,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1674 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1674: +.LC1672: +flds .LC860 +fstps -52(%ebp) +movb $2,-32(%ebp) +flds -52(%ebp) +movsbl -32(%ebp),%edi +pushl %edi +fildl (%esp) +addl $4,%esp +fdivrp %st,%st(1) +fstps -52(%ebp) +fldl .LC1678 +fcomps -52(%ebp) +fstsw %ax +sahf +jp 1f +je .LC1676 +1: +movl $232,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1679 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1679: +.LC1676: +flds .LC860 +fstps -52(%ebp) +movw $2,-36(%ebp) +flds -52(%ebp) +movswl -36(%ebp),%edi +pushl %edi +fildl (%esp) +addl $4,%esp +fdivrp %st,%st(1) +fstps -52(%ebp) +fldl .LC1678 +fcomps -52(%ebp) +fstsw %ax +sahf +jp 1f +je .LC1681 +1: +movl $233,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1683 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1683: +.LC1681: +flds .LC860 +fstps -52(%ebp) +movl $2,-40(%ebp) +flds -52(%ebp) +fildl -40(%ebp) +fdivrp %st,%st(1) +fstps -52(%ebp) +fldl .LC1678 +fcomps -52(%ebp) +fstsw %ax +sahf +jp 1f +je .LC1685 +1: +movl $234,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1687 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1687: +.LC1685: +flds .LC860 +fstps -52(%ebp) +movl $2,-44(%ebp) +flds -52(%ebp) +fildl -44(%ebp) +fdivrp %st,%st(1) +fstps -52(%ebp) +fldl .LC1678 +fcomps -52(%ebp) +fstsw %ax +sahf +jp 1f +je .LC1689 +1: +movl $235,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1691 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1691: +.LC1689: +flds .LC860 +fstps -52(%ebp) +movl $2,-48(%ebp) +movl -48(%ebp),%edi +flds -52(%ebp) +fldl .LC611 +movl %edi,%esi +shrl $1,%esi +pushl %esi +fildl (%esp) +addl $4,%esp +fmulp %st,%st(1) +andl $1,%edi +pushl %edi +fildl (%esp) +addl $4,%esp +faddp %st,%st(1) +sub $4,%esp +fstps (%esp) +flds (%esp) +addl $4,%esp +fdivrp %st,%st(1) +fstps -52(%ebp) +fldl .LC1678 +fcomps -52(%ebp) +fstsw %ax +sahf +jp 1f +je .LC1693 +1: +movl $236,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1695 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1695: +.LC1693: +flds .LC860 +fstps -52(%ebp) +flds .LC544 +fstps -64(%ebp) +flds -52(%ebp) +fdivs -64(%ebp) +fstps -52(%ebp) +fldl .LC1678 +fcomps -52(%ebp) +fstsw %ax +sahf +jp 1f +je .LC1697 +1: +movl $237,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1699 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1699: +.LC1697: +flds .LC860 +fstps -52(%ebp) +fldl .LC425 +fstpl -72(%ebp) +flds -52(%ebp) +fdivl -72(%ebp) +fstps -52(%ebp) +fldl .LC1678 +fcomps -52(%ebp) +fstsw %ax +sahf +jp 1f +je .LC1701 +1: +movl $238,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1703 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1703: +.LC1701: +fldl .LC889 +fstpl -60(%ebp) +movb $2,-32(%ebp) +fldl -60(%ebp) +movsbl -32(%ebp),%edi +pushl %edi +fildl (%esp) +addl $4,%esp +fdivrp %st,%st(1) +fstpl -60(%ebp) +fldl .LC1678 +fcompl -60(%ebp) +fstsw %ax +sahf +jp 1f +je .LC1705 +1: +movl $239,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1707 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1707: +.LC1705: +fldl .LC889 +fstpl -60(%ebp) +movw $2,-36(%ebp) +fldl -60(%ebp) +movswl -36(%ebp),%edi +pushl %edi +fildl (%esp) +addl $4,%esp +fdivrp %st,%st(1) +fstpl -60(%ebp) +fldl .LC1678 +fcompl -60(%ebp) +fstsw %ax +sahf +jp 1f +je .LC1709 +1: +movl $240,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1711 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1711: +.LC1709: +fldl .LC889 +fstpl -60(%ebp) +movl $2,-40(%ebp) +fldl -60(%ebp) +fidivl -40(%ebp) +fstpl -60(%ebp) +fldl .LC1678 +fcompl -60(%ebp) +fstsw %ax +sahf +jp 1f +je .LC1713 +1: +movl $241,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1715 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1715: +.LC1713: +fldl .LC889 +fstpl -60(%ebp) +movl $2,-44(%ebp) +fldl -60(%ebp) +fidivl -44(%ebp) +fstpl -60(%ebp) +fldl .LC1678 +fcompl -60(%ebp) +fstsw %ax +sahf +jp 1f +je .LC1717 +1: +movl $242,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1719 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1719: +.LC1717: +fldl .LC889 +fstpl -60(%ebp) +movl $2,-48(%ebp) +movl -48(%ebp),%edi +fldl -60(%ebp) +fldl .LC611 +movl %edi,%esi +shrl $1,%esi +pushl %esi +fildl (%esp) +addl $4,%esp +fmulp %st,%st(1) +andl $1,%edi +pushl %edi +fildl (%esp) +addl $4,%esp +faddp %st,%st(1) +fdivrp %st,%st(1) +fstpl -60(%ebp) +fldl .LC1678 +fcompl -60(%ebp) +fstsw %ax +sahf +jp 1f +je .LC1721 +1: +movl $243,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1723 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1723: +.LC1721: +fldl .LC889 +fstpl -60(%ebp) +flds .LC544 +fstps -64(%ebp) +fldl -60(%ebp) +fdivs -64(%ebp) +fstpl -60(%ebp) +fldl .LC1678 +fcompl -60(%ebp) +fstsw %ax +sahf +jp 1f +je .LC1725 +1: +movl $244,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1727 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1727: +.LC1725: +fldl .LC889 +fstpl -60(%ebp) +fldl .LC425 +fstpl -72(%ebp) +fldl -60(%ebp) +fdivl -72(%ebp) +fstpl -60(%ebp) +fldl .LC1678 +fcompl -60(%ebp) +fstsw %ax +sahf +jp 1f +je .LC1729 +1: +movl $245,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1731 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1731: +.LC1729: +movb $5,-12(%ebp) +movb $2,-32(%ebp) +movsbl -12(%ebp),%eax +movsbl -32(%ebp),%ecx +cdq +idivl %ecx +movl %edx,%ebx +movb %bl,-12(%ebp) +movsbl -12(%ebp),%edi +cmpl $1,%edi +je .LC1733 +movl $246,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1735 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1735: +.LC1733: +movb $5,-12(%ebp) +movw $2,-36(%ebp) +movsbl -12(%ebp),%eax +movswl -36(%ebp),%ecx +cdq +idivl %ecx +movl %edx,%ebx +movb %bl,-12(%ebp) +movsbl -12(%ebp),%edi +cmpl $1,%edi +je .LC1737 +movl $247,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1739 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1739: +.LC1737: +movb $5,-12(%ebp) +movl $2,-40(%ebp) +movsbl -12(%ebp),%eax +movl -40(%ebp),%ecx +cdq +idivl %ecx +movl %edx,%ebx +movb %bl,-12(%ebp) +movsbl -12(%ebp),%edi +cmpl $1,%edi +je .LC1741 +movl $248,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1743 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1743: +.LC1741: +movb $5,-12(%ebp) +movl $2,-44(%ebp) +movsbl -12(%ebp),%eax +movl -44(%ebp),%ecx +cdq +idivl %ecx +movl %edx,%ebx +movb %bl,-12(%ebp) +movsbl -12(%ebp),%edi +cmpl $1,%edi +je .LC1745 +movl $249,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1747 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1747: +.LC1745: +movb $5,-12(%ebp) +movl $2,-48(%ebp) +movsbl -12(%ebp),%edi +movl %edi,%eax +movl -48(%ebp),%ecx +xorl %edx,%edx +divl %ecx +movl %edx,%edi +movl %edi,%ebx +movb %bl,-12(%ebp) +movsbl -12(%ebp),%edi +cmpl $1,%edi +je .LC1749 +movl $250,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1751 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1751: +.LC1749: +movw $5,-16(%ebp) +movb $2,-32(%ebp) +movswl -16(%ebp),%eax +movsbl -32(%ebp),%ecx +cdq +idivl %ecx +movl %edx,%edi +movw %di,-16(%ebp) +movswl -16(%ebp),%edi +cmpl $1,%edi +je .LC1753 +movl $251,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1755 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1755: +.LC1753: +movw $5,-16(%ebp) +movw $2,-36(%ebp) +movswl -16(%ebp),%eax +movswl -36(%ebp),%ecx +cdq +idivl %ecx +movl %edx,%edi +movw %di,-16(%ebp) +movswl -16(%ebp),%edi +cmpl $1,%edi +je .LC1757 +movl $252,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1759 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1759: +.LC1757: +movw $5,-16(%ebp) +movl $2,-40(%ebp) +movswl -16(%ebp),%eax +movl -40(%ebp),%ecx +cdq +idivl %ecx +movl %edx,%edi +movw %di,-16(%ebp) +movswl -16(%ebp),%edi +cmpl $1,%edi +je .LC1761 +movl $253,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1763 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1763: +.LC1761: +movw $5,-16(%ebp) +movl $2,-44(%ebp) +movswl -16(%ebp),%eax +movl -44(%ebp),%ecx +cdq +idivl %ecx +movl %edx,%edi +movw %di,-16(%ebp) +movswl -16(%ebp),%edi +cmpl $1,%edi +je .LC1765 +movl $254,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1767 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1767: +.LC1765: +movw $5,-16(%ebp) +movl $2,-48(%ebp) +movswl -16(%ebp),%edi +movl %edi,%eax +movl -48(%ebp),%ecx +xorl %edx,%edx +divl %ecx +movl %edx,%edi +movw %di,-16(%ebp) +movswl -16(%ebp),%edi +cmpl $1,%edi +je .LC1769 +movl $255,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1771 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1771: +.LC1769: +movl $5,-20(%ebp) +movb $2,-32(%ebp) +movl -20(%ebp),%eax +movsbl -32(%ebp),%ecx +cdq +idivl %ecx +movl %edx,-20(%ebp) +cmpl $1,-20(%ebp) +je .LC1773 +movl $256,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1775 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1775: +.LC1773: +movl $5,-20(%ebp) +movw $2,-36(%ebp) +movl -20(%ebp),%eax +movswl -36(%ebp),%ecx +cdq +idivl %ecx +movl %edx,-20(%ebp) +cmpl $1,-20(%ebp) +je .LC1777 +movl $257,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1779 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1779: +.LC1777: +movl $5,-20(%ebp) +movl $2,-40(%ebp) +movl -20(%ebp),%eax +movl -40(%ebp),%ecx +cdq +idivl %ecx +movl %edx,-20(%ebp) +cmpl $1,-20(%ebp) +je .LC1781 +movl $258,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1783 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1783: +.LC1781: +movl $5,-20(%ebp) +movl $2,-44(%ebp) +movl -20(%ebp),%eax +movl -44(%ebp),%ecx +cdq +idivl %ecx +movl %edx,-20(%ebp) +cmpl $1,-20(%ebp) +je .LC1785 +movl $259,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1787 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1787: +.LC1785: +movl $5,-20(%ebp) +movl $2,-48(%ebp) +movl -20(%ebp),%edi +movl %edi,%eax +movl -48(%ebp),%ecx +xorl %edx,%edx +divl %ecx +movl %edx,%edi +movl %edi,-20(%ebp) +cmpl $1,-20(%ebp) +je .LC1789 +movl $260,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1791 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1791: +.LC1789: +movl $5,-24(%ebp) +movb $2,-32(%ebp) +movl -24(%ebp),%eax +movsbl -32(%ebp),%ecx +cdq +idivl %ecx +movl %edx,-24(%ebp) +cmpl $1,-24(%ebp) +je .LC1793 +movl $261,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1795 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1795: +.LC1793: +movl $5,-24(%ebp) +movw $2,-36(%ebp) +movl -24(%ebp),%eax +movswl -36(%ebp),%ecx +cdq +idivl %ecx +movl %edx,-24(%ebp) +cmpl $1,-24(%ebp) +je .LC1797 +movl $262,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1799 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1799: +.LC1797: +movl $5,-24(%ebp) +movl $2,-40(%ebp) +movl -24(%ebp),%eax +movl -40(%ebp),%ecx +cdq +idivl %ecx +movl %edx,-24(%ebp) +cmpl $1,-24(%ebp) +je .LC1801 +movl $263,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1803 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1803: +.LC1801: +movl $5,-24(%ebp) +movl $2,-44(%ebp) +movl -24(%ebp),%eax +movl -44(%ebp),%ecx +cdq +idivl %ecx +movl %edx,-24(%ebp) +cmpl $1,-24(%ebp) +je .LC1805 +movl $264,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1807 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1807: +.LC1805: +movl $5,-24(%ebp) +movl $2,-48(%ebp) +movl -24(%ebp),%edi +movl %edi,%eax +movl -48(%ebp),%ecx +xorl %edx,%edx +divl %ecx +movl %edx,%edi +movl %edi,-24(%ebp) +cmpl $1,-24(%ebp) +je .LC1809 +movl $265,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1811 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1811: +.LC1809: +movl $5,-28(%ebp) +movb $2,-32(%ebp) +movl -28(%ebp),%eax +movsbl -32(%ebp),%edi +movl %edi,%ecx +xorl %edx,%edx +divl %ecx +movl %edx,-28(%ebp) +movl -28(%ebp),%edi +cmpl $1,%edi +je .LC1813 +movl $266,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1815 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1815: +.LC1813: +movl $5,-28(%ebp) +movw $2,-36(%ebp) +movl -28(%ebp),%eax +movswl -36(%ebp),%edi +movl %edi,%ecx +xorl %edx,%edx +divl %ecx +movl %edx,-28(%ebp) +movl -28(%ebp),%edi +cmpl $1,%edi +je .LC1817 +movl $267,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1819 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1819: +.LC1817: +movl $5,-28(%ebp) +movl $2,-40(%ebp) +movl -28(%ebp),%eax +movl -40(%ebp),%edi +movl %edi,%ecx +xorl %edx,%edx +divl %ecx +movl %edx,-28(%ebp) +movl -28(%ebp),%edi +cmpl $1,%edi +je .LC1821 +movl $268,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1823 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1823: +.LC1821: +movl $5,-28(%ebp) +movl $2,-44(%ebp) +movl -28(%ebp),%eax +movl -44(%ebp),%edi +movl %edi,%ecx +xorl %edx,%edx +divl %ecx +movl %edx,-28(%ebp) +movl -28(%ebp),%edi +cmpl $1,%edi +je .LC1825 +movl $269,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1827 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1827: +.LC1825: +movl $5,-28(%ebp) +movl $2,-48(%ebp) +movl -28(%ebp),%eax +movl -48(%ebp),%ecx +xorl %edx,%edx +divl %ecx +movl %edx,-28(%ebp) +movl -28(%ebp),%edi +cmpl $1,%edi +je .LC1829 +movl $270,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1831 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1831: +.LC1829: +movb $5,-12(%ebp) +movb $2,-32(%ebp) +movsbl -12(%ebp),%edi +movsbl -32(%ebp),%ecx +movl %edi,%eax +sarl %cl,%eax +movl %eax,%ebx +movb %bl,-12(%ebp) +movsbl -12(%ebp),%edi +cmpl $1,%edi +je .LC1833 +movl $271,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1835 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1835: +.LC1833: +movb $5,-12(%ebp) +movw $2,-36(%ebp) +movsbl -12(%ebp),%edi +movswl -36(%ebp),%ecx +movl %edi,%eax +sarl %cl,%eax +movl %eax,%ebx +movb %bl,-12(%ebp) +movsbl -12(%ebp),%edi +cmpl $1,%edi +je .LC1837 +movl $272,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1839 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1839: +.LC1837: +movb $5,-12(%ebp) +movl $2,-40(%ebp) +movsbl -12(%ebp),%edi +movl -40(%ebp),%ecx +movl %edi,%eax +sarl %cl,%eax +movl %eax,%ebx +movb %bl,-12(%ebp) +movsbl -12(%ebp),%edi +cmpl $1,%edi +je .LC1841 +movl $273,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1843 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1843: +.LC1841: +movb $5,-12(%ebp) +movl $2,-44(%ebp) +movsbl -12(%ebp),%edi +movl -44(%ebp),%ecx +movl %edi,%eax +sarl %cl,%eax +movl %eax,%ebx +movb %bl,-12(%ebp) +movsbl -12(%ebp),%edi +cmpl $1,%edi +je .LC1845 +movl $274,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1847 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1847: +.LC1845: +movb $5,-12(%ebp) +movl $2,-48(%ebp) +movsbl -12(%ebp),%edi +movl -48(%ebp),%esi +movl %esi,%ecx +movl %edi,%eax +sarl %cl,%eax +movl %eax,%ebx +movb %bl,-12(%ebp) +movsbl -12(%ebp),%edi +cmpl $1,%edi +je .LC1849 +movl $275,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1851 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1851: +.LC1849: +movw $5,-16(%ebp) +movb $2,-32(%ebp) +movswl -16(%ebp),%edi +movsbl -32(%ebp),%ecx +movl %edi,%eax +sarl %cl,%eax +movl %eax,%edi +movw %di,-16(%ebp) +movswl -16(%ebp),%edi +cmpl $1,%edi +je .LC1853 +movl $276,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1855 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1855: +.LC1853: +movw $5,-16(%ebp) +movw $2,-36(%ebp) +movswl -16(%ebp),%edi +movswl -36(%ebp),%ecx +movl %edi,%eax +sarl %cl,%eax +movl %eax,%edi +movw %di,-16(%ebp) +movswl -16(%ebp),%edi +cmpl $1,%edi +je .LC1857 +movl $277,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1859 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1859: +.LC1857: +movw $5,-16(%ebp) +movl $2,-40(%ebp) +movswl -16(%ebp),%edi +movl -40(%ebp),%ecx +movl %edi,%eax +sarl %cl,%eax +movl %eax,%edi +movw %di,-16(%ebp) +movswl -16(%ebp),%edi +cmpl $1,%edi +je .LC1861 +movl $278,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1863 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1863: +.LC1861: +movw $5,-16(%ebp) +movl $2,-44(%ebp) +movswl -16(%ebp),%edi +movl -44(%ebp),%ecx +movl %edi,%eax +sarl %cl,%eax +movl %eax,%edi +movw %di,-16(%ebp) +movswl -16(%ebp),%edi +cmpl $1,%edi +je .LC1865 +movl $279,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1867 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1867: +.LC1865: +movw $5,-16(%ebp) +movl $2,-48(%ebp) +movswl -16(%ebp),%edi +movl -48(%ebp),%esi +movl %esi,%ecx +movl %edi,%eax +sarl %cl,%eax +movl %eax,%edi +movw %di,-16(%ebp) +movswl -16(%ebp),%edi +cmpl $1,%edi +je .LC1869 +movl $280,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1871 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1871: +.LC1869: +movl $5,-20(%ebp) +movb $2,-32(%ebp) +movsbl -32(%ebp),%ecx +sarl %cl,-20(%ebp) +cmpl $1,-20(%ebp) +je .LC1873 +movl $281,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1875 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1875: +.LC1873: +movl $5,-20(%ebp) +movw $2,-36(%ebp) +movswl -36(%ebp),%ecx +sarl %cl,-20(%ebp) +cmpl $1,-20(%ebp) +je .LC1877 +movl $282,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1879 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1879: +.LC1877: +movl $5,-20(%ebp) +movl $2,-40(%ebp) +movl -40(%ebp),%ecx +sarl %cl,-20(%ebp) +cmpl $1,-20(%ebp) +je .LC1881 +movl $283,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1883 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1883: +.LC1881: +movl $5,-20(%ebp) +movl $2,-44(%ebp) +movl -44(%ebp),%ecx +sarl %cl,-20(%ebp) +cmpl $1,-20(%ebp) +je .LC1885 +movl $284,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1887 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1887: +.LC1885: +movl $5,-20(%ebp) +movl $2,-48(%ebp) +movl -48(%ebp),%edi +movl %edi,%ecx +sarl %cl,-20(%ebp) +cmpl $1,-20(%ebp) +je .LC1889 +movl $285,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1891 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1891: +.LC1889: +movl $5,-24(%ebp) +movb $2,-32(%ebp) +movsbl -32(%ebp),%ecx +sarl %cl,-24(%ebp) +cmpl $1,-24(%ebp) +je .LC1893 +movl $286,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1895 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1895: +.LC1893: +movl $5,-24(%ebp) +movw $2,-36(%ebp) +movswl -36(%ebp),%ecx +sarl %cl,-24(%ebp) +cmpl $1,-24(%ebp) +je .LC1897 +movl $287,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1899 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1899: +.LC1897: +movl $5,-24(%ebp) +movl $2,-40(%ebp) +movl -40(%ebp),%ecx +sarl %cl,-24(%ebp) +cmpl $1,-24(%ebp) +je .LC1901 +movl $288,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1903 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1903: +.LC1901: +movl $5,-24(%ebp) +movl $2,-44(%ebp) +movl -44(%ebp),%ecx +sarl %cl,-24(%ebp) +cmpl $1,-24(%ebp) +je .LC1905 +movl $289,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1907 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1907: +.LC1905: +movl $5,-24(%ebp) +movl $2,-48(%ebp) +movl -48(%ebp),%edi +movl %edi,%ecx +sarl %cl,-24(%ebp) +cmpl $1,-24(%ebp) +je .LC1909 +movl $290,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1911 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1911: +.LC1909: +movl $5,-28(%ebp) +movb $2,-32(%ebp) +movl -28(%ebp),%edi +movsbl -32(%ebp),%ecx +movl %edi,%eax +shrl %cl,%eax +movl %eax,-28(%ebp) +movl -28(%ebp),%edi +cmpl $1,%edi +je .LC1913 +movl $291,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1915 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1915: +.LC1913: +movl $5,-28(%ebp) +movw $2,-36(%ebp) +movl -28(%ebp),%edi +movswl -36(%ebp),%ecx +movl %edi,%eax +shrl %cl,%eax +movl %eax,-28(%ebp) +movl -28(%ebp),%edi +cmpl $1,%edi +je .LC1917 +movl $292,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1919 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1919: +.LC1917: +movl $5,-28(%ebp) +movl $2,-40(%ebp) +movl -28(%ebp),%edi +movl -40(%ebp),%ecx +movl %edi,%eax +shrl %cl,%eax +movl %eax,-28(%ebp) +movl -28(%ebp),%edi +cmpl $1,%edi +je .LC1921 +movl $293,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1923 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1923: +.LC1921: +movl $5,-28(%ebp) +movl $2,-44(%ebp) +movl -28(%ebp),%edi +movl -44(%ebp),%ecx +movl %edi,%eax +shrl %cl,%eax +movl %eax,-28(%ebp) +movl -28(%ebp),%edi +cmpl $1,%edi +je .LC1925 +movl $294,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1927 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1927: +.LC1925: +movl $5,-28(%ebp) +movl $2,-48(%ebp) +movl -28(%ebp),%edi +movl -48(%ebp),%esi +movl %esi,%ecx +movl %edi,%eax +shrl %cl,%eax +movl %eax,-28(%ebp) +movl -28(%ebp),%edi +cmpl $1,%edi +je .LC1929 +movl $295,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1931 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1931: +.LC1929: +movb $5,-12(%ebp) +movb $2,-32(%ebp) +movsbl -12(%ebp),%edi +movsbl -32(%ebp),%ecx +movl %edi,%eax +sall %cl,%eax +movl %eax,%ebx +movb %bl,-12(%ebp) +movsbl -12(%ebp),%edi +cmpl $20,%edi +je .LC1933 +movl $296,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1935 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1935: +.LC1933: +movb $5,-12(%ebp) +movw $2,-36(%ebp) +movsbl -12(%ebp),%edi +movswl -36(%ebp),%ecx +movl %edi,%eax +sall %cl,%eax +movl %eax,%ebx +movb %bl,-12(%ebp) +movsbl -12(%ebp),%edi +cmpl $20,%edi +je .LC1937 +movl $297,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1939 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1939: +.LC1937: +movb $5,-12(%ebp) +movl $2,-40(%ebp) +movsbl -12(%ebp),%edi +movl -40(%ebp),%ecx +movl %edi,%eax +sall %cl,%eax +movl %eax,%ebx +movb %bl,-12(%ebp) +movsbl -12(%ebp),%edi +cmpl $20,%edi +je .LC1941 +movl $298,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1943 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1943: +.LC1941: +movb $5,-12(%ebp) +movl $2,-44(%ebp) +movsbl -12(%ebp),%edi +movl -44(%ebp),%ecx +movl %edi,%eax +sall %cl,%eax +movl %eax,%ebx +movb %bl,-12(%ebp) +movsbl -12(%ebp),%edi +cmpl $20,%edi +je .LC1945 +movl $299,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1947 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1947: +.LC1945: +movb $5,-12(%ebp) +movl $2,-48(%ebp) +movsbl -12(%ebp),%edi +movl -48(%ebp),%esi +movl %esi,%ecx +movl %edi,%eax +sall %cl,%eax +movl %eax,%ebx +movb %bl,-12(%ebp) +movsbl -12(%ebp),%edi +cmpl $20,%edi +je .LC1949 +movl $300,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1951 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1951: +.LC1949: +movw $5,-16(%ebp) +movb $2,-32(%ebp) +movswl -16(%ebp),%edi +movsbl -32(%ebp),%ecx +movl %edi,%eax +sall %cl,%eax +movl %eax,%edi +movw %di,-16(%ebp) +movswl -16(%ebp),%edi +cmpl $20,%edi +je .LC1953 +movl $301,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1955 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1955: +.LC1953: +movw $5,-16(%ebp) +movw $2,-36(%ebp) +movswl -16(%ebp),%edi +movswl -36(%ebp),%ecx +movl %edi,%eax +sall %cl,%eax +movl %eax,%edi +movw %di,-16(%ebp) +movswl -16(%ebp),%edi +cmpl $20,%edi +je .LC1957 +movl $302,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1959 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1959: +.LC1957: +movw $5,-16(%ebp) +movl $2,-40(%ebp) +movswl -16(%ebp),%edi +movl -40(%ebp),%ecx +movl %edi,%eax +sall %cl,%eax +movl %eax,%edi +movw %di,-16(%ebp) +movswl -16(%ebp),%edi +cmpl $20,%edi +je .LC1961 +movl $303,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1963 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1963: +.LC1961: +movw $5,-16(%ebp) +movl $2,-44(%ebp) +movswl -16(%ebp),%edi +movl -44(%ebp),%ecx +movl %edi,%eax +sall %cl,%eax +movl %eax,%edi +movw %di,-16(%ebp) +movswl -16(%ebp),%edi +cmpl $20,%edi +je .LC1965 +movl $304,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1967 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1967: +.LC1965: +movw $5,-16(%ebp) +movl $2,-48(%ebp) +movswl -16(%ebp),%edi +movl -48(%ebp),%esi +movl %esi,%ecx +movl %edi,%eax +sall %cl,%eax +movl %eax,%edi +movw %di,-16(%ebp) +movswl -16(%ebp),%edi +cmpl $20,%edi +je .LC1969 +movl $305,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1971 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1971: +.LC1969: +movl $5,-20(%ebp) +movb $2,-32(%ebp) +movsbl -32(%ebp),%ecx +sall %cl,-20(%ebp) +cmpl $20,-20(%ebp) +je .LC1973 +movl $306,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1975 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1975: +.LC1973: +movl $5,-20(%ebp) +movw $2,-36(%ebp) +movswl -36(%ebp),%ecx +sall %cl,-20(%ebp) +cmpl $20,-20(%ebp) +je .LC1977 +movl $307,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1979 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1979: +.LC1977: +movl $5,-20(%ebp) +movl $2,-40(%ebp) +movl -40(%ebp),%ecx +sall %cl,-20(%ebp) +cmpl $20,-20(%ebp) +je .LC1981 +movl $308,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1983 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1983: +.LC1981: +movl $5,-20(%ebp) +movl $2,-44(%ebp) +movl -44(%ebp),%ecx +sall %cl,-20(%ebp) +cmpl $20,-20(%ebp) +je .LC1985 +movl $309,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1987 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1987: +.LC1985: +movl $5,-20(%ebp) +movl $2,-48(%ebp) +movl -48(%ebp),%edi +movl %edi,%ecx +sall %cl,-20(%ebp) +cmpl $20,-20(%ebp) +je .LC1989 +movl $310,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1991 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1991: +.LC1989: +movl $5,-24(%ebp) +movb $2,-32(%ebp) +movsbl -32(%ebp),%ecx +sall %cl,-24(%ebp) +cmpl $20,-24(%ebp) +je .LC1993 +movl $311,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1995 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1995: +.LC1993: +movl $5,-24(%ebp) +movw $2,-36(%ebp) +movswl -36(%ebp),%ecx +sall %cl,-24(%ebp) +cmpl $20,-24(%ebp) +je .LC1997 +movl $312,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC1999 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC1999: +.LC1997: +movl $5,-24(%ebp) +movl $2,-40(%ebp) +movl -40(%ebp),%ecx +sall %cl,-24(%ebp) +cmpl $20,-24(%ebp) +je .LC2001 +movl $313,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2003 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC2003: +.LC2001: +movl $5,-24(%ebp) +movl $2,-44(%ebp) +movl -44(%ebp),%ecx +sall %cl,-24(%ebp) +cmpl $20,-24(%ebp) +je .LC2005 +movl $314,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2007 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC2007: +.LC2005: +movl $5,-24(%ebp) +movl $2,-48(%ebp) +movl -48(%ebp),%edi +movl %edi,%ecx +sall %cl,-24(%ebp) +cmpl $20,-24(%ebp) +je .LC2009 +movl $315,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2011 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC2011: +.LC2009: +movl $5,-28(%ebp) +movb $2,-32(%ebp) +movl -28(%ebp),%edi +movsbl -32(%ebp),%ecx +movl %edi,%eax +shll %cl,%eax +movl %eax,-28(%ebp) +movl -28(%ebp),%edi +cmpl $20,%edi +je .LC2013 +movl $316,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2015 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC2015: +.LC2013: +movl $5,-28(%ebp) +movw $2,-36(%ebp) +movl -28(%ebp),%edi +movswl -36(%ebp),%ecx +movl %edi,%eax +shll %cl,%eax +movl %eax,-28(%ebp) +movl -28(%ebp),%edi +cmpl $20,%edi +je .LC2017 +movl $317,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2019 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC2019: +.LC2017: +movl $5,-28(%ebp) +movl $2,-40(%ebp) +movl -28(%ebp),%edi +movl -40(%ebp),%ecx +movl %edi,%eax +shll %cl,%eax +movl %eax,-28(%ebp) +movl -28(%ebp),%edi +cmpl $20,%edi +je .LC2021 +movl $318,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2023 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC2023: +.LC2021: +movl $5,-28(%ebp) +movl $2,-44(%ebp) +movl -28(%ebp),%edi +movl -44(%ebp),%ecx +movl %edi,%eax +shll %cl,%eax +movl %eax,-28(%ebp) +movl -28(%ebp),%edi +cmpl $20,%edi +je .LC2025 +movl $319,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2027 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC2027: +.LC2025: +movl $5,-28(%ebp) +movl $2,-48(%ebp) +movl -28(%ebp),%edi +movl -48(%ebp),%esi +movl %esi,%ecx +movl %edi,%eax +shll %cl,%eax +movl %eax,-28(%ebp) +movl -28(%ebp),%edi +cmpl $20,%edi +je .LC2029 +movl $320,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2031 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC2031: +.LC2029: +movb $12,-12(%ebp) +movb $10,-32(%ebp) +movsbl -12(%ebp),%edi +movsbl -32(%ebp),%esi +andl %esi,%edi +movl %edi,%ebx +movb %bl,-12(%ebp) +movsbl -12(%ebp),%edi +cmpl $8,%edi +je .LC2033 +movl $321,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2035 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC2035: +.LC2033: +movb $12,-12(%ebp) +movw $10,-36(%ebp) +movsbl -12(%ebp),%edi +movswl -36(%ebp),%esi +andl %esi,%edi +movl %edi,%ebx +movb %bl,-12(%ebp) +movsbl -12(%ebp),%edi +cmpl $8,%edi +je .LC2037 +movl $322,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2039 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC2039: +.LC2037: +movb $12,-12(%ebp) +movl $10,-40(%ebp) +movsbl -12(%ebp),%edi +andl -40(%ebp),%edi +movl %edi,%ebx +movb %bl,-12(%ebp) +movsbl -12(%ebp),%edi +cmpl $8,%edi +je .LC2041 +movl $323,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2043 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC2043: +.LC2041: +movb $12,-12(%ebp) +movl $10,-44(%ebp) +movsbl -12(%ebp),%edi +andl -44(%ebp),%edi +movl %edi,%ebx +movb %bl,-12(%ebp) +movsbl -12(%ebp),%edi +cmpl $8,%edi +je .LC2045 +movl $324,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2047 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC2047: +.LC2045: +movb $12,-12(%ebp) +movl $10,-48(%ebp) +movsbl -12(%ebp),%edi +andl -48(%ebp),%edi +movl %edi,%ebx +movb %bl,-12(%ebp) +movsbl -12(%ebp),%edi +cmpl $8,%edi +je .LC2049 +movl $325,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2051 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC2051: +.LC2049: +movw $12,-16(%ebp) +movb $10,-32(%ebp) +movswl -16(%ebp),%edi +movsbl -32(%ebp),%esi +andl %esi,%edi +movw %di,-16(%ebp) +movswl -16(%ebp),%edi +cmpl $8,%edi +je .LC2053 +movl $326,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2055 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC2055: +.LC2053: +movw $12,-16(%ebp) +movw $10,-36(%ebp) +movswl -16(%ebp),%edi +movswl -36(%ebp),%esi +andl %esi,%edi +movw %di,-16(%ebp) +movswl -16(%ebp),%edi +cmpl $8,%edi +je .LC2057 +movl $327,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2059 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC2059: +.LC2057: +movw $12,-16(%ebp) +movl $10,-40(%ebp) +movswl -16(%ebp),%edi +andl -40(%ebp),%edi +movw %di,-16(%ebp) +movswl -16(%ebp),%edi +cmpl $8,%edi +je .LC2061 +movl $328,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2063 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC2063: +.LC2061: +movw $12,-16(%ebp) +movl $10,-44(%ebp) +movswl -16(%ebp),%edi +andl -44(%ebp),%edi +movw %di,-16(%ebp) +movswl -16(%ebp),%edi +cmpl $8,%edi +je .LC2065 +movl $329,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2067 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC2067: +.LC2065: +movw $12,-16(%ebp) +movl $10,-48(%ebp) +movswl -16(%ebp),%edi +andl -48(%ebp),%edi +movw %di,-16(%ebp) +movswl -16(%ebp),%edi +cmpl $8,%edi +je .LC2069 +movl $330,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2071 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC2071: +.LC2069: +movl $12,-20(%ebp) +movb $10,-32(%ebp) +movsbl -32(%ebp),%edi +andl %edi,-20(%ebp) +cmpl $8,-20(%ebp) +je .LC2073 +movl $331,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2075 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC2075: +.LC2073: +movl $12,-20(%ebp) +movw $10,-36(%ebp) +movswl -36(%ebp),%edi +andl %edi,-20(%ebp) +cmpl $8,-20(%ebp) +je .LC2077 +movl $332,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2079 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC2079: +.LC2077: +movl $12,-20(%ebp) +movl $10,-40(%ebp) +movl -40(%ebp),%edi +andl %edi,-20(%ebp) +cmpl $8,-20(%ebp) +je .LC2081 +movl $333,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2083 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC2083: +.LC2081: +movl $12,-20(%ebp) +movl $10,-44(%ebp) +movl -44(%ebp),%edi +andl %edi,-20(%ebp) +cmpl $8,-20(%ebp) +je .LC2085 +movl $334,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2087 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC2087: +.LC2085: +movl $12,-20(%ebp) +movl $10,-48(%ebp) +movl -20(%ebp),%edi +andl -48(%ebp),%edi +movl %edi,-20(%ebp) +cmpl $8,-20(%ebp) +je .LC2089 +movl $335,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2091 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC2091: +.LC2089: +movl $12,-24(%ebp) +movb $10,-32(%ebp) +movsbl -32(%ebp),%edi +andl %edi,-24(%ebp) +cmpl $8,-24(%ebp) +je .LC2093 +movl $336,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2095 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC2095: +.LC2093: +movl $12,-24(%ebp) +movw $10,-36(%ebp) +movswl -36(%ebp),%edi +andl %edi,-24(%ebp) +cmpl $8,-24(%ebp) +je .LC2097 +movl $337,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2099 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC2099: +.LC2097: +movl $12,-24(%ebp) +movl $10,-40(%ebp) +movl -40(%ebp),%edi +andl %edi,-24(%ebp) +cmpl $8,-24(%ebp) +je .LC2101 +movl $338,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2103 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC2103: +.LC2101: +movl $12,-24(%ebp) +movl $10,-44(%ebp) +movl -44(%ebp),%edi +andl %edi,-24(%ebp) +cmpl $8,-24(%ebp) +je .LC2105 +movl $339,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2107 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC2107: +.LC2105: +movl $12,-24(%ebp) +movl $10,-48(%ebp) +movl -24(%ebp),%edi +andl -48(%ebp),%edi +movl %edi,-24(%ebp) +cmpl $8,-24(%ebp) +je .LC2109 +movl $340,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2111 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC2111: +.LC2109: +movl $12,-28(%ebp) +movb $10,-32(%ebp) +movsbl -32(%ebp),%edi +andl %edi,-28(%ebp) +movl -28(%ebp),%edi +cmpl $8,%edi +je .LC2113 +movl $341,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2115 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC2115: +.LC2113: +movl $12,-28(%ebp) +movw $10,-36(%ebp) +movswl -36(%ebp),%edi +andl %edi,-28(%ebp) +movl -28(%ebp),%edi +cmpl $8,%edi +je .LC2117 +movl $342,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2119 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC2119: +.LC2117: +movl $12,-28(%ebp) +movl $10,-40(%ebp) +movl -40(%ebp),%edi +andl %edi,-28(%ebp) +movl -28(%ebp),%edi +cmpl $8,%edi +je .LC2121 +movl $343,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2123 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC2123: +.LC2121: +movl $12,-28(%ebp) +movl $10,-44(%ebp) +movl -44(%ebp),%edi +andl %edi,-28(%ebp) +movl -28(%ebp),%edi +cmpl $8,%edi +je .LC2125 +movl $344,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2127 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC2127: +.LC2125: +movl $12,-28(%ebp) +movl $10,-48(%ebp) +movl -48(%ebp),%edi +andl %edi,-28(%ebp) +movl -28(%ebp),%edi +cmpl $8,%edi +je .LC2129 +movl $345,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2131 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC2131: +.LC2129: +movb $12,-12(%ebp) +movb $10,-32(%ebp) +movsbl -12(%ebp),%edi +movsbl -32(%ebp),%esi +xorl %esi,%edi +movl %edi,%ebx +movb %bl,-12(%ebp) +movsbl -12(%ebp),%edi +cmpl $6,%edi +je .LC2133 +movl $346,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2135 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC2135: +.LC2133: +movb $12,-12(%ebp) +movw $10,-36(%ebp) +movsbl -12(%ebp),%edi +movswl -36(%ebp),%esi +xorl %esi,%edi +movl %edi,%ebx +movb %bl,-12(%ebp) +movsbl -12(%ebp),%edi +cmpl $6,%edi +je .LC2137 +movl $347,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2139 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC2139: +.LC2137: +movb $12,-12(%ebp) +movl $10,-40(%ebp) +movsbl -12(%ebp),%edi +xorl -40(%ebp),%edi +movl %edi,%ebx +movb %bl,-12(%ebp) +movsbl -12(%ebp),%edi +cmpl $6,%edi +je .LC2141 +movl $348,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2143 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC2143: +.LC2141: +movb $12,-12(%ebp) +movl $10,-44(%ebp) +movsbl -12(%ebp),%edi +xorl -44(%ebp),%edi +movl %edi,%ebx +movb %bl,-12(%ebp) +movsbl -12(%ebp),%edi +cmpl $6,%edi +je .LC2145 +movl $349,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2147 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC2147: +.LC2145: +movb $12,-12(%ebp) +movl $10,-48(%ebp) +movsbl -12(%ebp),%edi +xorl -48(%ebp),%edi +movl %edi,%ebx +movb %bl,-12(%ebp) +movsbl -12(%ebp),%edi +cmpl $6,%edi +je .LC2149 +movl $350,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2151 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC2151: +.LC2149: +movw $12,-16(%ebp) +movb $10,-32(%ebp) +movswl -16(%ebp),%edi +movsbl -32(%ebp),%esi +xorl %esi,%edi +movw %di,-16(%ebp) +movswl -16(%ebp),%edi +cmpl $6,%edi +je .LC2153 +movl $351,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2155 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC2155: +.LC2153: +movw $12,-16(%ebp) +movw $10,-36(%ebp) +movswl -16(%ebp),%edi +movswl -36(%ebp),%esi +xorl %esi,%edi +movw %di,-16(%ebp) +movswl -16(%ebp),%edi +cmpl $6,%edi +je .LC2157 +movl $352,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2159 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC2159: +.LC2157: +movw $12,-16(%ebp) +movl $10,-40(%ebp) +movswl -16(%ebp),%edi +xorl -40(%ebp),%edi +movw %di,-16(%ebp) +movswl -16(%ebp),%edi +cmpl $6,%edi +je .LC2161 +movl $353,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2163 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC2163: +.LC2161: +movw $12,-16(%ebp) +movl $10,-44(%ebp) +movswl -16(%ebp),%edi +xorl -44(%ebp),%edi +movw %di,-16(%ebp) +movswl -16(%ebp),%edi +cmpl $6,%edi +je .LC2165 +movl $354,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2167 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC2167: +.LC2165: +movw $12,-16(%ebp) +movl $10,-48(%ebp) +movswl -16(%ebp),%edi +xorl -48(%ebp),%edi +movw %di,-16(%ebp) +movswl -16(%ebp),%edi +cmpl $6,%edi +je .LC2169 +movl $355,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2171 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC2171: +.LC2169: +movl $12,-20(%ebp) +movb $10,-32(%ebp) +movsbl -32(%ebp),%edi +xorl %edi,-20(%ebp) +cmpl $6,-20(%ebp) +je .LC2173 +movl $356,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2175 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC2175: +.LC2173: +movl $12,-20(%ebp) +movw $10,-36(%ebp) +movswl -36(%ebp),%edi +xorl %edi,-20(%ebp) +cmpl $6,-20(%ebp) +je .LC2177 +movl $357,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2179 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC2179: +.LC2177: +movl $12,-20(%ebp) +movl $10,-40(%ebp) +movl -40(%ebp),%edi +xorl %edi,-20(%ebp) +cmpl $6,-20(%ebp) +je .LC2181 +movl $358,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2183 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC2183: +.LC2181: +movl $12,-20(%ebp) +movl $10,-44(%ebp) +movl -44(%ebp),%edi +xorl %edi,-20(%ebp) +cmpl $6,-20(%ebp) +je .LC2185 +movl $359,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2187 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC2187: +.LC2185: +movl $12,-20(%ebp) +movl $10,-48(%ebp) +movl -20(%ebp),%edi +xorl -48(%ebp),%edi +movl %edi,-20(%ebp) +cmpl $6,-20(%ebp) +je .LC2189 +movl $360,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2191 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC2191: +.LC2189: +movl $12,-24(%ebp) +movb $10,-32(%ebp) +movsbl -32(%ebp),%edi +xorl %edi,-24(%ebp) +cmpl $6,-24(%ebp) +je .LC2193 +movl $361,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2195 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC2195: +.LC2193: +movl $12,-24(%ebp) +movw $10,-36(%ebp) +movswl -36(%ebp),%edi +xorl %edi,-24(%ebp) +cmpl $6,-24(%ebp) +je .LC2197 +movl $362,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2199 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC2199: +.LC2197: +movl $12,-24(%ebp) +movl $10,-40(%ebp) +movl -40(%ebp),%edi +xorl %edi,-24(%ebp) +cmpl $6,-24(%ebp) +je .LC2201 +movl $363,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2203 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC2203: +.LC2201: +movl $12,-24(%ebp) +movl $10,-44(%ebp) +movl -44(%ebp),%edi +xorl %edi,-24(%ebp) +cmpl $6,-24(%ebp) +je .LC2205 +movl $364,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2207 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC2207: +.LC2205: +movl $12,-24(%ebp) +movl $10,-48(%ebp) +movl -24(%ebp),%edi +xorl -48(%ebp),%edi +movl %edi,-24(%ebp) +cmpl $6,-24(%ebp) +je .LC2209 +movl $365,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2211 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC2211: +.LC2209: +movl $12,-28(%ebp) +movb $10,-32(%ebp) +movsbl -32(%ebp),%edi +xorl %edi,-28(%ebp) +movl -28(%ebp),%edi +cmpl $6,%edi +je .LC2213 +movl $366,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2215 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC2215: +.LC2213: +movl $12,-28(%ebp) +movw $10,-36(%ebp) +movswl -36(%ebp),%edi +xorl %edi,-28(%ebp) +movl -28(%ebp),%edi +cmpl $6,%edi +je .LC2217 +movl $367,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2219 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC2219: +.LC2217: +movl $12,-28(%ebp) +movl $10,-40(%ebp) +movl -40(%ebp),%edi +xorl %edi,-28(%ebp) +movl -28(%ebp),%edi +cmpl $6,%edi +je .LC2221 +movl $368,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2223 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC2223: +.LC2221: +movl $12,-28(%ebp) +movl $10,-44(%ebp) +movl -44(%ebp),%edi +xorl %edi,-28(%ebp) +movl -28(%ebp),%edi +cmpl $6,%edi +je .LC2225 +movl $369,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2227 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC2227: +.LC2225: +movl $12,-28(%ebp) +movl $10,-48(%ebp) +movl -48(%ebp),%edi +xorl %edi,-28(%ebp) +movl -28(%ebp),%edi +cmpl $6,%edi +je .LC2229 +movl $370,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2231 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC2231: +.LC2229: +movb $12,-12(%ebp) +movb $10,-32(%ebp) +movsbl -12(%ebp),%edi +movsbl -32(%ebp),%esi +orl %esi,%edi +movl %edi,%ebx +movb %bl,-12(%ebp) +movsbl -12(%ebp),%edi +cmpl $14,%edi +je .LC2233 +movl $371,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2235 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC2235: +.LC2233: +movb $12,-12(%ebp) +movw $10,-36(%ebp) +movsbl -12(%ebp),%edi +movswl -36(%ebp),%esi +orl %esi,%edi +movl %edi,%ebx +movb %bl,-12(%ebp) +movsbl -12(%ebp),%edi +cmpl $14,%edi +je .LC2237 +movl $372,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2239 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC2239: +.LC2237: +movb $12,-12(%ebp) +movl $10,-40(%ebp) +movsbl -12(%ebp),%edi +orl -40(%ebp),%edi +movl %edi,%ebx +movb %bl,-12(%ebp) +movsbl -12(%ebp),%edi +cmpl $14,%edi +je .LC2241 +movl $373,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2243 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC2243: +.LC2241: +movb $12,-12(%ebp) +movl $10,-44(%ebp) +movsbl -12(%ebp),%edi +orl -44(%ebp),%edi +movl %edi,%ebx +movb %bl,-12(%ebp) +movsbl -12(%ebp),%edi +cmpl $14,%edi +je .LC2245 +movl $374,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2247 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC2247: +.LC2245: +movb $12,-12(%ebp) +movl $10,-48(%ebp) +movsbl -12(%ebp),%edi +orl -48(%ebp),%edi +movl %edi,%ebx +movb %bl,-12(%ebp) +movsbl -12(%ebp),%edi +cmpl $14,%edi +je .LC2249 +movl $375,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2251 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC2251: +.LC2249: +movw $12,-16(%ebp) +movb $10,-32(%ebp) +movswl -16(%ebp),%edi +movsbl -32(%ebp),%esi +orl %esi,%edi +movw %di,-16(%ebp) +movswl -16(%ebp),%edi +cmpl $14,%edi +je .LC2253 +movl $376,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2255 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC2255: +.LC2253: +movw $12,-16(%ebp) +movw $10,-36(%ebp) +movswl -16(%ebp),%edi +movswl -36(%ebp),%esi +orl %esi,%edi +movw %di,-16(%ebp) +movswl -16(%ebp),%edi +cmpl $14,%edi +je .LC2257 +movl $377,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2259 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC2259: +.LC2257: +movw $12,-16(%ebp) +movl $10,-40(%ebp) +movswl -16(%ebp),%edi +orl -40(%ebp),%edi +movw %di,-16(%ebp) +movswl -16(%ebp),%edi +cmpl $14,%edi +je .LC2261 +movl $378,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2263 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC2263: +.LC2261: +movw $12,-16(%ebp) +movl $10,-44(%ebp) +movswl -16(%ebp),%edi +orl -44(%ebp),%edi +movw %di,-16(%ebp) +movswl -16(%ebp),%edi +cmpl $14,%edi +je .LC2265 +movl $379,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2267 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC2267: +.LC2265: +movw $12,-16(%ebp) +movl $10,-48(%ebp) +movswl -16(%ebp),%edi +orl -48(%ebp),%edi +movw %di,-16(%ebp) +movswl -16(%ebp),%edi +cmpl $14,%edi +je .LC2269 +movl $380,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2271 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC2271: +.LC2269: +movl $12,-20(%ebp) +movb $10,-32(%ebp) +movsbl -32(%ebp),%edi +orl %edi,-20(%ebp) +cmpl $14,-20(%ebp) +je .LC2273 +movl $381,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2275 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC2275: +.LC2273: +movl $12,-20(%ebp) +movw $10,-36(%ebp) +movswl -36(%ebp),%edi +orl %edi,-20(%ebp) +cmpl $14,-20(%ebp) +je .LC2277 +movl $382,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2279 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC2279: +.LC2277: +movl $12,-20(%ebp) +movl $10,-40(%ebp) +movl -40(%ebp),%edi +orl %edi,-20(%ebp) +cmpl $14,-20(%ebp) +je .LC2281 +movl $383,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2283 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC2283: +.LC2281: +movl $12,-20(%ebp) +movl $10,-44(%ebp) +movl -44(%ebp),%edi +orl %edi,-20(%ebp) +cmpl $14,-20(%ebp) +je .LC2285 +movl $384,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2287 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC2287: +.LC2285: +movl $12,-20(%ebp) +movl $10,-48(%ebp) +movl -20(%ebp),%edi +orl -48(%ebp),%edi +movl %edi,-20(%ebp) +cmpl $14,-20(%ebp) +je .LC2289 +movl $385,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2291 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC2291: +.LC2289: +movl $12,-24(%ebp) +movb $10,-32(%ebp) +movsbl -32(%ebp),%edi +orl %edi,-24(%ebp) +cmpl $14,-24(%ebp) +je .LC2293 +movl $386,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2295 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC2295: +.LC2293: +movl $12,-24(%ebp) +movw $10,-36(%ebp) +movswl -36(%ebp),%edi +orl %edi,-24(%ebp) +cmpl $14,-24(%ebp) +je .LC2297 +movl $387,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2299 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC2299: +.LC2297: +movl $12,-24(%ebp) +movl $10,-40(%ebp) +movl -40(%ebp),%edi +orl %edi,-24(%ebp) +cmpl $14,-24(%ebp) +je .LC2301 +movl $388,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2303 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC2303: +.LC2301: +movl $12,-24(%ebp) +movl $10,-44(%ebp) +movl -44(%ebp),%edi +orl %edi,-24(%ebp) +cmpl $14,-24(%ebp) +je .LC2305 +movl $389,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2307 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC2307: +.LC2305: +movl $12,-24(%ebp) +movl $10,-48(%ebp) +movl -24(%ebp),%edi +orl -48(%ebp),%edi +movl %edi,-24(%ebp) +cmpl $14,-24(%ebp) +je .LC2309 +movl $390,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2311 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC2311: +.LC2309: +movl $12,-28(%ebp) +movb $10,-32(%ebp) +movsbl -32(%ebp),%edi +orl %edi,-28(%ebp) +movl -28(%ebp),%edi +cmpl $14,%edi +je .LC2313 +movl $391,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2315 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC2315: +.LC2313: +movl $12,-28(%ebp) +movw $10,-36(%ebp) +movswl -36(%ebp),%edi +orl %edi,-28(%ebp) +movl -28(%ebp),%edi +cmpl $14,%edi +je .LC2317 +movl $392,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2319 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC2319: +.LC2317: +movl $12,-28(%ebp) +movl $10,-40(%ebp) +movl -40(%ebp),%edi +orl %edi,-28(%ebp) +movl -28(%ebp),%edi +cmpl $14,%edi +je .LC2321 +movl $393,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2323 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC2323: +.LC2321: +movl $12,-28(%ebp) +movl $10,-44(%ebp) +movl -44(%ebp),%edi +orl %edi,-28(%ebp) +movl -28(%ebp),%edi +cmpl $14,%edi +je .LC2325 +movl $394,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2327 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC2327: +.LC2325: +movl $12,-28(%ebp) +movl $10,-48(%ebp) +movl -48(%ebp),%edi +orl %edi,-28(%ebp) +movl -28(%ebp),%edi +cmpl $14,%edi +je .LC2329 +movl $395,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2331 +pushl -8(%ebp) +pushl $f.706 +call printf +addl $8,%esp +.LC2331: +.LC2329: +cmpl $0,-8(%ebp) +je .LC2333 +movl $1,-84(%ebp) +movl 20(%ebp),%edi +cmpl $0,44(%edi) +je .LC2335 +pushl $1 +pushl $s714er.707 +call printf +addl $8,%esp +.LC2335: +.LC2333: +movl -84(%ebp),%eax +.LC705: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf2337: +.size s714,.Lf2337-s714 +.data +.align 1 +.type s715er.2339,@object +s715er.2339: +.byte 115 +.byte 55 +.byte 49 +.byte 53 +.byte 44 +.byte 101 +.byte 114 +.byte 37 +.byte 100 +.byte 10 +.byte 0 +.size s715er.2339,11 +.align 1 +.type qs715.2340,@object +.size qs715.2340,8 +qs715.2340: +.byte 115 +.byte 55 +.byte 49 +.byte 53 +.byte 32 +.byte 32 +.byte 32 +.byte 0 +.globl s715 +.text +.align 16 +.type s715,@function +s715: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +subl $28,%esp +movl $0,-28(%ebp) +movl $0,-20(%ebp) +leal qs715.2340,%edi +movl %edi,-4(%ebp) +movl 20(%ebp),%edi +leal 60(%edi),%edi +movl %edi,-8(%ebp) +movl $0,-16(%ebp) +.LC2341: +.LC2342: +movl -8(%ebp),%edi +leal 1(%edi),%esi +movl %esi,-8(%ebp) +movl -4(%ebp),%esi +leal 1(%esi),%ebx +movl %ebx,-4(%ebp) +movb (,%esi),%bl +movb %bl,(,%edi) +movsbl %bl,%edi +cmpl $0,%edi +jne .LC2341 +movl $1,-12(%ebp) +incl -12(%ebp) +incl -12(%ebp) +incl -12(%ebp) +incl -12(%ebp) +movl -12(%ebp),%edi +leal 1(%edi),%edi +movl %edi,-12(%ebp) +cmpl $6,%edi +je .LC2344 +movl 20(%ebp),%edi +cmpl $0,44(%edi) +je .LC2346 +pushl $1 +pushl $s715er.2339 +call printf +addl $8,%esp +.LC2346: +incl -16(%ebp) +.LC2344: +pushl -28(%ebp) +movl $3,-24(%ebp) +movl -24(%ebp),%edi +leal 2(%edi),%edi +pushl %edi +pushl -20(%ebp) +call s715f +addl $12,%esp +cmpl $5,%eax +je .LC2348 +movl 20(%ebp),%edi +cmpl $0,44(%edi) +je .LC2350 +pushl $2 +pushl $s715er.2339 +call printf +addl $8,%esp +.LC2350: +addl $2,-16(%ebp) +.LC2348: +movl -16(%ebp),%eax +.LC2338: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf2352: +.size s715,.Lf2352-s715 +.globl s715f +.align 16 +.type s715f,@function +s715f: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +movl 24(%ebp),%eax +.LC2353: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf2354: +.size s715f,.Lf2354-s715f +.data +.align 1 +.type s72er.2356,@object +s72er.2356: +.byte 115 +.byte 55 +.byte 50 +.byte 44 +.byte 101 +.byte 114 +.byte 37 +.byte 100 +.byte 10 +.byte 0 +.size s72er.2356,10 +.align 1 +.type qs72.2357,@object +.size qs72.2357,8 +qs72.2357: +.byte 115 +.byte 55 +.byte 50 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 0 +.globl s72 +.text +.align 16 +.type s72,@function +s72: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +subl $104,%esp +leal qs72.2357,%edi +movl %edi,-12(%ebp) +movl 20(%ebp),%edi +leal 60(%edi),%edi +movl %edi,-16(%ebp) +movl $0,-24(%ebp) +.LC2358: +.LC2359: +movl -16(%ebp),%edi +leal 1(%edi),%esi +movl %esi,-16(%ebp) +movl -12(%ebp),%esi +leal 1(%esi),%ebx +movl %ebx,-12(%ebp) +movb (,%esi),%bl +movb %bl,(,%edi) +movsbl %bl,%edi +cmpl $0,%edi +jne .LC2358 +movl $2,-4(%ebp) +cmpl $2,-4(%ebp) +je .LC2361 +incl -24(%ebp) +pushl $1 +pushl $s72er.2356 +call printf +addl $8,%esp +.LC2361: +movl -4(%ebp),%edi +movl %edi,%esi +negl %esi +leal (%esi,%edi),%edi +cmpl $0,%edi +je .LC2363 +addl $2,-24(%ebp) +pushl $2 +pushl $s72er.2356 +call printf +addl $8,%esp +.LC2363: +movl $0,-4(%ebp) +movl $0,-8(%ebp) +jmp .LC2368 +.LC2365: +movl -4(%ebp),%edi +leal (,%edi,2),%edi +orl $1,%edi +movl %edi,-4(%ebp) +.LC2366: +incl -8(%ebp) +.LC2368: +movl 20(%ebp),%edi +movl 4(%edi),%edi +cmpl %edi,-8(%ebp) +jl .LC2365 +movl -4(%ebp),%edi +notl %edi +cmpl $0,%edi +je .LC2369 +addl $4,-24(%ebp) +pushl $4 +pushl $s72er.2356 +call printf +addl $8,%esp +.LC2369: +movl $5,-4(%ebp) +movl -4(%ebp),%edi +leal 1(%edi),%edi +movl %edi,-4(%ebp) +cmpl $6,%edi +jne .LC2376 +movl -4(%ebp),%edi +subl $1,%edi +movl %edi,-4(%ebp) +cmpl $5,%edi +jne .LC2376 +movl -4(%ebp),%edi +leal 1(%edi),%esi +movl %esi,-4(%ebp) +cmpl $5,%edi +jne .LC2376 +movl -4(%ebp),%edi +movl %edi,%esi +subl $1,%esi +movl %esi,-4(%ebp) +cmpl $6,%edi +jne .LC2376 +cmpl $5,-4(%ebp) +je .LC2371 +.LC2376: +addl $8,-24(%ebp) +pushl $8 +pushl $s72er.2356 +call printf +addl $8,%esp +.LC2371: +movb $26,-32(%ebp) +movl $26,-40(%ebp) +fldl .LC2377 +fstpl -52(%ebp) +movw $26,-36(%ebp) +movl $26,-44(%ebp) +movl $26,-28(%ebp) +flds .LC2378 +fstps -56(%ebp) +movl $0,-20(%ebp) +movswl -36(%ebp),%edi +movl %edi,%ebx +movsbl %bl,%edi +cmpl $26,%edi +jne .LC2385 +movl -28(%ebp),%edi +movl %edi,%ebx +movsbl %bl,%edi +cmpl $26,%edi +jne .LC2385 +movl -40(%ebp),%edi +movl %edi,%ebx +movsbl %bl,%edi +cmpl $26,%edi +jne .LC2385 +movl -44(%ebp),%edi +movl %edi,%ebx +movsbl %bl,%edi +cmpl $26,%edi +jne .LC2385 +flds -56(%ebp) +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,%ebx +movsbl %bl,%edi +cmpl $26,%edi +jne .LC2385 +fldl -52(%ebp) +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,%ebx +movsbl %bl,%edi +cmpl $26,%edi +je .LC2379 +.LC2385: +incl -20(%ebp) +.LC2379: +movsbl -32(%ebp),%edi +movswl %di,%edi +cmpl $26,%edi +jne .LC2392 +movl -28(%ebp),%edi +movswl %di,%edi +cmpl $26,%edi +jne .LC2392 +movl -40(%ebp),%edi +movswl %di,%edi +cmpl $26,%edi +jne .LC2392 +movl -44(%ebp),%edi +movswl %di,%edi +cmpl $26,%edi +jne .LC2392 +flds -56(%ebp) +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,%edi +movswl %di,%edi +cmpl $26,%edi +jne .LC2392 +fldl -52(%ebp) +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,%edi +movswl %di,%edi +cmpl $26,%edi +je .LC2386 +.LC2392: +addl $2,-20(%ebp) +.LC2386: +movsbl -32(%ebp),%edi +cmpl $26,%edi +jne .LC2399 +movswl -36(%ebp),%edi +cmpl $26,%edi +jne .LC2399 +cmpl $26,-40(%ebp) +jne .LC2399 +movl -44(%ebp),%edi +cmpl $26,%edi +jne .LC2399 +flds -56(%ebp) +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +cmpl $26,%eax +jne .LC2399 +fldl -52(%ebp) +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +cmpl $26,%eax +je .LC2393 +.LC2399: +addl $4,-20(%ebp) +.LC2393: +movsbl -32(%ebp),%edi +cmpl $26,%edi +jne .LC2406 +movswl -36(%ebp),%edi +cmpl $26,%edi +jne .LC2406 +cmpl $26,-28(%ebp) +jne .LC2406 +movl -44(%ebp),%edi +cmpl $26,%edi +jne .LC2406 +flds -56(%ebp) +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +cmpl $26,%eax +jne .LC2406 +fldl -52(%ebp) +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +cmpl $26,%eax +je .LC2400 +.LC2406: +addl $8,-20(%ebp) +.LC2400: +movsbl -32(%ebp),%edi +cmpl $26,%edi +jne .LC2415 +movswl -36(%ebp),%edi +cmpl $26,%edi +jne .LC2415 +movl -28(%ebp),%edi +cmpl $26,%edi +jne .LC2415 +movl -40(%ebp),%edi +cmpl $26,%edi +jne .LC2415 +flds .LC847 +fcomps -56(%ebp) +fstsw %ax +sahf +jp .LC2416 +ja .LC2416 +flds -56(%ebp) +fsubs .LC847 +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,%edi +leal 0x80000000(%edi),%edi +movl %edi,-60(%ebp) +jmp .LC2417 +.LC2416: +flds -56(%ebp) +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,%edi +movl %edi,-60(%ebp) +.LC2417: +movl -60(%ebp),%edi +cmpl $26,%edi +jne .LC2415 +fldl .LC855 +fcompl -52(%ebp) +fstsw %ax +sahf +jp .LC2418 +ja .LC2418 +fldl -52(%ebp) +fsubl .LC855 +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,%edi +leal 0x80000000(%edi),%edi +movl %edi,-64(%ebp) +jmp .LC2419 +.LC2418: +fldl -52(%ebp) +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,%edi +movl %edi,-64(%ebp) +.LC2419: +movl -64(%ebp),%edi +cmpl $26,%edi +je .LC2407 +.LC2415: +addl $16,-20(%ebp) +.LC2407: +movsbl -32(%ebp),%edi +pushl %edi +fildl (%esp) +addl $4,%esp +fldl .LC2377 +fcompp +fstsw %ax +sahf +jp .LC2426 +jne .LC2426 +movswl -36(%ebp),%edi +pushl %edi +fildl (%esp) +addl $4,%esp +fldl .LC2377 +fcompp +fstsw %ax +sahf +jp .LC2426 +jne .LC2426 +fildl -28(%ebp) +fldl .LC2377 +fcompp +fstsw %ax +sahf +jp .LC2426 +jne .LC2426 +fildl -40(%ebp) +fldl .LC2377 +fcompp +fstsw %ax +sahf +jp .LC2426 +jne .LC2426 +movl -44(%ebp),%edi +fldl .LC611 +movl %edi,%esi +shrl $1,%esi +pushl %esi +fildl (%esp) +addl $4,%esp +fmulp %st,%st(1) +andl $1,%edi +pushl %edi +fildl (%esp) +addl $4,%esp +faddp %st,%st(1) +sub $4,%esp +fstps (%esp) +flds (%esp) +addl $4,%esp +fldl .LC2377 +fcompp +fstsw %ax +sahf +jp .LC2426 +jne .LC2426 +fldl -52(%ebp) +fldl .LC2377 +fcompp +fstsw %ax +sahf +jp 1f +je .LC2420 +1: +.LC2426: +addl $32,-20(%ebp) +.LC2420: +movsbl -32(%ebp),%edi +pushl %edi +fildl (%esp) +addl $4,%esp +fldl .LC2377 +fcompp +fstsw %ax +sahf +jp .LC2433 +jne .LC2433 +movswl -36(%ebp),%edi +pushl %edi +fildl (%esp) +addl $4,%esp +fldl .LC2377 +fcompp +fstsw %ax +sahf +jp .LC2433 +jne .LC2433 +fildl -28(%ebp) +fldl .LC2377 +fcompp +fstsw %ax +sahf +jp .LC2433 +jne .LC2433 +fildl -40(%ebp) +fldl .LC2377 +fcompp +fstsw %ax +sahf +jp .LC2433 +jne .LC2433 +movl -44(%ebp),%edi +fldl .LC611 +movl %edi,%esi +shrl $1,%esi +pushl %esi +fildl (%esp) +addl $4,%esp +fmulp %st,%st(1) +andl $1,%edi +pushl %edi +fildl (%esp) +addl $4,%esp +faddp %st,%st(1) +fldl .LC2377 +fcompp +fstsw %ax +sahf +jp .LC2433 +jne .LC2433 +fldl .LC2377 +fcomps -56(%ebp) +fstsw %ax +sahf +jp 1f +je .LC2427 +1: +.LC2433: +addl $64,-20(%ebp) +.LC2427: +cmpl $0,-20(%ebp) +je .LC2434 +addl $16,-24(%ebp) +pushl $16 +pushl $s72er.2356 +call printf +addl $8,%esp +.LC2434: +movl -24(%ebp),%eax +.LC2355: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf2436: +.size s72,.Lf2436-s72 +.data +.align 1 +.type s757er.2438,@object +s757er.2438: +.byte 115 +.byte 55 +.byte 53 +.byte 55 +.byte 44 +.byte 101 +.byte 114 +.byte 37 +.byte 100 +.byte 10 +.byte 0 +.size s757er.2438,11 +.align 1 +.type qs757.2439,@object +.size qs757.2439,8 +qs757.2439: +.byte 115 +.byte 55 +.byte 53 +.byte 55 +.byte 32 +.byte 32 +.byte 32 +.byte 0 +.globl s757 +.text +.align 16 +.type s757,@function +s757: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +subl $148,%esp +leal qs757.2439,%edi +movl %edi,-112(%ebp) +movl 20(%ebp),%edi +leal 60(%edi),%edi +movl %edi,-116(%ebp) +movl $0,-120(%ebp) +.LC2440: +.LC2441: +movl -116(%ebp),%edi +leal 1(%edi),%esi +movl %esi,-116(%ebp) +movl -112(%ebp),%esi +leal 1(%esi),%ebx +movl %ebx,-112(%ebp) +movb (,%esi),%bl +movb %bl,(,%edi) +movsbl %bl,%edi +cmpl $0,%edi +jne .LC2440 +movl $40,-124(%ebp) +movl -124(%ebp),%edi +leal (,%edi,8),%esi +leal (,%esi,4),%esi +cmpl $1280,%esi +jne .LC2445 +sarl $3,%edi +sarl $2,%edi +cmpl $1,%edi +je .LC2443 +.LC2445: +incl -120(%ebp) +movl 20(%ebp),%edi +cmpl $0,44(%edi) +je .LC2446 +pushl $1 +pushl $s757er.2438 +call printf +addl $8,%esp +.LC2446: +.LC2443: +movl $0,-84(%ebp) +movl $0,-100(%ebp) +jmp .LC2451 +.LC2448: +movl $1,-92(%ebp) +movl -92(%ebp),%edi +movl 20(%ebp),%esi +movl 16(%esi),%esi +movl %esi,%ecx +subl $1,%ecx +movl %edi,%eax +shll %cl,%eax +movl %eax,-96(%ebp) +movl $0,-104(%ebp) +movl -104(%ebp),%edi +notl %edi +movl -100(%ebp),%esi +movl %esi,%ecx +movl %edi,%eax +shrl %cl,%eax +movl %eax,-108(%ebp) +movl %esi,%ecx +movl %edi,%eax +shll %cl,%eax +movl %eax,-104(%ebp) +movl $0,-88(%ebp) +jmp .LC2455 +.LC2452: +movl -100(%ebp),%edi +cmpl %edi,-88(%ebp) +jge .LC2463 +movl $1,-132(%ebp) +jmp .LC2464 +.LC2463: +movl $0,-132(%ebp) +.LC2464: +movl -92(%ebp),%edi +andl -104(%ebp),%edi +cmpl $0,%edi +jne .LC2465 +movl $1,-136(%ebp) +jmp .LC2466 +.LC2465: +movl $0,-136(%ebp) +.LC2466: +movl -136(%ebp),%edi +cmpl %edi,-132(%ebp) +jne .LC2462 +movl -100(%ebp),%edi +cmpl %edi,-88(%ebp) +jge .LC2467 +movl $1,-140(%ebp) +jmp .LC2468 +.LC2467: +movl $0,-140(%ebp) +.LC2468: +movl -96(%ebp),%edi +andl -108(%ebp),%edi +cmpl $0,%edi +jne .LC2469 +movl $1,-144(%ebp) +jmp .LC2470 +.LC2469: +movl $0,-144(%ebp) +.LC2470: +movl -144(%ebp),%edi +cmpl %edi,-140(%ebp) +je .LC2456 +.LC2462: +movl $1,-84(%ebp) +.LC2456: +movl -92(%ebp),%edi +leal (,%edi,2),%edi +movl %edi,-92(%ebp) +movl -96(%ebp),%edi +shrl $1,%edi +movl %edi,-96(%ebp) +.LC2453: +incl -88(%ebp) +.LC2455: +movl 20(%ebp),%edi +movl 16(%edi),%edi +cmpl %edi,-88(%ebp) +jl .LC2452 +.LC2449: +incl -100(%ebp) +.LC2451: +movl 20(%ebp),%edi +movl 16(%edi),%edi +cmpl %edi,-100(%ebp) +jl .LC2448 +cmpl $0,-84(%ebp) +je .LC2471 +addl $2,-120(%ebp) +movl 20(%ebp),%edi +cmpl $0,44(%edi) +je .LC2473 +pushl $2 +pushl $s757er.2438 +call printf +addl $8,%esp +.LC2473: +.LC2471: +movl $3,-16(%ebp) +movl $2,-12(%ebp) +movl $1,-8(%ebp) +movl -12(%ebp),%edi +cmpl %edi,-16(%ebp) +jge .LC2481 +movl $1,-136(%ebp) +jmp .LC2482 +.LC2481: +movl $0,-136(%ebp) +.LC2482: +movl -8(%ebp),%edi +cmpl %edi,-136(%ebp) +jge .LC2479 +movl $1,-132(%ebp) +jmp .LC2480 +.LC2479: +movl $0,-132(%ebp) +.LC2480: +cmpl $1,-132(%ebp) +je .LC2475 +addl $4,-120(%ebp) +movl 20(%ebp),%edi +cmpl $0,44(%edi) +je .LC2483 +pushl $4 +pushl $s757er.2438 +call printf +addl $8,%esp +.LC2483: +.LC2475: +leal -76(%ebp),%edi +leal -80(%ebp),%esi +cmpl %esi,%edi +jne .LC2485 +addl $8,-120(%ebp) +movl 20(%ebp),%edi +cmpl $0,44(%edi) +je .LC2488 +pushl $8 +pushl $s757er.2438 +call printf +addl $8,%esp +.LC2488: +.LC2485: +leal -76(%ebp),%edi +leal -80(%ebp),%esi +cmpl %esi,%edi +jae .LC2490 +movl 20(%ebp),%edi +cmpl $0,40(%edi) +je .LC2493 +pushl $.LC2495 +call printf +addl $4,%esp +.LC2493: +.LC2490: +movl $0,-84(%ebp) +movl $0,-88(%ebp) +.LC2496: +movl -88(%ebp),%edi +leal -80(%ebp),%esi +movl $1,(%esi,%edi,4) +.LC2497: +incl -88(%ebp) +cmpl $16,-88(%ebp) +jl .LC2496 +movl $0,-76(%ebp) +movl $0,-64(%ebp) +movl $0,-56(%ebp) +movl $0,-52(%ebp) +movl $0,-44(%ebp) +movl $0,-28(%ebp) +movl $0,-16(%ebp) +.LC2506: +movl $0,-12(%ebp) +.LC2510: +movl $0,-8(%ebp) +.LC2514: +movl $0,-4(%ebp) +.LC2518: +movl -12(%ebp),%edi +cmpl %edi,-16(%ebp) +jge .LC2529 +movl $1,-144(%ebp) +jmp .LC2530 +.LC2529: +movl $0,-144(%ebp) +.LC2530: +movl -4(%ebp),%edi +cmpl %edi,-8(%ebp) +jge .LC2531 +movl $1,-148(%ebp) +jmp .LC2532 +.LC2531: +movl $0,-148(%ebp) +.LC2532: +movl -148(%ebp),%edi +cmpl %edi,-144(%ebp) +jne .LC2527 +movl $1,-140(%ebp) +jmp .LC2528 +.LC2527: +movl $0,-140(%ebp) +.LC2528: +movl -16(%ebp),%edi +movl -12(%ebp),%esi +leal (,%esi,4),%esi +leal (%esi,%edi,8),%edi +movl -8(%ebp),%esi +leal (,%esi,2),%esi +leal (%esi,%edi),%edi +movl -4(%ebp),%esi +leal (%esi,%edi),%edi +leal -80(%ebp),%esi +movl (%esi,%edi,4),%edi +cmpl %edi,-140(%ebp) +je .LC2522 +movl $1,-84(%ebp) +.LC2522: +.LC2519: +incl -4(%ebp) +cmpl $2,-4(%ebp) +jl .LC2518 +.LC2515: +incl -8(%ebp) +cmpl $2,-8(%ebp) +jl .LC2514 +.LC2511: +incl -12(%ebp) +cmpl $2,-12(%ebp) +jl .LC2510 +.LC2507: +incl -16(%ebp) +cmpl $2,-16(%ebp) +jl .LC2506 +cmpl $0,-84(%ebp) +je .LC2533 +addl $16,-120(%ebp) +movl 20(%ebp),%edi +cmpl $0,44(%edi) +je .LC2535 +pushl $16 +pushl $s757er.2438 +call printf +addl $8,%esp +.LC2535: +.LC2533: +movl $0,-128(%ebp) +movl -128(%ebp),%edi +cmpl $0,%edi +je .LC2537 +addl $32,-120(%ebp) +movl 20(%ebp),%edi +cmpl $0,44(%edi) +je .LC2539 +pushl $32 +pushl $s757er.2438 +call printf +addl $8,%esp +.LC2539: +.LC2537: +movl -120(%ebp),%eax +.LC2437: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf2541: +.size s757,.Lf2541-s757 +.data +.align 1 +.type fl.2543,@object +fl.2543: +.byte 76 +.byte 111 +.byte 99 +.byte 97 +.byte 108 +.byte 32 +.byte 101 +.byte 114 +.byte 114 +.byte 111 +.byte 114 +.byte 32 +.byte 37 +.byte 100 +.byte 46 +.byte 10 +.byte 0 +.size fl.2543,17 +.align 1 +.type s7813er.2544,@object +s7813er.2544: +.byte 115 +.byte 55 +.byte 56 +.byte 49 +.byte 51 +.byte 44 +.byte 101 +.byte 114 +.byte 37 +.byte 100 +.byte 10 +.byte 0 +.size s7813er.2544,12 +.align 1 +.type qs7813.2545,@object +.size qs7813.2545,8 +qs7813.2545: +.byte 115 +.byte 55 +.byte 56 +.byte 49 +.byte 51 +.byte 32 +.byte 32 +.byte 0 +.globl s7813 +.text +.align 16 +.type s7813,@function +s7813: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +subl $88,%esp +leal qs7813.2545,%edi +movl %edi,-24(%ebp) +movl 20(%ebp),%edi +leal 60(%edi),%esi +movl %esi,-28(%ebp) +movl $0,-8(%ebp) +movl $0,-32(%ebp) +movl 48(%edi),%edi +movl %edi,-4(%ebp) +.LC2546: +.LC2547: +movl -28(%ebp),%edi +leal 1(%edi),%esi +movl %esi,-28(%ebp) +movl -24(%ebp),%esi +leal 1(%esi),%ebx +movl %ebx,-24(%ebp) +movb (,%esi),%bl +movb %bl,(,%edi) +movsbl %bl,%edi +cmpl $0,%edi +jne .LC2546 +jmp .LC2549 +movl $1,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2551 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2551: +.LC2549: +jmp .LC2553 +movl $2,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2555 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2555: +.LC2553: +jmp .LC2557 +movl $3,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2559 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2559: +.LC2557: +jmp .LC2561 +movl $4,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2563 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2563: +.LC2561: +jmp .LC2565 +movl $5,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2567 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2567: +.LC2565: +jmp .LC2569 +movl $6,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2571 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2571: +.LC2569: +jmp .LC2573 +movl $7,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2575 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2575: +.LC2573: +jmp .LC2577 +movl $8,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2579 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2579: +.LC2577: +jmp .LC2581 +movl $9,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2583 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2583: +.LC2581: +jmp .LC2585 +movl $10,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2587 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2587: +.LC2585: +jmp .LC2589 +movl $11,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2591 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2591: +.LC2589: +jmp .LC2593 +movl $12,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2595 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2595: +.LC2593: +jmp .LC2597 +movl $13,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2599 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2599: +.LC2597: +jmp .LC2601 +movl $14,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2603 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2603: +.LC2601: +jmp .LC2605 +movl $15,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2607 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2607: +.LC2605: +jmp .LC2609 +movl $16,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2611 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2611: +.LC2609: +jmp .LC2613 +movl $17,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2615 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2615: +.LC2613: +jmp .LC2617 +movl $18,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2619 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2619: +.LC2617: +jmp .LC2621 +movl $16,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2623 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2623: +.LC2621: +jmp .LC2625 +movl $20,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2627 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2627: +.LC2625: +jmp .LC2629 +movl $21,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2631 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2631: +.LC2629: +jmp .LC2633 +movl $22,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2635 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2635: +.LC2633: +jmp .LC2637 +movl $23,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2639 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2639: +.LC2637: +jmp .LC2641 +movl $24,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2643 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2643: +.LC2641: +jmp .LC2645 +movl $25,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2647 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2647: +.LC2645: +jmp .LC2649 +movl $26,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2651 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2651: +.LC2649: +jmp .LC2653 +movl $27,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2655 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2655: +.LC2653: +jmp .LC2657 +movl $28,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2659 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2659: +.LC2657: +jmp .LC2661 +movl $26,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2663 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2663: +.LC2661: +jmp .LC2665 +movl $30,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2667 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2667: +.LC2665: +jmp .LC2669 +movl $31,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2671 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2671: +.LC2669: +jmp .LC2673 +movl $32,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2675 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2675: +.LC2673: +jmp .LC2677 +movl $33,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2679 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2679: +.LC2677: +jmp .LC2681 +movl $34,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2683 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2683: +.LC2681: +jmp .LC2685 +movl $35,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2687 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2687: +.LC2685: +jmp .LC2689 +movl $36,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2691 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2691: +.LC2689: +jmp .LC2693 +movl $37,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2695 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2695: +.LC2693: +jmp .LC2697 +movl $38,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2699 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2699: +.LC2697: +jmp .LC2701 +movl $39,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2703 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2703: +.LC2701: +jmp .LC2705 +movl $40,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2707 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2707: +.LC2705: +jmp .LC2709 +movl $41,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2711 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2711: +.LC2709: +jmp .LC2713 +movl $42,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2715 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2715: +.LC2713: +jmp .LC2717 +movl $43,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2719 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2719: +.LC2717: +jmp .LC2721 +movl $44,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2723 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2723: +.LC2721: +jmp .LC2725 +movl $45,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2727 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2727: +.LC2725: +jmp .LC2729 +movl $46,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2731 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2731: +.LC2729: +jmp .LC2733 +movl $47,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2735 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2735: +.LC2733: +jmp .LC2737 +movl $48,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2739 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2739: +.LC2737: +jmp .LC2741 +movl $49,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2743 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2743: +.LC2741: +jmp .LC2745 +movl $50,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2747 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2747: +.LC2745: +jmp .LC2749 +movl $51,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2751 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2751: +.LC2749: +jmp .LC2753 +movl $52,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2755 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2755: +.LC2753: +jmp .LC2757 +movl $53,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2759 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2759: +.LC2757: +jmp .LC2761 +movl $54,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2763 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2763: +.LC2761: +jmp .LC2765 +movl $55,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2767 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2767: +.LC2765: +jmp .LC2769 +movl $56,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2771 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2771: +.LC2769: +jmp .LC2773 +movl $57,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2775 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2775: +.LC2773: +jmp .LC2777 +movl $58,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2779 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2779: +.LC2777: +jmp .LC2781 +movl $56,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2783 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2783: +.LC2781: +jmp .LC2785 +movl $60,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2787 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2787: +.LC2785: +jmp .LC2789 +movl $61,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2791 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2791: +.LC2789: +jmp .LC2793 +movl $62,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2795 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2795: +.LC2793: +jmp .LC2797 +movl $63,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2799 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2799: +.LC2797: +jmp .LC2801 +movl $64,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2803 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2803: +.LC2801: +jmp .LC2805 +movl $65,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2807 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2807: +.LC2805: +jmp .LC2809 +movl $66,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2811 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2811: +.LC2809: +jmp .LC2813 +movl $67,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2815 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2815: +.LC2813: +jmp .LC2817 +movl $68,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2819 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2819: +.LC2817: +jmp .LC2821 +movl $69,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2823 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2823: +.LC2821: +jmp .LC2825 +movl $70,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2827 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2827: +.LC2825: +jmp .LC2829 +movl $71,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2831 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2831: +.LC2829: +jmp .LC2833 +movl $72,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2835 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2835: +.LC2833: +jmp .LC2837 +movl $73,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2839 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2839: +.LC2837: +jmp .LC2841 +movl $74,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2843 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2843: +.LC2841: +jmp .LC2845 +movl $75,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2847 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2847: +.LC2845: +cmpl $0,-8(%ebp) +je .LC2849 +movl 20(%ebp),%edi +cmpl $0,44(%edi) +je .LC2851 +pushl $1 +pushl $s7813er.2544 +call printf +addl $8,%esp +.LC2851: +incl -32(%ebp) +.LC2849: +movl $0,-8(%ebp) +movl $0,-16(%ebp) +movl $0,-12(%ebp) +movl -12(%ebp),%edi +leal 1(%edi),%esi +movl %esi,-12(%ebp) +cmpl $0,%edi +je .LC2854 +movl -16(%ebp),%edi +leal 1(%edi),%esi +movl %esi,-16(%ebp) +cmpl $0,%edi +je .LC2854 +movl $1,-44(%ebp) +jmp .LC2855 +.LC2854: +movl $0,-44(%ebp) +.LC2855: +movl -44(%ebp),%edi +movl %edi,-20(%ebp) +cmpl $1,-12(%ebp) +je .LC2856 +movl $1,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2858 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2858: +.LC2856: +cmpl $0,-16(%ebp) +je .LC2860 +movl $2,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2862 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2862: +.LC2860: +cmpl $0,-20(%ebp) +je .LC2864 +movl $3,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2866 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2866: +.LC2864: +cmpl $0,-12(%ebp) +je .LC2869 +movl -16(%ebp),%edi +leal 1(%edi),%esi +movl %esi,-16(%ebp) +cmpl $0,%edi +je .LC2869 +movl $1,-48(%ebp) +jmp .LC2870 +.LC2869: +movl $0,-48(%ebp) +.LC2870: +movl -48(%ebp),%edi +movl %edi,-20(%ebp) +cmpl $1,-12(%ebp) +je .LC2871 +movl $4,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2873 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2873: +.LC2871: +cmpl $1,-16(%ebp) +je .LC2875 +movl $5,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2877 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2877: +.LC2875: +cmpl $0,-20(%ebp) +je .LC2879 +movl $6,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2881 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2881: +.LC2879: +movl -12(%ebp),%edi +movl %edi,%esi +subl $1,%esi +movl %esi,-12(%ebp) +cmpl $0,%edi +je .LC2884 +cmpl $0,-16(%ebp) +je .LC2884 +movl $1,-52(%ebp) +jmp .LC2885 +.LC2884: +movl $0,-52(%ebp) +.LC2885: +movl -52(%ebp),%edi +movl %edi,-20(%ebp) +cmpl $0,-12(%ebp) +je .LC2886 +movl $7,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2888 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2888: +.LC2886: +cmpl $1,-16(%ebp) +je .LC2890 +movl $8,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2892 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2892: +.LC2890: +cmpl $1,-20(%ebp) +je .LC2894 +movl $9,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2896 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2896: +.LC2894: +cmpl $0,-12(%ebp) +je .LC2899 +movl -16(%ebp),%edi +movl %edi,%esi +subl $1,%esi +movl %esi,-16(%ebp) +cmpl $0,%edi +je .LC2899 +movl $1,-56(%ebp) +jmp .LC2900 +.LC2899: +movl $0,-56(%ebp) +.LC2900: +movl -56(%ebp),%edi +movl %edi,-20(%ebp) +cmpl $0,-12(%ebp) +je .LC2901 +movl $10,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2903 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2903: +.LC2901: +cmpl $1,-16(%ebp) +je .LC2905 +movl $11,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2907 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2907: +.LC2905: +cmpl $0,-20(%ebp) +je .LC2909 +movl $12,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2911 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2911: +.LC2909: +cmpl $0,-8(%ebp) +je .LC2913 +movl 20(%ebp),%edi +cmpl $0,44(%edi) +je .LC2915 +pushl $2 +pushl $s7813er.2544 +call printf +addl $8,%esp +.LC2915: +addl $2,-32(%ebp) +.LC2913: +movl $0,-8(%ebp) +movl $0,-16(%ebp) +movl $0,-12(%ebp) +movl -12(%ebp),%edi +leal 1(%edi),%esi +movl %esi,-12(%ebp) +cmpl $0,%edi +jne .LC2920 +cmpl $0,-16(%ebp) +je .LC2918 +.LC2920: +movl $1,-60(%ebp) +jmp .LC2919 +.LC2918: +movl $0,-60(%ebp) +.LC2919: +movl -60(%ebp),%edi +movl %edi,-20(%ebp) +cmpl $1,-12(%ebp) +je .LC2921 +movl $1,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2923 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2923: +.LC2921: +cmpl $0,-16(%ebp) +je .LC2925 +movl $2,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2927 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2927: +.LC2925: +cmpl $0,-20(%ebp) +je .LC2929 +movl $3,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2931 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2931: +.LC2929: +movl -16(%ebp),%edi +leal 1(%edi),%esi +movl %esi,-16(%ebp) +cmpl $0,%edi +jne .LC2936 +cmpl $0,-12(%ebp) +je .LC2934 +.LC2936: +movl $1,-64(%ebp) +jmp .LC2935 +.LC2934: +movl $0,-64(%ebp) +.LC2935: +movl -64(%ebp),%edi +movl %edi,-20(%ebp) +cmpl $1,-12(%ebp) +je .LC2937 +movl $4,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2939 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2939: +.LC2937: +cmpl $1,-16(%ebp) +je .LC2941 +movl $5,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2943 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2943: +.LC2941: +cmpl $1,-20(%ebp) +je .LC2945 +movl $6,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2947 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2947: +.LC2945: +movl -12(%ebp),%edi +movl %edi,%esi +subl $1,%esi +movl %esi,-12(%ebp) +cmpl $0,%edi +jne .LC2952 +movl -16(%ebp),%edi +movl %edi,%esi +subl $1,%esi +movl %esi,-16(%ebp) +cmpl $0,%edi +je .LC2950 +.LC2952: +movl $1,-68(%ebp) +jmp .LC2951 +.LC2950: +movl $0,-68(%ebp) +.LC2951: +movl -68(%ebp),%edi +movl %edi,-20(%ebp) +cmpl $0,-12(%ebp) +je .LC2953 +movl $7,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2955 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2955: +.LC2953: +cmpl $1,-16(%ebp) +je .LC2957 +movl $8,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2959 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2959: +.LC2957: +cmpl $1,-20(%ebp) +je .LC2961 +movl $9,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2963 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2963: +.LC2961: +cmpl $0,-12(%ebp) +jne .LC2968 +movl -16(%ebp),%edi +movl %edi,%esi +subl $1,%esi +movl %esi,-16(%ebp) +cmpl $0,%edi +je .LC2966 +.LC2968: +movl $1,-72(%ebp) +jmp .LC2967 +.LC2966: +movl $0,-72(%ebp) +.LC2967: +movl -72(%ebp),%edi +movl %edi,-20(%ebp) +cmpl $0,-12(%ebp) +je .LC2969 +movl $10,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2971 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2971: +.LC2969: +cmpl $0,-16(%ebp) +je .LC2973 +movl $11,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2975 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2975: +.LC2973: +cmpl $1,-20(%ebp) +je .LC2977 +movl $12,-8(%ebp) +cmpl $0,-4(%ebp) +je .LC2979 +pushl -8(%ebp) +pushl $fl.2543 +call printf +addl $8,%esp +.LC2979: +.LC2977: +cmpl $0,-8(%ebp) +je .LC2981 +movl 20(%ebp),%edi +cmpl $0,44(%edi) +je .LC2983 +pushl $4 +pushl $s7813er.2544 +call printf +addl $8,%esp +.LC2983: +addl $4,-32(%ebp) +.LC2981: +movl $0,-16(%ebp) +movl $0,-12(%ebp) +movl $0,-36(%ebp) +movl $1,-40(%ebp) +cmpl $0,-40(%ebp) +je .LC2987 +movl -36(%ebp),%edi +movl %edi,-76(%ebp) +jmp .LC2988 +.LC2987: +cmpl $0,-40(%ebp) +je .LC2989 +movl -12(%ebp),%edi +leal 1(%edi),%esi +movl %esi,-12(%ebp) +movl %edi,-80(%ebp) +jmp .LC2990 +.LC2989: +movl -16(%ebp),%edi +leal 1(%edi),%esi +movl %esi,-16(%ebp) +movl %edi,-80(%ebp) +.LC2990: +movl -80(%ebp),%edi +movl %edi,-76(%ebp) +.LC2988: +movl -76(%ebp),%edi +movl %edi,-20(%ebp) +cmpl $0,-20(%ebp) +jne .LC2994 +cmpl $0,-12(%ebp) +jne .LC2994 +cmpl $0,-16(%ebp) +je .LC2991 +.LC2994: +movl 20(%ebp),%edi +cmpl $0,44(%edi) +je .LC2995 +pushl $8 +pushl $s7813er.2544 +call printf +addl $8,%esp +.LC2995: +addl $8,-32(%ebp) +.LC2991: +cmpl $0,-40(%ebp) +je .LC3002 +movl -36(%ebp),%edi +movl %edi,-84(%ebp) +jmp .LC3003 +.LC3002: +movl $1,-84(%ebp) +.LC3003: +cmpl $0,-84(%ebp) +jne .LC3001 +cmpl $0,-36(%ebp) +je .LC3004 +movl $1,-88(%ebp) +jmp .LC3005 +.LC3004: +movl -36(%ebp),%edi +movl %edi,-88(%ebp) +.LC3005: +cmpl $0,-88(%ebp) +je .LC2997 +.LC3001: +movl 20(%ebp),%edi +cmpl $0,44(%edi) +je .LC3006 +pushl $16 +pushl $s7813er.2544 +call printf +addl $8,%esp +.LC3006: +addl $16,-32(%ebp) +.LC2997: +movl -32(%ebp),%eax +.LC2542: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf3008: +.size s7813,.Lf3008-s7813 +.data +.align 1 +.type s81er.3010,@object +s81er.3010: +.byte 115 +.byte 56 +.byte 49 +.byte 44 +.byte 101 +.byte 114 +.byte 37 +.byte 100 +.byte 10 +.byte 0 +.size s81er.3010,10 +.align 1 +.type qs81.3011,@object +.size qs81.3011,8 +qs81.3011: +.byte 115 +.byte 56 +.byte 49 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 0 +.align 1 +.type badtest.3012,@object +badtest.3012: +.byte 82 +.byte 101 +.byte 103 +.byte 105 +.byte 115 +.byte 116 +.byte 101 +.byte 114 +.byte 32 +.byte 99 +.byte 111 +.byte 117 +.byte 110 +.byte 116 +.byte 32 +.byte 102 +.byte 111 +.byte 114 +.byte 32 +.byte 37 +.byte 115 +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 117 +.byte 110 +.byte 114 +.byte 101 +.byte 108 +.byte 105 +.byte 97 +.byte 98 +.byte 108 +.byte 101 +.byte 46 +.byte 10 +.byte 0 +.size badtest.3012,38 +.align 1 +.type goodtest.3013,@object +goodtest.3013: +.byte 37 +.byte 100 +.byte 32 +.byte 114 +.byte 101 +.byte 103 +.byte 105 +.byte 115 +.byte 116 +.byte 101 +.byte 114 +.byte 115 +.byte 32 +.byte 97 +.byte 115 +.byte 115 +.byte 105 +.byte 103 +.byte 110 +.byte 101 +.byte 100 +.byte 32 +.byte 116 +.byte 111 +.byte 32 +.byte 37 +.byte 115 +.byte 32 +.byte 118 +.byte 97 +.byte 114 +.byte 105 +.byte 97 +.byte 98 +.byte 108 +.byte 101 +.byte 115 +.byte 46 +.byte 10 +.byte 0 +.size goodtest.3013,40 +.globl s81 +.text +.align 16 +.type s81,@function +s81: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +subl $56,%esp +movl $0,-56(%ebp) +movl $0,-44(%ebp) +movl $0,-48(%ebp) +movl $0,-52(%ebp) +leal qs81.3011,%edi +movl %edi,-36(%ebp) +movl 20(%ebp),%edi +leal 60(%edi),%edi +movl %edi,-40(%ebp) +.LC3014: +.LC3015: +movl -40(%ebp),%edi +leal 1(%edi),%esi +movl %esi,-40(%ebp) +movl -36(%ebp),%esi +leal 1(%esi),%ebx +movl %ebx,-36(%ebp) +movb (,%esi),%bl +movb %bl,(,%edi) +movsbl %bl,%edi +cmpl $0,%edi +jne .LC3014 +movl $1,-16(%ebp) +movl $0,-20(%ebp) +.LC3017: +movl -16(%ebp),%edi +movl %edi,%ebx +movb %bl,-4(%ebp) +movb %bl,-24(%ebp) +leal -16(%ebp),%esi +movl %esi,-8(%ebp) +leal -16(%ebp),%esi +movl %esi,-28(%ebp) +movl %edi,-12(%ebp) +movl %edi,-32(%ebp) +movsbl -4(%ebp),%edi +movsbl -24(%ebp),%esi +cmpl %esi,%edi +je .LC3021 +movl $1,-44(%ebp) +.LC3021: +movl -8(%ebp),%edi +movl -28(%ebp),%esi +cmpl %esi,%edi +je .LC3023 +movl $1,-48(%ebp) +.LC3023: +movl -32(%ebp),%edi +cmpl %edi,-12(%ebp) +je .LC3025 +movl $1,-52(%ebp) +.LC3025: +sall $1,-16(%ebp) +.LC3018: +incl -20(%ebp) +cmpl $50,-20(%ebp) +jl .LC3017 +cmpl $0,-44(%ebp) +je .LC3027 +incl -56(%ebp) +movl 20(%ebp),%edi +cmpl $0,44(%edi) +je .LC3029 +pushl $1 +pushl $s81er.3010 +call printf +addl $8,%esp +.LC3029: +.LC3027: +cmpl $0,-48(%ebp) +je .LC3031 +addl $2,-56(%ebp) +movl 20(%ebp),%edi +cmpl $0,44(%edi) +je .LC3033 +pushl $2 +pushl $s81er.3010 +call printf +addl $8,%esp +.LC3033: +.LC3031: +cmpl $0,-52(%ebp) +je .LC3035 +addl $4,-56(%ebp) +movl 20(%ebp),%edi +cmpl $0,44(%edi) +je .LC3037 +pushl $4 +pushl $s81er.3010 +call printf +addl $8,%esp +.LC3037: +.LC3035: +call regc +movl %eax,-16(%ebp) +movl 20(%ebp),%edi +cmpl $0,40(%edi) +je .LC3039 +cmpl $0,-16(%ebp) +jge .LC3041 +pushl $.LC434 +pushl $badtest.3012 +call printf +addl $8,%esp +jmp .LC3042 +.LC3041: +pushl $.LC434 +pushl -16(%ebp) +pushl $goodtest.3013 +call printf +addl $12,%esp +.LC3042: +.LC3039: +call regp +movl %eax,-16(%ebp) +movl 20(%ebp),%edi +cmpl $0,40(%edi) +je .LC3043 +cmpl $0,-16(%ebp) +jge .LC3045 +pushl $.LC3047 +pushl $badtest.3012 +call printf +addl $8,%esp +jmp .LC3046 +.LC3045: +pushl $.LC3047 +pushl -16(%ebp) +pushl $goodtest.3013 +call printf +addl $12,%esp +.LC3046: +.LC3043: +call regi +movl %eax,-16(%ebp) +movl 20(%ebp),%edi +cmpl $0,40(%edi) +je .LC3048 +cmpl $0,-16(%ebp) +jge .LC3050 +pushl $.LC435 +pushl $badtest.3012 +call printf +addl $8,%esp +jmp .LC3051 +.LC3050: +pushl $.LC435 +pushl -16(%ebp) +pushl $goodtest.3013 +call printf +addl $12,%esp +.LC3051: +.LC3048: +movl -56(%ebp),%eax +.LC3009: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf3052: +.size s81,.Lf3052-s81 +.globl regc +.align 16 +.type regc,@function +regc: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +subl $264,%esp +movb $0,-252(%ebp) +movb $1,-168(%ebp) +movb $2,-172(%ebp) +movb $3,-176(%ebp) +movb $4,-4(%ebp) +movb $5,-180(%ebp) +movb $6,-8(%ebp) +movb $7,-184(%ebp) +movb $8,-12(%ebp) +movb $9,-188(%ebp) +movb $10,-16(%ebp) +movb $11,-192(%ebp) +movb $12,-20(%ebp) +movb $13,-196(%ebp) +movb $14,-24(%ebp) +movb $15,-200(%ebp) +movb $16,-28(%ebp) +movb $17,-204(%ebp) +movb $18,-32(%ebp) +movb $19,-208(%ebp) +movb $20,-36(%ebp) +movb $21,-212(%ebp) +movb $22,-40(%ebp) +movb $23,-216(%ebp) +movb $24,-44(%ebp) +movb $25,-220(%ebp) +movb $26,-48(%ebp) +movb $27,-224(%ebp) +movb $28,-52(%ebp) +movb $29,-228(%ebp) +movb $30,-56(%ebp) +movb $31,-232(%ebp) +movb $32,-60(%ebp) +movb $33,-236(%ebp) +movb $34,-64(%ebp) +movb $35,-240(%ebp) +movb $36,-244(%ebp) +movb $37,-248(%ebp) +movb $38,-256(%ebp) +leal -168(%ebp),%edi +leal -252(%ebp),%esi +movl %edi,%ebx +subl %esi,%ebx +movl %ebx,%esi +movl %esi,-152(%ebp) +leal -172(%ebp),%esi +subl %edi,%esi +movl %esi,%edi +movl %edi,-148(%ebp) +leal -176(%ebp),%edi +leal -172(%ebp),%esi +subl %esi,%edi +movl %edi,-144(%ebp) +leal -180(%ebp),%edi +leal -176(%ebp),%esi +subl %esi,%edi +movl %edi,-140(%ebp) +leal -184(%ebp),%edi +leal -180(%ebp),%esi +subl %esi,%edi +movl %edi,-136(%ebp) +leal -188(%ebp),%edi +leal -184(%ebp),%esi +subl %esi,%edi +movl %edi,-132(%ebp) +leal -192(%ebp),%edi +leal -188(%ebp),%esi +subl %esi,%edi +movl %edi,-128(%ebp) +leal -196(%ebp),%edi +leal -192(%ebp),%esi +subl %esi,%edi +movl %edi,-124(%ebp) +leal -200(%ebp),%edi +leal -196(%ebp),%esi +subl %esi,%edi +movl %edi,-120(%ebp) +leal -204(%ebp),%edi +leal -200(%ebp),%esi +subl %esi,%edi +movl %edi,-116(%ebp) +leal -208(%ebp),%edi +leal -204(%ebp),%esi +subl %esi,%edi +movl %edi,-112(%ebp) +leal -212(%ebp),%edi +leal -208(%ebp),%esi +subl %esi,%edi +movl %edi,-108(%ebp) +leal -216(%ebp),%edi +leal -212(%ebp),%esi +subl %esi,%edi +movl %edi,-104(%ebp) +leal -220(%ebp),%edi +leal -216(%ebp),%esi +subl %esi,%edi +movl %edi,-100(%ebp) +leal -224(%ebp),%edi +leal -220(%ebp),%esi +subl %esi,%edi +movl %edi,-96(%ebp) +leal -228(%ebp),%edi +leal -224(%ebp),%esi +subl %esi,%edi +movl %edi,-92(%ebp) +leal -232(%ebp),%edi +leal -228(%ebp),%esi +subl %esi,%edi +movl %edi,-88(%ebp) +leal -236(%ebp),%edi +leal -232(%ebp),%esi +subl %esi,%edi +movl %edi,-84(%ebp) +leal -240(%ebp),%edi +leal -236(%ebp),%esi +subl %esi,%edi +movl %edi,-80(%ebp) +leal -244(%ebp),%edi +leal -240(%ebp),%esi +subl %esi,%edi +movl %edi,-76(%ebp) +leal -248(%ebp),%edi +leal -244(%ebp),%esi +subl %esi,%edi +movl %edi,-72(%ebp) +leal -256(%ebp),%edi +leal -248(%ebp),%esi +subl %esi,%edi +movl %edi,-68(%ebp) +movl -152(%ebp),%edi +movl %edi,-164(%ebp) +movl $1,-160(%ebp) +movl $0,-156(%ebp) +.LC3075: +movl -160(%ebp),%edi +cmpl $1,%edi +je .LC3081 +cmpl $2,%edi +je .LC3084 +cmpl $3,%edi +je .LC3089 +jmp .LC3079 +.LC3081: +movl -156(%ebp),%edi +leal -152(%ebp),%esi +movl -164(%ebp),%ebx +cmpl %ebx,(%esi,%edi,4) +je .LC3080 +movl -156(%ebp),%edi +leal -152(%ebp),%esi +movl (%esi,%edi,4),%edi +movl %edi,-264(%ebp) +movl $2,-160(%ebp) +movl $1,-260(%ebp) +jmp .LC3080 +.LC3084: +movl -156(%ebp),%edi +leal -152(%ebp),%esi +movl -164(%ebp),%ebx +cmpl %ebx,(%esi,%edi,4) +jne .LC3085 +movl $3,-160(%ebp) +jmp .LC3080 +.LC3085: +movl -156(%ebp),%edi +leal -152(%ebp),%esi +movl -264(%ebp),%ebx +cmpl %ebx,(%esi,%edi,4) +jne .LC3087 +incl -260(%ebp) +jmp .LC3080 +.LC3087: +movl $4,-160(%ebp) +jmp .LC3080 +.LC3089: +movl -156(%ebp),%edi +leal -152(%ebp),%esi +movl -164(%ebp),%ebx +cmpl %ebx,(%esi,%edi,4) +je .LC3080 +movl $4,-160(%ebp) +.LC3079: +.LC3080: +.LC3076: +incl -156(%ebp) +cmpl $22,-156(%ebp) +jl .LC3075 +cmpl $3,-160(%ebp) +jne .LC3092 +mov $16,%edi +movl %edi,%eax +subl -260(%ebp),%eax +jmp .LC3053 +.LC3092: +mov $-1,%eax +.LC3053: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf3094: +.size regc,.Lf3094-regc +.globl regi +.align 16 +.type regi,@function +regi: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +subl $264,%esp +movl $0,-252(%ebp) +movl $1,-168(%ebp) +movl $2,-172(%ebp) +movl $3,-176(%ebp) +movl $4,-4(%ebp) +movl $5,-180(%ebp) +movl $6,-8(%ebp) +movl $7,-184(%ebp) +movl $8,-12(%ebp) +movl $9,-188(%ebp) +movl $10,-16(%ebp) +movl $11,-192(%ebp) +movl $12,-20(%ebp) +movl $13,-196(%ebp) +movl $14,-24(%ebp) +movl $15,-200(%ebp) +movl $16,-28(%ebp) +movl $17,-204(%ebp) +movl $18,-32(%ebp) +movl $19,-208(%ebp) +movl $20,-36(%ebp) +movl $21,-212(%ebp) +movl $22,-40(%ebp) +movl $23,-216(%ebp) +movl $24,-44(%ebp) +movl $25,-220(%ebp) +movl $26,-48(%ebp) +movl $27,-224(%ebp) +movl $28,-52(%ebp) +movl $29,-228(%ebp) +movl $30,-56(%ebp) +movl $31,-232(%ebp) +movl $32,-60(%ebp) +movl $33,-236(%ebp) +movl $34,-64(%ebp) +movl $35,-240(%ebp) +movl $36,-244(%ebp) +movl $37,-248(%ebp) +movl $38,-256(%ebp) +leal -168(%ebp),%edi +mov $4,%esi +leal -252(%ebp),%ebx +movl %edi,%edx +subl %ebx,%edx +movl %edx,%eax +movl %esi,%ecx +cdq +idivl %ecx +movl %eax,-152(%ebp) +leal -172(%ebp),%ebx +subl %edi,%ebx +movl %ebx,%eax +movl %esi,%ecx +cdq +idivl %ecx +movl %eax,-148(%ebp) +leal -176(%ebp),%edi +leal -172(%ebp),%esi +subl %esi,%edi +movl %edi,%eax +mov $4,%ecx +cdq +idivl %ecx +movl %eax,-144(%ebp) +leal -180(%ebp),%edi +leal -176(%ebp),%esi +subl %esi,%edi +movl %edi,%eax +mov $4,%ecx +cdq +idivl %ecx +movl %eax,-140(%ebp) +leal -184(%ebp),%edi +leal -180(%ebp),%esi +subl %esi,%edi +movl %edi,%eax +mov $4,%ecx +cdq +idivl %ecx +movl %eax,-136(%ebp) +leal -188(%ebp),%edi +leal -184(%ebp),%esi +subl %esi,%edi +movl %edi,%eax +mov $4,%ecx +cdq +idivl %ecx +movl %eax,-132(%ebp) +leal -192(%ebp),%edi +leal -188(%ebp),%esi +subl %esi,%edi +movl %edi,%eax +mov $4,%ecx +cdq +idivl %ecx +movl %eax,-128(%ebp) +leal -196(%ebp),%edi +leal -192(%ebp),%esi +subl %esi,%edi +movl %edi,%eax +mov $4,%ecx +cdq +idivl %ecx +movl %eax,-124(%ebp) +leal -200(%ebp),%edi +leal -196(%ebp),%esi +subl %esi,%edi +movl %edi,%eax +mov $4,%ecx +cdq +idivl %ecx +movl %eax,-120(%ebp) +leal -204(%ebp),%edi +leal -200(%ebp),%esi +subl %esi,%edi +movl %edi,%eax +mov $4,%ecx +cdq +idivl %ecx +movl %eax,-116(%ebp) +leal -208(%ebp),%edi +leal -204(%ebp),%esi +subl %esi,%edi +movl %edi,%eax +mov $4,%ecx +cdq +idivl %ecx +movl %eax,-112(%ebp) +leal -212(%ebp),%edi +leal -208(%ebp),%esi +subl %esi,%edi +movl %edi,%eax +mov $4,%ecx +cdq +idivl %ecx +movl %eax,-108(%ebp) +leal -216(%ebp),%edi +leal -212(%ebp),%esi +subl %esi,%edi +movl %edi,%eax +mov $4,%ecx +cdq +idivl %ecx +movl %eax,-104(%ebp) +leal -220(%ebp),%edi +leal -216(%ebp),%esi +subl %esi,%edi +movl %edi,%eax +mov $4,%ecx +cdq +idivl %ecx +movl %eax,-100(%ebp) +leal -224(%ebp),%edi +leal -220(%ebp),%esi +subl %esi,%edi +movl %edi,%eax +mov $4,%ecx +cdq +idivl %ecx +movl %eax,-96(%ebp) +leal -228(%ebp),%edi +leal -224(%ebp),%esi +subl %esi,%edi +movl %edi,%eax +mov $4,%ecx +cdq +idivl %ecx +movl %eax,-92(%ebp) +leal -232(%ebp),%edi +leal -228(%ebp),%esi +subl %esi,%edi +movl %edi,%eax +mov $4,%ecx +cdq +idivl %ecx +movl %eax,-88(%ebp) +leal -236(%ebp),%edi +leal -232(%ebp),%esi +subl %esi,%edi +movl %edi,%eax +mov $4,%ecx +cdq +idivl %ecx +movl %eax,-84(%ebp) +leal -240(%ebp),%edi +leal -236(%ebp),%esi +subl %esi,%edi +movl %edi,%eax +mov $4,%ecx +cdq +idivl %ecx +movl %eax,-80(%ebp) +leal -244(%ebp),%edi +leal -240(%ebp),%esi +subl %esi,%edi +movl %edi,%eax +mov $4,%ecx +cdq +idivl %ecx +movl %eax,-76(%ebp) +leal -248(%ebp),%edi +leal -244(%ebp),%esi +subl %esi,%edi +movl %edi,%eax +mov $4,%ecx +cdq +idivl %ecx +movl %eax,-72(%ebp) +leal -256(%ebp),%edi +leal -248(%ebp),%esi +subl %esi,%edi +movl %edi,%eax +mov $4,%ecx +cdq +idivl %ecx +movl %eax,-68(%ebp) +movl -152(%ebp),%edi +movl %edi,-164(%ebp) +movl $1,-160(%ebp) +movl $0,-156(%ebp) +.LC3117: +movl -160(%ebp),%edi +cmpl $1,%edi +je .LC3123 +cmpl $2,%edi +je .LC3126 +cmpl $3,%edi +je .LC3131 +jmp .LC3121 +.LC3123: +movl -156(%ebp),%edi +leal -152(%ebp),%esi +movl -164(%ebp),%ebx +cmpl %ebx,(%esi,%edi,4) +je .LC3122 +movl -156(%ebp),%edi +leal -152(%ebp),%esi +movl (%esi,%edi,4),%edi +movl %edi,-264(%ebp) +movl $2,-160(%ebp) +movl $1,-260(%ebp) +jmp .LC3122 +.LC3126: +movl -156(%ebp),%edi +leal -152(%ebp),%esi +movl -164(%ebp),%ebx +cmpl %ebx,(%esi,%edi,4) +jne .LC3127 +movl $3,-160(%ebp) +jmp .LC3122 +.LC3127: +movl -156(%ebp),%edi +leal -152(%ebp),%esi +movl -264(%ebp),%ebx +cmpl %ebx,(%esi,%edi,4) +jne .LC3129 +incl -260(%ebp) +jmp .LC3122 +.LC3129: +movl $4,-160(%ebp) +jmp .LC3122 +.LC3131: +movl -156(%ebp),%edi +leal -152(%ebp),%esi +movl -164(%ebp),%ebx +cmpl %ebx,(%esi,%edi,4) +je .LC3122 +movl $4,-160(%ebp) +.LC3121: +.LC3122: +.LC3118: +incl -156(%ebp) +cmpl $22,-156(%ebp) +jl .LC3117 +cmpl $3,-160(%ebp) +jne .LC3134 +mov $16,%edi +movl %edi,%eax +subl -260(%ebp),%eax +jmp .LC3095 +.LC3134: +mov $-1,%eax +.LC3095: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf3136: +.size regi,.Lf3136-regi +.globl regp +.align 16 +.type regp,@function +regp: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +subl $264,%esp +leal -252(%ebp),%edi +movl %edi,-252(%ebp) +leal -228(%ebp),%edi +movl %edi,-228(%ebp) +leal -232(%ebp),%edi +movl %edi,-232(%ebp) +leal -236(%ebp),%edi +movl %edi,-236(%ebp) +leal -164(%ebp),%edi +movl %edi,-4(%ebp) +leal -164(%ebp),%edi +movl %edi,-164(%ebp) +leal -168(%ebp),%edi +movl %edi,-8(%ebp) +leal -168(%ebp),%edi +movl %edi,-168(%ebp) +leal -172(%ebp),%edi +movl %edi,-12(%ebp) +leal -172(%ebp),%edi +movl %edi,-172(%ebp) +leal -176(%ebp),%edi +movl %edi,-16(%ebp) +leal -176(%ebp),%edi +movl %edi,-176(%ebp) +leal -180(%ebp),%edi +movl %edi,-20(%ebp) +leal -180(%ebp),%edi +movl %edi,-180(%ebp) +leal -184(%ebp),%edi +movl %edi,-24(%ebp) +leal -184(%ebp),%edi +movl %edi,-184(%ebp) +leal -188(%ebp),%edi +movl %edi,-28(%ebp) +leal -188(%ebp),%edi +movl %edi,-188(%ebp) +leal -192(%ebp),%edi +movl %edi,-32(%ebp) +leal -192(%ebp),%edi +movl %edi,-192(%ebp) +leal -196(%ebp),%edi +movl %edi,-36(%ebp) +leal -196(%ebp),%edi +movl %edi,-196(%ebp) +leal -200(%ebp),%edi +movl %edi,-40(%ebp) +leal -200(%ebp),%edi +movl %edi,-200(%ebp) +leal -204(%ebp),%edi +movl %edi,-44(%ebp) +leal -204(%ebp),%edi +movl %edi,-204(%ebp) +leal -208(%ebp),%edi +movl %edi,-48(%ebp) +leal -208(%ebp),%edi +movl %edi,-208(%ebp) +leal -212(%ebp),%edi +movl %edi,-52(%ebp) +leal -212(%ebp),%edi +movl %edi,-212(%ebp) +leal -216(%ebp),%edi +movl %edi,-56(%ebp) +leal -216(%ebp),%edi +movl %edi,-216(%ebp) +leal -220(%ebp),%edi +movl %edi,-60(%ebp) +leal -220(%ebp),%edi +movl %edi,-220(%ebp) +leal -224(%ebp),%edi +movl %edi,-64(%ebp) +leal -224(%ebp),%edi +movl %edi,-224(%ebp) +leal -240(%ebp),%edi +movl %edi,-240(%ebp) +leal -244(%ebp),%edi +movl %edi,-244(%ebp) +leal -256(%ebp),%edi +movl %edi,-256(%ebp) +leal -228(%ebp),%edi +mov $4,%esi +leal -252(%ebp),%ebx +movl %edi,%edx +subl %ebx,%edx +movl %edx,%eax +movl %esi,%ecx +cdq +idivl %ecx +movl %eax,-152(%ebp) +leal -232(%ebp),%ebx +subl %edi,%ebx +movl %ebx,%eax +movl %esi,%ecx +cdq +idivl %ecx +movl %eax,-148(%ebp) +leal -236(%ebp),%edi +leal -232(%ebp),%esi +subl %esi,%edi +movl %edi,%eax +mov $4,%ecx +cdq +idivl %ecx +movl %eax,-144(%ebp) +leal -164(%ebp),%edi +leal -236(%ebp),%esi +subl %esi,%edi +movl %edi,%eax +mov $4,%ecx +cdq +idivl %ecx +movl %eax,-140(%ebp) +leal -168(%ebp),%edi +leal -164(%ebp),%esi +subl %esi,%edi +movl %edi,%eax +mov $4,%ecx +cdq +idivl %ecx +movl %eax,-136(%ebp) +leal -172(%ebp),%edi +leal -168(%ebp),%esi +subl %esi,%edi +movl %edi,%eax +mov $4,%ecx +cdq +idivl %ecx +movl %eax,-132(%ebp) +leal -176(%ebp),%edi +leal -172(%ebp),%esi +subl %esi,%edi +movl %edi,%eax +mov $4,%ecx +cdq +idivl %ecx +movl %eax,-128(%ebp) +leal -180(%ebp),%edi +leal -176(%ebp),%esi +subl %esi,%edi +movl %edi,%eax +mov $4,%ecx +cdq +idivl %ecx +movl %eax,-124(%ebp) +leal -184(%ebp),%edi +leal -180(%ebp),%esi +subl %esi,%edi +movl %edi,%eax +mov $4,%ecx +cdq +idivl %ecx +movl %eax,-120(%ebp) +leal -188(%ebp),%edi +leal -184(%ebp),%esi +subl %esi,%edi +movl %edi,%eax +mov $4,%ecx +cdq +idivl %ecx +movl %eax,-116(%ebp) +leal -192(%ebp),%edi +leal -188(%ebp),%esi +subl %esi,%edi +movl %edi,%eax +mov $4,%ecx +cdq +idivl %ecx +movl %eax,-112(%ebp) +leal -196(%ebp),%edi +leal -192(%ebp),%esi +subl %esi,%edi +movl %edi,%eax +mov $4,%ecx +cdq +idivl %ecx +movl %eax,-108(%ebp) +leal -200(%ebp),%edi +leal -196(%ebp),%esi +subl %esi,%edi +movl %edi,%eax +mov $4,%ecx +cdq +idivl %ecx +movl %eax,-104(%ebp) +leal -204(%ebp),%edi +leal -200(%ebp),%esi +subl %esi,%edi +movl %edi,%eax +mov $4,%ecx +cdq +idivl %ecx +movl %eax,-100(%ebp) +leal -208(%ebp),%edi +leal -204(%ebp),%esi +subl %esi,%edi +movl %edi,%eax +mov $4,%ecx +cdq +idivl %ecx +movl %eax,-96(%ebp) +leal -212(%ebp),%edi +leal -208(%ebp),%esi +subl %esi,%edi +movl %edi,%eax +mov $4,%ecx +cdq +idivl %ecx +movl %eax,-92(%ebp) +leal -216(%ebp),%edi +leal -212(%ebp),%esi +subl %esi,%edi +movl %edi,%eax +mov $4,%ecx +cdq +idivl %ecx +movl %eax,-88(%ebp) +leal -220(%ebp),%edi +leal -216(%ebp),%esi +subl %esi,%edi +movl %edi,%eax +mov $4,%ecx +cdq +idivl %ecx +movl %eax,-84(%ebp) +leal -224(%ebp),%edi +leal -220(%ebp),%esi +subl %esi,%edi +movl %edi,%eax +mov $4,%ecx +cdq +idivl %ecx +movl %eax,-80(%ebp) +leal -240(%ebp),%edi +leal -224(%ebp),%esi +subl %esi,%edi +movl %edi,%eax +mov $4,%ecx +cdq +idivl %ecx +movl %eax,-76(%ebp) +leal -244(%ebp),%edi +leal -240(%ebp),%esi +subl %esi,%edi +movl %edi,%eax +mov $4,%ecx +cdq +idivl %ecx +movl %eax,-72(%ebp) +leal -256(%ebp),%edi +leal -244(%ebp),%esi +subl %esi,%edi +movl %edi,%eax +mov $4,%ecx +cdq +idivl %ecx +movl %eax,-68(%ebp) +movl -152(%ebp),%edi +movl %edi,-248(%ebp) +movl $1,-160(%ebp) +movl $0,-156(%ebp) +.LC3159: +movl -160(%ebp),%edi +cmpl $1,%edi +je .LC3165 +cmpl $2,%edi +je .LC3168 +cmpl $3,%edi +je .LC3173 +jmp .LC3163 +.LC3165: +movl -156(%ebp),%edi +leal -152(%ebp),%esi +movl -248(%ebp),%ebx +cmpl %ebx,(%esi,%edi,4) +je .LC3164 +movl -156(%ebp),%edi +leal -152(%ebp),%esi +movl (%esi,%edi,4),%edi +movl %edi,-264(%ebp) +movl $2,-160(%ebp) +movl $1,-260(%ebp) +jmp .LC3164 +.LC3168: +movl -156(%ebp),%edi +leal -152(%ebp),%esi +movl -248(%ebp),%ebx +cmpl %ebx,(%esi,%edi,4) +jne .LC3169 +movl $3,-160(%ebp) +jmp .LC3164 +.LC3169: +movl -156(%ebp),%edi +leal -152(%ebp),%esi +movl -264(%ebp),%ebx +cmpl %ebx,(%esi,%edi,4) +jne .LC3171 +incl -260(%ebp) +jmp .LC3164 +.LC3171: +movl $4,-160(%ebp) +jmp .LC3164 +.LC3173: +movl -156(%ebp),%edi +leal -152(%ebp),%esi +movl -248(%ebp),%ebx +cmpl %ebx,(%esi,%edi,4) +je .LC3164 +movl $4,-160(%ebp) +.LC3163: +.LC3164: +.LC3160: +incl -156(%ebp) +cmpl $22,-156(%ebp) +jl .LC3159 +cmpl $3,-160(%ebp) +jne .LC3176 +mov $16,%edi +movl %edi,%eax +subl -260(%ebp),%eax +jmp .LC3137 +.LC3176: +mov $-1,%eax +.LC3137: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf3178: +.size regp,.Lf3178-regp +.bss +.align 4 +.type x3d.3180,@object +.size x3d.3180,420 +.lcomm x3d.3180,420 +.data +.align 1 +.type s84er.3181,@object +s84er.3181: +.byte 115 +.byte 56 +.byte 52 +.byte 44 +.byte 101 +.byte 114 +.byte 37 +.byte 100 +.byte 10 +.byte 0 +.size s84er.3181,10 +.align 1 +.type qs84.3182,@object +.size qs84.3182,8 +qs84.3182: +.byte 115 +.byte 56 +.byte 52 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 0 +.globl s84 +.text +.align 16 +.type s84,@function +s84: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +subl $172,%esp +leal qs84.3182,%edi +movl %edi,-156(%ebp) +movl 20(%ebp),%edi +leal 60(%edi),%edi +movl %edi,-160(%ebp) +movl $0,-164(%ebp) +.LC3183: +.LC3184: +movl -160(%ebp),%edi +leal 1(%edi),%esi +movl %esi,-160(%ebp) +movl -156(%ebp),%esi +leal 1(%esi),%ebx +movl %ebx,-156(%ebp) +movb (,%esi),%bl +movb %bl,(,%edi) +movsbl %bl,%edi +cmpl $0,%edi +jne .LC3183 +pushl $3 +call fip +addl $4,%esp +movl %eax,-168(%ebp) +movl -168(%ebp),%edi +cmpl $3,(,%edi) +je .LC3186 +movl 20(%ebp),%edi +cmpl $0,44(%edi) +je .LC3188 +pushl $1 +pushl $s84er.3181 +call printf +addl $8,%esp +.LC3188: +incl -164(%ebp) +.LC3186: +leal glork,%edi +movl %edi,-172(%ebp) +pushl $4 +call *-172(%ebp) +addl $4,%esp +cmpl $4,%eax +je .LC3190 +movl 20(%ebp),%edi +cmpl $0,44(%edi) +je .LC3192 +pushl $2 +pushl $s84er.3181 +call printf +addl $8,%esp +.LC3192: +addl $2,-164(%ebp) +.LC3190: +movl $0,-8(%ebp) +.LC3194: +movl -8(%ebp),%edi +leal -80(%ebp),%esi +pushl %edi +fildl (%esp) +addl $4,%esp +fstps (%esi,%edi,4) +movl -8(%ebp),%edi +leal (,%edi,4),%edi +leal -148(%ebp),%esi +leal -80(%ebp),%ebx +leal (%ebx,%edi),%ebx +movl %ebx,(%esi,%edi) +.LC3195: +incl -8(%ebp) +cmpl $17,-8(%ebp) +jl .LC3194 +flds .LC421 +fstps -152(%ebp) +movl $0,-8(%ebp) +.LC3198: +flds -152(%ebp) +movl -8(%ebp),%edi +leal -148(%ebp),%esi +movl (%esi,%edi,4),%edi +fadds (,%edi) +fstps -152(%ebp) +.LC3199: +incl -8(%ebp) +cmpl $17,-8(%ebp) +jl .LC3198 +flds .LC3204 +fcomps -152(%ebp) +fstsw %ax +sahf +jp 1f +je .LC3202 +1: +movl 20(%ebp),%edi +cmpl $0,44(%edi) +je .LC3205 +pushl $4 +pushl $s84er.3181 +call printf +addl $8,%esp +.LC3205: +addl $4,-164(%ebp) +.LC3202: +movl $0,-12(%ebp) +.LC3207: +movl $0,-8(%ebp) +.LC3211: +movl $0,-4(%ebp) +.LC3215: +movl -4(%ebp),%edi +movl -8(%ebp),%esi +movl -12(%ebp),%ebx +imul $28,%esi,%edx +imul $140,%ebx,%ecx +leal x3d.3180(%ecx),%ecx +leal (%ecx,%edx),%edx +imul $35,%ebx,%ebx +imul $7,%esi,%esi +leal (%esi,%ebx),%esi +leal (%edi,%esi),%esi +movl %esi,(%edx,%edi,4) +.LC3216: +incl -4(%ebp) +cmpl $7,-4(%ebp) +jl .LC3215 +.LC3212: +incl -8(%ebp) +cmpl $5,-8(%ebp) +jl .LC3211 +.LC3208: +incl -12(%ebp) +cmpl $3,-12(%ebp) +jl .LC3207 +movl $1,-12(%ebp) +movl $2,-8(%ebp) +movl $3,-4(%ebp) +pushl $0 +pushl $105 +pushl $x3d.3180 +call array +addl $12,%esp +movl %eax,%edi +pushl $35 +pushl $35 +imul $140,-12(%ebp),%esi +leal x3d.3180(%esi),%esi +pushl %esi +call array +addl $12,%esp +movl %eax,%esi +pushl $49 +pushl $7 +imul $28,-8(%ebp),%ebx +imul $140,-12(%ebp),%edx +leal x3d.3180(%edx),%edx +leal (%edx,%ebx),%ebx +pushl %ebx +call array +addl $12,%esp +leal (%esi,%edi),%edi +leal (%eax,%edi),%edi +movl -4(%ebp),%esi +imul $28,-8(%ebp),%ebx +imul $140,-12(%ebp),%edx +leal x3d.3180(%edx),%edx +leal (%edx,%ebx),%ebx +movl (%ebx,%esi,4),%esi +leal (%esi,%edi),%edi +subl $52,%edi +cmpl $0,%edi +je .LC3219 +movl 20(%ebp),%edi +cmpl $0,44(%edi) +je .LC3221 +pushl $8 +pushl $s84er.3181 +call printf +addl $8,%esp +.LC3221: +addl $8,-164(%ebp) +.LC3219: +movl -164(%ebp),%eax +.LC3179: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf3223: +.size s84,.Lf3223-s84 +.globl array +.align 16 +.type array,@function +array: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +subl $4,%esp +movl $0,-4(%ebp) +jmp .LC3228 +.LC3225: +movl -4(%ebp),%edi +movl 20(%ebp),%esi +movl 28(%ebp),%ebx +leal (%ebx,%edi),%ebx +cmpl %ebx,(%esi,%edi,4) +je .LC3229 +mov $1,%eax +jmp .LC3224 +.LC3229: +.LC3226: +incl -4(%ebp) +.LC3228: +movl 24(%ebp),%edi +cmpl %edi,-4(%ebp) +jl .LC3225 +mov $0,%eax +.LC3224: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf3231: +.size array,.Lf3231-array +.bss +.align 4 +.type y.3233,@object +.size y.3233,4 +.lcomm y.3233,4 +.globl fip +.text +.align 16 +.type fip,@function +fip: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +leal y.3233,%edi +movl 20(%ebp),%esi +movl %esi,y.3233 +movl %edi,%eax +.LC3232: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf3234: +.size fip,.Lf3234-fip +.globl glork +.align 16 +.type glork,@function +glork: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +movl 20(%ebp),%eax +.LC3235: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf3236: +.size glork,.Lf3236-glork +.data +.align 1 +.type s85er.3238,@object +s85er.3238: +.byte 115 +.byte 56 +.byte 53 +.byte 44 +.byte 101 +.byte 114 +.byte 37 +.byte 100 +.byte 10 +.byte 0 +.size s85er.3238,10 +.align 1 +.type qs85.3239,@object +.size qs85.3239,8 +qs85.3239: +.byte 115 +.byte 56 +.byte 53 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 0 +.align 4 +.type type.3247,@object +type.3247: +.long .LC434 +.long .LC436 +.long .LC435 +.long .LC437 +.long .LC438 +.long .LC439 +.long .LC440 +.size type.3247,28 +.align 1 +.type aln.3248,@object +aln.3248: +.byte 32 +.byte 97 +.byte 108 +.byte 105 +.byte 103 +.byte 110 +.byte 109 +.byte 101 +.byte 110 +.byte 116 +.byte 58 +.byte 32 +.byte 0 +.size aln.3248,13 +.globl s85 +.text +.align 16 +.type s85,@function +s85: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +subl $404,%esp +leal qs85.3239,%edi +movl %edi,-276(%ebp) +movl 20(%ebp),%edi +leal 60(%edi),%edi +movl %edi,-280(%ebp) +movl $0,-320(%ebp) +.LC3252: +.LC3253: +movl -280(%ebp),%edi +leal 1(%edi),%esi +movl %esi,-280(%ebp) +movl -276(%ebp),%esi +leal 1(%esi),%ebx +movl %ebx,-276(%ebp) +movb (,%esi),%bl +movb %bl,(,%edi) +movsbl %bl,%edi +cmpl $0,%edi +jne .LC3252 +leal -296(%ebp),%edi +leal -316(%ebp),%esi +subl %esi,%edi +cmpl $0,%edi +jle .LC3263 +leal -292(%ebp),%edi +leal -296(%ebp),%esi +subl %esi,%edi +cmpl $0,%edi +jle .LC3263 +leal -288(%ebp),%edi +leal -292(%ebp),%esi +subl %esi,%edi +cmpl $0,%edi +jg .LC3255 +.LC3263: +movl 20(%ebp),%edi +cmpl $0,44(%edi) +je .LC3264 +pushl $1 +pushl $s85er.3238 +call printf +addl $8,%esp +.LC3264: +incl -320(%ebp) +.LC3255: +leal -355(%ebp),%edi +leal -356(%ebp),%esi +subl %esi,%edi +movl %edi,-272(%ebp) +leal -358(%ebp),%edi +leal -360(%ebp),%esi +subl %esi,%edi +movl %edi,-268(%ebp) +leal -364(%ebp),%edi +leal -368(%ebp),%esi +subl %esi,%edi +movl %edi,-264(%ebp) +leal -372(%ebp),%edi +leal -376(%ebp),%esi +subl %esi,%edi +movl %edi,-260(%ebp) +leal -380(%ebp),%edi +leal -384(%ebp),%esi +subl %esi,%edi +movl %edi,-256(%ebp) +leal -388(%ebp),%edi +leal -392(%ebp),%esi +subl %esi,%edi +movl %edi,-252(%ebp) +leal -400(%ebp),%edi +leal -404(%ebp),%esi +subl %esi,%edi +movl %edi,-248(%ebp) +movl 20(%ebp),%edi +cmpl $0,40(%edi) +je .LC3279 +movl $0,-244(%ebp) +.LC3281: +movl -244(%ebp),%edi +leal (,%edi,4),%edi +leal -272(%ebp),%esi +pushl (%esi,%edi) +pushl $aln.3248 +pushl type.3247(%edi) +pushl $.LC3285 +call printf +addl $16,%esp +.LC3282: +incl -244(%ebp) +cmpl $7,-244(%ebp) +jl .LC3281 +.LC3279: +movl -284(%ebp),%edi +orl $56,%edi +movl %edi,-284(%ebp) +movl -284(%ebp),%edi +movl %edi,%esi +andl $0xfffffffc,%esi +sall $26,%edi +sarl $29,%edi +sall $30,%edi +sarl $30,%edi +andl $3,%edi +orl %edi,%esi +movl %esi,-284(%ebp) +movl -284(%ebp),%edi +movl %edi,%esi +andl $0xffffffc7,%esi +sall $30,%edi +sarl $30,%edi +sall $29,%edi +sarl $29,%edi +leal (,%edi,8),%edi +andl $56,%edi +orl %edi,%esi +movl %esi,-284(%ebp) +movl -284(%ebp),%edi +sall $26,%edi +sarl $29,%edi +cmpl $3,%edi +je .LC3286 +movl -284(%ebp),%edi +sall $26,%edi +sarl $29,%edi +cmpl $-1,%edi +jne .LC3288 +movl 20(%ebp),%edi +cmpl $0,40(%edi) +je .LC3289 +pushl $.LC3292 +call printf +addl $4,%esp +jmp .LC3289 +.LC3288: +movl 20(%ebp),%edi +cmpl $0,44(%edi) +je .LC3293 +pushl $2 +pushl $s85er.3238 +call printf +addl $8,%esp +.LC3293: +addl $2,-320(%ebp) +.LC3289: +.LC3286: +movl -284(%ebp),%edi +orl $64,%edi +movl %edi,-284(%ebp) +movl -284(%ebp),%edi +sall $25,%edi +sarl $31,%edi +cmpl $1,%edi +je .LC3295 +movl 20(%ebp),%edi +cmpl $0,40(%edi) +je .LC3297 +pushl $.LC3299 +call printf +addl $4,%esp +.LC3297: +.LC3295: +leal -240(%ebp),%edi +movl %edi,%esi +subl %edi,%esi +cmpl $0,%esi +jne .LC3307 +cmpl $0,%esi +jne .LC3307 +cmpl $0,%esi +jne .LC3307 +cmpl $0,%esi +jne .LC3307 +cmpl $0,%esi +jne .LC3307 +cmpl $0,%esi +jne .LC3307 +cmpl $0,%esi +je .LC3300 +.LC3307: +movl 20(%ebp),%edi +cmpl $0,44(%edi) +je .LC3308 +pushl $4 +pushl $s85er.3238 +call printf +addl $8,%esp +.LC3308: +addl $4,-320(%ebp) +.LC3300: +jmp .LC3310 +movl 20(%ebp),%edi +cmpl $0,44(%edi) +je .LC3312 +pushl $8 +pushl $s85er.3238 +call printf +addl $8,%esp +.LC3312: +addl $8,-320(%ebp) +.LC3310: +leal -352(%ebp),%edi +movl %edi,-288(%ebp) +movb $2,-352(%ebp) +movl -288(%ebp),%edi +movsbl (,%edi),%esi +leal 1(%esi),%esi +movl %esi,%ebx +movb %bl,(,%edi) +movsbl -352(%ebp),%edi +cmpl $3,%edi +je .LC3316 +movl 20(%ebp),%edi +cmpl $0,44(%edi) +je .LC3318 +pushl $16 +pushl $s85er.3238 +call printf +addl $8,%esp +.LC3318: +addl $16,-320(%ebp) +.LC3316: +movl -320(%ebp),%eax +.LC3237: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf3320: +.size s85,.Lf3320-s85 +.data +.align 1 +.type s86er.3322,@object +s86er.3322: +.byte 115 +.byte 56 +.byte 54 +.byte 44 +.byte 101 +.byte 114 +.byte 37 +.byte 100 +.byte 10 +.byte 0 +.size s86er.3322,10 +.align 1 +.type qs86.3323,@object +.size qs86.3323,8 +qs86.3323: +.byte 115 +.byte 56 +.byte 54 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 0 +.align 4 +.type x.3324,@object +x.3324: +.long 1 +.long 3 +.long 5 +.size x.3324,12 +.align 4 +.type pint.3325,@object +.size pint.3325,4 +pint.3325: +.long x.3324+8 +.bss +.align 4 +.type zero.3327,@object +.size zero.3327,40 +.lcomm zero.3327,40 +.data +.align 4 +.type y0.3328,@object +y0.3328: +.long 1065353216 +.long 1077936128 +.long 1084227584 +.long 1073741824 +.long 1082130432 +.long 1086324736 +.long 1077936128 +.long 1084227584 +.long 1088421888 +.long 0 +.long 0 +.long 0 +.size y0.3328,48 +.align 4 +.type y1.3329,@object +.size y1.3329,48 +y1.3329: +.long 1065353216 +.long 1077936128 +.long 1084227584 +.long 1073741824 +.long 1082130432 +.long 1086324736 +.long 1077936128 +.long 1084227584 +.long 1088421888 +.space 12 +.align 4 +.type y2.3330,@object +.size y2.3330,48 +y2.3330: +.long 1065353216 +.long 1077936128 +.long 1084227584 +.long 1073741824 +.long 1082130432 +.long 1086324736 +.long 1077936128 +.long 1084227584 +.long 1088421888 +.space 12 +.align 4 +.type y3.3331,@object +.size y3.3331,48 +y3.3331: +.long 1065353216 +.space 8 +.long 1073741824 +.space 8 +.long 1077936128 +.space 8 +.long 1082130432 +.space 8 +.globl s86 +.text +.align 16 +.type s86,@function +s86: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +subl $40,%esp +movl pint.3325,%edi +leal -4(%edi),%edi +movl %edi,-36(%ebp) +call one +movl -36(%ebp),%esi +leal (%esi,%eax,4),%edi +movl %edi,-4(%ebp) +leal qs86.3323,%edi +movl %edi,-24(%ebp) +movl 20(%ebp),%edi +leal 60(%edi),%edi +movl %edi,-28(%ebp) +movl $0,-32(%ebp) +.LC3332: +.LC3333: +movl -28(%ebp),%edi +leal 1(%edi),%esi +movl %esi,-28(%ebp) +movl -24(%ebp),%esi +leal 1(%esi),%ebx +movl %ebx,-24(%ebp) +movb (,%esi),%bl +movb %bl,(,%edi) +movsbl %bl,%edi +cmpl $0,%edi +jne .LC3332 +movl pint.3325,%edi +cmpl $5,(,%edi) +je .LC3335 +movl 20(%ebp),%edi +cmpl $0,44(%edi) +je .LC3337 +pushl $1 +pushl $s86er.3322 +call printf +addl $8,%esp +.LC3337: +incl -32(%ebp) +.LC3335: +movl -36(%ebp),%edi +cmpl $3,(,%edi) +je .LC3339 +movl 20(%ebp),%edi +cmpl $0,44(%edi) +je .LC3341 +pushl $2 +pushl $s86er.3322 +call printf +addl $8,%esp +.LC3341: +addl $2,-32(%ebp) +.LC3339: +movl -4(%ebp),%edi +cmpl $5,(,%edi) +je .LC3343 +movl 20(%ebp),%edi +cmpl $0,44(%edi) +je .LC3345 +pushl $4 +pushl $s86er.3322 +call printf +addl $8,%esp +.LC3345: +addl $4,-32(%ebp) +.LC3343: +movl $0,-20(%ebp) +movl $0,-8(%ebp) +.LC3347: +movl -8(%ebp),%edi +cmpl $0,zero.3327(,%edi,4) +je .LC3351 +movl $1,-20(%ebp) +.LC3351: +.LC3348: +incl -8(%ebp) +cmpl $10,-8(%ebp) +jl .LC3347 +cmpl $0,-20(%ebp) +je .LC3353 +movl 20(%ebp),%edi +cmpl $0,44(%edi) +je .LC3355 +pushl $8 +pushl $s86er.3322 +call printf +addl $8,%esp +.LC3355: +addl $8,-32(%ebp) +.LC3353: +movl $0,-20(%ebp) +movl $0,-12(%ebp) +.LC3357: +movl $0,-8(%ebp) +.LC3361: +imul $3,-12(%ebp),%edi +movl -8(%ebp),%esi +leal (%esi,%edi),%edi +movl %edi,-16(%ebp) +movl -8(%ebp),%edi +leal (,%edi,4),%edi +imul $12,-12(%ebp),%esi +leal y1.3329(%esi),%ebx +flds (%ebx,%edi) +fstps -40(%ebp) +leal y2.3330(%esi),%esi +flds (%esi,%edi) +fcomps -40(%ebp) +fstsw %ax +sahf +jp .LC3367 +jne .LC3367 +movl -16(%ebp),%edi +flds y0.3328(,%edi,4) +fcomps -40(%ebp) +fstsw %ax +sahf +jp 1f +je .LC3365 +1: +.LC3367: +movl $1,-20(%ebp) +.LC3365: +.LC3362: +incl -8(%ebp) +cmpl $3,-8(%ebp) +jl .LC3361 +.LC3358: +incl -12(%ebp) +cmpl $4,-12(%ebp) +jl .LC3357 +cmpl $0,-20(%ebp) +je .LC3368 +movl 20(%ebp),%edi +cmpl $0,44(%edi) +je .LC3370 +pushl $16 +pushl $s86er.3322 +call printf +addl $8,%esp +.LC3370: +addl $16,-32(%ebp) +.LC3368: +movl $0,-20(%ebp) +movl $0,-8(%ebp) +.LC3372: +movl -8(%ebp),%edi +imul $12,%edi,%esi +leal 1(%edi),%edi +pushl %edi +fildl (%esp) +addl $4,%esp +fcomps y3.3331(%esi) +fstsw %ax +sahf +jp 1f +je .LC3376 +1: +movl $1,-20(%ebp) +.LC3376: +.LC3373: +incl -8(%ebp) +cmpl $4,-8(%ebp) +jl .LC3372 +cmpl $0,-20(%ebp) +je .LC3378 +movl 20(%ebp),%edi +cmpl $0,44(%edi) +je .LC3380 +pushl $32 +pushl $s86er.3322 +call printf +addl $8,%esp +.LC3380: +addl $32,-32(%ebp) +.LC3378: +movl -32(%ebp),%eax +.LC3321: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf3382: +.size s86,.Lf3382-s86 +.globl one +.align 16 +.type one,@function +one: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +mov $1,%eax +.LC3383: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf3384: +.size one,.Lf3384-one +.data +.align 1 +.type s88er.3386,@object +s88er.3386: +.byte 115 +.byte 56 +.byte 56 +.byte 44 +.byte 101 +.byte 114 +.byte 37 +.byte 100 +.byte 10 +.byte 0 +.size s88er.3386,10 +.align 1 +.type qs88.3387,@object +.size qs88.3387,8 +qs88.3387: +.byte 115 +.byte 56 +.byte 56 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 0 +.globl s88 +.text +.align 16 +.type s88,@function +s88: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +subl $44,%esp +leal qs88.3387,%edi +movl %edi,-4(%ebp) +movl 20(%ebp),%edi +leal 60(%edi),%edi +movl %edi,-8(%ebp) +movl $0,-12(%ebp) +.LC3389: +.LC3390: +movl -8(%ebp),%edi +leal 1(%edi),%esi +movl %esi,-8(%ebp) +movl -4(%ebp),%esi +leal 1(%esi),%ebx +movl %ebx,-4(%ebp) +movb (,%esi),%bl +movb %bl,(,%edi) +movsbl %bl,%edi +cmpl $0,%edi +jne .LC3389 +jmp .LC3392 +movl 20(%ebp),%edi +cmpl $0,44(%edi) +je .LC3394 +pushl $1 +pushl $s88er.3386 +call printf +addl $8,%esp +.LC3394: +incl -12(%ebp) +.LC3392: +leal -32(%ebp),%edi +movl %edi,metricp +movl $2,-32(%ebp) +movl metricp,%edi +movl $3,(,%edi) +cmpl $3,-32(%ebp) +je .LC3396 +movl 20(%ebp),%edi +cmpl $0,44(%edi) +je .LC3398 +pushl $2 +pushl $s88er.3386 +call printf +addl $8,%esp +.LC3398: +addl $2,-12(%ebp) +.LC3396: +fldl .LC428 +fstpl -28(%ebp) +fldl .LC428 +fstpl -20(%ebp) +leal -28(%ebp),%edi +movl %edi,-36(%ebp) +movl -36(%ebp),%edi +fldl .LC427 +fstpl (,%edi) +movl -36(%ebp),%edi +fldl .LC427 +fstpl 8(%edi) +fldl -28(%ebp) +faddl -20(%ebp) +fldl .LC425 +fcompp +fstsw %ax +sahf +jp 1f +je .LC3401 +1: +movl 20(%ebp),%edi +cmpl $0,44(%edi) +je .LC3404 +pushl $4 +pushl $s88er.3386 +call printf +addl $8,%esp +.LC3404: +addl $4,-12(%ebp) +.LC3401: +movl -12(%ebp),%eax +.LC3385: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf3406: +.size s88,.Lf3406-s88 +.data +.align 1 +.type s9er.3408,@object +s9er.3408: +.byte 115 +.byte 57 +.byte 44 +.byte 101 +.byte 114 +.byte 37 +.byte 100 +.byte 10 +.byte 0 +.size s9er.3408,9 +.align 1 +.type qs9.3409,@object +.size qs9.3409,8 +qs9.3409: +.byte 115 +.byte 57 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 0 +.globl s9 +.text +.align 16 +.type s9,@function +s9: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +subl $36,%esp +leal qs9.3409,%edi +movl %edi,-12(%ebp) +movl 20(%ebp),%edi +leal 60(%edi),%edi +movl %edi,-16(%ebp) +movl $0,-20(%ebp) +.LC3410: +.LC3411: +movl -16(%ebp),%edi +leal 1(%edi),%esi +movl %esi,-16(%ebp) +movl -12(%ebp),%esi +leal 1(%esi),%ebx +movl %ebx,-12(%ebp) +movb (,%esi),%bl +movb %bl,(,%edi) +movsbl %bl,%edi +cmpl $0,%edi +jne .LC3410 +movl $0,-8(%ebp) +movl $0,-4(%ebp) +.LC3413: +movl $2,-24(%ebp) +movl $2,-28(%ebp) +movl $3,-32(%ebp) +movl $3,-36(%ebp) +cmpl $3,-36(%ebp) +jne .LC3419 +cmpl $3,-32(%ebp) +je .LC3417 +.LC3419: +movl $1,-8(%ebp) +.LC3417: +cmpl $2,-28(%ebp) +jne .LC3422 +cmpl $2,-24(%ebp) +je .LC3420 +.LC3422: +movl $1,-8(%ebp) +.LC3420: +.LC3414: +incl -4(%ebp) +cmpl $2,-4(%ebp) +jl .LC3413 +cmpl $0,-8(%ebp) +je .LC3427 +movl 20(%ebp),%edi +cmpl $0,44(%edi) +je .LC3425 +pushl $1 +pushl $s9er.3408 +call printf +addl $8,%esp +.LC3425: +incl -20(%ebp) +jmp .LC3427 +movl 20(%ebp),%edi +cmpl $0,44(%edi) +je .LC3428 +pushl $2 +pushl $s9er.3408 +call printf +addl $8,%esp +.LC3428: +addl $2,-20(%ebp) +.LC3427: +movl -20(%ebp),%eax +.LC3407: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf3430: +.size s9,.Lf3430-s9 +.globl setev +.align 16 +.type setev,@function +setev: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +movl $1066,extvar +mov $0,%eax +.LC3431: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf3432: +.size setev,.Lf3432-setev +.bss +.globl rfs +.align 1 +.type rfs,@object +.size rfs,8 +.comm rfs,8 +.globl crc +.align 4 +.type crc,@object +.size crc,4 +.comm crc,4 +.globl rrc +.align 4 +.type rrc,@object +.size rrc,4 +.comm rrc,4 +.globl flgl +.align 4 +.type flgl,@object +.size flgl,4 +.comm flgl,4 +.globl flgd +.align 4 +.type flgd,@object +.size flgd,4 +.comm flgd,4 +.globl flgm +.align 4 +.type flgm,@object +.size flgm,4 +.comm flgm,4 +.globl flgs +.align 4 +.type flgs,@object +.size flgs,4 +.comm flgs,4 +.globl dprec +.align 4 +.type dprec,@object +.size dprec,4 +.comm dprec,4 +.globl fprec +.align 4 +.type fprec,@object +.size fprec,4 +.comm fprec,4 +.globl dbits +.align 4 +.type dbits,@object +.size dbits,4 +.comm dbits,4 +.globl fbits +.align 4 +.type fbits,@object +.size fbits,4 +.comm fbits,4 +.globl ubits +.align 4 +.type ubits,@object +.size ubits,4 +.comm ubits,4 +.globl lbits +.align 4 +.type lbits,@object +.size lbits,4 +.comm lbits,4 +.globl metricp +.align 4 +.type metricp,@object +.size metricp,4 +.comm metricp,4 +.globl extvar +.align 4 +.type extvar,@object +.size extvar,4 +.comm extvar,4 +.data +.align 1 +.LC3299: +.byte 66 +.byte 101 +.byte 32 +.byte 101 +.byte 115 +.byte 112 +.byte 101 +.byte 99 +.byte 105 +.byte 97 +.byte 108 +.byte 108 +.byte 121 +.byte 32 +.byte 99 +.byte 97 +.byte 114 +.byte 101 +.byte 102 +.byte 117 +.byte 108 +.byte 32 +.byte 119 +.byte 105 +.byte 116 +.byte 104 +.byte 32 +.byte 49 +.byte 45 +.byte 98 +.byte 105 +.byte 116 +.byte 32 +.byte 102 +.byte 105 +.byte 101 +.byte 108 +.byte 100 +.byte 115 +.byte 33 +.byte 10 +.byte 0 +.align 1 +.LC3292: +.byte 83 +.byte 105 +.byte 103 +.byte 110 +.byte 32 +.byte 101 +.byte 120 +.byte 116 +.byte 101 +.byte 110 +.byte 115 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 105 +.byte 110 +.byte 32 +.byte 102 +.byte 105 +.byte 101 +.byte 108 +.byte 100 +.byte 115 +.byte 10 +.byte 0 +.align 1 +.LC3285: +.byte 37 +.byte 115 +.byte 37 +.byte 115 +.byte 37 +.byte 100 +.byte 10 +.byte 0 +.align 4 +.LC3204: +.long 1124597760 +.align 1 +.LC3047: +.byte 112 +.byte 111 +.byte 105 +.byte 110 +.byte 116 +.byte 101 +.byte 114 +.byte 0 +.align 1 +.LC2495: +.byte 73 +.byte 110 +.byte 99 +.byte 114 +.byte 101 +.byte 97 +.byte 115 +.byte 105 +.byte 110 +.byte 103 +.byte 32 +.byte 97 +.byte 114 +.byte 114 +.byte 97 +.byte 121 +.byte 32 +.byte 101 +.byte 108 +.byte 101 +.byte 109 +.byte 101 +.byte 110 +.byte 116 +.byte 115 +.byte 32 +.byte 97 +.byte 115 +.byte 115 +.byte 105 +.byte 103 +.byte 110 +.byte 101 +.byte 100 +.byte 32 +.byte 116 +.byte 111 +.byte 32 +.byte 100 +.byte 101 +.byte 99 +.byte 114 +.byte 101 +.byte 97 +.byte 115 +.byte 105 +.byte 110 +.byte 103 +.byte 32 +.byte 108 +.byte 111 +.byte 99 +.byte 97 +.byte 116 +.byte 105 +.byte 111 +.byte 110 +.byte 115 +.byte 10 +.byte 0 +.align 4 +.LC2378: +.long 1104150528 +.align 4 +.LC2377: +.long 0 +.long 1077542912 +.align 4 +.LC1678: +.long 0 +.long 1074003968 +.align 4 +.LC1503: +.long 0 +.long 1076101120 +.align 4 +.LC1474: +.long 1092616192 +.align 4 +.LC1299: +.long 0 +.long 1074266112 +.align 4 +.LC1270: +.long 1077936128 +.align 4 +.LC1095: +.long 0 +.long 1075576832 +.align 4 +.LC1066: +.long 1088421888 +.align 4 +.LC889: +.long 0 +.long 1075052544 +.align 4 +.LC860: +.long 1084227584 +.align 4 +.LC855: +.long 0 +.long 1105199104 +.align 4 +.LC847: +.long 1325400064 +.align 1 +.LC669: +.byte 113 +.byte 117 +.byte 101 +.byte 101 +.byte 112 +.byte 0 +.align 1 +.LC654: +.byte 10 +.byte 0 +.align 1 +.LC653: +.byte 37 +.byte 100 +.byte 0 +.align 1 +.LC648: +.byte 32 +.byte 32 +.byte 32 +.byte 107 +.byte 101 +.byte 121 +.byte 61 +.byte 0 +.align 4 +.LC611: +.long 0 +.long 1073741824 +.align 4 +.LC551: +.long 0 +.long 1087276160 +.align 4 +.LC550: +.long 0 +.long 1079984128 +.align 4 +.LC549: +.long 1123680256 +.align 4 +.LC544: +.long 1073741824 +.align 1 +.LC440: +.byte 100 +.byte 111 +.byte 117 +.byte 98 +.byte 108 +.byte 101 +.byte 0 +.align 1 +.LC439: +.byte 102 +.byte 108 +.byte 111 +.byte 97 +.byte 116 +.byte 0 +.align 1 +.LC438: +.byte 117 +.byte 110 +.byte 115 +.byte 105 +.byte 103 +.byte 110 +.byte 101 +.byte 100 +.byte 0 +.align 1 +.LC437: +.byte 108 +.byte 111 +.byte 110 +.byte 103 +.byte 0 +.align 1 +.LC436: +.byte 115 +.byte 104 +.byte 111 +.byte 114 +.byte 116 +.byte 0 +.align 1 +.LC435: +.byte 105 +.byte 110 +.byte 116 +.byte 0 +.align 1 +.LC434: +.byte 99 +.byte 104 +.byte 97 +.byte 114 +.byte 0 +.align 4 +.LC428: +.long 0 +.long 0 +.align 4 +.LC427: +.long 0 +.long 1072693248 +.align 4 +.LC426: +.long 0 +.long 1074790400 +.align 4 +.LC425: +.long 0 +.long 1073741824 +.align 4 +.LC421: +.long 0 +.align 4 +.LC420: +.long 1065353216 +.align 1 +.LC398: +.byte 113 +.byte 117 +.byte 101 +.byte 101 +.byte 112 +.byte 33 +.byte 0 +.align 1 +.LC387: +.byte 10 +.byte 9 +.byte 8 +.byte 13 +.byte 12 +.byte 92 +.byte 39 +.byte 0 +.align 1 +.LC383: +.byte 46 +.byte 34 +.byte 46 +.byte 0 +.align 1 +.LC370: +.byte 46 +.byte 46 +.byte 46 +.byte 0 +.align 4 +.LC340: +.long 0 +.long 1083410432 +.align 1 +.LC201: +.byte 32 +.byte 32 +.byte 32 +.byte 100 +.byte 105 +.byte 102 +.byte 102 +.byte 101 +.byte 114 +.byte 101 +.byte 110 +.byte 116 +.byte 32 +.byte 114 +.byte 101 +.byte 115 +.byte 117 +.byte 108 +.byte 116 +.byte 115 +.byte 32 +.byte 119 +.byte 104 +.byte 101 +.byte 110 +.byte 32 +.byte 97 +.byte 115 +.byte 115 +.byte 105 +.byte 103 +.byte 110 +.byte 101 +.byte 100 +.byte 32 +.byte 116 +.byte 111 +.byte 32 +.byte 108 +.byte 111 +.byte 110 +.byte 103 +.byte 115 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC200: +.byte 68 +.byte 101 +.byte 99 +.byte 105 +.byte 109 +.byte 97 +.byte 108 +.byte 32 +.byte 97 +.byte 110 +.byte 100 +.byte 32 +.byte 111 +.byte 99 +.byte 116 +.byte 97 +.byte 108 +.byte 47 +.byte 104 +.byte 101 +.byte 120 +.byte 32 +.byte 99 +.byte 111 +.byte 110 +.byte 115 +.byte 116 +.byte 97 +.byte 110 +.byte 116 +.byte 115 +.byte 32 +.byte 115 +.byte 111 +.byte 109 +.byte 101 +.byte 116 +.byte 105 +.byte 109 +.byte 101 +.byte 115 +.byte 32 +.byte 103 +.byte 105 +.byte 118 +.byte 101 +.byte 10 +.byte 0 +.align 1 +.LC27: +.byte 10 +.byte 70 +.byte 97 +.byte 105 +.byte 108 +.byte 101 +.byte 100 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC26: +.byte 10 +.byte 78 +.byte 111 +.byte 32 +.byte 101 +.byte 114 +.byte 114 +.byte 111 +.byte 114 +.byte 115 +.byte 32 +.byte 100 +.byte 101 +.byte 116 +.byte 101 +.byte 99 +.byte 116 +.byte 101 +.byte 100 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC20: +.byte 83 +.byte 101 +.byte 99 +.byte 116 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 37 +.byte 115 +.byte 32 +.byte 114 +.byte 101 +.byte 116 +.byte 117 +.byte 114 +.byte 110 +.byte 101 +.byte 100 +.byte 32 +.byte 37 +.byte 100 +.byte 46 +.byte 10 +.byte 0 +.text +.ident "LCC: 4.1" diff --git a/src/cmd/lccom/tst/x86-linux/cvt.1bk b/src/cmd/lccom/tst/x86-linux/cvt.1bk new file mode 100644 index 0000000..b28b302 --- /dev/null +++ b/src/cmd/lccom/tst/x86-linux/cvt.1bk @@ -0,0 +1,11 @@ +1 1 1 1 1 1 1 1 1.000000 1.000000 1.000000 +2 2 2 2 2 2 2 2 2.000000 2.000000 2.000000 +3 3 3 3 3 3 3 3 3.000000 3.000000 3.000000 +4 4 4 4 4 4 4 4 4.000000 4.000000 4.000000 +5 5 5 5 5 5 5 5 5.000000 5.000000 5.000000 +6 6 6 6 6 6 6 6 6.000000 6.000000 6.000000 +7 7 7 7 7 7 7 7 7.000000 7.000000 7.000000 +8 8 8 8 8 8 8 8 8.000000 8.000000 8.000000 +9 9 9 9 9 9 9 9 9.000000 9.000000 9.000000 +10 10 10 10 10 10 10 10 10.000000 10.000000 10.000000 +11 11 11 11 11 11 11 11 11.000000 11.000000 11.000000 diff --git a/src/cmd/lccom/tst/x86-linux/cvt.2bk b/src/cmd/lccom/tst/x86-linux/cvt.2bk new file mode 100644 index 0000000..241527d --- /dev/null +++ b/src/cmd/lccom/tst/x86-linux/cvt.2bk @@ -0,0 +1,2 @@ +tst/cvt.c:32: warning: conversion from `pointer to void function(void)' to `pointer to void' is compiler dependent +tst/cvt.c:33: warning: conversion from `pointer to void' to `pointer to void function(void)' is compiler dependent diff --git a/src/cmd/lccom/tst/x86-linux/cvt.sbk b/src/cmd/lccom/tst/x86-linux/cvt.sbk new file mode 100644 index 0000000..b5b86a6 --- /dev/null +++ b/src/cmd/lccom/tst/x86-linux/cvt.sbk @@ -0,0 +1,993 @@ +.globl print +.text +.align 16 +.type print,@function +print: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +fldl D +subl $8,%esp +fstpl (%esp) +fldl d +subl $8,%esp +fstpl (%esp) +flds f +subl $8,%esp +fstpl (%esp) +pushl L +pushl I +movw S,%di +movzwl %di,%edi +pushl %edi +movb C,%bl +movzbl %bl,%edi +pushl %edi +pushl l +pushl i +movswl s,%edi +pushl %edi +movsbl c,%edi +pushl %edi +pushl $.LC2 +call printf +addl $60,%esp +.LC1: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf3: +.size print,.Lf3-print +.globl main +.align 16 +.type main,@function +main: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +subl $296,%esp +movb $1,c +movsbl c,%edi +movl %edi,%esi +movw %si,s +movl %edi,i +movl %edi,l +movl %edi,%esi +movl %esi,%ebx +movb %bl,C +movl %esi,%ebx +movw %bx,S +movl %esi,I +movl %esi,L +pushl %edi +fildl (%esp) +addl $4,%esp +fstps f +pushl %edi +fildl (%esp) +addl $4,%esp +fstpl -8(%ebp) +fldl -8(%ebp) +fstpl d +fldl -8(%ebp) +fstpl D +call print +movw $2,s +movswl s,%edi +movl %edi,%ebx +movb %bl,c +movl %edi,i +movl %edi,l +movl %edi,%esi +movl %esi,%ebx +movb %bl,C +movl %esi,%ebx +movw %bx,S +movl %esi,I +movl %esi,L +pushl %edi +fildl (%esp) +addl $4,%esp +fstps f +pushl %edi +fildl (%esp) +addl $4,%esp +fstpl -16(%ebp) +fldl -16(%ebp) +fstpl d +fldl -16(%ebp) +fstpl D +call print +movl $3,i +movl i,%edi +movl %edi,%ebx +movb %bl,c +movl %edi,%esi +movw %si,s +movl %edi,l +movl %edi,%esi +movl %esi,%ebx +movb %bl,C +movl %esi,%ebx +movw %bx,S +movl %esi,I +movl %esi,L +pushl %edi +fildl (%esp) +addl $4,%esp +fstps f +pushl %edi +fildl (%esp) +addl $4,%esp +fstpl -24(%ebp) +fldl -24(%ebp) +fstpl d +fldl -24(%ebp) +fstpl D +call print +movl $4,l +movl l,%edi +movl %edi,%ebx +movb %bl,c +movl %edi,%esi +movw %si,s +movl %edi,i +movl %edi,%esi +movl %esi,%ebx +movb %bl,C +movl %esi,%ebx +movw %bx,S +movl %esi,I +movl %esi,L +pushl %edi +fildl (%esp) +addl $4,%esp +fstps f +pushl %edi +fildl (%esp) +addl $4,%esp +fstpl -32(%ebp) +fldl -32(%ebp) +fstpl d +fldl -32(%ebp) +fstpl D +call print +movb $5,C +movb C,%bl +movzbl %bl,%edi +movl %edi,%ebx +movb %bl,c +movl %edi,%esi +movw %si,s +movl %edi,i +movl %edi,l +movl %edi,%esi +movl %esi,%ebx +movw %bx,S +movl %esi,I +movl %esi,L +pushl %edi +fildl (%esp) +addl $4,%esp +fstps f +pushl %edi +fildl (%esp) +addl $4,%esp +fstpl -40(%ebp) +fldl -40(%ebp) +fstpl d +fldl -40(%ebp) +fstpl D +call print +movw $6,S +movw S,%di +movzwl %di,%edi +movl %edi,%ebx +movb %bl,c +movl %edi,%esi +movw %si,s +movl %edi,i +movl %edi,l +movl %edi,%esi +movl %esi,%ebx +movb %bl,C +movl %esi,I +movl %esi,L +pushl %edi +fildl (%esp) +addl $4,%esp +fstps f +pushl %edi +fildl (%esp) +addl $4,%esp +fstpl -48(%ebp) +fldl -48(%ebp) +fstpl d +fldl -48(%ebp) +fstpl D +call print +movl $7,I +movl I,%edi +movl %edi,%ebx +movb %bl,c +movl %edi,%ebx +movw %bx,s +movl %edi,i +movl %edi,l +movl %edi,%ebx +movb %bl,C +movl %edi,%esi +movw %si,S +movl %edi,L +fldl .LC5 +movl %edi,%esi +shrl $1,%esi +pushl %esi +fildl (%esp) +addl $4,%esp +fmulp %st,%st(1) +andl $1,%edi +pushl %edi +fildl (%esp) +addl $4,%esp +faddp %st,%st(1) +fstpl -56(%ebp) +fldl -56(%ebp) +fstps f +fldl -56(%ebp) +fstpl d +fldl -56(%ebp) +fstpl D +call print +movl $8,L +movl L,%edi +movl %edi,%ebx +movb %bl,c +movl %edi,%ebx +movw %bx,s +movl %edi,i +movl %edi,l +movl %edi,%ebx +movb %bl,C +movl %edi,%esi +movw %si,S +movw S,%si +movzwl %si,%esi +movl %esi,I +fldl .LC5 +movl %edi,%esi +shrl $1,%esi +pushl %esi +fildl (%esp) +addl $4,%esp +fmulp %st,%st(1) +andl $1,%edi +pushl %edi +fildl (%esp) +addl $4,%esp +faddp %st,%st(1) +fstpl -64(%ebp) +fldl -64(%ebp) +fstps f +fldl -64(%ebp) +fstpl d +fldl -64(%ebp) +fstpl D +call print +flds .LC6 +fstps f +flds f +fstps -84(%ebp) +flds -84(%ebp) +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,%edi +movl %edi,%ebx +movb %bl,c +movl %edi,%esi +movw %si,s +movl %edi,i +movl %edi,l +flds .LC10 +fcomps -84(%ebp) +fstsw %ax +sahf +jp .LC8 +ja .LC8 +flds -84(%ebp) +fsubs .LC10 +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,%edi +leal 0x80000000(%edi),%edi +movl %edi,-68(%ebp) +jmp .LC9 +.LC8: +flds -84(%ebp) +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,%edi +movl %edi,-68(%ebp) +.LC9: +movl -68(%ebp),%edi +movl %edi,%ebx +movb %bl,C +flds .LC10 +fcomps f +fstsw %ax +sahf +jp .LC12 +ja .LC12 +flds f +fsubs .LC10 +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,%edi +leal 0x80000000(%edi),%edi +movl %edi,-72(%ebp) +jmp .LC13 +.LC12: +flds f +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,%edi +movl %edi,-72(%ebp) +.LC13: +movl -72(%ebp),%edi +movw %di,S +flds .LC10 +fcomps f +fstsw %ax +sahf +jp .LC15 +ja .LC15 +flds f +fsubs .LC10 +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,%edi +leal 0x80000000(%edi),%edi +movl %edi,-76(%ebp) +jmp .LC16 +.LC15: +flds f +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,%edi +movl %edi,-76(%ebp) +.LC16: +movl -76(%ebp),%edi +movl %edi,I +flds .LC10 +fcomps f +fstsw %ax +sahf +jp .LC18 +ja .LC18 +flds f +fsubs .LC10 +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,%edi +leal 0x80000000(%edi),%edi +movl %edi,-80(%ebp) +jmp .LC19 +.LC18: +flds f +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,%edi +movl %edi,-80(%ebp) +.LC19: +movl -80(%ebp),%edi +movl %edi,L +flds f +fstpl -120(%ebp) +fldl -120(%ebp) +fstpl d +fldl -120(%ebp) +fstpl D +call print +fldl .LC20 +fstpl d +fldl d +fstpl -144(%ebp) +fldl -144(%ebp) +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,%edi +movl %edi,%ebx +movb %bl,c +movl %edi,%esi +movw %si,s +movl %edi,i +movl %edi,l +fldl .LC24 +fcompl -144(%ebp) +fstsw %ax +sahf +jp .LC22 +ja .LC22 +fldl -144(%ebp) +fsubl .LC24 +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,%edi +leal 0x80000000(%edi),%edi +movl %edi,-124(%ebp) +jmp .LC23 +.LC22: +fldl -144(%ebp) +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,%edi +movl %edi,-124(%ebp) +.LC23: +movl -124(%ebp),%edi +movl %edi,%ebx +movb %bl,C +fldl .LC24 +fcompl d +fstsw %ax +sahf +jp .LC26 +ja .LC26 +fldl d +fsubl .LC24 +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,%edi +leal 0x80000000(%edi),%edi +movl %edi,-128(%ebp) +jmp .LC27 +.LC26: +fldl d +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,%edi +movl %edi,-128(%ebp) +.LC27: +movl -128(%ebp),%edi +movw %di,S +fldl .LC24 +fcompl d +fstsw %ax +sahf +jp .LC29 +ja .LC29 +fldl d +fsubl .LC24 +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,%edi +leal 0x80000000(%edi),%edi +movl %edi,-132(%ebp) +jmp .LC30 +.LC29: +fldl d +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,%edi +movl %edi,-132(%ebp) +.LC30: +movl -132(%ebp),%edi +movl %edi,I +fldl .LC24 +fcompl d +fstsw %ax +sahf +jp .LC32 +ja .LC32 +fldl d +fsubl .LC24 +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,%edi +leal 0x80000000(%edi),%edi +movl %edi,-136(%ebp) +jmp .LC33 +.LC32: +fldl d +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,%edi +movl %edi,-136(%ebp) +.LC33: +movl -136(%ebp),%edi +movl %edi,L +fldl d +fstps f +fldl d +fstpl D +call print +fldl .LC34 +fstpl D +fldl D +fstpl -232(%ebp) +fldl -232(%ebp) +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,%edi +movl %edi,%ebx +movb %bl,c +movl %edi,%esi +movw %si,s +movl %edi,i +movl %edi,l +fldl .LC38 +fcompl -232(%ebp) +fstsw %ax +sahf +jp .LC36 +ja .LC36 +fldl -232(%ebp) +fsubl .LC38 +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,%edi +leal 0x80000000(%edi),%edi +movl %edi,-212(%ebp) +jmp .LC37 +.LC36: +fldl -232(%ebp) +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,%edi +movl %edi,-212(%ebp) +.LC37: +movl -212(%ebp),%edi +movl %edi,%ebx +movb %bl,C +fldl .LC38 +fcompl D +fstsw %ax +sahf +jp .LC40 +ja .LC40 +fldl D +fsubl .LC38 +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,%edi +leal 0x80000000(%edi),%edi +movl %edi,-216(%ebp) +jmp .LC41 +.LC40: +fldl D +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,%edi +movl %edi,-216(%ebp) +.LC41: +movl -216(%ebp),%edi +movw %di,S +fldl .LC38 +fcompl D +fstsw %ax +sahf +jp .LC43 +ja .LC43 +fldl D +fsubl .LC38 +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,%edi +leal 0x80000000(%edi),%edi +movl %edi,-220(%ebp) +jmp .LC44 +.LC43: +fldl D +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,%edi +movl %edi,-220(%ebp) +.LC44: +movl -220(%ebp),%edi +movl %edi,I +fldl .LC38 +fcompl D +fstsw %ax +sahf +jp .LC46 +ja .LC46 +fldl D +fsubl .LC38 +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,%edi +leal 0x80000000(%edi),%edi +movl %edi,-224(%ebp) +jmp .LC47 +.LC46: +fldl D +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,%edi +movl %edi,-224(%ebp) +.LC47: +movl -224(%ebp),%edi +movl %edi,L +fldl D +fstps f +fldl D +fstpl d +call print +movl $0,p +movl $0,p +movl $0,p +movl $0,p +movl P,%edi +movl %edi,p +movl $0,P +movl $0,P +movl $0,P +movl $0,P +movl p,%edi +movl %edi,P +mov $0,%eax +.LC4: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf48: +.size main,.Lf48-main +.bss +.globl P +.align 4 +.type P,@object +.size P,4 +.comm P,4 +.globl p +.align 4 +.type p,@object +.size p,4 +.comm p,4 +.globl D +.align 4 +.type D,@object +.size D,8 +.comm D,8 +.globl d +.align 4 +.type d,@object +.size d,8 +.comm d,8 +.globl f +.align 4 +.type f,@object +.size f,4 +.comm f,4 +.globl L +.align 4 +.type L,@object +.size L,4 +.comm L,4 +.globl I +.align 4 +.type I,@object +.size I,4 +.comm I,4 +.globl S +.align 2 +.type S,@object +.size S,2 +.comm S,2 +.globl C +.align 1 +.type C,@object +.size C,1 +.comm C,1 +.globl l +.align 4 +.type l,@object +.size l,4 +.comm l,4 +.globl i +.align 4 +.type i,@object +.size i,4 +.comm i,4 +.globl s +.align 2 +.type s,@object +.size s,2 +.comm s,2 +.globl c +.align 1 +.type c,@object +.size c,1 +.comm c,1 +.data +.align 4 +.LC38: +.long 0 +.long 1105199104 +.align 4 +.LC34: +.long 0 +.long 1076232192 +.align 4 +.LC24: +.long 0 +.long 1105199104 +.align 4 +.LC20: +.long 0 +.long 1076101120 +.align 4 +.LC10: +.long 1325400064 +.align 4 +.LC6: +.long 1091567616 +.align 4 +.LC5: +.long 0 +.long 1073741824 +.align 1 +.LC2: +.byte 37 +.byte 100 +.byte 32 +.byte 37 +.byte 100 +.byte 32 +.byte 37 +.byte 100 +.byte 32 +.byte 37 +.byte 108 +.byte 100 +.byte 32 +.byte 37 +.byte 117 +.byte 32 +.byte 37 +.byte 117 +.byte 32 +.byte 37 +.byte 117 +.byte 32 +.byte 37 +.byte 108 +.byte 117 +.byte 32 +.byte 37 +.byte 102 +.byte 32 +.byte 37 +.byte 102 +.byte 32 +.byte 37 +.byte 108 +.byte 102 +.byte 10 +.byte 0 +.text +.ident "LCC: 4.1" diff --git a/src/cmd/lccom/tst/x86-linux/fields.1bk b/src/cmd/lccom/tst/x86-linux/fields.1bk new file mode 100644 index 0000000..56fdeb9 --- /dev/null +++ b/src/cmd/lccom/tst/x86-linux/fields.1bk @@ -0,0 +1,5 @@ +x = 1 2 3 4 -3 6 +y = 3 8 9 +x = 1 2 3 0 0 6 +y = 2 8 16 +p->a = 0x3, p->b = 0xf diff --git a/src/cmd/lccom/tst/x86-linux/fields.2bk b/src/cmd/lccom/tst/x86-linux/fields.2bk new file mode 100644 index 0000000..51e1736 --- /dev/null +++ b/src/cmd/lccom/tst/x86-linux/fields.2bk @@ -0,0 +1,4 @@ +tst/fields.c:6: warning: initializer exceeds bit-field width +tst/fields.c:8: warning: initializer exceeds bit-field width +tst/fields.c:30: warning: missing return value +tst/fields.c:34: warning: missing return value diff --git a/src/cmd/lccom/tst/x86-linux/fields.sbk b/src/cmd/lccom/tst/x86-linux/fields.sbk new file mode 100644 index 0000000..b999036 --- /dev/null +++ b/src/cmd/lccom/tst/x86-linux/fields.sbk @@ -0,0 +1,321 @@ +.data +.globl x +.align 4 +.type x,@object +.size x,16 +x: +.long 1 +.byte 2 +.space 3 +.byte 3 +.byte 64 +.space 2 +.byte 80 +.byte 6 +.space 2 +.globl i +.align 4 +.type i,@object +.size i,4 +i: +.long 16 +.globl y +.align 4 +.type y,@object +.size y,8 +y: +.byte 35 +.space 3 +.byte 9 +.byte 0 +.byte 0 +.byte 0 +.globl main +.text +.align 16 +.type main,@function +main: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +movsbl x+13,%edi +pushl %edi +movl x+12,%edi +sall $25,%edi +sarl $29,%edi +pushl %edi +movl x+8,%edi +sall $16,%edi +sarl $28,%edi +pushl %edi +movl x+8,%edi +sall $20,%edi +sarl $20,%edi +pushl %edi +movsbl x+4,%edi +pushl %edi +pushl x +pushl $.LC4 +call printf +addl $28,%esp +pushl y+4 +movl y,%edi +movl %edi,%esi +shrl $2,%esi +andl $15,%esi +pushl %esi +andl $3,%edi +pushl %edi +pushl $.LC10 +call printf +addl $16,%esp +movl x+8,%edi +andl $0xffff0fff,%edi +movl i,%esi +sall $28,%esi +sarl $28,%esi +shll $12,%esi +andl $0xf000,%esi +orl %esi,%edi +movl %edi,x+8 +movl x+12,%edi +andl $0xffffff8f,%edi +movl %edi,x+12 +movsbl x+13,%edi +pushl %edi +movl x+12,%edi +sall $25,%edi +sarl $29,%edi +pushl %edi +movl x+8,%edi +sall $16,%edi +sarl $28,%edi +pushl %edi +movl x+8,%edi +sall $20,%edi +sarl $20,%edi +pushl %edi +movsbl x+4,%edi +pushl %edi +pushl x +pushl $.LC4 +call printf +addl $28,%esp +movl y,%edi +andl $0xfffffffc,%edi +orl $2,%edi +movl %edi,y +movl i,%edi +movl %edi,y+4 +pushl y+4 +movl y,%edi +movl %edi,%esi +shrl $2,%esi +andl $15,%esi +pushl %esi +andl $3,%edi +pushl %edi +pushl $.LC10 +call printf +addl $16,%esp +pushl $x +call f2 +addl $4,%esp +mov $0,%eax +.LC3: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf21: +.size main,.Lf21-main +.globl f1 +.align 16 +.type f1,@function +f1: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +movl 20(%ebp),%edi +andl $0xffffffc3,(,%edi) +movl 20(%ebp),%edi +movl (,%edi),%esi +andl $0xfffffffc,%esi +mov $0,%ebx +andl $3,%ebx +andl $3,%ebx +orl %ebx,%esi +movl %esi,(,%edi) +movl 20(%ebp),%edi +movl (,%edi),%edi +andl $60,%edi +cmpl $0,%edi +je .LC23 +pushl $.LC25 +call printf +addl $4,%esp +.LC23: +movl 20(%ebp),%edi +orl $3,(,%edi) +movl 20(%ebp),%edi +orl $60,(,%edi) +movl 20(%ebp),%edi +movl (,%edi),%edi +movl %edi,%esi +shrl $2,%esi +andl $15,%esi +pushl %esi +andl $3,%edi +pushl %edi +pushl $.LC26 +call printf +addl $12,%esp +mov $0,%eax +.LC22: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf27: +.size f1,.Lf27-f1 +.globl f2 +.align 16 +.type f2,@function +f2: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +subl $4,%esp +cmpl $0,i +jne .LC30 +movl $1,-4(%ebp) +jmp .LC31 +.LC30: +movl $0,-4(%ebp) +.LC31: +movl 20(%ebp),%edi +movl (,%edi),%esi +andl $0xfffffffc,%esi +movl -4(%ebp),%ebx +andl $3,%ebx +andl $3,%ebx +orl %ebx,%esi +movl %esi,(,%edi) +movl 20(%ebp),%edi +pushl %edi +call f1 +addl $4,%esp +movl (,%edi),%esi +andl $0xffffffc3,%esi +mov $0,%ebx +andl $15,%ebx +leal (,%ebx,4),%ebx +andl $60,%ebx +orl %ebx,%esi +movl %esi,(,%edi) +mov $0,%eax +.LC28: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf32: +.size f2,.Lf32-f2 +.data +.align 1 +.LC26: +.byte 112 +.byte 45 +.byte 62 +.byte 97 +.byte 32 +.byte 61 +.byte 32 +.byte 48 +.byte 120 +.byte 37 +.byte 120 +.byte 44 +.byte 32 +.byte 112 +.byte 45 +.byte 62 +.byte 98 +.byte 32 +.byte 61 +.byte 32 +.byte 48 +.byte 120 +.byte 37 +.byte 120 +.byte 10 +.byte 0 +.align 1 +.LC25: +.byte 112 +.byte 45 +.byte 62 +.byte 98 +.byte 32 +.byte 33 +.byte 61 +.byte 32 +.byte 48 +.byte 33 +.byte 10 +.byte 0 +.align 1 +.LC10: +.byte 121 +.byte 32 +.byte 61 +.byte 32 +.byte 37 +.byte 100 +.byte 32 +.byte 37 +.byte 100 +.byte 32 +.byte 37 +.byte 100 +.byte 10 +.byte 0 +.align 1 +.LC4: +.byte 120 +.byte 32 +.byte 61 +.byte 32 +.byte 37 +.byte 100 +.byte 32 +.byte 37 +.byte 100 +.byte 32 +.byte 37 +.byte 100 +.byte 32 +.byte 37 +.byte 100 +.byte 32 +.byte 37 +.byte 100 +.byte 32 +.byte 37 +.byte 100 +.byte 10 +.byte 0 +.text +.ident "LCC: 4.1" diff --git a/src/cmd/lccom/tst/x86-linux/float.h b/src/cmd/lccom/tst/x86-linux/float.h new file mode 100644 index 0000000..fde462b --- /dev/null +++ b/src/cmd/lccom/tst/x86-linux/float.h @@ -0,0 +1,37 @@ +#ifndef __FLOAT +#define __FLOAT + +#define FLT_ROUNDS (__flt_rounds()) +#define FLT_RADIX 2 + +#define FLT_DIG 6 +#define FLT_EPSILON 1.19209289550781250000e-07 +#define FLT_MANT_DIG 24 +#define FLT_MAX 3.40282346638528860000e+38 +#define FLT_MAX_10_EXP 38 +#define FLT_MAX_EXP 128 +#define FLT_MIN 1.17549435082228750000e-38 +#define FLT_MIN_10_EXP -37 +#define FLT_MIN_EXP -125 + +#define DBL_DIG 15 +#define DBL_EPSILON 2.22044604925031310000e-16 +#define DBL_MANT_DIG 53 +#define DBL_MAX 1.79769313486231570000e+308 +#define DBL_MAX_10_EXP 308 +#define DBL_MAX_EXP 1024 +#define DBL_MIN 2.22507385850720140000e-308 +#define DBL_MIN_10_EXP -307 +#define DBL_MIN_EXP -1021 + +#define LDBL_MANT_DIG DBL_MANT_DIG +#define LDBL_EPSILON DBL_EPSILON +#define LDBL_DIG DBL_DIG +#define LDBL_MIN_EXP DBL_MIN_EXP +#define LDBL_MIN DBL_MIN +#define LDBL_MIN_10_EXP DBL_MIN_10_EXP +#define LDBL_MAX_EXP DBL_MAX_EXP +#define LDBL_MAX DBL_MAX +#define LDBL_MAX_10_EXP DBL_MAX_10_EXP + +#endif /* __FLOAT */ diff --git a/src/cmd/lccom/tst/x86-linux/front.2bk b/src/cmd/lccom/tst/x86-linux/front.2bk new file mode 100644 index 0000000..bbd390a --- /dev/null +++ b/src/cmd/lccom/tst/x86-linux/front.2bk @@ -0,0 +1,29 @@ +tst/front.c:3: warning: missing return value +tst/front.c:10: warning: missing return value +tst/front.c:20: type error in argument 1 to `s'; found `pointer to struct D' expected `pointer to incomplete struct D defined at tst/front.c:14' +tst/front.c:21: warning: missing return value +tst/front.c:32: warning: missing return value +tst/front.c:36: operands of = have illegal types `pointer to int' and `pointer to const int' +tst/front.c:38: warning: missing return value +tst/front.c:62: operands of = have illegal types `pointer to char' and `pointer to const void' +tst/front.c:63: warning: missing return value +tst/front.c:68: warning: missing return value +tst/front.c:69: warning: inconsistent linkage for `yy' previously declared at tst/front.c:68 +tst/front.c:69: warning: missing return value +tst/front.c:71: invalid storage class `static' for `int function goo' +tst/front.c:71: warning: declaration of `goo' does not match previous declaration at tst/front.c:70 +tst/front.c:71: warning: missing return value +tst/front.c:74: warning: declaration of `xr' does not match previous declaration at tst/front.c:72 +tst/front.c:74: warning: missing return value +tst/front.c:81: warning: missing return value +tst/front.c:82: warning: declaration of `ss2' does not match previous declaration at tst/front.c:81 +tst/front.c:84: warning: inconsistent linkage for `ss5' previously declared at tst/front.c:80 +tst/front.c:92: type error in argument 1 to `gx1'; found `pointer to double' expected `double' +tst/front.c:92: warning: missing return value +tst/front.c:95: redeclaration of `hx1' previously declared at tst/front.c:94 +tst/front.c:98: warning: missing return value +tst/front.c:101: conflicting argument declarations for function `gg1' +tst/front.c:101: warning: missing return value +tst/front.c:112: type error in argument 4 to `qsort'; found `pointer to int function(pointer to pointer to char,pointer to pointer to char)' expected `pointer to int function(pointer to const void,pointer to const void)' +tst/front.c:113: warning: missing return value +tst/front.c:120: warning: missing return value diff --git a/src/cmd/lccom/tst/x86-linux/front.sbk b/src/cmd/lccom/tst/x86-linux/front.sbk new file mode 100644 index 0000000..8e49df0 --- /dev/null +++ b/src/cmd/lccom/tst/x86-linux/front.sbk @@ -0,0 +1,530 @@ +.globl main +.text +.align 16 +.type main,@function +main: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +pushl $0 +call exit +addl $4,%esp +mov $0,%eax +.LC1: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf2: +.size main,.Lf2-main +.globl nested +.align 16 +.type nested,@function +nested: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +cmpl $4,20(%ebp) +jge .LC7 +cmpl $114,24(%ebp) +je .LC10 +.LC7: +cmpl $1,20(%ebp) +jne .LC9 +movl 24(%ebp),%edi +cmpl $104,%edi +je .LC10 +cmpl $105,%edi +je .LC10 +.LC9: +cmpl $2,20(%ebp) +jne .LC4 +movl 24(%ebp),%edi +cmpl $111,%edi +je .LC10 +cmpl $121,%edi +jne .LC4 +.LC10: +movl 24(%ebp),%edi +movl %edi,20(%ebp) +.LC4: +mov $0,%eax +.LC3: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf11: +.size nested,.Lf11-nested +.globl s +.align 16 +.type s,@function +s: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +.LC12: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf13: +.size s,.Lf13-s +.data +.globl Dy +.align 4 +.type Dy,@object +.size Dy,8 +Dy: +.long 0 +.space 4 +.globl Dz +.align 4 +.type Dz,@object +.size Dz,8 +Dz: +.long 1 +.space 4 +.globl Dfunc +.text +.align 16 +.type Dfunc,@function +Dfunc: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf16: +.size Dfunc,.Lf16-Dfunc +.globl f +.align 16 +.type f,@function +f: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf18: +.size f,.Lf18-f +.globl f1 +.align 16 +.type f1,@function +f1: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf20: +.size f1,.Lf20-f1 +.globl f2 +.align 16 +.type f2,@function +f2: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf22: +.size f2,.Lf22-f2 +.globl g +.align 16 +.type g,@function +g: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf24: +.size g,.Lf24-g +.globl h +.align 16 +.type h,@function +h: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf26: +.size h,.Lf26-h +.globl h1 +.align 16 +.type h1,@function +h1: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf28: +.size h1,.Lf28-h1 +.globl h2 +.align 16 +.type h2,@function +h2: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf30: +.size h2,.Lf30-h2 +.data +.align 4 +.type yy.32,@object +.size yy.32,4 +yy.32: +.long 1 +.globl set1 +.text +.align 16 +.type set1,@function +set1: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf33: +.size set1,.Lf33-set1 +.data +.align 4 +.type yy.35,@object +.size yy.35,4 +yy.35: +.long 2 +.globl set2 +.text +.align 16 +.type set2,@function +set2: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf36: +.size set2,.Lf36-set2 +.align 16 +.type goo,@function +goo: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf38: +.size goo,.Lf38-goo +.globl sss +.align 16 +.type sss,@function +sss: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf40: +.size sss,.Lf40-sss +.bss +.align 4 +.type xr.42,@object +.size xr.42,4 +.lcomm xr.42,4 +.globl rrr +.text +.align 16 +.type rrr,@function +rrr: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf43: +.size rrr,.Lf43-rrr +.globl setstatic +.align 16 +.type setstatic,@function +setstatic: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf45: +.size setstatic,.Lf45-setstatic +.globl gx1 +.align 16 +.type gx1,@function +gx1: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf47: +.size gx1,.Lf47-gx1 +.globl ff1 +.align 16 +.type ff1,@function +ff1: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf49: +.size ff1,.Lf49-ff1 +.globl gg1 +.align 16 +.type gg1,@function +gg1: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf51: +.size gg1,.Lf51-gg1 +.globl hh1 +.align 16 +.type hh1,@function +hh1: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf53: +.size hh1,.Lf53-hh1 +.globl cmp +.align 16 +.type cmp,@function +cmp: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf55: +.size cmp,.Lf55-cmp +.globl sort +.align 16 +.type sort,@function +sort: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf57: +.size sort,.Lf57-sort +.globl onearg +.align 16 +.type onearg,@function +onearg: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf65: +.size onearg,.Lf65-onearg +.bss +.globl ss4 +.align 4 +.type ss4,@object +.size ss4,4 +.comm ss4,4 +.align 4 +.type ss2,@object +.size ss2,4 +.lcomm ss2,4 +.align 4 +.type ss5,@object +.size ss5,4 +.lcomm ss5,4 +.globl ss3 +.align 4 +.type ss3,@object +.size ss3,4 +.comm ss3,4 +.align 4 +.type ss1,@object +.size ss1,4 +.lcomm ss1,4 +.align 4 +.type yy,@object +.size yy,4 +.lcomm yy,4 +.globl z +.align 4 +.type z,@object +.size z,4 +.comm z,4 +.globl y +.align 4 +.type y,@object +.size y,4 +.comm y,4 +.globl x +.align 4 +.type x,@object +.size x,4 +.comm x,4 +.globl b +.align 4 +.type b,@object +.size b,4 +.comm b,4 +.globl a +.align 4 +.type a,@object +.size a,4 +.comm a,4 +.text +.ident "LCC: 4.1" diff --git a/src/cmd/lccom/tst/x86-linux/incr.1bk b/src/cmd/lccom/tst/x86-linux/incr.1bk new file mode 100644 index 0000000..e69de29 diff --git a/src/cmd/lccom/tst/x86-linux/incr.2bk b/src/cmd/lccom/tst/x86-linux/incr.2bk new file mode 100644 index 0000000..d9ef13c --- /dev/null +++ b/src/cmd/lccom/tst/x86-linux/incr.2bk @@ -0,0 +1,9 @@ +tst/incr.c:1: warning: missing return value +tst/incr.c:6: warning: expression with no effect elided +tst/incr.c:6: warning: expression with no effect elided +tst/incr.c:11: warning: missing return value +tst/incr.c:16: warning: expression with no effect elided +tst/incr.c:16: warning: expression with no effect elided +tst/incr.c:21: warning: missing return value +tst/incr.c:30: warning: missing return value +tst/incr.c:39: warning: missing return value diff --git a/src/cmd/lccom/tst/x86-linux/incr.sbk b/src/cmd/lccom/tst/x86-linux/incr.sbk new file mode 100644 index 0000000..8484568 --- /dev/null +++ b/src/cmd/lccom/tst/x86-linux/incr.sbk @@ -0,0 +1,181 @@ +.globl main +.text +.align 16 +.type main,@function +main: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +mov $0,%eax +.LC1: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf2: +.size main,.Lf2-main +.globl memchar +.align 16 +.type memchar,@function +memchar: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +subl $8,%esp +movl -8(%ebp),%edi +leal 1(%edi),%esi +movl %esi,-8(%ebp) +movb (,%edi),%bl +movb %bl,-4(%ebp) +movl -8(%ebp),%edi +leal 1(%edi),%edi +movl %edi,-8(%ebp) +movb (,%edi),%bl +movb %bl,-4(%ebp) +movl -8(%ebp),%edi +leal -1(%edi),%esi +movl %esi,-8(%ebp) +movb (,%edi),%bl +movb %bl,-4(%ebp) +movl -8(%ebp),%edi +leal -1(%edi),%edi +movl %edi,-8(%ebp) +movb (,%edi),%bl +movb %bl,-4(%ebp) +mov $0,%eax +.LC3: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf4: +.size memchar,.Lf4-memchar +.globl memint +.align 16 +.type memint,@function +memint: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +subl $8,%esp +movl -8(%ebp),%edi +leal 4(%edi),%esi +movl %esi,-8(%ebp) +movl (,%edi),%edi +movl %edi,-4(%ebp) +movl -8(%ebp),%edi +leal 4(%edi),%edi +movl %edi,-8(%ebp) +movl (,%edi),%edi +movl %edi,-4(%ebp) +movl -8(%ebp),%edi +leal -4(%edi),%esi +movl %esi,-8(%ebp) +movl (,%edi),%edi +movl %edi,-4(%ebp) +movl -8(%ebp),%edi +leal -4(%edi),%edi +movl %edi,-8(%ebp) +movl (,%edi),%edi +movl %edi,-4(%ebp) +mov $0,%eax +.LC5: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf6: +.size memint,.Lf6-memint +.globl regchar +.align 16 +.type regchar,@function +regchar: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +subl $8,%esp +movl -8(%ebp),%edi +leal 1(%edi),%esi +movl %esi,-8(%ebp) +movb (,%edi),%bl +movb %bl,-4(%ebp) +movl -8(%ebp),%edi +leal 1(%edi),%edi +movl %edi,-8(%ebp) +movb (,%edi),%bl +movb %bl,-4(%ebp) +movl -8(%ebp),%edi +leal -1(%edi),%esi +movl %esi,-8(%ebp) +movb (,%edi),%bl +movb %bl,-4(%ebp) +movl -8(%ebp),%edi +leal -1(%edi),%edi +movl %edi,-8(%ebp) +movb (,%edi),%bl +movb %bl,-4(%ebp) +mov $0,%eax +.LC7: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf8: +.size regchar,.Lf8-regchar +.globl regint +.align 16 +.type regint,@function +regint: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +subl $8,%esp +movl -8(%ebp),%edi +leal 4(%edi),%esi +movl %esi,-8(%ebp) +movl (,%edi),%edi +movl %edi,-4(%ebp) +movl -8(%ebp),%edi +leal 4(%edi),%edi +movl %edi,-8(%ebp) +movl (,%edi),%edi +movl %edi,-4(%ebp) +movl -8(%ebp),%edi +leal -4(%edi),%esi +movl %esi,-8(%ebp) +movl (,%edi),%edi +movl %edi,-4(%ebp) +movl -8(%ebp),%edi +leal -4(%edi),%edi +movl %edi,-8(%ebp) +movl (,%edi),%edi +movl %edi,-4(%ebp) +mov $0,%eax +.LC9: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf10: +.size regint,.Lf10-regint +.ident "LCC: 4.1" diff --git a/src/cmd/lccom/tst/x86-linux/init.1bk b/src/cmd/lccom/tst/x86-linux/init.1bk new file mode 100644 index 0000000..77aff09 --- /dev/null +++ b/src/cmd/lccom/tst/x86-linux/init.1bk @@ -0,0 +1,16 @@ + 1 2 3 4 + 5 6 + 7 +if +for +else +while +1 2 3 if +4 5 0 for +6 7 8 else +9 10 11 while +1 2 3 if +4 5 0 for +6 7 8 else +9 10 11 while +0 0 0 diff --git a/src/cmd/lccom/tst/x86-linux/init.2bk b/src/cmd/lccom/tst/x86-linux/init.2bk new file mode 100644 index 0000000..aafe415 --- /dev/null +++ b/src/cmd/lccom/tst/x86-linux/init.2bk @@ -0,0 +1,3 @@ +tst/init.c:36: warning: missing return value +tst/init.c:49: warning: missing return value +tst/init.c:59: warning: missing return value diff --git a/src/cmd/lccom/tst/x86-linux/init.sbk b/src/cmd/lccom/tst/x86-linux/init.sbk new file mode 100644 index 0000000..dbe3695 --- /dev/null +++ b/src/cmd/lccom/tst/x86-linux/init.sbk @@ -0,0 +1,336 @@ +.data +.globl words +.align 4 +.type words,@object +words: +.long 1 +.long 2 +.long 3 +.byte 105 +.byte 102 +.byte 0 +.space 3 +.space 2 +.long 4 +.long 5 +.space 4 +.byte 102 +.byte 111 +.byte 114 +.space 3 +.space 2 +.long 6 +.long 7 +.long 8 +.byte 101 +.byte 108 +.byte 115 +.byte 101 +.byte 0 +.space 1 +.space 2 +.long 9 +.long 10 +.long 11 +.byte 119 +.byte 104 +.byte 105 +.byte 108 +.byte 101 +.space 1 +.space 2 +.long 0 +.space 8 +.space 8 +.size words,100 +.globl wordlist +.align 4 +.type wordlist,@object +.size wordlist,4 +wordlist: +.long words +.globl x +.align 4 +.type x,@object +x: +.long 1 +.long 2 +.long 3 +.long 4 +.long 0 +.long 5 +.long 6 +.space 12 +.long 7 +.space 16 +.size x,60 +.globl y +.align 4 +.type y,@object +y: +.long x +.long x+20 +.long x+40 +.long 0 +.size y,16 +.globl main +.text +.align 16 +.type main,@function +main: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +subl $8,%esp +movl $0,-8(%ebp) +jmp .LC8 +.LC5: +movl $0,-4(%ebp) +jmp .LC12 +.LC9: +movl -4(%ebp),%edi +movl -8(%ebp),%esi +movl y(,%esi,4),%esi +pushl (%esi,%edi,4) +pushl $.LC13 +call printf +addl $8,%esp +.LC10: +incl -4(%ebp) +.LC12: +movl -4(%ebp),%edi +movl -8(%ebp),%esi +movl y(,%esi,4),%esi +cmpl $0,(%esi,%edi,4) +jne .LC9 +pushl $.LC14 +call printf +addl $4,%esp +.LC6: +incl -8(%ebp) +.LC8: +movl -8(%ebp),%edi +movl y(,%edi,4),%edi +cmpl $0,%edi +jne .LC5 +call f +pushl wordlist +call g +addl $4,%esp +mov $0,%eax +.LC4: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf15: +.size main,.Lf15-main +.data +.align 4 +.type keywords.17,@object +keywords.17: +.long .LC18 +.long .LC19 +.long .LC20 +.long .LC21 +.long 0 +.size keywords.17,20 +.globl f +.text +.align 16 +.type f,@function +f: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +subl $4,%esp +leal keywords.17,%edi +movl %edi,-4(%ebp) +jmp .LC25 +.LC22: +movl -4(%ebp),%edi +pushl (,%edi) +pushl $.LC26 +call printf +addl $8,%esp +.LC23: +movl -4(%ebp),%edi +leal 4(%edi),%edi +movl %edi,-4(%ebp) +.LC25: +movl -4(%ebp),%edi +movl (,%edi),%edi +cmpl $0,%edi +jne .LC22 +mov $0,%eax +.LC16: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf27: +.size f,.Lf27-f +.globl g +.align 16 +.type g,@function +g: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +subl $4,%esp +jmp .LC32 +.LC29: +movl $0,-4(%ebp) +jmp .LC36 +.LC33: +movl -4(%ebp),%edi +movl 20(%ebp),%esi +pushl (%esi,%edi,4) +pushl $.LC37 +call printf +addl $8,%esp +.LC34: +incl -4(%ebp) +.LC36: +movl -4(%ebp),%edi +cmpl $3,%edi +jb .LC33 +movl 20(%ebp),%edi +leal 12(%edi),%edi +pushl %edi +pushl $.LC26 +call printf +addl $8,%esp +.LC30: +movl 20(%ebp),%edi +leal 20(%edi),%edi +movl %edi,20(%ebp) +.LC32: +movl 20(%ebp),%edi +cmpl $0,(,%edi) +jne .LC29 +call h +mov $0,%eax +.LC28: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf38: +.size g,.Lf38-g +.globl h +.align 16 +.type h,@function +h: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +subl $4,%esp +movl $0,-4(%ebp) +jmp .LC43 +.LC40: +imul $20,-4(%ebp),%edi +leal words+12(%edi),%esi +pushl %esi +pushl words+8(%edi) +pushl words+4(%edi) +pushl words(%edi) +pushl $.LC44 +call printf +addl $20,%esp +.LC41: +incl -4(%ebp) +.LC43: +movl -4(%ebp),%edi +cmpl $5,%edi +jb .LC40 +mov $0,%eax +.LC39: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf48: +.size h,.Lf48-h +.data +.align 1 +.LC44: +.byte 37 +.byte 100 +.byte 32 +.byte 37 +.byte 100 +.byte 32 +.byte 37 +.byte 100 +.byte 32 +.byte 37 +.byte 115 +.byte 10 +.byte 0 +.align 1 +.LC37: +.byte 37 +.byte 100 +.byte 32 +.byte 0 +.align 1 +.LC26: +.byte 37 +.byte 115 +.byte 10 +.byte 0 +.align 1 +.LC21: +.byte 119 +.byte 104 +.byte 105 +.byte 108 +.byte 101 +.byte 0 +.align 1 +.LC20: +.byte 101 +.byte 108 +.byte 115 +.byte 101 +.byte 0 +.align 1 +.LC19: +.byte 102 +.byte 111 +.byte 114 +.byte 0 +.align 1 +.LC18: +.byte 105 +.byte 102 +.byte 0 +.align 1 +.LC14: +.byte 10 +.byte 0 +.align 1 +.LC13: +.byte 32 +.byte 37 +.byte 100 +.byte 0 +.text +.ident "LCC: 4.1" diff --git a/src/cmd/lccom/tst/x86-linux/limits.1bk b/src/cmd/lccom/tst/x86-linux/limits.1bk new file mode 100644 index 0000000..9beee8c --- /dev/null +++ b/src/cmd/lccom/tst/x86-linux/limits.1bk @@ -0,0 +1,14 @@ +UCHAR_MAX: 000000ff=255 +USHRT_MAX: 0000ffff=65535 +UINT_MAX: ffffffff=-1 +ULONG_MAX: ffffffff=-1 +CHAR_MAX: 0000007f=127 +SCHAR_MAX: 0000007f=127 +SHRT_MAX: 00007fff=32767 +INT_MAX: 7fffffff=2147483647 +LONG_MAX: 7fffffff=2147483647 +CHAR_MIN: ffffff80=-128 +SCHAR_MIN: ffffff80=-128 +SHRT_MIN: ffff8000=-32768 +INT_MIN: 80000000=-2147483648 +LONG_MIN: 80000000=-2147483648 diff --git a/src/cmd/lccom/tst/x86-linux/limits.2bk b/src/cmd/lccom/tst/x86-linux/limits.2bk new file mode 100644 index 0000000..e69de29 diff --git a/src/cmd/lccom/tst/x86-linux/limits.h b/src/cmd/lccom/tst/x86-linux/limits.h new file mode 100644 index 0000000..913bb97 --- /dev/null +++ b/src/cmd/lccom/tst/x86-linux/limits.h @@ -0,0 +1,30 @@ +#ifndef __LIMITS +#define __LIMITS + +#define CHAR_BIT 8 +#define MB_LEN_MAX 1 + +#define UCHAR_MAX 0xff +#define USHRT_MAX 0xffff +#define UINT_MAX (~0U) +#define ULONG_MAX (~0UL) + +#define SCHAR_MAX 0x7f +#define SHRT_MAX 0x7fff +#define INT_MAX 0x7fffffff +#define LONG_MAX 0x7fffffffL + +#define SCHAR_MIN (-SCHAR_MAX-1) +#define SHRT_MIN (-SHRT_MAX-1) +#define INT_MIN (-INT_MAX-1) +#define LONG_MIN (-LONG_MAX-1) + +#ifdef __CHAR_UNSIGNED__ +#define CHAR_MAX UCHAR_MAX +#define CHAR_MIN 0 +#else +#define CHAR_MAX SCHAR_MAX +#define CHAR_MIN SCHAR_MIN +#endif + +#endif /* __LIMITS */ diff --git a/src/cmd/lccom/tst/x86-linux/limits.sbk b/src/cmd/lccom/tst/x86-linux/limits.sbk new file mode 100644 index 0000000..4bf634e --- /dev/null +++ b/src/cmd/lccom/tst/x86-linux/limits.sbk @@ -0,0 +1,396 @@ +.globl main +.text +.align 16 +.type main,@function +main: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +pushl $255 +pushl $255 +pushl $.LC2 +call printf +addl $12,%esp +pushl $65535 +pushl $65535 +pushl $.LC3 +call printf +addl $12,%esp +pushl $0xffffffff +pushl $0xffffffff +pushl $.LC4 +call printf +addl $12,%esp +pushl $0xffffffff +pushl $0xffffffff +pushl $.LC5 +call printf +addl $12,%esp +pushl $127 +pushl $127 +pushl $.LC6 +call printf +addl $12,%esp +pushl $127 +pushl $127 +pushl $.LC7 +call printf +addl $12,%esp +pushl $32767 +pushl $32767 +pushl $.LC8 +call printf +addl $12,%esp +pushl $2147483647 +pushl $2147483647 +pushl $.LC9 +call printf +addl $12,%esp +pushl $2147483647 +pushl $2147483647 +pushl $.LC10 +call printf +addl $12,%esp +pushl $-128 +pushl $-128 +pushl $.LC11 +call printf +addl $12,%esp +pushl $-128 +pushl $-128 +pushl $.LC12 +call printf +addl $12,%esp +pushl $-32768 +pushl $-32768 +pushl $.LC13 +call printf +addl $12,%esp +pushl $-2147483648 +pushl $-2147483648 +pushl $.LC14 +call printf +addl $12,%esp +pushl $-2147483648 +pushl $-2147483648 +pushl $.LC15 +call printf +addl $12,%esp +mov $0,%eax +.LC1: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf16: +.size main,.Lf16-main +.data +.align 1 +.LC15: +.byte 76 +.byte 79 +.byte 78 +.byte 71 +.byte 95 +.byte 77 +.byte 73 +.byte 78 +.byte 58 +.byte 9 +.byte 37 +.byte 48 +.byte 56 +.byte 108 +.byte 120 +.byte 61 +.byte 37 +.byte 108 +.byte 100 +.byte 10 +.byte 0 +.align 1 +.LC14: +.byte 73 +.byte 78 +.byte 84 +.byte 95 +.byte 77 +.byte 73 +.byte 78 +.byte 58 +.byte 9 +.byte 37 +.byte 48 +.byte 56 +.byte 120 +.byte 61 +.byte 37 +.byte 100 +.byte 10 +.byte 0 +.align 1 +.LC13: +.byte 83 +.byte 72 +.byte 82 +.byte 84 +.byte 95 +.byte 77 +.byte 73 +.byte 78 +.byte 58 +.byte 9 +.byte 37 +.byte 48 +.byte 56 +.byte 120 +.byte 61 +.byte 37 +.byte 100 +.byte 10 +.byte 0 +.align 1 +.LC12: +.byte 83 +.byte 67 +.byte 72 +.byte 65 +.byte 82 +.byte 95 +.byte 77 +.byte 73 +.byte 78 +.byte 58 +.byte 9 +.byte 37 +.byte 48 +.byte 56 +.byte 120 +.byte 61 +.byte 37 +.byte 100 +.byte 10 +.byte 0 +.align 1 +.LC11: +.byte 67 +.byte 72 +.byte 65 +.byte 82 +.byte 95 +.byte 77 +.byte 73 +.byte 78 +.byte 58 +.byte 9 +.byte 37 +.byte 48 +.byte 56 +.byte 120 +.byte 61 +.byte 37 +.byte 100 +.byte 10 +.byte 0 +.align 1 +.LC10: +.byte 76 +.byte 79 +.byte 78 +.byte 71 +.byte 95 +.byte 77 +.byte 65 +.byte 88 +.byte 58 +.byte 9 +.byte 37 +.byte 48 +.byte 56 +.byte 108 +.byte 120 +.byte 61 +.byte 37 +.byte 108 +.byte 100 +.byte 10 +.byte 0 +.align 1 +.LC9: +.byte 73 +.byte 78 +.byte 84 +.byte 95 +.byte 77 +.byte 65 +.byte 88 +.byte 58 +.byte 9 +.byte 37 +.byte 48 +.byte 56 +.byte 120 +.byte 61 +.byte 37 +.byte 100 +.byte 10 +.byte 0 +.align 1 +.LC8: +.byte 83 +.byte 72 +.byte 82 +.byte 84 +.byte 95 +.byte 77 +.byte 65 +.byte 88 +.byte 58 +.byte 9 +.byte 37 +.byte 48 +.byte 56 +.byte 120 +.byte 61 +.byte 37 +.byte 100 +.byte 10 +.byte 0 +.align 1 +.LC7: +.byte 83 +.byte 67 +.byte 72 +.byte 65 +.byte 82 +.byte 95 +.byte 77 +.byte 65 +.byte 88 +.byte 58 +.byte 9 +.byte 37 +.byte 48 +.byte 56 +.byte 120 +.byte 61 +.byte 37 +.byte 100 +.byte 10 +.byte 0 +.align 1 +.LC6: +.byte 67 +.byte 72 +.byte 65 +.byte 82 +.byte 95 +.byte 77 +.byte 65 +.byte 88 +.byte 58 +.byte 9 +.byte 37 +.byte 48 +.byte 56 +.byte 120 +.byte 61 +.byte 37 +.byte 100 +.byte 10 +.byte 0 +.align 1 +.LC5: +.byte 85 +.byte 76 +.byte 79 +.byte 78 +.byte 71 +.byte 95 +.byte 77 +.byte 65 +.byte 88 +.byte 58 +.byte 9 +.byte 37 +.byte 48 +.byte 56 +.byte 108 +.byte 120 +.byte 61 +.byte 37 +.byte 108 +.byte 100 +.byte 10 +.byte 0 +.align 1 +.LC4: +.byte 85 +.byte 73 +.byte 78 +.byte 84 +.byte 95 +.byte 77 +.byte 65 +.byte 88 +.byte 58 +.byte 9 +.byte 37 +.byte 48 +.byte 56 +.byte 120 +.byte 61 +.byte 37 +.byte 100 +.byte 10 +.byte 0 +.align 1 +.LC3: +.byte 85 +.byte 83 +.byte 72 +.byte 82 +.byte 84 +.byte 95 +.byte 77 +.byte 65 +.byte 88 +.byte 58 +.byte 9 +.byte 37 +.byte 48 +.byte 56 +.byte 120 +.byte 61 +.byte 37 +.byte 100 +.byte 10 +.byte 0 +.align 1 +.LC2: +.byte 85 +.byte 67 +.byte 72 +.byte 65 +.byte 82 +.byte 95 +.byte 77 +.byte 65 +.byte 88 +.byte 58 +.byte 9 +.byte 37 +.byte 48 +.byte 56 +.byte 120 +.byte 61 +.byte 37 +.byte 100 +.byte 10 +.byte 0 +.text +.ident "LCC: 4.1" diff --git a/src/cmd/lccom/tst/x86-linux/math.h b/src/cmd/lccom/tst/x86-linux/math.h new file mode 100644 index 0000000..d2a31f4 --- /dev/null +++ b/src/cmd/lccom/tst/x86-linux/math.h @@ -0,0 +1,29 @@ +#ifndef __MATH +#define __MATH + +#define HUGE_VAL 1.79769313486231570000e+308 + +extern double acos(double); +extern double asin(double); +extern double atan(double); +extern double atan2(double, double); +extern double cos(double); +extern double sin(double); +extern double tan(double); +extern double cosh(double); +extern double sinh(double); +extern double tanh(double); +extern double exp(double); +extern double frexp(double, int *); +extern double ldexp(double, int); +extern double log(double); +extern double log10(double); +extern double modf(double, double *); +extern double pow(double, double); +extern double sqrt(double); +extern double ceil(double); +extern double fabs(double); +extern double floor(double); +extern double fmod(double, double); + +#endif /* __MATH */ diff --git a/src/cmd/lccom/tst/x86-linux/paranoia.1bk b/src/cmd/lccom/tst/x86-linux/paranoia.1bk new file mode 100644 index 0000000..6639dd3 --- /dev/null +++ b/src/cmd/lccom/tst/x86-linux/paranoia.1bk @@ -0,0 +1,183 @@ +Lest this program stop prematurely, i.e. before displaying + + `END OF TEST', + +try to persuade the computer NOT to terminate execution when an +error like Over/Underflow or Division by Zero occurs, but rather +to persevere with a surrogate value after, perhaps, displaying some +warning. If persuasion avails naught, don't despair but run this +program anyway to see how many milestones it passes, and then +amend it to make further progress. + +Answer questions with Y, y, N or n (unless otherwise indicated). + + +Diagnosis resumes after milestone Number 0 Page: 1 + +Users are invited to help debug and augment this program so it will +cope with unanticipated and newly uncovered arithmetic pathologies. + +Please send suggestions and interesting results to + Richard Karpinski + Computer Center U-76 + University of California + San Francisco, CA 94143-0704, USA + +In doing so, please include the following information: + Precision: double; + Version: 10 February 1989; + Computer: + + Compiler: + + Optimization level: + + Other relevant compiler options: + +Diagnosis resumes after milestone Number 1 Page: 2 + +Running this program should reveal these characteristics: + Radix = 1, 2, 4, 8, 10, 16, 100, 256 ... + Precision = number of significant digits carried. + U2 = Radix/Radix^Precision = One Ulp + (OneUlpnit in the Last Place) of 1.000xxx . + U1 = 1/Radix^Precision = One Ulp of numbers a little less than 1.0 . + Adequacy of guard digits for Mult., Div. and Subt. + Whether arithmetic is chopped, correctly rounded, or something else + for Mult., Div., Add/Subt. and Sqrt. + Whether a Sticky Bit used correctly for rounding. + UnderflowThreshold = an underflow threshold. + E0 and PseudoZero tell whether underflow is abrupt, gradual, or fuzzy. + V = an overflow threshold, roughly. + V0 tells, roughly, whether Infinity is represented. + Comparisions are checked for consistency with subtraction + and for contamination with pseudo-zeros. + Sqrt is tested. Y^X is not tested. + Extra-precise subexpressions are revealed but NOT YET tested. + Decimal-Binary conversion is NOT YET tested for accuracy. + +Diagnosis resumes after milestone Number 2 Page: 3 + +The program attempts to discriminate among + FLAWs, like lack of a sticky bit, + Serious DEFECTs, like lack of a guard digit, and + FAILUREs, like 2+2 == 5 . +Failures may confound subsequent diagnoses. + +The diagnostic capabilities of this program go beyond an earlier +program called `MACHAR', which can be found at the end of the +book `Software Manual for the Elementary Functions' (1980) by +W. J. Cody and W. Waite. Although both programs try to discover +the Radix, Precision and range (over/underflow thresholds) +of the arithmetic, this program tries to cope with a wider variety +of pathologies, and to say how well the arithmetic is implemented. + +The program is based upon a conventional radix representation for +floating-point numbers, but also allows logarithmic encoding +as used by certain early WANG machines. + +BASIC version of this program (C) 1983 by Prof. W. M. Kahan; +see source comments for more history. + +Diagnosis resumes after milestone Number 3 Page: 4 + +Program is now RUNNING tests on small integers: +-1, 0, 1/2, 1, 2, 3, 4, 5, 9, 27, 32 & 240 are O.K. + +Searching for Radix and Precision. +Radix = 2.000000 . +Closest relative separation found is U1 = 1.1102230e-16 . + +Recalculating radix and precision + confirms closest relative separation U1 . +Radix confirmed. +The number of significant digits of the Radix is 53.000000 . +Some subexpressions appear to be calculated extra +precisely with about 11 extra B-digits, i.e. +roughly 3.31133 extra significant decimals. +That feature is not tested further by this program. + +Diagnosis resumes after milestone Number 30 Page: 5 + +Subtraction appears to be normalized, as it should be. +Checking for guard digit in *, /, and -. + *, /, and - appear to have guard digits, as they should. + +Diagnosis resumes after milestone Number 40 Page: 6 + +Checking rounding on multiply, divide and add/subtract. +* is neither chopped nor correctly rounded. +/ is neither chopped nor correctly rounded. +Addition/Subtraction neither rounds nor chops. +Sticky bit used incorrectly or not at all. +FLAW: lack(s) of guard digits or failure(s) to correctly round or chop +(noted above) count as one flaw in the final tally below. + +Does Multiplication commute? Testing on 20 random pairs. + No failures found in 20 integer pairs. + +Running test of square root(x). +Testing if sqrt(X * X) == X for 20 Integers X. +Test for sqrt monotonicity. +sqrt has passed a test for Monotonicity. +Testing whether sqrt is rounded or chopped. +Square root is neither chopped nor correctly rounded. +Observed errors run from -5.0000000e-01 to 5.0000000e-01 ulps. + +Diagnosis resumes after milestone Number 90 Page: 7 + +Testing powers Z^i for small Integers Z and i. +... no discrepancis found. + +Seeking Underflow thresholds UfThold and E0. +Smallest strictly positive number found is E0 = 4.94066e-324 . +Since comparison denies Z = 0, evaluating (Z + Z) / Z should be safe. +What the machine gets for (Z + Z) / Z is 2.00000000000000000e+00 . +This is O.K., provided Over/Underflow has NOT just been signaled. +Underflow is gradual; it incurs Absolute Error = +(roundoff in UfThold) < E0. +The Underflow threshold is 2.22507385850720188e-308, below which +calculation may suffer larger Relative error than merely roundoff. +Since underflow occurs below the threshold +UfThold = (2.00000000000000000e+00) ^ (-1.02200000000000000e+03) +only underflow should afflict the expression + (2.00000000000000000e+00) ^ (-1.02200000000000000e+03); +actually calculating yields: 0.00000000000000000e+00 . +This computed value is O.K. + +Testing X^((X + 1) / (X - 1)) vs. exp(2) = 7.38905609893065218e+00 as X -> 1. +Accuracy seems adequate. +Testing powers Z^Q at four nearly extreme values. + ... no discrepancies found. + + +Diagnosis resumes after milestone Number 160 Page: 8 + +Searching for Overflow threshold: +This may generate an error. +Can `Z = -Y' overflow? +Trying it on Y = -inf . +Seems O.K. +Overflow threshold is V = 1.79769313486231571e+308 . +Overflow saturates at V0 = inf . +No Overflow should be signaled for V * 1 = 1.79769313486231571e+308 + nor for V / 1 = 1.79769313486231571e+308 . +Any overflow signal separating this * from the one +above is a DEFECT. + + +Diagnosis resumes after milestone Number 190 Page: 9 + + +What message and/or values does Division by Zero produce? + Trying to compute 1 / 0 produces ... inf . + + Trying to compute 0 / 0 produces ... nan . + +Diagnosis resumes after milestone Number 220 Page: 10 + + +The number of FLAWs discovered = 1. + +The arithmetic diagnosed seems Satisfactory though flawed. +END OF TEST. diff --git a/src/cmd/lccom/tst/x86-linux/paranoia.2bk b/src/cmd/lccom/tst/x86-linux/paranoia.2bk new file mode 100644 index 0000000..2718174 --- /dev/null +++ b/src/cmd/lccom/tst/x86-linux/paranoia.2bk @@ -0,0 +1,16 @@ +tst/paranoia.c:1867: warning: missing return value +tst/paranoia.c:1874: warning: missing return value +tst/paranoia.c:1884: warning: missing return value +tst/paranoia.c:1924: warning: missing return value +tst/paranoia.c:1939: warning: missing return value +tst/paranoia.c:1956: warning: missing return value +tst/paranoia.c:1975: warning: missing return value +tst/paranoia.c:1988: warning: missing return value +tst/paranoia.c:1995: warning: missing return value +tst/paranoia.c:2055: warning: missing return value +tst/paranoia.c:2062: warning: missing return value +tst/paranoia.c:2070: warning: missing return value +tst/paranoia.c:2087: warning: missing return value +tst/paranoia.c:2115: warning: missing return value +tst/paranoia.c:2144: warning: missing return value +tst/paranoia.c:2173: warning: missing return value diff --git a/src/cmd/lccom/tst/x86-linux/paranoia.sbk b/src/cmd/lccom/tst/x86-linux/paranoia.sbk new file mode 100644 index 0000000..285ef4f --- /dev/null +++ b/src/cmd/lccom/tst/x86-linux/paranoia.sbk @@ -0,0 +1,20618 @@ +.data +.globl Zero +.align 4 +.type Zero,@object +.size Zero,8 +Zero: +.long 0 +.long 0 +.globl Half +.align 4 +.type Half,@object +.size Half,8 +Half: +.long 0 +.long 1071644672 +.globl One +.align 4 +.type One,@object +.size One,8 +One: +.long 0 +.long 1072693248 +.globl Two +.align 4 +.type Two,@object +.size Two,8 +Two: +.long 0 +.long 1073741824 +.globl Three +.align 4 +.type Three,@object +.size Three,8 +Three: +.long 0 +.long 1074266112 +.globl Four +.align 4 +.type Four,@object +.size Four,8 +Four: +.long 0 +.long 1074790400 +.globl Five +.align 4 +.type Five,@object +.size Five,8 +Five: +.long 0 +.long 1075052544 +.globl Eight +.align 4 +.type Eight,@object +.size Eight,8 +Eight: +.long 0 +.long 1075838976 +.globl Nine +.align 4 +.type Nine,@object +.size Nine,8 +Nine: +.long 0 +.long 1075970048 +.globl TwentySeven +.align 4 +.type TwentySeven,@object +.size TwentySeven,8 +TwentySeven: +.long 0 +.long 1077608448 +.globl ThirtyTwo +.align 4 +.type ThirtyTwo,@object +.size ThirtyTwo,8 +ThirtyTwo: +.long 0 +.long 1077936128 +.globl TwoForty +.align 4 +.type TwoForty,@object +.size TwoForty,8 +TwoForty: +.long 0 +.long 1080950784 +.globl MinusOne +.align 4 +.type MinusOne,@object +.size MinusOne,8 +MinusOne: +.long 0 +.long -1074790400 +.globl OneAndHalf +.align 4 +.type OneAndHalf,@object +.size OneAndHalf,8 +OneAndHalf: +.long 0 +.long 1073217536 +.globl NoTrials +.align 4 +.type NoTrials,@object +.size NoTrials,4 +NoTrials: +.long 20 +.globl sigfpe +.text +.align 16 +.type sigfpe,@function +sigfpe: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +incl fpecount +pushl $.LC2 +call printf +addl $4,%esp +pushl $_iob+32 +call fflush +addl $4,%esp +movl sigsave,%edi +cmpl $0,%edi +je .LC4 +pushl sigsave +pushl $8 +call signal +addl $8,%esp +movl $0,sigsave +pushl $1 +pushl $ovfl_buf +call longjmp +addl $8,%esp +.LC4: +call abort +.LC1: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf6: +.size sigfpe,.Lf6-sigfpe +.data +.align 4 +.type msg.758,@object +msg.758: +.long .LC759 +.long .LC760 +.long .LC761 +.long .LC762 +.size msg.758,16 +.globl main +.text +.align 16 +.type main,@function +main: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +subl $1684,%esp +fldl .LC8 +fstpl Zero +fldl .LC9 +fstpl One +fldl One +fstpl -8(%ebp) +fldl -8(%ebp) +faddl -8(%ebp) +fstpl Two +fldl Two +fstpl -16(%ebp) +fldl -16(%ebp) +faddl -8(%ebp) +fstpl Three +fldl Three +fstpl -24(%ebp) +fldl -24(%ebp) +faddl -8(%ebp) +fstpl Four +fldl Four +fstpl -32(%ebp) +fldl -32(%ebp) +faddl -8(%ebp) +fstpl Five +fldl -32(%ebp) +faddl -32(%ebp) +fstpl Eight +fldl -24(%ebp) +fmull -24(%ebp) +fstpl Nine +fldl Nine +fmull -24(%ebp) +fstpl TwentySeven +fldl -32(%ebp) +fmull Eight +fstpl ThirtyTwo +fldl -32(%ebp) +fmull Five +fmull -24(%ebp) +fmull -32(%ebp) +fstpl TwoForty +fldl -8(%ebp) +fchs +fstpl MinusOne +fldl -8(%ebp) +fdivl -16(%ebp) +fstpl Half +fldl -8(%ebp) +faddl Half +fstpl OneAndHalf +movl $0,ErrCnt +movl $0,ErrCnt+4 +movl $0,ErrCnt+8 +movl $0,ErrCnt+12 +movl $1,PageNo +movl $0,Milestone +pushl $sigfpe +pushl $8 +call signal +addl $8,%esp +call Instructions +call Pause +call Heading +call Pause +call Characteristics +call Pause +call History +call Pause +movl $7,Milestone +pushl $.LC13 +call printf +addl $4,%esp +pushl $.LC15 +fldl Zero +faddl Zero +fldl Zero +fcompp +fstsw %ax +sahf +jp .LC16 +jne .LC16 +fldl One +fsubl One +fldl Zero +fcompp +fstsw %ax +sahf +jp .LC16 +jne .LC16 +fldl Zero +fcompl One +fstsw %ax +sahf +jp .LC16 +jae .LC16 +fldl One +faddl One +fldl Two +fcompp +fstsw %ax +sahf +jp .LC16 +jne .LC16 +movl $1,-36(%ebp) +jmp .LC17 +.LC16: +movl $0,-36(%ebp) +.LC17: +pushl -36(%ebp) +pushl $0 +call TstCond +addl $12,%esp +fldl Zero +fchs +fstpl Z +fldl .LC8 +fcompl Z +fstsw %ax +sahf +jp 1f +je .LC18 +1: +incl ErrCnt +pushl $.LC20 +call printf +addl $4,%esp +fldl .LC21 +fstpl U1 +fldl .LC9 +fstpl Radix +call TstPtUf +.LC18: +pushl $.LC23 +fldl Two +faddl One +fcompl Three +fstsw %ax +sahf +jp .LC24 +jne .LC24 +fldl Three +faddl One +fcompl Four +fstsw %ax +sahf +jp .LC24 +jne .LC24 +fldl Four +fldl Two +fldl Two +fchs +fmulp %st,%st(1) +faddp %st,%st(1) +fldl Zero +fcompp +fstsw %ax +sahf +jp .LC24 +jne .LC24 +fldl Four +fsubl Three +fsubl One +fldl Zero +fcompp +fstsw %ax +sahf +jp .LC24 +jne .LC24 +movl $1,-56(%ebp) +jmp .LC25 +.LC24: +movl $0,-56(%ebp) +.LC25: +pushl -56(%ebp) +pushl $0 +call TstCond +addl $12,%esp +fldl .LC8 +fsubl One +fcompl MinusOne +fstsw %ax +sahf +jp .LC28 +jne .LC28 +fldl MinusOne +faddl One +fldl Zero +fcompp +fstsw %ax +sahf +jp .LC28 +jne .LC28 +fldl One +faddl MinusOne +fldl Zero +fcompp +fstsw %ax +sahf +jp .LC28 +jne .LC28 +fldl One +subl $8,%esp +fstpl (%esp) +call fabs +addl $8,%esp +fstpl -132(%ebp) +fldl MinusOne +faddl -132(%ebp) +fldl Zero +fcompp +fstsw %ax +sahf +jp .LC28 +jne .LC28 +fldl MinusOne +fldl MinusOne +fmull MinusOne +faddp %st,%st(1) +fldl Zero +fcompp +fstsw %ax +sahf +jp .LC28 +jne .LC28 +movl $1,-100(%ebp) +jmp .LC29 +.LC28: +movl $0,-100(%ebp) +.LC29: +pushl $.LC27 +pushl -100(%ebp) +pushl $0 +call TstCond +addl $12,%esp +pushl $.LC31 +fldl Half +faddl MinusOne +faddl Half +fldl Zero +fcompp +fstsw %ax +sahf +jp .LC32 +jne .LC32 +movl $1,-152(%ebp) +jmp .LC33 +.LC32: +movl $0,-152(%ebp) +.LC33: +pushl -152(%ebp) +pushl $0 +call TstCond +addl $12,%esp +movl $10,Milestone +pushl $.LC35 +fldl Three +fmull Three +fcompl Nine +fstsw %ax +sahf +jp .LC36 +jne .LC36 +fldl Nine +fmull Three +fcompl TwentySeven +fstsw %ax +sahf +jp .LC36 +jne .LC36 +fldl Four +faddl Four +fcompl Eight +fstsw %ax +sahf +jp .LC36 +jne .LC36 +fldl Eight +fmull Four +fcompl ThirtyTwo +fstsw %ax +sahf +jp .LC36 +jne .LC36 +fldl ThirtyTwo +fsubl TwentySeven +fsubl Four +fsubl One +fldl Zero +fcompp +fstsw %ax +sahf +jp .LC36 +jne .LC36 +movl $1,-164(%ebp) +jmp .LC37 +.LC36: +movl $0,-164(%ebp) +.LC37: +pushl -164(%ebp) +pushl $0 +call TstCond +addl $12,%esp +pushl $.LC39 +fldl Four +faddl One +fcompl Five +fstsw %ax +sahf +jp .LC40 +jne .LC40 +fldl Four +fmull Five +fmull Three +fmull Four +fcompl TwoForty +fstsw %ax +sahf +jp .LC40 +jne .LC40 +fldl TwoForty +fdivl Three +fldl Four +fmull Four +fmull Five +fsubrp %st,%st(1) +fldl Zero +fcompp +fstsw %ax +sahf +jp .LC40 +jne .LC40 +fldl TwoForty +fdivl Four +fldl Five +fmull Three +fmull Four +fsubrp %st,%st(1) +fldl Zero +fcompp +fstsw %ax +sahf +jp .LC40 +jne .LC40 +fldl TwoForty +fdivl Five +fldl Four +fmull Three +fmull Four +fsubrp %st,%st(1) +fldl Zero +fcompp +fstsw %ax +sahf +jp .LC40 +jne .LC40 +movl $1,-216(%ebp) +jmp .LC41 +.LC40: +movl $0,-216(%ebp) +.LC41: +pushl -216(%ebp) +pushl $0 +call TstCond +addl $12,%esp +cmpl $0,ErrCnt +jne .LC42 +pushl $.LC44 +call printf +addl $4,%esp +pushl $.LC45 +call printf +addl $4,%esp +.LC42: +pushl $.LC46 +call printf +addl $4,%esp +fldl One +fstpl W +.LC47: +fldl W +fstpl -264(%ebp) +fldl -264(%ebp) +faddl -264(%ebp) +fstpl W +fldl W +fstpl -272(%ebp) +fldl -272(%ebp) +faddl One +fstpl Y +fldl Y +fsubl -272(%ebp) +fstpl Z +fldl Z +fsubl One +fstpl Y +.LC48: +fldl Y +subl $8,%esp +fstpl (%esp) +call fabs +addl $8,%esp +fstpl -264(%ebp) +fldl MinusOne +faddl -264(%ebp) +fldl Zero +fcompp +fstsw %ax +sahf +jp .LC47 +ja .LC47 +fldl Zero +fstpl Precision +fldl One +fstpl Y +.LC50: +fldl Y +fstpl -280(%ebp) +fldl W +faddl -280(%ebp) +fstpl Radix +fldl -280(%ebp) +faddl -280(%ebp) +fstpl Y +fldl Radix +fsubl W +fstpl Radix +.LC51: +fldl Zero +fcompl Radix +fstsw %ax +sahf +jp 1f +je .LC50 +1: +fldl Two +fcompl Radix +fstsw %ax +sahf +jp .LC53 +jbe .LC53 +fldl One +fstpl Radix +.LC53: +fldl Radix +subl $8,%esp +fstpl (%esp) +pushl $.LC55 +call printf +addl $12,%esp +fldl .LC9 +fcompl Radix +fstsw %ax +sahf +jp 1f +je .LC56 +1: +fldl One +fstpl W +.LC58: +fldl Precision +faddl One +fstpl Precision +fldl W +fmull Radix +fstpl W +fldl W +faddl One +fstpl Y +.LC59: +fldl Y +fsubl W +fldl One +fcompp +fstsw %ax +sahf +jp 1f +je .LC58 +1: +.LC56: +fldl One +fdivl W +fstpl U1 +fldl U1 +fstpl -272(%ebp) +fldl Radix +fmull -272(%ebp) +fstpl U2 +fldl -272(%ebp) +subl $8,%esp +fstpl (%esp) +pushl $.LC61 +call printf +addl $12,%esp +pushl $.LC62 +call printf +addl $4,%esp +fldl Radix +fstpl E0 +fldl U1 +fstpl E1 +fldl U2 +fstpl E9 +fldl Precision +fstpl E3 +fldl Four +fdivl Three +fstpl X +fldl X +fsubl One +fstpl Third +fldl Third +fstpl -280(%ebp) +fldl Half +fsubl -280(%ebp) +fstpl F6 +fldl F6 +fstpl -288(%ebp) +fldl -288(%ebp) +faddl -288(%ebp) +fstpl X +fldl X +fsubl -280(%ebp) +subl $8,%esp +fstpl (%esp) +call fabs +addl $8,%esp +fstpl -296(%ebp) +fldl -296(%ebp) +fstpl X +fldl U2 +fcompl X +fstsw %ax +sahf +jp .LC63 +jbe .LC63 +fldl U2 +fstpl X +.LC63: +.LC65: +fldl X +fstpl U2 +fldl U2 +fstpl -304(%ebp) +fldl Half +fmull -304(%ebp) +fldl ThirtyTwo +fmull -304(%ebp) +fmull -304(%ebp) +faddp %st,%st(1) +fstpl Y +fldl One +faddl Y +fstpl Y +fldl Y +fsubl One +fstpl X +.LC66: +fldl X +fcompl U2 +fstsw %ax +sahf +jp .LC68 +jae .LC68 +fldl Zero +fcompl X +fstsw %ax +sahf +jp .LC65 +jb .LC65 +.LC68: +fldl Two +fdivl Three +fstpl X +fldl X +fsubl Half +fstpl F6 +fldl F6 +fstpl -320(%ebp) +fldl -320(%ebp) +faddl -320(%ebp) +fstpl Third +fldl Third +fsubl Half +fstpl X +fldl X +faddl -320(%ebp) +subl $8,%esp +fstpl (%esp) +call fabs +addl $8,%esp +fstpl -328(%ebp) +fldl -328(%ebp) +fstpl X +fldl U1 +fcompl X +fstsw %ax +sahf +jp .LC69 +jbe .LC69 +fldl U1 +fstpl X +.LC69: +.LC71: +fldl X +fstpl U1 +fldl U1 +fstpl -344(%ebp) +fldl Half +fmull -344(%ebp) +fldl ThirtyTwo +fmull -344(%ebp) +fmull -344(%ebp) +faddp %st,%st(1) +fstpl Y +fldl Half +fsubl Y +fstpl Y +fldl Half +faddl Y +fstpl X +fldl Half +fsubl X +fstpl Y +fldl Half +faddl Y +fstpl X +.LC72: +fldl X +fcompl U1 +fstsw %ax +sahf +jp .LC74 +jae .LC74 +fldl Zero +fcompl X +fstsw %ax +sahf +jp .LC71 +jb .LC71 +.LC74: +fldl E1 +fcompl U1 +fstsw %ax +sahf +jp .LC75 +jne .LC75 +pushl $.LC77 +call printf +addl $4,%esp +jmp .LC76 +.LC75: +fldl U1 +subl $8,%esp +fstpl (%esp) +pushl $.LC78 +call printf +addl $12,%esp +.LC76: +fldl One +fdivl U1 +fstpl W +fldl Half +fsubl U1 +faddl Half +fstpl F9 +fldl U2 +fdivl U1 +faddl .LC79 +subl $8,%esp +fstpl (%esp) +call floor +addl $8,%esp +fstpl -360(%ebp) +fldl -360(%ebp) +fstpl Radix +fldl E0 +fcompl Radix +fstsw %ax +sahf +jp .LC80 +jne .LC80 +pushl $.LC82 +call printf +addl $4,%esp +jmp .LC81 +.LC80: +fldl Radix +subl $8,%esp +fstpl (%esp) +pushl $.LC83 +call printf +addl $12,%esp +.LC81: +pushl $.LC85 +fldl Eight +faddl Eight +fcompl Radix +fstsw %ax +sahf +jp .LC86 +jb .LC86 +movl $1,-364(%ebp) +jmp .LC87 +.LC86: +movl $0,-364(%ebp) +.LC87: +pushl -364(%ebp) +pushl $2 +call TstCond +addl $12,%esp +pushl $.LC89 +fldl Two +fcompl Radix +fstsw %ax +sahf +jp 1f +je .LC93 +1: +fldl .LC94 +fcompl Radix +fstsw %ax +sahf +jp 1f +je .LC93 +1: +fldl One +fcompl Radix +fstsw %ax +sahf +jp .LC90 +jne .LC90 +.LC93: +movl $1,-376(%ebp) +jmp .LC91 +.LC90: +movl $0,-376(%ebp) +.LC91: +pushl -376(%ebp) +pushl $3 +call TstCond +addl $12,%esp +movl $20,Milestone +pushl $.LC96 +fldl F9 +fsubl Half +fldl Half +fcompp +fstsw %ax +sahf +jp .LC97 +jbe .LC97 +movl $1,-388(%ebp) +jmp .LC98 +.LC97: +movl $0,-388(%ebp) +.LC98: +pushl -388(%ebp) +pushl $0 +call TstCond +addl $12,%esp +fldl F9 +fstpl X +movl $1,I +fldl X +fsubl Half +fstpl Y +fldl Y +fsubl Half +fstpl Z +pushl $.LC100 +fldl One +fcompl X +fstsw %ax +sahf +jp .LC103 +jne .LC103 +fldl Zero +fcompl Z +fstsw %ax +sahf +jp .LC101 +jne .LC101 +.LC103: +movl $1,-400(%ebp) +jmp .LC102 +.LC101: +movl $0,-400(%ebp) +.LC102: +pushl -400(%ebp) +pushl $0 +call TstCond +addl $12,%esp +fldl One +faddl U2 +fstpl X +movl $0,I +movl $25,Milestone +fldl Radix +fsubl One +fstpl BMinusU2 +fldl BMinusU2 +fsubl U2 +faddl One +fstpl BMinusU2 +fldl One +fcompl Radix +fstsw %ax +sahf +jp 1f +je .LC104 +1: +fldl U1 +subl $8,%esp +fstpl (%esp) +call log +addl $8,%esp +fstpl -440(%ebp) +fldl Radix +subl $8,%esp +fstpl (%esp) +call log +addl $8,%esp +fstpl -448(%ebp) +fldl TwoForty +fchs +fmull -440(%ebp) +fdivl -448(%ebp) +fstpl X +fldl Half +faddl X +subl $8,%esp +fstpl (%esp) +call floor +addl $8,%esp +fstpl -456(%ebp) +fldl -456(%ebp) +fstpl Y +fldl X +fsubl Y +subl $8,%esp +fstpl (%esp) +call fabs +addl $8,%esp +fstpl -464(%ebp) +fldl -464(%ebp) +fmull Four +fldl One +fcompp +fstsw %ax +sahf +jp .LC106 +jbe .LC106 +fldl Y +fstpl X +.LC106: +fldl X +fdivl TwoForty +fstpl Precision +fldl Half +faddl Precision +subl $8,%esp +fstpl (%esp) +call floor +addl $8,%esp +fstpl -472(%ebp) +fldl -472(%ebp) +fstpl Y +fldl Precision +fsubl Y +subl $8,%esp +fstpl (%esp) +call fabs +addl $8,%esp +fstpl -480(%ebp) +fldl -480(%ebp) +fmull TwoForty +fldl Half +fcompp +fstsw %ax +sahf +jp .LC108 +jbe .LC108 +fldl Y +fstpl Precision +.LC108: +.LC104: +fldl Precision +subl $8,%esp +fstpl (%esp) +call floor +addl $8,%esp +fstpl -448(%ebp) +fldl -448(%ebp) +fcompl Precision +fstsw %ax +sahf +jp .LC112 +jne .LC112 +fldl One +fcompl Radix +fstsw %ax +sahf +jp .LC110 +jne .LC110 +.LC112: +pushl $.LC113 +call printf +addl $4,%esp +pushl $.LC114 +call printf +addl $4,%esp +.LC110: +fldl One +fcompl Radix +fstsw %ax +sahf +jp .LC115 +jne .LC115 +pushl $.LC117 +call printf +addl $4,%esp +jmp .LC116 +.LC115: +fldl Precision +subl $8,%esp +fstpl (%esp) +pushl $.LC118 +call printf +addl $12,%esp +.LC116: +pushl $.LC120 +fldl U2 +fmull Nine +fmull Nine +fmull TwoForty +fldl One +fcompp +fstsw %ax +sahf +jp .LC121 +jbe .LC121 +movl $1,-452(%ebp) +jmp .LC122 +.LC121: +movl $0,-452(%ebp) +.LC122: +pushl -452(%ebp) +pushl $1 +call TstCond +addl $12,%esp +movl $30,Milestone +fldl One +fdivl Four +fstpl -492(%ebp) +fldl Four +fdivl Three +fsubl One +fsubl -492(%ebp) +fmull Three +fsubl -492(%ebp) +subl $8,%esp +fstpl (%esp) +call fabs +addl $8,%esp +fstpl -500(%ebp) +fldl -500(%ebp) +fstpl X +.LC123: +fldl X +fstpl Z2 +fldl Z2 +fstpl -516(%ebp) +fldl One +fldl Half +fmull -516(%ebp) +fldl ThirtyTwo +fmull -516(%ebp) +fmull -516(%ebp) +faddp %st,%st(1) +faddp %st,%st(1) +fsubl One +fstpl X +.LC124: +fldl X +fcompl Z2 +fstsw %ax +sahf +jp .LC126 +jae .LC126 +fldl Zero +fcompl X +fstsw %ax +sahf +jp .LC123 +jb .LC123 +.LC126: +fldl Three +fdivl Four +fldl Two +fdivl Three +fsubrp %st,%st(1) +fmull Three +fldl One +fdivl Four +fsubrp %st,%st(1) +subl $8,%esp +fstpl (%esp) +call fabs +addl $8,%esp +fstpl -532(%ebp) +fldl -532(%ebp) +fstpl Z +fldl -532(%ebp) +fstpl Y +fldl -532(%ebp) +fstpl X +.LC127: +fldl Z +fstpl Z1 +fldl One +fdivl Two +fstpl -540(%ebp) +fldl Z1 +fstpl -548(%ebp) +fldl -540(%ebp) +fldl -540(%ebp) +fldl Half +fmull -548(%ebp) +fldl ThirtyTwo +fmull -548(%ebp) +fmull -548(%ebp) +faddp %st,%st(1) +fsubrp %st,%st(1) +faddl -540(%ebp) +fsubrp %st,%st(1) +faddl -540(%ebp) +fstpl Z +.LC128: +fldl Z +fcompl Z1 +fstsw %ax +sahf +jp .LC130 +jae .LC130 +fldl Zero +fcompl Z +fstsw %ax +sahf +jp .LC127 +jb .LC127 +.LC130: +.LC131: +.LC134: +fldl Y +fstpl Y1 +fldl Y1 +fstpl -556(%ebp) +fldl Half +fldl Half +fldl Half +fmull -556(%ebp) +fldl ThirtyTwo +fmull -556(%ebp) +fmull -556(%ebp) +faddp %st,%st(1) +fsubrp %st,%st(1) +faddl Half +fsubrp %st,%st(1) +faddl Half +fstpl Y +.LC135: +fldl Y +fcompl Y1 +fstsw %ax +sahf +jp .LC137 +jae .LC137 +fldl Zero +fcompl Y +fstsw %ax +sahf +jp .LC134 +jb .LC134 +.LC137: +fldl X +fstpl X1 +fldl X1 +fstpl -556(%ebp) +fldl Half +fmull -556(%ebp) +fldl ThirtyTwo +fmull -556(%ebp) +fmull -556(%ebp) +faddp %st,%st(1) +fsubl F9 +faddl F9 +fstpl X +.LC132: +fldl X +fcompl X1 +fstsw %ax +sahf +jp .LC138 +jae .LC138 +fldl Zero +fcompl X +fstsw %ax +sahf +jp .LC131 +jb .LC131 +.LC138: +fldl Y1 +fcompl X1 +fstsw %ax +sahf +jp .LC141 +jne .LC141 +fldl Z1 +fcompl X1 +fstsw %ax +sahf +jp 1f +je .LC139 +1: +.LC141: +pushl $.LC142 +pushl $1 +call BadCond +addl $8,%esp +fldl Z1 +subl $8,%esp +fstpl (%esp) +fldl Y1 +subl $8,%esp +fstpl (%esp) +fldl X1 +subl $8,%esp +fstpl (%esp) +pushl $.LC143 +call printf +addl $28,%esp +pushl $.LC144 +call printf +addl $4,%esp +pushl $.LC145 +call printf +addl $4,%esp +pushl $.LC146 +call notify +addl $4,%esp +fldl U1 +fcompl X1 +fstsw %ax +sahf +jp 1f +je .LC150 +1: +fldl U1 +fcompl Y1 +fstsw %ax +sahf +jp 1f +je .LC150 +1: +fldl U1 +fcompl Z1 +fstsw %ax +sahf +jp .LC140 +jne .LC140 +.LC150: +pushl $.LC151 +call printf +addl $4,%esp +jmp .LC140 +.LC139: +fldl U1 +fcompl Z1 +fstsw %ax +sahf +jp .LC154 +jne .LC154 +fldl U2 +fcompl Z2 +fstsw %ax +sahf +jp 1f +je .LC152 +1: +.LC154: +fldl U1 +fcompl Z1 +fstsw %ax +sahf +jp .LC157 +jbe .LC157 +fldl U2 +fcompl Z2 +fstsw %ax +sahf +jp .LC155 +ja .LC155 +.LC157: +pushl $.LC158 +pushl $0 +call BadCond +addl $8,%esp +pushl $.LC159 +call notify +addl $4,%esp +fldl Z1 +fsubl U1 +subl $8,%esp +fstpl (%esp) +fldl U1 +subl $8,%esp +fstpl (%esp) +pushl $.LC160 +call printf +addl $20,%esp +fldl Z2 +fsubl U2 +subl $8,%esp +fstpl (%esp) +fldl U2 +subl $8,%esp +fstpl (%esp) +pushl $.LC161 +call printf +addl $20,%esp +jmp .LC156 +.LC155: +fldl Zero +fcompl Z1 +fstsw %ax +sahf +jp .LC164 +jae .LC164 +fldl Zero +fcompl Z2 +fstsw %ax +sahf +jp .LC162 +jb .LC162 +.LC164: +fldl Radix +subl $8,%esp +fstpl (%esp) +pushl $.LC165 +call printf +addl $12,%esp +pushl $.LC166 +call printf +addl $4,%esp +fldl Z2 +subl $8,%esp +fstpl (%esp) +fldl Z1 +subl $8,%esp +fstpl (%esp) +pushl $.LC167 +call printf +addl $20,%esp +pushl $.LC168 +call notify +addl $4,%esp +.LC162: +fldl Z2 +fcompl Z1 +fstsw %ax +sahf +jp .LC171 +jne .LC171 +fldl Zero +fcompl Z1 +fstsw %ax +sahf +jp .LC169 +jae .LC169 +.LC171: +fldl Z1 +fdivl U1 +fstpl X +fldl Z2 +fdivl U2 +fstpl Y +fldl X +fcompl Y +fstsw %ax +sahf +jp .LC172 +jae .LC172 +fldl Y +fstpl X +.LC172: +fldl X +subl $8,%esp +fstpl (%esp) +call log +addl $8,%esp +fstpl -580(%ebp) +fldl -580(%ebp) +fchs +fstpl Q +pushl $.LC174 +call printf +addl $4,%esp +fldl Radix +subl $8,%esp +fstpl (%esp) +call log +addl $8,%esp +fstpl -588(%ebp) +fldl Q +fdivl -588(%ebp) +subl $8,%esp +fstpl (%esp) +pushl $.LC175 +call printf +addl $12,%esp +fldl .LC94 +subl $8,%esp +fstpl (%esp) +call log +addl $8,%esp +fstpl -596(%ebp) +fldl Q +fdivl -596(%ebp) +subl $8,%esp +fstpl (%esp) +pushl $.LC176 +call printf +addl $12,%esp +.LC169: +pushl $.LC151 +call printf +addl $4,%esp +.LC156: +.LC152: +.LC140: +call Pause +movl $35,Milestone +fldl Two +fcompl Radix +fstsw %ax +sahf +jp .LC177 +ja .LC177 +fldl W +fldl Radix +fmull Radix +fdivrp %st,%st(1) +fstpl X +fldl X +fstpl -576(%ebp) +fldl -576(%ebp) +faddl One +fstpl Y +fldl Y +fsubl -576(%ebp) +fstpl Z +fldl Z +fstpl -584(%ebp) +fldl -584(%ebp) +faddl U2 +fstpl T +fldl T +fsubl -584(%ebp) +fstpl X +pushl $.LC180 +fldl U2 +fcompl X +fstsw %ax +sahf +jp .LC181 +jne .LC181 +movl $1,-560(%ebp) +jmp .LC182 +.LC181: +movl $0,-560(%ebp) +.LC182: +pushl -560(%ebp) +pushl $0 +call TstCond +addl $12,%esp +fldl U2 +fcompl X +fstsw %ax +sahf +jp .LC183 +jne .LC183 +pushl $.LC185 +call printf +addl $4,%esp +.LC183: +.LC177: +pushl $.LC186 +call printf +addl $4,%esp +fldl F9 +fmull One +fstpl Y +fldl One +fmull F9 +fstpl Z +fldl F9 +fsubl Half +fstpl X +fldl X +fstpl -588(%ebp) +fldl Y +fsubl Half +fsubl -588(%ebp) +fstpl Y +fldl Z +fsubl Half +fsubl -588(%ebp) +fstpl Z +fldl One +faddl U2 +fstpl X +fldl X +fstpl -604(%ebp) +fldl -604(%ebp) +fmull Radix +fstpl T +fldl Radix +fmull -604(%ebp) +fstpl R +fldl T +fsubl Radix +fstpl X +fldl Radix +fmull U2 +fstpl -620(%ebp) +fldl X +fsubl -620(%ebp) +fstpl X +fldl R +fsubl Radix +fstpl T +fldl T +fsubl -620(%ebp) +fstpl T +fldl Radix +fsubl One +fstpl -628(%ebp) +fldl X +fmull -628(%ebp) +fstpl X +fldl T +fmull -628(%ebp) +fstpl T +fldl Zero +fcompl X +fstsw %ax +sahf +jp .LC187 +jne .LC187 +fldl Zero +fcompl Y +fstsw %ax +sahf +jp .LC187 +jne .LC187 +fldl Zero +fcompl Z +fstsw %ax +sahf +jp .LC187 +jne .LC187 +fldl Zero +fcompl T +fstsw %ax +sahf +jp .LC187 +jne .LC187 +movl $1,GMult +jmp .LC188 +.LC187: +movl $0,GMult +pushl $.LC189 +pushl $0 +pushl $1 +call TstCond +addl $12,%esp +.LC188: +fldl Radix +fmull U2 +fstpl Z +fldl Z +fstpl -648(%ebp) +fldl One +faddl -648(%ebp) +fstpl X +fldl X +fstpl -656(%ebp) +fldl -656(%ebp) +faddl -648(%ebp) +fldl -656(%ebp) +fmull -656(%ebp) +fsubrp %st,%st(1) +subl $8,%esp +fstpl (%esp) +call fabs +addl $8,%esp +fstpl -664(%ebp) +fldl -664(%ebp) +fsubl U2 +fstpl Y +fldl One +fsubl U2 +fstpl X +fldl X +fstpl -680(%ebp) +fldl -680(%ebp) +fsubl U2 +fldl -680(%ebp) +fmull -680(%ebp) +fsubrp %st,%st(1) +subl $8,%esp +fstpl (%esp) +call fabs +addl $8,%esp +fstpl -688(%ebp) +fldl -688(%ebp) +fsubl U1 +fstpl Z +pushl $.LC191 +fldl Zero +fcompl Y +fstsw %ax +sahf +jp .LC192 +jb .LC192 +fldl Zero +fcompl Z +fstsw %ax +sahf +jp .LC192 +jb .LC192 +movl $1,-640(%ebp) +jmp .LC193 +.LC192: +movl $0,-640(%ebp) +.LC193: +pushl -640(%ebp) +pushl $0 +call TstCond +addl $12,%esp +fldl One +fsubl U2 +fstpl Y +fldl One +faddl U2 +fstpl X +fldl One +fdivl Y +fstpl Z +fldl Z +fsubl X +fstpl Y +fldl One +fdivl Three +fstpl X +fldl Three +fdivl Nine +fstpl Z +fldl Z +fstpl -740(%ebp) +fldl X +fsubl -740(%ebp) +fstpl X +fldl Nine +fdivl TwentySeven +fstpl T +fldl -740(%ebp) +fsubl T +fstpl Z +pushl $.LC195 +fldl Zero +fcompl X +fstsw %ax +sahf +jp .LC196 +jne .LC196 +fldl Zero +fcompl Y +fstsw %ax +sahf +jp .LC196 +jne .LC196 +fldl Zero +fcompl Z +fstsw %ax +sahf +jp .LC196 +jne .LC196 +movl $1,-700(%ebp) +jmp .LC197 +.LC196: +movl $0,-700(%ebp) +.LC197: +pushl -700(%ebp) +pushl $2 +call TstCond +addl $12,%esp +fldl F9 +fdivl One +fstpl Y +fldl F9 +fsubl Half +fstpl X +fldl Y +fsubl Half +fsubl X +fstpl Y +fldl One +faddl U2 +fstpl X +fldl X +fstpl -780(%ebp) +fldl -780(%ebp) +fdivl One +fstpl T +fldl T +fsubl -780(%ebp) +fstpl X +fldl Zero +fcompl X +fstsw %ax +sahf +jp .LC198 +jne .LC198 +fldl Zero +fcompl Y +fstsw %ax +sahf +jp .LC198 +jne .LC198 +fldl Zero +fcompl Z +fstsw %ax +sahf +jp .LC198 +jne .LC198 +movl $1,GDiv +jmp .LC199 +.LC198: +movl $0,GDiv +pushl $.LC200 +pushl $0 +pushl $1 +call TstCond +addl $12,%esp +.LC199: +fldl One +fldl One +faddl U2 +fdivrp %st,%st(1) +fstpl X +fldl X +fsubl Half +fsubl Half +fstpl Y +pushl $.LC202 +fldl Zero +fcompl Y +fstsw %ax +sahf +jp .LC203 +jbe .LC203 +movl $1,-792(%ebp) +jmp .LC204 +.LC203: +movl $0,-792(%ebp) +.LC204: +pushl -792(%ebp) +pushl $1 +call TstCond +addl $12,%esp +fldl One +fsubl U2 +fstpl X +fldl One +fldl Radix +fmull U2 +faddp %st,%st(1) +fstpl Y +fldl X +fstpl -844(%ebp) +fldl -844(%ebp) +fmull Radix +fstpl Z +fldl Y +fstpl -852(%ebp) +fldl -852(%ebp) +fmull Radix +fstpl T +fldl Z +fdivl Radix +fstpl R +fldl T +fdivl Radix +fstpl StickyBit +fldl R +fsubl -844(%ebp) +fstpl X +fldl StickyBit +fsubl -852(%ebp) +fstpl Y +pushl $.LC206 +fldl Zero +fcompl X +fstsw %ax +sahf +jp .LC207 +jne .LC207 +fldl Zero +fcompl Y +fstsw %ax +sahf +jp .LC207 +jne .LC207 +movl $1,-812(%ebp) +jmp .LC208 +.LC207: +movl $0,-812(%ebp) +.LC208: +pushl -812(%ebp) +pushl $0 +call TstCond +addl $12,%esp +fldl One +fsubl U1 +fstpl Y +fldl One +fsubl F9 +fstpl X +fldl One +fsubl Y +fstpl Y +fldl Radix +fsubl U2 +fstpl T +fldl Radix +fsubl BMinusU2 +fstpl Z +fldl Radix +fsubl T +fstpl T +fldl U1 +fcompl X +fstsw %ax +sahf +jp .LC209 +jne .LC209 +fldl U1 +fcompl Y +fstsw %ax +sahf +jp .LC209 +jne .LC209 +fldl U2 +fcompl Z +fstsw %ax +sahf +jp .LC209 +jne .LC209 +fldl U2 +fcompl T +fstsw %ax +sahf +jp .LC209 +jne .LC209 +movl $1,GAddSub +jmp .LC210 +.LC209: +movl $0,GAddSub +pushl $.LC211 +pushl $0 +pushl $1 +call TstCond +addl $12,%esp +.LC210: +fldl One +fcompl F9 +fstsw %ax +sahf +jp 1f +je .LC212 +1: +fldl F9 +fsubl One +fldl Zero +fcompp +fstsw %ax +sahf +jp .LC212 +ja .LC212 +pushl $.LC214 +pushl $1 +call BadCond +addl $8,%esp +pushl $.LC215 +call printf +addl $4,%esp +pushl $.LC216 +call printf +addl $4,%esp +pushl $.LC217 +call printf +addl $4,%esp +.LC212: +cmpl $1,GMult +jne .LC218 +cmpl $1,GDiv +jne .LC218 +cmpl $1,GAddSub +jne .LC218 +pushl $.LC220 +call printf +addl $4,%esp +.LC218: +movl $40,Milestone +call Pause +pushl $.LC221 +call printf +addl $4,%esp +movl $0,RMult +movl $0,RDiv +movl $0,RAddSub +fldl Radix +fdivl Two +fstpl RadixD2 +fldl Two +fstpl A1 +movl $0,Done +.LC222: +fldl Radix +fstpl AInvrse +.LC225: +fldl AInvrse +fstpl -924(%ebp) +fldl -924(%ebp) +fstpl X +fldl -924(%ebp) +fdivl A1 +fstpl AInvrse +.LC226: +fldl AInvrse +subl $8,%esp +fstpl (%esp) +call floor +addl $8,%esp +fstpl -924(%ebp) +fldl AInvrse +fcompl -924(%ebp) +fstsw %ax +sahf +jp 1f +je .LC225 +1: +fldl One +fcompl X +fstsw %ax +sahf +jp 1f +je .LC231 +1: +fldl Three +fcompl A1 +fstsw %ax +sahf +jp .LC229 +jae .LC229 +.LC231: +movl $1,-928(%ebp) +jmp .LC230 +.LC229: +movl $0,-928(%ebp) +.LC230: +movl -928(%ebp),%edi +movl %edi,Done +cmpl $0,Done +jne .LC232 +fldl Nine +faddl One +fstpl A1 +.LC232: +.LC223: +cmpl $0,Done +je .LC222 +fldl One +fcompl X +fstsw %ax +sahf +jp .LC234 +jne .LC234 +fldl Radix +fstpl A1 +.LC234: +fldl One +fdivl A1 +fstpl AInvrse +fldl A1 +fstpl X +fldl AInvrse +fstpl Y +movl $0,Done +.LC236: +fldl X +fmull Y +fsubl Half +fstpl Z +pushl $.LC240 +fldl Half +fcompl Z +fstsw %ax +sahf +jp .LC241 +jne .LC241 +movl $1,-928(%ebp) +jmp .LC242 +.LC241: +movl $0,-928(%ebp) +.LC242: +pushl -928(%ebp) +pushl $0 +call TstCond +addl $12,%esp +fldl Radix +fcompl X +fstsw %ax +sahf +jp .LC244 +jne .LC244 +movl $1,-940(%ebp) +jmp .LC245 +.LC244: +movl $0,-940(%ebp) +.LC245: +movl -940(%ebp),%edi +movl %edi,Done +fldl Radix +fstpl X +fldl One +fdivl X +fstpl Y +.LC237: +cmpl $0,Done +je .LC236 +fldl One +faddl U2 +fstpl Y2 +fldl One +fsubl U2 +fstpl Y1 +fldl OneAndHalf +fsubl U2 +fstpl X +fldl OneAndHalf +faddl U2 +fstpl Y +fldl X +fstpl -956(%ebp) +fldl Y2 +fstpl -964(%ebp) +fldl -956(%ebp) +fsubl U2 +fmull -964(%ebp) +fstpl Z +fldl Y +fstpl -972(%ebp) +fldl Y1 +fstpl -980(%ebp) +fldl -972(%ebp) +fmull -980(%ebp) +fstpl T +fldl Z +fsubl -956(%ebp) +fstpl Z +fldl T +fsubl -956(%ebp) +fstpl T +fldl -956(%ebp) +fmull -964(%ebp) +fstpl X +fldl -972(%ebp) +faddl U2 +fmull -980(%ebp) +fstpl Y +fldl X +fsubl OneAndHalf +fstpl X +fldl Y +fsubl OneAndHalf +fstpl Y +fldl Zero +fcompl X +fstsw %ax +sahf +jp .LC246 +jne .LC246 +fldl Zero +fcompl Y +fstsw %ax +sahf +jp .LC246 +jne .LC246 +fldl Zero +fcompl Z +fstsw %ax +sahf +jp .LC246 +jne .LC246 +fldl Zero +fcompl T +fstsw %ax +sahf +jp .LC246 +jb .LC246 +fldl OneAndHalf +faddl U2 +fstpl -1012(%ebp) +fldl -1012(%ebp) +fmull Y2 +fstpl X +fldl OneAndHalf +fsubl U2 +fstpl -1028(%ebp) +fldl -1028(%ebp) +fsubl U2 +fstpl Y +fldl -1012(%ebp) +faddl U2 +fstpl Z +fldl Y1 +fstpl -1036(%ebp) +fldl -1028(%ebp) +fmull -1036(%ebp) +fstpl T +fldl Z +fstpl -1044(%ebp) +fldl -1044(%ebp) +faddl U2 +fstpl -1052(%ebp) +fldl X +fsubl -1052(%ebp) +fstpl X +fldl Y +fstpl -1060(%ebp) +fldl -1060(%ebp) +fmull -1036(%ebp) +fstpl StickyBit +fldl -1044(%ebp) +fmull Y2 +fstpl S +fldl T +fsubl -1060(%ebp) +fstpl T +fldl U2 +fsubl -1060(%ebp) +faddl StickyBit +fstpl Y +fldl S +fldl -1052(%ebp) +faddl U2 +fsubrp %st,%st(1) +fstpl Z +fldl Y2 +faddl U2 +fmull -1036(%ebp) +fstpl StickyBit +fldl Y2 +fmull -1036(%ebp) +fstpl Y1 +fldl StickyBit +fsubl Y2 +fstpl StickyBit +fldl Y1 +fsubl Half +fstpl Y1 +fldl Zero +fcompl X +fstsw %ax +sahf +jp .LC248 +jne .LC248 +fldl Zero +fcompl Y +fstsw %ax +sahf +jp .LC248 +jne .LC248 +fldl Zero +fcompl Z +fstsw %ax +sahf +jp .LC248 +jne .LC248 +fldl Zero +fcompl T +fstsw %ax +sahf +jp .LC248 +jne .LC248 +fldl Zero +fcompl StickyBit +fstsw %ax +sahf +jp .LC248 +jne .LC248 +fldl Half +fcompl Y1 +fstsw %ax +sahf +jp .LC248 +jne .LC248 +movl $1,RMult +pushl $.LC250 +call printf +addl $4,%esp +jmp .LC249 +.LC248: +fldl X +faddl U2 +fldl Zero +fcompp +fstsw %ax +sahf +jp .LC251 +jne .LC251 +fldl Zero +fcompl Y +fstsw %ax +sahf +jp .LC251 +jbe .LC251 +fldl Z +faddl U2 +fldl Zero +fcompp +fstsw %ax +sahf +jp .LC251 +jne .LC251 +fldl Zero +fcompl T +fstsw %ax +sahf +jp .LC251 +jbe .LC251 +fldl StickyBit +faddl U2 +fldl Zero +fcompp +fstsw %ax +sahf +jp .LC251 +jne .LC251 +fldl Half +fcompl Y1 +fstsw %ax +sahf +jp .LC251 +jbe .LC251 +movl $2,RMult +pushl $.LC253 +call printf +addl $4,%esp +jmp .LC252 +.LC251: +pushl $.LC254 +call printf +addl $4,%esp +.LC252: +.LC249: +cmpl $1,RMult +jne .LC247 +cmpl $0,GMult +jne .LC247 +pushl $.LC257 +call notify +addl $4,%esp +jmp .LC247 +.LC246: +pushl $.LC254 +call printf +addl $4,%esp +.LC247: +movl $45,Milestone +fldl One +faddl U2 +fstpl Y2 +fldl One +fsubl U2 +fstpl Y1 +fldl OneAndHalf +faddl U2 +fstpl -1020(%ebp) +fldl -1020(%ebp) +faddl U2 +fstpl Z +fldl Z +fstpl -1028(%ebp) +fldl Y2 +fstpl -1036(%ebp) +fldl -1028(%ebp) +fdivl -1036(%ebp) +fstpl X +fldl OneAndHalf +fsubl U2 +fsubl U2 +fstpl T +fldl T +fstpl -1044(%ebp) +fldl Y1 +fstpl -1052(%ebp) +fldl -1044(%ebp) +fsubl U2 +fdivl -1052(%ebp) +fstpl Y +fldl -1028(%ebp) +faddl U2 +fdivl -1036(%ebp) +fstpl Z +fldl X +fsubl OneAndHalf +fstpl X +fldl Y +fsubl -1044(%ebp) +fstpl Y +fldl -1044(%ebp) +fdivl -1052(%ebp) +fstpl T +fldl Z +fsubl -1020(%ebp) +fstpl Z +fldl U2 +fsubl OneAndHalf +faddl T +fstpl T +fldl Zero +fcompl X +fstsw %ax +sahf +jp .LC258 +jb .LC258 +fldl Zero +fcompl Y +fstsw %ax +sahf +jp .LC258 +jb .LC258 +fldl Zero +fcompl Z +fstsw %ax +sahf +jp .LC258 +jb .LC258 +fldl Zero +fcompl T +fstsw %ax +sahf +jp .LC258 +jb .LC258 +fldl Y2 +fstpl -1076(%ebp) +fldl OneAndHalf +fdivl -1076(%ebp) +fstpl X +fldl OneAndHalf +fsubl U2 +fstpl Y +fldl OneAndHalf +faddl U2 +fstpl Z +fldl Y +fstpl -1092(%ebp) +fldl X +fsubl -1092(%ebp) +fstpl X +fldl Y1 +fstpl -1100(%ebp) +fldl OneAndHalf +fdivl -1100(%ebp) +fstpl T +fldl -1092(%ebp) +fdivl -1100(%ebp) +fstpl Y +fldl Z +fstpl -1108(%ebp) +fldl T +fldl -1108(%ebp) +faddl U2 +fsubrp %st,%st(1) +fstpl T +fldl Y +fsubl -1108(%ebp) +fstpl Y +fldl -1108(%ebp) +fdivl -1076(%ebp) +fstpl Z +fldl -1076(%ebp) +faddl U2 +fdivl -1076(%ebp) +fstpl Y1 +fldl Z +fsubl OneAndHalf +fstpl Z +fldl Y1 +fsubl -1076(%ebp) +fstpl Y2 +fldl F9 +fsubl U1 +fdivl F9 +fstpl Y1 +fldl Zero +fcompl X +fstsw %ax +sahf +jp .LC260 +jne .LC260 +fldl Zero +fcompl Y +fstsw %ax +sahf +jp .LC260 +jne .LC260 +fldl Zero +fcompl Z +fstsw %ax +sahf +jp .LC260 +jne .LC260 +fldl Zero +fcompl T +fstsw %ax +sahf +jp .LC260 +jne .LC260 +fldl Zero +fcompl Y2 +fstsw %ax +sahf +jp .LC260 +jne .LC260 +fldl Zero +fcompl Y2 +fstsw %ax +sahf +jp .LC260 +jne .LC260 +fldl Y1 +fsubl Half +fldl F9 +fsubl Half +fcompp +fstsw %ax +sahf +jp .LC260 +jne .LC260 +movl $1,RDiv +pushl $.LC262 +call printf +addl $4,%esp +cmpl $0,GDiv +jne .LC261 +pushl $.LC265 +call notify +addl $4,%esp +jmp .LC261 +.LC260: +fldl Zero +fcompl X +fstsw %ax +sahf +jp .LC266 +jbe .LC266 +fldl Zero +fcompl Y +fstsw %ax +sahf +jp .LC266 +jbe .LC266 +fldl Zero +fcompl Z +fstsw %ax +sahf +jp .LC266 +jbe .LC266 +fldl Zero +fcompl T +fstsw %ax +sahf +jp .LC266 +jbe .LC266 +fldl Zero +fcompl Y2 +fstsw %ax +sahf +jp .LC266 +jbe .LC266 +fldl Y1 +fsubl Half +fldl F9 +fsubl Half +fcompp +fstsw %ax +sahf +jp .LC266 +jbe .LC266 +movl $2,RDiv +pushl $.LC268 +call printf +addl $4,%esp +.LC266: +.LC261: +.LC258: +cmpl $0,RDiv +jne .LC269 +pushl $.LC271 +call printf +addl $4,%esp +.LC269: +fldl One +fdivl Radix +fstpl BInvrse +pushl $.LC273 +fldl BInvrse +fmull Radix +fsubl Half +fldl Half +fcompp +fstsw %ax +sahf +jp .LC274 +jne .LC274 +movl $1,-1064(%ebp) +jmp .LC275 +.LC274: +movl $0,-1064(%ebp) +.LC275: +pushl -1064(%ebp) +pushl $0 +call TstCond +addl $12,%esp +movl $50,Milestone +pushl $.LC277 +fldl F9 +faddl U1 +fsubl Half +fldl Half +fcompp +fstsw %ax +sahf +jp .LC278 +jne .LC278 +fldl BMinusU2 +faddl U2 +fsubl One +fldl Radix +fsubl One +fcompp +fstsw %ax +sahf +jp .LC278 +jne .LC278 +movl $1,-1084(%ebp) +jmp .LC279 +.LC278: +movl $0,-1084(%ebp) +.LC279: +pushl -1084(%ebp) +pushl $0 +call TstCond +addl $12,%esp +fldl One +fldl U1 +fmull U1 +fsubrp %st,%st(1) +fstpl X +fldl One +fldl U2 +fldl One +fsubl U2 +fmulp %st,%st(1) +faddp %st,%st(1) +fstpl Y +fldl F9 +fsubl Half +fstpl Z +fldl X +fsubl Half +fsubl Z +fstpl X +fldl Y +fsubl One +fstpl Y +fldl Zero +fcompl X +fstsw %ax +sahf +jp .LC280 +jne .LC280 +fldl Zero +fcompl Y +fstsw %ax +sahf +jp .LC280 +jne .LC280 +movl $2,RAddSub +pushl $.LC282 +call printf +addl $4,%esp +.LC280: +cmpl $1,GAddSub +jne .LC283 +fldl Half +faddl U2 +fmull U2 +fstpl X +fldl Half +fsubl U2 +fmull U2 +fstpl Y +fldl One +faddl X +fstpl X +fldl One +faddl Y +fstpl Y +fldl One +faddl U2 +fsubl X +fstpl X +fldl One +fsubl Y +fstpl Y +fldl Zero +fcompl X +fstsw %ax +sahf +jp .LC285 +jne .LC285 +fldl Zero +fcompl Y +fstsw %ax +sahf +jp .LC285 +jne .LC285 +fldl Half +faddl U2 +fmull U1 +fstpl X +fldl Half +fsubl U2 +fmull U1 +fstpl Y +fldl One +fsubl X +fstpl X +fldl One +fsubl Y +fstpl Y +fldl F9 +fsubl X +fstpl X +fldl One +fsubl Y +fstpl Y +fldl Zero +fcompl X +fstsw %ax +sahf +jp .LC287 +jne .LC287 +fldl Zero +fcompl Y +fstsw %ax +sahf +jp .LC287 +jne .LC287 +movl $1,RAddSub +pushl $.LC289 +call printf +addl $4,%esp +cmpl $0,GAddSub +jne .LC284 +pushl $.LC292 +call notify +addl $4,%esp +jmp .LC284 +.LC287: +pushl $.LC293 +call printf +addl $4,%esp +jmp .LC284 +.LC285: +pushl $.LC293 +call printf +addl $4,%esp +jmp .LC284 +.LC283: +pushl $.LC293 +call printf +addl $4,%esp +.LC284: +fldl One +fstpl S +fldl One +fldl Half +fldl One +faddl Half +fmulp %st,%st(1) +faddp %st,%st(1) +fstpl X +fldl One +faddl U2 +fmull Half +fstpl Y +fldl X +fstpl -1164(%ebp) +fldl Y +fstpl -1172(%ebp) +fldl -1164(%ebp) +fsubl -1172(%ebp) +fstpl Z +fldl -1172(%ebp) +fsubl -1164(%ebp) +fstpl T +fldl Z +faddl T +fstpl StickyBit +fldl Zero +fcompl StickyBit +fstsw %ax +sahf +jp 1f +je .LC294 +1: +fldl Zero +fstpl S +pushl $.LC296 +pushl $3 +call BadCond +addl $8,%esp +.LC294: +fldl Zero +fstpl StickyBit +cmpl $1,GMult +jne .LC297 +cmpl $1,GDiv +jne .LC297 +cmpl $1,GAddSub +jne .LC297 +cmpl $1,RMult +jne .LC297 +cmpl $1,RDiv +jne .LC297 +cmpl $1,RAddSub +jne .LC297 +fldl RadixD2 +subl $8,%esp +fstpl (%esp) +call floor +addl $8,%esp +fstpl -1180(%ebp) +fldl RadixD2 +fcompl -1180(%ebp) +fstsw %ax +sahf +jp .LC297 +jne .LC297 +pushl $.LC299 +call printf +addl $4,%esp +fldl Half +faddl U1 +fmull U2 +fstpl X +fldl Half +fmull U2 +fstpl Y +fldl One +faddl Y +fstpl Z +fldl One +faddl X +fstpl T +fldl Z +fsubl One +fldl Zero +fcompp +fstsw %ax +sahf +jp .LC300 +jb .LC300 +fldl T +fsubl One +fldl U2 +fcompp +fstsw %ax +sahf +jp .LC300 +ja .LC300 +fldl T +faddl Y +fstpl Z +fldl Z +fsubl X +fstpl Y +fldl Z +fsubl T +fldl U2 +fcompp +fstsw %ax +sahf +jp .LC302 +ja .LC302 +fldl Y +fsubl T +fldl Zero +fcompp +fstsw %ax +sahf +jp .LC302 +jne .LC302 +fldl Half +faddl U1 +fmull U1 +fstpl X +fldl Half +fmull U1 +fstpl Y +fldl One +fsubl Y +fstpl Z +fldl One +fsubl X +fstpl T +fldl Z +fsubl One +fldl Zero +fcompp +fstsw %ax +sahf +jp .LC304 +jne .LC304 +fldl T +fsubl F9 +fldl Zero +fcompp +fstsw %ax +sahf +jp .LC304 +jne .LC304 +fldl Half +fsubl U1 +fmull U1 +fstpl Z +fldl F9 +fsubl Z +fstpl T +fldl F9 +fsubl Y +fstpl Q +fldl T +fsubl F9 +fldl Zero +fcompp +fstsw %ax +sahf +jp .LC306 +jne .LC306 +fldl F9 +fsubl U1 +fsubl Q +fldl Zero +fcompp +fstsw %ax +sahf +jp .LC306 +jne .LC306 +fldl One +faddl U2 +fmull OneAndHalf +fstpl Z +fldl OneAndHalf +faddl U2 +fsubl Z +faddl U2 +fstpl T +fldl One +fldl Half +fdivl Radix +faddp %st,%st(1) +fstpl X +fldl One +fldl Radix +fmull U2 +faddp %st,%st(1) +fstpl Y +fldl X +fmull Y +fstpl Z +fldl Zero +fcompl T +fstsw %ax +sahf +jp .LC308 +jne .LC308 +fldl X +fldl Radix +fmull U2 +faddp %st,%st(1) +fsubl Z +fldl Zero +fcompp +fstsw %ax +sahf +jp .LC308 +jne .LC308 +fldl Two +fcompl Radix +fstsw %ax +sahf +jp 1f +je .LC310 +1: +fldl Two +faddl U2 +fstpl X +fldl X +fdivl Two +fstpl Y +fldl Y +fsubl One +fldl Zero +fcompp +fstsw %ax +sahf +jp .LC311 +jne .LC311 +fldl S +fstpl StickyBit +jmp .LC311 +.LC310: +fldl S +fstpl StickyBit +.LC311: +.LC308: +.LC306: +.LC304: +.LC302: +.LC300: +.LC297: +fldl One +fcompl StickyBit +fstsw %ax +sahf +jp .LC314 +jne .LC314 +pushl $.LC316 +call printf +addl $4,%esp +jmp .LC315 +.LC314: +pushl $.LC317 +call printf +addl $4,%esp +.LC315: +pushl $.LC319 +cmpl $0,GMult +je .LC320 +cmpl $0,GDiv +je .LC320 +cmpl $0,GAddSub +je .LC320 +cmpl $0,RMult +je .LC320 +cmpl $0,RDiv +je .LC320 +cmpl $0,RAddSub +je .LC320 +movl $1,-1184(%ebp) +jmp .LC321 +.LC320: +movl $0,-1184(%ebp) +.LC321: +pushl -1184(%ebp) +pushl $3 +call TstCond +addl $12,%esp +movl $60,Milestone +pushl $.LC45 +call printf +addl $4,%esp +pushl $.LC322 +call printf +addl $4,%esp +pushl NoTrials +pushl $.LC323 +call printf +addl $8,%esp +fldl .LC324 +subl $8,%esp +fstpl (%esp) +call sqrt +addl $8,%esp +fstpl -1192(%ebp) +fldl -1192(%ebp) +fstpl Random9 +fldl Third +fstpl Random1 +movl $1,I +.LC325: +call Random +fstpl -1200(%ebp) +fldl -1200(%ebp) +fstpl X +call Random +fstpl -1208(%ebp) +fldl -1208(%ebp) +fstpl Y +fldl Y +fmull X +fstpl Z9 +fldl X +fmull Y +fstpl Z +fldl Z +fsubl Z9 +fstpl Z9 +incl I +.LC326: +movl NoTrials,%edi +cmpl %edi,I +jg .LC328 +fldl Zero +fcompl Z9 +fstsw %ax +sahf +jp 1f +je .LC325 +1: +.LC328: +movl NoTrials,%edi +cmpl %edi,I +jne .LC329 +fldl One +fldl Half +fdivl Three +faddp %st,%st(1) +fstpl -1208(%ebp) +fldl -1208(%ebp) +fstpl Random1 +fldl U2 +faddl U1 +faddl One +fstpl -1216(%ebp) +fldl -1216(%ebp) +fstpl Random2 +fldl Random1 +fstpl -1224(%ebp) +fldl Random2 +fstpl -1232(%ebp) +fldl -1224(%ebp) +fmull -1232(%ebp) +fstpl Z +fldl -1232(%ebp) +fmull -1224(%ebp) +fstpl Y +fldl -1208(%ebp) +fmull -1216(%ebp) +fstpl -1240(%ebp) +fldl -1240(%ebp) +fsubl -1240(%ebp) +fstpl Z9 +.LC329: +movl NoTrials,%edi +cmpl %edi,I +je .LC331 +fldl Zero +fcompl Z9 +fstsw %ax +sahf +jp 1f +je .LC331 +1: +pushl $.LC333 +pushl $2 +call BadCond +addl $8,%esp +jmp .LC332 +.LC331: +pushl NoTrials +pushl $.LC334 +call printf +addl $8,%esp +.LC332: +movl $70,Milestone +pushl $.LC335 +call printf +addl $4,%esp +fldl Zero +subl $8,%esp +fstpl (%esp) +call sqrt +addl $8,%esp +fstpl -1212(%ebp) +fldl -1212(%ebp) +fcompl Zero +fstsw %ax +sahf +jp .LC338 +jne .LC338 +fldl Zero +fchs +fstpl -1220(%ebp) +fldl -1220(%ebp) +subl $8,%esp +fstpl (%esp) +call sqrt +addl $8,%esp +fstpl -1228(%ebp) +fldl -1228(%ebp) +fcompl -1220(%ebp) +fstsw %ax +sahf +jp .LC338 +jne .LC338 +fldl One +subl $8,%esp +fstpl (%esp) +call sqrt +addl $8,%esp +fstpl -1244(%ebp) +fldl -1244(%ebp) +fcompl One +fstsw %ax +sahf +jp .LC338 +jne .LC338 +movl $1,-1196(%ebp) +jmp .LC339 +.LC338: +movl $0,-1196(%ebp) +.LC339: +pushl $.LC337 +pushl -1196(%ebp) +pushl $0 +call TstCond +addl $12,%esp +fldl Zero +fstpl MinSqEr +fldl Zero +fstpl MaxSqEr +fldl Zero +fstpl J +fldl Radix +fstpl X +fldl U2 +fstpl OneUlp +pushl $1 +call SqXMinX +addl $4,%esp +fldl BInvrse +fstpl X +fldl BInvrse +fmull U1 +fstpl OneUlp +pushl $1 +call SqXMinX +addl $4,%esp +fldl U1 +fstpl X +fldl U1 +fmull U1 +fstpl OneUlp +pushl $1 +call SqXMinX +addl $4,%esp +fldl Zero +fcompl J +fstsw %ax +sahf +jp 1f +je .LC340 +1: +call Pause +.LC340: +pushl NoTrials +pushl $.LC342 +call printf +addl $8,%esp +fldl Zero +fstpl J +fldl Two +fstpl X +fldl Radix +fstpl Y +fldl One +fcompl Radix +fstsw %ax +sahf +jp 1f +je .LC343 +1: +.LC345: +fldl Y +fstpl -1284(%ebp) +fldl -1284(%ebp) +fstpl X +fldl Radix +fmull -1284(%ebp) +fstpl Y +.LC346: +fldl Y +fsubl X +fildl NoTrials +fcompp +fstsw %ax +sahf +jp .LC345 +ja .LC345 +.LC343: +fldl X +fmull U2 +fstpl OneUlp +movl $1,I +jmp .LC349 +.LC348: +fldl X +faddl One +fstpl X +pushl $2 +call SqXMinX +addl $4,%esp +fldl Zero +fcompl J +fstsw %ax +sahf +jp .LC351 +jae .LC351 +jmp .LC350 +.LC351: +incl I +.LC349: +movl NoTrials,%edi +cmpl %edi,I +jle .LC348 +.LC350: +pushl $.LC353 +call printf +addl $4,%esp +movl $-1,I +fldl BMinusU2 +fstpl X +fldl Radix +fstpl Y +fldl Radix +fldl Radix +fmull U2 +faddp %st,%st(1) +fstpl Z +movl $0,NotMonot +movl $0,Monot +jmp .LC355 +.LC354: +incl I +fldl X +subl $8,%esp +fstpl (%esp) +call sqrt +addl $8,%esp +fstpl -1292(%ebp) +fldl -1292(%ebp) +fstpl X +fldl Y +subl $8,%esp +fstpl (%esp) +call sqrt +addl $8,%esp +fstpl -1300(%ebp) +fldl -1300(%ebp) +fstpl Q +fldl Z +subl $8,%esp +fstpl (%esp) +call sqrt +addl $8,%esp +fstpl -1308(%ebp) +fldl -1308(%ebp) +fstpl Z +fldl Q +fcompl X +fstsw %ax +sahf +jp .LC359 +jb .LC359 +fldl Z +fcompl Q +fstsw %ax +sahf +jp .LC357 +jae .LC357 +.LC359: +movl $1,NotMonot +jmp .LC358 +.LC357: +fldl Q +faddl Half +subl $8,%esp +fstpl (%esp) +call floor +addl $8,%esp +fstpl -1324(%ebp) +fldl -1324(%ebp) +fstpl Q +cmpl $0,I +jg .LC362 +fldl Q +fmull Q +fcompl Radix +fstsw %ax +sahf +jp .LC360 +jne .LC360 +.LC362: +movl $1,Monot +jmp .LC361 +.LC360: +cmpl $0,I +jle .LC363 +cmpl $1,I +jle .LC365 +movl $1,Monot +jmp .LC364 +.LC365: +fldl Y +fmull BInvrse +fstpl Y +fldl Y +fstpl -1340(%ebp) +fldl -1340(%ebp) +fsubl U1 +fstpl X +fldl -1340(%ebp) +faddl U1 +fstpl Z +jmp .LC364 +.LC363: +fldl Q +fstpl Y +fldl Y +fstpl -1340(%ebp) +fldl -1340(%ebp) +fsubl U2 +fstpl X +fldl -1340(%ebp) +faddl U2 +fstpl Z +.LC364: +.LC361: +.LC358: +.LC355: +cmpl $0,NotMonot +jne .LC367 +cmpl $0,Monot +je .LC354 +.LC367: +cmpl $0,Monot +je .LC368 +pushl $.LC370 +call printf +addl $4,%esp +jmp .LC369 +.LC368: +pushl $.LC158 +pushl $2 +call BadCond +addl $8,%esp +fldl Y +subl $8,%esp +fstpl (%esp) +pushl $.LC371 +call printf +addl $12,%esp +.LC369: +movl $80,Milestone +fldl MinSqEr +faddl Half +fstpl MinSqEr +fldl MaxSqEr +fsubl Half +fstpl MaxSqEr +fldl One +faddl U2 +subl $8,%esp +fstpl (%esp) +call sqrt +addl $8,%esp +fstpl -1300(%ebp) +fldl -1300(%ebp) +fsubl One +fdivl U2 +fstpl Y +fldl Y +fsubl One +fldl U2 +fdivl Eight +faddp %st,%st(1) +fstpl SqEr +fldl MaxSqEr +fcompl SqEr +fstsw %ax +sahf +jp .LC372 +jae .LC372 +fldl SqEr +fstpl MaxSqEr +.LC372: +fldl Y +fldl U2 +fdivl Eight +faddp %st,%st(1) +fstpl SqEr +fldl MinSqEr +fcompl SqEr +fstsw %ax +sahf +jp .LC374 +jbe .LC374 +fldl SqEr +fstpl MinSqEr +.LC374: +fldl F9 +subl $8,%esp +fstpl (%esp) +call sqrt +addl $8,%esp +fstpl -1324(%ebp) +fldl -1324(%ebp) +fsubl U2 +fldl One +fsubl U2 +fsubrp %st,%st(1) +fdivl U1 +fstpl Y +fldl Y +fldl U1 +fdivl Eight +faddp %st,%st(1) +fstpl SqEr +fldl MaxSqEr +fcompl SqEr +fstsw %ax +sahf +jp .LC376 +jae .LC376 +fldl SqEr +fstpl MaxSqEr +.LC376: +fldl Y +faddl One +fldl U1 +fdivl Eight +faddp %st,%st(1) +fstpl SqEr +fldl MinSqEr +fcompl SqEr +fstsw %ax +sahf +jp .LC378 +jbe .LC378 +fldl SqEr +fstpl MinSqEr +.LC378: +fldl U2 +fstpl OneUlp +fldl OneUlp +fstpl X +movl $1,Indx +.LC380: +fldl X +faddl U1 +faddl X +faddl F9 +subl $8,%esp +fstpl (%esp) +call sqrt +addl $8,%esp +fstpl -1356(%ebp) +fldl -1356(%ebp) +fstpl Y +fldl Y +fsubl U2 +fldl One +fsubl U2 +faddl X +fsubrp %st,%st(1) +fdivl OneUlp +fstpl Y +fldl U1 +fsubl X +faddl F9 +fmull Half +fmull X +fmull X +fdivl OneUlp +fstpl Z +fldl Y +faddl Half +faddl Z +fstpl SqEr +fldl MinSqEr +fcompl SqEr +fstsw %ax +sahf +jp .LC384 +jbe .LC384 +fldl SqEr +fstpl MinSqEr +.LC384: +fldl Y +fsubl Half +faddl Z +fstpl SqEr +fldl MaxSqEr +fcompl SqEr +fstsw %ax +sahf +jp .LC386 +jae .LC386 +fldl SqEr +fstpl MaxSqEr +.LC386: +movl Indx,%edi +cmpl $1,%edi +je .LC390 +cmpl $3,%edi +jne .LC388 +.LC390: +fldl X +subl $8,%esp +fstpl (%esp) +call Sign +addl $8,%esp +fstpl -1396(%ebp) +fldl OneUlp +subl $8,%esp +fstpl (%esp) +call sqrt +addl $8,%esp +fstpl -1404(%ebp) +fldl Eight +fldl Nine +fmull -1404(%ebp) +fdivrp %st,%st(1) +subl $8,%esp +fstpl (%esp) +call floor +addl $8,%esp +fstpl -1412(%ebp) +fldl OneUlp +fmull -1396(%ebp) +fmull -1412(%ebp) +fstpl X +jmp .LC389 +.LC388: +fldl U1 +fstpl OneUlp +fldl OneUlp +fchs +fstpl X +.LC389: +.LC381: +incl Indx +cmpl $3,Indx +jle .LC380 +movl $85,Milestone +movl $0,SqRWrng +movl $0,Anomaly +movl $0,RSqrt +fldl One +fcompl Radix +fstsw %ax +sahf +jp 1f +je .LC391 +1: +pushl $.LC393 +call printf +addl $4,%esp +fldl Precision +subl $8,%esp +fstpl (%esp) +call floor +addl $8,%esp +fstpl -1356(%ebp) +fldl One +faddl Precision +fsubl -1356(%ebp) +subl $8,%esp +fstpl (%esp) +fldl Radix +subl $8,%esp +fstpl (%esp) +call pow +addl $16,%esp +fstpl -1364(%ebp) +fldl Half +faddl -1364(%ebp) +subl $8,%esp +fstpl (%esp) +call floor +addl $8,%esp +fstpl -1372(%ebp) +fldl -1372(%ebp) +fstpl D +fldl D +fdivl Radix +fstpl X +fldl D +fdivl A1 +fstpl Y +fldl X +subl $8,%esp +fstpl (%esp) +call floor +addl $8,%esp +fstpl -1396(%ebp) +fldl -1396(%ebp) +fcompl X +fstsw %ax +sahf +jp .LC396 +jne .LC396 +fldl Y +subl $8,%esp +fstpl (%esp) +call floor +addl $8,%esp +fstpl -1412(%ebp) +fldl -1412(%ebp) +fcompl Y +fstsw %ax +sahf +jp 1f +je .LC394 +1: +.LC396: +movl $1,Anomaly +jmp .LC395 +.LC394: +fldl Zero +fstpl X +fldl X +fstpl Z2 +fldl One +fstpl Y +fldl Y +fstpl Y2 +fldl Radix +fsubl One +fstpl Z1 +fldl Four +fmull D +fstpl FourD +.LC397: +fldl Z2 +fcompl Y2 +fstsw %ax +sahf +jp .LC400 +jae .LC400 +fldl Radix +fstpl Q +fldl Y +fstpl Y1 +.LC402: +fldl Half +fldl Q +fdivl Y1 +fsubrp %st,%st(1) +subl $8,%esp +fstpl (%esp) +call floor +addl $8,%esp +fstpl -1436(%ebp) +fldl Q +fldl -1436(%ebp) +fmull Y1 +faddp %st,%st(1) +subl $8,%esp +fstpl (%esp) +call fabs +addl $8,%esp +fstpl -1444(%ebp) +fldl -1444(%ebp) +fstpl X1 +fldl Y1 +fstpl Q +fldl X1 +fstpl Y1 +.LC403: +fldl Zero +fcompl X1 +fstsw %ax +sahf +jp .LC402 +jb .LC402 +fldl One +fcompl Q +fstsw %ax +sahf +jp .LC405 +jb .LC405 +fldl Y2 +fstpl Z2 +fldl Y +fstpl Z +.LC405: +.LC400: +fldl Y +faddl Two +fstpl Y +fldl X +faddl Eight +fstpl X +fldl Y2 +faddl X +fstpl Y2 +fldl FourD +fcompl Y2 +fstsw %ax +sahf +jp .LC407 +ja .LC407 +fldl Y2 +fsubl FourD +fstpl Y2 +.LC407: +.LC398: +fldl D +fcompl Y +fstsw %ax +sahf +jp .LC397 +ja .LC397 +fldl FourD +fsubl Z2 +fstpl X8 +fldl X8 +fstpl -1436(%ebp) +fldl -1436(%ebp) +fldl Z +fmull Z +faddp %st,%st(1) +fdivl FourD +fstpl Q +fldl -1436(%ebp) +fdivl Eight +fstpl X8 +fldl Q +fstpl -1452(%ebp) +fldl -1452(%ebp) +subl $8,%esp +fstpl (%esp) +call floor +addl $8,%esp +fstpl -1460(%ebp) +fldl -1460(%ebp) +fcompl -1452(%ebp) +fstsw %ax +sahf +jp 1f +je .LC409 +1: +movl $1,Anomaly +jmp .LC410 +.LC409: +movl $0,Break +.LC411: +fldl Z1 +fmull Z +fstpl X +fldl X +fstpl -1468(%ebp) +fldl -1468(%ebp) +fdivl Radix +subl $8,%esp +fstpl (%esp) +call floor +addl $8,%esp +fstpl -1476(%ebp) +fldl -1468(%ebp) +fldl -1476(%ebp) +fmull Radix +fsubrp %st,%st(1) +fstpl X +fldl One +fcompl X +fstsw %ax +sahf +jp .LC414 +jne .LC414 +movl $1,Break +jmp .LC415 +.LC414: +fldl Z1 +fsubl One +fstpl Z1 +.LC415: +.LC412: +cmpl $0,Break +jne .LC416 +fldl Zero +fcompl Z1 +fstsw %ax +sahf +jp .LC411 +jb .LC411 +.LC416: +fldl Zero +fcompl Z1 +fstsw %ax +sahf +jp .LC417 +jb .LC417 +cmpl $0,Break +jne .LC417 +movl $1,Anomaly +jmp .LC418 +.LC417: +fldl RadixD2 +fcompl Z1 +fstsw %ax +sahf +jp .LC419 +jae .LC419 +fldl Z1 +fsubl Radix +fstpl Z1 +.LC419: +.LC421: +call NewD +.LC422: +fldl U2 +fmull D +fldl F9 +fcompp +fstsw %ax +sahf +jp .LC421 +ja .LC421 +fldl D +fmull Radix +fsubl D +fldl W +fsubl D +fcompp +fstsw %ax +sahf +jp 1f +je .LC424 +1: +movl $1,Anomaly +jmp .LC425 +.LC424: +fldl D +fstpl Z2 +movl $0,I +fldl D +fldl One +faddl Z +fmull Half +faddp %st,%st(1) +fstpl Y +fldl D +faddl Z +faddl Q +fstpl X +call SR3750 +fldl D +fldl One +fsubl Z +fmull Half +faddp %st,%st(1) +faddl D +fstpl Y +fldl D +fsubl Z +faddl D +fstpl X +fldl X +fstpl -1508(%ebp) +fldl -1508(%ebp) +faddl Q +faddl -1508(%ebp) +fstpl X +call SR3750 +call NewD +fldl D +fsubl Z2 +fldl W +fsubl Z2 +fcompp +fstsw %ax +sahf +jp 1f +je .LC426 +1: +movl $1,Anomaly +jmp .LC427 +.LC426: +fldl D +fsubl Z2 +fstpl -1532(%ebp) +fldl -1532(%ebp) +fldl Z2 +fldl One +fsubl Z +fmull Half +faddp %st,%st(1) +faddp %st,%st(1) +fstpl Y +fldl -1532(%ebp) +fldl Z2 +fsubl Z +faddl Q +faddp %st,%st(1) +fstpl X +call SR3750 +fldl One +faddl Z +fmull Half +fstpl Y +fldl Q +fstpl X +call SR3750 +cmpl $0,I +jne .LC428 +movl $1,Anomaly +.LC428: +.LC427: +.LC425: +.LC418: +.LC410: +.LC395: +cmpl $0,I +je .LC432 +cmpl $0,Anomaly +je .LC430 +.LC432: +pushl $.LC433 +pushl $0 +call BadCond +addl $8,%esp +fldl W +subl $8,%esp +fstpl (%esp) +pushl $.LC434 +call printf +addl $12,%esp +pushl $.LC435 +call printf +addl $4,%esp +movl $1,SqRWrng +.LC430: +.LC391: +cmpl $0,Anomaly +jne .LC436 +fldl Zero +fcompl MinSqEr +fstsw %ax +sahf +jp .LC438 +ja .LC438 +fldl Zero +fcompl MaxSqEr +fstsw %ax +sahf +jp .LC438 +jb .LC438 +movl $1,RSqrt +pushl $.LC440 +call printf +addl $4,%esp +jmp .LC439 +.LC438: +fldl MaxSqEr +faddl U2 +fldl U2 +fsubl Half +fcompp +fstsw %ax +sahf +jp .LC444 +jb .LC444 +fldl Half +fcompl MinSqEr +fstsw %ax +sahf +jp .LC444 +jb .LC444 +fldl MinSqEr +faddl Radix +fldl Half +fcompp +fstsw %ax +sahf +jp .LC441 +jbe .LC441 +.LC444: +movl $1,SqRWrng +jmp .LC442 +.LC441: +movl $2,RSqrt +pushl $.LC445 +call printf +addl $4,%esp +.LC442: +.LC439: +.LC436: +cmpl $0,SqRWrng +je .LC446 +pushl $.LC448 +call printf +addl $4,%esp +fldl MinSqEr +fsubl Half +subl $8,%esp +fstpl (%esp) +pushl $.LC449 +call printf +addl $12,%esp +fldl Half +faddl MaxSqEr +subl $8,%esp +fstpl (%esp) +pushl $.LC450 +call printf +addl $12,%esp +pushl $.LC452 +fldl MaxSqEr +fsubl MinSqEr +fldl Radix +fmull Radix +fcompp +fstsw %ax +sahf +jp .LC453 +jbe .LC453 +movl $1,-1344(%ebp) +jmp .LC454 +.LC453: +movl $0,-1344(%ebp) +.LC454: +pushl -1344(%ebp) +pushl $1 +call TstCond +addl $12,%esp +.LC446: +movl $90,Milestone +call Pause +pushl $.LC455 +call printf +addl $4,%esp +movl $0,N +movl $0,I +fldl Zero +fchs +fstpl Z +movl $3,M +movl $0,Break +.LC456: +fldl One +fstpl X +call SR3980 +cmpl $10,I +jg .LC459 +movl $1023,I +call SR3980 +.LC459: +fldl MinusOne +fcompl Z +fstsw %ax +sahf +jp .LC461 +jne .LC461 +movl $1,Break +jmp .LC462 +.LC461: +fldl MinusOne +fstpl Z +call PrintIfNPositive +movl $0,N +movl $-4,I +.LC462: +.LC457: +cmpl $0,Break +je .LC456 +call PrintIfNPositive +movl N,%edi +movl %edi,N1 +movl $0,N +fldl A1 +fstpl Z +fldl W +subl $8,%esp +fstpl (%esp) +call log +addl $8,%esp +fstpl -1348(%ebp) +fldl A1 +subl $8,%esp +fstpl (%esp) +call log +addl $8,%esp +fstpl -1356(%ebp) +fldl Two +fmull -1348(%ebp) +fdivl -1356(%ebp) +subl $8,%esp +fstpl (%esp) +call floor +addl $8,%esp +fstpl -1364(%ebp) +fldl -1364(%ebp) +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,M +movl $0,Break +.LC463: +fldl Z +fstpl X +movl $1,I +call SR3980 +fldl AInvrse +fcompl Z +fstsw %ax +sahf +jp .LC466 +jne .LC466 +movl $1,Break +jmp .LC467 +.LC466: +fldl AInvrse +fstpl Z +.LC467: +.LC464: +cmpl $0,Break +je .LC463 +movl $100,Milestone +movl NoTrials,%edi +movl %edi,M +fldl Three +fstpl Z +.LC468: +fldl Z +fstpl X +movl $1,I +call SR3980 +.LC471: +fldl Z +faddl Two +fstpl Z +.LC472: +fldl Z +fdivl Three +subl $8,%esp +fstpl (%esp) +call floor +addl $8,%esp +fstpl -1380(%ebp) +fldl Three +fmull -1380(%ebp) +fldl Z +fcompp +fstsw %ax +sahf +jp 1f +je .LC471 +1: +.LC469: +fldl Eight +fmull Three +fcompl Z +fstsw %ax +sahf +jp .LC468 +ja .LC468 +cmpl $0,N +jle .LC474 +pushl $.LC476 +call printf +addl $4,%esp +pushl $.LC477 +call printf +addl $4,%esp +.LC474: +call PrintIfNPositive +movl N1,%edi +addl %edi,N +cmpl $0,N +jne .LC478 +pushl $.LC480 +call printf +addl $4,%esp +.LC478: +cmpl $0,N +jle .LC481 +call Pause +jmp .LC482 +.LC481: +pushl $.LC45 +call printf +addl $4,%esp +.LC482: +movl $110,Milestone +pushl $.LC483 +call printf +addl $4,%esp +fldl U1 +fstpl D +fldl Precision +subl $8,%esp +fstpl (%esp) +call floor +addl $8,%esp +fstpl -1380(%ebp) +fldl -1380(%ebp) +fcompl Precision +fstsw %ax +sahf +jp 1f +je .LC484 +1: +fldl BInvrse +fstpl D +fldl Precision +fstpl X +.LC486: +fldl D +fmull BInvrse +fstpl D +fldl X +fsubl One +fstpl X +.LC487: +fldl Zero +fcompl X +fstsw %ax +sahf +jp .LC486 +jb .LC486 +.LC484: +fldl One +fstpl Y +fldl D +fstpl Z +.LC489: +fldl Y +fstpl C +fldl Z +fstpl Y +fldl Y +fstpl -1388(%ebp) +fldl -1388(%ebp) +fmull -1388(%ebp) +fstpl Z +.LC490: +fldl Z +fcompl Y +fstsw %ax +sahf +jp .LC492 +jae .LC492 +fldl Z +faddl Z +fldl Z +fcompp +fstsw %ax +sahf +jp .LC489 +jb .LC489 +.LC492: +fldl C +fstpl Y +fldl Y +fmull D +fstpl Z +.LC493: +fldl Y +fstpl C +fldl Z +fstpl Y +fldl Y +fmull D +fstpl Z +.LC494: +fldl Z +fcompl Y +fstsw %ax +sahf +jp .LC496 +jae .LC496 +fldl Z +faddl Z +fldl Z +fcompp +fstsw %ax +sahf +jp .LC493 +jb .LC493 +.LC496: +fldl Two +fcompl Radix +fstsw %ax +sahf +jp .LC497 +jbe .LC497 +fldl Two +fstpl HInvrse +jmp .LC498 +.LC497: +fldl Radix +fstpl HInvrse +.LC498: +fldl One +fdivl HInvrse +fstpl H +fldl One +fdivl C +fstpl CInvrse +fldl C +fstpl E0 +fldl E0 +fmull H +fstpl Z +.LC499: +fldl E0 +fstpl Y +fldl Z +fstpl E0 +fldl E0 +fmull H +fstpl Z +.LC500: +fldl Z +fcompl E0 +fstsw %ax +sahf +jp .LC502 +jae .LC502 +fldl Z +faddl Z +fldl Z +fcompp +fstsw %ax +sahf +jp .LC499 +jb .LC499 +.LC502: +fldl E0 +fstpl UfThold +fldl Zero +fstpl E1 +fldl Zero +fstpl Q +fldl U2 +fstpl E9 +fldl One +faddl E9 +fstpl S +fldl C +fmull S +fstpl D +fldl C +fcompl D +fstsw %ax +sahf +jp .LC503 +jb .LC503 +fldl Radix +fmull U2 +fstpl E9 +fldl One +faddl E9 +fstpl S +fldl C +fmull S +fstpl D +fldl C +fcompl D +fstsw %ax +sahf +jp .LC504 +jb .LC504 +pushl $.LC507 +pushl $0 +call BadCond +addl $8,%esp +fldl E0 +fstpl Underflow +fldl Zero +fstpl Y1 +fldl Z +fstpl PseudoZero +call Pause +jmp .LC504 +.LC503: +fldl D +fstpl Underflow +fldl Underflow +fmull H +fstpl PseudoZero +fldl Zero +fstpl UfThold +.LC508: +fldl Underflow +fstpl Y1 +fldl PseudoZero +fstpl Underflow +fldl E1 +faddl E1 +fldl E1 +fcompp +fstsw %ax +sahf +jp .LC511 +jb .LC511 +fldl Underflow +fmull HInvrse +fstpl Y2 +fldl Y1 +fsubl Y2 +subl $8,%esp +fstpl (%esp) +call fabs +addl $8,%esp +fstpl -1452(%ebp) +fldl -1452(%ebp) +fstpl E1 +fldl Y1 +fstpl Q +fldl Zero +fcompl UfThold +fstsw %ax +sahf +jp .LC513 +jne .LC513 +fldl Y2 +fcompl Y1 +fstsw %ax +sahf +jp 1f +je .LC513 +1: +fldl Y1 +fstpl UfThold +.LC513: +.LC511: +fldl PseudoZero +fmull H +fstpl PseudoZero +.LC509: +fldl PseudoZero +fcompl Underflow +fstsw %ax +sahf +jp .LC515 +jae .LC515 +fldl PseudoZero +faddl PseudoZero +fldl PseudoZero +fcompp +fstsw %ax +sahf +jp .LC508 +jb .LC508 +.LC515: +.LC504: +fldl Zero +fcompl PseudoZero +fstsw %ax +sahf +jp 1f +je .LC516 +1: +pushl $.LC45 +call printf +addl $4,%esp +fldl PseudoZero +fstpl Z +fldl Zero +fcompl PseudoZero +fstsw %ax +sahf +jp .LC518 +jb .LC518 +pushl $.LC520 +pushl $0 +call BadCond +addl $8,%esp +pushl $.LC521 +call printf +addl $4,%esp +fldl PseudoZero +subl $8,%esp +fstpl (%esp) +pushl $.LC522 +call printf +addl $12,%esp +fldl PseudoZero +fchs +fstpl X +fldl Zero +fcompl X +fstsw %ax +sahf +jp .LC519 +jb .LC519 +pushl $.LC525 +call printf +addl $4,%esp +fldl X +subl $8,%esp +fstpl (%esp) +pushl $.LC526 +call printf +addl $12,%esp +jmp .LC519 +.LC518: +pushl $.LC527 +pushl $3 +call BadCond +addl $8,%esp +fldl PseudoZero +subl $8,%esp +fstpl (%esp) +pushl $.LC528 +call printf +addl $12,%esp +.LC519: +call TstPtUf +.LC516: +movl $120,Milestone +fldl CInvrse +fmull Y +fldl CInvrse +fmull Y1 +fcompp +fstsw %ax +sahf +jp .LC529 +jae .LC529 +fldl H +fmull S +fstpl S +fldl Underflow +fstpl E0 +.LC529: +fldl Zero +fcompl E1 +fstsw %ax +sahf +jp 1f +je .LC531 +1: +fldl E0 +fcompl E1 +fstsw %ax +sahf +jp 1f +je .LC531 +1: +pushl $.LC158 +pushl $2 +call BadCond +addl $8,%esp +fldl E0 +fcompl E1 +fstsw %ax +sahf +jp .LC533 +jbe .LC533 +pushl $.LC535 +call printf +addl $4,%esp +pushl $.LC536 +call printf +addl $4,%esp +fldl Zero +fcompl PseudoZero +fstsw %ax +sahf +jp .LC534 +jne .LC534 +fldl E1 +fstpl E0 +jmp .LC534 +.LC533: +pushl $.LC539 +call printf +addl $4,%esp +pushl $.LC540 +call printf +addl $4,%esp +.LC534: +.LC531: +fldl E0 +subl $8,%esp +fstpl (%esp) +pushl $.LC541 +call printf +addl $12,%esp +fldl E0 +fstpl Z +call TstPtUf +fldl E0 +fstpl Underflow +cmpl $1,N +jne .LC542 +fldl Y +fstpl Underflow +.LC542: +movl $4,I +fldl Zero +fcompl E1 +fstsw %ax +sahf +jp .LC544 +jne .LC544 +movl $3,I +.LC544: +fldl Zero +fcompl UfThold +fstsw %ax +sahf +jp .LC546 +jne .LC546 +subl $2,I +.LC546: +movl $1,UfNGrad +movl I,%edi +cmpl $1,%edi +jl .LC548 +cmpl $4,%edi +jg .LC548 +jmp *.LC571-4(,%edi,4) +.data +.align 4 +.LC571: +.long .LC550 +.long .LC557 +.long .LC562 +.long .LC563 +.text +.LC550: +fldl Underflow +fstpl UfThold +fldl CInvrse +fmull Q +fldl CInvrse +fmull Y +fmull S +fcompp +fstsw %ax +sahf +jp 1f +je .LC551 +1: +fldl Y +fstpl UfThold +pushl $.LC553 +pushl $0 +call BadCond +addl $8,%esp +fldl UfThold +subl $8,%esp +fstpl (%esp) +pushl $.LC554 +call printf +addl $12,%esp +fldl C +subl $8,%esp +fstpl (%esp) +pushl $.LC555 +call printf +addl $12,%esp +pushl $.LC556 +call printf +addl $4,%esp +.LC551: +call Pause +jmp .LC549 +.LC557: +pushl $.LC558 +pushl $0 +call BadCond +addl $8,%esp +pushl $.LC559 +call printf +addl $4,%esp +fldl Y2 +subl $8,%esp +fstpl (%esp) +fldl Q +subl $8,%esp +fstpl (%esp) +pushl $.LC560 +call printf +addl $20,%esp +fldl Q +fsubl Y2 +subl $8,%esp +fstpl (%esp) +call fabs +addl $8,%esp +fstpl -1468(%ebp) +fldl -1468(%ebp) +subl $8,%esp +fstpl (%esp) +pushl $.LC561 +call printf +addl $12,%esp +fldl Q +fstpl UfThold +jmp .LC549 +.LC562: +fldl X +fstpl X +jmp .LC549 +.LC563: +fldl UfThold +fcompl Q +fstsw %ax +sahf +jp .LC564 +jne .LC564 +fldl E0 +fcompl E1 +fstsw %ax +sahf +jp .LC564 +jne .LC564 +fldl UfThold +fldl E1 +fdivl E9 +fsubrp %st,%st(1) +subl $8,%esp +fstpl (%esp) +call fabs +addl $8,%esp +fstpl -1492(%ebp) +fldl E1 +fcompl -1492(%ebp) +fstsw %ax +sahf +jp .LC564 +jb .LC564 +movl $0,UfNGrad +pushl $.LC566 +call printf +addl $4,%esp +pushl $.LC567 +call printf +addl $4,%esp +fldl E0 +fmull CInvrse +fstpl Y +fldl Y +fldl OneAndHalf +faddl U2 +fmulp %st,%st(1) +fstpl Y +fldl CInvrse +fldl One +faddl U2 +fmulp %st,%st(1) +fstpl X +fldl Y +fdivl X +fstpl Y +fldl E0 +fcompl Y +fstsw %ax +sahf +jp .LC569 +jne .LC569 +movl $1,-1496(%ebp) +jmp .LC570 +.LC569: +movl $0,-1496(%ebp) +.LC570: +movl -1496(%ebp),%edi +movl %edi,IEEE +.LC564: +.LC548: +.LC549: +cmpl $0,UfNGrad +je .LC573 +pushl $.LC45 +call printf +addl $4,%esp +leal sigfpe,%edi +movl %edi,sigsave +pushl $ovfl_buf +call _setjmp +addl $4,%esp +cmpl $0,%eax +je .LC575 +pushl $.LC577 +call printf +addl $4,%esp +fldl H +faddl H +fstpl R +jmp .LC576 +.LC575: +fldl Underflow +fdivl UfThold +subl $8,%esp +fstpl (%esp) +call sqrt +addl $8,%esp +fstpl -1460(%ebp) +fldl -1460(%ebp) +fstpl R +.LC576: +movl $0,sigsave +fldl H +fcompl R +fstsw %ax +sahf +jp .LC578 +jb .LC578 +fldl R +fmull UfThold +fstpl Z +fldl Z +fldl One +fldl R +fmull H +fldl One +faddl H +fmulp %st,%st(1) +faddp %st,%st(1) +fmulp %st,%st(1) +fstpl X +jmp .LC579 +.LC578: +fldl UfThold +fstpl Z +fldl Z +fldl One +fldl H +fmull H +fldl One +faddl H +fmulp %st,%st(1) +faddp %st,%st(1) +fmulp %st,%st(1) +fstpl X +.LC579: +fldl Z +fcompl X +fstsw %ax +sahf +jp 1f +je .LC580 +1: +fldl X +fsubl Z +fldl Zero +fcompp +fstsw %ax +sahf +jp .LC580 +jne .LC580 +pushl $.LC158 +pushl $3 +call BadCond +addl $8,%esp +fldl Z +subl $8,%esp +fstpl (%esp) +fldl X +subl $8,%esp +fstpl (%esp) +pushl $.LC582 +call printf +addl $20,%esp +fldl X +fsubl Z +fstpl Z9 +fldl Z9 +subl $8,%esp +fstpl (%esp) +pushl $.LC583 +call printf +addl $12,%esp +pushl $.LC584 +call printf +addl $4,%esp +pushl $.LC585 +call printf +addl $4,%esp +pushl $.LC586 +call printf +addl $4,%esp +pushl $.LC587 +call printf +addl $4,%esp +pushl $.LC588 +call printf +addl $4,%esp +pushl $.LC589 +call printf +addl $4,%esp +leal sigfpe,%edi +movl %edi,sigsave +pushl $ovfl_buf +call _setjmp +addl $4,%esp +cmpl $0,%eax +je .LC590 +pushl $.LC592 +call printf +addl $4,%esp +jmp .LC591 +.LC590: +fldl X +fdivl Z +fsubl Half +fsubl Half +subl $8,%esp +fstpl (%esp) +pushl $.LC593 +call printf +addl $12,%esp +.LC591: +movl $0,sigsave +.LC580: +.LC573: +pushl $.LC595 +fldl UfThold +subl $8,%esp +fstpl (%esp) +pushl $.LC594 +call printf +addl $16,%esp +pushl $.LC596 +call printf +addl $4,%esp +pushl $.LC597 +call printf +addl $4,%esp +fldl U1 +fmull U1 +fstpl Y2 +fldl Y2 +fstpl -1468(%ebp) +fldl -1468(%ebp) +fmull -1468(%ebp) +fstpl Y +fldl Y +fmull U1 +fstpl Y2 +fldl UfThold +fcompl Y2 +fstsw %ax +sahf +jp .LC598 +jb .LC598 +fldl E0 +fcompl Y +fstsw %ax +sahf +jp .LC600 +jae .LC600 +pushl $.LC158 +pushl $2 +call BadCond +addl $8,%esp +movl $5,I +jmp .LC601 +.LC600: +pushl $.LC158 +pushl $1 +call BadCond +addl $8,%esp +movl $4,I +.LC601: +pushl I +pushl $.LC602 +call printf +addl $8,%esp +.LC598: +movl $130,Milestone +fldl UfThold +subl $8,%esp +fstpl (%esp) +call log +addl $8,%esp +fstpl -1476(%ebp) +fldl HInvrse +subl $8,%esp +fstpl (%esp) +call log +addl $8,%esp +fstpl -1484(%ebp) +fldl Half +fldl TwoForty +fmull -1476(%ebp) +fdivl -1484(%ebp) +fsubrp %st,%st(1) +subl $8,%esp +fstpl (%esp) +call floor +addl $8,%esp +fstpl -1492(%ebp) +fldl -1492(%ebp) +fchs +fdivl TwoForty +fstpl Y +fldl Y +faddl Y +fstpl Y2 +pushl $.LC603 +call printf +addl $4,%esp +fldl Y +subl $8,%esp +fstpl (%esp) +fldl HInvrse +subl $8,%esp +fstpl (%esp) +pushl $.LC604 +call printf +addl $20,%esp +fldl Y +subl $8,%esp +fstpl (%esp) +fldl HInvrse +subl $8,%esp +fstpl (%esp) +pushl $.LC605 +call printf +addl $20,%esp +fldl Y2 +subl $8,%esp +fstpl (%esp) +fldl HInvrse +subl $8,%esp +fstpl (%esp) +call pow +addl $16,%esp +fstpl -1508(%ebp) +fldl -1508(%ebp) +fstpl V9 +fldl V9 +subl $8,%esp +fstpl (%esp) +pushl $.LC606 +call printf +addl $12,%esp +fldl Zero +fcompl V9 +fstsw %ax +sahf +jp .LC609 +ja .LC609 +fldl Radix +faddl Radix +faddl E9 +fmull UfThold +fcompl V9 +fstsw %ax +sahf +jp .LC607 +jae .LC607 +.LC609: +pushl $.LC610 +pushl $1 +call BadCond +addl $8,%esp +fldl UfThold +subl $8,%esp +fstpl (%esp) +pushl $.LC611 +call printf +addl $12,%esp +jmp .LC608 +.LC607: +fldl UfThold +fldl One +faddl E9 +fmulp %st,%st(1) +fcompl V9 +fstsw %ax +sahf +jp .LC612 +jb .LC612 +pushl $.LC614 +call printf +addl $4,%esp +jmp .LC613 +.LC612: +pushl $.LC610 +pushl $2 +call BadCond +addl $8,%esp +fldl UfThold +subl $8,%esp +fstpl (%esp) +pushl $.LC611 +call printf +addl $12,%esp +.LC613: +.LC608: +movl $140,Milestone +pushl $.LC45 +call printf +addl $4,%esp +fldl Zero +fstpl X +movl $2,I +fldl Two +fmull Three +fstpl Y +fldl Zero +fstpl Q +movl $0,N +.LC615: +fldl X +fstpl Z +incl I +movl I,%edi +fldl Y +leal (%edi,%edi),%edi +pushl %edi +fildl (%esp) +addl $4,%esp +fdivrp %st,%st(1) +fstpl Y +fldl Y +faddl Q +fstpl R +fldl Z +fstpl -1540(%ebp) +fldl R +fstpl -1548(%ebp) +fldl -1540(%ebp) +faddl -1548(%ebp) +fstpl X +fldl -1540(%ebp) +fsubl X +faddl -1548(%ebp) +fstpl Q +.LC616: +fldl Z +fcompl X +fstsw %ax +sahf +jp .LC615 +jb .LC615 +fldl OneAndHalf +fldl One +fdivl Eight +faddp %st,%st(1) +fldl X +fldl OneAndHalf +fmull ThirtyTwo +fdivrp %st,%st(1) +faddp %st,%st(1) +fstpl Z +fldl Z +fstpl -1548(%ebp) +fldl -1548(%ebp) +fmull -1548(%ebp) +fstpl X +fldl X +fstpl -1556(%ebp) +fldl -1556(%ebp) +fmull -1556(%ebp) +fstpl Exp2 +fldl F9 +fstpl X +fldl X +fsubl U1 +fstpl Y +fldl Exp2 +subl $8,%esp +fstpl (%esp) +pushl $.LC618 +call printf +addl $12,%esp +movl $1,I +.LC619: +fldl X +fsubl BInvrse +fstpl Z +fldl X +faddl One +fldl Z +fldl One +fsubl BInvrse +fsubrp %st,%st(1) +fdivrp %st,%st(1) +fstpl Z +fldl Z +subl $8,%esp +fstpl (%esp) +fldl X +subl $8,%esp +fstpl (%esp) +call pow +addl $16,%esp +fstpl -1588(%ebp) +fldl -1588(%ebp) +fsubl Exp2 +fstpl Q +fldl Q +subl $8,%esp +fstpl (%esp) +call fabs +addl $8,%esp +fstpl -1596(%ebp) +fldl TwoForty +fmull U2 +fcompl -1596(%ebp) +fstsw %ax +sahf +jp .LC623 +jae .LC623 +movl $1,N +fldl X +fsubl BInvrse +fldl One +fsubl BInvrse +fsubrp %st,%st(1) +fstpl V9 +pushl $.LC625 +pushl $2 +call BadCond +addl $8,%esp +fldl Z +subl $8,%esp +fstpl (%esp) +fldl X +subl $8,%esp +fstpl (%esp) +call pow +addl $16,%esp +fstpl -1612(%ebp) +fldl -1612(%ebp) +subl $8,%esp +fstpl (%esp) +pushl $.LC626 +call printf +addl $12,%esp +fldl Z +subl $8,%esp +fstpl (%esp) +fldl V9 +subl $8,%esp +fstpl (%esp) +pushl $.LC627 +call printf +addl $20,%esp +fldl Q +subl $8,%esp +fstpl (%esp) +pushl $.LC628 +call printf +addl $12,%esp +pushl $.LC629 +call printf +addl $4,%esp +pushl $.LC630 +call printf +addl $4,%esp +jmp .LC621 +.LC623: +fldl Y +fstpl -1604(%ebp) +fldl -1604(%ebp) +fsubl X +fmull Two +faddl -1604(%ebp) +fstpl Z +fldl -1604(%ebp) +fstpl X +fldl Z +fstpl Y +fldl X +fsubl F9 +fstpl -1612(%ebp) +fldl One +fldl -1612(%ebp) +fmull -1612(%ebp) +faddp %st,%st(1) +fstpl Z +fldl One +fcompl Z +fstsw %ax +sahf +jp .LC631 +jae .LC631 +movl NoTrials,%edi +cmpl %edi,I +jge .LC631 +incl I +jmp .LC619 +.LC631: +fldl One +fcompl X +fstsw %ax +sahf +jp .LC633 +jae .LC633 +cmpl $0,N +jne .LC621 +pushl $.LC637 +call printf +addl $4,%esp +jmp .LC621 +.LC633: +fldl One +faddl U2 +fstpl X +fldl U2 +faddl U2 +fstpl Y +fldl Y +faddl X +fstpl Y +movl $1,I +jmp .LC619 +.LC621: +movl $150,Milestone +pushl $.LC638 +call printf +addl $4,%esp +movl $0,N +fldl A1 +fstpl Z +fldl C +subl $8,%esp +fstpl (%esp) +call log +addl $8,%esp +fstpl -1564(%ebp) +fldl A1 +subl $8,%esp +fstpl (%esp) +call log +addl $8,%esp +fstpl -1572(%ebp) +fldl Half +fldl -1564(%ebp) +fdivl -1572(%ebp) +fsubrp %st,%st(1) +subl $8,%esp +fstpl (%esp) +call floor +addl $8,%esp +fstpl -1580(%ebp) +fldl -1580(%ebp) +fstpl Q +movl $0,Break +.LC639: +fldl CInvrse +fstpl X +fldl Q +subl $8,%esp +fstpl (%esp) +fldl Z +subl $8,%esp +fstpl (%esp) +call pow +addl $16,%esp +fstpl -1588(%ebp) +fldl -1588(%ebp) +fstpl Y +call IsYeqX +fldl Q +fchs +fstpl Q +fldl C +fstpl X +fldl Q +subl $8,%esp +fstpl (%esp) +fldl Z +subl $8,%esp +fstpl (%esp) +call pow +addl $16,%esp +fstpl -1596(%ebp) +fldl -1596(%ebp) +fstpl Y +call IsYeqX +fldl One +fcompl Z +fstsw %ax +sahf +jp .LC642 +jbe .LC642 +movl $1,Break +jmp .LC643 +.LC642: +fldl AInvrse +fstpl Z +.LC643: +.LC640: +cmpl $0,Break +je .LC639 +call PrintIfNPositive +cmpl $0,N +jne .LC644 +pushl $.LC646 +call printf +addl $4,%esp +.LC644: +pushl $.LC45 +call printf +addl $4,%esp +movl $160,Milestone +call Pause +pushl $.LC647 +call printf +addl $4,%esp +pushl $.LC648 +call printf +addl $4,%esp +fldl CInvrse +fchs +fstpl Y +fldl HInvrse +fmull Y +fstpl V9 +leal sigfpe,%edi +movl %edi,sigsave +pushl $ovfl_buf +call _setjmp +addl $4,%esp +cmpl $0,%eax +je .LC649 +movl $0,I +fldl Y +fstpl V9 +jmp .LC651 +.LC649: +.LC652: +fldl Y +fstpl V +fldl V9 +fstpl Y +fldl HInvrse +fmull Y +fstpl V9 +.LC653: +fldl Y +fcompl V9 +fstsw %ax +sahf +jp .LC652 +ja .LC652 +movl $1,I +.LC651: +movl $0,sigsave +fldl V9 +fstpl Z +pushl $.LC655 +call printf +addl $4,%esp +fldl Y +subl $8,%esp +fstpl (%esp) +pushl $.LC656 +call printf +addl $12,%esp +fldl Y +fchs +fstpl V9 +fldl V9 +fstpl V0 +fldl V +fsubl Y +fldl V +faddl V0 +fcompp +fstsw %ax +sahf +jp .LC657 +jne .LC657 +pushl $.LC659 +call printf +addl $4,%esp +jmp .LC658 +.LC657: +pushl $.LC660 +call printf +addl $4,%esp +pushl $.LC661 +pushl $3 +call BadCond +addl $8,%esp +.LC658: +fldl Y +fcompl Z +fstsw %ax +sahf +jp 1f +je .LC662 +1: +pushl $.LC158 +pushl $1 +call BadCond +addl $8,%esp +fldl Z +subl $8,%esp +fstpl (%esp) +fldl Y +subl $8,%esp +fstpl (%esp) +pushl $.LC664 +call printf +addl $20,%esp +.LC662: +cmpl $0,I +je .LC665 +fldl V +fldl HInvrse +fmull U2 +fsubl HInvrse +fmulp %st,%st(1) +fstpl Y +fldl Y +fldl One +fsubl HInvrse +fmull U2 +fmull V +faddp %st,%st(1) +fstpl Z +fldl V0 +fcompl Z +fstsw %ax +sahf +jp .LC667 +jbe .LC667 +fldl Z +fstpl Y +.LC667: +fldl V0 +fcompl Y +fstsw %ax +sahf +jp .LC669 +jbe .LC669 +fldl Y +fstpl V +.LC669: +fldl V0 +fsubl V +fldl V0 +fcompp +fstsw %ax +sahf +jp .LC666 +jbe .LC666 +fldl V0 +fstpl V +jmp .LC666 +.LC665: +fldl Y +fldl HInvrse +fmull U2 +fsubl HInvrse +fmulp %st,%st(1) +fstpl V +fldl V +fldl One +fsubl HInvrse +fmull U2 +fmull Y +faddp %st,%st(1) +fstpl V +.LC666: +fldl V +subl $8,%esp +fstpl (%esp) +pushl $.LC673 +call printf +addl $12,%esp +cmpl $0,I +je .LC674 +fldl V0 +subl $8,%esp +fstpl (%esp) +pushl $.LC676 +call printf +addl $12,%esp +jmp .LC675 +.LC674: +pushl $.LC677 +call printf +addl $4,%esp +.LC675: +fldl V +fmull One +fstpl V9 +fldl V9 +subl $8,%esp +fstpl (%esp) +pushl $.LC678 +call printf +addl $12,%esp +fldl V +fdivl One +fstpl V9 +fldl V9 +subl $8,%esp +fstpl (%esp) +pushl $.LC679 +call printf +addl $12,%esp +pushl $.LC680 +call printf +addl $4,%esp +pushl $.LC681 +call printf +addl $4,%esp +movl $170,Milestone +fldl V +fchs +fldl V +fcompp +fstsw %ax +sahf +jp .LC686 +jbe .LC686 +fldl V0 +fchs +fldl V0 +fcompp +fstsw %ax +sahf +jp .LC686 +jbe .LC686 +fldl UfThold +fchs +fldl V +fcompp +fstsw %ax +sahf +jp .LC686 +jbe .LC686 +fldl V +fcompl UfThold +fstsw %ax +sahf +jp .LC682 +ja .LC682 +.LC686: +pushl $.LC687 +pushl $0 +call BadCond +addl $8,%esp +fldl UfThold +subl $8,%esp +fstpl (%esp) +fldl V0 +subl $8,%esp +fstpl (%esp) +fldl V +subl $8,%esp +fstpl (%esp) +pushl $.LC688 +call printf +addl $28,%esp +.LC682: +movl $175,Milestone +pushl $.LC45 +call printf +addl $4,%esp +movl $1,Indx +.LC689: +movl Indx,%edi +cmpl $1,%edi +je .LC695 +cmpl $2,%edi +je .LC696 +cmpl $3,%edi +je .LC697 +jmp .LC693 +.LC695: +fldl UfThold +fstpl Z +jmp .LC694 +.LC696: +fldl E0 +fstpl Z +jmp .LC694 +.LC697: +fldl PseudoZero +fstpl Z +.LC693: +.LC694: +fldl Zero +fcompl Z +fstsw %ax +sahf +jp 1f +je .LC698 +1: +fldl Z +subl $8,%esp +fstpl (%esp) +call sqrt +addl $8,%esp +fstpl -1628(%ebp) +fldl -1628(%ebp) +fstpl V9 +fldl V9 +fmull V9 +fstpl Y +fldl Radix +fmull E9 +fstpl -1660(%ebp) +fldl Y +fldl One +fsubl -1660(%ebp) +fdivrp %st,%st(1) +fldl Z +fcompp +fstsw %ax +sahf +jp .LC702 +ja .LC702 +fldl One +faddl -1660(%ebp) +fmull Z +fcompl Y +fstsw %ax +sahf +jp .LC700 +jae .LC700 +.LC702: +fldl U1 +fcompl V9 +fstsw %ax +sahf +jp .LC703 +jae .LC703 +pushl $.LC158 +pushl $1 +call BadCond +addl $8,%esp +jmp .LC704 +.LC703: +pushl $.LC158 +pushl $2 +call BadCond +addl $8,%esp +.LC704: +fldl Z +subl $8,%esp +fstpl (%esp) +pushl $.LC705 +call printf +addl $12,%esp +fldl Y +subl $8,%esp +fstpl (%esp) +pushl $.LC706 +call printf +addl $12,%esp +.LC700: +.LC698: +.LC690: +incl Indx +cmpl $3,Indx +jle .LC689 +movl $180,Milestone +movl $1,Indx +.LC707: +cmpl $1,Indx +jne .LC711 +fldl V +fstpl Z +jmp .LC712 +.LC711: +fldl V0 +fstpl Z +.LC712: +fldl Z +subl $8,%esp +fstpl (%esp) +call sqrt +addl $8,%esp +fstpl -1628(%ebp) +fldl -1628(%ebp) +fstpl V9 +fldl V9 +fstpl -1636(%ebp) +fldl One +fldl Radix +fmull E9 +fsubrp %st,%st(1) +fmull -1636(%ebp) +fstpl X +fldl -1636(%ebp) +fmull X +fstpl V9 +fldl One +fldl Two +fmull Radix +fmull E9 +fsubrp %st,%st(1) +fmull Z +fcompl V9 +fstsw %ax +sahf +jp .LC715 +ja .LC715 +fldl Z +fcompl V9 +fstsw %ax +sahf +jp .LC713 +jae .LC713 +.LC715: +fldl V9 +fstpl Y +fldl W +fcompl X +fstsw %ax +sahf +jp .LC716 +jbe .LC716 +pushl $.LC158 +pushl $1 +call BadCond +addl $8,%esp +jmp .LC717 +.LC716: +pushl $.LC158 +pushl $2 +call BadCond +addl $8,%esp +.LC717: +fldl Z +subl $8,%esp +fstpl (%esp) +pushl $.LC718 +call printf +addl $12,%esp +fldl Y +subl $8,%esp +fstpl (%esp) +pushl $.LC719 +call printf +addl $12,%esp +.LC713: +.LC708: +incl Indx +cmpl $2,Indx +jle .LC707 +movl $190,Milestone +call Pause +fldl UfThold +fmull V +fstpl X +fldl Radix +fmull Radix +fstpl Y +fldl X +fmull Y +fldl One +fcompp +fstsw %ax +sahf +jp .LC722 +ja .LC722 +fldl Y +fcompl X +fstsw %ax +sahf +jp .LC720 +jae .LC720 +.LC722: +fldl X +fmull Y +fldl U1 +fcompp +fstsw %ax +sahf +jp .LC725 +ja .LC725 +fldl Y +fdivl U1 +fcompl X +fstsw %ax +sahf +jp .LC723 +jae .LC723 +.LC725: +pushl $.LC726 +pushl $2 +call BadCond +addl $8,%esp +jmp .LC724 +.LC723: +pushl $.LC158 +pushl $3 +call BadCond +addl $8,%esp +.LC724: +pushl $.LC728 +fldl X +subl $8,%esp +fstpl (%esp) +pushl $.LC727 +call printf +addl $16,%esp +.LC720: +movl $200,Milestone +movl $1,Indx +.LC729: +fldl F9 +fstpl X +movl Indx,%edi +cmpl $2,%edi +jl .LC733 +cmpl $5,%edi +jg .LC733 +jmp *.LC739-8(,%edi,4) +.data +.align 4 +.LC739: +.long .LC735 +.long .LC736 +.long .LC737 +.long .LC738 +.text +.LC735: +fldl One +faddl U2 +fstpl X +jmp .LC734 +.LC736: +fldl V +fstpl X +jmp .LC734 +.LC737: +fldl UfThold +fstpl X +jmp .LC734 +.LC738: +fldl Radix +fstpl X +.LC733: +.LC734: +fldl X +fstpl Y +leal sigfpe,%edi +movl %edi,sigsave +pushl $ovfl_buf +call _setjmp +addl $4,%esp +cmpl $0,%eax +je .LC741 +fldl X +subl $8,%esp +fstpl (%esp) +pushl $.LC743 +call printf +addl $12,%esp +jmp .LC742 +.LC741: +fldl Y +fdivl X +fsubl Half +fsubl Half +fstpl V9 +fldl Zero +fcompl V9 +fstsw %ax +sahf +jp .LC744 +jne .LC744 +jmp .LC730 +.LC744: +fldl U1 +fchs +fcompl V9 +fstsw %ax +sahf +jp .LC746 +jne .LC746 +cmpl $5,Indx +jge .LC746 +pushl $.LC158 +pushl $3 +call BadCond +addl $8,%esp +jmp .LC747 +.LC746: +pushl $.LC158 +pushl $1 +call BadCond +addl $8,%esp +.LC747: +fldl X +subl $8,%esp +fstpl (%esp) +pushl $.LC748 +call printf +addl $12,%esp +fldl V9 +subl $8,%esp +fstpl (%esp) +pushl $.LC749 +call printf +addl $12,%esp +.LC742: +movl $0,sigsave +.LC730: +incl Indx +cmpl $5,Indx +jle .LC729 +movl $210,Milestone +fldl Zero +fstpl MyZero +pushl $.LC45 +call printf +addl $4,%esp +pushl $.LC750 +call printf +addl $4,%esp +leal sigfpe,%edi +movl %edi,sigsave +pushl $.LC751 +call printf +addl $4,%esp +pushl $ovfl_buf +call _setjmp +addl $4,%esp +cmpl $0,%eax +jne .LC752 +fldl One +fdivl MyZero +subl $8,%esp +fstpl (%esp) +pushl $.LC754 +call printf +addl $12,%esp +.LC752: +movl $0,sigsave +leal sigfpe,%edi +movl %edi,sigsave +pushl $.LC755 +call printf +addl $4,%esp +pushl $ovfl_buf +call _setjmp +addl $4,%esp +cmpl $0,%eax +jne .LC756 +fldl Zero +fdivl MyZero +subl $8,%esp +fstpl (%esp) +pushl $.LC754 +call printf +addl $12,%esp +.LC756: +movl $0,sigsave +movl $220,Milestone +call Pause +pushl $.LC45 +call printf +addl $4,%esp +movl $0,-1648(%ebp) +.LC763: +movl -1648(%ebp),%edi +cmpl $0,ErrCnt(,%edi,4) +je .LC767 +movl -1648(%ebp),%edi +leal (,%edi,4),%edi +pushl ErrCnt(%edi) +pushl msg.758(%edi) +pushl $.LC769 +call printf +addl $12,%esp +.LC767: +.LC764: +incl -1648(%ebp) +cmpl $4,-1648(%ebp) +jl .LC763 +pushl $.LC45 +call printf +addl $4,%esp +movl ErrCnt,%edi +movl ErrCnt+4,%esi +leal (%esi,%edi),%edi +movl ErrCnt+8,%esi +leal (%esi,%edi),%edi +movl ErrCnt+12,%esi +leal (%esi,%edi),%edi +cmpl $0,%edi +jle .LC770 +movl ErrCnt,%edi +movl ErrCnt+4,%esi +leal (%esi,%edi),%edi +movl ErrCnt+8,%esi +leal (%esi,%edi),%edi +cmpl $0,%edi +jne .LC775 +cmpl $0,ErrCnt+12 +jle .LC775 +pushl $.LC780 +call printf +addl $4,%esp +pushl $.LC781 +call printf +addl $4,%esp +.LC775: +movl ErrCnt,%edi +movl ErrCnt+4,%esi +leal (%esi,%edi),%edi +cmpl $0,%edi +jne .LC782 +cmpl $0,ErrCnt+8 +jle .LC782 +pushl $.LC786 +call printf +addl $4,%esp +pushl $.LC787 +call printf +addl $4,%esp +.LC782: +movl ErrCnt,%edi +movl ErrCnt+4,%esi +leal (%esi,%edi),%edi +cmpl $0,%edi +jle .LC788 +pushl $.LC791 +call printf +addl $4,%esp +pushl $.LC792 +call printf +addl $4,%esp +.LC788: +cmpl $0,ErrCnt +jle .LC771 +pushl $.LC795 +call printf +addl $4,%esp +pushl $.LC796 +call printf +addl $4,%esp +jmp .LC771 +.LC770: +pushl $.LC797 +call printf +addl $4,%esp +cmpl $1,RMult +jne .LC802 +cmpl $1,RDiv +jne .LC802 +cmpl $1,RAddSub +jne .LC802 +cmpl $1,RSqrt +je .LC798 +.LC802: +pushl $.LC803 +call printf +addl $4,%esp +jmp .LC799 +.LC798: +fldl One +fcompl StickyBit +fstsw %ax +sahf +jp .LC804 +ja .LC804 +fldl Radix +fsubl Two +fldl Radix +fsubl Nine +fsubl One +fmulp %st,%st(1) +fldl Zero +fcompp +fstsw %ax +sahf +jp .LC804 +jne .LC804 +pushl $.LC806 +call printf +addl $4,%esp +pushl $.LC807 +call printf +addl $4,%esp +fldl Two +fcompl Radix +fstsw %ax +sahf +jp .LC808 +jne .LC808 +fldl Precision +fldl Four +fmull Three +fmull Two +fsubrp %st,%st(1) +fldl Precision +fsubl TwentySeven +fsubl TwentySeven +faddl One +fmulp %st,%st(1) +fldl Zero +fcompp +fstsw %ax +sahf +jp .LC808 +jne .LC808 +pushl $.LC810 +call printf +addl $4,%esp +jmp .LC809 +.LC808: +pushl $.LC811 +call printf +addl $4,%esp +.LC809: +cmpl $0,IEEE +je .LC812 +pushl $.LC814 +call printf +addl $4,%esp +jmp .LC813 +.LC812: +pushl $.LC815 +call printf +addl $4,%esp +pushl $.LC816 +call printf +addl $4,%esp +.LC813: +.LC804: +pushl $.LC817 +call printf +addl $4,%esp +.LC799: +.LC771: +cmpl $0,fpecount +je .LC818 +pushl fpecount +pushl $.LC820 +call printf +addl $8,%esp +.LC818: +pushl $.LC821 +call printf +addl $4,%esp +mov $0,%eax +.LC7: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf822: +.size main,.Lf822-main +.globl Sign +.align 16 +.type Sign,@function +Sign: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +subl $8,%esp +fldl .LC8 +fcompl 20(%ebp) +fstsw %ax +sahf +jp .LC825 +ja .LC825 +fldl .LC9 +fstpl -8(%ebp) +jmp .LC826 +.LC825: +fldl .LC827 +fstpl -8(%ebp) +.LC826: +fldl -8(%ebp) +.LC823: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf828: +.size Sign,.Lf828-Sign +.globl Pause +.align 16 +.type Pause,@function +Pause: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +pushl Milestone +pushl $.LC830 +call printf +addl $8,%esp +pushl PageNo +pushl $.LC831 +call printf +addl $8,%esp +incl Milestone +incl PageNo +mov $0,%eax +.LC829: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf832: +.size Pause,.Lf832-Pause +.globl TstCond +.align 16 +.type TstCond,@function +TstCond: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +cmpl $0,24(%ebp) +jne .LC834 +pushl 28(%ebp) +pushl 20(%ebp) +call BadCond +addl $8,%esp +pushl $.LC814 +call printf +addl $4,%esp +.LC834: +mov $0,%eax +.LC833: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf836: +.size TstCond,.Lf836-TstCond +.data +.align 4 +.type msg.838,@object +msg.838: +.long .LC839 +.long .LC840 +.long .LC841 +.long .LC842 +.size msg.838,16 +.globl BadCond +.text +.align 16 +.type BadCond,@function +BadCond: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +movl 20(%ebp),%edi +leal ErrCnt(,%edi,4),%edi +incl (,%edi) +pushl 24(%ebp) +movl 20(%ebp),%edi +pushl msg.838(,%edi,4) +pushl $.LC843 +call printf +addl $12,%esp +mov $0,%eax +.LC837: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf844: +.size BadCond,.Lf844-BadCond +.globl Random +.align 16 +.type Random,@function +Random: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +subl $48,%esp +fldl Random1 +faddl Random9 +fstpl -8(%ebp) +fldl -8(%ebp) +fmull -8(%ebp) +fstpl -16(%ebp) +fldl -16(%ebp) +fmull -16(%ebp) +fstpl -16(%ebp) +fldl -8(%ebp) +fmull -16(%ebp) +fstpl -8(%ebp) +fldl -8(%ebp) +subl $8,%esp +fstpl (%esp) +call floor +addl $8,%esp +fstpl -48(%ebp) +fldl -8(%ebp) +fsubl -48(%ebp) +fstpl -16(%ebp) +fldl -16(%ebp) +fldl .LC846 +fmull -8(%ebp) +faddp %st,%st(1) +fstpl Random1 +fldl Random1 +.LC845: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf847: +.size Random,.Lf847-Random +.globl SqXMinX +.align 16 +.type SqXMinX,@function +SqXMinX: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +subl $40,%esp +fldl X +fmull BInvrse +fstpl -8(%ebp) +fldl X +fsubl -8(%ebp) +fstpl -16(%ebp) +fldl X +fmull X +subl $8,%esp +fstpl (%esp) +call sqrt +addl $8,%esp +fstpl -32(%ebp) +fldl -32(%ebp) +fsubl -8(%ebp) +fsubl -16(%ebp) +fdivl OneUlp +fstpl SqEr +fldl Zero +fcompl SqEr +fstsw %ax +sahf +jp 1f +je .LC849 +1: +fldl MinSqEr +fcompl SqEr +fstsw %ax +sahf +jp .LC851 +jbe .LC851 +fldl SqEr +fstpl MinSqEr +.LC851: +fldl MaxSqEr +fcompl SqEr +fstsw %ax +sahf +jp .LC853 +jae .LC853 +fldl SqEr +fstpl MaxSqEr +.LC853: +fldl J +faddl .LC9 +fstpl J +pushl $.LC45 +pushl 20(%ebp) +call BadCond +addl $8,%esp +fldl OneUlp +fmull SqEr +subl $8,%esp +fstpl (%esp) +fldl X +subl $8,%esp +fstpl (%esp) +fldl X +fmull X +subl $8,%esp +fstpl (%esp) +pushl $.LC855 +call printf +addl $28,%esp +pushl $.LC856 +call printf +addl $4,%esp +.LC849: +mov $0,%eax +.LC848: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf857: +.size SqXMinX,.Lf857-SqXMinX +.globl NewD +.align 16 +.type NewD,@function +NewD: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +subl $40,%esp +fldl Z1 +fmull Q +fstpl X +fldl Half +fldl X +fdivl Radix +fsubrp %st,%st(1) +subl $8,%esp +fstpl (%esp) +call floor +addl $8,%esp +fstpl -8(%ebp) +fldl -8(%ebp) +fmull Radix +faddl X +fstpl X +fldl X +fstpl -24(%ebp) +fldl Z +fstpl -32(%ebp) +fldl Q +fldl -24(%ebp) +fmull -32(%ebp) +fsubrp %st,%st(1) +fdivl Radix +fldl -24(%ebp) +fmull -24(%ebp) +fldl D +fdivl Radix +fmulp %st,%st(1) +faddp %st,%st(1) +fstpl Q +fldl -32(%ebp) +fldl Two +fmull -24(%ebp) +fmull D +fsubrp %st,%st(1) +fstpl Z +fldl Zero +fcompl Z +fstsw %ax +sahf +jp .LC859 +jb .LC859 +fldl Z +fchs +fstpl Z +fldl Z1 +fchs +fstpl Z1 +.LC859: +fldl Radix +fmull D +fstpl D +mov $0,%eax +.LC858: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf861: +.size NewD,.Lf861-NewD +.globl SR3750 +.align 16 +.type SR3750,@function +SR3750: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +subl $64,%esp +fldl X +fsubl Radix +fldl Z2 +fsubl Radix +fcompp +fstsw %ax +sahf +jp .LC863 +ja .LC863 +fldl X +fsubl Z2 +fldl W +fsubl Z2 +fcompp +fstsw %ax +sahf +jp .LC863 +jb .LC863 +incl I +fldl X +fmull D +subl $8,%esp +fstpl (%esp) +call sqrt +addl $8,%esp +fstpl -32(%ebp) +fldl -32(%ebp) +fstpl X2 +fldl X2 +fsubl Z2 +fldl Y +fsubl Z2 +fsubrp %st,%st(1) +fstpl Y2 +fldl X8 +fldl Y +fsubl Half +fdivrp %st,%st(1) +fstpl X2 +fldl X2 +fstpl -64(%ebp) +fldl -64(%ebp) +fldl Half +fmull -64(%ebp) +fmull -64(%ebp) +fsubrp %st,%st(1) +fstpl X2 +fldl Y2 +faddl Half +fldl Half +fsubl X2 +faddp %st,%st(1) +fstpl SqEr +fldl MinSqEr +fcompl SqEr +fstsw %ax +sahf +jp .LC865 +jbe .LC865 +fldl SqEr +fstpl MinSqEr +.LC865: +fldl Y2 +fsubl X2 +fstpl SqEr +fldl MaxSqEr +fcompl SqEr +fstsw %ax +sahf +jp .LC867 +jae .LC867 +fldl SqEr +fstpl MaxSqEr +.LC867: +.LC863: +mov $0,%eax +.LC862: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf869: +.size SR3750,.Lf869-SR3750 +.globl IsYeqX +.align 16 +.type IsYeqX,@function +IsYeqX: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +subl $8,%esp +fldl X +fcompl Y +fstsw %ax +sahf +jp 1f +je .LC871 +1: +cmpl $0,N +jg .LC873 +fldl Zero +fcompl Z +fstsw %ax +sahf +jp .LC875 +jne .LC875 +fldl Zero +fcompl Q +fstsw %ax +sahf +jp .LC875 +jb .LC875 +pushl $.LC877 +call printf +addl $4,%esp +jmp .LC876 +.LC875: +pushl $.LC878 +pushl $2 +call BadCond +addl $8,%esp +.LC876: +fldl Q +subl $8,%esp +fstpl (%esp) +fldl Z +subl $8,%esp +fstpl (%esp) +pushl $.LC879 +call printf +addl $20,%esp +fldl Y +subl $8,%esp +fstpl (%esp) +pushl $.LC880 +call printf +addl $12,%esp +fldl X +subl $8,%esp +fstpl (%esp) +pushl $.LC881 +call printf +addl $12,%esp +fldl Y +fsubl X +subl $8,%esp +fstpl (%esp) +pushl $.LC882 +call printf +addl $12,%esp +.LC873: +incl N +.LC871: +mov $0,%eax +.LC870: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf883: +.size IsYeqX,.Lf883-IsYeqX +.globl SR3980 +.align 16 +.type SR3980,@function +SR3980: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +subl $8,%esp +.LC885: +fildl I +fstpl Q +fldl Q +subl $8,%esp +fstpl (%esp) +fldl Z +subl $8,%esp +fstpl (%esp) +call pow +addl $16,%esp +fstpl -8(%ebp) +fldl -8(%ebp) +fstpl Y +call IsYeqX +movl I,%edi +leal 1(%edi),%edi +movl %edi,I +cmpl M,%edi +jle .LC888 +jmp .LC887 +.LC888: +fldl Z +fmull X +fstpl X +.LC886: +fldl W +fcompl X +fstsw %ax +sahf +jp .LC885 +ja .LC885 +.LC887: +mov $0,%eax +.LC884: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf890: +.size SR3980,.Lf890-SR3980 +.globl PrintIfNPositive +.align 16 +.type PrintIfNPositive,@function +PrintIfNPositive: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +cmpl $0,N +jle .LC892 +pushl N +pushl $.LC894 +call printf +addl $8,%esp +.LC892: +mov $0,%eax +.LC891: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf895: +.size PrintIfNPositive,.Lf895-PrintIfNPositive +.globl TstPtUf +.align 16 +.type TstPtUf,@function +TstPtUf: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +subl $48,%esp +movl $0,N +fldl Zero +fcompl Z +fstsw %ax +sahf +jp 1f +je .LC897 +1: +pushl $.LC899 +call printf +addl $4,%esp +pushl $.LC900 +call printf +addl $4,%esp +leal sigfpe,%edi +movl %edi,sigsave +pushl $ovfl_buf +call _setjmp +addl $4,%esp +cmpl $0,%eax +je .LC901 +jmp .LC903 +.LC901: +fldl Z +faddl Z +fdivl Z +fstpl Q9 +fldl Q9 +subl $8,%esp +fstpl (%esp) +pushl $.LC904 +call printf +addl $12,%esp +fldl Q9 +fsubl Two +subl $8,%esp +fstpl (%esp) +call fabs +addl $8,%esp +fstpl -16(%ebp) +fldl Radix +fmull U2 +fcompl -16(%ebp) +fstsw %ax +sahf +jp .LC905 +jbe .LC905 +pushl $.LC907 +call printf +addl $4,%esp +pushl $.LC908 +call printf +addl $4,%esp +jmp .LC906 +.LC905: +fldl One +fcompl Q9 +fstsw %ax +sahf +jp .LC911 +ja .LC911 +fldl Two +fcompl Q9 +fstsw %ax +sahf +jp .LC909 +jae .LC909 +.LC911: +.LC903: +movl $1,N +movl ErrCnt+4,%edi +leal 1(%edi),%edi +movl %edi,ErrCnt+4 +pushl $.LC914 +call printf +addl $4,%esp +jmp .LC910 +.LC909: +movl $1,N +movl ErrCnt+8,%edi +leal 1(%edi),%edi +movl %edi,ErrCnt+8 +pushl $.LC917 +call printf +addl $4,%esp +.LC910: +.LC906: +movl $0,sigsave +fldl Z +fmull One +fstpl V9 +fldl V9 +fstpl Random1 +fldl One +fmull Z +fstpl V9 +fldl V9 +fstpl Random2 +fldl Z +fdivl One +fstpl V9 +fldl Random1 +fcompl Z +fstsw %ax +sahf +jp .LC918 +jne .LC918 +fldl Random2 +fcompl Z +fstsw %ax +sahf +jp .LC918 +jne .LC918 +fldl V9 +fcompl Z +fstsw %ax +sahf +jp .LC918 +jne .LC918 +cmpl $0,N +jle .LC919 +call Pause +jmp .LC919 +.LC918: +movl $1,N +pushl $.LC922 +pushl $2 +call BadCond +addl $8,%esp +fldl Z +subl $8,%esp +fstpl (%esp) +pushl $.LC923 +call printf +addl $12,%esp +fldl Random1 +fcompl Z +fstsw %ax +sahf +jp 1f +je .LC924 +1: +fldl Random1 +subl $8,%esp +fstpl (%esp) +pushl $.LC926 +call printf +addl $12,%esp +.LC924: +fldl Random2 +fcompl Z +fstsw %ax +sahf +jp 1f +je .LC927 +1: +fldl Random1 +fcompl Random2 +fstsw %ax +sahf +jp 1f +je .LC927 +1: +fldl Random2 +subl $8,%esp +fstpl (%esp) +pushl $.LC929 +call printf +addl $12,%esp +.LC927: +fldl V9 +fcompl Z +fstsw %ax +sahf +jp 1f +je .LC930 +1: +fldl V9 +subl $8,%esp +fstpl (%esp) +pushl $.LC932 +call printf +addl $12,%esp +.LC930: +fldl Random1 +fcompl Random2 +fstsw %ax +sahf +jp 1f +je .LC933 +1: +movl ErrCnt+8,%edi +leal 1(%edi),%edi +movl %edi,ErrCnt+8 +pushl $.LC937 +pushl $2 +call BadCond +addl $8,%esp +fldl Random2 +subl $8,%esp +fstpl (%esp) +pushl $.LC938 +call printf +addl $12,%esp +fldl Random1 +subl $8,%esp +fstpl (%esp) +pushl $.LC939 +call printf +addl $12,%esp +.LC933: +call Pause +.LC919: +.LC897: +mov $0,%eax +.LC896: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf940: +.size TstPtUf,.Lf940-TstPtUf +.globl notify +.align 16 +.type notify,@function +notify: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +pushl 20(%ebp) +pushl $.LC942 +call printf +addl $8,%esp +pushl $.LC943 +call printf +addl $4,%esp +mov $0,%eax +.LC941: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf944: +.size notify,.Lf944-notify +.globl msglist +.align 16 +.type msglist,@function +msglist: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +jmp .LC947 +.LC946: +movl 20(%ebp),%edi +leal 4(%edi),%esi +movl %esi,20(%ebp) +pushl (,%edi) +pushl $.LC949 +call printf +addl $8,%esp +.LC947: +movl 20(%ebp),%edi +movl (,%edi),%edi +cmpl $0,%edi +jne .LC946 +mov $0,%eax +.LC945: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf950: +.size msglist,.Lf950-msglist +.data +.align 4 +.type instr.952,@object +instr.952: +.long .LC953 +.long .LC954 +.long .LC955 +.long .LC956 +.long .LC957 +.long .LC958 +.long .LC959 +.long .LC960 +.long .LC961 +.long 0 +.size instr.952,40 +.globl Instructions +.text +.align 16 +.type Instructions,@function +Instructions: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +pushl $instr.952 +call msglist +addl $4,%esp +mov $0,%eax +.LC951: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf962: +.size Instructions,.Lf962-Instructions +.data +.align 4 +.type head.964,@object +head.964: +.long .LC965 +.long .LC966 +.long .LC967 +.long .LC968 +.long .LC969 +.long .LC970 +.long .LC971 +.long .LC972 +.long .LC973 +.long .LC974 +.long .LC975 +.long .LC976 +.long .LC977 +.long .LC978 +.long 0 +.size head.964,60 +.globl Heading +.text +.align 16 +.type Heading,@function +Heading: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +pushl $head.964 +call msglist +addl $4,%esp +mov $0,%eax +.LC963: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf979: +.size Heading,.Lf979-Heading +.data +.align 4 +.type chars.981,@object +chars.981: +.long .LC982 +.long .LC983 +.long .LC984 +.long .LC985 +.long .LC986 +.long .LC987 +.long .LC988 +.long .LC989 +.long .LC990 +.long .LC991 +.long .LC992 +.long .LC993 +.long .LC994 +.long .LC995 +.long .LC996 +.long .LC997 +.long .LC998 +.long .LC999 +.long .LC1000 +.long 0 +.size chars.981,80 +.globl Characteristics +.text +.align 16 +.type Characteristics,@function +Characteristics: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +pushl $chars.981 +call msglist +addl $4,%esp +mov $0,%eax +.LC980: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf1001: +.size Characteristics,.Lf1001-Characteristics +.data +.align 4 +.type hist.1003,@object +hist.1003: +.long .LC1004 +.long .LC1005 +.long .LC1006 +.long .LC1007 +.long .LC1008 +.long .LC1009 +.long .LC1010 +.long .LC1011 +.long .LC1012 +.long .LC1013 +.long .LC1014 +.long .LC1015 +.long .LC1016 +.long .LC1017 +.long .LC1018 +.long .LC1019 +.long .LC1020 +.long 0 +.size hist.1003,72 +.globl History +.text +.align 16 +.type History,@function +History: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +pushl $hist.1003 +call msglist +addl $4,%esp +mov $0,%eax +.LC1002: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf1021: +.size History,.Lf1021-History +.globl pow +.align 16 +.type pow,@function +pow: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +subl $96,%esp +movl $0,-20(%ebp) +movl $0,-24(%ebp) +fldl .LC8 +fcompl 28(%ebp) +fstsw %ax +sahf +jp .LC1023 +jne .LC1023 +fldl .LC9 +jmp .LC1022 +.LC1023: +fldl .LC1028 +fcompl 28(%ebp) +fstsw %ax +sahf +jp .LC1027 +ja .LC1027 +fldl .LC1029 +fcompl 28(%ebp) +fstsw %ax +sahf +jp .LC1025 +jae .LC1025 +.LC1027: +fldl .LC827 +fcompl 20(%ebp) +fstsw %ax +sahf +jp 1f +je .LC1025 +1: +fldl 20(%ebp) +subl $8,%esp +fstpl (%esp) +call log +addl $8,%esp +fstpl -48(%ebp) +fldl 28(%ebp) +fmull -48(%ebp) +subl $8,%esp +fstpl (%esp) +call exp +addl $8,%esp +fstpl -56(%ebp) +fldl -56(%ebp) +jmp .LC1022 +.LC1025: +fldl .LC8 +fcompl 28(%ebp) +fstsw %ax +sahf +jp .LC1030 +jbe .LC1030 +fldl 28(%ebp) +fchs +fstpl 28(%ebp) +movl $1,-24(%ebp) +.LC1030: +leal -32(%ebp),%edi +pushl %edi +fldl 28(%ebp) +subl $8,%esp +fstpl (%esp) +call modf +addl $12,%esp +fstpl -64(%ebp) +fldl -64(%ebp) +fstpl 28(%ebp) +fldl .LC8 +fcompl 28(%ebp) +fstsw %ax +sahf +jp 1f +je .LC1032 +1: +fldl 20(%ebp) +subl $8,%esp +fstpl (%esp) +call log +addl $8,%esp +fstpl -72(%ebp) +fldl 28(%ebp) +fmull -72(%ebp) +subl $8,%esp +fstpl (%esp) +call exp +addl $8,%esp +fstpl -80(%ebp) +fldl -80(%ebp) +fstpl -16(%ebp) +jmp .LC1033 +.LC1032: +fldl .LC9 +fstpl -16(%ebp) +.LC1033: +leal -8(%ebp),%edi +pushl %edi +fldl 20(%ebp) +subl $8,%esp +fstpl (%esp) +call frexp +addl $12,%esp +fstpl -88(%ebp) +fldl -88(%ebp) +fstpl 20(%ebp) +fldl -32(%ebp) +subl $8,%esp +fnstcw 4(%esp) +movl 4(%esp),%edx +movb $12,%dh +movl %edx,0(%esp) +fldcw 0(%esp) +fistpl 0(%esp) +popl %eax +fldcw 0(%esp) +addl $4,%esp +movl %eax,-4(%ebp) +cmpl $0,%eax +je .LC1034 +.LC1036: +movl -4(%ebp),%edi +andl $1,%edi +cmpl $0,%edi +je .LC1040 +fldl -16(%ebp) +fmull 20(%ebp) +fstpl -16(%ebp) +movl -8(%ebp),%edi +addl %edi,-20(%ebp) +.LC1040: +movl -4(%ebp),%edi +sarl $1,%edi +movl %edi,-4(%ebp) +cmpl $0,%edi +jne .LC1042 +jmp .LC1038 +.LC1042: +fldl 20(%ebp) +fmull 20(%ebp) +fstpl 20(%ebp) +sall $1,-8(%ebp) +fldl .LC1046 +fcompl 20(%ebp) +fstsw %ax +sahf +jp .LC1036 +jbe .LC1036 +fldl .LC1047 +fmull 20(%ebp) +fstpl 20(%ebp) +decl -8(%ebp) +jmp .LC1036 +.LC1038: +.LC1034: +cmpl $0,-24(%ebp) +je .LC1048 +fldl .LC9 +fdivl -16(%ebp) +fstpl -16(%ebp) +negl -20(%ebp) +.LC1048: +pushl -20(%ebp) +fldl -16(%ebp) +subl $8,%esp +fstpl (%esp) +call ldexp +addl $12,%esp +fstpl -96(%ebp) +fldl -96(%ebp) +.LC1022: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf1050: +.size pow,.Lf1050-pow +.bss +.globl UfNGrad +.align 4 +.type UfNGrad,@object +.size UfNGrad,4 +.comm UfNGrad,4 +.globl SqRWrng +.align 4 +.type SqRWrng,@object +.size SqRWrng,4 +.comm SqRWrng,4 +.globl IEEE +.align 4 +.type IEEE,@object +.size IEEE,4 +.comm IEEE,4 +.globl Anomaly +.align 4 +.type Anomaly,@object +.size Anomaly,4 +.comm Anomaly,4 +.globl Monot +.align 4 +.type Monot,@object +.size Monot,4 +.comm Monot,4 +.globl NotMonot +.align 4 +.type NotMonot,@object +.size NotMonot,4 +.comm NotMonot,4 +.globl Done +.align 4 +.type Done,@object +.size Done,4 +.comm Done,4 +.globl Break +.align 4 +.type Break,@object +.size Break,4 +.comm Break,4 +.globl RSqrt +.align 4 +.type RSqrt,@object +.size RSqrt,4 +.comm RSqrt,4 +.globl RAddSub +.align 4 +.type RAddSub,@object +.size RAddSub,4 +.comm RAddSub,4 +.globl RDiv +.align 4 +.type RDiv,@object +.size RDiv,4 +.comm RDiv,4 +.globl RMult +.align 4 +.type RMult,@object +.size RMult,4 +.comm RMult,4 +.globl GAddSub +.align 4 +.type GAddSub,@object +.size GAddSub,4 +.comm GAddSub,4 +.globl GDiv +.align 4 +.type GDiv,@object +.size GDiv,4 +.comm GDiv,4 +.globl GMult +.align 4 +.type GMult,@object +.size GMult,4 +.comm GMult,4 +.globl N1 +.align 4 +.type N1,@object +.size N1,4 +.comm N1,4 +.globl N +.align 4 +.type N,@object +.size N,4 +.comm N,4 +.globl M +.align 4 +.type M,@object +.size M,4 +.comm M,4 +.globl PageNo +.align 4 +.type PageNo,@object +.size PageNo,4 +.comm PageNo,4 +.globl Milestone +.align 4 +.type Milestone,@object +.size Milestone,4 +.comm Milestone,4 +.globl fpecount +.align 4 +.type fpecount,@object +.size fpecount,4 +.comm fpecount,4 +.globl ErrCnt +.align 4 +.type ErrCnt,@object +.size ErrCnt,16 +.comm ErrCnt,16 +.globl Z9 +.align 4 +.type Z9,@object +.size Z9,8 +.comm Z9,8 +.globl Z2 +.align 4 +.type Z2,@object +.size Z2,8 +.comm Z2,8 +.globl Z1 +.align 4 +.type Z1,@object +.size Z1,8 +.comm Z1,8 +.globl PseudoZero +.align 4 +.type PseudoZero,@object +.size PseudoZero,8 +.comm PseudoZero,8 +.globl Z +.align 4 +.type Z,@object +.size Z,8 +.comm Z,8 +.globl Random2 +.align 4 +.type Random2,@object +.size Random2,8 +.comm Random2,8 +.globl Y2 +.align 4 +.type Y2,@object +.size Y2,8 +.comm Y2,8 +.globl Y1 +.align 4 +.type Y1,@object +.size Y1,8 +.comm Y1,8 +.globl Y +.align 4 +.type Y,@object +.size Y,8 +.comm Y,8 +.globl Random1 +.align 4 +.type Random1,@object +.size Random1,8 +.comm Random1,8 +.globl X8 +.align 4 +.type X8,@object +.size X8,8 +.comm X8,8 +.globl X2 +.align 4 +.type X2,@object +.size X2,8 +.comm X2,8 +.globl X1 +.align 4 +.type X1,@object +.size X1,8 +.comm X1,8 +.globl X +.align 4 +.type X,@object +.size X,8 +.comm X,8 +.globl W +.align 4 +.type W,@object +.size W,8 +.comm W,8 +.globl V9 +.align 4 +.type V9,@object +.size V9,8 +.comm V9,8 +.globl V0 +.align 4 +.type V0,@object +.size V0,8 +.comm V0,8 +.globl V +.align 4 +.type V,@object +.size V,8 +.comm V,8 +.globl U2 +.align 4 +.type U2,@object +.size U2,8 +.comm U2,8 +.globl U1 +.align 4 +.type U1,@object +.size U1,8 +.comm U1,8 +.globl UfThold +.align 4 +.type UfThold,@object +.size UfThold,8 +.comm UfThold,8 +.globl OneUlp +.align 4 +.type OneUlp,@object +.size OneUlp,8 +.comm OneUlp,8 +.globl S +.align 4 +.type S,@object +.size S,8 +.comm S,8 +.globl Underflow +.align 4 +.type Underflow,@object +.size Underflow,8 +.comm Underflow,8 +.globl T +.align 4 +.type T,@object +.size T,8 +.comm T,8 +.globl Random9 +.align 4 +.type Random9,@object +.size Random9,8 +.comm Random9,8 +.globl R +.align 4 +.type R,@object +.size R,8 +.comm R,8 +.globl Q9 +.align 4 +.type Q9,@object +.size Q9,8 +.comm Q9,8 +.globl Q +.align 4 +.type Q,@object +.size Q,8 +.comm Q,8 +.globl Precision +.align 4 +.type Precision,@object +.size Precision,8 +.comm Precision,8 +.globl MyZero +.align 4 +.type MyZero,@object +.size MyZero,8 +.comm MyZero,8 +.globl J +.align 4 +.type J,@object +.size J,8 +.comm J,8 +.globl StickyBit +.align 4 +.type StickyBit,@object +.size StickyBit,8 +.comm StickyBit,8 +.globl I +.align 4 +.type I,@object +.size I,4 +.comm I,4 +.globl HInvrse +.align 4 +.type HInvrse,@object +.size HInvrse,8 +.comm HInvrse,8 +.globl H +.align 4 +.type H,@object +.size H,8 +.comm H,8 +.globl F9 +.align 4 +.type F9,@object +.size F9,8 +.comm F9,8 +.globl F6 +.align 4 +.type F6,@object +.size F6,8 +.comm F6,8 +.globl Third +.align 4 +.type Third,@object +.size Third,8 +.comm Third,8 +.globl E9 +.align 4 +.type E9,@object +.size E9,8 +.comm E9,8 +.globl MaxSqEr +.align 4 +.type MaxSqEr,@object +.size MaxSqEr,8 +.comm MaxSqEr,8 +.globl SqEr +.align 4 +.type SqEr,@object +.size SqEr,8 +.comm SqEr,8 +.globl MinSqEr +.align 4 +.type MinSqEr,@object +.size MinSqEr,8 +.comm MinSqEr,8 +.globl E3 +.align 4 +.type E3,@object +.size E3,8 +.comm E3,8 +.globl Exp2 +.align 4 +.type Exp2,@object +.size Exp2,8 +.comm Exp2,8 +.globl E1 +.align 4 +.type E1,@object +.size E1,8 +.comm E1,8 +.globl E0 +.align 4 +.type E0,@object +.size E0,8 +.comm E0,8 +.globl FourD +.align 4 +.type FourD,@object +.size FourD,8 +.comm FourD,8 +.globl D +.align 4 +.type D,@object +.size D,8 +.comm D,8 +.globl CInvrse +.align 4 +.type CInvrse,@object +.size CInvrse,8 +.comm CInvrse,8 +.globl C +.align 4 +.type C,@object +.size C,8 +.comm C,8 +.globl A1 +.align 4 +.type A1,@object +.size A1,8 +.comm A1,8 +.globl AInvrse +.align 4 +.type AInvrse,@object +.size AInvrse,8 +.comm AInvrse,8 +.globl ch +.align 1 +.type ch,@object +.size ch,8 +.comm ch,8 +.globl Indx +.align 4 +.type Indx,@object +.size Indx,4 +.comm Indx,4 +.globl BMinusU2 +.align 4 +.type BMinusU2,@object +.size BMinusU2,8 +.comm BMinusU2,8 +.globl RadixD2 +.align 4 +.type RadixD2,@object +.size RadixD2,8 +.comm RadixD2,8 +.globl BInvrse +.align 4 +.type BInvrse,@object +.size BInvrse,8 +.comm BInvrse,8 +.globl Radix +.align 4 +.type Radix,@object +.size Radix,8 +.comm Radix,8 +.globl sigsave +.align 4 +.type sigsave,@object +.size sigsave,4 +.comm sigsave,4 +.globl ovfl_buf +.align 4 +.type ovfl_buf,@object +.size ovfl_buf,64 +.comm ovfl_buf,64 +.data +.align 4 +.LC1047: +.long 0 +.long 1073741824 +.align 4 +.LC1046: +.long 0 +.long 1071644672 +.align 4 +.LC1029: +.long 0 +.long 1083256832 +.align 4 +.LC1028: +.long 0 +.long -1064226816 +.align 1 +.LC1020: +.byte 115 +.byte 101 +.byte 101 +.byte 32 +.byte 115 +.byte 111 +.byte 117 +.byte 114 +.byte 99 +.byte 101 +.byte 32 +.byte 99 +.byte 111 +.byte 109 +.byte 109 +.byte 101 +.byte 110 +.byte 116 +.byte 115 +.byte 32 +.byte 102 +.byte 111 +.byte 114 +.byte 32 +.byte 109 +.byte 111 +.byte 114 +.byte 101 +.byte 32 +.byte 104 +.byte 105 +.byte 115 +.byte 116 +.byte 111 +.byte 114 +.byte 121 +.byte 46 +.byte 0 +.align 1 +.LC1019: +.byte 66 +.byte 65 +.byte 83 +.byte 73 +.byte 67 +.byte 32 +.byte 118 +.byte 101 +.byte 114 +.byte 115 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 111 +.byte 102 +.byte 32 +.byte 116 +.byte 104 +.byte 105 +.byte 115 +.byte 32 +.byte 112 +.byte 114 +.byte 111 +.byte 103 +.byte 114 +.byte 97 +.byte 109 +.byte 32 +.byte 40 +.byte 67 +.byte 41 +.byte 32 +.byte 49 +.byte 57 +.byte 56 +.byte 51 +.byte 32 +.byte 98 +.byte 121 +.byte 32 +.byte 80 +.byte 114 +.byte 111 +.byte 102 +.byte 46 +.byte 32 +.byte 87 +.byte 46 +.byte 32 +.byte 77 +.byte 46 +.byte 32 +.byte 75 +.byte 97 +.byte 104 +.byte 97 +.byte 110 +.byte 59 +.byte 0 +.align 1 +.LC1018: +.byte 97 +.byte 115 +.byte 32 +.byte 117 +.byte 115 +.byte 101 +.byte 100 +.byte 32 +.byte 98 +.byte 121 +.byte 32 +.byte 99 +.byte 101 +.byte 114 +.byte 116 +.byte 97 +.byte 105 +.byte 110 +.byte 32 +.byte 101 +.byte 97 +.byte 114 +.byte 108 +.byte 121 +.byte 32 +.byte 87 +.byte 65 +.byte 78 +.byte 71 +.byte 32 +.byte 109 +.byte 97 +.byte 99 +.byte 104 +.byte 105 +.byte 110 +.byte 101 +.byte 115 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC1017: +.byte 102 +.byte 108 +.byte 111 +.byte 97 +.byte 116 +.byte 105 +.byte 110 +.byte 103 +.byte 45 +.byte 112 +.byte 111 +.byte 105 +.byte 110 +.byte 116 +.byte 32 +.byte 110 +.byte 117 +.byte 109 +.byte 98 +.byte 101 +.byte 114 +.byte 115 +.byte 44 +.byte 32 +.byte 98 +.byte 117 +.byte 116 +.byte 32 +.byte 97 +.byte 108 +.byte 115 +.byte 111 +.byte 32 +.byte 97 +.byte 108 +.byte 108 +.byte 111 +.byte 119 +.byte 115 +.byte 32 +.byte 108 +.byte 111 +.byte 103 +.byte 97 +.byte 114 +.byte 105 +.byte 116 +.byte 104 +.byte 109 +.byte 105 +.byte 99 +.byte 32 +.byte 101 +.byte 110 +.byte 99 +.byte 111 +.byte 100 +.byte 105 +.byte 110 +.byte 103 +.byte 0 +.align 1 +.LC1016: +.byte 10 +.byte 84 +.byte 104 +.byte 101 +.byte 32 +.byte 112 +.byte 114 +.byte 111 +.byte 103 +.byte 114 +.byte 97 +.byte 109 +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 98 +.byte 97 +.byte 115 +.byte 101 +.byte 100 +.byte 32 +.byte 117 +.byte 112 +.byte 111 +.byte 110 +.byte 32 +.byte 97 +.byte 32 +.byte 99 +.byte 111 +.byte 110 +.byte 118 +.byte 101 +.byte 110 +.byte 116 +.byte 105 +.byte 111 +.byte 110 +.byte 97 +.byte 108 +.byte 32 +.byte 114 +.byte 97 +.byte 100 +.byte 105 +.byte 120 +.byte 32 +.byte 114 +.byte 101 +.byte 112 +.byte 114 +.byte 101 +.byte 115 +.byte 101 +.byte 110 +.byte 116 +.byte 97 +.byte 116 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 102 +.byte 111 +.byte 114 +.byte 0 +.align 1 +.LC1015: +.byte 111 +.byte 102 +.byte 32 +.byte 112 +.byte 97 +.byte 116 +.byte 104 +.byte 111 +.byte 108 +.byte 111 +.byte 103 +.byte 105 +.byte 101 +.byte 115 +.byte 44 +.byte 32 +.byte 97 +.byte 110 +.byte 100 +.byte 32 +.byte 116 +.byte 111 +.byte 32 +.byte 115 +.byte 97 +.byte 121 +.byte 32 +.byte 104 +.byte 111 +.byte 119 +.byte 32 +.byte 119 +.byte 101 +.byte 108 +.byte 108 +.byte 32 +.byte 116 +.byte 104 +.byte 101 +.byte 32 +.byte 97 +.byte 114 +.byte 105 +.byte 116 +.byte 104 +.byte 109 +.byte 101 +.byte 116 +.byte 105 +.byte 99 +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 105 +.byte 109 +.byte 112 +.byte 108 +.byte 101 +.byte 109 +.byte 101 +.byte 110 +.byte 116 +.byte 101 +.byte 100 +.byte 46 +.byte 0 +.align 1 +.LC1014: +.byte 111 +.byte 102 +.byte 32 +.byte 116 +.byte 104 +.byte 101 +.byte 32 +.byte 97 +.byte 114 +.byte 105 +.byte 116 +.byte 104 +.byte 109 +.byte 101 +.byte 116 +.byte 105 +.byte 99 +.byte 44 +.byte 32 +.byte 116 +.byte 104 +.byte 105 +.byte 115 +.byte 32 +.byte 112 +.byte 114 +.byte 111 +.byte 103 +.byte 114 +.byte 97 +.byte 109 +.byte 32 +.byte 116 +.byte 114 +.byte 105 +.byte 101 +.byte 115 +.byte 32 +.byte 116 +.byte 111 +.byte 32 +.byte 99 +.byte 111 +.byte 112 +.byte 101 +.byte 32 +.byte 119 +.byte 105 +.byte 116 +.byte 104 +.byte 32 +.byte 97 +.byte 32 +.byte 119 +.byte 105 +.byte 100 +.byte 101 +.byte 114 +.byte 32 +.byte 118 +.byte 97 +.byte 114 +.byte 105 +.byte 101 +.byte 116 +.byte 121 +.byte 0 +.align 1 +.LC1013: +.byte 116 +.byte 104 +.byte 101 +.byte 32 +.byte 82 +.byte 97 +.byte 100 +.byte 105 +.byte 120 +.byte 44 +.byte 32 +.byte 80 +.byte 114 +.byte 101 +.byte 99 +.byte 105 +.byte 115 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 97 +.byte 110 +.byte 100 +.byte 32 +.byte 114 +.byte 97 +.byte 110 +.byte 103 +.byte 101 +.byte 32 +.byte 40 +.byte 111 +.byte 118 +.byte 101 +.byte 114 +.byte 47 +.byte 117 +.byte 110 +.byte 100 +.byte 101 +.byte 114 +.byte 102 +.byte 108 +.byte 111 +.byte 119 +.byte 32 +.byte 116 +.byte 104 +.byte 114 +.byte 101 +.byte 115 +.byte 104 +.byte 111 +.byte 108 +.byte 100 +.byte 115 +.byte 41 +.byte 0 +.align 1 +.LC1012: +.byte 87 +.byte 46 +.byte 32 +.byte 74 +.byte 46 +.byte 32 +.byte 67 +.byte 111 +.byte 100 +.byte 121 +.byte 32 +.byte 97 +.byte 110 +.byte 100 +.byte 32 +.byte 87 +.byte 46 +.byte 32 +.byte 87 +.byte 97 +.byte 105 +.byte 116 +.byte 101 +.byte 46 +.byte 32 +.byte 65 +.byte 108 +.byte 116 +.byte 104 +.byte 111 +.byte 117 +.byte 103 +.byte 104 +.byte 32 +.byte 98 +.byte 111 +.byte 116 +.byte 104 +.byte 32 +.byte 112 +.byte 114 +.byte 111 +.byte 103 +.byte 114 +.byte 97 +.byte 109 +.byte 115 +.byte 32 +.byte 116 +.byte 114 +.byte 121 +.byte 32 +.byte 116 +.byte 111 +.byte 32 +.byte 100 +.byte 105 +.byte 115 +.byte 99 +.byte 111 +.byte 118 +.byte 101 +.byte 114 +.byte 0 +.align 1 +.LC1011: +.byte 98 +.byte 111 +.byte 111 +.byte 107 +.byte 32 +.byte 32 +.byte 96 +.byte 83 +.byte 111 +.byte 102 +.byte 116 +.byte 119 +.byte 97 +.byte 114 +.byte 101 +.byte 32 +.byte 77 +.byte 97 +.byte 110 +.byte 117 +.byte 97 +.byte 108 +.byte 32 +.byte 102 +.byte 111 +.byte 114 +.byte 32 +.byte 116 +.byte 104 +.byte 101 +.byte 32 +.byte 69 +.byte 108 +.byte 101 +.byte 109 +.byte 101 +.byte 110 +.byte 116 +.byte 97 +.byte 114 +.byte 121 +.byte 32 +.byte 70 +.byte 117 +.byte 110 +.byte 99 +.byte 116 +.byte 105 +.byte 111 +.byte 110 +.byte 115 +.byte 39 +.byte 32 +.byte 40 +.byte 49 +.byte 57 +.byte 56 +.byte 48 +.byte 41 +.byte 32 +.byte 98 +.byte 121 +.byte 0 +.align 1 +.LC1010: +.byte 112 +.byte 114 +.byte 111 +.byte 103 +.byte 114 +.byte 97 +.byte 109 +.byte 32 +.byte 99 +.byte 97 +.byte 108 +.byte 108 +.byte 101 +.byte 100 +.byte 32 +.byte 96 +.byte 77 +.byte 65 +.byte 67 +.byte 72 +.byte 65 +.byte 82 +.byte 39 +.byte 44 +.byte 32 +.byte 119 +.byte 104 +.byte 105 +.byte 99 +.byte 104 +.byte 32 +.byte 99 +.byte 97 +.byte 110 +.byte 32 +.byte 98 +.byte 101 +.byte 32 +.byte 102 +.byte 111 +.byte 117 +.byte 110 +.byte 100 +.byte 32 +.byte 97 +.byte 116 +.byte 32 +.byte 116 +.byte 104 +.byte 101 +.byte 32 +.byte 101 +.byte 110 +.byte 100 +.byte 32 +.byte 111 +.byte 102 +.byte 32 +.byte 116 +.byte 104 +.byte 101 +.byte 0 +.align 1 +.LC1009: +.byte 84 +.byte 104 +.byte 101 +.byte 32 +.byte 100 +.byte 105 +.byte 97 +.byte 103 +.byte 110 +.byte 111 +.byte 115 +.byte 116 +.byte 105 +.byte 99 +.byte 32 +.byte 99 +.byte 97 +.byte 112 +.byte 97 +.byte 98 +.byte 105 +.byte 108 +.byte 105 +.byte 116 +.byte 105 +.byte 101 +.byte 115 +.byte 32 +.byte 111 +.byte 102 +.byte 32 +.byte 116 +.byte 104 +.byte 105 +.byte 115 +.byte 32 +.byte 112 +.byte 114 +.byte 111 +.byte 103 +.byte 114 +.byte 97 +.byte 109 +.byte 32 +.byte 103 +.byte 111 +.byte 32 +.byte 98 +.byte 101 +.byte 121 +.byte 111 +.byte 110 +.byte 100 +.byte 32 +.byte 97 +.byte 110 +.byte 32 +.byte 101 +.byte 97 +.byte 114 +.byte 108 +.byte 105 +.byte 101 +.byte 114 +.byte 0 +.align 1 +.LC1008: +.byte 70 +.byte 97 +.byte 105 +.byte 108 +.byte 117 +.byte 114 +.byte 101 +.byte 115 +.byte 32 +.byte 109 +.byte 97 +.byte 121 +.byte 32 +.byte 99 +.byte 111 +.byte 110 +.byte 102 +.byte 111 +.byte 117 +.byte 110 +.byte 100 +.byte 32 +.byte 115 +.byte 117 +.byte 98 +.byte 115 +.byte 101 +.byte 113 +.byte 117 +.byte 101 +.byte 110 +.byte 116 +.byte 32 +.byte 100 +.byte 105 +.byte 97 +.byte 103 +.byte 110 +.byte 111 +.byte 115 +.byte 101 +.byte 115 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC1007: +.byte 32 +.byte 32 +.byte 32 +.byte 70 +.byte 65 +.byte 73 +.byte 76 +.byte 85 +.byte 82 +.byte 69 +.byte 115 +.byte 44 +.byte 32 +.byte 108 +.byte 105 +.byte 107 +.byte 101 +.byte 32 +.byte 50 +.byte 43 +.byte 50 +.byte 32 +.byte 61 +.byte 61 +.byte 32 +.byte 53 +.byte 32 +.byte 46 +.byte 0 +.align 1 +.LC1006: +.byte 32 +.byte 32 +.byte 32 +.byte 83 +.byte 101 +.byte 114 +.byte 105 +.byte 111 +.byte 117 +.byte 115 +.byte 32 +.byte 68 +.byte 69 +.byte 70 +.byte 69 +.byte 67 +.byte 84 +.byte 115 +.byte 44 +.byte 32 +.byte 108 +.byte 105 +.byte 107 +.byte 101 +.byte 32 +.byte 108 +.byte 97 +.byte 99 +.byte 107 +.byte 32 +.byte 111 +.byte 102 +.byte 32 +.byte 97 +.byte 32 +.byte 103 +.byte 117 +.byte 97 +.byte 114 +.byte 100 +.byte 32 +.byte 100 +.byte 105 +.byte 103 +.byte 105 +.byte 116 +.byte 44 +.byte 32 +.byte 97 +.byte 110 +.byte 100 +.byte 0 +.align 1 +.LC1005: +.byte 32 +.byte 32 +.byte 32 +.byte 70 +.byte 76 +.byte 65 +.byte 87 +.byte 115 +.byte 44 +.byte 32 +.byte 108 +.byte 105 +.byte 107 +.byte 101 +.byte 32 +.byte 108 +.byte 97 +.byte 99 +.byte 107 +.byte 32 +.byte 111 +.byte 102 +.byte 32 +.byte 97 +.byte 32 +.byte 115 +.byte 116 +.byte 105 +.byte 99 +.byte 107 +.byte 121 +.byte 32 +.byte 98 +.byte 105 +.byte 116 +.byte 44 +.byte 0 +.align 1 +.LC1004: +.byte 84 +.byte 104 +.byte 101 +.byte 32 +.byte 112 +.byte 114 +.byte 111 +.byte 103 +.byte 114 +.byte 97 +.byte 109 +.byte 32 +.byte 97 +.byte 116 +.byte 116 +.byte 101 +.byte 109 +.byte 112 +.byte 116 +.byte 115 +.byte 32 +.byte 116 +.byte 111 +.byte 32 +.byte 100 +.byte 105 +.byte 115 +.byte 99 +.byte 114 +.byte 105 +.byte 109 +.byte 105 +.byte 110 +.byte 97 +.byte 116 +.byte 101 +.byte 32 +.byte 97 +.byte 109 +.byte 111 +.byte 110 +.byte 103 +.byte 0 +.align 1 +.LC1000: +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 68 +.byte 101 +.byte 99 +.byte 105 +.byte 109 +.byte 97 +.byte 108 +.byte 45 +.byte 66 +.byte 105 +.byte 110 +.byte 97 +.byte 114 +.byte 121 +.byte 32 +.byte 99 +.byte 111 +.byte 110 +.byte 118 +.byte 101 +.byte 114 +.byte 115 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 78 +.byte 79 +.byte 84 +.byte 32 +.byte 89 +.byte 69 +.byte 84 +.byte 32 +.byte 116 +.byte 101 +.byte 115 +.byte 116 +.byte 101 +.byte 100 +.byte 32 +.byte 102 +.byte 111 +.byte 114 +.byte 32 +.byte 97 +.byte 99 +.byte 99 +.byte 117 +.byte 114 +.byte 97 +.byte 99 +.byte 121 +.byte 46 +.byte 0 +.align 1 +.LC999: +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 69 +.byte 120 +.byte 116 +.byte 114 +.byte 97 +.byte 45 +.byte 112 +.byte 114 +.byte 101 +.byte 99 +.byte 105 +.byte 115 +.byte 101 +.byte 32 +.byte 115 +.byte 117 +.byte 98 +.byte 101 +.byte 120 +.byte 112 +.byte 114 +.byte 101 +.byte 115 +.byte 115 +.byte 105 +.byte 111 +.byte 110 +.byte 115 +.byte 32 +.byte 97 +.byte 114 +.byte 101 +.byte 32 +.byte 114 +.byte 101 +.byte 118 +.byte 101 +.byte 97 +.byte 108 +.byte 101 +.byte 100 +.byte 32 +.byte 98 +.byte 117 +.byte 116 +.byte 32 +.byte 78 +.byte 79 +.byte 84 +.byte 32 +.byte 89 +.byte 69 +.byte 84 +.byte 32 +.byte 116 +.byte 101 +.byte 115 +.byte 116 +.byte 101 +.byte 100 +.byte 46 +.byte 0 +.align 1 +.LC998: +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 83 +.byte 113 +.byte 114 +.byte 116 +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 116 +.byte 101 +.byte 115 +.byte 116 +.byte 101 +.byte 100 +.byte 46 +.byte 32 +.byte 32 +.byte 89 +.byte 94 +.byte 88 +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 110 +.byte 111 +.byte 116 +.byte 32 +.byte 116 +.byte 101 +.byte 115 +.byte 116 +.byte 101 +.byte 100 +.byte 46 +.byte 0 +.align 1 +.LC997: +.byte 9 +.byte 97 +.byte 110 +.byte 100 +.byte 32 +.byte 102 +.byte 111 +.byte 114 +.byte 32 +.byte 99 +.byte 111 +.byte 110 +.byte 116 +.byte 97 +.byte 109 +.byte 105 +.byte 110 +.byte 97 +.byte 116 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 119 +.byte 105 +.byte 116 +.byte 104 +.byte 32 +.byte 112 +.byte 115 +.byte 101 +.byte 117 +.byte 100 +.byte 111 +.byte 45 +.byte 122 +.byte 101 +.byte 114 +.byte 111 +.byte 115 +.byte 46 +.byte 0 +.align 1 +.LC996: +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 67 +.byte 111 +.byte 109 +.byte 112 +.byte 97 +.byte 114 +.byte 105 +.byte 115 +.byte 105 +.byte 111 +.byte 110 +.byte 115 +.byte 32 +.byte 97 +.byte 114 +.byte 101 +.byte 32 +.byte 99 +.byte 104 +.byte 101 +.byte 99 +.byte 107 +.byte 101 +.byte 100 +.byte 32 +.byte 102 +.byte 111 +.byte 114 +.byte 32 +.byte 99 +.byte 111 +.byte 110 +.byte 115 +.byte 105 +.byte 115 +.byte 116 +.byte 101 +.byte 110 +.byte 99 +.byte 121 +.byte 32 +.byte 119 +.byte 105 +.byte 116 +.byte 104 +.byte 32 +.byte 115 +.byte 117 +.byte 98 +.byte 116 +.byte 114 +.byte 97 +.byte 99 +.byte 116 +.byte 105 +.byte 111 +.byte 110 +.byte 0 +.align 1 +.LC995: +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 86 +.byte 48 +.byte 32 +.byte 32 +.byte 116 +.byte 101 +.byte 108 +.byte 108 +.byte 115 +.byte 44 +.byte 32 +.byte 114 +.byte 111 +.byte 117 +.byte 103 +.byte 104 +.byte 108 +.byte 121 +.byte 44 +.byte 32 +.byte 119 +.byte 104 +.byte 101 +.byte 116 +.byte 104 +.byte 101 +.byte 114 +.byte 32 +.byte 32 +.byte 73 +.byte 110 +.byte 102 +.byte 105 +.byte 110 +.byte 105 +.byte 116 +.byte 121 +.byte 32 +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 114 +.byte 101 +.byte 112 +.byte 114 +.byte 101 +.byte 115 +.byte 101 +.byte 110 +.byte 116 +.byte 101 +.byte 100 +.byte 46 +.byte 0 +.align 1 +.LC994: +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 86 +.byte 32 +.byte 61 +.byte 32 +.byte 97 +.byte 110 +.byte 32 +.byte 111 +.byte 118 +.byte 101 +.byte 114 +.byte 102 +.byte 108 +.byte 111 +.byte 119 +.byte 32 +.byte 116 +.byte 104 +.byte 114 +.byte 101 +.byte 115 +.byte 104 +.byte 111 +.byte 108 +.byte 100 +.byte 44 +.byte 32 +.byte 114 +.byte 111 +.byte 117 +.byte 103 +.byte 104 +.byte 108 +.byte 121 +.byte 46 +.byte 0 +.align 1 +.LC993: +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 69 +.byte 48 +.byte 32 +.byte 97 +.byte 110 +.byte 100 +.byte 32 +.byte 80 +.byte 115 +.byte 101 +.byte 117 +.byte 100 +.byte 111 +.byte 90 +.byte 101 +.byte 114 +.byte 111 +.byte 32 +.byte 116 +.byte 101 +.byte 108 +.byte 108 +.byte 32 +.byte 119 +.byte 104 +.byte 101 +.byte 116 +.byte 104 +.byte 101 +.byte 114 +.byte 32 +.byte 117 +.byte 110 +.byte 100 +.byte 101 +.byte 114 +.byte 102 +.byte 108 +.byte 111 +.byte 119 +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 97 +.byte 98 +.byte 114 +.byte 117 +.byte 112 +.byte 116 +.byte 44 +.byte 32 +.byte 103 +.byte 114 +.byte 97 +.byte 100 +.byte 117 +.byte 97 +.byte 108 +.byte 44 +.byte 32 +.byte 111 +.byte 114 +.byte 32 +.byte 102 +.byte 117 +.byte 122 +.byte 122 +.byte 121 +.byte 46 +.byte 0 +.align 1 +.LC992: +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 85 +.byte 110 +.byte 100 +.byte 101 +.byte 114 +.byte 102 +.byte 108 +.byte 111 +.byte 119 +.byte 84 +.byte 104 +.byte 114 +.byte 101 +.byte 115 +.byte 104 +.byte 111 +.byte 108 +.byte 100 +.byte 32 +.byte 61 +.byte 32 +.byte 97 +.byte 110 +.byte 32 +.byte 117 +.byte 110 +.byte 100 +.byte 101 +.byte 114 +.byte 102 +.byte 108 +.byte 111 +.byte 119 +.byte 32 +.byte 116 +.byte 104 +.byte 114 +.byte 101 +.byte 115 +.byte 104 +.byte 111 +.byte 108 +.byte 100 +.byte 46 +.byte 0 +.align 1 +.LC991: +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 87 +.byte 104 +.byte 101 +.byte 116 +.byte 104 +.byte 101 +.byte 114 +.byte 32 +.byte 97 +.byte 32 +.byte 83 +.byte 116 +.byte 105 +.byte 99 +.byte 107 +.byte 121 +.byte 32 +.byte 66 +.byte 105 +.byte 116 +.byte 32 +.byte 117 +.byte 115 +.byte 101 +.byte 100 +.byte 32 +.byte 99 +.byte 111 +.byte 114 +.byte 114 +.byte 101 +.byte 99 +.byte 116 +.byte 108 +.byte 121 +.byte 32 +.byte 102 +.byte 111 +.byte 114 +.byte 32 +.byte 114 +.byte 111 +.byte 117 +.byte 110 +.byte 100 +.byte 105 +.byte 110 +.byte 103 +.byte 46 +.byte 0 +.align 1 +.LC990: +.byte 9 +.byte 102 +.byte 111 +.byte 114 +.byte 32 +.byte 77 +.byte 117 +.byte 108 +.byte 116 +.byte 46 +.byte 44 +.byte 32 +.byte 68 +.byte 105 +.byte 118 +.byte 46 +.byte 44 +.byte 32 +.byte 65 +.byte 100 +.byte 100 +.byte 47 +.byte 83 +.byte 117 +.byte 98 +.byte 116 +.byte 46 +.byte 32 +.byte 97 +.byte 110 +.byte 100 +.byte 32 +.byte 83 +.byte 113 +.byte 114 +.byte 116 +.byte 46 +.byte 0 +.align 1 +.LC989: +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 87 +.byte 104 +.byte 101 +.byte 116 +.byte 104 +.byte 101 +.byte 114 +.byte 32 +.byte 97 +.byte 114 +.byte 105 +.byte 116 +.byte 104 +.byte 109 +.byte 101 +.byte 116 +.byte 105 +.byte 99 +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 99 +.byte 104 +.byte 111 +.byte 112 +.byte 112 +.byte 101 +.byte 100 +.byte 44 +.byte 32 +.byte 99 +.byte 111 +.byte 114 +.byte 114 +.byte 101 +.byte 99 +.byte 116 +.byte 108 +.byte 121 +.byte 32 +.byte 114 +.byte 111 +.byte 117 +.byte 110 +.byte 100 +.byte 101 +.byte 100 +.byte 44 +.byte 32 +.byte 111 +.byte 114 +.byte 32 +.byte 115 +.byte 111 +.byte 109 +.byte 101 +.byte 116 +.byte 104 +.byte 105 +.byte 110 +.byte 103 +.byte 32 +.byte 101 +.byte 108 +.byte 115 +.byte 101 +.byte 0 +.align 1 +.LC988: +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 65 +.byte 100 +.byte 101 +.byte 113 +.byte 117 +.byte 97 +.byte 99 +.byte 121 +.byte 32 +.byte 111 +.byte 102 +.byte 32 +.byte 103 +.byte 117 +.byte 97 +.byte 114 +.byte 100 +.byte 32 +.byte 100 +.byte 105 +.byte 103 +.byte 105 +.byte 116 +.byte 115 +.byte 32 +.byte 102 +.byte 111 +.byte 114 +.byte 32 +.byte 77 +.byte 117 +.byte 108 +.byte 116 +.byte 46 +.byte 44 +.byte 32 +.byte 68 +.byte 105 +.byte 118 +.byte 46 +.byte 32 +.byte 97 +.byte 110 +.byte 100 +.byte 32 +.byte 83 +.byte 117 +.byte 98 +.byte 116 +.byte 46 +.byte 0 +.align 1 +.LC987: +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 85 +.byte 49 +.byte 32 +.byte 61 +.byte 32 +.byte 49 +.byte 47 +.byte 82 +.byte 97 +.byte 100 +.byte 105 +.byte 120 +.byte 94 +.byte 80 +.byte 114 +.byte 101 +.byte 99 +.byte 105 +.byte 115 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 61 +.byte 32 +.byte 79 +.byte 110 +.byte 101 +.byte 32 +.byte 85 +.byte 108 +.byte 112 +.byte 32 +.byte 111 +.byte 102 +.byte 32 +.byte 110 +.byte 117 +.byte 109 +.byte 98 +.byte 101 +.byte 114 +.byte 115 +.byte 32 +.byte 97 +.byte 32 +.byte 108 +.byte 105 +.byte 116 +.byte 116 +.byte 108 +.byte 101 +.byte 32 +.byte 108 +.byte 101 +.byte 115 +.byte 115 +.byte 32 +.byte 116 +.byte 104 +.byte 97 +.byte 110 +.byte 32 +.byte 49 +.byte 46 +.byte 48 +.byte 32 +.byte 46 +.byte 0 +.align 1 +.LC986: +.byte 9 +.byte 40 +.byte 79 +.byte 110 +.byte 101 +.byte 85 +.byte 108 +.byte 112 +.byte 110 +.byte 105 +.byte 116 +.byte 32 +.byte 105 +.byte 110 +.byte 32 +.byte 116 +.byte 104 +.byte 101 +.byte 32 +.byte 76 +.byte 97 +.byte 115 +.byte 116 +.byte 32 +.byte 80 +.byte 108 +.byte 97 +.byte 99 +.byte 101 +.byte 41 +.byte 32 +.byte 111 +.byte 102 +.byte 32 +.byte 49 +.byte 46 +.byte 48 +.byte 48 +.byte 48 +.byte 120 +.byte 120 +.byte 120 +.byte 32 +.byte 46 +.byte 0 +.align 1 +.LC985: +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 85 +.byte 50 +.byte 32 +.byte 61 +.byte 32 +.byte 82 +.byte 97 +.byte 100 +.byte 105 +.byte 120 +.byte 47 +.byte 82 +.byte 97 +.byte 100 +.byte 105 +.byte 120 +.byte 94 +.byte 80 +.byte 114 +.byte 101 +.byte 99 +.byte 105 +.byte 115 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 61 +.byte 32 +.byte 79 +.byte 110 +.byte 101 +.byte 32 +.byte 85 +.byte 108 +.byte 112 +.byte 0 +.align 1 +.LC984: +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 80 +.byte 114 +.byte 101 +.byte 99 +.byte 105 +.byte 115 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 61 +.byte 32 +.byte 110 +.byte 117 +.byte 109 +.byte 98 +.byte 101 +.byte 114 +.byte 32 +.byte 111 +.byte 102 +.byte 32 +.byte 115 +.byte 105 +.byte 103 +.byte 110 +.byte 105 +.byte 102 +.byte 105 +.byte 99 +.byte 97 +.byte 110 +.byte 116 +.byte 32 +.byte 100 +.byte 105 +.byte 103 +.byte 105 +.byte 116 +.byte 115 +.byte 32 +.byte 99 +.byte 97 +.byte 114 +.byte 114 +.byte 105 +.byte 101 +.byte 100 +.byte 46 +.byte 0 +.align 1 +.LC983: +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 82 +.byte 97 +.byte 100 +.byte 105 +.byte 120 +.byte 32 +.byte 61 +.byte 32 +.byte 49 +.byte 44 +.byte 32 +.byte 50 +.byte 44 +.byte 32 +.byte 52 +.byte 44 +.byte 32 +.byte 56 +.byte 44 +.byte 32 +.byte 49 +.byte 48 +.byte 44 +.byte 32 +.byte 49 +.byte 54 +.byte 44 +.byte 32 +.byte 49 +.byte 48 +.byte 48 +.byte 44 +.byte 32 +.byte 50 +.byte 53 +.byte 54 +.byte 32 +.byte 46 +.byte 46 +.byte 46 +.byte 0 +.align 1 +.LC982: +.byte 82 +.byte 117 +.byte 110 +.byte 110 +.byte 105 +.byte 110 +.byte 103 +.byte 32 +.byte 116 +.byte 104 +.byte 105 +.byte 115 +.byte 32 +.byte 112 +.byte 114 +.byte 111 +.byte 103 +.byte 114 +.byte 97 +.byte 109 +.byte 32 +.byte 115 +.byte 104 +.byte 111 +.byte 117 +.byte 108 +.byte 100 +.byte 32 +.byte 114 +.byte 101 +.byte 118 +.byte 101 +.byte 97 +.byte 108 +.byte 32 +.byte 116 +.byte 104 +.byte 101 +.byte 115 +.byte 101 +.byte 32 +.byte 99 +.byte 104 +.byte 97 +.byte 114 +.byte 97 +.byte 99 +.byte 116 +.byte 101 +.byte 114 +.byte 105 +.byte 115 +.byte 116 +.byte 105 +.byte 99 +.byte 115 +.byte 58 +.byte 0 +.align 1 +.LC978: +.byte 9 +.byte 79 +.byte 116 +.byte 104 +.byte 101 +.byte 114 +.byte 32 +.byte 114 +.byte 101 +.byte 108 +.byte 101 +.byte 118 +.byte 97 +.byte 110 +.byte 116 +.byte 32 +.byte 99 +.byte 111 +.byte 109 +.byte 112 +.byte 105 +.byte 108 +.byte 101 +.byte 114 +.byte 32 +.byte 111 +.byte 112 +.byte 116 +.byte 105 +.byte 111 +.byte 110 +.byte 115 +.byte 58 +.byte 0 +.align 1 +.LC977: +.byte 9 +.byte 79 +.byte 112 +.byte 116 +.byte 105 +.byte 109 +.byte 105 +.byte 122 +.byte 97 +.byte 116 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 108 +.byte 101 +.byte 118 +.byte 101 +.byte 108 +.byte 58 +.byte 10 +.byte 0 +.align 1 +.LC976: +.byte 9 +.byte 67 +.byte 111 +.byte 109 +.byte 112 +.byte 105 +.byte 108 +.byte 101 +.byte 114 +.byte 58 +.byte 10 +.byte 0 +.align 1 +.LC975: +.byte 9 +.byte 67 +.byte 111 +.byte 109 +.byte 112 +.byte 117 +.byte 116 +.byte 101 +.byte 114 +.byte 58 +.byte 10 +.byte 0 +.align 1 +.LC974: +.byte 9 +.byte 86 +.byte 101 +.byte 114 +.byte 115 +.byte 105 +.byte 111 +.byte 110 +.byte 58 +.byte 9 +.byte 49 +.byte 48 +.byte 32 +.byte 70 +.byte 101 +.byte 98 +.byte 114 +.byte 117 +.byte 97 +.byte 114 +.byte 121 +.byte 32 +.byte 49 +.byte 57 +.byte 56 +.byte 57 +.byte 59 +.byte 0 +.align 1 +.LC973: +.byte 9 +.byte 80 +.byte 114 +.byte 101 +.byte 99 +.byte 105 +.byte 115 +.byte 105 +.byte 111 +.byte 110 +.byte 58 +.byte 9 +.byte 100 +.byte 111 +.byte 117 +.byte 98 +.byte 108 +.byte 101 +.byte 59 +.byte 0 +.align 1 +.LC972: +.byte 73 +.byte 110 +.byte 32 +.byte 100 +.byte 111 +.byte 105 +.byte 110 +.byte 103 +.byte 32 +.byte 115 +.byte 111 +.byte 44 +.byte 32 +.byte 112 +.byte 108 +.byte 101 +.byte 97 +.byte 115 +.byte 101 +.byte 32 +.byte 105 +.byte 110 +.byte 99 +.byte 108 +.byte 117 +.byte 100 +.byte 101 +.byte 32 +.byte 116 +.byte 104 +.byte 101 +.byte 32 +.byte 102 +.byte 111 +.byte 108 +.byte 108 +.byte 111 +.byte 119 +.byte 105 +.byte 110 +.byte 103 +.byte 32 +.byte 105 +.byte 110 +.byte 102 +.byte 111 +.byte 114 +.byte 109 +.byte 97 +.byte 116 +.byte 105 +.byte 111 +.byte 110 +.byte 58 +.byte 0 +.align 1 +.LC971: +.byte 9 +.byte 83 +.byte 97 +.byte 110 +.byte 32 +.byte 70 +.byte 114 +.byte 97 +.byte 110 +.byte 99 +.byte 105 +.byte 115 +.byte 99 +.byte 111 +.byte 44 +.byte 32 +.byte 67 +.byte 65 +.byte 32 +.byte 57 +.byte 52 +.byte 49 +.byte 52 +.byte 51 +.byte 45 +.byte 48 +.byte 55 +.byte 48 +.byte 52 +.byte 44 +.byte 32 +.byte 85 +.byte 83 +.byte 65 +.byte 10 +.byte 0 +.align 1 +.LC970: +.byte 9 +.byte 85 +.byte 110 +.byte 105 +.byte 118 +.byte 101 +.byte 114 +.byte 115 +.byte 105 +.byte 116 +.byte 121 +.byte 32 +.byte 111 +.byte 102 +.byte 32 +.byte 67 +.byte 97 +.byte 108 +.byte 105 +.byte 102 +.byte 111 +.byte 114 +.byte 110 +.byte 105 +.byte 97 +.byte 0 +.align 1 +.LC969: +.byte 9 +.byte 67 +.byte 111 +.byte 109 +.byte 112 +.byte 117 +.byte 116 +.byte 101 +.byte 114 +.byte 32 +.byte 67 +.byte 101 +.byte 110 +.byte 116 +.byte 101 +.byte 114 +.byte 32 +.byte 85 +.byte 45 +.byte 55 +.byte 54 +.byte 0 +.align 1 +.LC968: +.byte 9 +.byte 82 +.byte 105 +.byte 99 +.byte 104 +.byte 97 +.byte 114 +.byte 100 +.byte 32 +.byte 75 +.byte 97 +.byte 114 +.byte 112 +.byte 105 +.byte 110 +.byte 115 +.byte 107 +.byte 105 +.byte 0 +.align 1 +.LC967: +.byte 80 +.byte 108 +.byte 101 +.byte 97 +.byte 115 +.byte 101 +.byte 32 +.byte 115 +.byte 101 +.byte 110 +.byte 100 +.byte 32 +.byte 115 +.byte 117 +.byte 103 +.byte 103 +.byte 101 +.byte 115 +.byte 116 +.byte 105 +.byte 111 +.byte 110 +.byte 115 +.byte 32 +.byte 97 +.byte 110 +.byte 100 +.byte 32 +.byte 105 +.byte 110 +.byte 116 +.byte 101 +.byte 114 +.byte 101 +.byte 115 +.byte 116 +.byte 105 +.byte 110 +.byte 103 +.byte 32 +.byte 114 +.byte 101 +.byte 115 +.byte 117 +.byte 108 +.byte 116 +.byte 115 +.byte 32 +.byte 116 +.byte 111 +.byte 0 +.align 1 +.LC966: +.byte 99 +.byte 111 +.byte 112 +.byte 101 +.byte 32 +.byte 119 +.byte 105 +.byte 116 +.byte 104 +.byte 32 +.byte 117 +.byte 110 +.byte 97 +.byte 110 +.byte 116 +.byte 105 +.byte 99 +.byte 105 +.byte 112 +.byte 97 +.byte 116 +.byte 101 +.byte 100 +.byte 32 +.byte 97 +.byte 110 +.byte 100 +.byte 32 +.byte 110 +.byte 101 +.byte 119 +.byte 108 +.byte 121 +.byte 32 +.byte 117 +.byte 110 +.byte 99 +.byte 111 +.byte 118 +.byte 101 +.byte 114 +.byte 101 +.byte 100 +.byte 32 +.byte 97 +.byte 114 +.byte 105 +.byte 116 +.byte 104 +.byte 109 +.byte 101 +.byte 116 +.byte 105 +.byte 99 +.byte 32 +.byte 112 +.byte 97 +.byte 116 +.byte 104 +.byte 111 +.byte 108 +.byte 111 +.byte 103 +.byte 105 +.byte 101 +.byte 115 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC965: +.byte 85 +.byte 115 +.byte 101 +.byte 114 +.byte 115 +.byte 32 +.byte 97 +.byte 114 +.byte 101 +.byte 32 +.byte 105 +.byte 110 +.byte 118 +.byte 105 +.byte 116 +.byte 101 +.byte 100 +.byte 32 +.byte 116 +.byte 111 +.byte 32 +.byte 104 +.byte 101 +.byte 108 +.byte 112 +.byte 32 +.byte 100 +.byte 101 +.byte 98 +.byte 117 +.byte 103 +.byte 32 +.byte 97 +.byte 110 +.byte 100 +.byte 32 +.byte 97 +.byte 117 +.byte 103 +.byte 109 +.byte 101 +.byte 110 +.byte 116 +.byte 32 +.byte 116 +.byte 104 +.byte 105 +.byte 115 +.byte 32 +.byte 112 +.byte 114 +.byte 111 +.byte 103 +.byte 114 +.byte 97 +.byte 109 +.byte 32 +.byte 115 +.byte 111 +.byte 32 +.byte 105 +.byte 116 +.byte 32 +.byte 119 +.byte 105 +.byte 108 +.byte 108 +.byte 0 +.align 1 +.LC961: +.byte 65 +.byte 110 +.byte 115 +.byte 119 +.byte 101 +.byte 114 +.byte 32 +.byte 113 +.byte 117 +.byte 101 +.byte 115 +.byte 116 +.byte 105 +.byte 111 +.byte 110 +.byte 115 +.byte 32 +.byte 119 +.byte 105 +.byte 116 +.byte 104 +.byte 32 +.byte 89 +.byte 44 +.byte 32 +.byte 121 +.byte 44 +.byte 32 +.byte 78 +.byte 32 +.byte 111 +.byte 114 +.byte 32 +.byte 110 +.byte 32 +.byte 40 +.byte 117 +.byte 110 +.byte 108 +.byte 101 +.byte 115 +.byte 115 +.byte 32 +.byte 111 +.byte 116 +.byte 104 +.byte 101 +.byte 114 +.byte 119 +.byte 105 +.byte 115 +.byte 101 +.byte 32 +.byte 105 +.byte 110 +.byte 100 +.byte 105 +.byte 99 +.byte 97 +.byte 116 +.byte 101 +.byte 100 +.byte 41 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC960: +.byte 97 +.byte 109 +.byte 101 +.byte 110 +.byte 100 +.byte 32 +.byte 105 +.byte 116 +.byte 32 +.byte 116 +.byte 111 +.byte 32 +.byte 109 +.byte 97 +.byte 107 +.byte 101 +.byte 32 +.byte 102 +.byte 117 +.byte 114 +.byte 116 +.byte 104 +.byte 101 +.byte 114 +.byte 32 +.byte 112 +.byte 114 +.byte 111 +.byte 103 +.byte 114 +.byte 101 +.byte 115 +.byte 115 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC959: +.byte 112 +.byte 114 +.byte 111 +.byte 103 +.byte 114 +.byte 97 +.byte 109 +.byte 32 +.byte 97 +.byte 110 +.byte 121 +.byte 119 +.byte 97 +.byte 121 +.byte 32 +.byte 116 +.byte 111 +.byte 32 +.byte 115 +.byte 101 +.byte 101 +.byte 32 +.byte 104 +.byte 111 +.byte 119 +.byte 32 +.byte 109 +.byte 97 +.byte 110 +.byte 121 +.byte 32 +.byte 109 +.byte 105 +.byte 108 +.byte 101 +.byte 115 +.byte 116 +.byte 111 +.byte 110 +.byte 101 +.byte 115 +.byte 32 +.byte 105 +.byte 116 +.byte 32 +.byte 112 +.byte 97 +.byte 115 +.byte 115 +.byte 101 +.byte 115 +.byte 44 +.byte 32 +.byte 97 +.byte 110 +.byte 100 +.byte 32 +.byte 116 +.byte 104 +.byte 101 +.byte 110 +.byte 0 +.align 1 +.LC958: +.byte 119 +.byte 97 +.byte 114 +.byte 110 +.byte 105 +.byte 110 +.byte 103 +.byte 46 +.byte 32 +.byte 32 +.byte 73 +.byte 102 +.byte 32 +.byte 112 +.byte 101 +.byte 114 +.byte 115 +.byte 117 +.byte 97 +.byte 115 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 97 +.byte 118 +.byte 97 +.byte 105 +.byte 108 +.byte 115 +.byte 32 +.byte 110 +.byte 97 +.byte 117 +.byte 103 +.byte 104 +.byte 116 +.byte 44 +.byte 32 +.byte 100 +.byte 111 +.byte 110 +.byte 39 +.byte 116 +.byte 32 +.byte 100 +.byte 101 +.byte 115 +.byte 112 +.byte 97 +.byte 105 +.byte 114 +.byte 32 +.byte 98 +.byte 117 +.byte 116 +.byte 32 +.byte 114 +.byte 117 +.byte 110 +.byte 32 +.byte 116 +.byte 104 +.byte 105 +.byte 115 +.byte 0 +.align 1 +.LC957: +.byte 116 +.byte 111 +.byte 32 +.byte 112 +.byte 101 +.byte 114 +.byte 115 +.byte 101 +.byte 118 +.byte 101 +.byte 114 +.byte 101 +.byte 32 +.byte 119 +.byte 105 +.byte 116 +.byte 104 +.byte 32 +.byte 97 +.byte 32 +.byte 115 +.byte 117 +.byte 114 +.byte 114 +.byte 111 +.byte 103 +.byte 97 +.byte 116 +.byte 101 +.byte 32 +.byte 118 +.byte 97 +.byte 108 +.byte 117 +.byte 101 +.byte 32 +.byte 97 +.byte 102 +.byte 116 +.byte 101 +.byte 114 +.byte 44 +.byte 32 +.byte 112 +.byte 101 +.byte 114 +.byte 104 +.byte 97 +.byte 112 +.byte 115 +.byte 44 +.byte 32 +.byte 100 +.byte 105 +.byte 115 +.byte 112 +.byte 108 +.byte 97 +.byte 121 +.byte 105 +.byte 110 +.byte 103 +.byte 32 +.byte 115 +.byte 111 +.byte 109 +.byte 101 +.byte 0 +.align 1 +.LC956: +.byte 101 +.byte 114 +.byte 114 +.byte 111 +.byte 114 +.byte 32 +.byte 108 +.byte 105 +.byte 107 +.byte 101 +.byte 32 +.byte 79 +.byte 118 +.byte 101 +.byte 114 +.byte 47 +.byte 85 +.byte 110 +.byte 100 +.byte 101 +.byte 114 +.byte 102 +.byte 108 +.byte 111 +.byte 119 +.byte 32 +.byte 111 +.byte 114 +.byte 32 +.byte 68 +.byte 105 +.byte 118 +.byte 105 +.byte 115 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 98 +.byte 121 +.byte 32 +.byte 90 +.byte 101 +.byte 114 +.byte 111 +.byte 32 +.byte 111 +.byte 99 +.byte 99 +.byte 117 +.byte 114 +.byte 115 +.byte 44 +.byte 32 +.byte 98 +.byte 117 +.byte 116 +.byte 32 +.byte 114 +.byte 97 +.byte 116 +.byte 104 +.byte 101 +.byte 114 +.byte 0 +.align 1 +.LC955: +.byte 116 +.byte 114 +.byte 121 +.byte 32 +.byte 116 +.byte 111 +.byte 32 +.byte 112 +.byte 101 +.byte 114 +.byte 115 +.byte 117 +.byte 97 +.byte 100 +.byte 101 +.byte 32 +.byte 116 +.byte 104 +.byte 101 +.byte 32 +.byte 99 +.byte 111 +.byte 109 +.byte 112 +.byte 117 +.byte 116 +.byte 101 +.byte 114 +.byte 32 +.byte 78 +.byte 79 +.byte 84 +.byte 32 +.byte 116 +.byte 111 +.byte 32 +.byte 116 +.byte 101 +.byte 114 +.byte 109 +.byte 105 +.byte 110 +.byte 97 +.byte 116 +.byte 101 +.byte 32 +.byte 101 +.byte 120 +.byte 101 +.byte 99 +.byte 117 +.byte 116 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 119 +.byte 104 +.byte 101 +.byte 110 +.byte 32 +.byte 97 +.byte 110 +.byte 0 +.align 1 +.LC954: +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 96 +.byte 69 +.byte 78 +.byte 68 +.byte 32 +.byte 79 +.byte 70 +.byte 32 +.byte 84 +.byte 69 +.byte 83 +.byte 84 +.byte 39 +.byte 44 +.byte 10 +.byte 0 +.align 1 +.LC953: +.byte 76 +.byte 101 +.byte 115 +.byte 116 +.byte 32 +.byte 116 +.byte 104 +.byte 105 +.byte 115 +.byte 32 +.byte 112 +.byte 114 +.byte 111 +.byte 103 +.byte 114 +.byte 97 +.byte 109 +.byte 32 +.byte 115 +.byte 116 +.byte 111 +.byte 112 +.byte 32 +.byte 112 +.byte 114 +.byte 101 +.byte 109 +.byte 97 +.byte 116 +.byte 117 +.byte 114 +.byte 101 +.byte 108 +.byte 121 +.byte 44 +.byte 32 +.byte 105 +.byte 46 +.byte 101 +.byte 46 +.byte 32 +.byte 98 +.byte 101 +.byte 102 +.byte 111 +.byte 114 +.byte 101 +.byte 32 +.byte 100 +.byte 105 +.byte 115 +.byte 112 +.byte 108 +.byte 97 +.byte 121 +.byte 105 +.byte 110 +.byte 103 +.byte 10 +.byte 0 +.align 1 +.LC949: +.byte 37 +.byte 115 +.byte 10 +.byte 0 +.align 1 +.LC943: +.byte 32 +.byte 32 +.byte 32 +.byte 80 +.byte 76 +.byte 69 +.byte 65 +.byte 83 +.byte 69 +.byte 32 +.byte 78 +.byte 79 +.byte 84 +.byte 73 +.byte 70 +.byte 89 +.byte 32 +.byte 75 +.byte 65 +.byte 82 +.byte 80 +.byte 73 +.byte 78 +.byte 75 +.byte 83 +.byte 73 +.byte 33 +.byte 10 +.byte 0 +.align 1 +.LC942: +.byte 37 +.byte 115 +.byte 32 +.byte 116 +.byte 101 +.byte 115 +.byte 116 +.byte 32 +.byte 97 +.byte 112 +.byte 112 +.byte 101 +.byte 97 +.byte 114 +.byte 115 +.byte 32 +.byte 116 +.byte 111 +.byte 32 +.byte 98 +.byte 101 +.byte 32 +.byte 105 +.byte 110 +.byte 99 +.byte 111 +.byte 110 +.byte 115 +.byte 105 +.byte 115 +.byte 116 +.byte 101 +.byte 110 +.byte 116 +.byte 46 +.byte 46 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC939: +.byte 9 +.byte 100 +.byte 105 +.byte 102 +.byte 102 +.byte 101 +.byte 114 +.byte 115 +.byte 32 +.byte 102 +.byte 114 +.byte 111 +.byte 109 +.byte 32 +.byte 90 +.byte 32 +.byte 42 +.byte 32 +.byte 49 +.byte 32 +.byte 61 +.byte 32 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 10 +.byte 0 +.align 1 +.LC938: +.byte 9 +.byte 67 +.byte 111 +.byte 109 +.byte 112 +.byte 97 +.byte 114 +.byte 105 +.byte 115 +.byte 111 +.byte 110 +.byte 32 +.byte 97 +.byte 108 +.byte 108 +.byte 101 +.byte 103 +.byte 101 +.byte 115 +.byte 32 +.byte 116 +.byte 104 +.byte 97 +.byte 116 +.byte 32 +.byte 49 +.byte 32 +.byte 42 +.byte 32 +.byte 90 +.byte 32 +.byte 61 +.byte 32 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 10 +.byte 0 +.align 1 +.LC937: +.byte 77 +.byte 117 +.byte 108 +.byte 116 +.byte 105 +.byte 112 +.byte 108 +.byte 105 +.byte 99 +.byte 97 +.byte 116 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 100 +.byte 111 +.byte 101 +.byte 115 +.byte 32 +.byte 110 +.byte 111 +.byte 116 +.byte 32 +.byte 99 +.byte 111 +.byte 109 +.byte 109 +.byte 117 +.byte 116 +.byte 101 +.byte 33 +.byte 10 +.byte 0 +.align 1 +.LC932: +.byte 90 +.byte 32 +.byte 47 +.byte 32 +.byte 49 +.byte 32 +.byte 61 +.byte 32 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 10 +.byte 0 +.align 1 +.LC929: +.byte 49 +.byte 32 +.byte 42 +.byte 32 +.byte 90 +.byte 32 +.byte 61 +.byte 61 +.byte 32 +.byte 37 +.byte 103 +.byte 10 +.byte 0 +.align 1 +.LC926: +.byte 90 +.byte 32 +.byte 42 +.byte 32 +.byte 49 +.byte 32 +.byte 61 +.byte 32 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 32 +.byte 0 +.align 1 +.LC923: +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 10 +.byte 9 +.byte 99 +.byte 111 +.byte 109 +.byte 112 +.byte 97 +.byte 114 +.byte 101 +.byte 115 +.byte 32 +.byte 100 +.byte 105 +.byte 102 +.byte 102 +.byte 101 +.byte 114 +.byte 101 +.byte 110 +.byte 116 +.byte 32 +.byte 102 +.byte 114 +.byte 111 +.byte 109 +.byte 32 +.byte 32 +.byte 0 +.align 1 +.LC922: +.byte 87 +.byte 104 +.byte 97 +.byte 116 +.byte 32 +.byte 112 +.byte 114 +.byte 105 +.byte 110 +.byte 116 +.byte 115 +.byte 32 +.byte 97 +.byte 115 +.byte 32 +.byte 90 +.byte 32 +.byte 61 +.byte 32 +.byte 0 +.align 1 +.LC917: +.byte 84 +.byte 104 +.byte 105 +.byte 115 +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 97 +.byte 32 +.byte 68 +.byte 69 +.byte 70 +.byte 69 +.byte 67 +.byte 84 +.byte 33 +.byte 10 +.byte 0 +.align 1 +.LC914: +.byte 84 +.byte 104 +.byte 105 +.byte 115 +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 97 +.byte 32 +.byte 86 +.byte 69 +.byte 82 +.byte 89 +.byte 32 +.byte 83 +.byte 69 +.byte 82 +.byte 73 +.byte 79 +.byte 85 +.byte 83 +.byte 32 +.byte 68 +.byte 69 +.byte 70 +.byte 69 +.byte 67 +.byte 84 +.byte 33 +.byte 10 +.byte 0 +.align 1 +.LC908: +.byte 32 +.byte 104 +.byte 97 +.byte 115 +.byte 32 +.byte 78 +.byte 79 +.byte 84 +.byte 32 +.byte 106 +.byte 117 +.byte 115 +.byte 116 +.byte 32 +.byte 98 +.byte 101 +.byte 101 +.byte 110 +.byte 32 +.byte 115 +.byte 105 +.byte 103 +.byte 110 +.byte 97 +.byte 108 +.byte 101 +.byte 100 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC907: +.byte 84 +.byte 104 +.byte 105 +.byte 115 +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 79 +.byte 46 +.byte 75 +.byte 46 +.byte 44 +.byte 32 +.byte 112 +.byte 114 +.byte 111 +.byte 118 +.byte 105 +.byte 100 +.byte 101 +.byte 100 +.byte 32 +.byte 79 +.byte 118 +.byte 101 +.byte 114 +.byte 47 +.byte 85 +.byte 110 +.byte 100 +.byte 101 +.byte 114 +.byte 102 +.byte 108 +.byte 111 +.byte 119 +.byte 0 +.align 1 +.LC904: +.byte 87 +.byte 104 +.byte 97 +.byte 116 +.byte 32 +.byte 116 +.byte 104 +.byte 101 +.byte 32 +.byte 109 +.byte 97 +.byte 99 +.byte 104 +.byte 105 +.byte 110 +.byte 101 +.byte 32 +.byte 103 +.byte 101 +.byte 116 +.byte 115 +.byte 32 +.byte 102 +.byte 111 +.byte 114 +.byte 32 +.byte 40 +.byte 90 +.byte 32 +.byte 43 +.byte 32 +.byte 90 +.byte 41 +.byte 32 +.byte 47 +.byte 32 +.byte 90 +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 32 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 32 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC900: +.byte 40 +.byte 90 +.byte 32 +.byte 43 +.byte 32 +.byte 90 +.byte 41 +.byte 32 +.byte 47 +.byte 32 +.byte 90 +.byte 32 +.byte 115 +.byte 104 +.byte 111 +.byte 117 +.byte 108 +.byte 100 +.byte 32 +.byte 98 +.byte 101 +.byte 32 +.byte 115 +.byte 97 +.byte 102 +.byte 101 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC899: +.byte 83 +.byte 105 +.byte 110 +.byte 99 +.byte 101 +.byte 32 +.byte 99 +.byte 111 +.byte 109 +.byte 112 +.byte 97 +.byte 114 +.byte 105 +.byte 115 +.byte 111 +.byte 110 +.byte 32 +.byte 100 +.byte 101 +.byte 110 +.byte 105 +.byte 101 +.byte 115 +.byte 32 +.byte 90 +.byte 32 +.byte 61 +.byte 32 +.byte 48 +.byte 44 +.byte 32 +.byte 101 +.byte 118 +.byte 97 +.byte 108 +.byte 117 +.byte 97 +.byte 116 +.byte 105 +.byte 110 +.byte 103 +.byte 32 +.byte 0 +.align 1 +.LC894: +.byte 83 +.byte 105 +.byte 109 +.byte 105 +.byte 108 +.byte 97 +.byte 114 +.byte 32 +.byte 100 +.byte 105 +.byte 115 +.byte 99 +.byte 114 +.byte 101 +.byte 112 +.byte 97 +.byte 110 +.byte 99 +.byte 105 +.byte 101 +.byte 115 +.byte 32 +.byte 104 +.byte 97 +.byte 118 +.byte 101 +.byte 32 +.byte 111 +.byte 99 +.byte 99 +.byte 117 +.byte 114 +.byte 114 +.byte 101 +.byte 100 +.byte 32 +.byte 37 +.byte 100 +.byte 32 +.byte 116 +.byte 105 +.byte 109 +.byte 101 +.byte 115 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC882: +.byte 9 +.byte 9 +.byte 116 +.byte 104 +.byte 101 +.byte 121 +.byte 32 +.byte 100 +.byte 105 +.byte 102 +.byte 102 +.byte 101 +.byte 114 +.byte 32 +.byte 98 +.byte 121 +.byte 32 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 32 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC881: +.byte 9 +.byte 119 +.byte 104 +.byte 105 +.byte 99 +.byte 104 +.byte 32 +.byte 99 +.byte 111 +.byte 109 +.byte 112 +.byte 97 +.byte 114 +.byte 101 +.byte 100 +.byte 32 +.byte 117 +.byte 110 +.byte 101 +.byte 113 +.byte 117 +.byte 97 +.byte 108 +.byte 32 +.byte 116 +.byte 111 +.byte 32 +.byte 99 +.byte 111 +.byte 114 +.byte 114 +.byte 101 +.byte 99 +.byte 116 +.byte 32 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 32 +.byte 59 +.byte 10 +.byte 0 +.align 1 +.LC880: +.byte 9 +.byte 121 +.byte 105 +.byte 101 +.byte 108 +.byte 100 +.byte 101 +.byte 100 +.byte 32 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 59 +.byte 10 +.byte 0 +.align 1 +.LC879: +.byte 9 +.byte 40 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 41 +.byte 32 +.byte 94 +.byte 32 +.byte 40 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 41 +.byte 10 +.byte 0 +.align 1 +.LC878: +.byte 99 +.byte 111 +.byte 109 +.byte 112 +.byte 117 +.byte 116 +.byte 105 +.byte 110 +.byte 103 +.byte 10 +.byte 0 +.align 1 +.LC877: +.byte 87 +.byte 65 +.byte 82 +.byte 78 +.byte 73 +.byte 78 +.byte 71 +.byte 58 +.byte 32 +.byte 32 +.byte 99 +.byte 111 +.byte 109 +.byte 112 +.byte 117 +.byte 116 +.byte 105 +.byte 110 +.byte 103 +.byte 10 +.byte 0 +.align 1 +.LC856: +.byte 9 +.byte 105 +.byte 110 +.byte 115 +.byte 116 +.byte 101 +.byte 97 +.byte 100 +.byte 32 +.byte 111 +.byte 102 +.byte 32 +.byte 99 +.byte 111 +.byte 114 +.byte 114 +.byte 101 +.byte 99 +.byte 116 +.byte 32 +.byte 118 +.byte 97 +.byte 108 +.byte 117 +.byte 101 +.byte 32 +.byte 48 +.byte 32 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC855: +.byte 115 +.byte 113 +.byte 114 +.byte 116 +.byte 40 +.byte 32 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 41 +.byte 32 +.byte 45 +.byte 32 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 32 +.byte 32 +.byte 61 +.byte 32 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 10 +.byte 0 +.align 4 +.LC846: +.long -1998362383 +.long 1054144693 +.align 1 +.LC843: +.byte 37 +.byte 115 +.byte 58 +.byte 32 +.byte 32 +.byte 37 +.byte 115 +.byte 0 +.align 1 +.LC842: +.byte 70 +.byte 76 +.byte 65 +.byte 87 +.byte 0 +.align 1 +.LC841: +.byte 68 +.byte 69 +.byte 70 +.byte 69 +.byte 67 +.byte 84 +.byte 0 +.align 1 +.LC840: +.byte 83 +.byte 69 +.byte 82 +.byte 73 +.byte 79 +.byte 85 +.byte 83 +.byte 32 +.byte 68 +.byte 69 +.byte 70 +.byte 69 +.byte 67 +.byte 84 +.byte 0 +.align 1 +.LC839: +.byte 70 +.byte 65 +.byte 73 +.byte 76 +.byte 85 +.byte 82 +.byte 69 +.byte 0 +.align 1 +.LC831: +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 80 +.byte 97 +.byte 103 +.byte 101 +.byte 58 +.byte 32 +.byte 37 +.byte 100 +.byte 10 +.byte 10 +.byte 0 +.align 1 +.LC830: +.byte 10 +.byte 68 +.byte 105 +.byte 97 +.byte 103 +.byte 110 +.byte 111 +.byte 115 +.byte 105 +.byte 115 +.byte 32 +.byte 114 +.byte 101 +.byte 115 +.byte 117 +.byte 109 +.byte 101 +.byte 115 +.byte 32 +.byte 97 +.byte 102 +.byte 116 +.byte 101 +.byte 114 +.byte 32 +.byte 109 +.byte 105 +.byte 108 +.byte 101 +.byte 115 +.byte 116 +.byte 111 +.byte 110 +.byte 101 +.byte 32 +.byte 78 +.byte 117 +.byte 109 +.byte 98 +.byte 101 +.byte 114 +.byte 32 +.byte 37 +.byte 100 +.byte 0 +.align 4 +.LC827: +.long 0 +.long -1074790400 +.align 1 +.LC821: +.byte 69 +.byte 78 +.byte 68 +.byte 32 +.byte 79 +.byte 70 +.byte 32 +.byte 84 +.byte 69 +.byte 83 +.byte 84 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC820: +.byte 10 +.byte 65 +.byte 32 +.byte 116 +.byte 111 +.byte 116 +.byte 97 +.byte 108 +.byte 32 +.byte 111 +.byte 102 +.byte 32 +.byte 37 +.byte 100 +.byte 32 +.byte 102 +.byte 108 +.byte 111 +.byte 97 +.byte 116 +.byte 105 +.byte 110 +.byte 103 +.byte 32 +.byte 112 +.byte 111 +.byte 105 +.byte 110 +.byte 116 +.byte 32 +.byte 101 +.byte 120 +.byte 99 +.byte 101 +.byte 112 +.byte 116 +.byte 105 +.byte 111 +.byte 110 +.byte 115 +.byte 32 +.byte 119 +.byte 101 +.byte 114 +.byte 101 +.byte 32 +.byte 114 +.byte 101 +.byte 103 +.byte 105 +.byte 115 +.byte 116 +.byte 101 +.byte 114 +.byte 101 +.byte 100 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC817: +.byte 84 +.byte 104 +.byte 101 +.byte 32 +.byte 97 +.byte 114 +.byte 105 +.byte 116 +.byte 104 +.byte 109 +.byte 101 +.byte 116 +.byte 105 +.byte 99 +.byte 32 +.byte 100 +.byte 105 +.byte 97 +.byte 103 +.byte 110 +.byte 111 +.byte 115 +.byte 101 +.byte 100 +.byte 32 +.byte 97 +.byte 112 +.byte 112 +.byte 101 +.byte 97 +.byte 114 +.byte 115 +.byte 32 +.byte 116 +.byte 111 +.byte 32 +.byte 98 +.byte 101 +.byte 32 +.byte 69 +.byte 120 +.byte 99 +.byte 101 +.byte 108 +.byte 108 +.byte 101 +.byte 110 +.byte 116 +.byte 33 +.byte 10 +.byte 0 +.align 1 +.LC816: +.byte 32 +.byte 100 +.byte 117 +.byte 114 +.byte 105 +.byte 110 +.byte 103 +.byte 32 +.byte 71 +.byte 114 +.byte 97 +.byte 100 +.byte 117 +.byte 97 +.byte 108 +.byte 32 +.byte 85 +.byte 110 +.byte 100 +.byte 101 +.byte 114 +.byte 102 +.byte 108 +.byte 111 +.byte 119 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC815: +.byte 44 +.byte 10 +.byte 101 +.byte 120 +.byte 99 +.byte 101 +.byte 112 +.byte 116 +.byte 32 +.byte 102 +.byte 111 +.byte 114 +.byte 32 +.byte 112 +.byte 111 +.byte 115 +.byte 115 +.byte 105 +.byte 98 +.byte 108 +.byte 121 +.byte 32 +.byte 68 +.byte 111 +.byte 117 +.byte 98 +.byte 108 +.byte 101 +.byte 32 +.byte 82 +.byte 111 +.byte 117 +.byte 110 +.byte 100 +.byte 105 +.byte 110 +.byte 103 +.byte 0 +.align 1 +.LC814: +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC811: +.byte 56 +.byte 53 +.byte 52 +.byte 0 +.align 1 +.LC810: +.byte 55 +.byte 53 +.byte 52 +.byte 0 +.align 1 +.LC807: +.byte 116 +.byte 104 +.byte 101 +.byte 32 +.byte 112 +.byte 114 +.byte 111 +.byte 112 +.byte 111 +.byte 115 +.byte 101 +.byte 100 +.byte 32 +.byte 73 +.byte 69 +.byte 69 +.byte 69 +.byte 32 +.byte 115 +.byte 116 +.byte 97 +.byte 110 +.byte 100 +.byte 97 +.byte 114 +.byte 100 +.byte 32 +.byte 80 +.byte 0 +.align 1 +.LC806: +.byte 82 +.byte 111 +.byte 117 +.byte 110 +.byte 100 +.byte 105 +.byte 110 +.byte 103 +.byte 32 +.byte 97 +.byte 112 +.byte 112 +.byte 101 +.byte 97 +.byte 114 +.byte 115 +.byte 32 +.byte 116 +.byte 111 +.byte 32 +.byte 99 +.byte 111 +.byte 110 +.byte 102 +.byte 111 +.byte 114 +.byte 109 +.byte 32 +.byte 116 +.byte 111 +.byte 32 +.byte 0 +.align 1 +.LC803: +.byte 84 +.byte 104 +.byte 101 +.byte 32 +.byte 97 +.byte 114 +.byte 105 +.byte 116 +.byte 104 +.byte 109 +.byte 101 +.byte 116 +.byte 105 +.byte 99 +.byte 32 +.byte 100 +.byte 105 +.byte 97 +.byte 103 +.byte 110 +.byte 111 +.byte 115 +.byte 101 +.byte 100 +.byte 32 +.byte 115 +.byte 101 +.byte 101 +.byte 109 +.byte 115 +.byte 32 +.byte 83 +.byte 97 +.byte 116 +.byte 105 +.byte 115 +.byte 102 +.byte 97 +.byte 99 +.byte 116 +.byte 111 +.byte 114 +.byte 121 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC797: +.byte 78 +.byte 111 +.byte 32 +.byte 102 +.byte 97 +.byte 105 +.byte 108 +.byte 117 +.byte 114 +.byte 101 +.byte 115 +.byte 44 +.byte 32 +.byte 100 +.byte 101 +.byte 102 +.byte 101 +.byte 99 +.byte 116 +.byte 115 +.byte 32 +.byte 110 +.byte 111 +.byte 114 +.byte 32 +.byte 102 +.byte 108 +.byte 97 +.byte 119 +.byte 115 +.byte 32 +.byte 104 +.byte 97 +.byte 118 +.byte 101 +.byte 32 +.byte 98 +.byte 101 +.byte 101 +.byte 110 +.byte 32 +.byte 100 +.byte 105 +.byte 115 +.byte 99 +.byte 111 +.byte 118 +.byte 101 +.byte 114 +.byte 101 +.byte 100 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC796: +.byte 32 +.byte 112 +.byte 114 +.byte 111 +.byte 103 +.byte 114 +.byte 97 +.byte 109 +.byte 39 +.byte 115 +.byte 32 +.byte 115 +.byte 117 +.byte 98 +.byte 115 +.byte 101 +.byte 113 +.byte 117 +.byte 101 +.byte 110 +.byte 116 +.byte 32 +.byte 100 +.byte 105 +.byte 97 +.byte 103 +.byte 110 +.byte 111 +.byte 115 +.byte 101 +.byte 115 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC795: +.byte 80 +.byte 111 +.byte 116 +.byte 101 +.byte 110 +.byte 116 +.byte 105 +.byte 97 +.byte 108 +.byte 108 +.byte 121 +.byte 32 +.byte 102 +.byte 97 +.byte 116 +.byte 97 +.byte 108 +.byte 32 +.byte 70 +.byte 65 +.byte 73 +.byte 76 +.byte 85 +.byte 82 +.byte 69 +.byte 32 +.byte 109 +.byte 97 +.byte 121 +.byte 32 +.byte 104 +.byte 97 +.byte 118 +.byte 101 +.byte 32 +.byte 115 +.byte 112 +.byte 111 +.byte 105 +.byte 108 +.byte 101 +.byte 100 +.byte 32 +.byte 116 +.byte 104 +.byte 105 +.byte 115 +.byte 0 +.align 1 +.LC792: +.byte 117 +.byte 110 +.byte 97 +.byte 99 +.byte 99 +.byte 101 +.byte 112 +.byte 116 +.byte 97 +.byte 98 +.byte 108 +.byte 101 +.byte 32 +.byte 83 +.byte 101 +.byte 114 +.byte 105 +.byte 111 +.byte 117 +.byte 115 +.byte 32 +.byte 68 +.byte 101 +.byte 102 +.byte 101 +.byte 99 +.byte 116 +.byte 115 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC791: +.byte 84 +.byte 104 +.byte 101 +.byte 32 +.byte 97 +.byte 114 +.byte 105 +.byte 116 +.byte 104 +.byte 109 +.byte 101 +.byte 116 +.byte 105 +.byte 99 +.byte 32 +.byte 100 +.byte 105 +.byte 97 +.byte 103 +.byte 110 +.byte 111 +.byte 115 +.byte 101 +.byte 100 +.byte 32 +.byte 104 +.byte 97 +.byte 115 +.byte 32 +.byte 0 +.align 1 +.LC787: +.byte 100 +.byte 101 +.byte 115 +.byte 112 +.byte 105 +.byte 116 +.byte 101 +.byte 32 +.byte 105 +.byte 110 +.byte 99 +.byte 111 +.byte 110 +.byte 118 +.byte 101 +.byte 110 +.byte 105 +.byte 101 +.byte 110 +.byte 116 +.byte 32 +.byte 68 +.byte 101 +.byte 102 +.byte 101 +.byte 99 +.byte 116 +.byte 115 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC786: +.byte 84 +.byte 104 +.byte 101 +.byte 32 +.byte 97 +.byte 114 +.byte 105 +.byte 116 +.byte 104 +.byte 109 +.byte 101 +.byte 116 +.byte 105 +.byte 99 +.byte 32 +.byte 100 +.byte 105 +.byte 97 +.byte 103 +.byte 110 +.byte 111 +.byte 115 +.byte 101 +.byte 100 +.byte 32 +.byte 109 +.byte 97 +.byte 121 +.byte 32 +.byte 98 +.byte 101 +.byte 32 +.byte 65 +.byte 99 +.byte 99 +.byte 101 +.byte 112 +.byte 116 +.byte 97 +.byte 98 +.byte 108 +.byte 101 +.byte 10 +.byte 0 +.align 1 +.LC781: +.byte 83 +.byte 97 +.byte 116 +.byte 105 +.byte 115 +.byte 102 +.byte 97 +.byte 99 +.byte 116 +.byte 111 +.byte 114 +.byte 121 +.byte 32 +.byte 116 +.byte 104 +.byte 111 +.byte 117 +.byte 103 +.byte 104 +.byte 32 +.byte 102 +.byte 108 +.byte 97 +.byte 119 +.byte 101 +.byte 100 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC780: +.byte 84 +.byte 104 +.byte 101 +.byte 32 +.byte 97 +.byte 114 +.byte 105 +.byte 116 +.byte 104 +.byte 109 +.byte 101 +.byte 116 +.byte 105 +.byte 99 +.byte 32 +.byte 100 +.byte 105 +.byte 97 +.byte 103 +.byte 110 +.byte 111 +.byte 115 +.byte 101 +.byte 100 +.byte 32 +.byte 115 +.byte 101 +.byte 101 +.byte 109 +.byte 115 +.byte 32 +.byte 0 +.align 1 +.LC769: +.byte 84 +.byte 104 +.byte 101 +.byte 32 +.byte 110 +.byte 117 +.byte 109 +.byte 98 +.byte 101 +.byte 114 +.byte 32 +.byte 111 +.byte 102 +.byte 32 +.byte 32 +.byte 37 +.byte 45 +.byte 50 +.byte 57 +.byte 115 +.byte 32 +.byte 37 +.byte 100 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC762: +.byte 70 +.byte 76 +.byte 65 +.byte 87 +.byte 115 +.byte 32 +.byte 32 +.byte 100 +.byte 105 +.byte 115 +.byte 99 +.byte 111 +.byte 118 +.byte 101 +.byte 114 +.byte 101 +.byte 100 +.byte 32 +.byte 61 +.byte 0 +.align 1 +.LC761: +.byte 68 +.byte 69 +.byte 70 +.byte 69 +.byte 67 +.byte 84 +.byte 115 +.byte 32 +.byte 32 +.byte 100 +.byte 105 +.byte 115 +.byte 99 +.byte 111 +.byte 118 +.byte 101 +.byte 114 +.byte 101 +.byte 100 +.byte 32 +.byte 61 +.byte 0 +.align 1 +.LC760: +.byte 83 +.byte 69 +.byte 82 +.byte 73 +.byte 79 +.byte 85 +.byte 83 +.byte 32 +.byte 68 +.byte 69 +.byte 70 +.byte 69 +.byte 67 +.byte 84 +.byte 115 +.byte 32 +.byte 32 +.byte 100 +.byte 105 +.byte 115 +.byte 99 +.byte 111 +.byte 118 +.byte 101 +.byte 114 +.byte 101 +.byte 100 +.byte 32 +.byte 61 +.byte 0 +.align 1 +.LC759: +.byte 70 +.byte 65 +.byte 73 +.byte 76 +.byte 85 +.byte 82 +.byte 69 +.byte 115 +.byte 32 +.byte 32 +.byte 101 +.byte 110 +.byte 99 +.byte 111 +.byte 117 +.byte 110 +.byte 116 +.byte 101 +.byte 114 +.byte 101 +.byte 100 +.byte 32 +.byte 61 +.byte 0 +.align 1 +.LC755: +.byte 10 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 84 +.byte 114 +.byte 121 +.byte 105 +.byte 110 +.byte 103 +.byte 32 +.byte 116 +.byte 111 +.byte 32 +.byte 99 +.byte 111 +.byte 109 +.byte 112 +.byte 117 +.byte 116 +.byte 101 +.byte 32 +.byte 48 +.byte 32 +.byte 47 +.byte 32 +.byte 48 +.byte 32 +.byte 112 +.byte 114 +.byte 111 +.byte 100 +.byte 117 +.byte 99 +.byte 101 +.byte 115 +.byte 32 +.byte 46 +.byte 46 +.byte 46 +.byte 0 +.align 1 +.LC754: +.byte 32 +.byte 32 +.byte 37 +.byte 46 +.byte 55 +.byte 101 +.byte 32 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC751: +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 84 +.byte 114 +.byte 121 +.byte 105 +.byte 110 +.byte 103 +.byte 32 +.byte 116 +.byte 111 +.byte 32 +.byte 99 +.byte 111 +.byte 109 +.byte 112 +.byte 117 +.byte 116 +.byte 101 +.byte 32 +.byte 49 +.byte 32 +.byte 47 +.byte 32 +.byte 48 +.byte 32 +.byte 112 +.byte 114 +.byte 111 +.byte 100 +.byte 117 +.byte 99 +.byte 101 +.byte 115 +.byte 32 +.byte 46 +.byte 46 +.byte 46 +.byte 0 +.align 1 +.LC750: +.byte 87 +.byte 104 +.byte 97 +.byte 116 +.byte 32 +.byte 109 +.byte 101 +.byte 115 +.byte 115 +.byte 97 +.byte 103 +.byte 101 +.byte 32 +.byte 97 +.byte 110 +.byte 100 +.byte 47 +.byte 111 +.byte 114 +.byte 32 +.byte 118 +.byte 97 +.byte 108 +.byte 117 +.byte 101 +.byte 115 +.byte 32 +.byte 100 +.byte 111 +.byte 101 +.byte 115 +.byte 32 +.byte 68 +.byte 105 +.byte 118 +.byte 105 +.byte 115 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 98 +.byte 121 +.byte 32 +.byte 90 +.byte 101 +.byte 114 +.byte 111 +.byte 32 +.byte 112 +.byte 114 +.byte 111 +.byte 100 +.byte 117 +.byte 99 +.byte 101 +.byte 63 +.byte 10 +.byte 0 +.align 1 +.LC749: +.byte 32 +.byte 32 +.byte 105 +.byte 110 +.byte 115 +.byte 116 +.byte 101 +.byte 97 +.byte 100 +.byte 44 +.byte 32 +.byte 88 +.byte 32 +.byte 47 +.byte 32 +.byte 88 +.byte 32 +.byte 45 +.byte 32 +.byte 49 +.byte 47 +.byte 50 +.byte 32 +.byte 45 +.byte 32 +.byte 49 +.byte 47 +.byte 50 +.byte 32 +.byte 61 +.byte 32 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 32 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC748: +.byte 32 +.byte 32 +.byte 88 +.byte 32 +.byte 47 +.byte 32 +.byte 88 +.byte 32 +.byte 100 +.byte 105 +.byte 102 +.byte 102 +.byte 101 +.byte 114 +.byte 115 +.byte 32 +.byte 102 +.byte 114 +.byte 111 +.byte 109 +.byte 32 +.byte 49 +.byte 32 +.byte 119 +.byte 104 +.byte 101 +.byte 110 +.byte 32 +.byte 88 +.byte 32 +.byte 61 +.byte 32 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 10 +.byte 0 +.align 1 +.LC743: +.byte 32 +.byte 32 +.byte 88 +.byte 32 +.byte 47 +.byte 32 +.byte 88 +.byte 32 +.byte 32 +.byte 116 +.byte 114 +.byte 97 +.byte 112 +.byte 115 +.byte 32 +.byte 119 +.byte 104 +.byte 101 +.byte 110 +.byte 32 +.byte 88 +.byte 32 +.byte 61 +.byte 32 +.byte 37 +.byte 103 +.byte 10 +.byte 0 +.align 1 +.LC728: +.byte 105 +.byte 115 +.byte 32 +.byte 116 +.byte 111 +.byte 111 +.byte 32 +.byte 102 +.byte 97 +.byte 114 +.byte 32 +.byte 102 +.byte 114 +.byte 111 +.byte 109 +.byte 32 +.byte 49 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC727: +.byte 32 +.byte 117 +.byte 110 +.byte 98 +.byte 97 +.byte 108 +.byte 97 +.byte 110 +.byte 99 +.byte 101 +.byte 100 +.byte 32 +.byte 114 +.byte 97 +.byte 110 +.byte 103 +.byte 101 +.byte 59 +.byte 32 +.byte 85 +.byte 102 +.byte 84 +.byte 104 +.byte 111 +.byte 108 +.byte 100 +.byte 32 +.byte 42 +.byte 32 +.byte 86 +.byte 32 +.byte 61 +.byte 32 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 10 +.byte 9 +.byte 37 +.byte 115 +.byte 10 +.byte 0 +.align 1 +.LC726: +.byte 66 +.byte 97 +.byte 100 +.byte 108 +.byte 121 +.byte 0 +.align 1 +.LC719: +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 116 +.byte 111 +.byte 111 +.byte 32 +.byte 102 +.byte 97 +.byte 114 +.byte 32 +.byte 102 +.byte 114 +.byte 111 +.byte 109 +.byte 32 +.byte 115 +.byte 113 +.byte 114 +.byte 116 +.byte 40 +.byte 90 +.byte 41 +.byte 32 +.byte 94 +.byte 32 +.byte 50 +.byte 32 +.byte 40 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 41 +.byte 32 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC718: +.byte 67 +.byte 111 +.byte 109 +.byte 112 +.byte 97 +.byte 114 +.byte 105 +.byte 115 +.byte 111 +.byte 110 +.byte 32 +.byte 97 +.byte 108 +.byte 108 +.byte 101 +.byte 103 +.byte 101 +.byte 115 +.byte 32 +.byte 116 +.byte 104 +.byte 97 +.byte 116 +.byte 32 +.byte 90 +.byte 32 +.byte 61 +.byte 32 +.byte 37 +.byte 49 +.byte 55 +.byte 101 +.byte 10 +.byte 0 +.align 1 +.LC706: +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 116 +.byte 111 +.byte 111 +.byte 32 +.byte 102 +.byte 97 +.byte 114 +.byte 32 +.byte 102 +.byte 114 +.byte 111 +.byte 109 +.byte 32 +.byte 115 +.byte 113 +.byte 114 +.byte 116 +.byte 40 +.byte 90 +.byte 41 +.byte 32 +.byte 94 +.byte 32 +.byte 50 +.byte 32 +.byte 61 +.byte 32 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 32 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC705: +.byte 67 +.byte 111 +.byte 109 +.byte 112 +.byte 97 +.byte 114 +.byte 105 +.byte 115 +.byte 111 +.byte 110 +.byte 32 +.byte 97 +.byte 108 +.byte 108 +.byte 101 +.byte 103 +.byte 101 +.byte 115 +.byte 32 +.byte 116 +.byte 104 +.byte 97 +.byte 116 +.byte 32 +.byte 119 +.byte 104 +.byte 97 +.byte 116 +.byte 32 +.byte 112 +.byte 114 +.byte 105 +.byte 110 +.byte 116 +.byte 115 +.byte 32 +.byte 97 +.byte 115 +.byte 32 +.byte 90 +.byte 32 +.byte 61 +.byte 32 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 10 +.byte 0 +.align 1 +.LC688: +.byte 43 +.byte 45 +.byte 37 +.byte 103 +.byte 44 +.byte 32 +.byte 43 +.byte 45 +.byte 37 +.byte 103 +.byte 10 +.byte 97 +.byte 110 +.byte 100 +.byte 32 +.byte 43 +.byte 45 +.byte 37 +.byte 103 +.byte 32 +.byte 97 +.byte 114 +.byte 101 +.byte 32 +.byte 99 +.byte 111 +.byte 110 +.byte 102 +.byte 117 +.byte 115 +.byte 101 +.byte 100 +.byte 32 +.byte 98 +.byte 121 +.byte 32 +.byte 79 +.byte 118 +.byte 101 +.byte 114 +.byte 102 +.byte 108 +.byte 111 +.byte 119 +.byte 46 +.byte 0 +.align 1 +.LC687: +.byte 67 +.byte 111 +.byte 109 +.byte 112 +.byte 97 +.byte 114 +.byte 105 +.byte 115 +.byte 111 +.byte 110 +.byte 115 +.byte 32 +.byte 105 +.byte 110 +.byte 118 +.byte 111 +.byte 108 +.byte 118 +.byte 105 +.byte 110 +.byte 103 +.byte 32 +.byte 0 +.align 1 +.LC681: +.byte 97 +.byte 98 +.byte 111 +.byte 118 +.byte 101 +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 97 +.byte 32 +.byte 68 +.byte 69 +.byte 70 +.byte 69 +.byte 67 +.byte 84 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC680: +.byte 65 +.byte 110 +.byte 121 +.byte 32 +.byte 111 +.byte 118 +.byte 101 +.byte 114 +.byte 102 +.byte 108 +.byte 111 +.byte 119 +.byte 32 +.byte 115 +.byte 105 +.byte 103 +.byte 110 +.byte 97 +.byte 108 +.byte 32 +.byte 115 +.byte 101 +.byte 112 +.byte 97 +.byte 114 +.byte 97 +.byte 116 +.byte 105 +.byte 110 +.byte 103 +.byte 32 +.byte 116 +.byte 104 +.byte 105 +.byte 115 +.byte 32 +.byte 42 +.byte 32 +.byte 102 +.byte 114 +.byte 111 +.byte 109 +.byte 32 +.byte 116 +.byte 104 +.byte 101 +.byte 32 +.byte 111 +.byte 110 +.byte 101 +.byte 10 +.byte 0 +.align 1 +.LC679: +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 110 +.byte 111 +.byte 114 +.byte 32 +.byte 102 +.byte 111 +.byte 114 +.byte 32 +.byte 86 +.byte 32 +.byte 47 +.byte 32 +.byte 49 +.byte 32 +.byte 61 +.byte 32 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 32 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC678: +.byte 78 +.byte 111 +.byte 32 +.byte 79 +.byte 118 +.byte 101 +.byte 114 +.byte 102 +.byte 108 +.byte 111 +.byte 119 +.byte 32 +.byte 115 +.byte 104 +.byte 111 +.byte 117 +.byte 108 +.byte 100 +.byte 32 +.byte 98 +.byte 101 +.byte 32 +.byte 115 +.byte 105 +.byte 103 +.byte 110 +.byte 97 +.byte 108 +.byte 101 +.byte 100 +.byte 32 +.byte 102 +.byte 111 +.byte 114 +.byte 32 +.byte 86 +.byte 32 +.byte 42 +.byte 32 +.byte 49 +.byte 32 +.byte 61 +.byte 32 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 10 +.byte 0 +.align 1 +.LC677: +.byte 84 +.byte 104 +.byte 101 +.byte 114 +.byte 101 +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 110 +.byte 111 +.byte 32 +.byte 115 +.byte 97 +.byte 116 +.byte 117 +.byte 114 +.byte 97 +.byte 116 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 118 +.byte 97 +.byte 108 +.byte 117 +.byte 101 +.byte 32 +.byte 98 +.byte 101 +.byte 99 +.byte 97 +.byte 117 +.byte 115 +.byte 101 +.byte 32 +.byte 116 +.byte 104 +.byte 101 +.byte 32 +.byte 115 +.byte 121 +.byte 115 +.byte 116 +.byte 101 +.byte 109 +.byte 32 +.byte 116 +.byte 114 +.byte 97 +.byte 112 +.byte 115 +.byte 32 +.byte 111 +.byte 110 +.byte 32 +.byte 111 +.byte 118 +.byte 101 +.byte 114 +.byte 102 +.byte 108 +.byte 111 +.byte 119 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC676: +.byte 79 +.byte 118 +.byte 101 +.byte 114 +.byte 102 +.byte 108 +.byte 111 +.byte 119 +.byte 32 +.byte 115 +.byte 97 +.byte 116 +.byte 117 +.byte 114 +.byte 97 +.byte 116 +.byte 101 +.byte 115 +.byte 32 +.byte 97 +.byte 116 +.byte 32 +.byte 86 +.byte 48 +.byte 32 +.byte 61 +.byte 32 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 32 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC673: +.byte 79 +.byte 118 +.byte 101 +.byte 114 +.byte 102 +.byte 108 +.byte 111 +.byte 119 +.byte 32 +.byte 116 +.byte 104 +.byte 114 +.byte 101 +.byte 115 +.byte 104 +.byte 111 +.byte 108 +.byte 100 +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 86 +.byte 32 +.byte 32 +.byte 61 +.byte 32 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 32 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC664: +.byte 111 +.byte 118 +.byte 101 +.byte 114 +.byte 102 +.byte 108 +.byte 111 +.byte 119 +.byte 32 +.byte 112 +.byte 97 +.byte 115 +.byte 116 +.byte 32 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 10 +.byte 9 +.byte 115 +.byte 104 +.byte 114 +.byte 105 +.byte 110 +.byte 107 +.byte 115 +.byte 32 +.byte 116 +.byte 111 +.byte 32 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 32 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC661: +.byte 45 +.byte 40 +.byte 45 +.byte 89 +.byte 41 +.byte 32 +.byte 100 +.byte 105 +.byte 102 +.byte 102 +.byte 101 +.byte 114 +.byte 115 +.byte 32 +.byte 102 +.byte 114 +.byte 111 +.byte 109 +.byte 32 +.byte 89 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC660: +.byte 102 +.byte 105 +.byte 110 +.byte 100 +.byte 115 +.byte 32 +.byte 97 +.byte 32 +.byte 0 +.align 1 +.LC659: +.byte 83 +.byte 101 +.byte 101 +.byte 109 +.byte 115 +.byte 32 +.byte 79 +.byte 46 +.byte 75 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC656: +.byte 84 +.byte 114 +.byte 121 +.byte 105 +.byte 110 +.byte 103 +.byte 32 +.byte 105 +.byte 116 +.byte 32 +.byte 111 +.byte 110 +.byte 32 +.byte 89 +.byte 32 +.byte 61 +.byte 32 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 32 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC655: +.byte 67 +.byte 97 +.byte 110 +.byte 32 +.byte 96 +.byte 90 +.byte 32 +.byte 61 +.byte 32 +.byte 45 +.byte 89 +.byte 39 +.byte 32 +.byte 111 +.byte 118 +.byte 101 +.byte 114 +.byte 102 +.byte 108 +.byte 111 +.byte 119 +.byte 63 +.byte 10 +.byte 0 +.align 1 +.LC648: +.byte 84 +.byte 104 +.byte 105 +.byte 115 +.byte 32 +.byte 109 +.byte 97 +.byte 121 +.byte 32 +.byte 103 +.byte 101 +.byte 110 +.byte 101 +.byte 114 +.byte 97 +.byte 116 +.byte 101 +.byte 32 +.byte 97 +.byte 110 +.byte 32 +.byte 101 +.byte 114 +.byte 114 +.byte 111 +.byte 114 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC647: +.byte 83 +.byte 101 +.byte 97 +.byte 114 +.byte 99 +.byte 104 +.byte 105 +.byte 110 +.byte 103 +.byte 32 +.byte 102 +.byte 111 +.byte 114 +.byte 32 +.byte 79 +.byte 118 +.byte 101 +.byte 114 +.byte 102 +.byte 108 +.byte 111 +.byte 119 +.byte 32 +.byte 116 +.byte 104 +.byte 114 +.byte 101 +.byte 115 +.byte 104 +.byte 111 +.byte 108 +.byte 100 +.byte 58 +.byte 10 +.byte 0 +.align 1 +.LC646: +.byte 32 +.byte 46 +.byte 46 +.byte 46 +.byte 32 +.byte 110 +.byte 111 +.byte 32 +.byte 100 +.byte 105 +.byte 115 +.byte 99 +.byte 114 +.byte 101 +.byte 112 +.byte 97 +.byte 110 +.byte 99 +.byte 105 +.byte 101 +.byte 115 +.byte 32 +.byte 102 +.byte 111 +.byte 117 +.byte 110 +.byte 100 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC638: +.byte 84 +.byte 101 +.byte 115 +.byte 116 +.byte 105 +.byte 110 +.byte 103 +.byte 32 +.byte 112 +.byte 111 +.byte 119 +.byte 101 +.byte 114 +.byte 115 +.byte 32 +.byte 90 +.byte 94 +.byte 81 +.byte 32 +.byte 97 +.byte 116 +.byte 32 +.byte 102 +.byte 111 +.byte 117 +.byte 114 +.byte 32 +.byte 110 +.byte 101 +.byte 97 +.byte 114 +.byte 108 +.byte 121 +.byte 32 +.byte 101 +.byte 120 +.byte 116 +.byte 114 +.byte 101 +.byte 109 +.byte 101 +.byte 32 +.byte 118 +.byte 97 +.byte 108 +.byte 117 +.byte 101 +.byte 115 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC637: +.byte 65 +.byte 99 +.byte 99 +.byte 117 +.byte 114 +.byte 97 +.byte 99 +.byte 121 +.byte 32 +.byte 115 +.byte 101 +.byte 101 +.byte 109 +.byte 115 +.byte 32 +.byte 97 +.byte 100 +.byte 101 +.byte 113 +.byte 117 +.byte 97 +.byte 116 +.byte 101 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC630: +.byte 9 +.byte 99 +.byte 97 +.byte 108 +.byte 99 +.byte 117 +.byte 108 +.byte 97 +.byte 116 +.byte 105 +.byte 111 +.byte 110 +.byte 115 +.byte 32 +.byte 105 +.byte 110 +.byte 118 +.byte 111 +.byte 108 +.byte 118 +.byte 105 +.byte 110 +.byte 103 +.byte 32 +.byte 116 +.byte 105 +.byte 110 +.byte 121 +.byte 32 +.byte 105 +.byte 110 +.byte 116 +.byte 101 +.byte 114 +.byte 101 +.byte 115 +.byte 116 +.byte 32 +.byte 114 +.byte 97 +.byte 116 +.byte 101 +.byte 115 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC629: +.byte 9 +.byte 84 +.byte 104 +.byte 105 +.byte 115 +.byte 32 +.byte 109 +.byte 117 +.byte 99 +.byte 104 +.byte 32 +.byte 101 +.byte 114 +.byte 114 +.byte 111 +.byte 114 +.byte 32 +.byte 109 +.byte 97 +.byte 121 +.byte 32 +.byte 115 +.byte 112 +.byte 111 +.byte 105 +.byte 108 +.byte 32 +.byte 102 +.byte 105 +.byte 110 +.byte 97 +.byte 110 +.byte 99 +.byte 105 +.byte 97 +.byte 108 +.byte 10 +.byte 0 +.align 1 +.LC628: +.byte 9 +.byte 100 +.byte 105 +.byte 102 +.byte 102 +.byte 101 +.byte 114 +.byte 115 +.byte 32 +.byte 102 +.byte 114 +.byte 111 +.byte 109 +.byte 32 +.byte 99 +.byte 111 +.byte 114 +.byte 114 +.byte 101 +.byte 99 +.byte 116 +.byte 32 +.byte 118 +.byte 97 +.byte 108 +.byte 117 +.byte 101 +.byte 32 +.byte 98 +.byte 121 +.byte 32 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 32 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC627: +.byte 9 +.byte 40 +.byte 49 +.byte 32 +.byte 43 +.byte 32 +.byte 40 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 41 +.byte 32 +.byte 94 +.byte 32 +.byte 40 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 41 +.byte 59 +.byte 10 +.byte 0 +.align 1 +.LC626: +.byte 32 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 32 +.byte 102 +.byte 111 +.byte 114 +.byte 10 +.byte 0 +.align 1 +.LC625: +.byte 67 +.byte 97 +.byte 108 +.byte 99 +.byte 117 +.byte 108 +.byte 97 +.byte 116 +.byte 101 +.byte 100 +.byte 0 +.align 1 +.LC618: +.byte 84 +.byte 101 +.byte 115 +.byte 116 +.byte 105 +.byte 110 +.byte 103 +.byte 32 +.byte 88 +.byte 94 +.byte 40 +.byte 40 +.byte 88 +.byte 32 +.byte 43 +.byte 32 +.byte 49 +.byte 41 +.byte 32 +.byte 47 +.byte 32 +.byte 40 +.byte 88 +.byte 32 +.byte 45 +.byte 32 +.byte 49 +.byte 41 +.byte 41 +.byte 32 +.byte 118 +.byte 115 +.byte 46 +.byte 32 +.byte 101 +.byte 120 +.byte 112 +.byte 40 +.byte 50 +.byte 41 +.byte 32 +.byte 61 +.byte 32 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 32 +.byte 97 +.byte 115 +.byte 32 +.byte 88 +.byte 32 +.byte 45 +.byte 62 +.byte 32 +.byte 49 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC614: +.byte 84 +.byte 104 +.byte 105 +.byte 115 +.byte 32 +.byte 99 +.byte 111 +.byte 109 +.byte 112 +.byte 117 +.byte 116 +.byte 101 +.byte 100 +.byte 32 +.byte 118 +.byte 97 +.byte 108 +.byte 117 +.byte 101 +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 79 +.byte 46 +.byte 75 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC611: +.byte 32 +.byte 32 +.byte 32 +.byte 116 +.byte 104 +.byte 114 +.byte 101 +.byte 115 +.byte 104 +.byte 111 +.byte 108 +.byte 100 +.byte 32 +.byte 61 +.byte 32 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 32 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC610: +.byte 116 +.byte 104 +.byte 105 +.byte 115 +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 110 +.byte 111 +.byte 116 +.byte 32 +.byte 98 +.byte 101 +.byte 116 +.byte 119 +.byte 101 +.byte 101 +.byte 110 +.byte 32 +.byte 48 +.byte 32 +.byte 97 +.byte 110 +.byte 100 +.byte 32 +.byte 117 +.byte 110 +.byte 100 +.byte 101 +.byte 114 +.byte 102 +.byte 108 +.byte 111 +.byte 119 +.byte 10 +.byte 0 +.align 1 +.LC606: +.byte 97 +.byte 99 +.byte 116 +.byte 117 +.byte 97 +.byte 108 +.byte 108 +.byte 121 +.byte 32 +.byte 99 +.byte 97 +.byte 108 +.byte 99 +.byte 117 +.byte 108 +.byte 97 +.byte 116 +.byte 105 +.byte 110 +.byte 103 +.byte 32 +.byte 121 +.byte 105 +.byte 101 +.byte 108 +.byte 100 +.byte 115 +.byte 58 +.byte 32 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 32 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC605: +.byte 115 +.byte 104 +.byte 111 +.byte 117 +.byte 108 +.byte 100 +.byte 32 +.byte 97 +.byte 102 +.byte 102 +.byte 108 +.byte 105 +.byte 99 +.byte 116 +.byte 32 +.byte 116 +.byte 104 +.byte 101 +.byte 32 +.byte 101 +.byte 120 +.byte 112 +.byte 114 +.byte 101 +.byte 115 +.byte 115 +.byte 105 +.byte 111 +.byte 110 +.byte 10 +.byte 9 +.byte 40 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 41 +.byte 32 +.byte 94 +.byte 32 +.byte 40 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 41 +.byte 59 +.byte 10 +.byte 0 +.align 1 +.LC604: +.byte 85 +.byte 102 +.byte 84 +.byte 104 +.byte 111 +.byte 108 +.byte 100 +.byte 32 +.byte 61 +.byte 32 +.byte 40 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 41 +.byte 32 +.byte 94 +.byte 32 +.byte 40 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 41 +.byte 10 +.byte 111 +.byte 110 +.byte 108 +.byte 121 +.byte 32 +.byte 117 +.byte 110 +.byte 100 +.byte 101 +.byte 114 +.byte 102 +.byte 108 +.byte 111 +.byte 119 +.byte 32 +.byte 0 +.align 1 +.LC603: +.byte 83 +.byte 105 +.byte 110 +.byte 99 +.byte 101 +.byte 32 +.byte 117 +.byte 110 +.byte 100 +.byte 101 +.byte 114 +.byte 102 +.byte 108 +.byte 111 +.byte 119 +.byte 32 +.byte 111 +.byte 99 +.byte 99 +.byte 117 +.byte 114 +.byte 115 +.byte 32 +.byte 98 +.byte 101 +.byte 108 +.byte 111 +.byte 119 +.byte 32 +.byte 116 +.byte 104 +.byte 101 +.byte 32 +.byte 116 +.byte 104 +.byte 114 +.byte 101 +.byte 115 +.byte 104 +.byte 111 +.byte 108 +.byte 100 +.byte 10 +.byte 0 +.align 1 +.LC602: +.byte 82 +.byte 97 +.byte 110 +.byte 103 +.byte 101 +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 116 +.byte 111 +.byte 111 +.byte 32 +.byte 110 +.byte 97 +.byte 114 +.byte 114 +.byte 111 +.byte 119 +.byte 59 +.byte 32 +.byte 85 +.byte 49 +.byte 94 +.byte 37 +.byte 100 +.byte 32 +.byte 85 +.byte 110 +.byte 100 +.byte 101 +.byte 114 +.byte 102 +.byte 108 +.byte 111 +.byte 119 +.byte 115 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC597: +.byte 109 +.byte 101 +.byte 114 +.byte 101 +.byte 108 +.byte 121 +.byte 32 +.byte 114 +.byte 111 +.byte 117 +.byte 110 +.byte 100 +.byte 111 +.byte 102 +.byte 102 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC596: +.byte 99 +.byte 97 +.byte 108 +.byte 99 +.byte 117 +.byte 108 +.byte 97 +.byte 116 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 109 +.byte 97 +.byte 121 +.byte 32 +.byte 115 +.byte 117 +.byte 102 +.byte 102 +.byte 101 +.byte 114 +.byte 32 +.byte 108 +.byte 97 +.byte 114 +.byte 103 +.byte 101 +.byte 114 +.byte 32 +.byte 82 +.byte 101 +.byte 108 +.byte 97 +.byte 116 +.byte 105 +.byte 118 +.byte 101 +.byte 32 +.byte 101 +.byte 114 +.byte 114 +.byte 111 +.byte 114 +.byte 32 +.byte 116 +.byte 104 +.byte 97 +.byte 110 +.byte 32 +.byte 0 +.align 1 +.LC595: +.byte 32 +.byte 98 +.byte 101 +.byte 108 +.byte 111 +.byte 119 +.byte 32 +.byte 119 +.byte 104 +.byte 105 +.byte 99 +.byte 104 +.byte 0 +.align 1 +.LC594: +.byte 84 +.byte 104 +.byte 101 +.byte 32 +.byte 85 +.byte 110 +.byte 100 +.byte 101 +.byte 114 +.byte 102 +.byte 108 +.byte 111 +.byte 119 +.byte 32 +.byte 116 +.byte 104 +.byte 114 +.byte 101 +.byte 115 +.byte 104 +.byte 111 +.byte 108 +.byte 100 +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 44 +.byte 32 +.byte 37 +.byte 115 +.byte 10 +.byte 0 +.align 1 +.LC593: +.byte 88 +.byte 32 +.byte 47 +.byte 32 +.byte 90 +.byte 32 +.byte 61 +.byte 32 +.byte 49 +.byte 32 +.byte 43 +.byte 32 +.byte 37 +.byte 103 +.byte 32 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC592: +.byte 88 +.byte 32 +.byte 47 +.byte 32 +.byte 90 +.byte 32 +.byte 102 +.byte 97 +.byte 105 +.byte 108 +.byte 115 +.byte 33 +.byte 10 +.byte 0 +.align 1 +.LC589: +.byte 101 +.byte 110 +.byte 99 +.byte 111 +.byte 117 +.byte 110 +.byte 116 +.byte 101 +.byte 114 +.byte 32 +.byte 68 +.byte 105 +.byte 118 +.byte 105 +.byte 115 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 98 +.byte 121 +.byte 32 +.byte 90 +.byte 101 +.byte 114 +.byte 111 +.byte 32 +.byte 97 +.byte 108 +.byte 116 +.byte 104 +.byte 111 +.byte 117 +.byte 103 +.byte 104 +.byte 32 +.byte 97 +.byte 99 +.byte 116 +.byte 117 +.byte 97 +.byte 108 +.byte 108 +.byte 121 +.byte 10 +.byte 0 +.align 1 +.LC588: +.byte 32 +.byte 32 +.byte 46 +.byte 46 +.byte 46 +.byte 32 +.byte 40 +.byte 102 +.byte 40 +.byte 88 +.byte 41 +.byte 32 +.byte 45 +.byte 32 +.byte 102 +.byte 40 +.byte 90 +.byte 41 +.byte 41 +.byte 32 +.byte 47 +.byte 32 +.byte 40 +.byte 88 +.byte 32 +.byte 45 +.byte 32 +.byte 90 +.byte 41 +.byte 32 +.byte 46 +.byte 46 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC587: +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 105 +.byte 102 +.byte 32 +.byte 40 +.byte 88 +.byte 32 +.byte 61 +.byte 61 +.byte 32 +.byte 90 +.byte 41 +.byte 32 +.byte 32 +.byte 46 +.byte 46 +.byte 46 +.byte 32 +.byte 32 +.byte 101 +.byte 108 +.byte 115 +.byte 101 +.byte 0 +.align 1 +.LC586: +.byte 99 +.byte 111 +.byte 110 +.byte 102 +.byte 117 +.byte 115 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 119 +.byte 104 +.byte 101 +.byte 110 +.byte 32 +.byte 105 +.byte 110 +.byte 110 +.byte 111 +.byte 99 +.byte 101 +.byte 110 +.byte 116 +.byte 32 +.byte 115 +.byte 116 +.byte 97 +.byte 116 +.byte 101 +.byte 109 +.byte 101 +.byte 110 +.byte 116 +.byte 115 +.byte 32 +.byte 108 +.byte 105 +.byte 107 +.byte 101 +.byte 10 +.byte 0 +.align 1 +.LC585: +.byte 116 +.byte 104 +.byte 105 +.byte 115 +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 97 +.byte 32 +.byte 83 +.byte 69 +.byte 82 +.byte 73 +.byte 79 +.byte 85 +.byte 83 +.byte 32 +.byte 68 +.byte 69 +.byte 70 +.byte 69 +.byte 67 +.byte 84 +.byte 10 +.byte 116 +.byte 104 +.byte 97 +.byte 116 +.byte 32 +.byte 99 +.byte 97 +.byte 117 +.byte 115 +.byte 101 +.byte 115 +.byte 32 +.byte 0 +.align 1 +.LC584: +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 83 +.byte 104 +.byte 111 +.byte 117 +.byte 108 +.byte 100 +.byte 32 +.byte 116 +.byte 104 +.byte 105 +.byte 115 +.byte 32 +.byte 78 +.byte 79 +.byte 84 +.byte 32 +.byte 115 +.byte 105 +.byte 103 +.byte 110 +.byte 97 +.byte 108 +.byte 32 +.byte 85 +.byte 110 +.byte 100 +.byte 101 +.byte 114 +.byte 102 +.byte 108 +.byte 111 +.byte 119 +.byte 44 +.byte 32 +.byte 0 +.align 1 +.LC583: +.byte 121 +.byte 101 +.byte 116 +.byte 32 +.byte 88 +.byte 32 +.byte 45 +.byte 32 +.byte 90 +.byte 32 +.byte 121 +.byte 105 +.byte 101 +.byte 108 +.byte 100 +.byte 115 +.byte 32 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 32 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC582: +.byte 88 +.byte 32 +.byte 61 +.byte 32 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 10 +.byte 9 +.byte 105 +.byte 115 +.byte 32 +.byte 110 +.byte 111 +.byte 116 +.byte 32 +.byte 101 +.byte 113 +.byte 117 +.byte 97 +.byte 108 +.byte 32 +.byte 116 +.byte 111 +.byte 32 +.byte 90 +.byte 32 +.byte 61 +.byte 32 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 32 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC577: +.byte 85 +.byte 110 +.byte 100 +.byte 101 +.byte 114 +.byte 102 +.byte 108 +.byte 111 +.byte 119 +.byte 32 +.byte 47 +.byte 32 +.byte 85 +.byte 102 +.byte 84 +.byte 104 +.byte 111 +.byte 108 +.byte 100 +.byte 32 +.byte 102 +.byte 97 +.byte 105 +.byte 108 +.byte 101 +.byte 100 +.byte 33 +.byte 10 +.byte 0 +.align 1 +.LC567: +.byte 40 +.byte 114 +.byte 111 +.byte 117 +.byte 110 +.byte 100 +.byte 111 +.byte 102 +.byte 102 +.byte 32 +.byte 105 +.byte 110 +.byte 32 +.byte 85 +.byte 102 +.byte 84 +.byte 104 +.byte 111 +.byte 108 +.byte 100 +.byte 41 +.byte 32 +.byte 60 +.byte 32 +.byte 69 +.byte 48 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC566: +.byte 85 +.byte 110 +.byte 100 +.byte 101 +.byte 114 +.byte 102 +.byte 108 +.byte 111 +.byte 119 +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 103 +.byte 114 +.byte 97 +.byte 100 +.byte 117 +.byte 97 +.byte 108 +.byte 59 +.byte 32 +.byte 105 +.byte 116 +.byte 32 +.byte 105 +.byte 110 +.byte 99 +.byte 117 +.byte 114 +.byte 115 +.byte 32 +.byte 65 +.byte 98 +.byte 115 +.byte 111 +.byte 108 +.byte 117 +.byte 116 +.byte 101 +.byte 32 +.byte 69 +.byte 114 +.byte 114 +.byte 111 +.byte 114 +.byte 32 +.byte 61 +.byte 10 +.byte 0 +.align 1 +.LC561: +.byte 124 +.byte 81 +.byte 32 +.byte 45 +.byte 32 +.byte 89 +.byte 124 +.byte 32 +.byte 61 +.byte 32 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 32 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC560: +.byte 112 +.byte 114 +.byte 105 +.byte 110 +.byte 116 +.byte 32 +.byte 111 +.byte 117 +.byte 116 +.byte 32 +.byte 97 +.byte 115 +.byte 32 +.byte 81 +.byte 32 +.byte 61 +.byte 32 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 44 +.byte 32 +.byte 89 +.byte 32 +.byte 61 +.byte 32 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 32 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC559: +.byte 81 +.byte 32 +.byte 61 +.byte 61 +.byte 32 +.byte 89 +.byte 32 +.byte 119 +.byte 104 +.byte 105 +.byte 108 +.byte 101 +.byte 32 +.byte 100 +.byte 101 +.byte 110 +.byte 121 +.byte 105 +.byte 110 +.byte 103 +.byte 32 +.byte 116 +.byte 104 +.byte 97 +.byte 116 +.byte 32 +.byte 124 +.byte 81 +.byte 32 +.byte 45 +.byte 32 +.byte 89 +.byte 124 +.byte 32 +.byte 61 +.byte 61 +.byte 32 +.byte 48 +.byte 59 +.byte 32 +.byte 116 +.byte 104 +.byte 101 +.byte 115 +.byte 101 +.byte 32 +.byte 118 +.byte 97 +.byte 108 +.byte 117 +.byte 101 +.byte 115 +.byte 10 +.byte 0 +.align 1 +.LC558: +.byte 85 +.byte 110 +.byte 100 +.byte 101 +.byte 114 +.byte 102 +.byte 108 +.byte 111 +.byte 119 +.byte 32 +.byte 99 +.byte 111 +.byte 110 +.byte 102 +.byte 117 +.byte 115 +.byte 101 +.byte 115 +.byte 32 +.byte 67 +.byte 111 +.byte 109 +.byte 112 +.byte 97 +.byte 114 +.byte 105 +.byte 115 +.byte 111 +.byte 110 +.byte 44 +.byte 32 +.byte 119 +.byte 104 +.byte 105 +.byte 99 +.byte 104 +.byte 32 +.byte 97 +.byte 108 +.byte 108 +.byte 101 +.byte 103 +.byte 101 +.byte 115 +.byte 32 +.byte 116 +.byte 104 +.byte 97 +.byte 116 +.byte 10 +.byte 0 +.align 1 +.LC556: +.byte 32 +.byte 111 +.byte 114 +.byte 32 +.byte 101 +.byte 108 +.byte 115 +.byte 101 +.byte 32 +.byte 109 +.byte 117 +.byte 108 +.byte 116 +.byte 105 +.byte 112 +.byte 108 +.byte 105 +.byte 99 +.byte 97 +.byte 116 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 103 +.byte 101 +.byte 116 +.byte 115 +.byte 32 +.byte 116 +.byte 111 +.byte 111 +.byte 32 +.byte 109 +.byte 97 +.byte 110 +.byte 121 +.byte 32 +.byte 108 +.byte 97 +.byte 115 +.byte 116 +.byte 32 +.byte 100 +.byte 105 +.byte 103 +.byte 105 +.byte 116 +.byte 115 +.byte 32 +.byte 119 +.byte 114 +.byte 111 +.byte 110 +.byte 103 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC555: +.byte 32 +.byte 99 +.byte 111 +.byte 109 +.byte 105 +.byte 110 +.byte 103 +.byte 32 +.byte 100 +.byte 111 +.byte 119 +.byte 110 +.byte 32 +.byte 102 +.byte 114 +.byte 111 +.byte 109 +.byte 32 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 10 +.byte 0 +.align 1 +.LC554: +.byte 97 +.byte 112 +.byte 112 +.byte 114 +.byte 111 +.byte 97 +.byte 99 +.byte 104 +.byte 32 +.byte 97 +.byte 32 +.byte 116 +.byte 104 +.byte 114 +.byte 101 +.byte 115 +.byte 104 +.byte 111 +.byte 108 +.byte 100 +.byte 32 +.byte 61 +.byte 32 +.byte 37 +.byte 46 +.byte 49 +.byte 55 +.byte 101 +.byte 10 +.byte 0 +.align 1 +.LC553: +.byte 69 +.byte 105 +.byte 116 +.byte 104 +.byte 101 +.byte 114 +.byte 32 +.byte 97 +.byte 99 +.byte 99 +.byte 117 +.byte 114 +.byte 97 +.byte 99 +.byte 121 +.byte 32 +.byte 100 +.byte 101 +.byte 116 +.byte 101 +.byte 114 +.byte 105 +.byte 111 +.byte 114 +.byte 97 +.byte 116 +.byte 101 +.byte 115 +.byte 32 +.byte 97 +.byte 115 +.byte 32 +.byte 110 +.byte 117 +.byte 109 +.byte 98 +.byte 101 +.byte 114 +.byte 115 +.byte 10 +.byte 0 +.align 1 +.LC541: +.byte 83 +.byte 109 +.byte 97 +.byte 108 +.byte 108 +.byte 101 +.byte 115 +.byte 116 +.byte 32 +.byte 115 +.byte 116 +.byte 114 +.byte 105 +.byte 99 +.byte 116 +.byte 108 +.byte 121 +.byte 32 +.byte 112 +.byte 111 +.byte 115 +.byte 105 +.byte 116 +.byte 105 +.byte 118 +.byte 101 +.byte 32 +.byte 110 +.byte 117 +.byte 109 +.byte 98 +.byte 101 +.byte 114 +.byte 32 +.byte 102 +.byte 111 +.byte 117 +.byte 110 +.byte 100 +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 69 +.byte 48 +.byte 32 +.byte 61 +.byte 32 +.byte 37 +.byte 103 +.byte 32 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC540: +.byte 32 +.byte 116 +.byte 104 +.byte 114 +.byte 101 +.byte 115 +.byte 104 +.byte 111 +.byte 108 +.byte 100 +.byte 32 +.byte 116 +.byte 104 +.byte 97 +.byte 110 +.byte 32 +.byte 112 +.byte 114 +.byte 111 +.byte 100 +.byte 117 +.byte 99 +.byte 116 +.byte 115 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC539: +.byte 68 +.byte 105 +.byte 102 +.byte 102 +.byte 101 +.byte 114 +.byte 101 +.byte 110 +.byte 99 +.byte 101 +.byte 32 +.byte 117 +.byte 110 +.byte 100 +.byte 101 +.byte 114 +.byte 102 +.byte 108 +.byte 111 +.byte 119 +.byte 115 +.byte 32 +.byte 97 +.byte 116 +.byte 32 +.byte 97 +.byte 32 +.byte 104 +.byte 105 +.byte 103 +.byte 104 +.byte 101 +.byte 114 +.byte 0 +.align 1 +.LC536: +.byte 32 +.byte 116 +.byte 104 +.byte 114 +.byte 101 +.byte 115 +.byte 104 +.byte 111 +.byte 108 +.byte 100 +.byte 32 +.byte 116 +.byte 104 +.byte 97 +.byte 110 +.byte 32 +.byte 100 +.byte 105 +.byte 102 +.byte 102 +.byte 101 +.byte 114 +.byte 101 +.byte 110 +.byte 99 +.byte 101 +.byte 115 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC535: +.byte 80 +.byte 114 +.byte 111 +.byte 100 +.byte 117 +.byte 99 +.byte 116 +.byte 115 +.byte 32 +.byte 117 +.byte 110 +.byte 100 +.byte 101 +.byte 114 +.byte 102 +.byte 108 +.byte 111 +.byte 119 +.byte 32 +.byte 97 +.byte 116 +.byte 32 +.byte 97 +.byte 32 +.byte 104 +.byte 105 +.byte 103 +.byte 104 +.byte 101 +.byte 114 +.byte 0 +.align 1 +.LC528: +.byte 118 +.byte 97 +.byte 108 +.byte 117 +.byte 101 +.byte 32 +.byte 80 +.byte 115 +.byte 101 +.byte 117 +.byte 100 +.byte 111 +.byte 90 +.byte 101 +.byte 114 +.byte 111 +.byte 32 +.byte 116 +.byte 104 +.byte 97 +.byte 116 +.byte 32 +.byte 112 +.byte 114 +.byte 105 +.byte 110 +.byte 116 +.byte 115 +.byte 32 +.byte 111 +.byte 117 +.byte 116 +.byte 32 +.byte 97 +.byte 115 +.byte 32 +.byte 37 +.byte 103 +.byte 32 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC527: +.byte 85 +.byte 110 +.byte 100 +.byte 101 +.byte 114 +.byte 102 +.byte 108 +.byte 111 +.byte 119 +.byte 32 +.byte 99 +.byte 97 +.byte 110 +.byte 32 +.byte 115 +.byte 116 +.byte 105 +.byte 99 +.byte 107 +.byte 32 +.byte 97 +.byte 116 +.byte 32 +.byte 97 +.byte 110 +.byte 32 +.byte 97 +.byte 108 +.byte 108 +.byte 101 +.byte 103 +.byte 101 +.byte 100 +.byte 108 +.byte 121 +.byte 32 +.byte 112 +.byte 111 +.byte 115 +.byte 105 +.byte 116 +.byte 105 +.byte 118 +.byte 101 +.byte 10 +.byte 0 +.align 1 +.LC526: +.byte 112 +.byte 111 +.byte 115 +.byte 105 +.byte 116 +.byte 105 +.byte 118 +.byte 101 +.byte 44 +.byte 32 +.byte 105 +.byte 115 +.byte 110 +.byte 39 +.byte 116 +.byte 59 +.byte 32 +.byte 105 +.byte 116 +.byte 32 +.byte 112 +.byte 114 +.byte 105 +.byte 110 +.byte 116 +.byte 115 +.byte 32 +.byte 111 +.byte 117 +.byte 116 +.byte 32 +.byte 97 +.byte 115 +.byte 32 +.byte 32 +.byte 37 +.byte 103 +.byte 32 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC525: +.byte 66 +.byte 117 +.byte 116 +.byte 32 +.byte 45 +.byte 80 +.byte 115 +.byte 101 +.byte 117 +.byte 100 +.byte 111 +.byte 90 +.byte 101 +.byte 114 +.byte 111 +.byte 44 +.byte 32 +.byte 119 +.byte 104 +.byte 105 +.byte 99 +.byte 104 +.byte 32 +.byte 115 +.byte 104 +.byte 111 +.byte 117 +.byte 108 +.byte 100 +.byte 32 +.byte 98 +.byte 101 +.byte 10 +.byte 0 +.align 1 +.LC522: +.byte 80 +.byte 115 +.byte 101 +.byte 117 +.byte 100 +.byte 111 +.byte 90 +.byte 101 +.byte 114 +.byte 111 +.byte 32 +.byte 116 +.byte 104 +.byte 97 +.byte 116 +.byte 32 +.byte 112 +.byte 114 +.byte 105 +.byte 110 +.byte 116 +.byte 115 +.byte 32 +.byte 111 +.byte 117 +.byte 116 +.byte 32 +.byte 97 +.byte 115 +.byte 58 +.byte 32 +.byte 37 +.byte 103 +.byte 32 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC521: +.byte 97 +.byte 108 +.byte 108 +.byte 101 +.byte 103 +.byte 101 +.byte 100 +.byte 108 +.byte 121 +.byte 32 +.byte 110 +.byte 101 +.byte 103 +.byte 97 +.byte 116 +.byte 105 +.byte 118 +.byte 101 +.byte 32 +.byte 118 +.byte 97 +.byte 108 +.byte 117 +.byte 101 +.byte 10 +.byte 0 +.align 1 +.LC520: +.byte 80 +.byte 111 +.byte 115 +.byte 105 +.byte 116 +.byte 105 +.byte 118 +.byte 101 +.byte 32 +.byte 101 +.byte 120 +.byte 112 +.byte 114 +.byte 101 +.byte 115 +.byte 115 +.byte 105 +.byte 111 +.byte 110 +.byte 115 +.byte 32 +.byte 99 +.byte 97 +.byte 110 +.byte 32 +.byte 117 +.byte 110 +.byte 100 +.byte 101 +.byte 114 +.byte 102 +.byte 108 +.byte 111 +.byte 119 +.byte 32 +.byte 116 +.byte 111 +.byte 32 +.byte 97 +.byte 110 +.byte 10 +.byte 0 +.align 1 +.LC507: +.byte 109 +.byte 117 +.byte 108 +.byte 116 +.byte 105 +.byte 112 +.byte 108 +.byte 105 +.byte 99 +.byte 97 +.byte 116 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 103 +.byte 101 +.byte 116 +.byte 115 +.byte 32 +.byte 116 +.byte 111 +.byte 111 +.byte 32 +.byte 109 +.byte 97 +.byte 110 +.byte 121 +.byte 32 +.byte 108 +.byte 97 +.byte 115 +.byte 116 +.byte 32 +.byte 100 +.byte 105 +.byte 103 +.byte 105 +.byte 116 +.byte 115 +.byte 32 +.byte 119 +.byte 114 +.byte 111 +.byte 110 +.byte 103 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC483: +.byte 83 +.byte 101 +.byte 101 +.byte 107 +.byte 105 +.byte 110 +.byte 103 +.byte 32 +.byte 85 +.byte 110 +.byte 100 +.byte 101 +.byte 114 +.byte 102 +.byte 108 +.byte 111 +.byte 119 +.byte 32 +.byte 116 +.byte 104 +.byte 114 +.byte 101 +.byte 115 +.byte 104 +.byte 111 +.byte 108 +.byte 100 +.byte 115 +.byte 32 +.byte 85 +.byte 102 +.byte 84 +.byte 104 +.byte 111 +.byte 108 +.byte 100 +.byte 32 +.byte 97 +.byte 110 +.byte 100 +.byte 32 +.byte 69 +.byte 48 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC480: +.byte 46 +.byte 46 +.byte 46 +.byte 32 +.byte 110 +.byte 111 +.byte 32 +.byte 100 +.byte 105 +.byte 115 +.byte 99 +.byte 114 +.byte 101 +.byte 112 +.byte 97 +.byte 110 +.byte 99 +.byte 105 +.byte 115 +.byte 32 +.byte 102 +.byte 111 +.byte 117 +.byte 110 +.byte 100 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC477: +.byte 9 +.byte 105 +.byte 110 +.byte 118 +.byte 111 +.byte 108 +.byte 118 +.byte 105 +.byte 110 +.byte 103 +.byte 32 +.byte 105 +.byte 110 +.byte 116 +.byte 101 +.byte 114 +.byte 101 +.byte 115 +.byte 116 +.byte 32 +.byte 114 +.byte 97 +.byte 116 +.byte 101 +.byte 115 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC476: +.byte 69 +.byte 114 +.byte 114 +.byte 111 +.byte 114 +.byte 115 +.byte 32 +.byte 108 +.byte 105 +.byte 107 +.byte 101 +.byte 32 +.byte 116 +.byte 104 +.byte 105 +.byte 115 +.byte 32 +.byte 109 +.byte 97 +.byte 121 +.byte 32 +.byte 105 +.byte 110 +.byte 118 +.byte 97 +.byte 108 +.byte 105 +.byte 100 +.byte 97 +.byte 116 +.byte 101 +.byte 32 +.byte 102 +.byte 105 +.byte 110 +.byte 97 +.byte 110 +.byte 99 +.byte 105 +.byte 97 +.byte 108 +.byte 32 +.byte 99 +.byte 97 +.byte 108 +.byte 99 +.byte 117 +.byte 108 +.byte 97 +.byte 116 +.byte 105 +.byte 111 +.byte 110 +.byte 115 +.byte 10 +.byte 0 +.align 1 +.LC455: +.byte 84 +.byte 101 +.byte 115 +.byte 116 +.byte 105 +.byte 110 +.byte 103 +.byte 32 +.byte 112 +.byte 111 +.byte 119 +.byte 101 +.byte 114 +.byte 115 +.byte 32 +.byte 90 +.byte 94 +.byte 105 +.byte 32 +.byte 102 +.byte 111 +.byte 114 +.byte 32 +.byte 115 +.byte 109 +.byte 97 +.byte 108 +.byte 108 +.byte 32 +.byte 73 +.byte 110 +.byte 116 +.byte 101 +.byte 103 +.byte 101 +.byte 114 +.byte 115 +.byte 32 +.byte 90 +.byte 32 +.byte 97 +.byte 110 +.byte 100 +.byte 32 +.byte 105 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC452: +.byte 115 +.byte 113 +.byte 114 +.byte 116 +.byte 32 +.byte 103 +.byte 101 +.byte 116 +.byte 115 +.byte 32 +.byte 116 +.byte 111 +.byte 111 +.byte 32 +.byte 109 +.byte 97 +.byte 110 +.byte 121 +.byte 32 +.byte 108 +.byte 97 +.byte 115 +.byte 116 +.byte 32 +.byte 100 +.byte 105 +.byte 103 +.byte 105 +.byte 116 +.byte 115 +.byte 32 +.byte 119 +.byte 114 +.byte 111 +.byte 110 +.byte 103 +.byte 0 +.align 1 +.LC450: +.byte 116 +.byte 111 +.byte 32 +.byte 37 +.byte 46 +.byte 55 +.byte 101 +.byte 32 +.byte 117 +.byte 108 +.byte 112 +.byte 115 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC449: +.byte 79 +.byte 98 +.byte 115 +.byte 101 +.byte 114 +.byte 118 +.byte 101 +.byte 100 +.byte 32 +.byte 101 +.byte 114 +.byte 114 +.byte 111 +.byte 114 +.byte 115 +.byte 32 +.byte 114 +.byte 117 +.byte 110 +.byte 32 +.byte 102 +.byte 114 +.byte 111 +.byte 109 +.byte 32 +.byte 37 +.byte 46 +.byte 55 +.byte 101 +.byte 32 +.byte 0 +.align 1 +.LC448: +.byte 83 +.byte 113 +.byte 117 +.byte 97 +.byte 114 +.byte 101 +.byte 32 +.byte 114 +.byte 111 +.byte 111 +.byte 116 +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 110 +.byte 101 +.byte 105 +.byte 116 +.byte 104 +.byte 101 +.byte 114 +.byte 32 +.byte 99 +.byte 104 +.byte 111 +.byte 112 +.byte 112 +.byte 101 +.byte 100 +.byte 32 +.byte 110 +.byte 111 +.byte 114 +.byte 32 +.byte 99 +.byte 111 +.byte 114 +.byte 114 +.byte 101 +.byte 99 +.byte 116 +.byte 108 +.byte 121 +.byte 32 +.byte 114 +.byte 111 +.byte 117 +.byte 110 +.byte 100 +.byte 101 +.byte 100 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC445: +.byte 83 +.byte 113 +.byte 117 +.byte 97 +.byte 114 +.byte 101 +.byte 32 +.byte 114 +.byte 111 +.byte 111 +.byte 116 +.byte 32 +.byte 97 +.byte 112 +.byte 112 +.byte 101 +.byte 97 +.byte 114 +.byte 115 +.byte 32 +.byte 116 +.byte 111 +.byte 32 +.byte 98 +.byte 101 +.byte 32 +.byte 99 +.byte 104 +.byte 111 +.byte 112 +.byte 112 +.byte 101 +.byte 100 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC440: +.byte 83 +.byte 113 +.byte 117 +.byte 97 +.byte 114 +.byte 101 +.byte 32 +.byte 114 +.byte 111 +.byte 111 +.byte 116 +.byte 32 +.byte 97 +.byte 112 +.byte 112 +.byte 101 +.byte 97 +.byte 114 +.byte 115 +.byte 32 +.byte 116 +.byte 111 +.byte 32 +.byte 98 +.byte 101 +.byte 32 +.byte 99 +.byte 111 +.byte 114 +.byte 114 +.byte 101 +.byte 99 +.byte 116 +.byte 108 +.byte 121 +.byte 32 +.byte 114 +.byte 111 +.byte 117 +.byte 110 +.byte 100 +.byte 101 +.byte 100 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC435: +.byte 32 +.byte 102 +.byte 97 +.byte 105 +.byte 108 +.byte 115 +.byte 32 +.byte 116 +.byte 101 +.byte 115 +.byte 116 +.byte 32 +.byte 119 +.byte 104 +.byte 101 +.byte 116 +.byte 104 +.byte 101 +.byte 114 +.byte 32 +.byte 115 +.byte 113 +.byte 114 +.byte 116 +.byte 32 +.byte 114 +.byte 111 +.byte 117 +.byte 110 +.byte 100 +.byte 115 +.byte 32 +.byte 111 +.byte 114 +.byte 32 +.byte 99 +.byte 104 +.byte 111 +.byte 112 +.byte 115 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC434: +.byte 82 +.byte 97 +.byte 100 +.byte 105 +.byte 120 +.byte 94 +.byte 80 +.byte 114 +.byte 101 +.byte 99 +.byte 105 +.byte 115 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 61 +.byte 32 +.byte 37 +.byte 46 +.byte 55 +.byte 101 +.byte 10 +.byte 0 +.align 1 +.LC433: +.byte 65 +.byte 110 +.byte 111 +.byte 109 +.byte 97 +.byte 108 +.byte 111 +.byte 117 +.byte 115 +.byte 32 +.byte 97 +.byte 114 +.byte 105 +.byte 116 +.byte 104 +.byte 109 +.byte 101 +.byte 116 +.byte 105 +.byte 99 +.byte 32 +.byte 119 +.byte 105 +.byte 116 +.byte 104 +.byte 32 +.byte 73 +.byte 110 +.byte 116 +.byte 101 +.byte 103 +.byte 101 +.byte 114 +.byte 32 +.byte 60 +.byte 32 +.byte 0 +.align 1 +.LC393: +.byte 84 +.byte 101 +.byte 115 +.byte 116 +.byte 105 +.byte 110 +.byte 103 +.byte 32 +.byte 119 +.byte 104 +.byte 101 +.byte 116 +.byte 104 +.byte 101 +.byte 114 +.byte 32 +.byte 115 +.byte 113 +.byte 114 +.byte 116 +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 114 +.byte 111 +.byte 117 +.byte 110 +.byte 100 +.byte 101 +.byte 100 +.byte 32 +.byte 111 +.byte 114 +.byte 32 +.byte 99 +.byte 104 +.byte 111 +.byte 112 +.byte 112 +.byte 101 +.byte 100 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC371: +.byte 115 +.byte 113 +.byte 114 +.byte 116 +.byte 40 +.byte 88 +.byte 41 +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 110 +.byte 111 +.byte 110 +.byte 45 +.byte 109 +.byte 111 +.byte 110 +.byte 111 +.byte 116 +.byte 111 +.byte 110 +.byte 105 +.byte 99 +.byte 32 +.byte 102 +.byte 111 +.byte 114 +.byte 32 +.byte 88 +.byte 32 +.byte 110 +.byte 101 +.byte 97 +.byte 114 +.byte 32 +.byte 37 +.byte 46 +.byte 55 +.byte 101 +.byte 32 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC370: +.byte 115 +.byte 113 +.byte 114 +.byte 116 +.byte 32 +.byte 104 +.byte 97 +.byte 115 +.byte 32 +.byte 112 +.byte 97 +.byte 115 +.byte 115 +.byte 101 +.byte 100 +.byte 32 +.byte 97 +.byte 32 +.byte 116 +.byte 101 +.byte 115 +.byte 116 +.byte 32 +.byte 102 +.byte 111 +.byte 114 +.byte 32 +.byte 77 +.byte 111 +.byte 110 +.byte 111 +.byte 116 +.byte 111 +.byte 110 +.byte 105 +.byte 99 +.byte 105 +.byte 116 +.byte 121 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC353: +.byte 84 +.byte 101 +.byte 115 +.byte 116 +.byte 32 +.byte 102 +.byte 111 +.byte 114 +.byte 32 +.byte 115 +.byte 113 +.byte 114 +.byte 116 +.byte 32 +.byte 109 +.byte 111 +.byte 110 +.byte 111 +.byte 116 +.byte 111 +.byte 110 +.byte 105 +.byte 99 +.byte 105 +.byte 116 +.byte 121 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC342: +.byte 84 +.byte 101 +.byte 115 +.byte 116 +.byte 105 +.byte 110 +.byte 103 +.byte 32 +.byte 105 +.byte 102 +.byte 32 +.byte 115 +.byte 113 +.byte 114 +.byte 116 +.byte 40 +.byte 88 +.byte 32 +.byte 42 +.byte 32 +.byte 88 +.byte 41 +.byte 32 +.byte 61 +.byte 61 +.byte 32 +.byte 88 +.byte 32 +.byte 102 +.byte 111 +.byte 114 +.byte 32 +.byte 37 +.byte 100 +.byte 32 +.byte 73 +.byte 110 +.byte 116 +.byte 101 +.byte 103 +.byte 101 +.byte 114 +.byte 115 +.byte 32 +.byte 88 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC337: +.byte 83 +.byte 113 +.byte 117 +.byte 97 +.byte 114 +.byte 101 +.byte 32 +.byte 114 +.byte 111 +.byte 111 +.byte 116 +.byte 32 +.byte 111 +.byte 102 +.byte 32 +.byte 48 +.byte 46 +.byte 48 +.byte 44 +.byte 32 +.byte 45 +.byte 48 +.byte 46 +.byte 48 +.byte 32 +.byte 111 +.byte 114 +.byte 32 +.byte 49 +.byte 46 +.byte 48 +.byte 32 +.byte 119 +.byte 114 +.byte 111 +.byte 110 +.byte 103 +.byte 0 +.align 1 +.LC335: +.byte 10 +.byte 82 +.byte 117 +.byte 110 +.byte 110 +.byte 105 +.byte 110 +.byte 103 +.byte 32 +.byte 116 +.byte 101 +.byte 115 +.byte 116 +.byte 32 +.byte 111 +.byte 102 +.byte 32 +.byte 115 +.byte 113 +.byte 117 +.byte 97 +.byte 114 +.byte 101 +.byte 32 +.byte 114 +.byte 111 +.byte 111 +.byte 116 +.byte 40 +.byte 120 +.byte 41 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC334: +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 78 +.byte 111 +.byte 32 +.byte 102 +.byte 97 +.byte 105 +.byte 108 +.byte 117 +.byte 114 +.byte 101 +.byte 115 +.byte 32 +.byte 102 +.byte 111 +.byte 117 +.byte 110 +.byte 100 +.byte 32 +.byte 105 +.byte 110 +.byte 32 +.byte 37 +.byte 100 +.byte 32 +.byte 105 +.byte 110 +.byte 116 +.byte 101 +.byte 103 +.byte 101 +.byte 114 +.byte 32 +.byte 112 +.byte 97 +.byte 105 +.byte 114 +.byte 115 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC333: +.byte 88 +.byte 32 +.byte 42 +.byte 32 +.byte 89 +.byte 32 +.byte 61 +.byte 61 +.byte 32 +.byte 89 +.byte 32 +.byte 42 +.byte 32 +.byte 88 +.byte 32 +.byte 116 +.byte 114 +.byte 105 +.byte 97 +.byte 108 +.byte 32 +.byte 102 +.byte 97 +.byte 105 +.byte 108 +.byte 115 +.byte 46 +.byte 10 +.byte 0 +.align 4 +.LC324: +.long 0 +.long 1074266112 +.align 1 +.LC323: +.byte 84 +.byte 101 +.byte 115 +.byte 116 +.byte 105 +.byte 110 +.byte 103 +.byte 32 +.byte 111 +.byte 110 +.byte 32 +.byte 37 +.byte 100 +.byte 32 +.byte 114 +.byte 97 +.byte 110 +.byte 100 +.byte 111 +.byte 109 +.byte 32 +.byte 112 +.byte 97 +.byte 105 +.byte 114 +.byte 115 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC322: +.byte 68 +.byte 111 +.byte 101 +.byte 115 +.byte 32 +.byte 77 +.byte 117 +.byte 108 +.byte 116 +.byte 105 +.byte 112 +.byte 108 +.byte 105 +.byte 99 +.byte 97 +.byte 116 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 99 +.byte 111 +.byte 109 +.byte 109 +.byte 117 +.byte 116 +.byte 101 +.byte 63 +.byte 32 +.byte 32 +.byte 0 +.align 1 +.LC319: +.byte 108 +.byte 97 +.byte 99 +.byte 107 +.byte 40 +.byte 115 +.byte 41 +.byte 32 +.byte 111 +.byte 102 +.byte 32 +.byte 103 +.byte 117 +.byte 97 +.byte 114 +.byte 100 +.byte 32 +.byte 100 +.byte 105 +.byte 103 +.byte 105 +.byte 116 +.byte 115 +.byte 32 +.byte 111 +.byte 114 +.byte 32 +.byte 102 +.byte 97 +.byte 105 +.byte 108 +.byte 117 +.byte 114 +.byte 101 +.byte 40 +.byte 115 +.byte 41 +.byte 32 +.byte 116 +.byte 111 +.byte 32 +.byte 99 +.byte 111 +.byte 114 +.byte 114 +.byte 101 +.byte 99 +.byte 116 +.byte 108 +.byte 121 +.byte 32 +.byte 114 +.byte 111 +.byte 117 +.byte 110 +.byte 100 +.byte 32 +.byte 111 +.byte 114 +.byte 32 +.byte 99 +.byte 104 +.byte 111 +.byte 112 +.byte 10 +.byte 40 +.byte 110 +.byte 111 +.byte 116 +.byte 101 +.byte 100 +.byte 32 +.byte 97 +.byte 98 +.byte 111 +.byte 118 +.byte 101 +.byte 41 +.byte 32 +.byte 99 +.byte 111 +.byte 117 +.byte 110 +.byte 116 +.byte 32 +.byte 97 +.byte 115 +.byte 32 +.byte 111 +.byte 110 +.byte 101 +.byte 32 +.byte 102 +.byte 108 +.byte 97 +.byte 119 +.byte 32 +.byte 105 +.byte 110 +.byte 32 +.byte 116 +.byte 104 +.byte 101 +.byte 32 +.byte 102 +.byte 105 +.byte 110 +.byte 97 +.byte 108 +.byte 32 +.byte 116 +.byte 97 +.byte 108 +.byte 108 +.byte 121 +.byte 32 +.byte 98 +.byte 101 +.byte 108 +.byte 111 +.byte 119 +.byte 0 +.align 1 +.LC317: +.byte 83 +.byte 116 +.byte 105 +.byte 99 +.byte 107 +.byte 121 +.byte 32 +.byte 98 +.byte 105 +.byte 116 +.byte 32 +.byte 117 +.byte 115 +.byte 101 +.byte 100 +.byte 32 +.byte 105 +.byte 110 +.byte 99 +.byte 111 +.byte 114 +.byte 114 +.byte 101 +.byte 99 +.byte 116 +.byte 108 +.byte 121 +.byte 32 +.byte 111 +.byte 114 +.byte 32 +.byte 110 +.byte 111 +.byte 116 +.byte 32 +.byte 97 +.byte 116 +.byte 32 +.byte 97 +.byte 108 +.byte 108 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC316: +.byte 83 +.byte 116 +.byte 105 +.byte 99 +.byte 107 +.byte 121 +.byte 32 +.byte 98 +.byte 105 +.byte 116 +.byte 32 +.byte 97 +.byte 112 +.byte 112 +.byte 97 +.byte 114 +.byte 101 +.byte 110 +.byte 116 +.byte 108 +.byte 121 +.byte 32 +.byte 117 +.byte 115 +.byte 101 +.byte 100 +.byte 32 +.byte 99 +.byte 111 +.byte 114 +.byte 114 +.byte 101 +.byte 99 +.byte 116 +.byte 108 +.byte 121 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC299: +.byte 67 +.byte 104 +.byte 101 +.byte 99 +.byte 107 +.byte 105 +.byte 110 +.byte 103 +.byte 32 +.byte 102 +.byte 111 +.byte 114 +.byte 32 +.byte 115 +.byte 116 +.byte 105 +.byte 99 +.byte 107 +.byte 121 +.byte 32 +.byte 98 +.byte 105 +.byte 116 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC296: +.byte 40 +.byte 88 +.byte 32 +.byte 45 +.byte 32 +.byte 89 +.byte 41 +.byte 32 +.byte 43 +.byte 32 +.byte 40 +.byte 89 +.byte 32 +.byte 45 +.byte 32 +.byte 88 +.byte 41 +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 110 +.byte 111 +.byte 110 +.byte 32 +.byte 122 +.byte 101 +.byte 114 +.byte 111 +.byte 33 +.byte 10 +.byte 0 +.align 1 +.LC293: +.byte 65 +.byte 100 +.byte 100 +.byte 105 +.byte 116 +.byte 105 +.byte 111 +.byte 110 +.byte 47 +.byte 83 +.byte 117 +.byte 98 +.byte 116 +.byte 114 +.byte 97 +.byte 99 +.byte 116 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 110 +.byte 101 +.byte 105 +.byte 116 +.byte 104 +.byte 101 +.byte 114 +.byte 32 +.byte 114 +.byte 111 +.byte 117 +.byte 110 +.byte 100 +.byte 115 +.byte 32 +.byte 110 +.byte 111 +.byte 114 +.byte 32 +.byte 99 +.byte 104 +.byte 111 +.byte 112 +.byte 115 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC292: +.byte 65 +.byte 100 +.byte 100 +.byte 47 +.byte 83 +.byte 117 +.byte 98 +.byte 116 +.byte 114 +.byte 97 +.byte 99 +.byte 116 +.byte 0 +.align 1 +.LC289: +.byte 65 +.byte 100 +.byte 100 +.byte 105 +.byte 116 +.byte 105 +.byte 111 +.byte 110 +.byte 47 +.byte 83 +.byte 117 +.byte 98 +.byte 116 +.byte 114 +.byte 97 +.byte 99 +.byte 116 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 97 +.byte 112 +.byte 112 +.byte 101 +.byte 97 +.byte 114 +.byte 115 +.byte 32 +.byte 116 +.byte 111 +.byte 32 +.byte 114 +.byte 111 +.byte 117 +.byte 110 +.byte 100 +.byte 32 +.byte 99 +.byte 111 +.byte 114 +.byte 114 +.byte 101 +.byte 99 +.byte 116 +.byte 108 +.byte 121 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC282: +.byte 65 +.byte 100 +.byte 100 +.byte 47 +.byte 83 +.byte 117 +.byte 98 +.byte 116 +.byte 114 +.byte 97 +.byte 99 +.byte 116 +.byte 32 +.byte 97 +.byte 112 +.byte 112 +.byte 101 +.byte 97 +.byte 114 +.byte 115 +.byte 32 +.byte 116 +.byte 111 +.byte 32 +.byte 98 +.byte 101 +.byte 32 +.byte 99 +.byte 104 +.byte 111 +.byte 112 +.byte 112 +.byte 101 +.byte 100 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC277: +.byte 73 +.byte 110 +.byte 99 +.byte 111 +.byte 109 +.byte 112 +.byte 108 +.byte 101 +.byte 116 +.byte 101 +.byte 32 +.byte 99 +.byte 97 +.byte 114 +.byte 114 +.byte 121 +.byte 45 +.byte 112 +.byte 114 +.byte 111 +.byte 112 +.byte 97 +.byte 103 +.byte 97 +.byte 116 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 105 +.byte 110 +.byte 32 +.byte 65 +.byte 100 +.byte 100 +.byte 105 +.byte 116 +.byte 105 +.byte 111 +.byte 110 +.byte 0 +.align 1 +.LC273: +.byte 82 +.byte 97 +.byte 100 +.byte 105 +.byte 120 +.byte 32 +.byte 42 +.byte 32 +.byte 40 +.byte 32 +.byte 49 +.byte 32 +.byte 47 +.byte 32 +.byte 82 +.byte 97 +.byte 100 +.byte 105 +.byte 120 +.byte 32 +.byte 41 +.byte 32 +.byte 100 +.byte 105 +.byte 102 +.byte 102 +.byte 101 +.byte 114 +.byte 115 +.byte 32 +.byte 102 +.byte 114 +.byte 111 +.byte 109 +.byte 32 +.byte 49 +.byte 0 +.align 1 +.LC271: +.byte 47 +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 110 +.byte 101 +.byte 105 +.byte 116 +.byte 104 +.byte 101 +.byte 114 +.byte 32 +.byte 99 +.byte 104 +.byte 111 +.byte 112 +.byte 112 +.byte 101 +.byte 100 +.byte 32 +.byte 110 +.byte 111 +.byte 114 +.byte 32 +.byte 99 +.byte 111 +.byte 114 +.byte 114 +.byte 101 +.byte 99 +.byte 116 +.byte 108 +.byte 121 +.byte 32 +.byte 114 +.byte 111 +.byte 117 +.byte 110 +.byte 100 +.byte 101 +.byte 100 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC268: +.byte 68 +.byte 105 +.byte 118 +.byte 105 +.byte 115 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 97 +.byte 112 +.byte 112 +.byte 101 +.byte 97 +.byte 114 +.byte 115 +.byte 32 +.byte 116 +.byte 111 +.byte 32 +.byte 99 +.byte 104 +.byte 111 +.byte 112 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC265: +.byte 68 +.byte 105 +.byte 118 +.byte 105 +.byte 115 +.byte 105 +.byte 111 +.byte 110 +.byte 0 +.align 1 +.LC262: +.byte 68 +.byte 105 +.byte 118 +.byte 105 +.byte 115 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 97 +.byte 112 +.byte 112 +.byte 101 +.byte 97 +.byte 114 +.byte 115 +.byte 32 +.byte 116 +.byte 111 +.byte 32 +.byte 114 +.byte 111 +.byte 117 +.byte 110 +.byte 100 +.byte 32 +.byte 99 +.byte 111 +.byte 114 +.byte 114 +.byte 101 +.byte 99 +.byte 116 +.byte 108 +.byte 121 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC257: +.byte 77 +.byte 117 +.byte 108 +.byte 116 +.byte 105 +.byte 112 +.byte 108 +.byte 105 +.byte 99 +.byte 97 +.byte 116 +.byte 105 +.byte 111 +.byte 110 +.byte 0 +.align 1 +.LC254: +.byte 42 +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 110 +.byte 101 +.byte 105 +.byte 116 +.byte 104 +.byte 101 +.byte 114 +.byte 32 +.byte 99 +.byte 104 +.byte 111 +.byte 112 +.byte 112 +.byte 101 +.byte 100 +.byte 32 +.byte 110 +.byte 111 +.byte 114 +.byte 32 +.byte 99 +.byte 111 +.byte 114 +.byte 114 +.byte 101 +.byte 99 +.byte 116 +.byte 108 +.byte 121 +.byte 32 +.byte 114 +.byte 111 +.byte 117 +.byte 110 +.byte 100 +.byte 101 +.byte 100 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC253: +.byte 77 +.byte 117 +.byte 108 +.byte 116 +.byte 105 +.byte 112 +.byte 108 +.byte 105 +.byte 99 +.byte 97 +.byte 116 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 97 +.byte 112 +.byte 112 +.byte 101 +.byte 97 +.byte 114 +.byte 115 +.byte 32 +.byte 116 +.byte 111 +.byte 32 +.byte 99 +.byte 104 +.byte 111 +.byte 112 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC250: +.byte 77 +.byte 117 +.byte 108 +.byte 116 +.byte 105 +.byte 112 +.byte 108 +.byte 105 +.byte 99 +.byte 97 +.byte 116 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 97 +.byte 112 +.byte 112 +.byte 101 +.byte 97 +.byte 114 +.byte 115 +.byte 32 +.byte 116 +.byte 111 +.byte 32 +.byte 114 +.byte 111 +.byte 117 +.byte 110 +.byte 100 +.byte 32 +.byte 99 +.byte 111 +.byte 114 +.byte 114 +.byte 101 +.byte 99 +.byte 116 +.byte 108 +.byte 121 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC240: +.byte 88 +.byte 32 +.byte 42 +.byte 32 +.byte 40 +.byte 49 +.byte 47 +.byte 88 +.byte 41 +.byte 32 +.byte 100 +.byte 105 +.byte 102 +.byte 102 +.byte 101 +.byte 114 +.byte 115 +.byte 32 +.byte 102 +.byte 114 +.byte 111 +.byte 109 +.byte 32 +.byte 49 +.byte 0 +.align 1 +.LC221: +.byte 67 +.byte 104 +.byte 101 +.byte 99 +.byte 107 +.byte 105 +.byte 110 +.byte 103 +.byte 32 +.byte 114 +.byte 111 +.byte 117 +.byte 110 +.byte 100 +.byte 105 +.byte 110 +.byte 103 +.byte 32 +.byte 111 +.byte 110 +.byte 32 +.byte 109 +.byte 117 +.byte 108 +.byte 116 +.byte 105 +.byte 112 +.byte 108 +.byte 121 +.byte 44 +.byte 32 +.byte 100 +.byte 105 +.byte 118 +.byte 105 +.byte 100 +.byte 101 +.byte 32 +.byte 97 +.byte 110 +.byte 100 +.byte 32 +.byte 97 +.byte 100 +.byte 100 +.byte 47 +.byte 115 +.byte 117 +.byte 98 +.byte 116 +.byte 114 +.byte 97 +.byte 99 +.byte 116 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC220: +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 32 +.byte 42 +.byte 44 +.byte 32 +.byte 47 +.byte 44 +.byte 32 +.byte 97 +.byte 110 +.byte 100 +.byte 32 +.byte 45 +.byte 32 +.byte 97 +.byte 112 +.byte 112 +.byte 101 +.byte 97 +.byte 114 +.byte 32 +.byte 116 +.byte 111 +.byte 32 +.byte 104 +.byte 97 +.byte 118 +.byte 101 +.byte 32 +.byte 103 +.byte 117 +.byte 97 +.byte 114 +.byte 100 +.byte 32 +.byte 100 +.byte 105 +.byte 103 +.byte 105 +.byte 116 +.byte 115 +.byte 44 +.byte 32 +.byte 97 +.byte 115 +.byte 32 +.byte 116 +.byte 104 +.byte 101 +.byte 121 +.byte 32 +.byte 115 +.byte 104 +.byte 111 +.byte 117 +.byte 108 +.byte 100 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC217: +.byte 32 +.byte 32 +.byte 46 +.byte 46 +.byte 46 +.byte 32 +.byte 32 +.byte 105 +.byte 102 +.byte 32 +.byte 40 +.byte 88 +.byte 32 +.byte 61 +.byte 61 +.byte 32 +.byte 49 +.byte 46 +.byte 48 +.byte 41 +.byte 32 +.byte 123 +.byte 46 +.byte 46 +.byte 46 +.byte 46 +.byte 46 +.byte 125 +.byte 32 +.byte 101 +.byte 108 +.byte 115 +.byte 101 +.byte 32 +.byte 123 +.byte 46 +.byte 46 +.byte 46 +.byte 47 +.byte 40 +.byte 88 +.byte 45 +.byte 49 +.byte 46 +.byte 48 +.byte 41 +.byte 46 +.byte 46 +.byte 46 +.byte 125 +.byte 10 +.byte 0 +.align 1 +.LC216: +.byte 32 +.byte 32 +.byte 115 +.byte 117 +.byte 99 +.byte 104 +.byte 32 +.byte 112 +.byte 114 +.byte 101 +.byte 99 +.byte 97 +.byte 117 +.byte 116 +.byte 105 +.byte 111 +.byte 110 +.byte 115 +.byte 32 +.byte 97 +.byte 103 +.byte 97 +.byte 105 +.byte 110 +.byte 115 +.byte 116 +.byte 32 +.byte 100 +.byte 105 +.byte 118 +.byte 105 +.byte 115 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 98 +.byte 121 +.byte 32 +.byte 122 +.byte 101 +.byte 114 +.byte 111 +.byte 32 +.byte 97 +.byte 115 +.byte 10 +.byte 0 +.align 1 +.LC215: +.byte 32 +.byte 32 +.byte 115 +.byte 117 +.byte 98 +.byte 116 +.byte 114 +.byte 97 +.byte 99 +.byte 116 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 121 +.byte 105 +.byte 101 +.byte 108 +.byte 100 +.byte 115 +.byte 32 +.byte 32 +.byte 40 +.byte 49 +.byte 45 +.byte 85 +.byte 49 +.byte 41 +.byte 32 +.byte 45 +.byte 32 +.byte 49 +.byte 32 +.byte 61 +.byte 32 +.byte 48 +.byte 32 +.byte 44 +.byte 32 +.byte 116 +.byte 104 +.byte 101 +.byte 114 +.byte 101 +.byte 98 +.byte 121 +.byte 32 +.byte 118 +.byte 105 +.byte 116 +.byte 105 +.byte 97 +.byte 116 +.byte 105 +.byte 110 +.byte 103 +.byte 10 +.byte 0 +.align 1 +.LC214: +.byte 99 +.byte 111 +.byte 109 +.byte 112 +.byte 97 +.byte 114 +.byte 105 +.byte 115 +.byte 111 +.byte 110 +.byte 32 +.byte 97 +.byte 108 +.byte 108 +.byte 101 +.byte 103 +.byte 101 +.byte 115 +.byte 32 +.byte 32 +.byte 40 +.byte 49 +.byte 45 +.byte 85 +.byte 49 +.byte 41 +.byte 32 +.byte 60 +.byte 32 +.byte 49 +.byte 32 +.byte 32 +.byte 97 +.byte 108 +.byte 116 +.byte 104 +.byte 111 +.byte 117 +.byte 103 +.byte 104 +.byte 10 +.byte 0 +.align 1 +.LC211: +.byte 45 +.byte 32 +.byte 108 +.byte 97 +.byte 99 +.byte 107 +.byte 115 +.byte 32 +.byte 71 +.byte 117 +.byte 97 +.byte 114 +.byte 100 +.byte 32 +.byte 68 +.byte 105 +.byte 103 +.byte 105 +.byte 116 +.byte 44 +.byte 32 +.byte 115 +.byte 111 +.byte 32 +.byte 99 +.byte 97 +.byte 110 +.byte 99 +.byte 101 +.byte 108 +.byte 108 +.byte 97 +.byte 116 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 111 +.byte 98 +.byte 115 +.byte 99 +.byte 117 +.byte 114 +.byte 101 +.byte 100 +.byte 0 +.align 1 +.LC206: +.byte 42 +.byte 32 +.byte 97 +.byte 110 +.byte 100 +.byte 47 +.byte 111 +.byte 114 +.byte 32 +.byte 47 +.byte 32 +.byte 103 +.byte 101 +.byte 116 +.byte 115 +.byte 32 +.byte 116 +.byte 111 +.byte 111 +.byte 32 +.byte 109 +.byte 97 +.byte 110 +.byte 121 +.byte 32 +.byte 108 +.byte 97 +.byte 115 +.byte 116 +.byte 32 +.byte 100 +.byte 105 +.byte 103 +.byte 105 +.byte 116 +.byte 115 +.byte 32 +.byte 119 +.byte 114 +.byte 111 +.byte 110 +.byte 103 +.byte 0 +.align 1 +.LC202: +.byte 67 +.byte 111 +.byte 109 +.byte 112 +.byte 117 +.byte 116 +.byte 101 +.byte 100 +.byte 32 +.byte 118 +.byte 97 +.byte 108 +.byte 117 +.byte 101 +.byte 32 +.byte 111 +.byte 102 +.byte 32 +.byte 49 +.byte 47 +.byte 49 +.byte 46 +.byte 48 +.byte 48 +.byte 48 +.byte 46 +.byte 46 +.byte 49 +.byte 32 +.byte 62 +.byte 61 +.byte 32 +.byte 49 +.byte 0 +.align 1 +.LC200: +.byte 68 +.byte 105 +.byte 118 +.byte 105 +.byte 115 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 108 +.byte 97 +.byte 99 +.byte 107 +.byte 115 +.byte 32 +.byte 97 +.byte 32 +.byte 71 +.byte 117 +.byte 97 +.byte 114 +.byte 100 +.byte 32 +.byte 68 +.byte 105 +.byte 103 +.byte 105 +.byte 116 +.byte 44 +.byte 32 +.byte 115 +.byte 111 +.byte 32 +.byte 88 +.byte 47 +.byte 49 +.byte 32 +.byte 33 +.byte 61 +.byte 32 +.byte 88 +.byte 0 +.align 1 +.LC195: +.byte 68 +.byte 105 +.byte 118 +.byte 105 +.byte 115 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 108 +.byte 97 +.byte 99 +.byte 107 +.byte 115 +.byte 32 +.byte 97 +.byte 32 +.byte 71 +.byte 117 +.byte 97 +.byte 114 +.byte 100 +.byte 32 +.byte 68 +.byte 105 +.byte 103 +.byte 105 +.byte 116 +.byte 44 +.byte 32 +.byte 115 +.byte 111 +.byte 32 +.byte 101 +.byte 114 +.byte 114 +.byte 111 +.byte 114 +.byte 32 +.byte 99 +.byte 97 +.byte 110 +.byte 32 +.byte 101 +.byte 120 +.byte 99 +.byte 101 +.byte 101 +.byte 100 +.byte 32 +.byte 49 +.byte 32 +.byte 117 +.byte 108 +.byte 112 +.byte 10 +.byte 111 +.byte 114 +.byte 32 +.byte 32 +.byte 49 +.byte 47 +.byte 51 +.byte 32 +.byte 32 +.byte 97 +.byte 110 +.byte 100 +.byte 32 +.byte 32 +.byte 51 +.byte 47 +.byte 57 +.byte 32 +.byte 32 +.byte 97 +.byte 110 +.byte 100 +.byte 32 +.byte 32 +.byte 57 +.byte 47 +.byte 50 +.byte 55 +.byte 32 +.byte 109 +.byte 97 +.byte 121 +.byte 32 +.byte 100 +.byte 105 +.byte 115 +.byte 97 +.byte 103 +.byte 114 +.byte 101 +.byte 101 +.byte 0 +.align 1 +.LC191: +.byte 42 +.byte 32 +.byte 103 +.byte 101 +.byte 116 +.byte 115 +.byte 32 +.byte 116 +.byte 111 +.byte 111 +.byte 32 +.byte 109 +.byte 97 +.byte 110 +.byte 121 +.byte 32 +.byte 102 +.byte 105 +.byte 110 +.byte 97 +.byte 108 +.byte 32 +.byte 100 +.byte 105 +.byte 103 +.byte 105 +.byte 116 +.byte 115 +.byte 32 +.byte 119 +.byte 114 +.byte 111 +.byte 110 +.byte 103 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC189: +.byte 42 +.byte 32 +.byte 108 +.byte 97 +.byte 99 +.byte 107 +.byte 115 +.byte 32 +.byte 97 +.byte 32 +.byte 71 +.byte 117 +.byte 97 +.byte 114 +.byte 100 +.byte 32 +.byte 68 +.byte 105 +.byte 103 +.byte 105 +.byte 116 +.byte 44 +.byte 32 +.byte 115 +.byte 111 +.byte 32 +.byte 49 +.byte 42 +.byte 88 +.byte 32 +.byte 33 +.byte 61 +.byte 32 +.byte 88 +.byte 0 +.align 1 +.LC186: +.byte 10 +.byte 67 +.byte 104 +.byte 101 +.byte 99 +.byte 107 +.byte 105 +.byte 110 +.byte 103 +.byte 32 +.byte 102 +.byte 111 +.byte 114 +.byte 32 +.byte 103 +.byte 117 +.byte 97 +.byte 114 +.byte 100 +.byte 32 +.byte 100 +.byte 105 +.byte 103 +.byte 105 +.byte 116 +.byte 32 +.byte 105 +.byte 110 +.byte 32 +.byte 42 +.byte 44 +.byte 32 +.byte 47 +.byte 44 +.byte 32 +.byte 97 +.byte 110 +.byte 100 +.byte 32 +.byte 45 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC185: +.byte 83 +.byte 117 +.byte 98 +.byte 116 +.byte 114 +.byte 97 +.byte 99 +.byte 116 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 97 +.byte 112 +.byte 112 +.byte 101 +.byte 97 +.byte 114 +.byte 115 +.byte 32 +.byte 116 +.byte 111 +.byte 32 +.byte 98 +.byte 101 +.byte 32 +.byte 110 +.byte 111 +.byte 114 +.byte 109 +.byte 97 +.byte 108 +.byte 105 +.byte 122 +.byte 101 +.byte 100 +.byte 44 +.byte 32 +.byte 97 +.byte 115 +.byte 32 +.byte 105 +.byte 116 +.byte 32 +.byte 115 +.byte 104 +.byte 111 +.byte 117 +.byte 108 +.byte 100 +.byte 32 +.byte 98 +.byte 101 +.byte 46 +.byte 0 +.align 1 +.LC180: +.byte 83 +.byte 117 +.byte 98 +.byte 116 +.byte 114 +.byte 97 +.byte 99 +.byte 116 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 110 +.byte 111 +.byte 116 +.byte 32 +.byte 110 +.byte 111 +.byte 114 +.byte 109 +.byte 97 +.byte 108 +.byte 105 +.byte 122 +.byte 101 +.byte 100 +.byte 32 +.byte 88 +.byte 61 +.byte 89 +.byte 44 +.byte 88 +.byte 43 +.byte 90 +.byte 32 +.byte 33 +.byte 61 +.byte 32 +.byte 89 +.byte 43 +.byte 90 +.byte 33 +.byte 0 +.align 1 +.LC176: +.byte 114 +.byte 111 +.byte 117 +.byte 103 +.byte 104 +.byte 108 +.byte 121 +.byte 32 +.byte 37 +.byte 103 +.byte 32 +.byte 101 +.byte 120 +.byte 116 +.byte 114 +.byte 97 +.byte 32 +.byte 115 +.byte 105 +.byte 103 +.byte 110 +.byte 105 +.byte 102 +.byte 105 +.byte 99 +.byte 97 +.byte 110 +.byte 116 +.byte 32 +.byte 100 +.byte 101 +.byte 99 +.byte 105 +.byte 109 +.byte 97 +.byte 108 +.byte 115 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC175: +.byte 112 +.byte 114 +.byte 101 +.byte 99 +.byte 105 +.byte 115 +.byte 101 +.byte 108 +.byte 121 +.byte 32 +.byte 119 +.byte 105 +.byte 116 +.byte 104 +.byte 32 +.byte 97 +.byte 98 +.byte 111 +.byte 117 +.byte 116 +.byte 32 +.byte 37 +.byte 103 +.byte 32 +.byte 101 +.byte 120 +.byte 116 +.byte 114 +.byte 97 +.byte 32 +.byte 66 +.byte 45 +.byte 100 +.byte 105 +.byte 103 +.byte 105 +.byte 116 +.byte 115 +.byte 44 +.byte 32 +.byte 105 +.byte 46 +.byte 101 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC174: +.byte 83 +.byte 111 +.byte 109 +.byte 101 +.byte 32 +.byte 115 +.byte 117 +.byte 98 +.byte 101 +.byte 120 +.byte 112 +.byte 114 +.byte 101 +.byte 115 +.byte 115 +.byte 105 +.byte 111 +.byte 110 +.byte 115 +.byte 32 +.byte 97 +.byte 112 +.byte 112 +.byte 101 +.byte 97 +.byte 114 +.byte 32 +.byte 116 +.byte 111 +.byte 32 +.byte 98 +.byte 101 +.byte 32 +.byte 99 +.byte 97 +.byte 108 +.byte 99 +.byte 117 +.byte 108 +.byte 97 +.byte 116 +.byte 101 +.byte 100 +.byte 32 +.byte 101 +.byte 120 +.byte 116 +.byte 114 +.byte 97 +.byte 10 +.byte 0 +.align 1 +.LC168: +.byte 111 +.byte 102 +.byte 32 +.byte 97 +.byte 110 +.byte 10 +.byte 101 +.byte 120 +.byte 116 +.byte 114 +.byte 97 +.byte 45 +.byte 112 +.byte 114 +.byte 101 +.byte 99 +.byte 105 +.byte 115 +.byte 105 +.byte 111 +.byte 110 +.byte 0 +.align 1 +.LC167: +.byte 90 +.byte 49 +.byte 32 +.byte 61 +.byte 32 +.byte 37 +.byte 46 +.byte 55 +.byte 101 +.byte 44 +.byte 32 +.byte 111 +.byte 114 +.byte 32 +.byte 90 +.byte 50 +.byte 32 +.byte 61 +.byte 32 +.byte 37 +.byte 46 +.byte 55 +.byte 101 +.byte 32 +.byte 0 +.align 1 +.LC166: +.byte 44 +.byte 32 +.byte 111 +.byte 114 +.byte 32 +.byte 101 +.byte 120 +.byte 97 +.byte 99 +.byte 116 +.byte 32 +.byte 114 +.byte 97 +.byte 116 +.byte 105 +.byte 111 +.byte 110 +.byte 97 +.byte 108 +.byte 32 +.byte 97 +.byte 114 +.byte 105 +.byte 116 +.byte 104 +.byte 109 +.byte 101 +.byte 116 +.byte 105 +.byte 99 +.byte 32 +.byte 97 +.byte 32 +.byte 114 +.byte 101 +.byte 115 +.byte 117 +.byte 108 +.byte 116 +.byte 10 +.byte 0 +.align 1 +.LC165: +.byte 66 +.byte 101 +.byte 99 +.byte 97 +.byte 117 +.byte 115 +.byte 101 +.byte 32 +.byte 111 +.byte 102 +.byte 32 +.byte 117 +.byte 110 +.byte 117 +.byte 115 +.byte 117 +.byte 97 +.byte 108 +.byte 32 +.byte 82 +.byte 97 +.byte 100 +.byte 105 +.byte 120 +.byte 32 +.byte 61 +.byte 32 +.byte 37 +.byte 102 +.byte 0 +.align 1 +.LC161: +.byte 9 +.byte 85 +.byte 50 +.byte 32 +.byte 61 +.byte 32 +.byte 37 +.byte 46 +.byte 55 +.byte 101 +.byte 44 +.byte 32 +.byte 90 +.byte 50 +.byte 32 +.byte 45 +.byte 32 +.byte 85 +.byte 50 +.byte 32 +.byte 61 +.byte 32 +.byte 37 +.byte 46 +.byte 55 +.byte 101 +.byte 10 +.byte 0 +.align 1 +.LC160: +.byte 9 +.byte 85 +.byte 49 +.byte 32 +.byte 61 +.byte 32 +.byte 37 +.byte 46 +.byte 55 +.byte 101 +.byte 44 +.byte 32 +.byte 90 +.byte 49 +.byte 32 +.byte 45 +.byte 32 +.byte 85 +.byte 49 +.byte 32 +.byte 61 +.byte 32 +.byte 37 +.byte 46 +.byte 55 +.byte 101 +.byte 10 +.byte 0 +.align 1 +.LC159: +.byte 80 +.byte 114 +.byte 101 +.byte 99 +.byte 105 +.byte 115 +.byte 105 +.byte 111 +.byte 110 +.byte 0 +.align 1 +.LC158: +.byte 0 +.align 1 +.LC151: +.byte 84 +.byte 104 +.byte 97 +.byte 116 +.byte 32 +.byte 102 +.byte 101 +.byte 97 +.byte 116 +.byte 117 +.byte 114 +.byte 101 +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 110 +.byte 111 +.byte 116 +.byte 32 +.byte 116 +.byte 101 +.byte 115 +.byte 116 +.byte 101 +.byte 100 +.byte 32 +.byte 102 +.byte 117 +.byte 114 +.byte 116 +.byte 104 +.byte 101 +.byte 114 +.byte 32 +.byte 98 +.byte 121 +.byte 32 +.byte 116 +.byte 104 +.byte 105 +.byte 115 +.byte 32 +.byte 112 +.byte 114 +.byte 111 +.byte 103 +.byte 114 +.byte 97 +.byte 109 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC146: +.byte 80 +.byte 111 +.byte 115 +.byte 115 +.byte 105 +.byte 98 +.byte 108 +.byte 121 +.byte 32 +.byte 115 +.byte 111 +.byte 109 +.byte 101 +.byte 32 +.byte 112 +.byte 97 +.byte 114 +.byte 116 +.byte 32 +.byte 111 +.byte 102 +.byte 32 +.byte 116 +.byte 104 +.byte 105 +.byte 115 +.byte 0 +.align 1 +.LC145: +.byte 98 +.byte 121 +.byte 32 +.byte 101 +.byte 120 +.byte 116 +.byte 114 +.byte 97 +.byte 45 +.byte 112 +.byte 114 +.byte 101 +.byte 99 +.byte 105 +.byte 115 +.byte 101 +.byte 32 +.byte 101 +.byte 118 +.byte 97 +.byte 108 +.byte 117 +.byte 97 +.byte 116 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 111 +.byte 102 +.byte 32 +.byte 97 +.byte 114 +.byte 105 +.byte 116 +.byte 104 +.byte 109 +.byte 101 +.byte 116 +.byte 105 +.byte 99 +.byte 32 +.byte 115 +.byte 117 +.byte 98 +.byte 101 +.byte 120 +.byte 112 +.byte 114 +.byte 101 +.byte 115 +.byte 115 +.byte 105 +.byte 111 +.byte 110 +.byte 115 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC144: +.byte 97 +.byte 114 +.byte 101 +.byte 32 +.byte 115 +.byte 121 +.byte 109 +.byte 112 +.byte 116 +.byte 111 +.byte 109 +.byte 115 +.byte 32 +.byte 111 +.byte 102 +.byte 32 +.byte 105 +.byte 110 +.byte 99 +.byte 111 +.byte 110 +.byte 115 +.byte 105 +.byte 115 +.byte 116 +.byte 101 +.byte 110 +.byte 99 +.byte 105 +.byte 101 +.byte 115 +.byte 32 +.byte 105 +.byte 110 +.byte 116 +.byte 114 +.byte 111 +.byte 100 +.byte 117 +.byte 99 +.byte 101 +.byte 100 +.byte 10 +.byte 0 +.align 1 +.LC143: +.byte 114 +.byte 101 +.byte 115 +.byte 112 +.byte 101 +.byte 99 +.byte 116 +.byte 105 +.byte 118 +.byte 101 +.byte 108 +.byte 121 +.byte 32 +.byte 32 +.byte 37 +.byte 46 +.byte 55 +.byte 101 +.byte 44 +.byte 32 +.byte 32 +.byte 37 +.byte 46 +.byte 55 +.byte 101 +.byte 44 +.byte 32 +.byte 32 +.byte 37 +.byte 46 +.byte 55 +.byte 101 +.byte 44 +.byte 10 +.byte 0 +.align 1 +.LC142: +.byte 68 +.byte 105 +.byte 115 +.byte 97 +.byte 103 +.byte 114 +.byte 101 +.byte 101 +.byte 109 +.byte 101 +.byte 110 +.byte 116 +.byte 115 +.byte 32 +.byte 97 +.byte 109 +.byte 111 +.byte 110 +.byte 103 +.byte 32 +.byte 116 +.byte 104 +.byte 101 +.byte 32 +.byte 118 +.byte 97 +.byte 108 +.byte 117 +.byte 101 +.byte 115 +.byte 32 +.byte 88 +.byte 49 +.byte 44 +.byte 32 +.byte 89 +.byte 49 +.byte 44 +.byte 32 +.byte 90 +.byte 49 +.byte 44 +.byte 10 +.byte 0 +.align 1 +.LC120: +.byte 80 +.byte 114 +.byte 101 +.byte 99 +.byte 105 +.byte 115 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 119 +.byte 111 +.byte 114 +.byte 115 +.byte 101 +.byte 32 +.byte 116 +.byte 104 +.byte 97 +.byte 110 +.byte 32 +.byte 53 +.byte 32 +.byte 100 +.byte 101 +.byte 99 +.byte 105 +.byte 109 +.byte 97 +.byte 108 +.byte 32 +.byte 102 +.byte 105 +.byte 103 +.byte 117 +.byte 114 +.byte 101 +.byte 115 +.byte 32 +.byte 32 +.byte 0 +.align 1 +.LC118: +.byte 84 +.byte 104 +.byte 101 +.byte 32 +.byte 110 +.byte 117 +.byte 109 +.byte 98 +.byte 101 +.byte 114 +.byte 32 +.byte 111 +.byte 102 +.byte 32 +.byte 115 +.byte 105 +.byte 103 +.byte 110 +.byte 105 +.byte 102 +.byte 105 +.byte 99 +.byte 97 +.byte 110 +.byte 116 +.byte 32 +.byte 100 +.byte 105 +.byte 103 +.byte 105 +.byte 116 +.byte 115 +.byte 32 +.byte 111 +.byte 102 +.byte 32 +.byte 116 +.byte 104 +.byte 101 +.byte 32 +.byte 82 +.byte 97 +.byte 100 +.byte 105 +.byte 120 +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 37 +.byte 102 +.byte 32 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC117: +.byte 108 +.byte 111 +.byte 103 +.byte 97 +.byte 114 +.byte 105 +.byte 116 +.byte 104 +.byte 109 +.byte 105 +.byte 99 +.byte 32 +.byte 101 +.byte 110 +.byte 99 +.byte 111 +.byte 100 +.byte 105 +.byte 110 +.byte 103 +.byte 32 +.byte 104 +.byte 97 +.byte 115 +.byte 32 +.byte 112 +.byte 114 +.byte 101 +.byte 99 +.byte 105 +.byte 115 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 99 +.byte 104 +.byte 97 +.byte 114 +.byte 97 +.byte 99 +.byte 116 +.byte 101 +.byte 114 +.byte 105 +.byte 122 +.byte 101 +.byte 100 +.byte 32 +.byte 115 +.byte 111 +.byte 108 +.byte 101 +.byte 108 +.byte 121 +.byte 32 +.byte 98 +.byte 121 +.byte 32 +.byte 85 +.byte 49 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC114: +.byte 111 +.byte 102 +.byte 32 +.byte 115 +.byte 105 +.byte 103 +.byte 110 +.byte 105 +.byte 102 +.byte 105 +.byte 99 +.byte 97 +.byte 110 +.byte 116 +.byte 32 +.byte 100 +.byte 105 +.byte 103 +.byte 105 +.byte 116 +.byte 115 +.byte 32 +.byte 98 +.byte 117 +.byte 116 +.byte 44 +.byte 32 +.byte 98 +.byte 121 +.byte 32 +.byte 105 +.byte 116 +.byte 115 +.byte 101 +.byte 108 +.byte 102 +.byte 44 +.byte 32 +.byte 116 +.byte 104 +.byte 105 +.byte 115 +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 97 +.byte 32 +.byte 109 +.byte 105 +.byte 110 +.byte 111 +.byte 114 +.byte 32 +.byte 102 +.byte 108 +.byte 97 +.byte 119 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC113: +.byte 80 +.byte 114 +.byte 101 +.byte 99 +.byte 105 +.byte 115 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 99 +.byte 97 +.byte 110 +.byte 110 +.byte 111 +.byte 116 +.byte 32 +.byte 98 +.byte 101 +.byte 32 +.byte 99 +.byte 104 +.byte 97 +.byte 114 +.byte 97 +.byte 99 +.byte 116 +.byte 101 +.byte 114 +.byte 105 +.byte 122 +.byte 101 +.byte 100 +.byte 32 +.byte 98 +.byte 121 +.byte 32 +.byte 97 +.byte 110 +.byte 32 +.byte 73 +.byte 110 +.byte 116 +.byte 101 +.byte 103 +.byte 101 +.byte 114 +.byte 32 +.byte 110 +.byte 117 +.byte 109 +.byte 98 +.byte 101 +.byte 114 +.byte 10 +.byte 0 +.align 1 +.LC100: +.byte 67 +.byte 111 +.byte 109 +.byte 112 +.byte 97 +.byte 114 +.byte 105 +.byte 115 +.byte 111 +.byte 110 +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 102 +.byte 117 +.byte 122 +.byte 122 +.byte 121 +.byte 44 +.byte 88 +.byte 61 +.byte 49 +.byte 32 +.byte 98 +.byte 117 +.byte 116 +.byte 32 +.byte 88 +.byte 45 +.byte 49 +.byte 47 +.byte 50 +.byte 45 +.byte 49 +.byte 47 +.byte 50 +.byte 32 +.byte 33 +.byte 61 +.byte 32 +.byte 48 +.byte 0 +.align 1 +.LC96: +.byte 40 +.byte 49 +.byte 45 +.byte 85 +.byte 49 +.byte 41 +.byte 45 +.byte 49 +.byte 47 +.byte 50 +.byte 32 +.byte 60 +.byte 32 +.byte 49 +.byte 47 +.byte 50 +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 70 +.byte 65 +.byte 76 +.byte 83 +.byte 69 +.byte 44 +.byte 32 +.byte 112 +.byte 114 +.byte 111 +.byte 103 +.byte 46 +.byte 32 +.byte 102 +.byte 97 +.byte 105 +.byte 108 +.byte 115 +.byte 63 +.byte 0 +.align 4 +.LC94: +.long 0 +.long 1076101120 +.align 1 +.LC89: +.byte 82 +.byte 97 +.byte 100 +.byte 105 +.byte 120 +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 110 +.byte 111 +.byte 116 +.byte 32 +.byte 97 +.byte 115 +.byte 32 +.byte 103 +.byte 111 +.byte 111 +.byte 100 +.byte 32 +.byte 97 +.byte 115 +.byte 32 +.byte 50 +.byte 32 +.byte 111 +.byte 114 +.byte 32 +.byte 49 +.byte 48 +.byte 0 +.align 1 +.LC85: +.byte 82 +.byte 97 +.byte 100 +.byte 105 +.byte 120 +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 116 +.byte 111 +.byte 111 +.byte 32 +.byte 98 +.byte 105 +.byte 103 +.byte 58 +.byte 32 +.byte 114 +.byte 111 +.byte 117 +.byte 110 +.byte 100 +.byte 111 +.byte 102 +.byte 102 +.byte 32 +.byte 112 +.byte 114 +.byte 111 +.byte 98 +.byte 108 +.byte 101 +.byte 109 +.byte 115 +.byte 0 +.align 1 +.LC83: +.byte 77 +.byte 89 +.byte 83 +.byte 84 +.byte 69 +.byte 82 +.byte 89 +.byte 58 +.byte 32 +.byte 114 +.byte 101 +.byte 99 +.byte 97 +.byte 108 +.byte 99 +.byte 117 +.byte 108 +.byte 97 +.byte 116 +.byte 101 +.byte 100 +.byte 32 +.byte 82 +.byte 97 +.byte 100 +.byte 105 +.byte 120 +.byte 32 +.byte 61 +.byte 32 +.byte 37 +.byte 46 +.byte 55 +.byte 101 +.byte 32 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC82: +.byte 82 +.byte 97 +.byte 100 +.byte 105 +.byte 120 +.byte 32 +.byte 99 +.byte 111 +.byte 110 +.byte 102 +.byte 105 +.byte 114 +.byte 109 +.byte 101 +.byte 100 +.byte 46 +.byte 10 +.byte 0 +.align 4 +.LC79: +.long 1202590843 +.long 1065646817 +.align 1 +.LC78: +.byte 103 +.byte 101 +.byte 116 +.byte 115 +.byte 32 +.byte 98 +.byte 101 +.byte 116 +.byte 116 +.byte 101 +.byte 114 +.byte 32 +.byte 99 +.byte 108 +.byte 111 +.byte 115 +.byte 101 +.byte 115 +.byte 116 +.byte 32 +.byte 114 +.byte 101 +.byte 108 +.byte 97 +.byte 116 +.byte 105 +.byte 118 +.byte 101 +.byte 32 +.byte 115 +.byte 101 +.byte 112 +.byte 97 +.byte 114 +.byte 97 +.byte 116 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 85 +.byte 49 +.byte 32 +.byte 61 +.byte 32 +.byte 37 +.byte 46 +.byte 55 +.byte 101 +.byte 32 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC77: +.byte 99 +.byte 111 +.byte 110 +.byte 102 +.byte 105 +.byte 114 +.byte 109 +.byte 115 +.byte 32 +.byte 99 +.byte 108 +.byte 111 +.byte 115 +.byte 101 +.byte 115 +.byte 116 +.byte 32 +.byte 114 +.byte 101 +.byte 108 +.byte 97 +.byte 116 +.byte 105 +.byte 118 +.byte 101 +.byte 32 +.byte 115 +.byte 101 +.byte 112 +.byte 97 +.byte 114 +.byte 97 +.byte 116 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 85 +.byte 49 +.byte 32 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC62: +.byte 82 +.byte 101 +.byte 99 +.byte 97 +.byte 108 +.byte 99 +.byte 117 +.byte 108 +.byte 97 +.byte 116 +.byte 105 +.byte 110 +.byte 103 +.byte 32 +.byte 114 +.byte 97 +.byte 100 +.byte 105 +.byte 120 +.byte 32 +.byte 97 +.byte 110 +.byte 100 +.byte 32 +.byte 112 +.byte 114 +.byte 101 +.byte 99 +.byte 105 +.byte 115 +.byte 105 +.byte 111 +.byte 110 +.byte 10 +.byte 32 +.byte 0 +.align 1 +.LC61: +.byte 67 +.byte 108 +.byte 111 +.byte 115 +.byte 101 +.byte 115 +.byte 116 +.byte 32 +.byte 114 +.byte 101 +.byte 108 +.byte 97 +.byte 116 +.byte 105 +.byte 118 +.byte 101 +.byte 32 +.byte 115 +.byte 101 +.byte 112 +.byte 97 +.byte 114 +.byte 97 +.byte 116 +.byte 105 +.byte 111 +.byte 110 +.byte 32 +.byte 102 +.byte 111 +.byte 117 +.byte 110 +.byte 100 +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 85 +.byte 49 +.byte 32 +.byte 61 +.byte 32 +.byte 37 +.byte 46 +.byte 55 +.byte 101 +.byte 32 +.byte 46 +.byte 10 +.byte 10 +.byte 0 +.align 1 +.LC55: +.byte 82 +.byte 97 +.byte 100 +.byte 105 +.byte 120 +.byte 32 +.byte 61 +.byte 32 +.byte 37 +.byte 102 +.byte 32 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC46: +.byte 83 +.byte 101 +.byte 97 +.byte 114 +.byte 99 +.byte 104 +.byte 105 +.byte 110 +.byte 103 +.byte 32 +.byte 102 +.byte 111 +.byte 114 +.byte 32 +.byte 82 +.byte 97 +.byte 100 +.byte 105 +.byte 120 +.byte 32 +.byte 97 +.byte 110 +.byte 100 +.byte 32 +.byte 80 +.byte 114 +.byte 101 +.byte 99 +.byte 105 +.byte 115 +.byte 105 +.byte 111 +.byte 110 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC45: +.byte 10 +.byte 0 +.align 1 +.LC44: +.byte 45 +.byte 49 +.byte 44 +.byte 32 +.byte 48 +.byte 44 +.byte 32 +.byte 49 +.byte 47 +.byte 50 +.byte 44 +.byte 32 +.byte 49 +.byte 44 +.byte 32 +.byte 50 +.byte 44 +.byte 32 +.byte 51 +.byte 44 +.byte 32 +.byte 52 +.byte 44 +.byte 32 +.byte 53 +.byte 44 +.byte 32 +.byte 57 +.byte 44 +.byte 32 +.byte 50 +.byte 55 +.byte 44 +.byte 32 +.byte 51 +.byte 50 +.byte 32 +.byte 38 +.byte 32 +.byte 50 +.byte 52 +.byte 48 +.byte 32 +.byte 97 +.byte 114 +.byte 101 +.byte 32 +.byte 79 +.byte 46 +.byte 75 +.byte 46 +.byte 10 +.byte 0 +.align 1 +.LC39: +.byte 53 +.byte 32 +.byte 33 +.byte 61 +.byte 32 +.byte 52 +.byte 43 +.byte 49 +.byte 44 +.byte 32 +.byte 50 +.byte 52 +.byte 48 +.byte 47 +.byte 51 +.byte 32 +.byte 33 +.byte 61 +.byte 32 +.byte 56 +.byte 48 +.byte 44 +.byte 32 +.byte 50 +.byte 52 +.byte 48 +.byte 47 +.byte 52 +.byte 32 +.byte 33 +.byte 61 +.byte 32 +.byte 54 +.byte 48 +.byte 44 +.byte 32 +.byte 111 +.byte 114 +.byte 32 +.byte 50 +.byte 52 +.byte 48 +.byte 47 +.byte 53 +.byte 32 +.byte 33 +.byte 61 +.byte 32 +.byte 52 +.byte 56 +.byte 0 +.align 1 +.LC35: +.byte 57 +.byte 32 +.byte 33 +.byte 61 +.byte 32 +.byte 51 +.byte 42 +.byte 51 +.byte 44 +.byte 32 +.byte 50 +.byte 55 +.byte 32 +.byte 33 +.byte 61 +.byte 32 +.byte 57 +.byte 42 +.byte 51 +.byte 44 +.byte 32 +.byte 51 +.byte 50 +.byte 32 +.byte 33 +.byte 61 +.byte 32 +.byte 56 +.byte 42 +.byte 52 +.byte 44 +.byte 32 +.byte 111 +.byte 114 +.byte 32 +.byte 51 +.byte 50 +.byte 45 +.byte 50 +.byte 55 +.byte 45 +.byte 52 +.byte 45 +.byte 49 +.byte 32 +.byte 33 +.byte 61 +.byte 32 +.byte 48 +.byte 0 +.align 1 +.LC31: +.byte 49 +.byte 47 +.byte 50 +.byte 32 +.byte 43 +.byte 32 +.byte 40 +.byte 45 +.byte 49 +.byte 41 +.byte 32 +.byte 43 +.byte 32 +.byte 49 +.byte 47 +.byte 50 +.byte 32 +.byte 33 +.byte 61 +.byte 32 +.byte 48 +.byte 0 +.align 1 +.LC27: +.byte 45 +.byte 49 +.byte 43 +.byte 49 +.byte 32 +.byte 33 +.byte 61 +.byte 32 +.byte 48 +.byte 44 +.byte 32 +.byte 40 +.byte 45 +.byte 49 +.byte 41 +.byte 43 +.byte 97 +.byte 98 +.byte 115 +.byte 40 +.byte 49 +.byte 41 +.byte 32 +.byte 33 +.byte 61 +.byte 32 +.byte 48 +.byte 44 +.byte 32 +.byte 111 +.byte 114 +.byte 32 +.byte 45 +.byte 49 +.byte 43 +.byte 40 +.byte 45 +.byte 49 +.byte 41 +.byte 42 +.byte 40 +.byte 45 +.byte 49 +.byte 41 +.byte 32 +.byte 33 +.byte 61 +.byte 32 +.byte 48 +.byte 0 +.align 1 +.LC23: +.byte 51 +.byte 32 +.byte 33 +.byte 61 +.byte 32 +.byte 50 +.byte 43 +.byte 49 +.byte 44 +.byte 32 +.byte 52 +.byte 32 +.byte 33 +.byte 61 +.byte 32 +.byte 51 +.byte 43 +.byte 49 +.byte 44 +.byte 32 +.byte 52 +.byte 43 +.byte 50 +.byte 42 +.byte 40 +.byte 45 +.byte 50 +.byte 41 +.byte 32 +.byte 33 +.byte 61 +.byte 32 +.byte 48 +.byte 44 +.byte 32 +.byte 111 +.byte 114 +.byte 32 +.byte 52 +.byte 45 +.byte 51 +.byte 45 +.byte 49 +.byte 32 +.byte 33 +.byte 61 +.byte 32 +.byte 48 +.byte 0 +.align 4 +.LC21: +.long -755914244 +.long 1062232653 +.align 1 +.LC20: +.byte 67 +.byte 111 +.byte 109 +.byte 112 +.byte 97 +.byte 114 +.byte 105 +.byte 115 +.byte 111 +.byte 110 +.byte 32 +.byte 97 +.byte 108 +.byte 108 +.byte 101 +.byte 103 +.byte 101 +.byte 115 +.byte 32 +.byte 116 +.byte 104 +.byte 97 +.byte 116 +.byte 32 +.byte 45 +.byte 48 +.byte 46 +.byte 48 +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 78 +.byte 111 +.byte 110 +.byte 45 +.byte 122 +.byte 101 +.byte 114 +.byte 111 +.byte 33 +.byte 10 +.byte 0 +.align 1 +.LC15: +.byte 48 +.byte 43 +.byte 48 +.byte 32 +.byte 33 +.byte 61 +.byte 32 +.byte 48 +.byte 44 +.byte 32 +.byte 49 +.byte 45 +.byte 49 +.byte 32 +.byte 33 +.byte 61 +.byte 32 +.byte 48 +.byte 44 +.byte 32 +.byte 49 +.byte 32 +.byte 60 +.byte 61 +.byte 32 +.byte 48 +.byte 44 +.byte 32 +.byte 111 +.byte 114 +.byte 32 +.byte 49 +.byte 43 +.byte 49 +.byte 32 +.byte 33 +.byte 61 +.byte 32 +.byte 50 +.byte 0 +.align 1 +.LC13: +.byte 80 +.byte 114 +.byte 111 +.byte 103 +.byte 114 +.byte 97 +.byte 109 +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 110 +.byte 111 +.byte 119 +.byte 32 +.byte 82 +.byte 85 +.byte 78 +.byte 78 +.byte 73 +.byte 78 +.byte 71 +.byte 32 +.byte 116 +.byte 101 +.byte 115 +.byte 116 +.byte 115 +.byte 32 +.byte 111 +.byte 110 +.byte 32 +.byte 115 +.byte 109 +.byte 97 +.byte 108 +.byte 108 +.byte 32 +.byte 105 +.byte 110 +.byte 116 +.byte 101 +.byte 103 +.byte 101 +.byte 114 +.byte 115 +.byte 58 +.byte 10 +.byte 0 +.align 4 +.LC9: +.long 0 +.long 1072693248 +.align 4 +.LC8: +.long 0 +.long 0 +.align 1 +.LC2: +.byte 10 +.byte 42 +.byte 32 +.byte 42 +.byte 32 +.byte 42 +.byte 32 +.byte 70 +.byte 76 +.byte 79 +.byte 65 +.byte 84 +.byte 73 +.byte 78 +.byte 71 +.byte 45 +.byte 80 +.byte 79 +.byte 73 +.byte 78 +.byte 84 +.byte 32 +.byte 69 +.byte 82 +.byte 82 +.byte 79 +.byte 82 +.byte 32 +.byte 42 +.byte 32 +.byte 42 +.byte 32 +.byte 42 +.byte 10 +.byte 0 +.text +.ident "LCC: 4.1" diff --git a/src/cmd/lccom/tst/x86-linux/sort.1bk b/src/cmd/lccom/tst/x86-linux/sort.1bk new file mode 100644 index 0000000..75e1f0d --- /dev/null +++ b/src/cmd/lccom/tst/x86-linux/sort.1bk @@ -0,0 +1,20 @@ +exchange(1,9) +exchange(3,7) +exchange(5,6) +exchange(0,5) +exchange(0,3) +exchange(0,0) +exchange(1,2) +exchange(6,6) +exchange(8,9) +exchange(7,8) +-51 +-1 +0 +1 +3 +10 +18 +32 +567 +789 diff --git a/src/cmd/lccom/tst/x86-linux/sort.2bk b/src/cmd/lccom/tst/x86-linux/sort.2bk new file mode 100644 index 0000000..81e6f38 --- /dev/null +++ b/src/cmd/lccom/tst/x86-linux/sort.2bk @@ -0,0 +1,5 @@ +tst/sort.c:23: warning: missing return value +tst/sort.c:30: warning: missing return value +tst/sort.c:37: warning: missing return value +tst/sort.c:41: warning: missing return value +tst/sort.c:65: warning: missing return value diff --git a/src/cmd/lccom/tst/x86-linux/sort.sbk b/src/cmd/lccom/tst/x86-linux/sort.sbk new file mode 100644 index 0000000..b4cfbb6 --- /dev/null +++ b/src/cmd/lccom/tst/x86-linux/sort.sbk @@ -0,0 +1,331 @@ +.data +.globl in +.align 4 +.type in,@object +in: +.long 10 +.long 32 +.long -1 +.long 567 +.long 3 +.long 18 +.long 1 +.long -51 +.long 789 +.long 0 +.size in,40 +.globl main +.text +.align 16 +.type main,@function +main: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +subl $4,%esp +pushl $10 +pushl $in +call sort +addl $8,%esp +movl $0,-4(%ebp) +jmp .LC5 +.LC2: +movl -4(%ebp),%edi +pushl in(,%edi,4) +call putd +addl $4,%esp +pushl $10 +call putchar +addl $4,%esp +.LC3: +incl -4(%ebp) +.LC5: +movl -4(%ebp),%edi +cmpl $10,%edi +jb .LC2 +mov $0,%eax +.LC1: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf6: +.size main,.Lf6-main +.globl putd +.align 16 +.type putd,@function +putd: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +cmpl $0,20(%ebp) +jge .LC8 +pushl $45 +call putchar +addl $4,%esp +negl 20(%ebp) +.LC8: +movl 20(%ebp),%eax +mov $10,%ecx +cdq +idivl %ecx +cmpl $0,%eax +je .LC10 +movl 20(%ebp),%eax +mov $10,%ecx +cdq +idivl %ecx +pushl %eax +call putd +addl $4,%esp +.LC10: +movl 20(%ebp),%eax +mov $10,%ecx +cdq +idivl %ecx +leal 48(%edx),%edi +pushl %edi +call putchar +addl $4,%esp +mov $0,%eax +.LC7: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf12: +.size putd,.Lf12-putd +.globl sort +.align 16 +.type sort,@function +sort: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +movl 24(%ebp),%edi +subl $1,%edi +movl %edi,24(%ebp) +pushl %edi +pushl $0 +movl 20(%ebp),%edi +movl %edi,xx +pushl %edi +call quick +addl $12,%esp +mov $0,%eax +.LC13: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf14: +.size sort,.Lf14-sort +.globl quick +.align 16 +.type quick,@function +quick: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +subl $4,%esp +movl 28(%ebp),%edi +cmpl %edi,24(%ebp) +jl .LC16 +mov $0,%eax +jmp .LC15 +.LC16: +pushl 28(%ebp) +pushl 24(%ebp) +pushl 20(%ebp) +call partition +addl $12,%esp +movl %eax,-4(%ebp) +movl -4(%ebp),%edi +subl $1,%edi +pushl %edi +pushl 24(%ebp) +pushl 20(%ebp) +call quick +addl $12,%esp +pushl 28(%ebp) +movl -4(%ebp),%edi +leal 1(%edi),%edi +pushl %edi +pushl 20(%ebp) +call quick +addl $12,%esp +mov $0,%eax +.LC15: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf18: +.size quick,.Lf18-quick +.globl partition +.align 16 +.type partition,@function +partition: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +subl $8,%esp +incl 28(%ebp) +movl 24(%ebp),%edi +movl %edi,-8(%ebp) +movl -8(%ebp),%edi +movl 20(%ebp),%esi +movl (%esi,%edi,4),%edi +movl %edi,-4(%ebp) +jmp .LC21 +.LC20: +incl 24(%ebp) +jmp .LC24 +.LC23: +incl 24(%ebp) +.LC24: +movl 24(%ebp),%edi +movl 20(%ebp),%esi +movl -4(%ebp),%ebx +cmpl %ebx,(%esi,%edi,4) +jl .LC23 +decl 28(%ebp) +jmp .LC27 +.LC26: +decl 28(%ebp) +.LC27: +movl 28(%ebp),%edi +movl 20(%ebp),%esi +movl -4(%ebp),%ebx +cmpl %ebx,(%esi,%edi,4) +jg .LC26 +movl 28(%ebp),%edi +cmpl %edi,24(%ebp) +jge .LC29 +movl 20(%ebp),%edi +movl 28(%ebp),%esi +leal (%edi,%esi,4),%esi +pushl %esi +movl 24(%ebp),%esi +leal (%edi,%esi,4),%edi +pushl %edi +call exchange +addl $8,%esp +.LC29: +.LC21: +movl 28(%ebp),%edi +cmpl %edi,24(%ebp) +jl .LC20 +movl 20(%ebp),%edi +movl 28(%ebp),%esi +leal (%edi,%esi,4),%esi +pushl %esi +movl -8(%ebp),%esi +leal (%edi,%esi,4),%edi +pushl %edi +call exchange +addl $8,%esp +movl 28(%ebp),%eax +.LC19: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf31: +.size partition,.Lf31-partition +.globl exchange +.align 16 +.type exchange,@function +exchange: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +subl $4,%esp +movl xx,%edi +mov $4,%esi +movl 24(%ebp),%ebx +subl %edi,%ebx +movl %ebx,%eax +movl %esi,%ecx +cdq +idivl %ecx +pushl %eax +movl 20(%ebp),%ebx +subl %edi,%ebx +movl %ebx,%eax +movl %esi,%ecx +cdq +idivl %ecx +pushl %eax +pushl $.LC33 +call printf +addl $12,%esp +movl 20(%ebp),%edi +movl (,%edi),%esi +movl %esi,-4(%ebp) +movl 24(%ebp),%esi +movl (,%esi),%esi +movl %esi,(,%edi) +movl 24(%ebp),%edi +movl -4(%ebp),%esi +movl %esi,(,%edi) +mov $0,%eax +.LC32: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf34: +.size exchange,.Lf34-exchange +.bss +.globl xx +.align 4 +.type xx,@object +.size xx,4 +.comm xx,4 +.data +.align 1 +.LC33: +.byte 101 +.byte 120 +.byte 99 +.byte 104 +.byte 97 +.byte 110 +.byte 103 +.byte 101 +.byte 40 +.byte 37 +.byte 100 +.byte 44 +.byte 37 +.byte 100 +.byte 41 +.byte 10 +.byte 0 +.text +.ident "LCC: 4.1" diff --git a/src/cmd/lccom/tst/x86-linux/spill.1bk b/src/cmd/lccom/tst/x86-linux/spill.1bk new file mode 100644 index 0000000..e69de29 diff --git a/src/cmd/lccom/tst/x86-linux/spill.2bk b/src/cmd/lccom/tst/x86-linux/spill.2bk new file mode 100644 index 0000000..afd73e2 --- /dev/null +++ b/src/cmd/lccom/tst/x86-linux/spill.2bk @@ -0,0 +1,6 @@ +tst/spill.c:1: warning: missing return value +tst/spill.c:3: warning: missing return value +tst/spill.c:5: warning: missing return value +tst/spill.c:7: warning: missing return value +tst/spill.c:9: warning: missing return value +tst/spill.c:17: warning: missing return value diff --git a/src/cmd/lccom/tst/x86-linux/spill.sbk b/src/cmd/lccom/tst/x86-linux/spill.sbk new file mode 100644 index 0000000..c66c3db --- /dev/null +++ b/src/cmd/lccom/tst/x86-linux/spill.sbk @@ -0,0 +1,286 @@ +.globl main +.text +.align 16 +.type main,@function +main: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +mov $0,%eax +.LC1: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf2: +.size main,.Lf2-main +.globl f +.align 16 +.type f,@function +f: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +call f +movl %eax,%edi +call f +leal (%eax,%edi),%edi +movl %edi,20(%ebp) +mov $0,%eax +.LC3: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf4: +.size f,.Lf4-f +.globl f2 +.align 16 +.type f2,@function +f2: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +subl $4,%esp +call f +movl %eax,%edi +cmpl $0,20(%ebp) +je .LC7 +call f +movl %eax,%esi +movl %esi,-4(%ebp) +jmp .LC8 +.LC7: +movl $1,-4(%ebp) +.LC8: +movl -4(%ebp),%esi +leal (%esi,%edi),%edi +movl %edi,20(%ebp) +mov $0,%eax +.LC5: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf9: +.size f2,.Lf9-f2 +.globl f3 +.align 16 +.type f3,@function +f3: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +subl $44,%esp +movl $0,-4(%ebp) +movl $0,-8(%ebp) +movl $0,-12(%ebp) +movl $0,-16(%ebp) +movl $0,-20(%ebp) +movl $0,-24(%ebp) +movl $0,-28(%ebp) +movl $0,-32(%ebp) +movl $0,-36(%ebp) +movl $0,-40(%ebp) +movl 24(%ebp),%edi +leal 4(%edi),%esi +movl %esi,24(%ebp) +cmpl $0,20(%ebp) +je .LC12 +call f +movl %eax,%esi +movl %esi,-44(%ebp) +jmp .LC13 +.LC12: +movl $0,-44(%ebp) +.LC13: +movl -44(%ebp),%esi +movl %esi,(,%edi) +mov $0,%eax +.LC10: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf14: +.size f3,.Lf14-f3 +.globl f4 +.align 16 +.type f4,@function +f4: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +subl $52,%esp +movl $0,-4(%ebp) +movl $0,-8(%ebp) +movl $0,-12(%ebp) +movl $0,-16(%ebp) +movl $0,-20(%ebp) +movl $0,-24(%ebp) +movl i,%edi +leal (,%edi,8),%esi +fldl a(%esi) +fstpl -36(%ebp) +fldl b(%esi) +fstpl -44(%ebp) +fldl -36(%ebp) +faddl -44(%ebp) +fldl .LC19 +fcompp +fstsw %ax +sahf +jp 1f +je .LC17 +1: +cmpl $0,%edi +je .LC17 +fldl -36(%ebp) +fsubl -44(%ebp) +fldl .LC19 +fcompp +fstsw %ax +sahf +jp 1f +je .LC17 +1: +movl $1,-28(%ebp) +jmp .LC18 +.LC17: +movl $0,-28(%ebp) +.LC18: +movl -28(%ebp),%edi +movl %edi,i +mov $0,%eax +.LC15: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf20: +.size f4,.Lf20-f4 +.globl f5 +.align 16 +.type f5,@function +f5: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +movl k,%edi +movl m,%esi +movl A,%ebx +movl %edi,%edx +imull %esi,%edx +leal (%ebx,%edx,8),%edx +movl j,%ecx +movl %ecx,%eax +imull %esi,%eax +leal (%ebx,%eax,8),%esi +movl n,%ebx +movl B,%eax +imull %ebx,%edi +leal (%eax,%edi,8),%edi +imull %ebx,%ecx +leal (%eax,%ecx,8),%ebx +fldl (,%edx) +fmull (,%esi) +fldl (,%edi) +fmull (,%ebx) +faddp %st,%st(1) +fstpl x +fldl (,%edx) +fmull (,%ebx) +fldl (,%edi) +fmull (,%esi) +fsubrp %st,%st(1) +fstpl x +mov $0,%eax +.LC21: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf22: +.size f5,.Lf22-f5 +.bss +.globl x +.align 4 +.type x,@object +.size x,8 +.comm x,8 +.globl B +.align 4 +.type B,@object +.size B,4 +.comm B,4 +.globl A +.align 4 +.type A,@object +.size A,4 +.comm A,4 +.globl n +.align 4 +.type n,@object +.size n,4 +.comm n,4 +.globl m +.align 4 +.type m,@object +.size m,4 +.comm m,4 +.globl k +.align 4 +.type k,@object +.size k,4 +.comm k,4 +.globl j +.align 4 +.type j,@object +.size j,4 +.comm j,4 +.globl i +.align 4 +.type i,@object +.size i,4 +.comm i,4 +.globl b +.align 4 +.type b,@object +.size b,80 +.comm b,80 +.globl a +.align 4 +.type a,@object +.size a,80 +.comm a,80 +.data +.align 4 +.LC19: +.long 0 +.long 0 +.text +.ident "LCC: 4.1" diff --git a/src/cmd/lccom/tst/x86-linux/stdarg.1bk b/src/cmd/lccom/tst/x86-linux/stdarg.1bk new file mode 100644 index 0000000..e973176 --- /dev/null +++ b/src/cmd/lccom/tst/x86-linux/stdarg.1bk @@ -0,0 +1,6 @@ +test 1 +test 2 +test 3 +test 4 +test 5.000000 +{1 2 3 4} {1 2 3 4} {1 2 3 4} {1 2 3 4} {1 2 3 4} {1 2 3 4} diff --git a/src/cmd/lccom/tst/x86-linux/stdarg.2bk b/src/cmd/lccom/tst/x86-linux/stdarg.2bk new file mode 100644 index 0000000..2b3f417 --- /dev/null +++ b/src/cmd/lccom/tst/x86-linux/stdarg.2bk @@ -0,0 +1 @@ +tst/stdarg.c:51: warning: missing return value diff --git a/src/cmd/lccom/tst/x86-linux/stdarg.h b/src/cmd/lccom/tst/x86-linux/stdarg.h new file mode 100644 index 0000000..5107bcd --- /dev/null +++ b/src/cmd/lccom/tst/x86-linux/stdarg.h @@ -0,0 +1,26 @@ +#ifndef __STDARG +#define __STDARG + +#if !defined(_VA_LIST) && !defined(__VA_LIST_DEFINED) +#define _VA_LIST +#define _VA_LIST_DEFINED +typedef char *__va_list; +#endif +static float __va_arg_tmp; +typedef __va_list va_list; + +#define va_start(list, start) ((void)((list) = (sizeof(start)<4 ? \ + (char *)((int *)&(start)+1) : (char *)(&(start)+1)))) +#define __va_arg(list, mode, n) (\ + __typecode(mode)==1 && sizeof(mode)==4 ? \ + (__va_arg_tmp = *(double *)(&(list += ((sizeof(double)+n)&~n))[-(int)((sizeof(double)+n)&~n)]), \ + *(mode *)&__va_arg_tmp) : \ + *(mode *)(&(list += ((sizeof(mode)+n)&~n))[-(int)((sizeof(mode)+n)&~n)])) +#define _bigendian_va_arg(list, mode, n) (\ + sizeof(mode)==1 ? *(mode *)(&(list += 4)[-1]) : \ + sizeof(mode)==2 ? *(mode *)(&(list += 4)[-2]) : __va_arg(list, mode, n)) +#define _littleendian_va_arg(list, mode, n) __va_arg(list, mode, n) +#define va_end(list) ((void)0) +#define va_arg(list, mode) _littleendian_va_arg(list, mode, 3U) +typedef void *__gnuc_va_list; +#endif diff --git a/src/cmd/lccom/tst/x86-linux/stdarg.sbk b/src/cmd/lccom/tst/x86-linux/stdarg.sbk new file mode 100644 index 0000000..8210428 --- /dev/null +++ b/src/cmd/lccom/tst/x86-linux/stdarg.sbk @@ -0,0 +1,400 @@ +.data +.globl x +.align 4 +.type x,@object +.size x,16 +x: +.long 1 +.long 2 +.long 3 +.long 4 +.globl main +.text +.align 16 +.type main,@function +main: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +subl $8,%esp +pushl $.LC2 +call print +addl $4,%esp +pushl $.LC4 +pushl $.LC3 +call print +addl $8,%esp +pushl $10 +pushl $3 +pushl $.LC5 +call print +addl $12,%esp +pushl $10 +pushl $4 +pushl $.LC8 +pushl $.LC7 +pushl $.LC6 +call print +addl $20,%esp +pushl $10 +fldl .LC10 +subl $8,%esp +fstpl (%esp) +pushl $.LC8 +pushl $.LC7 +pushl $.LC9 +call print +addl $24,%esp +leal x,%edi +movl %edi,-8(%ebp) +movl %edi,%esi +movl %esi,-4(%ebp) +subl $16,%esp +movl %esp,%edi +movl $16,%ecx +rep +movsb +movl -8(%ebp),%edi +movl %edi,%esi +subl $16,%esp +movl %esp,%edi +movl $16,%ecx +rep +movsb +movl -8(%ebp),%edi +movl %edi,%esi +subl $16,%esp +movl %esp,%edi +movl $16,%ecx +rep +movsb +movl -8(%ebp),%edi +movl %edi,%esi +subl $16,%esp +movl %esp,%edi +movl $16,%ecx +rep +movsb +movl -8(%ebp),%edi +movl %edi,%esi +subl $16,%esp +movl %esp,%edi +movl $16,%ecx +rep +movsb +movl -8(%ebp),%edi +movl %edi,%esi +subl $16,%esp +movl %esp,%edi +movl $16,%ecx +rep +movsb +pushl $.LC11 +call print +addl $100,%esp +mov $0,%eax +.LC1: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf12: +.size main,.Lf12-main +.globl print +.align 16 +.type print,@function +print: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +subl $28,%esp +leal 24(%ebp),%edi +movl %edi,-4(%ebp) +jmp .LC19 +.LC16: +movl 20(%ebp),%edi +movsbl (,%edi),%edi +cmpl $37,%edi +jne .LC20 +movl 20(%ebp),%edi +leal 1(%edi),%edi +movl %edi,20(%ebp) +movsbl (,%edi),%edi +movl %edi,-8(%ebp) +movl -8(%ebp),%edi +cmpl $115,%edi +je .LC36 +cmpl $115,%edi +jg .LC41 +.LC40: +movl -8(%ebp),%edi +cmpl $98,%edi +jl .LC22 +cmpl $102,%edi +jg .LC22 +jmp *.LC42-392(,%edi,4) +.data +.align 4 +.LC42: +.long .LC25 +.long .LC30 +.long .LC32 +.long .LC22 +.long .LC38 +.text +.LC41: +cmpl $119,-8(%ebp) +je .LC34 +jmp .LC22 +.LC25: +movl -4(%ebp),%edi +leal 16(%edi),%edi +movl %edi,-28(%ebp) +movl %edi,-4(%ebp) +leal -24(%ebp),%edi +movl -28(%ebp),%esi +leal -16(%esi),%esi +movl $16,%ecx +rep +movsb +pushl -12(%ebp) +pushl -16(%ebp) +pushl -20(%ebp) +pushl -24(%ebp) +pushl $.LC26 +call printf +addl $20,%esp +jmp .LC21 +.LC30: +movl -4(%ebp),%edi +leal 4(%edi),%edi +movl %edi,-4(%ebp) +movsbl -4(%edi),%edi +pushl %edi +pushl $.LC31 +call printf +addl $8,%esp +jmp .LC21 +.LC32: +movl -4(%ebp),%edi +leal 4(%edi),%edi +movl %edi,-4(%ebp) +pushl -4(%edi) +pushl $.LC33 +call printf +addl $8,%esp +jmp .LC21 +.LC34: +movl -4(%ebp),%edi +leal 4(%edi),%edi +movl %edi,-4(%ebp) +movswl -4(%edi),%edi +pushl %edi +pushl $.LC35 +call printf +addl $8,%esp +jmp .LC21 +.LC36: +movl -4(%ebp),%edi +leal 4(%edi),%edi +movl %edi,-4(%ebp) +pushl -4(%edi) +pushl $.LC37 +call printf +addl $8,%esp +jmp .LC21 +.LC38: +movl -4(%ebp),%edi +leal 8(%edi),%edi +movl %edi,-4(%ebp) +fldl -8(%edi) +subl $8,%esp +fstpl (%esp) +pushl $.LC39 +call printf +addl $12,%esp +jmp .LC21 +.LC22: +movl 20(%ebp),%edi +movsbl (,%edi),%edi +pushl %edi +pushl $.LC31 +call printf +addl $8,%esp +jmp .LC21 +.LC20: +movl 20(%ebp),%edi +movsbl (,%edi),%edi +pushl %edi +pushl $.LC31 +call printf +addl $8,%esp +.LC21: +.LC17: +incl 20(%ebp) +.LC19: +movl 20(%ebp),%edi +movsbl (,%edi),%edi +cmpl $0,%edi +jne .LC16 +mov $0,%eax +.LC13: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf44: +.size print,.Lf44-print +.bss +.align 4 +.type __va_arg_tmp,@object +.size __va_arg_tmp,4 +.lcomm __va_arg_tmp,4 +.data +.align 1 +.LC39: +.byte 37 +.byte 102 +.byte 0 +.align 1 +.LC37: +.byte 37 +.byte 115 +.byte 0 +.align 1 +.LC35: +.byte 37 +.byte 120 +.byte 0 +.align 1 +.LC33: +.byte 37 +.byte 100 +.byte 0 +.align 1 +.LC31: +.byte 37 +.byte 99 +.byte 0 +.align 1 +.LC26: +.byte 123 +.byte 37 +.byte 100 +.byte 32 +.byte 37 +.byte 100 +.byte 32 +.byte 37 +.byte 100 +.byte 32 +.byte 37 +.byte 100 +.byte 125 +.byte 0 +.align 1 +.LC11: +.byte 37 +.byte 98 +.byte 32 +.byte 37 +.byte 98 +.byte 32 +.byte 37 +.byte 98 +.byte 32 +.byte 37 +.byte 98 +.byte 32 +.byte 37 +.byte 98 +.byte 32 +.byte 37 +.byte 98 +.byte 10 +.byte 0 +.align 4 +.LC10: +.long 0 +.long 1075052544 +.align 1 +.LC9: +.byte 37 +.byte 115 +.byte 37 +.byte 115 +.byte 32 +.byte 37 +.byte 102 +.byte 37 +.byte 99 +.byte 0 +.align 1 +.LC8: +.byte 115 +.byte 116 +.byte 0 +.align 1 +.LC7: +.byte 116 +.byte 101 +.byte 0 +.align 1 +.LC6: +.byte 37 +.byte 115 +.byte 37 +.byte 115 +.byte 32 +.byte 37 +.byte 119 +.byte 37 +.byte 99 +.byte 0 +.align 1 +.LC5: +.byte 116 +.byte 101 +.byte 115 +.byte 116 +.byte 32 +.byte 37 +.byte 100 +.byte 37 +.byte 99 +.byte 0 +.align 1 +.LC4: +.byte 50 +.byte 0 +.align 1 +.LC3: +.byte 116 +.byte 101 +.byte 115 +.byte 116 +.byte 32 +.byte 37 +.byte 115 +.byte 10 +.byte 0 +.align 1 +.LC2: +.byte 116 +.byte 101 +.byte 115 +.byte 116 +.byte 32 +.byte 49 +.byte 10 +.byte 0 +.text +.ident "LCC: 4.1" diff --git a/src/cmd/lccom/tst/x86-linux/struct.1bk b/src/cmd/lccom/tst/x86-linux/struct.1bk new file mode 100644 index 0000000..807f3da --- /dev/null +++ b/src/cmd/lccom/tst/x86-linux/struct.1bk @@ -0,0 +1,5 @@ +(-1,-1) is not within [10,10; 310,310] +(1,1) is not within [10,10; 310,310] +(20,300) is within [10,10; 310,310] +(500,400) is not within [10,10; 310,310] +ab diff --git a/src/cmd/lccom/tst/x86-linux/struct.2bk b/src/cmd/lccom/tst/x86-linux/struct.2bk new file mode 100644 index 0000000..cb0fbd0 --- /dev/null +++ b/src/cmd/lccom/tst/x86-linux/struct.2bk @@ -0,0 +1,2 @@ +tst/struct.c:49: warning: missing return value +tst/struct.c:68: warning: missing return value diff --git a/src/cmd/lccom/tst/x86-linux/struct.sbk b/src/cmd/lccom/tst/x86-linux/struct.sbk new file mode 100644 index 0000000..ebfb5b4 --- /dev/null +++ b/src/cmd/lccom/tst/x86-linux/struct.sbk @@ -0,0 +1,476 @@ +.globl addpoint +.text +.align 16 +.type addpoint,@function +addpoint: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +movl 32(%ebp),%edi +addl %edi,24(%ebp) +movl 36(%ebp),%edi +addl %edi,28(%ebp) +movl 20(%ebp),%edi +leal 24(%ebp),%esi +movl $8,%ecx +rep +movsb +.LC1: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf5: +.size addpoint,.Lf5-addpoint +.globl canonrect +.align 16 +.type canonrect,@function +canonrect: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +subl $32,%esp +movl 32(%ebp),%edi +cmpl %edi,24(%ebp) +jge .LC11 +movl 24(%ebp),%edi +movl %edi,-20(%ebp) +jmp .LC12 +.LC11: +movl 32(%ebp),%edi +movl %edi,-20(%ebp) +.LC12: +movl -20(%ebp),%edi +movl %edi,-16(%ebp) +movl 36(%ebp),%edi +cmpl %edi,28(%ebp) +jge .LC21 +movl 28(%ebp),%edi +movl %edi,-24(%ebp) +jmp .LC22 +.LC21: +movl 36(%ebp),%edi +movl %edi,-24(%ebp) +.LC22: +movl -24(%ebp),%edi +movl %edi,-12(%ebp) +movl 32(%ebp),%edi +cmpl %edi,24(%ebp) +jle .LC27 +movl 24(%ebp),%edi +movl %edi,-28(%ebp) +jmp .LC28 +.LC27: +movl 32(%ebp),%edi +movl %edi,-28(%ebp) +.LC28: +movl -28(%ebp),%edi +movl %edi,-8(%ebp) +movl 36(%ebp),%edi +cmpl %edi,28(%ebp) +jle .LC38 +movl 28(%ebp),%edi +movl %edi,-32(%ebp) +jmp .LC39 +.LC38: +movl 36(%ebp),%edi +movl %edi,-32(%ebp) +.LC39: +movl -32(%ebp),%edi +movl %edi,-4(%ebp) +movl 20(%ebp),%edi +leal -16(%ebp),%esi +movl $16,%ecx +rep +movsb +.LC6: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf40: +.size canonrect,.Lf40-canonrect +.globl makepoint +.align 16 +.type makepoint,@function +makepoint: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +subl $8,%esp +movl 24(%ebp),%edi +movl %edi,-8(%ebp) +movl 28(%ebp),%edi +movl %edi,-4(%ebp) +movl 20(%ebp),%edi +leal -8(%ebp),%esi +movl $8,%ecx +rep +movsb +.LC41: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf44: +.size makepoint,.Lf44-makepoint +.globl makerect +.align 16 +.type makerect,@function +makerect: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +subl $16,%esp +leal -16(%ebp),%edi +leal 24(%ebp),%esi +movl $8,%ecx +rep +movsb +leal -8(%ebp),%edi +leal 32(%ebp),%esi +movl $8,%ecx +rep +movsb +leal -16(%ebp),%esi +subl $16,%esp +movl %esp,%edi +movl $16,%ecx +rep +movsb +pushl 20(%ebp) +call canonrect +addl $20,%esp +.LC45: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf48: +.size makerect,.Lf48-makerect +.globl ptinrect +.align 16 +.type ptinrect,@function +ptinrect: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +subl $4,%esp +movl 20(%ebp),%edi +cmpl 28(%ebp),%edi +jl .LC57 +cmpl 36(%ebp),%edi +jge .LC57 +movl 32(%ebp),%edi +cmpl %edi,24(%ebp) +jl .LC57 +movl 40(%ebp),%edi +cmpl %edi,24(%ebp) +jge .LC57 +movl $1,-4(%ebp) +jmp .LC58 +.LC57: +movl $0,-4(%ebp) +.LC58: +movl -4(%ebp),%eax +.LC49: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf59: +.size ptinrect,.Lf59-ptinrect +.data +.globl y +.align 1 +.type y,@object +.size y,3 +y: +.byte 97 +.byte 98 +.byte 0 +.globl odd +.text +.align 16 +.type odd,@function +odd: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +subl $4,%esp +leal -4(%ebp),%edi +leal 20(%ebp),%esi +movl $3,%ecx +rep +movsb +leal -4(%ebp),%edi +pushl %edi +pushl $.LC61 +call printf +addl $8,%esp +mov $0,%eax +.LC60: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf62: +.size odd,.Lf62-odd +.data +.align 4 +.LC64: +.long 0 +.long 0 +.align 4 +.LC65: +.long 320 +.long 320 +.align 4 +.LC66: +.long -1 +.long -1 +.long 1 +.long 1 +.long 20 +.long 300 +.long 500 +.long 400 +.globl main +.text +.align 16 +.type main,@function +main: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +subl $108,%esp +leal -68(%ebp),%edi +leal .LC64,%esi +movl $8,%ecx +rep +movsb +leal -76(%ebp),%edi +leal .LC65,%esi +movl $8,%ecx +rep +movsb +leal -36(%ebp),%edi +leal .LC66,%esi +movl $32,%ecx +rep +movsb +pushl $-10 +pushl $-10 +leal -84(%ebp),%edi +pushl %edi +call makepoint +addl $12,%esp +leal -84(%ebp),%esi +subl $8,%esp +movl %esp,%edi +movl $8,%ecx +rep +movsb +leal -76(%ebp),%esi +subl $8,%esp +movl %esp,%edi +movl $8,%ecx +rep +movsb +leal -92(%ebp),%edi +pushl %edi +call addpoint +addl $20,%esp +pushl $10 +pushl $10 +leal -100(%ebp),%edi +pushl %edi +call makepoint +addl $12,%esp +leal -100(%ebp),%esi +subl $8,%esp +movl %esp,%edi +movl $8,%ecx +rep +movsb +leal -68(%ebp),%esi +subl $8,%esp +movl %esp,%edi +movl $8,%ecx +rep +movsb +leal -108(%ebp),%edi +pushl %edi +call addpoint +addl $20,%esp +leal -108(%ebp),%esi +subl $8,%esp +movl %esp,%edi +movl $8,%ecx +rep +movsb +leal -92(%ebp),%esi +subl $8,%esp +movl %esp,%edi +movl $8,%ecx +rep +movsb +leal -52(%ebp),%edi +pushl %edi +call makerect +addl $20,%esp +movl $0,-4(%ebp) +jmp .LC70 +.LC67: +movl -4(%ebp),%edi +leal (,%edi,8),%edi +leal -32(%ebp),%esi +pushl (%esi,%edi) +leal -36(%ebp),%esi +pushl (%esi,%edi) +leal -60(%ebp),%edi +pushl %edi +call makepoint +addl $12,%esp +pushl -56(%ebp) +movl -4(%ebp),%edi +leal -36(%ebp),%esi +pushl (%esi,%edi,8) +pushl $.LC71 +call printf +addl $12,%esp +leal -52(%ebp),%esi +subl $16,%esp +movl %esp,%edi +movl $16,%ecx +rep +movsb +leal -60(%ebp),%esi +subl $8,%esp +movl %esp,%edi +movl $8,%ecx +rep +movsb +call ptinrect +addl $24,%esp +cmpl $0,%eax +jne .LC74 +pushl $.LC76 +call printf +addl $4,%esp +.LC74: +pushl -40(%ebp) +pushl -44(%ebp) +pushl -48(%ebp) +pushl -52(%ebp) +pushl $.LC77 +call printf +addl $20,%esp +.LC68: +incl -4(%ebp) +.LC70: +movl -4(%ebp),%edi +cmpl $4,%edi +jb .LC67 +leal y,%esi +subl $4,%esp +movl %esp,%edi +movl $3,%ecx +rep +movsb +call odd +addl $3,%esp +pushl $0 +call exit +addl $4,%esp +mov $0,%eax +.LC63: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf82: +.size main,.Lf82-main +.data +.align 1 +.LC77: +.byte 119 +.byte 105 +.byte 116 +.byte 104 +.byte 105 +.byte 110 +.byte 32 +.byte 91 +.byte 37 +.byte 100 +.byte 44 +.byte 37 +.byte 100 +.byte 59 +.byte 32 +.byte 37 +.byte 100 +.byte 44 +.byte 37 +.byte 100 +.byte 93 +.byte 10 +.byte 0 +.align 1 +.LC76: +.byte 110 +.byte 111 +.byte 116 +.byte 32 +.byte 0 +.align 1 +.LC71: +.byte 40 +.byte 37 +.byte 100 +.byte 44 +.byte 37 +.byte 100 +.byte 41 +.byte 32 +.byte 105 +.byte 115 +.byte 32 +.byte 0 +.align 1 +.LC61: +.byte 37 +.byte 115 +.byte 10 +.byte 0 +.text +.ident "LCC: 4.1" diff --git a/src/cmd/lccom/tst/x86-linux/switch.1bk b/src/cmd/lccom/tst/x86-linux/switch.1bk new file mode 100644 index 0000000..de46a73 --- /dev/null +++ b/src/cmd/lccom/tst/x86-linux/switch.1bk @@ -0,0 +1,76 @@ +b = 0x8 +f = 0xc +n = 0xa +r = 0xd +t = 0x9 +v = 0xb +x = 0x78 +f: +x = 0 +x = 1 +x = 2 +x = 2 +x = 2 +x = 2 +x = 2 +x = 7 +x = 8 +x = 9 +x = 9 +x = 9 +x = 9 +x = 9 +x = 9 +x = 9 +x = 16 +x = 17 +x = 18 +x = 19 +x = 20 +g: +1 1 +1 2 +2 3 +2 4 +2 5 +3 6 +d 6 +3 7 +d 7 +3 8 +d 8 +d 9 +d 10 +h: +i = 8 +i = 16 +i = 120 +i = 128 +i = 248 +i = 264 +i = 272 +i = 280 +i = 288 +i = 296 +i = 304 +i = 312 +488 defaults +x = 0x1000000 +x = 0x2000000 +x = 0x3000000 +x = 0x4000000 +x = 0x5000000 +x = 0x6000000 (default) +x = 0x7000000 (default) +0 +1 +2 +3 +4 +5 +0 +1 +2 +3 +4 +5 diff --git a/src/cmd/lccom/tst/x86-linux/switch.2bk b/src/cmd/lccom/tst/x86-linux/switch.2bk new file mode 100644 index 0000000..709b419 --- /dev/null +++ b/src/cmd/lccom/tst/x86-linux/switch.2bk @@ -0,0 +1,5 @@ +tst/switch.c:55: warning: missing return value +tst/switch.c:73: warning: missing return value +tst/switch.c:97: warning: missing return value +tst/switch.c:112: warning: missing return value +tst/switch.c:137: warning: missing return value diff --git a/src/cmd/lccom/tst/x86-linux/switch.sbk b/src/cmd/lccom/tst/x86-linux/switch.sbk new file mode 100644 index 0000000..4ecdc6c --- /dev/null +++ b/src/cmd/lccom/tst/x86-linux/switch.sbk @@ -0,0 +1,899 @@ +.globl main +.text +.align 16 +.type main,@function +main: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +subl $8,%esp +leal .LC6,%edi +movl %edi,-4(%ebp) +jmp .LC5 +.LC2: +movl -4(%ebp),%edi +movsbl (,%edi),%edi +pushl %edi +call backslash +addl $4,%esp +pushl %eax +movl -4(%ebp),%edi +movsbl (,%edi),%edi +pushl %edi +pushl $.LC7 +call printf +addl $12,%esp +.LC3: +incl -4(%ebp) +.LC5: +movl -4(%ebp),%edi +movsbl (,%edi),%edi +cmpl $0,%edi +jne .LC2 +call f +call g +call h +movl $16777216,-8(%ebp) +jmp .LC11 +.LC8: +pushl -8(%ebp) +call big +addl $4,%esp +.LC9: +addl $16777216,-8(%ebp) +.LC11: +movl -8(%ebp),%edi +andl $117440512,%edi +cmpl $0,%edi +jne .LC8 +call limit +mov $0,%eax +.LC1: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf12: +.size main,.Lf12-main +.globl backslash +.align 16 +.type backslash,@function +backslash: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +movl 20(%ebp),%edi +cmpl $102,%edi +je .LC17 +cmpl $102,%edi +jg .LC23 +.LC22: +cmpl $98,20(%ebp) +je .LC16 +jmp .LC14 +.LC23: +movl 20(%ebp),%edi +cmpl $110,%edi +je .LC18 +cmpl $110,%edi +jl .LC14 +.LC24: +movl 20(%ebp),%edi +cmpl $114,%edi +je .LC19 +cmpl $116,%edi +je .LC20 +cmpl $118,%edi +je .LC21 +jmp .LC14 +.LC16: +mov $8,%eax +jmp .LC13 +.LC17: +mov $12,%eax +jmp .LC13 +.LC18: +mov $10,%eax +jmp .LC13 +.LC19: +mov $13,%eax +jmp .LC13 +.LC20: +mov $9,%eax +jmp .LC13 +.LC21: +mov $11,%eax +jmp .LC13 +.LC14: +movl 20(%ebp),%eax +.LC13: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf25: +.size backslash,.Lf25-backslash +.globl f +.align 16 +.type f,@function +f: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +subl $12,%esp +movl $0,-8(%ebp) +pushl $.LC27 +call printf +addl $4,%esp +movl $0,-4(%ebp) +.LC28: +movl -4(%ebp),%edi +movl %edi,-12(%ebp) +movl -4(%ebp),%edi +cmpl $1,%edi +jl .LC32 +cmpl $20,%edi +jg .LC32 +jmp *.LC44-4(,%edi,4) +.data +.align 4 +.LC44: +.long .LC34 +.long .LC35 +.long .LC32 +.long .LC32 +.long .LC32 +.long .LC32 +.long .LC36 +.long .LC37 +.long .LC38 +.long .LC32 +.long .LC32 +.long .LC32 +.long .LC32 +.long .LC32 +.long .LC32 +.long .LC39 +.long .LC40 +.long .LC41 +.long .LC42 +.long .LC43 +.text +.LC34: +movl -4(%ebp),%edi +movl %edi,-8(%ebp) +jmp .LC33 +.LC35: +movl -4(%ebp),%edi +movl %edi,-8(%ebp) +jmp .LC33 +.LC36: +movl -4(%ebp),%edi +movl %edi,-8(%ebp) +jmp .LC33 +.LC37: +movl -4(%ebp),%edi +movl %edi,-8(%ebp) +jmp .LC33 +.LC38: +movl -4(%ebp),%edi +movl %edi,-8(%ebp) +jmp .LC33 +.LC39: +movl -4(%ebp),%edi +movl %edi,-8(%ebp) +jmp .LC33 +.LC40: +movl -4(%ebp),%edi +movl %edi,-8(%ebp) +jmp .LC33 +.LC41: +movl -4(%ebp),%edi +movl %edi,-8(%ebp) +jmp .LC33 +.LC42: +movl -4(%ebp),%edi +movl %edi,-8(%ebp) +jmp .LC33 +.LC43: +movl -4(%ebp),%edi +movl %edi,-8(%ebp) +.LC32: +.LC33: +pushl -8(%ebp) +pushl $.LC46 +call printf +addl $8,%esp +.LC29: +incl -4(%ebp) +cmpl $20,-4(%ebp) +jle .LC28 +mov $0,%eax +.LC26: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf47: +.size f,.Lf47-f +.globl g +.align 16 +.type g,@function +g: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +subl $4,%esp +pushl $.LC49 +call printf +addl $4,%esp +movl $1,-4(%ebp) +.LC50: +movl -4(%ebp),%edi +cmpl $1001,%edi +jl .LC67 +cmpl $1004,%edi +jg .LC68 +jmp *.LC69-4004(,%edi,4) +.data +.align 4 +.LC69: +.long .LC63 +.long .LC63 +.long .LC63 +.long .LC63 +.text +.LC67: +movl -4(%ebp),%edi +cmpl $1,%edi +jl .LC54 +cmpl $8,%edi +jg .LC54 +jmp *.LC71-4(,%edi,4) +.data +.align 4 +.LC71: +.long .LC56 +.long .LC56 +.long .LC58 +.long .LC58 +.long .LC58 +.long .LC60 +.long .LC60 +.long .LC60 +.text +.LC68: +movl -4(%ebp),%edi +cmpl $3001,%edi +jl .LC54 +cmpl $3004,%edi +jg .LC54 +jmp *.LC73-12004(,%edi,4) +.data +.align 4 +.LC73: +.long .LC65 +.long .LC65 +.long .LC65 +.long .LC65 +.text +.LC56: +pushl -4(%ebp) +pushl $.LC57 +call printf +addl $8,%esp +jmp .LC55 +.LC58: +pushl -4(%ebp) +pushl $.LC59 +call printf +addl $8,%esp +jmp .LC55 +.LC60: +pushl -4(%ebp) +pushl $.LC61 +call printf +addl $8,%esp +.LC54: +pushl -4(%ebp) +pushl $.LC62 +call printf +addl $8,%esp +jmp .LC55 +.LC63: +pushl -4(%ebp) +pushl $.LC64 +call printf +addl $8,%esp +jmp .LC55 +.LC65: +pushl -4(%ebp) +pushl $.LC66 +call printf +addl $8,%esp +.LC55: +.LC51: +incl -4(%ebp) +cmpl $10,-4(%ebp) +jle .LC50 +mov $0,%eax +.LC48: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf75: +.size g,.Lf75-g +.globl h +.align 16 +.type h,@function +h: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +subl $8,%esp +movl $0,-8(%ebp) +pushl $.LC77 +call printf +addl $4,%esp +movl $1,-4(%ebp) +.LC78: +movl -4(%ebp),%edi +cmpl $264,%edi +je .LC90 +cmpl $264,%edi +jg .LC98 +.LC97: +movl -4(%ebp),%edi +cmpl $120,%edi +je .LC88 +cmpl $120,%edi +jg .LC100 +.LC99: +movl -4(%ebp),%edi +cmpl $8,%edi +je .LC87 +cmpl $8,%edi +jl .LC82 +.LC101: +cmpl $16,-4(%ebp) +je .LC86 +jmp .LC82 +.LC100: +movl -4(%ebp),%edi +cmpl $128,%edi +je .LC84 +cmpl $128,%edi +jl .LC82 +.LC102: +cmpl $248,-4(%ebp) +je .LC91 +jmp .LC82 +.LC98: +movl -4(%ebp),%edi +cmpl $288,%edi +je .LC95 +cmpl $288,%edi +jg .LC104 +.LC103: +movl -4(%ebp),%edi +cmpl $272,%edi +je .LC92 +cmpl $272,%edi +jl .LC82 +.LC105: +cmpl $280,-4(%ebp) +je .LC89 +jmp .LC82 +.LC104: +movl -4(%ebp),%edi +cmpl $304,%edi +je .LC93 +cmpl $304,%edi +jg .LC107 +.LC106: +cmpl $296,-4(%ebp) +je .LC94 +jmp .LC82 +.LC107: +cmpl $312,-4(%ebp) +je .LC96 +jmp .LC82 +.LC82: +incl -8(%ebp) +jmp .LC79 +.LC84: +pushl -4(%ebp) +pushl $.LC85 +call printf +addl $8,%esp +jmp .LC83 +.LC86: +pushl -4(%ebp) +pushl $.LC85 +call printf +addl $8,%esp +jmp .LC83 +.LC87: +pushl -4(%ebp) +pushl $.LC85 +call printf +addl $8,%esp +jmp .LC83 +.LC88: +pushl -4(%ebp) +pushl $.LC85 +call printf +addl $8,%esp +jmp .LC83 +.LC89: +pushl -4(%ebp) +pushl $.LC85 +call printf +addl $8,%esp +jmp .LC83 +.LC90: +pushl -4(%ebp) +pushl $.LC85 +call printf +addl $8,%esp +jmp .LC83 +.LC91: +pushl -4(%ebp) +pushl $.LC85 +call printf +addl $8,%esp +jmp .LC83 +.LC92: +pushl -4(%ebp) +pushl $.LC85 +call printf +addl $8,%esp +jmp .LC83 +.LC93: +pushl -4(%ebp) +pushl $.LC85 +call printf +addl $8,%esp +jmp .LC83 +.LC94: +pushl -4(%ebp) +pushl $.LC85 +call printf +addl $8,%esp +jmp .LC83 +.LC95: +pushl -4(%ebp) +pushl $.LC85 +call printf +addl $8,%esp +jmp .LC83 +.LC96: +pushl -4(%ebp) +pushl $.LC85 +call printf +addl $8,%esp +.LC83: +.LC79: +incl -4(%ebp) +cmpl $500,-4(%ebp) +jle .LC78 +pushl -8(%ebp) +pushl $.LC108 +call printf +addl $8,%esp +mov $0,%eax +.LC76: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf109: +.size h,.Lf109-h +.globl big +.align 16 +.type big,@function +big: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +subl $4,%esp +movl 20(%ebp),%edi +andl $0x6000000,%edi +movl %edi,-4(%ebp) +movl -4(%ebp),%edi +cmpl $33554432,%edi +je .LC116 +cmpl $33554432,%edi +jg .LC120 +.LC119: +movl -4(%ebp),%edi +cmpl $-2,%edi +je .LC114 +cmpl $-1,%edi +je .LC114 +cmpl $0,%edi +je .LC114 +jmp .LC111 +.LC120: +movl -4(%ebp),%edi +cmpl $67108864,%edi +je .LC117 +jmp .LC111 +.LC114: +pushl 20(%ebp) +pushl $.LC115 +call printf +addl $8,%esp +jmp .LC112 +.LC116: +pushl 20(%ebp) +pushl $.LC115 +call printf +addl $8,%esp +jmp .LC112 +.LC117: +pushl 20(%ebp) +pushl $.LC115 +call printf +addl $8,%esp +jmp .LC112 +.LC111: +pushl 20(%ebp) +pushl $.LC118 +call printf +addl $8,%esp +.LC112: +mov $0,%eax +.LC110: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf121: +.size big,.Lf121-big +.globl limit +.align 16 +.type limit,@function +limit: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +subl $4,%esp +movl $-2147483648,-4(%ebp) +.LC123: +movl -4(%ebp),%edi +mov $-2147483648,%esi +cmpl $-2147483648,%edi +jl .LC127 +cmpl $-2147483644,%edi +jg .LC127 +leal (,%edi,4),%edi +leal (,%esi,4),%esi +subl %esi,%edi +jmp *.LC140(%edi) +.data +.align 4 +.LC140: +.long .LC129 +.long .LC131 +.long .LC133 +.long .LC135 +.long .LC137 +.text +.LC129: +pushl $.LC130 +call printf +addl $4,%esp +jmp .LC128 +.LC131: +pushl $.LC132 +call printf +addl $4,%esp +jmp .LC128 +.LC133: +pushl $.LC134 +call printf +addl $4,%esp +jmp .LC128 +.LC135: +pushl $.LC136 +call printf +addl $4,%esp +jmp .LC128 +.LC137: +pushl $.LC138 +call printf +addl $4,%esp +jmp .LC128 +.LC127: +pushl $.LC139 +call printf +addl $4,%esp +.LC128: +.LC124: +incl -4(%ebp) +cmpl $-2147483643,-4(%ebp) +jle .LC123 +movl $2147483647,-4(%ebp) +.LC141: +movl -4(%ebp),%edi +mov $2147483643,%esi +cmpl $2147483643,%edi +jl .LC145 +cmpl $2147483647,%edi +jg .LC145 +leal (,%edi,4),%edi +leal (,%esi,4),%esi +subl %esi,%edi +jmp *.LC152(%edi) +.data +.align 4 +.LC152: +.long .LC151 +.long .LC150 +.long .LC149 +.long .LC148 +.long .LC147 +.text +.LC147: +pushl $.LC130 +call printf +addl $4,%esp +jmp .LC146 +.LC148: +pushl $.LC132 +call printf +addl $4,%esp +jmp .LC146 +.LC149: +pushl $.LC134 +call printf +addl $4,%esp +jmp .LC146 +.LC150: +pushl $.LC136 +call printf +addl $4,%esp +jmp .LC146 +.LC151: +pushl $.LC138 +call printf +addl $4,%esp +jmp .LC146 +.LC145: +pushl $.LC139 +call printf +addl $4,%esp +.LC146: +.LC142: +decl -4(%ebp) +cmpl $2147483642,-4(%ebp) +jge .LC141 +mov $0,%eax +.LC122: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf153: +.size limit,.Lf153-limit +.data +.align 1 +.LC139: +.byte 53 +.byte 10 +.byte 0 +.align 1 +.LC138: +.byte 52 +.byte 10 +.byte 0 +.align 1 +.LC136: +.byte 51 +.byte 10 +.byte 0 +.align 1 +.LC134: +.byte 50 +.byte 10 +.byte 0 +.align 1 +.LC132: +.byte 49 +.byte 10 +.byte 0 +.align 1 +.LC130: +.byte 48 +.byte 10 +.byte 0 +.align 1 +.LC118: +.byte 120 +.byte 32 +.byte 61 +.byte 32 +.byte 48 +.byte 120 +.byte 37 +.byte 120 +.byte 32 +.byte 40 +.byte 100 +.byte 101 +.byte 102 +.byte 97 +.byte 117 +.byte 108 +.byte 116 +.byte 41 +.byte 10 +.byte 0 +.align 1 +.LC115: +.byte 120 +.byte 32 +.byte 61 +.byte 32 +.byte 48 +.byte 120 +.byte 37 +.byte 120 +.byte 10 +.byte 0 +.align 1 +.LC108: +.byte 37 +.byte 100 +.byte 32 +.byte 100 +.byte 101 +.byte 102 +.byte 97 +.byte 117 +.byte 108 +.byte 116 +.byte 115 +.byte 10 +.byte 0 +.align 1 +.LC85: +.byte 105 +.byte 32 +.byte 61 +.byte 32 +.byte 37 +.byte 100 +.byte 10 +.byte 0 +.align 1 +.LC77: +.byte 104 +.byte 58 +.byte 10 +.byte 0 +.align 1 +.LC66: +.byte 54 +.byte 32 +.byte 37 +.byte 100 +.byte 10 +.byte 0 +.align 1 +.LC64: +.byte 53 +.byte 32 +.byte 37 +.byte 100 +.byte 10 +.byte 0 +.align 1 +.LC62: +.byte 100 +.byte 32 +.byte 37 +.byte 100 +.byte 10 +.byte 0 +.align 1 +.LC61: +.byte 51 +.byte 32 +.byte 37 +.byte 100 +.byte 10 +.byte 0 +.align 1 +.LC59: +.byte 50 +.byte 32 +.byte 37 +.byte 100 +.byte 10 +.byte 0 +.align 1 +.LC57: +.byte 49 +.byte 32 +.byte 37 +.byte 100 +.byte 10 +.byte 0 +.align 1 +.LC49: +.byte 103 +.byte 58 +.byte 10 +.byte 0 +.align 1 +.LC46: +.byte 120 +.byte 32 +.byte 61 +.byte 32 +.byte 37 +.byte 100 +.byte 10 +.byte 0 +.align 1 +.LC27: +.byte 102 +.byte 58 +.byte 10 +.byte 0 +.align 1 +.LC7: +.byte 37 +.byte 99 +.byte 32 +.byte 61 +.byte 32 +.byte 48 +.byte 120 +.byte 37 +.byte 120 +.byte 10 +.byte 0 +.align 1 +.LC6: +.byte 98 +.byte 102 +.byte 110 +.byte 114 +.byte 116 +.byte 118 +.byte 120 +.byte 0 +.text +.ident "LCC: 4.1" diff --git a/src/cmd/lccom/tst/x86-linux/wf1.1bk b/src/cmd/lccom/tst/x86-linux/wf1.1bk new file mode 100644 index 0000000..a846267 --- /dev/null +++ b/src/cmd/lccom/tst/x86-linux/wf1.1bk @@ -0,0 +1,74 @@ +5 a +2 and +5 buf +16 c +8 char +1 compare +4 cond +5 count +1 d +1 die +3 else +1 entry +1 eof +4 err +1 error +1 exit +1 folded +1 for +1 free +1 frequencies +1 frequency +1 get +2 getchar +3 getword +14 if +2 in +1 index +1 input +1 install +8 int +1 into +1 is +4 isletter +1 it +1 itself +5 left +1 letter +7 lookup +1 main +2 malloc +1 message +2 n +1 necessary +12 next +9 node +4 of +1 on +1 or +1 otherwise +2 out +8 p +3 print +2 printf +16 return +5 right +4 root +25 s +2 storage +3 strcmp +1 strcpy +1 strlen +8 struct +1 structures +2 subtree +1 t +5 tprint +9 tree +1 uses +1 version +1 wf +3 while +21 word +9 words +2 z diff --git a/src/cmd/lccom/tst/x86-linux/wf1.2bk b/src/cmd/lccom/tst/x86-linux/wf1.2bk new file mode 100644 index 0000000..190e4a1 --- /dev/null +++ b/src/cmd/lccom/tst/x86-linux/wf1.2bk @@ -0,0 +1,2 @@ +tst/wf1.c:29: warning: missing return value +tst/wf1.c:87: warning: missing return value diff --git a/src/cmd/lccom/tst/x86-linux/wf1.sbk b/src/cmd/lccom/tst/x86-linux/wf1.sbk new file mode 100644 index 0000000..f3ee849 --- /dev/null +++ b/src/cmd/lccom/tst/x86-linux/wf1.sbk @@ -0,0 +1,437 @@ +.globl main +.text +.align 16 +.type main,@function +main: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +subl $24,%esp +movl $0,-24(%ebp) +movl $0,next +jmp .LC3 +.LC2: +leal -24(%ebp),%edi +pushl %edi +leal -20(%ebp),%edi +pushl %edi +call lookup +addl $8,%esp +incl (,%eax) +.LC3: +leal -20(%ebp),%edi +pushl %edi +call getword +addl $4,%esp +cmpl $0,%eax +jne .LC2 +pushl -24(%ebp) +call tprint +addl $4,%esp +mov $0,%eax +.LC1: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf5: +.size main,.Lf5-main +.globl err +.align 16 +.type err,@function +err: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +pushl 20(%ebp) +pushl $.LC7 +call printf +addl $8,%esp +pushl $1 +call exit +addl $4,%esp +mov $0,%eax +.LC6: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf8: +.size err,.Lf8-err +.globl getword +.align 16 +.type getword,@function +getword: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +subl $8,%esp +.LC10: +.LC11: +call getchar +movl %eax,%edi +movl %edi,-4(%ebp) +cmpl $-1,%edi +je .LC13 +pushl -4(%ebp) +call isletter +addl $4,%esp +cmpl $0,%eax +je .LC10 +.LC13: +movl 20(%ebp),%edi +movl %edi,-8(%ebp) +jmp .LC17 +.LC14: +movl -8(%ebp),%edi +leal 1(%edi),%esi +movl %esi,-8(%ebp) +movl -4(%ebp),%esi +movl %esi,%ebx +movb %bl,(,%edi) +.LC15: +call getchar +movl %eax,-4(%ebp) +.LC17: +pushl -4(%ebp) +call isletter +addl $4,%esp +movl %eax,-4(%ebp) +cmpl $0,%eax +jne .LC14 +movl -8(%ebp),%edi +movb $0,(,%edi) +movl -8(%ebp),%edi +movl 20(%ebp),%esi +cmpl %esi,%edi +jbe .LC18 +mov $1,%eax +jmp .LC9 +.LC18: +mov $0,%eax +.LC9: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf20: +.size getword,.Lf20-getword +.globl isletter +.align 16 +.type isletter,@function +isletter: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +movl 20(%ebp),%edi +cmpl $65,%edi +jl .LC22 +cmpl $90,%edi +jg .LC22 +addl $32,20(%ebp) +.LC22: +movl 20(%ebp),%edi +cmpl $97,%edi +jl .LC24 +cmpl $122,%edi +jg .LC24 +movl 20(%ebp),%eax +jmp .LC21 +.LC24: +mov $0,%eax +.LC21: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf26: +.size isletter,.Lf26-isletter +.globl lookup +.align 16 +.type lookup,@function +lookup: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +subl $4,%esp +movl 24(%ebp),%edi +movl (,%edi),%edi +cmpl $0,%edi +je .LC28 +movl 24(%ebp),%edi +movl (,%edi),%edi +pushl 12(%edi) +pushl 20(%ebp) +call strcmp +addl $8,%esp +movl %eax,-4(%ebp) +cmpl $0,-4(%ebp) +jge .LC30 +movl 24(%ebp),%edi +movl (,%edi),%edi +leal 4(%edi),%edi +pushl %edi +pushl 20(%ebp) +call lookup +addl $8,%esp +movl %eax,%edi +jmp .LC27 +.LC30: +cmpl $0,-4(%ebp) +jle .LC32 +movl 24(%ebp),%edi +movl (,%edi),%edi +leal 8(%edi),%edi +pushl %edi +pushl 20(%ebp) +call lookup +addl $8,%esp +movl %eax,%edi +jmp .LC27 +.LC32: +movl 24(%ebp),%edi +movl (,%edi),%eax +jmp .LC27 +.LC28: +cmpl $2000,next +jl .LC34 +pushl $.LC36 +call err +addl $4,%esp +.LC34: +movl next,%edi +sall $4,%edi +movl $0,words(%edi) +movl next,%edi +sall $4,%edi +movl $0,words+8(%edi) +movl $0,words+4(%edi) +pushl 20(%ebp) +call strlen +addl $4,%esp +leal 1(%eax),%edi +pushl %edi +call malloc +addl $4,%esp +movl next,%esi +sall $4,%esi +movl %eax,words+12(%esi) +movl next,%edi +sall $4,%edi +movl words+12(%edi),%edi +cmpl $0,%edi +jne .LC40 +pushl $.LC43 +call err +addl $4,%esp +.LC40: +pushl 20(%ebp) +movl next,%edi +sall $4,%edi +pushl words+12(%edi) +call strcpy +addl $8,%esp +movl next,%edi +leal 1(%edi),%esi +movl %esi,next +sall $4,%edi +leal words(%edi),%edi +movl 24(%ebp),%esi +movl %edi,(,%esi) +movl %edi,%eax +.LC27: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf45: +.size lookup,.Lf45-lookup +.globl tprint +.align 16 +.type tprint,@function +tprint: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +movl 20(%ebp),%edi +cmpl $0,%edi +je .LC47 +movl 20(%ebp),%edi +pushl 4(%edi) +call tprint +addl $4,%esp +movl 20(%ebp),%edi +pushl 12(%edi) +pushl (,%edi) +pushl $.LC49 +call printf +addl $12,%esp +movl 20(%ebp),%edi +pushl 8(%edi) +call tprint +addl $4,%esp +.LC47: +mov $0,%eax +.LC46: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf50: +.size tprint,.Lf50-tprint +.globl strcmp +.align 16 +.type strcmp,@function +strcmp: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +jmp .LC53 +.LC52: +movl 20(%ebp),%edi +leal 1(%edi),%esi +movl %esi,20(%ebp) +movsbl (,%edi),%edi +cmpl $0,%edi +jne .LC55 +mov $0,%eax +jmp .LC51 +.LC55: +incl 24(%ebp) +.LC53: +movl 20(%ebp),%edi +movsbl (,%edi),%edi +movl 24(%ebp),%esi +movsbl (,%esi),%esi +cmpl %esi,%edi +je .LC52 +movl 20(%ebp),%edi +movsbl (,%edi),%edi +cmpl $0,%edi +jne .LC57 +mov $-1,%eax +jmp .LC51 +.LC57: +movl 24(%ebp),%edi +movsbl (,%edi),%edi +cmpl $0,%edi +jne .LC59 +mov $1,%eax +jmp .LC51 +.LC59: +movl 20(%ebp),%edi +movsbl (,%edi),%edi +movl 24(%ebp),%esi +movsbl (,%esi),%esi +movl %edi,%eax +subl %esi,%eax +.LC51: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf61: +.size strcmp,.Lf61-strcmp +.bss +.globl next +.align 4 +.type next,@object +.size next,4 +.comm next,4 +.globl words +.align 4 +.type words,@object +.size words,32000 +.comm words,32000 +.data +.align 1 +.LC49: +.byte 37 +.byte 100 +.byte 9 +.byte 37 +.byte 115 +.byte 10 +.byte 0 +.align 1 +.LC43: +.byte 111 +.byte 117 +.byte 116 +.byte 32 +.byte 111 +.byte 102 +.byte 32 +.byte 119 +.byte 111 +.byte 114 +.byte 100 +.byte 32 +.byte 115 +.byte 116 +.byte 111 +.byte 114 +.byte 97 +.byte 103 +.byte 101 +.byte 0 +.align 1 +.LC36: +.byte 111 +.byte 117 +.byte 116 +.byte 32 +.byte 111 +.byte 102 +.byte 32 +.byte 110 +.byte 111 +.byte 100 +.byte 101 +.byte 32 +.byte 115 +.byte 116 +.byte 111 +.byte 114 +.byte 97 +.byte 103 +.byte 101 +.byte 0 +.align 1 +.LC7: +.byte 63 +.byte 32 +.byte 37 +.byte 115 +.byte 10 +.byte 0 +.text +.ident "LCC: 4.1" diff --git a/src/cmd/lccom/tst/x86-linux/yacc.1bk b/src/cmd/lccom/tst/x86-linux/yacc.1bk new file mode 100644 index 0000000..60de9b5 --- /dev/null +++ b/src/cmd/lccom/tst/x86-linux/yacc.1bk @@ -0,0 +1,10 @@ +a +b +load +negate +push 5 +c +load +multiply +add +store diff --git a/src/cmd/lccom/tst/x86-linux/yacc.2bk b/src/cmd/lccom/tst/x86-linux/yacc.2bk new file mode 100644 index 0000000..4b6dc39 --- /dev/null +++ b/src/cmd/lccom/tst/x86-linux/yacc.2bk @@ -0,0 +1,3 @@ +tst/yacc.c:345: warning: missing return value +tst/yacc.c:349: warning: missing return value +tst/yacc.c:360: warning: missing return value diff --git a/src/cmd/lccom/tst/x86-linux/yacc.sbk b/src/cmd/lccom/tst/x86-linux/yacc.sbk new file mode 100644 index 0000000..61f9858 --- /dev/null +++ b/src/cmd/lccom/tst/x86-linux/yacc.sbk @@ -0,0 +1,2384 @@ +.data +.globl yyin +.align 4 +.type yyin,@object +.size yyin,4 +yyin: +.long 0 +.globl yyout +.align 4 +.type yyout,@object +.size yyout,4 +yyout: +.long 0 +.globl yylex +.text +.align 16 +.type yylex,@function +yylex: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +subl $4,%esp +jmp .LC3 +.LC2: +.LC5: +movl -4(%ebp),%edi +cmpl $-1,%edi +jl .LC6 +cmpl $4,%edi +jg .LC6 +jmp *.LC17+4(,%edi,4) +.data +.align 4 +.LC17: +.long .LC7 +.long .LC8 +.long .LC11 +.long .LC12 +.long .LC7 +.long .LC14 +.text +.LC8: +call yywrap +cmpl $0,%eax +je .LC7 +mov $0,%eax +jmp .LC1 +.LC11: +mov $257,%eax +jmp .LC1 +.LC12: +mov $258,%eax +jmp .LC1 +.LC14: +movsbl yytext,%eax +jmp .LC1 +.LC6: +pushl -4(%ebp) +pushl $.LC16 +pushl yyout +call fprintf +addl $12,%esp +.LC7: +.LC3: +call yylook +movl %eax,-4(%ebp) +cmpl $0,%eax +jge .LC2 +mov $0,%eax +.LC1: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf19: +.size yylex,.Lf19-yylex +.data +.globl yyvstop +.align 4 +.type yyvstop,@object +yyvstop: +.long 0 +.long 4 +.long 0 +.long 3 +.long 4 +.long 0 +.long 2 +.long 4 +.long 0 +.long 1 +.long 4 +.long 0 +.long 2 +.long 0 +.long 1 +.long 0 +.long 0 +.size yyvstop,68 +.globl yycrank +.align 1 +.type yycrank,@object +yycrank: +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 1 +.byte 3 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 1 +.byte 4 +.byte 1 +.byte 3 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 1 +.byte 5 +.byte 5 +.byte 7 +.byte 5 +.byte 7 +.byte 5 +.byte 7 +.byte 5 +.byte 7 +.byte 5 +.byte 7 +.byte 5 +.byte 7 +.byte 5 +.byte 7 +.byte 5 +.byte 7 +.byte 5 +.byte 7 +.byte 5 +.byte 7 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 1 +.byte 6 +.byte 6 +.byte 8 +.byte 6 +.byte 8 +.byte 6 +.byte 8 +.byte 6 +.byte 8 +.byte 6 +.byte 8 +.byte 6 +.byte 8 +.byte 6 +.byte 8 +.byte 6 +.byte 8 +.byte 6 +.byte 8 +.byte 6 +.byte 8 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 6 +.byte 8 +.byte 6 +.byte 8 +.byte 6 +.byte 8 +.byte 6 +.byte 8 +.byte 6 +.byte 8 +.byte 6 +.byte 8 +.byte 6 +.byte 8 +.byte 6 +.byte 8 +.byte 6 +.byte 8 +.byte 6 +.byte 8 +.byte 6 +.byte 8 +.byte 6 +.byte 8 +.byte 6 +.byte 8 +.byte 6 +.byte 8 +.byte 6 +.byte 8 +.byte 6 +.byte 8 +.byte 6 +.byte 8 +.byte 6 +.byte 8 +.byte 6 +.byte 8 +.byte 6 +.byte 8 +.byte 6 +.byte 8 +.byte 6 +.byte 8 +.byte 6 +.byte 8 +.byte 6 +.byte 8 +.byte 6 +.byte 8 +.byte 6 +.byte 8 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 6 +.byte 8 +.byte 0 +.byte 0 +.byte 6 +.byte 8 +.byte 6 +.byte 8 +.byte 6 +.byte 8 +.byte 6 +.byte 8 +.byte 6 +.byte 8 +.byte 6 +.byte 8 +.byte 6 +.byte 8 +.byte 6 +.byte 8 +.byte 6 +.byte 8 +.byte 6 +.byte 8 +.byte 6 +.byte 8 +.byte 6 +.byte 8 +.byte 6 +.byte 8 +.byte 6 +.byte 8 +.byte 6 +.byte 8 +.byte 6 +.byte 8 +.byte 6 +.byte 8 +.byte 6 +.byte 8 +.byte 6 +.byte 8 +.byte 6 +.byte 8 +.byte 6 +.byte 8 +.byte 6 +.byte 8 +.byte 6 +.byte 8 +.byte 6 +.byte 8 +.byte 6 +.byte 8 +.byte 6 +.byte 8 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.size yycrank,290 +.globl yysvec +.align 4 +.type yysvec,@object +yysvec: +.long 0 +.long 0 +.long 0 +.long yycrank-2 +.long 0 +.long 0 +.long yycrank +.long yysvec+12 +.long 0 +.long yycrank +.long 0 +.long yyvstop+4 +.long yycrank +.long 0 +.long yyvstop+12 +.long yycrank+4 +.long 0 +.long yyvstop+24 +.long yycrank+38 +.long 0 +.long yyvstop+36 +.long yycrank +.long yysvec+60 +.long yyvstop+48 +.long yycrank +.long yysvec+72 +.long yyvstop+56 +.long 0 +.long 0 +.long 0 +.size yysvec,120 +.globl yytop +.align 4 +.type yytop,@object +.size yytop,4 +yytop: +.long yycrank+282 +.globl yybgin +.align 4 +.type yybgin,@object +.size yybgin,4 +yybgin: +.long yysvec+12 +.globl yymatch +.align 1 +.type yymatch,@object +yymatch: +.byte 0 +.byte 1 +.byte 1 +.byte 1 +.byte 1 +.byte 1 +.byte 1 +.byte 1 +.byte 1 +.byte 9 +.byte 10 +.byte 1 +.byte 1 +.byte 1 +.byte 1 +.byte 1 +.byte 1 +.byte 1 +.byte 1 +.byte 1 +.byte 1 +.byte 1 +.byte 1 +.byte 1 +.byte 1 +.byte 1 +.byte 1 +.byte 1 +.byte 1 +.byte 1 +.byte 1 +.byte 1 +.byte 9 +.byte 1 +.byte 1 +.byte 1 +.byte 1 +.byte 1 +.byte 1 +.byte 1 +.byte 1 +.byte 1 +.byte 1 +.byte 1 +.byte 1 +.byte 1 +.byte 1 +.byte 1 +.byte 48 +.byte 48 +.byte 48 +.byte 48 +.byte 48 +.byte 48 +.byte 48 +.byte 48 +.byte 48 +.byte 48 +.byte 1 +.byte 1 +.byte 1 +.byte 1 +.byte 1 +.byte 1 +.byte 1 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 1 +.byte 1 +.byte 1 +.byte 1 +.byte 65 +.byte 1 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 65 +.byte 1 +.byte 1 +.byte 1 +.byte 1 +.byte 1 +.byte 0 +.size yymatch,129 +.globl yyextra +.align 1 +.type yyextra,@object +yyextra: +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.byte 0 +.size yyextra,9 +.globl yylineno +.align 4 +.type yylineno,@object +.size yylineno,4 +yylineno: +.long 1 +.globl yysptr +.align 4 +.type yysptr,@object +.size yysptr,4 +yysptr: +.long yysbuf +.globl yyprevious +.align 4 +.type yyprevious,@object +.size yyprevious,4 +yyprevious: +.long 10 +.globl yylook +.text +.align 16 +.type yylook,@function +yylook: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +subl $44,%esp +cmpl $0,yymorfg +jne .LC35 +leal yytext,%edi +movl %edi,-16(%ebp) +jmp .LC36 +.LC35: +movl $0,yymorfg +movl yyleng,%edi +leal yytext(%edi),%edi +movl %edi,-16(%ebp) +.LC36: +.LC37: +leal yylstate,%edi +movl %edi,-8(%ebp) +movl yybgin,%edi +movl %edi,-4(%ebp) +movl %edi,yyestate +cmpl $10,yyprevious +jne .LC41 +movl -4(%ebp),%edi +leal 12(%edi),%edi +movl %edi,-4(%ebp) +.LC41: +.LC43: +movl -4(%ebp),%edi +movl (,%edi),%edi +movl %edi,-12(%ebp) +movl -12(%ebp),%edi +leal yycrank,%esi +cmpl %esi,%edi +jne .LC47 +movl -4(%ebp),%edi +movl 4(%edi),%edi +movl %edi,-28(%ebp) +movl -28(%ebp),%edi +cmpl $0,%edi +jne .LC49 +jmp .LC94 +.LC49: +movl -28(%ebp),%edi +movl (,%edi),%edi +leal yycrank,%esi +cmpl %esi,%edi +jne .LC51 +jmp .LC94 +.LC51: +.LC47: +movl -16(%ebp),%edi +leal 1(%edi),%esi +movl %esi,-16(%ebp) +movl yysptr,%esi +leal yysbuf,%ebx +cmpl %ebx,%esi +jbe .LC61 +movl yysptr,%esi +leal -1(%esi),%esi +movl %esi,yysptr +movsbl (,%esi),%esi +movl %esi,-40(%ebp) +jmp .LC62 +.LC61: +movl yyin,%esi +leal 4(%esi),%esi +movl (,%esi),%ebx +subl $1,%ebx +movl %ebx,(,%esi) +cmpl $0,%ebx +jl .LC63 +movl yyin,%esi +movl (,%esi),%ebx +leal 1(%ebx),%edx +movl %edx,(,%esi) +movsbl (,%ebx),%esi +andl $255,%esi +movl %esi,-44(%ebp) +jmp .LC64 +.LC63: +pushl yyin +call _filbuf +addl $4,%esp +movl %eax,%esi +movl %esi,-44(%ebp) +.LC64: +movl -44(%ebp),%esi +movl %esi,-40(%ebp) +.LC62: +movl -40(%ebp),%esi +movl %esi,yytchar +cmpl $10,%esi +jne .LC59 +incl yylineno +movl yytchar,%esi +movl %esi,-36(%ebp) +jmp .LC60 +.LC59: +movl yytchar,%esi +movl %esi,-36(%ebp) +.LC60: +cmpl $-1,-36(%ebp) +jne .LC57 +movl $0,-32(%ebp) +jmp .LC58 +.LC57: +movl yytchar,%esi +movl %esi,-32(%ebp) +.LC58: +movl -32(%ebp),%esi +movl %esi,-20(%ebp) +movl %esi,%ebx +movb %bl,(,%edi) +.LC65: +movl -12(%ebp),%edi +movl %edi,-24(%ebp) +leal yycrank,%esi +cmpl %esi,%edi +jbe .LC66 +movl -20(%ebp),%edi +movl -24(%ebp),%esi +leal (%esi,%edi,2),%edi +movl %edi,-12(%ebp) +movl -12(%ebp),%edi +movl %edi,%esi +movl yytop,%ebx +cmpl %ebx,%esi +ja .LC67 +movsbl (,%edi),%edi +imul $12,%edi,%edi +leal yysvec(%edi),%edi +movl -4(%ebp),%esi +cmpl %esi,%edi +jne .LC67 +leal yysvec,%edi +movl -12(%ebp),%esi +movsbl 1(%esi),%esi +imul $12,%esi,%esi +leal yysvec(%esi),%esi +cmpl %edi,%esi +jne .LC70 +movl -16(%ebp),%edi +leal -1(%edi),%edi +movl %edi,-16(%ebp) +movsbl (,%edi),%edi +movl %edi,yytchar +cmpl $10,yytchar +jne .LC72 +decl yylineno +.LC72: +movl yysptr,%edi +leal 1(%edi),%esi +movl %esi,yysptr +movl yytchar,%esi +movl %esi,%ebx +movb %bl,(,%edi) +jmp .LC94 +.LC70: +movl -8(%ebp),%edi +leal 4(%edi),%esi +movl %esi,-8(%ebp) +movl -12(%ebp),%esi +movsbl 1(%esi),%esi +imul $12,%esi,%esi +leal yysvec(%esi),%esi +movl %esi,-4(%ebp) +movl %esi,(,%edi) +jmp .LC43 +.LC66: +movl -12(%ebp),%edi +leal yycrank,%esi +cmpl %esi,%edi +jae .LC75 +leal yycrank,%edi +movl -12(%ebp),%esi +subl %esi,%edi +movl %edi,%eax +mov $2,%ecx +cdq +idivl %ecx +leal yycrank(,%eax,2),%edi +movl %edi,-24(%ebp) +movl %edi,-12(%ebp) +movl -20(%ebp),%edi +movl -12(%ebp),%esi +leal (%esi,%edi,2),%edi +movl %edi,-12(%ebp) +movl -12(%ebp),%edi +movl %edi,%esi +movl yytop,%ebx +cmpl %ebx,%esi +ja .LC77 +movsbl (,%edi),%edi +imul $12,%edi,%edi +leal yysvec(%edi),%edi +movl -4(%ebp),%esi +cmpl %esi,%edi +jne .LC77 +leal yysvec,%edi +movl -12(%ebp),%esi +movsbl 1(%esi),%esi +imul $12,%esi,%esi +leal yysvec(%esi),%esi +cmpl %edi,%esi +jne .LC79 +movl -16(%ebp),%edi +leal -1(%edi),%edi +movl %edi,-16(%ebp) +movsbl (,%edi),%edi +movl %edi,yytchar +cmpl $10,yytchar +jne .LC81 +decl yylineno +.LC81: +movl yysptr,%edi +leal 1(%edi),%esi +movl %esi,yysptr +movl yytchar,%esi +movl %esi,%ebx +movb %bl,(,%edi) +jmp .LC94 +.LC79: +movl -8(%ebp),%edi +leal 4(%edi),%esi +movl %esi,-8(%ebp) +movl -12(%ebp),%esi +movsbl 1(%esi),%esi +imul $12,%esi,%esi +leal yysvec(%esi),%esi +movl %esi,-4(%ebp) +movl %esi,(,%edi) +jmp .LC43 +.LC77: +movl -20(%ebp),%edi +movsbl yymatch(%edi),%edi +movl -24(%ebp),%esi +leal (%esi,%edi,2),%edi +movl %edi,-12(%ebp) +movl -12(%ebp),%edi +movl %edi,%esi +movl yytop,%ebx +cmpl %ebx,%esi +ja .LC83 +movsbl (,%edi),%edi +imul $12,%edi,%edi +leal yysvec(%edi),%edi +movl -4(%ebp),%esi +cmpl %esi,%edi +jne .LC83 +leal yysvec,%edi +movl -12(%ebp),%esi +movsbl 1(%esi),%esi +imul $12,%esi,%esi +leal yysvec(%esi),%esi +cmpl %edi,%esi +jne .LC85 +movl -16(%ebp),%edi +leal -1(%edi),%edi +movl %edi,-16(%ebp) +movsbl (,%edi),%edi +movl %edi,yytchar +cmpl $10,yytchar +jne .LC87 +decl yylineno +.LC87: +movl yysptr,%edi +leal 1(%edi),%esi +movl %esi,yysptr +movl yytchar,%esi +movl %esi,%ebx +movb %bl,(,%edi) +jmp .LC94 +.LC85: +movl -8(%ebp),%edi +leal 4(%edi),%esi +movl %esi,-8(%ebp) +movl -12(%ebp),%esi +movsbl 1(%esi),%esi +imul $12,%esi,%esi +leal yysvec(%esi),%esi +movl %esi,-4(%ebp) +movl %esi,(,%edi) +jmp .LC43 +.LC83: +.LC75: +.LC67: +movl -4(%ebp),%edi +movl 4(%edi),%edi +movl %edi,-4(%ebp) +cmpl $0,%edi +je .LC89 +movl -4(%ebp),%edi +movl (,%edi),%edi +movl %edi,-12(%ebp) +leal yycrank,%esi +cmpl %esi,%edi +je .LC89 +jmp .LC65 +.LC89: +movl -16(%ebp),%edi +leal -1(%edi),%edi +movl %edi,-16(%ebp) +movsbl (,%edi),%edi +movl %edi,yytchar +cmpl $10,yytchar +jne .LC91 +decl yylineno +.LC91: +movl yysptr,%edi +leal 1(%edi),%esi +movl %esi,yysptr +movl yytchar,%esi +movl %esi,%ebx +movb %bl,(,%edi) +jmp .LC94 +.LC93: +movl -16(%ebp),%edi +leal -1(%edi),%esi +movl %esi,-16(%ebp) +movb $0,(,%edi) +movl -8(%ebp),%edi +movl (,%edi),%edi +movl %edi,%esi +cmpl $0,%esi +je .LC96 +movl 8(%edi),%edi +movl %edi,yyfnd +cmpl $0,%edi +je .LC96 +movl yyfnd,%edi +cmpl $0,(,%edi) +jle .LC96 +movl -8(%ebp),%edi +movl %edi,yyolsp +movl yyfnd,%edi +movl (,%edi),%edi +movsbl yyextra(%edi),%edi +cmpl $0,%edi +je .LC98 +jmp .LC101 +.LC100: +movl -8(%ebp),%edi +leal -4(%edi),%edi +movl %edi,-8(%ebp) +movl -16(%ebp),%edi +leal -1(%edi),%esi +movl %esi,-16(%ebp) +movsbl (,%edi),%edi +movl %edi,yytchar +cmpl $10,yytchar +jne .LC103 +decl yylineno +.LC103: +movl yysptr,%edi +leal 1(%edi),%esi +movl %esi,yysptr +movl yytchar,%esi +movl %esi,%ebx +movb %bl,(,%edi) +.LC101: +movl yyfnd,%edi +movl (,%edi),%edi +negl %edi +pushl %edi +movl -8(%ebp),%edi +movl (,%edi),%edi +pushl 8(%edi) +call yyback +addl $8,%esp +cmpl $1,%eax +je .LC105 +movl -8(%ebp),%edi +leal yylstate,%esi +cmpl %esi,%edi +ja .LC100 +.LC105: +.LC98: +movl -16(%ebp),%edi +movsbl (,%edi),%esi +movl %esi,yyprevious +movl -8(%ebp),%esi +movl %esi,yylsp +leal yytext,%esi +subl %esi,%edi +leal 1(%edi),%edi +movl %edi,yyleng +movl yyleng,%edi +movb $0,yytext(%edi) +movl yyfnd,%edi +leal 4(%edi),%esi +movl %esi,yyfnd +movl (,%edi),%eax +jmp .LC34 +.LC96: +movl -16(%ebp),%edi +movsbl (,%edi),%edi +movl %edi,yytchar +cmpl $10,yytchar +jne .LC106 +decl yylineno +.LC106: +movl yysptr,%edi +leal 1(%edi),%esi +movl %esi,yysptr +movl yytchar,%esi +movl %esi,%ebx +movb %bl,(,%edi) +.LC94: +movl -8(%ebp),%edi +leal -4(%edi),%esi +movl %esi,-8(%ebp) +leal yylstate,%esi +cmpl %esi,%edi +ja .LC93 +movsbl yytext,%edi +cmpl $0,%edi +jne .LC108 +leal yysbuf,%edi +movl %edi,yysptr +mov $0,%eax +jmp .LC34 +.LC108: +movl yysptr,%edi +leal yysbuf,%esi +cmpl %esi,%edi +jbe .LC118 +movl yysptr,%edi +leal -1(%edi),%edi +movl %edi,yysptr +movsbl (,%edi),%edi +movl %edi,-40(%ebp) +jmp .LC119 +.LC118: +movl yyin,%edi +leal 4(%edi),%edi +movl (,%edi),%esi +subl $1,%esi +movl %esi,(,%edi) +cmpl $0,%esi +jl .LC120 +movl yyin,%edi +movl (,%edi),%esi +leal 1(%esi),%ebx +movl %ebx,(,%edi) +movsbl (,%esi),%edi +andl $255,%edi +movl %edi,-44(%ebp) +jmp .LC121 +.LC120: +pushl yyin +call _filbuf +addl $4,%esp +movl %eax,%edi +movl %edi,-44(%ebp) +.LC121: +movl -44(%ebp),%edi +movl %edi,-40(%ebp) +.LC119: +movl -40(%ebp),%edi +movl %edi,yytchar +cmpl $10,%edi +jne .LC116 +incl yylineno +movl yytchar,%edi +movl %edi,-36(%ebp) +jmp .LC117 +.LC116: +movl yytchar,%edi +movl %edi,-36(%ebp) +.LC117: +cmpl $-1,-36(%ebp) +jne .LC114 +movl $0,-32(%ebp) +jmp .LC115 +.LC114: +movl yytchar,%edi +movl %edi,-32(%ebp) +.LC115: +movl -32(%ebp),%edi +movl %edi,%ebx +movb %bl,yytext +movsbl %bl,%edi +movl %edi,yyprevious +cmpl $0,yyprevious +jle .LC122 +movl yyout,%edi +leal 4(%edi),%edi +movl (,%edi),%esi +subl $1,%esi +movl %esi,(,%edi) +cmpl $0,%esi +jl .LC125 +movl yyout,%edi +movl (,%edi),%esi +leal 1(%esi),%ebx +movl %ebx,(,%edi) +movl yyprevious,%edi +movl %edi,%ebx +movb %bl,(,%esi) +jmp .LC126 +.LC125: +pushl yyout +pushl yyprevious +call _flsbuf +addl $8,%esp +.LC126: +.LC122: +leal yytext,%edi +movl %edi,-16(%ebp) +jmp .LC37 +.LC34: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf127: +.size yylook,.Lf127-yylook +.globl yyback +.align 16 +.type yyback,@function +yyback: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +movl 20(%ebp),%edi +cmpl $0,%edi +jne .LC132 +mov $0,%eax +jmp .LC128 +.LC131: +movl 20(%ebp),%edi +leal 4(%edi),%esi +movl %esi,20(%ebp) +movl 24(%ebp),%esi +cmpl %esi,(,%edi) +jne .LC134 +mov $1,%eax +jmp .LC128 +.LC134: +.LC132: +movl 20(%ebp),%edi +cmpl $0,(,%edi) +jne .LC131 +mov $0,%eax +.LC128: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf136: +.size yyback,.Lf136-yyback +.globl yyinput +.align 16 +.type yyinput,@function +yyinput: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +subl $16,%esp +movl yysptr,%edi +leal yysbuf,%esi +cmpl %esi,%edi +jbe .LC146 +movl yysptr,%edi +leal -1(%edi),%edi +movl %edi,yysptr +movsbl (,%edi),%edi +movl %edi,-12(%ebp) +jmp .LC147 +.LC146: +movl yyin,%edi +leal 4(%edi),%edi +movl (,%edi),%esi +subl $1,%esi +movl %esi,(,%edi) +cmpl $0,%esi +jl .LC148 +movl yyin,%edi +movl (,%edi),%esi +leal 1(%esi),%ebx +movl %ebx,(,%edi) +movsbl (,%esi),%edi +andl $255,%edi +movl %edi,-16(%ebp) +jmp .LC149 +.LC148: +pushl yyin +call _filbuf +addl $4,%esp +movl %eax,%edi +movl %edi,-16(%ebp) +.LC149: +movl -16(%ebp),%edi +movl %edi,-12(%ebp) +.LC147: +movl -12(%ebp),%edi +movl %edi,yytchar +cmpl $10,%edi +jne .LC144 +incl yylineno +movl yytchar,%edi +movl %edi,-8(%ebp) +jmp .LC145 +.LC144: +movl yytchar,%edi +movl %edi,-8(%ebp) +.LC145: +cmpl $-1,-8(%ebp) +jne .LC142 +movl $0,-4(%ebp) +jmp .LC143 +.LC142: +movl yytchar,%edi +movl %edi,-4(%ebp) +.LC143: +movl -4(%ebp),%eax +.LC137: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf150: +.size yyinput,.Lf150-yyinput +.globl yyoutput +.align 16 +.type yyoutput,@function +yyoutput: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +movl yyout,%edi +leal 4(%edi),%edi +movl (,%edi),%esi +subl $1,%esi +movl %esi,(,%edi) +cmpl $0,%esi +jl .LC153 +movl yyout,%edi +movl (,%edi),%esi +leal 1(%esi),%ebx +movl %ebx,(,%edi) +movl 20(%ebp),%edi +movl %edi,%ebx +movb %bl,(,%esi) +jmp .LC154 +.LC153: +pushl yyout +pushl 20(%ebp) +call _flsbuf +addl $8,%esp +.LC154: +mov $0,%eax +.LC151: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf155: +.size yyoutput,.Lf155-yyoutput +.globl yyunput +.align 16 +.type yyunput,@function +yyunput: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +movl 20(%ebp),%edi +movl %edi,yytchar +cmpl $10,yytchar +jne .LC157 +decl yylineno +.LC157: +movl yysptr,%edi +leal 1(%edi),%esi +movl %esi,yysptr +movl yytchar,%esi +movl %esi,%ebx +movb %bl,(,%edi) +mov $0,%eax +.LC156: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf159: +.size yyunput,.Lf159-yyunput +.globl main +.align 16 +.type main,@function +main: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +leal _iob,%edi +movl %edi,yyin +leal _iob+32,%edi +movl %edi,yyout +call yyparse +mov $0,%eax +.LC160: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf162: +.size main,.Lf162-main +.globl yyerror +.align 16 +.type yyerror,@function +yyerror: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +pushl 20(%ebp) +pushl $.LC164 +call printf +addl $8,%esp +mov $0,%eax +.LC163: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf165: +.size yyerror,.Lf165-yyerror +.data +.globl yyexca +.align 2 +.type yyexca,@object +yyexca: +.word -1 +.word 1 +.word 0 +.word -1 +.word -2 +.word 0 +.size yyexca,12 +.globl yyact +.align 2 +.type yyact,@object +yyact: +.word 12 +.word 2 +.word 9 +.word 8 +.word 17 +.word 11 +.word 25 +.word 17 +.word 15 +.word 18 +.word 16 +.word 10 +.word 18 +.word 17 +.word 15 +.word 7 +.word 16 +.word 13 +.word 18 +.word 5 +.word 3 +.word 1 +.word 0 +.word 19 +.word 20 +.word 0 +.word 0 +.word 21 +.word 22 +.word 23 +.word 24 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 6 +.word 14 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 4 +.word 6 +.size yyact,498 +.globl yypact +.align 2 +.type yypact,@object +yypact: +.word -1000 +.word -9 +.word -1000 +.word 5 +.word -7 +.word -59 +.word -1000 +.word -1000 +.word -1000 +.word -40 +.word -29 +.word -40 +.word -40 +.word -1000 +.word -1000 +.word -40 +.word -40 +.word -40 +.word -40 +.word -38 +.word -35 +.word -38 +.word -38 +.word -1000 +.word -1000 +.word -1000 +.size yypact,52 +.globl yypgo +.align 2 +.type yypgo,@object +yypgo: +.word 0 +.word 21 +.word 20 +.word 17 +.word 11 +.size yypgo,10 +.globl yyr1 +.align 2 +.type yyr1,@object +yyr1: +.word 0 +.word 1 +.word 1 +.word 1 +.word 1 +.word 2 +.word 4 +.word 4 +.word 4 +.word 4 +.word 4 +.word 4 +.word 4 +.word 4 +.word 3 +.size yyr1,30 +.globl yyr2 +.align 2 +.type yyr2,@object +yyr2: +.word 0 +.word 0 +.word 2 +.word 3 +.word 3 +.word 3 +.word 3 +.word 3 +.word 3 +.word 3 +.word 2 +.word 3 +.word 1 +.word 1 +.word 1 +.size yyr2,30 +.globl yychk +.align 2 +.type yychk,@object +yychk: +.word -1000 +.word -1 +.word 10 +.word -2 +.word 256 +.word -3 +.word 257 +.word 10 +.word 10 +.word 61 +.word -4 +.word 45 +.word 40 +.word -3 +.word 258 +.word 43 +.word 45 +.word 42 +.word 47 +.word -4 +.word -4 +.word -4 +.word -4 +.word -4 +.word -4 +.word 41 +.size yychk,52 +.globl yydef +.align 2 +.type yydef,@object +yydef: +.word 1 +.word -2 +.word 2 +.word 0 +.word 0 +.word 0 +.word 14 +.word 3 +.word 4 +.word 0 +.word 5 +.word 0 +.word 0 +.word 12 +.word 13 +.word 0 +.word 0 +.word 0 +.word 0 +.word 10 +.word 0 +.word 6 +.word 7 +.word 8 +.word 9 +.word 11 +.size yydef,52 +.globl yychar +.align 4 +.type yychar,@object +.size yychar,4 +yychar: +.long -1 +.globl yynerrs +.align 4 +.type yynerrs,@object +.size yynerrs,4 +yynerrs: +.long 0 +.globl yyerrflag +.align 2 +.type yyerrflag,@object +.size yyerrflag,2 +yyerrflag: +.word 0 +.globl yyparse +.text +.align 16 +.type yyparse,@function +yyparse: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +subl $336,%esp +movw $0,-8(%ebp) +movl $-1,yychar +movl $0,yynerrs +movw $0,yyerrflag +leal -330(%ebp),%edi +movl %edi,-12(%ebp) +leal yyv-4,%edi +movl %edi,-20(%ebp) +.LC169: +movl -12(%ebp),%edi +leal 2(%edi),%edi +movl %edi,-12(%ebp) +leal -30(%ebp),%esi +cmpl %esi,%edi +jbe .LC170 +pushl $.LC173 +call yyerror +addl $4,%esp +mov $1,%eax +jmp .LC166 +.LC170: +movl -12(%ebp),%edi +movw -8(%ebp),%si +movw %si,(,%edi) +movl -20(%ebp),%edi +leal 4(%edi),%edi +movl %edi,-20(%ebp) +movl -20(%ebp),%edi +movl yyval,%esi +movl %esi,(,%edi) +.LC174: +movswl -8(%ebp),%edi +movw yypact(,%edi,2),%di +movw %di,-16(%ebp) +movswl -16(%ebp),%edi +cmpl $-1000,%edi +jg .LC175 +jmp .LC177 +.LC175: +cmpl $0,yychar +jge .LC178 +call yylex +movl %eax,yychar +cmpl $0,%eax +jge .LC180 +movl $0,yychar +.LC180: +.LC178: +movswl -16(%ebp),%edi +movl yychar,%esi +leal (%esi,%edi),%edi +movw %di,-16(%ebp) +movswl %di,%edi +cmpl $0,%edi +jl .LC184 +movswl -16(%ebp),%edi +cmpl $249,%edi +jl .LC182 +.LC184: +jmp .LC177 +.LC182: +movswl -16(%ebp),%edi +movw yyact(,%edi,2),%di +movw %di,-16(%ebp) +movswl %di,%edi +movswl yychk(,%edi,2),%edi +cmpl yychar,%edi +jne .LC185 +movl $-1,yychar +movl yylval,%edi +movl %edi,yyval +movw -16(%ebp),%di +movw %di,-8(%ebp) +movswl yyerrflag,%edi +cmpl $0,%edi +jle .LC169 +movswl yyerrflag,%edi +subl $1,%edi +movw %di,yyerrflag +jmp .LC169 +.LC185: +.LC177: +movswl -8(%ebp),%edi +movw yydef(,%edi,2),%di +movw %di,-16(%ebp) +movswl %di,%edi +cmpl $-2,%edi +jne .LC189 +cmpl $0,yychar +jge .LC191 +call yylex +movl %eax,yychar +cmpl $0,%eax +jge .LC193 +movl $0,yychar +.LC193: +.LC191: +leal yyexca,%edi +movl %edi,-24(%ebp) +jmp .LC198 +.LC195: +.LC196: +movl -24(%ebp),%edi +leal 4(%edi),%edi +movl %edi,-24(%ebp) +.LC198: +movl -24(%ebp),%edi +movswl (,%edi),%esi +cmpl $-1,%esi +jne .LC195 +movswl 2(%edi),%edi +movswl -8(%ebp),%esi +cmpl %esi,%edi +jne .LC195 +jmp .LC200 +.LC199: +movl -24(%ebp),%edi +movswl (,%edi),%edi +cmpl yychar,%edi +jne .LC202 +jmp .LC201 +.LC202: +.LC200: +movl -24(%ebp),%edi +leal 4(%edi),%edi +movl %edi,-24(%ebp) +movswl (,%edi),%edi +cmpl $0,%edi +jge .LC199 +.LC201: +movl -24(%ebp),%edi +movw 2(%edi),%di +movw %di,-16(%ebp) +movswl %di,%edi +cmpl $0,%edi +jge .LC204 +mov $0,%eax +jmp .LC166 +.LC204: +.LC189: +movswl -16(%ebp),%edi +cmpl $0,%edi +jne .LC206 +movswl yyerrflag,%edi +movl %edi,-336(%ebp) +movl -336(%ebp),%edi +cmpl $0,%edi +jl .LC208 +cmpl $3,%edi +jg .LC208 +jmp *.LC224(,%edi,4) +.data +.align 4 +.LC224: +.long .LC211 +.long .LC214 +.long .LC214 +.long .LC221 +.text +.LC211: +pushl $.LC212 +call yyerror +addl $4,%esp +.LC213: +incl yynerrs +.LC214: +movw $3,yyerrflag +jmp .LC216 +.LC215: +movl -12(%ebp),%edi +movswl (,%edi),%edi +movswl yypact(,%edi,2),%edi +leal 256(%edi),%edi +movw %di,-16(%ebp) +movswl -16(%ebp),%edi +cmpl $0,%edi +jl .LC218 +cmpl $249,%edi +jge .LC218 +movswl yyact(,%edi,2),%edi +movswl yychk(,%edi,2),%edi +cmpl $256,%edi +jne .LC218 +movswl -16(%ebp),%edi +movw yyact(,%edi,2),%di +movw %di,-8(%ebp) +jmp .LC169 +.LC218: +movl -12(%ebp),%edi +movswl (,%edi),%esi +movw yypact(,%esi,2),%si +movw %si,-16(%ebp) +leal -2(%edi),%edi +movl %edi,-12(%ebp) +movl -20(%ebp),%edi +leal -4(%edi),%edi +movl %edi,-20(%ebp) +.LC216: +movl -12(%ebp),%edi +leal -328(%ebp),%esi +cmpl %esi,%edi +jae .LC215 +.LC220: +mov $1,%eax +jmp .LC166 +.LC221: +cmpl $0,yychar +jne .LC222 +jmp .LC220 +.LC222: +movl $-1,yychar +jmp .LC174 +.LC208: +.LC206: +movw -16(%ebp),%di +movswl %di,%esi +leal (,%esi,2),%esi +leal yyr2(%esi),%ebx +movl -12(%ebp),%edx +movswl (,%ebx),%ecx +leal (,%ecx,2),%ecx +subl %ecx,%edx +movl %edx,-12(%ebp) +movl -20(%ebp),%edx +movl %edx,-4(%ebp) +movswl (,%ebx),%ebx +leal (,%ebx,4),%ebx +subl %ebx,%edx +movl %edx,-20(%ebp) +movl -20(%ebp),%ebx +movl 4(%ebx),%ebx +movl %ebx,yyval +movw %di,-332(%ebp) +movw yyr1(%esi),%di +movw %di,-16(%ebp) +movswl -16(%ebp),%edi +movswl yypgo(,%edi,2),%edi +movl -12(%ebp),%esi +movswl (,%esi),%esi +leal (%esi,%edi),%edi +leal 1(%edi),%edi +movw %di,-28(%ebp) +movswl -28(%ebp),%edi +cmpl $249,%edi +jge .LC227 +movw yyact(,%edi,2),%di +movw %di,-8(%ebp) +movswl %di,%edi +movswl yychk(,%edi,2),%edi +movswl -16(%ebp),%esi +negl %esi +cmpl %esi,%edi +je .LC225 +.LC227: +movswl -16(%ebp),%edi +movswl yypgo(,%edi,2),%edi +movw yyact(,%edi,2),%di +movw %di,-8(%ebp) +.LC225: +movswl -332(%ebp),%edi +movl %edi,-336(%ebp) +movl -336(%ebp),%edi +cmpl $4,%edi +jl .LC169 +cmpl $14,%edi +jg .LC169 +jmp *.LC249-16(,%edi,4) +.data +.align 4 +.LC249: +.long .LC231 +.long .LC232 +.long .LC234 +.long .LC236 +.long .LC238 +.long .LC240 +.long .LC242 +.long .LC169 +.long .LC244 +.long .LC246 +.long .LC248 +.text +.LC231: +movw $0,yyerrflag +jmp .LC169 +.LC232: +pushl $.LC233 +call printf +addl $4,%esp +jmp .LC169 +.LC234: +pushl $.LC235 +call printf +addl $4,%esp +jmp .LC169 +.LC236: +pushl $.LC237 +call printf +addl $4,%esp +jmp .LC169 +.LC238: +pushl $.LC239 +call printf +addl $4,%esp +jmp .LC169 +.LC240: +pushl $.LC241 +call printf +addl $4,%esp +jmp .LC169 +.LC242: +pushl $.LC243 +call printf +addl $4,%esp +jmp .LC169 +.LC244: +pushl $.LC245 +call printf +addl $4,%esp +jmp .LC169 +.LC246: +pushl $yytext +pushl $.LC247 +call printf +addl $8,%esp +jmp .LC169 +.LC248: +pushl $yytext +pushl $.LC164 +call printf +addl $8,%esp +jmp .LC169 +.LC166: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf251: +.size yyparse,.Lf251-yyparse +.globl yywrap +.align 16 +.type yywrap,@function +yywrap: +pushl %ebp +pushl %ebx +pushl %esi +pushl %edi +movl %esp,%ebp +mov $1,%eax +.LC252: +movl %ebp,%esp +popl %edi +popl %esi +popl %ebx +popl %ebp +ret +.Lf253: +.size yywrap,.Lf253-yywrap +.bss +.globl yyv +.align 4 +.type yyv,@object +.size yyv,600 +.comm yyv,600 +.globl yyfnd +.align 4 +.type yyfnd,@object +.size yyfnd,4 +.comm yyfnd,4 +.globl yyolsp +.align 4 +.type yyolsp,@object +.size yyolsp,4 +.comm yyolsp,4 +.globl yylsp +.align 4 +.type yylsp,@object +.size yylsp,4 +.comm yylsp,4 +.globl yylstate +.align 4 +.type yylstate,@object +.size yylstate,800 +.comm yylstate,800 +.globl yyestate +.align 4 +.type yyestate,@object +.size yyestate,4 +.comm yyestate,4 +.globl yytchar +.align 4 +.type yytchar,@object +.size yytchar,4 +.comm yytchar,4 +.globl yysbuf +.align 1 +.type yysbuf,@object +.size yysbuf,200 +.comm yysbuf,200 +.globl yymorfg +.align 4 +.type yymorfg,@object +.size yymorfg,4 +.comm yymorfg,4 +.globl yytext +.align 1 +.type yytext,@object +.size yytext,200 +.comm yytext,200 +.globl yyleng +.align 4 +.type yyleng,@object +.size yyleng,4 +.comm yyleng,4 +.globl yyval +.align 4 +.type yyval,@object +.size yyval,4 +.comm yyval,4 +.globl yylval +.align 4 +.type yylval,@object +.size yylval,4 +.comm yylval,4 +.data +.align 1 +.LC247: +.byte 112 +.byte 117 +.byte 115 +.byte 104 +.byte 32 +.byte 37 +.byte 115 +.byte 10 +.byte 0 +.align 1 +.LC245: +.byte 108 +.byte 111 +.byte 97 +.byte 100 +.byte 10 +.byte 0 +.align 1 +.LC243: +.byte 110 +.byte 101 +.byte 103 +.byte 97 +.byte 116 +.byte 101 +.byte 10 +.byte 0 +.align 1 +.LC241: +.byte 100 +.byte 105 +.byte 118 +.byte 105 +.byte 100 +.byte 101 +.byte 10 +.byte 0 +.align 1 +.LC239: +.byte 109 +.byte 117 +.byte 108 +.byte 116 +.byte 105 +.byte 112 +.byte 108 +.byte 121 +.byte 10 +.byte 0 +.align 1 +.LC237: +.byte 110 +.byte 101 +.byte 103 +.byte 97 +.byte 116 +.byte 101 +.byte 10 +.byte 97 +.byte 100 +.byte 100 +.byte 10 +.byte 0 +.align 1 +.LC235: +.byte 97 +.byte 100 +.byte 100 +.byte 10 +.byte 0 +.align 1 +.LC233: +.byte 115 +.byte 116 +.byte 111 +.byte 114 +.byte 101 +.byte 10 +.byte 0 +.align 1 +.LC212: +.byte 115 +.byte 121 +.byte 110 +.byte 116 +.byte 97 +.byte 120 +.byte 32 +.byte 101 +.byte 114 +.byte 114 +.byte 111 +.byte 114 +.byte 0 +.align 1 +.LC173: +.byte 121 +.byte 97 +.byte 99 +.byte 99 +.byte 32 +.byte 115 +.byte 116 +.byte 97 +.byte 99 +.byte 107 +.byte 32 +.byte 111 +.byte 118 +.byte 101 +.byte 114 +.byte 102 +.byte 108 +.byte 111 +.byte 119 +.byte 0 +.align 1 +.LC164: +.byte 37 +.byte 115 +.byte 10 +.byte 0 +.align 1 +.LC16: +.byte 98 +.byte 97 +.byte 100 +.byte 32 +.byte 115 +.byte 119 +.byte 105 +.byte 116 +.byte 99 +.byte 104 +.byte 32 +.byte 121 +.byte 121 +.byte 108 +.byte 111 +.byte 111 +.byte 107 +.byte 32 +.byte 37 +.byte 100 +.byte 0 +.text +.ident "LCC: 4.1" diff --git a/src/cmd/lccom/tst/yacc.0 b/src/cmd/lccom/tst/yacc.0 new file mode 100644 index 0000000..46de7cb --- /dev/null +++ b/src/cmd/lccom/tst/yacc.0 @@ -0,0 +1 @@ +a=-b+5*c diff --git a/src/cmd/lccom/tst/yacc.c b/src/cmd/lccom/tst/yacc.c new file mode 100644 index 0000000..caea406 --- /dev/null +++ b/src/cmd/lccom/tst/yacc.c @@ -0,0 +1,592 @@ +# define ID 257 +# define CON 258 +# define UNARYMINUS 259 +#define yyclearin yychar = -1 +#define yyerrok yyerrflag = 0 +extern int yychar; +extern short yyerrflag; +#ifndef YYMAXDEPTH +#define YYMAXDEPTH 150 +#endif +#ifndef YYSTYPE +#define YYSTYPE int +#endif +YYSTYPE yylval, yyval; +# define YYERRCODE 256 + + + +#include + +# define U(x) x +# define NLSTATE yyprevious=YYNEWLINE +# define BEGIN yybgin = yysvec + 1 + +# define INITIAL 0 +# define YYLERR yysvec +# define YYSTATE (yyestate-yysvec-1) +# define YYOPTIM 1 +# define YYLMAX 200 +# define output(c) (void)putc(c,yyout) +# define input() (((yytchar=yysptr>yysbuf?U(*--yysptr):getc(yyin))==10?(yylineno++,yytchar):yytchar)==EOF?0:yytchar) +# define unput(c) {yytchar= (c);if(yytchar=='\n')yylineno--;*yysptr++=yytchar;} +# define yymore() (yymorfg=1) +# define ECHO fprintf(yyout, "%s",yytext) +# define REJECT { nstr = yyreject(); goto yyfussy;} +int yyleng; extern char yytext[]; +int yymorfg; +extern char *yysptr, yysbuf[]; +int yytchar; +FILE *yyin = NULL, *yyout = NULL; +extern int yylineno; +struct yysvf { + struct yywork *yystoff; + struct yysvf *yyother; + int *yystops;}; +struct yysvf *yyestate; +extern struct yysvf yysvec[], *yybgin; +# define YYNEWLINE 10 +yylex(){ +int nstr; extern int yyprevious; +while((nstr = yylook()) >= 0) +yyfussy: switch(nstr){ +case 0: +if(yywrap()) return(0); break; +case 1: + return ID; +break; +case 2: + return CON; +break; +case 3: + ; +break; +case 4: + return yytext[0]; +break; +case -1: +break; +default: +fprintf(yyout,"bad switch yylook %d",nstr); +} return(0); } +/* end of yylex */ +int yyvstop[] ={ +0, + +4, +0, + +3, +4, +0, + +2, +4, +0, + +1, +4, +0, + +2, +0, + +1, +0, +0}; +# define YYTYPE char +struct yywork { YYTYPE verify, advance; } yycrank[] ={ +0,0, 0,0, 1,3, 0,0, +0,0, 0,0, 0,0, 0,0, +0,0, 0,0, 1,4, 1,3, +0,0, 0,0, 0,0, 0,0, +0,0, 0,0, 0,0, 0,0, +0,0, 0,0, 0,0, 0,0, +0,0, 0,0, 0,0, 0,0, +0,0, 0,0, 0,0, 0,0, +0,0, 0,0, 0,0, 0,0, +0,0, 0,0, 0,0, 0,0, +0,0, 0,0, 0,0, 0,0, +0,0, 0,0, 0,0, 0,0, +0,0, 1,5, 5,7, 5,7, +5,7, 5,7, 5,7, 5,7, +5,7, 5,7, 5,7, 5,7, +0,0, 0,0, 0,0, 0,0, +0,0, 0,0, 1,6, 6,8, +6,8, 6,8, 6,8, 6,8, +6,8, 6,8, 6,8, 6,8, +6,8, 0,0, 0,0, 0,0, +0,0, 0,0, 0,0, 0,0, +6,8, 6,8, 6,8, 6,8, +6,8, 6,8, 6,8, 6,8, +6,8, 6,8, 6,8, 6,8, +6,8, 6,8, 6,8, 6,8, +6,8, 6,8, 6,8, 6,8, +6,8, 6,8, 6,8, 6,8, +6,8, 6,8, 0,0, 0,0, +0,0, 0,0, 6,8, 0,0, +6,8, 6,8, 6,8, 6,8, +6,8, 6,8, 6,8, 6,8, +6,8, 6,8, 6,8, 6,8, +6,8, 6,8, 6,8, 6,8, +6,8, 6,8, 6,8, 6,8, +6,8, 6,8, 6,8, 6,8, +6,8, 6,8, 0,0, 0,0, +0,0}; +struct yysvf yysvec[] ={ +0, 0, 0, +yycrank+-1, 0, 0, +yycrank+0, yysvec+1, 0, +yycrank+0, 0, yyvstop+1, +yycrank+0, 0, yyvstop+3, +yycrank+2, 0, yyvstop+6, +yycrank+19, 0, yyvstop+9, +yycrank+0, yysvec+5, yyvstop+12, +yycrank+0, yysvec+6, yyvstop+14, +0, 0, 0}; +struct yywork *yytop = yycrank+141; +struct yysvf *yybgin = yysvec+1; +char yymatch[] ={ +00 ,01 ,01 ,01 ,01 ,01 ,01 ,01 , +01 ,011 ,012 ,01 ,01 ,01 ,01 ,01 , +01 ,01 ,01 ,01 ,01 ,01 ,01 ,01 , +01 ,01 ,01 ,01 ,01 ,01 ,01 ,01 , +011 ,01 ,01 ,01 ,01 ,01 ,01 ,01 , +01 ,01 ,01 ,01 ,01 ,01 ,01 ,01 , +'0' ,'0' ,'0' ,'0' ,'0' ,'0' ,'0' ,'0' , +'0' ,'0' ,01 ,01 ,01 ,01 ,01 ,01 , +01 ,'A' ,'A' ,'A' ,'A' ,'A' ,'A' ,'A' , +'A' ,'A' ,'A' ,'A' ,'A' ,'A' ,'A' ,'A' , +'A' ,'A' ,'A' ,'A' ,'A' ,'A' ,'A' ,'A' , +'A' ,'A' ,'A' ,01 ,01 ,01 ,01 ,'A' , +01 ,'A' ,'A' ,'A' ,'A' ,'A' ,'A' ,'A' , +'A' ,'A' ,'A' ,'A' ,'A' ,'A' ,'A' ,'A' , +'A' ,'A' ,'A' ,'A' ,'A' ,'A' ,'A' ,'A' , +'A' ,'A' ,'A' ,01 ,01 ,01 ,01 ,01 , +0}; +char yyextra[] ={ +0,0,0,0,0,0,0,0, +0}; +/* ncform 4.1 83/08/11 */ + +int yylineno =1; +# define YYU(x) x +# define NLSTATE yyprevious=YYNEWLINE +char yytext[YYLMAX]; +struct yysvf *yylstate [YYLMAX], **yylsp, **yyolsp; +char yysbuf[YYLMAX]; +char *yysptr = yysbuf; +int *yyfnd; +extern struct yysvf *yyestate; +int yyprevious = YYNEWLINE; +yylook(){ + register struct yysvf *yystate, **lsp; + register struct yywork *yyt; + struct yysvf *yyz; + int yych; + struct yywork *yyr; +# ifdef LEXDEBUG + int debug; +# endif + char *yylastch; + /* start off machines */ +# ifdef LEXDEBUG + debug = 0; +# endif + if (!yymorfg) + yylastch = yytext; + else { + yymorfg=0; + yylastch = yytext+yyleng; + } + for(;;){ + lsp = yylstate; + yyestate = yystate = yybgin; + if (yyprevious==YYNEWLINE) yystate++; + for (;;){ +# ifdef LEXDEBUG + if(debug)fprintf(yyout,"state %d\n",yystate-yysvec-1); +# endif + yyt = yystate->yystoff; + if(yyt == yycrank){ /* may not be any transitions */ + yyz = yystate->yyother; + if(yyz == 0)break; + if(yyz->yystoff == yycrank)break; + } + *yylastch++ = yych = input(); + tryagain: +# ifdef LEXDEBUG + if(debug){ + fprintf(yyout,"char "); + allprint(yych); + putchar('\n'); + } +# endif + yyr = yyt; + if ( yyt > yycrank){ + yyt = yyr + yych; + if (yyt <= yytop && yyt->verify+yysvec == yystate){ + if(yyt->advance+yysvec == YYLERR) /* error transitions */ + {unput(*--yylastch);break;} + *lsp++ = yystate = yyt->advance+yysvec; + goto contin; + } + } +# ifdef YYOPTIM + else if(yyt < yycrank) { /* r < yycrank */ + yyt = yyr = yycrank+(yycrank-yyt); +# ifdef LEXDEBUG + if(debug)fprintf(yyout,"compressed state\n"); +# endif + yyt = yyt + yych; + if(yyt <= yytop && yyt->verify+yysvec == yystate){ + if(yyt->advance+yysvec == YYLERR) /* error transitions */ + {unput(*--yylastch);break;} + *lsp++ = yystate = yyt->advance+yysvec; + goto contin; + } + yyt = yyr + YYU(yymatch[yych]); +# ifdef LEXDEBUG + if(debug){ + fprintf(yyout,"try fall back character "); + allprint(YYU(yymatch[yych])); + putchar('\n'); + } +# endif + if(yyt <= yytop && yyt->verify+yysvec == yystate){ + if(yyt->advance+yysvec == YYLERR) /* error transition */ + {unput(*--yylastch);break;} + *lsp++ = yystate = yyt->advance+yysvec; + goto contin; + } + } + if ((yystate = yystate->yyother) && (yyt= yystate->yystoff) != yycrank){ +# ifdef LEXDEBUG + if(debug)fprintf(yyout,"fall back to state %d\n",yystate-yysvec-1); +# endif + goto tryagain; + } +# endif + else + {unput(*--yylastch);break;} + contin: +# ifdef LEXDEBUG + if(debug){ + fprintf(yyout,"state %d char ",yystate-yysvec-1); + allprint(yych); + putchar('\n'); + } +# endif + ; + } +# ifdef LEXDEBUG + if(debug){ + fprintf(yyout,"stopped at %d with ",*(lsp-1)-yysvec-1); + allprint(yych); + putchar('\n'); + } +# endif + while (lsp-- > yylstate){ + *yylastch-- = 0; + if (*lsp != 0 && (yyfnd= (*lsp)->yystops) && *yyfnd > 0){ + yyolsp = lsp; + if(yyextra[*yyfnd]){ /* must backup */ + while(yyback((*lsp)->yystops,-*yyfnd) != 1 && lsp > yylstate){ + lsp--; + unput(*yylastch--); + } + } + yyprevious = YYU(*yylastch); + yylsp = lsp; + yyleng = yylastch-yytext+1; + yytext[yyleng] = 0; +# ifdef LEXDEBUG + if(debug){ + fprintf(yyout,"\nmatch "); + sprint(yytext); + fprintf(yyout," action %d\n",*yyfnd); + } +# endif + return(*yyfnd++); + } + unput(*yylastch); + } + if (yytext[0] == 0 /* && feof(yyin) */) + { + yysptr=yysbuf; + return(0); + } + yyprevious = yytext[0] = input(); + if (yyprevious>0) + output(yyprevious); + yylastch=yytext; +# ifdef LEXDEBUG + if(debug)putchar('\n'); +# endif + } + } +yyback(p, m) + int *p; +{ +if (p==0) return(0); +while (*p) + { + if (*p++ == m) + return(1); + } +return(0); +} + /* the following are only used in the lex library */ +yyinput(){ + return(input()); + } +yyoutput(c) + int c; { + output(c); + } +yyunput(c) + int c; { + unput(c); + } + +main() { + yyin = stdin; yyout = stdout; + yyparse(); + return 0; +} + +/* yyerror - issue error message */ +yyerror(s) char *s; { + printf("%s\n", s); +} +short yyexca[] ={ +-1, 1, + 0, -1, + -2, 0, + }; +# define YYNPROD 15 +# define YYLAST 249 +short yyact[]={ + + 12, 2, 9, 8, 17, 11, 25, 17, 15, 18, + 16, 10, 18, 17, 15, 7, 16, 13, 18, 5, + 3, 1, 0, 19, 20, 0, 0, 21, 22, 23, + 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 6, 14, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 4, 6 }; +short yypact[]={ + +-1000, -9,-1000, 5, -7, -59,-1000,-1000,-1000, -40, + -29, -40, -40,-1000,-1000, -40, -40, -40, -40, -38, + -35, -38, -38,-1000,-1000,-1000 }; +short yypgo[]={ + + 0, 21, 20, 17, 11 }; +short yyr1[]={ + + 0, 1, 1, 1, 1, 2, 4, 4, 4, 4, + 4, 4, 4, 4, 3 }; +short yyr2[]={ + + 0, 0, 2, 3, 3, 3, 3, 3, 3, 3, + 2, 3, 1, 1, 1 }; +short yychk[]={ + +-1000, -1, 10, -2, 256, -3, 257, 10, 10, 61, + -4, 45, 40, -3, 258, 43, 45, 42, 47, -4, + -4, -4, -4, -4, -4, 41 }; +short yydef[]={ + + 1, -2, 2, 0, 0, 0, 14, 3, 4, 0, + 5, 0, 0, 12, 13, 0, 0, 0, 0, 10, + 0, 6, 7, 8, 9, 11 }; +#ifndef lint +#endif + +# define YYFLAG -1000 +# define YYERROR goto yyerrlab +# define YYACCEPT return(0) +# define YYABORT return(1) + +/* parser for yacc output */ + +#ifdef YYDEBUG +int yydebug = 0; /* 1 for debugging */ +#endif +YYSTYPE yyv[YYMAXDEPTH]; /* where the values are stored */ +int yychar = -1; /* current input token number */ +int yynerrs = 0; /* number of errors */ +short yyerrflag = 0; /* error recovery flag */ + +yyparse() { + + short yys[YYMAXDEPTH]; + short yyj, yym; + register YYSTYPE *yypvt; + register short yystate, *yyps, yyn; + register YYSTYPE *yypv; + register short *yyxi; + + yystate = 0; + yychar = -1; + yynerrs = 0; + yyerrflag = 0; + yyps= &yys[-1]; + yypv= &yyv[-1]; + + yystack: /* put a state and value onto the stack */ + +#ifdef YYDEBUG + if( yydebug ) printf( "state %d, char 0%o\n", yystate, yychar ); +#endif + if( ++yyps> &yys[YYMAXDEPTH-1] ) { yyerror( "yacc stack overflow" ); return(1); } + *yyps = yystate; + ++yypv; + *yypv = yyval; + + yynewstate: + + yyn = yypact[yystate]; + + if( yyn<= YYFLAG ) goto yydefault; /* simple state */ + + if( yychar<0 ) if( (yychar=yylex())<0 ) yychar=0; + if( (yyn += yychar)<0 || yyn >= YYLAST ) goto yydefault; + + if( yychk[ yyn=yyact[ yyn ] ] == yychar ){ /* valid shift */ + yychar = -1; + yyval = yylval; + yystate = yyn; + if( yyerrflag > 0 ) --yyerrflag; + goto yystack; + } + + yydefault: + /* default state action */ + + if( (yyn=yydef[yystate]) == -2 ) { + if( yychar<0 ) if( (yychar=yylex())<0 ) yychar = 0; + /* look through exception table */ + + for( yyxi=yyexca; (*yyxi!= (-1)) || (yyxi[1]!=yystate) ; yyxi += 2 ) ; /* VOID */ + + while( *(yyxi+=2) >= 0 ){ + if( *yyxi == yychar ) break; + } + if( (yyn = yyxi[1]) < 0 ) return(0); /* accept */ + } + + if( yyn == 0 ){ /* error */ + /* error ... attempt to resume parsing */ + + switch( yyerrflag ){ + + case 0: /* brand new error */ + + yyerror( "syntax error" ); + yyerrlab: + ++yynerrs; + + case 1: + case 2: /* incompletely recovered error ... try again */ + + yyerrflag = 3; + + /* find a state where "error" is a legal shift action */ + + while ( yyps >= yys ) { + yyn = yypact[*yyps] + YYERRCODE; + if( yyn>= 0 && yyn < YYLAST && yychk[yyact[yyn]] == YYERRCODE ){ + yystate = yyact[yyn]; /* simulate a shift of "error" */ + goto yystack; + } + yyn = yypact[*yyps]; + + /* the current yyps has no shift onn "error", pop stack */ + +#ifdef YYDEBUG + if( yydebug ) printf( "error recovery pops state %d, uncovers %d\n", *yyps, yyps[-1] ); +#endif + --yyps; + --yypv; + } + + /* there is no state on the stack with an error shift ... abort */ + + yyabort: + return(1); + + + case 3: /* no shift yet; clobber input char */ + +#ifdef YYDEBUG + if( yydebug ) printf( "error recovery discards char %d\n", yychar ); +#endif + + if( yychar == 0 ) goto yyabort; /* don't discard EOF, quit */ + yychar = -1; + goto yynewstate; /* try again in the same state */ + + } + + } + + /* reduction by production yyn */ + +#ifdef YYDEBUG + if( yydebug ) printf("reduce %d\n",yyn); +#endif + yyps -= yyr2[yyn]; + yypvt = yypv; + yypv -= yyr2[yyn]; + yyval = yypv[1]; + yym=yyn; + /* consult goto table to find next state */ + yyn = yyr1[yyn]; + yyj = yypgo[yyn] + *yyps + 1; + if( yyj>=YYLAST || yychk[ yystate = yyact[yyj] ] != -yyn ) yystate = yyact[yypgo[yyn]]; + switch(yym){ + +case 4: +{ yyerrok; } break; +case 5: +{ printf("store\n"); } break; +case 6: +{ printf("add\n"); } break; +case 7: +{ printf("negate\nadd\n"); } break; +case 8: +{ printf("multiply\n"); } break; +case 9: +{ printf("divide\n"); } break; +case 10: +{ printf("negate\n"); } break; +case 12: +{ printf("load\n"); } break; +case 13: +{ printf("push %s\n", yytext); } break; +case 14: +{ printf("%s\n", yytext); } break; + } + goto yystack; /* stack new state and value */ + + } +int yywrap() { return 1; } diff --git a/src/cmd/lccom/types.c b/src/cmd/lccom/types.c new file mode 100644 index 0000000..115fa79 --- /dev/null +++ b/src/cmd/lccom/types.c @@ -0,0 +1,754 @@ +#include "c.h" +#include + +static Field isfield(const char *, Field); +static Type type(int, Type, int, int, void *); + +static struct entry { + struct type type; + struct entry *link; +} *typetable[128]; +static int maxlevel; + +static Symbol pointersym; + +Type chartype; /* char */ +Type doubletype; /* double */ +Type floattype; /* float */ +Type inttype; /* signed int */ +Type longdouble; /* long double */ +Type longtype; /* long */ +Type longlong; /* long long */ +Type shorttype; /* signed short int */ +Type signedchar; /* signed char */ +Type unsignedchar; /* unsigned char */ +Type unsignedlong; /* unsigned long int */ +Type unsignedlonglong; /* unsigned long long int */ +Type unsignedshort; /* unsigned short int */ +Type unsignedtype; /* unsigned int */ +Type funcptype; /* void (*)() */ +Type charptype; /* char* */ +Type voidptype; /* void* */ +Type voidtype; /* basic types: void */ +Type unsignedptr; /* unsigned type to hold void* */ +Type signedptr; /* signed type to hold void* */ +Type widechar; /* unsigned type that represents wchar_t */ + +static Type xxinit(int op, char *name, Metrics m) { + Symbol p = install(string(name), &types, GLOBAL, PERM); + Type ty = type(op, 0, m.size, m.align, p); + + assert(ty->align == 0 || ty->size%ty->align == 0); + p->type = ty; + p->addressed = m.outofline; + switch (ty->op) { + case INT: + p->u.limits.max.i = ones(8*ty->size)>>1; + p->u.limits.min.i = -p->u.limits.max.i - 1; + break; + case UNSIGNED: + p->u.limits.max.u = ones(8*ty->size); + p->u.limits.min.u = 0; + break; + case FLOAT: + if (ty->size == sizeof (float)) + p->u.limits.max.d = FLT_MAX; +#if 0 + else if (ty->size == sizeof (long double)) + p->u.limits.max.d = LDBL_MAX; +#endif + else + p->u.limits.max.d = DBL_MAX; + p->u.limits.min.d = -p->u.limits.max.d; + break; + default: assert(0); + } + return ty; +} +static Type type(int op, Type ty, int size, int align, void *sym) { + unsigned h = (op^((unsigned long)ty>>3)) +&(NELEMS(typetable)-1); + struct entry *tn; + + if (op != FUNCTION && (op != ARRAY || size > 0)) + for (tn = typetable[h]; tn; tn = tn->link) + if (tn->type.op == op && tn->type.type == ty + && tn->type.size == size && tn->type.align == align + && tn->type.u.sym == sym) + return &tn->type; + NEW0(tn, PERM); + tn->type.op = op; + tn->type.type = ty; + tn->type.size = size; + tn->type.align = align; + tn->type.u.sym = sym; + tn->link = typetable[h]; + typetable[h] = tn; + return &tn->type; +} +void type_init(int argc, char *argv[]) { + static int inited; + int i; + + if (inited) + return; + inited = 1; + if (!IR) + return; + for (i = 1; i < argc; i++) { + int size, align, outofline; + if (strncmp(argv[i], "-unsigned_char=", 15) == 0) + IR->unsigned_char = argv[i][15] - '0'; +#define xx(name) \ + else if (sscanf(argv[i], "-" #name "=%d,%d,%d", &size, &align, &outofline) == 3) { \ + IR->name.size = size; IR->name.align = align; \ + IR->name.outofline = outofline; } + xx(charmetric) + xx(shortmetric) + xx(intmetric) + xx(longmetric) + xx(longlongmetric) + xx(floatmetric) + xx(doublemetric) + xx(longdoublemetric) + xx(ptrmetric) + xx(structmetric) +#undef xx + } +#define xx(v,name,op,metrics) v=xxinit(op,name,IR->metrics) + xx(chartype, "char", IR->unsigned_char ? UNSIGNED : INT,charmetric); + xx(doubletype, "double", FLOAT, doublemetric); + xx(floattype, "float", FLOAT, floatmetric); + xx(inttype, "int", INT, intmetric); + xx(longdouble, "long double", FLOAT, longdoublemetric); + xx(longtype, "long int", INT, longmetric); + xx(longlong, "long long int", INT, longlongmetric); + xx(shorttype, "short", INT, shortmetric); + xx(signedchar, "signed char", INT, charmetric); + xx(unsignedchar, "unsigned char", UNSIGNED,charmetric); + xx(unsignedlong, "unsigned long", UNSIGNED,longmetric); + xx(unsignedshort, "unsigned short", UNSIGNED,shortmetric); + xx(unsignedtype, "unsigned int", UNSIGNED,intmetric); + xx(unsignedlonglong,"unsigned long long",UNSIGNED,longlongmetric); +#undef xx + { + Symbol p; + p = install(string("void"), &types, GLOBAL, PERM); + voidtype = type(VOID, NULL, 0, 0, p); + p->type = voidtype; + } + pointersym = install(string("T*"), &types, GLOBAL, PERM); + pointersym->addressed = IR->ptrmetric.outofline; + pointersym->u.limits.max.p = (void*)ones(8*IR->ptrmetric.size); + pointersym->u.limits.min.p = 0; + voidptype = ptr(voidtype); + funcptype = ptr(func(voidtype, NULL, 1)); + charptype = ptr(chartype); +#define xx(v,t) if (v==NULL && t->size==voidptype->size && t->align==voidptype->align) v=t + xx(unsignedptr,unsignedshort); + xx(unsignedptr,unsignedtype); + xx(unsignedptr,unsignedlong); + xx(unsignedptr,unsignedlonglong); + if (unsignedptr == NULL) + unsignedptr = type(UNSIGNED, NULL, voidptype->size, voidptype->align, voidptype->u.sym); + xx(signedptr,shorttype); + xx(signedptr,inttype); + xx(signedptr,longtype); + xx(signedptr,longlong); + if (signedptr == NULL) + signedptr = type(INT, NULL, voidptype->size, voidptype->align, voidptype->u.sym); +#undef xx + widechar = unsignedshort; + for (i = 0; i < argc; i++) { +#define xx(name,type) \ + if (strcmp(argv[i], "-wchar_t=" #name) == 0) \ + widechar = type; + xx(unsigned_char,unsignedchar) + xx(unsigned_int,unsignedtype) + xx(unsigned_short,unsignedshort) + } +#undef xx +} +void rmtypes(int lev) { + if (maxlevel >= lev) { + int i; + maxlevel = 0; + for (i = 0; i < NELEMS(typetable); i++) { + struct entry *tn, **tq = &typetable[i]; + while ((tn = *tq) != NULL) + if (tn->type.op == FUNCTION) + tq = &tn->link; + else if (tn->type.u.sym && tn->type.u.sym->scope >= lev) + *tq = tn->link; + else { + if (tn->type.u.sym && tn->type.u.sym->scope > maxlevel) + maxlevel = tn->type.u.sym->scope; + tq = &tn->link; + } + + } + } +} +Type ptr(Type ty) { + return type(POINTER, ty, IR->ptrmetric.size, + IR->ptrmetric.align, pointersym); +} +Type deref(Type ty) { + if (isptr(ty)) + ty = ty->type; + else + error("type error: %s\n", "pointer expected"); + return isenum(ty) ? unqual(ty)->type : ty; +} +Type array(Type ty, int n, int a) { + assert(ty); + if (isfunc(ty)) { + error("illegal type `array of %t'\n", ty); + return array(inttype, n, 0); + } + if (isarray(ty) && ty->size == 0) + error("missing array size\n"); + if (ty->size == 0) { + if (unqual(ty) == voidtype) + error("illegal type `array of %t'\n", ty); + else if (Aflag >= 2) + warning("declaring type array of %t' is undefined\n", ty); + + } else if (n > INT_MAX/ty->size) { + error("size of `array of %t' exceeds %d bytes\n", + ty, INT_MAX); + n = 1; + } + return type(ARRAY, ty, n*ty->size, + a ? a : ty->align, NULL); +} +Type atop(Type ty) { + if (isarray(ty)) + return ptr(ty->type); + error("type error: %s\n", "array expected"); + return ptr(ty); +} +Type qual(int op, Type ty) { + if (isarray(ty)) + ty = type(ARRAY, qual(op, ty->type), ty->size, + ty->align, NULL); + else if (isfunc(ty)) + warning("qualified function type ignored\n"); + else if ((isconst(ty) && op == CONST) + || (isvolatile(ty) && op == VOLATILE)) + error("illegal type `%k %t'\n", op, ty); + else { + if (isqual(ty)) { + op += ty->op; + ty = ty->type; + } + ty = type(op, ty, ty->size, ty->align, NULL); + } + return ty; +} +Type func(Type ty, Type *proto, int style) { + if (ty && (isarray(ty) || isfunc(ty))) + error("illegal return type `%t'\n", ty); + ty = type(FUNCTION, ty, 0, 0, NULL); + ty->u.f.proto = proto; + ty->u.f.oldstyle = style; + return ty; +} +Type freturn(Type ty) { + if (isfunc(ty)) + return ty->type; + error("type error: %s\n", "function expected"); + return inttype; +} +int variadic(Type ty) { + if (isfunc(ty) && ty->u.f.proto) { + int i; + for (i = 0; ty->u.f.proto[i]; i++) + ; + return i > 1 && ty->u.f.proto[i-1] == voidtype; + } + return 0; +} +Type newstruct(int op, char *tag) { + Symbol p; + + assert(tag); + if (*tag == 0) + tag = stringd(genlabel(1)); + else + if ((p = lookup(tag, types)) != NULL && (p->scope == level + || (p->scope == PARAM && level == PARAM+1))) { + if (p->type->op == op && !p->defined) + return p->type; + error("redefinition of `%s' previously defined at %w\n", + p->name, &p->src); + } + p = install(tag, &types, level, PERM); + p->type = type(op, NULL, 0, 0, p); + if (p->scope > maxlevel) + maxlevel = p->scope; + p->src = src; + return p->type; +} +Field newfield(char *name, Type ty, Type fty) { + Field p, *q = &ty->u.sym->u.s.flist; + + if (name == NULL) + name = stringd(genlabel(1)); + for (p = *q; p; q = &p->link, p = *q) + if (p->name == name) + error("duplicate field name `%s' in `%t'\n", + name, ty); + NEW0(p, PERM); + *q = p; + p->name = name; + p->type = fty; + if (xref) { /* omit */ + if (ty->u.sym->u.s.ftab == NULL) /* omit */ + ty->u.sym->u.s.ftab = table(NULL, level); /* omit */ + install(name, &ty->u.sym->u.s.ftab, 0, PERM)->src = src;/* omit */ + } /* omit */ + return p; +} +int eqtype(Type ty1, Type ty2, int ret) { + if (ty1 == ty2) + return 1; + if (ty1->op != ty2->op) + return 0; + switch (ty1->op) { + case ENUM: case UNION: case STRUCT: + case UNSIGNED: case INT: case FLOAT: + return 0; + case POINTER: return eqtype(ty1->type, ty2->type, 1); + case VOLATILE: case CONST+VOLATILE: + case CONST: return eqtype(ty1->type, ty2->type, 1); + case ARRAY: if (eqtype(ty1->type, ty2->type, 1)) { + if (ty1->size == ty2->size) + return 1; + if (ty1->size == 0 || ty2->size == 0) + return ret; + } + return 0; + case FUNCTION: if (eqtype(ty1->type, ty2->type, 1)) { + Type *p1 = ty1->u.f.proto, *p2 = ty2->u.f.proto; + if (p1 == p2) + return 1; + if (p1 && p2) { + for ( ; *p1 && *p2; p1++, p2++) + if (eqtype(unqual(*p1), unqual(*p2), 1) == 0) + return 0; + if (*p1 == NULL && *p2 == NULL) + return 1; + } else { + if (variadic(p1 ? ty1 : ty2)) + return 0; + if (p1 == NULL) + p1 = p2; + for ( ; *p1; p1++) { + Type ty = unqual(*p1); + if (promote(ty) != (isenum(ty) ? ty->type : ty)) + return 0; + } + return 1; + } + } + return 0; + } + assert(0); return 0; +} +Type promote(Type ty) { + ty = unqual(ty); + switch (ty->op) { + case ENUM: + return inttype; + case INT: + if (ty->size < inttype->size) + return inttype; + break; + case UNSIGNED: + if (ty->size < inttype->size) + return inttype; + if (ty->size < unsignedtype->size) + return unsignedtype; + break; + case FLOAT: + if (ty->size < doubletype->size) + return doubletype; + } + return ty; +} +Type signedint(Type ty) { + if (ty->op == INT) + return ty; + assert(ty->op == UNSIGNED); +#define xx(t) if (ty->size == t->size) return t + xx(inttype); + xx(longtype); + xx(longlong); +#undef xx + assert(0); return NULL; +} +Type compose(Type ty1, Type ty2) { + if (ty1 == ty2) + return ty1; + assert(ty1->op == ty2->op); + switch (ty1->op) { + case POINTER: + return ptr(compose(ty1->type, ty2->type)); + case CONST+VOLATILE: + return qual(CONST, qual(VOLATILE, + compose(ty1->type, ty2->type))); + case CONST: case VOLATILE: + return qual(ty1->op, compose(ty1->type, ty2->type)); + case ARRAY: { Type ty = compose(ty1->type, ty2->type); + if (ty1->size && ((ty1->type->size && ty2->size == 0) || ty1->size == ty2->size)) + return array(ty, ty1->size/ty1->type->size, ty1->align); + if (ty2->size && ty2->type->size && ty1->size == 0) + return array(ty, ty2->size/ty2->type->size, ty2->align); + return array(ty, 0, 0); } + case FUNCTION: { Type *p1 = ty1->u.f.proto, *p2 = ty2->u.f.proto; + Type ty = compose(ty1->type, ty2->type); + List tlist = NULL; + if (p1 == NULL && p2 == NULL) + return func(ty, NULL, 1); + if (p1 && p2 == NULL) + return func(ty, p1, ty1->u.f.oldstyle); + if (p2 && p1 == NULL) + return func(ty, p2, ty2->u.f.oldstyle); + for ( ; *p1 && *p2; p1++, p2++) { + Type ty = compose(unqual(*p1), unqual(*p2)); + if (isconst(*p1) || isconst(*p2)) + ty = qual(CONST, ty); + if (isvolatile(*p1) || isvolatile(*p2)) + ty = qual(VOLATILE, ty); + tlist = append(ty, tlist); + } + assert(*p1 == NULL && *p2 == NULL); + return func(ty, ltov(&tlist, PERM), 0); } + } + assert(0); return NULL; +} +int ttob(Type ty) { + switch (ty->op) { + case CONST: case VOLATILE: case CONST+VOLATILE: + return ttob(ty->type); + case VOID: case INT: case UNSIGNED: case FLOAT: + return ty->op + sizeop(ty->size); + case POINTER: + return POINTER + sizeop(voidptype->size); + case FUNCTION: + return POINTER + sizeop(funcptype->size); + case ARRAY: case STRUCT: case UNION: + return STRUCT; + case ENUM: + return INT + sizeop(inttype->size); + } + assert(0); return INT; +} +Type btot(int op, int size) { +#define xx(ty) if (size == (ty)->size) return ty; + switch (optype(op)) { + case F: + xx(floattype); + xx(doubletype); + xx(longdouble); + assert(0); return 0; + case I: + if (chartype->op == INT) + xx(chartype); + xx(signedchar); + xx(shorttype); + xx(inttype); + xx(longtype); + xx(longlong); + assert(0); return 0; + case U: + if (chartype->op == UNSIGNED) + xx(chartype); + xx(unsignedchar); + xx(unsignedshort); + xx(unsignedtype); + xx(unsignedlong); + xx(unsignedlonglong); + assert(0); return 0; + case P: + xx(voidptype); + xx(funcptype); + assert(0); return 0; + } +#undef xx + assert(0); return 0; +} +int hasproto(Type ty) { + if (ty == 0) + return 1; + switch (ty->op) { + case CONST: case VOLATILE: case CONST+VOLATILE: case POINTER: + case ARRAY: + return hasproto(ty->type); + case FUNCTION: + return hasproto(ty->type) && ty->u.f.proto; + case STRUCT: case UNION: + case VOID: case FLOAT: case ENUM: case INT: case UNSIGNED: + return 1; + } + assert(0); return 0; +} +/* fieldlist - construct a flat list of fields in type ty */ +Field fieldlist(Type ty) { + return ty->u.sym->u.s.flist; +} + +/* fieldref - find field name of type ty, return entry */ +Field fieldref(const char *name, Type ty) { + Field p = isfield(name, unqual(ty)->u.sym->u.s.flist); + + if (p && xref) { + Symbol q; + assert(unqual(ty)->u.sym->u.s.ftab); + q = lookup(name, unqual(ty)->u.sym->u.s.ftab); + assert(q); + use(q, src); + } + return p; +} + +/* ftype - return a function type for rty function (ty,...)' */ +Type ftype(Type rty, ...) { + va_list ap; + Type ty = NULL; + List list = NULL; + + va_start(ap, rty); + ty = va_arg(ap, Type); + for ( ; ty != NULL; ty = va_arg(ap, Type)) + list = append(ty, list); + va_end(ap); + return func(rty, ltov(&list, PERM), 0); +} + +/* isfield - if name is a field in flist, return pointer to the field structure */ +static Field isfield(const char *name, Field flist) { + for ( ; flist; flist = flist->link) + if (flist->name == name) + break; + return flist; +} + +/* outtype - output type ty */ +void outtype(Type ty, FILE *f) { + switch (ty->op) { + case CONST+VOLATILE: case CONST: case VOLATILE: + fprint(f, "%k %t", ty->op, ty->type); + break; + case STRUCT: case UNION: case ENUM: + assert(ty->u.sym); + if (ty->size == 0) + fprint(f, "incomplete "); + assert(ty->u.sym->name); + if (*ty->u.sym->name >= '1' && *ty->u.sym->name <= '9') { + Symbol p = findtype(ty); + if (p == 0) + fprint(f, "%k defined at %w", ty->op, &ty->u.sym->src); + else + fprint(f, p->name); + } else { + fprint(f, "%k %s", ty->op, ty->u.sym->name); + if (ty->size == 0) + fprint(f, " defined at %w", &ty->u.sym->src); + } + break; + case VOID: case FLOAT: case INT: case UNSIGNED: + fprint(f, ty->u.sym->name); + break; + case POINTER: + fprint(f, "pointer to %t", ty->type); + break; + case FUNCTION: + fprint(f, "%t function", ty->type); + if (ty->u.f.proto && ty->u.f.proto[0]) { + int i; + fprint(f, "(%t", ty->u.f.proto[0]); + for (i = 1; ty->u.f.proto[i]; i++) + if (ty->u.f.proto[i] == voidtype) + fprint(f, ",..."); + else + fprint(f, ",%t", ty->u.f.proto[i]); + fprint(f, ")"); + } else if (ty->u.f.proto && ty->u.f.proto[0] == 0) + fprint(f, "(void)"); + + break; + case ARRAY: + if (ty->size > 0 && ty->type && ty->type->size > 0) { + fprint(f, "array %d", ty->size/ty->type->size); + while (ty->type && isarray(ty->type) && ty->type->type->size > 0) { + ty = ty->type; + fprint(f, ",%d", ty->size/ty->type->size); + } + } else + fprint(f, "incomplete array"); + if (ty->type) + fprint(f, " of %t", ty->type); + break; + default: assert(0); + } +} + +/* printdecl - output a C declaration for symbol p of type ty */ +void printdecl(Symbol p, Type ty) { + switch (p->sclass) { + case AUTO: + fprint(stderr, "%s;\n", typestring(ty, p->name)); + break; + case STATIC: case EXTERN: + fprint(stderr, "%k %s;\n", p->sclass, typestring(ty, p->name)); + break; + case TYPEDEF: case ENUM: + break; + default: assert(0); + } +} + +/* printproto - output a prototype declaration for function p */ +void printproto(Symbol p, Symbol callee[]) { + if (p->type->u.f.proto) + printdecl(p, p->type); + else { + int i; + List list = 0; + if (callee[0] == 0) + list = append(voidtype, list); + else + for (i = 0; callee[i]; i++) + list = append(callee[i]->type, list); + printdecl(p, func(freturn(p->type), ltov(&list, PERM), 0)); + } +} + +/* prtype - print details of type ty on f with given indent */ +static void prtype(Type ty, FILE *f, int indent, unsigned mark) { + switch (ty->op) { + default: + fprint(f, "(%d %d %d [%p])", ty->op, ty->size, ty->align, ty->u.sym); + break; + case FLOAT: case INT: case UNSIGNED: case VOID: + fprint(f, "(%k %d %d [\"%s\"])", ty->op, ty->size, ty->align, ty->u.sym->name); + break; + case CONST+VOLATILE: case CONST: case VOLATILE: case POINTER: case ARRAY: + fprint(f, "(%k %d %d ", ty->op, ty->size, ty->align); + prtype(ty->type, f, indent+1, mark); + fprint(f, ")"); + break; + case STRUCT: case UNION: + fprint(f, "(%k %d %d [\"%s\"]", ty->op, ty->size, ty->align, ty->u.sym->name); + if (ty->x.marked != mark) { + Field p; + ty->x.marked = mark; + for (p = ty->u.sym->u.s.flist; p; p = p->link) { + fprint(f, "\n%I", indent+1); + prtype(p->type, f, indent+1, mark); + fprint(f, " %s@%d", p->name, p->offset); + if (p->lsb) + fprint(f, ":%d..%d", + fieldsize(p) + fieldright(p), fieldright(p)); + } + fprint(f, "\n%I", indent); + } + fprint(f, ")"); + break; + case ENUM: + fprint(f, "(%k %d %d [\"%s\"]", ty->op, ty->size, ty->align, ty->u.sym->name); + if (ty->x.marked != mark) { + int i; + Symbol *p = ty->u.sym->u.idlist; + ty->x.marked = mark; + for (i = 0; p[i] != NULL; i++) + fprint(f, "%I%s=%d\n", indent+1, p[i]->name, p[i]->u.value); + } + fprint(f, ")"); + break; + case FUNCTION: + fprint(f, "(%k %d %d ", ty->op, ty->size, ty->align); + prtype(ty->type, f, indent+1, mark); + if (ty->u.f.proto) { + int i; + fprint(f, "\n%I{", indent+1); + for (i = 0; ty->u.f.proto[i]; i++) { + if (i > 0) + fprint(f, "%I", indent+2); + prtype(ty->u.f.proto[i], f, indent+2, mark); + fprint(f, "\n"); + } + fprint(f, "%I}", indent+1); + } + fprint(f, ")"); + break; + } +} + +/* printtype - print details of type ty on fd */ +void printtype(Type ty, int fd) { + static unsigned mark; + prtype(ty, fd == 1 ? stdout : stderr, 0, ++mark); + fprint(fd == 1 ? stdout : stderr, "\n"); +} + +/* typestring - return ty as C declaration for str, which may be "" */ +char *typestring(Type ty, char *str) { + for ( ; ty; ty = ty->type) { + Symbol p; + switch (ty->op) { + case CONST+VOLATILE: case CONST: case VOLATILE: + if (isptr(ty->type)) + str = stringf("%k %s", ty->op, str); + else + return stringf("%k %s", ty->op, typestring(ty->type, str)); + break; + case STRUCT: case UNION: case ENUM: + assert(ty->u.sym); + if ((p = findtype(ty)) != NULL) + return *str ? stringf("%s %s", p->name, str) : p->name; + if (*ty->u.sym->name >= '1' && *ty->u.sym->name <= '9') + warning("unnamed %k in prototype\n", ty->op); + if (*str) + return stringf("%k %s %s", ty->op, ty->u.sym->name, str); + else + return stringf("%k %s", ty->op, ty->u.sym->name); + case VOID: case FLOAT: case INT: case UNSIGNED: + return *str ? stringf("%s %s", ty->u.sym->name, str) : ty->u.sym->name; + case POINTER: + if (!ischar(ty->type) && (p = findtype(ty)) != NULL) + return *str ? stringf("%s %s", p->name, str) : p->name; + str = stringf(isarray(ty->type) || isfunc(ty->type) ? "(*%s)" : "*%s", str); + break; + case FUNCTION: + if ((p = findtype(ty)) != NULL) + return *str ? stringf("%s %s", p->name, str) : p->name; + if (ty->u.f.proto == 0) + str = stringf("%s()", str); + else if (ty->u.f.proto[0]) { + int i; + str = stringf("%s(%s", str, typestring(ty->u.f.proto[0], "")); + for (i = 1; ty->u.f.proto[i]; i++) + if (ty->u.f.proto[i] == voidtype) + str = stringf("%s, ...", str); + else + str = stringf("%s, %s", str, typestring(ty->u.f.proto[i], "")); + str = stringf("%s)", str); + } else + str = stringf("%s(void)", str); + break; + case ARRAY: + if ((p = findtype(ty)) != NULL) + return *str ? stringf("%s %s", p->name, str) : p->name; + if (ty->type && ty->type->size > 0) + str = stringf("%s[%d]", str, ty->size/ty->type->size); + else + str = stringf("%s[]", str); + break; + default: assert(0); + } + } + assert(0); return 0; +} diff --git a/src/cmd/lccom/x86.md b/src/cmd/lccom/x86.md new file mode 100644 index 0000000..1e134b2 --- /dev/null +++ b/src/cmd/lccom/x86.md @@ -0,0 +1,1011 @@ +%{ +enum { EAX=0, ECX=1, EDX=2, EBX=3, ESI=6, EDI=7 }; +#include "c.h" +#define NODEPTR_TYPE Node +#define OP_LABEL(p) ((p)->op) +#define LEFT_CHILD(p) ((p)->kids[0]) +#define RIGHT_CHILD(p) ((p)->kids[1]) +#define STATE_LABEL(p) ((p)->x.state) +static void address(Symbol, Symbol, long); +static void blkfetch(int, int, int, int); +static void blkloop(int, int, int, int, int, int[]); +static void blkstore(int, int, int, int); +static void defaddress(Symbol); +static void defconst(int, int, Value); +static void defstring(int, char *); +static void defsymbol(Symbol); +static void doarg(Node); +static void emit2(Node); +static void export(Symbol); +static void clobber(Node); +static void function(Symbol, Symbol [], Symbol [], int); +static void global(Symbol); +static void import(Symbol); +static void local(Symbol); +static void progbeg(int, char **); +static void progend(void); +static void segment(int); +static void space(int); +static void target(Node); +extern int ckstack(Node, int); +extern int memop(Node); +extern int sametree(Node, Node); +static Symbol charreg[32], shortreg[32], intreg[32]; +static Symbol fltreg[32]; + +static Symbol charregw, shortregw, intregw, fltregw; + +static int cseg; + +static Symbol quo, rem; + +%} +%start stmt +%term CNSTF4=4113 +%term CNSTF8=8209 +%term CNSTF16=16401 +%term CNSTI1=1045 +%term CNSTI2=2069 +%term CNSTI4=4117 +%term CNSTI8=8213 +%term CNSTP4=4119 +%term CNSTP8=8215 +%term CNSTU1=1046 +%term CNSTU2=2070 +%term CNSTU4=4118 +%term CNSTU8=8214 + +%term ARGB=41 +%term ARGF4=4129 +%term ARGF8=8225 +%term ARGF16=16417 +%term ARGI4=4133 +%term ARGI8=8229 +%term ARGP4=4135 +%term ARGP8=8231 +%term ARGU4=4134 +%term ARGU8=8230 + +%term ASGNB=57 +%term ASGNF4=4145 +%term ASGNF8=8241 +%term ASGNF16=16433 +%term ASGNI1=1077 +%term ASGNI2=2101 +%term ASGNI4=4149 +%term ASGNI8=8245 +%term ASGNP4=4151 +%term ASGNP8=8247 +%term ASGNU1=1078 +%term ASGNU2=2102 +%term ASGNU4=4150 +%term ASGNU8=8246 + +%term INDIRB=73 +%term INDIRF4=4161 +%term INDIRF8=8257 +%term INDIRF16=16449 +%term INDIRI1=1093 +%term INDIRI2=2117 +%term INDIRI4=4165 +%term INDIRI8=8261 +%term INDIRP4=4167 +%term INDIRP8=8263 +%term INDIRU1=1094 +%term INDIRU2=2118 +%term INDIRU4=4166 +%term INDIRU8=8262 + +%term CVFF4=4209 +%term CVFF8=8305 +%term CVFF16=16497 +%term CVFI4=4213 +%term CVFI8=8309 + +%term CVIF4=4225 +%term CVIF8=8321 +%term CVIF16=16513 +%term CVII1=1157 +%term CVII2=2181 +%term CVII4=4229 +%term CVII8=8325 +%term CVIU1=1158 +%term CVIU2=2182 +%term CVIU4=4230 +%term CVIU8=8326 + +%term CVPP4=4247 +%term CVPP8=8343 +%term CVPP16=16535 +%term CVPU4=4246 +%term CVPU8=8342 + +%term CVUI1=1205 +%term CVUI2=2229 +%term CVUI4=4277 +%term CVUI8=8373 +%term CVUP4=4279 +%term CVUP8=8375 +%term CVUP16=16567 +%term CVUU1=1206 +%term CVUU2=2230 +%term CVUU4=4278 +%term CVUU8=8374 + +%term NEGF4=4289 +%term NEGF8=8385 +%term NEGF16=16577 +%term NEGI4=4293 +%term NEGI8=8389 + +%term CALLB=217 +%term CALLF4=4305 +%term CALLF8=8401 +%term CALLF16=16593 +%term CALLI4=4309 +%term CALLI8=8405 +%term CALLP4=4311 +%term CALLP8=8407 +%term CALLU4=4310 +%term CALLU8=8406 +%term CALLV=216 + +%term RETF4=4337 +%term RETF8=8433 +%term RETF16=16625 +%term RETI4=4341 +%term RETI8=8437 +%term RETP4=4343 +%term RETP8=8439 +%term RETU4=4342 +%term RETU8=8438 +%term RETV=248 + +%term ADDRGP4=4359 +%term ADDRGP8=8455 + +%term ADDRFP4=4375 +%term ADDRFP8=8471 + +%term ADDRLP4=4391 +%term ADDRLP8=8487 + +%term ADDF4=4401 +%term ADDF8=8497 +%term ADDF16=16689 +%term ADDI4=4405 +%term ADDI8=8501 +%term ADDP4=4407 +%term ADDP8=8503 +%term ADDU4=4406 +%term ADDU8=8502 + +%term SUBF4=4417 +%term SUBF8=8513 +%term SUBF16=16705 +%term SUBI4=4421 +%term SUBI8=8517 +%term SUBP4=4423 +%term SUBP8=8519 +%term SUBU4=4422 +%term SUBU8=8518 + +%term LSHI4=4437 +%term LSHI8=8533 +%term LSHU4=4438 +%term LSHU8=8534 + +%term MODI4=4453 +%term MODI8=8549 +%term MODU4=4454 +%term MODU8=8550 + +%term RSHI4=4469 +%term RSHI8=8565 +%term RSHU4=4470 +%term RSHU8=8566 + +%term BANDI4=4485 +%term BANDI8=8581 +%term BANDU4=4486 +%term BANDU8=8582 + +%term BCOMI4=4501 +%term BCOMI8=8597 +%term BCOMU4=4502 +%term BCOMU8=8598 + +%term BORI4=4517 +%term BORI8=8613 +%term BORU4=4518 +%term BORU8=8614 + +%term BXORI4=4533 +%term BXORI8=8629 +%term BXORU4=4534 +%term BXORU8=8630 + +%term DIVF4=4545 +%term DIVF8=8641 +%term DIVF16=16833 +%term DIVI4=4549 +%term DIVI8=8645 +%term DIVU4=4550 +%term DIVU8=8646 + +%term MULF4=4561 +%term MULF8=8657 +%term MULF16=16849 +%term MULI4=4565 +%term MULI8=8661 +%term MULU4=4566 +%term MULU8=8662 + +%term EQF4=4577 +%term EQF8=8673 +%term EQF16=16865 +%term EQI4=4581 +%term EQI8=8677 +%term EQU4=4582 +%term EQU8=8678 + +%term GEF4=4593 +%term GEF8=8689 +%term GEI4=4597 +%term GEI8=8693 +%term GEI16=16885 +%term GEU4=4598 +%term GEU8=8694 + +%term GTF4=4609 +%term GTF8=8705 +%term GTF16=16897 +%term GTI4=4613 +%term GTI8=8709 +%term GTU4=4614 +%term GTU8=8710 + +%term LEF4=4625 +%term LEF8=8721 +%term LEF16=16913 +%term LEI4=4629 +%term LEI8=8725 +%term LEU4=4630 +%term LEU8=8726 + +%term LTF4=4641 +%term LTF8=8737 +%term LTF16=16929 +%term LTI4=4645 +%term LTI8=8741 +%term LTU4=4646 +%term LTU8=8742 + +%term NEF4=4657 +%term NEF8=8753 +%term NEF16=16945 +%term NEI4=4661 +%term NEI8=8757 +%term NEU4=4662 +%term NEU8=8758 + +%term JUMPV=584 + +%term LABELV=600 + +%term LOADB=233 +%term LOADF4=4321 +%term LOADF8=8417 +%term LOADF16=16609 +%term LOADI1=1253 +%term LOADI2=2277 +%term LOADI4=4325 +%term LOADI8=8421 +%term LOADP4=4327 +%term LOADP8=8423 +%term LOADU1=1254 +%term LOADU2=2278 +%term LOADU4=4326 +%term LOADU8=8422 + +%term VREGP=711 +%% +reg: INDIRI1(VREGP) "# read register\n" +reg: INDIRU1(VREGP) "# read register\n" + +reg: INDIRI2(VREGP) "# read register\n" +reg: INDIRU2(VREGP) "# read register\n" + +reg: INDIRF4(VREGP) "# read register\n" +reg: INDIRI4(VREGP) "# read register\n" +reg: INDIRP4(VREGP) "# read register\n" +reg: INDIRU4(VREGP) "# read register\n" + +reg: INDIRF8(VREGP) "# read register\n" +reg: INDIRI8(VREGP) "# read register\n" +reg: INDIRP8(VREGP) "# read register\n" +reg: INDIRU8(VREGP) "# read register\n" + +stmt: ASGNI1(VREGP,reg) "# write register\n" +stmt: ASGNU1(VREGP,reg) "# write register\n" + +stmt: ASGNI2(VREGP,reg) "# write register\n" +stmt: ASGNU2(VREGP,reg) "# write register\n" + +stmt: ASGNF4(VREGP,reg) "# write register\n" +stmt: ASGNI4(VREGP,reg) "# write register\n" +stmt: ASGNP4(VREGP,reg) "# write register\n" +stmt: ASGNU4(VREGP,reg) "# write register\n" + +stmt: ASGNF8(VREGP,reg) "# write register\n" +stmt: ASGNI8(VREGP,reg) "# write register\n" +stmt: ASGNP8(VREGP,reg) "# write register\n" +stmt: ASGNU8(VREGP,reg) "# write register\n" +con: CNSTI1 "%a" +con: CNSTU1 "%a" + +con: CNSTI2 "%a" +con: CNSTU2 "%a" + +con: CNSTI4 "%a" +con: CNSTU4 "%a" +con: CNSTP4 "%a" + +con: CNSTI8 "%a" +con: CNSTU8 "%a" +con: CNSTP8 "%a" +stmt: reg "" +acon: ADDRGP4 "(%a)" +acon: con "(%0)" +base: ADDRGP4 "(%a)" +base: reg "[%0]" +base: ADDI4(reg,acon) "%1[%0]" +base: ADDP4(reg,acon) "%1[%0]" +base: ADDU4(reg,acon) "%1[%0]" +base: ADDRFP4 "(%a)[ebp]" +base: ADDRLP4 "(%a)[ebp]" +index: reg "%0" +index: LSHI4(reg,con1) "%0*2" +index: LSHI4(reg,con2) "%0*4" +index: LSHI4(reg,con3) "%0*8" + +con1: CNSTI4 "1" range(a, 1, 1) +con1: CNSTU4 "1" range(a, 1, 1) +con2: CNSTI4 "2" range(a, 2, 2) +con2: CNSTU4 "2" range(a, 2, 2) +con3: CNSTI4 "3" range(a, 3, 3) +con3: CNSTU4 "3" range(a, 3, 3) +index: LSHU4(reg,con1) "%0*2" +index: LSHU4(reg,con2) "%0*4" +index: LSHU4(reg,con3) "%0*8" +addr: base "%0" +addr: ADDI4(index,base) "%1[%0]" +addr: ADDP4(index,base) "%1[%0]" +addr: ADDU4(index,base) "%1[%0]" +addr: index "[%0]" +mem: INDIRI1(addr) "byte ptr %0" +mem: INDIRI2(addr) "word ptr %0" +mem: INDIRI4(addr) "dword ptr %0" +mem: INDIRU1(addr) "byte ptr %0" +mem: INDIRU2(addr) "word ptr %0" +mem: INDIRU4(addr) "dword ptr %0" +mem: INDIRP4(addr) "dword ptr %0" +rc: reg "%0" +rc: con "%0" + +mr: reg "%0" +mr: mem "%0" + +mrc0: mem "%0" +mrc0: rc "%0" +mrc1: mem "%0" 1 +mrc1: rc "%0" + +mrc3: mem "%0" 3 +mrc3: rc "%0" +reg: addr "lea %c,%0\n" 1 +reg: mrc0 "mov %c,%0\n" 1 +reg: LOADI1(reg) "# move\n" 1 +reg: LOADI2(reg) "# move\n" 1 +reg: LOADI4(reg) "# move\n" move(a) +reg: LOADU1(reg) "# move\n" 1 +reg: LOADU2(reg) "# move\n" 1 +reg: LOADU4(reg) "# move\n" move(a) +reg: LOADP4(reg) "# move\n" move(a) +reg: ADDI4(reg,mrc1) "?mov %c,%0\nadd %c,%1\n" 1 +reg: ADDP4(reg,mrc1) "?mov %c,%0\nadd %c,%1\n" 1 +reg: ADDU4(reg,mrc1) "?mov %c,%0\nadd %c,%1\n" 1 +reg: SUBI4(reg,mrc1) "?mov %c,%0\nsub %c,%1\n" 1 +reg: SUBP4(reg,mrc1) "?mov %c,%0\nsub %c,%1\n" 1 +reg: SUBU4(reg,mrc1) "?mov %c,%0\nsub %c,%1\n" 1 +reg: BANDI4(reg,mrc1) "?mov %c,%0\nand %c,%1\n" 1 +reg: BORI4(reg,mrc1) "?mov %c,%0\nor %c,%1\n" 1 +reg: BXORI4(reg,mrc1) "?mov %c,%0\nxor %c,%1\n" 1 +reg: BANDU4(reg,mrc1) "?mov %c,%0\nand %c,%1\n" 1 +reg: BORU4(reg,mrc1) "?mov %c,%0\nor %c,%1\n" 1 +reg: BXORU4(reg,mrc1) "?mov %c,%0\nxor %c,%1\n" 1 +stmt: ASGNI4(addr,ADDI4(mem,con1)) "inc %1\n" memop(a) +stmt: ASGNI4(addr,ADDU4(mem,con1)) "inc %1\n" memop(a) +stmt: ASGNP4(addr,ADDP4(mem,con1)) "inc %1\n" memop(a) +stmt: ASGNI4(addr,SUBI4(mem,con1)) "dec %1\n" memop(a) +stmt: ASGNI4(addr,SUBU4(mem,con1)) "dec %1\n" memop(a) +stmt: ASGNP4(addr,SUBP4(mem,con1)) "dec %1\n" memop(a) +stmt: ASGNI4(addr,ADDI4(mem,rc)) "add %1,%2\n" memop(a) +stmt: ASGNI4(addr,SUBI4(mem,rc)) "sub %1,%2\n" memop(a) +stmt: ASGNU4(addr,ADDU4(mem,rc)) "add %1,%2\n" memop(a) +stmt: ASGNU4(addr,SUBU4(mem,rc)) "sub %1,%2\n" memop(a) + +stmt: ASGNI4(addr,BANDI4(mem,rc)) "and %1,%2\n" memop(a) +stmt: ASGNI4(addr,BORI4(mem,rc)) "or %1,%2\n" memop(a) +stmt: ASGNI4(addr,BXORI4(mem,rc)) "xor %1,%2\n" memop(a) +stmt: ASGNU4(addr,BANDU4(mem,rc)) "and %1,%2\n" memop(a) +stmt: ASGNU4(addr,BORU4(mem,rc)) "or %1,%2\n" memop(a) +stmt: ASGNU4(addr,BXORU4(mem,rc)) "xor %1,%2\n" memop(a) +reg: BCOMI4(reg) "?mov %c,%0\nnot %c\n" 2 +reg: BCOMU4(reg) "?mov %c,%0\nnot %c\n" 2 +reg: NEGI4(reg) "?mov %c,%0\nneg %c\n" 2 + +stmt: ASGNI4(addr,BCOMI4(mem)) "not %1\n" memop(a) +stmt: ASGNU4(addr,BCOMU4(mem)) "not %1\n" memop(a) +stmt: ASGNI4(addr,NEGI4(mem)) "neg %1\n" memop(a) +reg: LSHI4(reg,con5) "?mov %c,%0\nsal %c,%1\n" 2 +reg: LSHU4(reg,con5) "?mov %c,%0\nshl %c,%1\n" 2 +reg: RSHI4(reg,con5) "?mov %c,%0\nsar %c,%1\n" 2 +reg: RSHU4(reg,con5) "?mov %c,%0\nshr %c,%1\n" 2 + +stmt: ASGNI4(addr,LSHI4(mem,con5)) "sal %1,%2\n" memop(a) +stmt: ASGNI4(addr,LSHU4(mem,con5)) "shl %1,%2\n" memop(a) +stmt: ASGNI4(addr,RSHI4(mem,con5)) "sar %1,%2\n" memop(a) +stmt: ASGNI4(addr,RSHU4(mem,con5)) "shr %1,%2\n" memop(a) + +con5: CNSTI4 "%a" range(a, 0, 31) + +reg: LSHI4(reg,reg) "?mov %c,%0\nmov ecx,%1\nsal %c,cl\n" 3 +reg: LSHU4(reg,reg) "?mov %c,%0\nmov ecx,%1\nshl %c,cl\n" 2 +reg: RSHI4(reg,reg) "?mov %c,%0\nmov ecx,%1\nsar %c,cl\n" 2 +reg: RSHU4(reg,reg) "?mov %c,%0\nmov ecx,%1\nshr %c,cl\n" 2 +reg: MULI4(reg,mrc3) "?mov %c,%0\nimul %c,%1\n" 14 +reg: MULI4(con,mr) "imul %c,%1,%0\n" 13 +reg: MULU4(reg,mr) "mul %1\n" 13 +reg: DIVU4(reg,reg) "xor edx,edx\ndiv %1\n" +reg: MODU4(reg,reg) "xor edx,edx\ndiv %1\n" +reg: DIVI4(reg,reg) "cdq\nidiv %1\n" +reg: MODI4(reg,reg) "cdq\nidiv %1\n" +reg: CVPU4(reg) "mov %c,%0\n" move(a) +reg: CVUP4(reg) "mov %c,%0\n" move(a) +reg: CVII4(INDIRI1(addr)) "movsx %c,byte ptr %0\n" 3 +reg: CVII4(INDIRI2(addr)) "movsx %c,word ptr %0\n" 3 +reg: CVUU4(INDIRU1(addr)) "movzx %c,byte ptr %0\n" 3 +reg: CVUU4(INDIRU2(addr)) "movzx %c,word ptr %0\n" 3 +reg: CVII4(reg) "# extend\n" 3 +reg: CVIU4(reg) "# extend\n" 3 +reg: CVUI4(reg) "# extend\n" 3 +reg: CVUU4(reg) "# extend\n" 3 + +reg: CVII1(reg) "# truncate\n" 1 +reg: CVII2(reg) "# truncate\n" 1 +reg: CVUU1(reg) "# truncate\n" 1 +reg: CVUU2(reg) "# truncate\n" 1 +stmt: ASGNI1(addr,rc) "mov byte ptr %0,%1\n" 1 +stmt: ASGNI2(addr,rc) "mov word ptr %0,%1\n" 1 +stmt: ASGNI4(addr,rc) "mov dword ptr %0,%1\n" 1 +stmt: ASGNU1(addr,rc) "mov byte ptr %0,%1\n" 1 +stmt: ASGNU2(addr,rc) "mov word ptr %0,%1\n" 1 +stmt: ASGNU4(addr,rc) "mov dword ptr %0,%1\n" 1 +stmt: ASGNP4(addr,rc) "mov dword ptr %0,%1\n" 1 +stmt: ARGI4(mrc3) "push %0\n" 1 +stmt: ARGU4(mrc3) "push %0\n" 1 +stmt: ARGP4(mrc3) "push %0\n" 1 +stmt: ASGNB(reg,INDIRB(reg)) "mov ecx,%a\nrep movsb\n" +stmt: ARGB(INDIRB(reg)) "# ARGB\n" +memf: INDIRF8(addr) "qword ptr %0" +memf: INDIRF4(addr) "dword ptr %0" +memf: CVFF8(INDIRF4(addr)) "dword ptr %0" +reg: memf "fld %0\n" 3 +stmt: ASGNF8(addr,reg) "fstp qword ptr %0\n" 7 +stmt: ASGNF4(addr,reg) "fstp dword ptr %0\n" 7 +stmt: ASGNF4(addr,CVFF4(reg)) "fstp dword ptr %0\n" 7 +stmt: ARGF8(reg) "sub esp,8\nfstp qword ptr [esp]\n" +stmt: ARGF4(reg) "sub esp,4\nfstp dword ptr [esp]\n" +reg: NEGF8(reg) "fchs\n" +reg: NEGF4(reg) "fchs\n" +flt: memf " %0" +flt: reg "p st(1),st" +reg: ADDF8(reg,flt) "fadd%1\n" +reg: ADDF4(reg,flt) "fadd%1\n" +reg: DIVF8(reg,flt) "fdiv%1\n" +reg: DIVF4(reg,flt) "fdiv%1\n" +reg: MULF8(reg,flt) "fmul%1\n" +reg: MULF4(reg,flt) "fmul%1\n" +reg: SUBF8(reg,flt) "fsub%1\n" +reg: SUBF4(reg,flt) "fsub%1\n" +reg: CVFF8(reg) "# CVFF8\n" +reg: CVFF4(reg) "sub esp,4\nfstp dword ptr 0[esp]\nfld dword ptr 0[esp]\nadd esp,4\n" 12 + +reg: CVFI4(reg) "call __ftol\n" 31 +reg: CVIF8(INDIRI4(addr)) "fild dword ptr %0\n" 10 +reg: CVIF4(reg) "push %0\nfild dword ptr 0[esp]\nadd esp,4\n" 12 + +reg: CVIF8(reg) "push %0\nfild dword ptr 0[esp]\nadd esp,4\n" 12 + +addrj: ADDRGP4 "%a" +addrj: reg "%0" 2 +addrj: mem "%0" 2 + +stmt: JUMPV(addrj) "jmp %0\n" 3 +stmt: LABELV "%a:\n" +stmt: EQI4(mem,rc) "cmp %0,%1\nje %a\n" 5 +stmt: GEI4(mem,rc) "cmp %0,%1\njge %a\n" 5 +stmt: GTI4(mem,rc) "cmp %0,%1\njg %a\n" 5 +stmt: LEI4(mem,rc) "cmp %0,%1\njle %a\n" 5 +stmt: LTI4(mem,rc) "cmp %0,%1\njl %a\n" 5 +stmt: NEI4(mem,rc) "cmp %0,%1\njne %a\n" 5 +stmt: GEU4(mem,rc) "cmp %0,%1\njae %a\n" 5 +stmt: GTU4(mem,rc) "cmp %0,%1\nja %a\n" 5 +stmt: LEU4(mem,rc) "cmp %0,%1\njbe %a\n" 5 +stmt: LTU4(mem,rc) "cmp %0,%1\njb %a\n" 5 +stmt: EQI4(reg,mrc1) "cmp %0,%1\nje %a\n" 4 +stmt: GEI4(reg,mrc1) "cmp %0,%1\njge %a\n" 4 +stmt: GTI4(reg,mrc1) "cmp %0,%1\njg %a\n" 4 +stmt: LEI4(reg,mrc1) "cmp %0,%1\njle %a\n" 4 +stmt: LTI4(reg,mrc1) "cmp %0,%1\njl %a\n" 4 +stmt: NEI4(reg,mrc1) "cmp %0,%1\njne %a\n" 4 + +stmt: EQU4(reg,mrc1) "cmp %0,%1\nje %a\n" 4 +stmt: GEU4(reg,mrc1) "cmp %0,%1\njae %a\n" 4 +stmt: GTU4(reg,mrc1) "cmp %0,%1\nja %a\n" 4 +stmt: LEU4(reg,mrc1) "cmp %0,%1\njbe %a\n" 4 +stmt: LTU4(reg,mrc1) "cmp %0,%1\njb %a\n" 4 +stmt: NEU4(reg,mrc1) "cmp %0,%1\njne %a\n" 4 +cmpf: memf " %0" +cmpf: reg "p" +stmt: EQF8(cmpf,reg) "fcomp%0\nfstsw ax\nsahf\njp %b\nje %a\n%b:\n" +stmt: GEF8(cmpf,reg) "fcomp%0\nfstsw ax\nsahf\njp %a\njbe %a\n" +stmt: GTF8(cmpf,reg) "fcomp%0\nfstsw ax\nsahf\njp %a\njb %a\n" +stmt: LEF8(cmpf,reg) "fcomp%0\nfstsw ax\nsahf\njp %a\njae %a\n" +stmt: LTF8(cmpf,reg) "fcomp%0\nfstsw ax\nsahf\njp %a\nja %a\n" +stmt: NEF8(cmpf,reg) "fcomp%0\nfstsw ax\nsahf\njp %a\njne %a\n" + +stmt: EQF4(cmpf,reg) "fcomp%0\nfstsw ax\nsahf\njp %b\nje %a\n%b:\n" +stmt: GEF4(cmpf,reg) "fcomp%0\nfstsw ax\nsahf\njp %a\njbe %a\n\n" +stmt: GTF4(cmpf,reg) "fcomp%0\nfstsw ax\nsahf\njp %a\njb %a\n" +stmt: LEF4(cmpf,reg) "fcomp%0\nfstsw ax\nsahf\njp %a\njae %a\n\n" +stmt: LTF4(cmpf,reg) "fcomp%0\nfstsw ax\nsahf\njp %a\nja %a\n" +stmt: NEF4(cmpf,reg) "fcomp%0\nfstsw ax\nsahf\njp %a\njne %a\n" +reg: CALLI4(addrj) "call %0\nadd esp,%a\n" +reg: CALLU4(addrj) "call %0\nadd esp,%a\n" +reg: CALLP4(addrj) "call %0\nadd esp,%a\n" +stmt: CALLV(addrj) "call %0\nadd esp,%a\n" +reg: CALLF4(addrj) "call %0\nadd esp,%a\n" +reg: CALLF8(addrj) "call %0\nadd esp,%a\n" +stmt: CALLF4(addrj) "call %0\nadd esp,%a\nfstp\n" +stmt: CALLF8(addrj) "call %0\nadd esp,%a\nfstp\n" + +stmt: RETI4(reg) "# ret\n" +stmt: RETU4(reg) "# ret\n" +stmt: RETP4(reg) "# ret\n" +stmt: RETF4(reg) "# ret\n" +stmt: RETF8(reg) "# ret\n" +%% +static void progbeg(int argc, char *argv[]) { + int i; + + { + union { + char c; + int i; + } u; + u.i = 0; + u.c = 1; + swap = ((int)(u.i == 1)) != IR->little_endian; + } + parseflags(argc, argv); + intreg[EAX] = mkreg("eax", EAX, 1, IREG); + intreg[EDX] = mkreg("edx", EDX, 1, IREG); + intreg[ECX] = mkreg("ecx", ECX, 1, IREG); + intreg[EBX] = mkreg("ebx", EBX, 1, IREG); + intreg[ESI] = mkreg("esi", ESI, 1, IREG); + intreg[EDI] = mkreg("edi", EDI, 1, IREG); + + shortreg[EAX] = mkreg("ax", EAX, 1, IREG); + shortreg[ECX] = mkreg("cx", ECX, 1, IREG); + shortreg[EDX] = mkreg("dx", EDX, 1, IREG); + shortreg[EBX] = mkreg("bx", EBX, 1, IREG); + shortreg[ESI] = mkreg("si", ESI, 1, IREG); + shortreg[EDI] = mkreg("di", EDI, 1, IREG); + + charreg[EAX] = mkreg("al", EAX, 1, IREG); + charreg[ECX] = mkreg("cl", ECX, 1, IREG); + charreg[EDX] = mkreg("dl", EDX, 1, IREG); + charreg[EBX] = mkreg("bl", EBX, 1, IREG); + for (i = 0; i < 8; i++) + fltreg[i] = mkreg("%d", i, 0, FREG); + charregw = mkwildcard(charreg); + shortregw = mkwildcard(shortreg); + intregw = mkwildcard(intreg); + fltregw = mkwildcard(fltreg); + + tmask[IREG] = (1<x.regnode->mask |= 1<x.regnode->mask |= 1<op)) { + case MUL+U: + setreg(p, quo); + rtarget(p, 0, intreg[EAX]); + break; + case DIV+I: case DIV+U: + setreg(p, quo); + rtarget(p, 0, quo); + break; + case MOD+I: case MOD+U: + setreg(p, rem); + rtarget(p, 0, quo); + break; + case ASGN+B: + rtarget(p, 0, intreg[EDI]); + rtarget(p->kids[1], 0, intreg[ESI]); + break; + case ARG+B: + rtarget(p->kids[0], 0, intreg[ESI]); + break; + case CVF+I: + setreg(p, intreg[EAX]); + break; + case CALL+I: case CALL+U: case CALL+P: case CALL+V: + setreg(p, intreg[EAX]); + break; + case RET+I: case RET+U: case RET+P: + rtarget(p, 0, intreg[EAX]); + break; + } +} + +static void clobber(Node p) { + static int nstack = 0; + + assert(p); + nstack = ckstack(p, nstack); + switch (specific(p->op)) { + case RSH+I: case RSH+U: case LSH+I: case LSH+U: + if (generic(p->kids[1]->op) != CNST + && !( generic(p->kids[1]->op) == INDIR + && specific(p->kids[1]->kids[0]->op) == VREG+P + && p->kids[1]->syms[RX]->u.t.cse + && generic(p->kids[1]->syms[RX]->u.t.cse->op) == CNST +)) { + spill(1<op) == EQ+F) + p->syms[1] = findlabel(genlabel(1)); + break; + case CALL+F: + spill(1<op)==F) + +int ckstack(Node p, int n) { + int i; + + for (i = 0; i < NELEMS(p->x.kids) && p->x.kids[i]; i++) + if (isfp(p->x.kids[i])) + n--; + if (isfp(p) && p->count > 0) + n++; + if (n > 8) + error("expression too complicated\n"); + debug(fprint(stderr, "(ckstack(%x)=%d)\n", p, n)); + assert(n >= 0); + return n; +} +int memop(Node p) { + assert(p); + assert(generic(p->op) == ASGN); + assert(p->kids[0]); + assert(p->kids[1]); + if (generic(p->kids[1]->kids[0]->op) == INDIR + && sametree(p->kids[0], p->kids[1]->kids[0]->kids[0])) + return 3; + else + return LBURG_MAX; +} +int sametree(Node p, Node q) { + return p == NULL && q == NULL + || p && q && p->op == q->op && p->syms[0] == q->syms[0] + && sametree(p->kids[0], q->kids[0]) + && sametree(p->kids[1], q->kids[1]); +} +static void emit2(Node p) { + int op = specific(p->op); +#define preg(f) ((f)[getregnum(p->x.kids[0])]->x.name) + + if (op == CVI+I && opsize(p->op) == 4 && opsize(p->x.kids[0]->op) == 1) + print("movsx %s,%s\n", p->syms[RX]->x.name +, preg(charreg)); + else if (op == CVI+U && opsize(p->op) == 4 && opsize(p->x.kids[0]->op) == 1) + print("movsx %s,%s\n", p->syms[RX]->x.name +, preg(charreg)); + else if (op == CVI+I && opsize(p->op) == 4 && opsize(p->x.kids[0]->op) == 2) + print("movsx %s,%s\n", p->syms[RX]->x.name +, preg(shortreg)); + else if (op == CVI+U && opsize(p->op) == 4 && opsize(p->x.kids[0]->op) == 2) + print("movsx %s,%s\n", p->syms[RX]->x.name +, preg(shortreg)); + + else if (op == CVU+I && opsize(p->op) == 4 && opsize(p->x.kids[0]->op) == 1) + print("movzx %s,%s\n", p->syms[RX]->x.name +, preg(charreg)); + else if (op == CVU+U && opsize(p->op) == 4 && opsize(p->x.kids[0]->op) == 1) + print("movzx %s,%s\n", p->syms[RX]->x.name +, preg(charreg)); + else if (op == CVU+I && opsize(p->op) == 4 && opsize(p->x.kids[0]->op) == 2) + print("movzx %s,%s\n", p->syms[RX]->x.name +, preg(shortreg)); + else if (op == CVU+U && opsize(p->op) == 4 && opsize(p->x.kids[0]->op) == 2) + print("movzx %s,%s\n", p->syms[RX]->x.name +, preg(shortreg)); + else if (generic(op) == CVI || generic(op) == CVU || generic(op) == LOAD) { + char *dst = intreg[getregnum(p)]->x.name; + char *src = preg(intreg); + assert(opsize(p->op) <= opsize(p->x.kids[0]->op)); + if (dst != src) + print("mov %s,%s\n", dst, src); + } + else if (op == ARG+B) + print("sub esp,%d\nmov edi,esp\nmov ecx,%d\nrep movsb\n", + roundup(p->syms[0]->u.c.v.i, 4), p->syms[0]->u.c.v.i); +} + +static void doarg(Node p) { + assert(p && p->syms[0]); + mkactual(4, p->syms[0]->u.c.v.i); +} +static void blkfetch(int k, int off, int reg, int tmp) {} +static void blkstore(int k, int off, int reg, int tmp) {} +static void blkloop(int dreg, int doff, int sreg, int soff, + int size, int tmps[]) {} +static void local(Symbol p) { + if (isfloat(p->type)) + p->sclass = AUTO; + if (askregvar(p, (*IR->x.rmap)(ttob(p->type))) == 0) { + assert(p->sclass == AUTO); + offset = roundup(offset + p->type->size, + p->type->align < 4 ? 4 : p->type->align); + p->x.offset = -offset; + p->x.name = stringd(-offset); + } +} +static void function(Symbol f, Symbol caller[], Symbol callee[], int n) { + int i; + + print("%s:\n", f->x.name); + print("push ebx\n"); + print("push esi\n"); + print("push edi\n"); + print("push ebp\n"); + print("mov ebp,esp\n"); + usedmask[0] = usedmask[1] = 0; + freemask[0] = freemask[1] = ~(unsigned)0; + offset = 16 + 4; + for (i = 0; callee[i]; i++) { + Symbol p = callee[i]; + Symbol q = caller[i]; + assert(q); + p->x.offset = q->x.offset = offset; + p->x.name = q->x.name = stringf("%d", p->x.offset); + p->sclass = q->sclass = AUTO; + offset += roundup(q->type->size, 4); + } + assert(caller[i] == 0); + offset = maxoffset = 0; + gencode(caller, callee); + framesize = roundup(maxoffset, 4); + if (framesize >= 4096) + print("mov eax,%d\ncall __chkstk\n", framesize); + else if (framesize > 0) + print("sub esp,%d\n", framesize); + emitcode(); + print("mov esp,ebp\n"); + print("pop ebp\n"); + print("pop edi\n"); + print("pop esi\n"); + print("pop ebx\n"); + print("ret\n"); + if (framesize >= 4096) { + int oldseg = cseg; + segment(0); + print("extrn __chkstk:near\n"); + segment(oldseg); + } +} +static void defsymbol(Symbol p) { + if (p->scope >= LOCAL && p->sclass == STATIC) + p->x.name = stringf("L%d", genlabel(1)); + else if (p->generated) + p->x.name = stringf("L%s", p->name); + else if (p->scope == GLOBAL || p->sclass == EXTERN) + p->x.name = stringf("_%s", p->name); + else if (p->scope == CONSTANTS + && (isint(p->type) || isptr(p->type)) + && p->name[0] == '0' && p->name[1] == 'x') + p->x.name = stringf("0%sH", &p->name[2]); + else + p->x.name = p->name; +} +static void address(Symbol q, Symbol p, long n) { + if (p->scope == GLOBAL + || p->sclass == STATIC || p->sclass == EXTERN) + q->x.name = stringf("%s%s%D", + p->x.name, n >= 0 ? "+" : "", n); + else { + assert(n <= INT_MAX && n >= INT_MIN); + q->x.offset = p->x.offset + n; + q->x.name = stringd(q->x.offset); + } +} +static void defconst(int suffix, int size, Value v) { + if (suffix == I && size == 1) + print("db %d\n", v.u); + else if (suffix == I && size == 2) + print("dw %d\n", v.i); + else if (suffix == I && size == 4) + print("dd %d\n", v.i); + else if (suffix == U && size == 1) + print("db 0%xH\n", (unsigned)((unsigned char)v.u)); + else if (suffix == U && size == 2) + print("dw 0%xH\n", (unsigned)((unsigned short)v.u)); + else if (suffix == U && size == 4) + print("dd 0%xH\n", (unsigned)v.u); + else if (suffix == P && size == 4) + print("dd 0%xH\n", (unsigned)v.p); + else if (suffix == F && size == 4) { + float f = v.d; + print("dd 0%xH\n", *(unsigned *)&f); + } + else if (suffix == F && size == 8) { + double d = v.d; + unsigned *p = (unsigned *)&d; + print("dd 0%xH\ndd 0%xH\n", p[swap], p[!swap]); + } + else assert(0); +} +static void defaddress(Symbol p) { + print("dd %s\n", p->x.name); +} +static void defstring(int n, char *str) { + char *s; + + for (s = str; s < str + n; s++) + print("db %d\n", (*s)&0377); +} +static void export(Symbol p) { + print("public %s\n", p->x.name); +} +static void import(Symbol p) { + int oldseg = cseg; + + if (p->ref > 0) { + segment(0); + print("extrn %s:near\n", p->x.name); + segment(oldseg); + } +} +static void global(Symbol p) { + print("align %d\n", + p->type->align > 4 ? 4 : p->type->align); + print("%s label byte\n", p->x.name); +} +static void space(int n) { + print("db %d dup (0)\n", n); +} +Interface x86IR = { + 1, 1, 0, /* char */ + 2, 2, 0, /* short */ + 4, 4, 0, /* int */ + 4, 4, 0, /* long */ + 4, 4, 0, /* long long */ + 4, 4, 1, /* float */ + 8, 4, 1, /* double */ + 8, 4, 1, /* long double */ + 4, 4, 0, /* T * */ + 0, 1, 0, /* struct */ + 1, /* little_endian */ + 0, /* mulops_calls */ + 0, /* wants_callb */ + 1, /* wants_argb */ + 0, /* left_to_right */ + 0, /* wants_dag */ + 0, /* unsigned_char */ + address, + blockbeg, + blockend, + defaddress, + defconst, + defstring, + defsymbol, + emit, + export, + function, + gen, + global, + import, + local, + progbeg, + progend, + segment, + space, + 0, 0, 0, 0, 0, 0, 0, + {1, rmap, + blkfetch, blkstore, blkloop, + _label, + _rule, + _nts, + _kids, + _string, + _templates, + _isinstruction, + _ntname, + emit2, + doarg, + target, + clobber, +} +}; diff --git a/src/cmd/lccom/x86linux.md b/src/cmd/lccom/x86linux.md new file mode 100644 index 0000000..d291d4c --- /dev/null +++ b/src/cmd/lccom/x86linux.md @@ -0,0 +1,1078 @@ +%{ +/* x86/linux lburg spec. Derived from x86.md by +Marcos Ramirez +Horst von Brand +Jacob Navia +*/ +enum { EAX=0, ECX=1, EDX=2, EBX=3, ESI=6, EDI=7 }; +#include "c.h" +#define NODEPTR_TYPE Node +#define OP_LABEL(p) ((p)->op) +#define LEFT_CHILD(p) ((p)->kids[0]) +#define RIGHT_CHILD(p) ((p)->kids[1]) +#define STATE_LABEL(p) ((p)->x.state) +extern int ckstack(Node, int); +extern int memop(Node); +extern int sametree(Node, Node); +static Symbol charreg[32], shortreg[32], intreg[32]; +static Symbol fltreg[32]; + +static Symbol charregw, shortregw, intregw, fltregw; + +static int cseg; + +static Symbol quo, rem; + +extern char *stabprefix; +extern void stabblock(int, int, Symbol*); +extern void stabend(Coordinate *, Symbol, Coordinate **, Symbol *, Symbol *); +extern void stabfend(Symbol, int); +extern void stabinit(char *, int, char *[]); +extern void stabline(Coordinate *); +extern void stabsym(Symbol); +extern void stabtype(Symbol); + +static int pflag = 0; + +#define hasargs(p) (p->syms[0] && p->syms[0]->u.c.v.i > 0 ? 0 : LBURG_MAX) +%} +%start stmt +%term CNSTF4=4113 +%term CNSTF8=8209 +%term CNSTF16=16401 +%term CNSTI1=1045 +%term CNSTI2=2069 +%term CNSTI4=4117 +%term CNSTI8=8213 +%term CNSTP4=4119 +%term CNSTP8=8215 +%term CNSTU1=1046 +%term CNSTU2=2070 +%term CNSTU4=4118 +%term CNSTU8=8214 + +%term ARGB=41 +%term ARGF4=4129 +%term ARGF8=8225 +%term ARGF16=16417 +%term ARGI4=4133 +%term ARGI8=8229 +%term ARGP4=4135 +%term ARGP8=8231 +%term ARGU4=4134 +%term ARGU8=8230 + +%term ASGNB=57 +%term ASGNF4=4145 +%term ASGNF8=8241 +%term ASGNF16=16433 +%term ASGNI1=1077 +%term ASGNI2=2101 +%term ASGNI4=4149 +%term ASGNI8=8245 +%term ASGNP4=4151 +%term ASGNP8=8247 +%term ASGNU1=1078 +%term ASGNU2=2102 +%term ASGNU4=4150 +%term ASGNU8=8246 + +%term INDIRB=73 +%term INDIRF4=4161 +%term INDIRF8=8257 +%term INDIRF16=16449 +%term INDIRI1=1093 +%term INDIRI2=2117 +%term INDIRI4=4165 +%term INDIRI8=8261 +%term INDIRP4=4167 +%term INDIRP8=8263 +%term INDIRU1=1094 +%term INDIRU2=2118 +%term INDIRU4=4166 +%term INDIRU8=8262 + +%term CVFF4=4209 +%term CVFF8=8305 +%term CVFF16=16497 +%term CVFI4=4213 +%term CVFI8=8309 + +%term CVIF4=4225 +%term CVIF8=8321 +%term CVIF16=16513 +%term CVII1=1157 +%term CVII2=2181 +%term CVII4=4229 +%term CVII8=8325 +%term CVIU1=1158 +%term CVIU2=2182 +%term CVIU4=4230 +%term CVIU8=8326 + +%term CVPP4=4247 +%term CVPP8=8343 +%term CVPP16=16535 +%term CVPU4=4246 +%term CVPU8=8342 + +%term CVUI1=1205 +%term CVUI2=2229 +%term CVUI4=4277 +%term CVUI8=8373 +%term CVUP4=4279 +%term CVUP8=8375 +%term CVUP16=16567 +%term CVUU1=1206 +%term CVUU2=2230 +%term CVUU4=4278 +%term CVUU8=8374 + +%term NEGF4=4289 +%term NEGF8=8385 +%term NEGF16=16577 +%term NEGI4=4293 +%term NEGI8=8389 + +%term CALLB=217 +%term CALLF4=4305 +%term CALLF8=8401 +%term CALLF16=16593 +%term CALLI4=4309 +%term CALLI8=8405 +%term CALLP4=4311 +%term CALLP8=8407 +%term CALLU4=4310 +%term CALLU8=8406 +%term CALLV=216 + +%term RETF4=4337 +%term RETF8=8433 +%term RETF16=16625 +%term RETI4=4341 +%term RETI8=8437 +%term RETP4=4343 +%term RETP8=8439 +%term RETU4=4342 +%term RETU8=8438 +%term RETV=248 + +%term ADDRGP4=4359 +%term ADDRGP8=8455 + +%term ADDRFP4=4375 +%term ADDRFP8=8471 + +%term ADDRLP4=4391 +%term ADDRLP8=8487 + +%term ADDF4=4401 +%term ADDF8=8497 +%term ADDF16=16689 +%term ADDI4=4405 +%term ADDI8=8501 +%term ADDP4=4407 +%term ADDP8=8503 +%term ADDU4=4406 +%term ADDU8=8502 + +%term SUBF4=4417 +%term SUBF8=8513 +%term SUBF16=16705 +%term SUBI4=4421 +%term SUBI8=8517 +%term SUBP4=4423 +%term SUBP8=8519 +%term SUBU4=4422 +%term SUBU8=8518 + +%term LSHI4=4437 +%term LSHI8=8533 +%term LSHU4=4438 +%term LSHU8=8534 + +%term MODI4=4453 +%term MODI8=8549 +%term MODU4=4454 +%term MODU8=8550 + +%term RSHI4=4469 +%term RSHI8=8565 +%term RSHU4=4470 +%term RSHU8=8566 + +%term BANDI4=4485 +%term BANDI8=8581 +%term BANDU4=4486 +%term BANDU8=8582 + +%term BCOMI4=4501 +%term BCOMI8=8597 +%term BCOMU4=4502 +%term BCOMU8=8598 + +%term BORI4=4517 +%term BORI8=8613 +%term BORU4=4518 +%term BORU8=8614 + +%term BXORI4=4533 +%term BXORI8=8629 +%term BXORU4=4534 +%term BXORU8=8630 + +%term DIVF4=4545 +%term DIVF8=8641 +%term DIVF16=16833 +%term DIVI4=4549 +%term DIVI8=8645 +%term DIVU4=4550 +%term DIVU8=8646 + +%term MULF4=4561 +%term MULF8=8657 +%term MULF16=16849 +%term MULI4=4565 +%term MULI8=8661 +%term MULU4=4566 +%term MULU8=8662 + +%term EQF4=4577 +%term EQF8=8673 +%term EQF16=16865 +%term EQI4=4581 +%term EQI8=8677 +%term EQU4=4582 +%term EQU8=8678 + +%term GEF4=4593 +%term GEF8=8689 +%term GEI4=4597 +%term GEI8=8693 +%term GEI16=16885 +%term GEU4=4598 +%term GEU8=8694 + +%term GTF4=4609 +%term GTF8=8705 +%term GTF16=16897 +%term GTI4=4613 +%term GTI8=8709 +%term GTU4=4614 +%term GTU8=8710 + +%term LEF4=4625 +%term LEF8=8721 +%term LEF16=16913 +%term LEI4=4629 +%term LEI8=8725 +%term LEU4=4630 +%term LEU8=8726 + +%term LTF4=4641 +%term LTF8=8737 +%term LTF16=16929 +%term LTI4=4645 +%term LTI8=8741 +%term LTU4=4646 +%term LTU8=8742 + +%term NEF4=4657 +%term NEF8=8753 +%term NEF16=16945 +%term NEI4=4661 +%term NEI8=8757 +%term NEU4=4662 +%term NEU8=8758 + +%term JUMPV=584 + +%term LABELV=600 + +%term LOADB=233 +%term LOADF4=4321 +%term LOADF8=8417 +%term LOADF16=16609 +%term LOADI1=1253 +%term LOADI2=2277 +%term LOADI4=4325 +%term LOADI8=8421 +%term LOADP4=4327 +%term LOADP8=8423 +%term LOADU1=1254 +%term LOADU2=2278 +%term LOADU4=4326 +%term LOADU8=8422 + +%term VREGP=711 +%% +reg: INDIRI1(VREGP) "# read register\n" +reg: INDIRU1(VREGP) "# read register\n" + +reg: INDIRI2(VREGP) "# read register\n" +reg: INDIRU2(VREGP) "# read register\n" + +reg: INDIRI4(VREGP) "# read register\n" +reg: INDIRP4(VREGP) "# read register\n" +reg: INDIRU4(VREGP) "# read register\n" + +reg: INDIRI8(VREGP) "# read register\n" +reg: INDIRP8(VREGP) "# read register\n" +reg: INDIRU8(VREGP) "# read register\n" + +freg: INDIRF4(VREGP) "# read register\n" +freg: INDIRF8(VREGP) "# read register\n" + +stmt: ASGNI1(VREGP,reg) "# write register\n" +stmt: ASGNU1(VREGP,reg) "# write register\n" + +stmt: ASGNI2(VREGP,reg) "# write register\n" +stmt: ASGNU2(VREGP,reg) "# write register\n" + +stmt: ASGNF4(VREGP,reg) "# write register\n" +stmt: ASGNI4(VREGP,reg) "# write register\n" +stmt: ASGNP4(VREGP,reg) "# write register\n" +stmt: ASGNU4(VREGP,reg) "# write register\n" + +stmt: ASGNF8(VREGP,reg) "# write register\n" +stmt: ASGNI8(VREGP,reg) "# write register\n" +stmt: ASGNP8(VREGP,reg) "# write register\n" +stmt: ASGNU8(VREGP,reg) "# write register\n" + +cnst: CNSTI1 "%a" +cnst: CNSTU1 "%a" + +cnst: CNSTI2 "%a" +cnst: CNSTU2 "%a" + +cnst: CNSTI4 "%a" +cnst: CNSTU4 "%a" +cnst: CNSTP4 "%a" + +cnst: CNSTI8 "%a" +cnst: CNSTU8 "%a" +cnst: CNSTP8 "%a" + +con: cnst "$%0" + +stmt: reg "" +stmt: freg "" + +acon: ADDRGP4 "%a" +acon: ADDRGP8 "%a" +acon: cnst "%0" + +baseaddr: ADDRGP4 "%a" +base: reg "(%0)" +base: ADDI4(reg,acon) "%1(%0)" +base: ADDP4(reg,acon) "%1(%0)" +base: ADDU4(reg,acon) "%1(%0)" +base: ADDRFP4 "%a(%%ebp)" +base: ADDRLP4 "%a(%%ebp)" + +index: reg "%0" +index: LSHI4(reg,con1) "%0,2" +index: LSHI4(reg,con2) "%0,4" +index: LSHI4(reg,con3) "%0,8" +index: LSHU4(reg,con1) "%0,2" +index: LSHU4(reg,con2) "%0,4" +index: LSHU4(reg,con3) "%0,8" + +con0: CNSTI4 "1" range(a, 0, 0) +con0: CNSTU4 "1" range(a, 0, 0) +con1: CNSTI4 "1" range(a, 1, 1) +con1: CNSTU4 "1" range(a, 1, 1) +con2: CNSTI4 "2" range(a, 2, 2) +con2: CNSTU4 "2" range(a, 2, 2) +con3: CNSTI4 "3" range(a, 3, 3) +con3: CNSTU4 "3" range(a, 3, 3) + +addr: base "%0" +addr: baseaddr "%0" +addr: ADDI4(index,baseaddr) "%1(,%0)" +addr: ADDP4(index,baseaddr) "%1(,%0)" +addr: ADDU4(index,baseaddr) "%1(,%0)" + +addr: ADDI4(reg,baseaddr) "%1(%0)" +addr: ADDP4(reg,baseaddr) "%1(%0)" +addr: ADDU4(reg,baseaddr) "%1(%0)" + +addr: ADDI4(index,reg) "(%1,%0)" +addr: ADDP4(index,reg) "(%1,%0)" +addr: ADDU4(index,reg) "(%1,%0)" + +addr: index "(,%0)" + +mem1: INDIRI1(addr) "%0" +mem1: INDIRU1(addr) "%0" +mem2: INDIRI2(addr) "%0" +mem2: INDIRU2(addr) "%0" +mem4: INDIRI4(addr) "%0" +mem4: INDIRU4(addr) "%0" +mem4: INDIRP4(addr) "%0" + +rc: reg "%0" +rc: con "%0" + +mr: reg "%0" +mr: mem4 "%0" + +mr1: reg "%0" +mr1: mem1 "%0" + +mr2: reg "%0" +mr2: mem2 "%0" + +mrc: mem4 "%0" 1 +mrc: mem1 "%0" 1 +mrc: mem2 "%0" 1 +mrc: rc "%0" + +reg: addr "leal %0,%c\n" 1 +reg: mr "movl %0,%c\n" 1 +reg: mr1 "movb %0,%c\n" 1 +reg: mr2 "movw %0,%c\n" 1 +reg: con "mov %0,%c\n" 1 + +reg: LOADI1(reg) "# move\n" 1 +reg: LOADI2(reg) "# move\n" 1 +reg: LOADI4(reg) "# move\n" move(a) +reg: LOADU1(reg) "# move\n" 1 +reg: LOADU2(reg) "# move\n" 1 +reg: LOADU4(reg) "# move\n" move(a) +reg: LOADP4(reg) "# move\n" move(a) +reg: ADDI4(reg,mrc) "?movl %0,%c\naddl %1,%c\n" 1 +reg: ADDP4(reg,mrc) "?movl %0,%c\naddl %1,%c\n" 1 +reg: ADDU4(reg,mrc) "?movl %0,%c\naddl %1,%c\n" 1 +reg: SUBI4(reg,mrc) "?movl %0,%c\nsubl %1,%c\n" 1 +reg: SUBP4(reg,mrc) "?movl %0,%c\nsubl %1,%c\n" 1 +reg: SUBU4(reg,mrc) "?movl %0,%c\nsubl %1,%c\n" 1 +reg: BANDI4(reg,mrc) "?movl %0,%c\nandl %1,%c\n" 1 +reg: BORI4(reg,mrc) "?movl %0,%c\norl %1,%c\n" 1 +reg: BXORI4(reg,mrc) "?movl %0,%c\nxorl %1,%c\n" 1 +reg: BANDU4(reg,mrc) "?movl %0,%c\nandl %1,%c\n" 1 +reg: BORU4(reg,mrc) "?movl %0,%c\norl %1,%c\n" 1 +reg: BXORU4(reg,mrc) "?movl %0,%c\nxorl %1,%c\n" 1 + +stmt: ASGNI4(addr,ADDI4(mem4,con1)) "incl %1\n" memop(a) +stmt: ASGNI4(addr,ADDU4(mem4,con1)) "incl %1\n" memop(a) +stmt: ASGNP4(addr,ADDP4(mem4,con1)) "incl %1\n" memop(a) +stmt: ASGNI4(addr,SUBI4(mem4,con1)) "decl %1\n" memop(a) +stmt: ASGNI4(addr,SUBU4(mem4,con1)) "decl %1\n" memop(a) +stmt: ASGNP4(addr,SUBP4(mem4,con1)) "decl %1\n" memop(a) +stmt: ASGNI4(addr,ADDI4(mem4,rc)) "addl %2,%1\n" memop(a) +stmt: ASGNI4(addr,SUBI4(mem4,rc)) "subl %2,%1\n" memop(a) +stmt: ASGNU4(addr,ADDU4(mem4,rc)) "addl %2,%1\n" memop(a) +stmt: ASGNU4(addr,SUBU4(mem4,rc)) "subl %2,%1\n" memop(a) + +stmt: ASGNI4(addr,BANDI4(mem4,rc)) "andl %2,%1\n" memop(a) +stmt: ASGNI4(addr,BORI4(mem4,rc)) "orl %2,%1\n" memop(a) +stmt: ASGNI4(addr,BXORI4(mem4,rc)) "xorl %2,%1\n" memop(a) +stmt: ASGNU4(addr,BANDU4(mem4,rc)) "andl %2,%1\n" memop(a) +stmt: ASGNU4(addr,BORU4(mem4,rc)) "orl %2,%1\n" memop(a) +stmt: ASGNU4(addr,BXORU4(mem4,rc)) "xorl %2,%1\n" memop(a) +reg: BCOMI4(reg) "?movl %0,%c\nnotl %c\n" 2 +reg: BCOMU4(reg) "?movl %0,%c\nnotl %c\n" 2 +reg: NEGI4(reg) "?movl %0,%c\nnegl %c\n" 2 + +stmt: ASGNI4(addr,BCOMI4(mem4)) "notl %1\n" memop(a) +stmt: ASGNU4(addr,BCOMU4(mem4)) "notl %1\n" memop(a) +stmt: ASGNI4(addr,NEGI4(mem4)) "negl %1\n" memop(a) +reg: LSHI4(reg,rc5) "?movl %0,%c\nsall %1,%c\n" 2 +reg: LSHU4(reg,rc5) "?movl %0,%c\nshll %1,%c\n" 2 +reg: RSHI4(reg,rc5) "?movl %0,%c\nsarl %1,%c\n" 2 +reg: RSHU4(reg,rc5) "?movl %0,%c\nshrl %1,%c\n" 2 + +stmt: ASGNI4(addr,LSHI4(mem4,rc5)) "sall %2,%1\n" memop(a) +stmt: ASGNI4(addr,LSHU4(mem4,rc5)) "shll %2,%1\n" memop(a) +stmt: ASGNI4(addr,RSHI4(mem4,rc5)) "sarl %2,%1\n" memop(a) +stmt: ASGNI4(addr,RSHU4(mem4,rc5)) "shrl %2,%1\n" memop(a) + +rc5: CNSTI4 "$%a" range(a, 0, 31) +rc5: reg "%%cl" +reg: MULI4(reg,mrc) "?movl %0,%c\nimull %1,%c\n" 14 +reg: MULI4(con,mr) "imul %0,%1,%c\n" 13 +reg: MULU4(reg,mr) "mull %1\n" 13 +reg: DIVU4(reg,reg) "xorl %%edx,%%edx\ndivl %1\n" +reg: MODU4(reg,reg) "xorl %%edx,%%edx\ndivl %1\n" +reg: DIVI4(reg,reg) "cdq\nidivl %1\n" +reg: MODI4(reg,reg) "cdq\nidivl %1\n" +reg: CVPU4(reg) "movl %0,%c\n" move(a) +reg: CVUP4(reg) "movl %0,%c\n" move(a) +reg: CVII4(INDIRI1(addr)) "movsbl %0,%c\n" 3 +reg: CVII4(INDIRI2(addr)) "movswl %0,%c\n" 3 +reg: CVUU4(INDIRU1(addr)) "movzbl %0,%c\n" 3 +reg: CVUU4(INDIRU2(addr)) "movzwl %0,%c\n" 3 +reg: CVII4(reg) "# extend\n" 3 +reg: CVIU4(reg) "# extend\n" 3 +reg: CVUI4(reg) "# extend\n" 3 +reg: CVUU4(reg) "# extend\n" 3 + +reg: CVII1(reg) "# truncate\n" 1 +reg: CVII2(reg) "# truncate\n" 1 +reg: CVUU1(reg) "# truncate\n" 1 +reg: CVUU2(reg) "# truncate\n" 1 + +mrca: mem4 "%0" +mrca: rc "%0" +mrca: ADDRGP4 "$%a" +mrca: ADDRGP8 "$%a" + +stmt: ASGNI1(addr,rc) "movb %1,%0\n" 1 +stmt: ASGNI2(addr,rc) "movw %1,%0\n" 1 +stmt: ASGNI4(addr,rc) "movl %1,%0\n" 1 +stmt: ASGNU1(addr,rc) "movb %1,%0\n" 1 +stmt: ASGNU2(addr,rc) "movw %1,%0\n" 1 +stmt: ASGNU4(addr,rc) "movl %1,%0\n" 1 +stmt: ASGNP4(addr,rc) "movl %1,%0\n" 1 +stmt: ARGI4(mrca) "pushl %0\n" 1 +stmt: ARGU4(mrca) "pushl %0\n" 1 +stmt: ARGP4(mrca) "pushl %0\n" 1 +stmt: ASGNB(reg,INDIRB(reg)) "movl $%a,%%ecx\nrep\nmovsb\n" +stmt: ARGB(INDIRB(reg)) "# ARGB\n" + +memf: INDIRF8(addr) "l %0" +memf: INDIRF4(addr) "s %0" +memf: CVFF8(INDIRF4(addr)) "s %0" +memf: CVFF4(INDIRF8(addr)) "l %0" + +freg: memf "fld%0\n" 3 + +stmt: ASGNF8(addr,freg) "fstpl %0\n" 7 +stmt: ASGNF4(addr,freg) "fstps %0\n" 7 +stmt: ASGNF4(addr,CVFF4(freg)) "fstps %0\n" 7 + +stmt: ARGF8(freg) "subl $8,%%esp\nfstpl (%%esp)\n" +stmt: ARGF4(freg) "subl $4,%%esp\nfstps (%%esp)\n" +freg: NEGF8(freg) "fchs\n" +freg: NEGF4(freg) "fchs\n" + +flt: memf "%0" +flt: freg "p %%st,%%st(1)" +flt2: memf "%0" +flt2: freg "rp %%st,%%st(1)" + +freg: ADDF4(freg,flt) "fadd%1\n" +freg: ADDF8(freg,flt) "fadd%1\n" + +freg: DIVF4(freg,flt2) "fdiv%1\n" +freg: DIVF8(freg,flt2) "fdiv%1\n" + +freg: MULF4(freg,flt) "fmul%1\n" +freg: MULF8(freg,flt) "fmul%1\n" + +freg: SUBF4(freg,flt2) "fsub%1\n" +freg: SUBF8(freg,flt2) "fsub%1\n" + +freg: CVFF8(freg) "# CVFF8\n" +freg: CVFF4(freg) "sub $4,%%esp\nfstps (%%esp)\nflds (%%esp)\naddl $4,%%esp\n" 12 + +reg: CVFI4(freg) "subl $8,%%esp\nfnstcw 4(%%esp)\nmovl 4(%%esp),%%edx\nmovb $12,%%dh\nmovl %%edx,0(%%esp)\nfldcw 0(%%esp)\nfistpl 0(%%esp)\npopl %c\nfldcw 0(%%esp)\naddl $4,%%esp\n" 31 + +freg: CVIF8(INDIRI4(addr)) "fildl %0\n" 10 +freg: CVIF8(reg) "pushl %0\nfildl (%%esp)\naddl $4,%%esp\n" 12 + +freg: CVIF4(INDIRI4(addr)) "fildl %0\n" 10 +freg: CVIF4(reg) "pushl %0\nfildl (%%esp)\naddl $4,%%esp\n" 12 + +addrj: ADDRGP4 "%a" +addrj: reg "*%0" 2 +addrj: mem4 "*%0" 2 + +stmt: LABELV "%a:\n" +stmt: JUMPV(addrj) "jmp %0\n" 3 +stmt: EQI4(mem4,rc) "cmpl %1,%0\nje %a\n" 5 +stmt: GEI4(mem4,rc) "cmpl %1,%0\njge %a\n" 5 +stmt: GTI4(mem4,rc) "cmpl %1,%0\njg %a\n" 5 +stmt: LEI4(mem4,rc) "cmpl %1,%0\njle %a\n" 5 +stmt: LTI4(mem4,rc) "cmpl %1,%0\njl %a\n" 5 +stmt: NEI4(mem4,rc) "cmpl %1,%0\njne %a\n" 5 +stmt: GEU4(mem4,rc) "cmpl %1,%0\njae %a\n" 5 +stmt: GTU4(mem4,rc) "cmpl %1,%0\nja %a\n" 5 +stmt: LEU4(mem4,rc) "cmpl %1,%0\njbe %a\n" 5 +stmt: LTU4(mem4,rc) "cmpl %1,%0\njb %a\n" 5 +stmt: EQI4(reg,mrc) "cmpl %1,%0\nje %a\n" 4 +stmt: GEI4(reg,mrc) "cmpl %1,%0\njge %a\n" 4 +stmt: GTI4(reg,mrc) "cmpl %1,%0\njg %a\n" 4 +stmt: LEI4(reg,mrc) "cmpl %1,%0\njle %a\n" 4 +stmt: LTI4(reg,mrc) "cmpl %1,%0\njl %a\n" 4 +stmt: NEI4(reg,mrc) "cmpl %1,%0\njne %a\n" 4 + +stmt: EQU4(reg,mrc) "cmpl %1,%0\nje %a\n" 4 +stmt: GEU4(reg,mrc) "cmpl %1,%0\njae %a\n" 4 +stmt: GTU4(reg,mrc) "cmpl %1,%0\nja %a\n" 4 +stmt: LEU4(reg,mrc) "cmpl %1,%0\njbe %a\n" 4 +stmt: LTU4(reg,mrc) "cmpl %1,%0\njb %a\n" 4 +stmt: NEU4(reg,mrc) "cmpl %1,%0\njne %a\n" 4 + +stmt: EQI4(BANDU4(mr,con),con0) "testl %1,%0\nje %a\n" 3 +stmt: NEI4(BANDU4(mr,con),con0) "testl %1,%0\njne %a\n" + +stmt: EQI4(BANDU4(CVII2(INDIRI2(addr)),con),con0) "testw %1,%0\nje %a\n" +stmt: NEI4(BANDU4(CVII2(INDIRI2(addr)),con),con0) "testw %1,%0\njne %a\n" +stmt: EQI4(BANDU4(CVIU2(INDIRI2(addr)),con),con0) "testw %1,%0\nje %a\n" +stmt: NEI4(BANDU4(CVIU2(INDIRI2(addr)),con),con0) "testw %1,%0\njne %a\n" +stmt: EQI4(BANDU4(CVII1(INDIRI1(addr)),con),con0) "testb %1,%0\nje %a\n" + +cmpf: INDIRF8(addr) "l %0" +cmpf: INDIRF4(addr) "s %0" +cmpf: CVFF8(INDIRF4(addr)) "s %0" +cmpf: freg "p" + +stmt: EQF8(cmpf,freg) "fcomp%0\nfstsw %%ax\nsahf\njp 1f\nje %a\n1:\n" +stmt: GEF8(cmpf,freg) "fcomp%0\nfstsw %%ax\nsahf\njp %a\njbe %a\n" +stmt: GTF8(cmpf,freg) "fcomp%0\nfstsw %%ax\nsahf\njp %a\njb %a\n" +stmt: LEF8(cmpf,freg) "fcomp%0\nfstsw %%ax\nsahf\njp %a\njae %a\n" +stmt: LTF8(cmpf,freg) "fcomp%0\nfstsw %%ax\nsahf\njp %a\nja %a\n" +stmt: NEF8(cmpf,freg) "fcomp%0\nfstsw %%ax\nsahf\njp %a\njne %a\n" + +stmt: EQF4(cmpf,freg) "fcomp%0\nfstsw %%ax\nsahf\njp 1f\nje %a\n1:\n" +stmt: GEF4(cmpf,freg) "fcomp%0\nfstsw %%ax\nsahf\njp %a\njbe %a\n" +stmt: GTF4(cmpf,freg) "fcomp%0\nfstsw %%ax\nsahf\njp %a\njb %a\n" +stmt: LEF4(cmpf,freg) "fcomp%0\nfstsw %%ax\nsahf\njp %a\njae %a\n" +stmt: LTF4(cmpf,freg) "fcomp%0\nfstsw %%ax\nsahf\njp %a\nja %a\n" +stmt: NEF4(cmpf,freg) "fcomp%0\nfstsw %%ax\nsahf\njp %a\njne %a\n" + +freg: DIVF8(freg,CVIF8(INDIRI4(addr))) "fidivl %1\n" +freg: DIVF8(CVIF8(INDIRI4(addr)),freg) "fidivrl %0\n" +freg: DIVF8(freg,CVIF8(CVII2(INDIRI2(addr)))) "fidivs %1\n" +freg: DIVF8(CVIF8(CVII2(INDIRI2(addr))),freg) "fidivrs %0\n" +freg: MULF8(freg,CVIF8(INDIRI4(addr))) "fimull %1\n" +freg: MULF8(freg,CVIF8(CVII2(INDIRI2(addr)))) "fimuls %1\n" +freg: SUBF8(freg,CVIF8(INDIRI4(addr))) "fisubl %1\n" +freg: SUBF8(CVIF8(INDIRI4(addr)),freg) "fisubrl %0\n" +freg: SUBF8(freg,CVIF8(CVII2(INDIRI2(addr)))) "fisubs %1\n" +freg: SUBF8(CVIF8(CVII2(INDIRI2(addr))),freg) "fisubrs %0\n" +freg: ADDF8(freg,CVIF8(INDIRI4(addr))) "fiaddl %1\n" +freg: ADDF8(freg,CVIF8(CVII2(INDIRI2(addr)))) "fiadds %1\n" +freg: ADDF8(freg,CVFF8(INDIRF4(addr))) "fdivs %1\n" +freg: SUBF8(freg,CVFF8(INDIRF4(addr))) "fsubs %1\n" +freg: MULF8(freg,CVFF8(INDIRF4(addr))) "fmuls %1\n" +freg: DIVF8(freg,CVFF8(INDIRF4(addr))) "fdivs %1\n" +freg: LOADF8(memf) "fld%0\n" + +reg: CALLI4(addrj) "call %0\naddl $%a,%%esp\n" hasargs(a) +reg: CALLU4(addrj) "call %0\naddl $%a,%%esp\n" hasargs(a) +reg: CALLP4(addrj) "call %0\naddl $%a,%%esp\n" hasargs(a) + +reg: CALLI4(addrj) "call %0\n" 1 +reg: CALLU4(addrj) "call %0\n" 1 +reg: CALLP4(addrj) "call %0\n" 1 + +stmt: CALLV(addrj) "call %0\naddl $%a,%%esp\n" hasargs(a) +stmt: CALLV(addrj) "call %0\n" 1 + +freg: CALLF4(addrj) "call %0\naddl $%a,%%esp\n" hasargs(a) +freg: CALLF4(addrj) "call %0\n" 1 + +stmt: CALLF4(addrj) "call %0\naddl $%a,%%esp\nfstp %%st(0)\n" hasargs(a) +stmt: CALLF4(addrj) "call %0\nfstp %%st(0)\n" 1 + +freg: CALLF8(addrj) "call %0\naddl $%a,%%esp\n" hasargs(a) +freg: CALLF8(addrj) "call %0\n" 1 + +stmt: CALLF8(addrj) "call %0\naddl $%a,%%esp\nfstp %%st(0)\n" hasargs(a) +stmt: CALLF8(addrj) "call %0\nfstp %%st(0)\n" 1 + +stmt: RETI4(reg) "# ret\n" +stmt: RETU4(reg) "# ret\n" +stmt: RETP4(reg) "# ret\n" +stmt: RETF4(freg) "# ret\n" +stmt: RETF8(freg) "# ret\n" +%% +static void progbeg(int argc, char *argv[]) { + int i; + extern Interface x86IR, x86linuxIR; + +#define xx(f) assert(!x86linuxIR.f); x86linuxIR.f = x86IR.f + xx(address); + xx(local); + xx(x.blkfetch); + xx(x.blkstore); + xx(x.blkloop); + xx(x.doarg); +#undef xx + { + union { + char c; + int i; + } u; + u.i = 0; + u.c = 1; + swap = ((int)(u.i == 1)) != IR->little_endian; + } + parseflags(argc, argv); + for (i = 0; i < argc; i++) + if (strcmp(argv[i], "-p") == 0 || strcmp(argv[i], "-pg") == 0) + pflag = 1; + intreg[EAX] = mkreg("%%eax", EAX, 1, IREG); + intreg[EDX] = mkreg("%%edx", EDX, 1, IREG); + intreg[ECX] = mkreg("%%ecx", ECX, 1, IREG); + intreg[EBX] = mkreg("%%ebx", EBX, 1, IREG); + intreg[ESI] = mkreg("%%esi", ESI, 1, IREG); + intreg[EDI] = mkreg("%%edi", EDI, 1, IREG); + shortreg[EAX] = mkreg("%%ax", EAX, 1, IREG); + shortreg[ECX] = mkreg("%%cx", ECX, 1, IREG); + shortreg[EDX] = mkreg("%%dx", EDX, 1, IREG); + shortreg[EBX] = mkreg("%%bx", EBX, 1, IREG); + shortreg[ESI] = mkreg("%%si", ESI, 1, IREG); + shortreg[EDI] = mkreg("%%di", EDI, 1, IREG); + charreg[EAX] = mkreg("%%al", EAX, 1, IREG); + charreg[ECX] = mkreg("%%cl", ECX, 1, IREG); + charreg[EDX] = mkreg("%%dl", EDX, 1, IREG); + charreg[EBX] = mkreg("%%bl", EBX, 1, IREG); + for (i = 0; i < 8; i++) + fltreg[i] = mkreg("%d", i, 0, FREG); + charregw = mkwildcard(charreg); + shortregw = mkwildcard(shortreg); + intregw = mkwildcard(intreg); + fltregw = mkwildcard(fltreg); + + tmask[IREG] = (1<x.regnode->mask |= 1<x.regnode->mask |= 1<type->size > 0) + print(".size %s,%d\n", prevg->x.name, prevg->type->size); + prevg = NULL; +} + +static void progend(void) { + globalend(); + (*IR->segment)(CODE); + print(".ident \"LCC: 4.1\"\n"); +} + +static void target(Node p) { + assert(p); + switch (specific(p->op)) { + case RSH+I: case RSH+U: case LSH+I: case LSH+U: + if (generic(p->kids[1]->op) != CNST + && !( generic(p->kids[1]->op) == INDIR + && specific(p->kids[1]->kids[0]->op) == VREG+P + && p->kids[1]->syms[RX]->u.t.cse + && generic(p->kids[1]->syms[RX]->u.t.cse->op) == CNST)) { + rtarget(p, 1, intreg[ECX]); + setreg(p, intreg[EAX]); + } + break; + case MUL+U: + setreg(p, quo); + rtarget(p, 0, intreg[EAX]); + break; + case DIV+I: case DIV+U: + setreg(p, quo); + rtarget(p, 0, intreg[EAX]); + rtarget(p, 1, intreg[ECX]); + break; + case MOD+I: case MOD+U: + setreg(p, rem); + rtarget(p, 0, intreg[EAX]); + rtarget(p, 1, intreg[ECX]); + break; + case ASGN+B: + rtarget(p, 0, intreg[EDI]); + rtarget(p->kids[1], 0, intreg[ESI]); + break; + case ARG+B: + rtarget(p->kids[0], 0, intreg[ESI]); + break; + case CVF+I: + setreg(p, intreg[EAX]); + break; + case CALL+I: case CALL+U: case CALL+P: case CALL+V: + setreg(p, intreg[EAX]); + break; + case RET+I: case RET+U: case RET+P: + rtarget(p, 0, intreg[EAX]); + break; + } +} + +static void clobber(Node p) { + static int nstack = 0; + + assert(p); + nstack = ckstack(p, nstack); + switch (specific(p->op)) { + case ASGN+B: case ARG+B: + spill(1<op); +#define preg(f) ((f)[getregnum(p->x.kids[0])]->x.name) + + if (op == CVI+I && opsize(p->op) == 4 && opsize(p->x.kids[0]->op) == 1) + print("movsbl %s,%s\n", preg(charreg), p->syms[RX]->x.name); + else if (op == CVI+U && opsize(p->op) == 4 && opsize(p->x.kids[0]->op) == 1) + print("movsbl %s,%s\n", preg(charreg), p->syms[RX]->x.name); + else if (op == CVI+I && opsize(p->op) == 4 && opsize(p->x.kids[0]->op) == 2) + print("movswl %s,%s\n", preg(shortreg), p->syms[RX]->x.name); + else if (op == CVI+U && opsize(p->op) == 4 && opsize(p->x.kids[0]->op) == 2) + print("movswl %s,%s\n", preg(shortreg), p->syms[RX]->x.name); + else if (op == CVU+I && opsize(p->op) == 4 && opsize(p->x.kids[0]->op) == 1) + print("movzbl %s,%s\n", preg(charreg), p->syms[RX]->x.name); + else if (op == CVU+U && opsize(p->op) == 4 && opsize(p->x.kids[0]->op) == 1) + print("movzbl %s,%s\n", preg(charreg), p->syms[RX]->x.name); + else if (op == CVU+I && opsize(p->op) == 4 && opsize(p->x.kids[0]->op) == 2) + print("movzwl %s,%s\n", preg(shortreg), p->syms[RX]->x.name); + else if (op == CVU+U && opsize(p->op) == 4 && opsize(p->x.kids[0]->op) == 2) + print("movzwl %s,%s\n", preg(shortreg), p->syms[RX]->x.name); + else if (generic(op) == CVI || generic(op) == CVU || generic(op) == LOAD) { + char *dst = intreg[getregnum(p)]->x.name; + char *src = preg(intreg); + assert(opsize(p->op) <= opsize(p->x.kids[0]->op)); + if (dst != src) + print("movl %s,%s\n", src, dst); + } else if (op == ARG+B) + print("subl $%d,%%esp\nmovl %%esp,%%edi\nmovl $%d,%%ecx\nrep\nmovsb\n", + roundup(p->syms[0]->u.c.v.i, 4), p->syms[0]->u.c.v.i); +} + +static void function(Symbol f, Symbol caller[], Symbol callee[], int n) { + int i; + + globalend(); + print(".align 16\n"); + print(".type %s,@function\n", f->x.name); + print("%s:\n", f->x.name); + print("pushl %%ebp\n"); + if (pflag) { + static int plab; + print("movl %%esp,%%ebp\n"); + (*IR->segment)(DATA); + print(".align 4\n.LP%d:\n.long 0\n", plab); + (*IR->segment)(CODE); + print("movl $.LP%d,%%edx\ncall mcount\n", plab); + plab++; + } + print("pushl %%ebx\n"); + print("pushl %%esi\n"); + print("pushl %%edi\n"); + print("movl %%esp,%%ebp\n"); + + usedmask[0] = usedmask[1] = 0; + freemask[0] = freemask[1] = ~0U; + offset = 16 + 4; + for (i = 0; callee[i]; i++) { + Symbol p = callee[i]; + Symbol q = caller[i]; + assert(q); + offset = roundup(offset, q->type->align); + p->x.offset = q->x.offset = offset; + p->x.name = q->x.name = stringf("%d", p->x.offset); + p->sclass = q->sclass = AUTO; + offset += roundup(q->type->size, 4); + } + assert(caller[i] == 0); + offset = maxoffset = 0; + gencode(caller, callee); + framesize = roundup(maxoffset, 4); + if (framesize > 0) + print("subl $%d,%%esp\n", framesize); + emitcode(); + print("movl %%ebp,%%esp\n"); + print("popl %%edi\n"); + print("popl %%esi\n"); + print("popl %%ebx\n"); + print("popl %%ebp\n"); + print("ret\n"); + { int l = genlabel(1); + print(".Lf%d:\n", l); + print(".size %s,.Lf%d-%s\n", f->x.name, l, f->x.name); + } +} + +static void defsymbol(Symbol p) { + if (p->scope >= LOCAL && p->sclass == STATIC) + p->x.name = stringf("%s.%d", p->name, genlabel(1)); + else if (p->generated) + p->x.name = stringf(".LC%s", p->name); + else if (p->scope == GLOBAL || p->sclass == EXTERN) + p->x.name = stringf("%s", p->name); + else + p->x.name = p->name; +} + +static void segment(int n) { + if (n == cseg) + return; + cseg = n; + if (cseg == CODE) + print(".text\n"); + else if (cseg == BSS) + print(".bss\n"); + else if (cseg == DATA || cseg == LIT) + print(".data\n"); +} + +static void defconst(int suffix, int size, Value v) { + if (suffix == I && size == 1) + print(".byte %d\n", (int)v.u); + else if (suffix == I && size == 2) + print(".word %d\n", (int)v.i); + else if (suffix == I && size == 4) + print(".long %d\n", (int)v.i); + else if (suffix == U && size == 1) + print(".byte %d\n", (int)((char)v.u)); + else if (suffix == U && size == 2) + print(".word %d\n", (int)v.u); + else if (suffix == U && size == 4) + print(".long %d\n", (int)v.u); + else if (suffix == P && size == 4) + print(".long %d\n", (int)v.p); + else if (suffix == F && size == 4) { + float f = v.d; + print(".long %d\n", (int)(*(unsigned *)&f)); + } else if (suffix == F && size == 8) { + double d = v.d; + unsigned *p = (unsigned *)&d; + print(".long %d\n.long %d\n", (int)p[swap], (int)p[!swap]); + } + else assert(0); +} + +static void defaddress(Symbol p) { + print(".long %s\n", p->x.name); +} + +static void defstring(int n, char *str) { + char *s; + + for (s = str; s < str + n; s++) + print(".byte %d\n", (*s)&0377); +} + +static void export(Symbol p) { + globalend(); + print(".globl %s\n", p->x.name); +} + +static void import(Symbol p) {} + +static void global(Symbol p) { + globalend(); + print(".align %d\n", p->type->align > 4 ? 4 : p->type->align); + if (!p->generated) { + print(".type %s,@%s\n", p->x.name, + isfunc(p->type) ? "function" : "object"); + if (p->type->size > 0) + print(".size %s,%d\n", p->x.name, p->type->size); + else + prevg = p; + } + if (p->u.seg == BSS) { + if (p->sclass == STATIC) + print(".lcomm %s,%d\n", p->x.name, p->type->size); + else + print(".comm %s,%d\n", p->x.name, p->type->size); + } else { + print("%s:\n", p->x.name); + } +} + +static void space(int n) { + if (cseg != BSS) + print(".space %d\n", n); +} + +Interface x86linuxIR = { + 1, 1, 0, /* char */ + 2, 2, 0, /* short */ + 4, 4, 0, /* int */ + 4, 4, 0, /* long */ + 4, 4, 0, /* long long */ + 4, 4, 1, /* float */ + 8, 4, 1, /* double */ + 8, 4, 1, /* long double */ + 4, 4, 0, /* T * */ + 0, 1, 0, /* struct */ + 1, /* little_endian */ + 0, /* mulops_calls */ + 0, /* wants_callb */ + 1, /* wants_argb */ + 0, /* left_to_right */ + 0, /* wants_dag */ + 0, /* unsigned_char */ + 0, /* address */ + blockbeg, + blockend, + defaddress, + defconst, + defstring, + defsymbol, + emit, + export, + function, + gen, + global, + import, + 0, /* local */ + progbeg, + progend, + segment, + space, + stabblock, stabend, 0, stabinit, stabline, stabsym, stabtype, + {1, rmap, + 0, 0, 0, /* blkfetch, blkstore, blkloop */ + _label, + _rule, + _nts, + _kids, + _string, + _templates, + _isinstruction, + _ntname, + emit2, + 0, /* doarg */ + target, + clobber, + } +}; diff --git a/src/cmd/lcpp/Makefile b/src/cmd/lcpp/Makefile new file mode 100644 index 0000000..6027676 --- /dev/null +++ b/src/cmd/lcpp/Makefile @@ -0,0 +1,49 @@ +TOPSRC = $(shell cd ../../..; pwd) +include $(TOPSRC)/target.mk +#include $(TOPSRC)/cross.mk + +OBJS = cpp.o lex.o nlist.o tokens.o macro.o eval.o \ + include.o hideset.o unix.o + +LDFLAGS += -g + +CFLAGS += -Werror -Wall -Os + +all: lcpp + +lcpp: $(OBJS) + ${CC} ${LDFLAGS} -o lcpp.elf $(OBJS) ${LIBS} + ${OBJDUMP} -S lcpp.elf > lcpp.dis + ${SIZE} lcpp.elf + ${ELF2AOUT} lcpp.elf $@ && rm lcpp.elf + +clean: + rm -rf *.o *.elf lcpp *.dis *~ tests + +install: all + install lcpp $(DESTDIR)/bin/ + +$(OBJS): cpp.h + +test: + mkdir -p tests + ./lcpp < ../cpp/tests/test1 > tests/run1 + -diff ../cpp/tests/res1 tests/run1 + ./lcpp < ../cpp/tests/test2 > tests/run2 + -diff ../cpp/tests/res2 tests/run2 + ./lcpp < ../cpp/tests/test3 > tests/run3 + -diff ../cpp/tests/res3 tests/run3 + ./lcpp < ../cpp/tests/test4 > tests/run4 + -diff ../cpp/tests/res4 tests/run4 + -./lcpp < ../cpp/tests/test5 > tests/run5 + -diff ../cpp/tests/res5 tests/run5 + ./lcpp < ../cpp/tests/test6 > tests/run6 + -diff ../cpp/tests/res6 tests/run6 + ./lcpp < ../cpp/tests/test7 > tests/run7 + -diff ../cpp/tests/res7 tests/run7 + ./lcpp < ../cpp/tests/test8 > tests/run8 + -diff ../cpp/tests/res8 tests/run8 + ./lcpp < ../cpp/tests/test9 > tests/run9 + -diff ../cpp/tests/res9 tests/run9 + ./lcpp < ../cpp/tests/test10 > tests/run10 + -diff ../cpp/tests/res10 tests/run10 diff --git a/src/cmd/lcpp/cpp.c b/src/cmd/lcpp/cpp.c new file mode 100644 index 0000000..f082fec --- /dev/null +++ b/src/cmd/lcpp/cpp.c @@ -0,0 +1,323 @@ +#include +#include +#include +#include +#include "cpp.h" + +#define OUTS 4096 + +char outbuf[OUTS]; +char *outp = outbuf; +Source *cursource; +int nerrs; +struct token nltoken = { NL, 0, 0, 0, 1, (uchar*)"\n" }; +char *curtime; +int incdepth; +int ifdepth; +int ifsatisfied[NIF]; +int skipping; + +char rcsid[] = "$Revision: 1.6 $ $Date: 2001/03/27 19:37:59 $"; + +int +main(int argc, char **argv) +{ + Tokenrow tr; + time_t t; + char ebuf[BUFSIZ]; + + setbuf(stderr, ebuf); + t = time(NULL); + curtime = ctime(&t); + maketokenrow(3, &tr); + expandlex(); + setup(argc, argv); + fixlex(); + iniths(); + genline(); + process(&tr); + flushout(); + fflush(stderr); + exit(nerrs > 0); + return 0; +} + +void +process(Tokenrow *trp) +{ + int anymacros = 0; + + for (;;) { + if (trp->tp >= trp->lp) { + trp->tp = trp->lp = trp->bp; + outp = outbuf; + anymacros |= gettokens(trp, 1); + trp->tp = trp->bp; + } + if (trp->tp->type == END) { + if (--incdepth>=0) { + if (cursource->ifdepth) + error(ERROR, + "Unterminated conditional in #include"); + unsetsource(); + cursource->line += cursource->lineinc; + trp->tp = trp->lp; + genline(); + continue; + } + if (ifdepth) + error(ERROR, "Unterminated #if/#ifdef/#ifndef"); + break; + } + if (trp->tp->type==SHARP) { + trp->tp += 1; + control(trp); + } else if (!skipping && anymacros) + expandrow(trp, NULL); + if (skipping) + setempty(trp); + puttokens(trp); + anymacros = 0; + cursource->line += cursource->lineinc; + if (cursource->lineinc>1) { + genline(); + } + } +} + +void +control(Tokenrow *trp) +{ + Nlist *np; + Token *tp; + + tp = trp->tp; + if (tp->type!=NAME) { + if (tp->type==NUMBER) + goto kline; + if (tp->type != NL) + error(ERROR, "Unidentifiable control line"); + return; /* else empty line */ + } + if ((np = lookup(tp, 0))==NULL || ((np->flag&ISKW)==0 && !skipping)) { + error(WARNING, "Unknown preprocessor control %t", tp); + return; + } + if (skipping) { + if ((np->flag&ISKW)==0) + return; + switch (np->val) { + case KENDIF: + if (--ifdepthifdepth; + setempty(trp); + return; + + case KIFDEF: + case KIFNDEF: + case KIF: + if (++ifdepth >= NIF) + error(FATAL, "#if too deeply nested"); + ++cursource->ifdepth; + return; + + case KELIF: + case KELSE: + if (ifdepth<=skipping) + break; + return; + + default: + return; + } + } + switch (np->val) { + case KDEFINE: + dodefine(trp); + break; + + case KUNDEF: + tp += 1; + if (tp->type!=NAME || trp->lp - trp->bp != 4) { + error(ERROR, "Syntax error in #undef"); + break; + } + if ((np = lookup(tp, 0)) != NULL) + np->flag &= ~ISDEFINED; + break; + + case KPRAGMA: + return; + + case KIFDEF: + case KIFNDEF: + case KIF: + if (++ifdepth >= NIF) + error(FATAL, "#if too deeply nested"); + ++cursource->ifdepth; + ifsatisfied[ifdepth] = 0; + if (eval(trp, np->val)) + ifsatisfied[ifdepth] = 1; + else + skipping = ifdepth; + break; + + case KELIF: + if (ifdepth==0) { + error(ERROR, "#elif with no #if"); + return; + } + if (ifsatisfied[ifdepth]==2) + error(ERROR, "#elif after #else"); + if (eval(trp, np->val)) { + if (ifsatisfied[ifdepth]) + skipping = ifdepth; + else { + skipping = 0; + ifsatisfied[ifdepth] = 1; + } + } else + skipping = ifdepth; + break; + + case KELSE: + if (ifdepth==0 || cursource->ifdepth==0) { + error(ERROR, "#else with no #if"); + return; + } + if (ifsatisfied[ifdepth]==2) + error(ERROR, "#else after #else"); + if (trp->lp - trp->bp != 3) + error(ERROR, "Syntax error in #else"); + skipping = ifsatisfied[ifdepth]? ifdepth: 0; + ifsatisfied[ifdepth] = 2; + break; + + case KENDIF: + if (ifdepth==0 || cursource->ifdepth==0) { + error(ERROR, "#endif with no #if"); + return; + } + --ifdepth; + --cursource->ifdepth; + if (trp->lp - trp->bp != 3) + error(WARNING, "Syntax error in #endif"); + break; + + case KERROR: + trp->tp = tp+1; + error(WARNING, "#error directive: %r", trp); + break; + + case KLINE: + trp->tp = tp+1; + expandrow(trp, ""); + tp = trp->bp+2; + kline: + if (tp+1>=trp->lp || tp->type!=NUMBER || tp+3lp + || (tp+3==trp->lp && (((tp+1)->type!=STRING) || *(tp+1)->t=='L'))){ + error(ERROR, "Syntax error in #line"); + return; + } + cursource->line = atol((char*)tp->t)-1; + if (cursource->line<0 || cursource->line>=32768) + error(WARNING, "#line specifies number out of range"); + tp = tp+1; + if (tp+1lp) + cursource->filename=(char*)newstring(tp->t+1,tp->len-2,0); + return; + + case KDEFINED: + error(ERROR, "Bad syntax for control line"); + break; + + case KINCLUDE: + doinclude(trp); + trp->lp = trp->bp; + return; + + case KEVAL: + eval(trp, np->val); + break; + + default: + error(ERROR, "Preprocessor control `%t' not yet implemented", tp); + break; + } + setempty(trp); + return; +} + +void * +domalloc(int size) +{ + void *p = malloc(size); + + if (p==NULL) + error(FATAL, "Out of memory from malloc"); + return p; +} + +void +dofree(void *p) +{ + free(p); +} + +void +error(enum errtype type, char *string, ...) +{ + va_list ap; + char *cp, *ep; + Token *tp; + Tokenrow *trp; + Source *s; + int i; + + fprintf(stderr, "cpp: "); + for (s=cursource; s; s=s->next) + if (*s->filename) + fprintf(stderr, "%s:%d ", s->filename, s->line); + va_start(ap, string); + for (ep=string; *ep; ep++) { + if (*ep=='%') { + switch (*++ep) { + + case 's': + cp = va_arg(ap, char *); + fprintf(stderr, "%s", cp); + break; + case 'd': + i = va_arg(ap, int); + fprintf(stderr, "%d", i); + break; + case 't': + tp = va_arg(ap, Token *); + fprintf(stderr, "%.*s", tp->len, tp->t); + break; + + case 'r': + trp = va_arg(ap, Tokenrow *); + for (tp=trp->tp; tplp&&tp->type!=NL; tp++) { + if (tp>trp->tp && tp->wslen) + fputc(' ', stderr); + fprintf(stderr, "%.*s", tp->len, tp->t); + } + break; + + default: + fputc(*ep, stderr); + break; + } + } else + fputc(*ep, stderr); + } + va_end(ap); + fputc('\n', stderr); + if (type==FATAL) + exit(1); + if (type!=WARNING) + nerrs = 1; + fflush(stderr); +} diff --git a/src/cmd/lcpp/cpp.h b/src/cmd/lcpp/cpp.h new file mode 100644 index 0000000..99ac7d3 --- /dev/null +++ b/src/cmd/lcpp/cpp.h @@ -0,0 +1,162 @@ +#ifdef CROSS +# include +#else +# include +#endif + +#define INS 4096 /* input buffer */ +#define OBS 2048 /* outbut buffer */ +#define NARG 32 /* Max number arguments to a macro */ +#define NINCLUDE 8 /* Max number of include directories (-I) */ +#define NIF 32 /* depth of nesting of #if */ +#ifndef EOF +#define EOF (-1) +#endif +#ifndef NULL +#define NULL 0 +#endif + +#ifndef __alpha +typedef unsigned char uchar; +#endif + +enum toktype { END, UNCLASS, NAME, NUMBER, STRING, CCON, NL, WS, DSHARP, + EQ, NEQ, LEQ, GEQ, LSH, RSH, LAND, LOR, PPLUS, MMINUS, + ARROW, SBRA, SKET, LP, RP, DOT, AND, STAR, PLUS, MINUS, + TILDE, NOT, SLASH, PCT, LT, GT, CIRC, OR, QUEST, + COLON, ASGN, COMMA, SHARP, SEMIC, CBRA, CKET, + ASPLUS, ASMINUS, ASSTAR, ASSLASH, ASPCT, ASCIRC, ASLSH, + ASRSH, ASOR, ASAND, ELLIPS, + DSHARP1, NAME1, DEFINED, UMINUS }; + +enum kwtype { KIF, KIFDEF, KIFNDEF, KELIF, KELSE, KENDIF, KINCLUDE, KDEFINE, + KUNDEF, KLINE, KERROR, KPRAGMA, KDEFINED, + KLINENO, KFILE, KDATE, KTIME, KSTDC, KEVAL }; + +#define ISDEFINED 01 /* has #defined value */ +#define ISKW 02 /* is PP keyword */ +#define ISUNCHANGE 04 /* can't be #defined in PP */ +#define ISMAC 010 /* builtin macro, e.g. __LINE__ */ + +#define EOB 0xFE /* sentinel for end of input buffer */ +#define EOFC 0xFD /* sentinel for end of input file */ +#define XPWS 1 /* token flag: white space to assure token sep. */ + +typedef struct token { + unsigned char type; + unsigned char flag; + unsigned short hideset; + unsigned int wslen; + unsigned int len; + uchar *t; +} Token; + +typedef struct tokenrow { + Token *tp; /* current one to scan */ + Token *bp; /* base (allocated value) */ + Token *lp; /* last+1 token used */ + int max; /* number allocated */ +} Tokenrow; + +typedef struct source { + char *filename; /* name of file of the source */ + int line; /* current line number */ + int lineinc; /* adjustment for \\n lines */ + uchar *inb; /* input buffer */ + uchar *inp; /* input pointer */ + uchar *inl; /* end of input */ + FILE* fd; /* input source */ + int ifdepth; /* conditional nesting in include */ + struct source *next; /* stack for #include */ +} Source; + +typedef struct nlist { + struct nlist *next; + uchar *name; + int len; + Tokenrow *vp; /* value as macro */ + Tokenrow *ap; /* list of argument names, if any */ + char val; /* value as preprocessor name */ + char flag; /* is defined, is pp name */ +} Nlist; + +typedef struct includelist { + char deleted; + char always; + char *file; +} Includelist; + +#define new(t) (t *)domalloc(sizeof(t)) +#define quicklook(a,b) (namebit[(a)&077] & (1<<((b)&037))) +#define quickset(a,b) namebit[(a)&077] |= (1<<((b)&037)) +extern unsigned long namebit[077+1]; + +enum errtype { WARNING, ERROR, FATAL }; + +void expandlex(void); +void fixlex(void); +void setup(int, char **); +int gettokens(Tokenrow *, int); +int comparetokens(Tokenrow *, Tokenrow *); +Source *setsource(char *, FILE *, char *); +void unsetsource(void); +void puttokens(Tokenrow *); +void process(Tokenrow *); +void *domalloc(int); +void dofree(void *); +void error(enum errtype, char *, ...); +void flushout(void); +int fillbuf(Source *); +int trigraph(Source *); +int foldline(Source *); +Nlist *lookup(Token *, int); +void control(Tokenrow *); +void dodefine(Tokenrow *); +void doadefine(Tokenrow *, int); +void doinclude(Tokenrow *); +void doif(Tokenrow *, enum kwtype); +void expand(Tokenrow *, Nlist *); +void builtin(Tokenrow *, int); +int gatherargs(Tokenrow *, Tokenrow **, int *); +void substargs(Nlist *, Tokenrow *, Tokenrow **); +void expandrow(Tokenrow *, char *); +void maketokenrow(int, Tokenrow *); +Tokenrow *copytokenrow(Tokenrow *, Tokenrow *); +Token *growtokenrow(Tokenrow *); +Tokenrow *normtokenrow(Tokenrow *); +void adjustrow(Tokenrow *, int); +void movetokenrow(Tokenrow *, Tokenrow *); +void insertrow(Tokenrow *, int, Tokenrow *); +void peektokens(Tokenrow *, char *); +void doconcat(Tokenrow *); +Tokenrow *stringify(Tokenrow *); +int lookuparg(Nlist *, Token *); +long eval(Tokenrow *, int); +void genline(void); +void setempty(Tokenrow *); +void makespace(Tokenrow *); +char *outnum(char *, int); +int digit(int); +uchar *newstring(uchar *, int, int); +int checkhideset(int, Nlist *); +void prhideset(int); +int newhideset(int, Nlist *); +int unionhideset(int, int); +void iniths(void); +void setobjname(char *); +#define rowlen(tokrow) ((tokrow)->lp - (tokrow)->bp) + +extern char *outp; +extern Token nltoken; +extern Source *cursource; +extern char *curtime; +extern int incdepth; +extern int ifdepth; +extern int ifsatisfied[NIF]; +extern int Mflag; +extern int skipping; +extern int verbose; +extern int Cplusplus; +extern Nlist *kwdefined; +extern Includelist includelist[NINCLUDE]; +extern char wd[]; diff --git a/src/cmd/lcpp/eval.c b/src/cmd/lcpp/eval.c new file mode 100644 index 0000000..9efb88a --- /dev/null +++ b/src/cmd/lcpp/eval.c @@ -0,0 +1,530 @@ +#include +#include +#include "cpp.h" + +#define NSTAK 32 +#define SGN 0 +#define UNS 1 +#define UND 2 + +#define UNSMARK 0x1000 + +struct value { + long val; + int type; +}; + +/* conversion types */ +#define RELAT 1 +#define ARITH 2 +#define LOGIC 3 +#define SPCL 4 +#define SHIFT 5 +#define UNARY 6 + +/* operator priority, arity, and conversion type, indexed by tokentype */ +struct pri { + char pri; + char arity; + char ctype; +} priority[] = { + { 0, 0, 0 }, /* END */ + { 0, 0, 0 }, /* UNCLASS */ + { 0, 0, 0 }, /* NAME */ + { 0, 0, 0 }, /* NUMBER */ + { 0, 0, 0 }, /* STRING */ + { 0, 0, 0 }, /* CCON */ + { 0, 0, 0 }, /* NL */ + { 0, 0, 0 }, /* WS */ + { 0, 0, 0 }, /* DSHARP */ + { 11, 2, RELAT }, /* EQ */ + { 11, 2, RELAT }, /* NEQ */ + { 12, 2, RELAT }, /* LEQ */ + { 12, 2, RELAT }, /* GEQ */ + { 13, 2, SHIFT }, /* LSH */ + { 13, 2, SHIFT }, /* RSH */ + { 7, 2, LOGIC }, /* LAND */ + { 6, 2, LOGIC }, /* LOR */ + { 0, 0, 0 }, /* PPLUS */ + { 0, 0, 0 }, /* MMINUS */ + { 0, 0, 0 }, /* ARROW */ + { 0, 0, 0 }, /* SBRA */ + { 0, 0, 0 }, /* SKET */ + { 3, 0, 0 }, /* LP */ + { 3, 0, 0 }, /* RP */ + { 0, 0, 0 }, /* DOT */ + { 10, 2, ARITH }, /* AND */ + { 15, 2, ARITH }, /* STAR */ + { 14, 2, ARITH }, /* PLUS */ + { 14, 2, ARITH }, /* MINUS */ + { 16, 1, UNARY }, /* TILDE */ + { 16, 1, UNARY }, /* NOT */ + { 15, 2, ARITH }, /* SLASH */ + { 15, 2, ARITH }, /* PCT */ + { 12, 2, RELAT }, /* LT */ + { 12, 2, RELAT }, /* GT */ + { 9, 2, ARITH }, /* CIRC */ + { 8, 2, ARITH }, /* OR */ + { 5, 2, SPCL }, /* QUEST */ + { 5, 2, SPCL }, /* COLON */ + { 0, 0, 0 }, /* ASGN */ + { 4, 2, 0 }, /* COMMA */ + { 0, 0, 0 }, /* SHARP */ + { 0, 0, 0 }, /* SEMIC */ + { 0, 0, 0 }, /* CBRA */ + { 0, 0, 0 }, /* CKET */ + { 0, 0, 0 }, /* ASPLUS */ + { 0, 0, 0 }, /* ASMINUS */ + { 0, 0, 0 }, /* ASSTAR */ + { 0, 0, 0 }, /* ASSLASH */ + { 0, 0, 0 }, /* ASPCT */ + { 0, 0, 0 }, /* ASCIRC */ + { 0, 0, 0 }, /* ASLSH */ + { 0, 0, 0 }, /* ASRSH */ + { 0, 0, 0 }, /* ASOR */ + { 0, 0, 0 }, /* ASAND */ + { 0, 0, 0 }, /* ELLIPS */ + { 0, 0, 0 }, /* DSHARP1 */ + { 0, 0, 0 }, /* NAME1 */ + { 16, 1, UNARY }, /* DEFINED */ + { 16, 0, UNARY }, /* UMINUS */ +}; + +int evalop(struct pri); +struct value tokval(Token *); +struct value vals[NSTAK], *vp; +enum toktype ops[NSTAK], *op; + +/* + * Evaluate an #if #elif #ifdef #ifndef line. trp->tp points to the keyword. + */ +long +eval(Tokenrow *trp, int kw) +{ + Token *tp; + Nlist *np; + int ntok, rand; + + trp->tp++; + if (kw==KIFDEF || kw==KIFNDEF) { + if (trp->lp - trp->bp != 4 || trp->tp->type!=NAME) { + error(ERROR, "Syntax error in #ifdef/#ifndef"); + return 0; + } + np = lookup(trp->tp, 0); + return (kw==KIFDEF) == (np && np->flag&(ISDEFINED|ISMAC)); + } + ntok = trp->tp - trp->bp; + kwdefined->val = KDEFINED; /* activate special meaning of defined */ + expandrow(trp, ""); + kwdefined->val = NAME; + vp = vals; + op = ops; + *op++ = END; + for (rand=0, tp = trp->bp+ntok; tp < trp->lp; tp++) { + switch(tp->type) { + case WS: + case NL: + continue; + + /* nilary */ + case NAME: + case NAME1: + case NUMBER: + case CCON: + case STRING: + if (rand) + goto syntax; + if (vp == &vals[NSTAK]) { + error(ERROR, "Eval botch (stack overflow)"); + return 0; + } + *vp++ = tokval(tp); + rand = 1; + continue; + + /* unary */ + case DEFINED: + case TILDE: + case NOT: + if (rand) + goto syntax; + *op++ = tp->type; + continue; + + /* unary-binary */ + case PLUS: case MINUS: case STAR: case AND: + if (rand==0) { + if (tp->type==MINUS) + *op++ = UMINUS; + if (tp->type==STAR || tp->type==AND) { + error(ERROR, "Illegal operator * or & in #if/#elsif"); + return 0; + } + continue; + } + /* flow through */ + + /* plain binary */ + case EQ: case NEQ: case LEQ: case GEQ: case LSH: case RSH: + case LAND: case LOR: case SLASH: case PCT: + case LT: case GT: case CIRC: case OR: case QUEST: + case COLON: case COMMA: + if (rand==0) + goto syntax; + if (evalop(priority[tp->type])!=0) + return 0; + *op++ = tp->type; + rand = 0; + continue; + + case LP: + if (rand) + goto syntax; + *op++ = LP; + continue; + + case RP: + if (!rand) + goto syntax; + if (evalop(priority[RP])!=0) + return 0; + if (op<=ops || op[-1]!=LP) { + goto syntax; + } + op--; + continue; + + default: + error(ERROR,"Bad operator (%t) in #if/#elsif", tp); + return 0; + } + } + if (rand==0) + goto syntax; + if (evalop(priority[END])!=0) + return 0; + if (op!=&ops[1] || vp!=&vals[1]) { + error(ERROR, "Botch in #if/#elsif"); + return 0; + } + if (vals[0].type==UND) + error(ERROR, "Undefined expression value"); + return vals[0].val; +syntax: + error(ERROR, "Syntax error in #if/#elsif"); + return 0; +} + +int +evalop(struct pri pri) +{ + struct value v1, v2; + long rv1, rv2; + int rtype, oper; + + v2.val = 0; + v2.type = 0; + rv2 = 0; + rtype = 0; + while (pri.pri < priority[op[-1]].pri) { + oper = *--op; + if (priority[oper].arity==2) { + v2 = *--vp; + rv2 = v2.val; + } + v1 = *--vp; + rv1 = v1.val; +/*lint -e574 -e644 */ + switch (priority[oper].ctype) { + case 0: + default: + error(WARNING, "Syntax error in #if/#endif"); + return 1; + case ARITH: + case RELAT: + if (v1.type==UNS || v2.type==UNS) + rtype = UNS; + else + rtype = SGN; + if (v1.type==UND || v2.type==UND) + rtype = UND; + if (priority[oper].ctype==RELAT && rtype==UNS) { + oper |= UNSMARK; + rtype = SGN; + } + break; + case SHIFT: + if (v1.type==UND || v2.type==UND) + rtype = UND; + else + rtype = v1.type; + if (rtype==UNS) + oper |= UNSMARK; + break; + case UNARY: + rtype = v1.type; + break; + case LOGIC: + case SPCL: + break; + } + switch (oper) { + case EQ: case EQ|UNSMARK: + rv1 = rv1==rv2; break; + case NEQ: case NEQ|UNSMARK: + rv1 = rv1!=rv2; break; + case LEQ: + rv1 = rv1<=rv2; break; + case GEQ: + rv1 = rv1>=rv2; break; + case LT: + rv1 = rv1rv2; break; + case LEQ|UNSMARK: + rv1 = (unsigned long)rv1<=rv2; break; + case GEQ|UNSMARK: + rv1 = (unsigned long)rv1>=rv2; break; + case LT|UNSMARK: + rv1 = (unsigned long)rv1rv2; break; + case LSH: + rv1 <<= rv2; break; + case LSH|UNSMARK: + rv1 = (unsigned long)rv1<>= rv2; break; + case RSH|UNSMARK: + rv1 = (unsigned long)rv1>>rv2; break; + case LAND: + rtype = UND; + if (v1.type==UND) + break; + if (rv1!=0) { + if (v2.type==UND) + break; + rv1 = rv2!=0; + } else + rv1 = 0; + rtype = SGN; + break; + case LOR: + rtype = UND; + if (v1.type==UND) + break; + if (rv1==0) { + if (v2.type==UND) + break; + rv1 = rv2!=0; + } else + rv1 = 1; + rtype = SGN; + break; + case AND: + rv1 &= rv2; break; + case STAR: + rv1 *= rv2; break; + case PLUS: + rv1 += rv2; break; + case MINUS: + rv1 -= rv2; break; + case UMINUS: + if (v1.type==UND) + rtype = UND; + rv1 = -rv1; break; + case OR: + rv1 |= rv2; break; + case CIRC: + rv1 ^= rv2; break; + case TILDE: + rv1 = ~rv1; break; + case NOT: + rv1 = !rv1; if (rtype!=UND) rtype = SGN; break; + case SLASH: + if (rv2==0) { + rtype = UND; + break; + } + if (rtype==UNS) + rv1 /= (unsigned long)rv2; + else + rv1 /= rv2; + break; + case PCT: + if (rv2==0) { + rtype = UND; + break; + } + if (rtype==UNS) + rv1 %= (unsigned long)rv2; + else + rv1 %= rv2; + break; + case COLON: + if (op[-1] != QUEST) + error(ERROR, "Bad ?: in #if/endif"); + else { + op--; + if ((--vp)->val==0) + v1 = v2; + rtype = v1.type; + rv1 = v1.val; + } + break; + case DEFINED: + break; + default: + error(ERROR, "Eval botch (unknown operator)"); + return 1; + } +/*lint +e574 +e644 */ + v1.val = rv1; + v1.type = rtype; + if (vp == &vals[NSTAK]) { + error(ERROR, "Eval botch (stack overflow)"); + return 0; + } + *vp++ = v1; + } + return 0; +} + +struct value +tokval(Token *tp) +{ + struct value v; + Nlist *np; + int i, base, c; + unsigned long n; + uchar *p; + + v.type = SGN; + v.val = 0; + switch (tp->type) { + + case NAME: + v.val = 0; + break; + + case NAME1: + if ((np = lookup(tp, 0)) != NULL && np->flag&(ISDEFINED|ISMAC)) + v.val = 1; + break; + + case NUMBER: + n = 0; + base = 10; + p = tp->t; + c = p[tp->len]; + p[tp->len] = '\0'; + if (*p=='0') { + base = 8; + if (p[1]=='x' || p[1]=='X') { + base = 16; + p++; + } + p++; + } + for (;; p++) { + if ((i = digit(*p)) < 0) + break; + if (i>=base) + error(WARNING, + "Bad digit in number %t", tp); + n *= base; + n += i; + } + if (n>=0x80000000 && base!=10) + v.type = UNS; + for (; *p; p++) { + if (*p=='u' || *p=='U') + v.type = UNS; + else if (*p=='l' || *p=='L') + ; + else { + error(ERROR, + "Bad number %t in #if/#elsif", tp); + break; + } + } + v.val = n; + tp->t[tp->len] = c; + break; + + case CCON: + n = 0; + p = tp->t; + if (*p=='L') { + p += 1; + error(WARNING, "Wide char constant value undefined"); + } + p += 1; + if (*p=='\\') { + p += 1; + if ((i = digit(*p))>=0 && i<=7) { + n = i; + p += 1; + if ((i = digit(*p))>=0 && i<=7) { + p += 1; + n <<= 3; + n += i; + if ((i = digit(*p))>=0 && i<=7) { + p += 1; + n <<= 3; + n += i; + } + } + } else if (*p=='x') { + p += 1; + while ((i = digit(*p))>=0 && i<=15) { + p += 1; + n <<= 4; + n += i; + } + } else { + static char cvcon[] + = "b\bf\fn\nr\rt\tv\v''\"\"??\\\\"; + for (i=0; i=sizeof(cvcon)) + error(WARNING, + "Undefined escape in character constant"); + } + } else if (*p=='\'') + error(ERROR, "Empty character constant"); + else + n = *p++; + if (*p!='\'') + error(WARNING, "Multibyte character constant undefined"); + else if (n>127) + error(WARNING, "Character constant taken as not signed"); + v.val = n; + break; + + case STRING: + error(ERROR, "String in #if/#elsif"); + break; + } + return v; +} + +int +digit(int i) +{ + if ('0'<=i && i<='9') + i -= '0'; + else if ('a'<=i && i<='f') + i -= 'a'-10; + else if ('A'<=i && i<='F') + i -= 'A'-10; + else + i = -1; + return i; +} diff --git a/src/cmd/lcpp/hideset.c b/src/cmd/lcpp/hideset.c new file mode 100644 index 0000000..ef06d53 --- /dev/null +++ b/src/cmd/lcpp/hideset.c @@ -0,0 +1,111 @@ +#include +#include +#include "cpp.h" + +/* + * A hideset is a null-terminated array of Nlist pointers. + * They are referred to by indices in the hidesets array. + * Hideset 0 is empty. + */ + +#define HSSIZ 32 +typedef Nlist **Hideset; +Hideset *hidesets; +int nhidesets = 0; +int maxhidesets = 3; +int inserths(Hideset, Hideset, Nlist *); + +/* + * Test for membership in a hideset + */ +int +checkhideset(int hs, Nlist *np) +{ + Hideset hsp; + + if (hs>=nhidesets) + abort(); + for (hsp = hidesets[hs]; *hsp; hsp++) { + if (*hsp == np) + return 1; + } + return 0; +} + +/* + * Return the (possibly new) hideset obtained by adding np to hs. + */ +int +newhideset(int hs, Nlist *np) +{ + int i, len; + Nlist *nhs[HSSIZ+3]; + Hideset hs1, hs2; + + len = inserths(nhs, hidesets[hs], np); + for (i=0; i=HSSIZ) + return hs; + if (nhidesets >= maxhidesets) { + maxhidesets = 3*maxhidesets/2+1; + hidesets = (Hideset *)realloc(hidesets, (sizeof (Hideset *))*maxhidesets); + if (hidesets == NULL) + error(FATAL, "Out of memory from realloc"); + } + hs1 = (Hideset)domalloc(len*sizeof *hs1); + memmove(hs1, nhs, len*sizeof *hs1); + hidesets[nhidesets] = hs1; + return nhidesets++; +} + +int +inserths(Hideset dhs, Hideset shs, Nlist *np) +{ + Hideset odhs = dhs; + + while (*shs && *shs < np) + *dhs++ = *shs++; + if (*shs != np) + *dhs++ = np; + do { + *dhs++ = *shs; + } while (*shs++); + return dhs - odhs; +} + +/* + * Hideset union + */ +int +unionhideset(int hs1, int hs2) +{ + Hideset hp; + + for (hp = hidesets[hs2]; *hp; hp++) + hs1 = newhideset(hs1, *hp); + return hs1; +} + +void +iniths(void) +{ + hidesets = (Hideset *)domalloc(maxhidesets*sizeof(Hideset *)); + hidesets[0] = (Hideset)domalloc(sizeof *hidesets[0]); + *hidesets[0] = NULL; + nhidesets++; +} + +void +prhideset(int hs) +{ + Hideset np; + + for (np = hidesets[hs]; *np; np++) { + fprintf(stderr, (char*)(*np)->name, (*np)->len); + fprintf(stderr, " "); + } +} diff --git a/src/cmd/lcpp/include.c b/src/cmd/lcpp/include.c new file mode 100644 index 0000000..6f65858 --- /dev/null +++ b/src/cmd/lcpp/include.c @@ -0,0 +1,118 @@ +#include +#include +#include "cpp.h" + +Includelist includelist[NINCLUDE]; + +extern char *objname; + +void +doinclude(Tokenrow *trp) +{ + char fname[256], iname[256]; + Includelist *ip; + int angled, len, i; + FILE *fd; + + trp->tp += 1; + if (trp->tp>=trp->lp) + goto syntax; + if (trp->tp->type!=STRING && trp->tp->type!=LT) { + len = trp->tp - trp->bp; + expandrow(trp, ""); + trp->tp = trp->bp+len; + } + if (trp->tp->type==STRING) { + len = trp->tp->len-2; + if (len > sizeof(fname) - 1) + len = sizeof(fname) - 1; + strncpy(fname, (char*)trp->tp->t+1, len); + angled = 0; + } else if (trp->tp->type==LT) { + len = 0; + trp->tp++; + while (trp->tp->type!=GT) { + if (trp->tp>trp->lp || len+trp->tp->len+2 >= sizeof(fname)) + goto syntax; + strncpy(fname+len, (char*)trp->tp->t, trp->tp->len); + len += trp->tp->len; + trp->tp++; + } + angled = 1; + } else + goto syntax; + trp->tp += 2; + if (trp->tp < trp->lp || len==0) + goto syntax; + fname[len] = '\0'; + if (fname[0]=='/') { + fd = fopen(fname, "r"); + strcpy(iname, fname); + } else for (fd = NULL,i=NINCLUDE-1; i>=0; i--) { + ip = &includelist[i]; + if (ip->file==NULL || ip->deleted || (angled && ip->always==0)) + continue; + if (strlen(fname)+strlen(ip->file)+2 > sizeof(iname)) + continue; + strcpy(iname, ip->file); + strcat(iname, "/"); + strcat(iname, fname); + if ((fd = fopen(iname, "r")) != NULL) + break; + } + if (Mflag > 1 || (! angled && Mflag == 1)) { + fwrite(objname,1,strlen(objname),stdout); + fwrite(iname,1,strlen(iname),stdout); + fwrite("\n",1,1,stdout); + } + if (fd != NULL) { + if (++incdepth > 10) + error(FATAL, "#include too deeply nested"); + setsource((char*)newstring((uchar*)iname, strlen(iname), 0), fd, NULL); + genline(); + } else { + trp->tp = trp->bp+2; + error(ERROR, "Could not find include file %r", trp); + } + return; +syntax: + error(ERROR, "Syntax error in #include"); + return; +} + +/* + * Generate a line directive for cursource + */ +void +genline(void) +{ + static Token ta = { UNCLASS }; + static Tokenrow tr = { &ta, &ta, &ta+1, 1 }; + uchar *p; + + ta.t = p = (uchar*)outp; + strcpy((char*)p, "#line "); + p += sizeof("#line ")-1; + p = (uchar*)outnum((char*)p, cursource->line); + *p++ = ' '; *p++ = '"'; + strcpy((char*)p, cursource->filename); + p += strlen((char*)p); + *p++ = '"'; *p++ = '\n'; + ta.len = (char*)p-outp; + outp = (char*)p; + tr.tp = tr.bp; + puttokens(&tr); +} + +void +setobjname(char *f) +{ + int n = strlen(f); + objname = (char*)domalloc(n+5); + strcpy(objname,f); + if(objname[n-2]=='.'){ + strcpy(objname+n-1,"$O: "); + }else{ + strcpy(objname+n,"$O: "); + } +} diff --git a/src/cmd/lcpp/lex.c b/src/cmd/lcpp/lex.c new file mode 100644 index 0000000..0920aef --- /dev/null +++ b/src/cmd/lcpp/lex.c @@ -0,0 +1,579 @@ +#include +#include +#include "cpp.h" + +/* + * lexical FSM encoding + * when in state state, and one of the characters + * in ch arrives, enter nextstate. + * States >= S_SELF are either final, or at least require special action. + * In 'fsm' there is a line for each state X charset X nextstate. + * List chars that overwrite previous entries later (e.g. C_ALPH + * can be overridden by '_' by a later entry; and C_XX is the + * the universal set, and should always be first. + * States above S_SELF are represented in the big table as negative values. + * S_SELF and S_SELFB encode the resulting token type in the upper bits. + * These actions differ in that S_SELF doesn't have a lookahead char, + * S_SELFB does. + * + * The encoding is blown out into a big table for time-efficiency. + * Entries have + * nextstate: 6 bits; ?\ marker: 1 bit; tokentype: 9 bits. + */ + +#define MAXSTATE 32 +#define ACT(tok,act) ((tok<<7)+act) +#define QBSBIT 0100 +#define GETACT(st) (st>>7)&0x1ff + +/* character classes */ +#define C_WS 1 +#define C_ALPH 2 +#define C_NUM 3 +#define C_EOF 4 +#define C_XX 5 + +enum state { + START=0, NUM1, NUM2, NUM3, ID1, ST1, ST2, ST3, COM1, COM2, COM3, COM4, + CC1, CC2, WS1, PLUS1, MINUS1, STAR1, SLASH1, PCT1, SHARP1, + CIRC1, GT1, GT2, LT1, LT2, OR1, AND1, ASG1, NOT1, DOTS1, + S_SELF=MAXSTATE, S_SELFB, S_EOF, S_NL, S_EOFSTR, + S_STNL, S_COMNL, S_EOFCOM, S_COMMENT, S_EOB, S_WS, S_NAME +}; + +int tottok; +int tokkind[256]; +struct fsm { + int state; /* if in this state */ + uchar ch[4]; /* and see one of these characters */ + int nextstate; /* enter this state if +ve */ +}; + +/*const*/ struct fsm fsm[] = { + /* start state */ + { START, { C_XX }, ACT(UNCLASS,S_SELF) }, + { START, { ' ', '\t', '\v' }, WS1 }, + { START, { C_NUM }, NUM1 }, + { START, { '.' }, NUM3 }, + { START, { C_ALPH }, ID1 }, + { START, { 'L' }, ST1 }, + { START, { '"' }, ST2 }, + { START, { '\'' }, CC1 }, + { START, { '/' }, COM1 }, + { START, { EOFC }, S_EOF }, + { START, { '\n' }, S_NL }, + { START, { '-' }, MINUS1 }, + { START, { '+' }, PLUS1 }, + { START, { '<' }, LT1 }, + { START, { '>' }, GT1 }, + { START, { '=' }, ASG1 }, + { START, { '!' }, NOT1 }, + { START, { '&' }, AND1 }, + { START, { '|' }, OR1 }, + { START, { '#' }, SHARP1 }, + { START, { '%' }, PCT1 }, + { START, { '[' }, ACT(SBRA,S_SELF) }, + { START, { ']' }, ACT(SKET,S_SELF) }, + { START, { '(' }, ACT(LP,S_SELF) }, + { START, { ')' }, ACT(RP,S_SELF) }, + { START, { '*' }, STAR1 }, + { START, { ',' }, ACT(COMMA,S_SELF) }, + { START, { '?' }, ACT(QUEST,S_SELF) }, + { START, { ':' }, ACT(COLON,S_SELF) }, + { START, { ';' }, ACT(SEMIC,S_SELF) }, + { START, { '{' }, ACT(CBRA,S_SELF) }, + { START, { '}' }, ACT(CKET,S_SELF) }, + { START, { '~' }, ACT(TILDE,S_SELF) }, + { START, { '^' }, CIRC1 }, + + /* saw a digit */ + { NUM1, { C_XX }, ACT(NUMBER,S_SELFB) }, + { NUM1, { C_NUM, C_ALPH, '.' }, NUM1 }, + { NUM1, { 'E', 'e' }, NUM2 }, + { NUM1, { '_' }, ACT(NUMBER,S_SELFB) }, + + /* saw possible start of exponent, digits-e */ + { NUM2, { C_XX }, ACT(NUMBER,S_SELFB) }, + { NUM2, { '+', '-' }, NUM1 }, + { NUM2, { C_NUM, C_ALPH }, NUM1 }, + { NUM2, { '_' }, ACT(NUMBER,S_SELFB) }, + + /* saw a '.', which could be a number or an operator */ + { NUM3, { C_XX }, ACT(DOT,S_SELFB) }, + { NUM3, { '.' }, DOTS1 }, + { NUM3, { C_NUM }, NUM1 }, + + { DOTS1, { C_XX }, ACT(UNCLASS, S_SELFB) }, + { DOTS1, { C_NUM }, NUM1 }, + { DOTS1, { '.' }, ACT(ELLIPS, S_SELF) }, + + /* saw a letter or _ */ + { ID1, { C_XX }, ACT(NAME,S_NAME) }, + { ID1, { C_ALPH, C_NUM }, ID1 }, + + /* saw L (start of wide string?) */ + { ST1, { C_XX }, ACT(NAME,S_NAME) }, + { ST1, { C_ALPH, C_NUM }, ID1 }, + { ST1, { '"' }, ST2 }, + { ST1, { '\'' }, CC1 }, + + /* saw " beginning string */ + { ST2, { C_XX }, ST2 }, + { ST2, { '"' }, ACT(STRING, S_SELF) }, + { ST2, { '\\' }, ST3 }, + { ST2, { '\n' }, S_STNL }, + { ST2, { EOFC }, S_EOFSTR }, + + /* saw \ in string */ + { ST3, { C_XX }, ST2 }, + { ST3, { '\n' }, S_STNL }, + { ST3, { EOFC }, S_EOFSTR }, + + /* saw ' beginning character const */ + { CC1, { C_XX }, CC1 }, + { CC1, { '\'' }, ACT(CCON, S_SELF) }, + { CC1, { '\\' }, CC2 }, + { CC1, { '\n' }, S_STNL }, + { CC1, { EOFC }, S_EOFSTR }, + + /* saw \ in ccon */ + { CC2, { C_XX }, CC1 }, + { CC2, { '\n' }, S_STNL }, + { CC2, { EOFC }, S_EOFSTR }, + + /* saw /, perhaps start of comment */ + { COM1, { C_XX }, ACT(SLASH, S_SELFB) }, + { COM1, { '=' }, ACT(ASSLASH, S_SELF) }, + { COM1, { '*' }, COM2 }, + { COM1, { '/' }, COM4 }, + + /* saw / then *, start of comment */ + { COM2, { C_XX }, COM2 }, + { COM2, { '\n' }, S_COMNL }, + { COM2, { '*' }, COM3 }, + { COM2, { EOFC }, S_EOFCOM }, + + /* saw the * possibly ending a comment */ + { COM3, { C_XX }, COM2 }, + { COM3, { '\n' }, S_COMNL }, + { COM3, { '*' }, COM3 }, + { COM3, { '/' }, S_COMMENT }, + + /* // comment */ + { COM4, { C_XX }, COM4 }, + { COM4, { '\n' }, S_NL }, + { COM4, { EOFC }, S_EOFCOM }, + + /* saw white space, eat it up */ + { WS1, { C_XX }, S_WS }, + { WS1, { ' ', '\t', '\v' }, WS1 }, + + /* saw -, check --, -=, -> */ + { MINUS1, { C_XX }, ACT(MINUS, S_SELFB) }, + { MINUS1, { '-' }, ACT(MMINUS, S_SELF) }, + { MINUS1, { '=' }, ACT(ASMINUS,S_SELF) }, + { MINUS1, { '>' }, ACT(ARROW,S_SELF) }, + + /* saw +, check ++, += */ + { PLUS1, { C_XX }, ACT(PLUS, S_SELFB) }, + { PLUS1, { '+' }, ACT(PPLUS, S_SELF) }, + { PLUS1, { '=' }, ACT(ASPLUS, S_SELF) }, + + /* saw <, check <<, <<=, <= */ + { LT1, { C_XX }, ACT(LT, S_SELFB) }, + { LT1, { '<' }, LT2 }, + { LT1, { '=' }, ACT(LEQ, S_SELF) }, + { LT2, { C_XX }, ACT(LSH, S_SELFB) }, + { LT2, { '=' }, ACT(ASLSH, S_SELF) }, + + /* saw >, check >>, >>=, >= */ + { GT1, { C_XX }, ACT(GT, S_SELFB) }, + { GT1, { '>' }, GT2 }, + { GT1, { '=' }, ACT(GEQ, S_SELF) }, + { GT2, { C_XX }, ACT(RSH, S_SELFB) }, + { GT2, { '=' }, ACT(ASRSH, S_SELF) }, + + /* = */ + { ASG1, { C_XX }, ACT(ASGN, S_SELFB) }, + { ASG1, { '=' }, ACT(EQ, S_SELF) }, + + /* ! */ + { NOT1, { C_XX }, ACT(NOT, S_SELFB) }, + { NOT1, { '=' }, ACT(NEQ, S_SELF) }, + + /* & */ + { AND1, { C_XX }, ACT(AND, S_SELFB) }, + { AND1, { '&' }, ACT(LAND, S_SELF) }, + { AND1, { '=' }, ACT(ASAND, S_SELF) }, + + /* | */ + { OR1, { C_XX }, ACT(OR, S_SELFB) }, + { OR1, { '|' }, ACT(LOR, S_SELF) }, + { OR1, { '=' }, ACT(ASOR, S_SELF) }, + + /* # */ + { SHARP1, { C_XX }, ACT(SHARP, S_SELFB) }, + { SHARP1, { '#' }, ACT(DSHARP, S_SELF) }, + + /* % */ + { PCT1, { C_XX }, ACT(PCT, S_SELFB) }, + { PCT1, { '=' }, ACT(ASPCT, S_SELF) }, + + /* * */ + { STAR1, { C_XX }, ACT(STAR, S_SELFB) }, + { STAR1, { '=' }, ACT(ASSTAR, S_SELF) }, + + /* ^ */ + { CIRC1, { C_XX }, ACT(CIRC, S_SELFB) }, + { CIRC1, { '=' }, ACT(ASCIRC, S_SELF) }, + + { -1 }, +}; + +/* first index is char, second is state */ +/* increase #states to power of 2 to encourage use of shift */ +short bigfsm[256][MAXSTATE]; + +void +expandlex(void) +{ + /*const*/ struct fsm *fp; + int i, j, nstate; + + for (fp = fsm; fp->state>=0; fp++) { + for (i=0; fp->ch[i]; i++) { + nstate = fp->nextstate; + if (nstate >= S_SELF) + nstate = ~nstate; + switch (fp->ch[i]) { + + case C_XX: /* random characters */ + for (j=0; j<256; j++) + bigfsm[j][fp->state] = nstate; + continue; + case C_ALPH: + for (j=0; j<=256; j++) + if (('a'<=j && j<='z') || + ('A'<=j && j<='Z') || j=='_') + bigfsm[j][fp->state] = nstate; + continue; + case C_NUM: + for (j='0'; j<='9'; j++) + bigfsm[j][fp->state] = nstate; + continue; + default: + bigfsm[fp->ch[i]][fp->state] = nstate; + } + } + } + /* install special cases for ? (trigraphs), \ (splicing), runes, and EOB */ + for (i=0; i0) + bigfsm[j][i] = ~bigfsm[j][i]; + bigfsm[j][i] &= ~QBSBIT; + } + bigfsm[EOB][i] = ~S_EOB; + if (bigfsm[EOFC][i]>=0) + bigfsm[EOFC][i] = ~S_EOF; + } +} + +void +fixlex(void) +{ + /* do C++ comments? */ + if (Cplusplus==0) + bigfsm['/'][COM1] = bigfsm['x'][COM1]; +} + +/* + * fill in a row of tokens from input, terminated by NL or END + * First token is put at trp->lp. + * Reset is non-zero when the input buffer can be "rewound." + * The value is a flag indicating that possible macros have + * been seen in the row. + */ +int +gettokens(Tokenrow *trp, int reset) +{ + register int c, state, oldstate; + register uchar *ip; + register Token *tp, *maxp; + int runelen; + Source *s = cursource; + int nmac = 0; + + tp = trp->lp; + ip = s->inp; + if (reset) { + s->lineinc = 0; + if (ip>=s->inl) { /* nothing in buffer */ + s->inl = s->inb; + fillbuf(s); + ip = s->inp = s->inb; + } else if (ip >= s->inb+(3*INS/4)) { + memmove(s->inb, ip, 4+s->inl-ip); + s->inl = s->inb+(s->inl-ip); + ip = s->inp = s->inb; + } + } + maxp = &trp->bp[trp->max]; + runelen = 1; + for (;;) { + continue2: + if (tp>=maxp) { + trp->lp = tp; + tp = growtokenrow(trp); + maxp = &trp->bp[trp->max]; + } + tp->type = UNCLASS; + tp->hideset = 0; + tp->t = ip; + tp->wslen = 0; + tp->flag = 0; + state = START; + for (;;) { + oldstate = state; + c = *ip; + if ((state = bigfsm[c][state]) >= 0) { + ip += runelen; + runelen = 1; + continue; + } + state = ~state; + reswitch: + switch (state&0177) { + case S_SELF: + ip += runelen; + runelen = 1; + case S_SELFB: + tp->type = GETACT(state); + tp->len = ip - tp->t; + tp++; + goto continue2; + + case S_NAME: /* like S_SELFB but with nmac check */ + tp->type = NAME; + tp->len = ip - tp->t; + nmac |= quicklook(tp->t[0], tp->len>1?tp->t[1]:0); + tp++; + goto continue2; + + case S_WS: + tp->wslen = ip - tp->t; + tp->t = ip; + state = START; + continue; + + default: + if ((state&QBSBIT)==0) { + ip += runelen; + runelen = 1; + continue; + } + state &= ~QBSBIT; + s->inp = ip; + if (c=='?') { /* check trigraph */ + if (trigraph(s)) { + state = oldstate; + continue; + } + goto reswitch; + } + if (c=='\\') { /* line-folding */ + if (foldline(s)) { + s->lineinc++; + state = oldstate; + continue; + } + goto reswitch; + } + error(WARNING, "Lexical botch in cpp"); + ip += runelen; + runelen = 1; + continue; + + case S_EOB: + s->inp = ip; + fillbuf(cursource); + state = oldstate; + continue; + + case S_EOF: + tp->type = END; + tp->len = 0; + s->inp = ip; + if (tp!=trp->bp && (tp-1)->type!=NL && cursource->fd!=NULL) + error(WARNING,"No newline at end of file"); + trp->lp = tp+1; + return nmac; + + case S_STNL: + error(ERROR, "Unterminated string or char const"); + case S_NL: + tp->t = ip; + tp->type = NL; + tp->len = 1; + tp->wslen = 0; + s->lineinc++; + s->inp = ip+1; + trp->lp = tp+1; + return nmac; + + case S_EOFSTR: + error(FATAL, "EOF in string or char constant"); + break; + + case S_COMNL: + s->lineinc++; + state = COM2; + ip += runelen; + runelen = 1; + if (ip >= s->inb+(7*INS/8)) { /* very long comment */ + memmove(tp->t, ip, 4+s->inl-ip); + s->inl -= ip-tp->t; + ip = tp->t+1; + } + continue; + + case S_EOFCOM: + error(WARNING, "EOF inside comment"); + --ip; + case S_COMMENT: + ++ip; + tp->t = ip; + tp->t[-1] = ' '; + tp->wslen = 1; + state = START; + continue; + } + break; + } + ip += runelen; + runelen = 1; + tp->len = ip - tp->t; + tp++; + } +} + +/* have seen ?; handle the trigraph it starts (if any) else 0 */ +int +trigraph(Source *s) +{ + int c; + + while (s->inp+2 >= s->inl && fillbuf(s)!=EOF) + ; + if (s->inp[1]!='?') + return 0; + c = 0; + switch(s->inp[2]) { + case '=': + c = '#'; break; + case '(': + c = '['; break; + case '/': + c = '\\'; break; + case ')': + c = ']'; break; + case '\'': + c = '^'; break; + case '<': + c = '{'; break; + case '!': + c = '|'; break; + case '>': + c = '}'; break; + case '-': + c = '~'; break; + } + if (c) { + *s->inp = c; + memmove(s->inp+1, s->inp+3, s->inl-s->inp+2); + s->inl -= 2; + } + return c; +} + +int +foldline(Source *s) +{ + while (s->inp+1 >= s->inl && fillbuf(s)!=EOF) + ; + if (s->inp[1] == '\n') { + memmove(s->inp, s->inp+2, s->inl-s->inp+3); + s->inl -= 2; + return 1; + } + return 0; +} + +int +fillbuf(Source *s) +{ + int n, nr; + + nr = INS/8; + if ((char *)s->inl+nr > (char *)s->inb+INS) + error(FATAL, "Input buffer overflow"); + if (s->fd==NULL || (n=fread((char *)s->inl, 1, INS/8, s->fd)) <= 0) + n = 0; + if ((*s->inp&0xff) == EOB) /* sentinel character appears in input */ + *s->inp = EOFC; + s->inl += n; + s->inl[0] = s->inl[1]= s->inl[2]= s->inl[3] = EOB; + if (n==0) { + s->inl[0] = s->inl[1]= s->inl[2]= s->inl[3] = EOFC; + return EOF; + } + return 0; +} + +/* + * Push down to new source of characters. + * If fd!=NULL and str==NULL, then from a file `name'; + * if fd==NULL and str, then from the string. + */ +Source * +setsource(char *name, FILE *fd, char *str) +{ + Source *s = new(Source); + int len; + + s->line = 1; + s->lineinc = 0; + s->fd = fd; + s->filename = name; + s->next = cursource; + s->ifdepth = 0; + cursource = s; + /* slop at right for EOB */ + if (str) { + len = strlen(str); + s->inb = domalloc(len+4); + s->inp = s->inb; + strncpy((char *)s->inp, str, len); + } else { + s->inb = domalloc(INS+4); + s->inp = s->inb; + len = 0; + } + s->inl = s->inp+len; + s->inl[0] = s->inl[1] = EOB; + return s; +} + +void +unsetsource(void) +{ + Source *s = cursource; + + if (s->fd != NULL) { + fclose(s->fd); + dofree(s->inb); + } + cursource = s->next; + dofree(s); +} diff --git a/src/cmd/lcpp/macro.c b/src/cmd/lcpp/macro.c new file mode 100644 index 0000000..c4a0920 --- /dev/null +++ b/src/cmd/lcpp/macro.c @@ -0,0 +1,516 @@ +#include +#include +#include "cpp.h" + +/* + * do a macro definition. tp points to the name being defined in the line + */ +void +dodefine(Tokenrow *trp) +{ + Token *tp; + Nlist *np; + Tokenrow *def, *args; + + tp = trp->tp+1; + if (tp>=trp->lp || tp->type!=NAME) { + error(ERROR, "#defined token is not a name"); + return; + } + np = lookup(tp, 1); + if (np->flag&ISUNCHANGE) { + error(ERROR, "#defined token %t can't be redefined", tp); + return; + } + /* collect arguments */ + tp += 1; + args = NULL; + if (tplp && tp->type==LP && tp->wslen==0) { + /* macro with args */ + int narg = 0; + tp += 1; + args = new(Tokenrow); + maketokenrow(2, args); + if (tp->type!=RP) { + int err = 0; + for (;;) { + Token *atp; + if (tp->type!=NAME) { + err++; + break; + } + if (narg>=args->max) + growtokenrow(args); + for (atp=args->bp; atplp; atp++) + if (atp->len==tp->len + && strncmp((char*)atp->t, (char*)tp->t, tp->len)==0) + error(ERROR, "Duplicate macro argument"); + *args->lp++ = *tp; + narg++; + tp += 1; + if (tp->type==RP) + break; + if (tp->type!=COMMA) { + err++; + break; + } + tp += 1; + } + if (err) { + error(ERROR, "Syntax error in macro parameters"); + return; + } + } + tp += 1; + } + trp->tp = tp; + if (((trp->lp)-1)->type==NL) + trp->lp -= 1; + def = normtokenrow(trp); + if (np->flag&ISDEFINED) { + if (comparetokens(def, np->vp) + || (np->ap==NULL) != (args==NULL) + || (np->ap && comparetokens(args, np->ap))) + error(ERROR, "Macro redefinition of %t", trp->bp+2); + } + if (args) { + Tokenrow *tap; + tap = normtokenrow(args); + dofree(args->bp); + args = tap; + } + np->ap = args; + np->vp = def; + np->flag |= ISDEFINED; +} + +/* + * Definition received via -D or -U + */ +void +doadefine(Tokenrow *trp, int type) +{ + Nlist *np; + static unsigned char one[] = "1"; + static Token onetoken[1] = {{ NUMBER, 0, 0, 0, 1, one }}; + static Tokenrow onetr = { onetoken, onetoken, onetoken+1, 1 }; + + trp->tp = trp->bp; + if (type=='U') { + if (trp->lp-trp->tp != 2 || trp->tp->type!=NAME) + goto syntax; + if ((np = lookup(trp->tp, 0)) == NULL) + return; + np->flag &= ~ISDEFINED; + return; + } + if (trp->tp >= trp->lp || trp->tp->type!=NAME) + goto syntax; + np = lookup(trp->tp, 1); + np->flag |= ISDEFINED; + trp->tp += 1; + if (trp->tp >= trp->lp || trp->tp->type==END) { + np->vp = &onetr; + return; + } + if (trp->tp->type!=ASGN) + goto syntax; + trp->tp += 1; + if ((trp->lp-1)->type == END) + trp->lp -= 1; + np->vp = normtokenrow(trp); + return; +syntax: + error(FATAL, "Illegal -D or -U argument %r", trp); +} + +/* + * Do macro expansion in a row of tokens. + * Flag is NULL if more input can be gathered. + */ +void +expandrow(Tokenrow *trp, char *flag) +{ + Token *tp; + Nlist *np; + + if (flag) + setsource(flag, NULL, ""); + for (tp = trp->tp; tplp; ) { + if (tp->type!=NAME + || quicklook(tp->t[0], tp->len>1?tp->t[1]:0)==0 + || (np = lookup(tp, 0))==NULL + || (np->flag&(ISDEFINED|ISMAC))==0 + || (tp->hideset && checkhideset(tp->hideset, np))) { + tp++; + continue; + } + trp->tp = tp; + if (np->val==KDEFINED) { + tp->type = DEFINED; + if ((tp+1)lp && (tp+1)->type==NAME) + (tp+1)->type = NAME1; + else if ((tp+3)lp && (tp+1)->type==LP + && (tp+2)->type==NAME && (tp+3)->type==RP) + (tp+2)->type = NAME1; + else + error(ERROR, "Incorrect syntax for `defined'"); + tp++; + continue; + } + if (np->flag&ISMAC) + builtin(trp, np->val); + else { + expand(trp, np); + } + tp = trp->tp; + } + if (flag) + unsetsource(); +} + +/* + * Expand the macro whose name is np, at token trp->tp, in the tokenrow. + * Return trp->tp at the first token next to be expanded + * (ordinarily the beginning of the expansion) + */ +void +expand(Tokenrow *trp, Nlist *np) +{ + Tokenrow ntr; + int ntokc, narg, i; + Token *tp; + Tokenrow *atr[NARG+1]; + int hs; + + copytokenrow(&ntr, np->vp); /* copy macro value */ + if (np->ap==NULL) /* parameterless */ + ntokc = 1; + else { + ntokc = gatherargs(trp, atr, &narg); + if (narg<0) { /* not actually a call (no '(') */ + /* gatherargs has already pushed trp->tr to the next token */ + return; + } + if (narg != rowlen(np->ap)) { + error(ERROR, "Disagreement in number of macro arguments"); + trp->tp->hideset = newhideset(trp->tp->hideset, np); + trp->tp += ntokc; + return; + } + substargs(np, &ntr, atr); /* put args into replacement */ + for (i=0; ibp); + dofree(atr[i]); + } + } + doconcat(&ntr); /* execute ## operators */ + hs = newhideset(trp->tp->hideset, np); + for (tp=ntr.bp; tptype==NAME) { + if (tp->hideset==0) + tp->hideset = hs; + else + tp->hideset = unionhideset(tp->hideset, hs); + } + } + ntr.tp = ntr.bp; + insertrow(trp, ntokc, &ntr); + trp->tp -= rowlen(&ntr); + dofree(ntr.bp); + return; +} + +/* + * Gather an arglist, starting in trp with tp pointing at the macro name. + * Return total number of tokens passed, stash number of args found. + * trp->tp is not changed relative to the tokenrow. + */ +int +gatherargs(Tokenrow *trp, Tokenrow **atr, int *narg) +{ + int parens = 1; + int ntok = 0; + Token *bp, *lp; + Tokenrow ttr; + int ntokp; + int needspace; + + *narg = -1; /* means that there is no macro call */ + /* look for the ( */ + for (;;) { + trp->tp++; + ntok++; + if (trp->tp >= trp->lp) { + gettokens(trp, 0); + if ((trp->lp-1)->type==END) { + trp->lp -= 1; + trp->tp -= ntok; + return ntok; + } + } + if (trp->tp->type==LP) + break; + if (trp->tp->type!=NL) + return ntok; + } + *narg = 0; + ntok++; + ntokp = ntok; + trp->tp++; + /* search for the terminating ), possibly extending the row */ + needspace = 0; + while (parens>0) { + if (trp->tp >= trp->lp) + gettokens(trp, 0); + if (needspace) { + needspace = 0; + makespace(trp); + } + if (trp->tp->type==END) { + trp->lp -= 1; + trp->tp -= ntok; + error(ERROR, "EOF in macro arglist"); + return ntok; + } + if (trp->tp->type==NL) { + trp->tp += 1; + adjustrow(trp, -1); + trp->tp -= 1; + makespace(trp); + needspace = 1; + continue; + } + if (trp->tp->type==LP) + parens++; + else if (trp->tp->type==RP) + parens--; + trp->tp++; + ntok++; + } + trp->tp -= ntok; + /* Now trp->tp won't move underneath us */ + lp = bp = trp->tp+ntokp; + for (; parens>=0; lp++) { + if (lp->type == LP) { + parens++; + continue; + } + if (lp->type==RP) + parens--; + if (lp->type==DSHARP) + lp->type = DSHARP1; /* ## not special in arg */ + if ((lp->type==COMMA && parens==0) || + (parens<0 && (lp-1)->type!=LP)) { + if (*narg>=NARG-1) + error(FATAL, "Sorry, too many macro arguments"); + ttr.bp = ttr.tp = bp; + ttr.lp = lp; + atr[(*narg)++] = normtokenrow(&ttr); + bp = lp+1; + } + } + return ntok; +} + +/* + * substitute the argument list into the replacement string + * This would be simple except for ## and # + */ +void +substargs(Nlist *np, Tokenrow *rtr, Tokenrow **atr) +{ + Tokenrow tatr; + Token *tp; + int ntok, argno; + + for (rtr->tp=rtr->bp; rtr->tplp; ) { + if (rtr->tp->type==SHARP) { /* string operator */ + tp = rtr->tp; + rtr->tp += 1; + if ((argno = lookuparg(np, rtr->tp))<0) { + error(ERROR, "# not followed by macro parameter"); + continue; + } + ntok = 1 + (rtr->tp - tp); + rtr->tp = tp; + insertrow(rtr, ntok, stringify(atr[argno])); + continue; + } + if (rtr->tp->type==NAME + && (argno = lookuparg(np, rtr->tp)) >= 0) { + if ((rtr->tp+1)->type==DSHARP || + (rtr->tp!=rtr->bp && (rtr->tp-1)->type==DSHARP)) + insertrow(rtr, 1, atr[argno]); + else { + copytokenrow(&tatr, atr[argno]); + expandrow(&tatr, ""); + insertrow(rtr, 1, &tatr); + dofree(tatr.bp); + } + continue; + } + rtr->tp++; + } +} + +/* + * Evaluate the ## operators in a tokenrow + */ +void +doconcat(Tokenrow *trp) +{ + Token *ltp, *ntp; + Tokenrow ntr; + int len; + + for (trp->tp=trp->bp; trp->tplp; trp->tp++) { + if (trp->tp->type==DSHARP1) + trp->tp->type = DSHARP; + else if (trp->tp->type==DSHARP) { + char tt[128]; + ltp = trp->tp-1; + ntp = trp->tp+1; + if (ltpbp || ntp>=trp->lp) { + error(ERROR, "## occurs at border of replacement"); + continue; + } + len = ltp->len + ntp->len; + strncpy((char*)tt, (char*)ltp->t, ltp->len); + strncpy((char*)tt+ltp->len, (char*)ntp->t, ntp->len); + tt[len] = '\0'; + setsource("<##>", NULL, tt); + maketokenrow(3, &ntr); + gettokens(&ntr, 1); + unsetsource(); + if (ntr.lp-ntr.bp!=2 || ntr.bp->type==UNCLASS) + error(WARNING, "Bad token %r produced by ##", &ntr); + ntr.lp = ntr.bp+1; + trp->tp = ltp; + makespace(&ntr); + insertrow(trp, (ntp-ltp)+1, &ntr); + dofree(ntr.bp); + trp->tp--; + } + } +} + +/* + * tp is a potential parameter name of macro mac; + * look it up in mac's arglist, and if found, return the + * corresponding index in the argname array. Return -1 if not found. + */ +int +lookuparg(Nlist *mac, Token *tp) +{ + Token *ap; + + if (tp->type!=NAME || mac->ap==NULL) + return -1; + for (ap=mac->ap->bp; apap->lp; ap++) { + if (ap->len==tp->len && strncmp((char*)ap->t,(char*)tp->t,ap->len)==0) + return ap - mac->ap->bp; + } + return -1; +} + +/* + * Return a quoted version of the tokenrow (from # arg) + */ +#define STRLEN 512 +Tokenrow * +stringify(Tokenrow *vp) +{ + static Token t = { STRING }; + static Tokenrow tr = { &t, &t, &t+1, 1 }; + Token *tp; + uchar s[STRLEN]; + uchar *sp = s, *cp; + int i, instring; + + *sp++ = '"'; + for (tp = vp->bp; tp < vp->lp; tp++) { + instring = tp->type==STRING || tp->type==CCON; + if (sp+2*tp->len >= &s[STRLEN-10]) { + error(ERROR, "Stringified macro arg is too long"); + break; + } + if (tp->wslen && (tp->flag&XPWS)==0) + *sp++ = ' '; + for (i=0, cp=tp->t; ilen; i++) { + if (instring && (*cp=='"' || *cp=='\\')) + *sp++ = '\\'; + *sp++ = *cp++; + } + } + *sp++ = '"'; + *sp = '\0'; + sp = s; + t.len = strlen((char*)sp); + t.t = newstring(sp, t.len, 0); + return &tr; +} + +/* + * expand a builtin name + */ +void +builtin(Tokenrow *trp, int biname) +{ + char *op; + Token *tp; + Source *s; + + tp = trp->tp; + trp->tp++; + /* need to find the real source */ + s = cursource; + while (s && s->fd==NULL) + s = s->next; + if (s==NULL) + s = cursource; + /* most are strings */ + tp->type = STRING; + if (tp->wslen) { + *outp++ = ' '; + tp->wslen = 1; + } + op = outp; + *op++ = '"'; + switch (biname) { + + case KLINENO: + tp->type = NUMBER; + op = outnum(op-1, s->line); + break; + + case KFILE: { + char *src = s->filename; + while ((*op++ = *src++) != 0) + if (src[-1] == '\\') + *op++ = '\\'; + op--; + break; + } + + case KDATE: + strncpy(op, curtime+4, 7); + strncpy(op+7, curtime+20, 4); + op += 11; + break; + + case KTIME: + strncpy(op, curtime+11, 8); + op += 8; + break; + + default: + error(ERROR, "cpp botch: unknown internal macro"); + return; + } + if (tp->type==STRING) + *op++ = '"'; + tp->t = (uchar*)outp; + tp->len = op - outp; + outp = op; +} diff --git a/src/cmd/lcpp/nlist.c b/src/cmd/lcpp/nlist.c new file mode 100644 index 0000000..b1776bb --- /dev/null +++ b/src/cmd/lcpp/nlist.c @@ -0,0 +1,103 @@ +#include +#include +#include "cpp.h" + +extern int getopt(int, char *const *, const char *); +extern char *optarg; +extern int optind; +extern int verbose; +extern int Cplusplus; +Nlist *kwdefined; + +#define NLSIZE 128 + +static Nlist *nlist[NLSIZE]; + +struct kwtab { + char *kw; + int val; + int flag; +} kwtab[] = { + { "if", KIF, ISKW }, + { "ifdef", KIFDEF, ISKW }, + { "ifndef", KIFNDEF, ISKW }, + { "elif", KELIF, ISKW }, + { "else", KELSE, ISKW }, + { "endif", KENDIF, ISKW }, + { "include", KINCLUDE, ISKW }, + { "define", KDEFINE, ISKW }, + { "undef", KUNDEF, ISKW }, + { "line", KLINE, ISKW }, + { "error", KERROR, ISKW }, + { "pragma", KPRAGMA, ISKW }, + { "eval", KEVAL, ISKW }, + { "defined", KDEFINED, ISDEFINED+ISUNCHANGE }, + { "ident", KPRAGMA, ISKW }, /* treat like pragma (ignored) */ + { "__LINE__", KLINENO, ISMAC+ISUNCHANGE }, + { "__FILE__", KFILE, ISMAC+ISUNCHANGE }, + { "__DATE__", KDATE, ISMAC+ISUNCHANGE }, + { "__TIME__", KTIME, ISMAC+ISUNCHANGE }, + { "__STDC__", KSTDC, ISUNCHANGE }, + { NULL }, +}; + +unsigned long namebit[077+1]; +Nlist *np; + +void +setup_kwtab(void) +{ + struct kwtab *kp; + Nlist *np; + Token t; + static Token deftoken[1] = {{ NAME, 0, 0, 0, 7, (uchar*)"defined" }}; + static Tokenrow deftr = { deftoken, deftoken, deftoken+1, 1 }; + + for (kp=kwtab; kp->kw; kp++) { + t.t = (uchar*)kp->kw; + t.len = strlen(kp->kw); + np = lookup(&t, 1); + np->flag = kp->flag; + np->val = kp->val; + if (np->val == KDEFINED) { + kwdefined = np; + np->val = NAME; + np->vp = &deftr; + np->ap = 0; + } + } +} + +Nlist * +lookup(Token *tp, int install) +{ + unsigned int h; + Nlist *np; + uchar *cp, *cpe; + + h = 0; + for (cp=tp->t, cpe=cp+tp->len; cpt==*np->name && tp->len==np->len + && strncmp((char*)tp->t, (char*)np->name, tp->len)==0) + return np; + np = np->next; + } + if (install) { + np = new(Nlist); + np->vp = NULL; + np->ap = NULL; + np->flag = 0; + np->val = 0; + np->len = tp->len; + np->name = newstring(tp->t, tp->len, 0); + np->next = nlist[h]; + nlist[h] = np; + quickset(tp->t[0], tp->len>1? tp->t[1]:0); + return np; + } + return NULL; +} diff --git a/src/cmd/lcpp/tokens.c b/src/cmd/lcpp/tokens.c new file mode 100644 index 0000000..05eb830 --- /dev/null +++ b/src/cmd/lcpp/tokens.c @@ -0,0 +1,372 @@ +#include +#include +#include "cpp.h" + +static char wbuf[2*OBS]; +static char *wbp = wbuf; + +/* + * 1 for tokens that don't need whitespace when they get inserted + * by macro expansion + */ +static const char wstab[] = { + 0, /* END */ + 0, /* UNCLASS */ + 0, /* NAME */ + 0, /* NUMBER */ + 0, /* STRING */ + 0, /* CCON */ + 1, /* NL */ + 0, /* WS */ + 0, /* DSHARP */ + 0, /* EQ */ + 0, /* NEQ */ + 0, /* LEQ */ + 0, /* GEQ */ + 0, /* LSH */ + 0, /* RSH */ + 0, /* LAND */ + 0, /* LOR */ + 0, /* PPLUS */ + 0, /* MMINUS */ + 0, /* ARROW */ + 1, /* SBRA */ + 1, /* SKET */ + 1, /* LP */ + 1, /* RP */ + 0, /* DOT */ + 0, /* AND */ + 0, /* STAR */ + 0, /* PLUS */ + 0, /* MINUS */ + 0, /* TILDE */ + 0, /* NOT */ + 0, /* SLASH */ + 0, /* PCT */ + 0, /* LT */ + 0, /* GT */ + 0, /* CIRC */ + 0, /* OR */ + 0, /* QUEST */ + 0, /* COLON */ + 0, /* ASGN */ + 1, /* COMMA */ + 0, /* SHARP */ + 1, /* SEMIC */ + 1, /* CBRA */ + 1, /* CKET */ + 0, /* ASPLUS */ + 0, /* ASMINUS */ + 0, /* ASSTAR */ + 0, /* ASSLASH */ + 0, /* ASPCT */ + 0, /* ASCIRC */ + 0, /* ASLSH */ + 0, /* ASRSH */ + 0, /* ASOR */ + 0, /* ASAND */ + 0, /* ELLIPS */ + 0, /* DSHARP1 */ + 0, /* NAME1 */ + 0, /* DEFINED */ + 0, /* UMINUS */ +}; + +void +maketokenrow(int size, Tokenrow *trp) +{ + trp->max = size; + if (size>0) + trp->bp = (Token *)domalloc(size*sizeof(Token)); + else + trp->bp = NULL; + trp->tp = trp->bp; + trp->lp = trp->bp; +} + +Token * +growtokenrow(Tokenrow *trp) +{ + int ncur = trp->tp - trp->bp; + int nlast = trp->lp - trp->bp; + + trp->max = 3*trp->max/2 + 1; + trp->bp = (Token *)realloc(trp->bp, trp->max*sizeof(Token)); + if (trp->bp == NULL) + error(FATAL, "Out of memory from realloc"); + trp->lp = &trp->bp[nlast]; + trp->tp = &trp->bp[ncur]; + return trp->lp; +} + +/* + * Compare a row of tokens, ignoring the content of WS; return !=0 if different + */ +int +comparetokens(Tokenrow *tr1, Tokenrow *tr2) +{ + Token *tp1, *tp2; + + tp1 = tr1->tp; + tp2 = tr2->tp; + if (tr1->lp-tp1 != tr2->lp-tp2) + return 1; + for (; tp1lp ; tp1++, tp2++) { + if (tp1->type != tp2->type + || (tp1->wslen==0) != (tp2->wslen==0) + || tp1->len != tp2->len + || strncmp((char*)tp1->t, (char*)tp2->t, tp1->len)!=0) + return 1; + } + return 0; +} + +/* + * replace ntok tokens starting at dtr->tp with the contents of str. + * tp ends up pointing just beyond the replacement. + * Canonical whitespace is assured on each side. + */ +void +insertrow(Tokenrow *dtr, int ntok, Tokenrow *str) +{ + int nrtok = rowlen(str); + + dtr->tp += ntok; + adjustrow(dtr, nrtok-ntok); + dtr->tp -= ntok; + movetokenrow(dtr, str); + makespace(dtr); + dtr->tp += nrtok; + makespace(dtr); +} + +/* + * make sure there is WS before trp->tp, if tokens might merge in the output + */ +void +makespace(Tokenrow *trp) +{ + uchar *tt; + Token *tp = trp->tp; + + if (tp >= trp->lp) + return; + if (tp->wslen) { + if (tp->flag&XPWS + && (wstab[tp->type] || + (trp->tp>trp->bp && wstab[(tp-1)->type]))) { + tp->wslen = 0; + return; + } + tp->t[-1] = ' '; + return; + } + if (wstab[tp->type] || + (trp->tp>trp->bp && wstab[(tp-1)->type])) + return; + tt = newstring(tp->t, tp->len, 1); + *tt++ = ' '; + tp->t = tt; + tp->wslen = 1; + tp->flag |= XPWS; +} + +/* + * Copy an entire tokenrow into another, at tp. + * It is assumed that there is enough space. + * Not strictly conforming. + */ +void +movetokenrow(Tokenrow *dtr, Tokenrow *str) +{ + int nby; + + /* nby = sizeof(Token) * (str->lp - str->bp); */ + nby = (char *)str->lp - (char *)str->bp; + memmove(dtr->tp, str->bp, nby); +} + +/* + * Move the tokens in a row, starting at tr->tp, rightward by nt tokens; + * nt may be negative (left move). + * The row may need to be grown. + * Non-strictly conforming because of the (char *), but easily fixed + */ +void +adjustrow(Tokenrow *trp, int nt) +{ + int nby, size; + + if (nt==0) + return; + size = (trp->lp - trp->bp) + nt; + while (size > trp->max) + growtokenrow(trp); + /* nby = sizeof(Token) * (trp->lp - trp->tp); */ + nby = (char *)trp->lp - (char *)trp->tp; + if (nby) + memmove(trp->tp+nt, trp->tp, nby); + trp->lp += nt; +} + +/* + * Copy a row of tokens into the destination holder, allocating + * the space for the contents. Return the destination. + */ +Tokenrow * +copytokenrow(Tokenrow *dtr, Tokenrow *str) +{ + int len = rowlen(str); + + maketokenrow(len, dtr); + movetokenrow(dtr, str); + dtr->lp += len; + return dtr; +} + +/* + * Produce a copy of a row of tokens. Start at trp->tp. + * The value strings are copied as well. The first token + * has WS available. + */ +Tokenrow * +normtokenrow(Tokenrow *trp) +{ + Token *tp; + Tokenrow *ntrp = new(Tokenrow); + int len; + + len = trp->lp - trp->tp; + if (len<=0) + len = 1; + maketokenrow(len, ntrp); + for (tp=trp->tp; tp < trp->lp; tp++) { + *ntrp->lp = *tp; + if (tp->len) { + ntrp->lp->t = newstring(tp->t, tp->len, 1); + *ntrp->lp->t++ = ' '; + if (tp->wslen) + ntrp->lp->wslen = 1; + } + ntrp->lp++; + } + if (ntrp->lp > ntrp->bp) + ntrp->bp->wslen = 0; + return ntrp; +} + +/* + * Debugging + */ +void +peektokens(Tokenrow *trp, char *str) +{ + Token *tp; + + tp = trp->tp; + flushout(); + if (str) + fprintf(stderr, "%s ", str); + if (tpbp || tp>trp->lp) + fprintf(stderr, "(tp offset %d) ", (int) (tp - trp->bp)); + for (tp=trp->bp; tplp && tpbp+32; tp++) { + if (tp->type!=NL) { + int c = tp->t[tp->len]; + tp->t[tp->len] = 0; + fprintf(stderr, "%s", tp->t); + tp->t[tp->len] = c; + } + if (tp->type==NAME) { + fprintf(stderr, tp==trp->tp?"{*":"{"); + prhideset(tp->hideset); + fprintf(stderr, "} "); + } else + fprintf(stderr, tp==trp->tp?"{%x*} ":"{%x} ", tp->type); + } + fprintf(stderr, "\n"); + fflush(stderr); +} + +void +puttokens(Tokenrow *trp) +{ + Token *tp; + int len; + uchar *p; + + if (verbose) + peektokens(trp, ""); + tp = trp->bp; + for (; tplp; tp++) { + len = tp->len+tp->wslen; + p = tp->t-tp->wslen; + while (tplp-1 && p+len == (tp+1)->t - (tp+1)->wslen) { + tp++; + len += tp->wslen+tp->len; + } + if (len>OBS/2) { /* handle giant token */ + if (wbp > wbuf) + fwrite(wbuf, 1, wbp-wbuf, stdout); + fwrite((char *)p, 1, len, stdout); + wbp = wbuf; + } else { + memcpy(wbp, p, len); + wbp += len; + } + if (wbp >= &wbuf[OBS]) { + fwrite(wbuf, 1, OBS, stdout); + if (wbp > &wbuf[OBS]) + memcpy(wbuf, wbuf+OBS, wbp - &wbuf[OBS]); + wbp -= OBS; + } + } + trp->tp = tp; + if (cursource->fd==stdin) + flushout(); +} + +void +flushout(void) +{ + if (wbp>wbuf) { + fwrite(wbuf, 1, wbp-wbuf, stdout); + fflush(stdout); + wbp = wbuf; + } +} + +/* + * turn a row into just a newline + */ +void +setempty(Tokenrow *trp) +{ + trp->tp = trp->bp; + trp->lp = trp->bp+1; + *trp->bp = nltoken; +} + +/* + * generate a number + */ +char * +outnum(char *p, int n) +{ + if (n>=10) + p = outnum(p, n/10); + *p++ = n%10 + '0'; + return p; +} + +/* + * allocate and initialize a new string from s, of length l, at offset o + * Null terminated. + */ +uchar * +newstring(uchar *s, int l, int o) +{ + uchar *ns = (uchar *)domalloc(l+o+1); + + ns[l+o] = '\0'; + return (uchar*)strncpy((char*)ns+o, (char*)s, l) - o; +} diff --git a/src/cmd/lcpp/unix.c b/src/cmd/lcpp/unix.c new file mode 100644 index 0000000..3df3a66 --- /dev/null +++ b/src/cmd/lcpp/unix.c @@ -0,0 +1,114 @@ +#include +#include +#include "cpp.h" + +extern int getopt(int, char *const *, const char *); +extern char *optarg, rcsid[]; +extern int optind; +int verbose; +int Mflag; /* only print active include files */ +char *objname; /* "src.$O: " */ +int Cplusplus = 1; + +void +setup(int argc, char **argv) +{ + int c, i; + FILE *fd; + char *fp, *dp; + Tokenrow tr; + extern void setup_kwtab(void); + + setup_kwtab(); + while ((c = getopt(argc, argv, "MNOVv+I:D:U:F:lg")) != -1) + switch (c) { + case 'N': + for (i=0; i=0; i--) { + if (includelist[i].file==NULL) { + includelist[i].always = 1; + includelist[i].file = optarg; + break; + } + } + if (i<0) + error(FATAL, "Too many -I directives"); + break; + case 'D': + case 'U': + setsource("", NULL, optarg); + maketokenrow(3, &tr); + gettokens(&tr, 1); + doadefine(&tr, c); + unsetsource(); + break; + case 'M': + Mflag++; + break; + case 'v': + fprintf(stderr, "%s %s\n", argv[0], rcsid); + break; + case 'V': + verbose++; + break; + case '+': + Cplusplus++; + break; + default: + break; + } + dp = "."; + fp = ""; + fd = stdin; + if (optind ld.dis + ${SIZE} ld.elf + ${ELF2AOUT} ld.elf $@ && rm ld.elf + +$(MAN): $(MANSRC) + ${MANROFF} $< > $@ + +clean: + rm -f *.o *.0 *.elf ${MAN} ld *.elf *.dis a.out tags *~ + +install: all + install ld ${DESTDIR}/bin/ld + cp ${MAN} ${DESTDIR}/share/man/cat1/ diff --git a/src/cmd/ld/ld.1 b/src/cmd/ld/ld.1 new file mode 100644 index 0000000..9535b38 --- /dev/null +++ b/src/cmd/ld/ld.1 @@ -0,0 +1,334 @@ +.\" Copyright (c) 1980 Regents of the University of California. +.\" All rights reserved. The Berkeley software License Agreement +.\" specifies the terms and conditions for redistribution. +.\" +.\" @(#)ld.1 6.4 (2.11BSD GTE) 1995/05/08 +.\" +.TH LD 1 "May 08, 1995" +.UC 2 +.SH NAME +ld \- link editor (2BSD) +.SH SYNOPSIS +.B ld +[ option ] ... file ... +.SH DESCRIPTION +.I Ld +combines several +object programs into one, resolves external +references, and searches libraries. +In the simplest case several object +.I files +are given, and +.I ld +combines them, producing +an object module which can be either executed or +become the input for a further +.I ld +run. +(In the latter case, the +.B \-r +option must be given +to preserve the relocation bits.)\ +The output of +.I ld +is left on +.BR a.out . +This file is made executable +only if no errors occurred during the load. +.PP +The argument routines are concatenated in the order +specified. The entry point of the output is the +beginning of the first routine (unless the \fB\-e\fP option is specified). +.PP +If any argument is a library, it is searched exactly once +at the point it is encountered in the argument list. +Only those routines defining an unresolved external +reference are loaded. +If a routine from a library +references another routine in the library, +and the library has not been processed by +.IR ranlib (1), +the referenced routine must appear after the +referencing routine in the library. +Thus the order of programs within libraries +may be important. +The first member of a library +should be a file named `\_\^\_.SYMDEF', +which is understood to be a dictionary for the library as produced by +.IR ranlib (1); +the dictionary is searched iteratively to satisfy as many references as +possible. +.PP +The symbols `\_etext', `\_edata' and `\_end' +(`etext', `edata' and `end' in C) +are reserved, and if referred to, +are set to the first location above the program, +the first location above initialized data, +and the first location above all data respectively. +It is erroneous to define these symbols. +.PP +.I Ld +understands several options. +Except for +.BR \-l , +they should appear before the file names. +.TP +.B \-D +Take the next argument as a decimal number and pad the data segment +with zero bytes to the indicated length. +.TP +.B \-d +Force definition of common storage +even if the +.B \-r +flag is present. +.TP +.B \-e +The following argument is taken to be the +name of the entry point of the loaded +program; location 0 is the default. +.TP +.BI \-L dir +Add +.I dir +to the list of directories in which libraries are searched for. +Directories specified with +.B \-L +are searched before the standard directories. +.TP +.BI \-l x +This +option is an abbreviation for the library name +.RI `lib x .a', +where +.I x +is a string. +.I Ld +searches for libraries first in any directories +specified with +.B \-L +options, then in the standard directories `/lib', `/usr/lib', and +`/usr/local/lib'. +A library is searched when its name is encountered, +so the placement of a +.B \-l +is significant. +.TP +.B \-M +produce a primitive load map, listing the names of the files +which will be loaded. +.TP +.B \-n +Arrange (by giving the output file a 0410 "magic number") that +when the output file is executed, +the text portion will be read-only and shared +among all users executing the file. +This involves moving the data areas up to the first +possible 8K byte boundary following the +end of the text. +This option creates a `pure executable' +format. +.TP +.B \-i +When the output file is executed, the program +text and data areas will live in separate address spaces. +The only difference between this option +and +.B \-n +is that here the text and data segments are in separate address spaces +and both start at location 0. +This option creates +a `separate executable' format. +.TP +.B \-z +This option is a synonym for the +.B \-i +option. On other systems (4.3BSD for example) the +.B \-z +option causes a demand paged executable to be built. This option +was added to 2.11BSD because some systems (those which use gcc) +do not safely ignore (with a warning) the +.B \-i +option. Adding the +.B \-z +option to 2.11BSD allows makefiles to be copied freely between multiple +platforms once again. +.TP +.B \-O +This is a text replacement overlay file; only the text segment +will be replaced by +.IR execve (2). +Shared data must have the same size as +the program overlaid, otherwise the +.IR execve (2) +will fail. +The entry point to the overlay may be defined with the +.B \-e +option. +This option allows the creation of a `replacement executable' +format. +.TP +.B \-o +The +.I name +argument after +.B \-o +is used as the name of the +.I ld +output file, instead of +.BR a.out . +.TP +.B \-r +Generate relocation bits in the output file +so that it can be the subject of another +.I ld +run. +This flag also prevents final definitions from being +given to common symbols, +and suppresses the `undefined symbol' diagnostics. +(Note that this option cannot be used with overlays (\fB-Z\fP) +since they cannot be reloaded.) +.TP +.B \-s +`Strip' the output, that is, remove the symbol table +and relocation bits to save space (but impair the +usefulness of the debuggers). +This information can also be removed by +.IR strip (1). +.TP +.B \-q +("quiet") Suppress the reporting of undefined symbols. Normally only +used when building networked kernels \- the large number of undefined +symbols is normal (due to the three phase link proceedure) but can be +distracting none the less. +.TP +.B \-t +("trace") Print the name of each file as it is processed. +.TP +.B \-u +Take the following argument as a symbol and enter +it as undefined in the symbol table. This is useful +for loading wholly from a library, since initially the symbol +table is empty and an unresolved reference is needed +to force the loading of the first routine. +.TP +.B \-v +("verbose") Print the VM statistics. Printing out the number of +pages swapped to and from the VM tmp file is now optional and only +used when a problem is suspected (or if you are voyeuristic). +.TP +.B \-X +Save local symbols +except for those whose names begin with `L'. +This option is used by +.IR cc (1) +to discard internally-generated labels while +retaining symbols local to routines. +.TP +.B \-x +Do not preserve local +(non-.globl) symbols in the output symbol table; only enter +external symbols. +This option saves some space in the output file. +It also allows +temporary labels to be discarded to prevent redefinition in +sucessive \fBld\fP's. +Warning: \fIadb\fP uses these local symbols, +especially when debugging overlaid programs, +so some debugging information is necessarily lost if this option is used. +.TP +.B \-Z +Indicate the creation of an automatic-overlay format. In addition a +.B \-i +or +.B \-n +must be present as overlays only work with shared text objects. Repeated +instances of +.B -Z +bracket the modules that will be loaded into a given overlay. Modules before +the first +.B \-Z +or after the concluding +.B \-Y +will be loaded into the non-overlaid text (base) area. Note that there may be +a maximum of NOVL (currently 15) overlays. This option produces the `overlaid +pure executable' and the `overlaid separate executable' formats. The loader +creates a small entry interface in the base segment for each subroutine in an +overlay. This interface ("thunk") arranges for the correct overlay to be +present before the actual routine is entered. +.TP +.B \-Y +Terminate text overlays. This allows any remaining modules or libraries to be +loaded into the base area. Note that the +.B \-Y +option used to be +.IR \-L , +but had to be changed when the loader was brought up to date with the +.I 4.3BSD +loader which uses +.I -L +to indicate a directory to be searched for library references. +.SH "AUTOMATIC TEXT OVERLAY EXAMPLE" +To set up an automatic text overlay object with the loader, use a command of +the form: +.IP +.nf +\fBld \-n \-X\fP /lib/crt0.o base.o base2.o +\fB\-Z\fP ov1a.o ov1b.o ... +\fB\-Z\fP ov2a.o ov2b.o ... +... +\fB\-Y\fP base3.o ... \-lovc +.fi +.PP +Assembly source code must be compiled using the assembler overlay flags: +\*(lq\fIas \-V\fP prog.s\*(rq which causes the assembler to leave certain +symbols unresolved so that +.I ld +may rearrange them. The various system compilers automatically use this +option. +.PP +When arranging modules into overlays, the following rules control the maximum +sizes for an executable file. The magic numbers are due to the granularity of +PDP-11 segmentation registers (there are 8 registers, each controlling an +8192-byte segment). The program is made up of four areas: base text, overlay +text, data + bss, and stack sections. The size of the overlay section is +controlled by the size of the largest of the overlays. Each section starts at +an address that is a multiple of 8Kb, thus the size of each section is rounded +up to a multiple of 8Kb. +.PP +In the case of separate overlaid executable files, the text and overlays share +one 64Kb byte address space; and the data + bss and stack share the other. +Thus, the total of the base text size (rounded up to an 8Kb boundary) plus the +maximum overlay size (similarly rounded) must be less than or equal to 64Kb. +Or, put another way, since there are only 8 segmentation registers available, +the number of segmentation registers needed for an overlaid object must be +less than or equal to 8. As an example, if the base text segment has 36800 +bytes and the largest overlay takes 14144, the base will fit in 5 segments and +the overlays in 2 segments; leaving one to spare. The data and bss together +must fit in 7 segments (56K bytes), leaving one 8Kb segment for the stack. All +of the limits can be checked by using +.IR checkobj (1). +.PP +For pure overlaid programs, the rules are similar except that all four +sections share one 64K-byte address space. The number of segments required by +the text, overlay, data + bss and stack are calculated in the same way. The +sum of the segments required, including one for the stack, must be less than +or equal to 8. Example: a program has 8128 bytes of base text, the largest +overlay is 16248 bytes, and the data and bss total 19500. The text requires 1 +8Kb segment, the overlays 2, and data and bss use 4, leaving one for the stack. +.SH FILES +.ta \w'/usr/local/lib/lib*.a\ \ 'u +/lib/lib*.a libraries +.br +/usr/lib/lib*.a more libraries +.br +/usr/local/lib/lib*.a still more libraries +.br +a.out output file +.SH "SEE ALSO" +adb(1), ar(1), as(1), cc(1), checkobj(1), f77(1), file(1), ranlib(1), +size(1), a.out(5) +.SH BUGS +The text overlay scheme presented is unique to the PDP-11 and 2BSD. The +\-i, \-P, \-Z, \-Y options are specific to 2BSD. The \-q and \-v options +are new with 2.11BSD. diff --git a/src/cmd/ld/ld.c b/src/cmd/ld/ld.c new file mode 100644 index 0000000..972624d --- /dev/null +++ b/src/cmd/ld/ld.c @@ -0,0 +1,1572 @@ +/* + * Linker for RetroBSD, MIPS32 architecture. + * + * Copyright (C) 2011 Serge Vakulenko, + * + * 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 the copyright notice and this + * permission notice and warranty disclaimer appear in supporting + * documentation, and that the name of the author not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * + * The author disclaim all warranties with regard to this + * software, including all implied warranties of merchantability + * and fitness. In no event shall the author 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. + */ +#ifdef CROSS +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# define MAXNAMLEN 63 +#else +# include +# include +# include +# include +# include +# include +# include +# include +#endif +#include +#include +#include +#include + +#define W 4 /* word size in bytes */ +#define BADDR 0x7f008000 /* start address in memory */ +#define SYMDEF "__.SYMDEF" +#define IS_LOCSYM(s) ((s)->n_name[0] == 'L' || \ + (s)->n_name[0] == '.') +#define hexdig(c) ((c)<='9' ? (c) - '0' : ((c)&7) + 9) + +struct exec filhdr; /* aout header */ + +#define HDRSZ sizeof(struct exec) + +struct archdr { /* archive header */ + char * ar_name; + long ar_date; + int ar_uid; + int ar_gid; + int ar_mode; + long ar_size; +} archdr; + +FILE *text, *reloc; /* input management */ + + /* output management */ +FILE *outb, *toutb, *doutb, *troutb, *droutb, *soutb; + + /* symbol management */ +struct local { + unsigned locindex; /* index to symbol in file */ + struct nlist *locsymbol; /* ptr to symbol table */ +}; + +#define NSYM 1500 +#define NSYMPR 500 +#define NLIBS 256 +#define RANTABSZ 500 + +struct nlist cursym; /* current symbol */ +struct nlist symtab [NSYM]; /* table of symbols */ +struct nlist **symhash [NSYM]; /* pointers to hash table */ +struct nlist *lastsym; /* last entered symbol */ +struct nlist *hshtab [NSYM+2]; /* hash table for symbols */ +struct local local [NSYMPR]; +int symindex; /* next free entry of symbol table */ +unsigned basaddr = BADDR; /* base address of loading */ +struct ranlib rantab [RANTABSZ]; +int rancount; /* number of elements in rantab */ + +/* + * library management + */ +unsigned liblist [NLIBS], *libp; + +/* + * internal symbols + */ +struct nlist *p_etext, *p_edata, *p_end, *p_gp, *entrypt; + +/* + * options + */ +int trace; /* internal trace flag */ +int xflag; /* discard local symbols */ +int Xflag; /* discard locals starting with 'L' or '.' */ +int Sflag; /* discard all except locals and globals*/ +int rflag; /* preserve relocation bits, don't define commons */ +int output_relinfo; +int sflag; /* discard all symbols */ +int dflag; /* define common even with rflag */ +int verbose; /* verbose mode */ + +/* + * cumulative sizes set in pass 1 + */ +unsigned tsize, dsize, bsize, ssize, nsym; + +/* + * symbol relocation; both passes + */ +unsigned ctrel, cdrel, cbrel; + +/* + * used after pass 1 + */ +unsigned torigin, dorigin, borigin; + +/* gp control, MIPS specific */ +unsigned gpoffset = 0x8000; /* offset from data start */ +unsigned gp; /* allocated address */ + +int ofilfnd; +char *ofilename = "l.out"; +char *filname; +int errlev; +int delarg = 4; +char tfname [] = "/tmp/ldaXXXXXX"; + +#define ALIGN(x,y) ((x)+(y)-1-((x)+(y)-1)%(y)) + +unsigned int fgetword (f) + register FILE *f; +{ + register unsigned int h; + + h = getc (f); + h |= getc (f) << 8; + h |= getc (f) << 16; + h |= getc (f) << 24; + return h; +} + +void fputword (h, f) + register unsigned int h; + register FILE *f; +{ + putc (h, f); + putc (h >> 8, f); + putc (h >> 16, f); + putc (h >> 24, f); +} + +int fgethdr (text, h) + register FILE *text; + register struct exec *h; +{ + h->a_magic = fgetword (text); + h->a_text = fgetword (text); + h->a_data = fgetword (text); + h->a_bss = fgetword (text); + h->a_reltext = fgetword (text); + h->a_reldata = fgetword (text); + h->a_syms = fgetword (text); + h->a_entry = fgetword (text); + return (1); +} + +void fputhdr (hdr, coutb) + register struct exec *hdr; + register FILE *coutb; +{ + fputword (hdr->a_magic, coutb); + fputword (hdr->a_text, coutb); + fputword (hdr->a_data, coutb); + fputword (hdr->a_bss, coutb); + fputword (hdr->a_reltext, coutb); + fputword (hdr->a_reldata, coutb); + fputword (hdr->a_syms, coutb); + fputword (hdr->a_entry, coutb); +} + +/* + * Read a relocation record: 1 to 6 bytes. + */ +void fgetrel (f, r) + register FILE *f; + register struct reloc *r; +{ + r->flags = getc (f); + if ((r->flags & RSMASK) == REXT) { + r->index = getc (f); + r->index |= getc (f) << 8; + r->index |= getc (f) << 16; + } + if ((r->flags & RFMASK) == RHIGH16 || + (r->flags & RFMASK) == RHIGH16S) { + r->offset = getc (f); + r->offset |= getc (f) << 8; + } +} + +/* + * Emit a relocation record: 1 to 6 bytes. + * Return a written length. + */ +unsigned fputrel (r, f) + register struct reloc *r; + register FILE *f; +{ + register unsigned nbytes = 1; + + putc (r->flags, f); + if ((r->flags & RSMASK) == REXT) { + putc (r->index, f); + putc (r->index >> 8, f); + putc (r->index >> 16, f); + nbytes += 3; + } + if ((r->flags & RFMASK) == RHIGH16 || + (r->flags & RFMASK) == RHIGH16S) { + putc (r->offset, f); + putc (r->offset >> 8, f); + nbytes += 2; + } + return nbytes; +} + +void delexit (int sig) +{ + unlink ("l.out"); + if (! delarg && ! rflag) + chmod (ofilename, 0777 & ~umask(0)); + exit (delarg); +} + +void error (int n, const char *s, ...) +{ + va_list ap; + + va_start (ap, s); + if (! errlev) + printf ("ld: "); + if (filname) + printf ("%s: ", filname); + vprintf (s, ap); + va_end (ap); + printf ("\n"); + if (n > 1) + delexit (0); + errlev = n; +} + +int fgetsym (text, sym) + register FILE *text; + register struct nlist *sym; +{ + register int c; + + c = getc (text); + if (c <= 0) + return 0; + sym->n_len = c; + sym->n_name = malloc (sym->n_len + 1); + if (! sym->n_name) + error (2, "out of memory"); + sym->n_type = getc (text); + sym->n_value = fgetword (text); + for (c=0; cn_len; c++) + sym->n_name [c] = getc (text); + sym->n_name [sym->n_len] = '\0'; + return sym->n_len + 6; +} + +void fputsym (s, file) + register struct nlist *s; + register FILE *file; +{ + register int i; + + putc (s->n_len, file); + putc (s->n_type, file); + fputword (s->n_value, file); + for (i=0; in_len; i++) + putc (s->n_name[i], file); +} + +/* + * Read the file header of the archive. + */ +int fgetarhdr (fd, h) + register FILE *fd; + register struct archdr *h; +{ + struct ar_hdr hdr; + register int len, nr; + register char *p; + char buf[20]; + + /* Read arhive name. Spaces should never happen. */ + nr = fread (buf, 1, sizeof (hdr.ar_name), fd); + if (nr != sizeof (hdr.ar_name) || buf[0] == ' ') + return 0; + buf[nr] = 0; + + /* Long name support. Set the "real" size of the file, + * and the long name flag/size. */ + h->ar_size = 0; + if (strncmp (buf, AR_EFMT1, sizeof(AR_EFMT1) - 1) == 0) { + len = atoi (buf + sizeof(AR_EFMT1) - 1); + if (len <= 0 || len > MAXNAMLEN) + return 0; + h->ar_name = malloc (len + 1); + if (! h->ar_name) + return 0; + nr = fread (h->ar_name, 1, len, fd); + if (nr != len) { +failed: free (h->ar_name); + return 0; + } + h->ar_name[len] = 0; + h->ar_size -= len; + } else { + /* Strip trailing spaces, null terminate. */ + p = buf + nr - 1; + while (*p == ' ') + --p; + *++p = '\0'; + + len = p - buf; + h->ar_name = malloc (len + 1); + if (! h->ar_name) + return 0; + strcpy (h->ar_name, buf); + } + + /* Read arhive date. */ + nr = fread (buf, 1, sizeof (hdr.ar_date), fd); + if (nr != sizeof (hdr.ar_date)) + goto failed; + buf[nr] = 0; + h->ar_date = strtol (buf, 0, 10); + + /* Read user id. */ + nr = fread (buf, 1, sizeof (hdr.ar_uid), fd); + if (nr != sizeof (hdr.ar_uid)) + goto failed; + buf[nr] = 0; + h->ar_uid = strtol (buf, 0, 10); + + /* Read group id. */ + nr = fread (buf, 1, sizeof (hdr.ar_gid), fd); + if (nr != sizeof (hdr.ar_gid)) + goto failed; + buf[nr] = 0; + h->ar_gid = strtol (buf, 0, 10); + + /* Read mode (octal). */ + nr = fread (buf, 1, sizeof (hdr.ar_mode), fd); + if (nr != sizeof (hdr.ar_mode)) + goto failed; + buf[nr] = 0; + h->ar_mode = strtol (buf, 0, 8); + + /* Read archive size. */ + nr = fread (buf, 1, sizeof (hdr.ar_size), fd); + if (nr != sizeof (hdr.ar_size)) + goto failed; + buf[nr] = 0; + h->ar_size = strtol (buf, 0, 10); + + /* Check secondary magic. */ + nr = fread (buf, 1, sizeof (hdr.ar_fmag), fd); + if (nr != sizeof (hdr.ar_fmag)) + goto failed; + buf[nr] = 0; + if (strcmp (buf, ARFMAG) != 0) + goto failed; + + return 1; +} + +void freerantab () +{ + register struct ranlib *p; + + for (p=rantab; pran_name); +} + +int fgetran (text, sym) + register FILE *text; + register struct ranlib *sym; +{ + register int c; + + /* read struct ranlib from file */ + /* 1 byte - length of name */ + /* 4 bytes - seek in archive */ + /* 'len' bytes - symbol name */ + /* if len == 0 then eof */ + /* return 1 if ok, 0 on eof */ + + sym->ran_len = getc (text); + if (sym->ran_len <= 0) + return (0); + sym->ran_name = malloc (sym->ran_len + 1); + if (! sym->ran_name) + error (2, "out of memory"); + sym->ran_off = fgetword (text); + for (c=0; cran_len; c++) + sym->ran_name [c] = getc (text); + sym->ran_name [sym->ran_len] = '\0'; + return (1); +} + +void getrantab () +{ + register struct ranlib *p; + + for (p=rantab; pn_type != N_EXT+N_UNDF) { + printf ("%s: ", sp->n_name); + error (1, "name redefined"); + return; + } + sp->n_type = type; + sp->n_value = val; +} + +void tcreat (buf, tempflg) + register FILE **buf; + register int tempflg; +{ + *buf = fopen (tempflg ? tfname : ofilename, "w+"); + if (! *buf) + error (2, tempflg ? + "cannot create temporary file" : + "cannot create output file"); + if (tempflg) + unlink (tfname); +} + +int reltype (stype) + int stype; +{ + switch (stype & N_TYPE) { + case N_UNDF: return (0); + case N_ABS: return (RABS); + case N_TEXT: return (RTEXT); + case N_DATA: return (RDATA); + case N_BSS: return (RBSS); + case N_STRNG: return (RDATA); + case N_COMM: return (RBSS); + case N_FN: return (0); + default: return (0); + } +} + +struct nlist *lookloc (lp, sn) + register struct local *lp; + register int sn; +{ + register struct local *clp; + + for (clp=local; clplocindex == sn) + return (clp->locsymbol); + if (trace) { + fprintf (stderr, "*** %d ***\n", sn); + for (clp=local; clplocindex); + fprintf (stderr, "\n"); + } + error (2, "bad symbol reference"); + return 0; +} + +void printrel (word, rel) + register unsigned word; + register struct reloc *rel; +{ + printf ("%08x %02x ", word, rel->flags); + + if ((rel->flags & RSMASK) == REXT) + printf ("%-3d ", rel->index); + else + printf (" "); + + if ((rel->flags & RFMASK) == RHIGH16 || + (rel->flags & RFMASK) == RHIGH16S) + printf ("%08x", rel->offset); + else + printf (" "); +} + +/* + * Relocate the word by a given offset. + * Return the new value of word and update rel. + */ +unsigned relword (lp, word, rel, offset) + struct local *lp; + register unsigned word; + register struct reloc *rel; + unsigned offset; +{ + register unsigned addr, delta; + register struct nlist *sp = 0; + + if (trace > 2) + printrel (word, rel); + /* + * Extract an address field from the instruction. + */ + switch (rel->flags & RFMASK) { + case RBYTE16: + addr = word & 0xffff; + break; + case RBYTE32: + addr = word; + break; + case RWORD16: + addr = (word & 0xffff) << 2; + break; + case RWORD26: + addr = (word & 0x3ffffff) << 2; + break; + case RHIGH16: + addr = (word & 0xffff) << 16; + addr += rel->offset; + break; + case RHIGH16S: + addr = (word & 0xffff) << 16; + addr += (signed short) rel->offset; + break; + default: + addr = 0; + break; + } + + /* + * Compute a delta for address. + * Update the relocation info, if needed. + */ + switch (rel->flags & RSMASK) { + case RTEXT: + delta = ctrel; + break; + case RDATA: + delta = cdrel; + break; + case RBSS: + delta = cbrel; + break; + case REXT: + sp = lookloc (lp, rel->index); + if (sp->n_type == N_EXT+N_UNDF || + sp->n_type == N_EXT+N_COMM) { + rel->index = nsym + (sp - symtab); + sp = 0; + delta = 0; + } else { + rel->flags &= RFMASK | RGPREL; + rel->flags |= reltype (sp->n_type); + delta = sp->n_value; + } + break; + default: + delta = 0; + break; + } + + if ((rel->flags & RGPREL) && ! output_relinfo) { + /* + * GP relative address. + */ + delta -= gp; + rel->flags &= ~RGPREL; + } + + /* + * Update the address field of the instruction. + * Update the relocation info, if needed. + */ + switch (rel->flags & RFMASK) { + case RBYTE16: + addr += delta; + word &= ~0xffff; + word |= addr & 0xffff; + break; + case RBYTE32: + word = addr + delta; + break; + case RWORD16: + if (! sp) + break; + addr += delta - offset - 4; + word &= ~0xffff; + word |= (addr >> 2) & 0xffff; + rel->flags = RABS; + break; + case RWORD26: + addr += delta; + word &= ~0x3ffffff; + word |= (addr >> 2) & 0x3ffffff; + break; + case RHIGH16: + addr += delta; + word &= ~0xffff; + word |= (addr >> 16) & 0xffff; + break; + case RHIGH16S: + addr += delta; + word &= ~0xffff; + word |= ((addr + 0x8000) >> 16) & 0xffff; + break; + } + if (trace > 2) { + //printf (" +%#x ", delta); + printf (" -> "); + printrel (word, rel); + printf ("\n"); + } + return word; +} + +void relocate (lp, b1, b2, len, origin) + struct local *lp; + FILE *b1, *b2; + unsigned len, origin; +{ + unsigned word, offset; + struct reloc rel; + + for (offset=0; offset archdr.ar_date + 2) + return (3); /* out of date archive */ + return (2); /* randomized archive */ +} + +int enter (hp) + register struct nlist **hp; +{ + register struct nlist *sp; + + if (*hp) { + lastsym = *hp; + return (0); + } + if (symindex >= NSYM) + error (2, "symbol table overflow"); + + symhash [symindex] = hp; + *hp = lastsym = sp = &symtab[symindex++]; + sp->n_len = cursym.n_len; + sp->n_name = cursym.n_name; + sp->n_type = cursym.n_type; + sp->n_value = cursym.n_value; + return (1); +} + +void symreloc() +{ + switch (cursym.n_type) { + case N_TEXT: + case N_EXT+N_TEXT: + cursym.n_value += ctrel; + return; + case N_DATA: + case N_EXT+N_DATA: + cursym.n_value += cdrel; + return; + case N_BSS: + case N_EXT+N_BSS: + cursym.n_value += cbrel; + return; + case N_EXT+N_UNDF: + case N_EXT+N_COMM: + return; + } + if (cursym.n_type & N_EXT) + cursym.n_type = N_EXT+N_ABS; +} + +/* + * Suboptimal 32-bit hash function. + * Copyright (C) 2006 Serge Vakulenko. + */ +unsigned hash_rot13 (s) + register const char *s; +{ + register unsigned hash, c; + + hash = 0; + while ((c = (unsigned char) *s++) != 0) { + hash += c; + hash -= (hash << 13) | (hash >> 19); + } + return hash; +} + +struct nlist **lookup() +{ + int clash; + register char *cp, *cp1; + register struct nlist **hp; + + hp = &hshtab[hash_rot13 (cursym.n_name) % NSYM + 2]; + while (*hp != 0) { + cp1 = (*hp)->n_name; + clash = 0; + for (cp = cursym.n_name; *cp;) { + if (*cp++ != *cp1++) { + clash = 1; + break; + } + } + if (! clash) + break; + if (++hp >= &hshtab[NSYM+2]) + hp = hshtab; + } + return (hp); +} + +struct nlist **slookup (s) + char *s; +{ + cursym.n_len = strlen (s) + 1; + cursym.n_name = s; + cursym.n_type = N_EXT+N_UNDF; + cursym.n_value = 0; + return (lookup ()); +} + +void readhdr (loc) + unsigned loc; +{ + fseek (text, loc, 0); + if (! fgethdr (text, &filhdr)) + error (2, "bad format"); + if (filhdr.a_magic != RMAGIC) + error (2, "bad magic"); + if (filhdr.a_text % W) + error (2, "bad length of text"); + if (filhdr.a_data % W) + error (2, "bad length of data"); + if (filhdr.a_bss % W) + error (2, "bad length of bss"); +} + +/* + * single file + */ +int load1 (loc, libflg, nloc) + unsigned loc; +{ + register struct nlist *sp; + int savindex, ndef, type, symlen, nsymbol; + + readhdr (loc); + if (filhdr.a_magic != RMAGIC) { + error (1, "file not relocatable"); + return (0); + } + fseek (reloc, loc + N_SYMOFF (filhdr), 0); + + ctrel = tsize; + cdrel = dsize - filhdr.a_text; + cbrel = bsize - (filhdr.a_text + filhdr.a_data); + + loc += HDRSZ + filhdr.a_text + filhdr.a_data + + filhdr.a_reltext + filhdr.a_reldata; + fseek (text, loc, 0); + ndef = 0; + savindex = symindex; + if (nloc) + nsymbol = 1; + else + nsymbol = 0; + for (;;) { + symlen = fgetsym (text, &cursym); + if (symlen == 0) + break; + type = cursym.n_type; + if (Sflag && ((type & N_TYPE) == N_ABS || + (type & N_TYPE) > N_COMM)) + { + free (cursym.n_name); + continue; + } + if (! (type & N_EXT)) { + if (! (sflag || xflag || + (Xflag && IS_LOCSYM(&cursym)))) + { + nsymbol++; + nloc += symlen; + } + free (cursym.n_name); + continue; + } + symreloc (); + if (enter (lookup ())) + continue; + free (cursym.n_name); + if (cursym.n_type == N_EXT+N_UNDF) + continue; + sp = lastsym; + if (sp->n_type == N_EXT+N_UNDF || + sp->n_type == N_EXT+N_COMM) + { + if (cursym.n_type == N_EXT+N_COMM) { + sp->n_type = cursym.n_type; + if (cursym.n_value > sp->n_value) + sp->n_value = cursym.n_value; + } + else if (sp->n_type==N_EXT+N_UNDF || + cursym.n_type==N_EXT+N_DATA || + cursym.n_type==N_EXT+N_BSS) + { + ndef++; + sp->n_type = cursym.n_type; + sp->n_value = cursym.n_value; + } + } + } + if (! libflg || ndef) { + tsize += filhdr.a_text; + dsize += filhdr.a_data; + bsize += filhdr.a_bss; + ssize += nloc; + nsym += nsymbol; + + /* Alignment. */ + tsize = (tsize + 3) & ~3; + dsize = (dsize + 3) & ~3; + bsize = (bsize + 3) & ~3; + return (1); + } + + /* + * No symbols defined by this library member. + * Rip out the hash table entries and reset the symbol table. + */ + while (symindex > savindex) { + register struct nlist **p; + + p = symhash[--symindex]; + free ((*p)->n_name); + *p = 0; + } + return (0); +} + +void addlibp (nloc) + register unsigned nloc; +{ + *libp++ = nloc; + if (libp >= &liblist[NLIBS]) + error (2, "library table overflow"); +} + +int step (nloc) + register unsigned nloc; +{ + fseek (text, nloc, 0); + if (! fgetarhdr (text, &archdr)) { + return (0); + } + if (load1 (nloc + ARHDRSZ, 1, mkfsym (archdr.ar_name, 0))) { + addlibp (nloc); + if (trace) + printf ("load '%s' offset %08x\n", archdr.ar_name, nloc); + } + free (archdr.ar_name); + return (1); +} + +int ldrand () +{ + register struct ranlib *p; + struct nlist **pp; + unsigned *oldp = libp; + + for (p=rantab; pran_name); + if (! *pp) + continue; + if ((*pp)->n_type == N_EXT+N_UNDF) + step (p->ran_off); + } + return (oldp != libp); +} + +/* + * scan a library to find defined symbols + */ +void load1lib (off0) + unsigned off0; +{ + register unsigned offset; + register unsigned *oldp; + + /* repeat while any symbols found */ + do { + oldp = libp; + offset = off0; + while (step (offset)) + offset += archdr.ar_size + ARHDRSZ; + } while (libp != oldp); + addlibp (-1); +} + +/* + * scan file to find defined symbols + */ +void load1arg (cp) + register char *cp; +{ + switch (getfile (cp)) { + case 0: /* regular file */ + load1 (0L, 0, mkfsym (cp, 0)); + break; + case 1: /* regular archive */ + load1lib (SARMAG); + break; + case 2: /* archive with table of contents */ + getrantab (); + while (ldrand ()) + continue; + freerantab (); + addlibp (-1); + break; + case 3: /* out of date table of contents */ + error (0, "out of date (warning)"); + load1lib (SARMAG + archdr.ar_size + ARHDRSZ); + break; + } + fclose (text); + fclose (reloc); +} + +void pass1 (argc, argv) + char **argv; +{ + register int c, i; + register char *ap, **p; + char save; + + /* scan files once to find symdefs */ + + p = argv + 1; + libp = liblist; + for (c=1; c= argc) + error (2, "-o: argument missing"); + ofilename = *p++; + ofilfnd++; + continue; + + /* 'use' */ + case 'u': + if (++c >= argc) + error (2, "-u: argument missing"); + enter (slookup (*p++)); + continue; + + /* 'entry' */ + case 'e': + if (++c >= argc) + error (2, "-e: argument missing"); + enter (slookup (*p++)); + entrypt = lastsym; + continue; + + /* base address of loading */ + case 'T': + basaddr = atol (ap+i+1); + break; + + /* library */ + case 'l': + save = ap [--i]; + ap [i] = '-'; + load1arg (&ap[i]); + ap [i] = save; + break; + + /* discard local symbols */ + case 'x': + xflag++; + continue; + + /* discard locals starting with 'L' or '.' */ + case 'X': + Xflag++; + continue; + + /* discard all except locals and globals*/ + case 'S': + Sflag++; + continue; + + /* preserve rel. bits, don't define common */ + case 'r': + rflag++; + output_relinfo++; + continue; + + /* discard all symbols */ + case 's': + sflag++; + xflag++; + continue; + + /* define common even with rflag */ + case 'd': + dflag++; + continue; + + /* tracing */ + case 't': + trace++; + continue; + + /* verbose */ + case 'v': + verbose++; + continue; + + default: + error (2, "unknown flag"); + } + break; + } + } +} + +void middle() +{ + register struct nlist *sp, *symp; + register unsigned t, cmsize; + int nund; + unsigned cmorigin; + + p_etext = *slookup ("_etext"); + p_edata = *slookup ("_edata"); + p_end = *slookup ("_end"); + p_gp = *slookup ("_gp"); + + /* + * If there are any undefined symbols, save the relocation bits. + */ + symp = &symtab[symindex]; + if (! output_relinfo) { + for (sp=symtab; spn_type == N_EXT+N_UNDF && + sp != p_end && sp != p_edata && + sp != p_etext && sp != p_gp) + { + output_relinfo++; + dflag = 0; + break; + } + } + if (output_relinfo) + sflag = 0; + + /* + * Assign common locations. + * Align text size to 16 bytes. + */ + cmsize = 0; + tsize = (tsize + 15) & ~15; + if (dflag || ! output_relinfo) { + ldrsym (p_etext, tsize, N_EXT+N_TEXT); + ldrsym (p_edata, dsize, N_EXT+N_DATA); + ldrsym (p_end, bsize, N_EXT+N_BSS); + + /* Set GP as offset from the start of data segment. */ + ldrsym (p_gp, gpoffset, N_EXT+N_DATA); + + for (sp=symtab; spn_type & N_TYPE) == N_COMM) { + t = sp->n_value; + sp->n_value = cmsize; + cmsize += t; + cmsize = (cmsize + 3) & ~3; + } + } + } + + /* + * Now set symbols to their final value. + */ + torigin = basaddr; + dorigin = torigin + tsize; + gp = dorigin + gpoffset; + cmorigin = dorigin + dsize; + borigin = cmorigin + cmsize; + nund = 0; + for (sp=symtab; spn_type) { + case N_EXT+N_UNDF: + if (! rflag) { + errlev |= 1; + if (sp == p_end || sp == p_edata || + sp == p_etext || sp == p_gp) + break; + if (! nund) + printf ("Undefined:\n"); + nund++; + printf ("\t%s\n", sp->n_name); + } + break; + default: + case N_EXT+N_ABS: + break; + case N_EXT+N_TEXT: + sp->n_value += torigin; + break; + case N_EXT+N_DATA: + sp->n_value += dorigin; + break; + case N_EXT+N_BSS: + sp->n_value += borigin; + break; + case N_COMM: + case N_EXT+N_COMM: + sp->n_type = N_EXT+N_BSS; + sp->n_value += cmorigin; + break; + } + } + if (sflag || xflag) + ssize = 0; + bsize += cmsize; + + /* + * Compute ssize; add length of local symbols, if need, + * and one more zero byte. Alignment will be taken at setupout. + */ + if (sflag) + ssize = 0; + else { + if (xflag) + ssize = 0; + for (sp = symtab; sp < &symtab[symindex]; sp++) + ssize += sp->n_len + 6; + ssize++; + } +} + +void setupout () +{ + tcreat (&outb, 0); + mktemp (tfname); + tcreat (&toutb, 1); + tcreat (&doutb, 1); + + if (! sflag || ! xflag) + tcreat (&soutb, 1); + if (output_relinfo) { + tcreat (&troutb, 1); + tcreat (&droutb, 1); + } + fseek (outb, sizeof(filhdr), 0); +} + +void load2 (loc) + unsigned loc; +{ + register struct nlist *sp; + register struct local *lp; + register int symno; + int type; + unsigned count; + + readhdr (loc); + ctrel = torigin; + cdrel = dorigin - filhdr.a_text; + cbrel = borigin - (filhdr.a_text + filhdr.a_data); + + if (trace > 1) + printf ("ctrel=%08x, cdrel=%08x, cbrel=%08x\n", + ctrel, cdrel, cbrel); + /* + * Reread the symbol table, recording the numbering + * of symbols for fixing external references. + */ + lp = local; + symno = -1; + loc += HDRSZ; + fseek (text, loc + filhdr.a_text + filhdr.a_data + + filhdr.a_reltext + filhdr.a_reldata, 0); + for (;;) { + symno++; + count = fgetsym (text, &cursym); + if (count == 0) + break; + symreloc (); + type = cursym.n_type; + if (Sflag && ((type & N_TYPE) == N_ABS || + (type & N_TYPE) > N_COMM)) + { + free (cursym.n_name); + continue; + } + if (! (type & N_EXT)) { + if (! (sflag || xflag || + (Xflag && IS_LOCSYM(&cursym)))) + fputsym (&cursym, soutb); + free (cursym.n_name); + continue; + } + if (! (sp = *lookup())) + error (2, "internal error: symbol not found"); + free (cursym.n_name); + if (cursym.n_type == N_EXT+N_UNDF || + cursym.n_type == N_EXT+N_COMM) + { + if (lp >= &local [NSYMPR]) + error (2, "local symbol table overflow"); + lp->locindex = symno; + lp++->locsymbol = sp; + continue; + } + if (cursym.n_type != sp->n_type || + cursym.n_value != sp->n_value) + { + printf ("%s: ", cursym.n_name); + error (1, "name redefined"); + } + } + + count = loc + filhdr.a_text + filhdr.a_data; + + if (trace > 1) + printf ("-- text --\n"); + fseek (text, loc, 0); + fseek (reloc, count, 0); + relocate (lp, toutb, troutb, filhdr.a_text, torigin); + + if (trace > 1) + printf ("-- data --\n"); + fseek (text, loc + filhdr.a_text, 0); + fseek (reloc, count + filhdr.a_reltext, 0); + relocate (lp, doutb, droutb, filhdr.a_data, dorigin); + + torigin += filhdr.a_text; + dorigin += filhdr.a_data; + borigin += filhdr.a_bss; + + /* Alignment. */ + torigin = (torigin + 3) & ~3; + dorigin = (dorigin + 3) & ~3; + borigin = (borigin + 3) & ~3; +} + +void load2arg (arname) + register char *arname; +{ + register unsigned *lp; + + if (getfile (arname) == 0) { + if (trace || verbose) + printf ("%s:\n", arname); + mkfsym (arname, 1); + load2 (0L); + } else { + /* scan archive members referenced */ + for (lp = libp; *lp != -1; lp++) { + fseek (text, *lp, 0); + fgetarhdr (text, &archdr); + if (trace || verbose) + printf ("%s(%s):\n", arname, archdr.ar_name); + mkfsym (archdr.ar_name, 1); + free (archdr.ar_name); + load2 (*lp + ARHDRSZ); + } + libp = ++lp; + } + fclose (text); + fclose (reloc); +} + +void pass2 (argc, argv) + int argc; + char **argv; +{ + register int c, i; + register char *ap, **p; + + p = argv + 1; + libp = liblist; + for (c=1; cn_type != N_EXT+N_TEXT && + entrypt->n_type != N_EXT+N_UNDF) + error (1, "entry out of text"); + else filhdr.a_entry = entrypt->n_value; + } else + filhdr.a_entry = basaddr; + + fseek (outb, 0, 0); + fputhdr (&filhdr, outb); + fclose (outb); +} + +int main (argc, argv) + char **argv; +{ + if (argc == 1) { + printf ("Usage:\n"); + printf (" ld [-sSxXrdt] [-o file] [-lname] [-u name] [-e name] [-T num] file...\n"); + printf ("Options:\n"); + printf (" -o filename Set output file name, default a.out\n"); + printf (" -llibname Search for library libname\n"); + printf (" -u symbol Start with undefined reference to symbol\n"); + printf (" -e symbol Set start address\n"); + printf (" -T address Set address of .text segment, default %#x\n", basaddr); + printf (" -s Discard all symbols\n"); + printf (" -S Discard all symbols except locals and globals\n"); + printf (" -x Discard local symbols\n"); + printf (" -X Discard locals starting with 'L' or '.'\n"); + printf (" -r Generate relocatable output\n"); + printf (" -d Force common symbols to be defined\n"); + printf (" -t Increase trace verbosity (up to 3)\n"); + exit (4); + } + if (signal (SIGINT, SIG_IGN) != SIG_IGN) + signal (SIGINT, delexit); + if (signal (SIGTERM, SIG_IGN) != SIG_IGN) + signal (SIGTERM, delexit); + + /* + * First pass: compute lengths of segments, symbol name table + * and entry address. + */ + pass1 (argc, argv); + filname = 0; + + /* + * Compute name table. + */ + middle (); + + /* + * Create temporary files. + */ + setupout (); + + /* + * Second pass: relocation. + */ + pass2 (argc, argv); + + /* + * Flush buffers, write a header. + */ + finishout (); + + if (! ofilfnd) { + unlink ("a.out"); + link ("l.out", "a.out"); + ofilename = "a.out"; + } + delarg = errlev; + delexit (0); + return (0); +} diff --git a/src/cmd/lex/Makefile b/src/cmd/lex/Makefile new file mode 100644 index 0000000..7f018a3 --- /dev/null +++ b/src/cmd/lex/Makefile @@ -0,0 +1,31 @@ +CFLAGS = -O +SEPFLAG= -i + +all: lex + +lex: lmain.o y.tab.o sub1.o sub2.o header.o + cc ${SEPFLAG} lmain.o y.tab.o sub1.o sub2.o header.o -o lex + +smallex: + cc ${SEPFLAG} lmain.o y.tab.o sub1.o sub2.o header.o -o lex + +y.tab.c: parser.y + yacc parser.y +lmain.o:lmain.c ldefs.c once.c + cc -c -O lmain.c +sub1.o: sub1.c ldefs.c + cc -c -O sub1.c +sub2.o: sub2.c ldefs.c + cc -c -O sub2.c +header.o: header.c ldefs.c + cc -c -O header.c + +install: all + -mkdir -p ${DESTDIR}/share/lex + chmod 755 ${DESTDIR}/share/lex + install -s -m 755 lex $(DESTDIR)/bin + install -c -m 444 ncform $(DESTDIR)/share/lex + install -c -m 444 nrform $(DESTDIR)/share/lex + +clean: + rm -f *.o lex y.tab.c diff --git a/src/cmd/lex/header.c b/src/cmd/lex/header.c new file mode 100644 index 0000000..1106320 --- /dev/null +++ b/src/cmd/lex/header.c @@ -0,0 +1,112 @@ +#ifndef lint +static char sccsid[] = "@(#)header.c 4.1 (Berkeley) 8/11/83"; +#endif +# include "ldefs.c" +phead1(){ + ratfor ? rhd1() : chd1(); + } + +chd1(){ + fprintf(fout,"# include \"stdio.h\"\n"); + if (ZCH>NCH) + fprintf(fout, "# define U(x) ((x)&0377)\n"); + else + fprintf(fout, "# define U(x) x\n"); + fprintf(fout, "# define NLSTATE yyprevious=YYNEWLINE\n"); + fprintf(fout,"# define BEGIN yybgin = yysvec + 1 +\n"); + fprintf(fout,"# define INITIAL 0\n"); + fprintf(fout,"# define YYLERR yysvec\n"); + fprintf(fout,"# define YYSTATE (yyestate-yysvec-1)\n"); + if(optim) + fprintf(fout,"# define YYOPTIM 1\n"); +# ifdef DEBUG + fprintf(fout,"# define LEXDEBUG 1\n"); +# endif + fprintf(fout,"# define YYLMAX 200\n"); + fprintf(fout,"# define output(c) putc(c,yyout)\n"); + fprintf(fout, "%s%d%s\n", + "# define input() (((yytchar=yysptr>yysbuf?U(*--yysptr):getc(yyin))==", + ctable['\n'], + "?(yylineno++,yytchar):yytchar)==EOF?0:yytchar)"); + fprintf(fout, +"# define unput(c) {yytchar= (c);if(yytchar=='\\n')yylineno--;*yysptr++=yytchar;}\n"); + fprintf(fout,"# define yymore() (yymorfg=1)\n"); + fprintf(fout,"# define ECHO fprintf(yyout, \"%%s\",yytext)\n"); + fprintf(fout,"# define REJECT { nstr = yyreject(); goto yyfussy;}\n"); + fprintf(fout,"int yyleng; extern char yytext[];\n"); + fprintf(fout,"int yymorfg;\n"); + fprintf(fout,"extern char *yysptr, yysbuf[];\n"); + fprintf(fout,"int yytchar;\n"); + fprintf(fout,"FILE *yyin ={stdin}, *yyout ={stdout};\n"); + fprintf(fout,"extern int yylineno;\n"); + fprintf(fout,"struct yysvf { \n"); + fprintf(fout,"\tstruct yywork *yystoff;\n"); + fprintf(fout,"\tstruct yysvf *yyother;\n"); + fprintf(fout,"\tint *yystops;};\n"); + fprintf(fout,"struct yysvf *yyestate;\n"); + fprintf(fout,"extern struct yysvf yysvec[], *yybgin;\n"); + } + +rhd1(){ + fprintf(fout,"integer function yylex(dummy)\n"); + fprintf(fout,"define YYLMAX 200\n"); + fprintf(fout,"define ECHO call yyecho(yytext,yyleng)\n"); + fprintf(fout,"define REJECT nstr = yyrjct(yytext,yyleng);goto 30998\n"); + fprintf(fout,"integer nstr,yylook,yywrap\n"); + fprintf(fout,"integer yyleng, yytext(YYLMAX)\n"); + fprintf(fout,"common /yyxel/ yyleng, yytext\n"); + fprintf(fout,"common /yyldat/ yyfnd, yymorf, yyprev, yybgin, yylsp, yylsta\n"); + fprintf(fout,"integer yyfnd, yymorf, yyprev, yybgin, yylsp, yylsta(YYLMAX)\n"); + fprintf(fout,"for(;;){\n"); + fprintf(fout,"\t30999 nstr = yylook(dummy)\n"); + fprintf(fout,"\tgoto 30998\n"); + fprintf(fout,"\t30000 k = yywrap(dummy)\n"); + fprintf(fout,"\tif(k .ne. 0){\n"); + fprintf(fout,"\tyylex=0; return; }\n"); + fprintf(fout,"\t\telse goto 30998\n"); + } + +phead2(){ + if(!ratfor)chd2(); + } + +chd2(){ + fprintf(fout,"while((nstr = yylook()) >= 0)\n"); + fprintf(fout,"yyfussy: switch(nstr){\n"); + fprintf(fout,"case 0:\n"); + fprintf(fout,"if(yywrap()) return(0); break;\n"); + } + +ptail(){ + if(!pflag) + ratfor ? rtail() : ctail(); + pflag = 1; + } + +ctail(){ + fprintf(fout,"case -1:\nbreak;\n"); /* for reject */ + fprintf(fout,"default:\n"); + fprintf(fout,"fprintf(yyout,\"bad switch yylook %%d\",nstr);\n"); + fprintf(fout,"} return(0); }\n"); + fprintf(fout,"/* end of yylex */\n"); + } + +rtail(){ + register int i; + fprintf(fout,"\n30998 if(nstr .lt. 0 .or. nstr .gt. %d)goto 30999\n",casecount); + fprintf(fout,"nstr = nstr + 1\n"); + fprintf(fout,"goto(\n"); + for(i=0; i +# include + +# define PP 1 +# ifdef unix + +# define CWIDTH 7 +# define CMASK 0177 +# define ASCII 1 +# endif + +# ifdef gcos +# define CWIDTH 9 +# define CMASK 0777 +# define ASCII 1 +# endif + +# ifdef ibm +# define CWIDTH 8 +# define CMASK 0377 +# define EBCDIC 1 +# endif + +# ifdef ASCII +# define NCH 128 +# endif + +# ifdef EBCDIC +# define NCH 256 +# endif + + +# define TOKENSIZE 1000 +# define DEFSIZE 40 +# define DEFCHAR 1000 +# define STARTCHAR 100 +# define STARTSIZE 256 +# define CCLSIZE 1000 +# ifdef SMALL +# define TREESIZE 600 +# define NTRANS 1500 +# define NSTATES 300 +# define MAXPOS 1500 +# define NOUTPUT 1500 +# endif + +# ifndef SMALL +# define TREESIZE 1000 +# define NSTATES 500 +# define MAXPOS 2500 +# define NTRANS 2000 +# define NOUTPUT 3000 +# endif +# define NACTIONS 100 +# define ALITTLEEXTRA 30 + +# define RCCL NCH+90 +# define RNCCL NCH+91 +# define RSTR NCH+92 +# define RSCON NCH+93 +# define RNEWE NCH+94 +# define FINAL NCH+95 +# define RNULLS NCH+96 +# define RCAT NCH+97 +# define STAR NCH+98 +# define PLUS NCH+99 +# define QUEST NCH+100 +# define DIV NCH+101 +# define BAR NCH+102 +# define CARAT NCH+103 +# define S1FINAL NCH+104 +# define S2FINAL NCH+105 + +# define DEFSECTION 1 +# define RULESECTION 2 +# define ENDSECTION 5 +# define TRUE 1 +# define FALSE 0 + +# define PC 1 +# define PS 1 + +# ifdef DEBUG +# define LINESIZE 110 +extern int yydebug; +extern int debug; /* 1 = on */ +extern int charc; +# endif + +# ifndef DEBUG +# define freturn(s) s +# endif + +extern int sargc; +extern char **sargv; +extern char buf[520]; +extern int ratfor; /* 1 = ratfor, 0 = C */ +extern int yyline; /* line number of file */ +extern int sect; +extern int eof; +extern int lgatflg; +extern int divflg; +extern int funcflag; +extern int pflag; +extern int casecount; +extern int chset; /* 1 = char set modified */ +extern FILE *fin, *fout, *fother, *errorf; +extern int fptr; +extern char *ratname, *cname; +extern int prev; /* previous input character */ +extern int pres; /* present input character */ +extern int peek; /* next input character */ +extern int *name; +extern int *left; +extern int *right; +extern int *parent; +extern char *nullstr; +extern int tptr; +extern char pushc[TOKENSIZE]; +extern char *pushptr; +extern char slist[STARTSIZE]; +extern char *slptr; +extern char **def, **subs, *dchar; +extern char **sname, *schar; +extern char *ccl; +extern char *ccptr; +extern char *dp, *sp; +extern int dptr, sptr; +extern char *bptr; /* store input position */ +extern char *tmpstat; +extern int count; +extern int **foll; +extern int *nxtpos; +extern int *positions; +extern int *gotof; +extern int *nexts; +extern char *nchar; +extern int **state; +extern int *sfall; /* fallback state num */ +extern char *cpackflg; /* true if state has been character packed */ +extern int *atable, aptr; +extern int nptr; +extern char symbol[NCH]; +extern char cindex[NCH]; +extern int xstate; +extern int stnum; +extern int ctable[]; +extern int ZCH; +extern int ccount; +extern char match[NCH]; +extern char extra[NACTIONS]; +extern char *pcptr, *pchar; +extern int pchlen; +extern int nstates, maxpos; +extern int yytop; +extern int report; +extern int ntrans, treesize, outsize; +extern long rcount; +extern int optim; +extern int *verify, *advance, *stoff; +extern int scon; +extern char *psave; +extern char *calloc(), *myalloc(); +extern int buserr(), segviol(); diff --git a/src/cmd/lex/lmain.c b/src/cmd/lex/lmain.c new file mode 100644 index 0000000..0fef63a --- /dev/null +++ b/src/cmd/lex/lmain.c @@ -0,0 +1,230 @@ +/* + * lex [-[drcyvntf]] [file] ... [file] + * + * Copyright 1976, Bell Telephone Laboratories, Inc., + * written by Eric Schmidt, August 27, 1976 + */ +#include "ldefs.c" +#include "once.c" + +main(argc,argv) + int argc; + char **argv; +{ + register int i; +# ifdef DEBUG +#include + signal(SIGBUS,buserr); + signal(SIGSEGV,segviol); +# endif + while (argc > 1 && argv[1][0] == '-' ){ + i = 0; + while(argv[1][++i]){ + switch (argv[1][i]){ +# ifdef DEBUG + case 'd': debug++; break; + case 'y': yydebug = TRUE; break; +# endif + case 'r': case 'R': + ratfor=TRUE; break; + case 'c': case 'C': + ratfor=FALSE; break; + case 't': case 'T': + fout = stdout; + errorf = stderr; + break; + case 'v': case 'V': + report = 1; + break; + case 'f': case 'F': + optim = FALSE; + break; + case 'n': case 'N': + report = 0; + break; + default: + warning("Unknown option %c",argv[1][i]); + } + } + argc--; + argv++; + } + sargc = argc; + sargv = argv; + if (argc > 1){ + fin = fopen(argv[++fptr], "r"); /* open argv[1] */ + sargc--; + } + else fin = stdin; + if(fin == NULL) + error ("Can't read input file %s",argc>1?argv[1]:"standard input"); + gch(); + /* may be gotten: def, subs, sname, schar, ccl, dchar */ + get1core(); + /* may be gotten: name, left, right, nullstr, parent */ + scopy("INITIAL",sp); + sname[0] = sp; + sp += slength("INITIAL") + 1; + sname[1] = 0; + if(yyparse(0)) exit(1); /* error return code */ + /* may be disposed of: def, subs, dchar */ + free1core(); + /* may be gotten: tmpstat, foll, positions, gotof, nexts, nchar, state, atable, sfall, cpackflg */ + get2core(); + ptail(); + mkmatch(); +# ifdef DEBUG + if(debug) pccl(); +# endif + sect = ENDSECTION; + if(tptr>0)cfoll(tptr-1); +# ifdef DEBUG + if(debug)pfoll(); +# endif + cgoto(); +# ifdef DEBUG + if(debug){ + printf("Print %d states:\n",stnum+1); + for(i=0;i<=stnum;i++)stprt(i); + } +# endif + /* may be disposed of: positions, tmpstat, foll, state, name, left, right, parent, ccl, schar, sname */ + /* may be gotten: verify, advance, stoff */ + free2core(); + get3core(); + layout(); + /* may be disposed of: verify, advance, stoff, nexts, nchar, + gotof, atable, ccpackflg, sfall */ +# ifdef DEBUG + free3core(); +# endif + if (ZCH > NCH) + cname = _PATH_SHARE "lex/ebcform"; + fother = fopen(ratfor?ratname:cname,"r"); + if(fother == NULL) + error("Lex driver missing, file %s",ratfor?ratname:cname); + while ( (i=getc(fother)) != EOF) + putc(i,fout); + + fclose(fother); + fclose(fout); + if( +# ifdef DEBUG + debug || +# endif + report == 1)statistics(); + fclose(stdout); + fclose(stderr); + exit(0); /* success return code */ + } +get1core(){ + register int i, val; + register char *p; +ccptr = ccl = myalloc(CCLSIZE,sizeof(*ccl)); +pcptr = pchar = myalloc(pchlen, sizeof(*pchar)); + def = (char **) myalloc(DEFSIZE,sizeof(*def)); + subs = (char **) myalloc(DEFSIZE,sizeof(*subs)); +dp = dchar = myalloc(DEFCHAR,sizeof(*dchar)); + sname = (char **) myalloc(STARTSIZE,sizeof(*sname)); +sp = schar = myalloc(STARTCHAR,sizeof(*schar)); + if(ccl == 0 || def == 0 || subs == 0 || dchar == 0 || sname == 0 || schar == 0) + error("Too little core to begin"); + } +free1core(){ + cfree(def,DEFSIZE,sizeof(*def)); + cfree(subs,DEFSIZE,sizeof(*subs)); + cfree(dchar,DEFCHAR,sizeof(*dchar)); + } +get2core(){ + register int i, val; + register char *p; + gotof = (int *) myalloc(nstates,sizeof(*gotof)); + nexts = (int *) myalloc(ntrans,sizeof(*nexts)); + nchar = myalloc(ntrans,sizeof(*nchar)); + state = (int **) myalloc(nstates,sizeof(*state)); + atable = (int *) myalloc(nstates,sizeof(*atable)); + sfall = (int *) myalloc(nstates,sizeof(*sfall)); + cpackflg = myalloc(nstates,sizeof(*cpackflg)); + tmpstat = myalloc(tptr+1,sizeof(*tmpstat)); + foll = (int **) myalloc(tptr+1,sizeof(*foll)); +nxtpos = positions = (int *) myalloc(maxpos,sizeof(*positions)); + if(tmpstat == 0 || foll == 0 || positions == 0 || + gotof == 0 || nexts == 0 || nchar == 0 || state == 0 || atable == 0 || sfall == 0 || cpackflg == 0 ) + error("Too little core for state generation"); + for(i=0;i<=tptr;i++)foll[i] = 0; + } +free2core(){ + cfree(positions,maxpos,sizeof(*positions)); + cfree(tmpstat,tptr+1,sizeof(*tmpstat)); + cfree(foll,tptr+1,sizeof(*foll)); + cfree(name,treesize,sizeof(*name)); + cfree(left,treesize,sizeof(*left)); + cfree(right,treesize,sizeof(*right)); + cfree(parent,treesize,sizeof(*parent)); + cfree(nullstr,treesize,sizeof(*nullstr)); + cfree(state,nstates,sizeof(*state)); + cfree(sname,STARTSIZE,sizeof(*sname)); + cfree(schar,STARTCHAR,sizeof(*schar)); + cfree(ccl,CCLSIZE,sizeof(*ccl)); + } +get3core(){ + register int i, val; + register char *p; + verify = (int *) myalloc(outsize,sizeof(*verify)); + advance = (int *) myalloc(outsize,sizeof(*advance)); + stoff = (int *) myalloc(stnum+2,sizeof(*stoff)); + if(verify == 0 || advance == 0 || stoff == 0) + error("Too little core for final packing"); + } +# ifdef DEBUG +free3core(){ + cfree(advance,outsize,sizeof(*advance)); + cfree(verify,outsize,sizeof(*verify)); + cfree(stoff,stnum+1,sizeof(*stoff)); + cfree(gotof,nstates,sizeof(*gotof)); + cfree(nexts,ntrans,sizeof(*nexts)); + cfree(nchar,ntrans,sizeof(*nchar)); + cfree(atable,nstates,sizeof(*atable)); + cfree(sfall,nstates,sizeof(*sfall)); + cfree(cpackflg,nstates,sizeof(*cpackflg)); + } +# endif +char *myalloc(a,b) + int a,b; { + register char *i; + i = calloc(a, b); + if(i==0) + warning("OOPS - calloc returns a 0"); + else if(i == (char *)-1){ +# ifdef DEBUG + warning("calloc returns a -1"); +# endif + return(0); + } + return(i); + } +# ifdef DEBUG +buserr(){ + fflush(errorf); + fflush(fout); + fflush(stdout); + fprintf(errorf,"Bus error\n"); + if(report == 1)statistics(); + fflush(errorf); + } +segviol(){ + fflush(errorf); + fflush(fout); + fflush(stdout); + fprintf(errorf,"Segmentation violation\n"); + if(report == 1)statistics(); + fflush(errorf); + } +# endif + +yyerror(s) +char *s; +{ + fprintf(stderr, "\"%s\", line %d: %s\n", + fptr > 0 ? sargv[fptr] : "", yyline, s); +} diff --git a/src/cmd/lex/ncform b/src/cmd/lex/ncform new file mode 100644 index 0000000..789650d --- /dev/null +++ b/src/cmd/lex/ncform @@ -0,0 +1,181 @@ +/* ncform 4.1 83/08/11 */ + +int yylineno =1; +# define YYU(x) x +# define NLSTATE yyprevious=YYNEWLINE +char yytext[YYLMAX]; +struct yysvf *yylstate [YYLMAX], **yylsp, **yyolsp; +char yysbuf[YYLMAX]; +char *yysptr = yysbuf; +int *yyfnd; +extern struct yysvf *yyestate; +int yyprevious = YYNEWLINE; +yylook(){ + register struct yysvf *yystate, **lsp; + register struct yywork *yyt; + struct yysvf *yyz; + int yych; + struct yywork *yyr; +# ifdef LEXDEBUG + int debug; +# endif + char *yylastch; + /* start off machines */ +# ifdef LEXDEBUG + debug = 0; +# endif + if (!yymorfg) + yylastch = yytext; + else { + yymorfg=0; + yylastch = yytext+yyleng; + } + for(;;){ + lsp = yylstate; + yyestate = yystate = yybgin; + if (yyprevious==YYNEWLINE) yystate++; + for (;;){ +# ifdef LEXDEBUG + if(debug)fprintf(yyout,"state %d\n",yystate-yysvec-1); +# endif + yyt = yystate->yystoff; + if(yyt == yycrank){ /* may not be any transitions */ + yyz = yystate->yyother; + if(yyz == 0)break; + if(yyz->yystoff == yycrank)break; + } + *yylastch++ = yych = input(); + tryagain: +# ifdef LEXDEBUG + if(debug){ + fprintf(yyout,"char "); + allprint(yych); + putchar('\n'); + } +# endif + yyr = yyt; + if ( (int)yyt > (int)yycrank){ + yyt = yyr + yych; + if (yyt <= yytop && yyt->verify+yysvec == yystate){ + if(yyt->advance+yysvec == YYLERR) /* error transitions */ + {unput(*--yylastch);break;} + *lsp++ = yystate = yyt->advance+yysvec; + goto contin; + } + } +# ifdef YYOPTIM + else if((int)yyt < (int)yycrank) { /* r < yycrank */ + yyt = yyr = yycrank+(yycrank-yyt); +# ifdef LEXDEBUG + if(debug)fprintf(yyout,"compressed state\n"); +# endif + yyt = yyt + yych; + if(yyt <= yytop && yyt->verify+yysvec == yystate){ + if(yyt->advance+yysvec == YYLERR) /* error transitions */ + {unput(*--yylastch);break;} + *lsp++ = yystate = yyt->advance+yysvec; + goto contin; + } + yyt = yyr + YYU(yymatch[yych]); +# ifdef LEXDEBUG + if(debug){ + fprintf(yyout,"try fall back character "); + allprint(YYU(yymatch[yych])); + putchar('\n'); + } +# endif + if(yyt <= yytop && yyt->verify+yysvec == yystate){ + if(yyt->advance+yysvec == YYLERR) /* error transition */ + {unput(*--yylastch);break;} + *lsp++ = yystate = yyt->advance+yysvec; + goto contin; + } + } + if ((yystate = yystate->yyother) && (yyt= yystate->yystoff) != yycrank){ +# ifdef LEXDEBUG + if(debug)fprintf(yyout,"fall back to state %d\n",yystate-yysvec-1); +# endif + goto tryagain; + } +# endif + else + {unput(*--yylastch);break;} + contin: +# ifdef LEXDEBUG + if(debug){ + fprintf(yyout,"state %d char ",yystate-yysvec-1); + allprint(yych); + putchar('\n'); + } +# endif + ; + } +# ifdef LEXDEBUG + if(debug){ + fprintf(yyout,"stopped at %d with ",*(lsp-1)-yysvec-1); + allprint(yych); + putchar('\n'); + } +# endif + while (lsp-- > yylstate){ + *yylastch-- = 0; + if (*lsp != 0 && (yyfnd= (*lsp)->yystops) && *yyfnd > 0){ + yyolsp = lsp; + if(yyextra[*yyfnd]){ /* must backup */ + while(yyback((*lsp)->yystops,-*yyfnd) != 1 && lsp > yylstate){ + lsp--; + unput(*yylastch--); + } + } + yyprevious = YYU(*yylastch); + yylsp = lsp; + yyleng = yylastch-yytext+1; + yytext[yyleng] = 0; +# ifdef LEXDEBUG + if(debug){ + fprintf(yyout,"\nmatch "); + sprint(yytext); + fprintf(yyout," action %d\n",*yyfnd); + } +# endif + return(*yyfnd++); + } + unput(*yylastch); + } + if (yytext[0] == 0 /* && feof(yyin) */) + { + yysptr=yysbuf; + return(0); + } + yyprevious = yytext[0] = input(); + if (yyprevious>0) + output(yyprevious); + yylastch=yytext; +# ifdef LEXDEBUG + if(debug)putchar('\n'); +# endif + } + } +yyback(p, m) + int *p; +{ +if (p==0) return(0); +while (*p) + { + if (*p++ == m) + return(1); + } +return(0); +} + /* the following are only used in the lex library */ +yyinput(){ + return(input()); + } +yyoutput(c) + int c; { + output(c); + } +yyunput(c) + int c; { + unput(c); + } diff --git a/src/cmd/lex/nrform b/src/cmd/lex/nrform new file mode 100644 index 0000000..8621ef9 --- /dev/null +++ b/src/cmd/lex/nrform @@ -0,0 +1,155 @@ +block data +integer cshift, csize, yynlin +common /yyllib/ cshift, csize, yynlin +data yynlin/YYNEWLINE/ +end +block data +common /yyldat/ yyfnd, ymorf, yyprev, yybgin, yytop +integer yyfnd, yymorf, yyprev, yybgin, yytop +data yybgin/1/ +data yyprev/YYNEWLINE/ +data yytop/YYTOPVAL/ +end +integer function yylook(dummy) +common /Lverif/ verif +common /Ladvan/ advan +common /Lstoff/ stoff +common /Lsfall/ sfall +common /Latable/ atable +common /Lextra/ extra +common /Lvstop/ vstop +integer verif(Sverif), advan(Sadvan),stoff(Sstoff),match(Smatch) +integer sfall(Ssfall),atable(Satable),extra(Sextra), vstop(Svstop) +integer state, lsp, r +integer ch, n +common /yyldat/ yyfnd, yymorf, yyprev, yybgin, yytop, yylsp, yylsta(YYLMAX) +common /yyxel/ yyleng, yytext +integer yyfnd, yymorf, yylsta, yylsp, yytext, yyprev, yyleng, yytop +integer lexshf, yytext(YYLMAX), yyback, yybgin +integer z, t +if (yymorf .eq. 0) + yyleng = 0 +else + yymorf=0 +1776 + lsp = 1 + state = yybgin + if (yyprev .eq. YYNEWLINE) + state = state + 1 + for (;;){ + r = stoff(state) + if (r .eq. 0){ + z = sfall(state) + if (z .eq. 0) + break + if(stoff(z) == 0) break + } + ch = input(dummy) + ich = lexshf(ch) + yyleng = yyleng+1 + yytext(yyleng) = ch + 1984 + if(r .gt. 0){ + t = r + ich + if (t<= yytop){ + if (verif(t) .eq. state){ + if(advan(t) == YYERROR){ + call unput(yytext(yyleng)) + yyleng = yyleng - 1 + break + } + state = advan(t) + yylsta(lsp) = state + lsp = lsp +1 + goto 2001 + } + } + } + if(r < 0){ + t = r + ich + if (t <= yytop .and. verif(t) .eq. state){ + if(advan(t) == YYERROR){ + call unput(yytext(yyleng)) + yyleng = yyleng - 1 + break + } + state = advan(t) + yylsta(lsp) = state + lsp = lsp +1 + goto 2001 + } + t = r + match(ich) + if(t <= yytop && state == verif(t)){ + if(advan(t) == YYERROR){ + call unput(yytext(yyleng)) + yyleng = yyleng - 1 + break + } + state = advan(t) + yylsta(lsp) = state + lsp = lsp + 1 + goto 2001 + } + } + else { + if (state > 0) state = sfall(state) + if (state .gt. 0) r = stoff(state) + if (state .gt. 0 .and. r .ne. 0) + goto 1984 + call unput(yytext(yyleng)) + yyleng = yyleng -1 + break + } + 2001 + continue + } + while (lsp .gt. 1){ + lsp = lsp -1 + ilsp = yylsta(lsp) + yyfnd = atable(ilsp) + if (yyfnd .gt. 0) + if (vstop(yyfnd) .gt. 0){ + r = vstop(yyfnd) + if (extra(r) .ne. 0){ + for(;;){ + ilsp = yylsta(lsp) + if (yyback(atable(ilsp), -r) .eq. 1) + break + lsp= lsp -1 + call unput(yytext(yyleng)) + yyleng = yyleng -1 + } + } + yyprev = lexshf(yytext(yyleng)) + yylsp = lsp + yyfnd = yyfnd + 1 + yylook = r + yytext(yyleng+1) = 0 + return + } + call unput(yytext(yyleng)) + } + if (yytext(1) .eq. 0){ + yylook=0 + return + } + yyprev = input(dummy) + call output(yyprev) + yyprev = lexshf(yyprev) + yyleng = 0 + goto 1776 +end +integer function yyback (isub, n) +common /Lvstop/ vstop +integer vstop(Svstop) +if (isub .ne. 0) +while (vstop(isub) .ne. 0){ + if (vstop(isub) .eq. m){ + yyback = 1 + return + } + isub = isub + 1 + } +yyback = 0 +return +end diff --git a/src/cmd/lex/once.c b/src/cmd/lex/once.c new file mode 100644 index 0000000..e890ce0 --- /dev/null +++ b/src/cmd/lex/once.c @@ -0,0 +1,131 @@ +/* once.c 4.1.1 (2.11BSD) 1996/10/23 */ + /* because of external definitions, this code should occur only once */ +# ifdef ASCII +int ctable[2*NCH] = { + 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}; +# endif +# ifdef EBCDIC +int ctable[2*NCH] = { + 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,128,129, +130,131,132,133,134,135,136,137,138,139, +140,141,142,143,144,145,146,147,148,149, +150,151,152,153,154,155,156,157,158,159, +160,161,162,163,164,165,166,167,168,169, +170,171,172,173,174,175,176,177,178,179, +180,181,182,183,184,185,186,187,188,189, +190,191,192,193,194,195,196,197,198,199, +200,201,202,203,204,205,206,207,208,209, +210,211,212,213,214,215,216,217,218,219, +220,221,222,223,224,225,226,227,228,229, +230,231,232,233,234,235,236,237,238,239, +240,241,242,243,244,245,246,247,248,249, +250,251,252,253,254,255}; +# endif +int ZCH = NCH; +FILE *fout = NULL, *errorf = {stdout}; +int sect = DEFSECTION; +int prev = '\n'; /* previous input character */ +int pres = '\n'; /* present input character */ +int peek = '\n'; /* next input character */ +char *pushptr = pushc; +char *slptr = slist; + +# if (unix || ibm) +char *cname = _PATH_SHARE "lex/ncform"; +char *ratname = _PATH_SHARE "lex/nrform"; +# endif + +# ifdef gcos +char *cname = "pounce/lexcform"; +char *ratname = "pounce/lexrform"; +# endif +int ccount = 1; +int casecount = 1; +int aptr = 1; +int nstates = NSTATES, maxpos = MAXPOS; +int treesize = TREESIZE, ntrans = NTRANS; +int yytop; +int outsize = NOUTPUT; +int sptr = 1; +int optim = TRUE; +int report = 2; +int debug; /* 1 = on */ +int charc; +int sargc; +char **sargv; +char buf[520]; +int ratfor; /* 1 = ratfor, 0 = C */ +int yyline; /* line number of file */ +int eof; +int lgatflg; +int divflg; +int funcflag; +int pflag; +int chset; /* 1 = char set modified */ +FILE *fin, *fother; +int fptr; +int *name; +int *left; +int *right; +int *parent; +char *nullstr; +int tptr; +char pushc[TOKENSIZE]; +char slist[STARTSIZE]; +char **def, **subs, *dchar; +char **sname, *schar; +char *ccl; +char *ccptr; +char *dp, *sp; +int dptr; +char *bptr; /* store input position */ +char *tmpstat; +int count; +int **foll; +int *nxtpos; +int *positions; +int *gotof; +int *nexts; +char *nchar; +int **state; +int *sfall; /* fallback state num */ +char *cpackflg; /* true if state has been character packed */ +int *atable; +int nptr; +char symbol[NCH]; +char cindex[NCH]; +int xstate; +int stnum; +char match[NCH]; +char extra[NACTIONS]; +char *pchar, *pcptr; +int pchlen = TOKENSIZE; + long rcount; +int *verify, *advance, *stoff; +int scon; +char *psave; +int buserr(), segviol(); diff --git a/src/cmd/lex/parser.y b/src/cmd/lex/parser.y new file mode 100644 index 0000000..966e58f --- /dev/null +++ b/src/cmd/lex/parser.y @@ -0,0 +1,714 @@ +%token CHAR CCL NCCL STR DELIM SCON ITER NEWE NULLS +%left SCON '/' NEWE +%left '|' +%left '$' '^' +%left CHAR CCL NCCL '(' '.' STR NULLS +%left ITER +%left CAT +%left '*' '+' '?' + +%{ +#ifndef lint +static char sccsid[] = "@(#)parser.y 4.1 (Berkeley) 8/11/83"; +#endif + +# include "ldefs.c" +%} +%% +%{ +int i; +int j,k; +int g; +char *p; +%} +acc : lexinput + ={ +# ifdef DEBUG + if(debug) sect2dump(); +# endif + } + ; +lexinput: defns delim prods end + | defns delim end + ={ + if(!funcflag)phead2(); + funcflag = TRUE; + } + | error + ={ +# ifdef DEBUG + if(debug) { + sect1dump(); + sect2dump(); + } +# endif + } + ; +end: delim | ; +defns: defns STR STR + ={ scopy($2,dp); + def[dptr] = dp; + dp += slength($2) + 1; + scopy($3,dp); + subs[dptr++] = dp; + if(dptr >= DEFSIZE) + error("Too many definitions"); + dp += slength($3) + 1; + if(dp >= dchar+DEFCHAR) + error("Definitions too long"); + subs[dptr]=def[dptr]=0; /* for lookup - require ending null */ + } + | + ; +delim: DELIM + ={ +# ifdef DEBUG + if(sect == DEFSECTION && debug) sect1dump(); +# endif + sect++; + } + ; +prods: prods pr + ={ $$ = mn2(RNEWE,$1,$2); + } + | pr + ={ $$ = $1;} + ; +pr: r NEWE + ={ + if(divflg == TRUE) + i = mn1(S1FINAL,casecount); + else i = mn1(FINAL,casecount); + $$ = mn2(RCAT,$1,i); + divflg = FALSE; + casecount++; + } + | error NEWE + ={ +# ifdef DEBUG + if(debug) sect2dump(); +# endif + } +r: CHAR + ={ $$ = mn0($1); } + | STR + ={ + p = $1; + i = mn0(*p++); + while(*p) + i = mn2(RSTR,i,*p++); + $$ = i; + } + | '.' + ={ symbol['\n'] = 0; + if(psave == FALSE){ + p = ccptr; + psave = ccptr; + for(i=1;i<'\n';i++){ + symbol[i] = 1; + *ccptr++ = i; + } + for(i='\n'+1;i ccl+CCLSIZE) + error("Too many large character classes"); + } + else + p = psave; + $$ = mn1(RCCL,p); + cclinter(1); + } + | CCL + ={ $$ = mn1(RCCL,$1); } + | NCCL + ={ $$ = mn1(RNCCL,$1); } + | r '*' + ={ $$ = mn1(STAR,$1); } + | r '+' + ={ $$ = mn1(PLUS,$1); } + | r '?' + ={ $$ = mn1(QUEST,$1); } + | r '|' r + ={ $$ = mn2(BAR,$1,$3); } + | r r %prec CAT + ={ $$ = mn2(RCAT,$1,$2); } + | r '/' r + ={ if(!divflg){ + j = mn1(S2FINAL,-casecount); + i = mn2(RCAT,$1,j); + $$ = mn2(DIV,i,$3); + } + else { + $$ = mn2(RCAT,$1,$3); + warning("Extra slash removed"); + } + divflg = TRUE; + } + | r ITER ',' ITER '}' + ={ if($2 > $4){ + i = $2; + $2 = $4; + $4 = i; + } + if($4 <= 0) + warning("Iteration range must be positive"); + else { + j = $1; + for(k = 2; k<=$2;k++) + j = mn2(RCAT,j,dupl($1)); + for(i = $2+1; i<=$4; i++){ + g = dupl($1); + for(k=2;k<=i;k++) + g = mn2(RCAT,g,dupl($1)); + j = mn2(BAR,j,g); + } + $$ = j; + } + } + | r ITER '}' + ={ + if($2 < 0)warning("Can't have negative iteration"); + else if($2 == 0) $$ = mn0(RNULLS); + else { + j = $1; + for(k=2;k<=$2;k++) + j = mn2(RCAT,j,dupl($1)); + $$ = j; + } + } + | r ITER ',' '}' + ={ + /* from n to infinity */ + if($2 < 0)warning("Can't have negative iteration"); + else if($2 == 0) $$ = mn1(STAR,$1); + else if($2 == 1)$$ = mn1(PLUS,$1); + else { /* >= 2 iterations minimum */ + j = $1; + for(k=2;k<$2;k++) + j = mn2(RCAT,j,dupl($1)); + k = mn1(PLUS,dupl($1)); + $$ = mn2(RCAT,j,k); + } + } + | SCON r + ={ $$ = mn2(RSCON,$2,$1); } + | '^' r + ={ $$ = mn1(CARAT,$2); } + | r '$' + ={ i = mn0('\n'); + if(!divflg){ + j = mn1(S2FINAL,-casecount); + k = mn2(RCAT,$1,j); + $$ = mn2(DIV,k,i); + } + else $$ = mn2(RCAT,$1,i); + divflg = TRUE; + } + | '(' r ')' + ={ $$ = $2; } + | NULLS + ={ $$ = mn0(RNULLS); } + ; +%% +yylex(){ + register char *p; + register int c, i; + char *t, *xp; + int n, j, k, x; + static int sectbegin; + static char token[TOKENSIZE]; + static int iter; + +# ifdef DEBUG + yylval = 0; +# endif + + if(sect == DEFSECTION) { /* definitions section */ + while(!eof) { + if(prev == '\n'){ /* next char is at beginning of line */ + getl(p=buf); + switch(*p){ + case '%': + switch(c= *(p+1)){ + case '%': + lgate(); + if(!ratfor)fprintf(fout,"# "); + fprintf(fout,"define YYNEWLINE %d\n",ctable['\n']); + if(!ratfor)fprintf(fout,"yylex(){\nint nstr; extern int yyprevious;\n"); + sectbegin = TRUE; + i = treesize*(sizeof(*name)+sizeof(*left)+ + sizeof(*right)+sizeof(*nullstr)+sizeof(*parent))+ALITTLEEXTRA; + c = myalloc(i,1); + if(c == 0) + error("Too little core for parse tree"); + p = c; + cfree(p,i,1); + name = myalloc(treesize,sizeof(*name)); + left = myalloc(treesize,sizeof(*left)); + right = myalloc(treesize,sizeof(*right)); + nullstr = myalloc(treesize,sizeof(*nullstr)); + parent = myalloc(treesize,sizeof(*parent)); + if(name == 0 || left == 0 || right == 0 || parent == 0 || nullstr == 0) + error("Too little core for parse tree"); + return(freturn(DELIM)); + case 'p': case 'P': /* has overridden number of positions */ + while(*p && !digit(*p))p++; + maxpos = siconv(p); +# ifdef DEBUG + if (debug) printf("positions (%%p) now %d\n",maxpos); +# endif + if(report == 2)report = 1; + continue; + case 'n': case 'N': /* has overridden number of states */ + while(*p && !digit(*p))p++; + nstates = siconv(p); +# ifdef DEBUG + if(debug)printf( " no. states (%%n) now %d\n",nstates); +# endif + if(report == 2)report = 1; + continue; + case 'e': case 'E': /* has overridden number of tree nodes */ + while(*p && !digit(*p))p++; + treesize = siconv(p); +# ifdef DEBUG + if (debug) printf("treesize (%%e) now %d\n",treesize); +# endif + if(report == 2)report = 1; + continue; + case 'o': case 'O': + while (*p && !digit(*p))p++; + outsize = siconv(p); + if (report ==2) report=1; + continue; + case 'a': case 'A': /* has overridden number of transitions */ + while(*p && !digit(*p))p++; + if(report == 2)report = 1; + ntrans = siconv(p); +# ifdef DEBUG + if (debug)printf("N. trans (%%a) now %d\n",ntrans); +# endif + continue; + case 'k': case 'K': /* overriden packed char classes */ + while (*p && !digit(*p))p++; + if (report==2) report=1; + cfree(pchar, pchlen, sizeof(*pchar)); + pchlen = siconv(p); +# ifdef DEBUG + if (debug) printf( "Size classes (%%k) now %d\n",pchlen); +# endif + pchar=pcptr=myalloc(pchlen, sizeof(*pchar)); + continue; + case 't': case 'T': /* character set specifier */ + ZCH = atoi(p+2); + if (ZCH < NCH) ZCH = NCH; + if (ZCH > 2*NCH) error("ch table needs redeclaration"); + chset = TRUE; + for(i = 0; i ZCH){ + warning("Character value %d out of range",n); + continue; + } + while(!space(*p) && *p) p++; + while(space(*p)) p++; + t = p; + while(*t){ + c = ctrans(&t); + if(ctable[c]){ + if (printable(c)) + warning("Character '%c' used twice",c); + else + warning("Character %o used twice",c); + } + else ctable[c] = n; + t++; + } + p = buf; + } + { + char chused[2*NCH]; int kr; + for(i=0; i= 0) p++; + t = p; + while(*p && index(*p," \t,") < 0)p++; + if(!*p) n = FALSE; + *p++ = 0; + if (*t == 0) continue; + i = sptr*2; + if(!ratfor)fprintf(fout,"# "); + fprintf(fout,"define %s %d\n",t,i); + scopy(t,sp); + sname[sptr++] = sp; + sname[sptr] = 0; /* required by lookup */ + if(sptr >= STARTSIZE) + error("Too many start conditions"); + sp += slength(sp) + 1; + if(sp >= schar+STARTCHAR) + error("Start conditions too long"); + } + continue; + default: + warning("Invalid request %s",p); + continue; + } /* end of switch after seeing '%' */ + case ' ': case '\t': /* must be code */ + lgate(); + fprintf(fout, "%s\n",p); + continue; + default: /* definition */ + while(*p && !space(*p)) p++; + if(*p == 0) + continue; + prev = *p; + *p = 0; + bptr = p+1; + yylval = buf; + if(digit(buf[0])) + warning("Substitution strings may not begin with digits"); + return(freturn(STR)); + } + } + /* still sect 1, but prev != '\n' */ + else { + p = bptr; + while(*p && space(*p)) p++; + if(*p == 0) + warning("No translation given - null string assumed"); + scopy(p,token); + yylval = token; + prev = '\n'; + return(freturn(STR)); + } + } + /* end of section one processing */ + } + else if(sect == RULESECTION){ /* rules and actions */ + while(!eof){ + switch(c=gch()){ + case '\0': + return(freturn(0)); + case '\n': + if(prev == '\n') continue; + x = NEWE; + break; + case ' ': + case '\t': + if(sectbegin == TRUE){ + cpyact(); + while((c=gch()) && c != '\n'); + continue; + } + if(!funcflag)phead2(); + funcflag = TRUE; + if(ratfor)fprintf(fout,"%d\n",30000+casecount); + else fprintf(fout,"case %d:\n",casecount); + if(cpyact()){ + if(ratfor)fprintf(fout,"goto 30997\n"); + else fprintf(fout,"break;\n"); + } + while((c=gch()) && c != '\n'); + if(peek == ' ' || peek == '\t' || sectbegin == TRUE){ + warning("Executable statements should occur right after %%"); + continue; + } + x = NEWE; + break; + case '%': + if(prev != '\n') goto character; + if(peek == '{'){ /* included code */ + getl(buf); + while(!eof && getl(buf) && scomp("%}",buf) != 0) + fprintf(fout,"%s\n",buf); + continue; + } + if(peek == '%'){ + c = gch(); + c = gch(); + x = DELIM; + break; + } + goto character; + case '|': + if(peek == ' ' || peek == '\t' || peek == '\n'){ + if(ratfor)fprintf(fout,"%d\n",30000+casecount++); + else fprintf(fout,"case %d:\n",casecount++); + continue; + } + x = '|'; + break; + case '$': + if(peek == '\n' || peek == ' ' || peek == '\t' || peek == '|' || peek == '/'){ + x = c; + break; + } + goto character; + case '^': + if(prev != '\n' && scon != TRUE) goto character; /* valid only at line begin */ + x = c; + break; + case '?': + case '+': + case '.': + case '*': + case '(': + case ')': + case ',': + case '/': + x = c; + break; + case '}': + iter = FALSE; + x = c; + break; + case '{': /* either iteration or definition */ + if(digit(c=gch())){ /* iteration */ + iter = TRUE; + ieval: + i = 0; + while(digit(c)){ + token[i++] = c; + c = gch(); + } + token[i] = 0; + yylval = siconv(token); + munput('c',c); + x = ITER; + break; + } + else { /* definition */ + i = 0; + while(c && c!='}'){ + token[i++] = c; + c = gch(); + } + token[i] = 0; + i = lookup(token,def); + if(i < 0) + warning("Definition %s not found",token); + else + munput('s',subs[i]); + continue; + } + case '<': /* start condition ? */ + if(prev != '\n') /* not at line begin, not start */ + goto character; + t = slptr; + do { + i = 0; + c = gch(); + while(c != ',' && c && c != '>'){ + token[i++] = c; + c = gch(); + } + token[i] = 0; + if(i == 0) + goto character; + i = lookup(token,sname); + if(i < 0) { + warning("Undefined start condition %s",token); + continue; + } + *slptr++ = i+1; + } while(c && c != '>'); + *slptr++ = 0; + /* check if previous value re-usable */ + for (xp=slist; xp slist+STARTSIZE) /* note not packed ! */ + error("Too many start conditions used"); + yylval = t; + x = SCON; + break; + case '"': + i = 0; + while((c=gch()) && c != '"' && c != '\n'){ + if(c == '\\') c = usescape(c=gch()); + token[i++] = c; + if(i > TOKENSIZE){ + warning("String too long"); + i = TOKENSIZE-1; + break; + } + } + if(c == '\n') { + yyline--; + warning("Non-terminated string"); + yyline++; + } + token[i] = 0; + if(i == 0)x = NULLS; + else if(i == 1){ + yylval = token[0]; + x = CHAR; + } + else { + yylval = token; + x = STR; + } + break; + case '[': + for(i=1;i k) { + n = j; + j = k; + k = n; + } + if(!(('A' <= j && k <= 'Z') || + ('a' <= j && k <= 'z') || + ('0' <= j && k <= '9'))) + warning("Non-portable Character Class"); + for(n=j+1;n<=k;n++) + symbol[n] = 1; /* implementation dependent */ + c = gch(); + } + } + /* try to pack ccl's */ + i = 0; + for(j=0;j= ccl+CCLSIZE) + error("Too many large character classes"); + } + cclinter(x==CCL); + break; + case '\\': + c = usescape(c=gch()); + default: + character: + if(iter){ /* second part of an iteration */ + iter = FALSE; + if('0' <= c && c <= '9') + goto ieval; + } + if(alpha(peek)){ + i = 0; + yylval = token; + token[i++] = c; + while(alpha(peek)) + token[i++] = gch(); + if(peek == '?' || peek == '*' || peek == '+') + munput('c',token[--i]); + token[i] = 0; + if(i == 1){ + yylval = token[0]; + x = CHAR; + } + else x = STR; + } + else { + yylval = c; + x = CHAR; + } + } + scon = FALSE; + if(x == SCON)scon = TRUE; + sectbegin = FALSE; + return(freturn(x)); + } + } + /* section three */ + ptail(); +# ifdef DEBUG + if(debug) + fprintf(fout,"\n/*this comes from section three - debug */\n"); +# endif + while(getl(buf) && !eof) + fprintf(fout,"%s\n",buf); + return(freturn(0)); + } +/* end of yylex */ +# ifdef DEBUG +freturn(i) + int i; { + if(yydebug) { + printf("now return "); + if(i < NCH) allprint(i); + else printf("%d",i); + printf(" yylval = "); + switch(i){ + case STR: case CCL: case NCCL: + strpt(yylval); + break; + case CHAR: + allprint(yylval); + break; + default: + printf("%d",yylval); + break; + } + putchar('\n'); + } + return(i); + } +# endif diff --git a/src/cmd/lex/sub1.c b/src/cmd/lex/sub1.c new file mode 100644 index 0000000..7b6b0c8 --- /dev/null +++ b/src/cmd/lex/sub1.c @@ -0,0 +1,692 @@ +# include "ldefs.c" + +char * +getl(p) /* return next line of input, throw away trailing '\n' */ + /* returns 0 if eof is had immediately */ + char *p; + { + register int c; + register char *s, *t; + t = s = p; + while(((c = gch()) != 0) && c != '\n') + *t++ = c; + *t = 0; + if(c == 0 && s == t) return(0); + prev = '\n'; + pres = '\n'; + return(s); + } +space(ch) + { + switch(ch) + { + case ' ': + case '\t': + case '\n': + return(1); + } + return(0); + } + +digit(c) +{ + return(c>='0' && c <= '9'); +} +error(s,p,d) + { + fprintf(errorf,"\"%s\", line %d: (Error) ", + fptr > 0 ? sargv[fptr] : "", yyline); + fprintf(errorf,s,p,d); + putc('\n',errorf); +# ifdef DEBUG + if(debug && sect != ENDSECTION) { + sect1dump(); + sect2dump(); + } +# endif + if( +# ifdef DEBUG + debug || +# endif + report == 1) statistics(); + exit(1); /* error return code */ + } + +warning(s,p,d) + { + fprintf(errorf,"\"%s\", line %d: (Warning) ", + fptr > 0 ? sargv[fptr] : "", yyline); + fprintf(errorf,s,p,d); + putc('\n',errorf); + fflush(errorf); + fflush(fout); + fflush(stdout); + } +index(a,s) + char *s; +{ + register int k; + for(k=0; s[k]; k++) + if (s[k]== a) + return(k); + return(-1); + } + +alpha(c) + int c; { +# ifdef ASCII +return('a' <= c && c <= 'z' || 'A' <= c && c <= 'Z'); +# endif +# ifdef EBCDIC +return(index(c,"abcdefghijklmnopqrstuvxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") >= 0); +# endif +} +printable(c) +{ +# ifdef ASCII +return( c>040 && c < 0177); +# endif +# ifdef EBCDIC +return(index(c, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.,;:><+*)('&%!-=\"")>=0); +# endif +} +lgate() +{ + char fname[20]; + if (lgatflg) return; + lgatflg=1; + if(fout == NULL){ + sprintf(fname, "lex.yy.%c", ratfor ? 'r' : 'c' ); + fout = fopen(fname, "w"); + } + if(fout == NULL) error("Can't open %s",fname); + if(ratfor) fprintf( fout, "#\n"); + phead1(); + } +/* scopy(ptr to str, ptr to str) - copy first arg str to second */ +/* returns ptr to second arg */ +scopy(s,t) + char *s, *t; { + register char *i; + i = t; + while(*i++ = *s++); + return; + } +siconv(t) /* convert string t, return integer value */ + char *t; { + register int i,sw; + register char *s; + s = t; + while(!(('0' <= *s && *s <= '9') || *s == '-') && *s) s++; + sw = 0; + if(*s == '-'){ /* neg */ + sw = 1; + s++; + } + i = 0; + while('0' <= *s && *s <= '9') + i = i * 10 + (*(s++)-'0'); + return(sw ? -i : i); + } +/* slength(ptr to str) - return integer length of string arg */ +/* excludes '\0' terminator */ +slength(s) + char *s; { + register int n; + register char *t; + t = s; + for (n = 0; *t++; n++); + return(n); + } +/* scomp(x,y) - return -1 if x < y, + 0 if x == y, + return 1 if x > y, all lexicographically */ +scomp(x,y) + char *x,*y; { + register char *a,*d; + a = x; + d = y; + while(*a || *d){ + if(*a > *d) + return(1); /* greater */ + if(*a < *d) + return(-1); /* less */ + a++; + d++; + } + return(0); /* equal */ + } +ctrans(ss) + char **ss; +{ + register int c, k; + if ((c = **ss) != '\\') + return(c); + switch(c= *++*ss) + { + case 'n': c = '\n'; break; + case 't': c = '\t'; break; + case 'r': c = '\r'; break; + case 'b': c = '\b'; break; + case 'f': c = 014; break; /* form feed for ascii */ + case '\\': c = '\\'; break; + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + c -= '0'; + while ((k = *(*ss+1)) >= '0' && k <= '7') + { + c = c*8 + k - '0'; + (*ss)++; + } + break; + } + return(c); +} +cclinter(sw) + int sw; { + /* sw = 1 ==> ccl */ + register int i, j, k; + int m; + if(!sw){ /* is NCCL */ + for(i=1;i= NCH) return; + i = cindex[i]; + /* see if ccl is already in our table */ + j = 0; + if(i){ + for(j=1;j= NCH) return; /* already in */ + m = 0; + k = 0; + for(i=1;i pushc ? *--pushptr : getc(fin); + if(peek == EOF && sargc > 1){ + hadeof = 1; + fclose(fin); + fin = fopen(sargv[++fptr],"r"); + if(fin == NULL) { + yyline = 0; + error("Cannot open file %s",sargv[fptr]); + } + peek = getc(fin); + sargc--; + } + if(c == EOF) { + eof = TRUE; + fclose(fin); + return(0); + } + if(c == '\n')yyline++; + return(c); + } +mn2(a,d,c) + int a,d,c; + { + name[tptr] = a; + left[tptr] = d; + right[tptr] = c; + parent[tptr] = 0; + nullstr[tptr] = 0; + switch(a){ + case RSTR: + parent[d] = tptr; + break; + case BAR: + case RNEWE: + if(nullstr[d] || nullstr[c]) nullstr[tptr] = TRUE; + parent[d] = parent[c] = tptr; + break; + case RCAT: + case DIV: + if(nullstr[d] && nullstr[c])nullstr[tptr] = TRUE; + parent[d] = parent[c] = tptr; + break; + case RSCON: + parent[d] = tptr; + nullstr[tptr] = nullstr[d]; + break; +# ifdef DEBUG + default: + warning("bad switch mn2 %d %d",a,d); + break; +# endif + } + if(tptr > treesize) + error("Parse tree too big %s",(treesize == TREESIZE?"\nTry using %e num":"")); + return(tptr++); + } +mn1(a,d) + int a,d; + { + name[tptr] = a; + left[tptr] = d; + parent[tptr] = 0; + nullstr[tptr] = 0; + switch(a){ + case RCCL: + case RNCCL: + if(slength(d) == 0) nullstr[tptr] = TRUE; + break; + case STAR: + case QUEST: + nullstr[tptr] = TRUE; + parent[d] = tptr; + break; + case PLUS: + case CARAT: + nullstr[tptr] = nullstr[d]; + parent[d] = tptr; + break; + case S2FINAL: + nullstr[tptr] = TRUE; + break; +# ifdef DEBUG + case FINAL: + case S1FINAL: + break; + default: + warning("bad switch mn1 %d %d",a,d); + break; +# endif + } + if(tptr > treesize) + error("Parse tree too big %s",(treesize == TREESIZE?"\nTry using %e num":"")); + return(tptr++); + } +mn0(a) + int a; + { + name[tptr] = a; + parent[tptr] = 0; + nullstr[tptr] = 0; + if(a >= NCH) switch(a){ + case RNULLS: nullstr[tptr] = TRUE; break; +# ifdef DEBUG + default: + warning("bad switch mn0 %d",a); + break; +# endif + } + if(tptr > treesize) + error("Parse tree too big %s",(treesize == TREESIZE?"\nTry using %e num":"")); + return(tptr++); + } +munput(t,p) /* implementation dependent */ + char *p; + int t; { + register int i,j; + if(t == 'c'){ + *pushptr++ = peek; /* watch out for this */ + peek = p; + } + else if(t == 's'){ + *pushptr++ = peek; + peek = p[0]; + i = slength(p); + for(j = i-1; j>=1; j--) + *pushptr++ = p[j]; + } +# ifdef DEBUG + else error("Unrecognized munput option %c",t); +# endif + if(pushptr >= pushc+TOKENSIZE) + error("Too many characters pushed"); + return; + } + +dupl(n) + int n; { + /* duplicate the subtree whose root is n, return ptr to it */ + register int i; + i = name[n]; + if(i < NCH) return(mn0(i)); + switch(i){ + case RNULLS: + return(mn0(i)); + case RCCL: case RNCCL: case FINAL: case S1FINAL: case S2FINAL: + return(mn1(i,left[n])); + case STAR: case QUEST: case PLUS: case CARAT: + return(mn1(i,dupl(left[n]))); + case RSTR: case RSCON: + return(mn2(i,dupl(left[n]),right[n])); + case BAR: case RNEWE: case RCAT: case DIV: + return(mn2(i,dupl(left[n]),dupl(right[n]))); +# ifdef DEBUG + default: + warning("bad switch dupl %d",n); +# endif + } + return(0); + } +# ifdef DEBUG +allprint(c) + char c; { + switch(c){ + case 014: + printf("\\f"); + charc++; + break; + case '\n': + printf("\\n"); + charc++; + break; + case '\t': + printf("\\t"); + charc++; + break; + case '\b': + printf("\\b"); + charc++; + break; + case ' ': + printf("\\\bb"); + break; + default: + if(!printable(c)){ + printf("\\%-3o",c); + charc += 3; + } + else + putchar(c); + break; + } + charc++; + return; + } +strpt(s) + char *s; { + charc = 0; + while(*s){ + allprint(*s++); + if(charc > LINESIZE){ + charc = 0; + printf("\n\t"); + } + } + return; + } +sect1dump(){ + register int i; + printf("Sect 1:\n"); + if(def[0]){ + printf("str trans\n"); + i = -1; + while(def[++i]) + printf("%s\t%s\n",def[i],subs[i]); + } + if(sname[0]){ + printf("start names\n"); + i = -1; + while(sname[++i]) + printf("%s\n",sname[i]); + } + if(chset == TRUE){ + printf("char set changed\n"); + for(i=1;i= pcptr)*pcptr++ = cindex[j]; + } + *pcptr++ = 0; + if(pcptr > pchar + pchlen) + error("Too many packed character classes"); + left[v] = p; + name[v] = RCCL; /* RNCCL eliminated */ +# ifdef DEBUG + if(debug && *p){ + printf("ccl %d: %d",v,*p++); + while(*p) + printf(", %d",*p++); + putchar('\n'); + } +# endif + } + break; + case CARAT: + cfoll(left[v]); + break; + case STAR: case PLUS: case QUEST: case RSCON: + cfoll(left[v]); + break; + case BAR: case RCAT: case DIV: case RNEWE: + cfoll(left[v]); + cfoll(right[v]); + break; +# ifdef DEBUG + case FINAL: + case S1FINAL: + case S2FINAL: + break; + default: + warning("bad switch cfoll %d",v); +# endif + } + return; + } +# ifdef DEBUG +pfoll() + { + register int i,k,*p; + int j; + /* print sets of chars which may follow positions */ + printf("pos\tchars\n"); + for(i=0;i= 1){ + printf("%d:\t%d",i,*p++); + for(k=2;k<=j;k++) + printf(", %d",*p++); + putchar('\n'); + } + } + return; + } +# endif +add(array,n) + int **array; + int n; { + register int i, *temp; + register char *ctemp; + temp = nxtpos; + ctemp = tmpstat; + array[n] = nxtpos; /* note no packing is done in positions */ + *temp++ = count; + for(i=0;i= positions+maxpos) + error("Too many positions %s",(maxpos== MAXPOS?"\nTry using %p num":"")); + return; + } +follow(v) + int v; + { + register int p; + if(v >= tptr-1)return; + p = parent[v]; + if(p == 0) return; + switch(name[p]){ + /* will not be CHAR RNULLS FINAL S1FINAL S2FINAL RCCL RNCCL */ + case RSTR: + if(tmpstat[p] == FALSE){ + count++; + tmpstat[p] = TRUE; + } + break; + case STAR: case PLUS: + first(v); + follow(p); + break; + case BAR: case QUEST: case RNEWE: + follow(p); + break; + case RCAT: case DIV: + if(v == left[p]){ + if(nullstr[right[p]]) + follow(p); + first(right[p]); + } + else follow(p); + break; + case RSCON: case CARAT: + follow(p); + break; +# ifdef DEBUG + default: + warning("bad switch follow %d",p); +# endif + } + return; + } +first(v) /* calculate set of positions with v as root which can be active initially */ + int v; { + register int i; + register char *p; + i = name[v]; + if(i < NCH)i = 1; + switch(i){ + case 1: case RCCL: case RNCCL: case RNULLS: case FINAL: case S1FINAL: case S2FINAL: + if(tmpstat[v] == FALSE){ + count++; + tmpstat[v] = TRUE; + } + break; + case BAR: case RNEWE: + first(left[v]); + first(right[v]); + break; + case CARAT: + if(stnum % 2 == 1) + first(left[v]); + break; + case RSCON: + i = stnum/2 +1; + p = right[v]; + while(*p) + if(*p++ == i){ + first(left[v]); + break; + } + break; + case STAR: case QUEST: case PLUS: case RSTR: + first(left[v]); + break; + case RCAT: case DIV: + first(left[v]); + if(nullstr[left[v]]) + first(right[v]); + break; +# ifdef DEBUG + default: + warning("bad switch first %d",v); +# endif + } + return; + } +cgoto(){ + register int i, j, s; + int npos, curpos, n; + int tryit; + char tch[NCH]; + int tst[NCH]; + char *q; + /* generate initial state, for each start condition */ + if(ratfor){ + fprintf(fout,"blockdata\n"); + fprintf(fout,"common /Lvstop/ vstop\n"); + fprintf(fout,"define Svstop %d\n",nstates+1); + fprintf(fout,"integer vstop(Svstop)\n"); + } + else fprintf(fout,"int yyvstop[] ={\n0,\n"); + while(stnum < 2 || stnum/2 < sptr){ + for(i = 0; i 0)first(tptr-1); + add(state,stnum); +# ifdef DEBUG + if(debug){ + if(stnum > 1) + printf("%s:\n",sname[stnum/2]); + pstate(stnum); + } +# endif + stnum++; + } + stnum--; + /* even stnum = might not be at line begin */ + /* odd stnum = must be at line begin */ + /* even states can occur anywhere, odd states only at line begin */ + for(s = 0; s <= stnum; s++){ + tryit = FALSE; + cpackflg[s] = FALSE; + sfall[s] = -1; + acompute(s); + for(i=0;i LINESIZE){ + charc = 0; + printf("\n\t"); + } + } + putchar('\n'); + } +# endif + /* for each char, calculate next state */ + n = 0; + for(i = 1; i= nstates) + error("Too many states %s",(nstates == NSTATES ? "\nTry using %n num":"")); + add(state,++stnum); +# ifdef DEBUG + if(debug)pstate(stnum); +# endif + tch[n] = i; + tst[n++] = stnum; + } + else { /* xstate >= 0 ==> state exists */ + tch[n] = i; + tst[n++] = xstate; + } + } + } + tch[n] = 0; + tst[n] = -1; + /* pack transitions into permanent array */ + if(n > 0) packtrans(s,tch,tst,n,tryit); + else gotof[s] = -1; + } + ratfor ? fprintf(fout,"end\n") : fprintf(fout,"0};\n"); + return; + } + /* Beware -- 70% of total CPU time is spent in this subroutine - + if you don't believe me - try it yourself ! */ +nextstate(s,c) + int s,c; { + register int j, *newpos; + register char *temp, *tz; + int *pos, i, *f, num, curpos, number; + /* state to goto from state s on char c */ + num = *state[s]; + temp = tmpstat; + pos = state[s] + 1; + for(i = 0; i=0;i--){ /* for each state */ + j = state[i]; + if(count == *j++){ + for(k=0;k= count) + return(i); + } + } + return(-1); + } +packtrans(st,tch,tst,cnt,tryit) + int st, *tst, cnt,tryit; + char *tch; { + /* pack transitions into nchar, nexts */ + /* nchar is terminated by '\0', nexts uses cnt, followed by elements */ + /* gotof[st] = index into nchr, nexts for state st */ + + /* sfall[st] = t implies t is fall back state for st */ + /* == -1 implies no fall back */ + + int cmin, cval, tcnt, diff, p, *ast; + register int i,j,k; + char *ach; + int go[NCH], temp[NCH], c; + int swork[NCH]; + char cwork[NCH]; + int upper; + + rcount += cnt; + cmin = -1; + cval = NCH; + ast = tst; + ach = tch; + /* try to pack transitions using ccl's */ + if(!optim)goto nopack; /* skip all compaction */ + if(tryit){ /* ccl's used */ + for(i=1;i cnt) continue; + diff = 0; + k = 0; + j = 0; + upper = p + tcnt; + while(ach[j] && p < upper){ + while(ach[j] < nchar[p] && ach[j]){diff++; j++; } + if(ach[j] == 0)break; + if(ach[j] > nchar[p]){diff=NCH;break;} + /* ach[j] == nchar[p] */ + if(ast[j] != nexts[++p] || ast[j] == -1 || (cpackflg[st] && ach[j] != match[ach[j]]))diff++; + j++; + } + while(ach[j]){ + diff++; + j++; + } + if(p < upper)diff = NCH; + if(diff < cval && diff < tcnt){ + cval = diff; + cmin = i; + if(cval == 0)break; + } + } + /* cmin = state "most like" state st */ +# ifdef DEBUG + if(debug)printf("select st %d for st %d diff %d\n",cmin,st,cval); +# endif +# ifdef PS + if(cmin != -1){ /* if we can use st cmin */ + gotof[st] = nptr; + k = 0; + sfall[st] = cmin; + p = gotof[cmin]+1; + j = 0; + while(ach[j]){ + /* if cmin has a transition on c, then so will st */ + /* st may be "larger" than cmin, however */ + while(ach[j] < nchar[p-1] && ach[j]){ + k++; + nchar[nptr] = ach[j]; + nexts[++nptr] = ast[j]; + j++; + } + if(nchar[p-1] == 0)break; + if(ach[j] > nchar[p-1]){ + warning("bad transition %d %d",st,cmin); + goto nopack; + } + /* ach[j] == nchar[p-1] */ + if(ast[j] != nexts[p] || ast[j] == -1 || (cpackflg[st] && ach[j] != match[ach[j]])){ + k++; + nchar[nptr] = ach[j]; + nexts[++nptr] = ast[j]; + } + p++; + j++; + } + while(ach[j]){ + nchar[nptr] = ach[j]; + nexts[++nptr] = ast[j++]; + k++; + } + nexts[gotof[st]] = cnt = k; + nchar[nptr++] = 0; + } + else { +# endif +nopack: + /* stick it in */ + gotof[st] = nptr; + nexts[nptr] = cnt; + for(i=0;i ntrans) + error("Too many transitions %s",(ntrans==NTRANS?"\nTry using %a num":"")); + return; + } +# ifdef DEBUG +pstate(s) + int s; { + register int *p,i,j; + printf("State %d:\n",s); + p = state[s]; + i = *p++; + if(i == 0) return; + printf("%4d",*p++); + for(j = 1; j= 0) + printf("%d\t",nexts[p+1]); + else printf("err\t"); + allprint(nchar[p++]); + while(nexts[p] == nexts[p+1] && nchar[p]){ + if(charc > LINESIZE){ + charc = 0; + printf("\n\t"); + } + allprint(nchar[p++]); + } + putchar('\n'); + } + putchar('\n'); + return; + } +# endif +acompute(s) /* compute action list = set of poss. actions */ + int s; { + register int *p, i, j; + int cnt, m; + int temp[300], k, neg[300], n; + k = 0; + n = 0; + p = state[s]; + cnt = *p++; + if(cnt > 300) + error("Too many positions for one state - acompute"); + for(i=0;iNACTIONS) error("Too many right contexts"); + extra[left[*p]] = 1; + } + else if(name[*p] == S2FINAL)neg[n++] = left[*p]; + p++; + } + atable[s] = -1; + if(k < 1 && n < 1) return; +# ifdef DEBUG + if(debug) printf("final %d actions:",s); +# endif + /* sort action list */ + for(i=0; i LINESIZE){ + printf("\n\t"); + charc = 0; + } + } + putchar('\n'); + } + charc = 0; + printf("match:\n"); + for(i=0;i LINESIZE){ + putchar('\n'); + charc = 0; + } + } + putchar('\n'); + return; + } +# endif +mkmatch(){ + register int i; + char tab[NCH]; + for(i=0; i outsize - ZCH) + error("output table overflow"); + for(j = bot; j<= top; j++){ + k=startup+ctable[nchar[j]]; + if(verify[k])break; + } + } while (j <= top); +# if DEBUG + if (debug) printf(" startup will be %d\n",startup); +# endif + /* have found place */ + for(j = bot; j<= top; j++){ + k = startup + ctable[nchar[j]]; + if (ctable[nchar[j]]<=0) + printf("j %d nchar %d ctable.nch %d\n",j,nchar[j],ctable[nchar[k]]); + verify[k] = i+1; /* state number + 1*/ + advance[k] = nexts[j+1]+1; /* state number + 1*/ + if(yytop < k) yytop = k; + } + } + else { + do { + ++startup; + if(startup > outsize - ZCH) + error("output table overflow"); + for(j = bot; j<= top; j++){ + k = startup + nchar[j]; + if(verify[k])break; + } + } while (j <= top); + /* have found place */ +# if DEBUG + if (debug) printf(" startup going to be %d\n", startup); +# endif + for(j = bot; j<= top; j++){ + k = startup + nchar[j]; + verify[k] = i+1; /* state number + 1*/ + advance[k] = nexts[j+1]+1; /* state number + 1*/ + if(yytop < k) yytop = k; + } + } + stoff[i] = startup; + } + + /* stoff[i] = offset into verify, advance for trans for state i */ + /* put out yywork */ + if(ratfor){ + fprintf(fout, "define YYTOPVAL %d\n", yytop); + rprint(verify,"verif",yytop+1); + rprint(advance,"advan",yytop+1); + shiftr(stoff, stnum); + rprint(stoff,"stoff",stnum+1); + shiftr(sfall, stnum); upone(sfall, stnum+1); + rprint(sfall,"sfall",stnum+1); + bprint(extra,"extra",casecount+1); + bprint(match,"match",NCH); + shiftr(atable, stnum); + rprint(atable,"atable",stnum+1); + return; + } + fprintf(fout,"# define YYTYPE %s\n",stnum+1 > NCH ? "int" : "char"); + fprintf(fout,"struct yywork { YYTYPE verify, advance; } yycrank[] ={\n"); + for(i=0;i<=yytop;i+=4){ + for(j=0;j<4;j++){ + k = i+j; + if(verify[k]) + fprintf(fout,"%d,%d,\t",verify[k],advance[k]); + else + fprintf(fout,"0,0,\t"); + } + putc('\n',fout); + } + fprintf(fout,"0,0};\n"); + + /* put out yysvec */ + + fprintf(fout,"struct yysvf yysvec[] ={\n"); + fprintf(fout,"0,\t0,\t0,\n"); + for(i=0;i<=stnum;i++){ /* for each state */ + if(cpackflg[i])stoff[i] = -stoff[i]; + fprintf(fout,"yycrank+%d,\t",stoff[i]); + if(sfall[i] != -1) + fprintf(fout,"yysvec+%d,\t", sfall[i]+1); /* state + 1 */ + else fprintf(fout,"0,\t\t"); + if(atable[i] != -1) + fprintf(fout,"yyvstop+%d,",atable[i]); + else fprintf(fout,"0,\t"); +# ifdef DEBUG + fprintf(fout,"\t\t/* state %d */",i); +# endif + putc('\n',fout); + } + fprintf(fout,"0,\t0,\t0};\n"); + + /* put out yymatch */ + + fprintf(fout,"struct yywork *yytop = yycrank+%d;\n",yytop); + fprintf(fout,"struct yysvf *yybgin = yysvec+1;\n"); + if(optim){ + fprintf(fout,"char yymatch[] ={\n"); + if (chset==0) /* no chset, put out in normal order */ + { + for(i=0; i=0; i--) + a[i+1]=a[i]; +} +upone(a,n) + int *a; +{ +int i; +for(i=0; i<=n ; i++) + a[i]++; +} +bprint(a,s,n) + char *s, *a; + int n; { + register int i, j, k; + fprintf(fout,"block data\n"); + fprintf(fout,"common /L%s/ %s\n",s,s); + fprintf(fout,"define S%s %d\n",s,n); + fprintf(fout,"integer %s (S%s)\n",s,s); + for(i=1;i=0;i--){ + j = array[i]; + if(j && *j++ == count){ + for(k=0;k= count){ + array[n] = array[i]; + return; + } + } + } + add(array,n); + return; + } +# endif diff --git a/src/cmd/ln.c b/src/cmd/ln.c new file mode 100644 index 0000000..d6eb781 --- /dev/null +++ b/src/cmd/ln.c @@ -0,0 +1,89 @@ +/* + * ln + */ +#include +#include +#include +#include +#include + +struct stat stb; +int fflag; /* force flag set? */ +int sflag; +char name[BUFSIZ]; +char *rindex(); +extern int errno; + +main(argc, argv) + int argc; + register char **argv; +{ + register int i, r; + + argc--, argv++; +again: + if (argc && strcmp(argv[0], "-f") == 0) { + fflag++; + argv++; + argc--; + } + if (argc && strcmp(argv[0], "-s") == 0) { + sflag++; + argv++; + argc--; + } + if (argc == 0) + goto usage; + else if (argc == 1) { + argv[argc] = "."; + argc++; + } + if (sflag == 0 && argc > 2) { + if (stat(argv[argc-1], &stb) < 0) + goto usage; + if ((stb.st_mode&S_IFMT) != S_IFDIR) + goto usage; + } + r = 0; + for(i = 0; i < argc-1; i++) + r |= linkit(argv[i], argv[argc-1]); + exit(r); +usage: + fprintf(stderr, "Usage: ln [ -s ] f1\nor: ln [ -s ] f1 f2\nln [ -s ] f1 ... fn d2\n"); + exit(1); +} + +int link(), symlink(); + +linkit(from, to) + char *from, *to; +{ + char *tail; + int (*linkf)() = sflag ? symlink : link; + + /* is target a directory? */ + if (sflag == 0 && fflag == 0 && stat(from, &stb) >= 0 + && (stb.st_mode&S_IFMT) == S_IFDIR) { + printf("%s is a directory\n", from); + return (1); + } + if (stat(to, &stb) >= 0 && (stb.st_mode&S_IFMT) == S_IFDIR) { + tail = rindex(from, '/'); + if (tail == 0) + tail = from; + else + tail++; + sprintf(name, "%s/%s", to, tail); + to = name; + } + if ((*linkf)(from, to) < 0) { + if (errno == EEXIST || sflag) + perror(to); + else if (access(from, 0) < 0) + perror(from); + else + perror(to); + return (1); + } + return (0); +} diff --git a/src/cmd/login/Makefile b/src/cmd/login/Makefile new file mode 100644 index 0000000..8d8cbce --- /dev/null +++ b/src/cmd/login/Makefile @@ -0,0 +1,51 @@ +# +# 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 redistribution 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. +# +TOPSRC = $(shell cd ../../..; pwd) +include $(TOPSRC)/target.mk + +CFLAGS += -Werror +LIBS := -lutil $(LIBS) + +SRCS = login.c +OBJS = login.o + +all: login + +login: ${OBJS} + ${CC} ${LDFLAGS} -o login.elf ${OBJS} ${LIBS} + ${OBJDUMP} -S login.elf > login.dis + ${SIZE} login.elf + ${ELF2AOUT} login.elf $@ && rm login.elf + +clean: + rm -f *.o *.elf ${MAN} login *.elf *.dis tags *~ + + +cleandir: clean + rm -f ${MAN} tags .depend + +depend: ${SRCS} + mkdep ${CFLAGS} ${SRCS} + +install: all + install -m 4755 login ${DESTDIR}/bin/login + +lint: ${SRCS} + lint ${CFLAGS} ${SRCS} + +tags: ${SRCS} + ctags ${SRCS} diff --git a/src/cmd/login/login.c b/src/cmd/login/login.c new file mode 100644 index 0000000..c8a1de4 --- /dev/null +++ b/src/cmd/login/login.c @@ -0,0 +1,577 @@ +/* + * login [ name ] + * login -h hostname (for telnetd, etc.) + * login -f name (for pre-authenticated login: datakit, xterm, etc.) + * + * Copyright (c) 1980, 1987, 1988 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef KERBEROS +#include +#include +char realm[REALM_SZ]; +int kerror = KSUCCESS, notickets = 1; +#endif + +#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. + */ +int timeout = 300; + +struct passwd *pwd; +int failures; +char term[64], *hostname, *username, *tty; + +struct sgttyb sgttyb; +struct tchars tc = { + CINTR, CQUIT, CSTART, CSTOP, CEOT, CBRK +}; +struct ltchars ltc = { + CSUSP, CDSUSP, CRPRNT, CFLUSH, CWERASE, CLNEXT +}; + +char *months[] = + { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", + "Sep", "Oct", "Nov", "Dec" }; + +void timedout(sig) + int sig; +{ + (void)fprintf(stderr, "Login timed out after %d seconds\n", timeout); + exit(0); +} + +main(argc, argv) + int argc; + char **argv; +{ + extern int errno, optind; + extern char *optarg, **environ; + struct timeval tp; + struct tm *ttp; + struct group *gr; + register int ch; + register char *p; + int ask, fflag, hflag, pflag, cnt; + int quietlog, passwd_req, ioctlval; + char *domain, *salt, *envinit[1], *ttyn, *pp; + char tbuf[MAXPATHLEN + 2], tname[sizeof(_PATH_TTY) + 10]; + char *ctime(), *ttyname(), *stypeof(), *crypt(), *getpass(); + time_t time(); + off_t lseek(); + + (void)signal(SIGALRM, timedout); + (void)alarm((u_int) timeout); + (void)signal(SIGQUIT, SIG_IGN); + (void)signal(SIGINT, SIG_IGN); + (void)setpriority(PRIO_PROCESS, 0, 0); +#ifdef Q_SETUID + (void)quota(Q_SETUID, 0, 0, 0); +#endif + /* + * -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 + */ + (void)gethostname(tbuf, sizeof(tbuf)); + domain = index(tbuf, '.'); + + fflag = hflag = pflag = 0; + passwd_req = 1; + while ((ch = getopt(argc, argv, "fh:p")) != EOF) + switch (ch) { + case 'f': + fflag = 1; + break; + case 'h': + if (getuid()) { + (void)fprintf(stderr, + "login: -h for super-user only.\n"); + exit(1); + } + hflag = 1; + if (domain && (p = index(optarg, '.')) && + strcasecmp(p, domain) == 0) + *p = 0; + hostname = optarg; + break; + case 'p': + pflag = 1; + break; + case '?': + default: + (void)fprintf(stderr, + "usage: login [-fp] [username]\n"); + exit(1); + } + argc -= optind; + argv += optind; + if (*argv) { + username = *argv; + ask = 0; + } else + ask = 1; + + ioctlval = 0; + (void)ioctl(0, TIOCLSET, &ioctlval); + (void)ioctl(0, TIOCNXCL, 0); + (void)fcntl(0, F_SETFL, ioctlval); + (void)ioctl(0, TIOCGETP, &sgttyb); + sgttyb.sg_erase = CERASE; + sgttyb.sg_kill = CKILL; + (void)ioctl(0, TIOCSLTC, <c); + (void)ioctl(0, TIOCSETC, &tc); + (void)ioctl(0, TIOCSETP, &sgttyb); + + for (cnt = getdtablesize(); cnt > 2; cnt--) + close(cnt); + + ttyn = ttyname(0); + if (ttyn == NULL || *ttyn == '\0') { + (void)sprintf(tname, "%s??", _PATH_TTY); + ttyn = tname; + } + if (tty = rindex(ttyn, '/')) + ++tty; + else + tty = ttyn; + + openlog("login", LOG_ODELAY, LOG_AUTH); + + for (cnt = 0;; ask = 1) { + ioctlval = 0; + (void)ioctl(0, TIOCSETD, &ioctlval); + + if (ask) { + fflag = 0; + getloginname(); + } + /* + * 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; +//printf("getpwnam returned username='%s' password='%s'\n", pwd->pw_name, pwd->pw_passwd); + } else { + salt = "xx"; + goto nouser; + } + + /* if user not super-user, check for disabled logins */ + if (pwd == NULL || pwd->pw_uid) + checknologin(); + + /* + * Disallow automatic login to root; if not invoked by + * root, disallow if the uid's differ. + */ + if (fflag && pwd) { + int uid = getuid(); + + passwd_req = pwd->pw_uid == 0 || + (uid && uid != pwd->pw_uid); + } + + /* + * If trying to log in as root, but with insecure terminal, + * refuse the login attempt. + */ + if (pwd->pw_uid == 0 && !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 no pre-authentication and a password exists + * for this user, prompt for one and verify it. + */ + if (!passwd_req || (pwd && !*pwd->pw_passwd)) + break; + +nouser: + setpriority(PRIO_PROCESS, 0, -4); + pp = getpass("Password:"); + p = crypt(pp, salt); + setpriority(PRIO_PROCESS, 0, 0); + +#ifdef KERBEROS + + /* + * If not present in pw file, act as we normally would. + * If we aren't Kerberos-authenticated, try the normal + * pw file for a password. If that's ok, log the user + * in without issueing any tickets. + */ + + if (pwd && !krb_get_lrealm(realm,1)) { + /* + * get TGT for local realm; be careful about uid's + * here for ticket file ownership + */ + (void)setreuid(geteuid(),pwd->pw_uid); + kerror = krb_get_pw_in_tkt(pwd->pw_name, "", realm, + "krbtgt", realm, DEFAULT_TKT_LIFE, pp); + (void)setuid(0); + if (kerror == INTK_OK) { + bzero(pp, strlen(pp)); + notickets = 0; /* user got ticket */ + break; + } + } +#endif +//printf("username='%s' password='%s' encrypted='%s' expected='%s' salt='%s'\n", username, pp, p, pwd->pw_passwd, salt); + (void) bzero(pp, strlen(pp)); + if (pwd && !strcmp(p, pwd->pw_passwd)) + 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); + (void)ioctl(0, TIOCHPCL, (struct sgttyb *)NULL); + sleepexit(1); + } + sleep((u_int)((cnt - 3) * 5)); + } + } + + /* committed to login -- turn off timeout */ + (void)alarm((u_int)0); + + /* paranoia... */ + endpwent(); + +#ifdef Q_SETUID + if (quota(Q_SETUID, pwd->pw_uid, 0, 0) < 0 && errno != EINVAL) { + switch(errno) { + case EUSERS: + (void)fprintf(stderr, + "Too many users logged on already.\nTry again later.\n"); + break; + case EPROCLIM: + (void)fprintf(stderr, + "You have too many processes running.\n"); + break; + default: + perror("quota (Q_SETUID)"); + } + sleepexit(0); + } +#endif + if (chdir(pwd->pw_dir) < 0) { + (void)printf("No 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; + +#ifdef KERBEROS + if (notickets && !quietlog) + (void)printf("Warning: no Kerberos tickets issued\n"); +#endif + + /* nothing else left to fail -- really log in */ + { + struct utmp utmp; + + bzero((char *)&utmp, sizeof(utmp)); + (void)time(&utmp.ut_time); + strncpy(utmp.ut_name, username, sizeof(utmp.ut_name)); + if (hostname) + strncpy(utmp.ut_host, hostname, sizeof(utmp.ut_host)); + strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line)); + login(&utmp); + } + + dolastlog(quietlog); + + if (!hflag) { /* XXX */ + static struct winsize win = { 0, 0, 0, 0 }; + + (void)ioctl(0, TIOCSWINSZ, &win); + } + + (void)chown(ttyn, pwd->pw_uid, + (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid); + (void)chmod(ttyn, 0620); + (void)setgid(pwd->pw_gid); + + initgroups(username, pwd->pw_gid); +#ifdef Q_DOWARN + quota(Q_DOWARN, pwd->pw_uid, (dev_t)-1, 0); +#endif + if (*pwd->pw_shell == '\0') + pwd->pw_shell = _PATH_BSHELL; + /* turn on new line discipline for the csh */ + else if (!strcmp(pwd->pw_shell, _PATH_CSHELL)) { + ioctlval = NTTYDISC; + (void)ioctl(0, TIOCSETD, &ioctlval); + } + + /* destroy environment unless user has requested preservation */ + if (!pflag) + environ = envinit; + (void)setenv("HOME", pwd->pw_dir, 1); + (void)setenv("SHELL", pwd->pw_shell, 1); + if (term[0] == '\0') + strncpy(term, stypeof(tty), sizeof(term)); + (void)setenv("TERM", term, 0); + (void)setenv("USER", pwd->pw_name, 1); + (void)setenv("PATH", _PATH_STDPATH, 0); + + if (tty[sizeof("tty")-1] == 'd') + syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name); + if (pwd->pw_uid == 0) + if (hostname) + syslog(LOG_NOTICE, "ROOT LOGIN ON %s FROM %s", + tty, hostname); + else + syslog(LOG_NOTICE, "ROOT LOGIN ON %s", tty); + + if (!quietlog) { + struct stat st; + + motd(); + (void)sprintf(tbuf, "%s%s", _PATH_MAIL, 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] = '-'; + strcpy(tbuf + 1, (p = rindex(pwd->pw_shell, '/')) ? + p + 1 : pwd->pw_shell); + + if (setlogin(pwd->pw_name) < 0) + fprintf(stderr, "login: setlogin(): %s\n", strerror(errno)); + + /* discard permissions last so can't get killed and drop core */ + (void)setuid(pwd->pw_uid); + + execlp(pwd->pw_shell, tbuf, 0); + (void)fprintf(stderr, "login: no shell: %s\n", strerror(errno)); + exit(0); +} + +getloginname() +{ + register int ch; + register char *p; + static char nbuf[UT_NAMESIZE + 1]; + + for (;;) { + (void)printf("login: "); + for (p = nbuf; (ch = getchar()) != '\n'; ) { + if (ch == EOF) { + badlogin(username); + exit(0); + } + if (p < nbuf + UT_NAMESIZE) + *p++ = ch; + } + if (p > nbuf) + if (nbuf[0] == '-') + (void)fprintf(stderr, + "login names may not start with '-'.\n"); + else { + *p = '\0'; + username = nbuf; + break; + } + } +} + +rootterm(ttyn) + char *ttyn; +{ + struct ttyent *t; + + return((t = getttynam(ttyn)) && t->ty_status&TTY_SECURE); +} + +jmp_buf motdinterrupt; + +void sigint(sig) + int sig; +{ + longjmp(motdinterrupt, 1); +} + +motd() +{ + register int fd, nchars; + sig_t oldint; + char tbuf[BUFSIZ]; + + if ((fd = open(_PATH_MOTD, 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); +} + +checknologin() +{ + register int fd, nchars; + char tbuf[BUFSIZ]; + + 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); + } +} + +dolastlog(quiet) + int quiet; +{ + struct lastlog ll; + int fd; + char *ctime(); + + 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", + sizeof(ll.ll_host), ll.ll_host); + else + (void)printf("on %.*s\n", + sizeof(ll.ll_line), ll.ll_line); + } + (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET); + } + bzero((char *)&ll, sizeof(ll)); + (void)time(&ll.ll_time); + strncpy(ll.ll_line, tty, sizeof(ll.ll_line)); + if (hostname) + strncpy(ll.ll_host, hostname, sizeof(ll.ll_host)); + (void)write(fd, (char *)&ll, sizeof(ll)); + (void)close(fd); + } +} + +badlogin(name) + char *name; +{ + if (failures == 0) + return; + if (hostname) + syslog(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, %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); +} + +getstr(buf, cnt, err) + char *buf, *err; + int cnt; +{ + char ch; + + do { + if (read(0, &ch, sizeof(ch)) != sizeof(ch)) + exit(1); + if (--cnt < 0) { + (void)fprintf(stderr, "%s too long\r\n", err); + sleepexit(1); + } + *buf++ = ch; + } while (ch); +} + +sleepexit(eval) + int eval; +{ + sleep((u_int)5); + exit(eval); +} diff --git a/src/cmd/lorder.sh b/src/cmd/lorder.sh new file mode 100644 index 0000000..37b94ff --- /dev/null +++ b/src/cmd/lorder.sh @@ -0,0 +1,34 @@ +trap "rm -f $$sym?ef; exit" 0 1 2 13 15 +case $# in +0) echo usage: lorder file ... + exit ;; +1) case $1 in + *.o) set $1 $1 + esac +esac +nm -g $* | sed ' + /^$/d + /:$/{ + /\.o:/!d + s/:// + h + s/.*/& &/ + p + d + } + /[TD] /{ + s/.* // + G + s/\n/ / + w '$$symdef' + d + } + s/.* // + G + s/\n/ / + w '$$symref' + d +' +sort $$symdef -o $$symdef +sort $$symref -o $$symref +join $$symref $$symdef | sed 's/[^ ]* *//' diff --git a/src/cmd/ls/Makefile b/src/cmd/ls/Makefile new file mode 100644 index 0000000..823ba74 --- /dev/null +++ b/src/cmd/ls/Makefile @@ -0,0 +1,32 @@ +# +# Public Domain. 12/3/1994 - Steven Schultz +# +TOPSRC = $(shell cd ../../..; pwd) +include $(TOPSRC)/target.mk + +CFLAGS = -O +SRCS = ls.c stat_flags.c +OBJS = ls.o stat_flags.o + +all: ls + +ls: ${OBJS} + ${CC} ${LDFLAGS} -o ls.elf ${OBJS} ${LIBS} + ${OBJDUMP} -S ls.elf > ls.dis + ${SIZE} ls.elf + ${ELF2AOUT} ls.elf $@ && rm ls.elf + +clean: + rm -f *.o *.elf *.dis ls tags *~ + +depend: ${SRCS} + mkdep ${CFLAGS} ${SRCS} + +install: all + install ls ${DESTDIR}/bin/ls + +lint: ${SRCS} + lint -hax ${SRCS} + +tags: ${SRCS} + ctags ${SRCS} diff --git a/src/cmd/ls/ls.c b/src/cmd/ls/ls.c new file mode 100644 index 0000000..f709ed5 --- /dev/null +++ b/src/cmd/ls/ls.c @@ -0,0 +1,695 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +/* + * ls + * + * 4.2bsd version for symbolic links, variable length + * directory entries, block size in the inode, etc. + */ +#include +#include +#include +#include +#include +#include +#include +//#include +#include + +#define kbytes(size) (((size) + 1023) / 1024) + +struct afile { + char ftype; /* file type, e.g. 'd', 'c', 'f' */ + ino_t fnum; /* inode number of file */ + short fmode; /* mode&~S_IFMT, perhaps ISARG */ + u_short fflags; /* st_flags (uappnd, uchg, schg, ...) */ + short fnl; /* number of links */ + uid_t fuid; /* owner id */ + gid_t fgid; /* group id */ + off_t fsize; /* file size */ + long fblks; /* number of blocks used */ + time_t fmtime; /* time (modify or access or create) */ + char *fname; /* file name */ + char *flinkto; /* symbolic link value */ +}; + +#define ISARG 0x8000 /* extra ``mode'' */ + +struct subdirs { + char *sd_name; + struct subdirs *sd_next; +} *subdirs; + +char aflg, dflg, gflg, lflg, sflg, tflg, uflg, iflg, fflg, cflg, rflg = 1; +char oflg, qflg, Aflg, Cflg, Fflg, Lflg, Rflg, usetabs; + +time_t now, sixmonthsago; + +char *dotp = "."; + +struct winsize win; +int twidth; + +struct afile *gstat(); +int fcmp(); +char *cat(), *savestr(); +char *fmtentry(); +char *getname(), *getgroup(); + +char *flags_to_string (unsigned flags, char *def); +unsigned string_to_flags (char **stringp, unsigned *setp, unsigned *clrp); + +main(argc, argv) + int argc; + char *argv[]; +{ + extern int optind; + struct afile *fp0, *fplast; + register struct afile *fp; + struct sgttyb sgbuf; + int ch, i; + time_t time(); + + Aflg = !getuid(); + (void) time(&now); sixmonthsago = now - 6L*30L*24L*60L*60L; now += 60; + twidth = 80; + if (isatty(1)) { + qflg = Cflg = 1; + (void) gtty(1, &sgbuf); + if (ioctl(1, TIOCGWINSZ, &win) != -1) + twidth = (win.ws_col == 0 ? 80 : win.ws_col); + if ((sgbuf.sg_flags & XTABS) != XTABS) + usetabs = 1; + } else + usetabs = 1; + while ((ch = getopt(argc, argv, "1ACLFRacdfgiloqrstu")) != EOF) + switch((char)ch) { +/* + * The -1, -C, and -l options override each other so shell aliasing + * works right. +*/ + case '1': + lflg = 0; + Cflg = 0; break; + case 'C': + lflg = 0; + Cflg = 1; break; + case 'l': + Cflg = 0; + lflg++; break; + case 'A': + Aflg++; break; + case 'L': + Lflg++; break; + case 'F': + Fflg++; break; + case 'R': + Rflg++; break; + case 'a': + aflg++; break; + case 'c': + uflg = 0; /* -c overrides -u */ + cflg++; break; + case 'd': + Rflg = 0; /* -d overrides -R */ + dflg++; break; + case 'f': + fflg++; break; + case 'g': + gflg++; break; + case 'i': + iflg++; break; + case 'o': + oflg++; break; + case 'q': + qflg = 1; break; + case 'r': + rflg = -1; break; + case 's': + sflg++; break; + case 't': + tflg++; break; + case 'u': + cflg = 0; /* -u overrides -c */ + uflg++; break; + case '?': + default: + fputs("usage: ls [ -1ACLFRacdfgiloqrstu ] [ file ]\n", stderr); + exit(1); + } + if (!lflg) + oflg = 0; + if (fflg) { + Aflg++; + aflg++; lflg = 0; sflg = 0; tflg = 0; + } + if (lflg) + Cflg = 0; + argc -= optind; + argv += optind; + if (argc == 0) { + argc++; + argv = &dotp; + } + fp = (struct afile *)calloc((u_int)argc, sizeof (struct afile)); + if (fp == 0) { + fputs("ls: out of memory\n", stderr); + exit(1); + } + fp0 = fp; + for (i = 0; i < argc; i++) { + if (gstat(fp, *argv, 1, (int *)0)) { + fp->fname = *argv; + fp->fmode |= ISARG; + fp++; + } + argv++; + } + fplast = fp; + if (fflg == 0) + qsort(fp0, fplast - fp0, sizeof (struct afile), fcmp); + if (dflg) { + formatf(fp0, fplast); + exit(0); + } + + if (fflg) + fp = fp0; + else { + for (fp = fp0; fp < fplast && fp->ftype != 'd'; fp++) + continue; + formatf(fp0, fp); + } + + if (fp < fplast) { + if (fp > fp0) + putchar('\n'); + for (;;) { + formatd(fp->fname, argc > 1); + while (subdirs) { + struct subdirs *t; + + t = subdirs; subdirs = t->sd_next; + putchar('\n'); + formatd(t->sd_name, 1); + cfree(t->sd_name); + cfree((char *)t); + } + if (++fp == fplast) + break; + putchar('\n'); + } + } + exit(0); +} + +formatd(name, dotitle) + char *name; + int dotitle; +{ + register struct afile *fp; + register struct subdirs *dp; + struct afile *dfp0, *dfplast; + int isadir; + long nkb, getdir(); + + nkb = getdir(name, &dfp0, &dfplast, &isadir); + if (dfp0 == 0) + return; + if (fflg == 0) + qsort(dfp0, dfplast - dfp0, sizeof (struct afile), fcmp); + if (dotitle) + printf("%s%s\n", name, isadir ? ":" : ""); + if (lflg || sflg) + printf("total %ld\n", nkb); + formatf(dfp0, dfplast); + if (Rflg) + for (fp = dfplast - 1; fp >= dfp0; fp--) { + if (fp->ftype != 'd' || + !strcmp(fp->fname, ".") || + !strcmp(fp->fname, "..")) + continue; + dp = (struct subdirs *)malloc(sizeof (struct subdirs)); + dp->sd_name = savestr(cat(name, fp->fname)); + dp->sd_next = subdirs; subdirs = dp; + } + for (fp = dfp0; fp < dfplast; fp++) { + if ((fp->fmode&ISARG) == 0 && fp->fname) + cfree(fp->fname); + if (fp->flinkto) + cfree(fp->flinkto); + } + cfree((char *)dfp0); +} + +long +getdir(dir, pfp0, pfplast, isadir) + char *dir; + struct afile **pfp0, **pfplast; + int *isadir; +{ + register struct afile *fp; + DIR *dirp; + register struct direct *dp; + struct stat st; + long nb; + int nent = 20; + + dirp = opendir(dir); + if (dirp == NULL) { + *pfp0 = *pfplast = NULL; + printf("%s unreadable\n", dir); /* not stderr! */ + return (0); + } + fstat(dirfd(dirp), &st); + if (S_ISDIR(st.st_mode)) + *isadir = 1; + else + *isadir = 0; + fp = *pfp0 = (struct afile *)calloc(nent, sizeof (struct afile)); + *pfplast = *pfp0 + nent; + nb = 0; + while (dp = readdir(dirp)) { + if (dp->d_ino == 0) + continue; + if (aflg == 0 && dp->d_name[0]=='.' && + (Aflg == 0 || dp->d_name[1]==0 || + dp->d_name[1]=='.' && dp->d_name[2]==0)) + continue; + if (gstat(fp, cat(dir, dp->d_name), Fflg+Rflg, &nb) == 0) + continue; + fp->fnum = dp->d_ino; + fp->fname = savestr(dp->d_name); + fp++; + if (fp == *pfplast) { + *pfp0 = (struct afile *)realloc((char *)*pfp0, + 2 * nent * sizeof (struct afile)); + if (*pfp0 == 0) { + fputs("ls: out of memory\n", stderr); + exit(1); + } + fp = *pfp0 + nent; + *pfplast = fp + nent; + nent *= 2; + } + } + closedir(dirp); + *pfplast = fp; + return (kbytes (nb * DEV_BSIZE)); +} + +int stat(), lstat(); + +struct afile * +gstat(fp, file, statarg, pnb) + register struct afile *fp; + char *file; + int statarg; + long *pnb; +{ + int (*statf)() = Lflg ? stat : lstat; + char buf[BUFSIZ]; int cc; + static struct afile azerofile; + + *fp = azerofile; + fp->fmode = 0; + fp->fnum = 0; + fp->ftype = '-'; + if (statarg || sflg || lflg || tflg) { + struct stat stb, stb1; + + if ((*statf)(file, &stb) < 0) { + if (statf == lstat || lstat(file, &stb) < 0) { + fprintf(stderr, "%s not found\n", file); + return (0); + } + } + fp->fblks = stb.st_blocks; + fp->fsize = stb.st_size; + switch (stb.st_mode & S_IFMT) { + + case S_IFDIR: + fp->ftype = 'd'; break; + case S_IFBLK: + fp->ftype = 'b'; fp->fsize = stb.st_rdev; break; + case S_IFCHR: + fp->ftype = 'c'; fp->fsize = stb.st_rdev; break; + case S_IFSOCK: + fp->ftype = 's'; fp->fsize = 0; break; + case S_IFLNK: + fp->ftype = 'l'; + if (lflg) { + cc = readlink(file, buf, BUFSIZ); + if (cc >= 0) { + buf[cc] = 0; + fp->flinkto = savestr(buf); + } + break; + } + if (stat(file, &stb1) < 0) + break; + if ((stb1.st_mode & S_IFMT) == S_IFDIR) { + stb = stb1; + fp->ftype = 'd'; + fp->fsize = stb.st_size; + fp->fblks = stb.st_blocks; + } + break; + } + fp->fnum = stb.st_ino; + fp->fmode = stb.st_mode & ~S_IFMT; + fp->fflags = stb.st_flags; + fp->fnl = stb.st_nlink; + fp->fuid = stb.st_uid; + fp->fgid = stb.st_gid; + if (uflg) + fp->fmtime = stb.st_atime; + else if (cflg) + fp->fmtime = stb.st_ctime; + else + fp->fmtime = stb.st_mtime; + if (pnb) + *pnb += stb.st_blocks; + } + return (fp); +} + +formatf(fp0, fplast) + struct afile *fp0, *fplast; +{ + register struct afile *fp; + register int i, j, w; + int width = 0, nentry = fplast - fp0; + int columns, lines, maxflags; + char *cp; + + if (fp0 == fplast) + return; + maxflags = 0; + if (oflg) { + for (fp = fp0; fp < fplast; fp++) + { + i = strlen (flags_to_string (fp->fflags, "-")); + if (i > maxflags) + maxflags = i; + } + } + if (lflg || Cflg == 0) + columns = 1; + else { + for (fp = fp0; fp < fplast; fp++) { + int len = strlen(fmtentry(fp, maxflags)); + + if (len > width) + width = len; + } + if (usetabs) + width = (width + 8) &~ 7; + else + width += 2; + columns = twidth / width; + if (columns == 0) + columns = 1; + } + lines = (nentry + columns - 1) / columns; + for (i = 0; i < lines; i++) { + for (j = 0; j < columns; j++) { + fp = fp0 + j * lines + i; + cp = fmtentry(fp, maxflags); + fputs(cp, stdout); + if (fp + lines >= fplast) { + putchar('\n'); + break; + } + w = strlen(cp); + while (w < width) + if (usetabs) { + w = (w + 8) &~ 7; + putchar('\t'); + } else { + w++; + putchar(' '); + } + } + } +} + +fcmp(f1, f2) + register struct afile *f1, *f2; +{ + + if (dflg == 0 && fflg == 0) { + if ((f1->fmode&ISARG) && f1->ftype == 'd') { + if ((f2->fmode&ISARG) == 0 || f2->ftype != 'd') + return (1); + } else { + if ((f2->fmode&ISARG) && f2->ftype == 'd') + return (-1); + } + } + if (tflg) { + if (f2->fmtime == f1->fmtime) + return (0); + if (f2->fmtime > f1->fmtime) + return (rflg); + return (-rflg); + } + return (rflg * strcmp(f1->fname, f2->fname)); +} + +char * +cat(dir, file) + char *dir, *file; +{ + static char dfile[BUFSIZ]; + register int dlen; + + if ((dlen = strlen(dir))+1+strlen(file)+1 > BUFSIZ) { + fputs("ls: filename too long\n", stderr); + exit(1); + } + if (!dir[0] || dir[0] == '.' && !dir[1]) + return(strcpy(dfile, file)); + (void) strcpy(dfile, dir); + if (dir[dlen - 1] != '/' && *file != '/') + dfile[dlen++] = '/'; + (void) strcpy(dfile + dlen, file); + return (dfile); +} + +char * +savestr(str) + char *str; +{ + register char *cp = strdup(str); + + if (cp == NULL) { + fputs("ls: out of memory\n", stderr); + exit(1); + } + return(cp); +} + +char *fmtinum(), *fmtsize(), *fmtlstuff(), *fmtmode(); + +char * +fmtentry(fp, maxflags) + register struct afile *fp; + int maxflags; +{ + static char fmtres[BUFSIZ]; + register char *cp, *dp; + + (void) sprintf(fmtres, "%s%s%s", + iflg ? fmtinum(fp) : "", + sflg ? fmtsize(fp) : "", + lflg ? fmtlstuff(fp, maxflags) : ""); + dp = &fmtres[strlen(fmtres)]; + for (cp = fp->fname; *cp; cp++) + if (qflg && (*cp < ' ' || *cp >= 0177)) + *dp++ = '?'; + else + *dp++ = *cp; + if (Fflg) { + if (fp->ftype == 'd') + *dp++ = '/'; + else if (fp->ftype == 'l') + *dp++ = '@'; + else if (fp->ftype == 's') + *dp++ = '='; + else if (fp->fmode & 0111) + *dp++ = '*'; + } + if (lflg && fp->flinkto) { + (void) strcpy(dp, " -> "); dp += 4; + for (cp = fp->flinkto; *cp; cp++) + if (qflg && (*cp < ' ' || *cp >= 0177)) + *dp++ = '?'; + else + *dp++ = *cp; + } + *dp++ = 0; + return (fmtres); +} + +char * +fmtinum(p) + register struct afile *p; +{ + static char inumbuf[8]; + + (void) sprintf(inumbuf, "%6u ", p->fnum); + return (inumbuf); +} + +char * +fmtsize(p) + register struct afile *p; +{ + static char sizebuf[16]; + + (void) sprintf (sizebuf, "%4ld ", kbytes (p->fblks * DEV_BSIZE)); + return (sizebuf); +} + +char * +fmtlstuff(p, maxflags) + register struct afile *p; + int maxflags; +{ + static char lstuffbuf[256]; + char gname[32], uname[32], fsize[32], ftime[32], fflags[64]; + register char *lp = lstuffbuf; + + /* type mode uname gname fsize ftime */ +/* get uname */ + { char *cp = getname(p->fuid); + if (cp) + (void) sprintf(uname, "%-9.9s", cp); + else + (void) sprintf(uname, "%-9u", p->fuid); + } +/* get gname */ + if (gflg) { + char *cp = getgroup(p->fgid); + if (cp) + (void) sprintf(gname, "%-9.9s", cp); + else + (void) sprintf(gname, "%-9u", p->fgid); + } +/* get flags */ + if (oflg) + (void) sprintf(fflags, "%-*s ", maxflags, + flags_to_string(p->fflags, "-")); +/* get fsize */ + if (p->ftype == 'b' || p->ftype == 'c') + (void) sprintf(fsize, "%3d,%4d", + major(p->fsize), minor(p->fsize)); + else if (p->ftype == 's') + (void) sprintf(fsize, "%8ld", 0L); + else + (void) sprintf(fsize, "%8ld", p->fsize); +/* get ftime */ + { char *cp = ctime(&p->fmtime); + if ((p->fmtime < sixmonthsago) || (p->fmtime > now)) + (void) sprintf(ftime, " %-7.7s %-4.4s ", cp+4, cp+20); + else + (void) sprintf(ftime, " %-12.12s ", cp+4); + } +/* splat */ + *lp++ = p->ftype; + lp = fmtmode(lp, p->fmode); + (void) sprintf(lp, "%3d %s%s%s%s%s", + p->fnl, uname, gflg ? gname : "", oflg ? fflags : "", fsize, ftime); + return (lstuffbuf); +} + +int m1[] = { 1, S_IREAD>>0, 'r', '-' }; +int m2[] = { 1, S_IWRITE>>0, 'w', '-' }; +int m3[] = { 3, S_ISUID|(S_IEXEC>>0), 's', S_ISUID, 'S', S_IEXEC>>0, 'x', '-' }; +int m4[] = { 1, S_IREAD>>3, 'r', '-' }; +int m5[] = { 1, S_IWRITE>>3, 'w', '-' }; +int m6[] = { 3, S_ISGID|(S_IEXEC>>3), 's', S_ISGID, 'S', S_IEXEC>>3, 'x', '-' }; +int m7[] = { 1, S_IREAD>>6, 'r', '-' }; +int m8[] = { 1, S_IWRITE>>6, 'w', '-' }; +int m9[] = { 3, S_ISVTX|(S_IEXEC>>6), 't', S_ISVTX, 'T', S_IEXEC>>6, 'x', '-' }; + +int *m[] = { m1, m2, m3, m4, m5, m6, m7, m8, m9}; + +char * +fmtmode(lp, flags) + char *lp; + register int flags; +{ + int **mp; + + for (mp = &m[0]; mp < &m[sizeof(m)/sizeof(m[0])]; ) { + register int *pairp = *mp++; + register int n = *pairp++; + + while (--n >= 0 && (flags&*pairp) != *pairp) + pairp += 2; + *lp++ = pairp[n>=0]; + } + return (lp); +} + +/* rest should be done with nameserver or database */ + +#include +#include +#include + +struct utmp utmp; +#define NMAX (sizeof (utmp.ut_name)) +#define SCPYN(a, b) strncpy(a, b, NMAX) + +#define NCACHE 64 /* power of 2 */ +#define CAMASK NCACHE - 1 + +char * +getname(uid) + uid_t uid; +{ + static struct ncache { + uid_t uid; + char name[NMAX+1]; + } c_uid[NCACHE]; + register struct passwd *pw; + register struct ncache *cp; + + setpassent(1); + cp = c_uid + (uid & CAMASK); + if (cp->uid == uid && *cp->name) + return(cp->name); + if (!(pw = getpwuid(uid))) + return((char *)0); + cp->uid = uid; + SCPYN(cp->name, pw->pw_name); + return(cp->name); +} + +char * +getgroup(gid) + gid_t gid; +{ + static struct ncache { + gid_t gid; + char name[NMAX+1]; + } c_gid[NCACHE]; + register struct group *gr; + register struct ncache *cp; + + cp = c_gid + (gid & CAMASK); + if (cp->gid == gid && *cp->name) + return(cp->name); + if (!(gr = getgrgid(gid))) + return((char *)0); + cp->gid = gid; + SCPYN(cp->name, gr->gr_name); + return(cp->name); +} diff --git a/src/cmd/ls/stat_flags.c b/src/cmd/ls/stat_flags.c new file mode 100644 index 0000000..c28f0d3 --- /dev/null +++ b/src/cmd/ls/stat_flags.c @@ -0,0 +1,148 @@ +/*- + * 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. + */ + +/* + * Modified from the 4.4-Lite version for 2.11BSD. + */ +#include +#include +#include +#include + +#define SAPPEND(s) { \ + if (prefix != NULL) \ + (void)strcat(string, prefix); \ + (void)strcat(string, s); \ + prefix = ","; \ +} + +/* + * flags_to_string -- + * Convert stat flags to a comma-separated string. If no flags + * are set, return the default string. + */ +char * +flags_to_string (flags, def) + register unsigned flags; + char *def; +{ + static char string[64]; + register char *prefix; + + string[0] = '\0'; + prefix = NULL; + if (flags & UF_APPEND) + SAPPEND("uappnd"); + if (flags & UF_IMMUTABLE) + SAPPEND("uchg"); + if (flags & UF_NODUMP) + SAPPEND("nodump"); + if (flags & SF_APPEND) + SAPPEND("sappnd"); + if (flags & SF_ARCHIVED) + SAPPEND("arch"); + if (flags & SF_IMMUTABLE) + SAPPEND("schg"); + return (prefix == NULL && def != NULL ? def : string); +} + +#define TEST(a, b, f) { \ + if (! memcmp(a, b, sizeof(b))) { \ + if (clear) { \ + if (clrp) \ + *clrp |= (f); \ + } else if (setp) \ + *setp |= (f); \ + break; \ + } \ +} + +/* + * string_to_flags -- + * Take string of arguments and return stat flags. Return 0 on + * success, 1 on failure. On failure, stringp is set to point + * to the offending token. + */ +unsigned +string_to_flags (stringp, setp, clrp) + char **stringp; + register unsigned *setp, *clrp; +{ + int clear; + char *string; + register char *p; + + if (setp) + *setp = 0; + if (clrp) + *clrp = 0; + string = *stringp; + while ((p = strsep(&string, "\t ,")) != NULL) { + *stringp = p; + if (*p == '\0') + continue; + if (p[0] == 'n' && p[1] == 'o') { + clear = 1; + p += 2; + } + else + clear = 0; /* This was done only once on entry! */ + switch (p[0]) { + case 'a': + TEST(p, "arch", SF_ARCHIVED); + TEST(p, "archived", SF_ARCHIVED); + return (1); + case 'd': + clear = !clear; + TEST(p, "dump", UF_NODUMP); + return (1); + case 's': + TEST(p, "sappnd", SF_APPEND); + TEST(p, "sappend", SF_APPEND); + TEST(p, "schg", SF_IMMUTABLE); + TEST(p, "schange", SF_IMMUTABLE); + TEST(p, "simmutable", SF_IMMUTABLE); + return (1); + case 'u': + TEST(p, "uappnd", UF_APPEND); + TEST(p, "uappend", UF_APPEND); + TEST(p, "uchg", UF_IMMUTABLE); + TEST(p, "uchange", UF_IMMUTABLE); + TEST(p, "uimmutable", UF_IMMUTABLE); + /* FALLTHROUGH */ + default: + return (1); + } + } + return (0); +} diff --git a/src/cmd/m4/Makefile b/src/cmd/m4/Makefile new file mode 100644 index 0000000..70ae4d6 --- /dev/null +++ b/src/cmd/m4/Makefile @@ -0,0 +1,28 @@ +# @(#)Makefile 1.0 (2.11BSD GTE) 4/5/94 + +DEFS= -DEXTENDED -I. +CFLAGS= -O ${DEFS} +DESTDIR= +SEPFLAG= -i +SRCS= eval.c expr.c look.c main.c misc.c +OBJS= eval.o expr.o look.o main.o misc.o + +all: m4 tags + +m4: ${OBJS} + cc ${SEPFLAG} -o m4 ${OBJS} + +install: all + install -s -m 755 m4 ${DESTDIR}/usr/bin/m4 + +lint: + lint -hax ${DEFS} ${SRCS} + +tags: + ctags -t *.h ${SRCS} + +clean: + -rm -f *.o m4 core + +depend: ${SRCS} + mkdep -p ${CFLAGS} ${SRCS} diff --git a/src/cmd/m4/NOTES b/src/cmd/m4/NOTES new file mode 100644 index 0000000..d60f80e --- /dev/null +++ b/src/cmd/m4/NOTES @@ -0,0 +1,64 @@ +m4 - macro processor + +PD m4 is based on the macro tool distributed with the software +tools (VOS) package, and described in the "SOFTWARE TOOLS" and +"SOFTWARE TOOLS IN PASCAL" books. It has been expanded to include +most of the command set of SysV m4, the standard UN*X macro processor. + +Since both PD m4 and UN*X m4 are based on SOFTWARE TOOLS macro, +there may be certain implementation similarities between +the two. The PD m4 was produced without ANY references to m4 +sources. + +written by: Ozan S. Yigit + +References: + + Software Tools distribution: macro + + Kernighan, Brian W. and P. J. Plauger, SOFTWARE + TOOLS IN PASCAL, Addison-Wesley, Mass. 1981 + + Kernighan, Brian W. and P. J. Plauger, SOFTWARE + TOOLS, Addison-Wesley, Mass. 1976 + + Kernighan, Brian W. and Dennis M. Ritchie, + THE M4 MACRO PROCESSOR, Unix Programmer's Manual, + Seventh Edition, Vol. 2, Bell Telephone Labs, 1979 + + System V man page for M4 + + +Implementation Notes: + +[1] PD m4 uses a different (and simpler) stack mechanism than the one + described in Software Tools and Software Tools in Pascal books. + The triple stack thing is replaced with a single stack containing + the call frames and the arguments. Each frame is back-linked to a + previous stack frame, which enables us to rewind the stack after + each nested call is completed. Each argument is a character pointer + to the beginning of the argument string within the string space. + The only exceptions to this are (*) arg 0 and arg 1, which are + the macro definition and macro name strings, stored dynamically + for the hash table. + + . . + | . | <-- sp | . | + +-------+ +-----+ + | arg 3 ------------------------------->| str | + +-------+ | . | + | arg 2 --------------+ . + +-------+ | + * | | | + +-------+ | +-----+ + | plev | <-- fp +---------------->| str | + +-------+ | . | + | type | . + +-------+ + | prcf -----------+ plev: paren level + +-------+ | type: call type + | . | | prcf: prev. call frame + . | + +-------+ | + | <----------+ + +-------+ diff --git a/src/cmd/m4/TEST/ack.m4 b/src/cmd/m4/TEST/ack.m4 new file mode 100644 index 0000000..de914bd --- /dev/null +++ b/src/cmd/m4/TEST/ack.m4 @@ -0,0 +1,40 @@ +# +# Copyright (c) 1989, 1993 +# The Regents of the University of California. All rights reserved. +# +# 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. +# +# @(#)ack.m4 8.1 (Berkeley) 6/6/93 +# + +define(ack, `ifelse($1,0,incr($2),$2,0,`ack(DECR($1),1)', +`ack(DECR($1), ack($1,DECR($2)))')') diff --git a/src/cmd/m4/TEST/hanoi.m4 b/src/cmd/m4/TEST/hanoi.m4 new file mode 100644 index 0000000..9371b34 --- /dev/null +++ b/src/cmd/m4/TEST/hanoi.m4 @@ -0,0 +1,45 @@ +# +# Copyright (c) 1989, 1993 +# The Regents of the University of California. All rights reserved. +# +# 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. +# +# @(#)hanoi.m4 8.1 (Berkeley) 6/6/93 +# + +define(hanoi, `trans(A, B, C, $1)') + +define(moved,`move disk from $1 to $2 +') + +define(trans, `ifelse($4,1,`moved($1,$2)', + `trans($1,$3,$2,DECR($4))moved($1,$2)trans($3,$2,$1,DECR($4))')') diff --git a/src/cmd/m4/TEST/hash.m4 b/src/cmd/m4/TEST/hash.m4 new file mode 100644 index 0000000..85d5aa8 --- /dev/null +++ b/src/cmd/m4/TEST/hash.m4 @@ -0,0 +1,55 @@ +# +# Copyright (c) 1989, 1993 +# The Regents of the University of California. All rights reserved. +# +# 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. +# +# @(#)hash.m4 8.1 (Berkeley) 6/6/93 +# + +dnl This probably will not run on any m4 that cannot +dnl handle char constants in eval. +dnl +changequote(<,>) define(HASHVAL,99) dnl +define(hash,) dnl +define(str, + ,1),)>) + >) dnl +define(KEYWORD,<$1,hash($1),>) dnl +define(TSTART, +) dnl +define(TEND,< "",0 +};>) dnl diff --git a/src/cmd/m4/TEST/sqroot.m4 b/src/cmd/m4/TEST/sqroot.m4 new file mode 100644 index 0000000..3c7501f --- /dev/null +++ b/src/cmd/m4/TEST/sqroot.m4 @@ -0,0 +1,45 @@ +# +# Copyright (c) 1989, 1993 +# The Regents of the University of California. All rights reserved. +# +# 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. +# +# @(#)sqroot.m4 8.1 (Berkeley) 6/6/93 +# + +define(square_root, + `ifelse(eval($1<0),1,negative-square-root, + `square_root_aux($1, 1, eval(($1+1)/2))')') +define(square_root_aux, + `ifelse($3, $2, $3, + $3, eval($1/$2), $3, + `square_root_aux($1, $3, eval(($3+($1/$3))/2))')') diff --git a/src/cmd/m4/TEST/string.m4 b/src/cmd/m4/TEST/string.m4 new file mode 100644 index 0000000..bff741a --- /dev/null +++ b/src/cmd/m4/TEST/string.m4 @@ -0,0 +1,45 @@ +# +# Copyright (c) 1989, 1993 +# The Regents of the University of California. All rights reserved. +# +# 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. +# +# @(#)string.m4 8.1 (Berkeley) 6/6/93 +# + +define(string,`integer $1(len(substr($2,1))) +str($1,substr($2,1),0) +data $1(len(substr($2,1)))/EOS/ +') + +define(str,`ifelse($2,",,data $1(incr($3))/`LET'substr($2,0,1)/ +`str($1,substr($2,1),incr($3))')') diff --git a/src/cmd/m4/TEST/test.m4 b/src/cmd/m4/TEST/test.m4 new file mode 100644 index 0000000..df8b78c --- /dev/null +++ b/src/cmd/m4/TEST/test.m4 @@ -0,0 +1,243 @@ +# +# Copyright (c) 1989, 1993 +# The Regents of the University of California. All rights reserved. +# +# 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. +# +# @(#)test.m4 8.1 (Berkeley) 6/6/93 +# + +# test file for mp (not comprehensive) +# +# v7 m4 does not have `decr'. +# +define(DECR,`eval($1-1)') +# +# include string macros +# +include(string.m4) +# +# create some fortrash strings for an even uglier language +# +string(TEXT, "text") +string(DATA, "data") +string(BEGIN, "begin") +string(END, "end") +string(IF, "if") +string(THEN, "then") +string(ELSE, "else") +string(CASE, "case") +string(REPEAT, "repeat") +string(WHILE, "while") +string(DEFAULT, "default") +string(UNTIL, "until") +string(FUNCTION, "function") +string(PROCEDURE, "procedure") +string(EXTERNAL, "external") +string(FORWARD, "forward") +string(TYPE, "type") +string(VAR, "var") +string(CONST, "const") +string(PROGRAM, "program") +string(INPUT, "input") +string(OUTPUT, "output") +# +divert(2) +diversion #1 +divert(3) +diversion #2 +divert(4) +diversion #3 +divert(5) +diversion #4 +divert(0) +define(abc,xxx) +ifdef(`abc',defined,undefined) +# +# v7 m4 does this wrong. The right output is +# this is A vEry lon sEntEnCE +# see m4 documentation for translit. +# +translit(`this is a very long sentence', abcdefg, ABCDEF) +# +# include towers-of-hanoi +# +include(hanoi.m4) +# +# some reasonable set of disks +# +hanoi(6) +# +# include ackermann's function +# +include(ack.m4) +# +# something like (3,3) will blow away un*x m4. +# +ack(2,3) +# +# include a square_root function for fixed nums +# +include(sqroot.m4) +# +# some square roots. +# +square_root(15) +square_root(100) +square_root(-4) +square_root(21372) +# +# some textual material for enjoyment. +# +[taken from the 'Clemson University Computer Newsletter', + September 1981, pp. 6-7] + +I am a wizard in the magical Kingdom of Transformation and I +slay dragons for a living. Actually, I am a systems programmer. +One of the problems with systems programming is explaining to +non-computer enthusiasts what that is. All of the terms I use to +describe my job are totally meaningless to them. Usually my response +to questions about my work is to say as little as possible. For +instance, if someone asks what happened at work this week, I say +"Nothing much" and then I change the subject. + +With the assistance of my brother, a mechanical engineer, I have devised +an analogy that everyone can understand. The analogy describes the +"Kingdom of Transformation" where travelers wander and are magically +transformed. This kingdom is the computer and the travelers are information. +The purpose of the computer is to change information to a more meaningful +forma. The law of conservation applies here: The computer never creates +and never intentionally destroys data. With no further ado, let us travel +to the Kingdom of Transformation: + +In a land far, far away, there is a magical kingdom called the Kingdom of +Transformation. A king rules over this land and employs a Council of +Wizardry. The main purpose of this kingdom is to provide a way for +neighboring kingdoms to transform citizens into more useful citizens. This +is done by allowing the citizens to enter the kingdom at one of its ports +and to travel any of the many routes in the kingdom. They are magically +transformed along the way. The income of the Kingdom of Transformation +comes from the many toll roads within its boundaries. + +The Kingdom of Transformation was created when several kingdoms got +together and discovered a mutual need for new talents and abilities for +citizens. They employed CTK, Inc. (Creators of Transformation, Inc.) to +create this kingdom. CTK designed the country, its transportation routes, +and its laws of transformation, and created the major highway system. + +Hazards +======= + +Because magic is not truly controllable, CTK invariably, but unknowingly, +creates dragons. Dragons are huge fire-breathing beasts which sometimes +injure or kill travelers. Fortunately, they do not travel, but always +remain near their den. + +Other hazards also exist which are potentially harmful. As the roads +become older and more weatherbeaten, pot-holes will develop, trees will +fall on travelers, etc. CTK maintenance men are called to fix these +problems. + +Wizards +======= + +The wizards play a major role in creating and maintaining the kingdom but +get little credit for their work because it is performed secretly. The +wizards do not wan the workers or travelers to learn their incantations +because many laws would be broken and chaos would result. + +CTK's grand design is always general enough to be applicable in many +different situations. As a result, it is often difficult to use. The +first duty of the wizards is to tailor the transformation laws so as to be +more beneficial and easier to use in their particular environment. + +After creation of the kingdom, a major duty of the wizards is to search for +and kill dragons. If travelers do not return on time or if they return +injured, the ruler of the country contacts the wizards. If the wizards +determine that the injury or death occurred due to the traveler's +negligence, they provide the traveler's country with additional warnings. +If not, they must determine if the cause was a road hazard or a dragon. If +the suspect a road hazard, they call in a CTK maintenance man to locate the +hazard and to eliminate it, as in repairing the pothole in the road. If +they think that cause was a dragon, then they must find and slay it. + +The most difficult part of eliminating a dragon is finding it. Sometimes +the wizard magically knows where the dragon's lair it, but often the wizard +must send another traveler along the same route and watch to see where he +disappears. This sounds like a failsafe method for finding dragons (and a +suicide mission for thr traveler) but the second traveler does not always +disappear. Some dragons eat any traveler who comes too close; others are +very picky. + +The wizards may call in CTK who designed the highway system and +transformation laws to help devise a way to locate the dragon. CTK also +helps provide the right spell or incantation to slay the dragon. (There is +no general spell to slay dragons; each dragon must be eliminated with a +different spell.) + +Because neither CTK nor wizards are perfect, spells to not always work +correctly. At best, nothing happens when the wrong spell is uttered. At +worst, the dragon becomes a much larger dragon or multiplies into several +smaller ones. In either case, new spells must be found. + +If all existing dragons are quiet (i.e. have eaten sufficiently), wizards +have time to do other things. They hide in castles and practice spells and +incatations. They also devise shortcuts for travelers and new laws of +transformation. + +Changes in the Kingdom +====================== + +As new transformation kingdoms are created and old ones are maintained, +CTK, Inc. is constantly learning new things. It learns ways to avoid +creating some of the dragons that they have previously created. It also +discovers new and better laws of transformation. As a result, CTK will +periodically create a new grand design which is far better than the old. +The wizards determine when is a good time to implement this new design. +This is when the tourist season is slow or when no important travelers +(VIPs) are to arrive. The kingdom must be closed for the actual +implementation and is leter reopened as a new and better place to go. + +A final question you might ask is what happens when the number of tourists +becomes too great for the kingdom to handle in a reasonable period of time +(i.e., the tourist lines at the ports are too long). The Kingdom of +Transformation has three options: (1) shorten the paths that a tourist must +travel, or (2) convince CTK to develop a faster breed of horses so that the +travelers can finish sooner, or (3) annex more territories so that the +kingdom can handle more travelers. + +Thus ends the story of the Kingdom of Transformation. I hope this has +explained my job to you: I slay dragons for a living. + +# +#should do an automatic undivert.. +# diff --git a/src/cmd/m4/eval.c b/src/cmd/m4/eval.c new file mode 100644 index 0000000..1dca907 --- /dev/null +++ b/src/cmd/m4/eval.c @@ -0,0 +1,787 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Ozan Yigit at York 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. + */ + +#if !defined(lint) && defined(DOSCCS) +static char sccsid[] = "@(#)eval.c 8.1 (Berkeley) 6/6/93"; +#endif + +/* + * eval.c + * Facility: m4 macro processor + * by: oz + */ + +#include +#include +#include +#include +#include "mdef.h" +#include "stdd.h" +#include "extern.h" +#include "pathnames.h" + +/* + * eval - evaluate built-in macros. + * argc - number of elements in argv. + * argv - element vector : + * argv[0] = definition of a user + * macro or nil if built-in. + * argv[1] = name of the macro or + * built-in. + * argv[2] = parameters to user-defined + * . macro or built-in. + * . + * + * Note that the minimum value for argc is 3. A call in the form + * of macro-or-builtin() will result in: + * argv[0] = nullstr + * argv[1] = macro-or-builtin + * argv[2] = nullstr + */ + +void +eval(argv, argc, td) +register char *argv[]; +register int argc; +register int td; +{ + register int c, n; + static int sysval = 0; + +#ifdef DEBUG + printf("argc = %d\n", argc); + for (n = 0; n < argc; n++) + printf("argv[%d] = %s\n", n, argv[n]); +#endif + /* + * if argc == 3 and argv[2] is null, then we + * have macro-or-builtin() type call. We adjust + * argc to avoid further checking.. + */ + if (argc == 3 && !*(argv[2])) + argc--; + + switch (td & ~STATIC) { + + case DEFITYPE: + if (argc > 2) + dodefine(argv[2], (argc > 3) ? argv[3] : null); + break; + + case PUSDTYPE: + if (argc > 2) + dopushdef(argv[2], (argc > 3) ? argv[3] : null); + break; + + case DUMPTYPE: + dodump(argv, argc); + break; + + case EXPRTYPE: + /* + * doexpr - evaluate arithmetic + * expression + */ + if (argc > 2) + pbnum(expr(argv[2])); + break; + + case IFELTYPE: + if (argc > 4) + doifelse(argv, argc); + break; + + case IFDFTYPE: + /* + * doifdef - select one of two + * alternatives based on the existence of + * another definition + */ + if (argc > 3) { + if (lookup(argv[2]) != nil) + pbstr(argv[3]); + else if (argc > 4) + pbstr(argv[4]); + } + break; + + case LENGTYPE: + /* + * dolen - find the length of the + * argument + */ + if (argc > 2) + pbnum((argc > 2) ? strlen(argv[2]) : 0); + break; + + case INCRTYPE: + /* + * doincr - increment the value of the + * argument + */ + if (argc > 2) + pbnum(atoi(argv[2]) + 1); + break; + + case DECRTYPE: + /* + * dodecr - decrement the value of the + * argument + */ + if (argc > 2) + pbnum(atoi(argv[2]) - 1); + break; + + case SYSCTYPE: + /* + * dosys - execute system command + */ + if (argc > 2) + sysval = system(argv[2]); + break; + + case SYSVTYPE: + /* + * dosysval - return value of the last + * system call. + * + */ + pbnum(sysval); + break; + + case INCLTYPE: + if (argc > 2) + if (!doincl(argv[2])) + oops("%s: %s", argv[2], strerror(errno)); + break; + + case SINCTYPE: + if (argc > 2) + (void) doincl(argv[2]); + break; +#ifdef EXTENDED + case PASTTYPE: + if (argc > 2) + if (!dopaste(argv[2])) + oops("%s: %s", argv[2], strerror(errno)); + break; + + case SPASTYPE: + if (argc > 2) + (void) dopaste(argv[2]); + break; +#endif + case CHNQTYPE: + dochq(argv, argc); + break; + + case CHNCTYPE: + dochc(argv, argc); + break; + + case SUBSTYPE: + /* + * dosub - select substring + * + */ + if (argc > 3) + dosub(argv, argc); + break; + + case SHIFTYPE: + /* + * doshift - push back all arguments + * except the first one (i.e. skip + * argv[2]) + */ + if (argc > 3) { + for (n = argc - 1; n > 3; n--) { + putback(rquote); + pbstr(argv[n]); + putback(lquote); + putback(','); + } + putback(rquote); + pbstr(argv[3]); + putback(lquote); + } + break; + + case DIVRTYPE: + if (argc > 2 && (n = atoi(argv[2])) != 0) + dodiv(n); + else { + active = stdout; + oindex = 0; + } + break; + + case UNDVTYPE: + doundiv(argv, argc); + break; + + case DIVNTYPE: + /* + * dodivnum - return the number of + * current output diversion + */ + pbnum(oindex); + break; + + case UNDFTYPE: + /* + * doundefine - undefine a previously + * defined macro(s) or m4 keyword(s). + */ + if (argc > 2) + for (n = 2; n < argc; n++) + remhash(argv[n], ALL); + break; + + case POPDTYPE: + /* + * dopopdef - remove the topmost + * definitions of macro(s) or m4 + * keyword(s). + */ + if (argc > 2) + for (n = 2; n < argc; n++) + remhash(argv[n], TOP); + break; + + case MKTMTYPE: + /* + * dotemp - create a temporary file + */ + if (argc > 2) + pbstr(mktemp(argv[2])); + break; + + case TRNLTYPE: + /* + * dotranslit - replace all characters in + * the source string that appears in the + * "from" string with the corresponding + * characters in the "to" string. + */ + if (argc > 3) { + char temp[MAXTOK]; + if (argc > 4) + map(temp, argv[2], argv[3], argv[4]); + else + map(temp, argv[2], argv[3], null); + pbstr(temp); + } + else if (argc > 2) + pbstr(argv[2]); + break; + + case INDXTYPE: + /* + * doindex - find the index of the second + * argument string in the first argument + * string. -1 if not present. + */ + pbnum((argc > 3) ? indx(argv[2], argv[3]) : -1); + break; + + case ERRPTYPE: + /* + * doerrp - print the arguments to stderr + * file + */ + if (argc > 2) { + for (n = 2; n < argc; n++) + fprintf(stderr, "%s ", argv[n]); + fprintf(stderr, "\n"); + } + break; + + case DNLNTYPE: + /* + * dodnl - eat-up-to and including + * newline + */ + while ((c = gpbc()) != '\n' && c != EOF) + ; + break; + + case M4WRTYPE: + /* + * dom4wrap - set up for + * wrap-up/wind-down activity + */ + m4wraps = (argc > 2) ? xstrdup(argv[2]) : null; + break; + + case EXITTYPE: + /* + * doexit - immediate exit from m4. + */ + exit((argc > 2) ? atoi(argv[2]) : 0); + break; + + case DEFNTYPE: + if (argc > 2) + for (n = 2; n < argc; n++) + dodefn(argv[n]); + break; + + default: + oops("%s: major botch.", "eval"); + break; + } +} + +char *dumpfmt = "`%s'\t`%s'\n"; /* format string for dumpdef */ + +/* + * expand - user-defined macro expansion + */ +void +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); + putback('$'); + break; + } + p--; + } + p--; + } + if (p == t) /* do last character */ + putback(*p); +} + +/* + * dodefine - install definition in the table + */ +void +dodefine(name, defn) +register char *name; +register char *defn; +{ + register ndptr p; + + if (!*name) + oops("null definition."); + if (STREQ(name, defn)) + oops("%s: recursive definition.", name); + if ((p = lookup(name)) == nil) + p = addent(name); + else if (p->defn != null) + free((char *) p->defn); + if (!*defn) + p->defn = null; + else + p->defn = xstrdup(defn); + p->type = MACRTYPE; +} + +/* + * dodefn - push back a quoted definition of + * the given name. + */ +void +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. + */ +void +dopushdef(name, defn) +register char *name; +register char *defn; +{ + register ndptr p; + + if (!*name) + oops("null definition"); + if (STREQ(name, defn)) + oops("%s: recursive definition.", name); + p = addent(name); + if (!*defn) + p->defn = null; + else + p->defn = xstrdup(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. + */ +void +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. + */ +void +doifelse(argv, argc) +register char *argv[]; +register int argc; +{ + cycle { + if (STREQ(argv[2], argv[3])) + 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. + */ +int +doincl(ifile) +char *ifile; +{ + if (ilevel + 1 == MAXINP) + oops("too many include files."); + if ((infile[ilevel + 1] = fopen(ifile, "r")) != NULL) { + ilevel++; + bbase[ilevel] = bufbase = bp; + return (1); + } + else + return (0); +} + +#ifdef EXTENDED +/* + * dopaste - include a given file without any + * macro processing. + */ +int +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 + */ +void +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 + */ +void +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 + */ +void +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) + oops("%s: cannot divert.", m4temp); + } + oindex = n; + active = outfile[n]; +} + +/* + * doundivert - undivert a specified output, or all + * other outputs, in numerical order. + */ +void +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 + */ +void +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. + */ +void +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/src/cmd/m4/expr.c b/src/cmd/m4/expr.c new file mode 100644 index 0000000..c990fe2 --- /dev/null +++ b/src/cmd/m4/expr.c @@ -0,0 +1,626 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Ozan Yigit at York 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. + */ + +#if !defined(lint) && defined(DOSCCS) +static char sccsid[] = "@(#)expr.c 8.1 (Berkeley) 6/6/93"; +#endif + +#include +#include "stdd.h" + +/* + * expression evaluator: performs a standard recursive + * descent parse to evaluate any expression permissible + * within the following grammar: + * + * expr : query EOS + * query : lor + * | lor "?" query ":" query + * lor : land { "||" land } + * land : bor { "&&" bor } + * bor : bxor { "|" bxor } + * bxor : band { "^" band } + * band : eql { "&" eql } + * eql : relat { eqrel relat } + * relat : shift { rel shift } + * shift : primary { shop primary } + * primary : term { addop term } + * term : unary { mulop unary } + * unary : factor + * | unop unary + * factor : constant + * | "(" query ")" + * constant: num + * | "'" CHAR "'" + * num : DIGIT + * | DIGIT num + * shop : "<<" + * | ">>" + * eqlrel : "=" + * | "==" + * | "!=" + * rel : "<" + * | ">" + * | "<=" + * | ">=" + * + * + * This expression evaluator is lifted from a public-domain + * C Pre-Processor included with the DECUS C Compiler distribution. + * It is hacked somewhat to be suitable for m4. + * + * Originally by: Mike Lutz + * Bob Harper + */ + +#define TRUE 1 +#define FALSE 0 +#define EOS (char) 0 +#define EQL 0 +#define NEQ 1 +#define LSS 2 +#define LEQ 3 +#define GTR 4 +#define GEQ 5 +#define OCTAL 8 +#define DECIMAL 10 + +static char *nxtch; /* Parser scan pointer */ + +static int query __P((void)); +static int lor __P((void)); +static int land __P((void)); +static int bor __P((void)); +static int bxor __P((void)); +static int band __P((void)); +static int eql __P((void)); +static int relat __P((void)); +static int shift __P((void)); +static int primary __P((void)); +static int term __P((void)); +static int unary __P((void)); +static int factor __P((void)); +static int constant __P((void)); +static int num __P((void)); +static int geteql __P((void)); +static int getrel __P((void)); +static int skipws __P((void)); +static void experr __P((char *)); + +/* + * For longjmp + */ +#include +static jmp_buf expjump; + +/* + * macros: + * ungetch - Put back the last character examined. + * getch - return the next character from expr string. + */ +#define ungetch() nxtch-- +#define getch() *nxtch++ + +int +expr(expbuf) +char *expbuf; +{ + register int rval; + + nxtch = expbuf; + if (setjmp(expjump) != 0) + return FALSE; + + rval = query(); + if (skipws() == EOS) + return rval; + + printf("m4: ill-formed expression.\n"); + return FALSE; +} + +/* + * query : lor | lor '?' query ':' query + */ +static int +query() +{ + register int bool, true_val, false_val; + + bool = lor(); + if (skipws() != '?') { + ungetch(); + return bool; + } + + true_val = query(); + if (skipws() != ':') + experr("bad query"); + + false_val = query(); + return bool ? true_val : false_val; +} + +/* + * lor : land { '||' land } + */ +static int +lor() +{ + register int c, vl, vr; + + vl = land(); + while ((c = skipws()) == '|' && getch() == '|') { + vr = land(); + vl = vl || vr; + } + + if (c == '|') + ungetch(); + ungetch(); + return vl; +} + +/* + * land : bor { '&&' bor } + */ +static int +land() +{ + register int c, vl, vr; + + vl = bor(); + while ((c = skipws()) == '&' && getch() == '&') { + vr = bor(); + vl = vl && vr; + } + + if (c == '&') + ungetch(); + ungetch(); + return vl; +} + +/* + * bor : bxor { '|' bxor } + */ +static int +bor() +{ + register int vl, vr, c; + + vl = bxor(); + while ((c = skipws()) == '|' && getch() != '|') { + ungetch(); + vr = bxor(); + vl |= vr; + } + + if (c == '|') + ungetch(); + ungetch(); + return vl; +} + +/* + * bxor : band { '^' band } + */ +static int +bxor() +{ + register int vl, vr; + + vl = band(); + while (skipws() == '^') { + vr = band(); + vl ^= vr; + } + + ungetch(); + return vl; +} + +/* + * band : eql { '&' eql } + */ +static int +band() +{ + register int vl, vr, c; + + vl = eql(); + while ((c = skipws()) == '&' && getch() != '&') { + ungetch(); + vr = eql(); + vl &= vr; + } + + if (c == '&') + ungetch(); + ungetch(); + return vl; +} + +/* + * eql : relat { eqrel relat } + */ +static int +eql() +{ + register int vl, vr, rel; + + vl = relat(); + while ((rel = geteql()) != -1) { + vr = relat(); + + switch (rel) { + + case EQL: + vl = (vl == vr); + break; + case NEQ: + vl = (vl != vr); + break; + } + } + return vl; +} + +/* + * relat : shift { rel shift } + */ +static int +relat() +{ + register int vl, vr, rel; + + vl = shift(); + while ((rel = getrel()) != -1) { + + vr = shift(); + switch (rel) { + + case LEQ: + vl = (vl <= vr); + break; + case LSS: + vl = (vl < vr); + break; + case GTR: + vl = (vl > vr); + break; + case GEQ: + vl = (vl >= vr); + break; + } + } + return vl; +} + +/* + * shift : primary { shop primary } + */ +static int +shift() +{ + register int vl, vr, c; + + vl = primary(); + while (((c = skipws()) == '<' || c == '>') && c == getch()) { + vr = primary(); + + if (c == '<') + vl <<= vr; + else + vl >>= vr; + } + + if (c == '<' || c == '>') + ungetch(); + ungetch(); + return vl; +} + +/* + * primary : term { addop term } + */ +static int +primary() +{ + register int c, vl, vr; + + vl = term(); + while ((c = skipws()) == '+' || c == '-') { + vr = term(); + if (c == '+') + vl += vr; + else + vl -= vr; + } + + ungetch(); + return vl; +} + +/* + * := { } + */ +static int +term() +{ + register int c, vl, vr; + + vl = unary(); + while ((c = skipws()) == '*' || c == '/' || c == '%') { + vr = unary(); + + switch (c) { + case '*': + vl *= vr; + break; + case '/': + vl /= vr; + break; + case '%': + vl %= vr; + break; + } + } + ungetch(); + return vl; +} + +/* + * unary : factor | unop unary + */ +static int +unary() +{ + register int val, c; + + if ((c = skipws()) == '!' || c == '~' || c == '-') { + val = unary(); + + switch (c) { + case '!': + return !val; + case '~': + return ~val; + case '-': + return -val; + } + } + + ungetch(); + return factor(); +} + +/* + * factor : constant | '(' query ')' + */ +static int +factor() +{ + register int val; + + if (skipws() == '(') { + val = query(); + if (skipws() != ')') + experr("bad factor"); + return val; + } + + ungetch(); + return constant(); +} + +/* + * constant: num | 'char' + * Note: constant() handles multi-byte constants + */ +static int +constant() +{ + register int i; + register int value; + register char c; + int v[sizeof(int)]; + + if (skipws() != '\'') { + ungetch(); + return num(); + } + for (i = 0; i < sizeof(int); i++) { + if ((c = getch()) == '\'') { + ungetch(); + break; + } + if (c == '\\') { + switch (c = getch()) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + ungetch(); + c = num(); + break; + case 'n': + c = 012; + break; + case 'r': + c = 015; + break; + case 't': + c = 011; + break; + case 'b': + c = 010; + break; + case 'f': + c = 014; + break; + } + } + v[i] = c; + } + if (i == 0 || getch() != '\'') + experr("illegal character constant"); + for (value = 0; --i >= 0;) { + value <<= 8; + value += v[i]; + } + return value; +} + +/* + * num : digit | num digit + */ +static int +num() +{ + register int rval, c, base; + int ndig; + + base = ((c = skipws()) == '0') ? OCTAL : DECIMAL; + rval = 0; + ndig = 0; + while (c >= '0' && c <= (base == OCTAL ? '7' : '9')) { + rval *= base; + rval += (c - '0'); + c = getch(); + ndig++; + } + ungetch(); + + if (ndig == 0) + experr("bad constant"); + + return rval; + +} + +/* + * eqlrel : '=' | '==' | '!=' + */ +static int +geteql() +{ + register int c1, c2; + + c1 = skipws(); + c2 = getch(); + + switch (c1) { + + case '=': + if (c2 != '=') + ungetch(); + return EQL; + + case '!': + if (c2 == '=') + return NEQ; + ungetch(); + ungetch(); + return -1; + + default: + ungetch(); + ungetch(); + return -1; + } +} + +/* + * rel : '<' | '>' | '<=' | '>=' + */ +static int +getrel() +{ + register int c1, c2; + + c1 = skipws(); + c2 = getch(); + + switch (c1) { + + case '<': + if (c2 == '=') + return LEQ; + ungetch(); + return LSS; + + case '>': + if (c2 == '=') + return GEQ; + ungetch(); + return GTR; + + default: + ungetch(); + ungetch(); + return -1; + } +} + +/* + * Skip over any white space and return terminating char. + */ +static int +skipws() +{ + register char c; + + while ((c = getch()) <= ' ' && c > EOS) + ; + return c; +} + +/* + * resets environment to eval(), prints an error + * and forces eval to return FALSE. + */ +static void +experr(msg) +char *msg; +{ + printf("m4: %s in expr.\n", msg); + longjmp(expjump, -1); +} diff --git a/src/cmd/m4/extern.h b/src/cmd/m4/extern.h new file mode 100644 index 0000000..df54d7c --- /dev/null +++ b/src/cmd/m4/extern.h @@ -0,0 +1,98 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Ozan Yigit at York 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. + * + * @(#)extern.h 8.1 (Berkeley) 6/6/93 + */ + +char *basename __P((char *)); +char *xalloc __P((unsigned int)); +int expr __P((char *)); +ndptr addent __P((char *)); +void chrsave __P((int)); +void dochc __P((char *[], int)); +void dochq __P((char *[], int)); +void dodefine __P((char *, char *)); +void dodefn __P((char *)); +void dodiv __P((int)); +void dodump __P((char *[], int)); +void doifelse __P((char *[], int)); +int doincl __P((char *)); +int dopaste __P((char *)); +void dopushdef __P((char *, char *)); +void dosub __P((char *[], int)); +void doundiv __P((char *[], int)); +void eval __P((char *[], int, int)); +void expand __P((char *[], int)); +void getdiv __P((int)); +char *xstrdup __P((const char *)); +int hash __P((char *)); +int indx __P((char *, char *)); +ndptr lookup __P((char *)); +void map __P((char *, char *, char *, char *)); +int onintr __P((int)); +void oops __P((const char *, ...)); +void pbnum __P((int)); +void pbstr __P((char *)); +void putback __P((int)); +void remhash __P((char *, int)); +void usage __P((void)); + +extern ndptr hashtab[]; /* hash table for macros etc. */ +extern stae mstack[]; /* stack of m4 machine */ +extern FILE *active; /* active output file pointer */ +extern FILE *infile[]; /* input file stack (0=stdin) */ +extern FILE *outfile[]; /* diversion array(0=bitbucket) */ +extern int fp; /* m4 call frame pointer */ +extern int ilevel; /* input file stack pointer */ +extern int oindex; /* diversion index. */ +extern int sp; /* current m4 stack pointer */ +extern char *bp; /* first available character */ +extern char buf[]; /* push-back buffer */ +extern char *bufbase; /* buffer base for this ilevel */ +extern char *bbase[]; /* buffer base per ilevel */ +extern char ecommt; /* end character for comment */ +extern char *endest; /* end of string space */ +extern char *endpbb; /* end of push-back buffer */ +extern char *ep; /* first free char in strspace */ +extern char lquote; /* left quote character (`) */ +extern char *m4temp; /* filename for diversions */ +extern char *m4wraps; /* m4wrap string default. */ +extern char *null; /* as it says.. just a null. */ +extern char *progname; /* program name */ +extern char rquote; /* right quote character (') */ +extern char scommt; /* start character for comment */ + +extern char *mktemp(); +extern char *malloc(); diff --git a/src/cmd/m4/look.c b/src/cmd/m4/look.c new file mode 100644 index 0000000..1638bed --- /dev/null +++ b/src/cmd/m4/look.c @@ -0,0 +1,144 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Ozan Yigit at York 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. + */ + +#if !defined(lint) && defined(DOSCCS) +static char sccsid[] = "@(#)look.c 8.1 (Berkeley) 6/6/93"; +#endif + +/* + * look.c + * Facility: m4 macro processor + * by: oz + */ + +#include +#include +#include +#include "mdef.h" +#include "stdd.h" +#include "extern.h" + +int +hash(name) +register char *name; +{ + register unsigned long h = 0; + while (*name) + h = (h << 5) + h + *name++; + return (h % HASHSIZE); +} + +/* + * find name in the hash table + */ +ndptr +lookup(name) +char *name; +{ + register ndptr p; + + for (p = hashtab[hash(name)]; p != nil; p = p->nxtptr) + if (STREQ(name, p->name)) + break; + return (p); +} + +/* + * hash and create an entry in the hash table. + * The new entry is added in front of a hash bucket. + */ +ndptr +addent(name) +char *name; +{ + register int h; + ndptr p; + + h = hash(name); + p = (ndptr) xalloc(sizeof(struct ndblock)); + p->nxtptr = hashtab[h]; + hashtab[h] = p; + p->name = xstrdup(name); + return p; +} + +static void +freent(p) +ndptr p; +{ + if (!(p->type & STATIC)) { + free((char *) p->name); + if (p->defn != null) + free((char *) p->defn); + } + free((char *) p); +} + +/* + * remove an entry from the hashtable + */ +void +remhash(name, all) +char *name; +int all; +{ + register int h; + register ndptr xp, tp, mp; + + h = hash(name); + mp = hashtab[h]; + tp = nil; + while (mp != nil) { + if (STREQ(mp->name, name)) { + mp = mp->nxtptr; + if (tp == nil) { + freent(hashtab[h]); + hashtab[h] = mp; + } + else { + xp = tp->nxtptr; + tp->nxtptr = mp; + freent(xp); + } + if (!all) + break; + } + else { + tp = mp; + mp = mp->nxtptr; + } + } +} diff --git a/src/cmd/m4/main.c b/src/cmd/m4/main.c new file mode 100644 index 0000000..2b653ed --- /dev/null +++ b/src/cmd/m4/main.c @@ -0,0 +1,422 @@ +/*- + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Ozan Yigit at York 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. + */ + +#if !defined(lint) && defined(DOSCCS) +static char copyright[] = +"@(#) Copyright (c) 1989, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; + +static char sccsid[] = "@(#)main.c 8.1 (Berkeley) 6/6/93"; +#endif + +/* + * main.c + * Facility: m4 macro processor + * by: oz + */ + +#include +#include +#include +#include +#include +#include +#include "mdef.h" +#include "stdd.h" +#include "extern.h" +#include "pathnames.h" + +ndptr hashtab[HASHSIZE]; /* hash table for macros etc. */ +char buf[BUFSIZE]; /* push-back buffer */ +char *bufbase = buf; /* the base for current ilevel */ +char *bbase[MAXINP]; /* the base for each ilevel */ +char *bp = buf; /* first available character */ +char *endpbb = buf+BUFSIZE; /* end of push-back buffer */ +stae mstack[STACKMAX+1]; /* stack of m4 machine */ +char strspace[STRSPMAX+1]; /* string space for evaluation */ +char *ep = strspace; /* first free char in strspace */ +char *endest= strspace+STRSPMAX;/* end of string space */ +int sp; /* current m4 stack pointer */ +int fp; /* m4 call frame pointer */ +FILE *infile[MAXINP]; /* input file stack (0=stdin) */ +FILE *outfile[MAXOUT]; /* diversion array(0=bitbucket)*/ +FILE *active; /* active output file pointer */ +char *m4temp; /* filename for diversions */ +int ilevel = 0; /* input file stack pointer */ +int oindex = 0; /* diversion index.. */ +char *null = ""; /* as it says.. just a null.. */ +char *m4wraps = ""; /* m4wrap string default.. */ +char *progname; /* name of this program */ +char lquote = LQUOTE; /* left quote character (`) */ +char rquote = RQUOTE; /* right quote character (') */ +char scommt = SCOMMT; /* start character for comment */ +char ecommt = ECOMMT; /* end character for comment */ + +struct keyblk keywrds[] = { /* m4 keywords to be installed */ + "include", INCLTYPE, + "sinclude", SINCTYPE, + "define", DEFITYPE, + "defn", DEFNTYPE, + "divert", DIVRTYPE, + "expr", EXPRTYPE, + "eval", EXPRTYPE, + "substr", SUBSTYPE, + "ifelse", IFELTYPE, + "ifdef", IFDFTYPE, + "len", LENGTYPE, + "incr", INCRTYPE, + "decr", DECRTYPE, + "dnl", DNLNTYPE, + "changequote", CHNQTYPE, + "changecom", CHNCTYPE, + "index", INDXTYPE, +#ifdef EXTENDED + "paste", PASTTYPE, + "spaste", SPASTYPE, +#endif + "popdef", POPDTYPE, + "pushdef", PUSDTYPE, + "dumpdef", DUMPTYPE, + "shift", SHIFTYPE, + "translit", TRNLTYPE, + "undefine", UNDFTYPE, + "undivert", UNDVTYPE, + "divnum", DIVNTYPE, + "maketemp", MKTMTYPE, + "errprint", ERRPTYPE, + "m4wrap", M4WRTYPE, + "m4exit", EXITTYPE, + "syscmd", SYSCTYPE, + "sysval", SYSVTYPE, + +#ifdef unix + "unix", MACRTYPE, +#else +#ifdef vms + "vms", MACRTYPE, +#endif +#endif +}; + +#define MAXKEYS (sizeof(keywrds)/sizeof(struct keyblk)) + +extern int optind; +extern char *optarg; + +void macro(); +void initkwds(); +extern int getopt(); + +int +main(argc,argv) + int argc; + char *argv[]; +{ + register int c; + register int n; + char *p; + register FILE *ifp; + + progname = basename(argv[0]); + + if (signal(SIGINT, SIG_IGN) != SIG_IGN) + signal(SIGINT, onintr); + + initkwds(); + + while ((c = getopt(argc, argv, "tD:U:o:")) != EOF) + switch(c) { + + case 'D': /* define something..*/ + for (p = optarg; *p; p++) + if (*p == '=') + break; + if (*p) + *p++ = EOS; + dodefine(optarg, p); + break; + case 'U': /* undefine... */ + remhash(optarg, TOP); + break; + case 'o': /* specific output */ + case '?': + usage(); + } + + argc -= optind; + argv += optind; + + active = stdout; /* default active output */ + /* filename for diversions */ + m4temp = mktemp(xstrdup(_PATH_DIVNAME)); + + bbase[0] = bufbase; + if (!argc) { + sp = -1; /* stack pointer initialized */ + fp = 0; /* frame pointer initialized */ + infile[0] = stdin; /* default input (naturally) */ + macro(); + } else + for (; argc--; ++argv) { + p = *argv; + if (p[0] == '-' && p[1] == '\0') + ifp = stdin; + else if ((ifp = fopen(p, "r")) == NULL) + oops("%s: %s", p, strerror(errno)); + sp = -1; + fp = 0; + infile[0] = ifp; + macro(); + if (ifp != stdin) + (void)fclose(ifp); + } + + if (*m4wraps) { /* anything for rundown ?? */ + ilevel = 0; /* in case m4wrap includes.. */ + bufbase = bp = buf; /* use the entire buffer */ + putback(EOF); /* eof is a must !! */ + pbstr(m4wraps); /* user-defined wrapup act */ + macro(); /* last will and testament */ + } + + if (active != stdout) + active = stdout; /* reset output just in case */ + for (n = 1; n < MAXOUT; n++) /* default wrap-up: undivert */ + if (outfile[n] != NULL) + getdiv(n); + /* remove bitbucket if used */ + if (outfile[0] != NULL) { + (void) fclose(outfile[0]); + m4temp[UNIQUE] = '0'; +#ifdef vms + (void) remove(m4temp); +#else + (void) unlink(m4temp); +#endif + } + + return 0; +} + +ndptr inspect(); + +/* + * macro - the work horse.. + */ +void +macro() { + char token[MAXTOK]; + register char *s; + register int t, l; + register ndptr p; + register int nlpar; + + cycle { + if ((t = gpbc()) == '_' || isalpha(t)) { + putback(t); + if ((p = inspect(s = token)) == nil) { + if (sp < 0) + while (*s) + putc(*s++, active); + else + while (*s) + chrsave(*s++); + } + else { + /* + * real thing.. First build a call frame: + */ + pushf(fp); /* previous call frm */ + pushf(p->type); /* type of the call */ + pushf(0); /* parenthesis level */ + fp = sp; /* new frame pointer */ + /* + * now push the string arguments: + */ + pushs(p->defn); /* defn string */ + pushs(p->name); /* macro name */ + pushs(ep); /* start next..*/ + + putback(l = gpbc()); + if (l != LPAREN) { /* add bracks */ + putback(RPAREN); + putback(LPAREN); + } + } + } + else if (t == EOF) { + if (sp > -1) + oops("unexpected end of input", ""); + if (ilevel <= 0) + break; /* all done thanks.. */ + --ilevel; + (void) fclose(infile[ilevel+1]); + bufbase = bbase[ilevel]; + continue; + } + /* + * non-alpha single-char token seen.. + * [the order of else if .. stmts is important.] + */ + else if (t == lquote) { /* strip quotes */ + nlpar = 1; + do { + if ((l = gpbc()) == rquote) + nlpar--; + else if (l == lquote) + nlpar++; + else if (l == EOF) + oops("missing right quote", ""); + if (nlpar > 0) { + if (sp < 0) + putc(l, active); + else + chrsave(l); + } + } + while (nlpar != 0); + } + + else if (sp < 0) { /* not in a macro at all */ + if (t == scommt) { /* comment handling here */ + putc(t, active); + while ((t = gpbc()) != ecommt) + putc(t, active); + } + putc(t, active); /* output directly.. */ + } + + else switch(t) { + + case LPAREN: + if (PARLEV > 0) + chrsave(t); + while (isspace(l = gpbc())) + ; /* skip blank, tab, nl.. */ + putback(l); + PARLEV++; + break; + + case RPAREN: + if (--PARLEV > 0) + chrsave(t); + else { /* end of argument list */ + chrsave(EOS); + + if (sp == STACKMAX) + oops("internal stack overflow", ""); + + if (CALTYP == MACRTYPE) + expand((char **) mstack+fp+1, sp-fp); + else + eval((char **) mstack+fp+1, sp-fp, CALTYP); + + ep = PREVEP; /* flush strspace */ + sp = PREVSP; /* previous sp.. */ + fp = PREVFP; /* rewind stack...*/ + } + break; + + case COMMA: + if (PARLEV == 1) { + chrsave(EOS); /* new argument */ + while (isspace(l = gpbc())) + ; + putback(l); + pushs(ep); + } else + chrsave(t); + break; + + default: + chrsave(t); /* stack the char */ + break; + } + } +} + +/* + * build an input token.. + * consider only those starting with _ or A-Za-z. This is a + * combo with lookup to speed things up. + */ +ndptr +inspect(tp) +register char *tp; +{ + register char c; + register char *name = tp; + register char *etp = tp+MAXTOK; + register ndptr p; + register unsigned long h = 0; + + while ((isalnum(c = gpbc()) || c == '_') && tp < etp) + h = (h << 5) + h + (*tp++ = c); + putback(c); + if (tp == etp) + oops("token too long", ""); + + *tp = EOS; + + for (p = hashtab[h%HASHSIZE]; p != nil; p = p->nxtptr) + if (STREQ(name, p->name)) + break; + return p; +} + +/* + * initkwds - initialise m4 keywords as fast as possible. + * This very similar to install, but without certain overheads, + * such as calling lookup. Malloc is not used for storing the + * keyword strings, since we simply use the static pointers + * within keywrds block. + */ +void +initkwds() { + register int i; + register int h; + register ndptr p; + + for (i = 0; i < MAXKEYS; i++) { + h = hash(keywrds[i].knam); + p = (ndptr) xalloc(sizeof(struct ndblock)); + p->nxtptr = hashtab[h]; + hashtab[h] = p; + p->name = keywrds[i].knam; + p->defn = null; + p->type = keywrds[i].ktyp | STATIC; + } +} diff --git a/src/cmd/m4/mdef.h b/src/cmd/m4/mdef.h new file mode 100644 index 0000000..cc256b0 --- /dev/null +++ b/src/cmd/m4/mdef.h @@ -0,0 +1,176 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Ozan Yigit at York 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. + * + * @(#)mdef.h 8.1 (Berkeley) 6/6/93 + */ + +#define MACRTYPE 1 +#define DEFITYPE 2 +#define EXPRTYPE 3 +#define SUBSTYPE 4 +#define IFELTYPE 5 +#define LENGTYPE 6 +#define CHNQTYPE 7 +#define SYSCTYPE 8 +#define UNDFTYPE 9 +#define INCLTYPE 10 +#define SINCTYPE 11 +#define PASTTYPE 12 +#define SPASTYPE 13 +#define INCRTYPE 14 +#define IFDFTYPE 15 +#define PUSDTYPE 16 +#define POPDTYPE 17 +#define SHIFTYPE 18 +#define DECRTYPE 19 +#define DIVRTYPE 20 +#define UNDVTYPE 21 +#define DIVNTYPE 22 +#define MKTMTYPE 23 +#define ERRPTYPE 24 +#define M4WRTYPE 25 +#define TRNLTYPE 26 +#define DNLNTYPE 27 +#define DUMPTYPE 28 +#define CHNCTYPE 29 +#define INDXTYPE 30 +#define SYSVTYPE 31 +#define EXITTYPE 32 +#define DEFNTYPE 33 + +#define STATIC 128 + +/* + * m4 special characters + */ + +#define ARGFLAG '$' +#define LPAREN '(' +#define RPAREN ')' +#define LQUOTE '`' +#define RQUOTE '\'' +#define COMMA ',' +#define SCOMMT '#' +#define ECOMMT '\n' + +#ifdef msdos +#define system(str) (-1) +#endif + +/* + * other important constants + */ + +#define EOS (char) 0 +#define MAXINP 10 /* maximum include files */ +#define MAXOUT 10 /* maximum # of diversions */ +#define MAXSTR 512 /* maximum size of string */ +#define BUFSIZE 4096 /* size of pushback buffer */ +#define STACKMAX 1024 /* size of call stack */ +#define STRSPMAX 4096 /* size of string space */ +#define MAXTOK MAXSTR /* maximum chars in a tokn */ +#define HASHSIZE 199 /* maximum size of hashtab */ + +#define ALL 1 +#define TOP 0 + +#define TRUE 1 +#define FALSE 0 +#define cycle for(;;) + +/* + * m4 data structures + */ + +typedef struct ndblock *ndptr; + +struct ndblock { /* hastable structure */ + char *name; /* entry name.. */ + char *defn; /* definition.. */ + int type; /* type of the entry.. */ + ndptr nxtptr; /* link to next entry.. */ +}; + +#define nil ((ndptr) 0) + +struct keyblk { + char *knam; /* keyword name */ + int ktyp; /* keyword type */ +}; + +typedef union { /* stack structure */ + int sfra; /* frame entry */ + char *sstr; /* string entry */ +} stae; + +/* + * macros for readibility and/or speed + * + * gpbc() - get a possibly pushed-back character + * pushf() - push a call frame entry onto stack + * pushs() - push a string pointer onto stack + */ +#define gpbc() (bp > bufbase) ? *--bp : getc(infile[ilevel]) +#define pushf(x) if (sp < STACKMAX) mstack[++sp].sfra = (x) +#define pushs(x) if (sp < STACKMAX) mstack[++sp].sstr = (x) + +/* + * . . + * | . | <-- sp | . | + * +-------+ +-----+ + * | arg 3 ----------------------->| str | + * +-------+ | . | + * | arg 2 ---PREVEP-----+ . + * +-------+ | + * . | | | + * +-------+ | +-----+ + * | plev | PARLEV +-------->| str | + * +-------+ | . | + * | type | CALTYP . + * +-------+ + * | prcf ---PREVFP--+ + * +-------+ | + * | . | PREVSP | + * . | + * +-------+ | + * | <----------+ + * +-------+ + * + */ +#define PARLEV (mstack[fp].sfra) +#define CALTYP (mstack[fp-1].sfra) +#define PREVEP (mstack[fp+3].sstr) +#define PREVSP (fp-3) +#define PREVFP (mstack[fp-2].sfra) diff --git a/src/cmd/m4/misc.c b/src/cmd/m4/misc.c new file mode 100644 index 0000000..b48881d --- /dev/null +++ b/src/cmd/m4/misc.c @@ -0,0 +1,244 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Ozan Yigit at York 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. + */ + +#if !defined(lint) && defined(DOSCCS) +static char sccsid[] = "@(#)misc.c 8.1 (Berkeley) 6/6/93"; +#endif + +#include +#include +#include +#include +#include "mdef.h" +#include "stdd.h" +#include "extern.h" +#include "pathnames.h" + +/* + * find the index of second str in the first str. + */ +int +indx(s1, s2) +char *s1; +char *s2; +{ + register char *t; + register char *p; + register char *m; + + for (p = s1; *p; p++) { + for (t = p, m = s2; *m && *m == *t; m++, t++); + if (!*m) + return (p - s1); + } + return (-1); +} +/* + * putback - push character back onto input + */ +void +putback(c) +char c; +{ + if (bp < endpbb) + *bp++ = c; + else + oops("too many characters pushed back"); +} + +/* + * pbstr - push string back onto input + * putback is replicated to improve + * performance. + */ +void +pbstr(s) +register char *s; +{ + register char *es; + register char *zp; + + es = s; + zp = bp; + + while (*es) + es++; + es--; + while (es >= s) + if (zp < endpbb) + *zp++ = *es--; + if ((bp = zp) == endpbb) + oops("too many characters pushed back"); +} + +/* + * pbnum - convert number to string, push back on input. + */ +void +pbnum(n) +int n; +{ + register int num; + + num = (n < 0) ? -n : n; + do { + putback(num % 10 + '0'); + } + while ((num /= 10) > 0); + + if (n < 0) + putback('-'); +} + +/* + * chrsave - put single char on string space + */ +void +chrsave(c) +char c; +{ + if (ep < endest) + *ep++ = c; + else + oops("string space overflow"); +} + +/* + * read in a diversion file, and dispose it. + */ +void +getdiv(n) +int n; +{ + register int c; + register FILE *dfil; + + if (active == outfile[n]) + oops("%s: diversion still active.", "undivert"); + (void) fclose(outfile[n]); + outfile[n] = NULL; + m4temp[UNIQUE] = n + '0'; + if ((dfil = fopen(m4temp, "r")) == NULL) + oops("%s: cannot undivert.", m4temp); + else + while ((c = getc(dfil)) != EOF) + putc(c, active); + (void) fclose(dfil); + +#ifdef vms + if (remove(m4temp)) +#else + if (unlink(m4temp) == -1) +#endif + oops("%s: cannot unlink.", m4temp); +} + +int +onintr() +{ + oops("interrupted."); +} + +char * +xalloc(n) +unsigned n; +{ + register char *p = malloc(n); + + if (p == NULL) + oops("malloc: %s", strerror(errno)); + return p; +} + +char * +xstrdup(s) +char *s; +{ + register char *p = strdup(s); + if (p == NULL) + oops("strdup: %s", strerror(errno)); + return p; +} + +char * +basename(s) +register char *s; +{ + register char *p; + extern char *strrchr(); + + if ((p = strrchr(s, '/')) == NULL) + return s; + + return ++p; +} + +void +usage() +{ + fprintf(stderr, "usage: m4 [-Dname[=val]] [-Uname]\n"); + exit(1); +} + +#if __STDC__ +#include +#else +#include +#endif + +void +#if __STDC__ +oops(const char *fmt, ...) +#else +/* VARARGS1 */ +oops(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, "%s: ", progname); + (void)vfprintf(stderr, fmt, ap); + va_end(ap); + (void)fprintf(stderr, "\n"); + exit(1); + /* NOTREACHED */ +} diff --git a/src/cmd/m4/pathnames.h b/src/cmd/m4/pathnames.h new file mode 100644 index 0000000..72f66d3 --- /dev/null +++ b/src/cmd/m4/pathnames.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Ozan Yigit at York 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. + * + * @(#)pathnames.h 8.1 (Berkeley) 6/6/93 + */ + +/* + * Definitions of diversion files. If the name of the file is changed, + * adjust UNIQUE to point to the wildcard (*) character in the filename. + */ + +#ifdef msdos +#define _PATH_DIVNAME "\\M4*XXXXXX" /* msdos diversion files */ +#define UNIQUE 3 /* unique char location */ +#endif + +#ifdef unix +#define _PATH_DIVNAME "/tmp/m4.0XXXXXX" /* unix diversion files */ +#define UNIQUE 8 /* unique char location */ +#endif + +#ifdef vms +#define _PATH_DIVNAME "sys$login:m4*XXXXXX" /* vms diversion files */ +#define UNIQUE 12 /* unique char location */ +#endif diff --git a/src/cmd/m4/stdd.h b/src/cmd/m4/stdd.h new file mode 100644 index 0000000..dd70431 --- /dev/null +++ b/src/cmd/m4/stdd.h @@ -0,0 +1,60 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Ozan Yigit at York 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. + * + * @(#)stdd.h 8.1 (Berkeley) 6/6/93 + */ + +/* + * standard defines + */ + +#define max(a,b) ((a) > (b)? (a): (b)) +#define min(a,b) ((a) < (b)? (a): (b)) + +#define iswhite(c) ((c) == ' ' || (c) == '\t') + +/* + * STREQ is an optimised strcmp(a,b)==0 + * STREQN is an optimised strncmp(a,b,n)==0; assumes n > 0 + */ +#define STREQ(a, b) ((a)[0] == (b)[0] && strcmp(a, b) == 0) +#define STREQN(a, b, n) ((a)[0] == (b)[0] && strncmp(a, b, n) == 0) + +#define YES 1 +#define NO 0 + +#define __P(protos) () + +extern int errno; diff --git a/src/cmd/m4/tags b/src/cmd/m4/tags new file mode 100644 index 0000000..4cc509e --- /dev/null +++ b/src/cmd/m4/tags @@ -0,0 +1,70 @@ +Mmain main.c /^main(argc,argv)$/ +STREQ stdd.h /^#define STREQ(a, b) ((a)[0] == (b)[0] && strcmp(a,/ +STREQN stdd.h /^#define STREQN(a, b, n) ((a)[0] == (b)[0] && strnc/ +__P stdd.h /^#define __P(protos) ()$/ +addent look.c /^ndptr $/ +band expr.c /^band()$/ +basename misc.c /^basename(s)$/ +bor expr.c /^bor()$/ +bxor expr.c /^bxor()$/ +chrsave misc.c /^chrsave(c)$/ +constant expr.c /^constant()$/ +dochc eval.c /^dochc(argv, argc)$/ +dochq eval.c /^dochq(argv, argc)$/ +dodefine eval.c /^dodefine(name, defn)$/ +dodefn eval.c /^dodefn(name)$/ +dodiv eval.c /^dodiv(n)$/ +dodump eval.c /^dodump(argv, argc)$/ +doifelse eval.c /^doifelse(argv, argc)$/ +doincl eval.c /^doincl(ifile)$/ +dopaste eval.c /^dopaste(pfile)$/ +dopushdef eval.c /^dopushdef(name, defn)$/ +dosub eval.c /^dosub(argv, argc)$/ +doundiv eval.c /^doundiv(argv, argc)$/ +eql expr.c /^eql()$/ +eval eval.c /^eval(argv, argc, td)$/ +expand eval.c /^expand(argv, argc)$/ +experr expr.c /^experr(msg)$/ +expr expr.c /^expr(expbuf)$/ +factor expr.c /^factor()$/ +freent look.c /^freent(p)$/ +getch expr.c /^#define getch() *nxtch++$/ +getdiv misc.c /^getdiv(n)$/ +geteql expr.c /^geteql()$/ +getrel expr.c /^getrel()$/ +gpbc mdef.h /^#define gpbc() (bp > bufbase) ? *--bp : getc(inf/ +hash look.c /^hash(name)$/ +indx misc.c /^indx(s1, s2)$/ +initkwds main.c /^initkwds() {$/ +inspect main.c /^inspect(tp) $/ +iswhite stdd.h /^#define iswhite(c) ((c) == ' ' || (c) == '\\t')$/ +land expr.c /^land()$/ +lookup look.c /^ndptr $/ +lor expr.c /^lor()$/ +macro main.c /^macro() {$/ +map eval.c /^map(dest, src, from, to)$/ +max stdd.h /^#define max(a,b) ((a) > (b)? (a): (b))$/ +min stdd.h /^#define min(a,b) ((a) < (b)? (a): (b))$/ +ndptr mdef.h 117 +num expr.c /^num()$/ +onintr misc.c /^onintr()$/ +oops misc.c /^oops(const char *fmt, ...)$/ +pbnum misc.c /^pbnum(n)$/ +pbstr misc.c /^pbstr(s)$/ +primary expr.c /^primary()$/ +pushf mdef.h /^#define pushf(x) if (sp < STACKMAX) mstack[++sp].s/ +pushs mdef.h /^#define pushs(x) if (sp < STACKMAX) mstack[++sp].s/ +putback misc.c /^putback(c)$/ +query expr.c /^query()$/ +relat expr.c /^relat()$/ +remhash look.c /^remhash(name, all)$/ +shift expr.c /^shift()$/ +skipws expr.c /^skipws()$/ +stae mdef.h 136 +system mdef.h /^#define system(str) (-1)$/ +term expr.c /^term()$/ +unary expr.c /^unary()$/ +ungetch expr.c /^#define ungetch() nxtch--$/ +usage misc.c /^usage()$/ +xalloc misc.c /^xalloc(n)$/ +xstrdup misc.c /^xstrdup(s)$/ diff --git a/src/cmd/mail.c b/src/cmd/mail.c new file mode 100644 index 0000000..20c61cb --- /dev/null +++ b/src/cmd/mail.c @@ -0,0 +1,693 @@ +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + /* copylet flags */ +#define REMOTE 1 /* remote mail, add rmtmsg */ +#define ORDINARY 2 +#define ZAP 3 /* zap header and trailing empty line */ +#define FORWARD 4 + +#define LSIZE 256 +#define MAXLET 300 /* maximum number of letters */ +#define MAILMODE 0600 /* mode of created mail */ + +char line[LSIZE]; +char resp[LSIZE]; +struct let { + long adr; + char change; +} let[MAXLET]; +int nlet = 0; +char lfil[50]; +long iop; +char lettmp[] = "/tmp/maXXXXX"; +char maildir[] = _PATH_MAIL; +char mailfile[] = _PATH_MAIL "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; +char dead[] = "dead.letter"; +char forwmsg[] = " forwarded\n"; +FILE *tmpf; +FILE *malf; +char my_name[60]; +int error; +int changed; +int forward; +char from[] = "From "; +int delex(); +int flgf; +int flgp; +int delflg = 1; +int hseqno; +jmp_buf sjbuf; +int rmail; + +main(argc, argv) +char **argv; +{ + register int i; + char *name; + struct passwd *pwent; + + if (!(name = getlogin()) || !*name || !(pwent = getpwnam(name)) || + getuid() != pwent->pw_uid) + pwent = getpwuid(getuid()); + strncpy(my_name, pwent ? pwent->pw_name : "???", sizeof(my_name)-1); + if (setjmp(sjbuf)) + done(); + for (i=SIGHUP; i<=SIGTERM; i++) + setsig(i, delex); + i = mkstemp(lettmp); + tmpf = fdopen(i, "r+w"); + if (i < 0 || tmpf == NULL) + panic("mail: %s: cannot open for writing", lettmp); + /* + * This protects against others reading mail from temp file and + * if we exit, the file will be deleted already. + */ + unlink(lettmp); + if (argv[0][0] == 'r') + rmail++; + if (argv[0][0] != 'r' && /* no favors for rmail*/ + (argc == 1 || argv[1][0] == '-' && !any(argv[1][1], "rhd"))) + printmail(argc, argv); + else + bulkmail(argc, argv); + done(); +} + +setsig(i, f) +int i; +sig_t f; +{ + if (signal(i, SIG_IGN) != SIG_IGN) + signal(i, f); +} + +any(c, str) + register int c; + register char *str; +{ + + while (*str) + if (c == *str++) + return(1); + return(0); +} + +printmail(argc, argv) + char **argv; +{ + int flg, i, j, print; + char *p, *getarg(); + struct stat statb; + + setuid(getuid()); + cat(mailfile, maildir, my_name); + for (; argc > 1; argv++, argc--) { + if (argv[1][0] != '-') + break; + switch (argv[1][1]) { + + case 'p': + flgp++; + /* fall thru... */ + case 'q': + delflg = 0; + break; + + case 'f': + if (argc >= 3) { + strcpy(mailfile, argv[2]); + argv++, argc--; + } + break; + + case 'b': + forward = 1; + break; + + default: + panic("unknown option %c", argv[1][1]); + /*NOTREACHED*/ + } + } + malf = fopen(mailfile, "r"); + if (malf == NULL) { + printf("No mail.\n"); + return; + } + flock(fileno(malf), LOCK_SH); + copymt(malf, tmpf); + fclose(malf); /* implicit unlock */ + fseek(tmpf, 0L, L_SET); + + changed = 0; + print = 1; + for (i = 0; i < nlet; ) { + j = forward ? i : nlet - i - 1; + if (setjmp(sjbuf)) { + print = 0; + } else { + if (print) + copylet(j, stdout, ORDINARY); + print = 1; + } + if (flgp) { + i++; + continue; + } + setjmp(sjbuf); + fputs("? ", stdout); + fflush(stdout); + if (fgets(resp, LSIZE, stdin) == NULL) + break; + switch (resp[0]) { + + default: + printf("usage\n"); + case '?': + print = 0; + printf("q\tquit\n"); + printf("x\texit without changing mail\n"); + printf("p\tprint\n"); + printf("s[file]\tsave (default mbox)\n"); + printf("w[file]\tsame without header\n"); + printf("-\tprint previous\n"); + printf("d\tdelete\n"); + printf("+\tnext (no delete)\n"); + printf("m user\tmail to user\n"); + printf("! cmd\texecute cmd\n"); + break; + + case '+': + case 'n': + case '\n': + i++; + break; + case 'x': + changed = 0; + case 'q': + goto donep; + case 'p': + break; + case '^': + case '-': + if (--i < 0) + i = 0; + break; + case 'y': + case 'w': + case 's': + flg = 0; + if (resp[1] != '\n' && resp[1] != ' ') { + printf("illegal\n"); + flg++; + print = 0; + continue; + } + if (resp[1] == '\n' || resp[1] == '\0') { + p = getenv("HOME"); + if (p != 0) + cat(resp+1, p, "/mbox"); + else + cat(resp+1, "", "mbox"); + } + for (p = resp+1; (p = getarg(lfil, p)) != NULL; ) { + malf = fopen(lfil, "a"); + if (malf == NULL) { + printf("mail: %s: cannot append\n", + lfil); + flg++; + continue; + } + copylet(j, malf, resp[0]=='w'? ZAP: ORDINARY); + fclose(malf); + } + if (flg) + print = 0; + else { + let[j].change = 'd'; + changed++; + i++; + } + break; + case 'm': + flg = 0; + if (resp[1] == '\n' || resp[1] == '\0') { + i++; + continue; + } + if (resp[1] != ' ') { + printf("invalid command\n"); + flg++; + print = 0; + continue; + } + for (p = resp+1; (p = getarg(lfil, p)) != NULL; ) + if (!sendmail(j, lfil, my_name)) + flg++; + if (flg) + print = 0; + else { + let[j].change = 'd'; + changed++; + i++; + } + break; + case '!': + system(resp+1); + printf("!\n"); + print = 0; + break; + case 'd': + let[j].change = 'd'; + changed++; + i++; + if (resp[1] == 'q') + goto donep; + break; + } + } + donep: + if (changed) + copyback(); +} + +/* copy temp or whatever back to /var/mail */ +copyback() +{ + register int i, c; + sigset_t set; + int fd, new = 0; + struct stat stbuf; + + sigemptyset(&set); + sigaddset(&set, SIGINT); + sigaddset(&set, SIGHUP); + sigaddset(&set, SIGQUIT); + (void)sigprocmask(SIG_BLOCK, &set, NULL); + fd = open(mailfile, O_RDWR | O_CREAT, MAILMODE); + if (fd >= 0) { + flock(fd, LOCK_EX); + malf = fdopen(fd, "r+w"); + } + if (fd < 0 || malf == NULL) + panic("can't rewrite %s", lfil); + fstat(fd, &stbuf); + if (stbuf.st_size != let[nlet].adr) { /* new mail has arrived */ + fseek(malf, let[nlet].adr, L_SET); + fseek(tmpf, let[nlet].adr, L_SET); + while ((c = getc(malf)) != EOF) + putc(c, tmpf); + let[++nlet].adr = stbuf.st_size; + new = 1; + fseek(malf, 0L, L_SET); + } + ftruncate(fd, 0L); + for (i = 0; i < nlet; i++) + if (let[i].change != 'd') + copylet(i, malf, ORDINARY); + fclose(malf); /* implict unlock */ + if (new) + printf("New mail has arrived.\n"); + (void)sigprocmask(SIG_UNBLOCK, &set, NULL); +} + +/* copy mail (f1) to temp (f2) */ +copymt(f1, f2) + FILE *f1, *f2; +{ + long nextadr; + + nlet = nextadr = 0; + let[0].adr = 0; + while (fgets(line, LSIZE, f1) != NULL) { + if (isfrom(line)) + let[nlet++].adr = nextadr; + nextadr += strlen(line); + fputs(line, f2); + } + let[nlet].adr = nextadr; /* last plus 1 */ +} + +copylet(n, f, type) + FILE *f; +{ + int ch; + long k; + char hostname[MAXHOSTNAMELEN]; + + fseek(tmpf, let[n].adr, L_SET); + k = let[n+1].adr - let[n].adr; + while (k-- > 1 && (ch = getc(tmpf)) != '\n') + if (type != ZAP) + putc(ch, f); + switch (type) { + + case REMOTE: + gethostname(hostname, sizeof (hostname)); + fprintf(f, " remote from %s\n", hostname); + break; + + case FORWARD: + fprintf(f, forwmsg); + break; + + case ORDINARY: + putc(ch, f); + break; + + case ZAP: + break; + + default: + panic("Bad letter type %d to copylet.", type); + } + while (k-- > 1) { + ch = getc(tmpf); + putc(ch, f); + } + if (type != ZAP || ch != '\n') + putc(getc(tmpf), f); +} + +isfrom(lp) +register char *lp; +{ + register char *p; + + for (p = from; *p; ) + if (*lp++ != *p++) + return(0); + return(1); +} + +bulkmail(argc, argv) +char **argv; +{ + char *truename; + int first; + register char *cp; + char *newargv[1000]; + register char **ap; + register char **vp; + int dflag; + + dflag = 0; + delflg = 0; + if (argc < 1) { + fprintf(stderr, "puke\n"); + return; + } + for (vp = argv, ap = newargv + 1; (*ap = *vp++) != 0; ap++) + if (ap[0][0] == '-' && ap[0][1] == 'd') + dflag++; + if (!dflag) { + /* give it to sendmail, rah rah! */ + unlink(lettmp); + ap = newargv+1; + if (rmail) + *ap-- = "-s"; + *ap = "-sendmail"; + setuid(getuid()); + execv(_PATH_SENDMAIL, ap); + perror(_PATH_SENDMAIL); + exit(EX_UNAVAILABLE); + } + + truename = 0; + line[0] = '\0'; + + /* + * When we fall out of this, argv[1] should be first name, + * argc should be number of names + 1. + */ + + while (argc > 1 && *argv[1] == '-') { + cp = *++argv; + argc--; + switch (cp[1]) { + case 'r': + if (argc <= 1) + usage(); + truename = argv[1]; + fgets(line, LSIZE, stdin); + if (strncmp("From", line, 4) == 0) + line[0] = '\0'; + argv++; + argc--; + break; + + case 'h': + if (argc <= 1) + usage(); + hseqno = atoi(argv[1]); + argv++; + argc--; + break; + + case 'd': + break; + + default: + usage(); + } + } + if (argc <= 1) + usage(); + if (truename == 0) + truename = my_name; + time(&iop); + fprintf(tmpf, "%s%s %s", from, truename, ctime(&iop)); + iop = ftell(tmpf); + flgf = first = 1; + for (;;) { + if (first) { + first = 0; + if (*line == '\0' && fgets(line, LSIZE, stdin) == NULL) + break; + } else { + if (fgets(line, LSIZE, stdin) == NULL) + break; + } + if (*line == '.' && line[1] == '\n' && isatty(fileno(stdin))) + break; + if (isfrom(line)) + putc('>', tmpf); + fputs(line, tmpf); + flgf = 0; + } + putc('\n', tmpf); + nlet = 1; + let[0].adr = 0; + let[1].adr = ftell(tmpf); + if (flgf) + return; + while (--argc > 0) + if (!sendmail(0, *++argv, truename)) + error++; + if (error && safefile(dead)) { + setuid(getuid()); + malf = fopen(dead, "w"); + if (malf == NULL) { + printf("mail: cannot open %s\n", dead); + fclose(tmpf); + return; + } + copylet(0, malf, ZAP); + fclose(malf); + printf("Mail saved in %s\n", dead); + } + fclose(tmpf); +} + +sendrmt(n, name) +char *name; +{ + FILE *rmf, *popen(); + register char *p; + char rsys[64], cmd[64]; + register pid; + int sts; + + for (p=rsys; *name!='!'; *p++ = *name++) + if (*name=='\0') + return(0); /* local address, no '!' */ + *p = '\0'; + if (name[1]=='\0') { + printf("null name\n"); + return(0); + } +skip: + if ((pid = fork()) == -1) { + fprintf(stderr, "mail: can't create proc for remote\n"); + return(0); + } + if (pid) { + while (wait(&sts) != pid) { + if (wait(&sts)==-1) + return(0); + } + return(!sts); + } + setuid(getuid()); + if (any('!', name+1)) + (void)sprintf(cmd, "uux - %s!rmail \\(%s\\)", rsys, name+1); + else + (void)sprintf(cmd, "uux - %s!rmail %s", rsys, name+1); + if ((rmf=popen(cmd, "w")) == NULL) + exit(1); + copylet(n, rmf, REMOTE); + exit(pclose(rmf) != 0); +} + +usage() +{ + fprintf(stderr, "Usage: mail [ -f ] people . . .\n"); + error = EX_USAGE; + done(); +} + +sendmail(n, name, fromaddr) + int n; + char *name, *fromaddr; +{ + char file[256]; + int fd; + struct passwd *pw; + char buf[128]; + off_t oldsize; + + if (*name=='!') + name++; + if (any('!', name)) + return (sendrmt(n, name)); + if ((pw = getpwnam(name)) == NULL) { + printf("mail: can't send to %s\n", name); + return(0); + } + cat(file, maildir, name); + if (!safefile(file)) + return(0); + fd = open(file, O_WRONLY | O_CREAT | O_EXLOCK, MAILMODE); + if (fd >= 0) + malf = fdopen(fd, "a"); + if (fd < 0 || malf == NULL) { + close(fd); + printf("mail: %s: cannot append\n", file); + return(0); + } + fchown(fd, pw->pw_uid, pw->pw_gid); + oldsize = ftell(malf); + (void)sprintf(buf, "%s@%ld\n", name, oldsize); + + copylet(n, malf, ORDINARY); /* Try to deliver the message */ + + /* If there is any error during the delivery of the message, + * the mail file may be corrupted (incomplete last line) and + * any subsequent mail will be apparently lost, since the + * before the 'From ' won't be there. So, restore the + * file to the pre-delivery size and report an error. + * + * fflush does "_flag |= _IOERR" so we don't need to check both the + # return from fflush and the ferror status. + */ + (void)fflush(malf); + if (ferror(malf)) { + printf("mail: %s: cannot append\n", file); + ftruncate(fd, oldsize); + fclose(malf); + return(0); + } + fclose(malf); + return(1); +} + +delex(i) +{ + sigset_t sigt; + + if (i != SIGINT) { + setsig(i, SIG_DFL); + sigemptyset(&sigt); + sigaddset(&sigt, i); + sigprocmask(SIG_UNBLOCK, &sigt, NULL); + } + putc('\n', stderr); + if (delflg) + longjmp(sjbuf, 1); + if (error == 0) + error = i; + done(); +} + +done() +{ + unlink(lettmp); + exit(error); +} + +cat(to, from1, from2) + char *to, *from1, *from2; +{ + register char *cp, *dp; + + cp = to; + for (dp = from1; *cp = *dp++; cp++) + ; + for (dp = from2; *cp++ = *dp++; ) + ; +} + +/* copy p... into s, update p */ +char * +getarg(s, p) + register char *s, *p; +{ + while (*p == ' ' || *p == '\t') + p++; + if (*p == '\n' || *p == '\0') + return(NULL); + while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0') + *s++ = *p++; + *s = '\0'; + return(p); +} + +safefile(f) + char *f; +{ + struct stat statb; + + if (lstat(f, &statb) < 0) + return (1); + if (statb.st_nlink != 1 || (statb.st_mode & S_IFMT) == S_IFLNK) { + fprintf(stderr, + "mail: %s has more than one link or is a symbolic link\n", + f); + return (0); + } + return (1); +} + +panic(msg, a1, a2, a3) + char *msg; +{ + fprintf(stderr, "mail: "); + fprintf(stderr, msg, a1, a2, a3); + fprintf(stderr, "\n"); + done(); +} diff --git a/src/cmd/make/Makefile b/src/cmd/make/Makefile new file mode 100644 index 0000000..59b202a --- /dev/null +++ b/src/cmd/make/Makefile @@ -0,0 +1,29 @@ +# Description file for the Make command +# Makefile 4.5 94/1/3 +TOPSRC = $(shell cd ../../..; pwd) +include $(TOPSRC)/target.mk +#include $(TOPSRC)/cross.mk + +CFLAGS += -Werror -Wall -I../ar -g +LDFLAGS += -g + +OBJS = main.o doname.o misc.o files.o dosys.o gram.o + +all: xmake + +xmake: ${OBJS} + ${CC} ${LDFLAGS} -o make.elf ${OBJS} ${LIBS} + ${OBJDUMP} -S make.elf > make.dis + ${SIZE} make.elf + ${ELF2AOUT} make.elf $@ && rm make.elf + +clean: + rm -f *.o *.elf xmake *.elf *.dis tags *~ gram.c + +install: all + install xmake $(DESTDIR)/bin/make + +gram.c: gram.y + $(YACC) gram.y + fgrep -v "static char yaccpar_sccsid" y.tab.c >gram.c + rm -f y.tab.c diff --git a/src/cmd/make/defs.h b/src/cmd/make/defs.h new file mode 100644 index 0000000..360257e --- /dev/null +++ b/src/cmd/make/defs.h @@ -0,0 +1,154 @@ +/* defs 4.10.1 1996/10/27 */ +#ifdef CROSS +# include +# include +#else +# include +# include +#endif +#include +#include + +#define SHELLCOM "/bin/sh" + +typedef long int TIMETYPE; + +/* to install metering, add a statement like + * #define METERFILE "/usr/sif/make/Meter" + * to turn metering on, set external variable meteron to 1. + */ + +/* define FSTATIC to be static on systems with C compilers + supporting file-static; otherwise define it to be null +*/ +#define FSTATIC static + +#define NO 0 +#define YES 1 + +#define unequal strcmp + +#define HASHSIZE 541 // 1021 +#define NLEFTS 80 // 512 +#define NCHARS 500 +#define NINTS 250 +#define INMAX 1350 // 7000 +#define OUTMAX 2300 // 7000 +#define MAXDIR 10 +#define QBUFMAX 5000 + +#define ALLDEPS 1 +#define SOMEDEPS 2 + +#define META 1 +#define TERMINAL 2 + +extern char funny[128]; + +#define ALLOC(x) (struct x *) ckalloc(sizeof(struct x)) + +extern int sigivalue; +extern int sigqvalue; +extern int wpid; +extern int dbgflag; +extern int prtrflag; +extern int silflag; +extern int noexflag; +extern int keepgoing; +extern int noruleflag; +extern int touchflag; +extern int questflag; +extern int ndocoms; +extern int ignerr; +extern int okdel; +extern int inarglist; +extern char *prompt; +extern int nopdir; +extern char junkname[]; +extern char *builtin[]; + +struct nameblock { + struct nameblock *nxtnameblock; + char *namep; + char *alias; + struct lineblock *linep; + int done:3; + int septype:3; + TIMETYPE modtime; +}; + +extern struct nameblock *mainname; +extern struct nameblock *firstname; + +struct lineblock { + struct lineblock *nxtlineblock; + struct depblock *depp; + struct shblock *shp; +}; +extern struct lineblock *sufflist; + +struct depblock { + struct depblock *nxtdepblock; + struct nameblock *depname; +}; + +struct shblock { + struct shblock *nxtshblock; + char *shbp; +}; + +struct varblock { + struct varblock *nxtvarblock; + char *varname; + char *varval; + int noreset:1; + int used:1; +}; +extern struct varblock *firstvar; + +struct pattern { + struct pattern *nxtpattern; + char *patval; +}; +extern struct pattern *firstpat; + +struct dirhdr { + struct dirhdr *nxtopendir; + DIR *dirfc; + char *dirn; +}; +extern struct dirhdr *firstod; + +struct chain { + struct chain *nextp; + char *datap; +}; + +extern char **linesptr; + +int yyparse (void); +void yyerror (char *s); +void enbint (void (*k)(int)); +void intrupt (int sig); +int eqsign (char *a); +void setvar (char *v, char *s); +void fatal (char *s); +void fatal1 (char *s, char *t); +struct varblock *varptr (char *v); +struct nameblock *srchname (char *s); +struct nameblock *makename (char *s); +int doname (struct nameblock *p, int reclevel, TIMETYPE *tval); +char *subst (char *a, char *b); +TIMETYPE exists (struct nameblock *pname); +void expand (struct depblock *q); +int dosys (char *comstring, int nohalt); +void touch (int force, char *name); +void fixname (char *s, char *d); +int suffix (char *a, char *b, char *p); +char *concat (char *a, char *b, char *c); +char *copys (char *s); +struct depblock *srchdir (char *pat, int mkchain, struct depblock *nextdbl); +int *ckalloc (int n); +struct chain *appendq (struct chain *head, char *tail); +char *mkqlist (struct chain *p); +TIMETYPE prestime (void); diff --git a/src/cmd/make/doname.c b/src/cmd/make/doname.c new file mode 100644 index 0000000..b665d3d --- /dev/null +++ b/src/cmd/make/doname.c @@ -0,0 +1,351 @@ +/* + * BASIC PROCEDURE. RECURSIVE. + * + * p->done = 0 don't know what to do yet + * p->done = 1 file in process of being updated + * p->done = 2 file already exists in current state + * p->done = 3 file make failed + */ +#include "defs.h" +#include +#include +#include + +extern char *sys_siglist[], arfile[], *arfname; + +int docom1(comstring, nohalt, noprint) + register char *comstring; + int nohalt, noprint; +{ + register int status; + + if (comstring[0] == '\0') + return(0); + + if (! silflag && (! noprint || noexflag)) { + printf("%s%s\n", (noexflag ? "" : prompt), comstring); + fflush(stdout); + } + if (noexflag) + return(0); + + status = dosys(comstring, nohalt); + if (status != 0) { + unsigned sig = status & 0177; + if (sig) { + if (sig < NSIG && sys_siglist[sig] != NULL && + *sys_siglist[sig] != '\0') + printf("*** %s", sys_siglist[sig]); + else + printf("*** Signal %d", sig); + if (status & 0200) + printf(" - core dumped"); + } else + printf("*** Exit %d", (status>>8) & 0xff); + + if (nohalt) + printf(" (ignored)\n"); + else + printf("\n"); + fflush(stdout); + } + return(status); +} + +int docom(q) + struct shblock *q; +{ + register char *s; + register int ign, nopr; + char string[OUTMAX]; + char string2[OUTMAX]; + + ++ndocoms; + if (questflag) + return(NO); + + if (touchflag) { + s = varptr("@")->varval; + if (! silflag) + printf("touch(%s)\n", s); + if (! noexflag) + touch(YES, s); + } else { + for (; q; q = q->nxtshblock) { + subst(q->shbp, string2); + fixname(string2, string); + + ign = ignerr; + nopr = NO; + for(s = string; *s=='-' || *s=='@'; ++s) { + if (*s == '-') + ign = YES; + else + nopr = YES; + } + + if (docom1(s, ign, nopr) && ! ign) { + if (keepgoing) + return(YES); + else + fatal((char *) NULL); + } + } + } + return(NO); +} + +int doname(p, reclevel, tval) + register struct nameblock *p; + int reclevel; + TIMETYPE *tval; +{ + int errstat; + u_char okdel1; + u_char didwork; + TIMETYPE td, td1, tdep, ptime, ptime1; + register struct depblock *q; + struct depblock *qtemp, *srchdir(), *suffp, *suffp1; + struct nameblock *p1, *p2; + struct shblock *implcom, *explcom; + register struct lineblock *lp; + struct lineblock *lp1, *lp2; + char *pnamep, *p1namep, *cp, *savenamep = NULL; + struct chain *qchain; + /* + * temp and sourcename are mutually exclusive - save 254 bytes of stack by + * reusing sourcename's buffer + */ + char sourcename[256], prefix[256], *temp = sourcename, concsuff[20]; + + { + /* + * VPATH= ${PATH1}:${PATH2} didn't work. This fix is so ugly I don't + * even want to think about it. Basically it grabs VPATH and + * explicitly does macro expansion before resolving names. Why + * VPATH didn't get handled correctly I have no idea; the symptom + * was that, while macro expansion got done, the .c files in the + * non-local directories wouldn't be found. + */ + static struct varblock *vpath_cp; + static char vpath_exp[256]; + + if (! vpath_cp) { + vpath_cp = varptr("VPATH"); + if (vpath_cp->varval) { + subst(vpath_cp->varval, vpath_exp); + setvar("VPATH", vpath_exp); + } + } + } + + if (p == 0) { + *tval = 0; + return(0); + } + + if (dbgflag) { + printf("doname(%s,%d)\n",p->namep,reclevel); + fflush(stdout); + } + + if (p->done > 0) { + *tval = p->modtime; + return(p->done == 3); + } + + errstat = 0; + tdep = 0; + implcom = 0; + explcom = 0; + ptime = exists(p); + ptime1 = 0; + didwork = NO; + p->done = 1; /* avoid infinite loops */ + + qchain = NULL; + + /* Expand any names that have embedded metacharaters */ + + for (lp = p->linep ; lp ; lp = lp->nxtlineblock) { + for (q = lp->depp ; q ; q=qtemp) { + qtemp = q->nxtdepblock; + expand(q); + } + } + + /* make sure all dependents are up to date */ + + for(lp = p->linep; lp; lp = lp->nxtlineblock) { + td = 0; + for (q = lp->depp; q; q = q->nxtdepblock) { + errstat += doname(q->depname, reclevel+1, &td1); + if (dbgflag) + printf("TIME(%s)=%ld\n", q->depname->namep, td1); + if (td1 > td) + td = td1; + if (ptime < td1) + qchain = appendq(qchain, q->depname->namep); + } + if (p->septype == SOMEDEPS) { + if (lp->shp != 0) { + if (ptimedepp==0) { + okdel1 = okdel; + okdel = NO; + setvar("@", p->namep); + setvar("?", mkqlist(qchain) ); + qchain = NULL; + if (! questflag) + errstat += docom(lp->shp); + setvar("@", (char *) NULL); + okdel = okdel1; + ptime1 = prestime(); + didwork = YES; + } + } + } else { + if (lp->shp != 0) { + if (explcom) + fprintf(stderr, "Too many command lines for `%s'\n", p->namep); + else + explcom = lp->shp; + } + + if (td > tdep) + tdep = td; + } + } + + /* Look for implicit dependents, using suffix rules */ + + if (index(p->namep, '(')) { + savenamep = p->namep; + p->namep = arfname; + } + + for(lp = sufflist ; lp ; lp = lp->nxtlineblock) { + for(suffp = lp->depp ; suffp ; suffp = suffp->nxtdepblock) { + pnamep = suffp->depname->namep; + if (suffix(p->namep, pnamep, prefix)) { + if (savenamep) + pnamep = ".a"; + + srchdir( concat(prefix,"*",temp), NO, (struct depblock *) NULL); + for(lp1 = sufflist ; lp1 ; lp1 = lp1->nxtlineblock) { + for(suffp1=lp1->depp ; suffp1 ; suffp1 = suffp1->nxtdepblock) { + p1namep = suffp1->depname->namep; + if ((p1=srchname(concat(p1namep, pnamep ,concsuff))) && + (p2=srchname(concat(prefix, p1namep ,sourcename)))) + { + errstat += doname(p2, reclevel+1, &td); + if (ptime < td) + qchain = appendq(qchain, p2->namep); + if (dbgflag) + printf("TIME(%s)=%ld\n", p2->namep, td); + if (td > tdep) + tdep = td; + setvar("*", prefix); + if (p2->alias) + setvar("<", copys(p2->alias)); + else + setvar("<", copys(p2->namep)); + for(lp2=p1->linep ; lp2 ; lp2 = lp2->nxtlineblock) { + implcom = lp2->shp; + if (implcom) + break; + } + goto endloop; + } + } + } + cp = rindex(prefix, '/'); + if (cp++ == 0) + cp = prefix; + setvar("*", cp); + } + } + } +endloop: + if (savenamep) + p->namep = savenamep; + + if (errstat==0 && (ptime 0) ? tdep : prestime(); + setvar("@", savenamep ? arfile : p->namep); + setvar("?", mkqlist(qchain) ); + if (explcom) { + errstat += docom(explcom); + } else if (implcom) { + errstat += docom(implcom); + } else if (p->septype == 0) { + p1 = srchname(".DEFAULT"); + if (p1) { + if (p->alias) + setvar("<", p->alias); + else + setvar("<", p->namep); + for (lp2 = p1->linep; lp2; lp2 = lp2->nxtlineblock) { + implcom = lp2->shp; + if (implcom) { + errstat += docom(implcom); + break; + } + } + } else if (keepgoing) { + printf("Don't know how to make %s\n", p->namep); + ++errstat; + } else + fatal1(" Don't know how to make %s", p->namep); + } + setvar("@", (char *) NULL); + if (noexflag || (ptime = exists(p)) == 0) + ptime = prestime(); + } + else if (errstat!=0 && reclevel==0) + printf("`%s' not remade because of errors\n", p->namep); + + else if (!questflag && reclevel==0 && didwork==NO) + printf("`%s' is up to date.\n", p->namep); + + if (questflag && reclevel==0) + exit(ndocoms>0 ? -1 : 0); + + p->done = (errstat ? 3 : 2); + if (ptime1 > ptime) + ptime = ptime1; + p->modtime = ptime; + *tval = ptime; + return(errstat); +} + +/* + * If there are any Shell meta characters in the name, + * expand into a list, after searching directory + */ +void expand(q) + register struct depblock *q; +{ + register char *s; + char *s1; + struct depblock *p; + + if (q->depname == NULL) + return; + s1 = q->depname->namep; + for (s=s1; ;) { + switch(*s++) { + case '\0': + return; + + case '*': + case '?': + case '[': + p = srchdir(s1, YES, q->nxtdepblock); + if (p) { + q->nxtdepblock = p; + q->depname = 0; + } + return; + } + } +} diff --git a/src/cmd/make/dosys.c b/src/cmd/make/dosys.c new file mode 100644 index 0000000..8c79a3e --- /dev/null +++ b/src/cmd/make/dosys.c @@ -0,0 +1,182 @@ +#include "defs.h" +#include +#include +#include +#include + +#define MAXARGV 254 /* execvp can only handle 254 anyhow */ + +int await() +{ + int status; + register int pid; + + enbint(SIG_IGN); + while ((pid = wait(&status)) != wpid) + if(pid == -1) + fatal("bad wait code"); + wpid = 0; + enbint(intrupt); + return(status); +} + +/* + * Close open directory files before exec'ing + */ +void doclose() +{ + register struct dirhdr *od; + + for (od = firstod; od; od = od->nxtopendir) { + if (od->dirfc != NULL) { + /* + * vfork kludge... + * we cannot call closedir since this will modify + * the parents data space; just call close directly. + */ + close(od->dirfc->dd_fd); + } + } +} + +int doexec(str) + register char *str; +{ + register char *t; + static char *argv[MAXARGV]; /* docom() ate most of the stack already */ + register char **p; + + while (*str==' ' || *str=='\t') + ++str; + if (*str == '\0') + return(-1); /* no command */ + + p = argv; + for (t = str; *t; ) { + if (p >= argv + MAXARGV) + fatal1("%s: Too many arguments.", str); + *p++ = t; + while (*t!=' ' && *t!='\t' && *t!='\0') + ++t; + if (*t) + for (*t++ = '\0'; *t==' ' || *t=='\t'; ++t) + ; + } + *p = NULL; + + wpid = vfork(); + if (wpid == 0) { + enbint(SIG_DFL); + doclose(); + enbint(intrupt); + execvp(str, argv); + fatal1("Cannot load %s",str); + } + return await(); +} + +int doshell(comstring, nohalt) + char *comstring; + int nohalt; +{ +#ifdef SHELLENV + char *shellcom = getenv("SHELL"); + char *shellstr; +#endif + wpid = vfork(); + if (wpid == 0) { + enbint(SIG_DFL); + doclose(); + +#ifdef SHELLENV + if (shellcom == 0) + shellcom = SHELLCOM; + shellstr = rindex(shellcom, '/') + 1; + execl(shellcom, shellstr, (nohalt ? "-c" : "-ce"), comstring, (char*)0); +#else + execl(SHELLCOM, "sh", (nohalt ? "-c" : "-ce"), comstring, (char*)0); +#endif + fatal("Couldn't load Shell"); + } + return await(); +} + +/* + * Are there are any Shell meta-characters? + */ +int metas(s) + register char *s; +{ + register int c; + + for (;;) { + c = *s++; + if (! c) + break; + if (funny[c] & META) + return c; + } + return 0; +} + +int dosys(comstring, nohalt) + register char *comstring; + int nohalt; +{ + register int status; + + if (metas(comstring)) + status = doshell(comstring, nohalt); + else + status = doexec(comstring); + + return(status); +} + +#include +#include + +void touch(force, name) + int force; + char *name; +{ + struct stat stbuff; + char junk[1]; + int fd; + + if (stat(name, &stbuff) < 0) { + if (force) + goto create; + fprintf(stderr, "touch: file %s does not exist.\n", name); + return; + } + + if(stbuff.st_size == 0) + goto create; + + fd = open(name, 2); + if (fd < 0) + goto bad; + + if (read(fd, junk, 1) < 1) { + close(fd); + goto bad; + } + lseek(fd, 0L, 0); + if (write(fd, junk, 1) < 1) { + close(fd); + goto bad; + } + close(fd); + return; + +bad: + fprintf(stderr, "Cannot touch %s\n", name); + return; + +create: + fd = creat(name, 0666); + if (fd < 0) + goto bad; + close(fd); +} diff --git a/src/cmd/make/files.c b/src/cmd/make/files.c new file mode 100644 index 0000000..bec38d4 --- /dev/null +++ b/src/cmd/make/files.c @@ -0,0 +1,547 @@ +#include "defs.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include "archive.h" /* from 'ar's directory */ + +/* UNIX DEPENDENT PROCEDURES */ + +/* DEFAULT RULES FOR UNIX */ + +char *builtin[] = { + ".SUFFIXES : .out .a .o .c .y .l .s .S", + "YACC=yacc", + "YFLAGS=", + "LEX=lex", + "LFLAGS=", + "CC=cc", + "AS=as", + "LD=ld", + "CFLAGS=", + "ASFLAGS=", + "LIBS=", + + ".c.a :", + "\t$(CC) $(CFLAGS) -c $<", + "\tar r $@ $*.o", + "\trm -f $*.o", + + ".c.o :", + "\t$(CC) $(CFLAGS) -c $<", + + ".S.o :", + "\t$(CC) $(ASFLAGS) -c $<", + + ".s.o :", + "\t$(AS) $(ASFLAGS) -o $@ $<", + + ".y.o :", + "\t$(YACC) $(YFLAGS) $<", + "\t$(CC) $(CFLAGS) -c y.tab.c", + "\trm y.tab.c", + "\tmv y.tab.o $@", + + ".l.o :", + "\t$(LEX) $(LFLAGS) $<", + "\t$(CC) $(CFLAGS) -c lex.yy.c", + "\trm lex.yy.c", + "\tmv lex.yy.o $@", + + ".y.c :", + "\t$(YACC) $(YFLAGS) $<", + "\tmv y.tab.c $@", + + ".l.c :", + "\t$(LEX) $(LFLAGS) $<", + "\tmv lex.yy.c $@", + + ".s.out .c.out .o.out :", + "\t$(CC) $(CFLAGS) $< $(LIBS) -o $@", + + ".y.out :", + "\t$(YACC) $(YFLAGS) $<", + "\t$(CC) $(CFLAGS) y.tab.c $(LIBS) -ly -o $@", + "\trm y.tab.c", + + ".l.out :", + "\t$(LEX) $(LFLAGS) $<", + "\t$(CC) $(CFLAGS) lex.yy.c $(LIBS) -ll -o $@", + "\trm lex.yy.c", + + 0 }; + +FSTATIC char nbuf[MAXNAMLEN + 1]; +FSTATIC char *nbufend = &nbuf[MAXNAMLEN]; + +char arfile[MAXPATHLEN]; +CHDR chdr; +char *arfname = chdr.name; +FILE *arfd; +off_t arpos; + +/* + * "borrowed" from 'ld' because we didn't want to drag in everything + * from 'ar'. The error checking was also ripped out, basically if any + * of the criteria for being an archive are not met then a -1 is returned + * and the rest of 'make' figures out what to do (bails out). + */ + +typedef struct ar_hdr HDR; + +/* Convert ar header field to an integer. */ +#define AR_ATOI(from, to, len, base) { \ + bcopy(from, buf, len); \ + buf[len] = '\0'; \ + to = strtoul(buf, (char **)NULL, base); \ +} + +int getarch() +{ + char hb[sizeof(HDR) + 1]; /* real header */ + register HDR *hdr; + register int len; + int nr; + register char *p; + char buf[20]; + + if (!arfd) + return(0); + fseek(arfd, arpos, 0); + + nr = fread(hb, 1, sizeof(HDR), arfd); + if (nr != sizeof(HDR)) + return(0); + + hdr = (HDR *)hb; + if (strncmp(hdr->ar_fmag, ARFMAG, sizeof(ARFMAG) - 1)) + return(0); + + /* 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] == ' ') + return(-1); + + /* + * 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) + return(-1); + nr = fread(chdr.name, 1, (size_t)len, arfd); + if (nr != len) + return(0); + chdr.name[len] = 0; + chdr.size -= len; + } else { + chdr.lname = 0; + bcopy(hdr->ar_name, chdr.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); +} + +void openarch(f) + register char *f; +{ + char magic[SARMAG]; + + arfd = fopen(f, "r"); + if (arfd == NULL) + return; + + fseek(arfd, 0L, 0); + fread(magic, SARMAG, 1, arfd); + arpos = SARMAG; + if (strncmp(magic, ARMAG, SARMAG)) + fatal1("%s is not an archive", f); +} + +void clarch() +{ + if (arfd) { + fclose (arfd); + arfd = 0; + } +} + +/* + * look inside archive for notation a(b) + * a(b) is file member b in archive a + */ +TIMETYPE lookarch(filename) + char *filename; +{ + char *p, *q, *send, s[MAXNAMLEN + 1]; + + for (p = filename; *p!= '(' ; ++p) + ; + *p = '\0'; + strcpy(arfile, filename); + openarch(filename); + *p++ = '('; + + send = s + sizeof(s); + + for( q = s; q < send && *p!='\0' && *p!=')' ; *q++ = *p++) + ; + *q++ = '\0'; + while (getarch()) { + if (! strcmp(arfname, s)) { + clarch(); + return(chdr.date); + } + arpos += (chdr.size + (chdr.size + (chdr.lname & 1))); + arpos += sizeof (struct ar_hdr); + } + strcpy(chdr.name, s); + clarch(); + return(0L); +} + +char *execat(s1, s2, si) + register char *s1, *s2; + char *si; +{ + register char *s; + + s = si; + while (*s1 && *s1 != ':' && *s1 != '-') + *s++ = *s1++; + if (si != s) + *s++ = '/'; + while (*s2) + *s++ = *s2++; + *s = '\0'; + return(*s1? ++s1: 0); +} + +/* + * findfl(name) (like execvp, but does path search and finds files) + */ +static char fname[128]; + +char *findfl(name) + register char *name; +{ + register char *p; + struct varblock *cp; + struct stat buf; + + for (p = name; *p; p++) + if(*p == '/') return(name); + + cp = varptr("VPATH"); + if(cp->varval == NULL || *cp->varval == 0) + p = ":"; + else + p = cp->varval; + + do { + p = execat(p, name, fname); + if(stat(fname,&buf) >= 0) + return(fname); + } while (p); + return((char *)-1); +} + +TIMETYPE exists(pname) + struct nameblock *pname; +{ + struct stat buf; + register char *s, *filename; + + filename = pname->namep; + + for(s = filename ; *s!='\0' && *s!='(' ; ++s) + ; + + if(*s == '(') + return(lookarch(filename)); + + if (stat(filename, &buf) >= 0) + return(buf.st_mtime); + + s = findfl(filename); + if (s != (char *)-1) { + pname->alias = copys(s); + if(stat(pname->alias, &buf) == 0) + return(buf.st_mtime); + } + return(0); +} + +TIMETYPE prestime() +{ + TIMETYPE t; + + time(&t); + return(t); +} + +static int amatch (char *s, char *p); + +static int umatch(s, p) + char *s, *p; +{ + if (*p == 0) + return 1; + while (*s) + if (amatch(s++, p)) + return 1; + return 0; +} + +/* + * stolen from glob through find + */ +static int amatch(s, p) + char *s, *p; +{ + register int cc, scc, k; + int c, lc; + + scc = *s; + lc = 077777; + c = *p; + switch (c) { + case '[': + k = 0; + while ((cc = *++p)) { + switch (cc) { + case ']': + if (k) + return amatch(++s, ++p); + else + return 0; + case '-': + k |= (lc <= scc) & (scc <= (cc = p[1])); + } + if (scc == (lc = cc)) + k++; + } + return 0; + + case '?': + caseq: + if (scc) + return amatch(++s, ++p); + return 0; + case '*': + return umatch(s, ++p); + case 0: + return ! scc; + } + if (c == scc) + goto caseq; + return 0; +} + +struct depblock *srchdir(pat, mkchain, nextdbl) + register char *pat; /* pattern to be matched in directory */ + int mkchain; /* nonzero if results to be remembered */ + struct depblock *nextdbl; /* final value for chain */ +{ + register DIR *dirf; + int cldir; + char *dirname, *dirpref, *endir, *filepat, *p, temp[MAXPATHLEN]; + char fullname[MAXPATHLEN], *p1, *p2; + struct nameblock *q; + struct depblock *thisdbl; + struct dirhdr *od; + struct pattern *patp; + struct varblock *cp, *varptr(); + char *path, pth[MAXPATHLEN], *strcpy(); + struct direct *dptr; + + thisdbl = 0; + + if (mkchain == NO) + for(patp=firstpat ; patp ; patp = patp->nxtpattern) + if (! unequal(pat, patp->patval)) + return(0); + + patp = ALLOC(pattern); + patp->nxtpattern = firstpat; + firstpat = patp; + patp->patval = copys(pat); + + endir = 0; + + for (p=pat; *p!='\0'; ++p) + if (*p == '/') + endir = p; + + if (endir == 0) { + dirpref = ""; + filepat = pat; + cp = varptr("VPATH"); + if (cp->varval == NULL) + path = "."; + else { + path = pth; + *path = '\0'; + /* + * expand VPATH; this is almost surely not the place to do + * this, but I have no intention whatsoever of attempting + * to understand this code. + */ + if (strncmp(cp->varval, ".:", 2) != 0) { + strcpy(pth,".:"); + subst(cp->varval, pth + 2); + } + else + subst(cp->varval, pth); + } + } else { + *endir = '\0'; + path = strcpy(pth, pat); + dirpref = concat(pat, "/", temp); + filepat = endir+1; + } + + while (*path) { /* Loop thru each VPATH directory */ + dirname = path; + for (; *path; path++) + if (*path == ':') { + *path++ = '\0'; + break; + } + + dirf = NULL; + cldir = NO; + + for (od = firstod; od; od = od->nxtopendir) + if (! unequal(dirname, od->dirn)) { + dirf = od->dirfc; + if (dirf != NULL) + rewinddir(dirf); /* start over at the beginning */ + break; + } + + if (dirf == NULL) { + dirf = opendir(dirname); + if (nopdir >= MAXDIR) + cldir = YES; + else { + ++nopdir; + od = ALLOC(dirhdr); + od->nxtopendir = firstod; + firstod = od; + od->dirfc = dirf; + od->dirn = copys(dirname); + fcntl(dirf->dd_fd, F_SETFD, 1); + } + } + + if (dirf == NULL) { + fprintf(stderr, "Directory %s: ", dirname); + fatal("Cannot open"); + } + else for (dptr = readdir(dirf); dptr != NULL; dptr = readdir(dirf)) { + p1 = dptr->d_name; + p2 = nbuf; + while ((p2nxtdepblock = nextdbl; + thisdbl->depname = q; + nextdbl = thisdbl; + } + } + } + + if (endir != 0) + *endir = '/'; + + if (cldir) { + closedir(dirf); + dirf = NULL; + } + } /* End of VPATH loop */ + return thisdbl; +} + +#ifdef METERFILE +#include + +int meteron = 0; /* default: metering off */ + +void meter(file) + char *file; +{ + TIMETYPE tvec; + char *p; + FILE *mout; + struct passwd *pwd; + + if (file == 0 || meteron == 0) + return; + + pwd = getpwuid(getuid()); + + time(&tvec); + + mout = fopen(file, "a"); + if (mout != NULL) { + p = ctime(&tvec); + p[16] = '\0'; + fprintf(mout, "User %s, %s\n", pwd->pw_name, p+4); + fclose(mout); + } +} +#endif + +/* + * copy s to d, changing file names to file aliases + */ +void fixname(s, d) + char *s, *d; +{ + register char *r, *q; + struct nameblock *pn; + char name[MAXPATHLEN]; + + while (*s) { + if (isspace(*s)) *d++ = *s++; + else { + r = name; + while (*s) { + if (isspace(*s)) break; + *r++ = *s++; + } + *r = '\0'; + + if (((pn = srchname(name)) != 0) && (pn->alias)) + q = pn->alias; + else q = name; + + while (*q) *d++ = *q++; + } + } + *d = '\0'; +} diff --git a/src/cmd/make/gram.y b/src/cmd/make/gram.y new file mode 100644 index 0000000..19ca8ee --- /dev/null +++ b/src/cmd/make/gram.y @@ -0,0 +1,288 @@ +%{ +#include "defs.h" +%} + +%term NAME SHELLINE START MACRODEF COLON DOUBLECOLON GREATER +%union + { + struct shblock *yshblock; + struct depblock *ydepblock; + struct nameblock *ynameblock; + } + +%type SHELLINE, shlist, shellist +%type NAME, namelist +%type deplist, dlist + +%% + +%{ +struct depblock *pp; +FSTATIC struct shblock *prevshp; + +FSTATIC struct nameblock *lefts[NLEFTS]; +struct nameblock *leftp; +FSTATIC int nlefts; + +struct lineblock *lp, *lpp; +FSTATIC struct depblock *prevdep; +FSTATIC int sepc; +%} + +file: + | file comline + ; + +comline: START + | MACRODEF + | START namelist deplist shellist = { + while ( --nlefts >= 0) + { + leftp = lefts[nlefts]; + if (leftp->septype == 0) + leftp->septype = sepc; + else if (leftp->septype != sepc) + fprintf(stderr, "Inconsistent rules lines for `%s'\n", + leftp->namep); + else if (sepc==ALLDEPS && *(leftp->namep)!='.' && $4!=0) + { + for (lp=leftp->linep; lp->nxtlineblock!=0; lp=lp->nxtlineblock) + if (lp->shp) + fprintf(stderr, "Multiple rules lines for `%s'\n", + leftp->namep); + } + + lp = ALLOC(lineblock); + lp->nxtlineblock = NULL; + lp->depp = $3; + lp->shp = $4; + + if (! unequal(leftp->namep, ".SUFFIXES") && $3==0) + leftp->linep = 0; + else if(leftp->linep == 0) + leftp->linep = lp; + else { + for (lpp = leftp->linep; lpp->nxtlineblock; + lpp = lpp->nxtlineblock) ; + if (sepc==ALLDEPS && leftp->namep[0]=='.') + lpp->shp = 0; + lpp->nxtlineblock = lp; + } + } + } + | error + ; + +namelist: NAME = { lefts[0] = $1; nlefts = 1; } + | namelist NAME = { lefts[nlefts++] = $2; + if (nlefts>=NLEFTS) fatal("Too many lefts"); } + ; + +deplist: + { + char junk[10]; + sprintf(junk, "%d", yylineno); + fatal1("Must be a separator on rules line %s", junk); + } + | dlist + ; + +dlist: sepchar = { prevdep = 0; $$ = 0; } + | dlist NAME = { + pp = ALLOC(depblock); + pp->nxtdepblock = NULL; + pp->depname = $2; + if(prevdep == 0) $$ = pp; + else prevdep->nxtdepblock = pp; + prevdep = pp; + } + ; + +sepchar: COLON = { sepc = ALLDEPS; } + | DOUBLECOLON = { sepc = SOMEDEPS; } + ; + +shellist: = {$$ = 0; } + | shlist = { $$ = $1; } + ; + +shlist: SHELLINE = { $$ = $1; prevshp = $1; } + | shlist SHELLINE = { $$ = $1; + prevshp->nxtshblock = $2; + prevshp = $2; + } + ; + +%% + +char *zznextc; /* zero if need another line; otherwise points to next char */ +int yylineno; +extern FILE * fin; + +int retsh(q) +char *q; +{ + register char *p; + struct shblock *sp; + char *copys(); + + for(p=q+1 ; *p==' '||*p=='\t' ; ++p) ; + + sp = ALLOC(shblock); + sp->nxtshblock = NULL; + sp->shbp = (fin == NULL) ? p : copys(p); + yylval.yshblock = sp; + zznextc = 0; + return(SHELLINE); +} + +int nextlin() +{ + static char yytext[INMAX]; + static char *yytextl = yytext+INMAX; + char *text, templin[INMAX]; + register char c; + register char *p, *t; + char lastch, *lastchp; + int incom; + int kc; + +again: + incom = NO; + zznextc = 0; + + if (fin == NULL) { + text = *linesptr++; + if (text == 0) + return(0); + ++yylineno; + } else { + for (p = text = yytext; p') { + ++zznextc; + return(GREATER); + } + + if (*zznextc == ';') + return retsh(zznextc); + + p = zznextc; + q = word; + + while (! (funny[(int)*p] & TERMINAL)) + *q++ = *p++; + + if (p != zznextc) { + *q = '\0'; + if((yylval.ynameblock=srchname(word))==0) + yylval.ynameblock = makename(word); + zznextc = p; + return(NAME); + } else { + fprintf(stderr,"Bad character %c (octal %o), line %d", + *zznextc,*zznextc,yylineno); + fatal( (char *) NULL ); + } + return(0); /* never executed */ +} diff --git a/src/cmd/make/history.txt b/src/cmd/make/history.txt new file mode 100644 index 0000000..02939d7 --- /dev/null +++ b/src/cmd/make/history.txt @@ -0,0 +1,98 @@ +/* +2.1 4/24/76 Base version + +2.2 4/26/76 Error found by SRB in overriding pattern rules; + corrected gram.y + +2.3 4/27/76 Further correction for overriding pattern rules; + corrected doname.c + +2.4 Removed .CLEAR name, added .IGNORE. + A .SUFFIXES rule without dependents clears the list + +2.5 Stripped output + +2.6 Changed doshell to accomodate new shell. + +2.7 Following SRB's sugestion, added ${...} as + alternate macro name + +2.8 Defined macros AS and DTGEN in files.c. + +2.9 Put in a fix to prevent removal of files + upon interrupt in a :: rule. + +2.10 Fixed bugs involving messages for :: + and closing standard input + +2.11 Changed time test from <= to < + (equal times are considered in sync) + +2.12 Installed -t flag (touch and update time of + files rather than issue commands) + Fixed bug in dosys + +2.13 Fixed lex.c to allow sharps (#) in commands + +2.14 Added .DEFAULT rule + +2.15 Changed to I/O System (stdio.h) + +2.16 Removed references to double floats and macro HAVELONGS; + committed to use of long ints for times. +2.17 Corrected metacharacter list in dosys.c. +2.18 Miscellaneous fixes +2.19 Updated files.c to use include file stat.h +2.20 Added -q flag for Mike Lesk +2.21 Added AWK rules and .w suffix to files.c +2.22 Added colon to the list of metacharacters +2.23 Macro substitutions on dependency lines. + Redid argument and macro setting. + Close files before exec'ing. + Print > at beginning of command lines. + No printing of commands beginnng with @. +2.24 Parametrized propt sequence in doname.c (4/1/77) +2.25 Added $? facility +2.26 Fixed bug in macro expansion +2.27 Repaired interrupt handling +2.28 Repaired bug in -n +2.29 Repaired bug in file closing and $? string creation +2.30 Repaired bug in grammar about command lines +2.31 Added -k flag, modified doname.c and defs +2.32 Made "keepgoing" the default, added -S flag, + changed handling of funny characters internally +2.3 Small fixups to interrupt and quit handling. + Changed default back to -k. +2.34 Added .PRECIOUS rule for interrupts +2.35 Added references to include files (due to TLL) +2.36 Fixed bug in lex.c so = permitted in rules on :; line +2.37 Miscellaneous code cleanups +2.38 Sleep one second after each touch in -t mode +2.39 Extended string[] declaration in doname.c +2.40 Permit recursive macro references +2.41 Separated YYLMAX into INMAX and OUTMAX macros, specifying longest + input and output lines respectively. +2.42 Fixed bug involving :: lines without dependents +2.43 Main name is first name that contains a slash or doesn't + begin with a dot +2.44 Fixed bug involving $$ on command line +2.45 Changed files.c to put .f before .e, .r and to use f77 instead of fc. +2.46 Changed dosys.c to eliminate copying and to call execvp. +2.47 Changed files.c to add ".out" suffix and rules. +2.48 Changed misc.c to permit tabs preceding = in macro definition +2.49 Added reference to . Removed -lS references from files.c +2.50 General cleanup to reduce lint messages. (changes in declarations + and in uses of variables) +2.51 Further cleanup making use of new Yacc features. +2.52 +2.53 Changed handling of "touch" +2.54 Fixed bug involving comments in lexical analyzer. +2.55 Ignore commands that begin with a # are comments. +2.56 Added = to list of META characters (to permit shell commands) +2.57 Changed lookarch and getobj to fix bugs. +2.58 Fixed interrupt handling. +2.59 Changed references to sprintf to accomodate new function definition + Also fixed extern declarations. +2.60 Limited the number of open directories. +2.61 Added code to handle archives with ascii headers. +*/ diff --git a/src/cmd/make/main.c b/src/cmd/make/main.c new file mode 100644 index 0000000..fb08b58 --- /dev/null +++ b/src/cmd/make/main.c @@ -0,0 +1,395 @@ +/* + * command make to update programs. + * Flags: + * 'd' print out debugging comments + * 'p' print out a version of the input graph + * 's' silent mode--don't print out commands + * 'f' the next argument is the name of the description file; + * "makefile" is the default + * 'i' ignore error codes from the shell + * 'S' stop after any command fails (normally do parallel work) + * 'n' don't issue, just print, commands + * 't' touch (update time of) files but don't issue command + * 'q' don't do anything, but check if object is up to date; + * returns exit code 0 if up to date, -1 if not + * 'e' environment variables have precedence over makefiles + */ +#include "defs.h" +#include +#include +#include +#include +#include +#ifdef CROSS +# include +#else +# include +#endif + +struct nameblock *mainname = NULL; +struct nameblock *firstname = NULL; +struct lineblock *sufflist = NULL; +struct varblock *firstvar = NULL; +struct pattern *firstpat = NULL; +struct dirhdr *firstod = NULL; + +int sigivalue = 0; +int sigqvalue = 0; +int wpid = 0; + +int dbgflag = NO; +int prtrflag = NO; +int silflag = NO; +int noexflag = NO; +int keepgoing = NO; +int noruleflag = NO; +int touchflag = NO; +int questflag = NO; +int ndocoms = NO; +int ignerr = NO; /* default is to stop on error */ +int okdel = YES; +int doenvlast = NO; +int inarglist; +char *prompt = ""; /* other systems -- pick what you want */ +int nopdir = 0; + +char junkname[20]; +char funny[128]; +char options[26 + 1] = { '-' }; + +char **linesptr = builtin; + +FILE * fin; +int firstrd = 0; + +extern char **environ; + +int isprecious(p) +char *p; +{ + register struct lineblock *lp; + register struct depblock *dp; + register struct nameblock *np; + + np = srchname(".PRECIOUS"); + if (np) + for (lp = np->linep ; lp ; lp = lp->nxtlineblock) + for (dp = lp->depp ; dp ; dp = dp->nxtdepblock) + if (! unequal(p, dp->depname->namep)) + return YES; + + return NO; +} + +void intrupt (sig) + int sig; +{ + char *p; + struct stat sbuf; + + if (okdel && !noexflag && !touchflag && + (p = varptr("@")->varval) && + (stat(p, &sbuf) >= 0 && (sbuf.st_mode&S_IFMT) == S_IFREG) && + ! isprecious(p)) + { + fprintf(stderr, "\n*** %s removed.", p); + unlink(p); + } + + if (junkname[0]) + unlink(junkname); + fprintf(stderr, "\n"); + exit(2); +} + +int rdd1(k) + FILE * k; +{ + extern int yylineno; + extern char *zznextc; + + fin = k; + yylineno = 0; + zznextc = 0; + + if (yyparse()) + fatal("Description file error"); + + if(fin != NULL && fin != stdin) + fclose(fin); + + return(0); +} + +void readenv() +{ + register char **ep, *p; + + for(ep=environ; *ep; ++ep) { + for (p = *ep; *p; p++) { + if (isalnum(*p)) + continue; + if (*p == '=') { + eqsign(*ep); + } + break; + } + } +} + +/* + * read and parse description + */ +int rddescf(descfile) + char *descfile; +{ + FILE * k; + + if (! firstrd++) { + if (! noruleflag) + rdd1 ((FILE *) NULL); + + if (doenvlast == NO) + readenv(); + } + if (! unequal(descfile, "-")) + return rdd1(stdin); + + k = fopen(descfile, "r"); + if (k != NULL) + return rdd1(k); + + return(1); +} + +/* + * This is done in a function by itself because 'uname()' uses a 640 + * structure which we do not want permanently allocated on main()'s stack. + */ +void setmachine() +{ + struct utsname foo; + + if (uname(&foo) < 0) + strcpy(foo.machine, "?"); + setvar("MACHINE", foo.machine); +} + +void printdesc(prntflag) + int prntflag; +{ + struct nameblock *p; + struct depblock *dp; + struct varblock *vp; + struct dirhdr *od; + struct shblock *sp; + struct lineblock *lp; + + if (prntflag) { + printf("Open directories:\n"); + for (od = firstod; od; od = od->nxtopendir) + printf("\t%d: %s\n", od->dirfc->dd_fd, od->dirn); + } + + if (firstvar != 0) + printf("Macros:\n"); + for (vp = firstvar; vp ; vp = vp->nxtvarblock) + printf("\t%s = %s\n", vp->varname, vp->varval); + + for (p = firstname; p; p = p->nxtnameblock) { + printf("\n\n%s", p->namep); + if (p->linep != 0) + printf(":"); + if (prntflag) + printf(" done=%d",p->done); + if (p == mainname) + printf(" (MAIN NAME)"); + for (lp = p->linep ; lp ; lp = lp->nxtlineblock) { + dp = lp->depp; + if (dp != 0) { + printf("\n depends on:"); + for (; dp ; dp = dp->nxtdepblock) + if (dp->depname != 0) + printf(" %s ", dp->depname->namep); + } + + sp = lp->shp; + if (sp != 0) { + printf("\n commands:\n"); + for (; sp != 0; sp = sp->nxtshblock) + printf("\t%s\n", sp->shbp); + } + } + } + printf("\n"); + fflush(stdout); +} + +void enbint(k) + void (*k)(int); +{ + if (sigivalue == 0) + signal(SIGINT,k); + if (sigqvalue == 0) + signal(SIGQUIT,k); +} + +int main(argc, argv) + int argc; + char *argv[]; +{ + register struct nameblock *p; + register int i, j; + int descset, nfargs; + TIMETYPE tjunk; + char c, *s; + static char onechar[2] = "X\0"; + char *op = options + 1; + +#ifdef METERFILE + meter(METERFILE); +#endif + + descset = 0; + + funny['\0'] = (META | TERMINAL); + for(s = "=|^();&<>*?[]:$`'\"\\\n" ; *s ; ++s) + funny[(int)*s] |= META; + for(s = "\n\t :;&>|" ; *s ; ++s) + funny[(int)*s] |= TERMINAL; + + inarglist = 1; + for(i=1; i= argc-1) + fatal("No description argument after -f flag"); + if (rddescf(argv[i+1]) != 0) + fatal1("Cannot open %s", argv[i+1]); + argv[i+1] = 0; + ++descset; + break; + + case 'e': + doenvlast = YES; + break; + + default: + onechar[0] = c; /* to make lint happy */ + fatal1("Unknown flag argument %s", onechar); + } + } + argv[i] = 0; + } + } + *op++ = '\0'; + if (strcmp(options, "-") == 0) + *options = '\0'; + setvar("MFLAGS", options); /* MFLAGS=options to make */ + + setmachine(); + + if (! descset) { + if (rddescf("makefile")) + rddescf("Makefile"); + } + if (doenvlast == YES) + readenv(); + + if (prtrflag) + printdesc(NO); + + if (srchname(".IGNORE")) + ++ignerr; + if (srchname(".SILENT")) + silflag = 1; + p = srchname(".SUFFIXES"); + if (p != 0) + sufflist = p->linep; + if (! sufflist) + fprintf(stderr,"No suffix list.\n"); + + sigivalue = (int) signal(SIGINT, SIG_IGN) & 01; + sigqvalue = (int) signal(SIGQUIT, SIG_IGN) & 01; + enbint(intrupt); + + nfargs = 0; + + for(i=1; i +#include + +FSTATIC struct nameblock *hashtab[HASHSIZE]; +FSTATIC int nhashed = 0; + +/* + * simple linear hash. hash function is sum of + * characters mod hash table size. + */ +int hashloc(s) + char *s; +{ + register int i; + register int hashval; + register char *t; + + hashval = 0; + + for(t=s; *t!='\0' ; ++t) + hashval += *t; + + hashval %= HASHSIZE; + + for(i=hashval; + hashtab[i]!=0 && unequal(s,hashtab[i]->namep); + i = (i+1)%HASHSIZE ) ; + + return(i); +} + +struct nameblock *srchname(s) + char *s; +{ + return( hashtab[hashloc(s)] ); +} + +int hasslash(s) + char *s; +{ + for (; *s; ++s) + if (*s == '/') + return(YES); + return(NO); +} + +struct nameblock *makename(s) + char *s; +{ + /* make a fresh copy of the string s */ + register struct nameblock *p; + + if (nhashed++ > HASHSIZE-3) + fatal("Hash table overflow"); + + p = ALLOC(nameblock); + p->nxtnameblock = firstname; + p->namep = copys(s); + p->linep = 0; + p->done = 0; + p->septype = 0; + p->modtime = 0; + + firstname = p; + if (mainname == NULL) + if (s[0]!='.' || hasslash(s)) + mainname = p; + + hashtab[hashloc(s)] = p; + + return(p); +} + +char *copys(s) + register char *s; +{ + register char *t, *t0; + + t = t0 = calloc(strlen(s) + 1, sizeof(char)); + if (t == NULL) + fatal("out of memory"); + while ((*t++ = *s++)) + ; + return(t0); +} + +/* + * c = concatenation of a and b + */ +char *concat(a, b, c) + register char *a, *b; + char *c; +{ + register char *t; + t = c; + + while ((*t = *a++)) + t++; + while ((*t++ = *b++)); + return c; +} + +/* + * is b the suffix of a? if so, set p = prefix + */ +int suffix(a, b, p) + register char *a, *b, *p; +{ + char *a0 = a, *b0 = b; + + while (*a++); + while (*b++); + + if ((a - a0) < (b - b0)) + return 0; + + while (b > b0) + if (*--a != *--b) + return 0; + + while (a0 < a) + *p++ = *a0++; + *p = '\0'; + return 1; +} + +int *ckalloc(n) + register int n; +{ + register int *p; + + p = (int *) calloc(1,n); + if (! p) + fatal("out of memory"); + + return p; +} + +/* + * copy string a into b, substituting for arguments + */ +char *subst(a,b) + register char *a,*b; +{ + static int depth = 0; + register char *s; + char vname[BUFSIZ]; + struct varblock *vbp; + char closer; + + if (++depth > 100) + fatal("infinitely recursive macro?"); + if (a != 0) { + while(*a) { + if (*a != '$') + *b++ = *a++; + else if (*++a=='\0' || *a=='$') + *b++ = *a++; + else { + s = vname; + if (*a=='(' || *a=='{') { + closer = (*a == '(') ? ')' : '}'; + ++a; + while (*a == ' ') + ++a; + while (*a!=' ' && *a!=closer && *a!='\0') + *s++ = *a++; + while (*a!=closer && *a!='\0') + ++a; + if (*a == closer) + ++a; + } else + *s++ = *a++; + + *s = '\0'; + vbp = varptr(vname); + if (vbp->varval != 0) { + b = subst(vbp->varval, b); + vbp->used = YES; + } + } + } + } + *b = '\0'; + --depth; + return(b); +} + +void setvar(v, s) + char *v, *s; +{ + struct varblock *p; + + p = varptr(v); + if (p->noreset == 0) { + p->varval = s; + p->noreset = inarglist; + if (p->used && unequal(v, "@") && unequal(v, "*") + && unequal(v, "<") && unequal(v, "?")) + fprintf(stderr, "Warning: %s changed after being used\n", v); + } +} + +/* + * look for arguments with equal signs but not colons + */ +int eqsign(a) + char *a; +{ + register char *s, *t, *b; + char buf[256]; + + while (*a == ' ') + ++a; + for (s=a; *s!='\0' && *s!=':'; ++s) { + if (*s == '=') { + b = buf; + for (t = a; *t!='=' && *t!=' ' && *t!='\t'; t++) + *b++ = *t; + *b = '\0'; + + for (++s; *s==' ' || *s=='\t'; ++s); + setvar(buf, copys(s)); + return(YES); + } + } + return(NO); +} + +struct varblock *varptr(v) + char *v; +{ + register struct varblock *vp; + + for (vp = firstvar; vp ; vp = vp->nxtvarblock) + if (! unequal(v, vp->varname)) + return(vp); + + vp = ALLOC(varblock); + vp->nxtvarblock = firstvar; + firstvar = vp; + vp->varname = copys(v); + vp->varval = 0; + return(vp); +} + +void fatal1(s, t) + char *s, *t; +{ + char buf[BUFSIZ]; + + sprintf(buf, s, t); + fatal(buf); +} + +void fatal(s) + char *s; +{ + if (s) + fprintf(stderr, "Make: %s. Stop.\n", s); + else + fprintf(stderr, "\nStop.\n"); + exit(1); +} + +void yyerror(s) + char *s; +{ + char buf[50]; + extern int yylineno; + + sprintf(buf, "line %d: %s", yylineno, s); + fatal(buf); +} + +struct chain *appendq(head, tail) + struct chain *head; + char *tail; +{ + register struct chain *p, *q; + + p = ALLOC(chain); + p->datap = tail; + + if (! head) + return(p); + for(q = head ; q->nextp ; q = q->nextp) + ; + q->nextp = p; + return(head); +} + +char *mkqlist(p) + struct chain *p; +{ + register char *qbufp, *s; + static char qbuf[QBUFMAX]; + + if (p == NULL) { + qbuf[0] = '\0'; + return 0; + } + + qbufp = qbuf; + + for (; p; p = p->nextp) { + s = p->datap; + if (qbufp+strlen(s) > &qbuf[QBUFMAX-3]) { + fprintf(stderr, "$? list too long\n"); + break; + } + while (*s) + *qbufp++ = *s++; + *qbufp++ = ' '; + } + *--qbufp = '\0'; + return qbuf; +} diff --git a/src/cmd/man/Makefile b/src/cmd/man/Makefile new file mode 100644 index 0000000..216eb49 --- /dev/null +++ b/src/cmd/man/Makefile @@ -0,0 +1,63 @@ +# +# Copyright (c) 1987 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. +# +TOPSRC = $(shell cd ../../..; pwd) +include $(TOPSRC)/target.mk + +CFLAGS += -Werror + +SRCS = man.c +OBJS = man.o + +all: man apropos + +man: ${OBJS} + ${CC} ${LDFLAGS} -o man.elf ${OBJS} ${LIBS} + ${OBJDUMP} -S man.elf > man.dis + ${SIZE} man.elf + ${ELF2AOUT} man.elf $@ && rm man.elf + +apropos: ${OBJS} + ${CC} ${LDFLAGS} -o apropos.elf ${OBJS} ${LIBS} + ${OBJDUMP} -S apropos.elf > apropos.dis + ${SIZE} apropos.elf + ${ELF2AOUT} apropos.elf $@ && rm apropos.elf + +clean: + rm -f *.o *.elf ${MAN} man apropos *.elf *.dis tags *~ + +depend: FRC + mkdep ${CFLAGS} ${ASRCS} ${MSRCS} + +install: all + @rm -f ${DESTDIR}/bin/whatis ${DESTDIR}/bin/apropos + install apropos ${DESTDIR}/bin/apropos + install man ${DESTDIR}/bin/man + ln ${DESTDIR}/bin/apropos ${DESTDIR}/bin/whatis + +lint: FRC + lint ${CFLAGS} ${ASRCS} + lint ${CFLAGS} ${MSRCS} + +tags: FRC + ctags ${ASRCS} + ctags ${MSRCS} + sort -o tags tags + +FRC: + +# DO NOT DELETE THIS LINE -- mkdep uses it. +# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY. diff --git a/src/cmd/man/apropos.c b/src/cmd/man/apropos.c new file mode 100644 index 0000000..a9b7c4f --- /dev/null +++ b/src/cmd/man/apropos.c @@ -0,0 +1,206 @@ +/* + * Copyright (c) 1987 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. + */ +#include +#include +#include +#include +#include + +#define MAXLINELEN 1000 /* max line handled */ +#define WHATIS "whatis" /* database name */ + +#define NO 0 /* no/false */ +#define YES 1 /* yes/true */ + +static char *myname; + +main(argc, argv) + int argc; + char **argv; +{ + extern char *optarg; + extern int optind; + register char *beg, *end, **C; + int ch, foundman = NO, *found, isapropos; + int a_match(), w_match(), (*match)(); + char *manpath = NULL, buf[MAXLINELEN + 1], fname[MAXPATHLEN + 1]; + char wbuf[MAXLINELEN + 1], *getenv(), *malloc(); + + myname = (beg = rindex(*argv, '/')) ? beg + 1 : *argv; + if (!strcmp(myname, "apropos")) { + isapropos = YES; + match = a_match; + } + else { + isapropos = NO; + match = w_match; + } + while ((ch = getopt(argc, argv, "M:P:")) != EOF) + switch((char)ch) { + case 'M': + case 'P': /* backward contemptible */ + manpath = optarg; + break; + case '?': + default: + usage(); + } + argv += optind; + argc -= optind; + if (argc < 1) + usage(); + + if (!(manpath = getenv("MANPATH"))) + manpath = _PATH_MAN; + + /*NOSTRICT*/ + if (!(found = (int *)malloc((u_int)argc))) { + fprintf(stderr, "%s: out of space.\n", myname); + exit(1); + } + bzero((char *)found, argc * sizeof(int)); + + if (isapropos) + for (C = argv; *C; ++C) /* convert to lower-case */ + lowstr(*C, *C); + else for (C = argv; *C; ++C) /* trim full paths */ + if (beg = rindex(*C, '/')) + *C = beg + 1; + + for (beg = manpath; beg; beg = end) { /* through path list */ + end = index(beg, ':'); + if (!end) + (void)sprintf(fname, "%s/%s", beg, WHATIS); + else { + (void)sprintf(fname, "%.*s/%s", end - beg, beg, WHATIS); + ++end; + } + if (!freopen(fname, "r", stdin)) + continue; + + /* for each file found */ + for (foundman = YES; gets(buf);) { + if (isapropos) + lowstr(buf, wbuf); + else + dashtrunc(buf, wbuf); + for (C = argv; *C; ++C) + if ((*match)(wbuf, *C)) { + puts(buf); + found[C - argv] = YES; + + /* only print line once */ + while (*++C) + if ((*match)(wbuf, *C)) + found[C - argv] = YES; + break; + } + } + } + if (!foundman) { + fprintf(stderr, "%s: no %s file found in %s.\n", myname, WHATIS, manpath); + exit(1); + } + for (C = argv; *C; ++C) + if (!found[C - argv]) + printf("%s: %s\n", *C, isapropos ? "nothing appropriate" : "not found"); +} + +/* + * a_match -- + * match for apropos; anywhere the string appears + */ +static +a_match(bp, str) + register char *bp, *str; +{ + register int len; + register char test; + + if (!*bp) + return(NO); + /* backward compatible: everything matches empty string */ + if (!*str) + return(YES); + for (test = *str++, len = strlen(str); *bp;) + if (test == *bp++ && !strncmp(bp, str, len)) + return(YES); + return(NO); +} + +/* + * w_match -- + * match for whatis; looks for full word match + */ +static +w_match(bp, str) + register char *bp, *str; +{ + register int len; + register char *start; + + if (!*str || !*bp) + return(NO); + for (len = strlen(str);;) { + for (; *bp && !isdigit(*bp) && !isalpha(*bp); ++bp); + if (!*bp) + break; + for (start = bp++; *bp && (isdigit(*bp) || isalpha(*bp)); ++bp); + if (bp - start == len && !strncasecmp(start, str, len)) + return(YES); + } + return(NO); +} + +/* + * dashtrunc -- + * truncate a string at " - " + */ +static +dashtrunc(from, to) + register char *from, *to; +{ + do { + if (from[0] == ' ' && from[1] == '-' && from[2] == ' ') + break; + } while (*to++ = *from++); + *to = '\0'; +} + +/* + * lowstr -- + * convert a string to lower case + */ +static +lowstr(from, to) + register char *from, *to; +{ + do { + *to++ = isupper(*from) ? tolower(*from) : *from; + } while (*from++); +} + +/* + * usage -- + * print usage message and die + */ +static +usage() +{ + fprintf(stderr, "usage: %s [-M path] string ...\n", myname); + exit(1); +} diff --git a/src/cmd/man/man.c b/src/cmd/man/man.c new file mode 100644 index 0000000..bc27f92 --- /dev/null +++ b/src/cmd/man/man.c @@ -0,0 +1,447 @@ +/* + * Copyright (c) 1987 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. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define NEW_PATH "/new/man" + +#define NO 0 +#define YES 1 + +static char *command, /* command buffer */ + *defpath, /* default search path */ + *locpath, /* local search path */ + *machine, /* machine type */ + *manpath, /* current search path */ + *newpath, /* new search path */ + *pager, /* requested pager */ + how; /* how to display */ + +#define ALL 0x1 /* show all man pages */ +#define CAT 0x2 /* copy file to stdout */ +#define WHERE 0x4 /* just tell me where */ + +typedef struct { + char *name, *msg; +} MANDIR; + +static MANDIR list1[] = { /* section one list */ + "cat1", "1st", "cat8", "8th", "cat6", "6th", + "cat.old", "old", NULL, NULL, +}; + +static MANDIR list2[] = { /* rest of the list */ + "cat2", "2nd", "cat3", "3rd", "cat4", "4th", + "cat5", "5th", "cat7", "7th", "cat3f", "3rd (F)", + NULL, NULL, +}; + +static MANDIR list3[2]; /* single section */ + +/* + * cat -- + * cat out the file + */ +static +cat(fname) + char *fname; +{ + register int fd, n; + char buf[BUFSIZ]; + + if (!(fd = open(fname, O_RDONLY, 0))) { + perror("man: open"); + exit(1); + } + while ((n = read(fd, buf, sizeof(buf))) > 0) + if (write(1, buf, n) != n) { + perror("man: write"); + exit(1); + } + if (n == -1) { + perror("man: read"); + exit(1); + } + (void)close(fd); +} + +/* + * add -- + * add a file name to the list for future paging + */ +static +add(fname) + char *fname; +{ + static u_int buflen; + static int len; + static char *cp; + int flen; + + if (!command) { + if (!(command = malloc(buflen = 1024))) { + fputs("man: out of space.\n", stderr); + exit(1); + } + len = strlen(strcpy(command, pager)); + cp = command + len; + } + flen = strlen(fname); + if (len + flen + 2 > buflen) { /* +2 == space, EOS */ + if (!(command = realloc(command, buflen += 1024))) { + fputs("man: out of space.\n", stderr); + exit(1); + } + cp = command + len; + } + *cp++ = ' '; + len += flen + 1; /* +1 = space */ + (void)strcpy(cp, fname); + cp += flen; +} + +/* + * manual -- + * given a directory list and a file name find a file that + * matches; check ${directory}/${dir}/{file name} and + * ${directory}/${dir}/${machine}/${file name}. + */ +static +manual(section, name) + MANDIR *section; + char *name; +{ + register char *beg, *end; + register MANDIR *dp; + register int res; + char fname[MAXPATHLEN + 1], *index(); + + if (strlen(name) > MAXNAMLEN-2) /* leave room for the ".0" */ + name[MAXNAMLEN-2] = '\0'; + for (beg = manpath, res = 0;; beg = end + 1) { + if (end = index(beg, ':')) + *end = '\0'; + for (dp = section; dp->name; ++dp) { + (void)sprintf(fname, "%s/%s/%s.0", beg, dp->name, name); + if (access(fname, R_OK)) { + (void)sprintf(fname, "%s/%s/%s/%s.0", beg, + dp->name, machine, name); + if (access(fname, R_OK)) + continue; + } + if (how & WHERE) + printf("man: found in %s.\n", fname); + else if (how & CAT) + cat(fname); + else + add(fname); + if (!(how & ALL)) + return(1); + res = 1; + } + if (!end) + return(res); + *end = ':'; + } + /*NOTREACHED*/ +} + +/* + * getsect -- + * return a point to the section structure for a particular suffix + */ +static MANDIR * +getsect(s) + char *s; +{ + switch(*s++) { + case '1': + if (!*s) + return(list1); + break; + case '2': + if (!*s) { + list3[0] = list2[0]; + return(list3); + } + break; + /* sect. 3 requests are for either section 3, or section 3[fF]. */ + case '3': + if (!*s) { + list3[0] = list2[1]; + return(list3); + } + else if ((*s == 'f' || *s == 'F') && !*++s) { + list3[0] = list2[5]; + return(list3); + } + break; + case '4': + if (!*s) { + list3[0] = list2[2]; + return(list3); + } + break; + case '5': + if (!*s) { + list3[0] = list2[3]; + return(list3); + } + break; + case '6': + if (!*s) { + list3[0] = list1[2]; + return(list3); + } + break; + case '7': + if (!*s) { + list3[0] = list2[4]; + return(list3); + } + break; + case '8': + if (!*s) { + list3[0] = list1[1]; + return(list3); + } + } + return((MANDIR *)NULL); +} + +static +man(argv) + char **argv; +{ + register char *p; + MANDIR *section; + int res; + + for (; *argv; ++argv) { + manpath = defpath; + section = NULL; + switch(**argv) { + case 'l': /* local */ + /* support the "{l,local,n,new}###" syntax */ + for (p = *argv; isalpha(*p); ++p); + if (!strncmp(*argv, "l", p - *argv) || + !strncmp(*argv, "local", p - *argv)) { + ++argv; + manpath = locpath; + section = getsect(p); + } + break; + case 'n': /* new */ + for (p = *argv; isalpha(*p); ++p); + if (!strncmp(*argv, "n", p - *argv) || + !strncmp(*argv, "new", p - *argv)) { + ++argv; + manpath = newpath; + section = getsect(p); + } + break; + /* + * old isn't really a separate section of the manual, + * and its entries are all in a single directory. + */ + case 'o': /* old */ + for (p = *argv; isalpha(*p); ++p); + if (!strncmp(*argv, "o", p - *argv) || + !strncmp(*argv, "old", p - *argv)) { + ++argv; + list3[0] = list1[3]; + section = list3; + } + break; + case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': + if (section = getsect(*argv)) + ++argv; + } + + if (*argv) { + if (section) + res = manual(section, *argv); + else { + res = manual(list1, *argv); + if (!res || (how & ALL)) + res += manual(list2, *argv); + } + if (res || how&WHERE) + continue; + } + + fputs("man: ", stderr); + if (*argv) + fprintf(stderr, "no entry for %s in the ", *argv); + else + fputs("what do you want from the ", stderr); + if (section) + fprintf(stderr, "%s section of the ", section->msg); + if (manpath == locpath) + fputs("local ", stderr); + else if (manpath == newpath) + fputs("new ", stderr); + if (*argv) + fputs("manual.\n", stderr); + else + fputs("manual?\n", stderr); + exit(1); + } +} + +/* + * jump -- + * strip out flag argument and jump + */ +static +jump(argv, flag, name) + char **argv, *name; + register char *flag; +{ + register 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); + fprintf(stderr, "%s: Command not found.\n", name); + exit(1); +} + +/* + * This is done in a function by itself because 'uname()' uses a 640 + * structure which we do not want permanently allocated on main()'s stack. +*/ +setmachine() + { + struct utsname foo; + + if (uname(&foo) < 0) + strcpy(foo.machine, "?"); + machine = strdup(foo.machine); + } + +/* + * usage -- + * print usage and die + */ +static +usage() +{ + fputs("usage: man [-] [-a] [-M path] [section] title ...\n", stderr); + exit(1); +} + +main(argc, argv) + int argc; + register char **argv; +{ + extern char *optarg; + extern int optind; + int ch; + + while ((ch = getopt(argc, argv, "-M:P:afkw")) != EOF) + switch((char)ch) { + case '-': + how |= CAT; + break; + case 'M': + case 'P': /* backward compatibility */ + defpath = optarg; + break; + case 'a': + how |= ALL; + break; + /* + * "man -f" and "man -k" are backward contemptible, + * undocumented ways of calling whatis(1) and apropos(1). + */ + case 'f': + jump(argv, "-f", "whatis"); + /*NOTREACHED*/ + case 'k': + jump(argv, "-k", "apropos"); + /*NOTREACHED*/ + /* + * Deliberately undocumented; really only useful when + * you're moving man pages around. Not worth adding. + */ + case 'w': + how |= WHERE | ALL; + break; + case '?': + default: + usage(); + } + argv += optind; + + if (!*argv) + usage(); + + if (!(how & CAT)) + if (!isatty(1)) + how |= CAT; + else if (pager = getenv("PAGER")) { + register char *p; + + /* + * if the user uses "more", we make it "more -s" + * watch out for PAGER = "mypager /bin/more" + */ + for (p = pager; *p && !isspace(*p); ++p); + for (; p > pager && *p != '/'; --p); + if (p != pager) + ++p; + /* make sure it's "more", not "morex" */ + if (!strncmp(p, "more", 4) && (!p[4] || isspace(p[4]))){ + char *opager = pager; + /* + * allocate space to add the "-s" + */ + if (!(pager = malloc((u_int)(strlen(opager) + + sizeof("-s") + 1)))) { + fputs("man: out of space.\n", stderr); + exit(1); + } + (void)sprintf(pager, "%s %s", opager, "-s"); + } + } + else + pager = _PATH_MORE " -s"; + if (!(machine = getenv("MACHINE"))) + setmachine(); + if (!defpath && !(defpath = getenv("MANPATH"))) + defpath = _PATH_MAN; + locpath = _PATH_LOCALMAN; + newpath = NEW_PATH; + man(argv); + /* use system(3) in case someone's pager is "pager arg1 arg2" */ + if (command) + (void)system(command); + exit(0); +} diff --git a/src/cmd/med/Makefile b/src/cmd/med/Makefile new file mode 100644 index 0000000..b29cd61 --- /dev/null +++ b/src/cmd/med/Makefile @@ -0,0 +1,27 @@ +#========================================== +# Makefile: makefile for med +# Copyright 2012 Majenko Technolohies +# (matt@majenko.co.uk +# Last Modified: 29/01/2012 +#========================================== + +TOPSRC = $(shell cd ../../..; pwd) +include $(TOPSRC)/target.mk + +OBJS = med.o +SRCS = med.c +LIBS += -lcurses -ltermcap -lvmf -lc + +all: med + +med: ${OBJS} + ${CC} ${LDFLAGS} -o med.elf ${OBJS} ${LIBS} + ${OBJDUMP} -S med.elf > med.dis + ${SIZE} med.elf + ${ELF2AOUT} med.elf $@ && rm med.elf + +clean: + -rm -f med ${OBJS} med.elf med.dis + +install: all + install med $(DESTDIR)/bin/ diff --git a/src/cmd/med/med.c b/src/cmd/med/med.c new file mode 100644 index 0000000..37faff6 --- /dev/null +++ b/src/cmd/med/med.c @@ -0,0 +1,534 @@ +/* Majenko Editor - a very very light-weight visual editor for + * RetroBSD. (c) 2012 Majenko Technologies. Use at your own risk! + * This is designed to use such a small footprint that it works entirely + * from disk as much as is practical. + */ + +#include +#include +#include +#include +#include +#include +#include + +WINDOW *win; + +FILE *file; + +int offset_line; +int cursor_line; +int cursor_column; +int screen_width; +int screen_height; +int file_lines; +char *filename; +char modified; + +struct vspace space; + +#define CTRL_A 1 +#define CTRL_B 2 +#define CTRL_C 3 +#define CTRL_D 4 +#define CTRL_E 5 +#define CTRL_F 6 +#define CTRL_G 7 +#define CTRL_H 8 +#define CTRL_I 9 +#define CTRL_J 10 +#define CTRL_K 11 +#define CTRL_L 12 +#define CTRL_M 13 +#define CTRL_N 14 +#define CTRL_O 15 +#define CTRL_P 16 +#define CTRL_Q 17 +#define CTRL_R 18 +#define CTRL_S 19 +#define CTRL_T 20 +#define CTRL_U 21 +#define CTRL_V 22 +#define CTRL_W 23 +#define CTRL_X 24 +#define CTRL_Y 25 +#define CTRL_Z 26 + +#define KEY_UP 256 +#define KEY_DOWN 257 +#define KEY_LEFT 258 +#define KEY_RIGHT 259 +#define KEY_F1 260 +#define KEY_F2 261 +#define KEY_F3 262 +#define KEY_F4 263 +#define KEY_F5 264 +#define KEY_F6 265 +#define KEY_F7 266 +#define KEY_F8 267 +#define KEY_F9 268 +#define KEY_F10 269 + +void sigint() +{ + clear(); + refresh(); + endwin(); + vmclose(&space); + printf("Aborted\n"); + exit(0); +} + +int input_value(char *prompt) +{ + char temp[100]; + mvwaddstr(win,screen_height,0," "); + mvwaddstr(win,screen_height,0,prompt); + refresh(); + nocbreak(); + echo(); + wgetstr(win,temp); + noecho(); + cbreak(); + return atoi(temp); +} + +void refresh_screen() +{ + char c; + struct vseg *seg; + char temp[100]; + int coff = 0; + int cpos; + unsigned char t; + + if(cursor_column<0) + cursor_column=0; + + cpos = cursor_column; + + if(cpos>79) + { + coff = cpos-79; + cpos = 79; + } + for(c=0; c=file_lines) + { + mvwaddstr(win,c,0,"~"); + clrtoeol(); + } else { + if(c == cursor_line-offset_line) + { + memcpy(temp,seg->s_cinfo+coff,80); + temp[79]=0; + temp[80]=0; + for(t=0; ts_cinfo+coff)>79) + { + temp[79]='>'; + } + if(coff>0) + { + temp[0]='<'; + } + mvwaddstr(win,c,0,temp); + } else { + memcpy(temp,seg->s_cinfo,80); + temp[79]=0; + temp[80]=0; + for(t=0; ts_cinfo)>79) + { + temp[79] = '>'; + } + mvwaddstr(win,c,0,temp); + } + clrtoeol(); + } + } + + standout(); + mvwaddstr(win,screen_height,0," "); + sprintf(temp,"Line: %d/%d %s %c", + offset_line+cursor_line+1, file_lines, filename, + modified==1 ? '*' : ' '); + + mvwaddstr(win,screen_height,0,temp); + standend(); + + mvwinch(win,cursor_line,cpos); + refresh(); +} + +void delete_char_to_left() +{ + struct vseg *seg1; + struct vseg *seg2; + int i; + int np; + if(cursor_column==0) + { + // We are joining lines + if(cursor_line+offset_line>0) + { + seg1 = vmmapseg(&space,cursor_line+offset_line); + seg2 = vmmapseg(&space,cursor_line+offset_line-1); + np = strlen(seg2->s_cinfo); + strncpy(&(seg2->s_cinfo[strlen(seg2->s_cinfo)]),seg1->s_cinfo,1024-strlen(seg2->s_cinfo)); + vmmodify(seg2); + for(i = cursor_line+offset_line; is_cinfo,seg2->s_cinfo); + vmmodify(seg1); + } + file_lines--; + cursor_column=np; + if(cursor_line>0) + { + cursor_line--; + } else { + offset_line--; + } + } + return; + } + + seg1 = vmmapseg(&space,cursor_line+offset_line); + for(i=cursor_column-1; i<1024; i++) + { + seg1->s_cinfo[i] = seg1->s_cinfo[i+1]; + } + vmmodify(seg1); + cursor_column--; +} + +void insert_char_at_cursor(int c) +{ + int line; + int len; + int i; + struct vseg *seg; + + line = offset_line + cursor_line; + seg = vmmapseg(&space,line); + len = strlen(seg->s_cinfo); + for(i=len; i>cursor_column; i--) + { + seg->s_cinfo[i] = seg->s_cinfo[i-1]; + } + seg->s_cinfo[len+1]=0; + seg->s_cinfo[cursor_column] = c; + cursor_column++; + vmmodify(seg); +} + +void save_file(char *fn) +{ + FILE *file; + int i; + struct vseg *seg; + + file = fopen(fn,"w"); + if(!file) + return; + for(i=0; is_cinfo,file); + fputc('\n',file); + } + fclose(file); +} + +int get_key() +{ + char escape[4]; + int key; + int c; + c = getch(); + if(c == '\e') + { + + // Start an escape sequence + escape[0] = 0; + escape[1] = 0; + escape[2] = 0; + escape[3] = 0; + + escape[0] = '\e'; + escape[1] = getch(); + escape[2] = getch(); + + if(!strcmp(escape,"\e[A")) + return KEY_UP; + + if(!strcmp(escape,"\e[B")) + return KEY_DOWN; + + if(!strcmp(escape,"\e[D")) + return KEY_LEFT; + + if(!strcmp(escape,"\e[C")) + return KEY_RIGHT; + + if(!strcmp(escape,"\eOS")) + return KEY_F4; + + } else { + return c; + } +} + +int main(int argc, char **argv) +{ + int status; + int d; + unsigned long lineno; + struct vseg *seg; + struct vseg *seg1; + int i; + + signal(SIGINT,&sigint); + + cursor_column = 0; + cursor_line = 0; + offset_line = 0; + + screen_width = 80; + screen_height = 21; + + if(argc!=2) + { + printf("Usage: med \n"); + printf("There are no options.\n"); + exit(10); + } + + status = vminit(20); + if(status == -1) + { + printf("Error: unable to lock memory\n"); + exit(10); + } + + status = vmopen(&space,NULL); + if(status == -1) + { + printf("Error: unable to lock scratch file\n"); + exit(10); + } + + modified = 0; + + filename = argv[1]; + file = fopen(argv[1],"r"); + + // If the file exists, load it into the VM system line by line - one line to a page. + if(file) + { + lineno = 0; + + seg = vmmapseg(&space,lineno); + bzero(seg->s_cinfo,1024); + while(fgets(seg->s_cinfo,1024,file)) + { + while(seg->s_cinfo[strlen(seg->s_cinfo)-1]=='\n') + seg->s_cinfo[strlen(seg->s_cinfo)-1] = 0; + vmmodify(seg); + lineno++; + file_lines++; + seg = vmmapseg(&space,lineno); + bzero(seg->s_cinfo,1024); + } + + fclose(file); + } else { + file_lines = 1; + } + + win = initscr(); + cbreak(); + noecho(); + + refresh_screen(); + + while(1) + { + d = get_key(); + switch(d) + { + case CTRL_G: + i = input_value("Goto: "); + if(i>0) + { + cursor_line=0; + offset_line = i-1; + if(offset_line>=file_lines) + offset_line = file_lines-1; + if(offset_line > screen_height/2) + { + offset_line = offset_line - (screen_height/2); + cursor_line = screen_height/2; + } + } + refresh_screen(); + break; + case CTRL_H: + delete_char_to_left(); + modified=1; + refresh_screen(); + break; + case KEY_UP: + if(cursor_line>0) + { + cursor_line--; + } else { + if(offset_line>0) + { + offset_line--; + } else { + break; + } + } + seg = vmmapseg(&space,offset_line+cursor_line); + if(cursor_column >= strlen(seg->s_cinfo)) + cursor_column = strlen(seg->s_cinfo); + refresh_screen(); + break; + case KEY_DOWN: + if(cursor_line+offset_line= strlen(seg->s_cinfo)) + cursor_column = strlen(seg->s_cinfo); + refresh_screen(); + } + break; + case KEY_RIGHT: + cursor_column++; + seg = vmmapseg(&space,offset_line+cursor_line); + if(cursor_column > strlen(seg->s_cinfo)) + { + if(cursor_line+offset_lines_cinfo); + } + } + refresh_screen(); + break; + case KEY_LEFT: + if(cursor_column>0) + { + cursor_column--; + refresh_screen(); + } else { + if(cursor_line>0) + { + cursor_line--; + seg = vmmapseg(&space,offset_line+cursor_line); + cursor_column = strlen(seg->s_cinfo); + refresh_screen(); + } else { + if(offset_line>0) + { + offset_line--; + seg = vmmapseg(&space,offset_line+cursor_line); + cursor_column = strlen(seg->s_cinfo); + refresh_screen(); + } + } + } + break; + case CTRL_V: + case CTRL_X: + save_file(filename); + modified=0; + refresh_screen(); + break; + case CTRL_L: + clear(); + refresh(); + refresh_screen(); + break; + case '\r': + case '\n': + // This is a tricky one. We need to split the current line + // at the cursor and insert the rightmost portion as a new + // line in between the current one and the next one. That means + // shuffling all the lines below this one down one. + + for(i=file_lines; i>offset_line+cursor_line; i--) + { + seg = vmmapseg(&space,i); + seg1 = vmmapseg(&space,i-1); + strcpy(seg->s_cinfo,seg1->s_cinfo); + vmmodify(seg); + vmmodify(seg1); + } + + seg = vmmapseg(&space,offset_line+cursor_line); + seg1 = vmmapseg(&space,offset_line+cursor_line+1); + strcpy(seg1->s_cinfo,&(seg->s_cinfo[cursor_column])); + seg->s_cinfo[cursor_column]=0; + vmmodify(seg); + vmmodify(seg1); + if(cursor_line0) + insert_char_at_cursor(' '); + modified=1; + refresh_screen(); + break; + default: + if(d>=32 && d<=127) + { + insert_char_at_cursor(d); + modified=1; + refresh_screen(); + } + } + if(d==CTRL_X) + break; + } + + clear(); + refresh(); + endwin(); + + vmclose(&space); + + return 0; +} diff --git a/src/cmd/mesg.c b/src/cmd/mesg.c new file mode 100644 index 0000000..9d60792 --- /dev/null +++ b/src/cmd/mesg.c @@ -0,0 +1,57 @@ +/* + * mesg -- set current tty to accept or + * forbid write permission. + * + * mesg [y] [n] + * y allow messages + * n forbid messages + */ +#include +#include +#include +#include + +struct stat sbuf; + +char *tty; +char *ttyname(); + +main(argc, argv) +char *argv[]; +{ + int r=0; + tty = ttyname(2); + if (tty == 0) + exit(13); + if(stat(tty, &sbuf) < 0) error("cannot stat"); + if(argc < 2) { + if(sbuf.st_mode & 020) + fprintf(stderr,"is y\n"); + else { r=1; + fprintf(stderr,"is n\n"); + } + } else switch(*argv[1]) { + case 'y': + newmode(sbuf.st_mode|020); break; + + case 'n': + newmode(sbuf.st_mode&~020); r=1; break; + + default: + error("usage: mesg [y] [n]"); + } + exit(r); +} + +error(s) +char *s; +{ + fprintf(stderr,"mesg: %s\n",s); + exit(-1); +} + +newmode(m) +{ + if(chmod(tty,m)<0) + error("cannot change mode"); +} diff --git a/src/cmd/mkdep.sh b/src/cmd/mkdep.sh new file mode 100644 index 0000000..92e826e --- /dev/null +++ b/src/cmd/mkdep.sh @@ -0,0 +1,102 @@ +#!/bin/sh - +# +# Copyright (c) 1987 Regents of the University of California. +# All rights reserved. +# +# Redistribution and use in source and binary forms are permitted +# provided that this notice is preserved and that due credit is given +# to the University of California at Berkeley. The name of the University +# may not be used to endorse or promote products derived from this +# software without specific prior written permission. This software +# is provided ``as is'' without express or implied warranty. +# +# @(#)mkdep.sh 5.11 (Berkeley) 5/5/88 +# + +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/src/cmd/mkdir.c b/src/cmd/mkdir.c new file mode 100644 index 0000000..3ed535e --- /dev/null +++ b/src/cmd/mkdir.c @@ -0,0 +1,108 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include +#include +#include +#include +#include +#include + +extern int errno; + +main(argc, argv) + int argc; + char **argv; +{ + extern int optind; + int ch, exitval, pflag; + + pflag = 0; + while ((ch = getopt(argc, argv, "p")) != EOF) + switch(ch) { + case 'p': + pflag = 1; + break; + case '?': + default: + usage(); + } + + if (!*(argv += optind)) + usage(); + + for (exitval = 0; *argv; ++argv) + if (pflag) + exitval |= build(*argv); + else if (mkdir(*argv, 0777) < 0) { + (void)fprintf(stderr, "mkdir: %s: %s\n", + *argv, strerror(errno)); + exitval = 1; + } + exit(exitval); +} + +build(path) + char *path; +{ + register char *p; + struct stat sb; + int create, ch; + + for (create = 0, p = path;; ++p) + if (!*p || *p == '/') { + ch = *p; + *p = '\0'; + if (stat(path, &sb)) { + if (errno != ENOENT || mkdir(path, 0777) < 0) { + (void)fprintf(stderr, "mkdir: %s: %s\n", + path, strerror(errno)); + return(1); + } + create = 1; + } + if (!(*p = ch)) + break; + } + if (!create) { + (void)fprintf(stderr, "mkdir: %s: %s\n", path, + strerror(EEXIST)); + return(1); + } + return(0); +} + +usage() +{ + (void)fprintf(stderr, "usage: mkdir [-p] dirname ...\n"); + exit(1); +} diff --git a/src/cmd/mkfs/Makefile b/src/cmd/mkfs/Makefile new file mode 100644 index 0000000..9663f70 --- /dev/null +++ b/src/cmd/mkfs/Makefile @@ -0,0 +1,43 @@ +# +# Public Domain. 1996/11/16 - Steven Schultz +# +TOPSRC = $(shell cd ../../..; pwd) +include $(TOPSRC)/target.mk +#include $(TOPSRC)/cross.mk + +CFLAGS += -Wall -Werror + +SRCS = mkfs.c +OBJS = mkfs.o +MAN = mkfs.0 +MANSRC = mkfs.8 + +all: mkfs mkfs.0 + +mkfs: ${OBJS} + ${CC} ${LDFLAGS} -o mkfs.elf ${OBJS} ${LIBS} + ${OBJDUMP} -S mkfs.elf > mkfs.dis + ${SIZE} mkfs.elf + ${ELF2AOUT} mkfs.elf $@ && rm mkfs.elf + +mkfs.0: ${MANSRC} + ${MANROFF} ${MANSRC} > ${MAN} + +clean: + rm -f *.o *.elf *.dis *~ ${MAN} mkfs tags + +depend: ${SRCS} + mkdep ${CFLAGS} ${SRCS} + +install: all + cp ${MAN} ${DESTDIR}/share/man/cat8/ + install mkfs ${DESTDIR}/sbin/mkfs + +lint: ${SRCS} + lint -hax ${SRCS} + +tags: ${SRCS} + ctags ${SRCS} + +# DO NOT DELETE THIS LINE -- mkdep uses it. +# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY. diff --git a/src/cmd/mkfs/mkfs.8 b/src/cmd/mkfs/mkfs.8 new file mode 100644 index 0000000..c57d7bd --- /dev/null +++ b/src/cmd/mkfs/mkfs.8 @@ -0,0 +1,87 @@ +.\" Copyright (c) 1980 Regents of the University of California. +.\" All rights reserved. The Berkeley software License Agreement +.\" specifies the terms and conditions for redistribution. +.\" +.\" @(#)mkfs.8 2.2 (2.11BSD) 1996/11/16 +.\" +.TH MKFS 8 "November 16, 1996" +.UC 2 +.SH NAME +mkfs \- construct a file system +.SH SYNOPSIS +.B /sbin/mkfs +[ +.B \-i bytes +] +[ +.B \-s size +] +[ +.B \-m gap +] +[ +.B \-n modulus +] +.B special +.SH DESCRIPTION +.B N.B.: +file systems are normally created with the +.IR newfs (8) +command. +.PP +.I Mkfs +constructs a file system +by writing on the special file +.IR special . +The size of the filesystem in logical blocks is specified by the +\fB\-s\fP +.I size +option. +Logical blocks are 1K (2 sectors) under 2.11BSD. +.PP +.in +0.5i +\fBNOTE:\fP The +.BR newfs (8) +program's \fB\-s\fP option is in units of \fBsectors\fP. +.BR Newfs (8) +converts this to filesystem (logical) blocks for +.BR mkfs (8) . +.br +.in -0.5i +.PP +The number of inodes is calculated based on the argument +.I bytes +to the +.B \-i +option. The default is 4096. If more inodes are desired in a filesystem +(there is an absolute maximum of 65500) then a lower value for \fIbytes\fP +should be used, perhaps 3072 or even 2048. +.PP +The flags +.B \-m +.I gap +and +.B \-n +.I modulus +determine the block interleaving +of the freelist that will be constructed, +where \fIgap\fP is the distance between successive 1024-byte blocks, +and \fImodulus\fP is the number of blocks before the pattern repeats, +typically one cylinder. +The optimal values for +these parameters vary with the speed and geometry of the disk, +as well as the speed of the processor. +.BR Newfs (8) +will calculate the correct values in almost all cases from the disklabel. +.SH "SEE ALSO" +fs(5), +dir(5), +disklabel(8), +fsck(8), +mkproto(8) +newfs(8) +.SH BUGS +The +.I lost+found +directory is created but the boot block is left uninitialized (see +.BR disklabel (8).) diff --git a/src/cmd/mkfs/mkfs.c b/src/cmd/mkfs/mkfs.c new file mode 100644 index 0000000..9a39356 --- /dev/null +++ b/src/cmd/mkfs/mkfs.c @@ -0,0 +1,500 @@ +/* + * Make a file system. Run by 'newfs' and not directly by users. + * usage: mkfs -s size -i byte/ino -n num -m num filsys + * + * NOTE: the size is specified in filesystem (1k) blocks. + */ +#include + +/* + * Need to do the following to get the larger incore inode structure + * (the kernel might be built with the inode times external/mapped-out). + * See /sys/h/localtimes.h and /sys/conf. + */ +#undef EXTERNALITIMES + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define UMASK 0755 +#define MAXFN 750 + +time_t utime; + +#ifdef CROSS +#define off_t unsigned long long +#endif + +int fsi; +int fso; +char buf [DEV_BSIZE]; + +union { + struct fblk fb; + char pad1 [DEV_BSIZE]; +} fbuf; + +union { + struct fs fs; + char pad2 [DEV_BSIZE]; +} filsys; + +u_int f_i = 16 * 1024; /* bytes/inode default */ + +/* + * initialize the file system + */ +struct inode node; + +struct direct root_dir[] = { + { ROOTINO, sizeof(struct direct), 1, "." }, + { ROOTINO, sizeof(struct direct), 2, ".." }, + { LOSTFOUNDINO, sizeof(struct direct), 10, "lost+found" }, + { 0, DIRBLKSIZ, 0, "" }, +}; + +struct direct root_dir_with_swap[] = { + { ROOTINO, sizeof(struct direct), 1, "." }, + { ROOTINO, sizeof(struct direct), 2, ".." }, + { LOSTFOUNDINO, sizeof(struct direct), 10, "lost+found" }, + { ROOTINO+2, sizeof(struct direct), 4, "swap" }, + { 0, DIRBLKSIZ, 0, "" }, +}; + +struct direct lost_found_dir[] = { + { LOSTFOUNDINO, sizeof(struct direct), 1, "." }, + { ROOTINO, sizeof(struct direct), 2, ".." }, + { 0, DIRBLKSIZ, 0, "" }, +}; + +int get_disk_size(char *fn) +{ + int size; + int fd; + struct stat sb; + + printf("Getting disk size for %s\n",fn); + + // Is it a /dev entry? + if(strncmp(fn,"/dev/",5)==0) + { + fd = open(fn,O_RDONLY); + ioctl(fd,RDGETMEDIASIZE,&size); + close(fd); + } else { + lstat(fn,&sb); + size = sb.st_size/1024; + } + return size; +} + +/* + * construct a set of directory entries in "buf". + * return size of directory. + */ +int +makedir (protodir, entries) + register struct direct *protodir; + int entries; +{ + char *cp; + int i, spcleft; + + spcleft = DIRBLKSIZ; + for (cp = buf, i = 0; i < entries - 1; i++) { + protodir[i].d_reclen = DIRSIZ(&protodir[i]); + bcopy(&protodir[i], cp, protodir[i].d_reclen); + cp += protodir[i].d_reclen; + spcleft -= protodir[i].d_reclen; + } + protodir[i].d_reclen = spcleft; + bcopy(&protodir[i], cp, DIRSIZ(&protodir[i])); + return (DIRBLKSIZ); +} + +void +rdfs (bno, bf) + daddr_t bno; + char *bf; +{ + int n; + off_t offset; + + offset = (off_t) bno*DEV_BSIZE; + if (lseek(fsi, offset, 0) != offset) { + printf("lseek read error: %ld\n", bno); + exit(1); + } + n = read(fsi, bf, DEV_BSIZE); + if (n != DEV_BSIZE) { + printf("read error: %ld\n", bno); + exit(1); + } +} + +void +wtfs (bno, bf) + daddr_t bno; + char *bf; +{ + int n; + off_t offset; + + offset = (off_t) bno*DEV_BSIZE; + if (lseek(fso, offset, 0) != offset) { + printf ("wtfs: lseek failed on block number %ld, offset=%ld\n", bno, offset); + exit(1); + } + n = write(fso, bf, DEV_BSIZE); + if (n != DEV_BSIZE) { + printf("write error: %ld\n", bno); + exit(1); + } +} + +void +iput (ip) + register struct inode *ip; +{ + struct dinode buf [INOPB]; + register struct dinode *dp; + register int i; + daddr_t d; + + filsys.fs.fs_tinode--; + d = itod(ip->i_number); + if (d >= filsys.fs.fs_isize) { + printf("ilist too small\n"); + return; + } + rdfs(d, buf); + dp = (struct dinode *)buf; + dp += itoo(ip->i_number); + + for (i=0; idi_addr[i] = ip->i_addr[i]; + dp->di_ic1 = ip->i_ic1; + dp->di_ic2 = ip->i_ic2; + wtfs(d, buf); +} + +daddr_t +alloc() +{ + register int i; + daddr_t bno; + + filsys.fs.fs_tfree--; + bno = filsys.fs.fs_free[--filsys.fs.fs_nfree]; + if (bno == 0) { + printf("out of free space\n"); + exit(1); + } + if (filsys.fs.fs_nfree <= 0) { + rdfs(bno, (char *)&fbuf); + filsys.fs.fs_nfree = fbuf.fb.df_nfree; + for (i=0; i> shift) & NMASK; + if (j == NIADDR) { + block[i] = filsys.fs.fs_isize + lbn; + wtfs (indir, (char*) block); + return; + } + if (block[i] != 0) { + indir = block [i]; + continue; + } + /* Allocate new indirect block. */ + newb = alloc(); + block[i] = newb; + wtfs (indir, (char*) block); + + bzero (block, DEV_BSIZE); + wtfs (newb, (char*) block); + indir = newb; + } +} + +/* + * create swap file + */ +void +mkswap () +{ + daddr_t lbn; + + node.i_atime = utime; + node.i_mtime = utime; + node.i_ctime = utime; + + node.i_number = ROOTINO + 2; + node.i_mode = IFREG | 0400; + node.i_nlink = 1; + node.i_size = filsys.fs.fs_swapsz * DEV_BSIZE; + node.i_flags = UF_NODUMP | UF_IMMUTABLE /*| SF_IMMUTABLE*/; + + for (lbn=0; lbn= NICFREE) { + fbuf.fb.df_nfree = filsys.fs.fs_nfree; + for (i=0; i= filsys.fs.fs_isize + filsys.fs.fs_swapsz) { + bfree(d); + } +} + +void +usage() +{ + printf("usage: mkfs [-i bytes/ino] [-p swapsize] special kbytes\n"); + exit(1); + /* NOTREACHED */ +} + +int +main (argc,argv) + int argc; + char **argv; +{ + register int c; + unsigned n, kbytes, swapsz = 0; + char *special; + + while ((c = getopt(argc, argv, "i:s:")) != EOF) { + switch (c) { + case 'i': + f_i = atoi(optarg); + break; + case 's': + swapsz = strtoul(optarg, 0, 0); + break; + default: + usage(); + break; + } + } + argc -= optind; + argv += optind; + if ((argc < 1 || argc > 2) || f_i == 0) + usage(); + special = argv[0]; + if(argc==2) + kbytes = strtoul(argv[1], 0, 0); + else + kbytes = get_disk_size(argv[0]); + + /* + * NOTE: this will fail if the device is currently mounted and the system + * is at securelevel 1 or higher. + * + * We do not get the partition information because 'newfs' has already + * done so and invoked us. This program should not be run manually unless + * you are absolutely sure you know what you are doing - use 'newfs' instead. + */ + fso = creat (special, 0666); + if (fso < 0) + err (1, "cannot create %s\n", special); + fsi = open (special, 0); + if (fsi < 0) + err (1, "cannot open %s\n", special); + + printf ("Size: %u kbytes\n", kbytes); + if (kbytes == 0) { + printf ("Can't make zero length filesystem\n"); + return -1; + } + + /* Check media: write zeroes to last block. */ + wtfs (kbytes-1, (char*) &filsys.fs); + + /* + * Calculate number of blocks of inodes as follows: + * + * n * DEV_BSIZE = # of bytes in the filesystem + * n * DEV_BSIZE / f_i = # of inodes to allocate + * n * DEV_BSIZE / f_i / INOPB = # of fs blocks of inodes + * + * Pretty - isn't it? + */ + n = (kbytes * DEV_BSIZE / f_i) / INOPB; + if (n <= 0) + n = 1; + printf ("Inodes: %u\n", n*INOPB); + + filsys.fs.fs_isize = n + 1; + filsys.fs.fs_fsize = kbytes; + filsys.fs.fs_swapsz = swapsz; + if (filsys.fs.fs_isize + filsys.fs.fs_swapsz >= filsys.fs.fs_fsize) { + printf ("%u/%u: bad ratio\n", + filsys.fs.fs_fsize, filsys.fs.fs_isize-2); + exit (1); + } + time (&utime); + filsys.fs.fs_time = utime; + filsys.fs.fs_magic1 = FSMAGIC1; + filsys.fs.fs_magic2 = FSMAGIC2; + filsys.fs.fs_tfree = 0; + filsys.fs.fs_tinode = 0; + bzero (buf, DEV_BSIZE); + for (n=SUPERB+1; n != filsys.fs.fs_isize; n++) { + wtfs (n, buf); + filsys.fs.fs_tinode += INOPB; + } + + bflist(); + + fsinit(); + + if (swapsz != 0) + mkswap(); + + wtfs (SUPERB, (char*) &filsys.fs); + exit(0); +} diff --git a/src/cmd/mknod/Makefile b/src/cmd/mknod/Makefile new file mode 100644 index 0000000..91bfcfa --- /dev/null +++ b/src/cmd/mknod/Makefile @@ -0,0 +1,42 @@ +# +# Public Domain. 1996/11/16 - Steven Schultz +# +TOPSRC = $(shell cd ../../..; pwd) +include $(TOPSRC)/target.mk + +CFLAGS += -Werror + +SRCS = mknod.c +OBJS = mknod.o +MAN = mknod.0 +MANSRC = mknod.8 + +all: mknod mknod.0 + +mknod: ${OBJS} + ${CC} ${LDFLAGS} -o mknod.elf ${OBJS} ${LIBS} + ${OBJDUMP} -S mknod.elf > mknod.dis + ${SIZE} mknod.elf + ${ELF2AOUT} mknod.elf $@ && rm mknod.elf + +mknod.0: ${MANSRC} + ${MANROFF} ${MANSRC} > ${MAN} + +clean: + rm -f *.o *.elf ${MAN} mknod *.elf *.dis tags *~ + +depend: ${SRCS} + mkdep ${CFLAGS} ${SRCS} + +install: all + cp ${MAN} ${DESTDIR}/share/man/cat8/ + install mknod ${DESTDIR}/sbin/mknod + +lint: ${SRCS} + lint -hax ${SRCS} + +tags: ${SRCS} + ctags ${SRCS} + +# DO NOT DELETE THIS LINE -- mkdep uses it. +# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY. diff --git a/src/cmd/mknod/mknod.8 b/src/cmd/mknod/mknod.8 new file mode 100644 index 0000000..afba728 --- /dev/null +++ b/src/cmd/mknod/mknod.8 @@ -0,0 +1,45 @@ +.\" Copyright (c) 1980 Regents of the University of California. +.\" All rights reserved. The Berkeley software License Agreement +.\" specifies the terms and conditions for redistribution. +.\" +.\" @(#)mknod.8 6.2.1 (2.11BSD) 1996/11/16 +.\" +.TH MKNOD 8 "November 16, 1996" +.UC 4 +.SH NAME +mknod \- build special file +.SH SYNOPSIS +.B /sbin/mknod +name +[ +.B c +] [ +.B b +] +major +minor +.SH DESCRIPTION +.I Mknod +makes a special file. +The first argument is the +.I name +of the entry. +The second is +.B b +if the special file is block-type (disks, tape) or +.B c +if it is character-type (other devices). +The last two arguments are +numbers specifying the +.I major +device type +and the +.I minor +device (e.g. unit, drive, or line number). +.PP +The assignment of major device numbers is specific to each system. +They have to be dug out of the +system source file +.I conf.c. +.SH "SEE ALSO" +mknod(2), makedev(8) diff --git a/src/cmd/mknod/mknod.c b/src/cmd/mknod/mknod.c new file mode 100644 index 0000000..592bcca --- /dev/null +++ b/src/cmd/mknod/mknod.c @@ -0,0 +1,47 @@ +#include +#include + +main(argc, argv) + int argc; + char **argv; +{ + int m, a, b; + + if(argc != 5) { + printf("arg count\n"); + goto usage; + } + if(*argv[2] == 'b') + m = 060666; else + if(*argv[2] == 'c') + m = 020666; else + goto usage; + a = number(argv[3]); + if(a < 0) + goto usage; + b = number(argv[4]); + if(b < 0) + goto usage; + if(mknod(argv[1], m, (a<<8)|b) < 0) { + fprintf(stderr, "mknod: "); + perror(argv[1]); + } + exit(0); + +usage: + printf("usage: mknod name b/c major minor\n"); +} + +number(s) +char *s; +{ + int n, c; + + n = 0; + while(c = *s++) { + if(c<'0' || c>'9') + return(-1); + n = n*10 + c-'0'; + } + return(n); +} diff --git a/src/cmd/mkpasswd/Makefile b/src/cmd/mkpasswd/Makefile new file mode 100644 index 0000000..c723937 --- /dev/null +++ b/src/cmd/mkpasswd/Makefile @@ -0,0 +1,52 @@ +# +# 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 redistribution 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. +# +TOPSRC = $(shell cd ../../..; pwd) +include $(TOPSRC)/target.mk + +CFLAGS += -Werror + +SRCS = mkpasswd.c +OBJS = mkpasswd.o +MAN = mkpasswd.0 +MANSRC = mkpasswd.8 + +all: mkpasswd ${MAN} + +mkpasswd: ${OBJS} + ${CC} ${LDFLAGS} -o mkpasswd.elf ${OBJS} ${LIBS} + ${OBJDUMP} -S mkpasswd.elf > mkpasswd.dis + ${SIZE} mkpasswd.elf + ${ELF2AOUT} mkpasswd.elf $@ && rm mkpasswd.elf + +${MAN}: ${MANSRC} + ${MANROFF} ${MANSRC} > ${MAN} + +clean: + rm -f *.o *.elf ${MAN} mkpasswd *.elf *.dis tags *~ + +depend: ${SRCS} + mkdep -p ${CFLAGS} ${SRCS} + +install: all + install mkpasswd ${DESTDIR}/sbin/mkpasswd + cp ${MAN} ${DESTDIR}/share/man/cat8/ + +lint: ${SRCS} + lint ${CFLAGS} ${SRCS} + +tags: ${SRCS} + ctags ${SRCS} diff --git a/src/cmd/mkpasswd/mkpasswd.8 b/src/cmd/mkpasswd/mkpasswd.8 new file mode 100644 index 0000000..3df5dc3 --- /dev/null +++ b/src/cmd/mkpasswd/mkpasswd.8 @@ -0,0 +1,59 @@ +.\" Copyright (c) 1985 The Regents of the University of California. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms are permitted +.\" provided that the above copyright notice and this paragraph are +.\" duplicated in all such forms and that any documentation, +.\" advertising materials, and other materials related to such +.\" distribution and use acknowledge that the software was developed +.\" by the University of California, Berkeley. The name of the +.\" University may not be used to endorse or promote products derived +.\" from this software without specific prior written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR +.\" IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED +.\" WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.\" @(#)mkpasswd.8 6.5 (Berkeley) 2/22/89 +.\" +.TH MKPASSWD 8 "February 22, 1989" +.UC 6 +.SH NAME +mkpasswd \- generate hashed password table +.SH SYNOPSIS +.B mkpasswd +[ +.B \-p +] passwdfile +.SH DESCRIPTION +.I Mkpasswd +is used to generated the hashed password database used by the +password library routines (see +.IR getpwent (3)). +.PP +The file +.I passwdfile +must be in password file format (see +.IR passwd (5)). +.I Mkpasswd +generates database files named ``passwdfile.pag'' and +``passwdfile.dir'' (see +.IR ndbm (3)). +Data subsequently taken from the database files differ from +.I passwdfile +in one respect. +Rather than storing the encrypted password in the database, +.I mkpasswd +stores the offset of the encrypted password in +.IR passwdfile . +.PP +.I Mkpasswd +exits zero on success, non-zero on failure. +.PP +The +.I \-p +option causes +.I mkpasswd +to create ``passwdfile.orig'', a password file in the +standard Version 7 format. +.SH SEE ALSO +chpass(1), passwd(1), getpwent(3), ndbm(3), passwd(5), vipw(8) diff --git a/src/cmd/mkpasswd/mkpasswd.c b/src/cmd/mkpasswd/mkpasswd.c new file mode 100644 index 0000000..c4831c0 --- /dev/null +++ b/src/cmd/mkpasswd/mkpasswd.c @@ -0,0 +1,211 @@ +/* + * Copyright (c) 1980, 1983 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. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +static FILE *_pw_fp; +static struct passwd _pw_passwd; +static off_t offset; + +#define MAXLINELENGTH 256 +static char line[MAXLINELENGTH]; + +/* from libc/gen/getpwent.c */ + +static +scanpw() +{ + register char *cp; + char *bp; + + for (;;) { + offset = ftell(_pw_fp); + if (!(fgets(line, sizeof(line), _pw_fp))) + return(0); + bp = line; + /* skip lines that are too big */ + if (!(cp = index(line, '\n'))) { + int ch; + + while ((ch = getc(_pw_fp)) != '\n' && ch != EOF) + ; + continue; + } + *cp = '\0'; + _pw_passwd.pw_name = strsep(&bp, ":"); + _pw_passwd.pw_passwd = strsep(&bp, ":"); + offset += _pw_passwd.pw_passwd - line; + if (!(cp = strsep(&bp, ":"))) + continue; + _pw_passwd.pw_uid = atoi(cp); + if (!(cp = strsep(&bp, ":"))) + continue; + _pw_passwd.pw_gid = atoi(cp); + _pw_passwd.pw_gecos = strsep(&bp, ":"); + _pw_passwd.pw_dir = strsep(&bp, ":"); + _pw_passwd.pw_shell = strsep(&bp, ":"); + return(1); + } + /* NOTREACHED */ +} + +/* + * Mkpasswd does two things -- use the ``arg'' file to create ``arg''.{pag,dir} + * for ndbm, and, if the -p flag is on, create a password file in the original + * format. It doesn't use the getpwent(3) routines because it has to figure + * out offsets for the encrypted passwords to put in the dbm files. One other + * problem is that, since the addition of shadow passwords, getpwent(3) has to + * use the dbm databases rather than simply scanning the actual file. This + * required the addition of a flag field to the dbm database to distinguish + * between a record keyed by name, and one keyed by uid. + */ +main(argc, argv) + int argc; + char **argv; +{ + extern int errno, optind; + register char *flag, *p, *t; + register int makeold; + FILE *oldfp; + DBM *dp; + datum key, content; + int ch; + char buf[256], nbuf[50]; + + makeold = 0; + while ((ch = getopt(argc, argv, "pv")) != EOF) + switch(ch) { + case 'p': /* create ``password.orig'' */ + makeold = 1; + /* FALLTHROUGH */ + case 'v': /* backward compatible */ + break; + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; + + if (argc != 1) + usage(); + + if (!(_pw_fp = fopen(*argv, "r"))) { + (void)fprintf(stderr, + "mkpasswd: %s: can't open for reading.\n", *argv); + exit(1); + } + + rmall(*argv); + (void)umask(0); + + /* open old password format file, dbm files */ + if (makeold) { + int oldfd; + + (void)sprintf(buf, "%s.orig", *argv); + if ((oldfd = open(buf, O_WRONLY|O_CREAT|O_EXCL, 0644)) < 0) { + (void)fprintf(stderr, "mkpasswd: %s: %s\n", buf, + strerror(errno)); + exit(1); + } + if (!(oldfp = fdopen(oldfd, "w"))) { + (void)fprintf(stderr, "mkpasswd: %s: fdopen failed.\n", + buf); + exit(1); + } + } + if (!(dp = dbm_open(*argv, O_WRONLY|O_CREAT|O_EXCL, 0644))) { + (void)fprintf(stderr, "mkpasswd: %s: %s\n", *argv, + strerror(errno)); + exit(1); + } + + content.dptr = buf; + while (scanpw()) { + /* create dbm entry */ + p = buf; +#define COMPACT(e) t = e; while (*p++ = *t++); + COMPACT(_pw_passwd.pw_name); + (void)sprintf(nbuf, "%ld", offset); + COMPACT(nbuf); + bcopy((char *)&_pw_passwd.pw_uid, p, sizeof(int)); + p += sizeof(int); + bcopy((char *)&_pw_passwd.pw_gid, p, sizeof(int)); + p += sizeof(int); + COMPACT(_pw_passwd.pw_gecos); + COMPACT(_pw_passwd.pw_dir); + COMPACT(_pw_passwd.pw_shell); + flag = p; + *p++ = _PW_KEYBYNAME; + content.dsize = p - buf; +#ifdef debug + (void)printf("store %s, uid %d\n", _pw_passwd.pw_name, + _pw_passwd.pw_uid); +#endif + key.dptr = _pw_passwd.pw_name; + key.dsize = strlen(_pw_passwd.pw_name); + if (dbm_store(dp, key, content, DBM_INSERT) < 0) + goto bad; + key.dptr = (char *)&_pw_passwd.pw_uid; + key.dsize = sizeof(int); + *flag = _PW_KEYBYUID; + if (dbm_store(dp, key, content, DBM_INSERT) < 0) + goto bad; + + /* create original format password file entry */ + if (!makeold) + continue; + fprintf(oldfp, "%s:%d:%d:%d:%s:%s:%s\n", _pw_passwd.pw_name, + offset, _pw_passwd.pw_uid, _pw_passwd.pw_gid, + _pw_passwd.pw_gecos, _pw_passwd.pw_dir, + _pw_passwd.pw_shell); + } + dbm_close(dp); + exit(0); + +bad: (void)fprintf(stderr, "mkpasswd: dbm_store failed.\n"); + rmall(*argv); + exit(1); +} + +rmall(fname) + char *fname; +{ + register char *p; + char buf[MAXPATHLEN]; + + for (p = strcpy(buf, fname); *p; ++p); + bcopy(".pag", p, 5); + (void)unlink(buf); + bcopy(".dir", p, 5); + (void)unlink(buf); + bcopy(".orig", p, 6); + (void)unlink(buf); +} + +usage() +{ + (void)fprintf(stderr, "usage: mkpasswd [-p] passwd_file\n"); + exit(1); +} diff --git a/src/cmd/more/Makefile b/src/cmd/more/Makefile new file mode 100644 index 0000000..82f4ab0 --- /dev/null +++ b/src/cmd/more/Makefile @@ -0,0 +1,28 @@ +# +# Copyright (c) 1980 Regents of the University of California. +# All rights reserved. The Berkeley software License Agreement +# specifies the terms and conditions for redistribution. +# +TOPSRC = $(shell cd ../../..; pwd) +include $(TOPSRC)/target.mk + +CFLAGS += -Werror + +SRCS = more.c +OBJS = more.o + +all: more + +more: ${OBJS} + ${CC} ${LDFLAGS} -o more.elf ${OBJS} ${LIBS} + ${OBJDUMP} -S more.elf > more.dis + ${SIZE} more.elf + ${ELF2AOUT} more.elf $@ && rm more.elf + +clean: + rm -f *.o *.elf ${MAN} more *.elf *.dis tags *~ + +install: all more.help + install more ${DESTDIR}/bin/more + @-rm -f ${DESTDIR}/share/misc/more.help + cp more.help ${DESTDIR}/share/misc/more.help diff --git a/src/cmd/more/more.c b/src/cmd/more/more.c new file mode 100644 index 0000000..a864778 --- /dev/null +++ b/src/cmd/more/more.c @@ -0,0 +1,1773 @@ +/* + * more.c - General purpose tty output filter and file perusal program + * + * by Eric Shienbrood, UC Berkeley + * + * modified by Geoff Peck, UCB to add underlining, single spacing + * modified by John Foderaro, UCB to add -c and MORE environment variable + * + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include +#undef putchar /* force use of function rather than macro */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define HELPFILE _PATH_SHARE "misc/more.help" +#define VI _PATH_VI + +#define Fopen(s,m) (Currline = 0,file_pos=0,fopen(s,m)) +#define Ftell(f) file_pos +#define Fseek(f,off) (file_pos=off,fseek(f,off,0)) +#define Getc(f) (++file_pos, getc(f)) +#define Ungetc(c,f) (--file_pos, ungetc(c,f)) + +#define MBIT CBREAK +#define stty(fd,argp) ioctl(fd,TIOCSETN,argp) + +#define TBUFSIZ 1024 +#define LINSIZ 256 +#define ctrl(letter) (letter & 077) +#define RUBOUT '\177' +#define ESC '\033' +#define QUIT '\034' + +struct sgttyb otty, savetty; +long file_pos, file_size; +int fnum, no_intty, no_tty; +int dum_opt, dlines; +int nscroll = 11; /* Number of lines scrolled by 'd' */ +int fold_opt = 1; /* Fold long lines */ +int stop_opt = 1; /* Stop after form feeds */ +int ssp_opt = 0; /* Suppress white space */ +int ul_opt = 1; /* Underline as best we can */ +int promptlen; +int Currline; /* Line we are currently at */ +int startup = 1; +int firstf = 1; +int notell = 1; +int docrterase = 0; +int docrtkill = 0; +int bad_so; /* True if overwriting does not turn off standout */ +int inwait, Pause, errors; +int within; /* true if we are within a file, + false if we are between files */ +int hard, dumb, noscroll, hardtabs, clreol; +int catch_susp; /* We should catch the SIGTSTP signal */ +char **fnames; /* The list of file names */ +int nfiles; /* Number of files left to process */ +char *shell; /* The name of the shell to use */ +int shellp; /* A previous shell command exists */ +char ch; +jmp_buf restore; +char Line[LINSIZ]; /* Line buffer */ +int Lpp = 24; /* lines per page */ +char *Clear; /* clear screen */ +char *eraseln; /* erase line */ +char *Senter, *Sexit;/* enter and exit standout mode */ +char *ULenter, *ULexit; /* enter and exit underline mode */ +char *chUL; /* underline character */ +char *chBS; /* backspace character */ +char *Home; /* go to home */ +char *cursorm; /* cursor movement */ +char cursorhome[40]; /* contains cursor movement to home */ +char *EodClr; /* clear rest of screen */ +int Mcol = 80; /* number of columns */ +int Wrap = 1; /* set if automargins */ +int soglitch; /* terminal has standout mode glitch */ +int ulglitch; /* terminal has underline mode glitch */ +int pstate = 0; /* current UL state */ +struct { + long chrctr, line; +} context, screen_start; +extern char PC; /* pad character */ + +/* + * Termcap stub. + */ +int tgetent (char *buffer, char *termtype) +{ + return 1; +} + +int tgetnum (char *name) +{ + if (name[0] == 'l' && name[1] == 'i') + return 25; + if (name[0] == 'c' && name[1] == 'o') + return 80; + return -1; +} + +int tgetflag (char *name) +{ + if (name[0] == 'a' && name[1] == 'm') + return 1; + return 0; +} + +char *tgetstr (char *name, char **area) +{ + /* erase to end of line */ + if (name[0] == 'c' && name[1] == 'e') + return "\33[K"; + + /* Clear screen */ + if (name[0] == 'c' && name[1] == 'l') + return "\33[2J"; + + /* Reverse */ + if (name[0] == 's' && name[1] == 'o') + return "\33[7m"; + + /* End reverse */ + if (name[0] == 's' && name[1] == 'e') + return "\33[m"; + + /* Home */ + if (name[0] == 'h' && name[1] == 'o') + return "\33[H"; + + /* Clear to end of screen */ + if (name[0] == 'c' && name[1] == 'd') + return "\33[J"; + return 0; +} + +char *tgoto (char *cstring, int hpos, int vpos) +{ + /* Not used */ + return ""; +} + +char PC; +void tputs (char *string, int nlines, int (*outfun) ()) +{ + fputs (string, stdout); +} + +/* +** Come here if a quit signal is received +*/ +void onquit(sig) + int sig; +{ + signal(SIGQUIT, SIG_IGN); + if (!inwait) { + putchar ('\n'); + if (!startup) { + signal(SIGQUIT, onquit); + longjmp (restore, 1); + } + else + Pause++; + } + else if (!dum_opt && notell) { + write (2, "[Use q or Q to quit]", 20); + promptlen += 20; + notell = 0; + } + signal(SIGQUIT, onquit); +} + +/* +** Come here if a signal for a window size change is received +*/ +void chgwinsz(sig) + int sig; +{ + struct winsize win; + + (void) signal(SIGWINCH, SIG_IGN); + if (ioctl(fileno(stdout), TIOCGWINSZ, &win) != -1) { + if (win.ws_row != 0) { + Lpp = win.ws_row; + nscroll = Lpp/2 - 1; + if (nscroll <= 0) + nscroll = 1; + dlines = Lpp - (noscroll ? 1 : 2); + } + if (win.ws_col != 0) + Mcol = win.ws_col; + } + (void) signal(SIGWINCH, chgwinsz); +} + +/* +** Clean up terminal state and exit. Also come here if interrupt signal received +*/ +void end_it (sig) + int sig; +{ + + reset_tty (); + if (clreol) { + putchar ('\r'); + clreos (); + fflush (stdout); + } + else if (!clreol && (promptlen > 0)) { + kill_line (); + fflush (stdout); + } + else + write (2, "\n", 1); + _exit(0); +} + +/* + * Come here when we get a suspend signal from the terminal + */ +void onsusp (sig) + int sig; +{ + /* ignore SIGTTOU so we don't get stopped if csh grabs the tty */ + signal(SIGTTOU, SIG_IGN); + reset_tty (); + fflush (stdout); + signal(SIGTTOU, SIG_DFL); + /* Send the TSTP signal to suspend our process group */ + signal(SIGTSTP, SIG_DFL); + sigsetmask(0L); + kill (0, SIGTSTP); + /* Pause for station break */ + + /* We're back */ + signal (SIGTSTP, onsusp); + set_tty (); + if (inwait) + longjmp (restore, 1); +} + +main(argc, argv) +int argc; +char *argv[]; +{ + register FILE *f; + register char *s; + register char *p; + register char ch; + register int left; + int prnames = 0; + int initopt = 0; + int srchopt = 0; + int clearit = 0; + int initline; + char initbuf[80]; + FILE *checkf(); + + nfiles = argc; + fnames = argv; + initterm (); + nscroll = Lpp/2 - 1; + if (nscroll <= 0) + nscroll = 1; + if(s = getenv("MORE")) argscan(s); + while (--nfiles > 0) { + if ((ch = (*++fnames)[0]) == '-') { + argscan(*fnames+1); + } + else if (ch == '+') { + s = *fnames; + if (*++s == '/') { + srchopt++; + for (++s, p = initbuf; p < initbuf + 79 && *s != '\0';) + *p++ = *s++; + *p = '\0'; + } + else { + initopt++; + for (initline = 0; *s != '\0'; s++) + if (isdigit (*s)) + initline = initline*10 + *s -'0'; + --initline; + } + } + else break; + } + /* allow clreol only if Home and eraseln and EodClr strings are + * defined, and in that case, make sure we are in noscroll mode + */ + if(clreol) + { + if((Home == NULL) || (*Home == '\0') || + (eraseln == NULL) || (*eraseln == '\0') || + (EodClr == NULL) || (*EodClr == '\0') ) + clreol = 0; + else noscroll = 1; + } + if (dlines == 0) + dlines = Lpp - (noscroll ? 1 : 2); + left = dlines; + if (nfiles > 1) + prnames++; + if (!no_intty && nfiles == 0) { + fputs("Usage: ",stderr); + fputs(argv[0],stderr); + fputs(" [-dfln] [+linenum | +/pattern] name1 name2 ...\n",stderr); + exit(1); + } + else + f = stdin; + if (!no_tty) { + signal(SIGQUIT, onquit); + signal(SIGINT, end_it); + signal(SIGWINCH, chgwinsz); + if (signal (SIGTSTP, SIG_IGN) == SIG_DFL) { + signal(SIGTSTP, onsusp); + catch_susp++; + } + stty (fileno(stderr), &otty); + } + if (no_intty) { + if (no_tty) + copy_file (stdin); + else { + if ((ch = Getc (f)) == '\f') + doclear(); + else { + Ungetc (ch, f); + if (noscroll && (ch != EOF)) { + if (clreol) + home (); + else + doclear (); + } + } + if (srchopt) + { + search (initbuf, stdin, 1); + if (noscroll) + left--; + } + else if (initopt) + skiplns (initline, stdin); + screen (stdin, left); + } + no_intty = 0; + prnames++; + firstf = 0; + } + + while (fnum < nfiles) { + if ((f = checkf (fnames[fnum], &clearit)) != NULL) { + context.line = context.chrctr = 0; + Currline = 0; + if (firstf) setjmp (restore); + if (firstf) { + firstf = 0; + if (srchopt) + { + search (initbuf, f, 1); + if (noscroll) + left--; + } + else if (initopt) + skiplns (initline, f); + } + else if (fnum < nfiles && !no_tty) { + setjmp (restore); + left = command (fnames[fnum], f); + } + if (left != 0) { + if ((noscroll || clearit) && (file_size != LONG_MAX)) + if (clreol) + home (); + else + doclear (); + if (prnames) { + if (bad_so) + erase (0); + if (clreol) + cleareol (); + pr("::::::::::::::"); + if (promptlen > 14) + erase (14); + printf ("\n"); + if(clreol) cleareol(); + printf("%s\n", fnames[fnum]); + if(clreol) cleareol(); + printf("::::::::::::::\n", fnames[fnum]); + if (left > Lpp - 4) + left = Lpp - 4; + } + if (no_tty) + copy_file (f); + else { + within++; + screen(f, left); + within = 0; + } + } + setjmp (restore); + fflush(stdout); + fclose(f); + screen_start.line = screen_start.chrctr = 0L; + context.line = context.chrctr = 0L; + } + fnum++; + firstf = 0; + } + reset_tty (); + exit(0); +} + +argscan(s) +char *s; +{ + for (dlines = 0; *s != '\0'; s++) + { + switch (*s) + { + case '0': case '1': case '2': + case '3': case '4': case '5': + case '6': case '7': case '8': + case '9': + dlines = dlines*10 + *s - '0'; + break; + case 'd': + dum_opt = 1; + break; + case 'l': + stop_opt = 0; + break; + case 'f': + fold_opt = 0; + break; + case 'p': + noscroll++; + break; + case 'c': + clreol++; + break; + case 's': + ssp_opt = 1; + break; + case 'u': + ul_opt = 0; + break; + } + } +} + + +/* +** Check whether the file named by fs is an ASCII file which the user may +** access. If it is, return the opened file. Otherwise return NULL. +*/ + +FILE * +checkf (fs, clearfirst) +register char *fs; +int *clearfirst; +{ + struct stat stbuf; + register FILE *f; + char c; + + if (stat (fs, &stbuf) == -1) { + fflush(stdout); + if (clreol) + cleareol (); + perror(fs); + return (NULL); + } + if ((stbuf.st_mode & S_IFMT) == S_IFDIR) { + printf("\n*** %s: directory ***\n\n", fs); + return (NULL); + } + if ((f=Fopen(fs, "r")) == NULL) { + fflush(stdout); + perror(fs); + return (NULL); + } + c = Getc(f); + + /* Try to see whether it is an ASCII file */ + + switch ((c | *f->_ptr << 8) & 0177777) { + case 0405: + case 0407: + case 0410: + case 0411: + case 0413: + case 0177545: + printf("\n******** %s: Not a text file ********\n\n", fs); + fclose (f); + return (NULL); + default: + break; + } + if (c == '\f') + *clearfirst = 1; + else { + *clearfirst = 0; + Ungetc (c, f); + } + if ((file_size = stbuf.st_size) == 0) + file_size = LONG_MAX; + return (f); +} + +/* +** A real function, for the tputs routine in termlib +*/ + +putch (ch) +char ch; +{ + putchar (ch); +} + +/* +** Print out the contents of the file f, one screenful at a time. +*/ + +#define STOP -10 + +screen (f, num_lines) +register FILE *f; +register int num_lines; +{ + register int c; + register int nchars; + int length; /* length of current line */ + static int prev_len = 1; /* length of previous line */ + + for (;;) { + while (num_lines > 0 && !Pause) { + if ((nchars = getline (f, &length)) == EOF) + { + if (clreol) + clreos(); + return; + } + if (ssp_opt && length == 0 && prev_len == 0) + continue; + prev_len = length; + if (bad_so || (Senter && *Senter == ' ') && promptlen > 0) + erase (0); + /* must clear before drawing line since tabs on some terminals + * do not erase what they tab over. + */ + if (clreol) + cleareol (); + prbuf (Line, length); + if (nchars < promptlen) + erase (nchars); /* erase () sets promptlen to 0 */ + else promptlen = 0; + /* is this needed? + * if (clreol) + * cleareol(); /* must clear again in case we wrapped * + */ + if (nchars < Mcol || !fold_opt) + prbuf("\n", 1); /* will turn off UL if necessary */ + if (nchars == STOP) + break; + num_lines--; + } + if (pstate) { + tputs(ULexit, 1, putch); + pstate = 0; + } + fflush(stdout); + if ((c = Getc(f)) == EOF) + { + if (clreol) + clreos (); + return; + } + + if (Pause && clreol) + clreos (); + Ungetc (c, f); + setjmp (restore); + Pause = 0; startup = 0; + if ((num_lines = command (NULL, f)) == 0) + return; + if (hard && promptlen > 0) + erase (0); + if (noscroll && num_lines >= dlines) + { + if (clreol) + home(); + else + doclear (); + } + screen_start.line = Currline; + screen_start.chrctr = Ftell (f); + } +} + +copy_file(f) +register FILE *f; +{ + register int c; + + while ((c = getc(f)) != EOF) + putchar(c); +} + +/* Put the print representation of an integer into a string */ +static char *sptr; + +scanstr (n, str) +int n; +char *str; +{ + sptr = str; + Sprintf (n); + *sptr = '\0'; +} + +Sprintf (n) +register int n; +{ + register int a; + + if (a = n/10) + Sprintf (a); + *sptr++ = n % 10 + '0'; +} + +static char bell = ctrl('G'); + +/* See whether the last component of the path name "path" is equal to the +** string "string" +*/ + +tailequ (path, string) +char *path; +register char *string; +{ + register char *tail; + + tail = path + strlen(path); + while (tail >= path) + if (*(--tail) == '/') + break; + ++tail; + while (*tail++ == *string++) + if (*tail == '\0') + return(1); + return(0); +} + +prompt (filename) +char *filename; +{ + if (clreol) + cleareol (); + else if (promptlen > 0) + kill_line (); + if (!hard) { + promptlen = 8; + if (Senter && Sexit) { + tputs (Senter, 1, putch); + promptlen += (2 * soglitch); + } + if (clreol) + cleareol (); + pr("--More--"); + if (filename != NULL) { + promptlen += printf ("(Next file: %s)", filename); + } + else if (!no_intty) { + promptlen += printf ("(%d%%)", (int)((file_pos * 100) / file_size)); + } + if (dum_opt) { + promptlen += pr("[Press space to continue, 'q' to quit.]"); + } + if (Senter && Sexit) + tputs (Sexit, 1, putch); + if (clreol) + clreos (); + fflush(stdout); + } + else + write (2, &bell, 1); + inwait++; +} + +/* +** Get a logical line +*/ + +getline(f, length) +register FILE *f; +int *length; +{ + register int c; + register char *p; + register int column; + static int colflg; + + p = Line; + column = 0; + c = Getc (f); + if (colflg && c == '\n') { + Currline++; + c = Getc (f); + } + while (p < &Line[LINSIZ - 1]) { + if (c == EOF) { + if (p > Line) { + *p = '\0'; + *length = p - Line; + return (column); + } + *length = p - Line; + return (EOF); + } + if (c == '\n') { + Currline++; + break; + } + *p++ = c; + if (c == '\t') + if (hardtabs && column < promptlen && !hard) { + if (eraseln && !dumb) { + column = 1 + (column | 7); + tputs (eraseln, 1, putch); + promptlen = 0; + } + else { + for (--p; column & 7 && p < &Line[LINSIZ - 1]; column++) { + *p++ = ' '; + } + if (column >= promptlen) promptlen = 0; + } + } + else + column = 1 + (column | 7); + else if (c == '\b' && column > 0) + column--; + else if (c == '\r') + column = 0; + else if (c == '\f' && stop_opt) { + p[-1] = '^'; + *p++ = 'L'; + column += 2; + Pause++; + } + else if (c == EOF) { + *length = p - Line; + return (column); + } + else if (c >= ' ' && c != RUBOUT) + column++; + if (column >= Mcol && fold_opt) break; + c = Getc (f); + } + if (column >= Mcol && Mcol > 0) { + if (!Wrap) { + *p++ = '\n'; + } + } + colflg = column == Mcol && fold_opt; + *length = p - Line; + *p = 0; + return (column); +} + +/* +** Erase the rest of the prompt, assuming we are starting at column col. +*/ + +erase (col) +register int col; +{ + + if (promptlen == 0) + return; + if (hard) { + putchar ('\n'); + } + else { + if (col == 0) + putchar ('\r'); + if (!dumb && eraseln) + tputs (eraseln, 1, putch); + else + for (col = promptlen - col; col > 0; col--) + putchar (' '); + } + promptlen = 0; +} + +/* +** Erase the current line entirely +*/ + +kill_line () +{ + erase (0); + if (!eraseln || dumb) putchar ('\r'); +} + +/* + * force clear to end of line + */ +cleareol() +{ + tputs(eraseln, 1, putch); +} + +clreos() +{ + tputs(EodClr, 1, putch); +} + +/* +** Print string and return number of characters +*/ + +pr(s1) +char *s1; +{ + register char *s; + register char c; + + for (s = s1; c = *s++; ) + putchar(c); + return (s - s1 - 1); +} + + +/* Print a buffer of n characters */ + +prbuf (s, n) +register char *s; +register int n; +{ + register char c; /* next output character */ + register int state; /* next output char's UL state */ +#define wouldul(s,n) ((n) >= 2 && (((s)[0] == '_' && (s)[1] == '\b') || ((s)[1] == '\b' && (s)[2] == '_'))) + + while (--n >= 0) + if (!ul_opt) + putchar (*s++); + else { + if (*s == ' ' && pstate == 0 && ulglitch && wouldul(s+1, n-1)) { + s++; + continue; + } + if (state = wouldul(s, n)) { + c = (*s == '_')? s[2] : *s ; + n -= 2; + s += 3; + } else + c = *s++; + if (state != pstate) { + if (c == ' ' && state == 0 && ulglitch && wouldul(s, n-1)) + state = 1; + else + tputs(state ? ULenter : ULexit, 1, putch); + } + if (c != ' ' || pstate == 0 || state != 0 || ulglitch == 0) + putchar(c); + if (state && *chUL) { + pr(chBS); + tputs(chUL, 1, putch); + } + pstate = state; + } +} + +/* +** Clear the screen +*/ + +doclear() +{ + if (Clear && !hard) { + tputs(Clear, 1, putch); + + /* Put out carriage return so that system doesn't + ** get confused by escape sequences when expanding tabs + */ + putchar ('\r'); + promptlen = 0; + } +} + +/* + * Go to home position + */ +home() +{ + tputs(Home,1,putch); +} + +static int lastcmd, lastarg, lastp; +static int lastcolon; +char shell_line[132]; + +/* +** Print an integer as a string of decimal digits, +** returning the length of the print representation. +*/ +printd (n) +register int n; +{ + register int a, nchars; + + if (a = n/10) + nchars = 1 + printd(a); + else + nchars = 1; + putchar (n % 10 + '0'); + return (nchars); +} + +/* +** Read a command and do it. A command consists of an optional integer +** argument followed by the command character. Return the number of lines +** to display in the next screenful. If there is nothing more to display +** in the current file, zero is returned. +*/ + +command (filename, f) +char *filename; +register FILE *f; +{ + register int nlines; + register int retval; + register char c; + char colonch; + FILE *helpf; + int done; + char comchar, cmdbuf[80], *p; + +#define ret(val) retval=val;done++;break + + done = 0; + if (!errors) + prompt (filename); + else + errors = 0; + for (;;) { + nlines = number (&comchar); + lastp = colonch = 0; + if (comchar == '.') { /* Repeat last command */ + lastp++; + comchar = lastcmd; + nlines = lastarg; + if (lastcmd == ':') + colonch = lastcolon; + } + lastcmd = comchar; + lastarg = nlines; + if (comchar == otty.sg_erase) { + kill_line (); + prompt (filename); + continue; + } + switch (comchar) { + case ':': + retval = colon (filename, colonch, nlines); + if (retval >= 0) + done++; + break; + case 'b': + case ctrl('B'): + { + register int initline; + + if (no_intty) { + write(2, &bell, 1); + return (-1); + } + + if (nlines == 0) nlines++; + + putchar ('\r'); + erase (0); + printf ("\n"); + if (clreol) + cleareol (); + printf ("...back %d page", nlines); + if (nlines > 1) + pr ("s\n"); + else + pr ("\n"); + + if (clreol) + cleareol (); + pr ("\n"); + + initline = Currline - dlines * (nlines + 1); + if (! noscroll) + --initline; + if (initline < 0) initline = 0; + Fseek(f, 0L); + Currline = 0; /* skiplns() will make Currline correct */ + skiplns(initline, f); + if (! noscroll) { + ret(dlines + 1); + } + else { + ret(dlines); + } + } + case ' ': + case 'z': + if (nlines == 0) nlines = dlines; + else if (comchar == 'z') dlines = nlines; + ret (nlines); + case 'd': + case ctrl('D'): + if (nlines != 0) nscroll = nlines; + ret (nscroll); + case 'q': + case 'Q': + end_it (); + case 's': + case 'f': + if (nlines == 0) nlines++; + if (comchar == 'f') + nlines *= dlines; + putchar ('\r'); + erase (0); + printf ("\n"); + if (clreol) + cleareol (); + printf ("...skipping %d line", nlines); + if (nlines > 1) + pr ("s\n"); + else + pr ("\n"); + + if (clreol) + cleareol (); + pr ("\n"); + + while (nlines > 0) { + while ((c = Getc (f)) != '\n') + if (c == EOF) { + retval = 0; + done++; + goto endsw; + } + Currline++; + nlines--; + } + ret (dlines); + case '\n': + if (nlines != 0) + dlines = nlines; + else + nlines = 1; + ret (nlines); + case '\f': + if (!no_intty) { + doclear (); + Fseek (f, screen_start.chrctr); + Currline = screen_start.line; + ret (dlines); + } + else { + write (2, &bell, 1); + break; + } + case '\'': + if (!no_intty) { + kill_line (); + pr ("\n***Back***\n\n"); + Fseek (f, context.chrctr); + Currline = context.line; + ret (dlines); + } + else { + write (2, &bell, 1); + break; + } + case '=': + kill_line (); + promptlen = printd (Currline); + fflush (stdout); + break; + case 'n': + lastp++; + case '/': + if (nlines == 0) nlines++; + kill_line (); + pr ("/"); + promptlen = 1; + fflush (stdout); + if (lastp) { + write (2,"\r", 1); + search (NULL, f, nlines); /* Use previous r.e. */ + } + else { + ttyin (cmdbuf, 78, '/'); + write (2, "\r", 1); + search (cmdbuf, f, nlines); + } + ret (dlines-1); + case '!': + do_shell (filename); + break; + case '?': + case 'h': + if ((helpf = fopen (HELPFILE, "r")) == NULL) + error ("Can't open help file"); + if (noscroll) doclear (); + copy_file (helpf); + fclose (helpf); + prompt (filename); + break; + case 'v': /* This case should go right before default */ + if (!no_intty) { + kill_line (); + cmdbuf[0] = '+'; + scanstr (Currline - dlines < 0 ? 0 + : Currline - (dlines + 1) / 2, &cmdbuf[1]); + pr ("vi "); pr (cmdbuf); putchar (' '); pr (fnames[fnum]); + execute (filename, VI, "vi", cmdbuf, fnames[fnum], 0); + break; + } + default: + if (dum_opt) { + kill_line (); + if (Senter && Sexit) { + tputs (Senter, 1, putch); + promptlen = pr ("[Press 'h' for instructions.]") + (2 * soglitch); + tputs (Sexit, 1, putch); + } + else + promptlen = pr ("[Press 'h' for instructions.]"); + fflush (stdout); + } + else + write (2, &bell, 1); + break; + } + if (done) break; + } + putchar ('\r'); +endsw: + inwait = 0; + notell++; + return (retval); +} + +char ch; + +/* + * Execute a colon-prefixed command. + * Returns <0 if not a command that should cause + * more of the file to be printed. + */ + +colon (filename, cmd, nlines) +char *filename; +int cmd; +int nlines; +{ + if (cmd == 0) + ch = readch (); + else + ch = cmd; + lastcolon = ch; + switch (ch) { + case 'f': + kill_line (); + if (!no_intty) + promptlen = printf ("\"%s\" line %d", fnames[fnum], Currline); + else + promptlen = printf ("[Not a file] line %d", Currline); + fflush (stdout); + return (-1); + case 'n': + if (nlines == 0) { + if (fnum >= nfiles - 1) + end_it (); + nlines++; + } + putchar ('\r'); + erase (0); + skipf (nlines); + return (0); + case 'p': + if (no_intty) { + write (2, &bell, 1); + return (-1); + } + putchar ('\r'); + erase (0); + if (nlines == 0) + nlines++; + skipf (-nlines); + return (0); + case '!': + do_shell (filename); + return (-1); + case 'q': + case 'Q': + end_it (); + default: + write (2, &bell, 1); + return (-1); + } +} + +/* +** Read a decimal number from the terminal. Set cmd to the non-digit which +** terminates the number. +*/ + +number(cmd) +char *cmd; +{ + register int i; + + i = 0; ch = otty.sg_kill; + for (;;) { + ch = readch (); + if (ch >= '0' && ch <= '9') + i = i*10 + ch - '0'; + else if (ch == otty.sg_kill) + i = 0; + else { + *cmd = ch; + break; + } + } + return (i); +} + +do_shell (filename) +char *filename; +{ + char cmdbuf[80]; + + kill_line (); + pr ("!"); + fflush (stdout); + promptlen = 1; + if (lastp) + pr (shell_line); + else { + ttyin (cmdbuf, 78, '!'); + if (expand (shell_line, cmdbuf)) { + kill_line (); + promptlen = printf ("!%s", shell_line); + } + } + fflush (stdout); + write (2, "\n", 1); + promptlen = 0; + shellp = 1; + execute (filename, shell, shell, "-c", shell_line, 0); +} + +/* +** Search for nth ocurrence of regular expression contained in buf in the file +*/ + +search (buf, file, n) +char buf[]; +FILE *file; +register int n; +{ + long startline = Ftell (file); + register long line1 = startline; + register long line2 = startline; + register long line3 = startline; + register int lncount; + int saveln, rv; + char *s; + + context.line = saveln = Currline; + context.chrctr = startline; + lncount = 0; + if ((s = re_comp (buf)) != 0) + error (s); + while (!feof (file)) { + line3 = line2; + line2 = line1; + line1 = Ftell (file); + rdline (file); + lncount++; + if ((rv = re_exec (Line)) == 1) + if (--n == 0) { + if (lncount > 3 || (lncount > 1 && no_intty)) + { + pr ("\n"); + if (clreol) + cleareol (); + pr("...skipping\n"); + } + if (!no_intty) { + Currline -= (lncount >= 3 ? 3 : lncount); + Fseek (file, line3); + if (noscroll) + if (clreol) { + home (); + cleareol (); + } + else + doclear (); + } + else { + kill_line (); + if (noscroll) + if (clreol) { + home (); + cleareol (); + } + else + doclear (); + pr (Line); + putchar ('\n'); + } + break; + } + else if (rv == -1) + error ("Regular expression botch"); + } + if (feof (file)) { + if (!no_intty) { + file->_flag &= ~_IOEOF; /* why doesn't fseek do this ??!!??! */ + Currline = saveln; + Fseek (file, startline); + } + else { + pr ("\nPattern not found\n"); + end_it (); + } + error ("Pattern not found"); + } +} + +execute (filename, cmd, args) +char *filename; +char *cmd, *args; +{ + int id; + int n; + + fflush (stdout); + reset_tty (); + for (n = 10; (id = fork ()) < 0 && n > 0; n--) + sleep (5); + if (id == 0) { + if (!isatty(0)) { + close(0); + open("/dev/tty", 0); + } + execv (cmd, &args); + write (2, "exec failed\n", 12); + exit (1); + } + if (id > 0) { + signal (SIGINT, SIG_IGN); + signal (SIGQUIT, SIG_IGN); + if (catch_susp) + signal(SIGTSTP, SIG_DFL); + while (wait(0) > 0); + signal (SIGINT, end_it); + signal (SIGQUIT, onquit); + if (catch_susp) + signal(SIGTSTP, onsusp); + } else + write(2, "can't fork\n", 11); + set_tty (); + pr ("------------------------\n"); + prompt (filename); +} +/* +** Skip n lines in the file f +*/ + +skiplns (n, f) +register int n; +register FILE *f; +{ + register char c; + + while (n > 0) { + while ((c = Getc (f)) != '\n') + if (c == EOF) + return; + n--; + Currline++; + } +} + +/* +** Skip nskip files in the file list (from the command line). Nskip may be +** negative. +*/ + +skipf (nskip) +register int nskip; +{ + if (nskip == 0) return; + if (nskip > 0) { + if (fnum + nskip > nfiles - 1) + nskip = nfiles - fnum - 1; + } + else if (within) + ++fnum; + fnum += nskip; + if (fnum < 0) + fnum = 0; + pr ("\n...Skipping "); + pr ("\n"); + if (clreol) + cleareol (); + pr ("...Skipping "); + pr (nskip > 0 ? "to file " : "back to file "); + pr (fnames[fnum]); + pr ("\n"); + if (clreol) + cleareol (); + pr ("\n"); + --fnum; +} + +/*----------------------------- Terminal I/O -------------------------------*/ + +initterm () +{ + char buf[TBUFSIZ]; + static char clearbuf[TBUFSIZ]; + char *clearptr, *padstr; + int ldisc; + int lmode; + char *term; + int tgrp; + struct winsize win; + +retry: + if (!(no_tty = gtty(fileno(stdout), &otty))) { + if (ioctl(fileno(stdout), TIOCLGET, &lmode) < 0) { + perror("TIOCLGET"); + exit(1); + } + docrterase = ((lmode & LCRTERA) != 0); + docrtkill = ((lmode & LCRTKIL) != 0); + /* + * Wait until we're in the foreground before we save the + * the terminal modes. + */ + if (ioctl(fileno(stdout), TIOCGPGRP, &tgrp) < 0) { + perror("TIOCGPGRP"); + exit(1); + } + if (tgrp != getpgrp(0)) { + kill(0, SIGTTOU); + goto retry; + } + if ((term = getenv("TERM")) == 0 || tgetent(buf, term) <= 0) { + dumb++; ul_opt = 0; + } + else { + if (ioctl(fileno(stdout), TIOCGWINSZ, &win) < 0) { + Lpp = tgetnum("li"); + Mcol = tgetnum("co"); + } else { + if ((Lpp = win.ws_row) == 0) + Lpp = tgetnum("li"); + if ((Mcol = win.ws_col) == 0) + Mcol = tgetnum("co"); + } + if ((Lpp <= 0) || tgetflag("hc")) { + hard++; /* Hard copy terminal */ + Lpp = 24; + } + if (Mcol <= 0) + Mcol = 80; + + if (tailequ (fnames[0], "page") || !hard && tgetflag("ns")) + noscroll++; + Wrap = tgetflag("am"); + bad_so = tgetflag ("xs"); + clearptr = clearbuf; + eraseln = tgetstr("ce",&clearptr); + Clear = tgetstr("cl", &clearptr); + Senter = tgetstr("so", &clearptr); + Sexit = tgetstr("se", &clearptr); + if ((soglitch = tgetnum("sg")) < 0) + soglitch = 0; + + /* + * Set up for underlining: some terminals don't need it; + * others have start/stop sequences, still others have an + * underline char sequence which is assumed to move the + * cursor forward one character. If underline sequence + * isn't available, settle for standout sequence. + */ + + if (tgetflag("ul") || tgetflag("os")) + ul_opt = 0; + if ((chUL = tgetstr("uc", &clearptr)) == NULL ) + chUL = ""; + if (((ULenter = tgetstr("us", &clearptr)) == NULL || + (ULexit = tgetstr("ue", &clearptr)) == NULL) && !*chUL) { + if ((ULenter = Senter) == NULL || (ULexit = Sexit) == NULL) { + ULenter = ""; + ULexit = ""; + } else + ulglitch = soglitch; + } else { + if ((ulglitch = tgetnum("ug")) < 0) + ulglitch = 0; + } + + if (padstr = tgetstr("pc", &clearptr)) + PC = *padstr; + Home = tgetstr("ho", &clearptr); + if (Home == 0 || *Home == '\0') + { + if ((cursorm = tgetstr("cm", &clearptr)) != NULL) { + strcpy(cursorhome, tgoto(cursorm, 0, 0)); + Home = cursorhome; + } + } + EodClr = tgetstr("cd", &clearptr); + if ((chBS = tgetstr("bc", &clearptr)) == NULL) + chBS = "\b"; + + } + if ((shell = getenv("SHELL")) == NULL) + shell = _PATH_BSHELL; + } + no_intty = gtty(fileno(stdin), &otty); + gtty(fileno(stderr), &otty); + savetty = otty; + hardtabs = !(otty.sg_flags & XTABS); + if (! no_tty) { + otty.sg_flags &= ~ECHO; + otty.sg_flags |= MBIT; + } +} + +readch () +{ + char ch; + + if (read (2, &ch, 1) <= 0) + if (errno != EINTR) + exit(0); + else + ch = otty.sg_kill; + return (ch); +} + +static char BS = '\b'; +static char *BSB = "\b \b"; +static char CARAT = '^'; +#define ERASEONECHAR \ + if (docrterase) \ + write (2, BSB, sizeof(BSB)); \ + else \ + write (2, &BS, sizeof(BS)); + +ttyin (buf, nmax, pchar) +char buf[]; +register int nmax; +char pchar; +{ + register char *sptr; + register char ch; + register int slash = 0; + int maxlen; + char cbuf; + + sptr = buf; + maxlen = 0; + while (sptr - buf < nmax) { + if (promptlen > maxlen) maxlen = promptlen; + ch = readch (); + if (ch == '\\') { + slash++; + } + else if ((ch == otty.sg_erase) && !slash) { + if (sptr > buf) { + --promptlen; + ERASEONECHAR + --sptr; + if ((*sptr < ' ' && *sptr != '\n') || *sptr == RUBOUT) { + --promptlen; + ERASEONECHAR + } + continue; + } + else { + if (!eraseln) promptlen = maxlen; + longjmp (restore, 1); + } + } + else if ((ch == otty.sg_kill) && !slash) { + if (hard) { + show (ch); + putchar ('\n'); + putchar (pchar); + } + else { + putchar ('\r'); + putchar (pchar); + if (eraseln) + erase (1); + else if (docrtkill) + while (promptlen-- > 1) + write (2, BSB, sizeof(BSB)); + promptlen = 1; + } + sptr = buf; + fflush (stdout); + continue; + } + if (slash && (ch == otty.sg_kill || ch == otty.sg_erase)) { + ERASEONECHAR + --sptr; + } + if (ch != '\\') + slash = 0; + *sptr++ = ch; + if ((ch < ' ' && ch != '\n' && ch != ESC) || ch == RUBOUT) { + ch += ch == RUBOUT ? -0100 : 0100; + write (2, &CARAT, 1); + promptlen++; + } + cbuf = ch; + if (ch != '\n' && ch != ESC) { + write (2, &cbuf, 1); + promptlen++; + } + else + break; + } + *--sptr = '\0'; + if (!eraseln) promptlen = maxlen; + if (sptr - buf >= nmax - 1) + error ("Line too long"); +} + +expand (outbuf, inbuf) +char *outbuf; +char *inbuf; +{ + register char *instr; + register char *outstr; + register char ch; + char temp[200]; + int changed = 0; + + instr = inbuf; + outstr = temp; + while ((ch = *instr++) != '\0') + switch (ch) { + case '%': + if (!no_intty) { + strcpy (outstr, fnames[fnum]); + outstr += strlen (fnames[fnum]); + changed++; + } + else + *outstr++ = ch; + break; + case '!': + if (!shellp) + error ("No previous command to substitute for"); + strcpy (outstr, shell_line); + outstr += strlen (shell_line); + changed++; + break; + case '\\': + if (*instr == '%' || *instr == '!') { + *outstr++ = *instr++; + break; + } + default: + *outstr++ = ch; + } + *outstr++ = '\0'; + strcpy (outbuf, temp); + return (changed); +} + +show (ch) +register char ch; +{ + char cbuf; + + if ((ch < ' ' && ch != '\n' && ch != ESC) || ch == RUBOUT) { + ch += ch == RUBOUT ? -0100 : 0100; + write (2, &CARAT, 1); + promptlen++; + } + cbuf = ch; + write (2, &cbuf, 1); + promptlen++; +} + +error (mess) +char *mess; +{ + if (clreol) + cleareol (); + else + kill_line (); + promptlen += strlen (mess); + if (Senter && Sexit) { + tputs (Senter, 1, putch); + pr(mess); + tputs (Sexit, 1, putch); + } + else + pr (mess); + fflush(stdout); + errors++; + longjmp (restore, 1); +} + + +set_tty () +{ + otty.sg_flags |= MBIT; + otty.sg_flags &= ~ECHO; + stty(fileno(stderr), &otty); +} + +reset_tty () +{ + if (pstate) { + tputs(ULexit, 1, putch); + fflush(stdout); + pstate = 0; + } + otty.sg_flags |= ECHO; + otty.sg_flags &= ~MBIT; + stty(fileno(stderr), &savetty); +} + +rdline (f) +register FILE *f; +{ + register char c; + register char *p; + + p = Line; + while ((c = Getc (f)) != '\n' && c != EOF && p - Line < LINSIZ - 1) + *p++ = c; + if (c == '\n') + Currline++; + *p = '\0'; +} diff --git a/src/cmd/more/more.help b/src/cmd/more/more.help new file mode 100644 index 0000000..1ced5c9 --- /dev/null +++ b/src/cmd/more/more.help @@ -0,0 +1,24 @@ + +Most commands optionally preceded by integer argument k. Defaults in brackets. +Star (*) indicates argument becomes new default. +------------------------------------------------------------------------------- + Display next k lines of text [current screen size] +z Display next k lines of text [current screen size]* + Display next k lines of text [1]* +d or ctrl-D Scroll k lines [current scroll size, initially 11]* +q or Q or Exit from more +s Skip forward k lines of text [1] +f Skip forward k screenfuls of text [1] +b or ctrl-B Skip backwards k screenfuls of text [1] +' Go to place where previous search started += Display current line number +/ Search for kth occurrence of regular expression [1] +n Search for kth occurrence of last r.e [1] +! or :! Execute in a subshell +v Start up /usr/ucb/vi at current line +ctrl-L Redraw screen +:n Go to kth next file [1] +:p Go to kth previous file [1] +:f Display current file name and line number +. Repeat previous command +------------------------------------------------------------------------------- diff --git a/src/cmd/mount/Makefile b/src/cmd/mount/Makefile new file mode 100644 index 0000000..e2baa79 --- /dev/null +++ b/src/cmd/mount/Makefile @@ -0,0 +1,42 @@ +# +# Public Domain. 1996/1/15 - Steven Schultz +# +TOPSRC = $(shell cd ../../..; pwd) +include $(TOPSRC)/target.mk + +CFLAGS += -Werror + +SRCS = mount.c getmntopts.c mount_ufs.c +OBJS = mount.o getmntopts.o mount_ufs.o +MAN = mount.0 +MANSRC = mount.8 + +all: mount ${MAN} + +mount: ${OBJS} + ${CC} ${LDFLAGS} -o mount.elf ${OBJS} ${LIBS} + ${OBJDUMP} -S mount.elf > mount.dis + ${SIZE} mount.elf + ${ELF2AOUT} mount.elf $@ && rm mount.elf + +${MAN}: ${MANSRC} + ${MANROFF} ${MANSRC} > ${MAN} + +clean: + rm -f *.o *.elf ${MAN} mount *.elf *.dis tags *~ + +depend: ${SRCS} + mkdep ${CFLAGS} ${SRCS} + +install: all + cp ${MAN} ${DESTDIR}/share/man/cat8/ + install mount ${DESTDIR}/sbin/mount + +lint: ${SRCS} + lint -hax ${SRCS} + +tags: ${SRCS} + ctags ${SRCS} + +# DO NOT DELETE THIS LINE -- mkdep uses it. +# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY. diff --git a/src/cmd/mount/getmntopts.3 b/src/cmd/mount/getmntopts.3 new file mode 100644 index 0000000..e85cfb5 --- /dev/null +++ b/src/cmd/mount/getmntopts.3 @@ -0,0 +1,178 @@ +.\" 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. +.\" +.\" @(#)getmntopts.3 8.1.1 (2.11BSD) 1996/1/16 +.\" +.TH GETMNTOPTS 3 "January 16, 1996" +.UC 7 +.SH NAME +\fBgetmntopts\fP \- scan mount options +.SH SYNOPSIS +.B #include +.sp +.B void +.br +.B getmntopts(options, mopts, flagp) +.br +.B char *options; +.br +.B struct mntopt *mopts; +.br +.B int *flagp +.SH DESCRIPTION +The +.BR getmntopts () +function takes a comma separated option list and a list +of valid option names, and computes the bitmask +corresponding to the requested set of options. +.PP +The string +.I options +is broken down into a sequence of comma separated tokens. +Each token is looked up in the table described by +.I mopts +and the bits in +the word referenced by +.I flagp +are updated. +The flag word is not initialized by +.BR getmntopt . +The table, +.IR mopts , +has the following format: +.sp +.cs R 24 +.nf +struct mntopt { + char *m_option; /* option name */ + int m_inverse; /* is this a negative option, eg "dev" */ + int m_flag; /* bit to set, eg MNT_RDONLY */ +}; +.br +.fi +.cs R +.PP +The members of this structure are: +.sp +.TP 10 +\fIm_option\fP +the option name, +for example +``suid''. +.TP 10 +\fIm_inverse\fP +tells +.B getmntopts +that the name has the inverse meaning of the +bit. +For example, +``suid'' +is the string, whereas the +mount flag is +MNT_NOSUID. +In this case, the sense of the string and the flag +are inverted, so the +.I m_inverse +flag should be set. +.TP 10 +\fIm_flag\fP +the value of the bit to be set or cleared in +the flag word when the option is recognized. +The bit is set when the option is discovered, +but cleared if the option name was preceded +by the letters +``no''. +The +.I m_inverse +flag causes these two operations to be reversed. +.PP +Each of the user visible +.I MNT_ +flags has a corresponding +.I MOPT_ +macro which defines an appropriate +.I "struct mntopt" +entry. +To simplify the program interface and ensure consistency across all +programs, a general purpose macro, +.IR MOPT_STDOPTS , +is defined which +contains an entry for all the generic VFS options. +In addition, the macros +.I MOPT_FORCE +and +.I MOPT_UPDATE +exist to enable the +.I MNT_FORCE +and +.I MNT_UPDATE +flags to be set. +Finally, the table must be terminated by an entry with a NULL +first element. +.SH EXAMPLES +Most commands will use the standard option set. +Local filesystems which support the +.I MNT_UPDATE +flag, would also have an +.I MOPT_UPDATE +entry. +This can be declared and used as follows: +.sp +.nf +.cs R 24 +#include "mntopts.h" + +struct mntopt mopts[] = { + MOPT_STDOPTS, + MOPT_UPDATE, + { NULL } +}; + + ... + mntflags = 0; + ... + getmntopts(options, mopts, &mntflags) + ... +.br +.fi +.cs R +.SH DIAGNOSTICS +The +.B getmntopts +function displays an error message and exits if an +unrecognized option is encountered. +.SH SEE ALSO +err(3), +mount(8) +.SH HISTORY +The +.B getmntopts +function appeared in 4.4BSD. diff --git a/src/cmd/mount/getmntopts.c b/src/cmd/mount/getmntopts.c new file mode 100644 index 0000000..48b9b0a --- /dev/null +++ b/src/cmd/mount/getmntopts.c @@ -0,0 +1,82 @@ +/*- + * 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. + */ +#include +#include + +#include +#include +#include +#include + +#include "mntopts.h" + +void +getmntopts(options, m0, flagp) + char *options; + struct mntopt *m0; + int *flagp; +{ + register struct mntopt *m; + int negative; + register char *opt; + char *optbuf; + + /* Copy option string, since it is about to be torn asunder... */ + if ((optbuf = strdup(options)) == NULL) + err(1, NULL); + + for (opt = optbuf; (opt = strtok(opt, ",")) != NULL; opt = NULL) { + /* Check for "no" prefix. */ + if (opt[0] == 'n' && opt[1] == 'o') { + negative = 1; + opt += 2; + } else + negative = 0; + + /* Scan option table. */ + for (m = m0; m->m_option != NULL; ++m) + if (strcasecmp(opt, m->m_option) == 0) + break; + + /* Save flag, or fail if option is not recognised. */ + if (m->m_option) { + if (negative == m->m_inverse) + *flagp |= m->m_flag; + else + *flagp &= ~m->m_flag; + } else + errx(1, "-o %s: option not supported", opt); + } + + free(optbuf); +} diff --git a/src/cmd/mount/mntopts.h b/src/cmd/mount/mntopts.h new file mode 100644 index 0000000..86772f3 --- /dev/null +++ b/src/cmd/mount/mntopts.h @@ -0,0 +1,81 @@ +/*- + * 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. + * + * @(#)mntopts.h 8.3.3 (2.11BSD) 1997/6/29 + */ + +struct mntopt { + char *m_option; /* option name */ + int m_inverse; /* if a negative option, eg "dev" */ + int m_flag; /* bit to set, eg. MNT_RDONLY */ +}; + +/* User-visible MNT_ flags. */ +#define MOPT_ASYNC { "async", 0, MNT_ASYNC } +#define MOPT_NOATIME { "accesstime", 1, MNT_NOATIME } +#define MOPT_NODEV { "dev", 1, MNT_NODEV } +#define MOPT_NOEXEC { "exec", 1, MNT_NOEXEC } +#define MOPT_NOSUID { "suid", 1, MNT_NOSUID } +#define MOPT_RDONLY { "rdonly", 0, MNT_RDONLY } +#define MOPT_SYNC { "sync", 0, MNT_SYNCHRONOUS } +#define MOPT_QUOTAS { "quotas", 0, 0 } + +/* Control flags. */ +#define MOPT_FORCE { "force", 1, MNT_FORCE } +#define MOPT_UPDATE { "update", 0, MNT_UPDATE } + +/* Support for old-style "ro", "rw" flags. */ +#define MOPT_RO { "ro", 0, MNT_RDONLY } +#define MOPT_RW { "rw", 1, MNT_RDONLY } +#define MOPT_RQ { "rq", 1, MNT_RDONLY } + +/* Ignored options (used for control in fstab) */ +#define MOPT_NOAUTO { "na", }, \ + { "auto", } + +#define MOPT_FSTAB_COMPAT \ + MOPT_RO, \ + MOPT_RW, \ + MOPT_RQ + +/* Standard options which all mounts can understand. */ +#define MOPT_STDOPTS \ + MOPT_FSTAB_COMPAT, \ + MOPT_QUOTAS, \ + MOPT_NOATIME, \ + MOPT_NOAUTO, \ + MOPT_NODEV, \ + MOPT_NOEXEC, \ + MOPT_NOSUID, \ + MOPT_RDONLY + +void getmntopts(); diff --git a/src/cmd/mount/mount.8 b/src/cmd/mount/mount.8 new file mode 100644 index 0000000..fb5257e --- /dev/null +++ b/src/cmd/mount/mount.8 @@ -0,0 +1,276 @@ +.\" Copyright (c) 1980, 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. +.\" +.\" @(#)mount.8 8.7.3 (2.11BSD) 1997/7/3 +.\" +.TH MOUNT 8 "November 16, 1996" +.UC 7 +.SH NAME +\fBmount\fP \- mount file systems +.SH SYNOPSIS +.B mount +[ \fB\-adfruvw\fP ] +[ \fB\-t\fP \fIufs\fP | \fIexternal_type\fP ] +.br +.B mount +[ \fB\-dfruvw\fP ] +\fIspecial\fP | \fInode\fP +.br +.B mount +[ \fB\-dfruvw\fP ] +[ \fB\-o\fP \fIoptions\fP ] +[ \fB\-t\fP \fIufs\fP | \fIexternal_type\fP ] +.I special node +.SH DESCRIPTION +The +.B mount +command +calls the +mount(2) +system call to prepare and graft a +.I "special device" +on to the file system tree at the point +.IR node . +If either +.I special +or +.I node +are not provided, the appropriate information is taken from the +fstab(5) +file. +.PP +The system maintains a list of currently mounted file systems. +If no arguments are given to +.BR mount , +this list is printed. +.PP +The options are as follows: +.sp +.TP 10 +\fB\-a\fP +Causes everything to be done except for the actual system call. +This option is useful in conjunction with the +.TP 10 +\fB\-v\fP +flag to +determine what the +.B mount +command is trying to do. +.TP 10 +\fB\-f\fP +Forces the revocation of write access when trying to downgrade +a filesystem mount status from read-write to read-only. For 2.11BSD this +flag is currently not implemented. +.TP 10 +\fB\-o\fP +Options are specified with a \fB\-o\fP +flag followed by a comma separated string of options. +The following options are available: +.sp +.RS 1.0i +.TP 10 +async +All I/O +to the file system should be done asynchronously. + +.B This is a dangerous flag to set, +.B and should not be used unless you are prepared to recreate the file +.B system should your system crash. +.TP 10 +force +The same as +\fB\-f\fP; +forces the revocation of write access when trying to downgrade +a filesystem mount status from read-write to read-only. This is not +(and likely never will be) supported in 2.11BSD. +.TP 10 +noaccesstime +File access times are not updated. + +.B This is a performance optimization for filesystems used for largely +.B read-only, short-lived data, e.g., news. +.TP 10 +noauto +This filesystem should be skipped when mount is run with the \fB\-a\fP flag. +.TP 10 +na +Same as noauto. +.TP 10 +nodev +Do not interpret character or block special devices on the file system. +This option is useful for a server that has file systems containing +special devices for architectures other than its own. +.TP 10 +noexec +Do not allow execution of any binaries on the mounted file system. +This option is useful for a server that has file systems containing +binaries for architectures other than its own. +.TP 10 +nosuid +Do not allow set-user-identifier or set-group-identifier bits to take effect. +.TP 10 +rdonly +The same as +\fB\-r\fP; +mount the file system read-only (even the super-user may not write it). +.TP 10 +sync +All I/O +to the file system should be done synchronously. +.TP 10 +update +The same as +\fB\-u\fP; +indicate that the status of an already mounted file system should be changed. +.PP +Any additional options specific to a filesystem type that is not +one of the internally known types (see the +\fB\-t\fP +option) may be passed as a comma separated list; these options are +distinguished by a leading +\&- (dash). +Options that take a value are specified using the syntax -option=value. +At present no 2.11BSD mount options use the following form, the example +has been retained for illustrative purposes only. +For example, the mount command: +.sp +mount -t mfs -o nosuid,-N,-s=4000 /dev/dk0b /tmp +.PP +causes +.B mount +to execute the equivalent of: +.sp +/sbin/mount_mfs -o nosuid -N -s 4000 /dev/dk0b /tmp +.br +.RE 1.0i +.TP 10 +\fB\-r\fP +The file system is to be mounted read-only. +Mount the file system read-only (even the super-user may not write it). +The same as the +``rdonly'' +argument to the +\fB\-o\fP +option. +.TP 10 +\fB\-t\fP "\fIufs\fP | \fIexternal type\fP" +The argument following the +\fB\-t\fP +is used to indicate the file system type. +The type +.I ufs +is the default. \fIUfs\fP is also the only value supported by 2.11BSD other +than \fIswap\fP. Thus +the \fB\-t\fP will rarely be used. +The \fB\-t\fP option can be used +to indicate that the actions should only be taken on +filesystems of the specified type. +More than one type may be specified in a comma separated list. +The list of filesystem types can be prefixed with +``no'' +to specify the filesystem types for which action should +.I not +be taken. +For example, the +.B mount +command: +.sp +mount -a -t nonfs,mfs +.sp +mounts all filesystems except those of type +NFS +and +MFS. +.sp +If the type is not one of the internally known types, +mount will attempt to execute a program in +.I /sbin/mount_XXX +where +.I XXX +is replaced by the type name. +For example, mfs filesystems are mounted by the program +.IR /sbin/mount_mfs . +.TP 10 +\fB\-u\fP +The +\fB\-u\fP +flag indicates that the status of an already mounted file +system should be changed. +Any of the options discussed above (the +\fB\-o\fP +option) +may be changed; +also a file system can be changed from read-only to read-write +or vice versa. +An attempt to change from read-write to read-only will fail if any +files on the filesystem are currently open for writing unless the +\fB\-f\fP +flag is also specified. +This is currently not implemented in 2.11BSD. +The ability to change the flags (nodev, nosuid, etc) is however supported. +The set of options is determined by first extracting the options +for the file system from the +.I fstab +table, +then applying any options specified by the +\fB\-o\fP +argument, +and finally applying the +\fB\-r\fP +or +\fB\-w\fP +option. +.TP 10 +\fB\-v\fP +Verbose mode. +.TP 10 +\fB\-w\fP +The file system object is to be read and write. +.SH FILES +.TP 10 +/etc/fstab +file system table +.SH SEE ALSO +mount(2), +fstab(5), +umount(8) +.SH BUGS +It is possible for a corrupted file system to cause a crash. +.PP +.B mount +and this manpage were ported from 4.4BSD-Lite to 2.11BSD to gain the +ability to set the various flags such as \fBnodev\fP, \fBnosuid\fP and +so on. Multiple filesystem types are not supported and several of the +options and flags are not implemented. +.SH HISTORY +A +.B mount +command appeared in Version 6 AT&T UNIX. diff --git a/src/cmd/mount/mount.c b/src/cmd/mount/mount.c new file mode 100644 index 0000000..0a72d0f --- /dev/null +++ b/src/cmd/mount/mount.c @@ -0,0 +1,488 @@ +/* + * Copyright (c) 1980, 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. + */ +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +int debug, verbose, skipvfs, mountrw; + +int badvfsname(); +int badvfstype(); +char *catopt(); +struct statfs *getmntpt(); +char **makevfslist(); +void mangle(); +int mountfs(); +void prmount(); +void usage(); + +/* From mount_ufs.c. */ +int mount_ufs(); + +/* Map from mount otions to printable formats. */ +static struct opt { + int o_opt; + char *o_name; +} optnames[] = { + { MNT_ASYNC, "asynchronous" }, + { MNT_NOATIME, "noaccesstime" }, + { MNT_NODEV, "nodev" }, + { MNT_NOEXEC, "noexec" }, + { MNT_NOSUID, "nosuid" }, + { MNT_QUOTA, "with quotas" }, + { MNT_RDONLY, "read-only" }, + { MNT_SYNCHRONOUS, "synchronous" }, + { NULL } +}; + +int +main(argc, argv) + int argc; + register char *argv[]; +{ + char *mntonname, **vfslist, *vfstype; + register struct fstab *fs; + struct statfs *mntbuf; + int all, ch, i, init_flags, mntsize, rval; + char *options, *na; + + all = init_flags = 0; + options = NULL; + vfslist = NULL; + vfstype = "ufs"; + while ((ch = getopt(argc, argv, "adfo:rwt:uv")) != EOF) + switch (ch) { + case 'a': + all = 1; + break; + case 'd': + debug = 1; + break; + case 'f': +#ifdef notnow + init_flags |= MNT_FORCE; +#endif + break; + case 'o': + if (*optarg) + options = catopt(options, optarg); + break; + case 'r': + init_flags |= MNT_RDONLY; + mountrw = 0; + break; + case 't': + if (vfslist != NULL) + errx(1, "only one -t option may be specified."); + vfslist = makevfslist(optarg); + vfstype = optarg; + break; + case 'u': + init_flags |= MNT_UPDATE; + break; + case 'v': + verbose = 1; + break; + case 'w': + init_flags &= ~MNT_RDONLY; + mountrw = 1; + break; + case '?': + default: + usage(); + /* NOTREACHED */ + } + argc -= optind; + argv += optind; + +#define BADTYPE(type) \ + (strcmp(type, FSTAB_RO) && \ + strcmp(type, FSTAB_RW) && strcmp(type, FSTAB_RQ)) + + rval = 0; + switch (argc) { + case 0: + if (all) + while ((fs = getfsent()) != NULL) { + if (BADTYPE(fs->fs_type)) + continue; + /* + * Check to see if "na" is one of the options, + * if so, don't mount it. + */ + if (fs->fs_mntops && + (na = strstr(fs->fs_mntops, "na")) && + ((na = fs->fs_mntops) || na[-1] == ',') && + (na[2] == ',' || na[2] == '\0')) { + continue; + } + if (badvfsname(fs->fs_vfstype, vfslist)) + continue; + if (mountfs(fs->fs_vfstype, fs->fs_spec, + fs->fs_file, init_flags, options, + fs->fs_mntops)) + rval = 1; + } + else { + if ((mntsize = getmntinfo(&mntbuf, MNT_NOWAIT)) == 0) + err(1, "getmntinfo"); + for (i = 0; i < mntsize; i++) { + if (badvfstype(mntbuf[i].f_type, vfslist)) + continue; + prmount(mntbuf[i].f_mntfromname, + mntbuf[i].f_mntonname, mntbuf[i].f_flags); + } + } + exit(rval); + case 1: + if (vfslist != NULL) + usage(); + + if (init_flags & MNT_UPDATE) { + if ((mntbuf = getmntpt(*argv)) == NULL) + errx(1, + "unknown special file or file system %s.", + *argv); + if ((fs = getfsfile(mntbuf->f_mntonname)) == NULL) + errx(1, "can't find fstab entry for %s.", + *argv); + /* If it's an update, ignore the fstab file options. */ + fs->fs_mntops = NULL; + mntonname = mntbuf->f_mntonname; + } else { + if ((fs = getfsfile(*argv)) == NULL && + (fs = getfsspec(*argv)) == NULL) + errx(1, + "%s: unknown special file or file system.", + *argv); + if (BADTYPE(fs->fs_type)) + errx(1, "%s has unknown file system type.", + *argv); + mntonname = fs->fs_file; + } + rval = mountfs(fs->fs_vfstype, fs->fs_spec, + mntonname, init_flags, options, fs->fs_mntops); + break; + case 2: + /* + * If -t flag has not been specified, and spec contains either + * a ':' or a '@' then assume that an NFS filesystem is being + * specified ala Sun. Since 2BSD does not support nfs an + * error is declared here rather than from mountfs(). + */ + if (vfslist == NULL && strpbrk(argv[0], ":@") != NULL) + err(1, "nfs not supported"); + rval = mountfs(vfstype, + argv[0], argv[1], init_flags, options, NULL); + break; + default: + usage(); + /* NOTREACHED */ + } + + exit(rval); +} + +int +mountfs(vfstype, spec, name, flags, options, mntopts) + char *vfstype, *spec, *name, *options, *mntopts; + int flags; +{ + /* List of directories containing mount_xxx subcommands. */ + static char *edirs[] = { + _PATH_SBIN, + _PATH_USRSBIN, + NULL + }; + char *argv[100], **edir; + struct statfs sf; + pid_t pid; + int argc, i; + int status; + char *optbuf, execname[MAXPATHLEN + 1]; + + if (options == NULL) { + if (mntopts == NULL || *mntopts == '\0') + options = "rw"; + else + options = mntopts; + mntopts = ""; + if (debug) + printf("options: %s\n", options); + } + optbuf = catopt(mntopts ? strdup(mntopts) : 0, options); + + if (strcmp(name, "/") == 0) + flags |= MNT_UPDATE; +#ifdef notnow + if (flags & MNT_FORCE) + optbuf = catopt(optbuf, "force"); +#endif + if (flags & MNT_RDONLY) + optbuf = catopt(optbuf, "ro"); + if (mountrw) + optbuf = catopt(optbuf, "rw"); + if (flags & MNT_UPDATE) + optbuf = catopt(optbuf, "update"); + + argc = 0; + argv[argc++] = vfstype; + mangle(optbuf, &argc, argv); + argv[argc++] = spec; + argv[argc++] = name; + argv[argc] = NULL; + + if (debug) { + (void)printf("exec: mount_%s", vfstype); + for (i = 1; i < argc; i++) + (void)printf(" %s", argv[i]); + (void)printf("\n"); + return (0); + } + + switch (pid = vfork()) { + case -1: /* Error. */ + warn("vfork"); + free(optbuf); + return (1); + case 0: /* Child. */ + if (strcmp(vfstype, "ufs") == 0) + _exit(mount_ufs(argc, (char **) argv)); + + /* Go find an executable. */ + edir = edirs; + do { + (void)sprintf(execname, "%s/mount_%s", *edir, vfstype); + execv(execname, (char **)argv); + if (errno != ENOENT) + warn("exec %s for %s", execname, name); + } while (*++edir != NULL); + + if (errno == ENOENT) + warn("exec %s for %s", execname, name); + _exit(1); + /* NOTREACHED */ + default: /* Parent. */ + free(optbuf); + + if (waitpid(pid, &status, 0) < 0) { + warn("waitpid"); + return (1); + } + + if (WIFEXITED(status)) { + if (WEXITSTATUS(status) != 0) + return (WEXITSTATUS(status)); + } else if (WIFSIGNALED(status)) { + warnx("%s: %s", name, sys_siglist[WTERMSIG(status)]); + return (1); + } + + if (verbose) { + if (statfs(name, &sf) < 0) { + warn("%s", name); + return (1); + } + prmount(sf.f_mntfromname, sf.f_mntonname, sf.f_flags); + } + break; + } + + return (0); +} + +void +prmount(spec, name, flags) + char *spec, *name; + int flags; +{ + register struct opt *o; + register int f; + + (void)printf("%s on %s", spec, name); + + flags &= MNT_VISFLAGMASK; + for (f = 0, o = optnames; flags && o->o_opt; o++) + if (flags & o->o_opt) { + (void)printf("%s%s", !f++ ? " (" : ", ", o->o_name); + flags &= ~o->o_opt; + } + (void)printf(f ? ")\n" : "\n"); +} + +struct statfs * +getmntpt(name) + char *name; +{ + struct statfs *mntbuf; + register int i, mntsize; + + mntsize = getmntinfo(&mntbuf, MNT_NOWAIT); + for (i = 0; i < mntsize; i++) + if (strcmp(mntbuf[i].f_mntfromname, name) == 0 || + strcmp(mntbuf[i].f_mntonname, name) == 0) + return (&mntbuf[i]); + return (NULL); +} + +int +badvfsname(vfsname, vfslist) + char *vfsname; + register char **vfslist; +{ + + if (vfslist == NULL) + return (0); + while (*vfslist != NULL) { + if (strcmp(vfsname, *vfslist) == 0) + return (skipvfs); + ++vfslist; + } + return (!skipvfs); +} + +int +badvfstype(vfstype, vfslist) + int vfstype; + register char **vfslist; +{ +static char *vfsnames[] = INITMOUNTNAMES; + + if ((vfstype < 0) || (vfstype > MOUNT_MAXTYPE)) + return (0); + + return (badvfsname(vfsnames[vfstype], vfslist)); +} + +char ** +makevfslist(fslist) + char *fslist; +{ + register char **av; + int i; + register char *nextcp; + + if (fslist == NULL) + return (NULL); + if (fslist[0] == 'n' && fslist[1] == 'o') { + fslist += 2; + skipvfs = 1; + } + for (i = 0, nextcp = fslist; *nextcp; nextcp++) + if (*nextcp == ',') + i++; + if ((av = (char **)malloc((size_t)(i + 2) * sizeof(char *))) == NULL) { + warn(NULL); + return (NULL); + } + nextcp = fslist; + i = 0; + av[i++] = nextcp; + while ((nextcp = strchr(nextcp, ',')) != NULL) { + *nextcp++ = '\0'; + av[i++] = nextcp; + } + av[i++] = NULL; + return (av); +} + +char * +catopt(s0, s1) + char *s0; + char *s1; +{ + size_t i; + char *cp; + + if (s0 && *s0) { + i = strlen(s0) + strlen(s1) + 1 + 1; + if ((cp = (char *)malloc(i)) == NULL) + err(1, NULL); + (void)sprintf(cp, "%s,%s", s0, s1); + } else + cp = strdup(s1); + + if (s0) + free(s0); + return (cp); +} + +void +mangle(options, argcp, argv) + char *options; + int *argcp; + register char **argv; +{ + register char *p; + char *s; + register int argc; + + argc = *argcp; + for (s = options; (p = strsep(&s, ",")) != NULL;) + if (*p != '\0') + if (*p == '-') { + argv[argc++] = p; + p = strchr(p, '='); + if (p) { + *p = '\0'; + argv[argc++] = p+1; + } + } else { + argv[argc++] = "-o"; + argv[argc++] = p; + } + + *argcp = argc; +} + +void +usage() +{ + + (void)fprintf(stderr, + "usage: mount %s %s\n mount %s\n mount %s\n", + "[-dfruvw] [-o options] [-t ufs | external_type]", + "special node", + "[-adfruvw] [-t ufs | external_type]", + "[-dfruvw] special | node"); + exit(1); +} diff --git a/src/cmd/mount/mount_ufs.c b/src/cmd/mount/mount_ufs.c new file mode 100644 index 0000000..193802e --- /dev/null +++ b/src/cmd/mount/mount_ufs.c @@ -0,0 +1,108 @@ +/*- + * Copyright (c) 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include +#include + +#include +#include +#include +#include +#include + +#include "mntopts.h" + +void ufs_usage(); + +static struct mntopt mopts[] = { + MOPT_STDOPTS, + MOPT_ASYNC, + MOPT_SYNC, + MOPT_UPDATE, + { NULL } +}; + +int +mount_ufs(argc, argv) + int argc; + register char *argv[]; +{ + extern int optreset; + int ch, mntflags; + + mntflags = 0; + optind = optreset = 1; /* Reset for parse of new argv. */ + while ((ch = getopt(argc, argv, "o:")) != EOF) + switch (ch) { + case 'o': + getmntopts(optarg, mopts, &mntflags); + break; + case '?': + default: + ufs_usage(); + } + argc -= optind; + argv += optind; + + if (argc != 2) + ufs_usage(); + + if (mount(argv[0], argv[1], mntflags) < 0) { + (void)fprintf(stderr, "%s on %s: ", argv[0], argv[1]); + switch (errno) { + case EMFILE: + (void)fprintf(stderr, "mount table full.\n"); + break; + case EINVAL: + if (mntflags & MNT_UPDATE) + (void)fprintf(stderr, + "Specified device does not match mounted device.\n"); + else + (void)fprintf(stderr, + "Incorrect super block.\n"); + break; + default: + (void)fprintf(stderr, "%s\n", strerror(errno)); + break; + } + fflush(stderr); + return (1); + } + return (0); +} + +void +ufs_usage() +{ + (void)fprintf(stderr, "usage: mount_ufs [-o options] special node\n"); + exit(1); +} diff --git a/src/cmd/msec/Makefile b/src/cmd/msec/Makefile new file mode 100644 index 0000000..9830ddf --- /dev/null +++ b/src/cmd/msec/Makefile @@ -0,0 +1,40 @@ +# +# Public Domain. 1995/03/13 - Steven Schultz +# +TOPSRC = $(shell cd ../../..; pwd) +include $(TOPSRC)/target.mk + +CFLAGS += -Werror -I../../../sys/include + +BIN = msec +SRCS = $(BIN).c +OBJS = $(BIN).o +MAN = $(BIN).0 + +all: $(BIN) ${MAN} + +$(BIN): ${OBJS} + ${CC} ${LDFLAGS} -o $@.elf ${OBJS} ${LIBS} + ${OBJDUMP} -S $@.elf > $@.dis + ${SIZE} $@.elf + ${ELF2AOUT} $@.elf $@ + +.SUFFIXES: .0 .1 + +.1.0: + ${MANROFF} $*.1 > $@ + +clean: + rm -f *.o *.elf ${MAN} *.elf *.dis tags *~ $(BIN) + +depend: ${SRCS} + mkdep ${CFLAGS} ${SRCS} + +install: all + install -m 755 $(BIN) ${DESTDIR}/bin + +lint: ${SRCS} + lint -hax ${SRCS} + +tags: ${SRCS} + ctags ${SRCS} diff --git a/src/cmd/msec/msec.1 b/src/cmd/msec/msec.1 new file mode 100644 index 0000000..e69de29 diff --git a/src/cmd/msec/msec.c b/src/cmd/msec/msec.c new file mode 100644 index 0000000..9015b66 --- /dev/null +++ b/src/cmd/msec/msec.c @@ -0,0 +1,10 @@ +#include +#include + +void main() +{ + while(1) + { + printf("ms: %u\r",msec()); + } +} diff --git a/src/cmd/mv.c b/src/cmd/mv.c new file mode 100644 index 0000000..2ec6473 --- /dev/null +++ b/src/cmd/mv.c @@ -0,0 +1,299 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +/* + * mv file1 file2 + */ +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define DELIM '/' +#define MODEBITS 07777 + +#define ISDIR(st) (((st).st_mode&S_IFMT) == S_IFDIR) +#define ISLNK(st) (((st).st_mode&S_IFMT) == S_IFLNK) +#define ISREG(st) (((st).st_mode&S_IFMT) == S_IFREG) +#define ISDEV(st) \ + (((st).st_mode&S_IFMT) == S_IFCHR || ((st).st_mode&S_IFMT) == S_IFBLK) + +char *dname(); +struct stat s1, s2; +int iflag = 0; /* interactive mode */ +int fflag = 0; /* force overwriting */ + +main(argc, argv) + register char *argv[]; +{ + register i, r; + register char *arg; + char *dest; + + if (argc < 2) + goto usage; + while (argc > 1 && *argv[1] == '-') { + argc--; + arg = *++argv; + + /* + * all files following a null option + * are considered file names + */ + if (*(arg+1) == '\0') + break; + while (*++arg != '\0') switch (*arg) { + + case 'i': + iflag++; + break; + + case 'f': + fflag++; + break; + + default: + goto usage; + } + } + if (argc < 3) + goto usage; + dest = argv[argc-1]; + if (stat(dest, &s2) >= 0 && ISDIR(s2)) { + r = 0; + for (i = 1; i < argc-1; i++) + r |= movewithshortname(argv[i], dest); + exit(r); + } + if (argc > 3) + goto usage; + r = move(argv[1], argv[2]); + exit(r); + /*NOTREACHED*/ +usage: + fprintf(stderr, +"usage: mv [-if] f1 f2 or mv [-if] f1 ... fn d1 (`fn' is a file or directory)\n"); + return (1); +} + +movewithshortname(src, dest) + char *src, *dest; +{ + register char *shortname; + char target[MAXPATHLEN + 1]; + + shortname = dname(src); + if (strlen(dest) + strlen(shortname) > MAXPATHLEN - 1) { + error("%s/%s: pathname too long", dest, + shortname); + return (1); + } + sprintf(target, "%s/%s", dest, shortname); + return (move(src, target)); +} + +int +query (char *prompt, ...) +{ + va_list args; + register int i, c; + + va_start (args, prompt); + vfprintf(stderr, prompt, args); + va_end (args); + i = c = getchar(); + while (c != '\n' && c != EOF) + c = getchar(); + return (i == 'y'); +} + +move(source, target) + char *source, *target; +{ + int targetexists; + + if (lstat(source, &s1) < 0) { + Perror2(source, "Cannot access"); + return (1); + } + /* + * First, try to rename source to destination. + * The only reason we continue on failure is if + * the move is on a nondirectory and not across + * file systems. + */ + targetexists = lstat(target, &s2) >= 0; + if (targetexists) { + if (s1.st_dev == s2.st_dev && s1.st_ino == s2.st_ino) { + error("%s and %s are identical", source, target); + return (1); + } + if (iflag && !fflag && isatty(fileno(stdin)) && + query("remove %s? ", target) == 0) + return (1); + if (access(target, 2) < 0 && !fflag && isatty(fileno(stdin))) { + if (query("override protection %o for %s? ", + s2.st_mode & MODEBITS, target) == 0) + return (1); + } + } + if (rename(source, target) >= 0) + return (0); + if (errno != EXDEV) { + Perror2(errno == ENOENT && targetexists == 0 ? target : source, + "rename"); + return (1); + } + if (ISDIR(s1)) { + error("can't mv directories across file systems"); + return (1); + } + if (targetexists && unlink(target) < 0) { + Perror2(target, "Cannot unlink"); + return (1); + } + /* + * File can't be renamed, try to recreate the symbolic + * link or special device, or copy the file wholesale + * between file systems. + */ + if (ISLNK(s1)) { + register m; + char symln[MAXPATHLEN + 1]; + + m = readlink(source, symln, sizeof (symln) - 1); + if (m < 0) { + Perror(source); + return (1); + } + symln[m] = '\0'; + + m = umask(~(s1.st_mode & MODEBITS)); + if (symlink(symln, target) < 0) { + Perror(target); + return (1); + } + (void) umask(m); + goto cleanup; + } + if (ISDEV(s1)) { + struct timeval tv[2]; + + if (mknod(target, s1.st_mode, s1.st_rdev) < 0) { + Perror(target); + return (1); + } + + tv[0].tv_sec = s1.st_atime; + tv[0].tv_usec = 0; + tv[1].tv_sec = s1.st_mtime; + tv[1].tv_usec = 0; + (void) utimes(target, tv); + goto cleanup; + } + if (ISREG(s1)) { + register int fi, fo, n; + struct timeval tv[2]; + char buf[MAXBSIZE]; + + fi = open(source, 0); + if (fi < 0) { + Perror(source); + return (1); + } + + fo = creat(target, s1.st_mode & MODEBITS); + if (fo < 0) { + Perror(target); + close(fi); + return (1); + } + + for (;;) { + n = read(fi, buf, sizeof buf); + if (n == 0) { + break; + } else if (n < 0) { + Perror2(source, "read"); + close(fi); + close(fo); + return (1); + } else if (write(fo, buf, n) != n) { + Perror2(target, "write"); + close(fi); + close(fo); + return (1); + } + } + + close(fi); + close(fo); + + tv[0].tv_sec = s1.st_atime; + tv[0].tv_usec = 0; + tv[1].tv_sec = s1.st_mtime; + tv[1].tv_usec = 0; + (void) utimes(target, tv); + goto cleanup; + } + error("%s: unknown file type %o", source, s1.st_mode); + return (1); + +cleanup: + if (unlink(source) < 0) { + Perror2(source, "Cannot unlink"); + return (1); + } + return (0); +} + +char * +dname(name) + register char *name; +{ + register char *p; + + p = name; + while (*p) + if (*p++ == DELIM && *p) + name = p; + return name; +} + +/*VARARGS*/ +error(fmt, a1, a2) + char *fmt; +{ + + fprintf(stderr, "mv: "); + fprintf(stderr, fmt, a1, a2); + fprintf(stderr, "\n"); +} + +Perror(s) + char *s; +{ + char buf[MAXPATHLEN + 10]; + + sprintf(buf, "mv: %s", s); + perror(buf); +} + +Perror2(s1, s2) + char *s1, *s2; +{ + char buf[MAXPATHLEN + 20]; + + sprintf(buf, "mv: %s: %s", s1, s2); + perror(buf); +} diff --git a/src/cmd/nice.c b/src/cmd/nice.c new file mode 100644 index 0000000..ad84277 --- /dev/null +++ b/src/cmd/nice.c @@ -0,0 +1,34 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include +#include + +#include +#include + +main(argc, argv) + int argc; + char *argv[]; +{ + int nicarg = 10; + + if (argc > 1 && argv[1][0] == '-') { + nicarg = atoi(&argv[1][1]); + argc--, argv++; + } + if (argc < 2) { + fputs("usage: nice [ -n ] command\n", stderr); + exit(1); + } + if (setpriority(PRIO_PROCESS, 0, + getpriority(PRIO_PROCESS, 0) + nicarg) < 0) { + perror("setpriority"); + exit(1); + } + execvp(argv[1], &argv[1]); + perror(argv[1]); + exit(1); +} diff --git a/src/cmd/nm.c.use.disk b/src/cmd/nm.c.use.disk new file mode 100644 index 0000000..bbb0314 --- /dev/null +++ b/src/cmd/nm.c.use.disk @@ -0,0 +1,430 @@ +/* + * This version of nm will use a disk file, rather than trying to store + * the entire symbol table in memory. Useful for some sites. + * + * 11/25/90 - The ASCII version of archives has been implemented, but this + * program was NOT updated. the normal version of 'nm' not only handles + * .a files correctly but can even process /unix. so this program is of even + * less value than before, this program is extremely slow even for cases + * which the regular 'nm' works well. + */ + +/* + * print symbol tables for + * object or archive files + * + * nm [-fgoprun] [name ...] +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +struct nnlist { /* symbol table entry */ + char n_name[8]; /* symbol name */ + char nn_type; /* type flag */ + char nn_ovno; + unsigned int n_value; /* value */ +}; +#define SYMFILE "/tmp/nm.sym.XXXXXX" +#define SELECT arch_flg ? arp.ar_name : *argv +int numsort_flg; +int undef_flg; +int revsort_flg = 1; +int globl_flg; +int nosort_flg; +int arch_flg; +int prep_flg; +int file_flg; +struct ar_hdr arp; +struct exec exp; +FILE *fi; +long off; +long ftell(); +char *malloc(); +char *realloc(); +char *mktemp(); +int symfile = -1; +char *symfname; +long lseek(); +long save_sym(); +struct nnlist *get_sym(); +int cleanup(); + +main(argc, argv) +char **argv; +{ + int narg; + int compare(); + int fcompare(); + + signal(SIGINT,cleanup); + signal(SIGHUP,cleanup); + signal(SIGTERM,cleanup); + signal(SIGQUIT,cleanup); + + if (--argc>0 && argv[1][0]=='-' && argv[1][1]!=0) { + argv++; + while (*++*argv) switch (**argv) { + case 'n': /* sort numerically */ + numsort_flg++; + continue; + + case 'g': /* globl symbols only */ + globl_flg++; + continue; + + case 'u': /* undefined symbols only */ + undef_flg++; + continue; + + case 'r': /* sort in reverse order */ + revsort_flg = -1; + continue; + + case 'p': /* don't sort -- symbol table order */ + nosort_flg++; + continue; + + case 'o': /* prepend a name to each line */ + prep_flg++; + continue; + + case 'f': /* use a file insted of memory - slow */ + file_flg++; + continue; + + default: /* oops */ + fprintf(stderr, "nm: invalid argument -%c\n", *argv[0]); + cleanup(1); + } + argc--; + } + if (argc == 0) { + argc = 1; + argv[1] = "a.out"; + } + narg = argc; + while(argc--) { + fi = fopen(*++argv,"r"); + if (fi == NULL) { + fprintf(stderr, "nm: cannot open %s\n", *argv); + continue; + } + off = sizeof(exp.a_magic); + fread((char *)&exp, 1, sizeof(exp.a_magic), fi); /* get magic no. */ + if (exp.a_magic == ARMAG) + arch_flg++; + else if (N_BADMAG(exp)) { + fprintf(stderr, "nm: %s-- bad format\n", *argv); + continue; + } + fseek(fi, 0L, L_SET); + if (arch_flg) { + (void) nextel(fi); + if (narg > 1) + printf("\n%s:\n", *argv); + } + do { + long o; + register i, n, c; + struct nnlist sym; + struct nnlist *symp = NULL; + long *idxsymfile = NULL; + unsigned ovsizes[1 + NOVL]; + + fread((char *)&exp, 1, sizeof(struct exec), fi); + if (N_BADMAG(exp)) /* archive element not in */ + continue; /* proper format - skip it */ + if (exp.a_magic == A_MAGIC5 || exp.a_magic == A_MAGIC6) { + fread((char *)ovsizes, 1, sizeof ovsizes, fi); + o = 0L; + for (i = 1; i <= NOVL; i++) + o += (long) ovsizes[i]; + fseek(fi, o, L_INCR); + } + o = (long)exp.a_text + exp.a_data; + if ((exp.a_flag & 01) == 0) + o *= 2; + fseek(fi, o, L_INCR); + if (file_flg) + set_sym(); + i = 0; + while (fread((char *)&sym, sizeof(sym), 1, fi) == 1) { + if (globl_flg && (sym.nn_type&N_EXT)==0) + continue; + switch (sym.nn_type&N_TYPE) { + case N_UNDF: + c = 'u'; + if (sym.n_value) + c = 'c'; + break; + + default: + case N_ABS: + c = 'a'; + break; + + case N_TEXT: + c = 't'; + break; + + case N_DATA: + c = 'd'; + break; + + case N_BSS: + c = 'b'; + break; + + case N_FN: + c = 'f'; + break; + } + if (undef_flg && c!='u') + continue; + if (sym.nn_type&N_EXT) + c = toupper(c); + sym.nn_type = c; + if (file_flg) { + if (idxsymfile==NULL) + idxsymfile = (long *)malloc(sizeof(long)); + else + idxsymfile = (long *)realloc(idxsymfile, (i+1)*sizeof(long)); + } else { + if (symp==NULL) + symp = (struct nnlist *)malloc(sizeof(struct nnlist)); + else + symp = (struct nnlist *)realloc(symp, (i+1)*sizeof(struct nnlist)); + } + if (file_flg) { + if (idxsymfile == NULL) { + fprintf(stderr, "nm: out of memory on %s\n", *argv); + cleanup(2); + } + } else { + if (symp == NULL) { + fprintf(stderr, "nm: try using the '-f' option.\n"); + cleanup(2); + } + } + if (file_flg) + idxsymfile[i++] = save_sym(&sym); + else + symp[i++] = sym; + } + if (i == 0) { + fprintf(stderr, "nm: %s-- no name list\n", SELECT); + continue; + } + if (nosort_flg==0) + if (file_flg) + qsort(idxsymfile, i, sizeof(long), fcompare); + else + qsort(symp, i, sizeof(struct nnlist), compare); + if ((arch_flg || narg>1) && prep_flg==0) + printf("\n%s:\n", SELECT); + for (n=0; nnn_type; + } else + c = symp[n].nn_type; + if (!undef_flg) { + if (c=='u' || c=='U') + printf(" "); + else { + if (file_flg) + printf("%08x", tt->n_value); + else + printf("%08x", symp[n].n_value); + } + printf(" %c ", c); + } + if (file_flg) { + if (tt->nn_ovno) + printf("%-8.8s %d", tt->n_name, + tt->nn_ovno); + else + printf("%.8s", tt->n_name); + } else { + if (symp[n].nn_ovno) + printf("%-8.8s %d", symp[n].n_name, + symp[n].nn_ovno); + else + printf("%.8s", symp[n].n_name); + } + printf("\n"); + if (file_flg) + free(tt); + } + if (file_flg) + if (idxsymfile) + free((char *)idxsymfile); + else + if (symp) + free((char *)symp); + } while(arch_flg && nextel(fi)); + fclose(fi); + } + cleanup(0); +} + +compare(p1, p2) +register struct nnlist *p1, *p2; +{ + register i; + + if (numsort_flg) { + if (p1->n_value > p2->n_value) + return(revsort_flg); + if (p1->n_value < p2->n_value) + return(-revsort_flg); + } + for(i=0; in_name); i++) + if (p1->n_name[i] != p2->n_name[i]) { + if (p1->n_name[i] > p2->n_name[i]) + return(revsort_flg); + else + return(-revsort_flg); + } + return(0); +} + +nextel(af) +register FILE *af; +{ + register r; + + fseek(af, off, L_SET); + r = fread((char *)&arp, 1, sizeof(struct ar_hdr), af); /* read archive header */ + if (r <= 0) + return(0); + if (arp.ar_size & 1) + ++arp.ar_size; + off = ftell(af) + arp.ar_size; /* offset to next element */ + return(1); +} + +fcompare(fi1, fi2) +register long *fi1, *fi2; +{ + register i; + register struct nnlist *p1, *p2; + + p1 = get_sym(*fi1); + p2 = get_sym(*fi2); + if (numsort_flg) { + if (p1->n_value > p2->n_value) { + free((char *)p1); + free((char *)p2); + return(revsort_flg); + } + if (p1->n_value < p2->n_value) { + free((char *)p1); + free((char *)p2); + return(-revsort_flg); + } + } + for(i=0; in_name); i++) + if (p1->n_name[i] != p2->n_name[i]) { + if (p1->n_name[i] > p2->n_name[i]) { + free((char *)p1); + free((char *)p2); + return(revsort_flg); + } else { + free((char *)p1); + free((char *)p2); + return(-revsort_flg); + } + } + free((char *)p1); + free((char *)p2); + return(0); +} + +/* + * Save a symbol in symfile + */ + +long +save_sym(sym) +struct nlist *sym; +{ + long ret_val; + + if ((ret_val = lseek(symfile,0L,L_INCR)) < 0) { + perror("lseek:save_sym"); + cleanup(1); + } + + if (write(symfile,sym,sizeof(struct nlist)) < 0) { + perror("write:save_sym"); + cleanup(1); + } + return(ret_val); +} + +/* + * Retrieve a symbol from symfile + */ + +struct nnlist * +get_sym(offset) +long offset; +{ + struct nnlist *temp; + + if(lseek(symfile,offset,L_SET) < 0) { + perror("lseek:get_sym"); + cleanup(1); + } + + temp = (struct nnlist *) malloc(sizeof(struct nnlist)); + if(read(symfile,temp,sizeof(struct nnlist)) != sizeof (struct nnlist)) { + perror("read:get_sym"); + cleanup(1); + } + + return(temp); +} + +/* + * Open The symfile + */ + +set_sym() +{ + if (symfile != -1) + close(symfile); + else + symfname = mktemp(SYMFILE); + if ((symfile = open(symfname,O_CREAT|O_RDWR|O_TRUNC,0666)) < 0) { + perror("open:symfile"); + cleanup(1); + } +} + +/* + * Cleanup Routine + */ + +int +cleanup(n) +int n; +{ + if (file_flg) + unlink(symfname); + exit(n); +} diff --git a/src/cmd/nm/Makefile b/src/cmd/nm/Makefile new file mode 100644 index 0000000..be3959c --- /dev/null +++ b/src/cmd/nm/Makefile @@ -0,0 +1,25 @@ +TOPSRC = $(shell cd ../../..; pwd) +include $(TOPSRC)/target.mk +#include $(TOPSRC)/cross.mk + +CFLAGS += -Werror -Wall -I../ar + +SRCS = nm.c +OBJS = nm.o + +all: nm + +nm: ${OBJS} + ${CC} ${LDFLAGS} -o nm.elf ${OBJS} ${LIBS} + ${OBJDUMP} -S nm.elf > nm.dis + ${SIZE} nm.elf + ${ELF2AOUT} nm.elf $@ && rm nm.elf + +clean: + rm -f *.o *.elf ${MAN} nm *.elf *.dis tags *~ + +install: all + install nm ${DESTDIR}/bin/nm + +lint: + lint -havx -I../ar ${SRCS} diff --git a/src/cmd/nm/nm.c b/src/cmd/nm/nm.c new file mode 100644 index 0000000..c916944 --- /dev/null +++ b/src/cmd/nm/nm.c @@ -0,0 +1,427 @@ +/* + * nm - print name list. string table version + */ +#ifdef CROSS +# include +# include +# include +# include +# include +# include +# include +#else +# include +# include +# include +# include +# include +# include +# include +# include +# include +#endif +#include +#include + +#include "archive.h" + +CHDR chdr; + +char gflg, nflg, oflg, pflg, uflg, rflg = 1, archive; +char **xargv; + +union { + char mag_armag[SARMAG+1]; + struct exec mag_exp; +} mag_un; + +int narg, errs; + +void error(n, s) + char *s; +{ + fprintf(stderr, "nm: %s:", *xargv); + if (archive) { + fprintf(stderr, "(%s)", chdr.name); + fprintf(stderr, ": "); + } else + fprintf(stderr, " "); + fprintf(stderr, "%s\n", s); + if (n) + exit(2); + errs = 1; +} + +/* + * "borrowed" from 'ar' because we didn't want to drag in everything else + * from 'ar'. The error checking was also ripped out, basically if any + * of the criteria for being an archive are not met then a -1 is returned + * and the rest of 'ld' figures out what to do. + */ + +/* + * read the archive header for this member. Use a file pointer + * rather than a file descriptor. + */ +int get_arobj(fp) + FILE *fp; +{ + struct ar_hdr *hdr; + register int len, nr; + register char *p; + char buf[20]; + static char hb[sizeof(struct ar_hdr) + 1]; /* real header */ + + nr = fread(hb, 1, sizeof(struct ar_hdr), fp); + if (nr != sizeof(struct ar_hdr)) + return(-1); + + hdr = (struct ar_hdr *)hb; + if (strncmp(hdr->ar_fmag, ARFMAG, sizeof(ARFMAG) - 1)) + return(-1); + +/* Convert ar header field to an integer. */ +#define AR_ATOI(from, to, len, base) { \ + bcopy(from, buf, len); \ + buf[len] = '\0'; \ + to = strtoul(buf, (char **)NULL, base); } + + /* Convert the header into the internal format. */ + AR_ATOI(hdr->ar_date, chdr.date, sizeof(hdr->ar_date), 10); + AR_ATOI(hdr->ar_uid, chdr.uid, sizeof(hdr->ar_uid), 10); + AR_ATOI(hdr->ar_gid, chdr.gid, sizeof(hdr->ar_gid), 10); + AR_ATOI(hdr->ar_mode, chdr.mode, sizeof(hdr->ar_mode), 8); + AR_ATOI(hdr->ar_size, chdr.size, sizeof(hdr->ar_size), 10); + + /* Leading spaces should never happen. */ + if (hdr->ar_name[0] == ' ') + return(-1); + + /* + * 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) + return(-1); + nr = fread(chdr.name, 1, (size_t)len, fp); + if (nr != len) + return(-1); + chdr.name[len] = 0; + chdr.size -= len; + } else { + chdr.lname = 0; + bcopy(hdr->ar_name, chdr.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); +} + +off_t nextel(af, off) + FILE *af; + off_t off; +{ + fseek(af, off, SEEK_SET); + if (get_arobj(af) < 0) + return 0; + off += sizeof (struct ar_hdr) + chdr.size + (chdr.lname & 1); + return off; +} + +unsigned int fgetword (f) + register FILE *f; +{ + register unsigned int h; + + h = getc (f); + h |= getc (f) << 8; + h |= getc (f) << 16; + h |= getc (f) << 24; + return h; +} + +/* + * Read a symbol table entry. + * Return a number of bytes read, or -1 on EOF. + * Format of symbol record: + * 1 byte: length of name in bytes + * 1 byte: type of symbol (N_UNDF, N_ABS, N_TEXT, etc) + * 4 bytes: value + * N bytes: name + */ +int fgetsym (fi, name, value, type) + register FILE *fi; + register char *name; + unsigned *value; + unsigned short *type; +{ + register int len; + unsigned nbytes; + + len = getc (fi); + if (len <= 0) + return -1; + *type = getc (fi); + *value = fgetword (fi); + nbytes = len + 6; + if (name) { + while (len-- > 0) + *name++ = getc (fi); + *name = '\0'; + } else + fseek (fi, len, SEEK_CUR); + return nbytes; +} + +int compare(p1, p2) + register struct nlist *p1, *p2; +{ + + if (nflg) { + if (p1->n_value > p2->n_value) + return(rflg); + if (p1->n_value < p2->n_value) + return(-rflg); + } + return (rflg * strcmp(p1->n_name, p2->n_name)); +} + +void psyms(symp, nsyms) + register struct nlist *symp; + int nsyms; +{ + register int n, c; + + for (n=0; n 1) + printf("\n%s:\n", *xargv); + } + + do { + off_t o, curpos; + register int i, n; + struct nlist *symp = NULL; + + curpos = ftell(fi); + if (fread((char *)&mag_un.mag_exp, 1, + sizeof(struct exec), fi) != sizeof(struct exec)) + continue; + if (N_BADMAG(mag_un.mag_exp)) + continue; + + o = N_SYMOFF(mag_un.mag_exp); + fseek(fi, curpos + o, SEEK_SET); + n = mag_un.mag_exp.a_syms; + if (n == 0) { + error(0, "no name list"); + continue; + } + + i = 0; + while (n > 0) { + unsigned value; + unsigned short type; + + int c = fgetsym (fi, 0, &value, &type); + if (c <= 0) + break; + n -= c; + if (gflg && (type & N_EXT) == 0) + continue; + if (uflg && (type & N_TYPE) == N_UNDF && value != 0) + continue; + i++; + } + + fseek(fi, curpos + o, SEEK_SET); + symp = (struct nlist *)malloc((i+1) * sizeof (struct nlist)); + if (symp == 0) + error(1, "out of memory"); + i = 0; + n = mag_un.mag_exp.a_syms; + while (n > 0) { + char name [256]; + + int c = fgetsym(fi, name, &symp[i].n_value, &symp[i].n_type); + if (c <= 0) + break; + n -= c; + if (gflg && (symp[i].n_type & N_EXT) == 0) + continue; + if (uflg && (symp[i].n_type & N_TYPE) == N_UNDF && + symp[i].n_value != 0) + continue; + + symp[i].n_name = malloc(c - 5); + if (! symp[i].n_name) + error(1, "out of memory"); + strcpy (symp[i].n_name, name); + i++; + } + + if (pflg==0) + qsort(symp, i, sizeof(struct nlist), compare); + if ((archive || narg>1) && oflg==0) + printf("\n%s:\n", archive ? chdr.name : *xargv); + + psyms(symp, i); + if (symp) { + for (n=0; n>i; n++) + free (symp[i].n_name); + free((char *)symp); + symp = NULL; + } + } while(archive && (off = nextel(fi, off)) != 0); +out: + fclose(fi); +} + +int main(argc, argv) + int argc; + char **argv; +{ + if (--argc>0 && argv[1][0]=='-' && argv[1][1]!=0) { + argv++; + while (*++*argv) switch (**argv) { + + case 'n': + nflg++; + continue; + case 'g': + gflg++; + continue; + case 'u': + uflg++; + continue; + case 'r': + rflg = -1; + continue; + case 'p': + pflg++; + continue; + case 'o': + oflg++; + continue; + case 'h': +usage: fprintf (stderr, "Usage:\n"); + fprintf (stderr, " nm [-gunrpo] file...\n"); + fprintf (stderr, "Options:\n"); + fprintf (stderr, " -g Display only external symbols\n"); + fprintf (stderr, " -u Display only undefined symbols\n"); + fprintf (stderr, " -n Sort symbols numerically by address\n"); + fprintf (stderr, " -r Reverse the order of the sort\n"); + fprintf (stderr, " -p Do not sort the symbols\n"); + fprintf (stderr, " -o Precede each symbol by the file name\n"); + return(1); + default: + fprintf(stderr, "nm: invalid argument -%c\n", + *argv[0]); + goto usage; + } + argc--; + } + if (argc == 0) { + argc = 1; + argv[1] = "a.out"; + } + narg = argc; + xargv = argv; + while (argc--) { + ++xargv; + namelist(); + } + return(errs); +} diff --git a/src/cmd/nohup.sh b/src/cmd/nohup.sh new file mode 100644 index 0000000..a119688 --- /dev/null +++ b/src/cmd/nohup.sh @@ -0,0 +1,7 @@ +trap "" 1 15 +if test -t 2>&1 ; then + echo "Sending output to 'nohup.out'" + exec nice -5 $* >>nohup.out 2>&1 +else + exec nice -5 $* 2>&1 +fi diff --git a/src/cmd/od.c b/src/cmd/od.c new file mode 100644 index 0000000..1556b1c --- /dev/null +++ b/src/cmd/od.c @@ -0,0 +1,883 @@ +/* + * od -- octal, hex, decimal, character dump of data in a file. + * + * usage: od [-abBcdDefFhHiIlLopPs[n]vw[n]xX] [file] [[+]offset[.][b] [label]] + * + * where the option flags have the following meaning: + * character object radix signed? + * a byte (10) (n.a.) ASCII named byte stream + * b byte 8 no byte octal + * c byte (8) (no) character with octal non-graphic bytes + * d short 10 no + * D long 10 no + * e,F double (10) double precision floating pt. + * f float (10) single precision floating pt. + * h,x short 16 no + * H,X long 16 no + * i short 10 yes + * I,l,L long 10 yes + * o,B short 8 no (default conversion) + * O long 8 no + * s[n] string (8) ASCII graphic strings + * + * p indicate EVEN parity on 'a' conversion + * P indicate ODD parity on 'a' conversion + * v show all data - don't skip like lines. + * w[n] bytes per display line + * + * More than one format character may be given. + * If {file} is not specified, standard input is read. + * If {file} is not specified, then {offset} must start with '+'. + * {Offset} may be HEX (0xnnn), OCTAL (0nn), or decimal (nnn.). + * The default is octal. The same radix will be used to display the address. + */ +#include +#include +#include + +#define DBUF_SIZE BUFSIZ +#define BIG_DBUF 32 +#define NO 0 +#define YES 1 +#define EVEN -1 +#define ODD 1 +#define UNSIGNED 0 +#define SIGNED 1 +#define PADDR 1 +#define MIN_SLEN 3 + +int a_put(); +int b_put(); +int c_put(); +int s_put(); +int us_put(); +int l_put(); +int f_put(); +int d_put(); +int st_put(); + +struct dfmt { + int df_field; /* external field required for object */ + int df_size; /* size (bytes) of object */ + int df_radix; /* conversion radix */ + int df_signed; /* signed? flag */ + int df_paddr; /* "put address on each line?" flag */ + int (*df_put)(); /* function to output object */ + char *df_fmt; /* output string format */ +} *conv_vec[32]; /* vector of conversions to be done */ + +struct dfmt ascii = { 3, sizeof (char), 10, 0, PADDR, a_put, 0}; +struct dfmt byte = { 3, sizeof (char), 8, UNSIGNED, PADDR, b_put, 0}; +struct dfmt cchar = { 3, sizeof (char), 8, UNSIGNED, PADDR, c_put, 0}; +struct dfmt u_s_oct = { 6, sizeof (short), 8, UNSIGNED, PADDR, us_put, 0}; +struct dfmt u_s_dec = { 5, sizeof (short), 10, UNSIGNED, PADDR, us_put, 0}; +struct dfmt u_s_hex = { 4, sizeof (short), 16, UNSIGNED, PADDR, us_put, 0}; +struct dfmt u_l_oct = {11, sizeof (long), 8, UNSIGNED, PADDR, l_put, 0}; +struct dfmt u_l_dec = {10, sizeof (long), 10, UNSIGNED, PADDR, l_put, 0}; +struct dfmt u_l_hex = { 8, sizeof (long), 16, UNSIGNED, PADDR, l_put, 0}; +struct dfmt s_s_dec = { 6, sizeof (short), 10, SIGNED, PADDR, s_put, 0}; +struct dfmt s_l_dec = {11, sizeof (long), 10, SIGNED, PADDR, l_put, 0}; +struct dfmt flt = {14, sizeof (float), 10, SIGNED, PADDR, f_put, 0}; +struct dfmt dble = {21, sizeof (double), 10, SIGNED, PADDR, d_put, 0}; +struct dfmt string = { 0, 0, 8, 0, NO, st_put, 0}; + + +char usage[] ="usage: od [-abcdfhilopswvx] [file] [[+]offset[.][b] [label]]"; +char dbuf[DBUF_SIZE]; +char lastdbuf[DBUF_SIZE]; +int addr_base = 8; /* default address base is OCTAL */ +long addr = 0L; /* current file offset */ +long label = -1L; /* current label; -1 is "off" */ +int dbuf_size = 16; /* file bytes / display line */ +int _parity = NO; /* show parity on ascii bytes */ +char fmt[] = " %s"; /* 12 blanks */ +char *icvt(); +char *scvt(); +char *underline(); +long get_addr(); + + +/* + * special form of _ctype + */ + +#define A 01 +#define G 02 +#define D 04 +#define P 010 +#define X 020 +#define isdigit(c) (_ctype[c] & D) +#define isascii(c) (_ctype[c] & A) +#define isgraphic(c) (_ctype[c] & G) +#define isprint(c) (_ctype[c] & P) +#define ishex(c) (_ctype[c] & (X|D)) + +char _ctype[256] = { +/* 000 */ 0, 0, 0, 0, 0, 0, 0, 0, +/* 010 */ A, A, A, 0, A, A, 0, 0, +/* 020 */ 0, 0, 0, 0, 0, 0, 0, 0, +/* 030 */ 0, 0, 0, 0, 0, 0, 0, 0, +/* 040 */ P|A, P|G|A, P|G|A, P|G|A, P|G|A, P|G|A, P|G|A, P|G|A, +/* 050 */ P|G|A, P|G|A, P|G|A, P|G|A, P|G|A, P|G|A, P|G|A, P|G|A, +/* 060 */ P|G|D|A,P|G|D|A,P|G|D|A,P|G|D|A,P|G|D|A,P|G|D|A,P|G|D|A,P|G|D|A, +/* 070 */ P|G|D|A,P|G|D|A, P|G|A, P|G|A, P|G|A, P|G|A, P|G|A, P|G|A, +/* 100 */ P|G|A, P|G|A, P|G|A, P|G|A, P|G|A, P|G|A, P|G|A, P|G|A, +/* 110 */ P|G|A, P|G|A, P|G|A, P|G|A, P|G|A, P|G|A, P|G|A, P|G|A, +/* 120 */ P|G|A, P|G|A, P|G|A, P|G|A, P|G|A, P|G|A, P|G|A, P|G|A, +/* 130 */ P|G|A, P|G|A, P|G|A, P|G|A, P|G|A, P|G|A, P|G|A, P|G|A, +/* 140 */ P|G|A,X|P|G|A,X|P|G|A,X|P|G|A,X|P|G|A,X|P|G|A,X|P|G|A, P|G|A, +/* 150 */ P|G|A, P|G|A, P|G|A, P|G|A, P|G|A, P|G|A, P|G|A, P|G|A, +/* 160 */ P|G|A, P|G|A, P|G|A, P|G|A, P|G|A, P|G|A, P|G|A, P|G|A, +/* 170 */ P|G|A, P|G|A, P|G|A, P|G|A, P|G|A, P|G|A, P|G|A, 0, +/* 200 */ 0, 0, 0, 0, 0, 0, 0, 0, +/* 210 */ 0, 0, 0, 0, 0, 0, 0, 0, +/* 220 */ 0, 0, 0, 0, 0, 0, 0, 0, +/* 230 */ 0, 0, 0, 0, 0, 0, 0, 0, +/* 240 */ 0, 0, 0, 0, 0, 0, 0, 0, +/* 250 */ 0, 0, 0, 0, 0, 0, 0, 0, +/* 260 */ 0, 0, 0, 0, 0, 0, 0, 0, +/* 270 */ 0, 0, 0, 0, 0, 0, 0, 0, +/* 300 */ 0, 0, 0, 0, 0, 0, 0, 0, +/* 310 */ 0, 0, 0, 0, 0, 0, 0, 0, +/* 320 */ 0, 0, 0, 0, 0, 0, 0, 0, +/* 330 */ 0, 0, 0, 0, 0, 0, 0, 0, +/* 340 */ 0, 0, 0, 0, 0, 0, 0, 0, +/* 350 */ 0, 0, 0, 0, 0, 0, 0, 0, +/* 360 */ 0, 0, 0, 0, 0, 0, 0, 0, +/* 370 */ 0, 0, 0, 0, 0, 0, 0, 0, +}; + + +main(argc, argv) +int argc; +char **argv; +{ + register char *p; + register char *l; + register n, same; + struct dfmt *d; + struct dfmt **cv = conv_vec; + int showall = NO; + int field, llen, nelm; + int max_llen = 0; + + argv++; + argc--; + + if(argc > 0) + { + p = *argv; + if(*p == '-') + { + while(*++p != '\0') + { + switch(*p) + { + case 'a': + d = &ascii; + break; + case 'b': + d = &byte; + break; + case 'c': + d = &cchar; + break; + case 'd': + d = &u_s_dec; + break; + case 'D': + d = &u_l_dec; + break; + case 'e': + case 'F': + d = &dble; + break; + case 'f': + d = &flt; + break; + case 'h': + case 'x': + d = &u_s_hex; + break; + case 'H': + case 'X': + d = &u_l_hex; + break; + case 'i': + d = &s_s_dec; + break; + case 'I': + case 'l': + case 'L': + d = &s_l_dec; + break; + case 'o': + case 'B': + d = &u_s_oct; + break; + case 'O': + d = &u_l_oct; + break; + case 'p': + _parity = EVEN; + continue; + case 'P': + _parity = ODD; + continue; + case 's': + d = &string; + *(cv++) = d; + while (isdigit(p[1])) + d->df_size = (10 * d->df_size) + (*++p - '0'); + if (d->df_size <= 0) + d->df_size = MIN_SLEN; + showall = YES; + continue; + case 'w': + dbuf_size = 0; + while (isdigit(p[1])) + dbuf_size = (10 * dbuf_size) + (*++p - '0'); + if (dbuf_size == 0) + dbuf_size = BIG_DBUF; + continue; + case 'v': + showall = YES; + continue; + default: + printf("od: bad flag -%c\n", *p); + puts(usage); + exit(1); + } + *(cv++) = d; + } + argc--; + argv++; + } + } + + /* + * if nothing spec'd, setup default conversion. + */ + if(cv == conv_vec) + *(cv++) = &u_s_oct; + + *cv = (struct dfmt *)0; + + /* + * calculate display parameters + */ + for (cv = conv_vec; d = *cv; cv++) + { + nelm = (dbuf_size + d->df_size - 1) / d->df_size; + llen = nelm * (d->df_field + 1); + if (llen > max_llen) + max_llen = llen; + } + + /* + * setup df_fmt to point to uniform output fields. + */ + for (cv = conv_vec; d = *cv; cv++) + { + if (d->df_field) /* only if external field is known */ + { + nelm = (dbuf_size + d->df_size - 1) / d->df_size; + field = max_llen / nelm; + d->df_fmt = fmt + 12 - (field - d->df_field); + } + } + + /* + * input file specified ? + */ + if(argc > 0 && **argv != '+') + { + if (freopen(*argv, "r", stdin) == NULL) + { + perror(*argv); + exit(1); + } + argv++; + argc--; + } + + /* + * check for possible offset [label] + */ + if (argc > 0) + { + addr = get_addr(*argv); + offset(addr); + argv++; + argc--; + + if (argc > 0) + label = get_addr(*argv); + } + + /* + * main dump loop + */ + same = -1; + while ((n = fread(dbuf, 1, dbuf_size, stdin)) > 0) + { + if (same>=0 && bcmp(dbuf, lastdbuf, dbuf_size) == 0 && !showall) + { + if (same==0) + { + printf("*\n"); + same = 1; + } + } + else + { + line(n); + same = 0; + p = dbuf; + l = lastdbuf; + for (nelm = 0; nelm < dbuf_size; nelm++) + { + *l++ = *p; + *p++ = '\0'; + } + } + addr += n; + if (label >= 0) + label += n; + } + + /* + * Some conversions require "flushing". + */ + n = 0; + for (cv = conv_vec; *cv; cv++) + { + if ((*cv)->df_paddr) + { + if (n++ == 0) + put_addr(addr, label, '\n'); + } + else + (*((*cv)->df_put))(0, *cv); + } +} + +put_addr(a, l, c) +long a; +long l; +char c; +{ + fputs(icvt(a, addr_base, UNSIGNED, 7), stdout); + if (l >= 0) + printf(" (%s)", icvt(l, addr_base, UNSIGNED, 7)); + putchar(c); +} + +line(n) +int n; +{ + register i, first; + register struct dfmt *c; + register struct dfmt **cv = conv_vec; + + first = YES; + while (c = *cv++) + { + if (c->df_paddr) + { + if (first) + { + put_addr(addr, label, ' '); + first = NO; + } + else + { + putchar('\t'); + if (label >= 0) + fputs("\t ", stdout); + } + } + i = 0; + while (i < n) + i += (*(c->df_put))(dbuf+i, c); + if (c->df_paddr) + putchar('\n'); + } +} + +s_put(n, d) +short *n; +struct dfmt *d; +{ + printf(d->df_fmt, icvt((long)*n, d->df_radix, d->df_signed, d->df_field)); + return(d->df_size); +} + +us_put(n, d) +unsigned short *n; +struct dfmt *d; +{ + printf(d->df_fmt, icvt((long)*n, d->df_radix, d->df_signed, d->df_field)); + return(d->df_size); +} + +l_put(n, d) +long *n; +struct dfmt *d; +{ + printf(d->df_fmt, icvt(*n, d->df_radix, d->df_signed, d->df_field)); + return(d->df_size); +} + +d_put(f, d) +double *f; +struct dfmt *d; +{ + char fbuf[24]; + struct l { long n[2]; }; + +#if vax + if ((((struct l *)f)->n[0] & 0xff00) == 0x8000) /* Vax illegal f.p. */ + sprintf(fbuf, " %08x %08x", + ((struct l *)f)->n[0], ((struct l *)f)->n[1]); + else +#endif + + sprintf(fbuf, "%21.14e", *f); + printf(d->df_fmt, fbuf); + return(d->df_size); +} + +f_put(f, d) +float *f; +struct dfmt *d; +{ + char fbuf[16]; + +#if vax + if ((*(long *)f & 0xff00) == 0x8000) /* Vax illegal f.p. form */ + sprintf(fbuf, " %08x", *(long *)f); + else +#endif + sprintf(fbuf, "%14.7e", *f); + printf(d->df_fmt, fbuf); + return(d->df_size); +} + + +char asc_name[34][4] = { +/* 000 */ "nul", "soh", "stx", "etx", "eot", "enq", "ack", "bel", +/* 010 */ " bs", " ht", " nl", " vt", " ff", " cr", " so", " si", +/* 020 */ "dle", "dc1", "dc2", "dc3", "dc4", "nak", "syn", "etb", +/* 030 */ "can", " em", "sub", "esc", " fs", " gs", " rs", " us", +/* 040 */ " sp", "del" +}; + +a_put(cc, d) +char *cc; +struct dfmt *d; +{ + int c = *cc; + register char *s = " "; + register pbit = parity((int)c & 0377); + + c &= 0177; + if (isgraphic(c)) + { + s[2] = c; + if (pbit == _parity) + printf(d->df_fmt, underline(s)); + else + printf(d->df_fmt, s); + } + else + { + if (c == 0177) + c = ' ' + 1; + if (pbit == _parity) + printf(d->df_fmt, underline(asc_name[c])); + else + printf(d->df_fmt, asc_name[c]); + } + return(1); +} + +parity(word) +int word; +{ + register int p = 0; + register int w = word; + + if (w) + do + { + p ^= 1; + } while(w &= (~(-w))); + return (p? ODD:EVEN); +} + +char * +underline(s) +char *s; +{ + static char ulbuf[16]; + register char *u = ulbuf; + + while (*s) + { + if (*s != ' ') + { + *u++ = '_'; + *u++ = '\b'; + } + *u++ = *s++; + } + *u = '\0'; + return(ulbuf); +} + +b_put(b, d) +char *b; +struct dfmt *d; +{ + printf(d->df_fmt, icvt((long)*b & 0377, d->df_radix, d->df_signed, d->df_field)); + return(1); +} + +c_put(cc, d) +char *cc; +struct dfmt *d; +{ + register char *s; + register int n; + register int c = *cc & 0377; + + s = scvt(c, d); + for (n = d->df_field - strlen(s); n > 0; n--) + putchar(' '); + printf(d->df_fmt, s); + return(1); +} + +char *scvt(c, d) +int c; +struct dfmt *d; +{ + static char s[2]; + + switch(c) + { + case '\0': + return("\\0"); + + case '\b': + return("\\b"); + + case '\f': + return("\\f"); + + case '\n': + return("\\n"); + + case '\r': + return("\\r"); + + case '\t': + return("\\t"); + + default: + if (isprint(c)) + { + s[0] = c; + return(s); + } + return(icvt((long)c, d->df_radix, d->df_signed, d->df_field)); + } +} + +/* + * Look for strings. + * A string contains bytes > 037 && < 177, and ends with a null. + * The minimum length is given in the dfmt structure. + */ + +#define CNULL '\0' +#define S_EMPTY 0 +#define S_FILL 1 +#define S_CONT 2 +#define SBUFSIZE 1024 + +static char str_buf[SBUFSIZE]; +static int str_mode = S_EMPTY; +static char *str_ptr; +static long str_addr; +static long str_label; + +st_put(cc, d) +char *cc; +struct dfmt *d; +{ + register int c; + + if (cc == 0) + { + pr_sbuf(d, YES); + return(1); + } + + c = (*cc & 0377); + + if (str_mode & S_FILL) + { + if (isascii(c)) + put_sbuf(c, d); + else + { + *str_ptr = CNULL; + if (c == NULL) + pr_sbuf(d, YES); + str_mode = S_EMPTY; + } + } + else if (isascii(c)) + { + str_mode = S_FILL; + str_addr = addr + (cc - dbuf); /* ugly */ + if ((str_label = label) >= 0) + str_label += (cc - dbuf); /* '' */ + str_ptr = str_buf; + put_sbuf(c, d); + } + + return(1); +} + +put_sbuf(c, d) +int c; +struct dfmt *d; +{ + *str_ptr++ = c; + if (str_ptr >= (str_buf + SBUFSIZE)) + { + pr_sbuf(d, NO); + str_ptr = str_buf; + str_mode |= S_CONT; + } +} + +pr_sbuf(d, end) +struct dfmt *d; +int end; +{ + register char *p = str_buf; + + if (str_mode == S_EMPTY + || (!(str_mode & S_CONT) && (str_ptr - str_buf) < d->df_size)) + return; + + if (!(str_mode & S_CONT)) + put_addr(str_addr, str_label, ' '); + + while (p < str_ptr) + fputs(scvt(*p++, d), stdout); + + if (end) + putchar('\n'); +} + +/* + * integer to ascii conversion + * + * This code has been rearranged to produce optimized runtime code. + */ + +#define MAXINTLENGTH 32 +static char _digit[] = "0123456789abcdef"; +static char _icv_buf[MAXINTLENGTH+1]; +static long _mask = 0x7fffffff; + +char * +icvt (value, radix, signd, ndigits) +long value; +int radix; +int signd; +int ndigits; +{ + register long val = value; + register long rad = radix; + register char *b = &_icv_buf[MAXINTLENGTH]; + register char *d = _digit; + register long tmp1; + register long tmp2; + long rem; + long kludge; + int sign; + + if (val == 0) + { + *--b = '0'; + sign = 0; + goto done; /*return(b);*/ + } + + if (signd && (sign = (val < 0))) /* signed conversion */ + { + /* + * It is necessary to do the first divide + * before the absolute value, for the case -2^31 + * + * This is actually what is being done... + * tmp1 = (int)(val % rad); + * val /= rad; + * val = -val + * *--b = d[-tmp1]; + */ + tmp1 = val / rad; + *--b = d[(tmp1 * rad) - val]; + val = -tmp1; + } + else /* unsigned conversion */ + { + sign = 0; + if (val < 0) + { /* ALL THIS IS TO SIMULATE UNSIGNED LONG MOD & DIV */ + kludge = _mask - (rad - 1); + val &= _mask; + /* + * This is really what's being done... + * rem = (kludge % rad) + (val % rad); + * val = (kludge / rad) + (val / rad) + (rem / rad) + 1; + * *--b = d[rem % rad]; + */ + tmp1 = kludge / rad; + tmp2 = val / rad; + rem = (kludge - (tmp1 * rad)) + (val - (tmp2 * rad)); + val = ++tmp1 + tmp2; + tmp1 = rem / rad; + val += tmp1; + *--b = d[rem - (tmp1 * rad)]; + } + } + + while (val) + { + /* + * This is really what's being done ... + * *--b = d[val % rad]; + * val /= rad; + */ + tmp1 = val / rad; + *--b = d[val - (tmp1 * rad)]; + val = tmp1; + } + +done: + if (sign) + *--b = '-'; + + tmp1 = ndigits - (&_icv_buf[MAXINTLENGTH] - b); + tmp2 = signd ? ' ' : '0'; + while (tmp1 > 0) + { + *--b = tmp2; + tmp1--; + } + + return(b); +} + +long get_addr(s) +register char *s; +{ + register char *p; + register long a; + register int d; + + if (*s=='+') + s++; + if (*s=='x') + { + s++; + addr_base = 16; + } + else if (*s=='0' && s[1]=='x') + { + s += 2; + addr_base = 16; + } + else if (*s == '0') + addr_base = 8; + p = s; + while(*p) + { + if (*p++=='.') + addr_base = 10; + } + for (a=0; *s; s++) + { + d = *s; + if(isdigit(d)) + a = a*addr_base + d - '0'; + else if (ishex(d) && addr_base==16) + a = a*addr_base + d + 10 - 'a'; + else + break; + } + + if (*s == '.') + s++; + if(*s=='b') + a *= 512; + if(*s=='B') + a *= 1024; + + return(a); +} + +offset(a) +long a; +{ + if (canseek(stdin)) + { + /* + * in case we're accessing a raw disk, + * we have to seek in multiples of a physical block. + */ + fseek(stdin, a & 0xfffffe00L, 0); + a &= 0x1ffL; + } + dumbseek(stdin, a); +} + +dumbseek(s, offset) +FILE *s; +long offset; +{ + char buf[BUFSIZ]; + int n; + int nr; + + while (offset > 0) + { + nr = (offset > BUFSIZ) ? BUFSIZ : (int)offset; + if ((n = fread(buf, 1, nr, s)) != nr) + { + fprintf(stderr, "EOF\n"); + exit(1); + } + offset -= n; + } +} + +#include +#include + +canseek(f) +FILE *f; +{ + struct stat statb; + + return( (fstat(fileno(f),&statb)==0) && + (statb.st_nlink > 0) && /*!pipe*/ + (!isatty(fileno(f))) ); +} diff --git a/src/cmd/pagesize.c b/src/cmd/pagesize.c new file mode 100644 index 0000000..72f90b8 --- /dev/null +++ b/src/cmd/pagesize.c @@ -0,0 +1,12 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include + +int main() +{ + printf("%d\n", getpagesize()); + return 0; +} diff --git a/src/cmd/passwd/Makefile b/src/cmd/passwd/Makefile new file mode 100644 index 0000000..6f80b1c --- /dev/null +++ b/src/cmd/passwd/Makefile @@ -0,0 +1,55 @@ +# +# Copyright (c) 1988 The Regents of the University of California. +# All rights reserved. +# +# Redistribution and use in source and binary forms are permitted +# provided that the above copyright notice and this paragraph are +# duplicated in all such forms and that any documentation, +# advertising materials, and other materials related to such +# distribution and use acknowledge that the software was developed +# by the University of California, Berkeley. The name of the +# University may not be used to endorse or promote products derived +# from this software without specific prior written permission. +# THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR +# IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED +# WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. +# +TOPSRC = $(shell cd ../../..; pwd) +include $(TOPSRC)/target.mk + +CFLAGS += -Werror + +SRCS = passwd.c +OBJS = passwd.o +MAN = passwd.0 +MANSRC = passwd.1 + +all: passwd ${MAN} + +passwd: ${OBJS} + ${CC} ${LDFLAGS} -o passwd.elf ${OBJS} ${LIBS} + ${OBJDUMP} -S passwd.elf > passwd.dis + ${SIZE} passwd.elf + ${ELF2AOUT} passwd.elf $@ && rm passwd.elf + +${MAN}: ${MANSRC} + ${MANROFF} ${MANSRC} > ${MAN} + +clean: + rm -f *.o *.elf ${MAN} passwd *.elf *.dis tags *~ + +cleandir: clean + rm -f tags .depend + +depend: ${SRCS} + mkdep ${CFLAGS} ${SRCS} + +install: ${MAN} passwd + install -m 4755 passwd ${DESTDIR}/bin/passwd + cp ${MAN} ${DESTDIR}/share/man/cat1/ + +lint: ${SRCS} + lint ${CFLAGS} ${SRCS} + +tags: ${SRCS} + ctags ${SRCS} diff --git a/src/cmd/passwd/passwd.1 b/src/cmd/passwd/passwd.1 new file mode 100644 index 0000000..d2c6471 --- /dev/null +++ b/src/cmd/passwd/passwd.1 @@ -0,0 +1,48 @@ +.\" Copyright (c) 1988 The Regents of the University of California. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms are permitted +.\" provided that the above copyright notice and this paragraph are +.\" duplicated in all such forms and that any documentation, +.\" advertising materials, and other materials related to such +.\" distribution and use acknowledge that the software was developed +.\" by the University of California, Berkeley. The name of the +.\" University may not be used to endorse or promote products derived +.\" from this software without specific prior written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR +.\" IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED +.\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.\" @(#)passwd.1 6.5 (Berkeley) 2/22/89 +.\" +.TH PASSWD 1 "February 22, 1989" +.UC 4 +.SH NAME +passwd \- change password file information +.SH SYNOPSIS +.B passwd +[ user ] +.SH DESCRIPTION +.I Passwd +changes the user's password. First, the user is prompted for their old +password, and then, if that is correct, for the new password. The new +password must be entered twice to forestall any typing errors. The +super-user is not prompted for the old password. +.PP +Once the password has been verified, +.I passwd +uses +.IR mkpasswd (8) +to update the user database. This is run in the background, and, +at very large sites could take several minutes. Until this update +is completed, the password file is unavailable for other updates +and the new password will not be available to programs. +.SH FILES +.DT +/etc/master.passwd the user database +.RE +.SH "SEE ALSO" +chpass(1), login(1), passwd(5), mkpasswd(8), vipw(8) +.br +Robert Morris and Ken Thompson, +.I UNIX password security diff --git a/src/cmd/passwd/passwd.c b/src/cmd/passwd/passwd.c new file mode 100644 index 0000000..68beda9 --- /dev/null +++ b/src/cmd/passwd/passwd.c @@ -0,0 +1,256 @@ +/* + * Copyright (c) 1988 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +uid_t uid; + +main(argc, argv) + int argc; + char **argv; +{ + extern int errno; + struct passwd *pw; + struct rlimit rlim; + FILE *temp_fp; + int fd; + char *fend, *np, *passwd, *temp, *tend; + char from[MAXPATHLEN], to[MAXPATHLEN]; + char *getnewpasswd(); + + uid = getuid(); + switch(--argc) { + case 0: + if (!(pw = getpwuid(uid))) { + fprintf(stderr, "passwd: unknown user: uid %u\n", uid); + exit(1); + } + break; + case 1: + if (!(pw = getpwnam(argv[1]))) { + fprintf(stderr, "passwd: unknown user %s.\n", argv[1]); + exit(1); + } + if (uid && uid != pw->pw_uid) { + fprintf(stderr, "passwd: %s\n", strerror(EACCES)); + exit(1); + } + break; + default: + fprintf(stderr, "usage: passwd [user]\n"); + exit(1); + } + + (void)signal(SIGHUP, SIG_IGN); + (void)signal(SIGINT, SIG_IGN); + (void)signal(SIGQUIT, SIG_IGN); + (void)signal(SIGTSTP, SIG_IGN); + + rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY; + (void)setrlimit(RLIMIT_CPU, &rlim); + (void)setrlimit(RLIMIT_FSIZE, &rlim); + + (void)umask(0); + + temp = _PATH_PTMP; + if ((fd = open(temp, O_WRONLY|O_CREAT|O_EXCL, 0600)) < 0) { + if (errno == EEXIST) { + fprintf(stderr, + "passwd: password file busy -- try again later.\n"); + exit(0); + } + fprintf(stderr, "passwd: %s: %s", temp, strerror(errno)); + goto bad; + } + if (!(temp_fp = fdopen(fd, "w"))) { + fprintf(stderr, "passwd: can't write %s\n", temp); + goto bad; + } + passwd = _PATH_SHADOW; + if (!freopen(passwd, "r", stdin)) { + fprintf(stderr, "passwd: can't read %s\n", passwd); + goto bad; + } + + printf("Changing password for %s.\n", pw->pw_name); + np = getnewpasswd(pw, temp); + + if (!copy(pw->pw_name, np, temp_fp, pw)) + goto bad; + + (void)fclose(temp_fp); + (void)fclose(stdin); + + switch(fork()) { + case 0: + break; + case -1: + fprintf(stderr, "passwd: can't fork"); + goto bad; + /* NOTREACHED */ + default: + exit(0); + /* NOTREACHED */ + } + + if (makedb(temp)) { + fprintf(stderr, "passwd: mkpasswd failed"); +bad: fprintf(stderr, "; password unchanged.\n"); + (void)unlink(temp); + exit(1); + } + + /* + * possible race; have to rename four files, and someone could slip + * in between them. LOCK_EX and rename the ``passwd.dir'' file first + * so that getpwent(3) can't slip in; the lock should never fail and + * it's unclear what to do if it does. Rename ``ptmp'' last so that + * passwd/vipw/chpass can't slip in. + */ + (void)setpriority(PRIO_PROCESS, 0, -20); + fend = strcpy(from, temp) + strlen(temp); + tend = strcpy(to, _PATH_PASSWD) + strlen(_PATH_PASSWD); + bcopy(".dir", fend, 5); + bcopy(".dir", tend, 5); + if ((fd = open(from, O_RDONLY, 0)) >= 0) + (void)flock(fd, LOCK_EX); + /* here we go... */ + (void)rename(from, to); + bcopy(".pag", fend, 5); + bcopy(".pag", tend, 5); + (void)rename(from, to); + bcopy(".orig", fend, 6); + (void)rename(from, _PATH_PASSWD); + (void)rename(temp, passwd); + /* done! */ + exit(0); +} + +copy(name, np, fp, pw) + char *name, *np; + FILE *fp; + struct passwd *pw; +{ + register int done; + register char *p; + char buf[256]; + + for (done = 0; fgets(buf, sizeof(buf), stdin);) { + /* skip lines that are too big */ + if (!index(buf, '\n')) { + fprintf(stderr, "passwd: line too long.\n"); + return(0); + } + if (done) { + fprintf(fp, "%s", buf); + continue; + } + if (!(p = index(buf, ':'))) { + fprintf(stderr, "passwd: corrupted entry.\n"); + return(0); + } + *p = '\0'; + if (strcmp(buf, name)) { + *p = ':'; + fprintf(fp, "%s", buf); + continue; + } + if (!(p = index(++p, ':'))) { + fprintf(stderr, "passwd: corrupted entry.\n"); + return(0); + } + /* + * reset change time to zero; when classes are implemented, + * go and get the "offset" value for this class and reset + * the timer. + */ + fprintf(fp, "%s:%s:%d:%d:%s:%s:%s\n", + pw->pw_name, np, pw->pw_uid, pw->pw_gid, + pw->pw_gecos, pw->pw_dir, pw->pw_shell); + done = 1; + } + return(1); +} + +char * +getnewpasswd(pw, temp) + register struct passwd *pw; + char *temp; +{ + register char *p, *t; + char buf[10], salt[2], *crypt(), *getpass(); + time_t time(); + + if (uid && pw->pw_passwd && + strcmp(crypt(getpass("Old password:"), pw->pw_passwd), + pw->pw_passwd)) { + (void)printf("passwd: %s.\n", strerror(EACCES)); + (void)unlink(temp); + exit(1); + } + + for (buf[0] = '\0';;) { + p = getpass("New password:"); + if (!*p) { + (void)printf("Password unchanged.\n"); + (void)unlink(temp); + exit(0); + } + if (strlen(p) <= 5) { + printf("Please enter a longer password.\n"); + continue; + } + for (t = p; *t && islower(*t); ++t); + if (!*t) { + 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; + 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)); + while ((salt[0] = random() % 93 + 33) == ':'); + while ((salt[1] = random() % 93 + 33) == ':'); + return(crypt(buf, salt)); +} + +makedb(file) + char *file; +{ + int status, pid, w; + + if (!(pid = vfork())) { + execl(_PATH_MKPASSWD, "mkpasswd", "-p", file, NULL); + _exit(127); + } + while ((w = wait(&status)) != pid && w != -1); + return(w == -1 || status); +} diff --git a/src/cmd/pforth/..bin b/src/cmd/pforth/..bin new file mode 100644 index 0000000000000000000000000000000000000000..9bcb868824cb9b3b4a70619565e6a25497f2744e GIT binary patch literal 60116 zcmeIbe|VNxdf)kg1PCnKc!ElOcJ&W#Ns>RlHn6_ZJ+QvB zCrOg^(9$I7yZ~KFlJ8tbCe)?0;JwR9?JwU-k_8Jz2`1DItnb5)`e~>w4fj-FOE28gv+3w5vS?WvRoi@oq; z&?0DAV+7YEhmaRT3)eL#$B3=N!gXttlf+A)MeF)sE)6Eh8F(6sT;5uw02-V;4AnIj zJ32}Ol{N5JpjsNRIE9iM$d5qX#o0RCMt&4p))>Jx$p^^Gp}JykZ+}OzQc}jwCy196 z2g}_(U6s|yk0I9-`#RUd{}6obrecrnYDa#Yc=4veVqZshGJw1S`Jqkyov-ZZ@9HX- zDkES&3|6!0mC_Xa--BO7S*Rz|$lpb-?I`tX?>O@Bg>>X{lAJ~k{n62$oQMBpNZW#A zlH?Ndk03AZP~MnaL;e)P^h|}ro;hzk6Thb1{TE6uQNiY1<@HMS%8;9Ya3i!rk z4F0o$Z%g*UH_CSmCWqnex5XWUCB1$W`5EN8#uPB^B-l@=-?=t92mfP%Z%!`4)5K)) z(3WSn^mis#kT)oA84B`y$Um;`mS>Xp;Xe;wGqmNIyYNl$i#khPj;jxl*Q(dCDye4x zx1?zU75Zf*^0UYb_}2*U*k6Fcdidwe(^5{_;n%^}Hg@(~-(KX;DR&O`I}f%auMhIj z7Uc=#=ZR~WCWqm1f3mo-w55j;d=%MnSE~qq5}9sDYD)dRXW?IjuWNjInwj;-3Ro-oGlA+rc5_jMZACP@eJL#gYVQ7f$g zyCT+E>Md1D0c!;71Y6oaQ0favlC*(s0$bM6+h0!Ak^!(T_2}BpOm7VA&x>iix!kjj z@p}mDCG&0_WSvMAkAXP{9}ap0{pFrYPk$ft0DLp}ql2Xgh71?M>8_+^@Y(+B@I5KN z^(Opf`K{0P--iF68-Gj$mvc$IcbroHd`jMA*^$wN0Q|B)Sv%hM)220juHS#|s zuIb#^wI2Q-!7uDum9)dZ7x-tAUig0;__fI}{67hNb20}1PXqsKvJc*Msiv#7?J)d5 zOZhJxh5zS4r!6@F|1Sc*vGX+i&49Nj=iq-IesNbPD_(bU5&2&tFX~DM+g0R0K(6gd z*Weq-w~)KLa_b-1AA&7wj3DbD*#82yxU09nSXrAaXF>j>8M&Mkkl#mMM0!7SrWN^r zMXv4IQXD33NB-YZxktYaApa}kC0%``%}neOJp{|EBoF6Hjz zCi2}hy|SrBL7J$e{m2;UPb=XkUvyCxq+Opo-FD@W`f*CUJ&Ggo(?A6 zedI5y-(4Ck5!clv3Ej)sDEAF**;E>QaZR!kOg}GRQZ>Q<1NfyqeH_vU21}H=0c^;0 zCU!5p{aH_Kdxtu+*_)Eqhmjpao3kN$4EYu0rHvWD zLU#&mn|Tu{GWd4zhZ{peOR29i_zL-NfWHP_A91!j zz{y?kpCqnJ@piGgrAe}bcv<6fJAxI^2C$KUt((DG!A1l2xf!ez?Dc@HpTUN~b_VSE z8EgVlm6Zi^1OjJ49UDM=`{AkQe<(@bRySRyl9kAZ zmDA~xG$MZ;dBIx7J^W9@FKJvG8qkUS4djJuS0xqrzW~3u@ry%_v=QV+%B)oc--kR+ zyr}WTuxXe^{w8wmi|M+39QkLEm%hj}+tSnL=J|An)iQ@(B<%w75#q&zrEo;Qg8Ua# zIUHEuL;lOiwS)cPc>g}~QREty+HtrQ{;=N#tehubVUM zD%h`pEluU-o=%RRV1EVdkpT|xnW71I!G9I};eq~v9GuiW%$fsUn;w3W0`jjRFRGNv z71r%mgKR{Vb#@cn0imfGrDHZ;!jgi(qHL*w?ct4_B@s|0eRn&Vl46 z{Qm%7Tk7a`e{&o8w}>C=W=~ccEH@8S2JeIYO|bfiW#!jDk|gKAAC7ohT(TPce*~|6 zveL7OxDEL{@k1O9h6ejsjM*%LT@b4b7CY$Q-s0x+2-yELi}jXXF7-}<{jFK7Tq$P$ajo`iLJ=E1RSg!2o=8oA zStvOSb`-4G$hjZNeF-$nyg-2e2T-%)P&kD!|<pOm*G9XThdwT=-E>2y@q@rc~O5y#dY&0 zvgdU*-KF6>@CEqAoC6dGUrFvGdoEWqQ0%OGj5fh9TAiL(uR!+PZONumWoxO_w;K5f za`9F2z*n_`vgck4 zJDQSX@CEs;P02}k&!HAHaqRf8WZtq!)m0C5Mo4SDg4X~jQ4?nU0z)0Nb(ppW1?E8V3&?5{*V zgk0KG+U&VfBl1z@;^w0A2IMo!tWI7C>qfpD(miO<|HwCxIUDNxeFNa^kb(K(p+){ z>@e8Ub+h0Nuv6;cS`H&FqsbkxOJEC|p9>f6t_6NwQvW#Xh5Wiz$x8Tpfp1S%!`Iib zPH@WE3cnh@wlh8dY(s7{t-P_b7k*5>b7OfJenP!)H3}Sg+B7a!O~HGfvvA!r$uzv@ zHw)K2n;e5br%va(XHLT3f?w2C49+`)?DM&6 z`NoXgp7bK$MP3%tTf)wHJJ^b4G0#A<4|z56lGdO!Fpa#y^r5tj>&dFT&r0uWcPFGpv&<$jL+4?Cjs+A@@Dx<;cszX=Z?u_rVHab!@v+gtZu~ z6>L*ye^USFIF7-0kiHWB1Uy&1*rQTk>?jWB*UOdznG^UZ=%WfXzvfW_0bR5}z?4t4j`==y1jr^YaK`tlf zk?YyF)wGreF2lPYt>e(Jl~vfWaSf~&?4geCQpZazVKur1Hf5fTJ>`4w?l)^2d&+Cj z_u}$#sAC7n)h=!wzi(?0nD>qb|rFDEFotxFg8R*_V`x<&K^ne2=^Vxz;@iRXl^-i`@09 zz-!3`DAZgdn#B zc?I%K(lMA8lKUT0Iw(@6#XjC{uv$q4*y z`SKIV1bi#U-r^IieefILHw`?I9D#QqvFV8?lH>44;k(PT*X&M#odR33x;Vg9*Ut0E zH`U=PXl0;3^!a750gh=)i$j(EmYzOOG~WZO%wV2NQWr3f%MYh}^Xy6ueF5(A`4bt^ z;vuDl`N)BA#g9-vY0Do-qaygRl{AmRb*pDgCB0w;*4W1~s5zYGr6=Sgq@5#eNtSjP z`6}|l!Jgz8{Cn_qS(@j$C&65oXUQ_bWK z*e$Rnp0RNJ^@hnI%3AI|e`0cUY~T8+U16sWmZgPrfHx-hzd1e?QkuYB3l|S|mHL>Z zoye|*T*EAtxUgM8b}d}SQn9&IY4I}i7?^9_!|Zr_x?X8XlPDYfCU{+Aia0)xgEcWv zAL=cZE3P*fIRn-PR?j*w(qE~Bv3(KzDtO(isUBOP+H%IrW0hk0rRMZPN>6`Fm-kHC zNh^@HsIzCYV{p4N{$8>%)tf-Rrp)o!jsIcfTgde!?{F&b*yPqBIR<_g{LvYlYo42X zOJ~6CuUWjae~82XC2;%dp~l9vpcmJyc@NBXEuDcF|LQ?C-MyV35Er1@?*3lOtot;zSN_S3$!hpr>Xq5jqt}Xj1bM-ev={zb&?_gs@Y-M0IMmrfCk`XuN3KEK z1+V>D_(5z;!8a;52G!&Ud^fbPvn4q}Y~C7FPZJ-4Y8!_%nVf?^3N0LJNiGqegldLb z2Coudly7WV^B(an$a_`BccF!pdWYC?9{c!yCO_=B-?RI`&gaq&uKQ7Z1U(Y^cS}#X z!k|)_(Z50(n}xhws84f?rxGZff4z!&aBI5A3MvV9UvK0e+E(5z1>oZdirxBqsI9vIK&r+!$@*rbij&yH|G z=@wW4Y?)$ndjIGiSSwgve^-XU)An|-&NN%nfP4tK<#f48&XabLw581)(0bSaZDu}#)jq`-T3s9*EWVQ5LheOgxcUppUHJFl zxt2Fv`2u~9Jp5U7gZyGrPoIq;FIm0CoAWQ)_lJ-dajUR2O#PATo@Twuj>Rq6{-h1O z6?}2y>cRdkYmy4`2y(4rf=%SZ$V)5-XbL&s_9K}b+P-i9?zcv#LU*13KSjQ@?E`~7 zFEcK(wx1*I9BB_{aC3UNPOgGq0ltq!h^iKYiT}TxRXKI&YzXf z^4x+pIalc8>6c!x4Pex#gzy`pq50|UMGcr?PV_;8%xjQ?Gd&K2~`W9}=Wl6~dY4=F8xy_yFKK3YB?dPa71Mw962kVh5y)VEMV%pUFr_%!(*PLF5BN_RSe?t&i&U)+^GLsG}OaQ(-S%Uhlu zENw|vBA@ti%FE8-8XVSz@&kcy$}37 z^2{D**M*851%DrW)6;#)Y53I}n2RsYo)4S@YXjT#bVqU-zT5O3*YHh4n`!?wuwk%e zTgoLITk3TU1lt9+xKVITau4|wa;+kHYFXpXA}`8r39UfBj=Yq$ytBDnDs@s1uv^*? zV^!OL-0%~~++N_pkE9!UJ@S&RDd4)=jm$G!;d-I_HE9OtdS%;TYD}Q+T9o9I_vdBSGsh(yUr)=oCow3#)dTq(cUh@7v-hD=V+jW}_dO4o>P@Rj6C z*NE^?NmwIBz#GBqxTX~@j${51*a#TUYltPsw2Ayk*FbajC{j4NI|Y6OJbONAhu{UU z6JQUgd0Vo_$daqzm%x{FrN}MhtH?{cX0Ho+EV>o2*$acU99LFs!p~h?SfOq!kvoyO zw%64NKOo<=vAiCBJN!e9T`i^IVn?O-l{G#*u!}*su@zC5B?Z-W{M4-qu)upM;d`MGU+&Dx{16G86UUIw1>9b0iOb2)Yw(_ z#HyBk!SWvax7@M7G7_rVem1q_y&>560;ybXNu#xQ4+lgM}a>7$u*;1oX# z{sDM>BaMn@yX3zN-pF91Pg`(zOiFHmuLoa7c^oFf#i6@k+#(Kr!? zGp;$SGdaxlJ>y;v2rJHd@O$J-=lYhCj}5un^n%xZ(Y|Km+>+i88UtGoR@cADt*W`V?LThat}4vccxTfS6k zNt>OtgRf`Yv!*kV-%f^+JCT=sJq30lZ#O-alS9a7k(X*Gc#iW>u)foJ0$Ytk zLcQ>tzBv!J0mi)gvdo%)1CvrdWHMaj3?wX#I?%U`2hL6>E-Tl zjIL*&d&zX}X*0c&2IQ-z52YEJkZ&M!tv+OEL%ywkk%tM;??t|=JebPck$os^(NJn| z0=W*E`v;-Z4kPEs*|AJck8L|R3p}_pz2b%+NLxYPbRXBTBli16@YUc;+qh|=RgRt4 z!3MyVWYGJ_x0FAhs@y}K8e$LC(!&0Z<2d}{#`4+@9!^@0d?k~&A{UUaBQGKyF=<7< ziCl-wy%nLP9qb<1BiV_?+EuB;E8rWpVmp&3kn35?@W~&QM4DnzP6gQQq3V<|6VTWb5Ve=PL3MsU7Yw*KsT~wbkV8-`dr)3f_RN0IaXIGM@8 zA8+iQ7=L5;-m%OdXH6q-dOq!g(qW+u{$*Yj-*3mb}4|l!DIjURFaM?Op2|hf6e=LIQT`fGPy9NDL@RQ(+ES~kJ8#!P9 z;Y@xgT+bN~*E4p3of^efdM&3EuVowtKL=jZGF&+U|33UurvZ=GcpiBg>>gNn_Mn|U zNB%$^lXs*qPIz8g|2oe?a=Nl3JYmH62WtS^C06WoIZp0?HG#b;#zw{m_S=v>&EeKb zC&!?cP0Weq;Jd&-E6)20jmYPa*D7bX+ctn*1A98vd9fGy9&)2HwmHlu+rjF0X8DSp zFY}T}X&+bt3`dt*yg|^@7w+C20bifTxdTITateGHyh(kQ-mNX14`TZQ_yl;Ud%%6J zn>vA?egJ2G4gNm(CGclw?64kk)$9ZCyAR-L!7J8N$Qai*)X&~;X#zV07W|MsOVti` z3oQ7G>z@_mhF!b^q9a&{#*o+VrhgHq%#Yc)x0uf4FwVa^xqs}y#O^O=jr^uI% z^KenNx96pF-k&4w9BH56K4Yb)*qdJHX$coxuab6yv}GX+&U&eoyq}d5%e|k;;kidCxf@X?0(j_4Di#_|%=WmASOpC-IpB zq&4Q!W}nFC8Wd?8a%rn1H5w`qT~%dO|S*cf;==fjigtHG{;W%CJLpWMeb z_`v=+Ut6*#;=#bzADHoJ`ZNlw;4bjf;OYEMk7h28)8Mzke}_=#zbY3UeG!O!E{Z?eA#7;7N%732kF z_J8mnz%ML!hUv)4nH`oc&H+Lr6;Wr$?1}9Rx;Je{7-R@HF zKr#h(2>-?7(a}r}=h#!@`}bsb+)sj^`-|}$JG>JR?zW!?za$=>nc>EH$4lYJbQSy> zczueeZ|_mgE%2MOc!|gC!?Wl2!SBrC9hJe}9Yyq)x6$q@yae6|UjLV7><9f}@OJP9 z@LDXtiadAkgXu5tDc@>GVW z6iM9|z)5@brS2VBN;o`m3o$8xFMFxGIl~hkZBCkgfqe+NZsK@Wlo630%?3zoBW*GI zJ~12bNBG+!(DeExUR1RAOb{y;^*b?$F&t5u%d=^eFOOh^1~qy_qm$W3)8p3Z-Xy2FAtpgPMyeJ9h5F z8^KnB)xXr8Ui%pA59b2BI-K-^KLXCyn8O@{@aZaCBPYR+fz#G--;URplk;Gwz#g)^p)Dc*6|l2l)*;#@Ex7@H0i5;*JvRY& z!LH@7=4Qqed$v1Z%hB@|wNKrL47g_{Y4=I9Jn9-6w;t@)FQ(-={Dub7Hg|)M{ZiV# zY)FTM5%5#s){pCRGd?;5eg#~ghO@ZfImQ5Z>o2GN-!#+}-d8>g)|O)U(@h`q1Z+E) z{^S~`58;LKu7jTd*RH1+@jmEna9^Ye27g1?$W(UTtC= zb|~K5&q#U&7G+4Y2E~H2VWNP{=VcM*kQ1TX0WcVx=r{1EdLB$1K8ymEPal!6)eBT zdY?o&y>>JD*7(@&o$*>lg|zp`|9E=N&vtu9XHUnDVtGeru|gg8k^VmE%gdd`&K=K4qNP9G-g_HfTx}F2C{q>k9ogMM~;R#u)=R}9+|_q5+0uE zxJOzmX`zfvpBKwJmv`VZ@MY#{2``5yjbIaCO9Pg^E8YfnZ3au9M;!pWZ{F2GG4%Tw zSp8}C7>z?4yg_gXxjmKFDIZ1Nj+~Yk9xzHyf}I0P%k!msWU#`w>EmF!lMf5Dgd3ih z!FPc_@&MkH+yFlc{)q>0E^%-L_%3PJN&BG>r#02HR=@wCz0hHe;EnHQ{^iCCYgVZp z>@e74oC9;Ap~Adl3GFHNy~w#SX(vgmwTy)R=HH3$JUGUt!SdtjM3sC7`4V~JUTI)` z2gr9WZ~H;m#-S^$Cq#+-7i0+X-X}81|AoMDuPu$gX(YdZr6Ywne!>(pf#ou3&v@T$ z<8pzIiih{weu|hSDDiySpe{o=yp#7i0m4S;A{1rwTafv*V=&*J62w>%Ll86MvF{>( zJ)lYWR?5MQ|Gg}pX#n!kj7-v&X@@_8Cn?l1*3)wH{M#xJJ_D@|9P=;7$2R=kEG_Ef z+Y##wY|by6-s%JzSCJAVi4TaZEfG$+Yp_J71}Uo2a!CX?kqU_6*^_)Vw?`A(gD zv@ib+$Y6UMhtYOEE#~(fJ8UvJ%f4mk7dOEF|Tc~Zic@J zSy#hfha!J2$N!BSf2?-a2fnu#{UM(pFP8IrP{e#EZv}GHmp9FK^9=d?dAqSb(TBcY zXgCe|UY%hWvW?0SJB>V$rAPl*mhV6s)OQX?{@>;JKhE)g@+YZ|@7eu*l?mqk;(@@1 zcjIh_@7BGTLZL6zF~s`XKW{@pmpHaZ++b{4)OQTp_SKN@^F`a$W%-_*WnF@7`(@}B zWN=Nm2Jbs~26avM{X2vC9*4{qb$u7lkheKkTFjR(?=pFplGpd~48EhMZ15eth+B`- zVD_8Ab^5EsjuFSNV-+})n$oai5Ye&qx1}x@}eyzslN>^9> z0%cf^A&$dm;KdD&pS;Xa3C9Hc**f@sbF9nrnXDcC8SROG7Pxi+U)wMZI_|&_BNGr+;2Bf#5rSG2J{=GknLwv?zZO< zipNy-Y?mSLlWMuzX9W~&Yi$1t`p}Ta3K?cwd}q+MM8E1s-x)NRR^89K&2>mzo5sra zO@5u!j!T2M?a+RH9GX`h$Dew69dScm$Gr35=Cuw7=g^7kWAt?_2i4$LV}t!rfUa+9 zXtzGsh;`G*AABmrXNYNP@@KKt^gYPqSs%#zuBAcV_bemt`;&%epg4!DdtSEAdD%9_ zHEtcebKZ5pcP)K)GQ>HZY51t44-NKtbsqEiUS-U$?pA27yz2N~X4Lh4PURm(UtT-% z&V@_R807n(QAeyX!>ot%$-d8zwa1ZHL*{cFsb}BMr8mtaA}Q$V1K*7{pLx_bcKkYL z;~2MnUx94jW%Bs`r$PLup=#VYb}S?3oguE%>V`nyE@wU%g0GouQ;{e35E*ddX~^}; zcSNnn{j3cw@YOo5O?jQ)Ms_Ye1?fx2zWy|L%rH$G)+NgN;Vkux$Ibk)g{1IaX-uxVzYJ;Hv1FhABBZ{Uwk=QGdOr@o?T@mlEp2Kq+WH2(!FO!GNbI|}#vw3{e9!iC2rHp{AL#42PjEAl*E6s0+s1Uy zMcx%8MBCQIu|ZNeKZ)zB^)t;pV(y1+r@=IF*QSq~7R$8{e5cp;!G`&FOG5m?^L2=L zY?I$5vE9aox!U3T%Xu3G^z!Y<+prG|zL%Vj^LAY`%^&OL7#Ya?Yx^8e5zE^aHeaky z><`EFJCI|;IF1kJ&nKauhfLG1yyL?(=VJ(ze-UO2q@MM=1hpB{_LT#Z2d4H-?j0}e zoIE%&R@gf^Rqzq10taf#(*O3`g>0=Uz&{0PLpS8tj(C0p9Kth^A$Fe?-W~TjCT!bw zzZGK{^1hpGtPc)B4O!lh$MIp?*pqT@k#_~@AShDpo&!@8b=eDAx3Slbmyej#L^9E7xQS=w&eI=X)^ zFXp{aI50K3^UH;?@qJUf3Ojd=?tOE7tT1-am-Y&~(>AQ4Ov`%?GOnkMzDJ&K`*3FW z69qz+uP{0`hOuq7*LBxAv}SsXU;o>5u56d>(E2O_e7}w~fw8=e0V1ugdy8R@i-@ z@cQ_~&_{B@Lg4bgF7$oH}GJCOb`?U+#7K$heD5!2>VkeL4STXV5r;~E(I zKQE&i+W&LJF@GDpHgRLPCT<)2UWK-;+kAE%KbE210CWm^CySj*+W9QZDDOCwmp8Q&+ls(g8f|V+;lAJ z3)7k*&%L!_{cNlLj`h`k=pXFm%dxL5$2#k4^XV_IzxfRh+gX7uLtB=i|6;i<8TJ^l zc?(e9PPkt8snm}B8{2dY-r&08w?7Q|@!!?e(C#%ozxUxelW~za?l0Z5iG9nA1nov0 z)AY^3kTQE+QJ+R%707FdeeHO)?@f=sEx=!bVm_z0^F*E2jE{DXV2@&F?yZ>b4&#F; ze3!)UjQC9wgWnl>m)L6nhIb$_`zO}hZ$_zO7@=*e=@h?jq8;nGi#XbA{Pc(IiOpxv z`Wr0M5M{r2Vz54kJ|e&4r=I%6eDl@IZ<v%kJ zd{UK}Ip;T;eh1mHqHY|gtqk0F98_P~a0*hd0g5&o;p2J7$Fc2qQS!Ex4L<{Edmr>N zFg3~XfA7@py$8pe3Zr|!R+yaHHNL;_r4z#i||qPM=MDGr)rqlfvF!ZX(uVGDL;A$;vDj~pY3GOhGUxyl*LmA) zJq@PI$G%>d$zLIk*RIZ(kr3yS-|SSs0J&%Oo6W8z`8u!Y!P2W zj|S}-Jic3pxYw}^W%r6l3*1|vQnzT!TVUD%4zcyRn(blqtKax>JS;ARmnXu05;%Ov z#yDTsx#U=%)vMCAFv{yQxw@VwFhci)y>fy0669Ej$Ic1(m~MZW-T>LQScb<^+tHrk z?z=6oNF4j3kfp^u=8t;zYb;OyYcJMAe`&iHAGxNRU%LkPi{B(x*L>}eLEEkn`KME#mT$ zb_~A)SvSY&5hxz(?`6k{@734U>D~|U8z$B()=Akq`Msb#t}Jfwex&-=*L6#N0i@11 zh@-46WkbC8@HTwR+hHSHolD^Rw>czd0WvQnhu4R3`23~ufBj}QELq6}|{R->eih+2} zpq@TB3aMv#o<|wipH&^KpWlfx#4@dS#NL6IV%_3AwZHPd)3w%HybQ(u zRgP<8BYgB%UQbNYZ;pBWbTRYOH{qT8lEHlLJ+$xsHeYAk68F6FvCesa+BWlg?cQ>3 z=f;-$Qyiq?81g$;2FIOg$E(t;hoO4R=jFQJ_zz3-@`-m-IiBkj$nSB-?^}HfKGxaq zS}7aki^TdM?qeP)9pX*CLi}>o3+@H9lh3Ekn9se>@;LwFH?XojMBe@bdeM57o<5JZ zpRj(AeH;7Y8s+{JvVCQL#N$*vmd7@JRGafY!^8vUf36LtM<05;Qg;3ulxujdbxWx^ zd&HjxJQ!;D)YQC*+qNy`ar)-)U5=S=d*$F7RnVZdh z4`Mlqx6O;2b8;2CxG#LUs0#go_&q#OJ)Ytibe(8tkUCEyHVwZ4avdu$`5ni8SI==C zjsYwp?#WEguUXewOSETjozWgsGUShIU;}bIUhIJPSpGQi1d8gL&+_Kd9|4d0ZJEBu z)A{sAbNcm}K8MbE^u1-aVaRs;B&6^3z2W2Z&u;Xhzdug@d?}~@ar)=WIsK2*KNC6qkJCSUa{3>q zfA;3|KTiKl=JY>K|Ln`@SNG4ZEG_nr-!!}g=KkMr8OC#HOw4Q8?!@HmGMX|F=>$y>HPQz5!U6I=Fu?_vR+wcq6@Up1aJ)E?`GzX9U$^plmz$-*A5R)h}>7Ty}&zkBrciSYxR#CzP1ZE&seUU**Kf~g92 zwD0`!{C9c!_UamLM{s3e`~~lM=JTARjqhfF?+R*I?^tAAYvdUzprqXx_+8Ek2LUWthpm&1rW6E4(#2ad15Jr@sv{U%hNo zzFx77ep4lcs`?cGas7;+-h_|&r{L$S?<&5L`8}%oJ?m=!$FlUHvcd0rekx_d_dkCr z)$V0<9pjDzufeH*cpiPr&+FeoPkn~boc66}Uf;T@@3_v_rxiKQ zrBA$FXlZFFtSRi?^ZMw-sCQ6j?ia_gs*UYcHf*alPUYI;+WZb=J&MGZ@3@ccb&T7l ze44ghW9>)3)%x?u+O_O%311x{j`O3b#PcYVZ?K;1J2+MN>MkF}2s7U64If_i(y^B- zvyBI#Ez=NV%Z)P432k-HWFH%UyNY++H&|~;J50ryd|p2sF`c-PSR2ZYi!Vc?kZG@H zu{y6ohWuDnj%DOy%cIzt@&~wm!<+igl|lPdj4K zpLxGU{=c;U)@SvPb+T+7`>8-$zWvUTyiRo+-XT3cC+{~{41Pz~d15dfG0dHq z?zeP3o*SyiR9weg)2(9@^gB>7lN*TReez*={pD|2#kDrC>o`=$a2i^@LGHt4=IgMW z^LA|-n400+x|W^Cyk_EiOUAc|iNd<)H+K!r&Cf#C-@Ti@{{*q)&^qmh4Eb{J-uP6z z-{6g9{XH%od>b9heUt-@^Hbi^9wW94^}j`IxCI~e?@}kf?`s&LY{$3X?$w5&2Ko$S z{jAR^$RJ*Ts&Uuoczy9WcH*_6XwP)tV~9Ezayr^JEwAe&jJmg~bWMx8-yyI5C{Qu& zxGsssHpg^-6YitZy}vY9x;}gbnuhf0C1@oi=7WGAp17dcxdWM+S%pb~2<`3n~ z`pvxB(%0Le5oi>O*T5SyY)6I}n_hq{$NI>RKy&F>?rV_Y9msMHLizFNaqLGRZPi1{ zpM(sy>nZ2~Um&{jXI1zd;x{A{0|$m!;v`%~Bb zb$!Pq4@{QF-`q34cZxl~{t{owBZa;(zKN^(K3NpPTV>?3>`112cUS+Yyf| zc^^8iV*CBnYQD_)JY=z2NG9I~vazc~Fy`UCprQ{VEQhqOVnXY!kFS&Lr{ z-%o!auX^VDCKSsTGgx*z?aiM%1fPM$HS&Qx?dHk?>#ObF0-b`Q{(OG=BXq2XeGq*o z_H32>ZDhl5LPf~$w#&!kY~H?nyysxw$2@+o-Ezz;Z$Ia4_-&IlUgFC+=1MA+q6LKx0|QIHvPt9crQN zP`*C#9O=8@3n1GZd4J>fu}s#-6VU6B`3=*M^C!yI%X|5Mm3TMwadp3huJcR3jAXI$ zXeJwf8gd-H18LViSS)uMS>HH*qHo*-yapNm0J;G=E_7PLVHp5Jl|2J9u zk275CJ?Ni9j`=o7yZ;Q*u70p@{I?(&AW%&mN9|TaLOl(3?+w3Y6N+Oe-%lRHl;e8w2>h8+y2ikU-#wVh zu>4vR^$Vos^S5U*Q3!Dy%opeDGM~=J#q+i-+}}Vb68jqo`llUoEhs>jAjeqL8KE=Q zA`=D7wmuFqOlQ{c*k{|pMxfX~)oWUTH2a_oS>8&>-(9fpypJFIA(n0Zo**sC_Pu$u z@0j&E;A4<=7I$8#`we*O=y9EB-umQi#d>)D8S~g?+vM*|SnmvVu-B#s~a+o`L$`?wXdJm^>-_j$FnqXf3w26TefSodja2K@m@lty= zkl!ed{I`+61X<2p?HmFBFVW7}zy3zYTy3?@u}<45^P}2(ne@5ZOS3{7K0~a3wf7$x z!v*4>g3Pl464xiOz5bSo*nE9U_k8FaIp&RhZ@({WZ3+GCbt30M9B1~uWklWolyMUM z=kJ)z=fCK~TIxHO5B~t%V^?f{{y1fOT%#@!JFoSn$ICcJ^xb?uH;+F5PxbFGc`fg$ z%*G1h*CFSeKC{pA{#92WTW9N<_w`X^*P8#_c^UofZ^PvM?Kx;|*T6=vNBlnJ#5%K- zJg|rLe9dQp)p3nK2s!2!@Xz0uG0nC9CgamKy7p*$(fFQyQ(sH3hX6gWUs8^1Lv?JQ zGKE6Fj}W^a#r{$^wnu)FH1!Rx9Xp`7{=4>hEYZiF-{sR>S51p^sS!Sor5L{n=CMcF zHAOj=6=Q9VK)y4xhuC$>vG!$XClq};g|G7EdrYx>+tm$?LXH!4EX%z5*t**;?aRLb z9n7$gD(@aT`SKWEp}agco?+1k7m;JzW1RQFBGQ%f?K+H{w;BCvyS|rCqdoI$(|2g% zGxp}UA8qf~A$<_989WYOUnM)w{7s`GvHMuZh3(T$8x;NPd6sQk2DxTv-}nykd(aqU z9)?!(uOMy2@#cOj?gMM!?GMlQ{mmrvSclI+{$`SO)JAOs{|L=chibJyaBjxa`)aT z-(29=m3R6E$6Mq35A2@Y%k4s5ub$wVA+IyfJkNjPS$stq`TA2-D5pT|_}KzQUwFSg zJ|ChloUexJ{Bz0C&s6z={kC&M{g_S>!FNRASp;K$gUKp7w+7SPuD2s{JVz^{iK3&!+jz^Qlb7@{dB_g8ZGQpC|TroD8w-SU-QW z$$Swvk3rlu!tw004(rn2ZQ}8g%2y`~`}lpD1K!#VKkif*4bMJI6?pHaaKLMG@6gbzDw-bS}p z`OV;-3f0=mZ)c=mL6|(acWhOBk4L{-hHdostqlIg)M^hV8Luy59oD0xJVu;v|1;sy zPRi-uJMlH1)|uEn=5sRHFDzxZwWk=q2Ux$(rr(I%>r}^~#y|1W$3qAG8Hm|f!@&77pKiV$_CZ`1K5<|bLt{6GkT*vsa%++PF;x4`J~QoG(Bsg2 zZ7Ptao_%1y7{@$^;p6#swXdUn`&s)O#^&^K)N^d8_x-dfKOQ}9_-)Dey=$3X_1KAeD>J<_nO^mnF_brX zc!_$J>u=hsr%$WLO4KtR$n+lcY5PZx6Mbf0gS_P#$SkLSGyL!?7H1@0eBd_c4>qXrP zy48J>*Y&sgqVD(8FV$n+-|(AjtowU{2FJR;=Vw4QtZjcp9FLjy**}5|@;3vQ=F97^ z0{7VXLtW+e!dG|m?H`}*Y-e326NP&Hm$2{e4d(4D8>;sL zA0@ji#QM9}yad@Nehby#7j&JAb#2e&=<_`O4fG7=agJzb#F%y5e5M!OskM1*Ui|f87<*DvW`)E=)Ph}W}@wJk81X9oOupjy<=u6O7p!YbIju5{F89t6} zb=cy~TqB9LzYX@Y&`6f%`1bf>Ilg<9FJl3i_0OME$NGucKI?8>^Z8=C)rsZCGA&Dd z1X52q=GAX`GB3kz#)q)MC*p=LLy@0=*Y2Jy_I}}$> zZ<>O4-5r7AxbKG7w&xz^`3&?JByYbSgiht;uV=FR59=7`g=2mM*>w9>T-)05(`fm6 zG=W(U)9i;4DCX0y?KMAa(39_kVwtbQ+vWzyHL8x!AG|&}x_^wlaIBB`vZp(q=FsUT=V%*>~h|+pFw55HWl&nIe;wuc!7XZf4va z$armj8#4H=xcZHmzV%($SlAYyFIuo>+ctkgRG-H_R(}JSW5p2VB7F2et_{C2TAi*9 zmucsnK2p!$9yOST`)2HYLy+L_p~gB!EXtNC8LF|o{Pk2N{5Gl2BKf}%IeY##sy^3_!SzL5`_Xdsk!42z zu2%r_1+Y zws!NAxL((vuRQ0G^T0ey!tVorVPh;SUrwy+c64_@%7(Y0xPF^v{bGCU=h*((o<${o z-jNE~FL4fA_5wam8Eu;1@vYC*xrk3plk(*`UoFqyqgC&Crf2@S^iF4byE45$oJVgW z(`(Q4v^|$SFA|%!GSj;>kDk9#tKMD4mTmBOpSNe9*^ar!P#81*z#%@1{h_ThnXRAx zer<){cz)2&TEOX#%2)ny zKIhLheBiwBx1$}~)-N7^JO%w z$2l0*nK{;?Fphj25XWoV`q^hbLs7k6kAUA|%*Og?U!Oa^r_gWA+D-FqnSt?V_X@o))vc0-lFU*YjLAFB6~ju)|;8`Hg&_p;qfg}}9si!cMEd+d#S zm#4w>M-x;7`TNhx*4;LFoH<%Z?}^$5_xIY>hM~GnzYV6J4?_9xGwGKCnBjZvBj!q< z*{@J`zRU-IYnsXUgYe(92l8XXv37YPTW=VDj%Q`pDajDiO>^9yg1l}Y^$=%tOpoFB zU}9ePSot)6N8H~T7k5oy*$jN%=6AuAJ?`q z`b#vxd-EpopvY5bi`CJMiGuCDp~U2=oJb6$-_`<7w9&sUDWLvA_7mSb%2H`Sv} zf0NvhFDGJof2dP^9Q8NHt%JWOANy0x`b62|s$hSL(enCi z0UnT@OEEpx-M));v(1KBH-CdX%K9KLTerMy-SV<^%gfd+FI%^~Y~7+fSKZ>+wQiQZ z9kSm>pt$cTz>h-uIO@F#|2X8{Wdw4Zn9taGk=HYC>|4iK9BZ*W``7VetUtVNG6I<| z)`6iuV|M|3EZ_A&Jwlz{fVmw%ab-pzMC< z$xQwt@e@!iJM3*)-+v@slbZ`Y1BFT6W}kecu;1_g^J>*L?RZ|U&;9P{d}aB&aq&8k zdo{0Jx#u+hDM%lLbBe;+ZC-zfc4B`}&Cnm;A-0Y0Wcmx*wrz`;?|#NMdOb{g3trf^ ztp(j`d?8QY{XDpNor_V2CWPk!y*4Li{X*S{mqXgD^-BaCWTFp&lWE9tFII-AO2~JZ z*!FydIKQ67`q&rlQO&phKx)6Ht*xMZ8d*KdZD%sv&SZV9Y+Y&!hYu4a)5!Y8cRSqA zn%{Gm?-Iwd96QfLo-=ukOFmv)EqGN#4~aIt!jiuN@!C^38W{tDok| z*Pi8@@7#92d~{!^k8QKPGyS}AW1)IZ)R6A@8G+O{hhyX$$gX9MZ++cF zf#!V%%I7U0N59;|FP>+89Wu}TC21b><@3by;@GJkd*-z+=Bpk@`Mi#!x$;hDdH=Ag z+*agRSI3n0sdDm1Io`2v`E8jE`F!2;<3PVh8!=yPmalreb)#$9<~OYX#r9X*(1&xi z>nsOsb>D&Vby8p3uI<)$I@5FAnoG}qRc|=c`?-1aR&XFwuQk&oPXys{h$5_{Q+*0M*YK?e)YA( zx%whLYc~B6w#RaHDP*=?|MGRu&#$=F*$#Qv1h3o2`rU-L531M8{QRCT@98XW^_m%d zAM?eyy6llG|Msf(#(6Y0nU4DnnV#!uzMWC;Zl9#yonbGQG2z-mZD{&SiSjnVw^9EGkfmu=dyP@ z)2qw$Si0uayPxUZB3-|*Jj|(A$6Rx~czsj7z4Pd;%=C_DdJM-o?KNh4`b~ROV@|yd znO=LQ=P_-r_I77_t|jk4BTzf!@y7Mo@$H;3%yrIYx_j6wH0+D;`n8?Pj}luy56aHj z--NyesUNSee-~aIRKhvV2yulD^qA_}sqP5$0T+bhT4R4a3dOyz{BiOWi3^Zfb#4?yhVP6)@u|7{h)@M1S?P&_P zyt#B@`Io2C@lrtVZ$X!Fj%)MMuI#~MF1ov}YA@E|H2m{W^j#ageP_NW%ai-}f32nP z%H+Yq&QX6dicco*950N{Ufgfdo?~(84tFsoJEkUU< z{q$*SeMT{S4s~kxp78^-d9>S^<(X9fN|9(EHlwwVx4{T?1T2TJKT~-*Kiseo1;!a^Y?07Cl z{}`T0qnZE8@!EY|mLBDARLP&Jk{xsT{A|}BkUe(Y{EM^K6JAC3+Jd3sFQxspaNVEZ z7Ul22IG)~t;`Jlbynf_y&ve%}$4w`cxApzx?WoGDy_a&BGN+g`_LcRG<;80?Q3n1< zpPI4S=jQoA_<;w0;DH}_;0GS~fd_uzf&X?qkl!!W((J-tW?uohw>P*Cci$BE9DXnM z6!O9h_uRtpHl&WQ5s_y;JbLi#yo{#Sk&isv?Mzf4^?SF+w$$)}F|?Tn}Ul2&w15q}bT7c$()%7|_C zI+ppJJEm#JwnabMKK)}owHNdITWk7ad6vGNG{fW2W!fbl?OG@8>p$yA){wVAJWU(& zdX}#Z`@k{{wpAPP`yO@FM|+lE4_RMzt*7-c{W5dUF!oEcWr=I!{m;+(HqMKe{MepY?*e(Oi?RJ=(du}f9A(>Shf83H-ul2X@e{)>bi#5U)C>{AJYzkIj*ArZc!)i8>?r#<<*ss zI@i(Z{1pH~w4=UlC_vVs0#(<+wdHwezIy00!vV-TZp z$9PWyc4jV^uN#^x-|&evUxA9LH!zRhkxcJC>FRBnNAE_acRka4X&${5_|W>E&GZ=l zbJp)-W^X#vo0><@A4LuA&-C=;T2=Jb7yTIP**TA1^kcrB9>3nn?BA-&w-VX$@-lQRYhx>Y@3pLayR2W-dmi34 z^+S$3`ByVOUJqV@tj+q9so$2vAA>yJSr_}}Ds-u;9P?Suv0q7b&cI*$9y-(L)H4tB z^^JDoc-fB5oq6oUF|Yxh59ZN{<4L>uc34;U4+h(-Z!XYg=e=z<-M0D+7SV_H7W%{e z!+dMUeCwC%M_gxO-h*I20@>f%+yPauJMNS0FV`LOxt2v)d&(nFtbb?L4<3`W=dn8O zQ*5hwJ%&3DPG$14Opg2av)KI>nD#y1SgvtAc6n^ljv*ee%~M1+kMU<9>(n6qwbak` z81+eRQq=dj7@yPa&Jf z@sK~3-KQ;4hon%a+ALP~`HA&4DLxH<7n_Y4W?3E!mA?Yr$i|HFDUSKEp3eQVna?m4 zt{Go?l>O?O!Z!2YqBG3nK4CSn_0&J^2lU02dF(ck_Hpw2-9J>5E4ey3K0MDj@q{TH z``G7t{xkOZbRQn~8I8Y|`2^kg9kV!otmjI|e$+3P%d z-xmJs$&mMj4y~3~{5oUfH`2M+n#Jx3>@$ODbZZDvua-RihM(iZ@!XD%&-r|!+*#~w z>FOOScNgNDXTGPAFXQXz=hr-Kej`|)Ez>#qJmeUfAl!EG>afkU&vj)JM_dAgFeho6HTf-ec(+l5D+voa}_x;B$r~UN&7-AT$BJ4n==Y!*jR~&t8lDDdz}}5yy4cF%{Nk+Fgc^&#cRFA5C+dTh?`S9J~7%yQ9SUdX6E-a;xj<@xios zUq0$p*UvtW^^3M+nP(_7_Md6aBmHNc>z+)1chdXsvECjp0Pg+}=i^lhi}+ix7) z2g}Z{W<%^V(=GGd>D0z!2gXLnS|<06@10p9!nXpo|2ceH@y>A=;%|=c z9pBG@A1l26weVHN^p^Y1$vxa7ALEXAu@kpjAM-9ve~^WrquI9YwLbchFDojPW&8ERy^kno b`{~*7a1A|WkLR)NaXpH%>wR1gF`fMX?tbZG literal 0 HcmV?d00001 diff --git a/src/cmd/pforth/Makefile b/src/cmd/pforth/Makefile new file mode 100644 index 0000000..81b37e5 --- /dev/null +++ b/src/cmd/pforth/Makefile @@ -0,0 +1,50 @@ +# makefile for pForth +# Portable Forth written in 'C' +# by Phil Burk +# For more info visit http://www.softsynth.com/pforth/ +# +# Use 'make all' to build standalone pForth executable. +# PForth can be built in several stages using these targets: +# - pfdicapp = executable pForth with minimal dictionary. All from 'C'. +# - pfdicdat = image of full dictionary build by compiling Forth code. +# - pforthapp = executable with embedded dictionary image. DEFAULT 'all' target. +# +# The file 'pfdicdat.h' is generated by pForth. It contains a binary image of the Forth dictionary. +# It allows pForth to work as a standalone image that does not need to load a dictionary file. + +TOPSRC = $(shell cd ../..; pwd) +include $(TOPSRC)/target.mk +#include $(TOPSRC)/cross.mk + +# Options include: PF_SUPPORT_FP PF_NO_MALLOC PF_NO_INIT PF_DEBUG +# See "docs/pf_ref.htm" file for more info. + +CFLAGS += -Wall -Os +#CFLAGS += -DPF_SUPPORT_FP +CFLAGS += -DPF_STATIC_DIC +LIBS += -lm + +OBJS = pf_cglue.o pf_clib.o pf_core.o pf_inner.o \ + pf_io.o pf_io_none.o pf_main.o pf_mem.o pf_save.o \ + pf_text.o pf_words.o pfcompil.o pfcustom.o +#OBJS += pf_io_posix.o +OBJS += pf_io_stdio.o + +all: ../pforth ../../lib/pforth.dic + +../pforth: ${OBJS} + ${CC} ${LDFLAGS} -o pforth.elf ${OBJS} ${LIBS} + ${OBJDUMP} -S pforth.elf > pforth.dis + ${SIZE} pforth.elf + ${ELF2AOUT} pforth.elf $@ + +pfdicdat.h pforth.dic: + (cd fth; ../pforth.elf -i system.fth) + mv fth/pforth.dic pforth.dic + mv fth/pfdicdat.h $@ + +../../lib/pforth.dic: pforth.dic + cp -p $< $@ + +clean: + rm -f *.o ${MAN} ../id ../groups ../whoami *.elf *.dis tags *~ diff --git a/src/cmd/pforth/Makefile-orig b/src/cmd/pforth/Makefile-orig new file mode 100644 index 0000000..3b18ad9 --- /dev/null +++ b/src/cmd/pforth/Makefile-orig @@ -0,0 +1,110 @@ +# makefile for pForth +# Portable Forth written in 'C' +# by Phil Burk +# For more info visit http://www.softsynth.com/pforth/ +# +# See "help" target below. + +.POSIX: + +# Options include: PF_SUPPORT_FP PF_NO_MALLOC PF_NO_INIT PF_DEBUG +# See "docs/pf_ref.htm" file for more info. + +TOPSRC = $(shell cd ../..; pwd) +include $(TOPSRC)/target.mk + +FULL_WARNINGS = \ +# -c89 \ + -fsigned-char \ + -fno-builtin \ + -fno-unroll-loops \ + -fpeephole \ + -fno-keep-inline-functions \ + -pedantic \ + -Wcast-qual \ + -Wall \ + -Wwrite-strings \ + -Winline \ + -Wmissing-prototypes \ + -Wmissing-declarations + +CCOPTS = -DPF_SUPPORT_FP -O2 -g $(FULL_WARNINGS) + +IO_SOURCE = pf_io_posix.c +#IO_SOURCE = pf_io_stdio.c + +EMBCCOPTS = -DPF_STATIC_DIC + +####################################### +PFBASESOURCE = pf_cglue.c pf_clib.c pf_core.c pf_inner.c \ + pf_io.c pf_io_none.c pf_main.c pf_mem.c pf_save.c \ + pf_text.c pf_words.c pfcompil.c pfcustom.c +PFSOURCE = $(PFBASESOURCE) $(IO_SOURCE) + +XCPPFLAGS = $(CDEFS) -I. + +COMPILE = $(CC) $(CCOPTS) $(CFLAGS) $(XCPPFLAGS) $(CPPFLAGS) +LINK = $(CC) $(LDFLAGS) + +.SUFFIXES: .c .o .eo + +PFOBJS = $(PFSOURCE:.c=.o) +PFEMBOBJS = $(PFSOURCE:.c=.eo) + +.c.o: + $(COMPILE) -c -o $@ $< + +.c.eo: + $(COMPILE) $(EMBCCOPTS) -c -o $@ $< + +all: pforth_standalone + +# Build pforth by compiling 'C' source. +pforth: $(PFOBJS) + $(LINK) -o $@ $(PFOBJS) + +# Build basic dictionary image by running newly built pforth and including "system.fth". +pfdicdat.h: pforth + wd=$$(pwd); (cd fth; $${wd}/pforth -i system.fth) + mv fth/pforth.dic pforth.dic + mv fth/pfdicdat.h $@ + +pforth_standalone: pfdicdat.h $(PFEMBOBJS) + $(LINK) -o $@ $(PFEMBOBJS) -lm + mv pforth .. + mv pforth.dic .. + @echo "" + @echo "Standalone pForth executable written to pforth_standalone" + + +# target aliases +pfdicapp: pforth + +pfdicdat: pfdicdat.h + +pforthapp: pforth_standalone + +help: + @echo "Use 'make all' to build standalone pForth executable." + @echo "PForth can be built in several stages using these targets:" + @echo " pfdicapp = executable pForth with minimal dictionary. All from 'C'." + @echo " pfdicdat = image of full dictionary build by compiling Forth code." + @echo " pforthapp = executable with embedded dictionary image. DEFAULT 'all' target." + @echo "" + @echo " The file 'pfdicdat.h' is generated by pForth. It contains a binary image of the Forth dictionary." + @echo " It allows pForth to work as a standalone image that does not need to load a dictionary file." + +install: + install -s -m 755 pforth ${DESTDIR}/bin/pforth + install -c -o bin -g bin -m 444 pforth.dic ${DESTDIR}/bin/pforth.dic + install -c -o bin -g bin -m 444 pfdicdat.h ${DESTDIR}/bin/pfdicdat.h + +test: + wd=$$(pwd); (cd fth; $${wd}/pforth_standalone -q t_corex.fth) + wd=$$(pwd); (cd fth; $${wd}/pforth_standalone -q t_strings.fth) + wd=$$(pwd); (cd fth; $${wd}/pforth_standalone -q t_locals.fth) + wd=$$(pwd); (cd fth; $${wd}/pforth_standalone -q t_alloc.fth) + wd=$$(pwd); (cd fth; $${wd}/pforth_standalone -q t_floats.fth) + +clean: + rm -f *.o *~ pforth_standalone pfdicdat.h ../pforth.dic ../pforth diff --git a/src/cmd/pforth/fth/ansilocs.fth b/src/cmd/pforth/fth/ansilocs.fth new file mode 100644 index 0000000..7c820b7 --- /dev/null +++ b/src/cmd/pforth/fth/ansilocs.fth @@ -0,0 +1,203 @@ +\ @(#) ansilocs.fth 98/01/26 1.3 +\ local variable support words +\ These support the ANSI standard (LOCAL) and TO words. +\ +\ They are built from the following low level primitives written in 'C': +\ (local@) ( i+1 -- n , fetch from ith local variable ) +\ (local!) ( n i+1 -- , store to ith local variable ) +\ (local.entry) ( num -- , allocate stack frame for num local variables ) +\ (local.exit) ( -- , free local variable stack frame ) +\ local-compiler ( -- addr , variable containing CFA of locals compiler ) +\ +\ Author: Phil Burk +\ Copyright 1994 3DO, Phil Burk, Larry Polansky, Devid Rosenboom +\ +\ The pForth software code is dedicated to the public domain, +\ and any third party may reproduce, distribute and modify +\ the pForth software code or any derivative works thereof +\ without any compensation or license. The pForth software +\ code is provided on an "as is" basis without any warranty +\ of any kind, including, without limitation, the implied +\ warranties of merchantability and fitness for a particular +\ purpose and their equivalents under the laws of any jurisdiction. +\ +\ 10/27/99 Fixed : foo { -- } 55 ; was entering local frame but not exiting. + +anew task-ansilocs.fth + +private{ + +decimal +16 constant LV_MAX_VARS \ maximum number of local variables +31 constant LV_MAX_CHARS \ maximum number of letters in name + +lv_max_vars lv_max_chars $array LV-NAMES +variable LV-#NAMES \ number of names currently defined + +\ Search name table for match +: LV.MATCH ( $string -- index true | $string false ) + 0 swap + lv-#names @ 0 + ?DO i lv-names + over $= + IF 2drop true i LEAVE + THEN + LOOP swap +; + +: LV.COMPILE.FETCH ( index -- ) + 1+ \ adjust for optimised (local@), LocalsPtr points above vars + CASE + 1 OF compile (1_local@) ENDOF + 2 OF compile (2_local@) ENDOF + 3 OF compile (3_local@) ENDOF + 4 OF compile (4_local@) ENDOF + 5 OF compile (5_local@) ENDOF + 6 OF compile (6_local@) ENDOF + 7 OF compile (7_local@) ENDOF + 8 OF compile (8_local@) ENDOF + dup [compile] literal compile (local@) + ENDCASE +; + +: LV.COMPILE.STORE ( index -- ) + 1+ \ adjust for optimised (local!), LocalsPtr points above vars + CASE + 1 OF compile (1_local!) ENDOF + 2 OF compile (2_local!) ENDOF + 3 OF compile (3_local!) ENDOF + 4 OF compile (4_local!) ENDOF + 5 OF compile (5_local!) ENDOF + 6 OF compile (6_local!) ENDOF + 7 OF compile (7_local!) ENDOF + 8 OF compile (8_local!) ENDOF + dup [compile] literal compile (local!) + ENDCASE +; + +: LV.COMPILE.LOCAL ( $name -- handled? , check for matching locals name ) +\ ." LV.COMPILER.LOCAL name = " dup count type cr + lv.match + IF ( index ) + lv.compile.fetch + true + ELSE + drop false + THEN +; + +: LV.CLEANUP ( -- , restore stack frame on exit from colon def ) + lv-#names @ + IF + compile (local.exit) + THEN +; +: LV.FINISH ( -- , restore stack frame on exit from colon def ) + lv.cleanup + lv-#names off + local-compiler off +; + +: LV.SETUP ( -- ) + 0 lv-#names ! +; + +: LV.TERM + ." Locals turned off" cr + lv-#names off + local-compiler off +; + +if.forgotten lv.term + +}private + +: (LOCAL) ( adr len -- , ANSI local primitive ) + dup + IF + lv-#names @ lv_max_vars >= abort" Too many local variables!" + lv-#names @ lv-names place +\ Warn programmer if local variable matches an existing dictionary name. + lv-#names @ lv-names find nip + IF + ." (LOCAL) - Note: " + lv-#names @ lv-names count type + ." redefined as a local variable in " + latest id. cr + THEN + 1 lv-#names +! + ELSE +\ Last local. Finish building local stack frame. + 2drop + lv-#names @ dup 0= \ fixed 10/27/99, Thanks to John Providenza + IF + drop ." (LOCAL) - Warning: no locals defined!" cr + ELSE + [compile] literal compile (local.entry) + ['] lv.compile.local local-compiler ! + THEN + THEN +; + + +: VALUE + CREATE ( n ) + , + immediate + DOES> + state @ + IF + [compile] aliteral + compile @ + ELSE + @ + THEN +; + +: TO ( val -- ) + bl word + lv.match + IF ( -- index ) + lv.compile.store + ELSE + find + 1 = 0= abort" TO or -> before non-local or non-value" + >body \ point to data + state @ + IF \ compiling ( -- pfa ) + [compile] aliteral + compile ! + ELSE \ executing ( -- val pfa ) + ! + THEN + THEN +; immediate + +: -> ( -- ) [compile] to ; immediate + +: +-> ( val -- ) + bl word + lv.match + IF ( -- index ) + 1+ \ adjust for optimised (local!), LocalsPtr points above vars + [compile] literal compile (local+!) + ELSE + find + 1 = 0= abort" +-> before non-local or non-value" + >body \ point to data + state @ + IF \ compiling ( -- pfa ) + [compile] aliteral + compile +! + ELSE \ executing ( -- val pfa ) + +! + THEN + THEN +; immediate + +: : lv.setup : ; +: ; lv.finish [compile] ; ; immediate +: exit lv.cleanup compile exit ; immediate +: does> lv.finish [compile] does> ; immediate + +privatize diff --git a/src/cmd/pforth/fth/bench.fth b/src/cmd/pforth/fth/bench.fth new file mode 100644 index 0000000..a5ca9c0 --- /dev/null +++ b/src/cmd/pforth/fth/bench.fth @@ -0,0 +1,198 @@ +\ @(#) bench.fth 97/12/10 1.1 +\ Benchmark Forth +\ by Phil Burk +\ 11/17/95 +\ +\ pForthV9 on Indy, compiled with gcc +\ bench1 took 15 seconds +\ bench2 took 16 seconds +\ bench3 took 17 seconds +\ bench4 took 17 seconds +\ bench5 took 19 seconds +\ sieve took 4 seconds +\ +\ Darren Gibbs reports that on an SGI Octane loaded with multiple users: +\ bench1 took 2.8sec +\ bench2 took 2.7 +\ bench3 took 2.9 +\ bench4 took 2.1 +\ bench 5 took 2.5 +\ seive took .6 +\ +\ HForth on Mac Quadra 800, 68040 +\ bench1 took 1.73 seconds +\ bench2 took 6.48 seconds +\ bench3 took 2.65 seconds +\ bench4 took 2.50 seconds +\ bench5 took 1.91 seconds +\ sieve took 0.45 seconds +\ +\ pForthV9 on Mac Quadra 800 +\ bench1 took 40 seconds +\ bench2 took 43 seconds +\ bench3 took 43 seconds +\ bench4 took 44 seconds +\ bench5 took 42 seconds +\ sieve took 20 seconds +\ +\ pForthV9 on PB5300, 100 MHz PPC 603 based Mac Powerbook +\ bench1 took 8.6 seconds +\ bench2 took 9.0 seconds +\ bench3 took 9.7 seconds +\ bench4 took 8.8 seconds +\ bench5 took 10.3 seconds +\ sieve took 2.3 seconds +\ +\ HForth on PB5300 +\ bench1 took 1.1 seconds +\ bench2 took 3.6 seconds +\ bench3 took 1.7 seconds +\ bench4 took 1.2 seconds +\ bench5 took 1.3 seconds +\ sieve took 0.2 seconds + +anew task-bench.fth + +decimal + +\ benchmark primitives +create #do 2000000 , + +: t1 #do @ 0 do loop ; +: t2 23 45 #do @ 0 do swap loop 2drop ; +: t3 23 #do @ 0 do dup drop loop drop ; +: t4 23 45 #do @ 0 do over drop loop 2drop ; +: t5 #do @ 0 do 23 45 + drop loop ; +: t6 23 #do @ 0 do >r r> loop drop ; +: t7 23 45 67 #do @ 0 do rot loop 2drop drop ; +: t8 #do @ 0 do 23 2* drop loop ; +: t9 #do @ 10 / 0 do 23 5 /mod 2drop loop ; +: t10 #do #do @ 0 do dup @ drop loop drop ; + +: foo ( noop ) ; +: t11 #do @ 0 do foo loop ; + +\ more complex benchmarks ----------------------- + +\ BENCH1 - sum data --------------------------------------- +create data1 23 , 45 , 67 , 89 , 111 , 222 , 333 , 444 , +: sum.cells ( addr num -- sum ) + 0 swap \ sum + 0 DO + over \ get address + i cells + @ + + LOOP + swap drop +; + +: bench1 ( -- ) + 200000 0 + DO + data1 8 sum.cells drop + LOOP +; + +\ BENCH2 - recursive factorial -------------------------- +: factorial ( n -- n! ) + dup 1 > + IF + dup 1- recurse * + ELSE + drop 1 + THEN +; + +: bench2 ( -- ) + 200000 0 + DO + 10 factorial drop + LOOP +; + +\ BENCH3 - DEFER ---------------------------------- +defer calc.answer +: answer ( n -- m ) + dup + + $ a5a5 xor + 1000 max +; +' answer is calc.answer +: bench3 + 1500000 0 + DO + i calc.answer drop + LOOP +; + +\ BENCH4 - locals --------------------------------- +: use.locals { x1 x2 | aa bb -- result } + x1 2* -> aa + x2 2/ -> bb + x1 aa * + x2 bb * + +; + +: bench4 + 400000 0 + DO + 234 567 use.locals drop + LOOP +; + +\ BENCH5 - string compare ------------------------------- +: match.strings { $s1 $s2 | adr1 len1 adr2 len2 -- flag } + $s1 count -> len1 -> adr1 + $s2 count -> len2 -> adr2 + len1 len2 - + IF + FALSE + ELSE + TRUE + len1 0 + DO + adr1 i + c@ + adr2 i + c@ - + IF + drop FALSE + leave + THEN + LOOP + THEN +; + +: bench5 ( -- ) + 60000 0 + DO + " This is a string. X foo" + " This is a string. Y foo" match.strings drop + LOOP +; + +\ SIEVE OF ERATOSTHENES from BYTE magazine ----------------------- + +DECIMAL 8190 CONSTANT TSIZE + +VARIABLE FLAGS TSIZE ALLOT + +: ( --- #primes ) FLAGS TSIZE 1 FILL + 0 TSIZE 0 + DO ( n ) I FLAGS + C@ + IF I DUP + 3 + DUP I + ( I2*+3 I3*+3 ) + BEGIN DUP TSIZE < ( same flag ) + WHILE 0 OVER FLAGS + C! ( i' i'' ) OVER + + REPEAT 2DROP 1+ + THEN + LOOP ; + +: SIEVE ." 10 iterations " CR 0 10 0 + DO swap drop + LOOP . ." primes " CR ; + +: SIEVE50 ." 50 iterations " CR 0 50 0 + DO swap drop + LOOP . ." primes " CR ; + +\ 10 iterations +\ 21.5 sec Amiga Multi-Forth Indirect Threaded +\ 8.82 sec Amiga 1000 running JForth +\ ~5 sec SGI Indy running pForthV9 diff --git a/src/cmd/pforth/fth/c_struct.fth b/src/cmd/pforth/fth/c_struct.fth new file mode 100644 index 0000000..86062d7 --- /dev/null +++ b/src/cmd/pforth/fth/c_struct.fth @@ -0,0 +1,242 @@ +\ @(#) c_struct.fth 98/01/26 1.2 +\ STRUCTUREs are for interfacing with 'C' programs. +\ Structures are created using :STRUCT and ;STRUCT +\ +\ This file must be loaded before loading any .J files. +\ +\ Author: Phil Burk +\ Copyright 1994 3DO, Phil Burk, Larry Polansky, Devid Rosenboom +\ +\ The pForth software code is dedicated to the public domain, +\ and any third party may reproduce, distribute and modify +\ the pForth software code or any derivative works thereof +\ without any compensation or license. The pForth software +\ code is provided on an "as is" basis without any warranty +\ of any kind, including, without limitation, the implied +\ warranties of merchantability and fitness for a particular +\ purpose and their equivalents under the laws of any jurisdiction. +\ +\ MOD: PLB 1/16/87 Use abort" instead of er.report +\ MDH 4/14/87 Added sign-extend words to ..@ +\ MOD: PLB 9/1/87 Add pointer to last member for debug. +\ MOD: MDH 4/30/88 Use fast addressing for ..@ and ..! +\ MOD: PLB/MDH 9/30/88 Fixed offsets for 16@+long and 8@+long +\ fixed OB.COMPILE.+@/! for 0 offset +\ MOD: PLB 1/11/89 Added EVEN-UP in case of last member BYTE +\ MOD: RDG 9/19/90 Added floating point member support +\ MOD: PLB 12/21/90 Optimized ..@ and ..! +\ 00001 PLB 11/20/91 Make structures IMMEDIATE with ALITERAL for speed +\ Don't need MOVEQ.L #0,D0 for 16@+WORD and 8@+WORD +\ 00002 PLB 8/3/92 Added S@ and S!, and support for RPTR +\ 951112 PLB Added FS@ and FS! +\ This version for the pForth system. + +ANEW TASK-C_STRUCT + +decimal +\ STRUCT ====================================================== +: <:STRUCT> ( pfa -- , run time action for a structure) + [COMPILE] CREATE + @ even-up here swap dup ( -- here # # ) + allot ( make room for ivars ) + 0 fill ( initialize to zero ) +\ immediate \ 00001 +\ DOES> [compile] aliteral \ 00001 +; + +\ Contents of a structure definition. +\ CELL 0 = size of instantiated structures +\ CELL 1 = #bytes to last member name in dictionary. +\ this is relative so it will work with structure +\ relocation schemes like MODULE + +: :STRUCT ( -- , Create a 'C' structure ) +\ Check pairs + ob-state @ + warning" :STRUCT - Previous :STRUCT or :CLASS unfinished!" + ob_def_struct ob-state ! ( set pair flags ) +\ +\ Create new struct defining word. + CREATE + here ob-current-class ! ( set current ) + 0 , ( initial ivar offset ) + 0 , ( location for #byte to last ) + DOES> <:STRUCT> +; + +: ;STRUCT ( -- , terminate structure ) + ob-state @ ob_def_struct = NOT + abort" ;STRUCT - Missing :STRUCT above!" + false ob-state ! + +\ Point to last member. + latest ob-current-class @ body> >name - ( byte difference of NFAs ) + ob-current-class @ cell+ ! +\ +\ Even up byte offset in case last member was BYTE. + ob-current-class @ dup @ even-up swap ! +; + +\ Member reference words. +: .. ( object -- member_address , calc addr of member ) + ob.stats? drop state @ + IF ?dup + IF [compile] literal compile + + THEN + ELSE + + THEN +; immediate + + +: (S+C!) ( val addr offset -- ) + c! ; +: (S+W!) ( val addr offset -- ) + w! ; +: (S+!) ( val addr offset -- ) + ! ; +: (S+REL!) ( ptr addr offset -- ) + >r if.use->rel r> ! ; + +: compile+!bytes ( offset size -- ) +\ ." compile+!bytes ( " over . dup . ." )" cr + swap [compile] literal \ compile offset into word + CASE + cell OF compile (s+!) ENDOF + 2 OF compile (s+w!) ENDOF + 1 OF compile (s+c!) ENDOF + -4 OF compile (s+rel!) ENDOF \ 00002 + -2 OF compile (s+w!) ENDOF + -1 OF compile (s+c!) ENDOF + true abort" s! - illegal size!" + ENDCASE +; + +: !BYTES ( value address size -- ) + CASE + cell OF ! ENDOF + -4 OF ( aptr addr ) swap if.use->rel swap ! ENDOF \ 00002 + ABS + 2 OF w! ENDOF + 1 OF c! ENDOF + true abort" s! - illegal size!" + ENDCASE +; + +\ These provide ways of setting and reading members values +\ without knowing their size in bytes. +: (S!) ( offset size -- , compile proper fetch ) + state @ + IF compile+!bytes + ELSE ( -- value addr off size ) + >r + r> !bytes + THEN +; +: S! ( value object -- , store value in member ) + ob.stats? + (s!) +; immediate + +: @BYTES ( addr +/-size -- value ) + CASE + cell OF @ ENDOF + 2 OF w@ ENDOF + 1 OF c@ ENDOF + -4 OF @ if.rel->use ENDOF \ 00002 + -2 OF w@ w->s ENDOF + -1 OF c@ b->s ENDOF + true abort" s@ - illegal size!" + ENDCASE +; + +: (S+UC@) ( addr offset -- val ) + c@ ; +: (S+UW@) ( addr offset -- val ) + w@ ; +: (S+@) ( addr offset -- val ) + @ ; +: (S+REL@) ( addr offset -- val ) + @ if.rel->use ; +: (S+C@) ( addr offset -- val ) + c@ b->s ; +: (S+W@) ( addr offset -- val ) + w@ w->s ; + +: compile+@bytes ( offset size -- ) +\ ." compile+@bytes ( " over . dup . ." )" cr + swap [compile] literal \ compile offset into word + CASE + cell OF compile (s+@) ENDOF + 2 OF compile (s+uw@) ENDOF + 1 OF compile (s+uc@) ENDOF + -4 OF compile (s+rel@) ENDOF \ 00002 + -2 OF compile (s+w@) ENDOF + -1 OF compile (s+c@) ENDOF + true abort" s@ - illegal size!" + ENDCASE +; + +: (S@) ( offset size -- , compile proper fetch ) + state @ + IF compile+@bytes + ELSE >r + r> @bytes + THEN +; + +: S@ ( object -- value , fetch value from member ) + ob.stats? + (s@) +; immediate + + + +exists? F* [IF] +\ 951112 Floating Point support +: FLPT ( -- , declare space for a floating point value. ) + 1 floats bytes +; +: (S+F!) ( val addr offset -- ) + f! ; +: (S+F@) ( addr offset -- val ) + f@ ; + +: FS! ( value object -- , fetch value from member ) + ob.stats? + 1 floats <> abort" FS@ with non-float!" + state @ + IF + [compile] literal + compile (s+f!) + ELSE (s+f!) + THEN +; immediate +: FS@ ( object -- value , fetch value from member ) + ob.stats? + 1 floats <> abort" FS@ with non-float!" + state @ + IF + [compile] literal + compile (s+f@) + ELSE (s+f@) + THEN +; immediate +[THEN] + +0 [IF] +:struct mapper + long map_l1 + long map_l2 + aptr map_a1 + rptr map_r1 + flpt map_f1 + short map_s1 + ushort map_s2 + byte map_b1 + ubyte map_b2 +;struct +mapper map1 + +: TT + -500 map1 s! map_s1 + map1 s@ map_s1 -500 - abort" map_s1 failed!" + -500 map1 s! map_s2 + map1 s@ map_s2 -500 $ FFFF and - abort" map_s2 failed!" + -89 map1 s! map_b1 + map1 s@ map_b1 -89 - abort" map_s1 failed!" + here map1 s! map_r1 + map1 s@ map_r1 here - abort" map_r1 failed!" + -89 map1 s! map_b2 + map1 s@ map_b2 -89 $ FF and - abort" map_s2 failed!" + 23.45 map1 fs! map_f1 + map1 fs@ map_f1 f. ." =?= 23.45" cr +; +." Testing c_struct.fth" cr +TT +[THEN] diff --git a/src/cmd/pforth/fth/case.fth b/src/cmd/pforth/fth/case.fth new file mode 100644 index 0000000..6ae79a6 --- /dev/null +++ b/src/cmd/pforth/fth/case.fth @@ -0,0 +1,78 @@ +\ @(#) case.fth 98/01/26 1.2 +\ CASE Statement +\ +\ This definition is based upon Wil Baden's assertion that +\ >MARK >RESOLVE ?BRANCH etc. are not needed if one has IF ELSE THEN etc. +\ +\ Author: Phil Burk +\ Copyright 1994 3DO, Phil Burk, Larry Polansky, Devid Rosenboom +\ +\ The pForth software code is dedicated to the public domain, +\ and any third party may reproduce, distribute and modify +\ the pForth software code or any derivative works thereof +\ without any compensation or license. The pForth software +\ code is provided on an "as is" basis without any warranty +\ of any kind, including, without limitation, the implied +\ warranties of merchantability and fitness for a particular +\ purpose and their equivalents under the laws of any jurisdiction. +\ +\ MOD: PLB 6/24/91 Check for missing ENDOF +\ MOD: PLB 8/7/91 Add ?OF and RANGEOF +\ MOD: PLB 11/2/99 Fixed nesting of CASE. Needed to save of-depth on stack as well as case-depth. + +anew TASK-CASE + +variable CASE-DEPTH +variable OF-DEPTH + +: CASE ( n -- , start case statement ) ( -c- case-depth ) + ?comp + of-depth @ 0 of-depth ! \ 11/2/99 + case-depth @ 0 case-depth ! ( allow nesting ) +; IMMEDIATE + +: ?OF ( n flag -- | n , doit if true ) ( -c- addr ) + [compile] IF + compile drop + 1 case-depth +! + 1 of-depth +! +; IMMEDIATE + +: OF ( n t -- | n , doit if match ) ( -c- addr ) + ?comp + compile over compile = + [compile] ?OF +; IMMEDIATE + +: (RANGEOF?) ( n lo hi -- | n flag ) + >r over ( n lo n ) <= + IF + dup r> ( n n hi ) <= + ELSE + rdrop false + THEN +; + +: RANGEOF ( n lo hi -- | n , doit if within ) ( -c- addr ) + compile (rangeof?) + [compile] ?OF +; IMMEDIATE + +: ENDOF ( -- ) ( addr -c- addr' ) + [compile] ELSE + -1 of-depth +! +; IMMEDIATE + +: ENDCASE ( n -- ) ( old-case-depth addr' addr' ??? -- ) + of-depth @ + IF >newline ." Missing ENDOF in CASE!" cr abort + THEN +\ + compile drop + case-depth @ 0 + ?DO [compile] THEN + LOOP + case-depth ! + of-depth ! +; IMMEDIATE + diff --git a/src/cmd/pforth/fth/condcomp.fth b/src/cmd/pforth/fth/condcomp.fth new file mode 100644 index 0000000..b95b005 --- /dev/null +++ b/src/cmd/pforth/fth/condcomp.fth @@ -0,0 +1,50 @@ +\ @(#) condcomp.fth 98/01/26 1.2 +\ Conditional Compilation support +\ +\ Words: STRINGS= [IF] [ELSE] [THEN] EXISTS? +\ +\ Lifted from X3J14 dpANS-6 document. + +anew task-condcomp.fth + +: [ELSE] ( -- ) + 1 + BEGIN \ level + BEGIN + BL WORD \ level $word + COUNT DUP \ level adr len len + WHILE \ level adr len + 2DUP S" [IF]" COMPARE 0= + IF \ level adr len + 2DROP 1+ \ level' + ELSE \ level adr len + 2DUP S" [ELSE]" + COMPARE 0= \ level adr len flag + IF \ level adr len + 2DROP 1- DUP IF 1+ THEN \ level' + ELSE \ level adr len + S" [THEN]" COMPARE 0= + IF + 1- \ level' + THEN + THEN + THEN + ?DUP 0= IF EXIT THEN \ level' + REPEAT 2DROP \ level + REFILL 0= UNTIL \ level + DROP +; IMMEDIATE + +: [IF] ( flag -- ) + 0= + IF POSTPONE [ELSE] + THEN +; IMMEDIATE + +: [THEN] ( -- ) +; IMMEDIATE + +: EXISTS? ( -- flag , true if defined ) + bl word find + swap drop +; immediate diff --git a/src/cmd/pforth/fth/coretest.fth b/src/cmd/pforth/fth/coretest.fth new file mode 100644 index 0000000..ec289f4 --- /dev/null +++ b/src/cmd/pforth/fth/coretest.fth @@ -0,0 +1,999 @@ +\ From: John Hayes S1I +\ Subject: core.fr +\ Date: Mon, 27 Nov 95 13:10 + +\ (C) 1995 JOHNS HOPKINS UNIVERSITY / APPLIED PHYSICS LABORATORY +\ MAY BE DISTRIBUTED FREELY AS LONG AS THIS COPYRIGHT NOTICE REMAINS. +\ VERSION 1.2 +\ THIS PROGRAM TESTS THE CORE WORDS OF AN ANS FORTH SYSTEM. +\ THE PROGRAM ASSUMES A TWO'S COMPLEMENT IMPLEMENTATION WHERE +\ THE RANGE OF SIGNED NUMBERS IS -2^(N-1) ... 2^(N-1)-1 AND +\ THE RANGE OF UNSIGNED NUMBERS IS 0 ... 2^(N)-1. +\ I HAVEN'T FIGURED OUT HOW TO TEST KEY, QUIT, ABORT, OR ABORT"... +\ I ALSO HAVEN'T THOUGHT OF A WAY TO TEST ENVIRONMENT?... + +\ Load test tools - Phil Burk +include? testing tester.fth + +TESTING CORE WORDS +HEX + +\ ------------------------------------------------------------------------ +TESTING BASIC ASSUMPTIONS + +{ -> } \ START WITH CLEAN SLATE +( TEST IF ANY BITS ARE SET; ANSWER IN BASE 1 ) +{ : BITSSET? IF 0 0 ELSE 0 THEN ; -> } +{ 0 BITSSET? -> 0 } ( ZERO IS ALL BITS CLEAR ) +{ 1 BITSSET? -> 0 0 } ( OTHER NUMBER HAVE AT LEAST ONE BIT ) +{ -1 BITSSET? -> 0 0 } + +\ ------------------------------------------------------------------------ +TESTING BOOLEANS: INVERT AND OR XOR + +{ 0 0 AND -> 0 } +{ 0 1 AND -> 0 } +{ 1 0 AND -> 0 } +{ 1 1 AND -> 1 } + +{ 0 INVERT 1 AND -> 1 } +{ 1 INVERT 1 AND -> 0 } + +0 CONSTANT 0S +0 INVERT CONSTANT 1S + +{ 0S INVERT -> 1S } +{ 1S INVERT -> 0S } + +{ 0S 0S AND -> 0S } +{ 0S 1S AND -> 0S } +{ 1S 0S AND -> 0S } +{ 1S 1S AND -> 1S } + +{ 0S 0S OR -> 0S } +{ 0S 1S OR -> 1S } +{ 1S 0S OR -> 1S } +{ 1S 1S OR -> 1S } + +{ 0S 0S XOR -> 0S } +{ 0S 1S XOR -> 1S } +{ 1S 0S XOR -> 1S } +{ 1S 1S XOR -> 0S } + +\ ------------------------------------------------------------------------ +TESTING 2* 2/ LSHIFT RSHIFT + +( WE TRUST 1S, INVERT, AND BITSSET?; WE WILL CONFIRM RSHIFT LATER ) +1S 1 RSHIFT INVERT CONSTANT MSB +{ MSB BITSSET? -> 0 0 } + +{ 0S 2* -> 0S } +{ 1 2* -> 2 } +{ 4000 2* -> 8000 } +{ 1S 2* 1 XOR -> 1S } +{ MSB 2* -> 0S } + +{ 0S 2/ -> 0S } +{ 1 2/ -> 0 } +{ 4000 2/ -> 2000 } +{ 1S 2/ -> 1S } \ MSB PROPOGATED +{ 1S 1 XOR 2/ -> 1S } +{ MSB 2/ MSB AND -> MSB } + +{ 1 0 LSHIFT -> 1 } +{ 1 1 LSHIFT -> 2 } +{ 1 2 LSHIFT -> 4 } +{ 1 F LSHIFT -> 8000 } \ BIGGEST GUARANTEED SHIFT +{ 1S 1 LSHIFT 1 XOR -> 1S } +{ MSB 1 LSHIFT -> 0 } + +{ 1 0 RSHIFT -> 1 } +{ 1 1 RSHIFT -> 0 } +{ 2 1 RSHIFT -> 1 } +{ 4 2 RSHIFT -> 1 } +{ 8000 F RSHIFT -> 1 } \ BIGGEST +{ MSB 1 RSHIFT MSB AND -> 0 } \ RSHIFT ZERO FILLS MSBS +{ MSB 1 RSHIFT 2* -> MSB } + +\ ------------------------------------------------------------------------ +TESTING COMPARISONS: 0= = 0< < > U< MIN MAX +0 INVERT CONSTANT MAX-UINT +0 INVERT 1 RSHIFT CONSTANT MAX-INT +0 INVERT 1 RSHIFT INVERT CONSTANT MIN-INT +0 INVERT 1 RSHIFT CONSTANT MID-UINT +0 INVERT 1 RSHIFT INVERT CONSTANT MID-UINT+1 + +0S CONSTANT +1S CONSTANT + +{ 0 0= -> } +{ 1 0= -> } +{ 2 0= -> } +{ -1 0= -> } +{ MAX-UINT 0= -> } +{ MIN-INT 0= -> } +{ MAX-INT 0= -> } + +{ 0 0 = -> } +{ 1 1 = -> } +{ -1 -1 = -> } +{ 1 0 = -> } +{ -1 0 = -> } +{ 0 1 = -> } +{ 0 -1 = -> } + +{ 0 0< -> } +{ -1 0< -> } +{ MIN-INT 0< -> } +{ 1 0< -> } +{ MAX-INT 0< -> } + +{ 0 1 < -> } +{ 1 2 < -> } +{ -1 0 < -> } +{ -1 1 < -> } +{ MIN-INT 0 < -> } +{ MIN-INT MAX-INT < -> } +{ 0 MAX-INT < -> } +{ 0 0 < -> } +{ 1 1 < -> } +{ 1 0 < -> } +{ 2 1 < -> } +{ 0 -1 < -> } +{ 1 -1 < -> } +{ 0 MIN-INT < -> } +{ MAX-INT MIN-INT < -> } +{ MAX-INT 0 < -> } + +{ 0 1 > -> } +{ 1 2 > -> } +{ -1 0 > -> } +{ -1 1 > -> } +{ MIN-INT 0 > -> } +{ MIN-INT MAX-INT > -> } +{ 0 MAX-INT > -> } +{ 0 0 > -> } +{ 1 1 > -> } +{ 1 0 > -> } +{ 2 1 > -> } +{ 0 -1 > -> } +{ 1 -1 > -> } +{ 0 MIN-INT > -> } +{ MAX-INT MIN-INT > -> } +{ MAX-INT 0 > -> } + +{ 0 1 U< -> } +{ 1 2 U< -> } +{ 0 MID-UINT U< -> } +{ 0 MAX-UINT U< -> } +{ MID-UINT MAX-UINT U< -> } +{ 0 0 U< -> } +{ 1 1 U< -> } +{ 1 0 U< -> } +{ 2 1 U< -> } +{ MID-UINT 0 U< -> } +{ MAX-UINT 0 U< -> } +{ MAX-UINT MID-UINT U< -> } + +{ 0 1 MIN -> 0 } +{ 1 2 MIN -> 1 } +{ -1 0 MIN -> -1 } +{ -1 1 MIN -> -1 } +{ MIN-INT 0 MIN -> MIN-INT } +{ MIN-INT MAX-INT MIN -> MIN-INT } +{ 0 MAX-INT MIN -> 0 } +{ 0 0 MIN -> 0 } +{ 1 1 MIN -> 1 } +{ 1 0 MIN -> 0 } +{ 2 1 MIN -> 1 } +{ 0 -1 MIN -> -1 } +{ 1 -1 MIN -> -1 } +{ 0 MIN-INT MIN -> MIN-INT } +{ MAX-INT MIN-INT MIN -> MIN-INT } +{ MAX-INT 0 MIN -> 0 } + +{ 0 1 MAX -> 1 } +{ 1 2 MAX -> 2 } +{ -1 0 MAX -> 0 } +{ -1 1 MAX -> 1 } +{ MIN-INT 0 MAX -> 0 } +{ MIN-INT MAX-INT MAX -> MAX-INT } +{ 0 MAX-INT MAX -> MAX-INT } +{ 0 0 MAX -> 0 } +{ 1 1 MAX -> 1 } +{ 1 0 MAX -> 1 } +{ 2 1 MAX -> 2 } +{ 0 -1 MAX -> 0 } +{ 1 -1 MAX -> 1 } +{ 0 MIN-INT MAX -> 0 } +{ MAX-INT MIN-INT MAX -> MAX-INT } +{ MAX-INT 0 MAX -> MAX-INT } + +\ ------------------------------------------------------------------------ +TESTING STACK OPS: 2DROP 2DUP 2OVER 2SWAP ?DUP DEPTH DROP DUP OVER ROT SWAP + +{ 1 2 2DROP -> } +{ 1 2 2DUP -> 1 2 1 2 } +{ 1 2 3 4 2OVER -> 1 2 3 4 1 2 } +{ 1 2 3 4 2SWAP -> 3 4 1 2 } +{ 0 ?DUP -> 0 } +{ 1 ?DUP -> 1 1 } +{ -1 ?DUP -> -1 -1 } +{ DEPTH -> 0 } +{ 0 DEPTH -> 0 1 } +{ 0 1 DEPTH -> 0 1 2 } +{ 0 DROP -> } +{ 1 2 DROP -> 1 } +{ 1 DUP -> 1 1 } +{ 1 2 OVER -> 1 2 1 } +{ 1 2 3 ROT -> 2 3 1 } +{ 1 2 SWAP -> 2 1 } + +\ ------------------------------------------------------------------------ +TESTING >R R> R@ + +{ : GR1 >R R> ; -> } +{ : GR2 >R R@ R> DROP ; -> } +{ 123 GR1 -> 123 } +{ 123 GR2 -> 123 } +{ 1S GR1 -> 1S } ( RETURN STACK HOLDS CELLS ) + +\ ------------------------------------------------------------------------ +TESTING ADD/SUBTRACT: + - 1+ 1- ABS NEGATE + +{ 0 5 + -> 5 } +{ 5 0 + -> 5 } +{ 0 -5 + -> -5 } +{ -5 0 + -> -5 } +{ 1 2 + -> 3 } +{ 1 -2 + -> -1 } +{ -1 2 + -> 1 } +{ -1 -2 + -> -3 } +{ -1 1 + -> 0 } +{ MID-UINT 1 + -> MID-UINT+1 } + +{ 0 5 - -> -5 } +{ 5 0 - -> 5 } +{ 0 -5 - -> 5 } +{ -5 0 - -> -5 } +{ 1 2 - -> -1 } +{ 1 -2 - -> 3 } +{ -1 2 - -> -3 } +{ -1 -2 - -> 1 } +{ 0 1 - -> -1 } +{ MID-UINT+1 1 - -> MID-UINT } + +{ 0 1+ -> 1 } +{ -1 1+ -> 0 } +{ 1 1+ -> 2 } +{ MID-UINT 1+ -> MID-UINT+1 } + +{ 2 1- -> 1 } +{ 1 1- -> 0 } +{ 0 1- -> -1 } +{ MID-UINT+1 1- -> MID-UINT } + +{ 0 NEGATE -> 0 } +{ 1 NEGATE -> -1 } +{ -1 NEGATE -> 1 } +{ 2 NEGATE -> -2 } +{ -2 NEGATE -> 2 } + +{ 0 ABS -> 0 } +{ 1 ABS -> 1 } +{ -1 ABS -> 1 } +{ MIN-INT ABS -> MID-UINT+1 } + +\ ------------------------------------------------------------------------ +TESTING MULTIPLY: S>D * M* UM* + +{ 0 S>D -> 0 0 } +{ 1 S>D -> 1 0 } +{ 2 S>D -> 2 0 } +{ -1 S>D -> -1 -1 } +{ -2 S>D -> -2 -1 } +{ MIN-INT S>D -> MIN-INT -1 } +{ MAX-INT S>D -> MAX-INT 0 } + +{ 0 0 M* -> 0 S>D } +{ 0 1 M* -> 0 S>D } +{ 1 0 M* -> 0 S>D } +{ 1 2 M* -> 2 S>D } +{ 2 1 M* -> 2 S>D } +{ 3 3 M* -> 9 S>D } +{ -3 3 M* -> -9 S>D } +{ 3 -3 M* -> -9 S>D } +{ -3 -3 M* -> 9 S>D } +{ 0 MIN-INT M* -> 0 S>D } +{ 1 MIN-INT M* -> MIN-INT S>D } +{ 2 MIN-INT M* -> 0 1S } +{ 0 MAX-INT M* -> 0 S>D } +{ 1 MAX-INT M* -> MAX-INT S>D } +{ 2 MAX-INT M* -> MAX-INT 1 LSHIFT 0 } +{ MIN-INT MIN-INT M* -> 0 MSB 1 RSHIFT } +{ MAX-INT MIN-INT M* -> MSB MSB 2/ } +{ MAX-INT MAX-INT M* -> 1 MSB 2/ INVERT } + +{ 0 0 * -> 0 } \ TEST IDENTITIES +{ 0 1 * -> 0 } +{ 1 0 * -> 0 } +{ 1 2 * -> 2 } +{ 2 1 * -> 2 } +{ 3 3 * -> 9 } +{ -3 3 * -> -9 } +{ 3 -3 * -> -9 } +{ -3 -3 * -> 9 } + +{ MID-UINT+1 1 RSHIFT 2 * -> MID-UINT+1 } +{ MID-UINT+1 2 RSHIFT 4 * -> MID-UINT+1 } +{ MID-UINT+1 1 RSHIFT MID-UINT+1 OR 2 * -> MID-UINT+1 } + +{ 0 0 UM* -> 0 0 } +{ 0 1 UM* -> 0 0 } +{ 1 0 UM* -> 0 0 } +{ 1 2 UM* -> 2 0 } +{ 2 1 UM* -> 2 0 } +{ 3 3 UM* -> 9 0 } + +{ MID-UINT+1 1 RSHIFT 2 UM* -> MID-UINT+1 0 } +{ MID-UINT+1 2 UM* -> 0 1 } +{ MID-UINT+1 4 UM* -> 0 2 } +{ 1S 2 UM* -> 1S 1 LSHIFT 1 } +{ MAX-UINT MAX-UINT UM* -> 1 1 INVERT } + +\ ------------------------------------------------------------------------ +TESTING DIVIDE: FM/MOD SM/REM UM/MOD */ */MOD / /MOD MOD + +{ 0 S>D 1 FM/MOD -> 0 0 } +{ 1 S>D 1 FM/MOD -> 0 1 } +{ 2 S>D 1 FM/MOD -> 0 2 } +{ -1 S>D 1 FM/MOD -> 0 -1 } +{ -2 S>D 1 FM/MOD -> 0 -2 } +{ 0 S>D -1 FM/MOD -> 0 0 } +{ 1 S>D -1 FM/MOD -> 0 -1 } +{ 2 S>D -1 FM/MOD -> 0 -2 } +{ -1 S>D -1 FM/MOD -> 0 1 } +{ -2 S>D -1 FM/MOD -> 0 2 } +{ 2 S>D 2 FM/MOD -> 0 1 } +{ -1 S>D -1 FM/MOD -> 0 1 } +{ -2 S>D -2 FM/MOD -> 0 1 } +{ 7 S>D 3 FM/MOD -> 1 2 } +{ 7 S>D -3 FM/MOD -> -2 -3 } +{ -7 S>D 3 FM/MOD -> 2 -3 } +{ -7 S>D -3 FM/MOD -> -1 2 } +{ MAX-INT S>D 1 FM/MOD -> 0 MAX-INT } +{ MIN-INT S>D 1 FM/MOD -> 0 MIN-INT } +{ MAX-INT S>D MAX-INT FM/MOD -> 0 1 } +{ MIN-INT S>D MIN-INT FM/MOD -> 0 1 } +{ 1S 1 4 FM/MOD -> 3 MAX-INT } +{ 1 MIN-INT M* 1 FM/MOD -> 0 MIN-INT } +{ 1 MIN-INT M* MIN-INT FM/MOD -> 0 1 } +{ 2 MIN-INT M* 2 FM/MOD -> 0 MIN-INT } +{ 2 MIN-INT M* MIN-INT FM/MOD -> 0 2 } +{ 1 MAX-INT M* 1 FM/MOD -> 0 MAX-INT } +{ 1 MAX-INT M* MAX-INT FM/MOD -> 0 1 } +{ 2 MAX-INT M* 2 FM/MOD -> 0 MAX-INT } +{ 2 MAX-INT M* MAX-INT FM/MOD -> 0 2 } +{ MIN-INT MIN-INT M* MIN-INT FM/MOD -> 0 MIN-INT } +{ MIN-INT MAX-INT M* MIN-INT FM/MOD -> 0 MAX-INT } +{ MIN-INT MAX-INT M* MAX-INT FM/MOD -> 0 MIN-INT } +{ MAX-INT MAX-INT M* MAX-INT FM/MOD -> 0 MAX-INT } + +{ 0 S>D 1 SM/REM -> 0 0 } +{ 1 S>D 1 SM/REM -> 0 1 } +{ 2 S>D 1 SM/REM -> 0 2 } +{ -1 S>D 1 SM/REM -> 0 -1 } +{ -2 S>D 1 SM/REM -> 0 -2 } +{ 0 S>D -1 SM/REM -> 0 0 } +{ 1 S>D -1 SM/REM -> 0 -1 } +{ 2 S>D -1 SM/REM -> 0 -2 } +{ -1 S>D -1 SM/REM -> 0 1 } +{ -2 S>D -1 SM/REM -> 0 2 } +{ 2 S>D 2 SM/REM -> 0 1 } +{ -1 S>D -1 SM/REM -> 0 1 } +{ -2 S>D -2 SM/REM -> 0 1 } +{ 7 S>D 3 SM/REM -> 1 2 } +{ 7 S>D -3 SM/REM -> 1 -2 } +{ -7 S>D 3 SM/REM -> -1 -2 } +{ -7 S>D -3 SM/REM -> -1 2 } +{ MAX-INT S>D 1 SM/REM -> 0 MAX-INT } +{ MIN-INT S>D 1 SM/REM -> 0 MIN-INT } +{ MAX-INT S>D MAX-INT SM/REM -> 0 1 } +{ MIN-INT S>D MIN-INT SM/REM -> 0 1 } +{ 1S 1 4 SM/REM -> 3 MAX-INT } +{ 2 MIN-INT M* 2 SM/REM -> 0 MIN-INT } +{ 2 MIN-INT M* MIN-INT SM/REM -> 0 2 } +{ 2 MAX-INT M* 2 SM/REM -> 0 MAX-INT } +{ 2 MAX-INT M* MAX-INT SM/REM -> 0 2 } +{ MIN-INT MIN-INT M* MIN-INT SM/REM -> 0 MIN-INT } +{ MIN-INT MAX-INT M* MIN-INT SM/REM -> 0 MAX-INT } +{ MIN-INT MAX-INT M* MAX-INT SM/REM -> 0 MIN-INT } +{ MAX-INT MAX-INT M* MAX-INT SM/REM -> 0 MAX-INT } + +{ 0 0 1 UM/MOD -> 0 0 } +{ 1 0 1 UM/MOD -> 0 1 } +{ 1 0 2 UM/MOD -> 1 0 } +{ 3 0 2 UM/MOD -> 1 1 } +{ MAX-UINT 2 UM* 2 UM/MOD -> 0 MAX-UINT } +{ MAX-UINT 2 UM* MAX-UINT UM/MOD -> 0 2 } +{ MAX-UINT MAX-UINT UM* MAX-UINT UM/MOD -> 0 MAX-UINT } + +: IFFLOORED + [ -3 2 / -2 = INVERT ] LITERAL IF POSTPONE \ THEN ; +: IFSYM + [ -3 2 / -1 = INVERT ] LITERAL IF POSTPONE \ THEN ; + +\ THE SYSTEM MIGHT DO EITHER FLOORED OR SYMMETRIC DIVISION. +\ SINCE WE HAVE ALREADY TESTED M*, FM/MOD, AND SM/REM WE CAN USE THEM IN TEST. +IFFLOORED : T/MOD >R S>D R> FM/MOD ; +IFFLOORED : T/ T/MOD SWAP DROP ; +IFFLOORED : TMOD T/MOD DROP ; +IFFLOORED : T*/MOD >R M* R> FM/MOD ; +IFFLOORED : T*/ T*/MOD SWAP DROP ; +IFSYM : T/MOD >R S>D R> SM/REM ; +IFSYM : T/ T/MOD SWAP DROP ; +IFSYM : TMOD T/MOD DROP ; +IFSYM : T*/MOD >R M* R> SM/REM ; +IFSYM : T*/ T*/MOD SWAP DROP ; + +{ 0 1 /MOD -> 0 1 T/MOD } +{ 1 1 /MOD -> 1 1 T/MOD } +{ 2 1 /MOD -> 2 1 T/MOD } +{ -1 1 /MOD -> -1 1 T/MOD } +{ -2 1 /MOD -> -2 1 T/MOD } +{ 0 -1 /MOD -> 0 -1 T/MOD } +{ 1 -1 /MOD -> 1 -1 T/MOD } +{ 2 -1 /MOD -> 2 -1 T/MOD } +{ -1 -1 /MOD -> -1 -1 T/MOD } +{ -2 -1 /MOD -> -2 -1 T/MOD } +{ 2 2 /MOD -> 2 2 T/MOD } +{ -1 -1 /MOD -> -1 -1 T/MOD } +{ -2 -2 /MOD -> -2 -2 T/MOD } +{ 7 3 /MOD -> 7 3 T/MOD } +{ 7 -3 /MOD -> 7 -3 T/MOD } +{ -7 3 /MOD -> -7 3 T/MOD } +{ -7 -3 /MOD -> -7 -3 T/MOD } +{ MAX-INT 1 /MOD -> MAX-INT 1 T/MOD } +{ MIN-INT 1 /MOD -> MIN-INT 1 T/MOD } +{ MAX-INT MAX-INT /MOD -> MAX-INT MAX-INT T/MOD } +{ MIN-INT MIN-INT /MOD -> MIN-INT MIN-INT T/MOD } + +{ 0 1 / -> 0 1 T/ } +{ 1 1 / -> 1 1 T/ } +{ 2 1 / -> 2 1 T/ } +{ -1 1 / -> -1 1 T/ } +{ -2 1 / -> -2 1 T/ } +{ 0 -1 / -> 0 -1 T/ } +{ 1 -1 / -> 1 -1 T/ } +{ 2 -1 / -> 2 -1 T/ } +{ -1 -1 / -> -1 -1 T/ } +{ -2 -1 / -> -2 -1 T/ } +{ 2 2 / -> 2 2 T/ } +{ -1 -1 / -> -1 -1 T/ } +{ -2 -2 / -> -2 -2 T/ } +{ 7 3 / -> 7 3 T/ } +{ 7 -3 / -> 7 -3 T/ } +{ -7 3 / -> -7 3 T/ } +{ -7 -3 / -> -7 -3 T/ } +{ MAX-INT 1 / -> MAX-INT 1 T/ } +{ MIN-INT 1 / -> MIN-INT 1 T/ } +{ MAX-INT MAX-INT / -> MAX-INT MAX-INT T/ } +{ MIN-INT MIN-INT / -> MIN-INT MIN-INT T/ } + +{ 0 1 MOD -> 0 1 TMOD } +{ 1 1 MOD -> 1 1 TMOD } +{ 2 1 MOD -> 2 1 TMOD } +{ -1 1 MOD -> -1 1 TMOD } +{ -2 1 MOD -> -2 1 TMOD } +{ 0 -1 MOD -> 0 -1 TMOD } +{ 1 -1 MOD -> 1 -1 TMOD } +{ 2 -1 MOD -> 2 -1 TMOD } +{ -1 -1 MOD -> -1 -1 TMOD } +{ -2 -1 MOD -> -2 -1 TMOD } +{ 2 2 MOD -> 2 2 TMOD } +{ -1 -1 MOD -> -1 -1 TMOD } +{ -2 -2 MOD -> -2 -2 TMOD } +{ 7 3 MOD -> 7 3 TMOD } +{ 7 -3 MOD -> 7 -3 TMOD } +{ -7 3 MOD -> -7 3 TMOD } +{ -7 -3 MOD -> -7 -3 TMOD } +{ MAX-INT 1 MOD -> MAX-INT 1 TMOD } +{ MIN-INT 1 MOD -> MIN-INT 1 TMOD } +{ MAX-INT MAX-INT MOD -> MAX-INT MAX-INT TMOD } +{ MIN-INT MIN-INT MOD -> MIN-INT MIN-INT TMOD } + +{ 0 2 1 */ -> 0 2 1 T*/ } +{ 1 2 1 */ -> 1 2 1 T*/ } +{ 2 2 1 */ -> 2 2 1 T*/ } +{ -1 2 1 */ -> -1 2 1 T*/ } +{ -2 2 1 */ -> -2 2 1 T*/ } +{ 0 2 -1 */ -> 0 2 -1 T*/ } +{ 1 2 -1 */ -> 1 2 -1 T*/ } +{ 2 2 -1 */ -> 2 2 -1 T*/ } +{ -1 2 -1 */ -> -1 2 -1 T*/ } +{ -2 2 -1 */ -> -2 2 -1 T*/ } +{ 2 2 2 */ -> 2 2 2 T*/ } +{ -1 2 -1 */ -> -1 2 -1 T*/ } +{ -2 2 -2 */ -> -2 2 -2 T*/ } +{ 7 2 3 */ -> 7 2 3 T*/ } +{ 7 2 -3 */ -> 7 2 -3 T*/ } +{ -7 2 3 */ -> -7 2 3 T*/ } +{ -7 2 -3 */ -> -7 2 -3 T*/ } +{ MAX-INT 2 MAX-INT */ -> MAX-INT 2 MAX-INT T*/ } +{ MIN-INT 2 MIN-INT */ -> MIN-INT 2 MIN-INT T*/ } + +{ 0 2 1 */MOD -> 0 2 1 T*/MOD } +{ 1 2 1 */MOD -> 1 2 1 T*/MOD } +{ 2 2 1 */MOD -> 2 2 1 T*/MOD } +{ -1 2 1 */MOD -> -1 2 1 T*/MOD } +{ -2 2 1 */MOD -> -2 2 1 T*/MOD } +{ 0 2 -1 */MOD -> 0 2 -1 T*/MOD } +{ 1 2 -1 */MOD -> 1 2 -1 T*/MOD } +{ 2 2 -1 */MOD -> 2 2 -1 T*/MOD } +{ -1 2 -1 */MOD -> -1 2 -1 T*/MOD } +{ -2 2 -1 */MOD -> -2 2 -1 T*/MOD } +{ 2 2 2 */MOD -> 2 2 2 T*/MOD } +{ -1 2 -1 */MOD -> -1 2 -1 T*/MOD } +{ -2 2 -2 */MOD -> -2 2 -2 T*/MOD } +{ 7 2 3 */MOD -> 7 2 3 T*/MOD } +{ 7 2 -3 */MOD -> 7 2 -3 T*/MOD } +{ -7 2 3 */MOD -> -7 2 3 T*/MOD } +{ -7 2 -3 */MOD -> -7 2 -3 T*/MOD } +{ MAX-INT 2 MAX-INT */MOD -> MAX-INT 2 MAX-INT T*/MOD } +{ MIN-INT 2 MIN-INT */MOD -> MIN-INT 2 MIN-INT T*/MOD } + +\ ------------------------------------------------------------------------ +TESTING HERE , @ ! CELL+ CELLS C, C@ C! CHARS 2@ 2! ALIGN ALIGNED +! ALLOT + +HERE 1 ALLOT +HERE +CONSTANT 2NDA +CONSTANT 1STA +{ 1STA 2NDA U< -> } \ HERE MUST GROW WITH ALLOT +{ 1STA 1+ -> 2NDA } \ ... BY ONE ADDRESS UNIT +( MISSING TEST: NEGATIVE ALLOT ) + +HERE 1 , +HERE 2 , +CONSTANT 2ND +CONSTANT 1ST +{ 1ST 2ND U< -> } \ HERE MUST GROW WITH ALLOT +{ 1ST CELL+ -> 2ND } \ ... BY ONE CELL +{ 1ST 1 CELLS + -> 2ND } +{ 1ST @ 2ND @ -> 1 2 } +{ 5 1ST ! -> } +{ 1ST @ 2ND @ -> 5 2 } +{ 6 2ND ! -> } +{ 1ST @ 2ND @ -> 5 6 } +{ 1ST 2@ -> 6 5 } +{ 2 1 1ST 2! -> } +{ 1ST 2@ -> 2 1 } +{ 1S 1ST ! 1ST @ -> 1S } \ CAN STORE CELL-WIDE VALUE + +HERE 1 C, +HERE 2 C, +CONSTANT 2NDC +CONSTANT 1STC +{ 1STC 2NDC U< -> } \ HERE MUST GROW WITH ALLOT +{ 1STC CHAR+ -> 2NDC } \ ... BY ONE CHAR +{ 1STC 1 CHARS + -> 2NDC } +{ 1STC C@ 2NDC C@ -> 1 2 } +{ 3 1STC C! -> } +{ 1STC C@ 2NDC C@ -> 3 2 } +{ 4 2NDC C! -> } +{ 1STC C@ 2NDC C@ -> 3 4 } + +ALIGN 1 ALLOT HERE ALIGN HERE 3 CELLS ALLOT +CONSTANT A-ADDR CONSTANT UA-ADDR +{ UA-ADDR ALIGNED -> A-ADDR } +{ 1 A-ADDR C! A-ADDR C@ -> 1 } +{ 1234 A-ADDR ! A-ADDR @ -> 1234 } +{ 123 456 A-ADDR 2! A-ADDR 2@ -> 123 456 } +{ 2 A-ADDR CHAR+ C! A-ADDR CHAR+ C@ -> 2 } +{ 3 A-ADDR CELL+ C! A-ADDR CELL+ C@ -> 3 } +{ 1234 A-ADDR CELL+ ! A-ADDR CELL+ @ -> 1234 } +{ 123 456 A-ADDR CELL+ 2! A-ADDR CELL+ 2@ -> 123 456 } + +: BITS ( X -- U ) + 0 SWAP BEGIN DUP WHILE DUP MSB AND IF >R 1+ R> THEN 2* REPEAT DROP ; +( CHARACTERS >= 1 AU, <= SIZE OF CELL, >= 8 BITS ) +{ 1 CHARS 1 < -> } +{ 1 CHARS 1 CELLS > -> } +( TBD: HOW TO FIND NUMBER OF BITS? ) + +( CELLS >= 1 AU, INTEGRAL MULTIPLE OF CHAR SIZE, >= 16 BITS ) +{ 1 CELLS 1 < -> } +{ 1 CELLS 1 CHARS MOD -> 0 } +{ 1S BITS 10 < -> } + +{ 0 1ST ! -> } +{ 1 1ST +! -> } +{ 1ST @ -> 1 } +{ -1 1ST +! 1ST @ -> 0 } + +\ ------------------------------------------------------------------------ +TESTING CHAR [CHAR] [ ] BL S" + +{ BL -> 20 } +{ CHAR X -> 58 } +{ CHAR HELLO -> 48 } +{ : GC1 [CHAR] X ; -> } +{ : GC2 [CHAR] HELLO ; -> } +{ GC1 -> 58 } +{ GC2 -> 48 } +{ : GC3 [ GC1 ] LITERAL ; -> } +{ GC3 -> 58 } +{ : GC4 S" XY" ; -> } +{ GC4 SWAP DROP -> 2 } +{ GC4 DROP DUP C@ SWAP CHAR+ C@ -> 58 59 } + +\ ------------------------------------------------------------------------ +TESTING ' ['] FIND EXECUTE IMMEDIATE COUNT LITERAL POSTPONE STATE + +{ : GT1 123 ; -> } +{ ' GT1 EXECUTE -> 123 } +{ : GT2 ['] GT1 ; IMMEDIATE -> } +{ GT2 EXECUTE -> 123 } +HERE 3 C, CHAR G C, CHAR T C, CHAR 1 C, CONSTANT GT1STRING +HERE 3 C, CHAR G C, CHAR T C, CHAR 2 C, CONSTANT GT2STRING +{ GT1STRING FIND -> ' GT1 -1 } +{ GT2STRING FIND -> ' GT2 1 } +( HOW TO SEARCH FOR NON-EXISTENT WORD? ) +{ : GT3 GT2 LITERAL ; -> } +{ GT3 -> ' GT1 } +{ GT1STRING COUNT -> GT1STRING CHAR+ 3 } + +{ : GT4 POSTPONE GT1 ; IMMEDIATE -> } +{ : GT5 GT4 ; -> } +{ GT5 -> 123 } +{ : GT6 345 ; IMMEDIATE -> } +{ : GT7 POSTPONE GT6 ; -> } +{ GT7 -> 345 } + +{ : GT8 STATE @ ; IMMEDIATE -> } +{ GT8 -> 0 } +{ : GT9 GT8 LITERAL ; -> } +{ GT9 0= -> } + +\ ------------------------------------------------------------------------ +TESTING IF ELSE THEN BEGIN WHILE REPEAT UNTIL RECURSE + +{ : GI1 IF 123 THEN ; -> } +{ : GI2 IF 123 ELSE 234 THEN ; -> } +{ 0 GI1 -> } +{ 1 GI1 -> 123 } +{ -1 GI1 -> 123 } +{ 0 GI2 -> 234 } +{ 1 GI2 -> 123 } +{ -1 GI1 -> 123 } + +{ : GI3 BEGIN DUP 5 < WHILE DUP 1+ REPEAT ; -> } +{ 0 GI3 -> 0 1 2 3 4 5 } +{ 4 GI3 -> 4 5 } +{ 5 GI3 -> 5 } +{ 6 GI3 -> 6 } + +{ : GI4 BEGIN DUP 1+ DUP 5 > UNTIL ; -> } +{ 3 GI4 -> 3 4 5 6 } +{ 5 GI4 -> 5 6 } +{ 6 GI4 -> 6 7 } + +{ : GI5 BEGIN DUP 2 > WHILE DUP 5 < WHILE DUP 1+ REPEAT 123 ELSE 345 THEN ; -> } +{ 1 GI5 -> 1 345 } +{ 2 GI5 -> 2 345 } +{ 3 GI5 -> 3 4 5 123 } +{ 4 GI5 -> 4 5 123 } +{ 5 GI5 -> 5 123 } + +{ : GI6 ( N -- 0,1,..N ) DUP IF DUP >R 1- RECURSE R> THEN ; -> } +{ 0 GI6 -> 0 } +{ 1 GI6 -> 0 1 } +{ 2 GI6 -> 0 1 2 } +{ 3 GI6 -> 0 1 2 3 } +{ 4 GI6 -> 0 1 2 3 4 } + +\ ------------------------------------------------------------------------ +TESTING DO LOOP +LOOP I J UNLOOP LEAVE EXIT + +{ : GD1 DO I LOOP ; -> } +{ 4 1 GD1 -> 1 2 3 } +{ 2 -1 GD1 -> -1 0 1 } +{ MID-UINT+1 MID-UINT GD1 -> MID-UINT } + +{ : GD2 DO I -1 +LOOP ; -> } +{ 1 4 GD2 -> 4 3 2 1 } +{ -1 2 GD2 -> 2 1 0 -1 } +{ MID-UINT MID-UINT+1 GD2 -> MID-UINT+1 MID-UINT } + +{ : GD3 DO 1 0 DO J LOOP LOOP ; -> } +{ 4 1 GD3 -> 1 2 3 } +{ 2 -1 GD3 -> -1 0 1 } +{ MID-UINT+1 MID-UINT GD3 -> MID-UINT } + +{ : GD4 DO 1 0 DO J LOOP -1 +LOOP ; -> } +{ 1 4 GD4 -> 4 3 2 1 } +{ -1 2 GD4 -> 2 1 0 -1 } +{ MID-UINT MID-UINT+1 GD4 -> MID-UINT+1 MID-UINT } + +{ : GD5 123 SWAP 0 DO I 4 > IF DROP 234 LEAVE THEN LOOP ; -> } +{ 1 GD5 -> 123 } +{ 5 GD5 -> 123 } +{ 6 GD5 -> 234 } + +{ : GD6 ( PAT: {0 0},{0 0}{1 0}{1 1},{0 0}{1 0}{1 1}{2 0}{2 1}{2 2} ) + 0 SWAP 0 DO + I 1+ 0 DO I J + 3 = IF I UNLOOP I UNLOOP EXIT THEN 1+ LOOP + LOOP ; -> } +{ 1 GD6 -> 1 } +{ 2 GD6 -> 3 } +{ 3 GD6 -> 4 1 2 } + +\ ------------------------------------------------------------------------ +TESTING DEFINING WORDS: : ; CONSTANT VARIABLE CREATE DOES> >BODY + +{ 123 CONSTANT X123 -> } +{ X123 -> 123 } +{ : EQU CONSTANT ; -> } +{ X123 EQU Y123 -> } +{ Y123 -> 123 } + +{ VARIABLE V1 -> } +{ 123 V1 ! -> } +{ V1 @ -> 123 } + +{ : NOP : POSTPONE ; ; -> } +{ NOP NOP1 NOP NOP2 -> } +{ NOP1 -> } +{ NOP2 -> } + +{ : DOES1 DOES> @ 1 + ; -> } +{ : DOES2 DOES> @ 2 + ; -> } +{ CREATE CR1 -> } +{ CR1 -> HERE } +{ ' CR1 >BODY -> HERE } +{ 1 , -> } +{ CR1 @ -> 1 } +{ DOES1 -> } +{ CR1 -> 2 } +{ DOES2 -> } +{ CR1 -> 3 } + +{ : WEIRD: CREATE DOES> 1 + DOES> 2 + ; -> } +{ WEIRD: W1 -> } +{ ' W1 >BODY -> HERE } +{ W1 -> HERE 1 + } +{ W1 -> HERE 2 + } + +\ ------------------------------------------------------------------------ +TESTING EVALUATE + +: GE1 S" 123" ; IMMEDIATE +: GE2 S" 123 1+" ; IMMEDIATE +: GE3 S" : GE4 345 ;" ; +: GE5 EVALUATE ; IMMEDIATE + +{ GE1 EVALUATE -> 123 } ( TEST EVALUATE IN INTERP. STATE ) +{ GE2 EVALUATE -> 124 } +{ GE3 EVALUATE -> } +{ GE4 -> 345 } + +{ : GE6 GE1 GE5 ; -> } ( TEST EVALUATE IN COMPILE STATE ) +{ GE6 -> 123 } +{ : GE7 GE2 GE5 ; -> } +{ GE7 -> 124 } + +\ ------------------------------------------------------------------------ +TESTING SOURCE >IN WORD + +: GS1 S" SOURCE" 2DUP EVALUATE + >R SWAP >R = R> R> = ; +{ GS1 -> } + +VARIABLE SCANS +: RESCAN? -1 SCANS +! SCANS @ IF 0 >IN ! THEN ; + +{ 2 SCANS ! +345 RESCAN? +-> 345 345 } + +: GS2 5 SCANS ! S" 123 RESCAN?" EVALUATE ; +{ GS2 -> 123 123 123 123 123 } + +: GS3 WORD COUNT SWAP C@ ; +{ BL GS3 HELLO -> 5 CHAR H } +{ CHAR " GS3 GOODBYE" -> 7 CHAR G } +{ BL GS3 +DROP -> 0 } \ BLANK LINE RETURN ZERO-LENGTH STRING + +: GS4 SOURCE >IN ! DROP ; +{ GS4 123 456 +-> } + +\ ------------------------------------------------------------------------ +TESTING <# # #S #> HOLD SIGN BASE >NUMBER HEX DECIMAL + +: S= \ ( ADDR1 C1 ADDR2 C2 -- T/F ) COMPARE TWO STRINGS. + >R SWAP R@ = IF \ MAKE SURE STRINGS HAVE SAME LENGTH + R> ?DUP IF \ IF NON-EMPTY STRINGS + 0 DO + OVER C@ OVER C@ - IF 2DROP UNLOOP EXIT THEN + SWAP CHAR+ SWAP CHAR+ + LOOP + THEN + 2DROP \ IF WE GET HERE, STRINGS MATCH + ELSE + R> DROP 2DROP \ LENGTHS MISMATCH + THEN ; + +: GP1 <# 41 HOLD 42 HOLD 0 0 #> S" BA" S= ; +{ GP1 -> } + +: GP2 <# -1 SIGN 0 SIGN -1 SIGN 0 0 #> S" --" S= ; +{ GP2 -> } + +: GP3 <# 1 0 # # #> S" 01" S= ; +{ GP3 -> } + +: GP4 <# 1 0 #S #> S" 1" S= ; +{ GP4 -> } + +24 CONSTANT MAX-BASE \ BASE 2 .. 36 +: COUNT-BITS + 0 0 INVERT BEGIN DUP WHILE >R 1+ R> 2* REPEAT DROP ; +COUNT-BITS 2* CONSTANT #BITS-UD \ NUMBER OF BITS IN UD + +: GP5 + BASE @ + MAX-BASE 1+ 2 DO \ FOR EACH POSSIBLE BASE + I BASE ! \ TBD: ASSUMES BASE WORKS + I 0 <# #S #> S" 10" S= AND + LOOP + SWAP BASE ! ; +{ GP5 -> } + +: GP6 + BASE @ >R 2 BASE ! + MAX-UINT MAX-UINT <# #S #> \ MAXIMUM UD TO BINARY + R> BASE ! \ S: C-ADDR U + DUP #BITS-UD = SWAP + 0 DO \ S: C-ADDR FLAG + OVER C@ [CHAR] 1 = AND \ ALL ONES + >R CHAR+ R> + LOOP SWAP DROP ; +{ GP6 -> } + +: GP7 + BASE @ >R MAX-BASE BASE ! + + A 0 DO + I 0 <# #S #> + 1 = SWAP C@ I 30 + = AND AND + LOOP + MAX-BASE A DO + I 0 <# #S #> + 1 = SWAP C@ 41 I A - + = AND AND + LOOP + R> BASE ! ; + +{ GP7 -> } + +\ >NUMBER TESTS +CREATE GN-BUF 0 C, +: GN-STRING GN-BUF 1 ; +: GN-CONSUMED GN-BUF CHAR+ 0 ; +: GN' [CHAR] ' WORD CHAR+ C@ GN-BUF C! GN-STRING ; + +{ 0 0 GN' 0' >NUMBER -> 0 0 GN-CONSUMED } +{ 0 0 GN' 1' >NUMBER -> 1 0 GN-CONSUMED } +{ 1 0 GN' 1' >NUMBER -> BASE @ 1+ 0 GN-CONSUMED } +{ 0 0 GN' -' >NUMBER -> 0 0 GN-STRING } \ SHOULD FAIL TO CONVERT THESE +{ 0 0 GN' +' >NUMBER -> 0 0 GN-STRING } +{ 0 0 GN' .' >NUMBER -> 0 0 GN-STRING } + +: >NUMBER-BASED + BASE @ >R BASE ! >NUMBER R> BASE ! ; + +{ 0 0 GN' 2' 10 >NUMBER-BASED -> 2 0 GN-CONSUMED } +{ 0 0 GN' 2' 2 >NUMBER-BASED -> 0 0 GN-STRING } +{ 0 0 GN' F' 10 >NUMBER-BASED -> F 0 GN-CONSUMED } +{ 0 0 GN' G' 10 >NUMBER-BASED -> 0 0 GN-STRING } +{ 0 0 GN' G' MAX-BASE >NUMBER-BASED -> 10 0 GN-CONSUMED } +{ 0 0 GN' Z' MAX-BASE >NUMBER-BASED -> 23 0 GN-CONSUMED } + +: GN1 \ ( UD BASE -- UD' LEN ) UD SHOULD EQUAL UD' AND LEN SHOULD BE ZERO. + BASE @ >R BASE ! + <# #S #> + 0 0 2SWAP >NUMBER SWAP DROP \ RETURN LENGTH ONLY + R> BASE ! ; +{ 0 0 2 GN1 -> 0 0 0 } +{ MAX-UINT 0 2 GN1 -> MAX-UINT 0 0 } +{ MAX-UINT DUP 2 GN1 -> MAX-UINT DUP 0 } +{ 0 0 MAX-BASE GN1 -> 0 0 0 } +{ MAX-UINT 0 MAX-BASE GN1 -> MAX-UINT 0 0 } +{ MAX-UINT DUP MAX-BASE GN1 -> MAX-UINT DUP 0 } + +: GN2 \ ( -- 16 10 ) + BASE @ >R HEX BASE @ DECIMAL BASE @ R> BASE ! ; +{ GN2 -> 10 A } + +\ ------------------------------------------------------------------------ +TESTING FILL MOVE + +CREATE FBUF 00 C, 00 C, 00 C, +CREATE SBUF 12 C, 34 C, 56 C, +: SEEBUF FBUF C@ FBUF CHAR+ C@ FBUF CHAR+ CHAR+ C@ ; + +{ FBUF 0 20 FILL -> } +{ SEEBUF -> 00 00 00 } + +{ FBUF 1 20 FILL -> } +{ SEEBUF -> 20 00 00 } + +{ FBUF 3 20 FILL -> } +{ SEEBUF -> 20 20 20 } + +{ FBUF FBUF 3 CHARS MOVE -> } \ BIZARRE SPECIAL CASE +{ SEEBUF -> 20 20 20 } + +{ SBUF FBUF 0 CHARS MOVE -> } +{ SEEBUF -> 20 20 20 } + +{ SBUF FBUF 1 CHARS MOVE -> } +{ SEEBUF -> 12 20 20 } + +{ SBUF FBUF 3 CHARS MOVE -> } +{ SEEBUF -> 12 34 56 } + +{ FBUF FBUF CHAR+ 2 CHARS MOVE -> } +{ SEEBUF -> 12 12 34 } + +{ FBUF CHAR+ FBUF 2 CHARS MOVE -> } +{ SEEBUF -> 12 34 34 } + +\ ------------------------------------------------------------------------ +TESTING OUTPUT: . ." CR EMIT SPACE SPACES TYPE U. + +: OUTPUT-TEST + ." YOU SHOULD SEE THE STANDARD GRAPHIC CHARACTERS:" CR + 41 BL DO I EMIT LOOP CR + 61 41 DO I EMIT LOOP CR + 7F 61 DO I EMIT LOOP CR + ." YOU SHOULD SEE 0-9 SEPARATED BY A SPACE:" CR + 9 1+ 0 DO I . LOOP CR + ." YOU SHOULD SEE 0-9 (WITH NO SPACES):" CR + [CHAR] 9 1+ [CHAR] 0 DO I 0 SPACES EMIT LOOP CR + ." YOU SHOULD SEE A-G SEPARATED BY A SPACE:" CR + [CHAR] G 1+ [CHAR] A DO I EMIT SPACE LOOP CR + ." YOU SHOULD SEE 0-5 SEPARATED BY TWO SPACES:" CR + 5 1+ 0 DO I [CHAR] 0 + EMIT 2 SPACES LOOP CR + ." YOU SHOULD SEE TWO SEPARATE LINES:" CR + S" LINE 1" TYPE CR S" LINE 2" TYPE CR + ." YOU SHOULD SEE THE NUMBER RANGES OF SIGNED AND UNSIGNED NUMBERS:" CR + ." SIGNED: " MIN-INT . MAX-INT . CR + ." UNSIGNED: " 0 U. MAX-UINT U. CR +; + +{ OUTPUT-TEST -> } + +\ ------------------------------------------------------------------------ +TESTING INPUT: ACCEPT + +CREATE ABUF 80 CHARS ALLOT + +: ACCEPT-TEST + CR ." PLEASE TYPE UP TO 80 CHARACTERS:" CR + ABUF 80 ACCEPT + CR ." RECEIVED: " [CHAR] " EMIT + ABUF SWAP TYPE [CHAR] " EMIT CR +; + +{ ACCEPT-TEST -> } + +\ ------------------------------------------------------------------------ +TESTING DICTIONARY SEARCH RULES + +{ : GDX 123 ; : GDX GDX 234 ; -> } + +{ GDX -> 123 234 } + + diff --git a/src/cmd/pforth/fth/filefind.fth b/src/cmd/pforth/fth/filefind.fth new file mode 100644 index 0000000..0723e38 --- /dev/null +++ b/src/cmd/pforth/fth/filefind.fth @@ -0,0 +1,119 @@ +\ @(#) filefind.fth 98/01/26 1.2 +\ FILE? ( -- , report which file this Forth word was defined in ) +\ +\ FILE? looks for ::::Filename and ;;;; in the dictionary +\ that have been left by INCLUDE. It figures out nested +\ includes and reports each file that defines the word. +\ +\ Author: Phil Burk +\ Copyright 1992 Phil Burk +\ +\ 00001 PLB 2/21/92 Handle words from kernel or keyboard. +\ Support EACH.FILE? +\ 961213 PLB Port to pForth. + +ANEW TASK-FILEFIND.FTH + +: BE@ { addr | val -- val , fetch from unaligned address in BigEndian order } + 4 0 + DO + addr i + c@ + val 8 lshift or -> val + LOOP + val +; + +: BE! { val addr -- , store to unaligned address in BigEndian order } + 4 0 + DO + val 3 i - 8 * rshift + addr i + c! + LOOP +; +: BEW@ { addr -- , fetch word from unaligned address in BigEndian order } + addr c@ 8 lshift + addr 1+ c@ OR +; + +: BEW! { val addr -- , store word to unaligned address in BigEndian order } + val 8 rshift addr c! + val addr 1+ c! +; + +\ scan dictionary from NFA for filename +: F?.SEARCH.NFA { nfa | dpth stoploop keyb nfa0 -- addr count } + 0 -> dpth + 0 -> stoploop + 0 -> keyb + nfa -> nfa0 + BEGIN + nfa prevname -> nfa + nfa 0> + IF + nfa 1+ be@ + CASE + $ 3a3a3a3a ( :::: ) + OF + dpth 0= + IF + nfa count 31 and + 4 - swap 4 + swap + true -> stoploop + ELSE + -1 dpth + -> dpth + THEN + ENDOF + $ 3b3b3b3b ( ;;;; ) + OF + 1 dpth + -> dpth + true -> keyb \ maybe from keyboard + ENDOF + ENDCASE + ELSE + true -> stoploop + keyb + IF + " keyboard" + ELSE + " 'C' kernel" + THEN + count + THEN + stoploop + UNTIL +; + +: FINDNFA.FROM { $name start_nfa -- nfa true | $word false } + context @ >r + start_nfa context ! + $name findnfa + r> context ! +; + +\ Search entire dictionary for all occurences of named word. +: FILE? { | $word nfa done? -- , take name from input } + 0 -> done? + bl word -> $word + $word findnfa + IF ( -- nfa ) + $word count type ." from:" cr + -> nfa + BEGIN + nfa f?.search.nfa ( addr cnt ) + nfa name> 12 .r \ print xt + 4 spaces type cr + nfa prevname dup -> nfa + 0> + IF + $word nfa findnfa.from \ search from one behind found nfa + swap -> nfa + not + ELSE + true + THEN + UNTIL + ELSE ( -- $word ) + count type ." not found!" cr + THEN +; + diff --git a/src/cmd/pforth/fth/floats.fth b/src/cmd/pforth/fth/floats.fth new file mode 100644 index 0000000..a6506fb --- /dev/null +++ b/src/cmd/pforth/fth/floats.fth @@ -0,0 +1,502 @@ +\ @(#) floats.fth 98/02/26 1.4 17:51:40 +\ High Level Forth support for Floating Point +\ +\ Author: Phil Burk and Darren Gibbs +\ Copyright 1994 3DO, Phil Burk, Larry Polansky, Devid Rosenboom +\ +\ The pForth software code is dedicated to the public domain, +\ and any third party may reproduce, distribute and modify +\ the pForth software code or any derivative works thereof +\ without any compensation or license. The pForth software +\ code is provided on an "as is" basis without any warranty +\ of any kind, including, without limitation, the implied +\ warranties of merchantability and fitness for a particular +\ purpose and their equivalents under the laws of any jurisdiction. +\ +\ 19970702 PLB Drop 0.0 in REPRESENT to fix 0.0 F. +\ 19980220 PLB Added FG. , fixed up large and small formatting +\ 19980812 PLB Now don't drop 0.0 in REPRESENT to fix 0.0 F. (!!!) +\ Fixed F~ by using (F.EXACTLY) + +ANEW TASK-FLOATS.FTH + +: FALIGNED ( addr -- a-addr ) + 1 floats 1- + + 1 floats / + 1 floats * +; + +: FALIGN ( -- , align DP ) + dp @ faligned dp ! +; + +\ account for size of create when aligning floats +here +create fp-create-size +fp-create-size swap - constant CREATE_SIZE + +: FALIGN.CREATE ( -- , align DP for float after CREATE ) + dp @ + CREATE_SIZE + + faligned + CREATE_SIZE - + dp ! +; + +: FCREATE ( -- , create with float aligned data ) + falign.create + CREATE +; + +: FVARIABLE ( -- ) ( F: -- ) + FCREATE 1 floats allot +; + +: FCONSTANT + FCREATE here 1 floats allot f! + DOES> f@ +; + +: F0SP ( -- ) ( F: ? -- ) + fdepth 0 max 0 ?DO fdrop LOOP +; + +\ Convert between single precision and floating point +: S>F ( s -- ) ( F: -- r ) + s>d d>f +; +: F>S ( -- s ) ( F: r -- ) + f>d d>s +; + +: (F.EXACTLY) ( r1 r2 -f- flag , return true if encoded equally ) { | caddr1 caddr2 fsize fcells } + 1 floats -> fsize + fsize cell 1- + cell 1- invert and \ round up to nearest multiple of stack size + cell / -> fcells ( number of cells per float ) +\ make room on data stack for floats data + fcells 0 ?DO 0 LOOP + sp@ -> caddr1 + fcells 0 ?DO 0 LOOP + sp@ -> caddr2 +\ compare bit representation + caddr1 f! + caddr2 f! + caddr1 fsize caddr2 fsize compare 0= + >r fcells 2* 0 ?DO drop LOOP r> \ drop float bits +; + +: F~ ( -0- flag ) ( r1 r2 r3 -f- ) + fdup F0< + IF + frot frot ( -- r3 r1 r2 ) + fover fover ( -- r3 r1 r2 r1 r2 ) + f- fabs ( -- r3 r1 r2 |r1-r2| ) + frot frot ( -- r3 |r1-r2| r1 r2 ) + fabs fswap fabs f+ ( -- r3 |r1-r2| |r1|+|r2| ) + frot fabs f* ( -- |r1-r2| |r1|+|r2|*|r3| ) + f< + ELSE + fdup f0= + IF + fdrop + (f.exactly) \ f- f0= \ 19980812 Used to cheat. Now actually compares bit patterns. + ELSE + frot frot ( -- r3 r1 r2 ) + f- fabs ( -- r3 |r1-r2| ) + fswap f< + THEN + THEN +; + +\ FP Output -------------------------------------------------------- +fvariable FVAR-REP \ scratch var for represent +: REPRESENT { c-addr u | n flag1 flag2 -- n flag1 flag2 , FLOATING } ( F: r -- ) + TRUE -> flag2 \ FIXME - need to check range + fvar-rep f! +\ + fvar-rep f@ f0< + IF + -1 -> flag1 + fvar-rep f@ fabs fvar-rep f! \ absolute value + ELSE + 0 -> flag1 + THEN +\ + fvar-rep f@ f0= + IF +\ fdrop \ 19970702 \ 19980812 Remove FDROP to fix "0.0 F." + c-addr u [char] 0 fill + 0 -> n + ELSE + fvar-rep f@ + flog + fdup f0< not + IF + 1 s>f f+ \ round up exponent + THEN + f>s -> n +\ ." REP - n = " n . cr +\ normalize r to u digits + fvar-rep f@ + 10 s>f u n - s>f f** f* + 1 s>f 2 s>f f/ f+ \ round result +\ +\ convert float to double_int then convert to text + f>d +\ ." REP - d = " over . dup . cr + <# u 1- 0 ?DO # loop #s #> \ ( -- addr cnt ) +\ Adjust exponent if rounding caused number of digits to increase. +\ For example from 9999 to 10000. + u - +-> n + c-addr u move + THEN +\ + n flag1 flag2 +; + +variable FP-PRECISION + +\ Set maximum digits that are meaningful for the precision that we use. +1 FLOATS 4 / 7 * constant FP_PRECISION_MAX + +: PRECISION ( -- u ) + fp-precision @ +; +: SET-PRECISION ( u -- ) + fp_precision_max min + fp-precision ! +; +7 set-precision + +32 constant FP_REPRESENT_SIZE +64 constant FP_OUTPUT_SIZE + +create FP-REPRESENT-PAD FP_REPRESENT_SIZE allot \ used with REPRESENT +create FP-OUTPUT-PAD FP_OUTPUT_SIZE allot \ used to assemble final output +variable FP-OUTPUT-PTR \ points into FP-OUTPUT-PAD + +: FP.HOLD ( char -- , add char to output ) + fp-output-ptr @ fp-output-pad 64 + < + IF + fp-output-ptr @ tuck c! + 1+ fp-output-ptr ! + ELSE + drop + THEN +; +: FP.APPEND { addr cnt -- , add string to output } + cnt 0 max 0 + ?DO + addr i + c@ fp.hold + LOOP +; + +: FP.STRIP.TRAILING.ZEROS ( -- , remove trailing zeros from fp output ) + BEGIN + fp-output-ptr @ fp-output-pad u> + fp-output-ptr @ 1- c@ [char] 0 = + and + WHILE + -1 fp-output-ptr +! + REPEAT +; + +: FP.APPEND.ZEROS ( numZeros -- ) + 0 max 0 + ?DO [char] 0 fp.hold + LOOP +; + +: FP.MOVE.DECIMAL { n prec -- , append with decimal point shifted } + fp-represent-pad n prec min fp.append + n prec - fp.append.zeros + [char] . fp.hold + fp-represent-pad n + + prec n - 0 max fp.append +; + +: (EXP.) ( n -- addr cnt , convert exponent to two digit value ) + dup abs 0 + <# # #s + rot 0< + IF [char] - HOLD + ELSE [char] + hold + THEN + #> +; + +: FP.REPRESENT ( -- n flag1 flag2 ) ( r -f- ) +; + +: (FS.) ( -- addr cnt ) ( F: r -- , scientific notation ) + fp-output-pad fp-output-ptr ! \ setup pointer + fp-represent-pad precision represent +\ ." (FS.) - represent " fp-represent-pad precision type cr + ( -- n flag1 flag2 ) + IF + IF [char] - fp.hold + THEN + 1 precision fp.move.decimal + [char] e fp.hold + 1- (exp.) fp.append \ n + ELSE + 2drop + s" " fp.append + THEN + fp-output-pad fp-output-ptr @ over - +; + +: FS. ( F: r -- , scientific notation ) + (fs.) type space +; + +: (FE.) ( -- addr cnt ) ( F: r -- , engineering notation ) { | n n3 -- } + fp-output-pad fp-output-ptr ! \ setup pointer + fp-represent-pad precision represent + ( -- n flag1 flag2 ) + IF + IF [char] - fp.hold + THEN +\ convert exponent to multiple of three + -> n + n 1- s>d 3 fm/mod \ use floored divide + 3 * -> n3 + 1+ precision fp.move.decimal \ amount to move decimal point + [char] e fp.hold + n3 (exp.) fp.append \ n + ELSE + 2drop + s" " fp.append + THEN + fp-output-pad fp-output-ptr @ over - +; + +: FE. ( F: r -- , engineering notation ) + (FE.) type space +; + +: (FG.) ( F: r -- , normal or scientific ) { | n n3 ndiff -- } + fp-output-pad fp-output-ptr ! \ setup pointer + fp-represent-pad precision represent + ( -- n flag1 flag2 ) + IF + IF [char] - fp.hold + THEN +\ compare n with precision to see whether we do scientific display + dup precision > + over -3 < OR + IF \ use exponential notation + 1 precision fp.move.decimal + fp.strip.trailing.zeros + [char] e fp.hold + 1- (exp.) fp.append \ n + ELSE + dup 0> + IF +\ POSITIVE EXPONENT - place decimal point in middle + precision fp.move.decimal + ELSE +\ NEGATIVE EXPONENT - use 0.000???? + s" 0." fp.append +\ output leading zeros + negate fp.append.zeros + fp-represent-pad precision fp.append + THEN + fp.strip.trailing.zeros + THEN + ELSE + 2drop + s" " fp.append + THEN + fp-output-pad fp-output-ptr @ over - +; + +: FG. ( F: r -- ) + (fg.) type space +; + +: (F.) ( F: r -- , normal or scientific ) { | n n3 ndiff prec' -- } + fp-output-pad fp-output-ptr ! \ setup pointer + fp-represent-pad \ place to put number + fdup flog 1 s>f f+ f>s precision max + fp_precision_max min dup -> prec' + represent + ( -- n flag1 flag2 ) + IF +\ add '-' sign if negative + IF [char] - fp.hold + THEN +\ compare n with precision to see whether we must do scientific display + dup fp_precision_max > + IF \ use exponential notation + 1 precision fp.move.decimal + fp.strip.trailing.zeros + [char] e fp.hold + 1- (exp.) fp.append \ n + ELSE + dup 0> + IF + \ POSITIVE EXPONENT - place decimal point in middle + prec' fp.move.decimal + ELSE + \ NEGATIVE EXPONENT - use 0.000???? + s" 0." fp.append + \ output leading zeros + dup negate precision min + fp.append.zeros + fp-represent-pad precision rot + fp.append + THEN + THEN + ELSE + 2drop + s" " fp.append + THEN + fp-output-pad fp-output-ptr @ over - +; + +: F. ( F: r -- ) + (f.) type space +; + +: F.S ( -- , print FP stack ) + ." FP> " + fdepth 0> + IF + fdepth 0 + DO + cr? + fdepth i - 1- \ index of next float + fpick f. cr? + LOOP + ELSE + ." empty" + THEN + cr +; + +\ FP Input ---------------------------------------------------------- +variable FP-REQUIRE-E \ must we put an E in FP numbers? +false fp-require-e ! \ violate ANSI !! + +: >FLOAT { c-addr u | dlo dhi u' fsign flag nshift -- flag } + u 0= IF false exit THEN + false -> flag + 0 -> nshift +\ +\ check for minus sign + c-addr c@ [char] - = dup -> fsign + c-addr c@ [char] + = OR + IF 1 +-> c-addr -1 +-> u \ skip char + THEN +\ +\ convert first set of digits + 0 0 c-addr u >number -> u' -> c-addr -> dhi -> dlo + u' 0> + IF +\ convert optional second set of digits + c-addr c@ [char] . = + IF + dlo dhi c-addr 1+ u' 1- dup -> nshift >number + dup nshift - -> nshift + -> u' -> c-addr -> dhi -> dlo + THEN +\ convert exponent + u' 0> + IF + c-addr c@ [char] E = + c-addr c@ [char] e = OR + IF + 1 +-> c-addr -1 +-> u' \ skip E char + u' 0> + IF + c-addr c@ [char] + = \ ignore + on exponent + IF + 1 +-> c-addr -1 +-> u' \ skip char + THEN + c-addr u' ((number?)) + num_type_single = + IF + nshift + -> nshift + true -> flag + THEN + ELSE + true -> flag \ allow "1E" + THEN + THEN + ELSE +\ only require E field if this variable is true + fp-require-e @ not -> flag + THEN + THEN +\ convert double precision int to float + flag + IF + dlo dhi d>f + 10 s>f nshift s>f f** f* \ apply exponent + fsign + IF + fnegate + THEN + THEN + flag +; + +3 constant NUM_TYPE_FLOAT \ possible return type for NUMBER? + +: (FP.NUMBER?) ( $addr -- 0 | n 1 | d 2 | r 3 , convert string to number ) +\ check to see if it is a valid float, if not use old (NUMBER?) + dup count >float + IF + drop NUM_TYPE_FLOAT + ELSE + (number?) + THEN +; + +defer fp.old.number? +variable FP-IF-INIT + +: FP.TERM ( -- , deinstall fp conversion ) + fp-if-init @ + IF + what's fp.old.number? is number? + fp-if-init off + THEN +; + +: FP.INIT ( -- , install FP converion ) + fp.term + what's number? is fp.old.number? + ['] (fp.number?) is number? + fp-if-init on + ." Floating point numeric conversion installed." cr +; + +FP.INIT +if.forgotten fp.term + + +0 [IF] + +23.8e-9 fconstant fsmall +1.0 fsmall f- fconstant falmost1 +." Should be 1.0 = " falmost1 f. cr + +: TSEGF ( r -f- , print in all formats ) +." --------------------------------" cr + 34 0 + DO + fdup fs. 4 spaces fdup fe. 4 spaces + fdup fg. 4 spaces fdup f. cr + 10.0 f/ + LOOP + fdrop +; + +: TFP + 1.234e+22 tsegf + 1.23456789e+22 tsegf + 0.927 fsin 1.234e+22 f* tsegf +; + +[THEN] diff --git a/src/cmd/pforth/fth/forget.fth b/src/cmd/pforth/fth/forget.fth new file mode 100644 index 0000000..4b872ac --- /dev/null +++ b/src/cmd/pforth/fth/forget.fth @@ -0,0 +1,97 @@ +\ @(#) forget.fth 98/01/26 1.2 +\ forget.fth +\ +\ forget part of dictionary +\ +\ Author: Phil Burk +\ Copyright 1994 3DO, Phil Burk, Larry Polansky, Devid Rosenboom +\ +\ The pForth software code is dedicated to the public domain, +\ and any third party may reproduce, distribute and modify +\ the pForth software code or any derivative works thereof +\ without any compensation or license. The pForth software +\ code is provided on an "as is" basis without any warranty +\ of any kind, including, without limitation, the implied +\ warranties of merchantability and fitness for a particular +\ purpose and their equivalents under the laws of any jurisdiction. +\ +\ 19970701 PLB Use unsigned compares for machines with "negative" addresses. + +variable RFENCE \ relocatable value below which we won't forget + +: FREEZE ( -- , protect below here ) + here rfence a! +; + +: FORGET.NFA ( nfa -- , set DP etc. ) + dup name> >code dp ! + prevname ( dup current ! ) dup context ! n>nextlink headers-ptr ! +; + +: VERIFY.FORGET ( nfa -- , ask for verification if below fence ) + dup name> >code rfence a@ u< \ 19970701 + IF + >newline dup id. ." is below fence!!" cr + drop + ELSE forget.nfa + THEN +; + +: (FORGET) ( -- ) + BL word findnfa + IF verify.forget + ELSE ." FORGET - couldn't find " count type cr abort + THEN +; + +variable LAST-FORGET \ contains address of last if.forgotten frame +0 last-forget ! + +: IF.FORGOTTEN ( -- , place links in dictionary without header ) + bl word find + IF ( xt ) + here \ start of frame + last-forget a@ a, \ Cell[0] = rel address of previous frame + last-forget a! \ point to this frame + compile, \ Cell[1] = xt for this frame + ELSE ." IF.FORGOTTEN - couldn't find " dup 9 dump cr count type cr abort + THEN +; +if.forgotten noop + +: [FORGET] ( -- , forget then exec forgotten words ) + (forget) + last-forget + BEGIN a@ dup 0<> \ 19970701 + IF dup here u> \ 19970701 + IF dup cell+ x@ execute false + ELSE dup last-forget a! true + THEN + ELSE true + THEN + UNTIL drop +; + +: FORGET ( -- , execute latest [FORGET] ) + " [FORGET]" find + IF execute + ELSE ." FORGET - couldn't find " count type cr abort + THEN +; + +: ANEW ( -- , forget if defined then redefine ) + >in @ + bl word find + IF over >in ! forget + THEN drop + >in ! variable +; + +: MARKER ( -- , define a word that forgets itself when executed, ANS ) + CREATE + latest namebase - \ convert to relocatable + , \ save for DOES> + DOES> ( -- body ) + @ namebase + \ convert back to NFA + verify.forget +; diff --git a/src/cmd/pforth/fth/history.fth b/src/cmd/pforth/fth/history.fth new file mode 100644 index 0000000..8c61eac --- /dev/null +++ b/src/cmd/pforth/fth/history.fth @@ -0,0 +1,513 @@ +\ Command Line History +\ +\ Author: Phil Burk +\ Copyright 1988 Phil Burk +\ Revised 2001 for pForth + +0 [IF] + +Requires an ANSI compatible terminal. + +To get Windows computers to use ANSI mode in their DOS windows, +Add this line to "C:\CONFIG.SYS" then reboot. + + device=c:\windows\command\ansi.sys + +When command line history is on, you can use the UP and DOWN arrow to scroll +through previous commands. Use the LEFT and RIGHT arrows to edit within a line. + CONTROL-A moves to beginning of line. + CONTROL-E moves to end of line. + CONTROL-X erases entire line. + + +HISTORY# ( -- , dump history buffer with numbers) +HISTORY ( -- , dump history buffer ) +XX ( line# -- , execute line x of history ) +HISTORY.RESET ( -- , clear history tables ) +HISTORY.ON ( -- , install history vectors ) +HISTORY.OFF ( -- , uninstall history vectors ) + +[THEN] + +include? ESC[ termio.fth + +ANEW TASK-HISTORY.FTH +decimal + +private{ + +\ You can expand the history buffer by increasing this constant!!!!!!!!!! +2048 constant KH_HISTORY_SIZE + +create KH-HISTORY kh_history_size allot +KH-HISTORY kh_history_size erase + +\ An entry in the history buffer consists of +\ byte - Count byte = N, +\ chars - N chars, +\ short - line number in Big Endian format, +\ byte - another Count byte = N, for reverse scan +\ +\ The most recent entry is put at the beginning, +\ older entries are shifted up. + +4 constant KH_LINE_EXTRA_SIZE ( 2 count bytes plus 2 size bytes ) + +: KH-END ( -- addr , end of history buffer ) + kh-history kh_history_size + +; + +: LINENUM@ ( addr -- w , stores in BigEndian format ) + dup c@ 8 shift + swap 1+ c@ or +; + +: LINENUM! ( w addr -- ) + over -8 shift over c! + 1+ c! +; + +variable KH-LOOK ( cursor offset into history, point to 1st count byte of line ) +variable KH-MAX +variable KH-COUNTER ( 16 bit counter for line # ) +variable KH-SPAN ( total number of characters in line ) +variable KH-MATCH-SPAN ( span for matching on shift-up ) +variable KH-CURSOR ( points to next insertion point ) +variable KH-ADDRESS ( address to store chars ) +variable KH-INSIDE ( true if we are scrolling inside the history buffer ) + +: KH.MAKE.ROOM ( N -- , make room for N more bytes at beginning) + >r ( save N ) + kh-history dup r@ + ( source dest ) + kh_history_size r> - 0 max move +; + +: KH.NEWEST.LINE ( -- addr count , most recent line ) + kh-history count +; + +: KH.REWIND ( -- , move cursor to most recent line ) + 0 kh-look ! +; + +: KH.CURRENT.ADDR ( -- $addr , count byte of current line ) + kh-look @ kh-history + +; + +: KH.CURRENT.LINE ( -- addr count ) + kh.current.addr count +; + +: KH.COMPARE ( addr count -- flag , true if redundant ) + kh.newest.line compare 0= \ note: ANSI COMPARE is different than JForth days +; + +: KH.NUM.ADDR ( -- addr , address of current line's line count ) + kh.current.line + +; + +: KH.CURRENT.NUM ( -- # , number of current line ) + kh.num.addr LINENUM@ +; + +: KH.ADDR++ ( $addr -- $addr' , convert one kh to previous ) + count + 3 + +; +: KH.ADDR-- ( $addr -- $addr' , convert one kh to next ) + dup 1- c@ \ get next lines endcount + 4 + \ account for lineNum and two count bytes + - \ calc previous address +; + +: KH.ENDCOUNT.ADDR ( -- addr , address of current end count ) + kh.num.addr 2+ +; + +: KH.ADD.LINE ( addr count -- ) + dup 256 > + IF ." KH.ADD.LINE - Too big for history!" 2drop + ELSE ( add to end ) +\ Compare with most recent line. + 2dup kh.compare + IF 2drop + ELSE + >r ( save count ) +\ Set look pointer to point to first count byte of last string. + 0 kh-look ! +\ Make room for this line of text and line header. +\ PLB20100823 Was cell+ which broke on 64-bit code. + r@ KH_LINE_EXTRA_SIZE + kh.make.room +\ Set count bytes at beginning and end. + r@ kh-history c! ( start count ) + r@ kh.endcount.addr c! + kh-counter @ kh.num.addr LINENUM! ( line ) +\ Number lines modulo 1024 + kh-counter @ 1+ $ 3FF and kh-counter ! + kh-history 1+ ( calc destination ) + r> cmove ( copy chars into space ) + THEN + THEN +; + +: KH.BACKUP.LINE { | cantmove addr' -- cantmove , advance KH-LOOK if in bounds } + true -> cantmove ( default flag, at end of history ) +\ KH-LOOK points to count at start of current line + kh.current.addr c@ \ do we have any lines? + IF + kh.current.addr kh.addr++ -> addr' + addr' kh-end U< \ within bounds? + IF + addr' c@ \ older line has chars? + IF + addr' kh-history - kh-look ! + false -> cantmove + THEN + THEN + THEN + cantmove +; + +: KH.FORWARD.LINE ( -- cantmove? ) + kh-look @ 0= dup not + IF kh.current.addr kh.addr-- + kh-history - kh-look ! + THEN +; + +: KH.OLDEST.LINE ( -- addr count | 0, oldest in buffer ) + BEGIN kh.backup.line + UNTIL + kh.current.line dup 0= + IF + nip + THEN +; + +: KH.FIND.LINE ( line# -- $addr ) + kh.rewind + BEGIN kh.current.num over - + WHILE kh.backup.line + IF ." Line not in History Buffer!" cr drop 0 exit + THEN + REPEAT + drop kh.current.addr +; + + +: KH-BUFFER ( -- buffer ) + kh-address @ +; + +: KH.RETURN ( -- , move to beginning of line ) + 0 out ! + 13 emit +; + +: KH.REPLACE.LINE ( addr count -- , make this the current line of input ) + kh.return + tio.erase.eol + dup kh-span ! + dup kh-cursor ! + 2dup kh-buffer swap cmove + type +; + +: KH.GET.MATCH ( -- , search for line with same start ) + kh-match-span @ 0= ( keep length for multiple matches ) + IF kh-span @ kh-match-span ! + THEN + BEGIN + kh.backup.line not + WHILE + kh.current.line drop + kh-buffer kh-match-span @ text= + IF kh.current.line kh.replace.line + exit + THEN + REPEAT +; + +: KH.FAR.RIGHT + kh-span @ kh-cursor @ - dup 0> + IF + tio.forwards + kh-span @ kh-cursor ! + ELSE drop + THEN +; + +: KH.FAR.LEFT ( -- ) + kh.return + kh-cursor off +; + +: KH.GET.OLDER ( -- , goto previous line ) + kh-inside @ + IF kh.backup.line drop + THEN + kh.current.line kh.replace.line + kh-inside on +; + +: KH.GET.NEWER ( -- , next line ) + kh.forward.line + IF + kh-inside off + tib 0 + ELSE kh.current.line + THEN + kh.replace.line +; + +: KH.CLEAR.LINE ( -- , rewind history scrolling and clear line ) + kh.rewind + tib 0 kh.replace.line + kh-inside off +; + +: KH.GO.RIGHT ( -- ) + kh-cursor @ kh-span @ < + IF 1 kh-cursor +! + 1 tio.forwards + THEN +; + +: KH.GO.LEFT ( -- ) + kh-cursor @ ?dup + IF 1- kh-cursor ! + 1 tio.backwards + THEN +; + +: KH.REFRESH ( -- , redraw current line as is ) + kh.return + kh-buffer kh-span @ type + tio.erase.eol + + kh.return + kh-cursor @ ?dup + IF tio.forwards + THEN + + kh-span @ out ! +; + +: KH.BACKSPACE ( -- , backspace character from buffer and screen ) + kh-cursor @ ?dup ( past 0? ) + IF kh-span @ < + IF ( inside line ) + kh-buffer kh-cursor @ + ( -- source ) + dup 1- ( -- source dest ) + kh-span @ kh-cursor @ - cmove +\ ." Deleted!" cr + ELSE + backspace + THEN + -1 kh-span +! + -1 kh-cursor +! + ELSE bell + THEN + kh.refresh +; + +: KH.DELETE ( -- , forward delete ) + kh-cursor @ kh-span @ < ( before end ) + IF ( inside line ) + kh-buffer kh-cursor @ + 1+ ( -- source ) + dup 1- ( -- source dest ) + kh-span @ kh-cursor @ - 0 max cmove + -1 kh-span +! + kh.refresh + THEN +; + +: KH.HANDLE.WINDOWS.KEY ( char -- , handle fkeys or arrows used by Windows ANSI.SYS ) + CASE + $ 8D OF kh.get.match ENDOF + 0 kh-match-span ! ( reset if any other key ) + $ 48 OF kh.get.older ENDOF + $ 50 OF kh.get.newer ENDOF + $ 4D OF kh.go.right ENDOF + $ 4B OF kh.go.left ENDOF + $ 91 OF kh.clear.line ENDOF + $ 74 OF kh.far.right ENDOF + $ 73 OF kh.far.left ENDOF + $ 53 OF kh.delete ENDOF + ENDCASE +; + +: KH.HANDLE.ANSI.KEY ( char -- , handle fkeys or arrows used by ANSI terminal ) + CASE + $ 41 OF kh.get.older ENDOF + $ 42 OF kh.get.newer ENDOF + $ 43 OF kh.go.right ENDOF + $ 44 OF kh.go.left ENDOF + ENDCASE +; + + +: KH.SPECIAL.KEY ( char -- true | false , handle fkeys or arrows, true if handled ) + true >r + CASE + + $ E0 OF key kh.handle.windows.key + ENDOF + + ASCII_ESCAPE OF + key dup $ 4F = \ for TELNET + $ 5B = OR \ for regular ANSI terminals + IF + key kh.handle.ansi.key + ELSE + rdrop false >r + THEN + ENDOF + + ASCII_BACKSPACE OF kh.backspace ENDOF + ASCII_DELETE OF kh.backspace ENDOF + ASCII_CTRL_X OF kh.clear.line ENDOF + ASCII_CTRL_A OF kh.far.left ENDOF + ASCII_CTRL_E OF kh.far.right ENDOF + + rdrop false >r + + ENDCASE + r> +; + +: KH.SMART.KEY ( -- char ) + BEGIN + key dup kh.special.key + WHILE + drop + REPEAT +; + +: KH.INSCHAR { charc | repaint -- } + false -> repaint + kh-cursor @ kh-span @ < + IF +\ Move characters up + kh-buffer kh-cursor @ + ( -- source ) + dup 1+ ( -- source dest ) + kh-span @ kh-cursor @ - cmove> + true -> repaint + THEN +\ write character to buffer + charc kh-buffer kh-cursor @ + c! + 1 kh-cursor +! + 1 kh-span +! + repaint + IF kh.refresh + ELSE charc emit + THEN +; + +: EOL? ( char -- flag , true if an end of line character ) + dup 13 = + swap 10 = OR +; + +: KH.GETLINE ( max -- ) + kh-max ! + kh-span off + kh-cursor off + kh-inside off + kh.rewind + 0 kh-match-span ! + BEGIN + kh-max @ kh-span @ > + IF kh.smart.key + dup EOL? not ( ) + ELSE 0 false + THEN ( -- char flag ) + WHILE ( -- char ) + kh.inschar + REPEAT drop + kh-span @ kh-cursor @ - ?dup + IF tio.forwards ( move to end of line ) + THEN + space + flushemit +; + +: KH.ACCEPT ( addr max -- numChars ) + swap kh-address ! + kh.getline + kh-span @ 0> + IF kh-buffer kh-span @ kh.add.line + THEN + kh-span @ +; + +: TEST.HISTORY + 4 0 DO + pad 128 kh.accept + cr pad swap type cr + LOOP +; + +}private + + +: HISTORY# ( -- , dump history buffer with numbers) + cr kh.oldest.line ?dup + IF + BEGIN kh.current.num 3 .r ." ) " type ?pause cr + kh.forward.line 0= + WHILE kh.current.line + REPEAT + THEN +; + +: HISTORY ( -- , dump history buffer ) + cr kh.oldest.line ?dup + IF + BEGIN type ?pause cr + kh.forward.line 0= + WHILE kh.current.line + REPEAT + THEN +; + +: XX ( line# -- , execute line x of history ) + kh.find.line ?dup + IF count evaluate + THEN +; + + +: HISTORY.RESET ( -- , clear history tables ) + kh-history kh_history_size erase + kh-counter off +; + +: HISTORY.ON ( -- , install history vectors ) + history.reset + what's accept ['] (accept) = + IF ['] kh.accept is accept + THEN +; + +: HISTORY.OFF ( -- , uninstall history vectors ) + what's accept ['] kh.accept = + IF ['] (accept) is accept + THEN +; + + +: AUTO.INIT + auto.init + history.on +; +: AUTO.TERM + history.off + auto.init +; + +if.forgotten history.off + +0 [IF] +history.reset +history.on +[THEN] diff --git a/src/cmd/pforth/fth/loadhist.fth b/src/cmd/pforth/fth/loadhist.fth new file mode 100644 index 0000000..a57f1ba --- /dev/null +++ b/src/cmd/pforth/fth/loadhist.fth @@ -0,0 +1,7 @@ +\ Load history and save new dictionary. +\ This is not part of the standard build because some computers +\ do not support ANSI terminal I/O. + +include? ESC[ termio.fth +include? HISTORY history.fth +c" pforth.dic" save-forth diff --git a/src/cmd/pforth/fth/loadp4th.fth b/src/cmd/pforth/fth/loadp4th.fth new file mode 100644 index 0000000..841fd67 --- /dev/null +++ b/src/cmd/pforth/fth/loadp4th.fth @@ -0,0 +1,46 @@ +\ @(#) loadp4th.fth 98/01/28 1.3 +\ Load various files needed by PForth +\ +\ Author: Phil Burk +\ Copyright 1994 3DO, Phil Burk, Larry Polansky, Devid Rosenboom +\ +\ The pForth software code is dedicated to the public domain, +\ and any third party may reproduce, distribute and modify +\ the pForth software code or any derivative works thereof +\ without any compensation or license. The pForth software +\ code is provided on an "as is" basis without any warranty +\ of any kind, including, without limitation, the implied +\ warranties of merchantability and fitness for a particular +\ purpose and their equivalents under the laws of any jurisdiction. + +include? forget forget.fth +include? >number numberio.fth +include? task-misc1.fth misc1.fth +include? case case.fth +include? $= strings.fth +include? privatize private.fth +include? (local) ansilocs.fth +include? { locals.fth +include? fm/mod math.fth +include? task-misc2.fth misc2.fth +include? [if] condcomp.fth + +\ load floating point support if basic support is in kernel +exists? F* + [IF] include? task-floats.fth floats.fth + [THEN] + +\ useful but optional stuff follows -------------------- + +include? task-member.fth member.fth +include? :struct c_struct.fth +include? smif{ smart_if.fth +include? file? filefind.fth +include? see see.fth +include? words.like wordslik.fth +include? trace trace.fth +include? ESC[ termio.fth +include? HISTORY history.fth +include? SDAD savedicd.fth + +map diff --git a/src/cmd/pforth/fth/locals.fth b/src/cmd/pforth/fth/locals.fth new file mode 100644 index 0000000..fed0cee --- /dev/null +++ b/src/cmd/pforth/fth/locals.fth @@ -0,0 +1,77 @@ +\ @(#) $M$ 98/01/26 1.2 +\ standard { v0 v1 ... vn | l0 l1 .. lm -- } syntax +\ based on ANSI basis words (LOCAL) and TO +\ +\ Author: Phil Burk +\ Copyright 1994 3DO, Phil Burk, Larry Polansky, Devid Rosenboom +\ +\ The pForth software code is dedicated to the public domain, +\ and any third party may reproduce, distribute and modify +\ the pForth software code or any derivative works thereof +\ without any compensation or license. The pForth software +\ code is provided on an "as is" basis without any warranty +\ of any kind, including, without limitation, the implied +\ warranties of merchantability and fitness for a particular +\ purpose and their equivalents under the laws of any jurisdiction. + +\ MOD: PLB 2/11/00 Allow EOL and \ between { }. + +anew task-locals.fth + +private{ +variable loc-temp-mode \ if true, declaring temporary variables +variable loc-comment-mode \ if true, in comment section +variable loc-done +}private + +: { ( -- ) + loc-done off + loc-temp-mode off + loc-comment-mode off + BEGIN + bl word count + dup 0> \ make sure we are not at the end of a line + IF + over c@ + CASE + \ handle special characters + ascii } OF loc-done on 2drop ENDOF + ascii | OF loc-temp-mode on 2drop ENDOF + ascii - OF loc-comment-mode on 2drop ENDOF + ascii ) OF ." { ... ) imbalance!" cr abort ENDOF + ascii \ OF postpone \ 2drop ENDOF \ Forth comment + + \ process name + >r ( save char ) + ( addr len ) + loc-comment-mode @ + IF + 2drop + ELSE + \ if in temporary mode, assign local var = 0 + loc-temp-mode @ + IF compile false + THEN + \ otherwise take value from stack + (local) + THEN + r> + ENDCASE + ELSE + 2drop refill 0= abort" End of input while defining local variables!" + THEN + loc-done @ + UNTIL + 0 0 (local) +; immediate + +privatize + +\ tests +: tlv1 { n -- } n dup n * dup n * ; + +: tlv2 { v1 v2 | l1 l2 -- } + v1 . v2 . cr + v1 v2 + -> l1 + l1 . l2 . cr +; diff --git a/src/cmd/pforth/fth/math.fth b/src/cmd/pforth/fth/math.fth new file mode 100644 index 0000000..e1852e2 --- /dev/null +++ b/src/cmd/pforth/fth/math.fth @@ -0,0 +1,89 @@ +\ @(#) math.fth 98/01/26 1.2 +\ Extended Math routines +\ FM/MOD SM/REM +\ +\ Author: Phil Burk +\ Copyright 1994 3DO, Phil Burk, Larry Polansky, Devid Rosenboom +\ +\ The pForth software code is dedicated to the public domain, +\ and any third party may reproduce, distribute and modify +\ the pForth software code or any derivative works thereof +\ without any compensation or license. The pForth software +\ code is provided on an "as is" basis without any warranty +\ of any kind, including, without limitation, the implied +\ warranties of merchantability and fitness for a particular +\ purpose and their equivalents under the laws of any jurisdiction. + +anew task-math.fth +decimal + +: FM/MOD { dl dh nn | dlp dhp nnp rem quo -- rem quo , floored } + dl dh dabs -> dhp -> dlp + nn abs -> nnp + dlp dhp nnp um/mod -> quo -> rem + dh 0< + IF \ negative dividend + nn 0< + IF \ negative divisor + rem negate -> rem + ELSE \ positive divisor + rem 0= + IF + quo negate -> quo + ELSE + quo 1+ negate -> quo + nnp rem - -> rem + THEN + THEN + ELSE \ positive dividend + nn 0< + IF \ negative divisor + rem 0= + IF + quo negate -> quo + ELSE + nnp rem - negate -> rem + quo 1+ negate -> quo + THEN + THEN + THEN + rem quo +; + +: SM/REM { dl dh nn | dlp dhp nnp rem quo -- rem quo , symmetric } + dl dh dabs -> dhp -> dlp + nn abs -> nnp + dlp dhp nnp um/mod -> quo -> rem + dh 0< + IF \ negative dividend + rem negate -> rem + nn 0> + IF \ positive divisor + quo negate -> quo + THEN + ELSE \ positive dividend + nn 0< + IF \ negative divisor + quo negate -> quo + THEN + THEN + rem quo +; + + +: /MOD ( a b -- rem quo ) + >r s>d r> sm/rem +; + +: MOD ( a b -- rem ) + /mod drop +; + +: */MOD ( a b c -- rem a*b/c , use double precision intermediate value ) + >r m* + r> sm/rem +; +: */ ( a b c -- a*b/c , use double precision intermediate value ) + */mod + nip +; diff --git a/src/cmd/pforth/fth/member.fth b/src/cmd/pforth/fth/member.fth new file mode 100644 index 0000000..6aeb36e --- /dev/null +++ b/src/cmd/pforth/fth/member.fth @@ -0,0 +1,155 @@ +\ @(#) member.fth 98/01/26 1.2 +\ This files, along with c_struct.fth, supports the definition of +\ structure members similar to those used in 'C'. +\ +\ Some of this same code is also used by ODE, +\ the Object Development Environment. +\ +\ Author: Phil Burk +\ Copyright 1994 3DO, Phil Burk, Larry Polansky, Devid Rosenboom +\ +\ The pForth software code is dedicated to the public domain, +\ and any third party may reproduce, distribute and modify +\ the pForth software code or any derivative works thereof +\ without any compensation or license. The pForth software +\ code is provided on an "as is" basis without any warranty +\ of any kind, including, without limitation, the implied +\ warranties of merchantability and fitness for a particular +\ purpose and their equivalents under the laws of any jurisdiction. +\ +\ MOD: PLB 1/16/87 Use abort" instead of er.report. +\ MOD: PLB 2/19/87 Made OB.MEMBER immediate, use literal. +\ MOD: PLB/MDH 6/7/88 Use 16 bit values in member defs. +\ MOD: PLB 7/31/88 Add USHORT and UBYTE. +\ MOD: PLB 1/20/89 Treat LITERAL as state sensitive. +\ MOD: RDG 9/19/90 Add floating point member support. +\ MOD: PLB 6/10/91 Add RPTR +\ 00001 PLB 8/3/92 Make RPTR a -4 for S@ and S! +\ 941102 RDG port to pforth +\ 941108 PLB more porting to pforth. Use ?LITERAL instead os smart literal. +\ 960710 PLB align long members for SUN + +ANEW TASK-MEMBER.FTH +decimal + +: FIND.BODY ( -- , pfa true | $name false , look for word in dict. ) +\ Return address of parameter data. + 32 word find + IF >body true + ELSE false + THEN +; + +\ Variables shared with object oriented code. + VARIABLE OB-STATE ( Compilation state. ) + VARIABLE OB-CURRENT-CLASS ( ABS_CLASS_BASE of current class ) + 1 constant OB_DEF_CLASS ( defining a class ) + 2 constant OB_DEF_STRUCT ( defining a structure ) + +4 constant OB_OFFSET_SIZE + +: OB.OFFSET@ ( member_def -- offset ) @ ; +: OB.OFFSET, ( value -- ) , ; +: OB.SIZE@ ( member_def -- offset ) + ob_offset_size + @ ; +: OB.SIZE, ( value -- ) , ; + +( Members are associated with an offset from the base of a structure. ) +: OB.MAKE.MEMBER ( +-bytes -- , make room in an object at compile time) + dup >r ( -- +-b , save #bytes ) + ABS ( -- |+-b| ) + ob-current-class @ ( -- b addr-space) + tuck @ ( as #b c , current space needed ) + over 3 and 0= ( multiple of four? ) + IF + aligned + ELSE + over 1 and 0= ( multiple of two? ) + IF + even-up + THEN + THEN + swap over + rot ! ( update space needed ) +\ Save data in member definition. %M + ob.offset, ( save old offset for ivar ) + r> ob.size, ( store size in bytes for ..! and ..@ ) +; + +\ Unions allow one to address the same memory as different members. +\ Unions work by saving the current offset for members on +\ the stack and then reusing it for different members. +: UNION{ ( -- offset , Start union definition. ) + ob-current-class @ @ +; + +: }UNION{ ( old-offset -- new-offset , Middle of union ) + union{ ( Get current for }UNION to compare ) + swap ob-current-class @ ! ( Set back to old ) +; + +: }UNION ( offset -- , Terminate union definition, check lengths. ) + union{ = NOT + abort" }UNION - Two parts of UNION are not the same size!" +; + +\ Make members compile their offset, for "disposable includes". +: OB.MEMBER ( #bytes -- , make room in an object at compile time) + ( -- offset , run time for structure ) + CREATE ob.make.member immediate + DOES> ob.offset@ ( get offset ) ?literal +; + +: OB.FINDIT ( -- pfa , get pfa of thing or error ) + find.body not + IF cr count type ." ???" + true abort" OB.FINDIT - Word not found!" + THEN +; + +: OB.STATS ( member_pfa -- offset #bytes ) + dup ob.offset@ swap + ob.size@ +; + +: OB.STATS? ( -- offset #bytes ) + ob.findit ob.stats +; + +: SIZEOF() ( OR -- #bytes , lookup size of object ) + ob.findit @ + ?literal +; immediate + +\ Basic word for defining structure members. +: BYTES ( #bytes -- , error check for structure only ) + ob-state @ ob_def_struct = not + abort" BYTES - Only valid in :STRUCT definitions." + ob.member +; + +\ Declare various types of structure members. +\ Negative size indicates a signed member. +: BYTE ( -- , declare space for a byte ) + -1 bytes ; + +: SHORT ( -- , declare space for a 16 bit value ) + -2 bytes ; + +: LONG ( -- ) + cell bytes ; + +: UBYTE ( -- , declare space for signed byte ) + 1 bytes ; + +: USHORT ( -- , declare space for signed 16 bit value ) + 2 bytes ; + + +\ Aliases +: APTR ( -- ) long ; +: RPTR ( -- ) -4 bytes ; \ relative relocatable pointer 00001 +: ULONG ( -- ) long ; + +: STRUCT ( -- , define a structure as an ivar ) + [compile] sizeof() bytes +; diff --git a/src/cmd/pforth/fth/misc1.fth b/src/cmd/pforth/fth/misc1.fth new file mode 100644 index 0000000..f5b11c7 --- /dev/null +++ b/src/cmd/pforth/fth/misc1.fth @@ -0,0 +1,175 @@ +\ @(#) misc1.fth 98/01/26 1.2 +\ miscellaneous words +\ +\ Author: Phil Burk +\ Copyright 1994 3DO, Phil Burk, Larry Polansky, Devid Rosenboom +\ +\ The pForth software code is dedicated to the public domain, +\ and any third party may reproduce, distribute and modify +\ the pForth software code or any derivative works thereof +\ without any compensation or license. The pForth software +\ code is provided on an "as is" basis without any warranty +\ of any kind, including, without limitation, the implied +\ warranties of merchantability and fitness for a particular +\ purpose and their equivalents under the laws of any jurisdiction. + +anew task-misc1.fth +decimal + +: >> rshift ; +: << lshift ; + +: (WARNING") ( flag $message -- ) + swap + IF count type + ELSE drop + THEN +; + +: WARNING" ( flag -- , print warning if true. ) + [compile] " ( compile message ) + state @ + IF compile (warning") + ELSE (warning") + THEN +; IMMEDIATE + +: (ABORT") ( flag $message -- ) + swap + IF count type cr abort + ELSE drop + THEN +; + +: ABORT" ( flag -- , print warning if true. ) + [compile] " ( compile message ) + state @ + IF compile (abort") + ELSE (abort") + THEN +; IMMEDIATE + + +: ?PAUSE ( -- , Pause if key hit. ) + ?terminal + IF key drop cr ." Hit space to continue, any other key to abort:" + key dup emit BL = not abort" Terminated" + THEN +; + +60 constant #cols + +: CR? ( -- , do CR if near end ) + OUT @ #cols 16 - 10 max > + IF cr + THEN +; + +: CLS ( -- clear screen ) + 40 0 do cr loop +; +: PAGE ( -- , clear screen, compatible with Brodie ) + cls +; + +: $ ( -- N , convert next number as hex ) + base @ hex + 32 lword number? num_type_single = not + abort" Not a single number!" + swap base ! + state @ + IF [compile] literal + THEN +; immediate + +: .HX ( nibble -- ) + dup 9 > + IF $ 37 + ELSE $ 30 + THEN + emit +; + +variable TAB-WIDTH 8 TAB-WIDTH ! +: TAB ( -- , tab over to next stop ) + out @ tab-width @ mod + tab-width @ swap - spaces +; + +\ Vocabulary listing +: WORDS ( -- ) + 0 latest + BEGIN dup 0<> + WHILE dup id. tab cr? ?pause + prevname + swap 1+ swap + REPEAT drop + cr . ." words" cr +; + +: VLIST words ; + +variable CLOSEST-NFA +variable CLOSEST-XT + +: >NAME ( xt -- nfa , scans dictionary for closest nfa, SLOW! ) + 0 closest-nfa ! + 0 closest-xt ! + latest + BEGIN dup 0<> + IF ( -- addr nfa ) 2dup name> ( addr nfa addr xt ) < + IF true ( addr below this cfa, can't be it) + ELSE ( -- addr nfa ) + 2dup name> ( addr nfa addr xt ) = + IF ( found it ! ) dup closest-nfa ! false + ELSE dup name> closest-xt @ > + IF dup closest-nfa ! dup name> closest-xt ! + THEN + true + THEN + THEN + ELSE false + THEN + WHILE + prevname + REPEAT ( -- cfa nfa ) + 2drop + closest-nfa @ +; + +: @EXECUTE ( addr -- , execute if non-zero ) + x@ ?dup + IF execute + THEN +; + +: TOLOWER ( char -- char_lower ) + dup ascii [ < + IF dup ascii @ > + IF ascii A - ascii a + + THEN + THEN +; + +: EVALUATE ( i*x c-addr num -- j*x , evaluate string of Forth ) +\ save current input state and switch to passed in string + source >r >r + set-source + -1 push-source-id + >in @ >r + 0 >in ! +\ interpret the string + interpret +\ restore input state + pop-source-id drop + r> >in ! + r> r> set-source +; + +: \S ( -- , comment out rest of file ) + source-id + IF + BEGIN \ using REFILL is safer than popping SOURCE-ID + refill 0= + UNTIL + THEN +; diff --git a/src/cmd/pforth/fth/misc2.fth b/src/cmd/pforth/fth/misc2.fth new file mode 100644 index 0000000..6c9af91 --- /dev/null +++ b/src/cmd/pforth/fth/misc2.fth @@ -0,0 +1,235 @@ +\ @(#) misc2.fth 98/01/26 1.2 +\ Utilities for PForth extracted from HMSL +\ +\ Author: Phil Burk +\ Copyright 1994 3DO, Phil Burk, Larry Polansky, Devid Rosenboom +\ +\ The pForth software code is dedicated to the public domain, +\ and any third party may reproduce, distribute and modify +\ the pForth software code or any derivative works thereof +\ without any compensation or license. The pForth software +\ code is provided on an "as is" basis without any warranty +\ of any kind, including, without limitation, the implied +\ warranties of merchantability and fitness for a particular +\ purpose and their equivalents under the laws of any jurisdiction. +\ +\ 00001 9/14/92 Added call, 'c w->s +\ 00002 11/23/92 Moved redef of : to loadcom.fth + +anew task-misc2.fth + +: 'N ( -- , make 'n state smart ) + bl word find + IF + state @ + IF namebase - ( make nfa relocatable ) + [compile] literal ( store nfa of word to be compiled ) + compile namebase+ + THEN + THEN +; IMMEDIATE + +: ?LITERAL ( n -- , do literal if compiling ) + state @ + IF [compile] literal + THEN +; + +: 'c ( -- xt , state sensitive ' ) + ' ?literal +; immediate + +variable if-debug + +decimal +create msec-delay 10000 , ( default for SUN ) +: (MSEC) ( #msecs -- ) + 0 + do msec-delay @ 0 + do loop + loop +; + +defer msec +' (msec) is msec + +: SHIFT ( val n -- val< + if swap + then +; + +\ sort top two items on stack. +: -2sort ( a b -- a>b | b>a , smallest on top of stack) + 2dup < + if swap + then +; + +: barray ( #bytes -- ) ( index -- addr ) + create allot + does> + +; + +: warray ( #words -- ) ( index -- addr ) + create 2* allot + does> swap 2* + +; + +: array ( #cells -- ) ( index -- addr ) + create cell* allot + does> swap cell* + +; + +: .bin ( n -- , print in binary ) + base @ binary swap . base ! +; +: .dec ( n -- ) + base @ decimal swap . base ! +; +: .hex ( n -- ) + base @ hex swap . base ! +; + +: B->S ( c -- c' , sign extend byte ) + dup $ 80 and + IF + $ FFFFFF00 or + ELSE + $ 000000FF and + THEN +; +: W->S ( 16bit-signed -- 32bit-signed ) + dup $ 8000 and + if + $ FFFF0000 or + ELSE + $ 0000FFFF and + then +; + +: WITHIN { n1 n2 n3 -- flag } + n2 n3 <= + IF + n2 n1 <= + n1 n3 < AND + ELSE + n2 n1 <= + n1 n3 < OR + THEN +; + +: MOVE ( src dst num -- ) + >r 2dup - 0< + IF + r> CMOVE> + ELSE + r> CMOVE + THEN +; + +: ERASE ( caddr num -- ) + dup 0> + IF + 0 fill + ELSE + 2drop + THEN +; + +: BLANK ( addr u -- , set memory to blank ) + DUP 0> + IF + BL FILL + ELSE + 2DROP + THEN +; + +\ Obsolete but included for CORE EXT word set. +: QUERY REFILL DROP ; +VARIABLE SPAN +: EXPECT accept span ! ; +: TIB source drop ; + + +: UNUSED ( -- unused , dictionary space ) + CODELIMIT HERE - +; + +: MAP ( -- , dump interesting dictionary info ) + ." Code Segment" cr + ." CODEBASE = " codebase .hex cr + ." HERE = " here .hex cr + ." CODELIMIT = " codelimit .hex cr + ." Compiled Code Size = " here codebase - . cr + ." CODE-SIZE = " code-size @ . cr + ." Code Room UNUSED = " UNUSED . cr + ." Name Segment" cr + ." NAMEBASE = " namebase .hex cr + ." HEADERS-PTR @ = " headers-ptr @ .hex cr + ." NAMELIMIT = " namelimit .hex cr + ." CONTEXT @ = " context @ .hex cr + ." LATEST = " latest .hex ." = " latest id. cr + ." Compiled Name size = " headers-ptr @ namebase - . cr + ." HEADERS-SIZE = " headers-size @ . cr + ." Name Room Left = " namelimit headers-ptr @ - . cr +; + + +\ Search for substring S2 in S1 +: SEARCH { addr1 cnt1 addr2 cnt2 | addr3 cnt3 flag -- addr3 cnt3 flag } +\ ." Search for " addr2 cnt2 type ." in " addr1 cnt1 type cr +\ if true, s1 contains s2 at addr3 with cnt3 chars remaining +\ if false, s3 = s1 + addr1 -> addr3 + cnt1 -> cnt3 + cnt1 cnt2 < not + IF + cnt1 cnt2 - 1+ 0 + DO + true -> flag + cnt2 0 + ?DO + addr2 i chars + c@ + addr1 i j + chars + c@ <> \ mismatch? + IF + false -> flag + LEAVE + THEN + LOOP + flag + IF + addr1 i chars + -> addr3 + cnt1 i - -> cnt3 + LEAVE + THEN + LOOP + THEN + addr3 cnt3 flag +; + diff --git a/src/cmd/pforth/fth/numberio.fth b/src/cmd/pforth/fth/numberio.fth new file mode 100644 index 0000000..4fc4c62 --- /dev/null +++ b/src/cmd/pforth/fth/numberio.fth @@ -0,0 +1,204 @@ +\ @(#) numberio.fth 98/01/26 1.2 +\ numberio.fth +\ +\ numeric conversion +\ +\ Author: Phil Burk +\ Copyright 1994 3DO, Phil Burk, Larry Polansky, Devid Rosenboom +\ +\ The pForth software code is dedicated to the public domain, +\ and any third party may reproduce, distribute and modify +\ the pForth software code or any derivative works thereof +\ without any compensation or license. The pForth software +\ code is provided on an "as is" basis without any warranty +\ of any kind, including, without limitation, the implied +\ warranties of merchantability and fitness for a particular +\ purpose and their equivalents under the laws of any jurisdiction. + +anew task-numberio.fth +decimal + +\ ------------------------ INPUT ------------------------------- +\ Convert a single character to a number in the given base. +: DIGIT ( char base -- n true | char false ) + >r +\ convert lower to upper + dup ascii a < not + IF + ascii a - ascii A + + THEN +\ + dup dup ascii A 1- > + IF ascii A - ascii 9 + 1+ + ELSE ( char char ) + dup ascii 9 > + IF + ( between 9 and A is bad ) + drop 0 ( trigger error below ) + THEN + THEN + ascii 0 - + dup r> < + IF dup 1+ 0> + IF nip true + ELSE drop FALSE + THEN + ELSE drop FALSE + THEN +; + +: >NUMBER ( ud1 c-addr1 u1 -- ud2 c-addr2 u2 , convert till bad char , CORE ) + >r + BEGIN + r@ 0> \ any characters left? + IF + dup c@ base @ + digit ( ud1 c-addr , n true | char false ) + IF + TRUE + ELSE + drop FALSE + THEN + ELSE + false + THEN + WHILE ( -- ud1 c-addr n ) + swap >r ( -- ud1lo ud1hi n ) + swap base @ ( -- ud1lo n ud1hi base ) + um* drop ( -- ud1lo n ud1hi*baselo ) + rot base @ ( -- n ud1hi*baselo ud1lo base ) + um* ( -- n ud1hi*baselo ud1lo*basello ud1lo*baselhi ) + d+ ( -- ud2 ) + r> 1+ \ increment char* + r> 1- >r \ decrement count + REPEAT + r> +; + +\ obsolete +: CONVERT ( ud1 c-addr1 -- ud2 c-addr2 , convert till bad char , CORE EXT ) + 256 >NUMBER DROP +; + +0 constant NUM_TYPE_BAD +1 constant NUM_TYPE_SINGLE +2 constant NUM_TYPE_DOUBLE + +\ This is similar to the F83 NUMBER? except that it returns a number type +\ and then either a single or double precision number. +: ((NUMBER?)) ( c-addr u -- 0 | n 1 | d 2 , convert string to number ) + dup 0= IF 2drop NUM_TYPE_BAD exit THEN \ any chars? + +\ prepare for >number + 0 0 2swap ( 0 0 c-addr cnt ) + +\ check for '-' at beginning, skip if present + over c@ ascii - = \ is it a '-' + dup >r \ save flag + IF 1- >r 1+ r> ( -- 0 0 c-addr+1 cnt-1 , skip past minus sign ) + THEN +\ + >number dup 0= \ convert as much as we can + IF + 2drop \ drop addr cnt + drop \ drop hi part of num + r@ \ check flag to see if '-' sign used + IF negate + THEN + NUM_TYPE_SINGLE + ELSE ( -- d addr cnt ) + 1 = swap \ if final character is '.' then double + c@ ascii . = AND + IF + r@ \ check flag to see if '-' sign used + IF dnegate + THEN + NUM_TYPE_DOUBLE + ELSE + 2drop + NUM_TYPE_BAD + THEN + THEN + rdrop +; + +: (NUMBER?) ( $addr -- 0 | n 1 | d 2 , convert string to number ) + count ((number?)) +; + +' (number?) is number? +\ hex +\ 0sp c" xyz" (number?) .s +\ 0sp c" 234" (number?) .s +\ 0sp c" -234" (number?) .s +\ 0sp c" 234." (number?) .s +\ 0sp c" -234." (number?) .s +\ 0sp c" 1234567855554444." (number?) .s + + +\ ------------------------ OUTPUT ------------------------------ +\ Number output based on F83 +variable HLD \ points to last character added + +: hold ( char -- , add character to text representation) + -1 hld +! + hld @ c! +; +: <# ( -- , setup conversion ) + pad hld ! +; +: #> ( d -- addr len , finish conversion ) + 2drop hld @ pad over - +; +: sign ( n -- , add '-' if negative ) + 0< if ascii - hold then +; +: # ( d -- d , convert one digit ) + base @ mu/mod rot 9 over < + IF 7 + + THEN + ascii 0 + hold +; +: #s ( d -- d , convert remaining digits ) + BEGIN # 2dup or 0= + UNTIL +; + + +: (UD.) ( ud -- c-addr cnt ) + <# #s #> +; +: UD. ( ud -- , print unsigned double number ) + (ud.) type space +; +: UD.R ( ud n -- ) + >r (ud.) r> over - spaces type +; +: (D.) ( d -- c-addr cnt ) + tuck dabs <# #s rot sign #> +; +: D. ( d -- ) + (d.) type space +; +: D.R ( d n -- , right justified ) + >r (d.) r> over - spaces type +; + +: (U.) ( u -- c-addr cnt ) + 0 (ud.) +; +: U. ( u -- , print unsigned number ) + 0 ud. +; +: U.R ( u n -- , print right justified ) + >r (u.) r> over - spaces type +; +: (.) ( n -- c-addr cnt ) + dup abs 0 <# #s rot sign #> +; +: . ( n -- , print signed number) + (.) type space +; +: .R ( n l -- , print right justified) + >r (.) r> over - spaces type +; diff --git a/src/cmd/pforth/fth/private.fth b/src/cmd/pforth/fth/private.fth new file mode 100644 index 0000000..0f843f8 --- /dev/null +++ b/src/cmd/pforth/fth/private.fth @@ -0,0 +1,48 @@ +\ @(#) private.fth 98/01/26 1.2 +\ PRIVATIZE +\ +\ Privatize words that are only needed within the file +\ and do not need to be exported. +\ +\ Usage: +\ PRIVATE{ +\ : FOO ; \ Everything between PRIVATE{ and }PRIVATE will become private. +\ : MOO ; +\ }PRIVATE +\ : GOO foo moo ; \ can use foo and moo +\ PRIVATIZE \ smudge foo and moo +\ ' foo \ will fail +\ +\ Copyright 1996 Phil Burk +\ +\ 19970701 PLB Use unsigned compares for machines with "negative" addresses. + +anew task-private.fth + +variable private-start +variable private-stop +$ 20 constant FLAG_SMUDGE + +: PRIVATE{ + latest private-start ! + 0 private-stop ! +; +: }PRIVATE + private-stop @ 0= not abort" Extra }PRIVATE" + latest private-stop ! +; +: PRIVATIZE ( -- , smudge all words between PRIVATE{ and }PRIVATE ) + private-start @ 0= abort" Missing PRIVATE{" + private-stop @ 0= abort" Missing }PRIVATE" + private-stop @ + BEGIN + dup private-start @ u> \ 19970701 + WHILE +\ ." Smudge " dup id. cr + dup c@ flag_smudge or over c! + prevname + REPEAT + drop + 0 private-start ! + 0 private-stop ! +; diff --git a/src/cmd/pforth/fth/savedicd.fth b/src/cmd/pforth/fth/savedicd.fth new file mode 100644 index 0000000..1c79fcf --- /dev/null +++ b/src/cmd/pforth/fth/savedicd.fth @@ -0,0 +1,177 @@ +\ @(#) savedicd.fth 98/01/26 1.2 +\ Save dictionary as data table. +\ +\ Author: Phil Burk +\ Copyright 1987 Phil Burk +\ All Rights Reserved. +\ +\ 970311 PLB Fixed problem with calling SDAD when in HEX mode. +\ 20010606 PLB Fixed AUTO.INIT , started with ';' !! + +decimal +ANEW TASK-SAVE_DIC_AS_DATA + +\ !!! set to 4 for minimally sized dictionary to prevent DIAB +\ compiler from crashing! Allocate more space in pForth. +4 constant SDAD_NAMES_EXTRA \ space for additional names +4 constant SDAD_CODE_EXTRA \ space for additional names + +\ buffer the file I/O for better performance +256 constant SDAD_BUFFER_SIZE +create SDAD-BUFFER SDAD_BUFFER_SIZE allot +variable SDAD-BUFFER-INDEX +variable SDAD-BUFFER-FID + 0 SDAD-BUFFER-FID ! + +: SDAD.FLUSH ( -- ior ) + sdad-buffer sdad-buffer-index @ \ data +\ 2dup type + sdad-buffer-fid @ write-file + 0 sdad-buffer-index ! +; + +: SDAD.EMIT ( char -- ) + sdad-buffer-index @ sdad_buffer_size >= + IF + sdad.flush abort" SDAD.FLUSH failed!" + THEN +\ + sdad-buffer sdad-buffer-index @ + c! + 1 sdad-buffer-index +! +; + +: SDAD.TYPE ( c-addr cnt -- ) + 0 DO + dup c@ sdad.emit \ char to buffer + 1+ \ advance char pointer + LOOP + drop +; + +: $SDAD.LINE ( $addr -- ) + count sdad.type + EOL sdad.emit +; + +: (U8.) ( u -- a l , unsigned conversion, at least 8 digits ) + 0 <# # # # # # # # #S #> +; +: (U2.) ( u -- a l , unsigned conversion, at least 2 digits ) + 0 <# # #S #> +; + +: SDAD.CLOSE ( -- ) + SDAD-BUFFER-FID @ ?dup + IF + sdad.flush abort" SDAD.FLUSH failed!" + close-file drop + 0 SDAD-BUFFER-FID ! + THEN +; + +: SDAD.OPEN ( -- ior, open file ) + sdad.close + s" pfdicdat.h" r/w create-file dup >r + IF + drop ." Could not create file pfdicdat.h" cr + ELSE + SDAD-BUFFER-FID ! + THEN + r> +; + +: SDAD.DUMP.HEX { val -- } + base @ >r hex + s" 0x" sdad.type + val (u8.) sdad.type + r> base ! +; +: SDAD.DUMP.HEX, + s" " sdad.type + sdad.dump.hex + ascii , sdad.emit +; + +: SDAD.DUMP.HEX.BYTE { val -- } + base @ >r hex + s" 0x" sdad.type + val (u2.) sdad.type + r> base ! +; +: SDAD.DUMP.HEX.BYTE, + sdad.dump.hex.byte + ascii , sdad.emit +; + +: SDAD.DUMP.DATA { start-address end-address num-zeros | num-bytes -- } + end-address start-address - -> num-bytes + num-bytes 0 + ?DO + i $ 7FF and 0= IF ." 0x" i .hex cr THEN \ progress report + i 15 and 0= + IF + + EOL sdad.emit + s" /* " sdad.type + i sdad.dump.hex + s" : */ " sdad.type + THEN \ 16 bytes per line, print offset + start-address i + c@ + sdad.dump.hex.byte, + LOOP +\ + num-zeros 0 + ?DO + i $ 7FF and 0= IF i . cr THEN \ progress report + i 15 and 0= IF EOL sdad.emit THEN \ 15 numbers per line + 0 sdad.dump.hex.byte, + LOOP +; + +: SDAD.DEFINE { $name val -- } + s" #define " sdad.type + $name count sdad.type + s" (" sdad.type + val sdad.dump.hex + c" )" $sdad.line +; + +: IS.LITTLE.ENDIAN? ( -- flag , is Forth in Little Endian mode? ) + 1 pad ! + pad c@ +; + +: SDAD { | fid -- } + sdad.open abort" sdad.open failed!" +\ Write headers. + c" /* This file generated by the Forth command SDAD */" $sdad.line + + c" HEADERPTR" headers-ptr @ namebase - sdad.define + c" RELCONTEXT" context @ namebase - sdad.define + c" CODEPTR" here codebase - sdad.define + c" IF_LITTLE_ENDIAN" IS.LITTLE.ENDIAN? IF 1 ELSE 0 THEN sdad.define + +." Saving Names" cr + s" static const uint8_t MinDicNames[] = {" sdad.type + namebase headers-ptr @ SDAD_NAMES_EXTRA sdad.dump.data + EOL sdad.emit + c" };" $sdad.line + +." Saving Code" cr + s" static const uint8_t MinDicCode[] = {" sdad.type + codebase here SDAD_CODE_EXTRA sdad.dump.data + EOL sdad.emit + c" };" $sdad.line + + sdad.close +; + +if.forgotten sdad.close + +: AUTO.INIT ( -- , init at launch ) + auto.init \ daisy chain initialization + 0 SDAD-BUFFER-FID ! + 0 SDAD-BUFFER-INDEX ! +; + +." Enter: SDAD" cr diff --git a/src/cmd/pforth/fth/see.fth b/src/cmd/pforth/fth/see.fth new file mode 100644 index 0000000..9d866ad --- /dev/null +++ b/src/cmd/pforth/fth/see.fth @@ -0,0 +1,218 @@ +\ @(#) see.fth 98/01/26 1.4 +\ SEE ( -- , disassemble pForth word ) +\ +\ Copyright 1996 Phil Burk + +' file? >code rfence a! + +anew task-see.fth + +: .XT ( xt -- , print execution tokens name ) + >name + dup c@ flag_immediate and + IF + ." POSTPONE " + THEN + id. space +; + +\ dictionary may be defined as byte code or cell code +0 constant BYTE_CODE + +BYTE_CODE [IF] + : CODE@ ( addr -- xt , fetch from code space ) C@ ; + 1 constant CODE_CELL + .( BYTE_CODE not implemented) abort +[ELSE] + : CODE@ ( addr -- xt , fetch from code space ) @ ; + CELL constant CODE_CELL +[THEN] + +private{ + +0 value see_level \ level of conditional imdentation +0 value see_addr \ address of next token +0 value see_out + +: SEE.INDENT.BY ( -- n ) + see_level 1+ 1 max 4 * +; + +: SEE.CR + >newline + see_addr ." ( ".hex ." )" + see.indent.by spaces + 0 -> see_out +; +: SEE.NEWLINE + see_out 0> + IF see.cr + THEN +; +: SEE.CR? + see_out 6 > + IF + see.newline + THEN +; +: SEE.OUT+ + 1 +-> see_out +; + +: SEE.ADVANCE + code_cell +-> see_addr +; +: SEE.GET.INLINE ( -- n ) + see_addr @ +; + +: SEE.GET.TARGET ( -- branch-target-addr ) + see_addr @ see_addr + +; + +: SEE.SHOW.LIT ( -- ) + see.get.inline . + see.advance + see.out+ +; + +exists? F* [IF] +: SEE.SHOW.FLIT ( -- ) + see_addr f@ f. + 1 floats +-> see_addr + see.out+ +; +[THEN] + +: SEE.SHOW.ALIT ( -- ) + see.get.inline >name id. space + see.advance + see.out+ +; + +: SEE.SHOW.STRING ( -- ) + see_addr count 2dup + aligned -> see_addr type + see.out+ +; +: SEE.SHOW.TARGET ( -- ) + see.get.target .hex see.advance +; + +: SEE.BRANCH ( -- addr | , handle branch ) + -1 +-> see_level + see.newline + see.get.inline 0> + IF \ forward branch + ." ELSE " + see.get.target \ calculate address of target + 1 +-> see_level + nip \ remove old address for THEN + ELSE + ." REPEAT " see.get.target .hex + drop \ remove old address for THEN + THEN + see.advance + see.cr +; + +: SEE.0BRANCH ( -- addr | , handle 0branch ) + see.newline + see.get.inline 0> + IF \ forward branch + ." IF or WHILE " + see.get.target \ calculate adress of target + 1 +-> see_level + ELSE + ." UNTIL=>" see.get.target .hex + THEN + see.advance + see.cr +; + +: SEE.XT { xt -- } + xt + CASE + 0 OF see_level 0> IF ." EXIT " see.out+ ELSE ." ;" 0 -> see_addr THEN ENDOF + ['] (LITERAL) OF see.show.lit ENDOF + ['] (ALITERAL) OF see.show.alit ENDOF +[ exists? (FLITERAL) [IF] ] + ['] (FLITERAL) OF see.show.flit ENDOF +[ [THEN] ] + ['] BRANCH OF see.branch ENDOF + ['] 0BRANCH OF see.0branch ENDOF + ['] (LOOP) OF -1 +-> see_level see.newline ." LOOP " see.advance see.cr ENDOF + ['] (+LOOP) OF -1 +-> see_level see.newline ." +LOOP" see.advance see.cr ENDOF + ['] (DO) OF see.newline ." DO" 1 +-> see_level see.cr ENDOF + ['] (?DO) OF see.newline ." ?DO " see.advance 1 +-> see_level see.cr ENDOF + ['] (.") OF .' ." ' see.show.string .' " ' ENDOF + ['] (C") OF .' C" ' see.show.string .' " ' ENDOF + ['] (S") OF .' S" ' see.show.string .' " ' ENDOF + + see.cr? xt .xt see.out+ + ENDCASE +; + +: (SEE) { cfa | xt -- } + 0 -> see_level + cfa -> see_addr + see.cr + 0 \ fake address for THEN handler + BEGIN + see_addr code@ -> xt + BEGIN + dup see_addr ( >newline .s ) = + WHILE + -1 +-> see_level see.newline + ." THEN " see.cr + drop + REPEAT + CODE_CELL +-> see_addr + xt see.xt + see_addr 0= + UNTIL + cr + 0= not abort" SEE conditional analyser nesting failed!" +; + +}PRIVATE + +: SEE ( -- , disassemble ) + ' + dup ['] FIRST_COLON > + IF + >code (see) + ELSE + >name id. + ." is primitive defined in 'C' kernel." cr + THEN +; + +PRIVATIZE + +0 [IF] + +: SEE.JOKE + dup swap drop +; + +: SEE.IF + IF + ." hello" cr + ELSE + ." bye" cr + THEN + see.joke +; +: SEE.DO + 4 0 + DO + i . cr + LOOP +; +: SEE." + ." Here are some strings." cr + c" Forth string." count type cr + s" Addr/Cnt string" type cr +; + +[THEN] diff --git a/src/cmd/pforth/fth/siev.fth b/src/cmd/pforth/fth/siev.fth new file mode 100644 index 0000000..579bf91 --- /dev/null +++ b/src/cmd/pforth/fth/siev.fth @@ -0,0 +1,31 @@ +\ #! /usr/stud/paysan/bin/forth + +DECIMAL +\ : SECS TIME&DATE SWAP 60 * + SWAP 3600 * + NIP NIP NIP ; +CREATE FLAGS 8190 ALLOT +variable eflag +\ FLAGS 8190 + CONSTANT EFLAG + +\ use secondary fill like pForth !!! +: FILL { caddr num charval -- } + num 0 + ?DO + charval caddr i + c! + LOOP +; + +: PRIMES ( -- n ) FLAGS 8190 1 FILL 0 3 EFLAG @ FLAGS + DO I C@ + IF DUP I + DUP EFLAG @ < + IF EFLAG @ SWAP + DO 0 I C! DUP +LOOP + ELSE DROP THEN SWAP 1+ SWAP + THEN 2 + + LOOP DROP ; + +: BENCHMARK 0 100 0 DO PRIMES NIP LOOP ; \ !!! ONLY 100 +\ SECS BENCHMARK . SECS SWAP - CR . .( secs) +: main + flags 8190 + eflag ! + benchmark ( . ) drop +; diff --git a/src/cmd/pforth/fth/smart_if.fth b/src/cmd/pforth/fth/smart_if.fth new file mode 100644 index 0000000..17c1b61 --- /dev/null +++ b/src/cmd/pforth/fth/smart_if.fth @@ -0,0 +1,57 @@ +\ @(#) smart_if.fth 98/01/26 1.2 +\ Smart Conditionals +\ Allow use of if, do, begin, etc.outside of colon definitions. +\ +\ Thanks to Mitch Bradley for the idea. +\ +\ Author: Phil Burk +\ Copyright 1994 3DO, Phil Burk, Larry Polansky, Devid Rosenboom +\ +\ The pForth software code is dedicated to the public domain, +\ and any third party may reproduce, distribute and modify +\ the pForth software code or any derivative works thereof +\ without any compensation or license. The pForth software +\ code is provided on an "as is" basis without any warranty +\ of any kind, including, without limitation, the implied +\ warranties of merchantability and fitness for a particular +\ purpose and their equivalents under the laws of any jurisdiction. + +anew task-smart_if.fth + +variable SMIF-XT \ execution token for conditional code +variable SMIF-DEPTH \ depth of nested conditionals + +: SMIF{ ( -- , if executing, start compiling, setup depth ) + state @ 0= + IF + :noname smif-xt ! + 1 smif-depth ! + ELSE + 1 smif-depth +! + THEN +; + +: }SMIF ( -- , unnest, stop compiling, execute code and forget ) + smif-xt @ + IF + -1 smif-depth +! + smif-depth @ 0 <= + IF + postpone ; \ stop compiling + smif-xt @ execute \ execute conditional code + smif-xt @ >code dp ! \ forget conditional code + 0 smif-xt ! \ clear so we don't mess up later + THEN + THEN +; + +\ redefine conditionals to use smart mode +: IF smif{ postpone if ; immediate +: DO smif{ postpone do ; immediate +: ?DO smif{ postpone ?do ; immediate +: BEGIN smif{ postpone begin ; immediate +: THEN postpone then }smif ; immediate +: REPEAT postpone repeat }smif ; immediate +: UNTIL postpone until }smif ; immediate +: LOOP postpone loop }smif ; immediate +: +LOOP postpone +loop }smif ; immediate diff --git a/src/cmd/pforth/fth/strings.fth b/src/cmd/pforth/fth/strings.fth new file mode 100644 index 0000000..7f0bb4e --- /dev/null +++ b/src/cmd/pforth/fth/strings.fth @@ -0,0 +1,97 @@ +\ @(#) strings.fth 98/01/26 1.2 +\ String support for PForth +\ +\ Copyright Phil Burk 1994 + +ANEW TASK-STRINGS.FTH + +: -TRAILING ( c-addr u1 -- c-addr u2 , strip trailing blanks ) + dup 0> + IF + BEGIN + 2dup 1- chars + c@ bl = + over 0> and + WHILE + 1- + REPEAT + THEN +; + +\ Structure of string table +: $ARRAY ( ) + CREATE ( #strings #chars_max -- ) + dup , + 2+ * even-up allot + DOES> ( index -- $addr ) + dup @ ( get #chars ) + rot * + cell+ +; + +\ Compare two strings +: $= ( $1 $2 -- flag , true if equal ) + -1 -rot + dup c@ 1+ 0 + DO dup c@ tolower + 2 pick c@ tolower - + IF rot drop 0 -rot LEAVE + THEN + 1+ swap 1+ swap + LOOP 2drop +; + +: TEXT= ( addr1 addr2 count -- flag ) + >r -1 -rot + r> 0 + DO dup c@ tolower + 2 pick c@ tolower - + IF rot drop 0 -rot LEAVE + THEN + 1+ swap 1+ swap + LOOP 2drop +; + +: TEXT=? ( addr1 count addr2 -- flag , for JForth compatibility ) + swap text= +; + +: $MATCH? ( $string1 $string2 -- flag , case INsensitive ) + dup c@ 1+ text= +; + + +: INDEX ( $string char -- false | address_char true , search for char in string ) + >r >r 0 r> r> + over c@ 1+ 1 + DO over i + c@ over = + IF rot drop + over i + rot rot LEAVE + THEN + LOOP 2drop + ?dup 0= 0= +; + + +: $APPEND.CHAR ( $string char -- ) \ ugly stack diagram + over count chars + c! + dup c@ 1+ swap c! +; + +\ ---------------------------------------------- +: ($ROM) ( index address -- $string ) + ( -- index address ) + swap 0 + DO dup c@ 1+ + aligned + LOOP +; + +: $ROM ( packed array of strings, unalterable ) + CREATE ( -- ) + DOES> ( index -- $string ) ($rom) +; + +: TEXTROM ( packed array of strings, unalterable ) + CREATE ( -- ) + DOES> ( index -- address count ) ($rom) count +; + +\ ----------------------------------------------- diff --git a/src/cmd/pforth/fth/system.fth b/src/cmd/pforth/fth/system.fth new file mode 100644 index 0000000..9370690 --- /dev/null +++ b/src/cmd/pforth/fth/system.fth @@ -0,0 +1,825 @@ +: FIRST_COLON ; + +: LATEST context @ ; + +: FLAG_IMMEDIATE 64 ; + +: IMMEDIATE + latest dup c@ flag_immediate OR + swap c! +; + +: ( 41 word drop ; immediate +( That was the definition for the comment word. ) +( Now we can add comments to what we are doing! ) +( Note that we are in decimal numeric input mode. ) + +: \ ( -- , comment out rest of line ) + EOL word drop +; immediate + +\ 1 echo ! \ Uncomment this line to echo Forth code while compiling. + +\ ********************************************************************* +\ This is another style of comment that is common in Forth. +\ pFORTH - Portable Forth System +\ Based on HMSL Forth +\ +\ Author: Phil Burk +\ Copyright 1994 3DO, Phil Burk, Larry Polansky, Devid Rosenboom +\ +\ The pForth software code is dedicated to the public domain, +\ and any third party may reproduce, distribute and modify +\ the pForth software code or any derivative works thereof +\ without any compensation or license. The pForth software +\ code is provided on an "as is" basis without any warranty +\ of any kind, including, without limitation, the implied +\ warranties of merchantability and fitness for a particular +\ purpose and their equivalents under the laws of any jurisdiction. +\ ********************************************************************* + +: COUNT dup 1+ swap c@ ; + +\ Miscellaneous support words +: ON ( addr -- , set true ) + -1 swap ! +; +: OFF ( addr -- , set false ) + 0 swap ! +; + +: CELL+ ( n -- n+cell ) cell + ; +: CELL- ( n -- n+cell ) cell - ; +: CELL* ( n -- n*cell ) cells ; + +: CHAR+ ( n -- n+size_of_char ) 1+ ; +: CHARS ( n -- n*size_of_char , don't do anything) ; immediate + +\ useful stack manipulation words +: -ROT ( a b c -- c a b ) + rot rot +; +: 3DUP ( a b c -- a b c a b c ) + 2 pick 2 pick 2 pick +; +: 2DROP ( a b -- ) + drop drop +; +: NIP ( a b -- b ) + swap drop +; +: TUCK ( a b -- b a b ) + swap over +; + +: <= ( a b -- f , true if A <= b ) + > 0= +; +: >= ( a b -- f , true if A >= b ) + < 0= +; + +: INVERT ( n -- 1'comp ) + -1 xor +; + +: NOT ( n -- !n , logical negation ) + 0= +; + +: NEGATE ( n -- -n ) + 0 swap - +; + +: DNEGATE ( d -- -d , negate by doing 0-d ) + 0 0 2swap d- +; + + +\ -------------------------------------------------------------------- + +: ID. ( nfa -- ) + count 31 and type +; + +: DECIMAL 10 base ! ; +: OCTAL 8 base ! ; +: HEX 16 base ! ; +: BINARY 2 base ! ; + +: PAD ( -- addr ) + here 128 + +; + +: $MOVE ( $src $dst -- ) + over c@ 1+ cmove +; +: BETWEEN ( n lo hi -- flag , true if between lo & hi ) + >r over r> > >r + < r> or 0= +; +: [ ( -- , enter interpreter mode ) + 0 state ! +; immediate +: ] ( -- enter compile mode ) + 1 state ! +; + +: EVEN-UP ( n -- n | n+1 , make even ) dup 1 and + ; +: ALIGNED ( addr -- a-addr ) + [ cell 1- ] literal + + [ cell 1- invert ] literal and +; +: ALIGN ( -- , align DP ) dp @ aligned dp ! ; +: ALLOT ( nbytes -- , allot space in dictionary ) dp +! ( align ) ; + +: C, ( c -- ) here c! 1 chars dp +! ; +: W, ( w -- ) dp @ even-up dup dp ! w! 2 chars dp +! ; +: , ( n -- , lay into dictionary ) align here ! cell allot ; + +\ Dictionary conversions ------------------------------------------ + +: N>NEXTLINK ( nfa -- nextlink , traverses name field ) + dup c@ 31 and 1+ + aligned +; + +: NAMEBASE ( -- base-of-names ) + Headers-Base @ +; +: CODEBASE ( -- base-of-code dictionary ) + Code-Base @ +; + +: NAMELIMIT ( -- limit-of-names ) + Headers-limit @ +; +: CODELIMIT ( -- limit-of-code, last address in dictionary ) + Code-limit @ +; + +: NAMEBASE+ ( rnfa -- nfa , convert relocatable nfa to actual ) + namebase + +; + +: >CODE ( xt -- secondary_code_address, not valid for primitives ) + codebase + +; + +: CODE> ( secondary_code_address -- xt , not valid for primitives ) + codebase - +; + +: N>LINK ( nfa -- lfa ) + 2 CELLS - +; + +: >BODY ( xt -- pfa ) + >code body_offset + +; + +: BODY> ( pfa -- xt ) + body_offset - code> +; + +\ convert between addresses useable by @, and relocatable addresses. +: USE->REL ( useable_addr -- rel_addr ) + codebase - +; +: REL->USE ( rel_addr -- useable_addr ) + codebase + +; + +\ for JForth code +\ : >REL ( adr -- adr ) ; immediate +\ : >ABS ( adr -- adr ) ; immediate + +: X@ ( addr -- xt , fetch execution token from relocatable ) @ ; +: X! ( addr -- xt , store execution token as relocatable ) ! ; + +\ Compiler support ------------------------------------------------ +: COMPILE, ( xt -- , compile call to xt ) + , +; + +( Compiler support , based on FIG ) +: [COMPILE] ( -- , compile now even if immediate ) + ' compile, +; IMMEDIATE + +: (COMPILE) ( xt -- , postpone compilation of token ) + [compile] literal ( compile a call to literal ) + ( store xt of word to be compiled ) + + [ ' compile, ] literal \ compile call to compile, + compile, +; + +: COMPILE ( -- , save xt and compile later ) + ' (compile) +; IMMEDIATE + + +: :NONAME ( -- xt , begin compilation of headerless secondary ) + align + here code> \ convert here to execution token + ] +; + +\ Error codes defined in ANSI Exception word set. +: ERR_ABORT -1 ; \ general abort +: ERR_EXECUTING -14 ; \ compile time word while not compiling +: ERR_PAIRS -22 ; \ mismatch in conditional +: ERR_DEFER -258 ; \ not a deferred word + +: ABORT ( i*x -- ) + ERR_ABORT throw +; + +\ Conditionals in '83 form ----------------------------------------- +: CONDITIONAL_KEY ( -- , lazy constant ) 29521 ; +: ?CONDITION ( f -- ) conditional_key - err_pairs ?error ; +: >MARK ( -- addr ) here 0 , ; +: >RESOLVE ( addr -- ) here over - swap ! ; +: mark ; immediate +: THEN ( f orig -- ) swap ?condition >resolve ; immediate +: BEGIN ( -- f dest ) ?comp conditional_key mark ; immediate + +\ conditionals built from primitives +: ELSE ( f orig1 -- f orig2 ) + [compile] AHEAD 2swap [compile] THEN ; immediate +: WHILE ( f dest -- f orig f dest ) [compile] if 2swap ; immediate +: REPEAT ( -- f orig f dest ) [compile] again [compile] then ; immediate + +: ['] ( -- xt , define compile time tick ) + ?comp ' [compile] literal +; immediate + +\ for example: +\ compile time: compile create , (does>) then ; +\ execution time: create , ',' data, then patch pi to point to @ +\ : con create , does> @ ; +\ 345 con pi +\ pi +\ +: (DOES>) ( xt -- , modify previous definition to execute code at xt ) + latest name> >code \ get address of code for new word + cell + \ offset to second cell in create word + ! \ store execution token of DOES> code in new word +; + +: DOES> ( -- , define execution code for CREATE word ) + 0 [compile] literal \ dummy literal to hold xt + here cell- \ address of zero in literal + compile (does>) \ call (DOES>) from new creation word + >r \ move addrz to return stack so ; doesn't see stack garbage + [compile] ; \ terminate part of code before does> + r> + :noname ( addrz xt ) + swap ! \ save execution token in literal +; immediate + +: VARIABLE ( -- ) + CREATE 0 , \ IMMEDIATE +\ DOES> [compile] aliteral \ %Q This could be optimised +; + +: 2VARIABLE ( -c- ) ( -x- addr ) + create 0 , 0 , +; + +: CONSTANT ( n -c- ) ( -x- n ) + CREATE , ( n -- ) + DOES> @ ( -- n ) +; + + + +0 1- constant -1 +0 2- constant -2 + +: 2! ( x1 x2 addr -- , store x2 followed by x1 ) + swap over ! cell+ ! +; +: 2@ ( addr -- x1 x2 ) + dup cell+ @ swap @ +; + + +: ABS ( n -- |n| ) + dup 0< + IF negate + THEN +; +: DABS ( d -- |d| ) + dup 0< + IF dnegate + THEN +; + +: S>D ( s -- d , extend signed single precision to double ) + dup 0< + IF -1 + ELSE 0 + THEN +; + +: D>S ( d -- s ) drop ; + +: /MOD ( a b -- rem quo , unsigned version, FIXME ) + >r s>d r> um/mod +; + +: MOD ( a b -- rem ) + /mod drop +; + +: 2* ( n -- n*2 ) + 1 lshift +; +: 2/ ( n -- n/2 ) + 1 arshift +; + +: D2* ( d -- d*2 ) + 2* over + cell 8 * 1- rshift or swap + 2* swap +; + +\ define some useful constants ------------------------------ +1 0= constant FALSE +0 0= constant TRUE +32 constant BL + + +\ Store and Fetch relocatable data addresses. --------------- +: IF.USE->REL ( use -- rel , preserve zero ) + dup IF use->rel THEN +; +: IF.REL->USE ( rel -- use , preserve zero ) + dup IF rel->use THEN +; + +: A! ( dictionary_address addr -- ) + >r if.use->rel r> ! +; +: A@ ( addr -- dictionary_address ) + @ if.rel->use +; + +: A, ( dictionary_address -- ) + if.use->rel , +; + +\ Stack data structure ---------------------------------------- +\ This is a general purpose stack utility used to implement necessary +\ stacks for the compiler or the user. Not real fast. +\ These stacks grow up which is different then normal. +\ cell 0 - stack pointer, offset from pfa of word +\ cell 1 - limit for range checking +\ cell 2 - first data location + +: :STACK ( #cells -- ) + CREATE 2 cells , ( offset of first data location ) + dup , ( limit for range checking, not currently used ) + cells cell+ allot ( allot an extra cell for safety ) +; + +: >STACK ( n stack -- , push onto stack, postincrement ) + dup @ 2dup cell+ swap ! ( -- n stack offset ) + + ! +; + +: STACK> ( stack -- n , pop , predecrement ) + dup @ cell- 2dup swap ! + + @ +; + +: STACK@ ( stack -- n , copy ) + dup @ cell- + @ +; + +: STACK.PICK ( index stack -- n , grab Nth from top of stack ) + dup @ cell- + + swap cells - \ offset for index + @ +; +: STACKP ( stack -- ptr , to next empty location on stack ) + dup @ + +; + +: 0STACKP ( stack -- , clear stack) + 8 swap ! +; + +32 :stack ustack +ustack 0stackp + +\ Define JForth like words. +: >US ustack >stack ; +: US> ustack stack> ; +: US@ ustack stack@ ; +: 0USP ustack 0stackp ; + + +\ DO LOOP ------------------------------------------------ + +3 constant do_flag +4 constant leave_flag +5 constant ?do_flag + +: DO ( -- , loop-back do_flag jump-from ?do_flag ) + ?comp + compile (do) + here >us do_flag >us ( for backward branch ) +; immediate + +: ?DO ( -- , loop-back do_flag jump-from ?do_flag , on user stack ) + ?comp + ( leave address to set for forward branch ) + compile (?do) + here 0 , + here >us do_flag >us ( for backward branch ) + >us ( for forward branch ) ?do_flag >us +; immediate + +: LEAVE ( -- addr leave_flag ) + compile (leave) + here 0 , >us + leave_flag >us +; immediate + +: LOOP-FORWARD ( -us- jump-from ?do_flag -- ) + BEGIN + us@ leave_flag = + us@ ?do_flag = + OR + WHILE + us> leave_flag = + IF + us> here over - cell+ swap ! + ELSE + us> dup + here swap - + cell+ swap ! + THEN + REPEAT +; + +: LOOP-BACK ( loop-addr do_flag -us- ) + us> do_flag ?pairs + us> here - here + ! + cell allot +; + +: LOOP ( -- , loop-back do_flag jump-from ?do_flag ) + compile (loop) + loop-forward loop-back +; immediate + +\ : DOTEST 5 0 do 333 . loop 888 . ; +\ : ?DOTEST0 0 0 ?do 333 . loop 888 . ; +\ : ?DOTEST1 5 0 ?do 333 . loop 888 . ; + +: +LOOP ( -- , loop-back do_flag jump-from ?do_flag ) + compile (+loop) + loop-forward loop-back +; immediate + +: UNLOOP ( loop-sys -r- ) + r> \ save return pointer + rdrop rdrop + >r +; + +: RECURSE ( ? -- ? , call the word currently being defined ) + latest name> compile, +; immediate + + + +: SPACE bl emit ; +: SPACES 512 min 0 max 0 ?DO space LOOP ; +: 0SP depth 0 ?do drop loop ; + +: >NEWLINE ( -- , CR if needed ) + out @ 0> + IF cr + THEN +; + + +\ Support for DEFER -------------------- +: CHECK.DEFER ( xt -- , error if not a deferred word by comparing to type ) + >code @ + ['] emit >code @ + - err_defer ?error +; + +: >is ( xt -- address_of_vector ) + >code + cell + +; + +: (IS) ( xt_do xt_deferred -- ) + >is ! +; + +: IS ( xt -- , act like normal IS ) + ' \ xt + dup check.defer + state @ + IF [compile] literal compile (is) + ELSE (is) + THEN +; immediate + +: (WHAT'S) ( xt -- xt_do ) + >is @ +; +: WHAT'S ( -- xt , what will deferred word call? ) + ' \ xt + dup check.defer + state @ + IF [compile] literal compile (what's) + ELSE (what's) + THEN +; immediate + +: /STRING ( addr len n -- addr' len' ) + over min rot over + -rot - +; +: PLACE ( addr len to -- , move string ) + 3dup 1+ swap cmove c! drop +; + +: PARSE-WORD ( char -- addr len ) + >r source tuck >in @ /string r@ skip over swap r> scan + >r over - rot r> dup 0<> + - >in ! +; +: PARSE ( char -- addr len ) + >r source >in @ /string over swap r> scan + >r over - dup r> 0<> - >in +! +; + +: LWORD ( char -- addr ) + parse-word here place here \ 00002 , use PARSE-WORD +; + +: ASCII ( -- char , state smart ) + bl parse drop c@ + state @ + IF [compile] literal + THEN +; immediate + +: CHAR ( -- char , interpret mode ) + bl parse drop c@ +; + +: [CHAR] ( -- char , for compile mode ) + char [compile] literal +; immediate + +: $TYPE ( $string -- ) + count type +; + +: 'word ( -- addr ) here ; + +: EVEN ( addr -- addr' ) dup 1 and + ; + +: (C") ( -- $addr , some Forths return addr AND count, OBSOLETE?) + r> dup count + aligned >r +; +: (S") ( -- c-addr cnt ) + r> count 2dup + aligned >r +; + +: (.") ( -- , type following string ) + r> count 2dup + aligned >r type +; + +: ", ( adr len -- , place string into dictionary ) + tuck 'word place 1+ allot align +; +: ," ( -- ) + [char] " parse ", +; + +: .( ( -- , type string delimited by parentheses ) + [CHAR] ) PARSE TYPE +; IMMEDIATE + +: ." ( -- , type string ) + state @ + IF compile (.") ," + ELSE [char] " parse type + THEN +; immediate + + +: .' ( -- , type string delimited by single quote ) + state @ + IF compile (.") [char] ' parse ", + ELSE [char] ' parse type + THEN +; immediate + +: C" ( -- addr , return string address, ANSI ) + state @ + IF compile (c") ," + ELSE [char] " parse pad place pad + THEN +; immediate + +: S" ( -- , -- addr , return string address, ANSI ) + state @ + IF compile (s") ," + ELSE [char] " parse pad place pad count + THEN +; immediate + +: " ( -- , -- addr , return string address ) + [compile] C" +; immediate +: P" ( -- , -- addr , return string address ) + [compile] C" +; immediate + +: "" ( -- addr ) + state @ + IF + compile (C") + bl parse-word ", + ELSE + bl parse-word pad place pad + THEN +; immediate + +: SLITERAL ( addr cnt -- , compile string ) + compile (S") + ", +; IMMEDIATE + +: $APPEND ( addr count $1 -- , append text to $1 ) + over >r + dup >r + count + ( -- a2 c2 end1 ) + swap cmove + r> dup c@ ( a1 c1 ) + r> + ( -- a1 totalcount ) + swap c! +; + + +\ ANSI word to replace [COMPILE] and COMPILE ---------------- +: POSTPONE ( -- ) + bl word find + dup 0= + IF + ." Postpone could not find " count type cr abort + ELSE + 0> + IF compile, \ immediate + ELSE (compile) \ normal + THEN + THEN +; immediate + +\ ----------------------------------------------------------------- +\ Auto Initialization +: AUTO.INIT ( -- ) +\ Kernel finds AUTO.INIT and executes it after loading dictionary. +\ ." Begin AUTO.INIT ------" cr +; +: AUTO.TERM ( -- ) +\ Kernel finds AUTO.TERM and executes it on bye. +\ ." End AUTO.TERM ------" cr +; + +\ -------------- INCLUDE ------------------------------------------ +variable TRACE-INCLUDE + +: INCLUDE.MARK.START ( $filename -- , mark start of include for FILE?) + " ::::" pad $MOVE + count pad $APPEND + pad ['] noop (:) +; + +: INCLUDE.MARK.END ( -- , mark end of include ) + " ;;;;" ['] noop (:) +; + +: $INCLUDE ( $filename -- ) +\ Print messages. + trace-include @ + IF + >newline ." Include " dup count type cr + THEN + here >r + dup + count r/o open-file + IF ( -- $filename bad-fid ) + drop ." Could not find file " $type cr abort + ELSE ( -- $filename good-fid ) + swap include.mark.start + depth >r + include-file \ will also close the file + depth 1+ r> - + IF + ." Warning: stack depth changed during include!" cr + .s cr + 0sp + THEN + include.mark.end + THEN + trace-include @ + IF + ." include added " here r@ - . ." bytes," + codelimit here - . ." left." cr + THEN + rdrop +; + +create INCLUDE-SAVE-NAME 128 allot +: INCLUDE ( -- ) + BL lword + dup include-save-name $move \ save for RI + $include +; + +: RI ( -- , ReInclude previous file as a convenience ) + include-save-name $include +; + +: INCLUDE? ( -- , load file if word not defined ) + bl word find + IF drop bl word drop ( eat word from source ) + ELSE drop include + THEN +; + +\ desired sizes for dictionary loaded after SAVE-FORTH +variable HEADERS-SIZE +variable CODE-SIZE + +: AUTO.INIT + auto.init + codelimit codebase - code-size ! + namelimit namebase - headers-size ! +; +auto.init + +: SAVE-FORTH ( $name -- ) + 0 \ Entry point + headers-ptr @ namebase - 65536 + \ NameSize + headers-size @ MAX + here codebase - 131072 + \ CodeSize + code-size @ MAX + (save-forth) + IF + ." SAVE-FORTH failed!" cr abort + THEN +; + +: TURNKEY ( $name entry-token-- ) + 0 \ NameSize = 0, names not saved in turnkey dictionary + here codebase - 131072 + \ CodeSize, remember that base is HEX + (save-forth) + IF + ." TURNKEY failed!" cr abort + THEN +; + +\ Now that we can load from files, load remainder of dictionary. + +trace-include on +trace-stack on + +include loadp4th.fth + +decimal + +: ;;;; ; \ Mark end of this file so FILE? can find things in here. +FREEZE \ prevent forgetting below this point + +.( Dictionary compiled, save in "pforth.dic".) cr +c" pforth.dic" save-forth + +\ Save the dictionary in "pfdicdat.h" file so pForth can be compiled for standalone mode. +SDAD diff --git a/src/cmd/pforth/fth/t_alloc.fth b/src/cmd/pforth/fth/t_alloc.fth new file mode 100644 index 0000000..4f20917 --- /dev/null +++ b/src/cmd/pforth/fth/t_alloc.fth @@ -0,0 +1,116 @@ +\ @(#) t_alloc.fth 97/01/28 1.4 +\ Test PForth ALLOCATE +\ +\ Copyright 1994 3DO, Phil Burk + +anew task-t_alloc.fth +decimal + +64 constant NUM_TAF_SLOTS + +variable TAF-MAX-ALLOC +variable TAF-MAX-SLOT + +\ hold addresses and sizes +NUM_TAF_SLOTS array TAF-ADDRESSES +NUM_TAF_SLOTS array TAF-SIZES + +: TAF.MAX.ALLOC? { | numb addr ior maxb -- max } + 0 -> maxb +\ determine maximum amount we can allocate + 1024 40 * -> numb + BEGIN + numb 0> + WHILE + numb allocate -> ior -> addr + ior 0= + IF \ success + addr free abort" Free failed!" + numb -> maxb + 0 -> numb + ELSE + numb 1024 - -> numb + THEN + REPEAT + maxb +; + +: TAF.INIT ( -- ) + NUM_TAF_SLOTS 0 + DO + 0 i taf-addresses ! + LOOP +\ + taf.max.alloc? ." Total Avail = " dup . cr + dup taf-max-alloc ! + NUM_TAF_SLOTS / taf-max-slot ! +; + +: TAF.ALLOC.SLOT { slotnum | addr size -- } +\ allocate some RAM + taf-max-slot @ 8 - + choose 8 + + dup allocate abort" Allocation failed!" + -> addr + -> size + addr slotnum taf-addresses ! + size slotnum taf-sizes ! +\ +\ paint RAM with slot number + addr size slotnum fill +; + +: TAF.FREE.SLOT { slotnum | addr size -- } + slotnum taf-addresses @ -> addr +\ something allocated so check it and free it. + slotnum taf-sizes @ 0 + DO + addr i + c@ slotnum - + IF + ." Error at " addr i + . + ." , slot# " slotnum . cr + abort + THEN + LOOP + addr free abort" Free failed!" + 0 slotnum taf-addresses ! +; + +: TAF.DO.SLOT { slotnum -- } + slotnum taf-addresses @ 0= + IF + slotnum taf.alloc.slot + ELSE + slotnum taf.free.slot + THEN +; + +: TAF.TERM + NUM_TAF_SLOTS 0 + DO + i taf-addresses @ + IF + i taf.free.slot + THEN + LOOP +\ + taf.max.alloc? dup ." Final MAX = " . cr + ." Original MAX = " taf-max-alloc @ dup . cr + = IF ." Test PASSED." ELSE ." Test FAILED!" THEN cr + +; + +: TAF.TEST ( NumTests -- ) + 1 max + dup . ." tests" cr \ flushemit + taf.init + ." Please wait for test to complete..." cr + 0 + DO NUM_TAF_SLOTS choose taf.do.slot + LOOP + taf.term +; + +.( Testing ALLOCATE and FREE) cr +10000 taf.test + diff --git a/src/cmd/pforth/fth/t_case.fth b/src/cmd/pforth/fth/t_case.fth new file mode 100644 index 0000000..6303125 --- /dev/null +++ b/src/cmd/pforth/fth/t_case.fth @@ -0,0 +1,16 @@ +\ test CASE +anew test-case +: TCASE ( N -- ) + CASE + 0 OF ." is zero" ENDOF + 1 OF + 2 choose + CASE + 0 OF ." chose zero" ENDOF + 1 OF ." chose one" ENDOF + [ .s cr ." of-depth = " of-depth @ . cr ] + ENDCASE + ENDOF + [ .s cr ." of-depth = " of-depth @ . cr ] + ENDCASE +; diff --git a/src/cmd/pforth/fth/t_corex.fth b/src/cmd/pforth/fth/t_corex.fth new file mode 100644 index 0000000..1f383c4 --- /dev/null +++ b/src/cmd/pforth/fth/t_corex.fth @@ -0,0 +1,226 @@ +\ @(#) t_corex.fth 98/03/16 1.2 +\ Test ANS Forth Core Extensions +\ +\ Copyright 1994 3DO, Phil Burk + +INCLUDE? }T{ t_tools.fth + +ANEW TASK-T_COREX.FTH + +DECIMAL + +\ STUB because missing definition in pForth - FIXME +: SAVE-INPUT ; +: RESTORE-INPUT -1 ; + +TEST{ + +\ ========================================================== +T{ 1 2 3 }T{ 1 2 3 }T + +\ ----------------------------------------------------- .( +T{ 27 .( IF YOU SEE THIS THEN .( WORKED!) }T{ 27 }T + +CR .( 1234 - SHOULD LINE UP WITH NEXT LINE.) CR 1234 8 .R CR + +T{ .( ) 987 .( TEST NULL STRING IN .( ) CR }T{ 987 }T + +\ ----------------------------------------------------- 0<> +T{ 5 0<> }T{ TRUE }T +T{ 0 0<> }T{ 0 }T +T{ -1000 0<> }T{ TRUE }T + +\ ----------------------------------------------------- 2>R 2R> 2R@ +: T2>R ( -- .... ) + 17 + 20 5 2>R + 19 + 2R@ + 37 + 2R> +\ 2>R should be the equivalent of SWAP >R >R so this next construct +\ should reduce to a SWAP. + 88 77 2>R R> R> +; +T{ T2>R }T{ 17 19 20 5 37 20 5 77 88 }T + +\ ----------------------------------------------------- :NONAME +T{ :NONAME 100 50 + ; EXECUTE }T{ 150 }T + +\ ----------------------------------------------------- <> +T{ 12345 12305 <> }T{ TRUE }T +T{ HEX 98765432 98765432 DECIMAL <> }T{ 0 }T + +\ ----------------------------------------------------- ?DO +: T?DO ( n -- sum_n ) 0 SWAP 1+ 0 ?DO i + LOOP ; +T{ 0 T?DO }T{ 0 }T +T{ 4 T?DO }T{ 10 }T + +\ ----------------------------------------------------- AGAIN +: T.AGAIN ( n -- ) + BEGIN + DUP . + DUP 6 < IF EXIT THEN + 1- + AGAIN +; +T{ 10 T.AGAIN CR }T{ 5 }T + +\ ----------------------------------------------------- C" +: T.C" ( -- $STRING ) + C" x5&" +; +T{ T.C" C@ }T{ 3 }T +T{ T.C" COUNT DROP C@ }T{ CHAR x }T +T{ T.C" COUNT DROP CHAR+ C@ }T{ CHAR 5 }T +T{ T.C" COUNT DROP 2 CHARS + C@ }T{ CHAR & }T + +\ ----------------------------------------------------- CASE +: T.CASE ( N -- ) + CASE + 1 OF 101 ENDOF + 27 OF 892 ENDOF + 941 SWAP \ default + ENDCASE +; +T{ 1 T.CASE }T{ 101 }T +T{ 27 T.CASE }T{ 892 }T +T{ 49 T.CASE }T{ 941 }T + +\ ----------------------------------------------------- COMPILE, +: COMPILE.SWAP ['] SWAP COMPILE, ; IMMEDIATE +: T.COMPILE, + 19 20 27 COMPILE.SWAP 39 +; +T{ T.COMPILE, }T{ 19 27 20 39 }T + +\ ----------------------------------------------------- CONVERT +: T.CONVERT + 0 S>D S" 1234xyz" DROP CONVERT + >R + D>S + R> C@ +; +T{ T.CONVERT }T{ 1234 CHAR x }T + +\ ----------------------------------------------------- ERASE +: T.COMMA.SEQ ( n -- , lay down N sequential bytes ) + 0 ?DO I C, LOOP +; +CREATE T-ERASE-DATA 64 T.COMMA.SEQ +T{ T-ERASE-DATA 8 + C@ }T{ 8 }T +T{ T-ERASE-DATA 7 + 3 ERASE +T{ T-ERASE-DATA 6 + C@ }T{ 6 }T +T{ T-ERASE-DATA 7 + C@ }T{ 0 }T +T{ T-ERASE-DATA 8 + C@ }T{ 0 }T +T{ T-ERASE-DATA 9 + C@ }T{ 0 }T +T{ T-ERASE-DATA 10 + C@ }T{ 10 }T + +\ ----------------------------------------------------- FALSE +T{ FALSE }T{ 0 }T + +\ ----------------------------------------------------- HEX +T{ HEX 10 DECIMAL }T{ 16 }T + +\ ----------------------------------------------------- MARKER +: INDIC? ( -- ifInDic , is the following word defined? ) + bl word find + swap drop 0= 0= +; +create FOOBAR +MARKER MYMARK \ create word that forgets itself +create GOOFBALL +MYMARK +T{ indic? foobar indic? mymark indic? goofball }T{ true false false }T + +\ ----------------------------------------------------- NIP +T{ 33 44 55 NIP }T{ 33 55 }T + +\ ----------------------------------------------------- PARSE +: T.PARSE ( char char -- addr num ) + PARSE + >R \ save length + PAD R@ CMOVE \ move string to pad + PAD R> +; +T{ CHAR % T.PARSE wxyz% SWAP C@ }T{ 4 CHAR w }T + +\ ----------------------------------------------------- PICK +T{ 13 12 11 10 2 PICK }T{ 13 12 11 10 12 }T + +\ ----------------------------------------------------- QUERY +T{ ' QUERY 0<> }T{ TRUE }T + +\ ----------------------------------------------------- REFILL +T{ ' REFILL 0<> }T{ TRUE }T + +\ ----------------------------------------------------- RESTORE-INPUT +T{ : T.SAVE-INPUT SAVE-INPUT RESTORE-INPUT ; T.SAVE-INPUT }T{ 0 }T \ EXPECTED FAILURE + +\ ----------------------------------------------------- ROLL +T{ 15 14 13 12 11 10 0 ROLL }T{ 15 14 13 12 11 10 }T +T{ 15 14 13 12 11 10 1 ROLL }T{ 15 14 13 12 10 11 }T +T{ 15 14 13 12 11 10 2 ROLL }T{ 15 14 13 11 10 12 }T +T{ 15 14 13 12 11 10 3 ROLL }T{ 15 14 12 11 10 13 }T +T{ 15 14 13 12 11 10 4 ROLL }T{ 15 13 12 11 10 14 }T + +\ ----------------------------------------------------- SOURCE-ID +T{ SOURCE-ID 0<> }T{ TRUE }T +T{ : T.SOURCE-ID S" SOURCE-ID" EVALUATE ; T.SOURCE-ID }T{ -1 }T + +\ ----------------------------------------------------- SPAN +T{ ' SPAN 0<> }T{ TRUE }T + +\ ----------------------------------------------------- TO VALUE +333 VALUE MY-VALUE +T{ MY-VALUE }T{ 333 }T +T{ 1000 TO MY-VALUE MY-VALUE }T{ 1000 }T +: TEST.VALUE ( -- 19 100 ) + 100 TO MY-VALUE + 19 + MY-VALUE +; +T{ TEST.VALUE }T{ 19 100 }T + +\ ----------------------------------------------------- TRUE +T{ TRUE }T{ 0 0= }T + +\ ----------------------------------------------------- TUCK +T{ 44 55 66 TUCK }T{ 44 66 55 66 }T + +\ ----------------------------------------------------- U.R +HEX CR .( ABCD4321 - SHOULD LINE UP WITH NEXT LINE.) CR +ABCD4321 C U.R CR DECIMAL + +\ ----------------------------------------------------- U> +T{ -5 3 U> }T{ TRUE }T +T{ 10 8 U> }T{ TRUE }T + +\ ----------------------------------------------------- UNUSED +T{ UNUSED 0> }T{ TRUE }T + +\ ----------------------------------------------------- WITHIN +T{ 4 5 10 WITHIN }T{ 0 }T +T{ 5 5 10 WITHIN }T{ TRUE }T +T{ 9 5 10 WITHIN }T{ TRUE }T +T{ 10 5 10 WITHIN }T{ 0 }T + +T{ 4 10 5 WITHIN }T{ TRUE }T +T{ 5 10 5 WITHIN }T{ 0 }T +T{ 9 10 5 WITHIN }T{ 0 }T +T{ 10 10 5 WITHIN }T{ TRUE }T + +T{ -6 -5 10 WITHIN }T{ 0 }T +T{ -5 -5 10 WITHIN }T{ TRUE }T +T{ 9 -5 10 WITHIN }T{ TRUE }T +T{ 10 -5 10 WITHIN }T{ 0 }T + + +\ ----------------------------------------------------- [COMPILE] +: T.[COMPILE].IF [COMPILE] IF ; IMMEDIATE +: T.[COMPILE] 40 0> T.[COMPILE].IF 97 ELSE 53 THEN 97 = ; +T{ T.[COMPILE] }T{ TRUE }T + +\ ----------------------------------------------------- \ +}TEST + diff --git a/src/cmd/pforth/fth/t_floats.fth b/src/cmd/pforth/fth/t_floats.fth new file mode 100644 index 0000000..3086b03 --- /dev/null +++ b/src/cmd/pforth/fth/t_floats.fth @@ -0,0 +1,134 @@ +\ @(#) t_floats.fth 98/02/26 1.1 17:46:04 +\ Test ANS Forth FLOAT words. +\ +\ Copyright 1994 3DO, Phil Burk + +INCLUDE? }T{ t_tools.fth + +ANEW TASK-T_FLOATS.FTH + +DECIMAL +3.14159265 fconstant PI + +TEST{ +\ ========================================================== +T{ 1 2 3 }T{ 1 2 3 }T +\ ----------------------------------------------------- D>F F>D +\ test some basic floating point <> integer conversion +T{ 4 0 D>F F>D }T{ 4 0 }T +T{ 835 0 D>F F>D }T{ 835 0 }T +T{ -57 -1 D>F F>D }T{ -57 -1 }T +T{ 15 S>F 2 S>F F/ F>S }T{ 7 }T \ 15.0/2.0 -> 7.5 + +\ ----------------------------------------------------- input +T{ 79.2 F>S }T{ 79 }T +T{ 0.003 F>S }T{ 0 }T + +\ ------------------------------------------------------ F~ +T{ 23.4 23.5 0.2 f~ }T{ true }T +T{ 23.4 23.7 0.2 f~ }T{ false }T +T{ 922.3 922.3 0.0 f~ }T{ true }T +T{ 922.3 922.31 0.0 f~ }T{ false }T +T{ 0.0 0.0 0.0 f~ }T{ true }T +T{ 0.0 -0.0 0.0 f~ }T{ false }T +T{ 50.0 51.0 -0.02 f~ }T{ true }T +T{ 50.0 51.0 -0.002 f~ }T{ false }T +T{ 500.0 510.0 -0.02 f~ }T{ true }T +T{ 500.0 510.0 -0.002 f~ }T{ false }T + +\ convert number to text representation and then back to float +: T_F. ( -- ok? ) ( r ftol -f- ) + fover (f.) >float fswap f~ + AND +; +: T_FS. ( -- ok? ) ( r -f- ) + fover (fs.) >float fswap f~ + AND +; +: T_FE. ( -- ok? ) ( r -f- ) + fover (fe.) >float fswap f~ + AND +; + +: T_FG. ( -- ok? ) ( r -f- ) + fover (f.) >float fswap f~ + AND +; + +: T_F>D ( -- ok? ) ( r -f- ) + fover f>d d>f fswap f~ +; + +T{ 0.0 0.00001 T_F. }T{ true }T +T{ 0.0 0.00001 T_FS. }T{ true }T +T{ 0.0 0.00001 T_FE. }T{ true }T +T{ 0.0 0.00001 T_FG. }T{ true }T +T{ 0.0 0.00001 T_F>D }T{ true }T + +T{ 12.34 -0.0001 T_F. }T{ true }T +T{ 12.34 -0.0001 T_FS. }T{ true }T +T{ 12.34 -0.0001 T_FE. }T{ true }T +T{ 12.34 -0.0001 T_FG. }T{ true }T +T{ 1234.0 -0.0001 T_F>D }T{ true }T + +T{ 2345 S>F 79 S>F F/ -0.0001 T_F. }T{ true }T +T{ 511 S>F -294 S>F F/ -0.0001 T_F. }T{ true }T + +: T.SERIES { N matchCFA | flag -- ok? } ( fstart fmult -f- ) + fswap ( -- fmust fstart ) + true -> flag + N 0 + ?DO + fdup -0.0001 matchCFA execute not + IF + false -> flag + ." T_F_SERIES failed for " i . fdup f. cr + leave + THEN +\ i . fdup f. cr + fover f* + LOOP + matchCFA >name id. ." T.SERIES final = " fs. cr + flag +; + +: T.SERIES_F. ['] t_f. t.series ; +: T.SERIES_FS. ['] t_fs. t.series ; +: T.SERIES_FG. ['] t_fg. t.series ; +: T.SERIES_FE. ['] t_fe. t.series ; +: T.SERIES_F>D ['] t_f>d t.series ; + +T{ 1.0 1.3 150 t.series_f. }T{ true }T +T{ 1.0 -1.3 150 t.series_f. }T{ true }T +T{ 2.3456789 1.3719 150 t.series_f. }T{ true }T + +T{ 3000.0 1.298 120 t.series_f>d }T{ true }T + +T{ 1.2 1.27751 150 t.series_fs. }T{ true }T +T{ 7.43 0.812255 200 t.series_fs. }T{ true }T + +T{ 1.195 1.30071 150 t.series_fe. }T{ true }T +T{ 5.913 0.80644 200 t.series_fe. }T{ true }T + +T{ 1.395 1.55071 120 t.series_fe. }T{ true }T +T{ 5.413 0.83644 160 t.series_fe. }T{ true }T + +\ ----------------------------------------------------- FABS +T{ 0.0 FABS 0.0 0.00001 F~ }T{ true }T +T{ 7.0 FABS 7.0 0.00001 F~ }T{ true }T +T{ -47.3 FABS 47.3 0.00001 F~ }T{ true }T + +\ ----------------------------------------------------- FSQRT +T{ 49.0 FSQRT 7.0 -0.0001 F~ }T{ true }T +T{ 2.0 FSQRT 1.414214 -0.0001 F~ }T{ true }T + +\ ----------------------------------------------------- FSIN +T{ 0.0 FSIN 0.0 0.00001 F~ }T{ true }T +T{ PI FSIN 0.0 0.00001 F~ }T{ true }T +T{ PI 2.0 F* FSIN 0.0 0.00001 F~ }T{ true }T +T{ PI 0.5 F* FSIN 1.0 0.00001 F~ }T{ true }T +T{ PI 6.0 F/ FSIN 0.5 0.00001 F~ }T{ true }T + +\ ----------------------------------------------------- \ +}TEST + diff --git a/src/cmd/pforth/fth/t_include.fth b/src/cmd/pforth/fth/t_include.fth new file mode 100644 index 0000000..8b1a6be --- /dev/null +++ b/src/cmd/pforth/fth/t_include.fth @@ -0,0 +1,18 @@ +\ Test INCLUDE errors. +\ +\ Copyright 2001Phil Burk + +include? }T{ t_tools.fth + +marker task-t_string.fth + +decimal + +: F_UNDEF " t_load_undef.fth" ; + +test{ + +T{ F_UNDEF ' $include catch }T{ F_UNDEF -13 }T + + +}test diff --git a/src/cmd/pforth/fth/t_load.fth b/src/cmd/pforth/fth/t_load.fth new file mode 100644 index 0000000..9475eff --- /dev/null +++ b/src/cmd/pforth/fth/t_load.fth @@ -0,0 +1,7 @@ +\ Test nested INCLUDE errors. +\ +\ Copyright 2001Phil Burk + +\ include t_load_undef.fth +\ include t_load_semi.fth +include t_load_defer.fth diff --git a/src/cmd/pforth/fth/t_load_defer.fth b/src/cmd/pforth/fth/t_load_defer.fth new file mode 100644 index 0000000..c5e79e9 --- /dev/null +++ b/src/cmd/pforth/fth/t_load_defer.fth @@ -0,0 +1,5 @@ +\ Test INCLUDE errors. + +what's dup >name id. \ but DUP is not deferred! + +We should never reach this text. diff --git a/src/cmd/pforth/fth/t_load_pairs.fth b/src/cmd/pforth/fth/t_load_pairs.fth new file mode 100644 index 0000000..14df207 --- /dev/null +++ b/src/cmd/pforth/fth/t_load_pairs.fth @@ -0,0 +1,5 @@ +\ Test INCLUDE errors. + +: T.LOAD.PAIRS + 10 0 DO i . THEN +; diff --git a/src/cmd/pforth/fth/t_load_semi.fth b/src/cmd/pforth/fth/t_load_semi.fth new file mode 100644 index 0000000..2082787 --- /dev/null +++ b/src/cmd/pforth/fth/t_load_semi.fth @@ -0,0 +1,6 @@ +\ Test INCLUDE errors. + +: T.LOAD.PAIRS + 1 IF + ." hello" cr +; \ missing a THEN diff --git a/src/cmd/pforth/fth/t_load_undef.fth b/src/cmd/pforth/fth/t_load_undef.fth new file mode 100644 index 0000000..4d77e1e --- /dev/null +++ b/src/cmd/pforth/fth/t_load_undef.fth @@ -0,0 +1,5 @@ +\ Test INCLUDE errors. + +: T.LOAD.UNDEF + 23 45 swap BADWORD \ reference an undefined word! +; diff --git a/src/cmd/pforth/fth/t_locals.fth b/src/cmd/pforth/fth/t_locals.fth new file mode 100644 index 0000000..17a6a8a --- /dev/null +++ b/src/cmd/pforth/fth/t_locals.fth @@ -0,0 +1,52 @@ +\ @(#) t_locals.fth 97/01/28 1.1 +\ Test PForth LOCAL variables. +\ +\ Copyright 1996 3DO, Phil Burk + +include? }T{ t_tools.fth + +anew task-t_locals.fth +decimal + +test{ + +\ test value and locals +T{ 333 value my-value my-value }T{ 333 }T +T{ 1000 -> my-value my-value }T{ 1000 }T +T{ 35 +-> my-value my-value }T{ 1035 }T +: test.value ( -- ok ) + 100 -> my-value + my-value 100 = + 47 +-> my-value + my-value 147 = AND +; +T{ test.value }T{ TRUE }T + +\ test locals in a word +: test.locs { aa bb | cc -- ok } + cc 0= + aa bb + -> cc + aa bb + cc = AND + aa -> cc + bb +-> cc + aa bb + cc = AND +; + +T{ 200 59 test.locs }T{ TRUE }T + +.( Test warning when no locals defined.) cr +: loc.nonames { -- } 1234 ; +T{ loc.nonames }T{ 1234 }T + +\ try to put EOLs and comments in variable list +: calc.area { + width \ horizontal dimension + height \ vertical dimension + -- area , calculate area of a rectangle } + width height * +; + +T{ 5 20 calc.area }T{ 100 }T + +}test + diff --git a/src/cmd/pforth/fth/t_nolf.fth b/src/cmd/pforth/fth/t_nolf.fth new file mode 100644 index 0000000..cf28149 --- /dev/null +++ b/src/cmd/pforth/fth/t_nolf.fth @@ -0,0 +1,4 @@ +\ Test behavior of pForth when line encountered with no EOF at end. + +." First Line of Two" cr +." Second Line of Two" cr \ No newline at end of file diff --git a/src/cmd/pforth/fth/t_strings.fth b/src/cmd/pforth/fth/t_strings.fth new file mode 100644 index 0000000..be75379 --- /dev/null +++ b/src/cmd/pforth/fth/t_strings.fth @@ -0,0 +1,106 @@ +\ @(#) t_strings.fth 97/12/10 1.1 +\ Test ANS Forth String Word Set +\ +\ Copyright 1994 3DO, Phil Burk + +include? }T{ t_tools.fth + +marker task-t_string.fth + +decimal + +test{ + +echo off + +\ ========================================================== +\ test is.ok? +T{ 1 2 3 }T{ 1 2 3 }T + +: STR1 S" Hello " ; +: STR2 S" Hello World" ; +: STR3 S" " ; + +\ ----------------------------------------------------- -TRAILING +T{ STR1 -TRAILING }T{ STR1 DROP 5 }T +T{ STR2 -TRAILING }T{ STR2 }T +T{ STR3 -TRAILING }T{ STR3 }T + +\ ----------------------------------------------------- /STRING +T{ STR2 6 /STRING }T{ STR2 DROP 6 CHARS + STR2 NIP 6 - }T + + +\ ----------------------------------------------------- BLANK +: T.COMMA.SEQ ( n -- , lay down N sequential bytes ) + 0 ?DO I C, LOOP +; +CREATE T-BLANK-DATA 64 T.COMMA.SEQ +T{ T-BLANK-DATA 8 + C@ }T{ 8 }T +T-BLANK-DATA 7 + 3 BLANK +T{ T-BLANK-DATA 6 + C@ }T{ 6 }T +T{ T-BLANK-DATA 7 + C@ }T{ BL }T +T{ T-BLANK-DATA 8 + C@ }T{ BL }T +T{ T-BLANK-DATA 9 + C@ }T{ BL }T +T{ T-BLANK-DATA 10 + C@ }T{ 10 }T +FORGET T.COMMA.SEQ + +\ ----------------------------------------------------- CMOVE +: T.COMMA.SEQ ( n -- , lay down N sequential bytes ) + 0 ?DO I C, LOOP +; +CREATE T-BLANK-DATA 64 T.COMMA.SEQ +T-BLANK-DATA 7 + T-BLANK-DATA 6 + 3 CMOVE +T{ T-BLANK-DATA 5 + C@ }T{ 5 }T +T{ T-BLANK-DATA 6 + C@ }T{ 7 }T +T{ T-BLANK-DATA 7 + C@ }T{ 8 }T +T{ T-BLANK-DATA 8 + C@ }T{ 9 }T +T{ T-BLANK-DATA 9 + C@ }T{ 9 }T +FORGET T.COMMA.SEQ + +\ ----------------------------------------------------- CMOVE> +: T.COMMA.SEQ ( n -- , lay down N sequential bytes ) + 0 ?DO I C, LOOP +; +CREATE T-BLANK-DATA 64 T.COMMA.SEQ +T{ T-BLANK-DATA 6 + T-BLANK-DATA 7 + 3 CMOVE> +T{ T-BLANK-DATA 5 + C@ }T{ 5 }T +T{ T-BLANK-DATA 6 + C@ }T{ 6 }T +T{ T-BLANK-DATA 7 + C@ }T{ 6 }T +T{ T-BLANK-DATA 8 + C@ }T{ 7 }T +T{ T-BLANK-DATA 9 + C@ }T{ 8 }T +T{ T-BLANK-DATA 10 + C@ }T{ 10 }T +FORGET T.COMMA.SEQ + +\ ----------------------------------------------------- COMPARE +T{ : T.COMPARE.1 S" abcd" S" abcd" compare ; t.compare.1 }T{ 0 }T +T{ : T.COMPARE.2 S" abcd" S" abcde" compare ; t.compare.2 }T{ -1 }T +T{ : T.COMPARE.3 S" abcdef" S" abcde" compare ; t.compare.3 }T{ 1 }T +T{ : T.COMPARE.4 S" abGd" S" abcde" compare ; t.compare.4 }T{ -1 }T +T{ : T.COMPARE.5 S" abcd" S" aXcde" compare ; t.compare.5 }T{ 1 }T +T{ : T.COMPARE.6 S" abGd" S" abcd" compare ; t.compare.6 }T{ -1 }T +T{ : T.COMPARE.7 S" World" S" World" compare ; t.compare.7 }T{ 0 }T +FORGET T.COMPARE.1 + +\ ----------------------------------------------------- SEARCH +: STR-SEARCH S" ABCDefghIJKL" ; +T{ : T.SEARCH.1 STR-SEARCH S" ABCD" SEARCH ; T.SEARCH.1 }T{ STR-SEARCH TRUE }T +T{ : T.SEARCH.2 STR-SEARCH S" efg" SEARCH ; T.SEARCH.2 }T{ + STR-SEARCH 4 - SWAP 4 CHARS + SWAP TRUE }T +T{ : T.SEARCH.3 STR-SEARCH S" IJKL" SEARCH ; T.SEARCH.3 }T{ + STR-SEARCH DROP 8 CHARS + 4 TRUE }T +T{ : T.SEARCH.4 STR-SEARCH STR-SEARCH SEARCH ; T.SEARCH.4 }T{ + STR-SEARCH TRUE }T + +T{ : T.SEARCH.5 STR-SEARCH S" CDex" SEARCH ; T.SEARCH.5 }T{ + STR-SEARCH FALSE }T +T{ : T.SEARCH.6 STR-SEARCH S" KLM" SEARCH ; T.SEARCH.6 }T{ + STR-SEARCH FALSE }T +FORGET STR-SEARCH + +\ ----------------------------------------------------- SLITERAL +CREATE FAKE-STRING CHAR H C, CHAR e C, CHAR l C, CHAR l C, CHAR o C, +ALIGN +T{ : T.SLITERAL.1 [ FAKE-STRING 5 ] SLITERAL ; T.SLITERAL.1 FAKE-STRING 5 COMPARE + }T{ 0 }T + +}test diff --git a/src/cmd/pforth/fth/t_tools.fth b/src/cmd/pforth/fth/t_tools.fth new file mode 100644 index 0000000..a165c3b --- /dev/null +++ b/src/cmd/pforth/fth/t_tools.fth @@ -0,0 +1,83 @@ +\ @(#) t_tools.fth 97/12/10 1.1 +\ Test Tools for pForth +\ +\ Based on testing tools from John Hayes +\ (c) 1993 Johns Hopkins University / Applied Physics Laboratory +\ +\ Syntax was changed to avoid conflict with { -> and } for local variables. +\ Also added tracking of #successes and #errors. + +anew task-t_tools.fth + +decimal + +variable TEST-DEPTH +variable TEST-PASSED +variable TEST-FAILED + +: TEST{ + depth test-depth ! + 0 test-passed ! + 0 test-failed ! +; + + +: }TEST + test-passed @ 4 .r ." passed, " + test-failed @ 4 .r ." failed." cr +; + + +VARIABLE actual-depth \ stack record +CREATE actual-results 20 CELLS ALLOT + +: empty-stack \ ( ... -- ) Empty stack. + DEPTH dup 0> + IF 0 DO DROP LOOP + ELSE drop + THEN ; + +CREATE the-test 128 CHARS ALLOT + +: ERROR \ ( c-addr u -- ) Display an error message followed by + \ the line that had the error. + TYPE the-test COUNT TYPE CR \ display line corresponding to error + empty-stack \ throw away every thing else +; + + +: T{ + source the-test place + empty-stack +; + +: }T{ \ ( ... -- ) Record depth and content of stack. + DEPTH actual-depth ! \ record depth + DEPTH 0 + ?DO + actual-results I CELLS + ! + LOOP \ save them +; + +: }T \ ( ... -- ) Compare stack (expected) contents with saved + \ (actual) contents. + DEPTH + actual-depth @ = + IF \ if depths match + 1 test-passed +! \ assume will pass + DEPTH 0 + ?DO \ for each stack item + actual-results I CELLS + @ \ compare actual with expected + <> + IF + -1 test-passed +! + 1 test-failed +! + S" INCORRECT RESULT: " error + LEAVE + THEN + LOOP + ELSE \ depth mismatch + 1 test-failed +! + S" WRONG NUMBER OF RESULTS: " error + THEN +; diff --git a/src/cmd/pforth/fth/termio.fth b/src/cmd/pforth/fth/termio.fth new file mode 100644 index 0000000..f9a835a --- /dev/null +++ b/src/cmd/pforth/fth/termio.fth @@ -0,0 +1,88 @@ +\ Terminal I/O +\ +\ Requires an ANSI compatible terminal. +\ +\ To get Windows computers to use ANSI mode in their DOS windows, +\ Add this line to "C:\CONFIG.SYS" then reboot. +\ +\ device=c:\windows\command\ansi.sys +\ +\ Author: Phil Burk +\ Copyright 1988 Phil Burk +\ Revised 2001 for pForth + +ANEW TASK-TERMIO.FTH +decimal + +$ 08 constant ASCII_BACKSPACE +$ 7F constant ASCII_DELETE +$ 1B constant ASCII_ESCAPE +$ 01 constant ASCII_CTRL_A +$ 05 constant ASCII_CTRL_E +$ 18 constant ASCII_CTRL_X + +\ ANSI Terminal Control +: ESC[ ( send ESCAPE and [ ) + ASCII_ESCAPE emit + ascii [ emit +; + +: CLS ( -- , clear screen ) + ESC[ ." 2J" +; + +: TIO.BACKWARDS ( n -- , move cursor backwards ) + ESC[ + base @ >r decimal + 0 .r + r> base ! + ascii D emit +; + +: TIO.FORWARDS ( n -- , move cursor forwards ) + ESC[ + base @ >r decimal + 0 .r + r> base ! + ascii C emit +; + +: TIO.ERASE.EOL ( -- , erase to the end of the line ) + ESC[ + ascii K emit +; + + +: BELL ( -- , ring the terminal bell ) + 7 emit +; + +: BACKSPACE ( -- , backspace action ) + 8 emit space 8 emit +; + +0 [IF] \ for testing + +: SHOWKEYS ( -- , show keys pressed in hex ) + BEGIN + key + dup . + ." , $ " dup .hex cr + ascii q = + UNTIL +; + +: AZ ascii z 1+ ascii a DO i emit LOOP ; + +: TEST.BACK1 + AZ 5 tio.backwards + 1000 msec + tio.erase.eol +; +: TEST.BACK2 + AZ 10 tio.backwards + 1000 msec + ." 12345" + 1000 msec +; +[THEN] diff --git a/src/cmd/pforth/fth/tester.fth b/src/cmd/pforth/fth/tester.fth new file mode 100644 index 0000000..f4f2dd8 --- /dev/null +++ b/src/cmd/pforth/fth/tester.fth @@ -0,0 +1,54 @@ +\ From: John Hayes S1I +\ Subject: tester.fr +\ Date: Mon, 27 Nov 95 13:10:09 PST + +\ (C) 1995 JOHNS HOPKINS UNIVERSITY / APPLIED PHYSICS LABORATORY +\ MAY BE DISTRIBUTED FREELY AS LONG AS THIS COPYRIGHT NOTICE REMAINS. +\ VERSION 1.1 +HEX + +\ SET THE FOLLOWING FLAG TO TRUE FOR MORE VERBOSE OUTPUT; THIS MAY +\ ALLOW YOU TO TELL WHICH TEST CAUSED YOUR SYSTEM TO HANG. +VARIABLE VERBOSE + FALSE VERBOSE ! + +: EMPTY-STACK \ ( ... -- ) EMPTY STACK: HANDLES UNDERFLOWED STACK TOO. + DEPTH ?DUP IF DUP 0< IF NEGATE 0 DO 0 LOOP ELSE 0 DO DROP LOOP THEN THEN ; + +: ERROR \ ( C-ADDR U -- ) DISPLAY AN ERROR MESSAGE FOLLOWED BY + \ THE LINE THAT HAD THE ERROR. + TYPE SOURCE TYPE CR \ DISPLAY LINE CORRESPONDING TO ERROR + EMPTY-STACK \ THROW AWAY EVERY THING ELSE +; + +VARIABLE ACTUAL-DEPTH \ STACK RECORD +CREATE ACTUAL-RESULTS 20 CELLS ALLOT + +: { \ ( -- ) SYNTACTIC SUGAR. + ; + +: -> \ ( ... -- ) RECORD DEPTH AND CONTENT OF STACK. + DEPTH DUP ACTUAL-DEPTH ! \ RECORD DEPTH + ?DUP IF \ IF THERE IS SOMETHING ON STACK + 0 DO ACTUAL-RESULTS I CELLS + ! LOOP \ SAVE THEM + THEN ; + +: } \ ( ... -- ) COMPARE STACK (EXPECTED) CONTENTS WITH SAVED + \ (ACTUAL) CONTENTS. + DEPTH ACTUAL-DEPTH @ = IF \ IF DEPTHS MATCH + DEPTH ?DUP IF \ IF THERE IS SOMETHING ON THE STACK + 0 DO \ FOR EACH STACK ITEM + ACTUAL-RESULTS I CELLS + @ \ COMPARE ACTUAL WITH EXPECTED + <> IF S" INCORRECT RESULT: " ERROR LEAVE THEN + LOOP + THEN + ELSE \ DEPTH MISMATCH + S" WRONG NUMBER OF RESULTS: " ERROR + THEN ; + +: TESTING \ ( -- ) TALKING COMMENT. + SOURCE VERBOSE @ + IF DUP >R TYPE CR R> >IN ! + ELSE >IN ! DROP + THEN ; + diff --git a/src/cmd/pforth/fth/trace.fth b/src/cmd/pforth/fth/trace.fth new file mode 100644 index 0000000..026f91b --- /dev/null +++ b/src/cmd/pforth/fth/trace.fth @@ -0,0 +1,460 @@ +\ @(#) trace.fth 98/01/28 1.2 +\ TRACE ( -- , trace pForth word ) +\ +\ Single step debugger. +\ TRACE ( i*x -- , setup trace for Forth word ) +\ S ( -- , step over ) +\ SM ( many -- , step over many times ) +\ SD ( -- , step down ) +\ G ( -- , go to end of word ) +\ GD ( n -- , go down N levels from current level, stop at end of this level ) +\ +\ This debugger works by emulating the inner interpreter of pForth. +\ It executes code and maintains a separate return stack for the +\ program under test. Thus all primitives that operate on the return +\ stack, such as DO and R> must be trapped. Local variables must +\ also be handled specially. Several state variables are also +\ saved and restored to establish the context for the program being +\ tested. +\ +\ Copyright 1997 Phil Burk +\ +\ Modifications: +\ 19990930 John Providenza - Fixed stack bugs in GD + +anew task-trace.fth + +: SPACE.TO.COLUMN ( col -- ) + out @ - spaces +; + +: IS.PRIMITIVE? ( xt -- flag , true if kernel primitive ) + ['] first_colon < +; + +0 value TRACE_IP \ instruction pointer +0 value TRACE_LEVEL \ level of descent for inner interpreter +0 value TRACE_LEVEL_MAX \ maximum level of descent + +private{ + +\ use fake return stack +128 cells constant TRACE_RETURN_SIZE \ size of return stack in bytes +create TRACE-RETURN-STACK TRACE_RETURN_SIZE 16 + allot +variable TRACE-RSP +: TRACE.>R ( n -- ) trace-rsp @ cell- dup trace-rsp ! ! ; \ *(--rsp) = n +: TRACE.R> ( -- n ) trace-rsp @ dup @ swap cell+ trace-rsp ! ; \ n = *rsp++ +: TRACE.R@ ( -- n ) trace-rsp @ @ ; ; \ n = *rsp +: TRACE.RPICK ( index -- n ) cells trace-rsp @ + @ ; ; \ n = rsp[index] +: TRACE.0RP ( -- n ) trace-return-stack trace_return_size + 8 + trace-rsp ! ; +: TRACE.RDROP ( -- ) cell trace-rsp +! ; +: TRACE.RCHECK ( -- , abort if return stack out of range ) + trace-rsp @ trace-return-stack u< + abort" TRACE return stack OVERFLOW!" + trace-rsp @ trace-return-stack trace_return_size + 12 + u> + abort" TRACE return stack UNDERFLOW!" +; + +\ save and restore several state variables +10 cells constant TRACE_STATE_SIZE +create TRACE-STATE-1 TRACE_STATE_SIZE allot +create TRACE-STATE-2 TRACE_STATE_SIZE allot + +variable TRACE-STATE-PTR +: TRACE.SAVE++ ( addr -- , save next thing ) + @ trace-state-ptr @ ! + cell trace-state-ptr +! +; + +: TRACE.SAVE.STATE ( -- ) + state trace.save++ + hld trace.save++ + base trace.save++ +; + +: TRACE.SAVE.STATE1 ( -- , save normal state ) + trace-state-1 trace-state-ptr ! + trace.save.state +; +: TRACE.SAVE.STATE2 ( -- , save state of word being debugged ) + trace-state-2 trace-state-ptr ! + trace.save.state +; + + +: TRACE.RESTORE++ ( addr -- , restore next thing ) + trace-state-ptr @ @ swap ! + cell trace-state-ptr +! +; + +: TRACE.RESTORE.STATE ( -- ) + state trace.restore++ + hld trace.restore++ + base trace.restore++ +; + +: TRACE.RESTORE.STATE1 ( -- ) + trace-state-1 trace-state-ptr ! + trace.restore.state +; +: TRACE.RESTORE.STATE2 ( -- ) + trace-state-2 trace-state-ptr ! + trace.restore.state +; + +\ The implementation of these pForth primitives is specific to pForth. + +variable TRACE-LOCALS-PTR \ point to top of local frame + +\ create a return stack frame for NUM local variables +: TRACE.(LOCAL.ENTRY) ( x0 x1 ... xn n -- ) { num | lp -- } + trace-locals-ptr @ trace.>r + trace-rsp @ trace-locals-ptr ! + trace-rsp @ num cells - trace-rsp ! \ make room for locals + trace-rsp @ -> lp + num 0 + DO + lp ! + cell +-> lp \ move data into locals frame on return stack + LOOP +; + +: TRACE.(LOCAL.EXIT) ( -- ) + trace-locals-ptr @ trace-rsp ! + trace.r> trace-locals-ptr ! +; +: TRACE.(LOCAL@) ( l# -- n , fetch from local frame ) + trace-locals-ptr @ swap cells - @ +; +: TRACE.(1_LOCAL@) ( -- n ) 1 trace.(local@) ; +: TRACE.(2_LOCAL@) ( -- n ) 2 trace.(local@) ; +: TRACE.(3_LOCAL@) ( -- n ) 3 trace.(local@) ; +: TRACE.(4_LOCAL@) ( -- n ) 4 trace.(local@) ; +: TRACE.(5_LOCAL@) ( -- n ) 5 trace.(local@) ; +: TRACE.(6_LOCAL@) ( -- n ) 6 trace.(local@) ; +: TRACE.(7_LOCAL@) ( -- n ) 7 trace.(local@) ; +: TRACE.(8_LOCAL@) ( -- n ) 8 trace.(local@) ; + +: TRACE.(LOCAL!) ( n l# -- , store into local frame ) + trace-locals-ptr @ swap cells - ! +; +: TRACE.(1_LOCAL!) ( -- n ) 1 trace.(local!) ; +: TRACE.(2_LOCAL!) ( -- n ) 2 trace.(local!) ; +: TRACE.(3_LOCAL!) ( -- n ) 3 trace.(local!) ; +: TRACE.(4_LOCAL!) ( -- n ) 4 trace.(local!) ; +: TRACE.(5_LOCAL!) ( -- n ) 5 trace.(local!) ; +: TRACE.(6_LOCAL!) ( -- n ) 6 trace.(local!) ; +: TRACE.(7_LOCAL!) ( -- n ) 7 trace.(local!) ; +: TRACE.(8_LOCAL!) ( -- n ) 8 trace.(local!) ; + +: TRACE.(LOCAL+!) ( n l# -- , store into local frame ) + trace-locals-ptr @ swap cells - +! +; +: TRACE.(?DO) { limit start ip -- ip' } + limit start = + IF + ip @ +-> ip \ BRANCH + ELSE + start trace.>r + limit trace.>r + cell +-> ip + THEN + ip +; + +: TRACE.(LOOP) { ip | limit indx -- ip' } + trace.r> -> limit + trace.r> 1+ -> indx + limit indx = + IF + cell +-> ip + ELSE + indx trace.>r + limit trace.>r + ip @ +-> ip + THEN + ip +; + +: TRACE.(+LOOP) { delta ip | limit indx oldindx -- ip' } + trace.r> -> limit + trace.r> -> oldindx + oldindx delta + -> indx +\ /* Do indices cross boundary between LIMIT-1 and LIMIT ? */ +\ if( ( (OldIndex - Limit) & ((Limit-1) - NewIndex) & 0x80000000 ) || +\ ( (NewIndex - Limit) & ((Limit-1) - OldIndex) & 0x80000000 ) ) + oldindx limit - limit 1- indx - AND $ 80000000 AND + indx limit - limit 1- oldindx - AND $ 80000000 AND OR + IF + cell +-> ip + ELSE + indx trace.>r + limit trace.>r + ip @ +-> ip + THEN + ip +; + +: TRACE.CHECK.IP { ip -- } + ip ['] first_colon u< + ip here u> OR + IF + ." TRACE - IP out of range = " ip .hex cr + abort + THEN +; + +: TRACE.SHOW.IP { ip -- , print name and offset } + ip code> >name dup id. + name> >code ip swap - ." +" . +; + +: TRACE.SHOW.STACK { | mdepth -- } + base @ >r + ." <" base @ decimal 1 .r ." :" + depth 1 .r ." > " + r> base ! + depth 5 min -> mdepth + depth mdepth - + IF + ." ... " \ if we don't show entire stack + THEN + mdepth 0 + ?DO + mdepth i 1+ - pick . \ show numbers in current base + LOOP +; + +: TRACE.SHOW.NEXT { ip -- } + >newline + ip trace.check.ip +\ show word name and offset + ." << " + ip trace.show.ip + 16 space.to.column +\ show data stack + trace.show.stack + 40 space.to.column ." ||" + trace_level 2* spaces + ip code@ + cell +-> ip +\ show primitive about to be executed + dup .xt space +\ trap any primitives that are followed by inline data + CASE + ['] (LITERAL) OF ip @ . ENDOF + ['] (ALITERAL) OF ip a@ . ENDOF +[ exists? (FLITERAL) [IF] ] + ['] (FLITERAL) OF ip f@ f. ENDOF +[ [THEN] ] + ['] BRANCH OF ip @ . ENDOF + ['] 0BRANCH OF ip @ . ENDOF + ['] (.") OF ip count type .' "' ENDOF + ['] (C") OF ip count type .' "' ENDOF + ['] (S") OF ip count type .' "' ENDOF + ENDCASE + 65 space.to.column ." >> " +; + +: TRACE.DO.PRIMITIVE { ip xt | oldhere -- ip' , perform code at ip } + xt + CASE + 0 OF -1 +-> trace_level trace.r> -> ip ENDOF \ EXIT + ['] (CREATE) OF ip cell- body_offset + ENDOF + ['] (LITERAL) OF ip @ cell +-> ip ENDOF + ['] (ALITERAL) OF ip a@ cell +-> ip ENDOF +[ exists? (FLITERAL) [IF] ] + ['] (FLITERAL) OF ip f@ 1 floats +-> ip ENDOF +[ [THEN] ] + ['] BRANCH OF ip @ +-> ip ENDOF + ['] 0BRANCH OF 0= IF ip @ +-> ip ELSE cell +-> ip THEN ENDOF + ['] >R OF trace.>r ENDOF + ['] R> OF trace.r> ENDOF + ['] R@ OF trace.r@ ENDOF + ['] RDROP OF trace.rdrop ENDOF + ['] 2>R OF trace.>r trace.>r ENDOF + ['] 2R> OF trace.r> trace.r> ENDOF + ['] 2R@ OF trace.r@ 1 trace.rpick ENDOF + ['] i OF 1 trace.rpick ENDOF + ['] j OF 3 trace.rpick ENDOF + ['] (LEAVE) OF trace.rdrop trace.rdrop ip @ +-> ip ENDOF + ['] (LOOP) OF ip trace.(loop) -> ip ENDOF + ['] (+LOOP) OF ip trace.(+loop) -> ip ENDOF + ['] (DO) OF trace.>r trace.>r ENDOF + ['] (?DO) OF ip trace.(?do) -> ip ENDOF + ['] (.") OF ip count type ip count + aligned -> ip ENDOF + ['] (C") OF ip ip count + aligned -> ip ENDOF + ['] (S") OF ip count ip count + aligned -> ip ENDOF + ['] (LOCAL.ENTRY) OF trace.(local.entry) ENDOF + ['] (LOCAL.EXIT) OF trace.(local.exit) ENDOF + ['] (LOCAL@) OF trace.(local@) ENDOF + ['] (1_LOCAL@) OF trace.(1_local@) ENDOF + ['] (2_LOCAL@) OF trace.(2_local@) ENDOF + ['] (3_LOCAL@) OF trace.(3_local@) ENDOF + ['] (4_LOCAL@) OF trace.(4_local@) ENDOF + ['] (5_LOCAL@) OF trace.(5_local@) ENDOF + ['] (6_LOCAL@) OF trace.(6_local@) ENDOF + ['] (7_LOCAL@) OF trace.(7_local@) ENDOF + ['] (8_LOCAL@) OF trace.(8_local@) ENDOF + ['] (LOCAL!) OF trace.(local!) ENDOF + ['] (1_LOCAL!) OF trace.(1_local!) ENDOF + ['] (2_LOCAL!) OF trace.(2_local!) ENDOF + ['] (3_LOCAL!) OF trace.(3_local!) ENDOF + ['] (4_LOCAL!) OF trace.(4_local!) ENDOF + ['] (5_LOCAL!) OF trace.(5_local!) ENDOF + ['] (6_LOCAL!) OF trace.(6_local!) ENDOF + ['] (7_LOCAL!) OF trace.(7_local!) ENDOF + ['] (8_LOCAL!) OF trace.(8_local!) ENDOF + ['] (LOCAL+!) OF trace.(local+!) ENDOF + >r xt EXECUTE r> + ENDCASE + ip +; + +: TRACE.DO.NEXT { ip | xt oldhere -- ip' , perform code at ip } + ip trace.check.ip +\ set context for word under test + trace.save.state1 + here -> oldhere + trace.restore.state2 + oldhere 256 + dp ! +\ get execution token + ip code@ -> xt + cell +-> ip +\ execute token + xt is.primitive? + IF \ primitive + ip xt trace.do.primitive -> ip + ELSE \ secondary + trace_level trace_level_max < + IF + ip trace.>r \ threaded execution + 1 +-> trace_level + xt codebase + -> ip + ELSE + \ treat it as a primitive + ip xt trace.do.primitive -> ip + THEN + THEN +\ restore original context + trace.rcheck + trace.save.state2 + trace.restore.state1 + oldhere dp ! + ip +; + +: TRACE.NEXT { ip | xt -- ip' } + trace_level 0> + IF + ip trace.do.next -> ip + THEN + trace_level 0> + IF + ip trace.show.next + ELSE + trace-stack on + ." Finished." cr + THEN + ip +; + +}private + +: TRACE ( i*x -- i*x , setup trace environment ) + ' dup is.primitive? + IF + drop ." Sorry. You can't trace a primitive." cr + ELSE + 1 -> trace_level + trace_level -> trace_level_max + trace.0rp + >code -> trace_ip + trace_ip trace.show.next + trace-stack off + trace.save.state2 + THEN +; + +: s ( -- , step over ) + trace_level -> trace_level_max + trace_ip trace.next -> trace_ip +; + +: sd ( -- , step down ) + trace_level 1+ -> trace_level_max + trace_ip trace.next -> trace_ip +; + +: sm ( many -- , step many times ) + trace_level -> trace_level_max + 0 + ?DO + trace_ip trace.next -> trace_ip + LOOP +; + +defer trace.user ( IP -- stop? ) +' 0= is trace.user + +: gd { more_levels | stop_level -- } + here what's trace.user u< \ has it been forgotten? + IF + ." Resetting TRACE.USER !!!" cr + ['] 0= is trace.user + THEN + + more_levels 0< + more_levels 10 > + or \ 19990930 - OR was missing + IF + ." GD level out of range (0-10), = " more_levels . cr + ELSE + trace_level more_levels + -> trace_level_max + trace_level 1- -> stop_level + BEGIN + trace_ip trace.user \ call deferred user word + ?dup \ leave flag for UNTIL \ 19990930 - was DUP + IF + ." TRACE.USER returned " dup . ." so stopping execution." cr + ELSE + trace_ip trace.next -> trace_ip + trace_level stop_level > not + THEN + UNTIL + THEN +; + +: g ( -- , execute until end of word ) + 0 gd +; + +: TRACE.HELP ( -- ) + ." TRACE ( i*x -- , setup trace for Forth word )" cr + ." S ( -- , step over )" cr + ." SM ( many -- , step over many times )" cr + ." SD ( -- , step down )" cr + ." G ( -- , go to end of word )" cr + ." GD ( n -- , go down N levels from current level," cr + ." stop at end of this level )" cr +; + +privatize + +0 [IF] +variable var1 +100 var1 ! +: FOO dup IF 1 + . THEN 77 var1 @ + . ; +: ZOO 29 foo 99 22 + . ; +: ROO 92 >r 1 r@ + . r> . ; +: MOO c" hello" count type + ." This is a message." cr + s" another message" type cr +; +: KOO 7 FOO ." DONE" ; +: TR.DO 4 0 DO i . LOOP ; +: TR.?DO 0 ?DO i . LOOP ; +: TR.LOC1 { aa bb } aa bb + . ; +: TR.LOC2 789 >r 4 5 tr.loc1 r> . ; + +[THEN] diff --git a/src/cmd/pforth/fth/tut.fth b/src/cmd/pforth/fth/tut.fth new file mode 100644 index 0000000..957ae34 --- /dev/null +++ b/src/cmd/pforth/fth/tut.fth @@ -0,0 +1,70 @@ +anew task-tut.fth + +: SUM.OF.N.A ( N -- SUM[N] , calculate sum of N integers ) + 0 \ starting value of SUM + BEGIN + OVER 0> \ Is N greater than zero? + WHILE + OVER + \ add N to sum + SWAP 1- SWAP \ decrement N + REPEAT + SWAP DROP \ get rid on N + ; + +: SUM.OF.N.B ( N -- SUM[N] ) + 0 SWAP \ starting value of SUM + 1+ 0 \ set indices for DO LOOP + ?DO \ safer than DO if N=0 + I + + LOOP +; + +: SUM.OF.N.C ( N -- SUM[N] ) + 0 \ starting value of SUM + BEGIN ( -- N' SUM ) + OVER + + SWAP 1- SWAP + OVER 0< + UNTIL + SWAP DROP +; + +: SUM.OF.N.D ( N -- SUM[N] ) + >R \ put NUM on return stack + 0 \ starting value of SUM + BEGIN ( -- SUM ) + R@ + \ add num to sum + R> 1- DUP >R + 0< + UNTIL + RDROP \ get rid of NUM +; + +: SUM.OF.N.E { NUM | SUM -- SUM[N] , use return stack } + BEGIN + NUM +-> SUM \ add NUM to SUM + -1 +-> NUM \ decrement NUM + NUM 0< + UNTIL + SUM \ return SUM +; + +: SUM.OF.N.F ( NUM -- SUM[N] , Gauss' method ) + DUP 1+ * 2/ +; + + +: TTT + 10 0 + DO + I SUM.OF.N.A . + I SUM.OF.N.B . + I SUM.OF.N.C . + I SUM.OF.N.D . + I SUM.OF.N.E . + I SUM.OF.N.F . + CR + LOOP +; +TTT + diff --git a/src/cmd/pforth/fth/utils/clone.fth b/src/cmd/pforth/fth/utils/clone.fth new file mode 100644 index 0000000..377d363 --- /dev/null +++ b/src/cmd/pforth/fth/utils/clone.fth @@ -0,0 +1,489 @@ +\ @(#) clone.fth 97/12/10 1.1 +\ Clone for PForth +\ +\ Create the smallest dictionary required to run an application. +\ +\ Clone decompiles the Forth dictionary starting with the top +\ word in the program. It then moves all referenced secondaries +\ into a new dictionary. +\ +\ This work was inspired by the CLONE feature that Mike Haas wrote +\ for JForth. Mike's CLONE disassembled 68000 machine code then +\ reassembled it which is much more difficult. +\ +\ Copyright Phil Burk & 3DO 1994 +\ +\ O- trap custom 'C' calls +\ O- investigate ALITERAL, XLITERAL, use XLITERAL in ['] + +anew task-clone.fth +decimal + +\ move to 'C' +: PRIMITIVE? ( xt -- flag , true if primitive ) + ['] FIRST_COLON < +; + +: 'SELF ( -- xt , return xt of word being compiled ) + ?comp + latest name> + [compile] literal +; immediate + + +:struct CL.REFERENCE + long clr_OriginalXT \ original XT of word + long clr_NewXT \ corresponding XT in cloned dictionary + long clr_TotalSize \ size including data in body +;struct + +variable CL-INITIAL-REFS \ initial number of refs to allocate +100 cl-initial-refs ! +variable CL-REF-LEVEL \ level of threading while scanning +variable CL-NUM-REFS \ number of secondaries referenced +variable CL-MAX-REFS \ max number of secondaries allocated +variable CL-LEVEL-MAX \ max level reached while scanning +variable CL-LEVEL-ABORT \ max level before aborting +10 cl-level-abort ! +variable CL-REFERENCES \ pointer to cl.reference array +variable CL-TRACE \ print debug stuff if true + +\ Cloned dictionary builds in allocated memory but XTs are relative +\ to normal code-base, if CL-TEST-MODE true. +variable CL-TEST-MODE + +variable CL-INITIAL-DICT \ initial size of dict to allocate +20 1024 * cl-initial-dict ! +variable CL-DICT-SIZE \ size of allocated cloned dictionary +variable CL-DICT-BASE \ pointer to virtual base of cloned dictionary +variable CL-DICT-ALLOC \ pointer to allocated dictionary memory +variable CL-DICT-PTR \ rel pointer index into cloned dictionary +0 cl-dict-base ! + + +: CL.INDENT ( -- ) + cl-ref-level @ 2* 2* spaces +; +: CL.DUMP.NAME ( xt -- ) + cl.indent + >name id. cr +; + +: CL.DICT[] ( relptr -- addr ) + cl-dict-base @ + +; + +: CL, ( cell -- , comma into clone dictionary ) + cl-dict-ptr @ cl.dict[] ! + cell cl-dict-ptr +! +; + + +: CL.FREE.DICT ( -- , free dictionary we built into ) + cl-dict-alloc @ ?dup + IF + free dup ?error + 0 cl-dict-alloc ! + THEN +; + +: CL.FREE.REFS ( -- , free dictionary we built into ) + cl-references @ ?dup + IF + free dup ?error + 0 cl-references ! + THEN +; + +: CL.ALLOC.REFS ( -- , allocate references to track ) + cl-initial-refs @ \ initial number of references + dup cl-max-refs ! \ maximum allowed + sizeof() cl.reference * + allocate dup ?error + cl-references ! +; + +: CL.RESIZE.REFS ( -- , allocate references to track ) + cl-max-refs @ \ current number of references allocated + 5 * 4 / dup cl-max-refs ! \ new maximum allowed +\ cl.indent ." Resize # references to " dup . cr + sizeof() cl.reference * + cl-references @ swap resize dup ?error + cl-references ! +; + + +: CL.ALLOC.DICT ( -- , allocate dictionary to build into ) + cl-initial-dict @ \ initial dictionary size + dup cl-dict-size ! + allocate dup ?error + cl-dict-alloc ! +\ +\ kludge dictionary if testing + cl-test-mode @ + IF + cl-dict-alloc @ code-base @ - cl-dict-ptr +! + code-base @ cl-dict-base ! + ELSE + cl-dict-alloc @ cl-dict-base ! + THEN + ." CL.ALLOC.DICT" cr + ." cl-dict-alloc = $" cl-dict-alloc @ .hex cr + ." cl-dict-base = $" cl-dict-base @ .hex cr + ." cl-dict-ptr = $" cl-dict-ptr @ .hex cr +; + +: CODEADDR>DATASIZE { code-addr -- datasize } +\ Determine size of any literal data following execution token. +\ Examples are text following (."), or branch offsets. + code-addr @ + CASE + ['] (literal) OF cell ENDOF \ a number + ['] 0branch OF cell ENDOF \ branch offset + ['] branch OF cell ENDOF + ['] (do) OF 0 ENDOF + ['] (?do) OF cell ENDOF + ['] (loop) OF cell ENDOF + ['] (+loop) OF cell ENDOF + ['] (.") OF code-addr cell+ c@ 1+ ENDOF \ text + ['] (s") OF code-addr cell+ c@ 1+ ENDOF + ['] (c") OF code-addr cell+ c@ 1+ ENDOF + 0 swap + ENDCASE +; + +: XT>SIZE ( xt -- wordsize , including code and data ) + dup >code + swap >name + dup latest = + IF + drop here + ELSE + dup c@ 1+ + aligned 8 + \ get next name + name> >code \ where is next word + THEN + swap - +; + +\ ------------------------------------------------------------------ +: CL.TRAVERSE.SECONDARY { code-addr ca-process | xt dsize -- } +\ scan secondary and pass each code-address to ca-process +\ CA-PROCESS ( code-addr -- , required stack action for vector ) + 1 cl-ref-level +! + cl-ref-level @ cl-level-abort @ > abort" Clone exceeded CL-ABORT-LEVEL" + BEGIN + code-addr @ -> xt +\ cl.indent ." CL.TRAVERSE.SECONDARY - code-addr = $" code-addr .hex ." , xt = $" xt .hex cr + code-addr codeaddr>datasize -> dsize \ any data after this? + code-addr ca-process execute \ process it + code-addr cell+ dsize + aligned -> code-addr \ skip past data +\ !!! Bummer! EXIT called in middle of secondary will cause early stop. + xt ['] EXIT = \ stop when we get to EXIT + UNTIL + -1 cl-ref-level +! +; + +\ ------------------------------------------------------------------ + +: CL.DUMP.XT ( xt -- ) + cl-trace @ + IF + dup primitive? + IF ." PRI: " + ELSE ." SEC: " + THEN + cl.dump.name + ELSE + drop + THEN +; + +\ ------------------------------------------------------------------ +: CL.REF[] ( index -- clref ) + sizeof() cl.reference * + cl-references @ + +; + +: CL.DUMP.REFS ( -- , print references ) + cl-num-refs @ 0 + DO + i 3 .r ." : " + i cl.ref[] + dup s@ clr_OriginalXT >name id. ." => " + dup s@ clr_NewXT . + ." , size = " + dup s@ clr_TotalSize . cr + drop \ clref + loop +; + +: CL.XT>REF_INDEX { xt | indx flag -- index flag , true if found } + BEGIN +\ cl.indent ." CL.XT>REF_INDEX - indx = " indx . cr + indx cl-num-refs @ >= + IF + true + ELSE + indx cl.ref[] s@ clr_OriginalXT +\ cl.indent ." CL.XT>REF_INDEX - clr_OriginalXT = " dup . cr + xt = + IF + true + dup -> flag + ELSE + false + indx 1+ -> indx + THEN + THEN + UNTIL + indx flag +\ cl.indent ." CL.XT>REF_INDEX - " xt >name id. space indx . flag . cr +; + +: CL.ADD.REF { xt | clref -- , add referenced secondary to list } + cl-references @ 0= abort" CL.ADD.REF - References not allocated!" +\ +\ do we need to allocate more room? + cl-num-refs @ cl-max-refs @ >= + IF + cl.resize.refs + THEN +\ + cl-num-refs @ cl.ref[] -> clref \ index into array + xt clref s! clr_OriginalXT + 0 clref s! clr_NewXT + xt xt>size clref s! clr_TotalSize +\ + 1 cl-num-refs +! +; + +\ ------------------------------------------------------------------ + +\ called by cl.traverse.secondary to compile each piece of secondary +: CL.RECOMPILE.SECONDARY { code-addr | xt clref dsize -- , } +\ recompile to new location +\ cl.indent ." CL.RECOMPILE.SECONDARY - enter - " .s cr + code-addr @ -> xt +\ cl.indent ." CL.RECOMPILE.SECONDARY - xt = $" dup .hex dup >name id. cr + xt cl.dump.xt + xt primitive? + IF + xt cl, + ELSE + xt CL.XT>REF_INDEX + IF + cl.ref[] -> clref + clref s@ clr_NewXT + dup 0= abort" CL.RECOMPILE.SECONDARY - unresolved NewXT" + cl, + ELSE + cl.indent ." CL.RECOMPILE.SECONDARY - xt not in ref table!" cr + abort + THEN + THEN +\ +\ transfer any literal data + code-addr codeaddr>datasize -> dsize + dsize 0> + IF +\ cl.indent ." CL.RECOMPILE.SECONDARY - copy inline data of size" dsize . cr + code-addr cell+ cl-dict-ptr @ cl.dict[] dsize move + cl-dict-ptr @ dsize + aligned cl-dict-ptr ! + THEN +\ cl.indent ." CL.RECOMPILE.SECONDARY - leave - " .s cr +; + +: CL.RECOMPILE.REF { indx | clref codesize datasize -- } +\ all references have been resolved so recompile new secondary + depth >r + indx cl.ref[] -> clref + cl-trace @ + IF + cl.indent + clref s@ clr_OriginalXT >name id. ." recompiled at $" + cl-dict-ptr @ .hex cr \ new address + THEN + cl-dict-ptr @ clref s! clr_NewXT +\ +\ traverse this secondary and compile into new dictionary + clref s@ clr_OriginalXT + >code ['] cl.recompile.secondary cl.traverse.secondary +\ +\ determine whether there is any data following definition + cl-dict-ptr @ + clref s@ clr_NewXT - -> codesize \ size of cloned code + clref s@ clr_TotalSize \ total bytes + codesize - -> datasize + cl-trace @ + IF + cl.indent + ." Move data: data size = " datasize . ." codesize = " codesize . cr + THEN +\ +\ copy any data that followed definition + datasize 0> + IF + clref s@ clr_OriginalXT >code codesize + + clref s@ clr_NewXT cl-dict-base @ + codesize + + datasize move + datasize cl-dict-ptr +! \ allot space in clone dictionary + THEN + + depth r> - abort" Stack depth change in CL.RECOMPILE.REF" +; + +\ ------------------------------------------------------------------ +: CL.SCAN.SECONDARY ( code-addr -- , scan word and add referenced secondaries to list ) + depth 1- >r +\ cl.indent ." CL.SCAN.SECONDARY - enter - " .s cr + cl-ref-level @ cl-level-max @ MAX cl-level-max ! + @ ( get xt ) +\ cl.indent ." CL.SCAN.SECONDARY - xt = " dup . dup >name id. cr + dup cl.dump.xt + dup primitive? + IF + drop +\ cl.indent ." CL.SCAN.SECONDARY - found primitive." cr + ELSE + dup CL.XT>REF_INDEX + IF + drop \ indx \ already referenced once so ignore + drop \ xt + ELSE + >r \ indx + dup cl.add.ref + >code 'self cl.traverse.secondary \ use 'self for recursion! + r> cl.recompile.ref \ now that all refs resolved, recompile + THEN + THEN +\ cl.indent ." CL.SCAN.SECONDARY - leave - " .s cr + depth r> - abort" Stack depth change in CL.SCAN.SECONDARY" +; + +: CL.CLONE.XT ( xt -- , scan top word and add referenced secondaries to list ) + dup primitive? abort" Cannot CLONE a PRIMITIVE word!" + 0 cl-ref-level ! + 0 cl-level-max ! + 0 cl-num-refs ! + dup cl.add.ref \ word being cloned is top of ref list + >code ['] cl.scan.secondary cl.traverse.secondary + 0 cl.recompile.ref +; + +\ ------------------------------------------------------------------ +: CL.XT>NEW_XT ( xt -- xt' , convert normal xt to xt in cloned dict ) + cl.xt>ref_index 0= abort" not in cloned dictionary!" + cl.ref[] s@ clr_NewXT +; +: CL.XT>NEW_ADDR ( xt -- addr , addr in cloned dict ) + cl.xt>New_XT + cl-dict-base @ + +; + +: CL.REPORT ( -- ) + ." Clone scan went " cl-level-max @ . ." levels deep." cr + ." Clone scanned " cl-num-refs @ . ." secondaries." cr + ." New dictionary size = " cl-dict-ptr @ cl-dict-base @ - . cr +; + + +\ ------------------------------------------------------------------ +: CL.TERM ( -- , cleanup ) + cl.free.refs + cl.free.dict +; + +: CL.INIT ( -- ) + cl.term + 0 cl-dict-size ! + ['] first_colon cl-dict-ptr ! + cl.alloc.dict + cl.alloc.refs +; + +: 'CLONE ( xt -- , clone dictionary from this word ) + cl.init + cl.clone.xt + cl.report + cl.dump.refs + cl-test-mode @ + IF ." WARNING - CL-TEST-MODE on so we can't save cloned image." cr + THEN +; + +: SAVE-CLONE ( -- ) + bl word + ." Save cloned image in " dup count type + drop ." SAVE-CLONE unimplemented!" \ %Q +; + +: CLONE ( -- ) + ' 'clone +; + +if.forgotten cl.term + +\ ---------------------------------- TESTS -------------------- + + +: TEST.CLONE ( -- ) + cl-test-mode @ not abort" CL-TEST-MODE not on!" + 0 cl.ref[] s@ clr_NewXT execute +; + + +: TEST.CLONE.REAL ( -- ) + cl-test-mode @ abort" CL-TEST-MODE on!" + code-base @ + 0 cl.ref[] s@ clr_NewXT \ get cloned execution token + cl-dict-base @ code-base ! +\ WARNING - code-base munged, only execute primitives or cloned code + execute + code-base ! \ restore code base for normal +; + + +: TCL1 + 34 dup + +; + +: TCL2 + ." Hello " tcl1 . cr +; + +: TCL3 + 4 0 + DO + tcl2 + i . cr + i 100 + . cr + LOOP +; + +create VAR1 567 , +: TCL4 + 345 var1 ! + ." VAR1 = " var1 @ . cr + var1 @ 345 - + IF + ." TCL4 failed!" cr + ELSE + ." TCL4 succeded! Yay!" cr + THEN +; + +\ do deferred words get cloned! +defer tcl.vector + +: TCL.DOIT ." Hello Fred!" cr ; +' tcl.doit is tcl.vector + +: TCL.DEFER + 12 . cr + tcl.vector + 999 dup + . cr +; + +trace-stack on +cl-test-mode on + diff --git a/src/cmd/pforth/fth/utils/dump_struct.fth b/src/cmd/pforth/fth/utils/dump_struct.fth new file mode 100644 index 0000000..8dfd202 --- /dev/null +++ b/src/cmd/pforth/fth/utils/dump_struct.fth @@ -0,0 +1,122 @@ +\ @(#) dump_struct.fth 97/12/10 1.1 +\ Dump contents of structure showing values and member names. +\ +\ Author: Phil Burk +\ Copyright 1987 Phil Burk +\ All Rights Reserved. +\ +\ MOD: PLB 9/4/88 Print size too. +\ MOD: PLB 9/9/88 Print U/S , add ADST +\ MOD: PLB 12/6/90 Modified to work with H4th +\ 941109 PLB Converted to pforth. Added RP detection. +\ 090609 PLB Convert >rel to use->rel and ..! to s! + +include? task-member.fth member.fth +include? task-c_struct c_struct.fth + +ANEW TASK-DUMP_STRUCT + +: EMIT-TO-COLUMN ( char col -- ) + out @ - 0 max 80 min 0 + DO dup emit + LOOP drop +; + +VARIABLE SN-FENCE +: STACK.NFAS ( fencenfa topnfa -- 0 nfa0 nfa1 ... ) +\ Fill stack with nfas of words until fence hit. + >r sn-fence ! + 0 r> ( set terminator ) + BEGIN ( -- 0 n0 n1 ... top ) + dup sn-fence @ > + WHILE +\ dup n>link @ \ JForth + dup prevname \ HForth + REPEAT + drop +; + +: DST.DUMP.TYPE ( +-size -- , dump data type, 941109) + dup abs 4 = + IF + 0< + IF ." RP" + ELSE ." U4" + THEN + ELSE + dup 0< + IF ascii U + ELSE ascii S + THEN emit abs 1 .r + THEN +; + +: DUMP.MEMBER ( addr member-pfa -- , dump member of structure) + ob.stats ( -- addr offset size ) + >r + r> ( -- addr' size ) + dup ABS 4 > ( -- addr' size flag ) + IF cr 2dup swap . . ABS dump + ELSE tuck @bytes 10 .r ( -- size ) + 3 spaces dst.dump.type + THEN +; + +VARIABLE DS-ADDR +: DUMP.STRUCT ( addr-data addr-structure -- ) + >newline swap >r ( -- as , save addr-data for dumping ) +\ dup cell+ @ over + \ JForth + dup code> >name swap cell+ @ over + \ HForth + stack.nfas ( fill stack with nfas of members ) + BEGIN + dup + WHILE ( continue until non-zero ) + dup name> >body r@ swap dump.member + bl 18 emit-to-column id. cr + ?pause + REPEAT drop rdrop +; + +: DST ( addr -- , dump contents of structure ) + ob.findit + state @ + IF [compile] literal compile dump.struct + ELSE dump.struct + THEN +; immediate + +: ADST ( absolute_address -- , dump structure ) + use->rel [compile] dst \ mod 090609 +; immediate + +\ For Testing Purposes +false [IF] +:STRUCT GOO + LONG DATAPTR + SHORT GOO_WIDTH + USHORT GOO_HEIGHT +;STRUCT + +:STRUCT FOO + LONG ALONG1 + STRUCT GOO AGOO + SHORT ASHORT1 + BYTE ABYTE + BYTE ABYTE2 +;STRUCT + +FOO AFOO +: AFOO.INIT + $ 12345678 afoo s! along1 + $ -665 afoo s! ashort1 + $ 21 afoo s! abyte + $ 43 afoo s! abyte2 + -234 afoo .. agoo s! goo_height +; +afoo.init + +: TDS ( afoo -- ) + dst foo +; + +[THEN] + diff --git a/src/cmd/pforth/fth/utils/load_file.fth b/src/cmd/pforth/fth/utils/load_file.fth new file mode 100644 index 0000000..71f5e56 --- /dev/null +++ b/src/cmd/pforth/fth/utils/load_file.fth @@ -0,0 +1,39 @@ +\ Load a file into an allocated memory image. +\ +\ Author: Phil Burk +\ Copyright 3DO 1995 + +anew task-load_file.fth + +: $LOAD.FILE { $filename | fid numbytes numread err data -- data-addr 0 | 0 err } + 0 -> data +\ open file + $filename count r/o open-file -> err -> fid + err + IF + ." $LOAD.FILE - Could not open input file!" cr + ELSE +\ determine size of file + fid file-size -> err -> numbytes + err + IF + ." $LOAD.FILE - File size failed!" cr + ELSE + ." File size = " numbytes . cr +\ allocate memory for sample, when done free memory using FREE + numbytes allocate -> err -> data + err + IF + ." $LOAD.FILE - Memory allocation failed!" cr + ELSE +\ read data + data numbytes fid read-file -> err + ." Read " . ." bytes from file " $filename count type cr + THEN + THEN + fid close-file drop + THEN + data err +; + +\ Example: c" myfile" $load.file abort" Oops!" free . diff --git a/src/cmd/pforth/fth/utils/make_all256.fth b/src/cmd/pforth/fth/utils/make_all256.fth new file mode 100644 index 0000000..87f2a75 --- /dev/null +++ b/src/cmd/pforth/fth/utils/make_all256.fth @@ -0,0 +1,57 @@ +\ @(#) make_all256.fth 97/12/10 1.1 +\ Make a file with all possible 256 bytes in random order. +\ +\ Author: Phil Burk +\ Copyright 1987 Phil Burk +\ All Rights Reserved. + +ANEW TASK-MAKE_ALL256 + +variable RAND8-SEED +19 rand8-seed ! +: RANDOM8 ( -- r8 , generate random bytes, repeat every 256 ) + RAND8-SEED @ + 77 * 55 + + $ FF and + dup RAND8-SEED ! +; + +create rand8-pad 256 allot +: make.256.data + 256 0 + DO + random8 rand8-pad i + c! + LOOP +; + +: SHUFFLE.DATA { num | ind1 ind2 -- } + num 0 + DO + 256 choose -> ind1 + 256 choose -> ind2 + ind1 rand8-pad + c@ + ind2 rand8-pad + c@ + ind1 rand8-pad + c! + ind2 rand8-pad + c! + LOOP +; + +: WRITE.256.FILE { | fid -- } + p" all256.raw" count r/w create-file + IF + drop ." Could not create file." cr + ELSE + -> fid + fid . cr + rand8-pad 256 fid write-file abort" write failed!" + fid close-file drop + THEN +; + +: MAKE.256.FILE + make.256.data + 1000 shuffle.data + write.256.file +; + +MAKE.256.FILE diff --git a/src/cmd/pforth/fth/utils/trace.fth b/src/cmd/pforth/fth/utils/trace.fth new file mode 100644 index 0000000..e2b948d --- /dev/null +++ b/src/cmd/pforth/fth/utils/trace.fth @@ -0,0 +1,438 @@ +\ @(#) trace.fth 98/01/08 1.1 +\ TRACE ( -- , trace pForth word ) +\ +\ Single step debugger. +\ TRACE ( i*x -- , setup trace for Forth word ) +\ S ( -- , step over ) +\ SM ( many -- , step over many times ) +\ SD ( -- , step down ) +\ G ( -- , go to end of word ) +\ GD ( n -- , go down N levels from current level, stop at end of this level ) +\ +\ This debugger works by emulating the inner interpreter of pForth. +\ It executes code and maintains a separate return stack for the +\ program under test. Thus all primitives that operate on the return +\ stack, such as DO and R> must be trapped. Local variables must +\ also be handled specially. Several state variables are also +\ saved and restored to establish the context for the program being +\ tested. +\ +\ Copyright 1997 Phil Burk + +anew task-trace.fth + +: SPACE.TO.COLUMN ( col -- ) + out @ - spaces +; + +: IS.PRIMITIVE? ( xt -- flag , true if kernel primitive ) + ['] first_colon < +; + +0 value TRACE_IP \ instruction pointer +0 value TRACE_LEVEL \ level of descent for inner interpreter +0 value TRACE_LEVEL_MAX \ maximum level of descent + +private{ + +\ use fake return stack +128 cells constant TRACE_RETURN_SIZE \ size of return stack in bytes +create TRACE-RETURN-STACK TRACE_RETURN_SIZE 16 + allot +variable TRACE-RSP +: TRACE.>R ( n -- ) trace-rsp @ cell- dup trace-rsp ! ! ; \ *(--rsp) = n +: TRACE.R> ( -- n ) trace-rsp @ dup @ swap cell+ trace-rsp ! ; \ n = *rsp++ +: TRACE.R@ ( -- n ) trace-rsp @ @ ; ; \ n = *rsp +: TRACE.RPICK ( index -- n ) cells trace-rsp @ + @ ; ; \ n = rsp[index] +: TRACE.0RP ( -- n ) trace-return-stack trace_return_size + 8 + trace-rsp ! ; +: TRACE.RDROP ( -- ) cell trace-rsp +! ; +: TRACE.RCHECK ( -- , abort if return stack out of range ) + trace-rsp @ trace-return-stack u< + abort" TRACE return stack OVERFLOW!" + trace-rsp @ trace-return-stack trace_return_size + 12 + u> + abort" TRACE return stack UNDERFLOW!" +; + +\ save and restore several state variables +10 cells constant TRACE_STATE_SIZE +create TRACE-STATE-1 TRACE_STATE_SIZE allot +create TRACE-STATE-2 TRACE_STATE_SIZE allot + +variable TRACE-STATE-PTR +: TRACE.SAVE++ ( addr -- , save next thing ) + @ trace-state-ptr @ ! + cell trace-state-ptr +! +; + +: TRACE.SAVE.STATE ( -- ) + state trace.save++ + hld trace.save++ + base trace.save++ +; + +: TRACE.SAVE.STATE1 ( -- , save normal state ) + trace-state-1 trace-state-ptr ! + trace.save.state +; +: TRACE.SAVE.STATE2 ( -- , save state of word being debugged ) + trace-state-2 trace-state-ptr ! + trace.save.state +; + + +: TRACE.RESTORE++ ( addr -- , restore next thing ) + trace-state-ptr @ @ swap ! + cell trace-state-ptr +! +; + +: TRACE.RESTORE.STATE ( -- ) + state trace.restore++ + hld trace.restore++ + base trace.restore++ +; + +: TRACE.RESTORE.STATE1 ( -- ) + trace-state-1 trace-state-ptr ! + trace.restore.state +; +: TRACE.RESTORE.STATE2 ( -- ) + trace-state-2 trace-state-ptr ! + trace.restore.state +; + +\ The implementation of these pForth primitives is specific to pForth. + +variable TRACE-LOCALS-PTR \ point to top of local frame + +\ create a return stack frame for NUM local variables +: TRACE.(LOCAL.ENTRY) ( x0 x1 ... xn n -- ) { num | lp -- } + trace-locals-ptr @ trace.>r + trace-rsp @ trace-locals-ptr ! + trace-rsp @ num cells - trace-rsp ! \ make room for locals + trace-rsp @ -> lp + num 0 + DO + lp ! + cell +-> lp \ move data into locals frame on return stack + LOOP +; + +: TRACE.(LOCAL.EXIT) ( -- ) + trace-locals-ptr @ trace-rsp ! + trace.r> trace-locals-ptr ! +; +: TRACE.(LOCAL@) ( l# -- n , fetch from local frame ) + trace-locals-ptr @ swap cells - @ +; +: TRACE.(1_LOCAL@) ( -- n ) 1 trace.(local@) ; +: TRACE.(2_LOCAL@) ( -- n ) 2 trace.(local@) ; +: TRACE.(3_LOCAL@) ( -- n ) 3 trace.(local@) ; +: TRACE.(4_LOCAL@) ( -- n ) 4 trace.(local@) ; +: TRACE.(5_LOCAL@) ( -- n ) 5 trace.(local@) ; +: TRACE.(6_LOCAL@) ( -- n ) 6 trace.(local@) ; +: TRACE.(7_LOCAL@) ( -- n ) 7 trace.(local@) ; +: TRACE.(8_LOCAL@) ( -- n ) 8 trace.(local@) ; + +: TRACE.(LOCAL!) ( n l# -- , store into local frame ) + trace-locals-ptr @ swap cells - ! +; +: TRACE.(1_LOCAL!) ( -- n ) 1 trace.(local!) ; +: TRACE.(2_LOCAL!) ( -- n ) 2 trace.(local!) ; +: TRACE.(3_LOCAL!) ( -- n ) 3 trace.(local!) ; +: TRACE.(4_LOCAL!) ( -- n ) 4 trace.(local!) ; +: TRACE.(5_LOCAL!) ( -- n ) 5 trace.(local!) ; +: TRACE.(6_LOCAL!) ( -- n ) 6 trace.(local!) ; +: TRACE.(7_LOCAL!) ( -- n ) 7 trace.(local!) ; +: TRACE.(8_LOCAL!) ( -- n ) 8 trace.(local!) ; + +: TRACE.(LOCAL+!) ( n l# -- , store into local frame ) + trace-locals-ptr @ swap cells - +! +; +: TRACE.(?DO) { limit start ip -- ip' } + limit start = + IF + ip @ +-> ip \ BRANCH + ELSE + start trace.>r + limit trace.>r + cell +-> ip + THEN + ip +; + +: TRACE.(LOOP) { ip | limit indx -- ip' } + trace.r> -> limit + trace.r> 1+ -> indx + limit indx = + IF + cell +-> ip + ELSE + indx trace.>r + limit trace.>r + ip @ +-> ip + THEN + ip +; + +: TRACE.(+LOOP) { delta ip | limit indx oldindx -- ip' } + trace.r> -> limit + trace.r> -> oldindx + oldindx delta + -> indx +\ /* Do indices cross boundary between LIMIT-1 and LIMIT ? */ +\ if( ( (OldIndex - Limit) & ((Limit-1) - NewIndex) & 0x80000000 ) || +\ ( (NewIndex - Limit) & ((Limit-1) - OldIndex) & 0x80000000 ) ) + oldindx limit - limit 1- indx - AND $ 80000000 AND + indx limit - limit 1- oldindx - AND $ 80000000 AND OR + IF + cell +-> ip + ELSE + indx trace.>r + limit trace.>r + ip @ +-> ip + THEN + ip +; + +: TRACE.CHECK.IP { ip -- } + ip ['] first_colon u< + ip here u> OR + IF + ." TRACE - IP out of range = " ip .hex cr + abort + THEN +; + +: TRACE.SHOW.IP { ip -- , print name and offset } + ip code> >name dup id. + name> >code ip swap - ." +" . +; + +: TRACE.SHOW.STACK { | mdepth -- } + base @ >r + ." <" base @ decimal 1 .r ." :" + depth 1 .r ." > " + r> base ! + depth 5 min -> mdepth + depth mdepth - + IF + ." ... " \ if we don't show entire stack + THEN + mdepth 0 + ?DO + mdepth i 1+ - pick . \ show numbers in current base + LOOP +; + +: TRACE.SHOW.NEXT { ip -- } + >newline + ip trace.check.ip +\ show word name and offset + ." << " + ip trace.show.ip + 30 space.to.column +\ show data stack + trace.show.stack + 65 space.to.column ." ||" + trace_level 2* spaces + ip code@ + cell +-> ip +\ show primitive about to be executed + dup .xt space +\ trap any primitives that are followed by inline data + CASE + ['] (LITERAL) OF ip @ . ENDOF + ['] (ALITERAL) OF ip a@ . ENDOF +[ exists? (FLITERAL) [IF] ] + ['] (FLITERAL) OF ip f@ f. ENDOF +[ [THEN] ] + ['] BRANCH OF ip @ . ENDOF + ['] 0BRANCH OF ip @ . ENDOF + ['] (.") OF ip count type .' "' ENDOF + ['] (C") OF ip count type .' "' ENDOF + ['] (S") OF ip count type .' "' ENDOF + ENDCASE + 100 space.to.column ." >> " +; + +: TRACE.DO.PRIMITIVE { ip xt | oldhere -- ip' , perform code at ip } + xt + CASE + 0 OF -1 +-> trace_level trace.r> -> ip ENDOF \ EXIT + ['] (CREATE) OF ip cell- body_offset + ENDOF + ['] (LITERAL) OF ip @ cell +-> ip ENDOF + ['] (ALITERAL) OF ip a@ cell +-> ip ENDOF +[ exists? (FLITERAL) [IF] ] + ['] (FLITERAL) OF ip f@ 1 floats +-> ip ENDOF +[ [THEN] ] + ['] BRANCH OF ip @ +-> ip ENDOF + ['] 0BRANCH OF 0= IF ip @ +-> ip ELSE cell +-> ip THEN ENDOF + ['] >R OF trace.>r ENDOF + ['] R> OF trace.r> ENDOF + ['] R@ OF trace.r@ ENDOF + ['] RDROP OF trace.rdrop ENDOF + ['] 2>R OF trace.>r trace.>r ENDOF + ['] 2R> OF trace.r> trace.r> ENDOF + ['] 2R@ OF trace.r@ 1 trace.rpick ENDOF + ['] i OF 1 trace.rpick ENDOF + ['] j OF 3 trace.rpick ENDOF + ['] (LEAVE) OF trace.rdrop trace.rdrop ip @ +-> ip ENDOF + ['] (LOOP) OF ip trace.(loop) -> ip ENDOF + ['] (+LOOP) OF ip trace.(+loop) -> ip ENDOF + ['] (DO) OF trace.>r trace.>r ENDOF + ['] (?DO) OF ip trace.(?do) -> ip ENDOF + ['] (.") OF ip count type ip count + aligned -> ip ENDOF + ['] (C") OF ip ip count + aligned -> ip ENDOF + ['] (S") OF ip count ip count + aligned -> ip ENDOF + ['] (LOCAL.ENTRY) OF trace.(local.entry) ENDOF + ['] (LOCAL.EXIT) OF trace.(local.exit) ENDOF + ['] (LOCAL@) OF trace.(local@) ENDOF + ['] (1_LOCAL@) OF trace.(1_local@) ENDOF + ['] (2_LOCAL@) OF trace.(2_local@) ENDOF + ['] (3_LOCAL@) OF trace.(3_local@) ENDOF + ['] (4_LOCAL@) OF trace.(4_local@) ENDOF + ['] (5_LOCAL@) OF trace.(5_local@) ENDOF + ['] (6_LOCAL@) OF trace.(6_local@) ENDOF + ['] (7_LOCAL@) OF trace.(7_local@) ENDOF + ['] (8_LOCAL@) OF trace.(8_local@) ENDOF + ['] (LOCAL!) OF trace.(local!) ENDOF + ['] (1_LOCAL!) OF trace.(1_local!) ENDOF + ['] (2_LOCAL!) OF trace.(2_local!) ENDOF + ['] (3_LOCAL!) OF trace.(3_local!) ENDOF + ['] (4_LOCAL!) OF trace.(4_local!) ENDOF + ['] (5_LOCAL!) OF trace.(5_local!) ENDOF + ['] (6_LOCAL!) OF trace.(6_local!) ENDOF + ['] (7_LOCAL!) OF trace.(7_local!) ENDOF + ['] (8_LOCAL!) OF trace.(8_local!) ENDOF + ['] (LOCAL+!) OF trace.(local+!) ENDOF + >r xt EXECUTE r> + ENDCASE + ip +; + +: TRACE.DO.NEXT { ip | xt oldhere -- ip' , perform code at ip } + ip trace.check.ip +\ set context for word under test + trace.save.state1 + here -> oldhere + trace.restore.state2 + oldhere 256 + dp ! +\ get execution token + ip code@ -> xt + cell +-> ip +\ execute token + xt is.primitive? + IF \ primitive + ip xt trace.do.primitive -> ip + ELSE \ secondary + trace_level trace_level_max < + IF + ip trace.>r \ threaded execution + 1 +-> trace_level + xt codebase + -> ip + ELSE + \ treat it as a primitive + ip xt trace.do.primitive -> ip + THEN + THEN +\ restore original context + trace.rcheck + trace.save.state2 + trace.restore.state1 + oldhere dp ! + ip +; + +: TRACE.NEXT { ip | xt -- ip' } + trace_level 0> + IF + ip trace.do.next -> ip + THEN + trace_level 0> + IF + ip trace.show.next + ELSE + ." Finished." cr + THEN + ip +; + +}private + +: TRACE ( i*x -- i*x , setup trace environment ) + ' dup is.primitive? + IF + drop ." Sorry. You can't trace a primitive." cr + ELSE + 1 -> trace_level + trace_level -> trace_level_max + trace.0rp + >code -> trace_ip + trace_ip trace.show.next + trace-stack off + trace.save.state2 + THEN +; + +: s ( -- , step over ) + trace_level -> trace_level_max + trace_ip trace.next -> trace_ip +; + +: sd ( -- , step down ) + trace_level 1+ -> trace_level_max + trace_ip trace.next -> trace_ip +; + +: sm ( many -- , step down ) + trace_level -> trace_level_max + 0 + ?DO + trace_ip trace.next -> trace_ip + LOOP +; + +: gd { more_levels | stop_level -- } + depth 1 < + IF + ." GD requires a MORE_LEVELS parameter." cr + ELSE + trace_level more_levels + -> trace_level_max + trace_level 1- -> stop_level + BEGIN + trace_ip trace.next -> trace_ip + trace_level stop_level > not + UNTIL + THEN +; + +: g ( -- , execute until end of word ) + 0 gd +; + +: TRACE.HELP ( -- ) + ." TRACE ( i*x -- , setup trace for Forth word )" cr + ." S ( -- , step over )" cr + ." SM ( many -- , step over many times )" cr + ." SD ( -- , step down )" cr + ." G ( -- , go to end of word )" cr + ." GD ( n -- , go down N levels from current level," cr + ." stop at end of this level )" cr +; + +privatize + +0 [IF] +variable var1 +100 var1 ! +: FOO dup IF 1 + . THEN 77 var1 @ + . ; +: ZOO 29 foo 99 22 + . ; +: ROO 92 >r 1 r@ + . r> . ; +: MOO c" hello" count type + ." This is a message." cr + s" another message" type cr +; +: KOO 7 FOO ." DONE" ; +: TR.DO 4 0 DO i . LOOP ; +: TR.?DO 0 ?DO i . LOOP ; +: TR.LOC1 { aa bb } aa bb + . ; +: TR.LOC2 789 >r 4 5 tr.loc1 r> . ; +[THEN] diff --git a/src/cmd/pforth/fth/wordslik.fth b/src/cmd/pforth/fth/wordslik.fth new file mode 100644 index 0000000..adaa74f --- /dev/null +++ b/src/cmd/pforth/fth/wordslik.fth @@ -0,0 +1,44 @@ +\ @(#) wordslik.fth 98/01/26 1.2 +\ +\ WORDS.LIKE ( -- , search for words that contain string ) +\ +\ Enter: WORDS.LIKE + +\ Enter: WORDS.LIKE EMIT +\ +\ Author: Phil Burk +\ Copyright 1994 3DO, Phil Burk, Larry Polansky, Devid Rosenboom +\ +\ The pForth software code is dedicated to the public domain, +\ and any third party may reproduce, distribute and modify +\ the pForth software code or any derivative works thereof +\ without any compensation or license. The pForth software +\ code is provided on an "as is" basis without any warranty +\ of any kind, including, without limitation, the implied +\ warranties of merchantability and fitness for a particular +\ purpose and their equivalents under the laws of any jurisdiction. + +anew task-wordslik.fth +decimal + + +: PARTIAL.MATCH.NAME ( $str1 nfa -- flag , is $str1 in nfa ??? ) + count $ 1F and + rot count + search + >r 2drop r> +; + +: WORDS.LIKE ( -- , print all words containing substring ) + BL word latest + >newline + BEGIN + prevname dup 0<> \ get previous name in dictionary + WHILE + 2dup partial.match.name + IF + dup id. tab + cr? + THEN + REPEAT 2drop + >newline +; diff --git a/src/cmd/pforth/pf_all.h b/src/cmd/pforth/pf_all.h new file mode 100644 index 0000000..2c532b0 --- /dev/null +++ b/src/cmd/pforth/pf_all.h @@ -0,0 +1,67 @@ +/* @(#) pf_all.h 98/01/26 1.2 */ + +#ifndef _pf_all_h +#define _pf_all_h + +/*************************************************************** +** Include all files needed for PForth +** +** Author: Phil Burk +** Copyright 1994 3DO, Phil Burk, Larry Polansky, David Rosenboom +** +** The pForth software code is dedicated to the public domain, +** and any third party may reproduce, distribute and modify +** the pForth software code or any derivative works thereof +** without any compensation or license. The pForth software +** code is provided on an "as is" basis without any warranty +** of any kind, including, without limitation, the implied +** warranties of merchantability and fitness for a particular +** purpose and their equivalents under the laws of any jurisdiction. +** +** 940521 PLB Creation. +** +***************************************************************/ + +#ifdef PF_EMBEDDED + #define PF_NO_INIT + #define PF_NO_STDIO + #define PF_NO_MALLOC + #define PF_NO_CLIB + #define PF_NO_FILEIO +#endif + +/* I don't see any way to pass compiler flags to the Mac Code Warrior compiler! */ +#ifdef __MWERKS__ + #define PF_SUPPORT_FP (1) +#endif + +#ifdef WIN32 + #define PF_USER_INC2 "pf_win32.h" +#endif + +#if defined(PF_USER_INC1) + #include PF_USER_INC1 +#else + #include "pf_inc1.h" +#endif + +#include "pforth.h" +#include "pf_types.h" +#include "pf_io.h" +#include "pf_guts.h" +#include "pf_text.h" +#include "pfcompil.h" +#include "pf_clib.h" +#include "pf_words.h" +#include "pf_save.h" +#include "pf_mem.h" +#include "pf_cglue.h" +#include "pf_core.h" + +#ifdef PF_USER_INC2 +/* This could be used to undef and redefine macros. */ + #include PF_USER_INC2 +#endif + +#endif /* _pf_all_h */ + diff --git a/src/cmd/pforth/pf_cglue.c b/src/cmd/pforth/pf_cglue.c new file mode 100644 index 0000000..a2f351b --- /dev/null +++ b/src/cmd/pforth/pf_cglue.c @@ -0,0 +1,100 @@ +/* @(#) pf_cglue.c 98/02/11 1.4 */ +/*************************************************************** +** 'C' Glue support for Forth based on 'C' +** +** Author: Phil Burk +** Copyright 1994 3DO, Phil Burk, Larry Polansky, David Rosenboom +** +** The pForth software code is dedicated to the public domain, +** and any third party may reproduce, distribute and modify +** the pForth software code or any derivative works thereof +** without any compensation or license. The pForth software +** code is provided on an "as is" basis without any warranty +** of any kind, including, without limitation, the implied +** warranties of merchantability and fitness for a particular +** purpose and their equivalents under the laws of any jurisdiction. +** +***************************************************************/ + +#include "pf_all.h" + +extern CFunc0 CustomFunctionTable[]; + +/***************************************************************/ +cell_t CallUserFunction( cell_t Index, int32_t ReturnMode, int32_t NumParams ) +{ + cell_t P1, P2, P3, P4, P5; + cell_t Result = 0; + CFunc0 CF; + +DBUG(("CallUserFunction: Index = %d, ReturnMode = %d, NumParams = %d\n", + Index, ReturnMode, NumParams )); + + CF = CustomFunctionTable[Index]; + + switch( NumParams ) + { + case 0: + Result = ((CFunc0) CF) ( ); + break; + case 1: + P1 = POP_DATA_STACK; + Result = ((CFunc1) CF) ( P1 ); + break; + case 2: + P2 = POP_DATA_STACK; + P1 = POP_DATA_STACK; + Result = ((CFunc2) CF) ( P1, P2 ); + break; + case 3: + P3 = POP_DATA_STACK; + P2 = POP_DATA_STACK; + P1 = POP_DATA_STACK; + Result = ((CFunc3) CF) ( P1, P2, P3 ); + break; + case 4: + P4 = POP_DATA_STACK; + P3 = POP_DATA_STACK; + P2 = POP_DATA_STACK; + P1 = POP_DATA_STACK; + Result = ((CFunc4) CF) ( P1, P2, P3, P4 ); + break; + case 5: + P5 = POP_DATA_STACK; + P4 = POP_DATA_STACK; + P3 = POP_DATA_STACK; + P2 = POP_DATA_STACK; + P1 = POP_DATA_STACK; + Result = ((CFunc5) CF) ( P1, P2, P3, P4, P5 ); + break; + default: + pfReportError("CallUserFunction", PF_ERR_NUM_PARAMS); + EXIT(1); + } + +/* Push result on Forth stack if requested. */ + if(ReturnMode == C_RETURNS_VALUE) PUSH_DATA_STACK( Result ); + + return Result; +} + +#if (!defined(PF_NO_INIT)) && (!defined(PF_NO_SHELL)) +/***************************************************************/ +Err CreateGlueToC( const char *CName, ucell_t Index, cell_t ReturnMode, int32_t NumParams ) +{ + ucell_t Packed; + char FName[40]; + + CStringToForth( FName, CName, sizeof(FName) ); + Packed = (Index & 0xFFFF) | 0 | (NumParams << 24) | + (ReturnMode << 31); + DBUG(("Packed = 0x%8x\n", Packed)); + + ffCreateSecondaryHeader( FName ); + CODE_COMMA( ID_CALL_C ); + CODE_COMMA(Packed); + ffFinishSecondary(); + + return 0; +} +#endif diff --git a/src/cmd/pforth/pf_cglue.h b/src/cmd/pforth/pf_cglue.h new file mode 100644 index 0000000..8b39ef3 --- /dev/null +++ b/src/cmd/pforth/pf_cglue.h @@ -0,0 +1,45 @@ +/* @(#) pf_cglue.h 96/12/18 1.7 */ +#ifndef _pf_c_glue_h +#define _pf_c_glue_h + +/*************************************************************** +** Include file for PForth 'C' Glue support +** +** Author: Phil Burk +** Copyright 1994 3DO, Phil Burk, Larry Polansky, David Rosenboom +** +** The pForth software code is dedicated to the public domain, +** and any third party may reproduce, distribute and modify +** the pForth software code or any derivative works thereof +** without any compensation or license. The pForth software +** code is provided on an "as is" basis without any warranty +** of any kind, including, without limitation, the implied +** warranties of merchantability and fitness for a particular +** purpose and their equivalents under the laws of any jurisdiction. +** +***************************************************************/ + +typedef cell_t (*CFunc0)( void ); +typedef cell_t (*CFunc1)( cell_t P1 ); +typedef cell_t (*CFunc2)( cell_t P1, cell_t P2 ); +typedef cell_t (*CFunc3)( cell_t P1, cell_t P2, cell_t P3 ); +typedef cell_t (*CFunc4)( cell_t P1, cell_t P2, cell_t P3, cell_t P4 ); +typedef cell_t (*CFunc5)( cell_t P1, cell_t P2, cell_t P3, cell_t P4, cell_t P5 ); + +#ifdef __cplusplus +extern "C" { +#endif + +Err CreateGlueToC( const char *CName, ucell_t Index, cell_t ReturnMode, int32_t NumParams ); +Err CompileCustomFunctions( void ); +Err LoadCustomFunctionTable( void ); +cell_t CallUserFunction( cell_t Index, int32_t ReturnMode, int32_t NumParams ); + +#ifdef __cplusplus +} +#endif + +#define C_RETURNS_VOID (0) +#define C_RETURNS_VALUE (1) + +#endif /* _pf_c_glue_h */ diff --git a/src/cmd/pforth/pf_clib.c b/src/cmd/pforth/pf_clib.c new file mode 100644 index 0000000..e36e0fb --- /dev/null +++ b/src/cmd/pforth/pf_clib.c @@ -0,0 +1,64 @@ +/* @(#) pf_clib.c 96/12/18 1.12 */ +/*************************************************************** +** Duplicate functions from stdlib for PForth based on 'C' +** +** This code duplicates some of the code in the 'C' lib +** because it reduces the dependency on foreign libraries +** for monitor mode where no OS is available. +** +** Author: Phil Burk +** Copyright 1994 3DO, Phil Burk, Larry Polansky, David Rosenboom +** +** The pForth software code is dedicated to the public domain, +** and any third party may reproduce, distribute and modify +** the pForth software code or any derivative works thereof +** without any compensation or license. The pForth software +** code is provided on an "as is" basis without any warranty +** of any kind, including, without limitation, the implied +** warranties of merchantability and fitness for a particular +** purpose and their equivalents under the laws of any jurisdiction. +** +**************************************************************** +** 961124 PLB Advance pointers in pfCopyMemory() and pfSetMemory() +***************************************************************/ + +#include "pf_all.h" + +#ifdef PF_NO_CLIB +/* Count chars until NUL. Replace strlen() */ +#define NUL ((char) 0) +cell_t pfCStringLength( const char *s ) +{ + cell_t len = 0; + while( *s++ != NUL ) len++; + return len; +} + +/* void *memset (void *s, cell_t c, size_t n); */ +void *pfSetMemory( void *s, cell_t c, cell_t n ) +{ + uint8_t *p = s, byt = (uint8_t) c; + while( (n--) > 0) *p++ = byt; + return s; +} + +/* void *memccpy (void *s1, const void *s2, cell_t c, size_t n); */ +void *pfCopyMemory( void *s1, const void *s2, cell_t n) +{ + uint8_t *p1 = s1; + const uint8_t *p2 = s2; + while( (n--) > 0) *p1++ = *p2++; + return s1; +} + +#endif /* PF_NO_CLIB */ + +char pfCharToUpper( char c ) +{ + return (char) ( ((c>='a') && (c<='z')) ? (c - ('a' - 'A')) : c ); +} + +char pfCharToLower( char c ) +{ + return (char) ( ((c>='A') && (c<='Z')) ? (c + ('a' - 'A')) : c ); +} diff --git a/src/cmd/pforth/pf_clib.h b/src/cmd/pforth/pf_clib.h new file mode 100644 index 0000000..b7f3bc6 --- /dev/null +++ b/src/cmd/pforth/pf_clib.h @@ -0,0 +1,63 @@ +/* @(#) pf_clib.h 96/12/18 1.10 */ +#ifndef _pf_clib_h +#define _pf_clib_h + +/*************************************************************** +** Include file for PForth tools +** +** Author: Phil Burk +** Copyright 1994 3DO, Phil Burk, Larry Polansky, David Rosenboom +** +** The pForth software code is dedicated to the public domain, +** and any third party may reproduce, distribute and modify +** the pForth software code or any derivative works thereof +** without any compensation or license. The pForth software +** code is provided on an "as is" basis without any warranty +** of any kind, including, without limitation, the implied +** warranties of merchantability and fitness for a particular +** purpose and their equivalents under the laws of any jurisdiction. +** +***************************************************************/ + +#ifdef PF_NO_CLIB + + #ifdef __cplusplus + extern "C" { + #endif + + cell_t pfCStringLength( const char *s ); + void *pfSetMemory( void *s, cell_t c, cell_t n ); + void *pfCopyMemory( void *s1, const void *s2, cell_t n); + #define EXIT(n) {while(1);} + + #ifdef __cplusplus + } + #endif + +#else /* PF_NO_CLIB */ + + #ifdef PF_USER_CLIB + #include PF_USER_CLIB + #else +/* Use stdlib functions if available because they are probably faster. */ + #define pfCStringLength strlen + #define pfSetMemory memset + #define pfCopyMemory memcpy + #define EXIT(n) exit(n) + #endif /* PF_USER_CLIB */ + +#endif /* !PF_NO_CLIB */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Always use my own functions to avoid macro expansion problems with tolower(*s++) */ +char pfCharToUpper( char c ); +char pfCharToLower( char c ); + +#ifdef __cplusplus +} +#endif + +#endif /* _pf_clib_h */ diff --git a/src/cmd/pforth/pf_core.c b/src/cmd/pforth/pf_core.c new file mode 100644 index 0000000..7a0fbb6 --- /dev/null +++ b/src/cmd/pforth/pf_core.c @@ -0,0 +1,584 @@ +/* @(#) pf_core.c 98/01/28 1.5 */ +/*************************************************************** +** Forth based on 'C' +** +** This file has the main entry points to the pForth library. +** +** Author: Phil Burk +** Copyright 1994 3DO, Phil Burk, Larry Polansky, David Rosenboom +** +** The pForth software code is dedicated to the public domain, +** and any third party may reproduce, distribute and modify +** the pForth software code or any derivative works thereof +** without any compensation or license. The pForth software +** code is provided on an "as is" basis without any warranty +** of any kind, including, without limitation, the implied +** warranties of merchantability and fitness for a particular +** purpose and their equivalents under the laws of any jurisdiction. +** +**************************************************************** +** 940502 PLB Creation. +** 940505 PLB More macros. +** 940509 PLB Moved all stack handling into inner interpreter. +** Added Create, Colon, Semicolon, HNumberQ, etc. +** 940510 PLB Got inner interpreter working with secondaries. +** Added (LITERAL). Compiles colon definitions. +** 940511 PLB Added conditionals, LITERAL, CREATE DOES> +** 940512 PLB Added DO LOOP DEFER, fixed R> +** 940520 PLB Added INCLUDE +** 940521 PLB Added NUMBER? +** 940930 PLB Outer Interpreter now uses deferred NUMBER? +** 941005 PLB Added ANSI locals, LEAVE, modularised +** 950320 RDG Added underflow checking for FP stack +** 970702 PLB Added STACK_SAFETY to FP stack size. +***************************************************************/ + +#include "pf_all.h" + +/*************************************************************** +** Global Data +***************************************************************/ + +char gScratch[TIB_SIZE]; +pfTaskData_t *gCurrentTask = NULL; +pfDictionary_t *gCurrentDictionary; +cell_t gNumPrimitives; + +ExecToken gLocalCompiler_XT; /* custom compiler for local variables */ +ExecToken gNumberQ_XT; /* XT of NUMBER? */ +ExecToken gQuitP_XT; /* XT of (QUIT) */ +ExecToken gAcceptP_XT; /* XT of ACCEPT */ + +/* Depth of data stack when colon called. */ +cell_t gDepthAtColon; + +/* Global Forth variables. */ +cell_t gVarContext; /* Points to last name field. */ +cell_t gVarState; /* 1 if compiling. */ +cell_t gVarBase; /* Numeric Base. */ +cell_t gVarEcho; /* Echo input. */ +cell_t gVarTraceLevel; /* Trace Level for Inner Interpreter. */ +cell_t gVarTraceStack; /* Dump Stack each time if true. */ +cell_t gVarTraceFlags; /* Enable various internal debug messages. */ +cell_t gVarQuiet; /* Suppress unnecessary messages, OK, etc. */ +cell_t gVarReturnCode; /* Returned to caller of Forth, eg. UNIX shell. */ + +/* data for INCLUDE that allows multiple nested files. */ +IncludeFrame gIncludeStack[MAX_INCLUDE_DEPTH]; +cell_t gIncludeIndex; + +static void pfResetForthTask( void ); +static void pfInit( void ); +static void pfTerm( void ); + +/* TODO move to pf_config.h header. */ +#define DEFAULT_RETURN_DEPTH (512) +#define DEFAULT_USER_DEPTH (512) +#define DEFAULT_HEADER_SIZE (120000) +#define DEFAULT_CODE_SIZE (300000) + +/* Initialize globals in a function to simplify loading on + * embedded systems which may not support initialization of data section. + */ +static void pfInit( void ) +{ +/* all zero */ + gCurrentTask = NULL; + gCurrentDictionary = NULL; + gNumPrimitives = 0; + gLocalCompiler_XT = 0; + gVarContext = (cell_t)NULL; /* Points to last name field. */ + gVarState = 0; /* 1 if compiling. */ + gVarEcho = 0; /* Echo input. */ + gVarTraceLevel = 0; /* Trace Level for Inner Interpreter. */ + gVarTraceFlags = 0; /* Enable various internal debug messages. */ + gVarReturnCode = 0; /* Returned to caller of Forth, eg. UNIX shell. */ + gIncludeIndex = 0; + +/* non-zero */ + gVarBase = 10; /* Numeric Base. */ + gDepthAtColon = DEPTH_AT_COLON_INVALID; + gVarTraceStack = 1; + + pfInitMemoryAllocator(); + ioInit(); +} +static void pfTerm( void ) +{ + ioTerm(); +} + +/*************************************************************** +** Task Management +***************************************************************/ + +void pfDeleteTask( PForthTask task ) +{ + pfTaskData_t *cftd = (pfTaskData_t *)task; + FREE_VAR( cftd->td_ReturnLimit ); + FREE_VAR( cftd->td_StackLimit ); + pfFreeMem( cftd ); +} + +/* Allocate some extra cells to protect against mild stack underflows. */ +#define STACK_SAFETY (8) +PForthTask pfCreateTask( cell_t UserStackDepth, cell_t ReturnStackDepth ) +{ + pfTaskData_t *cftd; + + cftd = ( pfTaskData_t * ) pfAllocMem( sizeof( pfTaskData_t ) ); + if( !cftd ) goto nomem; + pfSetMemory( cftd, 0, sizeof( pfTaskData_t )); + +/* Allocate User Stack */ + cftd->td_StackLimit = (cell_t *) pfAllocMem((ucell_t)(sizeof(cell_t) * + (UserStackDepth + STACK_SAFETY))); + if( !cftd->td_StackLimit ) goto nomem; + cftd->td_StackBase = cftd->td_StackLimit + UserStackDepth; + cftd->td_StackPtr = cftd->td_StackBase; + +/* Allocate Return Stack */ + cftd->td_ReturnLimit = (cell_t *) pfAllocMem((ucell_t)(sizeof(cell_t) * ReturnStackDepth) ); + if( !cftd->td_ReturnLimit ) goto nomem; + cftd->td_ReturnBase = cftd->td_ReturnLimit + ReturnStackDepth; + cftd->td_ReturnPtr = cftd->td_ReturnBase; + +/* Allocate Float Stack */ +#ifdef PF_SUPPORT_FP +/* Allocate room for as many Floats as we do regular data. */ + cftd->td_FloatStackLimit = (PF_FLOAT *) pfAllocMem((ucell_t)(sizeof(PF_FLOAT) * + (UserStackDepth + STACK_SAFETY))); + if( !cftd->td_FloatStackLimit ) goto nomem; + cftd->td_FloatStackBase = cftd->td_FloatStackLimit + UserStackDepth; + cftd->td_FloatStackPtr = cftd->td_FloatStackBase; +#endif + + cftd->td_InputStream = PF_STDIN; + + cftd->td_SourcePtr = &cftd->td_TIB[0]; + cftd->td_SourceNum = 0; + + return (PForthTask) cftd; + +nomem: + ERR("CreateTaskContext: insufficient memory.\n"); + if( cftd ) pfDeleteTask( (PForthTask) cftd ); + return NULL; +} + +/*************************************************************** +** Dictionary Management +***************************************************************/ + +cell_t pfExecIfDefined( const char *CString ) +{ + int result = 0; + if( NAME_BASE != (cell_t)NULL) + { + ExecToken XT; + if( ffFindC( CString, &XT ) ) + { + result = pfCatch( XT ); + } + } + return result; +} + +/*************************************************************** +** Delete a dictionary created by pfCreateDictionary() +*/ +void pfDeleteDictionary( PForthDictionary dictionary ) +{ + pfDictionary_t *dic = (pfDictionary_t *) dictionary; + if( !dic ) return; + + if( dic->dic_Flags & PF_DICF_ALLOCATED_SEGMENTS ) + { + FREE_VAR( dic->dic_HeaderBaseUnaligned ); + FREE_VAR( dic->dic_CodeBaseUnaligned ); + } + pfFreeMem( dic ); +} + +/*************************************************************** +** Create a complete dictionary. +** The dictionary consists of two parts, the header with the names, +** and the code portion. +** Delete using pfDeleteDictionary(). +** Return pointer to dictionary management structure. +*/ +PForthDictionary pfCreateDictionary( cell_t HeaderSize, cell_t CodeSize ) +{ +/* Allocate memory for initial dictionary. */ + pfDictionary_t *dic; + + dic = ( pfDictionary_t * ) pfAllocMem( sizeof( pfDictionary_t ) ); + if( !dic ) goto nomem; + pfSetMemory( dic, 0, sizeof( pfDictionary_t )); + + dic->dic_Flags |= PF_DICF_ALLOCATED_SEGMENTS; + +/* Align dictionary segments to preserve alignment of floats across hosts. + * Thank you Helmut Proelss for pointing out that this needs to be cast + * to (ucell_t) on 16 bit systems. + */ +#define DIC_ALIGNMENT_SIZE ((ucell_t)(0x10)) +#define DIC_ALIGN(addr) ((((ucell_t)(addr)) + DIC_ALIGNMENT_SIZE - 1) & ~(DIC_ALIGNMENT_SIZE - 1)) + +/* Allocate memory for header. */ + if( HeaderSize > 0 ) + { + dic->dic_HeaderBaseUnaligned = (ucell_t) pfAllocMem( (ucell_t) HeaderSize + DIC_ALIGNMENT_SIZE ); + if( !dic->dic_HeaderBaseUnaligned ) goto nomem; +/* Align header base. */ + dic->dic_HeaderBase = DIC_ALIGN(dic->dic_HeaderBaseUnaligned); + pfSetMemory( (char *) dic->dic_HeaderBase, 0xA5, (ucell_t) HeaderSize); + dic->dic_HeaderLimit = dic->dic_HeaderBase + HeaderSize; + dic->dic_HeaderPtr = dic->dic_HeaderBase; + } + else + { + dic->dic_HeaderBase = 0; + } + +/* Allocate memory for code. */ + dic->dic_CodeBaseUnaligned = (ucell_t) pfAllocMem( (ucell_t) CodeSize + DIC_ALIGNMENT_SIZE ); + if( !dic->dic_CodeBaseUnaligned ) goto nomem; + dic->dic_CodeBase = DIC_ALIGN(dic->dic_CodeBaseUnaligned); + pfSetMemory( (char *) dic->dic_CodeBase, 0x5A, (ucell_t) CodeSize); + + dic->dic_CodeLimit = dic->dic_CodeBase + CodeSize; + dic->dic_CodePtr.Byte = ((uint8_t *) (dic->dic_CodeBase + QUADUP(NUM_PRIMITIVES))); + + return (PForthDictionary) dic; +nomem: + pfDeleteDictionary( dic ); + return NULL; +} + +/*************************************************************** +** Used by Quit and other routines to restore system. +***************************************************************/ + +static void pfResetForthTask( void ) +{ +/* Go back to terminal input. */ + gCurrentTask->td_InputStream = PF_STDIN; + +/* Reset stacks. */ + gCurrentTask->td_StackPtr = gCurrentTask->td_StackBase; + gCurrentTask->td_ReturnPtr = gCurrentTask->td_ReturnBase; +#ifdef PF_SUPPORT_FP /* Reset Floating Point stack too! */ + gCurrentTask->td_FloatStackPtr = gCurrentTask->td_FloatStackBase; +#endif + +/* Advance >IN to end of input. */ + gCurrentTask->td_IN = gCurrentTask->td_SourceNum; + gVarState = 0; +} + +/*************************************************************** +** Set current task context. +***************************************************************/ + +void pfSetCurrentTask( PForthTask task ) +{ + gCurrentTask = (pfTaskData_t *) task; +} + +/*************************************************************** +** Set Quiet Flag. +***************************************************************/ + +void pfSetQuiet( cell_t IfQuiet ) +{ + gVarQuiet = (cell_t) IfQuiet; +} + +/*************************************************************** +** Query message status. +***************************************************************/ + +cell_t pfQueryQuiet( void ) +{ + return gVarQuiet; +} + +/*************************************************************** +** Top level interpreter. +***************************************************************/ +ThrowCode pfQuit( void ) +{ + ThrowCode exception; + int go = 1; + + while(go) + { + exception = ffOuterInterpreterLoop(); + if( exception == 0 ) + { + exception = ffOK(); + } + + switch( exception ) + { + case 0: + break; + + case THROW_BYE: + go = 0; + break; + + case THROW_ABORT: + default: + ffDotS(); + pfReportThrow( exception ); + pfHandleIncludeError(); + pfResetForthTask(); + break; + } + } + + return gVarReturnCode; +} + +/*************************************************************** +** Include file based on 'C' name. +***************************************************************/ + +cell_t pfIncludeFile( const char *FileName ) +{ + FileStream *fid; + cell_t Result; + char buffer[32]; + cell_t numChars, len; + +/* Open file. */ + fid = sdOpenFile( FileName, "r" ); + if( fid == NULL ) + { + ERR("pfIncludeFile could not open "); + ERR(FileName); + EMIT_CR; + return -1; + } + +/* Create a dictionary word named ::::FileName for FILE? */ + pfCopyMemory( &buffer[0], "::::", 4); + len = (cell_t) pfCStringLength(FileName); + numChars = ( len > (32-4-1) ) ? (32-4-1) : len; + pfCopyMemory( &buffer[4], &FileName[len-numChars], numChars+1 ); + CreateDicEntryC( ID_NOOP, buffer, 0 ); + + Result = ffIncludeFile( fid ); /* Also close the file. */ + +/* Create a dictionary word named ;;;; for FILE? */ + CreateDicEntryC( ID_NOOP, ";;;;", 0 ); + + return Result; +} + +/*************************************************************** +** Output 'C' string message. +** Use sdTerminalOut which works before initializing gCurrentTask. +***************************************************************/ +void pfDebugMessage( const char *CString ) +{ +#if 0 + while( *CString ) + { + char c = *CString++; + if( c == '\n' ) + { + sdTerminalOut( 0x0D ); + sdTerminalOut( 0x0A ); + pfDebugMessage( "DBG: " ); + } + else + { + sdTerminalOut( c ); + } + } +#else + (void)CString; +#endif +} + +/*************************************************************** +** Print a decimal number to debug output. +*/ +void pfDebugPrintDecimalNumber( int n ) +{ + pfDebugMessage( ConvertNumberToText( n, 10, TRUE, 1 ) ); +} + + +/*************************************************************** +** Output 'C' string message. +** This is provided to help avoid the use of printf() and other I/O +** which may not be present on a small embedded system. +** Uses ioType & ioEmit so requires that gCurrentTask has been initialized. +***************************************************************/ +void pfMessage( const char *CString ) +{ + ioType( CString, (cell_t) pfCStringLength(CString) ); +} + +/************************************************************************** +** Main entry point for pForth. +*/ +cell_t pfDoForth( const char *DicFileName, const char *SourceName, cell_t IfInit ) +{ + pfTaskData_t *cftd; + pfDictionary_t *dic = NULL; + cell_t Result = 0; + ExecToken EntryPoint = 0; + +#ifdef PF_USER_INIT + Result = PF_USER_INIT; + if( Result < 0 ) goto error1; +#endif + + pfInit(); + +/* Allocate Task structure. */ + pfDebugMessage("pfDoForth: call pfCreateTask()\n"); + cftd = pfCreateTask( DEFAULT_USER_DEPTH, DEFAULT_RETURN_DEPTH ); + + if( cftd ) + { + pfSetCurrentTask( cftd ); + + if( !gVarQuiet ) + { + MSG( "PForth V"PFORTH_VERSION ); + if( IsHostLittleEndian() ) MSG("-LE"); + else MSG("-BE"); +#if PF_BIG_ENDIAN_DIC + MSG("/BE"); +#elif PF_LITTLE_ENDIAN_DIC + MSG("/LE"); +#endif + if (sizeof(cell_t) == 8) + { + MSG("/64"); + } + else if (sizeof(cell_t) == 4) + { + MSG("/32"); + } + + MSG( ", built "__DATE__" "__TIME__ ); + } + +/* Don't use MSG before task set. */ + if( SourceName ) + { + pfDebugMessage("SourceName = "); pfDebugMessage(SourceName); pfDebugMessage("\n"); + } + + +#ifdef PF_NO_GLOBAL_INIT + if( LoadCustomFunctionTable() < 0 ) goto error2; /* Init custom 'C' call array. */ +#endif + +#if (!defined(PF_NO_INIT)) && (!defined(PF_NO_SHELL)) + if( IfInit ) + { + pfDebugMessage("Build dictionary from scratch.\n"); + dic = pfBuildDictionary( DEFAULT_HEADER_SIZE, DEFAULT_CODE_SIZE ); + } + else +#else + TOUCH(IfInit); +#endif /* !PF_NO_INIT && !PF_NO_SHELL*/ + { + if( DicFileName ) + { + pfDebugMessage("DicFileName = "); pfDebugMessage(DicFileName); pfDebugMessage("\n"); + EMIT_CR; + dic = pfLoadDictionary( DicFileName, &EntryPoint ); + } + else + { + MSG(" (static)"); + EMIT_CR; + dic = pfLoadStaticDictionary(); + } + } + if( dic == NULL ) goto error2; + + if( !gVarQuiet ) + { + EMIT_CR; + } + + pfDebugMessage("pfDoForth: try AUTO.INIT\n"); + Result = pfExecIfDefined("AUTO.INIT"); + if( Result != 0 ) + { + MSG("Error in AUTO.INIT"); + goto error2; + } + + if( EntryPoint != 0 ) + { + Result = pfCatch( EntryPoint ); + } +#ifndef PF_NO_SHELL + else + { + if( SourceName == NULL ) + { + pfDebugMessage("pfDoForth: pfQuit\n"); + Result = pfQuit(); + } + else + { + if( !gVarQuiet ) + { + MSG("Including: "); + MSG(SourceName); + MSG("\n"); + } + Result = pfIncludeFile( SourceName ); + } + } +#endif /* PF_NO_SHELL */ + + /* Clean up after running Forth. */ + pfExecIfDefined("AUTO.TERM"); + pfDeleteDictionary( dic ); + pfDeleteTask( cftd ); + } + + pfTerm(); + +#ifdef PF_USER_TERM + PF_USER_TERM; +#endif + + return Result; + +error2: + MSG("pfDoForth: Error occured.\n"); + pfDeleteTask( cftd ); + /* Terminate so we restore normal shell tty mode. */ + pfTerm(); + +#ifdef PF_USER_INIT +error1: +#endif + + return -1; +} + + +#ifdef PF_UNIT_TEST +cell_t pfUnitTest( void ) +{ + cell_t numErrors = 0; + numErrors += pfUnitTestText(); + return numErrors; +} +#endif diff --git a/src/cmd/pforth/pf_core.h b/src/cmd/pforth/pf_core.h new file mode 100644 index 0000000..451fad2 --- /dev/null +++ b/src/cmd/pforth/pf_core.h @@ -0,0 +1,38 @@ +/* @(#) pf_core.h 98/01/26 1.3 */ +#ifndef _pf_core_h +#define _pf_core_h + +/*************************************************************** +** Include file for PForth 'C' Glue support +** +** Author: Phil Burk +** Copyright 1994 3DO, Phil Burk, Larry Polansky, David Rosenboom +** +** The pForth software code is dedicated to the public domain, +** and any third party may reproduce, distribute and modify +** the pForth software code or any derivative works thereof +** without any compensation or license. The pForth software +** code is provided on an "as is" basis without any warranty +** of any kind, including, without limitation, the implied +** warranties of merchantability and fitness for a particular +** purpose and their equivalents under the laws of any jurisdiction. +** +***************************************************************/ + +#ifdef __cplusplus +extern "C" { +#endif + +void pfInitGlobals( void ); + +void pfDebugMessage( const char *CString ); +void pfDebugPrintDecimalNumber( int n ); + +cell_t pfUnitTestText( void ); + +#ifdef __cplusplus +} +#endif + + +#endif /* _pf_core_h */ diff --git a/src/cmd/pforth/pf_float.h b/src/cmd/pforth/pf_float.h new file mode 100644 index 0000000..f6761a5 --- /dev/null +++ b/src/cmd/pforth/pf_float.h @@ -0,0 +1,43 @@ +/* @(#) pf_float.h 98/01/28 1.1 */ +#ifndef _pf_float_h +#define _pf_float_h + +/*************************************************************** +** Include file for PForth, a Forth based on 'C' +** +** Author: Phil Burk +** Copyright 1994 3DO, Phil Burk, Larry Polansky, David Rosenboom +** +** The pForth software code is dedicated to the public domain, +** and any third party may reproduce, distribute and modify +** the pForth software code or any derivative works thereof +** without any compensation or license. The pForth software +** code is provided on an "as is" basis without any warranty +** of any kind, including, without limitation, the implied +** warranties of merchantability and fitness for a particular +** purpose and their equivalents under the laws of any jurisdiction. +** +***************************************************************/ + +typedef double PF_FLOAT; + +/* Define pForth specific math functions. */ + +#define fp_acos acos +#define fp_asin asin +#define fp_atan atan +#define fp_atan2 atan2 +#define fp_cos cos +#define fp_cosh cosh +#define fp_fabs fabs +#define fp_floor floor +#define fp_log log +#define fp_log10 log10 +#define fp_pow pow +#define fp_sin sin +#define fp_sinh sinh +#define fp_sqrt sqrt +#define fp_tan tan +#define fp_tanh tanh + +#endif diff --git a/src/cmd/pforth/pf_guts.h b/src/cmd/pforth/pf_guts.h new file mode 100644 index 0000000..e659623 --- /dev/null +++ b/src/cmd/pforth/pf_guts.h @@ -0,0 +1,597 @@ +/* @(#) pf_guts.h 98/01/28 1.4 */ +#ifndef _pf_guts_h +#define _pf_guts_h + +/*************************************************************** +** Include file for PForth, a Forth based on 'C' +** +** Author: Phil Burk +** Copyright 1994 3DO, Phil Burk, Larry Polansky, David Rosenboom +** +** The pForth software code is dedicated to the public domain, +** and any third party may reproduce, distribute and modify +** the pForth software code or any derivative works thereof +** without any compensation or license. The pForth software +** code is provided on an "as is" basis without any warranty +** of any kind, including, without limitation, the implied +** warranties of merchantability and fitness for a particular +** purpose and their equivalents under the laws of any jurisdiction. +** +***************************************************************/ + +/* +** PFORTH_VERSION changes when PForth is modified and released. +** See README file for version info. +*/ +#define PFORTH_VERSION "27" + +/* +** PFORTH_FILE_VERSION changes when incompatible changes are made +** in the ".dic" file format. +** +** FV3 - 950225 - Use ABS_TO_CODEREL for CodePtr. See file "pf_save.c". +** FV4 - 950309 - Added NameSize and CodeSize to pfSaveForth(). +** FV5 - 950316 - Added Floats and reserved words. +** FV6 - 961213 - Added ID_LOCAL_PLUSSTORE, ID_COLON_P, etc. +** FV7 - 971203 - Added ID_FILL, (1LOCAL@), etc., ran out of reserved, resorted. +** FV8 - 980818 - Added Endian flag. +** FV9 - 20100503 - Added support for 64-bit CELL. +*/ +#define PF_FILE_VERSION (9) /* Bump this whenever primitives added. */ +#define PF_EARLIEST_FILE_VERSION (9) /* earliest one still compatible */ + +/*************************************************************** +** Sizes and other constants +***************************************************************/ + +#define TIB_SIZE (256) + +#ifndef FALSE + #define FALSE (0) +#endif +#ifndef TRUE + #define TRUE (1) +#endif + +#define FFALSE (0) +#define FTRUE (-1) +#define BLANK (' ') + +#define FLAG_PRECEDENCE (0x80) +#define FLAG_IMMEDIATE (0x40) +#define FLAG_SMUDGE (0x20) +#define MASK_NAME_SIZE (0x1F) + +/* Debug TRACE flags */ +#define TRACE_INNER (0x0002) +#define TRACE_COMPILE (0x0004) +#define TRACE_SPECIAL (0x0008) + +/* Numeric types returned by NUMBER? */ +#define NUM_TYPE_BAD (0) +#define NUM_TYPE_SINGLE (1) +#define NUM_TYPE_DOUBLE (2) +#define NUM_TYPE_FLOAT (3) + +#define CREATE_BODY_OFFSET (3*sizeof(cell_t)) + +/*************************************************************** +** Primitive Token IDS +** Do NOT change the order of these IDs or dictionary files will break! +***************************************************************/ +enum cforth_primitive_ids +{ + ID_EXIT = 0, /* ID_EXIT must always be zero. */ +/* Do NOT change the order of these IDs or dictionary files will break! */ + ID_1MINUS, + ID_1PLUS, + ID_2DUP, + ID_2LITERAL, + ID_2LITERAL_P, + ID_2MINUS, + ID_2OVER, + ID_2PLUS, + ID_2SWAP, + ID_2_R_FETCH, + ID_2_R_FROM, + ID_2_TO_R, + ID_ACCEPT_P, + ID_ALITERAL, + ID_ALITERAL_P, + ID_ALLOCATE, + ID_AND, + ID_ARSHIFT, + ID_BAIL, + ID_BODY_OFFSET, + ID_BRANCH, + ID_BYE, + ID_CALL_C, + ID_CFETCH, + ID_CMOVE, + ID_CMOVE_UP, + ID_COLON, + ID_COLON_P, + ID_COMPARE, + ID_COMP_EQUAL, + ID_COMP_GREATERTHAN, + ID_COMP_LESSTHAN, + ID_COMP_NOT_EQUAL, + ID_COMP_U_GREATERTHAN, + ID_COMP_U_LESSTHAN, + ID_COMP_ZERO_EQUAL, + ID_COMP_ZERO_GREATERTHAN, + ID_COMP_ZERO_LESSTHAN, + ID_COMP_ZERO_NOT_EQUAL, + ID_CR, + ID_CREATE, + ID_CREATE_P, + ID_CSTORE, + ID_DEFER, + ID_DEFER_P, + ID_DEPTH, + ID_DIVIDE, + ID_DOT, + ID_DOTS, + ID_DO_P, + ID_DROP, + ID_DUMP, + ID_DUP, + ID_D_MINUS, + ID_D_MTIMES, + ID_D_MUSMOD, + ID_D_PLUS, + ID_D_UMSMOD, + ID_D_UMTIMES, + ID_EMIT, + ID_EMIT_P, + ID_EOL, + ID_ERRORQ_P, + ID_EXECUTE, + ID_FETCH, + ID_FILE_CLOSE, + ID_FILE_CREATE, + ID_FILE_OPEN, + ID_FILE_POSITION, + ID_FILE_READ, + ID_FILE_REPOSITION, + ID_FILE_RO, + ID_FILE_RW, + ID_FILE_SIZE, + ID_FILE_WRITE, + ID_FILL, + ID_FIND, + ID_FINDNFA, + ID_FLUSHEMIT, + ID_FREE, + ID_HERE, + ID_NUMBERQ_P, + ID_I, + ID_INCLUDE_FILE, + ID_J, + ID_KEY, + ID_LEAVE_P, + ID_LITERAL, + ID_LITERAL_P, + ID_LOADSYS, + ID_LOCAL_COMPILER, + ID_LOCAL_ENTRY, + ID_LOCAL_EXIT, + ID_LOCAL_FETCH, + ID_LOCAL_FETCH_1, + ID_LOCAL_FETCH_2, + ID_LOCAL_FETCH_3, + ID_LOCAL_FETCH_4, + ID_LOCAL_FETCH_5, + ID_LOCAL_FETCH_6, + ID_LOCAL_FETCH_7, + ID_LOCAL_FETCH_8, + ID_LOCAL_PLUSSTORE, + ID_LOCAL_STORE, + ID_LOCAL_STORE_1, + ID_LOCAL_STORE_2, + ID_LOCAL_STORE_3, + ID_LOCAL_STORE_4, + ID_LOCAL_STORE_5, + ID_LOCAL_STORE_6, + ID_LOCAL_STORE_7, + ID_LOCAL_STORE_8, + ID_LOOP_P, + ID_LSHIFT, + ID_MAX, + ID_MIN, + ID_MINUS, + ID_NAME_TO_PREVIOUS, + ID_NAME_TO_TOKEN, + ID_NOOP, + ID_NUMBERQ, + ID_OR, + ID_OVER, + ID_PICK, + ID_PLUS, + ID_PLUSLOOP_P, + ID_PLUS_STORE, + ID_QDO_P, + ID_QDUP, + ID_QTERMINAL, + ID_QUIT_P, + ID_REFILL, + ID_RESIZE, + ID_RESTORE_INPUT, + ID_ROLL, + ID_ROT, + ID_RP_FETCH, + ID_RP_STORE, + ID_RSHIFT, + ID_R_DROP, + ID_R_FETCH, + ID_R_FROM, + ID_SAVE_FORTH_P, + ID_SAVE_INPUT, + ID_SCAN, + ID_SEMICOLON, + ID_SKIP, + ID_SOURCE, + ID_SOURCE_ID, + ID_SOURCE_ID_POP, + ID_SOURCE_ID_PUSH, + ID_SOURCE_SET, + ID_SP_FETCH, + ID_SP_STORE, + ID_STORE, + ID_SWAP, + ID_TEST1, + ID_TEST2, + ID_TEST3, + ID_TICK, + ID_TIMES, + ID_TO_R, + ID_TYPE, + ID_TYPE_P, + ID_VAR_BASE, + ID_VAR_CODE_BASE, + ID_VAR_CODE_LIMIT, + ID_VAR_CONTEXT, + ID_VAR_DP, + ID_VAR_ECHO, + ID_VAR_HEADERS_BASE, + ID_VAR_HEADERS_LIMIT, + ID_VAR_HEADERS_PTR, + ID_VAR_NUM_TIB, + ID_VAR_OUT, + ID_VAR_RETURN_CODE, + ID_VAR_SOURCE_ID, + ID_VAR_STATE, + ID_VAR_TO_IN, + ID_VAR_TRACE_FLAGS, + ID_VAR_TRACE_LEVEL, + ID_VAR_TRACE_STACK, + ID_VLIST, + ID_WORD, + ID_WORD_FETCH, + ID_WORD_STORE, + ID_XOR, + ID_ZERO_BRANCH, + ID_CATCH, + ID_THROW, + ID_INTERPRET, + ID_FILE_WO, + ID_FILE_BIN, + /* Added to support 64 bit operation. */ + ID_CELL, + ID_CELLS, + /* DELETE-FILE */ + ID_FILE_DELETE, +/* If you add a word here, take away one reserved word below. */ +#ifdef PF_SUPPORT_FP +/* Only reserve space if we are adding FP so that we can detect +** unsupported primitives when loading dictionary. +*/ + ID_RESERVED01, + ID_RESERVED02, + ID_RESERVED03, + ID_RESERVED04, + ID_RESERVED05, + ID_RESERVED06, + ID_RESERVED07, + ID_RESERVED08, + ID_RESERVED09, + ID_RESERVED10, + ID_RESERVED11, + ID_RESERVED12, + ID_RESERVED13, + ID_FP_D_TO_F, + ID_FP_FSTORE, + ID_FP_FTIMES, + ID_FP_FPLUS, + ID_FP_FMINUS, + ID_FP_FSLASH, + ID_FP_F_ZERO_LESS_THAN, + ID_FP_F_ZERO_EQUALS, + ID_FP_F_LESS_THAN, + ID_FP_F_TO_D, + ID_FP_FFETCH, + ID_FP_FDEPTH, + ID_FP_FDROP, + ID_FP_FDUP, + ID_FP_FLITERAL, + ID_FP_FLITERAL_P, + ID_FP_FLOAT_PLUS, + ID_FP_FLOATS, + ID_FP_FLOOR, + ID_FP_FMAX, + ID_FP_FMIN, + ID_FP_FNEGATE, + ID_FP_FOVER, + ID_FP_FROT, + ID_FP_FROUND, + ID_FP_FSWAP, + ID_FP_FSTAR_STAR, + ID_FP_FABS, + ID_FP_FACOS, + ID_FP_FACOSH, + ID_FP_FALOG, + ID_FP_FASIN, + ID_FP_FASINH, + ID_FP_FATAN, + ID_FP_FATAN2, + ID_FP_FATANH, + ID_FP_FCOS, + ID_FP_FCOSH, + ID_FP_FLN, + ID_FP_FLNP1, + ID_FP_FLOG, + ID_FP_FSIN, + ID_FP_FSINCOS, + ID_FP_FSINH, + ID_FP_FSQRT, + ID_FP_FTAN, + ID_FP_FTANH, + ID_FP_FPICK, +#endif +/* Add new IDs by replacing reserved IDs or extending FP routines. */ +/* Do NOT change the order of these IDs or dictionary files will break! */ + NUM_PRIMITIVES /* This must always be LAST */ +}; + + + +/*************************************************************** +** THROW Codes +***************************************************************/ +/* ANSI standard definitions needed by pForth */ +#define THROW_ABORT (-1) +#define THROW_ABORT_QUOTE (-2) +#define THROW_STACK_OVERFLOW (-3) +#define THROW_STACK_UNDERFLOW (-4) +#define THROW_UNDEFINED_WORD (-13) +#define THROW_EXECUTING (-14) +#define THROW_PAIRS (-22) +#define THROW_FLOAT_STACK_UNDERFLOW ( -45) +#define THROW_QUIT (-56) + +/* THROW codes unique to pForth */ +#define THROW_BYE (-256) /* Exit program. */ +#define THROW_SEMICOLON (-257) /* Error detected at ; */ +#define THROW_DEFERRED (-258) /* Not a deferred word. Used in system.fth */ + +/*************************************************************** +** Structures +***************************************************************/ + +typedef struct pfTaskData_s +{ + cell_t *td_StackPtr; /* Primary data stack */ + cell_t *td_StackBase; + cell_t *td_StackLimit; + cell_t *td_ReturnPtr; /* Return stack */ + cell_t *td_ReturnBase; + cell_t *td_ReturnLimit; +#ifdef PF_SUPPORT_FP + PF_FLOAT *td_FloatStackPtr; + PF_FLOAT *td_FloatStackBase; + PF_FLOAT *td_FloatStackLimit; +#endif + cell_t *td_InsPtr; /* Instruction pointer, "PC" */ + FileStream *td_InputStream; +/* Terminal. */ + char td_TIB[TIB_SIZE]; /* Buffer for terminal input. */ + cell_t td_IN; /* Index into Source */ + cell_t td_SourceNum; /* #TIB after REFILL */ + char *td_SourcePtr; /* Pointer to TIB or other source. */ + cell_t td_LineNumber; /* Incremented on every refill. */ + cell_t td_OUT; /* Current output column. */ +} pfTaskData_t; + +typedef struct pfNode +{ + struct pfNode *n_Next; + struct pfNode *n_Prev; +} pfNode; + +/* Structure of header entry in dictionary. These will be stored in dictionary specific endian format*/ +typedef struct cfNameLinks +{ + cell_t cfnl_PreviousName; /* name relative address of previous */ + ExecToken cfnl_ExecToken; /* Execution token for word. */ +/* Followed by variable length name field. */ +} cfNameLinks; + +#define PF_DICF_ALLOCATED_SEGMENTS ( 0x0001) +typedef struct pfDictionary_s +{ + pfNode dic_Node; + ucell_t dic_Flags; +/* Headers contain pointers to names and dictionary. */ + + ucell_t dic_HeaderBaseUnaligned; + + ucell_t dic_HeaderBase; + ucell_t dic_HeaderPtr; + ucell_t dic_HeaderLimit; +/* Code segment contains tokenized code and data. */ + ucell_t dic_CodeBaseUnaligned; + ucell_t dic_CodeBase; + union + { + cell_t *Cell; + uint8_t *Byte; + } dic_CodePtr; + ucell_t dic_CodeLimit; +} pfDictionary_t; + +/* Save state of include when nesting files. */ +typedef struct IncludeFrame +{ + FileStream *inf_FileID; + cell_t inf_LineNumber; + cell_t inf_SourceNum; + cell_t inf_IN; + char inf_SaveTIB[TIB_SIZE]; +} IncludeFrame; + +#define MAX_INCLUDE_DEPTH (16) + +/*************************************************************** +** Prototypes +***************************************************************/ + +#ifdef __cplusplus +extern "C" { +#endif + +int pfCatch( ExecToken XT ); + +#ifdef __cplusplus +} +#endif + +/*************************************************************** +** External Globals +***************************************************************/ +extern pfTaskData_t *gCurrentTask; +extern pfDictionary_t *gCurrentDictionary; +extern char gScratch[TIB_SIZE]; +extern cell_t gNumPrimitives; + +extern ExecToken gLocalCompiler_XT; /* CFA of (LOCAL) compiler. */ +extern ExecToken gNumberQ_XT; /* XT of NUMBER? */ +extern ExecToken gQuitP_XT; /* XT of (QUIT) */ +extern ExecToken gAcceptP_XT; /* XT of ACCEPT */ + +#define DEPTH_AT_COLON_INVALID (-100) +extern cell_t gDepthAtColon; + +/* Global variables. */ +extern cell_t gVarContext; /* Points to last name field. */ +extern cell_t gVarState; /* 1 if compiling. */ +extern cell_t gVarBase; /* Numeric Base. */ +extern cell_t gVarEcho; /* Echo input from file. */ +extern cell_t gVarEchoAccept; /* Echo input from ACCEPT. */ +extern cell_t gVarTraceLevel; +extern cell_t gVarTraceStack; +extern cell_t gVarTraceFlags; +extern cell_t gVarQuiet; /* Suppress unnecessary messages, OK, etc. */ +extern cell_t gVarReturnCode; /* Returned to caller of Forth, eg. UNIX shell. */ + +extern IncludeFrame gIncludeStack[MAX_INCLUDE_DEPTH]; +extern cell_t gIncludeIndex; +/*************************************************************** +** Macros +***************************************************************/ + + +/* Endian specific macros for creating target dictionaries for machines with + +** different endian-ness. + +*/ + +#if defined(PF_BIG_ENDIAN_DIC) + +#define WRITE_FLOAT_DIC WriteFloatBigEndian +#define WRITE_CELL_DIC(addr,data) WriteCellBigEndian((uint8_t *)(addr),(ucell_t)(data)) +#define WRITE_SHORT_DIC(addr,data) Write16BigEndian((uint8_t *)(addr),(uint16_t)(data)) +#define READ_FLOAT_DIC ReadFloatBigEndian +#define READ_CELL_DIC(addr) ReadCellBigEndian((const uint8_t *)(addr)) +#define READ_SHORT_DIC(addr) Read16BigEndian((const uint8_t *)(addr)) + +#elif defined(PF_LITTLE_ENDIAN_DIC) + +#define WRITE_FLOAT_DIC WriteFloatLittleEndian +#define WRITE_CELL_DIC(addr,data) WriteCellLittleEndian((uint8_t *)(addr),(ucell_t)(data)) +#define WRITE_SHORT_DIC(addr,data) Write16LittleEndian((uint8_t *)(addr),(uint16_t)(data)) +#define READ_FLOAT_DIC ReadFloatLittleEndian +#define READ_CELL_DIC(addr) ReadCellLittleEndian((const uint8_t *)(addr)) +#define READ_SHORT_DIC(addr) Read16LittleEndian((const uint8_t *)(addr)) + +#else + +#define WRITE_FLOAT_DIC(addr,data) { *((PF_FLOAT *)(addr)) = (PF_FLOAT)(data); } +#define WRITE_CELL_DIC(addr,data) { *((cell_t *)(addr)) = (cell_t)(data); } +#define WRITE_SHORT_DIC(addr,data) { *((int16_t *)(addr)) = (int16_t)(data); } +#define READ_FLOAT_DIC(addr) ( *((PF_FLOAT *)(addr)) ) +#define READ_CELL_DIC(addr) ( *((const ucell_t *)(addr)) ) +#define READ_SHORT_DIC(addr) ( *((const uint16_t *)(addr)) ) + +#endif + + +#define HEADER_HERE (gCurrentDictionary->dic_HeaderPtr.Cell) +#define CODE_HERE (gCurrentDictionary->dic_CodePtr.Cell) +#define CODE_COMMA( N ) WRITE_CELL_DIC(CODE_HERE++,(N)) +#define NAME_BASE (gCurrentDictionary->dic_HeaderBase) +#define CODE_BASE (gCurrentDictionary->dic_CodeBase) +#define NAME_SIZE (gCurrentDictionary->dic_HeaderLimit - gCurrentDictionary->dic_HeaderBase) +#define CODE_SIZE (gCurrentDictionary->dic_CodeLimit - gCurrentDictionary->dic_CodeBase) + +#define IN_CODE_DIC(addr) ( ( ((uint8_t *)(addr)) >= gCurrentDictionary->dic_CodeBase) && ( ((uint8_t *)(addr)) < gCurrentDictionary->dic_CodeLimit) ) + +#define IN_NAME_DIC(addr) ( ( ((uint8_t *)(addr)) >= gCurrentDictionary->dic_HeaderBase) && ( ((uint8_t *)(addr)) < gCurrentDictionary->dic_HeaderLimit) ) +#define IN_DICS(addr) (IN_CODE_DIC(addr) || IN_NAME_DIC(addr)) + +/* Address conversion */ +#define ABS_TO_NAMEREL( a ) ((cell_t) (((ucell_t) a) - NAME_BASE )) +#define ABS_TO_CODEREL( a ) ((cell_t) (((ucell_t) a) - CODE_BASE )) +#define NAMEREL_TO_ABS( a ) ((ucell_t) (((cell_t) a) + NAME_BASE)) +#define CODEREL_TO_ABS( a ) ((ucell_t) (((cell_t) a) + CODE_BASE)) + +/* The check for >0 is only needed for CLONE testing. !!! */ +#define IsTokenPrimitive(xt) ((xt=0)) + +#define FREE_VAR(v) { if (v) { pfFreeMem((void *)(v)); v = 0; } } + +#define DATA_STACK_DEPTH (gCurrentTask->td_StackBase - gCurrentTask->td_StackPtr) +#define DROP_DATA_STACK (gCurrentTask->td_StackPtr++) +#define POP_DATA_STACK (*gCurrentTask->td_StackPtr++) +#define PUSH_DATA_STACK(x) {*(--(gCurrentTask->td_StackPtr)) = (cell_t) x; } + +/* Force Quad alignment. */ +#define QUADUP(x) (((x)+3)&~3) + +#define MIN(a,b) ( ((a)<(b)) ? (a) : (b) ) +#define MAX(a,b) ( ((a)>(b)) ? (a) : (b) ) + + +#ifndef TOUCH + #define TOUCH(argument) ((void)argument) +#endif + +/*************************************************************** +** I/O related macros +***************************************************************/ + +#define EMIT(c) ioEmit(c) +#define EMIT_CR EMIT('\n'); + +#define MSG(cs) pfMessage(cs) +#define ERR(x) MSG(x) + +#define DBUG(x) /* PRT(x) */ +#define DBUGX(x) /* DBUG(x) */ + +#define MSG_NUM_D(msg,num) { MSG(msg); ffDot((cell_t) num); EMIT_CR; } +#define MSG_NUM_H(msg,num) { MSG(msg); ffDotHex((cell_t) num); EMIT_CR; } + +#define DBUG_NUM_D(msg,num) { pfDebugMessage(msg); pfDebugPrintDecimalNumber((cell_t) num); pfDebugMessage("\n"); } + +#endif /* _pf_guts_h */ diff --git a/src/cmd/pforth/pf_host.h b/src/cmd/pforth/pf_host.h new file mode 100644 index 0000000..c95b16f --- /dev/null +++ b/src/cmd/pforth/pf_host.h @@ -0,0 +1,24 @@ +/* @(#) pf_host.h 96/12/18 1.12 */ +#ifndef _pf_system_h +#define _pf_system_h + +/*************************************************************** +** System Dependant Includes for PForth based on 'C' +** +** Author: Phil Burk +** Copyright 1994 3DO, Phil Burk, Larry Polansky, David Rosenboom +** +** The pForth software code is dedicated to the public domain, +** and any third party may reproduce, distribute and modify +** the pForth software code or any derivative works thereof +** without any compensation or license. The pForth software +** code is provided on an "as is" basis without any warranty +** of any kind, including, without limitation, the implied +** warranties of merchantability and fitness for a particular +** purpose and their equivalents under the laws of any jurisdiction. +** +**************************************************************** +***************************************************************/ + +#endif /* _pf_system_h */ + diff --git a/src/cmd/pforth/pf_inc1.h b/src/cmd/pforth/pf_inc1.h new file mode 100644 index 0000000..41ac788 --- /dev/null +++ b/src/cmd/pforth/pf_inc1.h @@ -0,0 +1,48 @@ +/* @(#) pf_unix.h 98/01/28 1.4 */ +#ifndef _pf_embedded_h +#define _pf_embedded_h + +/*************************************************************** +** Embedded System include file for PForth, a Forth based on 'C' +** +** Author: Phil Burk +** Copyright 1994 3DO, Phil Burk, Larry Polansky, David Rosenboom +** +** The pForth software code is dedicated to the public domain, +** and any third party may reproduce, distribute and modify +** the pForth software code or any derivative works thereof +** without any compensation or license. The pForth software +** code is provided on an "as is" basis without any warranty +** of any kind, including, without limitation, the implied +** warranties of merchantability and fitness for a particular +** purpose and their equivalents under the laws of any jurisdiction. +** +***************************************************************/ + +#ifndef PF_NO_CLIB + #include /* Needed for strlen(), memcpy(), and memset(). */ + #include /* Needed for exit(). */ +#endif + +#ifdef PF_NO_STDIO + #define NULL ((void *) 0) + #define EOF (-1) +#else + #ifdef CROSS + #include + #else + #include + #endif +#endif + +#ifdef PF_SUPPORT_FP + #include + + #ifndef PF_USER_FP + #include "pf_float.h" + #else + #include PF_USER_FP + #endif +#endif + +#endif /* _pf_embedded_h */ diff --git a/src/cmd/pforth/pf_inner.c b/src/cmd/pforth/pf_inner.c new file mode 100644 index 0000000..4e200d0 --- /dev/null +++ b/src/cmd/pforth/pf_inner.c @@ -0,0 +1,1803 @@ +/* @(#) pf_inner.c 98/03/16 1.7 */ +/*************************************************************** +** Inner Interpreter for Forth based on 'C' +** +** Author: Phil Burk +** Copyright 1994 3DO, Phil Burk, Larry Polansky, David Rosenboom +** +** The pForth software code is dedicated to the public domain, +** and any third party may reproduce, distribute and modify +** the pForth software code or any derivative works thereof +** without any compensation or license. The pForth software +** code is provided on an "as is" basis without any warranty +** of any kind, including, without limitation, the implied +** warranties of merchantability and fitness for a particular +** purpose and their equivalents under the laws of any jurisdiction. +** +**************************************************************** +** +** 940502 PLB Creation. +** 940505 PLB More macros. +** 940509 PLB Moved all stack stuff into pfCatch. +** 941014 PLB Converted to flat secondary strusture. +** 941027 rdg added casts to ID_SP_FETCH, ID_RP_FETCH, +** and ID_HERE for armcc +** 941130 PLB Made w@ unsigned +** +***************************************************************/ + +#include + +#include "pf_all.h" + +#ifdef WIN32 +#include +#endif + +#define SYSTEM_LOAD_FILE "system.fth" + +/*************************************************************** +** Macros for data stack access. +** TOS is cached in a register in pfCatch. +***************************************************************/ + +#define STKPTR (DataStackPtr) +#define M_POP (*(STKPTR++)) +#define M_PUSH(n) {*(--(STKPTR)) = (cell_t) (n);} +#define M_STACK(n) (STKPTR[n]) + +#define TOS (TopOfStack) +#define PUSH_TOS M_PUSH(TOS) +#define M_DUP PUSH_TOS; +#define M_DROP { TOS = M_POP; } + + +/*************************************************************** +** Macros for Floating Point stack access. +***************************************************************/ +#ifdef PF_SUPPORT_FP +#define FP_STKPTR (FloatStackPtr) +#define M_FP_SPZERO (gCurrentTask->td_FloatStackBase) +#define M_FP_POP (*(FP_STKPTR++)) +#define M_FP_PUSH(n) {*(--(FP_STKPTR)) = (PF_FLOAT) (n);} +#define M_FP_STACK(n) (FP_STKPTR[n]) + +#define FP_TOS (fpTopOfStack) +#define PUSH_FP_TOS M_FP_PUSH(FP_TOS) +#define M_FP_DUP PUSH_FP_TOS; +#define M_FP_DROP { FP_TOS = M_FP_POP; } +#endif + +/*************************************************************** +** Macros for return stack access. +***************************************************************/ + +#define TORPTR (ReturnStackPtr) +#define M_R_DROP {TORPTR++;} +#define M_R_POP (*(TORPTR++)) +#define M_R_PICK(n) (TORPTR[n]) +#define M_R_PUSH(n) {*(--(TORPTR)) = (cell_t) (n);} + +/*************************************************************** +** Misc Forth macros +***************************************************************/ + +#define M_BRANCH { InsPtr = (cell_t *) (((uint8_t *) InsPtr) + READ_CELL_DIC(InsPtr)); } + +/* Cache top of data stack like in JForth. */ +#ifdef PF_SUPPORT_FP +#define LOAD_REGISTERS \ + { \ + STKPTR = gCurrentTask->td_StackPtr; \ + TOS = M_POP; \ + FP_STKPTR = gCurrentTask->td_FloatStackPtr; \ + FP_TOS = M_FP_POP; \ + TORPTR = gCurrentTask->td_ReturnPtr; \ + } + +#define SAVE_REGISTERS \ + { \ + gCurrentTask->td_ReturnPtr = TORPTR; \ + M_PUSH( TOS ); \ + gCurrentTask->td_StackPtr = STKPTR; \ + M_FP_PUSH( FP_TOS ); \ + gCurrentTask->td_FloatStackPtr = FP_STKPTR; \ + } + +#else +/* Cache top of data stack like in JForth. */ +#define LOAD_REGISTERS \ + { \ + STKPTR = gCurrentTask->td_StackPtr; \ + TOS = M_POP; \ + TORPTR = gCurrentTask->td_ReturnPtr; \ + } + +#define SAVE_REGISTERS \ + { \ + gCurrentTask->td_ReturnPtr = TORPTR; \ + M_PUSH( TOS ); \ + gCurrentTask->td_StackPtr = STKPTR; \ + } +#endif + +#define M_DOTS \ + SAVE_REGISTERS; \ + ffDotS( ); \ + LOAD_REGISTERS; + +#define DO_VAR(varname) { PUSH_TOS; TOS = (cell_t) &varname; } + +#ifdef PF_SUPPORT_FP +#define M_THROW(err) \ + { \ + ExceptionReturnCode = (ThrowCode)(err); \ + TORPTR = InitialReturnStack; /* Will cause return to 'C' */ \ + STKPTR = InitialDataStack; \ + FP_STKPTR = InitialFloatStack; \ + } +#else +#define M_THROW(err) \ + { \ + ExceptionReturnCode = (err); \ + TORPTR = InitialReturnStack; /* Will cause return to 'C' */ \ + STKPTR = InitialDataStack; \ + } +#endif + +/*************************************************************** +** Other macros +***************************************************************/ + +#define BINARY_OP( op ) { TOS = M_POP op TOS; } +#define endcase break + +#if defined(PF_NO_SHELL) || !defined(PF_SUPPORT_TRACE) + #define TRACENAMES /* no names */ +#else +/* Display name of executing routine. */ +static void TraceNames( ExecToken Token, cell_t Level ) +{ + char *DebugName; + cell_t i; + + if( ffTokenToName( Token, &DebugName ) ) + { + cell_t NumSpaces; + if( gCurrentTask->td_OUT > 0 ) EMIT_CR; + EMIT( '>' ); + for( i=0; itd_OUT; + for( i=0; i < NumSpaces; i++ ) + { + EMIT( ' ' ); + } + ffDotS(); +/* No longer needed? gCurrentTask->td_OUT = 0; */ /* !!! Hack for ffDotS() */ + + } + else + { + MSG_NUM_H("Couldn't find Name for ", Token); + } +} + +#define TRACENAMES \ + if( (gVarTraceLevel > Level) ) \ + { SAVE_REGISTERS; TraceNames( Token, Level ); LOAD_REGISTERS; } +#endif /* PF_NO_SHELL */ + +/* Use local copy of CODE_BASE for speed. */ +#define LOCAL_CODEREL_TO_ABS( a ) ((cell_t *) (((cell_t) a) + CodeBase)) + +static const char *pfSelectFileModeCreate( int fam ); +static const char *pfSelectFileModeOpen( int fam ); + +/**************************************************************/ +static const char *pfSelectFileModeCreate( int fam ) +{ + const char *famText = NULL; + switch( fam ) + { + case (PF_FAM_WRITE_ONLY + PF_FAM_BINARY_FLAG): + famText = PF_FAM_BIN_CREATE_WO; + break; + case (PF_FAM_READ_WRITE + PF_FAM_BINARY_FLAG): + famText = PF_FAM_BIN_CREATE_RW; + break; + case PF_FAM_WRITE_ONLY: + famText = PF_FAM_CREATE_WO; + break; + case PF_FAM_READ_WRITE: + famText = PF_FAM_CREATE_RW; + break; + default: + famText = "illegal"; + break; + } + return famText; +} + +/**************************************************************/ +static const char *pfSelectFileModeOpen( int fam ) +{ + const char *famText = NULL; + switch( fam ) + { + case (PF_FAM_READ_ONLY + PF_FAM_BINARY_FLAG): + famText = PF_FAM_BIN_OPEN_RO; + break; + case (PF_FAM_WRITE_ONLY + PF_FAM_BINARY_FLAG): + famText = PF_FAM_BIN_CREATE_WO; + break; + case (PF_FAM_READ_WRITE + PF_FAM_BINARY_FLAG): + famText = PF_FAM_BIN_OPEN_RW; + break; + case PF_FAM_READ_ONLY: + famText = PF_FAM_OPEN_RO; + break; + case PF_FAM_WRITE_ONLY: + famText = PF_FAM_CREATE_WO; + break; + case PF_FAM_READ_WRITE: + default: + famText = PF_FAM_OPEN_RW; + break; + } + return famText; +} + +/**************************************************************/ +int pfCatch( ExecToken XT ) +{ + register cell_t TopOfStack; /* Cache for faster execution. */ + register cell_t *DataStackPtr; + register cell_t *ReturnStackPtr; + register cell_t *InsPtr = NULL; + register cell_t Token; + cell_t Scratch; + +#ifdef PF_SUPPORT_FP + PF_FLOAT fpTopOfStack; + PF_FLOAT *FloatStackPtr; + PF_FLOAT fpScratch; + PF_FLOAT fpTemp; + PF_FLOAT *InitialFloatStack; +#endif +#ifdef PF_SUPPORT_TRACE + cell_t Level = 0; +#endif + cell_t *LocalsPtr = NULL; + cell_t Temp; + cell_t *InitialReturnStack; + cell_t *InitialDataStack; + cell_t FakeSecondary[2]; + char *CharPtr; + cell_t *CellPtr; + FileStream *FileID; + uint8_t *CodeBase = (uint8_t *) CODE_BASE; + ThrowCode ExceptionReturnCode = 0; + +/* FIXME + gExecutionDepth += 1; + PRT(("pfCatch( 0x%x ), depth = %d\n", XT, gExecutionDepth )); +*/ + +/* +** Initialize FakeSecondary this way to avoid having stuff in the data section, +** which is not supported for some embedded system loaders. +*/ + FakeSecondary[0] = 0; + FakeSecondary[1] = ID_EXIT; /* For EXECUTE */ + +/* Move data from task structure to registers for speed. */ + LOAD_REGISTERS; + +/* Save initial stack depths for THROW */ + InitialReturnStack = TORPTR; + InitialDataStack = STKPTR ; +#ifdef PF_SUPPORT_FP + InitialFloatStack = FP_STKPTR; +#endif + + Token = XT; + + do + { +DBUG(("pfCatch: Token = 0x%x\n", Token )); + +/* --------------------------------------------------------------- */ +/* If secondary, thread down code tree until we hit a primitive. */ + while( !IsTokenPrimitive( Token ) ) + { +#ifdef PF_SUPPORT_TRACE + if((gVarTraceFlags & TRACE_INNER) ) + { + MSG("pfCatch: Secondary Token = 0x"); + ffDotHex(Token); + MSG_NUM_H(", InsPtr = 0x", InsPtr); + } + TRACENAMES; +#endif + +/* Save IP on return stack like a JSR. */ + M_R_PUSH( InsPtr ); + +/* Convert execution token to absolute address. */ + InsPtr = (cell_t *) ( LOCAL_CODEREL_TO_ABS(Token) ); + +/* Fetch token at IP. */ + Token = READ_CELL_DIC(InsPtr++); + +#ifdef PF_SUPPORT_TRACE +/* Bump level for trace display */ + Level++; +#endif + } + + +#ifdef PF_SUPPORT_TRACE + TRACENAMES; +#endif + +/* Execute primitive Token. */ + switch( Token ) + { + + /* Pop up a level in Forth inner interpreter. + ** Used to implement semicolon. + ** Put first in switch because ID_EXIT==0 */ + case ID_EXIT: + InsPtr = ( cell_t *) M_R_POP; +#ifdef PF_SUPPORT_TRACE + Level--; +#endif + endcase; + + case ID_1MINUS: TOS--; endcase; + + case ID_1PLUS: TOS++; endcase; + +#ifndef PF_NO_SHELL + case ID_2LITERAL: + ff2Literal( TOS, M_POP ); + M_DROP; + endcase; +#endif /* !PF_NO_SHELL */ + + case ID_2LITERAL_P: +/* hi part stored first, put on top of stack */ + PUSH_TOS; + TOS = READ_CELL_DIC(InsPtr++); + M_PUSH(READ_CELL_DIC(InsPtr++)); + endcase; + + case ID_2MINUS: TOS -= 2; endcase; + + case ID_2PLUS: TOS += 2; endcase; + + + case ID_2OVER: /* ( a b c d -- a b c d a b ) */ + PUSH_TOS; + Scratch = M_STACK(3); + M_PUSH(Scratch); + TOS = M_STACK(3); + endcase; + + case ID_2SWAP: /* ( a b c d -- c d a b ) */ + Scratch = M_STACK(0); /* c */ + M_STACK(0) = M_STACK(2); /* a */ + M_STACK(2) = Scratch; /* c */ + Scratch = TOS; /* d */ + TOS = M_STACK(1); /* b */ + M_STACK(1) = Scratch; /* d */ + endcase; + + case ID_2DUP: /* ( a b -- a b a b ) */ + PUSH_TOS; + Scratch = M_STACK(1); + M_PUSH(Scratch); + endcase; + + case ID_2_R_FETCH: + PUSH_TOS; + M_PUSH( (*(TORPTR+1)) ); + TOS = (*(TORPTR)); + endcase; + + case ID_2_R_FROM: + PUSH_TOS; + TOS = M_R_POP; + M_PUSH( M_R_POP ); + endcase; + + case ID_2_TO_R: + M_R_PUSH( M_POP ); + M_R_PUSH( TOS ); + M_DROP; + endcase; + + case ID_ACCEPT_P: /* ( c-addr +n1 -- +n2 ) */ + CharPtr = (char *) M_POP; + TOS = ioAccept( CharPtr, TOS ); + endcase; + +#ifndef PF_NO_SHELL + case ID_ALITERAL: + ffALiteral( ABS_TO_CODEREL(TOS) ); + M_DROP; + endcase; +#endif /* !PF_NO_SHELL */ + + case ID_ALITERAL_P: + PUSH_TOS; + TOS = (cell_t) LOCAL_CODEREL_TO_ABS( READ_CELL_DIC(InsPtr++) ); + endcase; + +/* Allocate some extra and put validation identifier at base */ +#define PF_MEMORY_VALIDATOR (0xA81B4D69) + case ID_ALLOCATE: + /* Allocate at least one cell's worth because we clobber first cell. */ + if ( TOS < sizeof(cell_t) ) + { + Temp = sizeof(cell_t); + } + else + { + Temp = TOS; + } + /* Allocate extra cells worth because we store validation info. */ + CellPtr = (cell_t *) pfAllocMem( Temp + sizeof(cell_t) ); + if( CellPtr ) + { +/* This was broken into two steps because different compilers incremented +** CellPtr before or after the XOR step. */ + Temp = (cell_t)CellPtr ^ PF_MEMORY_VALIDATOR; + *CellPtr++ = Temp; + M_PUSH( (cell_t) CellPtr ); + TOS = 0; + } + else + { + M_PUSH( 0 ); + TOS = -1; /* FIXME Fix error code. */ + } + endcase; + + case ID_AND: BINARY_OP( & ); endcase; + + case ID_ARSHIFT: BINARY_OP( >> ); endcase; /* Arithmetic right shift */ + + case ID_BODY_OFFSET: + PUSH_TOS; + TOS = CREATE_BODY_OFFSET; + endcase; + +/* Branch is followed by an offset relative to address of offset. */ + case ID_BRANCH: +DBUGX(("Before Branch: IP = 0x%x\n", InsPtr )); + M_BRANCH; +DBUGX(("After Branch: IP = 0x%x\n", InsPtr )); + endcase; + + case ID_BYE: + M_THROW( THROW_BYE ); + endcase; + + case ID_BAIL: + MSG("Emergency exit.\n"); + EXIT(1); + endcase; + + case ID_CATCH: + Scratch = TOS; + TOS = M_POP; + SAVE_REGISTERS; + Scratch = pfCatch( Scratch ); + LOAD_REGISTERS; + M_PUSH( TOS ); + TOS = Scratch; + endcase; + + case ID_CALL_C: + SAVE_REGISTERS; + Scratch = READ_CELL_DIC(InsPtr++); + CallUserFunction( Scratch & 0xFFFF, + (Scratch >> 31) & 1, + (Scratch >> 24) & 0x7F ); + LOAD_REGISTERS; + endcase; + + /* Support 32/64 bit operation. */ + case ID_CELL: + M_PUSH( TOS ); + TOS = sizeof(cell_t); + endcase; + + case ID_CELLS: + TOS = TOS * sizeof(cell_t); + endcase; + + case ID_CFETCH: TOS = *((uint8_t *) TOS); endcase; + + case ID_CMOVE: /* ( src dst n -- ) */ + { + register char *DstPtr = (char *) M_POP; /* dst */ + CharPtr = (char *) M_POP; /* src */ + for( Scratch=0; (ucell_t) Scratch < (ucell_t) TOS ; Scratch++ ) + { + *DstPtr++ = *CharPtr++; + } + M_DROP; + } + endcase; + + case ID_CMOVE_UP: /* ( src dst n -- ) */ + { + register char *DstPtr = ((char *) M_POP) + TOS; /* dst */ + CharPtr = ((char *) M_POP) + TOS;; /* src */ + for( Scratch=0; (ucell_t) Scratch < (ucell_t) TOS ; Scratch++ ) + { + *(--DstPtr) = *(--CharPtr); + } + M_DROP; + } + endcase; + +#ifndef PF_NO_SHELL + case ID_COLON: + SAVE_REGISTERS; + ffColon( ); + LOAD_REGISTERS; + endcase; + case ID_COLON_P: /* ( $name xt -- ) */ + CreateDicEntry( TOS, (char *) M_POP, 0 ); + M_DROP; + endcase; +#endif /* !PF_NO_SHELL */ + + case ID_COMPARE: + { + const char *s1, *s2; + cell_t len1; + s2 = (const char *) M_POP; + len1 = M_POP; + s1 = (const char *) M_POP; + TOS = ffCompare( s1, len1, s2, TOS ); + } + endcase; + +/* ( a b -- flag , Comparisons ) */ + case ID_COMP_EQUAL: + TOS = ( TOS == M_POP ) ? FTRUE : FFALSE ; + endcase; + case ID_COMP_NOT_EQUAL: + TOS = ( TOS != M_POP ) ? FTRUE : FFALSE ; + endcase; + case ID_COMP_GREATERTHAN: + TOS = ( M_POP > TOS ) ? FTRUE : FFALSE ; + endcase; + case ID_COMP_LESSTHAN: + TOS = ( M_POP < TOS ) ? FTRUE : FFALSE ; + endcase; + case ID_COMP_U_GREATERTHAN: + TOS = ( ((ucell_t)M_POP) > ((ucell_t)TOS) ) ? FTRUE : FFALSE ; + endcase; + case ID_COMP_U_LESSTHAN: + TOS = ( ((ucell_t)M_POP) < ((ucell_t)TOS) ) ? FTRUE : FFALSE ; + endcase; + case ID_COMP_ZERO_EQUAL: + TOS = ( TOS == 0 ) ? FTRUE : FFALSE ; + endcase; + case ID_COMP_ZERO_NOT_EQUAL: + TOS = ( TOS != 0 ) ? FTRUE : FALSE ; + endcase; + case ID_COMP_ZERO_GREATERTHAN: + TOS = ( TOS > 0 ) ? FTRUE : FFALSE ; + endcase; + case ID_COMP_ZERO_LESSTHAN: + TOS = ( TOS < 0 ) ? FTRUE : FFALSE ; + endcase; + + case ID_CR: + EMIT_CR; + endcase; + +#ifndef PF_NO_SHELL + case ID_CREATE: + SAVE_REGISTERS; + ffCreate(); + LOAD_REGISTERS; + endcase; +#endif /* !PF_NO_SHELL */ + + case ID_CREATE_P: + PUSH_TOS; +/* Put address of body on stack. Insptr points after code start. */ + TOS = (cell_t) ((char *)InsPtr - sizeof(cell_t) + CREATE_BODY_OFFSET ); + endcase; + + case ID_CSTORE: /* ( c caddr -- ) */ + *((uint8_t *) TOS) = (uint8_t) M_POP; + M_DROP; + endcase; + +/* Double precision add. */ + case ID_D_PLUS: /* D+ ( al ah bl bh -- sl sh ) */ + { + register ucell_t ah,al,bl,sh,sl; +#define bh TOS + bl = M_POP; + ah = M_POP; + al = M_POP; + sh = 0; + sl = al + bl; + if( sl < bl ) sh = 1; /* Carry */ + sh += ah + bh; + M_PUSH( sl ); + TOS = sh; +#undef bh + } + endcase; + +/* Double precision subtract. */ + case ID_D_MINUS: /* D- ( al ah bl bh -- sl sh ) */ + { + register ucell_t ah,al,bl,sh,sl; +#define bh TOS + bl = M_POP; + ah = M_POP; + al = M_POP; + sh = 0; + sl = al - bl; + if( al < bl ) sh = 1; /* Borrow */ + sh = ah - bh - sh; + M_PUSH( sl ); + TOS = sh; +#undef bh + } + endcase; + +/* Assume 8-bit char and calculate cell width. */ +#define NBITS ((sizeof(ucell_t)) * 8) +/* Define half the number of bits in a cell. */ +#define HNBITS (NBITS / 2) +/* Assume two-complement arithmetic to calculate lower half. */ +#define LOWER_HALF(n) ((n) & (((ucell_t)1 << HNBITS) - 1)) +#define HIGH_BIT ((ucell_t)1 << (NBITS - 1)) + +/* Perform cell*cell bit multiply for a 2 cell result, by factoring into half cell quantities. + * Using an improved algorithm suggested by Steve Green. + * Converted to 64-bit by Aleksej Saushev. + */ + case ID_D_UMTIMES: /* UM* ( a b -- lo hi ) */ + { + ucell_t ahi, alo, bhi, blo; /* input parts */ + ucell_t lo, hi, temp; +/* Get values from stack. */ + ahi = M_POP; + bhi = TOS; +/* Break into hi and lo 16 bit parts. */ + alo = LOWER_HALF(ahi); + ahi = ahi >> HNBITS; + blo = LOWER_HALF(bhi); + bhi = bhi >> HNBITS; + + lo = 0; + hi = 0; +/* higher part: ahi * bhi */ + hi += ahi * bhi; +/* middle (overlapping) part: ahi * blo */ + temp = ahi * blo; + lo += LOWER_HALF(temp); + hi += temp >> HNBITS; +/* middle (overlapping) part: alo * bhi */ + temp = alo * bhi; + lo += LOWER_HALF(temp); + hi += temp >> HNBITS; +/* lower part: alo * blo */ + temp = alo * blo; +/* its higher half overlaps with middle's lower half: */ + lo += temp >> HNBITS; +/* process carry: */ + hi += lo >> HNBITS; + lo = LOWER_HALF(lo); +/* combine lower part of result: */ + lo = (lo << HNBITS) + LOWER_HALF(temp); + + M_PUSH( lo ); + TOS = hi; + } + endcase; + +/* Perform cell*cell bit multiply for 2 cell result, using shift and add. */ + case ID_D_MTIMES: /* M* ( a b -- pl ph ) */ + { + ucell_t ahi, alo, bhi, blo; /* input parts */ + ucell_t lo, hi, temp; + int sg; +/* Get values from stack. */ + ahi = M_POP; + bhi = TOS; + +/* Calculate product sign: */ + sg = ((cell_t)(ahi ^ bhi) < 0); +/* Take absolute values and reduce to um* */ + if ((cell_t)ahi < 0) ahi = (ucell_t)(-ahi); + if ((cell_t)bhi < 0) bhi = (ucell_t)(-bhi); + +/* Break into hi and lo 16 bit parts. */ + alo = LOWER_HALF(ahi); + ahi = ahi >> HNBITS; + blo = LOWER_HALF(bhi); + bhi = bhi >> HNBITS; + + lo = 0; + hi = 0; +/* higher part: ahi * bhi */ + hi += ahi * bhi; +/* middle (overlapping) part: ahi * blo */ + temp = ahi * blo; + lo += LOWER_HALF(temp); + hi += temp >> HNBITS; +/* middle (overlapping) part: alo * bhi */ + temp = alo * bhi; + lo += LOWER_HALF(temp); + hi += temp >> HNBITS; +/* lower part: alo * blo */ + temp = alo * blo; +/* its higher half overlaps with middle's lower half: */ + lo += temp >> HNBITS; +/* process carry: */ + hi += lo >> HNBITS; + lo = LOWER_HALF(lo); +/* combine lower part of result: */ + lo = (lo << HNBITS) + LOWER_HALF(temp); + +/* Negate product if one operand negative. */ + if(sg) + { + /* lo = (ucell_t)(- lo); */ + lo = ~lo + 1; + hi = ~hi + ((lo == 0) ? 1 : 0); + } + + M_PUSH( lo ); + TOS = hi; + } + endcase; + +#define DULT(du1l,du1h,du2l,du2h) ( (du2h> 1) | (bh << (NBITS-1)); + bh = bh >> 1; + } + if( !DULT(al,ah,bl,bh) ) + { + + al = al - bl; + q |= 1; + } + M_PUSH( al ); /* rem */ + TOS = q; + } + endcase; + +/* Perform 2 cell by 1 cell divide for 2 cell result and remainder, using shift and subtract. */ + case ID_D_MUSMOD: /* MU/MOD ( al am bdiv -- rem ql qh ) */ + { + register ucell_t ah,am,al,ql,qh,di; +#define bdiv ((ucell_t)TOS) + ah = 0; + am = M_POP; + al = M_POP; + qh = ql = 0; + for( di=0; di<2*NBITS; di++ ) + { + if( bdiv <= ah ) + { + ah = ah - bdiv; + ql |= 1; + } + qh = (qh << 1) | (ql >> (NBITS-1)); + ql = ql << 1; + ah = (ah << 1) | (am >> (NBITS-1)); + am = (am << 1) | (al >> (NBITS-1)); + al = al << 1; +DBUG(("XX ah,m,l = 0x%8x,%8x,%8x - qh,l = 0x%8x,%8x\n", ah,am,al, qh,ql )); + } + if( bdiv <= ah ) + { + ah = ah - bdiv; + ql |= 1; + } + M_PUSH( ah ); /* rem */ + M_PUSH( ql ); + TOS = qh; +#undef bdiv + } + endcase; + +#ifndef PF_NO_SHELL + case ID_DEFER: + ffDefer( ); + endcase; +#endif /* !PF_NO_SHELL */ + + case ID_DEFER_P: + endcase; + + case ID_DEPTH: + PUSH_TOS; + TOS = gCurrentTask->td_StackBase - STKPTR; + endcase; + + case ID_DIVIDE: BINARY_OP( / ); endcase; + + case ID_DOT: + ffDot( TOS ); + M_DROP; + endcase; + + case ID_DOTS: + M_DOTS; + endcase; + + case ID_DROP: M_DROP; endcase; + + case ID_DUMP: + Scratch = M_POP; + DumpMemory( (char *) Scratch, TOS ); + M_DROP; + endcase; + + case ID_DUP: M_DUP; endcase; + + case ID_DO_P: /* ( limit start -- ) ( R: -- start limit ) */ + M_R_PUSH( TOS ); + M_R_PUSH( M_POP ); + M_DROP; + endcase; + + case ID_EOL: /* ( -- end_of_line_char ) */ + PUSH_TOS; + TOS = (cell_t) '\n'; + endcase; + + case ID_ERRORQ_P: /* ( flag num -- , quit if flag true ) */ + Scratch = TOS; + M_DROP; + if(TOS) + { + M_THROW(Scratch); + } + else + { + M_DROP; + } + endcase; + + case ID_EMIT_P: + EMIT( (char) TOS ); + M_DROP; + endcase; + + case ID_EXECUTE: +/* Save IP on return stack like a JSR. */ + M_R_PUSH( InsPtr ); +#ifdef PF_SUPPORT_TRACE +/* Bump level for trace. */ + Level++; +#endif + if( IsTokenPrimitive( TOS ) ) + { + WRITE_CELL_DIC( (cell_t *) &FakeSecondary[0], TOS); /* Build a fake secondary and execute it. */ + InsPtr = &FakeSecondary[0]; + } + else + { + InsPtr = (cell_t *) LOCAL_CODEREL_TO_ABS(TOS); + } + M_DROP; + endcase; + + case ID_FETCH: +#if (defined(PF_BIG_ENDIAN_DIC) || defined(PF_LITTLE_ENDIAN_DIC)) + if( IN_DICS( TOS ) ) + { + TOS = (cell_t) READ_CELL_DIC((cell_t *)TOS); + } + else + { + TOS = *((cell_t *)TOS); + } +#else + TOS = *((cell_t *)TOS); +#endif + endcase; + + case ID_FILE_CREATE: /* ( c-addr u fam -- fid ior ) */ +/* Build NUL terminated name string. */ + Scratch = M_POP; /* u */ + Temp = M_POP; /* caddr */ + if( Scratch < TIB_SIZE-2 ) + { + const char *famText = pfSelectFileModeCreate( TOS ); + pfCopyMemory( gScratch, (char *) Temp, (ucell_t) Scratch ); + gScratch[Scratch] = '\0'; + DBUG(("Create file = %s with famTxt %s\n", gScratch, famText )); + FileID = sdOpenFile( gScratch, famText ); + TOS = ( FileID == NULL ) ? -1 : 0 ; + M_PUSH( (cell_t) FileID ); + } + else + { + ERR("Filename too large for name buffer.\n"); + M_PUSH( 0 ); + TOS = -2; + } + endcase; + + case ID_FILE_DELETE: /* ( c-addr u -- ior ) */ +/* Build NUL terminated name string. */ + Temp = M_POP; /* caddr */ + if( TOS < TIB_SIZE-2 ) + { + pfCopyMemory( gScratch, (char *) Temp, (ucell_t) TOS ); + gScratch[TOS] = '\0'; + DBUG(("Delete file = %s\n", gScratch )); + TOS = sdDeleteFile( gScratch ); + } + else + { + ERR("Filename too large for name buffer.\n"); + TOS = -2; + } + endcase; + + case ID_FILE_OPEN: /* ( c-addr u fam -- fid ior ) */ +/* Build NUL terminated name string. */ + Scratch = M_POP; /* u */ + Temp = M_POP; /* caddr */ + if( Scratch < TIB_SIZE-2 ) + { + const char *famText = pfSelectFileModeOpen( TOS ); + pfCopyMemory( gScratch, (char *) Temp, (ucell_t) Scratch ); + gScratch[Scratch] = '\0'; + DBUG(("Open file = %s\n", gScratch )); + FileID = sdOpenFile( gScratch, famText ); + + TOS = ( FileID == NULL ) ? -1 : 0 ; + M_PUSH( (cell_t) FileID ); + } + else + { + ERR("Filename too large for name buffer.\n"); + M_PUSH( 0 ); + TOS = -2; + } + endcase; + + case ID_FILE_CLOSE: /* ( fid -- ior ) */ + TOS = sdCloseFile( (FileStream *) TOS ); + endcase; + + case ID_FILE_READ: /* ( addr len fid -- u2 ior ) */ + FileID = (FileStream *) TOS; + Scratch = M_POP; + CharPtr = (char *) M_POP; + Temp = sdReadFile( CharPtr, 1, Scratch, FileID ); + M_PUSH(Temp); + TOS = 0; + endcase; + + case ID_FILE_SIZE: /* ( fid -- ud ior ) */ +/* Determine file size by seeking to end and returning position. */ + FileID = (FileStream *) TOS; + { + off_t endposition, offsetHi; + off_t original = sdTellFile( FileID ); + sdSeekFile( FileID, 0, PF_SEEK_END ); + endposition = sdTellFile( FileID ); + M_PUSH(endposition); + /* Just use a 0 if they are the same size. */ + offsetHi = (sizeof(off_t) > sizeof(cell_t)) ? (endposition >> (8*sizeof(cell_t))) : 0 ; + M_PUSH(offsetHi); + sdSeekFile( FileID, original, PF_SEEK_SET ); + TOS = (original < 0) ? -4 : 0 ; /* !!! err num */ + } + endcase; + + case ID_FILE_WRITE: /* ( addr len fid -- ior ) */ + FileID = (FileStream *) TOS; + Scratch = M_POP; + CharPtr = (char *) M_POP; + Temp = sdWriteFile( CharPtr, 1, Scratch, FileID ); + TOS = (Temp != Scratch) ? -3 : 0; + endcase; + + case ID_FILE_REPOSITION: /* ( ud fid -- ior ) */ + { + off_t offset; + FileID = (FileStream *) TOS; + offset = M_POP; + /* Avoid compiler warnings on Mac. */ + offset = (sizeof(off_t) > sizeof(cell_t)) ? (offset << 8*sizeof(cell_t)) : 0 ; + offset += M_POP; + TOS = sdSeekFile( FileID, offset, PF_SEEK_SET ); + } + endcase; + + case ID_FILE_POSITION: /* ( fid -- ud ior ) */ + { + off_t position; + off_t offsetHi; + FileID = (FileStream *) TOS; + position = sdTellFile( FileID ); + M_PUSH(position); + /* Just use a 0 if they are the same size. */ + offsetHi = (sizeof(off_t) > sizeof(cell_t)) ? (position >> (8*sizeof(cell_t))) : 0 ; + M_PUSH(offsetHi); + TOS = (position < 0) ? -4 : 0 ; /* !!! err num */ + } + endcase; + + case ID_FILE_RO: /* ( -- fam ) */ + PUSH_TOS; + TOS = PF_FAM_READ_ONLY; + endcase; + + case ID_FILE_RW: /* ( -- fam ) */ + PUSH_TOS; + TOS = PF_FAM_READ_WRITE; + endcase; + + case ID_FILE_WO: /* ( -- fam ) */ + PUSH_TOS; + TOS = PF_FAM_WRITE_ONLY; + endcase; + + case ID_FILE_BIN: /* ( -- fam ) */ + TOS = TOS | PF_FAM_BINARY_FLAG; + endcase; + + case ID_FILL: /* ( caddr num charval -- ) */ + { + register char *DstPtr; + Temp = M_POP; /* num */ + DstPtr = (char *) M_POP; /* dst */ + for( Scratch=0; (ucell_t) Scratch < (ucell_t) Temp ; Scratch++ ) + { + *DstPtr++ = (char) TOS; + } + M_DROP; + } + endcase; + +#ifndef PF_NO_SHELL + case ID_FIND: /* ( $addr -- $addr 0 | xt +-1 ) */ + TOS = ffFind( (char *) TOS, (ExecToken *) &Temp ); + M_PUSH( Temp ); + endcase; + + case ID_FINDNFA: + TOS = ffFindNFA( (const ForthString *) TOS, (const ForthString **) &Temp ); + M_PUSH( (cell_t) Temp ); + endcase; +#endif /* !PF_NO_SHELL */ + + case ID_FLUSHEMIT: + sdTerminalFlush(); + endcase; + +/* Validate memory before freeing. Clobber validator and first word. */ + case ID_FREE: /* ( addr -- result ) */ + if( TOS == 0 ) + { + ERR("FREE passed NULL!\n"); + TOS = -2; /* FIXME error code */ + } + else + { + CellPtr = (cell_t *) TOS; + CellPtr--; + if( ((ucell_t)*CellPtr) != ((ucell_t)CellPtr ^ PF_MEMORY_VALIDATOR)) + { + TOS = -2; /* FIXME error code */ + } + else + { + CellPtr[0] = 0xDeadBeef; + pfFreeMem((char *)CellPtr); + TOS = 0; + } + } + endcase; + +#include "pfinnrfp.h" + + case ID_HERE: + PUSH_TOS; + TOS = (cell_t)CODE_HERE; + endcase; + + case ID_NUMBERQ_P: /* ( addr -- 0 | n 1 ) */ +/* Convert using number converter in 'C'. +** Only supports single precision for bootstrap. +*/ + TOS = (cell_t) ffNumberQ( (char *) TOS, &Temp ); + if( TOS == NUM_TYPE_SINGLE) + { + M_PUSH( Temp ); /* Push single number */ + } + endcase; + + case ID_I: /* ( -- i , DO LOOP index ) */ + PUSH_TOS; + TOS = M_R_PICK(1); + endcase; + +#ifndef PF_NO_SHELL + case ID_INCLUDE_FILE: + FileID = (FileStream *) TOS; + M_DROP; /* Drop now so that INCLUDE has a clean stack. */ + SAVE_REGISTERS; + Scratch = ffIncludeFile( FileID ); + LOAD_REGISTERS; + if( Scratch ) M_THROW(Scratch) + endcase; +#endif /* !PF_NO_SHELL */ + +#ifndef PF_NO_SHELL + case ID_INTERPRET: + SAVE_REGISTERS; + Scratch = ffInterpret(); + LOAD_REGISTERS; + if( Scratch ) M_THROW(Scratch) + endcase; +#endif /* !PF_NO_SHELL */ + + case ID_J: /* ( -- j , second DO LOOP index ) */ + PUSH_TOS; + TOS = M_R_PICK(3); + endcase; + + case ID_KEY: + PUSH_TOS; + TOS = ioKey(); + endcase; + +#ifndef PF_NO_SHELL + case ID_LITERAL: + ffLiteral( TOS ); + M_DROP; + endcase; +#endif /* !PF_NO_SHELL */ + + case ID_LITERAL_P: + DBUG(("ID_LITERAL_P: InsPtr = 0x%x, *InsPtr = 0x%x\n", InsPtr, *InsPtr )); + PUSH_TOS; + TOS = READ_CELL_DIC(InsPtr++); + endcase; + +#ifndef PF_NO_SHELL + case ID_LOCAL_COMPILER: DO_VAR(gLocalCompiler_XT); endcase; +#endif /* !PF_NO_SHELL */ + + case ID_LOCAL_FETCH: /* ( i -- n , fetch from local ) */ + TOS = *(LocalsPtr - TOS); + endcase; + +#define LOCAL_FETCH_N(num) \ + case ID_LOCAL_FETCH_##num: /* ( -- n , fetch from local ) */ \ + PUSH_TOS; \ + TOS = *(LocalsPtr -(num)); \ + endcase; + + LOCAL_FETCH_N(1); + LOCAL_FETCH_N(2); + LOCAL_FETCH_N(3); + LOCAL_FETCH_N(4); + LOCAL_FETCH_N(5); + LOCAL_FETCH_N(6); + LOCAL_FETCH_N(7); + LOCAL_FETCH_N(8); + + case ID_LOCAL_STORE: /* ( n i -- , store n in local ) */ + *(LocalsPtr - TOS) = M_POP; + M_DROP; + endcase; + +#define LOCAL_STORE_N(num) \ + case ID_LOCAL_STORE_##num: /* ( n -- , store n in local ) */ \ + *(LocalsPtr - (num)) = TOS; \ + M_DROP; \ + endcase; + + LOCAL_STORE_N(1); + LOCAL_STORE_N(2); + LOCAL_STORE_N(3); + LOCAL_STORE_N(4); + LOCAL_STORE_N(5); + LOCAL_STORE_N(6); + LOCAL_STORE_N(7); + LOCAL_STORE_N(8); + + case ID_LOCAL_PLUSSTORE: /* ( n i -- , add n to local ) */ + *(LocalsPtr - TOS) += M_POP; + M_DROP; + endcase; + + case ID_LOCAL_ENTRY: /* ( x0 x1 ... xn n -- ) */ + /* create local stack frame */ + { + cell_t i = TOS; + cell_t *lp; + DBUG(("LocalEntry: n = %d\n", TOS)); + /* End of locals. Create stack frame */ + DBUG(("LocalEntry: before RP@ = 0x%x, LP = 0x%x\n", + TORPTR, LocalsPtr)); + M_R_PUSH(LocalsPtr); + LocalsPtr = TORPTR; + TORPTR -= TOS; + DBUG(("LocalEntry: after RP@ = 0x%x, LP = 0x%x\n", + TORPTR, LocalsPtr)); + lp = TORPTR; + while(i-- > 0) + { + *lp++ = M_POP; /* Load local vars from stack */ + } + M_DROP; + } + endcase; + + case ID_LOCAL_EXIT: /* cleanup up local stack frame */ + DBUG(("LocalExit: before RP@ = 0x%x, LP = 0x%x\n", + TORPTR, LocalsPtr)); + TORPTR = LocalsPtr; + LocalsPtr = (cell_t *) M_R_POP; + DBUG(("LocalExit: after RP@ = 0x%x, LP = 0x%x\n", + TORPTR, LocalsPtr)); + endcase; + +#ifndef PF_NO_SHELL + case ID_LOADSYS: + MSG("Load "); MSG(SYSTEM_LOAD_FILE); EMIT_CR; + FileID = sdOpenFile(SYSTEM_LOAD_FILE, "r"); + if( FileID ) + { + SAVE_REGISTERS; + Scratch = ffIncludeFile( FileID ); /* Also closes the file. */ + LOAD_REGISTERS; + if( Scratch ) M_THROW(Scratch); + } + else + { + ERR(SYSTEM_LOAD_FILE); ERR(" could not be opened!\n"); + } + endcase; +#endif /* !PF_NO_SHELL */ + + case ID_LEAVE_P: /* ( R: index limit -- ) */ + M_R_DROP; + M_R_DROP; + M_BRANCH; + endcase; + + case ID_LOOP_P: /* ( R: index limit -- | index limit ) */ + Temp = M_R_POP; /* limit */ + Scratch = M_R_POP + 1; /* index */ + if( Scratch == Temp ) + { + InsPtr++; /* skip branch offset, exit loop */ + } + else + { +/* Push index and limit back to R */ + M_R_PUSH( Scratch ); + M_R_PUSH( Temp ); +/* Branch back to just after (DO) */ + M_BRANCH; + } + endcase; + + case ID_LSHIFT: BINARY_OP( << ); endcase; + + case ID_MAX: + Scratch = M_POP; + TOS = ( TOS > Scratch ) ? TOS : Scratch ; + endcase; + + case ID_MIN: + Scratch = M_POP; + TOS = ( TOS < Scratch ) ? TOS : Scratch ; + endcase; + + case ID_MINUS: BINARY_OP( - ); endcase; + +#ifndef PF_NO_SHELL + case ID_NAME_TO_TOKEN: + TOS = (cell_t) NameToToken((ForthString *)TOS); + endcase; + + case ID_NAME_TO_PREVIOUS: + TOS = (cell_t) NameToPrevious((ForthString *)TOS); + endcase; +#endif + + case ID_NOOP: + endcase; + + case ID_OR: BINARY_OP( | ); endcase; + + case ID_OVER: + PUSH_TOS; + TOS = M_STACK(1); + endcase; + + case ID_PICK: /* ( ... n -- sp(n) ) */ + TOS = M_STACK(TOS); + endcase; + + case ID_PLUS: BINARY_OP( + ); endcase; + + case ID_PLUS_STORE: /* ( n addr -- , add n to *addr ) */ +#if (defined(PF_BIG_ENDIAN_DIC) || defined(PF_LITTLE_ENDIAN_DIC)) + if( IN_DICS( TOS ) ) + { + Scratch = READ_CELL_DIC((cell_t *)TOS); + Scratch += M_POP; + WRITE_CELL_DIC((cell_t *)TOS,Scratch); + } + else + { + *((cell_t *)TOS) += M_POP; + } +#else + *((cell_t *)TOS) += M_POP; +#endif + M_DROP; + endcase; + + case ID_PLUSLOOP_P: /* ( delta -- ) ( R: index limit -- | index limit ) */ + { + ucell_t OldIndex, NewIndex, Limit; + + Limit = M_R_POP; + OldIndex = M_R_POP; + NewIndex = OldIndex + TOS; /* add TOS to index, not 1 */ +/* Do indices cross boundary between LIMIT-1 and LIMIT ? */ + if( ( (OldIndex - Limit) & ((Limit-1) - NewIndex) & 0x80000000 ) || + ( (NewIndex - Limit) & ((Limit-1) - OldIndex) & 0x80000000 ) ) + { + InsPtr++; /* skip branch offset, exit loop */ + } + else + { +/* Push index and limit back to R */ + M_R_PUSH( NewIndex ); + M_R_PUSH( Limit ); +/* Branch back to just after (DO) */ + M_BRANCH; + } + M_DROP; + } + endcase; + + case ID_QDO_P: /* (?DO) ( limit start -- ) ( R: -- start limit ) */ + Scratch = M_POP; /* limit */ + if( Scratch == TOS ) + { +/* Branch to just after (LOOP) */ + M_BRANCH; + } + else + { + M_R_PUSH( TOS ); + M_R_PUSH( Scratch ); + InsPtr++; /* skip branch offset, enter loop */ + } + M_DROP; + endcase; + + case ID_QDUP: if( TOS ) M_DUP; endcase; + + case ID_QTERMINAL: /* WARNING: Typically not fully implemented! */ + PUSH_TOS; + TOS = sdQueryTerminal(); + endcase; + + case ID_QUIT_P: /* Stop inner interpreter, go back to user. */ +#ifdef PF_SUPPORT_TRACE + Level = 0; +#endif + M_THROW(THROW_QUIT); + endcase; + + case ID_R_DROP: + M_R_DROP; + endcase; + + case ID_R_FETCH: + PUSH_TOS; + TOS = (*(TORPTR)); + endcase; + + case ID_R_FROM: + PUSH_TOS; + TOS = M_R_POP; + endcase; + + case ID_REFILL: + PUSH_TOS; + TOS = (ffRefill() > 0) ? FTRUE : FFALSE; + endcase; + +/* Resize memory allocated by ALLOCATE. */ + case ID_RESIZE: /* ( addr1 u -- addr2 result ) */ + { + cell_t *Addr1 = (cell_t *) M_POP; + /* Point to validator below users address. */ + cell_t *FreePtr = Addr1 - 1; + if( ((ucell_t)*FreePtr) != ((ucell_t)FreePtr ^ PF_MEMORY_VALIDATOR)) + { + /* 090218 - Fixed bug, was returning zero. */ + M_PUSH( Addr1 ); + TOS = -3; + } + else + { + /* Try to allocate. */ + CellPtr = (cell_t *) pfAllocMem( TOS + sizeof(cell_t) ); + if( CellPtr ) + { + /* Copy memory including validation. */ + pfCopyMemory( (char *) CellPtr, (char *) FreePtr, TOS + sizeof(cell_t) ); + *CellPtr = (cell_t)(((ucell_t)CellPtr) ^ (ucell_t)PF_MEMORY_VALIDATOR); + /* 090218 - Fixed bug that was incrementing the address twice. Thanks Reinhold Straub. */ + /* Increment past validator to user address. */ + M_PUSH( (cell_t) (CellPtr + 1) ); + TOS = 0; /* Result code. */ + /* Mark old cell as dead so we can't free it twice. */ + FreePtr[0] = 0xDeadBeef; + pfFreeMem((char *) FreePtr); + } + else + { + /* 090218 - Fixed bug, was returning zero. */ + M_PUSH( Addr1 ); + TOS = -4; /* FIXME Fix error code. */ + } + } + } + endcase; + +/* +** RP@ and RP! are called secondaries so we must +** account for the return address pushed before calling. +*/ + case ID_RP_FETCH: /* ( -- rp , address of top of return stack ) */ + PUSH_TOS; + TOS = (cell_t)TORPTR; /* value before calling RP@ */ + endcase; + + case ID_RP_STORE: /* ( rp -- , address of top of return stack ) */ + TORPTR = (cell_t *) TOS; + M_DROP; + endcase; + + case ID_ROLL: /* ( xu xu-1 xu-1 ... x0 u -- xu-1 xu-1 ... x0 xu ) */ + { + cell_t ri; + cell_t *srcPtr, *dstPtr; + Scratch = M_STACK(TOS); + srcPtr = &M_STACK(TOS-1); + dstPtr = &M_STACK(TOS); + for( ri=0; ri> TOS; } endcase; + +#ifndef PF_NO_SHELL + case ID_SAVE_FORTH_P: /* ( $name Entry NameSize CodeSize -- err ) */ + { + cell_t NameSize, CodeSize, EntryPoint; + CodeSize = TOS; + NameSize = M_POP; + EntryPoint = M_POP; + ForthStringToC( gScratch, (char *) M_POP, sizeof(gScratch) ); + TOS = ffSaveForth( gScratch, EntryPoint, NameSize, CodeSize ); + } + endcase; +#endif + +/* Source Stack +** EVALUATE >IN SourceID=(-1) 1111 +** keyboard >IN SourceID=(0) 2222 +** file >IN lineNumber filePos SourceID=(fileID) +*/ + case ID_SAVE_INPUT: /* FIXME - finish */ + { + } + endcase; + + case ID_SP_FETCH: /* ( -- sp , address of top of stack, sorta ) */ + PUSH_TOS; + TOS = (cell_t)STKPTR; + endcase; + + case ID_SP_STORE: /* ( sp -- , address of top of stack, sorta ) */ + STKPTR = (cell_t *) TOS; + M_DROP; + endcase; + + case ID_STORE: /* ( n addr -- , write n to addr ) */ +#if (defined(PF_BIG_ENDIAN_DIC) || defined(PF_LITTLE_ENDIAN_DIC)) + if( IN_DICS( TOS ) ) + { + WRITE_CELL_DIC((cell_t *)TOS,M_POP); + } + else + { + *((cell_t *)TOS) = M_POP; + } +#else + *((cell_t *)TOS) = M_POP; +#endif + M_DROP; + endcase; + + case ID_SCAN: /* ( addr cnt char -- addr' cnt' ) */ + Scratch = M_POP; /* cnt */ + Temp = M_POP; /* addr */ + TOS = ffScan( (char *) Temp, Scratch, (char) TOS, &CharPtr ); + M_PUSH((cell_t) CharPtr); + endcase; + +#ifndef PF_NO_SHELL + case ID_SEMICOLON: + SAVE_REGISTERS; + Scratch = ffSemiColon(); + LOAD_REGISTERS; + if( Scratch ) M_THROW( Scratch ); + endcase; +#endif /* !PF_NO_SHELL */ + + case ID_SKIP: /* ( addr cnt char -- addr' cnt' ) */ + Scratch = M_POP; /* cnt */ + Temp = M_POP; /* addr */ + TOS = ffSkip( (char *) Temp, Scratch, (char) TOS, &CharPtr ); + M_PUSH((cell_t) CharPtr); + endcase; + + case ID_SOURCE: /* ( -- c-addr num ) */ + PUSH_TOS; + M_PUSH( (cell_t) gCurrentTask->td_SourcePtr ); + TOS = (cell_t) gCurrentTask->td_SourceNum; + endcase; + + case ID_SOURCE_SET: /* ( c-addr num -- ) */ + gCurrentTask->td_SourcePtr = (char *) M_POP; + gCurrentTask->td_SourceNum = TOS; + M_DROP; + endcase; + + case ID_SOURCE_ID: + PUSH_TOS; + TOS = ffConvertStreamToSourceID( gCurrentTask->td_InputStream ) ; + endcase; + + case ID_SOURCE_ID_POP: + PUSH_TOS; + TOS = ffConvertStreamToSourceID( ffPopInputStream() ) ; + endcase; + + case ID_SOURCE_ID_PUSH: /* ( source-id -- ) */ + TOS = (cell_t)ffConvertSourceIDToStream( TOS ); + Scratch = ffPushInputStream((FileStream *) TOS ); + if( Scratch ) + { + M_THROW(Scratch); + } + else M_DROP; + endcase; + + case ID_SWAP: + Scratch = TOS; + TOS = *STKPTR; + *STKPTR = Scratch; + endcase; + + case ID_TEST1: + PUSH_TOS; + M_PUSH( 0x11 ); + M_PUSH( 0x22 ); + TOS = 0x33; + endcase; + + case ID_TEST2: + endcase; + + case ID_THROW: /* ( k*x err -- k*x | i*x err , jump to where CATCH was called ) */ + if(TOS) + { + M_THROW(TOS); + } + else M_DROP; + endcase; + +#ifndef PF_NO_SHELL + case ID_TICK: + PUSH_TOS; + CharPtr = (char *) ffWord( (char) ' ' ); + TOS = ffFind( CharPtr, (ExecToken *) &Temp ); + if( TOS == 0 ) + { + ERR("' could not find "); + ioType( (char *) CharPtr+1, *CharPtr ); + M_THROW(-13); + } + else + { + TOS = Temp; + } + endcase; +#endif /* !PF_NO_SHELL */ + + case ID_TIMES: BINARY_OP( * ); endcase; + + case ID_TYPE: + Scratch = M_POP; /* addr */ + ioType( (char *) Scratch, TOS ); + M_DROP; + endcase; + + case ID_TO_R: + M_R_PUSH( TOS ); + M_DROP; + endcase; + + case ID_VAR_BASE: DO_VAR(gVarBase); endcase; + case ID_VAR_CODE_BASE: DO_VAR(gCurrentDictionary->dic_CodeBase); endcase; + case ID_VAR_CODE_LIMIT: DO_VAR(gCurrentDictionary->dic_CodeLimit); endcase; + case ID_VAR_CONTEXT: DO_VAR(gVarContext); endcase; + case ID_VAR_DP: DO_VAR(gCurrentDictionary->dic_CodePtr.Cell); endcase; + case ID_VAR_ECHO: DO_VAR(gVarEcho); endcase; + case ID_VAR_HEADERS_BASE: DO_VAR(gCurrentDictionary->dic_HeaderBase); endcase; + case ID_VAR_HEADERS_LIMIT: DO_VAR(gCurrentDictionary->dic_HeaderLimit); endcase; + case ID_VAR_HEADERS_PTR: DO_VAR(gCurrentDictionary->dic_HeaderPtr); endcase; + case ID_VAR_NUM_TIB: DO_VAR(gCurrentTask->td_SourceNum); endcase; + case ID_VAR_OUT: DO_VAR(gCurrentTask->td_OUT); endcase; + case ID_VAR_STATE: DO_VAR(gVarState); endcase; + case ID_VAR_TO_IN: DO_VAR(gCurrentTask->td_IN); endcase; + case ID_VAR_TRACE_FLAGS: DO_VAR(gVarTraceFlags); endcase; + case ID_VAR_TRACE_LEVEL: DO_VAR(gVarTraceLevel); endcase; + case ID_VAR_TRACE_STACK: DO_VAR(gVarTraceStack); endcase; + case ID_VAR_RETURN_CODE: DO_VAR(gVarReturnCode); endcase; + + case ID_WORD: + TOS = (cell_t) ffWord( (char) TOS ); + endcase; + + case ID_WORD_FETCH: /* ( waddr -- w ) */ +#if (defined(PF_BIG_ENDIAN_DIC) || defined(PF_LITTLE_ENDIAN_DIC)) + if( IN_DICS( TOS ) ) + { + TOS = (uint16_t) READ_SHORT_DIC((uint16_t *)TOS); + } + else + { + TOS = *((uint16_t *)TOS); + } +#else + TOS = *((uint16_t *)TOS); +#endif + endcase; + + case ID_WORD_STORE: /* ( w waddr -- ) */ + +#if (defined(PF_BIG_ENDIAN_DIC) || defined(PF_LITTLE_ENDIAN_DIC)) + if( IN_DICS( TOS ) ) + { + WRITE_SHORT_DIC((uint16_t *)TOS,(uint16_t)M_POP); + } + else + { + *((uint16_t *)TOS) = (uint16_t) M_POP; + } +#else + *((uint16_t *)TOS) = (uint16_t) M_POP; +#endif + M_DROP; + endcase; + + case ID_XOR: BINARY_OP( ^ ); endcase; + + +/* Branch is followed by an offset relative to address of offset. */ + case ID_ZERO_BRANCH: +DBUGX(("Before 0Branch: IP = 0x%x\n", InsPtr )); + if( TOS == 0 ) + { + M_BRANCH; + } + else + { + InsPtr++; /* skip over offset */ + } + M_DROP; +DBUGX(("After 0Branch: IP = 0x%x\n", InsPtr )); + endcase; + + default: + ERR("pfCatch: Unrecognised token = 0x"); + ffDotHex(Token); + ERR(" at 0x"); + ffDotHex((cell_t) InsPtr); + EMIT_CR; + InsPtr = 0; + endcase; + } + + if(InsPtr) Token = READ_CELL_DIC(InsPtr++); /* Traverse to next token in secondary. */ + +#ifdef PF_DEBUG + M_DOTS; +#endif + +#if 0 + if( _CrtCheckMemory() == 0 ) + { + ERR("_CrtCheckMemory abort: InsPtr = 0x"); + ffDotHex((int)InsPtr); + ERR("\n"); + } +#endif + + } while( (InitialReturnStack - TORPTR) > 0 ); + + SAVE_REGISTERS; + + return ExceptionReturnCode; +} diff --git a/src/cmd/pforth/pf_io.c b/src/cmd/pforth/pf_io.c new file mode 100644 index 0000000..c86f21f --- /dev/null +++ b/src/cmd/pforth/pf_io.c @@ -0,0 +1,225 @@ +/* @(#) pf_io.c 96/12/23 1.12 */ +/*************************************************************** +** I/O subsystem for PForth based on 'C' +** +** Author: Phil Burk +** Copyright 1994 3DO, Phil Burk, Larry Polansky, David Rosenboom +** +** The pForth software code is dedicated to the public domain, +** and any third party may reproduce, distribute and modify +** the pForth software code or any derivative works thereof +** without any compensation or license. The pForth software +** code is provided on an "as is" basis without any warranty +** of any kind, including, without limitation, the implied +** warranties of merchantability and fitness for a particular +** purpose and their equivalents under the laws of any jurisdiction. +** +**************************************************************** +** 941004 PLB Extracted IO calls from pforth_main.c +***************************************************************/ + +#include "pf_all.h" + + +/*************************************************************** +** Initialize I/O system. +*/ +void ioInit( void ) +{ + /* System dependant terminal initialization. */ + sdTerminalInit(); +} +void ioTerm( void ) +{ + sdTerminalTerm(); +} + +/*************************************************************** +** Send single character to output stream. +*/ +void ioEmit( char c ) +{ + cell_t Result; + + Result = sdTerminalOut(c); + if( Result < 0 ) EXIT(1); + + if( gCurrentTask ) + { + if(c == '\n') + { + gCurrentTask->td_OUT = 0; + sdTerminalFlush(); + } + else + { + gCurrentTask->td_OUT++; + } + } +} + +/*************************************************************** +** Send an entire string.. +*/ +void ioType( const char *s, cell_t n ) +{ + cell_t i; + + for( i=0; i 0 ) /* Don't go beyond beginning of line. */ + { + EMIT(BACKSPACE); + EMIT(' '); + EMIT(BACKSPACE); + p--; + len--; + } + break; + + default: + sdTerminalEcho( (char) c ); + *p++ = (char) c; + len++; + break; + } + + } + +gotline: + sdDisableInput(); + sdTerminalEcho( SPACE ); + +/* NUL terminate line to simplify printing when debugging. */ + if( len < maxChars ) p[len] = '\0'; + + return len; +} + +#define UNIMPLEMENTED(name) { MSG(name); MSG("is unimplemented!\n"); } + + +/***********************************************************************************/ +/*********** File I/O **************************************************************/ +/***********************************************************************************/ +#ifdef PF_NO_FILEIO + +/* Provide stubs for standard file I/O */ + +FileStream *PF_STDIN; +FileStream *PF_STDOUT; + +cell_t sdInputChar( FileStream *stream ) +{ + UNIMPLEMENTED("sdInputChar"); + TOUCH(stream); + return -1; +} + +FileStream *sdOpenFile( const char *FileName, const char *Mode ) +{ + UNIMPLEMENTED("sdOpenFile"); + TOUCH(FileName); + TOUCH(Mode); + return NULL; +} +cell_t sdFlushFile( FileStream * Stream ) +{ + TOUCH(Stream); + return 0; +} +cell_t sdReadFile( void *ptr, cell_t Size, int32_t nItems, FileStream * Stream ) +{ + UNIMPLEMENTED("sdReadFile"); + TOUCH(ptr); + TOUCH(Size); + TOUCH(nItems); + TOUCH(Stream); + return 0; +} +cell_t sdWriteFile( void *ptr, cell_t Size, int32_t nItems, FileStream * Stream ) +{ + UNIMPLEMENTED("sdWriteFile"); + TOUCH(ptr); + TOUCH(Size); + TOUCH(nItems); + TOUCH(Stream); + return 0; +} +cell_t sdSeekFile( FileStream * Stream, cell_t Position, int32_t Mode ) +{ + UNIMPLEMENTED("sdSeekFile"); + TOUCH(Stream); + TOUCH(Position); + TOUCH(Mode); + return 0; +} +cell_t sdTellFile( FileStream * Stream ) +{ + UNIMPLEMENTED("sdTellFile"); + TOUCH(Stream); + return 0; +} +cell_t sdCloseFile( FileStream * Stream ) +{ + UNIMPLEMENTED("sdCloseFile"); + TOUCH(Stream); + return 0; +} + +FileStream *sdDeleteFile( const char *FileName ) +{ + UNIMPLEMENTED("sdDeleteFile"); + TOUCH(FileName); + return NULL; +} +#endif + diff --git a/src/cmd/pforth/pf_io.h b/src/cmd/pforth/pf_io.h new file mode 100644 index 0000000..58b9e90 --- /dev/null +++ b/src/cmd/pforth/pf_io.h @@ -0,0 +1,156 @@ +/* @(#) pf_io.h 98/01/26 1.2 */ +#ifndef _pf_io_h +#define _pf_io_h + +/*************************************************************** +** Include file for PForth IO +** +** Author: Phil Burk +** Copyright 1994 3DO, Phil Burk, Larry Polansky, David Rosenboom +** +** The pForth software code is dedicated to the public domain, +** and any third party may reproduce, distribute and modify +** the pForth software code or any derivative works thereof +** without any compensation or license. The pForth software +** code is provided on an "as is" basis without any warranty +** of any kind, including, without limitation, the implied +** warranties of merchantability and fitness for a particular +** purpose and their equivalents under the laws of any jurisdiction. +** +***************************************************************/ + +#define PF_CHAR_XON (0x11) +#define PF_CHAR_XOFF (0x13) + +int sdTerminalOut( char c ); +int sdTerminalEcho( char c ); +int sdTerminalFlush( void ); +int sdTerminalIn( void ); +int sdQueryTerminal( void ); +void sdTerminalInit( void ); +void sdTerminalTerm( void ); + +void ioInit( void ); +void ioTerm( void ); + + +#ifdef PF_NO_CHARIO + void sdEnableInput( void ); + void sdDisableInput( void ); + +#else /* PF_NO_CHARIO */ + #ifdef PF_USER_CHARIO +/* Get user prototypes or macros from include file. +** API must match that defined above for the stubs. +*/ +/* If your sdTerminalIn echos, define PF_KEY_ECHOS. */ + #include PF_USER_CHARIO + #else + #define sdEnableInput() /* sdTerminalOut( PF_CHAR_XON ) */ + #define sdDisableInput() /* sdTerminalOut( PF_CHAR_XOFF ) */ + + #endif +#endif /* PF_NO_CHARIO */ + +/* Define file access modes. */ +/* User can #undef and re#define using PF_USER_FILEIO if needed. */ +#define PF_FAM_READ_ONLY (0) +#define PF_FAM_READ_WRITE (1) +#define PF_FAM_WRITE_ONLY (2) +#define PF_FAM_BINARY_FLAG (8) + +#define PF_FAM_CREATE_WO ("w") +#define PF_FAM_CREATE_RW ("w+") +#define PF_FAM_OPEN_RO ("r") +#define PF_FAM_OPEN_RW ("r+") +#define PF_FAM_BIN_CREATE_WO ("wb") +#define PF_FAM_BIN_CREATE_RW ("wb+") +#define PF_FAM_BIN_OPEN_RO ("rb") +#define PF_FAM_BIN_OPEN_RW ("rb+") + +#ifdef PF_NO_FILEIO + + typedef void FileStream; + + extern FileStream *PF_STDIN; + extern FileStream *PF_STDOUT; + + #ifdef __cplusplus + extern "C" { + #endif + + /* Prototypes for stubs. */ + FileStream *sdOpenFile( const char *FileName, const char *Mode ); + cell_t sdFlushFile( FileStream * Stream ); + cell_t sdReadFile( void *ptr, cell_t Size, int32_t nItems, FileStream * Stream ); + cell_t sdWriteFile( void *ptr, cell_t Size, int32_t nItems, FileStream * Stream ); + cell_t sdSeekFile( FileStream * Stream, off_t Position, int32_t Mode ); + off_t sdTellFile( FileStream * Stream ); + cell_t sdCloseFile( FileStream * Stream ); + cell_t sdInputChar( FileStream *stream ); + + #ifdef __cplusplus + } + #endif + + #define PF_SEEK_SET (0) + #define PF_SEEK_CUR (1) + #define PF_SEEK_END (2) + /* + ** printf() is only used for debugging purposes. + ** It is not required for normal operation. + */ + #define PRT(x) /* No printf(). */ + +#else + + #ifdef PF_USER_FILEIO +/* Get user prototypes or macros from include file. +** API must match that defined above for the stubs. +*/ + #include PF_USER_FILEIO + + #else + typedef FILE FileStream; + + #define sdOpenFile fopen + #define sdDeleteFile remove + #define sdFlushFile fflush + #define sdReadFile fread + #define sdWriteFile fwrite + #define sdSeekFile fseek + #define sdTellFile ftell + #define sdCloseFile fclose + #define sdInputChar fgetc + + #define PF_STDIN ((FileStream *) stdin) + #define PF_STDOUT ((FileStream *) stdout) + + #define PF_SEEK_SET (0) + #define PF_SEEK_CUR (1) + #define PF_SEEK_END (2) + + /* + ** printf() is only used for debugging purposes. + ** It is not required for normal operation. + */ + #define PRT(x) { printf x; sdFlushFile(PF_STDOUT); } + #endif + +#endif /* PF_NO_FILEIO */ + + +#ifdef __cplusplus +extern "C" { +#endif + +cell_t ioAccept( char *Target, cell_t n1 ); +cell_t ioKey( void); +void ioEmit( char c ); +void ioType( const char *s, cell_t n); + +#ifdef __cplusplus +} +#endif + +#endif /* _pf_io_h */ diff --git a/src/cmd/pforth/pf_io_none.c b/src/cmd/pforth/pf_io_none.c new file mode 100644 index 0000000..e8a93c1 --- /dev/null +++ b/src/cmd/pforth/pf_io_none.c @@ -0,0 +1,49 @@ +/* $Id$ */ +/*************************************************************** +** I/O subsystem for PForth when NO CHARACTER I/O is supported. +** +** Author: Phil Burk +** Copyright 1994 3DO, Phil Burk, Larry Polansky, David Rosenboom +** +** The pForth software code is dedicated to the public domain, +** and any third party may reproduce, distribute and modify +** the pForth software code or any derivative works thereof +** without any compensation or license. The pForth software +** code is provided on an "as is" basis without any warranty +** of any kind, including, without limitation, the implied +** warranties of merchantability and fitness for a particular +** purpose and their equivalents under the laws of any jurisdiction. +** +**************************************************************** +** 941004 PLB Extracted IO calls from pforth_main.c +***************************************************************/ + +#include "pf_all.h" + + +#ifdef PF_NO_CHARIO +int sdTerminalOut( char c ) +{ + TOUCH(c); + return 0; +} +int sdTerminalEcho( char c ) +{ + TOUCH(c); + return 0; +} +int sdTerminalIn( void ) +{ + return -1; +} +int sdTerminalFlush( void ) +{ + return -1; +} +void sdTerminalInit( void ) +{ +} +void sdTerminalTerm( void ) +{ +} +#endif diff --git a/src/cmd/pforth/pf_io_posix.c b/src/cmd/pforth/pf_io_posix.c new file mode 100644 index 0000000..b337193 --- /dev/null +++ b/src/cmd/pforth/pf_io_posix.c @@ -0,0 +1,142 @@ +/* $Id$ */ +/*************************************************************** +** I/O subsystem for PForth based on 'C' +** +** Author: Phil Burk +** Copyright 1994 3DO, Phil Burk, Larry Polansky, David Rosenboom +** +** The pForth software code is dedicated to the public domain, +** and any third party may reproduce, distribute and modify +** the pForth software code or any derivative works thereof +** without any compensation or license. The pForth software +** code is provided on an "as is" basis without any warranty +** of any kind, including, without limitation, the implied +** warranties of merchantability and fitness for a particular +** purpose and their equivalents under the laws of any jurisdiction. +** +**************************************************************** +** 941004 PLB Extracted IO calls from pforth_main.c +** 090220 PLB Fixed broken sdQueryTerminal on Mac. It always returned true. +***************************************************************/ + +#include "pf_all.h" + +/* Configure console so that characters are not buffered. + * This allows KEY and ?TERMINAL to work and also HISTORY.ON + */ + +#include +#include +#include +#ifdef sun +#include /* Needed on Solaris for uint32_t in termio.h */ +#endif +#include +//#include + +static struct termios save_termios; +static int stdin_is_tty; + +/* poll() is broken in Mac OS X Tiger OS so use select() instead. */ +#ifndef PF_USE_SELECT +#define PF_USE_SELECT (1) +#endif + +/* Default portable terminal I/O. */ +int sdTerminalOut( char c ) +{ + return putchar(c); +} + +int sdTerminalEcho( char c ) +{ + putchar(c); + return 0; +} + +int sdTerminalIn( void ) +{ + return getchar(); +} + +int sdTerminalFlush( void ) +{ +#ifdef PF_NO_FILEIO + return -1; +#else + return fflush(PF_STDOUT); +#endif +} + +/****************************************************/ +int sdQueryTerminal( void ) +{ +#if PF_USE_SELECT + int select_retval; + fd_set readfds; + struct timeval tv; + FD_ZERO(&readfds); + FD_SET(STDIN_FILENO, &readfds); + /* Set timeout to zero so that we just poll and return. */ + tv.tv_sec = 0; + tv.tv_usec = 0; + select_retval = select(STDIN_FILENO+1, &readfds, NULL, NULL, &tv); + if (select_retval < 0) + { + perror("sdTerminalInit: select"); + } + return FD_ISSET(STDIN_FILENO,&readfds) ? FTRUE : FFALSE; + +#else + int result; + struct pollfd pfd = { 0 }; + sdTerminalFlush(); + pfd.fd = STDIN_FILENO; + pfd.events = POLLIN; + result = poll( &pfd, 1, 0 ); + /* On a Mac it may set revents to POLLNVAL because poll() is broken on Tiger. */ + if( pfd.revents & POLLNVAL ) + { + PRT(("sdQueryTerminal: poll got POLLNVAL, stdin not open\n")); + return FFALSE; + } + else + { + return (pfd.revents & POLLIN) ? FTRUE : FFALSE; + } +#endif +} + +/****************************************************/ +void sdTerminalInit(void) +{ + struct termios term; + + stdin_is_tty = isatty(STDIN_FILENO); + if (stdin_is_tty) + { +/* Get current terminal attributes and save them so we can restore them. */ + tcgetattr(STDIN_FILENO, &term); + save_termios = term; + +/* ICANON says to wait upon read until a character is received, + * and then to return it immediately (or soon enough....) + * ECHOCTL says not to echo backspaces and other control chars as ^H */ + term.c_lflag &= ~( ECHO | ECHONL | ECHOCTL | ICANON ); + term.c_cc[VTIME] = 0; + term.c_cc[VMIN] = 1; + if( tcsetattr(STDIN_FILENO, TCSANOW, &term) < 0 ) + { + perror("sdTerminalInit: tcsetattr"); + } + } +} + +/****************************************************/ +void sdTerminalTerm(void) +{ + if (stdin_is_tty) + { + tcsetattr(STDIN_FILENO, TCSANOW, &save_termios); + } +} diff --git a/src/cmd/pforth/pf_io_stdio.c b/src/cmd/pforth/pf_io_stdio.c new file mode 100644 index 0000000..53161fa --- /dev/null +++ b/src/cmd/pforth/pf_io_stdio.c @@ -0,0 +1,56 @@ +/* $Id$ */ +/*************************************************************** +** I/O subsystem for PForth for common systems. +** +** Author: Phil Burk +** Copyright 1994 3DO, Phil Burk, Larry Polansky, David Rosenboom +** +** The pForth software code is dedicated to the public domain, +** and any third party may reproduce, distribute and modify +** the pForth software code or any derivative works thereof +** without any compensation or license. The pForth software +** code is provided on an "as is" basis without any warranty +** of any kind, including, without limitation, the implied +** warranties of merchantability and fitness for a particular +** purpose and their equivalents under the laws of any jurisdiction. +** +**************************************************************** +** 941004 PLB Extracted IO calls from pforth_main.c +***************************************************************/ + +#include "pf_all.h" + +/* Default portable terminal I/O. */ +int sdTerminalOut( char c ) +{ + return putchar(c); +} +/* We don't need to echo because getchar() echos. */ +int sdTerminalEcho( char c ) +{ + return 0; +} +int sdTerminalIn( void ) +{ + return getchar(); +} +int sdQueryTerminal( void ) +{ + return 0; +} + +int sdTerminalFlush( void ) +{ +#ifdef PF_NO_FILEIO + return -1; +#else + return fflush(PF_STDOUT); +#endif +} + +void sdTerminalInit( void ) +{ +} +void sdTerminalTerm( void ) +{ +} diff --git a/src/cmd/pforth/pf_main.c b/src/cmd/pforth/pf_main.c new file mode 100644 index 0000000..3d7f215 --- /dev/null +++ b/src/cmd/pforth/pf_main.c @@ -0,0 +1,150 @@ +/* @(#) pf_main.c 98/01/26 1.2 */ +/*************************************************************** +** Forth based on 'C' +** +** main() routine that demonstrates how to call PForth as +** a module from 'C' based application. +** Customize this as needed for your application. +** +** Author: Phil Burk +** Copyright 1994 3DO, Phil Burk, Larry Polansky, David Rosenboom +** +** The pForth software code is dedicated to the public domain, +** and any third party may reproduce, distribute and modify +** the pForth software code or any derivative works thereof +** without any compensation or license. The pForth software +** code is provided on an "as is" basis without any warranty +** of any kind, including, without limitation, the implied +** warranties of merchantability and fitness for a particular +** purpose and their equivalents under the laws of any jurisdiction. +** +***************************************************************/ + +#if (defined(PF_NO_STDIO) || defined(PF_EMBEDDED)) + #define NULL ((void *) 0) + #define ERR(msg) /* { printf msg; } */ +#else + #ifdef CROSS + #include + #else + #include + #endif + #define ERR(msg) { printf msg; } +#endif + +#include "pforth.h" + +#ifndef PF_DEFAULT_DICTIONARY +#define PF_DEFAULT_DICTIONARY "/lib/pforth.dic" +#endif + +#ifdef __MWERKS__ + #include + #include +#endif + +#ifndef TRUE +#define TRUE (1) +#define FALSE (0) +#endif + +#ifdef PF_EMBEDDED +int main( void ) +{ + char IfInit = 0; + const char *DicName = NULL; + const char *SourceName = NULL; + pfMessage("\npForth Embedded\n"); + return pfDoForth( DicName, SourceName, IfInit); +} +#else + +int main( int argc, char **argv ) +{ +#ifdef PF_STATIC_DIC + const char *DicName = NULL; +#else /* PF_STATIC_DIC */ + const char *DicName = PF_DEFAULT_DICTIONARY; +#endif /* !PF_STATIC_DIC */ + + const char *SourceName = NULL; + char IfInit = FALSE; + char *s; + cell_t i; + int Result; + +/* For Metroworks on Mac */ +#ifdef __MWERKS__ + argc = ccommand(&argv); +#endif + + pfSetQuiet( FALSE ); +/* Parse command line. */ + for( i=1; idlln_Previous) +#define dllNextNode(n) ((n)->dlln_Next) + +void dllSetupList( DoublyLinkedList *dll ) +{ + dll->dll_First = &(dll->dll_Null); + dll->dll_Null = (DoublyLinkedListNode *) NULL; + dll->dll_Last = &(dll->dll_First); +} + +void dllLinkNodes( DoublyLinkedListNode *Node0, DoublyLinkedListNode *Node1 ) +{ + Node0->dlln_Next = Node1; + Node1->dlln_Previous = Node0; +} + +void dllInsertNodeBefore( DoublyLinkedListNode *NewNodePtr, + DoublyLinkedListNode *NodeInListPtr ) +{ + DoublyLinkedListNode *NodePreviousPtr = dllPreviousNode( NodeInListPtr ); + dllLinkNodes( NodePreviousPtr, NewNodePtr ); + dllLinkNodes( NewNodePtr, NodeInListPtr ); +} + +void dllInsertNodeAfter( DoublyLinkedListNode *NewNodePtr, + DoublyLinkedListNode *NodeInListPtr ) +{ + DoublyLinkedListNode *NodeNextPtr = dllNextNode( NodeInListPtr ); + dllLinkNodes( NodeInListPtr, NewNodePtr ); + dllLinkNodes( NewNodePtr, NodeNextPtr ); +} + +void dllDumpNode( DoublyLinkedListNode *NodePtr ) +{ + TOUCH(NodePtr); + DBUG((" 0x%x -> (0x%x) -> 0x%x\n", + dllPreviousNode( NodePtr ), NodePtr, + dllNextNode( NodePtr ) )); +} + +cell_t dllCheckNode( DoublyLinkedListNode *NodePtr ) +{ + if( (NodePtr->dlln_Next->dlln_Previous != NodePtr) || + (NodePtr->dlln_Previous->dlln_Next != NodePtr)) + { + ERR("dllCheckNode: Bad Node!\n"); + dllDumpNode( dllPreviousNode( NodePtr ) ); + dllDumpNode( NodePtr ); + dllDumpNode( dllNextNode( NodePtr ) ); + return -1; + } + else + { + return 0; + } +} +void dllRemoveNode( DoublyLinkedListNode *NodePtr ) +{ + if( dllCheckNode( NodePtr ) == 0 ) + { + dllLinkNodes( dllPreviousNode( NodePtr ), dllNextNode( NodePtr ) ); + } +} + +void dllAddNodeToHead( DoublyLinkedList *ListPtr, DoublyLinkedListNode *NewNodePtr ) +{ + dllInsertNodeBefore( NewNodePtr, ListPtr->dll_First ); +} + +void dllAddNodeToTail( DoublyLinkedList *ListPtr, DoublyLinkedListNode *NewNodePtr ) +{ + dllInsertNodeAfter( NewNodePtr, ListPtr->dll_Last ); +} + +#define dllIsNodeInList( n ) (!((n)->dlln_Next == NULL) ) +#define dllIsLastNode( n ) ((n)->dlln_Next->dll_nNext == NULL ) +#define dllIsListEmpty( l ) ((l)->dll_First == ((DoublyLinkedListNode *) &((l)->dll_Null)) ) +#define dllFirstNode( l ) ((l)->dll_First) + +static DoublyLinkedList gMemList; + +typedef struct MemListNode +{ + DoublyLinkedListNode mln_Node; + cell_t mln_Size; +} MemListNode; + +#ifdef PF_DEBUG +/*************************************************************** +** Dump memory list. +*/ +void maDumpList( void ) +{ + MemListNode *mln; + + MSG("PForth MemList\n"); + + for( mln = (MemListNode *) dllFirstNode( &gMemList ); + dllIsNodeInList( (DoublyLinkedListNode *) mln); + mln = (MemListNode *) dllNextNode( (DoublyLinkedListNode *) mln ) ) + { + MSG(" Node at = 0x"); ffDotHex(mln); + MSG_NUM_H(", size = 0x", mln->mln_Size); + } +} +#endif + + +/*************************************************************** +** Free mem of any size. +*/ +static void pfFreeRawMem( char *Mem, cell_t NumBytes ) +{ + MemListNode *mln, *FreeNode; + MemListNode *AdjacentLower = NULL; + MemListNode *AdjacentHigher = NULL; + MemListNode *NextBiggest = NULL; + +/* Allocate in whole blocks of 16 bytes */ + DBUG(("\npfFreeRawMem( 0x%x, 0x%x )\n", Mem, NumBytes )); + NumBytes = (NumBytes + PF_MEM_BLOCK_SIZE - 1) & ~(PF_MEM_BLOCK_SIZE - 1); + DBUG(("\npfFreeRawMem: Align NumBytes to 0x%x\n", NumBytes )); + +/* Check memory alignment. */ + if( ( ((cell_t)Mem) & (PF_MEM_BLOCK_SIZE - 1)) != 0) + { + MSG_NUM_H("pfFreeRawMem: misaligned Mem = 0x", (cell_t) Mem ); + return; + } + +/* Scan list from low to high looking for various nodes. */ + for( mln = (MemListNode *) dllFirstNode( &gMemList ); + dllIsNodeInList( (DoublyLinkedListNode *) mln); + mln = (MemListNode *) dllNextNode( (DoublyLinkedListNode *) mln ) ) + { + if( (((char *) mln) + mln->mln_Size) == Mem ) + { + AdjacentLower = mln; + } + else if( ((char *) mln) == ( Mem + NumBytes )) + { + AdjacentHigher = mln; + } +/* is this the next biggest node. */ + else if( (NextBiggest == NULL) && (mln->mln_Size >= NumBytes) ) + { + NextBiggest = mln; + } + } + +/* Check to see if we can merge nodes. */ + if( AdjacentHigher ) + { +DBUG((" Merge (0x%x) -> 0x%x\n", Mem, AdjacentHigher )); + NumBytes += AdjacentHigher->mln_Size; + dllRemoveNode( (DoublyLinkedListNode *) AdjacentHigher ); + } + if( AdjacentLower ) + { +DBUG((" Merge 0x%x -> (0x%x)\n", AdjacentLower, Mem )); + AdjacentLower->mln_Size += NumBytes; + } + else + { +DBUG((" Link before 0x%x\n", NextBiggest )); + FreeNode = (MemListNode *) Mem; + FreeNode->mln_Size = NumBytes; + if( NextBiggest == NULL ) + { +/* Nothing bigger so add to end of list. */ + dllAddNodeToTail( &gMemList, (DoublyLinkedListNode *) FreeNode ); + } + else + { +/* Add this node before the next biggest one we found. */ + dllInsertNodeBefore( (DoublyLinkedListNode *) FreeNode, + (DoublyLinkedListNode *) NextBiggest ); + } + } + +/* maDumpList(); */ +} + + + +/*************************************************************** +** Setup memory list. Initialize allocator. +*/ +static void pfInitMemBlock( void *addr, ucell_t poolSize ) +{ + char *AlignedMemory; + cell_t AlignedSize; + + pfDebugMessage("pfInitMemBlock()\n"); +/* Set globals. */ + gMemPoolPtr = addr; + gMemPoolSize = poolSize; + + dllSetupList( &gMemList ); + +/* Adjust to next highest aligned memory location. */ + AlignedMemory = (char *) ((((cell_t)gMemPoolPtr) + PF_MEM_BLOCK_SIZE - 1) & + ~(PF_MEM_BLOCK_SIZE - 1)); + +/* Adjust size to reflect aligned memory. */ + AlignedSize = gMemPoolSize - (AlignedMemory - gMemPoolPtr); + +/* Align size of pool. */ + AlignedSize = AlignedSize & ~(PF_MEM_BLOCK_SIZE - 1); + +/* Free to pool. */ + pfFreeRawMem( AlignedMemory, AlignedSize ); + +} + +/*************************************************************** +** Allocate mem from list of free nodes. +*/ +static char *pfAllocRawMem( cell_t NumBytes ) +{ + char *Mem = NULL; + MemListNode *mln; + pfDebugMessage("pfAllocRawMem()\n"); + + if( NumBytes <= 0 ) return NULL; + +/* Allocate in whole blocks of 16 bytes */ + NumBytes = (NumBytes + PF_MEM_BLOCK_SIZE - 1) & ~(PF_MEM_BLOCK_SIZE - 1); + + DBUG(("\npfAllocRawMem( 0x%x )\n", NumBytes )); + +/* Scan list from low to high until we find a node big enough. */ + for( mln = (MemListNode *) dllFirstNode( &gMemList ); + dllIsNodeInList( (DoublyLinkedListNode *) mln); + mln = (MemListNode *) dllNextNode( (DoublyLinkedListNode *) mln ) ) + { + if( mln->mln_Size >= NumBytes ) + { + cell_t RemSize; + + Mem = (char *) mln; + +/* Remove this node from list. */ + dllRemoveNode( (DoublyLinkedListNode *) mln ); + +/* Is there enough left in block to make it worth splitting? */ + RemSize = mln->mln_Size - NumBytes; + if( RemSize >= PF_MEM_BLOCK_SIZE ) + { + pfFreeRawMem( (Mem + NumBytes), RemSize ); + } + break; + } + + } +/* maDumpList(); */ + DBUG(("Allocate mem at 0x%x.\n", Mem )); + return Mem; +} + +/*************************************************************** +** Keep mem size at first cell. +*/ +char *pfAllocMem( cell_t NumBytes ) +{ + cell_t *IntMem; + + if( NumBytes <= 0 ) return NULL; + +/* Allocate an extra cell for size. */ + NumBytes += sizeof(cell_t); + + IntMem = (cell_t *)pfAllocRawMem( NumBytes ); + + if( IntMem != NULL ) *IntMem++ = NumBytes; + + return (char *) IntMem; +} + +/*************************************************************** +** Free mem with mem size at first cell. +*/ +void pfFreeMem( void *Mem ) +{ + cell_t *IntMem; + cell_t NumBytes; + + if( Mem == NULL ) return; + +/* Allocate an extra cell for size. */ + IntMem = (cell_t *) Mem; + IntMem--; + NumBytes = *IntMem; + + pfFreeRawMem( (char *) IntMem, NumBytes ); + +} + +void pfInitMemoryAllocator( void ) +{ + pfInitMemBlock( PF_MALLOC_ADDRESS, PF_MEM_POOL_SIZE ); +} +#else /* PF_NO_MALLOC */ + +int not_an_empty_file; /* Stops nasty compiler warnings when PF_NO_MALLOC not defined. */ + +#endif /* PF_NO_MALLOC */ diff --git a/src/cmd/pforth/pf_mem.h b/src/cmd/pforth/pf_mem.h new file mode 100644 index 0000000..8c81f91 --- /dev/null +++ b/src/cmd/pforth/pf_mem.h @@ -0,0 +1,47 @@ +/* @(#) pf_mem.h 98/01/26 1.3 */ +#ifndef _pf_mem_h +#define _pf_mem_h + +/*************************************************************** +** Include file for PForth Fake Memory Allocator +** +** Author: Phil Burk +** Copyright 1994 3DO, Phil Burk, Larry Polansky, David Rosenboom +** +** The pForth software code is dedicated to the public domain, +** and any third party may reproduce, distribute and modify +** code is provided on an "as is" basis without any warranty +** of any kind, including, without limitation, the implied +** warranties of merchantability and fitness for a particular +***************************************************************/ + +#ifdef PF_NO_MALLOC + + #ifdef __cplusplus + extern "C" { + #endif + + void pfInitMemoryAllocator( void ); + char *pfAllocMem( cell_t NumBytes ); + void pfFreeMem( void *Mem ); + + #ifdef __cplusplus + } + #endif + +#else + + #ifdef PF_USER_MALLOC +/* Get user prototypes or macros from include file. +** API must match that defined above for the stubs. +*/ + #include PF_USER_MALLOC + #else + #define pfInitMemoryAllocator() + #define pfAllocMem malloc + #define pfFreeMem free + #endif + +#endif /* PF_NO_MALLOC */ + +#endif /* _pf_mem_h */ diff --git a/src/cmd/pforth/pf_save.c b/src/cmd/pforth/pf_save.c new file mode 100644 index 0000000..5ac7bef --- /dev/null +++ b/src/cmd/pforth/pf_save.c @@ -0,0 +1,845 @@ +/* @(#) pf_save.c 98/01/26 1.3 */ +/*************************************************************** +** Save and Load Dictionary +** for PForth based on 'C' +** +** Compile file based version or static data based version +** depending on PF_NO_FILEIO switch. +** +** Author: Phil Burk +** Copyright 1994 3DO, Phil Burk, Larry Polansky, David Rosenboom +** +** The pForth software code is dedicated to the public domain, +** and any third party may reproduce, distribute and modify +** the pForth software code or any derivative works thereof +** without any compensation or license. The pForth software +** code is provided on an "as is" basis without any warranty +** of any kind, including, without limitation, the implied +** warranties of merchantability and fitness for a particular +** purpose and their equivalents under the laws of any jurisdiction. +** +**************************************************************** +** 940225 PLB Fixed CodePtr save, was using NAMEREL instead of CODEREL +** This would only work if the relative location +** of names and code was the same when saved and reloaded. +** 940228 PLB Added PF_NO_FILEIO version +** 961204 PLB Added PF_STATIC_DIC +** 000623 PLB Cast chars as ucell_t before shifting for 16 bit systems. +***************************************************************/ + +#include + +#include "pf_all.h" + +/* If no File I/O, then force static dictionary. */ +#ifdef PF_NO_FILEIO + #ifndef PF_STATIC_DIC + #define PF_STATIC_DIC + #endif +#endif + +#ifdef PF_STATIC_DIC + #include "pfdicdat.h" +#endif + +/* +Dictionary File Format based on IFF standard. +The chunk IDs, sizes, and data values are all Big Endian in conformance with the IFF standard. +The dictionaries may be big or little endian. + 'FORM' + size + 'P4TH' - Form Identifier + +Chunks + 'P4DI' + size + struct DictionaryInfoChunk + + 'P4NM' + size + Name and Header portion of dictionary. (Big or Little Endian) (Optional) + + 'P4CD' + size + Code portion of dictionary. (Big or Little Endian) +*/ + + +/***************************************************************/ +/* Endian-ness tools. */ +ucell_t ReadCellBigEndian( const uint8_t *addr ) +{ + ucell_t temp = (ucell_t)addr[0]; + temp = (temp << 8) | ((ucell_t)addr[1]); + temp = (temp << 8) | ((ucell_t)addr[2]); + temp = (temp << 8) | ((ucell_t)addr[3]); + if( sizeof(ucell_t) == 8 ) + { + temp = (temp << 8) | ((ucell_t)addr[4]); + temp = (temp << 8) | ((ucell_t)addr[5]); + temp = (temp << 8) | ((ucell_t)addr[6]); + temp = (temp << 8) | ((ucell_t)addr[7]); + } + + return temp; +} +/***************************************************************/ +/* Endian-ness tools. */ +uint32_t Read32BigEndian( const uint8_t *addr ) +{ + uint32_t temp = (uint32_t)addr[0]; + temp = (temp << 8) | ((uint32_t)addr[1]); + temp = (temp << 8) | ((uint32_t)addr[2]); + temp = (temp << 8) | ((uint32_t)addr[3]); + return temp; +} + +/***************************************************************/ +uint16_t Read16BigEndian( const uint8_t *addr ) +{ + return (uint16_t) ((addr[0]<<8) | addr[1]); +} + +/***************************************************************/ +ucell_t ReadCellLittleEndian( const uint8_t *addr ) +{ + ucell_t temp = 0; + if( sizeof(ucell_t) == 8 ) + { + temp = (temp << 8) | ((uint32_t)addr[7]); + temp = (temp << 8) | ((uint32_t)addr[6]); + temp = (temp << 8) | ((uint32_t)addr[5]); + temp = (temp << 8) | ((uint32_t)addr[4]); + } + temp = (temp << 8) | ((uint32_t)addr[3]); + temp = (temp << 8) | ((uint32_t)addr[2]); + temp = (temp << 8) | ((uint32_t)addr[1]); + temp = (temp << 8) | ((uint32_t)addr[0]); + return temp; +} + +/***************************************************************/ +uint32_t Read32LittleEndian( const uint8_t *addr ) +{ + uint32_t temp = (uint32_t)addr[3]; + temp = (temp << 8) | ((uint32_t)addr[2]); + temp = (temp << 8) | ((uint32_t)addr[1]); + temp = (temp << 8) | ((uint32_t)addr[0]); + return temp; +} + +/***************************************************************/ +uint16_t Read16LittleEndian( const uint8_t *addr ) +{ + const unsigned char *bp = (const unsigned char *) addr; + return (uint16_t) ((bp[1]<<8) | bp[0]); +} + +#ifdef PF_SUPPORT_FP + +/***************************************************************/ +static void ReverseCopyFloat( const PF_FLOAT *src, PF_FLOAT *dst ); + +static void ReverseCopyFloat( const PF_FLOAT *src, PF_FLOAT *dst ) +{ + int i; + unsigned char *d = (unsigned char *) dst; + const unsigned char *s = (const unsigned char *) src; + + for( i=0; i>56); + *addr++ = (uint8_t) (data>>48); + *addr++ = (uint8_t) (data>>40); + *addr++ = (uint8_t) (data>>32); + } +#endif + *addr++ = (uint8_t) (data>>24); + *addr++ = (uint8_t) (data>>16); + *addr++ = (uint8_t) (data>>8); + *addr = (uint8_t) (data); +} + +/***************************************************************/ +void Write32BigEndian( uint8_t *addr, uint32_t data ) +{ + *addr++ = (uint8_t) (data>>24); + *addr++ = (uint8_t) (data>>16); + *addr++ = (uint8_t) (data>>8); + *addr = (uint8_t) (data); +} + +/***************************************************************/ +void Write16BigEndian( uint8_t *addr, uint16_t data ) +{ + *addr++ = (uint8_t) (data>>8); + *addr = (uint8_t) (data); +} + +/***************************************************************/ +void WriteCellLittleEndian( uint8_t *addr, ucell_t data ) +{ + /* Write should be in order of increasing address + * to optimize for burst writes to DRAM. */ + if( sizeof(ucell_t) == 8 ) + { + *addr++ = (uint8_t) data; /* LSB at near end */ + data = data >> 8; + *addr++ = (uint8_t) data; + data = data >> 8; + *addr++ = (uint8_t) data; + data = data >> 8; + *addr++ = (uint8_t) data; + data = data >> 8; + } + *addr++ = (uint8_t) data; + data = data >> 8; + *addr++ = (uint8_t) data; + data = data >> 8; + *addr++ = (uint8_t) data; + data = data >> 8; + *addr = (uint8_t) data; +} +/***************************************************************/ +void Write32LittleEndian( uint8_t *addr, uint32_t data ) +{ + *addr++ = (uint8_t) data; + data = data >> 8; + *addr++ = (uint8_t) data; + data = data >> 8; + *addr++ = (uint8_t) data; + data = data >> 8; + *addr = (uint8_t) data; +} + +/***************************************************************/ +void Write16LittleEndian( uint8_t *addr, uint16_t data ) +{ + *addr++ = (uint8_t) data; + data = data >> 8; + *addr = (uint8_t) data; +} + +/***************************************************************/ +/* Return 1 if host CPU is Little Endian */ +int IsHostLittleEndian( void ) +{ + static int gEndianCheck = 1; + unsigned char *bp = (unsigned char *) &gEndianCheck; + return (int) (*bp); /* Return byte pointed to by address. If LSB then == 1 */ +} + +#if defined(PF_NO_FILEIO) || defined(PF_NO_SHELL) + +cell_t ffSaveForth( const char *FileName, ExecToken EntryPoint, cell_t NameSize, cell_t CodeSize) +{ + TOUCH(FileName); + TOUCH(EntryPoint); + TOUCH(NameSize); + TOUCH(CodeSize); + + pfReportError("ffSaveForth", PF_ERR_NOT_SUPPORTED); + return -1; +} + +#else /* PF_NO_FILEIO or PF_NO_SHELL */ + +/***************************************************************/ +static int Write32ToFile( FileStream *fid, uint32_t Val ) +{ + int numw; + uint8_t pad[4]; + + Write32BigEndian(pad,Val); + numw = sdWriteFile( pad, 1, sizeof(pad), fid ); + if( numw != sizeof(pad) ) return -1; + return 0; +} + +/***************************************************************/ +static cell_t WriteChunkToFile( FileStream *fid, cell_t ID, char *Data, int32_t NumBytes ) +{ + cell_t numw; + cell_t EvenNumW; + + EvenNumW = EVENUP(NumBytes); + + if( Write32ToFile( fid, ID ) < 0 ) goto error; + if( Write32ToFile( fid, EvenNumW ) < 0 ) goto error; + + numw = sdWriteFile( Data, 1, EvenNumW, fid ); + if( numw != EvenNumW ) goto error; + return 0; +error: + pfReportError("WriteChunkToFile", PF_ERR_WRITE_FILE); + return -1; +} + +/* Convert dictionary info chunk between native and on-disk (big-endian). */ +static void +convertDictionaryInfoWrite (DictionaryInfoChunk *sd) +{ +/* Convert all fields in DictionaryInfoChunk from Native to BigEndian. + * This assumes they are all 32-bit integers. + */ + int i; + uint32_t *p = (uint32_t *) sd; + for (i=0; i<((int)(sizeof(*sd)/sizeof(uint32_t))); i++) + { + Write32BigEndian( (uint8_t *)&p[i], p[i] ); + } +} + +static void +convertDictionaryInfoRead (DictionaryInfoChunk *sd) +{ +/* Convert all fields in structure from BigEndian to Native. */ + int i; + uint32_t *p = (uint32_t *) sd; + for (i=0; i<((int)(sizeof(*sd)/sizeof(uint32_t))); i++) + { + p[i] = Read32BigEndian( (uint8_t *)&p[i] ); + } +} + +/**************************************************************** +** Save Dictionary in File. +** If EntryPoint is NULL, save as development environment. +** If EntryPoint is non-NULL, save as turnKey environment with no names. +*/ +cell_t ffSaveForth( const char *FileName, ExecToken EntryPoint, cell_t NameSize, cell_t CodeSize) +{ + FileStream *fid; + DictionaryInfoChunk SD; + uint32_t FormSize; + uint32_t NameChunkSize = 0; + uint32_t CodeChunkSize; + uint32_t relativeCodePtr; + + fid = sdOpenFile( FileName, "wb" ); + if( fid == NULL ) + { + pfReportError("pfSaveDictionary", PF_ERR_OPEN_FILE); + return -1; + } + +/* Save in uninitialized form. */ + pfExecIfDefined("AUTO.TERM"); + +/* Write FORM Header ---------------------------- */ + if( Write32ToFile( fid, ID_FORM ) < 0 ) goto error; + if( Write32ToFile( fid, 0 ) < 0 ) goto error; + if( Write32ToFile( fid, ID_P4TH ) < 0 ) goto error; + +/* Write P4DI Dictionary Info ------------------ */ + SD.sd_Version = PF_FILE_VERSION; + + relativeCodePtr = ABS_TO_CODEREL(gCurrentDictionary->dic_CodePtr.Byte); /* 940225 */ + SD.sd_RelCodePtr = relativeCodePtr; + SD.sd_UserStackSize = sizeof(cell_t) * (gCurrentTask->td_StackBase - gCurrentTask->td_StackLimit); + SD.sd_ReturnStackSize = sizeof(cell_t) * (gCurrentTask->td_ReturnBase - gCurrentTask->td_ReturnLimit); + SD.sd_NumPrimitives = gNumPrimitives; /* Must match compiled dictionary. */ + +#ifdef PF_SUPPORT_FP + SD.sd_FloatSize = sizeof(PF_FLOAT); /* Must match compiled dictionary. */ +#else + SD.sd_FloatSize = 0; +#endif + + SD.sd_CellSize = sizeof(cell_t); + +/* Set bit that specifies whether dictionary is BIG or LITTLE Endian. */ + { +#if defined(PF_BIG_ENDIAN_DIC) + int eflag = SD_F_BIG_ENDIAN_DIC; +#elif defined(PF_LITTLE_ENDIAN_DIC) + int eflag = 0; +#else + int eflag = IsHostLittleEndian() ? 0 : SD_F_BIG_ENDIAN_DIC; +#endif + SD.sd_Flags = eflag; + } + + if( EntryPoint ) + { + SD.sd_EntryPoint = EntryPoint; /* Turnkey! */ + } + else + { + SD.sd_EntryPoint = 0; + } + +/* Do we save names? */ + if( NameSize == 0 ) + { + SD.sd_RelContext = 0; + SD.sd_RelHeaderPtr = 0; + SD.sd_NameSize = 0; + } + else + { + uint32_t relativeHeaderPtr; +/* Development mode. */ + SD.sd_RelContext = ABS_TO_NAMEREL(gVarContext); + relativeHeaderPtr = ABS_TO_NAMEREL(gCurrentDictionary->dic_HeaderPtr); + SD.sd_RelHeaderPtr = relativeHeaderPtr; + +/* How much real name space is there? */ + NameChunkSize = QUADUP(relativeHeaderPtr); /* Align */ + +/* NameSize must be 0 or greater than NameChunkSize + 1K */ + NameSize = QUADUP(NameSize); /* Align */ + if( NameSize > 0 ) + { + NameSize = MAX( NameSize, (NameChunkSize + 1024) ); + } + SD.sd_NameSize = NameSize; + } + +/* How much real code is there? */ + CodeChunkSize = QUADUP(relativeCodePtr); + CodeSize = QUADUP(CodeSize); /* Align */ + CodeSize = MAX( CodeSize, (CodeChunkSize + 2048) ); + SD.sd_CodeSize = CodeSize; + + + convertDictionaryInfoWrite (&SD); + + if( WriteChunkToFile( fid, ID_P4DI, (char *) &SD, sizeof(DictionaryInfoChunk) ) < 0 ) goto error; + +/* Write Name Fields if NameSize non-zero ------- */ + if( NameSize > 0 ) + { + if( WriteChunkToFile( fid, ID_P4NM, (char *) NAME_BASE, + NameChunkSize ) < 0 ) goto error; + } + +/* Write Code Fields ---------------------------- */ + if( WriteChunkToFile( fid, ID_P4CD, (char *) CODE_BASE, + CodeChunkSize ) < 0 ) goto error; + + FormSize = sdTellFile( fid ) - 8; + sdSeekFile( fid, 4, PF_SEEK_SET ); + if( Write32ToFile( fid, FormSize ) < 0 ) goto error; + + sdCloseFile( fid ); + +/* Restore initialization. */ + pfExecIfDefined("AUTO.INIT"); + return 0; + +error: + sdSeekFile( fid, 0, PF_SEEK_SET ); + Write32ToFile( fid, ID_BADF ); /* Mark file as bad. */ + sdCloseFile( fid ); + +/* Restore initialization. */ + pfExecIfDefined("AUTO.INIT"); + + return -1; +} + +#endif /* !PF_NO_FILEIO and !PF_NO_SHELL */ + + +#ifndef PF_NO_FILEIO + +/***************************************************************/ +static uint32_t Read32FromFile( FileStream *fid, uint32_t *ValPtr ) +{ + int32_t numr; + uint8_t pad[4]; + numr = sdReadFile( pad, 1, sizeof(pad), fid ); + if( numr != sizeof(pad) ) return -1; + *ValPtr = Read32BigEndian( pad ); + return 0; +} + +/***************************************************************/ +PForthDictionary pfLoadDictionary( const char *FileName, ExecToken *EntryPointPtr ) +{ + pfDictionary_t *dic = NULL; + FileStream *fid; + DictionaryInfoChunk *sd; + uint32_t ChunkID; + uint32_t ChunkSize; + uint32_t FormSize; + uint32_t BytesLeft; + uint32_t numr; + int isDicBigEndian; + +DBUG(("pfLoadDictionary( %s )\n", FileName )); + +/* Open file. */ + fid = sdOpenFile( FileName, "rb" ); + if( fid == NULL ) + { + pfReportError("pfLoadDictionary", PF_ERR_OPEN_FILE); + goto xt_error; + } + +/* Read FORM, Size, ID */ + if (Read32FromFile( fid, &ChunkID ) < 0) goto read_error; + if( ChunkID != ID_FORM ) + { + pfReportError("pfLoadDictionary", PF_ERR_WRONG_FILE); + goto error; + } + + if (Read32FromFile( fid, &FormSize ) < 0) goto read_error; + BytesLeft = FormSize; + + if (Read32FromFile( fid, &ChunkID ) < 0) goto read_error; + BytesLeft -= 4; + if( ChunkID != ID_P4TH ) + { + pfReportError("pfLoadDictionary", PF_ERR_BAD_FILE); + goto error; + } + +/* Scan and parse all chunks in file. */ + while( BytesLeft > 0 ) + { + if (Read32FromFile( fid, &ChunkID ) < 0) goto read_error; + if (Read32FromFile( fid, &ChunkSize ) < 0) goto read_error; + BytesLeft -= 8; + + DBUG(("ChunkID = %4s, Size = %d\n", (char *)&ChunkID, ChunkSize )); + + switch( ChunkID ) + { + case ID_P4DI: + sd = (DictionaryInfoChunk *) pfAllocMem( ChunkSize ); + if( sd == NULL ) goto nomem_error; + + numr = sdReadFile( sd, 1, ChunkSize, fid ); + if( numr != ChunkSize ) goto read_error; + BytesLeft -= ChunkSize; + + convertDictionaryInfoRead (sd); + + isDicBigEndian = sd->sd_Flags & SD_F_BIG_ENDIAN_DIC; + + if( !gVarQuiet ) + { + MSG("pForth loading dictionary from file "); MSG(FileName); + EMIT_CR; + MSG_NUM_D(" File format version is ", sd->sd_Version ); + MSG_NUM_D(" Name space size = ", sd->sd_NameSize ); + MSG_NUM_D(" Code space size = ", sd->sd_CodeSize ); + MSG_NUM_D(" Entry Point = ", sd->sd_EntryPoint ); + MSG_NUM_D(" Cell Size = ", sd->sd_CellSize ); + MSG( (isDicBigEndian ? " Big Endian Dictionary" : + " Little Endian Dictionary") ); + if( isDicBigEndian == IsHostLittleEndian() ) MSG(" !!!!"); + EMIT_CR; + } + + if( sd->sd_Version > PF_FILE_VERSION ) + { + pfReportError("pfLoadDictionary", PF_ERR_VERSION_FUTURE ); + goto error; + } + if( sd->sd_Version < PF_EARLIEST_FILE_VERSION ) + { + pfReportError("pfLoadDictionary", PF_ERR_VERSION_PAST ); + goto error; + } + if( sd->sd_CellSize != sizeof(cell_t) ) + { + pfReportError("pfLoadDictionary", PF_ERR_CELL_SIZE_CONFLICT ); + goto error; + } + if( sd->sd_NumPrimitives > NUM_PRIMITIVES ) + { + pfReportError("pfLoadDictionary", PF_ERR_NOT_SUPPORTED ); + goto error; + } + +/* Check to make sure that EndianNess of dictionary matches mode of pForth. */ +#if defined(PF_BIG_ENDIAN_DIC) + if(isDicBigEndian == 0) +#elif defined(PF_LITTLE_ENDIAN_DIC) + if(isDicBigEndian == 1) +#else + if( isDicBigEndian == IsHostLittleEndian() ) +#endif + { + pfReportError("pfLoadDictionary", PF_ERR_ENDIAN_CONFLICT ); + goto error; + } + +/* Check for compatible float size. */ +#ifdef PF_SUPPORT_FP + if( sd->sd_FloatSize != sizeof(PF_FLOAT) ) +#else + if( sd->sd_FloatSize != 0 ) +#endif + { + pfReportError("pfLoadDictionary", PF_ERR_FLOAT_CONFLICT ); + goto error; + } + + dic = pfCreateDictionary( sd->sd_NameSize, sd->sd_CodeSize ); + if( dic == NULL ) goto nomem_error; + gCurrentDictionary = dic; + if( sd->sd_NameSize > 0 ) + { + gVarContext = NAMEREL_TO_ABS(sd->sd_RelContext); /* Restore context. */ + gCurrentDictionary->dic_HeaderPtr = (ucell_t)(uint8_t *) + NAMEREL_TO_ABS(sd->sd_RelHeaderPtr); + } + else + { + gVarContext = 0; + gCurrentDictionary->dic_HeaderPtr = (ucell_t)NULL; + } + gCurrentDictionary->dic_CodePtr.Byte = (uint8_t *) CODEREL_TO_ABS(sd->sd_RelCodePtr); + gNumPrimitives = sd->sd_NumPrimitives; /* Must match compiled dictionary. */ +/* Pass EntryPoint back to caller. */ + if( EntryPointPtr != NULL ) *EntryPointPtr = sd->sd_EntryPoint; + pfFreeMem(sd); + break; + + case ID_P4NM: +#ifdef PF_NO_SHELL + pfReportError("pfLoadDictionary", PF_ERR_NO_SHELL ); + goto error; +#else + if( NAME_BASE == 0 ) + { + pfReportError("pfLoadDictionary", PF_ERR_NO_NAMES ); + goto error; + } + if( gCurrentDictionary == NULL ) + { + pfReportError("pfLoadDictionary", PF_ERR_BAD_FILE ); + goto error; + } + if( ChunkSize > NAME_SIZE ) + { + pfReportError("pfLoadDictionary", PF_ERR_TOO_BIG); + goto error; + } + numr = sdReadFile( (char *) NAME_BASE, 1, ChunkSize, fid ); + if( numr != ChunkSize ) goto read_error; + BytesLeft -= ChunkSize; +#endif /* PF_NO_SHELL */ + break; + + case ID_P4CD: + if( gCurrentDictionary == NULL ) + { + pfReportError("pfLoadDictionary", PF_ERR_BAD_FILE ); + goto error; + } + if( ChunkSize > CODE_SIZE ) + { + pfReportError("pfLoadDictionary", PF_ERR_TOO_BIG); + goto error; + } + numr = sdReadFile( (uint8_t *) CODE_BASE, 1, ChunkSize, fid ); + if( numr != ChunkSize ) goto read_error; + BytesLeft -= ChunkSize; + break; + + default: + pfReportError("pfLoadDictionary", PF_ERR_BAD_FILE ); + sdSeekFile( fid, ChunkSize, PF_SEEK_CUR ); + break; + } + } + + sdCloseFile( fid ); + + if( NAME_BASE != 0) + { + cell_t Result; +/* Find special words in dictionary for global XTs. */ + if( (Result = FindSpecialXTs()) < 0 ) + { + pfReportError("pfLoadDictionary: FindSpecialXTs", Result); + goto error; + } + } + +DBUG(("pfLoadDictionary: return %p\n", dic)); + return (PForthDictionary) dic; + +nomem_error: + pfReportError("pfLoadDictionary", PF_ERR_NO_MEM); + sdCloseFile( fid ); + return NULL; + +read_error: + pfReportError("pfLoadDictionary", PF_ERR_READ_FILE); +error: + sdCloseFile( fid ); +xt_error: + return NULL; +} + +#else + +PForthDictionary pfLoadDictionary( const char *FileName, ExecToken *EntryPointPtr ) +{ + (void) FileName; + (void) EntryPointPtr; + return NULL; +} +#endif /* !PF_NO_FILEIO */ + + + +/***************************************************************/ +PForthDictionary pfLoadStaticDictionary( void ) +{ +#ifdef PF_STATIC_DIC + cell_t Result; + pfDictionary_t *dic; + cell_t NewNameSize, NewCodeSize; + + if( IF_LITTLE_ENDIAN != IsHostLittleEndian() ) + { + MSG( (IF_LITTLE_ENDIAN ? + "Little Endian Dictionary on " : + "Big Endian Dictionary on ") ); + MSG( (IsHostLittleEndian() ? + "Little Endian CPU" : + "Big Endian CPU") ); + EMIT_CR; + } + +/* Check to make sure that EndianNess of dictionary matches mode of pForth. */ +#if defined(PF_BIG_ENDIAN_DIC) + if(IF_LITTLE_ENDIAN == 1) +#elif defined(PF_LITTLE_ENDIAN_DIC) + if(IF_LITTLE_ENDIAN == 0) +#else /* Code is native endian! */ + if( IF_LITTLE_ENDIAN != IsHostLittleEndian() ) +#endif + { + pfReportError("pfLoadStaticDictionary", PF_ERR_ENDIAN_CONFLICT ); + goto error; + } + + +#ifndef PF_EXTRA_HEADERS + #define PF_EXTRA_HEADERS (20000) +#endif +#ifndef PF_EXTRA_CODE + #define PF_EXTRA_CODE (40000) +#endif + +/* Copy static const data to allocated dictionaries. */ + NewNameSize = sizeof(MinDicNames) + PF_EXTRA_HEADERS; + NewCodeSize = sizeof(MinDicCode) + PF_EXTRA_CODE; + + DBUG_NUM_D( "static dic name size = ", NewNameSize ); + DBUG_NUM_D( "static dic code size = ", NewCodeSize ); + + gCurrentDictionary = dic = pfCreateDictionary( NewNameSize, NewCodeSize ); + if( !dic ) goto nomem_error; + + pfCopyMemory( (uint8_t *) dic->dic_HeaderBase, MinDicNames, sizeof(MinDicNames) ); + pfCopyMemory( (uint8_t *) dic->dic_CodeBase, MinDicCode, sizeof(MinDicCode) ); + DBUG(("Static data copied to newly allocated dictionaries.\n")); + + dic->dic_CodePtr.Byte = (uint8_t *) CODEREL_TO_ABS(CODEPTR); + gNumPrimitives = NUM_PRIMITIVES; + + if( NAME_BASE != 0) + { +/* Setup name space. */ + dic->dic_HeaderPtr = (ucell_t)(uint8_t *) NAMEREL_TO_ABS(HEADERPTR); + gVarContext = NAMEREL_TO_ABS(RELCONTEXT); /* Restore context. */ + +/* Find special words in dictionary for global XTs. */ + if( (Result = FindSpecialXTs()) < 0 ) + { + pfReportError("pfLoadStaticDictionary: FindSpecialXTs", Result); + goto error; + } + } + + return (PForthDictionary) dic; + +error: + return NULL; + +nomem_error: + pfReportError("pfLoadStaticDictionary", PF_ERR_NO_MEM); +#endif /* PF_STATIC_DIC */ + + return NULL; +} diff --git a/src/cmd/pforth/pf_save.h b/src/cmd/pforth/pf_save.h new file mode 100644 index 0000000..ea12cad --- /dev/null +++ b/src/cmd/pforth/pf_save.h @@ -0,0 +1,100 @@ +/* @(#) pf_save.h 96/12/18 1.8 */ +#ifndef _pforth_save_h +#define _pforth_save_h + +/*************************************************************** +** Include file for PForth SaveForth +** +** Author: Phil Burk +** Copyright 1994 3DO, Phil Burk, Larry Polansky, David Rosenboom +** +** The pForth software code is dedicated to the public domain, +** and any third party may reproduce, distribute and modify +** the pForth software code or any derivative works thereof +** without any compensation or license. The pForth software +** code is provided on an "as is" basis without any warranty +** of any kind, including, without limitation, the implied +** warranties of merchantability and fitness for a particular +** purpose and their equivalents under the laws of any jurisdiction. +** +** 941031 rdg fix redefinition of MAKE_ID and EVENUP to be conditional +** +***************************************************************/ + + +typedef struct DictionaryInfoChunk +{ +/* All fields are stored in BIG ENDIAN format for consistency in data files. + * All fields must be the same size for easy endian conversion. + * All fields must be 32 bit for file compatibility with older versions. + */ + int32_t sd_Version; + int32_t sd_RelContext; /* relative ptr to Dictionary Context */ + int32_t sd_RelHeaderPtr; /* relative ptr to Dictionary Header Ptr */ + int32_t sd_RelCodePtr; /* relative ptr to Dictionary Header Ptr */ + int32_t sd_EntryPoint; /* relative ptr to entry point or NULL */ + int32_t sd_UserStackSize; /* in bytes */ + int32_t sd_ReturnStackSize; /* in bytes */ + int32_t sd_NameSize; /* in bytes */ + int32_t sd_CodeSize; /* in bytes */ + int32_t sd_NumPrimitives; /* To distinguish between primitive and secondary. */ + uint32_t sd_Flags; + int32_t sd_FloatSize; /* In bytes. Must match code. 0 means no floats. */ + int32_t sd_CellSize; /* In bytes. Must match code. */ +} DictionaryInfoChunk; + +/* Bits in sd_Flags */ +#define SD_F_BIG_ENDIAN_DIC (1<<0) + +#ifndef MAKE_ID +#define MAKE_ID(a,b,c,d) ((((uint32_t)a)<<24)|(((uint32_t)b)<<16)|(((uint32_t)c)<<8)|((uint32_t)d)) +#endif + +#define ID_FORM MAKE_ID('F','O','R','M') +#define ID_P4TH MAKE_ID('P','4','T','H') +#define ID_P4DI MAKE_ID('P','4','D','I') +#define ID_P4NM MAKE_ID('P','4','N','M') +#define ID_P4CD MAKE_ID('P','4','C','D') +#define ID_BADF MAKE_ID('B','A','D','F') + +#ifndef EVENUP +#define EVENUP(n) ((n+1)&(~1)) +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +cell_t ffSaveForth( const char *FileName, ExecToken EntryPoint, cell_t NameSize, cell_t CodeSize ); + +/* Endian-ness tools. */ +int IsHostLittleEndian( void ); + +ucell_t ReadCellBigEndian( const uint8_t *addr ); +uint32_t Read32BigEndian( const uint8_t *addr ); +uint16_t Read16BigEndian( const uint8_t *addr ); + +ucell_t ReadCellLittleEndian( const uint8_t *addr ); +uint32_t Read32LittleEndian( const uint8_t *addr ); +uint16_t Read16LittleEndian( const uint8_t *addr ); + +void WriteCellBigEndian( uint8_t *addr, ucell_t data ); +void Write32BigEndian( uint8_t *addr, uint32_t data ); +void Write16BigEndian( uint8_t *addr, uint16_t data ); + +void WriteCellLittleEndian( uint8_t *addr, ucell_t data ); +void Write32LittleEndian( uint8_t *addr, uint32_t data ); +void Write16LittleEndian( uint8_t *addr, uint16_t data ); + +#ifdef PF_SUPPORT_FP +void WriteFloatBigEndian( PF_FLOAT *addr, PF_FLOAT data ); +PF_FLOAT ReadFloatBigEndian( const PF_FLOAT *addr ); +void WriteFloatLittleEndian( PF_FLOAT *addr, PF_FLOAT data ); +PF_FLOAT ReadFloatLittleEndian( const PF_FLOAT *addr ); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _pforth_save_h */ diff --git a/src/cmd/pforth/pf_text.c b/src/cmd/pforth/pf_text.c new file mode 100644 index 0000000..cdabea5 --- /dev/null +++ b/src/cmd/pforth/pf_text.c @@ -0,0 +1,407 @@ +/* @(#) pf_text.c 98/01/26 1.3 */ +/*************************************************************** +** Text Strings for Error Messages +** Various Text tools. +** +** For PForth based on 'C' +** +** Author: Phil Burk +** Copyright 1994 3DO, Phil Burk, Larry Polansky, David Rosenboom +** +** The pForth software code is dedicated to the public domain, +** and any third party may reproduce, distribute and modify +** the pForth software code or any derivative works thereof +** without any compensation or license. The pForth software +** code is provided on an "as is" basis without any warranty +** of any kind, including, without limitation, the implied +** warranties of merchantability and fitness for a particular +** purpose and their equivalents under the laws of any jurisdiction. +** +**************************************************************** +** 19970702 PLB Fixed ConvertNumberToText for unsigned numbers. +** 19980522 PLB Expand PAD for ConvertNumberToText so "-1 binary .s" doesn't crash. +***************************************************************/ + +#include "pf_all.h" + +#define PF_ENGLISH + +/* +** Define array of error messages. +** These are defined in one place to make it easier to translate them. +*/ +#ifdef PF_ENGLISH +/***************************************************************/ +void pfReportError( const char *FunctionName, Err ErrCode ) +{ + const char *s; + + MSG("Error in "); + MSG(FunctionName); + MSG(" - "); + + switch(ErrCode & 0xFF) + { + case PF_ERR_NO_MEM & 0xFF: + s = "insufficient memory"; break; + case PF_ERR_TOO_BIG & 0xFF: + s = "data chunk too large"; break; + case PF_ERR_NUM_PARAMS & 0xFF: + s = "incorrect number of parameters"; break; + case PF_ERR_OPEN_FILE & 0xFF: + s = "could not open file"; break; + case PF_ERR_WRONG_FILE & 0xFF: + s = "wrong type of file format"; break; + case PF_ERR_BAD_FILE & 0xFF: + s = "badly formatted file"; break; + case PF_ERR_READ_FILE & 0xFF: + s = "file read failed"; break; + case PF_ERR_WRITE_FILE & 0xFF: + s = "file write failed"; break; + case PF_ERR_CORRUPT_DIC & 0xFF: + s = "corrupted dictionary"; break; + case PF_ERR_NOT_SUPPORTED & 0xFF: + s = "not supported in this version"; break; + case PF_ERR_VERSION_FUTURE & 0xFF: + s = "version from future"; break; + case PF_ERR_VERSION_PAST & 0xFF: + s = "version is obsolete. Rebuild new one."; break; + case PF_ERR_COLON_STACK & 0xFF: + s = "stack depth changed between : and ; . Probably unbalanced conditional"; break; + case PF_ERR_HEADER_ROOM & 0xFF: + s = "no room left in header space"; break; + case PF_ERR_CODE_ROOM & 0xFF: + s = "no room left in code space"; break; + case PF_ERR_NO_SHELL & 0xFF: + s = "attempt to use names in forth compiled with PF_NO_SHELL"; break; + case PF_ERR_NO_NAMES & 0xFF: + s = "dictionary has no names"; break; + case PF_ERR_OUT_OF_RANGE & 0xFF: + s = "parameter out of range"; break; + case PF_ERR_ENDIAN_CONFLICT & 0xFF: + s = "endian-ness of dictionary does not match code"; break; + case PF_ERR_FLOAT_CONFLICT & 0xFF: + s = "float support mismatch between .dic file and code"; break; + case PF_ERR_CELL_SIZE_CONFLICT & 0xFF: + s = "cell size mismatch between .dic file and code"; break; + default: + s = "unrecognized error code!"; break; + } + MSG(s); + EMIT_CR; +} + +void pfReportThrow( ThrowCode code ) +{ + const char *s = NULL; + switch(code) + { + case THROW_ABORT: + case THROW_ABORT_QUOTE: + s = "ABORT"; break; + case THROW_STACK_OVERFLOW: + s = "Stack overflow!"; break; + case THROW_STACK_UNDERFLOW: + s = "Stack underflow!"; break; + case THROW_EXECUTING: + s = "Executing a compile-only word!"; break; + case THROW_FLOAT_STACK_UNDERFLOW: + s = "Float Stack underflow!"; break; + case THROW_UNDEFINED_WORD: + s = "Undefined word!"; break; + case THROW_PAIRS: + s = "Conditional control structure mismatch!"; break; + case THROW_BYE: + case THROW_QUIT: + break; + case THROW_SEMICOLON: + s = "Stack depth changed between : and ; . Probably unbalanced conditional!"; break; + case THROW_DEFERRED: + s = "Not a DEFERred word!"; break; + default: + s = "Unrecognized throw code!"; break; + } + + if( s ) + { + MSG_NUM_D("THROW code = ", code ); + MSG(s); + EMIT_CR; + } +} +#endif + +/************************************************************** +** Copy a Forth String to a 'C' string. +*/ + +char *ForthStringToC( char *dst, const char *FString, cell_t dstSize ) +{ + cell_t Len; + + Len = (cell_t) *FString; + /* Make sure the text + NUL can fit. */ + if( Len >= dstSize ) + { + Len = dstSize - 1; + } + pfCopyMemory( dst, FString+1, Len ); + dst[Len] = '\0'; + + return dst; +} + +/************************************************************** +** Copy a NUL terminated string to a Forth counted string. +*/ +char *CStringToForth( char *dst, const char *CString, cell_t dstSize ) +{ + cell_t i; + + /* Make sure the SIZE+text can fit. */ + for( i=1; is2; +*/ +cell_t ffCompare( const char *s1, cell_t len1, const char *s2, int32_t len2 ) +{ + cell_t i, result, n, diff; + + result = 0; + n = MIN(len1,len2); + for( i=0; i 0) ? -1 : 1 ; + break; + } + } + if( result == 0 ) /* Match up to MIN(len1,len2) */ + { + if( len1 < len2 ) + { + result = -1; + } + else if ( len1 > len2 ) + { + result = 1; + } + } + return result; +} + +/*************************************************************** +** Convert number to text. +*/ +#define CNTT_PAD_SIZE ((sizeof(cell_t)*8)+2) /* PLB 19980522 - Expand PAD so "-1 binary .s" doesn't crash. */ +static char cnttPad[CNTT_PAD_SIZE]; + +char *ConvertNumberToText( cell_t Num, cell_t Base, int32_t IfSigned, int32_t MinChars ) +{ + cell_t IfNegative = 0; + char *p,c; + ucell_t NewNum, Rem, uNum; + cell_t i = 0; + + uNum = Num; + if( IfSigned ) + { +/* Convert to positive and keep sign. */ + if( Num < 0 ) + { + IfNegative = TRUE; + uNum = -Num; + } + } + +/* Point past end of Pad */ + p = cnttPad + CNTT_PAD_SIZE; + *(--p) = (char) 0; /* NUL terminate */ + + while( (i++ '}')) c = '.'; + EMIT(c); + } + EMIT_CR; + } +} + + +/* Print name, mask off any dictionary bits. */ +void TypeName( const char *Name ) +{ + const char *FirstChar; + cell_t Len; + + FirstChar = Name+1; + Len = *Name & 0x1F; + + ioType( FirstChar, Len ); +} + + + +#ifdef PF_UNIT_TEST +/* Unit test for string conversion routines. */ +#define ASSERT_PAD_IS( index, value, msg ) \ + if( pad[index] != ((char)(value)) ) \ + { \ + ERR(( "ERROR text test failed: " msg "\n")); \ + numErrors += 1; \ + } \ + +cell_t pfUnitTestText( void ) +{ + cell_t numErrors = 0; + char pad[16]; + char fpad[8]; + + /* test CStringToForth */ + pfSetMemory(pad,0xA5,sizeof(pad)); + CStringToForth( pad, "frog", 6 ); + ASSERT_PAD_IS( 0, 4, "CS len 6" ); + ASSERT_PAD_IS( 4, 'g', "CS end 6" ); + ASSERT_PAD_IS( 5, 0xA5, "CS past 6" ); + + pfSetMemory(pad,0xA5,sizeof(pad)); + CStringToForth( pad, "frog", 5 ); + ASSERT_PAD_IS( 0, 4, "CS len 5" ); + ASSERT_PAD_IS( 4, 'g', "CS end 5" ); + ASSERT_PAD_IS( 5, 0xA5, "CS past 5" ); + + pfSetMemory(pad,0xA5,sizeof(pad)); + CStringToForth( pad, "frog", 4 ); + ASSERT_PAD_IS( 0, 3, "CS len 4" ); + ASSERT_PAD_IS( 3, 'o', "CS end 4" ); + ASSERT_PAD_IS( 4, 0xA5, "CS past 4" ); + + /* Make a Forth string for testing ForthStringToC. */ + CStringToForth( fpad, "frog", sizeof(fpad) ); + + pfSetMemory(pad,0xA5,sizeof(pad)); + ForthStringToC( pad, fpad, 6 ); + ASSERT_PAD_IS( 0, 'f', "FS len 6" ); + ASSERT_PAD_IS( 3, 'g', "FS end 6" ); + ASSERT_PAD_IS( 4, 0, "FS nul 6" ); + ASSERT_PAD_IS( 5, 0xA5, "FS past 6" ); + + pfSetMemory(pad,0xA5,sizeof(pad)); + ForthStringToC( pad, fpad, 5 ); + ASSERT_PAD_IS( 0, 'f', "FS len 5" ); + ASSERT_PAD_IS( 3, 'g', "FS end 5" ); + ASSERT_PAD_IS( 4, 0, "FS nul 5" ); + ASSERT_PAD_IS( 5, 0xA5, "FS past 5" ); + + pfSetMemory(pad,0xA5,sizeof(pad)); + ForthStringToC( pad, fpad, 4 ); + ASSERT_PAD_IS( 0, 'f', "FS len 4" ); + ASSERT_PAD_IS( 2, 'o', "FS end 4" ); + ASSERT_PAD_IS( 3, 0, "FS nul 4" ); + ASSERT_PAD_IS( 4, 0xA5, "FS past 4" ); + + return numErrors; +} +#endif diff --git a/src/cmd/pforth/pf_text.h b/src/cmd/pforth/pf_text.h new file mode 100644 index 0000000..d01df24 --- /dev/null +++ b/src/cmd/pforth/pf_text.h @@ -0,0 +1,71 @@ +/* @(#) pf_text.h 96/12/18 1.10 */ +#ifndef _pforth_text_h +#define _pforth_text_h + +/*************************************************************** +** Include file for PForth Text +** +** Author: Phil Burk +** Copyright 1994 3DO, Phil Burk, Larry Polansky, David Rosenboom +** +** The pForth software code is dedicated to the public domain, +** and any third party may reproduce, distribute and modify +** the pForth software code or any derivative works thereof +** without any compensation or license. The pForth software +** code is provided on an "as is" basis without any warranty +** of any kind, including, without limitation, the implied +** warranties of merchantability and fitness for a particular +** purpose and their equivalents under the laws of any jurisdiction. +** +***************************************************************/ + +#define PF_ERR_INDEX_MASK (0xFFFF) +#define PF_ERR_BASE (0x80000000) +#define PF_ERR_NO_MEM (PF_ERR_BASE | 0) +#define PF_ERR_TOO_BIG (PF_ERR_BASE | 2) +#define PF_ERR_NUM_PARAMS (PF_ERR_BASE | 3) +#define PF_ERR_OPEN_FILE (PF_ERR_BASE | 4) +#define PF_ERR_WRONG_FILE (PF_ERR_BASE | 5) +#define PF_ERR_BAD_FILE (PF_ERR_BASE | 6) +#define PF_ERR_READ_FILE (PF_ERR_BASE | 7) +#define PF_ERR_WRITE_FILE (PF_ERR_BASE | 8) +#define PF_ERR_CORRUPT_DIC (PF_ERR_BASE | 9) +#define PF_ERR_NOT_SUPPORTED (PF_ERR_BASE | 10) +#define PF_ERR_VERSION_FUTURE (PF_ERR_BASE | 11) +#define PF_ERR_VERSION_PAST (PF_ERR_BASE | 12) +#define PF_ERR_COLON_STACK (PF_ERR_BASE | 13) +#define PF_ERR_HEADER_ROOM (PF_ERR_BASE | 14) +#define PF_ERR_CODE_ROOM (PF_ERR_BASE | 15) +#define PF_ERR_NO_SHELL (PF_ERR_BASE | 16) +#define PF_ERR_NO_NAMES (PF_ERR_BASE | 17) +#define PF_ERR_OUT_OF_RANGE (PF_ERR_BASE | 18) +#define PF_ERR_ENDIAN_CONFLICT (PF_ERR_BASE | 19) +#define PF_ERR_FLOAT_CONFLICT (PF_ERR_BASE | 20) +#define PF_ERR_CELL_SIZE_CONFLICT (PF_ERR_BASE | 21) +/* If you add an error code here, also add a text message in "pf_text.c". */ + +#ifdef __cplusplus +extern "C" { +#endif + +void pfReportError( const char *FunctionName, Err ErrCode ); +void pfReportThrow( ThrowCode code ); + +char *ForthStringToC( char *dst, const char *FString, cell_t dstSize ); +char *CStringToForth( char *dst, const char *CString, cell_t dstSize ); + +cell_t ffCompare( const char *s1, cell_t len1, const char *s2, int32_t len2 ); +cell_t ffCompareText( const char *s1, const char *s2, cell_t len ); +cell_t ffCompareTextCaseN( const char *s1, const char *s2, cell_t len ); + +void DumpMemory( void *addr, cell_t cnt); +char *ConvertNumberToText( cell_t Num, cell_t Base, int32_t IfSigned, int32_t MinChars ); +void TypeName( const char *Name ); + +cell_t pfUnitTestText( void ); + +#ifdef __cplusplus +} +#endif + +#endif /* _pforth_text_h */ diff --git a/src/cmd/pforth/pf_types.h b/src/cmd/pforth/pf_types.h new file mode 100644 index 0000000..87d95f6 --- /dev/null +++ b/src/cmd/pforth/pf_types.h @@ -0,0 +1,35 @@ +/* @(#) pf_types.h 96/12/18 1.3 */ +#ifndef _pf_types_h +#define _pf_types_h + +/*************************************************************** +** Type declarations for PForth, a Forth based on 'C' +** +** Author: Phil Burk +** Copyright 1994 3DO, Phil Burk, Larry Polansky, David Rosenboom +** +** The pForth software code is dedicated to the public domain, +** and any third party may reproduce, distribute and modify +** the pForth software code or any derivative works thereof +** without any compensation or license. The pForth software +** code is provided on an "as is" basis without any warranty +** of any kind, including, without limitation, the implied +** warranties of merchantability and fitness for a particular +** purpose and their equivalents under the laws of any jurisdiction. +** +***************************************************************/ + +/*************************************************************** +** Type Declarations +***************************************************************/ + +#ifndef Err + typedef long Err; +#endif + +typedef cell_t *dicptr; + +typedef char ForthString; +typedef char *ForthStringPtr; + +#endif /* _pf_types_h */ diff --git a/src/cmd/pforth/pf_win32.h b/src/cmd/pforth/pf_win32.h new file mode 100644 index 0000000..1bb298a --- /dev/null +++ b/src/cmd/pforth/pf_win32.h @@ -0,0 +1,41 @@ +/* @(#) pf_win32.h 98/01/26 1.2 */ +#ifndef _pf_win32_h +#define _pf_win32_h + +#include + +/*************************************************************** +** WIN32 dependant include file for PForth, a Forth based on 'C' +** +** Author: Phil Burk +** Copyright 1994 3DO, Phil Burk, Larry Polansky, David Rosenboom +** +** The pForth software code is dedicated to the public domain, +** and any third party may reproduce, distribute and modify +** the pForth software code or any derivative works thereof +** without any compensation or license. The pForth software +** code is provided on an "as is" basis without any warranty +** of any kind, including, without limitation, the implied +** warranties of merchantability and fitness for a particular +** purpose and their equivalents under the laws of any jurisdiction. +** +***************************************************************/ + +/* Include as PF_USER_INC2 for PCs */ + +/* Modify some existing defines. */ + +/* +** The PC will insert LF characters into the dictionary files unless +** we use "b" mode! +*/ +#undef PF_FAM_CREATE +#define PF_FAM_CREATE ("wb+") + +#undef PF_FAM_OPEN_RO +#define PF_FAM_OPEN_RO ("rb") + +#undef PF_FAM_OPEN_RW +#define PF_FAM_OPEN_RW ("rb+") + +#endif /* _pf_win32_h */ diff --git a/src/cmd/pforth/pf_words.c b/src/cmd/pforth/pf_words.c new file mode 100644 index 0000000..d30e962 --- /dev/null +++ b/src/cmd/pforth/pf_words.c @@ -0,0 +1,223 @@ +/* @(#) pf_words.c 96/12/18 1.10 */ +/*************************************************************** +** Forth words for PForth based on 'C' +** +** Author: Phil Burk +** Copyright 1994 3DO, Phil Burk, Larry Polansky, David Rosenboom +** +** The pForth software code is dedicated to the public domain, +** and any third party may reproduce, distribute and modify +** the pForth software code or any derivative works thereof +** without any compensation or license. The pForth software +** code is provided on an "as is" basis without any warranty +** of any kind, including, without limitation, the implied +** warranties of merchantability and fitness for a particular +** purpose and their equivalents under the laws of any jurisdiction. +** +** +** 941031 rdg fix ffScan() to look for CRs and LFs +** +***************************************************************/ + +#include "pf_all.h" + + +/*************************************************************** +** Print number in current base to output stream. +** This version does not handle double precision. +*/ +void ffDot( cell_t n ) +{ + MSG( ConvertNumberToText( n, gVarBase, TRUE, 1 ) ); + EMIT(' '); +} + +/*************************************************************** +** Print number in current base to output stream. +** This version does not handle double precision. +*/ +void ffDotHex( cell_t n ) +{ + MSG( ConvertNumberToText( n, 16, FALSE, 1 ) ); + EMIT(' '); +} + +/* ( ... --- ... , print stack ) */ +void ffDotS( void ) +{ + cell_t *sp; + cell_t i, Depth; + + MSG("Stack<"); + MSG( ConvertNumberToText( gVarBase, 10, TRUE, 1 ) ); /* Print base in decimal. */ + MSG("> "); + + Depth = gCurrentTask->td_StackBase - gCurrentTask->td_StackPtr; + sp = gCurrentTask->td_StackBase; + + if( Depth < 0 ) + { + MSG("UNDERFLOW!"); + } + else + { + for( i=0; i 0 ) && + (( *s == BLANK) || ( *s == '\t')) ) + { +DBUGX(("ffSkip BLANK: %c, %d\n", *s, Cnt )); + s++; + Cnt--; + } + } + else + { + while(( Cnt > 0 ) && ( *s == c )) + { +DBUGX(("ffSkip: %c=0x%x, %d\n", *s, Cnt )); + s++; + Cnt--; + } + } + *AddrOut = s; + return Cnt; +} + +/* ( addr cnt char -- addr' cnt' , scan for char ) */ +cell_t ffScan( char *AddrIn, cell_t Cnt, char c, char **AddrOut ) +{ + char *s; + + s = AddrIn; + + if( c == BLANK ) + { + while(( Cnt > 0 ) && + ( *s != BLANK) && + ( *s != '\r') && + ( *s != '\n') && + ( *s != '\t')) + { +DBUGX(("ffScan BLANK: %c, %d\n", *s, Cnt )); + s++; + Cnt--; + } + } + else + { + while(( Cnt > 0 ) && ( *s != c )) + { +DBUGX(("ffScan: %c, %d\n", *s, Cnt )); + s++; + Cnt--; + } + } + *AddrOut = s; + return Cnt; +} + +/*************************************************************** +** Forth equivalent 'C' functions. +***************************************************************/ + +/* Convert a single digit to the corresponding hex number. */ +static cell_t HexDigitToNumber( char c ) +{ + if( (c >= '0') && (c <= '9') ) + { + return( c - '0' ); + } + else if ( (c >= 'A') && (c <= 'F') ) + { + return( c - 'A' + 0x0A ); + } + else + { + return -1; + } +} + +/* Convert a string to the corresponding number using BASE. */ +cell_t ffNumberQ( const char *FWord, cell_t *Num ) +{ + cell_t Len, i, Accum=0, n, Sign=1; + const char *s; + +/* get count */ + Len = *FWord++; + s = FWord; + +/* process initial minus sign */ + if( *s == '-' ) + { + Sign = -1; + s++; + Len--; + } + + for( i=0; i= gVarBase) ) + { + return NUM_TYPE_BAD; + } + + Accum = (Accum * gVarBase) + n; + } + *Num = Accum * Sign; + return NUM_TYPE_SINGLE; +} + +/*************************************************************** +** Compiler Support +***************************************************************/ + +/* ( char -- c-addr , parse word ) */ +char * ffWord( char c ) +{ + char *s1,*s2,*s3; + cell_t n1, n2, n3; + cell_t i, nc; + + s1 = gCurrentTask->td_SourcePtr + gCurrentTask->td_IN; + n1 = gCurrentTask->td_SourceNum - gCurrentTask->td_IN; + n2 = ffSkip( s1, n1, c, &s2 ); +DBUGX(("ffWord: s2=%c, %d\n", *s2, n2 )); + n3 = ffScan( s2, n2, c, &s3 ); +DBUGX(("ffWord: s3=%c, %d\n", *s3, n3 )); + nc = n2-n3; + if (nc > 0) + { + gScratch[0] = (char) nc; + for( i=0; itd_IN += (n1-n3) + 1; + return &gScratch[0]; +} diff --git a/src/cmd/pforth/pf_words.h b/src/cmd/pforth/pf_words.h new file mode 100644 index 0000000..0dc33fe --- /dev/null +++ b/src/cmd/pforth/pf_words.h @@ -0,0 +1,36 @@ +/* @(#) pf_words.h 96/12/18 1.7 */ +#ifndef _pforth_words_h +#define _pforth_words_h + +/*************************************************************** +** Include file for PForth Words +** +** Author: Phil Burk +** Copyright 1994 3DO, Phil Burk, Larry Polansky, David Rosenboom +** +** The pForth software code is dedicated to the public domain, +** and any third party may reproduce, distribute and modify +** the pForth software code or any derivative works thereof +** without any compensation or license. The pForth software +** code is provided on an "as is" basis without any warranty +** of any kind, including, without limitation, the implied +** warranties of merchantability and fitness for a particular +** purpose and their equivalents under the laws of any jurisdiction. +** +***************************************************************/ + +#ifdef __cplusplus +extern "C" { +#endif + +void ffDot( cell_t n ); +void ffDotHex( cell_t n ); +void ffDotS( void ); +cell_t ffSkip( char *AddrIn, cell_t Cnt, char c, char **AddrOut ); +cell_t ffScan( char *AddrIn, cell_t Cnt, char c, char **AddrOut ); + +#ifdef __cplusplus +} +#endif + +#endif /* _pforth_words_h */ diff --git a/src/cmd/pforth/pfcompfp.h b/src/cmd/pforth/pfcompfp.h new file mode 100644 index 0000000..e4da31f --- /dev/null +++ b/src/cmd/pforth/pfcompfp.h @@ -0,0 +1,78 @@ +/* @(#) pfcompfp.h 96/12/18 1.6 */ +/*************************************************************** +** Compile FP routines. +** This file is included from "pf_compile.c" +** +** These routines could be left out of an execute only version. +** +** Author: Darren Gibbs, Phil Burk +** Copyright 1994 3DO, Phil Burk, Larry Polansky, David Rosenboom +** +** The pForth software code is dedicated to the public domain, +** and any third party may reproduce, distribute and modify +** the pForth software code or any derivative works thereof +** without any compensation or license. The pForth software +** code is provided on an "as is" basis without any warranty +** of any kind, including, without limitation, the implied +** warranties of merchantability and fitness for a particular +** purpose and their equivalents under the laws of any jurisdiction. +** +**************************************************************** +** +***************************************************************/ + + +#ifdef PF_SUPPORT_FP +/* Core words */ + CreateDicEntryC( ID_FP_D_TO_F, "D>F", 0 ); + CreateDicEntryC( ID_FP_FSTORE, "F!", 0 ); + CreateDicEntryC( ID_FP_FTIMES, "F*", 0 ); + CreateDicEntryC( ID_FP_FPLUS, "F+", 0 ); + CreateDicEntryC( ID_FP_FMINUS, "F-", 0 ); + CreateDicEntryC( ID_FP_FSLASH, "F/", 0 ); + CreateDicEntryC( ID_FP_F_ZERO_LESS_THAN, "F0<", 0 ); + CreateDicEntryC( ID_FP_F_ZERO_EQUALS, "F0=", 0 ); + CreateDicEntryC( ID_FP_F_LESS_THAN, "F<", 0 ); + CreateDicEntryC( ID_FP_F_TO_D, "F>D", 0 ); + CreateDicEntryC( ID_FP_FFETCH, "F@", 0 ); + CreateDicEntryC( ID_FP_FDEPTH, "FDEPTH", 0 ); + CreateDicEntryC( ID_FP_FDROP, "FDROP", 0 ); + CreateDicEntryC( ID_FP_FDUP, "FDUP", 0 ); + CreateDicEntryC( ID_FP_FLITERAL, "FLITERAL", FLAG_IMMEDIATE ); + CreateDicEntryC( ID_FP_FLITERAL_P, "(FLITERAL)", 0 ); + CreateDicEntryC( ID_FP_FLOAT_PLUS, "FLOAT+", 0 ); + CreateDicEntryC( ID_FP_FLOATS, "FLOATS", 0 ); + CreateDicEntryC( ID_FP_FLOOR, "FLOOR", 0 ); + CreateDicEntryC( ID_FP_FMAX, "FMAX", 0 ); + CreateDicEntryC( ID_FP_FMIN, "FMIN", 0 ); + CreateDicEntryC( ID_FP_FNEGATE, "FNEGATE", 0 ); + CreateDicEntryC( ID_FP_FOVER, "FOVER", 0 ); + CreateDicEntryC( ID_FP_FROT, "FROT", 0 ); + CreateDicEntryC( ID_FP_FROUND, "FROUND", 0 ); + CreateDicEntryC( ID_FP_FSWAP, "FSWAP", 0 ); + +/* Extended words */ + CreateDicEntryC( ID_FP_FSTAR_STAR, "F**", 0 ); + CreateDicEntryC( ID_FP_FABS, "FABS", 0 ); + CreateDicEntryC( ID_FP_FACOS, "FACOS", 0 ); + CreateDicEntryC( ID_FP_FACOSH, "FACOSH", 0 ); + CreateDicEntryC( ID_FP_FALOG, "FALOG", 0 ); + CreateDicEntryC( ID_FP_FASIN, "FASIN", 0 ); + CreateDicEntryC( ID_FP_FASINH, "FASINH", 0 ); + CreateDicEntryC( ID_FP_FATAN, "FATAN", 0 ); + CreateDicEntryC( ID_FP_FATAN2, "FATAN2", 0 ); + CreateDicEntryC( ID_FP_FATANH, "FATANH", 0 ); + CreateDicEntryC( ID_FP_FCOS, "FCOS", 0 ); + CreateDicEntryC( ID_FP_FCOSH, "FCOSH", 0 ); + CreateDicEntryC( ID_FP_FLN, "FLN", 0 ); + CreateDicEntryC( ID_FP_FLNP1, "FLNP1", 0 ); + CreateDicEntryC( ID_FP_FLOG, "FLOG", 0 ); + CreateDicEntryC( ID_FP_FSIN, "FSIN", 0 ); + CreateDicEntryC( ID_FP_FSINCOS, "FSINCOS", 0 ); + CreateDicEntryC( ID_FP_FSINH, "FSINH", 0 ); + CreateDicEntryC( ID_FP_FSQRT, "FSQRT", 0 ); + CreateDicEntryC( ID_FP_FTAN, "FTAN", 0 ); + CreateDicEntryC( ID_FP_FTANH, "FTANH", 0 ); + CreateDicEntryC( ID_FP_FPICK, "FPICK", 0 ); + +#endif diff --git a/src/cmd/pforth/pfcompil.c b/src/cmd/pforth/pfcompil.c new file mode 100644 index 0000000..29a764d --- /dev/null +++ b/src/cmd/pforth/pfcompil.c @@ -0,0 +1,1187 @@ +/* @(#) pfcompil.c 98/01/26 1.5 */ +/*************************************************************** +** Compiler for PForth based on 'C' +** +** These routines could be left out of an execute only version. +** +** Author: Phil Burk +** Copyright 1994 3DO, Phil Burk, Larry Polansky, David Rosenboom +** +** The pForth software code is dedicated to the public domain, +** and any third party may reproduce, distribute and modify +** the pForth software code or any derivative works thereof +** without any compensation or license. The pForth software +** code is provided on an "as is" basis without any warranty +** of any kind, including, without limitation, the implied +** warranties of merchantability and fitness for a particular +** purpose and their equivalents under the laws of any jurisdiction. +** +**************************************************************** +** 941004 PLB Extracted IO calls from pforth_main.c +** 950320 RDG Added underflow checking for FP stack +***************************************************************/ + +#include "pf_all.h" +#include "pfcompil.h" + +#define ABORT_RETURN_CODE (10) +#define UINT32_MASK ((sizeof(ucell_t)-1)) + +/***************************************************************/ +/************** Static Prototypes ******************************/ +/***************************************************************/ + +static void ffStringColon( const ForthStringPtr FName ); +static cell_t CheckRedefinition( const ForthStringPtr FName ); +static void ffUnSmudge( void ); +static cell_t FindAndCompile( const char *theWord ); +static cell_t ffCheckDicRoom( void ); + +#ifndef PF_NO_INIT + static void CreateDeferredC( ExecToken DefaultXT, const char *CName ); +#endif + +cell_t NotCompiled( const char *FunctionName ) +{ + MSG("Function "); + MSG(FunctionName); + MSG(" not compiled in this version of PForth.\n"); + return -1; +} + +#ifndef PF_NO_SHELL +/*************************************************************** +** Create an entry in the Dictionary for the given ExecutionToken. +** FName is name in Forth format. +*/ +void CreateDicEntry( ExecToken XT, const ForthStringPtr FName, ucell_t Flags ) +{ + cfNameLinks *cfnl; + + cfnl = (cfNameLinks *) gCurrentDictionary->dic_HeaderPtr; + +/* Set link to previous header, if any. */ + if( gVarContext ) + { + WRITE_CELL_DIC( &cfnl->cfnl_PreviousName, ABS_TO_NAMEREL( gVarContext ) ); + } + else + { + cfnl->cfnl_PreviousName = 0; + } + +/* Put Execution token in header. */ + WRITE_CELL_DIC( &cfnl->cfnl_ExecToken, XT ); + +/* Advance Header Dictionary Pointer */ + gCurrentDictionary->dic_HeaderPtr += sizeof(cfNameLinks); + +/* Laydown name. */ + gVarContext = gCurrentDictionary->dic_HeaderPtr; + pfCopyMemory( (uint8_t *) gCurrentDictionary->dic_HeaderPtr, FName, (*FName)+1 ); + gCurrentDictionary->dic_HeaderPtr += (*FName)+1; + +/* Set flags. */ + *(char*)gVarContext |= (char) Flags; + +/* Align to quad byte boundaries with zeroes. */ + while( gCurrentDictionary->dic_HeaderPtr & UINT32_MASK ) + { + *(char*)(gCurrentDictionary->dic_HeaderPtr++) = 0; + } +} + +/*************************************************************** +** Convert name then create dictionary entry. +*/ +void CreateDicEntryC( ExecToken XT, const char *CName, ucell_t Flags ) +{ + ForthString FName[40]; + CStringToForth( FName, CName, sizeof(FName) ); + CreateDicEntry( XT, FName, Flags ); +} + +/*************************************************************** +** Convert absolute namefield address to previous absolute name +** field address or NULL. +*/ +const ForthString *NameToPrevious( const ForthString *NFA ) +{ + cell_t RelNamePtr; + const cfNameLinks *cfnl; + +/* DBUG(("\nNameToPrevious: NFA = 0x%x\n", (cell_t) NFA)); */ + cfnl = (const cfNameLinks *) ( ((const char *) NFA) - sizeof(cfNameLinks) ); + + RelNamePtr = READ_CELL_DIC((const cell_t *) (&cfnl->cfnl_PreviousName)); +/* DBUG(("\nNameToPrevious: RelNamePtr = 0x%x\n", (cell_t) RelNamePtr )); */ + if( RelNamePtr ) + { + return ( (ForthString *) NAMEREL_TO_ABS( RelNamePtr ) ); + } + else + { + return NULL; + } +} +/*************************************************************** +** Convert NFA to ExecToken. +*/ +ExecToken NameToToken( const ForthString *NFA ) +{ + const cfNameLinks *cfnl; + +/* Convert absolute namefield address to absolute link field address. */ + cfnl = (const cfNameLinks *) ( ((const char *) NFA) - sizeof(cfNameLinks) ); + + return READ_CELL_DIC((const cell_t *) (&cfnl->cfnl_ExecToken)); +} + +/*************************************************************** +** Find XTs needed by compiler. +*/ +cell_t FindSpecialXTs( void ) +{ + if( ffFindC( "(QUIT)", &gQuitP_XT ) == 0) goto nofind; + if( ffFindC( "NUMBER?", &gNumberQ_XT ) == 0) goto nofind; + if( ffFindC( "ACCEPT", &gAcceptP_XT ) == 0) goto nofind; +DBUG(("gNumberQ_XT = 0x%x\n", (unsigned int)gNumberQ_XT )); + return 0; + +nofind: + ERR("FindSpecialXTs failed!\n"); + return -1; +} + +/*************************************************************** +** Build a dictionary from scratch. +*/ +#ifndef PF_NO_INIT +PForthDictionary pfBuildDictionary( cell_t HeaderSize, cell_t CodeSize ) +{ + pfDictionary_t *dic; + + dic = pfCreateDictionary( HeaderSize, CodeSize ); + if( !dic ) goto nomem; + + pfDebugMessage("pfBuildDictionary: Start adding dictionary entries.\n"); + + gCurrentDictionary = dic; + gNumPrimitives = NUM_PRIMITIVES; + + CreateDicEntryC( ID_EXIT, "EXIT", 0 ); + pfDebugMessage("pfBuildDictionary: added EXIT\n"); + CreateDicEntryC( ID_1MINUS, "1-", 0 ); + pfDebugMessage("pfBuildDictionary: added 1-\n"); + CreateDicEntryC( ID_1PLUS, "1+", 0 ); + CreateDicEntryC( ID_2_R_FETCH, "2R@", 0 ); + CreateDicEntryC( ID_2_R_FROM, "2R>", 0 ); + CreateDicEntryC( ID_2_TO_R, "2>R", 0 ); + CreateDicEntryC( ID_2DUP, "2DUP", 0 ); + CreateDicEntryC( ID_2LITERAL, "2LITERAL", FLAG_IMMEDIATE ); + CreateDicEntryC( ID_2LITERAL_P, "(2LITERAL)", 0 ); + CreateDicEntryC( ID_2MINUS, "2-", 0 ); + CreateDicEntryC( ID_2PLUS, "2+", 0 ); + CreateDicEntryC( ID_2OVER, "2OVER", 0 ); + CreateDicEntryC( ID_2SWAP, "2SWAP", 0 ); + CreateDicEntryC( ID_ACCEPT_P, "(ACCEPT)", 0 ); + CreateDeferredC( ID_ACCEPT_P, "ACCEPT" ); + CreateDicEntryC( ID_ALITERAL, "ALITERAL", FLAG_IMMEDIATE ); + CreateDicEntryC( ID_ALITERAL_P, "(ALITERAL)", 0 ); + CreateDicEntryC( ID_ALLOCATE, "ALLOCATE", 0 ); + pfDebugMessage("pfBuildDictionary: added ALLOCATE\n"); + CreateDicEntryC( ID_ARSHIFT, "ARSHIFT", 0 ); + CreateDicEntryC( ID_AND, "AND", 0 ); + CreateDicEntryC( ID_BAIL, "BAIL", 0 ); + CreateDicEntryC( ID_BRANCH, "BRANCH", 0 ); + CreateDicEntryC( ID_BODY_OFFSET, "BODY_OFFSET", 0 ); + CreateDicEntryC( ID_BYE, "BYE", 0 ); + CreateDicEntryC( ID_CATCH, "CATCH", 0 ); + CreateDicEntryC( ID_CELL, "CELL", 0 ); + CreateDicEntryC( ID_CELLS, "CELLS", 0 ); + CreateDicEntryC( ID_CFETCH, "C@", 0 ); + CreateDicEntryC( ID_CMOVE, "CMOVE", 0 ); + CreateDicEntryC( ID_CMOVE_UP, "CMOVE>", 0 ); + CreateDicEntryC( ID_COLON, ":", 0 ); + CreateDicEntryC( ID_COLON_P, "(:)", 0 ); + CreateDicEntryC( ID_COMPARE, "COMPARE", 0 ); + CreateDicEntryC( ID_COMP_EQUAL, "=", 0 ); + CreateDicEntryC( ID_COMP_NOT_EQUAL, "<>", 0 ); + CreateDicEntryC( ID_COMP_GREATERTHAN, ">", 0 ); + CreateDicEntryC( ID_COMP_U_GREATERTHAN, "U>", 0 ); + pfDebugMessage("pfBuildDictionary: added U>\n"); + CreateDicEntryC( ID_COMP_LESSTHAN, "<", 0 ); + CreateDicEntryC( ID_COMP_U_LESSTHAN, "U<", 0 ); + CreateDicEntryC( ID_COMP_ZERO_EQUAL, "0=", 0 ); + CreateDicEntryC( ID_COMP_ZERO_NOT_EQUAL, "0<>", 0 ); + CreateDicEntryC( ID_COMP_ZERO_GREATERTHAN, "0>", 0 ); + CreateDicEntryC( ID_COMP_ZERO_LESSTHAN, "0<", 0 ); + CreateDicEntryC( ID_CR, "CR", 0 ); + CreateDicEntryC( ID_CREATE, "CREATE", 0 ); + CreateDicEntryC( ID_CREATE_P, "(CREATE)", 0 ); + CreateDicEntryC( ID_D_PLUS, "D+", 0 ); + CreateDicEntryC( ID_D_MINUS, "D-", 0 ); + CreateDicEntryC( ID_D_UMSMOD, "UM/MOD", 0 ); + CreateDicEntryC( ID_D_MUSMOD, "MU/MOD", 0 ); + CreateDicEntryC( ID_D_MTIMES, "M*", 0 ); + pfDebugMessage("pfBuildDictionary: added M*\n"); + CreateDicEntryC( ID_D_UMTIMES, "UM*", 0 ); + CreateDicEntryC( ID_DEFER, "DEFER", 0 ); + CreateDicEntryC( ID_CSTORE, "C!", 0 ); + CreateDicEntryC( ID_DEPTH, "DEPTH", 0 ); + pfDebugMessage("pfBuildDictionary: added DEPTH\n"); + CreateDicEntryC( ID_DIVIDE, "/", 0 ); + CreateDicEntryC( ID_DOT, ".", 0 ); + CreateDicEntryC( ID_DOTS, ".S", 0 ); + pfDebugMessage("pfBuildDictionary: added .S\n"); + CreateDicEntryC( ID_DO_P, "(DO)", 0 ); + CreateDicEntryC( ID_DROP, "DROP", 0 ); + CreateDicEntryC( ID_DUMP, "DUMP", 0 ); + CreateDicEntryC( ID_DUP, "DUP", 0 ); + CreateDicEntryC( ID_EMIT_P, "(EMIT)", 0 ); + pfDebugMessage("pfBuildDictionary: added (EMIT)\n"); + CreateDeferredC( ID_EMIT_P, "EMIT"); + pfDebugMessage("pfBuildDictionary: added EMIT\n"); + CreateDicEntryC( ID_EOL, "EOL", 0 ); + CreateDicEntryC( ID_ERRORQ_P, "(?ERROR)", 0 ); + CreateDicEntryC( ID_ERRORQ_P, "?ERROR", 0 ); + CreateDicEntryC( ID_EXECUTE, "EXECUTE", 0 ); + CreateDicEntryC( ID_FETCH, "@", 0 ); + CreateDicEntryC( ID_FILL, "FILL", 0 ); + CreateDicEntryC( ID_FIND, "FIND", 0 ); + CreateDicEntryC( ID_FILE_CREATE, "CREATE-FILE", 0 ); + CreateDicEntryC( ID_FILE_DELETE, "DELETE-FILE", 0 ); + CreateDicEntryC( ID_FILE_OPEN, "OPEN-FILE", 0 ); + CreateDicEntryC( ID_FILE_CLOSE, "CLOSE-FILE", 0 ); + CreateDicEntryC( ID_FILE_READ, "READ-FILE", 0 ); + CreateDicEntryC( ID_FILE_SIZE, "FILE-SIZE", 0 ); + CreateDicEntryC( ID_FILE_WRITE, "WRITE-FILE", 0 ); + CreateDicEntryC( ID_FILE_POSITION, "FILE-POSITION", 0 ); + CreateDicEntryC( ID_FILE_REPOSITION, "REPOSITION-FILE", 0 ); + CreateDicEntryC( ID_FILE_RO, "R/O", 0 ); + CreateDicEntryC( ID_FILE_RW, "R/W", 0 ); + CreateDicEntryC( ID_FILE_WO, "W/O", 0 ); + CreateDicEntryC( ID_FILE_BIN, "BIN", 0 ); + CreateDicEntryC( ID_FINDNFA, "FINDNFA", 0 ); + CreateDicEntryC( ID_FLUSHEMIT, "FLUSHEMIT", 0 ); + CreateDicEntryC( ID_FREE, "FREE", 0 ); +#include "pfcompfp.h" + CreateDicEntryC( ID_HERE, "HERE", 0 ); + CreateDicEntryC( ID_NUMBERQ_P, "(SNUMBER?)", 0 ); + CreateDicEntryC( ID_I, "I", 0 ); + CreateDicEntryC( ID_INTERPRET, "INTERPRET", 0 ); + CreateDicEntryC( ID_J, "J", 0 ); + CreateDicEntryC( ID_INCLUDE_FILE, "INCLUDE-FILE", 0 ); + CreateDicEntryC( ID_KEY, "KEY", 0 ); + CreateDicEntryC( ID_LEAVE_P, "(LEAVE)", 0 ); + CreateDicEntryC( ID_LITERAL, "LITERAL", FLAG_IMMEDIATE ); + CreateDicEntryC( ID_LITERAL_P, "(LITERAL)", 0 ); + CreateDicEntryC( ID_LOADSYS, "LOADSYS", 0 ); + CreateDicEntryC( ID_LOCAL_COMPILER, "LOCAL-COMPILER", 0 ); + CreateDicEntryC( ID_LOCAL_ENTRY, "(LOCAL.ENTRY)", 0 ); + CreateDicEntryC( ID_LOCAL_EXIT, "(LOCAL.EXIT)", 0 ); + CreateDicEntryC( ID_LOCAL_FETCH, "(LOCAL@)", 0 ); + CreateDicEntryC( ID_LOCAL_FETCH_1, "(1_LOCAL@)", 0 ); + CreateDicEntryC( ID_LOCAL_FETCH_2, "(2_LOCAL@)", 0 ); + CreateDicEntryC( ID_LOCAL_FETCH_3, "(3_LOCAL@)", 0 ); + CreateDicEntryC( ID_LOCAL_FETCH_4, "(4_LOCAL@)", 0 ); + CreateDicEntryC( ID_LOCAL_FETCH_5, "(5_LOCAL@)", 0 ); + CreateDicEntryC( ID_LOCAL_FETCH_6, "(6_LOCAL@)", 0 ); + CreateDicEntryC( ID_LOCAL_FETCH_7, "(7_LOCAL@)", 0 ); + CreateDicEntryC( ID_LOCAL_FETCH_8, "(8_LOCAL@)", 0 ); + CreateDicEntryC( ID_LOCAL_STORE, "(LOCAL!)", 0 ); + CreateDicEntryC( ID_LOCAL_STORE_1, "(1_LOCAL!)", 0 ); + CreateDicEntryC( ID_LOCAL_STORE_2, "(2_LOCAL!)", 0 ); + CreateDicEntryC( ID_LOCAL_STORE_3, "(3_LOCAL!)", 0 ); + CreateDicEntryC( ID_LOCAL_STORE_4, "(4_LOCAL!)", 0 ); + CreateDicEntryC( ID_LOCAL_STORE_5, "(5_LOCAL!)", 0 ); + CreateDicEntryC( ID_LOCAL_STORE_6, "(6_LOCAL!)", 0 ); + CreateDicEntryC( ID_LOCAL_STORE_7, "(7_LOCAL!)", 0 ); + CreateDicEntryC( ID_LOCAL_STORE_8, "(8_LOCAL!)", 0 ); + CreateDicEntryC( ID_LOCAL_PLUSSTORE, "(LOCAL+!)", 0 ); + CreateDicEntryC( ID_LOOP_P, "(LOOP)", 0 ); + CreateDicEntryC( ID_LSHIFT, "LSHIFT", 0 ); + CreateDicEntryC( ID_MAX, "MAX", 0 ); + CreateDicEntryC( ID_MIN, "MIN", 0 ); + CreateDicEntryC( ID_MINUS, "-", 0 ); + CreateDicEntryC( ID_NAME_TO_TOKEN, "NAME>", 0 ); + CreateDicEntryC( ID_NAME_TO_PREVIOUS, "PREVNAME", 0 ); + CreateDicEntryC( ID_NOOP, "NOOP", 0 ); + CreateDeferredC( ID_NUMBERQ_P, "NUMBER?" ); + CreateDicEntryC( ID_OR, "OR", 0 ); + CreateDicEntryC( ID_OVER, "OVER", 0 ); + pfDebugMessage("pfBuildDictionary: added OVER\n"); + CreateDicEntryC( ID_PICK, "PICK", 0 ); + CreateDicEntryC( ID_PLUS, "+", 0 ); + CreateDicEntryC( ID_PLUSLOOP_P, "(+LOOP)", 0 ); + CreateDicEntryC( ID_PLUS_STORE, "+!", 0 ); + CreateDicEntryC( ID_QUIT_P, "(QUIT)", 0 ); + CreateDeferredC( ID_QUIT_P, "QUIT" ); + CreateDicEntryC( ID_QDO_P, "(?DO)", 0 ); + CreateDicEntryC( ID_QDUP, "?DUP", 0 ); + CreateDicEntryC( ID_QTERMINAL, "?TERMINAL", 0 ); + CreateDicEntryC( ID_QTERMINAL, "KEY?", 0 ); + CreateDicEntryC( ID_REFILL, "REFILL", 0 ); + CreateDicEntryC( ID_RESIZE, "RESIZE", 0 ); + CreateDicEntryC( ID_ROLL, "ROLL", 0 ); + CreateDicEntryC( ID_ROT, "ROT", 0 ); + CreateDicEntryC( ID_RSHIFT, "RSHIFT", 0 ); + CreateDicEntryC( ID_R_DROP, "RDROP", 0 ); + CreateDicEntryC( ID_R_FETCH, "R@", 0 ); + CreateDicEntryC( ID_R_FROM, "R>", 0 ); + CreateDicEntryC( ID_RP_FETCH, "RP@", 0 ); + CreateDicEntryC( ID_RP_STORE, "RP!", 0 ); + CreateDicEntryC( ID_SEMICOLON, ";", FLAG_IMMEDIATE ); + CreateDicEntryC( ID_SP_FETCH, "SP@", 0 ); + CreateDicEntryC( ID_SP_STORE, "SP!", 0 ); + CreateDicEntryC( ID_STORE, "!", 0 ); + CreateDicEntryC( ID_SAVE_FORTH_P, "(SAVE-FORTH)", 0 ); + CreateDicEntryC( ID_SCAN, "SCAN", 0 ); + CreateDicEntryC( ID_SKIP, "SKIP", 0 ); + CreateDicEntryC( ID_SOURCE, "SOURCE", 0 ); + CreateDicEntryC( ID_SOURCE_SET, "SET-SOURCE", 0 ); + CreateDicEntryC( ID_SOURCE_ID, "SOURCE-ID", 0 ); + CreateDicEntryC( ID_SOURCE_ID_PUSH, "PUSH-SOURCE-ID", 0 ); + CreateDicEntryC( ID_SOURCE_ID_POP, "POP-SOURCE-ID", 0 ); + CreateDicEntryC( ID_SWAP, "SWAP", 0 ); + CreateDicEntryC( ID_TEST1, "TEST1", 0 ); + CreateDicEntryC( ID_TEST2, "TEST2", 0 ); + CreateDicEntryC( ID_TICK, "'", 0 ); + CreateDicEntryC( ID_TIMES, "*", 0 ); + CreateDicEntryC( ID_THROW, "THROW", 0 ); + CreateDicEntryC( ID_TO_R, ">R", 0 ); + CreateDicEntryC( ID_TYPE, "TYPE", 0 ); + CreateDicEntryC( ID_VAR_BASE, "BASE", 0 ); + CreateDicEntryC( ID_VAR_CODE_BASE, "CODE-BASE", 0 ); + CreateDicEntryC( ID_VAR_CODE_LIMIT, "CODE-LIMIT", 0 ); + CreateDicEntryC( ID_VAR_CONTEXT, "CONTEXT", 0 ); + CreateDicEntryC( ID_VAR_DP, "DP", 0 ); + CreateDicEntryC( ID_VAR_ECHO, "ECHO", 0 ); + CreateDicEntryC( ID_VAR_HEADERS_PTR, "HEADERS-PTR", 0 ); + CreateDicEntryC( ID_VAR_HEADERS_BASE, "HEADERS-BASE", 0 ); + CreateDicEntryC( ID_VAR_HEADERS_LIMIT, "HEADERS-LIMIT", 0 ); + CreateDicEntryC( ID_VAR_NUM_TIB, "#TIB", 0 ); + CreateDicEntryC( ID_VAR_RETURN_CODE, "RETURN-CODE", 0 ); + CreateDicEntryC( ID_VAR_TRACE_FLAGS, "TRACE-FLAGS", 0 ); + CreateDicEntryC( ID_VAR_TRACE_LEVEL, "TRACE-LEVEL", 0 ); + CreateDicEntryC( ID_VAR_TRACE_STACK, "TRACE-STACK", 0 ); + CreateDicEntryC( ID_VAR_OUT, "OUT", 0 ); + CreateDicEntryC( ID_VAR_STATE, "STATE", 0 ); + CreateDicEntryC( ID_VAR_TO_IN, ">IN", 0 ); + CreateDicEntryC( ID_WORD, "WORD", 0 ); + CreateDicEntryC( ID_WORD_FETCH, "W@", 0 ); + CreateDicEntryC( ID_WORD_STORE, "W!", 0 ); + CreateDicEntryC( ID_XOR, "XOR", 0 ); + CreateDicEntryC( ID_ZERO_BRANCH, "0BRANCH", 0 ); + + pfDebugMessage("pfBuildDictionary: FindSpecialXTs\n"); + if( FindSpecialXTs() < 0 ) goto error; + + if( CompileCustomFunctions() < 0 ) goto error; /* Call custom 'C' call builder. */ + +#ifdef PF_DEBUG + DumpMemory( dic->dic_HeaderBase, 256 ); + DumpMemory( dic->dic_CodeBase, 256 ); +#endif + + pfDebugMessage("pfBuildDictionary: Finished adding dictionary entries.\n"); + return (PForthDictionary) dic; + +error: + pfDebugMessage("pfBuildDictionary: Error adding dictionary entries.\n"); + pfDeleteDictionary( dic ); + return NULL; + +nomem: + return NULL; +} +#endif /* !PF_NO_INIT */ + +/* +** ( xt -- nfa 1 , x 0 , find NFA in dictionary from XT ) +** 1 for IMMEDIATE values +*/ +cell_t ffTokenToName( ExecToken XT, const ForthString **NFAPtr ) +{ + const ForthString *NameField; + cell_t Searching = TRUE; + cell_t Result = 0; + ExecToken TempXT; + + NameField = (ForthString *) gVarContext; +DBUGX(("\ffCodeToName: gVarContext = 0x%x\n", gVarContext)); + + do + { + TempXT = NameToToken( NameField ); + + if( TempXT == XT ) + { +DBUGX(("ffCodeToName: NFA = 0x%x\n", NameField)); + *NFAPtr = NameField ; + Result = 1; + Searching = FALSE; + } + else + { + NameField = NameToPrevious( NameField ); + if( NameField == NULL ) + { + *NFAPtr = 0; + Searching = FALSE; + } + } + } while ( Searching); + + return Result; +} + +/* +** ( $name -- $addr 0 | nfa -1 | nfa 1 , find NFA in dictionary ) +** 1 for IMMEDIATE values +*/ +cell_t ffFindNFA( const ForthString *WordName, const ForthString **NFAPtr ) +{ + const ForthString *WordChar; + uint8_t WordLen; + const char *NameField, *NameChar; + int8_t NameLen; + cell_t Searching = TRUE; + cell_t Result = 0; + + WordLen = (uint8_t) ((ucell_t)*WordName & 0x1F); + WordChar = WordName+1; + + NameField = (ForthString *) gVarContext; +DBUG(("\nffFindNFA: WordLen = %d, WordName = %*s\n", WordLen, WordLen, WordChar )); +DBUG(("\nffFindNFA: gVarContext = 0x%x\n", gVarContext)); + do + { + NameLen = (uint8_t) ((ucell_t)(*NameField) & MASK_NAME_SIZE); + NameChar = NameField+1; +/* DBUG((" %c\n", (*NameField & FLAG_SMUDGE) ? 'S' : 'V' )); */ + if( ((*NameField & FLAG_SMUDGE) == 0) && + (NameLen == WordLen) && + ffCompareTextCaseN( NameChar, WordChar, WordLen ) ) /* FIXME - slow */ + { +DBUG(("ffFindNFA: found it at NFA = 0x%x\n", NameField)); + *NFAPtr = NameField ; + Result = ((*NameField) & FLAG_IMMEDIATE) ? 1 : -1; + Searching = FALSE; + } + else + { + NameField = NameToPrevious( NameField ); + if( NameField == NULL ) + { + *NFAPtr = WordName; + Searching = FALSE; + } + } + } while ( Searching); +DBUG(("ffFindNFA: returns 0x%x\n", Result)); + return Result; +} + + +/*************************************************************** +** ( $name -- $name 0 | xt -1 | xt 1 ) +** 1 for IMMEDIATE values +*/ +cell_t ffFind( const ForthString *WordName, ExecToken *pXT ) +{ + const ForthString *NFA; + cell_t Result; + + Result = ffFindNFA( WordName, &NFA ); +DBUG(("ffFind: %8s at 0x%x\n", WordName+1, NFA)); /* WARNING, not NUL terminated. %Q */ + if( Result ) + { + *pXT = NameToToken( NFA ); + } + else + { + *pXT = (ExecToken) WordName; + } + + return Result; +} + +/**************************************************************** +** Find name when passed 'C' string. +*/ +cell_t ffFindC( const char *WordName, ExecToken *pXT ) +{ +DBUG(("ffFindC: %s\n", WordName )); + CStringToForth( gScratch, WordName, sizeof(gScratch) ); + return ffFind( gScratch, pXT ); +} + + +/***********************************************************/ +/********* Compiling New Words *****************************/ +/***********************************************************/ +#define DIC_SAFETY_MARGIN (400) + +/************************************************************* +** Check for dictionary overflow. +*/ +static cell_t ffCheckDicRoom( void ) +{ + cell_t RoomLeft; + RoomLeft = (char *)gCurrentDictionary->dic_HeaderLimit - + (char *)gCurrentDictionary->dic_HeaderPtr; + if( RoomLeft < DIC_SAFETY_MARGIN ) + { + pfReportError("ffCheckDicRoom", PF_ERR_HEADER_ROOM); + return PF_ERR_HEADER_ROOM; + } + + RoomLeft = (char *)gCurrentDictionary->dic_CodeLimit - + (char *)gCurrentDictionary->dic_CodePtr.Byte; + if( RoomLeft < DIC_SAFETY_MARGIN ) + { + pfReportError("ffCheckDicRoom", PF_ERR_CODE_ROOM); + return PF_ERR_CODE_ROOM; + } + return 0; +} + +/************************************************************* +** Create a dictionary entry given a string name. +*/ +void ffCreateSecondaryHeader( const ForthStringPtr FName) +{ + pfDebugMessage("ffCreateSecondaryHeader()\n"); +/* Check for dictionary overflow. */ + if( ffCheckDicRoom() ) return; + + pfDebugMessage("ffCreateSecondaryHeader: CheckRedefinition()\n"); + CheckRedefinition( FName ); +/* Align CODE_HERE */ + CODE_HERE = (cell_t *)( (((ucell_t)CODE_HERE) + UINT32_MASK) & ~UINT32_MASK); + CreateDicEntry( (ExecToken) ABS_TO_CODEREL(CODE_HERE), FName, FLAG_SMUDGE ); +} + +/************************************************************* +** Begin compiling a secondary word. +*/ +static void ffStringColon( const ForthStringPtr FName) +{ + ffCreateSecondaryHeader( FName ); + gVarState = 1; +} + +/************************************************************* +** Read the next ExecToken from the Source and create a word. +*/ +void ffColon( void ) +{ + char *FName; + + gDepthAtColon = DATA_STACK_DEPTH; + + FName = ffWord( BLANK ); + if( *FName > 0 ) + { + ffStringColon( FName ); + } +} + +/************************************************************* +** Check to see if name is already in dictionary. +*/ +static cell_t CheckRedefinition( const ForthStringPtr FName ) +{ + cell_t flag; + ExecToken XT; + + flag = ffFind( FName, &XT); + if ( flag && !gVarQuiet) + { + ioType( FName+1, (cell_t) *FName ); + MSG( " redefined.\n" ); /* FIXME - allow user to run off this warning. */ + } + return flag; +} + +void ffStringCreate( char *FName) +{ + ffCreateSecondaryHeader( FName ); + + CODE_COMMA( ID_CREATE_P ); + CODE_COMMA( ID_EXIT ); + ffFinishSecondary(); + +} + +/* Read the next ExecToken from the Source and create a word. */ +void ffCreate( void ) +{ + char *FName; + + FName = ffWord( BLANK ); + if( *FName > 0 ) + { + ffStringCreate( FName ); + } +} + +void ffStringDefer( const ForthStringPtr FName, ExecToken DefaultXT ) +{ + pfDebugMessage("ffStringDefer()\n"); + ffCreateSecondaryHeader( FName ); + + CODE_COMMA( ID_DEFER_P ); + CODE_COMMA( DefaultXT ); + + ffFinishSecondary(); + +} +#ifndef PF_NO_INIT +/* Convert name then create deferred dictionary entry. */ +static void CreateDeferredC( ExecToken DefaultXT, const char *CName ) +{ + char FName[40]; + CStringToForth( FName, CName, sizeof(FName) ); + ffStringDefer( FName, DefaultXT ); +} +#endif + +/* Read the next token from the Source and create a word. */ +void ffDefer( void ) +{ + char *FName; + + FName = ffWord( BLANK ); + if( *FName > 0 ) + { + ffStringDefer( FName, ID_QUIT_P ); + } +} + +/* Unsmudge the word to make it visible. */ +void ffUnSmudge( void ) +{ + *(char*)gVarContext &= ~FLAG_SMUDGE; +} + +/* Implement ; */ +ThrowCode ffSemiColon( void ) +{ + ThrowCode exception = 0; + gVarState = 0; + + if( (gDepthAtColon != DATA_STACK_DEPTH) && + (gDepthAtColon != DEPTH_AT_COLON_INVALID) ) /* Ignore if no ':' */ + { + exception = THROW_SEMICOLON; + } + else + { + ffFinishSecondary(); + } + gDepthAtColon = DEPTH_AT_COLON_INVALID; + return exception; +} + +/* Finish the definition of a Forth word. */ +void ffFinishSecondary( void ) +{ + CODE_COMMA( ID_EXIT ); + ffUnSmudge(); +} + +/**************************************************************/ +/* Used to pull a number from the dictionary to the stack */ +void ff2Literal( cell_t dHi, cell_t dLo ) +{ + CODE_COMMA( ID_2LITERAL_P ); + CODE_COMMA( dHi ); + CODE_COMMA( dLo ); +} +void ffALiteral( cell_t Num ) +{ + CODE_COMMA( ID_ALITERAL_P ); + CODE_COMMA( Num ); +} +void ffLiteral( cell_t Num ) +{ + CODE_COMMA( ID_LITERAL_P ); + CODE_COMMA( Num ); +} + +#ifdef PF_SUPPORT_FP +void ffFPLiteral( PF_FLOAT fnum ) +{ + /* Hack for Metrowerks complier which won't compile the + * original expression. + */ + PF_FLOAT *temp; + cell_t *dicPtr; + +/* Make sure that literal float data is float aligned. */ + dicPtr = CODE_HERE + 1; + while( (((ucell_t) dicPtr++) & (sizeof(PF_FLOAT) - 1)) != 0) + { + DBUG((" comma NOOP to align FPLiteral\n")); + CODE_COMMA( ID_NOOP ); + } + CODE_COMMA( ID_FP_FLITERAL_P ); + + temp = (PF_FLOAT *)CODE_HERE; + WRITE_FLOAT_DIC(temp,fnum); /* Write to dictionary. */ + temp++; + CODE_HERE = (cell_t *) temp; +} +#endif /* PF_SUPPORT_FP */ + +/**************************************************************/ +ThrowCode FindAndCompile( const char *theWord ) +{ + cell_t Flag; + ExecToken XT; + cell_t Num; + ThrowCode exception = 0; + + Flag = ffFind( theWord, &XT); +DBUG(("FindAndCompile: theWord = %8s, XT = 0x%x, Flag = %d\n", theWord, XT, Flag )); + +/* Is it a normal word ? */ + if( Flag == -1 ) + { + if( gVarState ) /* compiling? */ + { + CODE_COMMA( XT ); + } + else + { + exception = pfCatch( XT ); + } + } + else if ( Flag == 1 ) /* or is it IMMEDIATE ? */ + { +DBUG(("FindAndCompile: IMMEDIATE, theWord = 0x%x\n", theWord )); + exception = pfCatch( XT ); + } + else /* try to interpret it as a number. */ + { +/* Call deferred NUMBER? */ + cell_t NumResult; + +DBUG(("FindAndCompile: not found, try number?\n" )); + PUSH_DATA_STACK( theWord ); /* Push text of number */ + exception = pfCatch( gNumberQ_XT ); + if( exception ) goto error; + +DBUG(("FindAndCompile: after number?\n" )); + NumResult = POP_DATA_STACK; /* Success? */ + switch( NumResult ) + { + case NUM_TYPE_SINGLE: + if( gVarState ) /* compiling? */ + { + Num = POP_DATA_STACK; + ffLiteral( Num ); + } + break; + + case NUM_TYPE_DOUBLE: + if( gVarState ) /* compiling? */ + { + Num = POP_DATA_STACK; /* get hi portion */ + ff2Literal( Num, POP_DATA_STACK ); + } + break; + +#ifdef PF_SUPPORT_FP + case NUM_TYPE_FLOAT: + if( gVarState ) /* compiling? */ + { + ffFPLiteral( *gCurrentTask->td_FloatStackPtr++ ); + } + break; +#endif + + case NUM_TYPE_BAD: + default: + ioType( theWord+1, *theWord ); + MSG( " ? - unrecognized word!\n" ); + exception = THROW_UNDEFINED_WORD; + break; + + } + } +error: + return exception; +} + +/************************************************************** +** Forth outer interpreter. Parses words from Source. +** Executes them or compiles them based on STATE. +*/ +ThrowCode ffInterpret( void ) +{ + cell_t flag; + char *theWord; + ThrowCode exception = 0; + +/* Is there any text left in Source ? */ + while( gCurrentTask->td_IN < (gCurrentTask->td_SourceNum) ) + { + + pfDebugMessage("ffInterpret: calling ffWord(()\n"); + theWord = ffWord( BLANK ); + DBUG(("ffInterpret: theWord = 0x%x, Len = %d\n", theWord, *theWord )); + + if( *theWord > 0 ) + { + flag = 0; + if( gLocalCompiler_XT ) + { + PUSH_DATA_STACK( theWord ); /* Push word. */ + exception = pfCatch( gLocalCompiler_XT ); + if( exception ) goto error; + flag = POP_DATA_STACK; /* Compiled local? */ + } + if( flag == 0 ) + { + exception = FindAndCompile( theWord ); + if( exception ) goto error; + } + } + + DBUG(("ffInterpret: IN=%d, SourceNum=%d\n", gCurrentTask->td_IN, + gCurrentTask->td_SourceNum ) ); + } +error: + return exception; +} + +/**************************************************************/ +ThrowCode ffOK( void ) +{ + cell_t exception = 0; +/* Check for stack underflow. %Q what about overflows? */ + if( (gCurrentTask->td_StackBase - gCurrentTask->td_StackPtr) < 0 ) + { + exception = THROW_STACK_UNDERFLOW; + } +#ifdef PF_SUPPORT_FP /* Check floating point stack too! */ + else if((gCurrentTask->td_FloatStackBase - gCurrentTask->td_FloatStackPtr) < 0) + { + exception = THROW_FLOAT_STACK_UNDERFLOW; + } +#endif + else if( gCurrentTask->td_InputStream == PF_STDIN) + { + if( !gVarState ) /* executing? */ + { + if( !gVarQuiet ) + { + MSG( " ok\n" ); + if(gVarTraceStack) ffDotS(); + } + else + { + EMIT_CR; + } + } + } + return exception; +} + +/*************************************************************** +** Cleanup Include stack by popping and closing files. +***************************************************************/ +void pfHandleIncludeError( void ) +{ + FileStream *cur; + + while( (cur = ffPopInputStream()) != PF_STDIN) + { + DBUG(("ffCleanIncludeStack: closing 0x%x\n", cur )); + sdCloseFile(cur); + } +} + +/*************************************************************** +** Interpret input in a loop. +***************************************************************/ +ThrowCode ffOuterInterpreterLoop( void ) +{ + cell_t exception = 0; + do + { + exception = ffRefill(); + if(exception <= 0) break; + + exception = ffInterpret(); + if( exception == 0 ) + { + exception = ffOK(); + } + + } while( exception == 0 ); + return exception; +} + +/*************************************************************** +** Include then close a file +***************************************************************/ + +ThrowCode ffIncludeFile( FileStream *InputFile ) +{ + ThrowCode exception; + +/* Push file stream. */ + exception = ffPushInputStream( InputFile ); + if( exception < 0 ) return exception; + +/* Run outer interpreter for stream. */ + exception = ffOuterInterpreterLoop(); + if( exception ) + { + int i; +/* Report line number and nesting level. */ + MSG("INCLUDE error on line #"); ffDot(gCurrentTask->td_LineNumber); + MSG(", level = "); ffDot(gIncludeIndex ); + EMIT_CR + +/* Dump line of error and show offset in line for >IN */ + for( i=0; itd_SourceNum; i++ ) + { + char c = gCurrentTask->td_SourcePtr[i]; + if( c == '\t' ) c = ' '; + EMIT(c); + } + EMIT_CR; + for( i=0; i<(gCurrentTask->td_IN - 1); i++ ) EMIT('^'); + EMIT_CR; + } + +/* Pop file stream. */ + ffPopInputStream(); + +/* ANSI spec specifies that this should also close the file. */ + sdCloseFile(InputFile); + + return exception; +} + +#endif /* !PF_NO_SHELL */ + +/*************************************************************** +** Save current input stream on stack, use this new one. +***************************************************************/ +Err ffPushInputStream( FileStream *InputFile ) +{ + cell_t Result = 0; + IncludeFrame *inf; + +/* Push current input state onto special include stack. */ + if( gIncludeIndex < MAX_INCLUDE_DEPTH ) + { + inf = &gIncludeStack[gIncludeIndex++]; + inf->inf_FileID = gCurrentTask->td_InputStream; + inf->inf_IN = gCurrentTask->td_IN; + inf->inf_LineNumber = gCurrentTask->td_LineNumber; + inf->inf_SourceNum = gCurrentTask->td_SourceNum; +/* Copy TIB plus any NUL terminator into saved area. */ + if( (inf->inf_SourceNum > 0) && (inf->inf_SourceNum < (TIB_SIZE-1)) ) + { + pfCopyMemory( inf->inf_SaveTIB, gCurrentTask->td_TIB, inf->inf_SourceNum+1 ); + } + +/* Set new current input. */ + DBUG(( "ffPushInputStream: InputFile = 0x%x\n", InputFile )); + gCurrentTask->td_InputStream = InputFile; + gCurrentTask->td_LineNumber = 0; + } + else + { + ERR("ffPushInputStream: max depth exceeded.\n"); + return -1; + } + + + return Result; +} + +/*************************************************************** +** Go back to reading previous stream. +** Just return gCurrentTask->td_InputStream upon underflow. +***************************************************************/ +FileStream *ffPopInputStream( void ) +{ + IncludeFrame *inf; + FileStream *Result; + +DBUG(("ffPopInputStream: gIncludeIndex = %d\n", gIncludeIndex)); + Result = gCurrentTask->td_InputStream; + +/* Restore input state. */ + if( gIncludeIndex > 0 ) + { + inf = &gIncludeStack[--gIncludeIndex]; + gCurrentTask->td_InputStream = inf->inf_FileID; + DBUG(("ffPopInputStream: stream = 0x%x\n", gCurrentTask->td_InputStream )); + gCurrentTask->td_IN = inf->inf_IN; + gCurrentTask->td_LineNumber = inf->inf_LineNumber; + gCurrentTask->td_SourceNum = inf->inf_SourceNum; +/* Copy TIB plus any NUL terminator into saved area. */ + if( (inf->inf_SourceNum > 0) && (inf->inf_SourceNum < (TIB_SIZE-1)) ) + { + pfCopyMemory( gCurrentTask->td_TIB, inf->inf_SaveTIB, inf->inf_SourceNum+1 ); + } + + } +DBUG(("ffPopInputStream: return = 0x%x\n", Result )); + + return Result; +} + +/*************************************************************** +** Convert file pointer to value consistent with SOURCE-ID. +***************************************************************/ +cell_t ffConvertStreamToSourceID( FileStream *Stream ) +{ + cell_t Result; + if(Stream == PF_STDIN) + { + Result = 0; + } + else if(Stream == NULL) + { + Result = -1; + } + else + { + Result = (cell_t) Stream; + } + return Result; +} + +/*************************************************************** +** Convert file pointer to value consistent with SOURCE-ID. +***************************************************************/ +FileStream * ffConvertSourceIDToStream( cell_t id ) +{ + FileStream *stream; + + if( id == 0 ) + { + stream = PF_STDIN; + } + else if( id == -1 ) + { + stream = NULL; + } + else + { + stream = (FileStream *) id; + } + return stream; +} + +/************************************************************** +** Receive line from input stream. +** Return length, or -1 for EOF. +*/ +#define BACKSPACE (8) +static cell_t readLineFromStream( char *buffer, cell_t maxChars, FileStream *stream ) +{ + int c; + int len; + char *p; + static int lastChar = 0; + int done = 0; + +DBUGX(("readLineFromStream(0x%x, 0x%x, 0x%x)\n", buffer, len, stream )); + p = buffer; + len = 0; + while( (len < maxChars) && !done ) + { + c = sdInputChar(stream); + switch(c) + { + case EOF: + DBUG(("EOF\n")); + done = 1; + if( len <= 0 ) len = -1; + break; + + case '\n': + DBUGX(("EOL=\\n\n")); + if( lastChar != '\r' ) done = 1; + break; + + case '\r': + DBUGX(("EOL=\\r\n")); + done = 1; + break; + + default: + *p++ = (char) c; + len++; + break; + } + lastChar = c; + } + +/* NUL terminate line to simplify printing when debugging. */ + if( (len >= 0) && (len < maxChars) ) p[len] = '\0'; + + return len; +} + +/************************************************************** +** ( -- , fill Source from current stream ) +** Return 1 if successful, 0 for EOF, or a negative error. +*/ +cell_t ffRefill( void ) +{ + cell_t Num; + cell_t Result = 1; + +/* reset >IN for parser */ + gCurrentTask->td_IN = 0; + +/* get line from current stream */ + if( gCurrentTask->td_InputStream == PF_STDIN ) + { + /* ACCEPT is deferred so we call it through the dictionary. */ + PUSH_DATA_STACK( gCurrentTask->td_SourcePtr ); + PUSH_DATA_STACK( TIB_SIZE ); + pfCatch( gAcceptP_XT ); + Num = POP_DATA_STACK; + if( Num < 0 ) + { + Result = Num; + goto error; + } + } + else + { + Num = readLineFromStream( gCurrentTask->td_SourcePtr, TIB_SIZE, + gCurrentTask->td_InputStream ); + if( Num == EOF ) + { + Result = 0; + Num = 0; + } + } + + gCurrentTask->td_SourceNum = Num; + gCurrentTask->td_LineNumber++; /* Bump for include. */ + +/* echo input if requested */ + if( gVarEcho && ( Num > 0)) + { + ioType( gCurrentTask->td_SourcePtr, gCurrentTask->td_SourceNum ); + EMIT_CR; + } + +error: + return Result; +} diff --git a/src/cmd/pforth/pfcompil.h b/src/cmd/pforth/pfcompil.h new file mode 100644 index 0000000..99777cb --- /dev/null +++ b/src/cmd/pforth/pfcompil.h @@ -0,0 +1,73 @@ +/* @(#) pfcompil.h 96/12/18 1.11 */ + +#ifndef _pforth_compile_h +#define _pforth_compile_h + +/*************************************************************** +** Include file for PForth Compiler +** +** Author: Phil Burk +** Copyright 1994 3DO, Phil Burk, Larry Polansky, David Rosenboom +** +** The pForth software code is dedicated to the public domain, +** and any third party may reproduce, distribute and modify +** the pForth software code or any derivative works thereof +** without any compensation or license. The pForth software +** code is provided on an "as is" basis without any warranty +** of any kind, including, without limitation, the implied +** warranties of merchantability and fitness for a particular +** purpose and their equivalents under the laws of any jurisdiction. +** +***************************************************************/ + +#ifdef __cplusplus +extern "C" { +#endif + +Err ffPushInputStream( FileStream *InputFile ); +ExecToken NameToToken( const ForthString *NFA ); +FileStream * ffConvertSourceIDToStream( cell_t id ); +FileStream *ffPopInputStream( void ); +cell_t ffConvertStreamToSourceID( FileStream *Stream ); +cell_t ffFind( const ForthString *WordName, ExecToken *pXT ); +cell_t ffFindC( const char *WordName, ExecToken *pXT ); +cell_t ffFindNFA( const ForthString *WordName, const ForthString **NFAPtr ); +cell_t ffNumberQ( const char *FWord, cell_t *Num ); +cell_t ffRefill( void ); +cell_t ffTokenToName( ExecToken XT, const ForthString **NFAPtr ); +cell_t *NameToCode( ForthString *NFA ); +PForthDictionary pfBuildDictionary( cell_t HeaderSize, cell_t CodeSize ); +char *ffWord( char c ); +const ForthString *NameToPrevious( const ForthString *NFA ); +cell_t FindSpecialCFAs( void ); +cell_t FindSpecialXTs( void ); +cell_t NotCompiled( const char *FunctionName ); +void CreateDicEntry( ExecToken XT, const ForthStringPtr FName, ucell_t Flags ); +void CreateDicEntryC( ExecToken XT, const char *CName, ucell_t Flags ); +void ff2Literal( cell_t dHi, cell_t dLo ); +void ffALiteral( cell_t Num ); +void ffColon( void ); +void ffCreate( void ); +void ffCreateSecondaryHeader( const ForthStringPtr FName); +void ffDefer( void ); +void ffFinishSecondary( void ); +void ffLiteral( cell_t Num ); +void ffStringCreate( ForthStringPtr FName); +void ffStringDefer( const ForthStringPtr FName, ExecToken DefaultXT ); +void pfHandleIncludeError( void ); + +ThrowCode ffSemiColon( void ); +ThrowCode ffOK( void ); +ThrowCode ffInterpret( void ); +ThrowCode ffOuterInterpreterLoop( void ); +ThrowCode ffIncludeFile( FileStream *InputFile ); + +#ifdef PF_SUPPORT_FP +void ffFPLiteral( PF_FLOAT fnum ); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _pforth_compile_h */ diff --git a/src/cmd/pforth/pfcustom.c b/src/cmd/pforth/pfcustom.c new file mode 100644 index 0000000..e954b69 --- /dev/null +++ b/src/cmd/pforth/pfcustom.c @@ -0,0 +1,121 @@ +/* @(#) pfcustom.c 98/01/26 1.3 */ + +#ifndef PF_USER_CUSTOM + +/*************************************************************** +** Call Custom Functions for pForth +** +** Create a file similar to this and compile it into pForth +** by setting -DPF_USER_CUSTOM="mycustom.c" +** +** Using this, you could, for example, call X11 from Forth. +** See "pf_cglue.c" for more information. +** +** Author: Phil Burk +** Copyright 1994 3DO, Phil Burk, Larry Polansky, David Rosenboom +** +** The pForth software code is dedicated to the public domain, +** and any third party may reproduce, distribute and modify +** the pForth software code or any derivative works thereof +** without any compensation or license. The pForth software +** code is provided on an "as is" basis without any warranty +** of any kind, including, without limitation, the implied +** warranties of merchantability and fitness for a particular +** purpose and their equivalents under the laws of any jurisdiction. +** +***************************************************************/ + + +#include "pf_all.h" + +static cell_t CTest0( cell_t Val ); +static void CTest1( cell_t Val1, cell_t Val2 ); + +/**************************************************************** +** Step 1: Put your own special glue routines here +** or link them in from another file or library. +****************************************************************/ +static cell_t CTest0( cell_t Val ) +{ + MSG_NUM_D("CTest0: Val = ", Val); + return Val+1; +} + +static void CTest1( cell_t Val1, cell_t Val2 ) +{ + + MSG("CTest1: Val1 = "); ffDot(Val1); + MSG_NUM_D(", Val2 = ", Val2); +} + +/**************************************************************** +** Step 2: Create CustomFunctionTable. +** Do not change the name of CustomFunctionTable! +** It is used by the pForth kernel. +****************************************************************/ + +#ifdef PF_NO_GLOBAL_INIT +/****************** +** If your loader does not support global initialization, then you +** must define PF_NO_GLOBAL_INIT and provide a function to fill +** the table. Some embedded system loaders require this! +** Do not change the name of LoadCustomFunctionTable()! +** It is called by the pForth kernel. +*/ +#define NUM_CUSTOM_FUNCTIONS (2) +CFunc0 CustomFunctionTable[NUM_CUSTOM_FUNCTIONS]; + +Err LoadCustomFunctionTable( void ) +{ + CustomFunctionTable[0] = CTest0; + CustomFunctionTable[1] = CTest1; + return 0; +} + +#else +/****************** +** If your loader supports global initialization (most do.) then just +** create the table like this. +*/ +CFunc0 CustomFunctionTable[] = +{ + (CFunc0) CTest0, + (CFunc0) CTest1 +}; +#endif + +/**************************************************************** +** Step 3: Add custom functions to the dictionary. +** Do not change the name of CompileCustomFunctions! +** It is called by the pForth kernel. +****************************************************************/ + +#if (!defined(PF_NO_INIT)) && (!defined(PF_NO_SHELL)) +Err CompileCustomFunctions( void ) +{ + Err err; + int i = 0; +/* Compile Forth words that call your custom functions. +** Make sure order of functions matches that in LoadCustomFunctionTable(). +** Parameters are: Name in UPPER CASE, Function, Index, Mode, NumParams +*/ + err = CreateGlueToC( "CTEST0", i++, C_RETURNS_VALUE, 1 ); + if( err < 0 ) return err; + err = CreateGlueToC( "CTEST1", i++, C_RETURNS_VOID, 2 ); + if( err < 0 ) return err; + + return 0; +} +#else +Err CompileCustomFunctions( void ) { return 0; } +#endif + +/**************************************************************** +** Step 4: Recompile using compiler option PF_USER_CUSTOM +** and link with your code. +** Then rebuild the Forth using "pforth -i system.fth" +** Test: 10 Ctest0 ( should print message then '11' ) +****************************************************************/ + +#endif /* PF_USER_CUSTOM */ + diff --git a/src/cmd/pforth/pfdicdat.h b/src/cmd/pforth/pfdicdat.h new file mode 100644 index 0000000..479780a --- /dev/null +++ b/src/cmd/pforth/pfdicdat.h @@ -0,0 +1,3364 @@ +/* This file generated by the Forth command SDAD */ +#define HEADERPTR (0x00003D9C) +#define RELCONTEXT (0x00003D94) +#define CODEPTR (0x000093EC) +#define IF_LITTLE_ENDIAN (0x00000001) +static const uint8_t MinDicNames[] = { +/* 0x00000000: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x45,0x58,0x49,0x54,0x00,0x00,0x00, +/* 0x00000010: */ 0x08,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x02,0x31,0x2D,0x00,0x18,0x00,0x00,0x00, +/* 0x00000020: */ 0x02,0x00,0x00,0x00,0x02,0x31,0x2B,0x00,0x24,0x00,0x00,0x00,0x0A,0x00,0x00,0x00, +/* 0x00000030: */ 0x03,0x32,0x52,0x40,0x30,0x00,0x00,0x00,0x0B,0x00,0x00,0x00,0x03,0x32,0x52,0x3E, +/* 0x00000040: */ 0x3C,0x00,0x00,0x00,0x0C,0x00,0x00,0x00,0x03,0x32,0x3E,0x52,0x48,0x00,0x00,0x00, +/* 0x00000050: */ 0x03,0x00,0x00,0x00,0x04,0x32,0x44,0x55,0x50,0x00,0x00,0x00,0x54,0x00,0x00,0x00, +/* 0x00000060: */ 0x04,0x00,0x00,0x00,0x48,0x32,0x4C,0x49,0x54,0x45,0x52,0x41,0x4C,0x00,0x00,0x00, +/* 0x00000070: */ 0x64,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x0A,0x28,0x32,0x4C,0x49,0x54,0x45,0x52, +/* 0x00000080: */ 0x41,0x4C,0x29,0x00,0x78,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x02,0x32,0x2D,0x00, +/* 0x00000090: */ 0x8C,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x02,0x32,0x2B,0x00,0x98,0x00,0x00,0x00, +/* 0x000000A0: */ 0x07,0x00,0x00,0x00,0x05,0x32,0x4F,0x56,0x45,0x52,0x00,0x00,0xA4,0x00,0x00,0x00, +/* 0x000000B0: */ 0x09,0x00,0x00,0x00,0x05,0x32,0x53,0x57,0x41,0x50,0x00,0x00,0xB4,0x00,0x00,0x00, +/* 0x000000C0: */ 0x0D,0x00,0x00,0x00,0x08,0x28,0x41,0x43,0x43,0x45,0x50,0x54,0x29,0x00,0x00,0x00, +/* 0x000000D0: */ 0xC4,0x00,0x00,0x00,0xC8,0x00,0x00,0x00,0x06,0x41,0x43,0x43,0x45,0x50,0x54,0x00, +/* 0x000000E0: */ 0xD8,0x00,0x00,0x00,0x0E,0x00,0x00,0x00,0x48,0x41,0x4C,0x49,0x54,0x45,0x52,0x41, +/* 0x000000F0: */ 0x4C,0x00,0x00,0x00,0xE8,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x0A,0x28,0x41,0x4C, +/* 0x00000100: */ 0x49,0x54,0x45,0x52,0x41,0x4C,0x29,0x00,0xFC,0x00,0x00,0x00,0x10,0x00,0x00,0x00, +/* 0x00000110: */ 0x08,0x41,0x4C,0x4C,0x4F,0x43,0x41,0x54,0x45,0x00,0x00,0x00,0x10,0x01,0x00,0x00, +/* 0x00000120: */ 0x12,0x00,0x00,0x00,0x07,0x41,0x52,0x53,0x48,0x49,0x46,0x54,0x24,0x01,0x00,0x00, +/* 0x00000130: */ 0x11,0x00,0x00,0x00,0x03,0x41,0x4E,0x44,0x34,0x01,0x00,0x00,0x13,0x00,0x00,0x00, +/* 0x00000140: */ 0x04,0x42,0x41,0x49,0x4C,0x00,0x00,0x00,0x40,0x01,0x00,0x00,0x15,0x00,0x00,0x00, +/* 0x00000150: */ 0x06,0x42,0x52,0x41,0x4E,0x43,0x48,0x00,0x50,0x01,0x00,0x00,0x14,0x00,0x00,0x00, +/* 0x00000160: */ 0x0B,0x42,0x4F,0x44,0x59,0x5F,0x4F,0x46,0x46,0x53,0x45,0x54,0x60,0x01,0x00,0x00, +/* 0x00000170: */ 0x16,0x00,0x00,0x00,0x03,0x42,0x59,0x45,0x74,0x01,0x00,0x00,0xBD,0x00,0x00,0x00, +/* 0x00000180: */ 0x05,0x43,0x41,0x54,0x43,0x48,0x00,0x00,0x80,0x01,0x00,0x00,0xC2,0x00,0x00,0x00, +/* 0x00000190: */ 0x04,0x43,0x45,0x4C,0x4C,0x00,0x00,0x00,0x90,0x01,0x00,0x00,0xC3,0x00,0x00,0x00, +/* 0x000001A0: */ 0x05,0x43,0x45,0x4C,0x4C,0x53,0x00,0x00,0xA0,0x01,0x00,0x00,0x18,0x00,0x00,0x00, +/* 0x000001B0: */ 0x02,0x43,0x40,0x00,0xB0,0x01,0x00,0x00,0x19,0x00,0x00,0x00,0x05,0x43,0x4D,0x4F, +/* 0x000001C0: */ 0x56,0x45,0x00,0x00,0xBC,0x01,0x00,0x00,0x1A,0x00,0x00,0x00,0x06,0x43,0x4D,0x4F, +/* 0x000001D0: */ 0x56,0x45,0x3E,0x00,0xCC,0x01,0x00,0x00,0x1B,0x00,0x00,0x00,0x01,0x3A,0x00,0x00, +/* 0x000001E0: */ 0xDC,0x01,0x00,0x00,0x1C,0x00,0x00,0x00,0x03,0x28,0x3A,0x29,0xE8,0x01,0x00,0x00, +/* 0x000001F0: */ 0x1D,0x00,0x00,0x00,0x07,0x43,0x4F,0x4D,0x50,0x41,0x52,0x45,0xF4,0x01,0x00,0x00, +/* 0x00000200: */ 0x1E,0x00,0x00,0x00,0x01,0x3D,0x00,0x00,0x04,0x02,0x00,0x00,0x21,0x00,0x00,0x00, +/* 0x00000210: */ 0x02,0x3C,0x3E,0x00,0x10,0x02,0x00,0x00,0x1F,0x00,0x00,0x00,0x01,0x3E,0x00,0x00, +/* 0x00000220: */ 0x1C,0x02,0x00,0x00,0x22,0x00,0x00,0x00,0x02,0x55,0x3E,0x00,0x28,0x02,0x00,0x00, +/* 0x00000230: */ 0x20,0x00,0x00,0x00,0x01,0x3C,0x00,0x00,0x34,0x02,0x00,0x00,0x23,0x00,0x00,0x00, +/* 0x00000240: */ 0x02,0x55,0x3C,0x00,0x40,0x02,0x00,0x00,0x24,0x00,0x00,0x00,0x02,0x30,0x3D,0x00, +/* 0x00000250: */ 0x4C,0x02,0x00,0x00,0x27,0x00,0x00,0x00,0x03,0x30,0x3C,0x3E,0x58,0x02,0x00,0x00, +/* 0x00000260: */ 0x25,0x00,0x00,0x00,0x02,0x30,0x3E,0x00,0x64,0x02,0x00,0x00,0x26,0x00,0x00,0x00, +/* 0x00000270: */ 0x02,0x30,0x3C,0x00,0x70,0x02,0x00,0x00,0x28,0x00,0x00,0x00,0x02,0x43,0x52,0x00, +/* 0x00000280: */ 0x7C,0x02,0x00,0x00,0x29,0x00,0x00,0x00,0x06,0x43,0x52,0x45,0x41,0x54,0x45,0x00, +/* 0x00000290: */ 0x88,0x02,0x00,0x00,0x2A,0x00,0x00,0x00,0x08,0x28,0x43,0x52,0x45,0x41,0x54,0x45, +/* 0x000002A0: */ 0x29,0x00,0x00,0x00,0x98,0x02,0x00,0x00,0x39,0x00,0x00,0x00,0x02,0x44,0x2B,0x00, +/* 0x000002B0: */ 0xAC,0x02,0x00,0x00,0x36,0x00,0x00,0x00,0x02,0x44,0x2D,0x00,0xB8,0x02,0x00,0x00, +/* 0x000002C0: */ 0x3A,0x00,0x00,0x00,0x06,0x55,0x4D,0x2F,0x4D,0x4F,0x44,0x00,0xC4,0x02,0x00,0x00, +/* 0x000002D0: */ 0x38,0x00,0x00,0x00,0x06,0x4D,0x55,0x2F,0x4D,0x4F,0x44,0x00,0xD4,0x02,0x00,0x00, +/* 0x000002E0: */ 0x37,0x00,0x00,0x00,0x02,0x4D,0x2A,0x00,0xE4,0x02,0x00,0x00,0x3B,0x00,0x00,0x00, +/* 0x000002F0: */ 0x03,0x55,0x4D,0x2A,0xF0,0x02,0x00,0x00,0x2C,0x00,0x00,0x00,0x05,0x44,0x45,0x46, +/* 0x00000300: */ 0x45,0x52,0x00,0x00,0xFC,0x02,0x00,0x00,0x2B,0x00,0x00,0x00,0x02,0x43,0x21,0x00, +/* 0x00000310: */ 0x0C,0x03,0x00,0x00,0x2E,0x00,0x00,0x00,0x05,0x44,0x45,0x50,0x54,0x48,0x00,0x00, +/* 0x00000320: */ 0x18,0x03,0x00,0x00,0x2F,0x00,0x00,0x00,0x01,0x2F,0x00,0x00,0x28,0x03,0x00,0x00, +/* 0x00000330: */ 0x30,0x00,0x00,0x00,0x01,0x2E,0x00,0x00,0x34,0x03,0x00,0x00,0x31,0x00,0x00,0x00, +/* 0x00000340: */ 0x02,0x2E,0x53,0x00,0x40,0x03,0x00,0x00,0x32,0x00,0x00,0x00,0x04,0x28,0x44,0x4F, +/* 0x00000350: */ 0x29,0x00,0x00,0x00,0x4C,0x03,0x00,0x00,0x33,0x00,0x00,0x00,0x04,0x44,0x52,0x4F, +/* 0x00000360: */ 0x50,0x00,0x00,0x00,0x5C,0x03,0x00,0x00,0x34,0x00,0x00,0x00,0x04,0x44,0x55,0x4D, +/* 0x00000370: */ 0x50,0x00,0x00,0x00,0x6C,0x03,0x00,0x00,0x35,0x00,0x00,0x00,0x03,0x44,0x55,0x50, +/* 0x00000380: */ 0x7C,0x03,0x00,0x00,0x3D,0x00,0x00,0x00,0x06,0x28,0x45,0x4D,0x49,0x54,0x29,0x00, +/* 0x00000390: */ 0x88,0x03,0x00,0x00,0xD4,0x00,0x00,0x00,0x04,0x45,0x4D,0x49,0x54,0x00,0x00,0x00, +/* 0x000003A0: */ 0x98,0x03,0x00,0x00,0x3E,0x00,0x00,0x00,0x03,0x45,0x4F,0x4C,0xA8,0x03,0x00,0x00, +/* 0x000003B0: */ 0x3F,0x00,0x00,0x00,0x08,0x28,0x3F,0x45,0x52,0x52,0x4F,0x52,0x29,0x00,0x00,0x00, +/* 0x000003C0: */ 0xB4,0x03,0x00,0x00,0x3F,0x00,0x00,0x00,0x06,0x3F,0x45,0x52,0x52,0x4F,0x52,0x00, +/* 0x000003D0: */ 0xC8,0x03,0x00,0x00,0x40,0x00,0x00,0x00,0x07,0x45,0x58,0x45,0x43,0x55,0x54,0x45, +/* 0x000003E0: */ 0xD8,0x03,0x00,0x00,0x41,0x00,0x00,0x00,0x01,0x40,0x00,0x00,0xE8,0x03,0x00,0x00, +/* 0x000003F0: */ 0x4C,0x00,0x00,0x00,0x04,0x46,0x49,0x4C,0x4C,0x00,0x00,0x00,0xF4,0x03,0x00,0x00, +/* 0x00000400: */ 0x4D,0x00,0x00,0x00,0x04,0x46,0x49,0x4E,0x44,0x00,0x00,0x00,0x04,0x04,0x00,0x00, +/* 0x00000410: */ 0x43,0x00,0x00,0x00,0x0B,0x43,0x52,0x45,0x41,0x54,0x45,0x2D,0x46,0x49,0x4C,0x45, +/* 0x00000420: */ 0x14,0x04,0x00,0x00,0xC4,0x00,0x00,0x00,0x0B,0x44,0x45,0x4C,0x45,0x54,0x45,0x2D, +/* 0x00000430: */ 0x46,0x49,0x4C,0x45,0x28,0x04,0x00,0x00,0x44,0x00,0x00,0x00,0x09,0x4F,0x50,0x45, +/* 0x00000440: */ 0x4E,0x2D,0x46,0x49,0x4C,0x45,0x00,0x00,0x3C,0x04,0x00,0x00,0x42,0x00,0x00,0x00, +/* 0x00000450: */ 0x0A,0x43,0x4C,0x4F,0x53,0x45,0x2D,0x46,0x49,0x4C,0x45,0x00,0x50,0x04,0x00,0x00, +/* 0x00000460: */ 0x46,0x00,0x00,0x00,0x09,0x52,0x45,0x41,0x44,0x2D,0x46,0x49,0x4C,0x45,0x00,0x00, +/* 0x00000470: */ 0x64,0x04,0x00,0x00,0x4A,0x00,0x00,0x00,0x09,0x46,0x49,0x4C,0x45,0x2D,0x53,0x49, +/* 0x00000480: */ 0x5A,0x45,0x00,0x00,0x78,0x04,0x00,0x00,0x4B,0x00,0x00,0x00,0x0A,0x57,0x52,0x49, +/* 0x00000490: */ 0x54,0x45,0x2D,0x46,0x49,0x4C,0x45,0x00,0x8C,0x04,0x00,0x00,0x45,0x00,0x00,0x00, +/* 0x000004A0: */ 0x0D,0x46,0x49,0x4C,0x45,0x2D,0x50,0x4F,0x53,0x49,0x54,0x49,0x4F,0x4E,0x00,0x00, +/* 0x000004B0: */ 0xA0,0x04,0x00,0x00,0x47,0x00,0x00,0x00,0x0F,0x52,0x45,0x50,0x4F,0x53,0x49,0x54, +/* 0x000004C0: */ 0x49,0x4F,0x4E,0x2D,0x46,0x49,0x4C,0x45,0xB8,0x04,0x00,0x00,0x48,0x00,0x00,0x00, +/* 0x000004D0: */ 0x03,0x52,0x2F,0x4F,0xD0,0x04,0x00,0x00,0x49,0x00,0x00,0x00,0x03,0x52,0x2F,0x57, +/* 0x000004E0: */ 0xDC,0x04,0x00,0x00,0xC0,0x00,0x00,0x00,0x03,0x57,0x2F,0x4F,0xE8,0x04,0x00,0x00, +/* 0x000004F0: */ 0xC1,0x00,0x00,0x00,0x03,0x42,0x49,0x4E,0xF4,0x04,0x00,0x00,0x4E,0x00,0x00,0x00, +/* 0x00000500: */ 0x07,0x46,0x49,0x4E,0x44,0x4E,0x46,0x41,0x00,0x05,0x00,0x00,0x4F,0x00,0x00,0x00, +/* 0x00000510: */ 0x09,0x46,0x4C,0x55,0x53,0x48,0x45,0x4D,0x49,0x54,0x00,0x00,0x10,0x05,0x00,0x00, +/* 0x00000520: */ 0x50,0x00,0x00,0x00,0x04,0x46,0x52,0x45,0x45,0x00,0x00,0x00,0x24,0x05,0x00,0x00, +/* 0x00000530: */ 0x51,0x00,0x00,0x00,0x04,0x48,0x45,0x52,0x45,0x00,0x00,0x00,0x34,0x05,0x00,0x00, +/* 0x00000540: */ 0x52,0x00,0x00,0x00,0x0A,0x28,0x53,0x4E,0x55,0x4D,0x42,0x45,0x52,0x3F,0x29,0x00, +/* 0x00000550: */ 0x44,0x05,0x00,0x00,0x53,0x00,0x00,0x00,0x01,0x49,0x00,0x00,0x58,0x05,0x00,0x00, +/* 0x00000560: */ 0xBF,0x00,0x00,0x00,0x09,0x49,0x4E,0x54,0x45,0x52,0x50,0x52,0x45,0x54,0x00,0x00, +/* 0x00000570: */ 0x64,0x05,0x00,0x00,0x55,0x00,0x00,0x00,0x01,0x4A,0x00,0x00,0x78,0x05,0x00,0x00, +/* 0x00000580: */ 0x54,0x00,0x00,0x00,0x0C,0x49,0x4E,0x43,0x4C,0x55,0x44,0x45,0x2D,0x46,0x49,0x4C, +/* 0x00000590: */ 0x45,0x00,0x00,0x00,0x84,0x05,0x00,0x00,0x56,0x00,0x00,0x00,0x03,0x4B,0x45,0x59, +/* 0x000005A0: */ 0x9C,0x05,0x00,0x00,0x57,0x00,0x00,0x00,0x07,0x28,0x4C,0x45,0x41,0x56,0x45,0x29, +/* 0x000005B0: */ 0xA8,0x05,0x00,0x00,0x58,0x00,0x00,0x00,0x47,0x4C,0x49,0x54,0x45,0x52,0x41,0x4C, +/* 0x000005C0: */ 0xB8,0x05,0x00,0x00,0x59,0x00,0x00,0x00,0x09,0x28,0x4C,0x49,0x54,0x45,0x52,0x41, +/* 0x000005D0: */ 0x4C,0x29,0x00,0x00,0xC8,0x05,0x00,0x00,0x5A,0x00,0x00,0x00,0x07,0x4C,0x4F,0x41, +/* 0x000005E0: */ 0x44,0x53,0x59,0x53,0xDC,0x05,0x00,0x00,0x5B,0x00,0x00,0x00,0x0E,0x4C,0x4F,0x43, +/* 0x000005F0: */ 0x41,0x4C,0x2D,0x43,0x4F,0x4D,0x50,0x49,0x4C,0x45,0x52,0x00,0xEC,0x05,0x00,0x00, +/* 0x00000600: */ 0x5C,0x00,0x00,0x00,0x0D,0x28,0x4C,0x4F,0x43,0x41,0x4C,0x2E,0x45,0x4E,0x54,0x52, +/* 0x00000610: */ 0x59,0x29,0x00,0x00,0x04,0x06,0x00,0x00,0x5D,0x00,0x00,0x00,0x0C,0x28,0x4C,0x4F, +/* 0x00000620: */ 0x43,0x41,0x4C,0x2E,0x45,0x58,0x49,0x54,0x29,0x00,0x00,0x00,0x1C,0x06,0x00,0x00, +/* 0x00000630: */ 0x5E,0x00,0x00,0x00,0x08,0x28,0x4C,0x4F,0x43,0x41,0x4C,0x40,0x29,0x00,0x00,0x00, +/* 0x00000640: */ 0x34,0x06,0x00,0x00,0x5F,0x00,0x00,0x00,0x0A,0x28,0x31,0x5F,0x4C,0x4F,0x43,0x41, +/* 0x00000650: */ 0x4C,0x40,0x29,0x00,0x48,0x06,0x00,0x00,0x60,0x00,0x00,0x00,0x0A,0x28,0x32,0x5F, +/* 0x00000660: */ 0x4C,0x4F,0x43,0x41,0x4C,0x40,0x29,0x00,0x5C,0x06,0x00,0x00,0x61,0x00,0x00,0x00, +/* 0x00000670: */ 0x0A,0x28,0x33,0x5F,0x4C,0x4F,0x43,0x41,0x4C,0x40,0x29,0x00,0x70,0x06,0x00,0x00, +/* 0x00000680: */ 0x62,0x00,0x00,0x00,0x0A,0x28,0x34,0x5F,0x4C,0x4F,0x43,0x41,0x4C,0x40,0x29,0x00, +/* 0x00000690: */ 0x84,0x06,0x00,0x00,0x63,0x00,0x00,0x00,0x0A,0x28,0x35,0x5F,0x4C,0x4F,0x43,0x41, +/* 0x000006A0: */ 0x4C,0x40,0x29,0x00,0x98,0x06,0x00,0x00,0x64,0x00,0x00,0x00,0x0A,0x28,0x36,0x5F, +/* 0x000006B0: */ 0x4C,0x4F,0x43,0x41,0x4C,0x40,0x29,0x00,0xAC,0x06,0x00,0x00,0x65,0x00,0x00,0x00, +/* 0x000006C0: */ 0x0A,0x28,0x37,0x5F,0x4C,0x4F,0x43,0x41,0x4C,0x40,0x29,0x00,0xC0,0x06,0x00,0x00, +/* 0x000006D0: */ 0x66,0x00,0x00,0x00,0x0A,0x28,0x38,0x5F,0x4C,0x4F,0x43,0x41,0x4C,0x40,0x29,0x00, +/* 0x000006E0: */ 0xD4,0x06,0x00,0x00,0x68,0x00,0x00,0x00,0x08,0x28,0x4C,0x4F,0x43,0x41,0x4C,0x21, +/* 0x000006F0: */ 0x29,0x00,0x00,0x00,0xE8,0x06,0x00,0x00,0x69,0x00,0x00,0x00,0x0A,0x28,0x31,0x5F, +/* 0x00000700: */ 0x4C,0x4F,0x43,0x41,0x4C,0x21,0x29,0x00,0xFC,0x06,0x00,0x00,0x6A,0x00,0x00,0x00, +/* 0x00000710: */ 0x0A,0x28,0x32,0x5F,0x4C,0x4F,0x43,0x41,0x4C,0x21,0x29,0x00,0x10,0x07,0x00,0x00, +/* 0x00000720: */ 0x6B,0x00,0x00,0x00,0x0A,0x28,0x33,0x5F,0x4C,0x4F,0x43,0x41,0x4C,0x21,0x29,0x00, +/* 0x00000730: */ 0x24,0x07,0x00,0x00,0x6C,0x00,0x00,0x00,0x0A,0x28,0x34,0x5F,0x4C,0x4F,0x43,0x41, +/* 0x00000740: */ 0x4C,0x21,0x29,0x00,0x38,0x07,0x00,0x00,0x6D,0x00,0x00,0x00,0x0A,0x28,0x35,0x5F, +/* 0x00000750: */ 0x4C,0x4F,0x43,0x41,0x4C,0x21,0x29,0x00,0x4C,0x07,0x00,0x00,0x6E,0x00,0x00,0x00, +/* 0x00000760: */ 0x0A,0x28,0x36,0x5F,0x4C,0x4F,0x43,0x41,0x4C,0x21,0x29,0x00,0x60,0x07,0x00,0x00, +/* 0x00000770: */ 0x6F,0x00,0x00,0x00,0x0A,0x28,0x37,0x5F,0x4C,0x4F,0x43,0x41,0x4C,0x21,0x29,0x00, +/* 0x00000780: */ 0x74,0x07,0x00,0x00,0x70,0x00,0x00,0x00,0x0A,0x28,0x38,0x5F,0x4C,0x4F,0x43,0x41, +/* 0x00000790: */ 0x4C,0x21,0x29,0x00,0x88,0x07,0x00,0x00,0x67,0x00,0x00,0x00,0x09,0x28,0x4C,0x4F, +/* 0x000007A0: */ 0x43,0x41,0x4C,0x2B,0x21,0x29,0x00,0x00,0x9C,0x07,0x00,0x00,0x71,0x00,0x00,0x00, +/* 0x000007B0: */ 0x06,0x28,0x4C,0x4F,0x4F,0x50,0x29,0x00,0xB0,0x07,0x00,0x00,0x72,0x00,0x00,0x00, +/* 0x000007C0: */ 0x06,0x4C,0x53,0x48,0x49,0x46,0x54,0x00,0xC0,0x07,0x00,0x00,0x73,0x00,0x00,0x00, +/* 0x000007D0: */ 0x03,0x4D,0x41,0x58,0xD0,0x07,0x00,0x00,0x74,0x00,0x00,0x00,0x03,0x4D,0x49,0x4E, +/* 0x000007E0: */ 0xDC,0x07,0x00,0x00,0x75,0x00,0x00,0x00,0x01,0x2D,0x00,0x00,0xE8,0x07,0x00,0x00, +/* 0x000007F0: */ 0x77,0x00,0x00,0x00,0x05,0x4E,0x41,0x4D,0x45,0x3E,0x00,0x00,0xF4,0x07,0x00,0x00, +/* 0x00000800: */ 0x76,0x00,0x00,0x00,0x08,0x50,0x52,0x45,0x56,0x4E,0x41,0x4D,0x45,0x00,0x00,0x00, +/* 0x00000810: */ 0x04,0x08,0x00,0x00,0x78,0x00,0x00,0x00,0x04,0x4E,0x4F,0x4F,0x50,0x00,0x00,0x00, +/* 0x00000820: */ 0x18,0x08,0x00,0x00,0xE0,0x00,0x00,0x00,0x07,0x4E,0x55,0x4D,0x42,0x45,0x52,0x3F, +/* 0x00000830: */ 0x28,0x08,0x00,0x00,0x7A,0x00,0x00,0x00,0x02,0x4F,0x52,0x00,0x38,0x08,0x00,0x00, +/* 0x00000840: */ 0x7B,0x00,0x00,0x00,0x04,0x4F,0x56,0x45,0x52,0x00,0x00,0x00,0x44,0x08,0x00,0x00, +/* 0x00000850: */ 0x7C,0x00,0x00,0x00,0x04,0x50,0x49,0x43,0x4B,0x00,0x00,0x00,0x54,0x08,0x00,0x00, +/* 0x00000860: */ 0x7D,0x00,0x00,0x00,0x01,0x2B,0x00,0x00,0x64,0x08,0x00,0x00,0x7E,0x00,0x00,0x00, +/* 0x00000870: */ 0x07,0x28,0x2B,0x4C,0x4F,0x4F,0x50,0x29,0x70,0x08,0x00,0x00,0x7F,0x00,0x00,0x00, +/* 0x00000880: */ 0x02,0x2B,0x21,0x00,0x80,0x08,0x00,0x00,0x83,0x00,0x00,0x00,0x06,0x28,0x51,0x55, +/* 0x00000890: */ 0x49,0x54,0x29,0x00,0x8C,0x08,0x00,0x00,0xEC,0x00,0x00,0x00,0x04,0x51,0x55,0x49, +/* 0x000008A0: */ 0x54,0x00,0x00,0x00,0x9C,0x08,0x00,0x00,0x80,0x00,0x00,0x00,0x05,0x28,0x3F,0x44, +/* 0x000008B0: */ 0x4F,0x29,0x00,0x00,0xAC,0x08,0x00,0x00,0x81,0x00,0x00,0x00,0x04,0x3F,0x44,0x55, +/* 0x000008C0: */ 0x50,0x00,0x00,0x00,0xBC,0x08,0x00,0x00,0x82,0x00,0x00,0x00,0x09,0x3F,0x54,0x45, +/* 0x000008D0: */ 0x52,0x4D,0x49,0x4E,0x41,0x4C,0x00,0x00,0xCC,0x08,0x00,0x00,0x82,0x00,0x00,0x00, +/* 0x000008E0: */ 0x04,0x4B,0x45,0x59,0x3F,0x00,0x00,0x00,0xE0,0x08,0x00,0x00,0x84,0x00,0x00,0x00, +/* 0x000008F0: */ 0x06,0x52,0x45,0x46,0x49,0x4C,0x4C,0x00,0xF0,0x08,0x00,0x00,0x85,0x00,0x00,0x00, +/* 0x00000900: */ 0x06,0x52,0x45,0x53,0x49,0x5A,0x45,0x00,0x00,0x09,0x00,0x00,0x87,0x00,0x00,0x00, +/* 0x00000910: */ 0x04,0x52,0x4F,0x4C,0x4C,0x00,0x00,0x00,0x10,0x09,0x00,0x00,0x88,0x00,0x00,0x00, +/* 0x00000920: */ 0x03,0x52,0x4F,0x54,0x20,0x09,0x00,0x00,0x8B,0x00,0x00,0x00,0x06,0x52,0x53,0x48, +/* 0x00000930: */ 0x49,0x46,0x54,0x00,0x2C,0x09,0x00,0x00,0x8C,0x00,0x00,0x00,0x05,0x52,0x44,0x52, +/* 0x00000940: */ 0x4F,0x50,0x00,0x00,0x3C,0x09,0x00,0x00,0x8D,0x00,0x00,0x00,0x02,0x52,0x40,0x00, +/* 0x00000950: */ 0x4C,0x09,0x00,0x00,0x8E,0x00,0x00,0x00,0x02,0x52,0x3E,0x00,0x58,0x09,0x00,0x00, +/* 0x00000960: */ 0x89,0x00,0x00,0x00,0x03,0x52,0x50,0x40,0x64,0x09,0x00,0x00,0x8A,0x00,0x00,0x00, +/* 0x00000970: */ 0x03,0x52,0x50,0x21,0x70,0x09,0x00,0x00,0x92,0x00,0x00,0x00,0x41,0x3B,0x00,0x00, +/* 0x00000980: */ 0x7C,0x09,0x00,0x00,0x99,0x00,0x00,0x00,0x03,0x53,0x50,0x40,0x88,0x09,0x00,0x00, +/* 0x00000990: */ 0x9A,0x00,0x00,0x00,0x03,0x53,0x50,0x21,0x94,0x09,0x00,0x00,0x9B,0x00,0x00,0x00, +/* 0x000009A0: */ 0x01,0x21,0x00,0x00,0xA0,0x09,0x00,0x00,0x8F,0x00,0x00,0x00,0x0C,0x28,0x53,0x41, +/* 0x000009B0: */ 0x56,0x45,0x2D,0x46,0x4F,0x52,0x54,0x48,0x29,0x00,0x00,0x00,0xAC,0x09,0x00,0x00, +/* 0x000009C0: */ 0x91,0x00,0x00,0x00,0x04,0x53,0x43,0x41,0x4E,0x00,0x00,0x00,0xC4,0x09,0x00,0x00, +/* 0x000009D0: */ 0x93,0x00,0x00,0x00,0x04,0x53,0x4B,0x49,0x50,0x00,0x00,0x00,0xD4,0x09,0x00,0x00, +/* 0x000009E0: */ 0x94,0x00,0x00,0x00,0x06,0x53,0x4F,0x55,0x52,0x43,0x45,0x00,0xE4,0x09,0x00,0x00, +/* 0x000009F0: */ 0x98,0x00,0x00,0x00,0x0A,0x53,0x45,0x54,0x2D,0x53,0x4F,0x55,0x52,0x43,0x45,0x00, +/* 0x00000A00: */ 0xF4,0x09,0x00,0x00,0x95,0x00,0x00,0x00,0x09,0x53,0x4F,0x55,0x52,0x43,0x45,0x2D, +/* 0x00000A10: */ 0x49,0x44,0x00,0x00,0x08,0x0A,0x00,0x00,0x97,0x00,0x00,0x00,0x0E,0x50,0x55,0x53, +/* 0x00000A20: */ 0x48,0x2D,0x53,0x4F,0x55,0x52,0x43,0x45,0x2D,0x49,0x44,0x00,0x1C,0x0A,0x00,0x00, +/* 0x00000A30: */ 0x96,0x00,0x00,0x00,0x0D,0x50,0x4F,0x50,0x2D,0x53,0x4F,0x55,0x52,0x43,0x45,0x2D, +/* 0x00000A40: */ 0x49,0x44,0x00,0x00,0x34,0x0A,0x00,0x00,0x9C,0x00,0x00,0x00,0x04,0x53,0x57,0x41, +/* 0x00000A50: */ 0x50,0x00,0x00,0x00,0x4C,0x0A,0x00,0x00,0x9D,0x00,0x00,0x00,0x05,0x54,0x45,0x53, +/* 0x00000A60: */ 0x54,0x31,0x00,0x00,0x5C,0x0A,0x00,0x00,0x9E,0x00,0x00,0x00,0x05,0x54,0x45,0x53, +/* 0x00000A70: */ 0x54,0x32,0x00,0x00,0x6C,0x0A,0x00,0x00,0xA0,0x00,0x00,0x00,0x01,0x27,0x00,0x00, +/* 0x00000A80: */ 0x7C,0x0A,0x00,0x00,0xA1,0x00,0x00,0x00,0x01,0x2A,0x00,0x00,0x88,0x0A,0x00,0x00, +/* 0x00000A90: */ 0xBE,0x00,0x00,0x00,0x05,0x54,0x48,0x52,0x4F,0x57,0x00,0x00,0x94,0x0A,0x00,0x00, +/* 0x00000AA0: */ 0xA2,0x00,0x00,0x00,0x02,0x3E,0x52,0x00,0xA4,0x0A,0x00,0x00,0xA3,0x00,0x00,0x00, +/* 0x00000AB0: */ 0x04,0x54,0x59,0x50,0x45,0x00,0x00,0x00,0xB0,0x0A,0x00,0x00,0xA5,0x00,0x00,0x00, +/* 0x00000AC0: */ 0x04,0x42,0x41,0x53,0x45,0x00,0x00,0x00,0xC0,0x0A,0x00,0x00,0xA6,0x00,0x00,0x00, +/* 0x00000AD0: */ 0x09,0x43,0x4F,0x44,0x45,0x2D,0x42,0x41,0x53,0x45,0x00,0x00,0xD0,0x0A,0x00,0x00, +/* 0x00000AE0: */ 0xA7,0x00,0x00,0x00,0x0A,0x43,0x4F,0x44,0x45,0x2D,0x4C,0x49,0x4D,0x49,0x54,0x00, +/* 0x00000AF0: */ 0xE4,0x0A,0x00,0x00,0xA8,0x00,0x00,0x00,0x07,0x43,0x4F,0x4E,0x54,0x45,0x58,0x54, +/* 0x00000B00: */ 0xF8,0x0A,0x00,0x00,0xA9,0x00,0x00,0x00,0x02,0x44,0x50,0x00,0x08,0x0B,0x00,0x00, +/* 0x00000B10: */ 0xAA,0x00,0x00,0x00,0x04,0x45,0x43,0x48,0x4F,0x00,0x00,0x00,0x14,0x0B,0x00,0x00, +/* 0x00000B20: */ 0xAD,0x00,0x00,0x00,0x0B,0x48,0x45,0x41,0x44,0x45,0x52,0x53,0x2D,0x50,0x54,0x52, +/* 0x00000B30: */ 0x24,0x0B,0x00,0x00,0xAB,0x00,0x00,0x00,0x0C,0x48,0x45,0x41,0x44,0x45,0x52,0x53, +/* 0x00000B40: */ 0x2D,0x42,0x41,0x53,0x45,0x00,0x00,0x00,0x38,0x0B,0x00,0x00,0xAC,0x00,0x00,0x00, +/* 0x00000B50: */ 0x0D,0x48,0x45,0x41,0x44,0x45,0x52,0x53,0x2D,0x4C,0x49,0x4D,0x49,0x54,0x00,0x00, +/* 0x00000B60: */ 0x50,0x0B,0x00,0x00,0xAE,0x00,0x00,0x00,0x04,0x23,0x54,0x49,0x42,0x00,0x00,0x00, +/* 0x00000B70: */ 0x68,0x0B,0x00,0x00,0xB0,0x00,0x00,0x00,0x0B,0x52,0x45,0x54,0x55,0x52,0x4E,0x2D, +/* 0x00000B80: */ 0x43,0x4F,0x44,0x45,0x78,0x0B,0x00,0x00,0xB4,0x00,0x00,0x00,0x0B,0x54,0x52,0x41, +/* 0x00000B90: */ 0x43,0x45,0x2D,0x46,0x4C,0x41,0x47,0x53,0x8C,0x0B,0x00,0x00,0xB5,0x00,0x00,0x00, +/* 0x00000BA0: */ 0x0B,0x54,0x52,0x41,0x43,0x45,0x2D,0x4C,0x45,0x56,0x45,0x4C,0xA0,0x0B,0x00,0x00, +/* 0x00000BB0: */ 0xB6,0x00,0x00,0x00,0x0B,0x54,0x52,0x41,0x43,0x45,0x2D,0x53,0x54,0x41,0x43,0x4B, +/* 0x00000BC0: */ 0xB4,0x0B,0x00,0x00,0xAF,0x00,0x00,0x00,0x03,0x4F,0x55,0x54,0xC8,0x0B,0x00,0x00, +/* 0x00000BD0: */ 0xB2,0x00,0x00,0x00,0x05,0x53,0x54,0x41,0x54,0x45,0x00,0x00,0xD4,0x0B,0x00,0x00, +/* 0x00000BE0: */ 0xB3,0x00,0x00,0x00,0x03,0x3E,0x49,0x4E,0xE4,0x0B,0x00,0x00,0xB8,0x00,0x00,0x00, +/* 0x00000BF0: */ 0x04,0x57,0x4F,0x52,0x44,0x00,0x00,0x00,0xF0,0x0B,0x00,0x00,0xB9,0x00,0x00,0x00, +/* 0x00000C00: */ 0x02,0x57,0x40,0x00,0x00,0x0C,0x00,0x00,0xBA,0x00,0x00,0x00,0x02,0x57,0x21,0x00, +/* 0x00000C10: */ 0x0C,0x0C,0x00,0x00,0xBB,0x00,0x00,0x00,0x03,0x58,0x4F,0x52,0x18,0x0C,0x00,0x00, +/* 0x00000C20: */ 0xBC,0x00,0x00,0x00,0x07,0x30,0x42,0x52,0x41,0x4E,0x43,0x48,0x24,0x0C,0x00,0x00, +/* 0x00000C30: */ 0xF8,0x00,0x00,0x00,0x06,0x43,0x54,0x45,0x53,0x54,0x30,0x00,0x34,0x0C,0x00,0x00, +/* 0x00000C40: */ 0x04,0x01,0x00,0x00,0x06,0x43,0x54,0x45,0x53,0x54,0x31,0x00,0x44,0x0C,0x00,0x00, +/* 0x00000C50: */ 0x78,0x00,0x00,0x00,0x0E,0x3A,0x3A,0x3A,0x3A,0x73,0x79,0x73,0x74,0x65,0x6D,0x2E, +/* 0x00000C60: */ 0x66,0x74,0x68,0x00,0x54,0x0C,0x00,0x00,0x10,0x01,0x00,0x00,0x0B,0x46,0x49,0x52, +/* 0x00000C70: */ 0x53,0x54,0x5F,0x43,0x4F,0x4C,0x4F,0x4E,0x6C,0x0C,0x00,0x00,0x14,0x01,0x00,0x00, +/* 0x00000C80: */ 0x06,0x4C,0x41,0x54,0x45,0x53,0x54,0x00,0x80,0x0C,0x00,0x00,0x20,0x01,0x00,0x00, +/* 0x00000C90: */ 0x0E,0x46,0x4C,0x41,0x47,0x5F,0x49,0x4D,0x4D,0x45,0x44,0x49,0x41,0x54,0x45,0x00, +/* 0x00000CA0: */ 0x90,0x0C,0x00,0x00,0x2C,0x01,0x00,0x00,0x09,0x49,0x4D,0x4D,0x45,0x44,0x49,0x41, +/* 0x00000CB0: */ 0x54,0x45,0x00,0x00,0xA8,0x0C,0x00,0x00,0x4C,0x01,0x00,0x00,0x41,0x28,0x00,0x00, +/* 0x00000CC0: */ 0xBC,0x0C,0x00,0x00,0x60,0x01,0x00,0x00,0x41,0x5C,0x00,0x00,0xC8,0x0C,0x00,0x00, +/* 0x00000CD0: */ 0x70,0x01,0x00,0x00,0x05,0x43,0x4F,0x55,0x4E,0x54,0x00,0x00,0xD4,0x0C,0x00,0x00, +/* 0x00000CE0: */ 0x84,0x01,0x00,0x00,0x02,0x4F,0x4E,0x00,0xE4,0x0C,0x00,0x00,0x98,0x01,0x00,0x00, +/* 0x00000CF0: */ 0x03,0x4F,0x46,0x46,0xF0,0x0C,0x00,0x00,0xAC,0x01,0x00,0x00,0x05,0x43,0x45,0x4C, +/* 0x00000D00: */ 0x4C,0x2B,0x00,0x00,0xFC,0x0C,0x00,0x00,0xB8,0x01,0x00,0x00,0x05,0x43,0x45,0x4C, +/* 0x00000D10: */ 0x4C,0x2D,0x00,0x00,0x0C,0x0D,0x00,0x00,0xC4,0x01,0x00,0x00,0x05,0x43,0x45,0x4C, +/* 0x00000D20: */ 0x4C,0x2A,0x00,0x00,0x1C,0x0D,0x00,0x00,0xCC,0x01,0x00,0x00,0x05,0x43,0x48,0x41, +/* 0x00000D30: */ 0x52,0x2B,0x00,0x00,0x2C,0x0D,0x00,0x00,0xD4,0x01,0x00,0x00,0x45,0x43,0x48,0x41, +/* 0x00000D40: */ 0x52,0x53,0x00,0x00,0x3C,0x0D,0x00,0x00,0xD8,0x01,0x00,0x00,0x04,0x2D,0x52,0x4F, +/* 0x00000D50: */ 0x54,0x00,0x00,0x00,0x4C,0x0D,0x00,0x00,0xE4,0x01,0x00,0x00,0x04,0x33,0x44,0x55, +/* 0x00000D60: */ 0x50,0x00,0x00,0x00,0x5C,0x0D,0x00,0x00,0x0C,0x02,0x00,0x00,0x05,0x32,0x44,0x52, +/* 0x00000D70: */ 0x4F,0x50,0x00,0x00,0x6C,0x0D,0x00,0x00,0x18,0x02,0x00,0x00,0x03,0x4E,0x49,0x50, +/* 0x00000D80: */ 0x7C,0x0D,0x00,0x00,0x24,0x02,0x00,0x00,0x04,0x54,0x55,0x43,0x4B,0x00,0x00,0x00, +/* 0x00000D90: */ 0x88,0x0D,0x00,0x00,0x30,0x02,0x00,0x00,0x02,0x3C,0x3D,0x00,0x98,0x0D,0x00,0x00, +/* 0x00000DA0: */ 0x3C,0x02,0x00,0x00,0x02,0x3E,0x3D,0x00,0xA4,0x0D,0x00,0x00,0x48,0x02,0x00,0x00, +/* 0x00000DB0: */ 0x06,0x49,0x4E,0x56,0x45,0x52,0x54,0x00,0xB0,0x0D,0x00,0x00,0x58,0x02,0x00,0x00, +/* 0x00000DC0: */ 0x03,0x4E,0x4F,0x54,0xC0,0x0D,0x00,0x00,0x60,0x02,0x00,0x00,0x06,0x4E,0x45,0x47, +/* 0x00000DD0: */ 0x41,0x54,0x45,0x00,0xCC,0x0D,0x00,0x00,0x74,0x02,0x00,0x00,0x07,0x44,0x4E,0x45, +/* 0x00000DE0: */ 0x47,0x41,0x54,0x45,0xDC,0x0D,0x00,0x00,0x90,0x02,0x00,0x00,0x03,0x49,0x44,0x2E, +/* 0x00000DF0: */ 0xEC,0x0D,0x00,0x00,0xA8,0x02,0x00,0x00,0x07,0x44,0x45,0x43,0x49,0x4D,0x41,0x4C, +/* 0x00000E00: */ 0xF8,0x0D,0x00,0x00,0xBC,0x02,0x00,0x00,0x05,0x4F,0x43,0x54,0x41,0x4C,0x00,0x00, +/* 0x00000E10: */ 0x08,0x0E,0x00,0x00,0xD0,0x02,0x00,0x00,0x03,0x48,0x45,0x58,0x18,0x0E,0x00,0x00, +/* 0x00000E20: */ 0xE4,0x02,0x00,0x00,0x06,0x42,0x49,0x4E,0x41,0x52,0x59,0x00,0x24,0x0E,0x00,0x00, +/* 0x00000E30: */ 0xF8,0x02,0x00,0x00,0x03,0x50,0x41,0x44,0x34,0x0E,0x00,0x00,0x0C,0x03,0x00,0x00, +/* 0x00000E40: */ 0x05,0x24,0x4D,0x4F,0x56,0x45,0x00,0x00,0x40,0x0E,0x00,0x00,0x20,0x03,0x00,0x00, +/* 0x00000E50: */ 0x07,0x42,0x45,0x54,0x57,0x45,0x45,0x4E,0x50,0x0E,0x00,0x00,0x48,0x03,0x00,0x00, +/* 0x00000E60: */ 0x41,0x5B,0x00,0x00,0x60,0x0E,0x00,0x00,0x5C,0x03,0x00,0x00,0x01,0x5D,0x00,0x00, +/* 0x00000E70: */ 0x6C,0x0E,0x00,0x00,0x70,0x03,0x00,0x00,0x07,0x45,0x56,0x45,0x4E,0x2D,0x55,0x50, +/* 0x00000E80: */ 0x78,0x0E,0x00,0x00,0x88,0x03,0x00,0x00,0x07,0x41,0x4C,0x49,0x47,0x4E,0x45,0x44, +/* 0x00000E90: */ 0x88,0x0E,0x00,0x00,0xA4,0x03,0x00,0x00,0x05,0x41,0x4C,0x49,0x47,0x4E,0x00,0x00, +/* 0x00000EA0: */ 0x98,0x0E,0x00,0x00,0xBC,0x03,0x00,0x00,0x05,0x41,0x4C,0x4C,0x4F,0x54,0x00,0x00, +/* 0x00000EB0: */ 0xA8,0x0E,0x00,0x00,0xC8,0x03,0x00,0x00,0x02,0x43,0x2C,0x00,0xB8,0x0E,0x00,0x00, +/* 0x00000EC0: */ 0xE4,0x03,0x00,0x00,0x02,0x57,0x2C,0x00,0xC4,0x0E,0x00,0x00,0x14,0x04,0x00,0x00, +/* 0x00000ED0: */ 0x01,0x2C,0x00,0x00,0xD0,0x0E,0x00,0x00,0x2C,0x04,0x00,0x00,0x0A,0x4E,0x3E,0x4E, +/* 0x00000EE0: */ 0x45,0x58,0x54,0x4C,0x49,0x4E,0x4B,0x00,0xDC,0x0E,0x00,0x00,0x50,0x04,0x00,0x00, +/* 0x00000EF0: */ 0x08,0x4E,0x41,0x4D,0x45,0x42,0x41,0x53,0x45,0x00,0x00,0x00,0xF0,0x0E,0x00,0x00, +/* 0x00000F00: */ 0x5C,0x04,0x00,0x00,0x08,0x43,0x4F,0x44,0x45,0x42,0x41,0x53,0x45,0x00,0x00,0x00, +/* 0x00000F10: */ 0x04,0x0F,0x00,0x00,0x68,0x04,0x00,0x00,0x09,0x4E,0x41,0x4D,0x45,0x4C,0x49,0x4D, +/* 0x00000F20: */ 0x49,0x54,0x00,0x00,0x18,0x0F,0x00,0x00,0x74,0x04,0x00,0x00,0x09,0x43,0x4F,0x44, +/* 0x00000F30: */ 0x45,0x4C,0x49,0x4D,0x49,0x54,0x00,0x00,0x2C,0x0F,0x00,0x00,0x80,0x04,0x00,0x00, +/* 0x00000F40: */ 0x09,0x4E,0x41,0x4D,0x45,0x42,0x41,0x53,0x45,0x2B,0x00,0x00,0x40,0x0F,0x00,0x00, +/* 0x00000F50: */ 0x8C,0x04,0x00,0x00,0x05,0x3E,0x43,0x4F,0x44,0x45,0x00,0x00,0x54,0x0F,0x00,0x00, +/* 0x00000F60: */ 0x98,0x04,0x00,0x00,0x05,0x43,0x4F,0x44,0x45,0x3E,0x00,0x00,0x64,0x0F,0x00,0x00, +/* 0x00000F70: */ 0xA4,0x04,0x00,0x00,0x06,0x4E,0x3E,0x4C,0x49,0x4E,0x4B,0x00,0x74,0x0F,0x00,0x00, +/* 0x00000F80: */ 0xB8,0x04,0x00,0x00,0x05,0x3E,0x42,0x4F,0x44,0x59,0x00,0x00,0x84,0x0F,0x00,0x00, +/* 0x00000F90: */ 0xC8,0x04,0x00,0x00,0x05,0x42,0x4F,0x44,0x59,0x3E,0x00,0x00,0x94,0x0F,0x00,0x00, +/* 0x00000FA0: */ 0xD8,0x04,0x00,0x00,0x08,0x55,0x53,0x45,0x2D,0x3E,0x52,0x45,0x4C,0x00,0x00,0x00, +/* 0x00000FB0: */ 0xA4,0x0F,0x00,0x00,0xE4,0x04,0x00,0x00,0x08,0x52,0x45,0x4C,0x2D,0x3E,0x55,0x53, +/* 0x00000FC0: */ 0x45,0x00,0x00,0x00,0xB8,0x0F,0x00,0x00,0xF0,0x04,0x00,0x00,0x02,0x58,0x40,0x00, +/* 0x00000FD0: */ 0xCC,0x0F,0x00,0x00,0xF8,0x04,0x00,0x00,0x02,0x58,0x21,0x00,0xD8,0x0F,0x00,0x00, +/* 0x00000FE0: */ 0x00,0x05,0x00,0x00,0x08,0x43,0x4F,0x4D,0x50,0x49,0x4C,0x45,0x2C,0x00,0x00,0x00, +/* 0x00000FF0: */ 0xE4,0x0F,0x00,0x00,0x08,0x05,0x00,0x00,0x49,0x5B,0x43,0x4F,0x4D,0x50,0x49,0x4C, +/* 0x00001000: */ 0x45,0x5D,0x00,0x00,0xF8,0x0F,0x00,0x00,0x14,0x05,0x00,0x00,0x09,0x28,0x43,0x4F, +/* 0x00001010: */ 0x4D,0x50,0x49,0x4C,0x45,0x29,0x00,0x00,0x0C,0x10,0x00,0x00,0x28,0x05,0x00,0x00, +/* 0x00001020: */ 0x47,0x43,0x4F,0x4D,0x50,0x49,0x4C,0x45,0x20,0x10,0x00,0x00,0x34,0x05,0x00,0x00, +/* 0x00001030: */ 0x07,0x3A,0x4E,0x4F,0x4E,0x41,0x4D,0x45,0x30,0x10,0x00,0x00,0x48,0x05,0x00,0x00, +/* 0x00001040: */ 0x09,0x45,0x52,0x52,0x5F,0x41,0x42,0x4F,0x52,0x54,0x00,0x00,0x40,0x10,0x00,0x00, +/* 0x00001050: */ 0x54,0x05,0x00,0x00,0x0D,0x45,0x52,0x52,0x5F,0x45,0x58,0x45,0x43,0x55,0x54,0x49, +/* 0x00001060: */ 0x4E,0x47,0x00,0x00,0x54,0x10,0x00,0x00,0x60,0x05,0x00,0x00,0x09,0x45,0x52,0x52, +/* 0x00001070: */ 0x5F,0x50,0x41,0x49,0x52,0x53,0x00,0x00,0x6C,0x10,0x00,0x00,0x6C,0x05,0x00,0x00, +/* 0x00001080: */ 0x09,0x45,0x52,0x52,0x5F,0x44,0x45,0x46,0x45,0x52,0x00,0x00,0x80,0x10,0x00,0x00, +/* 0x00001090: */ 0x78,0x05,0x00,0x00,0x05,0x41,0x42,0x4F,0x52,0x54,0x00,0x00,0x94,0x10,0x00,0x00, +/* 0x000010A0: */ 0x84,0x05,0x00,0x00,0x0F,0x43,0x4F,0x4E,0x44,0x49,0x54,0x49,0x4F,0x4E,0x41,0x4C, +/* 0x000010B0: */ 0x5F,0x4B,0x45,0x59,0xA4,0x10,0x00,0x00,0x90,0x05,0x00,0x00,0x0A,0x3F,0x43,0x4F, +/* 0x000010C0: */ 0x4E,0x44,0x49,0x54,0x49,0x4F,0x4E,0x00,0xBC,0x10,0x00,0x00,0xA4,0x05,0x00,0x00, +/* 0x000010D0: */ 0x05,0x3E,0x4D,0x41,0x52,0x4B,0x00,0x00,0xD0,0x10,0x00,0x00,0xB8,0x05,0x00,0x00, +/* 0x000010E0: */ 0x08,0x3E,0x52,0x45,0x53,0x4F,0x4C,0x56,0x45,0x00,0x00,0x00,0xE0,0x10,0x00,0x00, +/* 0x000010F0: */ 0xD0,0x05,0x00,0x00,0x05,0x3C,0x4D,0x41,0x52,0x4B,0x00,0x00,0xF4,0x10,0x00,0x00, +/* 0x00001100: */ 0xD8,0x05,0x00,0x00,0x08,0x3C,0x52,0x45,0x53,0x4F,0x4C,0x56,0x45,0x00,0x00,0x00, +/* 0x00001110: */ 0x04,0x11,0x00,0x00,0xE8,0x05,0x00,0x00,0x05,0x3F,0x43,0x4F,0x4D,0x50,0x00,0x00, +/* 0x00001120: */ 0x18,0x11,0x00,0x00,0x00,0x06,0x00,0x00,0x06,0x3F,0x50,0x41,0x49,0x52,0x53,0x00, +/* 0x00001130: */ 0x28,0x11,0x00,0x00,0x10,0x06,0x00,0x00,0x42,0x49,0x46,0x00,0x38,0x11,0x00,0x00, +/* 0x00001140: */ 0x2C,0x06,0x00,0x00,0x44,0x54,0x48,0x45,0x4E,0x00,0x00,0x00,0x44,0x11,0x00,0x00, +/* 0x00001150: */ 0x3C,0x06,0x00,0x00,0x45,0x42,0x45,0x47,0x49,0x4E,0x00,0x00,0x54,0x11,0x00,0x00, +/* 0x00001160: */ 0x4C,0x06,0x00,0x00,0x45,0x41,0x47,0x41,0x49,0x4E,0x00,0x00,0x64,0x11,0x00,0x00, +/* 0x00001170: */ 0x68,0x06,0x00,0x00,0x45,0x55,0x4E,0x54,0x49,0x4C,0x00,0x00,0x74,0x11,0x00,0x00, +/* 0x00001180: */ 0x84,0x06,0x00,0x00,0x45,0x41,0x48,0x45,0x41,0x44,0x00,0x00,0x84,0x11,0x00,0x00, +/* 0x00001190: */ 0x9C,0x06,0x00,0x00,0x44,0x45,0x4C,0x53,0x45,0x00,0x00,0x00,0x94,0x11,0x00,0x00, +/* 0x000011A0: */ 0xAC,0x06,0x00,0x00,0x45,0x57,0x48,0x49,0x4C,0x45,0x00,0x00,0xA4,0x11,0x00,0x00, +/* 0x000011B0: */ 0xB8,0x06,0x00,0x00,0x46,0x52,0x45,0x50,0x45,0x41,0x54,0x00,0xB4,0x11,0x00,0x00, +/* 0x000011C0: */ 0xC4,0x06,0x00,0x00,0x43,0x5B,0x27,0x5D,0xC4,0x11,0x00,0x00,0xD4,0x06,0x00,0x00, +/* 0x000011D0: */ 0x07,0x28,0x44,0x4F,0x45,0x53,0x3E,0x29,0xD0,0x11,0x00,0x00,0xF0,0x06,0x00,0x00, +/* 0x000011E0: */ 0x45,0x44,0x4F,0x45,0x53,0x3E,0x00,0x00,0xE0,0x11,0x00,0x00,0x2C,0x07,0x00,0x00, +/* 0x000011F0: */ 0x08,0x56,0x41,0x52,0x49,0x41,0x42,0x4C,0x45,0x00,0x00,0x00,0xF0,0x11,0x00,0x00, +/* 0x00001200: */ 0x40,0x07,0x00,0x00,0x09,0x32,0x56,0x41,0x52,0x49,0x41,0x42,0x4C,0x45,0x00,0x00, +/* 0x00001210: */ 0x04,0x12,0x00,0x00,0x60,0x07,0x00,0x00,0x08,0x43,0x4F,0x4E,0x53,0x54,0x41,0x4E, +/* 0x00001220: */ 0x54,0x00,0x00,0x00,0x18,0x12,0x00,0x00,0x80,0x07,0x00,0x00,0x02,0x2D,0x31,0x00, +/* 0x00001230: */ 0x2C,0x12,0x00,0x00,0x90,0x07,0x00,0x00,0x02,0x2D,0x32,0x00,0x38,0x12,0x00,0x00, +/* 0x00001240: */ 0xA0,0x07,0x00,0x00,0x02,0x32,0x21,0x00,0x44,0x12,0x00,0x00,0xB8,0x07,0x00,0x00, +/* 0x00001250: */ 0x02,0x32,0x40,0x00,0x50,0x12,0x00,0x00,0xD0,0x07,0x00,0x00,0x03,0x41,0x42,0x53, +/* 0x00001260: */ 0x5C,0x12,0x00,0x00,0xE8,0x07,0x00,0x00,0x04,0x44,0x41,0x42,0x53,0x00,0x00,0x00, +/* 0x00001270: */ 0x68,0x12,0x00,0x00,0x00,0x08,0x00,0x00,0x03,0x53,0x3E,0x44,0x78,0x12,0x00,0x00, +/* 0x00001280: */ 0x28,0x08,0x00,0x00,0x03,0x44,0x3E,0x53,0x84,0x12,0x00,0x00,0x30,0x08,0x00,0x00, +/* 0x00001290: */ 0x04,0x2F,0x4D,0x4F,0x44,0x00,0x00,0x00,0x90,0x12,0x00,0x00,0x44,0x08,0x00,0x00, +/* 0x000012A0: */ 0x03,0x4D,0x4F,0x44,0xA0,0x12,0x00,0x00,0x50,0x08,0x00,0x00,0x02,0x32,0x2A,0x00, +/* 0x000012B0: */ 0xAC,0x12,0x00,0x00,0x60,0x08,0x00,0x00,0x02,0x32,0x2F,0x00,0xB8,0x12,0x00,0x00, +/* 0x000012C0: */ 0x70,0x08,0x00,0x00,0x03,0x44,0x32,0x2A,0xC4,0x12,0x00,0x00,0xA4,0x08,0x00,0x00, +/* 0x000012D0: */ 0x05,0x46,0x41,0x4C,0x53,0x45,0x00,0x00,0xD0,0x12,0x00,0x00,0xB4,0x08,0x00,0x00, +/* 0x000012E0: */ 0x04,0x54,0x52,0x55,0x45,0x00,0x00,0x00,0xE0,0x12,0x00,0x00,0xC4,0x08,0x00,0x00, +/* 0x000012F0: */ 0x02,0x42,0x4C,0x00,0xF0,0x12,0x00,0x00,0xD4,0x08,0x00,0x00,0x0B,0x49,0x46,0x2E, +/* 0x00001300: */ 0x55,0x53,0x45,0x2D,0x3E,0x52,0x45,0x4C,0xFC,0x12,0x00,0x00,0xE8,0x08,0x00,0x00, +/* 0x00001310: */ 0x0B,0x49,0x46,0x2E,0x52,0x45,0x4C,0x2D,0x3E,0x55,0x53,0x45,0x10,0x13,0x00,0x00, +/* 0x00001320: */ 0xFC,0x08,0x00,0x00,0x02,0x41,0x21,0x00,0x24,0x13,0x00,0x00,0x10,0x09,0x00,0x00, +/* 0x00001330: */ 0x02,0x41,0x40,0x00,0x30,0x13,0x00,0x00,0x1C,0x09,0x00,0x00,0x02,0x41,0x2C,0x00, +/* 0x00001340: */ 0x3C,0x13,0x00,0x00,0x28,0x09,0x00,0x00,0x06,0x3A,0x53,0x54,0x41,0x43,0x4B,0x00, +/* 0x00001350: */ 0x48,0x13,0x00,0x00,0x54,0x09,0x00,0x00,0x06,0x3E,0x53,0x54,0x41,0x43,0x4B,0x00, +/* 0x00001360: */ 0x58,0x13,0x00,0x00,0x78,0x09,0x00,0x00,0x06,0x53,0x54,0x41,0x43,0x4B,0x3E,0x00, +/* 0x00001370: */ 0x68,0x13,0x00,0x00,0x9C,0x09,0x00,0x00,0x06,0x53,0x54,0x41,0x43,0x4B,0x40,0x00, +/* 0x00001380: */ 0x78,0x13,0x00,0x00,0xB4,0x09,0x00,0x00,0x0A,0x53,0x54,0x41,0x43,0x4B,0x2E,0x50, +/* 0x00001390: */ 0x49,0x43,0x4B,0x00,0x88,0x13,0x00,0x00,0xD8,0x09,0x00,0x00,0x06,0x53,0x54,0x41, +/* 0x000013A0: */ 0x43,0x4B,0x50,0x00,0x9C,0x13,0x00,0x00,0xE8,0x09,0x00,0x00,0x07,0x30,0x53,0x54, +/* 0x000013B0: */ 0x41,0x43,0x4B,0x50,0xAC,0x13,0x00,0x00,0xFC,0x09,0x00,0x00,0x06,0x55,0x53,0x54, +/* 0x000013C0: */ 0x41,0x43,0x4B,0x00,0xBC,0x13,0x00,0x00,0x94,0x0A,0x00,0x00,0x03,0x3E,0x55,0x53, +/* 0x000013D0: */ 0xCC,0x13,0x00,0x00,0xA0,0x0A,0x00,0x00,0x03,0x55,0x53,0x3E,0xD8,0x13,0x00,0x00, +/* 0x000013E0: */ 0xAC,0x0A,0x00,0x00,0x03,0x55,0x53,0x40,0xE4,0x13,0x00,0x00,0xB8,0x0A,0x00,0x00, +/* 0x000013F0: */ 0x04,0x30,0x55,0x53,0x50,0x00,0x00,0x00,0xF0,0x13,0x00,0x00,0xC4,0x0A,0x00,0x00, +/* 0x00001400: */ 0x07,0x44,0x4F,0x5F,0x46,0x4C,0x41,0x47,0x00,0x14,0x00,0x00,0xD4,0x0A,0x00,0x00, +/* 0x00001410: */ 0x0A,0x4C,0x45,0x41,0x56,0x45,0x5F,0x46,0x4C,0x41,0x47,0x00,0x10,0x14,0x00,0x00, +/* 0x00001420: */ 0xE4,0x0A,0x00,0x00,0x08,0x3F,0x44,0x4F,0x5F,0x46,0x4C,0x41,0x47,0x00,0x00,0x00, +/* 0x00001430: */ 0x24,0x14,0x00,0x00,0xF4,0x0A,0x00,0x00,0x42,0x44,0x4F,0x00,0x38,0x14,0x00,0x00, +/* 0x00001440: */ 0x18,0x0B,0x00,0x00,0x43,0x3F,0x44,0x4F,0x44,0x14,0x00,0x00,0x58,0x0B,0x00,0x00, +/* 0x00001450: */ 0x45,0x4C,0x45,0x41,0x56,0x45,0x00,0x00,0x50,0x14,0x00,0x00,0x84,0x0B,0x00,0x00, +/* 0x00001460: */ 0x0C,0x4C,0x4F,0x4F,0x50,0x2D,0x46,0x4F,0x52,0x57,0x41,0x52,0x44,0x00,0x00,0x00, +/* 0x00001470: */ 0x60,0x14,0x00,0x00,0x0C,0x0C,0x00,0x00,0x09,0x4C,0x4F,0x4F,0x50,0x2D,0x42,0x41, +/* 0x00001480: */ 0x43,0x4B,0x00,0x00,0x78,0x14,0x00,0x00,0x38,0x0C,0x00,0x00,0x44,0x4C,0x4F,0x4F, +/* 0x00001490: */ 0x50,0x00,0x00,0x00,0x8C,0x14,0x00,0x00,0x50,0x0C,0x00,0x00,0x45,0x2B,0x4C,0x4F, +/* 0x000014A0: */ 0x4F,0x50,0x00,0x00,0x9C,0x14,0x00,0x00,0x68,0x0C,0x00,0x00,0x06,0x55,0x4E,0x4C, +/* 0x000014B0: */ 0x4F,0x4F,0x50,0x00,0xAC,0x14,0x00,0x00,0x7C,0x0C,0x00,0x00,0x47,0x52,0x45,0x43, +/* 0x000014C0: */ 0x55,0x52,0x53,0x45,0xBC,0x14,0x00,0x00,0x8C,0x0C,0x00,0x00,0x05,0x53,0x50,0x41, +/* 0x000014D0: */ 0x43,0x45,0x00,0x00,0xCC,0x14,0x00,0x00,0x98,0x0C,0x00,0x00,0x06,0x53,0x50,0x41, +/* 0x000014E0: */ 0x43,0x45,0x53,0x00,0xDC,0x14,0x00,0x00,0xD0,0x0C,0x00,0x00,0x03,0x30,0x53,0x50, +/* 0x000014F0: */ 0xEC,0x14,0x00,0x00,0xF4,0x0C,0x00,0x00,0x08,0x3E,0x4E,0x45,0x57,0x4C,0x49,0x4E, +/* 0x00001500: */ 0x45,0x00,0x00,0x00,0xF8,0x14,0x00,0x00,0x10,0x0D,0x00,0x00,0x0B,0x43,0x48,0x45, +/* 0x00001510: */ 0x43,0x4B,0x2E,0x44,0x45,0x46,0x45,0x52,0x0C,0x15,0x00,0x00,0x38,0x0D,0x00,0x00, +/* 0x00001520: */ 0x03,0x3E,0x49,0x53,0x20,0x15,0x00,0x00,0x48,0x0D,0x00,0x00,0x04,0x28,0x49,0x53, +/* 0x00001530: */ 0x29,0x00,0x00,0x00,0x2C,0x15,0x00,0x00,0x54,0x0D,0x00,0x00,0x42,0x49,0x53,0x00, +/* 0x00001540: */ 0x3C,0x15,0x00,0x00,0x90,0x0D,0x00,0x00,0x08,0x28,0x57,0x48,0x41,0x54,0x27,0x53, +/* 0x00001550: */ 0x29,0x00,0x00,0x00,0x48,0x15,0x00,0x00,0x9C,0x0D,0x00,0x00,0x46,0x57,0x48,0x41, +/* 0x00001560: */ 0x54,0x27,0x53,0x00,0x5C,0x15,0x00,0x00,0xD8,0x0D,0x00,0x00,0x07,0x2F,0x53,0x54, +/* 0x00001570: */ 0x52,0x49,0x4E,0x47,0x6C,0x15,0x00,0x00,0xF8,0x0D,0x00,0x00,0x05,0x50,0x4C,0x41, +/* 0x00001580: */ 0x43,0x45,0x00,0x00,0x7C,0x15,0x00,0x00,0x14,0x0E,0x00,0x00,0x0A,0x50,0x41,0x52, +/* 0x00001590: */ 0x53,0x45,0x2D,0x57,0x4F,0x52,0x44,0x00,0x8C,0x15,0x00,0x00,0x74,0x0E,0x00,0x00, +/* 0x000015A0: */ 0x05,0x50,0x41,0x52,0x53,0x45,0x00,0x00,0xA0,0x15,0x00,0x00,0xC0,0x0E,0x00,0x00, +/* 0x000015B0: */ 0x05,0x4C,0x57,0x4F,0x52,0x44,0x00,0x00,0xB0,0x15,0x00,0x00,0xD4,0x0E,0x00,0x00, +/* 0x000015C0: */ 0x45,0x41,0x53,0x43,0x49,0x49,0x00,0x00,0xC0,0x15,0x00,0x00,0xFC,0x0E,0x00,0x00, +/* 0x000015D0: */ 0x04,0x43,0x48,0x41,0x52,0x00,0x00,0x00,0xD0,0x15,0x00,0x00,0x10,0x0F,0x00,0x00, +/* 0x000015E0: */ 0x46,0x5B,0x43,0x48,0x41,0x52,0x5D,0x00,0xE0,0x15,0x00,0x00,0x1C,0x0F,0x00,0x00, +/* 0x000015F0: */ 0x05,0x24,0x54,0x59,0x50,0x45,0x00,0x00,0xF0,0x15,0x00,0x00,0x28,0x0F,0x00,0x00, +/* 0x00001600: */ 0x05,0x27,0x57,0x4F,0x52,0x44,0x00,0x00,0x00,0x16,0x00,0x00,0x30,0x0F,0x00,0x00, +/* 0x00001610: */ 0x04,0x45,0x56,0x45,0x4E,0x00,0x00,0x00,0x10,0x16,0x00,0x00,0x48,0x0F,0x00,0x00, +/* 0x00001620: */ 0x04,0x28,0x43,0x22,0x29,0x00,0x00,0x00,0x20,0x16,0x00,0x00,0x64,0x0F,0x00,0x00, +/* 0x00001630: */ 0x04,0x28,0x53,0x22,0x29,0x00,0x00,0x00,0x30,0x16,0x00,0x00,0x80,0x0F,0x00,0x00, +/* 0x00001640: */ 0x04,0x28,0x2E,0x22,0x29,0x00,0x00,0x00,0x40,0x16,0x00,0x00,0xA0,0x0F,0x00,0x00, +/* 0x00001650: */ 0x02,0x22,0x2C,0x00,0x50,0x16,0x00,0x00,0xBC,0x0F,0x00,0x00,0x02,0x2C,0x22,0x00, +/* 0x00001660: */ 0x5C,0x16,0x00,0x00,0xD0,0x0F,0x00,0x00,0x42,0x2E,0x28,0x00,0x68,0x16,0x00,0x00, +/* 0x00001670: */ 0xE4,0x0F,0x00,0x00,0x42,0x2E,0x22,0x00,0x74,0x16,0x00,0x00,0x20,0x10,0x00,0x00, +/* 0x00001680: */ 0x42,0x2E,0x27,0x00,0x80,0x16,0x00,0x00,0x68,0x10,0x00,0x00,0x42,0x43,0x22,0x00, +/* 0x00001690: */ 0x8C,0x16,0x00,0x00,0xAC,0x10,0x00,0x00,0x42,0x53,0x22,0x00,0x98,0x16,0x00,0x00, +/* 0x000016A0: */ 0xF4,0x10,0x00,0x00,0x41,0x22,0x00,0x00,0xA4,0x16,0x00,0x00,0xFC,0x10,0x00,0x00, +/* 0x000016B0: */ 0x42,0x50,0x22,0x00,0xB0,0x16,0x00,0x00,0x04,0x11,0x00,0x00,0x42,0x22,0x22,0x00, +/* 0x000016C0: */ 0xBC,0x16,0x00,0x00,0x4C,0x11,0x00,0x00,0x48,0x53,0x4C,0x49,0x54,0x45,0x52,0x41, +/* 0x000016D0: */ 0x4C,0x00,0x00,0x00,0xC8,0x16,0x00,0x00,0x60,0x11,0x00,0x00,0x07,0x24,0x41,0x50, +/* 0x000016E0: */ 0x50,0x45,0x4E,0x44,0xDC,0x16,0x00,0x00,0xA0,0x11,0x00,0x00,0x48,0x50,0x4F,0x53, +/* 0x000016F0: */ 0x54,0x50,0x4F,0x4E,0x45,0x00,0x00,0x00,0xEC,0x16,0x00,0x00,0x14,0x12,0x00,0x00, +/* 0x00001700: */ 0x09,0x41,0x55,0x54,0x4F,0x2E,0x49,0x4E,0x49,0x54,0x00,0x00,0x00,0x17,0x00,0x00, +/* 0x00001710: */ 0x18,0x12,0x00,0x00,0x09,0x41,0x55,0x54,0x4F,0x2E,0x54,0x45,0x52,0x4D,0x00,0x00, +/* 0x00001720: */ 0x14,0x17,0x00,0x00,0x1C,0x12,0x00,0x00,0x0D,0x54,0x52,0x41,0x43,0x45,0x2D,0x49, +/* 0x00001730: */ 0x4E,0x43,0x4C,0x55,0x44,0x45,0x00,0x00,0x28,0x17,0x00,0x00,0x2C,0x12,0x00,0x00, +/* 0x00001740: */ 0x12,0x49,0x4E,0x43,0x4C,0x55,0x44,0x45,0x2E,0x4D,0x41,0x52,0x4B,0x2E,0x53,0x54, +/* 0x00001750: */ 0x41,0x52,0x54,0x00,0x40,0x17,0x00,0x00,0x60,0x12,0x00,0x00,0x10,0x49,0x4E,0x43, +/* 0x00001760: */ 0x4C,0x55,0x44,0x45,0x2E,0x4D,0x41,0x52,0x4B,0x2E,0x45,0x4E,0x44,0x00,0x00,0x00, +/* 0x00001770: */ 0x5C,0x17,0x00,0x00,0x7C,0x12,0x00,0x00,0x08,0x24,0x49,0x4E,0x43,0x4C,0x55,0x44, +/* 0x00001780: */ 0x45,0x00,0x00,0x00,0x78,0x17,0x00,0x00,0xE4,0x13,0x00,0x00,0x11,0x49,0x4E,0x43, +/* 0x00001790: */ 0x4C,0x55,0x44,0x45,0x2D,0x53,0x41,0x56,0x45,0x2D,0x4E,0x41,0x4D,0x45,0x00,0x00, +/* 0x000017A0: */ 0x8C,0x17,0x00,0x00,0x70,0x14,0x00,0x00,0x07,0x49,0x4E,0x43,0x4C,0x55,0x44,0x45, +/* 0x000017B0: */ 0xA8,0x17,0x00,0x00,0x8C,0x14,0x00,0x00,0x02,0x52,0x49,0x00,0xB8,0x17,0x00,0x00, +/* 0x000017C0: */ 0x98,0x14,0x00,0x00,0x08,0x49,0x4E,0x43,0x4C,0x55,0x44,0x45,0x3F,0x00,0x00,0x00, +/* 0x000017D0: */ 0xC4,0x17,0x00,0x00,0xD0,0x14,0x00,0x00,0x0C,0x48,0x45,0x41,0x44,0x45,0x52,0x53, +/* 0x000017E0: */ 0x2D,0x53,0x49,0x5A,0x45,0x00,0x00,0x00,0xD8,0x17,0x00,0x00,0xE0,0x14,0x00,0x00, +/* 0x000017F0: */ 0x09,0x43,0x4F,0x44,0x45,0x2D,0x53,0x49,0x5A,0x45,0x00,0x00,0xF0,0x17,0x00,0x00, +/* 0x00001800: */ 0xF0,0x14,0x00,0x00,0x09,0x41,0x55,0x54,0x4F,0x2E,0x49,0x4E,0x49,0x54,0x00,0x00, +/* 0x00001810: */ 0x04,0x18,0x00,0x00,0x20,0x15,0x00,0x00,0x0A,0x53,0x41,0x56,0x45,0x2D,0x46,0x4F, +/* 0x00001820: */ 0x52,0x54,0x48,0x00,0x18,0x18,0x00,0x00,0xA4,0x15,0x00,0x00,0x07,0x54,0x55,0x52, +/* 0x00001830: */ 0x4E,0x4B,0x45,0x59,0x2C,0x18,0x00,0x00,0x78,0x00,0x00,0x00,0x10,0x3A,0x3A,0x3A, +/* 0x00001840: */ 0x3A,0x6C,0x6F,0x61,0x64,0x70,0x34,0x74,0x68,0x2E,0x66,0x74,0x68,0x00,0x00,0x00, +/* 0x00001850: */ 0x3C,0x18,0x00,0x00,0x78,0x00,0x00,0x00,0x0E,0x3A,0x3A,0x3A,0x3A,0x66,0x6F,0x72, +/* 0x00001860: */ 0x67,0x65,0x74,0x2E,0x66,0x74,0x68,0x00,0x58,0x18,0x00,0x00,0xF0,0x15,0x00,0x00, +/* 0x00001870: */ 0x06,0x52,0x46,0x45,0x4E,0x43,0x45,0x00,0x70,0x18,0x00,0x00,0x00,0x16,0x00,0x00, +/* 0x00001880: */ 0x06,0x46,0x52,0x45,0x45,0x5A,0x45,0x00,0x80,0x18,0x00,0x00,0x10,0x16,0x00,0x00, +/* 0x00001890: */ 0x0A,0x46,0x4F,0x52,0x47,0x45,0x54,0x2E,0x4E,0x46,0x41,0x00,0x90,0x18,0x00,0x00, +/* 0x000018A0: */ 0x44,0x16,0x00,0x00,0x0D,0x56,0x45,0x52,0x49,0x46,0x59,0x2E,0x46,0x4F,0x52,0x47, +/* 0x000018B0: */ 0x45,0x54,0x00,0x00,0xA4,0x18,0x00,0x00,0xA0,0x16,0x00,0x00,0x08,0x28,0x46,0x4F, +/* 0x000018C0: */ 0x52,0x47,0x45,0x54,0x29,0x00,0x00,0x00,0xBC,0x18,0x00,0x00,0xF0,0x16,0x00,0x00, +/* 0x000018D0: */ 0x0B,0x4C,0x41,0x53,0x54,0x2D,0x46,0x4F,0x52,0x47,0x45,0x54,0xD0,0x18,0x00,0x00, +/* 0x000018E0: */ 0x00,0x17,0x00,0x00,0x0C,0x49,0x46,0x2E,0x46,0x4F,0x52,0x47,0x4F,0x54,0x54,0x45, +/* 0x000018F0: */ 0x4E,0x00,0x00,0x00,0xE4,0x18,0x00,0x00,0x8C,0x17,0x00,0x00,0x08,0x5B,0x46,0x4F, +/* 0x00001900: */ 0x52,0x47,0x45,0x54,0x5D,0x00,0x00,0x00,0xFC,0x18,0x00,0x00,0x04,0x18,0x00,0x00, +/* 0x00001910: */ 0x06,0x46,0x4F,0x52,0x47,0x45,0x54,0x00,0x10,0x19,0x00,0x00,0x5C,0x18,0x00,0x00, +/* 0x00001920: */ 0x04,0x41,0x4E,0x45,0x57,0x00,0x00,0x00,0x20,0x19,0x00,0x00,0x9C,0x18,0x00,0x00, +/* 0x00001930: */ 0x06,0x4D,0x41,0x52,0x4B,0x45,0x52,0x00,0x30,0x19,0x00,0x00,0x78,0x00,0x00,0x00, +/* 0x00001940: */ 0x04,0x3B,0x3B,0x3B,0x3B,0x00,0x00,0x00,0x40,0x19,0x00,0x00,0x78,0x00,0x00,0x00, +/* 0x00001950: */ 0x10,0x3A,0x3A,0x3A,0x3A,0x6E,0x75,0x6D,0x62,0x65,0x72,0x69,0x6F,0x2E,0x66,0x74, +/* 0x00001960: */ 0x68,0x00,0x00,0x00,0x50,0x19,0x00,0x00,0xD4,0x18,0x00,0x00,0x11,0x54,0x41,0x53, +/* 0x00001970: */ 0x4B,0x2D,0x4E,0x55,0x4D,0x42,0x45,0x52,0x49,0x4F,0x2E,0x46,0x54,0x48,0x00,0x00, +/* 0x00001980: */ 0x6C,0x19,0x00,0x00,0xE4,0x18,0x00,0x00,0x05,0x44,0x49,0x47,0x49,0x54,0x00,0x00, +/* 0x00001990: */ 0x88,0x19,0x00,0x00,0xE4,0x19,0x00,0x00,0x07,0x3E,0x4E,0x55,0x4D,0x42,0x45,0x52, +/* 0x000019A0: */ 0x98,0x19,0x00,0x00,0x90,0x1A,0x00,0x00,0x07,0x43,0x4F,0x4E,0x56,0x45,0x52,0x54, +/* 0x000019B0: */ 0xA8,0x19,0x00,0x00,0xA4,0x1A,0x00,0x00,0x0C,0x4E,0x55,0x4D,0x5F,0x54,0x59,0x50, +/* 0x000019C0: */ 0x45,0x5F,0x42,0x41,0x44,0x00,0x00,0x00,0xB8,0x19,0x00,0x00,0xB4,0x1A,0x00,0x00, +/* 0x000019D0: */ 0x0F,0x4E,0x55,0x4D,0x5F,0x54,0x59,0x50,0x45,0x5F,0x53,0x49,0x4E,0x47,0x4C,0x45, +/* 0x000019E0: */ 0xD0,0x19,0x00,0x00,0xC4,0x1A,0x00,0x00,0x0F,0x4E,0x55,0x4D,0x5F,0x54,0x59,0x50, +/* 0x000019F0: */ 0x45,0x5F,0x44,0x4F,0x55,0x42,0x4C,0x45,0xE8,0x19,0x00,0x00,0xD4,0x1A,0x00,0x00, +/* 0x00001A00: */ 0x0B,0x28,0x28,0x4E,0x55,0x4D,0x42,0x45,0x52,0x3F,0x29,0x29,0x00,0x1A,0x00,0x00, +/* 0x00001A10: */ 0xC8,0x1B,0x00,0x00,0x09,0x28,0x4E,0x55,0x4D,0x42,0x45,0x52,0x3F,0x29,0x00,0x00, +/* 0x00001A20: */ 0x14,0x1A,0x00,0x00,0xD4,0x1B,0x00,0x00,0x03,0x48,0x4C,0x44,0x28,0x1A,0x00,0x00, +/* 0x00001A30: */ 0xE4,0x1B,0x00,0x00,0x04,0x48,0x4F,0x4C,0x44,0x00,0x00,0x00,0x34,0x1A,0x00,0x00, +/* 0x00001A40: */ 0x00,0x1C,0x00,0x00,0x02,0x3C,0x23,0x00,0x44,0x1A,0x00,0x00,0x10,0x1C,0x00,0x00, +/* 0x00001A50: */ 0x02,0x23,0x3E,0x00,0x50,0x1A,0x00,0x00,0x2C,0x1C,0x00,0x00,0x04,0x53,0x49,0x47, +/* 0x00001A60: */ 0x4E,0x00,0x00,0x00,0x5C,0x1A,0x00,0x00,0x48,0x1C,0x00,0x00,0x01,0x23,0x00,0x00, +/* 0x00001A70: */ 0x6C,0x1A,0x00,0x00,0x90,0x1C,0x00,0x00,0x02,0x23,0x53,0x00,0x78,0x1A,0x00,0x00, +/* 0x00001A80: */ 0xAC,0x1C,0x00,0x00,0x05,0x28,0x55,0x44,0x2E,0x29,0x00,0x00,0x84,0x1A,0x00,0x00, +/* 0x00001A90: */ 0xBC,0x1C,0x00,0x00,0x03,0x55,0x44,0x2E,0x94,0x1A,0x00,0x00,0xCC,0x1C,0x00,0x00, +/* 0x00001AA0: */ 0x04,0x55,0x44,0x2E,0x52,0x00,0x00,0x00,0xA0,0x1A,0x00,0x00,0xEC,0x1C,0x00,0x00, +/* 0x00001AB0: */ 0x04,0x28,0x44,0x2E,0x29,0x00,0x00,0x00,0xB0,0x1A,0x00,0x00,0x0C,0x1D,0x00,0x00, +/* 0x00001AC0: */ 0x02,0x44,0x2E,0x00,0xC0,0x1A,0x00,0x00,0x1C,0x1D,0x00,0x00,0x03,0x44,0x2E,0x52, +/* 0x00001AD0: */ 0xCC,0x1A,0x00,0x00,0x3C,0x1D,0x00,0x00,0x04,0x28,0x55,0x2E,0x29,0x00,0x00,0x00, +/* 0x00001AE0: */ 0xD8,0x1A,0x00,0x00,0x4C,0x1D,0x00,0x00,0x02,0x55,0x2E,0x00,0xE8,0x1A,0x00,0x00, +/* 0x00001AF0: */ 0x5C,0x1D,0x00,0x00,0x03,0x55,0x2E,0x52,0xF4,0x1A,0x00,0x00,0x7C,0x1D,0x00,0x00, +/* 0x00001B00: */ 0x03,0x28,0x2E,0x29,0x00,0x1B,0x00,0x00,0xA4,0x1D,0x00,0x00,0x01,0x2E,0x00,0x00, +/* 0x00001B10: */ 0x0C,0x1B,0x00,0x00,0xB4,0x1D,0x00,0x00,0x02,0x2E,0x52,0x00,0x18,0x1B,0x00,0x00, +/* 0x00001B20: */ 0x78,0x00,0x00,0x00,0x04,0x3B,0x3B,0x3B,0x3B,0x00,0x00,0x00,0x24,0x1B,0x00,0x00, +/* 0x00001B30: */ 0x78,0x00,0x00,0x00,0x0D,0x3A,0x3A,0x3A,0x3A,0x6D,0x69,0x73,0x63,0x31,0x2E,0x66, +/* 0x00001B40: */ 0x74,0x68,0x00,0x00,0x34,0x1B,0x00,0x00,0xD4,0x1D,0x00,0x00,0x0E,0x54,0x41,0x53, +/* 0x00001B50: */ 0x4B,0x2D,0x4D,0x49,0x53,0x43,0x31,0x2E,0x46,0x54,0x48,0x00,0x4C,0x1B,0x00,0x00, +/* 0x00001B60: */ 0xE4,0x1D,0x00,0x00,0x02,0x3E,0x3E,0x00,0x64,0x1B,0x00,0x00,0xEC,0x1D,0x00,0x00, +/* 0x00001B70: */ 0x02,0x3C,0x3C,0x00,0x70,0x1B,0x00,0x00,0xF4,0x1D,0x00,0x00,0x0A,0x28,0x57,0x41, +/* 0x00001B80: */ 0x52,0x4E,0x49,0x4E,0x47,0x22,0x29,0x00,0x7C,0x1B,0x00,0x00,0x18,0x1E,0x00,0x00, +/* 0x00001B90: */ 0x48,0x57,0x41,0x52,0x4E,0x49,0x4E,0x47,0x22,0x00,0x00,0x00,0x90,0x1B,0x00,0x00, +/* 0x00001BA0: */ 0x48,0x1E,0x00,0x00,0x08,0x28,0x41,0x42,0x4F,0x52,0x54,0x22,0x29,0x00,0x00,0x00, +/* 0x00001BB0: */ 0xA4,0x1B,0x00,0x00,0x74,0x1E,0x00,0x00,0x46,0x41,0x42,0x4F,0x52,0x54,0x22,0x00, +/* 0x00001BC0: */ 0xB8,0x1B,0x00,0x00,0xA4,0x1E,0x00,0x00,0x06,0x3F,0x50,0x41,0x55,0x53,0x45,0x00, +/* 0x00001BD0: */ 0xC8,0x1B,0x00,0x00,0x20,0x1F,0x00,0x00,0x05,0x23,0x43,0x4F,0x4C,0x53,0x00,0x00, +/* 0x00001BE0: */ 0xD8,0x1B,0x00,0x00,0x30,0x1F,0x00,0x00,0x03,0x43,0x52,0x3F,0xE8,0x1B,0x00,0x00, +/* 0x00001BF0: */ 0x68,0x1F,0x00,0x00,0x03,0x43,0x4C,0x53,0xF4,0x1B,0x00,0x00,0x8C,0x1F,0x00,0x00, +/* 0x00001C00: */ 0x04,0x50,0x41,0x47,0x45,0x00,0x00,0x00,0x00,0x1C,0x00,0x00,0x94,0x1F,0x00,0x00, +/* 0x00001C10: */ 0x41,0x24,0x00,0x00,0x10,0x1C,0x00,0x00,0x00,0x20,0x00,0x00,0x03,0x2E,0x48,0x58, +/* 0x00001C20: */ 0x1C,0x1C,0x00,0x00,0x3C,0x20,0x00,0x00,0x09,0x54,0x41,0x42,0x2D,0x57,0x49,0x44, +/* 0x00001C30: */ 0x54,0x48,0x00,0x00,0x28,0x1C,0x00,0x00,0x4C,0x20,0x00,0x00,0x03,0x54,0x41,0x42, +/* 0x00001C40: */ 0x3C,0x1C,0x00,0x00,0x78,0x20,0x00,0x00,0x05,0x57,0x4F,0x52,0x44,0x53,0x00,0x00, +/* 0x00001C50: */ 0x48,0x1C,0x00,0x00,0xE0,0x20,0x00,0x00,0x05,0x56,0x4C,0x49,0x53,0x54,0x00,0x00, +/* 0x00001C60: */ 0x58,0x1C,0x00,0x00,0xE8,0x20,0x00,0x00,0x0B,0x43,0x4C,0x4F,0x53,0x45,0x53,0x54, +/* 0x00001C70: */ 0x2D,0x4E,0x46,0x41,0x68,0x1C,0x00,0x00,0xF8,0x20,0x00,0x00,0x0A,0x43,0x4C,0x4F, +/* 0x00001C80: */ 0x53,0x45,0x53,0x54,0x2D,0x58,0x54,0x00,0x7C,0x1C,0x00,0x00,0x08,0x21,0x00,0x00, +/* 0x00001C90: */ 0x05,0x3E,0x4E,0x41,0x4D,0x45,0x00,0x00,0x90,0x1C,0x00,0x00,0xF4,0x21,0x00,0x00, +/* 0x00001CA0: */ 0x08,0x40,0x45,0x58,0x45,0x43,0x55,0x54,0x45,0x00,0x00,0x00,0xA0,0x1C,0x00,0x00, +/* 0x00001CB0: */ 0x0C,0x22,0x00,0x00,0x07,0x54,0x4F,0x4C,0x4F,0x57,0x45,0x52,0xB4,0x1C,0x00,0x00, +/* 0x00001CC0: */ 0x58,0x22,0x00,0x00,0x08,0x45,0x56,0x41,0x4C,0x55,0x41,0x54,0x45,0x00,0x00,0x00, +/* 0x00001CD0: */ 0xC4,0x1C,0x00,0x00,0xB4,0x22,0x00,0x00,0x02,0x5C,0x53,0x00,0xD8,0x1C,0x00,0x00, +/* 0x00001CE0: */ 0x78,0x00,0x00,0x00,0x04,0x3B,0x3B,0x3B,0x3B,0x00,0x00,0x00,0xE4,0x1C,0x00,0x00, +/* 0x00001CF0: */ 0x78,0x00,0x00,0x00,0x0C,0x3A,0x3A,0x3A,0x3A,0x63,0x61,0x73,0x65,0x2E,0x66,0x74, +/* 0x00001D00: */ 0x68,0x00,0x00,0x00,0xF4,0x1C,0x00,0x00,0xD4,0x22,0x00,0x00,0x09,0x54,0x41,0x53, +/* 0x00001D10: */ 0x4B,0x2D,0x43,0x41,0x53,0x45,0x00,0x00,0x0C,0x1D,0x00,0x00,0xE4,0x22,0x00,0x00, +/* 0x00001D20: */ 0x0A,0x43,0x41,0x53,0x45,0x2D,0x44,0x45,0x50,0x54,0x48,0x00,0x20,0x1D,0x00,0x00, +/* 0x00001D30: */ 0xF4,0x22,0x00,0x00,0x08,0x4F,0x46,0x2D,0x44,0x45,0x50,0x54,0x48,0x00,0x00,0x00, +/* 0x00001D40: */ 0x34,0x1D,0x00,0x00,0x04,0x23,0x00,0x00,0x44,0x43,0x41,0x53,0x45,0x00,0x00,0x00, +/* 0x00001D50: */ 0x48,0x1D,0x00,0x00,0x3C,0x23,0x00,0x00,0x43,0x3F,0x4F,0x46,0x58,0x1D,0x00,0x00, +/* 0x00001D60: */ 0x70,0x23,0x00,0x00,0x42,0x4F,0x46,0x00,0x64,0x1D,0x00,0x00,0x94,0x23,0x00,0x00, +/* 0x00001D70: */ 0x0A,0x28,0x52,0x41,0x4E,0x47,0x45,0x4F,0x46,0x3F,0x29,0x00,0x70,0x1D,0x00,0x00, +/* 0x00001D80: */ 0xC8,0x23,0x00,0x00,0x47,0x52,0x41,0x4E,0x47,0x45,0x4F,0x46,0x84,0x1D,0x00,0x00, +/* 0x00001D90: */ 0xDC,0x23,0x00,0x00,0x45,0x45,0x4E,0x44,0x4F,0x46,0x00,0x00,0x94,0x1D,0x00,0x00, +/* 0x00001DA0: */ 0xF0,0x23,0x00,0x00,0x47,0x45,0x4E,0x44,0x43,0x41,0x53,0x45,0xA4,0x1D,0x00,0x00, +/* 0x00001DB0: */ 0x78,0x00,0x00,0x00,0x04,0x3B,0x3B,0x3B,0x3B,0x00,0x00,0x00,0xB4,0x1D,0x00,0x00, +/* 0x00001DC0: */ 0x78,0x00,0x00,0x00,0x0F,0x3A,0x3A,0x3A,0x3A,0x73,0x74,0x72,0x69,0x6E,0x67,0x73, +/* 0x00001DD0: */ 0x2E,0x66,0x74,0x68,0xC4,0x1D,0x00,0x00,0x6C,0x24,0x00,0x00,0x10,0x54,0x41,0x53, +/* 0x00001DE0: */ 0x4B,0x2D,0x53,0x54,0x52,0x49,0x4E,0x47,0x53,0x2E,0x46,0x54,0x48,0x00,0x00,0x00, +/* 0x00001DF0: */ 0xDC,0x1D,0x00,0x00,0x7C,0x24,0x00,0x00,0x09,0x2D,0x54,0x52,0x41,0x49,0x4C,0x49, +/* 0x00001E00: */ 0x4E,0x47,0x00,0x00,0xF8,0x1D,0x00,0x00,0xC8,0x24,0x00,0x00,0x06,0x24,0x41,0x52, +/* 0x00001E10: */ 0x52,0x41,0x59,0x00,0x0C,0x1E,0x00,0x00,0x10,0x25,0x00,0x00,0x02,0x24,0x3D,0x00, +/* 0x00001E20: */ 0x1C,0x1E,0x00,0x00,0x98,0x25,0x00,0x00,0x05,0x54,0x45,0x58,0x54,0x3D,0x00,0x00, +/* 0x00001E30: */ 0x28,0x1E,0x00,0x00,0x1C,0x26,0x00,0x00,0x06,0x54,0x45,0x58,0x54,0x3D,0x3F,0x00, +/* 0x00001E40: */ 0x38,0x1E,0x00,0x00,0x28,0x26,0x00,0x00,0x07,0x24,0x4D,0x41,0x54,0x43,0x48,0x3F, +/* 0x00001E50: */ 0x48,0x1E,0x00,0x00,0x3C,0x26,0x00,0x00,0x05,0x49,0x4E,0x44,0x45,0x58,0x00,0x00, +/* 0x00001E60: */ 0x58,0x1E,0x00,0x00,0xCC,0x26,0x00,0x00,0x0C,0x24,0x41,0x50,0x50,0x45,0x4E,0x44, +/* 0x00001E70: */ 0x2E,0x43,0x48,0x41,0x52,0x00,0x00,0x00,0x68,0x1E,0x00,0x00,0xF4,0x26,0x00,0x00, +/* 0x00001E80: */ 0x06,0x28,0x24,0x52,0x4F,0x4D,0x29,0x00,0x80,0x1E,0x00,0x00,0x24,0x27,0x00,0x00, +/* 0x00001E90: */ 0x04,0x24,0x52,0x4F,0x4D,0x00,0x00,0x00,0x90,0x1E,0x00,0x00,0x40,0x27,0x00,0x00, +/* 0x00001EA0: */ 0x07,0x54,0x45,0x58,0x54,0x52,0x4F,0x4D,0xA0,0x1E,0x00,0x00,0x78,0x00,0x00,0x00, +/* 0x00001EB0: */ 0x04,0x3B,0x3B,0x3B,0x3B,0x00,0x00,0x00,0xB0,0x1E,0x00,0x00,0x78,0x00,0x00,0x00, +/* 0x00001EC0: */ 0x0F,0x3A,0x3A,0x3A,0x3A,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x2E,0x66,0x74,0x68, +/* 0x00001ED0: */ 0xC0,0x1E,0x00,0x00,0x60,0x27,0x00,0x00,0x10,0x54,0x41,0x53,0x4B,0x2D,0x50,0x52, +/* 0x00001EE0: */ 0x49,0x56,0x41,0x54,0x45,0x2E,0x46,0x54,0x48,0x00,0x00,0x00,0xD8,0x1E,0x00,0x00, +/* 0x00001EF0: */ 0x70,0x27,0x00,0x00,0x0D,0x50,0x52,0x49,0x56,0x41,0x54,0x45,0x2D,0x53,0x54,0x41, +/* 0x00001F00: */ 0x52,0x54,0x00,0x00,0xF4,0x1E,0x00,0x00,0x80,0x27,0x00,0x00,0x0C,0x50,0x52,0x49, +/* 0x00001F10: */ 0x56,0x41,0x54,0x45,0x2D,0x53,0x54,0x4F,0x50,0x00,0x00,0x00,0x0C,0x1F,0x00,0x00, +/* 0x00001F20: */ 0x90,0x27,0x00,0x00,0x0B,0x46,0x4C,0x41,0x47,0x5F,0x53,0x4D,0x55,0x44,0x47,0x45, +/* 0x00001F30: */ 0x24,0x1F,0x00,0x00,0xA0,0x27,0x00,0x00,0x08,0x50,0x52,0x49,0x56,0x41,0x54,0x45, +/* 0x00001F40: */ 0x7B,0x00,0x00,0x00,0x38,0x1F,0x00,0x00,0xC0,0x27,0x00,0x00,0x08,0x7D,0x50,0x52, +/* 0x00001F50: */ 0x49,0x56,0x41,0x54,0x45,0x00,0x00,0x00,0x4C,0x1F,0x00,0x00,0xF8,0x27,0x00,0x00, +/* 0x00001F60: */ 0x09,0x50,0x52,0x49,0x56,0x41,0x54,0x49,0x5A,0x45,0x00,0x00,0x60,0x1F,0x00,0x00, +/* 0x00001F70: */ 0x78,0x00,0x00,0x00,0x04,0x3B,0x3B,0x3B,0x3B,0x00,0x00,0x00,0x74,0x1F,0x00,0x00, +/* 0x00001F80: */ 0x78,0x00,0x00,0x00,0x10,0x3A,0x3A,0x3A,0x3A,0x61,0x6E,0x73,0x69,0x6C,0x6F,0x63, +/* 0x00001F90: */ 0x73,0x2E,0x66,0x74,0x68,0x00,0x00,0x00,0x84,0x1F,0x00,0x00,0xB4,0x28,0x00,0x00, +/* 0x00001FA0: */ 0x11,0x54,0x41,0x53,0x4B,0x2D,0x41,0x4E,0x53,0x49,0x4C,0x4F,0x43,0x53,0x2E,0x46, +/* 0x00001FB0: */ 0x54,0x48,0x00,0x00,0xA0,0x1F,0x00,0x00,0xC4,0x28,0x00,0x00,0x2B,0x4C,0x56,0x5F, +/* 0x00001FC0: */ 0x4D,0x41,0x58,0x5F,0x56,0x41,0x52,0x53,0xBC,0x1F,0x00,0x00,0xD4,0x28,0x00,0x00, +/* 0x00001FD0: */ 0x2C,0x4C,0x56,0x5F,0x4D,0x41,0x58,0x5F,0x43,0x48,0x41,0x52,0x53,0x00,0x00,0x00, +/* 0x00001FE0: */ 0xD0,0x1F,0x00,0x00,0xE4,0x28,0x00,0x00,0x28,0x4C,0x56,0x2D,0x4E,0x41,0x4D,0x45, +/* 0x00001FF0: */ 0x53,0x00,0x00,0x00,0xE8,0x1F,0x00,0x00,0x04,0x2B,0x00,0x00,0x29,0x4C,0x56,0x2D, +/* 0x00002000: */ 0x23,0x4E,0x41,0x4D,0x45,0x53,0x00,0x00,0xFC,0x1F,0x00,0x00,0x14,0x2B,0x00,0x00, +/* 0x00002010: */ 0x28,0x4C,0x56,0x2E,0x4D,0x41,0x54,0x43,0x48,0x00,0x00,0x00,0x10,0x20,0x00,0x00, +/* 0x00002020: */ 0x74,0x2B,0x00,0x00,0x30,0x4C,0x56,0x2E,0x43,0x4F,0x4D,0x50,0x49,0x4C,0x45,0x2E, +/* 0x00002030: */ 0x46,0x45,0x54,0x43,0x48,0x00,0x00,0x00,0x24,0x20,0x00,0x00,0x14,0x2D,0x00,0x00, +/* 0x00002040: */ 0x30,0x4C,0x56,0x2E,0x43,0x4F,0x4D,0x50,0x49,0x4C,0x45,0x2E,0x53,0x54,0x4F,0x52, +/* 0x00002050: */ 0x45,0x00,0x00,0x00,0x40,0x20,0x00,0x00,0xB4,0x2E,0x00,0x00,0x30,0x4C,0x56,0x2E, +/* 0x00002060: */ 0x43,0x4F,0x4D,0x50,0x49,0x4C,0x45,0x2E,0x4C,0x4F,0x43,0x41,0x4C,0x00,0x00,0x00, +/* 0x00002070: */ 0x5C,0x20,0x00,0x00,0xDC,0x2E,0x00,0x00,0x2A,0x4C,0x56,0x2E,0x43,0x4C,0x45,0x41, +/* 0x00002080: */ 0x4E,0x55,0x50,0x00,0x78,0x20,0x00,0x00,0xFC,0x2E,0x00,0x00,0x29,0x4C,0x56,0x2E, +/* 0x00002090: */ 0x46,0x49,0x4E,0x49,0x53,0x48,0x00,0x00,0x8C,0x20,0x00,0x00,0x14,0x2F,0x00,0x00, +/* 0x000020A0: */ 0x28,0x4C,0x56,0x2E,0x53,0x45,0x54,0x55,0x50,0x00,0x00,0x00,0xA0,0x20,0x00,0x00, +/* 0x000020B0: */ 0x28,0x2F,0x00,0x00,0x27,0x4C,0x56,0x2E,0x54,0x45,0x52,0x4D,0xB4,0x20,0x00,0x00, +/* 0x000020C0: */ 0x60,0x2F,0x00,0x00,0x07,0x28,0x4C,0x4F,0x43,0x41,0x4C,0x29,0xC4,0x20,0x00,0x00, +/* 0x000020D0: */ 0xC0,0x30,0x00,0x00,0x05,0x56,0x41,0x4C,0x55,0x45,0x00,0x00,0xD4,0x20,0x00,0x00, +/* 0x000020E0: */ 0x0C,0x31,0x00,0x00,0x42,0x54,0x4F,0x00,0xE4,0x20,0x00,0x00,0xA4,0x31,0x00,0x00, +/* 0x000020F0: */ 0x42,0x2D,0x3E,0x00,0xF0,0x20,0x00,0x00,0xAC,0x31,0x00,0x00,0x43,0x2B,0x2D,0x3E, +/* 0x00002100: */ 0xFC,0x20,0x00,0x00,0x50,0x32,0x00,0x00,0x01,0x3A,0x00,0x00,0x08,0x21,0x00,0x00, +/* 0x00002110: */ 0x5C,0x32,0x00,0x00,0x41,0x3B,0x00,0x00,0x14,0x21,0x00,0x00,0x68,0x32,0x00,0x00, +/* 0x00002120: */ 0x44,0x45,0x58,0x49,0x54,0x00,0x00,0x00,0x20,0x21,0x00,0x00,0x7C,0x32,0x00,0x00, +/* 0x00002130: */ 0x45,0x44,0x4F,0x45,0x53,0x3E,0x00,0x00,0x30,0x21,0x00,0x00,0x78,0x00,0x00,0x00, +/* 0x00002140: */ 0x04,0x3B,0x3B,0x3B,0x3B,0x00,0x00,0x00,0x40,0x21,0x00,0x00,0x78,0x00,0x00,0x00, +/* 0x00002150: */ 0x0E,0x3A,0x3A,0x3A,0x3A,0x6C,0x6F,0x63,0x61,0x6C,0x73,0x2E,0x66,0x74,0x68,0x00, +/* 0x00002160: */ 0x50,0x21,0x00,0x00,0x88,0x32,0x00,0x00,0x0F,0x54,0x41,0x53,0x4B,0x2D,0x4C,0x4F, +/* 0x00002170: */ 0x43,0x41,0x4C,0x53,0x2E,0x46,0x54,0x48,0x68,0x21,0x00,0x00,0x98,0x32,0x00,0x00, +/* 0x00002180: */ 0x2D,0x4C,0x4F,0x43,0x2D,0x54,0x45,0x4D,0x50,0x2D,0x4D,0x4F,0x44,0x45,0x00,0x00, +/* 0x00002190: */ 0x80,0x21,0x00,0x00,0xA8,0x32,0x00,0x00,0x30,0x4C,0x4F,0x43,0x2D,0x43,0x4F,0x4D, +/* 0x000021A0: */ 0x4D,0x45,0x4E,0x54,0x2D,0x4D,0x4F,0x44,0x45,0x00,0x00,0x00,0x98,0x21,0x00,0x00, +/* 0x000021B0: */ 0xB8,0x32,0x00,0x00,0x28,0x4C,0x4F,0x43,0x2D,0x44,0x4F,0x4E,0x45,0x00,0x00,0x00, +/* 0x000021C0: */ 0xB4,0x21,0x00,0x00,0xC8,0x32,0x00,0x00,0x41,0x7B,0x00,0x00,0xC8,0x21,0x00,0x00, +/* 0x000021D0: */ 0xC0,0x34,0x00,0x00,0x04,0x54,0x4C,0x56,0x31,0x00,0x00,0x00,0xD4,0x21,0x00,0x00, +/* 0x000021E0: */ 0xF0,0x34,0x00,0x00,0x04,0x54,0x4C,0x56,0x32,0x00,0x00,0x00,0xE4,0x21,0x00,0x00, +/* 0x000021F0: */ 0x78,0x00,0x00,0x00,0x04,0x3B,0x3B,0x3B,0x3B,0x00,0x00,0x00,0xF4,0x21,0x00,0x00, +/* 0x00002200: */ 0x78,0x00,0x00,0x00,0x0C,0x3A,0x3A,0x3A,0x3A,0x6D,0x61,0x74,0x68,0x2E,0x66,0x74, +/* 0x00002210: */ 0x68,0x00,0x00,0x00,0x04,0x22,0x00,0x00,0x44,0x35,0x00,0x00,0x0D,0x54,0x41,0x53, +/* 0x00002220: */ 0x4B,0x2D,0x4D,0x41,0x54,0x48,0x2E,0x46,0x54,0x48,0x00,0x00,0x1C,0x22,0x00,0x00, +/* 0x00002230: */ 0x54,0x35,0x00,0x00,0x06,0x46,0x4D,0x2F,0x4D,0x4F,0x44,0x00,0x34,0x22,0x00,0x00, +/* 0x00002240: */ 0x94,0x36,0x00,0x00,0x06,0x53,0x4D,0x2F,0x52,0x45,0x4D,0x00,0x44,0x22,0x00,0x00, +/* 0x00002250: */ 0x58,0x37,0x00,0x00,0x04,0x2F,0x4D,0x4F,0x44,0x00,0x00,0x00,0x54,0x22,0x00,0x00, +/* 0x00002260: */ 0x6C,0x37,0x00,0x00,0x03,0x4D,0x4F,0x44,0x64,0x22,0x00,0x00,0x78,0x37,0x00,0x00, +/* 0x00002270: */ 0x05,0x2A,0x2F,0x4D,0x4F,0x44,0x00,0x00,0x70,0x22,0x00,0x00,0x8C,0x37,0x00,0x00, +/* 0x00002280: */ 0x02,0x2A,0x2F,0x00,0x80,0x22,0x00,0x00,0x78,0x00,0x00,0x00,0x04,0x3B,0x3B,0x3B, +/* 0x00002290: */ 0x3B,0x00,0x00,0x00,0x8C,0x22,0x00,0x00,0x78,0x00,0x00,0x00,0x0D,0x3A,0x3A,0x3A, +/* 0x000022A0: */ 0x3A,0x6D,0x69,0x73,0x63,0x32,0x2E,0x66,0x74,0x68,0x00,0x00,0x9C,0x22,0x00,0x00, +/* 0x000022B0: */ 0x98,0x37,0x00,0x00,0x0E,0x54,0x41,0x53,0x4B,0x2D,0x4D,0x49,0x53,0x43,0x32,0x2E, +/* 0x000022C0: */ 0x46,0x54,0x48,0x00,0xB4,0x22,0x00,0x00,0xA8,0x37,0x00,0x00,0x42,0x27,0x4E,0x00, +/* 0x000022D0: */ 0xCC,0x22,0x00,0x00,0xE8,0x37,0x00,0x00,0x08,0x3F,0x4C,0x49,0x54,0x45,0x52,0x41, +/* 0x000022E0: */ 0x4C,0x00,0x00,0x00,0xD8,0x22,0x00,0x00,0x00,0x38,0x00,0x00,0x42,0x27,0x43,0x00, +/* 0x000022F0: */ 0xEC,0x22,0x00,0x00,0x0C,0x38,0x00,0x00,0x08,0x49,0x46,0x2D,0x44,0x45,0x42,0x55, +/* 0x00002300: */ 0x47,0x00,0x00,0x00,0xF8,0x22,0x00,0x00,0x1C,0x38,0x00,0x00,0x0A,0x4D,0x53,0x45, +/* 0x00002310: */ 0x43,0x2D,0x44,0x45,0x4C,0x41,0x59,0x00,0x0C,0x23,0x00,0x00,0x2C,0x38,0x00,0x00, +/* 0x00002320: */ 0x06,0x28,0x4D,0x53,0x45,0x43,0x29,0x00,0x20,0x23,0x00,0x00,0x60,0x38,0x00,0x00, +/* 0x00002330: */ 0x04,0x4D,0x53,0x45,0x43,0x00,0x00,0x00,0x30,0x23,0x00,0x00,0x6C,0x38,0x00,0x00, +/* 0x00002340: */ 0x05,0x53,0x48,0x49,0x46,0x54,0x00,0x00,0x40,0x23,0x00,0x00,0x94,0x38,0x00,0x00, +/* 0x00002350: */ 0x09,0x52,0x41,0x4E,0x44,0x2D,0x53,0x45,0x45,0x44,0x00,0x00,0x50,0x23,0x00,0x00, +/* 0x00002360: */ 0xA4,0x38,0x00,0x00,0x06,0x52,0x41,0x4E,0x44,0x4F,0x4D,0x00,0x64,0x23,0x00,0x00, +/* 0x00002370: */ 0xE0,0x38,0x00,0x00,0x06,0x43,0x48,0x4F,0x4F,0x53,0x45,0x00,0x74,0x23,0x00,0x00, +/* 0x00002380: */ 0xF8,0x38,0x00,0x00,0x07,0x57,0x43,0x48,0x4F,0x4F,0x53,0x45,0x84,0x23,0x00,0x00, +/* 0x00002390: */ 0x0C,0x39,0x00,0x00,0x05,0x32,0x53,0x4F,0x52,0x54,0x00,0x00,0x94,0x23,0x00,0x00, +/* 0x000023A0: */ 0x24,0x39,0x00,0x00,0x06,0x2D,0x32,0x53,0x4F,0x52,0x54,0x00,0xA4,0x23,0x00,0x00, +/* 0x000023B0: */ 0x3C,0x39,0x00,0x00,0x06,0x42,0x41,0x52,0x52,0x41,0x59,0x00,0xB4,0x23,0x00,0x00, +/* 0x000023C0: */ 0x5C,0x39,0x00,0x00,0x06,0x57,0x41,0x52,0x52,0x41,0x59,0x00,0xC4,0x23,0x00,0x00, +/* 0x000023D0: */ 0x88,0x39,0x00,0x00,0x05,0x41,0x52,0x52,0x41,0x59,0x00,0x00,0xD4,0x23,0x00,0x00, +/* 0x000023E0: */ 0xB4,0x39,0x00,0x00,0x04,0x2E,0x42,0x49,0x4E,0x00,0x00,0x00,0xE4,0x23,0x00,0x00, +/* 0x000023F0: */ 0xD4,0x39,0x00,0x00,0x04,0x2E,0x44,0x45,0x43,0x00,0x00,0x00,0xF4,0x23,0x00,0x00, +/* 0x00002400: */ 0xF4,0x39,0x00,0x00,0x04,0x2E,0x48,0x45,0x58,0x00,0x00,0x00,0x04,0x24,0x00,0x00, +/* 0x00002410: */ 0x14,0x3A,0x00,0x00,0x04,0x42,0x2D,0x3E,0x53,0x00,0x00,0x00,0x14,0x24,0x00,0x00, +/* 0x00002420: */ 0x50,0x3A,0x00,0x00,0x04,0x57,0x2D,0x3E,0x53,0x00,0x00,0x00,0x24,0x24,0x00,0x00, +/* 0x00002430: */ 0x8C,0x3A,0x00,0x00,0x06,0x57,0x49,0x54,0x48,0x49,0x4E,0x00,0x34,0x24,0x00,0x00, +/* 0x00002440: */ 0xF4,0x3A,0x00,0x00,0x04,0x4D,0x4F,0x56,0x45,0x00,0x00,0x00,0x44,0x24,0x00,0x00, +/* 0x00002450: */ 0x28,0x3B,0x00,0x00,0x05,0x45,0x52,0x41,0x53,0x45,0x00,0x00,0x54,0x24,0x00,0x00, +/* 0x00002460: */ 0x54,0x3B,0x00,0x00,0x05,0x42,0x4C,0x41,0x4E,0x4B,0x00,0x00,0x64,0x24,0x00,0x00, +/* 0x00002470: */ 0x7C,0x3B,0x00,0x00,0x05,0x51,0x55,0x45,0x52,0x59,0x00,0x00,0x74,0x24,0x00,0x00, +/* 0x00002480: */ 0x88,0x3B,0x00,0x00,0x04,0x53,0x50,0x41,0x4E,0x00,0x00,0x00,0x84,0x24,0x00,0x00, +/* 0x00002490: */ 0x98,0x3B,0x00,0x00,0x06,0x45,0x58,0x50,0x45,0x43,0x54,0x00,0x94,0x24,0x00,0x00, +/* 0x000024A0: */ 0xA8,0x3B,0x00,0x00,0x03,0x54,0x49,0x42,0xA4,0x24,0x00,0x00,0xB4,0x3B,0x00,0x00, +/* 0x000024B0: */ 0x06,0x55,0x4E,0x55,0x53,0x45,0x44,0x00,0xB0,0x24,0x00,0x00,0xC4,0x3B,0x00,0x00, +/* 0x000024C0: */ 0x03,0x4D,0x41,0x50,0xC0,0x24,0x00,0x00,0xA0,0x3E,0x00,0x00,0x06,0x53,0x45,0x41, +/* 0x000024D0: */ 0x52,0x43,0x48,0x00,0xCC,0x24,0x00,0x00,0x78,0x00,0x00,0x00,0x04,0x3B,0x3B,0x3B, +/* 0x000024E0: */ 0x3B,0x00,0x00,0x00,0xDC,0x24,0x00,0x00,0x78,0x00,0x00,0x00,0x10,0x3A,0x3A,0x3A, +/* 0x000024F0: */ 0x3A,0x63,0x6F,0x6E,0x64,0x63,0x6F,0x6D,0x70,0x2E,0x66,0x74,0x68,0x00,0x00,0x00, +/* 0x00002500: */ 0xEC,0x24,0x00,0x00,0xB4,0x3F,0x00,0x00,0x11,0x54,0x41,0x53,0x4B,0x2D,0x43,0x4F, +/* 0x00002510: */ 0x4E,0x44,0x43,0x4F,0x4D,0x50,0x2E,0x46,0x54,0x48,0x00,0x00,0x08,0x25,0x00,0x00, +/* 0x00002520: */ 0xC4,0x3F,0x00,0x00,0x46,0x5B,0x45,0x4C,0x53,0x45,0x5D,0x00,0x24,0x25,0x00,0x00, +/* 0x00002530: */ 0xAC,0x40,0x00,0x00,0x44,0x5B,0x49,0x46,0x5D,0x00,0x00,0x00,0x34,0x25,0x00,0x00, +/* 0x00002540: */ 0xC0,0x40,0x00,0x00,0x46,0x5B,0x54,0x48,0x45,0x4E,0x5D,0x00,0x44,0x25,0x00,0x00, +/* 0x00002550: */ 0xC4,0x40,0x00,0x00,0x47,0x45,0x58,0x49,0x53,0x54,0x53,0x3F,0x54,0x25,0x00,0x00, +/* 0x00002560: */ 0x78,0x00,0x00,0x00,0x04,0x3B,0x3B,0x3B,0x3B,0x00,0x00,0x00,0x64,0x25,0x00,0x00, +/* 0x00002570: */ 0x78,0x00,0x00,0x00,0x0E,0x3A,0x3A,0x3A,0x3A,0x6D,0x65,0x6D,0x62,0x65,0x72,0x2E, +/* 0x00002580: */ 0x66,0x74,0x68,0x00,0x74,0x25,0x00,0x00,0xDC,0x40,0x00,0x00,0x0F,0x54,0x41,0x53, +/* 0x00002590: */ 0x4B,0x2D,0x4D,0x45,0x4D,0x42,0x45,0x52,0x2E,0x46,0x54,0x48,0x8C,0x25,0x00,0x00, +/* 0x000025A0: */ 0xEC,0x40,0x00,0x00,0x09,0x46,0x49,0x4E,0x44,0x2E,0x42,0x4F,0x44,0x59,0x00,0x00, +/* 0x000025B0: */ 0xA4,0x25,0x00,0x00,0x1C,0x41,0x00,0x00,0x08,0x4F,0x42,0x2D,0x53,0x54,0x41,0x54, +/* 0x000025C0: */ 0x45,0x00,0x00,0x00,0xB8,0x25,0x00,0x00,0x2C,0x41,0x00,0x00,0x10,0x4F,0x42,0x2D, +/* 0x000025D0: */ 0x43,0x55,0x52,0x52,0x45,0x4E,0x54,0x2D,0x43,0x4C,0x41,0x53,0x53,0x00,0x00,0x00, +/* 0x000025E0: */ 0xCC,0x25,0x00,0x00,0x3C,0x41,0x00,0x00,0x0C,0x4F,0x42,0x5F,0x44,0x45,0x46,0x5F, +/* 0x000025F0: */ 0x43,0x4C,0x41,0x53,0x53,0x00,0x00,0x00,0xE8,0x25,0x00,0x00,0x4C,0x41,0x00,0x00, +/* 0x00002600: */ 0x0D,0x4F,0x42,0x5F,0x44,0x45,0x46,0x5F,0x53,0x54,0x52,0x55,0x43,0x54,0x00,0x00, +/* 0x00002610: */ 0x00,0x26,0x00,0x00,0x5C,0x41,0x00,0x00,0x0E,0x4F,0x42,0x5F,0x4F,0x46,0x46,0x53, +/* 0x00002620: */ 0x45,0x54,0x5F,0x53,0x49,0x5A,0x45,0x00,0x18,0x26,0x00,0x00,0x6C,0x41,0x00,0x00, +/* 0x00002630: */ 0x0A,0x4F,0x42,0x2E,0x4F,0x46,0x46,0x53,0x45,0x54,0x40,0x00,0x30,0x26,0x00,0x00, +/* 0x00002640: */ 0x74,0x41,0x00,0x00,0x0A,0x4F,0x42,0x2E,0x4F,0x46,0x46,0x53,0x45,0x54,0x2C,0x00, +/* 0x00002650: */ 0x44,0x26,0x00,0x00,0x7C,0x41,0x00,0x00,0x08,0x4F,0x42,0x2E,0x53,0x49,0x5A,0x45, +/* 0x00002660: */ 0x40,0x00,0x00,0x00,0x58,0x26,0x00,0x00,0x8C,0x41,0x00,0x00,0x08,0x4F,0x42,0x2E, +/* 0x00002670: */ 0x53,0x49,0x5A,0x45,0x2C,0x00,0x00,0x00,0x6C,0x26,0x00,0x00,0x94,0x41,0x00,0x00, +/* 0x00002680: */ 0x0E,0x4F,0x42,0x2E,0x4D,0x41,0x4B,0x45,0x2E,0x4D,0x45,0x4D,0x42,0x45,0x52,0x00, +/* 0x00002690: */ 0x80,0x26,0x00,0x00,0x1C,0x42,0x00,0x00,0x06,0x55,0x4E,0x49,0x4F,0x4E,0x7B,0x00, +/* 0x000026A0: */ 0x98,0x26,0x00,0x00,0x2C,0x42,0x00,0x00,0x07,0x7D,0x55,0x4E,0x49,0x4F,0x4E,0x7B, +/* 0x000026B0: */ 0xA8,0x26,0x00,0x00,0x44,0x42,0x00,0x00,0x06,0x7D,0x55,0x4E,0x49,0x4F,0x4E,0x00, +/* 0x000026C0: */ 0xB8,0x26,0x00,0x00,0x90,0x42,0x00,0x00,0x09,0x4F,0x42,0x2E,0x4D,0x45,0x4D,0x42, +/* 0x000026D0: */ 0x45,0x52,0x00,0x00,0xC8,0x26,0x00,0x00,0xB8,0x42,0x00,0x00,0x09,0x4F,0x42,0x2E, +/* 0x000026E0: */ 0x46,0x49,0x4E,0x44,0x49,0x54,0x00,0x00,0xDC,0x26,0x00,0x00,0x0C,0x43,0x00,0x00, +/* 0x000026F0: */ 0x08,0x4F,0x42,0x2E,0x53,0x54,0x41,0x54,0x53,0x00,0x00,0x00,0xF0,0x26,0x00,0x00, +/* 0x00002700: */ 0x20,0x43,0x00,0x00,0x09,0x4F,0x42,0x2E,0x53,0x54,0x41,0x54,0x53,0x3F,0x00,0x00, +/* 0x00002710: */ 0x04,0x27,0x00,0x00,0x2C,0x43,0x00,0x00,0x48,0x53,0x49,0x5A,0x45,0x4F,0x46,0x28, +/* 0x00002720: */ 0x29,0x00,0x00,0x00,0x18,0x27,0x00,0x00,0x3C,0x43,0x00,0x00,0x05,0x42,0x59,0x54, +/* 0x00002730: */ 0x45,0x53,0x00,0x00,0x2C,0x27,0x00,0x00,0x8C,0x43,0x00,0x00,0x04,0x42,0x59,0x54, +/* 0x00002740: */ 0x45,0x00,0x00,0x00,0x3C,0x27,0x00,0x00,0x98,0x43,0x00,0x00,0x05,0x53,0x48,0x4F, +/* 0x00002750: */ 0x52,0x54,0x00,0x00,0x4C,0x27,0x00,0x00,0xA4,0x43,0x00,0x00,0x04,0x4C,0x4F,0x4E, +/* 0x00002760: */ 0x47,0x00,0x00,0x00,0x5C,0x27,0x00,0x00,0xB0,0x43,0x00,0x00,0x05,0x55,0x42,0x59, +/* 0x00002770: */ 0x54,0x45,0x00,0x00,0x6C,0x27,0x00,0x00,0xC0,0x43,0x00,0x00,0x06,0x55,0x53,0x48, +/* 0x00002780: */ 0x4F,0x52,0x54,0x00,0x7C,0x27,0x00,0x00,0xD0,0x43,0x00,0x00,0x04,0x41,0x50,0x54, +/* 0x00002790: */ 0x52,0x00,0x00,0x00,0x8C,0x27,0x00,0x00,0xD8,0x43,0x00,0x00,0x04,0x52,0x50,0x54, +/* 0x000027A0: */ 0x52,0x00,0x00,0x00,0x9C,0x27,0x00,0x00,0xE8,0x43,0x00,0x00,0x05,0x55,0x4C,0x4F, +/* 0x000027B0: */ 0x4E,0x47,0x00,0x00,0xAC,0x27,0x00,0x00,0xF0,0x43,0x00,0x00,0x06,0x53,0x54,0x52, +/* 0x000027C0: */ 0x55,0x43,0x54,0x00,0xBC,0x27,0x00,0x00,0x78,0x00,0x00,0x00,0x04,0x3B,0x3B,0x3B, +/* 0x000027D0: */ 0x3B,0x00,0x00,0x00,0xCC,0x27,0x00,0x00,0x78,0x00,0x00,0x00,0x10,0x3A,0x3A,0x3A, +/* 0x000027E0: */ 0x3A,0x63,0x5F,0x73,0x74,0x72,0x75,0x63,0x74,0x2E,0x66,0x74,0x68,0x00,0x00,0x00, +/* 0x000027F0: */ 0xDC,0x27,0x00,0x00,0xFC,0x43,0x00,0x00,0x0D,0x54,0x41,0x53,0x4B,0x2D,0x43,0x5F, +/* 0x00002800: */ 0x53,0x54,0x52,0x55,0x43,0x54,0x00,0x00,0xF8,0x27,0x00,0x00,0x0C,0x44,0x00,0x00, +/* 0x00002810: */ 0x09,0x3C,0x3A,0x53,0x54,0x52,0x55,0x43,0x54,0x3E,0x00,0x00,0x10,0x28,0x00,0x00, +/* 0x00002820: */ 0x38,0x44,0x00,0x00,0x07,0x3A,0x53,0x54,0x52,0x55,0x43,0x54,0x24,0x28,0x00,0x00, +/* 0x00002830: */ 0xC8,0x44,0x00,0x00,0x07,0x3B,0x53,0x54,0x52,0x55,0x43,0x54,0x34,0x28,0x00,0x00, +/* 0x00002840: */ 0x5C,0x45,0x00,0x00,0x42,0x2E,0x2E,0x00,0x44,0x28,0x00,0x00,0xA0,0x45,0x00,0x00, +/* 0x00002850: */ 0x06,0x28,0x53,0x2B,0x43,0x21,0x29,0x00,0x50,0x28,0x00,0x00,0xAC,0x45,0x00,0x00, +/* 0x00002860: */ 0x06,0x28,0x53,0x2B,0x57,0x21,0x29,0x00,0x60,0x28,0x00,0x00,0xB8,0x45,0x00,0x00, +/* 0x00002870: */ 0x05,0x28,0x53,0x2B,0x21,0x29,0x00,0x00,0x70,0x28,0x00,0x00,0xC4,0x45,0x00,0x00, +/* 0x00002880: */ 0x08,0x28,0x53,0x2B,0x52,0x45,0x4C,0x21,0x29,0x00,0x00,0x00,0x80,0x28,0x00,0x00, +/* 0x00002890: */ 0xDC,0x45,0x00,0x00,0x0E,0x43,0x4F,0x4D,0x50,0x49,0x4C,0x45,0x2B,0x21,0x42,0x59, +/* 0x000028A0: */ 0x54,0x45,0x53,0x00,0x94,0x28,0x00,0x00,0x20,0x47,0x00,0x00,0x06,0x21,0x42,0x59, +/* 0x000028B0: */ 0x54,0x45,0x53,0x00,0xAC,0x28,0x00,0x00,0xF4,0x47,0x00,0x00,0x04,0x28,0x53,0x21, +/* 0x000028C0: */ 0x29,0x00,0x00,0x00,0xBC,0x28,0x00,0x00,0x24,0x48,0x00,0x00,0x42,0x53,0x21,0x00, +/* 0x000028D0: */ 0xCC,0x28,0x00,0x00,0x30,0x48,0x00,0x00,0x06,0x40,0x42,0x59,0x54,0x45,0x53,0x00, +/* 0x000028E0: */ 0xD8,0x28,0x00,0x00,0x48,0x49,0x00,0x00,0x07,0x28,0x53,0x2B,0x55,0x43,0x40,0x29, +/* 0x000028F0: */ 0xE8,0x28,0x00,0x00,0x54,0x49,0x00,0x00,0x07,0x28,0x53,0x2B,0x55,0x57,0x40,0x29, +/* 0x00002900: */ 0xF8,0x28,0x00,0x00,0x60,0x49,0x00,0x00,0x05,0x28,0x53,0x2B,0x40,0x29,0x00,0x00, +/* 0x00002910: */ 0x08,0x29,0x00,0x00,0x6C,0x49,0x00,0x00,0x08,0x28,0x53,0x2B,0x52,0x45,0x4C,0x40, +/* 0x00002920: */ 0x29,0x00,0x00,0x00,0x18,0x29,0x00,0x00,0x7C,0x49,0x00,0x00,0x06,0x28,0x53,0x2B, +/* 0x00002930: */ 0x43,0x40,0x29,0x00,0x2C,0x29,0x00,0x00,0x8C,0x49,0x00,0x00,0x06,0x28,0x53,0x2B, +/* 0x00002940: */ 0x57,0x40,0x29,0x00,0x3C,0x29,0x00,0x00,0x9C,0x49,0x00,0x00,0x0E,0x43,0x4F,0x4D, +/* 0x00002950: */ 0x50,0x49,0x4C,0x45,0x2B,0x40,0x42,0x59,0x54,0x45,0x53,0x00,0x4C,0x29,0x00,0x00, +/* 0x00002960: */ 0xE0,0x4A,0x00,0x00,0x04,0x28,0x53,0x40,0x29,0x00,0x00,0x00,0x64,0x29,0x00,0x00, +/* 0x00002970: */ 0x10,0x4B,0x00,0x00,0x42,0x53,0x40,0x00,0x74,0x29,0x00,0x00,0x78,0x00,0x00,0x00, +/* 0x00002980: */ 0x04,0x3B,0x3B,0x3B,0x3B,0x00,0x00,0x00,0x80,0x29,0x00,0x00,0x78,0x00,0x00,0x00, +/* 0x00002990: */ 0x10,0x3A,0x3A,0x3A,0x3A,0x73,0x6D,0x61,0x72,0x74,0x5F,0x69,0x66,0x2E,0x66,0x74, +/* 0x000029A0: */ 0x68,0x00,0x00,0x00,0x90,0x29,0x00,0x00,0x1C,0x4B,0x00,0x00,0x11,0x54,0x41,0x53, +/* 0x000029B0: */ 0x4B,0x2D,0x53,0x4D,0x41,0x52,0x54,0x5F,0x49,0x46,0x2E,0x46,0x54,0x48,0x00,0x00, +/* 0x000029C0: */ 0xAC,0x29,0x00,0x00,0x2C,0x4B,0x00,0x00,0x07,0x53,0x4D,0x49,0x46,0x2D,0x58,0x54, +/* 0x000029D0: */ 0xC8,0x29,0x00,0x00,0x3C,0x4B,0x00,0x00,0x0A,0x53,0x4D,0x49,0x46,0x2D,0x44,0x45, +/* 0x000029E0: */ 0x50,0x54,0x48,0x00,0xD8,0x29,0x00,0x00,0x4C,0x4B,0x00,0x00,0x05,0x53,0x4D,0x49, +/* 0x000029F0: */ 0x46,0x7B,0x00,0x00,0xEC,0x29,0x00,0x00,0x98,0x4B,0x00,0x00,0x05,0x7D,0x53,0x4D, +/* 0x00002A00: */ 0x49,0x46,0x00,0x00,0xFC,0x29,0x00,0x00,0x08,0x4C,0x00,0x00,0x42,0x49,0x46,0x00, +/* 0x00002A10: */ 0x0C,0x2A,0x00,0x00,0x14,0x4C,0x00,0x00,0x42,0x44,0x4F,0x00,0x18,0x2A,0x00,0x00, +/* 0x00002A20: */ 0x20,0x4C,0x00,0x00,0x43,0x3F,0x44,0x4F,0x24,0x2A,0x00,0x00,0x2C,0x4C,0x00,0x00, +/* 0x00002A30: */ 0x45,0x42,0x45,0x47,0x49,0x4E,0x00,0x00,0x30,0x2A,0x00,0x00,0x38,0x4C,0x00,0x00, +/* 0x00002A40: */ 0x44,0x54,0x48,0x45,0x4E,0x00,0x00,0x00,0x40,0x2A,0x00,0x00,0x44,0x4C,0x00,0x00, +/* 0x00002A50: */ 0x46,0x52,0x45,0x50,0x45,0x41,0x54,0x00,0x50,0x2A,0x00,0x00,0x50,0x4C,0x00,0x00, +/* 0x00002A60: */ 0x45,0x55,0x4E,0x54,0x49,0x4C,0x00,0x00,0x60,0x2A,0x00,0x00,0x5C,0x4C,0x00,0x00, +/* 0x00002A70: */ 0x44,0x4C,0x4F,0x4F,0x50,0x00,0x00,0x00,0x70,0x2A,0x00,0x00,0x68,0x4C,0x00,0x00, +/* 0x00002A80: */ 0x45,0x2B,0x4C,0x4F,0x4F,0x50,0x00,0x00,0x80,0x2A,0x00,0x00,0x78,0x00,0x00,0x00, +/* 0x00002A90: */ 0x04,0x3B,0x3B,0x3B,0x3B,0x00,0x00,0x00,0x90,0x2A,0x00,0x00,0x78,0x00,0x00,0x00, +/* 0x00002AA0: */ 0x10,0x3A,0x3A,0x3A,0x3A,0x66,0x69,0x6C,0x65,0x66,0x69,0x6E,0x64,0x2E,0x66,0x74, +/* 0x00002AB0: */ 0x68,0x00,0x00,0x00,0xA0,0x2A,0x00,0x00,0x74,0x4C,0x00,0x00,0x11,0x54,0x41,0x53, +/* 0x00002AC0: */ 0x4B,0x2D,0x46,0x49,0x4C,0x45,0x46,0x49,0x4E,0x44,0x2E,0x46,0x54,0x48,0x00,0x00, +/* 0x00002AD0: */ 0xBC,0x2A,0x00,0x00,0x84,0x4C,0x00,0x00,0x03,0x42,0x45,0x40,0xD8,0x2A,0x00,0x00, +/* 0x00002AE0: */ 0xE4,0x4C,0x00,0x00,0x03,0x42,0x45,0x21,0xE4,0x2A,0x00,0x00,0x48,0x4D,0x00,0x00, +/* 0x00002AF0: */ 0x04,0x42,0x45,0x57,0x40,0x00,0x00,0x00,0xF0,0x2A,0x00,0x00,0x80,0x4D,0x00,0x00, +/* 0x00002B00: */ 0x04,0x42,0x45,0x57,0x21,0x00,0x00,0x00,0x00,0x2B,0x00,0x00,0xBC,0x4D,0x00,0x00, +/* 0x00002B10: */ 0x0D,0x46,0x3F,0x2E,0x53,0x45,0x41,0x52,0x43,0x48,0x2E,0x4E,0x46,0x41,0x00,0x00, +/* 0x00002B20: */ 0x10,0x2B,0x00,0x00,0x54,0x4F,0x00,0x00,0x0C,0x46,0x49,0x4E,0x44,0x4E,0x46,0x41, +/* 0x00002B30: */ 0x2E,0x46,0x52,0x4F,0x4D,0x00,0x00,0x00,0x28,0x2B,0x00,0x00,0x94,0x4F,0x00,0x00, +/* 0x00002B40: */ 0x05,0x46,0x49,0x4C,0x45,0x3F,0x00,0x00,0x40,0x2B,0x00,0x00,0x78,0x00,0x00,0x00, +/* 0x00002B50: */ 0x04,0x3B,0x3B,0x3B,0x3B,0x00,0x00,0x00,0x50,0x2B,0x00,0x00,0x78,0x00,0x00,0x00, +/* 0x00002B60: */ 0x0B,0x3A,0x3A,0x3A,0x3A,0x73,0x65,0x65,0x2E,0x66,0x74,0x68,0x60,0x2B,0x00,0x00, +/* 0x00002B70: */ 0x98,0x50,0x00,0x00,0x0C,0x54,0x41,0x53,0x4B,0x2D,0x53,0x45,0x45,0x2E,0x46,0x54, +/* 0x00002B80: */ 0x48,0x00,0x00,0x00,0x74,0x2B,0x00,0x00,0xA8,0x50,0x00,0x00,0x03,0x2E,0x58,0x54, +/* 0x00002B90: */ 0x8C,0x2B,0x00,0x00,0xE0,0x50,0x00,0x00,0x09,0x42,0x59,0x54,0x45,0x5F,0x43,0x4F, +/* 0x00002BA0: */ 0x44,0x45,0x00,0x00,0x98,0x2B,0x00,0x00,0xF0,0x50,0x00,0x00,0x05,0x43,0x4F,0x44, +/* 0x00002BB0: */ 0x45,0x40,0x00,0x00,0xAC,0x2B,0x00,0x00,0xF8,0x50,0x00,0x00,0x09,0x43,0x4F,0x44, +/* 0x00002BC0: */ 0x45,0x5F,0x43,0x45,0x4C,0x4C,0x00,0x00,0xBC,0x2B,0x00,0x00,0x08,0x51,0x00,0x00, +/* 0x00002BD0: */ 0x69,0x53,0x45,0x45,0x5F,0x4C,0x45,0x56,0x45,0x4C,0x00,0x00,0xD0,0x2B,0x00,0x00, +/* 0x00002BE0: */ 0x18,0x51,0x00,0x00,0x68,0x53,0x45,0x45,0x5F,0x41,0x44,0x44,0x52,0x00,0x00,0x00, +/* 0x00002BF0: */ 0xE4,0x2B,0x00,0x00,0x28,0x51,0x00,0x00,0x67,0x53,0x45,0x45,0x5F,0x4F,0x55,0x54, +/* 0x00002C00: */ 0xF8,0x2B,0x00,0x00,0x38,0x51,0x00,0x00,0x2D,0x53,0x45,0x45,0x2E,0x49,0x4E,0x44, +/* 0x00002C10: */ 0x45,0x4E,0x54,0x2E,0x42,0x59,0x00,0x00,0x08,0x2C,0x00,0x00,0x64,0x51,0x00,0x00, +/* 0x00002C20: */ 0x26,0x53,0x45,0x45,0x2E,0x43,0x52,0x00,0x20,0x2C,0x00,0x00,0xA8,0x51,0x00,0x00, +/* 0x00002C30: */ 0x2B,0x53,0x45,0x45,0x2E,0x4E,0x45,0x57,0x4C,0x49,0x4E,0x45,0x30,0x2C,0x00,0x00, +/* 0x00002C40: */ 0xC8,0x51,0x00,0x00,0x27,0x53,0x45,0x45,0x2E,0x43,0x52,0x3F,0x44,0x2C,0x00,0x00, +/* 0x00002C50: */ 0xF0,0x51,0x00,0x00,0x28,0x53,0x45,0x45,0x2E,0x4F,0x55,0x54,0x2B,0x00,0x00,0x00, +/* 0x00002C60: */ 0x54,0x2C,0x00,0x00,0x08,0x52,0x00,0x00,0x2B,0x53,0x45,0x45,0x2E,0x41,0x44,0x56, +/* 0x00002C70: */ 0x41,0x4E,0x43,0x45,0x68,0x2C,0x00,0x00,0x1C,0x52,0x00,0x00,0x2E,0x53,0x45,0x45, +/* 0x00002C80: */ 0x2E,0x47,0x45,0x54,0x2E,0x49,0x4E,0x4C,0x49,0x4E,0x45,0x00,0x7C,0x2C,0x00,0x00, +/* 0x00002C90: */ 0x30,0x52,0x00,0x00,0x2E,0x53,0x45,0x45,0x2E,0x47,0x45,0x54,0x2E,0x54,0x41,0x52, +/* 0x00002CA0: */ 0x47,0x45,0x54,0x00,0x94,0x2C,0x00,0x00,0x54,0x52,0x00,0x00,0x2C,0x53,0x45,0x45, +/* 0x00002CB0: */ 0x2E,0x53,0x48,0x4F,0x57,0x2E,0x4C,0x49,0x54,0x00,0x00,0x00,0xAC,0x2C,0x00,0x00, +/* 0x00002CC0: */ 0x68,0x52,0x00,0x00,0x2D,0x53,0x45,0x45,0x2E,0x53,0x48,0x4F,0x57,0x2E,0x41,0x4C, +/* 0x00002CD0: */ 0x49,0x54,0x00,0x00,0xC4,0x2C,0x00,0x00,0x84,0x52,0x00,0x00,0x2F,0x53,0x45,0x45, +/* 0x00002CE0: */ 0x2E,0x53,0x48,0x4F,0x57,0x2E,0x53,0x54,0x52,0x49,0x4E,0x47,0xDC,0x2C,0x00,0x00, +/* 0x00002CF0: */ 0xB8,0x52,0x00,0x00,0x2F,0x53,0x45,0x45,0x2E,0x53,0x48,0x4F,0x57,0x2E,0x54,0x41, +/* 0x00002D00: */ 0x52,0x47,0x45,0x54,0xF4,0x2C,0x00,0x00,0xC8,0x52,0x00,0x00,0x2A,0x53,0x45,0x45, +/* 0x00002D10: */ 0x2E,0x42,0x52,0x41,0x4E,0x43,0x48,0x00,0x0C,0x2D,0x00,0x00,0x40,0x53,0x00,0x00, +/* 0x00002D20: */ 0x2B,0x53,0x45,0x45,0x2E,0x30,0x42,0x52,0x41,0x4E,0x43,0x48,0x20,0x2D,0x00,0x00, +/* 0x00002D30: */ 0xA8,0x53,0x00,0x00,0x26,0x53,0x45,0x45,0x2E,0x58,0x54,0x00,0x34,0x2D,0x00,0x00, +/* 0x00002D40: */ 0xBC,0x56,0x00,0x00,0x25,0x28,0x53,0x45,0x45,0x29,0x00,0x00,0x44,0x2D,0x00,0x00, +/* 0x00002D50: */ 0xD4,0x57,0x00,0x00,0x03,0x53,0x45,0x45,0x54,0x2D,0x00,0x00,0x78,0x00,0x00,0x00, +/* 0x00002D60: */ 0x04,0x3B,0x3B,0x3B,0x3B,0x00,0x00,0x00,0x60,0x2D,0x00,0x00,0x78,0x00,0x00,0x00, +/* 0x00002D70: */ 0x10,0x3A,0x3A,0x3A,0x3A,0x77,0x6F,0x72,0x64,0x73,0x6C,0x69,0x6B,0x2E,0x66,0x74, +/* 0x00002D80: */ 0x68,0x00,0x00,0x00,0x70,0x2D,0x00,0x00,0x3C,0x58,0x00,0x00,0x11,0x54,0x41,0x53, +/* 0x00002D90: */ 0x4B,0x2D,0x57,0x4F,0x52,0x44,0x53,0x4C,0x49,0x4B,0x2E,0x46,0x54,0x48,0x00,0x00, +/* 0x00002DA0: */ 0x8C,0x2D,0x00,0x00,0x4C,0x58,0x00,0x00,0x12,0x50,0x41,0x52,0x54,0x49,0x41,0x4C, +/* 0x00002DB0: */ 0x2E,0x4D,0x41,0x54,0x43,0x48,0x2E,0x4E,0x41,0x4D,0x45,0x00,0xA8,0x2D,0x00,0x00, +/* 0x00002DC0: */ 0x78,0x58,0x00,0x00,0x0A,0x57,0x4F,0x52,0x44,0x53,0x2E,0x4C,0x49,0x4B,0x45,0x00, +/* 0x00002DD0: */ 0xC4,0x2D,0x00,0x00,0x78,0x00,0x00,0x00,0x04,0x3B,0x3B,0x3B,0x3B,0x00,0x00,0x00, +/* 0x00002DE0: */ 0xD8,0x2D,0x00,0x00,0x78,0x00,0x00,0x00,0x0D,0x3A,0x3A,0x3A,0x3A,0x74,0x72,0x61, +/* 0x00002DF0: */ 0x63,0x65,0x2E,0x66,0x74,0x68,0x00,0x00,0xE8,0x2D,0x00,0x00,0xD0,0x58,0x00,0x00, +/* 0x00002E00: */ 0x0E,0x54,0x41,0x53,0x4B,0x2D,0x54,0x52,0x41,0x43,0x45,0x2E,0x46,0x54,0x48,0x00, +/* 0x00002E10: */ 0x00,0x2E,0x00,0x00,0xE0,0x58,0x00,0x00,0x0F,0x53,0x50,0x41,0x43,0x45,0x2E,0x54, +/* 0x00002E20: */ 0x4F,0x2E,0x43,0x4F,0x4C,0x55,0x4D,0x4E,0x18,0x2E,0x00,0x00,0xF4,0x58,0x00,0x00, +/* 0x00002E30: */ 0x0D,0x49,0x53,0x2E,0x50,0x52,0x49,0x4D,0x49,0x54,0x49,0x56,0x45,0x3F,0x00,0x00, +/* 0x00002E40: */ 0x30,0x2E,0x00,0x00,0x04,0x59,0x00,0x00,0x48,0x54,0x52,0x41,0x43,0x45,0x5F,0x49, +/* 0x00002E50: */ 0x50,0x00,0x00,0x00,0x48,0x2E,0x00,0x00,0x14,0x59,0x00,0x00,0x4B,0x54,0x52,0x41, +/* 0x00002E60: */ 0x43,0x45,0x5F,0x4C,0x45,0x56,0x45,0x4C,0x5C,0x2E,0x00,0x00,0x24,0x59,0x00,0x00, +/* 0x00002E70: */ 0x4F,0x54,0x52,0x41,0x43,0x45,0x5F,0x4C,0x45,0x56,0x45,0x4C,0x5F,0x4D,0x41,0x58, +/* 0x00002E80: */ 0x70,0x2E,0x00,0x00,0x34,0x59,0x00,0x00,0x31,0x54,0x52,0x41,0x43,0x45,0x5F,0x52, +/* 0x00002E90: */ 0x45,0x54,0x55,0x52,0x4E,0x5F,0x53,0x49,0x5A,0x45,0x00,0x00,0x88,0x2E,0x00,0x00, +/* 0x00002EA0: */ 0x44,0x59,0x00,0x00,0x32,0x54,0x52,0x41,0x43,0x45,0x2D,0x52,0x45,0x54,0x55,0x52, +/* 0x00002EB0: */ 0x4E,0x2D,0x53,0x54,0x41,0x43,0x4B,0x00,0xA4,0x2E,0x00,0x00,0x60,0x5B,0x00,0x00, +/* 0x00002EC0: */ 0x29,0x54,0x52,0x41,0x43,0x45,0x2D,0x52,0x53,0x50,0x00,0x00,0xC0,0x2E,0x00,0x00, +/* 0x00002ED0: */ 0x70,0x5B,0x00,0x00,0x28,0x54,0x52,0x41,0x43,0x45,0x2E,0x3E,0x52,0x00,0x00,0x00, +/* 0x00002EE0: */ 0xD4,0x2E,0x00,0x00,0x90,0x5B,0x00,0x00,0x28,0x54,0x52,0x41,0x43,0x45,0x2E,0x52, +/* 0x00002EF0: */ 0x3E,0x00,0x00,0x00,0xE8,0x2E,0x00,0x00,0xB4,0x5B,0x00,0x00,0x28,0x54,0x52,0x41, +/* 0x00002F00: */ 0x43,0x45,0x2E,0x52,0x40,0x00,0x00,0x00,0xFC,0x2E,0x00,0x00,0xC8,0x5B,0x00,0x00, +/* 0x00002F10: */ 0x2B,0x54,0x52,0x41,0x43,0x45,0x2E,0x52,0x50,0x49,0x43,0x4B,0x10,0x2F,0x00,0x00, +/* 0x00002F20: */ 0xE4,0x5B,0x00,0x00,0x29,0x54,0x52,0x41,0x43,0x45,0x2E,0x30,0x52,0x50,0x00,0x00, +/* 0x00002F30: */ 0x24,0x2F,0x00,0x00,0x08,0x5C,0x00,0x00,0x2B,0x54,0x52,0x41,0x43,0x45,0x2E,0x52, +/* 0x00002F40: */ 0x44,0x52,0x4F,0x50,0x38,0x2F,0x00,0x00,0x18,0x5C,0x00,0x00,0x2C,0x54,0x52,0x41, +/* 0x00002F50: */ 0x43,0x45,0x2E,0x52,0x43,0x48,0x45,0x43,0x4B,0x00,0x00,0x00,0x4C,0x2F,0x00,0x00, +/* 0x00002F60: */ 0xA0,0x5C,0x00,0x00,0x30,0x54,0x52,0x41,0x43,0x45,0x5F,0x53,0x54,0x41,0x54,0x45, +/* 0x00002F70: */ 0x5F,0x53,0x49,0x5A,0x45,0x00,0x00,0x00,0x64,0x2F,0x00,0x00,0xB0,0x5C,0x00,0x00, +/* 0x00002F80: */ 0x2D,0x54,0x52,0x41,0x43,0x45,0x2D,0x53,0x54,0x41,0x54,0x45,0x2D,0x31,0x00,0x00, +/* 0x00002F90: */ 0x80,0x2F,0x00,0x00,0xE4,0x5C,0x00,0x00,0x2D,0x54,0x52,0x41,0x43,0x45,0x2D,0x53, +/* 0x00002FA0: */ 0x54,0x41,0x54,0x45,0x2D,0x32,0x00,0x00,0x98,0x2F,0x00,0x00,0x18,0x5D,0x00,0x00, +/* 0x00002FB0: */ 0x2F,0x54,0x52,0x41,0x43,0x45,0x2D,0x53,0x54,0x41,0x54,0x45,0x2D,0x50,0x54,0x52, +/* 0x00002FC0: */ 0xB0,0x2F,0x00,0x00,0x28,0x5D,0x00,0x00,0x2C,0x54,0x52,0x41,0x43,0x45,0x2E,0x53, +/* 0x00002FD0: */ 0x41,0x56,0x45,0x2B,0x2B,0x00,0x00,0x00,0xC8,0x2F,0x00,0x00,0x48,0x5D,0x00,0x00, +/* 0x00002FE0: */ 0x30,0x54,0x52,0x41,0x43,0x45,0x2E,0x53,0x41,0x56,0x45,0x2E,0x53,0x54,0x41,0x54, +/* 0x00002FF0: */ 0x45,0x00,0x00,0x00,0xE0,0x2F,0x00,0x00,0x64,0x5D,0x00,0x00,0x31,0x54,0x52,0x41, +/* 0x00003000: */ 0x43,0x45,0x2E,0x53,0x41,0x56,0x45,0x2E,0x53,0x54,0x41,0x54,0x45,0x31,0x00,0x00, +/* 0x00003010: */ 0xFC,0x2F,0x00,0x00,0x78,0x5D,0x00,0x00,0x31,0x54,0x52,0x41,0x43,0x45,0x2E,0x53, +/* 0x00003020: */ 0x41,0x56,0x45,0x2E,0x53,0x54,0x41,0x54,0x45,0x32,0x00,0x00,0x18,0x30,0x00,0x00, +/* 0x00003030: */ 0x8C,0x5D,0x00,0x00,0x2F,0x54,0x52,0x41,0x43,0x45,0x2E,0x52,0x45,0x53,0x54,0x4F, +/* 0x00003040: */ 0x52,0x45,0x2B,0x2B,0x34,0x30,0x00,0x00,0xB0,0x5D,0x00,0x00,0x33,0x54,0x52,0x41, +/* 0x00003050: */ 0x43,0x45,0x2E,0x52,0x45,0x53,0x54,0x4F,0x52,0x45,0x2E,0x53,0x54,0x41,0x54,0x45, +/* 0x00003060: */ 0x4C,0x30,0x00,0x00,0xCC,0x5D,0x00,0x00,0x34,0x54,0x52,0x41,0x43,0x45,0x2E,0x52, +/* 0x00003070: */ 0x45,0x53,0x54,0x4F,0x52,0x45,0x2E,0x53,0x54,0x41,0x54,0x45,0x31,0x00,0x00,0x00, +/* 0x00003080: */ 0x68,0x30,0x00,0x00,0xE0,0x5D,0x00,0x00,0x34,0x54,0x52,0x41,0x43,0x45,0x2E,0x52, +/* 0x00003090: */ 0x45,0x53,0x54,0x4F,0x52,0x45,0x2E,0x53,0x54,0x41,0x54,0x45,0x32,0x00,0x00,0x00, +/* 0x000030A0: */ 0x88,0x30,0x00,0x00,0xF4,0x5D,0x00,0x00,0x30,0x54,0x52,0x41,0x43,0x45,0x2D,0x4C, +/* 0x000030B0: */ 0x4F,0x43,0x41,0x4C,0x53,0x2D,0x50,0x54,0x52,0x00,0x00,0x00,0xA8,0x30,0x00,0x00, +/* 0x000030C0: */ 0x04,0x5E,0x00,0x00,0x33,0x54,0x52,0x41,0x43,0x45,0x2E,0x28,0x4C,0x4F,0x43,0x41, +/* 0x000030D0: */ 0x4C,0x2E,0x45,0x4E,0x54,0x52,0x59,0x29,0xC4,0x30,0x00,0x00,0x90,0x5E,0x00,0x00, +/* 0x000030E0: */ 0x32,0x54,0x52,0x41,0x43,0x45,0x2E,0x28,0x4C,0x4F,0x43,0x41,0x4C,0x2E,0x45,0x58, +/* 0x000030F0: */ 0x49,0x54,0x29,0x00,0xE0,0x30,0x00,0x00,0xB0,0x5E,0x00,0x00,0x2E,0x54,0x52,0x41, +/* 0x00003100: */ 0x43,0x45,0x2E,0x28,0x4C,0x4F,0x43,0x41,0x4C,0x40,0x29,0x00,0xFC,0x30,0x00,0x00, +/* 0x00003110: */ 0xCC,0x5E,0x00,0x00,0x30,0x54,0x52,0x41,0x43,0x45,0x2E,0x28,0x31,0x5F,0x4C,0x4F, +/* 0x00003120: */ 0x43,0x41,0x4C,0x40,0x29,0x00,0x00,0x00,0x14,0x31,0x00,0x00,0xDC,0x5E,0x00,0x00, +/* 0x00003130: */ 0x30,0x54,0x52,0x41,0x43,0x45,0x2E,0x28,0x32,0x5F,0x4C,0x4F,0x43,0x41,0x4C,0x40, +/* 0x00003140: */ 0x29,0x00,0x00,0x00,0x30,0x31,0x00,0x00,0xEC,0x5E,0x00,0x00,0x30,0x54,0x52,0x41, +/* 0x00003150: */ 0x43,0x45,0x2E,0x28,0x33,0x5F,0x4C,0x4F,0x43,0x41,0x4C,0x40,0x29,0x00,0x00,0x00, +/* 0x00003160: */ 0x4C,0x31,0x00,0x00,0xFC,0x5E,0x00,0x00,0x30,0x54,0x52,0x41,0x43,0x45,0x2E,0x28, +/* 0x00003170: */ 0x34,0x5F,0x4C,0x4F,0x43,0x41,0x4C,0x40,0x29,0x00,0x00,0x00,0x68,0x31,0x00,0x00, +/* 0x00003180: */ 0x0C,0x5F,0x00,0x00,0x30,0x54,0x52,0x41,0x43,0x45,0x2E,0x28,0x35,0x5F,0x4C,0x4F, +/* 0x00003190: */ 0x43,0x41,0x4C,0x40,0x29,0x00,0x00,0x00,0x84,0x31,0x00,0x00,0x1C,0x5F,0x00,0x00, +/* 0x000031A0: */ 0x30,0x54,0x52,0x41,0x43,0x45,0x2E,0x28,0x36,0x5F,0x4C,0x4F,0x43,0x41,0x4C,0x40, +/* 0x000031B0: */ 0x29,0x00,0x00,0x00,0xA0,0x31,0x00,0x00,0x2C,0x5F,0x00,0x00,0x30,0x54,0x52,0x41, +/* 0x000031C0: */ 0x43,0x45,0x2E,0x28,0x37,0x5F,0x4C,0x4F,0x43,0x41,0x4C,0x40,0x29,0x00,0x00,0x00, +/* 0x000031D0: */ 0xBC,0x31,0x00,0x00,0x3C,0x5F,0x00,0x00,0x30,0x54,0x52,0x41,0x43,0x45,0x2E,0x28, +/* 0x000031E0: */ 0x38,0x5F,0x4C,0x4F,0x43,0x41,0x4C,0x40,0x29,0x00,0x00,0x00,0xD8,0x31,0x00,0x00, +/* 0x000031F0: */ 0x4C,0x5F,0x00,0x00,0x2E,0x54,0x52,0x41,0x43,0x45,0x2E,0x28,0x4C,0x4F,0x43,0x41, +/* 0x00003200: */ 0x4C,0x21,0x29,0x00,0xF4,0x31,0x00,0x00,0x68,0x5F,0x00,0x00,0x30,0x54,0x52,0x41, +/* 0x00003210: */ 0x43,0x45,0x2E,0x28,0x31,0x5F,0x4C,0x4F,0x43,0x41,0x4C,0x21,0x29,0x00,0x00,0x00, +/* 0x00003220: */ 0x0C,0x32,0x00,0x00,0x78,0x5F,0x00,0x00,0x30,0x54,0x52,0x41,0x43,0x45,0x2E,0x28, +/* 0x00003230: */ 0x32,0x5F,0x4C,0x4F,0x43,0x41,0x4C,0x21,0x29,0x00,0x00,0x00,0x28,0x32,0x00,0x00, +/* 0x00003240: */ 0x88,0x5F,0x00,0x00,0x30,0x54,0x52,0x41,0x43,0x45,0x2E,0x28,0x33,0x5F,0x4C,0x4F, +/* 0x00003250: */ 0x43,0x41,0x4C,0x21,0x29,0x00,0x00,0x00,0x44,0x32,0x00,0x00,0x98,0x5F,0x00,0x00, +/* 0x00003260: */ 0x30,0x54,0x52,0x41,0x43,0x45,0x2E,0x28,0x34,0x5F,0x4C,0x4F,0x43,0x41,0x4C,0x21, +/* 0x00003270: */ 0x29,0x00,0x00,0x00,0x60,0x32,0x00,0x00,0xA8,0x5F,0x00,0x00,0x30,0x54,0x52,0x41, +/* 0x00003280: */ 0x43,0x45,0x2E,0x28,0x35,0x5F,0x4C,0x4F,0x43,0x41,0x4C,0x21,0x29,0x00,0x00,0x00, +/* 0x00003290: */ 0x7C,0x32,0x00,0x00,0xB8,0x5F,0x00,0x00,0x30,0x54,0x52,0x41,0x43,0x45,0x2E,0x28, +/* 0x000032A0: */ 0x36,0x5F,0x4C,0x4F,0x43,0x41,0x4C,0x21,0x29,0x00,0x00,0x00,0x98,0x32,0x00,0x00, +/* 0x000032B0: */ 0xC8,0x5F,0x00,0x00,0x30,0x54,0x52,0x41,0x43,0x45,0x2E,0x28,0x37,0x5F,0x4C,0x4F, +/* 0x000032C0: */ 0x43,0x41,0x4C,0x21,0x29,0x00,0x00,0x00,0xB4,0x32,0x00,0x00,0xD8,0x5F,0x00,0x00, +/* 0x000032D0: */ 0x30,0x54,0x52,0x41,0x43,0x45,0x2E,0x28,0x38,0x5F,0x4C,0x4F,0x43,0x41,0x4C,0x21, +/* 0x000032E0: */ 0x29,0x00,0x00,0x00,0xD0,0x32,0x00,0x00,0xE8,0x5F,0x00,0x00,0x2F,0x54,0x52,0x41, +/* 0x000032F0: */ 0x43,0x45,0x2E,0x28,0x4C,0x4F,0x43,0x41,0x4C,0x2B,0x21,0x29,0xEC,0x32,0x00,0x00, +/* 0x00003300: */ 0x04,0x60,0x00,0x00,0x2B,0x54,0x52,0x41,0x43,0x45,0x2E,0x28,0x3F,0x44,0x4F,0x29, +/* 0x00003310: */ 0x04,0x33,0x00,0x00,0x6C,0x60,0x00,0x00,0x2C,0x54,0x52,0x41,0x43,0x45,0x2E,0x28, +/* 0x00003320: */ 0x4C,0x4F,0x4F,0x50,0x29,0x00,0x00,0x00,0x18,0x33,0x00,0x00,0xF0,0x60,0x00,0x00, +/* 0x00003330: */ 0x2D,0x54,0x52,0x41,0x43,0x45,0x2E,0x28,0x2B,0x4C,0x4F,0x4F,0x50,0x29,0x00,0x00, +/* 0x00003340: */ 0x30,0x33,0x00,0x00,0xD4,0x61,0x00,0x00,0x2E,0x54,0x52,0x41,0x43,0x45,0x2E,0x43, +/* 0x00003350: */ 0x48,0x45,0x43,0x4B,0x2E,0x49,0x50,0x00,0x48,0x33,0x00,0x00,0x40,0x62,0x00,0x00, +/* 0x00003360: */ 0x2D,0x54,0x52,0x41,0x43,0x45,0x2E,0x53,0x48,0x4F,0x57,0x2E,0x49,0x50,0x00,0x00, +/* 0x00003370: */ 0x60,0x33,0x00,0x00,0x88,0x62,0x00,0x00,0x30,0x54,0x52,0x41,0x43,0x45,0x2E,0x53, +/* 0x00003380: */ 0x48,0x4F,0x57,0x2E,0x53,0x54,0x41,0x43,0x4B,0x00,0x00,0x00,0x78,0x33,0x00,0x00, +/* 0x00003390: */ 0x60,0x63,0x00,0x00,0x2F,0x54,0x52,0x41,0x43,0x45,0x2E,0x53,0x48,0x4F,0x57,0x2E, +/* 0x000033A0: */ 0x4E,0x45,0x58,0x54,0x94,0x33,0x00,0x00,0x6C,0x65,0x00,0x00,0x32,0x54,0x52,0x41, +/* 0x000033B0: */ 0x43,0x45,0x2E,0x44,0x4F,0x2E,0x50,0x52,0x49,0x4D,0x49,0x54,0x49,0x56,0x45,0x00, +/* 0x000033C0: */ 0xAC,0x33,0x00,0x00,0xAC,0x6D,0x00,0x00,0x2D,0x54,0x52,0x41,0x43,0x45,0x2E,0x44, +/* 0x000033D0: */ 0x4F,0x2E,0x4E,0x45,0x58,0x54,0x00,0x00,0xC8,0x33,0x00,0x00,0xC0,0x6E,0x00,0x00, +/* 0x000033E0: */ 0x2A,0x54,0x52,0x41,0x43,0x45,0x2E,0x4E,0x45,0x58,0x54,0x00,0xE0,0x33,0x00,0x00, +/* 0x000033F0: */ 0x44,0x6F,0x00,0x00,0x05,0x54,0x52,0x41,0x43,0x45,0x00,0x00,0xF4,0x33,0x00,0x00, +/* 0x00003400: */ 0xF0,0x6F,0x00,0x00,0x01,0x53,0x00,0x00,0x04,0x34,0x00,0x00,0x28,0x70,0x00,0x00, +/* 0x00003410: */ 0x02,0x53,0x44,0x00,0x10,0x34,0x00,0x00,0x64,0x70,0x00,0x00,0x02,0x53,0x4D,0x00, +/* 0x00003420: */ 0x1C,0x34,0x00,0x00,0xB4,0x70,0x00,0x00,0x0A,0x54,0x52,0x41,0x43,0x45,0x2E,0x55, +/* 0x00003430: */ 0x53,0x45,0x52,0x00,0x28,0x34,0x00,0x00,0xC0,0x70,0x00,0x00,0x02,0x47,0x44,0x00, +/* 0x00003440: */ 0x3C,0x34,0x00,0x00,0x64,0x72,0x00,0x00,0x01,0x47,0x00,0x00,0x48,0x34,0x00,0x00, +/* 0x00003450: */ 0x74,0x72,0x00,0x00,0x0A,0x54,0x52,0x41,0x43,0x45,0x2E,0x48,0x45,0x4C,0x50,0x00, +/* 0x00003460: */ 0x54,0x34,0x00,0x00,0x78,0x00,0x00,0x00,0x04,0x3B,0x3B,0x3B,0x3B,0x00,0x00,0x00, +/* 0x00003470: */ 0x68,0x34,0x00,0x00,0x78,0x00,0x00,0x00,0x0E,0x3A,0x3A,0x3A,0x3A,0x74,0x65,0x72, +/* 0x00003480: */ 0x6D,0x69,0x6F,0x2E,0x66,0x74,0x68,0x00,0x78,0x34,0x00,0x00,0xD8,0x73,0x00,0x00, +/* 0x00003490: */ 0x0F,0x54,0x41,0x53,0x4B,0x2D,0x54,0x45,0x52,0x4D,0x49,0x4F,0x2E,0x46,0x54,0x48, +/* 0x000034A0: */ 0x90,0x34,0x00,0x00,0xE8,0x73,0x00,0x00,0x0F,0x41,0x53,0x43,0x49,0x49,0x5F,0x42, +/* 0x000034B0: */ 0x41,0x43,0x4B,0x53,0x50,0x41,0x43,0x45,0xA8,0x34,0x00,0x00,0xF8,0x73,0x00,0x00, +/* 0x000034C0: */ 0x0C,0x41,0x53,0x43,0x49,0x49,0x5F,0x44,0x45,0x4C,0x45,0x54,0x45,0x00,0x00,0x00, +/* 0x000034D0: */ 0xC0,0x34,0x00,0x00,0x08,0x74,0x00,0x00,0x0C,0x41,0x53,0x43,0x49,0x49,0x5F,0x45, +/* 0x000034E0: */ 0x53,0x43,0x41,0x50,0x45,0x00,0x00,0x00,0xD8,0x34,0x00,0x00,0x18,0x74,0x00,0x00, +/* 0x000034F0: */ 0x0C,0x41,0x53,0x43,0x49,0x49,0x5F,0x43,0x54,0x52,0x4C,0x5F,0x41,0x00,0x00,0x00, +/* 0x00003500: */ 0xF0,0x34,0x00,0x00,0x28,0x74,0x00,0x00,0x0C,0x41,0x53,0x43,0x49,0x49,0x5F,0x43, +/* 0x00003510: */ 0x54,0x52,0x4C,0x5F,0x45,0x00,0x00,0x00,0x08,0x35,0x00,0x00,0x38,0x74,0x00,0x00, +/* 0x00003520: */ 0x0C,0x41,0x53,0x43,0x49,0x49,0x5F,0x43,0x54,0x52,0x4C,0x5F,0x58,0x00,0x00,0x00, +/* 0x00003530: */ 0x20,0x35,0x00,0x00,0x48,0x74,0x00,0x00,0x04,0x45,0x53,0x43,0x5B,0x00,0x00,0x00, +/* 0x00003540: */ 0x38,0x35,0x00,0x00,0x60,0x74,0x00,0x00,0x03,0x43,0x4C,0x53,0x48,0x35,0x00,0x00, +/* 0x00003550: */ 0x70,0x74,0x00,0x00,0x0D,0x54,0x49,0x4F,0x2E,0x42,0x41,0x43,0x4B,0x57,0x41,0x52, +/* 0x00003560: */ 0x44,0x53,0x00,0x00,0x54,0x35,0x00,0x00,0xAC,0x74,0x00,0x00,0x0C,0x54,0x49,0x4F, +/* 0x00003570: */ 0x2E,0x46,0x4F,0x52,0x57,0x41,0x52,0x44,0x53,0x00,0x00,0x00,0x6C,0x35,0x00,0x00, +/* 0x00003580: */ 0xE8,0x74,0x00,0x00,0x0D,0x54,0x49,0x4F,0x2E,0x45,0x52,0x41,0x53,0x45,0x2E,0x45, +/* 0x00003590: */ 0x4F,0x4C,0x00,0x00,0x84,0x35,0x00,0x00,0xFC,0x74,0x00,0x00,0x04,0x42,0x45,0x4C, +/* 0x000035A0: */ 0x4C,0x00,0x00,0x00,0x9C,0x35,0x00,0x00,0x0C,0x75,0x00,0x00,0x09,0x42,0x41,0x43, +/* 0x000035B0: */ 0x4B,0x53,0x50,0x41,0x43,0x45,0x00,0x00,0xAC,0x35,0x00,0x00,0x78,0x00,0x00,0x00, +/* 0x000035C0: */ 0x04,0x3B,0x3B,0x3B,0x3B,0x00,0x00,0x00,0xC0,0x35,0x00,0x00,0x78,0x00,0x00,0x00, +/* 0x000035D0: */ 0x0F,0x3A,0x3A,0x3A,0x3A,0x68,0x69,0x73,0x74,0x6F,0x72,0x79,0x2E,0x66,0x74,0x68, +/* 0x000035E0: */ 0xD0,0x35,0x00,0x00,0x2C,0x75,0x00,0x00,0x10,0x54,0x41,0x53,0x4B,0x2D,0x48,0x49, +/* 0x000035F0: */ 0x53,0x54,0x4F,0x52,0x59,0x2E,0x46,0x54,0x48,0x00,0x00,0x00,0xE8,0x35,0x00,0x00, +/* 0x00003600: */ 0x3C,0x75,0x00,0x00,0x0F,0x4B,0x48,0x5F,0x48,0x49,0x53,0x54,0x4F,0x52,0x59,0x5F, +/* 0x00003610: */ 0x53,0x49,0x5A,0x45,0x04,0x36,0x00,0x00,0x4C,0x75,0x00,0x00,0x0A,0x4B,0x48,0x2D, +/* 0x00003620: */ 0x48,0x49,0x53,0x54,0x4F,0x52,0x59,0x00,0x1C,0x36,0x00,0x00,0x58,0x7D,0x00,0x00, +/* 0x00003630: */ 0x12,0x4B,0x48,0x5F,0x4C,0x49,0x4E,0x45,0x5F,0x45,0x58,0x54,0x52,0x41,0x5F,0x53, +/* 0x00003640: */ 0x49,0x5A,0x45,0x00,0x30,0x36,0x00,0x00,0x68,0x7D,0x00,0x00,0x06,0x4B,0x48,0x2D, +/* 0x00003650: */ 0x45,0x4E,0x44,0x00,0x4C,0x36,0x00,0x00,0x78,0x7D,0x00,0x00,0x08,0x4C,0x49,0x4E, +/* 0x00003660: */ 0x45,0x4E,0x55,0x4D,0x40,0x00,0x00,0x00,0x5C,0x36,0x00,0x00,0xA0,0x7D,0x00,0x00, +/* 0x00003670: */ 0x08,0x4C,0x49,0x4E,0x45,0x4E,0x55,0x4D,0x21,0x00,0x00,0x00,0x70,0x36,0x00,0x00, +/* 0x00003680: */ 0xC4,0x7D,0x00,0x00,0x07,0x4B,0x48,0x2D,0x4C,0x4F,0x4F,0x4B,0x84,0x36,0x00,0x00, +/* 0x00003690: */ 0xD4,0x7D,0x00,0x00,0x06,0x4B,0x48,0x2D,0x4D,0x41,0x58,0x00,0x94,0x36,0x00,0x00, +/* 0x000036A0: */ 0xE4,0x7D,0x00,0x00,0x0A,0x4B,0x48,0x2D,0x43,0x4F,0x55,0x4E,0x54,0x45,0x52,0x00, +/* 0x000036B0: */ 0xA4,0x36,0x00,0x00,0xF4,0x7D,0x00,0x00,0x07,0x4B,0x48,0x2D,0x53,0x50,0x41,0x4E, +/* 0x000036C0: */ 0xB8,0x36,0x00,0x00,0x04,0x7E,0x00,0x00,0x0D,0x4B,0x48,0x2D,0x4D,0x41,0x54,0x43, +/* 0x000036D0: */ 0x48,0x2D,0x53,0x50,0x41,0x4E,0x00,0x00,0xC8,0x36,0x00,0x00,0x14,0x7E,0x00,0x00, +/* 0x000036E0: */ 0x09,0x4B,0x48,0x2D,0x43,0x55,0x52,0x53,0x4F,0x52,0x00,0x00,0xE0,0x36,0x00,0x00, +/* 0x000036F0: */ 0x24,0x7E,0x00,0x00,0x0A,0x4B,0x48,0x2D,0x41,0x44,0x44,0x52,0x45,0x53,0x53,0x00, +/* 0x00003700: */ 0xF4,0x36,0x00,0x00,0x34,0x7E,0x00,0x00,0x09,0x4B,0x48,0x2D,0x49,0x4E,0x53,0x49, +/* 0x00003710: */ 0x44,0x45,0x00,0x00,0x08,0x37,0x00,0x00,0x44,0x7E,0x00,0x00,0x0C,0x4B,0x48,0x2E, +/* 0x00003720: */ 0x4D,0x41,0x4B,0x45,0x2E,0x52,0x4F,0x4F,0x4D,0x00,0x00,0x00,0x1C,0x37,0x00,0x00, +/* 0x00003730: */ 0x78,0x7E,0x00,0x00,0x0E,0x4B,0x48,0x2E,0x4E,0x45,0x57,0x45,0x53,0x54,0x2E,0x4C, +/* 0x00003740: */ 0x49,0x4E,0x45,0x00,0x34,0x37,0x00,0x00,0x84,0x7E,0x00,0x00,0x09,0x4B,0x48,0x2E, +/* 0x00003750: */ 0x52,0x45,0x57,0x49,0x4E,0x44,0x00,0x00,0x4C,0x37,0x00,0x00,0x98,0x7E,0x00,0x00, +/* 0x00003760: */ 0x0F,0x4B,0x48,0x2E,0x43,0x55,0x52,0x52,0x45,0x4E,0x54,0x2E,0x41,0x44,0x44,0x52, +/* 0x00003770: */ 0x60,0x37,0x00,0x00,0xAC,0x7E,0x00,0x00,0x0F,0x4B,0x48,0x2E,0x43,0x55,0x52,0x52, +/* 0x00003780: */ 0x45,0x4E,0x54,0x2E,0x4C,0x49,0x4E,0x45,0x78,0x37,0x00,0x00,0xB8,0x7E,0x00,0x00, +/* 0x00003790: */ 0x0A,0x4B,0x48,0x2E,0x43,0x4F,0x4D,0x50,0x41,0x52,0x45,0x00,0x90,0x37,0x00,0x00, +/* 0x000037A0: */ 0xC8,0x7E,0x00,0x00,0x0B,0x4B,0x48,0x2E,0x4E,0x55,0x4D,0x2E,0x41,0x44,0x44,0x52, +/* 0x000037B0: */ 0xA4,0x37,0x00,0x00,0xD4,0x7E,0x00,0x00,0x0E,0x4B,0x48,0x2E,0x43,0x55,0x52,0x52, +/* 0x000037C0: */ 0x45,0x4E,0x54,0x2E,0x4E,0x55,0x4D,0x00,0xB8,0x37,0x00,0x00,0xE0,0x7E,0x00,0x00, +/* 0x000037D0: */ 0x09,0x4B,0x48,0x2E,0x41,0x44,0x44,0x52,0x2B,0x2B,0x00,0x00,0xD0,0x37,0x00,0x00, +/* 0x000037E0: */ 0xF8,0x7E,0x00,0x00,0x09,0x4B,0x48,0x2E,0x41,0x44,0x44,0x52,0x2D,0x2D,0x00,0x00, +/* 0x000037F0: */ 0xE4,0x37,0x00,0x00,0x18,0x7F,0x00,0x00,0x10,0x4B,0x48,0x2E,0x45,0x4E,0x44,0x43, +/* 0x00003800: */ 0x4F,0x55,0x4E,0x54,0x2E,0x41,0x44,0x44,0x52,0x00,0x00,0x00,0xF8,0x37,0x00,0x00, +/* 0x00003810: */ 0x24,0x7F,0x00,0x00,0x0B,0x4B,0x48,0x2E,0x41,0x44,0x44,0x2E,0x4C,0x49,0x4E,0x45, +/* 0x00003820: */ 0x14,0x38,0x00,0x00,0x0C,0x80,0x00,0x00,0x0E,0x4B,0x48,0x2E,0x42,0x41,0x43,0x4B, +/* 0x00003830: */ 0x55,0x50,0x2E,0x4C,0x49,0x4E,0x45,0x00,0x28,0x38,0x00,0x00,0x90,0x80,0x00,0x00, +/* 0x00003840: */ 0x0F,0x4B,0x48,0x2E,0x46,0x4F,0x52,0x57,0x41,0x52,0x44,0x2E,0x4C,0x49,0x4E,0x45, +/* 0x00003850: */ 0x40,0x38,0x00,0x00,0xC8,0x80,0x00,0x00,0x0E,0x4B,0x48,0x2E,0x4F,0x4C,0x44,0x45, +/* 0x00003860: */ 0x53,0x54,0x2E,0x4C,0x49,0x4E,0x45,0x00,0x58,0x38,0x00,0x00,0xF0,0x80,0x00,0x00, +/* 0x00003870: */ 0x0C,0x4B,0x48,0x2E,0x46,0x49,0x4E,0x44,0x2E,0x4C,0x49,0x4E,0x45,0x00,0x00,0x00, +/* 0x00003880: */ 0x70,0x38,0x00,0x00,0x5C,0x81,0x00,0x00,0x09,0x4B,0x48,0x2D,0x42,0x55,0x46,0x46, +/* 0x00003890: */ 0x45,0x52,0x00,0x00,0x88,0x38,0x00,0x00,0x68,0x81,0x00,0x00,0x09,0x4B,0x48,0x2E, +/* 0x000038A0: */ 0x52,0x45,0x54,0x55,0x52,0x4E,0x00,0x00,0x9C,0x38,0x00,0x00,0x88,0x81,0x00,0x00, +/* 0x000038B0: */ 0x0F,0x4B,0x48,0x2E,0x52,0x45,0x50,0x4C,0x41,0x43,0x45,0x2E,0x4C,0x49,0x4E,0x45, +/* 0x000038C0: */ 0xB0,0x38,0x00,0x00,0xC0,0x81,0x00,0x00,0x0C,0x4B,0x48,0x2E,0x47,0x45,0x54,0x2E, +/* 0x000038D0: */ 0x4D,0x41,0x54,0x43,0x48,0x00,0x00,0x00,0xC8,0x38,0x00,0x00,0x2C,0x82,0x00,0x00, +/* 0x000038E0: */ 0x0C,0x4B,0x48,0x2E,0x46,0x41,0x52,0x2E,0x52,0x49,0x47,0x48,0x54,0x00,0x00,0x00, +/* 0x000038F0: */ 0xE0,0x38,0x00,0x00,0x74,0x82,0x00,0x00,0x0B,0x4B,0x48,0x2E,0x46,0x41,0x52,0x2E, +/* 0x00003900: */ 0x4C,0x45,0x46,0x54,0xF8,0x38,0x00,0x00,0x84,0x82,0x00,0x00,0x0C,0x4B,0x48,0x2E, +/* 0x00003910: */ 0x47,0x45,0x54,0x2E,0x4F,0x4C,0x44,0x45,0x52,0x00,0x00,0x00,0x0C,0x39,0x00,0x00, +/* 0x00003920: */ 0xB0,0x82,0x00,0x00,0x0C,0x4B,0x48,0x2E,0x47,0x45,0x54,0x2E,0x4E,0x45,0x57,0x45, +/* 0x00003930: */ 0x52,0x00,0x00,0x00,0x24,0x39,0x00,0x00,0xE4,0x82,0x00,0x00,0x0D,0x4B,0x48,0x2E, +/* 0x00003940: */ 0x43,0x4C,0x45,0x41,0x52,0x2E,0x4C,0x49,0x4E,0x45,0x00,0x00,0x3C,0x39,0x00,0x00, +/* 0x00003950: */ 0x04,0x83,0x00,0x00,0x0B,0x4B,0x48,0x2E,0x47,0x4F,0x2E,0x52,0x49,0x47,0x48,0x54, +/* 0x00003960: */ 0x54,0x39,0x00,0x00,0x40,0x83,0x00,0x00,0x0A,0x4B,0x48,0x2E,0x47,0x4F,0x2E,0x4C, +/* 0x00003970: */ 0x45,0x46,0x54,0x00,0x68,0x39,0x00,0x00,0x70,0x83,0x00,0x00,0x0A,0x4B,0x48,0x2E, +/* 0x00003980: */ 0x52,0x45,0x46,0x52,0x45,0x53,0x48,0x00,0x7C,0x39,0x00,0x00,0xB8,0x83,0x00,0x00, +/* 0x00003990: */ 0x0C,0x4B,0x48,0x2E,0x42,0x41,0x43,0x4B,0x53,0x50,0x41,0x43,0x45,0x00,0x00,0x00, +/* 0x000039A0: */ 0x90,0x39,0x00,0x00,0x48,0x84,0x00,0x00,0x09,0x4B,0x48,0x2E,0x44,0x45,0x4C,0x45, +/* 0x000039B0: */ 0x54,0x45,0x00,0x00,0xA8,0x39,0x00,0x00,0xB8,0x84,0x00,0x00,0x15,0x4B,0x48,0x2E, +/* 0x000039C0: */ 0x48,0x41,0x4E,0x44,0x4C,0x45,0x2E,0x57,0x49,0x4E,0x44,0x4F,0x57,0x53,0x2E,0x4B, +/* 0x000039D0: */ 0x45,0x59,0x00,0x00,0xBC,0x39,0x00,0x00,0x38,0x86,0x00,0x00,0x12,0x4B,0x48,0x2E, +/* 0x000039E0: */ 0x48,0x41,0x4E,0x44,0x4C,0x45,0x2E,0x41,0x4E,0x53,0x49,0x2E,0x4B,0x45,0x59,0x00, +/* 0x000039F0: */ 0xDC,0x39,0x00,0x00,0xE0,0x86,0x00,0x00,0x0E,0x4B,0x48,0x2E,0x53,0x50,0x45,0x43, +/* 0x00003A00: */ 0x49,0x41,0x4C,0x2E,0x4B,0x45,0x59,0x00,0xF8,0x39,0x00,0x00,0x48,0x88,0x00,0x00, +/* 0x00003A10: */ 0x0C,0x4B,0x48,0x2E,0x53,0x4D,0x41,0x52,0x54,0x2E,0x4B,0x45,0x59,0x00,0x00,0x00, +/* 0x00003A20: */ 0x10,0x3A,0x00,0x00,0x6C,0x88,0x00,0x00,0x0A,0x4B,0x48,0x2E,0x49,0x4E,0x53,0x43, +/* 0x00003A30: */ 0x48,0x41,0x52,0x00,0x28,0x3A,0x00,0x00,0x38,0x89,0x00,0x00,0x04,0x45,0x4F,0x4C, +/* 0x00003A40: */ 0x3F,0x00,0x00,0x00,0x3C,0x3A,0x00,0x00,0x60,0x89,0x00,0x00,0x0A,0x4B,0x48,0x2E, +/* 0x00003A50: */ 0x47,0x45,0x54,0x4C,0x49,0x4E,0x45,0x00,0x4C,0x3A,0x00,0x00,0x1C,0x8A,0x00,0x00, +/* 0x00003A60: */ 0x09,0x4B,0x48,0x2E,0x41,0x43,0x43,0x45,0x50,0x54,0x00,0x00,0x60,0x3A,0x00,0x00, +/* 0x00003A70: */ 0x5C,0x8A,0x00,0x00,0x0C,0x54,0x45,0x53,0x54,0x2E,0x48,0x49,0x53,0x54,0x4F,0x52, +/* 0x00003A80: */ 0x59,0x00,0x00,0x00,0x74,0x3A,0x00,0x00,0xA0,0x8A,0x00,0x00,0x08,0x48,0x49,0x53, +/* 0x00003A90: */ 0x54,0x4F,0x52,0x59,0x23,0x00,0x00,0x00,0x8C,0x3A,0x00,0x00,0xF8,0x8A,0x00,0x00, +/* 0x00003AA0: */ 0x07,0x48,0x49,0x53,0x54,0x4F,0x52,0x59,0xA0,0x3A,0x00,0x00,0x38,0x8B,0x00,0x00, +/* 0x00003AB0: */ 0x02,0x58,0x58,0x00,0xB0,0x3A,0x00,0x00,0x54,0x8B,0x00,0x00,0x0D,0x48,0x49,0x53, +/* 0x00003AC0: */ 0x54,0x4F,0x52,0x59,0x2E,0x52,0x45,0x53,0x45,0x54,0x00,0x00,0xBC,0x3A,0x00,0x00, +/* 0x00003AD0: */ 0x6C,0x8B,0x00,0x00,0x0A,0x48,0x49,0x53,0x54,0x4F,0x52,0x59,0x2E,0x4F,0x4E,0x00, +/* 0x00003AE0: */ 0xD4,0x3A,0x00,0x00,0xA8,0x8B,0x00,0x00,0x0B,0x48,0x49,0x53,0x54,0x4F,0x52,0x59, +/* 0x00003AF0: */ 0x2E,0x4F,0x46,0x46,0xE8,0x3A,0x00,0x00,0xE0,0x8B,0x00,0x00,0x09,0x41,0x55,0x54, +/* 0x00003B00: */ 0x4F,0x2E,0x49,0x4E,0x49,0x54,0x00,0x00,0xFC,0x3A,0x00,0x00,0xEC,0x8B,0x00,0x00, +/* 0x00003B10: */ 0x09,0x41,0x55,0x54,0x4F,0x2E,0x54,0x45,0x52,0x4D,0x00,0x00,0x10,0x3B,0x00,0x00, +/* 0x00003B20: */ 0x78,0x00,0x00,0x00,0x04,0x3B,0x3B,0x3B,0x3B,0x00,0x00,0x00,0x24,0x3B,0x00,0x00, +/* 0x00003B30: */ 0x78,0x00,0x00,0x00,0x10,0x3A,0x3A,0x3A,0x3A,0x73,0x61,0x76,0x65,0x64,0x69,0x63, +/* 0x00003B40: */ 0x64,0x2E,0x66,0x74,0x68,0x00,0x00,0x00,0x34,0x3B,0x00,0x00,0x00,0x8C,0x00,0x00, +/* 0x00003B50: */ 0x15,0x54,0x41,0x53,0x4B,0x2D,0x53,0x41,0x56,0x45,0x5F,0x44,0x49,0x43,0x5F,0x41, +/* 0x00003B60: */ 0x53,0x5F,0x44,0x41,0x54,0x41,0x00,0x00,0x50,0x3B,0x00,0x00,0x10,0x8C,0x00,0x00, +/* 0x00003B70: */ 0x10,0x53,0x44,0x41,0x44,0x5F,0x4E,0x41,0x4D,0x45,0x53,0x5F,0x45,0x58,0x54,0x52, +/* 0x00003B80: */ 0x41,0x00,0x00,0x00,0x70,0x3B,0x00,0x00,0x20,0x8C,0x00,0x00,0x0F,0x53,0x44,0x41, +/* 0x00003B90: */ 0x44,0x5F,0x43,0x4F,0x44,0x45,0x5F,0x45,0x58,0x54,0x52,0x41,0x8C,0x3B,0x00,0x00, +/* 0x00003BA0: */ 0x30,0x8C,0x00,0x00,0x10,0x53,0x44,0x41,0x44,0x5F,0x42,0x55,0x46,0x46,0x45,0x52, +/* 0x00003BB0: */ 0x5F,0x53,0x49,0x5A,0x45,0x00,0x00,0x00,0xA4,0x3B,0x00,0x00,0x40,0x8C,0x00,0x00, +/* 0x00003BC0: */ 0x0B,0x53,0x44,0x41,0x44,0x2D,0x42,0x55,0x46,0x46,0x45,0x52,0xC0,0x3B,0x00,0x00, +/* 0x00003BD0: */ 0x4C,0x8D,0x00,0x00,0x11,0x53,0x44,0x41,0x44,0x2D,0x42,0x55,0x46,0x46,0x45,0x52, +/* 0x00003BE0: */ 0x2D,0x49,0x4E,0x44,0x45,0x58,0x00,0x00,0xD4,0x3B,0x00,0x00,0x5C,0x8D,0x00,0x00, +/* 0x00003BF0: */ 0x0F,0x53,0x44,0x41,0x44,0x2D,0x42,0x55,0x46,0x46,0x45,0x52,0x2D,0x46,0x49,0x44, +/* 0x00003C00: */ 0xF0,0x3B,0x00,0x00,0x6C,0x8D,0x00,0x00,0x0A,0x53,0x44,0x41,0x44,0x2E,0x46,0x4C, +/* 0x00003C10: */ 0x55,0x53,0x48,0x00,0x08,0x3C,0x00,0x00,0x98,0x8D,0x00,0x00,0x09,0x53,0x44,0x41, +/* 0x00003C20: */ 0x44,0x2E,0x45,0x4D,0x49,0x54,0x00,0x00,0x1C,0x3C,0x00,0x00,0xF8,0x8D,0x00,0x00, +/* 0x00003C30: */ 0x09,0x53,0x44,0x41,0x44,0x2E,0x54,0x59,0x50,0x45,0x00,0x00,0x30,0x3C,0x00,0x00, +/* 0x00003C40: */ 0x24,0x8E,0x00,0x00,0x0A,0x24,0x53,0x44,0x41,0x44,0x2E,0x4C,0x49,0x4E,0x45,0x00, +/* 0x00003C50: */ 0x44,0x3C,0x00,0x00,0x38,0x8E,0x00,0x00,0x05,0x28,0x55,0x38,0x2E,0x29,0x00,0x00, +/* 0x00003C60: */ 0x58,0x3C,0x00,0x00,0x6C,0x8E,0x00,0x00,0x05,0x28,0x55,0x32,0x2E,0x29,0x00,0x00, +/* 0x00003C70: */ 0x68,0x3C,0x00,0x00,0x88,0x8E,0x00,0x00,0x0A,0x53,0x44,0x41,0x44,0x2E,0x43,0x4C, +/* 0x00003C80: */ 0x4F,0x53,0x45,0x00,0x78,0x3C,0x00,0x00,0xD8,0x8E,0x00,0x00,0x09,0x53,0x44,0x41, +/* 0x00003C90: */ 0x44,0x2E,0x4F,0x50,0x45,0x4E,0x00,0x00,0x8C,0x3C,0x00,0x00,0x4C,0x8F,0x00,0x00, +/* 0x00003CA0: */ 0x0D,0x53,0x44,0x41,0x44,0x2E,0x44,0x55,0x4D,0x50,0x2E,0x48,0x45,0x58,0x00,0x00, +/* 0x00003CB0: */ 0xA0,0x3C,0x00,0x00,0x94,0x8F,0x00,0x00,0x0E,0x53,0x44,0x41,0x44,0x2E,0x44,0x55, +/* 0x00003CC0: */ 0x4D,0x50,0x2E,0x48,0x45,0x58,0x2C,0x00,0xB8,0x3C,0x00,0x00,0xB4,0x8F,0x00,0x00, +/* 0x00003CD0: */ 0x12,0x53,0x44,0x41,0x44,0x2E,0x44,0x55,0x4D,0x50,0x2E,0x48,0x45,0x58,0x2E,0x42, +/* 0x00003CE0: */ 0x59,0x54,0x45,0x00,0xD0,0x3C,0x00,0x00,0xFC,0x8F,0x00,0x00,0x13,0x53,0x44,0x41, +/* 0x00003CF0: */ 0x44,0x2E,0x44,0x55,0x4D,0x50,0x2E,0x48,0x45,0x58,0x2E,0x42,0x59,0x54,0x45,0x2C, +/* 0x00003D00: */ 0xEC,0x3C,0x00,0x00,0x10,0x90,0x00,0x00,0x0E,0x53,0x44,0x41,0x44,0x2E,0x44,0x55, +/* 0x00003D10: */ 0x4D,0x50,0x2E,0x44,0x41,0x54,0x41,0x00,0x08,0x3D,0x00,0x00,0x54,0x91,0x00,0x00, +/* 0x00003D20: */ 0x0B,0x53,0x44,0x41,0x44,0x2E,0x44,0x45,0x46,0x49,0x4E,0x45,0x20,0x3D,0x00,0x00, +/* 0x00003D30: */ 0xA8,0x91,0x00,0x00,0x11,0x49,0x53,0x2E,0x4C,0x49,0x54,0x54,0x4C,0x45,0x2E,0x45, +/* 0x00003D40: */ 0x4E,0x44,0x49,0x41,0x4E,0x3F,0x00,0x00,0x34,0x3D,0x00,0x00,0xC4,0x91,0x00,0x00, +/* 0x00003D50: */ 0x04,0x53,0x44,0x41,0x44,0x00,0x00,0x00,0x50,0x3D,0x00,0x00,0xC0,0x93,0x00,0x00, +/* 0x00003D60: */ 0x09,0x41,0x55,0x54,0x4F,0x2E,0x49,0x4E,0x49,0x54,0x00,0x00,0x60,0x3D,0x00,0x00, +/* 0x00003D70: */ 0x78,0x00,0x00,0x00,0x04,0x3B,0x3B,0x3B,0x3B,0x00,0x00,0x00,0x74,0x3D,0x00,0x00, +/* 0x00003D80: */ 0x78,0x00,0x00,0x00,0x04,0x3B,0x3B,0x3B,0x3B,0x00,0x00,0x00,0x84,0x3D,0x00,0x00, +/* 0x00003D90: */ 0xE8,0x93,0x00,0x00,0x04,0x3B,0x3B,0x3B,0x3B,0x00,0x00,0x00, +0x00,0x00,0x00,0x00, +}; +static const uint8_t MinDicCode[] = { +/* 0x00000000: */ 0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x00000010: */ 0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x00000020: */ 0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x00000030: */ 0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x00000040: */ 0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x00000050: */ 0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x00000060: */ 0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x00000070: */ 0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x00000080: */ 0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x00000090: */ 0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x000000A0: */ 0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x000000B0: */ 0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x000000C0: */ 0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x2D,0x00,0x00,0x00,0x1C,0x8A,0x00,0x00, +/* 0x000000D0: */ 0x00,0x00,0x00,0x00,0x2D,0x00,0x00,0x00,0x3D,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000000E0: */ 0x2D,0x00,0x00,0x00,0xC8,0x1B,0x00,0x00,0x00,0x00,0x00,0x00,0x2D,0x00,0x00,0x00, +/* 0x000000F0: */ 0x83,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x17,0x00,0x00,0x00,0x00,0x00,0x00,0x81, +/* 0x00000100: */ 0x00,0x00,0x00,0x00,0x17,0x00,0x00,0x00,0x01,0x00,0x00,0x02,0x00,0x00,0x00,0x00, +/* 0x00000110: */ 0x00,0x00,0x00,0x00,0xA8,0x00,0x00,0x00,0x41,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00000120: */ 0x59,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x01,0x00,0x00, +/* 0x00000130: */ 0x35,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x20,0x01,0x00,0x00,0x7A,0x00,0x00,0x00, +/* 0x00000140: */ 0x9C,0x00,0x00,0x00,0x2B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00000150: */ 0x29,0x00,0x00,0x00,0xB8,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00000160: */ 0x3E,0x00,0x00,0x00,0xB8,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00000170: */ 0x35,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x9C,0x00,0x00,0x00,0x18,0x00,0x00,0x00, +/* 0x00000180: */ 0x00,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0x9C,0x00,0x00,0x00, +/* 0x00000190: */ 0x9B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000001A0: */ 0x9C,0x00,0x00,0x00,0x9B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC2,0x00,0x00,0x00, +/* 0x000001B0: */ 0x7D,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC2,0x00,0x00,0x00,0x75,0x00,0x00,0x00, +/* 0x000001C0: */ 0x00,0x00,0x00,0x00,0xC3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00, +/* 0x000001D0: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x88,0x00,0x00,0x00,0x88,0x00,0x00,0x00, +/* 0x000001E0: */ 0x00,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x7C,0x00,0x00,0x00, +/* 0x000001F0: */ 0x59,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x7C,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00000200: */ 0x02,0x00,0x00,0x00,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x33,0x00,0x00,0x00, +/* 0x00000210: */ 0x33,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x9C,0x00,0x00,0x00,0x33,0x00,0x00,0x00, +/* 0x00000220: */ 0x00,0x00,0x00,0x00,0x9C,0x00,0x00,0x00,0x7B,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00000230: */ 0x1F,0x00,0x00,0x00,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x00, +/* 0x00000240: */ 0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF, +/* 0x00000250: */ 0xBB,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00000260: */ 0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x9C,0x00,0x00,0x00,0x75,0x00,0x00,0x00, +/* 0x00000270: */ 0x00,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00000280: */ 0x00,0x00,0x00,0x00,0x09,0x00,0x00,0x00,0x36,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00000290: */ 0x70,0x01,0x00,0x00,0x59,0x00,0x00,0x00,0x1F,0x00,0x00,0x00,0x11,0x00,0x00,0x00, +/* 0x000002A0: */ 0xA3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x0A,0x00,0x00,0x00, +/* 0x000002B0: */ 0xA5,0x00,0x00,0x00,0x9B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x000002C0: */ 0x08,0x00,0x00,0x00,0xA5,0x00,0x00,0x00,0x9B,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000002D0: */ 0x59,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0xA5,0x00,0x00,0x00,0x9B,0x00,0x00,0x00, +/* 0x000002E0: */ 0x00,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0xA5,0x00,0x00,0x00, +/* 0x000002F0: */ 0x9B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x51,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00000300: */ 0x80,0x00,0x00,0x00,0x7D,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7B,0x00,0x00,0x00, +/* 0x00000310: */ 0x18,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x19,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00000320: */ 0xA2,0x00,0x00,0x00,0x7B,0x00,0x00,0x00,0x8E,0x00,0x00,0x00,0x1F,0x00,0x00,0x00, +/* 0x00000330: */ 0xA2,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x8E,0x00,0x00,0x00,0x7A,0x00,0x00,0x00, +/* 0x00000340: */ 0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00000350: */ 0xB2,0x00,0x00,0x00,0x9B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00000360: */ 0x01,0x00,0x00,0x00,0xB2,0x00,0x00,0x00,0x9B,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00000370: */ 0x35,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x11,0x00,0x00,0x00, +/* 0x00000380: */ 0x7D,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x03,0x00,0x00,0x00, +/* 0x00000390: */ 0x7D,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0xFC,0xFF,0xFF,0xFF,0x11,0x00,0x00,0x00, +/* 0x000003A0: */ 0x00,0x00,0x00,0x00,0xA9,0x00,0x00,0x00,0x41,0x00,0x00,0x00,0x88,0x03,0x00,0x00, +/* 0x000003B0: */ 0xA9,0x00,0x00,0x00,0x9B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xA9,0x00,0x00,0x00, +/* 0x000003C0: */ 0x7F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x51,0x00,0x00,0x00,0x2B,0x00,0x00,0x00, +/* 0x000003D0: */ 0x59,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0xA9,0x00,0x00,0x00,0x7F,0x00,0x00,0x00, +/* 0x000003E0: */ 0x00,0x00,0x00,0x00,0xA9,0x00,0x00,0x00,0x41,0x00,0x00,0x00,0x70,0x03,0x00,0x00, +/* 0x000003F0: */ 0x35,0x00,0x00,0x00,0xA9,0x00,0x00,0x00,0x9B,0x00,0x00,0x00,0xBA,0x00,0x00,0x00, +/* 0x00000400: */ 0x59,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0xA9,0x00,0x00,0x00,0x7F,0x00,0x00,0x00, +/* 0x00000410: */ 0x00,0x00,0x00,0x00,0xA4,0x03,0x00,0x00,0x51,0x00,0x00,0x00,0x9B,0x00,0x00,0x00, +/* 0x00000420: */ 0xC2,0x00,0x00,0x00,0xBC,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x35,0x00,0x00,0x00, +/* 0x00000430: */ 0x18,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x1F,0x00,0x00,0x00,0x11,0x00,0x00,0x00, +/* 0x00000440: */ 0x02,0x00,0x00,0x00,0x7D,0x00,0x00,0x00,0x88,0x03,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00000450: */ 0xAB,0x00,0x00,0x00,0x41,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xA6,0x00,0x00,0x00, +/* 0x00000460: */ 0x41,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xAC,0x00,0x00,0x00,0x41,0x00,0x00,0x00, +/* 0x00000470: */ 0x00,0x00,0x00,0x00,0xA7,0x00,0x00,0x00,0x41,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00000480: */ 0x50,0x04,0x00,0x00,0x7D,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x5C,0x04,0x00,0x00, +/* 0x00000490: */ 0x7D,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x5C,0x04,0x00,0x00,0x75,0x00,0x00,0x00, +/* 0x000004A0: */ 0x00,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0xC3,0x00,0x00,0x00, +/* 0x000004B0: */ 0x75,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x8C,0x04,0x00,0x00,0x14,0x00,0x00,0x00, +/* 0x000004C0: */ 0x7D,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x75,0x00,0x00,0x00, +/* 0x000004D0: */ 0x98,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x5C,0x04,0x00,0x00,0x75,0x00,0x00,0x00, +/* 0x000004E0: */ 0x00,0x00,0x00,0x00,0x5C,0x04,0x00,0x00,0x7D,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000004F0: */ 0x41,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x9B,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00000500: */ 0x14,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0xA0,0x00,0x00,0x00,0x00,0x05,0x00,0x00, +/* 0x00000510: */ 0x00,0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x00,0x05,0x00,0x00, +/* 0x00000520: */ 0x00,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0xA0,0x00,0x00,0x00,0x14,0x05,0x00,0x00, +/* 0x00000530: */ 0x00,0x00,0x00,0x00,0xA4,0x03,0x00,0x00,0x51,0x00,0x00,0x00,0x98,0x04,0x00,0x00, +/* 0x00000540: */ 0x5C,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF, +/* 0x00000550: */ 0x00,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0xF2,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00, +/* 0x00000560: */ 0x59,0x00,0x00,0x00,0xEA,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00000570: */ 0xFE,0xFE,0xFF,0xFF,0x00,0x00,0x00,0x00,0x48,0x05,0x00,0x00,0xBE,0x00,0x00,0x00, +/* 0x00000580: */ 0x00,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x51,0x73,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00000590: */ 0x84,0x05,0x00,0x00,0x75,0x00,0x00,0x00,0x60,0x05,0x00,0x00,0x3F,0x00,0x00,0x00, +/* 0x000005A0: */ 0x00,0x00,0x00,0x00,0x51,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000005B0: */ 0x14,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x51,0x00,0x00,0x00,0x7B,0x00,0x00,0x00, +/* 0x000005C0: */ 0x75,0x00,0x00,0x00,0x9C,0x00,0x00,0x00,0x9B,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000005D0: */ 0x51,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x51,0x00,0x00,0x00,0x75,0x00,0x00,0x00, +/* 0x000005E0: */ 0x14,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0xB2,0x00,0x00,0x00,0x41,0x00,0x00,0x00, +/* 0x000005F0: */ 0x24,0x00,0x00,0x00,0x54,0x05,0x00,0x00,0x3F,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00000600: */ 0x75,0x00,0x00,0x00,0x60,0x05,0x00,0x00,0x3F,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00000610: */ 0xE8,0x05,0x00,0x00,0x59,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x00,0x05,0x00,0x00, +/* 0x00000620: */ 0x84,0x05,0x00,0x00,0xA4,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x9C,0x00,0x00,0x00, +/* 0x00000630: */ 0x90,0x05,0x00,0x00,0xB8,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0xE8,0x05,0x00,0x00, +/* 0x00000640: */ 0x84,0x05,0x00,0x00,0xD0,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00000650: */ 0x15,0x00,0x00,0x00,0x00,0x05,0x00,0x00,0x9C,0x00,0x00,0x00,0x90,0x05,0x00,0x00, +/* 0x00000660: */ 0xD8,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0xBC,0x00,0x00,0x00, +/* 0x00000670: */ 0x00,0x05,0x00,0x00,0x9C,0x00,0x00,0x00,0x90,0x05,0x00,0x00,0xD8,0x05,0x00,0x00, +/* 0x00000680: */ 0x00,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0x00,0x05,0x00,0x00, +/* 0x00000690: */ 0x84,0x05,0x00,0x00,0xA4,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x84,0x06,0x00,0x00, +/* 0x000006A0: */ 0x09,0x00,0x00,0x00,0x2C,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x06,0x00,0x00, +/* 0x000006B0: */ 0x09,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x4C,0x06,0x00,0x00,0x2C,0x06,0x00,0x00, +/* 0x000006C0: */ 0x00,0x00,0x00,0x00,0xE8,0x05,0x00,0x00,0xA0,0x00,0x00,0x00,0x58,0x00,0x00,0x00, +/* 0x000006D0: */ 0x00,0x00,0x00,0x00,0x14,0x01,0x00,0x00,0x77,0x00,0x00,0x00,0x8C,0x04,0x00,0x00, +/* 0x000006E0: */ 0xC2,0x00,0x00,0x00,0x7D,0x00,0x00,0x00,0x9B,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000006F0: */ 0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x51,0x00,0x00,0x00, +/* 0x00000700: */ 0xB8,0x01,0x00,0x00,0x59,0x00,0x00,0x00,0xD4,0x06,0x00,0x00,0x00,0x05,0x00,0x00, +/* 0x00000710: */ 0xA2,0x00,0x00,0x00,0x92,0x00,0x00,0x00,0x8E,0x00,0x00,0x00,0x34,0x05,0x00,0x00, +/* 0x00000720: */ 0x9C,0x00,0x00,0x00,0x9B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x29,0x00,0x00,0x00, +/* 0x00000730: */ 0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x04,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00000740: */ 0x29,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x04,0x00,0x00, +/* 0x00000750: */ 0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x04,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00000760: */ 0x29,0x00,0x00,0x00,0x14,0x04,0x00,0x00,0x59,0x00,0x00,0x00,0x78,0x07,0x00,0x00, +/* 0x00000770: */ 0xD4,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x41,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00000780: */ 0x2A,0x00,0x00,0x00,0x78,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF, +/* 0x00000790: */ 0x2A,0x00,0x00,0x00,0x78,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0xFF,0xFF,0xFF, +/* 0x000007A0: */ 0x9C,0x00,0x00,0x00,0x7B,0x00,0x00,0x00,0x9B,0x00,0x00,0x00,0xAC,0x01,0x00,0x00, +/* 0x000007B0: */ 0x9B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x35,0x00,0x00,0x00,0xAC,0x01,0x00,0x00, +/* 0x000007C0: */ 0x41,0x00,0x00,0x00,0x9C,0x00,0x00,0x00,0x41,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000007D0: */ 0x35,0x00,0x00,0x00,0x26,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x08,0x00,0x00,0x00, +/* 0x000007E0: */ 0x60,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x35,0x00,0x00,0x00,0x26,0x00,0x00,0x00, +/* 0x000007F0: */ 0xBC,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x74,0x02,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00000800: */ 0x35,0x00,0x00,0x00,0x26,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x10,0x00,0x00,0x00, +/* 0x00000810: */ 0x80,0x07,0x00,0x00,0x15,0x00,0x00,0x00,0x0C,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00000820: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00000830: */ 0xA2,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x8E,0x00,0x00,0x00,0x3A,0x00,0x00,0x00, +/* 0x00000840: */ 0x00,0x00,0x00,0x00,0x30,0x08,0x00,0x00,0x33,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00000850: */ 0x59,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x72,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00000860: */ 0x59,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00000870: */ 0x50,0x08,0x00,0x00,0x7B,0x00,0x00,0x00,0xC2,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00000880: */ 0x08,0x00,0x00,0x00,0xA1,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x8B,0x00,0x00,0x00, +/* 0x00000890: */ 0x7A,0x00,0x00,0x00,0x9C,0x00,0x00,0x00,0x50,0x08,0x00,0x00,0x9C,0x00,0x00,0x00, +/* 0x000008A0: */ 0x00,0x00,0x00,0x00,0x2A,0x00,0x00,0x00,0x78,0x07,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000008B0: */ 0x00,0x00,0x00,0x00,0x2A,0x00,0x00,0x00,0x78,0x07,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000008C0: */ 0xFF,0xFF,0xFF,0xFF,0x2A,0x00,0x00,0x00,0x78,0x07,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000008D0: */ 0x20,0x00,0x00,0x00,0x35,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x08,0x00,0x00,0x00, +/* 0x000008E0: */ 0xD8,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x35,0x00,0x00,0x00,0xBC,0x00,0x00,0x00, +/* 0x000008F0: */ 0x08,0x00,0x00,0x00,0xE4,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0xA2,0x00,0x00,0x00, +/* 0x00000900: */ 0xD4,0x08,0x00,0x00,0x8E,0x00,0x00,0x00,0x9B,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00000910: */ 0x41,0x00,0x00,0x00,0xE8,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0xD4,0x08,0x00,0x00, +/* 0x00000920: */ 0x14,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x29,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00000930: */ 0x02,0x00,0x00,0x00,0xC3,0x00,0x00,0x00,0x14,0x04,0x00,0x00,0x35,0x00,0x00,0x00, +/* 0x00000940: */ 0x14,0x04,0x00,0x00,0xC3,0x00,0x00,0x00,0xAC,0x01,0x00,0x00,0xBC,0x03,0x00,0x00, +/* 0x00000950: */ 0x00,0x00,0x00,0x00,0x35,0x00,0x00,0x00,0x41,0x00,0x00,0x00,0x03,0x00,0x00,0x00, +/* 0x00000960: */ 0xAC,0x01,0x00,0x00,0x9C,0x00,0x00,0x00,0x9B,0x00,0x00,0x00,0x7D,0x00,0x00,0x00, +/* 0x00000970: */ 0x9B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x35,0x00,0x00,0x00,0x41,0x00,0x00,0x00, +/* 0x00000980: */ 0xB8,0x01,0x00,0x00,0x03,0x00,0x00,0x00,0x9C,0x00,0x00,0x00,0x9B,0x00,0x00,0x00, +/* 0x00000990: */ 0x7D,0x00,0x00,0x00,0x41,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x35,0x00,0x00,0x00, +/* 0x000009A0: */ 0x41,0x00,0x00,0x00,0xB8,0x01,0x00,0x00,0x7D,0x00,0x00,0x00,0x41,0x00,0x00,0x00, +/* 0x000009B0: */ 0x00,0x00,0x00,0x00,0x35,0x00,0x00,0x00,0x41,0x00,0x00,0x00,0xB8,0x01,0x00,0x00, +/* 0x000009C0: */ 0x7D,0x00,0x00,0x00,0x9C,0x00,0x00,0x00,0xC3,0x00,0x00,0x00,0x75,0x00,0x00,0x00, +/* 0x000009D0: */ 0x41,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x35,0x00,0x00,0x00,0x41,0x00,0x00,0x00, +/* 0x000009E0: */ 0x7D,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x08,0x00,0x00,0x00, +/* 0x000009F0: */ 0x9C,0x00,0x00,0x00,0x9B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x2A,0x00,0x00,0x00, +/* 0x00000A00: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x20,0x00,0x00,0x00, +/* 0x00000A10: */ 0xFC,0x10,0x1C,0x40,0x03,0x00,0x00,0x00,0xF8,0x10,0x1C,0x40,0x05,0x00,0x00,0x00, +/* 0x00000A20: */ 0x24,0xBF,0x1B,0x40,0x05,0x00,0x00,0x00,0x68,0xBF,0x1B,0x40,0x04,0x00,0x00,0x00, +/* 0x00000A30: */ 0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x00000A40: */ 0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x00000A50: */ 0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x00000A60: */ 0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x00000A70: */ 0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x00000A80: */ 0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x00000A90: */ 0x5A,0x5A,0x5A,0x5A,0xFC,0x09,0x00,0x00,0x54,0x09,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00000AA0: */ 0xFC,0x09,0x00,0x00,0x78,0x09,0x00,0x00,0x00,0x00,0x00,0x00,0xFC,0x09,0x00,0x00, +/* 0x00000AB0: */ 0x9C,0x09,0x00,0x00,0x00,0x00,0x00,0x00,0xFC,0x09,0x00,0x00,0xE8,0x09,0x00,0x00, +/* 0x00000AC0: */ 0x00,0x00,0x00,0x00,0x2A,0x00,0x00,0x00,0x78,0x07,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00000AD0: */ 0x03,0x00,0x00,0x00,0x2A,0x00,0x00,0x00,0x78,0x07,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00000AE0: */ 0x04,0x00,0x00,0x00,0x2A,0x00,0x00,0x00,0x78,0x07,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00000AF0: */ 0x05,0x00,0x00,0x00,0xE8,0x05,0x00,0x00,0x59,0x00,0x00,0x00,0x32,0x00,0x00,0x00, +/* 0x00000B00: */ 0x00,0x05,0x00,0x00,0x51,0x00,0x00,0x00,0x94,0x0A,0x00,0x00,0xC4,0x0A,0x00,0x00, +/* 0x00000B10: */ 0x94,0x0A,0x00,0x00,0x00,0x00,0x00,0x00,0xE8,0x05,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00000B20: */ 0x80,0x00,0x00,0x00,0x00,0x05,0x00,0x00,0x51,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00000B30: */ 0x00,0x00,0x00,0x00,0x14,0x04,0x00,0x00,0x51,0x00,0x00,0x00,0x94,0x0A,0x00,0x00, +/* 0x00000B40: */ 0xC4,0x0A,0x00,0x00,0x94,0x0A,0x00,0x00,0x94,0x0A,0x00,0x00,0xE4,0x0A,0x00,0x00, +/* 0x00000B50: */ 0x94,0x0A,0x00,0x00,0x00,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x57,0x00,0x00,0x00, +/* 0x00000B60: */ 0x00,0x05,0x00,0x00,0x51,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00000B70: */ 0x14,0x04,0x00,0x00,0x94,0x0A,0x00,0x00,0xD4,0x0A,0x00,0x00,0x94,0x0A,0x00,0x00, +/* 0x00000B80: */ 0x00,0x00,0x00,0x00,0xAC,0x0A,0x00,0x00,0xD4,0x0A,0x00,0x00,0x1E,0x00,0x00,0x00, +/* 0x00000B90: */ 0xAC,0x0A,0x00,0x00,0xE4,0x0A,0x00,0x00,0x1E,0x00,0x00,0x00,0x7A,0x00,0x00,0x00, +/* 0x00000BA0: */ 0xBC,0x00,0x00,0x00,0x64,0x00,0x00,0x00,0xA0,0x0A,0x00,0x00,0xD4,0x0A,0x00,0x00, +/* 0x00000BB0: */ 0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x28,0x00,0x00,0x00,0xA0,0x0A,0x00,0x00, +/* 0x00000BC0: */ 0x51,0x00,0x00,0x00,0x7B,0x00,0x00,0x00,0x75,0x00,0x00,0x00,0xAC,0x01,0x00,0x00, +/* 0x00000BD0: */ 0x9C,0x00,0x00,0x00,0x9B,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0x24,0x00,0x00,0x00, +/* 0x00000BE0: */ 0xA0,0x0A,0x00,0x00,0x35,0x00,0x00,0x00,0x51,0x00,0x00,0x00,0x9C,0x00,0x00,0x00, +/* 0x00000BF0: */ 0x75,0x00,0x00,0x00,0xAC,0x01,0x00,0x00,0x9C,0x00,0x00,0x00,0x9B,0x00,0x00,0x00, +/* 0x00000C00: */ 0x15,0x00,0x00,0x00,0x80,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0xA0,0x0A,0x00,0x00, +/* 0x00000C10: */ 0xC4,0x0A,0x00,0x00,0x00,0x06,0x00,0x00,0xA0,0x0A,0x00,0x00,0x51,0x00,0x00,0x00, +/* 0x00000C20: */ 0x75,0x00,0x00,0x00,0x51,0x00,0x00,0x00,0x9B,0x00,0x00,0x00,0xC2,0x00,0x00,0x00, +/* 0x00000C30: */ 0xBC,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x71,0x00,0x00,0x00, +/* 0x00000C40: */ 0x00,0x05,0x00,0x00,0x84,0x0B,0x00,0x00,0x0C,0x0C,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00000C50: */ 0x59,0x00,0x00,0x00,0x7E,0x00,0x00,0x00,0x00,0x05,0x00,0x00,0x84,0x0B,0x00,0x00, +/* 0x00000C60: */ 0x0C,0x0C,0x00,0x00,0x00,0x00,0x00,0x00,0x8E,0x00,0x00,0x00,0x8C,0x00,0x00,0x00, +/* 0x00000C70: */ 0x8C,0x00,0x00,0x00,0xA2,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x01,0x00,0x00, +/* 0x00000C80: */ 0x77,0x00,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0xC4,0x08,0x00,0x00, +/* 0x00000C90: */ 0xD4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x00,0x02,0x00,0x00, +/* 0x00000CA0: */ 0x74,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x73,0x00,0x00,0x00, +/* 0x00000CB0: */ 0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x10,0x00,0x00,0x00, +/* 0x00000CC0: */ 0x8C,0x0C,0x00,0x00,0x71,0x00,0x00,0x00,0xF8,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00, +/* 0x00000CD0: */ 0x2E,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00, +/* 0x00000CE0: */ 0x10,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x71,0x00,0x00,0x00,0xF8,0xFF,0xFF,0xFF, +/* 0x00000CF0: */ 0x00,0x00,0x00,0x00,0xAF,0x00,0x00,0x00,0x41,0x00,0x00,0x00,0x25,0x00,0x00,0x00, +/* 0x00000D00: */ 0xBC,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x28,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00000D10: */ 0x8C,0x04,0x00,0x00,0x41,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0xD4,0x00,0x00,0x00, +/* 0x00000D20: */ 0x8C,0x04,0x00,0x00,0x41,0x00,0x00,0x00,0x75,0x00,0x00,0x00,0x6C,0x05,0x00,0x00, +/* 0x00000D30: */ 0x3F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x8C,0x04,0x00,0x00,0xC2,0x00,0x00,0x00, +/* 0x00000D40: */ 0x7D,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x0D,0x00,0x00,0x9B,0x00,0x00,0x00, +/* 0x00000D50: */ 0x00,0x00,0x00,0x00,0xA0,0x00,0x00,0x00,0x35,0x00,0x00,0x00,0x10,0x0D,0x00,0x00, +/* 0x00000D60: */ 0xB2,0x00,0x00,0x00,0x41,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x1C,0x00,0x00,0x00, +/* 0x00000D70: */ 0x58,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x48,0x0D,0x00,0x00,0x00,0x05,0x00,0x00, +/* 0x00000D80: */ 0x15,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x48,0x0D,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00000D90: */ 0x38,0x0D,0x00,0x00,0x41,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xA0,0x00,0x00,0x00, +/* 0x00000DA0: */ 0x35,0x00,0x00,0x00,0x10,0x0D,0x00,0x00,0xB2,0x00,0x00,0x00,0x41,0x00,0x00,0x00, +/* 0x00000DB0: */ 0xBC,0x00,0x00,0x00,0x1C,0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00000DC0: */ 0x90,0x0D,0x00,0x00,0x00,0x05,0x00,0x00,0x15,0x00,0x00,0x00,0x08,0x00,0x00,0x00, +/* 0x00000DD0: */ 0x90,0x0D,0x00,0x00,0x00,0x00,0x00,0x00,0x7B,0x00,0x00,0x00,0x74,0x00,0x00,0x00, +/* 0x00000DE0: */ 0x88,0x00,0x00,0x00,0x7B,0x00,0x00,0x00,0x7D,0x00,0x00,0x00,0xD8,0x01,0x00,0x00, +/* 0x00000DF0: */ 0x75,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE4,0x01,0x00,0x00,0x02,0x00,0x00,0x00, +/* 0x00000E00: */ 0x9C,0x00,0x00,0x00,0x19,0x00,0x00,0x00,0x2B,0x00,0x00,0x00,0x33,0x00,0x00,0x00, +/* 0x00000E10: */ 0x00,0x00,0x00,0x00,0xA2,0x00,0x00,0x00,0x94,0x00,0x00,0x00,0x24,0x02,0x00,0x00, +/* 0x00000E20: */ 0xB3,0x00,0x00,0x00,0x41,0x00,0x00,0x00,0xD8,0x0D,0x00,0x00,0x8D,0x00,0x00,0x00, +/* 0x00000E30: */ 0x93,0x00,0x00,0x00,0x7B,0x00,0x00,0x00,0x9C,0x00,0x00,0x00,0x8E,0x00,0x00,0x00, +/* 0x00000E40: */ 0x91,0x00,0x00,0x00,0xA2,0x00,0x00,0x00,0x7B,0x00,0x00,0x00,0x75,0x00,0x00,0x00, +/* 0x00000E50: */ 0x88,0x00,0x00,0x00,0x8E,0x00,0x00,0x00,0x35,0x00,0x00,0x00,0x27,0x00,0x00,0x00, +/* 0x00000E60: */ 0x7D,0x00,0x00,0x00,0x75,0x00,0x00,0x00,0xB3,0x00,0x00,0x00,0x9B,0x00,0x00,0x00, +/* 0x00000E70: */ 0x00,0x00,0x00,0x00,0xA2,0x00,0x00,0x00,0x94,0x00,0x00,0x00,0xB3,0x00,0x00,0x00, +/* 0x00000E80: */ 0x41,0x00,0x00,0x00,0xD8,0x0D,0x00,0x00,0x7B,0x00,0x00,0x00,0x9C,0x00,0x00,0x00, +/* 0x00000E90: */ 0x8E,0x00,0x00,0x00,0x91,0x00,0x00,0x00,0xA2,0x00,0x00,0x00,0x7B,0x00,0x00,0x00, +/* 0x00000EA0: */ 0x75,0x00,0x00,0x00,0x35,0x00,0x00,0x00,0x8E,0x00,0x00,0x00,0x27,0x00,0x00,0x00, +/* 0x00000EB0: */ 0x75,0x00,0x00,0x00,0xB3,0x00,0x00,0x00,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00000EC0: */ 0x14,0x0E,0x00,0x00,0x51,0x00,0x00,0x00,0xF8,0x0D,0x00,0x00,0x51,0x00,0x00,0x00, +/* 0x00000ED0: */ 0x00,0x00,0x00,0x00,0xC4,0x08,0x00,0x00,0x74,0x0E,0x00,0x00,0x33,0x00,0x00,0x00, +/* 0x00000EE0: */ 0x18,0x00,0x00,0x00,0xB2,0x00,0x00,0x00,0x41,0x00,0x00,0x00,0xBC,0x00,0x00,0x00, +/* 0x00000EF0: */ 0x08,0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC4,0x08,0x00,0x00, +/* 0x00000F00: */ 0x74,0x0E,0x00,0x00,0x33,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00000F10: */ 0xFC,0x0E,0x00,0x00,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x70,0x01,0x00,0x00, +/* 0x00000F20: */ 0xA3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x51,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00000F30: */ 0x35,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x11,0x00,0x00,0x00, +/* 0x00000F40: */ 0x7D,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x8E,0x00,0x00,0x00,0x35,0x00,0x00,0x00, +/* 0x00000F50: */ 0x70,0x01,0x00,0x00,0x7D,0x00,0x00,0x00,0x88,0x03,0x00,0x00,0xA2,0x00,0x00,0x00, +/* 0x00000F60: */ 0x00,0x00,0x00,0x00,0x8E,0x00,0x00,0x00,0x70,0x01,0x00,0x00,0x03,0x00,0x00,0x00, +/* 0x00000F70: */ 0x7D,0x00,0x00,0x00,0x88,0x03,0x00,0x00,0xA2,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00000F80: */ 0x8E,0x00,0x00,0x00,0x70,0x01,0x00,0x00,0x03,0x00,0x00,0x00,0x7D,0x00,0x00,0x00, +/* 0x00000F90: */ 0x88,0x03,0x00,0x00,0xA2,0x00,0x00,0x00,0xA3,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00000FA0: */ 0x24,0x02,0x00,0x00,0x28,0x0F,0x00,0x00,0xF8,0x0D,0x00,0x00,0x02,0x00,0x00,0x00, +/* 0x00000FB0: */ 0xBC,0x03,0x00,0x00,0xA4,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00000FC0: */ 0x22,0x00,0x00,0x00,0x74,0x0E,0x00,0x00,0xA0,0x0F,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00000FD0: */ 0x59,0x00,0x00,0x00,0x29,0x00,0x00,0x00,0x74,0x0E,0x00,0x00,0xA3,0x00,0x00,0x00, +/* 0x00000FE0: */ 0x00,0x00,0x00,0x00,0xB2,0x00,0x00,0x00,0x41,0x00,0x00,0x00,0xBC,0x00,0x00,0x00, +/* 0x00000FF0: */ 0x1C,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x80,0x0F,0x00,0x00,0x00,0x05,0x00,0x00, +/* 0x00001000: */ 0xBC,0x0F,0x00,0x00,0x15,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00001010: */ 0x22,0x00,0x00,0x00,0x74,0x0E,0x00,0x00,0xA3,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00001020: */ 0xB2,0x00,0x00,0x00,0x41,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x28,0x00,0x00,0x00, +/* 0x00001030: */ 0x59,0x00,0x00,0x00,0x80,0x0F,0x00,0x00,0x00,0x05,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00001040: */ 0x27,0x00,0x00,0x00,0x74,0x0E,0x00,0x00,0xA0,0x0F,0x00,0x00,0x15,0x00,0x00,0x00, +/* 0x00001050: */ 0x14,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x27,0x00,0x00,0x00,0x74,0x0E,0x00,0x00, +/* 0x00001060: */ 0xA3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xB2,0x00,0x00,0x00,0x41,0x00,0x00,0x00, +/* 0x00001070: */ 0xBC,0x00,0x00,0x00,0x1C,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x48,0x0F,0x00,0x00, +/* 0x00001080: */ 0x00,0x05,0x00,0x00,0xBC,0x0F,0x00,0x00,0x15,0x00,0x00,0x00,0x1C,0x00,0x00,0x00, +/* 0x00001090: */ 0x59,0x00,0x00,0x00,0x22,0x00,0x00,0x00,0x74,0x0E,0x00,0x00,0xF8,0x02,0x00,0x00, +/* 0x000010A0: */ 0xF8,0x0D,0x00,0x00,0xF8,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0xB2,0x00,0x00,0x00, +/* 0x000010B0: */ 0x41,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x1C,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x000010C0: */ 0x64,0x0F,0x00,0x00,0x00,0x05,0x00,0x00,0xBC,0x0F,0x00,0x00,0x15,0x00,0x00,0x00, +/* 0x000010D0: */ 0x20,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x22,0x00,0x00,0x00,0x74,0x0E,0x00,0x00, +/* 0x000010E0: */ 0xF8,0x02,0x00,0x00,0xF8,0x0D,0x00,0x00,0xF8,0x02,0x00,0x00,0x70,0x01,0x00,0x00, +/* 0x000010F0: */ 0x00,0x00,0x00,0x00,0x68,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x68,0x10,0x00,0x00, +/* 0x00001100: */ 0x00,0x00,0x00,0x00,0xB2,0x00,0x00,0x00,0x41,0x00,0x00,0x00,0xBC,0x00,0x00,0x00, +/* 0x00001110: */ 0x24,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x48,0x0F,0x00,0x00,0x00,0x05,0x00,0x00, +/* 0x00001120: */ 0xC4,0x08,0x00,0x00,0x14,0x0E,0x00,0x00,0xA0,0x0F,0x00,0x00,0x15,0x00,0x00,0x00, +/* 0x00001130: */ 0x18,0x00,0x00,0x00,0xC4,0x08,0x00,0x00,0x14,0x0E,0x00,0x00,0xF8,0x02,0x00,0x00, +/* 0x00001140: */ 0xF8,0x0D,0x00,0x00,0xF8,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00001150: */ 0x64,0x0F,0x00,0x00,0x00,0x05,0x00,0x00,0xA0,0x0F,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00001160: */ 0x7B,0x00,0x00,0x00,0xA2,0x00,0x00,0x00,0x35,0x00,0x00,0x00,0xA2,0x00,0x00,0x00, +/* 0x00001170: */ 0x70,0x01,0x00,0x00,0x7D,0x00,0x00,0x00,0x9C,0x00,0x00,0x00,0x19,0x00,0x00,0x00, +/* 0x00001180: */ 0x8E,0x00,0x00,0x00,0x35,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x8E,0x00,0x00,0x00, +/* 0x00001190: */ 0x7D,0x00,0x00,0x00,0x9C,0x00,0x00,0x00,0x2B,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000011A0: */ 0xC4,0x08,0x00,0x00,0xB8,0x00,0x00,0x00,0x4D,0x00,0x00,0x00,0x35,0x00,0x00,0x00, +/* 0x000011B0: */ 0x24,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x3C,0x00,0x00,0x00,0x80,0x0F,0x00,0x00, +/* 0x000011C0: */ 0x18,0x50,0x6F,0x73,0x74,0x70,0x6F,0x6E,0x65,0x20,0x63,0x6F,0x75,0x6C,0x64,0x20, +/* 0x000011D0: */ 0x6E,0x6F,0x74,0x20,0x66,0x69,0x6E,0x64,0x20,0x5A,0x5A,0x5A,0x70,0x01,0x00,0x00, +/* 0x000011E0: */ 0xA3,0x00,0x00,0x00,0x28,0x00,0x00,0x00,0x78,0x05,0x00,0x00,0x15,0x00,0x00,0x00, +/* 0x000011F0: */ 0x20,0x00,0x00,0x00,0x25,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x10,0x00,0x00,0x00, +/* 0x00001200: */ 0x00,0x05,0x00,0x00,0x15,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x14,0x05,0x00,0x00, +/* 0x00001210: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x2A,0x00,0x00,0x00, +/* 0x00001220: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0x48,0x0F,0x00,0x00, +/* 0x00001230: */ 0x04,0x3A,0x3A,0x3A,0x3A,0x5A,0x5A,0x5A,0xF8,0x02,0x00,0x00,0x0C,0x03,0x00,0x00, +/* 0x00001240: */ 0x70,0x01,0x00,0x00,0xF8,0x02,0x00,0x00,0x60,0x11,0x00,0x00,0xF8,0x02,0x00,0x00, +/* 0x00001250: */ 0x59,0x00,0x00,0x00,0x78,0x00,0x00,0x00,0x1C,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00001260: */ 0x48,0x0F,0x00,0x00,0x04,0x3B,0x3B,0x3B,0x3B,0x5A,0x5A,0x5A,0x59,0x00,0x00,0x00, +/* 0x00001270: */ 0x78,0x00,0x00,0x00,0x1C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1C,0x12,0x00,0x00, +/* 0x00001280: */ 0x41,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x28,0x00,0x00,0x00,0xF4,0x0C,0x00,0x00, +/* 0x00001290: */ 0x80,0x0F,0x00,0x00,0x08,0x49,0x6E,0x63,0x6C,0x75,0x64,0x65,0x20,0x5A,0x5A,0x5A, +/* 0x000012A0: */ 0x35,0x00,0x00,0x00,0x70,0x01,0x00,0x00,0xA3,0x00,0x00,0x00,0x28,0x00,0x00,0x00, +/* 0x000012B0: */ 0x51,0x00,0x00,0x00,0xA2,0x00,0x00,0x00,0x35,0x00,0x00,0x00,0x70,0x01,0x00,0x00, +/* 0x000012C0: */ 0x48,0x00,0x00,0x00,0x44,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x38,0x00,0x00,0x00, +/* 0x000012D0: */ 0x33,0x00,0x00,0x00,0x80,0x0F,0x00,0x00,0x14,0x43,0x6F,0x75,0x6C,0x64,0x20,0x6E, +/* 0x000012E0: */ 0x6F,0x74,0x20,0x66,0x69,0x6E,0x64,0x20,0x66,0x69,0x6C,0x65,0x20,0x5A,0x5A,0x5A, +/* 0x000012F0: */ 0x1C,0x0F,0x00,0x00,0x28,0x00,0x00,0x00,0x78,0x05,0x00,0x00,0x15,0x00,0x00,0x00, +/* 0x00001300: */ 0x78,0x00,0x00,0x00,0x9C,0x00,0x00,0x00,0x2C,0x12,0x00,0x00,0x2E,0x00,0x00,0x00, +/* 0x00001310: */ 0xA2,0x00,0x00,0x00,0x54,0x00,0x00,0x00,0x2E,0x00,0x00,0x00,0x02,0x00,0x00,0x00, +/* 0x00001320: */ 0x8E,0x00,0x00,0x00,0x75,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x48,0x00,0x00,0x00, +/* 0x00001330: */ 0x80,0x0F,0x00,0x00,0x2C,0x57,0x61,0x72,0x6E,0x69,0x6E,0x67,0x3A,0x20,0x73,0x74, +/* 0x00001340: */ 0x61,0x63,0x6B,0x20,0x64,0x65,0x70,0x74,0x68,0x20,0x63,0x68,0x61,0x6E,0x67,0x65, +/* 0x00001350: */ 0x64,0x20,0x64,0x75,0x72,0x69,0x6E,0x67,0x20,0x69,0x6E,0x63,0x6C,0x75,0x64,0x65, +/* 0x00001360: */ 0x21,0x5A,0x5A,0x5A,0x28,0x00,0x00,0x00,0x31,0x00,0x00,0x00,0x28,0x00,0x00,0x00, +/* 0x00001370: */ 0xD0,0x0C,0x00,0x00,0x60,0x12,0x00,0x00,0x1C,0x12,0x00,0x00,0x41,0x00,0x00,0x00, +/* 0x00001380: */ 0xBC,0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x80,0x0F,0x00,0x00,0x12,0x20,0x20,0x20, +/* 0x00001390: */ 0x20,0x69,0x6E,0x63,0x6C,0x75,0x64,0x65,0x20,0x61,0x64,0x64,0x65,0x64,0x20,0x5A, +/* 0x000013A0: */ 0x51,0x00,0x00,0x00,0x8D,0x00,0x00,0x00,0x75,0x00,0x00,0x00,0x30,0x00,0x00,0x00, +/* 0x000013B0: */ 0x80,0x0F,0x00,0x00,0x06,0x62,0x79,0x74,0x65,0x73,0x2C,0x5A,0x74,0x04,0x00,0x00, +/* 0x000013C0: */ 0x51,0x00,0x00,0x00,0x75,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x80,0x0F,0x00,0x00, +/* 0x000013D0: */ 0x05,0x6C,0x65,0x66,0x74,0x2E,0x5A,0x5A,0x28,0x00,0x00,0x00,0x8C,0x00,0x00,0x00, +/* 0x000013E0: */ 0x00,0x00,0x00,0x00,0x2A,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000013F0: */ 0x0C,0x73,0x61,0x76,0x65,0x64,0x69,0x63,0x64,0x2E,0x66,0x74,0x68,0x5A,0x5A,0x5A, +/* 0x00001400: */ 0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x00001410: */ 0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x00001420: */ 0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x00001430: */ 0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x00001440: */ 0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x00001450: */ 0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x00001460: */ 0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x00001470: */ 0xC4,0x08,0x00,0x00,0xC0,0x0E,0x00,0x00,0x35,0x00,0x00,0x00,0xE4,0x13,0x00,0x00, +/* 0x00001480: */ 0x0C,0x03,0x00,0x00,0x7C,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0xE4,0x13,0x00,0x00, +/* 0x00001490: */ 0x7C,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0xC4,0x08,0x00,0x00,0xB8,0x00,0x00,0x00, +/* 0x000014A0: */ 0x4D,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x1C,0x00,0x00,0x00,0x33,0x00,0x00,0x00, +/* 0x000014B0: */ 0xC4,0x08,0x00,0x00,0xB8,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x15,0x00,0x00,0x00, +/* 0x000014C0: */ 0x0C,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x70,0x14,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000014D0: */ 0x2A,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0xD4,0x01,0x00, +/* 0x000014E0: */ 0x2A,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0x93,0x04,0x00, +/* 0x000014F0: */ 0x14,0x12,0x00,0x00,0x74,0x04,0x00,0x00,0x5C,0x04,0x00,0x00,0x75,0x00,0x00,0x00, +/* 0x00001500: */ 0xE0,0x14,0x00,0x00,0x9B,0x00,0x00,0x00,0x68,0x04,0x00,0x00,0x50,0x04,0x00,0x00, +/* 0x00001510: */ 0x75,0x00,0x00,0x00,0xD0,0x14,0x00,0x00,0x9B,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00001520: */ 0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xAD,0x00,0x00,0x00,0x41,0x00,0x00,0x00, +/* 0x00001530: */ 0x50,0x04,0x00,0x00,0x75,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x00,0x00,0x01,0x00, +/* 0x00001540: */ 0x7D,0x00,0x00,0x00,0xD0,0x14,0x00,0x00,0x41,0x00,0x00,0x00,0x73,0x00,0x00,0x00, +/* 0x00001550: */ 0x51,0x00,0x00,0x00,0x5C,0x04,0x00,0x00,0x75,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00001560: */ 0x00,0x00,0x02,0x00,0x7D,0x00,0x00,0x00,0xE0,0x14,0x00,0x00,0x41,0x00,0x00,0x00, +/* 0x00001570: */ 0x73,0x00,0x00,0x00,0x8F,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x24,0x00,0x00,0x00, +/* 0x00001580: */ 0x80,0x0F,0x00,0x00,0x12,0x53,0x41,0x56,0x45,0x2D,0x46,0x4F,0x52,0x54,0x48,0x20, +/* 0x00001590: */ 0x66,0x61,0x69,0x6C,0x65,0x64,0x21,0x5A,0x28,0x00,0x00,0x00,0x78,0x05,0x00,0x00, +/* 0x000015A0: */ 0x00,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x51,0x00,0x00,0x00, +/* 0x000015B0: */ 0x5C,0x04,0x00,0x00,0x75,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x00,0x00,0x02,0x00, +/* 0x000015C0: */ 0x7D,0x00,0x00,0x00,0x8F,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x20,0x00,0x00,0x00, +/* 0x000015D0: */ 0x80,0x0F,0x00,0x00,0x0F,0x54,0x55,0x52,0x4E,0x4B,0x45,0x59,0x20,0x66,0x61,0x69, +/* 0x000015E0: */ 0x6C,0x65,0x64,0x21,0x28,0x00,0x00,0x00,0x78,0x05,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000015F0: */ 0x2A,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xEC,0x93,0x00,0x00, +/* 0x00001600: */ 0x51,0x00,0x00,0x00,0xF0,0x15,0x00,0x00,0xFC,0x08,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00001610: */ 0x35,0x00,0x00,0x00,0x77,0x00,0x00,0x00,0x8C,0x04,0x00,0x00,0xA9,0x00,0x00,0x00, +/* 0x00001620: */ 0x9B,0x00,0x00,0x00,0x76,0x00,0x00,0x00,0x35,0x00,0x00,0x00,0xA8,0x00,0x00,0x00, +/* 0x00001630: */ 0x9B,0x00,0x00,0x00,0x2C,0x04,0x00,0x00,0xAD,0x00,0x00,0x00,0x9B,0x00,0x00,0x00, +/* 0x00001640: */ 0x00,0x00,0x00,0x00,0x35,0x00,0x00,0x00,0x77,0x00,0x00,0x00,0x8C,0x04,0x00,0x00, +/* 0x00001650: */ 0xF0,0x15,0x00,0x00,0x10,0x09,0x00,0x00,0x23,0x00,0x00,0x00,0xBC,0x00,0x00,0x00, +/* 0x00001660: */ 0x38,0x00,0x00,0x00,0xF4,0x0C,0x00,0x00,0x35,0x00,0x00,0x00,0x90,0x02,0x00,0x00, +/* 0x00001670: */ 0x80,0x0F,0x00,0x00,0x11,0x20,0x69,0x73,0x20,0x62,0x65,0x6C,0x6F,0x77,0x20,0x66, +/* 0x00001680: */ 0x65,0x6E,0x63,0x65,0x21,0x21,0x5A,0x5A,0x28,0x00,0x00,0x00,0x33,0x00,0x00,0x00, +/* 0x00001690: */ 0x15,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x10,0x16,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000016A0: */ 0xC4,0x08,0x00,0x00,0xB8,0x00,0x00,0x00,0x4E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00, +/* 0x000016B0: */ 0x10,0x00,0x00,0x00,0x44,0x16,0x00,0x00,0x15,0x00,0x00,0x00,0x30,0x00,0x00,0x00, +/* 0x000016C0: */ 0x80,0x0F,0x00,0x00,0x17,0x46,0x4F,0x52,0x47,0x45,0x54,0x20,0x2D,0x20,0x63,0x6F, +/* 0x000016D0: */ 0x75,0x6C,0x64,0x6E,0x27,0x74,0x20,0x66,0x69,0x6E,0x64,0x20,0x70,0x01,0x00,0x00, +/* 0x000016E0: */ 0xA3,0x00,0x00,0x00,0x28,0x00,0x00,0x00,0x78,0x05,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000016F0: */ 0x2A,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xB8,0x93,0x00,0x00, +/* 0x00001700: */ 0xC4,0x08,0x00,0x00,0xB8,0x00,0x00,0x00,0x4D,0x00,0x00,0x00,0xBC,0x00,0x00,0x00, +/* 0x00001710: */ 0x28,0x00,0x00,0x00,0x51,0x00,0x00,0x00,0xF0,0x16,0x00,0x00,0x10,0x09,0x00,0x00, +/* 0x00001720: */ 0x1C,0x09,0x00,0x00,0xF0,0x16,0x00,0x00,0xFC,0x08,0x00,0x00,0x00,0x05,0x00,0x00, +/* 0x00001730: */ 0x15,0x00,0x00,0x00,0x4C,0x00,0x00,0x00,0x80,0x0F,0x00,0x00,0x1D,0x49,0x46,0x2E, +/* 0x00001740: */ 0x46,0x4F,0x52,0x47,0x4F,0x54,0x54,0x45,0x4E,0x20,0x2D,0x20,0x63,0x6F,0x75,0x6C, +/* 0x00001750: */ 0x64,0x6E,0x27,0x74,0x20,0x66,0x69,0x6E,0x64,0x20,0x5A,0x5A,0x35,0x00,0x00,0x00, +/* 0x00001760: */ 0x59,0x00,0x00,0x00,0x09,0x00,0x00,0x00,0x34,0x00,0x00,0x00,0x28,0x00,0x00,0x00, +/* 0x00001770: */ 0x70,0x01,0x00,0x00,0xA3,0x00,0x00,0x00,0x28,0x00,0x00,0x00,0x78,0x05,0x00,0x00, +/* 0x00001780: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x78,0x00,0x00,0x00,0xA0,0x16,0x00,0x00, +/* 0x00001790: */ 0xF0,0x16,0x00,0x00,0x10,0x09,0x00,0x00,0x35,0x00,0x00,0x00,0x27,0x00,0x00,0x00, +/* 0x000017A0: */ 0xBC,0x00,0x00,0x00,0x4C,0x00,0x00,0x00,0x35,0x00,0x00,0x00,0x51,0x00,0x00,0x00, +/* 0x000017B0: */ 0x22,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x35,0x00,0x00,0x00, +/* 0x000017C0: */ 0xAC,0x01,0x00,0x00,0xF0,0x04,0x00,0x00,0x40,0x00,0x00,0x00,0xA4,0x08,0x00,0x00, +/* 0x000017D0: */ 0x15,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x35,0x00,0x00,0x00,0xF0,0x16,0x00,0x00, +/* 0x000017E0: */ 0xFC,0x08,0x00,0x00,0xB4,0x08,0x00,0x00,0x15,0x00,0x00,0x00,0x08,0x00,0x00,0x00, +/* 0x000017F0: */ 0xB4,0x08,0x00,0x00,0xBC,0x00,0x00,0x00,0x9C,0xFF,0xFF,0xFF,0x33,0x00,0x00,0x00, +/* 0x00001800: */ 0x00,0x00,0x00,0x00,0x48,0x0F,0x00,0x00,0x08,0x5B,0x46,0x4F,0x52,0x47,0x45,0x54, +/* 0x00001810: */ 0x5D,0x5A,0x5A,0x5A,0x4D,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x10,0x00,0x00,0x00, +/* 0x00001820: */ 0x40,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x80,0x0F,0x00,0x00, +/* 0x00001830: */ 0x17,0x46,0x4F,0x52,0x47,0x45,0x54,0x20,0x2D,0x20,0x63,0x6F,0x75,0x6C,0x64,0x6E, +/* 0x00001840: */ 0x27,0x74,0x20,0x66,0x69,0x6E,0x64,0x20,0x70,0x01,0x00,0x00,0xA3,0x00,0x00,0x00, +/* 0x00001850: */ 0x28,0x00,0x00,0x00,0x78,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0xB3,0x00,0x00,0x00, +/* 0x00001860: */ 0x41,0x00,0x00,0x00,0xC4,0x08,0x00,0x00,0xB8,0x00,0x00,0x00,0x4D,0x00,0x00,0x00, +/* 0x00001870: */ 0xBC,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x7B,0x00,0x00,0x00,0xB3,0x00,0x00,0x00, +/* 0x00001880: */ 0x9B,0x00,0x00,0x00,0x04,0x18,0x00,0x00,0x33,0x00,0x00,0x00,0xB3,0x00,0x00,0x00, +/* 0x00001890: */ 0x9B,0x00,0x00,0x00,0x2C,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x29,0x00,0x00,0x00, +/* 0x000018A0: */ 0x14,0x01,0x00,0x00,0x50,0x04,0x00,0x00,0x75,0x00,0x00,0x00,0x14,0x04,0x00,0x00, +/* 0x000018B0: */ 0x59,0x00,0x00,0x00,0xC0,0x18,0x00,0x00,0xD4,0x06,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000018C0: */ 0x41,0x00,0x00,0x00,0x50,0x04,0x00,0x00,0x7D,0x00,0x00,0x00,0x44,0x16,0x00,0x00, +/* 0x000018D0: */ 0x00,0x00,0x00,0x00,0x2A,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000018E0: */ 0x00,0x00,0x00,0x00,0xA2,0x00,0x00,0x00,0x35,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x000018F0: */ 0x61,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x58,0x02,0x00,0x00,0xBC,0x00,0x00,0x00, +/* 0x00001900: */ 0x1C,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x61,0x00,0x00,0x00,0x75,0x00,0x00,0x00, +/* 0x00001910: */ 0x59,0x00,0x00,0x00,0x41,0x00,0x00,0x00,0x7D,0x00,0x00,0x00,0x35,0x00,0x00,0x00, +/* 0x00001920: */ 0x35,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x41,0x00,0x00,0x00,0x01,0x00,0x00,0x00, +/* 0x00001930: */ 0x1F,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x28,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00001940: */ 0x41,0x00,0x00,0x00,0x75,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x39,0x00,0x00,0x00, +/* 0x00001950: */ 0x7D,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0x28,0x00,0x00,0x00, +/* 0x00001960: */ 0x35,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x39,0x00,0x00,0x00,0x1F,0x00,0x00,0x00, +/* 0x00001970: */ 0xBC,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00001980: */ 0x00,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x75,0x00,0x00,0x00, +/* 0x00001990: */ 0x35,0x00,0x00,0x00,0x8E,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0xBC,0x00,0x00,0x00, +/* 0x000019A0: */ 0x38,0x00,0x00,0x00,0x35,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x25,0x00,0x00,0x00, +/* 0x000019B0: */ 0xBC,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x18,0x02,0x00,0x00,0xB4,0x08,0x00,0x00, +/* 0x000019C0: */ 0x15,0x00,0x00,0x00,0x0C,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0xA4,0x08,0x00,0x00, +/* 0x000019D0: */ 0x15,0x00,0x00,0x00,0x0C,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0xA4,0x08,0x00,0x00, +/* 0x000019E0: */ 0x00,0x00,0x00,0x00,0xA2,0x00,0x00,0x00,0x8D,0x00,0x00,0x00,0x25,0x00,0x00,0x00, +/* 0x000019F0: */ 0xBC,0x00,0x00,0x00,0x3C,0x00,0x00,0x00,0x35,0x00,0x00,0x00,0x18,0x00,0x00,0x00, +/* 0x00001A00: */ 0xA5,0x00,0x00,0x00,0x41,0x00,0x00,0x00,0xE4,0x18,0x00,0x00,0xBC,0x00,0x00,0x00, +/* 0x00001A10: */ 0x10,0x00,0x00,0x00,0xB4,0x08,0x00,0x00,0x15,0x00,0x00,0x00,0x0C,0x00,0x00,0x00, +/* 0x00001A20: */ 0x33,0x00,0x00,0x00,0xA4,0x08,0x00,0x00,0x15,0x00,0x00,0x00,0x08,0x00,0x00,0x00, +/* 0x00001A30: */ 0xA4,0x08,0x00,0x00,0xBC,0x00,0x00,0x00,0x50,0x00,0x00,0x00,0x9C,0x00,0x00,0x00, +/* 0x00001A40: */ 0xA2,0x00,0x00,0x00,0x9C,0x00,0x00,0x00,0xA5,0x00,0x00,0x00,0x41,0x00,0x00,0x00, +/* 0x00001A50: */ 0x3B,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x88,0x00,0x00,0x00,0xA5,0x00,0x00,0x00, +/* 0x00001A60: */ 0x41,0x00,0x00,0x00,0x3B,0x00,0x00,0x00,0x39,0x00,0x00,0x00,0x8E,0x00,0x00,0x00, +/* 0x00001A70: */ 0x02,0x00,0x00,0x00,0x8E,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0xA2,0x00,0x00,0x00, +/* 0x00001A80: */ 0x15,0x00,0x00,0x00,0x64,0xFF,0xFF,0xFF,0x8E,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00001A90: */ 0x59,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0xE4,0x19,0x00,0x00,0x33,0x00,0x00,0x00, +/* 0x00001AA0: */ 0x00,0x00,0x00,0x00,0x2A,0x00,0x00,0x00,0x78,0x07,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00001AB0: */ 0x00,0x00,0x00,0x00,0x2A,0x00,0x00,0x00,0x78,0x07,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00001AC0: */ 0x01,0x00,0x00,0x00,0x2A,0x00,0x00,0x00,0x78,0x07,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00001AD0: */ 0x02,0x00,0x00,0x00,0x35,0x00,0x00,0x00,0x24,0x00,0x00,0x00,0xBC,0x00,0x00,0x00, +/* 0x00001AE0: */ 0x10,0x00,0x00,0x00,0x0C,0x02,0x00,0x00,0xA4,0x1A,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00001AF0: */ 0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00001B00: */ 0x09,0x00,0x00,0x00,0x7B,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00001B10: */ 0x2D,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0x35,0x00,0x00,0x00,0xA2,0x00,0x00,0x00, +/* 0x00001B20: */ 0xBC,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0xA2,0x00,0x00,0x00, +/* 0x00001B30: */ 0x02,0x00,0x00,0x00,0x8E,0x00,0x00,0x00,0xE4,0x19,0x00,0x00,0x35,0x00,0x00,0x00, +/* 0x00001B40: */ 0x24,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x28,0x00,0x00,0x00,0x0C,0x02,0x00,0x00, +/* 0x00001B50: */ 0x33,0x00,0x00,0x00,0x8D,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x08,0x00,0x00,0x00, +/* 0x00001B60: */ 0x60,0x02,0x00,0x00,0xB4,0x1A,0x00,0x00,0x15,0x00,0x00,0x00,0x54,0x00,0x00,0x00, +/* 0x00001B70: */ 0x59,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0x9C,0x00,0x00,0x00, +/* 0x00001B80: */ 0x18,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x2E,0x00,0x00,0x00,0x1E,0x00,0x00,0x00, +/* 0x00001B90: */ 0x11,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x8D,0x00,0x00,0x00, +/* 0x00001BA0: */ 0xBC,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x74,0x02,0x00,0x00,0xC4,0x1A,0x00,0x00, +/* 0x00001BB0: */ 0x15,0x00,0x00,0x00,0x0C,0x00,0x00,0x00,0x0C,0x02,0x00,0x00,0xA4,0x1A,0x00,0x00, +/* 0x00001BC0: */ 0x8C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x70,0x01,0x00,0x00,0xD4,0x1A,0x00,0x00, +/* 0x00001BD0: */ 0x00,0x00,0x00,0x00,0x2A,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00001BE0: */ 0x74,0x14,0x1C,0x40,0x80,0x07,0x00,0x00,0xD4,0x1B,0x00,0x00,0x7F,0x00,0x00,0x00, +/* 0x00001BF0: */ 0xD4,0x1B,0x00,0x00,0x41,0x00,0x00,0x00,0x2B,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00001C00: */ 0xF8,0x02,0x00,0x00,0xD4,0x1B,0x00,0x00,0x9B,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00001C10: */ 0x0C,0x02,0x00,0x00,0xD4,0x1B,0x00,0x00,0x41,0x00,0x00,0x00,0xF8,0x02,0x00,0x00, +/* 0x00001C20: */ 0x7B,0x00,0x00,0x00,0x75,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x26,0x00,0x00,0x00, +/* 0x00001C30: */ 0xBC,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x2D,0x00,0x00,0x00, +/* 0x00001C40: */ 0xE4,0x1B,0x00,0x00,0x00,0x00,0x00,0x00,0xA5,0x00,0x00,0x00,0x41,0x00,0x00,0x00, +/* 0x00001C50: */ 0x38,0x00,0x00,0x00,0x88,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x09,0x00,0x00,0x00, +/* 0x00001C60: */ 0x7B,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x10,0x00,0x00,0x00, +/* 0x00001C70: */ 0x59,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x7D,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00001C80: */ 0x30,0x00,0x00,0x00,0x7D,0x00,0x00,0x00,0xE4,0x1B,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00001C90: */ 0x48,0x1C,0x00,0x00,0x03,0x00,0x00,0x00,0x7A,0x00,0x00,0x00,0x24,0x00,0x00,0x00, +/* 0x00001CA0: */ 0xBC,0x00,0x00,0x00,0xEC,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x1C,0x00,0x00, +/* 0x00001CB0: */ 0x90,0x1C,0x00,0x00,0x10,0x1C,0x00,0x00,0x00,0x00,0x00,0x00,0xAC,0x1C,0x00,0x00, +/* 0x00001CC0: */ 0xA3,0x00,0x00,0x00,0x8C,0x0C,0x00,0x00,0x00,0x00,0x00,0x00,0xA2,0x00,0x00,0x00, +/* 0x00001CD0: */ 0xAC,0x1C,0x00,0x00,0x8E,0x00,0x00,0x00,0x7B,0x00,0x00,0x00,0x75,0x00,0x00,0x00, +/* 0x00001CE0: */ 0x98,0x0C,0x00,0x00,0xA3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x00, +/* 0x00001CF0: */ 0xE8,0x07,0x00,0x00,0x00,0x1C,0x00,0x00,0x90,0x1C,0x00,0x00,0x88,0x00,0x00,0x00, +/* 0x00001D00: */ 0x2C,0x1C,0x00,0x00,0x10,0x1C,0x00,0x00,0x00,0x00,0x00,0x00,0xEC,0x1C,0x00,0x00, +/* 0x00001D10: */ 0xA3,0x00,0x00,0x00,0x8C,0x0C,0x00,0x00,0x00,0x00,0x00,0x00,0xA2,0x00,0x00,0x00, +/* 0x00001D20: */ 0xEC,0x1C,0x00,0x00,0x8E,0x00,0x00,0x00,0x7B,0x00,0x00,0x00,0x75,0x00,0x00,0x00, +/* 0x00001D30: */ 0x98,0x0C,0x00,0x00,0xA3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00001D40: */ 0x00,0x00,0x00,0x00,0xAC,0x1C,0x00,0x00,0x00,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00001D50: */ 0x00,0x00,0x00,0x00,0xBC,0x1C,0x00,0x00,0x00,0x00,0x00,0x00,0xA2,0x00,0x00,0x00, +/* 0x00001D60: */ 0x3C,0x1D,0x00,0x00,0x8E,0x00,0x00,0x00,0x7B,0x00,0x00,0x00,0x75,0x00,0x00,0x00, +/* 0x00001D70: */ 0x98,0x0C,0x00,0x00,0xA3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x35,0x00,0x00,0x00, +/* 0x00001D80: */ 0xD0,0x07,0x00,0x00,0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1C,0x00,0x00, +/* 0x00001D90: */ 0x90,0x1C,0x00,0x00,0x88,0x00,0x00,0x00,0x2C,0x1C,0x00,0x00,0x10,0x1C,0x00,0x00, +/* 0x00001DA0: */ 0x00,0x00,0x00,0x00,0x7C,0x1D,0x00,0x00,0xA3,0x00,0x00,0x00,0x8C,0x0C,0x00,0x00, +/* 0x00001DB0: */ 0x00,0x00,0x00,0x00,0xA2,0x00,0x00,0x00,0x7C,0x1D,0x00,0x00,0x8E,0x00,0x00,0x00, +/* 0x00001DC0: */ 0x7B,0x00,0x00,0x00,0x75,0x00,0x00,0x00,0x98,0x0C,0x00,0x00,0xA3,0x00,0x00,0x00, +/* 0x00001DD0: */ 0x00,0x00,0x00,0x00,0x2A,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00001DE0: */ 0x00,0x00,0x00,0x00,0x8B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x72,0x00,0x00,0x00, +/* 0x00001DF0: */ 0x00,0x00,0x00,0x00,0x9C,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x14,0x00,0x00,0x00, +/* 0x00001E00: */ 0x70,0x01,0x00,0x00,0xA3,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0x08,0x00,0x00,0x00, +/* 0x00001E10: */ 0x33,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF4,0x10,0x00,0x00,0xB2,0x00,0x00,0x00, +/* 0x00001E20: */ 0x41,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00001E30: */ 0xF4,0x1D,0x00,0x00,0x00,0x05,0x00,0x00,0x15,0x00,0x00,0x00,0x08,0x00,0x00,0x00, +/* 0x00001E40: */ 0xF4,0x1D,0x00,0x00,0x00,0x00,0x00,0x00,0x9C,0x00,0x00,0x00,0xBC,0x00,0x00,0x00, +/* 0x00001E50: */ 0x1C,0x00,0x00,0x00,0x70,0x01,0x00,0x00,0xA3,0x00,0x00,0x00,0x28,0x00,0x00,0x00, +/* 0x00001E60: */ 0x78,0x05,0x00,0x00,0x15,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x33,0x00,0x00,0x00, +/* 0x00001E70: */ 0x00,0x00,0x00,0x00,0xF4,0x10,0x00,0x00,0xB2,0x00,0x00,0x00,0x41,0x00,0x00,0x00, +/* 0x00001E80: */ 0xBC,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x48,0x1E,0x00,0x00, +/* 0x00001E90: */ 0x00,0x05,0x00,0x00,0x15,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x48,0x1E,0x00,0x00, +/* 0x00001EA0: */ 0x00,0x00,0x00,0x00,0x82,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x70,0x00,0x00,0x00, +/* 0x00001EB0: */ 0x56,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x28,0x00,0x00,0x00,0x80,0x0F,0x00,0x00, +/* 0x00001EC0: */ 0x2E,0x48,0x69,0x74,0x20,0x73,0x70,0x61,0x63,0x65,0x20,0x74,0x6F,0x20,0x63,0x6F, +/* 0x00001ED0: */ 0x6E,0x74,0x69,0x6E,0x75,0x65,0x2C,0x20,0x61,0x6E,0x79,0x20,0x6F,0x74,0x68,0x65, +/* 0x00001EE0: */ 0x72,0x20,0x6B,0x65,0x79,0x20,0x74,0x6F,0x20,0x61,0x62,0x6F,0x72,0x74,0x3A,0x5A, +/* 0x00001EF0: */ 0x56,0x00,0x00,0x00,0x35,0x00,0x00,0x00,0xD4,0x00,0x00,0x00,0xC4,0x08,0x00,0x00, +/* 0x00001F00: */ 0x1E,0x00,0x00,0x00,0x58,0x02,0x00,0x00,0x48,0x0F,0x00,0x00,0x0A,0x54,0x65,0x72, +/* 0x00001F10: */ 0x6D,0x69,0x6E,0x61,0x74,0x65,0x64,0x5A,0x48,0x1E,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00001F20: */ 0x2A,0x00,0x00,0x00,0x78,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x3C,0x00,0x00,0x00, +/* 0x00001F30: */ 0xAF,0x00,0x00,0x00,0x41,0x00,0x00,0x00,0x20,0x1F,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00001F40: */ 0x10,0x00,0x00,0x00,0x75,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x0A,0x00,0x00,0x00, +/* 0x00001F50: */ 0x73,0x00,0x00,0x00,0x1F,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x08,0x00,0x00,0x00, +/* 0x00001F60: */ 0x28,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x28,0x00,0x00,0x00, +/* 0x00001F70: */ 0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x32,0x00,0x00,0x00,0x28,0x00,0x00,0x00, +/* 0x00001F80: */ 0x71,0x00,0x00,0x00,0xF8,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x68,0x1F,0x00,0x00, +/* 0x00001F90: */ 0x00,0x00,0x00,0x00,0xA5,0x00,0x00,0x00,0x41,0x00,0x00,0x00,0xD0,0x02,0x00,0x00, +/* 0x00001FA0: */ 0x59,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0xC0,0x0E,0x00,0x00,0xE0,0x00,0x00,0x00, +/* 0x00001FB0: */ 0xB4,0x1A,0x00,0x00,0x1E,0x00,0x00,0x00,0x58,0x02,0x00,0x00,0x48,0x0F,0x00,0x00, +/* 0x00001FC0: */ 0x14,0x4E,0x6F,0x74,0x20,0x61,0x20,0x73,0x69,0x6E,0x67,0x6C,0x65,0x20,0x6E,0x75, +/* 0x00001FD0: */ 0x6D,0x62,0x65,0x72,0x21,0x5A,0x5A,0x5A,0x48,0x1E,0x00,0x00,0x9C,0x00,0x00,0x00, +/* 0x00001FE0: */ 0xA5,0x00,0x00,0x00,0x9B,0x00,0x00,0x00,0xB2,0x00,0x00,0x00,0x41,0x00,0x00,0x00, +/* 0x00001FF0: */ 0xBC,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00002000: */ 0x35,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x09,0x00,0x00,0x00,0x1F,0x00,0x00,0x00, +/* 0x00002010: */ 0xBC,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x37,0x00,0x00,0x00, +/* 0x00002020: */ 0x15,0x00,0x00,0x00,0x0C,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x30,0x00,0x00,0x00, +/* 0x00002030: */ 0x7D,0x00,0x00,0x00,0xD4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x2A,0x00,0x00,0x00, +/* 0x00002040: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0xAF,0x00,0x00,0x00, +/* 0x00002050: */ 0x41,0x00,0x00,0x00,0x3C,0x20,0x00,0x00,0x41,0x00,0x00,0x00,0x44,0x08,0x00,0x00, +/* 0x00002060: */ 0x3C,0x20,0x00,0x00,0x41,0x00,0x00,0x00,0x9C,0x00,0x00,0x00,0x75,0x00,0x00,0x00, +/* 0x00002070: */ 0x98,0x0C,0x00,0x00,0x00,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00002080: */ 0x14,0x01,0x00,0x00,0x35,0x00,0x00,0x00,0x27,0x00,0x00,0x00,0xBC,0x00,0x00,0x00, +/* 0x00002090: */ 0x30,0x00,0x00,0x00,0x35,0x00,0x00,0x00,0x90,0x02,0x00,0x00,0x4C,0x20,0x00,0x00, +/* 0x000020A0: */ 0x30,0x1F,0x00,0x00,0xA4,0x1E,0x00,0x00,0x76,0x00,0x00,0x00,0x9C,0x00,0x00,0x00, +/* 0x000020B0: */ 0x02,0x00,0x00,0x00,0x9C,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0xC8,0xFF,0xFF,0xFF, +/* 0x000020C0: */ 0x33,0x00,0x00,0x00,0x28,0x00,0x00,0x00,0xA4,0x1D,0x00,0x00,0x80,0x0F,0x00,0x00, +/* 0x000020D0: */ 0x06,0x20,0x77,0x6F,0x72,0x64,0x73,0x5A,0x28,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000020E0: */ 0x78,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x2A,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000020F0: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x2A,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00002100: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00002110: */ 0xE8,0x20,0x00,0x00,0x9B,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00002120: */ 0xF8,0x20,0x00,0x00,0x9B,0x00,0x00,0x00,0x14,0x01,0x00,0x00,0x35,0x00,0x00,0x00, +/* 0x00002130: */ 0x27,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x94,0x00,0x00,0x00,0x03,0x00,0x00,0x00, +/* 0x00002140: */ 0x77,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x10,0x00,0x00,0x00, +/* 0x00002150: */ 0xB4,0x08,0x00,0x00,0x15,0x00,0x00,0x00,0x6C,0x00,0x00,0x00,0x03,0x00,0x00,0x00, +/* 0x00002160: */ 0x77,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x1C,0x00,0x00,0x00, +/* 0x00002170: */ 0x35,0x00,0x00,0x00,0xE8,0x20,0x00,0x00,0x9B,0x00,0x00,0x00,0xA4,0x08,0x00,0x00, +/* 0x00002180: */ 0x15,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x35,0x00,0x00,0x00,0x77,0x00,0x00,0x00, +/* 0x00002190: */ 0xF8,0x20,0x00,0x00,0x41,0x00,0x00,0x00,0x1F,0x00,0x00,0x00,0xBC,0x00,0x00,0x00, +/* 0x000021A0: */ 0x20,0x00,0x00,0x00,0x35,0x00,0x00,0x00,0xE8,0x20,0x00,0x00,0x9B,0x00,0x00,0x00, +/* 0x000021B0: */ 0x35,0x00,0x00,0x00,0x77,0x00,0x00,0x00,0xF8,0x20,0x00,0x00,0x9B,0x00,0x00,0x00, +/* 0x000021C0: */ 0xB4,0x08,0x00,0x00,0x15,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0xA4,0x08,0x00,0x00, +/* 0x000021D0: */ 0xBC,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x76,0x00,0x00,0x00,0x15,0x00,0x00,0x00, +/* 0x000021E0: */ 0x4C,0xFF,0xFF,0xFF,0x0C,0x02,0x00,0x00,0xE8,0x20,0x00,0x00,0x41,0x00,0x00,0x00, +/* 0x000021F0: */ 0x00,0x00,0x00,0x00,0xF0,0x04,0x00,0x00,0x81,0x00,0x00,0x00,0xBC,0x00,0x00,0x00, +/* 0x00002200: */ 0x08,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x35,0x00,0x00,0x00, +/* 0x00002210: */ 0x59,0x00,0x00,0x00,0x5B,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0xBC,0x00,0x00,0x00, +/* 0x00002220: */ 0x34,0x00,0x00,0x00,0x35,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x40,0x00,0x00,0x00, +/* 0x00002230: */ 0x1F,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x1C,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00002240: */ 0x41,0x00,0x00,0x00,0x75,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x61,0x00,0x00,0x00, +/* 0x00002250: */ 0x7D,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x00,0x00,0x00,0xA2,0x00,0x00,0x00, +/* 0x00002260: */ 0xA2,0x00,0x00,0x00,0x98,0x00,0x00,0x00,0x80,0x07,0x00,0x00,0x97,0x00,0x00,0x00, +/* 0x00002270: */ 0xB3,0x00,0x00,0x00,0x41,0x00,0x00,0x00,0xA2,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00002280: */ 0x00,0x00,0x00,0x00,0xB3,0x00,0x00,0x00,0x9B,0x00,0x00,0x00,0xBF,0x00,0x00,0x00, +/* 0x00002290: */ 0x96,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x8E,0x00,0x00,0x00,0xB3,0x00,0x00,0x00, +/* 0x000022A0: */ 0x9B,0x00,0x00,0x00,0x8E,0x00,0x00,0x00,0x8E,0x00,0x00,0x00,0x98,0x00,0x00,0x00, +/* 0x000022B0: */ 0x00,0x00,0x00,0x00,0x95,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x14,0x00,0x00,0x00, +/* 0x000022C0: */ 0x84,0x00,0x00,0x00,0x24,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0xF4,0xFF,0xFF,0xFF, +/* 0x000022D0: */ 0x00,0x00,0x00,0x00,0x2A,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000022E0: */ 0x00,0x00,0x00,0x00,0x2A,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000022F0: */ 0x00,0x00,0x00,0x00,0x2A,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00002300: */ 0x00,0x00,0x00,0x00,0xE8,0x05,0x00,0x00,0xF4,0x22,0x00,0x00,0x41,0x00,0x00,0x00, +/* 0x00002310: */ 0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF4,0x22,0x00,0x00,0x9B,0x00,0x00,0x00, +/* 0x00002320: */ 0xE4,0x22,0x00,0x00,0x41,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00002330: */ 0xE4,0x22,0x00,0x00,0x9B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x06,0x00,0x00, +/* 0x00002340: */ 0x59,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x00,0x05,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00002350: */ 0x01,0x00,0x00,0x00,0xE4,0x22,0x00,0x00,0x7F,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00002360: */ 0x01,0x00,0x00,0x00,0xF4,0x22,0x00,0x00,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00002370: */ 0xE8,0x05,0x00,0x00,0x59,0x00,0x00,0x00,0x7B,0x00,0x00,0x00,0x00,0x05,0x00,0x00, +/* 0x00002380: */ 0x59,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0x00,0x05,0x00,0x00,0x3C,0x23,0x00,0x00, +/* 0x00002390: */ 0x00,0x00,0x00,0x00,0xA2,0x00,0x00,0x00,0x7B,0x00,0x00,0x00,0x30,0x02,0x00,0x00, +/* 0x000023A0: */ 0xBC,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x35,0x00,0x00,0x00,0x8E,0x00,0x00,0x00, +/* 0x000023B0: */ 0x30,0x02,0x00,0x00,0x15,0x00,0x00,0x00,0x0C,0x00,0x00,0x00,0x8C,0x00,0x00,0x00, +/* 0x000023C0: */ 0xA4,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x94,0x23,0x00,0x00, +/* 0x000023D0: */ 0x00,0x05,0x00,0x00,0x3C,0x23,0x00,0x00,0x00,0x00,0x00,0x00,0x9C,0x06,0x00,0x00, +/* 0x000023E0: */ 0x80,0x07,0x00,0x00,0xF4,0x22,0x00,0x00,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000023F0: */ 0xF4,0x22,0x00,0x00,0x41,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x2C,0x00,0x00,0x00, +/* 0x00002400: */ 0xF4,0x0C,0x00,0x00,0x80,0x0F,0x00,0x00,0x16,0x4D,0x69,0x73,0x73,0x69,0x6E,0x67, +/* 0x00002410: */ 0x20,0x45,0x4E,0x44,0x4F,0x46,0x20,0x69,0x6E,0x20,0x43,0x41,0x53,0x45,0x21,0x5A, +/* 0x00002420: */ 0x28,0x00,0x00,0x00,0x78,0x05,0x00,0x00,0x59,0x00,0x00,0x00,0x33,0x00,0x00,0x00, +/* 0x00002430: */ 0x00,0x05,0x00,0x00,0xE4,0x22,0x00,0x00,0x41,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00002440: */ 0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x2C,0x06,0x00,0x00, +/* 0x00002450: */ 0x71,0x00,0x00,0x00,0xF8,0xFF,0xFF,0xFF,0xE4,0x22,0x00,0x00,0x9B,0x00,0x00,0x00, +/* 0x00002460: */ 0xF4,0x22,0x00,0x00,0x9B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x2A,0x00,0x00,0x00, +/* 0x00002470: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x35,0x00,0x00,0x00, +/* 0x00002480: */ 0x25,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x3C,0x00,0x00,0x00,0x03,0x00,0x00,0x00, +/* 0x00002490: */ 0x01,0x00,0x00,0x00,0x7D,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0xC4,0x08,0x00,0x00, +/* 0x000024A0: */ 0x1E,0x00,0x00,0x00,0x7B,0x00,0x00,0x00,0x25,0x00,0x00,0x00,0x11,0x00,0x00,0x00, +/* 0x000024B0: */ 0xBC,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x15,0x00,0x00,0x00, +/* 0x000024C0: */ 0xCC,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x29,0x00,0x00,0x00,0x35,0x00,0x00,0x00, +/* 0x000024D0: */ 0x14,0x04,0x00,0x00,0x08,0x00,0x00,0x00,0xA1,0x00,0x00,0x00,0x70,0x03,0x00,0x00, +/* 0x000024E0: */ 0xBC,0x03,0x00,0x00,0x59,0x00,0x00,0x00,0xF4,0x24,0x00,0x00,0xD4,0x06,0x00,0x00, +/* 0x000024F0: */ 0x00,0x00,0x00,0x00,0x35,0x00,0x00,0x00,0x41,0x00,0x00,0x00,0x88,0x00,0x00,0x00, +/* 0x00002500: */ 0xA1,0x00,0x00,0x00,0x7D,0x00,0x00,0x00,0xAC,0x01,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00002510: */ 0x80,0x07,0x00,0x00,0xD8,0x01,0x00,0x00,0x35,0x00,0x00,0x00,0x18,0x00,0x00,0x00, +/* 0x00002520: */ 0x02,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x32,0x00,0x00,0x00, +/* 0x00002530: */ 0x35,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x0C,0x22,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00002540: */ 0x02,0x00,0x00,0x00,0x7C,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x0C,0x22,0x00,0x00, +/* 0x00002550: */ 0x75,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x88,0x00,0x00,0x00, +/* 0x00002560: */ 0x33,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xD8,0x01,0x00,0x00, +/* 0x00002570: */ 0x57,0x00,0x00,0x00,0x1C,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x9C,0x00,0x00,0x00, +/* 0x00002580: */ 0x02,0x00,0x00,0x00,0x9C,0x00,0x00,0x00,0x71,0x00,0x00,0x00,0xA4,0xFF,0xFF,0xFF, +/* 0x00002590: */ 0x0C,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0xA2,0x00,0x00,0x00,0x80,0x07,0x00,0x00, +/* 0x000025A0: */ 0xD8,0x01,0x00,0x00,0x8E,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000025B0: */ 0x32,0x00,0x00,0x00,0x35,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x0C,0x22,0x00,0x00, +/* 0x000025C0: */ 0x59,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x7C,0x00,0x00,0x00,0x18,0x00,0x00,0x00, +/* 0x000025D0: */ 0x0C,0x22,0x00,0x00,0x75,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x20,0x00,0x00,0x00, +/* 0x000025E0: */ 0x88,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000025F0: */ 0xD8,0x01,0x00,0x00,0x57,0x00,0x00,0x00,0x1C,0x00,0x00,0x00,0x02,0x00,0x00,0x00, +/* 0x00002600: */ 0x9C,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x9C,0x00,0x00,0x00,0x71,0x00,0x00,0x00, +/* 0x00002610: */ 0xA4,0xFF,0xFF,0xFF,0x0C,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x9C,0x00,0x00,0x00, +/* 0x00002620: */ 0x98,0x25,0x00,0x00,0x00,0x00,0x00,0x00,0x35,0x00,0x00,0x00,0x18,0x00,0x00,0x00, +/* 0x00002630: */ 0x02,0x00,0x00,0x00,0x98,0x25,0x00,0x00,0x00,0x00,0x00,0x00,0xA2,0x00,0x00,0x00, +/* 0x00002640: */ 0xA2,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x8E,0x00,0x00,0x00, +/* 0x00002650: */ 0x8E,0x00,0x00,0x00,0x7B,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x02,0x00,0x00,0x00, +/* 0x00002660: */ 0x59,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x32,0x00,0x00,0x00,0x7B,0x00,0x00,0x00, +/* 0x00002670: */ 0x53,0x00,0x00,0x00,0x7D,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x7B,0x00,0x00,0x00, +/* 0x00002680: */ 0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x28,0x00,0x00,0x00,0x88,0x00,0x00,0x00, +/* 0x00002690: */ 0x33,0x00,0x00,0x00,0x7B,0x00,0x00,0x00,0x53,0x00,0x00,0x00,0x7D,0x00,0x00,0x00, +/* 0x000026A0: */ 0x88,0x00,0x00,0x00,0x88,0x00,0x00,0x00,0x57,0x00,0x00,0x00,0x0C,0x00,0x00,0x00, +/* 0x000026B0: */ 0x71,0x00,0x00,0x00,0xB8,0xFF,0xFF,0xFF,0x0C,0x02,0x00,0x00,0x81,0x00,0x00,0x00, +/* 0x000026C0: */ 0x24,0x00,0x00,0x00,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7B,0x00,0x00,0x00, +/* 0x000026D0: */ 0x70,0x01,0x00,0x00,0x7D,0x00,0x00,0x00,0x2B,0x00,0x00,0x00,0x35,0x00,0x00,0x00, +/* 0x000026E0: */ 0x18,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x9C,0x00,0x00,0x00,0x2B,0x00,0x00,0x00, +/* 0x000026F0: */ 0x00,0x00,0x00,0x00,0x9C,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00002700: */ 0x32,0x00,0x00,0x00,0x35,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x02,0x00,0x00,0x00, +/* 0x00002710: */ 0x7D,0x00,0x00,0x00,0x88,0x03,0x00,0x00,0x71,0x00,0x00,0x00,0xE8,0xFF,0xFF,0xFF, +/* 0x00002720: */ 0x00,0x00,0x00,0x00,0x29,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x38,0x27,0x00,0x00, +/* 0x00002730: */ 0xD4,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0xF4,0x26,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00002740: */ 0x29,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x54,0x27,0x00,0x00,0xD4,0x06,0x00,0x00, +/* 0x00002750: */ 0x00,0x00,0x00,0x00,0xF4,0x26,0x00,0x00,0x70,0x01,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00002760: */ 0x2A,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00002770: */ 0x2A,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x88,0xD7,0xA5,0x08, +/* 0x00002780: */ 0x2A,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0xDC,0xA5,0x08, +/* 0x00002790: */ 0x2A,0x00,0x00,0x00,0x78,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x00, +/* 0x000027A0: */ 0x14,0x01,0x00,0x00,0x70,0x27,0x00,0x00,0x9B,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x000027B0: */ 0x00,0x00,0x00,0x00,0x80,0x27,0x00,0x00,0x9B,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000027C0: */ 0x80,0x27,0x00,0x00,0x41,0x00,0x00,0x00,0x24,0x00,0x00,0x00,0x58,0x02,0x00,0x00, +/* 0x000027D0: */ 0x48,0x0F,0x00,0x00,0x0E,0x45,0x78,0x74,0x72,0x61,0x20,0x7D,0x50,0x52,0x49,0x56, +/* 0x000027E0: */ 0x41,0x54,0x45,0x3A,0x48,0x1E,0x00,0x00,0x14,0x01,0x00,0x00,0x80,0x27,0x00,0x00, +/* 0x000027F0: */ 0x9B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x70,0x27,0x00,0x00,0x41,0x00,0x00,0x00, +/* 0x00002800: */ 0x24,0x00,0x00,0x00,0x48,0x0F,0x00,0x00,0x10,0x4D,0x69,0x73,0x73,0x69,0x6E,0x67, +/* 0x00002810: */ 0x20,0x50,0x52,0x49,0x56,0x41,0x54,0x45,0x7B,0x5A,0x5A,0x5A,0x48,0x1E,0x00,0x00, +/* 0x00002820: */ 0x80,0x27,0x00,0x00,0x41,0x00,0x00,0x00,0x24,0x00,0x00,0x00,0x48,0x0F,0x00,0x00, +/* 0x00002830: */ 0x10,0x4D,0x69,0x73,0x73,0x69,0x6E,0x67,0x20,0x7D,0x50,0x52,0x49,0x56,0x41,0x54, +/* 0x00002840: */ 0x45,0x5A,0x5A,0x5A,0x48,0x1E,0x00,0x00,0x80,0x27,0x00,0x00,0x41,0x00,0x00,0x00, +/* 0x00002850: */ 0x35,0x00,0x00,0x00,0x70,0x27,0x00,0x00,0x41,0x00,0x00,0x00,0x22,0x00,0x00,0x00, +/* 0x00002860: */ 0xBC,0x00,0x00,0x00,0x28,0x00,0x00,0x00,0x35,0x00,0x00,0x00,0x18,0x00,0x00,0x00, +/* 0x00002870: */ 0x90,0x27,0x00,0x00,0x7A,0x00,0x00,0x00,0x7B,0x00,0x00,0x00,0x2B,0x00,0x00,0x00, +/* 0x00002880: */ 0x76,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0xC8,0xFF,0xFF,0xFF,0x33,0x00,0x00,0x00, +/* 0x00002890: */ 0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x70,0x27,0x00,0x00,0x9B,0x00,0x00,0x00, +/* 0x000028A0: */ 0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x27,0x00,0x00,0x9B,0x00,0x00,0x00, +/* 0x000028B0: */ 0x00,0x00,0x00,0x00,0x2A,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000028C0: */ 0x00,0x00,0x00,0x00,0x2A,0x00,0x00,0x00,0x78,0x07,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000028D0: */ 0x10,0x00,0x00,0x00,0x2A,0x00,0x00,0x00,0x78,0x07,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000028E0: */ 0x1F,0x00,0x00,0x00,0x2A,0x00,0x00,0x00,0xF4,0x24,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000028F0: */ 0x1F,0x00,0x00,0x00,0x03,0x46,0x49,0x44,0x4D,0x45,0x2D,0x41,0x44,0x44,0x52,0x45, +/* 0x00002900: */ 0x53,0x53,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x00002910: */ 0x5A,0x5A,0x5A,0x03,0x56,0x41,0x4C,0x2D,0x41,0x44,0x44,0x52,0x45,0x53,0x53,0x5A, +/* 0x00002920: */ 0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x00002930: */ 0x5A,0x5A,0x09,0x4E,0x55,0x4D,0x2D,0x5A,0x45,0x52,0x4F,0x53,0x69,0x6C,0x6F,0x63, +/* 0x00002940: */ 0x73,0x2E,0x66,0x74,0x68,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x00002950: */ 0x5A,0x09,0x4E,0x55,0x4D,0x2D,0x42,0x59,0x54,0x45,0x53,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x00002960: */ 0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x00002970: */ 0x07,0x4F,0x4C,0x44,0x49,0x4E,0x44,0x58,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x00002980: */ 0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x04, +/* 0x00002990: */ 0x43,0x4E,0x54,0x33,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x000029A0: */ 0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x04,0x46, +/* 0x000029B0: */ 0x4C,0x41,0x47,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x000029C0: */ 0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x03,0x51,0x55, +/* 0x000029D0: */ 0x4F,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x000029E0: */ 0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x000029F0: */ 0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x00002A00: */ 0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x00002A10: */ 0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x00002A20: */ 0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x00002A30: */ 0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x00002A40: */ 0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x00002A50: */ 0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x00002A60: */ 0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x00002A70: */ 0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x00002A80: */ 0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x00002A90: */ 0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x00002AA0: */ 0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x00002AB0: */ 0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x00002AC0: */ 0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x00002AD0: */ 0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x00002AE0: */ 0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x00002AF0: */ 0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x00002B00: */ 0x5A,0x5A,0x5A,0x5A,0x2A,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00002B10: */ 0x00,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x9C,0x00,0x00,0x00, +/* 0x00002B20: */ 0x04,0x2B,0x00,0x00,0x41,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00002B30: */ 0x80,0x00,0x00,0x00,0x38,0x00,0x00,0x00,0x53,0x00,0x00,0x00,0xE4,0x28,0x00,0x00, +/* 0x00002B40: */ 0x7B,0x00,0x00,0x00,0x10,0x25,0x00,0x00,0xBC,0x00,0x00,0x00,0x18,0x00,0x00,0x00, +/* 0x00002B50: */ 0x0C,0x02,0x00,0x00,0xB4,0x08,0x00,0x00,0x53,0x00,0x00,0x00,0x57,0x00,0x00,0x00, +/* 0x00002B60: */ 0x0C,0x00,0x00,0x00,0x71,0x00,0x00,0x00,0xD0,0xFF,0xFF,0xFF,0x9C,0x00,0x00,0x00, +/* 0x00002B70: */ 0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x01,0x00,0x00,0x00, +/* 0x00002B80: */ 0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x1C,0x00,0x00,0x00, +/* 0x00002B90: */ 0x33,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x5F,0x00,0x00,0x00,0x00,0x05,0x00,0x00, +/* 0x00002BA0: */ 0x15,0x00,0x00,0x00,0x6C,0x01,0x00,0x00,0x59,0x00,0x00,0x00,0x02,0x00,0x00,0x00, +/* 0x00002BB0: */ 0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x1C,0x00,0x00,0x00, +/* 0x00002BC0: */ 0x33,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x00,0x05,0x00,0x00, +/* 0x00002BD0: */ 0x15,0x00,0x00,0x00,0x3C,0x01,0x00,0x00,0x59,0x00,0x00,0x00,0x03,0x00,0x00,0x00, +/* 0x00002BE0: */ 0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x1C,0x00,0x00,0x00, +/* 0x00002BF0: */ 0x33,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x61,0x00,0x00,0x00,0x00,0x05,0x00,0x00, +/* 0x00002C00: */ 0x15,0x00,0x00,0x00,0x0C,0x01,0x00,0x00,0x59,0x00,0x00,0x00,0x04,0x00,0x00,0x00, +/* 0x00002C10: */ 0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x1C,0x00,0x00,0x00, +/* 0x00002C20: */ 0x33,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x62,0x00,0x00,0x00,0x00,0x05,0x00,0x00, +/* 0x00002C30: */ 0x15,0x00,0x00,0x00,0xDC,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x05,0x00,0x00,0x00, +/* 0x00002C40: */ 0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x1C,0x00,0x00,0x00, +/* 0x00002C50: */ 0x33,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x63,0x00,0x00,0x00,0x00,0x05,0x00,0x00, +/* 0x00002C60: */ 0x15,0x00,0x00,0x00,0xAC,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x06,0x00,0x00,0x00, +/* 0x00002C70: */ 0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x1C,0x00,0x00,0x00, +/* 0x00002C80: */ 0x33,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x64,0x00,0x00,0x00,0x00,0x05,0x00,0x00, +/* 0x00002C90: */ 0x15,0x00,0x00,0x00,0x7C,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x07,0x00,0x00,0x00, +/* 0x00002CA0: */ 0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x1C,0x00,0x00,0x00, +/* 0x00002CB0: */ 0x33,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x65,0x00,0x00,0x00,0x00,0x05,0x00,0x00, +/* 0x00002CC0: */ 0x15,0x00,0x00,0x00,0x4C,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x08,0x00,0x00,0x00, +/* 0x00002CD0: */ 0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x1C,0x00,0x00,0x00, +/* 0x00002CE0: */ 0x33,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x66,0x00,0x00,0x00,0x00,0x05,0x00,0x00, +/* 0x00002CF0: */ 0x15,0x00,0x00,0x00,0x1C,0x00,0x00,0x00,0x35,0x00,0x00,0x00,0x58,0x00,0x00,0x00, +/* 0x00002D00: */ 0x59,0x00,0x00,0x00,0x5E,0x00,0x00,0x00,0x00,0x05,0x00,0x00,0x33,0x00,0x00,0x00, +/* 0x00002D10: */ 0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x01,0x00,0x00,0x00, +/* 0x00002D20: */ 0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x1C,0x00,0x00,0x00, +/* 0x00002D30: */ 0x33,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x69,0x00,0x00,0x00,0x00,0x05,0x00,0x00, +/* 0x00002D40: */ 0x15,0x00,0x00,0x00,0x6C,0x01,0x00,0x00,0x59,0x00,0x00,0x00,0x02,0x00,0x00,0x00, +/* 0x00002D50: */ 0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x1C,0x00,0x00,0x00, +/* 0x00002D60: */ 0x33,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x6A,0x00,0x00,0x00,0x00,0x05,0x00,0x00, +/* 0x00002D70: */ 0x15,0x00,0x00,0x00,0x3C,0x01,0x00,0x00,0x59,0x00,0x00,0x00,0x03,0x00,0x00,0x00, +/* 0x00002D80: */ 0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x1C,0x00,0x00,0x00, +/* 0x00002D90: */ 0x33,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x6B,0x00,0x00,0x00,0x00,0x05,0x00,0x00, +/* 0x00002DA0: */ 0x15,0x00,0x00,0x00,0x0C,0x01,0x00,0x00,0x59,0x00,0x00,0x00,0x04,0x00,0x00,0x00, +/* 0x00002DB0: */ 0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x1C,0x00,0x00,0x00, +/* 0x00002DC0: */ 0x33,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x6C,0x00,0x00,0x00,0x00,0x05,0x00,0x00, +/* 0x00002DD0: */ 0x15,0x00,0x00,0x00,0xDC,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x05,0x00,0x00,0x00, +/* 0x00002DE0: */ 0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x1C,0x00,0x00,0x00, +/* 0x00002DF0: */ 0x33,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x6D,0x00,0x00,0x00,0x00,0x05,0x00,0x00, +/* 0x00002E00: */ 0x15,0x00,0x00,0x00,0xAC,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x06,0x00,0x00,0x00, +/* 0x00002E10: */ 0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x1C,0x00,0x00,0x00, +/* 0x00002E20: */ 0x33,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x6E,0x00,0x00,0x00,0x00,0x05,0x00,0x00, +/* 0x00002E30: */ 0x15,0x00,0x00,0x00,0x7C,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x07,0x00,0x00,0x00, +/* 0x00002E40: */ 0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x1C,0x00,0x00,0x00, +/* 0x00002E50: */ 0x33,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x6F,0x00,0x00,0x00,0x00,0x05,0x00,0x00, +/* 0x00002E60: */ 0x15,0x00,0x00,0x00,0x4C,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x08,0x00,0x00,0x00, +/* 0x00002E70: */ 0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x1C,0x00,0x00,0x00, +/* 0x00002E80: */ 0x33,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x70,0x00,0x00,0x00,0x00,0x05,0x00,0x00, +/* 0x00002E90: */ 0x15,0x00,0x00,0x00,0x1C,0x00,0x00,0x00,0x35,0x00,0x00,0x00,0x58,0x00,0x00,0x00, +/* 0x00002EA0: */ 0x59,0x00,0x00,0x00,0x68,0x00,0x00,0x00,0x00,0x05,0x00,0x00,0x33,0x00,0x00,0x00, +/* 0x00002EB0: */ 0x00,0x00,0x00,0x00,0x14,0x2B,0x00,0x00,0xBC,0x00,0x00,0x00,0x14,0x00,0x00,0x00, +/* 0x00002EC0: */ 0x74,0x2B,0x00,0x00,0xB4,0x08,0x00,0x00,0x15,0x00,0x00,0x00,0x0C,0x00,0x00,0x00, +/* 0x00002ED0: */ 0x33,0x00,0x00,0x00,0xA4,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x2B,0x00,0x00, +/* 0x00002EE0: */ 0x41,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00002EF0: */ 0x5D,0x00,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0xDC,0x2E,0x00,0x00, +/* 0x00002F00: */ 0x04,0x2B,0x00,0x00,0x98,0x01,0x00,0x00,0x5B,0x00,0x00,0x00,0x98,0x01,0x00,0x00, +/* 0x00002F10: */ 0x00,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x2B,0x00,0x00, +/* 0x00002F20: */ 0x9B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x0F,0x00,0x00,0x11,0x4C,0x6F,0x63, +/* 0x00002F30: */ 0x61,0x6C,0x73,0x20,0x74,0x75,0x72,0x6E,0x65,0x64,0x20,0x6F,0x66,0x66,0x5A,0x5A, +/* 0x00002F40: */ 0x28,0x00,0x00,0x00,0x04,0x2B,0x00,0x00,0x98,0x01,0x00,0x00,0x5B,0x00,0x00,0x00, +/* 0x00002F50: */ 0x98,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x84,0x17,0x00,0x00,0x28,0x2F,0x00,0x00, +/* 0x00002F60: */ 0x35,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0xDC,0x00,0x00,0x00,0x04,0x2B,0x00,0x00, +/* 0x00002F70: */ 0x41,0x00,0x00,0x00,0xC4,0x28,0x00,0x00,0x3C,0x02,0x00,0x00,0x48,0x0F,0x00,0x00, +/* 0x00002F80: */ 0x19,0x54,0x6F,0x6F,0x20,0x6D,0x61,0x6E,0x79,0x20,0x6C,0x6F,0x63,0x61,0x6C,0x20, +/* 0x00002F90: */ 0x76,0x61,0x72,0x69,0x61,0x62,0x6C,0x65,0x73,0x21,0x5A,0x5A,0x48,0x1E,0x00,0x00, +/* 0x00002FA0: */ 0x04,0x2B,0x00,0x00,0x41,0x00,0x00,0x00,0xE4,0x28,0x00,0x00,0xF8,0x0D,0x00,0x00, +/* 0x00002FB0: */ 0x04,0x2B,0x00,0x00,0x41,0x00,0x00,0x00,0xE4,0x28,0x00,0x00,0x4D,0x00,0x00,0x00, +/* 0x00002FC0: */ 0x18,0x02,0x00,0x00,0xBC,0x00,0x00,0x00,0x64,0x00,0x00,0x00,0x80,0x0F,0x00,0x00, +/* 0x00002FD0: */ 0x10,0x28,0x4C,0x4F,0x43,0x41,0x4C,0x29,0x20,0x2D,0x20,0x4E,0x6F,0x74,0x65,0x3A, +/* 0x00002FE0: */ 0x20,0x5A,0x5A,0x5A,0x04,0x2B,0x00,0x00,0x41,0x00,0x00,0x00,0xE4,0x28,0x00,0x00, +/* 0x00002FF0: */ 0x70,0x01,0x00,0x00,0xA3,0x00,0x00,0x00,0x80,0x0F,0x00,0x00,0x22,0x20,0x72,0x65, +/* 0x00003000: */ 0x64,0x65,0x66,0x69,0x6E,0x65,0x64,0x20,0x61,0x73,0x20,0x61,0x20,0x6C,0x6F,0x63, +/* 0x00003010: */ 0x61,0x6C,0x20,0x76,0x61,0x72,0x69,0x61,0x62,0x6C,0x65,0x20,0x69,0x6E,0x20,0x5A, +/* 0x00003020: */ 0x14,0x01,0x00,0x00,0x90,0x02,0x00,0x00,0x28,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00003030: */ 0x01,0x00,0x00,0x00,0x04,0x2B,0x00,0x00,0x7F,0x00,0x00,0x00,0x15,0x00,0x00,0x00, +/* 0x00003040: */ 0x7C,0x00,0x00,0x00,0x0C,0x02,0x00,0x00,0x04,0x2B,0x00,0x00,0x41,0x00,0x00,0x00, +/* 0x00003050: */ 0x35,0x00,0x00,0x00,0x24,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x40,0x00,0x00,0x00, +/* 0x00003060: */ 0x33,0x00,0x00,0x00,0x80,0x0F,0x00,0x00,0x25,0x28,0x4C,0x4F,0x43,0x41,0x4C,0x29, +/* 0x00003070: */ 0x20,0x2D,0x20,0x57,0x61,0x72,0x6E,0x69,0x6E,0x67,0x3A,0x20,0x6E,0x6F,0x20,0x6C, +/* 0x00003080: */ 0x6F,0x63,0x61,0x6C,0x73,0x20,0x64,0x65,0x66,0x69,0x6E,0x65,0x64,0x21,0x5A,0x5A, +/* 0x00003090: */ 0x28,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0x24,0x00,0x00,0x00,0x58,0x00,0x00,0x00, +/* 0x000030A0: */ 0x59,0x00,0x00,0x00,0x5C,0x00,0x00,0x00,0x00,0x05,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x000030B0: */ 0xB4,0x2E,0x00,0x00,0x5B,0x00,0x00,0x00,0x9B,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000030C0: */ 0x29,0x00,0x00,0x00,0x14,0x04,0x00,0x00,0x2C,0x01,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x000030D0: */ 0xDC,0x30,0x00,0x00,0xD4,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0xB2,0x00,0x00,0x00, +/* 0x000030E0: */ 0x41,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x1C,0x00,0x00,0x00,0x0E,0x00,0x00,0x00, +/* 0x000030F0: */ 0x59,0x00,0x00,0x00,0x41,0x00,0x00,0x00,0x00,0x05,0x00,0x00,0x15,0x00,0x00,0x00, +/* 0x00003100: */ 0x08,0x00,0x00,0x00,0x41,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC4,0x08,0x00,0x00, +/* 0x00003110: */ 0xB8,0x00,0x00,0x00,0x14,0x2B,0x00,0x00,0xBC,0x00,0x00,0x00,0x10,0x00,0x00,0x00, +/* 0x00003120: */ 0x14,0x2D,0x00,0x00,0x15,0x00,0x00,0x00,0x78,0x00,0x00,0x00,0x4D,0x00,0x00,0x00, +/* 0x00003130: */ 0x59,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0x24,0x00,0x00,0x00, +/* 0x00003140: */ 0x48,0x0F,0x00,0x00,0x26,0x54,0x4F,0x20,0x6F,0x72,0x20,0x2D,0x3E,0x20,0x62,0x65, +/* 0x00003150: */ 0x66,0x6F,0x72,0x65,0x20,0x6E,0x6F,0x6E,0x2D,0x6C,0x6F,0x63,0x61,0x6C,0x20,0x6F, +/* 0x00003160: */ 0x72,0x20,0x6E,0x6F,0x6E,0x2D,0x76,0x61,0x6C,0x75,0x65,0x5A,0x48,0x1E,0x00,0x00, +/* 0x00003170: */ 0xB8,0x04,0x00,0x00,0xB2,0x00,0x00,0x00,0x41,0x00,0x00,0x00,0xBC,0x00,0x00,0x00, +/* 0x00003180: */ 0x1C,0x00,0x00,0x00,0x0E,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x9B,0x00,0x00,0x00, +/* 0x00003190: */ 0x00,0x05,0x00,0x00,0x15,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x9B,0x00,0x00,0x00, +/* 0x000031A0: */ 0x00,0x00,0x00,0x00,0x0C,0x31,0x00,0x00,0x00,0x00,0x00,0x00,0xC4,0x08,0x00,0x00, +/* 0x000031B0: */ 0xB8,0x00,0x00,0x00,0x14,0x2B,0x00,0x00,0xBC,0x00,0x00,0x00,0x20,0x00,0x00,0x00, +/* 0x000031C0: */ 0x02,0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x67,0x00,0x00,0x00, +/* 0x000031D0: */ 0x00,0x05,0x00,0x00,0x15,0x00,0x00,0x00,0x74,0x00,0x00,0x00,0x4D,0x00,0x00,0x00, +/* 0x000031E0: */ 0x59,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0x24,0x00,0x00,0x00, +/* 0x000031F0: */ 0x48,0x0F,0x00,0x00,0x21,0x2B,0x2D,0x3E,0x20,0x62,0x65,0x66,0x6F,0x72,0x65,0x20, +/* 0x00003200: */ 0x6E,0x6F,0x6E,0x2D,0x6C,0x6F,0x63,0x61,0x6C,0x20,0x6F,0x72,0x20,0x6E,0x6F,0x6E, +/* 0x00003210: */ 0x2D,0x76,0x61,0x6C,0x75,0x65,0x5A,0x5A,0x48,0x1E,0x00,0x00,0xB8,0x04,0x00,0x00, +/* 0x00003220: */ 0xB2,0x00,0x00,0x00,0x41,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x1C,0x00,0x00,0x00, +/* 0x00003230: */ 0x0E,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x7F,0x00,0x00,0x00,0x00,0x05,0x00,0x00, +/* 0x00003240: */ 0x15,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00003250: */ 0x14,0x2F,0x00,0x00,0x1B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFC,0x2E,0x00,0x00, +/* 0x00003260: */ 0x92,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xDC,0x2E,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00003270: */ 0x00,0x00,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0xFC,0x2E,0x00,0x00, +/* 0x00003280: */ 0xF0,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x2A,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00003290: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x2A,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000032A0: */ 0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0x2A,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000032B0: */ 0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0x2A,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000032C0: */ 0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xB8,0x32,0x00,0x00,0x98,0x01,0x00,0x00, +/* 0x000032D0: */ 0x98,0x32,0x00,0x00,0x98,0x01,0x00,0x00,0xA8,0x32,0x00,0x00,0x98,0x01,0x00,0x00, +/* 0x000032E0: */ 0xC4,0x08,0x00,0x00,0xB8,0x00,0x00,0x00,0x70,0x01,0x00,0x00,0x35,0x00,0x00,0x00, +/* 0x000032F0: */ 0x25,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x5C,0x01,0x00,0x00,0x7B,0x00,0x00,0x00, +/* 0x00003300: */ 0x18,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x7D,0x00,0x00,0x00,0x7B,0x00,0x00,0x00, +/* 0x00003310: */ 0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x1C,0x00,0x00,0x00,0x33,0x00,0x00,0x00, +/* 0x00003320: */ 0xB8,0x32,0x00,0x00,0x84,0x01,0x00,0x00,0x0C,0x02,0x00,0x00,0x15,0x00,0x00,0x00, +/* 0x00003330: */ 0x1C,0x01,0x00,0x00,0x59,0x00,0x00,0x00,0x7C,0x00,0x00,0x00,0x7B,0x00,0x00,0x00, +/* 0x00003340: */ 0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x1C,0x00,0x00,0x00,0x33,0x00,0x00,0x00, +/* 0x00003350: */ 0x98,0x32,0x00,0x00,0x84,0x01,0x00,0x00,0x0C,0x02,0x00,0x00,0x15,0x00,0x00,0x00, +/* 0x00003360: */ 0xEC,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x2D,0x00,0x00,0x00,0x7B,0x00,0x00,0x00, +/* 0x00003370: */ 0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x1C,0x00,0x00,0x00,0x33,0x00,0x00,0x00, +/* 0x00003380: */ 0xA8,0x32,0x00,0x00,0x84,0x01,0x00,0x00,0x0C,0x02,0x00,0x00,0x15,0x00,0x00,0x00, +/* 0x00003390: */ 0xBC,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x29,0x00,0x00,0x00,0x7B,0x00,0x00,0x00, +/* 0x000033A0: */ 0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x33,0x00,0x00,0x00, +/* 0x000033B0: */ 0x80,0x0F,0x00,0x00,0x12,0x7B,0x20,0x2E,0x2E,0x2E,0x20,0x29,0x20,0x69,0x6D,0x62, +/* 0x000033C0: */ 0x61,0x6C,0x61,0x6E,0x63,0x65,0x21,0x5A,0x28,0x00,0x00,0x00,0x78,0x05,0x00,0x00, +/* 0x000033D0: */ 0x15,0x00,0x00,0x00,0x78,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x5C,0x00,0x00,0x00, +/* 0x000033E0: */ 0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x18,0x00,0x00,0x00, +/* 0x000033F0: */ 0x33,0x00,0x00,0x00,0x60,0x01,0x00,0x00,0x0C,0x02,0x00,0x00,0x15,0x00,0x00,0x00, +/* 0x00003400: */ 0x4C,0x00,0x00,0x00,0xA2,0x00,0x00,0x00,0xA8,0x32,0x00,0x00,0x41,0x00,0x00,0x00, +/* 0x00003410: */ 0xBC,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x0C,0x02,0x00,0x00,0x15,0x00,0x00,0x00, +/* 0x00003420: */ 0x24,0x00,0x00,0x00,0x98,0x32,0x00,0x00,0x41,0x00,0x00,0x00,0xBC,0x00,0x00,0x00, +/* 0x00003430: */ 0x10,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0xA4,0x08,0x00,0x00,0x00,0x05,0x00,0x00, +/* 0x00003440: */ 0x60,0x2F,0x00,0x00,0x8E,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x15,0x00,0x00,0x00, +/* 0x00003450: */ 0x48,0x00,0x00,0x00,0x0C,0x02,0x00,0x00,0x84,0x00,0x00,0x00,0x24,0x00,0x00,0x00, +/* 0x00003460: */ 0x48,0x0F,0x00,0x00,0x2C,0x45,0x6E,0x64,0x20,0x6F,0x66,0x20,0x69,0x6E,0x70,0x75, +/* 0x00003470: */ 0x74,0x20,0x77,0x68,0x69,0x6C,0x65,0x20,0x64,0x65,0x66,0x69,0x6E,0x69,0x6E,0x67, +/* 0x00003480: */ 0x20,0x6C,0x6F,0x63,0x61,0x6C,0x20,0x76,0x61,0x72,0x69,0x61,0x62,0x6C,0x65,0x73, +/* 0x00003490: */ 0x21,0x5A,0x5A,0x5A,0x48,0x1E,0x00,0x00,0xB8,0x32,0x00,0x00,0x41,0x00,0x00,0x00, +/* 0x000034A0: */ 0xBC,0x00,0x00,0x00,0x3C,0xFE,0xFF,0xFF,0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000034B0: */ 0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x2F,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000034C0: */ 0x59,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x5C,0x00,0x00,0x00,0x5F,0x00,0x00,0x00, +/* 0x000034D0: */ 0x35,0x00,0x00,0x00,0x5F,0x00,0x00,0x00,0xA1,0x00,0x00,0x00,0x35,0x00,0x00,0x00, +/* 0x000034E0: */ 0x5F,0x00,0x00,0x00,0xA1,0x00,0x00,0x00,0x5D,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000034F0: */ 0xA4,0x08,0x00,0x00,0xA4,0x08,0x00,0x00,0x59,0x00,0x00,0x00,0x04,0x00,0x00,0x00, +/* 0x00003500: */ 0x5C,0x00,0x00,0x00,0x5F,0x00,0x00,0x00,0xA4,0x1D,0x00,0x00,0x60,0x00,0x00,0x00, +/* 0x00003510: */ 0xA4,0x1D,0x00,0x00,0x28,0x00,0x00,0x00,0x5F,0x00,0x00,0x00,0x60,0x00,0x00,0x00, +/* 0x00003520: */ 0x7D,0x00,0x00,0x00,0x6B,0x00,0x00,0x00,0x61,0x00,0x00,0x00,0xA4,0x1D,0x00,0x00, +/* 0x00003530: */ 0x62,0x00,0x00,0x00,0xA4,0x1D,0x00,0x00,0x28,0x00,0x00,0x00,0x5D,0x00,0x00,0x00, +/* 0x00003540: */ 0x00,0x00,0x00,0x00,0x2A,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00003550: */ 0x00,0x00,0x00,0x00,0xA4,0x08,0x00,0x00,0xA4,0x08,0x00,0x00,0xA4,0x08,0x00,0x00, +/* 0x00003560: */ 0xA4,0x08,0x00,0x00,0xA4,0x08,0x00,0x00,0x59,0x00,0x00,0x00,0x08,0x00,0x00,0x00, +/* 0x00003570: */ 0x5C,0x00,0x00,0x00,0x5F,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0xE8,0x07,0x00,0x00, +/* 0x00003580: */ 0x6D,0x00,0x00,0x00,0x6C,0x00,0x00,0x00,0x61,0x00,0x00,0x00,0xD0,0x07,0x00,0x00, +/* 0x00003590: */ 0x6E,0x00,0x00,0x00,0x62,0x00,0x00,0x00,0x63,0x00,0x00,0x00,0x64,0x00,0x00,0x00, +/* 0x000035A0: */ 0x3A,0x00,0x00,0x00,0x70,0x00,0x00,0x00,0x6F,0x00,0x00,0x00,0x60,0x00,0x00,0x00, +/* 0x000035B0: */ 0x26,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x74,0x00,0x00,0x00,0x61,0x00,0x00,0x00, +/* 0x000035C0: */ 0x26,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x65,0x00,0x00,0x00, +/* 0x000035D0: */ 0x60,0x02,0x00,0x00,0x6F,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0x48,0x00,0x00,0x00, +/* 0x000035E0: */ 0x65,0x00,0x00,0x00,0x24,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x18,0x00,0x00,0x00, +/* 0x000035F0: */ 0x66,0x00,0x00,0x00,0x60,0x02,0x00,0x00,0x70,0x00,0x00,0x00,0x15,0x00,0x00,0x00, +/* 0x00003600: */ 0x24,0x00,0x00,0x00,0x66,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x60,0x02,0x00,0x00, +/* 0x00003610: */ 0x70,0x00,0x00,0x00,0x64,0x00,0x00,0x00,0x65,0x00,0x00,0x00,0x75,0x00,0x00,0x00, +/* 0x00003620: */ 0x6F,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0x5C,0x00,0x00,0x00,0x61,0x00,0x00,0x00, +/* 0x00003630: */ 0x26,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x4C,0x00,0x00,0x00,0x65,0x00,0x00,0x00, +/* 0x00003640: */ 0x24,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x66,0x00,0x00,0x00, +/* 0x00003650: */ 0x60,0x02,0x00,0x00,0x70,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0x28,0x00,0x00,0x00, +/* 0x00003660: */ 0x64,0x00,0x00,0x00,0x65,0x00,0x00,0x00,0x75,0x00,0x00,0x00,0x60,0x02,0x00,0x00, +/* 0x00003670: */ 0x6F,0x00,0x00,0x00,0x66,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x60,0x02,0x00,0x00, +/* 0x00003680: */ 0x70,0x00,0x00,0x00,0x65,0x00,0x00,0x00,0x66,0x00,0x00,0x00,0x5D,0x00,0x00,0x00, +/* 0x00003690: */ 0x00,0x00,0x00,0x00,0xA4,0x08,0x00,0x00,0xA4,0x08,0x00,0x00,0xA4,0x08,0x00,0x00, +/* 0x000036A0: */ 0xA4,0x08,0x00,0x00,0xA4,0x08,0x00,0x00,0x59,0x00,0x00,0x00,0x08,0x00,0x00,0x00, +/* 0x000036B0: */ 0x5C,0x00,0x00,0x00,0x5F,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0xE8,0x07,0x00,0x00, +/* 0x000036C0: */ 0x6D,0x00,0x00,0x00,0x6C,0x00,0x00,0x00,0x61,0x00,0x00,0x00,0xD0,0x07,0x00,0x00, +/* 0x000036D0: */ 0x6E,0x00,0x00,0x00,0x62,0x00,0x00,0x00,0x63,0x00,0x00,0x00,0x64,0x00,0x00,0x00, +/* 0x000036E0: */ 0x3A,0x00,0x00,0x00,0x70,0x00,0x00,0x00,0x6F,0x00,0x00,0x00,0x60,0x00,0x00,0x00, +/* 0x000036F0: */ 0x26,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x34,0x00,0x00,0x00,0x65,0x00,0x00,0x00, +/* 0x00003700: */ 0x60,0x02,0x00,0x00,0x6F,0x00,0x00,0x00,0x61,0x00,0x00,0x00,0x25,0x00,0x00,0x00, +/* 0x00003710: */ 0xBC,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x66,0x00,0x00,0x00,0x60,0x02,0x00,0x00, +/* 0x00003720: */ 0x70,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x61,0x00,0x00,0x00, +/* 0x00003730: */ 0x26,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x66,0x00,0x00,0x00, +/* 0x00003740: */ 0x60,0x02,0x00,0x00,0x70,0x00,0x00,0x00,0x65,0x00,0x00,0x00,0x66,0x00,0x00,0x00, +/* 0x00003750: */ 0x5D,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xA2,0x00,0x00,0x00,0x00,0x08,0x00,0x00, +/* 0x00003760: */ 0x8E,0x00,0x00,0x00,0x94,0x36,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x37,0x00,0x00, +/* 0x00003770: */ 0x33,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xA2,0x00,0x00,0x00,0x37,0x00,0x00,0x00, +/* 0x00003780: */ 0x8E,0x00,0x00,0x00,0x94,0x36,0x00,0x00,0x00,0x00,0x00,0x00,0x78,0x37,0x00,0x00, +/* 0x00003790: */ 0x18,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x2A,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000037A0: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC4,0x08,0x00,0x00,0xB8,0x00,0x00,0x00, +/* 0x000037B0: */ 0x4D,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x2C,0x00,0x00,0x00,0xB2,0x00,0x00,0x00, +/* 0x000037C0: */ 0x41,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x1C,0x00,0x00,0x00,0x50,0x04,0x00,0x00, +/* 0x000037D0: */ 0x75,0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x80,0x04,0x00,0x00, +/* 0x000037E0: */ 0x00,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0xB2,0x00,0x00,0x00,0x41,0x00,0x00,0x00, +/* 0x000037F0: */ 0xBC,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00003800: */ 0xA0,0x00,0x00,0x00,0xE8,0x37,0x00,0x00,0x00,0x00,0x00,0x00,0x2A,0x00,0x00,0x00, +/* 0x00003810: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x2A,0x00,0x00,0x00, +/* 0x00003820: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x27,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00003830: */ 0x00,0x00,0x00,0x00,0x32,0x00,0x00,0x00,0x1C,0x38,0x00,0x00,0x41,0x00,0x00,0x00, +/* 0x00003840: */ 0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x32,0x00,0x00,0x00,0x71,0x00,0x00,0x00, +/* 0x00003850: */ 0xFC,0xFF,0xFF,0xFF,0x71,0x00,0x00,0x00,0xE0,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00, +/* 0x00003860: */ 0x2D,0x00,0x00,0x00,0x2C,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x35,0x00,0x00,0x00, +/* 0x00003870: */ 0x26,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x60,0x02,0x00,0x00, +/* 0x00003880: */ 0x12,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x72,0x00,0x00,0x00, +/* 0x00003890: */ 0x00,0x00,0x00,0x00,0x2A,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000038A0: */ 0xB4,0xB8,0x1B,0x40,0x94,0x38,0x00,0x00,0x41,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x000038B0: */ 0xBD,0x7A,0x00,0x00,0xA1,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x0F,0x1B,0x00,0x00, +/* 0x000038C0: */ 0x7D,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x11,0x00,0x00,0x00, +/* 0x000038D0: */ 0x35,0x00,0x00,0x00,0x94,0x38,0x00,0x00,0x9B,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000038E0: */ 0xA4,0x38,0x00,0x00,0xA1,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0xF0,0xFF,0xFF,0xFF, +/* 0x000038F0: */ 0x6C,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x00,0x75,0x00,0x00,0x00, +/* 0x00003900: */ 0xE0,0x38,0x00,0x00,0x7D,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00, +/* 0x00003910: */ 0x1F,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x9C,0x00,0x00,0x00, +/* 0x00003920: */ 0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0xBC,0x00,0x00,0x00, +/* 0x00003930: */ 0x08,0x00,0x00,0x00,0x9C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x29,0x00,0x00,0x00, +/* 0x00003940: */ 0xBC,0x03,0x00,0x00,0x59,0x00,0x00,0x00,0x54,0x39,0x00,0x00,0xD4,0x06,0x00,0x00, +/* 0x00003950: */ 0x00,0x00,0x00,0x00,0x7D,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x29,0x00,0x00,0x00, +/* 0x00003960: */ 0x50,0x08,0x00,0x00,0xBC,0x03,0x00,0x00,0x59,0x00,0x00,0x00,0x78,0x39,0x00,0x00, +/* 0x00003970: */ 0xD4,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x9C,0x00,0x00,0x00,0x50,0x08,0x00,0x00, +/* 0x00003980: */ 0x7D,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x29,0x00,0x00,0x00,0xC4,0x01,0x00,0x00, +/* 0x00003990: */ 0xBC,0x03,0x00,0x00,0x59,0x00,0x00,0x00,0xA4,0x39,0x00,0x00,0xD4,0x06,0x00,0x00, +/* 0x000039A0: */ 0x00,0x00,0x00,0x00,0x9C,0x00,0x00,0x00,0xC4,0x01,0x00,0x00,0x7D,0x00,0x00,0x00, +/* 0x000039B0: */ 0x00,0x00,0x00,0x00,0xA5,0x00,0x00,0x00,0x41,0x00,0x00,0x00,0xE4,0x02,0x00,0x00, +/* 0x000039C0: */ 0x9C,0x00,0x00,0x00,0xA4,0x1D,0x00,0x00,0xA5,0x00,0x00,0x00,0x9B,0x00,0x00,0x00, +/* 0x000039D0: */ 0x00,0x00,0x00,0x00,0xA5,0x00,0x00,0x00,0x41,0x00,0x00,0x00,0xA8,0x02,0x00,0x00, +/* 0x000039E0: */ 0x9C,0x00,0x00,0x00,0xA4,0x1D,0x00,0x00,0xA5,0x00,0x00,0x00,0x9B,0x00,0x00,0x00, +/* 0x000039F0: */ 0x00,0x00,0x00,0x00,0xA5,0x00,0x00,0x00,0x41,0x00,0x00,0x00,0xD0,0x02,0x00,0x00, +/* 0x00003A00: */ 0x9C,0x00,0x00,0x00,0xA4,0x1D,0x00,0x00,0xA5,0x00,0x00,0x00,0x9B,0x00,0x00,0x00, +/* 0x00003A10: */ 0x00,0x00,0x00,0x00,0x35,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x80,0x00,0x00,0x00, +/* 0x00003A20: */ 0x11,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00003A30: */ 0x00,0xFF,0xFF,0xFF,0x7A,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0x10,0x00,0x00,0x00, +/* 0x00003A40: */ 0x59,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00003A50: */ 0x35,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x11,0x00,0x00,0x00, +/* 0x00003A60: */ 0xBC,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF, +/* 0x00003A70: */ 0x7A,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00003A80: */ 0xFF,0xFF,0x00,0x00,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00003A90: */ 0x03,0x00,0x00,0x00,0x5C,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x61,0x00,0x00,0x00, +/* 0x00003AA0: */ 0x30,0x02,0x00,0x00,0xBC,0x00,0x00,0x00,0x28,0x00,0x00,0x00,0x60,0x00,0x00,0x00, +/* 0x00003AB0: */ 0x5F,0x00,0x00,0x00,0x30,0x02,0x00,0x00,0x5F,0x00,0x00,0x00,0x61,0x00,0x00,0x00, +/* 0x00003AC0: */ 0x20,0x00,0x00,0x00,0x11,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0x20,0x00,0x00,0x00, +/* 0x00003AD0: */ 0x60,0x00,0x00,0x00,0x5F,0x00,0x00,0x00,0x30,0x02,0x00,0x00,0x5F,0x00,0x00,0x00, +/* 0x00003AE0: */ 0x61,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x7A,0x00,0x00,0x00,0x5D,0x00,0x00,0x00, +/* 0x00003AF0: */ 0x00,0x00,0x00,0x00,0xA2,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x75,0x00,0x00,0x00, +/* 0x00003B00: */ 0x26,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x8E,0x00,0x00,0x00, +/* 0x00003B10: */ 0x1A,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0x0C,0x00,0x00,0x00,0x8E,0x00,0x00,0x00, +/* 0x00003B20: */ 0x19,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x35,0x00,0x00,0x00,0x25,0x00,0x00,0x00, +/* 0x00003B30: */ 0xBC,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00003B40: */ 0x4C,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x0C,0x02,0x00,0x00, +/* 0x00003B50: */ 0x00,0x00,0x00,0x00,0x35,0x00,0x00,0x00,0x25,0x00,0x00,0x00,0xBC,0x00,0x00,0x00, +/* 0x00003B60: */ 0x14,0x00,0x00,0x00,0xC4,0x08,0x00,0x00,0x4C,0x00,0x00,0x00,0x15,0x00,0x00,0x00, +/* 0x00003B70: */ 0x08,0x00,0x00,0x00,0x0C,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x84,0x00,0x00,0x00, +/* 0x00003B80: */ 0x33,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x2A,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00003B90: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC8,0x00,0x00,0x00,0x88,0x3B,0x00,0x00, +/* 0x00003BA0: */ 0x9B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x00,0x00,0x00,0x33,0x00,0x00,0x00, +/* 0x00003BB0: */ 0x00,0x00,0x00,0x00,0x74,0x04,0x00,0x00,0x51,0x00,0x00,0x00,0x75,0x00,0x00,0x00, +/* 0x00003BC0: */ 0x00,0x00,0x00,0x00,0x80,0x0F,0x00,0x00,0x0C,0x43,0x6F,0x64,0x65,0x20,0x53,0x65, +/* 0x00003BD0: */ 0x67,0x6D,0x65,0x6E,0x74,0x5A,0x5A,0x5A,0x28,0x00,0x00,0x00,0x80,0x0F,0x00,0x00, +/* 0x00003BE0: */ 0x18,0x20,0x20,0x20,0x43,0x4F,0x44,0x45,0x42,0x41,0x53,0x45,0x20,0x20,0x20,0x20, +/* 0x00003BF0: */ 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x3D,0x20,0x5A,0x5A,0x5A,0x5C,0x04,0x00,0x00, +/* 0x00003C00: */ 0xF4,0x39,0x00,0x00,0x28,0x00,0x00,0x00,0x80,0x0F,0x00,0x00,0x18,0x20,0x20,0x20, +/* 0x00003C10: */ 0x48,0x45,0x52,0x45,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, +/* 0x00003C20: */ 0x20,0x20,0x20,0x3D,0x20,0x5A,0x5A,0x5A,0x51,0x00,0x00,0x00,0xF4,0x39,0x00,0x00, +/* 0x00003C30: */ 0x28,0x00,0x00,0x00,0x80,0x0F,0x00,0x00,0x18,0x20,0x20,0x20,0x43,0x4F,0x44,0x45, +/* 0x00003C40: */ 0x4C,0x49,0x4D,0x49,0x54,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x3D, +/* 0x00003C50: */ 0x20,0x5A,0x5A,0x5A,0x74,0x04,0x00,0x00,0xF4,0x39,0x00,0x00,0x28,0x00,0x00,0x00, +/* 0x00003C60: */ 0x80,0x0F,0x00,0x00,0x18,0x20,0x20,0x20,0x43,0x6F,0x6D,0x70,0x69,0x6C,0x65,0x64, +/* 0x00003C70: */ 0x20,0x43,0x6F,0x64,0x65,0x20,0x53,0x69,0x7A,0x65,0x20,0x3D,0x20,0x5A,0x5A,0x5A, +/* 0x00003C80: */ 0x51,0x00,0x00,0x00,0x5C,0x04,0x00,0x00,0x75,0x00,0x00,0x00,0xA4,0x1D,0x00,0x00, +/* 0x00003C90: */ 0x28,0x00,0x00,0x00,0x80,0x0F,0x00,0x00,0x18,0x20,0x20,0x20,0x43,0x4F,0x44,0x45, +/* 0x00003CA0: */ 0x2D,0x53,0x49,0x5A,0x45,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x3D, +/* 0x00003CB0: */ 0x20,0x5A,0x5A,0x5A,0xE0,0x14,0x00,0x00,0x41,0x00,0x00,0x00,0xA4,0x1D,0x00,0x00, +/* 0x00003CC0: */ 0x28,0x00,0x00,0x00,0x80,0x0F,0x00,0x00,0x18,0x20,0x20,0x20,0x43,0x6F,0x64,0x65, +/* 0x00003CD0: */ 0x20,0x52,0x6F,0x6F,0x6D,0x20,0x55,0x4E,0x55,0x53,0x45,0x44,0x20,0x20,0x20,0x3D, +/* 0x00003CE0: */ 0x20,0x5A,0x5A,0x5A,0xB4,0x3B,0x00,0x00,0xA4,0x1D,0x00,0x00,0x28,0x00,0x00,0x00, +/* 0x00003CF0: */ 0x80,0x0F,0x00,0x00,0x0C,0x4E,0x61,0x6D,0x65,0x20,0x53,0x65,0x67,0x6D,0x65,0x6E, +/* 0x00003D00: */ 0x74,0x5A,0x5A,0x5A,0x28,0x00,0x00,0x00,0x80,0x0F,0x00,0x00,0x18,0x20,0x20,0x20, +/* 0x00003D10: */ 0x4E,0x41,0x4D,0x45,0x42,0x41,0x53,0x45,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, +/* 0x00003D20: */ 0x20,0x20,0x20,0x3D,0x20,0x5A,0x5A,0x5A,0x50,0x04,0x00,0x00,0xF4,0x39,0x00,0x00, +/* 0x00003D30: */ 0x28,0x00,0x00,0x00,0x80,0x0F,0x00,0x00,0x18,0x20,0x20,0x20,0x48,0x45,0x41,0x44, +/* 0x00003D40: */ 0x45,0x52,0x53,0x2D,0x50,0x54,0x52,0x20,0x40,0x20,0x20,0x20,0x20,0x20,0x20,0x3D, +/* 0x00003D50: */ 0x20,0x5A,0x5A,0x5A,0xAD,0x00,0x00,0x00,0x41,0x00,0x00,0x00,0xF4,0x39,0x00,0x00, +/* 0x00003D60: */ 0x28,0x00,0x00,0x00,0x80,0x0F,0x00,0x00,0x18,0x20,0x20,0x20,0x4E,0x41,0x4D,0x45, +/* 0x00003D70: */ 0x4C,0x49,0x4D,0x49,0x54,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x3D, +/* 0x00003D80: */ 0x20,0x5A,0x5A,0x5A,0x68,0x04,0x00,0x00,0xF4,0x39,0x00,0x00,0x28,0x00,0x00,0x00, +/* 0x00003D90: */ 0x80,0x0F,0x00,0x00,0x18,0x20,0x20,0x20,0x43,0x4F,0x4E,0x54,0x45,0x58,0x54,0x20, +/* 0x00003DA0: */ 0x40,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x3D,0x20,0x5A,0x5A,0x5A, +/* 0x00003DB0: */ 0xA8,0x00,0x00,0x00,0x41,0x00,0x00,0x00,0xF4,0x39,0x00,0x00,0x28,0x00,0x00,0x00, +/* 0x00003DC0: */ 0x80,0x0F,0x00,0x00,0x18,0x20,0x20,0x20,0x4C,0x41,0x54,0x45,0x53,0x54,0x20,0x20, +/* 0x00003DD0: */ 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x3D,0x20,0x5A,0x5A,0x5A, +/* 0x00003DE0: */ 0x14,0x01,0x00,0x00,0xF4,0x39,0x00,0x00,0x80,0x0F,0x00,0x00,0x03,0x20,0x3D,0x20, +/* 0x00003DF0: */ 0x14,0x01,0x00,0x00,0x90,0x02,0x00,0x00,0x28,0x00,0x00,0x00,0x80,0x0F,0x00,0x00, +/* 0x00003E00: */ 0x18,0x20,0x20,0x20,0x43,0x6F,0x6D,0x70,0x69,0x6C,0x65,0x64,0x20,0x4E,0x61,0x6D, +/* 0x00003E10: */ 0x65,0x20,0x73,0x69,0x7A,0x65,0x20,0x3D,0x20,0x5A,0x5A,0x5A,0xAD,0x00,0x00,0x00, +/* 0x00003E20: */ 0x41,0x00,0x00,0x00,0x50,0x04,0x00,0x00,0x75,0x00,0x00,0x00,0xA4,0x1D,0x00,0x00, +/* 0x00003E30: */ 0x28,0x00,0x00,0x00,0x80,0x0F,0x00,0x00,0x18,0x20,0x20,0x20,0x48,0x45,0x41,0x44, +/* 0x00003E40: */ 0x45,0x52,0x53,0x2D,0x53,0x49,0x5A,0x45,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x3D, +/* 0x00003E50: */ 0x20,0x5A,0x5A,0x5A,0xD0,0x14,0x00,0x00,0x41,0x00,0x00,0x00,0xA4,0x1D,0x00,0x00, +/* 0x00003E60: */ 0x28,0x00,0x00,0x00,0x80,0x0F,0x00,0x00,0x18,0x20,0x20,0x20,0x4E,0x61,0x6D,0x65, +/* 0x00003E70: */ 0x20,0x52,0x6F,0x6F,0x6D,0x20,0x4C,0x65,0x66,0x74,0x20,0x20,0x20,0x20,0x20,0x3D, +/* 0x00003E80: */ 0x20,0x5A,0x5A,0x5A,0x68,0x04,0x00,0x00,0xAD,0x00,0x00,0x00,0x41,0x00,0x00,0x00, +/* 0x00003E90: */ 0x75,0x00,0x00,0x00,0xA4,0x1D,0x00,0x00,0x28,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00003EA0: */ 0xA4,0x08,0x00,0x00,0xA4,0x08,0x00,0x00,0xA4,0x08,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00003EB0: */ 0x07,0x00,0x00,0x00,0x5C,0x00,0x00,0x00,0x5F,0x00,0x00,0x00,0x6D,0x00,0x00,0x00, +/* 0x00003EC0: */ 0x60,0x00,0x00,0x00,0x6E,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x62,0x00,0x00,0x00, +/* 0x00003ED0: */ 0x20,0x00,0x00,0x00,0x58,0x02,0x00,0x00,0xBC,0x00,0x00,0x00,0xC4,0x00,0x00,0x00, +/* 0x00003EE0: */ 0x60,0x00,0x00,0x00,0x62,0x00,0x00,0x00,0x75,0x00,0x00,0x00,0x02,0x00,0x00,0x00, +/* 0x00003EF0: */ 0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x32,0x00,0x00,0x00,0xB4,0x08,0x00,0x00, +/* 0x00003F00: */ 0x6F,0x00,0x00,0x00,0x62,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00003F10: */ 0x80,0x00,0x00,0x00,0x50,0x00,0x00,0x00,0x61,0x00,0x00,0x00,0x53,0x00,0x00,0x00, +/* 0x00003F20: */ 0x7D,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x5F,0x00,0x00,0x00,0x53,0x00,0x00,0x00, +/* 0x00003F30: */ 0x55,0x00,0x00,0x00,0x7D,0x00,0x00,0x00,0x7D,0x00,0x00,0x00,0x18,0x00,0x00,0x00, +/* 0x00003F40: */ 0x21,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0xA4,0x08,0x00,0x00, +/* 0x00003F50: */ 0x6F,0x00,0x00,0x00,0x57,0x00,0x00,0x00,0x0C,0x00,0x00,0x00,0x71,0x00,0x00,0x00, +/* 0x00003F60: */ 0xB8,0xFF,0xFF,0xFF,0x65,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x2C,0x00,0x00,0x00, +/* 0x00003F70: */ 0x5F,0x00,0x00,0x00,0x53,0x00,0x00,0x00,0x7D,0x00,0x00,0x00,0x6D,0x00,0x00,0x00, +/* 0x00003F80: */ 0x60,0x00,0x00,0x00,0x53,0x00,0x00,0x00,0x75,0x00,0x00,0x00,0x6E,0x00,0x00,0x00, +/* 0x00003F90: */ 0x57,0x00,0x00,0x00,0x0C,0x00,0x00,0x00,0x71,0x00,0x00,0x00,0x60,0xFF,0xFF,0xFF, +/* 0x00003FA0: */ 0x63,0x00,0x00,0x00,0x64,0x00,0x00,0x00,0x65,0x00,0x00,0x00,0x5D,0x00,0x00,0x00, +/* 0x00003FB0: */ 0x00,0x00,0x00,0x00,0x2A,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00003FC0: */ 0x00,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0xC4,0x08,0x00,0x00, +/* 0x00003FD0: */ 0xB8,0x00,0x00,0x00,0x70,0x01,0x00,0x00,0x35,0x00,0x00,0x00,0xBC,0x00,0x00,0x00, +/* 0x00003FE0: */ 0xB0,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x64,0x0F,0x00,0x00,0x04,0x5B,0x49,0x46, +/* 0x00003FF0: */ 0x5D,0x5A,0x5A,0x5A,0x1D,0x00,0x00,0x00,0x24,0x00,0x00,0x00,0xBC,0x00,0x00,0x00, +/* 0x00004000: */ 0x14,0x00,0x00,0x00,0x0C,0x02,0x00,0x00,0x02,0x00,0x00,0x00,0x15,0x00,0x00,0x00, +/* 0x00004010: */ 0x64,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x64,0x0F,0x00,0x00,0x06,0x5B,0x45,0x4C, +/* 0x00004020: */ 0x53,0x45,0x5D,0x5A,0x1D,0x00,0x00,0x00,0x24,0x00,0x00,0x00,0xBC,0x00,0x00,0x00, +/* 0x00004030: */ 0x24,0x00,0x00,0x00,0x0C,0x02,0x00,0x00,0x01,0x00,0x00,0x00,0x35,0x00,0x00,0x00, +/* 0x00004040: */ 0xBC,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x15,0x00,0x00,0x00, +/* 0x00004050: */ 0x24,0x00,0x00,0x00,0x64,0x0F,0x00,0x00,0x06,0x5B,0x54,0x48,0x45,0x4E,0x5D,0x5A, +/* 0x00004060: */ 0x1D,0x00,0x00,0x00,0x24,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x08,0x00,0x00,0x00, +/* 0x00004070: */ 0x01,0x00,0x00,0x00,0x81,0x00,0x00,0x00,0x24,0x00,0x00,0x00,0xBC,0x00,0x00,0x00, +/* 0x00004080: */ 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0x40,0xFF,0xFF,0xFF, +/* 0x00004090: */ 0x0C,0x02,0x00,0x00,0x84,0x00,0x00,0x00,0x24,0x00,0x00,0x00,0xBC,0x00,0x00,0x00, +/* 0x000040A0: */ 0x2C,0xFF,0xFF,0xFF,0x33,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x24,0x00,0x00,0x00, +/* 0x000040B0: */ 0xBC,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0xC4,0x3F,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000040C0: */ 0x00,0x00,0x00,0x00,0xC4,0x08,0x00,0x00,0xB8,0x00,0x00,0x00,0x4D,0x00,0x00,0x00, +/* 0x000040D0: */ 0x9C,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x2A,0x00,0x00,0x00, +/* 0x000040E0: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x000040F0: */ 0x20,0x00,0x00,0x00,0xB8,0x00,0x00,0x00,0x4D,0x00,0x00,0x00,0xBC,0x00,0x00,0x00, +/* 0x00004100: */ 0x14,0x00,0x00,0x00,0xB8,0x04,0x00,0x00,0xB4,0x08,0x00,0x00,0x15,0x00,0x00,0x00, +/* 0x00004110: */ 0x08,0x00,0x00,0x00,0xA4,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x2A,0x00,0x00,0x00, +/* 0x00004120: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x2A,0x00,0x00,0x00, +/* 0x00004130: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x2A,0x00,0x00,0x00, +/* 0x00004140: */ 0x78,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x2A,0x00,0x00,0x00, +/* 0x00004150: */ 0x78,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x2A,0x00,0x00,0x00, +/* 0x00004160: */ 0x78,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x41,0x00,0x00,0x00, +/* 0x00004170: */ 0x00,0x00,0x00,0x00,0x14,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x5C,0x41,0x00,0x00, +/* 0x00004180: */ 0x7D,0x00,0x00,0x00,0x41,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x04,0x00,0x00, +/* 0x00004190: */ 0x00,0x00,0x00,0x00,0x35,0x00,0x00,0x00,0xA2,0x00,0x00,0x00,0xD0,0x07,0x00,0x00, +/* 0x000041A0: */ 0x2C,0x41,0x00,0x00,0x41,0x00,0x00,0x00,0x24,0x02,0x00,0x00,0x41,0x00,0x00,0x00, +/* 0x000041B0: */ 0x7B,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x11,0x00,0x00,0x00, +/* 0x000041C0: */ 0x24,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x88,0x03,0x00,0x00, +/* 0x000041D0: */ 0x15,0x00,0x00,0x00,0x24,0x00,0x00,0x00,0x7B,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x000041E0: */ 0x01,0x00,0x00,0x00,0x11,0x00,0x00,0x00,0x24,0x00,0x00,0x00,0xBC,0x00,0x00,0x00, +/* 0x000041F0: */ 0x08,0x00,0x00,0x00,0x70,0x03,0x00,0x00,0x9C,0x00,0x00,0x00,0x7B,0x00,0x00,0x00, +/* 0x00004200: */ 0x7D,0x00,0x00,0x00,0x88,0x00,0x00,0x00,0x9B,0x00,0x00,0x00,0x74,0x41,0x00,0x00, +/* 0x00004210: */ 0x8E,0x00,0x00,0x00,0x8C,0x41,0x00,0x00,0x00,0x00,0x00,0x00,0x2C,0x41,0x00,0x00, +/* 0x00004220: */ 0x41,0x00,0x00,0x00,0x41,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1C,0x42,0x00,0x00, +/* 0x00004230: */ 0x9C,0x00,0x00,0x00,0x2C,0x41,0x00,0x00,0x41,0x00,0x00,0x00,0x9B,0x00,0x00,0x00, +/* 0x00004240: */ 0x00,0x00,0x00,0x00,0x1C,0x42,0x00,0x00,0x1E,0x00,0x00,0x00,0x58,0x02,0x00,0x00, +/* 0x00004250: */ 0x48,0x0F,0x00,0x00,0x32,0x7D,0x55,0x4E,0x49,0x4F,0x4E,0x20,0x2D,0x20,0x54,0x77, +/* 0x00004260: */ 0x6F,0x20,0x70,0x61,0x72,0x74,0x73,0x20,0x6F,0x66,0x20,0x55,0x4E,0x49,0x4F,0x4E, +/* 0x00004270: */ 0x20,0x61,0x72,0x65,0x20,0x6E,0x6F,0x74,0x20,0x74,0x68,0x65,0x20,0x73,0x61,0x6D, +/* 0x00004280: */ 0x65,0x20,0x73,0x69,0x7A,0x65,0x21,0x5A,0x48,0x1E,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00004290: */ 0x29,0x00,0x00,0x00,0x94,0x41,0x00,0x00,0x2C,0x01,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x000042A0: */ 0xAC,0x42,0x00,0x00,0xD4,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x6C,0x41,0x00,0x00, +/* 0x000042B0: */ 0xE8,0x37,0x00,0x00,0x00,0x00,0x00,0x00,0xEC,0x40,0x00,0x00,0x58,0x02,0x00,0x00, +/* 0x000042C0: */ 0xBC,0x00,0x00,0x00,0x44,0x00,0x00,0x00,0x28,0x00,0x00,0x00,0x70,0x01,0x00,0x00, +/* 0x000042D0: */ 0xA3,0x00,0x00,0x00,0x80,0x0F,0x00,0x00,0x06,0x20,0x20,0x20,0x3F,0x3F,0x3F,0x5A, +/* 0x000042E0: */ 0xB4,0x08,0x00,0x00,0x48,0x0F,0x00,0x00,0x1B,0x4F,0x42,0x2E,0x46,0x49,0x4E,0x44, +/* 0x000042F0: */ 0x49,0x54,0x20,0x2D,0x20,0x57,0x6F,0x72,0x64,0x20,0x6E,0x6F,0x74,0x20,0x66,0x6F, +/* 0x00004300: */ 0x75,0x6E,0x64,0x21,0x48,0x1E,0x00,0x00,0x00,0x00,0x00,0x00,0x35,0x00,0x00,0x00, +/* 0x00004310: */ 0x6C,0x41,0x00,0x00,0x9C,0x00,0x00,0x00,0x7C,0x41,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00004320: */ 0xB8,0x42,0x00,0x00,0x0C,0x43,0x00,0x00,0x00,0x00,0x00,0x00,0xB8,0x42,0x00,0x00, +/* 0x00004330: */ 0x41,0x00,0x00,0x00,0xE8,0x37,0x00,0x00,0x00,0x00,0x00,0x00,0x1C,0x41,0x00,0x00, +/* 0x00004340: */ 0x41,0x00,0x00,0x00,0x4C,0x41,0x00,0x00,0x1E,0x00,0x00,0x00,0x58,0x02,0x00,0x00, +/* 0x00004350: */ 0x48,0x0F,0x00,0x00,0x2A,0x42,0x59,0x54,0x45,0x53,0x20,0x2D,0x20,0x4F,0x6E,0x6C, +/* 0x00004360: */ 0x79,0x20,0x76,0x61,0x6C,0x69,0x64,0x20,0x69,0x6E,0x20,0x3A,0x53,0x54,0x52,0x55, +/* 0x00004370: */ 0x43,0x54,0x20,0x64,0x65,0x66,0x69,0x6E,0x69,0x74,0x69,0x6F,0x6E,0x73,0x2E,0x5A, +/* 0x00004380: */ 0x48,0x1E,0x00,0x00,0x90,0x42,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x07,0x00,0x00, +/* 0x00004390: */ 0x3C,0x43,0x00,0x00,0x00,0x00,0x00,0x00,0x90,0x07,0x00,0x00,0x3C,0x43,0x00,0x00, +/* 0x000043A0: */ 0x00,0x00,0x00,0x00,0xC2,0x00,0x00,0x00,0x3C,0x43,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000043B0: */ 0x59,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x3C,0x43,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000043C0: */ 0x59,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x3C,0x43,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000043D0: */ 0xA4,0x43,0x00,0x00,0x00,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0xFC,0xFF,0xFF,0xFF, +/* 0x000043E0: */ 0x3C,0x43,0x00,0x00,0x00,0x00,0x00,0x00,0xA4,0x43,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000043F0: */ 0x2C,0x43,0x00,0x00,0x3C,0x43,0x00,0x00,0x00,0x00,0x00,0x00,0x2A,0x00,0x00,0x00, +/* 0x00004400: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x29,0x00,0x00,0x00, +/* 0x00004410: */ 0x41,0x00,0x00,0x00,0x70,0x03,0x00,0x00,0x51,0x00,0x00,0x00,0x9C,0x00,0x00,0x00, +/* 0x00004420: */ 0x35,0x00,0x00,0x00,0xBC,0x03,0x00,0x00,0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00004430: */ 0x4C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1C,0x41,0x00,0x00,0x41,0x00,0x00,0x00, +/* 0x00004440: */ 0x48,0x0F,0x00,0x00,0x30,0x3A,0x53,0x54,0x52,0x55,0x43,0x54,0x20,0x2D,0x20,0x50, +/* 0x00004450: */ 0x72,0x65,0x76,0x69,0x6F,0x75,0x73,0x20,0x3A,0x53,0x54,0x52,0x55,0x43,0x54,0x20, +/* 0x00004460: */ 0x6F,0x72,0x20,0x3A,0x43,0x4C,0x41,0x53,0x53,0x20,0x75,0x6E,0x66,0x69,0x6E,0x69, +/* 0x00004470: */ 0x73,0x68,0x65,0x64,0x21,0x5A,0x5A,0x5A,0xF4,0x1D,0x00,0x00,0x4C,0x41,0x00,0x00, +/* 0x00004480: */ 0x1C,0x41,0x00,0x00,0x9B,0x00,0x00,0x00,0x29,0x00,0x00,0x00,0x51,0x00,0x00,0x00, +/* 0x00004490: */ 0x2C,0x41,0x00,0x00,0x9B,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000044A0: */ 0x14,0x04,0x00,0x00,0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x04,0x00,0x00, +/* 0x000044B0: */ 0x59,0x00,0x00,0x00,0xC0,0x44,0x00,0x00,0xD4,0x06,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000044C0: */ 0x0C,0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x1C,0x41,0x00,0x00,0x41,0x00,0x00,0x00, +/* 0x000044D0: */ 0x4C,0x41,0x00,0x00,0x1E,0x00,0x00,0x00,0x58,0x02,0x00,0x00,0x48,0x0F,0x00,0x00, +/* 0x000044E0: */ 0x20,0x3B,0x53,0x54,0x52,0x55,0x43,0x54,0x20,0x2D,0x20,0x4D,0x69,0x73,0x73,0x69, +/* 0x000044F0: */ 0x6E,0x67,0x20,0x3A,0x53,0x54,0x52,0x55,0x43,0x54,0x20,0x61,0x62,0x6F,0x76,0x65, +/* 0x00004500: */ 0x21,0x5A,0x5A,0x5A,0x48,0x1E,0x00,0x00,0xA4,0x08,0x00,0x00,0x1C,0x41,0x00,0x00, +/* 0x00004510: */ 0x9B,0x00,0x00,0x00,0x14,0x01,0x00,0x00,0x2C,0x41,0x00,0x00,0x41,0x00,0x00,0x00, +/* 0x00004520: */ 0xC8,0x04,0x00,0x00,0x08,0x21,0x00,0x00,0x75,0x00,0x00,0x00,0x2C,0x41,0x00,0x00, +/* 0x00004530: */ 0x41,0x00,0x00,0x00,0xAC,0x01,0x00,0x00,0x9B,0x00,0x00,0x00,0x2C,0x41,0x00,0x00, +/* 0x00004540: */ 0x41,0x00,0x00,0x00,0x35,0x00,0x00,0x00,0x41,0x00,0x00,0x00,0x70,0x03,0x00,0x00, +/* 0x00004550: */ 0x9C,0x00,0x00,0x00,0x9B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x43,0x00,0x00, +/* 0x00004560: */ 0x33,0x00,0x00,0x00,0xB2,0x00,0x00,0x00,0x41,0x00,0x00,0x00,0xBC,0x00,0x00,0x00, +/* 0x00004570: */ 0x28,0x00,0x00,0x00,0x81,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x14,0x00,0x00,0x00, +/* 0x00004580: */ 0x58,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x7D,0x00,0x00,0x00,0x00,0x05,0x00,0x00, +/* 0x00004590: */ 0x15,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x7D,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000045A0: */ 0x7D,0x00,0x00,0x00,0x2B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7D,0x00,0x00,0x00, +/* 0x000045B0: */ 0xBA,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7D,0x00,0x00,0x00,0x9B,0x00,0x00,0x00, +/* 0x000045C0: */ 0x00,0x00,0x00,0x00,0x7D,0x00,0x00,0x00,0xA2,0x00,0x00,0x00,0xD4,0x08,0x00,0x00, +/* 0x000045D0: */ 0x8E,0x00,0x00,0x00,0x9B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x9C,0x00,0x00,0x00, +/* 0x000045E0: */ 0x58,0x00,0x00,0x00,0xC2,0x00,0x00,0x00,0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00, +/* 0x000045F0: */ 0xBC,0x00,0x00,0x00,0x1C,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00004600: */ 0xB8,0x45,0x00,0x00,0x00,0x05,0x00,0x00,0x15,0x00,0x00,0x00,0x10,0x01,0x00,0x00, +/* 0x00004610: */ 0x59,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00, +/* 0x00004620: */ 0xBC,0x00,0x00,0x00,0x1C,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00004630: */ 0xAC,0x45,0x00,0x00,0x00,0x05,0x00,0x00,0x15,0x00,0x00,0x00,0xE0,0x00,0x00,0x00, +/* 0x00004640: */ 0x59,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00, +/* 0x00004650: */ 0xBC,0x00,0x00,0x00,0x1C,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00004660: */ 0xA0,0x45,0x00,0x00,0x00,0x05,0x00,0x00,0x15,0x00,0x00,0x00,0xB0,0x00,0x00,0x00, +/* 0x00004670: */ 0x59,0x00,0x00,0x00,0xFC,0xFF,0xFF,0xFF,0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00, +/* 0x00004680: */ 0xBC,0x00,0x00,0x00,0x1C,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00004690: */ 0xC4,0x45,0x00,0x00,0x00,0x05,0x00,0x00,0x15,0x00,0x00,0x00,0x80,0x00,0x00,0x00, +/* 0x000046A0: */ 0x90,0x07,0x00,0x00,0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00, +/* 0x000046B0: */ 0x1C,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0xAC,0x45,0x00,0x00, +/* 0x000046C0: */ 0x00,0x05,0x00,0x00,0x15,0x00,0x00,0x00,0x54,0x00,0x00,0x00,0x80,0x07,0x00,0x00, +/* 0x000046D0: */ 0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x1C,0x00,0x00,0x00, +/* 0x000046E0: */ 0x33,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0xA0,0x45,0x00,0x00,0x00,0x05,0x00,0x00, +/* 0x000046F0: */ 0x15,0x00,0x00,0x00,0x28,0x00,0x00,0x00,0xB4,0x08,0x00,0x00,0x48,0x0F,0x00,0x00, +/* 0x00004700: */ 0x12,0x73,0x21,0x20,0x2D,0x20,0x69,0x6C,0x6C,0x65,0x67,0x61,0x6C,0x20,0x73,0x69, +/* 0x00004710: */ 0x7A,0x65,0x21,0x5A,0x48,0x1E,0x00,0x00,0x33,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00004720: */ 0xC2,0x00,0x00,0x00,0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00, +/* 0x00004730: */ 0x14,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x9B,0x00,0x00,0x00,0x15,0x00,0x00,0x00, +/* 0x00004740: */ 0xB0,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0xFC,0xFF,0xFF,0xFF,0x7B,0x00,0x00,0x00, +/* 0x00004750: */ 0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x33,0x00,0x00,0x00, +/* 0x00004760: */ 0x9C,0x00,0x00,0x00,0xD4,0x08,0x00,0x00,0x9C,0x00,0x00,0x00,0x9B,0x00,0x00,0x00, +/* 0x00004770: */ 0x15,0x00,0x00,0x00,0x7C,0x00,0x00,0x00,0xD0,0x07,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00004780: */ 0x02,0x00,0x00,0x00,0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00, +/* 0x00004790: */ 0x14,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0xBA,0x00,0x00,0x00,0x15,0x00,0x00,0x00, +/* 0x000047A0: */ 0x50,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x7B,0x00,0x00,0x00, +/* 0x000047B0: */ 0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x33,0x00,0x00,0x00, +/* 0x000047C0: */ 0x2B,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0x28,0x00,0x00,0x00,0xB4,0x08,0x00,0x00, +/* 0x000047D0: */ 0x48,0x0F,0x00,0x00,0x12,0x73,0x21,0x20,0x2D,0x20,0x69,0x6C,0x6C,0x65,0x67,0x61, +/* 0x000047E0: */ 0x6C,0x20,0x73,0x69,0x7A,0x65,0x21,0x5A,0x48,0x1E,0x00,0x00,0x33,0x00,0x00,0x00, +/* 0x000047F0: */ 0x00,0x00,0x00,0x00,0xB2,0x00,0x00,0x00,0x41,0x00,0x00,0x00,0xBC,0x00,0x00,0x00, +/* 0x00004800: */ 0x10,0x00,0x00,0x00,0xDC,0x45,0x00,0x00,0x15,0x00,0x00,0x00,0x14,0x00,0x00,0x00, +/* 0x00004810: */ 0xA2,0x00,0x00,0x00,0x7D,0x00,0x00,0x00,0x8E,0x00,0x00,0x00,0x20,0x47,0x00,0x00, +/* 0x00004820: */ 0x00,0x00,0x00,0x00,0x20,0x43,0x00,0x00,0xF4,0x47,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00004830: */ 0xC2,0x00,0x00,0x00,0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00, +/* 0x00004840: */ 0x14,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x41,0x00,0x00,0x00,0x15,0x00,0x00,0x00, +/* 0x00004850: */ 0xF4,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x7B,0x00,0x00,0x00, +/* 0x00004860: */ 0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x33,0x00,0x00,0x00, +/* 0x00004870: */ 0xB9,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0xCC,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00004880: */ 0x01,0x00,0x00,0x00,0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00, +/* 0x00004890: */ 0x14,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x15,0x00,0x00,0x00, +/* 0x000048A0: */ 0xA4,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0xFC,0xFF,0xFF,0xFF,0x7B,0x00,0x00,0x00, +/* 0x000048B0: */ 0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x33,0x00,0x00,0x00, +/* 0x000048C0: */ 0x41,0x00,0x00,0x00,0xE8,0x08,0x00,0x00,0x15,0x00,0x00,0x00,0x78,0x00,0x00,0x00, +/* 0x000048D0: */ 0x90,0x07,0x00,0x00,0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00, +/* 0x000048E0: */ 0x18,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0xB9,0x00,0x00,0x00,0x50,0x3A,0x00,0x00, +/* 0x000048F0: */ 0x15,0x00,0x00,0x00,0x50,0x00,0x00,0x00,0x80,0x07,0x00,0x00,0x7B,0x00,0x00,0x00, +/* 0x00004900: */ 0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x33,0x00,0x00,0x00, +/* 0x00004910: */ 0x18,0x00,0x00,0x00,0x14,0x3A,0x00,0x00,0x15,0x00,0x00,0x00,0x28,0x00,0x00,0x00, +/* 0x00004920: */ 0xB4,0x08,0x00,0x00,0x48,0x0F,0x00,0x00,0x12,0x73,0x40,0x20,0x2D,0x20,0x69,0x6C, +/* 0x00004930: */ 0x6C,0x65,0x67,0x61,0x6C,0x20,0x73,0x69,0x7A,0x65,0x21,0x5A,0x48,0x1E,0x00,0x00, +/* 0x00004940: */ 0x33,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7D,0x00,0x00,0x00,0x18,0x00,0x00,0x00, +/* 0x00004950: */ 0x00,0x00,0x00,0x00,0x7D,0x00,0x00,0x00,0xB9,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00004960: */ 0x7D,0x00,0x00,0x00,0x41,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7D,0x00,0x00,0x00, +/* 0x00004970: */ 0x41,0x00,0x00,0x00,0xE8,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x7D,0x00,0x00,0x00, +/* 0x00004980: */ 0x18,0x00,0x00,0x00,0x14,0x3A,0x00,0x00,0x00,0x00,0x00,0x00,0x7D,0x00,0x00,0x00, +/* 0x00004990: */ 0xB9,0x00,0x00,0x00,0x50,0x3A,0x00,0x00,0x00,0x00,0x00,0x00,0x9C,0x00,0x00,0x00, +/* 0x000049A0: */ 0x58,0x00,0x00,0x00,0xC2,0x00,0x00,0x00,0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00, +/* 0x000049B0: */ 0xBC,0x00,0x00,0x00,0x1C,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x000049C0: */ 0x60,0x49,0x00,0x00,0x00,0x05,0x00,0x00,0x15,0x00,0x00,0x00,0x10,0x01,0x00,0x00, +/* 0x000049D0: */ 0x59,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00, +/* 0x000049E0: */ 0xBC,0x00,0x00,0x00,0x1C,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x000049F0: */ 0x54,0x49,0x00,0x00,0x00,0x05,0x00,0x00,0x15,0x00,0x00,0x00,0xE0,0x00,0x00,0x00, +/* 0x00004A00: */ 0x59,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00, +/* 0x00004A10: */ 0xBC,0x00,0x00,0x00,0x1C,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00004A20: */ 0x48,0x49,0x00,0x00,0x00,0x05,0x00,0x00,0x15,0x00,0x00,0x00,0xB0,0x00,0x00,0x00, +/* 0x00004A30: */ 0x59,0x00,0x00,0x00,0xFC,0xFF,0xFF,0xFF,0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00, +/* 0x00004A40: */ 0xBC,0x00,0x00,0x00,0x1C,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00004A50: */ 0x6C,0x49,0x00,0x00,0x00,0x05,0x00,0x00,0x15,0x00,0x00,0x00,0x80,0x00,0x00,0x00, +/* 0x00004A60: */ 0x90,0x07,0x00,0x00,0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00, +/* 0x00004A70: */ 0x1C,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x8C,0x49,0x00,0x00, +/* 0x00004A80: */ 0x00,0x05,0x00,0x00,0x15,0x00,0x00,0x00,0x54,0x00,0x00,0x00,0x80,0x07,0x00,0x00, +/* 0x00004A90: */ 0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x1C,0x00,0x00,0x00, +/* 0x00004AA0: */ 0x33,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x7C,0x49,0x00,0x00,0x00,0x05,0x00,0x00, +/* 0x00004AB0: */ 0x15,0x00,0x00,0x00,0x28,0x00,0x00,0x00,0xB4,0x08,0x00,0x00,0x48,0x0F,0x00,0x00, +/* 0x00004AC0: */ 0x12,0x73,0x40,0x20,0x2D,0x20,0x69,0x6C,0x6C,0x65,0x67,0x61,0x6C,0x20,0x73,0x69, +/* 0x00004AD0: */ 0x7A,0x65,0x21,0x5A,0x48,0x1E,0x00,0x00,0x33,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00004AE0: */ 0xB2,0x00,0x00,0x00,0x41,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x10,0x00,0x00,0x00, +/* 0x00004AF0: */ 0x9C,0x49,0x00,0x00,0x15,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0xA2,0x00,0x00,0x00, +/* 0x00004B00: */ 0x7D,0x00,0x00,0x00,0x8E,0x00,0x00,0x00,0x30,0x48,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00004B10: */ 0x20,0x43,0x00,0x00,0xE0,0x4A,0x00,0x00,0x00,0x00,0x00,0x00,0x2A,0x00,0x00,0x00, +/* 0x00004B20: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x2A,0x00,0x00,0x00, +/* 0x00004B30: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x2A,0x00,0x00,0x00, +/* 0x00004B40: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x57,0x00,0x00,0x00,0xB2,0x00,0x00,0x00, +/* 0x00004B50: */ 0x41,0x00,0x00,0x00,0x24,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x28,0x00,0x00,0x00, +/* 0x00004B60: */ 0x34,0x05,0x00,0x00,0x2C,0x4B,0x00,0x00,0x9B,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00004B70: */ 0x01,0x00,0x00,0x00,0x3C,0x4B,0x00,0x00,0x9B,0x00,0x00,0x00,0x15,0x00,0x00,0x00, +/* 0x00004B80: */ 0x14,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x3C,0x4B,0x00,0x00, +/* 0x00004B90: */ 0x7F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x2C,0x4B,0x00,0x00,0x41,0x00,0x00,0x00, +/* 0x00004BA0: */ 0xBC,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x80,0x07,0x00,0x00,0x3C,0x4B,0x00,0x00, +/* 0x00004BB0: */ 0x7F,0x00,0x00,0x00,0x3C,0x4B,0x00,0x00,0x41,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00004BC0: */ 0x00,0x00,0x00,0x00,0x30,0x02,0x00,0x00,0xBC,0x00,0x00,0x00,0x38,0x00,0x00,0x00, +/* 0x00004BD0: */ 0x5C,0x32,0x00,0x00,0x2C,0x4B,0x00,0x00,0x41,0x00,0x00,0x00,0x40,0x00,0x00,0x00, +/* 0x00004BE0: */ 0x2C,0x4B,0x00,0x00,0x41,0x00,0x00,0x00,0x8C,0x04,0x00,0x00,0xA9,0x00,0x00,0x00, +/* 0x00004BF0: */ 0x9B,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x2C,0x4B,0x00,0x00, +/* 0x00004C00: */ 0x9B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x4C,0x4B,0x00,0x00,0x10,0x06,0x00,0x00, +/* 0x00004C10: */ 0x00,0x00,0x00,0x00,0x4C,0x4B,0x00,0x00,0xF4,0x0A,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00004C20: */ 0x4C,0x4B,0x00,0x00,0x18,0x0B,0x00,0x00,0x00,0x00,0x00,0x00,0x4C,0x4B,0x00,0x00, +/* 0x00004C30: */ 0x3C,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x2C,0x06,0x00,0x00,0x98,0x4B,0x00,0x00, +/* 0x00004C40: */ 0x00,0x00,0x00,0x00,0xB8,0x06,0x00,0x00,0x98,0x4B,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00004C50: */ 0x68,0x06,0x00,0x00,0x98,0x4B,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x0C,0x00,0x00, +/* 0x00004C60: */ 0x98,0x4B,0x00,0x00,0x00,0x00,0x00,0x00,0x50,0x0C,0x00,0x00,0x98,0x4B,0x00,0x00, +/* 0x00004C70: */ 0x00,0x00,0x00,0x00,0x2A,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00004C80: */ 0x00,0x00,0x00,0x00,0xA4,0x08,0x00,0x00,0x59,0x00,0x00,0x00,0x02,0x00,0x00,0x00, +/* 0x00004C90: */ 0x5C,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00004CA0: */ 0x00,0x00,0x00,0x00,0x32,0x00,0x00,0x00,0x5F,0x00,0x00,0x00,0x53,0x00,0x00,0x00, +/* 0x00004CB0: */ 0x7D,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00004CC0: */ 0x08,0x00,0x00,0x00,0x72,0x00,0x00,0x00,0x7A,0x00,0x00,0x00,0x6A,0x00,0x00,0x00, +/* 0x00004CD0: */ 0x71,0x00,0x00,0x00,0xD4,0xFF,0xFF,0xFF,0x60,0x00,0x00,0x00,0x5D,0x00,0x00,0x00, +/* 0x00004CE0: */ 0x00,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x5C,0x00,0x00,0x00, +/* 0x00004CF0: */ 0x59,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00004D00: */ 0x32,0x00,0x00,0x00,0x5F,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x03,0x00,0x00,0x00, +/* 0x00004D10: */ 0x53,0x00,0x00,0x00,0x75,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x08,0x00,0x00,0x00, +/* 0x00004D20: */ 0xA1,0x00,0x00,0x00,0x8B,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x53,0x00,0x00,0x00, +/* 0x00004D30: */ 0x7D,0x00,0x00,0x00,0x2B,0x00,0x00,0x00,0x71,0x00,0x00,0x00,0xC8,0xFF,0xFF,0xFF, +/* 0x00004D40: */ 0x5D,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x01,0x00,0x00,0x00, +/* 0x00004D50: */ 0x5C,0x00,0x00,0x00,0x5F,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00004D60: */ 0x08,0x00,0x00,0x00,0x72,0x00,0x00,0x00,0x5F,0x00,0x00,0x00,0x02,0x00,0x00,0x00, +/* 0x00004D70: */ 0x18,0x00,0x00,0x00,0x7A,0x00,0x00,0x00,0x5D,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00004D80: */ 0x59,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x5C,0x00,0x00,0x00,0x5F,0x00,0x00,0x00, +/* 0x00004D90: */ 0x59,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x8B,0x00,0x00,0x00,0x60,0x00,0x00,0x00, +/* 0x00004DA0: */ 0x2B,0x00,0x00,0x00,0x5F,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x02,0x00,0x00,0x00, +/* 0x00004DB0: */ 0x2B,0x00,0x00,0x00,0x5D,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xA4,0x08,0x00,0x00, +/* 0x00004DC0: */ 0xA4,0x08,0x00,0x00,0xA4,0x08,0x00,0x00,0xA4,0x08,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00004DD0: */ 0x05,0x00,0x00,0x00,0x5C,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00004DE0: */ 0x6A,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x6B,0x00,0x00,0x00, +/* 0x00004DF0: */ 0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x6C,0x00,0x00,0x00,0x5F,0x00,0x00,0x00, +/* 0x00004E00: */ 0x6D,0x00,0x00,0x00,0x5F,0x00,0x00,0x00,0x76,0x00,0x00,0x00,0x69,0x00,0x00,0x00, +/* 0x00004E10: */ 0x5F,0x00,0x00,0x00,0x25,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0xE4,0x00,0x00,0x00, +/* 0x00004E20: */ 0x5F,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x84,0x4C,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00004E30: */ 0x3A,0x3A,0x3A,0x3A,0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00, +/* 0x00004E40: */ 0x74,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x24,0x00,0x00,0x00, +/* 0x00004E50: */ 0xBC,0x00,0x00,0x00,0x48,0x00,0x00,0x00,0x5F,0x00,0x00,0x00,0x70,0x01,0x00,0x00, +/* 0x00004E60: */ 0x59,0x00,0x00,0x00,0x1F,0x00,0x00,0x00,0x11,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00004E70: */ 0x04,0x00,0x00,0x00,0x75,0x00,0x00,0x00,0x9C,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00004E80: */ 0x04,0x00,0x00,0x00,0x7D,0x00,0x00,0x00,0x9C,0x00,0x00,0x00,0xB4,0x08,0x00,0x00, +/* 0x00004E90: */ 0x6B,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x80,0x07,0x00,0x00, +/* 0x00004EA0: */ 0x60,0x00,0x00,0x00,0x7D,0x00,0x00,0x00,0x6A,0x00,0x00,0x00,0x15,0x00,0x00,0x00, +/* 0x00004EB0: */ 0x48,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x3B,0x3B,0x3B,0x3B,0x7B,0x00,0x00,0x00, +/* 0x00004EC0: */ 0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x2C,0x00,0x00,0x00,0x33,0x00,0x00,0x00, +/* 0x00004ED0: */ 0x59,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x7D,0x00,0x00,0x00, +/* 0x00004EE0: */ 0x6A,0x00,0x00,0x00,0xB4,0x08,0x00,0x00,0x6C,0x00,0x00,0x00,0x15,0x00,0x00,0x00, +/* 0x00004EF0: */ 0x08,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0x44,0x00,0x00,0x00, +/* 0x00004F00: */ 0xB4,0x08,0x00,0x00,0x6B,0x00,0x00,0x00,0x62,0x00,0x00,0x00,0xBC,0x00,0x00,0x00, +/* 0x00004F10: */ 0x1C,0x00,0x00,0x00,0x48,0x0F,0x00,0x00,0x08,0x6B,0x65,0x79,0x62,0x6F,0x61,0x72, +/* 0x00004F20: */ 0x64,0x5A,0x5A,0x5A,0x15,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x48,0x0F,0x00,0x00, +/* 0x00004F30: */ 0x0A,0x27,0x43,0x27,0x20,0x6B,0x65,0x72,0x6E,0x65,0x6C,0x5A,0x70,0x01,0x00,0x00, +/* 0x00004F40: */ 0x61,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0xBC,0xFE,0xFF,0xFF,0x5D,0x00,0x00,0x00, +/* 0x00004F50: */ 0x00,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x5C,0x00,0x00,0x00, +/* 0x00004F60: */ 0xA8,0x00,0x00,0x00,0x41,0x00,0x00,0x00,0xA2,0x00,0x00,0x00,0x60,0x00,0x00,0x00, +/* 0x00004F70: */ 0xA8,0x00,0x00,0x00,0x9B,0x00,0x00,0x00,0x5F,0x00,0x00,0x00,0x4E,0x00,0x00,0x00, +/* 0x00004F80: */ 0x8E,0x00,0x00,0x00,0xA8,0x00,0x00,0x00,0x9B,0x00,0x00,0x00,0x5D,0x00,0x00,0x00, +/* 0x00004F90: */ 0x00,0x00,0x00,0x00,0xA4,0x08,0x00,0x00,0xA4,0x08,0x00,0x00,0xA4,0x08,0x00,0x00, +/* 0x00004FA0: */ 0x59,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x5C,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00004FB0: */ 0x00,0x00,0x00,0x00,0x6B,0x00,0x00,0x00,0xC4,0x08,0x00,0x00,0xB8,0x00,0x00,0x00, +/* 0x00004FC0: */ 0x69,0x00,0x00,0x00,0x5F,0x00,0x00,0x00,0x4E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00, +/* 0x00004FD0: */ 0xA4,0x00,0x00,0x00,0x5F,0x00,0x00,0x00,0x70,0x01,0x00,0x00,0xA3,0x00,0x00,0x00, +/* 0x00004FE0: */ 0x80,0x0F,0x00,0x00,0x06,0x20,0x66,0x72,0x6F,0x6D,0x3A,0x5A,0x28,0x00,0x00,0x00, +/* 0x00004FF0: */ 0x6A,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0xBC,0x4D,0x00,0x00,0x60,0x00,0x00,0x00, +/* 0x00005000: */ 0x77,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x0C,0x00,0x00,0x00,0xB4,0x1D,0x00,0x00, +/* 0x00005010: */ 0x59,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x98,0x0C,0x00,0x00,0xA3,0x00,0x00,0x00, +/* 0x00005020: */ 0x28,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x76,0x00,0x00,0x00,0x35,0x00,0x00,0x00, +/* 0x00005030: */ 0x6A,0x00,0x00,0x00,0x25,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x24,0x00,0x00,0x00, +/* 0x00005040: */ 0x5F,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x54,0x4F,0x00,0x00,0x9C,0x00,0x00,0x00, +/* 0x00005050: */ 0x6A,0x00,0x00,0x00,0x58,0x02,0x00,0x00,0x15,0x00,0x00,0x00,0x08,0x00,0x00,0x00, +/* 0x00005060: */ 0xB4,0x08,0x00,0x00,0xBC,0x00,0x00,0x00,0x8C,0xFF,0xFF,0xFF,0x15,0x00,0x00,0x00, +/* 0x00005070: */ 0x20,0x00,0x00,0x00,0x70,0x01,0x00,0x00,0xA3,0x00,0x00,0x00,0x80,0x0F,0x00,0x00, +/* 0x00005080: */ 0x0B,0x20,0x6E,0x6F,0x74,0x20,0x66,0x6F,0x75,0x6E,0x64,0x21,0x28,0x00,0x00,0x00, +/* 0x00005090: */ 0x5D,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x2A,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000050A0: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x21,0x00,0x00,0x35,0x00,0x00,0x00, +/* 0x000050B0: */ 0x18,0x00,0x00,0x00,0x20,0x01,0x00,0x00,0x11,0x00,0x00,0x00,0xBC,0x00,0x00,0x00, +/* 0x000050C0: */ 0x14,0x00,0x00,0x00,0x80,0x0F,0x00,0x00,0x09,0x50,0x4F,0x53,0x54,0x50,0x4F,0x4E, +/* 0x000050D0: */ 0x45,0x20,0x5A,0x5A,0x90,0x02,0x00,0x00,0x8C,0x0C,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000050E0: */ 0x2A,0x00,0x00,0x00,0x78,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000050F0: */ 0x41,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x2A,0x00,0x00,0x00,0x78,0x07,0x00,0x00, +/* 0x00005100: */ 0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x2A,0x00,0x00,0x00,0xDC,0x30,0x00,0x00, +/* 0x00005110: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x2A,0x00,0x00,0x00,0xDC,0x30,0x00,0x00, +/* 0x00005120: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x2A,0x00,0x00,0x00,0xDC,0x30,0x00,0x00, +/* 0x00005130: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x14,0x51,0x00,0x00, +/* 0x00005140: */ 0x41,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x01,0x00,0x00,0x00, +/* 0x00005150: */ 0x73,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0xA1,0x00,0x00,0x00, +/* 0x00005160: */ 0x00,0x00,0x00,0x00,0xF4,0x0C,0x00,0x00,0x0F,0x00,0x00,0x00,0x24,0x51,0x00,0x00, +/* 0x00005170: */ 0x41,0x00,0x00,0x00,0x80,0x0F,0x00,0x00,0x02,0x28,0x20,0x5A,0xF4,0x39,0x00,0x00, +/* 0x00005180: */ 0x80,0x0F,0x00,0x00,0x01,0x29,0x5A,0x5A,0x38,0x51,0x00,0x00,0x98,0x0C,0x00,0x00, +/* 0x00005190: */ 0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x34,0x51,0x00,0x00, +/* 0x000051A0: */ 0x9B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x34,0x51,0x00,0x00, +/* 0x000051B0: */ 0x41,0x00,0x00,0x00,0x25,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x08,0x00,0x00,0x00, +/* 0x000051C0: */ 0x64,0x51,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x34,0x51,0x00,0x00, +/* 0x000051D0: */ 0x41,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x1F,0x00,0x00,0x00, +/* 0x000051E0: */ 0xBC,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0xA8,0x51,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000051F0: */ 0x59,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x34,0x51,0x00,0x00, +/* 0x00005200: */ 0x7F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF8,0x50,0x00,0x00,0x0F,0x00,0x00,0x00, +/* 0x00005210: */ 0x24,0x51,0x00,0x00,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x00,0x00, +/* 0x00005220: */ 0x24,0x51,0x00,0x00,0x41,0x00,0x00,0x00,0x41,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00005230: */ 0x0F,0x00,0x00,0x00,0x24,0x51,0x00,0x00,0x41,0x00,0x00,0x00,0x41,0x00,0x00,0x00, +/* 0x00005240: */ 0x0F,0x00,0x00,0x00,0x24,0x51,0x00,0x00,0x41,0x00,0x00,0x00,0x7D,0x00,0x00,0x00, +/* 0x00005250: */ 0x00,0x00,0x00,0x00,0x1C,0x52,0x00,0x00,0xA4,0x1D,0x00,0x00,0x08,0x52,0x00,0x00, +/* 0x00005260: */ 0xF0,0x51,0x00,0x00,0x00,0x00,0x00,0x00,0x1C,0x52,0x00,0x00,0x08,0x21,0x00,0x00, +/* 0x00005270: */ 0x90,0x02,0x00,0x00,0x8C,0x0C,0x00,0x00,0x08,0x52,0x00,0x00,0xF0,0x51,0x00,0x00, +/* 0x00005280: */ 0x00,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x24,0x51,0x00,0x00,0x41,0x00,0x00,0x00, +/* 0x00005290: */ 0x70,0x01,0x00,0x00,0x03,0x00,0x00,0x00,0x7D,0x00,0x00,0x00,0x88,0x03,0x00,0x00, +/* 0x000052A0: */ 0x0F,0x00,0x00,0x00,0x24,0x51,0x00,0x00,0x9B,0x00,0x00,0x00,0xA3,0x00,0x00,0x00, +/* 0x000052B0: */ 0xF0,0x51,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x52,0x00,0x00,0xF4,0x39,0x00,0x00, +/* 0x000052C0: */ 0x08,0x52,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x07,0x00,0x00,0x0F,0x00,0x00,0x00, +/* 0x000052D0: */ 0x14,0x51,0x00,0x00,0x7F,0x00,0x00,0x00,0xA8,0x51,0x00,0x00,0x1C,0x52,0x00,0x00, +/* 0x000052E0: */ 0x25,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x34,0x00,0x00,0x00,0x80,0x0F,0x00,0x00, +/* 0x000052F0: */ 0x05,0x45,0x4C,0x53,0x45,0x20,0x5A,0x5A,0x30,0x52,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00005300: */ 0x01,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x14,0x51,0x00,0x00,0x7F,0x00,0x00,0x00, +/* 0x00005310: */ 0x18,0x02,0x00,0x00,0x15,0x00,0x00,0x00,0x1C,0x00,0x00,0x00,0x80,0x0F,0x00,0x00, +/* 0x00005320: */ 0x07,0x52,0x45,0x50,0x45,0x41,0x54,0x20,0x30,0x52,0x00,0x00,0xF4,0x39,0x00,0x00, +/* 0x00005330: */ 0x33,0x00,0x00,0x00,0x08,0x52,0x00,0x00,0x64,0x51,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00005340: */ 0xA8,0x51,0x00,0x00,0x1C,0x52,0x00,0x00,0x25,0x00,0x00,0x00,0xBC,0x00,0x00,0x00, +/* 0x00005350: */ 0x38,0x00,0x00,0x00,0x80,0x0F,0x00,0x00,0x0C,0x49,0x46,0x20,0x6F,0x72,0x20,0x57, +/* 0x00005360: */ 0x48,0x49,0x4C,0x45,0x20,0x5A,0x5A,0x5A,0x30,0x52,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00005370: */ 0x01,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x14,0x51,0x00,0x00,0x7F,0x00,0x00,0x00, +/* 0x00005380: */ 0x15,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x80,0x0F,0x00,0x00,0x07,0x55,0x4E,0x54, +/* 0x00005390: */ 0x49,0x4C,0x3D,0x3E,0x30,0x52,0x00,0x00,0xF4,0x39,0x00,0x00,0x08,0x52,0x00,0x00, +/* 0x000053A0: */ 0x64,0x51,0x00,0x00,0x00,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x01,0x00,0x00,0x00, +/* 0x000053B0: */ 0x5C,0x00,0x00,0x00,0x5F,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000053C0: */ 0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x5C,0x00,0x00,0x00, +/* 0x000053D0: */ 0x33,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x14,0x51,0x00,0x00,0x41,0x00,0x00,0x00, +/* 0x000053E0: */ 0x25,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x1C,0x00,0x00,0x00,0x80,0x0F,0x00,0x00, +/* 0x000053F0: */ 0x05,0x45,0x58,0x49,0x54,0x20,0x5A,0x5A,0xF0,0x51,0x00,0x00,0x15,0x00,0x00,0x00, +/* 0x00005400: */ 0x20,0x00,0x00,0x00,0x80,0x0F,0x00,0x00,0x01,0x3B,0x5A,0x5A,0x59,0x00,0x00,0x00, +/* 0x00005410: */ 0x00,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x24,0x51,0x00,0x00,0x9B,0x00,0x00,0x00, +/* 0x00005420: */ 0x15,0x00,0x00,0x00,0x90,0x02,0x00,0x00,0x59,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00005430: */ 0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x14,0x00,0x00,0x00, +/* 0x00005440: */ 0x33,0x00,0x00,0x00,0x54,0x52,0x00,0x00,0x15,0x00,0x00,0x00,0x68,0x02,0x00,0x00, +/* 0x00005450: */ 0x59,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00, +/* 0x00005460: */ 0xBC,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x68,0x52,0x00,0x00, +/* 0x00005470: */ 0x15,0x00,0x00,0x00,0x40,0x02,0x00,0x00,0x59,0x00,0x00,0x00,0x15,0x00,0x00,0x00, +/* 0x00005480: */ 0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x14,0x00,0x00,0x00, +/* 0x00005490: */ 0x33,0x00,0x00,0x00,0xC8,0x52,0x00,0x00,0x15,0x00,0x00,0x00,0x18,0x02,0x00,0x00, +/* 0x000054A0: */ 0x59,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00, +/* 0x000054B0: */ 0xBC,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x40,0x53,0x00,0x00, +/* 0x000054C0: */ 0x15,0x00,0x00,0x00,0xF0,0x01,0x00,0x00,0x59,0x00,0x00,0x00,0x71,0x00,0x00,0x00, +/* 0x000054D0: */ 0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x38,0x00,0x00,0x00, +/* 0x000054E0: */ 0x33,0x00,0x00,0x00,0x80,0x07,0x00,0x00,0x0F,0x00,0x00,0x00,0x14,0x51,0x00,0x00, +/* 0x000054F0: */ 0x7F,0x00,0x00,0x00,0xA8,0x51,0x00,0x00,0x80,0x0F,0x00,0x00,0x05,0x4C,0x4F,0x4F, +/* 0x00005500: */ 0x50,0x20,0x5A,0x5A,0x08,0x52,0x00,0x00,0x64,0x51,0x00,0x00,0x15,0x00,0x00,0x00, +/* 0x00005510: */ 0xA4,0x01,0x00,0x00,0x59,0x00,0x00,0x00,0x7E,0x00,0x00,0x00,0x7B,0x00,0x00,0x00, +/* 0x00005520: */ 0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x38,0x00,0x00,0x00,0x33,0x00,0x00,0x00, +/* 0x00005530: */ 0x80,0x07,0x00,0x00,0x0F,0x00,0x00,0x00,0x14,0x51,0x00,0x00,0x7F,0x00,0x00,0x00, +/* 0x00005540: */ 0xA8,0x51,0x00,0x00,0x80,0x0F,0x00,0x00,0x05,0x2B,0x4C,0x4F,0x4F,0x50,0x5A,0x5A, +/* 0x00005550: */ 0x08,0x52,0x00,0x00,0x64,0x51,0x00,0x00,0x15,0x00,0x00,0x00,0x58,0x01,0x00,0x00, +/* 0x00005560: */ 0x59,0x00,0x00,0x00,0x32,0x00,0x00,0x00,0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00, +/* 0x00005570: */ 0xBC,0x00,0x00,0x00,0x34,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0xA8,0x51,0x00,0x00, +/* 0x00005580: */ 0x80,0x0F,0x00,0x00,0x02,0x44,0x4F,0x5A,0x59,0x00,0x00,0x00,0x01,0x00,0x00,0x00, +/* 0x00005590: */ 0x0F,0x00,0x00,0x00,0x14,0x51,0x00,0x00,0x7F,0x00,0x00,0x00,0x64,0x51,0x00,0x00, +/* 0x000055A0: */ 0x15,0x00,0x00,0x00,0x10,0x01,0x00,0x00,0x59,0x00,0x00,0x00,0x80,0x00,0x00,0x00, +/* 0x000055B0: */ 0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x3C,0x00,0x00,0x00, +/* 0x000055C0: */ 0x33,0x00,0x00,0x00,0xA8,0x51,0x00,0x00,0x80,0x0F,0x00,0x00,0x04,0x3F,0x44,0x4F, +/* 0x000055D0: */ 0x20,0x5A,0x5A,0x5A,0x08,0x52,0x00,0x00,0x59,0x00,0x00,0x00,0x01,0x00,0x00,0x00, +/* 0x000055E0: */ 0x0F,0x00,0x00,0x00,0x14,0x51,0x00,0x00,0x7F,0x00,0x00,0x00,0x64,0x51,0x00,0x00, +/* 0x000055F0: */ 0x15,0x00,0x00,0x00,0xC0,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x80,0x0F,0x00,0x00, +/* 0x00005600: */ 0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x24,0x00,0x00,0x00, +/* 0x00005610: */ 0x33,0x00,0x00,0x00,0x80,0x0F,0x00,0x00,0x03,0x2E,0x22,0x20,0x84,0x52,0x00,0x00, +/* 0x00005620: */ 0x80,0x0F,0x00,0x00,0x02,0x22,0x20,0x5A,0x15,0x00,0x00,0x00,0x88,0x00,0x00,0x00, +/* 0x00005630: */ 0x59,0x00,0x00,0x00,0x48,0x0F,0x00,0x00,0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00, +/* 0x00005640: */ 0xBC,0x00,0x00,0x00,0x24,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x80,0x0F,0x00,0x00, +/* 0x00005650: */ 0x03,0x43,0x22,0x20,0x84,0x52,0x00,0x00,0x80,0x0F,0x00,0x00,0x02,0x22,0x20,0x5A, +/* 0x00005660: */ 0x15,0x00,0x00,0x00,0x50,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x64,0x0F,0x00,0x00, +/* 0x00005670: */ 0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x24,0x00,0x00,0x00, +/* 0x00005680: */ 0x33,0x00,0x00,0x00,0x80,0x0F,0x00,0x00,0x03,0x53,0x22,0x20,0x84,0x52,0x00,0x00, +/* 0x00005690: */ 0x80,0x0F,0x00,0x00,0x02,0x22,0x20,0x5A,0x15,0x00,0x00,0x00,0x18,0x00,0x00,0x00, +/* 0x000056A0: */ 0xC8,0x51,0x00,0x00,0x5F,0x00,0x00,0x00,0xA8,0x50,0x00,0x00,0xF0,0x51,0x00,0x00, +/* 0x000056B0: */ 0x33,0x00,0x00,0x00,0x5D,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xA4,0x08,0x00,0x00, +/* 0x000056C0: */ 0x59,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x5C,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x000056D0: */ 0x00,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x14,0x51,0x00,0x00,0x9B,0x00,0x00,0x00, +/* 0x000056E0: */ 0x5F,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x24,0x51,0x00,0x00,0x9B,0x00,0x00,0x00, +/* 0x000056F0: */ 0x64,0x51,0x00,0x00,0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x00,0x00, +/* 0x00005700: */ 0x24,0x51,0x00,0x00,0x41,0x00,0x00,0x00,0xF0,0x50,0x00,0x00,0x6A,0x00,0x00,0x00, +/* 0x00005710: */ 0x35,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x24,0x51,0x00,0x00,0x41,0x00,0x00,0x00, +/* 0x00005720: */ 0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x34,0x00,0x00,0x00,0x80,0x07,0x00,0x00, +/* 0x00005730: */ 0x0F,0x00,0x00,0x00,0x14,0x51,0x00,0x00,0x7F,0x00,0x00,0x00,0xA8,0x51,0x00,0x00, +/* 0x00005740: */ 0x80,0x0F,0x00,0x00,0x05,0x54,0x48,0x45,0x4E,0x20,0x5A,0x5A,0x64,0x51,0x00,0x00, +/* 0x00005750: */ 0x33,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0xB8,0xFF,0xFF,0xFF,0xF8,0x50,0x00,0x00, +/* 0x00005760: */ 0x0F,0x00,0x00,0x00,0x24,0x51,0x00,0x00,0x7F,0x00,0x00,0x00,0x60,0x00,0x00,0x00, +/* 0x00005770: */ 0xA8,0x53,0x00,0x00,0x0F,0x00,0x00,0x00,0x24,0x51,0x00,0x00,0x41,0x00,0x00,0x00, +/* 0x00005780: */ 0x24,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x74,0xFF,0xFF,0xFF,0x28,0x00,0x00,0x00, +/* 0x00005790: */ 0x24,0x00,0x00,0x00,0x58,0x02,0x00,0x00,0x48,0x0F,0x00,0x00,0x28,0x53,0x45,0x45, +/* 0x000057A0: */ 0x20,0x63,0x6F,0x6E,0x64,0x69,0x74,0x69,0x6F,0x6E,0x61,0x6C,0x20,0x61,0x6E,0x61, +/* 0x000057B0: */ 0x6C,0x79,0x73,0x65,0x72,0x20,0x6E,0x65,0x73,0x74,0x69,0x6E,0x67,0x20,0x66,0x61, +/* 0x000057C0: */ 0x69,0x6C,0x65,0x64,0x21,0x5A,0x5A,0x5A,0x48,0x1E,0x00,0x00,0x5D,0x00,0x00,0x00, +/* 0x000057D0: */ 0x00,0x00,0x00,0x00,0xA0,0x00,0x00,0x00,0x35,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x000057E0: */ 0x10,0x01,0x00,0x00,0x1F,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x14,0x00,0x00,0x00, +/* 0x000057F0: */ 0x8C,0x04,0x00,0x00,0xBC,0x56,0x00,0x00,0x15,0x00,0x00,0x00,0x3C,0x00,0x00,0x00, +/* 0x00005800: */ 0x08,0x21,0x00,0x00,0x90,0x02,0x00,0x00,0x80,0x0F,0x00,0x00,0x24,0x20,0x69,0x73, +/* 0x00005810: */ 0x20,0x70,0x72,0x69,0x6D,0x69,0x74,0x69,0x76,0x65,0x20,0x64,0x65,0x66,0x69,0x6E, +/* 0x00005820: */ 0x65,0x64,0x20,0x69,0x6E,0x20,0x27,0x43,0x27,0x20,0x6B,0x65,0x72,0x6E,0x65,0x6C, +/* 0x00005830: */ 0x2E,0x5A,0x5A,0x5A,0x28,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x2A,0x00,0x00,0x00, +/* 0x00005840: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x70,0x01,0x00,0x00, +/* 0x00005850: */ 0x59,0x00,0x00,0x00,0x1F,0x00,0x00,0x00,0x11,0x00,0x00,0x00,0x88,0x00,0x00,0x00, +/* 0x00005860: */ 0x70,0x01,0x00,0x00,0xA0,0x3E,0x00,0x00,0xA2,0x00,0x00,0x00,0x0C,0x02,0x00,0x00, +/* 0x00005870: */ 0x8E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC4,0x08,0x00,0x00,0xB8,0x00,0x00,0x00, +/* 0x00005880: */ 0x14,0x01,0x00,0x00,0xF4,0x0C,0x00,0x00,0x76,0x00,0x00,0x00,0x35,0x00,0x00,0x00, +/* 0x00005890: */ 0x27,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x2C,0x00,0x00,0x00,0x03,0x00,0x00,0x00, +/* 0x000058A0: */ 0x4C,0x58,0x00,0x00,0xBC,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x35,0x00,0x00,0x00, +/* 0x000058B0: */ 0x90,0x02,0x00,0x00,0x4C,0x20,0x00,0x00,0x30,0x1F,0x00,0x00,0x15,0x00,0x00,0x00, +/* 0x000058C0: */ 0xC8,0xFF,0xFF,0xFF,0x0C,0x02,0x00,0x00,0xF4,0x0C,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000058D0: */ 0x2A,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000058E0: */ 0xAF,0x00,0x00,0x00,0x41,0x00,0x00,0x00,0x75,0x00,0x00,0x00,0x98,0x0C,0x00,0x00, +/* 0x000058F0: */ 0x00,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x10,0x01,0x00,0x00,0x20,0x00,0x00,0x00, +/* 0x00005900: */ 0x00,0x00,0x00,0x00,0x2A,0x00,0x00,0x00,0xDC,0x30,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00005910: */ 0x00,0x00,0x00,0x00,0x2A,0x00,0x00,0x00,0xDC,0x30,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00005920: */ 0x00,0x00,0x00,0x00,0x2A,0x00,0x00,0x00,0xDC,0x30,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00005930: */ 0x00,0x00,0x00,0x00,0x2A,0x00,0x00,0x00,0x78,0x07,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00005940: */ 0x00,0x02,0x00,0x00,0x2A,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00005950: */ 0x0D,0x3A,0x3A,0x3A,0x3A,0x74,0x72,0x61,0x63,0x65,0x2E,0x66,0x74,0x68,0x5A,0x5A, +/* 0x00005960: */ 0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x00005970: */ 0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x00005980: */ 0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x00005990: */ 0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x000059A0: */ 0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x000059B0: */ 0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x000059C0: */ 0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x000059D0: */ 0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x000059E0: */ 0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x000059F0: */ 0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x00005A00: */ 0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x00005A10: */ 0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x00005A20: */ 0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x00005A30: */ 0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x00005A40: */ 0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x00005A50: */ 0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x00005A60: */ 0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x00005A70: */ 0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x00005A80: */ 0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x00005A90: */ 0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x00005AA0: */ 0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x00005AB0: */ 0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x00005AC0: */ 0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x00005AD0: */ 0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x00005AE0: */ 0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x00005AF0: */ 0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x00005B00: */ 0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x00005B10: */ 0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x00005B20: */ 0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x00005B30: */ 0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x00005B40: */ 0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x00005B50: */ 0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x00005B60: */ 0x2A,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00005B70: */ 0x60,0x5B,0x00,0x00,0x41,0x00,0x00,0x00,0xB8,0x01,0x00,0x00,0x35,0x00,0x00,0x00, +/* 0x00005B80: */ 0x60,0x5B,0x00,0x00,0x9B,0x00,0x00,0x00,0x9B,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00005B90: */ 0x60,0x5B,0x00,0x00,0x41,0x00,0x00,0x00,0x35,0x00,0x00,0x00,0x41,0x00,0x00,0x00, +/* 0x00005BA0: */ 0x9C,0x00,0x00,0x00,0xAC,0x01,0x00,0x00,0x60,0x5B,0x00,0x00,0x9B,0x00,0x00,0x00, +/* 0x00005BB0: */ 0x00,0x00,0x00,0x00,0x60,0x5B,0x00,0x00,0x41,0x00,0x00,0x00,0x41,0x00,0x00,0x00, +/* 0x00005BC0: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC3,0x00,0x00,0x00,0x60,0x5B,0x00,0x00, +/* 0x00005BD0: */ 0x41,0x00,0x00,0x00,0x7D,0x00,0x00,0x00,0x41,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00005BE0: */ 0x00,0x00,0x00,0x00,0x44,0x59,0x00,0x00,0x34,0x59,0x00,0x00,0x7D,0x00,0x00,0x00, +/* 0x00005BF0: */ 0x59,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x7D,0x00,0x00,0x00,0x60,0x5B,0x00,0x00, +/* 0x00005C00: */ 0x9B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC2,0x00,0x00,0x00,0x60,0x5B,0x00,0x00, +/* 0x00005C10: */ 0x7F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x5B,0x00,0x00,0x41,0x00,0x00,0x00, +/* 0x00005C20: */ 0x44,0x59,0x00,0x00,0x23,0x00,0x00,0x00,0x48,0x0F,0x00,0x00,0x1C,0x54,0x52,0x41, +/* 0x00005C30: */ 0x43,0x45,0x20,0x72,0x65,0x74,0x75,0x72,0x6E,0x20,0x73,0x74,0x61,0x63,0x6B,0x20, +/* 0x00005C40: */ 0x4F,0x56,0x45,0x52,0x46,0x4C,0x4F,0x57,0x21,0x5A,0x5A,0x5A,0x48,0x1E,0x00,0x00, +/* 0x00005C50: */ 0x60,0x5B,0x00,0x00,0x41,0x00,0x00,0x00,0x44,0x59,0x00,0x00,0x34,0x59,0x00,0x00, +/* 0x00005C60: */ 0x7D,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x0C,0x00,0x00,0x00,0x7D,0x00,0x00,0x00, +/* 0x00005C70: */ 0x22,0x00,0x00,0x00,0x48,0x0F,0x00,0x00,0x1D,0x54,0x52,0x41,0x43,0x45,0x20,0x72, +/* 0x00005C80: */ 0x65,0x74,0x75,0x72,0x6E,0x20,0x73,0x74,0x61,0x63,0x6B,0x20,0x55,0x4E,0x44,0x45, +/* 0x00005C90: */ 0x52,0x46,0x4C,0x4F,0x57,0x21,0x5A,0x5A,0x48,0x1E,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00005CA0: */ 0x2A,0x00,0x00,0x00,0x78,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x00,0x00,0x00, +/* 0x00005CB0: */ 0x2A,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x5A,0x5A,0x5A,0x5A, +/* 0x00005CC0: */ 0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x00005CD0: */ 0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x00005CE0: */ 0x5A,0x5A,0x5A,0x5A,0x2A,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00005CF0: */ 0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x00005D00: */ 0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A, +/* 0x00005D10: */ 0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A,0x2A,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00005D20: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x41,0x00,0x00,0x00,0x18,0x5D,0x00,0x00, +/* 0x00005D30: */ 0x41,0x00,0x00,0x00,0x9B,0x00,0x00,0x00,0xC2,0x00,0x00,0x00,0x18,0x5D,0x00,0x00, +/* 0x00005D40: */ 0x7F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xB2,0x00,0x00,0x00,0x28,0x5D,0x00,0x00, +/* 0x00005D50: */ 0xD4,0x1B,0x00,0x00,0x28,0x5D,0x00,0x00,0xA5,0x00,0x00,0x00,0x28,0x5D,0x00,0x00, +/* 0x00005D60: */ 0x00,0x00,0x00,0x00,0xB0,0x5C,0x00,0x00,0x18,0x5D,0x00,0x00,0x9B,0x00,0x00,0x00, +/* 0x00005D70: */ 0x48,0x5D,0x00,0x00,0x00,0x00,0x00,0x00,0xE4,0x5C,0x00,0x00,0x18,0x5D,0x00,0x00, +/* 0x00005D80: */ 0x9B,0x00,0x00,0x00,0x48,0x5D,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x5D,0x00,0x00, +/* 0x00005D90: */ 0x41,0x00,0x00,0x00,0x41,0x00,0x00,0x00,0x9C,0x00,0x00,0x00,0x9B,0x00,0x00,0x00, +/* 0x00005DA0: */ 0xC2,0x00,0x00,0x00,0x18,0x5D,0x00,0x00,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00005DB0: */ 0xB2,0x00,0x00,0x00,0x8C,0x5D,0x00,0x00,0xD4,0x1B,0x00,0x00,0x8C,0x5D,0x00,0x00, +/* 0x00005DC0: */ 0xA5,0x00,0x00,0x00,0x8C,0x5D,0x00,0x00,0x00,0x00,0x00,0x00,0xB0,0x5C,0x00,0x00, +/* 0x00005DD0: */ 0x18,0x5D,0x00,0x00,0x9B,0x00,0x00,0x00,0xB0,0x5D,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00005DE0: */ 0xE4,0x5C,0x00,0x00,0x18,0x5D,0x00,0x00,0x9B,0x00,0x00,0x00,0xB0,0x5D,0x00,0x00, +/* 0x00005DF0: */ 0x00,0x00,0x00,0x00,0x2A,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00005E00: */ 0x00,0x00,0x00,0x00,0xA4,0x08,0x00,0x00,0x59,0x00,0x00,0x00,0x02,0x00,0x00,0x00, +/* 0x00005E10: */ 0x5C,0x00,0x00,0x00,0xF4,0x5D,0x00,0x00,0x41,0x00,0x00,0x00,0x70,0x5B,0x00,0x00, +/* 0x00005E20: */ 0x60,0x5B,0x00,0x00,0x41,0x00,0x00,0x00,0xF4,0x5D,0x00,0x00,0x9B,0x00,0x00,0x00, +/* 0x00005E30: */ 0x60,0x5B,0x00,0x00,0x41,0x00,0x00,0x00,0x5F,0x00,0x00,0x00,0xC3,0x00,0x00,0x00, +/* 0x00005E40: */ 0x75,0x00,0x00,0x00,0x60,0x5B,0x00,0x00,0x9B,0x00,0x00,0x00,0x60,0x5B,0x00,0x00, +/* 0x00005E50: */ 0x41,0x00,0x00,0x00,0x6A,0x00,0x00,0x00,0x5F,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00005E60: */ 0x00,0x00,0x00,0x00,0x32,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x9B,0x00,0x00,0x00, +/* 0x00005E70: */ 0xC2,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x67,0x00,0x00,0x00, +/* 0x00005E80: */ 0x71,0x00,0x00,0x00,0xE4,0xFF,0xFF,0xFF,0x5D,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00005E90: */ 0xF4,0x5D,0x00,0x00,0x41,0x00,0x00,0x00,0x60,0x5B,0x00,0x00,0x9B,0x00,0x00,0x00, +/* 0x00005EA0: */ 0x90,0x5B,0x00,0x00,0xF4,0x5D,0x00,0x00,0x9B,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00005EB0: */ 0xF4,0x5D,0x00,0x00,0x41,0x00,0x00,0x00,0x9C,0x00,0x00,0x00,0xC3,0x00,0x00,0x00, +/* 0x00005EC0: */ 0x75,0x00,0x00,0x00,0x41,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00005ED0: */ 0x01,0x00,0x00,0x00,0xB0,0x5E,0x00,0x00,0x00,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00005EE0: */ 0x02,0x00,0x00,0x00,0xB0,0x5E,0x00,0x00,0x00,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00005EF0: */ 0x03,0x00,0x00,0x00,0xB0,0x5E,0x00,0x00,0x00,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00005F00: */ 0x04,0x00,0x00,0x00,0xB0,0x5E,0x00,0x00,0x00,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00005F10: */ 0x05,0x00,0x00,0x00,0xB0,0x5E,0x00,0x00,0x00,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00005F20: */ 0x06,0x00,0x00,0x00,0xB0,0x5E,0x00,0x00,0x00,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00005F30: */ 0x07,0x00,0x00,0x00,0xB0,0x5E,0x00,0x00,0x00,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00005F40: */ 0x08,0x00,0x00,0x00,0xB0,0x5E,0x00,0x00,0x00,0x00,0x00,0x00,0xF4,0x5D,0x00,0x00, +/* 0x00005F50: */ 0x41,0x00,0x00,0x00,0x9C,0x00,0x00,0x00,0xC3,0x00,0x00,0x00,0x75,0x00,0x00,0x00, +/* 0x00005F60: */ 0x9B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x01,0x00,0x00,0x00, +/* 0x00005F70: */ 0x4C,0x5F,0x00,0x00,0x00,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x02,0x00,0x00,0x00, +/* 0x00005F80: */ 0x4C,0x5F,0x00,0x00,0x00,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x03,0x00,0x00,0x00, +/* 0x00005F90: */ 0x4C,0x5F,0x00,0x00,0x00,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x04,0x00,0x00,0x00, +/* 0x00005FA0: */ 0x4C,0x5F,0x00,0x00,0x00,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x05,0x00,0x00,0x00, +/* 0x00005FB0: */ 0x4C,0x5F,0x00,0x00,0x00,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x06,0x00,0x00,0x00, +/* 0x00005FC0: */ 0x4C,0x5F,0x00,0x00,0x00,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x07,0x00,0x00,0x00, +/* 0x00005FD0: */ 0x4C,0x5F,0x00,0x00,0x00,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x08,0x00,0x00,0x00, +/* 0x00005FE0: */ 0x4C,0x5F,0x00,0x00,0x00,0x00,0x00,0x00,0xF4,0x5D,0x00,0x00,0x41,0x00,0x00,0x00, +/* 0x00005FF0: */ 0x9C,0x00,0x00,0x00,0xC3,0x00,0x00,0x00,0x75,0x00,0x00,0x00,0x7F,0x00,0x00,0x00, +/* 0x00006000: */ 0x00,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x5C,0x00,0x00,0x00, +/* 0x00006010: */ 0x5F,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00, +/* 0x00006020: */ 0x20,0x00,0x00,0x00,0x61,0x00,0x00,0x00,0x41,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00006030: */ 0x03,0x00,0x00,0x00,0x67,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0x24,0x00,0x00,0x00, +/* 0x00006040: */ 0x60,0x00,0x00,0x00,0x70,0x5B,0x00,0x00,0x5F,0x00,0x00,0x00,0x70,0x5B,0x00,0x00, +/* 0x00006050: */ 0xC2,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x67,0x00,0x00,0x00, +/* 0x00006060: */ 0x61,0x00,0x00,0x00,0x5D,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xA4,0x08,0x00,0x00, +/* 0x00006070: */ 0xA4,0x08,0x00,0x00,0x59,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x5C,0x00,0x00,0x00, +/* 0x00006080: */ 0x90,0x5B,0x00,0x00,0x6A,0x00,0x00,0x00,0x90,0x5B,0x00,0x00,0x02,0x00,0x00,0x00, +/* 0x00006090: */ 0x6B,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x61,0x00,0x00,0x00,0x1E,0x00,0x00,0x00, +/* 0x000060A0: */ 0xBC,0x00,0x00,0x00,0x1C,0x00,0x00,0x00,0xC2,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x000060B0: */ 0x01,0x00,0x00,0x00,0x67,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0x28,0x00,0x00,0x00, +/* 0x000060C0: */ 0x61,0x00,0x00,0x00,0x70,0x5B,0x00,0x00,0x60,0x00,0x00,0x00,0x70,0x5B,0x00,0x00, +/* 0x000060D0: */ 0x5F,0x00,0x00,0x00,0x41,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x01,0x00,0x00,0x00, +/* 0x000060E0: */ 0x67,0x00,0x00,0x00,0x5F,0x00,0x00,0x00,0x5D,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000060F0: */ 0xA4,0x08,0x00,0x00,0xA4,0x08,0x00,0x00,0xA4,0x08,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00006100: */ 0x05,0x00,0x00,0x00,0x5C,0x00,0x00,0x00,0x90,0x5B,0x00,0x00,0x6B,0x00,0x00,0x00, +/* 0x00006110: */ 0x90,0x5B,0x00,0x00,0x6D,0x00,0x00,0x00,0x63,0x00,0x00,0x00,0x5F,0x00,0x00,0x00, +/* 0x00006120: */ 0x7D,0x00,0x00,0x00,0x6C,0x00,0x00,0x00,0x63,0x00,0x00,0x00,0x61,0x00,0x00,0x00, +/* 0x00006130: */ 0x75,0x00,0x00,0x00,0x61,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x62,0x00,0x00,0x00, +/* 0x00006140: */ 0x75,0x00,0x00,0x00,0x11,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x80, +/* 0x00006150: */ 0x11,0x00,0x00,0x00,0x62,0x00,0x00,0x00,0x61,0x00,0x00,0x00,0x75,0x00,0x00,0x00, +/* 0x00006160: */ 0x61,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x63,0x00,0x00,0x00,0x75,0x00,0x00,0x00, +/* 0x00006170: */ 0x11,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x11,0x00,0x00,0x00, +/* 0x00006180: */ 0x7A,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x1C,0x00,0x00,0x00,0xC2,0x00,0x00,0x00, +/* 0x00006190: */ 0x59,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x67,0x00,0x00,0x00,0x15,0x00,0x00,0x00, +/* 0x000061A0: */ 0x28,0x00,0x00,0x00,0x62,0x00,0x00,0x00,0x70,0x5B,0x00,0x00,0x61,0x00,0x00,0x00, +/* 0x000061B0: */ 0x70,0x5B,0x00,0x00,0x60,0x00,0x00,0x00,0x41,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x000061C0: */ 0x02,0x00,0x00,0x00,0x67,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x5D,0x00,0x00,0x00, +/* 0x000061D0: */ 0x00,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x5C,0x00,0x00,0x00, +/* 0x000061E0: */ 0x5F,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x10,0x01,0x00,0x00,0x23,0x00,0x00,0x00, +/* 0x000061F0: */ 0x5F,0x00,0x00,0x00,0x51,0x00,0x00,0x00,0x22,0x00,0x00,0x00,0x7A,0x00,0x00,0x00, +/* 0x00006200: */ 0xBC,0x00,0x00,0x00,0x34,0x00,0x00,0x00,0x80,0x0F,0x00,0x00,0x1A,0x54,0x52,0x41, +/* 0x00006210: */ 0x43,0x45,0x20,0x2D,0x20,0x49,0x50,0x20,0x6F,0x75,0x74,0x20,0x6F,0x66,0x20,0x72, +/* 0x00006220: */ 0x61,0x6E,0x67,0x65,0x20,0x3D,0x20,0x5A,0x5F,0x00,0x00,0x00,0xF4,0x39,0x00,0x00, +/* 0x00006230: */ 0x28,0x00,0x00,0x00,0x78,0x05,0x00,0x00,0x5D,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00006240: */ 0x59,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x5C,0x00,0x00,0x00,0x5F,0x00,0x00,0x00, +/* 0x00006250: */ 0x98,0x04,0x00,0x00,0x08,0x21,0x00,0x00,0x35,0x00,0x00,0x00,0x90,0x02,0x00,0x00, +/* 0x00006260: */ 0x77,0x00,0x00,0x00,0x8C,0x04,0x00,0x00,0x5F,0x00,0x00,0x00,0x9C,0x00,0x00,0x00, +/* 0x00006270: */ 0x75,0x00,0x00,0x00,0x80,0x0F,0x00,0x00,0x02,0x20,0x2B,0x5A,0xA4,0x1D,0x00,0x00, +/* 0x00006280: */ 0x5D,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xA4,0x08,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00006290: */ 0x01,0x00,0x00,0x00,0x5C,0x00,0x00,0x00,0xA5,0x00,0x00,0x00,0x41,0x00,0x00,0x00, +/* 0x000062A0: */ 0xA2,0x00,0x00,0x00,0x80,0x0F,0x00,0x00,0x01,0x3C,0x5A,0x5A,0xA5,0x00,0x00,0x00, +/* 0x000062B0: */ 0x41,0x00,0x00,0x00,0xA8,0x02,0x00,0x00,0x59,0x00,0x00,0x00,0x01,0x00,0x00,0x00, +/* 0x000062C0: */ 0xB4,0x1D,0x00,0x00,0x80,0x0F,0x00,0x00,0x01,0x3A,0x5A,0x5A,0x2E,0x00,0x00,0x00, +/* 0x000062D0: */ 0x59,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0xB4,0x1D,0x00,0x00,0x80,0x0F,0x00,0x00, +/* 0x000062E0: */ 0x02,0x3E,0x20,0x5A,0x8E,0x00,0x00,0x00,0xA5,0x00,0x00,0x00,0x9B,0x00,0x00,0x00, +/* 0x000062F0: */ 0x2E,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x74,0x00,0x00,0x00, +/* 0x00006300: */ 0x69,0x00,0x00,0x00,0x2E,0x00,0x00,0x00,0x5F,0x00,0x00,0x00,0x75,0x00,0x00,0x00, +/* 0x00006310: */ 0xBC,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x80,0x0F,0x00,0x00,0x04,0x2E,0x2E,0x2E, +/* 0x00006320: */ 0x20,0x5A,0x5A,0x5A,0x5F,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00006330: */ 0x80,0x00,0x00,0x00,0x24,0x00,0x00,0x00,0x5F,0x00,0x00,0x00,0x53,0x00,0x00,0x00, +/* 0x00006340: */ 0x02,0x00,0x00,0x00,0x75,0x00,0x00,0x00,0x7C,0x00,0x00,0x00,0xA4,0x1D,0x00,0x00, +/* 0x00006350: */ 0x71,0x00,0x00,0x00,0xE4,0xFF,0xFF,0xFF,0x5D,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00006360: */ 0x59,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x5C,0x00,0x00,0x00,0xF4,0x0C,0x00,0x00, +/* 0x00006370: */ 0x5F,0x00,0x00,0x00,0xD4,0x61,0x00,0x00,0x80,0x0F,0x00,0x00,0x03,0x3C,0x3C,0x20, +/* 0x00006380: */ 0x5F,0x00,0x00,0x00,0x40,0x62,0x00,0x00,0x59,0x00,0x00,0x00,0x10,0x00,0x00,0x00, +/* 0x00006390: */ 0xE0,0x58,0x00,0x00,0x88,0x62,0x00,0x00,0x59,0x00,0x00,0x00,0x28,0x00,0x00,0x00, +/* 0x000063A0: */ 0xE0,0x58,0x00,0x00,0x80,0x0F,0x00,0x00,0x03,0x20,0x7C,0x7C,0x0F,0x00,0x00,0x00, +/* 0x000063B0: */ 0x20,0x59,0x00,0x00,0x41,0x00,0x00,0x00,0x50,0x08,0x00,0x00,0x98,0x0C,0x00,0x00, +/* 0x000063C0: */ 0x5F,0x00,0x00,0x00,0xF0,0x50,0x00,0x00,0xC2,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x000063D0: */ 0x01,0x00,0x00,0x00,0x67,0x00,0x00,0x00,0x35,0x00,0x00,0x00,0xA8,0x50,0x00,0x00, +/* 0x000063E0: */ 0x8C,0x0C,0x00,0x00,0x59,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x7B,0x00,0x00,0x00, +/* 0x000063F0: */ 0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x1C,0x00,0x00,0x00,0x33,0x00,0x00,0x00, +/* 0x00006400: */ 0x5F,0x00,0x00,0x00,0x41,0x00,0x00,0x00,0xA4,0x1D,0x00,0x00,0x15,0x00,0x00,0x00, +/* 0x00006410: */ 0x40,0x01,0x00,0x00,0x59,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x7B,0x00,0x00,0x00, +/* 0x00006420: */ 0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x1C,0x00,0x00,0x00,0x33,0x00,0x00,0x00, +/* 0x00006430: */ 0x5F,0x00,0x00,0x00,0x10,0x09,0x00,0x00,0xA4,0x1D,0x00,0x00,0x15,0x00,0x00,0x00, +/* 0x00006440: */ 0x10,0x01,0x00,0x00,0x59,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0x7B,0x00,0x00,0x00, +/* 0x00006450: */ 0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x1C,0x00,0x00,0x00,0x33,0x00,0x00,0x00, +/* 0x00006460: */ 0x5F,0x00,0x00,0x00,0x41,0x00,0x00,0x00,0xA4,0x1D,0x00,0x00,0x15,0x00,0x00,0x00, +/* 0x00006470: */ 0xE0,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x7B,0x00,0x00,0x00, +/* 0x00006480: */ 0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x1C,0x00,0x00,0x00,0x33,0x00,0x00,0x00, +/* 0x00006490: */ 0x5F,0x00,0x00,0x00,0x41,0x00,0x00,0x00,0xA4,0x1D,0x00,0x00,0x15,0x00,0x00,0x00, +/* 0x000064A0: */ 0xB0,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x80,0x0F,0x00,0x00,0x7B,0x00,0x00,0x00, +/* 0x000064B0: */ 0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x24,0x00,0x00,0x00,0x33,0x00,0x00,0x00, +/* 0x000064C0: */ 0x5F,0x00,0x00,0x00,0x70,0x01,0x00,0x00,0xA3,0x00,0x00,0x00,0x80,0x0F,0x00,0x00, +/* 0x000064D0: */ 0x01,0x22,0x5A,0x5A,0x15,0x00,0x00,0x00,0x78,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x000064E0: */ 0x48,0x0F,0x00,0x00,0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00, +/* 0x000064F0: */ 0x24,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x5F,0x00,0x00,0x00,0x70,0x01,0x00,0x00, +/* 0x00006500: */ 0xA3,0x00,0x00,0x00,0x80,0x0F,0x00,0x00,0x01,0x22,0x5A,0x5A,0x15,0x00,0x00,0x00, +/* 0x00006510: */ 0x40,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x64,0x0F,0x00,0x00,0x7B,0x00,0x00,0x00, +/* 0x00006520: */ 0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x24,0x00,0x00,0x00,0x33,0x00,0x00,0x00, +/* 0x00006530: */ 0x5F,0x00,0x00,0x00,0x70,0x01,0x00,0x00,0xA3,0x00,0x00,0x00,0x80,0x0F,0x00,0x00, +/* 0x00006540: */ 0x01,0x22,0x5A,0x5A,0x15,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x33,0x00,0x00,0x00, +/* 0x00006550: */ 0x59,0x00,0x00,0x00,0x41,0x00,0x00,0x00,0xE0,0x58,0x00,0x00,0x80,0x0F,0x00,0x00, +/* 0x00006560: */ 0x03,0x3E,0x3E,0x20,0x5D,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xA4,0x08,0x00,0x00, +/* 0x00006570: */ 0x59,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x5C,0x00,0x00,0x00,0x60,0x00,0x00,0x00, +/* 0x00006580: */ 0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00, +/* 0x00006590: */ 0xBC,0x00,0x00,0x00,0x28,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x80,0x07,0x00,0x00, +/* 0x000065A0: */ 0x0F,0x00,0x00,0x00,0x20,0x59,0x00,0x00,0x7F,0x00,0x00,0x00,0x90,0x5B,0x00,0x00, +/* 0x000065B0: */ 0x69,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0xE8,0x07,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x000065C0: */ 0x2A,0x00,0x00,0x00,0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00, +/* 0x000065D0: */ 0x20,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x5F,0x00,0x00,0x00,0xB8,0x01,0x00,0x00, +/* 0x000065E0: */ 0x14,0x00,0x00,0x00,0x7D,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0xB4,0x07,0x00,0x00, +/* 0x000065F0: */ 0x59,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00, +/* 0x00006600: */ 0xBC,0x00,0x00,0x00,0x28,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x5F,0x00,0x00,0x00, +/* 0x00006610: */ 0x41,0x00,0x00,0x00,0xC2,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x01,0x00,0x00,0x00, +/* 0x00006620: */ 0x67,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0x78,0x07,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00006630: */ 0x0F,0x00,0x00,0x00,0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00, +/* 0x00006640: */ 0x28,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x5F,0x00,0x00,0x00,0x10,0x09,0x00,0x00, +/* 0x00006650: */ 0xC2,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x67,0x00,0x00,0x00, +/* 0x00006660: */ 0x15,0x00,0x00,0x00,0x3C,0x07,0x00,0x00,0x59,0x00,0x00,0x00,0x15,0x00,0x00,0x00, +/* 0x00006670: */ 0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x24,0x00,0x00,0x00, +/* 0x00006680: */ 0x33,0x00,0x00,0x00,0x5F,0x00,0x00,0x00,0x41,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00006690: */ 0x01,0x00,0x00,0x00,0x67,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0x04,0x07,0x00,0x00, +/* 0x000066A0: */ 0x59,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00, +/* 0x000066B0: */ 0xBC,0x00,0x00,0x00,0x48,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x24,0x00,0x00,0x00, +/* 0x000066C0: */ 0xBC,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x5F,0x00,0x00,0x00,0x41,0x00,0x00,0x00, +/* 0x000066D0: */ 0x59,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x67,0x00,0x00,0x00,0x15,0x00,0x00,0x00, +/* 0x000066E0: */ 0x14,0x00,0x00,0x00,0xC2,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x01,0x00,0x00,0x00, +/* 0x000066F0: */ 0x67,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0xA8,0x06,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00006700: */ 0xA2,0x00,0x00,0x00,0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00, +/* 0x00006710: */ 0x14,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x70,0x5B,0x00,0x00,0x15,0x00,0x00,0x00, +/* 0x00006720: */ 0x80,0x06,0x00,0x00,0x59,0x00,0x00,0x00,0x8E,0x00,0x00,0x00,0x7B,0x00,0x00,0x00, +/* 0x00006730: */ 0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x33,0x00,0x00,0x00, +/* 0x00006740: */ 0x90,0x5B,0x00,0x00,0x15,0x00,0x00,0x00,0x58,0x06,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00006750: */ 0x8D,0x00,0x00,0x00,0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00, +/* 0x00006760: */ 0x14,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0xB4,0x5B,0x00,0x00,0x15,0x00,0x00,0x00, +/* 0x00006770: */ 0x30,0x06,0x00,0x00,0x59,0x00,0x00,0x00,0x8C,0x00,0x00,0x00,0x7B,0x00,0x00,0x00, +/* 0x00006780: */ 0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x33,0x00,0x00,0x00, +/* 0x00006790: */ 0x08,0x5C,0x00,0x00,0x15,0x00,0x00,0x00,0x08,0x06,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x000067A0: */ 0x0C,0x00,0x00,0x00,0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00, +/* 0x000067B0: */ 0x18,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x70,0x5B,0x00,0x00,0x70,0x5B,0x00,0x00, +/* 0x000067C0: */ 0x15,0x00,0x00,0x00,0xDC,0x05,0x00,0x00,0x59,0x00,0x00,0x00,0x0B,0x00,0x00,0x00, +/* 0x000067D0: */ 0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x18,0x00,0x00,0x00, +/* 0x000067E0: */ 0x33,0x00,0x00,0x00,0x90,0x5B,0x00,0x00,0x90,0x5B,0x00,0x00,0x15,0x00,0x00,0x00, +/* 0x000067F0: */ 0xB0,0x05,0x00,0x00,0x59,0x00,0x00,0x00,0x0A,0x00,0x00,0x00,0x7B,0x00,0x00,0x00, +/* 0x00006800: */ 0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x33,0x00,0x00,0x00, +/* 0x00006810: */ 0xB4,0x5B,0x00,0x00,0x59,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0xC8,0x5B,0x00,0x00, +/* 0x00006820: */ 0x15,0x00,0x00,0x00,0x7C,0x05,0x00,0x00,0x59,0x00,0x00,0x00,0x53,0x00,0x00,0x00, +/* 0x00006830: */ 0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x1C,0x00,0x00,0x00, +/* 0x00006840: */ 0x33,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0xC8,0x5B,0x00,0x00, +/* 0x00006850: */ 0x15,0x00,0x00,0x00,0x4C,0x05,0x00,0x00,0x59,0x00,0x00,0x00,0x55,0x00,0x00,0x00, +/* 0x00006860: */ 0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x1C,0x00,0x00,0x00, +/* 0x00006870: */ 0x33,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0xC8,0x5B,0x00,0x00, +/* 0x00006880: */ 0x15,0x00,0x00,0x00,0x1C,0x05,0x00,0x00,0x59,0x00,0x00,0x00,0x57,0x00,0x00,0x00, +/* 0x00006890: */ 0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x2C,0x00,0x00,0x00, +/* 0x000068A0: */ 0x33,0x00,0x00,0x00,0x08,0x5C,0x00,0x00,0x08,0x5C,0x00,0x00,0x5F,0x00,0x00,0x00, +/* 0x000068B0: */ 0x41,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x67,0x00,0x00,0x00, +/* 0x000068C0: */ 0x15,0x00,0x00,0x00,0xDC,0x04,0x00,0x00,0x59,0x00,0x00,0x00,0x71,0x00,0x00,0x00, +/* 0x000068D0: */ 0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x1C,0x00,0x00,0x00, +/* 0x000068E0: */ 0x33,0x00,0x00,0x00,0x5F,0x00,0x00,0x00,0x6C,0x60,0x00,0x00,0x69,0x00,0x00,0x00, +/* 0x000068F0: */ 0x15,0x00,0x00,0x00,0xAC,0x04,0x00,0x00,0x59,0x00,0x00,0x00,0x7E,0x00,0x00,0x00, +/* 0x00006900: */ 0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x1C,0x00,0x00,0x00, +/* 0x00006910: */ 0x33,0x00,0x00,0x00,0x5F,0x00,0x00,0x00,0xF0,0x60,0x00,0x00,0x69,0x00,0x00,0x00, +/* 0x00006920: */ 0x15,0x00,0x00,0x00,0x7C,0x04,0x00,0x00,0x59,0x00,0x00,0x00,0x32,0x00,0x00,0x00, +/* 0x00006930: */ 0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x18,0x00,0x00,0x00, +/* 0x00006940: */ 0x33,0x00,0x00,0x00,0x70,0x5B,0x00,0x00,0x70,0x5B,0x00,0x00,0x15,0x00,0x00,0x00, +/* 0x00006950: */ 0x50,0x04,0x00,0x00,0x59,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x7B,0x00,0x00,0x00, +/* 0x00006960: */ 0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x1C,0x00,0x00,0x00,0x33,0x00,0x00,0x00, +/* 0x00006970: */ 0x5F,0x00,0x00,0x00,0x04,0x60,0x00,0x00,0x69,0x00,0x00,0x00,0x15,0x00,0x00,0x00, +/* 0x00006980: */ 0x20,0x04,0x00,0x00,0x59,0x00,0x00,0x00,0x80,0x0F,0x00,0x00,0x7B,0x00,0x00,0x00, +/* 0x00006990: */ 0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x33,0x00,0x00,0x00, +/* 0x000069A0: */ 0x5F,0x00,0x00,0x00,0x70,0x01,0x00,0x00,0xA3,0x00,0x00,0x00,0x5F,0x00,0x00,0x00, +/* 0x000069B0: */ 0x70,0x01,0x00,0x00,0x7D,0x00,0x00,0x00,0x88,0x03,0x00,0x00,0x69,0x00,0x00,0x00, +/* 0x000069C0: */ 0x15,0x00,0x00,0x00,0xDC,0x03,0x00,0x00,0x59,0x00,0x00,0x00,0x48,0x0F,0x00,0x00, +/* 0x000069D0: */ 0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x28,0x00,0x00,0x00, +/* 0x000069E0: */ 0x33,0x00,0x00,0x00,0x5F,0x00,0x00,0x00,0x5F,0x00,0x00,0x00,0x70,0x01,0x00,0x00, +/* 0x000069F0: */ 0x7D,0x00,0x00,0x00,0x88,0x03,0x00,0x00,0x69,0x00,0x00,0x00,0x15,0x00,0x00,0x00, +/* 0x00006A00: */ 0xA0,0x03,0x00,0x00,0x59,0x00,0x00,0x00,0x64,0x0F,0x00,0x00,0x7B,0x00,0x00,0x00, +/* 0x00006A10: */ 0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x2C,0x00,0x00,0x00,0x33,0x00,0x00,0x00, +/* 0x00006A20: */ 0x5F,0x00,0x00,0x00,0x70,0x01,0x00,0x00,0x5F,0x00,0x00,0x00,0x70,0x01,0x00,0x00, +/* 0x00006A30: */ 0x7D,0x00,0x00,0x00,0x88,0x03,0x00,0x00,0x69,0x00,0x00,0x00,0x15,0x00,0x00,0x00, +/* 0x00006A40: */ 0x60,0x03,0x00,0x00,0x59,0x00,0x00,0x00,0x5C,0x00,0x00,0x00,0x7B,0x00,0x00,0x00, +/* 0x00006A50: */ 0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x33,0x00,0x00,0x00, +/* 0x00006A60: */ 0x04,0x5E,0x00,0x00,0x15,0x00,0x00,0x00,0x38,0x03,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00006A70: */ 0x5D,0x00,0x00,0x00,0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00, +/* 0x00006A80: */ 0x14,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x90,0x5E,0x00,0x00,0x15,0x00,0x00,0x00, +/* 0x00006A90: */ 0x10,0x03,0x00,0x00,0x59,0x00,0x00,0x00,0x5E,0x00,0x00,0x00,0x7B,0x00,0x00,0x00, +/* 0x00006AA0: */ 0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x33,0x00,0x00,0x00, +/* 0x00006AB0: */ 0xB0,0x5E,0x00,0x00,0x15,0x00,0x00,0x00,0xE8,0x02,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00006AC0: */ 0x5F,0x00,0x00,0x00,0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00, +/* 0x00006AD0: */ 0x14,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0xCC,0x5E,0x00,0x00,0x15,0x00,0x00,0x00, +/* 0x00006AE0: */ 0xC0,0x02,0x00,0x00,0x59,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x7B,0x00,0x00,0x00, +/* 0x00006AF0: */ 0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x33,0x00,0x00,0x00, +/* 0x00006B00: */ 0xDC,0x5E,0x00,0x00,0x15,0x00,0x00,0x00,0x98,0x02,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00006B10: */ 0x61,0x00,0x00,0x00,0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00, +/* 0x00006B20: */ 0x14,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0xEC,0x5E,0x00,0x00,0x15,0x00,0x00,0x00, +/* 0x00006B30: */ 0x70,0x02,0x00,0x00,0x59,0x00,0x00,0x00,0x62,0x00,0x00,0x00,0x7B,0x00,0x00,0x00, +/* 0x00006B40: */ 0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x33,0x00,0x00,0x00, +/* 0x00006B50: */ 0xFC,0x5E,0x00,0x00,0x15,0x00,0x00,0x00,0x48,0x02,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00006B60: */ 0x63,0x00,0x00,0x00,0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00, +/* 0x00006B70: */ 0x14,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x0C,0x5F,0x00,0x00,0x15,0x00,0x00,0x00, +/* 0x00006B80: */ 0x20,0x02,0x00,0x00,0x59,0x00,0x00,0x00,0x64,0x00,0x00,0x00,0x7B,0x00,0x00,0x00, +/* 0x00006B90: */ 0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x33,0x00,0x00,0x00, +/* 0x00006BA0: */ 0x1C,0x5F,0x00,0x00,0x15,0x00,0x00,0x00,0xF8,0x01,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00006BB0: */ 0x65,0x00,0x00,0x00,0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00, +/* 0x00006BC0: */ 0x14,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x2C,0x5F,0x00,0x00,0x15,0x00,0x00,0x00, +/* 0x00006BD0: */ 0xD0,0x01,0x00,0x00,0x59,0x00,0x00,0x00,0x66,0x00,0x00,0x00,0x7B,0x00,0x00,0x00, +/* 0x00006BE0: */ 0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x33,0x00,0x00,0x00, +/* 0x00006BF0: */ 0x3C,0x5F,0x00,0x00,0x15,0x00,0x00,0x00,0xA8,0x01,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00006C00: */ 0x68,0x00,0x00,0x00,0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00, +/* 0x00006C10: */ 0x14,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x4C,0x5F,0x00,0x00,0x15,0x00,0x00,0x00, +/* 0x00006C20: */ 0x80,0x01,0x00,0x00,0x59,0x00,0x00,0x00,0x69,0x00,0x00,0x00,0x7B,0x00,0x00,0x00, +/* 0x00006C30: */ 0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x33,0x00,0x00,0x00, +/* 0x00006C40: */ 0x68,0x5F,0x00,0x00,0x15,0x00,0x00,0x00,0x58,0x01,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00006C50: */ 0x6A,0x00,0x00,0x00,0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00, +/* 0x00006C60: */ 0x14,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x78,0x5F,0x00,0x00,0x15,0x00,0x00,0x00, +/* 0x00006C70: */ 0x30,0x01,0x00,0x00,0x59,0x00,0x00,0x00,0x6B,0x00,0x00,0x00,0x7B,0x00,0x00,0x00, +/* 0x00006C80: */ 0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x33,0x00,0x00,0x00, +/* 0x00006C90: */ 0x88,0x5F,0x00,0x00,0x15,0x00,0x00,0x00,0x08,0x01,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00006CA0: */ 0x6C,0x00,0x00,0x00,0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00, +/* 0x00006CB0: */ 0x14,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x98,0x5F,0x00,0x00,0x15,0x00,0x00,0x00, +/* 0x00006CC0: */ 0xE0,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x6D,0x00,0x00,0x00,0x7B,0x00,0x00,0x00, +/* 0x00006CD0: */ 0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x33,0x00,0x00,0x00, +/* 0x00006CE0: */ 0xA8,0x5F,0x00,0x00,0x15,0x00,0x00,0x00,0xB8,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00006CF0: */ 0x6E,0x00,0x00,0x00,0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00, +/* 0x00006D00: */ 0x14,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0xB8,0x5F,0x00,0x00,0x15,0x00,0x00,0x00, +/* 0x00006D10: */ 0x90,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x6F,0x00,0x00,0x00,0x7B,0x00,0x00,0x00, +/* 0x00006D20: */ 0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x33,0x00,0x00,0x00, +/* 0x00006D30: */ 0xC8,0x5F,0x00,0x00,0x15,0x00,0x00,0x00,0x68,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00006D40: */ 0x70,0x00,0x00,0x00,0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00, +/* 0x00006D50: */ 0x14,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0xD8,0x5F,0x00,0x00,0x15,0x00,0x00,0x00, +/* 0x00006D60: */ 0x40,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x67,0x00,0x00,0x00,0x7B,0x00,0x00,0x00, +/* 0x00006D70: */ 0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x33,0x00,0x00,0x00, +/* 0x00006D80: */ 0xE8,0x5F,0x00,0x00,0x15,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0xA2,0x00,0x00,0x00, +/* 0x00006D90: */ 0x60,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x8E,0x00,0x00,0x00,0x33,0x00,0x00,0x00, +/* 0x00006DA0: */ 0x5F,0x00,0x00,0x00,0x5D,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xA4,0x08,0x00,0x00, +/* 0x00006DB0: */ 0xA4,0x08,0x00,0x00,0x59,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x5C,0x00,0x00,0x00, +/* 0x00006DC0: */ 0x5F,0x00,0x00,0x00,0xD4,0x61,0x00,0x00,0x64,0x5D,0x00,0x00,0x51,0x00,0x00,0x00, +/* 0x00006DD0: */ 0x6B,0x00,0x00,0x00,0xE0,0x5D,0x00,0x00,0x61,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00006DE0: */ 0x00,0x01,0x00,0x00,0x7D,0x00,0x00,0x00,0xA9,0x00,0x00,0x00,0x9B,0x00,0x00,0x00, +/* 0x00006DF0: */ 0x5F,0x00,0x00,0x00,0xF0,0x50,0x00,0x00,0x6A,0x00,0x00,0x00,0xC2,0x00,0x00,0x00, +/* 0x00006E00: */ 0x59,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x67,0x00,0x00,0x00,0x60,0x00,0x00,0x00, +/* 0x00006E10: */ 0xF4,0x58,0x00,0x00,0xBC,0x00,0x00,0x00,0x1C,0x00,0x00,0x00,0x5F,0x00,0x00,0x00, +/* 0x00006E20: */ 0x60,0x00,0x00,0x00,0x6C,0x65,0x00,0x00,0x69,0x00,0x00,0x00,0x15,0x00,0x00,0x00, +/* 0x00006E30: */ 0x6C,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x20,0x59,0x00,0x00,0x41,0x00,0x00,0x00, +/* 0x00006E40: */ 0x0F,0x00,0x00,0x00,0x30,0x59,0x00,0x00,0x41,0x00,0x00,0x00,0x20,0x00,0x00,0x00, +/* 0x00006E50: */ 0xBC,0x00,0x00,0x00,0x38,0x00,0x00,0x00,0x5F,0x00,0x00,0x00,0x70,0x5B,0x00,0x00, +/* 0x00006E60: */ 0x59,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x20,0x59,0x00,0x00, +/* 0x00006E70: */ 0x7F,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x5C,0x04,0x00,0x00,0x7D,0x00,0x00,0x00, +/* 0x00006E80: */ 0x69,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x5F,0x00,0x00,0x00, +/* 0x00006E90: */ 0x60,0x00,0x00,0x00,0x6C,0x65,0x00,0x00,0x69,0x00,0x00,0x00,0x18,0x5C,0x00,0x00, +/* 0x00006EA0: */ 0x78,0x5D,0x00,0x00,0xCC,0x5D,0x00,0x00,0x61,0x00,0x00,0x00,0xA9,0x00,0x00,0x00, +/* 0x00006EB0: */ 0x9B,0x00,0x00,0x00,0x5F,0x00,0x00,0x00,0x5D,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00006EC0: */ 0xA4,0x08,0x00,0x00,0x59,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x5C,0x00,0x00,0x00, +/* 0x00006ED0: */ 0x0F,0x00,0x00,0x00,0x20,0x59,0x00,0x00,0x41,0x00,0x00,0x00,0x25,0x00,0x00,0x00, +/* 0x00006EE0: */ 0xBC,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x5F,0x00,0x00,0x00,0xAC,0x6D,0x00,0x00, +/* 0x00006EF0: */ 0x69,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x20,0x59,0x00,0x00,0x41,0x00,0x00,0x00, +/* 0x00006F00: */ 0x25,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x5F,0x00,0x00,0x00, +/* 0x00006F10: */ 0x60,0x63,0x00,0x00,0x15,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0xB6,0x00,0x00,0x00, +/* 0x00006F20: */ 0x84,0x01,0x00,0x00,0x80,0x0F,0x00,0x00,0x09,0x46,0x69,0x6E,0x69,0x73,0x68,0x65, +/* 0x00006F30: */ 0x64,0x2E,0x5A,0x5A,0x28,0x00,0x00,0x00,0x5F,0x00,0x00,0x00,0x5D,0x00,0x00,0x00, +/* 0x00006F40: */ 0x00,0x00,0x00,0x00,0xA0,0x00,0x00,0x00,0x35,0x00,0x00,0x00,0xF4,0x58,0x00,0x00, +/* 0x00006F50: */ 0xBC,0x00,0x00,0x00,0x3C,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x80,0x0F,0x00,0x00, +/* 0x00006F60: */ 0x23,0x53,0x6F,0x72,0x72,0x79,0x2E,0x20,0x59,0x6F,0x75,0x20,0x63,0x61,0x6E,0x27, +/* 0x00006F70: */ 0x74,0x20,0x74,0x72,0x61,0x63,0x65,0x20,0x61,0x20,0x70,0x72,0x69,0x6D,0x69,0x74, +/* 0x00006F80: */ 0x69,0x76,0x65,0x2E,0x28,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0x60,0x00,0x00,0x00, +/* 0x00006F90: */ 0x59,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x20,0x59,0x00,0x00, +/* 0x00006FA0: */ 0x9B,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x20,0x59,0x00,0x00,0x41,0x00,0x00,0x00, +/* 0x00006FB0: */ 0x0F,0x00,0x00,0x00,0x30,0x59,0x00,0x00,0x9B,0x00,0x00,0x00,0xE4,0x5B,0x00,0x00, +/* 0x00006FC0: */ 0x8C,0x04,0x00,0x00,0x0F,0x00,0x00,0x00,0x10,0x59,0x00,0x00,0x9B,0x00,0x00,0x00, +/* 0x00006FD0: */ 0x0F,0x00,0x00,0x00,0x10,0x59,0x00,0x00,0x41,0x00,0x00,0x00,0x60,0x63,0x00,0x00, +/* 0x00006FE0: */ 0xB6,0x00,0x00,0x00,0x98,0x01,0x00,0x00,0x78,0x5D,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00006FF0: */ 0x0F,0x00,0x00,0x00,0x20,0x59,0x00,0x00,0x41,0x00,0x00,0x00,0x0F,0x00,0x00,0x00, +/* 0x00007000: */ 0x30,0x59,0x00,0x00,0x9B,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x10,0x59,0x00,0x00, +/* 0x00007010: */ 0x41,0x00,0x00,0x00,0xC0,0x6E,0x00,0x00,0x0F,0x00,0x00,0x00,0x10,0x59,0x00,0x00, +/* 0x00007020: */ 0x9B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x20,0x59,0x00,0x00, +/* 0x00007030: */ 0x41,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x30,0x59,0x00,0x00, +/* 0x00007040: */ 0x9B,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x10,0x59,0x00,0x00,0x41,0x00,0x00,0x00, +/* 0x00007050: */ 0xC0,0x6E,0x00,0x00,0x0F,0x00,0x00,0x00,0x10,0x59,0x00,0x00,0x9B,0x00,0x00,0x00, +/* 0x00007060: */ 0x00,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x20,0x59,0x00,0x00,0x41,0x00,0x00,0x00, +/* 0x00007070: */ 0x0F,0x00,0x00,0x00,0x30,0x59,0x00,0x00,0x9B,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00007080: */ 0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x28,0x00,0x00,0x00,0x0F,0x00,0x00,0x00, +/* 0x00007090: */ 0x10,0x59,0x00,0x00,0x41,0x00,0x00,0x00,0xC0,0x6E,0x00,0x00,0x0F,0x00,0x00,0x00, +/* 0x000070A0: */ 0x10,0x59,0x00,0x00,0x9B,0x00,0x00,0x00,0x71,0x00,0x00,0x00,0xE0,0xFF,0xFF,0xFF, +/* 0x000070B0: */ 0x00,0x00,0x00,0x00,0x2D,0x00,0x00,0x00,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000070C0: */ 0xA4,0x08,0x00,0x00,0x59,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x5C,0x00,0x00,0x00, +/* 0x000070D0: */ 0x51,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0xB4,0x70,0x00,0x00,0x90,0x0D,0x00,0x00, +/* 0x000070E0: */ 0x23,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x3C,0x00,0x00,0x00,0x80,0x0F,0x00,0x00, +/* 0x000070F0: */ 0x18,0x52,0x65,0x73,0x65,0x74,0x74,0x69,0x6E,0x67,0x20,0x54,0x52,0x41,0x43,0x45, +/* 0x00007100: */ 0x2E,0x55,0x53,0x45,0x52,0x20,0x21,0x21,0x21,0x5A,0x5A,0x5A,0x28,0x00,0x00,0x00, +/* 0x00007110: */ 0x59,0x00,0x00,0x00,0x24,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0xB4,0x70,0x00,0x00, +/* 0x00007120: */ 0x48,0x0D,0x00,0x00,0x5F,0x00,0x00,0x00,0x26,0x00,0x00,0x00,0x5F,0x00,0x00,0x00, +/* 0x00007130: */ 0x59,0x00,0x00,0x00,0x0A,0x00,0x00,0x00,0x1F,0x00,0x00,0x00,0x7A,0x00,0x00,0x00, +/* 0x00007140: */ 0xBC,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x80,0x0F,0x00,0x00,0x20,0x47,0x44,0x20, +/* 0x00007150: */ 0x6C,0x65,0x76,0x65,0x6C,0x20,0x6F,0x75,0x74,0x20,0x6F,0x66,0x20,0x72,0x61,0x6E, +/* 0x00007160: */ 0x67,0x65,0x20,0x28,0x30,0x2D,0x31,0x30,0x29,0x2C,0x20,0x3D,0x20,0x5A,0x5A,0x5A, +/* 0x00007170: */ 0x5F,0x00,0x00,0x00,0xA4,0x1D,0x00,0x00,0x28,0x00,0x00,0x00,0x15,0x00,0x00,0x00, +/* 0x00007180: */ 0xDC,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x20,0x59,0x00,0x00,0x41,0x00,0x00,0x00, +/* 0x00007190: */ 0x5F,0x00,0x00,0x00,0x7D,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x30,0x59,0x00,0x00, +/* 0x000071A0: */ 0x9B,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x20,0x59,0x00,0x00,0x41,0x00,0x00,0x00, +/* 0x000071B0: */ 0x01,0x00,0x00,0x00,0x6A,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x10,0x59,0x00,0x00, +/* 0x000071C0: */ 0x41,0x00,0x00,0x00,0xB4,0x70,0x00,0x00,0x81,0x00,0x00,0x00,0xBC,0x00,0x00,0x00, +/* 0x000071D0: */ 0x50,0x00,0x00,0x00,0x80,0x0F,0x00,0x00,0x14,0x54,0x52,0x41,0x43,0x45,0x2E,0x55, +/* 0x000071E0: */ 0x53,0x45,0x52,0x20,0x72,0x65,0x74,0x75,0x72,0x6E,0x65,0x64,0x20,0x5A,0x5A,0x5A, +/* 0x000071F0: */ 0x35,0x00,0x00,0x00,0xA4,0x1D,0x00,0x00,0x80,0x0F,0x00,0x00,0x16,0x73,0x6F,0x20, +/* 0x00007200: */ 0x73,0x74,0x6F,0x70,0x70,0x69,0x6E,0x67,0x20,0x65,0x78,0x65,0x63,0x75,0x74,0x69, +/* 0x00007210: */ 0x6F,0x6E,0x2E,0x5A,0x28,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0x38,0x00,0x00,0x00, +/* 0x00007220: */ 0x0F,0x00,0x00,0x00,0x10,0x59,0x00,0x00,0x41,0x00,0x00,0x00,0xC0,0x6E,0x00,0x00, +/* 0x00007230: */ 0x0F,0x00,0x00,0x00,0x10,0x59,0x00,0x00,0x9B,0x00,0x00,0x00,0x0F,0x00,0x00,0x00, +/* 0x00007240: */ 0x20,0x59,0x00,0x00,0x41,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x1F,0x00,0x00,0x00, +/* 0x00007250: */ 0x58,0x02,0x00,0x00,0xBC,0x00,0x00,0x00,0x60,0xFF,0xFF,0xFF,0x5D,0x00,0x00,0x00, +/* 0x00007260: */ 0x00,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x70,0x00,0x00, +/* 0x00007270: */ 0x00,0x00,0x00,0x00,0x80,0x0F,0x00,0x00,0x37,0x20,0x20,0x54,0x52,0x41,0x43,0x45, +/* 0x00007280: */ 0x20,0x20,0x28,0x20,0x69,0x2A,0x78,0x20,0x3C,0x6E,0x61,0x6D,0x65,0x3E,0x20,0x2D, +/* 0x00007290: */ 0x2D,0x20,0x2C,0x20,0x73,0x65,0x74,0x75,0x70,0x20,0x74,0x72,0x61,0x63,0x65,0x20, +/* 0x000072A0: */ 0x66,0x6F,0x72,0x20,0x46,0x6F,0x72,0x74,0x68,0x20,0x77,0x6F,0x72,0x64,0x20,0x29, +/* 0x000072B0: */ 0x28,0x00,0x00,0x00,0x80,0x0F,0x00,0x00,0x1B,0x20,0x20,0x53,0x20,0x20,0x20,0x20, +/* 0x000072C0: */ 0x20,0x20,0x28,0x20,0x2D,0x2D,0x20,0x2C,0x20,0x73,0x74,0x65,0x70,0x20,0x6F,0x76, +/* 0x000072D0: */ 0x65,0x72,0x20,0x29,0x28,0x00,0x00,0x00,0x80,0x0F,0x00,0x00,0x2B,0x20,0x20,0x53, +/* 0x000072E0: */ 0x4D,0x20,0x20,0x20,0x20,0x20,0x28,0x20,0x6D,0x61,0x6E,0x79,0x20,0x2D,0x2D,0x20, +/* 0x000072F0: */ 0x2C,0x20,0x73,0x74,0x65,0x70,0x20,0x6F,0x76,0x65,0x72,0x20,0x6D,0x61,0x6E,0x79, +/* 0x00007300: */ 0x20,0x74,0x69,0x6D,0x65,0x73,0x20,0x29,0x28,0x00,0x00,0x00,0x80,0x0F,0x00,0x00, +/* 0x00007310: */ 0x1B,0x20,0x20,0x53,0x44,0x20,0x20,0x20,0x20,0x20,0x28,0x20,0x2D,0x2D,0x20,0x2C, +/* 0x00007320: */ 0x20,0x73,0x74,0x65,0x70,0x20,0x64,0x6F,0x77,0x6E,0x20,0x29,0x28,0x00,0x00,0x00, +/* 0x00007330: */ 0x80,0x0F,0x00,0x00,0x23,0x20,0x20,0x47,0x20,0x20,0x20,0x20,0x20,0x20,0x28,0x20, +/* 0x00007340: */ 0x2D,0x2D,0x20,0x2C,0x20,0x67,0x6F,0x20,0x74,0x6F,0x20,0x65,0x6E,0x64,0x20,0x6F, +/* 0x00007350: */ 0x66,0x20,0x77,0x6F,0x72,0x64,0x20,0x29,0x28,0x00,0x00,0x00,0x80,0x0F,0x00,0x00, +/* 0x00007360: */ 0x36,0x20,0x20,0x47,0x44,0x20,0x20,0x20,0x20,0x20,0x28,0x20,0x6E,0x20,0x2D,0x2D, +/* 0x00007370: */ 0x20,0x2C,0x20,0x67,0x6F,0x20,0x64,0x6F,0x77,0x6E,0x20,0x4E,0x20,0x6C,0x65,0x76, +/* 0x00007380: */ 0x65,0x6C,0x73,0x20,0x66,0x72,0x6F,0x6D,0x20,0x63,0x75,0x72,0x72,0x65,0x6E,0x74, +/* 0x00007390: */ 0x20,0x6C,0x65,0x76,0x65,0x6C,0x2C,0x5A,0x28,0x00,0x00,0x00,0x80,0x0F,0x00,0x00, +/* 0x000073A0: */ 0x2D,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, +/* 0x000073B0: */ 0x20,0x20,0x20,0x73,0x74,0x6F,0x70,0x20,0x61,0x74,0x20,0x65,0x6E,0x64,0x20,0x6F, +/* 0x000073C0: */ 0x66,0x20,0x74,0x68,0x69,0x73,0x20,0x6C,0x65,0x76,0x65,0x6C,0x20,0x29,0x5A,0x5A, +/* 0x000073D0: */ 0x28,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x2A,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000073E0: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x2A,0x00,0x00,0x00,0x78,0x07,0x00,0x00, +/* 0x000073F0: */ 0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x2A,0x00,0x00,0x00,0x78,0x07,0x00,0x00, +/* 0x00007400: */ 0x00,0x00,0x00,0x00,0x7F,0x00,0x00,0x00,0x2A,0x00,0x00,0x00,0x78,0x07,0x00,0x00, +/* 0x00007410: */ 0x00,0x00,0x00,0x00,0x1B,0x00,0x00,0x00,0x2A,0x00,0x00,0x00,0x78,0x07,0x00,0x00, +/* 0x00007420: */ 0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x2A,0x00,0x00,0x00,0x78,0x07,0x00,0x00, +/* 0x00007430: */ 0x00,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x2A,0x00,0x00,0x00,0x78,0x07,0x00,0x00, +/* 0x00007440: */ 0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x08,0x74,0x00,0x00,0xD4,0x00,0x00,0x00, +/* 0x00007450: */ 0x59,0x00,0x00,0x00,0x5B,0x00,0x00,0x00,0xD4,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007460: */ 0x48,0x74,0x00,0x00,0x80,0x0F,0x00,0x00,0x02,0x32,0x4A,0x5A,0x00,0x00,0x00,0x00, +/* 0x00007470: */ 0x48,0x74,0x00,0x00,0xA5,0x00,0x00,0x00,0x41,0x00,0x00,0x00,0xA2,0x00,0x00,0x00, +/* 0x00007480: */ 0xA8,0x02,0x00,0x00,0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xB4,0x1D,0x00,0x00, +/* 0x00007490: */ 0x8E,0x00,0x00,0x00,0xA5,0x00,0x00,0x00,0x9B,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x000074A0: */ 0x44,0x00,0x00,0x00,0xD4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x74,0x00,0x00, +/* 0x000074B0: */ 0xA5,0x00,0x00,0x00,0x41,0x00,0x00,0x00,0xA2,0x00,0x00,0x00,0xA8,0x02,0x00,0x00, +/* 0x000074C0: */ 0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xB4,0x1D,0x00,0x00,0x8E,0x00,0x00,0x00, +/* 0x000074D0: */ 0xA5,0x00,0x00,0x00,0x9B,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x43,0x00,0x00,0x00, +/* 0x000074E0: */ 0xD4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x74,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x000074F0: */ 0x4B,0x00,0x00,0x00,0xD4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00007500: */ 0x07,0x00,0x00,0x00,0xD4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00007510: */ 0x08,0x00,0x00,0x00,0xD4,0x00,0x00,0x00,0x8C,0x0C,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00007520: */ 0x08,0x00,0x00,0x00,0xD4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x2A,0x00,0x00,0x00, +/* 0x00007530: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x2A,0x00,0x00,0x00, +/* 0x00007540: */ 0x78,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x2A,0x00,0x00,0x00, +/* 0x00007550: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007560: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007570: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007580: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007590: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000075A0: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000075B0: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000075C0: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000075D0: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000075E0: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000075F0: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007600: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007610: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007620: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007630: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007640: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007650: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007660: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007670: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007680: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007690: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000076A0: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000076B0: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000076C0: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000076D0: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000076E0: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000076F0: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007700: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007710: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007720: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007730: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007740: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007750: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007760: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007770: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007780: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007790: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000077A0: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000077B0: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000077C0: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000077D0: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000077E0: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000077F0: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007800: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007810: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007820: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007830: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007840: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007850: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007860: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007870: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007880: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007890: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000078A0: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000078B0: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000078C0: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000078D0: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000078E0: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000078F0: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007900: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007910: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007920: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007930: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007940: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007950: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007960: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007970: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007980: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007990: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000079A0: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000079B0: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000079C0: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000079D0: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000079E0: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000079F0: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007A00: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007A10: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007A20: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007A30: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007A40: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007A50: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007A60: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007A70: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007A80: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007A90: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007AA0: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007AB0: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007AC0: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007AD0: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007AE0: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007AF0: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007B00: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007B10: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007B20: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007B30: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007B40: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007B50: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007B60: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007B70: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007B80: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007B90: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007BA0: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007BB0: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007BC0: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007BD0: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007BE0: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007BF0: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007C00: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007C10: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007C20: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007C30: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007C40: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007C50: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007C60: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007C70: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007C80: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007C90: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007CA0: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007CB0: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007CC0: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007CD0: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007CE0: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007CF0: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007D00: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007D10: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007D20: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007D30: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007D40: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007D50: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x2A,0x00,0x00,0x00,0x78,0x07,0x00,0x00, +/* 0x00007D60: */ 0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x4C,0x75,0x00,0x00,0x3C,0x75,0x00,0x00, +/* 0x00007D70: */ 0x7D,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x35,0x00,0x00,0x00,0x18,0x00,0x00,0x00, +/* 0x00007D80: */ 0x59,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x6C,0x38,0x00,0x00,0x9C,0x00,0x00,0x00, +/* 0x00007D90: */ 0x02,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x7A,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007DA0: */ 0x7B,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0xF8,0xFF,0xFF,0xFF,0x6C,0x38,0x00,0x00, +/* 0x00007DB0: */ 0x7B,0x00,0x00,0x00,0x2B,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x2B,0x00,0x00,0x00, +/* 0x00007DC0: */ 0x00,0x00,0x00,0x00,0x2A,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007DD0: */ 0x00,0x00,0x00,0x00,0x2A,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007DE0: */ 0x00,0x00,0x00,0x00,0x2A,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007DF0: */ 0x00,0x00,0x00,0x00,0x2A,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007E00: */ 0x00,0x00,0x00,0x00,0x2A,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007E10: */ 0x00,0x00,0x00,0x00,0x2A,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007E20: */ 0x00,0x00,0x00,0x00,0x2A,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007E30: */ 0x00,0x00,0x00,0x00,0x2A,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007E40: */ 0x00,0x00,0x00,0x00,0xA2,0x00,0x00,0x00,0x4C,0x75,0x00,0x00,0x35,0x00,0x00,0x00, +/* 0x00007E50: */ 0x8D,0x00,0x00,0x00,0x7D,0x00,0x00,0x00,0x3C,0x75,0x00,0x00,0x8E,0x00,0x00,0x00, +/* 0x00007E60: */ 0x75,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x73,0x00,0x00,0x00, +/* 0x00007E70: */ 0xF4,0x3A,0x00,0x00,0x00,0x00,0x00,0x00,0x4C,0x75,0x00,0x00,0x70,0x01,0x00,0x00, +/* 0x00007E80: */ 0x00,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC4,0x7D,0x00,0x00, +/* 0x00007E90: */ 0x9B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC4,0x7D,0x00,0x00,0x41,0x00,0x00,0x00, +/* 0x00007EA0: */ 0x4C,0x75,0x00,0x00,0x7D,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x98,0x7E,0x00,0x00, +/* 0x00007EB0: */ 0x70,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x78,0x7E,0x00,0x00,0x1D,0x00,0x00,0x00, +/* 0x00007EC0: */ 0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xAC,0x7E,0x00,0x00,0x7D,0x00,0x00,0x00, +/* 0x00007ED0: */ 0x00,0x00,0x00,0x00,0xC8,0x7E,0x00,0x00,0x78,0x7D,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00007EE0: */ 0x70,0x01,0x00,0x00,0x7D,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x03,0x00,0x00,0x00, +/* 0x00007EF0: */ 0x7D,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x35,0x00,0x00,0x00,0x01,0x00,0x00,0x00, +/* 0x00007F00: */ 0x18,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x7D,0x00,0x00,0x00, +/* 0x00007F10: */ 0x75,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC8,0x7E,0x00,0x00,0x08,0x00,0x00,0x00, +/* 0x00007F20: */ 0x00,0x00,0x00,0x00,0x35,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x00,0x01,0x00,0x00, +/* 0x00007F30: */ 0x1F,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x38,0x00,0x00,0x00,0x80,0x0F,0x00,0x00, +/* 0x00007F40: */ 0x22,0x4B,0x48,0x2E,0x41,0x44,0x44,0x2E,0x4C,0x49,0x4E,0x45,0x20,0x2D,0x20,0x54, +/* 0x00007F50: */ 0x6F,0x6F,0x20,0x62,0x69,0x67,0x20,0x66,0x6F,0x72,0x20,0x68,0x69,0x73,0x74,0x6F, +/* 0x00007F60: */ 0x72,0x79,0x21,0x5A,0x0C,0x02,0x00,0x00,0x15,0x00,0x00,0x00,0x9C,0x00,0x00,0x00, +/* 0x00007F70: */ 0x03,0x00,0x00,0x00,0xB8,0x7E,0x00,0x00,0xBC,0x00,0x00,0x00,0x10,0x00,0x00,0x00, +/* 0x00007F80: */ 0x0C,0x02,0x00,0x00,0x15,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0xA2,0x00,0x00,0x00, +/* 0x00007F90: */ 0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC4,0x7D,0x00,0x00,0x9B,0x00,0x00,0x00, +/* 0x00007FA0: */ 0x8D,0x00,0x00,0x00,0x58,0x7D,0x00,0x00,0x7D,0x00,0x00,0x00,0x44,0x7E,0x00,0x00, +/* 0x00007FB0: */ 0x8D,0x00,0x00,0x00,0x4C,0x75,0x00,0x00,0x2B,0x00,0x00,0x00,0x8D,0x00,0x00,0x00, +/* 0x00007FC0: */ 0x18,0x7F,0x00,0x00,0x2B,0x00,0x00,0x00,0xE4,0x7D,0x00,0x00,0x41,0x00,0x00,0x00, +/* 0x00007FD0: */ 0xC8,0x7E,0x00,0x00,0xA0,0x7D,0x00,0x00,0xE4,0x7D,0x00,0x00,0x41,0x00,0x00,0x00, +/* 0x00007FE0: */ 0x02,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0xFF,0x03,0x00,0x00,0x11,0x00,0x00,0x00, +/* 0x00007FF0: */ 0xE4,0x7D,0x00,0x00,0x9B,0x00,0x00,0x00,0x4C,0x75,0x00,0x00,0x02,0x00,0x00,0x00, +/* 0x00008000: */ 0x8E,0x00,0x00,0x00,0x19,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xA4,0x08,0x00,0x00, +/* 0x00008010: */ 0xA4,0x08,0x00,0x00,0x59,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x5C,0x00,0x00,0x00, +/* 0x00008020: */ 0xB4,0x08,0x00,0x00,0x69,0x00,0x00,0x00,0x98,0x7E,0x00,0x00,0x18,0x00,0x00,0x00, +/* 0x00008030: */ 0xBC,0x00,0x00,0x00,0x50,0x00,0x00,0x00,0x98,0x7E,0x00,0x00,0xE0,0x7E,0x00,0x00, +/* 0x00008040: */ 0x6A,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x68,0x7D,0x00,0x00,0x23,0x00,0x00,0x00, +/* 0x00008050: */ 0xBC,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x18,0x00,0x00,0x00, +/* 0x00008060: */ 0xBC,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x4C,0x75,0x00,0x00, +/* 0x00008070: */ 0x75,0x00,0x00,0x00,0xC4,0x7D,0x00,0x00,0x9B,0x00,0x00,0x00,0xA4,0x08,0x00,0x00, +/* 0x00008080: */ 0x69,0x00,0x00,0x00,0x5F,0x00,0x00,0x00,0x5D,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00008090: */ 0xC4,0x7D,0x00,0x00,0x41,0x00,0x00,0x00,0x24,0x00,0x00,0x00,0x35,0x00,0x00,0x00, +/* 0x000080A0: */ 0x58,0x02,0x00,0x00,0xBC,0x00,0x00,0x00,0x1C,0x00,0x00,0x00,0x98,0x7E,0x00,0x00, +/* 0x000080B0: */ 0xF8,0x7E,0x00,0x00,0x4C,0x75,0x00,0x00,0x75,0x00,0x00,0x00,0xC4,0x7D,0x00,0x00, +/* 0x000080C0: */ 0x9B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0C,0x80,0x00,0x00,0xBC,0x00,0x00,0x00, +/* 0x000080D0: */ 0xF8,0xFF,0xFF,0xFF,0xAC,0x7E,0x00,0x00,0x35,0x00,0x00,0x00,0x24,0x00,0x00,0x00, +/* 0x000080E0: */ 0xBC,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x18,0x02,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000080F0: */ 0x84,0x7E,0x00,0x00,0xD4,0x7E,0x00,0x00,0x7B,0x00,0x00,0x00,0x75,0x00,0x00,0x00, +/* 0x00008100: */ 0xBC,0x00,0x00,0x00,0x4C,0x00,0x00,0x00,0x0C,0x80,0x00,0x00,0xBC,0x00,0x00,0x00, +/* 0x00008110: */ 0x38,0x00,0x00,0x00,0x80,0x0F,0x00,0x00,0x1B,0x4C,0x69,0x6E,0x65,0x20,0x6E,0x6F, +/* 0x00008120: */ 0x74,0x20,0x69,0x6E,0x20,0x48,0x69,0x73,0x74,0x6F,0x72,0x79,0x20,0x42,0x75,0x66, +/* 0x00008130: */ 0x66,0x65,0x72,0x21,0x28,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00008140: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0xA8,0xFF,0xFF,0xFF, +/* 0x00008150: */ 0x33,0x00,0x00,0x00,0x98,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x24,0x7E,0x00,0x00, +/* 0x00008160: */ 0x41,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00008170: */ 0xAF,0x00,0x00,0x00,0x9B,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x0D,0x00,0x00,0x00, +/* 0x00008180: */ 0xD4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x68,0x81,0x00,0x00,0xE8,0x74,0x00,0x00, +/* 0x00008190: */ 0x35,0x00,0x00,0x00,0xF4,0x7D,0x00,0x00,0x9B,0x00,0x00,0x00,0x35,0x00,0x00,0x00, +/* 0x000081A0: */ 0x14,0x7E,0x00,0x00,0x9B,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x5C,0x81,0x00,0x00, +/* 0x000081B0: */ 0x9C,0x00,0x00,0x00,0x19,0x00,0x00,0x00,0xA3,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000081C0: */ 0x04,0x7E,0x00,0x00,0x41,0x00,0x00,0x00,0x24,0x00,0x00,0x00,0xBC,0x00,0x00,0x00, +/* 0x000081D0: */ 0x14,0x00,0x00,0x00,0xF4,0x7D,0x00,0x00,0x41,0x00,0x00,0x00,0x04,0x7E,0x00,0x00, +/* 0x000081E0: */ 0x9B,0x00,0x00,0x00,0x0C,0x80,0x00,0x00,0x58,0x02,0x00,0x00,0xBC,0x00,0x00,0x00, +/* 0x000081F0: */ 0x38,0x00,0x00,0x00,0xAC,0x7E,0x00,0x00,0x33,0x00,0x00,0x00,0x5C,0x81,0x00,0x00, +/* 0x00008200: */ 0x04,0x7E,0x00,0x00,0x41,0x00,0x00,0x00,0x98,0x25,0x00,0x00,0xBC,0x00,0x00,0x00, +/* 0x00008210: */ 0x10,0x00,0x00,0x00,0xAC,0x7E,0x00,0x00,0x88,0x81,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00008220: */ 0x15,0x00,0x00,0x00,0xC0,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0xF4,0x7D,0x00,0x00, +/* 0x00008230: */ 0x41,0x00,0x00,0x00,0x14,0x7E,0x00,0x00,0x41,0x00,0x00,0x00,0x75,0x00,0x00,0x00, +/* 0x00008240: */ 0x35,0x00,0x00,0x00,0x25,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x20,0x00,0x00,0x00, +/* 0x00008250: */ 0xAC,0x74,0x00,0x00,0xF4,0x7D,0x00,0x00,0x41,0x00,0x00,0x00,0x14,0x7E,0x00,0x00, +/* 0x00008260: */ 0x9B,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x33,0x00,0x00,0x00, +/* 0x00008270: */ 0x00,0x00,0x00,0x00,0x68,0x81,0x00,0x00,0x14,0x7E,0x00,0x00,0x98,0x01,0x00,0x00, +/* 0x00008280: */ 0x00,0x00,0x00,0x00,0x34,0x7E,0x00,0x00,0x41,0x00,0x00,0x00,0xBC,0x00,0x00,0x00, +/* 0x00008290: */ 0x0C,0x00,0x00,0x00,0x0C,0x80,0x00,0x00,0x33,0x00,0x00,0x00,0xAC,0x7E,0x00,0x00, +/* 0x000082A0: */ 0x88,0x81,0x00,0x00,0x34,0x7E,0x00,0x00,0x84,0x01,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000082B0: */ 0x90,0x80,0x00,0x00,0xBC,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x34,0x7E,0x00,0x00, +/* 0x000082C0: */ 0x98,0x01,0x00,0x00,0xA8,0x3B,0x00,0x00,0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000082D0: */ 0x15,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0xAC,0x7E,0x00,0x00,0x88,0x81,0x00,0x00, +/* 0x000082E0: */ 0x00,0x00,0x00,0x00,0x84,0x7E,0x00,0x00,0xA8,0x3B,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x000082F0: */ 0x00,0x00,0x00,0x00,0x88,0x81,0x00,0x00,0x34,0x7E,0x00,0x00,0x98,0x01,0x00,0x00, +/* 0x00008300: */ 0x00,0x00,0x00,0x00,0x14,0x7E,0x00,0x00,0x41,0x00,0x00,0x00,0xF4,0x7D,0x00,0x00, +/* 0x00008310: */ 0x41,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x20,0x00,0x00,0x00, +/* 0x00008320: */ 0x59,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x14,0x7E,0x00,0x00,0x7F,0x00,0x00,0x00, +/* 0x00008330: */ 0x59,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0xAC,0x74,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00008340: */ 0x14,0x7E,0x00,0x00,0x41,0x00,0x00,0x00,0x81,0x00,0x00,0x00,0xBC,0x00,0x00,0x00, +/* 0x00008350: */ 0x1C,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x14,0x7E,0x00,0x00,0x9B,0x00,0x00,0x00, +/* 0x00008360: */ 0x59,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x70,0x74,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00008370: */ 0x68,0x81,0x00,0x00,0x5C,0x81,0x00,0x00,0xF4,0x7D,0x00,0x00,0x41,0x00,0x00,0x00, +/* 0x00008380: */ 0xA3,0x00,0x00,0x00,0xE8,0x74,0x00,0x00,0x68,0x81,0x00,0x00,0x14,0x7E,0x00,0x00, +/* 0x00008390: */ 0x41,0x00,0x00,0x00,0x81,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x08,0x00,0x00,0x00, +/* 0x000083A0: */ 0xAC,0x74,0x00,0x00,0xF4,0x7D,0x00,0x00,0x41,0x00,0x00,0x00,0xAF,0x00,0x00,0x00, +/* 0x000083B0: */ 0x9B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x7E,0x00,0x00,0x41,0x00,0x00,0x00, +/* 0x000083C0: */ 0x81,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x74,0x00,0x00,0x00,0xF4,0x7D,0x00,0x00, +/* 0x000083D0: */ 0x41,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x3C,0x00,0x00,0x00, +/* 0x000083E0: */ 0x5C,0x81,0x00,0x00,0x14,0x7E,0x00,0x00,0x41,0x00,0x00,0x00,0x7D,0x00,0x00,0x00, +/* 0x000083F0: */ 0x35,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0xF4,0x7D,0x00,0x00,0x41,0x00,0x00,0x00, +/* 0x00008400: */ 0x14,0x7E,0x00,0x00,0x41,0x00,0x00,0x00,0x75,0x00,0x00,0x00,0x19,0x00,0x00,0x00, +/* 0x00008410: */ 0x15,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x0C,0x75,0x00,0x00,0x80,0x07,0x00,0x00, +/* 0x00008420: */ 0xF4,0x7D,0x00,0x00,0x7F,0x00,0x00,0x00,0x80,0x07,0x00,0x00,0x14,0x7E,0x00,0x00, +/* 0x00008430: */ 0x7F,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0xFC,0x74,0x00,0x00, +/* 0x00008440: */ 0x70,0x83,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x7E,0x00,0x00,0x41,0x00,0x00,0x00, +/* 0x00008450: */ 0xF4,0x7D,0x00,0x00,0x41,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0xBC,0x00,0x00,0x00, +/* 0x00008460: */ 0x54,0x00,0x00,0x00,0x5C,0x81,0x00,0x00,0x14,0x7E,0x00,0x00,0x41,0x00,0x00,0x00, +/* 0x00008470: */ 0x7D,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x35,0x00,0x00,0x00,0x01,0x00,0x00,0x00, +/* 0x00008480: */ 0xF4,0x7D,0x00,0x00,0x41,0x00,0x00,0x00,0x14,0x7E,0x00,0x00,0x41,0x00,0x00,0x00, +/* 0x00008490: */ 0x75,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x73,0x00,0x00,0x00, +/* 0x000084A0: */ 0x19,0x00,0x00,0x00,0x80,0x07,0x00,0x00,0xF4,0x7D,0x00,0x00,0x7F,0x00,0x00,0x00, +/* 0x000084B0: */ 0x70,0x83,0x00,0x00,0x00,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x8D,0x00,0x00,0x00, +/* 0x000084C0: */ 0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x14,0x00,0x00,0x00, +/* 0x000084D0: */ 0x33,0x00,0x00,0x00,0xC0,0x81,0x00,0x00,0x15,0x00,0x00,0x00,0x58,0x01,0x00,0x00, +/* 0x000084E0: */ 0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x7E,0x00,0x00,0x9B,0x00,0x00,0x00, +/* 0x000084F0: */ 0x59,0x00,0x00,0x00,0x48,0x00,0x00,0x00,0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00, +/* 0x00008500: */ 0xBC,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x84,0x82,0x00,0x00, +/* 0x00008510: */ 0x15,0x00,0x00,0x00,0x20,0x01,0x00,0x00,0x59,0x00,0x00,0x00,0x50,0x00,0x00,0x00, +/* 0x00008520: */ 0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x14,0x00,0x00,0x00, +/* 0x00008530: */ 0x33,0x00,0x00,0x00,0xB0,0x82,0x00,0x00,0x15,0x00,0x00,0x00,0xF8,0x00,0x00,0x00, +/* 0x00008540: */ 0x59,0x00,0x00,0x00,0x4D,0x00,0x00,0x00,0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00, +/* 0x00008550: */ 0xBC,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x04,0x83,0x00,0x00, +/* 0x00008560: */ 0x15,0x00,0x00,0x00,0xD0,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x4B,0x00,0x00,0x00, +/* 0x00008570: */ 0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x14,0x00,0x00,0x00, +/* 0x00008580: */ 0x33,0x00,0x00,0x00,0x40,0x83,0x00,0x00,0x15,0x00,0x00,0x00,0xA8,0x00,0x00,0x00, +/* 0x00008590: */ 0x59,0x00,0x00,0x00,0x91,0x00,0x00,0x00,0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00, +/* 0x000085A0: */ 0xBC,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0xE4,0x82,0x00,0x00, +/* 0x000085B0: */ 0x15,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x74,0x00,0x00,0x00, +/* 0x000085C0: */ 0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x14,0x00,0x00,0x00, +/* 0x000085D0: */ 0x33,0x00,0x00,0x00,0x2C,0x82,0x00,0x00,0x15,0x00,0x00,0x00,0x58,0x00,0x00,0x00, +/* 0x000085E0: */ 0x59,0x00,0x00,0x00,0x73,0x00,0x00,0x00,0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00, +/* 0x000085F0: */ 0xBC,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x74,0x82,0x00,0x00, +/* 0x00008600: */ 0x15,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x53,0x00,0x00,0x00, +/* 0x00008610: */ 0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x14,0x00,0x00,0x00, +/* 0x00008620: */ 0x33,0x00,0x00,0x00,0x48,0x84,0x00,0x00,0x15,0x00,0x00,0x00,0x08,0x00,0x00,0x00, +/* 0x00008630: */ 0x33,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x41,0x00,0x00,0x00, +/* 0x00008640: */ 0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x14,0x00,0x00,0x00, +/* 0x00008650: */ 0x33,0x00,0x00,0x00,0x84,0x82,0x00,0x00,0x15,0x00,0x00,0x00,0x80,0x00,0x00,0x00, +/* 0x00008660: */ 0x59,0x00,0x00,0x00,0x42,0x00,0x00,0x00,0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00, +/* 0x00008670: */ 0xBC,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0xB0,0x82,0x00,0x00, +/* 0x00008680: */ 0x15,0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x43,0x00,0x00,0x00, +/* 0x00008690: */ 0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x14,0x00,0x00,0x00, +/* 0x000086A0: */ 0x33,0x00,0x00,0x00,0x04,0x83,0x00,0x00,0x15,0x00,0x00,0x00,0x30,0x00,0x00,0x00, +/* 0x000086B0: */ 0x59,0x00,0x00,0x00,0x44,0x00,0x00,0x00,0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00, +/* 0x000086C0: */ 0xBC,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x40,0x83,0x00,0x00, +/* 0x000086D0: */ 0x15,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000086E0: */ 0xB4,0x08,0x00,0x00,0xA2,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0xE0,0x00,0x00,0x00, +/* 0x000086F0: */ 0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x18,0x00,0x00,0x00, +/* 0x00008700: */ 0x33,0x00,0x00,0x00,0x56,0x00,0x00,0x00,0xB8,0x84,0x00,0x00,0x15,0x00,0x00,0x00, +/* 0x00008710: */ 0x30,0x01,0x00,0x00,0x08,0x74,0x00,0x00,0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00, +/* 0x00008720: */ 0xBC,0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x56,0x00,0x00,0x00, +/* 0x00008730: */ 0x35,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x4F,0x00,0x00,0x00,0x1E,0x00,0x00,0x00, +/* 0x00008740: */ 0x59,0x00,0x00,0x00,0x5B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0x7A,0x00,0x00,0x00, +/* 0x00008750: */ 0xBC,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x56,0x00,0x00,0x00,0x38,0x86,0x00,0x00, +/* 0x00008760: */ 0x15,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x8C,0x00,0x00,0x00,0xA4,0x08,0x00,0x00, +/* 0x00008770: */ 0xA2,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0xC8,0x00,0x00,0x00,0xE8,0x73,0x00,0x00, +/* 0x00008780: */ 0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x14,0x00,0x00,0x00, +/* 0x00008790: */ 0x33,0x00,0x00,0x00,0xB8,0x83,0x00,0x00,0x15,0x00,0x00,0x00,0xA4,0x00,0x00,0x00, +/* 0x000087A0: */ 0xF8,0x73,0x00,0x00,0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00, +/* 0x000087B0: */ 0x14,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0xB8,0x83,0x00,0x00,0x15,0x00,0x00,0x00, +/* 0x000087C0: */ 0x80,0x00,0x00,0x00,0x38,0x74,0x00,0x00,0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00, +/* 0x000087D0: */ 0xBC,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0xE4,0x82,0x00,0x00, +/* 0x000087E0: */ 0x15,0x00,0x00,0x00,0x5C,0x00,0x00,0x00,0x18,0x74,0x00,0x00,0x7B,0x00,0x00,0x00, +/* 0x000087F0: */ 0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x33,0x00,0x00,0x00, +/* 0x00008800: */ 0x74,0x82,0x00,0x00,0x15,0x00,0x00,0x00,0x38,0x00,0x00,0x00,0x28,0x74,0x00,0x00, +/* 0x00008810: */ 0x7B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x14,0x00,0x00,0x00, +/* 0x00008820: */ 0x33,0x00,0x00,0x00,0x2C,0x82,0x00,0x00,0x15,0x00,0x00,0x00,0x14,0x00,0x00,0x00, +/* 0x00008830: */ 0x8C,0x00,0x00,0x00,0xA4,0x08,0x00,0x00,0xA2,0x00,0x00,0x00,0x33,0x00,0x00,0x00, +/* 0x00008840: */ 0x8E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x56,0x00,0x00,0x00,0x35,0x00,0x00,0x00, +/* 0x00008850: */ 0xE0,0x86,0x00,0x00,0xBC,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x33,0x00,0x00,0x00, +/* 0x00008860: */ 0x15,0x00,0x00,0x00,0xE4,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0xA4,0x08,0x00,0x00, +/* 0x00008870: */ 0x59,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x5C,0x00,0x00,0x00,0xA4,0x08,0x00,0x00, +/* 0x00008880: */ 0x6A,0x00,0x00,0x00,0x14,0x7E,0x00,0x00,0x41,0x00,0x00,0x00,0xF4,0x7D,0x00,0x00, +/* 0x00008890: */ 0x41,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x3C,0x00,0x00,0x00, +/* 0x000088A0: */ 0x5C,0x81,0x00,0x00,0x14,0x7E,0x00,0x00,0x41,0x00,0x00,0x00,0x7D,0x00,0x00,0x00, +/* 0x000088B0: */ 0x35,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0xF4,0x7D,0x00,0x00,0x41,0x00,0x00,0x00, +/* 0x000088C0: */ 0x14,0x7E,0x00,0x00,0x41,0x00,0x00,0x00,0x75,0x00,0x00,0x00,0x1A,0x00,0x00,0x00, +/* 0x000088D0: */ 0xB4,0x08,0x00,0x00,0x6A,0x00,0x00,0x00,0x5F,0x00,0x00,0x00,0x5C,0x81,0x00,0x00, +/* 0x000088E0: */ 0x14,0x7E,0x00,0x00,0x41,0x00,0x00,0x00,0x7D,0x00,0x00,0x00,0x2B,0x00,0x00,0x00, +/* 0x000088F0: */ 0x59,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x14,0x7E,0x00,0x00,0x7F,0x00,0x00,0x00, +/* 0x00008900: */ 0x59,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0xF4,0x7D,0x00,0x00,0x7F,0x00,0x00,0x00, +/* 0x00008910: */ 0x60,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x70,0x83,0x00,0x00, +/* 0x00008920: */ 0x15,0x00,0x00,0x00,0x0C,0x00,0x00,0x00,0x5F,0x00,0x00,0x00,0xD4,0x00,0x00,0x00, +/* 0x00008930: */ 0x5D,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x35,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00008940: */ 0x0D,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0x9C,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00008950: */ 0x0A,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0x7A,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00008960: */ 0xD4,0x7D,0x00,0x00,0x9B,0x00,0x00,0x00,0xF4,0x7D,0x00,0x00,0x98,0x01,0x00,0x00, +/* 0x00008970: */ 0x14,0x7E,0x00,0x00,0x98,0x01,0x00,0x00,0x34,0x7E,0x00,0x00,0x98,0x01,0x00,0x00, +/* 0x00008980: */ 0x84,0x7E,0x00,0x00,0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x7E,0x00,0x00, +/* 0x00008990: */ 0x9B,0x00,0x00,0x00,0xD4,0x7D,0x00,0x00,0x41,0x00,0x00,0x00,0xF4,0x7D,0x00,0x00, +/* 0x000089A0: */ 0x41,0x00,0x00,0x00,0x1F,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x1C,0x00,0x00,0x00, +/* 0x000089B0: */ 0x48,0x88,0x00,0x00,0x35,0x00,0x00,0x00,0x38,0x89,0x00,0x00,0x58,0x02,0x00,0x00, +/* 0x000089C0: */ 0x15,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000089D0: */ 0xA4,0x08,0x00,0x00,0xBC,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x6C,0x88,0x00,0x00, +/* 0x000089E0: */ 0x15,0x00,0x00,0x00,0xB0,0xFF,0xFF,0xFF,0x33,0x00,0x00,0x00,0xF4,0x7D,0x00,0x00, +/* 0x000089F0: */ 0x41,0x00,0x00,0x00,0x14,0x7E,0x00,0x00,0x41,0x00,0x00,0x00,0x75,0x00,0x00,0x00, +/* 0x00008A00: */ 0x81,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0xAC,0x74,0x00,0x00, +/* 0x00008A10: */ 0x8C,0x0C,0x00,0x00,0x4F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x9C,0x00,0x00,0x00, +/* 0x00008A20: */ 0x24,0x7E,0x00,0x00,0x9B,0x00,0x00,0x00,0x60,0x89,0x00,0x00,0xF4,0x7D,0x00,0x00, +/* 0x00008A30: */ 0x41,0x00,0x00,0x00,0x25,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x14,0x00,0x00,0x00, +/* 0x00008A40: */ 0x5C,0x81,0x00,0x00,0xF4,0x7D,0x00,0x00,0x41,0x00,0x00,0x00,0x24,0x7F,0x00,0x00, +/* 0x00008A50: */ 0xF4,0x7D,0x00,0x00,0x41,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00008A60: */ 0x04,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x32,0x00,0x00,0x00, +/* 0x00008A70: */ 0xF8,0x02,0x00,0x00,0x59,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x1C,0x8A,0x00,0x00, +/* 0x00008A80: */ 0x28,0x00,0x00,0x00,0xF8,0x02,0x00,0x00,0x9C,0x00,0x00,0x00,0xA3,0x00,0x00,0x00, +/* 0x00008A90: */ 0x28,0x00,0x00,0x00,0x71,0x00,0x00,0x00,0xD8,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00, +/* 0x00008AA0: */ 0x28,0x00,0x00,0x00,0xC8,0x80,0x00,0x00,0x81,0x00,0x00,0x00,0xBC,0x00,0x00,0x00, +/* 0x00008AB0: */ 0x44,0x00,0x00,0x00,0xD4,0x7E,0x00,0x00,0x59,0x00,0x00,0x00,0x03,0x00,0x00,0x00, +/* 0x00008AC0: */ 0xB4,0x1D,0x00,0x00,0x80,0x0F,0x00,0x00,0x02,0x29,0x20,0x5A,0xA3,0x00,0x00,0x00, +/* 0x00008AD0: */ 0xA4,0x1E,0x00,0x00,0x28,0x00,0x00,0x00,0x90,0x80,0x00,0x00,0x24,0x00,0x00,0x00, +/* 0x00008AE0: */ 0xBC,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0xAC,0x7E,0x00,0x00,0x15,0x00,0x00,0x00, +/* 0x00008AF0: */ 0xC4,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x28,0x00,0x00,0x00,0xC8,0x80,0x00,0x00, +/* 0x00008B00: */ 0x81,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x2C,0x00,0x00,0x00,0xA3,0x00,0x00,0x00, +/* 0x00008B10: */ 0xA4,0x1E,0x00,0x00,0x28,0x00,0x00,0x00,0x90,0x80,0x00,0x00,0x24,0x00,0x00,0x00, +/* 0x00008B20: */ 0xBC,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0xAC,0x7E,0x00,0x00,0x15,0x00,0x00,0x00, +/* 0x00008B30: */ 0xDC,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0xF0,0x80,0x00,0x00,0x81,0x00,0x00,0x00, +/* 0x00008B40: */ 0xBC,0x00,0x00,0x00,0x0C,0x00,0x00,0x00,0x70,0x01,0x00,0x00,0x58,0x22,0x00,0x00, +/* 0x00008B50: */ 0x00,0x00,0x00,0x00,0x4C,0x75,0x00,0x00,0x3C,0x75,0x00,0x00,0x28,0x3B,0x00,0x00, +/* 0x00008B60: */ 0xE4,0x7D,0x00,0x00,0x98,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x54,0x8B,0x00,0x00, +/* 0x00008B70: */ 0x59,0x00,0x00,0x00,0xC8,0x00,0x00,0x00,0x90,0x0D,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00008B80: */ 0x0D,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x18,0x00,0x00,0x00, +/* 0x00008B90: */ 0x59,0x00,0x00,0x00,0x1C,0x8A,0x00,0x00,0x59,0x00,0x00,0x00,0xC8,0x00,0x00,0x00, +/* 0x00008BA0: */ 0x48,0x0D,0x00,0x00,0x00,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0xC8,0x00,0x00,0x00, +/* 0x00008BB0: */ 0x90,0x0D,0x00,0x00,0x59,0x00,0x00,0x00,0x1C,0x8A,0x00,0x00,0x1E,0x00,0x00,0x00, +/* 0x00008BC0: */ 0xBC,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x0D,0x00,0x00,0x00, +/* 0x00008BD0: */ 0x59,0x00,0x00,0x00,0xC8,0x00,0x00,0x00,0x48,0x0D,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00008BE0: */ 0xF0,0x14,0x00,0x00,0x6C,0x8B,0x00,0x00,0x00,0x00,0x00,0x00,0xA8,0x8B,0x00,0x00, +/* 0x00008BF0: */ 0xE0,0x8B,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x2F,0x00,0x00,0xA8,0x8B,0x00,0x00, +/* 0x00008C00: */ 0x2A,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00008C10: */ 0x2A,0x00,0x00,0x00,0x78,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00, +/* 0x00008C20: */ 0x2A,0x00,0x00,0x00,0x78,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00, +/* 0x00008C30: */ 0x2A,0x00,0x00,0x00,0x78,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00, +/* 0x00008C40: */ 0x2A,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x2C,0x30,0x78,0x30, +/* 0x00008C50: */ 0x30,0x2C,0x30,0x78,0x30,0x30,0x2C,0x30,0x78,0x30,0x30,0x2C,0x30,0x78,0x30,0x30, +/* 0x00008C60: */ 0x2C,0x30,0x78,0x30,0x31,0x2C,0x2C,0x30,0x78,0x32,0x43,0x2C,0x30,0x78,0x33,0x30, +/* 0x00008C70: */ 0x2C,0x30,0x78,0x37,0x38,0x2C,0x30,0x78,0x33,0x32,0x2C,0x30,0x78,0x34,0x33,0x2C, +/* 0x00008C80: */ 0x30,0x78,0x32,0x43,0x2C,0x30,0x78,0x33,0x30,0x2C,0x30,0x78,0x37,0x38,0x2C,0x30, +/* 0x00008C90: */ 0x78,0x33,0x33,0x2C,0x30,0x78,0x33,0x30,0x30,0x2C,0x30,0x78,0x33,0x30,0x2C,0x30, +/* 0x00008CA0: */ 0x78,0x32,0x43,0x2C,0x30,0x78,0x33,0x30,0x2C,0x30,0x78,0x37,0x38,0x2C,0x30,0x78, +/* 0x00008CB0: */ 0x33,0x33,0x2C,0x30,0x78,0x33,0x30,0x2C,0x30,0x78,0x32,0x43,0x2C,0x30,0x78,0x33, +/* 0x00008CC0: */ 0x30,0x2C,0x0A,0x2F,0x2A,0x20,0x30,0x78,0x30,0x30,0x33,0x30,0x2C,0x30,0x78,0x33, +/* 0x00008CD0: */ 0x33,0x2C,0x30,0x78,0x33,0x30,0x2C,0x30,0x78,0x32,0x43,0x2C,0x30,0x78,0x33,0x30, +/* 0x00008CE0: */ 0x2C,0x30,0x78,0x37,0x38,0x2C,0x30,0x78,0x33,0x33,0x2C,0x0A,0x2F,0x2A,0x20,0x30, +/* 0x00008CF0: */ 0x78,0x30,0x30,0x30,0x30,0x38,0x43,0x44,0x30,0x3A,0x20,0x2A,0x78,0x32,0x41,0x2C, +/* 0x00008D00: */ 0x30,0x78,0x37,0x38,0x2C,0x30,0x78,0x33,0x32,0x2C,0x30,0x78,0x34,0x31,0x2C,0x30, +/* 0x00008D10: */ 0x78,0x32,0x43,0x2C,0x0A,0x2F,0x2A,0x20,0x30,0x78,0x30,0x30,0x30,0x30,0x38,0x44, +/* 0x00008D20: */ 0x30,0x30,0x3A,0x20,0x2A,0x2F,0x20,0x30,0x78,0x33,0x30,0x2C,0x30,0x2C,0x30,0x78, +/* 0x00008D30: */ 0x32,0x43,0x2C,0x30,0x78,0x33,0x30,0x2C,0x30,0x78,0x37,0x38,0x2C,0x0A,0x2F,0x2A, +/* 0x00008D40: */ 0x20,0x30,0x78,0x30,0x30,0x30,0x30,0x38,0x44,0x33,0x30,0x3A,0x2A,0x00,0x00,0x00, +/* 0x00008D50: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF2,0x00,0x00,0x00,0x2A,0x00,0x00,0x00, +/* 0x00008D60: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0x77,0xA7,0x08,0x40,0x8C,0x00,0x00, +/* 0x00008D70: */ 0x4C,0x8D,0x00,0x00,0x41,0x00,0x00,0x00,0x5C,0x8D,0x00,0x00,0x41,0x00,0x00,0x00, +/* 0x00008D80: */ 0x4B,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x4C,0x8D,0x00,0x00, +/* 0x00008D90: */ 0x9B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x4C,0x8D,0x00,0x00,0x41,0x00,0x00,0x00, +/* 0x00008DA0: */ 0x30,0x8C,0x00,0x00,0x3C,0x02,0x00,0x00,0xBC,0x00,0x00,0x00,0x24,0x00,0x00,0x00, +/* 0x00008DB0: */ 0x6C,0x8D,0x00,0x00,0x48,0x0F,0x00,0x00,0x12,0x53,0x44,0x41,0x44,0x2E,0x46,0x4C, +/* 0x00008DC0: */ 0x55,0x53,0x48,0x20,0x66,0x61,0x69,0x6C,0x65,0x64,0x21,0x5A,0x48,0x1E,0x00,0x00, +/* 0x00008DD0: */ 0x40,0x8C,0x00,0x00,0x4C,0x8D,0x00,0x00,0x41,0x00,0x00,0x00,0x7D,0x00,0x00,0x00, +/* 0x00008DE0: */ 0x2B,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x4C,0x8D,0x00,0x00, +/* 0x00008DF0: */ 0x7F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00008E00: */ 0x32,0x00,0x00,0x00,0x35,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x98,0x8D,0x00,0x00, +/* 0x00008E10: */ 0x02,0x00,0x00,0x00,0x71,0x00,0x00,0x00,0xEC,0xFF,0xFF,0xFF,0x33,0x00,0x00,0x00, +/* 0x00008E20: */ 0x00,0x00,0x00,0x00,0x70,0x01,0x00,0x00,0xF8,0x8D,0x00,0x00,0x3E,0x00,0x00,0x00, +/* 0x00008E30: */ 0x98,0x8D,0x00,0x00,0x00,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00008E40: */ 0x00,0x1C,0x00,0x00,0x48,0x1C,0x00,0x00,0x48,0x1C,0x00,0x00,0x48,0x1C,0x00,0x00, +/* 0x00008E50: */ 0x48,0x1C,0x00,0x00,0x48,0x1C,0x00,0x00,0x48,0x1C,0x00,0x00,0x48,0x1C,0x00,0x00, +/* 0x00008E60: */ 0x90,0x1C,0x00,0x00,0x10,0x1C,0x00,0x00,0x00,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00008E70: */ 0x00,0x00,0x00,0x00,0x00,0x1C,0x00,0x00,0x48,0x1C,0x00,0x00,0x90,0x1C,0x00,0x00, +/* 0x00008E80: */ 0x10,0x1C,0x00,0x00,0x00,0x00,0x00,0x00,0x5C,0x8D,0x00,0x00,0x41,0x00,0x00,0x00, +/* 0x00008E90: */ 0x81,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x3C,0x00,0x00,0x00,0x6C,0x8D,0x00,0x00, +/* 0x00008EA0: */ 0x48,0x0F,0x00,0x00,0x12,0x53,0x44,0x41,0x44,0x2E,0x46,0x4C,0x55,0x53,0x48,0x20, +/* 0x00008EB0: */ 0x66,0x61,0x69,0x6C,0x65,0x64,0x21,0x5A,0x48,0x1E,0x00,0x00,0x42,0x00,0x00,0x00, +/* 0x00008EC0: */ 0x33,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x5C,0x8D,0x00,0x00, +/* 0x00008ED0: */ 0x9B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x88,0x8E,0x00,0x00,0x64,0x0F,0x00,0x00, +/* 0x00008EE0: */ 0x0A,0x70,0x66,0x64,0x69,0x63,0x64,0x61,0x74,0x2E,0x68,0x5A,0x49,0x00,0x00,0x00, +/* 0x00008EF0: */ 0x43,0x00,0x00,0x00,0x35,0x00,0x00,0x00,0xA2,0x00,0x00,0x00,0xBC,0x00,0x00,0x00, +/* 0x00008F00: */ 0x3C,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x80,0x0F,0x00,0x00,0x20,0x43,0x6F,0x75, +/* 0x00008F10: */ 0x6C,0x64,0x20,0x6E,0x6F,0x74,0x20,0x63,0x72,0x65,0x61,0x74,0x65,0x20,0x66,0x69, +/* 0x00008F20: */ 0x6C,0x65,0x20,0x70,0x66,0x64,0x69,0x63,0x64,0x61,0x74,0x2E,0x68,0x5A,0x5A,0x5A, +/* 0x00008F30: */ 0x28,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0x0C,0x00,0x00,0x00,0x5C,0x8D,0x00,0x00, +/* 0x00008F40: */ 0x9B,0x00,0x00,0x00,0x8E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x00008F50: */ 0x01,0x00,0x00,0x00,0x5C,0x00,0x00,0x00,0xA5,0x00,0x00,0x00,0x41,0x00,0x00,0x00, +/* 0x00008F60: */ 0xA2,0x00,0x00,0x00,0xD0,0x02,0x00,0x00,0x64,0x0F,0x00,0x00,0x02,0x30,0x78,0x5A, +/* 0x00008F70: */ 0xF8,0x8D,0x00,0x00,0x5F,0x00,0x00,0x00,0x38,0x8E,0x00,0x00,0xF8,0x8D,0x00,0x00, +/* 0x00008F80: */ 0x8E,0x00,0x00,0x00,0xA5,0x00,0x00,0x00,0x9B,0x00,0x00,0x00,0x5D,0x00,0x00,0x00, +/* 0x00008F90: */ 0x00,0x00,0x00,0x00,0x64,0x0F,0x00,0x00,0x03,0x20,0x20,0x20,0xF8,0x8D,0x00,0x00, +/* 0x00008FA0: */ 0x4C,0x8F,0x00,0x00,0x59,0x00,0x00,0x00,0x2C,0x00,0x00,0x00,0x98,0x8D,0x00,0x00, +/* 0x00008FB0: */ 0x00,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x5C,0x00,0x00,0x00, +/* 0x00008FC0: */ 0xA5,0x00,0x00,0x00,0x41,0x00,0x00,0x00,0xA2,0x00,0x00,0x00,0xD0,0x02,0x00,0x00, +/* 0x00008FD0: */ 0x64,0x0F,0x00,0x00,0x02,0x30,0x78,0x5A,0xF8,0x8D,0x00,0x00,0x5F,0x00,0x00,0x00, +/* 0x00008FE0: */ 0x6C,0x8E,0x00,0x00,0xF8,0x8D,0x00,0x00,0x8E,0x00,0x00,0x00,0xA5,0x00,0x00,0x00, +/* 0x00008FF0: */ 0x9B,0x00,0x00,0x00,0x5D,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xB4,0x8F,0x00,0x00, +/* 0x00009000: */ 0x59,0x00,0x00,0x00,0x2C,0x00,0x00,0x00,0x98,0x8D,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00009010: */ 0xA4,0x08,0x00,0x00,0x59,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x5C,0x00,0x00,0x00, +/* 0x00009020: */ 0x60,0x00,0x00,0x00,0x5F,0x00,0x00,0x00,0x75,0x00,0x00,0x00,0x6C,0x00,0x00,0x00, +/* 0x00009030: */ 0x62,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00, +/* 0x00009040: */ 0x98,0x00,0x00,0x00,0x53,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0xFF,0x07,0x00,0x00, +/* 0x00009050: */ 0x11,0x00,0x00,0x00,0x24,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x18,0x00,0x00,0x00, +/* 0x00009060: */ 0x80,0x0F,0x00,0x00,0x02,0x30,0x78,0x5A,0x53,0x00,0x00,0x00,0xF4,0x39,0x00,0x00, +/* 0x00009070: */ 0x28,0x00,0x00,0x00,0x53,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x0F,0x00,0x00,0x00, +/* 0x00009080: */ 0x11,0x00,0x00,0x00,0x24,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x30,0x00,0x00,0x00, +/* 0x00009090: */ 0x3E,0x00,0x00,0x00,0x98,0x8D,0x00,0x00,0x64,0x0F,0x00,0x00,0x03,0x2F,0x2A,0x20, +/* 0x000090A0: */ 0xF8,0x8D,0x00,0x00,0x53,0x00,0x00,0x00,0x4C,0x8F,0x00,0x00,0x64,0x0F,0x00,0x00, +/* 0x000090B0: */ 0x05,0x3A,0x20,0x2A,0x2F,0x20,0x5A,0x5A,0xF8,0x8D,0x00,0x00,0x5F,0x00,0x00,0x00, +/* 0x000090C0: */ 0x53,0x00,0x00,0x00,0x7D,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0xFC,0x8F,0x00,0x00, +/* 0x000090D0: */ 0x71,0x00,0x00,0x00,0x70,0xFF,0xFF,0xFF,0x61,0x00,0x00,0x00,0x59,0x00,0x00,0x00, +/* 0x000090E0: */ 0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x64,0x00,0x00,0x00,0x53,0x00,0x00,0x00, +/* 0x000090F0: */ 0x59,0x00,0x00,0x00,0xFF,0x07,0x00,0x00,0x11,0x00,0x00,0x00,0x24,0x00,0x00,0x00, +/* 0x00009100: */ 0xBC,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x53,0x00,0x00,0x00,0xA4,0x1D,0x00,0x00, +/* 0x00009110: */ 0x28,0x00,0x00,0x00,0x53,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x0F,0x00,0x00,0x00, +/* 0x00009120: */ 0x11,0x00,0x00,0x00,0x24,0x00,0x00,0x00,0xBC,0x00,0x00,0x00,0x0C,0x00,0x00,0x00, +/* 0x00009130: */ 0x3E,0x00,0x00,0x00,0x98,0x8D,0x00,0x00,0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x00009140: */ 0xFC,0x8F,0x00,0x00,0x71,0x00,0x00,0x00,0xA4,0xFF,0xFF,0xFF,0x5D,0x00,0x00,0x00, +/* 0x00009150: */ 0x00,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x5C,0x00,0x00,0x00, +/* 0x00009160: */ 0x64,0x0F,0x00,0x00,0x08,0x23,0x64,0x65,0x66,0x69,0x6E,0x65,0x20,0x5A,0x5A,0x5A, +/* 0x00009170: */ 0xF8,0x8D,0x00,0x00,0x5F,0x00,0x00,0x00,0x70,0x01,0x00,0x00,0xF8,0x8D,0x00,0x00, +/* 0x00009180: */ 0x64,0x0F,0x00,0x00,0x03,0x20,0x20,0x28,0xF8,0x8D,0x00,0x00,0x60,0x00,0x00,0x00, +/* 0x00009190: */ 0x4C,0x8F,0x00,0x00,0x48,0x0F,0x00,0x00,0x01,0x29,0x5A,0x5A,0x24,0x8E,0x00,0x00, +/* 0x000091A0: */ 0x5D,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x01,0x00,0x00,0x00, +/* 0x000091B0: */ 0xF8,0x02,0x00,0x00,0x9B,0x00,0x00,0x00,0xF8,0x02,0x00,0x00,0x18,0x00,0x00,0x00, +/* 0x000091C0: */ 0x00,0x00,0x00,0x00,0xA4,0x08,0x00,0x00,0x59,0x00,0x00,0x00,0x01,0x00,0x00,0x00, +/* 0x000091D0: */ 0x5C,0x00,0x00,0x00,0xD8,0x8E,0x00,0x00,0x48,0x0F,0x00,0x00,0x11,0x73,0x64,0x61, +/* 0x000091E0: */ 0x64,0x2E,0x6F,0x70,0x65,0x6E,0x20,0x66,0x61,0x69,0x6C,0x65,0x64,0x21,0x5A,0x5A, +/* 0x000091F0: */ 0x48,0x1E,0x00,0x00,0x48,0x0F,0x00,0x00,0x33,0x2F,0x2A,0x20,0x54,0x68,0x69,0x73, +/* 0x00009200: */ 0x20,0x66,0x69,0x6C,0x65,0x20,0x67,0x65,0x6E,0x65,0x72,0x61,0x74,0x65,0x64,0x20, +/* 0x00009210: */ 0x62,0x79,0x20,0x74,0x68,0x65,0x20,0x46,0x6F,0x72,0x74,0x68,0x20,0x63,0x6F,0x6D, +/* 0x00009220: */ 0x6D,0x61,0x6E,0x64,0x20,0x53,0x44,0x41,0x44,0x20,0x2A,0x2F,0x24,0x8E,0x00,0x00, +/* 0x00009230: */ 0x48,0x0F,0x00,0x00,0x09,0x48,0x45,0x41,0x44,0x45,0x52,0x50,0x54,0x52,0x5A,0x5A, +/* 0x00009240: */ 0xAD,0x00,0x00,0x00,0x41,0x00,0x00,0x00,0x50,0x04,0x00,0x00,0x75,0x00,0x00,0x00, +/* 0x00009250: */ 0x54,0x91,0x00,0x00,0x48,0x0F,0x00,0x00,0x0A,0x52,0x45,0x4C,0x43,0x4F,0x4E,0x54, +/* 0x00009260: */ 0x45,0x58,0x54,0x5A,0xA8,0x00,0x00,0x00,0x41,0x00,0x00,0x00,0x50,0x04,0x00,0x00, +/* 0x00009270: */ 0x75,0x00,0x00,0x00,0x54,0x91,0x00,0x00,0x48,0x0F,0x00,0x00,0x07,0x43,0x4F,0x44, +/* 0x00009280: */ 0x45,0x50,0x54,0x52,0x51,0x00,0x00,0x00,0x5C,0x04,0x00,0x00,0x75,0x00,0x00,0x00, +/* 0x00009290: */ 0x54,0x91,0x00,0x00,0x48,0x0F,0x00,0x00,0x10,0x49,0x46,0x5F,0x4C,0x49,0x54,0x54, +/* 0x000092A0: */ 0x4C,0x45,0x5F,0x45,0x4E,0x44,0x49,0x41,0x4E,0x5A,0x5A,0x5A,0xA8,0x91,0x00,0x00, +/* 0x000092B0: */ 0xBC,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x01,0x00,0x00,0x00, +/* 0x000092C0: */ 0x15,0x00,0x00,0x00,0x0C,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x000092D0: */ 0x54,0x91,0x00,0x00,0x80,0x0F,0x00,0x00,0x0C,0x53,0x61,0x76,0x69,0x6E,0x67,0x20, +/* 0x000092E0: */ 0x4E,0x61,0x6D,0x65,0x73,0x5A,0x5A,0x5A,0x28,0x00,0x00,0x00,0x64,0x0F,0x00,0x00, +/* 0x000092F0: */ 0x26,0x73,0x74,0x61,0x74,0x69,0x63,0x20,0x63,0x6F,0x6E,0x73,0x74,0x20,0x75,0x69, +/* 0x00009300: */ 0x6E,0x74,0x38,0x5F,0x74,0x20,0x4D,0x69,0x6E,0x44,0x69,0x63,0x4E,0x61,0x6D,0x65, +/* 0x00009310: */ 0x73,0x5B,0x5D,0x20,0x3D,0x20,0x7B,0x5A,0xF8,0x8D,0x00,0x00,0x50,0x04,0x00,0x00, +/* 0x00009320: */ 0xAD,0x00,0x00,0x00,0x41,0x00,0x00,0x00,0x10,0x8C,0x00,0x00,0x10,0x90,0x00,0x00, +/* 0x00009330: */ 0x3E,0x00,0x00,0x00,0x98,0x8D,0x00,0x00,0x48,0x0F,0x00,0x00,0x02,0x7D,0x3B,0x5A, +/* 0x00009340: */ 0x24,0x8E,0x00,0x00,0x80,0x0F,0x00,0x00,0x0B,0x53,0x61,0x76,0x69,0x6E,0x67,0x20, +/* 0x00009350: */ 0x43,0x6F,0x64,0x65,0x28,0x00,0x00,0x00,0x64,0x0F,0x00,0x00,0x25,0x73,0x74,0x61, +/* 0x00009360: */ 0x74,0x69,0x63,0x20,0x63,0x6F,0x6E,0x73,0x74,0x20,0x75,0x69,0x6E,0x74,0x38,0x5F, +/* 0x00009370: */ 0x74,0x20,0x4D,0x69,0x6E,0x44,0x69,0x63,0x43,0x6F,0x64,0x65,0x5B,0x5D,0x20,0x3D, +/* 0x00009380: */ 0x20,0x7B,0x5A,0x5A,0xF8,0x8D,0x00,0x00,0x5C,0x04,0x00,0x00,0x51,0x00,0x00,0x00, +/* 0x00009390: */ 0x20,0x8C,0x00,0x00,0x10,0x90,0x00,0x00,0x3E,0x00,0x00,0x00,0x98,0x8D,0x00,0x00, +/* 0x000093A0: */ 0x48,0x0F,0x00,0x00,0x02,0x7D,0x3B,0x5A,0x24,0x8E,0x00,0x00,0x88,0x8E,0x00,0x00, +/* 0x000093B0: */ 0x5D,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF8,0x8B,0x00,0x00,0x88,0x8E,0x00,0x00, +/* 0x000093C0: */ 0xE0,0x8B,0x00,0x00,0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x5C,0x8D,0x00,0x00, +/* 0x000093D0: */ 0x9B,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x4C,0x8D,0x00,0x00, +/* 0x000093E0: */ 0x9B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00, +}; diff --git a/src/cmd/pforth/pfinnrfp.h b/src/cmd/pforth/pfinnrfp.h new file mode 100644 index 0000000..566380f --- /dev/null +++ b/src/cmd/pforth/pfinnrfp.h @@ -0,0 +1,336 @@ +/* @(#) pfinnrfp.h 98/02/26 1.4 */ +/*************************************************************** +** Compile FP routines. +** This file is included from "pf_inner.c" +** +** These routines could be left out of an execute only version. +** +** Author: Darren Gibbs, Phil Burk +** Copyright 1994 3DO, Phil Burk, Larry Polansky, David Rosenboom +** +** The pForth software code is dedicated to the public domain, +** and any third party may reproduce, distribute and modify +** the pForth software code or any derivative works thereof +** without any compensation or license. The pForth software +** code is provided on an "as is" basis without any warranty +** of any kind, including, without limitation, the implied +** warranties of merchantability and fitness for a particular +** purpose and their equivalents under the laws of any jurisdiction. +** +**************************************************************** +** +***************************************************************/ + +#ifdef PF_SUPPORT_FP + +#define FP_DHI1 (((PF_FLOAT)0x40000000)*4.0) + + case ID_FP_D_TO_F: /* ( dlo dhi -- ) ( F: -- r ) */ + PUSH_FP_TOS; + Scratch = M_POP; /* dlo */ + DBUG(("dlo = 0x%8x , ", Scratch)); + DBUG(("dhi = 0x%8x\n", TOS)); + + if( ((TOS == 0) && (Scratch >= 0)) || + ((TOS == -1) && (Scratch < 0))) + { + /* <= 32 bit precision. */ + FP_TOS = ((PF_FLOAT) Scratch); /* Convert dlo and push on FP stack. */ + } + else /* > 32 bit precision. */ + { + fpTemp = ((PF_FLOAT) TOS); /* dhi */ + fpTemp *= FP_DHI1; + fpScratch = ( (PF_FLOAT) ((ucell_t)Scratch) ); /* Convert TOS and push on FP stack. */ + FP_TOS = fpTemp + fpScratch; + } + M_DROP; + /* printf("d2f = %g\n", FP_TOS); */ + break; + + case ID_FP_FSTORE: /* ( addr -- ) ( F: r -- ) */ +#if (defined(PF_BIG_ENDIAN_DIC) || defined(PF_LITTLE_ENDIAN_DIC)) + if( IN_CODE_DIC(TOS) ) + { + WRITE_FLOAT_DIC( (PF_FLOAT *) TOS, FP_TOS ); + } + else + { + *((PF_FLOAT *) TOS) = FP_TOS; + } +#else + *((PF_FLOAT *) TOS) = FP_TOS; +#endif + M_FP_DROP; /* drop FP value */ + M_DROP; /* drop addr */ + break; + + case ID_FP_FTIMES: /* ( F: r1 r2 -- r1*r2 ) */ + FP_TOS = M_FP_POP * FP_TOS; + break; + + case ID_FP_FPLUS: /* ( F: r1 r2 -- r1+r2 ) */ + FP_TOS = M_FP_POP + FP_TOS; + break; + + case ID_FP_FMINUS: /* ( F: r1 r2 -- r1-r2 ) */ + FP_TOS = M_FP_POP - FP_TOS; + break; + + case ID_FP_FSLASH: /* ( F: r1 r2 -- r1/r2 ) */ + FP_TOS = M_FP_POP / FP_TOS; + break; + + case ID_FP_F_ZERO_LESS_THAN: /* ( -- flag ) ( F: r -- ) */ + PUSH_TOS; + TOS = (FP_TOS < 0.0) ? FTRUE : FFALSE ; + M_FP_DROP; + break; + + case ID_FP_F_ZERO_EQUALS: /* ( -- flag ) ( F: r -- ) */ + PUSH_TOS; + TOS = (FP_TOS == 0.0) ? FTRUE : FFALSE ; + M_FP_DROP; + break; + + case ID_FP_F_LESS_THAN: /* ( -- flag ) ( F: r1 r2 -- ) */ + PUSH_TOS; + TOS = (M_FP_POP < FP_TOS) ? FTRUE : FFALSE ; + M_FP_DROP; + break; + + case ID_FP_F_TO_D: /* ( -- dlo dhi) ( F: r -- ) */ + /* printf("f2d = %g\n", FP_TOS); */ + { + ucell_t dlo; + cell_t dhi; + int ifNeg; + /* Convert absolute value, then negate D if negative. */ + PUSH_TOS; /* Save old TOS */ + fpTemp = FP_TOS; + M_FP_DROP; + ifNeg = (fpTemp < 0.0); + if( ifNeg ) + { + fpTemp = 0.0 - fpTemp; + } + fpScratch = fpTemp / FP_DHI1; + /* printf("f2d - fpScratch = %g\n", fpScratch); */ + dhi = (cell_t) fpScratch; /* dhi */ + fpScratch = ((PF_FLOAT) dhi) * FP_DHI1; + /* printf("f2d - , dhi = 0x%x, fpScratch = %g\n", dhi, fpScratch); */ + + fpTemp = fpTemp - fpScratch; /* Remainder */ + dlo = (ucell_t) fpTemp; + /* printf("f2d - , dlo = 0x%x, fpTemp = %g\n", dlo, fpTemp); */ + if( ifNeg ) + { + dlo = 0 - dlo; + dhi = 0 - dhi - 1; + } + /* Push onto stack. */ + TOS = dlo; + PUSH_TOS; + TOS = dhi; + } + break; + + case ID_FP_FFETCH: /* ( addr -- ) ( F: -- r ) */ + PUSH_FP_TOS; +#if (defined(PF_BIG_ENDIAN_DIC) || defined(PF_LITTLE_ENDIAN_DIC)) + if( IN_CODE_DIC(TOS) ) + { + FP_TOS = READ_FLOAT_DIC( (PF_FLOAT *) TOS ); + } + else + { + FP_TOS = *((PF_FLOAT *) TOS); + } +#else + FP_TOS = *((PF_FLOAT *) TOS); +#endif + M_DROP; + break; + + case ID_FP_FDEPTH: /* ( -- n ) ( F: -- ) */ + PUSH_TOS; + /* Add 1 to account for FP_TOS in cached in register. */ + TOS = (( M_FP_SPZERO - FP_STKPTR) + 1); + break; + + case ID_FP_FDROP: /* ( -- ) ( F: r -- ) */ + M_FP_DROP; + break; + + case ID_FP_FDUP: /* ( -- ) ( F: r -- r r ) */ + PUSH_FP_TOS; + break; + + case ID_FP_FLOAT_PLUS: /* ( addr1 -- addr2 ) ( F: -- ) */ + TOS = TOS + sizeof(PF_FLOAT); + break; + + case ID_FP_FLOATS: /* ( n -- size ) ( F: -- ) */ + TOS = TOS * sizeof(PF_FLOAT); + break; + + case ID_FP_FLOOR: /* ( -- ) ( F: r1 -- r2 ) */ + FP_TOS = (PF_FLOAT) fp_floor( FP_TOS ); + break; + + case ID_FP_FMAX: /* ( -- ) ( F: r1 r2 -- r3 ) */ + fpScratch = M_FP_POP; + FP_TOS = ( FP_TOS > fpScratch ) ? FP_TOS : fpScratch ; + break; + + case ID_FP_FMIN: /* ( -- ) ( F: r1 r2 -- r3 ) */ + fpScratch = M_FP_POP; + FP_TOS = ( FP_TOS < fpScratch ) ? FP_TOS : fpScratch ; + break; + + case ID_FP_FNEGATE: + FP_TOS = -FP_TOS; + break; + + case ID_FP_FOVER: /* ( -- ) ( F: r1 r2 -- r1 r2 r1 ) */ + PUSH_FP_TOS; + FP_TOS = M_FP_STACK(1); + break; + + case ID_FP_FROT: /* ( -- ) ( F: r1 r2 r3 -- r2 r3 r1 ) */ + fpScratch = M_FP_POP; /* r2 */ + fpTemp = M_FP_POP; /* r1 */ + M_FP_PUSH( fpScratch ); /* r2 */ + PUSH_FP_TOS; /* r3 */ + FP_TOS = fpTemp; /* r1 */ + break; + + case ID_FP_FROUND: + ERR("\nID_FP_FROUND - Not Yet!! FIXME\n"); + break; + + case ID_FP_FSWAP: /* ( -- ) ( F: r1 r2 -- r2 r1 ) */ + fpScratch = FP_TOS; + FP_TOS = *FP_STKPTR; + *FP_STKPTR = fpScratch; + break; + + case ID_FP_FSTAR_STAR: /* ( -- ) ( F: r1 r2 -- r1^r2 ) */ + fpScratch = M_FP_POP; + FP_TOS = (PF_FLOAT) fp_pow(fpScratch, FP_TOS); + break; + + case ID_FP_FABS: /* ( -- ) ( F: r1 -- r2 ) */ + FP_TOS = (PF_FLOAT) fp_fabs( FP_TOS ); + break; + + case ID_FP_FACOS: /* ( -- ) ( F: r1 -- r2 ) */ + FP_TOS = (PF_FLOAT) fp_acos( FP_TOS ); + break; + + case ID_FP_FACOSH: /* ( -- ) ( F: r1 -- r2 ) */ + /* fp_acosh(x) = fp_log(y + sqrt(y^2 - 1) */ + FP_TOS = (PF_FLOAT) fp_log(FP_TOS + (fp_sqrt((FP_TOS * FP_TOS) - 1))); + break; + + case ID_FP_FALOG: /* ( -- ) ( F: r1 -- r2 ) */ + FP_TOS = (PF_FLOAT) fp_pow(10.0,FP_TOS); + break; + + case ID_FP_FASIN: /* ( -- ) ( F: r1 -- r2 ) */ + FP_TOS = (PF_FLOAT) fp_asin( FP_TOS ); + break; + + case ID_FP_FASINH: /* ( -- ) ( F: r1 -- r2 ) */ + /* asinh(x) = fp_log(y + fp_sqrt(y^2 + 1) */ + FP_TOS = (PF_FLOAT) fp_log(FP_TOS + (fp_sqrt((FP_TOS * FP_TOS) + 1))); + break; + + case ID_FP_FATAN: /* ( -- ) ( F: r1 -- r2 ) */ + FP_TOS = (PF_FLOAT) fp_atan( FP_TOS ); + break; + + case ID_FP_FATAN2: /* ( -- ) ( F: r1 r2 -- atan(r1/r2) ) */ + fpTemp = M_FP_POP; + FP_TOS = (PF_FLOAT) fp_atan2( fpTemp, FP_TOS ); + break; + + case ID_FP_FATANH: /* ( -- ) ( F: r1 -- r2 ) */ + FP_TOS = (PF_FLOAT) (0.5 * fp_log((1 + FP_TOS) / (1 - FP_TOS))); + break; + + case ID_FP_FCOS: /* ( -- ) ( F: r1 -- r2 ) */ + FP_TOS = (PF_FLOAT) fp_cos( FP_TOS ); + break; + + case ID_FP_FCOSH: /* ( -- ) ( F: r1 -- r2 ) */ + FP_TOS = (PF_FLOAT) fp_cosh( FP_TOS ); + break; + +#ifndef PF_NO_SHELL + case ID_FP_FLITERAL: + ffFPLiteral( FP_TOS ); + M_FP_DROP; + endcase; +#endif /* !PF_NO_SHELL */ + + case ID_FP_FLITERAL_P: + PUSH_FP_TOS; +#if 0 +/* Some wimpy compilers can't handle this! */ + FP_TOS = *(((PF_FLOAT *)InsPtr)++); +#else + { + PF_FLOAT *fptr; + fptr = (PF_FLOAT *)InsPtr; + FP_TOS = READ_FLOAT_DIC( fptr++ ); + InsPtr = (cell_t *) fptr; + } +#endif + endcase; + + case ID_FP_FLN: /* ( -- ) ( F: r1 -- r2 ) */ + FP_TOS = (PF_FLOAT) fp_log(FP_TOS); + break; + + case ID_FP_FLNP1: /* ( -- ) ( F: r1 -- r2 ) */ + FP_TOS = (PF_FLOAT) (fp_log(FP_TOS) + 1.0); + break; + + case ID_FP_FLOG: /* ( -- ) ( F: r1 -- r2 ) */ + FP_TOS = (PF_FLOAT) fp_log10( FP_TOS ); + break; + + case ID_FP_FSIN: /* ( -- ) ( F: r1 -- r2 ) */ + FP_TOS = (PF_FLOAT) fp_sin( FP_TOS ); + break; + + case ID_FP_FSINCOS: /* ( -- ) ( F: r1 -- r2 r3 ) */ + M_FP_PUSH((PF_FLOAT) fp_sin(FP_TOS)); + FP_TOS = (PF_FLOAT) fp_cos(FP_TOS); + break; + + case ID_FP_FSINH: /* ( -- ) ( F: r1 -- r2 ) */ + FP_TOS = (PF_FLOAT) fp_sinh( FP_TOS ); + break; + + case ID_FP_FSQRT: /* ( -- ) ( F: r1 -- r2 ) */ + FP_TOS = (PF_FLOAT) fp_sqrt( FP_TOS ); + break; + + case ID_FP_FTAN: /* ( -- ) ( F: r1 -- r2 ) */ + FP_TOS = (PF_FLOAT) fp_tan( FP_TOS ); + break; + + case ID_FP_FTANH: /* ( -- ) ( F: r1 -- r2 ) */ + FP_TOS = (PF_FLOAT) fp_tanh( FP_TOS ); + break; + + case ID_FP_FPICK: /* ( n -- ) ( F: -- f[n] ) */ + PUSH_FP_TOS; /* push cached floats into RAM */ + FP_TOS = FP_STKPTR[TOS]; /* 0 FPICK gets top of FP stack */ + M_DROP; + break; + + +#endif diff --git a/src/cmd/pforth/pforth.dic b/src/cmd/pforth/pforth.dic new file mode 100644 index 0000000000000000000000000000000000000000..fe0f24424cbb2b88353c687c025af1fba11fc479 GIT binary patch literal 53728 zcmeIbUvO1de($+K0tA+A?BIk>tJ4QtZVMyHY8t1BTa9(lIUvPCQtKQU8RH-s$%bwj z(IDJ(jN9sjxkC~s?Y*SUvE+8wOl7L(_A33ff4}egt>0SfxBl$4*Zy<13=C~clK=h2;D&0? z;D%Cfk|Z0TM-NEe{p@ z;K!jQ(2AA_u1yXjFNGGbZ%dAIvauS-sHTm~&!Kk#ySC`r!1Q&Hr~_97WvfPWZj zXeoAgmj|nB;jchfp`|I5+<<=s>M72Z;STbn(2AA_u1!8cUI{f6`}zjDi`B9+j(D8o zvf@ysr*})W8Tm2fx?+E61N?8m*KaQNTCXnTCpa$MJXGxO?nwrbS0O*Nd7$*lu7NFE zD&^`Z*l&W>ZGNRZ4ga6umyj3g$qe!@kn6k4ecC&L{Es0XxsoKOkwbfQcO~cHzYyZK z;g}@3g#6pcOS_dfB_APw5qZ%INpcgu3BIo7g|&C!zXZRmdtlpOaj1L``FGU&Ci&9P zYv31mZc0|de_4DJY2lv~AKsL-z!$`6^bPP&1-vuqf^U}Z_-4`v{|tOxN9U#y_@@KD zDH(_VO5i(_{qQaF-9yO{c-w7h_fT1{A47f?xuGQmj5`VTd+L|gCFkIOH}GxAMR=;1 zEFIqV+_r&Ias_##^0wh1Uq}ABy4#*jZo_{AzHWHivv=WJ;g^)kTkKb#Ag@!edri_v z2X0T}2CKBoYUJmT7xAwJ-oC#Gg$?juHBEaZ>4IMmU*A$1u)KZ9UsEm(4LA;VB5w%t z@HXX1%b#)avo18_>yxCL<3p+I+fXa7 z0=ptsD)*JE<$$$-mB5w{43_%?k|dpAo55Ce_YG81wPX-%i+VI|DbpJV`+YHuw^e#~ z(0>nuy=2<$L(CJY;&Cv?;KM<0aG=s#?H%Z69Dr{He{`rE!I0o0IL(#R4Lvt-4Zb(! zx8H=nEWiD^fjjX3tNiBP{(JD4OO{#p{w+l(r2*vSTl$78J*o3og4tg6TZYP(r5X8K z%01;F{-_YIe_nkUIo@Rz~sUMjzG3Vu8MvX;Jb@#XT`v&bXJTeIoxBJwN9%Ud#lPH`1% zhiUo-ilxdcm7B<~B0u8H*4O6f$N59a$KX4`A8rW|?dAUJ&?}^`XEJ^byfNaO8i11~ z@IT<#km6lp8^CsPT+#B?UBL=y57=nH*3V))!NvmiwOMRG*y{n?FpC`p+a0jyXR(uD z;{p5KS?nCxM8Lj2i(LkLBVZe6vFl)az_K#0vCMbC_6EJI%%GoueLG-TnZZ_a^7&4{ zvND4;gG~l3D>K+eu(tx1l^LuLY+t~#GJ}nRO$96~GuSlP{(xm=20I4!CKzpMgRKKf zPJw+FY$@2l;M(Lo@&V<(aB4~}BOgSr+g2R820tD6-u|2Lhu{~rQE&L~!7u4AZsRnO z+(UjFxq+_vvKV}Q1O3utKiP0xjeLvavaE-Pq_H|2*)Uk`een zfv+1H>>7vv)0AJcAO5f4i=2>-!2fsRmBFrK@c(_vuX!K-1NcR2nDgNO0=}`O!W7W9 zWnielPL=*VG0)KdLU@!+K8^BM2*Qd*}q!0OjKweTUSE`&O zcOw6fQRYNBiF_J)(KFN^{wMO!;&1r>9Q1mI2AK5TNB$6b@us2V4E#^w>#MH}+E33T z|4eyvv7&q#`QLC{-aWuXnu6EB{w>&wfc5oyM!gMo7K}9zlk!OQKJs59FD?xx4G$&B z{{&xO?(XqiunPHaI6lCY1JC*g z{y)OkjSLK}hQ9>AtRr32HY49hUfONLb|f2+>la1&t4Rsjx#N)+2nWA^aC+jc_BW>Y zBvo+N(hqIv9ja7!br19n^iP7VGHoA4tyGg4|)_zy-wr%B7ua!6f-U_~a4oc2~ z^??;zC?EW&JSVcN@cZGHbPo*oGjUu;K8n1Ug~M(5lkjyc#qYwO3wo@r*RlRXz8GcZ z$;O8nOHqE7^B%Hm>LuMh#Ub=tk*_1uO}H{(?Sp&+xxS6bg8KI%-&X!wIzR11Zd^?I z_33;uiM$%QuD^Hi2z)bqeRVj@na7YjkQaA;GdT(0DZlBP$r<<__@%x5Tnkl`^T@8R z>-q<(m*Gc^>o0HBXCEO?BQGnZz)j>6>h_k}KZZXW;>z8<+lqbnkuM=H8R)J$Z#F!V zB-hmKDUYm%cip^{^-^)@m82Q@zHx)a(gt|f%1fHlYmhGF0`juWaB$=+OOb!-I#Bk12C0wza=pI);1(c}b9IGvrID+^2KTBD=<2+})a7 zgugAny*0T4?^<CVY!%q@mJC}<+pgq#2W)Ew6_8!;E_)l7iS}qOJHYAyJ=f-=q369vTNf8{8kz0d$~;AZ-HG?r!&>LhkQew&N-d> z$57V09E8Z<>J<& z@;LGyWo9Qg4W^M@@0N?6G~kg>A=Al1yS|U?I=8&NhxI!3L%xX2<;Wlx%gF`gE6Cli zKJ(fYc-OkixCSj(Hm$veeAl!=r0&SA%c$$i#i8EfX3Zsc!Mebfub%_!AE&Le%swEo#E z@MqwcY$*okT|>TrTwfg;wyw93ub6IgUvd}zI{ZVuTiWB$`ULDwhQ*<^@;5j)n5MWU zX@+-AxVYGrbig+SzBTEDZ-HO>LO2~KJ;+t%O{qMBd{{Y%o02`qr)K4@`oERRbcnPHkSsHjqs}&;2*G!U?nlib{u&Sxg0JP@E7tP z8-3qzZJQPyt%iMbi$v2Z)n-x zQ>;D{;(NeOfo(~lWGC_swof(%suj9P%f~^{z=M<2B@!%Y}y$Uu8wye20$PQKMCh}=@*fFXO4um%U7;F_|etB`Y zI?&$RA1*Y1E1m07%xg(>z?#r|I9;1(J2m(Y+_~`a3~Be2($09~MA${#C~+$vh@&9* zaVK#{h-+w`HI*C&b9_FQL2cnOFTEf?PTYR_=dvvBEVAQc@lbDa5&k56Ll)D6s=1N;_vdVQ3Fcfsz8<$O@Tns%XYteCshOjd)P0bAx33+LZfWY_sCUFT0u zjg9Z$FufsmBSK8Ak$^w2GyrCsU?4Osw?t(qkSFBW>Z!mHVETN8#%=01x z)oSS5x54#m!>g$tOQ7TvFzdcFg_4zDpsmD;%oD^HkWU$JJF|DzfqWRe{u>02U6~ww zvhUDauTLDdK2O57wHeP5d9zQI#^v#U#SKDHhg{0K%aSTK=$Us;?Ad%68uW}r#2;n@U8Im z6_)g<>_qNCUi1|8g+CGWD#>B^bMQ-AhD+@<;!)&F$aRSC!+!){4?l#B)5sqyw*=MX zJaXfg$gk9%T!wFguS4}C_)hrxmSIgMH<0_(8*WeT!0%LVxP9mz{1N#U)Tq-Lc=z=i z;V-C9uB+kmZQPv658LnG+Iw*KSJMXG0Dhe`kA(K!)?4ZRYG~X(@Y~wj#QhKWkL5eL z{{epwenkr>#eSNJ8T1I)>fgan5u)rTzedJN59%^%)P=34a)ViKh|rvz>1#zuec$WqmS&d>z9}4_!bWL2f9&T1-|n%46WRE@2Y#J2)RFPo9X6EgTerbhD7KZjyV#Qy!0wsf zz?KYQ41m?suS;pNqz9Sdz?x`a%Lx2__{{@bl5zO=;a9Y9e{gGgU<>yO_Jdso+nPZ~ zk#8b%`CKAN@;>riIQAI;b2LMA_IeGX0^*t_q|gI4JZ_@wO^>XWWHD(Q5S+$8P@ zam(8{q4lx=+Dco1T?Jd(TpSuIzLGT3pH@DN51YT4G{K*QXD@H0`c2v%x#=tD2KmKg zBXSG!vgU2x$b8ZM+KIe`+bZP|+6Va~UzF!s!Y>31mWMzG6b?`9xaAJ~1coA?k;hZtH@8I6asokLgNq>~M3oY@SQS7huaxWlj#M8uGA#PpY%e&a_-^JBi zb8~Ab?gPOt6)Vs;#K&|8)(~V-^)}lxsH4{lTk@-Bj?NP{Hh%0!?(s} z*KqaBai!;7^Ew~W8+y_K)C67yU%Dl|-@XC){oh5dYv{M(#&Gj=cEU=aL!YC`VjN9na+1^X&R`qCN$Fk~DMY+4Z4d7r@VgZ+@mf z`3U|Fe8Y=#*8?}ed@x}1Gu_F@@Qv^dz0TpAhqn@SAFK&%#kNWr$Cmq?1DSVQ!IriN zu1yNaqsaA&r0GDOL|&5K5=y#|-$!1~TwZFcl*=Xh71$YVh%u{;Bi~Zy_5wG_lWFAp z$ji2;z)|GJ-^1qmO4v{He9?@&v@HeBAa^QnPUq+{qX0w<0dd>l>7zgzX66c9k$b-t;Q@I)WIP%i%z11EpZa}_g ze7Xgkl#p8(J4<-h#|^A1a#eYAUy&`?WE}a3^0$V|L$5HmARj}n=Q`c;9YsEgytF(r zSnjSS?<1c@uH)9p8Tbpv4fnImDJAETuNb$jICvTU^d{me<>C+z(|m+{*!pB^^P8C* z=Gom-`^I-qy|q6(_kT>>g%{&I>wcm$UE1Fpo+c0Cw!G?w+-pfQ^0_X?#;d(sUc>$d zb@IO11K06**sy@k|bL#9I?yBZN{+gWn`wI!A0P`zV1WI1c_X zIL}J-m)g@k;xk}PMf&f+W=~(<=1DGswSuh#V?$)fDWjX~AlvXG;yQ_I9N4^zjg4Iq zzXRR}{&0q~N*KoF;US%!;E#Z(Pc7{V7mKSoS5Jbk7}(sN;$2Ax*z^NfYf=I`0!I1T zO-S*R5wPPqtQBk$?0qou;e7K_xjn6RG6UYUIkYp+d%TmJL~cc1_U>@Mz**#y@u{3# zL_UGMTsy&Y%!6PTGfdYxf!_pc?9R%C-}KF0umYHA^<{;&uIHTH3f5!c2e!0$4Y3-m z6Ku)mSGZS2Jo0hmdS&7}kxv?5=?UYu5BZGo+~?X#{7&Ta#t)|nCXp{Avws&796`RO zevuoD=pRSEp*)nzr;zW2^r^vf$ahVjHQFWQd_Vgrlhgjbi(x!8J z_paFPu2mXK_@a}IOuGW(X(j81jbO_%s2TaH@;6eI4ahrjz~=V$qy&E&erZc(T{jOb z3?iS)hSl$3tO?B$>)&oA+r}1 z(p^Gs?x7r&HOWWt9q>!L(zG{_dwMA|`3!e=t-XU>jq>)cwfB)nku8@Gv@}4I$XU6< zGcK#aj(~-_fwUqY&tyy_oyezC)A%qhqxmERShKOi^sQ7(kWXPNiq+236aUx0Uiw;8?_KHl5tK;DQP?|pP3myqMV zi9zH+^|N~&qsTke&-QrtBkwUj+vA-<&ims;CI^4Kv3GLfjlKKEGk=^WZkn{IKYTze zOpw7Jmxwz`T;1k!*A4jFDZl16d=D2E^_$DvyXb3ok!Lb_4YCgaUP69&%Zu&lX(Vhx zB`d*MJ|>N3!L@7qmh}3h1^j*RC1%gO(S@8Z|6nFR6t2xC!nMgL*vUa`rPpQUcwOQe z`z&}}`$+XT{4Mz9c3*ClyCysdb{8z%N2KuQkngKw^se-Q(Mw0DX73`T*=fx88UE~&JY-2j9f;EtFNLMVq%)_zeJzz~>IJ(^KW?yfA*oi*^-jT=I zO(i;cAKZztReh$+?d`1Xuze1E4|phhz4s4rp)!B+}ZOF1+cSV!6)olY(T#BGS9eLVa8Ai`TBO+5wQxN?+>Gy9QyP3 zrVflBoZS1JtUvE3u5%>z=dh8|*ZWdBzK;{vN8IDw2dMTI`_hZE_OMBER-44F2uX0t zOXcKBmQP&!+{omxmYzN^wmaMOxC4HTwCP$pY;LC+w$uN>9}V|T+SwatA8B}7|7!4i z;1Bm!+PS3VQJUVD?e`tv_4JpXU}9Hz?x+WB71&ED7JB1Oux7A<9OlLAe((+8Urq7! zshD)hksKq=`{L_ETwC_U3}RT?X3^))KJxO*Cn89qhy$HpFQy zxdV0~hjoE@{dpB^U7B{t8*wYSw!96N=F#3UL>|px4Lj%be4=9`*lMuWEN!@rgv~zi z)8HKe=TysbEvs5GPTYCo+=k(qpAg6G)no?zb}hc1Ilw$vbUv5YXL)cQyahbV+gY5H?c!mL!*r6|B5s_x)aSW4^8bXm!}G;ahSeRM_lQf&(9TVBFZkE3+W>wZ z{A*eLQ#{SCkGPMB+b~ZY*(H03zqLR-StiGbzejvp53iQFzw3io#GNIs{tssJO?LsZ zr&zBLcY?UI@3hCb@FeRk;?5J-o|Y+%;|%=?_($NG&vH++(w`~p&0O5vldb3z_i-+6 z?g>}=fIiK|%{}Q#-HB`5HJ9Jq6R*r)#5LvO=AL||PZ8Iei<^4_midUd&RpEwld!BQ ziR&ZofqJuox(B`|muBv%SjtBu9L~kfJsnHGBkou(Ztf{r#w~Ftb8&M|%Q9|>JDZD} zdule_W4V}%n|pc|d!)OXi<^6jmhnv7ja=N^)3nTU#N8n->$hopvkLtfynb|cEQhB{ z>%YeO4=fu`==!uReINWTcsgF&v!_^TJMimcvp!AlATta0fOow3#6YiP^qf8kn1blXJwKduuiy;!J^`z%TFPoR;?S0Nw&C zO|gy$7~=~0F7l!Ze%L^J?q@%yQc70Bj|YBR(gc42eno1BYww|?1?;l%TT4l&x(Beq zdb|gI8a~tQDfbN~Rj|YOFP@L~WOBF$o}M`HR(6-{F!+sw@ftWh#~bdDodCZh9`18< zv#a~1aArCSejmIs#nZPF$jAM!hUrQLVTzOoHEu z`eDzcowqy~`{18|vsMkyBA-HTJmi`%)*gFcdB0xH=A#oNf1 zBRtYc-#dfOy)2E}Mi-Ime}K=?3H#P<>1NVZ@KxZ;P0K?fJg%PH0&51-p3C7fJ0$nO zHe`Ce?6SMwZeahg1lIUcPr5fTG!X7dG=U!me*~N*FsC`zTs%#%0sLrcgOlQRR?+wm z>?9bzZO`^(+Rbwm{9FyL5%)$ff>XAz*Usx%$qBHlU=Nw!@V1ct4A^xr%Mk4nms|wD z1x|f~o{NBMVE1!a8*9GXV5{HrI<$u~C7WGbpM?ap$9>|Oi8DXS8Y;JHBYv1k^RxR6 z52kf)0Y3q5{jx3{BD%n@X8PPEp7qfP_+4;)8m`uY=ja3AJAatA)8^qV;eD)QV0%&w zfBMh?*Vkajz|4=w-+XW;9V2@_H+OXVom#`OmK8M@p;_k`b2B*)3dl*=;8-%^t`ae!>ZyiXptfJcmX1ju! zU9tyke}?fo0{yTjIRbVO%zEU8d2#~0=V;olagsZ$F4z<3_OP|wS8lh{4Q#Kp^K=Gl z0OB|Pi!fGWyf=_SQtg^BKi_Z&;}4?7I0DW37*+yid;86V;9T?^R8 zKXDEm=z9@=bRv%;hdP#h-nN|dfi?YU)*r*$ndpG+1Z(t(@Af#e&>rBY!5cE@DQvpW zd>?FChMh*<_-CARMn;nJ@KyMSvp83xzFTz(d=h*`#Ch)fI@npThi0)YTke3}0?R-5 z@(I|-vsn7<&&qE+IL9_;a=J$|_V&d1-raFeVgqr$6!JuRZO?LhSE;vqSFy6IRIC=+ z3n6|b@hdB(Vrf^n>6T8RB->A1fw)IQT)3zYv+Hs2j@dNn=!n-3XNc<}?jh5(rE!=H6hph0z&3*MOvgqaz!*WEOy%{;dytQrCL{?D1tf>TZh)ov`BEXS1nc_? z+BoQycyY2l+@v@S{yz9458ylt4t@dr@dt3WGT5QLM%*XF{l=%`T0bUk<%tLEg$8T* zCVlKLGynQXAf37Zb{6b0u7TNTs50)DLVJt-41x{BT_LXCJZRHF;nOUm?4k-0{Pv5CgFWy`Vi3;x($8wu*o_|LL!k3}u zz%j4n_*jSkn8ih%d_7`$BNmU#NyAbp1mCd{H=oC#p9VC=R>1!Z%KNBc9&F`2nDx)6 z{T8zM%s|nn*3mXm_Y08WLr9z{B$P?Hkjb`xZ9RVumMjQuGoN2Tz9VBW zt^P5O*gmGU4wlXE?;y)+_%~4G&*k`ko8x_NCi=klW%7K!znITILJ>QT?keP{FK?Xh z#2B;{b@O&(d7=+}ug7rOe@pzwc?GhLLC&z#h^sO_`p3L{_sF2WV>t5vSC0QbbNqk# zFR702xBO?738wwl!N7)hQY`l<@h_%OXp2xDz%=cR?_lF$*3Ua(} zK(?$g?OOPlKKiv5n=f8n@x#lqeBfh0d^W>5g#MG4=_=uzU^`m|-z$t|c|Mc1V;Q48 z@vlIaAm_$W2M(bY_Z_}k+<9|`GTIi6P^^o3@m!#PG^~GE)`sA_H8I{a6f?X(Ze)}n zS0MPVjrI8jWSnLE31k|U$g}5E^{kg6?~_^?7yVN{zJP*tjrI2(H$xut9XEq@@m(G3 z68)+leOJd|Tx~n+Hs>L6ZF*F;ZSwP^cAOf-t%vsW{m``P*#Fea>xdijI;LF+H?3tj zG>=Z4AEU2hKBxx2dNf$&0`$qsrY_5KpCjErY5s>VhT|TNy6vB1x#;^xzUO3+_Z_Fm zpUUyRw`9n-zh%$MmN_q5r#Q#0hj+|75BQFg?<{#VM4cIhOh+FYZ1dVQrt^KKm|orO zD$kQvo$EPW-=k9g9n|HuBk%g+5;P9^-c{5QYsoOn;drv`^L_0J^faU|?fd%E;5oxMZCI8l z>xW6o8PA*fa|==7eXcl%oJQ8?zV{W+yXMmb#kGa+d|B@&IGBHsIr?5$9OtKzf0-TM z56jyLGLU^j-yO?%=KtX9@FizaL>GQ_Ld~E~Y zrL%spVf?xNG+2%&A?xblufKgz9pA6B-}o-w6R@i?JldNtZA+#T(`v^y ziTUU4M0`Fwu?)Tgm@h-bV;TG&fc5rhn6DnbH<-6kK+O9kZ^Je)_ %n78YkY5G_; z`^c)yzt+$G6tTQ*;E*nsC$@+E`a{Tm<1zLR$Illa`-XAamA8Kw=Xf-j*F}!oAoVQY zC8!g!9aaxc9h}}jwQr)Zd+N~Scwyhvbiv1&3Y@6TOaI$$hqJk+0RJ?kjo^md92Bo_ zhzjA^$Z&L>rBCX8<_O!?-ETCQhy3Vc=~3SuhMKapA&t+)|+z{uJ*)E_Iyt@?+?p*3i5r+c8=Pv zLh@8Aw8n8z0Bm4(t0P$TDGm{F&$otrJ2oE7?JZNbf9_y^_FZG!)%Q~EL%y?WP>y`Q-|PD($hM8R{1XuF z47l&H8uE3$%!gF+@~t1&hxc;zTihS;y;aXkewV|&2z}{0uJK%DpEdjqWM7RsDZVI- zSM`lM2-zOdcB->D=$KE``3rQcQ!`|LdVKDE*uooQbky-Rq0cyG4Y3Rh*^c%K=xXoL z>|NSu%zhVb<^A#TkJIw{?yTP;FxW2f+WD{H^~2j4em0X^@ss|DKFX)jmftdXig@ej zm~>pL<9A{#-(!Wn2Me!HOiq2T@W#Zx-4kmVB$hF@sYUU9T|;c|et7LUXZhYP+02fI z-%8)BEwrU`;J#yuIwY;dVDGW?(e5^ zPvvIKn*T2C(FK17$LSZkT8N9~ z_FEO=9Kv@iOn-{`Tz?y!qi5e&W-4ZQY^_q=JpFy#BV@`sSVGVK^tfJPRler$q|_@Ru~ zruIw|(}^vDz6|L<+tPI6G2QRMn-0^#XX?cC#>KSy)%u#=;8Fi-NBuvC3Xu6Ye#EpH z&)fQMH9&0FI0we|&&#NW`u`}Gz7t-XxH0UBTL<40H$Tg^kX`$ad8juCoq|5hjz8n5 zoo_(a?HH8DtiScL9v&A#rhNh$r!R^bf=`I_J$3CEY)|*jV#v$d$;;ZeZp~1vkKf1g zy>>&epF27>?Th-txHiaZZ*5pUZRqbkhk@$Lgt|@ z^U!}W-}Vf9jH77_P~MLFb-rt_9osk7={UT>dF6Um$9(@ku&SxcJw4yE_nOILkz-t6 zx^@%$KqCb0Mjhkc0Xr08=JplsBhgp4No$C0y%FBFH$M8d0B@aQI-AmQqE1J~M?1db z&5|JOeZ)5WnEnA276HDy?Y967zTf{-j_v^%K7_<F0k5~BevpAqWqMXU+H8T3*Bzh7w(oc6 zZ3h|Xk08siA9@+GjN0}b+}^Wyx^Qqm&z={ir#S!bo8G(c&_rutY~S|_Q`37U4ivsK z@qMGlUY|NJ{lX5@>-X!>6$)jRo(nt&uBiIV;6C2=9^Vo3&d)8K=>9FFPYO)twwrzW z5G20>Itayi-a1=OgYojQt=DJrcR9wrE5Dy$h-1lb<*8qQTr=O|=v_{Itc zx#ZviC;d2x*BqALHqn-2JKvU;YXmar3-fTS#&X*)#J&#M&JHi-I9BzYA>Yrm8GX}P zNPScSjJ##hPmV`}_6(liEyFXAZEPOOt`++V$P~(NP`nMM4d8IJTvxL-jDGd|1@?!f zh42DISWg0n_rE>n%Q~MN%X6oY`YX!!Gr6{$?_;D6a;=QY?EDtbos(cO-uAL?O^|hq zd7QyN)}t%KwPk+xuhS*3-GyHqZxRPjGY?9fxdlgL(N* zcixWQ`_u3F{9`@!Un>;%Tz+%g-h)me1)e$@*upME!LNeMU5DoDS?iM-?AYhL9~JvvFeW>BvP9fQ;}Kd++<`pbQCbu0t!4(U0B@9;<5Z^dZW_#=?IVuv_dp8}+P z`-XZ3?QZAT1exws?x^3+WMdUJ^nq9w+dbOwyz$Rf2FvI7Sqw2x%N?-~;iXu%I8JS^ zyzg|a%T&z)S~Qhy^Sso017zKp?sXI!-=&T<%P=bF5H?Em;#Ltb8WGnM1DPJ#5E zcl@r*2k^1XGnot&zAaPas1M>g=8^JY-o`7$FUGv!T0lGbblQyRT>Gqy<3E0TCR;<8 zW?sE$y+%);N83-rUxIAg*cN{C<`0o=E88QUr{cLh*739Ioc9?ff{&xmoEwafvga#h z$G<_jj%QQ1mE&XjRN%o-$0uGEjNGwfIgiA*?I;foRA#@alTRO_!~5ZRbe3Pn1K>P1 zJ2DGA$kccDSHJckl$YxLT2LN%kgxmJ@W6w}ucgo7f!h8Q`=IlL-!iiQM{EXuBjh~h zw~y?{e$UE&9?k(wBCg4d&(B%cm`k*0aGuc~Lo%d~b6^v4JYVdB_gwx2he;IGH=X&- zr#}iF^*b|t&!-FNkLC0mGyVF{(0@Ire-qyFP`m~0@6PF;%k)_uET})8(?62wFZ&Gr ziJX34rjOefwEsp7p4N|NDJ|cn#Eutj-xb0wIoF zbv-ZG)~`XK<8ts@Vd|Wu|G$dt(V(8exDQe`y>HPMzP(kLK6GFo_vWVFcq6@UF`td2 zzr}g)xwM~||IN%^k>iyX*1L2v&%0l!PE8fwa55z=6H}hsG$_u zeIV^>BaY9V@V1%l;l;fWpj$svPU?brG8(5+|3(&O(G+S}U;YYThddVOqi%sZ&F_lsj+)yB>m8`jnFIGU@EbMuFg zRy+=2+U%ZzTRXvUbh82QuwZj&XdnmU$j!>J8?T{fDLt-`nG( z7-7V_-|*>aFYSA|JUe+1+B^;MXueUVI-#zvnQUW^KdIrvybor%CG9X2XVbZVIBGn{ z7LM9bwqJY)8iR~`Jv*xN8f3`#RpppR{%C$=JDcAqy!RsB;y4Lu-+KZ3IGTs+r*Y^7 zXg@RsjY3{_+D49V(?r>}oq$I1y}Ge2#B2xCsN*_F9c`*(oEXq7ZoZ~F1Vvl+rF?$& zn_p&IALVVuveo9N9kJ-oyx$`K|F-`&WaW=#vTjd9vH#clsX$!5{*IBnPHi1NB;E#h zZ1^2Z!^qduaUyR#;sf!%r|tRNP}`@jVCy2dbGl`0g?KIN#e$&!Wn`d5L`OMtdV`zqNTAH`{7{uH&@x3LFw>WYL^Pb)Fw{X`hAf}uIRzQS3s5cY93A%;eHT0K4Mls#`yNBoIh@ncwsCpg zD~slI&(!D|7j=I|+9GtDI%vmvNi5bm#`{}LpA~;?fp~qWPiG)~YQ0xOVm=7y{*7(s z7!b3e)icDjCjL}f5`QXf)^4WNmcHHzjY4Bk+yigPuw5DE(f9&nK9)y*6q--Rd|!hM zA42AH2+H?I$LeoG+G>Q9zW^Dm*VE7gzCd;!RNwyMdC!p7wVyk7=hHh%oaaqLzRxRP zh5UYLY}5CVqpr`deGB;zWN>}m*geGqla+}#--zJfQ7Nx$ezm&V4L?~mmmt`+e4on#k zJC;0K{G zr~*0XI`=uJC=Wwo5nlsuUXF9uD%#r)Ie&Z?@?OORM|E1EXvg%i{MxmA)+3*Gl(f6S z#vyII1{rGS3d>G2f9hJtJkLXQQ22cvzb(wT{}OUD6wB?rrEi{44~qIr({B?$pl>?$ z&F^_g8&rEXz47L?H2rSz18LPW-4CIdznHF1N6vG=X?qgd2i1fSQlYTg&sPwJTeG3W!x?=5@I z^LxsMn0F?IZzr2B;-)e9O=Yi}GzY_f~tORs<5B$%^vjfFMMRVFc$VlrVBiq zQ#j~6?0mB(T=QwmHIv_Nj{7<1upQS`li+c!`f=CXI4_Z=1Q+*sku; ze39=k`)#1!D#hB)H!{;VC8iGT8($Nj_0jLw83vZ`)%jQ3&%1vAt?9pFJJ#> z!|fmP8Q3@ZeRlLF_l~=lmVN0syY!vjJGJj%d#JbHm^OI7*Ka`^PUQGsAV)lo^}M_| z7k?&8ubyl1s26d+KOM2!{;cnv!&>ZWXq+P4c>aBR}f?D(zC+ z*Zr2hZCl&d{jR^kzV3JR4YlXT&yroY$Gn>1FF}^mZ;1E}eaC+EwcpT>bAjc^zw>YKcY`DEZxBb`-(8KozquOuT0eU3wJx4_c0%$LceZ|1>4EDe$JuBW zPtve&_=g<74Sg57&iQ4O<7<%N^Vn9W4yr(hvNYQM3G`>sC}f;tb{%9sKC_h1!*OK! zy~eYQ+KlBBvwq^1HJ>ilTb-CD=4oEyqmX*aF|B^flWFO0vp$3kJ`p#32a5b8ymq|? z_2_e0do%uNj`q9TnQXrP?ty82{r4S?aV;?o?_4no#eUxduT9tEruj1T7$k4I>fcj2 zS)VFI{6w_(f`kEd#=*gF$nCI*8*0~9C zP20e01Fuhw9T;bQ7|SER;+gJec%^^`04Brx)ni$@OWdQ1?PB?2o1TR)LLWk-kg{V? z|MWwiXCoHV*S2XLIy)il8uZZ>DsquyY%^_H{xeYY{ZHZD<5^mG`GJWhH&G6g0e`@3vx`n*DXCrCT-njCiaT%5

    e$#PG{xvP@QS!D8Fm*7}WNh4(+A4}XGe@EL3Mn=^gOySSyWBks#BTDxP1zmuWQ zO>0np1DJiq5M}d={>Qc9cQk6_wc#}FxYI}K`TH7%Sk7qgy%Y|=`5|T*BNk=zlnk|4 zUVb-K3BSML9-hC=;cs>r{7nwqFt$xTE^ouWQHQ>^+|P({`r)TgwC8Vm=s)ckoGa9| zO)S6lHP7g)4eFq<#Gl)ukC;C1io10=@`FvtoccQxsQa0r0K;tZ5^n+~{>mTd0 z#NQmGK>9I`NAq692O6SH)7ua9xjMF)aZ)}%$DaB5g9+;G$@EM=pWdEKuPf6t&3t-S zGd)PAN;De!fy>dXlo?1 zwZ6udebI8+cPz)^(m?P%>a%TUAGVKKrj?nU8Th=vI+62s>iI1t`M7`@##Rt9&}0~$aN9Kcbw|Sc1W03tt%->J^5Z=9g*E@!|ehK%dIPb;v z#WTcN)>g>#fWJ=^%Wj>Vi~0&&^N@*ka1E|q&#{KuGW{)>em(@{-#yeX1u(-eJJ-(_ zKf9(N?|hyQ{uUC>`gQoP+5`E%VPErirR3{ZTW#=i$5aW$g?-b;IbJRne)iFMX ze}su?T|4FD{GBU*2TR=X$+Q{xyv<*LDLYRYqAk-th3uT)6n>|LhlYIsI{Ws~z{};K zE&O77+(*x+%jfCvH2)_vTVI;T)-a!wkH+FX8T}W>n)74cpP#p5{Xb1Zw!xpPnPBy+ zZKc1IqrZNR>~CfH?F5fM%VZAWx46_boxhu9@OQXsv1s2sZ1;uo@prP!$D{dpH29le z(WbwdWyt3fvAjRjsXdSSn^=~?-#d%#DQ0=1ybInw=e#PGkNY;5@%A-?>z`3b9sMT0 z7E_9nYJS%SaJudT(HvN6Im^bijy#9&#t8dWmBFNw0GQ@oHavgYH_S!EmFR78e zj>^Zg1b9GpEXDZfw|v>Gvmutv-^hxxKFG_KEiYTPylmO>vSrK5mMt$^wkXe6w%B(q zn|afHLc5J}jO(5P{1~Kd1mxOf6tbUKEswE%wWpqGW82!#Vqc5-*}nD{kNU&C zjZw&Su?$V{(e5Jnn7{LZdgeQt9W6%@ivCttthNlX9QxFHo4IAB%LMIEXTo}qUCOw96GHrrw)q|JJtvgafdeF&V)K=ykvmh!>> zraJ;zpYL+a&u6hbwuNg{)A^fj+OO;EEGT!qp0yGDE!MmKhMVc^-^xL^aO4O{k^&L> z#b-xd&zjzAmtSy!sZ~qp0>g(svqklfr*9Uoh+aQ+TYmA>FtF!3Ibiej+mTsYIRqH)px~?qULf5Jb zrK34Qd90iDoo%;Gn+mmkypDML!ziS_AzwG!-MYnnivmjTAv-tOU-h-`4w%++c|L6c zIr_ylrq_J$LZ-Qpr7>MTP0TO$h1$MkTGwEvtL+#0wDybn(spKPYx_vP4fUD!De~;x zSD&S;?JGU#SVz+vSAb&KYi(Hn`O0*blc%~LLU~`PuWjd9%R7_lIfu-rXPc-ulIi_u z0X=^cR=ti)@Av|G{{E|a4VfOp_kny@BggW^GTvk|vn~%UplcapInQUhD{6EL$lA4> z(TDzKtz|iqrK!Nb1J%wUwfcRT{_tn$I|ictrcB>^sCoOX$d*Z;NDH;`&HA*=&b|5c zO<8)=O^(iuopYJ~4?aWxZchJ5rtdm7Z-2hF@L5^?F;k~WroyyMxu@i-UUgg4LHxh_987fO3NOIthNMc>DC@mQPpXqKMldB8Vu9Qhl%_MwfL zo^xT|hf(iDrnfTFL!4L7wYK)|EKciex#qLyZ|$mgInx_mK+oUZRqte`H@1MDzrm~C z{!H)n1@!zqUiEr1z1<7wHBxZ(3Yp&c0($;VuX^{H7;WQ;1@u}oy=$4?8w=?9`@Pyb zo9XRYK+o$2^=2|X``Ubd-jnIYy>8d?^Xd6JzuN1_?77ySPw!Z!*O2K=E}-Y{|7!0R zq+eXK&u8y!rgt&Z+qZz8zYDCr6Pe!B0(w_7J^g0B`xnsj_ky+81*!KYG++7dWO~je zA3~#07v%XSj(^9DVZQ4pl85!Azq#$YUccUgALD4go>1TA@Ym1>kos}2`xo%)pc2YA z%F*9pzr@k`O5IV&-v^F!jqTwYpg_W6#&=|V0ok-0A=7$(iuPlg_rOOX-}$gy(XR7A zZGQgl`C;nfZ+u&yd>w#7h}R8^kx+l2Y)>Owo|TZc{Vikji)FF=QD-)P2CVH?fc`yn zbP;2K1k1N%53gq5*4ADu!)f^Eq3F9#c-zi&PgSN4@N2n+SEddXc8~dKVm{5Yd!jHl zx6$72JZ+w%P_4ggvwV5w^|!dcAMdr5*vbrxymj;Uo~^@4>YyJD3)#x2^S7O&Y(9p3 zI(@Ai%Mo?W^OvQ~r?akx8Au;|mL1RSx7a7*5Z)9tdA^P8l#-USTnKl6Au!}9)(@ib-FFUkALy8aN{ zdJaOCWmT?r>4q(La>(C)YX0i{=D{g;ai{k0_g2!x;fdXcywB7g{9u1{9Ov_?ZCm4F zxklmjiTAE7hwrXrT`u?xDEzLsNAv!Ap^)x26j};UT#HF0n*jdn{}nmP6HsqgKZ(|M{;*!n=;Z%+Az(TVgecfUV5r~A9;Mtl3xlA;~# z^{1WXV0b#Gu=~(~1H8JIVy&SKtY=%AQU1S8Rv4R(`AzeS+*!BdITHP2@VYP`l;b{n z1AJb7uSWi2jclLG>o2L1J$L!L=+`+qKA4tff5*q)Gq)a#*Z=+w;PCtAKjUa${}76M zIk4gRBhP!rJMU<#1ZmfxtzRW=H)--|wf9mEQ|1zLR!3Rim?rLcHaeQLs5pPS~_ z;nyDcwFiFffnR&z*Bg}{c@5fd z?PpLol#v8p<9K~TQ-pQxlP~qO7fYq~zTW;aFNpayzt{KjU>=t(tjnjT4t#&j4xdkZ z0)5-pGF-&AHr$tpaWnAxvDO#*bA*Cfwi4--^@(jSznaCn{B0D994+^0_$b>?wE0hD z{8*-^kF{Z(ZS)1mkl$Z2ZYSjP`|g?OdwpfOy~b3&1$`TS6xu_cPjNK90~&>*ej$_1 zlfT(^Ha~6ef?k6RvE6Og=b?B#*#vK%_n}%lL?w+gY2J<#`+{k;VR>xF)mDgbl(_4V z` zF+|d3FchCI!e>_q1jN89VCkfA=yBi3~lnCZ>e zIMZ6U=tt|Pe=Mi=VtT*ntuO48#vdcj@C0<3ddWw-mPz~i&oYuUq%CkfM;-Ed=C2Lg zz&s7sRU7V088&40%)e2ZNp)j6jCUW-aAIaIFL7<0{l=VsV_q?>X^x_o*RgIft?{d} z{A0NbV3x(B?PS*KFw|yc>uHE-F&WY{ag6%bJ*MBE>05XG9`mvtZTIMtA~MmzmOjh- zGxi}UMAnJTVru+Yx zNJ6v|?H0f+LlvqmgG2FoXrXfGGs8j1GUdw=^Haz9?;YrOAoE%U*~czZXUjN32GLd= z3(7sveCdwKCE;>_$J%WO|zy(2IVI3i=+40h^NIcUV%8tdpmYD1=**zAv8KGyPV6r` z(OJEKPV564(P>#gC-x`p=IfzPTt67BufDlOogItT*?8;f^H3Zp9$ha4M5mWO7`;UuXXO08INQ$=LFG+>jkTH)+QZ=P1(@kxk?A%aCPif_jdnd2jra z^qg+_^mVkMPh_^@#>Q-oNL_ov~L?uLCuuU@{f{VOdrqp_6L0& z@#gpDc%nj?>a(M=&rjT^@hs~M)byw6eGoD8`YF@`d9UY2)@PKj&di+?OUTzVpVh&~ z=l>S3E$lG8zZGSg6Ekz`KmFr+Kwn&0z-}vXpC|pzEd5>VN8i~$yv`VT5{BUV)a##? zZ=~yR+uKn6v$XD4;k`GN??1MI^O2Z-@u*(>UHB-+bm~ym&~`DMeKG3Aba!c_N%A$E z<#;RON1jXNXVa+J|H|<`fo=C$vI8lfp4&^ma#-mL<^Lc5Ch@Oa=miqweW62Z<*wuO zjUT0BdS`Zg2|e4)V4P#k5cN7pw`8=3D z!nL9H?Sk55h=vgJbWA=E*@sRNPgY_4`J0Q*-v;~ked0F3t7C}ios|5|#)T;VdyTbe z@^R50Kg70m?Sy_=T{oj+8KYfoME@P*#N;zgEB3!JzIXTd*mV1z9lhvwL)Q00DCVOL z?@{q>%J>uNyAMq8Gl2Y(I-jb}SxE1%J%PSsKIRwCftEu*?}YOAsjlHv%d)uR@DBax zxnv`W*@IRn*hzUUEZc`?zz&w;?X)AVw=T2 zaf5W)cPhc5o+#J-6G{_bVrb$%?9FY~3h+;>mC z#Xa(I?uZvlxZU!Yc6s{YPd-J{Hrj?A@}fueVz5EAQeL>3WO(`0gyW?N_cl^s)7gV==ae>Fslkm9e*dtif-N z9wcoGy88Mn2dBrT_wM$!+Jn=DLwom4Z`?J_r{VUM_U;b4ufE2E8t;U5vQDvnE18E^ zo|tQY>$v#cZ-h27zlXB?{Jd?<>*>$POT8?skeBt>4~5Uj$2l$bhx?qzl|7%wy2tq_ N%Fg$3KE!nLe*-j(pXvYr literal 0 HcmV?d00001 diff --git a/src/cmd/pforth/pforth.h b/src/cmd/pforth/pforth.h new file mode 100644 index 0000000..a50265f --- /dev/null +++ b/src/cmd/pforth/pforth.h @@ -0,0 +1,101 @@ +/* @(#) pforth.h 98/01/26 1.2 */ +#ifndef _pforth_h +#define _pforth_h + +/*************************************************************** +** Include file for pForth, a portable Forth based on 'C' +** +** This file is included in any application that uses pForth as a tool. +** +** Author: Phil Burk +** Copyright 1994 3DO, Phil Burk, Larry Polansky, David Rosenboom +** +** The pForth software code is dedicated to the public domain, +** and any third party may reproduce, distribute and modify +** the pForth software code or any derivative works thereof +** without any compensation or license. The pForth software +** code is provided on an "as is" basis without any warranty +** of any kind, including, without limitation, the implied +** warranties of merchantability and fitness for a particular +** purpose and their equivalents under the laws of any jurisdiction. +** +** +***************************************************************/ + +/* Define stubs for data types so we can pass pointers but not touch inside. */ +typedef void *PForthTask; +typedef void *PForthDictionary; + +/* Integer types for Forth cells, signed and unsigned: */ +typedef int cell_t; +typedef unsigned int ucell_t; + +typedef char int8_t; +typedef unsigned char uint8_t; + +typedef short int16_t; +typedef unsigned short uint16_t; + +typedef int int32_t; +typedef unsigned int uint32_t; + +typedef ucell_t ExecToken; /* Execution Token */ +typedef cell_t ThrowCode; + +#ifdef __cplusplus +extern "C" { +#endif + +/* Main entry point to pForth. */ +cell_t pfDoForth( const char *DicName, const char *SourceName, cell_t IfInit ); + +/* Turn off messages. */ +void pfSetQuiet( cell_t IfQuiet ); + +/* Query message status. */ +cell_t pfQueryQuiet( void ); + +/* Send a message using low level I/O of pForth */ +void pfMessage( const char *CString ); + +/* Create a task used to maintain context of execution. */ +PForthTask pfCreateTask( cell_t UserStackDepth, cell_t ReturnStackDepth ); + +/* Establish this task as the current task. */ +void pfSetCurrentTask( PForthTask task ); + +/* Delete task created by pfCreateTask */ +void pfDeleteTask( PForthTask task ); + +/* Build a dictionary with all the basic kernel words. */ +PForthDictionary pfBuildDictionary( cell_t HeaderSize, cell_t CodeSize ); + +/* Create an empty dictionary. */ +PForthDictionary pfCreateDictionary( cell_t HeaderSize, cell_t CodeSize ); + +/* Load dictionary from a file. */ +PForthDictionary pfLoadDictionary( const char *FileName, ExecToken *EntryPointPtr ); + +/* Load dictionary from static array in "pfdicdat.h". */ +PForthDictionary pfLoadStaticDictionary( void ); + +/* Delete dictionary data. */ +void pfDeleteDictionary( PForthDictionary dict ); + +/* Execute the pForth interpreter. Yes, QUIT is an odd name but it has historical meaning. */ +ThrowCode pfQuit( void ); + +/* Execute a single execution token in the current task and return 0 or an error code. */ +int pfCatch( ExecToken XT ); + +/* Include the given pForth source code file. */ +ThrowCode pfIncludeFile( const char *FileName ); + +/* Execute a Forth word by name. */ +ThrowCode pfExecIfDefined( const char *CString ); + +#ifdef __cplusplus +} +#endif + +#endif /* _pforth_h */ diff --git a/src/cmd/pforth/readme.txt b/src/cmd/pforth/readme.txt new file mode 100644 index 0000000..3c7162b --- /dev/null +++ b/src/cmd/pforth/readme.txt @@ -0,0 +1,97 @@ +README for pForth - a Portable ANS-like Forth written in ANSI 'C' + +by Phil Burk +with Larry Polansky, David Rosenboom and Darren Gibbs. +Support for 64-bit cells by Aleksej Saushev. + +Last updated: May 20, 2010 V26 + +Code for pForth is maintained on Google at: + http://code.google.com/p/pforth/ + +Documentation for pForth at: + http://www.softsynth.com/pforth/ + +For technical support please use the pForth forum at: + http://groups.google.com/group/pforthdev + +The author is available for customization of pForth, porting to new +platforms, or developing pForth applications on a contractual basis. +If interested, contact Phil Burk at: + http://www.softsynth.com/contacts.php + +-- LEGAL NOTICE ----------------------------------------- + +The pForth software code is dedicated to the public domain, +and any third party may reproduce, distribute and modify +the pForth software code or any derivative works thereof +without any compensation or license. The pForth software +code is provided on an "as is" basis without any warranty +of any kind, including, without limitation, the implied +warranties of merchantability and fitness for a particular +purpose and their equivalents under the laws of any jurisdiction. + +-- Contents of SDK -------------------------------------- + + build - tools for building pForth on various platforms + build/win32/vs2005 - Visual Studio 2005 Project and Solution + build/unix - Makefile for unix + + csrc - pForth kernel in ANSI 'C' + csrc/pf_main.c - main() application for a standalone Forth + csrc/stdio - I/O code using basic stdio for generic platforms + csrc/posix - I/O code for Posix platform + csrc/win32 - I/O code for basic WIN32 platform + csrc/win32_console - I/O code for WIN32 console that supports command line history + + fth - Forth code + fth/util - utility functions + +-- How to build pForth ------------------------------------ + +See pForth reference manual at: + + http://www.softsynth.com/pforth/pf_ref.htm + +-- How to run pForth ------------------------------------ + +Once you have compiled and built the dictionary, just enter: + pforth + +To compile source code files use: INCLUDE filename + +To create a custom dictionary enter in pForth: + c" newfilename.dic" SAVE-FORTH +The name must end in ".dic". + +To run PForth with the new dictionary enter in the shell: + pforth -dnewfilename.dic + +To run PForth and automatically include a forth file: + pforth myprogram.fth + +-- How to Test PForth ------------------------------------ + +You can test the Forth without loading a dictionary +which might be necessary if the dictionary can't be built. + +Enter: pforth -i +In pForth, enter: 3 4 + . +In pForth, enter: loadsys +In pForth, enter: 10 0 do i . loop + +PForth comes with a small test suite. To test the Core words, +you can use the coretest developed by John Hayes. + +Enter: pforth +Enter: include tester.fth +Enter: include coretest.fth + +To run the other tests, enter: + + pforth t_corex.fth + pforth t_strings.fth + pforth t_locals.fth + pforth t_alloc.fth + +They will report the number of tests that pass or fail. diff --git a/src/cmd/pforth/releases.txt b/src/cmd/pforth/releases.txt new file mode 100644 index 0000000..3bcd596 --- /dev/null +++ b/src/cmd/pforth/releases.txt @@ -0,0 +1,273 @@ +Release History for pForth - a Portable ANS-like Forth written in ANSI 'C' + +Documentation for pForth at http://www.softsynth.com/pforth/ + +V27 + - Fixed REPOSITION-FILE FILE-SIZE and FILE-POSITION. + They used to use single precision offset. Now use double as specified. + - Delete object directories in Makefile clean. + - Fixed "Issue 4: Filehandle remains locked upon INCLUDE error". + http://code.google.com/p/pforth/issues/detail?id=4&can=1 + - Fixed scrambled HISTORY on 64-bit systems. Was using CELL+ but really needed 4 +. + - Fixed floating point input. Now accepts "1E" as 1.0. Was Issue #2. + - Fixed lots of warning and made code compatible with C89 and ANSI. Uses -pedantic. + - Use fseek and ftell on WIN32 instead of fseeko and ftello. + - Makefile is now more standard. Builds in same dir as Makefile. Uses CFLAGS etc. + - Add support for console IO with _WATCOMC_ + - Internal CStringToForth and ForthStringToC now take a destination size for safety. + - Run units tests for CStringToForth and ForthStringToC if PF_UNIT_TESTS is defined. + +V26 5/20/2010 + - 64-bit support for M* UM/MOD etc by Aleksej Saushev. Thanks Aleksej! + +V25 5/19/2010 + - Added 64-bit CELL support contributed by Aleksej Saushev. Thanks Aleksej! + - Added "-x c" to Makefile CCOPTS to prevent confusion with C++ + - Allow space after -d command line option. + - Restore normal tty mode if pForth dictionary loading fails. + +V24 2/20/09 + - Fixed Posix IO on Mac. ?TERMINAL was always returning true. + - ACCCEPT now emits a space at end of line before output. + - Fixed RESIZE because it was returning the wrong address. + +V23 8/4/2008 + - Removed -v option from mkdir in build/unix/Makefile. It was not supported on FreeBSD. + Thank you Alexsej Saushev for reporting this. + +V23 7/20/2008 + - Reorganized for Google Code project. + +V22 (unreleased) + - Added command line history and cursor control words. + - Sped up UM* and M* by a factor of 3. Thanks to Steve Green for suggested algorithm. + - Modified ACCEPT so that a line at the end of a file that does NOT have a line + terminator will now be processed. + - Use _getch(), _putch(), and _kbhit() so that KEY, EMIT and ?TERMINAL will work on PC. + - Fixed : foo { -- } 55 ; - Was entering local frame but not exiting. Now prints error. + - Redefined MAKE_ID to protect it from 16 bit ints + - John Providenza says "If you split local variables onto 2 lines, PForth crashes." Fixed. Also allow \ + - Fixed float evaluation in EVALUATE in "quit.fth". + - Flush register cache for ffColon and ffSemiColon to prevent stack warnings from ; + +V21 - 9/16/1998 + - Fixed some compiler warnings. + +V20 + - Expand PAD for ConvertNumberToText so "-1 binary .s" doesn't crash. + Thank you Michael Connor of Vancouver for reporting this bug. + + - Removed FDROP in REPRESENT to fix stack underflow after "0.0 F.". + Thank you Jim Rosenow of Minnesota for reporting this bug. + - Changed pfCharToLower to function to prevent macro expansion bugs under VXWORKS + Thank you Jim Rosenow of Minnesota for reporting this bug. + + - "0.0 F~" now checks actual binary encoding of floats. Before this it used to just + compare value which was incorrect. Now "0.0 -0.0 0.0 F~" returns FALSE. + + - Fixed definition of INPUT$ in tutorial. + Thank you Hampton Miller of California for reporting this bug. + + - Added support for producing a target dictionary with a different + Endian-ness than the host CPU. See PF_BIG_ENDIAN_DIC and PF_LITTLE_ENDIAN_DIC. + + - PForth kernel now comes up in a mode that uses BASE for numeric input when + started with "-i" option. It used to always consider numeric input as HEX. + Initial BASE is decimal. + +V19 4/1998 + + - Warn if local var name matches dictionary, : foo { count -- } ; + - TO -> and +-> now parse input stream. No longer use to-flag. + - TO -> and +-> now give error if used with non-immediate word. + - Added (FLITERAL) support to SEE. + - Aded TRACE facility for single step debugging of Forth words. + - Added stub for ?TERMINAL and KEY? for embedded systems. + - Added PF_NO_GLOBAL_INIT for no reliance on global initialization. + - Added PF_USER_FLOAT for customization of FP support. + - Added floating point to string conversion words (F.) (FS.) (FE.) + For example: : F. (F.) TYPE SPACE ; + - Reversed order that values are placed on return stack in 2>R + so that it matches ANS standard. 2>R is now same as SWAP >R >R + Thank you Leo Wong for reporting this bug. + + - Added PF_USER_INIT and PF_USER_TERM for user definable init and term calls. + + - FIXED memory leak in pfDoForth() + +V18 + - Make FILL a 'C' primitive. + - optimized locals with (1_LOCAL@) + - optimized inner interpreter by 15% + - fix tester.fth failures + - Added define for PF_KEY_ECHOS which turns off echo in ACCEPT if defined. + - Fixed MARKER. Was equivalent to ANEW instead of proper ANS definition. + - Fixed saving and restoring of TIB when nesting include files. + +V17 + - Fixed input of large floats. 0.7071234567 F. used to fail. + +V16 + * Define PF_USER_CUSTOM if you are defining your own custom + 'C' glue routines. This will ifndef the published example. + - Fixed warning in pf_cglue.c. + - Fixed SDAD in savedicd.fth. It used to generate bogus 'C' code + if called when (BASE != 10), as in HEX mode. + - Fixed address comparisons in forget.fth and private.fth for + addresses above 0x80000000. Must be unsigned. + - Call FREEZE at end of system.fth to initialize rfence. + - Fixed 0.0 F. which used to leave 0.0 on FP stack. + - Added FPICK ( n -- ) ( i*f -- i*f f[n] ) + - .S now prints hex numbers as unsigned. + - Fixed internal number to text conversion for unsigned nums. + +V15 - 2/15/97 + * If you use PF_USER_FILEIO, you must now define PF_STDIN and PF_STDOUT + among other additions. See "pf_io.h". + * COMPARE now matches ANS STRING word set! + - Added PF_USER_INC1 and PF_USER_INC2 for optional includes + and host customization. See "pf_all.h". + - Fixed more warnings. + - Fixed >NAME and WORDS for systems with high "negative" addresses. + - Added WORDS.LIKE utility. Enter: WORDS.LIKE EMIT + - Added stack check after every word in high level interpreter. + Enter QUIT to enter high level interpreter which uses this feature. + - THROW will no longer crash if not using high level interpreter. + - Isolated all host dependencies into "pf_unix.h", "pf_win32.h", + "pf_mac.h", etc. See "pf_all.h". + - Added tests for CORE EXT, STRINGS words sets. + - Added SEARCH + - Fixed WHILE and REPEAT for multiple WHILEs. + - Fixed .( ) for empty strings. + - Fixed FATAN2 which could not compile on some systems (Linux gcc). + +V14 - 12/23/96 + * pforth command now requires -d before dictionary name. + Eg. pforth -dcustom.dic test.fth + * PF_USER_* now need to be defined as include file names. + * PF_USER_CHARIO now requires different functions to be defined. + See "csrc/pf_io.h". + - Moved pfDoForth() from pf_main.c to pf_core.c to simplify + file with main(). + - Fix build with PF_NO_INIT + - Makefile now has target for embedded dictionary, "gmake pfemb". + +V13 - 12/15/96 + - Add "extern 'C' {" to pf_mem.h for C++ + - Separate PF_STATIC_DIC from PF_NO_FILEIO so that we can use a static + dictionary but also have file I/O. + - Added PF_USER_FILEIO, PF_USER_CHARIO, PF_USER_CLIB. + - INCLUDE now aborts if file not found. + - Add +-> which allows you to add to a local variable, like +! . + - VALUE now works properly as a self fetching constant. + - Add CODE-SIZE and HEADERS-SIZE which lets you resize + dictionary saved using SAVE-FORTH. + - Added FILE?. Enter "FILE? THEN" to see what files THEN is defined in. + - Fixed bug in local variables that caused problems if compilation + aborted in a word with local variables. + - Added SEE which "disassembles" Forth words. See "see.fth". + - Added PRIVATE{ which can be used to hide low level support + words. See "private.fth". + +V12 - 12/1/96 + - Advance pointers in pfCopyMemory() and pfSetMemory() + to fix PF_NO_CLIB build. + - Increase size of array for PF_NO_MALLOC + - Eliminate many warnings involving type casts and (const char *) + - Fix error recovery in dictionary creation. + - Conditionally eliminate some include files for embedded builds. + - Cleanup some test files. + +V11 - 11/14/96 + - Added support for AUTO.INIT and AUTO.TERM. These are called + automagically when the Forth starts and quits. + - Change all int to int32. + - Changed DO LOOP to ?DO LOOP in ENDCASE and LV.MATCH + to fix hang when zero local variables. + - Align long word members in :STRUCT to avoid bus errors. + +V10 - 3/21/96 + - Close nested source files when INCLUDE aborts. + - Add PF_NO_CLIB option to reduce OS dependencies. + - Add CREATE-FILE, fix R/W access mode for OPEN-FILE. + - Use PF_FLOAT instead of FLOAT to avoid DOS problem. + - Add PF_HOST_DOS for compilation control. + - Shorten all long file names to fit in the 8.3 format + required by some primitive operating systems. My + apologies to those with modern computers who suffer + as a result. ;-) + +V9 - 10/13/95 + - Cleaned up and documented for alpha release. + - Added EXISTS? + - compile floats.fth if F* exists + - got PF_NO_SHELL working + - added TURNKEY to build headerless dictionary apps + - improved release script and rlsMakefile + - added FS@ and FS! for FLPT structure members + +V8 - 5/1/95 + - Report line number and line dump when INCLUDE aborts + - Abort if stack depth changes in colon definition. Helps + detect unbalanced conditionals (IF without THEN). + - Print bytes added by include. Helps determine current file. + - Added RETURN-CODE which is returned to caller, eg. UNIX shell. + - Changed Header and Code sizes to 60000 and 150000 + - Added check for overflowing dictionary when creating secondaries. + +V8 - 5/1/95 + - Report line number and line dump when INCLUDE aborts + - Abort if stack depth changes in colon definition. Helps + detect unbalanced conditionals (IF without THEN). + - Print bytes added by include. Helps determine current file. + - Added RETURN-CODE which is returned to caller, eg. UNIX shell. + - Changed Header and Code sizes to 60000 and 150000 + - Added check for overflowing dictionary when creating secondaries. + +V7 - 4/12/95 + - Converted to 3DO Teamware environment + - Added conditional compiler [IF] [ELSE] [THEN], use like #if + - Fixed W->S B->S for positive values + - Fixed ALLOCATE FREE validation. Was failing on some 'C' compilers. + - Added FILE-SIZE + - Fixed ERASE, now fills with zero instead of BL + +V6 - 3/16/95 + - Added floating point + - Changed NUMBER? to return a numeric type + - Support double number entry, eg. 234. -> 234 0 + +V5 - 3/9/95 + - Added pfReportError() + - Fixed problem with NumPrimitives growing and breaking dictionaries + - Reduced size of saved dictionaries, 198K -> 28K in one instance + - Funnel all terminal I/O through ioKey() and ioEmit() + - Removed dependencies on printf() except for debugging + +V4 - 3/6/95 + - Added smart conditionals to allow IF THEN DO LOOP etc. + outside colon definitions. + - Fixed RSHIFT, made logical. + - Added ARSHIFT for arithmetic shift. + - Added proper M* + - Added <> U> U< + - Added FM/MOD SM/REM /MOD MOD */ */MOD + - Added +LOOP EVALUATE UNLOOP EXIT + - Everything passes "coretest.fth" except UM/MOD FIND and WORD + +V3 - 3/1/95 + - Added support for embedded systems: PF_NO_FILEIO + and PF_NO_MALLOC. + - Fixed bug in dictionary loader that treated HERE as name relative. + +V2 - 8/94 + - made improvements necessary for use with M2 Verilog testing + +V1 - 5/94 + - built pForth from various Forths including HMSL + +---------------------------------------------------------- + + +Enjoy, +Phil Burk diff --git a/src/cmd/picoc/Makefile b/src/cmd/picoc/Makefile new file mode 100644 index 0000000..d704b7d --- /dev/null +++ b/src/cmd/picoc/Makefile @@ -0,0 +1,65 @@ +TOPSRC = $(shell cd ../../..; pwd) +include $(TOPSRC)/target.mk + +#CC=gcc +CFLAGS+= -g -DUNIX_HOST -DVER=\"`svnversion -n`\" -DFILENAME_MAX=64 -DL_tmpnam=30 -DCLOCKS_PER_SEC=80000000 -DPATH_MAX=200 -Os -Werror +LIBS=-lm -lc + +TARGET = picoc +SRCS = picoc.c table.c lex.c parse.c expression.c heap.c type.c \ + variable.c clibrary.c platform.c include.c debug.c \ + platform/platform_unix.c platform/library_unix.c \ + cstdlib/stdio.c cstdlib/math.c cstdlib/string.c cstdlib/stdlib.c \ + cstdlib/time.c cstdlib/errno.c cstdlib/ctype.c cstdlib/stdbool.c \ + cstdlib/unistd.c retrobsd.c +OBJS := $(SRCS:%.c=%.o) + +all: $(TARGET) + +$(TARGET): $(OBJS) + ${CC} ${LDFLAGS} -o ${TARGET}.elf ${OBJS} ${LIBS} + ${OBJDUMP} -S ${TARGET}.elf > ${TARGET}.dis + ${SIZE} ${TARGET}.elf + ${ELF2AOUT} ${TARGET}.elf $@ + +install: $(TARGET) + cp $(TARGET) $(TOPSRC)/bin + +test: all + (cd tests; make test) + +clean: + rm -f $(TARGET) $(OBJS) *~ *.elf *.dis + +count: + @echo "Core:" + @cat picoc.h interpreter.h picoc.c table.c lex.c parse.c expression.c platform.c heap.c type.c variable.c include.c debug.c | grep -v '^[ ]*/\*' | grep -v '^[ ]*$$' | wc + @echo "" + @echo "Everything:" + @cat $(SRCS) *.h */*.h | wc + +.PHONY: clibrary.c + +picoc.o: picoc.c picoc.h +table.o: table.c interpreter.h platform.h +lex.o: lex.c interpreter.h platform.h +parse.o: parse.c picoc.h interpreter.h platform.h +expression.o: expression.c interpreter.h platform.h +heap.o: heap.c interpreter.h platform.h +type.o: type.c interpreter.h platform.h +variable.o: variable.c interpreter.h platform.h +clibrary.o: clibrary.c picoc.h interpreter.h platform.h +platform.o: platform.c picoc.h interpreter.h platform.h +include.o: include.c picoc.h interpreter.h platform.h +debug.o: debug.c interpreter.h platform.h +platform/platform_unix.o: platform/platform_unix.c picoc.h interpreter.h platform.h +platform/library_unix.o: platform/library_unix.c interpreter.h platform.h +cstdlib/stdio.o: cstdlib/stdio.c interpreter.h platform.h +cstdlib/math.o: cstdlib/math.c interpreter.h platform.h +cstdlib/string.o: cstdlib/string.c interpreter.h platform.h +cstdlib/stdlib.o: cstdlib/stdlib.c interpreter.h platform.h +cstdlib/time.o: cstdlib/time.c interpreter.h platform.h +cstdlib/errno.o: cstdlib/errno.c interpreter.h platform.h +cstdlib/ctype.o: cstdlib/ctype.c interpreter.h platform.h +cstdlib/stdbool.o: cstdlib/stdbool.c interpreter.h platform.h +cstdlib/unistd.o: cstdlib/unistd.c interpreter.h platform.h diff --git a/src/cmd/picoc/README b/src/cmd/picoc/README new file mode 100644 index 0000000..18779d3 --- /dev/null +++ b/src/cmd/picoc/README @@ -0,0 +1,91 @@ +picoc +----- + +PicoC is a very small C interpreter for scripting. It was originally written +as a script language for a UAV's on-board flight system. It's also very +suitable for other robotic, embedded and non-embedded applications. + +The core C source code is around 3500 lines of code. It's not intended to be +a complete implementation of ISO C but it has all the essentials. When +compiled it only takes a few k of code space and is also very sparing of +data space. This means it can work well in small embedded devices. It's also +a fun example of how to create a very small language implementation while +still keeping the code readable. + +picoc is now feature frozen. Since it's important that it remain small it's +intended that no more major features will be added from now on. It's been +tested on x86-32, x86-64, powerpc, arm, ultrasparc, HP-PA and blackfin +processors and is easy to port to new targets. + + +Compiling picoc +--------------- + +picoc can be compiled for a UNIX/Linux/POSIX host by typing "make". + +The test suite can be run by typing "make test". + + +Porting picoc +------------- + +platform.h is where you select your platform type and specify the includes +etc. for your platform. + +platform_XXX.c contains support functions so the compiler can work on +your platform, such as how to write characters to the console etc.. + +platform_library.c contains your library of functions you want to make +available to user programs. + +There's also a clibrary.c which contains user library functions like +printf() which are platform-independent. + +Porting the system will involve setting up suitable includes and defines +in platform.h, writing some I/O routines in platform_XXX.c, putting +whatever user functions you want in platform_library.c and then changing +the main program in picoc.c to whatever you need to do to get programs +into the system. + +platform.h is set to UNIX_HOST by default so tests can be easily run on +a UNIX system. You'll need to specify your own host setup dependent on +your target platform. + + +Copyright +--------- + +picoc is published under the "New BSD License". +http://www.opensource.org/licenses/bsd-license.php + + +Copyright (c) 2009-2011, Zik Saleeba +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + * Neither the name of the Zik Saleeba nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(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 --git a/src/cmd/picoc/clibrary.c b/src/cmd/picoc/clibrary.c new file mode 100644 index 0000000..a87ebfd --- /dev/null +++ b/src/cmd/picoc/clibrary.c @@ -0,0 +1,679 @@ +/* picoc mini standard C library - provides an optional tiny C standard library + * if BUILTIN_MINI_STDLIB is defined */ + +#include "picoc.h" +#include "interpreter.h" + +/* the picoc version string */ +static const char *VersionString = NULL; + +/* endian-ness checking */ +static const int __ENDIAN_CHECK__ = 1; + +static int BigEndian = 0; +static int LittleEndian = 0; + + +/* global initialisation for libraries */ +void LibraryInit() +{ + /* define the version number macro */ + VersionString = TableStrRegister(PICOC_VERSION); + VariableDefinePlatformVar(NULL, "PICOC_VERSION", CharPtrType, (union AnyValue *)&VersionString, FALSE); + + /* define endian-ness macros */ + BigEndian = ((*(char*)&__ENDIAN_CHECK__) == 0); + LittleEndian = ((*(char*)&__ENDIAN_CHECK__) == 1); + + VariableDefinePlatformVar(NULL, "BIG_ENDIAN", &IntType, (union AnyValue *)&BigEndian, FALSE); + VariableDefinePlatformVar(NULL, "LITTLE_ENDIAN", &IntType, (union AnyValue *)&LittleEndian, FALSE); +} + +/* add a library */ +void LibraryAdd(struct Table *GlobalTable, const char *LibraryName, struct LibraryFunction *FuncList) +{ + struct ParseState Parser; + int Count; + char *Identifier; + struct ValueType *ReturnType; + struct Value *NewValue; + void *Tokens; + char *IntrinsicName = TableStrRegister("c library"); + + /* read all the library definitions */ + for (Count = 0; FuncList[Count].Prototype != NULL; Count++) + { + Tokens = LexAnalyse(IntrinsicName, FuncList[Count].Prototype, strlen((char *)FuncList[Count].Prototype), NULL); + LexInitParser(&Parser, FuncList[Count].Prototype, Tokens, IntrinsicName, TRUE, FALSE); + TypeParse(&Parser, &ReturnType, &Identifier, NULL); + NewValue = ParseFunctionDefinition(&Parser, ReturnType, Identifier); + NewValue->Val->FuncDef.Intrinsic = FuncList[Count].Func; + HeapFreeMem(Tokens); + } +} + +/* print a type to a stream without using printf/sprintf */ +void PrintType(struct ValueType *Typ, IOFILE *Stream) +{ + switch (Typ->Base) + { + case TypeVoid: PrintStr("void", Stream); break; + case TypeInt: PrintStr("int", Stream); break; + case TypeShort: PrintStr("short", Stream); break; + case TypeChar: PrintStr("char", Stream); break; + case TypeLong: PrintStr("long", Stream); break; + case TypeUnsignedInt: PrintStr("unsigned int", Stream); break; + case TypeUnsignedShort: PrintStr("unsigned short", Stream); break; + case TypeUnsignedLong: PrintStr("unsigned long", Stream); break; +#ifndef NO_FP + case TypeFP: PrintStr("double", Stream); break; +#endif + case TypeFunction: PrintStr("function", Stream); break; + case TypeMacro: PrintStr("macro", Stream); break; + case TypePointer: if (Typ->FromType) PrintType(Typ->FromType, Stream); PrintCh('*', Stream); break; + case TypeArray: PrintType(Typ->FromType, Stream); PrintCh('[', Stream); if (Typ->ArraySize != 0) PrintSimpleInt(Typ->ArraySize, Stream); PrintCh(']', Stream); break; + case TypeStruct: PrintStr("struct ", Stream); PrintStr(Typ->Identifier, Stream); break; + case TypeUnion: PrintStr("union ", Stream); PrintStr(Typ->Identifier, Stream); break; + case TypeEnum: PrintStr("enum ", Stream); PrintStr(Typ->Identifier, Stream); break; + case TypeGotoLabel: PrintStr("goto label ", Stream); break; + case Type_Type: PrintStr("type ", Stream); break; + } +} + + +#ifdef BUILTIN_MINI_STDLIB + +/* + * This is a simplified standard library for small embedded systems. It doesn't require + * a system stdio library to operate. + * + * A more complete standard library for larger computers is in the library_XXX.c files. + */ + +IOFILE *CStdOut; +IOFILE CStdOutBase; + +static int TRUEValue = 1; +static int ZeroValue = 0; + +void BasicIOInit() +{ + CStdOutBase.Putch = &PlatformPutc; + CStdOut = &CStdOutBase; +} + +/* initialise the C library */ +void CLibraryInit() +{ + /* define some constants */ + VariableDefinePlatformVar(NULL, "NULL", &IntType, (union AnyValue *)&ZeroValue, FALSE); + VariableDefinePlatformVar(NULL, "TRUE", &IntType, (union AnyValue *)&TRUEValue, FALSE); + VariableDefinePlatformVar(NULL, "FALSE", &IntType, (union AnyValue *)&ZeroValue, FALSE); +} + +/* stream for writing into strings */ +void SPutc(unsigned char Ch, union OutputStreamInfo *Stream) +{ + struct StringOutputStream *Out = &Stream->Str; + *Out->WritePos++ = Ch; +} + +/* print a character to a stream without using printf/sprintf */ +void PrintCh(char OutCh, struct OutputStream *Stream) +{ + (*Stream->Putch)(OutCh, &Stream->i); +} + +/* print a string to a stream without using printf/sprintf */ +void PrintStr(const char *Str, struct OutputStream *Stream) +{ + while (*Str != 0) + PrintCh(*Str++, Stream); +} + +/* print a single character a given number of times */ +void PrintRepeatedChar(char ShowChar, int Length, struct OutputStream *Stream) +{ + while (Length-- > 0) + PrintCh(ShowChar, Stream); +} + +/* print an unsigned integer to a stream without using printf/sprintf */ +void PrintUnsigned(unsigned long Num, unsigned int Base, int FieldWidth, int ZeroPad, int LeftJustify, struct OutputStream *Stream) +{ + char Result[33]; + int ResPos = sizeof(Result); + + Result[--ResPos] = '\0'; + if (Num == 0) + Result[--ResPos] = '0'; + + while (Num > 0) + { + unsigned long NextNum = Num / Base; + unsigned long Digit = Num - NextNum * Base; + if (Digit < 10) + Result[--ResPos] = '0' + Digit; + else + Result[--ResPos] = 'a' + Digit - 10; + + Num = NextNum; + } + + if (FieldWidth > 0 && !LeftJustify) + PrintRepeatedChar(ZeroPad ? '0' : ' ', FieldWidth - (sizeof(Result) - 1 - ResPos), Stream); + + PrintStr(&Result[ResPos], Stream); + + if (FieldWidth > 0 && LeftJustify) + PrintRepeatedChar(' ', FieldWidth - (sizeof(Result) - 1 - ResPos), Stream); +} + +/* print an integer to a stream without using printf/sprintf */ +void PrintSimpleInt(long Num, struct OutputStream *Stream) +{ + PrintInt(Num, -1, FALSE, FALSE, Stream); +} + +/* print an integer to a stream without using printf/sprintf */ +void PrintInt(long Num, int FieldWidth, int ZeroPad, int LeftJustify, struct OutputStream *Stream) +{ + if (Num < 0) + { + PrintCh('-', Stream); + Num = -Num; + if (FieldWidth != 0) + FieldWidth--; + } + + PrintUnsigned((unsigned long)Num, 10, FieldWidth, ZeroPad, LeftJustify, Stream); +} + +#ifndef NO_FP +/* print a double to a stream without using printf/sprintf */ +void PrintFP(double Num, struct OutputStream *Stream) +{ + int Exponent = 0; + int MaxDecimal; + + if (Num < 0) + { + PrintCh('-', Stream); + Num = -Num; + } + + if (Num >= 1e7) + Exponent = log10(Num); + else if (Num <= 1e-7 && Num != 0.0) + Exponent = log10(Num) - 0.999999999; + + Num /= pow(10.0, Exponent); + PrintInt((long)Num, 0, FALSE, FALSE, Stream); + PrintCh('.', Stream); + Num = (Num - (long)Num) * 10; + if (abs(Num) >= 1e-7) + { + for (MaxDecimal = 6; MaxDecimal > 0 && abs(Num) >= 1e-7; Num = (Num - (long)(Num + 1e-7)) * 10, MaxDecimal--) + PrintCh('0' + (long)(Num + 1e-7), Stream); + } + else + PrintCh('0', Stream); + + if (Exponent != 0) + { + PrintCh('e', Stream); + PrintInt(Exponent, 0, FALSE, FALSE, Stream); + } +} +#endif + +/* intrinsic functions made available to the language */ +void GenericPrintf(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs, struct OutputStream *Stream) +{ + char *FPos; + struct Value *NextArg = Param[0]; + struct ValueType *FormatType; + int ArgCount = 1; + int LeftJustify = FALSE; + int ZeroPad = FALSE; + int FieldWidth = 0; + char *Format = Param[0]->Val->Pointer; + + for (FPos = Format; *FPos != '\0'; FPos++) + { + if (*FPos == '%') + { + FPos++; + if (*FPos == '-') + { + /* a leading '-' means left justify */ + LeftJustify = TRUE; + FPos++; + } + + if (*FPos == '0') + { + /* a leading zero means zero pad a decimal number */ + ZeroPad = TRUE; + FPos++; + } + + /* get any field width in the format */ + while (isdigit((int)*FPos)) + FieldWidth = FieldWidth * 10 + (*FPos++ - '0'); + + /* now check the format type */ + switch (*FPos) + { + case 's': FormatType = CharPtrType; break; + case 'd': case 'u': case 'x': case 'b': case 'c': FormatType = &IntType; break; +#ifndef NO_FP + case 'f': FormatType = &FPType; break; +#endif + case '%': PrintCh('%', Stream); FormatType = NULL; break; + case '\0': FPos--; FormatType = NULL; break; + default: PrintCh(*FPos, Stream); FormatType = NULL; break; + } + + if (FormatType != NULL) + { + /* we have to format something */ + if (ArgCount >= NumArgs) + PrintStr("XXX", Stream); /* not enough parameters for format */ + else + { + NextArg = (struct Value *)((char *)NextArg + MEM_ALIGN(sizeof(struct Value) + TypeStackSizeValue(NextArg))); + if (NextArg->Typ != FormatType && + !((FormatType == &IntType || *FPos == 'f') && IS_NUMERIC_COERCIBLE(NextArg)) && + !(FormatType == CharPtrType && (NextArg->Typ->Base == TypePointer || + (NextArg->Typ->Base == TypeArray && NextArg->Typ->FromType->Base == TypeChar) ) ) ) + PrintStr("XXX", Stream); /* bad type for format */ + else + { + switch (*FPos) + { + case 's': + { + char *Str; + + if (NextArg->Typ->Base == TypePointer) + Str = NextArg->Val->Pointer; + else + Str = &NextArg->Val->ArrayMem[0]; + + if (Str == NULL) + PrintStr("NULL", Stream); + else + PrintStr(Str, Stream); + break; + } + case 'd': PrintInt(ExpressionCoerceInteger(NextArg), FieldWidth, ZeroPad, LeftJustify, Stream); break; + case 'u': PrintUnsigned(ExpressionCoerceUnsignedInteger(NextArg), 10, FieldWidth, ZeroPad, LeftJustify, Stream); break; + case 'x': PrintUnsigned(ExpressionCoerceUnsignedInteger(NextArg), 16, FieldWidth, ZeroPad, LeftJustify, Stream); break; + case 'b': PrintUnsigned(ExpressionCoerceUnsignedInteger(NextArg), 2, FieldWidth, ZeroPad, LeftJustify, Stream); break; + case 'c': PrintCh(ExpressionCoerceUnsignedInteger(NextArg), Stream); break; +#ifndef NO_FP + case 'f': PrintFP(ExpressionCoerceFP(NextArg), Stream); break; +#endif + } + } + } + + ArgCount++; + } + } + else + PrintCh(*FPos, Stream); + } +} + +/* printf(): print to console output */ +void LibPrintf(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + struct OutputStream ConsoleStream; + + ConsoleStream.Putch = &PlatformPutc; + GenericPrintf(Parser, ReturnValue, Param, NumArgs, &ConsoleStream); +} + +/* sprintf(): print to a string */ +void LibSPrintf(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + struct OutputStream StrStream; + + StrStream.Putch = &SPutc; + StrStream.i.Str.Parser = Parser; + StrStream.i.Str.WritePos = Param[0]->Val->Pointer; + + GenericPrintf(Parser, ReturnValue, Param+1, NumArgs-1, &StrStream); + PrintCh(0, &StrStream); + ReturnValue->Val->Pointer = *Param; +} + +/* get a line of input. protected from buffer overrun */ +void LibGets(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Pointer = PlatformGetLine(Param[0]->Val->Pointer, GETS_BUF_MAX, NULL); + if (ReturnValue->Val->Pointer != NULL) + { + char *EOLPos = strchr(Param[0]->Val->Pointer, '\n'); + if (EOLPos != NULL) + *EOLPos = '\0'; + } +} + +void LibGetc(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = PlatformGetCharacter(); +} + +void LibExit(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + PlatformExit(Param[0]->Val->Integer); +} + +#ifdef PICOC_LIBRARY +void LibSin(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->FP = sin(Param[0]->Val->FP); +} + +void LibCos(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->FP = cos(Param[0]->Val->FP); +} + +void LibTan(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->FP = tan(Param[0]->Val->FP); +} + +void LibAsin(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->FP = asin(Param[0]->Val->FP); +} + +void LibAcos(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->FP = acos(Param[0]->Val->FP); +} + +void LibAtan(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->FP = atan(Param[0]->Val->FP); +} + +void LibSinh(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->FP = sinh(Param[0]->Val->FP); +} + +void LibCosh(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->FP = cosh(Param[0]->Val->FP); +} + +void LibTanh(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->FP = tanh(Param[0]->Val->FP); +} + +void LibExp(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->FP = exp(Param[0]->Val->FP); +} + +void LibFabs(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->FP = fabs(Param[0]->Val->FP); +} + +void LibLog(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->FP = log(Param[0]->Val->FP); +} + +void LibLog10(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->FP = log10(Param[0]->Val->FP); +} + +void LibPow(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->FP = pow(Param[0]->Val->FP, Param[1]->Val->FP); +} + +void LibSqrt(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->FP = sqrt(Param[0]->Val->FP); +} + +void LibRound(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->FP = floor(Param[0]->Val->FP + 0.5); /* XXX - fix for soft float */ +} + +void LibCeil(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->FP = ceil(Param[0]->Val->FP); +} + +void LibFloor(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->FP = floor(Param[0]->Val->FP); +} +#endif + +#ifndef NO_STRING_FUNCTIONS +void LibMalloc(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Pointer = malloc(Param[0]->Val->Integer); +} + +#ifndef NO_CALLOC +void LibCalloc(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Pointer = calloc(Param[0]->Val->Integer, Param[1]->Val->Integer); +} +#endif + +#ifndef NO_REALLOC +void LibRealloc(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Pointer = realloc(Param[0]->Val->Pointer, Param[1]->Val->Integer); +} +#endif + +void LibFree(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + free(Param[0]->Val->Pointer); +} + +void LibStrcpy(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + char *To = (char *)Param[0]->Val->Pointer; + char *From = (char *)Param[1]->Val->Pointer; + + while (*From != '\0') + *To++ = *From++; + + *To = '\0'; +} + +void LibStrncpy(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + char *To = (char *)Param[0]->Val->Pointer; + char *From = (char *)Param[1]->Val->Pointer; + int Len = Param[2]->Val->Integer; + + for (; *From != '\0' && Len > 0; Len--) + *To++ = *From++; + + if (Len > 0) + *To = '\0'; +} + +void LibStrcmp(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + char *Str1 = (char *)Param[0]->Val->Pointer; + char *Str2 = (char *)Param[1]->Val->Pointer; + int StrEnded; + + for (StrEnded = FALSE; !StrEnded; StrEnded = (*Str1 == '\0' || *Str2 == '\0'), Str1++, Str2++) + { + if (*Str1 < *Str2) { ReturnValue->Val->Integer = -1; return; } + else if (*Str1 > *Str2) { ReturnValue->Val->Integer = 1; return; } + } + + ReturnValue->Val->Integer = 0; +} + +void LibStrncmp(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + char *Str1 = (char *)Param[0]->Val->Pointer; + char *Str2 = (char *)Param[1]->Val->Pointer; + int Len = Param[2]->Val->Integer; + int StrEnded; + + for (StrEnded = FALSE; !StrEnded && Len > 0; StrEnded = (*Str1 == '\0' || *Str2 == '\0'), Str1++, Str2++, Len--) + { + if (*Str1 < *Str2) { ReturnValue->Val->Integer = -1; return; } + else if (*Str1 > *Str2) { ReturnValue->Val->Integer = 1; return; } + } + + ReturnValue->Val->Integer = 0; +} + +void LibStrcat(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + char *To = (char *)Param[0]->Val->Pointer; + char *From = (char *)Param[1]->Val->Pointer; + + while (*To != '\0') + To++; + + while (*From != '\0') + *To++ = *From++; + + *To = '\0'; +} + +void LibIndex(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + char *Pos = (char *)Param[0]->Val->Pointer; + int SearchChar = Param[1]->Val->Integer; + + while (*Pos != '\0' && *Pos != SearchChar) + Pos++; + + if (*Pos != SearchChar) + ReturnValue->Val->Pointer = NULL; + else + ReturnValue->Val->Pointer = Pos; +} + +void LibRindex(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + char *Pos = (char *)Param[0]->Val->Pointer; + int SearchChar = Param[1]->Val->Integer; + + ReturnValue->Val->Pointer = NULL; + for (; *Pos != '\0'; Pos++) + { + if (*Pos == SearchChar) + ReturnValue->Val->Pointer = Pos; + } +} + +void LibStrlen(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + char *Pos = (char *)Param[0]->Val->Pointer; + int Len; + + for (Len = 0; *Pos != '\0'; Pos++) + Len++; + + ReturnValue->Val->Integer = Len; +} + +void LibMemset(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + /* we can use the system memset() */ + memset(Param[0]->Val->Pointer, Param[1]->Val->Integer, Param[2]->Val->Integer); +} + +void LibMemcpy(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + /* we can use the system memcpy() */ + memcpy(Param[0]->Val->Pointer, Param[1]->Val->Pointer, Param[2]->Val->Integer); +} + +void LibMemcmp(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + unsigned char *Mem1 = (unsigned char *)Param[0]->Val->Pointer; + unsigned char *Mem2 = (unsigned char *)Param[1]->Val->Pointer; + int Len = Param[2]->Val->Integer; + + for (; Len > 0; Mem1++, Mem2++, Len--) + { + if (*Mem1 < *Mem2) { ReturnValue->Val->Integer = -1; return; } + else if (*Mem1 > *Mem2) { ReturnValue->Val->Integer = 1; return; } + } + + ReturnValue->Val->Integer = 0; +} +#endif + +/* list of all library functions and their prototypes */ +struct LibraryFunction CLibrary[] = +{ + { LibPrintf, "void printf(char *, ...);" }, + { LibSPrintf, "char *sprintf(char *, char *, ...);" }, + { LibGets, "char *gets(char *);" }, + { LibGetc, "int getchar();" }, + { LibExit, "void exit(int);" }, +#ifdef PICOC_LIBRARY + { LibSin, "float sin(float);" }, + { LibCos, "float cos(float);" }, + { LibTan, "float tan(float);" }, + { LibAsin, "float asin(float);" }, + { LibAcos, "float acos(float);" }, + { LibAtan, "float atan(float);" }, + { LibSinh, "float sinh(float);" }, + { LibCosh, "float cosh(float);" }, + { LibTanh, "float tanh(float);" }, + { LibExp, "float exp(float);" }, + { LibFabs, "float fabs(float);" }, + { LibLog, "float log(float);" }, + { LibLog10, "float log10(float);" }, + { LibPow, "float pow(float,float);" }, + { LibSqrt, "float sqrt(float);" }, + { LibRound, "float round(float);" }, + { LibCeil, "float ceil(float);" }, + { LibFloor, "float floor(float);" }, +#endif + { LibMalloc, "void *malloc(int);" }, +#ifndef NO_CALLOC + { LibCalloc, "void *calloc(int,int);" }, +#endif +#ifndef NO_REALLOC + { LibRealloc, "void *realloc(void *,int);" }, +#endif + { LibFree, "void free(void *);" }, +#ifndef NO_STRING_FUNCTIONS + { LibStrcpy, "void strcpy(char *,char *);" }, + { LibStrncpy, "void strncpy(char *,char *,int);" }, + { LibStrcmp, "int strcmp(char *,char *);" }, + { LibStrncmp, "int strncmp(char *,char *,int);" }, + { LibStrcat, "void strcat(char *,char *);" }, + { LibIndex, "char *index(char *,int);" }, + { LibRindex, "char *rindex(char *,int);" }, + { LibStrlen, "int strlen(char *);" }, + { LibMemset, "void memset(void *,int,int);" }, + { LibMemcpy, "void memcpy(void *,void *,int);" }, + { LibMemcmp, "int memcmp(void *,void *,int);" }, +#endif + { NULL, NULL } +}; + +#endif /* BUILTIN_MINI_STDLIB */ diff --git a/src/cmd/picoc/cstdlib/ctype.c b/src/cmd/picoc/cstdlib/ctype.c new file mode 100644 index 0000000..d1e8140 --- /dev/null +++ b/src/cmd/picoc/cstdlib/ctype.c @@ -0,0 +1,110 @@ +/* string.h library for large systems - small embedded systems use clibrary.c instead */ +#include +#include "../interpreter.h" + +#ifndef BUILTIN_MINI_STDLIB + +void StdIsalnum(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = isalnum(Param[0]->Val->Integer); +} + +void StdIsalpha(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = isalpha(Param[0]->Val->Integer); +} + +void StdIsblank(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + int ch = Param[0]->Val->Integer; + ReturnValue->Val->Integer = (ch == ' ') | (ch == '\t'); +} + +void StdIscntrl(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = iscntrl(Param[0]->Val->Integer); +} + +void StdIsdigit(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = isdigit(Param[0]->Val->Integer); +} + +void StdIsgraph(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = isgraph(Param[0]->Val->Integer); +} + +void StdIslower(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = islower(Param[0]->Val->Integer); +} + +void StdIsprint(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = isprint(Param[0]->Val->Integer); +} + +void StdIspunct(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = ispunct(Param[0]->Val->Integer); +} + +void StdIsspace(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = isspace(Param[0]->Val->Integer); +} + +void StdIsupper(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = isupper(Param[0]->Val->Integer); +} + +void StdIsxdigit(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = isxdigit(Param[0]->Val->Integer); +} + +void StdTolower(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = tolower(Param[0]->Val->Integer); +} + +void StdToupper(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = toupper(Param[0]->Val->Integer); +} + +void StdIsascii(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = isascii(Param[0]->Val->Integer); +} + +void StdToascii(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = toascii(Param[0]->Val->Integer); +} + +/* all string.h functions */ +struct LibraryFunction StdCtypeFunctions[] = +{ + { StdIsalnum, "int isalnum(int);" }, + { StdIsalpha, "int isalpha(int);" }, + { StdIsblank, "int isblank(int);" }, + { StdIscntrl, "int iscntrl(int);" }, + { StdIsdigit, "int isdigit(int);" }, + { StdIsgraph, "int isgraph(int);" }, + { StdIslower, "int islower(int);" }, + { StdIsprint, "int isprint(int);" }, + { StdIspunct, "int ispunct(int);" }, + { StdIsspace, "int isspace(int);" }, + { StdIsupper, "int isupper(int);" }, + { StdIsxdigit, "int isxdigit(int);" }, + { StdTolower, "int tolower(int);" }, + { StdToupper, "int toupper(int);" }, + { StdIsascii, "int isascii(int);" }, + { StdToascii, "int toascii(int);" }, + { NULL, NULL } +}; + +#endif /* !BUILTIN_MINI_STDLIB */ diff --git a/src/cmd/picoc/cstdlib/errno.c b/src/cmd/picoc/cstdlib/errno.c new file mode 100644 index 0000000..e5becbf --- /dev/null +++ b/src/cmd/picoc/cstdlib/errno.c @@ -0,0 +1,655 @@ +/* string.h library for large systems - small embedded systems use clibrary.c instead */ +#include +#include "../interpreter.h" + +#ifndef BUILTIN_MINI_STDLIB + +#ifdef EACCES +static int EACCESValue = EACCES; +#endif + +#ifdef EADDRINUSE +static int EADDRINUSEValue = EADDRINUSE; +#endif + +#ifdef EADDRNOTAVAIL +static int EADDRNOTAVAILValue = EADDRNOTAVAIL; +#endif + +#ifdef EAFNOSUPPORT +static int EAFNOSUPPORTValue = EAFNOSUPPORT; +#endif + +#ifdef EAGAIN +static int EAGAINValue = EAGAIN; +#endif + +#ifdef EALREADY +static int EALREADYValue = EALREADY; +#endif + +#ifdef EBADF +static int EBADFValue = EBADF; +#endif + +#ifdef EBADMSG +static int EBADMSGValue = EBADMSG; +#endif + +#ifdef EBUSY +static int EBUSYValue = EBUSY; +#endif + +#ifdef ECANCELED +static int ECANCELEDValue = ECANCELED; +#endif + +#ifdef ECHILD +static int ECHILDValue = ECHILD; +#endif + +#ifdef ECONNABORTED +static int ECONNABORTEDValue = ECONNABORTED; +#endif + +#ifdef ECONNREFUSED +static int ECONNREFUSEDValue = ECONNREFUSED; +#endif + +#ifdef ECONNRESET +static int ECONNRESETValue = ECONNRESET; +#endif + +#ifdef EDEADLK +static int EDEADLKValue = EDEADLK; +#endif + +#ifdef EDESTADDRREQ +static int EDESTADDRREQValue = EDESTADDRREQ; +#endif + +#ifdef EDOM +static int EDOMValue = EDOM; +#endif + +#ifdef EDQUOT +static int EDQUOTValue = EDQUOT; +#endif + +#ifdef EEXIST +static int EEXISTValue = EEXIST; +#endif + +#ifdef EFAULT +static int EFAULTValue = EFAULT; +#endif + +#ifdef EFBIG +static int EFBIGValue = EFBIG; +#endif + +#ifdef EHOSTUNREACH +static int EHOSTUNREACHValue = EHOSTUNREACH; +#endif + +#ifdef EIDRM +static int EIDRMValue = EIDRM; +#endif + +#ifdef EILSEQ +static int EILSEQValue = EILSEQ; +#endif + +#ifdef EINPROGRESS +static int EINPROGRESSValue = EINPROGRESS; +#endif + +#ifdef EINTR +static int EINTRValue = EINTR; +#endif + +#ifdef EINVAL +static int EINVALValue = EINVAL; +#endif + +#ifdef EIO +static int EIOValue = EIO; +#endif + +#ifdef EISCONN +static int EISCONNValue = EISCONN; +#endif + +#ifdef EISDIR +static int EISDIRValue = EISDIR; +#endif + +#ifdef ELOOP +static int ELOOPValue = ELOOP; +#endif + +#ifdef EMFILE +static int EMFILEValue = EMFILE; +#endif + +#ifdef EMLINK +static int EMLINKValue = EMLINK; +#endif + +#ifdef EMSGSIZE +static int EMSGSIZEValue = EMSGSIZE; +#endif + +#ifdef EMULTIHOP +static int EMULTIHOPValue = EMULTIHOP; +#endif + +#ifdef ENAMETOOLONG +static int ENAMETOOLONGValue = ENAMETOOLONG; +#endif + +#ifdef ENETDOWN +static int ENETDOWNValue = ENETDOWN; +#endif + +#ifdef ENETRESET +static int ENETRESETValue = ENETRESET; +#endif + +#ifdef ENETUNREACH +static int ENETUNREACHValue = ENETUNREACH; +#endif + +#ifdef ENFILE +static int ENFILEValue = ENFILE; +#endif + +#ifdef ENOBUFS +static int ENOBUFSValue = ENOBUFS; +#endif + +#ifdef ENODATA +static int ENODATAValue = ENODATA; +#endif + +#ifdef ENODEV +static int ENODEVValue = ENODEV; +#endif + +#ifdef ENOENT +static int ENOENTValue = ENOENT; +#endif + +#ifdef ENOEXEC +static int ENOEXECValue = ENOEXEC; +#endif + +#ifdef ENOLCK +static int ENOLCKValue = ENOLCK; +#endif + +#ifdef ENOLINK +static int ENOLINKValue = ENOLINK; +#endif + +#ifdef ENOMEM +static int ENOMEMValue = ENOMEM; +#endif + +#ifdef ENOMSG +static int ENOMSGValue = ENOMSG; +#endif + +#ifdef ENOPROTOOPT +static int ENOPROTOOPTValue = ENOPROTOOPT; +#endif + +#ifdef ENOSPC +static int ENOSPCValue = ENOSPC; +#endif + +#ifdef ENOSR +static int ENOSRValue = ENOSR; +#endif + +#ifdef ENOSTR +static int ENOSTRValue = ENOSTR; +#endif + +#ifdef ENOSYS +static int ENOSYSValue = ENOSYS; +#endif + +#ifdef ENOTCONN +static int ENOTCONNValue = ENOTCONN; +#endif + +#ifdef ENOTDIR +static int ENOTDIRValue = ENOTDIR; +#endif + +#ifdef ENOTEMPTY +static int ENOTEMPTYValue = ENOTEMPTY; +#endif + +#ifdef ENOTRECOVERABLE +static int ENOTRECOVERABLEValue = ENOTRECOVERABLE; +#endif + +#ifdef ENOTSOCK +static int ENOTSOCKValue = ENOTSOCK; +#endif + +#ifdef ENOTSUP +static int ENOTSUPValue = ENOTSUP; +#endif + +#ifdef ENOTTY +static int ENOTTYValue = ENOTTY; +#endif + +#ifdef ENXIO +static int ENXIOValue = ENXIO; +#endif + +#ifdef EOPNOTSUPP +static int EOPNOTSUPPValue = EOPNOTSUPP; +#endif + +#ifdef EOVERFLOW +static int EOVERFLOWValue = EOVERFLOW; +#endif + +#ifdef EOWNERDEAD +static int EOWNERDEADValue = EOWNERDEAD; +#endif + +#ifdef EPERM +static int EPERMValue = EPERM; +#endif + +#ifdef EPIPE +static int EPIPEValue = EPIPE; +#endif + +#ifdef EPROTO +static int EPROTOValue = EPROTO; +#endif + +#ifdef EPROTONOSUPPORT +static int EPROTONOSUPPORTValue = EPROTONOSUPPORT; +#endif + +#ifdef EPROTOTYPE +static int EPROTOTYPEValue = EPROTOTYPE; +#endif + +#ifdef ERANGE +static int ERANGEValue = ERANGE; +#endif + +#ifdef EROFS +static int EROFSValue = EROFS; +#endif + +#ifdef ESPIPE +static int ESPIPEValue = ESPIPE; +#endif + +#ifdef ESRCH +static int ESRCHValue = ESRCH; +#endif + +#ifdef ESTALE +static int ESTALEValue = ESTALE; +#endif + +#ifdef ETIME +static int ETIMEValue = ETIME; +#endif + +#ifdef ETIMEDOUT +static int ETIMEDOUTValue = ETIMEDOUT; +#endif + +#ifdef ETXTBSY +static int ETXTBSYValue = ETXTBSY; +#endif + +#ifdef EWOULDBLOCK +static int EWOULDBLOCKValue = EWOULDBLOCK; +#endif + +#ifdef EXDEV +static int EXDEVValue = EXDEV; +#endif + + +/* creates various system-dependent definitions */ +void StdErrnoSetupFunc(void) +{ + /* defines */ +#ifdef EACCES + VariableDefinePlatformVar(NULL, "EACCES", &IntType, (union AnyValue *)&EACCESValue, FALSE); +#endif + +#ifdef EADDRINUSE + VariableDefinePlatformVar(NULL, "EADDRINUSE", &IntType, (union AnyValue *)&EADDRINUSEValue, FALSE); +#endif + +#ifdef EADDRNOTAVAIL + VariableDefinePlatformVar(NULL, "EADDRNOTAVAIL", &IntType, (union AnyValue *)&EADDRNOTAVAILValue, FALSE); +#endif + +#ifdef EAFNOSUPPORT + VariableDefinePlatformVar(NULL, "EAFNOSUPPORT", &IntType, (union AnyValue *)&EAFNOSUPPORTValue, FALSE); +#endif + +#ifdef EAGAIN + VariableDefinePlatformVar(NULL, "EAGAIN", &IntType, (union AnyValue *)&EAGAINValue, FALSE); +#endif + +#ifdef EALREADY + VariableDefinePlatformVar(NULL, "EALREADY", &IntType, (union AnyValue *)&EALREADYValue, FALSE); +#endif + +#ifdef EBADF + VariableDefinePlatformVar(NULL, "EBADF", &IntType, (union AnyValue *)&EBADFValue, FALSE); +#endif + +#ifdef EBADMSG + VariableDefinePlatformVar(NULL, "EBADMSG", &IntType, (union AnyValue *)&EBADMSGValue, FALSE); +#endif + +#ifdef EBUSY + VariableDefinePlatformVar(NULL, "EBUSY", &IntType, (union AnyValue *)&EBUSYValue, FALSE); +#endif + +#ifdef ECANCELED + VariableDefinePlatformVar(NULL, "ECANCELED", &IntType, (union AnyValue *)&ECANCELEDValue, FALSE); +#endif + +#ifdef ECHILD + VariableDefinePlatformVar(NULL, "ECHILD", &IntType, (union AnyValue *)&ECHILDValue, FALSE); +#endif + +#ifdef ECONNABORTED + VariableDefinePlatformVar(NULL, "ECONNABORTED", &IntType, (union AnyValue *)&ECONNABORTEDValue, FALSE); +#endif + +#ifdef ECONNREFUSED + VariableDefinePlatformVar(NULL, "ECONNREFUSED", &IntType, (union AnyValue *)&ECONNREFUSEDValue, FALSE); +#endif + +#ifdef ECONNRESET + VariableDefinePlatformVar(NULL, "ECONNRESET", &IntType, (union AnyValue *)&ECONNRESETValue, FALSE); +#endif + +#ifdef EDEADLK + VariableDefinePlatformVar(NULL, "EDEADLK", &IntType, (union AnyValue *)&EDEADLKValue, FALSE); +#endif + +#ifdef EDESTADDRREQ + VariableDefinePlatformVar(NULL, "EDESTADDRREQ", &IntType, (union AnyValue *)&EDESTADDRREQValue, FALSE); +#endif + +#ifdef EDOM + VariableDefinePlatformVar(NULL, "EDOM", &IntType, (union AnyValue *)&EDOMValue, FALSE); +#endif + +#ifdef EDQUOT + VariableDefinePlatformVar(NULL, "EDQUOT", &IntType, (union AnyValue *)&EDQUOTValue, FALSE); +#endif + +#ifdef EEXIST + VariableDefinePlatformVar(NULL, "EEXIST", &IntType, (union AnyValue *)&EEXISTValue, FALSE); +#endif + +#ifdef EFAULT + VariableDefinePlatformVar(NULL, "EFAULT", &IntType, (union AnyValue *)&EFAULTValue, FALSE); +#endif + +#ifdef EFBIG + VariableDefinePlatformVar(NULL, "EFBIG", &IntType, (union AnyValue *)&EFBIGValue, FALSE); +#endif + +#ifdef EHOSTUNREACH + VariableDefinePlatformVar(NULL, "EHOSTUNREACH", &IntType, (union AnyValue *)&EHOSTUNREACHValue, FALSE); +#endif + +#ifdef EIDRM + VariableDefinePlatformVar(NULL, "EIDRM", &IntType, (union AnyValue *)&EIDRMValue, FALSE); +#endif + +#ifdef EILSEQ + VariableDefinePlatformVar(NULL, "EILSEQ", &IntType, (union AnyValue *)&EILSEQValue, FALSE); +#endif + +#ifdef EINPROGRESS + VariableDefinePlatformVar(NULL, "EINPROGRESS", &IntType, (union AnyValue *)&EINPROGRESSValue, FALSE); +#endif + +#ifdef EINTR + VariableDefinePlatformVar(NULL, "EINTR", &IntType, (union AnyValue *)&EINTRValue, FALSE); +#endif + +#ifdef EINVAL + VariableDefinePlatformVar(NULL, "EINVAL", &IntType, (union AnyValue *)&EINVALValue, FALSE); +#endif + +#ifdef EIO + VariableDefinePlatformVar(NULL, "EIO", &IntType, (union AnyValue *)&EIOValue, FALSE); +#endif + +#ifdef EISCONN + VariableDefinePlatformVar(NULL, "EISCONN", &IntType, (union AnyValue *)&EISCONNValue, FALSE); +#endif + +#ifdef EISDIR + VariableDefinePlatformVar(NULL, "EISDIR", &IntType, (union AnyValue *)&EISDIRValue, FALSE); +#endif + +#ifdef ELOOP + VariableDefinePlatformVar(NULL, "ELOOP", &IntType, (union AnyValue *)&ELOOPValue, FALSE); +#endif + +#ifdef EMFILE + VariableDefinePlatformVar(NULL, "EMFILE", &IntType, (union AnyValue *)&EMFILEValue, FALSE); +#endif + +#ifdef EMLINK + VariableDefinePlatformVar(NULL, "EMLINK", &IntType, (union AnyValue *)&EMLINKValue, FALSE); +#endif + +#ifdef EMSGSIZE + VariableDefinePlatformVar(NULL, "EMSGSIZE", &IntType, (union AnyValue *)&EMSGSIZEValue, FALSE); +#endif + +#ifdef EMULTIHOP + VariableDefinePlatformVar(NULL, "EMULTIHOP", &IntType, (union AnyValue *)&EMULTIHOPValue, FALSE); +#endif + +#ifdef ENAMETOOLONG + VariableDefinePlatformVar(NULL, "ENAMETOOLONG", &IntType, (union AnyValue *)&ENAMETOOLONGValue, FALSE); +#endif + +#ifdef ENETDOWN + VariableDefinePlatformVar(NULL, "ENETDOWN", &IntType, (union AnyValue *)&ENETDOWNValue, FALSE); +#endif + +#ifdef ENETRESET + VariableDefinePlatformVar(NULL, "ENETRESET", &IntType, (union AnyValue *)&ENETRESETValue, FALSE); +#endif + +#ifdef ENETUNREACH + VariableDefinePlatformVar(NULL, "ENETUNREACH", &IntType, (union AnyValue *)&ENETUNREACHValue, FALSE); +#endif + +#ifdef ENFILE + VariableDefinePlatformVar(NULL, "ENFILE", &IntType, (union AnyValue *)&ENFILEValue, FALSE); +#endif + +#ifdef ENOBUFS + VariableDefinePlatformVar(NULL, "ENOBUFS", &IntType, (union AnyValue *)&ENOBUFSValue, FALSE); +#endif + +#ifdef ENODATA + VariableDefinePlatformVar(NULL, "ENODATA", &IntType, (union AnyValue *)&ENODATAValue, FALSE); +#endif + +#ifdef ENODEV + VariableDefinePlatformVar(NULL, "ENODEV", &IntType, (union AnyValue *)&ENODEVValue, FALSE); +#endif + +#ifdef ENOENT + VariableDefinePlatformVar(NULL, "ENOENT", &IntType, (union AnyValue *)&ENOENTValue, FALSE); +#endif + +#ifdef ENOEXEC + VariableDefinePlatformVar(NULL, "ENOEXEC", &IntType, (union AnyValue *)&ENOEXECValue, FALSE); +#endif + +#ifdef ENOLCK + VariableDefinePlatformVar(NULL, "ENOLCK", &IntType, (union AnyValue *)&ENOLCKValue, FALSE); +#endif + +#ifdef ENOLINK + VariableDefinePlatformVar(NULL, "ENOLINK", &IntType, (union AnyValue *)&ENOLINKValue, FALSE); +#endif + +#ifdef ENOMEM + VariableDefinePlatformVar(NULL, "ENOMEM", &IntType, (union AnyValue *)&ENOMEMValue, FALSE); +#endif + +#ifdef ENOMSG + VariableDefinePlatformVar(NULL, "ENOMSG", &IntType, (union AnyValue *)&ENOMSGValue, FALSE); +#endif + +#ifdef ENOPROTOOPT + VariableDefinePlatformVar(NULL, "ENOPROTOOPT", &IntType, (union AnyValue *)&ENOPROTOOPTValue, FALSE); +#endif + +#ifdef ENOSPC + VariableDefinePlatformVar(NULL, "ENOSPC", &IntType, (union AnyValue *)&ENOSPCValue, FALSE); +#endif + +#ifdef ENOSR + VariableDefinePlatformVar(NULL, "ENOSR", &IntType, (union AnyValue *)&ENOSRValue, FALSE); +#endif + +#ifdef ENOSTR + VariableDefinePlatformVar(NULL, "ENOSTR", &IntType, (union AnyValue *)&ENOSTRValue, FALSE); +#endif + +#ifdef ENOSYS + VariableDefinePlatformVar(NULL, "ENOSYS", &IntType, (union AnyValue *)&ENOSYSValue, FALSE); +#endif + +#ifdef ENOTCONN + VariableDefinePlatformVar(NULL, "ENOTCONN", &IntType, (union AnyValue *)&ENOTCONNValue, FALSE); +#endif + +#ifdef ENOTDIR + VariableDefinePlatformVar(NULL, "ENOTDIR", &IntType, (union AnyValue *)&ENOTDIRValue, FALSE); +#endif + +#ifdef ENOTEMPTY + VariableDefinePlatformVar(NULL, "ENOTEMPTY", &IntType, (union AnyValue *)&ENOTEMPTYValue, FALSE); +#endif + +#ifdef ENOTRECOVERABLE + VariableDefinePlatformVar(NULL, "ENOTRECOVERABLE", &IntType, (union AnyValue *)&ENOTRECOVERABLEValue, FALSE); +#endif + +#ifdef ENOTSOCK + VariableDefinePlatformVar(NULL, "ENOTSOCK", &IntType, (union AnyValue *)&ENOTSOCKValue, FALSE); +#endif + +#ifdef ENOTSUP + VariableDefinePlatformVar(NULL, "ENOTSUP", &IntType, (union AnyValue *)&ENOTSUPValue, FALSE); +#endif + +#ifdef ENOTTY + VariableDefinePlatformVar(NULL, "ENOTTY", &IntType, (union AnyValue *)&ENOTTYValue, FALSE); +#endif + +#ifdef ENXIO + VariableDefinePlatformVar(NULL, "ENXIO", &IntType, (union AnyValue *)&ENXIOValue, FALSE); +#endif + +#ifdef EOPNOTSUPP + VariableDefinePlatformVar(NULL, "EOPNOTSUPP", &IntType, (union AnyValue *)&EOPNOTSUPPValue, FALSE); +#endif + +#ifdef EOVERFLOW + VariableDefinePlatformVar(NULL, "EOVERFLOW", &IntType, (union AnyValue *)&EOVERFLOWValue, FALSE); +#endif + +#ifdef EOWNERDEAD + VariableDefinePlatformVar(NULL, "EOWNERDEAD", &IntType, (union AnyValue *)&EOWNERDEADValue, FALSE); +#endif + +#ifdef EPERM + VariableDefinePlatformVar(NULL, "EPERM", &IntType, (union AnyValue *)&EPERMValue, FALSE); +#endif + +#ifdef EPIPE + VariableDefinePlatformVar(NULL, "EPIPE", &IntType, (union AnyValue *)&EPIPEValue, FALSE); +#endif + +#ifdef EPROTO + VariableDefinePlatformVar(NULL, "EPROTO", &IntType, (union AnyValue *)&EPROTOValue, FALSE); +#endif + +#ifdef EPROTONOSUPPORT + VariableDefinePlatformVar(NULL, "EPROTONOSUPPORT", &IntType, (union AnyValue *)&EPROTONOSUPPORTValue, FALSE); +#endif + +#ifdef EPROTOTYPE + VariableDefinePlatformVar(NULL, "EPROTOTYPE", &IntType, (union AnyValue *)&EPROTOTYPEValue, FALSE); +#endif + +#ifdef ERANGE + VariableDefinePlatformVar(NULL, "ERANGE", &IntType, (union AnyValue *)&ERANGEValue, FALSE); +#endif + +#ifdef EROFS + VariableDefinePlatformVar(NULL, "EROFS", &IntType, (union AnyValue *)&EROFSValue, FALSE); +#endif + +#ifdef ESPIPE + VariableDefinePlatformVar(NULL, "ESPIPE", &IntType, (union AnyValue *)&ESPIPEValue, FALSE); +#endif + +#ifdef ESRCH + VariableDefinePlatformVar(NULL, "ESRCH", &IntType, (union AnyValue *)&ESRCHValue, FALSE); +#endif + +#ifdef ESTALE + VariableDefinePlatformVar(NULL, "ESTALE", &IntType, (union AnyValue *)&ESTALEValue, FALSE); +#endif + +#ifdef ETIME + VariableDefinePlatformVar(NULL, "ETIME", &IntType, (union AnyValue *)&ETIMEValue, FALSE); +#endif + +#ifdef ETIMEDOUT + VariableDefinePlatformVar(NULL, "ETIMEDOUT", &IntType, (union AnyValue *)&ETIMEDOUTValue, FALSE); +#endif + +#ifdef ETXTBSY + VariableDefinePlatformVar(NULL, "ETXTBSY", &IntType, (union AnyValue *)&ETXTBSYValue, FALSE); +#endif + +#ifdef EWOULDBLOCK + VariableDefinePlatformVar(NULL, "EWOULDBLOCK", &IntType, (union AnyValue *)&EWOULDBLOCKValue, FALSE); +#endif + +#ifdef EXDEV + VariableDefinePlatformVar(NULL, "EXDEV", &IntType, (union AnyValue *)&EXDEVValue, FALSE); +#endif + + VariableDefinePlatformVar(NULL, "errno", &IntType, (union AnyValue *)&errno, TRUE); +} + +#endif /* !BUILTIN_MINI_STDLIB */ diff --git a/src/cmd/picoc/cstdlib/math.c b/src/cmd/picoc/cstdlib/math.c new file mode 100644 index 0000000..0ba29a4 --- /dev/null +++ b/src/cmd/picoc/cstdlib/math.c @@ -0,0 +1,187 @@ +/* stdio.h library for large systems - small embedded systems use clibrary.c instead */ +#include "../interpreter.h" + +#ifndef BUILTIN_MINI_STDLIB +#ifndef NO_FP + +static double M_EValue = 2.7182818284590452354; /* e */ +static double M_LOG2EValue = 1.4426950408889634074; /* log_2 e */ +static double M_LOG10EValue = 0.43429448190325182765; /* log_10 e */ +static double M_LN2Value = 0.69314718055994530942; /* log_e 2 */ +static double M_LN10Value = 2.30258509299404568402; /* log_e 10 */ +static double M_PIValue = 3.14159265358979323846; /* pi */ +static double M_PI_2Value = 1.57079632679489661923; /* pi/2 */ +static double M_PI_4Value = 0.78539816339744830962; /* pi/4 */ +static double M_1_PIValue = 0.31830988618379067154; /* 1/pi */ +static double M_2_PIValue = 0.63661977236758134308; /* 2/pi */ +static double M_2_SQRTPIValue = 1.12837916709551257390; /* 2/sqrt(pi) */ +static double M_SQRT2Value = 1.41421356237309504880; /* sqrt(2) */ +static double M_SQRT1_2Value = 0.70710678118654752440; /* 1/sqrt(2) */ + + +void MathSin(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->FP = sin(Param[0]->Val->FP); +} + +void MathCos(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->FP = cos(Param[0]->Val->FP); +} + +void MathTan(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->FP = tan(Param[0]->Val->FP); +} + +void MathAsin(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->FP = asin(Param[0]->Val->FP); +} + +void MathAcos(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->FP = acos(Param[0]->Val->FP); +} + +void MathAtan(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->FP = atan(Param[0]->Val->FP); +} + +void MathAtan2(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->FP = atan2(Param[0]->Val->FP, Param[1]->Val->FP); +} + +void MathSinh(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->FP = sinh(Param[0]->Val->FP); +} + +void MathCosh(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->FP = cosh(Param[0]->Val->FP); +} + +void MathTanh(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->FP = tanh(Param[0]->Val->FP); +} + +void MathExp(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->FP = exp(Param[0]->Val->FP); +} + +void MathFabs(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->FP = fabs(Param[0]->Val->FP); +} + +void MathFmod(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->FP = fmod(Param[0]->Val->FP, Param[1]->Val->FP); +} + +void MathFrexp(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->FP = frexp(Param[0]->Val->FP, Param[1]->Val->Pointer); +} + +void MathLdexp(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->FP = ldexp(Param[0]->Val->FP, Param[1]->Val->Integer); +} + +void MathLog(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->FP = log(Param[0]->Val->FP); +} + +void MathLog10(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->FP = log10(Param[0]->Val->FP); +} + +void MathModf(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->FP = modf(Param[0]->Val->FP, Param[0]->Val->Pointer); +} + +void MathPow(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->FP = pow(Param[0]->Val->FP, Param[1]->Val->FP); +} + +void MathSqrt(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->FP = sqrt(Param[0]->Val->FP); +} + +void MathRound(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + /* this awkward definition of "round()" due to it being inconsistently + * declared in math.h */ + ReturnValue->Val->FP = ceil(Param[0]->Val->FP - 0.5); +} + +void MathCeil(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->FP = ceil(Param[0]->Val->FP); +} + +void MathFloor(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->FP = floor(Param[0]->Val->FP); +} + +/* all math.h functions */ +struct LibraryFunction MathFunctions[] = +{ + { MathAcos, "float acos(float);" }, + { MathAsin, "float asin(float);" }, + { MathAtan, "float atan(float);" }, + { MathAtan2, "float atan2(float, float);" }, + { MathCeil, "float ceil(float);" }, + { MathCos, "float cos(float);" }, + { MathCosh, "float cosh(float);" }, + { MathExp, "float exp(float);" }, + { MathFabs, "float fabs(float);" }, + { MathFloor, "float floor(float);" }, + { MathFmod, "float fmod(float, float);" }, + { MathFrexp, "float frexp(float, int *);" }, + { MathLdexp, "float ldexp(float, int);" }, + { MathLog, "float log(float);" }, + { MathLog10, "float log10(float);" }, + { MathModf, "float modf(float, float *);" }, + { MathPow, "float pow(float,float);" }, + { MathRound, "float round(float);" }, + { MathSin, "float sin(float);" }, + { MathSinh, "float sinh(float);" }, + { MathSqrt, "float sqrt(float);" }, + { MathTan, "float tan(float);" }, + { MathTanh, "float tanh(float);" }, + { NULL, NULL } +}; + +/* creates various system-dependent definitions */ +void MathSetupFunc(void) +{ + VariableDefinePlatformVar(NULL, "M_E", &FPType, (union AnyValue *)&M_EValue, FALSE); + VariableDefinePlatformVar(NULL, "M_LOG2E", &FPType, (union AnyValue *)&M_LOG2EValue, FALSE); + VariableDefinePlatformVar(NULL, "M_LOG10E", &FPType, (union AnyValue *)&M_LOG10EValue, FALSE); + VariableDefinePlatformVar(NULL, "M_LN2", &FPType, (union AnyValue *)&M_LN2Value, FALSE); + VariableDefinePlatformVar(NULL, "M_LN10", &FPType, (union AnyValue *)&M_LN10Value, FALSE); + VariableDefinePlatformVar(NULL, "M_PI", &FPType, (union AnyValue *)&M_PIValue, FALSE); + VariableDefinePlatformVar(NULL, "M_PI_2", &FPType, (union AnyValue *)&M_PI_2Value, FALSE); + VariableDefinePlatformVar(NULL, "M_PI_4", &FPType, (union AnyValue *)&M_PI_4Value, FALSE); + VariableDefinePlatformVar(NULL, "M_1_PI", &FPType, (union AnyValue *)&M_1_PIValue, FALSE); + VariableDefinePlatformVar(NULL, "M_2_PI", &FPType, (union AnyValue *)&M_2_PIValue, FALSE); + VariableDefinePlatformVar(NULL, "M_2_SQRTPI", &FPType, (union AnyValue *)&M_2_SQRTPIValue, FALSE); + VariableDefinePlatformVar(NULL, "M_SQRT2", &FPType, (union AnyValue *)&M_SQRT2Value, FALSE); + VariableDefinePlatformVar(NULL, "M_SQRT1_2", &FPType, (union AnyValue *)&M_SQRT1_2Value, FALSE); +} + +#endif /* !NO_FP */ +#endif /* !BUILTIN_MINI_STDLIB */ diff --git a/src/cmd/picoc/cstdlib/stdbool.c b/src/cmd/picoc/cstdlib/stdbool.c new file mode 100644 index 0000000..30b2528 --- /dev/null +++ b/src/cmd/picoc/cstdlib/stdbool.c @@ -0,0 +1,22 @@ +/* string.h library for large systems - small embedded systems use clibrary.c instead */ +#include "../interpreter.h" + +#ifndef BUILTIN_MINI_STDLIB + +static int trueValue = 1; +static int falseValue = 0; + + +/* structure definitions */ +const char StdboolDefs[] = "typedef int bool;"; + +/* creates various system-dependent definitions */ +void StdboolSetupFunc(void) +{ + /* defines */ + VariableDefinePlatformVar(NULL, "true", &IntType, (union AnyValue *)&trueValue, FALSE); + VariableDefinePlatformVar(NULL, "false", &IntType, (union AnyValue *)&falseValue, FALSE); + VariableDefinePlatformVar(NULL, "__bool_true_false_are_defined", &IntType, (union AnyValue *)&trueValue, FALSE); +} + +#endif /* !BUILTIN_MINI_STDLIB */ diff --git a/src/cmd/picoc/cstdlib/stdio.c b/src/cmd/picoc/cstdlib/stdio.c new file mode 100644 index 0000000..869230d --- /dev/null +++ b/src/cmd/picoc/cstdlib/stdio.c @@ -0,0 +1,742 @@ +/* stdio.h library for large systems - small embedded systems use clibrary.c instead */ +#ifndef BUILTIN_MINI_STDLIB + +#include +#include "../interpreter.h" + +#define MAX_FORMAT 80 +#define MAX_SCANF_ARGS 10 + +FILE *CStdOut; + +static int ZeroValue = 0; +static int EOFValue = EOF; +static int SEEK_SETValue = SEEK_SET; +static int SEEK_CURValue = SEEK_CUR; +static int SEEK_ENDValue = SEEK_END; +static int BUFSIZValue = BUFSIZ; +static int FILENAME_MAXValue = FILENAME_MAX; +static int _IOFBFValue = _IOFBF; +static int _IOLBFValue = _IOLBF; +static int _IONBFValue = _IONBF; +static int L_tmpnamValue = L_tmpnam; +static int GETS_MAXValue = 255; /* arbitrary maximum size of a gets() file */ + +static FILE *stdinValue; +static FILE *stdoutValue; +static FILE *stderrValue; + +struct ValueType *FilePtrType = NULL; + + +/* our own internal output stream which can output to FILE * or strings */ +typedef struct StdOutStreamStruct +{ + FILE *FilePtr; + char *StrOutPtr; + int StrOutLen; + int CharCount; + +} StdOutStream; + +/* our representation of varargs within picoc */ +struct StdVararg +{ + struct Value **Param; + int NumArgs; +}; + +/* initialises the I/O system so error reporting works */ +void BasicIOInit() +{ + CStdOut = stdout; + stdinValue = stdin; + stdoutValue = stdout; + stderrValue = stderr; +} + +/* output a single character to either a FILE * or a string */ +void StdioOutPutc(int OutCh, StdOutStream *Stream) +{ + if (Stream->FilePtr != NULL) + { + /* output to stdio stream */ + putc(OutCh, Stream->FilePtr); + Stream->CharCount++; + } + else if (Stream->StrOutLen < 0 || Stream->StrOutLen > 1) + { + /* output to a string */ + *Stream->StrOutPtr = OutCh; + Stream->StrOutPtr++; + + if (Stream->StrOutLen > 1) + Stream->StrOutLen--; + + Stream->CharCount++; + } +} + +/* output a string to either a FILE * or a string */ +void StdioOutPuts(const char *Str, StdOutStream *Stream) +{ + if (Stream->FilePtr != NULL) + { + /* output to stdio stream */ + fputs(Str, Stream->FilePtr); + } + else + { + /* output to a string */ + while (*Str != '\0') + { + if (Stream->StrOutLen < 0 || Stream->StrOutLen > 1) + { + /* output to a string */ + *Stream->StrOutPtr = *Str; + Str++; + Stream->StrOutPtr++; + + if (Stream->StrOutLen > 1) + Stream->StrOutLen--; + + Stream->CharCount++; + } + } + } +} + +/* printf-style format of an int or other word-sized object */ +void StdioFprintfWord(StdOutStream *Stream, const char *Format, unsigned int Value) +{ + if (Stream->FilePtr != NULL) + Stream->CharCount += fprintf(Stream->FilePtr, Format, Value); + + else if (Stream->StrOutLen >= 0) + { +#ifndef WIN32 + int CCount = snprintf(Stream->StrOutPtr, Stream->StrOutLen, Format, Value); +#else + int CCount = _snprintf(Stream->StrOutPtr, Stream->StrOutLen, Format, Value); +#endif + Stream->StrOutPtr += CCount; + Stream->StrOutLen -= CCount; + Stream->CharCount += CCount; + } + else + { + int CCount = sprintf(Stream->StrOutPtr, Format, Value); + Stream->CharCount += CCount; + Stream->StrOutPtr += CCount; + } +} + +/* printf-style format of a floating point number */ +void StdioFprintfFP(StdOutStream *Stream, const char *Format, double Value) +{ + if (Stream->FilePtr != NULL) + Stream->CharCount += fprintf(Stream->FilePtr, Format, Value); + + else if (Stream->StrOutLen >= 0) + { +#ifndef WIN32 + int CCount = snprintf(Stream->StrOutPtr, Stream->StrOutLen, Format, Value); +#else + int CCount = _snprintf(Stream->StrOutPtr, Stream->StrOutLen, Format, Value); +#endif + Stream->StrOutPtr += CCount; + Stream->StrOutLen -= CCount; + Stream->CharCount += CCount; + } + else + { + int CCount = sprintf(Stream->StrOutPtr, Format, Value); + Stream->CharCount += CCount; + Stream->StrOutPtr += CCount; + } +} + +/* printf-style format of a pointer */ +void StdioFprintfPointer(StdOutStream *Stream, const char *Format, void *Value) +{ + if (Stream->FilePtr != NULL) + Stream->CharCount += fprintf(Stream->FilePtr, Format, Value); + + else if (Stream->StrOutLen >= 0) + { +#ifndef WIN32 + int CCount = snprintf(Stream->StrOutPtr, Stream->StrOutLen, Format, Value); +#else + int CCount = _snprintf(Stream->StrOutPtr, Stream->StrOutLen, Format, Value); +#endif + Stream->StrOutPtr += CCount; + Stream->StrOutLen -= CCount; + Stream->CharCount += CCount; + } + else + { + int CCount = sprintf(Stream->StrOutPtr, Format, Value); + Stream->CharCount += CCount; + Stream->StrOutPtr += CCount; + } +} + +/* internal do-anything v[s][n]printf() formatting system with output to strings or FILE * */ +int StdioBasePrintf(struct ParseState *Parser, FILE *Stream, char *StrOut, int StrOutLen, char *Format, struct StdVararg *Args) +{ + struct Value *ThisArg = Args->Param[0]; + int ArgCount = 0; + char *FPos; + char OneFormatBuf[MAX_FORMAT+1]; + int OneFormatCount; + struct ValueType *ShowType; + StdOutStream SOStream; + + if (Format == NULL) + Format = "[null format]\n"; + + FPos = Format; + SOStream.FilePtr = Stream; + SOStream.StrOutPtr = StrOut; + SOStream.StrOutLen = StrOutLen; + SOStream.CharCount = 0; + + while (*FPos != '\0') + { + if (*FPos == '%') + { + /* work out what type we're printing */ + FPos++; + ShowType = NULL; + OneFormatBuf[0] = '%'; + OneFormatCount = 1; + + do + { + switch (*FPos) + { + case 'd': case 'i': ShowType = &IntType; break; /* integer decimal */ + case 'o': case 'u': case 'x': case 'X': ShowType = &IntType; break; /* integer base conversions */ +#ifndef NO_FP + case 'e': case 'E': ShowType = &FPType; break; /* double, exponent form */ + case 'f': case 'F': ShowType = &FPType; break; /* double, fixed-point */ + case 'g': case 'G': ShowType = &FPType; break; /* double, flexible format */ +#endif + case 'a': case 'A': ShowType = &IntType; break; /* hexadecimal, 0x- format */ + case 'c': ShowType = &IntType; break; /* character */ + case 's': ShowType = CharPtrType; break; /* string */ + case 'p': ShowType = VoidPtrType; break; /* pointer */ + case 'n': ShowType = &VoidType; break; /* number of characters written */ + case 'm': ShowType = &VoidType; break; /* strerror(errno) */ + case '%': ShowType = &VoidType; break; /* just a '%' character */ + case '\0': ShowType = &VoidType; break; /* end of format string */ + } + + /* copy one character of format across to the OneFormatBuf */ + OneFormatBuf[OneFormatCount] = *FPos; + OneFormatCount++; + + /* do special actions depending on the conversion type */ + if (ShowType == &VoidType) + { + switch (*FPos) + { + case 'm': StdioOutPuts(strerror(errno), &SOStream); break; + case '%': StdioOutPutc(*FPos, &SOStream); break; + case '\0': OneFormatBuf[OneFormatCount] = '\0'; StdioOutPutc(*FPos, &SOStream); break; + case 'n': + ThisArg = (struct Value *)((char *)ThisArg + MEM_ALIGN(sizeof(struct Value) + TypeStackSizeValue(ThisArg))); + if (ThisArg->Typ->Base == TypeArray && ThisArg->Typ->FromType->Base == TypeInt) + *(int *)ThisArg->Val->Pointer = SOStream.CharCount; + break; + } + } + + FPos++; + + } while (ShowType == NULL && OneFormatCount < MAX_FORMAT); + + if (ShowType != &VoidType) + { + if (ArgCount >= Args->NumArgs) + StdioOutPuts("XXX", &SOStream); + else + { + /* null-terminate the buffer */ + OneFormatBuf[OneFormatCount] = '\0'; + + /* print this argument */ + ThisArg = (struct Value *)((char *)ThisArg + MEM_ALIGN(sizeof(struct Value) + TypeStackSizeValue(ThisArg))); + if (ShowType == &IntType) + { + /* show a signed integer */ + if (IS_NUMERIC_COERCIBLE(ThisArg)) + StdioFprintfWord(&SOStream, OneFormatBuf, ExpressionCoerceUnsignedInteger(ThisArg)); + else + StdioOutPuts("XXX", &SOStream); + } +#ifndef NO_FP + else if (ShowType == &FPType) + { + /* show a floating point number */ + if (IS_NUMERIC_COERCIBLE(ThisArg)) + StdioFprintfFP(&SOStream, OneFormatBuf, ExpressionCoerceFP(ThisArg)); + else + StdioOutPuts("XXX", &SOStream); + } +#endif + else if (ShowType == CharPtrType) + { + if (ThisArg->Typ->Base == TypePointer) + StdioFprintfPointer(&SOStream, OneFormatBuf, ThisArg->Val->Pointer); + + else if (ThisArg->Typ->Base == TypeArray && ThisArg->Typ->FromType->Base == TypeChar) + StdioFprintfPointer(&SOStream, OneFormatBuf, &ThisArg->Val->ArrayMem[0]); + + else + StdioOutPuts("XXX", &SOStream); + } + else if (ShowType == VoidPtrType) + { + if (ThisArg->Typ->Base == TypePointer) + StdioFprintfPointer(&SOStream, OneFormatBuf, ThisArg->Val->Pointer); + + else if (ThisArg->Typ->Base == TypeArray) + StdioFprintfPointer(&SOStream, OneFormatBuf, &ThisArg->Val->ArrayMem[0]); + + else + StdioOutPuts("XXX", &SOStream); + } + + ArgCount++; + } + } + } + else + { + /* just output a normal character */ + StdioOutPutc(*FPos, &SOStream); + FPos++; + } + } + + /* null-terminate */ + if (SOStream.StrOutPtr != NULL && SOStream.StrOutLen > 0) + *SOStream.StrOutPtr = '\0'; + + return SOStream.CharCount; +} + +/* internal do-anything v[s][n]scanf() formatting system with input from strings or FILE * */ +int StdioBaseScanf(struct ParseState *Parser, FILE *Stream, char *StrIn, char *Format, struct StdVararg *Args) +{ + struct Value *ThisArg = Args->Param[0]; + int ArgCount = 0; + void *ScanfArg[MAX_SCANF_ARGS]; + + if (Args->NumArgs > MAX_SCANF_ARGS) + ProgramFail(Parser, "too many arguments to scanf() - %d max", MAX_SCANF_ARGS); + + for (ArgCount = 0; ArgCount < Args->NumArgs; ArgCount++) + { + ThisArg = (struct Value *)((char *)ThisArg + MEM_ALIGN(sizeof(struct Value) + TypeStackSizeValue(ThisArg))); + + if (ThisArg->Typ->Base == TypePointer) + ScanfArg[ArgCount] = ThisArg->Val->Pointer; + + else if (ThisArg->Typ->Base == TypeArray) + ScanfArg[ArgCount] = &ThisArg->Val->ArrayMem[0]; + + else + ProgramFail(Parser, "non-pointer argument to scanf() - argument %d after format", ArgCount+1); + } + + if (Stream != NULL) + return fscanf(Stream, Format, ScanfArg[0], ScanfArg[1], ScanfArg[2], ScanfArg[3], ScanfArg[4], ScanfArg[5], ScanfArg[6], ScanfArg[7], ScanfArg[8], ScanfArg[9]); + else + return sscanf(StrIn, Format, ScanfArg[0], ScanfArg[1], ScanfArg[2], ScanfArg[3], ScanfArg[4], ScanfArg[5], ScanfArg[6], ScanfArg[7], ScanfArg[8], ScanfArg[9]); +} + +/* stdio calls */ +void StdioFopen(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Pointer = fopen(Param[0]->Val->Pointer, Param[1]->Val->Pointer); +} + +void StdioFreopen(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Pointer = freopen(Param[0]->Val->Pointer, Param[1]->Val->Pointer, Param[2]->Val->Pointer); +} + +void StdioFclose(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = fclose(Param[0]->Val->Pointer); +} + +void StdioFread(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = fread(Param[0]->Val->Pointer, Param[1]->Val->Integer, Param[2]->Val->Integer, Param[3]->Val->Pointer); +} + +void StdioFwrite(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = fwrite(Param[0]->Val->Pointer, Param[1]->Val->Integer, Param[2]->Val->Integer, Param[3]->Val->Pointer); +} + +void StdioFgetc(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = fgetc(Param[0]->Val->Pointer); +} + +void StdioFgets(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Pointer = fgets(Param[0]->Val->Pointer, Param[1]->Val->Integer, Param[2]->Val->Pointer); +} + +void StdioRemove(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = remove(Param[0]->Val->Pointer); +} + +void StdioRename(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = rename(Param[0]->Val->Pointer, Param[1]->Val->Pointer); +} + +void StdioRewind(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + rewind(Param[0]->Val->Pointer); +} + +void StdioTmpfile(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Pointer = tmpfile(); +} + +void StdioClearerr(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + clearerr((FILE *)Param[0]->Val->Pointer); +} + +void StdioFeof(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = feof((FILE *)Param[0]->Val->Pointer); +} + +void StdioFerror(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = ferror((FILE *)Param[0]->Val->Pointer); +} + +void StdioFileno(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ +#ifndef WIN32 + ReturnValue->Val->Integer = fileno((FILE *)Param[0]->Val->Pointer); +#else + ReturnValue->Val->Integer = _fileno(Param[0]->Val->Pointer); +#endif +} + +void StdioFflush(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = fflush(Param[0]->Val->Pointer); +} + +void StdioFgetpos(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = fgetpos(Param[0]->Val->Pointer, Param[1]->Val->Pointer); +} + +void StdioFsetpos(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = fsetpos(Param[0]->Val->Pointer, Param[1]->Val->Pointer); +} + +void StdioFputc(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = fputc(Param[0]->Val->Integer, Param[1]->Val->Pointer); +} + +void StdioFputs(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = fputs(Param[0]->Val->Pointer, Param[1]->Val->Pointer); +} + +void StdioFtell(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = ftell(Param[0]->Val->Pointer); +} + +void StdioFseek(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = fseek(Param[0]->Val->Pointer, Param[1]->Val->Integer, Param[2]->Val->Integer); +} + +void StdioPerror(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + perror(Param[0]->Val->Pointer); +} + +void StdioPutc(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = putc(Param[0]->Val->Integer, (FILE *)Param[1]->Val->Pointer); +} + +void StdioPutchar(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = putchar(Param[0]->Val->Integer); +} + +void StdioSetbuf(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + setbuf(Param[0]->Val->Pointer, Param[1]->Val->Pointer); +} + +void StdioSetvbuf(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + setvbuf(Param[0]->Val->Pointer, Param[1]->Val->Pointer, Param[2]->Val->Integer, Param[3]->Val->Integer); +} + +void StdioUngetc(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = ungetc(Param[0]->Val->Integer, Param[1]->Val->Pointer); +} + +void StdioPuts(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = puts(Param[0]->Val->Pointer); +} + +void StdioGets(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Pointer = fgets(Param[0]->Val->Pointer, GETS_MAXValue, stdin); + if (ReturnValue->Val->Pointer != NULL) + { + char *EOLPos = strchr(Param[0]->Val->Pointer, '\n'); + if (EOLPos != NULL) + *EOLPos = '\0'; + } +} + +void StdioGetchar(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = getchar(); +} + +void StdioPrintf(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + struct StdVararg PrintfArgs; + + PrintfArgs.Param = Param; + PrintfArgs.NumArgs = NumArgs-1; + ReturnValue->Val->Integer = StdioBasePrintf(Parser, stdout, NULL, 0, Param[0]->Val->Pointer, &PrintfArgs); +} + +void StdioVprintf(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = StdioBasePrintf(Parser, stdout, NULL, 0, Param[0]->Val->Pointer, Param[1]->Val->Pointer); +} + +void StdioFprintf(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + struct StdVararg PrintfArgs; + + PrintfArgs.Param = Param + 1; + PrintfArgs.NumArgs = NumArgs-2; + ReturnValue->Val->Integer = StdioBasePrintf(Parser, Param[0]->Val->Pointer, NULL, 0, Param[1]->Val->Pointer, &PrintfArgs); +} + +void StdioVfprintf(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = StdioBasePrintf(Parser, Param[0]->Val->Pointer, NULL, 0, Param[1]->Val->Pointer, Param[2]->Val->Pointer); +} + +void StdioSprintf(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + struct StdVararg PrintfArgs; + + PrintfArgs.Param = Param + 1; + PrintfArgs.NumArgs = NumArgs-2; + ReturnValue->Val->Integer = StdioBasePrintf(Parser, NULL, Param[0]->Val->Pointer, -1, Param[1]->Val->Pointer, &PrintfArgs); +} + +void StdioSnprintf(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + struct StdVararg PrintfArgs; + + PrintfArgs.Param = Param+2; + PrintfArgs.NumArgs = NumArgs-3; + ReturnValue->Val->Integer = StdioBasePrintf(Parser, NULL, Param[0]->Val->Pointer, Param[1]->Val->Integer, Param[2]->Val->Pointer, &PrintfArgs); +} + +void StdioScanf(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + struct StdVararg ScanfArgs; + + ScanfArgs.Param = Param; + ScanfArgs.NumArgs = NumArgs-1; + ReturnValue->Val->Integer = StdioBaseScanf(Parser, stdin, NULL, Param[0]->Val->Pointer, &ScanfArgs); +} + +void StdioFscanf(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + struct StdVararg ScanfArgs; + + ScanfArgs.Param = Param+1; + ScanfArgs.NumArgs = NumArgs-2; + ReturnValue->Val->Integer = StdioBaseScanf(Parser, Param[0]->Val->Pointer, NULL, Param[1]->Val->Pointer, &ScanfArgs); +} + +void StdioSscanf(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + struct StdVararg ScanfArgs; + + ScanfArgs.Param = Param+1; + ScanfArgs.NumArgs = NumArgs-2; + ReturnValue->Val->Integer = StdioBaseScanf(Parser, NULL, Param[0]->Val->Pointer, Param[1]->Val->Pointer, &ScanfArgs); +} + +void StdioVsprintf(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = StdioBasePrintf(Parser, NULL, Param[0]->Val->Pointer, -1, Param[1]->Val->Pointer, Param[2]->Val->Pointer); +} + +void StdioVsnprintf(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = StdioBasePrintf(Parser, NULL, Param[0]->Val->Pointer, Param[1]->Val->Integer, Param[2]->Val->Pointer, Param[3]->Val->Pointer); +} + +void StdioVscanf(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = StdioBaseScanf(Parser, stdin, NULL, Param[0]->Val->Pointer, Param[1]->Val->Pointer); +} + +void StdioVfscanf(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = StdioBaseScanf(Parser, Param[0]->Val->Pointer, NULL, Param[1]->Val->Pointer, Param[2]->Val->Pointer); +} + +void StdioVsscanf(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = StdioBaseScanf(Parser, NULL, Param[0]->Val->Pointer, Param[1]->Val->Pointer, Param[2]->Val->Pointer); +} + +/* handy structure definitions */ +const char StdioDefs[] = "\ +typedef struct __va_listStruct va_list; \ +typedef struct __FILEStruct FILE;\ +"; + +/* all stdio functions */ +struct LibraryFunction StdioFunctions[] = +{ + { StdioFopen, "FILE *fopen(char *, char *);" }, + { StdioFreopen, "FILE *freopen(char *, char *, FILE *);" }, + { StdioFclose, "int fclose(FILE *);" }, + { StdioFread, "int fread(void *, int, int, FILE *);" }, + { StdioFwrite, "int fwrite(void *, int, int, FILE *);" }, + { StdioFgetc, "int fgetc(FILE *);" }, + { StdioFgetc, "int getc(FILE *);" }, + { StdioFgets, "char *fgets(char *, int, FILE *);" }, + { StdioFputc, "int fputc(int, FILE *);" }, + { StdioFputs, "int fputs(char *, FILE *);" }, + { StdioRemove, "int remove(char *);" }, + { StdioRename, "int rename(char *, char *);" }, + { StdioRewind, "void rewind(FILE *);" }, + { StdioTmpfile, "FILE *tmpfile();" }, + { StdioClearerr,"void clearerr(FILE *);" }, + { StdioFeof, "int feof(FILE *);" }, + { StdioFerror, "int ferror(FILE *);" }, + { StdioFileno, "int fileno(FILE *);" }, + { StdioFflush, "int fflush(FILE *);" }, + { StdioFgetpos, "int fgetpos(FILE *, int *);" }, + { StdioFsetpos, "int fsetpos(FILE *, int *);" }, + { StdioFtell, "int ftell(FILE *);" }, + { StdioFseek, "int fseek(FILE *, int, int);" }, + { StdioPerror, "void perror(char *);" }, + { StdioPutc, "int putc(char *, FILE *);" }, + { StdioPutchar, "int putchar(int);" }, + { StdioPutchar, "int fputchar(int);" }, + { StdioSetbuf, "void setbuf(FILE *, char *);" }, + { StdioSetvbuf, "void setvbuf(FILE *, char *, int, int);" }, + { StdioUngetc, "int ungetc(int, FILE *);" }, + { StdioPuts, "int puts(char *);" }, + { StdioGets, "char *gets(char *);" }, + { StdioGetchar, "int getchar();" }, + { StdioPrintf, "int printf(char *, ...);" }, + { StdioFprintf, "int fprintf(FILE *, char *, ...);" }, + { StdioSprintf, "int sprintf(char *, char *, ...);" }, + { StdioSnprintf,"int snprintf(char *, int, char *, ...);" }, + { StdioScanf, "int scanf(char *, ...);" }, + { StdioFscanf, "int fscanf(FILE *, char *, ...);" }, + { StdioSscanf, "int sscanf(char *, char *, ...);" }, + { StdioVprintf, "int vprintf(char *, va_list);" }, + { StdioVfprintf,"int vfprintf(FILE *, char *, va_list);" }, + { StdioVsprintf,"int vsprintf(char *, char *, va_list);" }, + { StdioVsnprintf,"int vsnprintf(char *, int, char *, va_list);" }, + { StdioVscanf, "int vscanf(char *, va_list);" }, + { StdioVfscanf, "int vfscanf(FILE *, char *, va_list);" }, + { StdioVsscanf, "int vsscanf(char *, char *, va_list);" }, + { NULL, NULL } +}; + +/* creates various system-dependent definitions */ +void StdioSetupFunc(void) +{ + struct ValueType *StructFileType; + struct ValueType *FilePtrType; + + /* make a "struct __FILEStruct" which is the same size as a native FILE structure */ + StructFileType = TypeCreateOpaqueStruct(NULL, TableStrRegister("__FILEStruct"), sizeof(FILE)); + + /* get a FILE * type */ + FilePtrType = TypeGetMatching(NULL, StructFileType, TypePointer, 0, StrEmpty, TRUE); + + /* make a "struct __va_listStruct" which is the same size as our struct StdVararg */ + TypeCreateOpaqueStruct(NULL, TableStrRegister("__va_listStruct"), sizeof(FILE)); + + /* define EOF equal to the system EOF */ + VariableDefinePlatformVar(NULL, "EOF", &IntType, (union AnyValue *)&EOFValue, FALSE); + VariableDefinePlatformVar(NULL, "SEEK_SET", &IntType, (union AnyValue *)&SEEK_SETValue, FALSE); + VariableDefinePlatformVar(NULL, "SEEK_CUR", &IntType, (union AnyValue *)&SEEK_CURValue, FALSE); + VariableDefinePlatformVar(NULL, "SEEK_END", &IntType, (union AnyValue *)&SEEK_ENDValue, FALSE); + VariableDefinePlatformVar(NULL, "BUFSIZ", &IntType, (union AnyValue *)&BUFSIZValue, FALSE); + VariableDefinePlatformVar(NULL, "FILENAME_MAX", &IntType, (union AnyValue *)&FILENAME_MAXValue, FALSE); + VariableDefinePlatformVar(NULL, "_IOFBF", &IntType, (union AnyValue *)&_IOFBFValue, FALSE); + VariableDefinePlatformVar(NULL, "_IOLBF", &IntType, (union AnyValue *)&_IOLBFValue, FALSE); + VariableDefinePlatformVar(NULL, "_IONBF", &IntType, (union AnyValue *)&_IONBFValue, FALSE); + VariableDefinePlatformVar(NULL, "L_tmpnam", &IntType, (union AnyValue *)&L_tmpnamValue, FALSE); + VariableDefinePlatformVar(NULL, "GETS_MAX", &IntType, (union AnyValue *)&GETS_MAXValue, FALSE); + + /* define stdin, stdout and stderr */ + VariableDefinePlatformVar(NULL, "stdin", FilePtrType, (union AnyValue *)&stdinValue, FALSE); + VariableDefinePlatformVar(NULL, "stdout", FilePtrType, (union AnyValue *)&stdoutValue, FALSE); + VariableDefinePlatformVar(NULL, "stderr", FilePtrType, (union AnyValue *)&stderrValue, FALSE); + + /* define NULL, TRUE and FALSE */ + if (!VariableDefined(TableStrRegister("NULL"))) + VariableDefinePlatformVar(NULL, "NULL", &IntType, (union AnyValue *)&ZeroValue, FALSE); +} + +/* portability-related I/O calls */ +void PrintCh(char OutCh, FILE *Stream) +{ + putc(OutCh, Stream); +} + +void PrintSimpleInt(long Num, FILE *Stream) +{ + fprintf(Stream, "%ld", Num); +} + +void PrintStr(const char *Str, FILE *Stream) +{ + fputs(Str, Stream); +} + +void PrintFP(double Num, FILE *Stream) +{ + fprintf(Stream, "%f", Num); +} + +#endif /* !BUILTIN_MINI_STDLIB */ diff --git a/src/cmd/picoc/cstdlib/stdlib.c b/src/cmd/picoc/cstdlib/stdlib.c new file mode 100644 index 0000000..8eebb1c --- /dev/null +++ b/src/cmd/picoc/cstdlib/stdlib.c @@ -0,0 +1,174 @@ +/* stdlib.h library for large systems - small embedded systems use clibrary.c instead */ +#include "../interpreter.h" + +#ifndef BUILTIN_MINI_STDLIB + +static int ZeroValue = 0; + +#ifndef NO_FP +void StdlibAtof(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->FP = atof(Param[0]->Val->Pointer); +} +#endif + +void StdlibAtoi(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = atoi(Param[0]->Val->Pointer); +} + +void StdlibAtol(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = atol(Param[0]->Val->Pointer); +} + +#ifndef NO_FP +void StdlibStrtod(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->FP = strtod(Param[0]->Val->Pointer, Param[1]->Val->Pointer); +} +#endif + +void StdlibStrtol(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = strtol(Param[0]->Val->Pointer, Param[1]->Val->Pointer, Param[2]->Val->Integer); +} + +void StdlibStrtoul(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = strtoul(Param[0]->Val->Pointer, Param[1]->Val->Pointer, Param[2]->Val->Integer); +} + +void StdlibMalloc(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Pointer = malloc(Param[0]->Val->Integer); +} + +void StdlibCalloc(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Pointer = calloc(Param[0]->Val->Integer, Param[1]->Val->Integer); +} + +void StdlibRealloc(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Pointer = realloc(Param[0]->Val->Pointer, Param[1]->Val->Integer); +} + +void StdlibFree(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + free(Param[0]->Val->Pointer); +} + +void StdlibRand(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = rand(); +} + +void StdlibSrand(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + srand(Param[0]->Val->Integer); +} + +void StdlibAbort(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ProgramFail(Parser, "abort"); +} + +void StdlibExit(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + PlatformExit(Param[0]->Val->Integer); +} + +void StdlibGetenv(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Pointer = getenv(Param[0]->Val->Pointer); +} + +void StdlibSystem(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = system(Param[0]->Val->Pointer); +} + +#if 0 +void StdlibBsearch(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Pointer = bsearch(Param[0]->Val->Pointer, Param[1]->Val->Pointer, Param[2]->Val->Integer, Param[3]->Val->Integer, (int (*)())Param[4]->Val->Pointer); +} +#endif + +void StdlibAbs(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = abs(Param[0]->Val->Integer); +} + +void StdlibLabs(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = labs(Param[0]->Val->Integer); +} + +#if 0 +void StdlibDiv(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = div(Param[0]->Val->Integer, Param[1]->Val->Integer); +} + +void StdlibLdiv(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = ldiv(Param[0]->Val->Integer, Param[1]->Val->Integer); +} +#endif + +#if 0 +/* handy structure definitions */ +const char StdlibDefs[] = "\ +typedef struct { \ + int quot, rem; \ +} div_t; \ +\ +typedef struct { \ + int quot, rem; \ +} ldiv_t; \ +"; +#endif + +/* all stdlib.h functions */ +struct LibraryFunction StdlibFunctions[] = +{ +#ifndef NO_FP + { StdlibAtof, "float atof(char *);" }, + { StdlibStrtod, "float strtod(char *,char **);" }, +#endif + { StdlibAtoi, "int atoi(char *);" }, + { StdlibAtol, "int atol(char *);" }, + { StdlibStrtol, "int strtol(char *,char **,int);" }, + { StdlibStrtoul, "int strtoul(char *,char **,int);" }, + { StdlibMalloc, "void *malloc(int);" }, + { StdlibCalloc, "void *calloc(int,int);" }, + { StdlibRealloc, "void *realloc(void *,int);" }, + { StdlibFree, "void free(void *);" }, + { StdlibRand, "int rand();" }, + { StdlibSrand, "void srand(int);" }, + { StdlibAbort, "void abort();" }, + { StdlibExit, "void exit(int);" }, + { StdlibGetenv, "char *getenv(char *);" }, + { StdlibSystem, "int system(char *);" }, +/* { StdlibBsearch, "void *bsearch(void *,void *,int,int,int (*)());" }, */ +/* { StdlibQsort, "void *qsort(void *,int,int,int (*)());" }, */ + { StdlibAbs, "int abs(int);" }, + { StdlibLabs, "int labs(int);" }, +#if 0 + { StdlibDiv, "div_t div(int);" }, + { StdlibLdiv, "ldiv_t ldiv(int);" }, +#endif + { NULL, NULL } +}; + +/* creates various system-dependent definitions */ +void StdlibSetupFunc(void) +{ + /* define NULL, TRUE and FALSE */ + if (!VariableDefined(TableStrRegister("NULL"))) + VariableDefinePlatformVar(NULL, "NULL", &IntType, (union AnyValue *)&ZeroValue, FALSE); +} + +#endif /* !BUILTIN_MINI_STDLIB */ diff --git a/src/cmd/picoc/cstdlib/string.c b/src/cmd/picoc/cstdlib/string.c new file mode 100644 index 0000000..560e921 --- /dev/null +++ b/src/cmd/picoc/cstdlib/string.c @@ -0,0 +1,190 @@ +/* string.h library for large systems - small embedded systems use clibrary.c instead */ +#include "../interpreter.h" + +#ifndef BUILTIN_MINI_STDLIB + +static int ZeroValue = 0; + +void StringStrcpy(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Pointer = strcpy(Param[0]->Val->Pointer, Param[1]->Val->Pointer); +} + +void StringStrncpy(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Pointer = strncpy(Param[0]->Val->Pointer, Param[1]->Val->Pointer, Param[2]->Val->Integer); +} + +void StringStrcmp(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = strcmp(Param[0]->Val->Pointer, Param[1]->Val->Pointer); +} + +void StringStrncmp(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = strncmp(Param[0]->Val->Pointer, Param[1]->Val->Pointer, Param[2]->Val->Integer); +} + +void StringStrcat(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Pointer = strcat(Param[0]->Val->Pointer, Param[1]->Val->Pointer); +} + +void StringStrncat(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Pointer = strncat(Param[0]->Val->Pointer, Param[1]->Val->Pointer, Param[2]->Val->Integer); +} + +#ifndef WIN32 +void StringIndex(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Pointer = index(Param[0]->Val->Pointer, Param[1]->Val->Integer); +} + +void StringRindex(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Pointer = rindex(Param[0]->Val->Pointer, Param[1]->Val->Integer); +} +#endif + +void StringStrlen(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = strlen(Param[0]->Val->Pointer); +} + +void StringMemset(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Pointer = memset(Param[0]->Val->Pointer, Param[1]->Val->Integer, Param[2]->Val->Integer); +} + +void StringMemcpy(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Pointer = memcpy(Param[0]->Val->Pointer, Param[1]->Val->Pointer, Param[2]->Val->Integer); +} + +void StringMemcmp(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = memcmp(Param[0]->Val->Pointer, Param[1]->Val->Pointer, Param[2]->Val->Integer); +} + +void StringMemmove(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Pointer = memmove(Param[0]->Val->Pointer, Param[1]->Val->Pointer, Param[2]->Val->Integer); +} + +void StringMemchr(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Pointer = memchr(Param[0]->Val->Pointer, Param[1]->Val->Integer, Param[2]->Val->Integer); +} + +void StringStrchr(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Pointer = strchr(Param[0]->Val->Pointer, Param[1]->Val->Integer); +} + +void StringStrrchr(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Pointer = strrchr(Param[0]->Val->Pointer, Param[1]->Val->Integer); +} + +/* We don't have locales - this is pointless +void StringStrcoll(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = strcoll(Param[0]->Val->Pointer, Param[1]->Val->Pointer); +} +*/ + +void StringStrerror(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Pointer = (void*) strerror(Param[0]->Val->Integer); +} + +void StringStrspn(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = strspn(Param[0]->Val->Pointer, Param[1]->Val->Pointer); +} + +void StringStrcspn(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = strcspn(Param[0]->Val->Pointer, Param[1]->Val->Pointer); +} + +void StringStrpbrk(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Pointer = strpbrk(Param[0]->Val->Pointer, Param[1]->Val->Pointer); +} + +void StringStrstr(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Pointer = strstr(Param[0]->Val->Pointer, Param[1]->Val->Pointer); +} + +void StringStrtok(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Pointer = strtok(Param[0]->Val->Pointer, Param[1]->Val->Pointer); +} + +/* - We don't have locales, this is pointless. +void StringStrxfrm(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = strxfrm(Param[0]->Val->Pointer, Param[1]->Val->Pointer, Param[2]->Val->Integer); +} +*/ + +#ifndef WIN32 +void StringStrdup(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Pointer = strdup(Param[0]->Val->Pointer); +} + +void StringStrtok_r(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Pointer = strtok_r(Param[0]->Val->Pointer, Param[1]->Val->Pointer, Param[2]->Val->Pointer); +} +#endif + +/* all string.h functions */ +struct LibraryFunction StringFunctions[] = +{ +#ifndef WIN32 + { StringIndex, "char *index(char *,int);" }, + { StringRindex, "char *rindex(char *,int);" }, +#endif + { StringMemcpy, "void *memcpy(void *,void *,int);" }, + { StringMemmove, "void *memmove(void *,void *,int);" }, + { StringMemchr, "void *memchr(char *,int,int);" }, + { StringMemcmp, "int memcmp(void *,void *,int);" }, + { StringMemset, "void *memset(void *,int,int);" }, + { StringStrcat, "char *strcat(char *,char *);" }, + { StringStrncat, "char *strncat(char *,char *,int);" }, + { StringStrchr, "char *strchr(char *,int);" }, + { StringStrrchr, "char *strrchr(char *,int);" }, + { StringStrcmp, "int strcmp(char *,char *);" }, + { StringStrncmp, "int strncmp(char *,char *,int);" }, +/* { StringStrcoll, "int strcoll(char *,char *);" }, */ + { StringStrcpy, "char *strcpy(char *,char *);" }, + { StringStrncpy, "char *strncpy(char *,char *,int);" }, + { StringStrerror, "char *strerror(int);" }, + { StringStrlen, "int strlen(char *);" }, + { StringStrspn, "int strspn(char *,char *);" }, + { StringStrcspn, "int strcspn(char *,char *);" }, + { StringStrpbrk, "char *strpbrk(char *,char *);" }, + { StringStrstr, "char *strstr(char *,char *);" }, + { StringStrtok, "char *strtok(char *,char *);" }, +/* { StringStrxfrm, "int strxfrm(char *,char *,int);" }, */ +#ifndef WIN32 + { StringStrdup, "char *strdup(char *);" }, + { StringStrtok_r, "char *strtok_r(char *,char *,char **);" }, +#endif + { NULL, NULL } +}; + +/* creates various system-dependent definitions */ +void StringSetupFunc(void) +{ + /* define NULL */ + if (!VariableDefined(TableStrRegister("NULL"))) + VariableDefinePlatformVar(NULL, "NULL", &IntType, (union AnyValue *)&ZeroValue, FALSE); +} + +#endif /* !BUILTIN_MINI_STDLIB */ diff --git a/src/cmd/picoc/cstdlib/time.c b/src/cmd/picoc/cstdlib/time.c new file mode 100644 index 0000000..52dc98f --- /dev/null +++ b/src/cmd/picoc/cstdlib/time.c @@ -0,0 +1,140 @@ +/* string.h library for large systems - small embedded systems use clibrary.c instead */ +#include +#include "../interpreter.h" + +#ifndef BUILTIN_MINI_STDLIB + +static int CLOCKS_PER_SECValue = CLOCKS_PER_SEC; + +#ifdef CLK_PER_SEC +static int CLK_PER_SECValue = CLK_PER_SEC; +#endif + +#ifdef CLK_TCK +static int CLK_TCKValue = CLK_TCK; +#endif + +void StdAsctime(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Pointer = asctime(Param[0]->Val->Pointer); +} + +/* we don't have clock +void StdClock(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = clock(); +} +*/ + +void StdCtime(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Pointer = ctime(Param[0]->Val->Pointer); +} + +#ifndef NO_FP +/* We don't have difftime +void StdDifftime(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->FP = difftime((time_t)Param[0]->Val->Integer, Param[1]->Val->Integer); +} +*/ +#endif + +void StdGmtime(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Pointer = gmtime(Param[0]->Val->Pointer); +} + +void StdLocaltime(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Pointer = localtime(Param[0]->Val->Pointer); +} + +/* We don't have mktime +void StdMktime(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = (int)mktime(Param[0]->Val->Pointer); +} +*/ + +void StdTime(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = (int)time(Param[0]->Val->Pointer); +} + +void StdStrftime(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = strftime(Param[0]->Val->Pointer, Param[1]->Val->Integer, Param[2]->Val->Pointer, Param[3]->Val->Pointer); +} + +#ifndef WIN32 +/* We don't have strptime +void StdStrptime(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + extern char *strptime(const char *s, const char *format, struct tm *tm); + + ReturnValue->Val->Pointer = strptime(Param[0]->Val->Pointer, Param[1]->Val->Pointer, Param[2]->Val->Pointer); +} +*/ + +/* We don't have gmtime_r +void StdGmtime_r(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Pointer = gmtime_r(Param[0]->Val->Pointer, Param[1]->Val->Pointer); +} +*/ + +/* We don't have timegm +void StdTimegm(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = timegm(Param[0]->Val->Pointer); +} +*/ +#endif + +/* handy structure definitions */ +const char StdTimeDefs[] = "\ +typedef int time_t; \ +typedef int clock_t;\ +"; + +/* all string.h functions */ +struct LibraryFunction StdTimeFunctions[] = +{ + { StdAsctime, "char *asctime(struct tm *);" }, +/* { StdClock, "time_t clock();" }, */ + { StdCtime, "char *ctime(int *);" }, +#ifndef NO_FP +/* { StdDifftime, "double difftime(int, int);" }, */ +#endif + { StdGmtime, "struct tm *gmtime(int *);" }, + { StdLocaltime, "struct tm *localtime(int *);" }, +/* { StdMktime, "int mktime(struct tm *ptm);" }, */ + { StdTime, "int time(int *);" }, + { StdStrftime, "int strftime(char *, int, char *, struct tm *);" }, +#ifndef WIN32 +/* { StdStrptime, "char *strptime(char *, char *, struct tm *);" },*/ +/* { StdGmtime_r, "struct tm *gmtime_r(int *, struct tm *);" },*/ +/* { StdTimegm, "int timegm(struct tm *);" }, */ +#endif + { NULL, NULL } +}; + + +/* creates various system-dependent definitions */ +void StdTimeSetupFunc(void) +{ + /* make a "struct tm" which is the same size as a native tm structure */ + TypeCreateOpaqueStruct(NULL, TableStrRegister("tm"), sizeof(struct tm)); + + /* define CLK_PER_SEC etc. */ + VariableDefinePlatformVar(NULL, "CLOCKS_PER_SEC", &IntType, (union AnyValue *)&CLOCKS_PER_SECValue, FALSE); +#ifdef CLK_PER_SEC + VariableDefinePlatformVar(NULL, "CLK_PER_SEC", &IntType, (union AnyValue *)&CLK_PER_SECValue, FALSE); +#endif +#ifdef CLK_TCK + VariableDefinePlatformVar(NULL, "CLK_TCK", &IntType, (union AnyValue *)&CLK_TCKValue, FALSE); +#endif +} + +#endif /* !BUILTIN_MINI_STDLIB */ diff --git a/src/cmd/picoc/cstdlib/unistd.c b/src/cmd/picoc/cstdlib/unistd.c new file mode 100644 index 0000000..30ca390 --- /dev/null +++ b/src/cmd/picoc/cstdlib/unistd.c @@ -0,0 +1,531 @@ +/* stdlib.h library for large systems - small embedded systems use clibrary.c instead */ +#include +#include +#include +#include "../interpreter.h" + +#ifndef BUILTIN_MINI_STDLIB + +static int ZeroValue = 0; + +void UnistdAccess(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = access(Param[0]->Val->Pointer, Param[1]->Val->Integer); +} + +void UnistdAlarm(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = alarm(Param[0]->Val->Integer); +} + +void UnistdChdir(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = chdir(Param[0]->Val->Pointer); +} + +void UnistdChroot(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = chroot(Param[0]->Val->Pointer); +} + +void UnistdChown(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = chown(Param[0]->Val->Pointer, Param[1]->Val->Integer, Param[2]->Val->Integer); +} + +void UnistdClose(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = close(Param[0]->Val->Integer); +} + +/* +void UnistdConfstr(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = confstr(Param[0]->Val->Integer, Param[1]->Val->Pointer, Param[2]->Val->Integer); +} +*/ + +/* +void UnistdCtermid(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Pointer = ctermid(Param[0]->Val->Pointer); +} +*/ +#if 0 +void UnistdCuserid(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Pointer = cuserid(Param[0]->Val->Pointer); +} +#endif + +void UnistdDup(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = dup(Param[0]->Val->Integer); +} + +void UnistdDup2(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = dup2(Param[0]->Val->Integer, Param[1]->Val->Integer); +} + +void Unistd_Exit(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + _exit(Param[0]->Val->Integer); +} + +void UnistdFchown(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = fchown(Param[0]->Val->Integer, Param[1]->Val->Integer, Param[2]->Val->Integer); +} + +void UnistdFchdir(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = fchdir(Param[0]->Val->Integer); +} + +/* +void UnistdFdatasync(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = fdatasync(Param[0]->Val->Integer); +} +*/ + +void UnistdFork(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = fork(); +} + +/* +void UnistdFpathconf(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = fpathconf(Param[0]->Val->Integer, Param[1]->Val->Integer); +} +*/ + +void UnistdFsync(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = fsync(Param[0]->Val->Integer); +} + +void UnistdFtruncate(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = ftruncate(Param[0]->Val->Integer, Param[1]->Val->Integer); +} + +/* +void UnistdGetcwd(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Pointer = getcwd(Param[0]->Val->Pointer, Param[1]->Val->Integer); +} +*/ + +void UnistdGetdtablesize(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = getdtablesize(); +} + +void UnistdGetegid(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = getegid(); +} + +void UnistdGeteuid(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = geteuid(); +} + +void UnistdGetgid(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = getgid(); +} + +void UnistdGethostid(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = gethostid(); +} + +void UnistdGetlogin(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Pointer = getlogin(); +} + +/* +void UnistdGetlogin_r(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = getlogin_r(Param[0]->Val->Pointer, Param[1]->Val->Integer); +} +*/ + +void UnistdGetpagesize(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = getpagesize(); +} + +void UnistdGetpass(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Pointer = getpass(Param[0]->Val->Pointer); +} + +#if 0 +void UnistdGetpgid(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = getpgid(Param[0]->Val->Integer); +} +#endif + +void UnistdGetpgrp(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = getpgrp(); +} + +void UnistdGetpid(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = getpid(); +} + +void UnistdGetppid(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = getppid(); +} + +#if 0 +void UnistdGetsid(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = getsid(Param[0]->Val->Integer); +} +#endif + +void UnistdGetuid(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = getuid(); +} + +/* +void UnistdGetwd(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Pointer = getcwd(Param[0]->Val->Pointer, PATH_MAX); +} +*/ + +void UnistdIsatty(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = isatty(Param[0]->Val->Integer); +} + +/* +void UnistdLchown(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = lchown(Param[0]->Val->Pointer, Param[1]->Val->Integer, Param[2]->Val->Integer); +} +*/ + +void UnistdLink(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = link(Param[0]->Val->Pointer, Param[1]->Val->Pointer); +} + +/* +void UnistdLockf(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = lockf(Param[0]->Val->Integer, Param[1]->Val->Integer, Param[2]->Val->Integer); +} +*/ + +void UnistdLseek(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = lseek(Param[0]->Val->Integer, Param[1]->Val->Integer, Param[2]->Val->Integer); +} + +void UnistdNice(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = nice(Param[0]->Val->Integer); +} + +/* +void UnistdPathconf(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = pathconf(Param[0]->Val->Pointer, Param[1]->Val->Integer); +} +*/ + +void UnistdPause(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = pause(); +} + +#if 0 +void UnistdPread(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = pread(Param[0]->Val->Integer, Param[1]->Val->Pointer, Param[2]->Val->Integer, Param[3]->Val->Integer); +} + +void UnistdPwrite(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = pwrite(Param[0]->Val->Integer, Param[1]->Val->Pointer, Param[2]->Val->Integer, Param[3]->Val->Integer); +} +#endif + +void UnistdRead(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = read(Param[0]->Val->Integer, Param[1]->Val->Pointer, Param[2]->Val->Integer); +} + +void UnistdReadlink(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = readlink(Param[0]->Val->Pointer, Param[1]->Val->Pointer, Param[2]->Val->Integer); +} + +void UnistdRmdir(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = rmdir(Param[0]->Val->Pointer); +} + +void UnistdSbrk(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Pointer = sbrk(Param[0]->Val->Integer); +} + +void UnistdSetgid(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = setgid(Param[0]->Val->Integer); +} + +/* +void UnistdSetpgid(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = setpgid(Param[0]->Val->Integer, Param[1]->Val->Integer); +} +*/ + +void UnistdSetpgrp(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = setpgrp(); +} + +void UnistdSetregid(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = setregid(Param[0]->Val->Integer, Param[1]->Val->Integer); +} + +void UnistdSetreuid(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = setreuid(Param[0]->Val->Integer, Param[1]->Val->Integer); +} + +/* +void UnistdSetsid(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = setsid(); +} +*/ + +void UnistdSetuid(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = setuid(Param[0]->Val->Integer); +} + +void UnistdSleep(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = sleep(Param[0]->Val->Integer); +} + +#if 0 +void UnistdSwab(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = swab(Param[0]->Val->Pointer, Param[1]->Val->Pointer, Param[2]->Val->Integer); +} +#endif + +void UnistdSymlink(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = symlink(Param[0]->Val->Pointer, Param[1]->Val->Pointer); +} + +void UnistdSync(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + sync(); +} + +/* +void UnistdSysconf(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = sysconf(Param[0]->Val->Integer); +} +*/ + +/* +void UnistdTcgetpgrp(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = tcgetpgrp(Param[0]->Val->Integer); +} +*/ + +/* +void UnistdTcsetpgrp(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = tcsetpgrp(Param[0]->Val->Integer, Param[1]->Val->Integer); +} +*/ + +void UnistdTruncate(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = truncate(Param[0]->Val->Pointer, Param[1]->Val->Integer); +} + +void UnistdTtyname(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Pointer = ttyname(Param[0]->Val->Integer); +} + +/* +void UnistdTtyname_r(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = ttyname_r(Param[0]->Val->Integer, Param[1]->Val->Pointer, Param[2]->Val->Integer); +} +*/ + +void UnistdUalarm(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = ualarm(Param[0]->Val->Integer, Param[1]->Val->Integer); +} + +void UnistdUnlink(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = unlink(Param[0]->Val->Pointer); +} + +void UnistdUsleep(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = 0; + usleep(Param[0]->Val->Integer); +} + +void UnistdVfork(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = vfork(); +} + +void UnistdWrite(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = write(Param[0]->Val->Integer, Param[1]->Val->Pointer, Param[2]->Val->Integer); +} + + +/* handy structure definitions */ +const char UnistdDefs[] = "\ +typedef int uid_t; \ +typedef int gid_t; \ +typedef int pid_t; \ +typedef int off_t; \ +typedef int size_t; \ +typedef int ssize_t; \ +typedef int useconds_t;\ +typedef int intptr_t;\ +"; + +/* all unistd.h functions */ +struct LibraryFunction UnistdFunctions[] = +{ + { UnistdAccess, "int access(char *, int);" }, + { UnistdAlarm, "unsigned int alarm(unsigned int);" }, +/* { UnistdBrk, "int brk(void *);" }, */ + { UnistdChdir, "int chdir(char *);" }, + { UnistdChroot, "int chroot(char *);" }, + { UnistdChown, "int chown(char *, uid_t, gid_t);" }, + { UnistdClose, "int close(int);" }, +/* { UnistdConfstr, "size_t confstr(int, char *, size_t);" }, */ +/* { UnistdCtermid, "char *ctermid(char *);" }, */ +/* { UnistdCuserid, "char *cuserid(char *);" }, */ + { UnistdDup, "int dup(int);" }, + { UnistdDup2, "int dup2(int, int);" }, +/* { UnistdEncrypt, "void encrypt(char[64], int);" }, */ +/* { UnistdExecl, "int execl(char *, char *, ...);" }, */ +/* { UnistdExecle, "int execle(char *, char *, ...);" }, */ +/* { UnistdExeclp, "int execlp(char *, char *, ...);" }, */ +/* { UnistdExecv, "int execv(char *, char *[]);" }, */ +/* { UnistdExecve, "int execve(char *, char *[], char *[]);" }, */ +/* { UnistdExecvp, "int execvp(char *, char *[]);" }, */ + { Unistd_Exit, "void _exit(int);" }, + { UnistdFchown, "int fchown(int, uid_t, gid_t);" }, + { UnistdFchdir, "int fchdir(int);" }, +/* { UnistdFdatasync, "int fdatasync(int);" }, */ + { UnistdFork, "pid_t fork(void);" }, +/* { UnistdFpathconf, "long fpathconf(int, int);" }, */ + { UnistdFsync, "int fsync(int);" }, + { UnistdFtruncate, "int ftruncate(int, off_t);" }, +/* { UnistdGetcwd, "char *getcwd(char *, size_t);" },*/ + { UnistdGetdtablesize, "int getdtablesize(void);" }, + { UnistdGetegid, "gid_t getegid(void);" }, + { UnistdGeteuid, "uid_t geteuid(void);" }, + { UnistdGetgid, "gid_t getgid(void);" }, +/* { UnistdGetgroups, "int getgroups(int, gid_t []);" }, */ + { UnistdGethostid, "long gethostid(void);" }, + { UnistdGetlogin, "char *getlogin(void);" }, +/* { UnistdGetlogin_r, "int getlogin_r(char *, size_t);" },*/ +/* { UnistdGetopt, "int getopt(int, char * [], char *);" }, */ + { UnistdGetpagesize, "int getpagesize(void);" }, + { UnistdGetpass, "char *getpass(char *);" }, +/* { UnistdGetpgid, "pid_t getpgid(pid_t);" }, */ + { UnistdGetpgrp, "pid_t getpgrp(void);" }, + { UnistdGetpid, "pid_t getpid(void);" }, + { UnistdGetppid, "pid_t getppid(void);" }, +/* { UnistdGetsid, "pid_t getsid(pid_t);" }, */ + { UnistdGetuid, "uid_t getuid(void);" }, +/* { UnistdGetwd, "char *getwd(char *);" }, */ + { UnistdIsatty, "int isatty(int);" }, +/* { UnistdLchown, "int lchown(char *, uid_t, gid_t);" },*/ + { UnistdLink, "int link(char *, char *);" }, +/* { UnistdLockf, "int lockf(int, int, off_t);" },*/ + { UnistdLseek, "off_t lseek(int, off_t, int);" }, + { UnistdNice, "int nice(int);" }, +/* { UnistdPathconf, "long pathconf(char *, int);" },*/ + { UnistdPause, "int pause(void);" }, +/* { UnistdPipe, "int pipe(int [2]);" }, */ +/* { UnistdPread, "ssize_t pread(int, void *, size_t, off_t);" }, */ +/* { UnistdPthread_atfork,"int pthread_atfork(void (*)(void), void (*)(void), void(*)(void));" }, */ +/* { UnistdPwrite, "ssize_t pwrite(int, void *, size_t, off_t);" }, */ + { UnistdRead, "ssize_t read(int, void *, size_t);" }, + { UnistdReadlink, "int readlink(char *, char *, size_t);" }, + { UnistdRmdir, "int rmdir(char *);" }, + { UnistdSbrk, "void *sbrk(intptr_t);" }, + { UnistdSetgid, "int setgid(gid_t);" }, +/* { UnistdSetpgid, "int setpgid(pid_t, pid_t);" }, */ + { UnistdSetpgrp, "pid_t setpgrp(void);" }, + { UnistdSetregid, "int setregid(gid_t, gid_t);" }, + { UnistdSetreuid, "int setreuid(uid_t, uid_t);" }, +/* { UnistdSetsid, "pid_t setsid(void);" }, */ + { UnistdSetuid, "int setuid(uid_t);" }, + { UnistdSleep, "unsigned int sleep(unsigned int);" }, +/* { UnistdSwab, "void swab(void *, void *, ssize_t);" }, */ + { UnistdSymlink, "int symlink(char *, char *);" }, + { UnistdSync, "void sync(void);" }, +/* { UnistdSysconf, "long sysconf(int);" }, */ +/* { UnistdTcgetpgrp, "pid_t tcgetpgrp(int);" }, */ +/* { UnistdTcsetpgrp, "int tcsetpgrp(int, pid_t);" },*/ + { UnistdTruncate, "int truncate(char *, off_t);" }, + { UnistdTtyname, "char *ttyname(int);" }, +/* { UnistdTtyname_r, "int ttyname_r(int, char *, size_t);" }, */ + { UnistdUalarm, "useconds_t ualarm(useconds_t, useconds_t);" }, + { UnistdUnlink, "int unlink(char *);" }, + { UnistdUsleep, "int usleep(useconds_t);" }, + { UnistdVfork, "pid_t vfork(void);" }, + { UnistdWrite, "ssize_t write(int, void *, size_t);" }, + { NULL, NULL } +}; + +/* creates various system-dependent definitions */ +void UnistdSetupFunc(void) +{ + /* define NULL */ + if (!VariableDefined(TableStrRegister("NULL"))) + VariableDefinePlatformVar(NULL, "NULL", &IntType, (union AnyValue *)&ZeroValue, FALSE); + + /* define optarg and friends */ + VariableDefinePlatformVar(NULL, "optarg", CharPtrType, (union AnyValue *)&optarg, TRUE); + VariableDefinePlatformVar(NULL, "optind", &IntType, (union AnyValue *)&optind, TRUE); + VariableDefinePlatformVar(NULL, "opterr", &IntType, (union AnyValue *)&opterr, TRUE); + VariableDefinePlatformVar(NULL, "optopt", &IntType, (union AnyValue *)&optopt, TRUE); +} + +#endif /* !BUILTIN_MINI_STDLIB */ + diff --git a/src/cmd/picoc/debug.c b/src/cmd/picoc/debug.c new file mode 100644 index 0000000..ba09fe2 --- /dev/null +++ b/src/cmd/picoc/debug.c @@ -0,0 +1,127 @@ +/* picoc interactive debugger */ + +#ifndef NO_DEBUGGER + +#include "interpreter.h" + +#define BREAKPOINT_TABLE_SIZE 21 +#define BREAKPOINT_HASH(p) ( ((unsigned long)(p)->FileName) ^ (((p)->Line << 16) | ((p)->CharacterPos << 16)) ) + +struct Table BreakpointTable; +struct TableEntry *BreakpointHashTable[BREAKPOINT_TABLE_SIZE]; +int BreakpointCount = 0; +int DebugManualBreak = FALSE; + +/* initialise the debugger by clearing the breakpoint table */ +void DebugInit() +{ + TableInitTable(&BreakpointTable, &BreakpointHashTable[0], BREAKPOINT_TABLE_SIZE, TRUE); + BreakpointCount = 0; +} + +/* free the contents of the breakpoint table */ +void DebugCleanup() +{ + struct TableEntry *Entry; + struct TableEntry *NextEntry; + int Count; + + for (Count = 0; Count < BreakpointTable.Size; Count++) + { + for (Entry = BreakpointHashTable[Count]; Entry != NULL; Entry = NextEntry) + { + NextEntry = Entry->Next; + HeapFreeMem(Entry); + } + } +} + +/* search the table for a breakpoint */ +static struct TableEntry *DebugTableSearchBreakpoint(struct ParseState *Parser, int *AddAt) +{ + struct TableEntry *Entry; + int HashValue = BREAKPOINT_HASH(Parser) % BreakpointTable.Size; + + for (Entry = BreakpointHashTable[HashValue]; Entry != NULL; Entry = Entry->Next) + { + if (Entry->p.b.FileName == Parser->FileName && Entry->p.b.Line == Parser->Line && Entry->p.b.CharacterPos == Parser->CharacterPos) + return Entry; /* found */ + } + + *AddAt = HashValue; /* didn't find it in the chain */ + return NULL; +} + +/* set a breakpoint in the table */ +void DebugSetBreakpoint(struct ParseState *Parser) +{ + int AddAt; + struct TableEntry *FoundEntry = DebugTableSearchBreakpoint(Parser, &AddAt); + + if (FoundEntry == NULL) + { + /* add it to the table */ + struct TableEntry *NewEntry = HeapAllocMem(sizeof(struct TableEntry)); + if (NewEntry == NULL) + ProgramFail(NULL, "out of memory"); + + NewEntry->p.b.FileName = Parser->FileName; + NewEntry->p.b.Line = Parser->Line; + NewEntry->p.b.CharacterPos = Parser->CharacterPos; + NewEntry->Next = BreakpointHashTable[AddAt]; + BreakpointHashTable[AddAt] = NewEntry; + BreakpointCount++; + } +} + +/* delete a breakpoint from the hash table */ +int DebugClearBreakpoint(struct ParseState *Parser) +{ + struct TableEntry **EntryPtr; + int HashValue = BREAKPOINT_HASH(Parser) % BreakpointTable.Size; + + for (EntryPtr = &BreakpointHashTable[HashValue]; *EntryPtr != NULL; EntryPtr = &(*EntryPtr)->Next) + { + struct TableEntry *DeleteEntry = *EntryPtr; + if (DeleteEntry->p.b.FileName == Parser->FileName && DeleteEntry->p.b.Line == Parser->Line && DeleteEntry->p.b.CharacterPos == Parser->CharacterPos) + { + *EntryPtr = DeleteEntry->Next; + HeapFreeMem(DeleteEntry); + BreakpointCount--; + + return TRUE; + } + } + + return FALSE; +} + +/* before we run a statement, check if there's anything we have to do with the debugger here */ +void DebugCheckStatement(struct ParseState *Parser) +{ + int DoBreak = FALSE; + int AddAt; + + /* has the user manually pressed break? */ + if (DebugManualBreak) + { + DoBreak = TRUE; + DebugManualBreak = FALSE; + } + + /* is this a breakpoint location? */ + if (BreakpointCount != 0 && DebugTableSearchBreakpoint(Parser, &AddAt) != NULL) + DoBreak = TRUE; + + /* handle a break */ + if (DoBreak) + { + PlatformPrintf("Handling a break\n"); + PicocParseInteractiveNoStartPrompt(FALSE); + } +} + +void DebugStep() +{ +} +#endif /* !NO_DEBUGGER */ diff --git a/src/cmd/picoc/expression.c b/src/cmd/picoc/expression.c new file mode 100644 index 0000000..597016b --- /dev/null +++ b/src/cmd/picoc/expression.c @@ -0,0 +1,1492 @@ +/* picoc expression evaluator - a stack-based expression evaluation system + * which handles operator precedence */ + +#include "interpreter.h" + +/* whether evaluation is left to right for a given precedence level */ +#define IS_LEFT_TO_RIGHT(p) ((p) != 2 && (p) != 14) +#define BRACKET_PRECEDENCE 20 +#define IS_TYPE_TOKEN(t) ((t) >= TokenIntType && (t) <= TokenUnsignedType) + +#define DEEP_PRECEDENCE (BRACKET_PRECEDENCE*1000) + +#ifdef DEBUG_EXPRESSIONS +#define debugf printf +#else +void debugf(char *Format, ...) +{ +} +#endif + +/* local prototypes */ +enum OperatorOrder +{ + OrderNone, + OrderPrefix, + OrderInfix, + OrderPostfix +}; + +/* a stack of expressions we use in evaluation */ +struct ExpressionStack +{ + struct ExpressionStack *Next; /* the next lower item on the stack */ + struct Value *Val; /* the value for this stack node */ + enum LexToken Op; /* the operator */ + short unsigned int Precedence; /* the operator precedence of this node */ + unsigned char Order; /* the evaluation order of this operator */ +}; + +/* operator precedence definitions */ +struct OpPrecedence +{ + unsigned int PrefixPrecedence:4; + unsigned int PostfixPrecedence:4; + unsigned int InfixPrecedence:4; + char *Name; +}; + +/* NOTE: the order of this array must correspond exactly to the order of these tokens in enum LexToken */ +static struct OpPrecedence OperatorPrecedence[] = +{ + /* TokenNone, */ { 0, 0, 0, "none" }, + /* TokenComma, */ { 0, 0, 0, "," }, + /* TokenAssign, */ { 0, 0, 2, "=" }, /* TokenAddAssign, */ { 0, 0, 2, "+=" }, /* TokenSubtractAssign, */ { 0, 0, 2, "-=" }, + /* TokenMultiplyAssign, */ { 0, 0, 2, "*=" }, /* TokenDivideAssign, */ { 0, 0, 2, "/=" }, /* TokenModulusAssign, */ { 0, 0, 2, "%=" }, + /* TokenShiftLeftAssign, */ { 0, 0, 2, "<<=" }, /* TokenShiftRightAssign, */ { 0, 0, 2, ">>=" }, /* TokenArithmeticAndAssign, */ { 0, 0, 2, "&=" }, + /* TokenArithmeticOrAssign, */ { 0, 0, 2, "|=" }, /* TokenArithmeticExorAssign, */ { 0, 0, 2, "^=" }, + /* TokenQuestionMark, */ { 0, 0, 3, "?" }, /* TokenColon, */ { 0, 0, 3, ":" }, + /* TokenLogicalOr, */ { 0, 0, 4, "||" }, + /* TokenLogicalAnd, */ { 0, 0, 5, "&&" }, + /* TokenArithmeticOr, */ { 0, 0, 6, "|" }, + /* TokenArithmeticExor, */ { 0, 0, 7, "^" }, + /* TokenAmpersand, */ { 14, 0, 8, "&" }, + /* TokenEqual, */ { 0, 0, 9, "==" }, /* TokenNotEqual, */ { 0, 0, 9, "!=" }, + /* TokenLessThan, */ { 0, 0, 10, "<" }, /* TokenGreaterThan, */ { 0, 0, 10, ">" }, /* TokenLessEqual, */ { 0, 0, 10, "<=" }, /* TokenGreaterEqual, */ { 0, 0, 10, ">=" }, + /* TokenShiftLeft, */ { 0, 0, 11, "<<" }, /* TokenShiftRight, */ { 0, 0, 11, ">>" }, + /* TokenPlus, */ { 14, 0, 12, "+" }, /* TokenMinus, */ { 14, 0, 12, "-" }, + /* TokenAsterisk, */ { 14, 0, 13, "*" }, /* TokenSlash, */ { 0, 0, 13, "/" }, /* TokenModulus, */ { 0, 0, 13, "%" }, + /* TokenIncrement, */ { 14, 15, 0, "++" }, /* TokenDecrement, */ { 14, 15, 0, "--" }, /* TokenUnaryNot, */ { 14, 0, 0, "!" }, /* TokenUnaryExor, */ { 14, 0, 0, "~" }, /* TokenSizeof, */ { 14, 0, 0, "sizeof" }, /* TokenCast, */ { 14, 0, 0, "cast" }, + /* TokenLeftSquareBracket, */ { 0, 0, 15, "[" }, /* TokenRightSquareBracket, */ { 0, 15, 0, "]" }, /* TokenDot, */ { 0, 0, 15, "." }, /* TokenArrow, */ { 0, 0, 15, "->" }, + /* TokenOpenBracket, */ { 15, 0, 0, "(" }, /* TokenCloseBracket, */ { 0, 15, 0, ")" } +}; + +void ExpressionParseFunctionCall(struct ParseState *Parser, struct ExpressionStack **StackTop, const char *FuncName, int RunIt); + +#ifdef DEBUG_EXPRESSIONS +/* show the contents of the expression stack */ +void ExpressionStackShow(struct ExpressionStack *StackTop) +{ + printf("Expression stack [0x%lx,0x%lx]: ", (long)HeapStackTop, (long)StackTop); + + while (StackTop != NULL) + { + if (StackTop->Order == OrderNone) + { + /* it's a value */ + if (StackTop->Val->IsLValue) + printf("lvalue="); + else + printf("value="); + + switch (StackTop->Val->Typ->Base) + { + case TypeVoid: printf("void"); break; + case TypeInt: printf("%d:int", StackTop->Val->Val->Integer); break; + case TypeShort: printf("%d:short", StackTop->Val->Val->ShortInteger); break; + case TypeChar: printf("%d:char", StackTop->Val->Val->Character); break; + case TypeLong: printf("%d:long", StackTop->Val->Val->LongInteger); break; + case TypeUnsignedShort: printf("%d:unsigned short", StackTop->Val->Val->UnsignedShortInteger); break; + case TypeUnsignedInt: printf("%d:unsigned int", StackTop->Val->Val->UnsignedInteger); break; + case TypeUnsignedLong: printf("%d:unsigned long", StackTop->Val->Val->UnsignedLongInteger); break; + case TypeFP: printf("%f:fp", StackTop->Val->Val->FP); break; + case TypeFunction: printf("%s:function", StackTop->Val->Val->Identifier); break; + case TypeMacro: printf("%s:macro", StackTop->Val->Val->Identifier); break; + case TypePointer: + if (StackTop->Val->Val->Pointer == NULL) + printf("ptr(NULL)"); + else if (StackTop->Val->Typ->FromType->Base == TypeChar) + printf("\"%s\":string", (char *)StackTop->Val->Val->Pointer); + else + printf("ptr(0x%lx)", (long)StackTop->Val->Val->Pointer); + break; + case TypeArray: printf("array"); break; + case TypeStruct: printf("%s:struct", StackTop->Val->Val->Identifier); break; + case TypeUnion: printf("%s:union", StackTop->Val->Val->Identifier); break; + case TypeEnum: printf("%s:enum", StackTop->Val->Val->Identifier); break; + case Type_Type: PrintType(StackTop->Val->Val->Typ, CStdOut); printf(":type"); break; + default: printf("unknown"); break; + } + printf("[0x%lx,0x%lx]", (long)StackTop, (long)StackTop->Val); + } + else + { + /* it's an operator */ + printf("op='%s' %s %d", OperatorPrecedence[(int)StackTop->Op].Name, + (StackTop->Order == OrderPrefix) ? "prefix" : ((StackTop->Order == OrderPostfix) ? "postfix" : "infix"), + StackTop->Precedence); + printf("[0x%lx]", (long)StackTop); + } + + StackTop = StackTop->Next; + if (StackTop != NULL) + printf(", "); + } + + printf("\n"); +} +#endif + +long ExpressionCoerceInteger(struct Value *Val) +{ + switch (Val->Typ->Base) + { + case TypeInt: return (long)Val->Val->Integer; + case TypeChar: return (long)Val->Val->Character; + case TypeShort: return (long)Val->Val->ShortInteger; + case TypeLong: return (long)Val->Val->LongInteger; + case TypeUnsignedInt: return (long)Val->Val->UnsignedInteger; + case TypeUnsignedShort: return (long)Val->Val->UnsignedShortInteger; + case TypeUnsignedLong: return (long)Val->Val->UnsignedLongInteger; + case TypePointer: return (long)Val->Val->Pointer; +#ifndef NO_FP + case TypeFP: return (long)Val->Val->FP; +#endif + default: return 0; + } +} + +unsigned long ExpressionCoerceUnsignedInteger(struct Value *Val) +{ + switch (Val->Typ->Base) + { + case TypeInt: return (unsigned long)Val->Val->Integer; + case TypeChar: return (unsigned long)Val->Val->Character; + case TypeShort: return (unsigned long)Val->Val->ShortInteger; + case TypeLong: return (unsigned long)Val->Val->LongInteger; + case TypeUnsignedInt: return (unsigned long)Val->Val->UnsignedInteger; + case TypeUnsignedShort: return (unsigned long)Val->Val->UnsignedShortInteger; + case TypeUnsignedLong: return (unsigned long)Val->Val->UnsignedLongInteger; + case TypePointer: return (unsigned long)Val->Val->Pointer; +#ifndef NO_FP + case TypeFP: return (unsigned long)Val->Val->FP; +#endif + default: return 0; + } +} + +#ifndef NO_FP +double ExpressionCoerceFP(struct Value *Val) +{ +#ifndef BROKEN_FLOAT_CASTS + int IntVal; + unsigned UnsignedVal; + + switch (Val->Typ->Base) + { + case TypeInt: IntVal = Val->Val->Integer; return (double)IntVal; + case TypeChar: IntVal = Val->Val->Character; return (double)IntVal; + case TypeShort: IntVal = Val->Val->ShortInteger; return (double)IntVal; + case TypeLong: IntVal = Val->Val->LongInteger; return (double)IntVal; + case TypeUnsignedInt: UnsignedVal = Val->Val->UnsignedInteger; return (double)UnsignedVal; + case TypeUnsignedShort: UnsignedVal = Val->Val->UnsignedShortInteger; return (double)UnsignedVal; + case TypeUnsignedLong: UnsignedVal = Val->Val->UnsignedLongInteger; return (double)UnsignedVal; + case TypeFP: return Val->Val->FP; + default: return 0.0; + } +#else + switch (Val->Typ->Base) + { + case TypeInt: return (double)Val->Val->Integer; + case TypeChar: return (double)Val->Val->Character; + case TypeShort: return (double)Val->Val->ShortInteger; + case TypeLong: return (double)Val->Val->LongInteger; + case TypeUnsignedInt: return (double)Val->Val->UnsignedInteger; + case TypeUnsignedShort: return (double)Val->Val->UnsignedShortInteger; + case TypeUnsignedLong: return (double)Val->Val->UnsignedLongInteger; + case TypeFP: return (double)Val->Val->FP; + default: return 0.0; + } +#endif +} +#endif + +/* assign an integer value */ +long ExpressionAssignInt(struct ParseState *Parser, struct Value *DestValue, long FromInt, int After) +{ + long Result; + + if (!DestValue->IsLValue) + ProgramFail(Parser, "can't assign to this"); + + if (After) + Result = ExpressionCoerceInteger(DestValue); + else + Result = FromInt; + + switch (DestValue->Typ->Base) + { + case TypeInt: DestValue->Val->Integer = FromInt; break; + case TypeShort: DestValue->Val->ShortInteger = (short)FromInt; break; + case TypeChar: DestValue->Val->Character = (unsigned char)FromInt; break; + case TypeLong: DestValue->Val->LongInteger = (long)FromInt; break; + case TypeUnsignedInt: DestValue->Val->UnsignedInteger = (unsigned int)FromInt; break; + case TypeUnsignedShort: DestValue->Val->UnsignedShortInteger = (unsigned short)FromInt; break; + case TypeUnsignedLong: DestValue->Val->UnsignedLongInteger = (unsigned long)FromInt; break; + default: break; + } + return Result; +} + +#ifndef NO_FP +/* assign a floating point value */ +double ExpressionAssignFP(struct ParseState *Parser, struct Value *DestValue, double FromFP) +{ + if (!DestValue->IsLValue) + ProgramFail(Parser, "can't assign to this"); + + DestValue->Val->FP = FromFP; + return FromFP; +} +#endif + +/* push a node on to the expression stack */ +void ExpressionStackPushValueNode(struct ParseState *Parser, struct ExpressionStack **StackTop, struct Value *ValueLoc) +{ + struct ExpressionStack *StackNode = VariableAlloc(Parser, sizeof(struct ExpressionStack), FALSE); + StackNode->Next = *StackTop; + StackNode->Val = ValueLoc; + *StackTop = StackNode; +#ifdef FANCY_ERROR_MESSAGES + StackNode->Line = Parser->Line; + StackNode->CharacterPos = Parser->CharacterPos; +#endif +#ifdef DEBUG_EXPRESSIONS + ExpressionStackShow(*StackTop); +#endif +} + +/* push a blank value on to the expression stack by type */ +struct Value *ExpressionStackPushValueByType(struct ParseState *Parser, struct ExpressionStack **StackTop, struct ValueType *PushType) +{ + struct Value *ValueLoc = VariableAllocValueFromType(Parser, PushType, FALSE, NULL, FALSE); + ExpressionStackPushValueNode(Parser, StackTop, ValueLoc); + + return ValueLoc; +} + +/* push a value on to the expression stack */ +void ExpressionStackPushValue(struct ParseState *Parser, struct ExpressionStack **StackTop, struct Value *PushValue) +{ + struct Value *ValueLoc = VariableAllocValueAndCopy(Parser, PushValue, FALSE); + ExpressionStackPushValueNode(Parser, StackTop, ValueLoc); +} + +void ExpressionStackPushLValue(struct ParseState *Parser, struct ExpressionStack **StackTop, struct Value *PushValue, int Offset) +{ + struct Value *ValueLoc = VariableAllocValueShared(Parser, PushValue); + ValueLoc->Val = (void *)((char *)ValueLoc->Val + Offset); + ExpressionStackPushValueNode(Parser, StackTop, ValueLoc); +} + +void ExpressionStackPushDereference(struct ParseState *Parser, struct ExpressionStack **StackTop, struct Value *DereferenceValue) +{ + struct Value *DerefVal; + struct Value *ValueLoc; + int Offset; + struct ValueType *DerefType; + int DerefIsLValue; + void *DerefDataLoc = VariableDereferencePointer(Parser, DereferenceValue, &DerefVal, &Offset, &DerefType, &DerefIsLValue); + if (DerefDataLoc == NULL) + ProgramFail(Parser, "NULL pointer dereference"); + + ValueLoc = VariableAllocValueFromExistingData(Parser, DerefType, (union AnyValue *)DerefDataLoc, DerefIsLValue, DerefVal); + ExpressionStackPushValueNode(Parser, StackTop, ValueLoc); +} + +void ExpressionPushInt(struct ParseState *Parser, struct ExpressionStack **StackTop, long IntValue) +{ + struct Value *ValueLoc = VariableAllocValueFromType(Parser, &IntType, FALSE, NULL, FALSE); + ValueLoc->Val->Integer = IntValue; + ExpressionStackPushValueNode(Parser, StackTop, ValueLoc); +} + +#ifndef NO_FP +void ExpressionPushFP(struct ParseState *Parser, struct ExpressionStack **StackTop, double FPValue) +{ + struct Value *ValueLoc = VariableAllocValueFromType(Parser, &FPType, FALSE, NULL, FALSE); + ValueLoc->Val->FP = FPValue; + ExpressionStackPushValueNode(Parser, StackTop, ValueLoc); +} +#endif + +/* assign to a pointer */ +void ExpressionAssignToPointer(struct ParseState *Parser, struct Value *ToValue, struct Value *FromValue, const char *FuncName, int ParamNo, int AllowPointerCoercion) +{ + struct ValueType *PointedToType = ToValue->Typ->FromType; + + if (FromValue->Typ == ToValue->Typ || FromValue->Typ == VoidPtrType || (ToValue->Typ == VoidPtrType && FromValue->Typ->Base == TypePointer)) + ToValue->Val->Pointer = FromValue->Val->Pointer; /* plain old pointer assignment */ + + else if (FromValue->Typ->Base == TypeArray && (PointedToType == FromValue->Typ->FromType || ToValue->Typ == VoidPtrType)) + { + /* the form is: blah *x = array of blah */ + ToValue->Val->Pointer = (void *)&FromValue->Val->ArrayMem[0]; + } + else if (FromValue->Typ->Base == TypePointer && FromValue->Typ->FromType->Base == TypeArray && + (PointedToType == FromValue->Typ->FromType->FromType || ToValue->Typ == VoidPtrType) ) + { + /* the form is: blah *x = pointer to array of blah */ + ToValue->Val->Pointer = VariableDereferencePointer(Parser, FromValue, NULL, NULL, NULL, NULL); + } + else if (IS_NUMERIC_COERCIBLE(FromValue) && ExpressionCoerceInteger(FromValue) == 0) + { + /* null pointer assignment */ + ToValue->Val->Pointer = NULL; + } + else if (AllowPointerCoercion && IS_NUMERIC_COERCIBLE(FromValue)) + { + /* assign integer to native pointer */ + ToValue->Val->Pointer = (void *)(unsigned long)ExpressionCoerceUnsignedInteger(FromValue); + } + else if (AllowPointerCoercion && FromValue->Typ->Base == TypePointer) + { + /* assign a pointer to a pointer to a different type */ + ToValue->Val->Pointer = FromValue->Val->Pointer; + } + else + AssignFail(Parser, "%t from %t", ToValue->Typ, FromValue->Typ, 0, 0, FuncName, ParamNo); +} + +/* assign any kind of value */ +void ExpressionAssign(struct ParseState *Parser, struct Value *DestValue, struct Value *SourceValue, int Force, const char *FuncName, int ParamNo, int AllowPointerCoercion) +{ + if (!DestValue->IsLValue && !Force) + AssignFail(Parser, "not an lvalue", NULL, NULL, 0, 0, FuncName, ParamNo); + + if (IS_NUMERIC_COERCIBLE(DestValue) && !IS_NUMERIC_COERCIBLE_PLUS_POINTERS(SourceValue, AllowPointerCoercion)) + AssignFail(Parser, "%t from %t", DestValue->Typ, SourceValue->Typ, 0, 0, FuncName, ParamNo); + + switch (DestValue->Typ->Base) + { + case TypeInt: DestValue->Val->Integer = ExpressionCoerceInteger(SourceValue); break; + case TypeShort: DestValue->Val->ShortInteger = (short)ExpressionCoerceInteger(SourceValue); break; + case TypeChar: DestValue->Val->Character = (unsigned char)ExpressionCoerceUnsignedInteger(SourceValue); break; + case TypeLong: DestValue->Val->LongInteger = ExpressionCoerceInteger(SourceValue); break; + case TypeUnsignedInt: DestValue->Val->UnsignedInteger = ExpressionCoerceUnsignedInteger(SourceValue); break; + case TypeUnsignedShort: DestValue->Val->UnsignedShortInteger = (unsigned short)ExpressionCoerceUnsignedInteger(SourceValue); break; + case TypeUnsignedLong: DestValue->Val->UnsignedLongInteger = ExpressionCoerceUnsignedInteger(SourceValue); break; + +#ifndef NO_FP + case TypeFP: + if (!IS_NUMERIC_COERCIBLE_PLUS_POINTERS(SourceValue, AllowPointerCoercion)) + AssignFail(Parser, "%t from %t", DestValue->Typ, SourceValue->Typ, 0, 0, FuncName, ParamNo); + + DestValue->Val->FP = ExpressionCoerceFP(SourceValue); + break; +#endif + case TypePointer: + ExpressionAssignToPointer(Parser, DestValue, SourceValue, FuncName, ParamNo, AllowPointerCoercion); + break; + + case TypeArray: + if (SourceValue->Typ->Base == TypeArray && DestValue->Typ->FromType == DestValue->Typ->FromType && DestValue->Typ->ArraySize == 0) + { + /* destination array is unsized - need to resize the destination array to the same size as the source array */ + DestValue->Typ = SourceValue->Typ; + VariableRealloc(Parser, DestValue, TypeSizeValue(DestValue, FALSE)); + + if (DestValue->LValueFrom != NULL) + { + /* copy the resized value back to the LValue */ + DestValue->LValueFrom->Val = DestValue->Val; + DestValue->LValueFrom->AnyValOnHeap = DestValue->AnyValOnHeap; + } + } + + if (DestValue->Typ != SourceValue->Typ) + AssignFail(Parser, "%t from %t", DestValue->Typ, SourceValue->Typ, 0, 0, FuncName, ParamNo); + + if (DestValue->Typ->ArraySize != SourceValue->Typ->ArraySize) + AssignFail(Parser, "from an array of size %d to one of size %d", NULL, NULL, DestValue->Typ->ArraySize, SourceValue->Typ->ArraySize, FuncName, ParamNo); + + memcpy((void *)DestValue->Val, (void *)SourceValue->Val, TypeSizeValue(DestValue, FALSE)); + break; + + case TypeStruct: + case TypeUnion: + if (DestValue->Typ != SourceValue->Typ) + AssignFail(Parser, "%t from %t", DestValue->Typ, SourceValue->Typ, 0, 0, FuncName, ParamNo); + + memcpy((void *)DestValue->Val, (void *)SourceValue->Val, TypeSizeValue(SourceValue, FALSE)); + break; + + default: + AssignFail(Parser, "%t", DestValue->Typ, NULL, 0, 0, FuncName, ParamNo); + break; + } +} + +/* evaluate the first half of a ternary operator x ? y : z */ +void ExpressionQuestionMarkOperator(struct ParseState *Parser, struct ExpressionStack **StackTop, struct Value *BottomValue, struct Value *TopValue) +{ + if (!IS_NUMERIC_COERCIBLE(TopValue)) + ProgramFail(Parser, "first argument to '?' should be a number"); + + if (ExpressionCoerceInteger(TopValue)) + { + /* the condition's true, return the BottomValue */ + ExpressionStackPushValue(Parser, StackTop, BottomValue); + } + else + { + /* the condition's false, return void */ + ExpressionStackPushValueByType(Parser, StackTop, &VoidType); + } +} + +/* evaluate the second half of a ternary operator x ? y : z */ +void ExpressionColonOperator(struct ParseState *Parser, struct ExpressionStack **StackTop, struct Value *BottomValue, struct Value *TopValue) +{ + if (TopValue->Typ->Base == TypeVoid) + { + /* invoke the "else" part - return the BottomValue */ + ExpressionStackPushValue(Parser, StackTop, BottomValue); + } + else + { + /* it was a "then" - return the TopValue */ + ExpressionStackPushValue(Parser, StackTop, TopValue); + } +} + +/* evaluate a prefix operator */ +void ExpressionPrefixOperator(struct ParseState *Parser, struct ExpressionStack **StackTop, enum LexToken Op, struct Value *TopValue) +{ + struct Value *Result; + union AnyValue *ValPtr; + + debugf("ExpressionPrefixOperator()\n"); + switch (Op) + { + case TokenAmpersand: + if (!TopValue->IsLValue) + ProgramFail(Parser, "can't get the address of this"); + + ValPtr = TopValue->Val; + Result = VariableAllocValueFromType(Parser, TypeGetMatching(Parser, TopValue->Typ, TypePointer, 0, StrEmpty, TRUE), FALSE, NULL, FALSE); + Result->Val->Pointer = (void *)ValPtr; + ExpressionStackPushValueNode(Parser, StackTop, Result); + break; + + case TokenAsterisk: + ExpressionStackPushDereference(Parser, StackTop, TopValue); + break; + + case TokenSizeof: + /* return the size of the argument */ + if (TopValue->Typ == &TypeType) + ExpressionPushInt(Parser, StackTop, TypeSize(TopValue->Val->Typ, TopValue->Val->Typ->ArraySize, TRUE)); + else + ExpressionPushInt(Parser, StackTop, TypeSize(TopValue->Typ, TopValue->Typ->ArraySize, TRUE)); + break; + + default: + /* an arithmetic operator */ +#ifndef NO_FP + if (TopValue->Typ == &FPType) + { + /* floating point prefix arithmetic */ + double ResultFP = 0.0; + + switch (Op) + { + case TokenPlus: ResultFP = TopValue->Val->FP; break; + case TokenMinus: ResultFP = -TopValue->Val->FP; break; + default: ProgramFail(Parser, "invalid operation"); break; + } + + ExpressionPushFP(Parser, StackTop, ResultFP); + } + else +#endif + if (IS_NUMERIC_COERCIBLE(TopValue)) + { + /* integer prefix arithmetic */ + long ResultInt = 0; + long TopInt = ExpressionCoerceInteger(TopValue); + switch (Op) + { + case TokenPlus: ResultInt = TopInt; break; + case TokenMinus: ResultInt = -TopInt; break; + case TokenIncrement: ResultInt = ExpressionAssignInt(Parser, TopValue, TopInt+1, FALSE); break; + case TokenDecrement: ResultInt = ExpressionAssignInt(Parser, TopValue, TopInt-1, FALSE); break; + case TokenUnaryNot: ResultInt = !TopInt; break; + case TokenUnaryExor: ResultInt = ~TopInt; break; + default: ProgramFail(Parser, "invalid operation"); break; + } + + ExpressionPushInt(Parser, StackTop, ResultInt); + } + else if (TopValue->Typ->Base == TypePointer) + { + /* pointer prefix arithmetic */ + int Size = TypeSize(TopValue->Typ->FromType, 0, TRUE); + struct Value *StackValue; + void *ResultPtr; + + if (TopValue->Val->Pointer == NULL) + ProgramFail(Parser, "invalid use of a NULL pointer"); + + if (!TopValue->IsLValue) + ProgramFail(Parser, "can't assign to this"); + + switch (Op) + { + case TokenIncrement: TopValue->Val->Pointer = (void *)((char *)TopValue->Val->Pointer + Size); break; + case TokenDecrement: TopValue->Val->Pointer = (void *)((char *)TopValue->Val->Pointer - Size); break; + default: ProgramFail(Parser, "invalid operation"); break; + } + + ResultPtr = TopValue->Val->Pointer; + StackValue = ExpressionStackPushValueByType(Parser, StackTop, TopValue->Typ); + StackValue->Val->Pointer = ResultPtr; + } + else + ProgramFail(Parser, "invalid operation"); + break; + } +} + +/* evaluate a postfix operator */ +void ExpressionPostfixOperator(struct ParseState *Parser, struct ExpressionStack **StackTop, enum LexToken Op, struct Value *TopValue) +{ + debugf("ExpressionPostfixOperator()\n"); + if (IS_NUMERIC_COERCIBLE(TopValue)) + { + long ResultInt = 0; + long TopInt = ExpressionCoerceInteger(TopValue); + switch (Op) + { + case TokenIncrement: ResultInt = ExpressionAssignInt(Parser, TopValue, TopInt+1, TRUE); break; + case TokenDecrement: ResultInt = ExpressionAssignInt(Parser, TopValue, TopInt-1, TRUE); break; + case TokenRightSquareBracket: ProgramFail(Parser, "not supported"); break; /* XXX */ + case TokenCloseBracket: ProgramFail(Parser, "not supported"); break; /* XXX */ + default: ProgramFail(Parser, "invalid operation"); break; + } + + ExpressionPushInt(Parser, StackTop, ResultInt); + } + else if (TopValue->Typ->Base == TypePointer) + { + /* pointer postfix arithmetic */ + int Size = TypeSize(TopValue->Typ->FromType, 0, TRUE); + struct Value *StackValue; + void *OrigPointer = TopValue->Val->Pointer; + + if (TopValue->Val->Pointer == NULL) + ProgramFail(Parser, "invalid use of a NULL pointer"); + + if (!TopValue->IsLValue) + ProgramFail(Parser, "can't assign to this"); + + switch (Op) + { + case TokenIncrement: TopValue->Val->Pointer = (void *)((char *)TopValue->Val->Pointer + Size); break; + case TokenDecrement: TopValue->Val->Pointer = (void *)((char *)TopValue->Val->Pointer - Size); break; + default: ProgramFail(Parser, "invalid operation"); break; + } + + StackValue = ExpressionStackPushValueByType(Parser, StackTop, TopValue->Typ); + StackValue->Val->Pointer = OrigPointer; + } + else + ProgramFail(Parser, "invalid operation"); +} + +/* evaluate an infix operator */ +void ExpressionInfixOperator(struct ParseState *Parser, struct ExpressionStack **StackTop, enum LexToken Op, struct Value *BottomValue, struct Value *TopValue) +{ + long ResultInt = 0; + struct Value *StackValue; + void *Pointer; + + debugf("ExpressionInfixOperator()\n"); + if (BottomValue == NULL || TopValue == NULL) + ProgramFail(Parser, "invalid expression"); + + if (Op == TokenLeftSquareBracket) + { + /* array index */ + int ArrayIndex; + struct Value *Result = NULL; + + if (!IS_NUMERIC_COERCIBLE(TopValue)) + ProgramFail(Parser, "array index must be an integer"); + + ArrayIndex = ExpressionCoerceInteger(TopValue); + + /* make the array element result */ + switch (BottomValue->Typ->Base) + { + case TypeArray: Result = VariableAllocValueFromExistingData(Parser, BottomValue->Typ->FromType, (union AnyValue *)(&BottomValue->Val->ArrayMem[0] + TypeSize(BottomValue->Typ, ArrayIndex, TRUE)), BottomValue->IsLValue, BottomValue->LValueFrom); break; + case TypePointer: Result = VariableAllocValueFromExistingData(Parser, BottomValue->Typ->FromType, (union AnyValue *)((char *)BottomValue->Val->Pointer + TypeSize(BottomValue->Typ->FromType, 0, TRUE) * ArrayIndex), BottomValue->IsLValue, BottomValue->LValueFrom); break; + default: ProgramFail(Parser, "this %t is not an array", BottomValue->Typ); + } + + ExpressionStackPushValueNode(Parser, StackTop, Result); + } + else if (Op == TokenQuestionMark) + ExpressionQuestionMarkOperator(Parser, StackTop, TopValue, BottomValue); + + else if (Op == TokenColon) + ExpressionColonOperator(Parser, StackTop, TopValue, BottomValue); + +#ifndef NO_FP + else if ( (TopValue->Typ == &FPType && BottomValue->Typ == &FPType) || + (TopValue->Typ == &FPType && IS_NUMERIC_COERCIBLE(BottomValue)) || + (IS_NUMERIC_COERCIBLE(TopValue) && BottomValue->Typ == &FPType) ) + { + /* floating point infix arithmetic */ + int ResultIsInt = FALSE; + double ResultFP = 0.0; + double TopFP = (TopValue->Typ == &FPType) ? TopValue->Val->FP : (double)ExpressionCoerceInteger(TopValue); + double BottomFP = (BottomValue->Typ == &FPType) ? BottomValue->Val->FP : (double)ExpressionCoerceInteger(BottomValue); + + switch (Op) + { + case TokenAssign: ResultFP = ExpressionAssignFP(Parser, BottomValue, TopFP); break; + case TokenAddAssign: ResultFP = ExpressionAssignFP(Parser, BottomValue, BottomFP + TopFP); break; + case TokenSubtractAssign: ResultFP = ExpressionAssignFP(Parser, BottomValue, BottomFP - TopFP); break; + case TokenMultiplyAssign: ResultFP = ExpressionAssignFP(Parser, BottomValue, BottomFP * TopFP); break; + case TokenDivideAssign: ResultFP = ExpressionAssignFP(Parser, BottomValue, BottomFP / TopFP); break; + case TokenEqual: ResultInt = BottomFP == TopFP; ResultIsInt = TRUE; break; + case TokenNotEqual: ResultInt = BottomFP != TopFP; ResultIsInt = TRUE; break; + case TokenLessThan: ResultInt = BottomFP < TopFP; ResultIsInt = TRUE; break; + case TokenGreaterThan: ResultInt = BottomFP > TopFP; ResultIsInt = TRUE; break; + case TokenLessEqual: ResultInt = BottomFP <= TopFP; ResultIsInt = TRUE; break; + case TokenGreaterEqual: ResultInt = BottomFP >= TopFP; ResultIsInt = TRUE; break; + case TokenPlus: ResultFP = BottomFP + TopFP; break; + case TokenMinus: ResultFP = BottomFP - TopFP; break; + case TokenAsterisk: ResultFP = BottomFP * TopFP; break; + case TokenSlash: ResultFP = BottomFP / TopFP; break; + default: ProgramFail(Parser, "invalid operation"); break; + } + + if (ResultIsInt) + ExpressionPushInt(Parser, StackTop, ResultInt); + else + ExpressionPushFP(Parser, StackTop, ResultFP); + } +#endif + else if (IS_NUMERIC_COERCIBLE(TopValue) && IS_NUMERIC_COERCIBLE(BottomValue)) + { + /* integer operation */ + long TopInt = ExpressionCoerceInteger(TopValue); + long BottomInt = ExpressionCoerceInteger(BottomValue); + switch (Op) + { + case TokenAssign: ResultInt = ExpressionAssignInt(Parser, BottomValue, TopInt, FALSE); break; + case TokenAddAssign: ResultInt = ExpressionAssignInt(Parser, BottomValue, BottomInt + TopInt, FALSE); break; + case TokenSubtractAssign: ResultInt = ExpressionAssignInt(Parser, BottomValue, BottomInt - TopInt, FALSE); break; + case TokenMultiplyAssign: ResultInt = ExpressionAssignInt(Parser, BottomValue, BottomInt * TopInt, FALSE); break; + case TokenDivideAssign: ResultInt = ExpressionAssignInt(Parser, BottomValue, BottomInt / TopInt, FALSE); break; +#ifndef NO_MODULUS + case TokenModulusAssign: ResultInt = ExpressionAssignInt(Parser, BottomValue, BottomInt % TopInt, FALSE); break; +#endif + case TokenShiftLeftAssign: ResultInt = ExpressionAssignInt(Parser, BottomValue, BottomInt << TopInt, FALSE); break; + case TokenShiftRightAssign: ResultInt = ExpressionAssignInt(Parser, BottomValue, BottomInt >> TopInt, FALSE); break; + case TokenArithmeticAndAssign: ResultInt = ExpressionAssignInt(Parser, BottomValue, BottomInt & TopInt, FALSE); break; + case TokenArithmeticOrAssign: ResultInt = ExpressionAssignInt(Parser, BottomValue, BottomInt | TopInt, FALSE); break; + case TokenArithmeticExorAssign: ResultInt = ExpressionAssignInt(Parser, BottomValue, BottomInt ^ TopInt, FALSE); break; + case TokenLogicalOr: ResultInt = BottomInt || TopInt; break; + case TokenLogicalAnd: ResultInt = BottomInt && TopInt; break; + case TokenArithmeticOr: ResultInt = BottomInt | TopInt; break; + case TokenArithmeticExor: ResultInt = BottomInt ^ TopInt; break; + case TokenAmpersand: ResultInt = BottomInt & TopInt; break; + case TokenEqual: ResultInt = BottomInt == TopInt; break; + case TokenNotEqual: ResultInt = BottomInt != TopInt; break; + case TokenLessThan: ResultInt = BottomInt < TopInt; break; + case TokenGreaterThan: ResultInt = BottomInt > TopInt; break; + case TokenLessEqual: ResultInt = BottomInt <= TopInt; break; + case TokenGreaterEqual: ResultInt = BottomInt >= TopInt; break; + case TokenShiftLeft: ResultInt = BottomInt << TopInt; break; + case TokenShiftRight: ResultInt = BottomInt >> TopInt; break; + case TokenPlus: ResultInt = BottomInt + TopInt; break; + case TokenMinus: ResultInt = BottomInt - TopInt; break; + case TokenAsterisk: ResultInt = BottomInt * TopInt; break; + case TokenSlash: ResultInt = BottomInt / TopInt; break; +#ifndef NO_MODULUS + case TokenModulus: ResultInt = BottomInt % TopInt; break; +#endif + default: ProgramFail(Parser, "invalid operation"); break; + } + + ExpressionPushInt(Parser, StackTop, ResultInt); + } + else if (BottomValue->Typ->Base == TypePointer && IS_NUMERIC_COERCIBLE(TopValue)) + { + /* pointer/integer infix arithmetic */ + long TopInt = ExpressionCoerceInteger(TopValue); + + if (Op == TokenEqual || Op == TokenNotEqual) + { + /* comparison to a NULL pointer */ + if (TopInt != 0) + ProgramFail(Parser, "invalid operation"); + + if (Op == TokenEqual) + ExpressionPushInt(Parser, StackTop, BottomValue->Val->Pointer == NULL); + else + ExpressionPushInt(Parser, StackTop, BottomValue->Val->Pointer != NULL); + } + else if (Op == TokenPlus || Op == TokenMinus) + { + /* pointer arithmetic */ + int Size = TypeSize(BottomValue->Typ->FromType, 0, TRUE); + + Pointer = BottomValue->Val->Pointer; + if (Pointer == NULL) + ProgramFail(Parser, "invalid use of a NULL pointer"); + + if (Op == TokenPlus) + Pointer = (void *)((char *)Pointer + TopInt * Size); + else + Pointer = (void *)((char *)Pointer - TopInt * Size); + + StackValue = ExpressionStackPushValueByType(Parser, StackTop, BottomValue->Typ); + StackValue->Val->Pointer = Pointer; + } + else if (Op == TokenAssign && TopInt == 0) + { + /* assign a NULL pointer */ + HeapUnpopStack(sizeof(struct Value)); + ExpressionAssign(Parser, BottomValue, TopValue, FALSE, NULL, 0, FALSE); + ExpressionStackPushValueNode(Parser, StackTop, BottomValue); + } + else if (Op == TokenAddAssign || Op == TokenSubtractAssign) + { + /* pointer arithmetic */ + int Size = TypeSize(BottomValue->Typ->FromType, 0, TRUE); + + Pointer = BottomValue->Val->Pointer; + if (Pointer == NULL) + ProgramFail(Parser, "invalid use of a NULL pointer"); + + if (Op == TokenAddAssign) + Pointer = (void *)((char *)Pointer + TopInt * Size); + else + Pointer = (void *)((char *)Pointer - TopInt * Size); + + HeapUnpopStack(sizeof(struct Value)); + BottomValue->Val->Pointer = Pointer; + ExpressionStackPushValueNode(Parser, StackTop, BottomValue); + } + else + ProgramFail(Parser, "invalid operation"); + } + else if (BottomValue->Typ->Base == TypePointer && TopValue->Typ->Base == TypePointer && Op != TokenAssign) + { + /* pointer/pointer operations */ + char *TopLoc = (char *)TopValue->Val->Pointer; + char *BottomLoc = (char *)BottomValue->Val->Pointer; + + switch (Op) + { + case TokenEqual: ExpressionPushInt(Parser, StackTop, BottomLoc == TopLoc); break; + case TokenNotEqual: ExpressionPushInt(Parser, StackTop, BottomLoc != TopLoc); break; + case TokenMinus: ExpressionPushInt(Parser, StackTop, BottomLoc - TopLoc); break; + default: ProgramFail(Parser, "invalid operation"); break; + } + } + else if (Op == TokenAssign) + { + /* assign a non-numeric type */ + HeapUnpopStack(sizeof(struct Value)); /* XXX - possible bug if lvalue is a temp value and takes more than sizeof(struct Value) */ + ExpressionAssign(Parser, BottomValue, TopValue, FALSE, NULL, 0, FALSE); + ExpressionStackPushValueNode(Parser, StackTop, BottomValue); + } + else if (Op == TokenCast) + { + /* cast a value to a different type */ /* XXX - possible bug if the destination type takes more than sizeof(struct Value) + sizeof(struct ValueType *) */ + struct Value *ValueLoc = ExpressionStackPushValueByType(Parser, StackTop, BottomValue->Val->Typ); + ExpressionAssign(Parser, ValueLoc, TopValue, TRUE, NULL, 0, TRUE); + } + else + ProgramFail(Parser, "invalid operation"); +} + +/* take the contents of the expression stack and compute the top until there's nothing greater than the given precedence */ +void ExpressionStackCollapse(struct ParseState *Parser, struct ExpressionStack **StackTop, int Precedence, int *IgnorePrecedence) +{ + int FoundPrecedence = Precedence; + struct Value *TopValue; + struct Value *BottomValue; + struct ExpressionStack *TopStackNode = *StackTop; + struct ExpressionStack *TopOperatorNode; + + debugf("ExpressionStackCollapse(%d):\n", Precedence); +#ifdef DEBUG_EXPRESSIONS + ExpressionStackShow(*StackTop); +#endif + while (TopStackNode != NULL && TopStackNode->Next != NULL && FoundPrecedence >= Precedence) + { + /* find the top operator on the stack */ + if (TopStackNode->Order == OrderNone) + TopOperatorNode = TopStackNode->Next; + else + TopOperatorNode = TopStackNode; + + FoundPrecedence = TopOperatorNode->Precedence; + + /* does it have a high enough precedence? */ + if (FoundPrecedence >= Precedence && TopOperatorNode != NULL) + { + /* execute this operator */ + switch (TopOperatorNode->Order) + { + case OrderPrefix: + /* prefix evaluation */ + debugf("prefix evaluation\n"); + TopValue = TopStackNode->Val; + + /* pop the value and then the prefix operator - assume they'll still be there until we're done */ + HeapPopStack(NULL, sizeof(struct ExpressionStack) + sizeof(struct Value) + TypeStackSizeValue(TopValue)); + HeapPopStack(TopOperatorNode, sizeof(struct ExpressionStack)); + *StackTop = TopOperatorNode->Next; + + /* do the prefix operation */ + if (Parser->Mode == RunModeRun && FoundPrecedence < *IgnorePrecedence) + { + /* run the operator */ + ExpressionPrefixOperator(Parser, StackTop, TopOperatorNode->Op, TopValue); + } + else + { + /* we're not running it so just return 0 */ + ExpressionPushInt(Parser, StackTop, 0); + } + break; + + case OrderPostfix: + /* postfix evaluation */ + debugf("postfix evaluation\n"); + TopValue = TopStackNode->Next->Val; + + /* pop the postfix operator and then the value - assume they'll still be there until we're done */ + HeapPopStack(NULL, sizeof(struct ExpressionStack)); + HeapPopStack(TopValue, sizeof(struct ExpressionStack) + sizeof(struct Value) + TypeStackSizeValue(TopValue)); + *StackTop = TopStackNode->Next->Next; + + /* do the postfix operation */ + if (Parser->Mode == RunModeRun && FoundPrecedence < *IgnorePrecedence) + { + /* run the operator */ + ExpressionPostfixOperator(Parser, StackTop, TopOperatorNode->Op, TopValue); + } + else + { + /* we're not running it so just return 0 */ + ExpressionPushInt(Parser, StackTop, 0); + } + break; + + case OrderInfix: + /* infix evaluation */ + debugf("infix evaluation\n"); + TopValue = TopStackNode->Val; + if (TopValue != NULL) + { + BottomValue = TopOperatorNode->Next->Val; + + /* pop a value, the operator and another value - assume they'll still be there until we're done */ + HeapPopStack(NULL, sizeof(struct ExpressionStack) + sizeof(struct Value) + TypeStackSizeValue(TopValue)); + HeapPopStack(NULL, sizeof(struct ExpressionStack)); + HeapPopStack(BottomValue, sizeof(struct ExpressionStack) + sizeof(struct Value) + TypeStackSizeValue(BottomValue)); + *StackTop = TopOperatorNode->Next->Next; + + /* do the infix operation */ + if (Parser->Mode == RunModeRun && FoundPrecedence <= *IgnorePrecedence) + { + /* run the operator */ + ExpressionInfixOperator(Parser, StackTop, TopOperatorNode->Op, BottomValue, TopValue); + } + else + { + /* we're not running it so just return 0 */ + ExpressionPushInt(Parser, StackTop, 0); + } + } + else + FoundPrecedence = -1; + break; + + case OrderNone: + /* this should never happen */ + assert(TopOperatorNode->Order != OrderNone); + break; + } + + /* if we've returned above the ignored precedence level turn ignoring off */ + if (FoundPrecedence <= *IgnorePrecedence) + *IgnorePrecedence = DEEP_PRECEDENCE; + } +#ifdef DEBUG_EXPRESSIONS + ExpressionStackShow(*StackTop); +#endif + TopStackNode = *StackTop; + } + debugf("ExpressionStackCollapse() finished\n"); +#ifdef DEBUG_EXPRESSIONS + ExpressionStackShow(*StackTop); +#endif +} + +/* push an operator on to the expression stack */ +void ExpressionStackPushOperator(struct ParseState *Parser, struct ExpressionStack **StackTop, enum OperatorOrder Order, enum LexToken Token, int Precedence) +{ + struct ExpressionStack *StackNode = VariableAlloc(Parser, sizeof(struct ExpressionStack), FALSE); + StackNode->Next = *StackTop; + StackNode->Order = Order; + StackNode->Op = Token; + StackNode->Precedence = Precedence; + *StackTop = StackNode; + debugf("ExpressionStackPushOperator()\n"); +#ifdef FANCY_ERROR_MESSAGES + StackNode->Line = Parser->Line; + StackNode->CharacterPos = Parser->CharacterPos; +#endif +#ifdef DEBUG_EXPRESSIONS + ExpressionStackShow(*StackTop); +#endif +} + +/* do the '.' and '->' operators */ +void ExpressionGetStructElement(struct ParseState *Parser, struct ExpressionStack **StackTop, enum LexToken Token) +{ + struct Value *Ident; + + /* get the identifier following the '.' or '->' */ + if (LexGetToken(Parser, &Ident, TRUE) != TokenIdentifier) + ProgramFail(Parser, "need an structure or union member after '%s'", (Token == TokenDot) ? "." : "->"); + + if (Parser->Mode == RunModeRun) + { + /* look up the struct element */ + struct Value *ParamVal = (*StackTop)->Val; + struct Value *StructVal = ParamVal; + struct ValueType *StructType = ParamVal->Typ; + char *DerefDataLoc = (char *)ParamVal->Val; + struct Value *MemberValue; + struct Value *Result; + + /* if we're doing '->' dereference the struct pointer first */ + if (Token == TokenArrow) + DerefDataLoc = VariableDereferencePointer(Parser, ParamVal, &StructVal, NULL, &StructType, NULL); + + if (StructType->Base != TypeStruct && StructType->Base != TypeUnion) + ProgramFail(Parser, "can't use '%s' on something that's not a struct or union %s : it's a %t", (Token == TokenDot) ? "." : "->", (Token == TokenArrow) ? "pointer" : "", ParamVal->Typ); + + if (!TableGet(StructType->Members, Ident->Val->Identifier, &MemberValue, NULL, NULL, NULL)) + ProgramFail(Parser, "doesn't have a member called '%s'", Ident->Val->Identifier); + + /* pop the value - assume it'll still be there until we're done */ + HeapPopStack(ParamVal, sizeof(struct ExpressionStack) + sizeof(struct Value) + TypeStackSizeValue(StructVal)); + *StackTop = (*StackTop)->Next; + + /* make the result value for this member only */ + Result = VariableAllocValueFromExistingData(Parser, MemberValue->Typ, (void *)(DerefDataLoc + MemberValue->Val->Integer), TRUE, (StructVal != NULL) ? StructVal->LValueFrom : NULL); + ExpressionStackPushValueNode(Parser, StackTop, Result); + } +} + +/* parse an expression with operator precedence */ +int ExpressionParse(struct ParseState *Parser, struct Value **Result) +{ + struct Value *LexValue; + int PrefixState = TRUE; + int Done = FALSE; + int BracketPrecedence = 0; + int LocalPrecedence; + int Precedence = 0; + int IgnorePrecedence = DEEP_PRECEDENCE; + struct ExpressionStack *StackTop = NULL; + int TernaryDepth = 0; + + debugf("ExpressionParse():\n"); + do + { + struct ParseState PreState; + enum LexToken Token; + + ParserCopy(&PreState, Parser); + Token = LexGetToken(Parser, &LexValue, TRUE); + if ( ( ( (int)Token > TokenComma && (int)Token <= (int)TokenOpenBracket) || + (Token == TokenCloseBracket && BracketPrecedence != 0)) && + (Token != TokenColon || TernaryDepth > 0) ) + { + /* it's an operator with precedence */ + if (PrefixState) + { + /* expect a prefix operator */ + if (OperatorPrecedence[(int)Token].PrefixPrecedence == 0) + ProgramFail(Parser, "operator not expected here"); + + LocalPrecedence = OperatorPrecedence[(int)Token].PrefixPrecedence; + Precedence = BracketPrecedence + LocalPrecedence; + + if (Token == TokenOpenBracket) + { + /* it's either a new bracket level or a cast */ + enum LexToken BracketToken = LexGetToken(Parser, &LexValue, FALSE); + if (IS_TYPE_TOKEN(BracketToken) && (StackTop == NULL || StackTop->Op != TokenSizeof) ) + { + /* it's a cast - get the new type */ + struct ValueType *CastType; + char *CastIdentifier; + struct Value *CastTypeValue; + + TypeParse(Parser, &CastType, &CastIdentifier, NULL); + if (LexGetToken(Parser, &LexValue, TRUE) != TokenCloseBracket) + ProgramFail(Parser, "brackets not closed"); + + /* scan and collapse the stack to the precedence of this infix cast operator, then push */ + Precedence = BracketPrecedence + OperatorPrecedence[(int)TokenCast].PrefixPrecedence; + + ExpressionStackCollapse(Parser, &StackTop, Precedence+1, &IgnorePrecedence); + CastTypeValue = VariableAllocValueFromType(Parser, &TypeType, FALSE, NULL, FALSE); + CastTypeValue->Val->Typ = CastType; + ExpressionStackPushValueNode(Parser, &StackTop, CastTypeValue); + ExpressionStackPushOperator(Parser, &StackTop, OrderInfix, TokenCast, Precedence); + } + else + { + /* boost the bracket operator precedence */ + BracketPrecedence += BRACKET_PRECEDENCE; + } + } + else + { + /* scan and collapse the stack to the precedence of this operator, then push */ + ExpressionStackCollapse(Parser, &StackTop, Precedence, &IgnorePrecedence); + ExpressionStackPushOperator(Parser, &StackTop, OrderPrefix, Token, Precedence); + } + } + else + { + /* expect an infix or postfix operator */ + if (OperatorPrecedence[(int)Token].PostfixPrecedence != 0) + { + switch (Token) + { + case TokenCloseBracket: + case TokenRightSquareBracket: + if (BracketPrecedence == 0) + { + /* assume this bracket is after the end of the expression */ + ParserCopy(Parser, &PreState); + Done = TRUE; + } + else + { + /* collapse to the bracket precedence */ + ExpressionStackCollapse(Parser, &StackTop, BracketPrecedence, &IgnorePrecedence); + BracketPrecedence -= BRACKET_PRECEDENCE; + } + break; + + default: + /* scan and collapse the stack to the precedence of this operator, then push */ + Precedence = BracketPrecedence + OperatorPrecedence[(int)Token].PostfixPrecedence; + ExpressionStackCollapse(Parser, &StackTop, Precedence, &IgnorePrecedence); + ExpressionStackPushOperator(Parser, &StackTop, OrderPostfix, Token, Precedence); + break; + } + } + else if (OperatorPrecedence[(int)Token].InfixPrecedence != 0) + { + /* scan and collapse the stack, then push */ + Precedence = BracketPrecedence + OperatorPrecedence[(int)Token].InfixPrecedence; + + /* for right to left order, only go down to the next higher precedence so we evaluate it in reverse order */ + /* for left to right order, collapse down to this precedence so we evaluate it in forward order */ + if (IS_LEFT_TO_RIGHT(OperatorPrecedence[(int)Token].InfixPrecedence)) + ExpressionStackCollapse(Parser, &StackTop, Precedence, &IgnorePrecedence); + else + ExpressionStackCollapse(Parser, &StackTop, Precedence+1, &IgnorePrecedence); + + if (Token == TokenDot || Token == TokenArrow) + { + ExpressionGetStructElement(Parser, &StackTop, Token); /* this operator is followed by a struct element so handle it as a special case */ + } + else + { + /* if it's a && or || operator we may not need to evaluate the right hand side of the expression */ + if ( (Token == TokenLogicalOr || Token == TokenLogicalAnd) && IS_NUMERIC_COERCIBLE(StackTop->Val)) + { + long LHSInt = ExpressionCoerceInteger(StackTop->Val); + if ( ( (Token == TokenLogicalOr && LHSInt) || (Token == TokenLogicalAnd && !LHSInt) ) && + (IgnorePrecedence > Precedence) ) + IgnorePrecedence = Precedence; + } + + /* push the operator on the stack */ + ExpressionStackPushOperator(Parser, &StackTop, OrderInfix, Token, Precedence); + PrefixState = TRUE; + + switch (Token) + { + case TokenQuestionMark: TernaryDepth++; break; + case TokenColon: TernaryDepth--; break; + default: break; + } + } + + /* treat an open square bracket as an infix array index operator followed by an open bracket */ + if (Token == TokenLeftSquareBracket) + { + /* boost the bracket operator precedence, then push */ + BracketPrecedence += BRACKET_PRECEDENCE; + } + } + else + ProgramFail(Parser, "operator not expected here"); + } + } + else if (Token == TokenIdentifier) + { + /* it's a variable, function or a macro */ + if (!PrefixState) + ProgramFail(Parser, "identifier not expected here"); + + if (LexGetToken(Parser, NULL, FALSE) == TokenOpenBracket) + { + ExpressionParseFunctionCall(Parser, &StackTop, LexValue->Val->Identifier, Parser->Mode == RunModeRun && Precedence < IgnorePrecedence); + } + else + { + if (Parser->Mode == RunModeRun && Precedence < IgnorePrecedence) + { + struct Value *VariableValue = NULL; + + VariableGet(Parser, LexValue->Val->Identifier, &VariableValue); + if (VariableValue->Typ->Base == TypeMacro) + { + /* evaluate a macro as a kind of simple subroutine */ + struct ParseState MacroParser; + struct Value *MacroResult; + + ParserCopy(&MacroParser, &VariableValue->Val->MacroDef.Body); + if (VariableValue->Val->MacroDef.NumParams != 0) + ProgramFail(&MacroParser, "macro arguments missing"); + + if (!ExpressionParse(&MacroParser, &MacroResult) || LexGetToken(&MacroParser, NULL, FALSE) != TokenEndOfFunction) + ProgramFail(&MacroParser, "expression expected"); + + ExpressionStackPushValueNode(Parser, &StackTop, MacroResult); + } + else if (VariableValue->Typ == &VoidType) + ProgramFail(Parser, "a void value isn't much use here"); + else + ExpressionStackPushLValue(Parser, &StackTop, VariableValue, 0); /* it's a value variable */ + } + else /* push a dummy value */ + ExpressionPushInt(Parser, &StackTop, 0); + + } + + /* if we've successfully ignored the RHS turn ignoring off */ + if (Precedence <= IgnorePrecedence) + IgnorePrecedence = DEEP_PRECEDENCE; + + PrefixState = FALSE; + } + else if ((int)Token > TokenCloseBracket && (int)Token <= TokenCharacterConstant) + { + /* it's a value of some sort, push it */ + if (!PrefixState) + ProgramFail(Parser, "value not expected here"); + + PrefixState = FALSE; + ExpressionStackPushValue(Parser, &StackTop, LexValue); + } + else if (IS_TYPE_TOKEN(Token)) + { + /* it's a type. push it on the stack like a value. this is used in sizeof() */ + struct ValueType *Typ; + char *Identifier; + struct Value *TypeValue; + + if (!PrefixState) + ProgramFail(Parser, "type not expected here"); + + PrefixState = FALSE; + ParserCopy(Parser, &PreState); + TypeParse(Parser, &Typ, &Identifier, NULL); + TypeValue = VariableAllocValueFromType(Parser, &TypeType, FALSE, NULL, FALSE); + TypeValue->Val->Typ = Typ; + ExpressionStackPushValueNode(Parser, &StackTop, TypeValue); + } + else + { + /* it isn't a token from an expression */ + ParserCopy(Parser, &PreState); + Done = TRUE; + } + + } while (!Done); + + /* check that brackets have been closed */ + if (BracketPrecedence > 0) + ProgramFail(Parser, "brackets not closed"); + + /* scan and collapse the stack to precedence 0 */ + ExpressionStackCollapse(Parser, &StackTop, 0, &IgnorePrecedence); + + /* fix up the stack and return the result if we're in run mode */ + if (StackTop != NULL) + { + /* all that should be left is a single value on the stack */ + if (Parser->Mode == RunModeRun) + { + if (StackTop->Order != OrderNone || StackTop->Next != NULL) + ProgramFail(Parser, "invalid expression"); + + *Result = StackTop->Val; + HeapPopStack(StackTop, sizeof(struct ExpressionStack)); + } + else + HeapPopStack(StackTop->Val, sizeof(struct ExpressionStack) + sizeof(struct Value) + TypeStackSizeValue(StackTop->Val)); + } + + debugf("ExpressionParse() done\n\n"); +#ifdef DEBUG_EXPRESSIONS + ExpressionStackShow(StackTop); +#endif + return StackTop != NULL; +} + + +/* do a parameterised macro call */ +void ExpressionParseMacroCall(struct ParseState *Parser, struct ExpressionStack **StackTop, const char *MacroName, struct MacroDef *MDef) +{ + struct Value *ReturnValue = NULL; + struct Value *Param; + struct Value **ParamArray = NULL; + int ArgCount; + enum LexToken Token; + + if (Parser->Mode == RunModeRun) + { + /* create a stack frame for this macro */ +#ifndef NO_FP + ExpressionStackPushValueByType(Parser, StackTop, &FPType); /* largest return type there is */ +#else + ExpressionStackPushValueByType(Parser, StackTop, &IntType); /* largest return type there is */ +#endif + ReturnValue = (*StackTop)->Val; + HeapPushStackFrame(); + ParamArray = HeapAllocStack(sizeof(struct Value *) * MDef->NumParams); + if (ParamArray == NULL) + ProgramFail(Parser, "out of memory"); + } + else + ExpressionPushInt(Parser, StackTop, 0); + + /* parse arguments */ + ArgCount = 0; + do { + if (ExpressionParse(Parser, &Param)) + { + if (Parser->Mode == RunModeRun) + { + if (ArgCount < MDef->NumParams) + ParamArray[ArgCount] = Param; + else + ProgramFail(Parser, "too many arguments to %s()", MacroName); + } + + ArgCount++; + Token = LexGetToken(Parser, NULL, TRUE); + if (Token != TokenComma && Token != TokenCloseBracket) + ProgramFail(Parser, "comma expected"); + } + else + { + /* end of argument list? */ + Token = LexGetToken(Parser, NULL, TRUE); + if (!TokenCloseBracket) + ProgramFail(Parser, "bad argument"); + } + + } while (Token != TokenCloseBracket); + + if (Parser->Mode == RunModeRun) + { + /* evaluate the macro */ + struct ParseState MacroParser; + int Count; + struct Value *EvalValue; + + if (ArgCount < MDef->NumParams) + ProgramFail(Parser, "not enough arguments to '%s'", MacroName); + + if (MDef->Body.Pos == NULL) + ProgramFail(Parser, "'%s' is undefined", MacroName); + + ParserCopy(&MacroParser, &MDef->Body); + VariableStackFrameAdd(Parser, MacroName, 0); + TopStackFrame->NumParams = ArgCount; + TopStackFrame->ReturnValue = ReturnValue; + for (Count = 0; Count < MDef->NumParams; Count++) + VariableDefine(Parser, MDef->ParamName[Count], ParamArray[Count], NULL, TRUE); + + ExpressionParse(&MacroParser, &EvalValue); + ExpressionAssign(Parser, ReturnValue, EvalValue, TRUE, MacroName, 0, FALSE); + VariableStackFramePop(Parser); + HeapPopStackFrame(); + } +} + +/* do a function call */ +void ExpressionParseFunctionCall(struct ParseState *Parser, struct ExpressionStack **StackTop, const char *FuncName, int RunIt) +{ + struct Value *ReturnValue = NULL; + struct Value *FuncValue; + struct Value *Param; + struct Value **ParamArray = NULL; + int ArgCount; + enum LexToken Token = LexGetToken(Parser, NULL, TRUE); /* open bracket */ + enum RunMode OldMode = Parser->Mode; + + if (RunIt) + { + /* get the function definition */ + VariableGet(Parser, FuncName, &FuncValue); + + if (FuncValue->Typ->Base == TypeMacro) + { + /* this is actually a macro, not a function */ + ExpressionParseMacroCall(Parser, StackTop, FuncName, &FuncValue->Val->MacroDef); + return; + } + + if (FuncValue->Typ->Base != TypeFunction) + ProgramFail(Parser, "%t is not a function - can't call", FuncValue->Typ); + + ExpressionStackPushValueByType(Parser, StackTop, FuncValue->Val->FuncDef.ReturnType); + ReturnValue = (*StackTop)->Val; + HeapPushStackFrame(); + ParamArray = HeapAllocStack(sizeof(struct Value *) * FuncValue->Val->FuncDef.NumParams); + if (ParamArray == NULL) + ProgramFail(Parser, "out of memory"); + } + else + { + ExpressionPushInt(Parser, StackTop, 0); + Parser->Mode = RunModeSkip; + } + + /* parse arguments */ + ArgCount = 0; + do { + if (RunIt && ArgCount < FuncValue->Val->FuncDef.NumParams) + ParamArray[ArgCount] = VariableAllocValueFromType(Parser, FuncValue->Val->FuncDef.ParamType[ArgCount], FALSE, NULL, FALSE); + + if (ExpressionParse(Parser, &Param)) + { + if (RunIt) + { + if (ArgCount < FuncValue->Val->FuncDef.NumParams) + { + ExpressionAssign(Parser, ParamArray[ArgCount], Param, TRUE, FuncName, ArgCount+1, FALSE); + VariableStackPop(Parser, Param); + } + else + { + if (!FuncValue->Val->FuncDef.VarArgs) + ProgramFail(Parser, "too many arguments to %s()", FuncName); + } + } + + ArgCount++; + Token = LexGetToken(Parser, NULL, TRUE); + if (Token != TokenComma && Token != TokenCloseBracket) + ProgramFail(Parser, "comma expected"); + } + else + { + /* end of argument list? */ + Token = LexGetToken(Parser, NULL, TRUE); + if (!TokenCloseBracket) + ProgramFail(Parser, "bad argument"); + } + + } while (Token != TokenCloseBracket); + + if (RunIt) + { + /* run the function */ + if (ArgCount < FuncValue->Val->FuncDef.NumParams) + ProgramFail(Parser, "not enough arguments to '%s'", FuncName); + + if (FuncValue->Val->FuncDef.Intrinsic == NULL) + { + /* run a user-defined function */ + struct ParseState FuncParser; + int Count; + + if (FuncValue->Val->FuncDef.Body.Pos == NULL) + ProgramFail(Parser, "'%s' is undefined", FuncName); + + ParserCopy(&FuncParser, &FuncValue->Val->FuncDef.Body); + VariableStackFrameAdd(Parser, FuncName, FuncValue->Val->FuncDef.Intrinsic ? FuncValue->Val->FuncDef.NumParams : 0); + TopStackFrame->NumParams = ArgCount; + TopStackFrame->ReturnValue = ReturnValue; + for (Count = 0; Count < FuncValue->Val->FuncDef.NumParams; Count++) + VariableDefine(Parser, FuncValue->Val->FuncDef.ParamName[Count], ParamArray[Count], NULL, TRUE); + + if (ParseStatement(&FuncParser, TRUE) != ParseResultOk) + ProgramFail(&FuncParser, "function body expected"); + + if (RunIt) + { + if (FuncParser.Mode == RunModeRun && FuncValue->Val->FuncDef.ReturnType != &VoidType) + ProgramFail(&FuncParser, "no value returned from a function returning %t", FuncValue->Val->FuncDef.ReturnType); + + else if (FuncParser.Mode == RunModeGoto) + ProgramFail(&FuncParser, "couldn't find goto label '%s'", FuncParser.SearchGotoLabel); + } + + VariableStackFramePop(Parser); + } + else + FuncValue->Val->FuncDef.Intrinsic(Parser, ReturnValue, ParamArray, ArgCount); + + HeapPopStackFrame(); + } + + Parser->Mode = OldMode; +} + +/* parse an expression */ +long ExpressionParseInt(struct ParseState *Parser) +{ + struct Value *Val; + long Result = 0; + + if (!ExpressionParse(Parser, &Val)) + ProgramFail(Parser, "expression expected"); + + if (Parser->Mode == RunModeRun) + { + if (!IS_NUMERIC_COERCIBLE(Val)) + ProgramFail(Parser, "integer value expected instead of %t", Val->Typ); + + Result = ExpressionCoerceInteger(Val); + VariableStackPop(Parser, Val); + } + + return Result; +} + diff --git a/src/cmd/picoc/heap.c b/src/cmd/picoc/heap.c new file mode 100644 index 0000000..ab44f84 --- /dev/null +++ b/src/cmd/picoc/heap.c @@ -0,0 +1,289 @@ +/* picoc heap memory allocation. This is a complete (but small) memory + * allocator for embedded systems which have no memory allocator. Alternatively + * you can define USE_MALLOC_HEAP to use your system's own malloc() allocator */ + +/* stack grows up from the bottom and heap grows down from the top of heap space */ +#include "interpreter.h" + +#define FREELIST_BUCKETS 8 /* freelists for 4, 8, 12 ... 32 byte allocs */ +#define SPLIT_MEM_THRESHOLD 16 /* don't split memory which is close in size */ + +#ifdef USE_MALLOC_STACK +static unsigned char *HeapMemory = NULL; /* stack memory since our heap is malloc()ed */ +static void *HeapBottom = NULL; /* the bottom of the (downward-growing) heap */ +static void *StackFrame = NULL; /* the current stack frame */ +void *HeapStackTop = NULL; /* the top of the stack */ +#else +# ifdef SURVEYOR_HOST +static unsigned char *HeapMemory = (unsigned char *)C_HEAPSTART; /* all memory - stack and heap */ +static void *HeapBottom = (void *)C_HEAPSTART + HEAP_SIZE; /* the bottom of the (downward-growing) heap */ +static void *StackFrame = (void *)C_HEAPSTART; /* the current stack frame */ +void *HeapStackTop = (void *)C_HEAPSTART; /* the top of the stack */ +void *HeapMemStart = (void *)C_HEAPSTART; +# else +static unsigned char HeapMemory[HEAP_SIZE]; /* all memory - stack and heap */ +static void *HeapBottom = &HeapMemory[HEAP_SIZE]; /* the bottom of the (downward-growing) heap */ +static void *StackFrame = &HeapMemory[0]; /* the current stack frame */ +void *HeapStackTop = &HeapMemory[0]; /* the top of the stack */ +# endif +#endif + +static struct AllocNode *FreeListBucket[FREELIST_BUCKETS]; /* we keep a pool of freelist buckets to reduce fragmentation */ +static struct AllocNode *FreeListBig; /* free memory which doesn't fit in a bucket */ + +#ifdef DEBUG_HEAP +void ShowBigList() +{ + struct AllocNode *LPos; + + printf("Heap: bottom=0x%lx 0x%lx-0x%lx, big freelist=", (long)HeapBottom, (long)&HeapMemory[0], (long)&HeapMemory[HEAP_SIZE]); + for (LPos = FreeListBig; LPos != NULL; LPos = LPos->NextFree) + printf("0x%lx:%d ", (long)LPos, LPos->Size); + + printf("\n"); +} +#endif + +/* initialise the stack and heap storage */ +void HeapInit(int StackOrHeapSize) +{ + int Count; + int AlignOffset = 0; + +#ifdef USE_MALLOC_STACK + HeapMemory = malloc(StackOrHeapSize); +#endif + + while (((unsigned long)&HeapMemory[AlignOffset] & (sizeof(ALIGN_TYPE)-1)) != 0) + AlignOffset++; + + StackFrame = &HeapMemory[AlignOffset]; + HeapStackTop = &HeapMemory[AlignOffset]; + *(void **)StackFrame = NULL; + HeapBottom = &HeapMemory[StackOrHeapSize-sizeof(ALIGN_TYPE)+AlignOffset]; + FreeListBig = NULL; + for (Count = 0; Count < FREELIST_BUCKETS; Count++) + FreeListBucket[Count] = NULL; +} + +void HeapCleanup() +{ +#ifdef USE_MALLOC_STACK + free(HeapMemory); +#endif +} + +/* allocate some space on the stack, in the current stack frame + * clears memory. can return NULL if out of stack space */ +void *HeapAllocStack(int Size) +{ + char *NewMem = HeapStackTop; + char *NewTop = (char *)HeapStackTop + MEM_ALIGN(Size); +#ifdef DEBUG_HEAP + printf("HeapAllocStack(%ld) at 0x%lx\n", (unsigned long)MEM_ALIGN(Size), (unsigned long)HeapStackTop); +#endif + if (NewTop > (char *)HeapBottom) + return NULL; + + HeapStackTop = (void *)NewTop; + memset((void *)NewMem, '\0', Size); + return NewMem; +} + +/* allocate some space on the stack, in the current stack frame */ +void HeapUnpopStack(int Size) +{ +#ifdef DEBUG_HEAP + printf("HeapUnpopStack(%ld) at 0x%lx\n", (unsigned long)MEM_ALIGN(Size), (unsigned long)HeapStackTop); +#endif + HeapStackTop = (void *)((char *)HeapStackTop + MEM_ALIGN(Size)); +} + +/* free some space at the top of the stack */ +int HeapPopStack(void *Addr, int Size) +{ + int ToLose = MEM_ALIGN(Size); + if (ToLose > ((char *)HeapStackTop - (char *)&HeapMemory[0])) + return FALSE; + +#ifdef DEBUG_HEAP + printf("HeapPopStack(0x%lx, %ld) back to 0x%lx\n", (unsigned long)Addr, (unsigned long)MEM_ALIGN(Size), (unsigned long)HeapStackTop - ToLose); +#endif + HeapStackTop = (void *)((char *)HeapStackTop - ToLose); + assert(Addr == NULL || HeapStackTop == Addr); + + return TRUE; +} + +/* push a new stack frame on to the stack */ +void HeapPushStackFrame() +{ +#ifdef DEBUG_HEAP + printf("Adding stack frame at 0x%lx\n", (unsigned long)HeapStackTop); +#endif + *(void **)HeapStackTop = StackFrame; + StackFrame = HeapStackTop; + HeapStackTop = (void *)((char *)HeapStackTop + MEM_ALIGN(sizeof(ALIGN_TYPE))); +} + +/* pop the current stack frame, freeing all memory in the frame. can return NULL */ +int HeapPopStackFrame() +{ + if (*(void **)StackFrame != NULL) + { + HeapStackTop = StackFrame; + StackFrame = *(void **)StackFrame; +#ifdef DEBUG_HEAP + printf("Popping stack frame back to 0x%lx\n", (unsigned long)HeapStackTop); +#endif + return TRUE; + } + else + return FALSE; +} + +/* allocate some dynamically allocated memory. memory is cleared. can return NULL if out of memory */ +void *HeapAllocMem(int Size) +{ +#ifdef USE_MALLOC_HEAP + return calloc(Size, 1); +#else + struct AllocNode *NewMem = NULL; + struct AllocNode **FreeNode; + int AllocSize = MEM_ALIGN(Size) + MEM_ALIGN(sizeof(NewMem->Size)); + int Bucket; + void *ReturnMem; + + if (Size == 0) + return NULL; + + assert(Size > 0); + + /* make sure we have enough space for an AllocNode */ + if (AllocSize < sizeof(struct AllocNode)) + AllocSize = sizeof(struct AllocNode); + + Bucket = AllocSize >> 2; + if (Bucket < FREELIST_BUCKETS && FreeListBucket[Bucket] != NULL) + { + /* try to allocate from a freelist bucket first */ +#ifdef DEBUG_HEAP + printf("allocating %d(%d) from bucket", Size, AllocSize); +#endif + NewMem = FreeListBucket[Bucket]; + assert((unsigned long)NewMem >= (unsigned long)&HeapMemory[0] && (unsigned char *)NewMem - &HeapMemory[0] < HEAP_SIZE); + FreeListBucket[Bucket] = *(struct AllocNode **)NewMem; + assert(FreeListBucket[Bucket] == NULL || ((unsigned long)FreeListBucket[Bucket] >= (unsigned long)&HeapMemory[0] && (unsigned char *)FreeListBucket[Bucket] - &HeapMemory[0] < HEAP_SIZE)); + NewMem->Size = AllocSize; + } + else if (FreeListBig != NULL) + { + /* grab the first item from the "big" freelist we can fit in */ + for (FreeNode = &FreeListBig; *FreeNode != NULL && (*FreeNode)->Size < AllocSize; FreeNode = &(*FreeNode)->NextFree) + {} + + if (*FreeNode != NULL) + { + assert((unsigned long)*FreeNode >= (unsigned long)&HeapMemory[0] && (unsigned char *)*FreeNode - &HeapMemory[0] < HEAP_SIZE); + assert((*FreeNode)->Size < HEAP_SIZE && (*FreeNode)->Size > 0); + if ((*FreeNode)->Size < AllocSize + SPLIT_MEM_THRESHOLD) + { + /* close in size - reduce fragmentation by not splitting */ +#ifdef DEBUG_HEAP + printf("allocating %d(%d) from freelist, no split (%d)", Size, AllocSize, (*FreeNode)->Size); +#endif + NewMem = *FreeNode; + assert((unsigned long)NewMem >= (unsigned long)&HeapMemory[0] && (unsigned char *)NewMem - &HeapMemory[0] < HEAP_SIZE); + *FreeNode = NewMem->NextFree; + } + else + { + /* split this big memory chunk */ +#ifdef DEBUG_HEAP + printf("allocating %d(%d) from freelist, split chunk (%d)", Size, AllocSize, (*FreeNode)->Size); +#endif + NewMem = (void *)((char *)*FreeNode + (*FreeNode)->Size - AllocSize); + assert((unsigned long)NewMem >= (unsigned long)&HeapMemory[0] && (unsigned char *)NewMem - &HeapMemory[0] < HEAP_SIZE); + (*FreeNode)->Size -= AllocSize; + NewMem->Size = AllocSize; + } + } + } + + if (NewMem == NULL) + { + /* couldn't allocate from a freelist - try to increase the size of the heap area */ +#ifdef DEBUG_HEAP + printf("allocating %d(%d) at bottom of heap (0x%lx-0x%lx)", Size, AllocSize, (long)((char *)HeapBottom - AllocSize), (long)HeapBottom); +#endif + if ((char *)HeapBottom - AllocSize < (char *)HeapStackTop) + return NULL; + + HeapBottom = (void *)((char *)HeapBottom - AllocSize); + NewMem = HeapBottom; + NewMem->Size = AllocSize; + } + + ReturnMem = (void *)((char *)NewMem + MEM_ALIGN(sizeof(NewMem->Size))); + memset(ReturnMem, '\0', AllocSize - MEM_ALIGN(sizeof(NewMem->Size))); +#ifdef DEBUG_HEAP + printf(" = %lx\n", (unsigned long)ReturnMem); +#endif + return ReturnMem; +#endif +} + +/* free some dynamically allocated memory */ +void HeapFreeMem(void *Mem) +{ +#ifdef USE_MALLOC_HEAP + free(Mem); +#else + struct AllocNode *MemNode = (struct AllocNode *)((char *)Mem - MEM_ALIGN(sizeof(MemNode->Size))); + int Bucket = MemNode->Size >> 2; + +#ifdef DEBUG_HEAP + printf("HeapFreeMem(0x%lx)\n", (unsigned long)Mem); +#endif + assert((unsigned long)Mem >= (unsigned long)&HeapMemory[0] && (unsigned char *)Mem - &HeapMemory[0] < HEAP_SIZE); + assert(MemNode->Size < HEAP_SIZE && MemNode->Size > 0); + if (Mem == NULL) + return; + + if ((void *)MemNode == HeapBottom) + { + /* pop it off the bottom of the heap, reducing the heap size */ +#ifdef DEBUG_HEAP + printf("freeing %d from bottom of heap\n", MemNode->Size); +#endif + HeapBottom = (void *)((char *)HeapBottom + MemNode->Size); +#ifdef DEBUG_HEAP + ShowBigList(); +#endif + } + else if (Bucket < FREELIST_BUCKETS) + { + /* we can fit it in a bucket */ +#ifdef DEBUG_HEAP + printf("freeing %d to bucket\n", MemNode->Size); +#endif + assert(FreeListBucket[Bucket] == NULL || ((unsigned long)FreeListBucket[Bucket] >= (unsigned long)&HeapMemory[0] && (unsigned char *)FreeListBucket[Bucket] - &HeapMemory[0] < HEAP_SIZE)); + *(struct AllocNode **)MemNode = FreeListBucket[Bucket]; + FreeListBucket[Bucket] = (struct AllocNode *)MemNode; + } + else + { + /* put it in the big memory freelist */ +#ifdef DEBUG_HEAP + printf("freeing %lx:%d to freelist\n", (unsigned long)Mem, MemNode->Size); +#endif + assert(FreeListBig == NULL || ((unsigned long)FreeListBig >= (unsigned long)&HeapMemory[0] && (unsigned char *)FreeListBig - &HeapMemory[0] < HEAP_SIZE)); + MemNode->NextFree = FreeListBig; + FreeListBig = MemNode; +#ifdef DEBUG_HEAP + ShowBigList(); +#endif + } +#endif +} + diff --git a/src/cmd/picoc/include.c b/src/cmd/picoc/include.c new file mode 100644 index 0000000..a0f9be3 --- /dev/null +++ b/src/cmd/picoc/include.c @@ -0,0 +1,115 @@ +/* picoc include system - can emulate system includes from built-in libraries + * or it can include and parse files if the system has files */ + +#include "picoc.h" +#include "interpreter.h" + +#ifndef NO_HASH_INCLUDE + +/* a list of libraries we can include */ +struct IncludeLibrary +{ + char *IncludeName; + void (*SetupFunction)(void); + struct LibraryFunction *FuncList; + const char *SetupCSource; + struct IncludeLibrary *NextLib; +}; + +struct IncludeLibrary *IncludeLibList = NULL; + + +/* initialise the built-in include libraries */ +void IncludeInit() +{ +#ifndef BUILTIN_MINI_STDLIB + IncludeRegister("ctype.h", NULL, &StdCtypeFunctions[0], NULL); + IncludeRegister("errno.h", &StdErrnoSetupFunc, NULL, NULL); +# ifndef NO_FP + IncludeRegister("math.h", &MathSetupFunc, &MathFunctions[0], NULL); +# endif + IncludeRegister("stdbool.h", &StdboolSetupFunc, NULL, StdboolDefs); + IncludeRegister("stdio.h", &StdioSetupFunc, &StdioFunctions[0], StdioDefs); + IncludeRegister("stdlib.h", &StdlibSetupFunc, &StdlibFunctions[0], NULL); + IncludeRegister("string.h", &StringSetupFunc, &StringFunctions[0], NULL); + IncludeRegister("time.h", &StdTimeSetupFunc, &StdTimeFunctions[0], StdTimeDefs); +# ifndef WIN32 + IncludeRegister("unistd.h", &UnistdSetupFunc, &UnistdFunctions[0], UnistdDefs); +# endif +#endif +} + +/* clean up space used by the include system */ +void IncludeCleanup() +{ + struct IncludeLibrary *ThisInclude = IncludeLibList; + struct IncludeLibrary *NextInclude; + + while (ThisInclude != NULL) + { + NextInclude = ThisInclude->NextLib; + HeapFreeMem(ThisInclude); + ThisInclude = NextInclude; + } + + IncludeLibList = NULL; +} + +/* register a new build-in include file */ +void IncludeRegister(const char *IncludeName, void (*SetupFunction)(void), struct LibraryFunction *FuncList, const char *SetupCSource) +{ + struct IncludeLibrary *NewLib = HeapAllocMem(sizeof(struct IncludeLibrary)); + NewLib->IncludeName = TableStrRegister(IncludeName); + NewLib->SetupFunction = SetupFunction; + NewLib->FuncList = FuncList; + NewLib->SetupCSource = SetupCSource; + NewLib->NextLib = IncludeLibList; + IncludeLibList = NewLib; +} + +/* include all of the system headers */ +void PicocIncludeAllSystemHeaders() +{ + struct IncludeLibrary *ThisInclude = IncludeLibList; + + for (; ThisInclude != NULL; ThisInclude = ThisInclude->NextLib) + IncludeFile(ThisInclude->IncludeName); +} + +/* include one of a number of predefined libraries, or perhaps an actual file */ +void IncludeFile(char *FileName) +{ + struct IncludeLibrary *LInclude; + + /* scan for the include file name to see if it's in our list of predefined includes */ + for (LInclude = IncludeLibList; LInclude != NULL; LInclude = LInclude->NextLib) + { + if (strcmp(LInclude->IncludeName, FileName) == 0) + { + /* found it - protect against multiple inclusion */ + if (!VariableDefined(FileName)) + { + VariableDefine(NULL, FileName, NULL, &VoidType, FALSE); + + /* run an extra startup function if there is one */ + if (LInclude->SetupFunction != NULL) + (*LInclude->SetupFunction)(); + + /* parse the setup C source code - may define types etc. */ + if (LInclude->SetupCSource != NULL) + PicocParse(FileName, LInclude->SetupCSource, strlen(LInclude->SetupCSource), TRUE, TRUE, FALSE, FALSE); + + /* set up the library functions */ + if (LInclude->FuncList != NULL) + LibraryAdd(&GlobalTable, FileName, LInclude->FuncList); + } + + return; + } + } + + /* not a predefined file, read a real file */ + PicocPlatformScanFile(FileName); +} + +#endif /* NO_HASH_INCLUDE */ diff --git a/src/cmd/picoc/interpreter.h b/src/cmd/picoc/interpreter.h new file mode 100644 index 0000000..8643340 --- /dev/null +++ b/src/cmd/picoc/interpreter.h @@ -0,0 +1,523 @@ +/* picoc main header file - this has all the main data structures and + * function prototypes. If you're just calling picoc you should look at the + * external interface instead, in picoc.h */ + +#ifndef INTERPRETER_H +#define INTERPRETER_H + +#include "platform.h" + + +/* handy definitions */ +#ifndef TRUE +#define TRUE 1 +#define FALSE 0 +#endif + +#ifndef NULL +#define NULL 0 +#endif + +#ifndef min +#define min(x,y) (((x)<(y))?(x):(y)) +#endif + +#define MEM_ALIGN(x) (((x) + sizeof(ALIGN_TYPE) - 1) & ~(sizeof(ALIGN_TYPE)-1)) + +#define GETS_BUF_MAX 256 + +/* small processors use a simplified FILE * for stdio, otherwise use the system FILE * */ +#ifdef BUILTIN_MINI_STDLIB +typedef struct OutputStream IOFILE; +#else +typedef FILE IOFILE; +#endif + +/* coercion of numeric types to other numeric types */ +#ifndef NO_FP +#define IS_FP(v) ((v)->Typ->Base == TypeFP) +#define FP_VAL(v) ((v)->Val->FP) +#else +#define IS_FP(v) 0 +#define FP_VAL(v) 0 +#endif + +#define IS_POINTER_COERCIBLE(v, ap) ((ap) ? ((v)->Typ->Base == TypePointer) : 0) +#define POINTER_COERCE(v) ((int)(v)->Val->Pointer) + +#define IS_INTEGER_NUMERIC_TYPE(t) ((t)->Base >= TypeInt && (t)->Base <= TypeUnsignedLong) +#define IS_INTEGER_NUMERIC(v) IS_INTEGER_NUMERIC_TYPE((v)->Typ) +#define IS_NUMERIC_COERCIBLE(v) (IS_INTEGER_NUMERIC(v) || IS_FP(v)) +#define IS_NUMERIC_COERCIBLE_PLUS_POINTERS(v,ap) (IS_NUMERIC_COERCIBLE(v) || IS_POINTER_COERCIBLE(v,ap)) + + +struct Table; + +/* lexical tokens */ +enum LexToken +{ + /* 0x00 */ TokenNone, + /* 0x01 */ TokenComma, + /* 0x02 */ TokenAssign, TokenAddAssign, TokenSubtractAssign, TokenMultiplyAssign, TokenDivideAssign, TokenModulusAssign, + /* 0x08 */ TokenShiftLeftAssign, TokenShiftRightAssign, TokenArithmeticAndAssign, TokenArithmeticOrAssign, TokenArithmeticExorAssign, + /* 0x0d */ TokenQuestionMark, TokenColon, + /* 0x0f */ TokenLogicalOr, + /* 0x10 */ TokenLogicalAnd, + /* 0x11 */ TokenArithmeticOr, + /* 0x12 */ TokenArithmeticExor, + /* 0x13 */ TokenAmpersand, + /* 0x14 */ TokenEqual, TokenNotEqual, + /* 0x16 */ TokenLessThan, TokenGreaterThan, TokenLessEqual, TokenGreaterEqual, + /* 0x1a */ TokenShiftLeft, TokenShiftRight, + /* 0x1c */ TokenPlus, TokenMinus, + /* 0x1e */ TokenAsterisk, TokenSlash, TokenModulus, + /* 0x21 */ TokenIncrement, TokenDecrement, TokenUnaryNot, TokenUnaryExor, TokenSizeof, TokenCast, + /* 0x27 */ TokenLeftSquareBracket, TokenRightSquareBracket, TokenDot, TokenArrow, + /* 0x2b */ TokenOpenBracket, TokenCloseBracket, + /* 0x2d */ TokenIdentifier, TokenIntegerConstant, TokenFPConstant, TokenStringConstant, TokenCharacterConstant, + /* 0x32 */ TokenSemicolon, TokenEllipsis, + /* 0x34 */ TokenLeftBrace, TokenRightBrace, + /* 0x36 */ TokenIntType, TokenCharType, TokenFloatType, TokenDoubleType, TokenVoidType, TokenEnumType, + /* 0x3c */ TokenLongType, TokenSignedType, TokenShortType, TokenStaticType, TokenAutoType, TokenRegisterType, TokenExternType, TokenStructType, TokenUnionType, TokenUnsignedType, TokenTypedef, + /* 0x46 */ TokenContinue, TokenDo, TokenElse, TokenFor, TokenGoto, TokenIf, TokenWhile, TokenBreak, TokenSwitch, TokenCase, TokenDefault, TokenReturn, + /* 0x52 */ TokenHashDefine, TokenHashInclude, TokenHashIf, TokenHashIfdef, TokenHashIfndef, TokenHashElse, TokenHashEndif, + /* 0x59 */ TokenNew, TokenDelete, + /* 0x5b */ TokenOpenMacroBracket, + /* 0x5c */ TokenEOF, TokenEndOfLine, TokenEndOfFunction +}; + +/* used in dynamic memory allocation */ +struct AllocNode +{ + unsigned int Size; + struct AllocNode *NextFree; +}; + +/* whether we're running or skipping code */ +enum RunMode +{ + RunModeRun, /* we're running code as we parse it */ + RunModeSkip, /* skipping code, not running */ + RunModeReturn, /* returning from a function */ + RunModeCaseSearch, /* searching for a case label */ + RunModeBreak, /* breaking out of a switch/while/do */ + RunModeContinue, /* as above but repeat the loop */ + RunModeGoto /* searching for a goto label */ +}; + +/* parser state - has all this detail so we can parse nested files */ +struct ParseState +{ + const unsigned char *Pos; /* the character position in the source text */ + char *FileName; /* what file we're executing (registered string) */ + short int Line; /* line number we're executing */ + short int CharacterPos; /* character/column in the line we're executing */ + enum RunMode Mode; /* whether to skip or run code */ + int SearchLabel; /* what case label we're searching for */ + const char *SearchGotoLabel;/* what goto label we're searching for */ + const char *SourceText; /* the entire source text */ + short int HashIfLevel; /* how many "if"s we're nested down */ + short int HashIfEvaluateToLevel; /* if we're not evaluating an if branch, what the last evaluated level was */ + char DebugMode; /* debugging mode */ +}; + +/* values */ +enum BaseType +{ + TypeVoid, /* no type */ + TypeInt, /* integer */ + TypeShort, /* short integer */ + TypeChar, /* a single character (unsigned) */ + TypeLong, /* long integer */ + TypeUnsignedInt, /* unsigned integer */ + TypeUnsignedShort, /* unsigned short integer */ + TypeUnsignedLong, /* unsigned long integer */ +#ifndef NO_FP + TypeFP, /* floating point */ +#endif + TypeFunction, /* a function */ + TypeMacro, /* a macro */ + TypePointer, /* a pointer */ + TypeArray, /* an array of a sub-type */ + TypeStruct, /* aggregate type */ + TypeUnion, /* merged type */ + TypeEnum, /* enumerated integer type */ + TypeGotoLabel, /* a label we can "goto" */ + Type_Type /* a type for storing types */ +}; + +/* data type */ +struct ValueType +{ + enum BaseType Base; /* what kind of type this is */ + int ArraySize; /* the size of an array type */ + int Sizeof; /* the storage required */ + int AlignBytes; /* the alignment boundary of this type */ + const char *Identifier; /* the name of a struct or union */ + struct ValueType *FromType; /* the type we're derived from (or NULL) */ + struct ValueType *DerivedTypeList; /* first in a list of types derived from this one */ + struct ValueType *Next; /* next item in the derived type list */ + struct Table *Members; /* members of a struct or union */ + int OnHeap; /* true if allocated on the heap */ + int StaticQualifier; /* true if it's a static */ +}; + +/* function definition */ +struct FuncDef +{ + struct ValueType *ReturnType; /* the return value type */ + int NumParams; /* the number of parameters */ + int VarArgs; /* has a variable number of arguments after the explicitly specified ones */ + struct ValueType **ParamType; /* array of parameter types */ + char **ParamName; /* array of parameter names */ + void (*Intrinsic)(); /* intrinsic call address or NULL */ + struct ParseState Body; /* lexical tokens of the function body if not intrinsic */ +}; + +/* macro definition */ +struct MacroDef +{ + int NumParams; /* the number of parameters */ + char **ParamName; /* array of parameter names */ + struct ParseState Body; /* lexical tokens of the function body if not intrinsic */ +}; + +/* values */ +union AnyValue +{ + unsigned char Character; + short ShortInteger; + int Integer; + long LongInteger; + unsigned short UnsignedShortInteger; + unsigned int UnsignedInteger; + unsigned long UnsignedLongInteger; + char *Identifier; + char ArrayMem[2]; /* placeholder for where the data starts, doesn't point to it */ + struct ValueType *Typ; + struct FuncDef FuncDef; + struct MacroDef MacroDef; +#ifndef NO_FP + double FP; +#endif + void *Pointer; /* unsafe native pointers */ +}; + +struct Value +{ + struct ValueType *Typ; /* the type of this value */ + union AnyValue *Val; /* pointer to the AnyValue which holds the actual content */ + struct Value *LValueFrom; /* if an LValue, this is a Value our LValue is contained within (or NULL) */ + char ValOnHeap; /* this Value is on the heap */ + char ValOnStack; /* the AnyValue is on the stack along with this Value */ + char AnyValOnHeap; /* the AnyValue is separately allocated from the Value on the heap */ + char IsLValue; /* is modifiable and is allocated somewhere we can usefully modify it */ +}; + +/* hash table data structure */ +struct TableEntry +{ + struct TableEntry *Next; /* next item in this hash chain */ + const char *DeclFileName; /* where the variable was declared */ + unsigned short DeclLine; + unsigned short DeclColumn; + + union TableEntryPayload + { + struct ValueEntry + { + char *Key; /* points to the shared string table */ + struct Value *Val; /* the value we're storing */ + } v; /* used for tables of values */ + + char Key[1]; /* dummy size - used for the shared string table */ + + struct BreakpointEntry /* defines a breakpoint */ + { + const char *FileName; + short int Line; + short int CharacterPos; + } b; + + } p; +}; + +struct Table +{ + short Size; + short OnHeap; + struct TableEntry **HashTable; +}; + +/* stack frame for function calls */ +struct StackFrame +{ + struct ParseState ReturnParser; /* how we got here */ + const char *FuncName; /* the name of the function we're in */ + struct Value *ReturnValue; /* copy the return value here */ + struct Value **Parameter; /* array of parameter values */ + int NumParams; /* the number of parameters */ + struct Table LocalTable; /* the local variables and parameters */ + struct TableEntry *LocalHashTable[LOCAL_TABLE_SIZE]; + struct StackFrame *PreviousStackFrame; /* the next lower stack frame */ +}; + +/* lexer state */ +enum LexMode +{ + LexModeNormal, + LexModeHashInclude, + LexModeHashDefine, + LexModeHashDefineSpace, + LexModeHashDefineSpaceIdent +}; + +struct LexState +{ + const char *Pos; + const char *End; + const char *FileName; + int Line; + int CharacterPos; + const char *SourceText; + enum LexMode Mode; + int EmitExtraNewlines; +}; + +/* library function definition */ +struct LibraryFunction +{ + void (*Func)(struct ParseState *Parser, struct Value *, struct Value **, int); + const char *Prototype; +}; + +/* output stream-type specific state information */ +union OutputStreamInfo +{ + struct StringOutputStream + { + struct ParseState *Parser; + char *WritePos; + } Str; +}; + +/* stream-specific method for writing characters to the console */ +typedef void CharWriter(unsigned char, union OutputStreamInfo *); + +/* used when writing output to a string - eg. sprintf() */ +struct OutputStream +{ + CharWriter *Putch; + union OutputStreamInfo i; +}; + +/* possible results of parsing a statement */ +enum ParseResult { ParseResultEOF, ParseResultError, ParseResultOk }; + +/* globals */ +extern void *HeapStackTop; +extern struct Table GlobalTable; +extern struct StackFrame *TopStackFrame; +extern struct ValueType UberType; +extern struct ValueType IntType; +extern struct ValueType CharType; +#ifndef NO_FP +extern struct ValueType FPType; +#endif +extern struct ValueType VoidType; +extern struct ValueType TypeType; +extern struct ValueType FunctionType; +extern struct ValueType MacroType; +extern struct ValueType GotoLabelType; +extern struct ValueType *CharPtrType; +extern struct ValueType *CharPtrPtrType; +extern struct ValueType *CharArrayType; +extern struct ValueType *VoidPtrType; +extern char *StrEmpty; +extern struct PointerValue NULLPointer; +extern struct LibraryFunction CLibrary[]; +extern struct LibraryFunction PlatformLibrary[]; +extern IOFILE *CStdOut; + +/* table.c */ +void TableInit(); +char *TableStrRegister(const char *Str); +char *TableStrRegister2(const char *Str, int Len); +void TableInitTable(struct Table *Tbl, struct TableEntry **HashTable, int Size, int OnHeap); +int TableSet(struct Table *Tbl, char *Key, struct Value *Val, const char *DeclFileName, int DeclLine, int DeclColumn); +int TableGet(struct Table *Tbl, const char *Key, struct Value **Val, const char **DeclFileName, int *DeclLine, int *DeclColumn); +struct Value *TableDelete(struct Table *Tbl, const char *Key); +char *TableSetIdentifier(struct Table *Tbl, const char *Ident, int IdentLen); +void TableStrFree(); + +/* lex.c */ +void LexInit(); +void LexCleanup(); +void *LexAnalyse(const char *FileName, const char *Source, int SourceLen, int *TokenLen); +void LexInitParser(struct ParseState *Parser, const char *SourceText, void *TokenSource, char *FileName, int RunIt, int SetDebugMode); +enum LexToken LexGetToken(struct ParseState *Parser, struct Value **Value, int IncPos); +enum LexToken LexRawPeekToken(struct ParseState *Parser); +void LexToEndOfLine(struct ParseState *Parser); +void *LexCopyTokens(struct ParseState *StartParser, struct ParseState *EndParser); +void LexInteractiveClear(struct ParseState *Parser); +void LexInteractiveCompleted(struct ParseState *Parser); +void LexInteractiveStatementPrompt(); + +/* parse.c */ +/* the following are defined in picoc.h: + * void PicocParse(const char *FileName, const char *Source, int SourceLen, int RunIt, int CleanupNow, int CleanupSource); + * void PicocParseInteractive(); */ +void PicocParseInteractiveNoStartPrompt(int EnableDebugger); +enum ParseResult ParseStatement(struct ParseState *Parser, int CheckTrailingSemicolon); +struct Value *ParseFunctionDefinition(struct ParseState *Parser, struct ValueType *ReturnType, char *Identifier); +void ParseCleanup(); +void ParserCopyPos(struct ParseState *To, struct ParseState *From); +void ParserCopy(struct ParseState *To, struct ParseState *From); + +/* expression.c */ +int ExpressionParse(struct ParseState *Parser, struct Value **Result); +long ExpressionParseInt(struct ParseState *Parser); +void ExpressionAssign(struct ParseState *Parser, struct Value *DestValue, struct Value *SourceValue, int Force, const char *FuncName, int ParamNo, int AllowPointerCoercion); +long ExpressionCoerceInteger(struct Value *Val); +unsigned long ExpressionCoerceUnsignedInteger(struct Value *Val); +#ifndef NO_FP +double ExpressionCoerceFP(struct Value *Val); +#endif + +/* type.c */ +void TypeInit(); +void TypeCleanup(); +int TypeSize(struct ValueType *Typ, int ArraySize, int Compact); +int TypeSizeValue(struct Value *Val, int Compact); +int TypeStackSizeValue(struct Value *Val); +int TypeLastAccessibleOffset(struct Value *Val); +int TypeParseFront(struct ParseState *Parser, struct ValueType **Typ, int *IsStatic); +void TypeParseIdentPart(struct ParseState *Parser, struct ValueType *BasicTyp, struct ValueType **Typ, char **Identifier); +void TypeParse(struct ParseState *Parser, struct ValueType **Typ, char **Identifier, int *IsStatic); +struct ValueType *TypeGetMatching(struct ParseState *Parser, struct ValueType *ParentType, enum BaseType Base, int ArraySize, const char *Identifier, int AllowDuplicates); +struct ValueType *TypeCreateOpaqueStruct(struct ParseState *Parser, const char *StructName, int Size); + +/* heap.c */ +void HeapInit(int StackSize); +void HeapCleanup(); +void *HeapAllocStack(int Size); +int HeapPopStack(void *Addr, int Size); +void HeapUnpopStack(int Size); +void HeapPushStackFrame(); +int HeapPopStackFrame(); +void *HeapAllocMem(int Size); +void HeapFreeMem(void *Mem); + +/* variable.c */ +void VariableInit(); +void VariableCleanup(); +void VariableFree(struct Value *Val); +void VariableTableCleanup(struct Table *HashTable); +void *VariableAlloc(struct ParseState *Parser, int Size, int OnHeap); +void VariableStackPop(struct ParseState *Parser, struct Value *Var); +struct Value *VariableAllocValueAndData(struct ParseState *Parser, int DataSize, int IsLValue, struct Value *LValueFrom, int OnHeap); +struct Value *VariableAllocValueAndCopy(struct ParseState *Parser, struct Value *FromValue, int OnHeap); +struct Value *VariableAllocValueFromType(struct ParseState *Parser, struct ValueType *Typ, int IsLValue, struct Value *LValueFrom, int OnHeap); +struct Value *VariableAllocValueFromExistingData(struct ParseState *Parser, struct ValueType *Typ, union AnyValue *FromValue, int IsLValue, struct Value *LValueFrom); +struct Value *VariableAllocValueShared(struct ParseState *Parser, struct Value *FromValue); +struct Value *VariableDefine(struct ParseState *Parser, char *Ident, struct Value *InitValue, struct ValueType *Typ, int MakeWritable); +struct Value *VariableDefineButIgnoreIdentical(struct ParseState *Parser, char *Ident, struct ValueType *Typ, int IsStatic, int *FirstVisit); +int VariableDefined(const char *Ident); +void VariableRealloc(struct ParseState *Parser, struct Value *FromValue, int NewSize); +void VariableGet(struct ParseState *Parser, const char *Ident, struct Value **LVal); +void VariableDefinePlatformVar(struct ParseState *Parser, char *Ident, struct ValueType *Typ, union AnyValue *FromValue, int IsWritable); +void VariableStackFrameAdd(struct ParseState *Parser, const char *FuncName, int NumParams); +void VariableStackFramePop(struct ParseState *Parser); +struct Value *VariableStringLiteralGet(char *Ident); +void VariableStringLiteralDefine(char *Ident, struct Value *Val); +void *VariableDereferencePointer(struct ParseState *Parser, struct Value *PointerValue, struct Value **DerefVal, int *DerefOffset, struct ValueType **DerefType, int *DerefIsLValue); + +/* clibrary.c */ +void BasicIOInit(); +void LibraryInit(); +void LibraryAdd(struct Table *GlobalTable, const char *LibraryName, struct LibraryFunction *FuncList); +void CLibraryInit(); +void PrintCh(char OutCh, IOFILE *Stream); +void PrintSimpleInt(long Num, IOFILE *Stream); +void PrintInt(long Num, int FieldWidth, int ZeroPad, int LeftJustify, IOFILE *Stream); +void PrintStr(const char *Str, IOFILE *Stream); +void PrintFP(double Num, IOFILE *Stream); +void PrintType(struct ValueType *Typ, IOFILE *Stream); +void LibPrintf(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs); + +/* platform.c */ +/* the following are defined in picoc.h: + * void PicocCallMain(int argc, char **argv); + * int PicocPlatformSetExitPoint(); + * void PicocInitialise(int StackSize); + * void PicocCleanup(); + * void PicocPlatformScanFile(const char *FileName); + * extern int PicocExitValue; */ +void ProgramFail(struct ParseState *Parser, const char *Message, ...); +void AssignFail(struct ParseState *Parser, const char *Format, struct ValueType *Type1, struct ValueType *Type2, int Num1, int Num2, const char *FuncName, int ParamNo); +void LexFail(struct LexState *Lexer, const char *Message, ...); +void PlatformInit(); +void PlatformCleanup(); +char *PlatformGetLine(char *Buf, int MaxLen, const char *Prompt); +int PlatformGetCharacter(); +void PlatformPutc(unsigned char OutCh, union OutputStreamInfo *); +void PlatformErrorPrefix(struct ParseState *Parser); +void PlatformPrintf(const char *Format, ...); +void PlatformVPrintf(const char *Format, va_list Args); +void PlatformExit(int ExitVal); +char *PlatformMakeTempName(char *TempNameBuffer); +void PlatformLibraryInit(); + +/* include.c */ +void IncludeInit(); +void IncludeCleanup(); +void IncludeRegister(const char *IncludeName, void (*SetupFunction)(void), struct LibraryFunction *FuncList, const char *SetupCSource); +void IncludeFile(char *Filename); +/* the following is defined in picoc.h: + * void PicocIncludeAllSystemHeaders(); */ + +/* debug.c */ +extern int DebugManualBreak; +void DebugInit(); +void DebugCleanup(); +void DebugCheckStatement(struct ParseState *Parser); + + +/* stdio.c */ +extern const char StdioDefs[]; +extern struct LibraryFunction StdioFunctions[]; +void StdioSetupFunc(void); + +/* math.c */ +extern struct LibraryFunction MathFunctions[]; +void MathSetupFunc(void); + +/* string.c */ +extern struct LibraryFunction StringFunctions[]; +void StringSetupFunc(void); + +/* stdlib.c */ +extern struct LibraryFunction StdlibFunctions[]; +void StdlibSetupFunc(void); + +/* time.c */ +extern const char StdTimeDefs[]; +extern struct LibraryFunction StdTimeFunctions[]; +void StdTimeSetupFunc(void); + +/* errno.c */ +void StdErrnoSetupFunc(void); + +/* ctype.c */ +extern struct LibraryFunction StdCtypeFunctions[]; + +/* stdbool.c */ +extern const char StdboolDefs[]; +void StdboolSetupFunc(void); + +/* unistd.c */ +extern const char UnistdDefs[]; +extern struct LibraryFunction UnistdFunctions[]; +void UnistdSetupFunc(void); + +#endif /* INTERPRETER_H */ diff --git a/src/cmd/picoc/lex.c b/src/cmd/picoc/lex.c new file mode 100644 index 0000000..93683ba --- /dev/null +++ b/src/cmd/picoc/lex.c @@ -0,0 +1,978 @@ +/* picoc lexer - converts source text into a tokenised form */ + +#include "interpreter.h" + +#ifdef NO_CTYPE +#define isalpha(c) (((c) >= 'a' && (c) <= 'z') || ((c) >= 'A' && (c) <= 'Z')) +#define isdigit(c) ((c) >= '0' && (c) <= '9') +#define isalnum(c) (isalpha(c) || isdigit(c)) +#define isspace(c) ((c) == ' ' || (c) == '\t' || (c) == '\r' || (c) == '\n') +#endif +#define isCidstart(c) (isalpha(c) || (c)=='_' || (c)=='#') +#define isCident(c) (isalnum(c) || (c)=='_') + +#define IS_HEX_ALPHA_DIGIT(c) (((c) >= 'a' && (c) <= 'f') || ((c) >= 'A' && (c) <= 'F')) +#define IS_BASE_DIGIT(c,b) (((c) >= '0' && (c) < '0' + (((b)<10)?(b):10)) || (((b) > 10) ? IS_HEX_ALPHA_DIGIT(c) : FALSE)) +#define GET_BASE_DIGIT(c) (((c) <= '9') ? ((c) - '0') : (((c) <= 'F') ? ((c) - 'A' + 10) : ((c) - 'a' + 10))) + +#define NEXTIS(c,x,y) { if (NextChar == (c)) { LEXER_INC(Lexer); GotToken = (x); } else GotToken = (y); } +#define NEXTIS3(c,x,d,y,z) { if (NextChar == (c)) { LEXER_INC(Lexer); GotToken = (x); } else NEXTIS(d,y,z) } +#define NEXTIS4(c,x,d,y,e,z,a) { if (NextChar == (c)) { LEXER_INC(Lexer); GotToken = (x); } else NEXTIS3(d,y,e,z,a) } +#define NEXTIS3PLUS(c,x,d,y,e,z,a) { if (NextChar == (c)) { LEXER_INC(Lexer); GotToken = (x); } else if (NextChar == (d)) { if (Lexer->Pos[1] == (e)) { LEXER_INCN(Lexer, 2); GotToken = (z); } else { LEXER_INC(Lexer); GotToken = (y); } } else GotToken = (a); } +#define NEXTISEXACTLY3(c,d,y,z) { if (NextChar == (c) && Lexer->Pos[1] == (d)) { LEXER_INCN(Lexer, 2); GotToken = (y); } else GotToken = (z); } + +#define LEXER_INC(l) ( (l)->Pos++, (l)->CharacterPos++ ) +#define LEXER_INCN(l, n) ( (l)->Pos+=(n), (l)->CharacterPos+=(n) ) +#define TOKEN_DATA_OFFSET 2 + +#define MAX_CHAR_VALUE 255 /* maximum value which can be represented by a "char" data type */ + +static union AnyValue LexAnyValue; +static struct Value LexValue = { &VoidType, &LexAnyValue, NULL, FALSE, FALSE, FALSE }; + +struct ReservedWord +{ + const char *Word; + enum LexToken Token; + const char *SharedWord; /* word stored in shared string space */ +}; + +static struct ReservedWord ReservedWords[] = +{ + { "#define", TokenHashDefine, NULL }, + { "#else", TokenHashElse, NULL }, + { "#endif", TokenHashEndif, NULL }, + { "#if", TokenHashIf, NULL }, + { "#ifdef", TokenHashIfdef, NULL }, + { "#ifndef", TokenHashIfndef, NULL }, + { "#include", TokenHashInclude, NULL }, + { "auto", TokenAutoType, NULL }, + { "break", TokenBreak, NULL }, + { "case", TokenCase, NULL }, + { "char", TokenCharType, NULL }, + { "continue", TokenContinue, NULL }, + { "default", TokenDefault, NULL }, + { "delete", TokenDelete, NULL }, + { "do", TokenDo, NULL }, +#ifndef NO_FP + { "double", TokenDoubleType, NULL }, +#endif + { "else", TokenElse, NULL }, + { "enum", TokenEnumType, NULL }, + { "extern", TokenExternType, NULL }, +#ifndef NO_FP + { "float", TokenFloatType, NULL }, +#endif + { "for", TokenFor, NULL }, + { "goto", TokenGoto, NULL }, + { "if", TokenIf, NULL }, + { "int", TokenIntType, NULL }, + { "long", TokenLongType, NULL }, + { "new", TokenNew, NULL }, + { "register", TokenRegisterType, NULL }, + { "return", TokenReturn, NULL }, + { "short", TokenShortType, NULL }, + { "signed", TokenSignedType, NULL }, + { "sizeof", TokenSizeof, NULL }, + { "static", TokenStaticType, NULL }, + { "struct", TokenStructType, NULL }, + { "switch", TokenSwitch, NULL }, + { "typedef", TokenTypedef, NULL }, + { "union", TokenUnionType, NULL }, + { "unsigned", TokenUnsignedType, NULL }, + { "void", TokenVoidType, NULL }, + { "while", TokenWhile, NULL } +}; + +/* linked list of tokens used in interactive mode */ +struct TokenLine +{ + struct TokenLine *Next; + unsigned char *Tokens; + int NumBytes; +}; + +static struct TokenLine *InteractiveHead = NULL; +static struct TokenLine *InteractiveTail = NULL; +static struct TokenLine *InteractiveCurrentLine = NULL; +static int LexUseStatementPrompt = FALSE; + + +/* initialise the lexer */ +void LexInit() +{ + int Count; + + for (Count = 0; Count < sizeof(ReservedWords) / sizeof(struct ReservedWord); Count++) + ReservedWords[Count].SharedWord = TableStrRegister(ReservedWords[Count].Word); +} + +/* deallocate */ +void LexCleanup() +{ + LexInteractiveClear(NULL); +} + +/* check if a word is a reserved word - used while scanning */ +enum LexToken LexCheckReservedWord(const char *Word) +{ + int Count; + + for (Count = 0; Count < sizeof(ReservedWords) / sizeof(struct ReservedWord); Count++) + { + if (Word == ReservedWords[Count].SharedWord) + return ReservedWords[Count].Token; + } + + return TokenNone; +} + +/* get a numeric literal - used while scanning */ +enum LexToken LexGetNumber(struct LexState *Lexer, struct Value *Value) +{ + int Result = 0; + int Base = 10; + enum LexToken ResultToken; +#ifndef NO_FP + double FPResult; + double FPDiv; +#endif + + if (*Lexer->Pos == '0') + { + /* a binary, octal or hex literal */ + LEXER_INC(Lexer); + if (Lexer->Pos != Lexer->End) + { + if (*Lexer->Pos == 'x' || *Lexer->Pos == 'X') + { Base = 16; LEXER_INC(Lexer); } + else if (*Lexer->Pos == 'b' || *Lexer->Pos == 'B') + { Base = 2; LEXER_INC(Lexer); } + else if (*Lexer->Pos != '.') + Base = 8; + } + } + + /* get the value */ + for (; Lexer->Pos != Lexer->End && IS_BASE_DIGIT(*Lexer->Pos, Base); LEXER_INC(Lexer)) + Result = Result * Base + GET_BASE_DIGIT(*Lexer->Pos); + + if (Result >= 0 && Result <= MAX_CHAR_VALUE) + { + Value->Typ = &CharType; + Value->Val->Character = Result; + ResultToken = TokenCharacterConstant; + } + else + { + Value->Typ = &IntType; + Value->Val->Integer = Result; + ResultToken = TokenIntegerConstant; + } + + if (Lexer->Pos == Lexer->End) + return ResultToken; + + if (*Lexer->Pos == 'l' || *Lexer->Pos == 'L') + { + LEXER_INC(Lexer); + return ResultToken; + } + +#ifndef NO_FP + if (Lexer->Pos == Lexer->End || *Lexer->Pos != '.') + return ResultToken; + + Value->Typ = &FPType; + LEXER_INC(Lexer); + for (FPDiv = 1.0/Base, FPResult = (double)Result; Lexer->Pos != Lexer->End && IS_BASE_DIGIT(*Lexer->Pos, Base); LEXER_INC(Lexer), FPDiv /= (double)Base) + FPResult += GET_BASE_DIGIT(*Lexer->Pos) * FPDiv; + + if (Lexer->Pos != Lexer->End && (*Lexer->Pos == 'e' || *Lexer->Pos == 'E')) + { + double ExponentMultiplier = 1.0; + + LEXER_INC(Lexer); + if (Lexer->Pos != Lexer->End && *Lexer->Pos == '-') + { + ExponentMultiplier = -1.0; + LEXER_INC(Lexer); + } + + Result = 0; + while (Lexer->Pos != Lexer->End && IS_BASE_DIGIT(*Lexer->Pos, Base)) + { + Result = Result * Base + GET_BASE_DIGIT(*Lexer->Pos); + LEXER_INC(Lexer); + } + + FPResult *= pow((double)Base, (double)Result * ExponentMultiplier); + } + + Value->Val->FP = FPResult; + + return TokenFPConstant; +#else + return ResultToken; +#endif +} + +/* get a reserved word or identifier - used while scanning */ +enum LexToken LexGetWord(struct LexState *Lexer, struct Value *Value) +{ + const char *StartPos = Lexer->Pos; + enum LexToken Token; + + do { + LEXER_INC(Lexer); + } while (Lexer->Pos != Lexer->End && isCident((int)*Lexer->Pos)); + + Value->Typ = NULL; + Value->Val->Identifier = TableStrRegister2(StartPos, Lexer->Pos - StartPos); + + Token = LexCheckReservedWord(Value->Val->Identifier); + switch (Token) + { + case TokenHashInclude: Lexer->Mode = LexModeHashInclude; break; + case TokenHashDefine: Lexer->Mode = LexModeHashDefine; break; + default: break; + } + + if (Token != TokenNone) + return Token; + + if (Lexer->Mode == LexModeHashDefineSpace) + Lexer->Mode = LexModeHashDefineSpaceIdent; + + return TokenIdentifier; +} + +/* unescape a character from an octal character constant */ +unsigned char LexUnEscapeCharacterConstant(const char **From, const char *End, unsigned char FirstChar, int Base) +{ + unsigned char Total = GET_BASE_DIGIT(FirstChar); + int CCount; + for (CCount = 0; IS_BASE_DIGIT(**From, Base) && CCount < 2; CCount++, (*From)++) + Total = Total * Base + GET_BASE_DIGIT(**From); + + return Total; +} + +/* unescape a character from a string or character constant */ +unsigned char LexUnEscapeCharacter(const char **From, const char *End) +{ + unsigned char ThisChar; + + while ( *From != End && **From == '\\' && + &(*From)[1] != End && (*From)[1] == '\n' ) + (*From) += 2; /* skip escaped end of lines with LF line termination */ + + while ( *From != End && **From == '\\' && + &(*From)[1] != End && &(*From)[2] != End && (*From)[1] == '\r' && (*From)[2] == '\n') + (*From) += 3; /* skip escaped end of lines with CR/LF line termination */ + + if (*From == End) + return '\\'; + + if (**From == '\\') + { + /* it's escaped */ + (*From)++; + if (*From == End) + return '\\'; + + ThisChar = *(*From)++; + switch (ThisChar) + { + case '\\': return '\\'; + case '\'': return '\''; + case '"': return '"'; + case 'a': return '\a'; + case 'b': return '\b'; + case 'f': return '\f'; + case 'n': return '\n'; + case 'r': return '\r'; + case 't': return '\t'; + case 'v': return '\v'; + case '0': case '1': case '2': case '3': return LexUnEscapeCharacterConstant(From, End, ThisChar, 8); + case 'x': return LexUnEscapeCharacterConstant(From, End, '0', 16); + default: return ThisChar; + } + } + else + return *(*From)++; +} + +/* get a string constant - used while scanning */ +enum LexToken LexGetStringConstant(struct LexState *Lexer, struct Value *Value, char EndChar) +{ + int Escape = FALSE; + const char *StartPos = Lexer->Pos; + const char *EndPos; + char *EscBuf; + char *EscBufPos; + char *RegString; + struct Value *ArrayValue; + + while (Lexer->Pos != Lexer->End && (*Lexer->Pos != EndChar || Escape)) + { + /* find the end */ + if (Escape) + { + if (*Lexer->Pos == '\r' && Lexer->Pos+1 != Lexer->End) + Lexer->Pos++; + + if (*Lexer->Pos == '\n' && Lexer->Pos+1 != Lexer->End) + { + Lexer->Line++; + Lexer->Pos++; + Lexer->CharacterPos = 0; + Lexer->EmitExtraNewlines++; + } + + Escape = FALSE; + } + else if (*Lexer->Pos == '\\') + Escape = TRUE; + + LEXER_INC(Lexer); + } + EndPos = Lexer->Pos; + + EscBuf = HeapAllocStack(EndPos - StartPos); + if (EscBuf == NULL) + LexFail(Lexer, "out of memory"); + + for (EscBufPos = EscBuf, Lexer->Pos = StartPos; Lexer->Pos != EndPos;) + *EscBufPos++ = LexUnEscapeCharacter(&Lexer->Pos, EndPos); + + /* try to find an existing copy of this string literal */ + RegString = TableStrRegister2(EscBuf, EscBufPos - EscBuf); + HeapPopStack(EscBuf, EndPos - StartPos); + ArrayValue = VariableStringLiteralGet(RegString); + if (ArrayValue == NULL) + { + /* create and store this string literal */ + ArrayValue = VariableAllocValueAndData(NULL, 0, FALSE, NULL, TRUE); + ArrayValue->Typ = CharArrayType; + ArrayValue->Val = (union AnyValue *)RegString; + VariableStringLiteralDefine(RegString, ArrayValue); + } + + /* create the the pointer for this char* */ + Value->Typ = CharPtrType; + Value->Val->Pointer = RegString; + if (*Lexer->Pos == EndChar) + LEXER_INC(Lexer); + + return TokenStringConstant; +} + +/* get a character constant - used while scanning */ +enum LexToken LexGetCharacterConstant(struct LexState *Lexer, struct Value *Value) +{ + Value->Typ = &CharType; + Value->Val->Character = LexUnEscapeCharacter(&Lexer->Pos, Lexer->End); + if (Lexer->Pos != Lexer->End && *Lexer->Pos != '\'') + LexFail(Lexer, "expected \"'\""); + + LEXER_INC(Lexer); + return TokenCharacterConstant; +} + +/* skip a comment - used while scanning */ +void LexSkipComment(struct LexState *Lexer, char NextChar, enum LexToken *ReturnToken) +{ + if (NextChar == '*') + { + /* conventional C comment */ + while (Lexer->Pos != Lexer->End && (*(Lexer->Pos-1) != '*' || *Lexer->Pos != '/')) + { + if (*Lexer->Pos == '\n') + Lexer->EmitExtraNewlines++; + + LEXER_INC(Lexer); + } + + if (Lexer->Pos != Lexer->End) + LEXER_INC(Lexer); + + Lexer->Mode = LexModeNormal; + } + else + { + /* C++ style comment */ + while (Lexer->Pos != Lexer->End && *Lexer->Pos != '\n') + LEXER_INC(Lexer); + } +} + +/* get a single token from the source - used while scanning */ +enum LexToken LexScanGetToken(struct LexState *Lexer, struct Value **Value) +{ + char ThisChar; + char NextChar; + enum LexToken GotToken = TokenNone; + + /* handle cases line multi-line comments or string constants which mess up the line count */ + if (Lexer->EmitExtraNewlines > 0) + { + Lexer->EmitExtraNewlines--; + return TokenEndOfLine; + } + + /* scan for a token */ + do + { + *Value = &LexValue; + while (Lexer->Pos != Lexer->End && isspace((int)*Lexer->Pos)) + { + if (*Lexer->Pos == '\n') + { + Lexer->Line++; + Lexer->Pos++; + Lexer->Mode = LexModeNormal; + Lexer->CharacterPos = 0; + return TokenEndOfLine; + } + else if (Lexer->Mode == LexModeHashDefine || Lexer->Mode == LexModeHashDefineSpace) + Lexer->Mode = LexModeHashDefineSpace; + + else if (Lexer->Mode == LexModeHashDefineSpaceIdent) + Lexer->Mode = LexModeNormal; + + LEXER_INC(Lexer); + } + + if (Lexer->Pos == Lexer->End || *Lexer->Pos == '\0') + return TokenEOF; + + ThisChar = *Lexer->Pos; + if (isCidstart((int)ThisChar)) + return LexGetWord(Lexer, *Value); + + if (isdigit((int)ThisChar)) + return LexGetNumber(Lexer, *Value); + + NextChar = (Lexer->Pos+1 != Lexer->End) ? *(Lexer->Pos+1) : 0; + LEXER_INC(Lexer); + switch (ThisChar) + { + case '"': GotToken = LexGetStringConstant(Lexer, *Value, '"'); break; + case '\'': GotToken = LexGetCharacterConstant(Lexer, *Value); break; + case '(': if (Lexer->Mode == LexModeHashDefineSpaceIdent) GotToken = TokenOpenMacroBracket; else GotToken = TokenOpenBracket; Lexer->Mode = LexModeNormal; break; + case ')': GotToken = TokenCloseBracket; break; + case '=': NEXTIS('=', TokenEqual, TokenAssign); break; + case '+': NEXTIS3('=', TokenAddAssign, '+', TokenIncrement, TokenPlus); break; + case '-': NEXTIS4('=', TokenSubtractAssign, '>', TokenArrow, '-', TokenDecrement, TokenMinus); break; + case '*': NEXTIS('=', TokenMultiplyAssign, TokenAsterisk); break; + case '/': if (NextChar == '/' || NextChar == '*') { LEXER_INC(Lexer); LexSkipComment(Lexer, NextChar, &GotToken); } else NEXTIS('=', TokenDivideAssign, TokenSlash); break; + case '%': NEXTIS('=', TokenModulusAssign, TokenModulus); break; + case '<': if (Lexer->Mode == LexModeHashInclude) GotToken = LexGetStringConstant(Lexer, *Value, '>'); else { NEXTIS3PLUS('=', TokenLessEqual, '<', TokenShiftLeft, '=', TokenShiftLeftAssign, TokenLessThan); } break; + case '>': NEXTIS3PLUS('=', TokenGreaterEqual, '>', TokenShiftRight, '=', TokenShiftRightAssign, TokenGreaterThan); break; + case ';': GotToken = TokenSemicolon; break; + case '&': NEXTIS3('=', TokenArithmeticAndAssign, '&', TokenLogicalAnd, TokenAmpersand); break; + case '|': NEXTIS3('=', TokenArithmeticOrAssign, '|', TokenLogicalOr, TokenArithmeticOr); break; + case '{': GotToken = TokenLeftBrace; break; + case '}': GotToken = TokenRightBrace; break; + case '[': GotToken = TokenLeftSquareBracket; break; + case ']': GotToken = TokenRightSquareBracket; break; + case '!': NEXTIS('=', TokenNotEqual, TokenUnaryNot); break; + case '^': NEXTIS('=', TokenArithmeticExorAssign, TokenArithmeticExor); break; + case '~': GotToken = TokenUnaryExor; break; + case ',': GotToken = TokenComma; break; + case '.': NEXTISEXACTLY3('.', '.', TokenEllipsis, TokenDot); break; + case '?': GotToken = TokenQuestionMark; break; + case ':': GotToken = TokenColon; break; + default: LexFail(Lexer, "illegal character '%c'", ThisChar); break; + } + } while (GotToken == TokenNone); + + return GotToken; +} + +/* what size value goes with each token */ +int LexTokenSize(enum LexToken Token) +{ + switch (Token) + { + case TokenIdentifier: case TokenStringConstant: return sizeof(char *); + case TokenIntegerConstant: return sizeof(int); + case TokenCharacterConstant: return sizeof(unsigned char); + case TokenFPConstant: return sizeof(double); + default: return 0; + } +} + +/* produce tokens from the lexer and return a heap buffer with the result - used for scanning */ +void *LexTokenise(struct LexState *Lexer, int *TokenLen) +{ + enum LexToken Token; + void *HeapMem; + struct Value *GotValue; + int MemUsed = 0; + int ValueSize; + int ReserveSpace = (Lexer->End - Lexer->Pos) * 4 + 16; + void *TokenSpace = HeapAllocStack(ReserveSpace); + char *TokenPos = (char *)TokenSpace; + int LastCharacterPos = 0; + + if (TokenSpace == NULL) + LexFail(Lexer, "out of memory"); + + do + { + /* store the token at the end of the stack area */ + Token = LexScanGetToken(Lexer, &GotValue); + +#ifdef DEBUG_LEXER + printf("Token: %02x\n", Token); +#endif + *(unsigned char *)TokenPos = Token; + TokenPos++; + MemUsed++; + + *(unsigned char *)TokenPos = (unsigned char)LastCharacterPos; + TokenPos++; + MemUsed++; + + ValueSize = LexTokenSize(Token); + if (ValueSize > 0) + { + /* store a value as well */ + memcpy((void *)TokenPos, (void *)GotValue->Val, ValueSize); + TokenPos += ValueSize; + MemUsed += ValueSize; + } + + LastCharacterPos = Lexer->CharacterPos; + + } while (Token != TokenEOF); + + HeapMem = HeapAllocMem(MemUsed); + if (HeapMem == NULL) + LexFail(Lexer, "out of memory"); + + assert(ReserveSpace >= MemUsed); + memcpy(HeapMem, TokenSpace, MemUsed); + HeapPopStack(TokenSpace, ReserveSpace); +#ifdef DEBUG_LEXER + { + int Count; + printf("Tokens: "); + for (Count = 0; Count < MemUsed; Count++) + printf("%02x ", *((unsigned char *)HeapMem+Count)); + printf("\n"); + } +#endif + if (TokenLen) + *TokenLen = MemUsed; + + return HeapMem; +} + +/* lexically analyse some source text */ +void *LexAnalyse(const char *FileName, const char *Source, int SourceLen, int *TokenLen) +{ + struct LexState Lexer; + + Lexer.Pos = Source; + Lexer.End = Source + SourceLen; + Lexer.Line = 1; + Lexer.FileName = FileName; + Lexer.Mode = LexModeNormal; + Lexer.EmitExtraNewlines = 0; + Lexer.CharacterPos = 1; + Lexer.SourceText = Source; + + return LexTokenise(&Lexer, TokenLen); +} + +/* prepare to parse a pre-tokenised buffer */ +void LexInitParser(struct ParseState *Parser, const char *SourceText, void *TokenSource, char *FileName, int RunIt, int EnableDebugger) +{ + Parser->Pos = TokenSource; + Parser->Line = 1; + Parser->FileName = FileName; + Parser->Mode = RunIt ? RunModeRun : RunModeSkip; + Parser->SearchLabel = 0; + Parser->HashIfLevel = 0; + Parser->HashIfEvaluateToLevel = 0; + Parser->CharacterPos = 0; + Parser->SourceText = SourceText; + Parser->DebugMode = EnableDebugger; +} + +/* get the next token, without pre-processing */ +enum LexToken LexGetRawToken(struct ParseState *Parser, struct Value **Value, int IncPos) +{ + enum LexToken Token = TokenNone; + int ValueSize; + char *Prompt = NULL; + + do + { + /* get the next token */ + if (Parser->Pos == NULL && InteractiveHead != NULL) + Parser->Pos = InteractiveHead->Tokens; + + if (Parser->FileName != StrEmpty || InteractiveHead != NULL) + { + /* skip leading newlines */ + while ((Token = (enum LexToken)*(unsigned char *)Parser->Pos) == TokenEndOfLine) + { + Parser->Line++; + Parser->Pos += TOKEN_DATA_OFFSET; + } + } + + if (Parser->FileName == StrEmpty && (InteractiveHead == NULL || Token == TokenEOF)) + { + /* we're at the end of an interactive input token list */ + char LineBuffer[LINEBUFFER_MAX]; + void *LineTokens; + int LineBytes; + struct TokenLine *LineNode; + + if (InteractiveHead == NULL || (unsigned char *)Parser->Pos == &InteractiveTail->Tokens[InteractiveTail->NumBytes-TOKEN_DATA_OFFSET]) + { + /* get interactive input */ + if (LexUseStatementPrompt) + { + Prompt = INTERACTIVE_PROMPT_STATEMENT; + LexUseStatementPrompt = FALSE; + } + else + Prompt = INTERACTIVE_PROMPT_LINE; + + if (PlatformGetLine(&LineBuffer[0], LINEBUFFER_MAX, Prompt) == NULL) + return TokenEOF; + + /* put the new line at the end of the linked list of interactive lines */ + LineTokens = LexAnalyse(StrEmpty, &LineBuffer[0], strlen(LineBuffer), &LineBytes); + LineNode = VariableAlloc(Parser, sizeof(struct TokenLine), TRUE); + LineNode->Tokens = LineTokens; + LineNode->NumBytes = LineBytes; + if (InteractiveHead == NULL) + { + /* start a new list */ + InteractiveHead = LineNode; + Parser->Line = 1; + Parser->CharacterPos = 0; + } + else + InteractiveTail->Next = LineNode; + + InteractiveTail = LineNode; + InteractiveCurrentLine = LineNode; + Parser->Pos = LineTokens; + } + else + { + /* go to the next token line */ + if (Parser->Pos != &InteractiveCurrentLine->Tokens[InteractiveCurrentLine->NumBytes-TOKEN_DATA_OFFSET]) + { + /* scan for the line */ + for (InteractiveCurrentLine = InteractiveHead; Parser->Pos != &InteractiveCurrentLine->Tokens[InteractiveCurrentLine->NumBytes-TOKEN_DATA_OFFSET]; InteractiveCurrentLine = InteractiveCurrentLine->Next) + { assert(InteractiveCurrentLine->Next != NULL); } + } + + assert(InteractiveCurrentLine != NULL); + InteractiveCurrentLine = InteractiveCurrentLine->Next; + assert(InteractiveCurrentLine != NULL); + Parser->Pos = InteractiveCurrentLine->Tokens; + } + + Token = (enum LexToken)*(unsigned char *)Parser->Pos; + } + } while ((Parser->FileName == StrEmpty && Token == TokenEOF) || Token == TokenEndOfLine); + + Parser->CharacterPos = *((unsigned char *)Parser->Pos + 1); + ValueSize = LexTokenSize(Token); + if (ValueSize > 0) + { + /* this token requires a value - unpack it */ + if (Value != NULL) + { + switch (Token) + { + case TokenStringConstant: LexValue.Typ = CharPtrType; break; + case TokenIdentifier: LexValue.Typ = NULL; break; + case TokenIntegerConstant: LexValue.Typ = &IntType; break; + case TokenCharacterConstant: LexValue.Typ = &CharType; break; +#ifndef NO_FP + case TokenFPConstant: LexValue.Typ = &FPType; break; +#endif + default: break; + } + + memcpy((void *)LexValue.Val, (void *)((char *)Parser->Pos + TOKEN_DATA_OFFSET), ValueSize); + LexValue.ValOnHeap = FALSE; + LexValue.ValOnStack = FALSE; + LexValue.IsLValue = FALSE; + LexValue.LValueFrom = NULL; + *Value = &LexValue; + } + + if (IncPos) + Parser->Pos += ValueSize + TOKEN_DATA_OFFSET; + } + else + { + if (IncPos && Token != TokenEOF) + Parser->Pos += TOKEN_DATA_OFFSET; + } + +#ifdef DEBUG_LEXER + printf("Got token=%02x inc=%d pos=%d\n", Token, IncPos, Parser->CharacterPos); +#endif + assert(Token >= TokenNone && Token <= TokenEndOfFunction); + return Token; +} + +/* correct the token position depending if we already incremented the position */ +void LexHashIncPos(struct ParseState *Parser, int IncPos) +{ + if (!IncPos) + LexGetRawToken(Parser, NULL, TRUE); +} + +/* handle a #ifdef directive */ +void LexHashIfdef(struct ParseState *Parser, int IfNot) +{ + /* get symbol to check */ + struct Value *IdentValue; + struct Value *SavedValue; + int IsDefined; + enum LexToken Token = LexGetRawToken(Parser, &IdentValue, TRUE); + + if (Token != TokenIdentifier) + ProgramFail(Parser, "identifier expected"); + + /* is the identifier defined? */ + IsDefined = TableGet(&GlobalTable, IdentValue->Val->Identifier, &SavedValue, NULL, NULL, NULL); + if (Parser->HashIfEvaluateToLevel == Parser->HashIfLevel && ( (IsDefined && !IfNot) || (!IsDefined && IfNot)) ) + { + /* #if is active, evaluate to this new level */ + Parser->HashIfEvaluateToLevel++; + } + + Parser->HashIfLevel++; +} + +/* handle a #if directive */ +void LexHashIf(struct ParseState *Parser) +{ + /* get symbol to check */ + struct Value *IdentValue; + struct Value *SavedValue; + struct ParseState MacroParser; + enum LexToken Token = LexGetRawToken(Parser, &IdentValue, TRUE); + + if (Token == TokenIdentifier) + { + /* look up a value from a macro definition */ + if (!TableGet(&GlobalTable, IdentValue->Val->Identifier, &SavedValue, NULL, NULL, NULL)) + ProgramFail(Parser, "'%s' is undefined", IdentValue->Val->Identifier); + + if (SavedValue->Typ->Base != TypeMacro) + ProgramFail(Parser, "value expected"); + + ParserCopy(&MacroParser, &SavedValue->Val->MacroDef.Body); + Token = LexGetRawToken(&MacroParser, &IdentValue, TRUE); + } + + if (Token != TokenCharacterConstant) + ProgramFail(Parser, "value expected"); + + /* is the identifier defined? */ + if (Parser->HashIfEvaluateToLevel == Parser->HashIfLevel && IdentValue->Val->Character) + { + /* #if is active, evaluate to this new level */ + Parser->HashIfEvaluateToLevel++; + } + + Parser->HashIfLevel++; +} + +/* handle a #else directive */ +void LexHashElse(struct ParseState *Parser) +{ + if (Parser->HashIfEvaluateToLevel == Parser->HashIfLevel - 1) + Parser->HashIfEvaluateToLevel++; /* #if was not active, make this next section active */ + + else if (Parser->HashIfEvaluateToLevel == Parser->HashIfLevel) + { + /* #if was active, now go inactive */ + if (Parser->HashIfLevel == 0) + ProgramFail(Parser, "#else without #if"); + + Parser->HashIfEvaluateToLevel--; + } +} + +/* handle a #endif directive */ +void LexHashEndif(struct ParseState *Parser) +{ + if (Parser->HashIfLevel == 0) + ProgramFail(Parser, "#endif without #if"); + + Parser->HashIfLevel--; + if (Parser->HashIfEvaluateToLevel > Parser->HashIfLevel) + Parser->HashIfEvaluateToLevel = Parser->HashIfLevel; +} + +/* get the next token given a parser state, pre-processing as we go */ +enum LexToken LexGetToken(struct ParseState *Parser, struct Value **Value, int IncPos) +{ + enum LexToken Token; + int TryNextToken; + + /* implements the pre-processor #if commands */ + do + { + int WasPreProcToken = TRUE; + + Token = LexGetRawToken(Parser, Value, IncPos); + switch (Token) + { + case TokenHashIfdef: LexHashIncPos(Parser, IncPos); LexHashIfdef(Parser, FALSE); break; + case TokenHashIfndef: LexHashIncPos(Parser, IncPos); LexHashIfdef(Parser, TRUE); break; + case TokenHashIf: LexHashIncPos(Parser, IncPos); LexHashIf(Parser); break; + case TokenHashElse: LexHashIncPos(Parser, IncPos); LexHashElse(Parser); break; + case TokenHashEndif: LexHashIncPos(Parser, IncPos); LexHashEndif(Parser); break; + default: WasPreProcToken = FALSE; break; + } + + /* if we're going to reject this token, increment the token pointer to the next one */ + TryNextToken = (Parser->HashIfEvaluateToLevel < Parser->HashIfLevel && Token != TokenEOF) || WasPreProcToken; + if (!IncPos && TryNextToken) + LexGetRawToken(Parser, NULL, TRUE); + + } while (TryNextToken); + + return Token; +} + +/* take a quick peek at the next token, skipping any pre-processing */ +enum LexToken LexRawPeekToken(struct ParseState *Parser) +{ + return (enum LexToken)*(unsigned char *)Parser->Pos; +} + +/* find the end of the line */ +void LexToEndOfLine(struct ParseState *Parser) +{ + while (TRUE) + { + enum LexToken Token = (enum LexToken)*(unsigned char *)Parser->Pos; + if (Token == TokenEndOfLine || Token == TokenEOF) + return; + else + LexGetRawToken(Parser, NULL, TRUE); + } +} + +/* copy the tokens from StartParser to EndParser into new memory, removing TokenEOFs and terminate with a TokenEndOfFunction */ +void *LexCopyTokens(struct ParseState *StartParser, struct ParseState *EndParser) +{ + int MemSize = 0; + int CopySize; + unsigned char *Pos = (unsigned char *)StartParser->Pos; + unsigned char *NewTokens; + unsigned char *NewTokenPos; + struct TokenLine *ILine; + + if (InteractiveHead == NULL) + { + /* non-interactive mode - copy the tokens */ + MemSize = EndParser->Pos - StartParser->Pos; + NewTokens = VariableAlloc(StartParser, MemSize + TOKEN_DATA_OFFSET, TRUE); + memcpy(NewTokens, (void *)StartParser->Pos, MemSize); + } + else + { + /* we're in interactive mode - add up line by line */ + for (InteractiveCurrentLine = InteractiveHead; InteractiveCurrentLine != NULL && (Pos < &InteractiveCurrentLine->Tokens[0] || Pos >= &InteractiveCurrentLine->Tokens[InteractiveCurrentLine->NumBytes]); InteractiveCurrentLine = InteractiveCurrentLine->Next) + {} /* find the line we just counted */ + + if (EndParser->Pos >= StartParser->Pos && EndParser->Pos < &InteractiveCurrentLine->Tokens[InteractiveCurrentLine->NumBytes]) + { + /* all on a single line */ + MemSize = EndParser->Pos - StartParser->Pos; + NewTokens = VariableAlloc(StartParser, MemSize + TOKEN_DATA_OFFSET, TRUE); + memcpy(NewTokens, (void *)StartParser->Pos, MemSize); + } + else + { + /* it's spread across multiple lines */ + MemSize = &InteractiveCurrentLine->Tokens[InteractiveCurrentLine->NumBytes-TOKEN_DATA_OFFSET] - Pos; + + for (ILine = InteractiveCurrentLine->Next; ILine != NULL && (EndParser->Pos < &ILine->Tokens[0] || EndParser->Pos >= &ILine->Tokens[ILine->NumBytes]); ILine = ILine->Next) + MemSize += ILine->NumBytes - TOKEN_DATA_OFFSET; + + assert(ILine != NULL); + MemSize += EndParser->Pos - &ILine->Tokens[0]; + NewTokens = VariableAlloc(StartParser, MemSize + TOKEN_DATA_OFFSET, TRUE); + + CopySize = &InteractiveCurrentLine->Tokens[InteractiveCurrentLine->NumBytes-TOKEN_DATA_OFFSET] - Pos; + memcpy(NewTokens, Pos, CopySize); + NewTokenPos = NewTokens + CopySize; + for (ILine = InteractiveCurrentLine->Next; ILine != NULL && (EndParser->Pos < &ILine->Tokens[0] || EndParser->Pos >= &ILine->Tokens[ILine->NumBytes]); ILine = ILine->Next) + { + memcpy(NewTokenPos, &ILine->Tokens[0], ILine->NumBytes - TOKEN_DATA_OFFSET); + NewTokenPos += ILine->NumBytes-TOKEN_DATA_OFFSET; + } + assert(ILine != NULL); + memcpy(NewTokenPos, &ILine->Tokens[0], EndParser->Pos - &ILine->Tokens[0]); + } + } + + NewTokens[MemSize] = (unsigned char)TokenEndOfFunction; + + return NewTokens; +} + +/* indicate that we've completed up to this point in the interactive input and free expired tokens */ +void LexInteractiveClear(struct ParseState *Parser) +{ + while (InteractiveHead != NULL) + { + struct TokenLine *NextLine = InteractiveHead->Next; + + HeapFreeMem(InteractiveHead->Tokens); + HeapFreeMem(InteractiveHead); + InteractiveHead = NextLine; + } + + if (Parser != NULL) + Parser->Pos = NULL; + InteractiveTail = NULL; +} + +/* indicate that we've completed up to this point in the interactive input and free expired tokens */ +void LexInteractiveCompleted(struct ParseState *Parser) +{ + while (InteractiveHead != NULL && !(Parser->Pos >= &InteractiveHead->Tokens[0] && Parser->Pos < &InteractiveHead->Tokens[InteractiveHead->NumBytes])) + { + /* this token line is no longer needed - free it */ + struct TokenLine *NextLine = InteractiveHead->Next; + + HeapFreeMem(InteractiveHead->Tokens); + HeapFreeMem(InteractiveHead); + InteractiveHead = NextLine; + + if (InteractiveHead == NULL) + { + /* we've emptied the list */ + Parser->Pos = NULL; + InteractiveTail = NULL; + } + } +} + +/* the next time we prompt, make it the full statement prompt */ +void LexInteractiveStatementPrompt() +{ + LexUseStatementPrompt = TRUE; +} diff --git a/src/cmd/picoc/msvc/picoc/picoc.sln b/src/cmd/picoc/msvc/picoc/picoc.sln new file mode 100644 index 0000000..e2be657 --- /dev/null +++ b/src/cmd/picoc/msvc/picoc/picoc.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 11 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "picoc", "picoc.vcxproj", "{C0156FB3-55AB-4F82-8A97-A776DFC57951}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {C0156FB3-55AB-4F82-8A97-A776DFC57951}.Debug|Win32.ActiveCfg = Debug|Win32 + {C0156FB3-55AB-4F82-8A97-A776DFC57951}.Debug|Win32.Build.0 = Debug|Win32 + {C0156FB3-55AB-4F82-8A97-A776DFC57951}.Release|Win32.ActiveCfg = Release|Win32 + {C0156FB3-55AB-4F82-8A97-A776DFC57951}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/src/cmd/picoc/msvc/picoc/picoc.vcxproj b/src/cmd/picoc/msvc/picoc/picoc.vcxproj new file mode 100644 index 0000000..63f24a0 --- /dev/null +++ b/src/cmd/picoc/msvc/picoc/picoc.vcxproj @@ -0,0 +1,111 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + $(VCTargetsPath11) + + + {C0156FB3-55AB-4F82-8A97-A776DFC57951} + Win32Proj + picoc + + + + Application + true + v110 + Unicode + + + Application + false + v110 + true + Unicode + + + + + + + + + + + + + true + + + false + + + + NotUsing + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + + + Console + true + + + + + Level3 + NotUsing + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + + + Console + true + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/cmd/picoc/msvc/picoc/picoc.vcxproj.filters b/src/cmd/picoc/msvc/picoc/picoc.vcxproj.filters new file mode 100644 index 0000000..77be70a --- /dev/null +++ b/src/cmd/picoc/msvc/picoc/picoc.vcxproj.filters @@ -0,0 +1,99 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + {9cc822ce-c7ed-4deb-93d2-ab0077cfe681} + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files\cstdlib + + + Source Files\cstdlib + + + Source Files\cstdlib + + + Source Files\cstdlib + + + Source Files\cstdlib + + + Source Files\cstdlib + + + Source Files\cstdlib + + + Source Files\cstdlib + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/src/cmd/picoc/parse.c b/src/cmd/picoc/parse.c new file mode 100644 index 0000000..6eefb0b --- /dev/null +++ b/src/cmd/picoc/parse.c @@ -0,0 +1,917 @@ +/* picoc parser - parses source and executes statements */ + +#include "picoc.h" +#include "interpreter.h" + +/* a chunk of heap-allocated tokens we'll cleanup when we're done */ +struct CleanupTokenNode +{ + void *Tokens; + const char *SourceText; + struct CleanupTokenNode *Next; +}; + +static struct CleanupTokenNode *CleanupTokenList = NULL; + + +/* deallocate any memory */ +void ParseCleanup() +{ + while (CleanupTokenList != NULL) + { + struct CleanupTokenNode *Next = CleanupTokenList->Next; + + HeapFreeMem(CleanupTokenList->Tokens); + if (CleanupTokenList->SourceText != NULL) + HeapFreeMem((void *)CleanupTokenList->SourceText); + + HeapFreeMem(CleanupTokenList); + CleanupTokenList = Next; + } +} + +/* parse a statement, but only run it if Condition is TRUE */ +enum ParseResult ParseStatementMaybeRun(struct ParseState *Parser, int Condition, int CheckTrailingSemicolon) +{ + if (Parser->Mode != RunModeSkip && !Condition) + { + enum RunMode OldMode = Parser->Mode; + int Result; + Parser->Mode = RunModeSkip; + Result = ParseStatement(Parser, CheckTrailingSemicolon); + Parser->Mode = OldMode; + return Result; + } + else + return ParseStatement(Parser, CheckTrailingSemicolon); +} + +/* count the number of parameters to a function or macro */ +int ParseCountParams(struct ParseState *Parser) +{ + int ParamCount = 0; + + enum LexToken Token = LexGetToken(Parser, NULL, TRUE); + if (Token != TokenCloseBracket && Token != TokenEOF) + { + /* count the number of parameters */ + ParamCount++; + while ((Token = LexGetToken(Parser, NULL, TRUE)) != TokenCloseBracket && Token != TokenEOF) + { + if (Token == TokenComma) + ParamCount++; + } + } + + return ParamCount; +} + +/* parse a function definition and store it for later */ +struct Value *ParseFunctionDefinition(struct ParseState *Parser, struct ValueType *ReturnType, char *Identifier) +{ + struct ValueType *ParamType; + char *ParamIdentifier; + enum LexToken Token = TokenNone; + struct ParseState ParamParser; + struct Value *FuncValue; + struct Value *OldFuncValue; + struct ParseState FuncBody; + int ParamCount = 0; + + if (TopStackFrame != NULL) + ProgramFail(Parser, "nested function definitions are not allowed"); + + LexGetToken(Parser, NULL, TRUE); /* open bracket */ + ParserCopy(&ParamParser, Parser); + ParamCount = ParseCountParams(Parser); + if (ParamCount > PARAMETER_MAX) + ProgramFail(Parser, "too many parameters"); + + FuncValue = VariableAllocValueAndData(Parser, sizeof(struct FuncDef) + sizeof(struct ValueType *) * ParamCount + sizeof(const char *) * ParamCount, FALSE, NULL, TRUE); + FuncValue->Typ = &FunctionType; + FuncValue->Val->FuncDef.ReturnType = ReturnType; + FuncValue->Val->FuncDef.NumParams = ParamCount; + FuncValue->Val->FuncDef.VarArgs = FALSE; + FuncValue->Val->FuncDef.ParamType = (struct ValueType **)((char *)FuncValue->Val + sizeof(struct FuncDef)); + FuncValue->Val->FuncDef.ParamName = (char **)((char *)FuncValue->Val->FuncDef.ParamType + sizeof(struct ValueType *) * ParamCount); + + for (ParamCount = 0; ParamCount < FuncValue->Val->FuncDef.NumParams; ParamCount++) + { + /* harvest the parameters into the function definition */ + if (ParamCount == FuncValue->Val->FuncDef.NumParams-1 && LexGetToken(&ParamParser, NULL, FALSE) == TokenEllipsis) + { + /* ellipsis at end */ + FuncValue->Val->FuncDef.NumParams--; + FuncValue->Val->FuncDef.VarArgs = TRUE; + break; + } + else + { + /* add a parameter */ + TypeParse(&ParamParser, &ParamType, &ParamIdentifier, NULL); + if (ParamType->Base == TypeVoid) + { + /* this isn't a real parameter at all - delete it */ + ParamCount--; + FuncValue->Val->FuncDef.NumParams--; + } + else + { + FuncValue->Val->FuncDef.ParamType[ParamCount] = ParamType; + FuncValue->Val->FuncDef.ParamName[ParamCount] = ParamIdentifier; + } + } + + Token = LexGetToken(&ParamParser, NULL, TRUE); + if (Token != TokenComma && ParamCount < FuncValue->Val->FuncDef.NumParams-1) + ProgramFail(&ParamParser, "comma expected"); + } + + if (FuncValue->Val->FuncDef.NumParams != 0 && Token != TokenCloseBracket && Token != TokenComma && Token != TokenEllipsis) + ProgramFail(&ParamParser, "bad parameter"); + + if (strcmp(Identifier, "main") == 0) + { + /* make sure it's int main() */ + if ( FuncValue->Val->FuncDef.ReturnType != &IntType && + FuncValue->Val->FuncDef.ReturnType != &VoidType ) + ProgramFail(Parser, "main() should return an int or void"); + + if (FuncValue->Val->FuncDef.NumParams != 0 && + (FuncValue->Val->FuncDef.NumParams != 2 || FuncValue->Val->FuncDef.ParamType[0] != &IntType) ) + ProgramFail(Parser, "bad parameters to main()"); + } + + /* look for a function body */ + Token = LexGetToken(Parser, NULL, FALSE); + if (Token == TokenSemicolon) + LexGetToken(Parser, NULL, TRUE); /* it's a prototype, absorb the trailing semicolon */ + else + { + /* it's a full function definition with a body */ + if (Token != TokenLeftBrace) + ProgramFail(Parser, "bad function definition"); + + ParserCopy(&FuncBody, Parser); + if (ParseStatementMaybeRun(Parser, FALSE, TRUE) != ParseResultOk) + ProgramFail(Parser, "function definition expected"); + + FuncValue->Val->FuncDef.Body = FuncBody; + FuncValue->Val->FuncDef.Body.Pos = LexCopyTokens(&FuncBody, Parser); + + /* is this function already in the global table? */ + if (TableGet(&GlobalTable, Identifier, &OldFuncValue, NULL, NULL, NULL)) + { + if (OldFuncValue->Val->FuncDef.Body.Pos == NULL) + { + /* override an old function prototype */ + VariableFree(TableDelete(&GlobalTable, Identifier)); + } + else + ProgramFail(Parser, "'%s' is already defined", Identifier); + } + } + + if (!TableSet(&GlobalTable, Identifier, FuncValue, (char *)Parser->FileName, Parser->Line, Parser->CharacterPos)) + ProgramFail(Parser, "'%s' is already defined", Identifier); + + return FuncValue; +} + +/* parse an array initialiser and assign to a variable */ +int ParseArrayInitialiser(struct ParseState *Parser, struct Value *NewVariable, int DoAssignment) +{ + int ArrayIndex = 0; + enum LexToken Token; + struct Value *CValue; + + /* count the number of elements in the array */ + if (DoAssignment && Parser->Mode == RunModeRun) + { + struct ParseState CountParser; + int NumElements; + + ParserCopy(&CountParser, Parser); + NumElements = ParseArrayInitialiser(&CountParser, NewVariable, FALSE); + if (NewVariable->Typ->ArraySize == 0) + VariableRealloc(Parser, NewVariable, NumElements); + + else if (NewVariable->Typ->ArraySize != NumElements) + AssignFail(Parser, "from an array of size %d to one of size %d", NULL, NULL, NumElements, NewVariable->Typ->ArraySize, NULL, 0); + } + + /* parse the array initialiser */ + Token = LexGetToken(Parser, NULL, FALSE); + while (Token != TokenRightBrace) + { + struct Value *ArrayElement = NULL; + + if (Parser->Mode == RunModeRun && DoAssignment) + ArrayElement = VariableAllocValueFromExistingData(Parser, NewVariable->Typ->FromType, (union AnyValue *)(&NewVariable->Val->ArrayMem[0] + TypeSize(NewVariable->Typ->FromType, 0, TRUE) * ArrayIndex), TRUE, NewVariable); + + if (!ExpressionParse(Parser, &CValue)) + ProgramFail(Parser, "expression expected"); + + if (Parser->Mode == RunModeRun && DoAssignment) + { + ExpressionAssign(Parser, ArrayElement, CValue, FALSE, NULL, 0, FALSE); + VariableStackPop(Parser, CValue); + VariableStackPop(Parser, ArrayElement); + } + + ArrayIndex++; + + Token = LexGetToken(Parser, NULL, FALSE); + if (Token == TokenComma) + { + LexGetToken(Parser, NULL, TRUE); + Token = LexGetToken(Parser, NULL, FALSE); + } + else if (Token != TokenRightBrace) + ProgramFail(Parser, "comma expected"); + } + + if (Token == TokenRightBrace) + LexGetToken(Parser, NULL, TRUE); + else + ProgramFail(Parser, "'}' expected"); + + return ArrayIndex; +} + +/* assign an initial value to a variable */ +void ParseDeclarationAssignment(struct ParseState *Parser, struct Value *NewVariable, int DoAssignment) +{ + struct Value *CValue; + + if (LexGetToken(Parser, NULL, FALSE) == TokenLeftBrace) + { + /* this is an array initialiser */ + LexGetToken(Parser, NULL, TRUE); + ParseArrayInitialiser(Parser, NewVariable, DoAssignment); + } + else + { + /* this is a normal expression initialiser */ + if (!ExpressionParse(Parser, &CValue)) + ProgramFail(Parser, "expression expected"); + + if (Parser->Mode == RunModeRun && DoAssignment) + { + ExpressionAssign(Parser, NewVariable, CValue, FALSE, NULL, 0, FALSE); + VariableStackPop(Parser, CValue); + } + } +} + +/* declare a variable or function */ +int ParseDeclaration(struct ParseState *Parser, enum LexToken Token) +{ + char *Identifier; + struct ValueType *BasicType; + struct ValueType *Typ; + struct Value *NewVariable = NULL; + int IsStatic = FALSE; + int FirstVisit = FALSE; + + TypeParseFront(Parser, &BasicType, &IsStatic); + do + { + TypeParseIdentPart(Parser, BasicType, &Typ, &Identifier); + if ((Token != TokenVoidType && Token != TokenStructType && Token != TokenUnionType && Token != TokenEnumType) && Identifier == StrEmpty) + ProgramFail(Parser, "identifier expected"); + + if (Identifier != StrEmpty) + { + /* handle function definitions */ + if (LexGetToken(Parser, NULL, FALSE) == TokenOpenBracket) + { + ParseFunctionDefinition(Parser, Typ, Identifier); + return FALSE; + } + else + { + if (Typ == &VoidType && Identifier != StrEmpty) + ProgramFail(Parser, "can't define a void variable"); + + if (Parser->Mode == RunModeRun || Parser->Mode == RunModeGoto) + NewVariable = VariableDefineButIgnoreIdentical(Parser, Identifier, Typ, IsStatic, &FirstVisit); + + if (LexGetToken(Parser, NULL, FALSE) == TokenAssign) + { + /* we're assigning an initial value */ + LexGetToken(Parser, NULL, TRUE); + ParseDeclarationAssignment(Parser, NewVariable, !IsStatic || FirstVisit); + } + } + } + + Token = LexGetToken(Parser, NULL, FALSE); + if (Token == TokenComma) + LexGetToken(Parser, NULL, TRUE); + + } while (Token == TokenComma); + + return TRUE; +} + +/* parse a #define macro definition and store it for later */ +void ParseMacroDefinition(struct ParseState *Parser) +{ + struct Value *MacroName; + char *MacroNameStr; + struct Value *ParamName; + struct Value *MacroValue; + + if (LexGetToken(Parser, &MacroName, TRUE) != TokenIdentifier) + ProgramFail(Parser, "identifier expected"); + + MacroNameStr = MacroName->Val->Identifier; + + if (LexRawPeekToken(Parser) == TokenOpenMacroBracket) + { + /* it's a parameterised macro, read the parameters */ + enum LexToken Token = LexGetToken(Parser, NULL, TRUE); + struct ParseState ParamParser; + int NumParams; + int ParamCount = 0; + + ParserCopy(&ParamParser, Parser); + NumParams = ParseCountParams(&ParamParser); + MacroValue = VariableAllocValueAndData(Parser, sizeof(struct MacroDef) + sizeof(const char *) * NumParams, FALSE, NULL, TRUE); + MacroValue->Val->MacroDef.NumParams = NumParams; + MacroValue->Val->MacroDef.ParamName = (char **)((char *)MacroValue->Val + sizeof(struct MacroDef)); + + Token = LexGetToken(Parser, &ParamName, TRUE); + + while (Token == TokenIdentifier) + { + /* store a parameter name */ + MacroValue->Val->MacroDef.ParamName[ParamCount++] = ParamName->Val->Identifier; + + /* get the trailing comma */ + Token = LexGetToken(Parser, NULL, TRUE); + if (Token == TokenComma) + Token = LexGetToken(Parser, &ParamName, TRUE); + + else if (Token != TokenCloseBracket) + ProgramFail(Parser, "comma expected"); + } + + if (Token != TokenCloseBracket) + ProgramFail(Parser, "close bracket expected"); + } + else + { + /* allocate a simple unparameterised macro */ + MacroValue = VariableAllocValueAndData(Parser, sizeof(struct MacroDef), FALSE, NULL, TRUE); + MacroValue->Val->MacroDef.NumParams = 0; + } + + /* copy the body of the macro to execute later */ + ParserCopy(&MacroValue->Val->MacroDef.Body, Parser); + MacroValue->Typ = &MacroType; + LexToEndOfLine(Parser); + MacroValue->Val->MacroDef.Body.Pos = LexCopyTokens(&MacroValue->Val->MacroDef.Body, Parser); + + if (!TableSet(&GlobalTable, MacroNameStr, MacroValue, (char *)Parser->FileName, Parser->Line, Parser->CharacterPos)) + ProgramFail(Parser, "'%s' is already defined", MacroNameStr); +} + +/* copy the entire parser state */ +void ParserCopy(struct ParseState *To, struct ParseState *From) +{ + memcpy((void *)To, (void *)From, sizeof(*To)); +} + +/* copy where we're at in the parsing */ +void ParserCopyPos(struct ParseState *To, struct ParseState *From) +{ + To->Pos = From->Pos; + To->Line = From->Line; + To->HashIfLevel = From->HashIfLevel; + To->HashIfEvaluateToLevel = From->HashIfEvaluateToLevel; + To->CharacterPos = From->CharacterPos; +} + +/* parse a "for" statement */ +void ParseFor(struct ParseState *Parser) +{ + int Condition; + struct ParseState PreConditional; + struct ParseState PreIncrement; + struct ParseState PreStatement; + struct ParseState After; + + if (LexGetToken(Parser, NULL, TRUE) != TokenOpenBracket) + ProgramFail(Parser, "'(' expected"); + + if (ParseStatement(Parser, TRUE) != ParseResultOk) + ProgramFail(Parser, "statement expected"); + + ParserCopyPos(&PreConditional, Parser); + if (LexGetToken(Parser, NULL, FALSE) == TokenSemicolon) + Condition = TRUE; + else + Condition = ExpressionParseInt(Parser); + + if (LexGetToken(Parser, NULL, TRUE) != TokenSemicolon) + ProgramFail(Parser, "';' expected"); + + ParserCopyPos(&PreIncrement, Parser); + ParseStatementMaybeRun(Parser, FALSE, FALSE); + + if (LexGetToken(Parser, NULL, TRUE) != TokenCloseBracket) + ProgramFail(Parser, "')' expected"); + + ParserCopyPos(&PreStatement, Parser); + if (ParseStatementMaybeRun(Parser, Condition, TRUE) != ParseResultOk) + ProgramFail(Parser, "statement expected"); + + if (Parser->Mode == RunModeContinue) + Parser->Mode = RunModeRun; + + ParserCopyPos(&After, Parser); + + while (Condition && Parser->Mode == RunModeRun) + { + ParserCopyPos(Parser, &PreIncrement); + ParseStatement(Parser, FALSE); + + ParserCopyPos(Parser, &PreConditional); + if (LexGetToken(Parser, NULL, FALSE) == TokenSemicolon) + Condition = TRUE; + else + Condition = ExpressionParseInt(Parser); + + if (Condition) + { + ParserCopyPos(Parser, &PreStatement); + ParseStatement(Parser, TRUE); + + if (Parser->Mode == RunModeContinue) + Parser->Mode = RunModeRun; + } + } + + if (Parser->Mode == RunModeBreak) + Parser->Mode = RunModeRun; + + ParserCopyPos(Parser, &After); +} + +/* parse a block of code and return what mode it returned in */ +enum RunMode ParseBlock(struct ParseState *Parser, int AbsorbOpenBrace, int Condition) +{ + if (AbsorbOpenBrace && LexGetToken(Parser, NULL, TRUE) != TokenLeftBrace) + ProgramFail(Parser, "'{' expected"); + + if (Parser->Mode == RunModeSkip || !Condition) + { + /* condition failed - skip this block instead */ + enum RunMode OldMode = Parser->Mode; + Parser->Mode = RunModeSkip; + while (ParseStatement(Parser, TRUE) == ParseResultOk) + {} + Parser->Mode = OldMode; + } + else + { + /* just run it in its current mode */ + while (ParseStatement(Parser, TRUE) == ParseResultOk) + {} + } + + if (LexGetToken(Parser, NULL, TRUE) != TokenRightBrace) + ProgramFail(Parser, "'}' expected"); + + return Parser->Mode; +} + +/* parse a typedef declaration */ +void ParseTypedef(struct ParseState *Parser) +{ + struct ValueType *Typ; + struct ValueType **TypPtr; + char *TypeName; + struct Value InitValue; + + TypeParse(Parser, &Typ, &TypeName, NULL); + + if (Parser->Mode == RunModeRun) + { + TypPtr = &Typ; + InitValue.Typ = &TypeType; + InitValue.Val = (union AnyValue *)TypPtr; + VariableDefine(Parser, TypeName, &InitValue, NULL, FALSE); + } +} + +/* parse a statement */ +enum ParseResult ParseStatement(struct ParseState *Parser, int CheckTrailingSemicolon) +{ + struct Value *CValue; + struct Value *LexerValue; + struct Value *VarValue; + int Condition; + struct ParseState PreState; + enum LexToken Token; + + /* if we're debugging, check for a breakpoint */ + if (Parser->DebugMode && Parser->Mode == RunModeRun) + DebugCheckStatement(Parser); + + /* take note of where we are and then grab a token to see what statement we have */ + ParserCopy(&PreState, Parser); + Token = LexGetToken(Parser, &LexerValue, TRUE); + + switch (Token) + { + case TokenEOF: + return ParseResultEOF; + + case TokenIdentifier: + /* might be a typedef-typed variable declaration or it might be an expression */ + if (VariableDefined(LexerValue->Val->Identifier)) + { + VariableGet(Parser, LexerValue->Val->Identifier, &VarValue); + if (VarValue->Typ->Base == Type_Type) + { + *Parser = PreState; + ParseDeclaration(Parser, Token); + break; + } + } + else + { + /* it might be a goto label */ + enum LexToken NextToken = LexGetToken(Parser, NULL, FALSE); + if (NextToken == TokenColon) + { + /* declare the identifier as a goto label */ + LexGetToken(Parser, NULL, TRUE); + if (Parser->Mode == RunModeGoto && LexerValue->Val->Identifier == Parser->SearchGotoLabel) + Parser->Mode = RunModeRun; + + CheckTrailingSemicolon = FALSE; + break; + } + } + /* else fallthrough to expression */ + + case TokenAsterisk: + case TokenAmpersand: + case TokenIncrement: + case TokenDecrement: + case TokenOpenBracket: + *Parser = PreState; + ExpressionParse(Parser, &CValue); + if (Parser->Mode == RunModeRun) + VariableStackPop(Parser, CValue); + break; + + case TokenLeftBrace: + ParseBlock(Parser, FALSE, TRUE); + CheckTrailingSemicolon = FALSE; + break; + + case TokenIf: + if (LexGetToken(Parser, NULL, TRUE) != TokenOpenBracket) + ProgramFail(Parser, "'(' expected"); + + Condition = ExpressionParseInt(Parser); + + if (LexGetToken(Parser, NULL, TRUE) != TokenCloseBracket) + ProgramFail(Parser, "')' expected"); + + if (ParseStatementMaybeRun(Parser, Condition, TRUE) != ParseResultOk) + ProgramFail(Parser, "statement expected"); + + if (LexGetToken(Parser, NULL, FALSE) == TokenElse) + { + LexGetToken(Parser, NULL, TRUE); + if (ParseStatementMaybeRun(Parser, !Condition, TRUE) != ParseResultOk) + ProgramFail(Parser, "statement expected"); + } + CheckTrailingSemicolon = FALSE; + break; + + case TokenWhile: + { + struct ParseState PreConditional; + enum RunMode PreMode = Parser->Mode; + + if (LexGetToken(Parser, NULL, TRUE) != TokenOpenBracket) + ProgramFail(Parser, "'(' expected"); + + ParserCopyPos(&PreConditional, Parser); + do + { + ParserCopyPos(Parser, &PreConditional); + Condition = ExpressionParseInt(Parser); + if (LexGetToken(Parser, NULL, TRUE) != TokenCloseBracket) + ProgramFail(Parser, "')' expected"); + + if (ParseStatementMaybeRun(Parser, Condition, TRUE) != ParseResultOk) + ProgramFail(Parser, "statement expected"); + + if (Parser->Mode == RunModeContinue) + Parser->Mode = PreMode; + + } while (Parser->Mode == RunModeRun && Condition); + + if (Parser->Mode == RunModeBreak) + Parser->Mode = PreMode; + + CheckTrailingSemicolon = FALSE; + } + break; + + case TokenDo: + { + struct ParseState PreStatement; + enum RunMode PreMode = Parser->Mode; + ParserCopyPos(&PreStatement, Parser); + do + { + ParserCopyPos(Parser, &PreStatement); + if (ParseStatement(Parser, TRUE) != ParseResultOk) + ProgramFail(Parser, "statement expected"); + + if (Parser->Mode == RunModeContinue) + Parser->Mode = PreMode; + + if (LexGetToken(Parser, NULL, TRUE) != TokenWhile) + ProgramFail(Parser, "'while' expected"); + + if (LexGetToken(Parser, NULL, TRUE) != TokenOpenBracket) + ProgramFail(Parser, "'(' expected"); + + Condition = ExpressionParseInt(Parser); + if (LexGetToken(Parser, NULL, TRUE) != TokenCloseBracket) + ProgramFail(Parser, "')' expected"); + + } while (Condition && Parser->Mode == RunModeRun); + + if (Parser->Mode == RunModeBreak) + Parser->Mode = PreMode; + } + break; + + case TokenFor: + ParseFor(Parser); + CheckTrailingSemicolon = FALSE; + break; + + case TokenSemicolon: + CheckTrailingSemicolon = FALSE; + break; + + case TokenIntType: + case TokenShortType: + case TokenCharType: + case TokenLongType: + case TokenFloatType: + case TokenDoubleType: + case TokenVoidType: + case TokenStructType: + case TokenUnionType: + case TokenEnumType: + case TokenSignedType: + case TokenUnsignedType: + case TokenStaticType: + case TokenAutoType: + case TokenRegisterType: + case TokenExternType: + *Parser = PreState; + CheckTrailingSemicolon = ParseDeclaration(Parser, Token); + break; + + case TokenHashDefine: + ParseMacroDefinition(Parser); + CheckTrailingSemicolon = FALSE; + break; + +#ifndef NO_HASH_INCLUDE + case TokenHashInclude: + if (LexGetToken(Parser, &LexerValue, TRUE) != TokenStringConstant) + ProgramFail(Parser, "\"filename.h\" expected"); + + IncludeFile((char *)LexerValue->Val->Pointer); + CheckTrailingSemicolon = FALSE; + break; +#endif + + case TokenSwitch: + if (LexGetToken(Parser, NULL, TRUE) != TokenOpenBracket) + ProgramFail(Parser, "'(' expected"); + + Condition = ExpressionParseInt(Parser); + + if (LexGetToken(Parser, NULL, TRUE) != TokenCloseBracket) + ProgramFail(Parser, "')' expected"); + + if (LexGetToken(Parser, NULL, FALSE) != TokenLeftBrace) + ProgramFail(Parser, "'{' expected"); + + { + /* new block so we can store parser state */ + enum RunMode OldMode = Parser->Mode; + int OldSearchLabel = Parser->SearchLabel; + Parser->Mode = RunModeCaseSearch; + Parser->SearchLabel = Condition; + + ParseBlock(Parser, TRUE, OldMode != RunModeSkip); + + if (Parser->Mode != RunModeReturn) + Parser->Mode = OldMode; + + Parser->SearchLabel = OldSearchLabel; + } + + CheckTrailingSemicolon = FALSE; + break; + + case TokenCase: + if (Parser->Mode == RunModeCaseSearch) + { + Parser->Mode = RunModeRun; + Condition = ExpressionParseInt(Parser); + Parser->Mode = RunModeCaseSearch; + } + else + Condition = ExpressionParseInt(Parser); + + if (LexGetToken(Parser, NULL, TRUE) != TokenColon) + ProgramFail(Parser, "':' expected"); + + if (Parser->Mode == RunModeCaseSearch && Condition == Parser->SearchLabel) + Parser->Mode = RunModeRun; + + CheckTrailingSemicolon = FALSE; + break; + + case TokenDefault: + if (LexGetToken(Parser, NULL, TRUE) != TokenColon) + ProgramFail(Parser, "':' expected"); + + if (Parser->Mode == RunModeCaseSearch) + Parser->Mode = RunModeRun; + + CheckTrailingSemicolon = FALSE; + break; + + case TokenBreak: + if (Parser->Mode == RunModeRun) + Parser->Mode = RunModeBreak; + break; + + case TokenContinue: + if (Parser->Mode == RunModeRun) + Parser->Mode = RunModeContinue; + break; + + case TokenReturn: + if (Parser->Mode == RunModeRun) + { + if (TopStackFrame->ReturnValue->Typ->Base != TypeVoid) + { + if (!ExpressionParse(Parser, &CValue)) + ProgramFail(Parser, "value required in return"); + + ExpressionAssign(Parser, TopStackFrame->ReturnValue, CValue, TRUE, NULL, 0, FALSE); + VariableStackPop(Parser, CValue); + } + else + { + if (ExpressionParse(Parser, &CValue)) + ProgramFail(Parser, "value in return from a void function"); + } + + Parser->Mode = RunModeReturn; + } + else + ExpressionParse(Parser, &CValue); + break; + + case TokenTypedef: + ParseTypedef(Parser); + break; + + case TokenGoto: + if (LexGetToken(Parser, &LexerValue, TRUE) != TokenIdentifier) + ProgramFail(Parser, "identifier expected"); + + if (Parser->Mode == RunModeRun) + { + /* start scanning for the goto label */ + Parser->SearchGotoLabel = LexerValue->Val->Identifier; + Parser->Mode = RunModeGoto; + } + break; + + case TokenDelete: + { + /* try it as a function or variable name to delete */ + if (LexGetToken(Parser, &LexerValue, TRUE) != TokenIdentifier) + ProgramFail(Parser, "identifier expected"); + + if (Parser->Mode == RunModeRun) + { + /* delete this variable or function */ + CValue = TableDelete(&GlobalTable, LexerValue->Val->Identifier); + + if (CValue == NULL) + ProgramFail(Parser, "'%s' is not defined", LexerValue->Val->Identifier); + + VariableFree(CValue); + } + break; + } + + default: + *Parser = PreState; + return ParseResultError; + } + + if (CheckTrailingSemicolon) + { + if (LexGetToken(Parser, NULL, TRUE) != TokenSemicolon) + ProgramFail(Parser, "';' expected"); + } + + return ParseResultOk; +} + +/* quick scan a source file for definitions */ +void PicocParse(const char *FileName, const char *Source, int SourceLen, int RunIt, int CleanupNow, int CleanupSource, int EnableDebugger) +{ + struct ParseState Parser; + enum ParseResult Ok; + struct CleanupTokenNode *NewCleanupNode; + char *RegFileName = TableStrRegister(FileName); + + void *Tokens = LexAnalyse(RegFileName, Source, SourceLen, NULL); + + /* allocate a cleanup node so we can clean up the tokens later */ + if (!CleanupNow) + { + NewCleanupNode = HeapAllocMem(sizeof(struct CleanupTokenNode)); + if (NewCleanupNode == NULL) + ProgramFail(NULL, "out of memory"); + + NewCleanupNode->Tokens = Tokens; + if (CleanupSource) + NewCleanupNode->SourceText = Source; + else + NewCleanupNode->SourceText = NULL; + + NewCleanupNode->Next = CleanupTokenList; + CleanupTokenList = NewCleanupNode; + } + + /* do the parsing */ + LexInitParser(&Parser, Source, Tokens, RegFileName, RunIt, EnableDebugger); + + do { + Ok = ParseStatement(&Parser, TRUE); + } while (Ok == ParseResultOk); + + if (Ok == ParseResultError) + ProgramFail(&Parser, "parse error"); + + /* clean up */ + if (CleanupNow) + HeapFreeMem(Tokens); +} + +/* parse interactively */ +void PicocParseInteractiveNoStartPrompt(int EnableDebugger) +{ + struct ParseState Parser; + enum ParseResult Ok; + + LexInitParser(&Parser, NULL, NULL, StrEmpty, TRUE, EnableDebugger); + PicocPlatformSetExitPoint(); + LexInteractiveClear(&Parser); + + do + { + LexInteractiveStatementPrompt(); + Ok = ParseStatement(&Parser, TRUE); + LexInteractiveCompleted(&Parser); + + } while (Ok == ParseResultOk); + + if (Ok == ParseResultError) + ProgramFail(&Parser, "parse error"); + + PlatformPrintf("\n"); +} + +/* parse interactively, showing a startup message */ +void PicocParseInteractive() +{ + PlatformPrintf(INTERACTIVE_PROMPT_START); + PicocParseInteractiveNoStartPrompt(TRUE); +} diff --git a/src/cmd/picoc/picoc.c b/src/cmd/picoc/picoc.c new file mode 100644 index 0000000..1f98eec --- /dev/null +++ b/src/cmd/picoc/picoc.c @@ -0,0 +1,104 @@ +/* picoc main program - this varies depending on your operating system and + * how you're using picoc */ + +/* include only picoc.h here - should be able to use it with only the external interfaces, no internals from interpreter.h */ +#include "picoc.h" + +/* platform-dependent code for running programs is in this file */ + +#if defined(UNIX_HOST) || defined(WIN32) +#include +#include +#include + +#define PICOC_STACK_SIZE (128*1024) /* space for the the stack */ + +int main(int argc, char **argv) +{ + int ParamCount = 1; + int DontRunMain = FALSE; + int StackSize = getenv("STACKSIZE") ? atoi(getenv("STACKSIZE")) : PICOC_STACK_SIZE; + + if (argc < 2) + { + printf("Format: picoc ... [- ...] : run a program (calls main() to start it)\n" + " picoc -s ... [- ...] : script mode - runs the program without calling main()\n" + " picoc -i : interactive mode\n"); + exit(1); + } + + PicocInitialise(StackSize); + + if (strcmp(argv[ParamCount], "-s") == 0 || strcmp(argv[ParamCount], "-m") == 0) + { + DontRunMain = TRUE; + PicocIncludeAllSystemHeaders(); + ParamCount++; + } + + if (argc > ParamCount && strcmp(argv[ParamCount], "-i") == 0) + { + PicocIncludeAllSystemHeaders(); + PicocParseInteractive(TRUE); + } + else + { + if (PicocPlatformSetExitPoint()) + { + PicocCleanup(); + return PicocExitValue; + } + + for (; ParamCount < argc && strcmp(argv[ParamCount], "-") != 0; ParamCount++) + PicocPlatformScanFile(argv[ParamCount]); + + if (!DontRunMain) + PicocCallMain(argc - ParamCount, &argv[ParamCount]); + } + + PicocCleanup(); + return PicocExitValue; +} +#else +# ifdef SURVEYOR_HOST +# define HEAP_SIZE C_HEAPSIZE +# include +# include "../srv.h" +# include "../print.h" +# include "../string.h" + +int picoc(char *SourceStr) +{ + char *pos; + + PicocInitialise(HEAP_SIZE); + + if (SourceStr) + { + for (pos = SourceStr; *pos != 0; pos++) + { + if (*pos == 0x1a) + { + *pos = 0x20; + } + } + } + + PicocExitBuf[40] = 0; + PicocPlatformSetExitPoint(); + if (PicocExitBuf[40]) { + printf("Leaving PicoC\n\r"); + PicocCleanup(); + return PicocExitValue; + } + + if (SourceStr) + PicocParse("nofile", SourceStr, strlen(SourceStr), TRUE, TRUE, FALSE); + + PicocParseInteractive(); + PicocCleanup(); + + return PicocExitValue; +} +# endif +#endif diff --git a/src/cmd/picoc/picoc.h b/src/cmd/picoc/picoc.h new file mode 100644 index 0000000..ab95985 --- /dev/null +++ b/src/cmd/picoc/picoc.h @@ -0,0 +1,52 @@ +/* picoc external interface. This should be the only header you need to use if + * you're using picoc as a library. Internal details are in interpreter.h */ +#ifndef PICOC_H +#define PICOC_H + +/* picoc version number */ +#ifdef VER +#define PICOC_VERSION "v2.2 beta r" VER /* VER is the subversion version number, obtained via the Makefile */ +#else +#define PICOC_VERSION "v2.2" +#endif + +/* handy definitions */ +#ifndef TRUE +#define TRUE 1 +#define FALSE 0 +#endif + + +#if defined(UNIX_HOST) || defined(WIN32) +#include + +/* mark where to end the program for platforms which require this */ +extern jmp_buf PicocExitBuf; + +/* this has to be a macro, otherwise errors will occur due to the stack being corrupt */ +#define PicocPlatformSetExitPoint() setjmp(PicocExitBuf) +#endif + +#ifdef SURVEYOR_HOST +/* mark where to end the program for platforms which require this */ +extern int PicocExitBuf[]; + +#define PicocPlatformSetExitPoint() setjmp(PicocExitBuf) +#endif + +/* parse.c */ +void PicocParse(const char *FileName, const char *Source, int SourceLen, int RunIt, int CleanupNow, int CleanupSource, int EnableDebugger); +void PicocParseInteractive(); + +/* platform.c */ +void PicocCallMain(int argc, char **argv); +void PicocInitialise(int StackSize); +void PicocCleanup(); +void PicocPlatformScanFile(const char *FileName); + +extern int PicocExitValue; + +/* include.c */ +void PicocIncludeAllSystemHeaders(); + +#endif /* PICOC_H */ diff --git a/src/cmd/picoc/platform.c b/src/cmd/picoc/platform.c new file mode 100644 index 0000000..1a83168 --- /dev/null +++ b/src/cmd/picoc/platform.c @@ -0,0 +1,242 @@ +/* picoc's interface to the underlying platform. most platform-specific code + * is in platform/platform_XX.c and platform/library_XX.c */ + +#include "picoc.h" +#include "interpreter.h" + +/* the value passed to exit() */ +int PicocExitValue = 0; + +/* initialise everything */ +void PicocInitialise(int StackSize) +{ + PlatformInit(); + BasicIOInit(); + HeapInit(StackSize); + TableInit(); + VariableInit(); + LexInit(); + TypeInit(); +#ifndef NO_HASH_INCLUDE + IncludeInit(); +#endif + LibraryInit(); +#ifdef BUILTIN_MINI_STDLIB + LibraryAdd(&GlobalTable, "c library", &CLibrary[0]); + CLibraryInit(); +#endif + PlatformLibraryInit(); + DebugInit(); +} + +/* free memory */ +void PicocCleanup() +{ + DebugCleanup(); +#ifndef NO_HASH_INCLUDE + IncludeCleanup(); +#endif + ParseCleanup(); + LexCleanup(); + VariableCleanup(); + TypeCleanup(); + TableStrFree(); + HeapCleanup(); + PlatformCleanup(); +} + +/* platform-dependent code for running programs */ +#if defined(UNIX_HOST) || defined(WIN32) + +#define CALL_MAIN_NO_ARGS_RETURN_VOID "main();" +#define CALL_MAIN_WITH_ARGS_RETURN_VOID "main(__argc,__argv);" +#define CALL_MAIN_NO_ARGS_RETURN_INT "__exit_value = main();" +#define CALL_MAIN_WITH_ARGS_RETURN_INT "__exit_value = main(__argc,__argv);" + +void PicocCallMain(int argc, char **argv) +{ + /* check if the program wants arguments */ + struct Value *FuncValue = NULL; + + if (!VariableDefined(TableStrRegister("main"))) + ProgramFail(NULL, "main() is not defined"); + + VariableGet(NULL, TableStrRegister("main"), &FuncValue); + if (FuncValue->Typ->Base != TypeFunction) + ProgramFail(NULL, "main is not a function - can't call it"); + + if (FuncValue->Val->FuncDef.NumParams != 0) + { + /* define the arguments */ + VariableDefinePlatformVar(NULL, "__argc", &IntType, (union AnyValue *)&argc, FALSE); + VariableDefinePlatformVar(NULL, "__argv", CharPtrPtrType, (union AnyValue *)&argv, FALSE); + } + + if (FuncValue->Val->FuncDef.ReturnType == &VoidType) + { + if (FuncValue->Val->FuncDef.NumParams == 0) + PicocParse("startup", CALL_MAIN_NO_ARGS_RETURN_VOID, strlen(CALL_MAIN_NO_ARGS_RETURN_VOID), TRUE, TRUE, FALSE, TRUE); + else + PicocParse("startup", CALL_MAIN_WITH_ARGS_RETURN_VOID, strlen(CALL_MAIN_WITH_ARGS_RETURN_VOID), TRUE, TRUE, FALSE, TRUE); + } + else + { + VariableDefinePlatformVar(NULL, "__exit_value", &IntType, (union AnyValue *)&PicocExitValue, TRUE); + + if (FuncValue->Val->FuncDef.NumParams == 0) + PicocParse("startup", CALL_MAIN_NO_ARGS_RETURN_INT, strlen(CALL_MAIN_NO_ARGS_RETURN_INT), TRUE, TRUE, FALSE, TRUE); + else + PicocParse("startup", CALL_MAIN_WITH_ARGS_RETURN_INT, strlen(CALL_MAIN_WITH_ARGS_RETURN_INT), TRUE, TRUE, FALSE, TRUE); + } +} +#endif + +void PrintSourceTextErrorLine(const char *FileName, const char *SourceText, int Line, int CharacterPos) +{ + int LineCount; + const char *LinePos; + const char *CPos; + int CCount; + + if (SourceText != NULL) + { + /* find the source line */ + for (LinePos = SourceText, LineCount = 1; *LinePos != '\0' && LineCount < Line; LinePos++) + { + if (*LinePos == '\n') + LineCount++; + } + + /* display the line */ + for (CPos = LinePos; *CPos != '\n' && *CPos != '\0'; CPos++) + PrintCh(*CPos, CStdOut); + PrintCh('\n', CStdOut); + + /* display the error position */ + for (CPos = LinePos, CCount = 0; *CPos != '\n' && *CPos != '\0' && (CCount < CharacterPos || *CPos == ' '); CPos++, CCount++) + { + if (*CPos == '\t') + PrintCh('\t', CStdOut); + else + PrintCh(' ', CStdOut); + } + } + else + { + /* assume we're in interactive mode - try to make the arrow match up with the input text */ + for (CCount = 0; CCount < CharacterPos + (int)strlen(INTERACTIVE_PROMPT_STATEMENT); CCount++) + PrintCh(' ', CStdOut); + } + PlatformPrintf("^\n%s:%d: ", FileName, Line, CharacterPos); + +} + +/* display the source line and line number to identify an error */ +void PlatformErrorPrefix(struct ParseState *Parser) +{ + if (Parser != NULL) + PrintSourceTextErrorLine(Parser->FileName, Parser->SourceText, Parser->Line, Parser->CharacterPos); +} + +/* exit with a message */ +void ProgramFail(struct ParseState *Parser, const char *Message, ...) +{ + va_list Args; + + PlatformErrorPrefix(Parser); + va_start(Args, Message); + PlatformVPrintf(Message, Args); + va_end(Args); + PlatformPrintf("\n"); + PlatformExit(1); +} + +/* like ProgramFail() but gives descriptive error messages for assignment */ +void AssignFail(struct ParseState *Parser, const char *Format, struct ValueType *Type1, struct ValueType *Type2, int Num1, int Num2, const char *FuncName, int ParamNo) +{ + PlatformErrorPrefix(Parser); + PlatformPrintf("can't %s ", (FuncName == NULL) ? "assign" : "set"); + + if (Type1 != NULL) + PlatformPrintf(Format, Type1, Type2); + else + PlatformPrintf(Format, Num1, Num2); + + if (FuncName != NULL) + PlatformPrintf(" in argument %d of call to %s()", ParamNo, FuncName); + + ProgramFail(NULL, ""); +} + +/* exit lexing with a message */ +void LexFail(struct LexState *Lexer, const char *Message, ...) +{ + va_list Args; + + PrintSourceTextErrorLine(Lexer->FileName, Lexer->SourceText, Lexer->Line, Lexer->CharacterPos); + va_start(Args, Message); + PlatformVPrintf(Message, Args); + va_end(Args); + PlatformPrintf("\n"); + PlatformExit(1); +} + +/* printf for compiler error reporting */ +void PlatformPrintf(const char *Format, ...) +{ + va_list Args; + + va_start(Args, Format); + PlatformVPrintf(Format, Args); + va_end(Args); +} + +void PlatformVPrintf(const char *Format, va_list Args) +{ + const char *FPos; + + for (FPos = Format; *FPos != '\0'; FPos++) + { + if (*FPos == '%') + { + FPos++; + switch (*FPos) + { + case 's': PrintStr(va_arg(Args, char *), CStdOut); break; + case 'd': PrintSimpleInt(va_arg(Args, int), CStdOut); break; + case 'c': PrintCh(va_arg(Args, int), CStdOut); break; + case 't': PrintType(va_arg(Args, struct ValueType *), CStdOut); break; +#ifndef NO_FP + case 'f': PrintFP(va_arg(Args, double), CStdOut); break; +#endif + case '%': PrintCh('%', CStdOut); break; + case '\0': FPos--; break; + } + } + else + PrintCh(*FPos, CStdOut); + } +} + +/* make a new temporary name. takes a static buffer of char [7] as a parameter. should be initialised to "XX0000" + * where XX can be any characters */ +char *PlatformMakeTempName(char *TempNameBuffer) +{ + int CPos = 5; + + while (CPos > 1) + { + if (TempNameBuffer[CPos] < '9') + { + TempNameBuffer[CPos]++; + return TableStrRegister(TempNameBuffer); + } + else + { + TempNameBuffer[CPos] = '0'; + CPos--; + } + } + + return TableStrRegister(TempNameBuffer); +} diff --git a/src/cmd/picoc/platform.h b/src/cmd/picoc/platform.h new file mode 100644 index 0000000..2709bac --- /dev/null +++ b/src/cmd/picoc/platform.h @@ -0,0 +1,148 @@ +/* all platform-specific includes and defines go in this file */ +#ifndef PLATFORM_H +#define PLATFORM_H + + +/* configurable options */ +/* select your host type (or do it in the Makefile): + * #define UNIX_HOST + * #define FLYINGFOX_HOST + * #define SURVEYOR_HOST + * #define SRV1_UNIX_HOST + * #define UMON_HOST + * #define WIN32 (predefined on MSVC) + */ + +#define LARGE_INT_POWER_OF_TEN 1000000000 /* the largest power of ten which fits in an int on this architecture */ +#if defined(__hppa__) || defined(__sparc__) +#define ALIGN_TYPE double /* the default data type to use for alignment */ +#else +#define ALIGN_TYPE void * /* the default data type to use for alignment */ +#endif + +#define GLOBAL_TABLE_SIZE 97 /* global variable table */ +#define STRING_TABLE_SIZE 97 /* shared string table size */ +#define STRING_LITERAL_TABLE_SIZE 97 /* string literal table size */ +#define PARAMETER_MAX 16 /* maximum number of parameters to a function */ +#define LINEBUFFER_MAX 256 /* maximum number of characters on a line */ +#define LOCAL_TABLE_SIZE 11 /* size of local variable table (can expand) */ +#define STRUCT_TABLE_SIZE 11 /* size of struct/union member table (can expand) */ + +#define INTERACTIVE_PROMPT_START "starting picoc " PICOC_VERSION "\n" +#define INTERACTIVE_PROMPT_STATEMENT "picoc> " +#define INTERACTIVE_PROMPT_LINE " > " + +/* host platform includes */ +#ifdef UNIX_HOST +# define USE_MALLOC_STACK /* stack is allocated using malloc() */ +# define USE_MALLOC_HEAP /* heap is allocated using malloc() */ +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# ifndef NO_FP +# include +# define PICOC_MATH_LIBRARY +//# define USE_READLINE +# undef BIG_ENDIAN +# if defined(__powerpc__) || defined(__hppa__) || defined(__sparc__) +# define BIG_ENDIAN +# endif +# endif + +extern jmp_buf ExitBuf; + +#else +# ifdef WIN32 +# define USE_MALLOC_STACK /* stack is allocated using malloc() */ +# define USE_MALLOC_HEAP /* heap is allocated using malloc() */ +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# define PICOC_MATH_LIBRARY +# undef BIG_ENDIAN + +extern jmp_buf ExitBuf; + +# else +# ifdef FLYINGFOX_HOST +# define HEAP_SIZE (16*1024) /* space for the heap and the stack */ +# define NO_HASH_INCLUDE +# include +# include +# include +# include +# include +# include +# include +# define assert(x) +# define BUILTIN_MINI_STDLIB +# undef BIG_ENDIAN + +# else +# ifdef SURVEYOR_HOST +# define HEAP_SIZE C_HEAPSIZE +# define NO_FP +# define NO_CTYPE +# define NO_HASH_INCLUDE +# define NO_MODULUS +# include +# include "../string.h" +# include "../print.h" +# include "../srv.h" +# include "../setjmp.h" +# include "../stdarg.h" +# include "../colors.h" +# include "../neural.h" +# include "../gps.h" +# include "../i2c.h" +# include "../jpeg.h" +# include "../malloc.h" +# include "../xmodem.h" +# define assert(x) +# undef BIG_ENDIAN +# define NO_CALLOC +# define NO_REALLOC +# define BROKEN_FLOAT_CASTS +# define BUILTIN_MINI_STDLIB +# else +# ifdef UMON_HOST +# define HEAP_SIZE (128*1024) /* space for the heap and the stack */ +# define NO_FP +# define BUILTIN_MINI_STDLIB +# include +# include +# include +# include +# include +# include +# include "monlib.h" +# define assert(x) +# define malloc mon_malloc +# define calloc(a,b) mon_malloc(a*b) +# define realloc mon_realloc +# define free mon_free +# endif +# endif +# endif + +extern int ExitBuf[]; + +# endif +#endif + +#endif /* PLATFORM_H */ diff --git a/src/cmd/picoc/platform/library_ffox.c b/src/cmd/picoc/platform/library_ffox.c new file mode 100644 index 0000000..9e68e62 --- /dev/null +++ b/src/cmd/picoc/platform/library_ffox.c @@ -0,0 +1,13 @@ +#include "../interpreter.h" + +/* list of all library functions and their prototypes */ +struct LibraryFunction PlatformLibrary[] = +{ + { NULL, NULL } +}; + +void PlatformLibraryInit() +{ + LibraryAdd(&GlobalTable, "platform library", &PlatformLibrary); +} + diff --git a/src/cmd/picoc/platform/library_msvc.c b/src/cmd/picoc/platform/library_msvc.c new file mode 100644 index 0000000..c2c54b4 --- /dev/null +++ b/src/cmd/picoc/platform/library_msvc.c @@ -0,0 +1,5 @@ +#include "../interpreter.h" + +void PlatformLibraryInit() +{ +} diff --git a/src/cmd/picoc/platform/library_srv1.c b/src/cmd/picoc/platform/library_srv1.c new file mode 100644 index 0000000..a8cd443 --- /dev/null +++ b/src/cmd/picoc/platform/library_srv1.c @@ -0,0 +1,809 @@ +#include "../interpreter.h" + +static int Blobcnt, Blobx1, Blobx2, Bloby1, Bloby2, Iy1, Iy2, Iu1, Iu2, Iv1, Iv2; +static int GPSlat, GPSlon, GPSalt, GPSfix, GPSsat, GPSutc, Elcount, Ercount; +static int ScanVect[16], NNVect[NUM_OUTPUT]; + +struct ValueType *IntArrayType; + + +void SRV1SetupFunc() +{ + IntArrayType = TypeGetMatching(NULL, &IntType, TypeArray, 16, StrEmpty, TRUE); + VariableDefinePlatformVar(NULL, "scanvect", IntArrayType, (union AnyValue *)&ScanVect, FALSE); + VariableDefinePlatformVar(NULL, "neuron", IntArrayType, (union AnyValue *)&NNVect, FALSE); + VariableDefinePlatformVar(NULL, "blobcnt", &IntType, (union AnyValue *)&Blobcnt, FALSE); + VariableDefinePlatformVar(NULL, "blobx1", &IntType, (union AnyValue *)&Blobx1, FALSE); + VariableDefinePlatformVar(NULL, "blobx2", &IntType, (union AnyValue *)&Blobx2, FALSE); + VariableDefinePlatformVar(NULL, "bloby1", &IntType, (union AnyValue *)&Bloby1, FALSE); + VariableDefinePlatformVar(NULL, "bloby2", &IntType, (union AnyValue *)&Bloby2, FALSE); + VariableDefinePlatformVar(NULL, "lcount", &IntType, (union AnyValue *)&Elcount, FALSE); + VariableDefinePlatformVar(NULL, "rcount", &IntType, (union AnyValue *)&Ercount, FALSE); + VariableDefinePlatformVar(NULL, "y1", &IntType, (union AnyValue *)&Iy1, FALSE); + VariableDefinePlatformVar(NULL, "y2", &IntType, (union AnyValue *)&Iy2, FALSE); + VariableDefinePlatformVar(NULL, "u1", &IntType, (union AnyValue *)&Iu1, FALSE); + VariableDefinePlatformVar(NULL, "u2", &IntType, (union AnyValue *)&Iu2, FALSE); + VariableDefinePlatformVar(NULL, "v1", &IntType, (union AnyValue *)&Iv1, FALSE); + VariableDefinePlatformVar(NULL, "v2", &IntType, (union AnyValue *)&Iv2, FALSE); + VariableDefinePlatformVar(NULL, "gpslat", &IntType, (union AnyValue *)&GPSlat, FALSE); + VariableDefinePlatformVar(NULL, "gpslon", &IntType, (union AnyValue *)&GPSlon, FALSE); + VariableDefinePlatformVar(NULL, "gpsalt", &IntType, (union AnyValue *)&GPSalt, FALSE); + VariableDefinePlatformVar(NULL, "gpsfix", &IntType, (union AnyValue *)&GPSfix, FALSE); + VariableDefinePlatformVar(NULL, "gpssat", &IntType, (union AnyValue *)&GPSsat, FALSE); + VariableDefinePlatformVar(NULL, "gpsutc", &IntType, (union AnyValue *)&GPSutc, FALSE); +} + +void Csignal(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) // check for kbhit, return t or nil +{ + if (getsignal()) + ReturnValue->Val->Integer = 1; + else + ReturnValue->Val->Integer = 0; +} + +void Cinput(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) // return 0-9 from console input +{ + ReturnValue->Val->Integer = getch(); +} + +void Cdelay(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + int del; + + del = Param[0]->Val->Integer; + if ((del < 0) || (del > 1000000)) + return; + delayMS(del); +} + +void Crand(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = (int)rand() % (unsigned int)(Param[0]->Val->Integer + 1); +} + +void Ctime(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = (int)readRTC(); +} + +void Ciodir(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + int dir; + + dir = Param[0]->Val->Integer; + *pPORTHIO_DIR = ((dir << 10) & 0xFC00) + (*pPORTHIO_DIR & 0x03FF); // H15/14/13/12/11/10 - 1=output, 0=input + *pPORTHIO_INEN = (((~dir) << 10) & 0xFC00) + (*pPORTHIO_INEN & 0x03FF); // invert dir bits to enable inputs +} + +void Cioread(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = (*pPORTHIO >> 10) & 0x003F; +} + +void Ciowrite(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + *pPORTHIO = ((Param[0]->Val->Integer << 10) & 0xFC00) + (*pPORTHIO & 0x03FF); +} + +void Cpeek(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + int size, ptr; + unsigned char *cp; + unsigned short *sp; + unsigned int *ip; + + /* x = peek(addr, size); + mask ptr to align with word size */ + ptr = Param[0]->Val->Integer; + size = Param[1]->Val->Integer; + switch (size) { + case 1: // char * + cp = (unsigned char *)ptr; + ReturnValue->Val->Integer = (int)((unsigned int)*cp); + break; + case 2: // short * + sp = (unsigned short *)(ptr & 0xFFFFFFFE); // align with even boundary + ReturnValue->Val->Integer = (int)((unsigned short)*sp); + break; + case 4: // int * + ip = (unsigned int *)(ptr & 0xFFFFFFFC); // aling with quad boundary + ReturnValue->Val->Integer = (int)*ip; + break; + default: + ReturnValue->Val->Integer = 0; + break; + } +} + +void Cpoke(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + int size, ptr, val; + unsigned char *cp; + unsigned short *sp; + unsigned int *ip; + + /* x = poke(addr, size, val); + mask ptr to align with word size */ + ptr = Param[0]->Val->Integer; + size = Param[1]->Val->Integer; + val = Param[2]->Val->Integer; + switch (size) { + case 1: // char * + cp = (unsigned char *)ptr; + *cp = (unsigned char)(val & 0x000000FF); + break; + case 2: // short * + sp = (unsigned short *)(ptr & 0xFFFFFFFE); + *sp = (unsigned short)(val & 0x0000FFFF); + break; + case 4: // int * + ip = (unsigned int *)(ptr & 0xFFFFFFFC); + *ip = val; + break; + default: // don't bother with bad value + break; + } +} + +void Cencoders(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + unsigned int ix; + + ix = encoders(); // read left and right encoders; save data to C globals lcount, rcount + Elcount = (ix >> 16) & 0x0000FFFF; + Ercount = ix & 0x0000FFFF; +} + +void Cmotors(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + lspeed = Param[0]->Val->Integer; + if ((lspeed < -100) || (lspeed > 100)) + ProgramFail(NULL, "motors(): left motor value out of range"); + rspeed = Param[1]->Val->Integer; + if ((rspeed < -100) || (rspeed > 100)) + ProgramFail(NULL, "motors(): right motor value out of range"); + if (!pwm1_init) { + initPWM(); + pwm1_init = 1; + pwm1_mode = PWM_PWM; + base_speed = 50; + } + setPWM(lspeed, rspeed); +} + +void Cmotors2(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + lspeed2 = Param[0]->Val->Integer; + if ((lspeed2 < -100) || (lspeed2 > 100)) + ProgramFail(NULL, "motors2(): left motor value out of range"); + rspeed2 = Param[1]->Val->Integer; + if ((rspeed2 < -100) || (rspeed2 > 100)) + ProgramFail(NULL, "motors2(): right motor value out of range"); + if (!pwm2_init) { + initPWM2(); + pwm2_init = 1; + pwm2_mode = PWM_PWM; + base_speed2 = 50; + } + setPWM2(lspeed2, rspeed2); +} + +void Cservos(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + int lspeed, rspeed; + + lspeed = Param[0]->Val->Integer; + if ((lspeed < 0) || (lspeed > 100)) + ProgramFail(NULL, "servos(): TMR2 value out of range"); + rspeed = Param[1]->Val->Integer; + if ((rspeed < 0) || (rspeed > 100)) + ProgramFail(NULL, "servos()(): TMR3 value out of range"); + if (!pwm1_init) { + initPPM1(); + pwm1_init = 1; + pwm1_mode = PWM_PPM; + } + setPPM1(lspeed, rspeed); +} + +void Cservos2(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + int lspeed, rspeed; + + lspeed = Param[0]->Val->Integer; + if ((lspeed < 0) || (lspeed > 100)) + ProgramFail(NULL, "servos2(): TMR6 value out of range"); + rspeed = Param[1]->Val->Integer; + if ((rspeed < 0) || (rspeed > 100)) + ProgramFail(NULL, "servos2(): TMR7 value out of range"); + if (!pwm2_init) { + initPPM2(); + pwm2_init = 1; + pwm2_mode = PWM_PPM; + } + setPPM2(lspeed, rspeed); +} + +void Claser(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) // laser(1) turns them on, laser(0) turns them off +{ + *pPORTHIO &= 0xFD7F; // turn off both lasers + switch (Param[0]->Val->Integer) { + case 1: + *pPORTHIO |= 0x0080; // turn on left laser + break; + case 2: + *pPORTHIO |= 0x0200; // turn on right laser + break; + case 3: + *pPORTHIO |= 0x0280; // turn on both lasers + break; + } +} + +void Csonar(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) // read sonar module +{ + unsigned int i; + i = Param[0]->Val->Integer; + if ((i<1) || (i>4)) { + ProgramFail(NULL, "sonar(): 1, 2, 3, 4 are only valid selections"); + } + sonar(); + ReturnValue->Val->Integer = sonar_data[i] / 100; +} + +void Crange(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = laser_range(0); +} + +void Cbattery(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + if (*pPORTHIO & 0x0004) + ReturnValue->Val->Integer = 0; // low battery voltage detected + else + ReturnValue->Val->Integer = 1; // battery voltage okay +} + +void Cvcolor(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) // set color bin - + // vcolor (color, ymin, ymax, umin, umax, vmin, vmax); +{ + int ix; + + ix = Param[0]->Val->Integer; + ymin[ix] = Param[1]->Val->Integer; + ymax[ix] = Param[2]->Val->Integer; + umin[ix] = Param[3]->Val->Integer; + umax[ix] = Param[4]->Val->Integer; + vmin[ix] = Param[5]->Val->Integer; + vmax[ix] = Param[6]->Val->Integer; +} + +void Cvcam(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) // set camera functions - + // enable/disable AGC(4) / AWB(2) / AEC(1) camera controls + // vcam(7) = AGC+AWB+AEC on vcam(0) = AGC+AWB+AEC off +{ + unsigned char cx, i2c_data[2]; + + cx = (unsigned char)Param[0]->Val->Integer & 0x07; + i2c_data[0] = 0x13; + i2c_data[1] = 0xC0 + cx; + i2cwrite(0x30, (unsigned char *)i2c_data, 1, SCCB_ON); // OV9655 + i2cwrite(0x21, (unsigned char *)i2c_data, 1, SCCB_ON); // OV7725 +} + +void Cvfind(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) // set color bin - + // vfind (color, x1, x2, y1, y2); +{ + int ix, x1, x2, y1, y2; + + ix = Param[0]->Val->Integer; + x1 = Param[1]->Val->Integer; + x2 = Param[2]->Val->Integer; + y1 = Param[3]->Val->Integer; + y2 = Param[4]->Val->Integer; + ReturnValue->Val->Integer = vfind((unsigned char *)FRAME_BUF, ix, x1, x2, y1, y2); +} + +void Cvcap(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + grab_frame(); // capture frame for processing +} + +void Cvrcap(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + grab_reference_frame(); // capture reference frame for differencing +} + +void Cvdiff(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + frame_diff_flag = Param[0]->Val->Integer; // set/clear frame_diff_flag +} + +void Cvpix(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + int x, y, ix; + x = Param[0]->Val->Integer; + y = Param[1]->Val->Integer; + ix = vpix((unsigned char *)FRAME_BUF, x, y); + Iy1 = ((ix>>16) & 0x000000FF); // Y1 + Iu1 = ((ix>>24) & 0x000000FF); // U + Iv1 = ((ix>>8) & 0x000000FF); // V +} + +void Cvscan(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + int col, thresh, ix; + col = Param[0]->Val->Integer; + if ((col < 1) || (col > 9)) + ProgramFail(NULL, "vscan(): number of columns must be between 1 and 9"); + thresh = Param[1]->Val->Integer; + if ((thresh < 0) || (thresh > 9999)) + ProgramFail(NULL, "vscan(): threshold must be between 0 and 9999"); + ix = vscan((unsigned char *)SPI_BUFFER1, (unsigned char *)FRAME_BUF, thresh, (unsigned int)col, (unsigned int *)&ScanVect[0]); + ReturnValue->Val->Integer = ix; +} + +void Cvmean(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + vmean((unsigned char *)FRAME_BUF); + Iy1 = mean[0]; + Iu1 = mean[1]; + Iv1 = mean[2]; +} + +// search for blob by color, index; return center point X,Y and width Z +void Cvblob(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) { + int ix, iblob, numblob; + + ix = Param[0]->Val->Integer; + if (ix > MAX_COLORS) + ProgramFail(NULL, "blob(): invalid color index"); + iblob = Param[1]->Val->Integer; + if (iblob > MAX_BLOBS) + ProgramFail(NULL, "blob(): invalid blob index"); + + numblob = vblob((unsigned char *)FRAME_BUF, (unsigned char *)FRAME_BUF3, ix); + + if ((blobcnt[iblob] == 0) || (numblob == -1)) { + Blobcnt = 0; + } else { + Blobcnt = blobcnt[iblob]; + Blobx1 = blobx1[iblob]; + Blobx2 = blobx2[iblob]; + Bloby1 = bloby1[iblob]; + Bloby2 = bloby2[iblob]; + } + ReturnValue->Val->Integer = numblob; +} + +void Cvjpeg (struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) { + unsigned int image_size, qual; + unsigned char *output_start, *output_end; + + qual = Param[0]->Val->Integer; + if ((qual < 1) || (qual > 8)) + ProgramFail(NULL, "vjpeg(): quality parameter out of range"); + + output_start = (unsigned char *)JPEG_BUF; + output_end = encode_image((unsigned char *)FRAME_BUF, output_start, qual, + FOUR_TWO_TWO, imgWidth, imgHeight); + image_size = (unsigned int)(output_end - output_start); + + ReturnValue->Val->Integer = image_size; +} + +void Cvsend (struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) { + unsigned int ix, image_size; + unsigned char *cp; + + image_size = Param[0]->Val->Integer; + if ((image_size < 0) || (image_size > 200000)) + ProgramFail(NULL, "vsend(): image size out of range"); + + led1_on(); + + cp = (unsigned char *)JPEG_BUF; + for (ix=0; ixVal->Integer = ix; +} + +void Ctilt(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) // return reading from HMC6352 I2C compass +{ + unsigned int ix; + + ix = (unsigned int)Param[0]->Val->Integer; + if ((ix<1) || (ix>3)) + ProgramFail(NULL, "tilt(): invalid channel"); + ReturnValue->Val->Integer = tilt(ix); +} + +void Canalog(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) // return reading from HMC6352 I2C compass +{ + unsigned char i2c_data[3], device_id; + unsigned int ix, channel; + unsigned char mask1[] = { 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x08 }; + unsigned char mask2[] = { 0x10, 0x20, 0x40, 0x80, 0x00, 0x00, 0x00, 0x00 }; + + // decide which i2c device based on channel range + ix = (unsigned char)Param[0]->Val->Integer; + if ((ix<1) || (ix>28)) + ProgramFail(NULL, "analog(): invalid channel"); + device_id = 0; + switch (ix / 10) { + case 0: + device_id = 0x20; // channels 1-8 + break; + case 1: + device_id = 0x23; // channels 11-18 + break; + case 2: + device_id = 0x24; // channels 21-28 + break; + } + channel = ix % 10; + if ((channel<1) || (channel>8)) + ProgramFail(NULL, "analog(): invalid channel"); + + // set timer register 3 + i2c_data[0] = 0x03; + i2c_data[1] = 0x01; + i2cwrite(device_id, (unsigned char *)i2c_data, 1, SCCB_ON); + + // set analog channel + i2c_data[0] = 0x02; + i2c_data[1] = mask1[channel-1]; + i2c_data[2] = mask2[channel-1]; + i2cwritex(device_id, (unsigned char *)i2c_data, 3, SCCB_ON); + + // small delay + delayUS(1000); + + // read data + i2c_data[0] = 0x00; + i2cread(device_id, (unsigned char *)i2c_data, 2, SCCB_ON); + ix = (((i2c_data[0] & 0x0F) << 8) + i2c_data[1]); + ReturnValue->Val->Integer = ix; +} + +void Cgps(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + gps_parse(); + GPSlat = gps_gga.lat; + GPSlon = gps_gga.lon; + GPSalt = gps_gga.alt; + GPSfix = gps_gga.fix; + GPSsat = gps_gga.sat; + GPSutc = gps_gga.utc; +} + +void Creadi2c(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) // syntax val = readi2c(device, register); +{ + unsigned char i2c_device, i2c_data[2]; + + i2c_device = (unsigned char)Param[0]->Val->Integer; + i2c_data[0] = (unsigned char)Param[1]->Val->Integer; + + i2cread(i2c_device, (unsigned char *)i2c_data, 1, SCCB_OFF); + ReturnValue->Val->Integer = ((int)i2c_data[0] & 0x000000FF); +} + +void Creadi2c2(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) // syntax two_byte_val = readi2c(device, register); +{ + unsigned char i2c_device, i2c_data[2]; + + i2c_device = (unsigned char)Param[0]->Val->Integer; + i2c_data[0] = (unsigned char)Param[1]->Val->Integer; + + i2cread(i2c_device, (unsigned char *)i2c_data, 2, SCCB_OFF); + ReturnValue->Val->Integer = (((unsigned int)i2c_data[0] << 8) + i2c_data[1]); +} + +void Cwritei2c(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) // syntax writei2c(device, register, value); +{ + unsigned char i2c_device, i2c_data[2]; + + i2c_device = (unsigned char)Param[0]->Val->Integer; + i2c_data[0] = (unsigned char)Param[1]->Val->Integer; + i2c_data[1] = (unsigned char)Param[2]->Val->Integer; + + i2cwrite(i2c_device, (unsigned char *)i2c_data, 1, SCCB_OFF); +} + +void Csin(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) // sin(angle) +{ + int ix; + + ix = Param[0]->Val->Integer; // input to function is angle in degrees + ReturnValue->Val->Integer = sin(ix); +} + +void Ccos(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) // cos(angle) +{ + int ix; + + ix = Param[0]->Val->Integer; // input to function is angle in degrees + ReturnValue->Val->Integer = cos(ix); +} + +void Ctan(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) // tan(angle) +{ + int ix; + + ix = Param[0]->Val->Integer; // input to function is angle in degrees + ReturnValue->Val->Integer = tan(ix); +} + +void Casin(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) // asin(y,hyp) +{ + int y, hyp; + y = Param[0]->Val->Integer; + hyp = Param[1]->Val->Integer; + if (y > hyp) + ProgramFail(NULL, "asin(): opposite greater than hypotenuse"); + ReturnValue->Val->Integer = asin(y, hyp); +} + +void Cacos(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) // acos(x,hyp) +{ + int x, hyp; + x = Param[0]->Val->Integer; + hyp = Param[1]->Val->Integer; + if (x > hyp) + ProgramFail(NULL, "acos(): adjacent greater than hypotenuse"); + ReturnValue->Val->Integer = acos(x, hyp); +} + +void Catan(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) // atan(y,x) +{ + int x ,y; + y = Param[0]->Val->Integer; + x = Param[1]->Val->Integer; + ReturnValue->Val->Integer = atan(y, x); +} + +void Cgps_head(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) // gps_head(lat1, lon1, lat2, lon2) +{ + int lat1, lon1, lat2, lon2; + lat1 = Param[0]->Val->Integer; + lon1 = Param[1]->Val->Integer; + lat2 = Param[2]->Val->Integer; + lon2 = Param[3]->Val->Integer; + ReturnValue->Val->Integer = gps_head(lat1, lon1, lat2, lon2); +} + +void Cgps_dist(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) // gps_dist(lat1, lon1, lat2, lon2) +{ + int lat1, lon1, lat2, lon2; + lat1 = Param[0]->Val->Integer; + lon1 = Param[1]->Val->Integer; + lat2 = Param[2]->Val->Integer; + lon2 = Param[3]->Val->Integer; + ReturnValue->Val->Integer = gps_dist(lat1, lon1, lat2, lon2); +} + +void Csqrt(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) // sqrt(x) +{ + int x; + x = Param[0]->Val->Integer; + ReturnValue->Val->Integer = isqrt(x); +} + +void Cnnset(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) { + int ix, i1; + + ix = Param[0]->Val->Integer; + if (ix > NUM_NPATTERNS) + ProgramFail(NULL, "nnset(): invalid index"); + for (i1=0; i1<8; i1++) + npattern[ix*8 + i1] = (unsigned char)Param[i1+1]->Val->Integer; +} + +void Cnnshow(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) { + int ix; + + ix = Param[0]->Val->Integer; + if (ix > NUM_NPATTERNS) + ProgramFail(NULL, "nnshow(): invalid index"); + nndisplay(ix); +} + +void Cnninit(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) { + nninit_network(); +} + +void Cnntrain(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) { + int ix, i1; + + nntrain_network(10000); + for (ix=0; ixVal->Integer; + for (i2=0; i2<8; i2++) { + if (ch & nmask[i2]) + N_IN(ix++) = 1024; + else + N_IN(ix++) = 0; + } + } + nncalculate_network(); + ix = 0; + max = 0; + for (i1=0; i1Val->Integer = ix; +} + +void Cnnmatchblob(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) { + int ix, i1, max; + + ix = Param[0]->Val->Integer; + if (ix > MAX_BLOBS) + ProgramFail(NULL, "nnmatchblob(): invalid blob index"); + if (!blobcnt[ix]) + ProgramFail(NULL, "nnmatchblob(): not a valid blob"); + /* use data still in blob_buf[] (FRAME_BUF3) + square the aspect ratio of x1, x2, y1, y2 + then subsample blob pixels to populate N_IN(0:63) with 0:1024 values + then nncalculate_network() and display the N_OUT() results */ + nnscale8x8((unsigned char *)FRAME_BUF3, blobix[ix], blobx1[ix], blobx2[ix], + bloby1[ix], bloby2[ix], imgWidth, imgHeight); + nncalculate_network(); + ix = 0; + max = 0; + for (i1=0; i1Val->Integer = ix; +} + +void Cnnlearnblob (struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) { + int ix; + + ix = Param[0]->Val->Integer; + if (ix > NUM_NPATTERNS) + ProgramFail(NULL, "nnlearnblob(): invalid index"); + if (!blobcnt[0]) + ProgramFail(NULL, "nnlearnblob(): no blob to grab"); + nnscale8x8((unsigned char *)FRAME_BUF3, blobix[0], blobx1[0], blobx2[0], + bloby1[0], bloby2[0], imgWidth, imgHeight); + nnpack8x8(ix); + nndisplay(ix); +} + +void Cautorun (struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) { + int ix, t0; + unsigned char ch; + + ix = Param[0]->Val->Integer; + t0 = readRTC(); + while (readRTC() < (t0 + ix*1000)) { // watch for ESC in 'ix' seconds + if (getchar(&ch)) { + if (ch == 0x1B) { // if ESC found, exit picoC + printf("found ESC\r\n"); + ExitBuf[40] = 1; + longjmp(ExitBuf, 1); + } + } + } +} + +void Clineno (struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) { + ReturnValue->Val->Integer = Parser->Line; +} + +void Cerrormsg (struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) { + PlatformErrorPrefix(Parser); + LibPrintf(Parser, ReturnValue, Param, NumArgs); +} + +/* nothing here because we don't add any functions until srv1.h is #included */ +struct LibraryFunction PlatformLibrary[] = +{ + { NULL, NULL } +}; + +/* list of all library functions included with srv1.h */ +struct LibraryFunction SRV1Functions[] = +{ + { Csignal, "int signal();" }, + { Cinput, "int input();" }, + { Cdelay, "void delay(int);" }, + { Crand, "int rand(int);" }, + { Ctime, "int time();" }, + { Ciodir, "void iodir(int);" }, + { Cioread, "int ioread();" }, + { Ciowrite, "void iowrite(int);" }, + { Cpeek, "int peek(int, int);" }, + { Cpoke, "void poke(int, int, int);" }, + { Cmotors, "void motors(int, int);" }, + { Cmotors2, "void motors2(int, int);" }, + { Cservos, "void servos(int, int);" }, + { Cservos2, "void servos2(int, int);" }, + { Cencoders, "void encoders();" }, + { Claser, "void laser(int);" }, + { Csonar, "int sonar(int);" }, + { Crange, "int range();" }, + { Cbattery, "int battery();" }, + { Cvcolor, "void vcolor(int, int, int, int, int, int, int);" }, + { Cvfind, "int vfind(int, int, int, int, int);" }, + { Cvcam, "void vcam(int);" }, + { Cvcap, "void vcap();" }, + { Cvrcap, "void vrcap();" }, + { Cvdiff, "void vdiff(int);" }, + { Cvpix, "void vpix(int, int);" }, + { Cvscan, "int vscan(int, int);" }, + { Cvmean, "void vmean();" }, + { Cvblob, "int vblob(int, int);" }, + { Cvjpeg, "int vjpeg(int);" }, + { Cvsend, "void vsend(int);" }, + { Ccompass, "int compass();" }, + { Canalog, "int analog(int);" }, + { Ctilt, "int tilt(int);" }, + { Cgps, "void gps();" }, + { Creadi2c, "int readi2c(int, int);" }, + { Creadi2c2, "int readi2c2(int, int);" }, + { Cwritei2c, "void writei2c(int, int, int);" }, + { Csin, "int sin(int);" }, + { Ccos, "int cos(int);" }, + { Ctan, "int tan(int);" }, + { Casin, "int asin(int, int);" }, + { Cacos, "int acos(int, int);" }, + { Catan, "int atan(int, int);" }, + { Cgps_head, "int gps_head(int, int, int, int);" }, + { Cgps_dist, "int gps_dist(int, int, int, int);" }, + { Csqrt, "int sqrt(int);" }, + { Cnnshow, "void nnshow(int);" }, + { Cnnset, "void nnset(int, int, int, int, int, int, int, int, int);" }, + { Cnninit, "void nninit();" }, + { Cnntrain, "void nntrain();" }, + { Cnntest, "int nntest(int, int, int, int, int, int, int, int);" }, + { Cnnmatchblob, "int nnmatchblob(int);" }, + { Cnnlearnblob, "void nnlearnblob(int);" }, + { Cautorun, "void autorun(int);" }, + { Clineno, "int lineno();" }, + { Cerrormsg, "void errormsg(char *);" }, + { NULL, NULL } +}; + +void PlatformLibraryInit() +{ + IncludeRegister("srv1.h", &SRV1SetupFunc, &SRV1Functions[0], NULL); +} diff --git a/src/cmd/picoc/platform/library_surveyor.c b/src/cmd/picoc/platform/library_surveyor.c new file mode 100644 index 0000000..283aff2 --- /dev/null +++ b/src/cmd/picoc/platform/library_surveyor.c @@ -0,0 +1,944 @@ +#include "../interpreter.h" +#include "../picoc.h" + +static int Blobcnt, Blobx1, Blobx2, Bloby1, Bloby2, Iy1, Iy2, Iu1, Iu2, Iv1, Iv2; +static int Cxmin, Cxmax, Cymin, Cymax; +static int GPSlat, GPSlon, GPSalt, GPSfix, GPSsat, GPSutc, Elcount, Ercount; +static int ScanVect[16], NNVect[NUM_OUTPUT]; + +void PlatformLibraryInit() +{ + struct ValueType *IntArrayType; + + IntArrayType = TypeGetMatching(NULL, &IntType, TypeArray, 16, StrEmpty, TRUE); + VariableDefinePlatformVar(NULL, "scanvect", IntArrayType, (union AnyValue *)&ScanVect, FALSE); + VariableDefinePlatformVar(NULL, "neuron", IntArrayType, (union AnyValue *)&NNVect, FALSE); + VariableDefinePlatformVar(NULL, "xbuf", CharArrayType, (union AnyValue *)&xbuff, FALSE); + VariableDefinePlatformVar(NULL, "blobcnt", &IntType, (union AnyValue *)&Blobcnt, FALSE); + VariableDefinePlatformVar(NULL, "blobx1", &IntType, (union AnyValue *)&Blobx1, FALSE); + VariableDefinePlatformVar(NULL, "blobx2", &IntType, (union AnyValue *)&Blobx2, FALSE); + VariableDefinePlatformVar(NULL, "bloby1", &IntType, (union AnyValue *)&Bloby1, FALSE); + VariableDefinePlatformVar(NULL, "bloby2", &IntType, (union AnyValue *)&Bloby2, FALSE); + VariableDefinePlatformVar(NULL, "lcount", &IntType, (union AnyValue *)&Elcount, FALSE); + VariableDefinePlatformVar(NULL, "rcount", &IntType, (union AnyValue *)&Ercount, FALSE); + VariableDefinePlatformVar(NULL, "y1", &IntType, (union AnyValue *)&Iy1, FALSE); + VariableDefinePlatformVar(NULL, "y2", &IntType, (union AnyValue *)&Iy2, FALSE); + VariableDefinePlatformVar(NULL, "u1", &IntType, (union AnyValue *)&Iu1, FALSE); + VariableDefinePlatformVar(NULL, "u2", &IntType, (union AnyValue *)&Iu2, FALSE); + VariableDefinePlatformVar(NULL, "v1", &IntType, (union AnyValue *)&Iv1, FALSE); + VariableDefinePlatformVar(NULL, "v2", &IntType, (union AnyValue *)&Iv2, FALSE); + VariableDefinePlatformVar(NULL, "gpslat", &IntType, (union AnyValue *)&GPSlat, FALSE); + VariableDefinePlatformVar(NULL, "gpslon", &IntType, (union AnyValue *)&GPSlon, FALSE); + VariableDefinePlatformVar(NULL, "gpsalt", &IntType, (union AnyValue *)&GPSalt, FALSE); + VariableDefinePlatformVar(NULL, "gpsfix", &IntType, (union AnyValue *)&GPSfix, FALSE); + VariableDefinePlatformVar(NULL, "gpssat", &IntType, (union AnyValue *)&GPSsat, FALSE); + VariableDefinePlatformVar(NULL, "gpsutc", &IntType, (union AnyValue *)&GPSutc, FALSE); + VariableDefinePlatformVar(NULL, "cxmin", &IntType, (union AnyValue *)&Cxmin, FALSE); + VariableDefinePlatformVar(NULL, "cxmax", &IntType, (union AnyValue *)&Cxmax, FALSE); + VariableDefinePlatformVar(NULL, "cymin", &IntType, (union AnyValue *)&Cymin, FALSE); + VariableDefinePlatformVar(NULL, "cymax", &IntType, (union AnyValue *)&Cymax, FALSE); + LibraryAdd(&GlobalTable, "platform library", &PlatformLibrary[0]); +} + +void Csignal(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) // check for kbhit, return t or nil +{ + ReturnValue->Val->Integer = getsignal(); +} + +void Csignal1(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) // check for kbhit, return t or nil +{ + ReturnValue->Val->Integer = uart1Signal(); +} + +void Cinput(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) // return 0-9 from console input +{ + ReturnValue->Val->Integer = getch(); +} + +void Cinput1(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) // return 0-9 from console input +{ + ReturnValue->Val->Integer = uart1GetCh(); +} + +void Cread_int(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) // return 0-9 from console input +{ + int ix, sign; + unsigned char ch; + + ix = 0; + sign = 1; + while (1) { + ch = getch(); + if (ch == '-') { + sign = -1; + continue; + } + if ((ch < '0') || (ch > '9')) { // if not '-' or 0-9, we're done + ReturnValue->Val->Integer = ix * sign; + return; + } + ix = (ix * 10) + (ch & 0x0F); + } +} + +void Cread_str(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) // read string from console +{ + int ix; + unsigned char ch; + + ix = 0; + char *cp = (char *)Param[0]->Val->Pointer; + while (1) { + ch = getch(); + cp[ix++] = ch; + if ((ch == 0) || (ch == 0x01)) { // null or ctrl-A + ix--; + cp[ix] = 0; + break; + } + if (ix > 1023) { + cp[ix] = 0; + ix--; + break; + } + } + ReturnValue->Val->Integer = ix; +} + +void Cinit_uart1(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) // return 0-9 from console input +{ + int ii; + ii = Param[0]->Val->Integer; // ii = baudrate for uart1 + init_uart1(ii); +} + +void Coutput(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) // return 0-9 from console input +{ + int ch; + ch = Param[0]->Val->Integer; + putchar((unsigned char)ch); +} + +void Coutput1(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) // return 0-9 from console input +{ + int ch; + ch = Param[0]->Val->Integer; + uart1SendChar((unsigned char)ch); +} + +void Cdelay(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + int del; + + del = Param[0]->Val->Integer; + if ((del < 0) || (del > 1000000)) + return; + delayMS(del); +} + +void Crand(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = (int)rand() % (unsigned int)(Param[0]->Val->Integer + 1); +} + +void Ctime(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = (int)readRTC(); +} + +void Ciodir(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + int dir; + + dir = Param[0]->Val->Integer; + *pPORTHIO_DIR = ((dir << 10) & 0xFC00) + (*pPORTHIO_DIR & 0x03FF); // H15/14/13/12/11/10 - 1=output, 0=input + *pPORTHIO_INEN = (((~dir) << 10) & 0xFC00) + (*pPORTHIO_INEN & 0x03FF); // invert dir bits to enable inputs +} + +void Cioread(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = (*pPORTHIO >> 10) & 0x003F; +} + +void Ciowrite(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + *pPORTHIO = ((Param[0]->Val->Integer << 10) & 0xFC00) + (*pPORTHIO & 0x03FF); +} + +void Cpeek(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + int size, ptr; + unsigned char *cp; + unsigned short *sp; + unsigned int *ip; + + /* x = peek(addr, size); + mask ptr to align with word size */ + ptr = Param[0]->Val->Integer; + size = Param[1]->Val->Integer; + switch (size) { + case 1: // char * + cp = (unsigned char *)ptr; + ReturnValue->Val->Integer = (int)((unsigned int)*cp); + break; + case 2: // short * + sp = (unsigned short *)(ptr & 0xFFFFFFFE); // align with even boundary + ReturnValue->Val->Integer = (int)((unsigned short)*sp); + break; + case 4: // int * + ip = (unsigned int *)(ptr & 0xFFFFFFFC); // aling with quad boundary + ReturnValue->Val->Integer = (int)*ip; + break; + default: + ReturnValue->Val->Integer = 0; + break; + } +} + +void Cpoke(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + int size, ptr, val; + unsigned char *cp; + unsigned short *sp; + unsigned int *ip; + + /* x = poke(addr, size, val); + mask ptr to align with word size */ + ptr = Param[0]->Val->Integer; + size = Param[1]->Val->Integer; + val = Param[2]->Val->Integer; + switch (size) { + case 1: // char * + cp = (unsigned char *)ptr; + *cp = (unsigned char)(val & 0x000000FF); + break; + case 2: // short * + sp = (unsigned short *)(ptr & 0xFFFFFFFE); + *sp = (unsigned short)(val & 0x0000FFFF); + break; + case 4: // int * + ip = (unsigned int *)(ptr & 0xFFFFFFFC); + *ip = val; + break; + default: // don't bother with bad value + break; + } +} + +void Cencoders(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + unsigned int ix; + + ix = encoders(); // read left and right encoders; save data to C globals lcount, rcount + Elcount = (ix >> 16) & 0x0000FFFF; + Ercount = ix & 0x0000FFFF; +} + +void Cencoderx(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) // return reading from HMC6352 I2C compass +{ + int ix; + + ix = (unsigned char)Param[0]->Val->Integer; + if ((ix<0) || (ix>7)) + ProgramFail(NULL, "encoderx(): invalid channel"); + ReturnValue->Val->Integer = encoder_4wd(ix); +} + +void Cmotors(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + lspeed = Param[0]->Val->Integer; + if ((lspeed < -100) || (lspeed > 100)) + ProgramFail(NULL, "motors(): left motor value out of range"); + rspeed = Param[1]->Val->Integer; + if ((rspeed < -100) || (rspeed > 100)) + ProgramFail(NULL, "motors(): right motor value out of range"); + if (!pwm1_init) { + initPWM(); + pwm1_init = 1; + pwm1_mode = PWM_PWM; + base_speed = 50; + } + setPWM(lspeed, rspeed); +} + +void Cmotors2(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + lspeed2 = Param[0]->Val->Integer; + if ((lspeed2 < -100) || (lspeed2 > 100)) + ProgramFail(NULL, "motors2(): left motor value out of range"); + rspeed2 = Param[1]->Val->Integer; + if ((rspeed2 < -100) || (rspeed2 > 100)) + ProgramFail(NULL, "motors2(): right motor value out of range"); + if (!pwm2_init) { + initPWM2(); + pwm2_init = 1; + pwm2_mode = PWM_PWM; + base_speed2 = 50; + } + setPWM2(lspeed2, rspeed2); +} + +/* motor control for SRV-4WD controller */ +void Cmotorx(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + unsigned char ch; + int ls, rs; + + ls = Param[0]->Val->Integer; + if ((ls < -100) || (ls > 100)) + ProgramFail(NULL, "motors(): left motor value out of range"); + ls = (ls * 127) / 100; // scale to full +/-127 range + rs = Param[1]->Val->Integer; + if ((rs < -100) || (rs > 100)) + ProgramFail(NULL, "motors(): right motor value out of range"); + rs = (rs * 127) / 100; // scale to full +/-127 range + if (xwd_init == 0) { + xwd_init = 1; + init_uart1(115200); + delayMS(10); + } + uart1SendChar('x'); + uart1SendChar((char)ls); + uart1SendChar((char)rs); + while (uart1GetChar(&ch)) // flush the receive buffer + continue; +} + +void Cservos(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + int lspeed, rspeed; + + lspeed = Param[0]->Val->Integer; + if ((lspeed < 0) || (lspeed > 100)) + ProgramFail(NULL, "servos(): TMR2 value out of range"); + rspeed = Param[1]->Val->Integer; + if ((rspeed < 0) || (rspeed > 100)) + ProgramFail(NULL, "servos()(): TMR3 value out of range"); + if (!pwm1_init) { + initPPM1(); + pwm1_init = 1; + pwm1_mode = PWM_PPM; + } + setPPM1(lspeed, rspeed); +} + +void Cservos2(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + int lspeed, rspeed; + + lspeed = Param[0]->Val->Integer; + if ((lspeed < 0) || (lspeed > 100)) + ProgramFail(NULL, "servos2(): TMR6 value out of range"); + rspeed = Param[1]->Val->Integer; + if ((rspeed < 0) || (rspeed > 100)) + ProgramFail(NULL, "servos2(): TMR7 value out of range"); + if (!pwm2_init) { + initPPM2(); + pwm2_init = 1; + pwm2_mode = PWM_PPM; + } + setPPM2(lspeed, rspeed); +} + +void Claser(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) // laser(1) turns them on, laser(0) turns them off +{ + *pPORTHIO &= 0xFD7F; // turn off both lasers + switch (Param[0]->Val->Integer) { + case 1: + *pPORTHIO |= 0x0080; // turn on left laser + break; + case 2: + *pPORTHIO |= 0x0200; // turn on right laser + break; + case 3: + *pPORTHIO |= 0x0280; // turn on both lasers + break; + } +} + +void Csonar(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) // read sonar module +{ + unsigned int i; + i = Param[0]->Val->Integer; + if ((i<1) || (i>4)) { + ProgramFail(NULL, "sonar(): 1, 2, 3, 4 are only valid selections"); + } + sonar(); + ReturnValue->Val->Integer = sonar_data[i] / 100; +} + +void Crange(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = laser_range(0); +} + +void Cbattery(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + if (*pPORTHIO & 0x0004) + ReturnValue->Val->Integer = 0; // low battery voltage detected + else + ReturnValue->Val->Integer = 1; // battery voltage okay +} + +void Cvcolor(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) // set color bin - + // vcolor (color, ymin, ymax, umin, umax, vmin, vmax); +{ + int ix; + + ix = Param[0]->Val->Integer; + ymin[ix] = Param[1]->Val->Integer; + ymax[ix] = Param[2]->Val->Integer; + umin[ix] = Param[3]->Val->Integer; + umax[ix] = Param[4]->Val->Integer; + vmin[ix] = Param[5]->Val->Integer; + vmax[ix] = Param[6]->Val->Integer; +} + +void Cvcam(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) // set camera functions - + // enable/disable AGC(4) / AWB(2) / AEC(1) camera controls + // vcam(7) = AGC+AWB+AEC on vcam(0) = AGC+AWB+AEC off +{ + unsigned char cx, i2c_data[2]; + + cx = (unsigned char)Param[0]->Val->Integer & 0x07; + i2c_data[0] = 0x13; + i2c_data[1] = 0xC0 + cx; + i2cwrite(0x30, (unsigned char *)i2c_data, 1, SCCB_ON); // OV9655 + i2cwrite(0x21, (unsigned char *)i2c_data, 1, SCCB_ON); // OV7725 +} + +void Cvfind(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) // set color bin - + // vfind (color, x1, x2, y1, y2); +{ + int ix, x1, x2, y1, y2; + + ix = Param[0]->Val->Integer; + x1 = Param[1]->Val->Integer; + x2 = Param[2]->Val->Integer; + y1 = Param[3]->Val->Integer; + y2 = Param[4]->Val->Integer; + ReturnValue->Val->Integer = vfind((unsigned char *)FRAME_BUF, ix, x1, x2, y1, y2); +} + +void Cvcap(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + grab_frame(); // capture frame for processing +} + +void Cvrcap(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + grab_reference_frame(); // capture reference frame for differencing +} + +void Cvdiff(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + frame_diff_flag = Param[0]->Val->Integer; // set/clear frame_diff_flag +} + +void Cvpix(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + int x, y, ix; + x = Param[0]->Val->Integer; + y = Param[1]->Val->Integer; + ix = vpix((unsigned char *)FRAME_BUF, x, y); + Iy1 = ((ix>>16) & 0x000000FF); // Y1 + Iu1 = ((ix>>24) & 0x000000FF); // U + Iv1 = ((ix>>8) & 0x000000FF); // V +} + +void Cvscan(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + int col, thresh, ix; + col = Param[0]->Val->Integer; + if ((col < 1) || (col > 9)) + ProgramFail(NULL, "vscan(): number of columns must be between 1 and 9"); + thresh = Param[1]->Val->Integer; + if ((thresh < 0) || (thresh > 9999)) + ProgramFail(NULL, "vscan(): threshold must be between 0 and 9999"); + ix = vscan((unsigned char *)SPI_BUFFER1, (unsigned char *)FRAME_BUF, thresh, (unsigned int)col, (unsigned int *)&ScanVect[0]); + ReturnValue->Val->Integer = ix; +} + +void Cvmean(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + vmean((unsigned char *)FRAME_BUF); + Iy1 = mean[0]; + Iu1 = mean[1]; + Iv1 = mean[2]; +} + +// search for blob by color, index; return center point X,Y and width Z +void Cvblob(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) { + int ix, iblob, numblob; + + ix = Param[0]->Val->Integer; + if (ix > MAX_COLORS) + ProgramFail(NULL, "blob(): invalid color index"); + iblob = Param[1]->Val->Integer; + if (iblob > MAX_BLOBS) + ProgramFail(NULL, "blob(): invalid blob index"); + + numblob = vblob((unsigned char *)FRAME_BUF, (unsigned char *)FRAME_BUF3, ix); + + if ((blobcnt[iblob] == 0) || (numblob == -1)) { + Blobcnt = 0; + } else { + Blobcnt = blobcnt[iblob]; + Blobx1 = blobx1[iblob]; + Blobx2 = blobx2[iblob]; + Bloby1 = bloby1[iblob]; + Bloby2 = bloby2[iblob]; + } + ReturnValue->Val->Integer = numblob; +} + +void Cvjpeg (struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) { + unsigned int image_size, qual; + unsigned char *output_start, *output_end; + + qual = Param[0]->Val->Integer; + if ((qual < 1) || (qual > 8)) + ProgramFail(NULL, "vjpeg(): quality parameter out of range"); + + output_start = (unsigned char *)JPEG_BUF; + output_end = encode_image((unsigned char *)FRAME_BUF, output_start, qual, + FOUR_TWO_TWO, imgWidth, imgHeight); + image_size = (unsigned int)(output_end - output_start); + + ReturnValue->Val->Integer = image_size; +} + +void Cvsend (struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) { + unsigned int ix, image_size; + unsigned char *cp; + + image_size = Param[0]->Val->Integer; + if ((image_size < 0) || (image_size > 200000)) + ProgramFail(NULL, "vsend(): image size out of range"); + + led1_on(); + + cp = (unsigned char *)JPEG_BUF; + for (ix=0; ixVal->Integer = ix; +} + +void Ccompassx(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) // return reading from HMC5843 I2C compass +{ + short x, y, z; + int ix; + + ix = (int)read_compass3x(&x, &y, &z); + Cxmin = cxmin; + Cxmax = cxmax; + Cymin = cymin; + Cymax = cymax; + ReturnValue->Val->Integer = ix; +} + +void Ccompassxcal(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) // return reading from HMC5843 I2C compass +{ + /* cxmin, cxmax, cymin, cymax */ + cxmin = Param[0]->Val->Integer; + cxmax = Param[1]->Val->Integer; + cymin = Param[2]->Val->Integer; + cymax = Param[3]->Val->Integer; + compass_continuous_calibration = Param[4]->Val->Integer; // continuous calibration: off = 0, on = 1 +} + +void Ctilt(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) // return reading from HMC6352 I2C compass +{ + unsigned int ix; + + ix = (unsigned int)Param[0]->Val->Integer; + if ((ix<1) || (ix>3)) + ProgramFail(NULL, "tilt(): invalid channel"); + ReturnValue->Val->Integer = tilt(ix); +} + +void Canalog(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) // return reading from HMC6352 I2C compass +{ + unsigned int ix, channel; + + ix = (unsigned char)Param[0]->Val->Integer; + if ((ix<1) || (ix>28)) + ProgramFail(NULL, "analog(): invalid channel"); + channel = ix % 10; + if ((channel<1) || (channel>8)) + ProgramFail(NULL, "analog(): invalid channel"); + ReturnValue->Val->Integer = analog(ix); +} + + +/* read analog channel 0-7 from SRV-4WD ( + channel 0 = battery level + channel 1 = 5V gyro + channel 2 = 3.3V gyro + channel 3 = IR1 + channel 4 = IR2 + channel 6 = IR3 + channel 7 = IR4 + */ +void Canalogx(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) // return reading from HMC6352 I2C compass +{ + int ix; + + ix = (unsigned char)Param[0]->Val->Integer; + if ((ix<0) || (ix>7)) + ProgramFail(NULL, "analogx(): invalid channel"); + ReturnValue->Val->Integer = analog_4wd(ix); +} + +void Cgps(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + gps_parse(); + GPSlat = gps_gga.lat; + GPSlon = gps_gga.lon; + GPSalt = gps_gga.alt; + GPSfix = gps_gga.fix; + GPSsat = gps_gga.sat; + GPSutc = gps_gga.utc; +} + +void Creadi2c(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) // syntax val = readi2c(device, register); +{ + unsigned char i2c_device, i2c_data[2]; + + i2c_device = (unsigned char)Param[0]->Val->Integer; + i2c_data[0] = (unsigned char)Param[1]->Val->Integer; + + i2cread(i2c_device, (unsigned char *)i2c_data, 1, SCCB_OFF); + ReturnValue->Val->Integer = ((int)i2c_data[0] & 0x000000FF); +} + +void Creadi2c2(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) // syntax two_byte_val = readi2c(device, register); +{ + unsigned char i2c_device, i2c_data[2]; + + i2c_device = (unsigned char)Param[0]->Val->Integer; + i2c_data[0] = (unsigned char)Param[1]->Val->Integer; + + i2cread(i2c_device, (unsigned char *)i2c_data, 2, SCCB_OFF); + ReturnValue->Val->Integer = (((unsigned int)i2c_data[0] << 8) + i2c_data[1]); +} + +void Cwritei2c(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) // syntax writei2c(device, register, value); +{ + unsigned char i2c_device, i2c_data[2]; + + i2c_device = (unsigned char)Param[0]->Val->Integer; + i2c_data[0] = (unsigned char)Param[1]->Val->Integer; + i2c_data[1] = (unsigned char)Param[2]->Val->Integer; + + i2cwrite(i2c_device, (unsigned char *)i2c_data, 1, SCCB_OFF); +} + +void Cabs(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) // abs(int) +{ + int ix; + + ix = Param[0]->Val->Integer; // return absolute value of int + if (ix < 0) + ix = -ix; + ReturnValue->Val->Integer = ix; +} +void Csin(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) // sin(angle) +{ + int ix; + + ix = Param[0]->Val->Integer; // input to function is angle in degrees + ReturnValue->Val->Integer = sin(ix); +} + +void Ccos(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) // cos(angle) +{ + int ix; + + ix = Param[0]->Val->Integer; // input to function is angle in degrees + ReturnValue->Val->Integer = cos(ix); +} + +void Ctan(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) // tan(angle) +{ + int ix; + + ix = Param[0]->Val->Integer; // input to function is angle in degrees + ReturnValue->Val->Integer = tan(ix); +} + +void Casin(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) // asin(y,hyp) +{ + int y, hyp; + y = Param[0]->Val->Integer; + hyp = Param[1]->Val->Integer; + if (y > hyp) + ProgramFail(NULL, "asin(): opposite greater than hypotenuse"); + ReturnValue->Val->Integer = asin(y, hyp); +} + +void Cacos(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) // acos(x,hyp) +{ + int x, hyp; + x = Param[0]->Val->Integer; + hyp = Param[1]->Val->Integer; + if (x > hyp) + ProgramFail(NULL, "acos(): adjacent greater than hypotenuse"); + ReturnValue->Val->Integer = acos(x, hyp); +} + +void Catan(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) // atan(y,x) +{ + int x ,y; + y = Param[0]->Val->Integer; + x = Param[1]->Val->Integer; + ReturnValue->Val->Integer = atan(y, x); +} + +void Cgps_head(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) // gps_head(lat1, lon1, lat2, lon2) +{ + int lat1, lon1, lat2, lon2; + lat1 = Param[0]->Val->Integer; + lon1 = Param[1]->Val->Integer; + lat2 = Param[2]->Val->Integer; + lon2 = Param[3]->Val->Integer; + ReturnValue->Val->Integer = gps_head(lat1, lon1, lat2, lon2); +} + +void Cgps_dist(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) // gps_dist(lat1, lon1, lat2, lon2) +{ + int lat1, lon1, lat2, lon2; + lat1 = Param[0]->Val->Integer; + lon1 = Param[1]->Val->Integer; + lat2 = Param[2]->Val->Integer; + lon2 = Param[3]->Val->Integer; + ReturnValue->Val->Integer = gps_dist(lat1, lon1, lat2, lon2); +} + +void Csqrt(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) // sqrt(x) +{ + int x; + x = Param[0]->Val->Integer; + ReturnValue->Val->Integer = isqrt(x); +} + +void Cnnset(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) { + int ix, i1; + + ix = Param[0]->Val->Integer; + if (ix > NUM_NPATTERNS) + ProgramFail(NULL, "nnset(): invalid index"); + for (i1=0; i1<8; i1++) + npattern[ix*8 + i1] = (unsigned char)Param[i1+1]->Val->Integer; +} + +void Cnnshow(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) { + int ix; + + ix = Param[0]->Val->Integer; + if (ix > NUM_NPATTERNS) + ProgramFail(NULL, "nnshow(): invalid index"); + nndisplay(ix); +} + +void Cnninit(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) { + nninit_network(); +} + +void Cnntrain(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) { + int ix, i1; + + nntrain_network(10000); + for (ix=0; ixVal->Integer; + for (i2=0; i2<8; i2++) { + if (ch & nmask[i2]) + N_IN(ix++) = 1024; + else + N_IN(ix++) = 0; + } + } + nncalculate_network(); + ix = 0; + max = 0; + for (i1=0; i1Val->Integer = ix; +} + +void Cnnmatchblob(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) { + int ix, i1, max; + + ix = Param[0]->Val->Integer; + if (ix > MAX_BLOBS) + ProgramFail(NULL, "nnmatchblob(): invalid blob index"); + if (!blobcnt[ix]) + ProgramFail(NULL, "nnmatchblob(): not a valid blob"); + /* use data still in blob_buf[] (FRAME_BUF3) + square the aspect ratio of x1, x2, y1, y2 + then subsample blob pixels to populate N_IN(0:63) with 0:1024 values + then nncalculate_network() and display the N_OUT() results */ + nnscale8x8((unsigned char *)FRAME_BUF3, blobix[ix], blobx1[ix], blobx2[ix], + bloby1[ix], bloby2[ix], imgWidth, imgHeight); + nncalculate_network(); + ix = 0; + max = 0; + for (i1=0; i1Val->Integer = ix; +} + +void Cnnlearnblob (struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) { + int ix; + + ix = Param[0]->Val->Integer; + if (ix > NUM_NPATTERNS) + ProgramFail(NULL, "nnlearnblob(): invalid index"); + if (!blobcnt[0]) + ProgramFail(NULL, "nnlearnblob(): no blob to grab"); + nnscale8x8((unsigned char *)FRAME_BUF3, blobix[0], blobx1[0], blobx2[0], + bloby1[0], bloby2[0], imgWidth, imgHeight); + nnpack8x8(ix); + nndisplay(ix); +} + +void Cautorun (struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) { + int ix, t0; + unsigned char ch; + + ix = Param[0]->Val->Integer; + t0 = readRTC(); + while (readRTC() < (t0 + ix*1000)) { // watch for ESC in 'ix' seconds + if (getchar(&ch)) { + if (ch == 0x1B) { // if ESC found, exit picoC + printf("found ESC\r\n"); + PlatformExit(0); + } + } + } +} + +void Clineno (struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) { + ReturnValue->Val->Integer = Parser->Line; +} + +void Cerrormsg (struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) { + PlatformErrorPrefix(Parser); + LibPrintf(Parser, ReturnValue, Param, NumArgs); +} + +/* list of all library functions and their prototypes */ +struct LibraryFunction PlatformLibrary[] = +{ + { Csignal, "int signal();" }, + { Csignal1, "int signal1();" }, + { Cinput, "int input();" }, + { Cinput1, "int input1();" }, + { Cinit_uart1, "void init_uart1(int);" }, + { Cread_int, "int read_int();" }, + { Cread_str, "int read_str(char *);" }, + { Coutput, "void output(int);" }, + { Coutput1, "void output1(int);" }, + { Cdelay, "void delay(int);" }, + { Crand, "int rand(int);" }, + { Ctime, "int time();" }, + { Ciodir, "void iodir(int);" }, + { Cioread, "int ioread();" }, + { Ciowrite, "void iowrite(int);" }, + { Cpeek, "int peek(int, int);" }, + { Cpoke, "void poke(int, int, int);" }, + { Cmotors, "void motors(int, int);" }, + { Cmotors2, "void motors2(int, int);" }, + { Cmotorx, "void motorx(int, int);" }, + { Cservos, "void servos(int, int);" }, + { Cservos2, "void servos2(int, int);" }, + { Cencoders, "void encoders();" }, + { Cencoderx, "int encoderx(int);" }, + { Claser, "void laser(int);" }, + { Csonar, "int sonar(int);" }, + { Crange, "int range();" }, + { Cbattery, "int battery();" }, + { Cvcolor, "void vcolor(int, int, int, int, int, int, int);" }, + { Cvfind, "int vfind(int, int, int, int, int);" }, + { Cvcam, "void vcam(int);" }, + { Cvcap, "void vcap();" }, + { Cvrcap, "void vrcap();" }, + { Cvdiff, "void vdiff(int);" }, + { Cvpix, "void vpix(int, int);" }, + { Cvscan, "int vscan(int, int);" }, + { Cvmean, "void vmean();" }, + { Cvblob, "int vblob(int, int);" }, + { Cvjpeg, "int vjpeg(int);" }, + { Cvsend, "void vsend(int);" }, + { Ccompass, "int compass();" }, + { Ccompassx, "int compassx();" }, + { Ccompassxcal, "void compassxcal(int, int, int, int, int);" }, + { Canalog, "int analog(int);" }, + { Canalogx, "int analogx(int);" }, + { Ctilt, "int tilt(int);" }, + { Cgps, "void gps();" }, + { Creadi2c, "int readi2c(int, int);" }, + { Creadi2c2, "int readi2c2(int, int);" }, + { Cwritei2c, "void writei2c(int, int, int);" }, + { Cabs, "int abs(int);" }, + { Csin, "int sin(int);" }, + { Ccos, "int cos(int);" }, + { Ctan, "int tan(int);" }, + { Casin, "int asin(int, int);" }, + { Cacos, "int acos(int, int);" }, + { Catan, "int atan(int, int);" }, + { Cgps_head, "int gps_head(int, int, int, int);" }, + { Cgps_dist, "int gps_dist(int, int, int, int);" }, + { Csqrt, "int sqrt(int);" }, + { Cnnshow, "void nnshow(int);" }, + { Cnnset, "void nnset(int, int, int, int, int, int, int, int, int);" }, + { Cnninit, "void nninit();" }, + { Cnntrain, "void nntrain();" }, + { Cnntest, "int nntest(int, int, int, int, int, int, int, int);" }, + { Cnnmatchblob, "int nnmatchblob(int);" }, + { Cnnlearnblob, "void nnlearnblob(int);" }, + { Cautorun, "void autorun(int);" }, + { Clineno, "int lineno();" }, + { Cerrormsg, "void errormsg(char *);" }, + { NULL, NULL } +}; + diff --git a/src/cmd/picoc/platform/library_unix.c b/src/cmd/picoc/platform/library_unix.c new file mode 100644 index 0000000..0308702 --- /dev/null +++ b/src/cmd/picoc/platform/library_unix.c @@ -0,0 +1,29 @@ +#include "../interpreter.h" + +void UnixSetupFunc() +{ +} + +void Ctest (struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + printf("test(%d)\n", Param[0]->Val->Integer); + Param[0]->Val->Integer = 1234; +} + +void Clineno (struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) +{ + ReturnValue->Val->Integer = Parser->Line; +} + +/* list of all library functions and their prototypes */ +struct LibraryFunction UnixFunctions[] = +{ + { Ctest, "void test(int);" }, + { Clineno, "int lineno();" }, + { NULL, NULL } +}; + +void PlatformLibraryInit() +{ + IncludeRegister("picoc_unix.h", &UnixSetupFunc, &UnixFunctions[0], NULL); +} diff --git a/src/cmd/picoc/platform/platform_ffox.c b/src/cmd/picoc/platform/platform_ffox.c new file mode 100644 index 0000000..ea7bd7e --- /dev/null +++ b/src/cmd/picoc/platform/platform_ffox.c @@ -0,0 +1,51 @@ +#include "../interpreter.h" + +/* deallocate any storage */ +void PlatformCleanup() +{ +} + +/* get a line of interactive input */ +char *PlatformGetLine(char *Buf, int MaxLen) +{ + // XXX - unimplemented so far + return NULL; +} + +/* get a character of interactive input */ +int PlatformGetCharacter() +{ + // XXX - unimplemented so far + return 0; +} + +/* write a character to the console */ +void PlatformPutc(unsigned char OutCh, union OutputStreamInfo *Stream) +{ + // XXX - unimplemented so far +} + +/* read a file into memory */ +char *PlatformReadFile(const char *FileName) +{ + // XXX - unimplemented so far + return NULL; +} + +/* read and scan a file for definitions */ +void PlatformScanFile(const char *FileName) +{ + char *SourceStr = PlatformReadFile(FileName); + Parse(FileName, SourceStr, strlen(SourceStr), TRUE); + //free(SourceStr); +} + +/* mark where to end the program for platforms which require this */ +jmp_buf ExitBuf; + +/* exit the program */ +void PlatformExit() +{ + longjmp(ExitBuf, 1); +} + diff --git a/src/cmd/picoc/platform/platform_msvc.c b/src/cmd/picoc/platform/platform_msvc.c new file mode 100644 index 0000000..14718aa --- /dev/null +++ b/src/cmd/picoc/platform/platform_msvc.c @@ -0,0 +1,80 @@ +#include "../picoc.h" +#include "../interpreter.h" + +/* mark where to end the program for platforms which require this */ +jmp_buf PicocExitBuf; + +void PlatformInit() +{ +} + +void PlatformCleanup() +{ +} + +/* get a line of interactive input */ +char *PlatformGetLine(char *Buf, int MaxLen, const char *Prompt) +{ + if (Prompt != NULL) + printf("%s", Prompt); + + fflush(stdout); + return fgets(Buf, MaxLen, stdin); +} + +/* get a character of interactive input */ +int PlatformGetCharacter() +{ + fflush(stdout); + return getchar(); +} + +/* write a character to the console */ +void PlatformPutc(unsigned char OutCh, union OutputStreamInfo *Stream) +{ + putchar(OutCh); +} + +/* read a file into memory */ +char *PlatformReadFile(const char *FileName) +{ + struct stat FileInfo; + char *ReadText; + FILE *InFile; + int BytesRead; + + if (stat(FileName, &FileInfo)) + ProgramFail(NULL, "can't read file %s\n", FileName); + + ReadText = malloc(FileInfo.st_size + 1); + if (ReadText == NULL) + ProgramFail(NULL, "out of memory\n"); + + InFile = fopen(FileName, "r"); + if (InFile == NULL) + ProgramFail(NULL, "can't read file %s\n", FileName); + + BytesRead = fread(ReadText, 1, FileInfo.st_size, InFile); + if (BytesRead == 0) + ProgramFail(NULL, "can't read file %s\n", FileName); + + ReadText[BytesRead] = '\0'; + fclose(InFile); + + return ReadText; +} + +/* read and scan a file for definitions */ +void PicocPlatformScanFile(const char *FileName) +{ + char *SourceStr = PlatformReadFile(FileName); + + PicocParse(FileName, SourceStr, strlen(SourceStr), TRUE, FALSE, TRUE, TRUE); +} + +/* exit the program */ +void PlatformExit(int RetVal) +{ + PicocExitValue = RetVal; + longjmp(PicocExitBuf, 1); +} diff --git a/src/cmd/picoc/platform/platform_surveyor.c b/src/cmd/picoc/platform/platform_surveyor.c new file mode 100644 index 0000000..1557747 --- /dev/null +++ b/src/cmd/picoc/platform/platform_surveyor.c @@ -0,0 +1,71 @@ +#include "../interpreter.h" +#include "../picoc.h" + +/* mark where to end the program for platforms which require this */ +int PicocExitBuf[41]; + +/* deallocate any storage */ +void PlatformCleanup() +{ +} + +/* get a line of interactive input */ +char *PlatformGetLine(char *Buf, int MaxLen, const char *Prompt) +{ + int ix; + char ch, *cp; + + printf(Prompt); + + ix = 0; + cp = 0; + + // If the first character is \n or \r, eat it + ch = getch(); + if (ch == '\n' || ch == '\r') + { + // And get the next character + ch = getch(); + } + + while (ix++ < MaxLen) { + + if (ch == 0x1B || ch == 0x03) { // ESC character or ctrl-c (to avoid problem with TeraTerm) - exit + printf("Leaving PicoC\n"); + return NULL; + } + if (ch == '\n') { + *cp++ = '\n'; // if newline, send newline character followed by null + *cp = 0; + return Buf; + } + *cp++ = ch; + ix++; + ch = getch(); + } + return NULL; +} + +/* write a character to the console */ +void PlatformPutc(unsigned char OutCh, union OutputStreamInfo *Stream) +{ + if (OutCh == '\n') + putchar('\r'); + + putchar(OutCh); +} + +/* read a character */ +int PlatformGetCharacter() +{ + return getch(); +} + +/* exit the program */ +void PlatformExit(int RetVal) +{ + PicocExitValue = RetVal; + PicocExitBuf[40] = 1; + longjmp(PicocExitBuf, 1); +} + diff --git a/src/cmd/picoc/platform/platform_unix.c b/src/cmd/picoc/platform/platform_unix.c new file mode 100644 index 0000000..ac65d32 --- /dev/null +++ b/src/cmd/picoc/platform/platform_unix.c @@ -0,0 +1,137 @@ +#include "../picoc.h" +#include "../interpreter.h" + +#ifdef USE_READLINE +#include +#include +#endif + +/* mark where to end the program for platforms which require this */ +jmp_buf PicocExitBuf; + +#ifndef NO_DEBUGGER +#include + +static void BreakHandler(int Signal) +{ + PlatformPrintf("break\n"); + DebugManualBreak = TRUE; +} + +void PlatformInit() +{ + /* capture the break signal and pass it to the debugger */ + signal(SIGINT, BreakHandler); +} +#else +void PlatformInit() +{ +} +#endif + +void PlatformCleanup() +{ +} + +/* get a line of interactive input */ +char *PlatformGetLine(char *Buf, int MaxLen, const char *Prompt) +{ +#ifdef USE_READLINE + if (Prompt != NULL) + { + /* use GNU readline to read the line */ + char *InLine = readline(Prompt); + if (InLine == NULL) + return NULL; + + Buf[MaxLen] = '\0'; + strncpy(Buf, InLine, MaxLen-1); + strncat(Buf, "\n", MaxLen-1); + + if (InLine[0] != '\0') + add_history(InLine); + + free(InLine); + return Buf; + } +#endif + + if (Prompt != NULL) + printf("%s", Prompt); + + fflush(stdout); + return fgets(Buf, MaxLen, stdin); +} + +/* get a character of interactive input */ +int PlatformGetCharacter() +{ + fflush(stdout); + return getchar(); +} + +/* write a character to the console */ +void PlatformPutc(unsigned char OutCh, union OutputStreamInfo *Stream) +{ + putchar(OutCh); +} + +/* read a file into memory */ +char *PlatformReadFile(const char *FileName) +{ + struct stat FileInfo; + char *ReadText; + FILE *InFile; + int BytesRead; + char *p; + + if (stat(FileName, &FileInfo)) + ProgramFail(NULL, "can't read file %s\n", FileName); + + ReadText = malloc(FileInfo.st_size + 1); + if (ReadText == NULL) + ProgramFail(NULL, "out of memory\n"); + + InFile = fopen(FileName, "r"); + if (InFile == NULL) + ProgramFail(NULL, "can't read file %s\n", FileName); + + BytesRead = fread(ReadText, 1, FileInfo.st_size, InFile); + if (BytesRead == 0) + ProgramFail(NULL, "can't read file %s\n", FileName); + + ReadText[BytesRead] = '\0'; + fclose(InFile); + + if ((ReadText[0] == '#') && (ReadText[1] == '!')) + { + for (p = ReadText; (*p != '\r') && (*p != '\n'); ++p) + { + *p = ' '; + } + } + + return ReadText; +} + +/* read and scan a file for definitions */ +void PicocPlatformScanFile(const char *FileName) +{ + char *SourceStr = PlatformReadFile(FileName); + + /* ignore "#!/path/to/picoc" .. by replacing the "#!" with "//" */ + if (SourceStr != NULL && SourceStr[0] == '#' && SourceStr[1] == '!') + { + SourceStr[0] = '/'; + SourceStr[1] = '/'; + } + + PicocParse(FileName, SourceStr, strlen(SourceStr), TRUE, FALSE, TRUE, TRUE); +} + +/* exit the program */ +void PlatformExit(int RetVal) +{ + PicocExitValue = RetVal; + longjmp(PicocExitBuf, 1); +} diff --git a/src/cmd/picoc/retrobsd.c b/src/cmd/picoc/retrobsd.c new file mode 100644 index 0000000..ff5459c --- /dev/null +++ b/src/cmd/picoc/retrobsd.c @@ -0,0 +1,20 @@ +#include +#include + +/* Fixes for RetroBSD missing functions */ + +static const double one = 1.0, Zero[] = {0.0, -0.0,}; + + +int fgetpos(FILE *stream, int *pos) +{ + *pos = ftell(stream); + return *pos; +} + +int fsetpos(FILE *stream, int *pos) +{ + fseek(stream,SEEK_SET,*pos); + return *pos; +} + diff --git a/src/cmd/picoc/table.c b/src/cmd/picoc/table.c new file mode 100644 index 0000000..c051925 --- /dev/null +++ b/src/cmd/picoc/table.c @@ -0,0 +1,190 @@ +/* picoc hash table module. This hash table code is used for both symbol tables + * and the shared string table. */ + +#include "interpreter.h" + +struct Table StringTable; +struct TableEntry *StringHashTable[STRING_TABLE_SIZE]; +char *StrEmpty = NULL; + +/* initialise the shared string system */ +void TableInit() +{ + TableInitTable(&StringTable, &StringHashTable[0], STRING_TABLE_SIZE, TRUE); + StrEmpty = TableStrRegister(""); +} + +/* hash function for strings */ +static unsigned int TableHash(const char *Key, int Len) +{ + unsigned int Hash = Len; + int Offset; + int Count; + + for (Count = 0, Offset = 8; Count < Len; Count++, Offset+=7) + { + if (Offset > sizeof(unsigned int) * 8 - 7) + Offset -= sizeof(unsigned int) * 8 - 6; + + Hash ^= *Key++ << Offset; + } + + return Hash; +} + +/* initialise a table */ +void TableInitTable(struct Table *Tbl, struct TableEntry **HashTable, int Size, int OnHeap) +{ + Tbl->Size = Size; + Tbl->OnHeap = OnHeap; + Tbl->HashTable = HashTable; + memset((void *)HashTable, '\0', sizeof(struct TableEntry *) * Size); +} + +/* check a hash table entry for a key */ +static struct TableEntry *TableSearch(struct Table *Tbl, const char *Key, int *AddAt) +{ + struct TableEntry *Entry; + int HashValue = ((unsigned long)Key) % Tbl->Size; /* shared strings have unique addresses so we don't need to hash them */ + + for (Entry = Tbl->HashTable[HashValue]; Entry != NULL; Entry = Entry->Next) + { + if (Entry->p.v.Key == Key) + return Entry; /* found */ + } + + *AddAt = HashValue; /* didn't find it in the chain */ + return NULL; +} + +/* set an identifier to a value. returns FALSE if it already exists. + * Key must be a shared string from TableStrRegister() */ +int TableSet(struct Table *Tbl, char *Key, struct Value *Val, const char *DeclFileName, int DeclLine, int DeclColumn) +{ + int AddAt; + struct TableEntry *FoundEntry = TableSearch(Tbl, Key, &AddAt); + + if (FoundEntry == NULL) + { /* add it to the table */ + struct TableEntry *NewEntry = VariableAlloc(NULL, sizeof(struct TableEntry), Tbl->OnHeap); + NewEntry->DeclFileName = DeclFileName; + NewEntry->DeclLine = DeclLine; + NewEntry->DeclColumn = DeclColumn; + NewEntry->p.v.Key = Key; + NewEntry->p.v.Val = Val; + NewEntry->Next = Tbl->HashTable[AddAt]; + Tbl->HashTable[AddAt] = NewEntry; + return TRUE; + } + + return FALSE; +} + +/* find a value in a table. returns FALSE if not found. + * Key must be a shared string from TableStrRegister() */ +int TableGet(struct Table *Tbl, const char *Key, struct Value **Val, const char **DeclFileName, int *DeclLine, int *DeclColumn) +{ + int AddAt; + struct TableEntry *FoundEntry = TableSearch(Tbl, Key, &AddAt); + if (FoundEntry == NULL) + return FALSE; + + *Val = FoundEntry->p.v.Val; + + if (DeclFileName != NULL) + { + *DeclFileName = FoundEntry->DeclFileName; + *DeclLine = FoundEntry->DeclLine; + *DeclColumn = FoundEntry->DeclColumn; + } + + return TRUE; +} + +/* remove an entry from the table */ +struct Value *TableDelete(struct Table *Tbl, const char *Key) +{ + struct TableEntry **EntryPtr; + int HashValue = ((unsigned long)Key) % Tbl->Size; /* shared strings have unique addresses so we don't need to hash them */ + + for (EntryPtr = &Tbl->HashTable[HashValue]; *EntryPtr != NULL; EntryPtr = &(*EntryPtr)->Next) + { + if ((*EntryPtr)->p.v.Key == Key) + { + struct TableEntry *DeleteEntry = *EntryPtr; + struct Value *Val = DeleteEntry->p.v.Val; + *EntryPtr = DeleteEntry->Next; + HeapFreeMem(DeleteEntry); + + return Val; + } + } + + return NULL; +} + +/* check a hash table entry for an identifier */ +static struct TableEntry *TableSearchIdentifier(struct Table *Tbl, const char *Key, int Len, int *AddAt) +{ + struct TableEntry *Entry; + int HashValue = TableHash(Key, Len) % Tbl->Size; + + for (Entry = Tbl->HashTable[HashValue]; Entry != NULL; Entry = Entry->Next) + { + if (strncmp(&Entry->p.Key[0], (char *)Key, Len) == 0 && Entry->p.Key[Len] == '\0') + return Entry; /* found */ + } + + *AddAt = HashValue; /* didn't find it in the chain */ + return NULL; +} + +/* set an identifier and return the identifier. share if possible */ +char *TableSetIdentifier(struct Table *Tbl, const char *Ident, int IdentLen) +{ + int AddAt; + struct TableEntry *FoundEntry = TableSearchIdentifier(Tbl, Ident, IdentLen, &AddAt); + + if (FoundEntry != NULL) + return &FoundEntry->p.Key[0]; + else + { /* add it to the table - we economise by not allocating the whole structure here */ + struct TableEntry *NewEntry = HeapAllocMem(sizeof(struct TableEntry) - sizeof(union TableEntryPayload) + IdentLen + 1); + if (NewEntry == NULL) + ProgramFail(NULL, "out of memory"); + + strncpy((char *)&NewEntry->p.Key[0], (char *)Ident, IdentLen); + NewEntry->p.Key[IdentLen] = '\0'; + NewEntry->Next = Tbl->HashTable[AddAt]; + Tbl->HashTable[AddAt] = NewEntry; + return &NewEntry->p.Key[0]; + } +} + +/* register a string in the shared string store */ +char *TableStrRegister2(const char *Str, int Len) +{ + return TableSetIdentifier(&StringTable, Str, Len); +} + +char *TableStrRegister(const char *Str) +{ + return TableStrRegister2(Str, strlen((char *)Str)); +} + +/* free all the strings */ +void TableStrFree() +{ + struct TableEntry *Entry; + struct TableEntry *NextEntry; + int Count; + + for (Count = 0; Count < StringTable.Size; Count++) + { + for (Entry = StringTable.HashTable[Count]; Entry != NULL; Entry = NextEntry) + { + NextEntry = Entry->Next; + HeapFreeMem(Entry); + } + } +} diff --git a/src/cmd/picoc/tests/00_assignment.c b/src/cmd/picoc/tests/00_assignment.c new file mode 100644 index 0000000..56738ba --- /dev/null +++ b/src/cmd/picoc/tests/00_assignment.c @@ -0,0 +1,13 @@ +#include + +int a; +a = 42; +printf("%d\n", a); + +int b = 64; +printf("%d\n", b); + +int c = 12, d = 34; +printf("%d, %d\n", c, d); + +void main() {} diff --git a/src/cmd/picoc/tests/00_assignment.expect b/src/cmd/picoc/tests/00_assignment.expect new file mode 100644 index 0000000..d4407f3 --- /dev/null +++ b/src/cmd/picoc/tests/00_assignment.expect @@ -0,0 +1,3 @@ +42 +64 +12, 34 diff --git a/src/cmd/picoc/tests/01_comment.c b/src/cmd/picoc/tests/01_comment.c new file mode 100644 index 0000000..ce8d687 --- /dev/null +++ b/src/cmd/picoc/tests/01_comment.c @@ -0,0 +1,10 @@ +#include + +printf("Hello\n"); +printf("Hello\n"); /* this is a comment */ printf("Hello\n"); +printf("Hello\n"); +// this is also a comment sayhello(); +printf("Hello\n"); + + +void main() {} diff --git a/src/cmd/picoc/tests/01_comment.expect b/src/cmd/picoc/tests/01_comment.expect new file mode 100644 index 0000000..b1387ad --- /dev/null +++ b/src/cmd/picoc/tests/01_comment.expect @@ -0,0 +1,5 @@ +Hello +Hello +Hello +Hello +Hello diff --git a/src/cmd/picoc/tests/02_printf.c b/src/cmd/picoc/tests/02_printf.c new file mode 100644 index 0000000..f779c1e --- /dev/null +++ b/src/cmd/picoc/tests/02_printf.c @@ -0,0 +1,13 @@ +#include + +printf("Hello world\n"); + +int Count; +for (Count = -5; Count <= 5; Count++) + printf("Count = %d\n", Count); + +printf("String 'hello', 'there' is '%s', '%s'\n", "hello", "there"); +printf("Character 'A' is '%c'\n", 65); +printf("Character 'a' is '%c'\n", 'a'); + +void main() {} diff --git a/src/cmd/picoc/tests/02_printf.expect b/src/cmd/picoc/tests/02_printf.expect new file mode 100644 index 0000000..f67a0f6 --- /dev/null +++ b/src/cmd/picoc/tests/02_printf.expect @@ -0,0 +1,15 @@ +Hello world +Count = -5 +Count = -4 +Count = -3 +Count = -2 +Count = -1 +Count = 0 +Count = 1 +Count = 2 +Count = 3 +Count = 4 +Count = 5 +String 'hello', 'there' is 'hello', 'there' +Character 'A' is 'A' +Character 'a' is 'a' diff --git a/src/cmd/picoc/tests/03_struct.c b/src/cmd/picoc/tests/03_struct.c new file mode 100644 index 0000000..079622d --- /dev/null +++ b/src/cmd/picoc/tests/03_struct.c @@ -0,0 +1,21 @@ +#include + +struct fred +{ + int boris; + int natasha; +}; + +struct fred bloggs; + +bloggs.boris = 12; +bloggs.natasha = 34; + +printf("%d\n", bloggs.boris); +printf("%d\n", bloggs.natasha); + +//struct fred jones[2]; +//jones[0].boris = 12; +//jones[0].natasha = 34; + +void main() {} diff --git a/src/cmd/picoc/tests/03_struct.expect b/src/cmd/picoc/tests/03_struct.expect new file mode 100644 index 0000000..8e994dd --- /dev/null +++ b/src/cmd/picoc/tests/03_struct.expect @@ -0,0 +1,2 @@ +12 +34 diff --git a/src/cmd/picoc/tests/04_for.c b/src/cmd/picoc/tests/04_for.c new file mode 100644 index 0000000..de563b5 --- /dev/null +++ b/src/cmd/picoc/tests/04_for.c @@ -0,0 +1,10 @@ +#include + +int Count; + +for (Count = 1; Count <= 10; Count++) +{ + printf("%d\n", Count); +} + +void main() {} diff --git a/src/cmd/picoc/tests/04_for.expect b/src/cmd/picoc/tests/04_for.expect new file mode 100644 index 0000000..f00c965 --- /dev/null +++ b/src/cmd/picoc/tests/04_for.expect @@ -0,0 +1,10 @@ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 diff --git a/src/cmd/picoc/tests/05_array.c b/src/cmd/picoc/tests/05_array.c new file mode 100644 index 0000000..03dac05 --- /dev/null +++ b/src/cmd/picoc/tests/05_array.c @@ -0,0 +1,16 @@ +#include + +int Count; +int Array[10]; + +for (Count = 1; Count <= 10; Count++) +{ + Array[Count-1] = Count * Count; +} + +for (Count = 0; Count < 10; Count++) +{ + printf("%d\n", Array[Count]); +} + +void main() {} diff --git a/src/cmd/picoc/tests/05_array.expect b/src/cmd/picoc/tests/05_array.expect new file mode 100644 index 0000000..bc7257c --- /dev/null +++ b/src/cmd/picoc/tests/05_array.expect @@ -0,0 +1,10 @@ +1 +4 +9 +16 +25 +36 +49 +64 +81 +100 diff --git a/src/cmd/picoc/tests/06_case.c b/src/cmd/picoc/tests/06_case.c new file mode 100644 index 0000000..1858205 --- /dev/null +++ b/src/cmd/picoc/tests/06_case.c @@ -0,0 +1,24 @@ +#include + +int Count; + +for (Count = 0; Count < 4; Count++) +{ + printf("%d\n", Count); + switch (Count) + { + case 1: + printf("%d\n", 1); + break; + + case 2: + printf("%d\n", 2); + break; + + default: + printf("%d\n", 0); + break; + } +} + +void main() {} diff --git a/src/cmd/picoc/tests/06_case.expect b/src/cmd/picoc/tests/06_case.expect new file mode 100644 index 0000000..fab2c20 --- /dev/null +++ b/src/cmd/picoc/tests/06_case.expect @@ -0,0 +1,8 @@ +0 +0 +1 +1 +2 +2 +3 +0 diff --git a/src/cmd/picoc/tests/07_function.c b/src/cmd/picoc/tests/07_function.c new file mode 100644 index 0000000..0501380 --- /dev/null +++ b/src/cmd/picoc/tests/07_function.c @@ -0,0 +1,25 @@ +#include + +int myfunc(int x) +{ + return x * x; +} + +printf("%d\n", myfunc(3)); +printf("%d\n", myfunc(4)); + +void vfunc(int a) +{ + printf("a=%d\n", a); +} + +vfunc(1234); + +void qfunc() +{ + printf("qfunc()\n"); +} + +qfunc(); + +void main() {} diff --git a/src/cmd/picoc/tests/07_function.expect b/src/cmd/picoc/tests/07_function.expect new file mode 100644 index 0000000..8ffb0a7 --- /dev/null +++ b/src/cmd/picoc/tests/07_function.expect @@ -0,0 +1,4 @@ +9 +16 +a=1234 +qfunc() diff --git a/src/cmd/picoc/tests/08_while.c b/src/cmd/picoc/tests/08_while.c new file mode 100644 index 0000000..aee79ba --- /dev/null +++ b/src/cmd/picoc/tests/08_while.c @@ -0,0 +1,19 @@ +#include + +int a; +int p; +int t; + +a = 1; +p = 0; +t = 0; + +while (a < 100) +{ + printf("%d\n", a); + t = a; + a = t + p; + p = t; +} + +void main() {} diff --git a/src/cmd/picoc/tests/08_while.expect b/src/cmd/picoc/tests/08_while.expect new file mode 100644 index 0000000..702d4c0 --- /dev/null +++ b/src/cmd/picoc/tests/08_while.expect @@ -0,0 +1,11 @@ +1 +1 +2 +3 +5 +8 +13 +21 +34 +55 +89 diff --git a/src/cmd/picoc/tests/09_do_while.c b/src/cmd/picoc/tests/09_do_while.c new file mode 100644 index 0000000..e55b83a --- /dev/null +++ b/src/cmd/picoc/tests/09_do_while.c @@ -0,0 +1,20 @@ +#include + +int a; +int p; +int t; + +a = 1; +p = 0; +t = 0; + +do +{ + printf("%d\n", a); + t = a; + a = t + p; + p = t; +} while (a < 100); + + +void main() {} diff --git a/src/cmd/picoc/tests/09_do_while.expect b/src/cmd/picoc/tests/09_do_while.expect new file mode 100644 index 0000000..702d4c0 --- /dev/null +++ b/src/cmd/picoc/tests/09_do_while.expect @@ -0,0 +1,11 @@ +1 +1 +2 +3 +5 +8 +13 +21 +34 +55 +89 diff --git a/src/cmd/picoc/tests/10_pointer.c b/src/cmd/picoc/tests/10_pointer.c new file mode 100644 index 0000000..1bd40e3 --- /dev/null +++ b/src/cmd/picoc/tests/10_pointer.c @@ -0,0 +1,37 @@ +#include + +int a; +int *b; +int c; + +a = 42; +b = &a; +printf("a = %d\n", *b); + +struct ziggy +{ + int a; + int b; + int c; +} bolshevic; + +bolshevic.a = 12; +bolshevic.b = 34; +bolshevic.c = 56; + +printf("bolshevic.a = %d\n", bolshevic.a); +printf("bolshevic.b = %d\n", bolshevic.b); +printf("bolshevic.c = %d\n", bolshevic.c); + +struct ziggy *tsar = &bolshevic; + +printf("tsar->a = %d\n", tsar->a); +printf("tsar->b = %d\n", tsar->b); +printf("tsar->c = %d\n", tsar->c); + +/* +b = &(bolshevic.b); +printf("bolshevic.b = %d\n", *b); +*/ + +void main() {} diff --git a/src/cmd/picoc/tests/10_pointer.expect b/src/cmd/picoc/tests/10_pointer.expect new file mode 100644 index 0000000..97116c0 --- /dev/null +++ b/src/cmd/picoc/tests/10_pointer.expect @@ -0,0 +1,7 @@ +a = 42 +bolshevic.a = 12 +bolshevic.b = 34 +bolshevic.c = 56 +tsar->a = 12 +tsar->b = 34 +tsar->c = 56 diff --git a/src/cmd/picoc/tests/11_precedence.c b/src/cmd/picoc/tests/11_precedence.c new file mode 100644 index 0000000..f7a4bda --- /dev/null +++ b/src/cmd/picoc/tests/11_precedence.c @@ -0,0 +1,38 @@ +#include + +int a; +int b; +int c; +int d; +int e; +int f; +int x; +int y; + +a = 12; +b = 34; +c = 56; +d = 78; +e = 0; +f = 1; + +printf("%d\n", c + d); +printf("%d\n", (y = c + d)); +/* printf("%d\n", a ? b+c : c+d); +printf("%d\n", a ? b+c : c+d); +printf("%d\n", a || b ? b+c : c+d); */ +printf("%d\n", e || e && f); +printf("%d\n", e || f && f); +printf("%d\n", e && e || f); +printf("%d\n", e && f || f); +printf("%d\n", a && f | f); +printf("%d\n", a | b ^ c & d); +printf("%d, %d\n", a == a, a == b); +printf("%d, %d\n", a != a, a != b); +printf("%d\n", a != b && c != d); +printf("%d\n", a + b * c / f); +printf("%d\n", a + b * c / f); +printf("%d\n", (4 << 4)); +printf("%d\n", (64 >> 4)); + +void main() {} diff --git a/src/cmd/picoc/tests/11_precedence.expect b/src/cmd/picoc/tests/11_precedence.expect new file mode 100644 index 0000000..b692396 --- /dev/null +++ b/src/cmd/picoc/tests/11_precedence.expect @@ -0,0 +1,15 @@ +134 +134 +0 +1 +1 +1 +1 +46 +1, 0 +0, 1 +1 +1916 +1916 +64 +4 diff --git a/src/cmd/picoc/tests/12_hashdefine.c b/src/cmd/picoc/tests/12_hashdefine.c new file mode 100644 index 0000000..6ffaf3f --- /dev/null +++ b/src/cmd/picoc/tests/12_hashdefine.c @@ -0,0 +1,10 @@ +#include + +#define FRED 12 +#define BLOGGS(x) (12*(x)) + +printf("%d\n", FRED); +printf("%d, %d, %d\n", BLOGGS(1), BLOGGS(2), BLOGGS(3)); + + +void main() {} diff --git a/src/cmd/picoc/tests/12_hashdefine.expect b/src/cmd/picoc/tests/12_hashdefine.expect new file mode 100644 index 0000000..99f2ed5 --- /dev/null +++ b/src/cmd/picoc/tests/12_hashdefine.expect @@ -0,0 +1,2 @@ +12 +12, 24, 36 diff --git a/src/cmd/picoc/tests/13_integer_literals.c b/src/cmd/picoc/tests/13_integer_literals.c new file mode 100644 index 0000000..f021de2 --- /dev/null +++ b/src/cmd/picoc/tests/13_integer_literals.c @@ -0,0 +1,16 @@ +#include + +int a = 24680; +int b = 01234567; +int c = 0x2468ac; +int d = 0x2468AC; +int e = 0b010101010101; + +printf("%d\n", a); +printf("%d\n", b); +printf("%d\n", c); +printf("%d\n", d); +printf("%d\n", e); + + +void main() {} diff --git a/src/cmd/picoc/tests/13_integer_literals.expect b/src/cmd/picoc/tests/13_integer_literals.expect new file mode 100644 index 0000000..f5aca06 --- /dev/null +++ b/src/cmd/picoc/tests/13_integer_literals.expect @@ -0,0 +1,5 @@ +24680 +342391 +2386092 +2386092 +1365 diff --git a/src/cmd/picoc/tests/14_if.c b/src/cmd/picoc/tests/14_if.c new file mode 100644 index 0000000..bb56ef4 --- /dev/null +++ b/src/cmd/picoc/tests/14_if.c @@ -0,0 +1,17 @@ +#include + +int a = 1; + +if (a) + printf("a is true\n"); +else + printf("a is false\n"); + +int b = 0; +if (b) + printf("b is true\n"); +else + printf("b is false\n"); + + +void main() {} diff --git a/src/cmd/picoc/tests/14_if.expect b/src/cmd/picoc/tests/14_if.expect new file mode 100644 index 0000000..c32c415 --- /dev/null +++ b/src/cmd/picoc/tests/14_if.expect @@ -0,0 +1,2 @@ +a is true +b is false diff --git a/src/cmd/picoc/tests/15_recursion.c b/src/cmd/picoc/tests/15_recursion.c new file mode 100644 index 0000000..4733c8f --- /dev/null +++ b/src/cmd/picoc/tests/15_recursion.c @@ -0,0 +1,16 @@ +#include + +int factorial(int i) +{ + if (i < 2) + return i; + else + return i * factorial(i - 1); +} + +int Count; + +for (Count = 1; Count <= 10; Count++) + printf("%d\n", factorial(Count)); + +void main() {} diff --git a/src/cmd/picoc/tests/15_recursion.expect b/src/cmd/picoc/tests/15_recursion.expect new file mode 100644 index 0000000..db47b28 --- /dev/null +++ b/src/cmd/picoc/tests/15_recursion.expect @@ -0,0 +1,10 @@ +1 +2 +6 +24 +120 +720 +5040 +40320 +362880 +3628800 diff --git a/src/cmd/picoc/tests/16_nesting.c b/src/cmd/picoc/tests/16_nesting.c new file mode 100644 index 0000000..90a62bf --- /dev/null +++ b/src/cmd/picoc/tests/16_nesting.c @@ -0,0 +1,16 @@ +#include + +int x, y, z; + +for (x = 0; x < 2; x++) +{ + for (y = 0; y < 3; y++) + { + for (z = 0; z < 3; z++) + { + printf("%d %d %d\n", x, y, z); + } + } +} + +void main() {} diff --git a/src/cmd/picoc/tests/16_nesting.expect b/src/cmd/picoc/tests/16_nesting.expect new file mode 100644 index 0000000..625ee13 --- /dev/null +++ b/src/cmd/picoc/tests/16_nesting.expect @@ -0,0 +1,18 @@ +0 0 0 +0 0 1 +0 0 2 +0 1 0 +0 1 1 +0 1 2 +0 2 0 +0 2 1 +0 2 2 +1 0 0 +1 0 1 +1 0 2 +1 1 0 +1 1 1 +1 1 2 +1 2 0 +1 2 1 +1 2 2 diff --git a/src/cmd/picoc/tests/17_enum.c b/src/cmd/picoc/tests/17_enum.c new file mode 100644 index 0000000..f53c88c --- /dev/null +++ b/src/cmd/picoc/tests/17_enum.c @@ -0,0 +1,24 @@ +#include + +enum fred +{ + a, + b, + c, + d, + e = 54, + f = 73, + g, + h +}; + +enum fred frod; + +printf("%d %d %d %d %d %d %d %d\n", a, b, c, d, e, f, g, h); +printf("%d\n", frod); +frod = 12; +printf("%d\n", frod); +frod = e; +printf("%d\n", frod); + +void main() {} diff --git a/src/cmd/picoc/tests/17_enum.expect b/src/cmd/picoc/tests/17_enum.expect new file mode 100644 index 0000000..0c17a2d --- /dev/null +++ b/src/cmd/picoc/tests/17_enum.expect @@ -0,0 +1,4 @@ +0 1 2 3 54 73 74 75 +0 +12 +54 diff --git a/src/cmd/picoc/tests/18_include.c b/src/cmd/picoc/tests/18_include.c new file mode 100644 index 0000000..f2bfcc6 --- /dev/null +++ b/src/cmd/picoc/tests/18_include.c @@ -0,0 +1,7 @@ +#include + +printf("including\n"); +#include "18_include.h" +printf("done\n"); + +void main() {} diff --git a/src/cmd/picoc/tests/18_include.expect b/src/cmd/picoc/tests/18_include.expect new file mode 100644 index 0000000..87729df --- /dev/null +++ b/src/cmd/picoc/tests/18_include.expect @@ -0,0 +1,3 @@ +including +included +done diff --git a/src/cmd/picoc/tests/18_include.h b/src/cmd/picoc/tests/18_include.h new file mode 100644 index 0000000..01f894d --- /dev/null +++ b/src/cmd/picoc/tests/18_include.h @@ -0,0 +1 @@ +printf("included\n"); diff --git a/src/cmd/picoc/tests/19_pointer_arithmetic.c b/src/cmd/picoc/tests/19_pointer_arithmetic.c new file mode 100644 index 0000000..96c7e6a --- /dev/null +++ b/src/cmd/picoc/tests/19_pointer_arithmetic.c @@ -0,0 +1,24 @@ +#include + +int a; +int *b; +int *c; + +a = 42; +b = &a; +c = NULL; + +printf("%d\n", *b); + +if (b == NULL) + printf("b is NULL\n"); +else + printf("b is not NULL\n"); + +if (c == NULL) + printf("c is NULL\n"); +else + printf("c is not NULL\n"); + + +void main() {} diff --git a/src/cmd/picoc/tests/19_pointer_arithmetic.expect b/src/cmd/picoc/tests/19_pointer_arithmetic.expect new file mode 100644 index 0000000..0cf781b --- /dev/null +++ b/src/cmd/picoc/tests/19_pointer_arithmetic.expect @@ -0,0 +1,3 @@ +42 +b is not NULL +c is NULL diff --git a/src/cmd/picoc/tests/20_pointer_comparison.c b/src/cmd/picoc/tests/20_pointer_comparison.c new file mode 100644 index 0000000..bab1d5e --- /dev/null +++ b/src/cmd/picoc/tests/20_pointer_comparison.c @@ -0,0 +1,20 @@ +#include + +int a; +int b; +int *d; +int *e; +d = &a; +e = &b; +a = 12; +b = 34; +printf("%d\n", *d); +printf("%d\n", *e); +printf("%d\n", d == e); +printf("%d\n", d != e); +d = e; +printf("%d\n", d == e); +printf("%d\n", d != e); + + +void main() {} diff --git a/src/cmd/picoc/tests/20_pointer_comparison.expect b/src/cmd/picoc/tests/20_pointer_comparison.expect new file mode 100644 index 0000000..5d1e5f5 --- /dev/null +++ b/src/cmd/picoc/tests/20_pointer_comparison.expect @@ -0,0 +1,6 @@ +12 +34 +0 +1 +1 +0 diff --git a/src/cmd/picoc/tests/21_char_array.c b/src/cmd/picoc/tests/21_char_array.c new file mode 100644 index 0000000..0f158cd --- /dev/null +++ b/src/cmd/picoc/tests/21_char_array.c @@ -0,0 +1,29 @@ +#include + +int x = 'a'; +char y = x; + +char *a = "hello"; + +printf("%s\n", a); + +int c; +c = *a; + +char *b; +for (b = a; *b != 0; b++) + printf("%c: %d\n", *b, *b); + +char destarray[10]; +char *dest = &destarray[0]; +char *src = a; + +while (*src != 0) + *dest++ = *src++; + +*dest = 0; + +printf("copied string is %s\n", destarray); + + +void main() {} diff --git a/src/cmd/picoc/tests/21_char_array.expect b/src/cmd/picoc/tests/21_char_array.expect new file mode 100644 index 0000000..dbc6068 --- /dev/null +++ b/src/cmd/picoc/tests/21_char_array.expect @@ -0,0 +1,7 @@ +hello +h: 104 +e: 101 +l: 108 +l: 108 +o: 111 +copied string is hello diff --git a/src/cmd/picoc/tests/22_floating_point.c b/src/cmd/picoc/tests/22_floating_point.c new file mode 100644 index 0000000..37754a4 --- /dev/null +++ b/src/cmd/picoc/tests/22_floating_point.c @@ -0,0 +1,45 @@ +#include +#include + +// variables +float a = 12.34 + 56.78; +printf("%f\n", a); + +// infix operators +printf("%f\n", 12.34 + 56.78); +printf("%f\n", 12.34 - 56.78); +printf("%f\n", 12.34 * 56.78); +printf("%f\n", 12.34 / 56.78); + +// comparison operators +printf("%d %d %d %d %d %d\n", 12.34 < 56.78, 12.34 <= 56.78, 12.34 == 56.78, 12.34 >= 56.78, 12.34 > 56.78, 12.34 != 56.78); +printf("%d %d %d %d %d %d\n", 12.34 < 12.34, 12.34 <= 12.34, 12.34 == 12.34, 12.34 >= 12.34, 12.34 > 12.34, 12.34 != 12.34); +printf("%d %d %d %d %d %d\n", 56.78 < 12.34, 56.78 <= 12.34, 56.78 == 12.34, 56.78 >= 12.34, 56.78 > 12.34, 56.78 != 12.34); + +// assignment operators +a = 12.34; +a += 56.78; +printf("%f\n", a); + +a = 12.34; +a -= 56.78; +printf("%f\n", a); + +a = 12.34; +a *= 56.78; +printf("%f\n", a); + +a = 12.34; +a /= 56.78; +printf("%f\n", a); + +// prefix operators +printf("%f\n", +12.34); +printf("%f\n", -12.34); + +// type coercion +a = 2; +printf("%f\n", a); +printf("%f\n", sin(2)); + +void main() {} diff --git a/src/cmd/picoc/tests/22_floating_point.expect b/src/cmd/picoc/tests/22_floating_point.expect new file mode 100644 index 0000000..282d089 --- /dev/null +++ b/src/cmd/picoc/tests/22_floating_point.expect @@ -0,0 +1,16 @@ +69.120000 +69.120000 +-44.440000 +700.665200 +0.217330 +1 1 0 0 0 1 +0 1 1 1 0 0 +0 0 0 1 1 1 +69.120000 +-44.440000 +700.665200 +0.217330 +12.340000 +-12.340000 +2.000000 +0.909297 diff --git a/src/cmd/picoc/tests/23_type_coercion.c b/src/cmd/picoc/tests/23_type_coercion.c new file mode 100644 index 0000000..9076952 --- /dev/null +++ b/src/cmd/picoc/tests/23_type_coercion.c @@ -0,0 +1,49 @@ +#include + +void charfunc(char a) +{ + printf("char: %c\n", a); +} + +void intfunc(int a) +{ + printf("int: %d\n", a); +} + +void floatfunc(float a) +{ + printf("float: %f\n", a); +} + +charfunc('a'); +charfunc(98); +charfunc(99.0); + +intfunc('a'); +intfunc(98); +intfunc(99.0); + +floatfunc('a'); +floatfunc(98); +floatfunc(99.0); + +printf("%c %d %f\n", 'a', 'b', 'c'); +printf("%c %d %f\n", 97, 98, 99); +printf("%c %d %f\n", 97.0, 98.0, 99.0); + +char b = 97; +char c = 97.0; + +printf("%d %d\n", b, c); + +int d = 'a'; +int e = 97.0; + +printf("%d %d\n", d, e); + +float f = 'a'; +float g = 97; + +printf("%f %f\n", f, g); + +void main() {} diff --git a/src/cmd/picoc/tests/23_type_coercion.expect b/src/cmd/picoc/tests/23_type_coercion.expect new file mode 100644 index 0000000..a4c5b68 --- /dev/null +++ b/src/cmd/picoc/tests/23_type_coercion.expect @@ -0,0 +1,15 @@ +char: a +char: b +char: c +int: 97 +int: 98 +int: 99 +float: 97.000000 +float: 98.000000 +float: 99.000000 +a 98 99.000000 +a 98 99.000000 +a 98 99.000000 +97 97 +97 97 +97.000000 97.000000 diff --git a/src/cmd/picoc/tests/24_math_library.c b/src/cmd/picoc/tests/24_math_library.c new file mode 100644 index 0000000..892c4b8 --- /dev/null +++ b/src/cmd/picoc/tests/24_math_library.c @@ -0,0 +1,23 @@ +#include +#include + +printf("%f\n", sin(0.12)); +printf("%f\n", cos(0.12)); +printf("%f\n", tan(0.12)); +printf("%f\n", asin(0.12)); +printf("%f\n", acos(0.12)); +printf("%f\n", atan(0.12)); +printf("%f\n", sinh(0.12)); +printf("%f\n", cosh(0.12)); +printf("%f\n", tanh(0.12)); +printf("%f\n", exp(0.12)); +printf("%f\n", fabs(-0.12)); +printf("%f\n", log(0.12)); +printf("%f\n", log10(0.12)); +printf("%f\n", pow(0.12, 0.12)); +printf("%f\n", sqrt(0.12)); +printf("%f\n", round(12.34)); +printf("%f\n", ceil(12.34)); +printf("%f\n", floor(12.34)); + +void main() {} diff --git a/src/cmd/picoc/tests/24_math_library.expect b/src/cmd/picoc/tests/24_math_library.expect new file mode 100644 index 0000000..99f7299 --- /dev/null +++ b/src/cmd/picoc/tests/24_math_library.expect @@ -0,0 +1,18 @@ +0.119712 +0.992809 +0.120579 +0.120290 +1.450506 +0.119429 +0.120288 +1.007209 +0.119427 +1.127497 +0.120000 +-2.120264 +-0.920819 +0.775357 +0.346410 +12.000000 +13.000000 +12.000000 diff --git a/src/cmd/picoc/tests/25_quicksort.c b/src/cmd/picoc/tests/25_quicksort.c new file mode 100644 index 0000000..724d9c5 --- /dev/null +++ b/src/cmd/picoc/tests/25_quicksort.c @@ -0,0 +1,80 @@ +#include + +int array[16]; + +//Swap integer values by array indexes +void swap(int a, int b) +{ + int tmp = array[a]; + array[a] = array[b]; + array[b] = tmp; +} + +//Partition the array into two halves and return the +//index about which the array is partitioned +int partition(int left, int right) +{ + int pivotIndex = left; + int pivotValue = array[pivotIndex]; + int index = left; + int i; + + swap(pivotIndex, right); + for(i = left; i < right; i++) + { + if(array[i] < pivotValue) + { + swap(i, index); + index += 1; + } + } + swap(right, index); + + return index; +} + +//Quicksort the array +void quicksort(int left, int right) +{ + if(left >= right) + return; + + int index = partition(left, right); + quicksort(left, index - 1); + quicksort(index + 1, right); +} + +void main() +{ + int i; + + array[0] = 62; + array[1] = 83; + array[2] = 4; + array[3] = 89; + array[4] = 36; + array[5] = 21; + array[6] = 74; + array[7] = 37; + array[8] = 65; + array[9] = 33; + array[10] = 96; + array[11] = 38; + array[12] = 53; + array[13] = 16; + array[14] = 74; + array[15] = 55; + + for (i = 0; i < 16; i++) + printf("%d ", array[i]); + + printf("\n"); + + quicksort(0, 15); + + for (i = 0; i < 16; i++) + printf("%d ", array[i]); + + printf("\n"); +} + diff --git a/src/cmd/picoc/tests/25_quicksort.expect b/src/cmd/picoc/tests/25_quicksort.expect new file mode 100644 index 0000000..2d39cd3 --- /dev/null +++ b/src/cmd/picoc/tests/25_quicksort.expect @@ -0,0 +1,2 @@ +62 83 4 89 36 21 74 37 65 33 96 38 53 16 74 55 +4 16 21 33 36 37 38 53 55 62 65 74 74 83 89 96 diff --git a/src/cmd/picoc/tests/26_character_constants.c b/src/cmd/picoc/tests/26_character_constants.c new file mode 100644 index 0000000..6553f76 --- /dev/null +++ b/src/cmd/picoc/tests/26_character_constants.c @@ -0,0 +1,13 @@ +#include + +printf("%d\n", '\1'); +printf("%d\n", '\10'); +printf("%d\n", '\100'); +printf("%d\n", '\x01'); +printf("%d\n", '\x0e'); +printf("%d\n", '\x10'); +printf("%d\n", '\x40'); +printf("test \x407\n"); + + +void main() {} diff --git a/src/cmd/picoc/tests/26_character_constants.expect b/src/cmd/picoc/tests/26_character_constants.expect new file mode 100644 index 0000000..53e27d0 --- /dev/null +++ b/src/cmd/picoc/tests/26_character_constants.expect @@ -0,0 +1,8 @@ +1 +8 +64 +1 +14 +16 +64 +test @7 diff --git a/src/cmd/picoc/tests/27_sizeof.c b/src/cmd/picoc/tests/27_sizeof.c new file mode 100644 index 0000000..52703aa --- /dev/null +++ b/src/cmd/picoc/tests/27_sizeof.c @@ -0,0 +1,12 @@ +#include + +char a; +int b; +double c; + +printf("%d\n", sizeof(a)); +printf("%d\n", sizeof(b)); +printf("%d\n", sizeof(c)); + + +void main() {} diff --git a/src/cmd/picoc/tests/27_sizeof.expect b/src/cmd/picoc/tests/27_sizeof.expect new file mode 100644 index 0000000..7329e00 --- /dev/null +++ b/src/cmd/picoc/tests/27_sizeof.expect @@ -0,0 +1,3 @@ +1 +4 +8 diff --git a/src/cmd/picoc/tests/28_strings.c b/src/cmd/picoc/tests/28_strings.c new file mode 100644 index 0000000..d173060 --- /dev/null +++ b/src/cmd/picoc/tests/28_strings.c @@ -0,0 +1,41 @@ +#include +#include + +char a[10]; + +strcpy(a, "hello"); +printf("%s\n", a); + +strncpy(a, "gosh", 2); +printf("%s\n", a); + +printf("%d\n", strcmp(a, "apple") > 0); +printf("%d\n", strcmp(a, "goere") > 0); +printf("%d\n", strcmp(a, "zebra") < 0); + +printf("%d\n", strlen(a)); + +strcat(a, "!"); +printf("%s\n", a); + +printf("%d\n", strncmp(a, "apple", 2) > 0); +printf("%d\n", strncmp(a, "goere", 2) == 0); +printf("%d\n", strncmp(a, "goerg", 2) == 0); +printf("%d\n", strncmp(a, "zebra", 2) < 0); + +printf("%s\n", index(a, 'o')); +printf("%s\n", rindex(a, 'l')); +printf("%d\n", rindex(a, 'x') == NULL); + +memset(&a[1], 'r', 4); +printf("%s\n", a); + +memcpy(&a[2], a, 2); +printf("%s\n", a); + +printf("%d\n", memcmp(a, "apple", 4) > 0); +printf("%d\n", memcmp(a, "grgr", 4) == 0); +printf("%d\n", memcmp(a, "zebra", 4) < 0); + + +void main() {} diff --git a/src/cmd/picoc/tests/28_strings.expect b/src/cmd/picoc/tests/28_strings.expect new file mode 100644 index 0000000..fd9217a --- /dev/null +++ b/src/cmd/picoc/tests/28_strings.expect @@ -0,0 +1,19 @@ +hello +gollo +1 +1 +1 +5 +gollo! +1 +1 +1 +1 +ollo! +lo! +1 +grrrr! +grgrr! +1 +1 +1 diff --git a/src/cmd/picoc/tests/29_array_address.c b/src/cmd/picoc/tests/29_array_address.c new file mode 100644 index 0000000..a8562af --- /dev/null +++ b/src/cmd/picoc/tests/29_array_address.c @@ -0,0 +1,8 @@ +#include +#include + +char a[10]; +strcpy(a, "abcdef"); +printf("%s\n", &a[1]); + +void main() {} diff --git a/src/cmd/picoc/tests/29_array_address.expect b/src/cmd/picoc/tests/29_array_address.expect new file mode 100644 index 0000000..9bc8683 --- /dev/null +++ b/src/cmd/picoc/tests/29_array_address.expect @@ -0,0 +1 @@ +bcdef diff --git a/src/cmd/picoc/tests/30_hanoi.c b/src/cmd/picoc/tests/30_hanoi.c new file mode 100644 index 0000000..5ca6667 --- /dev/null +++ b/src/cmd/picoc/tests/30_hanoi.c @@ -0,0 +1,125 @@ +/* example from http://barnyard.syr.edu/quickies/hanoi.c */ + +/* hanoi.c: solves the tower of hanoi problem. (Programming exercise.) */ +/* By Terry R. McConnell (12/2/97) */ +/* Compile: cc -o hanoi hanoi.c */ + +/* This program does no error checking. But then, if it's right, +it's right ... right ? */ + + +/* The original towers of hanoi problem seems to have been originally posed +by one M. Claus in 1883. There is a popular legend that goes along with +it that has been often repeated and paraphrased. It goes something like this: +In the great temple at Benares there are 3 golden spikes. On one of them, +God placed 64 disks increasing in size from bottom to top, at the beginning +of time. Since then, and to this day, the priest on duty constantly transfers +disks, one at a time, in such a way that no larger disk is ever put on top +of a smaller one. When the disks have been transferred entirely to another +spike the Universe will come to an end in a large thunderclap. + +This paraphrases the original legend due to DeParville, La Nature, Paris 1884, +Part I, 285-286. For this and further information see: Mathematical +Recreations & Essays, W.W. Rouse Ball, MacMillan, NewYork, 11th Ed. 1967, +303-305. +* +* +*/ + +#include +#include + +#define TRUE 1 +#define FALSE 0 + +#define N 4 /* This is the number of "disks" on tower A initially. */ + /* Taken to be 64 in the legend. The number of moves + required, in general, is 2^N - 1. For N = 64, this is + 18,446,744,073,709,551,615 */ + +int A[N], B[N], C[N]; /* These are the three towers. For example if the +state of A is 0,1,3,4, that means that there are three discs on A of sizes +1, 3, and 4. (Think of right as being the "down" direction.) */ + +void Hanoi(int,int*,int*,int*); + +/* Print the current configuration of A, B, and C to the screen */ + +void +PrintAll() +{ + int i; + + printf("A: "); + for(i=0;i + +int main(int argc, char **argv) +{ + int Count; + + printf("hello world %d\n", argc); + for (Count = 0; Count < argc; Count++) + printf("arg %d: %s\n", Count, argv[Count]); + + return 0; +} diff --git a/src/cmd/picoc/tests/31_args.expect b/src/cmd/picoc/tests/31_args.expect new file mode 100644 index 0000000..bf25112 --- /dev/null +++ b/src/cmd/picoc/tests/31_args.expect @@ -0,0 +1,6 @@ +hello world 5 +arg 0: - +arg 1: arg1 +arg 2: arg2 +arg 3: arg3 +arg 4: arg4 diff --git a/src/cmd/picoc/tests/32_led.c b/src/cmd/picoc/tests/32_led.c new file mode 100644 index 0000000..d1a28b6 --- /dev/null +++ b/src/cmd/picoc/tests/32_led.c @@ -0,0 +1,264 @@ +/* example from http://barnyard.syr.edu/quickies/led.c */ + +/* led.c: print out number as if on 7 line led display. I.e., write integer + given on command line like this: + _ _ _ + | _| _| |_| |_ + | |_ _| | _| etc. + + We assume the terminal behaves like a classical teletype. So the top + lines of all digits have to be printed first, then the middle lines of + all digits, etc. + + By Terry R. McConnell + + compile: cc -o led led.c + + If you just want to link in the subroutine print_led that does all the + work, compile with -DNO_MAIN, and declare the following in any source file + that uses the call: + + extern void print_led(unsigned long x, char *buf); + + Bug: you cannot call repeatedly to print more than one number to a line. + That would require curses or some other terminal API that allows moving the + cursor to a previous line. + + */ + + + +#include +#include + +#define MAX_DIGITS 32 +#define NO_MAIN + + +/* Print the top line of the digit d into buffer. + Does not null terminate buffer. */ + +void topline(int d, char *p){ + + *p++ = ' '; + switch(d){ + + /* all these have _ on top line */ + + case 0: + case 2: + case 3: + case 5: + case 7: + case 8: + case 9: + *p++ = '_'; + break; + default: + *p++=' '; + + } + *p++=' '; +} + +/* Print the middle line of the digit d into the buffer. + Does not null terminate. */ + +void midline(int d, char *p){ + + switch(d){ + + /* those that have leading | on middle line */ + + case 0: + case 4: + case 5: + case 6: + case 8: + case 9: + *p++='|'; + break; + default: + *p++=' '; + } + switch(d){ + + /* those that have _ on middle line */ + + case 2: + case 3: + case 4: + case 5: + case 6: + case 8: + case 9: + *p++='_'; + break; + default: + *p++=' '; + + } + switch(d){ + + /* those that have closing | on middle line */ + + case 0: + case 1: + case 2: + case 3: + case 4: + case 7: + case 8: + case 9: + *p++='|'; + break; + default: + *p++=' '; + + } +} + +/* Print the bottom line of the digit d. Does not null terminate. */ + +void botline(int d, char *p){ + + + switch(d){ + + /* those that have leading | on bottom line */ + + case 0: + case 2: + case 6: + case 8: + *p++='|'; + break; + default: + *p++=' '; + } + switch(d){ + + /* those that have _ on bottom line */ + + case 0: + case 2: + case 3: + case 5: + case 6: + case 8: + *p++='_'; + break; + default: + *p++=' '; + + } + switch(d){ + + /* those that have closing | on bottom line */ + + case 0: + case 1: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + *p++='|'; + break; + default: + *p++=' '; + + } +} + +/* Write the led representation of integer to string buffer. */ + +void print_led(unsigned long x, char *buf) +{ + + int i=0,n; + static int d[MAX_DIGITS]; + + + /* extract digits from x */ + + n = ( x == 0L ? 1 : 0 ); /* 0 is a digit, hence a special case */ + + while(x){ + d[n++] = (int)(x%10L); + if(n >= MAX_DIGITS)break; + x = x/10L; + } + + /* print top lines of all digits */ + + for(i=n-1;i>=0;i--){ + topline(d[i],buf); + buf += 3; + *buf++=' '; + } + *buf++='\n'; /* move teletype to next line */ + + /* print middle lines of all digits */ + + for(i=n-1;i>=0;i--){ + midline(d[i],buf); + buf += 3; + *buf++=' '; + } + *buf++='\n'; + + /* print bottom lines of all digits */ + + for(i=n-1;i>=0;i--){ + botline(d[i],buf); + buf += 3; + *buf++=' '; + } + *buf++='\n'; + *buf='\0'; +} + +int main() +{ + char buf[5*MAX_DIGITS]; + print_led(1234567, buf); + printf("%s\n",buf); + + return 0; +} + +#ifndef NO_MAIN +int main(int argc, char **argv) +{ + + int i=0,n; + long x; + static int d[MAX_DIGITS]; + char buf[5*MAX_DIGITS]; + + if(argc != 2){ + fprintf(stderr,"led: usage: led integer\n"); + return 1; + } + + /* fetch argument from command line */ + + x = atol(argv[1]); + + /* sanity check */ + + if(x<0){ + fprintf(stderr,"led: %d must be non-negative\n",x); + return 1; + } + + print_led(x,buf); + printf("%s\n",buf); + + return 0; + +} +#endif diff --git a/src/cmd/picoc/tests/32_led.expect b/src/cmd/picoc/tests/32_led.expect new file mode 100644 index 0000000..c53b58a --- /dev/null +++ b/src/cmd/picoc/tests/32_led.expect @@ -0,0 +1,4 @@ + _ _ _ _ + | _| _| |_| |_ |_ | + | |_ _| | _| |_| | + diff --git a/src/cmd/picoc/tests/33_ternary_op.c b/src/cmd/picoc/tests/33_ternary_op.c new file mode 100644 index 0000000..5c1cead --- /dev/null +++ b/src/cmd/picoc/tests/33_ternary_op.c @@ -0,0 +1,10 @@ +#include + +int Count; + +for (Count = 0; Count < 10; Count++) +{ + printf("%d\n", (Count < 5) ? (Count*Count) : (Count * 3)); +} + +void main() {} diff --git a/src/cmd/picoc/tests/33_ternary_op.expect b/src/cmd/picoc/tests/33_ternary_op.expect new file mode 100644 index 0000000..45ea507 --- /dev/null +++ b/src/cmd/picoc/tests/33_ternary_op.expect @@ -0,0 +1,10 @@ +0 +1 +4 +9 +16 +15 +18 +21 +24 +27 diff --git a/src/cmd/picoc/tests/34_array_assignment.c b/src/cmd/picoc/tests/34_array_assignment.c new file mode 100644 index 0000000..afe544e --- /dev/null +++ b/src/cmd/picoc/tests/34_array_assignment.c @@ -0,0 +1,18 @@ +#include + +int a[4]; + +a[0] = 12; +a[1] = 23; +a[2] = 34; +a[3] = 45; + +printf("%d %d %d %d\n", a[0], a[1], a[2], a[3]); + +int b[4]; + +b = a; + +printf("%d %d %d %d\n", b[0], b[1], b[2], b[3]); + +void main() {} diff --git a/src/cmd/picoc/tests/34_array_assignment.expect b/src/cmd/picoc/tests/34_array_assignment.expect new file mode 100644 index 0000000..9736bf5 --- /dev/null +++ b/src/cmd/picoc/tests/34_array_assignment.expect @@ -0,0 +1,2 @@ +12 23 34 45 +12 23 34 45 diff --git a/src/cmd/picoc/tests/35_sizeof.c b/src/cmd/picoc/tests/35_sizeof.c new file mode 100644 index 0000000..87c783a --- /dev/null +++ b/src/cmd/picoc/tests/35_sizeof.c @@ -0,0 +1,9 @@ +#include + +char a; +short b; + +printf("%d %d\n", sizeof(char), sizeof(a)); +printf("%d %d\n", sizeof(short), sizeof(b)); + +void main() {} diff --git a/src/cmd/picoc/tests/35_sizeof.expect b/src/cmd/picoc/tests/35_sizeof.expect new file mode 100644 index 0000000..534fb83 --- /dev/null +++ b/src/cmd/picoc/tests/35_sizeof.expect @@ -0,0 +1,2 @@ +1 1 +2 2 diff --git a/src/cmd/picoc/tests/36_array_initialisers.c b/src/cmd/picoc/tests/36_array_initialisers.c new file mode 100644 index 0000000..ce8695b --- /dev/null +++ b/src/cmd/picoc/tests/36_array_initialisers.c @@ -0,0 +1,16 @@ +#include + +int Count; + +int Array[10] = { 12, 34, 56, 78, 90, 123, 456, 789, 8642, 9753 }; + +for (Count = 0; Count < 10; Count++) + printf("%d: %d\n", Count, Array[Count]); + +int Array2[10] = { 12, 34, 56, 78, 90, 123, 456, 789, 8642, 9753, }; + +for (Count = 0; Count < 10; Count++) + printf("%d: %d\n", Count, Array2[Count]); + + +void main() {} diff --git a/src/cmd/picoc/tests/36_array_initialisers.expect b/src/cmd/picoc/tests/36_array_initialisers.expect new file mode 100644 index 0000000..3ac6c77 --- /dev/null +++ b/src/cmd/picoc/tests/36_array_initialisers.expect @@ -0,0 +1,20 @@ +0: 12 +1: 34 +2: 56 +3: 78 +4: 90 +5: 123 +6: 456 +7: 789 +8: 8642 +9: 9753 +0: 12 +1: 34 +2: 56 +3: 78 +4: 90 +5: 123 +6: 456 +7: 789 +8: 8642 +9: 9753 diff --git a/src/cmd/picoc/tests/37_sprintf.c b/src/cmd/picoc/tests/37_sprintf.c new file mode 100644 index 0000000..839a4d8 --- /dev/null +++ b/src/cmd/picoc/tests/37_sprintf.c @@ -0,0 +1,12 @@ +#include + +char Buf[100]; +int Count; + +for (Count = 1; Count <= 20; Count++) +{ + sprintf(Buf, "->%02d<-\n", Count); + printf("%s", Buf); +} + +void main() {} diff --git a/src/cmd/picoc/tests/37_sprintf.expect b/src/cmd/picoc/tests/37_sprintf.expect new file mode 100644 index 0000000..a643da8 --- /dev/null +++ b/src/cmd/picoc/tests/37_sprintf.expect @@ -0,0 +1,20 @@ +->01<- +->02<- +->03<- +->04<- +->05<- +->06<- +->07<- +->08<- +->09<- +->10<- +->11<- +->12<- +->13<- +->14<- +->15<- +->16<- +->17<- +->18<- +->19<- +->20<- diff --git a/src/cmd/picoc/tests/38_multiple_array_index.c b/src/cmd/picoc/tests/38_multiple_array_index.c new file mode 100644 index 0000000..383d3ee --- /dev/null +++ b/src/cmd/picoc/tests/38_multiple_array_index.c @@ -0,0 +1,29 @@ +#include + +int a[4][4]; +int b = 0; +int x; +int y; + +for (x = 0; x < 4; x++) +{ + for (y = 0; y < 4; y++) + { + b++; + a[x][y] = b; + } +} + + + +for (x = 0; x < 4; x++) +{ + printf("x=%d: ", x); + for (y = 0; y < 4; y++) + { + printf("%d ", a[x][y]); + } + printf("\n"); +} + +void main() {} diff --git a/src/cmd/picoc/tests/38_multiple_array_index.expect b/src/cmd/picoc/tests/38_multiple_array_index.expect new file mode 100644 index 0000000..747ad75 --- /dev/null +++ b/src/cmd/picoc/tests/38_multiple_array_index.expect @@ -0,0 +1,4 @@ +x=0: 1 2 3 4 +x=1: 5 6 7 8 +x=2: 9 10 11 12 +x=3: 13 14 15 16 diff --git a/src/cmd/picoc/tests/39_typedef.c b/src/cmd/picoc/tests/39_typedef.c new file mode 100644 index 0000000..e36791c --- /dev/null +++ b/src/cmd/picoc/tests/39_typedef.c @@ -0,0 +1,26 @@ +#include + +typedef int MyInt; + +MyInt a = 1; +printf("%d\n", a); + +struct FunStruct +{ + int i; + int j; +}; + +typedef struct FunStruct MyFunStruct; + +MyFunStruct b; +b.i = 12; +b.j = 34; +printf("%d,%d\n", b.i, b.j); + +typedef MyFunStruct *MoreFunThanEver; + +MoreFunThanEver c = &b; +printf("%d,%d\n", c->i, c->j); + +void main() {} diff --git a/src/cmd/picoc/tests/39_typedef.expect b/src/cmd/picoc/tests/39_typedef.expect new file mode 100644 index 0000000..b9050a9 --- /dev/null +++ b/src/cmd/picoc/tests/39_typedef.expect @@ -0,0 +1,3 @@ +1 +12,34 +12,34 diff --git a/src/cmd/picoc/tests/40_stdio.c b/src/cmd/picoc/tests/40_stdio.c new file mode 100644 index 0000000..546ca52 --- /dev/null +++ b/src/cmd/picoc/tests/40_stdio.c @@ -0,0 +1,47 @@ +#include + +FILE *f = fopen("fred.txt", "w"); +fwrite("hello\nhello\n", 1, 12, f); +fclose(f); + +char freddy[7]; +f = fopen("fred.txt", "r"); +if (fread(freddy, 1, 6, f) != 6) + printf("couldn't read fred.txt\n"); + +freddy[6] = '\0'; +fclose(f); + +printf("%s", freddy); + +char InChar; +char ShowChar; +f = fopen("fred.txt", "r"); +while ( (InChar = fgetc(f)) != EOF) +{ + ShowChar = InChar; + if (ShowChar < ' ') + ShowChar = '.'; + + printf("ch: %d '%c'\n", InChar, ShowChar); +} +fclose(f); + +f = fopen("fred.txt", "r"); +while ( (InChar = getc(f)) != EOF) +{ + ShowChar = InChar; + if (ShowChar < ' ') + ShowChar = '.'; + + printf("ch: %d '%c'\n", InChar, ShowChar); +} +fclose(f); + +f = fopen("fred.txt", "r"); +while (fgets(freddy, sizeof(freddy), f) != NULL) + printf("x: %s", freddy); + +fclose(f); + +void main() {} diff --git a/src/cmd/picoc/tests/40_stdio.expect b/src/cmd/picoc/tests/40_stdio.expect new file mode 100644 index 0000000..e08167a --- /dev/null +++ b/src/cmd/picoc/tests/40_stdio.expect @@ -0,0 +1,27 @@ +hello +ch: 104 'h' +ch: 101 'e' +ch: 108 'l' +ch: 108 'l' +ch: 111 'o' +ch: 10 '.' +ch: 104 'h' +ch: 101 'e' +ch: 108 'l' +ch: 108 'l' +ch: 111 'o' +ch: 10 '.' +ch: 104 'h' +ch: 101 'e' +ch: 108 'l' +ch: 108 'l' +ch: 111 'o' +ch: 10 '.' +ch: 104 'h' +ch: 101 'e' +ch: 108 'l' +ch: 108 'l' +ch: 111 'o' +ch: 10 '.' +x: hello +x: hello diff --git a/src/cmd/picoc/tests/41_hashif.c b/src/cmd/picoc/tests/41_hashif.c new file mode 100644 index 0000000..b1883c0 --- /dev/null +++ b/src/cmd/picoc/tests/41_hashif.c @@ -0,0 +1,80 @@ +#include + +printf("#include test\n"); + +#if 1 + #if 0 + printf("a\n"); + #else + printf("b\n"); + #endif +#else + #if 0 + printf("c\n"); + #else + printf("d\n"); + #endif +#endif + +#if 0 + #if 1 + printf("e\n"); + #else + printf("f\n"); + #endif +#else + #if 1 + printf("g\n"); + #else + printf("h\n"); + #endif +#endif + +#define DEF + +#ifdef DEF + #ifdef DEF + printf("i\n"); + #else + printf("j\n"); + #endif +#else + #ifdef DEF + printf("k\n"); + #else + printf("l\n"); + #endif +#endif + +#ifndef DEF + #ifndef DEF + printf("m\n"); + #else + printf("n\n"); + #endif +#else + #ifndef DEF + printf("o\n"); + #else + printf("p\n"); + #endif +#endif + +#define ONE 1 +#define ZERO 0 + +#if ONE + #if ZERO + printf("q\n"); + #else + printf("r\n"); + #endif +#else + #if ZERO + printf("s\n"); + #else + printf("t\n"); + #endif +#endif + +void main() {} diff --git a/src/cmd/picoc/tests/41_hashif.expect b/src/cmd/picoc/tests/41_hashif.expect new file mode 100644 index 0000000..5fd414b --- /dev/null +++ b/src/cmd/picoc/tests/41_hashif.expect @@ -0,0 +1,6 @@ +#include test +b +g +i +p +r diff --git a/src/cmd/picoc/tests/42_function_pointer.c b/src/cmd/picoc/tests/42_function_pointer.c new file mode 100644 index 0000000..ce39708 --- /dev/null +++ b/src/cmd/picoc/tests/42_function_pointer.c @@ -0,0 +1,15 @@ +#include + +int fred(int p) +{ + printf("yo %d\n", p); + return 42; +} + +int (*f)(int) = &fred; + +int main() +{ + printf("%d\n", (*f)(24)); + return 0; +} diff --git a/src/cmd/picoc/tests/43_void_param.c b/src/cmd/picoc/tests/43_void_param.c new file mode 100644 index 0000000..4803d94 --- /dev/null +++ b/src/cmd/picoc/tests/43_void_param.c @@ -0,0 +1,10 @@ +#include + +void fred(void) +{ + printf("yo\n"); +} + +fred(); + +void main() {} diff --git a/src/cmd/picoc/tests/43_void_param.expect b/src/cmd/picoc/tests/43_void_param.expect new file mode 100644 index 0000000..092bfb9 --- /dev/null +++ b/src/cmd/picoc/tests/43_void_param.expect @@ -0,0 +1 @@ +yo diff --git a/src/cmd/picoc/tests/44_scoped_declarations.c b/src/cmd/picoc/tests/44_scoped_declarations.c new file mode 100644 index 0000000..50337ef --- /dev/null +++ b/src/cmd/picoc/tests/44_scoped_declarations.c @@ -0,0 +1,12 @@ +#include + +int a; + +for (a = 0; a < 2; a++) +{ + int b = a; +} + +printf("it's all good\n"); + +void main() {} diff --git a/src/cmd/picoc/tests/44_scoped_declarations.expect b/src/cmd/picoc/tests/44_scoped_declarations.expect new file mode 100644 index 0000000..231ccc0 --- /dev/null +++ b/src/cmd/picoc/tests/44_scoped_declarations.expect @@ -0,0 +1 @@ +it's all good diff --git a/src/cmd/picoc/tests/45_empty_for.c b/src/cmd/picoc/tests/45_empty_for.c new file mode 100644 index 0000000..28d0b6c --- /dev/null +++ b/src/cmd/picoc/tests/45_empty_for.c @@ -0,0 +1,16 @@ +#include + +int main() +{ + int Count = 0; + + for (;;) + { + Count++; + printf("%d\n", Count); + if (Count >= 10) + break; + } + + return 0; +} diff --git a/src/cmd/picoc/tests/45_empty_for.expect b/src/cmd/picoc/tests/45_empty_for.expect new file mode 100644 index 0000000..f00c965 --- /dev/null +++ b/src/cmd/picoc/tests/45_empty_for.expect @@ -0,0 +1,10 @@ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 diff --git a/src/cmd/picoc/tests/46_grep.c b/src/cmd/picoc/tests/46_grep.c new file mode 100644 index 0000000..b142f98 --- /dev/null +++ b/src/cmd/picoc/tests/46_grep.c @@ -0,0 +1,562 @@ +/* + * The information in this document is subject to change + * without notice and should not be construed as a commitment + * by Digital Equipment Corporation or by DECUS. + * + * Neither Digital Equipment Corporation, DECUS, nor the authors + * assume any responsibility for the use or reliability of this + * document or the described software. + * + * Copyright (C) 1980, DECUS + * + * General permission to copy or modify, but not for profit, is + * hereby granted, provided that the above copyright notice is + * included and reference made to the fact that reproduction + * privileges were granted by DECUS. + */ +#include + +/* + * grep + * + * Runs on the Decus compiler or on vms, On vms, define as: + * grep :== "$disk:[account]grep" (native) + * grep :== "$disk:[account]grep grep" (Decus) + * See below for more information. + */ + +#if 0 +char *documentation[] = { +"grep searches a file for a given pattern. Execute by", +" grep [flags] regular_expression file_list\n", +"Flags are single characters preceeded by '-':", +" -c Only a count of matching lines is printed", +" -f Print file name for matching lines switch, see below", +" -n Each line is preceeded by its line number", +" -v Only print non-matching lines\n", +"The file_list is a list of files (wildcards are acceptable on RSX modes).", +"\nThe file name is normally printed if there is a file given.", +"The -f flag reverses this action (print name no file, not if more).\n", +0 }; + +char *patdoc[] = { +"The regular_expression defines the pattern to search for. Upper- and", +"lower-case are always ignored. Blank lines never match. The expression", +"should be quoted to prevent file-name translation.", +"x An ordinary character (not mentioned below) matches that character.", +"'\\' The backslash quotes any character. \"\\$\" matches a dollar-sign.", +"'^' A circumflex at the beginning of an expression matches the", +" beginning of a line.", +"'$' A dollar-sign at the end of an expression matches the end of a line.", +"'.' A period matches any character except \"new-line\".", +"':a' A colon matches a class of characters described by the following", +"':d' character. \":a\" matches any alphabetic, \":d\" matches digits,", +"':n' \":n\" matches alphanumerics, \": \" matches spaces, tabs, and", +"': ' other control characters, such as new-line.", +"'*' An expression followed by an asterisk matches zero or more", +" occurrances of that expression: \"fo*\" matches \"f\", \"fo\"", +" \"foo\", etc.", +"'+' An expression followed by a plus sign matches one or more", +" occurrances of that expression: \"fo+\" matches \"fo\", etc.", +"'-' An expression followed by a minus sign optionally matches", +" the expression.", +"'[]' A string enclosed in square brackets matches any character in", +" that string, but no others. If the first character in the", +" string is a circumflex, the expression matches any character", +" except \"new-line\" and the characters in the string. For", +" example, \"[xyz]\" matches \"xx\" and \"zyx\", while \"[^xyz]\"", +" matches \"abc\" but not \"axb\". A range of characters may be", +" specified by two characters separated by \"-\". Note that,", +" [a-z] matches alphabetics, while [z-a] never matches.", +"The concatenation of regular expressions is a regular expression.", +0}; +#endif + +#define LMAX 512 +#define PMAX 256 + +#define CHAR 1 +#define BOL 2 +#define EOL 3 +#define ANY 4 +#define CLASS 5 +#define NCLASS 6 +#define STAR 7 +#define PLUS 8 +#define MINUS 9 +#define ALPHA 10 +#define DIGIT 11 +#define NALPHA 12 +#define PUNCT 13 +#define RANGE 14 +#define ENDPAT 15 + +int cflag=0, fflag=0, nflag=0, vflag=0, nfile=0, debug=0; + +char *pp, lbuf[LMAX], pbuf[PMAX]; + +char *cclass(); +char *pmatch(); + + +/*** Display a file name *******************************/ +void file(char *s) +{ + printf("File %s:\n", s); +} + +/*** Report unopenable file ****************************/ +void cant(char *s) +{ + fprintf(stderr, "%s: cannot open\n", s); +} + +/*** Give good help ************************************/ +void help(char **hp) +{ + char **dp; + + for (dp = hp; *dp; ++dp) + printf("%s\n", *dp); +} + +/*** Display usage summary *****************************/ +void usage(char *s) +{ + fprintf(stderr, "?GREP-E-%s\n", s); + fprintf(stderr, + "Usage: grep [-cfnv] pattern [file ...]. grep ? for help\n"); + exit(1); +} + +/*** Compile the pattern into global pbuf[] ************/ +void compile(char *source) +{ + char *s; /* Source string pointer */ + char *lp; /* Last pattern pointer */ + int c; /* Current character */ + int o; /* Temp */ + char *spp; /* Save beginning of pattern */ + + s = source; + if (debug) + printf("Pattern = \"%s\"\n", s); + pp = pbuf; + while (c = *s++) { + /* + * STAR, PLUS and MINUS are special. + */ + if (c == '*' || c == '+' || c == '-') { + if (pp == pbuf || + (o=pp[-1]) == BOL || + o == EOL || + o == STAR || + o == PLUS || + o == MINUS) + badpat("Illegal occurrance op.", source, s); + store(ENDPAT); + store(ENDPAT); + spp = pp; /* Save pattern end */ + while (--pp > lp) /* Move pattern down */ + *pp = pp[-1]; /* one byte */ + *pp = (c == '*') ? STAR : + (c == '-') ? MINUS : PLUS; + pp = spp; /* Restore pattern end */ + continue; + } + /* + * All the rest. + */ + lp = pp; /* Remember start */ + switch(c) { + + case '^': + store(BOL); + break; + + case '$': + store(EOL); + break; + + case '.': + store(ANY); + break; + + case '[': + s = cclass(source, s); + break; + + case ':': + if (*s) { + switch(tolower(c = *s++)) { + + case 'a': + case 'A': + store(ALPHA); + break; + + case 'd': + case 'D': + store(DIGIT); + break; + + case 'n': + case 'N': + store(NALPHA); + break; + + case ' ': + store(PUNCT); + break; + + default: + badpat("Unknown : type", source, s); + + } + break; + } + else badpat("No : type", source, s); + + case '\\': + if (*s) + c = *s++; + + default: + store(CHAR); + store(tolower(c)); + } + } + store(ENDPAT); + store(0); /* Terminate string */ + if (debug) { + for (lp = pbuf; lp < pp;) { + if ((c = (*lp++ & 0377)) < ' ') + printf("\\%o ", c); + else printf("%c ", c); + } + printf("\n"); + } +} + +/*** Compile a class (within []) ***********************/ +char *cclass(char *source, char *src) +/* char *source; // Pattern start -- for error msg. */ +/* char *src; // Class start */ +{ + char *s; /* Source pointer */ + char *cp; /* Pattern start */ + int c; /* Current character */ + int o; /* Temp */ + + s = src; + o = CLASS; + if (*s == '^') { + ++s; + o = NCLASS; + } + store(o); + cp = pp; + store(0); /* Byte count */ + while ((c = *s++) && c!=']') { + if (c == '\\') { /* Store quoted char */ + if ((c = *s++) == '\0') /* Gotta get something */ + badpat("Class terminates badly", source, s); + else store(tolower(c)); + } + else if (c == '-' && + (pp - cp) > 1 && *s != ']' && *s != '\0') { + c = pp[-1]; /* Range start */ + pp[-1] = RANGE; /* Range signal */ + store(c); /* Re-store start */ + c = *s++; /* Get end char and*/ + store(tolower(c)); /* Store it */ + } + else { + store(tolower(c)); /* Store normal char */ + } + } + if (c != ']') + badpat("Unterminated class", source, s); + if ((c = (pp - cp)) >= 256) + badpat("Class too large", source, s); + if (c == 0) + badpat("Empty class", source, s); + *cp = c; + return(s); +} + +/*** Store an entry in the pattern buffer **************/ +void store(int op) +{ + if (pp >= &pbuf[PMAX]) + error("Pattern too complex\n"); + *pp++ = op; +} + +/*** Report a bad pattern specification ****************/ +void badpat(char *message, char *source, char *stop) +/* char *message; // Error message */ +/* char *source; // Pattern start */ +/* char *stop; // Pattern end */ +{ + fprintf(stderr, "-GREP-E-%s, pattern is\"%s\"\n", message, source); + fprintf(stderr, "-GREP-E-Stopped at byte %d, '%c'\n", + stop-source, stop[-1]); + error("?GREP-E-Bad pattern\n"); +} + +/*** Scan the file for the pattern in pbuf[] ***********/ +void grep(FILE *fp, char *fn) +/* FILE *fp; // File to process */ +/* char *fn; // File name (for -f option) */ +{ + int lno, count, m; + + lno = 0; + count = 0; + while (fgets(lbuf, LMAX, fp)) { + ++lno; + m = match(); + if ((m && !vflag) || (!m && vflag)) { + ++count; + if (!cflag) { + if (fflag && fn) { + file(fn); + fn = 0; + } + if (nflag) + printf("%d\t", lno); + printf("%s\n", lbuf); + } + } + } + if (cflag) { + if (fflag && fn) + file(fn); + printf("%d\n", count); + } +} + +/*** Match line (lbuf) with pattern (pbuf) return 1 if match ***/ +void match() +{ + char *l; /* Line pointer */ + + for (l = lbuf; *l; ++l) { + if (pmatch(l, pbuf)) + return(1); + } + return(0); +} + +/*** Match partial line with pattern *******************/ +char *pmatch(char *line, char *pattern) +/* char *line; // (partial) line to match */ +/* char *pattern; // (partial) pattern to match */ +{ + char *l; /* Current line pointer */ + char *p; /* Current pattern pointer */ + char c; /* Current character */ + char *e; /* End for STAR and PLUS match */ + int op; /* Pattern operation */ + int n; /* Class counter */ + char *are; /* Start of STAR match */ + + l = line; + if (debug > 1) + printf("pmatch(\"%s\")\n", line); + p = pattern; + while ((op = *p++) != ENDPAT) { + if (debug > 1) + printf("byte[%d] = 0%o, '%c', op = 0%o\n", + l-line, *l, *l, op); + switch(op) { + + case CHAR: + if (tolower(*l++) != *p++) + return(0); + break; + + case BOL: + if (l != lbuf) + return(0); + break; + + case EOL: + if (*l != '\0') + return(0); + break; + + case ANY: + if (*l++ == '\0') + return(0); + break; + + case DIGIT: + if ((c = *l++) < '0' || (c > '9')) + return(0); + break; + + case ALPHA: + c = tolower(*l++); + if (c < 'a' || c > 'z') + return(0); + break; + + case NALPHA: + c = tolower(*l++); + if (c >= 'a' && c <= 'z') + break; + else if (c < '0' || c > '9') + return(0); + break; + + case PUNCT: + c = *l++; + if (c == 0 || c > ' ') + return(0); + break; + + case CLASS: + case NCLASS: + c = tolower(*l++); + n = *p++ & 0377; + do { + if (*p == RANGE) { + p += 3; + n -= 2; + if (c >= p[-2] && c <= p[-1]) + break; + } + else if (c == *p++) + break; + } while (--n > 1); + if ((op == CLASS) == (n <= 1)) + return(0); + if (op == CLASS) + p += n - 2; + break; + + case MINUS: + e = pmatch(l, p); /* Look for a match */ + while (*p++ != ENDPAT); /* Skip over pattern */ + if (e) /* Got a match? */ + l = e; /* Yes, update string */ + break; /* Always succeeds */ + + case PLUS: /* One or more ... */ + if ((l = pmatch(l, p)) == 0) + return(0); /* Gotta have a match */ + case STAR: /* Zero or more ... */ + are = l; /* Remember line start */ + while (*l && (e = pmatch(l, p))) + l = e; /* Get longest match */ + while (*p++ != ENDPAT); /* Skip over pattern */ + while (l >= are) { /* Try to match rest */ + if (e = pmatch(l, p)) + return(e); + --l; /* Nope, try earlier */ + } + return(0); /* Nothing else worked */ + + default: + printf("Bad op code %d\n", op); + error("Cannot happen -- match\n"); + } + } + return(l); +} + +/*** Report an error ***********************************/ +void error(char *s) +{ + fprintf(stderr, "%s", s); + exit(1); +} + +/*** Main program - parse arguments & grep *************/ +int main(int argc, char **argv) +{ + char *p; + int c, i; + int gotpattern; + + FILE *f; + + if (argc <= 1) + usage("No arguments"); + if (argc == 2 && argv[1][0] == '?' && argv[1][1] == 0) { + help(documentation); + help(patdoc); + return; + } + nfile = argc-1; + gotpattern = 0; + for (i=1; i < argc; ++i) { + p = argv[i]; + if (*p == '-') { + ++p; + while (c = *p++) { + switch(tolower(c)) { + + case '?': + help(documentation); + break; + + case 'C': + case 'c': + ++cflag; + break; + + case 'D': + case 'd': + ++debug; + break; + + case 'F': + case 'f': + ++fflag; + break; + + case 'n': + case 'N': + ++nflag; + break; + + case 'v': + case 'V': + ++vflag; + break; + + default: + usage("Unknown flag"); + } + } + argv[i] = 0; + --nfile; + } else if (!gotpattern) { + compile(p); + argv[i] = 0; + ++gotpattern; + --nfile; + } + } + if (!gotpattern) + usage("No pattern"); + if (nfile == 0) + grep(stdin, 0); + else { + fflag = fflag ^ (nfile > 0); + for (i=1; i < argc; ++i) { + if (p = argv[i]) { + if ((f=fopen(p, "r")) == NULL) + cant(p); + else { + grep(f, p); + fclose(f); + } + } + } + } +} + diff --git a/src/cmd/picoc/tests/47_switch_return.c b/src/cmd/picoc/tests/47_switch_return.c new file mode 100644 index 0000000..2fdb8bd --- /dev/null +++ b/src/cmd/picoc/tests/47_switch_return.c @@ -0,0 +1,23 @@ +#include + +void fred(int x) +{ + switch (x) + { + case 1: printf("1\n"); return; + case 2: printf("2\n"); break; + case 3: printf("3\n"); return; + } + + printf("out\n"); +} + +int main() +{ + fred(1); + fred(2); + fred(3); + + return 0; +} + diff --git a/src/cmd/picoc/tests/47_switch_return.expect b/src/cmd/picoc/tests/47_switch_return.expect new file mode 100644 index 0000000..b6deb7e --- /dev/null +++ b/src/cmd/picoc/tests/47_switch_return.expect @@ -0,0 +1,4 @@ +1 +2 +out +3 diff --git a/src/cmd/picoc/tests/48_nested_break.c b/src/cmd/picoc/tests/48_nested_break.c new file mode 100644 index 0000000..4b01a99 --- /dev/null +++ b/src/cmd/picoc/tests/48_nested_break.c @@ -0,0 +1,24 @@ +#include + +int a; +char b; + +a = 0; +while (a < 2) +{ + printf("%d", a++); + break; + + b = 'A'; + while (b < 'C') + { + printf("%c", b++); + } + printf("e"); +} +printf("\n"); + +int main() +{ + return 0; +} diff --git a/src/cmd/picoc/tests/48_nested_break.expect b/src/cmd/picoc/tests/48_nested_break.expect new file mode 100644 index 0000000..573541a --- /dev/null +++ b/src/cmd/picoc/tests/48_nested_break.expect @@ -0,0 +1 @@ +0 diff --git a/src/cmd/picoc/tests/49_bracket_evaluation.c b/src/cmd/picoc/tests/49_bracket_evaluation.c new file mode 100644 index 0000000..b4303c6 --- /dev/null +++ b/src/cmd/picoc/tests/49_bracket_evaluation.c @@ -0,0 +1,21 @@ +#include + +struct point +{ + double x; + double y; +}; + +struct point point_array[100]; + +int main() +{ + int my_point = 10; + + point_array[my_point].x = 12.34; + point_array[my_point].y = 56.78; + + printf("%f, %f\n", point_array[my_point].x, point_array[my_point].y); + + return 0; +} diff --git a/src/cmd/picoc/tests/49_bracket_evaluation.expect b/src/cmd/picoc/tests/49_bracket_evaluation.expect new file mode 100644 index 0000000..1da66db --- /dev/null +++ b/src/cmd/picoc/tests/49_bracket_evaluation.expect @@ -0,0 +1 @@ +12.340000, 56.780000 diff --git a/src/cmd/picoc/tests/50_logical_second_arg.c b/src/cmd/picoc/tests/50_logical_second_arg.c new file mode 100644 index 0000000..f4be825 --- /dev/null +++ b/src/cmd/picoc/tests/50_logical_second_arg.c @@ -0,0 +1,27 @@ +#include + +int fred() +{ + printf("fred\n"); + return 0; +} + +int joe() +{ + printf("joe\n"); + return 1; +} + +int main() +{ + printf("%d\n", fred() && joe()); + printf("%d\n", fred() || joe()); + printf("%d\n", joe() && fred()); + printf("%d\n", joe() || fred()); + printf("%d\n", fred() && (1 + joe())); + printf("%d\n", fred() || (0 + joe())); + printf("%d\n", joe() && (0 + fred())); + printf("%d\n", joe() || (1 + fred())); + + return 0; +} diff --git a/src/cmd/picoc/tests/50_logical_second_arg.expect b/src/cmd/picoc/tests/50_logical_second_arg.expect new file mode 100644 index 0000000..d6174ae --- /dev/null +++ b/src/cmd/picoc/tests/50_logical_second_arg.expect @@ -0,0 +1,20 @@ +fred +0 +fred +joe +1 +joe +fred +0 +joe +1 +fred +0 +fred +joe +1 +joe +fred +0 +joe +1 diff --git a/src/cmd/picoc/tests/51_static.c b/src/cmd/picoc/tests/51_static.c new file mode 100644 index 0000000..3e93ba9 --- /dev/null +++ b/src/cmd/picoc/tests/51_static.c @@ -0,0 +1,26 @@ +#include + +static int fred = 1234; +static int joe; + +void henry() +{ + static int fred = 4567; + + printf("%d\n", fred); + fred++; +} + +void main() +{ + printf("%d\n", fred); + henry(); + henry(); + henry(); + henry(); + printf("%d\n", fred); + fred = 8901; + joe = 2345; + printf("%d\n", fred); + printf("%d\n", joe); +} diff --git a/src/cmd/picoc/tests/51_static.expect b/src/cmd/picoc/tests/51_static.expect new file mode 100644 index 0000000..18224fa --- /dev/null +++ b/src/cmd/picoc/tests/51_static.expect @@ -0,0 +1,8 @@ +1234 +4567 +4568 +4569 +4570 +1234 +8901 +2345 diff --git a/src/cmd/picoc/tests/52_unnamed_enum.c b/src/cmd/picoc/tests/52_unnamed_enum.c new file mode 100644 index 0000000..7e99bfd --- /dev/null +++ b/src/cmd/picoc/tests/52_unnamed_enum.c @@ -0,0 +1,24 @@ +#include + +enum fred { a, b, c }; + +printf("a=%d\n", a); +printf("b=%d\n", b); +printf("c=%d\n", c); + +enum fred d; + +typedef enum { e, f, g } h; +typedef enum { i, j, k } m; + +printf("e=%d\n", e); +printf("f=%d\n", f); +printf("g=%d\n", g); + +printf("i=%d\n", i); +printf("j=%d\n", j); +printf("k=%d\n", k); + +void main() +{ +} diff --git a/src/cmd/picoc/tests/52_unnamed_enum.expect b/src/cmd/picoc/tests/52_unnamed_enum.expect new file mode 100644 index 0000000..84f2ac8 --- /dev/null +++ b/src/cmd/picoc/tests/52_unnamed_enum.expect @@ -0,0 +1,9 @@ +a=0 +b=1 +c=2 +e=0 +f=1 +g=2 +i=0 +j=1 +k=2 diff --git a/src/cmd/picoc/tests/54_goto.c b/src/cmd/picoc/tests/54_goto.c new file mode 100644 index 0000000..65ee7e2 --- /dev/null +++ b/src/cmd/picoc/tests/54_goto.c @@ -0,0 +1,52 @@ +#include + +void fred() +{ + printf("In fred()\n"); + goto done; + printf("In middle\n"); +done: + printf("At end\n"); +} + +void joe() +{ + int b = 5678; + + printf("In joe()\n"); + + { + int c = 1234; + printf("c = %d\n", c); + goto outer; + printf("uh-oh\n"); + } + +outer: + + printf("done\n"); +} + +void henry() +{ + int a; + + printf("In henry()\n"); + goto inner; + + { + int b; +inner: + b = 1234; + printf("b = %d\n", b); + } + + printf("done\n"); +} + +void main() +{ + fred(); + joe(); + henry(); +} diff --git a/src/cmd/picoc/tests/54_goto.expect b/src/cmd/picoc/tests/54_goto.expect new file mode 100644 index 0000000..8e553fa --- /dev/null +++ b/src/cmd/picoc/tests/54_goto.expect @@ -0,0 +1,8 @@ +In fred() +At end +In joe() +c = 1234 +done +In henry() +b = 1234 +done diff --git a/src/cmd/picoc/tests/55_array_initialiser.c b/src/cmd/picoc/tests/55_array_initialiser.c new file mode 100644 index 0000000..6d3d028 --- /dev/null +++ b/src/cmd/picoc/tests/55_array_initialiser.c @@ -0,0 +1,12 @@ +#include + +int main() +{ + int fred[3] = { 12, 34, 56 }; + double joe[] = { 23.4, 56.7, 89.0 }; + + printf("%d %d %d\n", fred[0], fred[1], fred[2]); + printf("%f %f %f\n", joe[0], joe[1], joe[2]); + + return 0; +} diff --git a/src/cmd/picoc/tests/55_array_initialiser.expect b/src/cmd/picoc/tests/55_array_initialiser.expect new file mode 100644 index 0000000..c486310 --- /dev/null +++ b/src/cmd/picoc/tests/55_array_initialiser.expect @@ -0,0 +1,2 @@ +12 34 56 +23.400000 56.700000 89.000000 diff --git a/src/cmd/picoc/tests/Makefile b/src/cmd/picoc/tests/Makefile new file mode 100644 index 0000000..a73199a --- /dev/null +++ b/src/cmd/picoc/tests/Makefile @@ -0,0 +1,74 @@ +TESTS= 00_assignment.test \ + 01_comment.test \ + 02_printf.test \ + 03_struct.test \ + 04_for.test \ + 05_array.test \ + 06_case.test \ + 07_function.test \ + 08_while.test \ + 09_do_while.test \ + 10_pointer.test \ + 11_precedence.test \ + 12_hashdefine.test \ + 13_integer_literals.test \ + 14_if.test \ + 15_recursion.test \ + 16_nesting.test \ + 17_enum.test \ + 18_include.test \ + 19_pointer_arithmetic.test \ + 20_pointer_comparison.test \ + 21_char_array.test \ + 22_floating_point.test \ + 23_type_coercion.test \ + 24_math_library.test \ + 25_quicksort.test \ + 26_character_constants.test \ + 28_strings.test \ + 29_array_address.test \ + 30_hanoi.test \ + 31_args.test \ + 32_led.test \ + 33_ternary_op.test \ + 34_array_assignment.test \ + 35_sizeof.test \ + 36_array_initialisers.test \ + 37_sprintf.test \ + 38_multiple_array_index.test \ + 39_typedef.test \ + 40_stdio.test \ + 41_hashif.test \ + 43_void_param.test \ + 44_scoped_declarations.test \ + 45_empty_for.test \ + 47_switch_return.test \ + 48_nested_break.test \ + 49_bracket_evaluation.test \ + 50_logical_second_arg.test \ + 51_static.test \ + 52_unnamed_enum.test \ + 54_goto.test \ + 55_array_initialiser.test + +%.test: %.expect %.c + @echo Test: $*... + @if [ "x`echo $* | grep args`" != "x" ]; \ + then \ + ../picoc $*.c - arg1 arg2 arg3 arg4 2>&1 >$*.output; \ + else \ + ../picoc $*.c 2>&1 >$*.output; \ + fi + @if [ "x`diff -qbu $*.expect $*.output`" != "x" ]; \ + then \ + echo "error in test $*"; \ + diff -u $*.expect $*.output; \ + rm -f $*.output; \ + exit 1; \ + fi; \ + rm -f $*.output + +all: test + +test: $(TESTS) + @echo "test passed" diff --git a/src/cmd/picoc/type.c b/src/cmd/picoc/type.c new file mode 100644 index 0000000..2f91df9 --- /dev/null +++ b/src/cmd/picoc/type.c @@ -0,0 +1,549 @@ +/* picoc data type module. This manages a tree of data types and has facilities + * for parsing data types. */ + +#include "interpreter.h" + +/* some basic types */ +struct ValueType UberType; +struct ValueType IntType; +struct ValueType ShortType; +struct ValueType CharType; +struct ValueType LongType; +struct ValueType UnsignedIntType; +struct ValueType UnsignedShortType; +struct ValueType UnsignedLongType; +#ifndef NO_FP +struct ValueType FPType; +#endif +struct ValueType VoidType; +struct ValueType TypeType; +struct ValueType FunctionType; +struct ValueType MacroType; +struct ValueType EnumType; +struct ValueType GotoLabelType; +struct ValueType *CharPtrType; +struct ValueType *CharPtrPtrType; +struct ValueType *CharArrayType; +struct ValueType *VoidPtrType; + +static int PointerAlignBytes; +static int IntAlignBytes; + + +/* add a new type to the set of types we know about */ +struct ValueType *TypeAdd(struct ParseState *Parser, struct ValueType *ParentType, enum BaseType Base, int ArraySize, const char *Identifier, int Sizeof, int AlignBytes) +{ + struct ValueType *NewType = VariableAlloc(Parser, sizeof(struct ValueType), TRUE); + NewType->Base = Base; + NewType->ArraySize = ArraySize; + NewType->Sizeof = Sizeof; + NewType->AlignBytes = AlignBytes; + NewType->Identifier = Identifier; + NewType->Members = NULL; + NewType->FromType = ParentType; + NewType->DerivedTypeList = NULL; + NewType->OnHeap = TRUE; + NewType->Next = ParentType->DerivedTypeList; + ParentType->DerivedTypeList = NewType; + + return NewType; +} + +/* given a parent type, get a matching derived type and make one if necessary. + * Identifier should be registered with the shared string table. */ +struct ValueType *TypeGetMatching(struct ParseState *Parser, struct ValueType *ParentType, enum BaseType Base, int ArraySize, const char *Identifier, int AllowDuplicates) +{ + int Sizeof; + int AlignBytes; + struct ValueType *ThisType = ParentType->DerivedTypeList; + while (ThisType != NULL && (ThisType->Base != Base || ThisType->ArraySize != ArraySize || ThisType->Identifier != Identifier)) + ThisType = ThisType->Next; + + if (ThisType != NULL) + { + if (AllowDuplicates) + return ThisType; + else + ProgramFail(Parser, "data type '%s' is already defined", Identifier); + } + + switch (Base) + { + case TypePointer: Sizeof = sizeof(void *); AlignBytes = PointerAlignBytes; break; + case TypeArray: Sizeof = ArraySize * ParentType->Sizeof; AlignBytes = ParentType->AlignBytes; break; + case TypeEnum: Sizeof = sizeof(int); AlignBytes = IntAlignBytes; break; + default: Sizeof = 0; AlignBytes = 0; break; /* structs and unions will get bigger when we add members to them */ + } + + return TypeAdd(Parser, ParentType, Base, ArraySize, Identifier, Sizeof, AlignBytes); +} + +/* stack space used by a value */ +int TypeStackSizeValue(struct Value *Val) +{ + if (Val != NULL && Val->ValOnStack) + return TypeSizeValue(Val, FALSE); + else + return 0; +} + +/* memory used by a value */ +int TypeSizeValue(struct Value *Val, int Compact) +{ + if (IS_INTEGER_NUMERIC(Val) && !Compact) + return sizeof(ALIGN_TYPE); /* allow some extra room for type extension */ + else if (Val->Typ->Base != TypeArray) + return Val->Typ->Sizeof; + else + return Val->Typ->FromType->Sizeof * Val->Typ->ArraySize; +} + +/* memory used by a variable given its type and array size */ +int TypeSize(struct ValueType *Typ, int ArraySize, int Compact) +{ + if (IS_INTEGER_NUMERIC_TYPE(Typ) && !Compact) + return sizeof(ALIGN_TYPE); /* allow some extra room for type extension */ + else if (Typ->Base != TypeArray) + return Typ->Sizeof; + else + return Typ->FromType->Sizeof * ArraySize; +} + +/* add a base type */ +void TypeAddBaseType(struct ValueType *TypeNode, enum BaseType Base, int Sizeof, int AlignBytes) +{ + TypeNode->Base = Base; + TypeNode->ArraySize = 0; + TypeNode->Sizeof = Sizeof; + TypeNode->AlignBytes = AlignBytes; + TypeNode->Identifier = StrEmpty; + TypeNode->Members = NULL; + TypeNode->FromType = NULL; + TypeNode->DerivedTypeList = NULL; + TypeNode->OnHeap = FALSE; + TypeNode->Next = UberType.DerivedTypeList; + UberType.DerivedTypeList = TypeNode; +} + +/* initialise the type system */ +void TypeInit() +{ + struct IntAlign { char x; int y; } ia; + struct ShortAlign { char x; short y; } sa; + struct CharAlign { char x; char y; } ca; + struct LongAlign { char x; long y; } la; +#ifndef NO_FP + struct DoubleAlign { char x; double y; } da; +#endif + struct PointerAlign { char x; void *y; } pa; + + IntAlignBytes = (char *)&ia.y - &ia.x; + PointerAlignBytes = (char *)&pa.y - &pa.x; + + UberType.DerivedTypeList = NULL; + TypeAddBaseType(&IntType, TypeInt, sizeof(int), IntAlignBytes); + TypeAddBaseType(&ShortType, TypeShort, sizeof(short), (char *)&sa.y - &sa.x); + TypeAddBaseType(&CharType, TypeChar, sizeof(unsigned char), (char *)&ca.y - &ca.x); + TypeAddBaseType(&LongType, TypeLong, sizeof(long), (char *)&la.y - &la.x); + TypeAddBaseType(&UnsignedIntType, TypeUnsignedInt, sizeof(unsigned int), IntAlignBytes); + TypeAddBaseType(&UnsignedShortType, TypeUnsignedShort, sizeof(unsigned short), (char *)&sa.y - &sa.x); + TypeAddBaseType(&UnsignedLongType, TypeUnsignedLong, sizeof(unsigned long), (char *)&la.y - &la.x); + TypeAddBaseType(&VoidType, TypeVoid, 0, 1); + TypeAddBaseType(&FunctionType, TypeFunction, sizeof(int), IntAlignBytes); + TypeAddBaseType(&MacroType, TypeMacro, sizeof(int), IntAlignBytes); + TypeAddBaseType(&GotoLabelType, TypeGotoLabel, 0, 1); +#ifndef NO_FP + TypeAddBaseType(&FPType, TypeFP, sizeof(double), (char *)&da.y - &da.x); + TypeAddBaseType(&TypeType, Type_Type, sizeof(double), (char *)&da.y - &da.x); /* must be large enough to cast to a double */ +#else + TypeAddBaseType(&TypeType, Type_Type, sizeof(struct ValueType *), PointerAlignBytes); +#endif + CharArrayType = TypeAdd(NULL, &CharType, TypeArray, 0, StrEmpty, sizeof(char), (char *)&ca.y - &ca.x); + CharPtrType = TypeAdd(NULL, &CharType, TypePointer, 0, StrEmpty, sizeof(void *), PointerAlignBytes); + CharPtrPtrType = TypeAdd(NULL, CharPtrType, TypePointer, 0, StrEmpty, sizeof(void *), PointerAlignBytes); + VoidPtrType = TypeAdd(NULL, &VoidType, TypePointer, 0, StrEmpty, sizeof(void *), PointerAlignBytes); +} + +/* deallocate heap-allocated types */ +void TypeCleanupNode(struct ValueType *Typ) +{ + struct ValueType *SubType; + struct ValueType *NextSubType; + + /* clean up and free all the sub-nodes */ + for (SubType = Typ->DerivedTypeList; SubType != NULL; SubType = NextSubType) + { + NextSubType = SubType->Next; + TypeCleanupNode(SubType); + if (SubType->OnHeap) + { + /* if it's a struct or union deallocate all the member values */ + if (SubType->Members != NULL) + { + VariableTableCleanup(SubType->Members); + HeapFreeMem(SubType->Members); + } + + /* free this node */ + HeapFreeMem(SubType); + } + } +} + +void TypeCleanup() +{ + TypeCleanupNode(&UberType); +} + +/* parse a struct or union declaration */ +void TypeParseStruct(struct ParseState *Parser, struct ValueType **Typ, int IsStruct) +{ + struct Value *LexValue; + struct ValueType *MemberType; + char *MemberIdentifier; + char *StructIdentifier; + struct Value *MemberValue; + enum LexToken Token; + int AlignBoundary; + + Token = LexGetToken(Parser, &LexValue, FALSE); + if (Token == TokenIdentifier) + { + LexGetToken(Parser, &LexValue, TRUE); + StructIdentifier = LexValue->Val->Identifier; + Token = LexGetToken(Parser, NULL, FALSE); + } + else + { + static char TempNameBuf[7] = "^s0000"; + StructIdentifier = PlatformMakeTempName(TempNameBuf); + } + + *Typ = TypeGetMatching(Parser, &UberType, IsStruct ? TypeStruct : TypeUnion, 0, StructIdentifier, Token != TokenLeftBrace); + + Token = LexGetToken(Parser, NULL, FALSE); + if (Token != TokenLeftBrace) + { + /* use the already defined structure */ + if ((*Typ)->Members == NULL) + ProgramFail(Parser, "structure '%s' isn't defined", LexValue->Val->Identifier); + + return; + } + + if (TopStackFrame != NULL) + ProgramFail(Parser, "struct/union definitions can only be globals"); + + LexGetToken(Parser, NULL, TRUE); + (*Typ)->Members = VariableAlloc(Parser, sizeof(struct Table) + STRUCT_TABLE_SIZE * sizeof(struct TableEntry), TRUE); + (*Typ)->Members->HashTable = (struct TableEntry **)((char *)(*Typ)->Members + sizeof(struct Table)); + TableInitTable((*Typ)->Members, (struct TableEntry **)((char *)(*Typ)->Members + sizeof(struct Table)), STRUCT_TABLE_SIZE, TRUE); + + do { + TypeParse(Parser, &MemberType, &MemberIdentifier, NULL); + if (MemberType == NULL || MemberIdentifier == NULL) + ProgramFail(Parser, "invalid type in struct"); + + MemberValue = VariableAllocValueAndData(Parser, sizeof(int), FALSE, NULL, TRUE); + MemberValue->Typ = MemberType; + if (IsStruct) + { + /* allocate this member's location in the struct */ + AlignBoundary = MemberValue->Typ->AlignBytes; + if (((*Typ)->Sizeof & (AlignBoundary-1)) != 0) + (*Typ)->Sizeof += AlignBoundary - ((*Typ)->Sizeof & (AlignBoundary-1)); + + MemberValue->Val->Integer = (*Typ)->Sizeof; + (*Typ)->Sizeof += TypeSizeValue(MemberValue, TRUE); + } + else + { + /* union members always start at 0, make sure it's big enough to hold the largest member */ + MemberValue->Val->Integer = 0; + if (MemberValue->Typ->Sizeof > (*Typ)->Sizeof) + (*Typ)->Sizeof = TypeSizeValue(MemberValue, TRUE); + } + + /* make sure to align to the size of the largest member's alignment */ + if ((*Typ)->AlignBytes < MemberValue->Typ->AlignBytes) + (*Typ)->AlignBytes = MemberValue->Typ->AlignBytes; + + /* define it */ + if (!TableSet((*Typ)->Members, MemberIdentifier, MemberValue, Parser->FileName, Parser->Line, Parser->CharacterPos)) + ProgramFail(Parser, "member '%s' already defined", &MemberIdentifier); + + if (LexGetToken(Parser, NULL, TRUE) != TokenSemicolon) + ProgramFail(Parser, "semicolon expected"); + + } while (LexGetToken(Parser, NULL, FALSE) != TokenRightBrace); + + /* now align the structure to the size of its largest member's alignment */ + AlignBoundary = (*Typ)->AlignBytes; + if (((*Typ)->Sizeof & (AlignBoundary-1)) != 0) + (*Typ)->Sizeof += AlignBoundary - ((*Typ)->Sizeof & (AlignBoundary-1)); + + LexGetToken(Parser, NULL, TRUE); +} + +/* create a system struct which has no user-visible members */ +struct ValueType *TypeCreateOpaqueStruct(struct ParseState *Parser, const char *StructName, int Size) +{ + struct ValueType *Typ = TypeGetMatching(Parser, &UberType, TypeStruct, 0, StructName, FALSE); + + /* create the (empty) table */ + Typ->Members = VariableAlloc(Parser, sizeof(struct Table) + STRUCT_TABLE_SIZE * sizeof(struct TableEntry), TRUE); + Typ->Members->HashTable = (struct TableEntry **)((char *)Typ->Members + sizeof(struct Table)); + TableInitTable(Typ->Members, (struct TableEntry **)((char *)Typ->Members + sizeof(struct Table)), STRUCT_TABLE_SIZE, TRUE); + Typ->Sizeof = Size; + + return Typ; +} + +/* parse an enum declaration */ +void TypeParseEnum(struct ParseState *Parser, struct ValueType **Typ) +{ + struct Value *LexValue; + struct Value InitValue; + enum LexToken Token; + struct ValueType *EnumType; + int EnumValue = 0; + char *EnumIdentifier; + + Token = LexGetToken(Parser, &LexValue, FALSE); + if (Token == TokenIdentifier) + { + LexGetToken(Parser, &LexValue, TRUE); + EnumIdentifier = LexValue->Val->Identifier; + Token = LexGetToken(Parser, NULL, FALSE); + } + else + { + static char TempNameBuf[7] = "^e0000"; + EnumIdentifier = PlatformMakeTempName(TempNameBuf); + } + + EnumType = TypeGetMatching(Parser, &UberType, TypeEnum, 0, EnumIdentifier, Token != TokenLeftBrace); + *Typ = &IntType; + if (Token != TokenLeftBrace) + { + /* use the already defined enum */ + if ((*Typ)->Members == NULL) + ProgramFail(Parser, "enum '%s' isn't defined", EnumIdentifier); + + return; + } + + if (TopStackFrame != NULL) + ProgramFail(Parser, "enum definitions can only be globals"); + + LexGetToken(Parser, NULL, TRUE); + (*Typ)->Members = &GlobalTable; + memset((void *)&InitValue, '\0', sizeof(struct Value)); + InitValue.Typ = &IntType; + InitValue.Val = (union AnyValue *)&EnumValue; + do { + if (LexGetToken(Parser, &LexValue, TRUE) != TokenIdentifier) + ProgramFail(Parser, "identifier expected"); + + EnumIdentifier = LexValue->Val->Identifier; + if (LexGetToken(Parser, NULL, FALSE) == TokenAssign) + { + LexGetToken(Parser, NULL, TRUE); + EnumValue = ExpressionParseInt(Parser); + } + + VariableDefine(Parser, EnumIdentifier, &InitValue, NULL, FALSE); + + Token = LexGetToken(Parser, NULL, TRUE); + if (Token != TokenComma && Token != TokenRightBrace) + ProgramFail(Parser, "comma expected"); + + EnumValue++; + + } while (Token == TokenComma); +} + +/* parse a type - just the basic type */ +int TypeParseFront(struct ParseState *Parser, struct ValueType **Typ, int *IsStatic) +{ + struct ParseState Before; + struct Value *LexerValue; + enum LexToken Token; + int Unsigned = FALSE; + struct Value *VarValue; + int StaticQualifier = FALSE; + *Typ = NULL; + + /* ignore leading type qualifiers */ + ParserCopy(&Before, Parser); + Token = LexGetToken(Parser, &LexerValue, TRUE); + while (Token == TokenStaticType || Token == TokenAutoType || Token == TokenRegisterType || Token == TokenExternType) + { + if (Token == TokenStaticType) + StaticQualifier = TRUE; + + Token = LexGetToken(Parser, &LexerValue, TRUE); + } + + if (IsStatic != NULL) + *IsStatic = StaticQualifier; + + /* handle signed/unsigned with no trailing type */ + if (Token == TokenSignedType || Token == TokenUnsignedType) + { + enum LexToken FollowToken = LexGetToken(Parser, &LexerValue, FALSE); + Unsigned = (Token == TokenUnsignedType); + + if (FollowToken != TokenIntType && FollowToken != TokenLongType && FollowToken != TokenShortType && FollowToken != TokenCharType) + { + if (Token == TokenUnsignedType) + *Typ = &UnsignedIntType; + else + *Typ = &IntType; + + return TRUE; + } + + Token = LexGetToken(Parser, &LexerValue, TRUE); + } + + switch (Token) + { + case TokenIntType: *Typ = Unsigned ? &UnsignedIntType : &IntType; break; + case TokenShortType: *Typ = Unsigned ? &UnsignedShortType : &ShortType; break; + case TokenCharType: *Typ = &CharType; break; + case TokenLongType: *Typ = Unsigned ? &UnsignedLongType : &LongType; break; +#ifndef NO_FP + case TokenFloatType: case TokenDoubleType: *Typ = &FPType; break; +#endif + case TokenVoidType: *Typ = &VoidType; break; + + case TokenStructType: case TokenUnionType: + if (*Typ != NULL) + ProgramFail(Parser, "bad type declaration"); + + TypeParseStruct(Parser, Typ, Token == TokenStructType); + break; + + case TokenEnumType: + if (*Typ != NULL) + ProgramFail(Parser, "bad type declaration"); + + TypeParseEnum(Parser, Typ); + break; + + case TokenIdentifier: + /* we already know it's a typedef-defined type because we got here */ + VariableGet(Parser, LexerValue->Val->Identifier, &VarValue); + *Typ = VarValue->Val->Typ; + break; + + default: ParserCopy(Parser, &Before); return FALSE; + } + + return TRUE; +} + +/* parse a type - the part at the end after the identifier. eg. array specifications etc. */ +struct ValueType *TypeParseBack(struct ParseState *Parser, struct ValueType *FromType) +{ + enum LexToken Token; + struct ParseState Before; + + ParserCopy(&Before, Parser); + Token = LexGetToken(Parser, NULL, TRUE); + if (Token == TokenLeftSquareBracket) + { + /* add another array bound */ + if (LexGetToken(Parser, NULL, FALSE) == TokenRightSquareBracket) + { + /* an unsized array */ + LexGetToken(Parser, NULL, TRUE); + return TypeGetMatching(Parser, TypeParseBack(Parser, FromType), TypeArray, 0, StrEmpty, TRUE); + } + else + { + /* get a numeric array size */ + enum RunMode OldMode = Parser->Mode; + int ArraySize; + Parser->Mode = RunModeRun; + ArraySize = ExpressionParseInt(Parser); + Parser->Mode = OldMode; + + if (LexGetToken(Parser, NULL, TRUE) != TokenRightSquareBracket) + ProgramFail(Parser, "']' expected"); + + return TypeGetMatching(Parser, TypeParseBack(Parser, FromType), TypeArray, ArraySize, StrEmpty, TRUE); + } + } + else + { + /* the type specification has finished */ + ParserCopy(Parser, &Before); + return FromType; + } +} + +/* parse a type - the part which is repeated with each identifier in a declaration list */ +void TypeParseIdentPart(struct ParseState *Parser, struct ValueType *BasicTyp, struct ValueType **Typ, char **Identifier) +{ + struct ParseState Before; + enum LexToken Token; + struct Value *LexValue; + int Done = FALSE; + *Typ = BasicTyp; + *Identifier = StrEmpty; + + while (!Done) + { + ParserCopy(&Before, Parser); + Token = LexGetToken(Parser, &LexValue, TRUE); + switch (Token) + { + case TokenOpenBracket: + if (*Typ != NULL) + ProgramFail(Parser, "bad type declaration"); + + TypeParse(Parser, Typ, Identifier, NULL); + if (LexGetToken(Parser, NULL, TRUE) != TokenCloseBracket) + ProgramFail(Parser, "')' expected"); + break; + + case TokenAsterisk: + if (*Typ == NULL) + ProgramFail(Parser, "bad type declaration"); + + *Typ = TypeGetMatching(Parser, *Typ, TypePointer, 0, StrEmpty, TRUE); + break; + + case TokenIdentifier: + if (*Typ == NULL || *Identifier != StrEmpty) + ProgramFail(Parser, "bad type declaration"); + + *Identifier = LexValue->Val->Identifier; + Done = TRUE; + break; + + default: ParserCopy(Parser, &Before); Done = TRUE; break; + } + } + + if (*Typ == NULL) + ProgramFail(Parser, "bad type declaration"); + + if (*Identifier != StrEmpty) + { + /* parse stuff after the identifier */ + *Typ = TypeParseBack(Parser, *Typ); + } +} + +/* parse a type - a complete declaration including identifier */ +void TypeParse(struct ParseState *Parser, struct ValueType **Typ, char **Identifier, int *IsStatic) +{ + struct ValueType *BasicType; + + TypeParseFront(Parser, &BasicType, IsStatic); + TypeParseIdentPart(Parser, BasicType, Typ, Identifier); +} + diff --git a/src/cmd/picoc/variable.c b/src/cmd/picoc/variable.c new file mode 100644 index 0000000..c90717c --- /dev/null +++ b/src/cmd/picoc/variable.c @@ -0,0 +1,369 @@ +/* picoc variable storage. This provides ways of defining and accessing + * variables */ + +#include "interpreter.h" + +/* maximum size of a value to temporarily copy while we create a variable */ +#define MAX_TMP_COPY_BUF 256 + +/* the table of global definitions */ +struct Table GlobalTable; +struct TableEntry *GlobalHashTable[GLOBAL_TABLE_SIZE]; + +/* the table of string literal values */ +struct Table StringLiteralTable; +struct TableEntry *StringLiteralHashTable[STRING_LITERAL_TABLE_SIZE]; + +/* the stack */ +struct StackFrame *TopStackFrame = NULL; + + +/* initialise the variable system */ +void VariableInit() +{ + TableInitTable(&GlobalTable, &GlobalHashTable[0], GLOBAL_TABLE_SIZE, TRUE); + TableInitTable(&StringLiteralTable, &StringLiteralHashTable[0], STRING_LITERAL_TABLE_SIZE, TRUE); + TopStackFrame = NULL; +} + +/* deallocate the contents of a variable */ +void VariableFree(struct Value *Val) +{ + if (Val->ValOnHeap || Val->AnyValOnHeap) + { + /* free function bodies */ + if (Val->Typ == &FunctionType && Val->Val->FuncDef.Intrinsic == NULL && Val->Val->FuncDef.Body.Pos != NULL) + HeapFreeMem((void *)Val->Val->FuncDef.Body.Pos); + + /* free macro bodies */ + if (Val->Typ == &MacroType) + HeapFreeMem((void *)Val->Val->MacroDef.Body.Pos); + + /* free the AnyValue */ + if (Val->AnyValOnHeap) + HeapFreeMem(Val->Val); + } + + /* free the value */ + if (Val->ValOnHeap) + HeapFreeMem(Val); +} + +/* deallocate the global table and the string literal table */ +void VariableTableCleanup(struct Table *HashTable) +{ + struct TableEntry *Entry; + struct TableEntry *NextEntry; + int Count; + + for (Count = 0; Count < HashTable->Size; Count++) + { + for (Entry = HashTable->HashTable[Count]; Entry != NULL; Entry = NextEntry) + { + NextEntry = Entry->Next; + VariableFree(Entry->p.v.Val); + + /* free the hash table entry */ + HeapFreeMem(Entry); + } + } +} + +void VariableCleanup() +{ + VariableTableCleanup(&GlobalTable); + VariableTableCleanup(&StringLiteralTable); +} + +/* allocate some memory, either on the heap or the stack and check if we've run out */ +void *VariableAlloc(struct ParseState *Parser, int Size, int OnHeap) +{ + void *NewValue; + + if (OnHeap) + NewValue = HeapAllocMem(Size); + else + NewValue = HeapAllocStack(Size); + + if (NewValue == NULL) + ProgramFail(Parser, "out of memory"); + +#ifdef DEBUG_HEAP + if (!OnHeap) + printf("pushing %d at 0x%lx\n", Size, (unsigned long)NewValue); +#endif + + return NewValue; +} + +/* allocate a value either on the heap or the stack using space dependent on what type we want */ +struct Value *VariableAllocValueAndData(struct ParseState *Parser, int DataSize, int IsLValue, struct Value *LValueFrom, int OnHeap) +{ + struct Value *NewValue = VariableAlloc(Parser, MEM_ALIGN(sizeof(struct Value)) + DataSize, OnHeap); + NewValue->Val = (union AnyValue *)((char *)NewValue + MEM_ALIGN(sizeof(struct Value))); + NewValue->ValOnHeap = OnHeap; + NewValue->AnyValOnHeap = FALSE; + NewValue->ValOnStack = !OnHeap; + NewValue->IsLValue = IsLValue; + NewValue->LValueFrom = LValueFrom; + + return NewValue; +} + +/* allocate a value given its type */ +struct Value *VariableAllocValueFromType(struct ParseState *Parser, struct ValueType *Typ, int IsLValue, struct Value *LValueFrom, int OnHeap) +{ + int Size = TypeSize(Typ, Typ->ArraySize, FALSE); + struct Value *NewValue = VariableAllocValueAndData(Parser, Size, IsLValue, LValueFrom, OnHeap); + assert(Size >= 0 || Typ == &VoidType); + NewValue->Typ = Typ; + + return NewValue; +} + +/* allocate a value either on the heap or the stack and copy its value. handles overlapping data */ +struct Value *VariableAllocValueAndCopy(struct ParseState *Parser, struct Value *FromValue, int OnHeap) +{ + struct ValueType *DType = FromValue->Typ; + struct Value *NewValue; + char TmpBuf[MAX_TMP_COPY_BUF]; + int CopySize = TypeSizeValue(FromValue, TRUE); + + assert(CopySize <= MAX_TMP_COPY_BUF); + memcpy((void *)&TmpBuf[0], (void *)FromValue->Val, CopySize); + NewValue = VariableAllocValueAndData(Parser, CopySize, FromValue->IsLValue, FromValue->LValueFrom, OnHeap); + NewValue->Typ = DType; + memcpy((void *)NewValue->Val, (void *)&TmpBuf[0], CopySize); + + return NewValue; +} + +/* allocate a value either on the heap or the stack from an existing AnyValue and type */ +struct Value *VariableAllocValueFromExistingData(struct ParseState *Parser, struct ValueType *Typ, union AnyValue *FromValue, int IsLValue, struct Value *LValueFrom) +{ + struct Value *NewValue = VariableAlloc(Parser, sizeof(struct Value), FALSE); + NewValue->Typ = Typ; + NewValue->Val = FromValue; + NewValue->ValOnHeap = FALSE; + NewValue->AnyValOnHeap = FALSE; + NewValue->ValOnStack = FALSE; + NewValue->IsLValue = IsLValue; + NewValue->LValueFrom = LValueFrom; + + return NewValue; +} + +/* allocate a value either on the heap or the stack from an existing Value, sharing the value */ +struct Value *VariableAllocValueShared(struct ParseState *Parser, struct Value *FromValue) +{ + return VariableAllocValueFromExistingData(Parser, FromValue->Typ, FromValue->Val, FromValue->IsLValue, FromValue->IsLValue ? FromValue : NULL); +} + +/* reallocate a variable so its data has a new size */ +void VariableRealloc(struct ParseState *Parser, struct Value *FromValue, int NewSize) +{ + if (FromValue->AnyValOnHeap) + VariableFree((void*)FromValue->Val); + + FromValue->Val = VariableAlloc(Parser, NewSize, TRUE); + FromValue->AnyValOnHeap = TRUE; +} + +/* define a variable. Ident must be registered */ +struct Value *VariableDefine(struct ParseState *Parser, char *Ident, struct Value *InitValue, struct ValueType *Typ, int MakeWritable) +{ + struct Value *AssignValue; + + if (InitValue != NULL) + AssignValue = VariableAllocValueAndCopy(Parser, InitValue, TopStackFrame == NULL); + else + AssignValue = VariableAllocValueFromType(Parser, Typ, MakeWritable, NULL, TopStackFrame == NULL); + + AssignValue->IsLValue = MakeWritable; + + if (!TableSet((TopStackFrame == NULL) ? &GlobalTable : &TopStackFrame->LocalTable, Ident, AssignValue, Parser ? ((char *)Parser->FileName) : NULL, Parser ? Parser->Line : 0, Parser ? Parser->CharacterPos : 0)) + ProgramFail(Parser, "'%s' is already defined", Ident); + + return AssignValue; +} + +/* define a variable. Ident must be registered. If it's a redefinition from the same declaration don't throw an error */ +struct Value *VariableDefineButIgnoreIdentical(struct ParseState *Parser, char *Ident, struct ValueType *Typ, int IsStatic, int *FirstVisit) +{ + struct Value *ExistingValue; + const char *DeclFileName; + int DeclLine; + int DeclColumn; + + if (IsStatic) + { + char MangledName[LINEBUFFER_MAX]; + char *MNPos = &MangledName[0]; + char *MNEnd = &MangledName[LINEBUFFER_MAX-1]; + const char *RegisteredMangledName; + + /* make the mangled static name (avoiding using sprintf() to minimise library impact) */ + memset((void *)&MangledName, '\0', sizeof(MangledName)); + *MNPos++ = '/'; + strncpy(MNPos, (char *)Parser->FileName, MNEnd - MNPos); + MNPos += strlen(MNPos); + + if (TopStackFrame != NULL) + { + /* we're inside a function */ + if (MNEnd - MNPos > 0) *MNPos++ = '/'; + strncpy(MNPos, (char *)TopStackFrame->FuncName, MNEnd - MNPos); + MNPos += strlen(MNPos); + } + + if (MNEnd - MNPos > 0) *MNPos++ = '/'; + strncpy(MNPos, Ident, MNEnd - MNPos); + RegisteredMangledName = TableStrRegister(MangledName); + + /* is this static already defined? */ + if (!TableGet(&GlobalTable, RegisteredMangledName, &ExistingValue, &DeclFileName, &DeclLine, &DeclColumn)) + { + /* define the mangled-named static variable store in the global scope */ + ExistingValue = VariableAllocValueFromType(Parser, Typ, TRUE, NULL, TRUE); + TableSet(&GlobalTable, (char *)RegisteredMangledName, ExistingValue, (char *)Parser->FileName, Parser->Line, Parser->CharacterPos); + *FirstVisit = TRUE; + } + + /* static variable exists in the global scope - now make a mirroring variable in our own scope with the short name */ + VariableDefinePlatformVar(Parser, Ident, ExistingValue->Typ, ExistingValue->Val, TRUE); + return ExistingValue; + } + else + { + if (Parser->Line != 0 && TableGet((TopStackFrame == NULL) ? &GlobalTable : &TopStackFrame->LocalTable, Ident, &ExistingValue, &DeclFileName, &DeclLine, &DeclColumn) + && DeclFileName == Parser->FileName && DeclLine == Parser->Line && DeclColumn == Parser->CharacterPos) + return ExistingValue; + else + return VariableDefine(Parser, Ident, NULL, Typ, TRUE); + } +} + +/* check if a variable with a given name is defined. Ident must be registered */ +int VariableDefined(const char *Ident) +{ + struct Value *FoundValue; + + if (TopStackFrame == NULL || !TableGet(&TopStackFrame->LocalTable, Ident, &FoundValue, NULL, NULL, NULL)) + { + if (!TableGet(&GlobalTable, Ident, &FoundValue, NULL, NULL, NULL)) + return FALSE; + } + + return TRUE; +} + +/* get the value of a variable. must be defined. Ident must be registered */ +void VariableGet(struct ParseState *Parser, const char *Ident, struct Value **LVal) +{ + if (TopStackFrame == NULL || !TableGet(&TopStackFrame->LocalTable, Ident, LVal, NULL, NULL, NULL)) + { + if (!TableGet(&GlobalTable, Ident, LVal, NULL, NULL, NULL)) + ProgramFail(Parser, "'%s' is undefined", Ident); + } +} + +/* define a global variable shared with a platform global. Ident will be registered */ +void VariableDefinePlatformVar(struct ParseState *Parser, char *Ident, struct ValueType *Typ, union AnyValue *FromValue, int IsWritable) +{ + struct Value *SomeValue = VariableAllocValueAndData(NULL, 0, IsWritable, NULL, TRUE); + SomeValue->Typ = Typ; + SomeValue->Val = FromValue; + + if (!TableSet((TopStackFrame == NULL) ? &GlobalTable : &TopStackFrame->LocalTable, TableStrRegister(Ident), SomeValue, Parser ? Parser->FileName : NULL, Parser ? Parser->Line : 0, Parser ? Parser->CharacterPos : 0)) + ProgramFail(Parser, "'%s' is already defined", Ident); +} + +/* free and/or pop the top value off the stack. Var must be the top value on the stack! */ +void VariableStackPop(struct ParseState *Parser, struct Value *Var) +{ + int Success; + +#ifdef DEBUG_HEAP + if (Var->ValOnStack) + printf("popping %ld at 0x%lx\n", (unsigned long)(sizeof(struct Value) + TypeSizeValue(Var, FALSE)), (unsigned long)Var); +#endif + + if (Var->ValOnHeap) + { + if (Var->Val != NULL) + HeapFreeMem(Var->Val); + + Success = HeapPopStack(Var, sizeof(struct Value)); /* free from heap */ + } + else if (Var->ValOnStack) + Success = HeapPopStack(Var, sizeof(struct Value) + TypeSizeValue(Var, FALSE)); /* free from stack */ + else + Success = HeapPopStack(Var, sizeof(struct Value)); /* value isn't our problem */ + + if (!Success) + ProgramFail(Parser, "stack underrun"); +} + +/* add a stack frame when doing a function call */ +void VariableStackFrameAdd(struct ParseState *Parser, const char *FuncName, int NumParams) +{ + struct StackFrame *NewFrame; + + HeapPushStackFrame(); + NewFrame = HeapAllocStack(sizeof(struct StackFrame) + sizeof(struct Value *) * NumParams); + if (NewFrame == NULL) + ProgramFail(Parser, "out of memory"); + + ParserCopy(&NewFrame->ReturnParser, Parser); + NewFrame->FuncName = FuncName; + NewFrame->Parameter = (NumParams > 0) ? ((void *)((char *)NewFrame + sizeof(struct StackFrame))) : NULL; + TableInitTable(&NewFrame->LocalTable, &NewFrame->LocalHashTable[0], LOCAL_TABLE_SIZE, FALSE); + NewFrame->PreviousStackFrame = TopStackFrame; + TopStackFrame = NewFrame; +} + +/* remove a stack frame */ +void VariableStackFramePop(struct ParseState *Parser) +{ + if (TopStackFrame == NULL) + ProgramFail(Parser, "stack is empty - can't go back"); + + ParserCopy(Parser, &TopStackFrame->ReturnParser); + TopStackFrame = TopStackFrame->PreviousStackFrame; + HeapPopStackFrame(); +} + +/* get a string literal. assumes that Ident is already registered. NULL if not found */ +struct Value *VariableStringLiteralGet(char *Ident) +{ + struct Value *LVal = NULL; + + if (TableGet(&StringLiteralTable, Ident, &LVal, NULL, NULL, NULL)) + return LVal; + else + return NULL; +} + +/* define a string literal. assumes that Ident is already registered */ +void VariableStringLiteralDefine(char *Ident, struct Value *Val) +{ + TableSet(&StringLiteralTable, Ident, Val, NULL, 0, 0); +} + +/* check a pointer for validity and dereference it for use */ +void *VariableDereferencePointer(struct ParseState *Parser, struct Value *PointerValue, struct Value **DerefVal, int *DerefOffset, struct ValueType **DerefType, int *DerefIsLValue) +{ + if (DerefVal != NULL) + *DerefVal = NULL; + + if (DerefType != NULL) + *DerefType = PointerValue->Typ->FromType; + + if (DerefOffset != NULL) + *DerefOffset = 0; + + if (DerefIsLValue != NULL) + *DerefIsLValue = TRUE; + + return PointerValue->Val->Pointer; +} diff --git a/src/cmd/portio/Makefile b/src/cmd/portio/Makefile new file mode 100644 index 0000000..e967761 --- /dev/null +++ b/src/cmd/portio/Makefile @@ -0,0 +1,28 @@ +TOPSRC = $(shell cd ../../..; pwd) +include $(TOPSRC)/target.mk + +CFLAGS += -Werror -Wall + +SRCS = portio.c +OBJS = portio.o + +all: portio lol + +portio: ${OBJS} + ${CC} ${LDFLAGS} -o portio.elf ${OBJS} ${LIBS} + ${OBJDUMP} -S portio.elf > portio.dis + ${SIZE} portio.elf + ${ELF2AOUT} portio.elf $@ && rm portio.elf + +lol: lol.o + ${CC} ${LDFLAGS} -o lol.elf lol.o ${LIBS} + ${OBJDUMP} -S lol.elf > lol.dis + ${SIZE} lol.elf + ${ELF2AOUT} lol.elf $@ && rm lol.elf + +clean: + rm -f *.o *.elf portio lol *.elf *.dis *~ + +install: all + install portio $(DESTDIR)/bin/ + install lol $(DESTDIR)/bin/ diff --git a/src/cmd/portio/font6x10.c b/src/cmd/portio/font6x10.c new file mode 100644 index 0000000..668221a --- /dev/null +++ b/src/cmd/portio/font6x10.c @@ -0,0 +1,2361 @@ +/* + * Font information: + * name: 6x10 + * facename: -Misc-Fixed-Medium-R-Normal--10-100-75-75-C-60-ISO10646-1 + * w x h: 6x9 + * size: 127 + * ascent: 8 + * descent: 1 + * first char: 0 (0x00) + * last char: 126 (0x7e) + * default char: 0 (0x00) + * proportional: no + * Public domain terminal emulator font. Share and enjoy. + */ + +/* Font character bitmap data. */ +static const unsigned char font6x10_bits[] = { + +/* Character 0 (0x00): + width 6 + +------+ + | | + |* * * | + | | + |* * | + | | + |* * | + | | + |* * * | + | | + +------+ */ +0x00, +0xa8, +0x00, +0x88, +0x00, +0x88, +0x00, +0xa8, +0x00, + +/* Character 32 (0x20): + width 6 + +------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + +------+ */ +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, + +/* Character 33 (0x21): + width 6 + +------+ + | | + | * | + | * | + | * | + | * | + | * | + | | + | * | + | | + +------+ */ +0x00, +0x20, +0x20, +0x20, +0x20, +0x20, +0x00, +0x20, +0x00, + +/* Character 34 (0x22): + width 6 + +------+ + | | + | * * | + | * * | + | * * | + | | + | | + | | + | | + | | + +------+ */ +0x00, +0x50, +0x50, +0x50, +0x00, +0x00, +0x00, +0x00, +0x00, + +/* Character 35 (0x23): + width 6 + +------+ + | | + | * * | + | * * | + |***** | + | * * | + |***** | + | * * | + | * * | + | | + +------+ */ +0x00, +0x50, +0x50, +0xf8, +0x50, +0xf8, +0x50, +0x50, +0x00, + +/* Character 36 (0x24): + width 6 + +------+ + | | + | * | + | *** | + |* * | + | *** | + | * * | + | *** | + | * | + | | + +------+ */ +0x00, +0x20, +0x70, +0xa0, +0x70, +0x28, +0x70, +0x20, +0x00, + +/* Character 37 (0x25): + width 6 + +------+ + | | + | * * | + |* * * | + | * * | + | * | + | * * | + |* * * | + |* * | + | | + +------+ */ +0x00, +0x48, +0xa8, +0x50, +0x20, +0x50, +0xa8, +0x90, +0x00, + +/* Character 38 (0x26): + width 6 + +------+ + | | + | * | + |* * | + |* * | + | * | + |* * * | + |* * | + | ** * | + | | + +------+ */ +0x00, +0x40, +0xa0, +0xa0, +0x40, +0xa8, +0x90, +0x68, +0x00, + +/* Character 39 (0x27): + width 6 + +------+ + | | + | * | + | * | + | * | + | | + | | + | | + | | + | | + +------+ */ +0x00, +0x20, +0x20, +0x20, +0x00, +0x00, +0x00, +0x00, +0x00, + +/* Character 40 (0x28): + width 6 + +------+ + | | + | * | + | * | + | * | + | * | + | * | + | * | + | * | + | | + +------+ */ +0x00, +0x10, +0x20, +0x40, +0x40, +0x40, +0x20, +0x10, +0x00, + +/* Character 41 (0x29): + width 6 + +------+ + | | + | * | + | * | + | * | + | * | + | * | + | * | + | * | + | | + +------+ */ +0x00, +0x40, +0x20, +0x10, +0x10, +0x10, +0x20, +0x40, +0x00, + +/* Character 42 (0x2a): + width 6 + +------+ + | | + | | + |* * | + | * * | + |***** | + | * * | + |* * | + | | + | | + +------+ */ +0x00, +0x00, +0x88, +0x50, +0xf8, +0x50, +0x88, +0x00, +0x00, + +/* Character 43 (0x2b): + width 6 + +------+ + | | + | | + | * | + | * | + |***** | + | * | + | * | + | | + | | + +------+ */ +0x00, +0x00, +0x20, +0x20, +0xf8, +0x20, +0x20, +0x00, +0x00, + +/* Character 44 (0x2c): + width 6 + +------+ + | | + | | + | | + | | + | | + | | + | ** | + | * | + | * | + +------+ */ +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x30, +0x20, +0x40, + +/* Character 45 (0x2d): + width 6 + +------+ + | | + | | + | | + | | + |***** | + | | + | | + | | + | | + +------+ */ +0x00, +0x00, +0x00, +0x00, +0xf8, +0x00, +0x00, +0x00, +0x00, + +/* Character 46 (0x2e): + width 6 + +------+ + | | + | | + | | + | | + | | + | | + | * | + | *** | + | * | + +------+ */ +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x20, +0x70, +0x20, + +/* Character 47 (0x2f): + width 6 + +------+ + | | + | * | + | * | + | * | + | * | + | * | + |* | + |* | + | | + +------+ */ +0x00, +0x08, +0x08, +0x10, +0x20, +0x40, +0x80, +0x80, +0x00, + +/* Character 48 (0x30): + width 6 + +------+ + | | + | * | + | * * | + |* * | + |* * | + |* * | + | * * | + | * | + | | + +------+ */ +0x00, +0x20, +0x50, +0x88, +0x88, +0x88, +0x50, +0x20, +0x00, + +/* Character 49 (0x31): + width 6 + +------+ + | | + | * | + | ** | + |* * | + | * | + | * | + | * | + |***** | + | | + +------+ */ +0x00, +0x20, +0x60, +0xa0, +0x20, +0x20, +0x20, +0xf8, +0x00, + +/* Character 50 (0x32): + width 6 + +------+ + | | + | *** | + |* * | + | * | + | ** | + | * | + |* | + |***** | + | | + +------+ */ +0x00, +0x70, +0x88, +0x08, +0x30, +0x40, +0x80, +0xf8, +0x00, + +/* Character 51 (0x33): + width 6 + +------+ + | | + |***** | + | * | + | * | + | ** | + | * | + |* * | + | *** | + | | + +------+ */ +0x00, +0xf8, +0x08, +0x10, +0x30, +0x08, +0x88, +0x70, +0x00, + +/* Character 52 (0x34): + width 6 + +------+ + | | + | * | + | ** | + | * * | + |* * | + |***** | + | * | + | * | + | | + +------+ */ +0x00, +0x10, +0x30, +0x50, +0x90, +0xf8, +0x10, +0x10, +0x00, + +/* Character 53 (0x35): + width 6 + +------+ + | | + |***** | + |* | + |* ** | + |** * | + | * | + |* * | + | *** | + | | + +------+ */ +0x00, +0xf8, +0x80, +0xb0, +0xc8, +0x08, +0x88, +0x70, +0x00, + +/* Character 54 (0x36): + width 6 + +------+ + | | + | ** | + | * | + |* | + |* ** | + |** * | + |* * | + | *** | + | | + +------+ */ +0x00, +0x30, +0x40, +0x80, +0xb0, +0xc8, +0x88, +0x70, +0x00, + +/* Character 55 (0x37): + width 6 + +------+ + | | + |***** | + | * | + | * | + | * | + | * | + | * | + | * | + | | + +------+ */ +0x00, +0xf8, +0x08, +0x10, +0x10, +0x20, +0x40, +0x40, +0x00, + +/* Character 56 (0x38): + width 6 + +------+ + | | + | *** | + |* * | + |* * | + | *** | + |* * | + |* * | + | *** | + | | + +------+ */ +0x00, +0x70, +0x88, +0x88, +0x70, +0x88, +0x88, +0x70, +0x00, + +/* Character 57 (0x39): + width 6 + +------+ + | | + | *** | + |* * | + |* ** | + | ** * | + | * | + | * | + | ** | + | | + +------+ */ +0x00, +0x70, +0x88, +0x98, +0x68, +0x08, +0x10, +0x60, +0x00, + +/* Character 58 (0x3a): + width 6 + +------+ + | | + | | + | * | + | *** | + | * | + | | + | * | + | *** | + | * | + +------+ */ +0x00, +0x00, +0x20, +0x70, +0x20, +0x00, +0x20, +0x70, +0x20, + +/* Character 59 (0x3b): + width 6 + +------+ + | | + | | + | * | + | *** | + | * | + | | + | ** | + | * | + | * | + +------+ */ +0x00, +0x00, +0x20, +0x70, +0x20, +0x00, +0x30, +0x20, +0x40, + +/* Character 60 (0x3c): + width 6 + +------+ + | | + | * | + | * | + | * | + | * | + | * | + | * | + | * | + | | + +------+ */ +0x00, +0x08, +0x10, +0x20, +0x40, +0x20, +0x10, +0x08, +0x00, + +/* Character 61 (0x3d): + width 6 + +------+ + | | + | | + | | + |***** | + | | + |***** | + | | + | | + | | + +------+ */ +0x00, +0x00, +0x00, +0xf8, +0x00, +0xf8, +0x00, +0x00, +0x00, + +/* Character 62 (0x3e): + width 6 + +------+ + | | + | * | + | * | + | * | + | * | + | * | + | * | + | * | + | | + +------+ */ +0x00, +0x40, +0x20, +0x10, +0x08, +0x10, +0x20, +0x40, +0x00, + +/* Character 63 (0x3f): + width 6 + +------+ + | | + | *** | + |* * | + | * | + | * | + | * | + | | + | * | + | | + +------+ */ +0x00, +0x70, +0x88, +0x10, +0x20, +0x20, +0x00, +0x20, +0x00, + +/* Character 64 (0x40): + width 6 + +------+ + | | + | *** | + |* * | + |* ** | + |* * * | + |* ** | + |* | + | *** | + | | + +------+ */ +0x00, +0x70, +0x88, +0x98, +0xa8, +0xb0, +0x80, +0x70, +0x00, + +/* Character 65 (0x41): + width 6 + +------+ + | | + | * | + | * * | + |* * | + |* * | + |***** | + |* * | + |* * | + | | + +------+ */ +0x00, +0x20, +0x50, +0x88, +0x88, +0xf8, +0x88, +0x88, +0x00, + +/* Character 66 (0x42): + width 6 + +------+ + | | + |**** | + | * * | + | * * | + | *** | + | * * | + | * * | + |**** | + | | + +------+ */ +0x00, +0xf0, +0x48, +0x48, +0x70, +0x48, +0x48, +0xf0, +0x00, + +/* Character 67 (0x43): + width 6 + +------+ + | | + | *** | + |* * | + |* | + |* | + |* | + |* * | + | *** | + | | + +------+ */ +0x00, +0x70, +0x88, +0x80, +0x80, +0x80, +0x88, +0x70, +0x00, + +/* Character 68 (0x44): + width 6 + +------+ + | | + |**** | + | * * | + | * * | + | * * | + | * * | + | * * | + |**** | + | | + +------+ */ +0x00, +0xf0, +0x48, +0x48, +0x48, +0x48, +0x48, +0xf0, +0x00, + +/* Character 69 (0x45): + width 6 + +------+ + | | + |***** | + |* | + |* | + |**** | + |* | + |* | + |***** | + | | + +------+ */ +0x00, +0xf8, +0x80, +0x80, +0xf0, +0x80, +0x80, +0xf8, +0x00, + +/* Character 70 (0x46): + width 6 + +------+ + | | + |***** | + |* | + |* | + |**** | + |* | + |* | + |* | + | | + +------+ */ +0x00, +0xf8, +0x80, +0x80, +0xf0, +0x80, +0x80, +0x80, +0x00, + +/* Character 71 (0x47): + width 6 + +------+ + | | + | *** | + |* * | + |* | + |* | + |* ** | + |* * | + | *** | + | | + +------+ */ +0x00, +0x70, +0x88, +0x80, +0x80, +0x98, +0x88, +0x70, +0x00, + +/* Character 72 (0x48): + width 6 + +------+ + | | + |* * | + |* * | + |* * | + |***** | + |* * | + |* * | + |* * | + | | + +------+ */ +0x00, +0x88, +0x88, +0x88, +0xf8, +0x88, +0x88, +0x88, +0x00, + +/* Character 73 (0x49): + width 6 + +------+ + | | + | *** | + | * | + | * | + | * | + | * | + | * | + | *** | + | | + +------+ */ +0x00, +0x70, +0x20, +0x20, +0x20, +0x20, +0x20, +0x70, +0x00, + +/* Character 74 (0x4a): + width 6 + +------+ + | | + | *** | + | * | + | * | + | * | + | * | + |* * | + | ** | + | | + +------+ */ +0x00, +0x38, +0x10, +0x10, +0x10, +0x10, +0x90, +0x60, +0x00, + +/* Character 75 (0x4b): + width 6 + +------+ + | | + |* * | + |* * | + |* * | + |** | + |* * | + |* * | + |* * | + | | + +------+ */ +0x00, +0x88, +0x90, +0xa0, +0xc0, +0xa0, +0x90, +0x88, +0x00, + +/* Character 76 (0x4c): + width 6 + +------+ + | | + |* | + |* | + |* | + |* | + |* | + |* | + |***** | + | | + +------+ */ +0x00, +0x80, +0x80, +0x80, +0x80, +0x80, +0x80, +0xf8, +0x00, + +/* Character 77 (0x4d): + width 6 + +------+ + | | + |* * | + |* * | + |** ** | + |* * * | + |* * | + |* * | + |* * | + | | + +------+ */ +0x00, +0x88, +0x88, +0xd8, +0xa8, +0x88, +0x88, +0x88, +0x00, + +/* Character 78 (0x4e): + width 6 + +------+ + | | + |* * | + |* * | + |** * | + |* * * | + |* ** | + |* * | + |* * | + | | + +------+ */ +0x00, +0x88, +0x88, +0xc8, +0xa8, +0x98, +0x88, +0x88, +0x00, + +/* Character 79 (0x4f): + width 6 + +------+ + | | + | *** | + |* * | + |* * | + |* * | + |* * | + |* * | + | *** | + | | + +------+ */ +0x00, +0x70, +0x88, +0x88, +0x88, +0x88, +0x88, +0x70, +0x00, + +/* Character 80 (0x50): + width 6 + +------+ + | | + |**** | + |* * | + |* * | + |**** | + |* | + |* | + |* | + | | + +------+ */ +0x00, +0xf0, +0x88, +0x88, +0xf0, +0x80, +0x80, +0x80, +0x00, + +/* Character 81 (0x51): + width 6 + +------+ + | | + | *** | + |* * | + |* * | + |* * | + |* * | + |* * * | + | *** | + | * | + +------+ */ +0x00, +0x70, +0x88, +0x88, +0x88, +0x88, +0xa8, +0x70, +0x08, + +/* Character 82 (0x52): + width 6 + +------+ + | | + |**** | + |* * | + |* * | + |**** | + |* * | + |* * | + |* * | + | | + +------+ */ +0x00, +0xf0, +0x88, +0x88, +0xf0, +0xa0, +0x90, +0x88, +0x00, + +/* Character 83 (0x53): + width 6 + +------+ + | | + | *** | + |* * | + |* | + | *** | + | * | + |* * | + | *** | + | | + +------+ */ +0x00, +0x70, +0x88, +0x80, +0x70, +0x08, +0x88, +0x70, +0x00, + +/* Character 84 (0x54): + width 6 + +------+ + | | + |***** | + | * | + | * | + | * | + | * | + | * | + | * | + | | + +------+ */ +0x00, +0xf8, +0x20, +0x20, +0x20, +0x20, +0x20, +0x20, +0x00, + +/* Character 85 (0x55): + width 6 + +------+ + | | + |* * | + |* * | + |* * | + |* * | + |* * | + |* * | + | *** | + | | + +------+ */ +0x00, +0x88, +0x88, +0x88, +0x88, +0x88, +0x88, +0x70, +0x00, + +/* Character 86 (0x56): + width 6 + +------+ + | | + |* * | + |* * | + |* * | + | * * | + | * * | + | * * | + | * | + | | + +------+ */ +0x00, +0x88, +0x88, +0x88, +0x50, +0x50, +0x50, +0x20, +0x00, + +/* Character 87 (0x57): + width 6 + +------+ + | | + |* * | + |* * | + |* * | + |* * * | + |* * * | + |** ** | + |* * | + | | + +------+ */ +0x00, +0x88, +0x88, +0x88, +0xa8, +0xa8, +0xd8, +0x88, +0x00, + +/* Character 88 (0x58): + width 6 + +------+ + | | + |* * | + |* * | + | * * | + | * | + | * * | + |* * | + |* * | + | | + +------+ */ +0x00, +0x88, +0x88, +0x50, +0x20, +0x50, +0x88, +0x88, +0x00, + +/* Character 89 (0x59): + width 6 + +------+ + | | + |* * | + |* * | + | * * | + | * | + | * | + | * | + | * | + | | + +------+ */ +0x00, +0x88, +0x88, +0x50, +0x20, +0x20, +0x20, +0x20, +0x00, + +/* Character 90 (0x5a): + width 6 + +------+ + | | + |***** | + | * | + | * | + | * | + | * | + |* | + |***** | + | | + +------+ */ +0x00, +0xf8, +0x08, +0x10, +0x20, +0x40, +0x80, +0xf8, +0x00, + +/* Character 91 (0x5b): + width 6 + +------+ + | | + | *** | + | * | + | * | + | * | + | * | + | * | + | *** | + | | + +------+ */ +0x00, +0x70, +0x40, +0x40, +0x40, +0x40, +0x40, +0x70, +0x00, + +/* Character 92 (0x5c): + width 6 + +------+ + | | + |* | + |* | + | * | + | * | + | * | + | * | + | * | + | | + +------+ */ +0x00, +0x80, +0x80, +0x40, +0x20, +0x10, +0x08, +0x08, +0x00, + +/* Character 93 (0x5d): + width 6 + +------+ + | | + | *** | + | * | + | * | + | * | + | * | + | * | + | *** | + | | + +------+ */ +0x00, +0x70, +0x10, +0x10, +0x10, +0x10, +0x10, +0x70, +0x00, + +/* Character 94 (0x5e): + width 6 + +------+ + | | + | * | + | * * | + |* * | + | | + | | + | | + | | + | | + +------+ */ +0x00, +0x20, +0x50, +0x88, +0x00, +0x00, +0x00, +0x00, +0x00, + +/* Character 95 (0x5f): + width 6 + +------+ + | | + | | + | | + | | + | | + | | + | | + | | + |***** | + +------+ */ +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0xf8, + +/* Character 96 (0x60): + width 6 + +------+ + | * | + | * | + | | + | | + | | + | | + | | + | | + | | + +------+ */ +0x20, +0x10, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, + +/* Character 97 (0x61): + width 6 + +------+ + | | + | | + | | + | *** | + | * | + | **** | + |* * | + | **** | + | | + +------+ */ +0x00, +0x00, +0x00, +0x70, +0x08, +0x78, +0x88, +0x78, +0x00, + +/* Character 98 (0x62): + width 6 + +------+ + | | + |* | + |* | + |* ** | + |** * | + |* * | + |** * | + |* ** | + | | + +------+ */ +0x00, +0x80, +0x80, +0xb0, +0xc8, +0x88, +0xc8, +0xb0, +0x00, + +/* Character 99 (0x63): + width 6 + +------+ + | | + | | + | | + | *** | + |* * | + |* | + |* * | + | *** | + | | + +------+ */ +0x00, +0x00, +0x00, +0x70, +0x88, +0x80, +0x88, +0x70, +0x00, + +/* Character 100 (0x64): + width 6 + +------+ + | | + | * | + | * | + | ** * | + |* ** | + |* * | + |* ** | + | ** * | + | | + +------+ */ +0x00, +0x08, +0x08, +0x68, +0x98, +0x88, +0x98, +0x68, +0x00, + +/* Character 101 (0x65): + width 6 + +------+ + | | + | | + | | + | *** | + |* * | + |***** | + |* | + | *** | + | | + +------+ */ +0x00, +0x00, +0x00, +0x70, +0x88, +0xf8, +0x80, +0x70, +0x00, + +/* Character 102 (0x66): + width 6 + +------+ + | | + | ** | + | * * | + | * | + |**** | + | * | + | * | + | * | + | | + +------+ */ +0x00, +0x30, +0x48, +0x40, +0xf0, +0x40, +0x40, +0x40, +0x00, + +/* Character 103 (0x67): + width 6 + +------+ + | | + | | + | | + | **** | + |* * | + |* * | + | **** | + | * | + |* * | + +------+ */ +0x00, +0x00, +0x00, +0x78, +0x88, +0x88, +0x78, +0x08, +0x88, + +/* Character 104 (0x68): + width 6 + +------+ + | | + |* | + |* | + |* ** | + |** * | + |* * | + |* * | + |* * | + | | + +------+ */ +0x00, +0x80, +0x80, +0xb0, +0xc8, +0x88, +0x88, +0x88, +0x00, + +/* Character 105 (0x69): + width 6 + +------+ + | | + | * | + | | + | ** | + | * | + | * | + | * | + | *** | + | | + +------+ */ +0x00, +0x20, +0x00, +0x60, +0x20, +0x20, +0x20, +0x70, +0x00, + +/* Character 106 (0x6a): + width 6 + +------+ + | | + | * | + | | + | ** | + | * | + | * | + | * | + | * * | + | ** | + +------+ */ +0x00, +0x08, +0x00, +0x18, +0x08, +0x08, +0x08, +0x48, +0x30, + +/* Character 107 (0x6b): + width 6 + +------+ + | | + |* | + |* | + |* * | + |* * | + |*** | + |* * | + |* * | + | | + +------+ */ +0x00, +0x80, +0x80, +0x88, +0x90, +0xe0, +0x90, +0x88, +0x00, + +/* Character 108 (0x6c): + width 6 + +------+ + | | + | ** | + | * | + | * | + | * | + | * | + | * | + | *** | + | | + +------+ */ +0x00, +0x60, +0x20, +0x20, +0x20, +0x20, +0x20, +0x70, +0x00, + +/* Character 109 (0x6d): + width 6 + +------+ + | | + | | + | | + |** * | + |* * * | + |* * * | + |* * * | + |* * | + | | + +------+ */ +0x00, +0x00, +0x00, +0xd0, +0xa8, +0xa8, +0xa8, +0x88, +0x00, + +/* Character 110 (0x6e): + width 6 + +------+ + | | + | | + | | + |* ** | + |** * | + |* * | + |* * | + |* * | + | | + +------+ */ +0x00, +0x00, +0x00, +0xb0, +0xc8, +0x88, +0x88, +0x88, +0x00, + +/* Character 111 (0x6f): + width 6 + +------+ + | | + | | + | | + | *** | + |* * | + |* * | + |* * | + | *** | + | | + +------+ */ +0x00, +0x00, +0x00, +0x70, +0x88, +0x88, +0x88, +0x70, +0x00, + +/* Character 112 (0x70): + width 6 + +------+ + | | + | | + | | + |* ** | + |** * | + |* * | + |** * | + |* ** | + |* | + +------+ */ +0x00, +0x00, +0x00, +0xb0, +0xc8, +0x88, +0xc8, +0xb0, +0x80, + +/* Character 113 (0x71): + width 6 + +------+ + | | + | | + | | + | ** * | + |* ** | + |* * | + |* ** | + | ** * | + | * | + +------+ */ +0x00, +0x00, +0x00, +0x68, +0x98, +0x88, +0x98, +0x68, +0x08, + +/* Character 114 (0x72): + width 6 + +------+ + | | + | | + | | + |* ** | + |** * | + |* | + |* | + |* | + | | + +------+ */ +0x00, +0x00, +0x00, +0xb0, +0xc8, +0x80, +0x80, +0x80, +0x00, + +/* Character 115 (0x73): + width 6 + +------+ + | | + | | + | | + | *** | + |* | + | *** | + | * | + |**** | + | | + +------+ */ +0x00, +0x00, +0x00, +0x70, +0x80, +0x70, +0x08, +0xf0, +0x00, + +/* Character 116 (0x74): + width 6 + +------+ + | | + | * | + | * | + |**** | + | * | + | * | + | * * | + | ** | + | | + +------+ */ +0x00, +0x40, +0x40, +0xf0, +0x40, +0x40, +0x48, +0x30, +0x00, + +/* Character 117 (0x75): + width 6 + +------+ + | | + | | + | | + |* * | + |* * | + |* * | + |* ** | + | ** * | + | | + +------+ */ +0x00, +0x00, +0x00, +0x88, +0x88, +0x88, +0x98, +0x68, +0x00, + +/* Character 118 (0x76): + width 6 + +------+ + | | + | | + | | + |* * | + |* * | + | * * | + | * * | + | * | + | | + +------+ */ +0x00, +0x00, +0x00, +0x88, +0x88, +0x50, +0x50, +0x20, +0x00, + +/* Character 119 (0x77): + width 6 + +------+ + | | + | | + | | + |* * | + |* * | + |* * * | + |* * * | + | * * | + | | + +------+ */ +0x00, +0x00, +0x00, +0x88, +0x88, +0xa8, +0xa8, +0x50, +0x00, + +/* Character 120 (0x78): + width 6 + +------+ + | | + | | + | | + |* * | + | * * | + | * | + | * * | + |* * | + | | + +------+ */ +0x00, +0x00, +0x00, +0x88, +0x50, +0x20, +0x50, +0x88, +0x00, + +/* Character 121 (0x79): + width 6 + +------+ + | | + | | + | | + |* * | + |* * | + |* ** | + | ** * | + | * | + | *** | + +------+ */ +0x00, +0x00, +0x00, +0x88, +0x88, +0x98, +0x68, +0x08, +0x70, + +/* Character 122 (0x7a): + width 6 + +------+ + | | + | | + | | + |***** | + | * | + | * | + | * | + |***** | + | | + +------+ */ +0x00, +0x00, +0x00, +0xf8, +0x10, +0x20, +0x40, +0xf8, +0x00, + +/* Character 123 (0x7b): + width 6 + +------+ + | | + | ** | + | * | + | * | + | ** | + | * | + | * | + | ** | + | | + +------+ */ +0x00, +0x18, +0x20, +0x10, +0x60, +0x10, +0x20, +0x18, +0x00, + +/* Character 124 (0x7c): + width 6 + +------+ + | | + | * | + | * | + | * | + | * | + | * | + | * | + | * | + | | + +------+ */ +0x00, +0x20, +0x20, +0x20, +0x20, +0x20, +0x20, +0x20, +0x00, + +/* Character 125 (0x7d): + width 6 + +------+ + | | + | ** | + | * | + | * | + | ** | + | * | + | * | + | ** | + | | + +------+ */ +0x00, +0x60, +0x10, +0x20, +0x18, +0x20, +0x10, +0x60, +0x00, + +/* Character 126 (0x7e): + width 6 + +------+ + | | + | * * | + |* * * | + |* * | + | | + | | + | | + | | + | | + +------+ */ +0x00, +0x48, +0xa8, +0x90, +0x00, +0x00, +0x00, +0x00, +0x00, +}; + +/* Character->glyph mapping. */ +static const unsigned short font6x10_offset[128] = { + 0, /* (0x00) */ + 0, /* (0x01) */ + 0, /* (0x02) */ + 0, /* (0x03) */ + 0, /* (0x04) */ + 0, /* (0x05) */ + 0, /* (0x06) */ + 0, /* (0x07) */ + 0, /* (0x08) */ + 0, /* (0x09) */ + 0, /* (0x0a) */ + 0, /* (0x0b) */ + 0, /* (0x0c) */ + 0, /* (0x0d) */ + 0, /* (0x0e) */ + 0, /* (0x0f) */ + 0, /* (0x10) */ + 0, /* (0x11) */ + 0, /* (0x12) */ + 0, /* (0x13) */ + 0, /* (0x14) */ + 0, /* (0x15) */ + 0, /* (0x16) */ + 0, /* (0x17) */ + 0, /* (0x18) */ + 0, /* (0x19) */ + 0, /* (0x1a) */ + 0, /* (0x1b) */ + 0, /* (0x1c) */ + 0, /* (0x1d) */ + 0, /* (0x1e) */ + 0, /* (0x1f) */ + 9, /* (0x20) */ + 18, /* (0x21) */ + 27, /* (0x22) */ + 36, /* (0x23) */ + 45, /* (0x24) */ + 54, /* (0x25) */ + 63, /* (0x26) */ + 72, /* (0x27) */ + 81, /* (0x28) */ + 90, /* (0x29) */ + 99, /* (0x2a) */ + 108, /* (0x2b) */ + 117, /* (0x2c) */ + 126, /* (0x2d) */ + 135, /* (0x2e) */ + 144, /* (0x2f) */ + 153, /* (0x30) */ + 162, /* (0x31) */ + 171, /* (0x32) */ + 180, /* (0x33) */ + 189, /* (0x34) */ + 198, /* (0x35) */ + 207, /* (0x36) */ + 216, /* (0x37) */ + 225, /* (0x38) */ + 234, /* (0x39) */ + 243, /* (0x3a) */ + 252, /* (0x3b) */ + 261, /* (0x3c) */ + 270, /* (0x3d) */ + 279, /* (0x3e) */ + 288, /* (0x3f) */ + 297, /* (0x40) */ + 306, /* (0x41) */ + 315, /* (0x42) */ + 324, /* (0x43) */ + 333, /* (0x44) */ + 342, /* (0x45) */ + 351, /* (0x46) */ + 360, /* (0x47) */ + 369, /* (0x48) */ + 378, /* (0x49) */ + 387, /* (0x4a) */ + 396, /* (0x4b) */ + 405, /* (0x4c) */ + 414, /* (0x4d) */ + 423, /* (0x4e) */ + 432, /* (0x4f) */ + 441, /* (0x50) */ + 450, /* (0x51) */ + 459, /* (0x52) */ + 468, /* (0x53) */ + 477, /* (0x54) */ + 486, /* (0x55) */ + 495, /* (0x56) */ + 504, /* (0x57) */ + 513, /* (0x58) */ + 522, /* (0x59) */ + 531, /* (0x5a) */ + 540, /* (0x5b) */ + 549, /* (0x5c) */ + 558, /* (0x5d) */ + 567, /* (0x5e) */ + 576, /* (0x5f) */ + 585, /* (0x60) */ + 594, /* (0x61) */ + 603, /* (0x62) */ + 612, /* (0x63) */ + 621, /* (0x64) */ + 630, /* (0x65) */ + 639, /* (0x66) */ + 648, /* (0x67) */ + 657, /* (0x68) */ + 666, /* (0x69) */ + 675, /* (0x6a) */ + 684, /* (0x6b) */ + 693, /* (0x6c) */ + 702, /* (0x6d) */ + 711, /* (0x6e) */ + 720, /* (0x6f) */ + 729, /* (0x70) */ + 738, /* (0x71) */ + 747, /* (0x72) */ + 756, /* (0x73) */ + 765, /* (0x74) */ + 774, /* (0x75) */ + 783, /* (0x76) */ + 792, /* (0x77) */ + 801, /* (0x78) */ + 810, /* (0x79) */ + 819, /* (0x7a) */ + 828, /* (0x7b) */ + 837, /* (0x7c) */ + 846, /* (0x7d) */ + 855, /* (0x7e) */ + 0, /* (0x7f) */ +}; + +#define FONT_WIDTH 6 +#define FONT_HEIGHT 9 diff --git a/src/cmd/portio/lol.c b/src/cmd/portio/lol.c new file mode 100644 index 0000000..19e1abe --- /dev/null +++ b/src/cmd/portio/lol.c @@ -0,0 +1,219 @@ +/* + * Basic LoL Shield Test for Duinomite running RetroBSD. + * + * Some LoL signals are used for SD card on Duinomite. + * So I had to modify Duinomite-shield, by cutting signals + * D9-D12 and connecting them to A1-A5. + * + * Writen for the LoL Shield, designed by Jimmie Rodgers: + * http://jimmieprodgers.com/kits/lolshield/ + * + * Copyright (C) 2012 Serge Vakulenko, + * + * 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 the copyright notice and this + * permission notice and warranty disclaimer appear in supporting + * documentation, and that the name of the author not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * + * The author disclaim all warranties with regard to this + * software, including all implied warranties of merchantability + * and fitness. In no event shall the author 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. + */ +#include +#include +#include +#include +#include +#include +#include + +#include "font6x10.c" + +/* + * Display a line of text. + */ +void display (fd, text) + int fd; + const char *text; +{ + static short picture [9]; + const unsigned char *glyph; + int c, x, y; + + /* Clear image. */ + memset (picture, 0, sizeof(picture)); + + /* Build a running text. */ + while (*text != 0) { + /* Get next symbol. */ + c = *text++; + if (c < ' ' || c > '~') + continue; + glyph = font6x10_bits + font6x10_offset [c]; + + for (x=0; x>= 1; + + /* Add a column of pixels */ + for (y=0; y>= 1; + + /* Display a frame. */ + ioctl (fd, GPIO_LOL | 120, picture); + } +} + +/* + * Demo 1: + * 1) vertical lines; + * 2) horizontal lines; + * 3) all LEDs on. + */ +void demo1 (fd) +{ + static unsigned short picture[9]; + int y, frame; + + printf ("LoL Demo 1 "); + fflush (stdout); + + for (frame = 0; frame<14; frame++) { + printf ("."); + fflush (stdout); + memset (picture, 0, sizeof(picture)); + + for (y=0; y<9; y++) + picture[y] |= 1 << frame; + + /* Display a frame. */ + ioctl (fd, GPIO_LOL | 100, picture); + } + for (frame = 0; frame<9; frame++) { + printf (":"); + fflush (stdout); + memset (picture, 0, sizeof(picture)); + + picture[frame] = (1 << 14) - 1; + + /* Display a frame. */ + ioctl (fd, GPIO_LOL | 100, picture); + } + printf (","); + fflush (stdout); + memset (picture, 0xFF, sizeof(picture)); + + /* Display a frame. */ + ioctl (fd, GPIO_LOL | 250, picture); + ioctl (fd, GPIO_LOL | 250, picture); + + printf (" Done\n"); +} + +void demo2 (fd) +{ + static unsigned short picture[9]; + int x, y, dx, dy; + + printf ("LoL Demo 2: press ^C to stop\n"); + memset (picture, 0, sizeof(picture)); + x = 0; + y = 0; + dx = 1; + dy = 1; + for (;;) { + /* Draw ball. */ + picture[y] |= 1 << x; + ioctl (fd, GPIO_LOL | 120, picture); + picture[y] &= ~(1 << x); + + /* Move the ball. */ + x += dx; + if (x < 0 || x >= 14) { + dx = -dx; + x += dx + dx; + } + y += dy; + if (y < 0 || y >= 9) { + dy = -dy; + y += dy + dy; + } + } +} + +void usage () +{ + fprintf (stderr, "LoL shield utility.\n"); + fprintf (stderr, "Usage:\n"); + fprintf (stderr, " lol [options] text\n"); + fprintf (stderr, "Options:\n"); + fprintf (stderr, " -1 -- demo of vertical and horizontal lines\n"); + fprintf (stderr, " -2 -- demo of ball in a box\n"); + fprintf (stderr, " text -- display a running text\n"); + exit (-1); +} + +int main (argc, argv) + char **argv; +{ + const char *devname = "/dev/porta"; + int fd, idle = 1; + + /* Open gpio device. */ + fd = open (devname, 1); + if (fd < 0) { + perror (devname); + exit (-1); + } + + for (;;) { + switch (getopt (argc, argv, "12")) { + case EOF: + break; + case '1': + demo1 (fd); + idle = 0; + continue; + case '2': + demo2 (fd); + idle = 0; + continue; + default: + usage (); + } + break; + } + argc -= optind; + argv += optind; + if (argc < 1 && idle) + usage (); + + while (argc-- > 0) { + display (fd, *argv++); + } + return 0; +} diff --git a/src/cmd/portio/portio.c b/src/cmd/portio/portio.c new file mode 100644 index 0000000..cfb67fa --- /dev/null +++ b/src/cmd/portio/portio.c @@ -0,0 +1,306 @@ +/* + * Control general purpose i/o pins. + * + * Copyright (C) 2012 Serge Vakulenko, + * + * 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 the copyright notice and this + * permission notice and warranty disclaimer appear in supporting + * documentation, and that the name of the author not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * + * The author disclaim all warranties with regard to this + * software, including all implied warranties of merchantability + * and fitness. In no event shall the author 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. + */ +#include +#include +#include +#include +#include +#include +#include + +enum { + OP_ASSIGN, + OP_CONF_INPUT, + OP_CONF_OUTPUT, + OP_CONF_OPENDRAIN, + OP_DECONF, + OP_SET, + OP_CLEAR, + OP_INVERT, + OP_POLL, +}; + +const char *opname[] = { + "ASSIGN", + "CONF_INPUT", + "CONF_OUTPUT", + "CONF_OPENDRAIN", + "DECONF", + "SET", + "CLEAR", + "INVERT", + "POLL", +}; + +char *progname; +int verbose; +int fd; + +/* + * Parse port name. + * Split it into port number and pin mask. + * Return nonzero on success. + * Examples: + * a0 single pin + * b3-7,11 list of pins + * c same as c0-15 (zero mask returned) + */ +int parse_port (char *arg, int *pnum, int *pmask) +{ + char *arg0 = arg; + + if (*arg >= 'a' && *arg <='z') + *pnum = *arg - 'a'; + else if (*arg >= 'A' && *arg <='Z') + *pnum = *arg - 'A'; + else { +fatal: fprintf (stderr, "%s: incorrect port '%s'\n", progname, arg0); + return 0; + } + *pmask = 0; + while (*++arg) { + char *ep; + unsigned from = strtoul (arg, &ep, 10); + if (ep == arg) + goto fatal; + arg = ep + 1; + if (*ep == '-') { + unsigned to = strtoul (arg, &ep, 10); + if (ep == arg) + goto fatal; + arg = ep + 1; + if (from > to) { + unsigned v = from; + from = to; + to = v; + } + *pmask |= (0xffff >> (15 - to + from)) << from; + } else { + *pmask |= 1 << from; + } + if (*ep == 0) + return 1; + if (*ep != ',') + goto fatal; + } + return 1; +} + +void do_op (int op, char *port_arg, char *value_arg) +{ + int pnum, pmask, i, value = 0; + + if (! parse_port (port_arg, &pnum, &pmask)) + return; + if (pmask == 0) { + /* No pin numbers - use all pins. */ + pmask = 0xffff; + } + + if (value_arg) { + if (value_arg[0] == '0' && value_arg[1] == 'b') { + /* Binary value 0bxxx */ + value = strtoul (value_arg + 2, 0, 2); + } else + value = strtoul (value_arg, 0, 0); + if (verbose) + printf ("%s port %c mask %04x value %04x\n", + opname[op], pnum + 'A', pmask, value); + } else if (verbose) { + printf ("%s port %c mask %04x\n", + opname[op], pnum + 'A', pmask); + } + + switch (op) { + case OP_ASSIGN: + if (pmask == 0xffff) { /* All pins */ + if (ioctl (fd, GPIO_STORE | GPIO_PORT (pnum), value) < 0) + perror ("GPIO_STORE"); + + } else if (pmask & (pmask-1)) { /* Several pins */ + for (i=1; ! (pmask & i); i<<=1) + value <<= 1; + if (ioctl (fd, GPIO_STORE | GPIO_PORT (pnum), value) < 0) + perror ("GPIO_STORE"); + + } else if (value & 1) { /* Set single pin */ + if (ioctl (fd, GPIO_SET | GPIO_PORT (pnum), pmask) < 0) + perror ("GPIO_SET"); + } else { /* Clear single pin */ + if (ioctl (fd, GPIO_CLEAR | GPIO_PORT (pnum), pmask) < 0) + perror ("GPIO_SET"); + } + break; + case OP_CONF_INPUT: + if (ioctl (fd, GPIO_CONFIN | GPIO_PORT (pnum), pmask) < 0) + perror ("GPIO_CONFIN"); + break; + case OP_CONF_OUTPUT: + if (ioctl (fd, GPIO_CONFOUT | GPIO_PORT (pnum), pmask) < 0) + perror ("GPIO_CONFOUT"); + break; + case OP_CONF_OPENDRAIN: + if (ioctl (fd, GPIO_CONFOD | GPIO_PORT (pnum), pmask) < 0) + perror ("GPIO_CONFOD"); + break; + case OP_DECONF: + if (ioctl (fd, GPIO_DECONF | GPIO_PORT (pnum), pmask) < 0) + perror ("GPIO_DECONF"); + break; + case OP_SET: + if (ioctl (fd, GPIO_SET | GPIO_PORT (pnum), pmask) < 0) + perror ("GPIO_SET"); + break; + case OP_CLEAR: + if (ioctl (fd, GPIO_CLEAR | GPIO_PORT (pnum), pmask) < 0) + perror ("GPIO_CLEAR"); + break; + case OP_INVERT: + if (ioctl (fd, GPIO_INVERT | GPIO_PORT (pnum), pmask) < 0) + perror ("GPIO_INVERT"); + break; + case OP_POLL: + value = ioctl (fd, GPIO_POLL | GPIO_PORT (pnum), 0); + if (value < 0) + perror ("GPIO_POLL"); + if (pmask == 0xffff) { /* All pins */ + printf ("0x%04x\n", value); + + } else { /* Some pins */ + value &= pmask; + for (i=1; ! (pmask & i); i<<=1) + value >>= 1; + printf ("%#x\n", value); + } + break; + } +} + +void usage () +{ + fprintf (stderr, "Control gpio pins.\n"); + fprintf (stderr, "Usage:\n"); + fprintf (stderr, " %s option...\n", progname); + fprintf (stderr, "Options:\n"); + fprintf (stderr, " -i ports configure ports as input\n"); + fprintf (stderr, " -o ports configure ports as output\n"); + fprintf (stderr, " -d ports configure ports as open-drain output\n"); + fprintf (stderr, " -x ports deconfigure ports\n"); + fprintf (stderr, " -a port value assign port value\n"); + fprintf (stderr, " -s ports set ports to 1\n"); + fprintf (stderr, " -c ports clear ports (set to 0)\n"); + fprintf (stderr, " -r ports reverse ports (invert)\n"); + fprintf (stderr, " -g ports get port values\n"); + fprintf (stderr, " -m msec delay in milliseconds\n"); + fprintf (stderr, " -v verbose mode\n"); + fprintf (stderr, "Ports:\n"); + fprintf (stderr, " a0 single pin\n"); + fprintf (stderr, " b3-7,11 list of pins\n"); + fprintf (stderr, " c same as c0-15\n"); + exit (-1); +} + +int main (int argc, char **argv) +{ + register int op, msec; + register char *arg; + const char *devname = "/dev/porta"; + + progname = *argv++; + if (argc <= 1) + usage(); + + fd = open (devname, 1); + if (fd < 0) { + perror (devname); + return -1; + } + + /* Default operation is poll. */ + op = OP_POLL; + while (--argc > 0) { + arg = *argv++; + if (arg[0] != '-') { + if (op == OP_ASSIGN) { + if (--argc <= 0 || **argv=='-') { + fprintf (stderr, "%s: option -a: second argument missed\n", progname); + return -1; + } + do_op (op, arg, *argv++); + } else { + do_op (op, arg, 0); + } + continue; + } + if (arg[1] == 0 || arg[2] != 0) { +badop: fprintf (stderr, "%s: unknown option `%s'\n", progname, arg); + return -1; + } + switch (arg[1]) { + case 'i': /* configure ports as input */ + op = OP_CONF_INPUT; + break; + case 'o': /* configure ports as output */ + op = OP_CONF_OUTPUT; + break; + case 'd': /* configure ports as open-drain output */ + op = OP_CONF_OPENDRAIN; + break; + case 'x': /* deconfigure ports */ + op = OP_DECONF; + break; + case 'a': /* set a value of port */ + op = OP_ASSIGN; + break; + case 's': /* set ports to 1 */ + op = OP_SET; + break; + case 'c': /* clear ports */ + op = OP_CLEAR; + break; + case 'r': /* reverse ports */ + op = OP_INVERT; + break; + case 'g': /* get port values */ + op = OP_POLL; + break; + case 'v': /* verbose mode */ + verbose++; + break; + case 'm': /* delay in milliseconds */ + if (--argc <= 0 || **argv=='-') { + fprintf (stderr, "%s: option -m: argument missed\n", progname); + return -1; + } + msec = strtol (*argv++, 0, 0); + usleep (msec * 1000); + break; + case 'h': /* help */ + usage(); + default: + goto badop; + } + } + return 0; +} diff --git a/src/cmd/pr.c b/src/cmd/pr.c new file mode 100644 index 0000000..a9997ee --- /dev/null +++ b/src/cmd/pr.c @@ -0,0 +1,457 @@ +/* + * print file with headings + * 2+head+2+page[56]+5 + */ +#include +#include +#include +#include +#include +#include + +/* Making putcp a macro sped things up by 14%. */ +#define putcp(c) if (page >= fpage) putchar(c) + +int ncol = 1; +char *header; +int col; +int icol; +FILE *file; +char *bufp; +#define BUFS 9000 /* at least 66 * 132 */ +char buffer[BUFS]; /* for multi-column output */ +char obuf[BUFSIZ]; +#define FF 014 +int line; +char *colp[72]; +int nofile; +char isclosed[10]; +FILE *ifile[10]; +char **lastarg; +int peekc; +int fpage; +int page; +int colw; +int nspace; +int width = 72; +int length = 66; +int plength = 61; +int margin = 10; +int ntflg; +int fflg; +int mflg; +int tabc; +char *tty; +int mode; +char *ttyname(); +char *ctime(); + +void +onintr (sig) + int sig; +{ + if (tty) + chmod(tty, mode); + _exit(1); +} + +main(argc, argv) +char **argv; +{ + int nfdone; + + setbuf(stdout, obuf); + if (signal(SIGINT, SIG_IGN) != SIG_IGN) + signal(SIGINT, onintr); + lastarg = &argv[argc-1]; + fixtty(); + for (nfdone=0; argc>1; argc--) { + argv++; + if (**argv == '-') { + switch (*++*argv) { + case 'h': /* define page header */ + if (argc>=2) { + header = *++argv; + argc--; + } + continue; + + case 't': /* don't print page headers */ + ntflg++; + continue; + + case 'f': /* use form feeds */ + fflg++; + plength = 60; + continue; + + case 'l': /* length of page */ + length = atoi(++*argv); + continue; + + case 'w': /* width of page */ + width = atoi(++*argv); + continue; + + case 's': /* col separator */ + if (*++*argv) + tabc = **argv; + else + tabc = '\t'; + continue; + + case 'm': /* all files at once */ + mflg++; + continue; + + default: + if (numeric(*argv)) { /* # of cols */ + if ((ncol = atoi(*argv)) == 0) { + fprintf(stderr, "can't print 0 cols, using 1 instead.\n"); + ncol = 1; + } + } else { + fprintf(stderr, "pr: bad key %s\n", *argv); + exit(1); + } + continue; + } + } else if (**argv == '+') { /* start at page ++*argv */ + fpage = atoi(++*argv); + } else { + print(*argv, argv); + nfdone++; + if (mflg) + break; + } + } + if (nfdone==0) + print((char *)0, (char **)0); + done(); +} + +done() +{ + + if (tty) + chmod(tty, mode); + exit(0); +} + +/* numeric -- returns 1 if str is numeric, elsewise 0 */ +numeric(str) + char *str; +{ + for (; *str ; str++) { + if (*str > '9' || *str < '0') { + return(0); + } + } + return(1); +} + +fixtty() +{ + struct stat sbuf; + + tty = ttyname(1); + if (tty == 0) + return; + stat(tty, &sbuf); + mode = sbuf.st_mode&0777; + chmod(tty, 0600); +} + +/* print -- print file */ +print(fp, argp) +char *fp; +char **argp; +{ + struct stat sbuf; + register sncol; + register char *sheader; + register char *cbuf; + char linebuf[150], *cp; + + if (ntflg) + margin = 0; + else + margin = 10; + if (length <= margin) + length = 66; + if (width <= 0) + width = 72; + if (ncol>72 || ncol>width) { + fprintf(stderr, "pr: No room for columns.\n"); + done(); + } + if (mflg) { + mopen(argp); + ncol = nofile; + } + colw = width/(ncol==0? 1 : ncol); + sncol = ncol; + sheader = header; + plength = length-5; + if (ntflg) + plength = length; + if (--ncol<0) + ncol = 0; + if (mflg) + fp = 0; + if (fp) { + if((file=fopen(fp, "r"))==NULL) { + if (tty==NULL) + perror(fp); + ncol = sncol; + header = sheader; + return; + } + stat(fp, &sbuf); + } else { + file = stdin; + time(&sbuf.st_mtime); + } + if (header == 0) + header = fp?fp:""; + cbuf = ctime(&sbuf.st_mtime); + cbuf[16] = '\0'; + cbuf[24] = '\0'; + page = 1; + icol = 0; + colp[ncol] = bufp = buffer; + if (mflg==0) + nexbuf(); + while (mflg&&nofile || (!mflg)&&tpgetc(ncol)>0) { + if (mflg==0) { + colp[ncol]--; + if (colp[ncol] < buffer) + colp[ncol] = &buffer[BUFS]; + } + line = 0; + if (ntflg==0) { + if (fflg) { + /* Assume a ff takes two blank lines at the + top of the page. */ + line = 2; + sprintf(linebuf, "%s %s %s Page %d\n\n\n", + cbuf+4, cbuf+20, header, page); + } else + sprintf(linebuf, "\n\n%s %s %s Page %d\n\n\n", + cbuf+4, cbuf+20, header, page); + for(cp=linebuf;*cp;) put(*cp++); + } + putpage(); + if (ntflg==0) { + if (fflg) + put('\f'); + else + while(line=10) { + fprintf(stderr, "pr: Too many args\n"); + done(); + } + } +} + +putpage() +{ + register int lastcol, i, c; + int j; + + if (ncol==0) { + while (line512) + n = 512; + if((n=fread(rbufp,1,n,file)) <= 0){ + fclose(file); + *rbufp = 0376; + } + else { + rbufp += n; + if (rbufp >= &buffer[BUFS]) + rbufp = buffer; + *rbufp = 0375; + } + bufp = rbufp; +} + +tpgetc(ai) +{ + register char **p; + register int c, i; + + i = ai; + if (mflg) { + if((c=getc(ifile[i])) == EOF) { + if (isclosed[i]==0) { + isclosed[i] = 1; + if (--nofile <= 0) + return(0); + } + return('\n'); + } + if (c==FF && ncol>0) + c = '\n'; + return(c); + } +loop: + c = **(p = &colp[i]) & 0377; + if (c == 0375) { + nexbuf(); + c = **p & 0377; + } + if (c == 0376) + return(0); + (*p)++; + if (*p >= &buffer[BUFS]) + *p = buffer; + if (c==0) + goto loop; + return(c); +} + +pgetc(i) +{ + register int c; + + if (peekc) { + c = peekc; + peekc = 0; + } else + c = tpgetc(i); + if (tabc) + return(c); + switch (c) { + + case '\t': + icol++; + if ((icol&07) != 0) + peekc = '\t'; + return(' '); + + case '\n': + icol = 0; + break; + + case 010: + case 033: + icol--; + break; + } + if (c >= ' ') + icol++; + return(c); +} +put(ac) +{ + register int ns, c; + + c = ac; + if (tabc) { + putcp(c); + if (c=='\n') + line++; + return; + } + switch (c) { + + case ' ': + nspace++; + col++; + return; + + case '\n': + col = 0; + nspace = 0; + line++; + break; + + case 010: + case 033: + if (--col<0) + col = 0; + if (--nspace<0) + nspace = 0; + + } + while(nspace) { + if (nspace>2 && col > (ns=((col-nspace)|07))) { + nspace = col-ns-1; + putcp('\t'); + } else { + nspace--; + putcp(' '); + } + } + if (c >= ' ') + col++; + putcp(c); +} diff --git a/src/cmd/printenv.c b/src/cmd/printenv.c new file mode 100644 index 0000000..d3481d1 --- /dev/null +++ b/src/cmd/printenv.c @@ -0,0 +1,51 @@ +/* + * printenv + * + * Bill Joy, UCB + * February, 1979 + * + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include +#include +#include + +int prefix(cp, dp) + char *cp, *dp; +{ + while (*cp && *dp && *cp == *dp) + cp++, dp++; + if (*cp == 0) + return (*dp == '='); + return 0; +} + +int main(argc, argv) + int argc; + char *argv[]; +{ + register char **ep; + int found = 0; + + if (! environ) + return 1; + + argc--, argv++; + for (ep = environ; *ep; ep++) { + if (argc == 0 || prefix(argv[0], *ep)) { + register char *cp = *ep; + + found++; + if (argc) { + while (*cp && *cp != '=') + cp++; + if (*cp == '=') + cp++; + } + printf("%s\n", cp); + } + } + return !found; +} diff --git a/src/cmd/printf/Makefile b/src/cmd/printf/Makefile new file mode 100644 index 0000000..ca01647 --- /dev/null +++ b/src/cmd/printf/Makefile @@ -0,0 +1,42 @@ +# +# Public Domain. 1995/05/02 - Steven Schultz +# +TOPSRC = $(shell cd ../../..; pwd) +include $(TOPSRC)/target.mk + +CFLAGS += -Werror -DNOFPU + +SRCS = printf.c +OBJS = printf.o +MAN = printf.0 +MANSRC = printf.1 + +all: printf ${MAN} + +printf: ${OBJS} + ${CC} ${LDFLAGS} -o printf.elf ${OBJS} ${LIBS} + ${OBJDUMP} -S printf.elf > printf.dis + ${SIZE} printf.elf + ${ELF2AOUT} printf.elf $@ && rm printf.elf + +${MAN}: ${MANSRC} + ${MANROFF} ${MANSRC} > ${MAN} + +clean: + rm -f *.o *.elf ${MAN} printf *.elf *.dis tags *~ + +depend: ${SRCS} + mkdep ${CFLAGS} ${SRCS} + +install: all + cp ${MAN} ${DESTDIR}/share/man/cat1/ + install printf ${DESTDIR}/bin/printf + +lint: ${SRCS} + lint -hax ${SRCS} + +tags: ${SRCS} + ctags ${SRCS} + +# DO NOT DELETE THIS LINE -- mkdep uses it. +# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY. diff --git a/src/cmd/printf/printf.1 b/src/cmd/printf/printf.1 new file mode 100644 index 0000000..b2909e7 --- /dev/null +++ b/src/cmd/printf/printf.1 @@ -0,0 +1,294 @@ +.\" 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.1 (2.11BSD) 1995/05/02 +.\" +.TH PRINTF 1 "May 2, 1995" +.UC 4 +.SH NAME +printf \- formatted output +.SH SYNOPSIS +.B printf format [ arguments ... ] +.SH DESCRIPTION +.B Printf +formats and prints its arguments, after the first, under control +of the +.IR format . +The +.I 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 +.IR argument . +.PP +The +.I arguments +after the first are treated as strings if the corresponding format is +either +.B c +or +.BR s ; +otherwise it is evaluated as a C constant, with the following extensions: +.TP +.B \(bu +A leading plus or minus sign is allowed. +.TP +.B \(bu +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. +.PP +The format string is reused as often as necessary to satisfy the +.IR 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 +ANSI C +Standard +X3J11. +The characters and their meanings +are as follows: +.br +.po +0.5i +.TP 10 +.B \ea +Write a character. +.TP 10 +.B \eb +Write a character. +.TP 10 +.B \ef +Write a character. +.TP 10 +.B \en +Write a character. +.TP 10 +.B \er +Write a character. +.TP 10 +.B \et +Write a character. +.TP 10 +.B \ev +Write a character. +.TP 10 +.B \e\' +Write a character. +.TP 10 +.B \e\e +Write a backslash character. +.TP 10 +.B \e\fInum\fP +Write an 8-bit character whose +ASCII +value is the 1-, 2-, or 3-digit +octal number +.IR num . +.br +.po -0.5i +.PP +Each format specification is introduced by the percent character +(``%''). +The remainder of the format specification includes, +in the following order: +.sp +"Zero or more of the following flags:" +.sp +.po +0.5i +.TP 10 +.B # +A `#' character +specifying that the value should be printed in an ``alternate form''. +For +.BR c , +.BR d , +and +.BR s , +formats, this option has no effect. For the +.B o +formats the precision of the number is increased to force the first +character of the output string to a zero. For the +.B x +(\fBX\fP) +format, a non-zero result has the string +0x +(0X) +prepended to it. For +.BR e , +.BR E , +.BR f , +.BR g , +and +.BR 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 +.B g +and +.B G +formats, trailing zeros are not removed from the result as they +would otherwise be; +.TP 10 +.B \- +A minus sign `\-' which specifies +.I left adjustment +of the output in the indicated field; +.TP 10 +.B + +A `+' character specifying that there should always be +a sign placed before the number when using signed formats. +.TP 10 +.B \` \' +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; +.TP 10 +.B 0 +A zero `0' character indicating that zero-padding should be used +rather than blank-padding. A `\-' overrides a `0' if both are used; +.po -0.5i +.TP +Field Width: +An optional digit string specifying a +.IR "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); +.TP +Precision: +An optional period, +\fB\.\fP, +followed by an optional digit string giving a +.I precision +which specifies the number of digits to appear after the decimal point, +for +.B e +and +.B 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; +.TP +Format: +.br +A character which indicates the type of format to use (one of +.BR diouxXfwEgGcs ). +.PP +A field width or precision may be +.B * +instead of a digit string. +In this case an +.I argument +supplies the field width or precision. +.PP +The format characters and their meanings are: +.TP 10 +.B diouXx +The +.I argument +is printed as a signed decimal (d or i), unsigned decimal, unsigned octal, +or unsigned hexadecimal (X or x), respectively. +.TP 10 +.B f +The +.I 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. +.TP 10 +.B eE +The +.I argument +is printed in the style +.B 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. +.TP 10 +.B gG +The +.I argument +is printed in style +.B f +or in style +.B e +(\fBE\fP) +whichever gives full precision in minimum space. +.TP 10 +.B c +The first character of +.I argument +is printed. +.TP 10 +.B s +Characters from the string +.I 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. +.TP 10 +.B % +Print a \`%\'; no argument is used. +.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 +.B Printf +exits 0 on success, 1 on failure. +.SH SEE ALSO +.IR printf (3) +.SH HISTORY +The +.B printf +command appeared in +.BR 4.3\-Reno . +It is modeled +after the standard library function, +.BR printf (3). +.SH BUGS +Since the floating point numbers are translated from +ASCII +to floating-point and +then back again, floating-point precision may be lost. +.PP +ANSI +hexadecimal character constants were deliberately not provided. diff --git a/src/cmd/printf/printf.c b/src/cmd/printf/printf.c new file mode 100644 index 0000000..5143a46 --- /dev/null +++ b/src/cmd/printf/printf.c @@ -0,0 +1,386 @@ +/* + * 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. + */ +#include +#include +#include +#include +#include + +#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 char **gargv; + +static int asciicode(); +static void escape(); +static int getchr(); +static int getint(); +static int getlong(); +static char *getstr(); +static char *mklong(); +static void usage(); +#ifndef NOFPU +static double getdouble(); +#endif + +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, *start; + register char *fmt; + + 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; + } +#ifndef NOFPU + case 'e': case 'E': case 'f': case 'g': case 'G': { + double p; + + p = getdouble(); + PF(start, p); + break; + } +#endif + default: + warnx("illegal format character", NULL, NULL); + return (1); + } + *fmt = nextch; + } + /* NOTREACHED */ +} + +static char * +mklong(str, ch) + register char *str; + int ch; +{ + static char copy[64]; + register int len; + + if (ch == 'X') /* XXX */ + ch = 'x'; + len = strlen(str) + 2; + bcopy(str, copy, 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; + int 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 > 65535) { + warnx("%s: %s", *gargv, strerror(ERANGE)); + return (1); + } + *ip = val; + return (0); +} + +static int +getlong(lp) + register 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 == 2147483647L) { + warnx("%s: %s", *gargv, strerror(ERANGE)); + return (1); + } + if (val == (-2147483647L-1)) { + warnx("%s: %s", *gargv, strerror(ERANGE)); + return (1); + } + + *lp = val; + ++gargv; + return (0); + } + *lp = (long)asciicode(); + return (0); +} + +#ifndef NOFPU +static double +getdouble() +{ + if (!*gargv) + return ((double)0); + if (strchr(Number, **gargv)) + return (atof(*gargv++)); + return ((double)asciicode()); +} +#endif + +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/src/cmd/ps.c b/src/cmd/ps.c new file mode 100644 index 0000000..ada4184 --- /dev/null +++ b/src/cmd/ps.c @@ -0,0 +1,831 @@ +/* + * 1999/8/11 - Remove reference to SDETACH. It was removed from the kernel + * (finally) because it was not needed. + * + * 1997/12/16 - Fix coredump when processing -U. + * + * 1996/11/16 - Move 'psdatabase' in /var/run. + * + * 12/20/94 - Missing casts caused errors in reporting on swapped + * processes - sms + * 1/7/93 - Heavily revised when the symbol table format changed - sms + * + * ps - process status + * Usage: ps [ acgklnrtuwxU# ] [ corefile [ swapfile ] ] + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define within(x,y,z) (((unsigned)(x) >= (y)) && ((unsigned)(x) < (z))) +#define round(x,y) ((long) ((((long) (x) + (long) (y) - 1L) / (long) (y)) * (long) (y))) + +struct nlist nl[] = { +#define X_PROC 0 + { "_proc" }, +#define X_NPROC 1 + { "_nproc" }, +#define X_HZ 2 + { "_hz" }, + { "_ipc" }, + { "_lbolt" }, + { "_memlock" }, + { "_runin" }, + { "_runout" }, + { "_selwait" }, + { "_u" }, + { "" }, +}; + +/* + * This is no longer the size of a symbol's name, symbols can be much + * larger now. This define says how many characters of a symbol's name + * to save in the wait channel name. A new define has been created to + * limit the size of symbol string read from the string table. +*/ +#define NNAMESIZ 8 +#define MAXSYMLEN 32 + +struct proc *mproc, proc[8]; +struct user u; +int hz; +int chkpid = 0; +char aflg; /* -a: all processes, not just mine */ +char cflg; /* -c: not complete listing of args, just comm. */ +char gflg; /* -g: complete listing including group headers, etc */ +char kflg; /* -k: read from core file instead of real memory */ +char lflg; /* -l: long listing form */ +char nflg; /* -n: numeric wchans */ +char rflg; /* -r: raw output in style */ +char uflg; /* -u: user name */ +char wflg; /* -w[w]: wide terminal */ +char xflg; /* -x: ALL processes, even those without ttys */ +char *tptr, *mytty; +char *uname; +int file; +int nproc; +int nchans; +int nttys; +int npr; /* number of processes found so far */ +int twidth; /* terminal width */ +int cmdstart; /* start position for command field */ +char *memf; /* name of kernel memory file */ +char *kmemf = "/dev/kmem"; /* name of physical memory file */ +char *swapf; /* name of swap file to use */ +int kmem, mem, swap; + +/* + * Structure for the unix wchan table + */ +typedef struct wchan { + char cname[NNAMESIZ]; + unsigned caddr; +} WCHAN; + +WCHAN *wchand; + +/* + * 256 terminals was not only wasteful but unrealistic. For one thing + * 2.11BSD uses bit 7 of the minor device (for almost all terminal interfaces) + * to indicate direct/modem status - this means that 128 terminals is + * a better maximum number of terminals, for another thing the system can't + * support 256 terminals - other resources (memory, files, processes) will + * have been exhausted long ago. If 'ps' complains about too many terminals + * it is time to clean up /dev! + */ +#define MAXTTYS 160 /* 128 plus a few extra */ + +struct ttys { + char name[14]; /* MAXNAMLEN uses too much memory, besides */ + /* device names tend to be very short */ + dev_t ttyd; + +} allttys[MAXTTYS]; + +struct map { + off_t b1, e1; off_t f1; + off_t b2, e2; off_t f2; +}; + +struct winsize ws; +struct map datmap; +struct psout *outargs; /* info for first npr processes */ + +/* + * Attempt to avoid stats by guessing minor device + * numbers from tty names. Console is known, + * know that r(hp|up|mt) are unlikely as are different mem's, + * floppy, null, tty, etc. + */ +void +maybetty(cp) + register char *cp; +{ + register struct ttys *dp; + struct stat stb; + + /* Allow only terminal devices. */ + switch (cp[0]) { + case 'c': + if (strcmp(cp, "console") == 0) + break; + return; + case 't': + if (strncmp(cp, "tty", 3) == 0) + break; + return; + default: + return; + } + if (nttys >= MAXTTYS) { + fprintf(stderr, "ps: tty table overflow\n"); + exit(1); + } + dp = &allttys[nttys++]; + (void)strcpy(dp->name, cp); + + if (stat(dp->name, &stb) == 0 && + (stb.st_mode & S_IFMT) == S_IFCHR) + dp->ttyd = stb.st_rdev; + else + dp->ttyd = -1; +} + +void +getdev() +{ + register DIR *df; + register struct direct *dbuf; + + if (chdir("/dev") < 0) { + perror("/dev"); + exit(1); + } + if ((df = opendir(".")) == NULL) { + fprintf(stderr, "Can't open . in /dev\n"); + exit(1); + } + while ((dbuf = readdir(df))) + maybetty(dbuf->d_name); + closedir(df); +} + +char * +gettty() +{ + register int tty_step; + register char *p; + + if (u.u_ttyp) { + for (tty_step = 0; tty_step < nttys; ++tty_step) { + if (allttys[tty_step].ttyd == u.u_ttyd) { + p = allttys[tty_step].name; + if (strncmp(p, "tty", 3) == 0) + p += 3; + return(p); + } + } + } + return("?"); +} + +unsigned +getptr(adr) + off_t adr; +{ + unsigned ptr = 0; + + if (lseek(file, adr, 0) == (off_t) -1 || + read (file, &ptr, sizeof(ptr)) != sizeof(ptr)) + return 0; + return ptr; +} + +int +getbyte(adr) + register char *adr; +{ + char b; + + if (lseek(file, (off_t) adr, 0) == (off_t) -1 || read (file, &b, 1) < 1) + return(0); + return((unsigned) b); +} + +int +getcmd(a, addr) + off_t addr; + register struct psout *a; +{ + /* amount of top of stack to examine for args */ +#define ARGLIST (DEV_BSIZE * 2) + char abuf [ARGLIST]; + char cmd[82], *bp; + off_t ap; + unsigned ssize, cp; + + /* in case of early return */ + bp = a->o_args; + strcat(bp, " ("); + strcat(bp, u.u_comm); + strcat(bp, ")"); + bp[63] = 0; /* max room in psout is 64 chars */ + + if (mproc->p_pid == 0) + return(1); + + /* look for in-core process */ + if (mproc->p_flag & SLOAD) { + addr += mproc->p_ssize; /* file offset to top of stack */ + lseek(file, addr - sizeof (char **), 0); + if (read(file, (char *) &ap, sizeof (char *)) != sizeof (char *)) + return (1); + if (ap == 0) + return(1); + bp = cmd; + while (bp < cmd + sizeof(a->o_args)) { + int c, nbad = 0; + + cp = getptr(ap); + if (! cp) + break; + ap += sizeof(char*); + while ((c = getbyte(cp++)) && bp < cmd + sizeof (a->o_args)) { + if (c < ' ' || c > '~') { + if (nbad++ > 3) + break; + continue; + } + *bp++ = c; + } + *bp++ = ' '; + } + *bp++ = 0; + strcpy(a->o_args, cmd); + return(1); + } + + /* process is swapped out */ + ssize = mproc->p_ssize; + if (ssize <= sizeof(abuf)) { + lseek(file, addr, 0); + if (read(file, abuf, ssize) != ssize) + return (1); + } else { + /* skip some blocks of stack */ + ssize = (ssize % DEV_BSIZE) + DEV_BSIZE; + addr += mproc->p_ssize - ssize; + lseek(file, addr, 0); + if (read(file, abuf, sizeof(abuf)) != sizeof(abuf)) + return (1); + } + ap = *(unsigned*) &abuf[ssize - sizeof(unsigned)]; + if (ap == 0) + return(1); + bp = cmd; + while (bp < cmd + sizeof(a->o_args)) { + int i, c, nbad = 0; + + i = ap + ssize - USER_DATA_END; + if ((i & 3) || i < 0 || i >= ssize) + break; + cp = *(unsigned*) &abuf[i]; + if (! cp) + break; + ap += sizeof(char*); + while (bp < cmd + sizeof (a->o_args)) { + i = cp++ + ssize - USER_DATA_END; + if (i < 0 || i >= ssize) + break; + c = abuf[i]; + if (! c) + break; + if (c < ' ' || c > '~') { + if (nbad++ > 3) + break; + continue; + } + *bp++ = c; + } + *bp++ = ' '; + } + *bp++ = 0; + if (cmd[0] > ' ' && (cmd[0] != '-' || cmd[1] > ' ')) + strcpy(a->o_args, cmd); + if (xflg || gflg || tptr || cmd[0] != '-') + return(1); + return(0); +} + +/* + * Save command data to outargs[]. + * Return 1 on success. + */ +int +savcom(puid) + int puid; +{ + char *tp; + off_t addr; + off_t daddr, saddr; + register struct psout *a; + register struct proc *procp = mproc; + register struct user *up = &u; + long txtsiz, datsiz, stksiz; + + if (procp->p_flag & SLOAD) { + addr = procp->p_addr; + daddr = procp->p_daddr; + saddr = procp->p_saddr; + file = mem; + } else { + addr = (off_t)procp->p_addr * DEV_BSIZE; + daddr = (off_t)procp->p_daddr * DEV_BSIZE; + saddr = (off_t)procp->p_saddr * DEV_BSIZE; + file = swap; + } + lseek(file, addr, 0); + if (read(file, (char *) up, sizeof (u)) != sizeof (u)) + return(0); + + txtsiz = up->u_tsize; /* set up address maps for user pcs */ + datsiz = up->u_dsize; + stksiz = up->u_ssize; + datmap.b1 = txtsiz; + datmap.e1 = datmap.b1 + datsiz; + datmap.f1 = daddr; + datmap.f2 = saddr; + datmap.b2 = stackbas(stksiz); + datmap.e2 = stacktop(stksiz); + tp = gettty(); + if ((tptr && strncmp(tptr, tp, 2) != 0) || + (! aflg && strncmp(mytty, tp, 2) != 0)) + return(0); + a = &outargs[npr]; /* saving com starts here */ + a->o_uid = puid; + a->o_pid = procp->p_pid; + a->o_flag = procp->p_flag; + a->o_ppid = procp->p_ppid; + a->o_cpu = procp->p_cpu; + a->o_pri = procp->p_pri; + a->o_nice = procp->p_nice; + a->o_addr0 = procp->p_addr; + a->o_size = (procp->p_dsize + procp->p_ssize + USIZE) / DEV_BSIZE; + a->o_wchan = procp->p_wchan; + a->o_pgrp = procp->p_pgrp; + strncpy(a->o_tty, tp, sizeof (a->o_tty)); + a->o_ttyd = tp[0] == '?' ? -1 : up->u_ttyd; + a->o_stat = procp->p_stat; + a->o_flag = procp->p_flag; + + if (a->o_stat == SZOMB) + return(1); + a->o_utime = up->u_ru.ru_utime; + a->o_stime = up->u_ru.ru_stime; + a->o_cutime = up->u_cru.ru_utime; + a->o_cstime = up->u_cru.ru_stime; + a->o_sigs = (int)up->u_signal[SIGINT] + (int)up->u_signal[SIGQUIT]; + a->o_uname[0] = 0; + strncpy(a->o_comm, up->u_comm, MAXCOMLEN); + if (cflg) + return (1); + else + return getcmd(a, saddr); +} + +int +pscomp(x1, x2) + register struct psout *x1, *x2; +{ + register int c; + + c = (x1)->o_ttyd - (x2)->o_ttyd; + if (c == 0) + c = (x1)->o_pid - (x2)->o_pid; + return(c); +} + +/* + * fixup figures out everybodys name and sorts into a nice order. + */ +void +fixup(np) + register int np; +{ + register int i; + register struct passwd *pw; + + if (uflg) { + setpwent(); + /* + * If we want names, traverse the password file. For each + * passwd entry, look for it in the processes. + * In case of multiple entries in the password file we believe + * the first one (same thing ls does). + */ + while ((pw = getpwent()) != (struct passwd *) NULL) { + for (i = 0; i < np; i++) + if (outargs[i].o_uid == pw->pw_uid) { + if (outargs[i].o_uname[0] == 0) + strcpy(outargs[i].o_uname, pw->pw_name); + } + } + endpwent(); + } + qsort(outargs, np, sizeof (outargs[0]), pscomp); +} + +int +wchancomp(x1, x2) + register WCHAN *x1, *x2; +{ + if (x1->caddr > x2->caddr) + return(1); + else if (x1->caddr == x2->caddr) + return(0); + else + return(-1); +} + +void +addchan(name, caddr) + char *name; + unsigned caddr; +{ + static int left = 0; + register WCHAN *wp; + + if (left == 0) { + if (wchand) { + left = 50; + wchand = (WCHAN *)realloc(wchand, (nchans + left) * + sizeof (struct wchan)); + } else { + left = 300; + wchand = (WCHAN *)malloc(left * sizeof (struct wchan)); + } + if (! wchand) { + fprintf(stderr, "ps: out of wait channel memory\n"); + nflg++; + return; + } + } + wp = &wchand[nchans++]; + left--; + strncpy(wp->cname, name, NNAMESIZ - 1); + wp->cname[NNAMESIZ-1] = '\0'; + wp->caddr = caddr; +} + +char * +getchan(chan) + register unsigned int chan; +{ + register int i; + register char *prevsym; + + prevsym = ""; + if (chan) { + for (i = 0; i < nchans; i++) { + if (wchand[i].caddr > chan) + return (prevsym); + prevsym = wchand[i].cname; + } + } + return(prevsym); +} + +void +perrexit(msg) + char *msg; +{ + perror(msg); + exit(1); +} + +void +openfiles(argc, argv) + char **argv; +{ + if (kflg) + kmemf = argc > 1 ? argv[1] : _PATH_CORE; + kmem = open(kmemf, 0); + if (kmem < 0) + perrexit(kmemf); + if (!kflg) + memf = _PATH_MEM; + else + memf = kmemf; + mem = open(memf, 0); + if (mem < 0) + perrexit(memf); + swapf = argc > 2 ? argv[2] : _PATH_SWAP; + swap = open(swapf, 0); + if (swap < 0) + perrexit(swapf); +} + +void +getkvars(argc,argv) + int argc; + char **argv; +{ + knlist(nl); + if (! nflg) { + int i; + for (i=0; io_utime + a->o_stime + 30) / hz; + printf("%3ld:",tm / 60); + tm %= 60; + printf(tm < 10 ? "0%ld" : "%ld",tm); +} + +char *uhdr = "USER PID NICE SZ TTY TIME"; + +void +upr(a) + register struct psout *a; +{ + printf("%-8.8s%6u%4d%4d %-3.3s",a->o_uname,a->o_pid,a->o_nice,a->o_size,a->o_tty); + ptime(a); +} + +char *shdr = " PID TTY TIME"; + +void +spr (a) + register struct psout *a; +{ + printf("%6u %-3.3s",a->o_pid,a->o_tty); + ptime(a); +} + +char *lhdr = " F S UID PID PPID CPU PRI NICE ADDR SZ WCHAN TTY TIME"; + +void +lpr(a) + register struct psout *a; +{ + static char clist[] = "0SWRIZT"; + + printf("%3o %c%6u%6u%6u%4d%4d%4d%#7x%4d", + 0377 & a->o_flag, clist[(unsigned char)a->o_stat], + a->o_uid, a->o_pid, a->o_ppid, a->o_cpu & 0377, + a->o_pri, a->o_nice, a->o_addr0, a->o_size); + if (nflg) + if (a->o_wchan) + printf("%*.*x", NNAMESIZ, NNAMESIZ, (unsigned) a->o_wchan); + else + fputs(" ", stdout); + else + printf(" %-*.*s",NNAMESIZ, NNAMESIZ, getchan(a->o_wchan)); + printf(" %-3.3s",a->o_tty); + ptime(a); +} + +void +printhdr() +{ + register char *hdr, *cmdstr = " COMMAND"; + + if (rflg) + return; + if (lflg && uflg) { + fputs("ps: specify only one of l and u.\n",stderr); + exit(1); + } + hdr = lflg ? lhdr : (uflg ? uhdr : shdr); + fputs(hdr,stdout); + cmdstart = strlen(hdr); + if (cmdstart + strlen(cmdstr) >= twidth) + cmdstr = " CMD"; + printf("%s\n", cmdstr); + fflush(stdout); +} + +int +main (argc, argv) + char **argv; +{ + int uid, euid, puid, nread; + register int i, j; + char *ap; + register struct proc *procp; + + if ((ioctl(fileno(stdout), TIOCGWINSZ, &ws) != -1 && + ioctl(fileno(stderr), TIOCGWINSZ, &ws) != -1 && + ioctl(fileno(stdin), TIOCGWINSZ, &ws) != -1) || + ws.ws_col == 0) + twidth = 80; + else + twidth = ws.ws_col; + + mytty = ttyname(0); + + argc--, argv++; + if (argc > 0) { + ap = argv [0]; + while (*ap) switch (*ap++) { + case '-': + break; + + case 'a': + aflg++; + break; + + case 'c': + cflg++; + break; + + case 'g': + gflg++; + break; + + case 'k': + kflg++; + break; + + case 'l': + lflg = 1; + break; + + case 'n': + nflg++; + lflg = 1; + break; + + case 'r': + rflg++; + break; + + case 't': + if (*ap) { + tptr = ap; + } else if (! mytty) { + /* Stdin is not a tty - 't' flag ignored. */ + break; + } else { + tptr = mytty; + if (strncmp(tptr, "/dev/", 5) == 0) + tptr += 5; + } + if (strncmp(tptr, "tty", 3) == 0) + tptr += 3; + aflg++; + gflg++; + if (tptr && *tptr == '?') + xflg++; + while (*ap) + ap++; + break; + + case 'u': + uflg = 1; + break; + + case 'w': + if (wflg) + twidth = BUFSIZ; + else if (twidth < 132) + twidth = 132; + wflg++; + break; + + case 'x': + xflg++; + break; + + default: + if (!isdigit(ap[-1])) + break; + chkpid = atoi(--ap); + *ap = '\0'; + aflg++; + xflg++; + break; + } + } + + openfiles(argc, argv); + getkvars(argc, argv); + lseek(kmem, (off_t)nl[X_PROC].n_value, 0); + uid = getuid(); + euid = geteuid(); + /* handle case where ps is in background and ttyname returns 0 */ + if (!mytty) mytty = ""; + if (!strncmp(mytty,"/dev/",5)) mytty += 5; + if (!strncmp(mytty,"tty",3)) mytty += 3; + printhdr(); + for (i = 0; i < nproc; i += 8) { + j = nproc - i; + if (j > 8) + j = 8; + j *= sizeof (struct proc); + if ((nread = read(kmem, (char *) proc, j)) != j) { + fprintf(stderr, "ps: error reading proc table from %s\n", kmemf); + if (nread == -1) + break; + } + for (j = nread / sizeof (struct proc) - 1; j >= 0; j--) { + mproc = &proc[j]; + procp = mproc; + /* skip processes that don't exist */ + if (procp->p_stat == 0) + continue; + /* skip those without a tty unless -x */ + if (procp->p_pgrp == 0 && xflg == 0) + continue; + /* skip group leaders on a tty unless -g, -x, or -t.. */ + if (!tptr && !gflg && !xflg && procp->p_ppid == 1) + continue; + /* -g also skips those where **argv is "-" - see savcom */ + puid = procp->p_uid; + /* skip other peoples processes unless -a or a specific pid */ + if ((uid != puid && euid != puid && aflg == 0) || + (chkpid != 0 && chkpid != procp->p_pid)) + continue; + if (savcom(puid)) + npr++; + } + } + fixup(npr); + for (i = 0; i < npr; i++) { + register int cmdwidth = twidth - cmdstart - 2; + register struct psout *a = &outargs[i]; + + if (rflg) { + if (write(1, (char *) a, sizeof (*a)) != sizeof (*a)) + perror("write"); + continue; + } else if (lflg) + lpr(a); + else if (uflg) + upr(a); + else + spr(a); + + if (cmdwidth < 0) + cmdwidth = 80 - cmdstart - 2; + if (a->o_stat == SZOMB) + printf("%.*s", cmdwidth, " "); + else if (a->o_pid == 0) + printf("%.*s", cmdwidth, " swapper"); + else + printf(" %.*s", twidth - cmdstart - 2, cflg ? a->o_comm : a->o_args); + putchar('\n'); + } + exit(!npr); +} diff --git a/src/cmd/pstat/Makefile b/src/cmd/pstat/Makefile new file mode 100644 index 0000000..efd05db --- /dev/null +++ b/src/cmd/pstat/Makefile @@ -0,0 +1,42 @@ +# +# Should be installed with kmem group. +# +TOPSRC = $(shell cd ../../..; pwd) +include $(TOPSRC)/target.mk + +CFLAGS += -Werror + +SRCS = pstat.c +OBJS = pstat.o +MAN = pstat.0 +MANSRC = pstat.8 + +all: pstat ${MAN} + +pstat: ${OBJS} + ${CC} ${LDFLAGS} -o pstat.elf ${OBJS} ${LIBS} + ${OBJDUMP} -S pstat.elf > pstat.dis + ${SIZE} pstat.elf + ${ELF2AOUT} pstat.elf $@ && rm pstat.elf + +${MAN}: ${MANSRC} + ${MANROFF} ${MANSRC} > ${MAN} + +clean: + rm -f *.o *.elf ${MAN} pstat *.elf *.dis tags *~ + +depend: ${SRCS} + mkdep ${CFLAGS} ${SRCS} + +install: pstat + cp ${MAN} ${DESTDIR}/share/man/cat8/ + install -m 2755 pstat ${DESTDIR}/sbin/pstat + +lint: ${SRCS} + lint -hax ${SRCS} + +tags: ${SRCS} + ctags ${SRCS} + +# DO NOT DELETE THIS LINE -- mkdep uses it. +# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY. diff --git a/src/cmd/pstat/pstat.8 b/src/cmd/pstat/pstat.8 new file mode 100644 index 0000000..6a02b44 --- /dev/null +++ b/src/cmd/pstat/pstat.8 @@ -0,0 +1,358 @@ +.\" Copyright (c) 1980 Regents of the University of California. +.\" All rights reserved. The Berkeley software License Agreement +.\" specifies the terms and conditions for redistribution. +.\" +.\" @(#)pstat.8 6.3.2 (2.11BSD) 1997/9/2 +.\" +.TH PSTAT 8 "September 2, 1997" +.UC 4 +.SH NAME +pstat \- print system facts +.SH SYNOPSIS +.B /usr/sbin/pstat +.B \-aixptufT +[ +.B suboptions +] [ +.B system +] [ +.B corefile +] +.SH DESCRIPTION +.I Pstat +interprets the contents of certain system tables. +If +.I corefile +is given, the tables are sought there, otherwise +in +.I /dev/kmem. +The required namelist is taken from +.I /vmunix +unless +.I system +is specified. +Options are +.TP \w'WCHAN\ 'u +.B \-a +Under +.BR \-p , +describe all process slots rather than just active ones. +.TP +.B \-i +Print the inode table with the these headings: +.IP LOC +The core location of this table entry. +.PD 0 +.IP FLAGS +Miscellaneous state variables encoded thus: +.RS +.IP L +locked +.IP U +update time +.RI ( fs (5)) +must be corrected +.IP A +access time must be corrected +.IP M +file system is mounted here +.IP W +wanted by another process (L flag is on) +.IP T +contains a text file +.IP C +changed time must be corrected +.IP S +shared lock applied +.IP E +exclusive lock applied +.IP Z +someone waiting for a lock +.RE +.IP CNT +Number of open file table entries for this inode. +.IP DEV +Major and minor device number of file system in which +this inode resides. +.IP RDC +Reference count of shared locks on the inode. +.IP WRC +Reference count of exclusive locks on the inode (this may +be > 1 if, for example, a file descriptor is inherited across a fork). +.IP INO +I-number within the device. +.IP MODE +Mode bits, see +.IR chmod (2). +.IP NLK +Number of links to this inode. +.IP UID +User ID of owner. +.IP SIZ/DEV +Number of bytes in an ordinary file, or +major and minor device of special file. +.PD +.TP +.B \-x +Print the text table with these headings: +.IP LOC +The core location of this table entry. +.PD 0 +.IP FLAGS +Miscellaneous state variables encoded thus: +.RS +.IP T +.IR ptrace (2) +in effect +.IP W +text not yet written on swap device +.IP L +loading in progress +.IP K +locked +.IP w +wanted (L flag is on) +.IP P +resulted from demand-page-from-inode exec format (see +.IR execve (2)) +.RE +.PD +.IP DADDR +Disk address in swap, measured in multiples of 512 bytes. +.IP CADDR +Head of a linked list of loaded processes using this text segment. +.IP RSS +Size of resident text, measured in multiples of 512 bytes. +.IP SIZE +Size of text segment, measured in multiples of 512 bytes. +.IP IPTR +Core location of corresponding inode. +.IP CNT +Number of processes using this text segment. +.IP CCNT +Number of processes in core using this text segment. +.IP FORW +Forward link in free list. +.IP BACK +Backward link in free list. +.PD +.TP +.B \-p +Print process table for active processes with these headings: +.IP LOC +The core location of this table entry. +.PD 0 +.IP S +Run state encoded thus: +.RS +.IP 0 +no process +.IP 1 +waiting for some event +.IP 3 +runnable +.IP 4 +being created +.IP 5 +being terminated +.IP 6 +stopped (by signal or under trace) +.RE +.IP F +Miscellaneous state variables, or'ed together (hexadecimal): +.RS +.IP 0001 9n +loaded +.IP 0002 +system process (swapper) +.IP 0004 +locked for swap out +.IP 0008 +swap save area +.IP 0010 +traced +.IP 0020 +used in tracing +.IP 0040 +user settable lock in core +.IP 0100 +process resulted from +.IR vfork (2) +.IP 0200 +parent in vfork, waiting for child +.IP 0400 +parent has released child in vfork +.IP 1000 +detached inherited by init +.IP 2000 +no SIGCHLD signal to parent +.IP 4000 +selecting; wakeup/waiting danger +.RE +.IP PRI +Scheduling priority, see +.IR setpriority (2). +.IP SIG +Signals received (signals 1-32 coded in bits 0-31), +.IP UID +Real user ID. +.IP SLP +Amount of time process has been blocked. +.IP TIM +Time resident in seconds; times over 127 coded as 127. +.IP CPU +Weighted integral of CPU time, for scheduler. +.IP NI +Nice level, +see +.IR setpriority (2). +.IP PGRP +Process number of root of process group. +.IP PID +The process ID number. +.IP PPID +The process ID of parent process. +.IP ADDR +If in core, the page frame number of the first page of the `u-area' of +the process. +If swapped out, the position in the swap area +measured in multiples of 512 bytes. +.IP RSS +Resident set size \- the number of physical page frames allocated +to this process. +.IP SRSS +RSS at last swap (0 if never swapped). +.IP SIZE +Virtual size of process image (data+stack) in multiples of 512 bytes. +.IP WCHAN +Wait channel number of a waiting process. +.IP LINK +Link pointer in list of runnable processes. +.IP TEXTP +If text is pure, pointer to location of text table entry. +.PD +.TP +.B \-t +Print table for terminals +with these headings: +.IP RAW +Number of characters in raw input queue. +.PD 0 +.IP CAN +Number of characters in canonicalized input queue. +.IP OUT +Number of characters in putput queue. +.IP MODE +See +.IR tty (4). +.IP ADDR +Physical device address. +.IP DEL +Number of delimiters (newlines) in canonicalized input queue. +.IP COL +Calculated column position of terminal. +.IP STATE +Miscellaneous state variables encoded thus: +.RS +.IP T +delay timeout in progress +.IP W +waiting for open to complete +.IP O +open +.IP F +outq has been flushed during DMA +.IP C +carrier is on +.IP B +busy doing output +.IP A +process is awaiting output +.IP X +open for exclusive use +.IP S +output stopped +.IP H +hangup on close +.RE +.IP PGRP +Process group for which this is controlling terminal. +.IP DISC +Line discipline; blank is old tty OTTYDISC or ``new tty'' for NTTYDISC +or ``net'' for NETLDISC (see +.IR bk (4)). +.PD +.TP +.B \-u +print information about a user process; +the next argument is its address as given +by +.IR ps (1). +The process must be in main memory, or the file used can +be a core image and the address 0. +Only the fields located in the first page cluster can be located +succesfully if the process is in main memory. +.TP +.B \-f +Print the open file table with these headings: +.IP LOC +The core location of this table entry. +.IP TYPE +The type of object the file table entry points to. +.PD 0 +.IP FLG +Miscellaneous state variables encoded thus: +.RS +.IP R +open for reading +.IP W +open for writing +.IP A +open for appending +.IP S +shared lock present +.IP X +exclusive lock present +.IP I +signal pgrp when data ready +.RE +.IP CNT +Number of processes that know this open file. +.IP MSG +Number of messages outstanding for this file. +.IP DATA +The location of the inode table entry or socket structure for this file. +.IP OFFSET +The file offset (see +.IR lseek (2)). +.PD +.PP +.B \-s +print information about swap space usage: the number of (1k byte) pages used +and free is given as well as the number of used pages which belong +to text images. +.PP +.B \-T +prints the number of used and free slots in the several system tables +and is useful for checking to see how full system tables have become if the +system is under heavy load. +.SH FILES +.ta \w'/dev/kmem 'u +/vmunix namelist +.br +/dev/kmem default source of tables +.SH SEE ALSO +iostat(1), +ps(1), +systat(1), +vmstat(1), +stat(2), +fs(5), +.br +K. Thompson, +.I UNIX Implementation +.SH BUGS +It would be very useful if the system recorded \*(lqmaximum occupancy\*(rq +on the tables reported by +.B \-T; +even more useful if these tables were dynamically allocated. diff --git a/src/cmd/pstat/pstat.c b/src/cmd/pstat/pstat.c new file mode 100644 index 0000000..b01f0b4 --- /dev/null +++ b/src/cmd/pstat/pstat.c @@ -0,0 +1,556 @@ +/* + * Print system stuff + * + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include +#define KERNEL +#include +#include +#undef KERNEL +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +char *fcore = "/dev/kmem"; +char *fmem = "/dev/mem"; +int fc, fm; + +struct nlist nl[] = { +#define SINODE 0 + { "_inode" }, +#define SPROC 1 + { "_proc" }, +#define SKL 2 + { "_cnttys" }, +#define SFIL 3 + { "_file" }, +#define SNSWAP 4 + { "_nswap" }, +#define SWAPMAP 5 + { "_swapmap" }, +#define SNPROC 6 + { "_nproc" }, + { "" } +}; + +int inof; +int prcf; +int ttyf; +int usrf; +long ubase; +int filf; +int swpf; +int totflg; +int allflg; +int kflg; + +main(argc, argv) +char **argv; +{ + register char *argp; + int allflags; + + argc--, argv++; + while (argc > 0 && **argv == '-') { + argp = *argv++; + argp++; + argc--; + while (*argp++) + switch (argp[-1]) { + + case 'T': + totflg++; + break; + + case 'a': + allflg++; + break; + + case 'i': + inof++; + break; + + case 'k': + kflg++; + fcore = fmem = "/core"; + break; + + case 'p': + prcf++; + break; + + case 't': + ttyf++; + break; + + case 'u': + if (argc == 0) + break; + argc--; + usrf++; + sscanf( *argv++, "%lx", &ubase); + break; + + case 'f': + filf++; + break; + case 's': + swpf++; + break; + default: + usage(); + exit(1); + } + } + if (argc>0) { + fcore = fmem = argv[0]; + kflg++; + } + if ((fc = open(fcore, 0)) < 0) { + printf("Can't find %s\n", fcore); + exit(1); + } + if ((fm = open(fmem, 0)) < 0) { + printf("Can't find %s\n", fmem); + exit(1); + } + knlist(nl); + + if (nl[0].n_value == 0) { + printf("no namelist, n_type: %d n_value: %x n_name: %s\n", nl[0].n_type, nl[0].n_value, nl[0].n_name); + exit(1); + } + if (! (filf | totflg | inof | prcf | ttyf | usrf | swpf)) + filf++; + + if (filf||totflg) + dofile(); + if (inof||totflg) + doinode(); + if (prcf||totflg) + doproc(); + if (ttyf) + dotty(); + if (usrf) + dousr(); + if (swpf||totflg) + doswap(); +} + +usage() +{ + printf("usage: pstat -[aikptfsT] [-u [ubase]] [core]\n"); +} + +doinode() +{ + register struct inode *ip; + struct inode *xinode; + register int nin; + u_int ainode; + + nin = 0; + xinode = (struct inode *)calloc(NINODE, sizeof (struct inode)); + ainode = nl[SINODE].n_value; + if (xinode == NULL) { + fprintf(stderr, "can't allocate memory for inode table\n"); + return; + } + lseek(fc, (off_t)ainode, 0); + read(fc, xinode, NINODE * sizeof(struct inode)); + for (ip = xinode; ip < &xinode[NINODE]; ip++) + if (ip->i_count) + nin++; + if (totflg) { + printf("%3d/%3d inodes\n", nin, NINODE); + return; + } + printf("%d/%d active inodes\n", nin, NINODE); + printf(" LOC FLAGS CNT DEVICE RDC WRC INO MODE NLK UID SIZE/DEV FS\n"); + for (ip = xinode; ip < &xinode[NINODE]; ip++) { + if (ip->i_count == 0) + continue; + printf("%08x ", ainode + (ip - xinode)*sizeof (*ip)); + putf((long)ip->i_flag&ILOCKED, 'L'); + putf((long)ip->i_flag&IUPD, 'U'); + putf((long)ip->i_flag&IACC, 'A'); + putf((long)ip->i_flag&IMOUNT, 'M'); + putf((long)ip->i_flag&IWANT, 'W'); + putf((long)ip->i_flag&ITEXT, 'T'); + putf((long)ip->i_flag&ICHG, 'C'); + putf((long)ip->i_flag&ISHLOCK, 'S'); + putf((long)ip->i_flag&IEXLOCK, 'E'); + putf((long)ip->i_flag&ILWAIT, 'Z'); + putf((long)ip->i_flag&IPIPE, 'P'); + putf((long)ip->i_flag&IMOD, 'm'); + putf((long)ip->i_flag&IRENAME, 'r'); + putf((long)ip->i_flag&IXMOD, 'x'); + printf("%4d", ip->i_count); + printf("%4d,%3d", major(ip->i_dev), minor(ip->i_dev)); + printf("%4d", ip->i_flag&IPIPE ? 0 : ip->i_shlockc); + printf("%4d", ip->i_flag&IPIPE ? 0 : ip->i_exlockc); + printf("%6u ", ip->i_number); + printf("%7.1o", ip->i_mode); + printf("%4d", ip->i_nlink); + printf("%5u", ip->i_uid); + if ((ip->i_mode&IFMT)==IFBLK || (ip->i_mode&IFMT)==IFCHR) + printf("%6d,%3d", major(ip->i_rdev), minor(ip->i_rdev)); + else + printf("%10ld", ip->i_size); + printf(" %08x", ip->i_fs); + printf("\n"); + } + free(xinode); +} + +u_int +getuint(loc) + off_t loc; +{ + u_int word; + + lseek(fc, loc, 0); + read(fc, &word, sizeof (word)); + + return (word); +} + +putf(v, n) + long v; + char n; +{ + if (v) + printf("%c", n); + else + printf(" "); +} + +doproc() +{ + struct proc *xproc; + u_int nproc, aproc; + register struct proc *pp; + register loc, np; + + nproc = getuint((off_t)nl[SNPROC].n_value); + xproc = (struct proc *)calloc(nproc, sizeof (struct proc)); + aproc = nl[SPROC].n_value; + if (nproc < 0 || nproc > 10000) { + fprintf(stderr, "number of procs is preposterous (%d)\n", + nproc); + return; + } + if (xproc == NULL) { + fprintf(stderr, "can't allocate memory for proc table\n"); + return; + } + lseek(fc, (off_t)aproc, 0); + read(fc, xproc, nproc * sizeof (struct proc)); + np = 0; + for (pp=xproc; pp < &xproc[nproc]; pp++) + if (pp->p_stat) + np++; + if (totflg) { + printf("%3d/%3d processes\n", np, nproc); + return; + } + printf("%d/%d processes\n", np, nproc); + printf(" LOC S F PRI SIG UID SLP TIM CPU NI PGRP PID PPID ADDR SADDR DADDR SIZE WCHAN LINK SIGM\n"); + for (pp=xproc; pp<&xproc[nproc]; pp++) { + if (pp->p_stat==0 && allflg==0) + continue; + printf("%08x", aproc + (pp - xproc)*sizeof (*pp)); + printf(" %2d", pp->p_stat); + printf(" %7.1x", pp->p_flag); + printf(" %3d", pp->p_pri); + printf(" %8.1lx", pp->p_sig); + printf(" %5u", pp->p_uid); + printf(" %3d", pp->p_slptime); + printf(" %3d", pp->p_time); + printf(" %4d", pp->p_cpu&0377); + printf(" %3d", pp->p_nice); + printf(" %6d", pp->p_pgrp); + printf(" %6d", pp->p_pid); + printf(" %6d", pp->p_ppid); + printf(" %8x", pp->p_addr); + printf(" %8x", pp->p_saddr); + printf(" %8x", pp->p_daddr); + printf(" %6x", pp->p_dsize+pp->p_ssize); + printf(" %8x", pp->p_wchan); + printf(" %8x", pp->p_link); + printf(" %8.1lx", pp->p_sigmask); + printf("\n"); + } + free(xproc); +} + +static int ttyspace = 64; +static struct tty *tty; + +dotty() +{ + if ((tty = (struct tty *)malloc(ttyspace * sizeof(*tty))) == 0) { + printf("pstat: out of memory\n"); + return; + } + dottytype("cn", SKL); +} + +dottytype(name, type) +char *name; +{ + register struct tty *tp; + + printf("%s line\n", name); + lseek(fc, (long)nl[type].n_value, 0); + read(fc, tty, sizeof(struct tty)); + printf(" # RAW CAN OUT MODE ADDR DEL COL STATE PGRP\n"); + ttyprt(tty, 0); +} + +ttyprt(atp, line) +struct tty *atp; +{ + register struct tty *tp; + + printf("%2d", line); + tp = atp; + + printf("%4d%4d", tp->t_rawq.c_cc, tp->t_canq.c_cc); + printf("%4d %12.1lo %8x %4d %4d ", tp->t_outq.c_cc, tp->t_flags, + tp->t_addr, tp->t_delct, tp->t_col); + putf(tp->t_state&TS_TIMEOUT, 'T'); + putf(tp->t_state&TS_WOPEN, 'W'); + putf(tp->t_state&TS_ISOPEN, 'O'); + putf(tp->t_state&TS_FLUSH, 'F'); + putf(tp->t_state&TS_CARR_ON, 'C'); + putf(tp->t_state&TS_BUSY, 'B'); + putf(tp->t_state&TS_ASLEEP, 'A'); + putf(tp->t_state&TS_XCLUDE, 'X'); + putf(tp->t_state&TS_TTSTOP, 'S'); + putf(tp->t_state&TS_HUPCLS, 'H'); + putf(tp->t_state&TS_TBLOCK, 'b'); + putf(tp->t_state&TS_RCOLL, 'r'); + putf(tp->t_state&TS_WCOLL, 'w'); + putf(tp->t_state&TS_ASYNC, 'a'); + printf("%6d\n", tp->t_pgrp); +} + +dousr() +{ + struct user U; + long *ip; + register i, j; + + lseek(fm, ubase, 0); + read(fm, &U, sizeof(U)); + printf("procp\t%p\n", U.u_procp); + printf("frame\t%p\n", U.u_frame); + printf("comm\t%s\n", U.u_comm); + printf("arg\t%p %p %p %p %p %p\n", U.u_arg[0], U.u_arg[1], + U.u_arg[2], U.u_arg[3], U.u_arg[4], U.u_arg[5]); + printf("qsave\t"); + for (i = 0; i < sizeof (label_t) / sizeof (int); i++) + printf("%p ", U.u_qsave.val[i]); + printf("\n"); + printf("rval\t%p\n", U.u_rval); + printf("error\t%d\n", U.u_error); + printf("uids\t%d,%d,%d,%d,%d\n", U.u_uid, U.u_svuid, U.u_ruid, + U.u_svgid, U.u_rgid); + printf("groups"); + for (i = 0; (i < NGROUPS) && (U.u_groups[i] != NOGROUP); i++) { + if (i%8 == 0) printf("\t"); + printf("%u ", U.u_groups[i]); + if (i%8 == 7) printf("\n"); + } + if (i%8) printf("\n"); + printf("tsize\t%.1x\n", U.u_tsize); + printf("dsize\t%.1x\n", U.u_dsize); + printf("ssize\t%.1x\n", U.u_ssize); + printf("ssave\t"); + for (i = 0; i < sizeof (label_t) / sizeof (int); i++) + printf("%.1x ", U.u_ssave.val[i]); + printf("\n"); + printf("rsave\t"); + for (i = 0; i < sizeof (label_t) / sizeof (int); i++) + printf("%.1x ", U.u_rsave.val[i]); + printf("\n"); + printf("signal"); + for (i = 0; i < NSIG; i++) { + if (i%8 == 0) printf("\t"); + printf("%.1x ", U.u_signal[i]); + if (i%8 == 7) printf("\n"); + } + if (i%8) printf("\n"); + printf("sigmask"); + for (i = 0; i < NSIG; i++) { + if (i%8 == 0) printf("\t"); + printf("%.1lx ", U.u_sigmask[i]); + if (i%8 == 7) printf("\n"); + } + if (i%8) printf("\n"); + printf("sigonstack\t%.1lx\n", U.u_sigonstack); + printf("sigintr\t%.1lx\n", U.u_sigintr); + printf("oldmask\t%.1lx\n", U.u_oldmask); + printf("code\t%08x\n", U.u_code); + printf("psflags\t%d\n", U.u_psflags); + printf("ss_base\t%.1x ss_size %.1x ss_flags %.1x\n", + U.u_sigstk.ss_base, U.u_sigstk.ss_size, U.u_sigstk.ss_flags); + printf("ofile"); + for (i = 0; i < NOFILE; i++) + { + if (i%8 == 0) printf("\t"); + printf("%.1x ", U.u_ofile[i]); + if (i%8 == 7) printf("\n"); + } + if (i%8) printf("\n"); + printf("pofile"); + for (i = 0; i < NOFILE; i++) + { + if (i%8 == 0) printf("\t"); + printf("%.1x ", U.u_pofile[i]); + if (i%8 == 7) printf("\n"); + } + if (i%8) printf("\n"); + printf("lastfile\t%d\n", U.u_lastfile); + printf("cdir\t%.1x\n", U.u_cdir); + printf("rdir\t%.1x\n", U.u_rdir); + printf("ttyp\t%.1x\n", U.u_ttyp); + printf("ttyd\t%d,%d\n", major(U.u_ttyd), minor(U.u_ttyd)); + printf("cmask\t%.1x\n", U.u_cmask); + printf("ru\t"); + ip = (long *)&U.u_ru; + for (i = 0; i < sizeof (U.u_ru) / sizeof (long); i++) + printf("%ld ", ip[i]); + printf("\n"); + printf("cru\t"); + ip = (long *)&U.u_cru; + for (i = 0; i < sizeof (U.u_cru) / sizeof (long); i++) + printf("%ld ", ip[i]); + printf("\n"); + printf("timer\t%ld %ld %ld %ld\n", U.u_timer[0].it_interval, + U.u_timer[0].it_value, U.u_timer[1].it_interval, + U.u_timer[1].it_value); + printf("start\t%08x\n", U.u_start); + printf("prof\t%.1x %u %u %u\n", U.u_prof.pr_base, U.u_prof.pr_size, + U.u_prof.pr_off, U.u_prof.pr_scale); + printf("rlimit cur\t"); + for (i = 0; i < RLIM_NLIMITS; i++) + { + if (U.u_rlimit[i].rlim_cur == RLIM_INFINITY) + printf("infinite "); + else + printf("%ld ", U.u_rlimit[i].rlim_cur); + } + printf("\n"); + printf("rlimit max\t"); + for (i = 0; i < RLIM_NLIMITS; i++) + { + if (U.u_rlimit[i].rlim_max == RLIM_INFINITY) + printf("infinite "); + else + printf("%ld ", U.u_rlimit[i].rlim_max); + } + printf("\n"); + printf("ncache\t%ld %u %d,%d\n", U.u_ncache.nc_prevoffset, + U.u_ncache.nc_inumber, major(U.u_ncache.nc_dev), + minor(U.u_ncache.nc_dev)); +} + +oatoi(s) +char *s; +{ + register v; + + v = 0; + while (*s) + v = (v<<3) + *s++ - '0'; + return(v); +} + +dofile() +{ + struct file *xfile; + register struct file *fp; + register nf; + u_int loc, afile; + static char *dtypes[] = { "???", "inode", "socket", "pipe" }; + + nf = 0; + xfile = (struct file *)calloc(NFILE, sizeof (struct file)); + if (xfile == NULL) { + fprintf(stderr, "can't allocate memory for file table\n"); + return; + } + afile = nl[SFIL].n_value; + lseek(fc, (off_t)afile, 0); + read(fc, xfile, NFILE * sizeof (struct file)); + for (fp=xfile; fp < &xfile[NFILE]; fp++) + if (fp->f_count) + nf++; + if (totflg) { + printf("%3d/%3d files\n", nf, NFILE); + return; + } + printf("%d/%d open files\n", nf, NFILE); + printf(" LOC TYPE FLG CNT MSG DATA OFFSET\n"); + loc = afile; + for (fp=xfile; fp < &xfile[NFILE]; fp++, loc += sizeof (*fp)) + { + if (fp->f_count==0) + continue; + printf("%08x ", loc); + if (fp->f_type <= DTYPE_PIPE) + printf("%-8.8s", dtypes[fp->f_type]); + else + printf("8d", fp->f_type); + putf((long)fp->f_flag&FREAD, 'R'); + putf((long)fp->f_flag&FWRITE, 'W'); + putf((long)fp->f_flag&FAPPEND, 'A'); + putf((long)fp->f_flag&FSHLOCK, 'S'); + putf((long)fp->f_flag&FEXLOCK, 'X'); + putf((long)fp->f_flag&FASYNC, 'I'); + putf((long)fp->f_flag&FNONBLOCK, 'n'); + putf((long)fp->f_flag&FMARK, 'm'); + putf((long)fp->f_flag&FDEFER, 'd'); + printf(" %3d", fp->f_count); + printf(" %3d", fp->f_msgcount); + printf(" %08x", fp->f_data); + if (fp->f_offset < 0) + printf(" 0x%lx\n", fp->f_offset); + else + printf(" %ld\n", fp->f_offset); + } + free(xfile); +} + +doswap() +{ + u_int nswap, used; + int i, num; + struct map smap; + struct mapent *swp; + + nswap = getuint((off_t)nl[SNSWAP].n_value); + + lseek(fc, (off_t)nl[SWAPMAP].n_value, 0); + read(fc, &smap, sizeof (smap)); + num = (smap.m_limit - smap.m_map); + swp = (struct mapent *)calloc(num, sizeof (*swp)); + lseek(fc, (off_t)smap.m_map, 0); + read(fc, swp, num * sizeof (*swp)); + for (used = 0, i = 0; swp[i].m_size; i++) + used += swp[i].m_size; + printf("%d/%d swapmap entries\n", i, num); + printf("%u kbytes swap used, %u kbytes free\n", nswap - used, used); +} diff --git a/src/cmd/pwd.c b/src/cmd/pwd.c new file mode 100644 index 0000000..389f139 --- /dev/null +++ b/src/cmd/pwd.c @@ -0,0 +1,26 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +/* + * Print working (current) directory + */ +#include +#include +#include + +char *getwd(); + +main() +{ + char pathname[MAXPATHLEN + 1]; + + if (getwd(pathname) == NULL) { + fprintf(stderr, "pwd: %s\n", pathname); + exit(1); + } + printf("%s\n", pathname); + exit(0); +} diff --git a/src/cmd/pwm/Makefile b/src/cmd/pwm/Makefile new file mode 100644 index 0000000..28b4fd2 --- /dev/null +++ b/src/cmd/pwm/Makefile @@ -0,0 +1,39 @@ +# +# Public Domain. 1995/03/13 - Steven Schultz +# +TOPSRC = $(shell cd ../../..; pwd) +include $(TOPSRC)/target.mk + +CFLAGS += -Werror -I../../../sys/include + +SRCS = pwm.c +OBJS = pwm.o +MAN = pwm.0 + +all: pwm ${MAN} + +pwm: ${OBJS} + ${CC} ${LDFLAGS} -o pwm.elf ${OBJS} ${LIBS} + ${OBJDUMP} -S pwm.elf > pwm.dis + ${SIZE} pwm.elf + ${ELF2AOUT} pwm.elf $@ + +.SUFFIXES: .0 .1 + +.1.0: + ${MANROFF} $*.1 > $@ + +clean: + rm -f *.o *.elf ${MAN} *.elf *.dis tags *~ pwm + +depend: ${SRCS} + mkdep ${CFLAGS} ${SRCS} + +install: all + install -m 755 pwm ${DESTDIR}/bin + +lint: ${SRCS} + lint -hax ${SRCS} + +tags: ${SRCS} + ctags ${SRCS} diff --git a/src/cmd/pwm/pwm.1 b/src/cmd/pwm/pwm.1 new file mode 100644 index 0000000..e69de29 diff --git a/src/cmd/pwm/pwm.c b/src/cmd/pwm/pwm.c new file mode 100644 index 0000000..b39e882 --- /dev/null +++ b/src/cmd/pwm/pwm.c @@ -0,0 +1,72 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int oc; + +void error(char *message) +{ + fprintf(stderr,"Error: %s: %d\n",message,errno); +} + +int openDevice(int dev) +{ + char temp[20]; + int mode=OC_MODE_PWM; + + sprintf(temp,"/dev/oc%d",dev); + oc = open(temp,O_RDWR); + if(!oc) + { + error("Could not open PWM device"); + return 0; + } + if(ioctl(oc,OC_SET_MODE,&mode)==-1) + { + error("Could not switch channel to PWM mode"); + return 0; + } + return 1; +} + +int main(int argc, char *argv[]) +{ + int unit; + unsigned int duty; + long tduty; + + if(argc!=3) + { + error("Specify a channel and a duty cycle"); + exit(10); + } + + unit = atoi(argv[1]); + tduty = atol(argv[2]); + duty = (unsigned long)tduty; + + if((unit<0) || (unit>4)) + { + error("Invalid channel specified"); + exit(10); + } + + + if(openDevice(unit)==0) + exit(10); + + + if(ioctl(oc,OC_PWM_DUTY,&duty)==-1) + { + error("Could not set duty"); + exit(10); + } + + return 0; +} diff --git a/src/cmd/ranlib/Makefile b/src/cmd/ranlib/Makefile new file mode 100644 index 0000000..cafe6b1 --- /dev/null +++ b/src/cmd/ranlib/Makefile @@ -0,0 +1,36 @@ +TOPSRC = $(shell cd ../../..; pwd) +include $(TOPSRC)/target.mk +#include $(TOPSRC)/cross.mk + +CFLAGS += -Werror -Wall -g -I. -I../ar +LDFLAGS += -g + +SRCS = ../ar/archive.c ranlib.c +OBJS = archive.o ranlib.o +MAN = ranlib.0 ranlib.5.0 +MANSRC = ranlib.1 + +all: ranlib $(MAN) + +ranlib: ${OBJS} + ${CC} ${LDFLAGS} -o ranlib.elf ${OBJS} ${LIBS} + ${OBJDUMP} -S ranlib.elf > ranlib.dis + ${SIZE} ranlib.elf + ${ELF2AOUT} ranlib.elf $@ + +archive.o: ../ar/archive.c + ${CC} ${CFLAGS} -c -o $@ $< + +ranlib.0: ranlib.1 + ${MANROFF} $< > $@ + +ranlib.5.0: ranlib.5.5 + ${MANROFF} $< > $@ + +clean: + rm -f *.o *.0 *.elf ${MAN} ranlib *.elf *.dis a.out tags *~ + +install: + cp ranlib.5.0 ${DESTDIR}/share/man/cat5/ranlib.0 + cp ranlib.0 ${DESTDIR}/share/man/cat1/ranlib.0 + install ranlib ${DESTDIR}/bin/ranlib diff --git a/src/cmd/ranlib/ranlib.1 b/src/cmd/ranlib/ranlib.1 new file mode 100644 index 0000000..4d15f7e --- /dev/null +++ b/src/cmd/ranlib/ranlib.1 @@ -0,0 +1,84 @@ +.\" Copyright (c) 1990 Regents of the University of California. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (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 6.7 (Berkeley) 5/9/91 +.\" +.TH RANLIB 1 "May 9, 1991" +.AT 3 +.UC 6 +.SH NAME +ranlib \- table-of-contents for archive libraries +.SH SYNOPSIS +.nf +.ft B +ranlib [-t] file ... +.fi +.ft R +.SH DESCRIPTION +.I Ranlib +creates a table of external references for archive libraries, +normally used by the loader, +.IR 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: +.TP +\-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 +.IR cp (1) ) , +the +.I \-t +option can be used to ``touch'' the modification time so that it +appears that the table is up-to-date. +.SH FILES +.TP 14 +/tmp +default temporary file directory +.TP 14 +ranlib.XXXXXX +temporary file names +.SH SEE ALSO +.IR ar (1) , +.IR ld (1) , +.IR lorder (1) , +.IR nm (1) , +.IR ranlib (5) +.SH HISTORY +A +.I ranlib +command appeared in Version 7 AT&T UNIX. diff --git a/src/cmd/ranlib/ranlib.5.5 b/src/cmd/ranlib/ranlib.5.5 new file mode 100644 index 0000000..8d2ffde --- /dev/null +++ b/src/cmd/ranlib/ranlib.5.5 @@ -0,0 +1,70 @@ +.\" 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. +.\" +.\" @(#)ranlib.5.5 5.2 (Berkeley) 5/10/91 +.\" +.TH RANLIB 5 "May 10, 1991" +.AT 3 +.UC 6 +.SH NAME +ranlib \- archive (library) table-of-contents format +.SH SYNOPSIS +.nf +.ft B +#include +.fi +.ft R +.SH DESCRIPTION +The archive table-of-contents command +.I ranlib +creates a table of contents for archives, containing object files, to +be used by the link-editor +.IR ld (1) . +It operates on archives created with the utility +.IR ar (1) . +.PP +The +.I Ranlib +function +prepends a new file to the archive which has two separate parts. +The first part is a standard archive header, which has a special name +field, "__.SYMDEF". +.PP +The second part is a list of ranlib structures of variable size. +Each of the ranlib structures consists of a sequence of records, terminated +by 1, 2, 3 or 4 zero bytes (to align to word boundary). +.PP +Every record consists of a byte with name length, a word specifying an offset +from the beginning of the archive to the start of the archive file which defines the symbol, +and a symbol name of given length. +.SH SEE ALSO +.IR ar (1) , +.IR ranlib (1) diff --git a/src/cmd/ranlib/ranlib.c b/src/cmd/ranlib/ranlib.c new file mode 100644 index 0000000..fd0ff2b --- /dev/null +++ b/src/cmd/ranlib/ranlib.c @@ -0,0 +1,467 @@ +/*- + * Copyright (c) 1990 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. + */ +#ifdef CROSS +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# define _PATH_RANTMP "/tmp/ranlib.XXXXXX" +#else +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +#endif +#include +#include +#include +#include "archive.h" + +u_int options; /* UNUSED -- keep open_archive happy */ + +CHDR chdr; /* converted header */ +char *archive; /* archive name */ +char *tname = "temporary file"; /* 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 */ +int verbose; + +void error(name) + char *name; +{ + (void)fprintf(stderr, "ranlib: %s: %s\n", name, strerror(errno)); + exit(1); +} + +void *emalloc(len) + int len; +{ + char *p; + + p = malloc((u_int)len); + if (! p) + error(archive); + return((void *)p); +} + +int sgets(buf, n, fp) + char *buf; + int n; + register FILE *fp; +{ + register int i, c; + + n--; /* room for null */ + for (i = 0; i < n; i++) { + c = getc(fp); + if (c == EOF || c == 0) + break; + *buf++ = c; + } + *buf = '\0'; + return(i + 1); +} + +unsigned int fgetword (f) + register FILE *f; +{ + register unsigned int h; + + h = getc (f); + h |= getc (f) << 8; + h |= getc (f) << 16; + h |= getc (f) << 24; + return h; +} + +/* + * Read a symbol table entry. + * Return a number of bytes read, 0 on end of table or -1 on EOF. + * Format of symbol record: + * 1 byte: length of name in bytes + * 1 byte: type of symbol (N_UNDF, N_ABS, N_TEXT, etc) + * 4 bytes: value + * N bytes: name + */ +int fgetsym (fi, name, value, type) + register FILE *fi; + register char *name; + unsigned *value; + unsigned short *type; +{ + register int len; + unsigned nbytes; + + len = getc (fi); + if (len < 0) { + return -1; + } + if (len == 0) { + return 0; + } + *type = getc (fi); + *value = fgetword (fi); + nbytes = len + 6; + if (name) { + while (len-- > 0) + *name++ = getc (fi); + *name = '\0'; + } else + fseek (fi, len, SEEK_CUR); + return nbytes; +} + +/* + * Read the exec structure; ignore any files that don't look exactly right. + */ +void rexec(rfd, wfd) + int rfd; + int wfd; +{ + register RLIB *rp; + long nsyms; + register int nr, symlen; + struct exec ebuf; + off_t r_off, w_off; + + /* 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, (char *)&ebuf, sizeof(struct exec)); + if (nr != sizeof(struct exec)) + goto bad1; + + /* Check magic number and symbol count. */ + if (N_BADMAG(ebuf) || ebuf.a_syms == 0) + goto bad1; + + /* Seek to symbol table. */ + if (fseek(fp, (off_t)N_SYMOFF(ebuf) + r_off, SEEK_SET) == (off_t)-1) + goto bad1; + + /* For each symbol read the nlist entry and save it as necessary. */ + nsyms = ebuf.a_syms; + while (nsyms > 4) { + unsigned value; + unsigned short type; + char name [256]; + + int c = fgetsym(fp, name, &value, &type); + if (c < 0) { + if (feof(fp)) { + /* Bad file format. */ + errno = EINVAL; + } + error(archive); + } + nsyms -= c; + symlen = c - 6; + + /* Ignore if no name or local. */ + if (symlen <= 0 || ! (type & N_EXT)) + continue; + + /* + * If the symbol is an undefined external and the n_value + * field is non-zero, keep it. + */ + if ((type & N_TYPE) == N_UNDF && ! value) + continue; + + rp = (RLIB *)emalloc(sizeof(RLIB)); + rp->next = NULL; + rp->pos = w_off; + rp->symlen = symlen; + rp->sym = (char*) emalloc(symlen + 1); + bcopy(name, rp->sym, symlen + 1); + tsymlen += symlen; + + /* Build in forward order for "ar -m" command. */ + *pnext = rp; + pnext = &rp->next; + ++symcnt; + } +bad1: (void)lseek(rfd, (off_t)r_off, SEEK_SET); +} + +/* + * symobj -- + * Write the symbol table into the archive, computing offsets as + * writing. + */ +void symobj() +{ + register RLIB *rp; + char hb[sizeof(struct ar_hdr) + 1]; + long ransize, baseoff; + + /* Rewind the archive, leaving the magic number. */ + if (fseek(fp, (off_t)SARMAG, SEEK_SET) == (off_t)-1) + error(archive); + + /* Compute the size of rantab. */ + ransize = 0; + for (rp = rhead; rp; rp = rp->next) { + ransize += rp->symlen + 5; + } + ransize += 4 - (ransize & 3); + + /* Put out the ranlib archive file header. */ + (void)sprintf(hb, HDR2, RANLIBMAG, 0L, getuid(), getgid(), + 0666 & ~umask(0), ransize, ARFMAG); + if (! fwrite(hb, sizeof(struct ar_hdr), 1, fp)) + error(tname); + + /* Offset of the first archive file. */ + baseoff = SARMAG + sizeof(struct ar_hdr) + ransize; + + /* + * Write out the ranlib structures. The offset into the archive + * is the base value plus the offset to the first archive file. + */ + for (rp = rhead; rp; rp = rp->next) { + /* Write struct ranlib to file. + * 1 byte - length of name. + * 4 bytes - seek in archive. + * 'len' bytes - symbol name. */ + unsigned offset = baseoff + rp->pos; + fputc (rp->symlen, fp); + if (! fwrite((char *)&offset, 4, 1, fp)) + error(archive); + if (! fwrite(rp->sym, rp->symlen, 1, fp)) + error(tname); + if (verbose) + fprintf (stderr, "%8u %s\n", offset, rp->sym); + ransize -= rp->symlen + 5; + } + + /* Align to word boundary. */ + while (ransize-- > 0) + fputc (0, fp); + + (void)fflush(fp); +} + +void 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); +} + +int tmp() +{ +#ifndef CROSS + long set, oset; +#endif + int fd; + char path[MAXPATHLEN]; + + bcopy(_PATH_RANTMP, path, sizeof(_PATH_RANTMP)); + +#ifndef CROSS + set = sigmask(SIGHUP) | sigmask(SIGINT) | + sigmask(SIGQUIT) | sigmask(SIGTERM); + oset = sigsetmask(set); +#endif + fd = mkstemp(path); + if (fd < 0) + error(tname); + (void)unlink(path); +#ifndef CROSS + (void)sigsetmask(oset); +#endif + return(fd); +} + +int 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) == 0) { + 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); +} + +int 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); +} + +void usage() +{ + fprintf(stderr, "Usage:\n"); + fprintf(stderr, " ranlib [-t] file...\n"); + fprintf(stderr, "Options:\n"); + fprintf(stderr, " -t Update the timestamp of the symbol map\n"); + fprintf(stderr, " -v Verbose: print the resulting symbol map\n"); + exit(1); +} + +int main(argc, argv) + int argc; + char **argv; +{ + int ch, eval, tflag; + + tflag = 0; + while ((ch = getopt(argc, argv, "tv")) != EOF) + switch(ch) { + case 't': + tflag = 1; + break; + case 'v': + verbose = 1; + break; + case 'h': + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; + + if (! *argv) + usage(); + + for (eval = 0; (archive = *argv++);) + eval |= tflag ? touch() : build(); + return eval; +} + +/* + * For archive.c. + */ +char *rname(path) + char *path; +{ + register char *ind; + + ind = rindex(path, '/'); + if (! ind) + return path; + return ind + 1; +} + +void badfmt() +{ + errno = EINVAL; + error(archive); +} diff --git a/src/cmd/rdprof/Makefile b/src/cmd/rdprof/Makefile new file mode 100644 index 0000000..157b70f --- /dev/null +++ b/src/cmd/rdprof/Makefile @@ -0,0 +1,40 @@ +# +# Public Domain. 1995/03/13 - Steven Schultz +# +TOPSRC = $(shell cd ../../..; pwd) +include $(TOPSRC)/target.mk + +CFLAGS += -Werror -I../../../sys/include + +BIN = rdprof +SRCS = $(BIN).c +OBJS = $(BIN).o +MAN = $(BIN).0 + +all: $(BIN) ${MAN} + +$(BIN): ${OBJS} + ${CC} ${LDFLAGS} -o $@.elf ${OBJS} ${LIBS} + ${OBJDUMP} -S $@.elf > $@.dis + ${SIZE} $@.elf + ${ELF2AOUT} $@.elf $@ + +.SUFFIXES: .0 .1 + +.1.0: + ${MANROFF} $*.1 > $@ + +clean: + rm -f *.o *.elf ${MAN} *.elf *.dis tags *~ $(BIN) + +depend: ${SRCS} + mkdep ${CFLAGS} ${SRCS} + +install: all + install -m 755 $(BIN) ${DESTDIR}/sbin + +lint: ${SRCS} + lint -hax ${SRCS} + +tags: ${SRCS} + ctags ${SRCS} diff --git a/src/cmd/rdprof/rdprof.1 b/src/cmd/rdprof/rdprof.1 new file mode 100644 index 0000000..e69de29 diff --git a/src/cmd/rdprof/rdprof.c b/src/cmd/rdprof/rdprof.c new file mode 100644 index 0000000..264ccfe --- /dev/null +++ b/src/cmd/rdprof/rdprof.c @@ -0,0 +1,196 @@ +#include +#include +#include +#include +#include +#include +#include + +void usage() +{ + printf("Usage: rdprof [-w] [-s ] [-r repeat] [-b blocks] -d \n"); + exit(10); +} + +int numblocks(int fd) +{ + int size=0; + ioctl(fd,RDGETMEDIASIZE,&size); + return size; +} + +void read_test(char *dev, unsigned int blocks, int blocksize, int repeats) +{ + int fd; + int size; + char buffer[blocksize]; + unsigned int toread; + unsigned int start_time; + unsigned int end_time; + unsigned int time_taken; + int i; + float bps; + + fd = open(dev,O_RDONLY); + + if(!fd) + { + printf("Error: unable to open %s for reading.\n",dev); + exit(10); + } + size = numblocks(fd); + if(size==0) + { + printf("Error: unable to get media size.\n"); + close(fd); + exit(0); + } + if(blocks>size) + { + printf("More blocks requested than media size. Reducing.\n"); + blocks = size; + } + if(blocks==0) + { + blocks=size; + } + + printf("Testing read of %s from 0 to %d with %d byte blocks...\n", + dev,blocks-1,blocksize); + + start_time = msec(); + for(i=0; i 0) + { + if(toread>blocksize) + { + toread -= read(fd,buffer,blocksize); + } else { + toread -= read(fd,buffer,toread); + } + } + } + end_time = msec(); + close(fd); + time_taken = end_time - start_time; + bps = (float)((blocks*repeats) * 1024) / ((float)time_taken / 1000.0); + + printf("Time taken: %f seconds. Speed: %f KBytes/second\n", + time_taken / 1000.0, bps/1024.0); +} + +void write_test(char *dev, unsigned int blocks, int blocksize, int repeats) +{ + int fd; + int size; + char buffer[blocksize]; + unsigned int towrite; + unsigned int start_time; + unsigned int end_time; + unsigned int time_taken; + int i; + float bps; + + for(size=0; sizesize) + { + printf("More blocks requested than media size. Reducing.\n"); + blocks = size; + } + if(blocks==0) + { + blocks=size; + } + + printf("Testing write of %s from 0 to %d with %d byte blocks...\n", + dev,blocks-1,blocksize); + + start_time = msec(); + for(i=0; i 0) + { + if(towrite>blocksize) + { + towrite -= write(fd,buffer,blocksize); + } else { + towrite -= write(fd,buffer,towrite); + } + } + } + end_time = msec(); + close(fd); + time_taken = end_time - start_time; + bps = (float)((blocks*repeats) * 1024) / ((float)time_taken / 1000.0); + + printf("Time taken: %f seconds. Speed: %f KBytes/second\n", + time_taken / 1000.0, bps/1024.0); +} + +void main(int argc, char *argv[]) +{ + int opt; + unsigned char write_enable = 0; + char *device = NULL; + unsigned int blocks = 0; + int blocksize = 1024; + int repeats = 1; + + printf("RetroDisk Profiler\n"); + + while((opt = getopt(argc,argv,"wd:b:s:r:"))!=-1) + { + switch(opt) + { + case 'w': + printf("Write tests enabled!\n"); + write_enable=1; + break; + case 'd': + device = optarg; + break; + case 'b': + blocks = atoi(optarg); + break; + case 's': + blocksize = atoi(optarg); + break; + case 'r': + repeats = atoi(optarg); + break; + } + } + + if(device==NULL) + { + usage(); + } + + read_test(device,blocks,blocksize,repeats); + if(write_enable==1) + write_test(device,blocks,blocksize,repeats); +} + diff --git a/src/cmd/re/Makefile b/src/cmd/re/Makefile new file mode 100644 index 0000000..cd901e2 --- /dev/null +++ b/src/cmd/re/Makefile @@ -0,0 +1,32 @@ +# +# Visual text editor for Unix. +# Based on sources of RAND Editor. +# Part of Demos Operating System Project, Russia 1982-1991. +# +# Alex P. Roudnev, Moscow, KIAE, 1984 +# +TOPSRC = $(shell cd ../../..; pwd) +include $(TOPSRC)/target.mk + +CFLAGS += -Wall -Werror -DMULTIWIN=0 +#CFLAGS += -DDEBUG + +OBJS = r.cmd.o r.edit.o r.file.o r.gettc.o r.misc.o \ + r.macro.o r.main.o r.display.o r.termcap.o r.ttyio.o r.window.o + +all: re + +re: ${OBJS} + ${CC} ${LDFLAGS} -o re.elf ${OBJS} ${LIBS} + ${OBJDUMP} -S re.elf > re.dis + ${SIZE} re.elf + ${ELF2AOUT} re.elf $@ + +${OBJ}: r.defs.h + +clean: + rm -f *.o *.elf re *.elf *.dis *~ + +install: all help.txt + install re $(DESTDIR)/bin/re + cp -p help.txt $(DESTDIR)/share/re.help diff --git a/src/cmd/re/Makefile-linux b/src/cmd/re/Makefile-linux new file mode 100644 index 0000000..3b86646 --- /dev/null +++ b/src/cmd/re/Makefile-linux @@ -0,0 +1,24 @@ +# +# Visual text editor for Unix. +# Based on sources of RAND Editor. +# Part of Demos Operating System Project, Russia 1982-1991. +# +# Alex P. Roudnev, Moscow, KIAE, 1984 +# +CFLAGS = -Os -g -Wall -Werror -DDEBUG -DMULTIWIN=0 + +# For Linux and Mac OS X +CFLAGS += -DTERMIOS + +all: re + +OBJS = r.cmd.o r.edit.o r.file.o r.gettc.o r.misc.o \ + r.macro.o r.main.o r.display.o r.termcap.o r.ttyio.o r.window.o + +re: $(OBJS) + cc $(OBJS) -o $@ + +$(OBJS): r.defs.h + +clean: + rm -f *.o *~ re *.dis *.elf diff --git a/src/cmd/re/README.txt b/src/cmd/re/README.txt new file mode 100644 index 0000000..a5ad2ee --- /dev/null +++ b/src/cmd/re/README.txt @@ -0,0 +1,44 @@ +TERMCAP variable contains a list of terminal capabilities. + + co Numeric Number of columns + li Numeric Number of lines + nb Flag No bell + cm String Cursor movement + cl String Clear screen + ho String Home: move to top left corner + up String Move up + do String Move down + nd String Move right + le String Move left + cu String Draw cursor label + kh String Key Home + kH String Key End + ku String Key Up + kd String Key Down + kr String Key Right + kl String Key Left + kP String Key Page Up + kN String Key Page Down + kI String Key Insert Char + kD String Key Delete Char + k1 String Key F1 + k2 String Key F2 + k3 String Key F3 + k4 String Key F4 + k5 String Key F5 + k6 String Key F6 + k7 String Key F7 + k8 String Key F8 + k9 String Key F9 + k0 String Key F10 + F1 String Key F11 + F2 String Key F12 + + +Example for Linux terminal: + +TERMCAP=:co#80:li#25:cm=\E[%i%d;%dH:cl=\E[H\E[2J:ho=\E[H:\ +up=\E[A:do=\E[B:nd=\E[C:le=\10:cu=\E[7m \E[m:ku=\E[A:kd=\E[B:\ +kr=\E[C:kl=\E[D:kP=\E[5~:kN=\E[6~:kI=\E[2~:kD=\E[3~:kh=\E[1~:kH=\E[4~:\ +k1=\E[[A:k2=\E[[B:k3=\E[[C:k4=\E[[D:k5=\E[15~:k6=\E[17~:\ +k7=\E[18~:k8=\E[19~:k9=\E[20~:k0=\E[21~:F1=\E[23~:F2=\E[24~: diff --git a/src/cmd/re/help.txt b/src/cmd/re/help.txt new file mode 100644 index 0000000..b2e8edd --- /dev/null +++ b/src/cmd/re/help.txt @@ -0,0 +1,23 @@ + ____________________________ ______________________________ + | F1 | F2 | F3 | F4 | | F5 | F6 | F7 | F8 | + | | | Next | | | | | | | + | Cmd | Save | File |Filter| | Copy | Paste |Search| Goto | + |_____|______|______|______| |______|_______|______|______| + + ____________________________ + ^N - Help, New/Next File | | | | + ^X ^C - Exit wih Saving | Insert | Home | Page | + ^A - Arguments | | | Up | + ^A qa - Exit without Saving |________|________|________| + ^F, ^B - Search Forward, Backward | | | | + ^D - Delete symbol | Delete | End | Page | + ^Y - Delete line/block | | | Down | + ^C - Copy line/block |________|________|________| + ^V - Paste line/block | | + ^P - Quote next symbol | ^ | + ^X i - Insert Mode | | | + ^L - Refresh screen _________|________|_________ + ^X f - Shift view to right | | | | + ^X b - Shift view to left | <-- | | | --> | + ^A >x - Create Macro | | V | | + ^A $x - Use Macro |________|________|________| diff --git a/src/cmd/re/r.cmd.c b/src/cmd/re/r.cmd.c new file mode 100644 index 0000000..c0fac3c --- /dev/null +++ b/src/cmd/re/r.cmd.c @@ -0,0 +1,830 @@ +/* + * Main loop of editor. + * + * RED editor for OS DEMOS + * Alex P. Roudnev, Moscow, KIAE, 1984 + */ +#include "r.defs.h" +#include + +static int insert_mode = 1; /* Insert mode */ +static int clr_arg_area; /* Need to erase the arg area */ +static int fname_cvt_flag; /* Disable filename conversion on "re -" */ + +/* + * Run an external filter. + * Return 0 in case of errors. + */ +static int callexec() +{ + register int i; + char **execargs; + register char *cp, **e; + int j, k, m, pipef[2]; + char pwbuf[100]; +#define NARGS 20 + + /* + * Get a counter of paragraphs (positive) or lines (negative or 'l'). + * Assume 1 paragraph by default. + */ + i = curwksp->topline + cursorline; + m = 1; + cp = param_str; + if (*cp == '-' || (*cp >= '0' && *cp <= '9')) { + cp = s2i(param_str, &m); + if (cp == 0) { +noargerr: error("Invalid argument."); + return(0); + } + } + m = -m; + if (*cp == 'l') { + cp++; + m = -m; + } + + /* + * Build an arg vector. + */ + e = execargs = (char**) salloc(NARGS*(sizeof (char *))); + while (*cp == ' ') + cp++; + while (*cp != 0) { + *e++ = cp; /* arg address */ + if (e >= execargs + NARGS) + goto noargerr; /* too much */ + if (*cp == '"') { + cp++; + e[-1]++; + while (*cp++ != '"') + if (*cp == 0) + goto noargerr; + cp[-1] = 0; + } + else if (*cp++ == '\'') { + e[-1]++; + while (*cp++ != '\'') + if (*cp == 0) + goto noargerr; + cp[-1] = 0; + } + else { + while (*cp != ' ' && *cp != ',' && *cp) + cp++; + } + while (*cp == ' ' || *cp == ',') + *cp++ = 0; + } + *e = 0; + + /* + * Run the command through pipe. + * (re) | (command; re) + * Second copy of re will fetch the rest from the pipe. + */ + if (pipe(pipef) < 0) { +nopiperr: + error("Can not fork or write pipe."); + return(0); + } + j = fork(); + if (j < 0) + goto nopiperr; + if (j == 0) { /* command; re */ + close(0); /* set as stdin */ + if (dup(pipef[0]) < 0) + exit(-1); + close(1); /* output to temporary file */ + open(tmpname, 1); + lseek(1, tempseek, 0); + j = 2; + + /* Close all other descriptors. */ + while ((k = dup(1)) >= 0) + if (k > j) + j = k; + while (j >= 2) + close(j--); + i = fork(); + if (i < 0) + goto nopiperr; + if (i != 0) { /* re */ + while (wait(&m) != i); /* wait, then read */ + while (read(0, pwbuf, 100)); /* until exhausted */ + exit(m >> 8); /* and return the status */ + } + execvp(execargs[0], execargs); + exit(0xDF); /* exit code matches doreplace */ + } + + /* Parent. */ + telluser("Executing ...",0); + free((char*)execargs); + doreplace(i, m, j, pipef); + return(1); +} + +/* + * Insert a symbol to current line at a current position. + */ +static void cline_insert_char(keysym) +{ + int i, c; + + /* Check the window margin. */ + if (cursorcol > curwin->text_maxcol) { + if (cline_modified) + putline(); + wksp_offset(defroffset); + i = curwksp->topline + cursorline; + if (clineno != i) + getlin(i); + } + cline_modified = 1; + c = cursorcol + curwksp->offset; + if (c >= cline_max - 2) { + /* Expand the line. */ + cline_expand(c + 2); + } + if (c >= cline_len - 1) { + /* Append spaces to the line. */ + for (i=cline_len-1; i<=c; i++) + cline[i] = ' '; + cline[c+1] = '\n'; + cline_len = c + 2; + } + else if (insert_mode) { + /* Push the rest of the line. */ + if (cline_len >= cline_max) + cline_expand(cline_len + 1); + for (i=cline_len; i>c; i--) + cline[i] = cline[i-1]; + cline_len++; + drawlines(- c + curwksp->offset - 1, cursorline); + poscursor(c - curwksp->offset, cursorline); + } + + /* Store the symbol. */ + if (keysym == CCCTRLQUOTE) + keysym = COCURS; + cline[c] = keysym; + wputc(keysym, 1); +} + +/* + * Draw the bottom line: message, file name, current line number. + */ +static void drawstatus() +{ + window_t *owin; + char numstr[16], *cp; + int i, ccol, cline; + + /* Switch to param window. */ + owin = curwin; + cline = cursorline; + ccol = cursorcol; + win_switch(¶mwin); + paramwin.text_maxcol = NCOLS; + if (clr_arg_area) { + if (! message_displayed) { + poscursor(0, 0); + //putch(COERLN); + for (i=PARAMWIDTH; i>0; i--) + wputc('~', 0); + } + if (owin->wksp->wfile) { + i = strlen(file[owin->wksp->wfile].name); + if (i < PARAMWIDTH-4) { + poscursor(PARAMWIDTH-i-2, 0); + wputc('"', 0); + wputs(file[owin->wksp->wfile].name, NCOLS-2); + wputc('"', 0); + } + } + poscursor(PARAMWIDTH, 0); + wputs(insert_mode ? "~~Ins~~Line:~~~~~~~" : + "~~~~~~~Line:~~~~~~~", NCOLS); + } + /* Display the current line number. */ + i = owin->wksp->topline + cline + 1; + cp = numstr + sizeof(numstr); + *--cp = '\0'; + *--cp = '~'; + *--cp = '~'; + *--cp = '~'; + *--cp = '~'; + *--cp = '~'; + do { + (*--cp = '0' + (i % 10)); + i /= 10; + } while (i); + cp[6] = '\0'; + poscursor(PARAMWIDTH+12, 0); + wputs(cp, NCOLS-2); + + /* Switch back to editor window. */ + win_switch(owin); + paramwin.text_maxcol = PARAMWIDTH; + poscursor(ccol, cline); + if (highlight_position) { + wputc(COCURS, 1); + poscursor(ccol, cline); + dumpcbuf(); + sleep(1); + drawlines(cline, cline); + poscursor(ccol, cline); + } +} + +/* + * Main editor loop. + */ +void mainloop() +{ + void (*linefunc)(int, int); + void (*blockfunc)(int, int, int, int); + int i, m; + + for (;;) { + clr_arg_area = 1; +newnumber: + keysym = -1; /* mark the symbol as used */ +errclear: + drawstatus(); +nextkey: + highlight_position = 0; + clr_arg_area = 0; + getkeysym(); + if (message_displayed) { + /* Clear the message after any key pressed. */ + message_displayed = 0; + clr_arg_area = 1; + goto errclear; + } + + /* + * Edit the current line. + */ + if (! CTRLCHAR(keysym) || keysym == CCCTRLQUOTE || + keysym == CCBACKSPACE || keysym == CCDELCH || + (keysym == CCTAB && insert_mode)) + { + /* Backspace at column 0: join lines. */ + if (keysym == CCBACKSPACE && cursorcol + curwksp->offset == 0) { + int lnum = curwksp->topline + cursorline; + if (lnum > file[curfile].nlines) { + /* Beyond end of file - move up. */ + movecursor(CCMOVEUP); + keysym = -1; + goto nextkey; + } + if (file[curfile].writable == 0 || lnum == 0) { + /* File not writable or at line 0. */ + keysym = -1; + goto nextkey; + } + /* Append the current line to the previous one. */ + putline(); + getlin(lnum - 1); + combineline(lnum - 1, cline_len - 1); + continue; + } + if (file[curfile].writable == 0) + goto nowriterr; + + /* No current line? Get it! */ + i = curwksp->topline + cursorline; + if (clineno != i) + getlin(i); + + /* Delete char after line end: join lines. */ + if (keysym == CCDELCH && + cursorcol + curwksp->offset >= cline_len - 1) + { + int lnum = curwksp->topline + cursorline; + if (lnum >= file[curfile].nlines) { + /* Beyond end of file. */ + keysym = -1; + goto nextkey; + } + if (file[curfile].writable == 0) { + /* File not writable. */ + keysym = -1; + goto nowriterr; + } + /* Append the next line to the current one. */ + putline(); + combineline(lnum, cursorcol + curwksp->offset); + continue; + } + + /* Delete the symbol. */ + if (keysym == CCDELCH || keysym == CCBACKSPACE) { + int thiscol = cursorcol + curwksp->offset; + int thisrow = cursorline; + + if (keysym == CCBACKSPACE) + thiscol--; + if (cline_len < thiscol + 2) { + if (keysym == CCBACKSPACE) + movecursor(CCMOVELEFT); + keysym = -1; + goto nextkey; + } + for (i=thiscol; ioffset; + drawlines(-thiscol-1, cursorline); + poscursor(thiscol, thisrow); + cline_modified = 1; + keysym = -1; + goto nextkey; + } + if (keysym == CCTAB) { + /* Expand tabs to 4 spaces. */ + do { + cline_insert_char(' '); + } while ((cursorcol + curwksp->offset) & 3); + } else + cline_insert_char(keysym); + keysym = -1; + goto nextkey; + } + if (keysym == CCRETURN) { + /* - split the line. */ + if (file[curfile].writable == 0) + goto nowriterr; + putline(); + splitline(curwksp->topline + cursorline, + cursorcol + curwksp->offset); + movecursor(keysym); + keysym = -1; + goto errclear; + } + + /* + * Cursor movement. + */ + if (keysym <= CCEND) { + movecursor(keysym); + if (keysym == CCMOVEUP || keysym == CCMOVEDOWN || + keysym == CCPGDOWN || keysym == CCPGUP || + keysym == CCRETURN || keysym == CCHOME) { + /* Row changed: save current line. */ + putline(); + goto newnumber; + } + keysym = -1; + goto nextkey; + } + + /* Window margin. */ + if (cursorcol > curwin->text_maxcol) + poscursor(curwin->text_maxcol, cursorline); + putline(); + switch (keysym) { + case CCQUIT: + if (endit()) + return; + continue; + + case CCPARAM: + break; + + case CCLOFFSET: + wksp_offset(- defloffset); + continue; + + case CCSETFILE: + switchfile(); + continue; + + case CCINSLIN: + if (file[curfile].writable == 0) + goto nowriterr; + insertlines(curwksp->topline + cursorline, 1); + continue; + + case CCMISRCH: + search(-1); + continue; + + case CCDELLIN: + if (file[curfile].writable == 0) + goto nowriterr; + deletelines(curwksp->topline + cursorline, 1); + continue; + + case CCPASTE: + if (file[curfile].writable == 0) + goto nowriterr; + if (pickbuf->nrows == 0) { + error("Clipboard is empty."); + continue; + } + paste(pickbuf, curwksp->topline + cursorline, + curwksp->offset + cursorcol); + continue; + + case CCCOPY: + picklines(curwksp->topline + cursorline, 1); + continue; + + case CCINSMODE: + insert_mode = 1 - insert_mode; /* change it */ + continue; + + case CCGOTO: + gtfcn(0); + continue; + + case CCPLSRCH: + search(1); + continue; + + case CCROFFSET: + wksp_offset(defroffset); + continue; + + case CCDELCH: + goto notimperr; + + case CCSAVEFILE: + savefile(NULL, curfile); + continue; + + case CCDOCMD: + goto notstrerr; + + case CCREDRAW: /* Redraw screen */ + redisplay(); + keysym = -1; + continue; +#if MULTIWIN + case CCMAKEWIN: + win_open(deffile); + continue; + + case CCCHWINDOW: + win_goto(-1); + continue; +#endif + /* case CCMOVELEFT: */ + /* case CCTAB: */ + /* case CCMOVEDOWN: */ + /* case CCHOME: */ + /* case CCRETURN: */ + /* case CCMOVEUP: */ + default: + goto badkeyerr; + } + + /* + * Cmd: prompt. + */ + param(); +gotcmd: + switch (keysym) { + case CCQUIT: + if (param_len > 0 && + (int_to_ext(param_str, param_len), *param_str) == 'a') + { + if (param_str[1] != 'd') + return; + cleanup(); + inputfile = -1; /* to force a dump */ + fatal("ABORTED"); + } + if (endit()) + return; + continue; + + case CCPARAM: + continue; + + case CCLOFFSET: + if (param_type <= 0) + goto notstrerr; + if (s2i(param_str, &i)) + goto notinterr; + wksp_offset(-i); + continue; + + case CCSETFILE: + if (param_type <= 0) + goto notstrerr; + if (param_str == 0) + goto noargerr; + if (fname_cvt_flag || ! inputfile) + int_to_ext(param_str, param_len); + fname_cvt_flag = 1; + editfile(param_str, 0, 0, 1, 1); + continue; + + case CCINSLIN: + if (file[curfile].writable == 0) + goto nowriterr; + if (param_type != 0) { + linefunc = insertlines; + blockfunc = openspaces; + break; + } + splitline(param_r0, param_c0); + continue; + + case CCMISRCH: + case CCPLSRCH: + if (param_type <= 0) + goto notstrerr; + if (param_str == 0) + goto noargerr; + if (searchkey) + free(searchkey); + searchkey = param_str; + param_len = 0; + search(keysym == CCPLSRCH ? 1 : -1); + continue; + + case CCDELLIN: + if (file[curfile].writable == 0) + goto nowriterr; + if (param_type != 0) { + if (param_type > 0 && param_str && param_str[0] == '>') { + mstore(deletebuf, param_str + 1); + continue; + } + linefunc = deletelines; + blockfunc = closespaces; + break; + } + combineline(param_r0, param_c0); + continue; + + case CCPASTE: + if (param_type > 0 && param_str && param_str[0] == '$') { + if (mfetch(deletebuf, param_str + 1)) + goto errclear; + continue; + } + if (param_type != 0) + goto notstrerr; + if (file[curfile].writable == 0) + goto nowriterr; + if (deletebuf->nrows == 0) { + error ("Delete buffer is empty."); + continue; + } + paste(deletebuf, curwksp->topline + cursorline, + curwksp->offset + cursorcol); + continue; + + case CCMOVELEFT: + case CCTAB: + case CCMOVEDOWN: + case CCHOME: + case CCEND: + case CCMOVEUP: + case CCMOVERIGHT: + if (s2i(param_str, &i)) + goto notinterr; + if (i <= 0) + goto notposerr; + m = ((keysym <= CCEND) ? keysym : 0); + while (--i >= 0) + movecursor(m); + continue; + + case CCRETURN: + if (param_type <= 0 || ! param_str) + goto notimperr; + int_to_ext(param_str, param_len); + switch (param_str[0]) { + case '>': + msvtag(param_str + 1); + break; + case '$': + if (mdeftag(param_str + 1)) { + /* Wait again on a Cmd: prompt. */ + keysym = -1; + getkeysym(); + if (! CTRLCHAR(keysym)) + goto noargerr; + goto gotcmd; + } + break; + case 'w': + if(param_str[1] == ' ' && param_str[2] == '+') + file[curwksp->wfile].writable = 1; + else + file[curwksp->wfile].writable = 0; + break; + case 'r': /* Redraw screen */ + redisplay(); + break; + case 'q': + keysym = CCQUIT; + if (param_str[1] == 'a') { + return; + } + goto nextkey; + default: + goto noargerr; + } + continue; + + case CCCOPY: + if (param_type == 0) + goto notimperr; + if (param_type > 0 && param_str && param_str[0] == '>') { + mstore(pickbuf, param_str + 1); + continue; + } + linefunc = picklines; + blockfunc = pickspaces; + break; + + case CCINSMODE: + insert_mode = ! insert_mode; + continue; + + case CCGOTO: + if (param_type == 0) + gtfcn(file[curfile].nlines); + else if (param_type > 0) { + if(param_str && param_str[0] == '$') { + mgotag(param_str + 1); + continue; + } + if (s2i(param_str, &i)) + goto notinterr; + gtfcn(i - 1); + } else + goto noargerr; + continue; + + case CCROFFSET: + if (param_type <= 0) + goto notstrerr; + if (s2i(param_str, &i)) + goto notinterr; + wksp_offset(i); + continue; + + case CCDELCH: + goto notimperr; + + case CCSAVEFILE: + if (param_type <= 0) + goto notstrerr; + if (param_str == 0) + goto noargerr; + int_to_ext(param_str, param_len); + savefile(param_str, curfile); + continue; + + case CCDOCMD: + if (param_type <= 0) + goto notstrerr; + int_to_ext(param_str, param_len); + if (file[curfile].writable == 0) + goto nowriterr; + callexec(); + continue; +#if MULTIWIN + case CCMAKEWIN: + if (param_type == 0) + win_remove(); + else if (param_type < 0) + goto notstrerr; + else { + int_to_ext(param_str, param_len); + win_open(param_str); + } + continue; + + case CCCHWINDOW: + if (param_type <= 0) + goto notstrerr; + if (s2i(param_str, &i)) + goto notinterr; + if (i <= 0) + goto notposerr; + win_goto(i - 1); + continue; +#endif + default: + goto badkeyerr; + } +spdir: + if (param_type > 0) { + if(param_str[0] == '$') { + if (mdeftag(param_str + 1)) + goto spdir; + continue; + } + if (s2i(param_str, &i)) + goto notinterr; + if (i <= 0) + goto notposerr; + linefunc(curwksp->topline + cursorline, i); + + } else if (param_c1 == param_c0) { + linefunc(param_r0, (param_r1 - param_r0) + 1); + } else { + blockfunc(param_r0, param_c0, + (param_c1 - param_c0), (param_r1 - param_r0) + 1); + } + continue; +badkeyerr: + error("Unknown command."); + continue; +notstrerr: + error("Need a string parameter."); + continue; +noargerr: + error("Invalid argument."); + continue; +notinterr: + error("Need a numeric parameter."); + continue; +notposerr: + error("Need a positive parameter."); + continue; +notimperr: + error("Feature not implemented yet."); + continue; +nowriterr: + error("You cannot modify this file!"); + continue; + } +} + +/* + * Search forward/backward in file. + * delta = 1 / -1 + * Setup a window when needed, and show a found text. + * Search for "searchkey". + */ +void search(delta) + int delta; +{ + register char *at, *sk, *fk; + int ln, lkey, col, lin, slin, i; + + param_len = 0; + if (searchkey == 0 || *searchkey == 0) { + error("Nothing to search for."); + return; + } + col = cursorcol; + slin = lin = cursorline; + if (delta == 1) + telluser("+", 0); + else + telluser("-", 0); + telluser("Search: ", 1); + telluser(searchkey, 9); + wputc(COCURS, 1); + poscursor(col, lin); + dumpcbuf(); + lkey = 0; + sk = searchkey; + while (*sk++) + lkey++; + ln = lin + curwksp->topline; + getlin (ln); + putline(); + at = cline + col + curwksp->offset; + for (;;) { + at += delta; + while (at < cline || at > cline + cline_len - lkey) { + /* Abort on interrupt from the tty. */ + i = interrupt(); + if (i || (ln += delta) < 0 || + (wksp_position(curwksp, ln) && delta == 1)) + { + drawlines(lin, lin); + poscursor(col, lin); + error(i ? "Interrupt." : "Search key not found."); + highlight_position = 0; + return; + } + getlin(ln); + putline(); + at = cline; + if (delta < 0) + at += cline_len - lkey; + } + sk = searchkey; + fk = at; + while (*sk == *fk++ && *++sk); + if (*sk == 0) { + cgoto(ln, at - cline, slin, 0); + highlight_position = 1; + return; + } + } +} diff --git a/src/cmd/re/r.defs.h b/src/cmd/re/r.defs.h new file mode 100644 index 0000000..1f23d97 --- /dev/null +++ b/src/cmd/re/r.defs.h @@ -0,0 +1,348 @@ +/* + * Global definitions. + * + * RED editor for OS DEMOS + * Alex P. Roudnev, Moscow, KIAE, 1984 + */ +#include +#include +#include +#include +#include + +#ifdef DEBUG +#include +#endif + +/* + * DEBUGCHECK: check consistency of segment chains. + */ +#ifdef DEBUG +# define DEBUGCHECK checksegm() +#else +# define DEBUGCHECK /* */ +#endif + +#define MOVECMD(x) ((x) >= CCMOVEUP && (x) <= CCEND) +#define CTRLCHAR(x) (((x) >= 0 && (x) < ' ') || ((x) >= 0177 && (x) < 0240)) +#define MAXCOLS 256 /* max. width of screen */ +#define MAXLINES 64 /* max. height of screen */ +#define LBUFFER 256 /* lower limit for the current line buffer */ +#define PARAMWIDTH (NCOLS-18) /* input field of paramwin */ +#define FILEMODE 0664 /* access mode for newly created files */ +#define MAXFILES 14 /* max. files under edit */ +#define MAXWINLIST 10 /* max.windows */ + +#ifndef MULTIWIN +#define MULTIWIN 1 /* enable splitting a screen into multiple windows */ +#endif + +#define BADF -1 +#define CONTF -2 + +/* OUTPUT CODES */ + +#define COSTART 0 +#define COUP 1 +#define CODN 2 +#define CORN 3 +#define COHO 4 +#define CORT 5 +#define COLT 6 +#define COCURS 7 +#define COBELL 8 +#define COFIN 9 +#define COERASE 10 +#define COERLN 11 +#define COMCOD 12 /* Number of output codes */ + +/* margin characters */ +#define LMCH '|' +#define RMCH '|' +#define TMCH '-' +#define BMCH '-' +#define MRMCH '>' +#define MLMCH '<' +#define ELMCH ';' +#define DOTCH '+' + +/* + * Descriptor of file segment. Contains from 1 to 127 lines of file, + * written sequentially. An elementary component of descriptor chain. + */ +#define FSDMAXL 127 /* Max. number of lines in descriptor */ + +typedef struct segment { + struct segment *prev; /* Previous descriptor in chain */ + struct segment *next; /* Next descriptor in chain */ + int nlines; /* Count of lines in descriptor, + * or 0 when end of chain */ + int fdesc; /* File descriptor, or 0 for end of chain */ + off_t seek; /* Byte offset in the file */ + char data; /* Varying amount of data, needed + * to store the next nlines-1 lines. */ + /* + * Interpretation of next byte: + * 1-127 offset of this line from a previous line + * 0 empty line + * -n line starts at offset n*128+next bytes + * from beginning of previous line. + * There are at least nlines-1 bytes allocated or more, + * in case of very long lines. + */ +} segment_t; + +#define sizeof_segment_t offsetof (segment_t, data) + +typedef struct { + segment_t *chain; /* Chain of segments */ + char *name; /* File name */ + char writable; /* Do we have a write permission */ +#define EDITED 2 /* Value when file was modified */ + + char backup_done; /* Already copied to .bak */ + int nlines; /* Number of non-empty lines in file */ +} file_t; + +file_t file[MAXFILES]; /* Table of files */ +int curfile; + +/* + * Workspace describes a generic file under edit. + */ +typedef struct { + segment_t *cursegm; /* Current segment */ + int topline; /* Top left row on a display */ + int offset; /* Column offset of a displayed text */ + int line; /* Current line number */ + int segmline; /* Number of first line in the current segment */ + int wfile; /* File number, or 0 when not attached */ + int cursorcol; /* Saved cursorcol, when not active */ + int cursorrow; /* Saved cursorline, when not active */ +} workspace_t; + +workspace_t *curwksp, *pickwksp; + +/* + * Window - a region on the display. + * All display coordinates, and also text_col and text_row, are measured relative + * to (0,0) = top left of screen. + */ +typedef struct { + workspace_t *wksp; /* Pointer to workspace */ + workspace_t *altwksp; /* Alternative workspace */ + int prevwinnum; /* Number of previous window */ + int base_row; /* Top row of the window */ + int base_col; /* Left column of the window */ + int max_row; /* Bottom row of the window */ + int max_col; /* Right column of the window */ + int text_row; /* Top row of text area */ + int text_col; /* Left column of text area */ + int text_maxrow; /* Height-1 of text area */ + int text_maxcol; /* Width-1 of text area */ + unsigned char *firstcol; /* Numbers of first non-space symbols */ + unsigned char *lastcol; /* Numbers of last non-space symbols */ + char *leftbar; /* Symbols on left edge */ + char *rightbar; /* Symbols on right edge */ +} window_t; + +window_t *winlist[MAXWINLIST]; +int nwinlist; + +window_t *curwin; /* Current window */ +window_t wholescreen; /* The whole screen */ +window_t paramwin; /* Window to enter arguments */ + +/* + * Copy-and-paste clipboard. + */ +typedef struct { + int linenum; /* Index of first line in "#" */ + int nrows; /* Number of lines */ + int ncolumns; /* Number of columns */ +} clipboard_t; + +clipboard_t *pickbuf, *deletebuf; + +/* + * Control codes. + */ +#define CCCTRLQUOTE 0 /* knockdown next char ^P */ +#define CCMOVEUP 1 /* move up 1 line up */ +#define CCMOVEDOWN 2 /* move down 1 line down */ +#define CCRETURN 3 /* return ^M */ +#define CCHOME 4 /* home cursor ^X h home */ +#define CCMOVERIGHT 5 /* move right right */ +#define CCMOVELEFT 6 /* move left left */ +#define CCTAB 7 /* tab ^I */ +#define CCPGDOWN 010 /* next page ^X n pg down */ +#define CCPGUP 011 /* previous page ^X p page up */ +#define CCEND 012 /* cursor to end ^X e end */ +#define CCCOPY 013 /* copy to clipboard ^C f5 */ +#define CCMAKEWIN 014 /* make a window --disabled-- */ +#define CCINSLIN 015 /* insert line/block ^O */ +#define CCSETFILE 016 /* set file ^N f3 */ +#define CCCHWINDOW 017 /* change window --disabled-- */ +#define CCGOTO 020 /* goto linenumber ^G f8 */ +#define CCDOCMD 021 /* execute a filter ^X x f4 */ +#define CCPLSRCH 022 /* plus search ^F f7 */ +#define CCROFFSET 023 /* shift view right ^X f */ +#define CCDELCH 024 /* character delete ^D delete */ +#define CCSAVEFILE 025 /* make new file f2 */ +#define CCMISRCH 030 /* minus search ^B */ +#define CCLOFFSET 031 /* shift view left ^X b */ +#define CCPASTE 032 /* paste from clipboard ^V f6 */ +#define CCREDRAW 033 /* redraw all ^L */ +#define CCINSMODE 034 /* insert mode ^X i insert */ +#define CCBACKSPACE 035 /* backspace and erase ^H */ +#define CCDELLIN 036 /* delete line/block ^Y */ +#define CCPARAM 037 /* enter parameter ^A f1 */ +#define CCQUIT 0177 /* terminate session ^X ^C */ +#define CCINTRUP 0237 /* interrupt (journal) */ + +int cursorline; /* physical position of */ +int cursorcol; /* cursor from (0,0)=ulhc of text in window */ + +int NCOLS, NLINES; /* size of the screen */ + +extern char *curspos, *cvtout[]; +extern char cntlmotions[]; +extern const char in0tab[]; /* input control codes */ + +extern int keysym; /* Current input symbol, -1 - need more */ +char intrflag; /* INTR signal occured */ +int highlight_position; /* Highlight the current cursor position */ +int message_displayed; /* Arg area contains an error message */ + +/* Defaults. */ +extern int defloffset, defroffset; +extern char deffile[]; + +/* + * Global variables for param(). + * param_len - length of the parameter; + * param_str - string value of the parameter, + * param_type - type of the parameter, + * param_c0, param_r0, param_c1, + * param_r1 - coordinates of cursor-defined area + */ +int param_len; +char *param_str, param_type; +int param_c0, param_r0, param_c1, param_r1; + +/* + * Current line. + */ +char *cline; /* allocated array */ +int cline_max; /* allocated length */ +int cline_len; /* used length */ +int cline_incr; /* increment for reallocation */ +char cline_modified; /* line was modified */ +int clineno; /* line number in file */ + +/* + * File descriptors: + */ +int tempfile; /* Temporary file */ +off_t tempseek; /* Offset in temporary file */ +int journal; /* Journaling file */ +int inputfile; /* Input file (stdin or journal) */ + +char *searchkey; + +int userid, groupid; + +char *tmpname; /* name of file, for do command */ + +/* + * Translation of control codes to escape sequences. + */ +typedef struct { + int keysym; + char *value; +} keycode_t; + +extern keycode_t keytab[]; + +int getkeysym (void); /* read command from terminal */ +void getlin (int); /* get a line from current file */ +void putline (void); /* put a line to current file */ +void movecursor (int); /* cursor movement operation */ +void poscursor (int, int); /* position a cursor in current window */ +void pcursor (int, int); /* move screen cursor */ +void drawlines (int, int); /* show lines of file */ +void cline_expand (int); /* extend cline array */ +int putch (int); /* output symbol or op */ +void wputc (int, int); /* put a symbol to a current window */ +void wputs (char *, int); /* put a string to a current window */ +void putblanks (int); /* output a line of spaces */ +int endit (void); /* end a session and write all */ +void switchfile (void); /* switch to alternative file */ +void search (int); /* search a text in file */ +void paste (clipboard_t *, int, int); /* put a buffer into file */ +int mfetch (clipboard_t *, char *); /* get a buffer by name */ +void mstore (clipboard_t *, char *); /* store a buffer by name */ +void gtfcn (int); /* go to line by number */ +int savefile (char *, int); /* save a file */ +void error (char *); /* display error message */ +char *param (void); /* get a parameter */ +int cline_read (int); /* read next line from file */ +int int_to_ext (char *, int); /* conversion of line from internal to external form */ +void cleanup (void); /* cleanup before exit */ +void fatal (char *); /* print error message and exit */ +int editfile (char *, int, int, int, int); /* open a file for editing */ +void splitline (int, int); /* split a line at given position */ +void combineline (int, int); /* merge a line with next one */ +int msvtag (char *name); /* save a file position by name */ +int mdeftag (char *); /* define a file area by name */ +void redisplay (void); /* redraw all */ +int mgotag (char *); /* return a cursor back to named position */ +void execr (char **); /* run command with given parameters */ +void telluser (char *, int); /* display a message in arg area */ +void doreplace(int, int, int, int*); /* replace lines via pipe */ +void win_open (char *); /* make new window */ +void win_remove (void); /* remove last window */ +void win_goto (int); /* switch to window by number */ +void win_switch (window_t *); /* switch to given window */ +void win_borders (window_t *, int); /* draw borders for a window */ +void win_create (window_t *, int, int, int, int, int); + /* create new window */ +void dumpcbuf (void); /* flush output buffer */ +char *s2i (char *, int *); /* convert a string to number */ +char *salloc (int); /* allocate zeroed memory */ +void insertlines (int, int); /* insert lines */ +void deletelines (int, int); /* delete lines from file */ +void picklines (int, int); /* get lines from file to pick workspace */ +void openspaces (int, int, int, int); /* insert spaces */ +void closespaces (int, int, int, int); /* delete rectangular area */ +void pickspaces (int, int, int, int); /* get rectangular area to pick buffer */ +int interrupt (void); /* we have been interrupted? */ +void wksp_switch (void); /* switch to alternative workspace */ +int wksp_seek (workspace_t *, int); /* set file position by line number */ +int wksp_position (workspace_t *, int); /* set workspace position */ +void wksp_forward (int); /* move page down or up */ +void wksp_offset (int); /* shift a text view to right or left */ +void wksp_redraw (workspace_t *, int, int, int, int); + /* redisplay windows of the file */ +void cgoto (int, int, int, int); /* scroll window to show a given area */ +char *append (char *, char *); /* append strings */ +char *tgoto (char *, int, int); /* cursor addressing */ +segment_t *file2segm (int); /* create a file descriptor list for a file */ +void puts1 (char *); /* write a string to stdout */ +void checksegm (void); /* check segm correctness */ +int segmwrite (segment_t *, int, int); /* write descriptor chain to file */ +void printsegm (segment_t *); /* debug output of segm chains */ +int checkpriv (int); /* check access rights */ +int getpriv (int); /* get file access modes */ +void tcread (void); /* load termcap descriptions */ +char *tgetstr(char *, char *, char **); /* get string option from termcap */ +int tgetnum (char *, char *); /* get a numeric termcap option */ +int tgetflag (char *, char *); /* get a flag termcap option */ +char *getnm (int); /* get user id as printable text */ +void ttstartup (void); /* setup terminal modes */ +void ttcleanup (void); /* restore terminal modes */ +int get1w (int); /* read word */ +int get1c (int); /* read byte */ +void put1w (int, int); /* write word */ +void put1c (int, int); /* write byte */ +void mainloop (void); /* main editor loop */ diff --git a/src/cmd/re/r.display.c b/src/cmd/re/r.display.c new file mode 100644 index 0000000..476b503 --- /dev/null +++ b/src/cmd/re/r.display.c @@ -0,0 +1,577 @@ +/* + * Interface to display - logical level. + * + * RED editor for OS DEMOS + * Alex P. Roudnev, Moscow, KIAE, 1984 + */ +#include "r.defs.h" + +/* + * Draw lines from lo to lf. + * In case lo is negative: + * - draw only line lf; + * - use cline as a source; + * - draw only from column -lo. + */ +void drawlines(lo, lf) + int lo, lf; +{ + register int i, l0; + int j, k, l1; + char lmc, *cp, draw_border; + + l0 = lo; + lo += 2; + if (lo > 0) + lo = 0; /* Initial column */ + l1 = lo; + lmc = (curwin->base_col == curwin->text_col ? 0 : + curwksp->offset == 0 ? LMCH : MLMCH); + draw_border = (curwin->text_col + curwin->text_maxcol < curwin->max_col); + while (l0 <= lf) { + lo = l1; + if (l0 < 0) { + l0 = lf; + lf = -1; + i = 0; + } else { + if (l0 != lf && interrupt()) + return; + i = wksp_seek(curwksp, curwksp->topline + l0); + if (i && lmc != 0) + lmc = ELMCH; + } + if (! lmc || lo < 0 || lmc == curwin->leftbar[l0]) + poscursor(0, l0); + else { + poscursor(-1, l0); + wputc(lmc, 0); + } + curwin->leftbar[l0] = lmc; + if (draw_border != 0) + draw_border = RMCH; + if (i != 0) + i = 0; + else { + if (lf >= 0) + cline_read(1); + i = (cline_len - 1) - curwksp->offset; + if (i < 0) + i = 0; + else if (i > curwin->text_maxcol) { + if (draw_border && i > 1 + curwin->text_maxcol) + draw_border = MRMCH; + i = 1 + curwin->text_maxcol; + } + } + + /* + * Draw symbols. + * Skip initial spaces, when possible. + */ + if (lo == 0) { + int fc; + for (fc=0; cline != 0 && cline[curwksp->offset + fc]==' '; fc++); + j = curwin->text_maxcol + 1; + if (fc > j) + fc = j; + if (fc > 255) + fc = 255; + lo = (curwin->firstcol[l0] > fc) ? - fc : - curwin->firstcol[l0]; + if (i + lo <= 0) + lo = 0; + else + curwin->firstcol[l0] = fc; + } + if (lo) + poscursor(-lo, l0); + j = i + lo; + cp = cline + curwksp->offset - lo; + while(j--) + putch(*cp++); + cursorcol += (i + lo); + if (curwin->lastcol[l0] < cursorcol) + curwin->lastcol[l0] = cursorcol; + + /* Fill a tail by spaces. */ + j = curwin->lastcol[l0]; + k = j - i; + if (k > 0) { + putblanks(k); + } + if (i > curwin->text_maxcol) { + /* Too long line - add continuation mark. */ + pcursor(curwin->text_col + curwin->text_maxcol, l0); + putch('~'); + } + if (curwin->text_col + cursorcol >= NCOLS) { + /* Cursor lost after last column: move it to known position. */ + cursorcol = 0; + pcursor(0, l0); + } + if (draw_border && draw_border != curwin->rightbar[l0]) { + poscursor(curwin->max_col - curwin->text_col, l0); + wputc(draw_border, 0); + } + curwin->rightbar[l0] = draw_border; + curwin->lastcol[l0] = (k > 0 ? i : j); + ++l0; + } +} + +/* + * Position a cursor in a current window. + */ +void poscursor(col, lin) + int col, lin; +{ + register int scol; + int slin; + + if (cursorline == lin) { + if (cursorcol == col) + return; + if ((cursorcol == col-1) && putch(CORT)) { + ++cursorcol; + return; + } + if ((cursorcol == col+1) && putch(COLT)) { + --cursorcol; + return; + } + } + if (cursorcol == col) { + if ((cursorline == lin-1) && putch(CODN)) { + ++cursorline; + return; + } + if ((cursorline == lin+1) && putch(COUP)) { + --cursorline; + return; + } + } + scol = col + curwin->text_col; + slin = lin + curwin->text_row; /* screen col, lin */ + cursorcol = col; + cursorline = lin; + pcursor(scol, slin); /* direct positioning */ +} + +/* + * Move a cursor within the current window. + * Argument is: + * CCMOVELEFT, CCMOVERIGHT - one column to left or to right + * CCMOVEUP, CCMOVEDOWN - one line up or down + * CCPGUP, CCPGDOWN - page down or up + * CCHOME, CCEND - to line start or end + * CCRETURN - to start of next line + * CCTAB - to next tab stop + * 0 - no movement, check only + */ +void movecursor(arg) + int arg; +{ + register int lin, col; + + lin = cursorline; + col = cursorcol; + switch (arg) { + case 0: + break; + case CCHOME: /* home: cursor to line start */ + col = - curwksp->offset; + break; + case CCMOVELEFT: /* backspace */ + if (col + curwksp->offset > 0) { + --col; + break; + } + if (lin + curwksp->topline <= 0) + break; + lin--; + /* fall through... */ + case CCEND: /* home: cursor to line end */ + if (clineno != curwksp->topline + lin) + getlin(curwksp->topline + lin); + col = cline_len - 1 - curwksp->offset; + if (col >= 0 && col <= curwin->text_maxcol) + break; + curwksp->offset = cline_len - 1 - curwin->text_maxcol + defroffset; + if (curwksp->offset < 0) + curwksp->offset = 0; + drawlines(0, curwin->text_maxrow); + clineno = -1; + getlin(curwksp->topline + lin); + col = cline_len - 1 - curwksp->offset; + break; + case CCRETURN: /* return */ + col = 0; + /* fall through... */ + case CCMOVEDOWN: /* move down 1 line */ + if (lin < curwin->text_maxrow) + ++lin; + else { + putline(); + lin += curwksp->topline + 1; + wksp_forward(curwin->text_maxrow / 2); + lin -= curwksp->topline; + } + break; + case CCMOVEUP: /* move up 1 line */ + if (lin > 0) + --lin; + else if (curwksp->topline > 0) { + putline(); + lin += curwksp->topline - 1; + wksp_forward(- curwin->text_maxrow / 2); + lin -= curwksp->topline; + } + break; + case CCMOVERIGHT: /* move forward */ + ++col; + break; + case CCTAB: /* tab */ + col += curwksp->offset; + col = (col + 4) & ~3; + col -= curwksp->offset; + break; + case CCPGDOWN: + putline(); + wksp_forward(curwin->text_maxrow); + lin = cursorline; + break; + case CCPGUP: + putline(); + wksp_forward(- curwin->text_maxrow); + lin = cursorline; + break; + } + if (col > curwin->text_maxcol) { + curwksp->offset += defroffset; + col -= defroffset; + drawlines(0, curwin->text_maxrow); + clineno = -1; + } else if (col < 0) { + curwksp->offset -= defloffset - col; + col = defloffset; + if (curwksp->offset < 0) { + col += curwksp->offset; + curwksp->offset = 0; + } + drawlines(0, curwin->text_maxrow); + clineno = -1; + } + + if (lin < 0) + lin = 0; + else if (lin > curwin->text_maxrow) + lin = curwin->text_maxrow; + + poscursor(col, lin); +} + +/* + * Put a symbol to current position. + * When flag=1, count it to line size. + */ +void wputc(j, flg) + int j, flg; +{ + if (flg && keysym != ' ') { + if (curwin->firstcol[cursorline] > cursorcol) + curwin->firstcol[cursorline] = cursorcol; + if (curwin->lastcol[cursorline] <= cursorcol) + curwin->lastcol[cursorline] = cursorcol + 1; + } + ++cursorcol; + if (curwin->text_col + cursorcol >= NCOLS) + cursorcol = - curwin->text_col; + putch(j); + if (cursorcol <= 0) + poscursor(0, + cursorline < 0 ? 0 : + cursorline > curwin->text_maxrow ? 0 : + cursorline); + movecursor(0); +} + +/* + * Get a "Cmd:" parameter. + * On return, param_type contains a type of entered parameter: + * 0 -- no value entered. + * -1 -- text area defined. Coordinates of top left corner are saved in + * param_c0, param_r0, bottom right corner - in param_c1, param_r1. + * 1 -- string value. Allocated string is in param_str, + * length in param_len. Old value of param_str is deallocated + * on a next call. + */ +char *param() +{ + register char *c1; + char *cp, *c2; + int c, ccol, cline, old_offset, old_topline; + register int i, pn; + window_t *w; +#define LPARAM 20 /* length increment */ + + if (param_len != 0 && param_str != 0) + free(param_str); + param_c1 = param_c0 = cursorcol + curwksp->offset; + param_r1 = param_r0 = cursorline + curwksp->topline; + wputc(COCURS, 1); + poscursor(cursorcol, cursorline); + w = curwin; + old_topline = curwksp->topline; + old_offset = curwksp->offset; +back: + telluser("Cmd: ", 0); + win_switch(¶mwin); + poscursor(5, 0); + do { + keysym = -1; + getkeysym(); + } while (keysym == CCBACKSPACE); + + if (MOVECMD(keysym)) { + telluser("*** Area defined by cursor ***", 0); + win_switch(w); + poscursor(param_c0 - curwksp->offset, param_r0 - curwksp->topline); +t0: + while (MOVECMD(keysym)) { + movecursor(keysym); + if (cursorline + curwksp->topline == param_r0 && + cursorcol + curwksp->offset == param_c0) + goto back; + keysym = -1; + getkeysym(); + } + if (! CTRLCHAR(keysym) || keysym == CCBACKSPACE) { + error("Printing character illegal here"); + keysym = -1; + getkeysym(); + goto t0; + } + if (cursorcol + curwksp->offset > param_c0) + param_c1 = cursorcol + curwksp->offset; + else + param_c0 = cursorcol + curwksp->offset; + if (cursorline + curwksp->topline > param_r0) + param_r1 = cursorline + curwksp->topline; + else + param_r0 = cursorline + curwksp->topline; + param_len = 0; + param_str = NULL; + param_type = -1; + + } else if (CTRLCHAR(keysym)) { + param_len = 0; + param_str = NULL; + param_type = 0; + } else { + param_len = pn = 0; +loop: + c = getkeysym(); + if (pn >= param_len) { + cp = param_str; + param_str = salloc(param_len + LPARAM + 1); /* 1 for int_to_ext */ + c1 = param_str; + c2 = cp; + for (i=0; itopline; + ccol = param_c0 - curwksp->offset; + if (cline >= curwin->text_row && cline <= curwin->text_maxrow && + ccol >= curwin->text_col && ccol <= curwin->text_maxcol) { + drawlines(cline, cline); + } else { + curwksp->topline = old_topline; + curwksp->offset = old_offset; + cline = param_r0 - curwksp->topline; + ccol = param_c0 - curwksp->offset; + drawlines(0, curwin->text_maxrow); + } + poscursor(ccol, cline); + return (param_str); +} + +/* + * Draw borders for a window. + * When vertf, draw a vertical borders. + */ +void win_borders(win, vertf) + register window_t *win; + int vertf; +{ +#if MULTIWIN + register int i; + + win_switch(&wholescreen); + if (win->base_row != win->text_row) { + poscursor(win->base_col, win->base_row); + for (i = win->base_col; i <= win->max_col; i++) + wputc(TMCH, 0); + } + if (vertf) { + int j; + for (j = win->base_row + 1; j <= win->max_row - 1; j++) { + int c = win->leftbar[j - win->base_row - 1]; + if (c != 0) { + poscursor(win->base_col, j); + wputc(c, 0); + poscursor(win->max_col, j); + wputc(win->rightbar[j - win->base_row - 1], 0); + } + } + } + if (win->base_row != win->text_row) { + poscursor(win->base_col, win->max_row); + for (i = win->base_col; i <= win->max_col; i++) + wputc(BMCH, 0); + } + /* poscursor(win->base_col + 1, win->base_row + 1); */ +#endif + win_switch(win); +} + +/* + * Display error message. + */ +void error(msg) + char *msg; +{ + putch(COBELL); + telluser("**** ", 0); + telluser(msg, 5); + message_displayed = 1; +} + +/* + * Display a message from column col. + * When col=0 - clear the arg area. + */ +void telluser(msg, col) + char *msg; + int col; +{ + window_t *oldwin; + register int c, l; + + oldwin = curwin; + c = cursorcol; + l = cursorline; + win_switch(¶mwin); + if (col == 0) { + poscursor(0, 0); + putblanks(paramwin.text_maxcol); + } + poscursor(col, 0); + /* while (*msg) wputc(*msg++, 0); */ + wputs(msg, PARAMWIDTH); + win_switch(oldwin); + poscursor(c, l); + dumpcbuf(); +} + +/* + * Redraw a screen. + */ +void redisplay() +{ + register int i; + int j; + register window_t *curp, *curp0 = curwin; + int col = cursorcol, lin = cursorline; + + /* Center the current line. */ + i = curwin->text_maxrow / 2; + if (lin < i && curwksp->topline > i - lin) { + curwksp->topline -= i - lin; + lin = i; + } else if (lin > i) { + j = file[curfile].nlines - curwin->text_maxrow; + if (curwksp->topline < j) { + curwksp->topline += lin - i; + lin = i; + if (curwksp->topline > j) { + lin += curwksp->topline - j; + curwksp->topline = j; + } + } + } + win_switch(&wholescreen); + cursorcol = cursorline = 0; + putch(COFIN); + putch(COSTART); + putch(COHO); + for (j=0; jtext_maxrow+1; i++) { + curp->firstcol[i] = 0; + curp->lastcol[i] = 0; /* curwin->text_maxcol;*/ + curp->leftbar[i] = ' '; + curp->rightbar[i] = ' '; + } + win_borders(curp, 0); + drawlines(0, curp->text_maxrow); + } + win_switch(curp0); + poscursor(col, lin); +} + +/* + * Put a string, limited by column. + */ +void wputs(ss, ml) + char *ss; + int ml; +{ + register char *s = ss; + + while (*s && cursorcol < ml) + wputc(*s++, 0); +} diff --git a/src/cmd/re/r.edit.c b/src/cmd/re/r.edit.c new file mode 100644 index 0000000..3c5bf8a --- /dev/null +++ b/src/cmd/re/r.edit.c @@ -0,0 +1,1380 @@ +/* + * Functions for manipulating file contents. + * + * RED editor for OS DEMOS + * Alex P. Roudnev, Moscow, KIAE, 1984 + */ +#include "r.defs.h" +#include +#include + +#define NBYMAX 150 /* Max size for segment data, +1 */ + +/* + * Setup for a file read routine. + */ +#define CHARBUFSZ 512 + +static int file_desc; /* Input file descriptor */ +static int file_offset; /* Position of next read from file_desc */ +static char read_buf[CHARBUFSZ]; +static int buf_count; /* Number of valid bytes in read_buf */ +static int buf_next; /* Next unread index in read_buf */ +static int cline_read_offset; /* Offset of next unread symbol */ + +/* + * Setup for a cline_read routine to read a given file starting + * from a given offset. + */ +static void cline_setup(fi, offset) + int fi, offset; +{ + if (fi <= 0) { + file_desc = fi; + return; + } + if (file_desc == fi && offset <= file_offset && + offset >= file_offset - buf_count) + { + /* New offset is inside the last buffer. */ + buf_next = buf_count + offset - file_offset; + } else { + lseek(fi, (off_t) offset, 0); + file_offset = offset; + buf_next = 0; + buf_count = 0; + } + cline_len = 0; + file_desc = fi; + cline_read_offset = file_offset + buf_next - buf_count; +} + +/* + * Convert a line from external to internal form. + * *si - current input symbol + * *(se-1) - previous input symbol + * *so - current place in output string + * no - current column on output, +1 (1 when empty) + * mo - max resulting column number + * + * Return value: + * 0 - end of line + * 1 - end of input string + * 2 - overflow of the output line + */ +static int ext_to_int(si, se, so, no, mo) + char **si, *se, **so; + int *no, mo; +{ + register char *st, *sf; + register unsigned sy; + int s1, n, i; + int ir = 0; + + sf = *si; + st = *so; + /*==== se +=1; ====*/ + n = *no; + /* main loop */ + while ((sy = *sf) != '\n' && sf != se) { + if (n+2 > mo) { + ir = 2; + break; + } + if (sy == '\11') { + /* Expand tabs to 4 spaces. */ + i = (n + 4) & ~3; + if (i > mo) { + ir = 2; + break; + } + for (; n mo) { + ir = 2; + break; + } + *st++ = COCURS; + *st++ = ((sy >> 6) & 3) + '0'; + *st++ = ((sy >> 3) & 7) + '0'; + *st++ = (sy & 7) + '0'; + n += 4; + goto next; + } + } + *st++ = sy; + n++; +next: + sf++; + } + if (ir == 0) { + if (sy == '\n') + sf++; + else + ir = 1; + } + *si = sf; + *so = st; + *no = n; + *st = 0; + return ir; +} + +/* + * Main function for reading next line from file. + * Controlled by global variables file_desc and file_offset. + * Returns a last symbol or -1 on EOF. + * When parameter fill_cline is nonzero, a buffer "cline" is filled with data. + * Length of a line (including trailing \n) is returned in cline_len. + * Last byte is \n, or -1 on EOF. + * + * Line is converted from external to internal format. + * Tabs are expanded, non-printing characters converted to pair of bytes. + * To convert it back, use int_to_ext() function. + * + * When parameter fill_cline is zero, cline is not allocated. + * This mode is used to build a descriptor chain. + */ +int cline_read(fill_cline) + int fill_cline; +{ + register char *c, *se; + register int ko; + char *si, *so; + + if (file_desc <= 0) { + if (cline_max == 0) + cline_expand(1); + cline_len = 1; + cline[0] = '\n'; + return ('\n'); + } + if (! cline) + cline_expand(0); + so = cline; + ko = (buf_next >= buf_count) ? 1 : 2; + do { + if (ko == 1) { + buf_next = 0; + buf_count = read(file_desc, read_buf, CHARBUFSZ); + if (buf_count < 0) { + error("Read Error"); + buf_count = 0; + } + file_offset += buf_count; + } + if (buf_count <= buf_next) { + ko = 1; + break; + } /* read buf empty */ + + si = read_buf + buf_next; + se = read_buf + buf_count; + if (! fill_cline) { + c = si; + while (*c++ != '\n' && c != se); + buf_next = c - read_buf; + ko = (*(c-1) == '\n') ? 0 : 1; + continue; + } + while (! cline_max || (ko = ext_to_int(&si, se, &so, &cline_len, cline_max)) == 2) { + cline_len = so - cline; + cline_expand(0); + so = cline + cline_len; + } + buf_next = si - read_buf; + } while (ko); + + /* ko=0 - '\n', 1 - end of file */ + cline_read_offset = file_offset + buf_next - buf_count; + if (ko == 1) + file_desc = 0; + + /* Remove trailing spaces. */ + if (fill_cline && so) { + *so = ' '; + c = so; + while (*c == ' ' && c-- != cline); + *++c = '\n'; + cline_len = (c - cline) + 1; + } + return ko ? -1 : '\n'; +} + +/* + * Scan a file and create a segment chain. + * Works from a current offset in the file. + */ +static segment_t *fdesc2segm(chan) + int chan; +{ + register segment_t *thissegm = 0, *lastsegm = 0; + segment_t *firstsegm = 0; + register int nby = 0; + char *bpt; + int c; + char fby [NBYMAX+1]; + int i, lct, nl = 0, sl, kl; + + c = -2; + sl = 0; + for (;;) { + /* Here c is a next symbol: -1 designates EOF, -2 - enter a loop + */ + if ((c < 0) || nby >= NBYMAX || nl == FSDMAXL) { + if (c != -2) { + lastsegm = thissegm; + thissegm = (segment_t *)salloc(nby + sizeof_segment_t); + if (firstsegm == 0) + firstsegm = thissegm; + else + lastsegm->next = thissegm; + thissegm->prev = lastsegm; + thissegm->next = 0; + thissegm->nlines = nl; + file[chan].nlines += nl; + thissegm->fdesc = chan; + thissegm->seek = sl; + bpt = &(thissegm->data); + for (i=0; inext = lastsegm = (segment_t*) salloc(sizeof_segment_t); + lastsegm->prev = thissegm; + return (firstsegm); + } + sl = cline_read_offset; + nl = nby = lct = 0; + } + kl = cline_read_offset; + c = cline_read(0); + lct = cline_read_offset - kl; + if (c != -1 || lct) { + if (lct > 127) { + fby[nby++] = (lct / 128) | 0200; + lct = lct % 128; + } + fby[nby++] = lct; + ++nl; + } + } +} + +/* + * Create a file descriptor list for a file. + */ +segment_t *file2segm(fd) + int fd; +{ + cline_setup(fd, 0); + return fdesc2segm(fd); +} + +/* + * Conversion of a line from internal to external form, + * performed right in place. + * Line should contain at least nbytes+1 symbols. + * Returns a length of resulting string. + * Tail spaces are stripped. + */ +int int_to_ext(line, nbytes) + char *line; + int nbytes; +{ + register char *fm,*to; /* pointers for move */ + register unsigned cc; /* current character */ + int lnb; /* 1 + last non-blank col */ + int cn; /* col number */ + int i, j; + + line[nbytes] = '\n'; + fm = to = line; + cn = -1; + lnb = 0; + while ((cc = *fm++) != '\n') { + cn++; + if (cc != ' ') { + while (++lnb <= cn) + *to++ = ' '; + /* decode non-printing symbols */ + if (cc == COCURS) { + if (*fm >= '@' || (unsigned)*fm > 0200) { + *to++ = *fm++ & 037; + continue; + } + if (*fm == '#') { + *to++ = '\177'; + fm++; + continue; + } + /* XXX */ + i = 0; + j = 0; + while (j++ <3 && (*fm >= '0' && *fm <= '7')) + i = (i<<3) + (*fm++ - '0'); + *to++ = i & 0377; + continue; + } + *to++ = cc; + } /* while - continue - not skip */ + } + *to++ = '\n'; + return (to - line); +} + +/* + * Expand a cline array to contain at least a given number of bytes. + * cline contains an allocated string; + * cline_max is an allocated length. + */ +void cline_expand(minbytes) + int minbytes; +{ + register int nbytes; + register char *buf; + + nbytes = cline_max + cline_incr; + if (nbytes < minbytes) + nbytes = minbytes; + buf = salloc(nbytes + 1); + cline_incr += cline_incr >> 1; + if (cline != 0) { + memcpy (buf, cline, cline_max); + free(cline); + } + cline = buf; + cline_max = nbytes; +} + +/* + * Insert n spaces into cline at position col. + */ +void putbks(col, n) + int col, n; +{ + register int i; + + if (n <= 0) + return; + if (col > cline_len-1) { + n += col - (cline_len-1); + col = cline_len-1; + } + if (cline_max <= (cline_len += n)) + cline_expand(cline_len); + for (i = cline_len - (n + 1); i >= col; i--) + cline[i + n] = cline[i]; + for (i = col + n - 1; i >= col; i--) + cline[i] = ' '; +} + +/* + * Setup a file and offset to get a line nlo from workspace wksp. + * After this call, a function cline_read(0) will fetch the needed line. + * Return 0 when done, 1 when no such line. + */ +int wksp_seek(wksp, lno) + workspace_t *wksp; + int lno; +{ + register char *cp; + int i; + register int j, seek; + + /* Get a needed segment. */ + if (wksp_position(wksp, lno)) + return (1); + + /* Now compute the offset. */ + seek = wksp->cursegm->seek; + i = lno - wksp->segmline; + cp = &(wksp->cursegm->data); + while (i-- != 0) { + if ((j = *(cp++)) & 0200) { + seek += 128*(j&0177); + j = *(cp++); + } + seek += j; + } + cline_setup(wksp->cursegm->fdesc, seek); + return (0); +} + +/* + * Set workspace position to segm with given line. + */ +int wksp_position(wk,lno) + workspace_t *wk; + int lno; +{ + register workspace_t *wksp; + + wksp = wk; + if (lno < 0) + fatal("Wposit neg arg"); + while (lno >= (wksp->segmline + wksp->cursegm->nlines)) { + if (wksp->cursegm->fdesc == 0) { + wksp->line = wksp->segmline; + return (1); + } + wksp->segmline += wksp->cursegm->nlines; + wksp->cursegm = wksp->cursegm->next; + } + while (lno < wksp->segmline) { + if ((wksp->cursegm = wksp->cursegm->prev) == 0) + fatal("Wposit 0 prev"); + wksp->segmline -= wksp->cursegm->nlines; + } + if (wksp->segmline < 0) fatal("WPOSIT LINE CT LOST"); + wksp->line = lno; + return 0; +} + +/* + * Switch to alternative file. + */ +void switchfile() +{ + if (curwin->altwksp->wfile == 0) { + if (editfile(deffile, 0, 0, 0, 1) <= 0) + error("Cannot open help file."); + return; + } + wksp_switch(); + drawlines(0, curwin->text_maxrow); + poscursor(curwksp->cursorcol, curwksp->cursorrow); +} + +/* + * Switch to alternative workspace. + */ +void wksp_switch() +{ + register workspace_t *oldwksp; + + curwksp->cursorcol = cursorcol; + curwksp->cursorrow = cursorline; + + oldwksp = curwksp; + curwksp = curwin->altwksp; + curfile = curwksp->wfile; + + curwin->wksp = curwksp; + curwin->altwksp = oldwksp; +} + +/* + * Create a segment with n empty lines. + */ +static segment_t *blanklines(n) + int n; +{ + int i; + register segment_t *f,*g; + register char *c; + + f = (segment_t *)salloc(sizeof_segment_t); + while (n) { + i = n > FSDMAXL ? FSDMAXL : n; + g = (segment_t *)salloc(sizeof_segment_t + i); + g->next = f; + f->prev = g; + g->nlines = i; + g->fdesc = -1; + c = &g->data; + n -= i; + while (i--) + *c++ = 1; + f = g; + } + return (f); +} + +/* + * Split a segment by line n in workspace w. + * On return, w.line == segmline and cursegm points to the first line + * after the break (which can be a line from the tail block). + * Initial segm can keep some unused space. + * When applied to the end of file, the current position will be + * at the final segment. + * When the needed line is beyond the end of file, additional segments + * are appended (with fdesc == -1). + * When realloc_flag==1, the block is reallocated to free some space. + * WARNING: breaksegm can disrupt the validity of pointers in workspace. + * Recommended to call wksp_redraw(). + */ +static int breaksegm(w, n, realloc_flag) + workspace_t *w; + int n, realloc_flag; +{ + int nby, i, j, jj, k, lfb0; + register segment_t *f,*ff; + segment_t *fn; + register char *c; + char *cc; + off_t offs; + + DEBUGCHECK; + if (wksp_position(w, n)) { + f = w->cursegm; + ff = f->prev; + free((char *)f); + fn = blanklines(n - w->line); + w->cursegm = fn; + fn->prev = ff; + if (ff) + ff->next = fn; + else + file[w->wfile].chain = fn; + wksp_position(w, n); + return (1); + } + f = w->cursegm; + cc = c = &f->data; + offs = 0; + ff = f; + nby = n - w->segmline; + if (nby != 0) { + /* get down to the nth line */ + for (i=0; i nlines - nby; /* number of lines in new segm */ + lfb0 = c - cc; + cc = c; + while (--i >= 0) { + if (*cc++ < 0) { + j++; + cc++; + } + } + ff = (segment_t *)salloc(sizeof_segment_t + j); + ff->nlines = jj; + ff->fdesc = f->fdesc; + offs += f->seek; + ff->seek = offs; + cc = &ff->data; + for (k=0; knext = f->next)) + ff->next->prev = ff; + ff->prev = f; + f->next = ff; + f->nlines = nby; + if (realloc_flag && jj > 4 && f->prev) { + ff = (segment_t *)salloc(sizeof_segment_t+lfb0); + *ff = *f; + c = &(ff->data); + cc = &(f->data); + while (lfb0--) { + *c++ = *cc++; + } + ff->prev->next = ff->next->prev = ff; + free((char*) f); + f = ff; + ff = f->next; + } + } + w->cursegm = ff; + w->segmline = n; + DEBUGCHECK; + return (0); +} + +/* + * Try to merge several segments into one to save some space. + * Join w->cursegm->prev and w->cursegm, in case they are adjacent. + */ +static int catsegm(w) + workspace_t *w; +{ + register segment_t *f0, *f; + segment_t *f2; + register char *c; + char *cc; + int i, j, l0=0, l1=0, lb0=0, lb1, dl, nl0, nl1, fd0, kod = 0; + /* l0, l1: byte count in a file area, described by f0, f; + * lb0, lb1: length of data in segm; + * nl0, nl1: number of lines in segm */ + + f = w->cursegm; + if ((f0 = f->prev) == 0) { + file[w->wfile].chain = f; + return(0); + } + f0->next = f; + fd0 = f0->fdesc; + nl0 = f0->nlines; + while (fd0>0 && fd0==f->fdesc && (nl0+(nl1=f->nlines)< FSDMAXL)) { + dl = f->seek - f0->seek; + /* Compute the block length, if unknown */ + if (l0 == 0) { + i = nl0; + cc = c = &f0->data; + while(i--) { + if ((j = *c++) & 0200) + j = (j & 0177) * 128 + *c++; + l0 += j; + } + lb0 = c - cc; + } + if (dl != l0) + return(kod); + /* Merge two segments and try to repeat */ + i = nl1; + cc = c = &(f0->data); + while (i--) { + if ((j = *c++) & 0200) + j = (j & 0177) * 128 + *c++; + l1 += j; + } + lb1 = c - cc; + f2 = f; + f = (segment_t*) salloc(sizeof_segment_t + lb0 + lb1); + *f = *f0; + f->next = f2->next; + w->cursegm = f; + w->segmline -= nl0; + nl0 = f->nlines = nl0 + nl1; + c = &(f->data); + i =lb0; + cc = &(f0->data); + while (i--) + *c++ = *cc++; + i = lb1; + cc = &(f2->data); + while (i--) + *c++ = *cc++; + lb0 += lb1; + l0 += l1; + kod = 1; + free((char *)f2); + free((char *)f0); + f->next->prev = f; + f0 = f->prev; + if (f0) + f0->next = f; + else + file[w->wfile].chain = f; + f0 = f; + f = f0->next; + } + return(kod); +} + +/* + * Insert a segment f into file, described by wksp, before the line at. + * The calling routine should call wksp_redraw() with needed args. + */ +static void insert(wksp, f, at) + workspace_t *wksp; + segment_t *f; + int at; +{ + register segment_t *w0, *wf, *ff; + + DEBUGCHECK; + ff = f; + while (ff->next->fdesc) { + ff = ff->next; + } + breaksegm(wksp, at, 1); + wf = wksp->cursegm; + w0 = wf->prev; + free((char *)ff->next); + ff->next = wf; + wf->prev = ff; + f->prev = w0; + wksp->cursegm = f; + wksp->line = wksp->segmline = at; + if (file[wksp->wfile].writable) + file[wksp->wfile].writable = EDITED; + catsegm(wksp); + DEBUGCHECK; +} + +/* + * Insert lines. + */ +void insertlines(from, number) + int from, number; +{ + if (from >= file[curfile].nlines) + return; + file[curfile].nlines += number; + insert(curwksp, blanklines(number), from); + wksp_redraw((workspace_t *)NULL, curfile, + from, from + number - 1, number); + poscursor(cursorcol, from - curwksp->topline); +} + +/* + * Insert spaces. + */ +void openspaces(line, col, number, nl) + int line, col, number, nl; +{ + register int i, j; + + for (i=line; itopline; + if (j <= curwin->text_maxrow) + drawlines(j, j); + } + poscursor(col - curwksp->offset, line - curwksp->topline); +} + +/* + * Append a line buf of length n to the temporary file. + * Return a segment for this line. + */ +static segment_t *writemp(buf, nbytes) + char *buf; + int nbytes; +{ + register segment_t *f1, *f2; + register char *p; + + if (file_desc == tempfile) + file_desc = 0; + lseek(tempfile, tempseek, 0); + + nbytes = int_to_ext(buf, nbytes-1); + if (write(tempfile, buf, nbytes) != nbytes) + return 0; + + /* now make segm */ + f1 = (segment_t *)salloc(2 + sizeof_segment_t); + f2 = (segment_t *)salloc(sizeof_segment_t); + f2->prev = f1; + f1->next = f2; + f1->nlines = 1; + f1->fdesc = tempfile; + f1->seek = tempseek; + if (nbytes <= 127) + f1->data = nbytes; + else { + p = &f1->data; + *p++ = (nbytes / 128)|0200; + *p = nbytes % 128; + } + tempseek += nbytes; + return (f1); +} + +/* + * Split a line at col position. + */ +void splitline(line, col) + int line, col; +{ + register int nsave; + register char csave; + + if (line >= file[curfile].nlines) { + file[curfile].nlines++; + return; + } + getlin(line); + if (col >= cline_len - 1) + insertlines(line+1, 1); + else { + file[curfile].nlines++; + csave = cline[col]; + cline[col] = '\n'; + nsave = cline_len; + cline_len = col+1; + cline_modified = 1; + putline(); + cline[col] = csave; + insert(curwksp, writemp(cline+col, nsave-col), line+1); + wksp_redraw((workspace_t *)NULL, curfile, line, line+1, 1); + } + poscursor(col - curwksp->offset, line - curwksp->topline); +} + +/* + * Delete specified lines from the workspace. + * Returns a segment chain of the deleted lines, with tail segment appended. + * Needs wksp_redraw(). + */ +static segment_t *delete(wksp, from, to) + workspace_t *wksp; + int from, to; +{ + segment_t *w0; + register segment_t *wf,*f0,*ff; + breaksegm(wksp,to+1,1); + DEBUGCHECK; + wf = wksp->cursegm; + breaksegm(wksp,from,1); + f0 = wksp->cursegm; + ff = wf->prev; + w0 = f0->prev; + wksp->cursegm = wf; + wf->prev = w0; + f0->prev = 0; + ff->next = (segment_t *) salloc(sizeof_segment_t); + ff->next->prev = ff; + catsegm(wksp); + file[wksp->wfile].writable = EDITED; + DEBUGCHECK; + return (f0); +} + +/* + * Delete lines from file. + * frum < 0 - do not call wksp_redraw (used for "exec"). + */ +void deletelines(frum, number) + int frum, number; +{ + register int n,from; + register segment_t *f; + + if ((from = frum) < 0) + from = -from-1; + if (from < file[curfile].nlines) + if ((file[curfile].nlines -= number) <= from) + file[curfile].nlines = from + 1; + f = delete(curwksp, from, from + number - 1); + if (frum >= 0) + wksp_redraw((workspace_t *)NULL, curfile, from, + from + number - 1, -number); + n = file[2].nlines; + insert(pickwksp, f, n); + wksp_redraw((workspace_t *)NULL, 2, n, n, number); + deletebuf->linenum = n; + deletebuf->nrows = number; + deletebuf->ncolumns = 0; + file[2].nlines += number; + poscursor(cursorcol, from - curwksp->topline); +} + +/* + * Pick (flg=0) / delete (flg=1). + */ +static void pcspaces(line, col, number, nl, flg) + int line, col, number, nl, flg; +{ + register segment_t *f1,*f2; + segment_t *f0; + char *linebuf, *bp; + register int i; + int j, n, line0, line1; + + if (file_desc == tempfile) + file_desc = 0; + linebuf = salloc(number+1); + f0 = f2 = 0; + line0 = line; + line1 = line0 + nl; + while ((nl = (line1 - line0)) != 0) { + if (nl > FSDMAXL) + nl = FSDMAXL; + f1 = (segment_t*) salloc(sizeof_segment_t + (number>127 ? nl*2 : nl)); + if (f2) { + f2->next = f1; + f1->prev = f2; + } else + f0 = f1; + bp = &(f1->data); + f1->nlines = nl; + f1->fdesc = tempfile; + f1->seek = tempseek; + for (j=line0; j= cline_len) { + if (col+number >= cline_max) + cline_expand(col+number+1); + for (i=cline_len-1; i 127) + *bp++ = (n/128) | 0200; + *bp++ = n % 128; + tempseek += n; + } + f2 = f1; + line0 = line0 + nl; + } + f2->next = (segment_t*) salloc(sizeof_segment_t); + f2->next->prev = f2; + nl = line1 - line; + if (flg) { + for (j=line; j= cline_len) { + if (col+number >= cline_max) + cline_expand(col+number+1); + for (i=cline_len-1; itopline; + if (i <= curwin->text_maxrow) + drawlines(i, i); + } + } + n = file[2].nlines; + insert(pickwksp, f0, n); + wksp_redraw((workspace_t *)NULL, 2, n, n, nl); + if (flg) { + deletebuf->linenum = n; + deletebuf->nrows = nl; + deletebuf->ncolumns = number; + } else { + pickbuf->linenum = n; + pickbuf->nrows = nl; + pickbuf->ncolumns = number; + } + file[2].nlines += nl; + free(linebuf); + poscursor(col - curwksp->offset, line - curwksp->topline); +} + +/* + * Delete rectangular area. + */ +void closespaces(line, col, number, nl) + int line, col, number, nl; +{ + pcspaces(line, col, number, nl, 1); +} + +/* + * Merge a line with next one. + */ +void combineline(line, col) + int line, col; +{ + register char *temp; + register int nsave, i; + + if (file[curfile].nlines > line+1) + file[curfile].nlines--; + else + file[curfile].nlines = line+1; + getlin(line+1); + temp = salloc(cline_len); + for (i=0; i cline_max) + cline_expand(col+nsave); + for (i=cline_len-1; ioffset, line - curwksp->topline); +} + +/* + * Returns a copy of segment subchain, from f to end, not including end. + * When end = NULL - up to the end of file. + */ +static segment_t *copysegm(f, end) + segment_t *f, *end; +{ + segment_t *res, *ff, *rend = 0; + register int i; + register char *c1, *c2; + + res = 0; + while (f->fdesc && f != end) { + c1 = &f->data; + for (i = f->nlines; i; i--) + if (*c1++ & 0200) + c1++; + c2 = (char*) f; /* !!! Count the size !!! */ + i = c1 - c2; + c2 = salloc(i); + ff = (segment_t*) c2; + c2 += i; + while (i--) + *--c2 = *--c1; + if (res) { + rend->next = ff; + ff->prev = rend; + rend = ff; + } else + res = rend = ff; + f = f->next; + } + if (res) { + rend->next = (segment_t *)salloc(sizeof_segment_t); + rend->next->prev = rend; + rend = rend->next; + } else + res = rend = (segment_t *)salloc(sizeof_segment_t); + + if (f->fdesc == 0) + rend->seek = f->seek; + return res; +} + +/* + * Returns a segment chain for the given lines, tail segment appended. + * Needs wksp_redraw. + */ +static segment_t *pick(wksp, from, to) + workspace_t *wksp; + int from, to; +{ + segment_t *wf; + + breaksegm(wksp, to+1, 1); + wf = wksp->cursegm; + breaksegm(wksp, from, 1); + return copysegm(wksp->cursegm, wf); +} + +/* + * Get lines from file to pick workspace. + */ +void picklines(from, number) + int from, number; +{ + register int n; + register segment_t *f; + + f = pick(curwksp, from, from + number - 1); + /* because of breaksegm */ + wksp_redraw((workspace_t *)NULL, curfile, from, from + number - 1, 0); + n = file[2].nlines; + insert(pickwksp, f, n); + wksp_redraw((workspace_t *)NULL, 2, n, n, number); + pickbuf->linenum = n; + pickbuf->nrows = number; + pickbuf->ncolumns = 0; + file[2].nlines += number; + poscursor(cursorcol, from - curwksp->topline); +} + +/* + * Get a rectangular area to pick buffer. + */ +void pickspaces(line, col, number, nl) + int line, col, number, nl; +{ + pcspaces(line, col, number, nl, 0); +} + +/* + * Paste lines from the clipboard before the specified line. + * (buf->ncolumns must be 0) + */ +static void plines(buf, line) + clipboard_t *buf; + int line; +{ + int lbuf, cc, cl; + segment_t *w0, *w1; + register segment_t *f, *g; + register int j; + + cc = cursorcol; + cl = cursorline; + breaksegm(pickwksp, buf->linenum + buf->nrows, 1); + w1 = pickwksp->cursegm; + breaksegm(pickwksp, buf->linenum, 1); + w0 = pickwksp->cursegm; + f = g = copysegm(w0, w1); + lbuf = 0; + while (g->fdesc) { + lbuf += g->nlines; + g = g->next; + } + insert(curwksp, f, line); + wksp_redraw((workspace_t *)NULL, curfile, line, line, lbuf); + poscursor(cc, cl); + if ((file[curfile].nlines += lbuf) <= (j = line + lbuf)) + file[curfile].nlines = j+1; +} + +/* + * Paste a block from clipboard to a specified line/col. + * (buf->ncolumns must be nonzero) + */ +static void pspaces(buf, line, col) + clipboard_t *buf; + int line, col; +{ + workspace_t *oldwksp; + char *linebuf; + int nc, i, j; + + linebuf = salloc(nc = buf->ncolumns); + oldwksp = curwksp; + for (i=0; inrows; i++) { + curwksp = pickwksp; + getlin(buf->linenum + i); + if (cline_len-1 < nc) + for (j=cline_len-1; jtopline; + if (j <= curwin->text_maxrow) + drawlines(j, j); + } + free(linebuf); + poscursor(col - curwksp->offset, line - curwksp->topline); +} + +/* + * Paste a text from clipboard to a specified place in a file. + * When buf->ncolumns == 0, lines are inserted, otherwise columns. + */ +void paste(buf, line, col) + clipboard_t *buf; + int line, col; +{ + if (buf->ncolumns == 0) + plines(buf, line); + else + pspaces(buf, line, col); +} + +/* + * Get a line from the current workspace. + * Line is stored in cline, length in cline_len. + */ +void getlin(ln) + int ln; +{ + cline_modified = 0; + clineno = ln; + if (wksp_seek(curwksp, ln)) { + if (cline_max == 0) + cline_expand(1); + cline[0] = '\n'; + cline_len = 1; + } else + cline_read(1); +} + +/* + * Store cline into the current workspace, at line number clineno. + */ +void putline() +{ + segment_t *w0,*cl; + register segment_t *wf, *wg; + register workspace_t *w; + int i; + char flg; + + DEBUGCHECK; + if (cline_modified == 0) { + clineno = -1; + return; + } + if (file[curfile].nlines <= clineno) + file[curfile].nlines = clineno + 1; + cline_modified = 0; + cline[cline_len-1] = '\n'; + cl = writemp(cline, cline_len); + w = curwin->wksp; /* w s can be replaced by curwksp */ + i = clineno; + flg = breaksegm(w,i,1); + wg = w->cursegm; + w0 = wg->prev; + if (flg == 0) { + breaksegm(w, i+1, 0); + wf = w->cursegm; + free((char *)cl->next); + cl->next = wf; + wf->prev = cl; + } + free((char *)wg); + cl->prev = w0; + w->cursegm = cl; + w->line = w->segmline = i; + file[w->wfile].writable = EDITED; + clineno = -1; + catsegm(w); + wksp_redraw(w, w->wfile, i, i, 0); + DEBUGCHECK; +} + +/* + * Free the segment chain. + */ +void freesegm(f) + segment_t *f; +{ + register segment_t *g; + + while (f) { + g = f; + f = f->next; + free((char *)g); + } +} + +/* + * Replace m lines from "line", via jproc pipe. + */ +void doreplace(line, m, jproc, pipef) + int line, m, jproc, *pipef; +{ + register segment_t *e, *ee; + register int l; + int n; + + close(pipef[0]); + breaksegm(curwksp, line, 0); + if (m == 0) + close(pipef[1]); + else { + m = segmwrite(curwksp->cursegm, m, pipef[1]); + if (m == -1) { + error("Can't write on pipe."); + kill(jproc, 9); + } + } + while (wait(&n) != jproc); /* wait for completion */ + if ((n & 0xFF00) == 0xDF00) { + error("Can't find the program to execute."); + return; + } + if ((n & 0xFF00) == 0xFE00 || (n & 0xFF) != 0) { + error("Abnormal termination of program."); + return; + } + file_desc = -1; /* forget old position before fork */ + if (m) + deletelines(-1-line,m); + cline_setup(tempfile, tempseek); + ee = fdesc2segm(tempfile); + tempseek = cline_read_offset; + l = 0; + if (ee->nlines) { + e = ee; + while (e->fdesc) { + l += e->nlines; + e = e->next; + } + insert(curwksp, ee, line); + file[curfile].nlines += l; + } + wksp_redraw((workspace_t *)NULL, curfile, line, line + m, l - m); + poscursor(cursorcol, cursorline); +} + +#ifdef DEBUG +/* + * Debug output of segm chains. + */ +void printsegm(f) + segment_t *f; +{ + int i; + register char *c; + + printf("\n**********"); + while (f) { + printf("\nsegmnl=%d chan=%d seek=%lu at %p", + f->nlines, f->fdesc, (long) f->seek, f); + if (f->next && f != f->next->prev) + printf("\n*** next block bad backpointer ***"); + c = &(f->data); + for (i=0; inlines; i++) { + if ((i % 20) == 0) + putchar('\n'); + printf(" %d", *c++); + } + f = f->next; + } +} + +/* + * Check segm correctness. + */ +void checksegm() +{ + register segment_t *f; + register int nl; + + nl = 0; + f = file[curfile].chain; + while (f) { + if (curwksp->line >= nl && + curwksp->line < nl + f->nlines && + curwksp->cursegm != f && curwksp->cursegm->prev) + fatal("CKFSD CURFSD LOST"); + + if (f->next && f->next->prev != f) + fatal("CKFSD BAD CHAIN"); + + nl += f->nlines; + f = f->next; + } +} +#endif diff --git a/src/cmd/re/r.file.c b/src/cmd/re/r.file.c new file mode 100644 index 0000000..6a18e13 --- /dev/null +++ b/src/cmd/re/r.file.c @@ -0,0 +1,302 @@ +/* + * Opening and saving files. + * + * RED editor for OS DEMOS + * Alex P. Roudnev, Moscow, KIAE, 1984 + */ +#include "r.defs.h" +#include + +/* + * Save a file from the channel n to a given filename. + * When filename is NULL, use the name from file[n].name. + * When no permission to write, ask to write to current directory. + */ +int savefile(filename, n) + char *filename; + int n; +{ + char *fname, *last_slash; + int newfd, dir_writable, need_backup = 1; + + /* Get the directory name. */ + if (filename) { + fname = filename; + } else { + fname = file[n].name; + if (file[n].backup_done) + need_backup = 0; + } + last_slash = strrchr (fname, '/'); + if (last_slash != 0) { + *last_slash = '\0'; + if (access(fname, F_OK) < 0) { + *last_slash = '/'; + error ("Directory does not exist."); + return(0); + } + dir_writable = (access(fname, R_OK | W_OK) == 0); + *last_slash = '/'; + } else { + dir_writable = (access(".", R_OK | W_OK) == 0); + } + + if (! dir_writable) { + if (filename) { + error ("Can't write to specified directory"); + return(0); + } + if (last_slash == 0) { + error ("Can't write to current directory"); + return(0); + } + telluser("Press ^N to save to current directory", 0); + keysym = -1; + need_backup = 1; + getkeysym(); + if (keysym != CCSETFILE) + return(-1); + if (access(".", R_OK | W_OK) < 0) { + error ("Can't write to current directory"); + return(0); + } + fname = last_slash + 1; /* points to file base name */ + } + + /* Open fname for write, make backup. */ + if (need_backup) { + char *backup = append (fname, "~"); + unlink(backup); + if (link(fname, backup) < 0 && errno != ENOENT) { + error ("Link failed!"); + free(backup); + return(0); + } + if (! filename) + file[n].backup_done = 1; + free(backup); + } + unlink(fname); + newfd = creat(fname, getpriv(n)); + if (newfd < 0) { + error ("Creat failed!"); + return(0); + } + /* chown(fname, userid); */ + + /* Copy the data. */ + telluser("save: ", 0); + telluser(fname, 6); + return segmwrite(file[n].chain, 0xfffff, newfd) == -1 ? 0 : 1; +} + +/* + * Write a segment chain into the file. + * When maxlines>0 - put only maxlines lines of text. + * When maxlines<0 - put only -maxlines paragraphs. + * Return a count of written lines, or -1 on error. + */ +int segmwrite(ff, maxlines, newf) + segment_t *ff; + int maxlines, newf; +{ + register segment_t *f; + register char *c; + register int i; + int j, k, bflag, tlines; + + if (cline_max < LBUFFER) + cline_expand(LBUFFER); + f = ff; + bflag = 1; + tlines = 0; + while (f->fdesc && maxlines) { + if (f->fdesc > 0) { + i = 0; + c = &f->data; + for (j=f->nlines; j; j--) { + if (maxlines < 0) { + /* Check the count of empty lines. */ + if (bflag && *c != 1) + bflag = 0; + else if (bflag == 0 && *c == 1) { + bflag = 1; + if (++maxlines == 0) + break; + } + } + if (*c & 0200) + i += 128 * (*c++ & 0177); + i += *c++; + ++tlines; + /* Check the line count. */ + if (maxlines > 0 && --maxlines == 0) + break; + } + lseek(f->fdesc, f->seek, 0); + while (i) { + j = (i < LBUFFER) ? i : LBUFFER; + if (read(f->fdesc, cline, j) < 0) + /* ignore errors */; + if (write(newf, cline, j) < 0) { + error("DANGER -- WRITE ERROR"); + close(newf); + return(-1); + } + i -= j; + } + } else { + j = f->nlines; + if (maxlines < 0) { + if (bflag == 0 && ++maxlines == 0) + j = 0; + bflag = 1; + } else { + if (j > maxlines) + j = maxlines; + maxlines -= j; + } + k = j; + while (k) + cline[--k] = '\n'; + if (j && write(newf, cline, j) < 0) { + error("DANGER -- WRITE ERROR"); + close(newf); + return(-1); + } + tlines += j; + } + f = f->next; + } + close(newf); + return tlines; +} + +/* + * Open the file for editing, starting from the given line and column. + * File is opened in the current window. When file does not exist, + * and mkflg==1, ask a user for a permission to create a file. + * Return -1, when the file was not opened and not created. + * When putflg==1, file is displayed on the screen. + */ +int editfile(filename, line, col, mkflg, puflg) + char *filename; + int line, col, mkflg, puflg; +{ + int i, j; + register int fn; + register char *c,*d; + + fn = -1; + for (i=0; i= 0) { + if (fn >= MAXFILES) { + error("Too many files -- editor limit!"); + close(fn); + return(0); + } + j = checkpriv(fn); + if (j == 0) { + error("File read protected."); + close(fn); + return(0); + } + file[fn].writable = (j == 2) ? 1 : 0; + telluser("Use: ",0); + telluser(filename, 5); + } else { + if (! mkflg) + return (-1); + telluser("Press ^N to create new file: ",0); + telluser(filename, 28); + keysym = -1; + getkeysym(); + if (keysym != CCSETFILE && keysym != 'Y' && keysym != 'y') + return(-1); + /* Find the directory. */ + for (c=d=filename; *c; c++) + if (*c == '/') + d = c; + if (d > filename) { + *d = '\0'; + i = open(filename, 0); + } else + i = open(".", 0); + + if (i < 0) { + error("Specified directory does not exist."); + return(0); + } + if (checkpriv(i) != 2) { + error("Can't write in:"); + telluser (filename, 21); + return(0); + } + close(i); + if (d > filename) + *d = '/'; + + /* Create file */ + fn = creat(filename, FILEMODE); + close(fn); + fn = open(filename, 0); + if (fn < 0) { + error("Create failed!"); + return(0); + } + if (fn >= MAXFILES) { + close(fn); + error("Too many files -- Editor limit!"); + return(0); + } + file[fn].writable = 1; + if (chown(filename, userid, groupid) < 0) + /* ignore errors */; + } + param_len = 0; /* so its kept around */ + file[fn].name = filename; + } + /* Flush the output buffer, as here is a long operation. */ + dumpcbuf(); + wksp_switch(); + if (! file[fn].chain) + file[fn].chain = file2segm(fn); + curwksp->cursegm = file[fn].chain; + curfile = curwksp->wfile = fn; + curwksp->line = curwksp->segmline = 0; + curwksp->topline = line; + curwksp->offset = col; + if (puflg) { + drawlines(0, curwin->text_maxrow); + poscursor(0, 0); + } + return(1); +} + +/* + * End a session and write all. + * Return 0 on write error. + */ +int endit() +{ + register int i, ko = 1; + + for (i=0; i= 0) + return(tc); + c = tc; + while (*c != 0) { + if (*c == '?') { + optional = 1; + c++; + } else if (*c < ' ') { + *buftc++ = *c++; + continue; + } else + optional = 0; + name[0] = *c++; + name[1] = *c++; + name[2] = 0; + if (tgetstr(termcap, name, &buftc) == 0) { + /* not found */ + if (! optional) + return(0); + *buftc++ = 0; + } + buftc--; + } + *buftc++ = 0; + buftc = strdup (buftc0); +#ifdef TEST + printf("%s=", tc); + ptss(buftc); +#endif + return(buftc); +} + +/* + * Sort the keytab for the function findt(). + */ +static void itsort(fb, fe, ns) + keycode_t *fb,*fe; + int ns; +{ + register keycode_t *fr, *fw; + char c; + keycode_t temp; + + fw = fb - 1; + while (fw != fe) { + fr = fb = ++fw; + c = fw->value[ns]; + while (fr++ != fe) { + if (fr->value[ns] == c) { + if (fr != ++fw) { + temp = *fr; + *fr = *fw; + *fw = temp; + } + } + } + if (c != 0 && (fw - fb) > 1) + itsort(fb, fw, ns+1); + } +} + +/* + * Load termcap descriptions. + */ +void tcread() +{ + register int i; + register keycode_t *ir, *iw; + char *termcap; + + /* Terminal description is placed in TERMCAP variable. */ + termcap = getenv("TERMCAP"); + if (! termcap) { + /* Default: linux console. */ + termcap = ":co#80:li#25:cm=\33[%i%d;%dH:cl=\33[H\33[2J:ho=\33[H:" + "up=\33[A:do=\33[B:nd=\33[C:le=\10:cu=\33[7m@\33[m:" + "ku=\33[A:kd=\33[B:kr=\33[C:kl=\33[D:kP=\33[5~:kN=\33[6~:" + "kI=\33[2~:kD=\33[3~:kh=\33[1~:kH=\33[4~:" + "k1=\33[A:k2=\33[B:k3=\33[C:k4=\33[D:k5=\33[15~:" + "k6=\33[17~:k7=\33[18~:k8=\33[19~:k9=\33[20~:k0=\33[21~:" + "F1=\33[23~:F2=\33[24~:"; + } + curspos = gettcs(termcap, "cm"); + if (! curspos) { + puts1 ("re: terminal does not support direct positioning\n"); + exit(1); + } + NCOLS = tgetnum(termcap, "co"); + NLINES = tgetnum(termcap, "li"); + if (NCOLS <= 60 || NLINES < 8) { + puts1 ("re: too small screen size\n"); + exit(1); + } + if (NCOLS > MAXCOLS) + NCOLS = MAXCOLS; + if (NLINES > MAXLINES) + NLINES = MAXLINES; + for (i=0; ivalue; ir++) { + if (ir->value[0] > ' ') { + iw->value = gettcs(termcap, ir->value); + if (iw->value == 0) { + continue; + } + } else + iw->value = ir->value; + iw->keysym = ir->keysym; + iw++; + } + iw->value = NULL; + iw->keysym = 0; + itsort(keytab, iw-1, 0); +} diff --git a/src/cmd/re/r.macro.c b/src/cmd/re/r.macro.c new file mode 100644 index 0000000..44b5dca --- /dev/null +++ b/src/cmd/re/r.macro.c @@ -0,0 +1,190 @@ +/* + * Implementation of macro features. + * + * RED editor for OS DEMOS + * Alex P. Roudnev, Moscow, KIAE, 1984 + */ +#include "r.defs.h" + +/* + * Types of macros + * TAG - poition in file + * BUF - paste buffer + */ +#define MTAG 1 +#define MBUF 2 + +typedef struct { + int line, col, nfile; +} tag_t; + +typedef union { + clipboard_t mclipboard; + tag_t mtag; +} macro_t; + +#define NMACRO ('z'-'a'+1) + +static macro_t *mtab_data[NMACRO]; + +static char mtab_type[NMACRO]; + +/* + * Find a macro by name. + * When nbytes=0, it finds and checks a type. + * Otherwise, creates a new descriptor. + */ +static macro_t *mfind(name, typ, nbytes) + register char *name; + int typ, nbytes; +{ + register int i; + + i = ((*name | 040) & 0177) - 'a'; + if (i < 0 || i > 'z'-'a' || name[1] != 0) { + error("Invalid macro name"); + return 0; + } + if (nbytes == 0) { + /* Check the type of macro. */ + if (mtab_type[i] != typ) { + error (mtab_type[i] ? "Invalid type of macro" : "Macro undefined"); + return 0; + } + } else { + /* Reallocate. */ + if (mtab_data[i]) { + free(mtab_data[i]); + telluser("Macro redefined",0); + } + mtab_data[i] = (macro_t*) salloc(nbytes); + mtab_type[i] = typ; + } + return mtab_data[i]; +} + +/* + * Fetch a clipboard by name. + * Return 0 on error. + */ +int mfetch(cb, name) + register clipboard_t *cb; + register char *name; +{ + register macro_t *m; + + m = mfind(name, MBUF, 0); + if (! m) + return 0; + + *cb = m->mclipboard; + return 1; +} + +/* + * Store a clipboard by name. + */ +void mstore(cb, name) + register clipboard_t *cb; + register char *name; +{ + register macro_t *m; + + m = mfind(name, MBUF, sizeof(clipboard_t)); + if (m) + m->mclipboard = *cb; +} + +/* + * Save a current cursor position in a file under the given name. + * The deficiency is that the tag is not linked to a file + * and moves when lines are inserted or deleted. + */ +int msvtag(name) + register char *name; +{ + register macro_t *m; + register workspace_t *cws; + + cws = curwksp; + m = mfind(name, MTAG, sizeof(tag_t)); + if (! m) + return 0; + m->mtag.line = cursorline + cws->topline; + m->mtag.col = cursorcol + cws->offset; + m->mtag.nfile = cws->wfile; + return 1; +} + +/* + * Return a cursor back to named position. + * cgoto is common for it and other functions. + */ +int mgotag(name) + char *name; +{ + register int i; + int fnew = 0; + register macro_t *m; + + m = mfind(name, MTAG, 0); + if (! m) + return 0; + i = m->mtag.nfile; + if (curwksp->wfile != i) { + editfile(file[i].name, 0, 0, 0, 0); + fnew = 1; + } + cgoto(m->mtag.line, m->mtag.col, -1, fnew); + highlight_position = 1; + return 1; +} + +/* + * Define the parameters, describing the text area between the current + * cursor and a given tag name. Param_type is set to -2. + */ +int mdeftag(name) + char *name; +{ + register macro_t *m; + register workspace_t *cws; + int cl, ln, f = 0; + + m = mfind(name, MTAG, 0); + if (! m) + return 0; + cws = curwksp; + if (m->mtag.nfile != cws->wfile) { + error("File mismatch"); + return(0); + } + param_type = -2; + param_r1 = m->mtag.line; + param_c1 = m->mtag.col ; + if (param_r0 > param_r1) { + f++; + ln = param_r1; + param_r1 = param_r0; + param_r0 = ln; + } else + ln = param_r0; + + if (param_c0 > param_c1) { + f++; + cl = param_c1; + param_c1 = param_c0; + param_c0 = cl; + } else + cl = param_c0; + if (f) { + cgoto(ln, cl, -1, 0); + } + if (param_r1 == param_r0) + telluser("*** Columns defined by tag ***", 0); + else if (param_c1 == param_c0) + telluser("*** Lines defined by tag ***", 0); + else + telluser("*** Square defined by tag ***", 0); + return 1; +} diff --git a/src/cmd/re/r.main.c b/src/cmd/re/r.main.c new file mode 100644 index 0000000..a2b2b6f --- /dev/null +++ b/src/cmd/re/r.main.c @@ -0,0 +1,466 @@ +/* + * Main program: enter/exit, open windows, parse options. + * + * Usage: + * re file [line-number] - Open file + * or + * re - Open last edited file + * or + * re - - Replay last session after crash + * + * RED editor for OS DEMOS + * Alex P. Roudnev, Moscow, KIAE, 1984 + */ +#include "r.defs.h" +#include +#include + +int keysym = -1; /* -1 when the symbol already processed */ + +/* + * Parameters for file scrolling. + */ +int defplline = 10; /* +LINE */ +int defmiline = 10; /* -LINE */ +int defloffset = 24; /* LEFT OFFSET */ +int defroffset = 24; /* RIGHT OFFSET */ + +char deffile[] = "/share/re.help"; /* Help file */ + +/* Initial values. */ +int cline_max = 0; +int cline_incr = 20; /* Increment for line expand */ +int clineno = -1; +char cline_modified = 0; + +int journal = -1; /* File descriptor for a journal */ +int inputfile = 0; /* Journal or stdin */ + +int oldttmode; /* Saved access mode of /dev/tty */ + +static char *ttynm, *jname, *rfile; +static clipboard_t pb, db; + +static void checksig(int); + +/* + * Fatal signal catched. + */ +void fatalsig(n) + int n; +{ + fatal("Fatal signal"); +} + +/* + * Ignore signals ^C and ^\ + */ +static void ignsig(n) + int n; +{ + signal(SIGQUIT, ignsig); + signal(SIGINT, checksig); +} + +/* + * On first ^C from a user - set intrflag. + * On second ^C - abort the editor session. + */ +static void checksig(n) + int n; +{ + signal(SIGINT, ignsig); + if (intrflag) + fatal("RE WAS INTERRUPTED\n"); + ignsig(0); + intrflag = 1; +} + +/* + * Initialize modes and files. + * 0 - start a new session + * 1 - restore a previous session + * 2 - replay the session from a journal + */ +static void startup(restart) + int restart; +{ + register int i; + register char *c, *name; + + if (nice(-10) < 0) + /* ignore errors */; + userid = getuid(); + groupid = getgid(); + setuid(userid); + setgid(groupid); + name = getenv("USER"); + if (! name) + name = getnm(userid); + ttynm = ttyname(0); + if (! ttynm) + ttynm = "nottyno\0\0"; + c = ttynm + strlen (ttynm) - 2; + if (*c == '/') + *c = '-'; + tmpname = append(append("/tmp/ret", c), name); + jname = append(append("/tmp/rej", c), name); + rfile = append(append("/tmp/res", c), name); + if (restart) { + journal = open(jname, 2); + if (journal >= 0 && restart != 2) + close(journal); + } + if (restart != 2) { + unlink(jname); + journal = creat(jname, FILEMODE); + } else + inputfile = journal; + if (journal < 0) { + puts1("can't open journal.\n"); + exit(1); + } + unlink(tmpname); + i = creat(tmpname, 0600); + if (i < 0) { + puts1("Can't open temporary file.\n"); + exit(1); + } + /* Temporary file should be rd/wr, need to reopen. */ + close(i); + i = open(tmpname, 2); + file[i].name = tmpname; + file[i].writable = 1; + tempfile = i; + /* Pseudo-file '#' - store all deleted and copied/pasted. */ + file[2].name = "#"; + file[2].nlines = 0; + pickwksp = (workspace_t*) salloc(sizeof(workspace_t)); + pickwksp->cursegm = file[2].chain = (segment_t*) salloc(sizeof_segment_t); + pickwksp->wfile = 2; + pickbuf = &pb; + deletebuf = &db; + + /* Set tty modes. */ + ttstartup(); + + /* Setup a window for a whole screen. */ + win_create(&wholescreen, 0, NCOLS-1, 0, NLINES-1, 0); + + /* Setup a window for a Cmd line. */ + win_create(¶mwin, 0, NCOLS-1, NLINES-1, NLINES-1, 0); + paramwin.text_maxcol = PARAMWIDTH; + + /* Close the terminal from 'write' messages from other users. */ + oldttmode = getpriv(0); + chmod(ttynm, 0600); + + /* + * Catch signals. + */ + for (i=SIGTERM; i; i--) + signal(i, fatalsig); + signal(SIGINT, checksig); + signal(SIGQUIT, ignsig); + curwin = &wholescreen; + putch(COSTART); + putch(COHO); +} + +/* + * Make or restore window state. + * '!' - restore, ' ' - make new. + */ +static void getstate(init_flag) + char init_flag; +{ + int nletters, base_col, max_col, base_row, max_row, row, col, winnum, gf; + register int i, n; + register char *f1; + char *fname; + int gbuf; + window_t *win; + + if (init_flag != '!' || (gbuf = open(rfile, 0)) <= 0 || + (nwinlist = get1w(gbuf)) == -1) + { +make: /* Create initial window state. */ + nwinlist = 1; + win = (window_t*) salloc(sizeof(window_t)); + winlist[0] = win; + win_create(win, 0, NCOLS-1, 0, NLINES-2, MULTIWIN); + win_borders(win, 0); + poscursor(0, 0); + return; + } + winnum = get1w(gbuf); + for (n=0; nprevwinnum = get1w(gbuf); + base_col = get1w(gbuf); + max_col = get1w(gbuf); + base_row = get1w(gbuf); + max_row = get1w(gbuf); + win_create(win, base_col, max_col, base_row, max_row, MULTIWIN); + win_borders(win, 0); + gf = 0; + nletters = get1w(gbuf); + if (nletters != 0) { + f1 = fname = salloc(nletters); + do { + *f1 = get1c(gbuf); + } while (*f1++); + row = get1w(gbuf); + col = get1w(gbuf); + if (editfile(fname, row, col, 0, 0) == 1) + gf = 1; + curwksp->cursorcol = get1w(gbuf); + curwksp->cursorrow = get1w(gbuf); + poscursor(curwksp->cursorcol, curwksp->cursorrow); + } + nletters = get1w(gbuf); + if (nletters < 0) + goto make; + f1 = fname = salloc(nletters); + do { + *f1 = get1c(gbuf); + } while (*f1++); + row = get1w(gbuf); + col = get1w(gbuf); + if (editfile(fname, row, col, 0, (n != winnum)) == 1) + gf = 1; + curwksp->cursorcol = get1w(gbuf); + curwksp->cursorrow = get1w(gbuf); + if (gf == 0) { + if (editfile(deffile, 0, 0, 0, (n != winnum)) <= 0) + error("Cannot open help file."); + curwksp->cursorcol = curwksp->cursorrow = 0; + } + poscursor(curwksp->cursorcol, curwksp->cursorrow); + } + win_switch(winlist[winnum]); + poscursor(curwksp->cursorcol, curwksp->cursorrow); + if (nwinlist > 1) + for (i=0; i 0 && write(journal, str, len) != len) + /* ignore errors */; + if (write(journal, &code2, 1) != 1) + /* ignore errors */; +} + +/* + * Write state of windows, to restore session later. + */ +static void savestate() +{ + int i, nletters; + register int winnum; + register char *f1; + char *fname; + register window_t *win; + int sbuf; + + curwksp->cursorcol = cursorcol; + curwksp->cursorrow = cursorline; + unlink(rfile); + sbuf = creat(rfile, FILEMODE); + if (sbuf <= 0) + return; + put1w(nwinlist, sbuf); + for (winnum=0; winnum < nwinlist; winnum++) + if (winlist[winnum] == curwin) + break; + put1w(winnum, sbuf); + for (i=0; iprevwinnum, sbuf); + put1w(win->base_col, sbuf); + put1w(win->max_col, sbuf); + put1w(win->base_row, sbuf); + put1w(win->max_row, sbuf); + f1 = fname = file[win->altwksp->wfile].name; + if (f1) { + while (*f1++); + nletters = f1 - fname; + put1w(nletters, sbuf); + f1 = fname; + do { + put1c(*f1, sbuf); + } while (*f1++); + put1w(win->altwksp->topline, sbuf); + put1w(win->altwksp->offset, sbuf); + put1w(win->altwksp->cursorcol, sbuf); + put1w(win->altwksp->cursorrow, sbuf); + } else + put1w(0, sbuf); + + f1 = fname = file[win->wksp->wfile].name; + if (f1) { + while (*f1++); + nletters = f1 - fname; + put1w(nletters, sbuf); + f1 = fname; + do { + put1c(*f1, sbuf); + } while (*f1++); + put1w(win->wksp->topline, sbuf); + put1w(win->wksp->offset, sbuf); + put1w(win->wksp->cursorcol, sbuf); + put1w(win->wksp->cursorrow, sbuf); + } + } + close(sbuf); +} + +/* + * Main routine. + */ +int main(nargs, args) + int nargs; + char *args[]; +{ + int restart, i; + char *cp, init_flag = ' '; + + tcread(); + + /* Mode: 0 - normal, 1 - restart, 2 - from journal file /tmp/rej.. */ + restart = 0; + if (nargs == 1) { + restart = 1; + init_flag = '!'; + + } else if (*(cp = args[1]) == '-') { + if (*++cp) { + /* Journal file specified. */ + inputfile = open(cp, 0); + if (inputfile < 0) { + puts1("Can't open journal file.\n"); + return 1; + } + } else + restart = 2; + nargs = 1; + } + + startup(restart); + if (inputfile) { + if (read(inputfile, &init_flag, 1) <= 0) { + cleanup(); + puts1("Journal file is empty.\n"); + return 1; + } + } else { + /* For repeated session */ + if (write(journal, &init_flag, 1) != 1) + /* ignore errors */; + } + getstate(init_flag); + + if (nargs > 1 && *args[1] != '\0') { + i = defplline + 1; + if ((nargs > 2) && (s2i(args[2],&i) || i <= defplline+1)) + i = defplline+1; + poscursor(curwksp->cursorcol, curwksp->cursorrow); + writefile(CCPARAM, args[1], CCSETFILE); + if (editfile(args[1], i - defplline - 1, 0, 1, 1) <= 0) { + /* Failed to open file - use empty buffer. */ + drawlines(0, curwin->text_maxrow); + poscursor(curwksp->cursorcol, curwksp->cursorrow); + } else { + /* File opened. */ + if (nargs > 2 && i > 1) + writefile(CCPARAM, args[2], CCGOTO); + } + } else { + /* Saved session restored. */ + drawlines(0, curwin->text_maxrow); + poscursor(curwksp->cursorcol, curwksp->cursorrow); + } + telluser("", 0); + mainloop(); + putch(COFIN); + dumpcbuf(); + wputc('\n', 0); + cleanup(); + savestate(); /* Save a session. */ + dumpcbuf(); + return 0; +} + +/* + * Cleanup before exit. + */ +void cleanup() +{ + /* Restore tty mode and exit */ + ttcleanup(); + close(tempfile); + unlink(tmpname); + close(journal); + chmod(ttynm, 07777 & oldttmode); +} + +/* + * Print error message and exit. + */ +void fatal(s) + char *s; +{ + putch(COFIN); + putch(COBELL); + dumpcbuf(); + ttcleanup(); + puts1("\nFirst the bad news: editor just "); + if (s) { + puts1("died:\n"); + puts1(s); + } else + puts1("ran out of space.\n"); + puts1("\nNow the good news - your editing session can be reproduced\n"); + puts1("from file "); + puts1(jname); + puts1("\nUse command 're -' to do it.\n"); +#ifdef DEBUG + if (inputfile || ! isatty(1)) { + register int i; + register workspace_t *w; + + if (s) + printf("%s\n\n", s); + for (i = 0; i < MAXFILES; i++) + if (file[i].chain) { + printf("\n*** File[%d] = %s\n", i, file[i].name); + printsegm(file[i].chain); + } + for (i = 0; i < nwinlist; i++) { + w = winlist[i]->wksp; + printf("\nWindow #%d: chain %d, current line %d at block %p,\n", + i, w->wfile, w->line, w->cursegm); + printf(" first line %d, ulhc (%d,%d)\n", + w->segmline, w->offset, w->topline); + } + for (i=12; i; i--) + signal(i, 0); + } +#endif + close(journal); + exit(1); +} diff --git a/src/cmd/re/r.misc.c b/src/cmd/re/r.misc.c new file mode 100644 index 0000000..e36ceed --- /dev/null +++ b/src/cmd/re/r.misc.c @@ -0,0 +1,214 @@ +/* + * Miscellaneous functions. + * + * RED editor for OS DEMOS + * Alex P. Roudnev, Moscow, KIAE, 1984 + */ +#include "r.defs.h" +#include +#include + +/* + * Allocate zeroed memory. + * Always succeeds. + */ +char *salloc(n) + int n; +{ + register char *c; + + c = calloc(n, 1); + if (! c) + fatal(NULL); + return (c); +} + +/* + * Check access rights. + * Return 0 - no access; + * 1 - only read; + * 2 - read and write. + */ +int checkpriv(fildes) + int fildes; +{ + register struct stat *buf; + struct stat buffer; + int anum, num; + register int unum, gnum; + + if (userid == 0) + return 2; /* superuser accesses all */ + buf = &buffer; + fstat(fildes, buf); + unum = gnum = anum = 0; + if (buf->st_uid == userid) { + if (buf->st_mode & 0200) + unum = 2; + else if (buf->st_mode & 0400) + unum = 1; + } + if (buf->st_gid == groupid) { + if (buf->st_mode & 020) + gnum = 2; + else if (buf->st_mode & 040) + gnum = 1; + } + if (buf->st_mode & 02) + anum = 2; + else if (buf->st_mode & 04) + anum = 1; + num = (unum > gnum ? unum : gnum); + num = (num > anum ? num : anum); + return num; +} + +/* + * Get file access modes. + */ +int getpriv(fildes) + int fildes; +{ + struct stat buffer; + register struct stat *buf; + + buf = &buffer; + fstat(fildes,buf); + return (buf->st_mode & 0777); +} + +/* + * Write a string to stdout. + */ +void puts1(s) + char *s; +{ + register int len = strlen (s); + + if (len <= 0) + return; + if (write(1, s, len) != len) + /* ignore errors */; +} + +/* + * Append strings. + * Allocates memory. + */ +char *append(name, ext) + char *name, *ext; +{ + int lname; + register char *c, *d, *newname; + + lname = 0; + c = name; + while (*c++) + ++lname; + c = ext; + while (*c++) + ++lname; + newname = c = salloc(lname + 1); + d = name; + while (*d) + *c++ = *d++; + d = ext; + while ((*c++ = *d++) != 0); + return newname; +} + +/* + * Convert a string to number. Store result into *i. + * Return pointer to first symbol after a number, or 0 if none. + */ +char *s2i(s, i) + char *s; + int *i; +{ + register char lc, c; + register int val; + int sign; + char *ans; + + sign = 1; + val = lc = 0; + ans = 0; + while ((c = *s++) != 0) { + if (c >= '0' && c <= '9') val = 10*val + c - '0'; + else if (c == '-' && lc == 0) sign = -1; + else { + ans = --s; + break; + } + lc = c; + } + *i = val * sign; + return ans; +} + +/* + * Get user id as printable text. + */ +char *getnm(uid) + int uid; +{ +#define LNAME 8 + static char namewd[LNAME+1]; + register int i; + + i = LNAME; + namewd[LNAME]=0; + while (i > 1 && uid > 0) { + namewd[--i] = '0' + uid %10; + uid /= 10; + } + return &namewd[i]; +} + +/* + * Read word. + */ +int get1w(fd) + int fd; +{ + int i; + + if (read(fd, &i, sizeof(int)) != sizeof(int)) + return -1; + return i; +} + +/* + * Read byte. + */ +int get1c(fd) + int fd; +{ + char c; + + if (read(fd, &c, 1) == 1) + return (unsigned char) c; + return -1; +} + +/* + * Write word. + */ +void put1w(w, fd) + int fd, w; +{ + if (write(fd, &w, sizeof(int)) != sizeof(int)) + /* ignore errors */; +} + +/* + * Write byte. + */ +void put1c(c, fd) + int c, fd; +{ + char sym = c; + + if (write(fd, &sym, 1) != 1) + /* ignore errors */; +} diff --git a/src/cmd/re/r.termcap.c b/src/cmd/re/r.termcap.c new file mode 100644 index 0000000..856f441 --- /dev/null +++ b/src/cmd/re/r.termcap.c @@ -0,0 +1,248 @@ +/* + * Mini-variant of termcap library. + * + * RED editor for OS DEMOS + * Alex P. Roudnev, Moscow, KIAE, 1984 + */ +#include "r.defs.h" +#include + +/* + * 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. + */ +int tgetnum(bp, id) + register char *bp; + char *id; +{ + register int i, base; + + 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. + */ +int tgetflag(bp, id) + register char *bp; + char *id; +{ + 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); + } + } +} + +/* + * 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,jdelay=0; + while(*str>='0' && *str<='9') { + jdelay=jdelay*10+(*str++ - '0'); + } + 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; + } + if(jdelay>100) jdelay=100; + while(jdelay--) *cp++='\200'; + *cp++ = 0; + str = *area; + *area = cp; + return (str); +} + +/* + * 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(bp, id, area) + register char *bp; + char *id, **area; +{ + 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); + } +} + +/* + * Routine to perform cursor addressing. + * CM is a string containing printf type escapes to allow + * cursor addressing. We start out ready to print the destination + * line, and switch each time we print row or column. + * The following escapes are defined for substituting row/column: + * + * %d as in printf + * %2 like %2d + * %3 like %3d + * %. gives %c hacking special case characters + * %+x like %c but adding x first + * + * The codes below affect the state but don't use up a value. + * + * %r reverses row/column + * %i increments row/column (for one origin indexing) + * %% gives % + * + * all other characters are ``self-inserting''. + */ +char *tgoto(CM, destcol, destline) + char *CM; + int destcol, destline; +{ + static char result[16]; + static char added[10]; + char *cp = CM; + register char *dp = result; + register int c; + int oncol = 0; + register int which = destline; + + added[0] = 0; + while ((c = *cp++) != 0) { + if (c != '%') { + *dp++ = c; + continue; + } + switch (c = *cp++) { + case 'd': + if (which < 10) + goto one; + if (which < 100) + goto two; + /* fall into... */ + case '3': + *dp++ = (which / 100) | '0'; + which %= 100; + /* fall into... */ + case '2': +two: + *dp++ = which / 10 | '0'; +one: + *dp++ = which % 10 | '0'; +swap: + oncol = 1 - oncol; +setwhich: + which = oncol ? destcol : destline; + continue; + + case '+': + which += *cp++; + /* fall into... */ + case '.': + *dp++ = which; + goto swap; + + case 'r': + oncol = 1; + goto setwhich; + + case 'i': + destcol++; + destline++; + which++; + continue; + + case '%': + *dp++ = c; + continue; + + default: + return "OOPS"; + } + } + strcpy(dp, added); + return result; +} diff --git a/src/cmd/re/r.ttyio.c b/src/cmd/re/r.ttyio.c new file mode 100644 index 0000000..4fdd75d --- /dev/null +++ b/src/cmd/re/r.ttyio.c @@ -0,0 +1,419 @@ +/* + * Interface to display - physical level. + * Parsing escape sequences. + * + * RED editor for OS DEMOS + * Alex P. Roudnev, Moscow, KIAE, 1984 + */ +#include "r.defs.h" +#include + +#ifdef TERMIOS +#include + +#ifndef NCC +# define NCC NCCS +#endif + +static struct termios tioparam; + +#else /* TERMIOS */ + +static struct sgttyb templ; +static struct tchars tchars0; +static struct ltchars ltchars0; + +#endif /* TERMIOS */ + +/* + * Output character buffer. + */ +#define OUTBUFSZ 256 /* Size of output buffer */ + +static char out_buf[OUTBUFSZ]; +static int out_count = 0; + +static int jsym_next = -1; +static int quote_flag = 0; + +/* + * Setup terminal modes. + */ +void ttstartup() +{ +#ifdef TERMIOS + { + struct termios param; + register int i; + + tcgetattr(0, &tioparam); + param = tioparam; + + for (i=0; i= 0 && cr <= COMCOD) { + s = cvtout[cr]; + if (! s) + return(0); + while ((cr = *s++) != 0) + putcbuf(cr); + } else { + out_buf[out_count++] = c; + if (out_count == OUTBUFSZ) + dumpcbuf(); + } + return(1); +} + +/* + * Output a line of spaces. + */ +void putblanks(k) + register int k; +{ + cursorcol += k; + while (k--) { + out_buf[out_count++] = ' '; + if (out_count == OUTBUFSZ) + dumpcbuf(); + } + dumpcbuf(); +} + +/* + * Flush output buffer. + */ +void dumpcbuf() +{ + if (out_count == 0) + return; + if (write(2, out_buf, out_count) != out_count) + /* ignore errors */; + out_count = 0; +} + +/* + * Decode an input key code. + * Values *fb, *fe are NULL on first call, + * then used for key search. + * Return values: + * CONTF - need next char; + * BADF - no such keycode; + * >=0 - keycode detected. + */ +static int findt (fb, fe, sy, ns) + keycode_t **fb, **fe; + char sy; + int ns; +{ + char sy1; + register keycode_t *fi; + + fi = *fb ? *fb : keytab; + *fb = 0; + if (sy == 0) + return BADF; + for (; fi != *fe; fi++) { + if (! *fe && ! fi->value) + goto exit; + sy1 = fi->value[ns]; + if (*fb) { + if (sy != sy1) + goto exit; + } else { + if (sy == sy1) { + *fb = fi; + } + } + } +exit: + *fe = fi; /* for "addkey" */ + if (! *fb) + return BADF; + fi = *fb; + if (fi->value[ns + 1]) + return CONTF; + return fi->keysym; +} + +/* + * Read a command from the journal file. + * Return 0 on EOF. + */ +static int readfc() +{ + char sy1 = CCQUIT; + do { + keysym = jsym_next; + if (intrflag || read(inputfile, &sy1, 1) != 1) { + if (inputfile != journal) + close(inputfile); + else + lseek(journal, (long) -1, 1); + inputfile = 0; + intrflag = 0; + putch(COBELL); + dumpcbuf(); + return 0; + } + jsym_next = (unsigned char) sy1; + } while (keysym < 0); + return 1; +} + +/* + * Read a symbol from the user terminal, or from journal. + * Received symbol or keycode is stored in keysym. + */ +int getkeysym() +{ + keycode_t *i1, *i2; + int ts, k; + char sy1; + + dumpcbuf(); + + /* Previous symbol not consumed yet. */ + if (keysym != -1) + return keysym; + + /* Read from a jornal file. */ + if (inputfile != 0 && readfc()) + return keysym; + + /* Read from a terminal keyboard. */ +new: + intrflag = 0; + if (read(inputfile, &sy1, 1) != 1) + goto readquit; + + keysym = (unsigned char) sy1; + if (keysym == 0177) { + keysym = CCBACKSPACE; + goto readychr; + } + if (keysym > 037) + goto readychr; + if (quote_flag) { + keysym += 0100; + goto readychr; + } + /* Decode ^X sequences. */ + if (keysym == ('X' & 037)) { + if (read(inputfile, &sy1, 1) != 1) + goto readquit; + + switch (sy1) { + case 'C' & 037: /* ^X ^C */ + keysym = CCQUIT; + goto readychr; + case 'n': /* ^X n */ + case 'N': /* ^X N */ + keysym = CCPGDOWN; + goto readychr; + case 'p': /* ^X p */ + case 'P': /* ^X P */ + keysym = CCPGUP; + goto readychr; + case 'f': /* ^X f */ + case 'F': /* ^X F */ + keysym = CCROFFSET; + goto readychr; + case 'b': /* ^X b */ + case 'B': /* ^X B */ + keysym = CCLOFFSET; + goto readychr; + case 'h': /* ^X h */ + case 'H': /* ^X H */ + keysym = CCHOME; + goto readychr; + case 'e': /* ^X e */ + case 'E': /* ^X E */ + keysym = CCEND; + goto readychr; + case 'i': /* ^X i */ + case 'I': /* ^X I */ + keysym = CCINSMODE; + goto readychr; + case 'x': /* ^X x */ + case 'X': /* ^X X */ + keysym = CCDOCMD; + goto readychr; + default: + ; + } + keysym = sy1 & 037; + goto corrcntr; + } + /* Control code detected - search in the table. */ + i1 = i2 = 0; + ts = 0; + sy1 = keysym; + while ((k = findt(&i1, &i2, sy1, ts++)) == CONTF) { + if (read(inputfile, &sy1, 1) != 1) + goto readquit; + } + if (k == BADF) { + if (ts == 1) + goto corrcntr; + goto new; + } + keysym = k; + goto readychr; + +corrcntr: + if (keysym > 0 && keysym <= 037) + keysym = in0tab[keysym]; +readychr: + if (keysym == -1) + goto new; + quote_flag = 0; + if (keysym == CCCTRLQUOTE) { + quote_flag = 1; + } + sy1 = keysym; + if (write (journal, &sy1, 1) != 1) + /* ignore errors */; + keysym = (unsigned char) keysym; + return keysym; + +readquit: + if (intrflag) { + keysym = CCPARAM; + intrflag = 0; + goto readychr; + } + keysym = CCQUIT; + goto readychr; +} + +/* + * We were interrupted? + */ +int interrupt() +{ + char sy1; + + if (inputfile) { + if (jsym_next == CCINTRUP) { + jsym_next = -1; + return 1; + } + return 0; + } + if (intrflag) { + intrflag = 0; + sy1 = CCINTRUP; + if (write(journal, &sy1, 1) != 1) + /* ignore errors */; + return 1; + } + return 0; +} diff --git a/src/cmd/re/r.window.c b/src/cmd/re/r.window.c new file mode 100644 index 0000000..aa682bd --- /dev/null +++ b/src/cmd/re/r.window.c @@ -0,0 +1,400 @@ +/* + * Implementing windows. + * + * RED editor for OS DEMOS + * Alex P. Roudnev, Moscow, KIAE, 1984 + */ +#include "r.defs.h" + +/* + * Move a current window by nl rows down. + */ +void wksp_forward(nl) + int nl; +{ + register int cc, cl; + + if (nl < 0) { + if (curwksp->topline == 0) { + if (cursorline != 0) + poscursor(cursorcol, 0); + return; + } + } else { + int last_line = file[curfile].nlines - curwksp->topline; + if (last_line <= curwin->text_maxrow) { + if (cursorline != last_line) + poscursor(cursorcol, last_line); + return; + } + } + curwksp->topline += nl; + if (curwksp->topline > file[curfile].nlines - curwin->text_maxrow) + curwksp->topline = file[curfile].nlines - curwin->text_maxrow; + if (curwksp->topline < 0) + curwksp->topline = 0; + cc = cursorcol; + cl = cursorline; + drawlines(0, curwin->text_maxrow); + poscursor(cc, cl); +} + +/* + * Shift a text view by nc columns to right. + */ +void wksp_offset(nc) + int nc; +{ + register int cl, cc; + + cl = cursorline; + cc = cursorcol; + if ((curwksp->offset + nc) < 0) + nc = - curwksp->offset; + curwksp->offset += nc; + drawlines(0, curwin->text_maxrow); + cc -= nc; + if (cc < 0) + cc = 0; + else if (cc > curwin->text_maxcol) + cc = curwin->text_maxcol; + poscursor(cc, cl); +} + +/* + * Go to line by number. + */ +void gtfcn(number) + int number; +{ + register int i; + + wksp_forward(number - curwksp->topline - curwin->text_maxrow / 2); + i = number - curwksp->topline; + if (i >= 0) { + if (i > curwin->text_maxrow) + i = curwin->text_maxrow; + poscursor(cursorcol, i); + } +} + +/* + * Scroll window to show a given area. + * slin - line number with a cursor tag, to erase + * ok_to_move=0 - do not move the window, when possible + */ +void cgoto(ln, col, slin, ok_to_move) + int ln, col, slin, ok_to_move; +{ + register int lin; + + lin = ln - curwksp->topline; + if (ok_to_move || lin < 0 || lin > curwin->text_maxrow) { + ok_to_move = -1; + lin = curwin->text_maxrow / 2; + curwksp->topline = ln - lin; + if (curwksp->topline < 0) { + lin += curwksp->topline; + curwksp->topline = 0; + } + } + col -= curwksp->offset; + if (col < 0 || col > curwin->text_maxcol) { + curwksp->offset += col; + col = 0; + ok_to_move = -1; + } + if (ok_to_move) + drawlines(0, curwin->text_maxrow); + else if (slin >=0) + drawlines(slin, slin); + + poscursor(col, lin); +} + + +/* + * Switch to given window. + * Compute cursorcol, cursorline for new window. + */ +void win_switch(ww) + window_t *ww; +{ + register window_t *w = ww; + + cursorcol -= (w->text_col - curwin->text_col); + cursorline -= (w->text_row - curwin->text_row); + curwin = w; + curwksp = curwin->wksp; + if (curwksp) + curfile = curwksp->wfile; +} + +/* + * Create new window. + * Flag need_borders = 1 when borders enable. + */ +void win_create(w, col_left, col_right, row_top, row_bottom, need_borders) + register window_t *w; + int col_left, col_right, row_top, row_bottom, need_borders; +{ + register int i, size; + + w->base_col = col_left; + w->max_col = col_right; + w->base_row = row_top; + w->max_row = row_bottom; + if (need_borders) { + w->text_col = col_left + 1; + w->text_row = row_top + 1; + w->text_maxcol = col_right - col_left - 2; + w->text_maxrow = row_bottom - row_top - 2; + } else { + w->text_col = col_left; + w->text_row = row_top; + w->text_maxcol = col_right - col_left; + w->text_maxrow = row_bottom - row_top; + } + + w->wksp = (workspace_t*) salloc(sizeof(workspace_t)); + w->altwksp = (workspace_t*) salloc(sizeof(workspace_t)); + + /* eventually this extra space may not be needed */ + size = NLINES - row_top + 1; + w->firstcol = (unsigned char*) salloc(size); + for (i=0; ifirstcol[i] = w->text_maxcol + 1; + w->lastcol = (unsigned char*) salloc(size); + w->leftbar = salloc(size); + w->rightbar = salloc(size); + w->wksp->cursegm = file[2].chain; /* "#", as it's always available */ +} + +/* + * Make new window. + */ +void win_open(file) + char *file; +{ + register window_t *oldwin, *win; + int winnum; + + /* Any space for a new window? */ + if (nwinlist >= MAXWINLIST) { + error("Can't make any more windows."); + return; + } + win = winlist[nwinlist++] = (window_t*) salloc(sizeof(window_t)); + + /* Find a window number. */ + oldwin = curwin; + for (winnum=0; winlist[winnum] != oldwin; winnum++); + win->prevwinnum = winnum; + +#if MULTIWIN + /* + * Split the window into two, horizontally or vertically. + */ + if (cursorcol == 0 && cursorline > 0 + && cursorline < oldwin->text_maxrow) + { + /* Split horizontally. */ + register int i; + win_create(win, oldwin->base_col, oldwin->max_col, + oldwin->base_row + cursorline + 1, oldwin->max_row, 1); + oldwin->max_row = oldwin->base_row + cursorline + 1; + oldwin->text_maxrow = cursorline - 1; + for (i=0; i <= win->text_maxrow; i++) { + win->firstcol[i] = oldwin->firstcol[i + cursorline + 1]; + win->lastcol[i] = oldwin->lastcol[i + cursorline + 1]; + } + } else if (cursorline == 0 && cursorcol > 0 + && cursorcol < oldwin->text_maxcol-1) + { + /* Split vertically. */ + register int i; + win_create(win, oldwin->base_col + cursorcol + 2, oldwin->max_col, + oldwin->base_row, oldwin->max_row, 1); + oldwin->max_col = oldwin->base_col + cursorcol + 1; + oldwin->text_maxcol = cursorcol - 1; + for (i=0; i <= win->text_maxrow; i++) { + if (oldwin->lastcol[i] > oldwin->text_maxcol + 1) { + win->firstcol[i] = 0; + win->lastcol[i] = oldwin->lastcol[i] - cursorcol - 2; + oldwin->lastcol[i] = oldwin->text_maxcol + 1; + oldwin->rightbar[i] = MRMCH; + } + } + } else { + error("Can't put a window there."); + nwinlist--; + free(win); + return; + } +#else + /* + * Every window occupies the entire screen. + */ + win_create(win, oldwin->base_col, oldwin->max_col, + oldwin->base_row, oldwin->max_row, 1); +#endif + oldwin->wksp->cursorcol = oldwin->altwksp->cursorcol = 0; + oldwin->wksp->cursorrow = oldwin->altwksp->cursorrow = 0; + win_switch(win); + //defplline = defmiline = (win->max_row - win->base_row)/ 4 + 1; + if (editfile (file, 0, 0, 1, 1) <= 0 && + editfile (deffile, 0, 0, 0, 1) <= 0) + error("Cannot open help file."); + win_borders(oldwin, 1); + win_borders(win, 1); + poscursor(0, 0); +} + +/* + * Remove last window. + */ +void win_remove() +{ + int j, pwinnum; + register int i; + register window_t *win, *pwin; + + if (nwinlist == 1) { + error ("Can't remove the last window."); + return; + } + win = winlist[--nwinlist]; + pwinnum = win->prevwinnum; + pwin = winlist[pwinnum]; + if (pwin->max_row != win->max_row) { + /* Vertical */ + pwin->firstcol[j = pwin->text_maxrow+1] = 0; + pwin->lastcol[j++] = pwin->text_maxcol+1; + for (i=0; i<=win->text_maxrow; i++) { + pwin->firstcol[j+i] = win->firstcol[i]; + pwin->lastcol[j+i] = win->lastcol[i]; + } + pwin->max_row = win->max_row; + pwin->text_maxrow = pwin->max_row - pwin->base_row - 2; + } else { + /* Horizontal */ + for (i=0; i<=pwin->text_maxrow; i++) { + pwin->lastcol[i] = win->lastcol[i] + + win->base_col - pwin->base_col; + if (pwin->firstcol[i] > pwin->text_maxcol) + pwin->firstcol[i] = pwin->text_maxcol; + } + pwin->max_col = win->max_col; + pwin->text_maxcol = pwin->max_col - pwin->base_col - 2; + } + win_borders(pwin, 1); + win_goto(pwinnum); + drawlines(0, curwin->text_maxrow); + poscursor(0, 0); + DEBUGCHECK; + free(win->firstcol); + free(win->lastcol); + free(win->leftbar); + free(win->rightbar); + free((char *)win->wksp); + free((char *)win->altwksp); + free((char *)win); + DEBUGCHECK; +} + +/* + * Switch to another window by number. + * When number is -1, select a next window after the curwin. + */ +void win_goto(winnum) + int winnum; +{ + register window_t *oldwin, *win; + + oldwin = curwin; + oldwin->wksp->cursorcol = cursorcol; + oldwin->wksp->cursorrow = cursorline; + if (winnum < 0) { + /* Find a window next to the current one. */ + for (winnum=0; winnum= nwinlist) + winnum = 0; + } + win = winlist[winnum]; + if (win == oldwin) + return; + + /* win_borders(oldwin, win); */ + win_switch(win); + //defplline = defmiline = (win->max_row - win->base_row) / 4 + 1; + poscursor(curwin->wksp->cursorcol, curwin->wksp->cursorrow); +} + +/* + * Redisplay changed windows after lines in file shifted. + * + * w - workspace; + * fn - index of changed file; + * from, to, delta - ranged of changed lines and a number of lines in it + * + * Actions: + * 1. Redraw all windows, overlapped with the given area; + * 2. Changed workspaces get updated segm pointers; + * 3. Line numbers updated in workspaces, containing the tails + * of changed files. + */ +void wksp_redraw(w, fn, from, to, delta) + workspace_t *w; + int from, to, delta, fn; +{ + register workspace_t *tw; + register int i, j; + int k, l, m; + window_t *owin; + + for (i = 0; i < nwinlist; i++) { + tw = winlist[i]->altwksp; + if (tw->wfile == fn && tw != w) { + /* Update segm pointer. */ + tw->line = tw->segmline = 0; + tw->cursegm = file[fn].chain; + + /* Update a line number */ + j = delta >= 0 ? to : from; + if (tw->topline > j) + tw->topline += delta; + } + tw = winlist[i]->wksp; + if (tw->wfile == fn && tw != w) { + /* Update a segm pointer. */ + tw->line = tw->segmline = 0; + tw->cursegm = file[fn].chain; + + /* Update a line number */ + j = (delta >= 0) ? to : from; + if (tw->topline > j) + tw->topline += delta; + + /* Redraw the window, if changed */ + j = (from > tw->topline) ? from : tw->topline; + k = tw->topline + winlist[i]->text_maxrow; + if (k > to) + k = to; + if (j <= k) { + owin = curwin; + l = cursorcol; + m = cursorline; + win_switch(winlist[i]); + drawlines(j - tw->topline, + delta == 0 ? k - tw->topline : winlist[i]->text_maxrow); + win_switch(owin); + poscursor(l, m); + } + } + } +} diff --git a/src/cmd/reboot/Makefile b/src/cmd/reboot/Makefile new file mode 100644 index 0000000..ebba953 --- /dev/null +++ b/src/cmd/reboot/Makefile @@ -0,0 +1,47 @@ +TOPSRC = $(shell cd ../../..; pwd) +include $(TOPSRC)/target.mk + +SRCS = reboot.c +OBJS = reboot.o +MAN = reboot.0 +MANSRC = reboot.8 + +all: reboot ${MAN} + +reboot: ${OBJS} + ${CC} ${LDFLAGS} -o reboot.elf ${OBJS} -lc + ${OBJDUMP} -S reboot.elf > reboot.dis + ${SIZE} reboot.elf + ${ELF2AOUT} reboot.elf $@ + ln -f $@ halt + ln -f $@ poweroff + +${MAN}: ${MANSRC} + ${MANROFF} ${MANSRC} > ${MAN} + +clean: + rm -f *.o *~ *.elf *.dis ${MAN} reboot halt poweroff tags + +depend: ${SRCS} + mkdep ${CFLAGS} ${SRCS} + +install: all + cp ${MAN} ${DESTDIR}/share/man/cat8/ + @-rm -f ${DESTDIR}/share/man/cat8/fastboot.0 ${DESTDIR}/share/man/cat8/halt.0 + ln ${DESTDIR}/share/man/cat8/reboot.0 ${DESTDIR}/share/man/cat8/fastboot.0 + ln ${DESTDIR}/share/man/cat8/reboot.0 ${DESTDIR}/share/man/cat8/halt.0 + install reboot ${DESTDIR}/sbin/reboot + @-rm -f ${DESTDIR}/sbin/fastboot ${DESTDIR}/sbin/halt ${DESTDIR}/sbin/poweroff + ln -f ${DESTDIR}/sbin/reboot ${DESTDIR}/sbin/halt + ln -f ${DESTDIR}/sbin/reboot ${DESTDIR}/sbin/fastboot + ln -f ${DESTDIR}/sbin/reboot ${DESTDIR}/sbin/poweroff + ln -f ${DESTDIR}/sbin/reboot ${DESTDIR}/sbin/bootloader + +lint: ${SRCS} + lint -hax ${SRCS} + +tags: ${SRCS} + ctags ${SRCS} + +# DO NOT DELETE THIS LINE -- mkdep uses it. +# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY. diff --git a/src/cmd/reboot/reboot.8 b/src/cmd/reboot/reboot.8 new file mode 100644 index 0000000..9eee250 --- /dev/null +++ b/src/cmd/reboot/reboot.8 @@ -0,0 +1,133 @@ +.\" Copyright (c) 1980 Regents of the University of California. +.\" All rights reserved. The Berkeley software License Agreement +.\" specifies the terms and conditions for redistribution. +.\" +.\" @(#)reboot.8 2.2 (2.11BSD) 1996/11/16 +.\" +.TH REBOOT 8 "May 24, 1996" +.UC 2 +.SH NAME +reboot \- stopping and restarting the system +.SH SYNOPSIS +.B /sbin/reboot +[ +.B \-lqnhdarsfRD +] +.br +.B /sbin/halt +[ +.B \-lqndars +] +.br +.B /sbin/fastboot +[ +.B \-lqndarsRD +] +.SH DESCRIPTION +2.11BSD is started by placing it in memory at location zero and transferring to +its entry point. Since the system is not reentrant, it is necessary to read +it in from disk or tape each time it is to be boot strapped. +.PP +.B "Rebooting a running system:" +When the system is running and a reboot is desired, +.IR shutdown (8) +is normally used to stop time sharing and put the system into single user +mode. If there are no users then +.B /sbin/reboot +can be used without shutting the system down first. +.PP +Reboot normally causes the disks to be synced and allows the system to +perform other shutdown activities such as resynchronizing hardware +time-of-day clocks. A multi-user reboot (as described below) is then +initiated. This causes a system to be booted and an automatic disk check +to be performed. If all this succeeds without incident, the system is then +brought up for multi-user operation. +.PP +Options to reboot are: +.TP +.B \-l +Don't try to tell +.IR syslogd (8) +what's about to happen. +.TP +.B \-q +Reboot quickly and ungracefully, without shutting down running processes +first. +.TP +.B \-n +Don't sync before rebooting. This can be used if a disk or the processor +is on fire. +.TP +.B \-h +Don't reboot, simply halt the processor. +.TP +.B \-d +Dump memory onto the dump device, usually part of swap, before rebooting. +The dump is done in the same way as after a panic. +.TP +.B \-a +Have the system booter ask for the name of the system to be booted, rather +than immediately booting the default system (/unix). +.TP +.B \-r +Mount the root file system as +.I "read only" +when the system reboots. This is not supported by the kernel in 2.11BSD. +.TP +.B \-s +Don't enter multi-user mode after system has rebooted \- stay in single +user mode. +.TP +.B \-f +Fast reboot. Omit the automatic file system consistency check when the system +reboots and goes multi-user. This is accomplished by passing a +.I fast reboot +flag on to the rebooting kernel. This currently prevents the use of +.B \-f +flag in conjunction with the +.B \-h +(halt) flag. +.TP +.B \-D +Set the +.IR autoconfig (8) +debug flag. This is normally not used unless one is debugging the +.I autoconfig +program. +.TP +.B \-R +Tells the kernel to use the compiled in root device. Normally the system +uses the device from which it was booted as the root/swap/pipe/dump device. +.PP +.I Reboot +normally places a shutdown record in the login accounting file +/usr/adm/wtmp. This is inhibited if the +.B \-q +or +.B \-n +options are present. +Note that the +.B \-f +(fast reboot) and +.B \-n +(don't sync) +options are contradictory; the request for a fast reboot is ignored in this +case. +.PP +.I Halt +and +.I fastboot +are synonymous with ``\fBreboot \-h\fP'' and ``\fBreboot \-f\fP'', respectively. +.PP +.B "Power fail and crash recovery:" +Normally, the system will reboot itself at power-up or after crashes +\fBif\fP the contents of low memory are intact. +An automatic consistency check of the file systems will be +performed, and unless this fails, the system will resume multi-user +operations. +.SH "SEE ALSO" +autoconfig(8), +sync(2), +utmp(8), +shutdown(8), +syslogd(8) diff --git a/src/cmd/reboot/reboot.c b/src/cmd/reboot/reboot.c new file mode 100644 index 0000000..f266ec4 --- /dev/null +++ b/src/cmd/reboot/reboot.c @@ -0,0 +1,181 @@ +/* + * Reboot ... + * + * Copyright (c) 1980,1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define OPTS "lqnhdarsfRD" + +main(argc, argv) + int argc; + char **argv; +{ + int howto; /* reboot options argument */ + int needlog = 1; /* tell syslog what's happening */ + int quickly = 0; /* go down quickly & ungracefully */ + char *myname; /* name we were invoked as */ + char args[20], *ap; /* collected arguments for syslog */ + int i; + char *rindex(); + + if (myname = rindex(argv[0], '/')) + myname++; + else + myname = argv[0]; + if (strcmp(myname, "halt") == 0) + howto = RB_HALT; + else if (strcmp(myname, "fasthalt") == 0) + howto = RB_HALT|RB_NOFSCK; + else if (strcmp(myname, "fastboot") == 0) + howto = RB_NOFSCK; + else if (strcmp(myname, "poweroff") == 0) + howto = RB_HALT|RB_POWEROFF; + else if (strcmp(myname, "bootloader") == 0) + howto = RB_HALT|RB_BOOTLOADER; + else + howto = 0; + + ap = args; + *ap++ = '-'; + *ap = '\0'; + while ((i = getopt(argc, argv, OPTS)) != EOF) { + switch((char)i) { + case 'l': needlog = 0; break; + case 'q': quickly++; break; + case 'n': howto |= RB_NOSYNC; break; + case 'h': howto |= RB_HALT; break; + case 'd': howto |= RB_DUMP; break; + case 'a': howto |= RB_ASKNAME; break; + case 'r': howto |= RB_RDONLY; break; + case 's': howto |= RB_SINGLE; break; + case 'f': howto |= RB_NOFSCK; break; + case 'R': howto |= RB_DFLTROOT; break; + case 'D': howto |= RB_AUTODEBUG; break; + case 'p': howto |= RB_HALT|RB_POWEROFF; break; + case '?': + fprintf(stderr, + "usage: %s [-%s]\n", myname, OPTS); + exit(EX_USAGE); + /*NOTREACHED*/ + } + if (index(args+1, (char)i) == 0) { + *ap++ = (char)i; + *ap = '\0'; + } + } + + if ((howto & (RB_NOSYNC|RB_NOFSCK)) == (RB_NOSYNC|RB_NOFSCK) + && !(howto & RB_HALT)) { + fprintf(stderr, + "%s: no sync and no fsck are a dangerous combination; no fsck ignored.\n", + myname); + howto &= ~RB_NOFSCK; + } + if (needlog) { + char *user; + struct passwd *pw; + + user = getlogin(); + if (user == (char *)0 && (pw = getpwuid(getuid()))) + user = pw->pw_name; + if (user == (char *)0) + user = "root"; + openlog(myname, 0, LOG_AUTH); + syslog(LOG_CRIT, "%s; %s by %s", + args, (howto&RB_HALT)?"halted":"rebooted", user); + } + /* + * Do a sync early on so disks start transfers while we're killing + * processes. + */ + if (! (howto & RB_NOSYNC)) + sync(); + + printf("killing processes..."); + fflush(stdout); + (void) signal(SIGHUP, SIG_IGN); /* for remote connections */ + if (kill(1, SIGTSTP) == -1) { + fprintf(stderr, "%s: can\'t idle init\n", myname); + exit(EX_NOPERM); + } + //sleep(1); + (void) kill(-1, SIGTERM); /* one chance to catch it */ + //sleep(1); + printf(" done\n"); + + /* + * After the processes receive the TERM signal start the rest of the + * buffers out to disk. Wait five seconds between SIGTERM and SIGKILL so + * the processes have a chance to clean up and exit nicely. + */ + if (!(howto & RB_NOSYNC)) { + sync(); + //sleep(1); + } + + if (! quickly) { + for (i = 1; ; i++) { + if (kill(-1, SIGKILL) == -1) { + if (errno == ESRCH) + break; + perror(myname); + kill(1, SIGHUP); + exit(EX_OSERR); + } + if (i > 5) { + fprintf(stderr, + "CAUTION: some process(es) wouldn't die\n"); + break; + } + sleep(i); + } + if (! (howto & RB_NOSYNC)) { + markdown(); + sync(); + //sleep(1); + } + } + reboot(howto); + perror(myname); + kill(1, SIGHUP); + exit(EX_OSERR); +} + + +/* + * Make shutdown entry in /usr/adm/utmp. + */ +#include +#include + +#define SCPYN(a, b) strncpy(a, b, sizeof(a)) + +markdown() +{ + struct utmp wtmp; + register int f = open(_PATH_WTMP, O_WRONLY|O_APPEND); + + if (f >= 0) { + bzero((char *)&wtmp, sizeof(wtmp)); + SCPYN(wtmp.ut_line, "~"); + SCPYN(wtmp.ut_name, "shutdown"); + SCPYN(wtmp.ut_host, ""); + (void) time(&wtmp.ut_time); + write(f, (char *)&wtmp, sizeof(wtmp)); + close(f); + } +} diff --git a/src/cmd/reloc/Makefile b/src/cmd/reloc/Makefile new file mode 100644 index 0000000..799683c --- /dev/null +++ b/src/cmd/reloc/Makefile @@ -0,0 +1,12 @@ +CC = gcc +CFLAGS = -g -ansi -Wall +LIBS = + +reloc: reloc.c + $(CC) $(CFLAGS) -o reloc reloc.c + +clean: + -rm *core reloc reloc.o + +shar: reloc.c makefile reloc.1 notes README + shar reloc.c makefile reloc.1 notes README > reloc.shar diff --git a/src/cmd/reloc/reloc.1 b/src/cmd/reloc/reloc.1 new file mode 100644 index 0000000..7ddf6f1 --- /dev/null +++ b/src/cmd/reloc/reloc.1 @@ -0,0 +1,71 @@ +'\" t +.TH RELOC 1 "3 MAy 1997" +.SH NAME +reloc \- examine NetBSD/sparc symbol table and relocation information +.SH SYNOPSIS +.B reloc +[ +.B \-h +.B \-x +.B \-d +.B \-t +.B \-s +.B \-c +.B \-n +.B \-a +] +.I infile +.SH DESCRIPTION +.B reloc +examines NetBSD/sparc object and executable files (a.out format files) +and prints a.out header, symbol table and relocation information in +a human-readable form on stdout. +.PP +Performs a function similar to the +.B nm +system utility, but prints more of the information contained in an a.out +file. +.PP +.SH OPTIONS +.TP 10 +.B \-h +Print a representation of the a.out ``exec'' header. +.TP +.B \-x +Print extra information derivable from, but not directly contained by +the a.out header. +.TP +.B \-d +Print a representation of the ``.data'' segment relocation information. +.TP +.B \-t +Print a representation of the ``.text'' segment relocation information. +.TP +.B \-s +Print a representation of the symbol table information. +.TP +.B \-c +When printing relocation information, show the correspondence of the +relocations to symbol table entries. +.TP +.B \-c +When printing symbol table, don't print symbol names +.TP +.B \-a +Show everything: equivalent to ``-h -d -t -s -c -x'' +.SH FILES +.I infile +must be specified. +.SH BUGS +.PP +The output format is awkward. +.SH "SEE ALSO" +.PD +a.out(5), stab(5), nm(1), nlist(3) +.SH AUTHOR +Bruce Ediger, bediger@csn.net +.PP +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +without any conditions or restrictions. This software is provided ``as +is'' without express or implied warranty. diff --git a/src/cmd/reloc/reloc.c b/src/cmd/reloc/reloc.c new file mode 100644 index 0000000..90278b0 --- /dev/null +++ b/src/cmd/reloc/reloc.c @@ -0,0 +1,668 @@ +/* + * reloc - program to print out all of the a.out header, symbol table, and + * relocation information in an a.out file. Prints out more information + * than ``nm'', and correlates a relocation info to symbol table entries if + * it can. + * + * Author: Bruce Ediger, bediger@csn.net + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, + * without any conditions or restrictions. This software is provided + * ``as is'' without express or implied warranty. + */ +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +char *read_extent(FILE *fin, int rsize, int offset, int calling_lineno); +char *read_stringtable(FILE *fin, struct exec *exhdr, int *strtbl_sz); + +void cleanup(FILE *fin, int count, ...); + +void run_header(struct exec *exhdr, int extended_info); +void run_reloc(struct exec *exhdr, int size, struct relocation_info *data_reloc, struct nlist *symtabl, char *stringtable, int strtbl_sz, int correspondence); +void run_symtable(struct exec *exhdr, struct nlist *symbol_table, char *stringtable, int strtbl_sz, int print_symnames); + +char *print_reloc_type(enum reloc_type type); +char *symbol_type(struct nlist *sym); +char *print_reloc_segment(int segnum); + +extern char *optarg; +extern int optind; + +struct stat attributes; + +int main(int ac, char **av) +{ + FILE *fin = NULL; + struct exec *exhdr = NULL; + char *fname = NULL; + char *stringtable; + int strtbl_sz; + struct relocation_info *data_reloc = NULL, *text_reloc = NULL; + struct nlist *symbol_table = NULL; + int show_header = 0; + int show_data_reloc = 0; + int show_text_reloc = 0; + int show_symbol_table = 0; + int print_symnames = 1; + int correspondence = 0; + int hdr_info = 0; + int opt; + + while (-1 != (opt = getopt(ac, av, "hdtsacxn"))) { + switch (opt) { + case 'h': show_header = 1; break; + case 'x': show_header = hdr_info = 1; break; /* show_header implied */ + case 'd': show_data_reloc = 1; break; + case 't': show_text_reloc = 1; break; + case 's': show_symbol_table = 1; break; + case 'c': correspondence = 1; break; + case 'n': print_symnames = 0; break; + case 'a': + show_header = show_data_reloc = show_text_reloc = show_symbol_table = correspondence = hdr_info = 1; + break; + default: errout: + fprintf(stderr, "%s: show exec header, relocation and symbol table data\n", av[0]); + fprintf(stderr, "usage: %s [-h] [-d] [-t] [-s] [-c] [-x] [-a] \n", av[0]); + fprintf(stderr, " -h: show exec header\n" + " -x: show info derivable from exec header \n" + " -d: show data segment relocations\n" + " -t: show text segment relocations\n" + " -c: show symbols that correspond to relocations\n" + " -s: show symbol table\n" + " -n: when showing symbol table, don't print symbol names\n" + " -a: show it all\n"); + return 1; + break; + } + } + + if (0 == show_header && 0 == show_data_reloc && 0 == show_text_reloc && + 0 == show_symbol_table) + show_header = show_data_reloc = show_text_reloc = show_symbol_table = correspondence = 1; + + if (optind < ac) + fname = av[optind]; + + if (NULL == fname) { + fprintf(stderr, "Need a file to examine\n"); + goto errout; + } + + if (NULL == (fin = fopen(fname, "r"))) { + fprintf(stderr, "Couldn't open \"%s\" for reading: %s\n", + fname, strerror(errno)); + return 1; + } + + if (stat(fname, &attributes) < 0) { + fprintf(stderr, "Problem on stat(2) of \"%s\": %s\n", + fname, strerror(errno)); + fclose(fin); + return 1; + } + + exhdr = (struct exec *)read_extent(fin, sizeof(*exhdr), 0, __LINE__); + + if (NULL == exhdr) { + cleanup(fin, 1, exhdr); + return 2; + } + + if (show_header) { + puts("a.out header:"); + run_header(exhdr, hdr_info); + } + + if (N_BADMAG(*exhdr)) { + fprintf(stderr, "%s isn't a recognized NetBSD a.out file\n", fname); + cleanup(fin, 1, exhdr); + return 3; + } + + stringtable = read_stringtable(fin, exhdr, &strtbl_sz); + data_reloc = (struct relocation_info *)read_extent(fin, exhdr->a_drsize, N_DRELOFF(*exhdr), __LINE__); + text_reloc = (struct relocation_info *)read_extent(fin, exhdr->a_trsize, N_TRELOFF(*exhdr), __LINE__); + symbol_table = (struct nlist *) read_extent(fin, exhdr->a_syms, N_SYMOFF(*exhdr), __LINE__); + + if (show_data_reloc) { + puts("\nData relocations:"); + run_reloc(exhdr, exhdr->a_drsize, data_reloc, symbol_table, stringtable, strtbl_sz, correspondence); + } + + if (show_text_reloc) { + puts("\nText relocations:"); + run_reloc(exhdr, exhdr->a_trsize, text_reloc, symbol_table, stringtable, strtbl_sz, correspondence); + } + + if (show_symbol_table) { + puts("\nSymbol table:"); + run_symtable(exhdr, symbol_table, stringtable, strtbl_sz, print_symnames); + } + + cleanup(fin, 5, exhdr, stringtable, data_reloc, text_reloc, symbol_table); + + return 0; +} + +void +cleanup(FILE *fin, int count, ...) +{ + va_list ap; + int i; + + if (NULL != fin) + fclose(fin); + + va_start(ap, count); + + for (i = 0; i < count; ++i) { + char *p = va_arg(ap, char *); + + if (NULL != p) + free(p); + } + + va_end(ap); +} + +char * +read_stringtable(FILE *fin, struct exec *exhdr, int *strtbl_sz) +{ + unsigned long length; + char *p = NULL; + + assert(NULL != fin); + + if (NULL == exhdr) { + fprintf(stderr, "Trying to read string table, but got no a.out header\n"); + return NULL; + } + + if (fseek(fin, N_STROFF(*exhdr), SEEK_SET) < 0) { + fprintf(stderr, "Problem seeking to string table: %s\n", + strerror(errno)); + return NULL; + } + + if (fread(&length, sizeof(length), 1, fin) != 1) { + fprintf(stderr, "Problem reading length of string table: %s\n", + strerror(errno)); + return NULL; + } + + if (length >= 4) { + p = read_extent(fin, length, N_STROFF(*exhdr), __LINE__); + *strtbl_sz = length; + printf("\nstring table size %d\n", *strtbl_sz); + } else { + fprintf(stderr, "Problem, length of string table read as %d," + " can't be right\n, ", length); + *strtbl_sz = 0; + } + + return p; +} + + +char * +read_extent(FILE *fin, int rsize, int offset, int calling_lineno) +{ + char *r = NULL; + off_t potential_eof = (off_t)rsize + (off_t)offset; + + assert(NULL != fin); + + if (potential_eof > attributes.st_size) { + fprintf(stderr, "Line %d, reading extent from %d, size %d:" + " larger than file size %qd\n", calling_lineno, offset, + rsize, attributes.st_size); + + } else if (fseek(fin, offset, SEEK_SET) < 0) { + + fprintf(stderr, "Line %d, seeking to extent at %d, file size %qd: %s\n", + calling_lineno, offset, attributes.st_size, strerror(errno)); + + } else { + + r = malloc(rsize); + assert(NULL != r); + + if (fread(r, 1, rsize, fin) != rsize) { + fprintf(stderr, "Line %d, problem reading in extent\n", calling_lineno); + free(r); + r = NULL; + } + } + + return r; +} + +void +run_reloc( + struct exec *exhdr, + int size, + struct relocation_info *reloc, + struct nlist *symtabl, + char *stringtable, + int strtbl_sz, + int correspondence +) +{ + int i, count; + int max_ordinal; + + if (NULL == exhdr || NULL == symtabl || NULL == stringtable || NULL == reloc) { + if (NULL == exhdr) fprintf(stderr, "a.out header NULL, "); + if (NULL == symtabl) fprintf(stderr, "symbol table NULL, "); + if (NULL == stringtable) fprintf(stderr, "string table NULL, "); + if (NULL == reloc) fprintf(stderr, "relocation table NULL, "); + fprintf(stderr, " can't possibly list the relocations meaningfully\n"); + return; + } + + max_ordinal = exhdr->a_syms/sizeof(*symtabl); + + count = size/sizeof(*reloc); + + printf("%d relocations\n", count); + + for (i = 0; i < count; ++i) { + printf("r_address 0x%x, symbol ordinal %d, ", reloc[i].r_address, + reloc[i].r_symbolnum); + + if (reloc[i].r_extern) + fputs("extern, ", stdout); + else { + printf("local, %s segment, ", print_reloc_segment(reloc[i].r_symbolnum)); + } + + printf( + "r_addend 0x%x (%d), type %s (0x%x)", + reloc[i].r_addend, + reloc[i].r_addend, + print_reloc_type(reloc[i].r_type), reloc[i].r_type + ); + + + if (reloc[i].r_extern && correspondence && reloc[i].r_symbolnum <= max_ordinal) { + char *sname = ""; + /* stuff from struct nlist associated with this relocation */ + + if (symtabl[reloc[i].r_symbolnum].n_un.n_strx >= 4 && + symtabl[reloc[i].r_symbolnum].n_un.n_strx < strtbl_sz) + sname = &stringtable[symtabl[reloc[i].r_symbolnum].n_un.n_strx]; + else + fprintf(stderr, + "relocation entry %d, symbol ordinal %d, n_strx is %d, " + "string table size is %d\n", + i, reloc[i].r_symbolnum, symtabl[reloc[i].r_symbolnum].n_un.n_strx, + strtbl_sz); + + printf("\n name \"%s\" (sym num %d), type 0x%x - %s, desc 0x%x, value 0x%x\n", + sname, + reloc[i].r_symbolnum, + symtabl[reloc[i].r_symbolnum].n_type, + symbol_type(&symtabl[reloc[i].r_symbolnum]), + symtabl[reloc[i].r_symbolnum].n_desc, + symtabl[reloc[i].r_symbolnum].n_value + ); + } else + fputc('\n', stdout); + } +} + +char * +print_reloc_type(enum reloc_type type) +{ + char *r = NULL; + + if (type == RELOC_8) { + r = "RELOC_8, 8 bit simple, "; + } else if (type == RELOC_16) { + r = "RELOC_16, 16 bit simple, "; + } else if (type == RELOC_32) { + r = "RELOC_32, 32 bit simple, "; + } else if (type == RELOC_DISP8) { + r = "RELOC_DISP8, 8 bit PC relative, "; + } else if (type == RELOC_DISP16) { + r = "RELOC_DISP16, 16 bit PC relative, "; + } else if (type == RELOC_DISP32) { + r = "RELOC_DISP32, 32 bit PC relative, "; + } else if (type == RELOC_WDISP30) { + r = "RELOC_WDISP30, 30 bit PC relative CALL, "; + } else if (type == RELOC_WDISP22) { + r = "RELOC_WDISP22, 22 bit PC relative BRANCH, "; + } else if (type == RELOC_HI22) { + r = "RELOC_HI22, "; + } else if (type == RELOC_22) { + r = "RELOC_22, "; + } else if (type == RELOC_13) { + r = "RELOC_13, "; + } else if (type == RELOC_LO10) { + r = "RELOC_LO10, "; + } else if (type == RELOC_BASE13) { + r = "RELOC_BASE13, "; + } else if (type == RELOC_BASE22) { + r = "RELOC_BASE22, "; + } else if (type == RELOC_PC10) { + r = "RELOC_PC10, 10 bit PC relative PIC, "; + } else if (type == RELOC_PC22) { + r = "RELOC_PC22, 22 bit PC relative PIC, "; + } else if (type == RELOC_JMP_TBL) { + r = "RELOC_JMP_TBL, jump table relative PIC, "; + } else if (type == RELOC_GLOB_DAT) { + r = "RELOC_GLOB_DAT, rtld global data, "; + } else if (type == RELOC_JMP_SLOT) { + r = "RELOC_JMP_SLOT, rtld jump slot, "; + } else if (type == RELOC_RELATIVE) { + r = "RELOC_RELATIVE, rtld relative, "; + } else { + r = "some unknown reloc type..., "; + } + + assert(NULL != r); + + return r; +} + +char * +print_reloc_segment(int segnum) +{ + char *r = "unknown segment"; + + switch (segnum) { + case N_TEXT: r = "N_TEXT"; break; + case N_DATA: r = "N_DATA"; break; + case N_BSS: r = "N_BSS"; break; + } + + return r; +} + +static char symbol_type_buffer[512]; + +char * +symbol_type(struct nlist *sym) +{ + unsigned char n_type = sym->n_type; + + symbol_type_buffer[0] = '\0'; + +/* + N_EXT = 0x01 = 0000 0001 + N_TYPE = 0x1e = 0001 1110 + N_STAB = 0xe0 = 1110 0000 <= not just a mask. if n_type field has + one or more of these bits set, the whole + n_type field is signifigant. + */ + + if (n_type & N_EXT) + strcat(symbol_type_buffer, "external, "); + + if ((n_type & N_TYPE) & ~N_EXT) { + switch ((n_type & N_TYPE) & ~N_EXT) { + case N_UNDF : strcat(symbol_type_buffer, "undefined, "); break; + case N_ABS : strcat(symbol_type_buffer, "absolute address, "); break; + case N_TEXT : strcat(symbol_type_buffer, "text segment, "); break; + case N_DATA : strcat(symbol_type_buffer, "data segment, "); break; + case N_BSS : strcat(symbol_type_buffer, "bss segment, "); break; + case N_INDR : strcat(symbol_type_buffer, "alias definition, "); break; + case N_SIZE : strcat(symbol_type_buffer, "symbol's size, "); break; + case N_COMM : strcat(symbol_type_buffer, "common reference, "); break; + case N_FN : + if (n_type & N_EXT) + strcat(symbol_type_buffer, "file name, "); + else + strcat(symbol_type_buffer, "warning message, "); + break; + } + } + + if ((n_type & N_STAB)) { + switch (n_type & ~N_EXT) { + case N_GSYM: strcat(symbol_type_buffer, "global symbol, "); break; + case N_FNAME: strcat(symbol_type_buffer, "F77 function name, "); break; + case N_FUN: strcat(symbol_type_buffer, "procedure name, "); break; + case N_STSYM: strcat(symbol_type_buffer, "data segment variable, "); break; + case N_LCSYM: strcat(symbol_type_buffer, "bss segment variable, "); break; + case N_MAIN: strcat(symbol_type_buffer, "main function name, "); break; + case N_PC: strcat(symbol_type_buffer, "global Pascal symbol, "); break; + case N_RSYM: strcat(symbol_type_buffer, "register variable, "); break; + + case N_DSLINE: case N_BSLINE: case N_SLINE: + sprintf( + &symbol_type_buffer[strlen(symbol_type_buffer)], + "line %d at address 0x%x, ", + sym->n_desc, + sym->n_value + ); + break; + + case N_SSYM: strcat(symbol_type_buffer, "structure/union element, "); break; + case N_SO: strcat(symbol_type_buffer, "main source file name, "); break; + + case N_LSYM: + sprintf( + &symbol_type_buffer[strlen(symbol_type_buffer)], + "stack variable, [%%fp + %d]", + sym->n_value + ); + break; + + case N_BINCL: strcat(symbol_type_buffer, "include file beginning, "); break; + case N_SOL: strcat(symbol_type_buffer, "included source file name, "); break; + + case N_PSYM: + sprintf( + &symbol_type_buffer[strlen(symbol_type_buffer)], + "parameter variable, [%%fp + %d]", + sym->n_value + ); + break; + + case N_EINCL: strcat(symbol_type_buffer, "include file end, "); break; + case N_ENTRY: strcat(symbol_type_buffer, "alternate entry point, "); break; + case N_LBRAC: strcat(symbol_type_buffer, "left bracket, "); break; + case N_EXCL: strcat(symbol_type_buffer, "deleted include file, "); break; + case N_RBRAC: strcat(symbol_type_buffer, "right bracket, "); break; + case N_BCOMM: strcat(symbol_type_buffer, "begin common, "); break; + case N_ECOMM: strcat(symbol_type_buffer, "end common, "); break; + case N_ECOML: strcat(symbol_type_buffer, "end common (local name), "); break; + case N_LENG: strcat(symbol_type_buffer, "length of preceding entry, "); break; + } + } + + if (' ' == symbol_type_buffer[strlen(symbol_type_buffer)-1]) + symbol_type_buffer[strlen(symbol_type_buffer)-1] = '\0'; + if (',' == symbol_type_buffer[strlen(symbol_type_buffer)-1]) + symbol_type_buffer[strlen(symbol_type_buffer)-1] = '\0'; + + return symbol_type_buffer; +} + +void +run_symtable( + struct exec *exhdr, + struct nlist *symtabl, + char *stringtable, + int strtbl_sz, + int sym_names) +{ + int i, count; + + if (NULL == exhdr || NULL == symtabl || NULL == stringtable) { + if (NULL == exhdr) fprintf(stderr, "a.out header NULL, "); + if (NULL == symtabl) fprintf(stderr, "symbol table NULL, "); + if (NULL == stringtable) fprintf(stderr, "string table NULL, "); + fprintf(stderr, " can't possibly list the symbol table meaningfully\n"); + return; + } + + count = exhdr->a_syms/sizeof(*symtabl); + + printf("%d symbols\n", count); + + for (i = 0; i < count; ++i) { + if (!sym_names) + printf("%4d name offset (%d), type 0x%x - %s, other 0x%x, desc 0x%x, value 0x%x (%d)\n", + i, + symtabl[i].n_un.n_strx, + symtabl[i].n_type, + symbol_type(&symtabl[i]), + symtabl[i].n_other, + symtabl[i].n_desc, + symtabl[i].n_value, + symtabl[i].n_value + ); + else { + char *sname = ""; + + if (symtabl[i].n_un.n_strx >= 0 && symtabl[i].n_un.n_strx < strtbl_sz) + sname = &stringtable[symtabl[i].n_un.n_strx]; + + printf("%4d name \"%s\" (%d), type 0x%x - %s, other 0x%x, desc 0x%x, value 0x%x (%d)\n", + i, + sname, + symtabl[i].n_un.n_strx, + symtabl[i].n_type, + symbol_type(&symtabl[i]), + symtabl[i].n_other, + symtabl[i].n_desc, + symtabl[i].n_value, + symtabl[i].n_value + ); + } + } +} + +void +run_header(struct exec *exhdr, int extended_info) +{ + char *id = NULL; + + assert(NULL != exhdr); + + /* print raw values */ + printf( + "\ta_midmag 0x%08x (mid %d, magic 0%o, flag 0x%x)\n" + "\ta_text 0x%08x\n" + "\ta_data 0x%08x\n" + "\ta_bss 0x%08x\n" + "\ta_syms 0x%08x\n" + "\ta_entry 0x%08x\n" + "\ta_trsize 0x%08x\n" + "\ta_drsize 0x%08x\n", + exhdr->a_midmag, + N_GETMID(*exhdr), N_GETMAGIC(*exhdr), N_GETFLAG(*exhdr), + exhdr->a_text, + exhdr->a_data, + exhdr->a_bss, + exhdr->a_syms, + exhdr->a_entry, + exhdr->a_trsize, + exhdr->a_drsize + ); + + printf( + "magic number %04o: %s\n", N_GETMAGIC(*exhdr), + N_GETMAGIC(*exhdr) == OMAGIC ? "old impure format" : + N_GETMAGIC(*exhdr) == NMAGIC ? "read-only text" : + N_GETMAGIC(*exhdr) == ZMAGIC ? "demand load format" : + N_GETMAGIC(*exhdr) == QMAGIC ? "deprecated format" : + "totally funky" + ); + + switch (N_GETMID(*exhdr)) { + case MID_ZERO: id = "unknown - implementation dependent"; break; + case MID_SUN010: id = "sun 68010/68020 binary"; break; + case MID_SUN020: id = "sun 68020-only binary"; break; + case MID_PC386: id = "386 PC binary. (so quoth BFD)"; break; + case MID_HP200: id = "hp200 (68010) BSD binary"; break; + case MID_I386: id = "i386 BSD binary"; break; + case MID_M68K: id = "m68k BSD binary with 8K page sizes"; break; + case MID_M68K4K: id = "m68k BSD binary with 4K page sizes"; break; + case MID_NS32532: id = "ns32532"; break; + case MID_SPARC: id = "sparc"; break; + case MID_PMAX: id = "pmax"; break; + case MID_VAX: id = "vax"; break; + case MID_ALPHA: id = "Alpha BSD binary"; break; + case MID_MIPS: id = "big-endian MIPS"; break; + case MID_ARM6: id = "ARM6"; break; + case MID_HP300: id = "hp300 (68020+68881) BSD binary"; break; + case MID_HPUX: id = "hp200/300 HP-UX binary"; break; + case MID_HPUX800: id = "hp800 HP-UX binary"; break; + default: + id = "don't know"; break; + } + + printf("type %d, %s\n", N_GETMID(*exhdr), id); + + /* this left shift seems a bit bogus */ + + switch((N_GETFLAG(*exhdr) & EX_DPMASK)>>4) { + case 0: + id = "traditional executable or object file"; break; + case 1: + id = "object file contains PIC code"; break; + case 2: + id = "dynamic executable"; break; + case 3: + id = "position independent executable image"; break; + default: + id = NULL; + } + + if (NULL != id) + printf("flags: 0x%x, %s\n", N_GETFLAG(*exhdr), id); + else + printf("flags: 0x%x\n", N_GETFLAG(*exhdr)); + + if (extended_info) { + unsigned long txt_addr; + unsigned long dat_addr; + unsigned long bss_addr; + + /* N_TXTADDR and N_DATADDR macros DON'T WORK */ + if (N_GETMAGIC(*exhdr) == ZMAGIC) { + txt_addr = __LDPGSZ; + dat_addr = ((txt_addr + exhdr->a_text + __LDPGSZ - 1) & ~(__LDPGSZ - 1)); + } else if (N_GETMAGIC(*exhdr) == OMAGIC) { + txt_addr = 0; + dat_addr = txt_addr + exhdr->a_text; + } else { + txt_addr = 0xdeadbeef; + dat_addr = 0xcafebabe; + } + + bss_addr = dat_addr + exhdr->a_data; + + printf(" text segment size = 0x%lx, text segment file offset = %ld\n", exhdr->a_text, N_TXTOFF(*exhdr)); + printf(" data segment size = 0x%lx, data segment file offset = %ld\n", exhdr->a_data, N_DATOFF(*exhdr)); + printf(" bss segment size = 0x%lx\n", exhdr->a_bss); + printf(" text segment relocation size = 0x%lx, file offset = %ld, %d text relocations\n", + exhdr->a_trsize, N_TRELOFF(*exhdr), exhdr->a_trsize/sizeof(struct relocation_info)); + printf(" data segment relocation size = 0x%lx, file offset = %ld, %d data relocations\n", + exhdr->a_drsize, N_DRELOFF(*exhdr), exhdr->a_drsize/sizeof(struct relocation_info)); + printf(" symbol table size = 0x%lx, symbol table file offset = %ld (%d symbols)\n", + exhdr->a_syms, N_SYMOFF(*exhdr), exhdr->a_syms/sizeof(struct nlist)); + printf(" string table file offset = 0x%lx (%d)\n", N_STROFF(*exhdr), N_STROFF(*exhdr)); + printf(" entry point = 0x%lx\n", exhdr->a_entry); + printf(" text address = 0x%lx\n\tdata address = 0x%lx\n" + "\tbss address = 0x%lx\n", + txt_addr, dat_addr, bss_addr + /* N_TXTADDR(*exhdr), N_DATADDR(*exhdr), N_BSSADDR(*exhdr) */ + ); + } +} diff --git a/src/cmd/renice/Makefile b/src/cmd/renice/Makefile new file mode 100644 index 0000000..6bc6f29 --- /dev/null +++ b/src/cmd/renice/Makefile @@ -0,0 +1,42 @@ +# +# Public Domain. 1996/11/16 - Steven Schultz +# +TOPSRC = $(shell cd ../../..; pwd) +include $(TOPSRC)/target.mk + +CFLAGS += -Werror + +SRCS = renice.c +OBJS = renice.o +MAN = renice.0 +MANSRC = renice.8 + +all: renice ${MAN} + +renice: ${OBJS} + ${CC} ${LDFLAGS} -o renice.elf ${OBJS} ${LIBS} + ${OBJDUMP} -S renice.elf > renice.dis + ${SIZE} renice.elf + ${ELF2AOUT} renice.elf $@ && rm renice.elf + +${MAN}: ${MANSRC} + ${MANROFF} ${MANSRC} > ${MAN} + +clean: + rm -f *.o *.elf ${MAN} renice *.elf *.dis tags *~ + +depend: ${SRCS} + mkdep ${CFLAGS} ${SRCS} + +install: renice + cp ${MAN} ${DESTDIR}/share/man/cat8/ + install renice ${DESTDIR}/bin/renice + +lint: ${SRCS} + lint -hax ${SRCS} + +tags: ${SRCS} + ctags ${SRCS} + +# DO NOT DELETE THIS LINE -- mkdep uses it. +# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY. diff --git a/src/cmd/renice/renice.8 b/src/cmd/renice/renice.8 new file mode 100644 index 0000000..f800614 --- /dev/null +++ b/src/cmd/renice/renice.8 @@ -0,0 +1,75 @@ +.\" Copyright (c) 1980 Regents of the University of California. +.\" All rights reserved. The Berkeley software License Agreement +.\" specifies the terms and conditions for redistribution. +.\" +.\" @(#)renice.8 6.2.1 (2.11BSD) 1996/11/17 +.\" +.TH RENICE 8 "November 17, 1996" +.UC 4 +.SH NAME +renice \- alter priority of running processes +.SH SYNOPSIS +.B renice +priority [ [ +.B \-p +] pid ... ] [ [ +.B \-g +] pgrp ... ] [ [ +.B \-u +] user ... ] +.SH DESCRIPTION +.I Renice +alters the +scheduling priority of one or more running processes. +The +.I who +parameters are interpreted as process ID's, process group +ID's, or user names. +.IR Renice 'ing +a process group causes all processes in the process group +to have their scheduling priority altered. +.IR Renice '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. To force +.I who +parameters to be interpreted as process group ID's, a +.B \-g +may be specified. To force the +.I who +parameters to be interpreted as user names, a +.B \-u +may be given. Supplying +.B \-p +will reset +.I who +interpretation to be (the default) process ID's. +For example, +.sp + renice +1 987 -u daemon root -p 32 +.sp +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 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 PRIO_MIN (\-20) +to 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 +/etc/passwd to map user names to user ID's +.SH SEE ALSO +getpriority(2), 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. diff --git a/src/cmd/renice/renice.c b/src/cmd/renice/renice.c new file mode 100644 index 0000000..10cb52a --- /dev/null +++ b/src/cmd/renice/renice.c @@ -0,0 +1,89 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include +#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; + + 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/src/cmd/retroforth/LICENSE b/src/cmd/retroforth/LICENSE new file mode 100644 index 0000000..80747ad --- /dev/null +++ b/src/cmd/retroforth/LICENSE @@ -0,0 +1,30 @@ +Permission to use, copy, modify, and/or distribute this software for +any purpose with or without fee is hereby granted, provided that the +above copyright notice and this permission notice appear in all +copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL +WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE +AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 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. + +Copyright (c) 2008 - 2012, Charles Childers +Copyright (c) 2009 - 2011, Luke Parrish +Copyright (c) 2009 - 2010, JGL +Copyright (c) 2010 - 2011, Marc Simpson +Copyright (c) 2011 - 2012, Oleksandr Kozachuk +Copyright (c) 2010, Jay Skeer +Copyright (c) 2010, Greg Copeland +Copyright (c) 2011, Aleksej Saushev +Copyright (c) 2011, Foucist +Copyright (c) 2011, Erturk Kocalar +Copyright (c) 2011, Kenneth Keating +Copyright (c) 2011, Ashley Feniello +Copyright (c) 2011, Peter Salvi +Copyright (c) 2011, Christian Kellermann +Copyright (c) 2011, Jorge Acereda +Copyright (c) 2011, Remy Moueza diff --git a/src/cmd/retroforth/Makefile b/src/cmd/retroforth/Makefile new file mode 100644 index 0000000..74dd862 --- /dev/null +++ b/src/cmd/retroforth/Makefile @@ -0,0 +1,29 @@ +TOPSRC = $(shell cd ../../..; pwd) +include $(TOPSRC)/target.mk + +CFLAGS += -Werror -Wall + +SRCS = retro.c +OBJS = retro.o +BIN = retroforth +LIBS += -ltermcap + +all: $(BIN) + +$(BIN): ${SRCS} + ${CC} ${LDFLAGS} -o $(BIN).elf $(SRCS) ${LIBS} + ${SIZE} $(BIN).elf + ${OBJDUMP} -S $(BIN).elf > $(BIN).dis + ${ELF2AOUT} $(BIN).elf $@ && rm $(BIN).elf + +clean: + rm -f *.o *.elf $(BIN) *.elf *.dis *~ + +install: all + install $(BIN) $(DESTDIR)/bin/ + cp retroImage $(DESTDIR)/lib/ + +image: $(BIN) + cat image/meta.rx image/kernel.rx > core.rx + ./$(BIN) --shrink --image retroImage --with core.rx + rm core.rx diff --git a/src/cmd/retroforth/NOTES b/src/cmd/retroforth/NOTES new file mode 100644 index 0000000..71f84f1 --- /dev/null +++ b/src/cmd/retroforth/NOTES @@ -0,0 +1,48 @@ +*This is a random collection of notes and snippits related to things I'm working on* + +== Dealing with Cell Sizes == + +In 11.2 new queries have been added to allow for checking the endian type amd bits +per cell. A standard system will be 32-bit, little endian, but with the recent +expansions into embedded realms, this should help ensure that images run only o +compatible Ngaro implementations. + +It would be useful to allow for code to be conditionally compiled based on bit size +and endian type. A possibility is to draw frm the doc{ style blocks. + + +chain: cell' + : size ( -n ) -13 5 out wait 5 in dup 0 = [ drop 32 ] ifTrue ; + : bits{ ( n"- ) + size <> [ repeat getToken "}" compare if; again ] ifTrue ; + : } ( - ) ; immediate +;chain + + +With this, the following will work: + + +with cell' + +32 bits{ +... code if ^cell'size = 32 ... +} + +16 bits{ +... code if ^cell'size = 16 ... +} + + +== Image Naming == + +retroImage + +Followed by an optional suffix referring to bits per cell: + + 16 for 16-bit + 64 for 64-bit + +And a final optional suffix for endian: + + BE for big endian + diff --git a/src/cmd/retroforth/README b/src/cmd/retroforth/README new file mode 100644 index 0000000..c93e0bd --- /dev/null +++ b/src/cmd/retroforth/README @@ -0,0 +1,43 @@ +============== +Retro Language +============== + +-------- +Overview +-------- +Retro is a concatenative, stack-based programming language with +roots in Forth. It is intended to be clean and practical. + +All code, documentation, and any binaries included are provided +under the ISC License unless otherwise noted in the source. Please +feel free to take, use, and modify Retro as you see fit. + + +------------- +Documentation +------------- +Retro comes with a variety of documents describing the language, +virtual machine, and implementation details. Most of these are +in ReStructured Text (ReST) format and can be converted to other +formats using docutils. A stylesheet is included for HTML output. + + +------------ +Getting Help +------------ +We have an irc channel on the freenode network. Join *#retro* on +*irc.freenode.net*. If you ask a question, please be patient. We +have large idle times, but the channel is logged (see +http://rx-core.org/dev/rancid) and we generally try to answer +questions in a reasonible time period. + +You can also ask questions on the mailing list. Signups, and a +public archive, are at http://groups.google.com/group/retro-10 + +*Please read the documentation before asking questions.* + + +----------- +Bug Reports +----------- +Bugs can be reported to the irc channel or mailing list. diff --git a/src/cmd/retroforth/doc/An_Introduction_to_Retro.rst b/src/cmd/retroforth/doc/An_Introduction_to_Retro.rst new file mode 100644 index 0000000..0381b60 --- /dev/null +++ b/src/cmd/retroforth/doc/An_Introduction_to_Retro.rst @@ -0,0 +1,1199 @@ +======================== +An Introduction to Retro +======================== + +--------------- +Getting Started +--------------- + +Choosing a VM +============= +Retro runs on a virtual machine. This has been implemented in many languages, and +allows easy portability to most platforms. + +The table below lists the current implementations, and the features they support. +For most users, we recommend using *C*, *Python*, or *Ruby*, as these are feature +complete, and can be setup quickly and easily. + ++------------+--------------+---+---+---+---+---+---+---+----------------------+ +| Language | File | A | B | C | D | E | F | G | Building | ++============+==============+===+===+===+===+===+===+===+======================+ +| Assembly | retro.s | x | x | x | x | x | x | x | | as retro.s -o retro| +| | | | | | | | | | | ld retro.o -o retro| ++------------+--------------+---+---+---+---+---+---+---+----------------------+ +| C | retro.c | x | x | x | x | x | x | x | gcc retro.c -o retro | ++------------+--------------+---+---+---+---+---+---+---+----------------------+ +| C# | retro.cs | x | x | | x | x | x | x | gmcs retro.cs | ++------------+--------------+---+---+---+---+---+---+---+----------------------+ +| F# | retro.fsx | x | x | x | x | x | x | x | | ++------------+--------------+---+---+---+---+---+---+---+----------------------+ +| Forth | retro.fs | x | x | x | | x | x | x | | ++------------+--------------+---+---+---+---+---+---+---+----------------------+ +| Go | gonga/ | x | x | x | x | x | x | x | cd gonga && make | ++------------+--------------+---+---+---+---+---+---+---+----------------------+ +| Lisp | retro.lisp | x | | | | x | x | x | | ++------------+--------------+---+---+---+---+---+---+---+----------------------+ +| Java | retro.java | x | | | | x | x | x | javac retro.java | ++------------+--------------+---+---+---+---+---+---+---+----------------------+ +| Lua | retro.lua | x | | | | x | x | x | | ++------------+--------------+---+---+---+---+---+---+---+----------------------+ +| Perl | retro.pl | x | | | | x | x | x | | ++------------+--------------+---+---+---+---+---+---+---+----------------------+ +| Python | retro.py | x | x | x | x | x | x | x | | ++------------+--------------+---+---+---+---+---+---+---+----------------------+ +| Ruby | retro.rb | x | x | x | x | x | x | x | | ++------------+--------------+---+---+---+---+---+---+---+----------------------+ + +A) save image +B) "include", "needs" +C) file i/o +D) query host environment +E) get current time +F) passes core tests +G) passes vocabulary tests + + +The Image File +============== +Once you have selected (and built, if necessary) a VM, you will need to put it +and the *retroImage* into a directory. You should then be able to start the VM +and interact with Retro. + + +The Library +=========== +If you are using the Assembly, C, F#, Forth, Go, Python, or Ruby VM +implementations, you can also copy or symlink the *library* directory into the +same directory as your VM and *retroImage*. + +This is optional, but copying it over is recommended as it simplifies loading +libraries and handling dependencies. + + +Basic Interactions +================== +When you start Retro, you should see something like the following: + +:: + + Retro 11.1 (1234567890) + + ok + +At this point you are at the *listener*, which reads and processes your +input. You are now set to begin exploring Retro. + +Normally Retro will process input as soon as whitespace is encountered [1]_. +This limits editing options [2]_, but serves to simplify the listener +significantly. + +To exit, run **bye**: + +:: + + bye + + +---------------------- +Exploring the Language +---------------------- + +Names And Numbers +================= +At a fundamental level, the Retro language consists of whitespace delimited +tokens representing either names or numbers. + +The *listener* will attempt to look up tokens in the *dictionary*. If found, +the information in the *dictionary header* is used to carry out the actions +specified in the name's *definition*. + +If a token can't be found in the dictionary, Retro tries to convert it to +a number. If successful, the number is pushed to the *data stack.* If not, +an error is reported. + +Retro permits names to contain any characters other than space, tab, cr, and +lf. Names are *case sensitive*, so the following are three *different* names +from Retro's perspective: + +:: + + foo Foo FOO + + +The Compiler +============ +To create new functions, you use the compiler. This is generally started by using +**:** (pronounced *colon*). A simple example: + +:: + + : foo 1 2 + putn ; + +Breaking this apart: + +:: + + : foo + +This creates a new function named *foo* and starts the compiler. A **:** should +always be followed by the name of the function to create. + +:: + + 1 + +Normally this would push a *1* to the data stack. However, since the compiler +is active, the listener will compile the code needed to push a *1* to the stack +into the definition instead. + +:: + + 2 + +And again, but compile a *2* instead of a *1*. + +:: + + + + +Since *+* is a normal function, the listener compiles a call to it rather than +calling it immediately. + +:: + + putn + +**putn** is a function that takes a number from the stack and displays it. When +encountered in a defintion, the compiler will lay down a call to it and continue. + +:: + + ; + +Functions are terminated with a **;**. This is a special case as **;** is a *compiler +macro*, and is *called at compile time*, but *ignored when the compiler is not +active.* + + +Hyperstatic Global Environment +============================== +This now brings up an interesting subpoint. Retro provides a *hyper-static +global environment.* This can be difficult to explain, so let's take a quick +look at how it works: + +:: + + : scale ( x-y ) a @ * ; + a ? + 1000 variable: a + : scale ( x-y ) a @ * ; + 3 scale putn + >>> 3000 + 100 a ! + 3 scale putn + >>> 300 + 5 variable: a + 3 scale putn + >>> 300 + a @ putn + >>> 5 + +Output is marked with **>>>**. + +Note that we create two variables with the same name (*a*). The definition for +*scale* still refers to the old variable, even though we can no longer directly +manipulate it. + +In a hyper-static global environment, functions continue to refer to the variables +and earlier functions that existed when they were defined. If you create a new +variable or function with the same name as an existing one, it only affects future +code. + + +Classes +======= +Getting back to function creation, it's time for a clarification: in Retro, the +listener is unaware of how to handle a dictionary entry and has no concept of the +difference between compiling and interpreting. + +The actual work is handled by something we call *class handlers*. + +Each dictionary header contains a variety of information: + ++--------+------------------+ +| Offset | Description | ++========+==================+ +| 0 | link to previous | ++--------+------------------+ +| 1 | class handler | ++--------+------------------+ +| 2 | xt | ++--------+------------------+ +| 3+ | name of function | ++--------+------------------+ + +When a token is found, the listener pushes the contents of the xt field and the +class handler field to the stack, then calls the **withClass** function. This then +calls the *class handler* function, which does something with the *xt* (pointer +to the actual compiled code or data). + +So, when you enter: + +:: + + 1 2 + + +What actually happens is this: + +1. The listener tries to find *1* in the dictionary. This fails, so *1* is pushed + to the stack, and the *.data* class handler is pushed to the stack. *withClass* + then passes control to *.data*. + +2. The *.data* class looks at the *compiler* variable, sees that it's off, and then + leaves the *1* on the stack. + +3. This is repeated for the *2*. + +4. When **+** is encountered, it is found to exist in the dictionary. The *xt* is + pushed to the stack, and the *.word* class handler is pushed. Then *withClass* + is called. + +5. *withClass* passes control to *.word*, which checks *compiler*, sees that it is + off, and then calls the *xt* corresponding to the definition of **+**. + +When you create a definition, the flow is altered slightly: + +1. The listener tries to find *1* in the dictionary. This fails, so *1* is pushed + to the stack, and the *.data* class handler is pushed to the stack. *withClass* + then passes control to *.data*. + +2. The *.data* class looks at the *compiler* variable, sees that it's on, and lays + down the code needed to push *1* to the stack. + +3. This is repeated for the *2*. + +4. When *+* is encountered, it is found to exist in the dictionary. The *xt* is + pushed to the stack, and the *.word* class handler is pushed. Then *withClass* + is called. + +5. *withClass* passes control to *.word*, which checks *compiler*, sees that it is + on, so compiles the necessary code to call the *xt* corresponding to the + definition of *+*. + +This model differs from Forth (and most other languages) in that the listener is +kept out of the loop. All actions are handled by the function classes. A useful +side effect is that additional classes can be created at any time, and assigned +to any named functions or data structures. + +The following classes are defined by default: + ++------------+-----------------------------------------------------------+ +| Function | Description | ++============+===========================================================+ +| .word | This is the class handler for normal functions. If the | +| | *compiler* is off, it executes the function passed to it. | +| | If the *compiler* is on, it compiles a call to the | +| | function. | ++------------+-----------------------------------------------------------+ +| .compiler | This class handler is used for functions that act as | +| | compile-time macros. The function pointer is executed if | +| | the *compiler* is on. If off, it ignores pointer. | ++------------+-----------------------------------------------------------+ +| .primitive | Used for a small set of functions that can map directly to| +| | Ngaro instructions. This acts the same as *.word*, but | +| | inlines the machine code at compile time rather than lay | +| | down a call. | ++------------+-----------------------------------------------------------+ +| .macro | Used for general macros. Functions with this class are | +| | always executed. | ++------------+-----------------------------------------------------------+ +| .data | This is used for data structures. If *compiler* is off, it| +| | leaves the pointer on the stack. If the *compiler* is on | +| | this compiles the value into another function. | ++------------+-----------------------------------------------------------+ +| .parse | Special class used for *parsing prefixes*. Acts the same | +| | as *.macro* | ++------------+-----------------------------------------------------------+ + +By default, colon definitions are given a class of *.word*, and entries made +by **create**, **variable**, and **constant** get a class of *.data*. To assign +the *.macro* class or the *.compiler* class, use either **immediate** or +**compile-only** after the **;**. + + +Data Structures +=============== +You can create named data structures using **create**, **variable**, +**variable:**, **constant**, and **elements**. + + +Constants +--------- +These are the simplest data structure. The *xt* is set to a value, which is +either left on the stack or compiled into a definition. + +:: + + 100 constant ONE-HUNDRED + +By convention, constants in Retro should have names in all uppercase. + + +Variables +--------- +A variable is a named pointer to a memory location holding a value that may change +over time. Retro provides two ways to create a variable: + +:: + + variable a + +The first, using **variable**, creates a name and allocates one cell for storage. +The memory is initialized to zero. + +:: + + 10 variable: b + +The second, **variable:**, takes a value from the stack, and creates a name, +allocates one cell for storage, and then initializes it to the value specified. +This is cleaner than doing: + +:: + + variable a + 10 a ! + + +Custom Structures +----------------- +You can also create custom data structures by creating a name, and allocating +space yourself. For instance: + +:: + + create test + 10 , 20 , 30 , + +This would create a data structure named *test*, with three values, initialized +to 10, 20, and 30. The values would be stored in consecutive memory locations. +If you want to allocate a buffer, you could use **allot** here: + +:: + + create buffer + 2048 allot + +The use of **allot** reserves space, and initializes the space to zero. + + +Elements +-------- +Elements are a hybrid between variables and custom data structures. They create +a series of names that point to consecutive cells in memory. + +:: + + 3 elements a b c + + 100 a ! + 200 b ! + 300 c ! + + a @+ putn + >>> 100 + @+ putn + >>> 200 + @ putn + >>> 300 + + +Strings +------- +In addition to the basic data structures above, Retro also provides support for +string data. + +Creating a string simply requires wrapping text with quotation marks: + +:: + + "this is a string" + " this string has leading and trailing spaces " + +When creating strings, Retro uses a floating, rotating buffer for temporary +strings. Strings created in a definition are considered permanent. + +You can obtain the length of a string using either **getLength** or **withLength**: + +:: + + "this is a string" getLength + "this is also a string" withLength + +**getLength** will consume the string pointer, while **withLength** preserves it. + + +Comparisons +----------- +Strings can be compared using **compare**: + +:: + + "test 1" "test 2" compare putn + >>> 0 + "test" "test" compare putn + >>> -1 + +The comparisons are case sensitive. + + +Searching +--------- + +For a Substring +``````````````` +Substrings can be located using **^strings'search**. This will return a pointer +to the location of the substring or a flag of 0 if the substring is not found. + +:: + + "this is a long string" + "a long" ^strings'search + .s puts + + +For a Character +``````````````` +Searching for specific characters in a string is done using **^strings'findChar**. +This will return a pointer to the string starting with the character, or a flag +if 0 if the character is not found. + +:: + + "this is a string" + 'a ^strings'findChar + .s puts + + +Extracting a Substring +---------------------- +Retro provides three functions for splitting strings. + +The first, **^strings'getSubset**, takes a string, a starting offset, and a +length. It then returns a new string based on the provided values. + +:: + + "this is a string" + 5 8 ^strings'getSubset + .s puts + +The other two are **^strings'splitAtChar** and **^strings'splitAtChar:**. The +first form takes a string and character from the stack and returns two +strings. The second takes a string and parses for a character. + +:: + + "This is a test. So is this" '. ^strings'splitAtChar puts puts + "This is a test. So is this" ^strings'splitAtChar: . puts puts + + +Trim Whitespace +--------------- +Leading whitespace can be removed with **^strings'trimLeft** and trailing +whitespace with **^strings'trimRight**. + +:: + + : foo + cr " apples" ^strings'trimLeft puts + "are good! " ^strings'trimRight puts + 100 putn ; + foo + + +Append and Prepend +------------------ +To append strings, use **^string'append**. This consumes two strings, returning +a new string starting with the first and ending with the second. + +:: + + "hello," " world!" ^strings'append puts + +A varient exists for placing the second string first. This is +**^strings'prepend**. + +:: + + : sayHelloTo ( $- ) "hello, " ^strings'prepend puts cr ; + "world" sayHelloTo + + +Case Conversion +--------------- +To convert a string to uppercase, use **^strings'toUpper**. + +:: + + "hello" ^strings'toUpper puts + +To convert a string to lowercase, use **^strings'toLower**. + +:: + + "Hello Again" ^strings'toLower puts + + +Reversal +-------- +To reverse the order of the text in a string, use **^strings'reverse**. + +:: + + "hello, world!" ^strings'reverse puts + + +Implementation Notes +-------------------- +Strings in Retro are null-terminated. They are stored in the image memory. E.g., +assuming a starting address of 12345 and a string of "hello", it will look like +this in memory: + +:: + + 12345 h + 12346 e + 12347 l + 12348 l + 12349 o + 12350 0 + +You can pass pointers to a string on the stack. + + +Prefixes +======== +Before going further, let's consider the use of prefixes in Retro. The earlier +examples involving variables used **@** and **!** (for *fetch* and *store*) to access +and modify values. Retro allows these actions to be bound to a name more tightly: + +:: + + variable a + variable b + + 100 !a + @a !b + +This would be functionally the same as: + +:: + + variable a + variable b + + 100 a ! + a @ b ! + +You can mix these models freely, or just use what you prefer. I personally find +that the prefixes make things slightly clearer, but most of them are completely +optional [3]_. + +Other prefixes include: + ++----------+--------------------------------------------------+ +| Function | Description | ++==========+==================================================+ +| & | Return a pointer to a function or data structure | ++----------+--------------------------------------------------+ +| ``+`` | Add TOS to the value stored in a variable | ++----------+--------------------------------------------------+ +| ``-`` | Subtract TOS from the value stored in a variable | ++----------+--------------------------------------------------+ +| @ | Return the value stored in a variable | ++----------+--------------------------------------------------+ +| ! | Store TOS into a variable | ++----------+--------------------------------------------------+ +| ^ | Access a function or data element in a vocabulary| ++----------+--------------------------------------------------+ +| ' | Return ASCII code for following character | ++----------+--------------------------------------------------+ +| $ | Parse number as hexadecimal | ++----------+--------------------------------------------------+ +| # | Parse number as decimal | ++----------+--------------------------------------------------+ +| % | Parse number as binary | ++----------+--------------------------------------------------+ +| " | Parse and return a string | ++----------+--------------------------------------------------+ + + +Quotes +====== +In addition to colon definitions, Retro also provides support for anonymous, +nestable blocks of code called *quotes*. These can be created inside definitions, +or at the interpreter. + +Quotes are essential in Retro as they form the basis for conditional execution, +loops, and other forms of flow control. + +To create a quote, simply wrap a sequence of code in square brackets: + +:: + + [ 1 2 + putn ] + +To make use of quotes, Retro provides *combinators*. + + +Combinators +=========== +A combinator is a function that consumes functions as input. These are +divided into three primary types: compositional, execution flow, and data +flow [4]_. + + +Compositional +------------- +A compositional combinator takes elements from the stack and returns a +new quote. + +**cons** takes two values from the stack and returns a new quote that +will push these values to the stack when executed. + +:: + + 1 2 cons + +Functionally, this is the same as: + +:: + + [ 1 2 ] + +**take** pulls a value and a quote from the stack and returns a new +quote executing the specified quote before pushing the value to the +stack. +:: + + 4 [ 1+ ] take + +Functionally this is the same as: + +:: + + [ 1+ 4 ] + +**curry** takes a value and a quote and returns a new quote applying +the specified quote to the specified value. As an example, + +:: + + : acc ( n- ) here swap , [ dup ++ @ ] curry ; + +This would create an accumulator function, which takes an initial value +and returns a quote that will increase the accumulator by 1 each time it +is invoked. It will also return the latest value. So: + +:: + + 10 acc + dup do putn + dup do putn + dup do putn + + +Execution Flow +-------------- +Combinators of this type execute other functions. + + +Fundamental +``````````` + +**do** takes a quote and executes it immediately. + +:: + + [ 1 putn ] do + &words do + + +Conditionals +```````````` +Retro provides four combinators for use with conditional execution of +quotes. These are **if**, **ifTrue**, **ifFalse**, and **when**. + +**if** takes a flag and two quotes from the stack. If the flag is +*true*, the first quote is executed. If false, the second quote is +executed. + +:: + + -1 [ "true\n" puts ] [ "false\n" puts ] if + 0 [ "true\n" puts ] [ "false\n" puts ] if + +**ifTrue** takes a flag and one quote from the stack. If the flag is true, +the quote is executed. If false, the quote is discarded. + +:: + + -1 [ "true\n" puts ] ifTrue + 0 [ "true\n" puts ] ifTrue + +**ifFalse** takes a flag and one quote from the stack. If the flag is false, +the quote is executed. If true, the quote is discarded. + +:: + + -1 [ "false\n" puts ] ifFalse + 0 [ "false\n" puts ] ifFalse + +**when** takes a number and two quotes. The number is duplicated, and the +first quote is executed. If it returns true, the second quote is executed. +If false, the second quote is discarded. + +Additionally, if the first quote is true, **when** will exit the calling +function, but if false, it returns to the calling function. + +:: + + : test ( n- ) + [ 1 = ] [ drop "Yes\n" puts ] when + [ 2 = ] [ drop "No\n" puts ] when + drop "No idea\n" puts ; + + +Looping +``````` +Several combinators are available for handling various looping constructs. + +**while** takes a quote from the stack and executes it repeatedly as long +as the quote returns a *true* flag on the stack. This flag must be well +formed and equal *-1*. + +:: + + 10 [ dup putn space 1- dup 0 <> ] while + +**times** takes a count and quote from the stack. The quote will be executed +the number of times specified. No indexes are pushed to the stack. + +:: + + 1 10 [ dup putn space 1+ ] times + +The **iter** and **iterd** varients act similarly, but do push indexes to +the stacks. **iter** counts up from 0, and **iterd** counts downward to 1. + +:: + + 10 [ putn space ] iter + 10 [ putn space ] iterd + + +Data Flow +````````` +These combinators exist to simplify stack usage in various circumstances. + + +Preserving +`````````` +Preserving combinators execute code while preserving portions of the data stack. + +**dip** takes a value and a quote, moves the value off the main stack +temporarily, executes the quote, and then restores the value. + +:: + + 10 20 [ 1+ ] dip + +Would yield the following on the stack: + +:: + + 11 20 + +This is functionally the same as doing: + +:: + + 10 20 push 1+ pop + +**sip** is similar to **dip**, but leaves a copy of the original value on +the stack during execution of the quote. So: + +:: + + 10 [ 1+ ] sip + +Leaves us with: + +:: + + 11 10 + +This is functionally the same as: + +:: + + 10 dup 1+ swap + + +Cleave +`````` +Cleave combinators apply multiple quotations to a single value or set +of values. + +**bi** takes a value and two quotes, it then applies each quote to a +copy of the value. + +:: + + 100 [ 1+ ] [ 1- ] bi + +**tri** takes a value and three quotes. It then applies each quote to a +copy of the value. + +:: + + 100 [ 1+ ] [ 1- ] [ dup * ] tri + + +Spread +`````` +Spread combinators apply multiple quotations to multiple values. The asterisk +suffixed to these function names signifies that they are spread combinators. + +**bi*** takes two values and two quotes. It applies the first quote to the +first value and the second quote to the second value. + +:: + + 1 2 [ 1+ ] [ 2 * ] bi* + +**tri*** takes three values and three quotes, applying the first quote to +the first value, the second quote to the second value, and the third quote +to the third value. + +:: + + 1 2 3 [ 1+ ] [ 2 * ] [ 1- ] tri* + + +Apply +````` +Apply combinators apply a single quotation to multiple values. The at sign +suffixed to these function names signifies that they are apply combinators. + +**bi@** takes two values and a quote. It then applies the quote to each value. + +:: + + 1 2 [ 1+ ] bi@ + +**tri@** takes three values and a quote. It then applies the quote to each +value. + +:: + + 1 2 3 [ 1+ ] tri@ + +**each@** takes a pointer, a quote, and a type constant. It then applies the +quote to each value in the pointer. In the case of a linear buffer, it also +takes a length. + +:: + + ( arrays ) + create a 3 , ( 3 items ) 1 , 2 , 3 , + a [ @ putn space ] ^types'ARRAY each@ + + ( buffer ) + "hello" withLength [ @ putc ] ^types'BUFFER each@ + + ( string ) + "HELLO" [ @ putc ] ^types'STRING each@ + + ( linked list ) + last [ @ d->name puts space ] ^types'LIST each@ + + +Conditionals +============ +Retro has a number of functions for implementing comparisons and conditional +execution of code. + + +Comparisons +----------- ++----------+-----------+-----------------------------------------+ +| Function | Stack | Description | ++==========+===========+=========================================+ +| = | ab-f | compare a == b | ++----------+-----------+-----------------------------------------+ +| > | ab-f | compare a > b | ++----------+-----------+-----------------------------------------+ +| < | ab-f | compare a < b | ++----------+-----------+-----------------------------------------+ +| >= | ab-f | compare a >= b | ++----------+-----------+-----------------------------------------+ +| <= | ab-f | compare a <= b | ++----------+-----------+-----------------------------------------+ +| <> | ab-f | compare a <> b | ++----------+-----------+-----------------------------------------+ +| compare | $$-f | compare two strings | ++----------+-----------+-----------------------------------------+ +| if; | f- | if flag is true, exit function | ++----------+-----------+-----------------------------------------+ +| 0; | n-? | if n <> 0, leave n on stack and continue| +| | | if n = 0, drop n and exit function | ++----------+-----------+-----------------------------------------+ +| if | fqq- | Execute one of two quotes depending on | +| | | value of flag | ++----------+-----------+-----------------------------------------+ +| ifTrue | fq- | Execute quote if flag is not zero | ++----------+-----------+-----------------------------------------+ +| ifFalse | fq- | Execute quote if flag is zero | ++----------+-----------+-----------------------------------------+ +| when | nqq-n | Execute second quote if first quote | +| | | returns true. Exits caller if second | +| | | quote is executed. | ++----------+-----------+-----------------------------------------+ + + +Namespaces +========== +Sometimes you will want to hide some functions or data structures from the +main dictionary. This is done by wrapping the code in question in double +curly braces: + +:: + + 23 constant foo + + {{ + 1 constant ONE + 2 constant TWO + : foo ONE TWO + ; + foo + }} + + foo ( refers to the first foo; the second foo is now hidden ) + +When the closing braces are encountered, the headers for the functions following +the opening braces are hidden. + +If you want to hide some functions, but reveal others, you can add **---reveal---** +into the mix: + +:: + + {{ + 1 constant ONE + 2 constant TWO + ---reveal--- + : foo ONE TWO + ; + }} + +At this point, *foo* would be visible, but the constants would be hidden. + + +Vocabularies +============ +Vocabularies allow grouping of related functions and data, and selectively +exposing them. Active vocabularies are searched before the main dictionary +and the order for searching is configurable at runtime. + + +Creation +-------- + +:: + + chain: name' + ...functions... + ;chain + +Vocabulary names should generally be lowercase, and should end with a single +apostrophe. + + +Exposing and Hiding +------------------- +Use **with** to add a vocabulary to the search order. The most recently +exposed vocabularies are searched first, with the global dictionary +searched last. + +:: + + with console' + +The most recent vocabulary can be closed using **without**. + +:: + + without + +You can also close all vocabularies using **global**. + +:: + + global + +As a simplification, you can reset the search order and load a series +of vocabularies using **with|**: + +:: + + with| console' files' strings' | + + +Direct Access +------------- +It is possible to directly use functions and variables in a vocabulary +using the **^** prefix. + +:: + + ^vocabulary'function + +As an example: + +:: + + : redWords ^console'red words ^console'normal ; + +This is recommended over exposing a full vocabulary as it keeps the +exposed functions down, helping to avoid naming conflicts. + + +Vectored Execution +================== +One of the design goals of Retro is flexibility. And one way this is achieved is +by allowing existing colon definitions to be replaced with new code. We call this +*revectoring* a definition. + ++-----------+-------+----------------------------------------------------+ +| Function | Stack | Description | ++===========+=======+====================================================+ +| :is | aa- | Assign the function (a2) to act as (a1) | ++-----------+-------+----------------------------------------------------+ +| :devector | a- | Restore the original definition of (a) | ++-----------+-------+----------------------------------------------------+ +| is | a"- | Parse for a function name and set it to act as (a) | ++-----------+-------+----------------------------------------------------+ +| devector | "- | Parse for a function name and restore the original | +| | | definition | ++-----------+-------+----------------------------------------------------+ + +Example: + +:: + + : foo ( -n ) 100 ; + : bar ( - ) foo 10 + putn ; + bar + >>> 110 + [ 20 ] is foo + bar + >>> 30 + devector foo + bar + >>> 110 + +This technique is used to allow for fixing of buggy code in existing images +and adding new functionality. + + +Input and Output +================ +Getting away from the quotes, combinators, compiler, and other bits, let's take +a short look at input and output options. + + +Console +------- +At the listener level, Retro provides a few basic functions for reading and +displaying data. + ++----------+-------+--------------------------------------------------------+ +| Function | Stack | Description | ++==========+=======+========================================================+ +| getc | -c | Read a single keypress | ++----------+-------+--------------------------------------------------------+ +| accept | c- | Read a string into the text input buffer | ++----------+-------+--------------------------------------------------------+ +| getToken | -$ | Read a whitespace delimited token and return a pointer | ++----------+-------+--------------------------------------------------------+ +| putc | c- | Display a single character | ++----------+-------+--------------------------------------------------------+ +| puts | $- | Display a string | ++----------+-------+--------------------------------------------------------+ +| clear | ``-`` | Clear the display | ++----------+-------+--------------------------------------------------------+ +| space | ``-`` | Display a blank space | ++----------+-------+--------------------------------------------------------+ +| cr | ``-`` | Move cursor to the next line | ++----------+-------+--------------------------------------------------------+ + +The **puts** function handles a number of escape sequences to allow for formatted +output. + ++------+------------------------------------------------+ +| Code | Use | ++======+================================================+ +| \n | newline | ++------+------------------------------------------------+ +| \[ | ASCII 27, followed by [ | ++------+------------------------------------------------+ +| \\ | Display a \ | ++------+------------------------------------------------+ +| \' | Display a " | ++------+------------------------------------------------+ +| %d | Display a number from the stack (decimal) | ++------+------------------------------------------------+ +| %o | Display a number from the stack (octal) | ++------+------------------------------------------------+ +| %x | Display a number from the stack (hexadecimal) | ++------+------------------------------------------------+ +| %s | Display a string from the stack | ++------+------------------------------------------------+ +| %c | Display a character from the stack | ++------+------------------------------------------------+ +| %% | Display a % | ++------+------------------------------------------------+ + +As an example: + +:: + + 3 1 2 "%d + %d = %d\n" puts + >>> 2 + 1 = 3 + + : I'm ( "- ) + getToken "\nHello %s, welcome back.\n" puts ; + + I'm crc + >>> Hello crc, welcome back + + +--------- +Footnotes +--------- + +.. [1] With some VM implementations, Retro will not process the input until + the enter key is pressed. This is system-level buffering, and is not + the standard Retro behavior. There are external tools included with + Retro to alter the behavior to match the standard. + +.. [2] You can not use Retro with tools like *rlwrap*, and editing is limited + to use of backspace. The arrow keys are not supported by Retro. + +.. [3] The exceptions here would be the *&* prefix for obtaining a pointer inside + a definition and the *"* prefix for parsing strings. All of the others can + be worked around or ignored easily. + +.. [4] The terminology and some function names are borrowed from the Factor + language. diff --git a/src/cmd/retroforth/doc/Coding_Style.rst b/src/cmd/retroforth/doc/Coding_Style.rst new file mode 100644 index 0000000..34e15c1 --- /dev/null +++ b/src/cmd/retroforth/doc/Coding_Style.rst @@ -0,0 +1,129 @@ +============ +Coding Style +============ + + +---------- +Formatting +---------- +* Use ASCII or UTF8 +* Use 2 space indent, no tabs +* Use Unix-style line endings +* If a function is more than one line, start the code on the line + following the name +* All functions should have stack comments +* Try not to exceed 80 characters per line +* Avoid trailing whitespace +* Closing semicolons should not be on a separate line + + +------ +Naming +------ +* Use short names for indexes +* Vocabulary names should end with an apostrophe +* Class names should begin with a period +* Constants should be in UPPERCASE +* Use camelCase with the initial word lowercase. Keep acronyms uppercase. +* Use of dotted notation (e.g., list.size) is acceptable for functions + operating on a data structure + + +-------- +Comments +-------- +* Comments should be enclosed in parenthesis +* Keep comments roughly aligned within a local grouping +* Avoid superfluous comments +* All functions should have stack comments +* A space should preceed the closing parenthesis + + +-------------- +Stack Comments +-------------- +Stack comments in Retro are a compact form, using short codes +in place of actual words. These codes are listed in the next +section. + +A typical comment for a function that takes two arguments and +leaves one will look like: + +:: + + ( xy-z ) + +In a few cases, functions may consume or leave a variable number +of arguments. In this case, we denote it like: + +:: + + ( n-n || n- ) + +There are two other modifiers in use. Some functions have different +compile-time and run-time stack use. We prefix the comment with +C: for compile-time, and R: for run-time actions. + +If not specified, the stack comments are for runtime effects. +Functions with no C: are assumed to have no stack impact during +compilation. + ++------------+------------------------------------+ +| Code | Used for | ++============+====================================+ +| x, y, z, n | Generic numbers | ++------------+------------------------------------+ +| q, r | Quotient, Remainder (for division) | ++------------+------------------------------------+ +| ``"`` | Function parses for a string | ++------------+------------------------------------+ +| q | Quote | ++------------+------------------------------------+ +| a | Address | ++------------+------------------------------------+ +| ``$`` | Zero-terminated string | ++------------+------------------------------------+ +| c | ASCII character | ++------------+------------------------------------+ +| f | Flag | ++------------+------------------------------------+ +| t | Type constant | ++------------+------------------------------------+ +| ... | Variable number of values on stack | ++------------+------------------------------------+ + + +------------- +Documentation +------------- +* Use reStructuredText for compatibility +* Try to keeps lines to a max of 80 characters +* Use the following section title adornment styles: + +:: + + ============== + Document Title + ============== + + ------------------------------------------ + Document Subtitle, or Major Division Title + ------------------------------------------ + + Section + ======= + + Subsection + ---------- + + Sub-Subsection + `````````````` + + Sub-Sub-Subsection + .................. + +* Use two blank lines before each section/subsection/etc. title. One blank line + is sufficient between immediately adjacent titles. +* Documentation should be released under ISC license or CC0 +* For libraries: embedded documentation using **doc{** should be placed at the + end of the file diff --git a/src/cmd/retroforth/doc/Commentary.txt b/src/cmd/retroforth/doc/Commentary.txt new file mode 100644 index 0000000..3d5772c --- /dev/null +++ b/src/cmd/retroforth/doc/Commentary.txt @@ -0,0 +1,2009 @@ +Building Retro +-------------- +The process of building a new retroImage is a straightforward, though not +trivial, process. It involves several stages, and some tricks. This is +a commentary on the code, which should help make the process easier to +understand. + + +Stage 1: The Metacompiler +========================= +The first of the three stages of Retro is the metacompiler. This comprises +the assembler, and secondary compiler, and is used to create a new image. +There are some tricky things: + +1) The target memory is allocated +2) But all pointers compiled in it need to be adjusted to be relative to + zero, so it'll continue working after replacing the old image +3) We can't know the locations of the class handler until we are finished + laying down a fair portion of the new kernel +4) When we move the image to overwrite the old one, we can't rely on any + code locations in either image + +So let's begin. + + 2560 constant IMAGE-SIZE + +This just specifies how much memory to set aside for the initial kernel built +by the metacompiler. If you need to increase, it's safer to increase in small +increments and rebuild rather than trying a big jump. (Large increases can +cause the new image to overwrite the bootNew routine, which is an easy way +to generate a badly corrupted image.) + + 7 elements target origin 'WORD 'MACRO 'DATA link chain + +A list of variables used by the metacompiler. + ++--------+----------------------------------------------------------+ +| target | Holds a pointer to the next free address in the target | +| | memory. This is similar to "heap" | ++--------+----------------------------------------------------------+ +| origin | Holds a pointer to the start of the target memory | ++--------+----------------------------------------------------------+ +| 'WORD | Holds a pointer to the .word class | ++--------+----------------------------------------------------------+ +| 'MACRO | Holds a pointer to the .macro class | ++--------+----------------------------------------------------------+ +| 'DATA | Holds a pointer to the .data class | ++--------+----------------------------------------------------------+ +| link | Holds pointer to prior entry (for initial dictionary) | ++--------+----------------------------------------------------------+ +| chain | Holds pointer to variable that will become "last" | ++--------+----------------------------------------------------------+ + + : m, ( n- ) @target !+ !target ; + +This is like "," but it writes the value to the target memory instead +of the standard heap. Each time it's called, "target" is increased by +one. + + : vm: ( n"- ) ` : .data ` m, ` ; ; + +This is used to build functions that lay down opcodes into the target +memory space. Functionally the following forms would be equivilent: + + 0 vm: nop, + : nop, 0 m, ; + +The use of "vm:" helps keep things a bit more readable though, so it +is preferred to do it this way. + + 0 vm: nop, 1 vm: lit, 2 vm: dup, + 3 vm: drop, 4 vm: swap, 5 vm: push, + 6 vm: pop, 7 vm: loop, 8 vm: jump, + 9 vm: ;, 10 vm: >jump, 11 vm: >, 25 vm: 0; 26 vm: 1+, + 27 vm: 1-, 28 vm: in, 29 vm: out, + 30 vm: wait, + +Create functions for laying down each opcode. This is pretty easy +to grasp. The number is the opcode number (in decimal), and the names +all end with a comma to distinguish them from higher-level functions. + + : pad ( - ) 32 @origin + !target ; + +Used to ensure that function addresses are greater than the number of +opcodes. + + : t-here ( -n ) @target @origin - ; + +Like "here", but returns a pointer in the target buffer. The pointer +is set relative to zero, not the physical start of the target buffer. + + : endKernel ( - ) + t-here "\nKernel ends @ %d\n" puts + IMAGE-SIZE t-here - "%d cells free" puts + depth 1 >= [ "\nError in stack depth!: " puts .s ] ifTrue ; + +This is called at the end of the initial kernel. It does some sanity checks +on the stack depth and displays some statistics on the size of the kernel. + + : main: ( - ) t-here [ "\nMAIN @ %d" puts ] [ @origin 1+ ! ] bi ; + +This is called to mark the main entry point in the image. It replaces the +jump at the image start with a jump to the code that follows it. + + : label: ( "- ) t-here constant ; + +Create a symbolic name pointing to something in the target space, with the +pointer being relative to zero. + + : # ( n- ) lit, m, ; + +This is used to compile a value as a literal. In normal definitons you'd just +do: + + : foo 1 2 + ; + +However, the classes are not aware of the target image. So we manually tell +Retro to compile them. + + : foo 1 # 2 # + ; + +This continues with the next function: + + : __# ( $- ) lit, toNumber m, ; parsing + +This is a parsing prefix; it serves as a shortcut for numbers. Instead of +doing: + + 1 # 2 # + +We can do: + + #1 #2 + +Which I find a bit cleaner. + + : $, ( $- ) withLength [ @+ m, ] times 0 m, drop ; + +Copy a string from the current image into the target memory space. + +The above finishes off what I consider the core of the assembler. The code +then moves on to extend this into a target compiler and machine forth +dialect. + + : t: ( "- ) label: nop, nop, &m, reclass ; + +Since : creates a dictionary header in the current image, we can't use it to +create functions in the target. We define "t:" (for "target :") to create a +label, compile two nop instructions, and then change the label's class to call +"m," + +Since the Retro VM is direct threaded, this basically makes a function in the +target compile a call to itself when referenced. The following forms would +be functionally identical: + + ( without t: or # ) + label: foo lit, 1 m, lit, 2 m, ;, ;, + label: bar ' foo m, ;, ;, + + ( with t: and # ) + t: foo #1 #2 ;, ;, + t: bar foo ;, ;, + +As can be seen, the second is much more compact and readable. + +Note the double ;, at the end of the functions. Retro 11 expects colon +definitions to end in a double return. This could be stripped out to save +space, but some of the debugging tools (such as dissect' and autopsy.rx) +require this to locate the end of a function in memory. + +Later on a modified ";" is defined to do this for us. + + {{ + : cond ( -a ) @target 0 m, ; + ---reveal--- + : =if ( -a ) !jump, cond ; + : jump, cond ; + : >if ( -a ) > ( xy-n ) >>, ; + t: out ( np- ) out, ; t: in ( p-n ) in, ; + +These are functions that map directly to Ngaro instructions. We will use the +instructions directly in most cases (to save some overhead), but this serves +to allow normal definitions to use them if desired. + + t: wait ( - ) #0 #0 out, wait, ; + +The "wait," instruction needs a bit of extra help to actually trigger an I/O +event. This provides it. + + t: over ( xy-xyx ) push, dup, pop, swap, ; + t: not ( x-y ) #-1 xor, ; + t: on ( a- ) #-1 swap, !, ; + t: off ( a- ) #0 swap, !, ; + t: / ( xy-q ) /mod, swap, drop, ; + t: mod ( xy-r ) /mod, drop, ; + t: negate ( x-y ) #-1 *, ; + +Additional stack, variable, and math functions that are quite useful. + + t: do ( a- ) 1-, push, ; + +This is used to invoke a function. The 1-, is used to account for the way the +VM increments the instruction pointer. + + t: @+ ( a-ac ) dup, 1+, swap, @, ; + t: !+ ( ca-a ) dup, 1+, push, !, pop, ; + +Rather handy functions for "fetch from and return next" and "store to and +return next". This allows easy access to linear arrays or strings: + + ( an example of using @+ ) + create array 1 , 2 , 3 , + array @+ putn @+ putn @+ putn drop + +Continuing on, we now have the core of the actual colon compiler: + + t: here ( -a ) heap # @, ; + t: , ( n- ) here !+ heap # !, ; + +Note the use of "!+" in ",". This is a clean way of implementing this +functionality. + + t: ;; ( - ) #9 , ; + t: t-; ( - ) ;; ;; compiler # off ; + +For terminating definitions. These are exposed as ";;" and ";", respectively. +We allow the "t-" prefix to avoid confusion with the ";" provided by the +metacompiler. + +TIP: + + If you are pressed for space, you can save a fair amount of memory by + removing the second ";;" here. + +And back to the code: + + t: ($,) ( a-a ) repeat @+ 0; , again ; + t: $ ( a- ) ($,) drop, #0 , ; + +This is used to compile a string into memory. We'll see how it is used +when we get to ":". + +Since we lack any counted loops, the "($,)" has been factored out into a +separate definition. + + + t: push ( n- ) #5 , ; + t: pop ( -n ) #6 , ; + +These are exposed as macros; they lay down push, and pop, instructions when +executed. + + t: (if) ( -a ) , here #0 , ; + t: t-=if ( R: xy- C: -a ) #12 jump: (if) + t: t->if ( R: xy- C: -a ) #11 jump: (if) + t: t-

    yyyy-mm-dd

    +

    article title

    + +... rest of the article ... + +If you do not have the header setup this way, some of the views will +fail to work properly (if at all). diff --git a/src/cmd/retroforth/examples/casket/corpse/corpse.rx b/src/cmd/retroforth/examples/casket/corpse/corpse.rx new file mode 100644 index 0000000..70e647a --- /dev/null +++ b/src/cmd/retroforth/examples/casket/corpse/corpse.rx @@ -0,0 +1,135 @@ +( corpse, a weblog in forth ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) + +needs casket' +with casket' + +( Setup App-specific Paths ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +: ARTICLES ( -$ ) casket:root "articles/" ^strings'append ; +: CURRENT ( -$ ) casket:root "current" ^strings'append ; + +( variables and buffers ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +: article ( -n ) @memory 65535 - ; +3 elements current requested this + +( support code ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +: getCurrent ( - ) + article CURRENT ^files'slurp drop article toNumber !current ; + +: setRequest ( - ) + casket:options toNumber !requested ; + +: commonHeader ( - ) + Content-type: text/html + "header.html" withTemplate ; + +: commonFooter ( - ) + "footer.html" withTemplate ; + +: navbar ( - ) + @requested 1- dup [ "
    prior" tputs ] &drop if + @requested 1- dup + [ @current @requested <> [ 1+ " | " tputs ] ifTrue ] ifTrue + @requested dup @current < + [ 1+ "next" tputs ] &drop if + @requested " | comments" tputs + @requested " | permalink" tputs ; + +( paths ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +{{ + : articleNavigationBar + setRequest + "" + tputs + &navbar @current @requested "

    Post %d of %d: %q

    " tputs ; + : displayArticle + article ARTICLES @requested toString ^strings'append ^files'slurp drop + article formatted off puts formatted on ; +---reveal--- + : /article + commonHeader + articleNavigationBar + displayArticle + @current "

    View comments for this article

    " tputs + commonFooter ; + : /comments + commonHeader + articleNavigationBar + displayArticle + "discuss.erx" withTemplate + commonFooter ; +}} + +: /css + Content-type: text/css + "corpse.css" withTemplate ; + +{{ + : findHeader ( h-h$ ) + repeat + dup ^files'readLine + dup 0 4 ^strings'getSubset "

    " compare if; drop + again ; + : getHeader ( h-$ ) + findHeader nip 4 over getLength 9 - ^strings'getSubset ; + : displayLink ( $n- ) + dup "
  • Post #%d: %s
  • " tputs ; +---reveal--- + : /all + commonHeader + "

    Index of All Posts

    " tputs + "
      " tputs + @current dup !this + [ ARTICLES swap toString ^strings'append ^files':R ^files'open + [ getHeader @this displayLink ] sip ^files'close drop this -- ] iterd + "
    " tputs + commonFooter ; +}} + +{{ + : findHeader ( h-h$ ) + repeat + dup ^files'readLine + dup 0 4 ^strings'getSubset "

    " compare if; drop + again ; + : getHeader ( h-$ ) + findHeader nip 4 over getLength 9 - ^strings'getSubset ; + : displayLink ( $n- ) + swap + "%s" tputs + "%u/article/%d" tputs + ( "n/a" ) "" tputs ; +---reveal--- + : /rss + Content-type: application/rss+xml + "rss" withTemplate + @current dup !this + [ ARTICLES swap toString ^strings'append ^files':R ^files'open + [ getHeader @this displayLink ] sip ^files'close drop this -- ] iterd + "" tputs ; +}} + +: /index + commonHeader + @current @requested + "" tputs + 4 [ + &navbar @current @requested "

    Post %d of %d: %q

    " + tputs space + article ARTICLES @requested toString ^strings'append ^files'slurp drop + article tputs + requested -- + ] times + commonFooter ; + +( Define Index ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +[ @current !requested /index ] is / + +( Casket Configuration ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +[ ( -$ ) "/path/to/corpse/directory/" ] is casket:root +[ ( -$ ) "http://corpse/url" ] is casket:url +&getCurrent is doBeforeDispatch +&dispatch is boot + +.s save bye diff --git a/src/cmd/retroforth/examples/casket/corpse/templates/corpse.css b/src/cmd/retroforth/examples/casket/corpse/templates/corpse.css new file mode 100644 index 0000000..5706150 --- /dev/null +++ b/src/cmd/retroforth/examples/casket/corpse/templates/corpse.css @@ -0,0 +1,11 @@ +body { background: #fefefe; color: black; } +p, li { font-family: serif; } +pre { background: #efefef; overflow: auto; } +a:link { color: #0B0080; } +a:visited { color: #0645AD; } +a:hover { color: #3366BB; } +h1, h2, h3, h4 { color: #0B0080; font-family: sans-serif; font-variant: small-caps; } +.header { font-size: large; text-transform: lowercase; text-align: left; } +.nav { position: absolute; top: 0; right: 0; } +.footer { border-top: 1px solid black; text-align: right; } +.older { background: #eeeeee; border-top: 3px solid black; text-align: right; } diff --git a/src/cmd/retroforth/examples/casket/corpse/templates/discuss.erx b/src/cmd/retroforth/examples/casket/corpse/templates/discuss.erx new file mode 100644 index 0000000..3890155 --- /dev/null +++ b/src/cmd/retroforth/examples/casket/corpse/templates/discuss.erx @@ -0,0 +1,13 @@ +
    +
    + + +blog comments powered by Disqus diff --git a/src/cmd/retroforth/examples/casket/corpse/templates/footer.html b/src/cmd/retroforth/examples/casket/corpse/templates/footer.html new file mode 100644 index 0000000..08f1480 --- /dev/null +++ b/src/cmd/retroforth/examples/casket/corpse/templates/footer.html @@ -0,0 +1,5 @@ + + + diff --git a/src/cmd/retroforth/examples/casket/corpse/templates/header.html b/src/cmd/retroforth/examples/casket/corpse/templates/header.html new file mode 100644 index 0000000..de6d029 --- /dev/null +++ b/src/cmd/retroforth/examples/casket/corpse/templates/header.html @@ -0,0 +1,10 @@ + + + + + Insert Title Here + + + + +

    header text

    diff --git a/src/cmd/retroforth/examples/casket/corpse/templates/rss b/src/cmd/retroforth/examples/casket/corpse/templates/rss new file mode 100644 index 0000000..e7e063a --- /dev/null +++ b/src/cmd/retroforth/examples/casket/corpse/templates/rss @@ -0,0 +1,7 @@ + + +title +%u +blog description +en-us + diff --git a/src/cmd/retroforth/examples/casket/incision/Makefile b/src/cmd/retroforth/examples/casket/incision/Makefile new file mode 100644 index 0000000..747757d --- /dev/null +++ b/src/cmd/retroforth/examples/casket/incision/Makefile @@ -0,0 +1,20 @@ +# Set this to the retro root directory +# +# You should have at least a 'retro' binary, the 'retroImage', and +# 'library' directory there +# +# Note that while you can run Rancid under the Python VM, we need +# the C VM for building (at present) + +RX = ~/code/rx + +default: clean + cp $(RX)/retroImage . + @ln -s $(RX)/library . + clang -Wall $(RX)/src/vm/retro.c -o retro + ./retro --with incision.rx --shrink + chmod 666 retroImage + chmod 666 current + +clean: + rm -f retroImage nextImage library retro diff --git a/src/cmd/retroforth/examples/casket/incision/current b/src/cmd/retroforth/examples/casket/incision/current new file mode 100644 index 0000000..c227083 --- /dev/null +++ b/src/cmd/retroforth/examples/casket/incision/current @@ -0,0 +1 @@ +0 \ No newline at end of file diff --git a/src/cmd/retroforth/examples/casket/incision/cuts/0 b/src/cmd/retroforth/examples/casket/incision/cuts/0 new file mode 100644 index 0000000..6df6300 --- /dev/null +++ b/src/cmd/retroforth/examples/casket/incision/cuts/0 @@ -0,0 +1,5 @@ +This is a test + of incision + +1 2 3 + diff --git a/src/cmd/retroforth/examples/casket/incision/incision.rx b/src/cmd/retroforth/examples/casket/incision/incision.rx new file mode 100644 index 0000000..43b0f1c --- /dev/null +++ b/src/cmd/retroforth/examples/casket/incision/incision.rx @@ -0,0 +1,55 @@ +( incision, a pastebin ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) + +needs casket' +with casket' + +: CUTS ( -$ ) casket:root "cuts/" ^strings'append ; +: CURRENT ( -$ ) casket:root "current" ^strings'append ; + + +variable current + +create scratch + 32 allot + +create query + 8192 allot + +: getCurrent ( - ) + scratch CURRENT ^files'slurp drop scratch toNumber !current ; + +: /view + Content-type: text/html + "header.erx" withTemplate + query 0 8129 fill + query CUTS casket:options ^strings'append ^files'slurp + query "
    %s
    " puts + "footer.erx" withTemplate ; + +: /post + Content-type: text/html + "header.erx" withTemplate + @current 1+ "

    permalink" tputs + getFormData 8 + [ "

    %s
    " puts ] sip + withLength CUTS @current 1+ toString ^strings'append ^files'spew drop + @current 1+ toString withLength CURRENT ^files'spew drop + "footer.erx" withTemplate ; + +: /css + Content-type: text/css + "incision.css" withTemplate ; + +: /index + Content-type: text/html + "header.erx" withTemplate + "index.erx" withTemplate + "footer.erx" withTemplate ; + + +[ /index ] is / +[ ( -$ ) "/path/to/incision/" ] is casket:root +[ ( -$ ) "http://url/for/incision" ] is casket:url +&getCurrent is doBeforeDispatch +&dispatch is boot + +.s save bye diff --git a/src/cmd/retroforth/examples/casket/incision/templates/footer.erx b/src/cmd/retroforth/examples/casket/incision/templates/footer.erx new file mode 100644 index 0000000..308b1d0 --- /dev/null +++ b/src/cmd/retroforth/examples/casket/incision/templates/footer.erx @@ -0,0 +1,2 @@ + + diff --git a/src/cmd/retroforth/examples/casket/incision/templates/header.erx b/src/cmd/retroforth/examples/casket/incision/templates/header.erx new file mode 100644 index 0000000..bd5852c --- /dev/null +++ b/src/cmd/retroforth/examples/casket/incision/templates/header.erx @@ -0,0 +1,9 @@ + + + + + +

    incision: a pastebin in retro

    +
    + + diff --git a/src/cmd/retroforth/examples/casket/incision/templates/incision.css b/src/cmd/retroforth/examples/casket/incision/templates/incision.css new file mode 100644 index 0000000..5706150 --- /dev/null +++ b/src/cmd/retroforth/examples/casket/incision/templates/incision.css @@ -0,0 +1,11 @@ +body { background: #fefefe; color: black; } +p, li { font-family: serif; } +pre { background: #efefef; overflow: auto; } +a:link { color: #0B0080; } +a:visited { color: #0645AD; } +a:hover { color: #3366BB; } +h1, h2, h3, h4 { color: #0B0080; font-family: sans-serif; font-variant: small-caps; } +.header { font-size: large; text-transform: lowercase; text-align: left; } +.nav { position: absolute; top: 0; right: 0; } +.footer { border-top: 1px solid black; text-align: right; } +.older { background: #eeeeee; border-top: 3px solid black; text-align: right; } diff --git a/src/cmd/retroforth/examples/casket/incision/templates/index.erx b/src/cmd/retroforth/examples/casket/incision/templates/index.erx new file mode 100644 index 0000000..a78a4d9 --- /dev/null +++ b/src/cmd/retroforth/examples/casket/incision/templates/index.erx @@ -0,0 +1,4 @@ +
    +
    + +
    diff --git a/src/cmd/retroforth/examples/casket/rancid/Makefile b/src/cmd/retroforth/examples/casket/rancid/Makefile new file mode 100644 index 0000000..385af5b --- /dev/null +++ b/src/cmd/retroforth/examples/casket/rancid/Makefile @@ -0,0 +1,18 @@ +# Set this to the retro root directory +# +# You should have at least a 'retro' binary, the 'retroImage', and +# 'library' directory there +# +# Note that while you can run Rancid under the Python VM, we need +# the C VM for building (at present) + +RX = ~/code/rx + +default: + @cp $(RX)/retroImage . + @ln -s $(RX)/library . + $(RX)/retro --with rancid.rx --shrink + @rm library + +clean: + @rm -f retroImage diff --git a/src/cmd/retroforth/examples/casket/rancid/rancid.rx b/src/cmd/retroforth/examples/casket/rancid/rancid.rx new file mode 100644 index 0000000..95cc5bc --- /dev/null +++ b/src/cmd/retroforth/examples/casket/rancid/rancid.rx @@ -0,0 +1,81 @@ +( rancid, an irc log browser ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +needs casket' +with casket' + +( support code ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +: LOGS ( -$ ) casket:root "logs/" ^strings'append ; + +: commonHeader ( - ) + Content-type: text/html + "header.html" withTemplate ; + +: commonFooter ( - ) + "footer.html" withTemplate ; + +: navbar + casket:options tempString + dup ', swap 2 + ! + dup ', swap 5 + ! + "20" ^strings'prepend "script.erx" withTemplate ; + +( paths ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +{{ + 2 elements content lines + + : clean ( $- ) + withLength + [ dup @ 10 13 within [ 999 swap &! sip ] ifTrue 1+ ] times drop ; + + : getLine ( $-$ ) + 999 ^strings'splitAtChar drop lines ++ ; + + : loadSourceData ( $- ) + here swap ^files'slurp here !content heap +! 32 , 0 , + @content clean ; + + : countLines ( $- ) + [ getLine dup 1 <> ] while drop ; + + : prepare ( $- ) + 0 !lines heap [ loadSourceData @content countLines ] preserve lines -- ; + + : display ( $- ) + "" puts + 32 ^strings'splitAtChar "%s" puts + 32 ^strings'splitAtChar 1+ ^strings'chop ^strings'chop "%s%s" puts + "\n" puts ; + + : dumpLines ( - ) + @lines [ @content ^files'readLine display ] times ; +---reveal--- + : /log ( - ) + commonHeader + navbar + LOGS casket:options ^strings'append + heap [ + dup keepString [ prepare ] dip + ^files':R ^files'open !content + "\n" puts + dumpLines + "\n
    \n" puts + @content ^files'close drop + ] preserve + commonFooter ; +}} + +: /css + Content-type: text/css + "rancid.css" withTemplate ; + +: /index + commonHeader + "default.erx" withTemplate + commonFooter ; + +( Casket Configuration ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +[ /index ] is / +[ ( -$ ) "/path/to/rancid/" ] is casket:root +[ ( -$ ) "http://url/to/rancid" ] is casket:url +&dispatch is boot + +.s save bye diff --git a/src/cmd/retroforth/examples/casket/rancid/templates/default.erx b/src/cmd/retroforth/examples/casket/rancid/templates/default.erx new file mode 100644 index 0000000..0bb2563 --- /dev/null +++ b/src/cmd/retroforth/examples/casket/rancid/templates/default.erx @@ -0,0 +1,90 @@ +

    The Retro project has logs of conversation in the #retro irc channel on irc.freenode.net going + back to 2006. This is a small web app to allow viewing them in a nicer fashion.

    + +

    To get started, select a date from the calendar below. These logs are updated hourly. For direct + linking, use this URL, replacing the yy.mm.dd with the date you wish to link to: +
    %u/log/yy.mm.dd

    + + diff --git a/src/cmd/retroforth/examples/casket/rancid/templates/footer.html b/src/cmd/retroforth/examples/casket/rancid/templates/footer.html new file mode 100644 index 0000000..d9b1478 --- /dev/null +++ b/src/cmd/retroforth/examples/casket/rancid/templates/footer.html @@ -0,0 +1,4 @@ +
    +

    Rancid is © 2011 by Charles Childers

    + + diff --git a/src/cmd/retroforth/examples/casket/rancid/templates/header.html b/src/cmd/retroforth/examples/casket/rancid/templates/header.html new file mode 100644 index 0000000..05c8ae4 --- /dev/null +++ b/src/cmd/retroforth/examples/casket/rancid/templates/header.html @@ -0,0 +1,81 @@ + + + + + Rancid: An IRC Log Viewer + + + + +

    Rancid

    diff --git a/src/cmd/retroforth/examples/casket/rancid/templates/rancid.css b/src/cmd/retroforth/examples/casket/rancid/templates/rancid.css new file mode 100644 index 0000000..825ed59 --- /dev/null +++ b/src/cmd/retroforth/examples/casket/rancid/templates/rancid.css @@ -0,0 +1,199 @@ +body { + font: 100% sans-serif; + background: #ffffff; + color: black; + margin: 2em; + padding: 0em 2em; } + +p.topic-title { + font-weight: bold; } + +table.docinfo { + text-align: left; + margin: 2em 0em; } + +a[href] { + color: #436976; + background-color: transparent; } + +a.toc-backref { + text-decoration: none; } + +h1 a[href] { + color: #003a6b; + text-decoration: none; + background-color: transparent; } + +a.strong { + font-weight: bold; } + +img { + margin: 0; + border: 0; } + +p { + margin: 0.5em 0 1em 0; + line-height: 1.5em; } + +p a:visited { + color: purple; + background-color: transparent; } + +p a:active { + color: red; + background-color: transparent; } + +a:hover { + text-decoration: none; } + +p img { + border: 0; + margin: 0; } + +p.rubric { + font-weight: bold; + font-style: italic; } + +h1.title { + color: #003a6b; + font-size: 250%; + margin-bottom: 0em; } + +h2.subtitle { + color: #003a6b; + border-bottom: 0px; } + +h1, h2, h3, h4, h5, h6 { + color: #555; + background-color: transparent; + margin: 0em; + padding-top: 0.5em; } + +h1 { + font-size: 160%; + margin-bottom: 0.5em; + border-bottom: 2px solid #aaa; } + +h2 { + font-size: 140%; + margin-bottom: 0.5em; + border-bottom: 1px solid #aaa; } + +h3 { + font-size: 130%; + margin-bottom: 0.5em; } + +h4 { + font-size: 110%; + font-weight: bold; + margin-bottom: 0.5em; } + +h5 { + font-size: 105%; + font-weight: bold; + margin-bottom: 0.5em; } + +h6 { + font-size: 100%; + font-weight: bold; + margin-bottom: 0.5em; } + +dt { + font-style: italic; } + +dd { + margin-bottom: 1.5em; } + +div.admonition, div.note, div.tip, div.caution, div.important { + margin: 2em 2em; + padding: 0em 1em; + border-top: 1px solid #aaa; + border-left: 1px solid #aaa; + border-bottom: 2px solid #555; + border-right: 2px solid #555; } + +div.important { + background: transparent url('../images/important.png') 10px 2px no-repeat; } + +div.caution { + background: transparent url('../images/caution.png') 10px 2px no-repeat; } + +div.note { + background: transparent url('../images/note.png') 10px 2px no-repeat; } + +div.tip { + background: transparent url('../images/tip.png') 10px 2px no-repeat; } + +div.admonition-example { + background: transparent url('../images/tip.png') 10px 2px no-repeat; } + +div.admonition-critical-example { + background: transparent url('../images/important.png') 10px 2px no-repeat; } + +p.admonition-title { + font-weight: bold; + border-bottom: 1px solid #aaa; + padding-left: 30px; } + +table.docutils { + text-align: left; + border: 1px solid gray; + border-collapse: collapse; + width: 100%; + margin: 1.5em 0em; } + +table.docutils caption { + font-style: italic; } + +table.docutils td, table.docutils th { + padding: 0.25em 0.5em; } + +table.docutils th { + background-color: #dddddd; } + +div.sidebar { + width: 33%; + float: right; + margin: 0em 2em; + padding: 0em 1em; + border-top: 1px solid #aaa; + border-left: 1px solid #aaa; + border-bottom: 2px solid #555; + border-right: 2px solid #555; } + +p.sidebar-title { + margin-bottom: 0em; + color: #003a6b; + border-bottom: 1px solid #aaa; + font-weight: bold; } + +p.sidebar-subtitle { + margin-top: 0em; + font-style: italic; + color: #003a6b; } + +pre.literal-block { + margin-left: 1em; + margin-right: 1em; + background: #dddddd; } + +ol.simple, ul.simple { + margin-bottom: 1em } + +ol.arabic { + list-style: decimal } + +ol.loweralpha { + list-style: lower-alpha } + +ol.upperalpha { + list-style: upper-alpha } + +ol.lowerroman { + list-style: lower-roman } + +ol.upperroman { + list-style: upper-roman } + +td.label { + width: 8%; } diff --git a/src/cmd/retroforth/examples/casket/rancid/templates/script.erx b/src/cmd/retroforth/examples/casket/rancid/templates/script.erx new file mode 100644 index 0000000..aa1fb0b --- /dev/null +++ b/src/cmd/retroforth/examples/casket/rancid/templates/script.erx @@ -0,0 +1,39 @@ +
    + +
    diff --git a/src/cmd/retroforth/examples/casket/unwell/Makefile b/src/cmd/retroforth/examples/casket/unwell/Makefile new file mode 100644 index 0000000..2b3a127 --- /dev/null +++ b/src/cmd/retroforth/examples/casket/unwell/Makefile @@ -0,0 +1,18 @@ +# Set this to the retro root directory +# +# You should have at least a 'retro' binary, the 'retroImage', and +# 'library' directory there +# +# Note that while you can run Rancid under the Python VM, we need +# the C VM for building (at present) + +RX = ~/code/rx + +default: + @cp $(RX)/retroImage . + @ln -s $(RX)/library . + $(RX)/retro --with unwell.rx --shrink + @rm library + +clean: + @rm -f retroImage diff --git a/src/cmd/retroforth/examples/casket/unwell/autopsy.rx b/src/cmd/retroforth/examples/casket/unwell/autopsy.rx new file mode 100644 index 0000000..417fc30 --- /dev/null +++ b/src/cmd/retroforth/examples/casket/unwell/autopsy.rx @@ -0,0 +1,193 @@ +( unwell - web based debugger for Retro ) +( copyright [c] 2011, Charles Childers ) + +{{ + : decompile ( a-a ) [ ^dissect'decompile ] sip "%d %S\n" puts ; + variable buffer + variable ptr + : terminate ( - ) 0 @ptr ! ; + : start ( -a ) @buffer ; + : end ( -a ) @ptr ; + : add ( c- ) end ! ptr ++ terminate ; + : get ( -c ) ptr -- end @ terminate ; + : empty ( - ) start !ptr terminate ; + : size ( -n ) end start - ; + : set ( a- ) !buffer empty ; + + : image 0 ; + + variable ip + create port 13 allot + create handler 13 allot + + create rs + 1024 allot + rs set + + : ip++ ` 1 ` ip ` +! ; immediate + : rs> get ; + : >rs add ; + : >image ; + + : register: ( p"- ) ' swap handler + ! ; + : (ready) 1 !port ; + : >port port + ; + : port? 0 12 1+ within ; + + : port[ ` >port ` dup ` push ` @ ; immediate + : ]port ` pop ` ! ` (ready) ; immediate + + : reader getc ; + : input port[ 1 = [ reader ] [ 0 ] if ]port ; + 1 register: input + + : output port[ 1 = [ putc ] ifTrue 0 ]port ; + 2 register: output + + : files + [ -1 = ] [ drop [ >image ] dip ^files'open ] when + [ -2 = ] [ drop ^files'read ] when + [ -3 = ] [ drop ^files'write ] when + [ -4 = ] [ drop ^files'close ] when + [ -5 = ] [ drop ^files'pos ] when + [ -6 = ] [ drop ^files'seek ] when + [ -7 = ] [ drop ^files'size ] when + [ -8 = ] [ drop >image ^files'delete ] when + [ 1 = ] [ drop 0 ] when + [ 2 = ] [ drop >image :include 0 ] when + drop 0 ; + + : vm-files port[ files ]port ; + 4 register: vm-files + + : query + [ -1 = ] [ drop 32768 ] when + [ -5 = ] [ drop depth ] when + [ -6 = ] [ drop size ] when + [ -8 = ] [ drop time ] when + [ -9 = ] [ drop 32768 !ip 0 ] when + [ -10 = ] [ drop &>image bi@ getEnv 0 ] when + drop 0 ( default ) ; + + : vm-info port[ query ]port ; + 5 register: vm-info + + : handle dup handler + @ dup [ 0; do ] [ 2drop ] if ; + : ?handle dup >port @ &handle &drop if ; + : i/o 12 [ 0; ?handle ] iterd ; + + : (jmp) ` ip ` @ ` >image ` @ ` 1- ` ip ` ! ; immediate + + : vm_nop ; + : vm_lit ip++ ip @ >image @ ; + ( Native dup, drop, swap ) + : vm_push >rs ; + : vm_pop rs> ; + : vm_loop ip++ 1- dup 0 > [ (jmp) ] [ drop ] if ; + : vm_jmp ip++ (jmp) ; + : vm_ret rs> !ip ; + : vm_>jmp ip++ > [ (jmp) ] ifTrue ; + : vm_jmp ip++ <> [ (jmp) ] ifTrue ; + : vm_=jmp ip++ = [ (jmp) ] ifTrue ; + : vm_@ >image @ ; + : vm_! >image ! ; + ( Native +, -, *, ) + : vm_/mod 2over [ 0 = ] bi@ or [ 32768 !ip "\nError: divide by zero detected\n" puts ] [ /mod ] if ; + ( Native and, or, xor, shl , shr ) + : vm_0exit dup 0 = [ drop rs> ip ! ] ifTrue ; + ( Native inc [1+], dec [1-] ) + : vm_in >port dup [ @ 0 ] dip ! ; + : vm_out dup port? [ >port ! ] [ 2drop ] if ; + : vm_wait port @ 1 <> &i/o ifTrue ; + + create opcodes + &vm_nop , &vm_lit , &dup , + &drop , &swap , &vm_push , + &vm_pop , &vm_loop , &vm_jmp , + &vm_ret , &vm_>jmp , &vm_jmp , &vm_=jmp , &vm_@ , + &vm_! , &+ , &- , + &* , &vm_/mod , &and , + &or , &xor , &<< , + &>> , &vm_0exit , &1+ , + &1- , &vm_in , &vm_out , + &vm_wait , + + create counts + 32 allot + variable calls + + : process + @ip >image @ dup 0 30 within + [ 1 over counts + +! opcodes + @ do ] + [ calls ++ @ip >rs 1- !ip ] if ; + + : --- ( - ) + 24 [ '- putc ] times cr ; + + : displayRegisters ( - ) + depth size @ip "IP: %d RSP: %d SP: %d" puts .s cr ; + + : displayInstruction ( - ) + @ip decompile drop ; + + variable (steps) + + : step ( - ) + (steps) ++ + size 0 >= 0; drop + cr --- displayRegisters displayInstruction --- + process ip ++ ; + + : steps ( n- ) + &step times ; + + : stats ( - ) + @(steps) "\nTotal instructions processed: %d\n" puts + @calls "\n%d calls\n" puts + counts @+ "NOP: %d\n" puts + @+ "LIT: %d\n" puts + @+ "DUP: %d\n" puts + @+ "DROP: %d\n" puts + @+ "SWAP: %d\n" puts + @+ "PUSH: %d\n" puts + @+ "POP: %d\n" puts + @+ "LOOP: %d\n" puts + @+ "JUMP: %d\n" puts + @+ "RET: %d\n" puts + @+ ">JUMP: %d\n" puts + @+ "<JUMP: %d\n" puts + @+ "<>JUMP: %d\n" puts + @+ "=JUMP: %d\n" puts + @+ "@: %d\n" puts + @+ "!: %d\n" puts + @+ "+: %d\n" puts + @+ "-: %d\n" puts + @+ "*: %d\n" puts + @+ "/MOD: %d\n" puts + @+ "AND: %d\n" puts + @+ "OR: %d\n" puts + @+ "XOR: %d\n" puts + @+ "<<: %d\n" puts + @+ ">>: %d\n" puts + @+ "0;: %d\n" puts + @+ "1+: %d\n" puts + @+ "1-: %d\n" puts + @+ "IN: %d\n" puts + @+ "OUT: %d\n" puts + @ "WAIT: %d\n" puts ; +---reveal--- + : /trace ( "- ) + commonHeader + "trace.erx" withTemplate + counts 0 31 fill + 0 !calls + empty 0 !(steps) + casket:options dup 1 > [ "here ]] " ^strings'prepend " ;" ^strings'append withLength eval listen !ip ] [ drop 0 !ip ] if + "
    " puts
    +        2000 steps
    +      cr stats
    +      "
    " puts + commonFooter ; +}} diff --git a/src/cmd/retroforth/examples/casket/unwell/templates/css b/src/cmd/retroforth/examples/casket/unwell/templates/css new file mode 100644 index 0000000..41aa95e --- /dev/null +++ b/src/cmd/retroforth/examples/casket/unwell/templates/css @@ -0,0 +1,7 @@ +body { background: #222; color: #ccc; } +a { text-decoration: none; color: #ccc; border-bottom: 1px solid #ccc; } +#nav { position: absolute; top: 0; right: 10px; } +#nav a { text-decoration: none; border: 1px solid black; padding: 3px 10px; background: #444; color: #fff; border-radius: 4px; } +#nav a:hover { background: #777; color: #fff; } +#output { background: #444; position: relative; color: #fff; border-radius: 4px; width: 800px; } +tt { white-space: pre; } diff --git a/src/cmd/retroforth/examples/casket/unwell/templates/eval.erx b/src/cmd/retroforth/examples/casket/unwell/templates/eval.erx new file mode 100644 index 0000000..6f14826 --- /dev/null +++ b/src/cmd/retroforth/examples/casket/unwell/templates/eval.erx @@ -0,0 +1,11 @@ + +
    +

    Code to evaluate:

    +
    +

    Press enter or click evaluate to + run your code.

    diff --git a/src/cmd/retroforth/examples/casket/unwell/templates/examine.erx b/src/cmd/retroforth/examples/casket/unwell/templates/examine.erx new file mode 100644 index 0000000..5c67a2b --- /dev/null +++ b/src/cmd/retroforth/examples/casket/unwell/templates/examine.erx @@ -0,0 +1,14 @@ + +
    +

    Code to examine:

    +
    +

    Press enter or click examine to + display decompilation of your code.

    + +

    Do not provide a colon definition; the pasted code will be + compiled inside a quote and displayed.

    diff --git a/src/cmd/retroforth/examples/casket/unwell/templates/footer.html b/src/cmd/retroforth/examples/casket/unwell/templates/footer.html new file mode 100644 index 0000000..a318390 --- /dev/null +++ b/src/cmd/retroforth/examples/casket/unwell/templates/footer.html @@ -0,0 +1,10 @@ + + + diff --git a/src/cmd/retroforth/examples/casket/unwell/templates/header.html b/src/cmd/retroforth/examples/casket/unwell/templates/header.html new file mode 100644 index 0000000..4c0c520 --- /dev/null +++ b/src/cmd/retroforth/examples/casket/unwell/templates/header.html @@ -0,0 +1,12 @@ + + + + unwell + + + +

    unwell: debugging from a browser

    + +
    diff --git a/src/cmd/retroforth/examples/casket/unwell/templates/trace.erx b/src/cmd/retroforth/examples/casket/unwell/templates/trace.erx new file mode 100644 index 0000000..01b78fe --- /dev/null +++ b/src/cmd/retroforth/examples/casket/unwell/templates/trace.erx @@ -0,0 +1,14 @@ + +
    +

    Code to examine:

    +
    +

    Press enter or click examine to + display decompilation of your code.

    + +

    Do not provide a colon definition; the pasted code will be + compiled inside a quote and executed in a sandbox.

    diff --git a/src/cmd/retroforth/examples/casket/unwell/unwell.rx b/src/cmd/retroforth/examples/casket/unwell/unwell.rx new file mode 100644 index 0000000..1d7d1fe --- /dev/null +++ b/src/cmd/retroforth/examples/casket/unwell/unwell.rx @@ -0,0 +1,197 @@ +( unwell - web based debugger for Retro ) +( copyright [c] 2011, Charles Childers ) + +( ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +( Some notes on this: ) +( - it is *not* a replacement for Autopsy ) +( - as with most of the things I develop, this is primarily for my personal ) +( use ) +( ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) + +needs casket' +needs dissect' +with casket' + + +( ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +( Custom decompiler. The standard autopsy debugger doesn't output HTML, so we ) +( create our own here. ) +( ) +( Of interest here is buildString, which builds a string from tokens returned ) +( by a quote. This is useful in various contexts, not limited to this code. ) +( ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) + +{{ + variable this + variable str + + : asc " ' ' " ; + + : pad ( $n-$ ) [ 32 ^strings'appendChar ] times ; + + : buildString ( q-$ ) + depth [ do ] dip depth swap - 1- [ ^strings'append ] times ; + + : following + @this @ toString this ++ ; + + : padName ( $-$ ) + withLength @str getLength - 24 swap - dup 0 > &pad &drop if ; + + : appendName ( $-$ ) + padName + @str toNumber 32 127 within + [ @str toNumber asc 2 + ! asc ^strings'append ] [ 5 pad ] if + @str toNumber xt->d dup [ d->name ^strings'append ] &drop if ; + + : buildLink ( $- ) + keepString !str + [ "" @str "" ] buildString appendName ; + + : instr ( n-af ) + this ++ ^dissect'lookupOpcode + [ [ "call " swap buildLink ^strings'append ] dip ] ifFalse ; +---reveal--- + : decompile ( a-a$ ) + dup !this @ instr [ following buildLink ^strings'append ] ifTrue @this swap ; + : display + [ &decompile sip "%d%s\n" puts + dup 1- ^dissect'endOfWord? not ] while drop ; +}} + + + +( ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +( Simplify the header/footer stuff a bit. This will change when I finish the ) +( combinator based HTML generator. ) +( ) +( commonHeader .... commonFooter => [ ... ] stdTemplate ) +( ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) + +: commonHeader ( - ) + Content-type: text/html + "header.html" withTemplate ; + +: commonFooter ( - ) + "footer.html" withTemplate ; + +: stdTemplate ( q- ) + commonHeader do commonFooter ; + + +( ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +( The basic views ) +( ) +( /css ) +( This is the standard stylesheet. The default configuration is to use a ) +( dark color scheme based on the Web and Android releases of Retro ) +( ) +( /index ) +( The default view. This displays a six column table of named items in the) +( dictionary. Clicking them takes you to the /decompile view for the code ) +( in question. ) +( ) +( /decompile/address ) +( Dissassemble the code starting at address. This tries to detect the end ) +( of a function by looking for the standard double VM_RET laid down by the) +( Retro compiler. Jump and call targets are hyperlinked, and both ASCII ) +( and symbolic names for values are displayed. ) +( ) +( /examine/ ) +( Compile and then decompile a bit of code. Useful if you suspect odd bugs) +( related to macros and the like. ) +( ) +( /evaluate/ ) +( Compile and run a bit of code. This is *unsafe* and will be removed or ) +( sandboxed later ) +( ) +( /trace/ ) +( Compile and run a bit of code in a sandboxed environment. Displays the ) +( results of the run, instruction by instruction. This is roughly the same) +( as *steps* in Autopsy. ) +( ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) + +serve: css as text/css + +: /decompile + commonHeader + casket:options toNumber xt->d dup [ d->name "

    Showing decompiled code for %s

    " puts ] [ drop ] if + "
    + + + + " puts + casket:options toNumber display + "
    addressngaro assembly
    " puts + commonFooter ; + + +{{ + 2 elements buffer count + : restore ( - ) &getc :devector ok ; + : get ( -c ) @buffer @ ; + : next ( -c ) @count [ count -- get buffer ++ ] [ 32 restore ] if ; + : replace ( - ) &next &getc :is ; + + : word ( d- ) dup @d->xt swap @d->class withClass ; + : build# ( - ) tib toNumber .data ; + : number ( - ) tib isNumber? [ build# ] [ notFound ] if ; + : process ( af- ) [ word ] [ drop number ] if ; + + + : dump + "
    + + + + " puts + display + "
    addressngaro assembly
    " puts ; +---reveal--- + : eval ( an- ) dup 0 > [ !count !buffer replace ] [ 2drop ] if ; + : listen ( - ) repeat ok 32 accept tib find process &getc @ 0; drop again ; + + : /eval + commonHeader + "eval.erx" withTemplate + "
    " puts
    +      casket:options dup 1 > [ withLength eval listen ] [ drop ] if
    +    "
    " puts + commonFooter ; + + : /examine + commonHeader + "examine.erx" withTemplate + "
    " puts
    +      casket:options dup 1 > [ "here ]] " ^strings'prepend " ;" ^strings'append withLength eval listen dump ] [ drop ] if
    +    "
    " puts + commonFooter ; +}} + + +{{ + variable count +---reveal--- + : /index + commonHeader + here build "

    Image Build ID: %s
    Memory Used: %d cells

    " puts + "

    The following functions are defined in this image:

    " tputs + 0 !count + "
    \n" puts + last [ dup d->name swap @d->xt "" tputs + count ++ @count 6 > [ 0 !count "\n" puts ] ifTrue ] ^types'LIST each@ + @count [ "" puts ] times "\n" puts + "
    %S
    " puts + commonFooter ; +}} + +[ /index ] is / + +include autopsy.rx +hide eval hide listen hide stdTemplate hide commonFooter hide commonHeader hide display hide decompile + +[ ( -$ ) "/path/to/unwell/" ] is casket:root +[ ( -$ ) "http://url/for/unwell" ] is casket:url +&dispatch is boot + +.s save bye diff --git a/src/cmd/retroforth/examples/editor.rx b/src/cmd/retroforth/examples/editor.rx new file mode 100644 index 0000000..725fc56 --- /dev/null +++ b/src/cmd/retroforth/examples/editor.rx @@ -0,0 +1,293 @@ +( retro editor v11-2011.10.25 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +( Key Action ) +( --- ------------------------------------------------- ) +( i Move cursor up ) +( j Move cursor left ) +( k Move cursor down ) +( l Move cursor right ) +( [ Switch to previous block ) +( ] Switch to next block ) +( e Evaluate current block ) +( E Evaluate all blocks ) +( m Move cursor to start of next line ) +( I Move cursor to top line of block ) +( J Move cursor to start of current line ) +( K Move cursor to last line of block ) +( L Move cursor to end of current line ) +( M Center cursor on current line ) +( z Exit RxE ) +( { Load "blocks" ) +( } Save "blocks" ) +( TAB Switch between edit and command mode ) +( ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) + +chain: editor' + +{{ + 2 elements buffer count + : restore ( - ) &getc :devector ok ; + : get ( -c ) @buffer @ ; + : next ( -c ) @count [ count -- get buffer ++ ] [ 32 restore ] if ; + : replace ( - ) &next &getc :is ; + : eval ( an- ) !count !buffer replace ; + + 7 elements #blocks offset blk line column mode active + : toBlock 1600 * @offset + ; + : thisBlock @blk toBlock ; + : toLine 80 * thisBlock + ; + + ( check boundaries ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) + : top ( - ) 0 !line ; + : bot ( - ) 19 !line ; + : beg ( - ) 0 !column ; + : end ( - ) 79 !column ; + : mid ( - ) 41 !column ; + : 1st ( - ) 0 !blk ; + : bounds ( - ) + @column -1 = [ end line -- ] ifTrue + @column 80 = [ beg line ++ ] ifTrue + @line -1 = [ top blk -- ] ifTrue + @line 20 = [ bot blk ++ ] ifTrue + @blk -1 = [ 1st ] ifTrue + @blk @#blocks >= [ blk -- ] ifTrue ; + + ( display a block ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) + : rows 20 [ dup 80 [ @ putc ] ^types'BUFFER each@ 80 + cr ] times ; + : mode? @mode [ "INS" ] [ "CMD" ] if ; + : .block @column @line @blk mode? "(%s) #%d - %d:%d " puts ; + : bar 80 [ '- putc ] times cr ; + : vb @blk toBlock rows drop bar .block ; + : (v) ( - ) clear vb ; + : pos ( -cl ) @column @line ; + : get ( cl-a ) toLine + ; + : va ( a-va ) dup @ swap ; + : c! ( a- ) '* swap ! ; + : show ( va- ) dup c! (v) ! ; + : display ( - ) bounds pos get va show ; + + ( input processing ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) + : advance? ( - ) line ++ @line 20 >= [ 0 !line blk ++ ] ifTrue 0 !column ; + : del ( - ) + @column dup + [ dup 80 = + [ drop !column display 0 ] + [ 32 over @line get ! 1+ -1 ] if + ] while ; + : remap ( c-c ) + dup 9 = [ drop 27 ] ifTrue + dup 13 = [ drop 0 ] ifTrue + dup 10 = [ drop 0 advance? display ] ifTrue ; + : input ( - ) + repeat + display + @mode 0; drop + getc 0; + dup 27 <> 0; drop + dup 8 = [ drop column -- display ] [ pos get ! column ++ ] if + again ; + : rxe.in ( -c ) mode on remapping [ remapping off input ] preserve mode off ; + : match ( c- ) "$$_" dup [ 2 + ! ] dip find [ @d->xt do ] &drop if ; + : edit? ( c-c ) dup 27 = [ rxe.in drop ] ifTrue ; + + ( various support bits ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) + : new ( - ) @offset 32 1600 @#blocks * fill ; + : e ( - ) thisBlock 1600 eval ; + : ea ( - ) @offset @#blocks 1600 * eval ; + : run ( - ) + active on &remap &remapKeys :is clear + [ display getc edit? match @active ] while ; +---reveal--- + : setBlocks ( n- ) !#blocks @memory 1600 @#blocks * - !offset new ; + : edit ( - ) + @ch 22 >= @cw 80 >= and + &run [ "requires an 80x22 or greater display, sorry!\n" puts ] if ; + : $$i line -- ; + : $$j column -- ; + : $$k line ++ ; + : $$l column ++ ; + : $$m $$k beg ; + : $$I top ; + : $$J beg ; + : $$K bot ; + : $$L end ; + : $$M mid ; + : $$D del ; + : $$[ blk -- ; + : $$] blk ++ ; + : $${ @offset "blocks" ^files'slurp drop ; + : $$} @offset @#blocks 1600 * "blocks" ^files'spew drop ; + : $$e active off e ; + : $$E active off ea ; + : $$z active off ; + 128 setBlocks +}} +;chain + +global +with editor' + + +doc{ + +============ +Retro Editor +============ + + +-------- +Overview +-------- +The Retro Editor is a block editor for use with Retro. + +For most users, files are a better choice. However there are +at least two cases where you may want or need to use them: + + * keeping sources embeded in the image + * if you are using a VM that lacks file i/o + + +------- +Loading +------- + +:: + + include editor.rx + + +----------- +Quick Guide +----------- + +Starting +======== +Once loaded, you'll need to start it using **edit**: + +:: + + edit + + +The Interface +============= + +You'll see a screen looking something like: + +:: + + * + + + + + + + + + + + + + + + + + + + + -------------------------------------------------------------------------------- + (CMD) #0 - 0:0 + + +The asterisk at the top is the cursor. The line at the +bottom marks the end of the current block. Below the line +is a status row, showing the current mode (CMD or INS), the +current block number, and the current row and column. + + +Exiting +======= +Press *z*. This should return you to the Retro listener. + + +Navigation +========== +Restart the editor with **edit**. + +The following keys can be used to navigate through the +blocks. + ++-----+--------------------------------------------+ +| Key | Used for | ++=====+============================================+ +| i | Move cursor up | ++-----+--------------------------------------------+ +| j | Move cursor left | ++-----+--------------------------------------------+ +| k | Move cursor down | ++-----+--------------------------------------------+ +| l | Move cursor right | ++-----+--------------------------------------------+ +| [ | Switch to previous block | ++-----+--------------------------------------------+ +| ] | Switch to next block | ++-----+--------------------------------------------+ +| m | Move cursor to start of next line | ++-----+--------------------------------------------+ +| I | Move cursor to top line of block | ++-----+--------------------------------------------+ +| J | Move cursor to start of current line | ++-----+--------------------------------------------+ +| K | Move cursor to last line of block | ++-----+--------------------------------------------+ +| L | Move cursor to end of current line | ++-----+--------------------------------------------+ +| M | Center cursor on current line | ++-----+--------------------------------------------+ + + +Entry Mode +========== +Use the *tab* key to switch to entry mode, and again to +switch back to command mode. + + +Evaluating Code +=============== +When you're ready to process the code you've entered, use +the following keys to pass the code to the listener. + +**Note:** *This will stop the editor from running. You will +have to restart it manually after evaluating code.* + ++-----+--------------------------------------------+ +| Key | Used for | ++=====+============================================+ +| e | Evaluate current block | ++-----+--------------------------------------------+ +| E | Evaluate all blocks | ++-----+--------------------------------------------+ + + +Loading And Saving +================== +Blocks are stored in the image file. If you are using a VM +that supports the files' vocabulary, you can use the following +keys to import and export the blocks to regular files. + ++-----+--------------------------------------------+ +| Key | Used for | ++=====+============================================+ +| { | Load the contents of "blocks" | ++-----+--------------------------------------------+ +| } | Store all blocks into "blocks" | ++-----+--------------------------------------------+ + + +----------- +Misc. Notes +----------- +Retro's blocks are 1600 cells in length each. They are displayed as +80 columns and 20 rows. + +}doc diff --git a/src/cmd/retroforth/examples/games/chess.rx b/src/cmd/retroforth/examples/games/chess.rx new file mode 100644 index 0000000..1f0d7f1 --- /dev/null +++ b/src/cmd/retroforth/examples/games/chess.rx @@ -0,0 +1,87 @@ +doc{ +=============== +Chess for Retro +=============== + + +-------- +Overview +-------- +This is a simple console-based chess game for two human players. It was +inspired by Ray St. Marie's c4thches3 for colorForth, and draws a bit from +"RetroChess" and "RetroChess for Reva", which were earlier implementations. + + +-------- +Gameplay +-------- +The game starts with **new**: + +:: + + new + +This will display a board: + +:: + + 0 1 2 3 4 5 6 7 + +-----------------+ + 0 | r n b q k b n r | + 1 | p p p p p p p p | + 2 | . . . . . . . . | + 3 | . . . . . . . . | + 4 | . . . . . . . . | + 5 | . . . . . . . . | + 6 | P P P P P P P P | + 7 | R N B Q K B N R | + +-----------------+ + 0 1 2 3 4 5 6 7 + +Then you can move a piece by using **move**: + +:: + + move 1,0 3,0 + +This would then display: + +:: + + 0 1 2 3 4 5 6 7 + +-----------------+ + 0 | r n b q k b n r | + 1 | . p p p p p p p | + 2 | . . . . . . . . | + 3 | p . . . . . . . | + 4 | . . . . . . . . | + 5 | . . . . . . . . | + 6 | P P P P P P P P | + 7 | R N B Q K B N R | + +-----------------+ + 0 1 2 3 4 5 6 7 + +Moves are specified as a starting row and column and an ending row and +column. The game does not do any checks to ensure that moves are valid. +We assume that you know how to play and will only make valid moves. +}doc + + +{{ + + "rnbqkbnrpppppppp................................PPPPPPPPRNBQKBNR" string BLANK + + create board + 64 allot + + : --- ( - ) " +-----------------+\n" puts ; + : ### ( - ) " 0 1 2 3 4 5 6 7 \n" puts ; + : row ( a-a ) "%d | " puts 8 [ @+ putc space ] times "|\n" puts ; + + : r,c ( ""-nn ) ', accept tib toNumber getNumber swap ; + : get ( ""-a ) r,c 8 * board 2+ ; +---reveal--- + : display ( - ) cr ### --- board 8 [ row ] iter drop --- ### cr ; + : new ( - ) BLANK board 64 copy display ; + : move ( ""- ) get dup @ [ '. swap ! ] dip get ! display ; +}} diff --git a/src/cmd/retroforth/examples/games/cloak-of-darkness.rx b/src/cmd/retroforth/examples/games/cloak-of-darkness.rx new file mode 100644 index 0000000..33df49f --- /dev/null +++ b/src/cmd/retroforth/examples/games/cloak-of-darkness.rx @@ -0,0 +1,267 @@ +( ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +( embalm - interactive fiction ) +( copyright [c] 2011, Charles Childers ) +( ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) + +needs array' +needs struct' +needs enum' +needs linkedList' + +with struct' + + +( ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +( At a fundamental level, everything derives from a single generic "object" ) +( structure. This contains a lot of fields, most of which aren't relevant to ) +( all of the objects. So there's some waste here, but it simplfies things ) +( overall. ) +( ) +( The objects have a .type field. We use the enum' library to create a series ) +( of enumerated data types. Each object gets tagged with a type, so we can ) +( enumerate things later. And functions can use this to prevent execution on ) +( objects that they do not support. ) +( ) +( When you create an object, you should provide a short name, and a detailed ) +( description. ) +( ) +( So: ) +( ) +( object foo ) +( "Foo" nameOf foo ) +( "This is a small brass key." describes foo ) +( ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) + +1 ^enum'enum| ROOM ITEM | + +{ 1 field .description + 1 field .shortDescription + 1 field .type + 1 field .onLook + 1 field .onEntry + 1 field .location + 1 field .visited + 1 field .toNorth + 1 field .toSouth + 1 field .toEast + 1 field .toWest + 1 field .onNorth + 1 field .onSouth + 1 field .onEast + 1 field .onWest + 1 field .postDescription + 1 field .preDescription + 1 field .onRead +} object + +: describes ( $"- ) + keepString ' .description ! ; + +: nameOf ( $"- ) + keepString ' .shortDescription ! ; + + +( ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +( Creation of Rooms ) +( ) +( ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) + +: room ( "- ) + object ROOM @last @d->xt .type ! ; + +: invertDirection ( a$-a ) + [ "north" compare ] [ .toSouth ] whend + [ "south" compare ] [ .toNorth ] whend + [ "east" compare ] [ .toWest ] whend + [ "west" compare ] [ .toEast ] whend + drop ; + +: is ( a""""- ) + getToken invertDirection getToken drop ' swap ! ; + + + +( ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +( Creation of items ) +( ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) + +^linkedList'new: items + +: item ( "- ) + object ITEM @last @d->xt .type ! + @last @d->xt items ^linkedList'b.add ; + +: contains ( a"- ) + ' .location ! ; + +: has? ( a-af ) + dup .location @ 0 = ; + +: displayItem ( a- ) + dup .shortDescription @ swap xt->d d->name "(%s) - %s\n" puts ; + +: inventory ( - ) + "\nYou are carrying:\n" puts + items [ ^linkedList'.value @ has? [ displayItem ] [ drop ] if ] ^types'LIST each@ ; + + +( ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +( Game Play Loop ) +( ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) + +variable at + +: invalidDirection ( - ) + "You can not go in that direction.\n" puts ; + +: moveNorth ( - ) + @at .onNorth @ + [ @at .onNorth @ do @at .toNorth @ 0; !at ] + [ @at .toNorth @ 0 <> + [ @at .toNorth @ !at ] + [ invalidDirection ] if ] if ; + +: moveSouth ( - ) + @at .onSouth @ + [ @at .onSouth @ do @at .toSouth @ 0; !at ] + [ @at .toSouth @ 0 <> + [ @at .toSouth @ !at ] + [ invalidDirection ] if ] if ; + +: moveEast ( - ) + @at .onEast @ + [ @at .onEast @ do @at .toEast @ 0; !at ] + [ @at .toEast @ 0 <> + [ @at .toEast @ !at ] + [ invalidDirection ] if ] if ; + +: moveWest ( - ) + @at .onWest @ + [ @at .onWest @ do @at .toWest @ 0; !at ] + [ @at .toWest @ 0 <> + [ @at .toWest @ !at ] + [ invalidDirection ] if ] if ; + +: describeCurrentRoom ( - ) + @at .shortDescription @ puts 2cr + [ @at .preDescription @ 0; do ] do + @at .visited @ + [ @at .description @ puts 2cr -1 @at .visited ! ] ifFalse + [ @at .postDescription @ 0; do ] do ; + +: play ( - ) + clear + repeat + describeCurrentRoom + "> " puts getToken + [ [ "n" compare ] [ moveNorth ] whend + [ "s" compare ] [ moveSouth ] whend + [ "e" compare ] [ moveEast ] whend + [ "w" compare ] [ moveWest ] whend + [ "l" compare ] [ @at .description @ puts ] whend + [ "i" compare ] [ inventory ] whend + [ "drop" compare ] [ getToken find [ @d->xt .location @at swap ! ] [ drop ] if ] whend + [ "take" compare ] [ getToken find [ @d->xt .location 0 swap ! ] + [ "\nI don't see that here.\n" puts ] if ] whend + [ "x" compare ] + [ getToken find + [ @d->xt dup .location @ [ @at = ] [ 0 = ] bi or + [ .description @ puts cr ] [ drop "\nI don't see that here.\n" puts ] if + ] [ "\nI don't see that here\n" puts ] if ] whend + + [ "read" compare ] [ getToken find + [ @d->xt dup .location @ [ @at = ] [ 0 = ] bi or + [ .onRead @ dup [ do ] [ "You can't read this" puts ] if ] [ drop "\nI don't see that here.\n" puts ] if + ] [ "\nI don't see that here\n" puts ] if ] whend + [ "quit" compare ] [ "\n\nThanks for playing!\n\n" puts bye ] whend + ] do + 2cr + again ; + + +( ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +( A sample game based on Cloak of Darkness ) +( ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) + +variable blunders + +room foyer +room bar +room cloakroom +item cloak +item hook +item message + +( ==[ cloak ]================================================================ ) +"velvet cloak" nameOf cloak + +"A handsome cloak, of velvet trimmed with statin, and slightly splattered\n +raindrops. Its blackness is so deep that it almost seems to suck light from\n +the room." describes cloak + + + +( ==[ cloak ]================================================================ ) +"brass hook" nameOf hook + +"It's just a small brass hook. You could probably hang a cloak on +it." describes hook + + +( ==[ message ]============================================================== ) + +"message" nameOf message + +"There appears to be something scrawled in the sawdust on the floor." describes +message + +[ cloak .location @ cloakroom = + [ @blunders 2 >= [ "\nThe message reads 'You win!'\n\n" puts bye ] + [ "\nThe message is heavily smudged due to your blundering, but you can make\nout the words 'You lose!'\n\n" puts bye ] if ] + [ "It's too dark to read anything here.\n" puts ] if ] message .onRead ! + + +( ==[ foyer ]================================================================ ) +"The Foyer" nameOf foyer + +"You are standing in a spacious hall, splendidly decorated in red and gold\n +with glittering chandeliers overhead. The entrance from the street is to the\n +north, and there are doorways south and west." describes foyer + +[ "You've only just arrived, and besides, the weather outside seems to be\n +getting worse.\n" puts ] foyer .onNorth ! + +foyer is north of bar +foyer is east of cloakroom + +foyer !at + +( ==[ cloakroom ]============================================================ ) +"Cloakroom" nameOf cloakroom + +"The walls of this small room were clearly once lined with hooks, though now\n +only one remains. The exit is a door to the east." describes cloakroom + +cloakroom is west of foyer + +cloakroom contains hook + + +( ==[ bar ]================================================================== ) +"Foyer Bar" nameOf bar + +"The bar, much rougher than you'd have guessed after the opulence of of the\n +foyer to the north, is completely empty.\n\n +There seems to be some sort of message scrawled in the sawdust on the +floor." describes bar + +[ cloak .location @ cloakroom <> [ "It is very dark in here.\n\n" puts ] ifTrue ] +bar .postDescription ! + +[ blunders ++ ] foyer .onEast ! +[ blunders ++ ] foyer .onWest ! +[ blunders ++ ] foyer .onSouth ! + +bar is south of foyer + +bar contains message diff --git a/src/cmd/retroforth/examples/games/hangman/dict.retro b/src/cmd/retroforth/examples/games/hangman/dict.retro new file mode 100644 index 0000000..7f7520f --- /dev/null +++ b/src/cmd/retroforth/examples/games/hangman/dict.retro @@ -0,0 +1,49 @@ +( ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +( Hangman for Retro Console ) +( * System dictionary access. ) +( ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +( Copyright [c] 2010-11, Marc Simpson ) +( License: ISC ) +( ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) + +( --[ Variables ]--------------------------------------------- ) + +: sys-dict "wordlist.txt" ^files':R ; + +variable dict +create dict-word 80 allot +variable dict-size + +( --[ Access ]------------------------------------------------ ) + +: open-dict ( -h ) sys-dict ^files'open dup 0 < + [ "\nError: can't open dictionary." puts ] ifTrue ; + +: init ( -h ) open-dict dup 0 < if; + dup dup !dict ^files'size !dict-size ; + +: initialise ( - ) @dict 0 = [ init 0 > + [ "\nInitialisation successful." puts ] + [ "\nInitialisation failed." puts ] if + ] ifTrue ; + +: toRandom ( n-n ) ^math'random swap /mod drop ; +: rand-off ( -n ) @dict-size toRandom ; +: rand-pos ( -n ) rand-off @dict ^files'seek drop ; + +: >line ( - ) repeat @dict ^files'read 10 = if; again ; +: fread! ( ha-f ) swap ^files'read dup rot ! ; +: (readline) ( - ) dict-word repeat @dict over fread! drop + dup @ 10 = if; 1+ again ; +: readline ( a- ) (readline) 0 swap ! ; + +: rand-word ( - ) rand-pos >line readline ; +: close-dict ( - ) @dict ^files'close 0 <> + [ "Error: Can't close dictionary." puts ] ifTrue ; + +( --[ Retrieval ]--------------------------------------------- ) + +: get-word ( -$ ) + rand-word dict-word dup ^strings'toLower over withLength copy ; + +( ============================================================ ) diff --git a/src/cmd/retroforth/examples/games/hangman/graphics.retro b/src/cmd/retroforth/examples/games/hangman/graphics.retro new file mode 100644 index 0000000..3d34b32 --- /dev/null +++ b/src/cmd/retroforth/examples/games/hangman/graphics.retro @@ -0,0 +1,41 @@ +( ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +( Hangman for Retro Console ) +( * Drawing routines. ) +( ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +( Copyright [c] 2010-11, Marc Simpson ) +( License: ISC ) +( ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) + +needs console' + +( --[ Drawing Routines ]-------------------------------------- ) + +: bar ( xyn- ) [ ^console'at-xy ] dip [ '- putc ] times ; +: col ( xyn- ) [ 2over ^console'at-xy '| putc 1+ ] times 2drop ; + +( --[ Stages ]------------------------------------------------ ) + +( NOTE: 13 is FIXED unless we add more drawing XTs ) + +13 constant stages + +create graphics stages allot +graphics variable: current-graphic + +: graphic, @current-graphic ! current-graphic ++ ; + +[ 20 15 15 bar ] graphic, +[ 20 5 10 col ] graphic, +[ 20 5 15 bar ] graphic, +[ 21 6 ^console'at-xy '/ putc ] graphic, +[ 30 6 2 col ] graphic, +[ 30 8 ^console'at-xy '@ putc ] graphic, +[ 30 9 1 col ] graphic, +[ 29 9 ^console'at-xy '/ putc ] graphic, +[ 31 9 ^console'at-xy '\ putc ] graphic, +[ 30 9 1 col ] graphic, +[ 30 10 1 col ] graphic, +[ 29 11 ^console'at-xy '/ putc ] graphic, +[ 31 11 ^console'at-xy '\ putc ] graphic, + +( ============================================================ ) diff --git a/src/cmd/retroforth/examples/games/hangman/hangman b/src/cmd/retroforth/examples/games/hangman/hangman new file mode 100755 index 0000000..5b45822 --- /dev/null +++ b/src/cmd/retroforth/examples/games/hangman/hangman @@ -0,0 +1,14 @@ +#! /bin/sh + +if [ ! -f "wordlist.txt" ]; then + if [ -f "/usr/share/dict/words" ]; then + echo "Wordlist missing -- symlinking the system dictionary." + ln -s /usr/share/dict/words wordlist.txt + fi +fi + +if [ ! -f "library" ]; then + ln -s ../../../library . +fi + +../../../retro --image ../../../retroImage --with hangman.retro diff --git a/src/cmd/retroforth/examples/games/hangman/hangman.retro b/src/cmd/retroforth/examples/games/hangman/hangman.retro new file mode 100644 index 0000000..4acdb1c --- /dev/null +++ b/src/cmd/retroforth/examples/games/hangman/hangman.retro @@ -0,0 +1,110 @@ +( ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +( Hangman for Retro Console ) +( * Main game logic. ) +( ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +( Copyright [c] 2010-11, Marc Simpson ) +( License: ISC ) +( ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) + +needs console' + +( File inclusion will only work if you're running retro from ) +( the same directory as hangman. ) + +include graphics.retro +include dict.retro + +( --[ Variables ]--------------------------------------------- ) + +5 elements target guessed lifeline this-char foul-count +stages constant lives ( see graphics.retro ) +create foul-addr lives allot + +( --[ Offset Calculation ]------------------------------------ ) + +( Build an array with offsets for a given character in string ) + +: offsets, ( c$- ) + withLength [ [ 2over @ = ] dip swap &, &drop if 1+ ] iter + 2drop ; + +: offsets ( $c-an ) here 2rot swap offsets, here over - ; + +( --[ Allocation ]-------------------------------------------- ) + +: unallot ( n- ) negate allot ; +: unarray ( an- ) nip unallot ; + +( --[ Masking ]----------------------------------------------- ) + +( The array contains offset information; set the guess string ) + +: update-guessed ( $ offsets len - ) + [ 2over @ + @this-char swap ! 1+ ] times 2drop ; + +: toGuess ( guessed target c - ) + dup !this-char offsets ( guessed offsets length ) + 2over [ &update-guessed dip ] dip unarray ; + +: guessChar ( c- ) @guessed @target rot toGuess ; + +( --[ Printing ]---------------------------------------------- ) + +: .target ( - ) @target puts ; +: .guessed ( - ) @guessed puts ; +: .input ( - ) @lifeline "Tries: (%d): " puts ; +: .fouls ( - ) "Fouls: " puts foul-addr puts ; +: .prompt ( - ) 0 0 ^console'at-xy .guessed cr .fouls cr .input ; +: .already ( - ) " [already guessed]" puts ; +: .correct ( - ) " [correct guess] " puts ; +: .graphic ( - ) lives @lifeline - 1- graphics + @ do ; +: .wrong ( - ) " [not present] " puts .graphic ; + +( --[ Guessing ]---------------------------------------------- ) + +: 0<> ( x-f ) 0 = not ; +: has ( $c-f ) ^strings'findChar 0<> ; + +: foul+ ( c- ) foul-addr @foul-count + ! foul-count ++ ; + +: (guess) ( c- ) + @guessed over has + [ .already ] + [ @target over has + [ dup guessChar .correct ] + [ foul-addr over has + [ .already ] + [ dup foul+ lifeline -- .wrong ] if ] if ] if drop ; + +: guess ( - ) .prompt getc &putc &(guess) bi ; + +( --[ Game Logic ]-------------------------------------------- ) + +: _string ( n-$ ) here swap [ '_ , ] times 0 , ; + +: >target ( $- ) withLength swap !target _string !guessed ; + +: 0fouls ( - ) 0 !foul-count + foul-addr lives [ 0 over ! 1+ ] times drop ; + +: revive ( - ) lives !lifeline 0fouls ; +: remaining ( -f ) guessed @ '_ has ; +: alive ( -f ) remaining lifeline @ 0<> and ; +: dead? ( -f ) alive not ; +: foot ( - ) 0 20 ^console'at-xy ; +: .lose ( - ) foot "You LOSE; the word was: " puts .target ; +: .win ( - ) foot .target "\nYou WIN!" puts ; +: endgame ( - ) @lifeline &.win &.lose if ; + +: (hangman) ( - ) clear repeat dead? if; guess again ; +: hangman ( $- ) >target revive (hangman) endgame ; + +( --[ Main Game ]--------------------------------------------- ) + +: y-or-n ( -f ) getc [ 'y = ] [ 'Y = ] bi or ; +: .again? ( -f ) "\n\nPlay again? [Y/N] " puts y-or-n ; +: play ( - ) + initialise @dict 0; drop + repeat get-word hangman .again? [ close-dict bye ] ifFalse again ; +( ============================================================ ) +play diff --git a/src/cmd/retroforth/examples/games/life.rx b/src/cmd/retroforth/examples/games/life.rx new file mode 100644 index 0000000..48a86a9 --- /dev/null +++ b/src/cmd/retroforth/examples/games/life.rx @@ -0,0 +1,95 @@ +( Conway's Game of Life ) +( Copyright [c] 2011, charles Childers ) + +create world + 20 20 * allot + +create next + 20 20 * allot + +( Assumes anything outside the bounds is "dead" ) +{{ + variable surrounding + : get ( rc- ) + 2over [ 0 19 within ] bi@ and + [ world + [ 20 * ] dip + @ ] [ 2drop 0 ] if ; + : neighbor? ( rc- ) get +surrounding ; + : NW ( rc-rc ) 2over [ 1- ] bi@ neighbor? ; + : NN ( rc-rc ) 2over [ 1- ] dip neighbor? ; + : NE ( rc-rc ) 2over [ 1- ] dip 1+ neighbor? ; + : WW ( rc-rc ) 2over 1- neighbor? ; + : EE ( rc-rc ) 2over 1+ neighbor? ; + : SW ( rc-rc ) 2over [ 1+ ] dip 1- neighbor? ; + : SS ( rc-rc ) 2over [ 1+ ] dip neighbor? ; + : SE ( rc-rc ) 2over [ 1+ ] bi@ neighbor? ; + : count ( rc-rcn ) + 0 !surrounding + NW NN NE + WW EE + SW SS SE @surrounding ; + : alive ( rc-n ) + count + [ 0 1 within ] [ drop 0 ] when + [ 4 8 within ] [ drop 0 ] when + [ 2 3 within ] [ drop 1 ] when ; + : dead ( rc-n ) + count + [ 3 = ] [ drop 1 ] when + [ 0 2 within ] [ drop 0 ] when + [ 4 8 within ] [ drop 0 ] when ; + : newState ( rc-n ) + 2over get 1 = [ alive ] [ dead ] if ; + : set ( nrc- ) next + [ 20 * ] dip + ! ; + : cols ( r- ) + 20 [ over swap newState 2rot set ] iter drop ; + : output ( n- ) [ 'o ] [ '. ] if putc space ; +---reveal--- + : display ( - ) + cr world 20 [ 20 [ @+ output ] times cr ] times drop ; + : gen ( - ) + 20 [ cols ] iter next world 20 20 * copy ; + : delay ( - ) time 1+ [ time over <= ] while drop ; + : generations ( n- ) + [ delay clear gen display ] times ; +}} + + + +{{ + 2 elements line column + : toLine 20 * world + ; + + ( check boundaries ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) + : top ( - ) 0 !line ; + : bot ( - ) 19 !line ; + : beg ( - ) 0 !column ; + : end ( - ) 19 !column ; + : bounds ( - ) + @column -1 = [ end line -- ] ifTrue + @column 20 = [ beg line ++ ] ifTrue + @line -1 = [ top ] ifTrue + @line 20 = [ bot ] ifTrue ; + + ( display a block ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) + : rows 20 [ 20 [ @+ [ 'o ] [ '. ] if putc space ] times cr ] times ; + : vb world rows drop ; + : (v) ( - ) clear vb ; + : pos ( -cl ) @column @line ; + : get ( cl-a ) toLine + ; + : va ( a-va ) dup @ swap ; + : c! ( a- ) '@ swap ! ; + : show ( va- ) dup c! (v) ! ; + : display ( - ) bounds pos get va show ; + + : keys + [ 'i = ] [ drop line -- -1 ] when + [ 'k = ] [ drop line ++ -1 ] when + [ 'j = ] [ drop column -- -1 ] when + [ 'l = ] [ drop column ++ -1 ] when + [ 32 = ] [ drop @line toLine @column + dup @ [ 0 ] [ 1 ] if swap ! -1 ] when + [ 'z = ] [ drop 0 ] when ; +---reveal--- + : edit + [ display getc keys ] while ; +}} + diff --git a/src/cmd/retroforth/examples/games/maze.rx b/src/cmd/retroforth/examples/games/maze.rx new file mode 100644 index 0000000..187904e --- /dev/null +++ b/src/cmd/retroforth/examples/games/maze.rx @@ -0,0 +1,79 @@ +( ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +( Simple ASCII Maze ) +( ) +( Features: ) +( - ASCII graphics ) +( - 16x16 map ) +( - Collision Detection w/map items ) +( - Move using the ijkl keys ) +( ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +( Charles Childers, July 2009 ) +( Updated for Retro 11.x in October 2011 ) +( ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) + +16 constant ROWS +16 constant COLUMNS +6 elements x y lastChar oldX oldY play? + +: $, ( $- ) + withLength [ @+ , ] times drop ; + +create board + "A # # ####### #" $, + "# ## # # # #" $, + "# #" $, + "# #### ### # # " $, + "# # # # # # " $, + "### # # # " $, + "# ## # # # # " $, + "# # ###### ## # " $, + "# # ### # # " $, + "# # # # # # ## #" $, + "# # # ## # #" $, + "# # ###### # #" $, + "# # # #" $, + "############ # #" $, + "# #" $, + "Z ##############" $, + +{{ + : row ( a-a ) + "| " puts COLUMNS [ @+ putc space ] times "|\n" puts ; + + : --- ( - ) + space 33 [ '- putc ] times cr ; +---reveal--- + : display ( - ) + clear --- board ROWS [ row ] times drop --- + @y @x "Player at: %d, %d\n" puts ; +}} + +: bounds + @x 0 < [ 0 !x ] ifTrue + @x COLUMNS 1- > [ COLUMNS 1- !x ] ifTrue + @y 0 < [ 0 !y ] ifTrue + @y ROWS 1- > [ ROWS 1- !y ] ifTrue ; + +: pos 16 * board + + ; +: update @x !oldX @y !oldY ; +: get @x @y pos @ !lastChar ; +: rst @lastChar @x @y pos ! ; +: put bounds get 64 @x @y pos ! ; + +: undo + @oldX !x @oldY !y ; + +: wall? @x @y pos @ '# = [ undo ] ifTrue ; +: end? @x @y pos @ 'Z = [ put update display "You win!\n" puts play? off ] ifTrue ; + +: turn + getc + [ 'i = ] [ drop rst y -- ] when + [ 'k = ] [ drop rst y ++ ] when + [ 'j = ] [ drop rst x -- ] when + [ 'l = ] [ drop rst x ++ ] when + [ 'z = ] [ drop play? off ] when + drop rst undo ; + +: maze play? on + get put [ display turn wall? end? put update @play? ] while ; diff --git a/src/cmd/retroforth/examples/games/spots.rx b/src/cmd/retroforth/examples/games/spots.rx new file mode 100644 index 0000000..5d5e377 --- /dev/null +++ b/src/cmd/retroforth/examples/games/spots.rx @@ -0,0 +1,4 @@ +with canvas' +: spots + clear + repeat click? [ mouse 4 solid red circle ] ifTrue again ; diff --git a/src/cmd/retroforth/examples/games/tic-tac-toe.rx b/src/cmd/retroforth/examples/games/tic-tac-toe.rx new file mode 100644 index 0000000..7a0e70e --- /dev/null +++ b/src/cmd/retroforth/examples/games/tic-tac-toe.rx @@ -0,0 +1,40 @@ +with canvas' + +3 elements mx my color + +: toggle dup @ not swap ! ; +: player @color [ red ] [ blue ] if color toggle ; + +: drawBoard ( - ) + 0 0 @fh @fw white solid box + 0 50 150 black hline + 0 100 150 black hline + 50 0 150 black vline + 100 0 150 black vline ; + +: top ( n- ) 5 40 40 player solid box ; +: middle ( n- ) 55 40 40 player solid box ; +: bottom ( n- ) 105 40 40 player solid box ; + +: column ( nn- ) + swap + [ 0 50 within ] [ top ] whend + [ 50 100 within ] [ middle ] whend + [ 100 150 within ] [ bottom ] whend + 2drop ; + +: row ( nn- ) + [ 0 50 within ] [ 5 column ] whend + [ 50 100 within ] [ 55 column ] whend + [ 100 150 within ] [ 105 column ] whend + 2drop ; + +: moved? ( nn-nnf ) + 2over @mx = [ @my = ] dip and [ 2over [ !my ] [ !mx ] bi* ] dip ; + +: process ( - ) + click? [ mouse swap moved? [ row ] [ 2drop ] if ] ifTrue ; + +: tic-tac-toe ( - ) + clear drawBoard repeat process again ; + diff --git a/src/cmd/retroforth/examples/langs/Makefile b/src/cmd/retroforth/examples/langs/Makefile new file mode 100644 index 0000000..16cc0d1 --- /dev/null +++ b/src/cmd/retroforth/examples/langs/Makefile @@ -0,0 +1,13 @@ +default: clean bf_helloImage bf_squaresImage + +clean: + rm -f bf_helloImage bf_squaresImage + +bf_helloImage: + ../retro --image ../retroImage --with examples/hello.bf + mv appImage bf_helloImage + +bf_squaresImage: + ../retro --image ../retroImage --with examples/squares.bf + mv appImage bf_squaresImage + diff --git a/src/cmd/retroforth/examples/langs/assembler.rx b/src/cmd/retroforth/examples/langs/assembler.rx new file mode 100644 index 0000000..32dec3c --- /dev/null +++ b/src/cmd/retroforth/examples/langs/assembler.rx @@ -0,0 +1,170 @@ +( Ngaro Assembler ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +( Copyright [c] 2008 - 2011, Charles Childers ) +( Copyright [c] 2009 - 2010, Luke Parrish ) +( Copyright [c] 2010, Marc Simpson ) +( Copyright [c] 2010, Jay Skeer ) +( ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) + +8000 constant MAX-APP-SIZE + +( Assembler ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +3 elements target origin fid +: pad ( - ) @origin 32 + !target ; +: m, ( n- ) @target !+ !target ; +: vm: ( n"- ) ` : .data ` m, ` ; ; + 0 vm: nop, 1 vm: lit, 2 vm: dup, + 3 vm: drop, 4 vm: swap, 5 vm: push, + 6 vm: pop, 7 vm: loop, 8 vm: jump, + 9 vm: ret, 10 vm: >jump, 11 vm: >, 25 vm: 0; 26 vm: 1+, + 27 vm: 1-, 28 vm: in, 29 vm: out, + 30 vm: wait, + +: t-here ( -n ) @target @origin - ; + +{{ + : writeByte ( n- ) + @fid ^files'write drop ; + + : applyMask ( n- ) + %00000000000000000000000011111111 and ; + + : writeCell ( n- ) + dup applyMask writeByte + 8 >> dup applyMask writeByte + 8 >> dup applyMask writeByte + 8 >> applyMask writeByte ; +---reveal--- + : saveImage ( - ) + "appImage" ^files':W ^files'open !fid + @origin t-here [ @+ writeCell ] times drop + @fid ^files'close drop bye ; +}} + +: endApp ( - ) + t-here "\nApp ends @ %d\n" puts + MAX-APP-SIZE t-here - "%d cells free" puts + depth 1 >= [ "\nError in stack depth!: " puts .s ] ifTrue ; +: :main ( - ) t-here [ "\nMAIN @ %d" puts ] [ @origin 1+ ! ] bi ; +: # ( n- ) lit, m, ; +: __# ( $- ) lit, toNumber m, ; parsing +: $, ( $- ) withLength [ @+ m, ] times 0 m, drop ; + +: __: ( $- ) header t-here @last !d->xt ; parsing +: call ( "- ) ' m, ; +: jump ( "- ) 8 m, ' m, ; + +( Setup target memory for new image ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +here [ !target ] [ !origin ] bi MAX-APP-SIZE allot +jump, 0 m, pad +reset + +doc{ +=============== +Ngaro Assembler +=============== + + +-------- +Overview +-------- +This is an assembler for the Ngaro instruction set. It is intended to be the +first in a series of small tools to help target other languages to the Ngaro +virtual machine. + + +--------- +Functions +--------- + ++----------+-----------+------------------------------------------------+ +| Name | Stack | Usage | ++==========+===========+================================================+ +| nop, | ``-`` | Ngaro instruction | ++----------+-----------+------------------------------------------------+ +| lit, | ``-`` | Ngaro instruction | ++----------+-----------+------------------------------------------------+ +| dup, | ``-`` | Ngaro instruction | ++----------+-----------+------------------------------------------------+ +| drop, | ``-`` | Ngaro instruction | ++----------+-----------+------------------------------------------------+ +| swap, | ``-`` | Ngaro instruction | ++----------+-----------+------------------------------------------------+ +| push, | ``-`` | Ngaro instruction | ++----------+-----------+------------------------------------------------+ +| pop, | ``-`` | Ngaro instruction | ++----------+-----------+------------------------------------------------+ +| loop, | ``-`` | Ngaro instruction | ++----------+-----------+------------------------------------------------+ +| jump, | ``-`` | Ngaro instruction | ++----------+-----------+------------------------------------------------+ +| ret, | ``-`` | Ngaro instruction | ++----------+-----------+------------------------------------------------+ +| >jump, | ``-`` | Ngaro instruction | ++----------+-----------+------------------------------------------------+ +| >, | ``-`` | Ngaro instruction | ++----------+-----------+------------------------------------------------+ +| 0; | ``-`` | Ngaro instruction | ++----------+-----------+------------------------------------------------+ +| 1+, | ``-`` | Ngaro instruction | ++----------+-----------+------------------------------------------------+ +| 1-, | ``-`` | Ngaro instruction | ++----------+-----------+------------------------------------------------+ +| in, | ``-`` | Ngaro instruction | ++----------+-----------+------------------------------------------------+ +| out, | ``-`` | Ngaro instruction | ++----------+-----------+------------------------------------------------+ +| wait, | ``-`` | Ngaro instruction | ++----------+-----------+------------------------------------------------+ +| :main | ``-`` | Main entry point | ++----------+-----------+------------------------------------------------+ +| # | n- | Compile a number as a literal | ++----------+-----------+------------------------------------------------+ +| __# | $- | Prefix; compile a number as a literal | ++----------+-----------+------------------------------------------------+ +| $, | $- | Compile a string to the target buffer | ++----------+-----------+------------------------------------------------+ +| __: | $- | Prefix; create a label | ++----------+-----------+------------------------------------------------+ +| call | "- | Compile a call to a label | ++----------+-----------+------------------------------------------------+ +| jump | "- | Compile a jump to a label | ++----------+-----------+------------------------------------------------+ +| saveImage| ``-`` | Save the target buffer to *appImage* | ++----------+-----------+------------------------------------------------+ +| t-here | -n | Current address in target buffer | ++----------+-----------+------------------------------------------------+ +| endApp | ``-`` | End assembly and exit | ++----------+-----------+------------------------------------------------+ + +}doc diff --git a/src/cmd/retroforth/examples/langs/basic.rx b/src/cmd/retroforth/examples/langs/basic.rx new file mode 100644 index 0000000..fdd0404 --- /dev/null +++ b/src/cmd/retroforth/examples/langs/basic.rx @@ -0,0 +1,284 @@ +( rxBASIC ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +( This is a minimalistic BASIC compiler. It's written in Retro and runs on ) +( Ngaro virtual machine. ) +( ) +( The implemenation was first described on the Corpse blog in post #98: ) +( http://rx-core.org/dev/corpse/article/98 ) +( ) +( There are string variables and numeric variables. Twenty six of each, named ) +( A$ - Z$ for the string variables and A# to Z# for the integer variables. ) +( ) +( Valid Syntax Forms: ) +( 0000 CLS ) +( 0000 PRINT [type] ) +( 0000 PRINT "string" ) +( 0000 INPUT [type] ) +( 0000 GOTO ) +( 0000 LET [type] = value ) +( 0000 LET [type] += [type] ) +( 0000 LET # -= # ) +( 0000 LET # *= # ) +( 0000 LET # /= # ) +( 0000 LET # %= # ) +( 0000 IF [type] [type] THEN ) +( 0000 END ) +( 0000 RUN ) +( 0000 QUIT ) +( 0000 REM text ) +( ) +( With regards to the implementation, line numbers are required. We have an ) +( array of 4k lines. Each element points to a subroutine. So RxBASIC will ) +( compile each line as a separate subroutine. RUN will cycle through each ) +( the array, executing the subroutine for each line. ) +( ) +( All commands and variables must be UPPERCASE. ) +( ) +( ) +( Copyright [c] 2011, Charles Childers. Use under the ISC License ) +( ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) + +create lines + 4096 allot + +create svars + 27 allot + +create nvars + 27 allot + + +: error ( n- ) + [ 1 = ] [ "\nE1: Invalid line number\n" puts ] whend + [ 2 = ] [ "\nE2: Unknown keyword\n" puts ] whend + [ 3 = ] [ "\nE3: Invalid LET form\n" puts ] whend + drop ; + +: setCurrentLine ( "- ) + "\n> " puts here getNumber + dup 0 4000 within [ lines + ! ] [ 2drop 1 error setCurrentLine ] if ; + +: handleKeyword ( "- ) ; + +: basic ( - ) + clear "rxBASIC\n" puts + repeat setCurrentLine handleKeyword again ; + + +( Helper Functions ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +: # ( n- ) 1 , , ; + +: getVariable ( "-af ) + getc dup putc 'A - getc dup putc '$ = [ svars + -1 ] [ nvars + 0 ] if ; + + +( RxBASIC Commands ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +: do_cls ( - ) + &clear , &; do ; + +: do_print ( "- ) + getc dup putc + dup '" = [ drop '" accept tib keepString # &puts , ] + [ 'A - getc dup putc '$ = [ svars + # &@ , &puts , ] + [ nvars + # &@ , &putn , ] if ] if + &; do ; + +{{ + : readString ( "-$ ) remapping [ remapping off 10 accept tib ] preserve ; +---reveal--- + : do_input ( "- ) + getVariable [ &readString , &keepString ] + [ &getToken , &toNumber ] if , # &! , &; do ; + : do_rem ( "- ) readString drop &; do ; +}} + +: do_goto ( "- ) + 8 , getNumber lines + , &; do ; + +{{ + : strPrepend ^strings'prepend ; + : assignValue ( af"- ) + [ eatLeading? off getc putc '" accept tib keepString eatLeading? on ] + [ getNumber ] if 2# &! , &; do ; + : addVariable ( af"- ) + [ getVariable drop over # &@ , # &@ , &strPrepend , # &! , &; do ] + [ getVariable drop over # &@ , # &@ , &+ , # &! , &; do ] if ; + : subVariable ( af"- ) + [ "\nERROR\n" puts ] + [ getVariable drop over # &@ , # &@ , swap, &- , # &! , &; do ] if ; + : mulVariable ( af"- ) + [ "\nERROR\n" puts ] + [ getVariable drop over # &@ , # &@ , swap, &* , # &! , &; do ] if ; + : divVariable ( af"- ) + [ "\nERROR\n" puts ] + [ getVariable drop over # &@ , # &@ , swap, &/ , # &! , &; do ] if ; + : modVariable ( af"- ) + [ "\nERROR\n" puts ] + [ getVariable drop over # &@ , # &@ , swap, &mod , # &! , &; do ] if ; +---reveal--- + : do_let ( - ) + getVariable + getToken + [ "=" compare ] [ assignValue ] whend + [ "+=" compare ] [ addVariable ] whend + [ "-=" compare ] [ subVariable ] whend + [ "*=" compare ] [ mulVariable ] whend + [ "/=" compare ] [ divVariable ] whend + [ "%=" compare ] [ modVariable ] whend + drop 3 error ; +}} + +{{ + : ifString + # &@ , getToken getVariable drop # &@ , + &compare , "<>" compare [ ¬ , ] ifTrue ; + : ifNumber + # &@ , getToken getVariable drop # &@ , + find drop @d->xt , ; +---reveal--- + : do_if ( - ) + getVariable + &ifString &ifNumber if getToken drop 25 , &drop , handleKeyword &; do ; +}} + + +{{ + variable continue + : done? dup lines 4000 + > [ continue off ] ifTrue ; +---reveal--- + : do_end ( - ) + continue # &off , &; do ; + : do_run ( - ) + continue on &; do cr lines [ @+ [ 0; do ] do done? @continue ] while ; +}} + +( Patch the handleKeyword stub to process the RxBASIC commands ~~~~~~~~~~~~~~ ) +: dispatch ( "- ) + getToken + [ "CLS" compare ] [ do_cls ] whend + [ "PRINT" compare ] [ do_print ] whend + [ "INPUT" compare ] [ do_input ] whend + [ "GOTO" compare ] [ do_goto ] whend + [ "LET" compare ] [ do_let ] whend + [ "IF" compare ] [ do_if ] whend + [ "END" compare ] [ do_end ] whend + [ "RUN" compare ] [ do_run ] whend + [ "QUIT" compare ] [ bye ] whend + [ "REM" compare ] [ do_rem ] whend + drop 2 error ; +&dispatch is handleKeyword + +( Documentation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +doc{ +========================= +RxBASIC Programming Guide +========================= + + +------------ +Introduction +------------ +RxBASIC is a minimalistic dialect of the BASIC language. It is not +intended to be used for anything other than simple experiments. + + +------------ +The Language +------------ + +Line Numbers +============ +RxBASIC requires each keyword to be prefixed by a line number. The +implementation provides 4,000 lines for your use. + + +Variables +========= +There are two types of variables: numeric and string. Strings can +hold textual data, while numeric variables can only hold numbers. +(Note that the numbers could represent other data types, such as +characters if desired). + +RxBASIC provides twenty six of each variable type, named after each +letter in the English alphabet. A suffix (either $ or #) denotes +the type. $ is used for string variables, and # for numeric +variables. + + +Keywords +======== +RxBASIC recognizes a small number of keywords. These are: CLS, +PRINT, INPUT, GOTO, LET, IF, THEN, END, RUN, QUIT, and REM. The usage +of each is shown in the table below. + ++-------+-----------------------------------------------------------+ +| CLS | | ++-------+-----------------------------------------------------------+ +| PRINT | [type] | ++-------+-----------------------------------------------------------+ +| PRINT | "string" | ++-------+-----------------------------------------------------------+ +| INPUT | [type] | ++-------+-----------------------------------------------------------+ +| GOTO | | ++-------+-----------------------------------------------------------+ +| LET | [type] = value | ++-------+-----------------------------------------------------------+ +| LET | [type] += [type] | ++-------+-----------------------------------------------------------+ +| LET | # -= # | ++-------+-----------------------------------------------------------+ +| LET | # *= # | ++-------+-----------------------------------------------------------+ +| LET | # /= # | ++-------+-----------------------------------------------------------+ +| LET | # %= # | ++-------+-----------------------------------------------------------+ +| IF | [type] [type] THEN | ++-------+-----------------------------------------------------------+ +| END | | ++-------+-----------------------------------------------------------+ +| RUN | | ++-------+-----------------------------------------------------------+ +| QUIT | | ++-------+-----------------------------------------------------------+ +| REM | text | ++-------+-----------------------------------------------------------+ + +All commands *must* be specified in uppercase. + + +---------- +Techniques +---------- + +Combining Strings +================= + +:: + + 0001 LET A$ = "HELLO, " + 0002 LET B$ = "WORLD!" + 0003 LET A$ += B$ + + +Copy The Value Of One Variable To Another +========================================= + +:: + + 0001 LET A$ = "" + 0002 LET B$ = "foo" + 0003 LET A$ += B$ + + +Conditional +=========== + +:: + + 0001 LET A$ = "100" + 0002 LET B$ = "200" + 0003 IF A$ = B$ THEN PRINT "MATCH" +}doc + +basic diff --git a/src/cmd/retroforth/examples/langs/bf.rx b/src/cmd/retroforth/examples/langs/bf.rx new file mode 100644 index 0000000..9b9520c --- /dev/null +++ b/src/cmd/retroforth/examples/langs/bf.rx @@ -0,0 +1,74 @@ +( Support functions: basic input, output, and data pointer support ) +:wait + #0 #0 out, + wait, + ret, + +:bye + #-9 #5 out, + ret, + +:dp 32768 m, + +:bf_> + dp # @, + 1+, + dp # !, + ret, + +:bf_< + dp # @, + 1-, + dp # !, + ret, + +:bf_+ + dp # @, @, + 1+, + dp # @, !, + ret, + +:bf_- + dp # @, @, + 1-, + dp # @, !, + ret, + +:bf_. + dp # @, @, + #1 #2 out, + call wait + #0 #3 out, + ret, + +:bf_, + #1 #1 out, + call wait + #1 in, + dp # @, !, + ret, + +( Actual BrainF*** compiler ) +variable ip + +: run + t-here putn space @ip @ putc cr + @ip @ ip ++ + [ '> = ] [ drop bf_> m, ] when + [ '< = ] [ drop bf_< m, ] when + [ '+ = ] [ drop bf_+ m, ] when + [ '- = ] [ drop bf_- m, ] when + [ '. = ] [ drop bf_. m, ] when + [ ', = ] [ drop bf_, m, ] when + [ '[ = ] [ drop t-here dp # @, @, lit, 0 m, =jump, @target 0 m, ] when + [ '] = ] [ drop swap jump, m, t-here swap ! ] when + drop ; + +: do + [ run @ip @ ] while ; + +: bf: ( "- ) + '~ accept tib keepString !ip cr do ; + +( Start Compilation of BrainF*** code after this ) +:main diff --git a/src/cmd/retroforth/examples/langs/examples/hello.bf b/src/cmd/retroforth/examples/langs/examples/hello.bf new file mode 100644 index 0000000..f7aed25 --- /dev/null +++ b/src/cmd/retroforth/examples/langs/examples/hello.bf @@ -0,0 +1,9 @@ +include assembler.rx +include bf.rx + +bf: >+++++++++[<++++++++>-]<.>+++++++[<++++>-]<+.+++++++..+++.[-]>++++++++[<++++>-]~ +bf: <.>+++++++++++[<+++++>-]<.>++++++++[<+++>-]<.+++.------.--------.[-]>++++++++[~ +bf: <++++>-]<+.[-]++++++++++.~ + +endApp +saveImage diff --git a/src/cmd/retroforth/examples/langs/examples/squares.bf b/src/cmd/retroforth/examples/langs/examples/squares.bf new file mode 100644 index 0000000..2d01a71 --- /dev/null +++ b/src/cmd/retroforth/examples/langs/examples/squares.bf @@ -0,0 +1,10 @@ +include assembler.rx +include bf.rx + +bf: ++++[>+++++<-]>[<+++++>-]+<+[>[>+>+<<-]++>>[<<+>>-]>>>[-]++>[-]~ +bf: +>>>+[[-]++++++>>>]<<<[[<++++++++<++>>-]+<.<[>----<-]<]<<[>>>>>~ +bf: [>>>[-]+++++++++<[>-<-]+++++++++>[-[<->-]+[<<<]]<[>+<-]>]<<-]<<~ +bf: -]~ + +endApp +saveImage diff --git a/src/cmd/retroforth/examples/master_theorem/8-bit_classics.rx b/src/cmd/retroforth/examples/master_theorem/8-bit_classics.rx new file mode 100644 index 0000000..734fc4e --- /dev/null +++ b/src/cmd/retroforth/examples/master_theorem/8-bit_classics.rx @@ -0,0 +1,13 @@ +( For 8-bit Classics ) +( Each screencap corresponds to a character. There are eight screens ) +( and each of them contains eight bits hidden in the picture. ) + +needs array' + +binary +^array'new{ 01100111 01100001 + 01101101 01100101 + 01101111 01110110 + 01100101 01110010 } [ putc ] ^array'apply + + diff --git a/src/cmd/retroforth/examples/master_theorem/masters_of_many_theorems.rx b/src/cmd/retroforth/examples/master_theorem/masters_of_many_theorems.rx new file mode 100644 index 0000000..83ea58e --- /dev/null +++ b/src/cmd/retroforth/examples/master_theorem/masters_of_many_theorems.rx @@ -0,0 +1,26 @@ +( A Puzzle involving Math ) +( Or more specifically, the Pythagorean Theorem ) +( "For a right triangle with legs a and b and ) +( hypotenuse c: a^2 + b^2 = c^2 ) + + +needs math' + +: toIndex ( c-n ) + 'a - 1+ ; + +: h 'h toIndex ; +: o 'o toIndex ; +: f 'f toIndex ; +: c 'c toIndex ; + +: ^2 ( n-n ) 2 pow ; + +: toAlpha ( n-c ) + 'a 1- + ; + +: x1 h ^2 o ^2 + ^math'squareRoot toAlpha putc ; +: x2 h ^2 f ^2 + ^math'squareRoot 2 / toAlpha putc ; +: x3 5 ^2 c ^2 - ^math'squareRoot toAlpha putc ; + +: solve x1 x2 x3 ; diff --git a/src/cmd/retroforth/examples/master_theorem/murder_at_sea.rx b/src/cmd/retroforth/examples/master_theorem/murder_at_sea.rx new file mode 100644 index 0000000..cbe4a67 --- /dev/null +++ b/src/cmd/retroforth/examples/master_theorem/murder_at_sea.rx @@ -0,0 +1,48 @@ +Flag semaphores are at the heart of this puzzle. In the text, +M provides a series of times. These correspond to flag semaphore +positions. If you picture the flag positions as the hands on an +analog clock, this should become clear. + +So: + + 715 130 625 730 925 745 730 915 700 + +These are our times. + + : display ( n- ) + [ 730 = ] [ drop 'A putc ] when + [ 130 = ] [ drop 'E putc ] when + [ 625 = ] [ drop 'G putc ] when + [ 745 = ] [ drop 'H putc ] when + [ 700 = ] [ drop 'K putc ] when + [ 715 = ] [ drop 'M putc ] when + [ 915 = ] [ drop 'R putc ] when + [ 925 = ] [ drop 'S putc ] when ; + +Less elegant than a lookup table, but suitable for this +quick and dirty solution. Map each time to a character +and display them. + + "" ^buffer'set + +Setup a temporary string as a buffer. + + depth [ ^buffer'add ] times + +Adds all of the times to the buffer. + + ^buffer'start ^strings'reverse + +Reverse the order of the buffer, and leave a pointer... + + [ @ display ] ^types'STRING each@ + +And apply a quote to each item in the buffer. This is pretty +simple: fetch the item, and give it to the display function. + +This yields the answer: MEGASHARK + +All in all, a boring puzzle. Once you figure out that M wants +you to use flag semaphores in place of times, it's easy to find +the answer. + diff --git a/src/cmd/retroforth/examples/master_theorem/my_star_chart.rx b/src/cmd/retroforth/examples/master_theorem/my_star_chart.rx new file mode 100644 index 0000000..8b541ce --- /dev/null +++ b/src/cmd/retroforth/examples/master_theorem/my_star_chart.rx @@ -0,0 +1,63 @@ +This is pretty easy. Each code name is based on particular characters from +the facts about each star. For example, the star named "water": + +Type: taurus +Age: 1 billion years +Distance: 18 x 10^10 light years +Temperature: 5000 K +Color: white + +The name comes from the first character of the color, the age, the first +character of the type, the temperature (divide by 1000), and the distance +(ignore the 10^10 part). The numbers correspond to the letters of the +alphabet, with an index value of one. + +So to start, the alphabet, with the zero position filled by an underscore: + + : letters "_abcdefghijklmnopqrstuvwxyz" ; + +Easy enough. Next, an array of variables. I'm going to use a trick here, +which needs some explanation. Variables created with *elements* have their +data stored sequentially, with headers being separated. So we can access +them as a unit or structure later. + + 6 elements color age type temperature distance padding + +There is an used padding variable. This will be useful later. + +We'll follow this up with some helper functions to improve readability: + + : getNumber getNumber ; + : toLetter letters + @ ; + +The first function, *getNumber*, parses and returns a number from the +input stream. The second takes an index value and returns the corresponding +letter from the alphabet. + +With these, we can now implement functions for each fact. + + : Type: getToken @ !type ; + : Age: getNumber toLetter !age 2getToken 2drop ; + : Distance: getNumber toLetter !distance 2 [ 2getToken 2drop ] times ; + : Temperature: getNumber 1000 / toLetter !temperature getToken drop ; + : Color: getToken @ !color ; + +This is all a bit messy, but for a quick solution, it'll work. Each "fact" +handler parses the input stream, extracts the character code (doing any +adjustments needed), and sets the appropriate variable to the characters. + +Once these are defined, we can paste in the facts about our unknown star: + +Type: main +Age: 1 billion years +Distance: 14 x 10^10 light years +Temperature: 5000 K +Color: red + +And now we have an answer: + + color puts + +Note here that we treat our variables as a string. Since the values are +sequential the unused *padding* variable acts as a null terminator and + we don't need to do anything else to get the correct answer of *ramen*. diff --git a/src/cmd/retroforth/examples/master_theorem/prison_life.rx b/src/cmd/retroforth/examples/master_theorem/prison_life.rx new file mode 100644 index 0000000..eab8b1b --- /dev/null +++ b/src/cmd/retroforth/examples/master_theorem/prison_life.rx @@ -0,0 +1,18 @@ +needs array' + +create tapCodes + 'a , 'b , 'c , 'd , 'e , + 'f , 'g , 'h , 'i , 'j , + 'l , 'm , 'n , 'o , 'p , + 'q , 'r , 's , 't , 'u , + +: tapToChar ( rc-c ) + [ 1- ] bi@ swap 5 * tapCodes + + @ ; + +: decode ( a- ) + @+ 2 / [ @+ swap @+ swap [ tapToChar putc ] dip ] times drop ; + +^array'new{ 4 4 2 3 1 5 + 1 2 2 4 4 2 1 4 + 3 2 1 1 3 3 } decode + diff --git a/src/cmd/retroforth/examples/master_theorem/synesthesia.rx b/src/cmd/retroforth/examples/master_theorem/synesthesia.rx new file mode 100644 index 0000000..03ad133 --- /dev/null +++ b/src/cmd/retroforth/examples/master_theorem/synesthesia.rx @@ -0,0 +1,183 @@ +( The first part of the puzzle is a table, with six rows of six ) +( characters. We'll create a table to hold this data: ) + + : table: ( n"- ) + create [ getToken @ , ] times ; + +( First up, a helper function that'll parse and build the tables. ) +( Pass it a count, and follow it by the table name, then a ) +( whitespace delimited series of tokens. ) + + 36 table: initial 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 + +( The initial table. This is an exact match to the table shown. ) + + 36 table: colors 1 2 3 4 2 5 + 6 7 8 6 3 1 + 9 5 0 5 7 A + B C Q C D 4 + 8 7 0 4 B 3 + 7 D Q 5 A 9 + +( The table of characters has colors. Each color is matched to ) +( two characters. We have a second table with values that ) +( represent the color arrangement. ) + + + : clue ( -$ ) + "25 BACON BITS VANILLA 29 BROWNIES AND ALLSPICE 2" ; + +( Below the table is a string of text that encodes the answer to ) +( this puzzle. We create a string named "clue" to hold this. ) + + : withToken ( $q- ) + [ " " ^strings'prepend " " ^strings'append ] dip + [ [ 32 ^strings'splitAtChar ^strings'chop ] dip [ do ] sip over 1 <> ] while 2drop ; + +( You aren't expected to understand this. Breaking it down: ) + + [ " " ^strings'prepend " " ^strings'append ] dip + +( Adds a space before and after the string passed to the ) +( withToken function. This simplifies the following bits of code. ) + + [ [ 32 ^strings'splitAtChar ^strings'chop ] dip [ do ] sip over 1 <> ] while 2drop ; + +( This isn't too complex. Breaking it down further: ) + + [ .... ] while 2drop + +( Everything is inside a while loop. The 2drop removes the ) +( pointers when execution is finished. ) + + [ 32 ^strings'splitAtChar ^strings'chop ] dip + +( Inside the loop, this temporarily hides the quote, splits ) +( a whitespace delimited token off the string, and removes ) +( the trailing space with ^strings'chop. ) + + [ do ] sip + +( Execute the quote, keeping a copy of the pointer on the stack after ) +( execution completes. ) + + over 1 <> + +( The condition for the while loop. When no tokens remain, the pointer ) +( value will be returned as "1". So if not 1, there are more tokens to ) +( process. ) + +( In actual use, this is pretty nice. It means you can do things like: ) + + "hello 123 again" [ "Token: %s\n" puts ] withToken + +( The quote will be executed once for each word in the string. Now, ) +( back to the solution. ) + + : append + dup isNumber? [ [ @ ^buffer'add ] ^types'STRING each@ ] + [ @ ^buffer'add ] if ; + +( This is a factor of the simplify function which we'll look at next. ) +( It looks at a token to see if it's a number or a word. If it's a ) +( number, each character in the string is added to a buffer. If it's a ) +( word, then only the first character is added. ) + +( Note the use of each@, another combinator which allows a quote to be ) +( executed for each item in a data structure. ) + + : simplify ( $-$ ) + heap [ here ^buffer'set 128 allot + &append withToken ] preserve + ^buffer'start ; + +( The rules of the puzzle dictate that each numeric digit has a color, ) +( and each word has a color. simplify compresses a string into just the) +( relevant subset. To break this down: ) + + heap [ ... ] preserve + +( We'll use the heap as a buffer. Encasing the code using this buffer ) +( in a preservation quote cleans up any allocations when we are done. ) + + here ^buffer'set + +( Sets the buffer to the heap. ) + + 128 allot + +( Allocates space for our buffer. This will be rolled back after ) +( preserve is executed. ) + + &append withToken + +( Applies the append function to each token in a string. We could also ) +( have specified this as: ) + + [ append ] withToken + +( The & syntax is a shortcut for single-function quotes. ) + + ^buffer'start + +( When execution of simplify finishes, we'll return a pointer to the ) +( buffer we created. ) + + : getIndex ( c-n ) + initial [ [ @ over <> ] sip 1+ swap ] while nip initial - 1- ; + +( Lookup a character in the initial array, and return the index value ) +( for later use. ) + + : colorize ( $-$ ) + simplify + "" tempString ^buffer'set + [ @ getIndex colors + @ ^buffer'add ] ^types'STRING each@ ^buffer'start ; + +( Convert a raw string into a colored one. ) + + simplify + +( Start by reducing to just the relevant data. ) + + "" tempString ^buffer'set + +( Create an empty string to use as a buffer. ) + + [ @ getIndex colors + @ ^buffer'add ] ^types'STRING each@ + +( Use each@ to apply a quote to each character in the simplified ) +( string. For each character, we find the index, lookup the ) +( corresponding character in the colors array, and add that to the new ) +( string. ) + + ^buffer'start + +( Returns the colored string. ) + +( We're almost there. All we need to do is decode the colored string. ) + + : match? ( n-nf ) + [ colors + @ over = ] sip swap ; + : matches + [ @ 36 [ match? [ initial + @ putc ] [ drop ] if ] iter drop space ] ^types'STRING each@ ; + +( This is a quick hack to remap a color to all matching characters. ) +( Since each color corresponds to two characters, this will display ) +( pairs of characters. ) + +( With this, we can do: ) + + clue colorize matches + +( And we get the following output: ) +( S2 W5 BE BE TV S2 M9 BE AL AL S2 ) +( From this, it's easy to deduce the solution: ) +( S W E E T S M E L L S ) +( Or: ) +( SWEET SMELLS ) diff --git a/src/cmd/retroforth/examples/master_theorem/what_i_do_in_my_basement.rx b/src/cmd/retroforth/examples/master_theorem/what_i_do_in_my_basement.rx new file mode 100644 index 0000000..2edc772 --- /dev/null +++ b/src/cmd/retroforth/examples/master_theorem/what_i_do_in_my_basement.rx @@ -0,0 +1,63 @@ +This puzzle involves finding a hidden message, encoded using a series of digits in various +numeric bases. + +Given M's habit of hiding subtle clues in the article text, there are a number of references to +*basement*. It's rather opaque, but the only real significance is that the puzzle somehow +involves work with various bases. + +There are two parts to the puzzle: a column of shapes on the left, and a series of colored +and/or shaped tiles on the right. Each row is in a different base. The shape on the left tells +which base (count the number of sides), the tiles on the right encode the digits of each +number. + +Solid colored tiles are zero, the others are the number of sides in the priamry shape. + +So: + + : convertToDecimal: ( n"-n ) + base ! getNumber decimal ; + +Pass this a base, and it'll parse a number and return the decimal form. + +With this, we can convert the numbers: + + 5 convertToDecimal: 0032 + 8 convertToDecimal: 0025 + 3 convertToDecimal: 0100 + 2 convertToDecimal: 1110 + 6 convertToDecimal: 0001 + 4 convertToDecimal: 0102 + 7 convertToDecimal: 0034 + +Now to translate to ASCII. First, a string containing the letters. This has an _ as the first +character. Since the results of M's puzzles have thus far been using an index of 1 rather than +0, this lets us avoid incrementing each value by 1. + + : alpha ( -$ ) + "_abcdefghijklmnopqrstuzwxyz" ; + +Next up is a function to translate an integer into an ASCII character. Simply add the integer +to the address returned by alpha, and fetch the stored character. + + : toAlpha ( n-c ) + alpha + @ ; + +Easy enough. Now to simplify building a string. We'll use the buffer' vocabulary for this. +First, create a temporary string and then set it as the buffer. + + "" tempString ^buffer'set + +Next, translate each value returned by convertToDecimal: to an ASCII code and add it to the +buffer: + + depth [ toAlpha ^buffer'add ] times + +And finally display the result: + + ^buffer'start puts + +At this point, the resulting string is "yraniuq", which is reversed from what we want. So to +fix it: + + ^buffer'start ^strings'reverse puts + diff --git a/src/cmd/retroforth/examples/master_theorem/words_words_words_2.rx b/src/cmd/retroforth/examples/master_theorem/words_words_words_2.rx new file mode 100644 index 0000000..3723920 --- /dev/null +++ b/src/cmd/retroforth/examples/master_theorem/words_words_words_2.rx @@ -0,0 +1,23 @@ +( Plenty of words in the text, but some stand out. The ones with ) +( colors have sounds in common with various numbers. ) + +( The trick to this puzzle is to group by color, and add the ) +( numeric values up. So: ) + +( red altitude foresight 2 4 -> 6 ) +( purple intended wonder foreground 10 1 4 -> 15 ) +( blue before to to tension 4 2 2 10 -> 18 ) +( green attention pretend 10 10 -> 20 ) +( yellow magnitude elated tenderly once 2 8 10 1 -> 21 ) +( gray fate fortitude 8 4 2 -> 14 ) +( pink tonight to someones 2 2 1 -> 5 ) + +( And then we can map the final values to alphabetic characters: ) + +needs array' + +( remap so that 1 = a, 2 = b, and so on ) +: toAlpha ( n-c ) + 96 + ; + +^array'new{ 6 15 18 20 21 14 5 } [ toAlpha putc ] ^array'apply diff --git a/src/cmd/retroforth/examples/misc/bmi.rx b/src/cmd/retroforth/examples/misc/bmi.rx new file mode 100644 index 0000000..17ee666 --- /dev/null +++ b/src/cmd/retroforth/examples/misc/bmi.rx @@ -0,0 +1,23 @@ +( Body Mass Index Calculator ) +( Ported from Ron Aaron's Reva ) + +variables| height weight | + +"BMI Calculator 1.1\n" string VERSION +"height, in centimeters" string HEIGHT +"weight, in kilograms" string WEIGHT + +: get ( a$- ) + "\nPlease enter your %s: " puts getNumber swap ! ; +: getHeight height HEIGHT get ; +: getWeight weight WEIGHT get ; +: showBMI + @weight 100000 @height dup * &* dip / 10 /mod + @height @weight + "\nFor a weight of %d kg, and a height of %d cm, the BMI is %d.%d\n" puts ; + +: getBMI + VERSION puts getHeight getWeight showBMI bye ; + +getBMI + diff --git a/src/cmd/retroforth/examples/misc/draw.rx b/src/cmd/retroforth/examples/misc/draw.rx new file mode 100644 index 0000000..fe3943e --- /dev/null +++ b/src/cmd/retroforth/examples/misc/draw.rx @@ -0,0 +1,44 @@ +needs canvas' +with canvas' + +create colors + &black , &white , &blue , + &green , &cyan , &red , + &purple , &brown , &gray , + &darkGray , &brightBlue , &brightGreen , + &brightCyan , &brightRed , &magenta , + &yellow , + +( ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +( Draw the menu of colors at the bottom ) +( ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +: (draw ( n- ) over @fh 50 - 50 50 solid box ; +: advance) ( aa-aa ) swap 50 + swap ; +: menu ( - ) + 0 colors 16 [ @+ do (draw advance) ] times 2drop ; +: ui ( - ) + clear 0 0 dimensions white solid box menu ; + + +: region: ( "- ) + ` within ` [ ` drop ' , ` 0 ` ] ` ifTrue ; compile-only + +: check ( -f ) + mouse @fh 50 - > [ + dup 0 49 region: black dup 50 99 region: white + dup 100 149 region: blue dup 150 199 region: green + dup 200 249 region: cyan dup 250 299 region: red + dup 300 349 region: purple dup 350 399 region: brown + dup 400 449 region: gray dup 450 499 region: darkgray + dup 500 549 region: brightblue dup 550 599 region: brightgreen + dup 600 649 region: brightcyan dup 650 699 region: brightred + dup 700 749 region: magenta dup 750 799 region: yellow + ] [ drop -1 ] if ; + + +( ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +( The main application loop ) +( ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +: (draw) click? 0; drop check 0; drop mouse pixel ; +: draw ui black repeat (draw) again ; + diff --git a/src/cmd/retroforth/examples/rosetta_code/100_doors.rx b/src/cmd/retroforth/examples/rosetta_code/100_doors.rx new file mode 100644 index 0000000..cbb5508 --- /dev/null +++ b/src/cmd/retroforth/examples/rosetta_code/100_doors.rx @@ -0,0 +1,4 @@ +: squared ( n-n ) dup * ; +: doors ( n- ) + [ 1 repeat 2over squared > 0; drop dup squared putn space 1+ again ] do 2drop ; +100 doors diff --git a/src/cmd/retroforth/examples/rosetta_code/1d-cellular-automota.rx b/src/cmd/retroforth/examples/rosetta_code/1d-cellular-automota.rx new file mode 100644 index 0000000..bbee6af --- /dev/null +++ b/src/cmd/retroforth/examples/rosetta_code/1d-cellular-automota.rx @@ -0,0 +1,38 @@ +{{ + : $, ( $- ) withLength [ @+ , ] times @ , ; + create this ".###.##.#.#.#.#..#.." $, + create next this getLength allot + create group "..." $, + variable neighbours + + : reset 0 !neighbours ; + : hasNeighbour? @ '# = [ neighbours ++ ] ifTrue ; + : countNeighboursOnEdge '# = [ 1 ] [ 0 ] if !neighbours ; + : flip dup this + @ '# = [ '. ] [ '# ] if ; + : extract dup this + 1- group 3 copy ; + + : count + ( left ) [ 0 = ] [ @this countNeighboursOnEdge ] when + ( right ) [ 19 = ] [ this 19 + @ countNeighboursOnEdge ] when + ( middle ) reset extract group dup 2 + 2hasNeighbour? ; + + : process + reset count @neighbours + [ 0 = ] [ drop dup next + '. swap ! ] when + [ 1 = ] [ drop dup this + @ over next + ! ] when + [ 2 = ] [ drop flip over next + ! ] when + drop ; + + : generation + 0 this getLength + [ process 1+ ] times drop + next this withLength copy ; +---reveal--- + : generations + cr 0 swap [ [ this swap "%d %s\n" puts ] sip generation 1+ ] times drop ; +}} +1 2 3 +10 generations + 5 generations +.s + diff --git a/src/cmd/retroforth/examples/rosetta_code/99_bottles_of_beer.rx b/src/cmd/retroforth/examples/rosetta_code/99_bottles_of_beer.rx new file mode 100644 index 0000000..da53f38 --- /dev/null +++ b/src/cmd/retroforth/examples/rosetta_code/99_bottles_of_beer.rx @@ -0,0 +1,16 @@ +[ dup "%d bottles" puts ] +[ "1 bottle" puts ] +[ "no more bottles" puts ] +create bottles , , , + +: .bottles dup 2 ^math'min bottles + @ do ; +: .beer .bottles " of beer" puts ; +: .wall .beer " on the wall" puts ; +: .take "Take one down, pass it around" puts ; +: .verse .wall cr .beer cr + 1- .take cr .wall cr ; +: ?dup dup 0; ; +: verses [ cr .verse dup 0 <> ] while drop ; + +99 verses +bye diff --git a/src/cmd/retroforth/examples/rosetta_code/README b/src/cmd/retroforth/examples/rosetta_code/README new file mode 100644 index 0000000..4665052 --- /dev/null +++ b/src/cmd/retroforth/examples/rosetta_code/README @@ -0,0 +1,16 @@ +Rosetta Code +============ +Rosetta Code is a website that provides comparisons in implementation of common +tasks across a variety of languages. This directory contains the Retro code for +these examples. + +Please note that many of these will have textual comments added; they are intended +for study, not running directly. + +If you make changes here, please update the appropriate pages on the rosettacode.org +site to reflect them. + +Legal +===== +The code here is dual licensed under ISC (for inclusion in Retro) and GFDL (for +posting to Rosetta Code). diff --git a/src/cmd/retroforth/examples/rosetta_code/a_plus_b.rx b/src/cmd/retroforth/examples/rosetta_code/a_plus_b.rx new file mode 100644 index 0000000..341ae72 --- /dev/null +++ b/src/cmd/retroforth/examples/rosetta_code/a_plus_b.rx @@ -0,0 +1 @@ +: try ( "-n ) 2getNumber + putn ; diff --git a/src/cmd/retroforth/examples/rosetta_code/accumulator_factory.rx b/src/cmd/retroforth/examples/rosetta_code/accumulator_factory.rx new file mode 100644 index 0000000..eb92974 --- /dev/null +++ b/src/cmd/retroforth/examples/rosetta_code/accumulator_factory.rx @@ -0,0 +1,11 @@ +: acc here swap , [ &+! &@ bi ] curry ; + +( create an accumulator function ) +1 acc + +( and give it a name ) +constant x + +( add values to it and display the results ) +5 x do putn + 2 x do putn diff --git a/src/cmd/retroforth/examples/rosetta_code/address_of_a_variable.rx b/src/cmd/retroforth/examples/rosetta_code/address_of_a_variable.rx new file mode 100644 index 0000000..2811e73 --- /dev/null +++ b/src/cmd/retroforth/examples/rosetta_code/address_of_a_variable.rx @@ -0,0 +1,7 @@ +( get the address ) +variable a +&a + +( set the address ) +variable b +100 @last !d->xt diff --git a/src/cmd/retroforth/examples/rosetta_code/apply_a_callback_to_an_array.rx b/src/cmd/retroforth/examples/rosetta_code/apply_a_callback_to_an_array.rx new file mode 100644 index 0000000..f533940 --- /dev/null +++ b/src/cmd/retroforth/examples/rosetta_code/apply_a_callback_to_an_array.rx @@ -0,0 +1,8 @@ +Using the array' library to multiply each value in an array by 10 and display the results: + + [ 1 2 3 4 5 ] ^array'fromQuote [ 10 * ] ^array'map ^array'display + +Retro also provides ^array'apply for use when you don't want to alter the contents of the array: + + [ "Hello" "World" "Foo" ] ^array'fromQuote [ "%s " puts ] ^array'apply + diff --git a/src/cmd/retroforth/examples/rosetta_code/arithmetic_integer.rx b/src/cmd/retroforth/examples/rosetta_code/arithmetic_integer.rx new file mode 100644 index 0000000..73d78c3 --- /dev/null +++ b/src/cmd/retroforth/examples/rosetta_code/arithmetic_integer.rx @@ -0,0 +1,8 @@ +: arithmetic ( ab- ) + over "\na = %d" puts + dup "\nb = %d" puts + 2over + "\na + b = %d" puts + 2over - "\na - b = %d" puts + 2over * "\na * b = %d" puts + /mod "\na / b = %d" puts + "\na mod b = %d\n" puts ; diff --git a/src/cmd/retroforth/examples/rosetta_code/binary_digits.rx b/src/cmd/retroforth/examples/rosetta_code/binary_digits.rx new file mode 100644 index 0000000..6569b59 --- /dev/null +++ b/src/cmd/retroforth/examples/rosetta_code/binary_digits.rx @@ -0,0 +1,2 @@ +9000 50 5 3 [ binary putn cr decimal ] times + diff --git a/src/cmd/retroforth/examples/rosetta_code/bitwise_operations.rx b/src/cmd/retroforth/examples/rosetta_code/bitwise_operations.rx new file mode 100644 index 0000000..6ca8b1d --- /dev/null +++ b/src/cmd/retroforth/examples/rosetta_code/bitwise_operations.rx @@ -0,0 +1,11 @@ +: bitwise ( ab- ) + cr + over "a = %d\n" puts + dup "b = %d\n" puts + 2over and "a and b = %d\n" puts + 2over or "a or b = %d\n" puts + 2over xor "a xor b = %d\n" puts + over not "not a = %d\n" puts + 2over << "a << b = %d\n" puts + 2over >> "a >> b = %d\n" puts + 2drop ; diff --git a/src/cmd/retroforth/examples/rosetta_code/boolean_functions.rx b/src/cmd/retroforth/examples/rosetta_code/boolean_functions.rx new file mode 100644 index 0000000..55792da --- /dev/null +++ b/src/cmd/retroforth/examples/rosetta_code/boolean_functions.rx @@ -0,0 +1,2 @@ +( Zero is false and non-zero is true. Comparison functions return -1 for ) +( true and 0 for false. ) diff --git a/src/cmd/retroforth/examples/rosetta_code/character_codes.rx b/src/cmd/retroforth/examples/rosetta_code/character_codes.rx new file mode 100644 index 0000000..2272064 --- /dev/null +++ b/src/cmd/retroforth/examples/rosetta_code/character_codes.rx @@ -0,0 +1 @@ +'c putc diff --git a/src/cmd/retroforth/examples/rosetta_code/character_matching.rx b/src/cmd/retroforth/examples/rosetta_code/character_matching.rx new file mode 100644 index 0000000..6db43bf --- /dev/null +++ b/src/cmd/retroforth/examples/rosetta_code/character_matching.rx @@ -0,0 +1,14 @@ +: startsWith? ( $1 $2 - f ) + withLength &swap dip 0 swap ^strings'getSubset compare ; + +"abcdefghijkl" "abcde" startsWith? +"abcdefghijkl" "bcd" startsWith? + +"abcdefghijkl" "bcd" ^strings'search +"abcdefghijkl" "zmq" ^strings'search + +: endsWith? ( $1 $2 - f ) + swap withLength + over getLength - compare ; + +"abcdefghijkl" "ijkl" endsWith? +"abcdefghijkl" "abc" endsWith? diff --git a/src/cmd/retroforth/examples/rosetta_code/comments.rx b/src/cmd/retroforth/examples/rosetta_code/comments.rx new file mode 100644 index 0000000..b678d70 --- /dev/null +++ b/src/cmd/retroforth/examples/rosetta_code/comments.rx @@ -0,0 +1,2 @@ +( comments are placed between parenthesis. A space ) +( must follow the opening parenthesis. ) diff --git a/src/cmd/retroforth/examples/rosetta_code/conditional_structures.rx b/src/cmd/retroforth/examples/rosetta_code/conditional_structures.rx new file mode 100644 index 0000000..403a584 --- /dev/null +++ b/src/cmd/retroforth/examples/rosetta_code/conditional_structures.rx @@ -0,0 +1,9 @@ +( condition ) [ ( true statements ) ] ifTrue +( condition ) [ ( false statements ) ] ifFalse +( condition ) [ ( true statements ) ] [ ( false statements ) ] if + +: foo ( n- ) + [ 1 = ] [ drop ( if quote evaluates to true ) ] when + [ 2 = ] [ drop ( if quote evaluates to true ) ] when + [ 3 = ] [ drop ( if quote evaluates to true ) ] when + drop ( default action ) ; diff --git a/src/cmd/retroforth/examples/rosetta_code/conways_game_of_life.rx b/src/cmd/retroforth/examples/rosetta_code/conways_game_of_life.rx new file mode 100644 index 0000000..60b27de --- /dev/null +++ b/src/cmd/retroforth/examples/rosetta_code/conways_game_of_life.rx @@ -0,0 +1,78 @@ +create world + 20 20 * allot + +create next + 20 20 * allot + +create initial +( 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ) +( 0 ) 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , +( 1 ) 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 1 , 0 , 0 , 1 , 1 , 0 , +( 2 ) 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 1 , 0 , 0 , 1 , 1 , 0 , +( 3 ) 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 1 , 0 , 0 , 0 , 0 , 0 , +( 4 ) 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , +( 5 ) 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , +( 6 ) 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , +( 7 ) 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , +( 8 ) 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , +( 9 ) 0 , 0 , 0 , 0 , 0 , 0 , 1 , 0 , 1 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , +( 10 ) 0 , 0 , 0 , 0 , 0 , 0 , 1 , 0 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , +( 11 ) 0 , 0 , 0 , 0 , 0 , 0 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , +( 12 ) 0 , 0 , 0 , 0 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , +( 13 ) 0 , 0 , 1 , 0 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , +( 14 ) 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 1 , 1 , 0 , 0 , 0 , 0 , +( 15 ) 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 1 , 1 , 0 , 0 , 0 , 0 , +( 16 ) 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 1 , 1 , 0 , 0 , +( 17 ) 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 1 , 1 , 0 , 0 , +( 18 ) 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , +( 19 ) 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , + +( Assumes anything outside the bounds is "dead" ) +{{ + variable surrounding + : get ( rc- ) + 2over [ 0 19 within ] bi@ and + [ world + [ 20 * ] dip + @ ] [ 2drop 0 ] if ; + : neighbor? ( rc- ) get +surrounding ; + : NW ( rc-rc ) 2over [ 1- ] bi@ neighbor? ; + : NN ( rc-rc ) 2over [ 1- ] dip neighbor? ; + : NE ( rc-rc ) 2over [ 1- ] dip 1+ neighbor? ; + : WW ( rc-rc ) 2over 1- neighbor? ; + : EE ( rc-rc ) 2over 1+ neighbor? ; + : SW ( rc-rc ) 2over [ 1+ ] dip 1- neighbor? ; + : SS ( rc-rc ) 2over [ 1+ ] dip neighbor? ; + : SE ( rc-rc ) 2over [ 1+ ] bi@ neighbor? ; + : count ( rc-rcn ) + 0 !surrounding + NW NN NE + WW EE + SW SS SE @surrounding ; + : alive ( rc-n ) + count + [ 0 1 within ] [ drop 0 ] when + [ 4 8 within ] [ drop 0 ] when + [ 2 3 within ] [ drop 1 ] when ; + : dead ( rc-n ) + count + [ 3 = ] [ drop 1 ] when + [ 0 2 within ] [ drop 0 ] when + [ 4 8 within ] [ drop 0 ] when ; + : newState ( rc-n ) + 2over get 1 = [ alive ] [ dead ] if ; + : set ( nrc- ) next + [ 20 * ] dip + ! ; + : cols ( r- ) + 20 [ over swap newState 2rot set ] iter drop ; + : output ( n- ) [ 'o ] [ '. ] if putc space ; +---reveal--- + : display ( - ) + cr world 20 [ 20 [ @+ output ] times cr ] times drop ; + : start ( - ) + initial world 20 20 * copy display ; + : gen ( - ) + 20 [ cols ] iter next world 20 20 * copy ; + : delay ( - ) time 1+ [ time over <= ] while drop ; + : run ( n- ) + [ delay clear gen display ] times ; +}} + +start 20 run diff --git a/src/cmd/retroforth/examples/rosetta_code/copy_a_string.rx b/src/cmd/retroforth/examples/rosetta_code/copy_a_string.rx new file mode 100644 index 0000000..88609ba --- /dev/null +++ b/src/cmd/retroforth/examples/rosetta_code/copy_a_string.rx @@ -0,0 +1 @@ +"this is a string" dup tempString diff --git a/src/cmd/retroforth/examples/rosetta_code/counting_in_octal.rx b/src/cmd/retroforth/examples/rosetta_code/counting_in_octal.rx new file mode 100644 index 0000000..21a1593 --- /dev/null +++ b/src/cmd/retroforth/examples/rosetta_code/counting_in_octal.rx @@ -0,0 +1,3 @@ +octal +17777777777 [ putn cr ] iter + diff --git a/src/cmd/retroforth/examples/rosetta_code/create_a_file.rx b/src/cmd/retroforth/examples/rosetta_code/create_a_file.rx new file mode 100644 index 0000000..e47cc4a --- /dev/null +++ b/src/cmd/retroforth/examples/rosetta_code/create_a_file.rx @@ -0,0 +1,3 @@ +with files' +"output.txt" :w open close drop +"/output.txt" :w open close drop diff --git a/src/cmd/retroforth/examples/rosetta_code/create_an_html_table.rx b/src/cmd/retroforth/examples/rosetta_code/create_an_html_table.rx new file mode 100644 index 0000000..de3101b --- /dev/null +++ b/src/cmd/retroforth/examples/rosetta_code/create_an_html_table.rx @@ -0,0 +1,16 @@ +Using the casket::html' library which allows creation of HTML using quotes and combinators: + + needs casket::html' + + with casket::html' + : rnd ( -$ ) random 1000 mod toString ; + + [ [ [ ] td [ "x" ] td [ "y" ] td [ "z" ] td ] tr + [ [ "1" ] td [ rnd ] td [ rnd ] td [ rnd ] td ] tr + [ [ "2" ] td [ rnd ] td [ rnd ] td [ rnd ] td ] tr + [ [ "3" ] td [ rnd ] td [ rnd ] td [ rnd ] td ] tr + [ [ "4" ] td [ rnd ] td [ rnd ] td [ rnd ] td ] tr + [ [ "5" ] td [ rnd ] td [ rnd ] td [ rnd ] td ] tr + [ [ "6" ] td [ rnd ] td [ rnd ] td [ rnd ] td ] tr + ] table + diff --git a/src/cmd/retroforth/examples/rosetta_code/define_a_primitive_type.rx b/src/cmd/retroforth/examples/rosetta_code/define_a_primitive_type.rx new file mode 100644 index 0000000..9a9c7cc --- /dev/null +++ b/src/cmd/retroforth/examples/rosetta_code/define_a_primitive_type.rx @@ -0,0 +1,17 @@ +{{ + variable update +---reveal--- + : .limited @update &! &@ if update off ; + : to dup 1 10 within [ update on ] [ drop "Out of bounds\n" puts ] if ; + : limited: create 1 , &.limited reclass ; +}} + +This creates a data element that returns a value from 1 to 10. Alteration +of the value is possible using to. + +limited: foo +1 to foo +foo .s +51 to foo +foo .s +bye diff --git a/src/cmd/retroforth/examples/rosetta_code/delete_a_file.rx b/src/cmd/retroforth/examples/rosetta_code/delete_a_file.rx new file mode 100644 index 0000000..7e0f24d --- /dev/null +++ b/src/cmd/retroforth/examples/rosetta_code/delete_a_file.rx @@ -0,0 +1,3 @@ +with files' +"input.txt" delete +"/input.txt" delete diff --git a/src/cmd/retroforth/examples/rosetta_code/determine_if_a_string_is_numeric.rx b/src/cmd/retroforth/examples/rosetta_code/determine_if_a_string_is_numeric.rx new file mode 100644 index 0000000..d49f4b7 --- /dev/null +++ b/src/cmd/retroforth/examples/rosetta_code/determine_if_a_string_is_numeric.rx @@ -0,0 +1,3 @@ +Retro does not have floating point numbers. For others, it provides isNumber?: + +"123" isNumber? diff --git a/src/cmd/retroforth/examples/rosetta_code/documentation.rx b/src/cmd/retroforth/examples/rosetta_code/documentation.rx new file mode 100644 index 0000000..e30ed73 --- /dev/null +++ b/src/cmd/retroforth/examples/rosetta_code/documentation.rx @@ -0,0 +1,20 @@ +Retro allows for insertion of documentation blocks. The contents of these can be +in any format desired, though the standard Retro system uses Restructured Text for +all embedded and external documentation. + + doc{ + ============= + Function: foo + ============= + + Stack + ---- + a1 a2 - b + + Usage + ----- + Adds a1 to a2 returning b. + }doc + + : foo ( aa-b ) + ; + diff --git a/src/cmd/retroforth/examples/rosetta_code/dynamic_variable_names.rx b/src/cmd/retroforth/examples/rosetta_code/dynamic_variable_names.rx new file mode 100644 index 0000000..fe3ca69 --- /dev/null +++ b/src/cmd/retroforth/examples/rosetta_code/dynamic_variable_names.rx @@ -0,0 +1,11 @@ +: newVariable: ( "- ) + getToken header 0 , ; + +newVariable: foo + +Or: + +: newVariable: ( "- ) + create 0 , ; + +newVariable: foo diff --git a/src/cmd/retroforth/examples/rosetta_code/empty_program.rx b/src/cmd/retroforth/examples/rosetta_code/empty_program.rx new file mode 100644 index 0000000..cb00094 --- /dev/null +++ b/src/cmd/retroforth/examples/rosetta_code/empty_program.rx @@ -0,0 +1,7 @@ +An empty file is the smallest valid program. + +To save a turnkey application doing nothing, you need to do a bit more +work though: + +&bye is boot +save diff --git a/src/cmd/retroforth/examples/rosetta_code/empty_string.rx b/src/cmd/retroforth/examples/rosetta_code/empty_string.rx new file mode 100644 index 0000000..7a9c23c --- /dev/null +++ b/src/cmd/retroforth/examples/rosetta_code/empty_string.rx @@ -0,0 +1,23 @@ +Create an empty string and assign it to a variable. In these keepString is +used to ensure that the string is permanent. + + ( by creating a variable ) + "" keepString variable: foo + + ( by setting an existing variable 'foo' ) + "" keepString !foo + +Checking that a string is empty. A string with a length of zero is assumed to be empty. + + : emtpy? ( $-f ) getLength 0 = ; + + "" empty? putn + "hello" empty? putn + +Check that a string is not empty. + + : notEmpty? ( $-f ) getLength 0 > ; + + "" notEmpty? putn + "hello" notEmpty? putn + diff --git a/src/cmd/retroforth/examples/rosetta_code/environment_variables.rx b/src/cmd/retroforth/examples/rosetta_code/environment_variables.rx new file mode 100644 index 0000000..2736eda --- /dev/null +++ b/src/cmd/retroforth/examples/rosetta_code/environment_variables.rx @@ -0,0 +1,2 @@ +here "HOME" getEnv +here puts diff --git a/src/cmd/retroforth/examples/rosetta_code/execute_brainf___.rx b/src/cmd/retroforth/examples/rosetta_code/execute_brainf___.rx new file mode 100644 index 0000000..569c8d4 --- /dev/null +++ b/src/cmd/retroforth/examples/rosetta_code/execute_brainf___.rx @@ -0,0 +1,155 @@ + ( Ngaro Assembler ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) + ( Copyright [c] 2008 - 2011, Charles Childers ) + ( Copyright [c] 2009 - 2010, Luke Parrish ) + ( Copyright [c] 2010, Marc Simpson ) + ( Copyright [c] 2010, Jay Skeer ) + ( ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) + + 8000 constant MAX-APP-SIZE + + ( Assembler ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) + 3 elements target origin fid + : pad ( - ) @origin 32 + !target ; + : m, ( n- ) @target !+ !target ; + : vm: ( n"- ) ` : .data ` m, ` ; ; + 0 vm: nop, 1 vm: lit, 2 vm: dup, + 3 vm: drop, 4 vm: swap, 5 vm: push, + 6 vm: pop, 7 vm: loop, 8 vm: jump, + 9 vm: ret, 10 vm: >jump, 11 vm: >, 25 vm: 0; 26 vm: 1+, + 27 vm: 1-, 28 vm: in, 29 vm: out, + 30 vm: wait, + + : t-here ( -n ) @target @origin - ; + + {{ + : writeByte ( n- ) + @fid ^files'write drop ; + + : applyMask ( n- ) + %00000000000000000000000011111111 and ; + + : writeCell ( n- ) + dup applyMask writeByte + 8 >> dup applyMask writeByte + 8 >> dup applyMask writeByte + 8 >> applyMask writeByte ; + ---reveal--- + : saveImage ( - ) + "appImage" ^files':W ^files'open !fid + @origin t-here [ @+ writeCell ] times drop + @fid ^files'close drop bye ; + }} + + : endApp ( - ) + t-here "\nApp ends @ %d\n" puts + MAX-APP-SIZE t-here - "%d cells free" puts + depth 1 >= [ "\nError in stack depth!: " puts .s ] ifTrue ; + : :main ( - ) t-here [ "\nMAIN @ %d" puts ] [ @origin 1+ ! ] bi ; + : # ( n- ) lit, m, ; + : __# ( $- ) lit, toNumber m, ; parsing + : $, ( $- ) withLength [ @+ m, ] times 0 m, drop ; + + : __: ( $- ) header t-here @last !d->xt ; parsing + : call ( "- ) ' m, ; + : jump ( "- ) 8 m, ' m, ; + + ( Setup target memory for new image ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) + here [ !target ] [ !origin ] bi MAX-APP-SIZE allot + jump, 0 m, pad + reset + + + ( Support functions: basic input, output, and data pointer support ) + :wait + #0 #0 out, + wait, + ret, + + :bye + #-9 #5 out, + ret, + + :dp 32768 m, + + :bf_> + dp # @, + 1+, + dp # !, + ret, + + :bf_< + dp # @, + 1-, + dp # !, + ret, + + :bf_+ + dp # @, @, + 1+, + dp # @, !, + ret, + + :bf_- + dp # @, @, + 1-, + dp # @, !, + ret, + + :bf_. + dp # @, @, + #1 #2 out, + call wait + #0 #3 out, + ret, + + :bf_, + #1 #1 out, + call wait + #1 in, + dp # @, !, + ret, + + ( Actual BrainF*** compiler ) + variable ip + + : run + t-here putn space @ip @ putc cr + @ip @ ip ++ + [ '> = ] [ drop bf_> m, ] when + [ '< = ] [ drop bf_< m, ] when + [ '+ = ] [ drop bf_+ m, ] when + [ '- = ] [ drop bf_- m, ] when + [ '. = ] [ drop bf_. m, ] when + [ ', = ] [ drop bf_, m, ] when + [ '[ = ] [ drop t-here dp # @, @, lit, 0 m, =jump, @target 0 m, ] when + [ '] = ] [ drop swap jump, m, t-here swap ! ] when + drop ; + + : do + [ run @ip @ ] while ; + + : bf: ( "- ) + '~ accept tib keepString !ip cr do ; + + ( Start Compilation of BrainF*** code after this ) + :main + +Apart from support code, the actual compiler is implemented in the run function. +This accepts sources like: + + bf: >+++++++++[<++++++++>-]<.>+++++++[<++++>-]<+.+++++++..+++.[-]>++++++++[<++++>-]~ + bf: <.>+++++++++++[<+++++>-]<.>++++++++[<+++>-]<.+++.------.--------.[-]>++++++++[~ + bf: <++++>-]<+.[-]++++++++++.~ + + endApp + saveImage + +And upon completion a new appImage file is created. This can be run from the command line, using the --image command line argument: + + ./retro --image appImage + diff --git a/src/cmd/retroforth/examples/rosetta_code/exponentiaion_operator.rx b/src/cmd/retroforth/examples/rosetta_code/exponentiaion_operator.rx new file mode 100644 index 0000000..f993b53 --- /dev/null +++ b/src/cmd/retroforth/examples/rosetta_code/exponentiaion_operator.rx @@ -0,0 +1,9 @@ +etro has no floating point support in the standard VM. + +From the math' vocabulary: + +: pow ( bp-n ) 1 swap [ over * ] times nip ; + +And in use: + +2 5 ^math'pow diff --git a/src/cmd/retroforth/examples/rosetta_code/extend_your_language.rx b/src/cmd/retroforth/examples/rosetta_code/extend_your_language.rx new file mode 100644 index 0000000..7c36d74 --- /dev/null +++ b/src/cmd/retroforth/examples/rosetta_code/extend_your_language.rx @@ -0,0 +1,18 @@ +Since flow control is handled using combinators, we simply define a new one: + +: 4wayIf ( flag flag both neither first second ) + heap [ cons &cons dip [ [ cons ] dip ] dip rot ] preserve + [ do [ -1 = ] bi@ and ] [ 2drop do drop do ] when + [ do [ 0 = ] bi@ and ] [ 2drop do nip do ] when + [ do 0 = swap -1 = and ] [ drop nip do drop do ] when + [ do -1 = swap 0 = and ] [ drop nip do nip do ] when + drop 2drop ; + +This is fairly noisy in terms of stack manipulations, but its +usage is clean and consistent with the rest of Retro: + +: test +-1 -1 [ 1 ] [ 2 ] [ 3 ] [ 4 ] 4wayIf .s drop + 0 0 [ 1 ] [ 2 ] [ 3 ] [ 4 ] 4wayIf .s drop +-1 0 [ 1 ] [ 2 ] [ 3 ] [ 4 ] 4wayIf .s drop + 0 -1 [ 1 ] [ 2 ] [ 3 ] [ 4 ] 4wayIf .s drop ; diff --git a/src/cmd/retroforth/examples/rosetta_code/factorial.rx b/src/cmd/retroforth/examples/rosetta_code/factorial.rx new file mode 100644 index 0000000..8af7901 --- /dev/null +++ b/src/cmd/retroforth/examples/rosetta_code/factorial.rx @@ -0,0 +1,4 @@ +A recursive implementation from the benchmarking code. + +: dup 1 = if; dup 1- * ; +: factorial dup 0 = [ 1+ ] [ ] if ; diff --git a/src/cmd/retroforth/examples/rosetta_code/fibonacci_sequence.rx b/src/cmd/retroforth/examples/rosetta_code/fibonacci_sequence.rx new file mode 100644 index 0000000..460b1f1 --- /dev/null +++ b/src/cmd/retroforth/examples/rosetta_code/fibonacci_sequence.rx @@ -0,0 +1,11 @@ +Recursive + +: fib ( n-m ) dup [ 0 = ] [ 1 = ] bi or if; [ 1- fib ] sip [ 2 - fib ] do + ; + + +Iterative + +2 elements previous result +: fib ( n-m ) + -1 !previous 1 !result + 1+ [ @result @previous over + !result !previous ] times @result ; diff --git a/src/cmd/retroforth/examples/rosetta_code/file_io.rx b/src/cmd/retroforth/examples/rosetta_code/file_io.rx new file mode 100644 index 0000000..0d76726 --- /dev/null +++ b/src/cmd/retroforth/examples/rosetta_code/file_io.rx @@ -0,0 +1,2 @@ +with files' +here dup "input.txt" slurp "output.txt" spew diff --git a/src/cmd/retroforth/examples/rosetta_code/file_size.rx b/src/cmd/retroforth/examples/rosetta_code/file_size.rx new file mode 100644 index 0000000..ca8cca2 --- /dev/null +++ b/src/cmd/retroforth/examples/rosetta_code/file_size.rx @@ -0,0 +1,22 @@ +The simple way is to open and read the size. This may crash if the file does not exist. + +with files' +"input.txt" :R open &size sip close drop putn +"/input.txt" :R open &size sip close drop putn + +For added stability, check that the returned file handle is not zero: + +with files' +"input.txt" :r open over 0 <> [ &size sip close drop ] ifTrue + +Or, if you need to do this more often, setup a function that'll also display an error +message if the file does not exist: + +with files' +: getFileSize ( $-n ) + :r open 0 over = + [ "File does Not Exist\n" puts ] + [ &size sip close drop ] if ; + +"input.txt" getFileSize putn +"/input.txt" getFileSize putn diff --git a/src/cmd/retroforth/examples/rosetta_code/find_limit_of_recursion.rx b/src/cmd/retroforth/examples/rosetta_code/find_limit_of_recursion.rx new file mode 100644 index 0000000..8ee0e1c --- /dev/null +++ b/src/cmd/retroforth/examples/rosetta_code/find_limit_of_recursion.rx @@ -0,0 +1,4 @@ +When run, this will display the address stack depth until it reaches the max depth. Once +the address stack is full, Retro will crash. + +: try -6 5 out wait 5 in putn cr try ; diff --git a/src/cmd/retroforth/examples/rosetta_code/fizzbuzz.rx b/src/cmd/retroforth/examples/rosetta_code/fizzbuzz.rx new file mode 100644 index 0000000..f610541 --- /dev/null +++ b/src/cmd/retroforth/examples/rosetta_code/fizzbuzz.rx @@ -0,0 +1,16 @@ +: fizz? ( s-f ) 3 mod 0 = ; +: buzz? ( s-f ) 5 mod 0 = ; +: num? ( s-f ) dup fizz? swap buzz? or 0 = ; +: ?fizz ( s- ) fizz? [ "Fizz" puts ] ifTrue ; +: ?buzz ( s- ) buzz? [ "Buzz" puts ] ifTrue ; +: ?num ( s- ) num? &putn &drop if ; +: fizzbuzz ( s- ) dup ?fizz dup ?buzz dup ?num space ; +: all ( - ) 100 [ 1+ fizzbuzz ] iter ; + + +needs math' +: + [ 15 ^math'divisor? ] [ drop "FizzBuzz" puts ] when + [ 3 ^math'divisor? ] [ drop "Fizz" puts ] when + [ 5 ^math'divisor? ] [ drop "Buzz" puts ] when putn ; +: fizzbuzz cr 100 [ 1+ space ] iter ; diff --git a/src/cmd/retroforth/examples/rosetta_code/function_definition.rx b/src/cmd/retroforth/examples/rosetta_code/function_definition.rx new file mode 100644 index 0000000..c05d297 --- /dev/null +++ b/src/cmd/retroforth/examples/rosetta_code/function_definition.rx @@ -0,0 +1 @@ +: multiply ( nn-n ) * ; diff --git a/src/cmd/retroforth/examples/rosetta_code/greatest_common_divisor.rx b/src/cmd/retroforth/examples/rosetta_code/greatest_common_divisor.rx new file mode 100644 index 0000000..cc5fe7d --- /dev/null +++ b/src/cmd/retroforth/examples/rosetta_code/greatest_common_divisor.rx @@ -0,0 +1,3 @@ +This is from the math extensions library. + +: gcd ( ab-n ) [ tuck mod dup ] while drop ; diff --git a/src/cmd/retroforth/examples/rosetta_code/guess_the_number.rx b/src/cmd/retroforth/examples/rosetta_code/guess_the_number.rx new file mode 100644 index 0000000..ff5f84b --- /dev/null +++ b/src/cmd/retroforth/examples/rosetta_code/guess_the_number.rx @@ -0,0 +1,12 @@ +: checkGuess ( gn-gf || f ) + over = [ drop 0 ] [ "Sorry, try again!\n" puts -1 ] if ; + +: think ( -n ) + random abs 10 mod 1+ ; + +: guess ( - ) + "I'm thinking of a number between 1 and 10.\n" puts + "Try to guess it!\n" puts + think [ getNumber checkGuess ] while + "You got it!\n" puts ; + diff --git a/src/cmd/retroforth/examples/rosetta_code/guess_the_number_with_feedback.rx b/src/cmd/retroforth/examples/rosetta_code/guess_the_number_with_feedback.rx new file mode 100644 index 0000000..eb894c1 --- /dev/null +++ b/src/cmd/retroforth/examples/rosetta_code/guess_the_number_with_feedback.rx @@ -0,0 +1,16 @@ +: high|low ( gn-g$ ) + over > [ "high" ] [ "low" ] if ; + +: checkGuess ( gn-gf || f ) + 2over = [ "You guessed correctly!\n" puts 2drop 0 ] + [ high|low "Sorry, your guess was too %s.\nTry again.\n" puts -1 ] if ; + +: think ( -n ) + random abs 100 mod 1+ ; + +: guess ( - ) + "I'm thinking of a number between 1 and 100.\n" puts + "Try to guess it!\n" puts + think [ getNumber checkGuess ] while + "You got it!\n" puts ; + diff --git a/src/cmd/retroforth/examples/rosetta_code/hanoi.rx b/src/cmd/retroforth/examples/rosetta_code/hanoi.rx new file mode 100644 index 0000000..ca6b419 --- /dev/null +++ b/src/cmd/retroforth/examples/rosetta_code/hanoi.rx @@ -0,0 +1,14 @@ +4 elements a b c n + +: vars !c !b !a !n ; +: hanoi ( num from to via -- ) + vars + @n 0 <> + [ + @n @a @b @c + @n 1- @a @c @b hanoi + vars + @b @a "\nMove a ring from %d to %d" puts + @n 1- @c @b @a hanoi + ] ifTrue ; + diff --git a/src/cmd/retroforth/examples/rosetta_code/hello_world_standard_error.rx b/src/cmd/retroforth/examples/rosetta_code/hello_world_standard_error.rx new file mode 100644 index 0000000..c6efcf4 --- /dev/null +++ b/src/cmd/retroforth/examples/rosetta_code/hello_world_standard_error.rx @@ -0,0 +1 @@ +"Goodbye, World!" withLength "/dev/stderr" ^files'spew diff --git a/src/cmd/retroforth/examples/rosetta_code/hello_world_text.rx b/src/cmd/retroforth/examples/rosetta_code/hello_world_text.rx new file mode 100644 index 0000000..a84145f --- /dev/null +++ b/src/cmd/retroforth/examples/rosetta_code/hello_world_text.rx @@ -0,0 +1 @@ +"Goodbye, World!" puts diff --git a/src/cmd/retroforth/examples/rosetta_code/increment_a_numerical_string.rx b/src/cmd/retroforth/examples/rosetta_code/increment_a_numerical_string.rx new file mode 100644 index 0000000..99821ea --- /dev/null +++ b/src/cmd/retroforth/examples/rosetta_code/increment_a_numerical_string.rx @@ -0,0 +1 @@ +"123" toNumber 1+ toString diff --git a/src/cmd/retroforth/examples/rosetta_code/integer_comparison.rx b/src/cmd/retroforth/examples/rosetta_code/integer_comparison.rx new file mode 100644 index 0000000..307434d --- /dev/null +++ b/src/cmd/retroforth/examples/rosetta_code/integer_comparison.rx @@ -0,0 +1,15 @@ +Taking the numbers from the stack: + +: example ( ab- ) + cons + [ do > [ "A > B\n" puts ] ifTrue ] + [ do < [ "A < B\n" puts ] ifTrue ] + [ do = [ "A = B\n" puts ] ifTrue ] tri ; + +Or, to parse for numbers: + +: example ( ab- ) + getToken getToken &toNumber bi@ cons + [ do > [ "A > B\n" puts ] ifTrue ] + [ do < [ "A < B\n" puts ] ifTrue ] + [ do = [ "A = B\n" puts ] ifTrue ] tri ; diff --git a/src/cmd/retroforth/examples/rosetta_code/integer_sequence.rx b/src/cmd/retroforth/examples/rosetta_code/integer_sequence.rx new file mode 100644 index 0000000..91199a5 --- /dev/null +++ b/src/cmd/retroforth/examples/rosetta_code/integer_sequence.rx @@ -0,0 +1 @@ +0 [ [ putn space ] sip 1+ dup 0 <> ] while drop diff --git a/src/cmd/retroforth/examples/rosetta_code/interactive_programming.rx b/src/cmd/retroforth/examples/rosetta_code/interactive_programming.rx new file mode 100644 index 0000000..b301b3e --- /dev/null +++ b/src/cmd/retroforth/examples/rosetta_code/interactive_programming.rx @@ -0,0 +1,6 @@ +Retro's interpreter is started automatically. Once you see the "ok" prompt, you can proceed +to enter code: + +: f ( $$$-$ ) [ ^strings'prepend ] sip ^strings'prepend ^strings'append tempString ; +"Rosetta" "Code" ":" f + diff --git a/src/cmd/retroforth/examples/rosetta_code/leap_year.rx b/src/cmd/retroforth/examples/rosetta_code/leap_year.rx new file mode 100644 index 0000000..6a7cebf --- /dev/null +++ b/src/cmd/retroforth/examples/rosetta_code/leap_year.rx @@ -0,0 +1,5 @@ + : isLeapYear? ( y-f ) + dup 400 mod 0 = [ drop -1 0 ] [ 1 ] if 0; drop + dup 100 mod 0 = [ drop 0 0 ] [ 1 ] if 0; drop + 4 mod 0 = ; + diff --git a/src/cmd/retroforth/examples/rosetta_code/least_common_multiple.rx b/src/cmd/retroforth/examples/rosetta_code/least_common_multiple.rx new file mode 100644 index 0000000..f863898 --- /dev/null +++ b/src/cmd/retroforth/examples/rosetta_code/least_common_multiple.rx @@ -0,0 +1,4 @@ +This is from the math extensions library included with Retro. + +: gcd ( ab-n ) [ tuck mod dup ] while drop ; +: lcm ( ab-n ) 2over gcd [ * ] dip / ; diff --git a/src/cmd/retroforth/examples/rosetta_code/literals_integer.rx b/src/cmd/retroforth/examples/rosetta_code/literals_integer.rx new file mode 100644 index 0000000..eb9dc29 --- /dev/null +++ b/src/cmd/retroforth/examples/rosetta_code/literals_integer.rx @@ -0,0 +1,9 @@ +#100 ( decimal ) +%100 ( binary ) +$100 ( hex ) +'c ( ascii character ) +100 ( number in current base ) + +Numbers without a prefix are interpreted using the current base, which +is a variable Valid characters are stored in a string called numbers, +which can also be altered to allow for larger bases. diff --git a/src/cmd/retroforth/examples/rosetta_code/literals_string.rx b/src/cmd/retroforth/examples/rosetta_code/literals_string.rx new file mode 100644 index 0000000..e0ea6e4 --- /dev/null +++ b/src/cmd/retroforth/examples/rosetta_code/literals_string.rx @@ -0,0 +1,5 @@ +Strings are enclosed in double quotes, and can contain anything other than a double quote. +ASCII characters are prefixed by a single quote. + +'c +"hello, world!" diff --git a/src/cmd/retroforth/examples/rosetta_code/loops_downward_for.rx b/src/cmd/retroforth/examples/rosetta_code/loops_downward_for.rx new file mode 100644 index 0000000..0def26c --- /dev/null +++ b/src/cmd/retroforth/examples/rosetta_code/loops_downward_for.rx @@ -0,0 +1,2 @@ +11 [ putn space ] iterd + diff --git a/src/cmd/retroforth/examples/rosetta_code/loops_for.rx b/src/cmd/retroforth/examples/rosetta_code/loops_for.rx new file mode 100644 index 0000000..14b9148 --- /dev/null +++ b/src/cmd/retroforth/examples/rosetta_code/loops_for.rx @@ -0,0 +1,2 @@ +6 [ 0; cr [ '* emit ] times ] iter + diff --git a/src/cmd/retroforth/examples/rosetta_code/loops_infinite.rx b/src/cmd/retroforth/examples/rosetta_code/loops_infinite.rx new file mode 100644 index 0000000..19376aa --- /dev/null +++ b/src/cmd/retroforth/examples/rosetta_code/loops_infinite.rx @@ -0,0 +1,2 @@ +[ "SPAM\n" puts -1 ] while + diff --git a/src/cmd/retroforth/examples/rosetta_code/loops_while.rx b/src/cmd/retroforth/examples/rosetta_code/loops_while.rx new file mode 100644 index 0000000..1a0bb7c --- /dev/null +++ b/src/cmd/retroforth/examples/rosetta_code/loops_while.rx @@ -0,0 +1,2 @@ +1024 [ cr &putn sip 2 / dup ] while + diff --git a/src/cmd/retroforth/examples/rosetta_code/memory_allocation.rx b/src/cmd/retroforth/examples/rosetta_code/memory_allocation.rx new file mode 100644 index 0000000..ba11759 --- /dev/null +++ b/src/cmd/retroforth/examples/rosetta_code/memory_allocation.rx @@ -0,0 +1,19 @@ +Retro's memory is directly accessible via @ and !. This is used for all functions and +data structures. A variable, heap, points to the next free address. allot can be used +to allocate or free memory. The amount of memory varies by the runtime, and can be +accessed via the memory variable. + +( display total memory available ) +@memory putn + +( display unused memory ) +@memory here - putn + +( display next free address ) +here putn + +( allocate 1000 cells ) +1000 allot + +( free 500 cells ) +-500 allot diff --git a/src/cmd/retroforth/examples/rosetta_code/mouse_position.rx b/src/cmd/retroforth/examples/rosetta_code/mouse_position.rx new file mode 100644 index 0000000..c106dff --- /dev/null +++ b/src/cmd/retroforth/examples/rosetta_code/mouse_position.rx @@ -0,0 +1,4 @@ +This currently requires a VM with support for the canvas device. + +needs canvas' +^canvas'mouse diff --git a/src/cmd/retroforth/examples/rosetta_code/palindrome_detection.rx b/src/cmd/retroforth/examples/rosetta_code/palindrome_detection.rx new file mode 100644 index 0000000..372ec34 --- /dev/null +++ b/src/cmd/retroforth/examples/rosetta_code/palindrome_detection.rx @@ -0,0 +1,5 @@ +needs hash' +: palindrome? ( $-f ) dup ^hash'hash [ ^strings'reverse ^hash'hash ] dip = ; + +"ingirumimusnocteetconsumimurigni" palindrome? putn + diff --git a/src/cmd/retroforth/examples/rosetta_code/pangram_checker.rx b/src/cmd/retroforth/examples/rosetta_code/pangram_checker.rx new file mode 100644 index 0000000..d5e061c --- /dev/null +++ b/src/cmd/retroforth/examples/rosetta_code/pangram_checker.rx @@ -0,0 +1,5 @@ +: isPangram? ( $-f ) + ^strings'toLower + heap [ 27 allot ] preserve + [ @ 'a - dup 0 25 within [ [ 'a + ] [ here + ] bi ! ] &drop if ] + ^types'STRING each@ here "abcdefghijklmnopqrstuvwxyz" compare ; diff --git a/src/cmd/retroforth/examples/rosetta_code/program_termination.rx b/src/cmd/retroforth/examples/rosetta_code/program_termination.rx new file mode 100644 index 0000000..e1d579d --- /dev/null +++ b/src/cmd/retroforth/examples/rosetta_code/program_termination.rx @@ -0,0 +1,2 @@ +problem? [ bye ] ifTrue + diff --git a/src/cmd/retroforth/examples/rosetta_code/read_entire_file.rx b/src/cmd/retroforth/examples/rosetta_code/read_entire_file.rx new file mode 100644 index 0000000..a2d95b1 --- /dev/null +++ b/src/cmd/retroforth/examples/rosetta_code/read_entire_file.rx @@ -0,0 +1,2 @@ +with files' +here "input.txt" slurp diff --git a/src/cmd/retroforth/examples/rosetta_code/repeat_a_string.rx b/src/cmd/retroforth/examples/rosetta_code/repeat_a_string.rx new file mode 100644 index 0000000..0c66e62 --- /dev/null +++ b/src/cmd/retroforth/examples/rosetta_code/repeat_a_string.rx @@ -0,0 +1,5 @@ +with strings' +: repeatString ( $n-$ ) + 1- [ dup ] dip [ over prepend ] times nip ; + +"ha" 5 repeatString diff --git a/src/cmd/retroforth/examples/rosetta_code/reverse_a_string.rx b/src/cmd/retroforth/examples/rosetta_code/reverse_a_string.rx new file mode 100644 index 0000000..80f570d --- /dev/null +++ b/src/cmd/retroforth/examples/rosetta_code/reverse_a_string.rx @@ -0,0 +1,2 @@ +with strings' +"asdf" reverse puts diff --git a/src/cmd/retroforth/examples/rosetta_code/roman_numerals.rx b/src/cmd/retroforth/examples/rosetta_code/roman_numerals.rx new file mode 100644 index 0000000..626722d --- /dev/null +++ b/src/cmd/retroforth/examples/rosetta_code/roman_numerals.rx @@ -0,0 +1,28 @@ +This is a port of the Forth code; but returns a string rather than displaying +the roman numerals. It only handles numbers between 1 and 3999. + +: vector ( ...n"- ) + here [ &, times ] dip : .data ` swap ` + ` @ ` do ` ; ; +: .I dup @ ^buffer'add ; +: .V dup 1 + @ ^buffer'add ; +: .X dup 2 + @ ^buffer'add ; + +[ .I .X drop ] +[ .V .I .I .I drop ] +[ .V .I .I drop ] +[ .V .I drop ] +[ .V drop ] +[ .I .V drop ] +[ .I .I .I drop ] +[ .I .I drop ] +[ .I drop ] +&drop +10 vector .digit + +: record ( an- ) + 10 /mod dup [ [ over 2 + ] dip record ] &drop if .digit ; +: toRoman ( n-a ) + here ^buffer'set + dup 1 3999 within 0 = + [ "EX LIMITO!\n" ] [ "IVXLCDM" swap record here ] if ; + diff --git a/src/cmd/retroforth/examples/rosetta_code/rot-13.rx b/src/cmd/retroforth/examples/rosetta_code/rot-13.rx new file mode 100644 index 0000000..9003155 --- /dev/null +++ b/src/cmd/retroforth/examples/rosetta_code/rot-13.rx @@ -0,0 +1,11 @@ +{{ + : rotate ( cb-c ) tuck - 13 + 26 mod + ; + : rotate? ( c-c ) + dup 'a 'z within [ 'a rotate ] ifTrue + dup 'A 'Z within [ 'A rotate ] ifTrue ; +---reveal--- + : rot13 ( s-s ) dup [ [ @ rotate? ] sip ! ] ^types'STRING each@ ; +}} + +"abcdef123GHIJKL" rot13 dup puts cr rot13 puts +"abjurer NOWHERE" rot13 puts diff --git a/src/cmd/retroforth/examples/rosetta_code/shell_one-liner.rx b/src/cmd/retroforth/examples/rosetta_code/shell_one-liner.rx new file mode 100644 index 0000000..17d48f9 --- /dev/null +++ b/src/cmd/retroforth/examples/rosetta_code/shell_one-liner.rx @@ -0,0 +1,2 @@ +echo '"hello\n" puts bye' | ./retro + diff --git a/src/cmd/retroforth/examples/rosetta_code/singly_linked_list_transversal.rx b/src/cmd/retroforth/examples/rosetta_code/singly_linked_list_transversal.rx new file mode 100644 index 0000000..6c7cc17 --- /dev/null +++ b/src/cmd/retroforth/examples/rosetta_code/singly_linked_list_transversal.rx @@ -0,0 +1,9 @@ +: traverse ( l- ) repeat @ 0; again ; + +Or, using combinators: + +last [ drop ] ^types'LIST each@ + +With combinators you can also perform an operation on each element in a linked list: + +last [ @d->name puts space ] ^types'LIST each@ diff --git a/src/cmd/retroforth/examples/rosetta_code/sleep.rx b/src/cmd/retroforth/examples/rosetta_code/sleep.rx new file mode 100644 index 0000000..17abf8f --- /dev/null +++ b/src/cmd/retroforth/examples/rosetta_code/sleep.rx @@ -0,0 +1,9 @@ +Retro has no fine grained timer; so we have to make due with seconds. + +: sleep ( n- ) + [ time [ time over - 1 > ] until drop ] times ; + +: test + "\nTime to sleep (in seconds): " puts getNumber + "\nSleeping..." sleep + "\nAwake!\n" ; diff --git a/src/cmd/retroforth/examples/rosetta_code/stack.rx b/src/cmd/retroforth/examples/rosetta_code/stack.rx new file mode 100644 index 0000000..3422296 --- /dev/null +++ b/src/cmd/retroforth/examples/rosetta_code/stack.rx @@ -0,0 +1,15 @@ +: stack ( n"- ) create 0 , allot ; +: push ( na- ) dup ++ dup @ + ! ; +: pop ( a-n ) dup @ over -- + @ ; +: top ( a-n ) dup @ + @ ; +: empty? ( a-f ) @ 0 = ; + +10 stack st + +1 st push +2 st push +3 st push +st empty? putn +st top putn +st pop putn st pop putn st pop putn +st empty? putn diff --git a/src/cmd/retroforth/examples/rosetta_code/string_case.rx b/src/cmd/retroforth/examples/rosetta_code/string_case.rx new file mode 100644 index 0000000..c3305ff --- /dev/null +++ b/src/cmd/retroforth/examples/rosetta_code/string_case.rx @@ -0,0 +1,3 @@ +with strings' +"alphaBETA" toUpper puts +"alphaBETA" toLower puts diff --git a/src/cmd/retroforth/examples/rosetta_code/string_concatenation.rx b/src/cmd/retroforth/examples/rosetta_code/string_concatenation.rx new file mode 100644 index 0000000..3555a25 --- /dev/null +++ b/src/cmd/retroforth/examples/rosetta_code/string_concatenation.rx @@ -0,0 +1,2 @@ +with strings' +"hello" "literal" append puts diff --git a/src/cmd/retroforth/examples/rosetta_code/string_length.rx b/src/cmd/retroforth/examples/rosetta_code/string_length.rx new file mode 100644 index 0000000..b8b83a5 --- /dev/null +++ b/src/cmd/retroforth/examples/rosetta_code/string_length.rx @@ -0,0 +1,23 @@ +Byte Length + +"møøse" getLength putn + +Character Length + +Retro does not have built-in support for Unicode, but counting of +UTF8 characters can be done with a small amount of effort. + +chain: UTF8' +{{ + : utf+ ( $-$ ) + [ 1+ dup @ %11000000 and %10000000 = ] while ; + : count ( $-$ ) + 0 !here + repeat dup @ 0; drop utf+ here ++ again ; +---reveal--- + : getLength ( $-n ) + count drop @here ; +}} +;chain + +"møøse" ^UTF8'getLength putn diff --git a/src/cmd/retroforth/examples/rosetta_code/system_time.rx b/src/cmd/retroforth/examples/rosetta_code/system_time.rx new file mode 100644 index 0000000..042c34c --- /dev/null +++ b/src/cmd/retroforth/examples/rosetta_code/system_time.rx @@ -0,0 +1,3 @@ +Displays the number of seconds since the Unix epoch: + +time putn diff --git a/src/cmd/retroforth/examples/rosetta_code/terminal_control_clear_the_screen.rx b/src/cmd/retroforth/examples/rosetta_code/terminal_control_clear_the_screen.rx new file mode 100644 index 0000000..efa6e54 --- /dev/null +++ b/src/cmd/retroforth/examples/rosetta_code/terminal_control_clear_the_screen.rx @@ -0,0 +1,2 @@ +clear + diff --git a/src/cmd/retroforth/examples/rosetta_code/terminal_control_determine_the_height_and_width_of_the_terminal_window.rx b/src/cmd/retroforth/examples/rosetta_code/terminal_control_determine_the_height_and_width_of_the_terminal_window.rx new file mode 100644 index 0000000..2051683 --- /dev/null +++ b/src/cmd/retroforth/examples/rosetta_code/terminal_control_determine_the_height_and_width_of_the_terminal_window.rx @@ -0,0 +1,5 @@ +This information is provided by Retro in the ch (height) and cw (width) variables. +You can manually obtain the values by using I/O ports: + +-3 5 out wait 5 in !cw +-4 5 out wait 5 in !ch diff --git a/src/cmd/retroforth/examples/rosetta_code/terminal_control_moving_the_cursor_to_a_specific_location_on_the_screen.rx b/src/cmd/retroforth/examples/rosetta_code/terminal_control_moving_the_cursor_to_a_specific_location_on_the_screen.rx new file mode 100644 index 0000000..1b95673 --- /dev/null +++ b/src/cmd/retroforth/examples/rosetta_code/terminal_control_moving_the_cursor_to_a_specific_location_on_the_screen.rx @@ -0,0 +1,2 @@ +with console' +: hello 3 6 at-xy "Hello" puts ; diff --git a/src/cmd/retroforth/examples/rosetta_code/terminal_control_ringing_the_terminal_bell.rx b/src/cmd/retroforth/examples/rosetta_code/terminal_control_ringing_the_terminal_bell.rx new file mode 100644 index 0000000..754f7a0 --- /dev/null +++ b/src/cmd/retroforth/examples/rosetta_code/terminal_control_ringing_the_terminal_bell.rx @@ -0,0 +1 @@ +7 putc diff --git a/src/cmd/retroforth/examples/rosetta_code/time_a_function.rx b/src/cmd/retroforth/examples/rosetta_code/time_a_function.rx new file mode 100644 index 0000000..257d7d7 --- /dev/null +++ b/src/cmd/retroforth/examples/rosetta_code/time_a_function.rx @@ -0,0 +1,9 @@ +Retro has a time function returning the current time in seconds. This +can be used to build a simple timing function: + +: .runtime ( a- ) time [ do time ] dip - "\n%d\n" puts ; + +: test 20000 [ putn space ] iterd ; +&test .runtime + +Finer measurements are not possible with the standard implementation. diff --git a/src/cmd/retroforth/examples/rosetta_code/tokenize_a_string.rx b/src/cmd/retroforth/examples/rosetta_code/tokenize_a_string.rx new file mode 100644 index 0000000..625d800 --- /dev/null +++ b/src/cmd/retroforth/examples/rosetta_code/tokenize_a_string.rx @@ -0,0 +1,22 @@ +{{ + : char ( -$ ) " " ; + : tokenize ( $-$$ ) + @char ^strings'splitAtChar withLength 1- over + 0 swap ! tempString ; + : action ( $- ) + keepString ^buffer'add ; +---reveal--- + : split ( $cb- ) + ^buffer'set !char + char ^strings'append + [ tokenize action dup 1 <> ] while drop + ^buffer'get drop ; +}} + +This will suffice to split a string into an array of substrings. It is used like this: +create strings 100 allot + +"Hello,How,Are,You,Today" ', strings split + +Since the buffer' vocabulary creates a zero-terminated buffer, we can display it using the each@ combinator and a simple quote: + +strings [ @ "%s." puts ] ^types'STRING each@ diff --git a/src/cmd/retroforth/examples/rosetta_code/unicode_variable_names.rx b/src/cmd/retroforth/examples/rosetta_code/unicode_variable_names.rx new file mode 100644 index 0000000..47e3f88 --- /dev/null +++ b/src/cmd/retroforth/examples/rosetta_code/unicode_variable_names.rx @@ -0,0 +1,8 @@ +This has been tested on Retro 11.0 running under OS X. + + variable Δ + 1 !Δ + @Δ putn + 1 +Δ + @Δ putn + diff --git a/src/cmd/retroforth/examples/rosetta_code/user_input_text.rx b/src/cmd/retroforth/examples/rosetta_code/user_input_text.rx new file mode 100644 index 0000000..5ff64ac --- /dev/null +++ b/src/cmd/retroforth/examples/rosetta_code/user_input_text.rx @@ -0,0 +1,6 @@ +: example ( "- ) + remapping off + "Enter a string: " puts 10 accept tib tempString + [ "Enter 75000: " puts getNumber 75000 = cr ] until + "Your string was: '%s'\n" puts + remapping on ; diff --git a/src/cmd/retroforth/examples/util/cat.rx b/src/cmd/retroforth/examples/util/cat.rx new file mode 100644 index 0000000..ecfb5cd --- /dev/null +++ b/src/cmd/retroforth/examples/util/cat.rx @@ -0,0 +1,2 @@ +: cat ( $- ) + here swap ^files'slurp drop here cr puts ; diff --git a/src/cmd/retroforth/examples/util/extract-doc.rx b/src/cmd/retroforth/examples/util/extract-doc.rx new file mode 100644 index 0000000..09ec583 --- /dev/null +++ b/src/cmd/retroforth/examples/util/extract-doc.rx @@ -0,0 +1,20 @@ +2 elements in out + +: seekDocBlock ( - ) + [ @in ^files'readLine "doc{" compare not ] while ; + +: extractDocBlock ( - ) + [ @in ^files'readLine dup + "}doc" compare [ drop 0 ] [ @out ^files'writeLine -1 ] if ] while ; + +: changeSuffix ( $-$ ) + 3 [ ^strings'chop ] times ".rst" ^strings'append ; + +: extractDocs ( $- ) + dup ^files':R ^files'open !in changeSuffix ^files':W ^files'open !out + seekDocBlock + extractDocBlock + @in @out [ ^files'close drop ] bi@ ; + +: extractDocsFrom ( "- ) + getToken extractDocs ; diff --git a/src/cmd/retroforth/examples/util/grep.rx b/src/cmd/retroforth/examples/util/grep.rx new file mode 100644 index 0000000..2698535 --- /dev/null +++ b/src/cmd/retroforth/examples/util/grep.rx @@ -0,0 +1,29 @@ +( "filename" "substring" grep ) +( display all lines containing "substring" in "filename" ) + +{{ + 2 elements token content + + : clean ( $- ) + withLength + [ dup @ 10 13 within [ 999 swap &! sip ] ifTrue 1+ ] times drop ; + + : getLine ( $-$$ ) + 999 ^strings'splitAtChar ^strings'chop ; + + : process ( $- ) + dup @token ^strings'search [ puts cr ] &drop if ; + + : loadSourceData ( $- ) + here swap ^files'slurp here !content heap +! 32 , 0 , + @content clean ; + + : eachLine ( $- ) + [ getLine process dup 1 <> ] while drop ; + +---reveal--- + : grep ( $$- ) + cr keepString !token + heap [ loadSourceData @content eachLine ] preserve ; +}} + diff --git a/src/cmd/retroforth/examples/util/head.rx b/src/cmd/retroforth/examples/util/head.rx new file mode 100644 index 0000000..b4abce8 --- /dev/null +++ b/src/cmd/retroforth/examples/util/head.rx @@ -0,0 +1,8 @@ +{{ + variable fid +---reveal--- + : head ( $n- ) + swap ^files':R ^files'open !fid + cr [ @fid ^files'readLine puts cr ] times + @fid ^files'close drop ; +}} diff --git a/src/cmd/retroforth/examples/util/wc.rx b/src/cmd/retroforth/examples/util/wc.rx new file mode 100644 index 0000000..367e339 --- /dev/null +++ b/src/cmd/retroforth/examples/util/wc.rx @@ -0,0 +1,28 @@ +{{ + 3 elements content lines words + + : clean ( $- ) + withLength + [ dup @ 10 13 within [ 999 swap &! sip ] ifTrue 1+ ] times drop ; + + : remaining ( $-n ) + 32 ^strings'splitAtChar ^strings'chop drop ; + + : getLine ( $-$$ ) + 999 ^strings'splitAtChar ^strings'chop ; + + : countWords ( $- ) + [ words ++ remaining dup 1 <> ] while drop ; + + : loadSourceData ( $- ) + here swap ^files'slurp here !content heap +! 32 , 0 , + @content clean ; + + : countLines ( $- ) + [ getLine lines ++ countWords dup 1 <> ] while drop ; +---reveal--- + : wc ( $-nnn ) + lines words [ 0 swap ! ] bi@ + heap [ loadSourceData @content countLines ] preserve + @lines @words @content getLength [ 1- ] tri@ ; +}} diff --git a/src/cmd/retroforth/image/kernel.rx b/src/cmd/retroforth/image/kernel.rx new file mode 100644 index 0000000..5527d4f --- /dev/null +++ b/src/cmd/retroforth/image/kernel.rx @@ -0,0 +1,826 @@ +( Retro ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +( Copyright [c] 2008 - 2012, Charles Childers ) +( Copyright [c] 2009 - 2010, Luke Parrish ) +( Copyright [c] 2010, Marc Simpson ) +( Copyright [c] 2010, Jay Skeer ) +( ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) + + +( Kernel Begins ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +IMAGE-SIZE constant CORE +CORE 0000 + constant TIB +TIB 512 + constant HEAP + +( Initial Variables ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +mark variable last ( Pointer to the most recent dictionary header ) +HEAP variable: heap ( Starting address of the data/code heap ) +variable compiler ( Is the compiler on or off? ) +variable which ( Pointer to dictionary header of the most recently ) + ( looked up word ) +pad +label: copytag "Retro" $, +label: version "11.2" $, +label: build "2012.01.14" $, +label: okmsg "ok " $, + +( Primitives ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +t: dup ( n-nn ) dup, ; t: 1+ ( n-n ) 1+, ; +t: 1- ( n-n ) 1-, ; t: swap ( xy-yx ) swap, ; +t: drop ( n- ) drop, ; t: and ( xy-n ) and, ; +t: or ( xy-n ) or, ; t: xor ( xy-n ) xor, ; +t: @ ( a-n ) @, ; t: ! ( na- ) !, ; +t: + ( xy-n ) +, ; t: - ( xy-n ) -, ; +t: * ( xy-n ) *, ; t: /mod ( xy-qr ) /mod, ; +t: << ( xy-n ) <<, ; t: >> ( xy-n ) >>, ; +t: out ( np- ) out, ; t: in ( p-n ) in, ; +t: wait ( - ) 0 # 0 # out, wait, ; + +t: over ( xy-xyx ) push, dup, pop, swap, ; +t: not ( x-y ) -1 # xor, ; +t: on ( a- ) -1 # swap, !, ; +t: off ( a- ) 0 # swap, !, ; +t: / ( xy-q ) /mod, swap, drop, ; +t: mod ( xy-r ) /mod, drop, ; +t: negate ( x-y ) -1 # *, ; +t: do ( a- ) 1-, push, ; +t: @+ ( a-ac ) dup, 1+, swap, @, ; +t: !+ ( ca-a ) dup, 1+, push, !, pop, ; + +( Core Compiler ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +t: here ( -a ) heap # @, ; +t: , ( n- ) here !+ heap # !, ; +t: ;; ( - ) 9 # , ; +t: t-; ( - ) ;; ;; compiler # off ; +t: ($,) ( a-a ) repeat @+ 0; , again ; +t: $ ( a- ) ($,) drop, 0 # , ; +t: push ( n- ) 5 # , ; +t: pop ( -n ) 6 # , ; + +( Conditionals and Flow Control ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +t: (if) ( -a ) , here 0 # , ; +t: t-=if ( R: xy- C: -a ) 12 # jump: (if) +t: t->if ( R: xy- C: -a ) 11 # jump: (if) +t: t- ( a- ) (puts) drop, ; +t: puts ( a- ) ; + +( Console Input ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +variable break ( Holds the delimiter for 'accept' ) +-1 variable: remapping ( Allow extended whitespace? ) +-1 variable: eatLeading? ( Eat leading delimiters? ) +-1 variable: tabAsWhitespace + +t: tib ( -a ) TIB # ; + +t: remapKeys ( c-c ) ; +t: ws ( c-c ) + dup, 127 # =if drop, 8 # then + dup, 13 # =if drop, 10 # then + remapping # @, 0; drop, + dup, 10 # =if drop, 32 # then + tabAsWhitespace # @, 0 # !if dup, 9 # =if drop, 32 # then then ; + +t: ( -c ) 1 # 1 # out, wait 1 # in, ; +t: getc ( -c ) repeat remapKeys dup 0 # !if ws ; then drop, again ; +t: putc? ( n-n ) dup, 8 # =if drop, break # @, ; then dup, putc ; +t: eat ( a-a ) + eatLeading? # @, 0; drop + repeat getc putc? dup, break # @, !if swap, !+ ; then drop, again ; +t: guard? ( n-n ) dup, 1+, tib class ( a-a ) 1+, ; +t: d->xt ( a-a ) 1+, 1+, ; +t: d->name ( a-a ) 1+, 1+, 1+, ; +t: header ( $- ) push, here ( Entry Start ) + last # @, , ( Link to previous ) + last # !, ( Set as newest ) + ' .data # , ( Class = .data ) + here 0 # , ( XT ) + pop, $ ( Name ) + here swap, !, ; ( Patch XT to HERE ) +t: create ( "- ) 32 # accept tib header ; +t: [[ ( - ) compiler # off ; +t: ]] ( - ) compiler # on ; +t: : ( "- ) create ' .word # last # @, d->class !, ]] 0 # , 0 # , ; +t: t-( ( "- ) ') # accept ; + +( Quotes ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +t: [ ( -naa ) compiler # @, 8 # , here 0 # , here compiler # on ; +t: ] ( naa-q ) push, ;; here swap, !, compiler # !, pop, .data ; + +( Combinators ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +t: empty ( - ) ; +t: if ( fqq- ) + push, swap, pop, swap, 0 # !if drop, do ; then swap, drop, do ; +t: ifTrue ( fq- ) ' empty # if ; +t: ifFalse ( fq- ) ' empty # swap, if ; +t: dip ( nq-n ) swap, push, do pop, ; +t: sip ( nq-n ) over ' do # dip ; + +( Conditionals ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +t: = ( xy-f ) =if -1 # ; then 0 # ; +t: <> ( xy-f ) !if -1 # ; then 0 # ; +t: >= ( xy-f ) >if -1 # ; then 0 # ; +t: <= ( xy-f ) if 0 # ; then -1 # ; +t: > ( xy-f ) if 7 # -, then then ; +t: isNegative? ( a-a ) + dup, @, '- # =if -1 # negate? # !, 1+, ; then 1 # negate? # !, ; +t: (convert) + repeat + dup, @, 0; toDigit #value # @, base # @, *, +, #value # !, 1+, + again ; +t: toNumber ( $-n ) + isNegative? 0 # #value # !, (convert) drop, #value # @, negate? # @, *, ; +t: (isnumber) + repeat dup, @, 0; digit? flag # @, and, flag # !, 1+, again ; +t: isNumber? ( $-f ) isNegative? flag # on (isnumber) drop, flag # @, ; + +( Startup ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +6 elements memory fb fw fh cw ch + +t: boot ( - ) + copytag # puts 32 # putc version # puts + 32 # putc 40 # putc build # puts 41 # putc cr ; +t: query ( n-n ) 5 # out, wait 5 # in, ; +t: run-on-boot ( - ) + -1 # query memory # !, ( Memory Size ) + -2 # query fb # !, ( Canvas Present? ) + -3 # query fw # !, ( Canvas Width ) + -4 # query fh # !, ( Canvas Height ) + -11 # query cw # !, ( Console Width ) + -12 # query ch # !, ( Console Height ) + boot ; + +( Dictionary Search ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +2 elements name found +t: prepare ( a-a ) found # off name # !, last # @, ; +t: done ( -af ) which # @, found # @, ; +t: match? ( $-$f ) dup, d->name name # @, compare ; +t: ( $- ) + repeat match? 0 # !if which # !, found # on ; then @ 0; again ; +t: find ( $-af ) prepare done ; +t: t-' ( "-a ) 32 # accept tib find 0 # !if d->xt @, ; then drop, 0 # ; + +( Word Prefixes and "Not Found" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +label: ___ "___" $, +t: get ( $-$ ) dup, @, ___ # 2 # +, !, 1+, ; +t: xt:class ( d-aa ) dup, d->xt @, swap, d->class @, ; +t: try ( - ) + tib get find 0 # + !if d->xt @, ___ # find + 0 # !if xt:class withClass 0 # ; then drop, + then drop, -1 # ; +t: ( -f ) tib getLength 2 # >if try then ; +t: notFound ( - ) 0; drop cr tib puts 32 # putc '? # putc cr ; + +( Listener ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +t: ok ( - ) compiler # @, not 0; drop, cr okmsg # puts ; +t: word ( d- ) xt:class jump: withClass +t: build# ( - ) tib toNumber ' .data # withClass ; +t: number ( - ) tib isNumber? 0 # !if build# ; then notFound ; +t: process ( af- ) 0 # !if word ; then drop number ; +t: listen ( - ) repeat ok 32 # accept tib find process again ; + +( Initial Dictionary ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +' 1+ prim: 1+ ' 1- prim: 1- +' swap prim: swap ' drop prim: drop +' and prim: and ' or prim: or +' xor prim: xor ' @ prim: @ +' ! prim: ! ' + prim: + +' - prim: - ' * prim: * +' /mod prim: /mod ' << prim: << +' >> prim: >> ' tib word: tib +' dup prim: dup ' in prim: in +' out prim: out ' accept word: accept +' here word: here ' , word: , +' create word: create ' ]] word: ]] +' : word: : ' header word: header +' cr word: cr ' putc word: putc +' remapKeys word: remapKeys ' word: +' over word: over +' not word: not ' on word: on +' off word: off ' / word: / +' mod word: mod ' negate word: negate +' do word: do ' nums word: numbers +' wait word: wait ' t-' word: ' +' @+ word: @+ ' !+ word: !+ +' keepString word: keepString ' getLength word: getLength +' withLength word: withLength ' withClass word: withClass +' .word word: .word ' .macro word: .macro +' .data word: .data ' .primitive word: .primitive +' d->class word: d->class ' d->xt word: d->xt +' d->name word: d->name ' boot word: boot +' toNumber word: toNumber ' isNumber? word: isNumber? +' ok word: ok ' listen word: listen +' getc word: getc ' find word: find +' notFound word: notFound ' word: +' puts word: puts ' compare word: compare +' redraw word: redraw ' if word: if +' ifTrue word: ifTrue ' ifFalse word: ifFalse +' dip word: dip ' sip word: sip +' = word: = ' <> word: <> +' < word: < ' > word: > +' <= word: <= ' >= word: >= + +' t-; macro: ; ' ;; macro: ;; +' t-=if macro: =if ' t->if macro: >if +' t-class ! + +( Dictionary ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +{{ + create a 0 , create b 0 , create c 0 , create xt 0 , + : skim ( a-a ) + last repeat @ over over d->xt @ =if nip ;; then 0; again ; + : getHeaders ( $- ) + xt ! 0 a ! 0 b ! 0 c ! + last repeat @ 0; dup d->xt @ xt @ =if dup b ! @ a ! ;; then dup c ! again ; + : ( a- ) getHeaders b @ 0; drop a @ c @ ! ; +---reveal--- + : d' ( "-a ) ' drop which @ ; + : xt->d ( a-d || a-0 ) dup skim over over = [ - ] [ nip ] if ; + : :hide ( a- ) + dup xt->d last @ = [ drop last @ @ last ! ] [ ] if ; + : hide ( "- ) ' 0; :hide ; +}} +hide list +: reclass ( a- ) last @ d->class ! ; +: reclass: ( a"- ) d' d->class ! ; + +( Initial Prefixes ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +{{ + : xt:class ( a-aa ) dup xt->d 0; d->class @ withClass ; +---reveal--- + : __& ( a-a ) .data ; &.macro reclass + : __@ ( a-n ) xt:class &@ xt:class ; &.macro reclass + : __! ( na- ) xt:class &! xt:class ; &.macro reclass + : __+ ( na- ) xt:class &+! .word ; &.macro reclass + : __- ( na- ) xt:class &-! .word ; &.macro reclass + : __2 ( a- ) &xt:class sip xt:class ; &.macro reclass +}} + +( Classes ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +: .compiler ( a- ) @compiler &do &drop if ; +: immediate ( - ) &.macro reclass ; +: compile-only ( "- ) &.compiler reclass ; + +( Remap some classes for efficiency and safety ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +here +{{ + : c: ( "- ) &.compiler reclass: ; + c: pop c: push c: 0; c: ;; c: ; c: repeat c: again +}} +!heap + +( Compiler Macros ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +: ` ( "- ) + ' dup 0 !if .data @which @d->class , ;; then + drop tib isNumber? -1 + =if tib toNumber .data &.data , ;; then + notFound ; compile-only +: jump: ( "- ) ' 0; 8 , , ; compile-only + +( Additional Combinators ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +: [] ( - ) ` [ ` ] ; immediate +: while ( q- ) [ repeat dup dip swap 0; drop again ] do drop ; +: curry ( nq-q ) [ [ ` [ ] dip .data ] dip , ` ] ; +: take ( qq-q ) swap [ [ ` [ ] dip , ] dip .data ` ] ; +: bi ( xqq- ) &sip dip do ; +: bi* ( xyqq- ) &dip dip do ; +: bi@ ( xyq- ) dup bi* ; +: tri ( xqqq- ) [ &sip dip sip ] dip do ; +: tri* ( xyzqqq- ) [ [ swap &dip dip ] 2dip ] dip do ; +: tri@ ( xyzq- ) 2dup tri* ; +: cons ( ab-q ) 2push ` [ 2pop &.data bi@ ` ] ; +: preserve ( aq- ) swap &@ sip [ &do dip ] dip ! ; +: when ( nqq-n ) + [ over swap do ] dip swap + [ do -1 ] [ drop 0 ] if 0; pop 2drop ; +: whend ( nqq-? ) + [ over swap do ] dip swap + [ nip do -1 ] [ drop 0 ] if 0; pop 2drop ; + +{{ + : for ( R: n- C: -a ) here ` push ; compile-only + : next ( R: - C: a- ) ` pop 7 , , ; compile-only + : i 2pop pop 2over 2push swap - swap push ; + : tors ( -n ) ` pop ` dup ` push ; compile-only +---reveal--- + : times ( nq- ) + over 1 >= [ swap for dup dip next drop ] [ 2drop ] if ; + : iterd ( nq- ) + over 1 >= [ swap for tors swap dup dip next drop ] [ 2drop ] if ; + : iter ( nq- ) + over 1 >= [ swap dup push for i swap dup dip next pop 2drop ] [ 2drop ] if ; +}} + +{{ + : ( qa- ) [ dup [ swap dup &do dip ] dip 1+ ] times 2drop ; + : array ( aq- ) swap @+ dup 1 > [ ] [ 2drop ] if ; + : buffer ( anq- ) 2rot ; + : list ( lq- ) [ &@ dip 2over [ [ do ] dip ] dip over @ ] while 2drop ; +---reveal--- + : ( ...t- ) drop ; + : each@ ( ...t- ) + [ 0 ( ARRAY ) = ] [ array ] whend + [ 1 ( BUFFER ) = ] [ buffer ] whend + [ 2 ( STRING ) = ] [ &withLength dip buffer ] whend + [ 3 ( LIST ) = ] [ list ] whend + ; +}} + +( Memory Blocks ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +: copy ( aan- ) [ &@+ dip !+ ] times 2drop ; +: fill ( ann- ) swap !here [ @here swap !+ ] times drop ; + +( Conditionals ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +: ahead ( -a ) 8 , here 0 , ; +: if; ( f- ) ` not ` 0; ` drop ; compile-only +: within ( xlu-f ) &over dip <= &>= dip and ; + +( Data Structures ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +: variable: ( n"- ) create , ; +: variable ( "- ) 0 variable: ; +: constant ( n"- ) create @last !d->xt ; +: string ( $"- ) keepString constant ; +: allot ( n- ) dup 0 < [ +heap ] [ repeat 0; 1- 0 , again ] if ; +{{ + : list ( n-a ) here swap allot ; + : element ( a-a ) create dup @last !d->xt 1+ ; +---reveal--- + : elements ( n"- ) dup list swap &element times drop ; +}} + +( Numbers and Math ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +: decimal ( - ) 10 !base ; +: hex ( - ) 16 !base ; +: octal ( - ) 8 !base ; +: binary ( - ) 2 !base ; + +( Output ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +{{ + create buf 32 allot + 2 elements digits pos + : split ( n-... ) + repeat @base /mod swap numbers + @ swap digits ++ 0; again ; + : build ( ...- ) + buf @pos [ @pos swap !+ ] ifTrue + @digits [ !+ ] times 0 swap ! ; + : negate? ( n-n ) dup 0 >= if; negate 45 !pos ; +---reveal--- + : toString ( n-$ ) 0 [ !pos ] [ !digits ] bi negate? split build buf ; +}} +: clear ( - ) -1 putc ; +: space ( - ) 32 putc ; +: putn ( n- ) toString puts ; + +( Parsing prefixes ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +: .parse ( a- ) do ; +: parsing ( - ) &.parse reclass ; +{{ + : number ( a- ) base [ do toNumber .data ] preserve ; +---reveal--- + : __$ ( $-n ) &hex number ; parsing + : __# ( $-n ) &decimal number ; parsing + : __% ( $-n ) &binary number ; parsing + : __' ( $-n ) @ .data ; parsing +}} + +( Chained Vocabularies ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +create dicts 64 allot +{{ + 2 elements active prior + create "|" 124 , 0 , + create "%%" 37 , 37 , 0 , + : seal ( - ) last repeat @ 0; @active over @ =if 0 swap ! ;; then again ; + : revert ( - ) @prior 0; !last 0 !prior ; + : safety ( - ) "%%" header immediate &revert @last !d->xt ; +---reveal--- + : %% ( - ) revert ; + : <%> ( a- ) @last !prior !last ; + : .chain ( a- ) @dicts &drop &<%> if ; + : chain: ( "- ) create 0 , &.chain reclass @last !active safety ; + : ;chain ( - ) seal @last @active [ !last ] [ !d->xt ] bi ; + : :with ( a- ) 0; @dicts 1+ dicts + ! dicts ++ ; + : with ( "- ) ' :with ; + : without ( - ) @dicts 0; 1- !dicts ; + : global ( - ) 0 !dicts ; + : findInChain ( $a-df ) :with find without ; + : with| ( "- ) + global + repeat + 32 accept tib "|" compare if; + tib find [ @d->xt :with ] &drop if + again ; +}} + +: rename: ( a"- ) + create dup xt->d swap :hide + [ @d->xt @last !d->xt ] [ @d->class @last !d->class ] bi ; + +( Extend 'find' and 'xt->d' to search chains before global ~~~~~~~~~~~~~~~~~~ ) +{{ + 5 elements flag dt name safety xt + : search ( - ) @dicts repeat 0; dup dicts + <%> @xt do 1- again ; + : (chains ( $- ) !name 0 [ !dt ] [ !flag ] bi @last !safety ; + : back) ( - ) @safety !last ; + : seek ( na-n ) @name default: find [ !dt flag on drop 1 ] &drop if ; + : lookup ( $-af ) + &seek !xt (chains search back) + @flag [ @dt @flag ] [ @name default: find ] if ; + &lookup is find + + : seek ( - ) + @name default: xt->d dup [ !dt flag on drop 1 ] &drop if ; + : lookup ( a-d ) + &seek !xt (chains search back) + @flag [ @dt ] [ @name default: xt->d ] if ; + &lookup is xt->d +}} + +( Extend Prefix Handler ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +{{ + 4 elements xt class name flag + create ___ 95 , 95 , 95 , 0 , + + ( Split Token into Prefix and Name ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) + : action ( - ) @xt @class withClass ; + : (split ( -a ) @+ ___ tuck 1+ 1+ ! swap !name ; + : prefix) ( $-f ) + find [ [ @d->class !class ] [ @d->xt !xt ] bi -1 ] [ 0 ] if ; + + ( Prefix Handling ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) + : handle ( - ) + @class &.parse = + [ flag off @name action ] + [ @name find [ @d->xt action flag off ] &drop if ] + if ; + + ( Main Wrapper ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) + : try ( - ) + flag on tib (split prefix) [ handle ] &drop if @flag ; + &try is +}} + +( Core Strings ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +{{ + : buffers ( -a ) 2048 here + ; + variable next +---reveal--- + : tempString ( $-$ ) + withLength 1+ + @next 12 = [ 0 !next ] ifTrue + @next 512 * buffers + [ swap copy ] sip + next ++ ; +}} + +{{ + variable end + : pad ( -a ) 1024 here + ; + : keep ( - ) @compiler &keepString &tempString if .data ; + : >pad ( $-$ ) pad over getLength 1+ copy pad keep ; + : chop ( $-$ ) end -- 0 @end ! ; + : >$ ( n- ) dup 8 = [ chop drop ] [ @end !+ !end ] if ; + : end? ( $-$ ) @end @1- '" = [ chop >pad -1 ] [ 0 ] if ; + : noEat ( q- ) eatLeading? off do eatLeading? on ; + : withPad ( q- ) 32 pad 1- ! &pad &tib :is noEat &tib :devector ; + : get ( -c ) getc dup putc ; +---reveal--- + : __" ( "-a ) + dup withLength + !end + end? [ 32 >$ [ end? [ 0 ] [ get >$ -1 ] if ] while ] ifFalse ; parsing + : " ( "-$ ) [ '" accept pad 1- keep ] withPad ; immediate +}} + +( Formatted String Display ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +-1 variable: formatted +{{ + : withBase ( n$q-$ ) [ swap ] dip base [ do ] preserve ; + : char ( $-$ ) + @+ [ 'n = ] [ cr ] whend + [ '' = ] [ '" putc ] whend + [ '[ = ] [ 27 putc putc ] when + putc ; + : obj ( $-$ ) + @+ [ 'd = ] [ [ decimal putn ] withBase ] whend + [ 'o = ] [ [ octal putn ] withBase ] whend + [ 'x = ] [ [ hex putn ] withBase ] whend + [ 'c = ] [ swap putc ] whend + [ 's = ] [ formatted off &puts dip formatted on ] whend + putc ; + : complex ( $-n ) + repeat + @+ 0; + dup '\ = [ drop char 0 ] ifTrue + dup '% = [ drop obj 0 ] ifTrue + putc + again ; + : simple ( $- ) [ @ putc ] 2 ( STRING ) each@ ; + : defer ( q- ) update off do update on redraw ; + [ [ @formatted [ complex drop ] &simple if ] defer ] is +}} + +( Debugging ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +: depth ( -n ) -5 5 out wait 5 in ; +: reset ( ...- ) depth repeat 0; 1- nip again ; +: .s ( - ) + depth [ "\n<%d> " puts ] sip 0; + heap [ [ here 1+ ;; [[ 128 allot ]] ] do !heap + dup [ swap , ] times + [ here 1- @ dup putn space -1 allot ] times ] preserve ; + +{{ + : list ( a- ) [ d->name puts space ] 3 ( LIST ) each@ ; + : others ( - ) @dicts repeat 0; cr dup dicts + list 1- again ; +---reveal--- + : words ( - ) cr formatted dup [ off others cr last list ] preserve ; +}} + +( Misc. Words ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +: save ( - ) 1 4 out wait ; +: bye ( - ) cr -9 5 out wait ; +: getToken ( "-$ ) 32 accept tib tempString ; +: getNumber ( "-n ) getToken toNumber ; +: :include ( $- ) 2 4 out wait ; +: include ( "- ) getToken :include ; +: time ( -n ) -8 5 out wait 5 in ; +: delay ( n- ) time + [ dup time > ] while drop ; +: getEnv ( a$- ) -10 5 out wait ; +: later ( - ) 2pop swap 2push ; +: doc{ ( "- ) repeat getToken "}doc" compare if; again ; +: variables| ( "- ) + repeat getToken "|" compare if; tib header 0 , again ; + +( Math Operations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +: pow ( bp-n ) 1 swap [ over * ] times nip ; +: abs ( n-n ) dup 0 < &negate ifTrue ; +: min ( ab-c ) 2over < &drop &nip if ; +: max ( ab-c ) 2over < &nip &drop if ; +{{ + variables| w z | + : seeds? ( - ) @w @z and ; + : seed ( - ) time [ 62903 and !w ] [ 78578 and !z ] bi ; + : ?seed ( - ) repeat seeds? 0 <> if; seed again ; + : (random) ( -x ) + 36969 z @ 65535 and * @z 16 >> + !z + 18000 w @ 65535 and * @w 16 >> + !w + @z 16 << @w + ; +---reveal--- + : random ( -x ) ?seed (random) abs ; +}} + +( Generic Buffer ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +global +chain: buffer' +{{ + variables| buffer ptr | + : terminate ( - ) 0 @ptr ! ; +---reveal--- + : start ( -a ) @buffer ; + : end ( -a ) @ptr ; + : add ( c- ) end ! ptr ++ terminate ; + : get ( -c ) ptr -- end @ terminate ; + : empty ( - ) start !ptr terminate ; + : size ( -n ) end start - ; + : set ( a- ) !buffer empty ; +}} +;chain + +( Text Strings ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +with buffer' +chain: strings' +{{ + variables| len needle haystack flag right left src | + : buffer ( -a ) here 8192 + ; + : trim ( $-$ ) + dup withLength + 1- dup @ 32 =if 0 swap ! dup 1- -- trim ;; then drop ; + : place ( $$n- ) [ copy 0 ] sip here + ! ; + : prep ( $$- ) swap !haystack [ getLength !len ] [ !needle ] bi 0 !flag ; + : move ( - ) @haystack here @len place haystack ++ ; + : cmp ( - ) + @flag 0 <> if; @needle here compare [ @haystack 1- !flag ] ifTrue ; +---reveal--- + : search ( $$-f ) + flag off prep @haystack getLength [ move cmp ] times @flag ; + : findChar ( $c-a ) + !needle + repeat @+ + dup 0 =if 2drop 0 ;; then + @needle =if 1- ;; then + again ; + : chop ( $-$ ) tempString withLength over + 1- 0 swap ! ; + : getSubset ( $nn-$ ) + buffer 0 1024 fill + !right !left !src + @src @left + @right buffer swap copy buffer tempString ; + : trimLeft ( $-$ ) [ @+ [ 32 = ] [ 0 <> ] bi = ] while 1- ; + : trimRight ( $-$ ) + buffer [ 0 1024 fill ] [ over getLength copy ] [ trim ] tri tempString ; + : prepend ( $$-$ ) + buffer 0 1024 fill + withLength buffer swap dup © dip + &withLength dip buffer + swap copy buffer tempString ; + : append ( $$-$ ) swap prepend ; + : appendChar ( $c-$ ) swap tempString [ withLength + !+ 0 swap ! ] sip ; + : toLower ( $-$ ) + withLength 1+ + [ buffer + [ @+ dup 'A 'Z within [ 'a + 'A - ] ifTrue ] dip ! ] iter + drop buffer tempString ; + : toUpper ( $-$ ) + withLength 1+ + [ buffer + [ @+ dup 'a 'z within [ 'A + 'a - ] ifTrue ] dip ! ] iter + drop buffer tempString ; +}} + : reverse ( $-$ ) + dup tempString set + [ getLength ] [ withLength + 1- ] bi swap + [ dup @ add 1- ] times drop + start tempString ; + : split ( $n-$$ ) + 2over 0 swap getSubset [ + ] dip ; + : splitAtChar ( $c-$$ ) + 2over over swap findChar over - 1+ 0 swap getSubset [ findChar 1+ ] dip ; + : splitAtChar: ( $"-$$ ) + 32 accept tib @ .data ` splitAtChar ; immediate +;chain +without + +( Access Words Within Chains Directly ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +with strings' +: __^ ( "- ) + splitAtChar: ' find + [ @d->xt findInChain [ [ @d->xt ] [ @d->class ] bi do ] &drop if ] + &drop if ; parsing + +: needs ( "- ) + getToken dup find nip + &drop [ "library/" prepend chop ".rx" append :include ] if ; +without + +( Files ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +chain: files' +{{ + variables| fid fsize active | + : io ( n-f ) 4 out wait 4 in ; + : done ( nn- ) 2drop active off ; +---reveal--- + 0 constant :R + 1 constant :W + 2 constant :A + 3 constant :M + : open ( $m-h ) -1 io ; + : read ( h-f ) -2 io ; + : write ( ch-f ) -3 io ; + : close ( h-f ) -4 io ; + : pos ( h-n ) -5 io ; + : seek ( nh-f ) -6 io ; + : size ( h-n ) -7 io ; + : delete ( $-n ) -8 io ; + : slurp ( a$-n ) + :R open !fid + @fid size !fsize + @fsize [ @fid read swap !+ ] times 0 swap ! + @fid close drop @fsize ; + : spew ( an$-n ) + :W open !fid 0 !fsize + [ @+ @fid write drop fsize ++ ] times drop + @fid close drop @fsize ; + : readLine ( h-a ) + active on + tib [ over read dup 10 13 within + [ drop 0 swap ! drop active off ] [ swap !+ ] if @active ] while + tib tempString ; + : writeLine ( $h- ) + !fid active on + [ @+ dup 0 = &done [ @fid write drop ] if @active ] while + 10 @fid write drop ; +}} +;chain + +( types' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +chain: types' + 0 constant ARRAY ( -n ) + 1 constant BUFFER ( -n ) + 2 constant STRING ( -n ) + 3 constant LIST ( -n ) +;chain + +( cleanup ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +hide =if +hide !if +hide >if +hide class ! +: next ( - ) 6 , 7 , , ; ' .macro last @ d->class ! +: ['] ( "-a ) ' .data ; ' .macro last @ d->class ! +: elements ( n"- ) for create 0 , next ; + +( Assembler ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +8 elements target origin 'WORD 'MACRO 'DATA 'PRIM link chain +: m, ( n- ) target @ !+ target ! ; +: vm: ( n"- ) ['] : do .data ['] m, , ['] ; do ; + 0 vm: nop, 1 vm: lit, 2 vm: dup, + 3 vm: drop, 4 vm: swap, 5 vm: push, + 6 vm: pop, 7 vm: loop, 8 vm: jump, + 9 vm: ;, 10 vm: >jump, 11 vm: >, 25 vm: 0; 26 vm: 1+, + 27 vm: 1-, 28 vm: in, 29 vm: out, + 30 vm: wait, + +: t-here ( -n ) target @ origin @ - ; +: pad ( - ) 32 origin @ + target ! ; +: endKernel ( - ) ; +: main: ( - ) t-here origin @ 1+ ! ; +: label: ( "- ) t-here constant ; +: # ( n- ) lit, m, ; +: $, ( $- ) withLength for @+ m, next 0 m, drop ; + +( Metacompiler ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +: t: ( "- ) label: nop, nop, ['] m, last @ d->class ! ; + +{{ + : cond ( -a ) target @ 0 m, ; +---reveal--- + : =if ( -a ) !jump, cond ; + : jump, cond ; + : >if ( -a ) jump, 11 vm: >, 25 vm: 0; 26 vm: 1+, + 27 vm: 1-, 28 vm: in, 29 vm: out, + 30 vm: wait, + +: t-here ( -n ) @target @origin - ; +: pad ( - ) 32 @origin + !target ; +: endKernel ( - ) + t-here "\nKernel ends @ %d\n" puts + IMAGE-SIZE t-here - "%d cells free" puts + depth 1 >= [ "\nError in stack depth!: " puts .s ] ifTrue ; +: main: ( - ) t-here [ "\nMAIN @ %d" puts ] [ @origin 1+ ! ] bi ; +: label: ( "- ) t-here constant ; +: # ( n- ) lit, m, ; +: __# ( $- ) lit, toNumber m, ; parsing +: $, ( $- ) withLength [ @+ m, ] times 0 m, drop ; + +( Metacompiler ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +: t: ( "- ) label: nop, nop, &m, reclass ; + +{{ + : cond ( -a ) @target 0 m, ; +---reveal--- + : =if ( -a ) !jump, cond ; + : jump, cond ; + : >if ( -a ) @flag and !flag ] apply drop @flag not ; + + : stringIn? ( $a-f ) + -1 !flag + [ over compare not @flag and !flag ] apply drop @flag not ; + + : display ( a- ) + cr [ putn space ] apply ; +}} + +{{ + variables| a c n | + + : pair ( -aa ) + @n @a + dup 1+ ; + + : exchange ( aa- ) + 2over [ @ ] bi@ [ swap ! ] dip swap ! ; + + : contrast ( aa-f ) + [ @ ] bi@ > ; +---reveal--- + : sort:bubble ( a- ) + @+ !c !a + @c @c * + [ @c @a length ^math'even? + [ !n pair contrast [ pair exchange ] ifTrue ] iter ] times ; +}} +;chain + +doc{ +====== +Arrays +====== + + +-------- +Overview +-------- +This library provides a vocabulary for working with arrays. + + +-------------- +Implementation +-------------- +Arrays are stored as a linear sequence of values. In memory, they +are represented like: + +:: + + +---+--------------------+ + | 0 | number of elements | + +---+--------------------+ + | 1 | first value | + +---+--------------------+ + | 2 | second value | + +---+--------------------+ + | n | ... nth value ... | + +---+--------------------+ + + + +------- +Loading +------- +The following should suffice: + +:: + + needs array' + + +-------- +Examples +-------- + +:: + + ( Create an array with four elements ) + ^array'new{ 1 2 3 4 } constant a + + ( Add 10 to each element in an array ) + a [ 10 + ] ^array'map + + ( Display an array ) + a ^array'display + + ( Average the values in an array ) + ^array'new{ 1 2 3 4 5 } [ ^array'sum ] [ ^array'length ] bi / + + +--------- +Functions +--------- + ++-------------+-----------+------------------------------------------------+ +| Name | Stack | Usage | ++=============+===========+================================================+ +| new{ | "-a | Create a new array. Parses and adds numbers to | +| | | the array until "}" is reached. Returns a | +| | | pointer to the new array. | ++-------------+-----------+------------------------------------------------+ +| display | a- | Display all values in the array | ++-------------+-----------+------------------------------------------------+ +| in? | na- | Returns -1 if value (n) is a value in the array| ++-------------+-----------+------------------------------------------------+ +| stringIn? | $n- | Returns -1 if string ($) is a string in the | +| | | array | ++-------------+-----------+------------------------------------------------+ +| map | aq- | Apply quote to each item in the array. Updates | +| | | the array with the values returned by the quote| ++-------------+-----------+------------------------------------------------+ +| apply | aq- | Apply quote to each item in the array. Does not| +| | | modify the array contents. | ++-------------+-----------+------------------------------------------------+ +| sum | a-n | Add all values in an array | ++-------------+-----------+------------------------------------------------+ +| length | a-n | Get the number of items in an array | ++-------------+-----------+------------------------------------------------+ +| reverse | a- | Reverse the order of all elements in an array | ++-------------+-----------+------------------------------------------------+ +| append | aa-a | Append two arrays and return a new one | ++-------------+-----------+------------------------------------------------+ +| fromQuote | q-a | Generate an array from the values returned by a| +| | | quote | ++-------------+-----------+------------------------------------------------+ +| toQuote | a-q | Generate a quote from the values stored in an | +| | | array | ++-------------+-----------+------------------------------------------------+ +| sort:bubble | a- | Sort the items in an array using bubble sort | ++-------------+-----------+------------------------------------------------+ +}doc diff --git a/src/cmd/retroforth/library/assertion.rx b/src/cmd/retroforth/library/assertion.rx new file mode 100644 index 0000000..7df0623 --- /dev/null +++ b/src/cmd/retroforth/library/assertion.rx @@ -0,0 +1,178 @@ +( ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +( Assertion words for Retro 11 ) +( ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +( Copyright [c] 2011, Marc Simpson ) +( ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) + +chain: assertion' + +( ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) + +variable assertionFlag + +: assert ( f- ) @assertionFlag and !assertionFlag ; +: available ( n-f ) 1+ depth <= dup assert ; + +: assert= 2 available [ = assert ] ifTrue ; +: assertFalse 1 available [ 0 = assert ] ifTrue ; +: assertTrue 1 available [ 0 = not assert ] ifTrue ; +: assert> 2 available [ > assert ] ifTrue ; +: assert>= 2 available [ >= assert ] ifTrue ; +: assert< 2 available [ < assert ] ifTrue ; +: assert<= 2 available [ <= assert ] ifTrue ; + +( ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) + +: putAssertion ( f- ) + cr [ "Success" ] [ reset "Failure" ] if puts ; + +( ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) + +: preCond ( - ) ; +: postCond ( f- ) putAssertion ; + +{{ + : buildUp preCond assertionFlag on ; + : tearDown @assertionFlag assertionFlag on postCond ; +---reveal--- +: .assertion ( a- ) + ` buildUp .word ` tearDown ; +}} + +: assertion ( - ) &.assertion reclass ; +;chain + +doc{ +========== +Assertions +========== + + +-------- +Overview +-------- +This vocabulary provides support for testing code in a clean, +predicatable manner. + +Assertion predicates first check the stack for underflow; if +the stack is deep enough, their embedded predicates are applied; +if not, the assertion fails. + +The result of each assertion - including the underflow check - +is ANDed with the assertionFlag which can then be tested after +the containing thread has finished executing; this is handled by +the .assertion word class. + +For custom behaviour, revector preCond and/or postCond; by +default the pre-condition is an effective nop while the post- +condition simply prints 'Success' or 'Failure'. + +Given that each assertion predicate mutates assertionFlag, use +of the word class .assertion is encouraged; this resets the +assertionFlag before execution and push its final value to the +stack before calling postCond when the thread exits. + +NOTE: For simplicity of implementation, failure within a word of +class .assertion will not result in immediate termination; +instead, the false value of assertionFlag is left to propagate. + + +------- +Loading +------- +The following should suffice: + +:: + + needs assertion' + + +-------- +Examples +-------- +:: + + ( Our assertions ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) + + ( n.b, underflow is dealt with sanely ) + : a1 ( xyz- ) 30 assert= 20 assert= 10 assert= ; assertion + : a2 ( xy- ) assertTrue assertFalse ; assertion + : a3 ( x- ) 5 assert< ; assertion + + ( Simple demo ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) + : go + "\n----------" puts + 10 20 30 a1 + 30 20 10 a1 + "\n----------" puts + 10 a1 + "\n----------" puts + a1 + "\n----------" puts + -1 0 a2 + 0 -1 a2 + -1 -1 a2 + -1 a2 + "\n----------" puts + 3 a3 + 4 a3 + 5 a3 + a3 + "\n----------" puts + ; + + clear go + + ( Adjusting pre- and post- conditions ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) + : myPreCond .s ; + : myPostCond [ "Fatal error: assertion failure." puts bye ] ifFalse ; + &myPostCond is postCond + &myPreCond is preCond + + ( 'go' will now exit on first failure ) + go + + +--------- +Functions +--------- + ++---------------+-------+-----------------------------------------------------+ +| Name | Stack | Usage | ++===============+=======+=====================================================+ +| assertionFlag | -a | Variable. This holds a true (-1) or false (0) | +| | | value indicating whether the current set of | +| | | assertions have passed or failed. The **.assertion**| +| | | class will set this to true automatically. | ++---------------+-------+-----------------------------------------------------+ +| assert | f- | Updates the **assertionFlag** using bitwise AND | ++---------------+-------+-----------------------------------------------------+ +| available | n-f | Checks to see if there are at least *n* items on the| +| | | stack. Returns true if there are, or false otherwise| ++---------------+-------+-----------------------------------------------------+ +| assert= | nn- | Check to see if two values are equal | ++---------------+-------+-----------------------------------------------------+ +| assertFalse | f- | Check to see if flag is false (0) | ++---------------+-------+-----------------------------------------------------+ +| assertTrue | f- | Check to see if flag is true (non-zero) | ++---------------+-------+-----------------------------------------------------+ +| assert> | nn- | Check to see if n1 is greather than n2 | ++---------------+-------+-----------------------------------------------------+ +| assert>= | nn- | Check to see if n1 is greater than or equal to n2 | ++---------------+-------+-----------------------------------------------------+ +| assert< | nn- | Check to see if n1 is less than n2 | ++---------------+-------+-----------------------------------------------------+ +| assert<= | nn- | Check to see if n1 is less than or equal to n2 | ++---------------+-------+-----------------------------------------------------+ +| putAssertion | f- | Display 'Success' or 'Failure' based on flag | ++---------------+-------+-----------------------------------------------------+ +| preCond | ``-`` | Hook, does nothing bu default | ++---------------+-------+-----------------------------------------------------+ +| postCond | f- | Hook, displays 'Success' or 'Failure' by default | ++---------------+-------+-----------------------------------------------------+ +| .assertion | a- | Class handler for assertions | ++---------------+-------+-----------------------------------------------------+ +| assertion | ``-`` | Change the class of a function to **.asssertion** | ++---------------+-------+-----------------------------------------------------+ + +}doc diff --git a/src/cmd/retroforth/library/bad.rx b/src/cmd/retroforth/library/bad.rx new file mode 100644 index 0000000..cebc66d --- /dev/null +++ b/src/cmd/retroforth/library/bad.rx @@ -0,0 +1,128 @@ +( Byte Addressing for Retro ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +( Copyright [c] 2010, Marc Simpson ) +( Copyright [c] 2011, Charles Childers ) +( License: ISC ) +( ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) + +chain: bad' + variable pool +{{ + variable byte + + : byte-mask ( xn-b ) + 255 swap 8 * dup [ << and ] dip >> ; + + : replace + [ 0 = ] [ [ [ [ drop @byte ] dip ] dip ] dip ] whend + [ 1 = ] [ [ [ drop @byte ] dip ] dip ] whend + [ 2 = ] [ [ drop @byte ] dip ] whend + [ 3 = ] [ drop @byte ] whend + drop ; +---reveal--- + : unpack ( c-bbbb ) + dup $FF and swap + dup 8 >> $FF and swap + dup 16 >> $FF and swap + 24 >> $FF and ; + + : pack ( bbbb-c ) + 24 << swap 16 << + swap 8 << + swap + ; + + : b@ ( a-b ) + 4 /mod @pool + swap + 4 /mod ( address byte-offset cell ) + rot + @ swap byte-mask ; + + : b! ( ba- ) + swap !byte + 4 /mod @pool + swap [ dup @ unpack ] dip + replace pack swap ! ; + + : b@+ ( a-ab ) dup 1+ swap b@ ; + + : b!+ ( ba-a ) dup 1+ [ b! ] dip ; + + : newPool ( n- ) + here !pool 4 /mod + allot ; +}} +;chain + +doc{ +=============== +Byte Addressing +=============== + + +-------- +Overview +-------- +The Ngaro virtual machine underlying Retro does not provide access to memory +in units other than a standard cell. This simplifies things in many ways, but +can be very wasteful of memory, especially when dealing with large amounts of +text. This library provides support for dealing with byte-level access to the +Ngaro memory. + + +----------- +Terminology +----------- +*byte*: A unit of memory consisting of eight bits. + +*cell*: A unit of memory consisting of thirty two bits. + + +------- +Loading +------- +:: + + needs bad' + + +------- +Example +------- +:: + + 1024 ^bad'newPool + 'e 0 ^bad'b! + 'f 1 ^bad'b! + 'g 2 ^bad'b! + 'h 3 ^bad'b! + ^bad'pool @ putn + 2 ^bad'@ putn + + +--------- +Functions +--------- ++----------+--------+------------------------------------------------+ +| Function | Stack | Used For | ++==========+========+================================================+ +| pool | -a | Variable. This holds a pointer to the current | +| | | byte addressable memory pool | ++----------+--------+------------------------------------------------+ +| unpack | c-bbbb | Given a byte-packed cell on the stack return | +| | | the bytes it contains | ++----------+--------+------------------------------------------------+ +| pack | bbbb-c | Pack four byes into a cell, return the cell on | +| | | the stack | ++----------+--------+------------------------------------------------+ +| b@ | a-b | Fetch a byte from the active byte addressable | +| | | memory pool | ++----------+--------+------------------------------------------------+ +| b! | ba- | Store a byte into the currently active byte | +| | | addressable memory pool | ++----------+--------+------------------------------------------------+ +| b@+ | a-ab | Fetch a byte from the active byte addressable | +| | | memory pool. Returns next byte address and the | +| | | byte fetched | ++----------+--------+------------------------------------------------+ +| b!+ | ba-a | Store a byte into the currently active byte | +| | | addressable memory pool. Returns next byte | +| | | address | ++----------+--------+------------------------------------------------+ +| newPool | n- | Allocate a new pool of *n* characters and set | +| | | **pool** to point to it | ++----------+--------+------------------------------------------------+ +}doc diff --git a/src/cmd/retroforth/library/bstrings.rx b/src/cmd/retroforth/library/bstrings.rx new file mode 100644 index 0000000..0cb7a02 --- /dev/null +++ b/src/cmd/retroforth/library/bstrings.rx @@ -0,0 +1,130 @@ +( Byte Strings for Retro ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +( Copyright [c] 2011, Charles Childers ) +( License: ISC ) +( ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) + +needs bad' + +chain: bstrings' + : pack ( $-a ) + withLength 1+ + [ ^bad'newPool ] [ [ [ @+ ] dip ^bad'b! ] iter ] bi + drop ^bad'pool @ ; + + : getLength ( a-n ) + ^bad'pool ! 0 [ ^bad'b@+ ] while 1- ; + + : unpack ( a-$ ) + getLength + "" tempString tuck swap 1+ [ ^bad'b@ swap !+ ] iter drop ; + + : withLength ( a-an ) + dup getLength ; + + : puts ( a- ) + getLength [ ^bad'b@ putc ] iter ; + + : toLower ( a-a ) + unpack ^strings'toLower pack ; + + : toUpper ( a-a ) + unpack ^strings'toUpper pack ; +;chain + + +doc{ +=================== +Byte Packed Strings +=================== + + +-------- +Overview +-------- +This library builds on the *byte addressing* vocabulary (**bad'**) to provide +support for creating and working with byte-packed strings. + +Generally it's better to use the cell-based strings. They are larger in memory, +but much faster to work with. If space is critical though, this library can be +used to significantly reduce the memory consumed, at the cost of performance. + +As an example of how this works, consider a simple string: "This is a test." + +:: + + "This is a test." + +Retro will create a string in memory that looks like: + +:: + + 0000 T + 0001 h + 0002 i + 0003 s + 0004 + 0005 i + 0006 s + 0007 + 0008 a + 0009 + 0010 t + 0011 e + 0012 s + 0013 t + 0014 . + 0015 + +So 16 cells used. If we byte pack this, it reduces considerably: + +:: + + 0000 This + 0001 is + 0002 a te + 0003 st + +Down to four cells. It's a straightforward 4:1 reduction. + + +----------- +Terminology +----------- +*byte*: A unit of memory consisting of eight bits. + +*cell*: A unit of memory consisting of thirty two bits. + + +------- +Loading +------- +:: + + needs bstrings' + + +--------- +Functions +--------- ++------------+--------+------------------------------------------------+ +| Function | Stack | Used For | ++============+========+================================================+ +| pack | $-a | Convert a standard string into a byte packed | +| | | string | ++------------+--------+------------------------------------------------+ +| getLength | a-n | Return the length of a byte packed string (in | +| | | characters) | ++------------+--------+------------------------------------------------+ +| unpack | a-$ | Convert a byte packed string into a standard | +| | | string | ++------------+--------+------------------------------------------------+ +| withLength | a-an | Return the length (in characters) and address | +| | | of a byte-packed string | ++------------+--------+------------------------------------------------+ +| puts | a- | Display a bye packed string | ++------------+--------+------------------------------------------------+ +| toLower | a-a | Convert a byte packed string to lowercase | ++------------+--------+------------------------------------------------+ +| toUpper | a-a | Convert a byte packed string to uppercase | ++------------+--------+------------------------------------------------+ +}doc diff --git a/src/cmd/retroforth/library/calendar.rx b/src/cmd/retroforth/library/calendar.rx new file mode 100644 index 0000000..ead8240 --- /dev/null +++ b/src/cmd/retroforth/library/calendar.rx @@ -0,0 +1,114 @@ +( Calculations Involving Time and Date ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +needs math' + +chain: calendar' + +( Useful Constants; Avoid Magic Numbers ) +10080 constant MINUTES/WEEK + 1440 constant MINUTES/DAY + 60 constant MINUTES/HOUR + + 24 constant HOURS/DAY + + 7 constant DAYS/WEEK + 365 constant DAYS/YEAR + + 52 constant WEEKS/YEAR + + 60 constant SECONDS/MINUTE + 3600 constant SECONDS/HOUR +86400 constant SECONDS/DAY + +{{ + create name 4 allot + create days + 31 , 28 , 31 , 30 , 31 , 30 , + 31 , 31 , 30 , 31 , 30 , 31 , +---reveal--- + : dayToName ( n-$ ) + 3 * "SunMonTueWedThuFriSat" + name 3 copy name ; + : daysPerMonth ( m-n ) + days + @ ; + : secondsPerMonth ( m-n ) + daysPerMonth SECONDS/DAY * ; + : isLeapYear? ( y-f ) + dup 400 mod 0 = [ drop -1 0 ] [ 1 ] if 0; drop + dup 100 mod 0 = [ drop 0 0 ] [ 1 ] if 0; drop + 4 mod 0 = ; + : secondsPerYear ( y-n ) + isLeapYear? [ 31622400 ] [ 31536000 ] if ; +}} + + +: toJulian ( dmy-j ) + [ 3 - dup 0 < dup ] dip + + [ 12 and + 306 * 5 + 10 / + ] dip + dup [ 1461 4 ^math'*/ + dup 578053 > ] dip + swap [ [ 3 + ] dip [ 100 / - ] sip 400 / + ] ifTrue 1721116 + ; + +: toDayOfWeek ( dmy-n ) + toJulian 7 mod 1+ dup 7 = [ drop 0 ] ifTrue ; + +;chain + +doc{ +======================== +Time & Date Calculations +======================== + + +-------- +Overview +-------- +This vocabulary provides support for doing calculations involving time +and dates. + + +--------- +Functions +--------- ++-----------------+-------+--------------------------------------+ +| Function | Stack | Used For | ++=================+=======+======================================+ +| MINUTES/WEEK | -n | Number of minutes in a week | ++-----------------+-------+--------------------------------------+ +| MINUTES/DAY | -n | Number of minutes in a day | ++-----------------+-------+--------------------------------------+ +| MINUTES/HOUR | -n | Number of minutes in an hour | ++-----------------+-------+--------------------------------------+ +| HOURS/DAY | -n | Number of hours in a day | ++-----------------+-------+--------------------------------------+ +| DAYS/WEEK | -n | Number of days in a week | ++-----------------+-------+--------------------------------------+ +| DAYS/YEAR | -n | Number of days in a typical year | ++-----------------+-------+--------------------------------------+ +| WEEKS/YEAR | -n | Number of weeks in a year | ++-----------------+-------+--------------------------------------+ +| SECONDS/MINUTE | -n | Number of seconds in a minute | ++-----------------+-------+--------------------------------------+ +| SECONDS/HOUR | -n | Number of seconds in an hour | ++-----------------+-------+--------------------------------------+ +| SECONDS/DAY | -n | Number of seconds in a day | ++-----------------+-------+--------------------------------------+ +| dayToName | n-$ | Convert the number of a day to a | +| | | three letter abbreviation | ++-----------------+-------+--------------------------------------+ +| daysPerMonth | m-n | Return the number of days in a given | +| | | month | ++-----------------+-------+--------------------------------------+ +| secondsPerMonth | m-n | Return the number of seconds in a | +| | | given month | ++-----------------+-------+--------------------------------------+ +| isLeapYear? | y-f | Return true (-1) if the year is a | +| | | leap year or false (0) otherwise | ++-----------------+-------+--------------------------------------+ +| secondsPerYear | y-n | Return the number of seconds in a | +| | | given year | ++-----------------+-------+--------------------------------------+ +| toJulian | dmy-j | Convert a date into a Julian day | ++-----------------+-------+--------------------------------------+ +| toDayOfWeek | dmy-n | Convert a date to the numeric day of | +| | | the week | ++-----------------+-------+--------------------------------------+ + +}doc diff --git a/src/cmd/retroforth/library/canvas.rx b/src/cmd/retroforth/library/canvas.rx new file mode 100644 index 0000000..6312c24 --- /dev/null +++ b/src/cmd/retroforth/library/canvas.rx @@ -0,0 +1,137 @@ +( canvas' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) + +chain: canvas' + ( Mouse ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) + : mouse ( -xy ) 1 7 out wait ; + : click? ( -f ) 2 7 out wait ; + + ( Drawing ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +{{ + variable solid? + : io ( n- ) 6 out wait ; +---reveal--- + : solid ( - ) solid? on ; + : pixel ( xy- ) 2 io ; + : box ( xyhw- ) @solid? [ 4 ] [ 3 ] if io solid? off ; + : vline ( xyh- ) 5 io ; + : hline ( xyw- ) 6 io ; + : circle ( xyw- ) @solid? [ 8 ] [ 7 ] if io solid? off ; + ( Colors ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) + : setColor ( c- ) 1 io ; + : color: ( n"-n ) ` : dup .data ` setColor ` ; 1+ ; + 0 color: black + color: blue + color: green + color: cyan + color: red + color: purple + color: brown + color: gray + color: darkGray + color: brightBlue + color: brightGreen + color: brightCyan + color: brightRed + color: magenta + color: yellow + color: white + drop hide color: + : dimensions ( -hw ) @fh @fw ; +}} +;chain + +doc{ +:Title: canvas' +:Author: Charles Childers +:Version: 1.0 + +canvas' +======= +This library provides support for the canvas device provided by the +JavaScript implementation of Ngaro. + + +Loading +======= +Since the JavaScript implementation has no file I/O, build an image with +this loaded manually. + +:: + + needs infix' + include vm/web/dumpImage.rx + + +Examples +======== + +:: + + 100 100 50 ^canvas'red ^canvas'solid ^canvas'circle + + +Functions +========= + ++---------------+-----------+-------------------------------------------------+ +| Name | Stack | Usage | ++===============+===========+=================================================+ +| mouse | -xy | Current mouse coordinates | ++---------------+-----------+-------------------------------------------------+ +| click? | -f | Is mouse button clicked? | ++---------------+-----------+-------------------------------------------------+ +| setColor | c- | Set color to *c*. Used by various other words | ++---------------+-----------+-------------------------------------------------+ +| pixel | xy- | Draw a pixel in the current color | ++---------------+-----------+-------------------------------------------------+ +| solid | ``-`` | Modifier; tells **box** and **circle** to draw | +| | | a filled in shape rather than an outline | ++---------------+-----------+-------------------------------------------------+ +| box | xyhw- | Draw a box | ++---------------+-----------+-------------------------------------------------+ +| vline | xyh- | Draw a vertical line | ++---------------+-----------+-------------------------------------------------+ +| hline | xyw- | Draw a horizontal line | ++---------------+-----------+-------------------------------------------------+ +| circle | xyw- | Draw a circle | ++---------------+-----------+-------------------------------------------------+ +| black | ``-`` | Set color | ++---------------+-----------+-------------------------------------------------+ +| blue | ``-`` | Set color | ++---------------+-----------+-------------------------------------------------+ +| green | ``-`` | Set color | ++---------------+-----------+-------------------------------------------------+ +| cyan | ``-`` | Set color | ++---------------+-----------+-------------------------------------------------+ +| red | ``-`` | Set color | ++---------------+-----------+-------------------------------------------------+ +| purple | ``-`` | Set color | ++---------------+-----------+-------------------------------------------------+ +| brown | ``-`` | Set color | ++---------------+-----------+-------------------------------------------------+ +| gray | ``-`` | Set color | ++---------------+-----------+-------------------------------------------------+ +| darkGray | ``-`` | Set color | ++---------------+-----------+-------------------------------------------------+ +| brightBlue | ``-`` | Set color | ++---------------+-----------+-------------------------------------------------+ +| brightGreen | ``-`` | Set color | ++---------------+-----------+-------------------------------------------------+ +| brightCyan | ``-`` | Set color | ++---------------+-----------+-------------------------------------------------+ +| brightRed | ``-`` | Set color | ++---------------+-----------+-------------------------------------------------+ +| magenta | ``-`` | Set color | ++---------------+-----------+-------------------------------------------------+ +| yellow | ``-`` | Set color | ++---------------+-----------+-------------------------------------------------+ +| white | ``-`` | Set color | ++---------------+-----------+-------------------------------------------------+ +| dimensions | -hw | Return height and width of canvas | ++---------------+-----------+-------------------------------------------------+ + + +Data Structures +=============== +None. +}doc diff --git a/src/cmd/retroforth/library/casket.rx b/src/cmd/retroforth/library/casket.rx new file mode 100644 index 0000000..a483f43 --- /dev/null +++ b/src/cmd/retroforth/library/casket.rx @@ -0,0 +1,236 @@ +( casket ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +chain: casket' +{{ + variable :options + : KiB ( n-n ) 1024 * ; +---reveal--- + : casket:path ( -$ ) @memory 8 KiB - ; + : casket:options ( -$ ) @:options ; + : casket:buffer ( -$ ) @memory 16 KiB - ; + : casket:form ( -$ ) @memory 32 KiB - ; + : casket:root ( -$ ) "./" ; + : casket:url ( -$ ) "http://domain.com/path/to/cgi" ; + : getRequest ( -$ ) + casket:path dup "PATH_INFO" getEnv + withLength 0 <> [ dup 1+ '/ ^strings'findChar 1+ !:options ] + [ "/" swap 2 copy casket:path 0 !:options ] if ; +}} + ( ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) + : Content-type: ( "- ) + "Content-type: " getToken ^strings'append "\n\n" ^strings'append + keepString .data ` puts ; immediate + ( ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +: tputs ; + {{ + : withBase ( n$q-$ ) [ swap ] dip base &do preserve ; + : char ( $-$ ) + @+ [ 'n = ] [ cr ] whend + [ '' = ] [ '" putc ] whend + [ '[ = ] [ 27 putc putc ] when + putc ; + : obj ( $-$ ) + @+ [ 'd = ] [ [ decimal putn ] withBase ] whend + [ 'o = ] [ [ octal putn ] withBase ] whend + [ 'x = ] [ [ hex putn ] withBase ] whend + [ 'c = ] [ swap putc ] whend + [ 's = ] [ &tputs dip ] whend + [ 'S = ] [ [ [ @ "&#x%x;" puts ] ^types'STRING each@ ] dip ] whend + [ 'q = ] [ &do dip ] whend + [ 'u = ] [ casket:url puts ] whend + putc ; + : complex ( $-n ) + repeat + @+ 0; + dup '\ = [ drop char 0 ] ifTrue + dup '% = [ drop obj 0 ] ifTrue + putc + again ; + [ complex drop ] is tputs + }} + ( ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) + {{ + : withBase ( n$q-$ ) [ swap ] dip base &do preserve ; + : other ( c- ) + [ '< = ] [ "<" puts ] whend + [ '> = ] [ ">" puts ] whend + [ '& = ] [ "&" puts ] whend + putc ; + : complex ( $-n ) + repeat @+ 0; other again ; + ---reveal--- + : eputs complex drop ; + }} + ( ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) + {{ + create buffer ( -a ) + 16 1024 * allot + : casket:templates ( -$ ) casket:root "templates/" ^strings'append ; + ---reveal--- + : withTemplate ( $- ) + buffer 0 16 1024 * fill + casket:templates ^strings'prepend buffer swap ^files'slurp drop + buffer tputs ; + : withFile ( $- ) + buffer 0 16 1024 * fill + casket:templates ^strings'prepend buffer swap ^files'slurp drop + buffer [ @ putc ] ^types'STRING each@ ; + }} + +: /404 + Content-type: text/html + "

    404

    " tputs cr bye ; +: / + Content-type: text/html + "

    casket

    " tputs cr bye ; + +: doBeforeDispatch ; + +: dispatch + doBeforeDispatch + getRequest 1+ + [ @+ [ 0 <> ] [ '/ <> ] bi and ] while 1- 0 swap ! + casket:path find [ @d->xt do ] [ drop /404 ] if bye ; + +{{ + create bit 5 allot + : extract ( $c-$a ) drop @+ bit ! @+ bit 1+ ! bit ; + : render ( $c-$n ) + dup '+ = [ drop 32 ] ifTrue + dup 13 = [ drop 32 ] ifTrue + dup 10 = [ drop 32 ] ifTrue + dup '% = [ extract hex toNumber decimal ] ifTrue ; + : ( $-$ ) repeat @+ 0; render ^buffer'add again ; +---reveal--- + : decode ( $- ) casket:buffer ^buffer'set drop ; +}} + +: serve: ( """- ) + getToken dup + "/" ^strings'prepend header + compiler on + keepString .data getToken drop + ` Content-type: ` withTemplate ` ; &.word reclass ; + +: getFormData ( -$ ) + casket:form "QUERY_STRING" getEnv + casket:form decode casket:buffer withLength casket:form swap 1+ copy + casket:form ; +;chain + +doc{ +====== +Casket +====== + +-------- +Overview +-------- +Casket is a lightweight framework intended to simplify the development of +web apps in Retro. + +Casket grew out of my work on the Corpse blog and later through work on the +Rancid IRC log viewer. + + +--------- +Functions +--------- ++------------------+-------+--------------------------------------------------+ +| Name | Stack | Usage | ++==================+=======+==================================================+ +| serve: | """- | Serve a file with a specific mime type | ++------------------+-------+--------------------------------------------------+ +| decode | $- | Decode a URL encoded string | ++------------------+-------+--------------------------------------------------+ +| dispatch | ``-`` | Look for a view handler (e.g., /index) and call | +| | | it, or call **/404** if none is found | ++------------------+-------+--------------------------------------------------+ +| doBeforeDispatch | ``-`` | Code to execute before processing paths. This is | +| | | always called before **dispatch**. | ++------------------+-------+--------------------------------------------------+ +| / | ``-`` | Default index page | ++------------------+-------+--------------------------------------------------+ +| /404 | ``-`` | Default 404 error page | ++------------------+-------+--------------------------------------------------+ +| withTemplate | $- | Include and render a template file using the | +| | | **tputs** function | ++------------------+-------+--------------------------------------------------+ +| withFile | $- | Include and render a raw file | ++------------------+-------+--------------------------------------------------+ +| tputs | ...$- | This is a replacement for **puts**, which adds | +| | | additional escape sequences for use with the | +| | | templates. | ++------------------+-------+--------------------------------------------------+ +| eputs | $- | This is a replacement for **puts**, which escapes| +| | | html entities for use with
     and such        |
    ++------------------+-------+--------------------------------------------------+
    +| Content-type:    | "-    | Generate a MIME header for a file or view        |
    ++------------------+-------+--------------------------------------------------+
    +| getFormData      | -$    | Process a form and return the elements as a text |
    +|                  |       | string                                           |
    ++------------------+-------+--------------------------------------------------+
    +| getRequest       | ``-`` | Internal: Read the PATH_INFO environment variable|
    +|                  |       | and parse for **casket:path** and                |
    +|                  |       | **casket:options**                               |
    ++------------------+-------+--------------------------------------------------+
    +| casket:url       | -a    | Function returning application url               |
    ++------------------+-------+--------------------------------------------------+
    +| casket:root      | -a    | Function returning path to application root      |
    ++------------------+-------+--------------------------------------------------+
    +| casket:form      | -a    | Internal buffer for form data                    |
    ++------------------+-------+--------------------------------------------------+
    +| casket:buffer    | -a    | Internal buffer                                  |
    ++------------------+-------+--------------------------------------------------+
    +| casket:options   | -a    | Returns optional data following view)            |
    ++------------------+-------+--------------------------------------------------+
    +| casket:path      | -a    | Returns requested view (e.g., /index)            |
    ++------------------+-------+--------------------------------------------------+
    +
    +
    +-------
    +Example
    +-------
    +
    +application.rx
    +==============
    +::
    +
    +  needs casket'
    +  with casket'
    +
    + : /index
    +    Content-type: text/html
    +    "index.erx" withTemplate ;
    +
    +  : /test
    +    Content-type: text/html
    +    casket:options "test.erx" withTemplate ;
    +
    +  [ ( -$ ) "/path/to/app/" ] is casket:root
    +  [ ( -$ ) "http://domain.ext/path/to/cgi" ] is casket:url
    +  &/index is /
    +  &dispatch is boot
    +  save bye
    +
    +
    +index.erx
    +=========
    +::
    +
    +  
    +  

    Test of Casket

    +

    test apple + or test banana.

    + + + +test.erx +======== +:: + + " tputs +

    You requested...

    +

    An %s.

    + + +}doc diff --git a/src/cmd/retroforth/library/char.rx b/src/cmd/retroforth/library/char.rx new file mode 100644 index 0000000..b83c6b8 --- /dev/null +++ b/src/cmd/retroforth/library/char.rx @@ -0,0 +1,72 @@ +( Character Vocabulary ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +chain: char' + : isChar? ( c-f ) 'A 'z within ; + : isUpper? ( c-f ) 'A 'Z within ; + : isLower? ( c-f ) 'a 'z within ; + : isNumeric? ( c-f ) '0 '9 within ; + : isWhitespace? ( c-f ) [ 32 = ] [ 9 = ] [ [ 10 = ] [ 13 = ] bi or ] tri 2or ; + : toUpper ( c-c ) dup isUpper? if; dup isNumeric? if; 32 - ; + : toLower ( c-c ) dup isLower? if; dup isNumeric? if; 32 + ; +;chain + +doc{ +:Title: char' +:Author: Charles Childers +:Version: 1.0 + +char' +===== +This library provides a vocabulary for simple operations on ASCII characters. + + +Loading +======= +The following should suffice: + +:: + + needs char' + + +Examples +======== + +:: + + 97 ^char'isChar? + 'a dup ^char'isUpper? [ ^char'toLower ] ifTrue + + +Functions +========= + ++---------------+---------+------------------------------------------------+ +| Name | Stack | Usage | ++===============+=========+================================================+ +| isChar? | c-f | Return true if a given value is an alphabetic | +| | | character (A-Z or a-z). If not, return false | ++---------------+---------+------------------------------------------------+ +| isUpper? | c-f | Return true if character is uppercase, false | +| | | otherwise | ++---------------+---------+------------------------------------------------+ +| isLower? | c-f | Return true if character is lowercase, false | +| | | otherwise | ++---------------+---------+------------------------------------------------+ +| isNumeric? | c-f | Return true if character is between 0 - 9 | +| | | inclusive, or false otherwise | ++---------------+---------+------------------------------------------------+ +| isWhitespace? | c-f | Return true if character is a space, tab, or | +| | | end of line. Returns false otherwise | ++---------------+---------+------------------------------------------------+ +| toUpper | c-c | Convert a lowercase character to uppercase. | +| | | This will only work on a lowercase character. | ++---------------+---------+------------------------------------------------+ +| toLower | c-c | Convert an upperacase character to lowercase. | +| | | This will only work on an uppercase character. | ++---------------+---------+------------------------------------------------+ + + +Data Structures +=============== +None. +}doc diff --git a/src/cmd/retroforth/library/combinators.rx b/src/cmd/retroforth/library/combinators.rx new file mode 100644 index 0000000..b111233 --- /dev/null +++ b/src/cmd/retroforth/library/combinators.rx @@ -0,0 +1,68 @@ +chain: combinators' +{{ + variable xt +---reveal--- + : loopd ( seq- ) + 2rot 2over < + [ [ [ [ &do sip ] dip ] dip 1- 2over < ] while ] ifTrue + 2drop drop ; + + : indexd ( -n ) + 2pop 2pop 2pop 2pop 2pop + dup !xt + 2push 2push 2push 2push 2push @xt ; + + : loopi ( seq- ) + 2rot 2over < + [ [ [ [ &do sip ] dip 1+ ] dip 2over < ] while ] ifTrue + 2drop drop ; + + : indexi ( -n ) + 2pop 2pop 2pop pop + dup !xt + 2push 2push 2push push @xt ; +}} +;chain + +doc{ +=========== +Combinators +=========== + + +-------- +Overview +-------- +This library serves as a home to various combinators that are useful, but not +essential to the core Retro language. + + +------- +Loading +------- +:: + + needs combinators' + + +--------- +Functions +--------- ++----------+---------+------------------------------------------------+ +| Function | Stack | Used For | ++==========+=========+================================================+ +| loopd | seq- | Execute a loop. Index starts at high value (e) | +| | | and decrements to low value (s). The loop body | +| | | is quote (q). | ++----------+---------+------------------------------------------------+ +| indexd | -n | Return the current index for a decrementing | +| | | loop. | ++----------+---------+------------------------------------------------+ +| loopi | seq- | Execute a loop. Index starts at low value (s) | +| | | and increments to high value (e). The loop body| +| | | is quote (q). | ++----------+---------+------------------------------------------------+ +| indexi | -n | Return the current index for an incrementing | +| | | loop. | ++----------+---------+------------------------------------------------+ +}doc diff --git a/src/cmd/retroforth/library/console.rx b/src/cmd/retroforth/library/console.rx new file mode 100644 index 0000000..9cec41b --- /dev/null +++ b/src/cmd/retroforth/library/console.rx @@ -0,0 +1,76 @@ +( VT100/ANSI Console Words ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +chain: console' + -1 variable: colors + : esc ( $- ) @colors &puts &drop if ; + : black ( - ) "\[30m" esc ; : onBlack ( - ) "\[40m" esc ; + : red ( - ) "\[31m" esc ; : onRed ( - ) "\[41m" esc ; + : green ( - ) "\[32m" esc ; : onGreen ( - ) "\[42m" esc ; + : yellow ( - ) "\[33m" esc ; : onYellow ( - ) "\[43m" esc ; + : blue ( - ) "\[34m" esc ; : onBlue ( - ) "\[44m" esc ; + : magenta ( - ) "\[35m" esc ; : onMagenta ( - ) "\[45m" esc ; + : cyan ( - ) "\[36m" esc ; : onCyan ( - ) "\[46m" esc ; + : white ( - ) "\[37m" esc ; : onWhite ( - ) "\[47m" esc ; + : normal ( - ) "\[0m" esc ; : bold ( - ) "\[1m" esc ; + : at-xy ( xy- ) "\[%d;%dH" esc ; + : home ( - ) 0 0 at-xy ; + : dimensions ( -hw ) @ch @cw ; +;chain + + +doc{ +console' +======== + +.. class:: corefunc + ++-----------------+-----------+-----------------------------------------------+ +| Function | Stack | Notes | ++=================+===========+===============================================+ +| colors | -a | Variable; indicates if console exists | ++-----------------+-----------+-----------------------------------------------+ +| esc | $- | Display a string starting as an escape | +| | | sequence | ++-----------------+-----------+-----------------------------------------------+ +| at-xy | xy- | Move cursor to x,y | ++-----------------+-----------+-----------------------------------------------+ +| home | ``-`` | Move cursor to top left corner | ++-----------------+-----------+-----------------------------------------------+ +| black | ``-`` | Set foreground color | ++-----------------+-----------+-----------------------------------------------+ +| onBlack | ``-`` | Set background color | ++-----------------+-----------+-----------------------------------------------+ +| red | ``-`` | Set foreground color | ++-----------------+-----------+-----------------------------------------------+ +| onRed | ``-`` | Set background color | ++-----------------+-----------+-----------------------------------------------+ +| green | ``-`` | Set foreground color | ++-----------------+-----------+-----------------------------------------------+ +| onGreen | ``-`` | Set background color | ++-----------------+-----------+-----------------------------------------------+ +| yellow | ``-`` | Set foreground color | ++-----------------+-----------+-----------------------------------------------+ +| onYellow | ``-`` | Set background color | ++-----------------+-----------+-----------------------------------------------+ +| blue | ``-`` | Set foreground color | ++-----------------+-----------+-----------------------------------------------+ +| onBlue | ``-`` | Set background color | ++-----------------+-----------+-----------------------------------------------+ +| magenta | ``-`` | Set foreground color | ++-----------------+-----------+-----------------------------------------------+ +| onMagenta | ``-`` | Set background color | ++-----------------+-----------+-----------------------------------------------+ +| cyan | ``-`` | Set foreground color | ++-----------------+-----------+-----------------------------------------------+ +| onCyan | ``-`` | Set background color | ++-----------------+-----------+-----------------------------------------------+ +| white | ``-`` | Set foreground color | ++-----------------+-----------+-----------------------------------------------+ +| onWhite | ``-`` | Set background color | ++-----------------+-----------+-----------------------------------------------+ +| normal | ``-`` | Reset colors to default | ++-----------------+-----------+-----------------------------------------------+ +| bold | ``-`` | Set color attribute to bold/bright | ++-----------------+-----------+-----------------------------------------------+ +| dimensions | -hw | Return height and width of console | ++-----------------+-----------+-----------------------------------------------+ +}doc diff --git a/src/cmd/retroforth/library/crypto.rx b/src/cmd/retroforth/library/crypto.rx new file mode 100644 index 0000000..4b5b86e --- /dev/null +++ b/src/cmd/retroforth/library/crypto.rx @@ -0,0 +1,156 @@ +needs array' + +chain: crypto' + +{{ + variable offset + : rotate ( cb-c ) tuck - @offset + 26 mod + ; + : rotate? ( c-c ) + dup 'a 'z within [ 'a rotate ] ifTrue + dup 'A 'Z within [ 'A rotate ] ifTrue ; +---reveal--- + : ceaser ( $n-$ ) + !offset dup [ [ @ rotate? ] sip ! ] ^types'STRING each@ ; +}} + +: rot13 ( $-$ ) 13 ceaser ; + +{{ + create tapCodes + 'a , 'b , 'c , 'd , 'e , + 'f , 'g , 'h , 'i , 'j , + 'l , 'm , 'n , 'o , 'p , + 'q , 'r , 's , 't , 'u , + + : getIndex ( c-n ) + tapCodes [ [ @ over <> ] sip 1+ swap ] while nip tapCodes - ; + + : encrypt ( c-cr ) + [ 6 < ] [ 1 swap ] when + [ 11 < ] [ 2 swap 5 - ] when + [ 16 < ] [ 3 swap 10 - ] when + [ 21 < ] [ 4 swap 15 - ] when ; + + : tapToChar ( rc-c ) + [ 1- ] bi@ swap 5 * tapCodes + + @ ; + +---reveal--- + : tapcode:encrypt ( $-a ) + ^strings'toLower + withLength here ^buffer'set 2 * 1+ allot withLength 2 * ^buffer'add + [ @ getIndex encrypt swap ^buffer'add ^buffer'add ] ^types'STRING each@ + ^buffer'start ; + + : tapcode:decrypt ( a-$ ) + "" tempString ^buffer'set + @+ 2 / [ @+ swap @+ swap [ tapToChar ^buffer'add ] dip ] times drop + ^buffer'start ; +}} + +{{ + create pens 26 allot + : pig: ( $"- ) keepString getToken @ 'a - pens + ! ; + + "_|" pig: a "|_|" pig: b + "|_" pig: c "]" pig: d + "[]" pig: e "[" pig: f + "-|" pig: g "|-|" pig: h + "|-" pig: i ":|" pig: j + "|:|" pig: k "|:" pig: l + ".]" pig: m "[.]" pig: n + "[." pig: o "=|" pig: p + "|=|" pig: q "|=" pig: r + "\/" pig: s ">" pig: t + "<" pig: u "/\" pig: v + "\./" pig: w ".>" pig: x + "<." pig: y "/.\" pig: z + + : decrypt ( $-c ) + pens [ [ @ over compare not ] sip 1+ swap ] while nip pens - 'a + 1- ; +---reveal--- + : pigpen:encrypt ( $-a ) + withLength "" tempString ^buffer'set ^buffer'add + [ @ 'a - pens + @ ^buffer'add ] ^types'STRING each@ + ^buffer'start ; + + : pigpen:decrypt ( a-$ ) + "" tempString ^buffer'set [ decrypt ^buffer'add ] ^array'apply ^buffer'start ; +}} + + + +{{ + create keystream + 27 allot + + : alphabet ( -$ ) + "_abcdefghijklmnopqrstuvwxyz" ; + + : encode ( c-c ) + 'a - keystream + @ ; + + : getIndex ( c-n ) + keystream [ [ @ over <> ] sip 1+ swap ] while nip keystream - ; + + : decode ( c-c ) + getIndex alphabet + @ ; +---reveal--- + : keyword:setKey ( $- ) + keystream 26 copy ; + + : keyword:encode ( $-$ ) + dup [ [ @ encode ] sip ! ] ^types'STRING each@ ; + + : keyword:decode ( $-$ ) + dup [ [ @ decode ] sip ! ] ^types'STRING each@ ; +}} +;chain + + +doc{ +====== +Crypto +====== + +-------- +Overview +-------- +I enjoy dabbling with logic puzzles and classical forms of encryption. +This vocabulary is intended to be a tool to help with these diversions. + + +--------- +Functions +--------- + ++-----------------+-------+----------------------------------------------------+ +| Name | Stack | Usage | ++=================+=======+====================================================+ +| ceaser | $n-$ | Encrypt (or decrypt) a string using the ceaser | +| | | algorithm. The value n is the number of | +| | | characters to shift the alphabet by. | ++-----------------+-------+----------------------------------------------------+ +| rot13 | $-$ | Encrypt or decrypt a string using rot13. This | +| | | is a trivial variant of the ceaser algorithm. | ++-----------------+-------+----------------------------------------------------+ +| tapcode:encrypt | $-a | Encrypt a string into a tapcode array | ++-----------------+-------+----------------------------------------------------+ +| tapcode:decrypt | a-$ | Decrypt a tapcode array into a string | ++-----------------+-------+----------------------------------------------------+ +| pigpen:encrypt | $-a | Convert a string into a pigpen encoded array. | +| | | To display the pigpen sequence, try: | +| | | | +| | | :: | +| | | | +| | | "ab" ^crypto'toPigpen [ puts space ] ^array'apply| ++-----------------+-------+----------------------------------------------------+ +| pigpen:decrypt | a-$ | Decode a pigpen encoded array into a string | ++-----------------+-------+----------------------------------------------------+ +| keyword:setKey | $- | Set the key to use for keyword encryption. This | +| | | should be 26 characters long. | ++-----------------+-------+----------------------------------------------------+ +| keyword:encrypt | $-$ | Encrypt a string using keyword encryption | ++-----------------+-------+----------------------------------------------------+ +| keyword:decrypt | $-$ | Decrypt a string using keyword encryption | ++-----------------+-------+----------------------------------------------------+ +}doc diff --git a/src/cmd/retroforth/library/decompose.rx b/src/cmd/retroforth/library/decompose.rx new file mode 100644 index 0000000..89ffb1b --- /dev/null +++ b/src/cmd/retroforth/library/decompose.rx @@ -0,0 +1,107 @@ +( templates for casket ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) + +needs casket' +with casket' + +chain: decompose' + +variable attrs +variable src + +: buildString ( q-$ ) + depth [ do ] dip depth swap - 1- [ ^strings'append ] times ; + +: attr:reset ( - ) attrs off ; +: attr:first? @attrs [ "" !attrs ] ifFalse ; + +: accept + ` attr:first? + ` src ` ! ` [ ` attrs ` @ tib keepString .data "='" .data ` src ` @ ` "'" .data ` ] + ` buildString ` keepString ` attrs ` ! ; immediate + +: :id ( $- ) ; +: :name ( $- ) ; +: :class ( $- ) ; +: :width ( $- ) ; +: :height ( $- ) ; +: :href ( $- ) ; + +: getAttrs ( -$ ) @attrs attr:reset ; + +: stylesheet ( q- ) + "" tputs ; +: br ( - ) "
    " tputs ; +: hr ( - ) "
    " tputs ; + +: accept + ` attrs ` @ ` [ ` getAttrs [ "<" tib " %s>" ] buildString keepString .data ` ] + ` [ [ "<" tib ">" ] buildString keepString .data ` ] ` if ` tputs + ` do ` depth ` 0 ` > ` [ ` tputs ` ] ` ifTrue + [ "" ] buildString keepString .data ` tputs ` 0 ` attrs ` ! ; immediate + +: a ( q- ) ; +: b ( q- ) ; +: i ( q- ) ; +: u ( q- ) ; +: pre ( q- ) ; +: p ( q- ) ; +: h1 ( q- ) ; +: h2 ( q- ) ; +: h3 ( q- ) ; +: h4 ( q- ) ; +: div ( q- ) ; +: span ( q- ) ; +: head ( q- ) ; +: table ( q- ) ; +: tr ( q- ) ; +: td ( q- ) ; +: html ( q- ) ; +: head ( q- ) ; +: body ( q- ) ; +: title ( q- ) ; +;chain + + +without + +doc{ +======================= +Casket: HTML Generation +======================= + + +-------- +Overview +-------- +The core Casket framework provides minimal templating, but no easy way to +generate HTML from code. + + +This vocabulary provides support for generating HTML using a series of +combinators. Textual data returned will be displayed (using **^casket'tputs**), +and various attributes are supported. + + +------- +Loading +------- +:: + + needs decompose' + + +------- +Example +------- +:: + + : /index + Content-type: text/html + [ [ [ "Hello" ] title ] head + [ [ "Welcome" ] h1 + [ "This is a paragraph." ] p ] body ] html ; + +}doc + diff --git a/src/cmd/retroforth/library/decorator.rx b/src/cmd/retroforth/library/decorator.rx new file mode 100644 index 0000000..6f4fca9 --- /dev/null +++ b/src/cmd/retroforth/library/decorator.rx @@ -0,0 +1,60 @@ +( Decorator Concept for Retro ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +( Notes: ) +( - the VM is a hybrid bytecode/direct threaded model, so: ) +( 1. , compiles a call to the decorator word ) +( 2. 2 + , skip over the vector header of the original word and compile ) +( a call to it ) +( 3. 9 , compile a return instruction ) +( ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) + +chain: decorator' + : decorate ( aa- ) + here [ , dup 2 + , 9 , ] dip swap :is ; + + : undecorate ( a- ) + :devector ; +;chain + +doc{ +================= +Decorator Concept +================= + + +-------- +Overview +-------- +A decorator extends an existing function by appending ocde that will be +executed before (and possibly after) execution of the original function. + + +----- +Usage +----- +:: + + ok : foo + putn cr ; + ok 1 + ok 2 + ok foo 3 + ok : demo 2over "%d + %d = " puts ; + ok &foo + ok &demo + ok decorate + ok 1 + ok 2 + ok foo 2 + 1 = 3 + ok + + +--------- +Functions +--------- ++------------+-------+----------------------------------------+ +| Name | Stack | Usage | ++============+=======+========================================+ +| decorate | aa- | Apply decoration (a2) to function (a1) | ++------------+-------+----------------------------------------+ +| undecorate | a- | Remove a decoration from a function | ++------------+-------+----------------------------------------+ +}doc diff --git a/src/cmd/retroforth/library/dissect.rx b/src/cmd/retroforth/library/dissect.rx new file mode 100644 index 0000000..9d4c43a --- /dev/null +++ b/src/cmd/retroforth/library/dissect.rx @@ -0,0 +1,75 @@ +( Dissect ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +( Copyright [c] 2010 - 2011, Charles Childers ) +( Copyright [c] 2011, Marc Simpson ) +( ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) + +chain: dissect' +{{ + : case + [ over = ] dip swap + [ nip do -1 ] [ drop 0 ] if 0; pop drop ; +---reveal--- + : lookupOpcode ( n-$ff ) + 0 [ "nop " 0 ] case 1 [ "lit " -1 ] case + 2 [ "dup " 0 ] case 3 [ "drop " 0 ] case + 4 [ "swap " 0 ] case 5 [ "push " 0 ] case + 6 [ "pop " 0 ] case 7 [ "loop " -1 ] case + 8 [ "jump " -1 ] case 9 [ "; " 0 ] case + 10 [ ">jump " -1 ] case 11 [ "> " 0 ] case 25 [ "0; " 0 ] case + 26 [ "1+ " 0 ] case 27 [ "1- " 0 ] case + 28 [ "in " 0 ] case 29 [ "out " 0 ] case + 30 [ "wait " 0 ] case + toString 0 0 ; +}} + +{{ + variable this + : following @this @ toString this ++ ; + : instr ( n-af ) + this ++ lookupOpcode + [ [ "call " ^strings'prepend ] dip ] ifFalse ; +---reveal--- + : decompile ( a-a$ ) + dup !this @ instr [ following ^strings'append ] ifTrue @this swap ; +}} + +: endOfWord? ( a-f ) @+ swap @ [ 9 = ] bi@ and ; +;chain + +doc{ +======= +Dissect +======= + + +-------- +Overview +-------- +This vocabulary provides a basic decompiler for the Ngaro instruction set. + + +----- +Usage +----- + + +--------- +Functions +--------- ++--------------+-------+-------------------------------------------------+ +| Name | Stack | Usage | ++==============+=======+=================================================+ +| lookupOpcode | n-$ff | | ++--------------+-------+-------------------------------------------------+ +| decompile | a-a$ | | ++--------------+-------+-------------------------------------------------+ +| endOfWord? | a-f | | ++--------------+-------+-------------------------------------------------+ +}doc diff --git a/src/cmd/retroforth/library/enum.rx b/src/cmd/retroforth/library/enum.rx new file mode 100644 index 0000000..eb50f96 --- /dev/null +++ b/src/cmd/retroforth/library/enum.rx @@ -0,0 +1,56 @@ +( Enumeration ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +chain: enum' +: step ( n-n ) 1+ ; +: enum ( n"-N ) dup constant step ; +{{ + : + repeat + getToken dup "|" compare if; + header dup @last !d->xt step + again ; +---reveal--- + : enum| ( n"- ) 2drop ; +}} +;chain + +doc{ +=========== +Enumeration +=========== + +-------- +Overview +-------- +This vocabulary adds support for enumerated values. + + +----- +Usage +----- +:: + + 0 enum A enum B enum C enum D drop + +Or + +:: + + 0 enum| A B C D | + + +--------- +Functions +--------- ++-----------+-------+---------------------------------------------------------+ +| Function | Stack | Usage | ++===========+=======+=========================================================+ +| step | n-n | Increment for next enumerated value. Defaults to **1+** | +| | | but can be revectored as needed | ++-----------+-------+---------------------------------------------------------+ +| enum | n"-n | Create an enumerated constant, and increment the value | +| | | using **step** | ++-----------+-------+---------------------------------------------------------+ +| ``enum|`` | n"- | Create a series of enumerated values, incremented by | +| | | **step** | ++-----------+-------+---------------------------------------------------------+ +}doc diff --git a/src/cmd/retroforth/library/eval.rx b/src/cmd/retroforth/library/eval.rx new file mode 100644 index 0000000..4b7a1a8 --- /dev/null +++ b/src/cmd/retroforth/library/eval.rx @@ -0,0 +1,98 @@ +( String Evaluation and Conditional Execution ~~~~~~~~~~~~~~~ ) +( Copyright [c] 2009 - 2011, Charles Childers, Luke Parrish ) +( ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +chain: eval' + +( Evaluate A String ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +{{ + variables| buffer count | + : restore ( - ) &getc :devector ok ; + : get ( -c ) @buffer @ ; + : next ( -c ) @count [ count -- get buffer ++ ] [ 32 restore ] if ; + : replace ( - ) &next &getc :is ; + + : word ( d- ) dup @d->xt swap @d->class withClass ; + : build# ( - ) tib toNumber .data ; + : number ( - ) tib isNumber? [ build# ] [ notFound ] if ; + : process ( af- ) [ word ] [ drop number ] if ; + + : setup ( an- ) dup 0 > [ !count !buffer replace ] [ 2drop ] if ; + : listen ( - ) repeat ok 32 accept tib find process &getc @ 0; drop again ; +---reveal--- + : eval ( $- ) withLength setup listen ; +}} + +( Conditional Execution ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +{{ + : evalTib ( - ) tib eval ; + : error ( - ) "Invalid Syntax\n" puts ; + : read ( - ) '} accept ; + : block ( "- ) '{ getc dup putc space = [ getc drop read ] [ error ] if ; + : evalBlock ( "- ) block evalTib ; + : ifBlock ( f"- ) &evalBlock &block if ; + : defined? ( "-f ) getToken find nip ; +---reveal--- + : ifDefined ( "- ) defined? ifBlock ; + : ifNotDefined ( "- ) defined? not ifBlock ; +}} + +;chain + +doc{ +===== +eval' +===== + + +-------- +Overview +-------- +This library provides a vocabulary for evaluating code contained in strings. + +Retro was not designed to allow textual strings to be evaluated. This works +by remapping the keyboard input to read from a string, until the string is +exhausted. Additionally, it has a built-in varient of the listener to process +input immediately, rather than after the function returns. + +This library should be used only if there's no other (clean) way to solve a +problem. + + +------- +Loading +------- +The following should suffice: + +:: + + needs eval' + + +-------- +Examples +-------- + +:: + + : foo ( -n ) 99 "54 + putn" ^eval'eval 5 ; + + ^eval'ifNotDefined foo { 100 constant foo } + ^eval'ifDefined foo { foo 10 * putn } + + +--------- +Functions +--------- + ++---------------+-------+------------------------------------------------------------------+ +| Function | Stack | Description | ++===============+=======+==================================================================+ +| eval | $- | Evaluate a string | ++---------------+-------+------------------------------------------------------------------+ +| ifDefined | ""- | Parse for a name, if found, execute code in the following string | +| | | block. Otherwise ignore the string block. | ++---------------+-------+------------------------------------------------------------------+ +| ifNotDefined | ""- | Parse for a name, if not found, execute code in the following | +| | | string block. If found, ignore the string block. | ++---------------+-------+------------------------------------------------------------------+ +}doc diff --git a/src/cmd/retroforth/library/forth.rx b/src/cmd/retroforth/library/forth.rx new file mode 100644 index 0000000..904edd3 --- /dev/null +++ b/src/cmd/retroforth/library/forth.rx @@ -0,0 +1,186 @@ +chain: forth' + ( loops ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) + : for ( n- ) ` [ ; compile-only + : next ( - ) ` ] ` times ; compile-only + + + ( conditionals ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) + : then ( - ) ` ] [ ` if ] [ ` ifTrue ] if ; compile-only + : else ( - ) ` ] drop -1 ` [ ; compile-only + : if ( n- ) 0 ` [ ; compile-only + : 0< ( n-f ) 0 < ; + : 0= ( n-f ) 0 = ; + + ( address stack ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) + : r@ ( -n ) ` pop ` dup ` push ; compile-only + : >r ( n- ) ` push ; compile-only + : r> ( -n ) ` pop ; compile-only + + + ( data stack ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) + : 2dup ( xy-xyxy ) 2over ; + + + ( console i/o ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) + : emit ( c- ) putc ; + : key ( -c ) getc ; + : type ( an- ) [ @+ putc ] times drop ; + : spaces ( n- ) &space times ; + + + ( math and bitwise ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) + : */mod ( abc-rq ) &* dip /mod ; + : lshift ( ab-c ) << ; + : rshift ( ab-c ) >> ; +{{ + variable r +---reveal--- + : fm/mod ( ab-mq ) + 2over xor 0 < + if dup !r /mod over [ 1- swap @r + swap ] ifTrue else /mod then ; + : sm/mod ( ab-rq ) + /mod ; +}} + + + ( strings ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +{{ + : keep ( $-a ) + ahead here tib withLength , [ @+ dup , ] while drop [ here swap ! ] dip ; +---reveal--- + : c" ( "-a ) '" accept keep .data ; immediate + : s" ( "-an ) ` c" ` @+ ; immediate + : count ( a-an ) @+ ; +}} + + + ( compiler ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) + : lateBinding ( "- ) + getToken "on" compare + if [ default: : @last dup @ !last ] &: :is + [ default: ; !last ] &; :is else &: :devector &; :devector then ; + + : [ ( - ) ` [[ ; immediate + : ] ( - ) ]] ; + : state ( -a ) compiler ; + : ['] ( "-a ) ' .data ; compile-only + : recurse ( - ) @last @d->xt , ; compile-only + + ( misc ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) + : char ( "-c ) @getToken ; + : [char] ( "-c ) char .data ; compile-only +;chain + +doc{ +=============== +Forth for Retro +=============== + +-------- +Overview +-------- +This vocabulary will make Retro closer to a traditional Forth system. When +it is visible, some things will be significantly different than in a standard +Retro system, but it will also be easier to port existing Forth code. + +Eventually this should provide a large subset of the ANS Forth standard, with +the limitation that only lowercase function names are provided. + + +----- +Notes +----- + + +Strings +======= +Strings in ANS Forth are represented either as counted, or address and length +pairs. + +This differs from the strings in Retro which are represented as null-terminated +character arrays. So existing functions can't be directly used with strings +created by the functions this vocabulary provides, and these functions can not +be used freely with Retro strings. + +For counted strings, you get a pointer to a structure in memory that looks like: + +:: + + length,characters + +These can be unpacked into address/length pairs using **count**. + + +--------- +Functions +--------- ++-------------+----------+----------------------------------------------------+ +| Function | Stack | Usage | ++=============+==========+====================================================+ +| if | f- | Start a conditional sequence | ++-------------+----------+----------------------------------------------------+ +| else | ``-`` | Start the second half of a conditional sequence | ++-------------+----------+----------------------------------------------------+ +| then | ``-`` | End a conditional sequence | ++-------------+----------+----------------------------------------------------+ +| 0< | n-f | Return true flag if n is less than zero | ++-------------+----------+----------------------------------------------------+ +| 0= | n-f | Return true flag if n is equal to zero | ++-------------+----------+----------------------------------------------------+ +| for | n- | Start a counted loop | ++-------------+----------+----------------------------------------------------+ +| next | ``-`` | End a counted loop | ++-------------+----------+----------------------------------------------------+ +| r@ | -n | Return a copy of the top item on the address stack | ++-------------+----------+----------------------------------------------------+ +| ``>r`` | n- | Push a value to the address stack | ++-------------+----------+----------------------------------------------------+ +| ``r>`` | -n | Pop a value off the address stack | ++-------------+----------+----------------------------------------------------+ +| 2dup | xy-xyxy | Duplicate the top two items on the stack | ++-------------+----------+----------------------------------------------------+ +| emit | c- | Display a character | ++-------------+----------+----------------------------------------------------+ +| key | -c | Read a keypress | ++-------------+----------+----------------------------------------------------+ +| type | an- | Display n characters from string | ++-------------+----------+----------------------------------------------------+ +| spaces | n- | Display a series of spaces | ++-------------+----------+----------------------------------------------------+ +| state | -a | Same as **compiler** | ++-------------+----------+----------------------------------------------------+ +| ``[']`` | "-a | Return the address of a function. Compile-time | +| | | version of **'** | ++-------------+----------+----------------------------------------------------+ +| recurse | ``-`` | Compile a call to the current function into the | +| | | function | ++-------------+----------+----------------------------------------------------+ +| ``*/mod`` | abc-rq | Multiply a by b, then divide the results by c. | +| | | Returns the remainder and the quotient. | ++-------------+----------+----------------------------------------------------+ +| rshift | ab-c | Shift bits right | ++-------------+----------+----------------------------------------------------+ +| lshift | ab-c | Shift bits left | ++-------------+----------+----------------------------------------------------+ +| fm/mod | ab-mq | Floored divide and remainder | ++-------------+----------+----------------------------------------------------+ +| sm/mod | ab-mq | Symmetric divide and remainder | ++-------------+----------+----------------------------------------------------+ +| ``c"`` | ``"-a`` | Parse and return a counted string | ++-------------+----------+----------------------------------------------------+ +| ``s"`` | ``"-an`` | Parse and return a string and its length | ++-------------+----------+----------------------------------------------------+ +| count | a-an | Convert a counted string to an addr/len pair | ++-------------+----------+----------------------------------------------------+ +| ``[`` | ``-`` | Turn **compiler** off | ++-------------+----------+----------------------------------------------------+ +| ``]`` | ``-`` | Turn **compiler** on | ++-------------+----------+----------------------------------------------------+ +| char | ``"-c`` | Parse for and return an ASCII character | ++-------------+----------+----------------------------------------------------+ +|``[char]`` | ``"-c`` | Compile-time version of **char** | ++-------------+----------+----------------------------------------------------+ +| lateBinding | ``$-`` | "on" binds names to functions after execution of | +| | | **;**, "off" binds immediately | ++-------------+----------+----------------------------------------------------+ +}doc diff --git a/src/cmd/retroforth/library/hash.rx b/src/cmd/retroforth/library/hash.rx new file mode 100644 index 0000000..051bcec --- /dev/null +++ b/src/cmd/retroforth/library/hash.rx @@ -0,0 +1,93 @@ +( ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +( Proposed hash function for Retro -- based on djb2, Bernstein ) +( ) +( see: http://www.cse.yorku.ca/~oz/hash.html, for example. ) +( ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +( Copyright [c] 2010, Marc Simpson ) +( License: ISC ) +( ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) + +chain: hash' + ( Dan Bernstein, comp.lang.c with 'abs' hack ) + : djb2 ( $-n ) + 5381 over getLength + [ [ dup 5 << + over ] dip + @ + ] iter nip abs ; + + ( 193, 389, 769 are all pretty good; if you expect to have ) + ( a lot of keys, use a larger prime. ) + 389 variable: hash-prime + + ( Vector the favoured hash function -- we intend to offer ) + ( a range of implementations and allow the user to choose ) + : hash ( $-n ) djb2 @hash-prime mod ; +;chain + +doc{ +================= +Hashing Functions +================= + + +-------- +Overview +-------- +This library provides a vocabulary for generating hashes from strings. + +Most documented hash functions leverage unsigned longs during computation. +Here we use *signed* cells as unsigned words are not offered by Retro at +the present time. So that we avoid returning negative hash values, hashing +is filtered through **abs**. (Negative values emerge due to shifting into +the sign bit.) + +The **hash-prime** variable has been selected to provide a reasonable balance +between clashing and key size -- this is to ensure that associative arrays +built using **hash** don't need to allocate too much heap. This can be +adjusted by revectoring **hash** in the [unlikely] event of large tables. + + +------- +Loading +------- +The following should suffice: + +:: + + needs hash' + + +-------- +Examples +-------- + +:: + + needs hash' + "hello" ^hash'hash + + +--------- +Functions +--------- + ++----------+-----------+---------------------------------+ +| Name | Stack | Usage | ++==========+===========+=================================+ +| djb2 | $-n | Generate a djb2 hash. This is | +| | | the default option. | ++----------+-----------+---------------------------------+ +| hash | $-n | Generate a hash from a string. | +| | | Normally this is all you need to| +| | | use. | ++----------+-----------+---------------------------------+ + + +--------------- +Data Structures +--------------- + ++------------+-----------+---------------------------------+ +| Name | Stack | Usage | ++============+===========+=================================+ +| hash-prime | -a | Prime used by hashing algorithim| ++------------+-----------+---------------------------------+ +}doc diff --git a/src/cmd/retroforth/library/infix.rx b/src/cmd/retroforth/library/infix.rx new file mode 100644 index 0000000..85d2369 --- /dev/null +++ b/src/cmd/retroforth/library/infix.rx @@ -0,0 +1,75 @@ +( Infix Math for Retro ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +chain: infix' +{{ + : common getToken toNumber .data ; +---reveal--- + : add ( n"-n ) common ` + ; immediate + : sub ( n"-n ) common ` - ; immediate + : mul ( n"-n ) common ` * ; immediate + : div ( n"-n ) common ` / ; immediate + : xmod ( n"-n ) common ` mod ; immediate + : dmod ( n"-n ) common ` /mod ; immediate + : ^ ( n"-n ) common ` pow ; immediate +}} + &add rename: + + &sub rename: - + &mul rename: * + &xmod rename: mod + &div rename: / + &dmod rename: /mod +;chain + +doc{ +========== +Infix Math +========== + +-------- +Overview +-------- +This library provides a vocabulary for supporting simple infix math. + +Expressions are processed from left to right. + + +Loading +======= +The following should suffice: + +:: + + needs infix' + + +Examples +======== + +:: + + with infix' + + 1 + 2 putn + 4 * 2 + 3 putn + + +Functions +========= + ++----------+-----------+--------------+ +| Name | Stack | Usage | ++==========+===========+==============+ +| ``+`` | ( x"-y ) | ``1 + 2`` | ++----------+-----------+--------------+ +| ``-`` | ( x"-y ) | ``2 - 1`` | ++----------+-----------+--------------+ +| ``*`` | ( x"-y ) | ``3 * 3`` | ++----------+-----------+--------------+ +| ``/`` | ( x"-y ) | ``4 / 2`` | ++----------+-----------+--------------+ +| ``mod`` | ( x"-y ) | ``5 % 2`` | ++----------+-----------+--------------+ +| ``/mod`` | ( x"-qr ) | ``5 /mod 2`` | ++----------+-----------+--------------+ +| ``^`` | ( x"-n ) | ``5 ^ 2`` | ++----------+-----------+--------------+ +}doc diff --git a/src/cmd/retroforth/library/linkedList.rx b/src/cmd/retroforth/library/linkedList.rx new file mode 100644 index 0000000..2c58f99 --- /dev/null +++ b/src/cmd/retroforth/library/linkedList.rx @@ -0,0 +1,111 @@ +needs struct' +with struct' + +chain: linkedList' + { 2 fields .prior .value } node + + : new: ( -a ) &node clone variable: ; + + ( back linked lists ) + : add ( nL- ) + tuck @ swap + &node ^struct'clone [ [ .value ! ] [ .prior ! ] bi ] sip swap ! ; + + : remove ( L-n ) + dup @ dup .value @ [ .prior @ swap ! ] dip ; + + : addNode ( NL- ) + [ @ over .prior ! ] sip ! ; + + : removeNode ( L-N ) + dup @ [ .prior @ swap ! ] sip ; + + : nth ( nL-N ) + swap [ .prior @ ] times ; +;chain + +without + +doc{ +============ +Linked Lists +============ + +-------- +Overview +-------- +While linked lists are a simple data structure, they are very useful. +This vocabulary provides a foundation for creating and using them in +a predicatable, consistent way. + +The **linkedList'** vocabulary provides support for single linked +lists. + + +Back Linked Lists +================= +In this form a list consists of a series of nodes that each point to +the prior node. The list pointer variable is updated with each **add** +or **remove** to point to the newest node in the chain. + + +-------- +Examples +-------- + +Creating A List +=============== +:: + + ^linkedList'new: L + + +Adding A Value To A List +======================== +:: + + 100 L ^linkList'add + + +Removing A Value From A List +============================ +:: + + L ^linkList'remove + + +Accessing A Specific Node +========================= +:: + + 10 L ^linkList'nth + + +--------- +Functions +--------- + ++--------------+-------+-----------------------------------------------+ +| Name | Stack | Usage | ++==============+=======+===============================================+ +| node | "- | Structure for list nodes | ++--------------+-------+-----------------------------------------------+ +| .prior | a-a | Access prior node field | ++--------------+-------+-----------------------------------------------+ +| .value | a-a | Access value field | ++--------------+-------+-----------------------------------------------+ +| new: | "- | Create a list. This gives a variable pointing | +| | | to a **node** structure | ++--------------+-------+-----------------------------------------------+ +| add | nL- | Add a value to a list. Allocates a new node | ++--------------+-------+-----------------------------------------------+ +| remove | L-n | Remove a node from a list and return its value| ++--------------+-------+-----------------------------------------------+ +| addNode | NL- | Add a node to a list | ++--------------+-------+-----------------------------------------------+ +| removeNode | L-N | Remove a node from a list. Returns the node | ++--------------+-------+-----------------------------------------------+ +| nth | nL-N | Return the *nth* node from the list. Indexing | +| | | starts at *1*. | ++--------------+-------+-----------------------------------------------+ +}doc diff --git a/src/cmd/retroforth/library/locals.rx b/src/cmd/retroforth/library/locals.rx new file mode 100644 index 0000000..6235296 --- /dev/null +++ b/src/cmd/retroforth/library/locals.rx @@ -0,0 +1,88 @@ +chain: locals' +{{ + create locals + 6 allot + variable # + : local; ( a- ) + ` ;; ` ;; drop ` [[ &; :devector ; + : rename ( $- ) + @# locals + @ over getLength 1+ copy ; + : patch ( aa$-a ) + drop [ here swap ! ] dip ; + : next ( - ) + # ++ ; +---reveal--- + : aaaaaaaaaaaa ( a-a ) dup 00 + .data ; immediate + : bbbbbbbbbbbb ( a-a ) dup 01 + .data ; immediate + : cccccccccccc ( a-a ) dup 02 + .data ; immediate + : dddddddddddd ( a-a ) dup 03 + .data ; immediate + : eeeeeeeeeeee ( a-a ) dup 04 + .data ; immediate + : ffffffffffff ( a-a ) dup 05 + .data ; immediate + &aaaaaaaaaaaa xt->d d->name locals 00 + ! + &bbbbbbbbbbbb xt->d d->name locals 01 + ! + &cccccccccccc xt->d d->name locals 02 + ! + &dddddddddddd xt->d d->name locals 03 + ! + &eeeeeeeeeeee xt->d d->name locals 04 + ! + &ffffffffffff xt->d d->name locals 05 + ! + : locals{ ( "n-a ) + 0 !# + ahead here [ getToken dup "}" compare [ patch 0 ] [ 0 , rename next -1 ] if ] while + dup .data &local; &; :is @# 1- [ ` !+ ] times ` ! ; immediate + here ]] locals{ a b c d e f } ; !heap +}} +;chain + + +doc{ +=============== +Local Variables +=============== + +-------- +Overview +-------- +This vocabulary provides an easy way to give functions access to local variables within +certain limitations. + +* Variable names are limited to twelve characters +* Functions using local variables are not reentrant + + +------- +Example +------- +:: + + : foo ( nos tos - result ) locals{ tos nos } @nos @tos + @nos * ; + +Note here that **locals{** will modify the temporary variable names to match the names +you specify. + + +--------- +Functions +--------- ++---------+-----------------+----------------------+-------------------------------------+ +| Name | Stack (Runtime) | Stack (Compile-Time) | Usage | ++=========+=================+======================+=====================================+ +| locals{ | ``-`` | -a | Parse for and setup local variables.| +| | | | The parsing ends when **}** is | +| | | | found. Local variables are created | +| | | | and initialized in reverse order of | +| | | | stack comments. | ++---------+-----------------+----------------------+-------------------------------------+ +| a | -a | a-a | First local variable | ++---------+-----------------+----------------------+-------------------------------------+ +| b | -a | a-a | Second local variable | ++---------+-----------------+----------------------+-------------------------------------+ +| c | -a | a-a | Third local variable | ++---------+-----------------+----------------------+-------------------------------------+ +| d | -a | a-a | Fourth local variable | ++---------+-----------------+----------------------+-------------------------------------+ +| e | -a | a-a | Fifth local variable | ++---------+-----------------+----------------------+-------------------------------------+ +| f | -a | a-a | Sixth local variable | ++---------+-----------------+----------------------+-------------------------------------+ + +The initial variable names will be replaced by **locals{** each time it is used. +}doc diff --git a/src/cmd/retroforth/library/math.rx b/src/cmd/retroforth/library/math.rx new file mode 100644 index 0000000..fa32450 --- /dev/null +++ b/src/cmd/retroforth/library/math.rx @@ -0,0 +1,47 @@ +( Math Extensions ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) + +chain: math' +{{ + : closer ( sg-sgn ) 2over / over - 2 / ; + : loop ( sg-sr ) repeat closer 0; + again ; +---reveal--- + : squareRoot ( s-r ) 1 loop nip ; +}} + +: gcd ( ab-n ) [ tuck mod dup ] while drop ; +: lcm ( ab-n ) 2over gcd [ * ] dip / ; +: divisor? ( ab-f ) mod 0 = ; +: */ ( abc-d ) [ * ] dip / ; +: even? ( n-f ) 2 mod 0 = ; +: odd? ( n-f ) 2 mod 0 <> ; +;chain + +doc{ +Overview +======== +This library provides support for additional mathmatic operations not provided +by the core Retro language. + +Functions +========= ++------------+-------+-----------------------------------------------------+ +| Function | Stack | Description | ++============+=======+=====================================================+ +| squareRoot | x-n | Find an (approximate) square root for a given value | ++------------+-------+-----------------------------------------------------+ +| gcd | xy-n | Find the greatest common denominator for two values | ++------------+-------+-----------------------------------------------------+ +| lcm | xy-n | Find the least common multiplier for two values | ++------------+-------+-----------------------------------------------------+ +| divisor? | ab-f | Tests to see if b is a divisor of a. Returns a flag.| ++------------+-------+-----------------------------------------------------+ +| ``*/`` | abc-d | Multiply a by b, then divide bye c to get d | ++------------+-------+-----------------------------------------------------+ +| even? | n-f | Returns a flag indicating whether or not a number is| +| | | true | ++------------+-------+-----------------------------------------------------+ +| odd? | n-f | Returns a flag indicating whether or not a number is| +| | | false | ++------------+-------+-----------------------------------------------------+ +}doc + diff --git a/src/cmd/retroforth/library/stack.rx b/src/cmd/retroforth/library/stack.rx new file mode 100644 index 0000000..8762bf3 --- /dev/null +++ b/src/cmd/retroforth/library/stack.rx @@ -0,0 +1,90 @@ +( stack' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) + +chain: stack' +{{ + variable stack +---reveal--- + : get ( -a ) @stack ; + : set ( n- ) !stack ; + : new ( "- ) here dup , set 100 allot ; + : new: ( "- ) create new ; + : push ( n- ) get &++ [ @ ! ] bi ; + : pop ( -n ) get &@ [ -- @ ] bi ; + : depth ( -n ) get [ @ ] sip - ; +}} +;chain + +doc{ +:Title: stack' +:Author: Charles Childers +:Version: 1.0 + +stack' +====== +This library provides a vocabulary for creating and using custom LIFO stacks. + + +Loading +======= +The following should suffice: + +:: + + needs stack' + + +Examples +======== + +:: + + with stack' + + new: foo + 100 push + 200 push + + new: bar + 300 push + 400 push + 500 push + + depth putn + pop putn + + foo set + depth putn + pop putn + pop putn + + bar set + pop putn + pop putn + + +Functions +========= + ++----------+-----------+---------------------------------+ +| Name | Stack | Usage | ++==========+===========+=================================+ +| get | -a | Get address of current stack | ++----------+-----------+---------------------------------+ +| set | a- | Activate a stack | ++----------+-----------+---------------------------------+ +| new | ``-`` | Create a new anonymous stack | ++----------+-----------+---------------------------------+ +| new: | ``"-`` | Create a new named stack | ++----------+-----------+---------------------------------+ +| push | n- | Push a value to a stack | ++----------+-----------+---------------------------------+ +| pop | -n | Pop a value from a stack | ++----------+-----------+---------------------------------+ +| depth | -n | Return number of items on stack | ++----------+-----------+---------------------------------+ + + +Data Structures +=============== +None. +}doc diff --git a/src/cmd/retroforth/library/struct.rx b/src/cmd/retroforth/library/struct.rx new file mode 100644 index 0000000..7baec3e --- /dev/null +++ b/src/cmd/retroforth/library/struct.rx @@ -0,0 +1,83 @@ +chain: struct' +{{ + : new ( nn$- ) header over ]] .data ` + ` ; &.word reclass + ; +---reveal--- + : { ( -n ) 0 ; + : field ( nn"-n ) getToken new ; + : fields ( n"- ) + [ getToken dup isNumber? [ toNumber getToken new ] [ 1 swap new ] if ] times ; + : } ( n"- ) [ here swap allot constant ] curry constant &.word reclass ; + : size ( a-n ) 1+ @ ; + : clone ( a-a ) here swap size allot ; +}} +;chain + + +doc{ +========== +Structures +========== + + +-------- +Overview +-------- +This vocabulary provides support for creating and using simple data +structures. + + +------- +Example +------- +:: + + with struct' + + { + 1 field .id + 4 field .initials + 1 field .jobcode + } employee + + ( The above could also be written as: ) + { 3 fields .id 4 .initials .jobcode } employee + + employee Fred + 1 Fred !.id + "fjh" Fred .initials 3 copy + 22 Fred !.jobcode + + employee Sue + 2 Sue !.id + "sjs" Sue .initials 3 copy + 91 Sue !.jobcode + + Fred @.id putn + Sue @.id putn + Sue .initials puts + + +--------- +Functions +--------- + ++-------+-------+----------------------------------------------------------+ +| Name | Stack | Used for | ++=======+=======+==========================================================+ +| { | -n | Start a new structure | ++-------+-------+----------------------------------------------------------+ +| field | nn"-n | Add a field to a structure. Takes the number of cells to | +| | | allocate and parses for a name | ++-------+-------+----------------------------------------------------------+ +| fields| n"-n | Add multiple fields to a structure. Takes the number of | +| | | fields and parses for names and optionally sizes. | ++-------+-------+----------------------------------------------------------+ +| } | n"- | End a structure. Parses for the structure name | ++-------+-------+----------------------------------------------------------+ +| size | a-n | Return the size of a structure. The address must be the | +| | | address of the function created by **}**, not the actual | +| | | allocated structure. | ++-------+-------+----------------------------------------------------------+ +| clone | a-a | Given a structure address, return a new anonyous instance| ++-------+-------+----------------------------------------------------------+ +}doc diff --git a/src/cmd/retroforth/library/values.rx b/src/cmd/retroforth/library/values.rx new file mode 100644 index 0000000..950f68d --- /dev/null +++ b/src/cmd/retroforth/library/values.rx @@ -0,0 +1,75 @@ +( Values for Retro ) +( ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +( Copyright [c] 2009 - 2011, Charles Childers ) +( License: ISC ) +( ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) + +chain: values' +{{ + variable state + : (value) @state [ ! ] [ @ ] if state off ; +---reveal--- + : .value .data ` (value) ; + : to state on ; + : value create 0 , &.value reclass ; +}} +;chain + +doc{ +:Title: values' +:Author: Charles Childers +:Version: 1.0 + +values' +======= +A value is a variable that returns the stored value when used. This +library provides an implementation for Retro. + + +Loading +======= +The following should suffice: + +:: + + needs values' + + +Examples +======== + +:: + + with values' + + value foo + + 100 to foo + + foo foo + .s + + 50 to foo + foo foo + .s + + +Functions +========= + ++----------+-----------+-------------------------+ +| Name | Stack | Usage | ++==========+===========+=========================+ +| .value | | a-n | | Return a stored value | +| | | *or* | | | +| | | na- | | Update a stored value | ++----------+-----------+-------------------------+ +| to | ```-`` | Switch value to update | +| | | mode | ++----------+-----------+-------------------------+ +| value | "- | Create a new value | ++----------+-----------+-------------------------+ + + +Data Structures +=============== +None. +}doc diff --git a/src/cmd/retroforth/library/variations.rx b/src/cmd/retroforth/library/variations.rx new file mode 100644 index 0000000..8662df2 --- /dev/null +++ b/src/cmd/retroforth/library/variations.rx @@ -0,0 +1,32 @@ +chain: variations' +{{ + : ignore ( - ) repeat getToken "}" compare if; again ; +---reveal--- + : size ( -n ) -13 5 out wait 5 in dup 0 = [ drop 32 ] ifTrue ; + : endian ( -n ) -14 5 out wait 5 in ; + : bits{ ( n"- ) size <> &ignore ifTrue ; + : bigEndian{ ( n"- ) endian 1 = &ignore ifTrue ; + : littleEndian ( n"- ) endian 0 = &ignore ifTrue ; + : } ( - ) ; immediate +}} +;chain + + +doc{ ++--------------+-------+------------------------------------------------+ +| Function | Stack | Usage | ++==============+=======+================================================+ +| size | -n | Return the number of bits per cell | ++--------------+-------+------------------------------------------------+ +| endian | -n | Return 0 for little endian or 1 for big endian | ++--------------+-------+------------------------------------------------+ +| bits{ | n"- | Execute code up to **}** if the bits per cell | +| | | matches *n* | ++--------------+-------+------------------------------------------------+ +| bigEndian | "- | Execute code up to **}** if endian is big | ++--------------+-------+------------------------------------------------+ +| littleEndian | "- | Execute code up to **}** if endian is little | ++--------------+-------+------------------------------------------------+ +| } | ``-`` | Does nothing | ++--------------+-------+------------------------------------------------+ +}doc diff --git a/src/cmd/retroforth/retro.c b/src/cmd/retroforth/retro.c new file mode 100644 index 0000000..bc9ac84 --- /dev/null +++ b/src/cmd/retroforth/retro.c @@ -0,0 +1,704 @@ +/* Ngaro VM ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + Copyright (c) 2008 - 2011, Charles Childers + Copyright (c) 2009 - 2010, Luke Parrish + Copyright (c) 2010, Marc Simpson + Copyright (c) 2010, Jay Skeer + Copyright (c) 2011, Kenneth Keating + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +#include +#include +#include +#include +#include +#include +#if 0 +# include +#else +# define termios sgttyb +#endif +#include + +/* Configuration ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +---------+---------+---------+ + | 16 bit | 32 bit | 64 bit | + +------------+---------+---------+---------+ + | IMAGE_SIZE | 32000 | 1000000 | 1000000 | + +------------+---------+---------+---------+ + | CELL | int16_t | int32_t | int64_t | + +------------+---------+---------+---------+ + + If memory is tight, cut the MAX_FILE_NAME and MAX_REQUEST_LENGTH. + + You can also cut the ADDRESSES stack size down, but if you have + heavy nesting or recursion this may cause problems. If you do modify + it and experience odd problems, try raising it a bit higher. + + Use -DRX16 to select defaults for 16-bit, or -DRX64 to select the + defaults for 64-bit. Without these, the compiler will generate a + standard 32-bit VM. + + Use -DRXBE to enable the BE suffix for big endian images. This is + only useful on big endian systems. + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +#define CELL int32_t +#define IMAGE_SIZE 10000 +#define ADDRESSES 1024 +#define STACK_DEPTH 128 +#define PORTS 12 +#define MAX_FILE_NAME 1024 +#define MAX_REQUEST_LENGTH 1024 +#define MAX_OPEN_FILES 8 +#define LOCAL "/lib/retroImage" +#define CELLSIZE 32 + +#ifdef RX64 +#undef CELL +#undef CELLSIZE +#undef LOCAL +#define CELL int64_t +#define CELLSIZE 64 +#define LOCAL "retroImage64" +#endif + +#ifdef RX16 +#undef CELL +#undef CELLSIZE +#undef LOCAL +#undef IMAGE_SIZE +#define CELL int16_t +#define CELLSIZE 16 +#define IMAGE_SIZE 32000 +#define LOCAL "retroImage16" +#endif + +#ifdef RXBE +#define LOCAL_FNAME (LOCAL "BE") +#define VM_ENDIAN 1 +#else +#define LOCAL_FNAME (LOCAL) +#define VM_ENDIAN 0 +#endif + + +enum vm_opcode {VM_NOP, VM_LIT, VM_DUP, VM_DROP, VM_SWAP, VM_PUSH, VM_POP, + VM_LOOP, VM_JUMP, VM_RETURN, VM_GT_JUMP, VM_LT_JUMP, + VM_NE_JUMP,VM_EQ_JUMP, VM_FETCH, VM_STORE, VM_ADD, + VM_SUB, VM_MUL, VM_DIVMOD, VM_AND, VM_OR, VM_XOR, VM_SHL, + VM_SHR, VM_ZERO_EXIT, VM_INC, VM_DEC, VM_IN, VM_OUT, + VM_WAIT }; +#define NUM_OPS VM_WAIT + 1 + +typedef struct { + CELL sp, rsp, ip; + CELL data[STACK_DEPTH]; + CELL address[ADDRESSES]; + CELL ports[PORTS]; + FILE *files[MAX_OPEN_FILES]; + FILE *input[MAX_OPEN_FILES]; + CELL isp; + CELL image[IMAGE_SIZE]; + CELL shrink, padding; + int stats[NUM_OPS + 1]; + int max_sp, max_rsp; + char filename[MAX_FILE_NAME]; + char request[MAX_REQUEST_LENGTH]; + struct termios new_termios, old_termios; +} VM; + +/* Macros ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +#define IP vm->ip +#define SP vm->sp +#define RSP vm->rsp +#define DROP { vm->data[SP] = 0; if (--SP < 0) IP = IMAGE_SIZE; } +#define TOS vm->data[SP] +#define NOS vm->data[SP-1] +#define TORS vm->address[RSP] + +/* Helper Functions ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +void rxGetString(VM *vm, int starting) +{ + CELL i = 0; + while(vm->image[starting] && i < MAX_REQUEST_LENGTH) + vm->request[i++] = (char)vm->image[starting++]; + vm->request[i] = 0; +} + +/* Console I/O Support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +void rxWriteConsole(VM *vm, CELL c) { + (c > 0) ? putchar((char)c) : printf("\033[2J\033[1;1H"); + /* Erase the previous character if c = backspace */ + if (c == 8) { + putchar(32); + putchar(8); + } +} + +CELL rxReadConsole(VM *vm) { + CELL c; + if ((c = getc(vm->input[vm->isp])) == EOF && vm->input[vm->isp] != stdin) { + fclose(vm->input[vm->isp--]); + c = 0; + } + if (c == EOF && vm->input[vm->isp] == stdin) + exit(0); + return c; +} + +void rxIncludeFile(VM *vm, char *s) { + FILE *file; + if ((file = fopen(s, "r"))) + vm->input[++vm->isp] = file; +} + +void rxPrepareInput(VM *vm) { + vm->isp = 0; + vm->input[vm->isp] = stdin; +} + +void rxPrepareOutput(VM *vm) { +#if 0 + tcgetattr(0, &vm->old_termios); + vm->new_termios = vm->old_termios; + vm->new_termios.c_iflag &= ~(BRKINT+ISTRIP+IXON+IXOFF); + vm->new_termios.c_iflag |= (IGNBRK+IGNPAR); + vm->new_termios.c_lflag &= ~(ICANON+ISIG+IEXTEN+ECHO); + vm->new_termios.c_cc[VMIN] = 1; + vm->new_termios.c_cc[VTIME] = 0; + tcsetattr(0, TCSANOW, &vm->new_termios); +#else + ioctl(0, TIOCGETP, &vm->old_termios); + vm->new_termios = vm->old_termios; + vm->new_termios.sg_flags &= ~(ECHO | CRMOD | XTABS | RAW); + vm->new_termios.sg_flags |= CBREAK; + ioctl(0, TIOCSETP, &vm->new_termios); +#endif +} + +void rxRestoreIO(VM *vm) { +#if 0 + tcsetattr(0, TCSANOW, &vm->old_termios); +#else + ioctl(0, TIOCSETP, &vm->old_termios); +#endif +} + +/* File I/O Support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +CELL rxGetFileHandle(VM *vm) +{ + CELL i; + for(i = 1; i < MAX_OPEN_FILES; i++) + if (vm->files[i] == 0) + return i; + return 0; +} + +void rxAddInputSource(VM *vm) { + CELL name = TOS; DROP; + rxGetString(vm, name); + rxIncludeFile(vm, vm->request); +} + +CELL rxOpenFile(VM *vm) { + CELL slot, mode, name; + slot = rxGetFileHandle(vm); + mode = TOS; DROP; + name = TOS; DROP; + rxGetString(vm, name); + if (slot > 0) + { + if (mode == 0) vm->files[slot] = fopen(vm->request, "r"); + if (mode == 1) vm->files[slot] = fopen(vm->request, "w"); + if (mode == 2) vm->files[slot] = fopen(vm->request, "a"); + if (mode == 3) vm->files[slot] = fopen(vm->request, "r+"); + } + if (vm->files[slot] == NULL) + { + vm->files[slot] = 0; + slot = 0; + } + return slot; +} + +CELL rxReadFile(VM *vm) { + CELL c = fgetc(vm->files[TOS]); DROP; + return (c == EOF) ? 0 : c; +} + +CELL rxWriteFile(VM *vm) { + CELL slot, c, r; + slot = TOS; DROP; + c = TOS; DROP; + r = fputc(c, vm->files[slot]); + return (r == EOF) ? 0 : 1; +} + +CELL rxCloseFile(VM *vm) { + fclose(vm->files[TOS]); + vm->files[TOS] = 0; + DROP; + return 0; +} + +CELL rxGetFilePosition(VM *vm) { + CELL slot = TOS; DROP; + return (CELL) ftell(vm->files[slot]); +} + +CELL rxSetFilePosition(VM *vm) { + CELL slot, pos, r; + slot = TOS; DROP; + pos = TOS; DROP; + r = fseek(vm->files[slot], pos, SEEK_SET); + return r; +} + +CELL rxGetFileSize(VM *vm) { + CELL slot, current, r, size; + slot = TOS; DROP; + current = ftell(vm->files[slot]); + r = fseek(vm->files[slot], 0, SEEK_END); + size = ftell(vm->files[slot]); + fseek(vm->files[slot], current, SEEK_SET); + return (r == 0) ? size : 0; +} + +CELL rxDeleteFile(VM *vm) { + CELL name = TOS; DROP; + rxGetString(vm, name); + return (unlink(vm->request) == 0) ? -1 : 0; +} + +CELL rxLoadImage(VM *vm, char *image) { + FILE *fp; + CELL x = 0; + + if ((fp = fopen(image, "rb")) != NULL) { + x = fread(&vm->image, sizeof(CELL), IMAGE_SIZE, fp); + fclose(fp); + } + else { + printf("Unable to find the retroImage!\n"); + exit(1); + } + return x; +} + +CELL rxSaveImage(VM *vm, char *image) { + FILE *fp; + CELL x = 0; + + if ((fp = fopen(image, "wb")) == NULL) + { + printf("Unable to save the retroImage!\n"); + rxRestoreIO(vm); + exit(2); + } + + if (vm->shrink == 0) + x = fwrite(&vm->image, sizeof(CELL), IMAGE_SIZE, fp); + else + x = fwrite(&vm->image, sizeof(CELL), vm->image[3], fp); + fclose(fp); + + return x; +} + +/* Environment Query ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +void rxQueryEnvironment(VM *vm) { + CELL req, dest; + char *r; + req = TOS; DROP; + dest = TOS; DROP; + + rxGetString(vm, req); + r = getenv(vm->request); + + if (r != 0) + while (*r != '\0') + { + vm->image[dest] = *r; + dest++; + r++; + } + else + vm->image[dest] = 0; +} + +/* Device I/O Handler ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +void rxDeviceHandler(VM *vm) { + struct winsize w; + if (vm->ports[0] != 1) { + /* Input */ + if (vm->ports[0] == 0 && vm->ports[1] == 1) { + vm->ports[1] = rxReadConsole(vm); + vm->ports[0] = 1; + } + + /* Output (character generator) */ + if (vm->ports[2] == 1) { + rxWriteConsole(vm, TOS); DROP + vm->ports[2] = 0; + vm->ports[0] = 1; + } + + /* File IO and Image Saving */ + if (vm->ports[4] != 0) { + vm->ports[0] = 1; + switch (vm->ports[4]) { + case 1: rxSaveImage(vm, vm->filename); + vm->ports[4] = 0; + break; + case 2: rxAddInputSource(vm); + vm->ports[4] = 0; + break; + case -1: vm->ports[4] = rxOpenFile(vm); + break; + case -2: vm->ports[4] = rxReadFile(vm); + break; + case -3: vm->ports[4] = rxWriteFile(vm); + break; + case -4: vm->ports[4] = rxCloseFile(vm); + break; + case -5: vm->ports[4] = rxGetFilePosition(vm); + break; + case -6: vm->ports[4] = rxSetFilePosition(vm); + break; + case -7: vm->ports[4] = rxGetFileSize(vm); + break; + case -8: vm->ports[4] = rxDeleteFile(vm); + break; + default: vm->ports[4] = 0; + } + } + + /* Capabilities */ + if (vm->ports[5] != 0) { + vm->ports[0] = 1; + switch(vm->ports[5]) { + case -1: vm->ports[5] = IMAGE_SIZE; + break; + case -2: vm->ports[5] = 0; + break; + case -3: vm->ports[5] = 0; + break; + case -4: vm->ports[5] = 0; + break; + case -5: vm->ports[5] = SP; + break; + case -6: vm->ports[5] = RSP; + break; + case -7: vm->ports[5] = 0; + break; + case -8: vm->ports[5] = time(NULL); + break; + case -9: vm->ports[5] = 0; + IP = IMAGE_SIZE; + break; + case -10: vm->ports[5] = 0; + rxQueryEnvironment(vm); + break; + case -11: ioctl(0, TIOCGWINSZ, &w); + vm->ports[5] = w.ws_col; + break; + case -12: ioctl(0, TIOCGWINSZ, &w); + vm->ports[5] = w.ws_row; + break; + case -13: vm->ports[5] = CELLSIZE; + break; + case -14: vm->ports[5] = VM_ENDIAN; + break; + default: vm->ports[5] = 0; + } + } + } +} + +/* The VM ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +void rxProcessOpcode(VM *vm) { + CELL a, b, opcode; + opcode = vm->image[IP]; + + if (opcode > NUM_OPS) + vm->stats[NUM_OPS]++; + else + vm->stats[opcode]++; + + switch(opcode) { + case VM_NOP: + break; + case VM_LIT: + SP++; + IP++; + TOS = vm->image[IP]; + if (vm->max_sp < SP) + vm->max_sp = SP; + break; + case VM_DUP: + SP++; + vm->data[SP] = NOS; + if (vm->max_sp < SP) + vm->max_sp = SP; + break; + case VM_DROP: + DROP + break; + case VM_SWAP: + a = TOS; + TOS = NOS; + NOS = a; + break; + case VM_PUSH: + RSP++; + TORS = TOS; + DROP + if (vm->max_rsp < RSP) + vm->max_rsp = RSP; + break; + case VM_POP: + SP++; + TOS = TORS; + RSP--; + break; + case VM_LOOP: + TOS--; + IP++; + if (TOS != 0 && TOS > -1) + IP = vm->image[IP] - 1; + else + DROP; + break; + case VM_JUMP: + IP++; + IP = vm->image[IP] - 1; + if (IP < 0) + IP = IMAGE_SIZE; + else { + if (vm->image[IP+1] == 0) + IP++; + if (vm->image[IP+1] == 0) + IP++; + } + break; + case VM_RETURN: + IP = TORS; + RSP--; + if (IP < 0) + IP = IMAGE_SIZE; + else { + if (vm->image[IP+1] == 0) + IP++; + if (vm->image[IP+1] == 0) + IP++; + } + break; + case VM_GT_JUMP: + IP++; + if(NOS > TOS) + IP = vm->image[IP] - 1; + DROP DROP + break; + case VM_LT_JUMP: + IP++; + if(NOS < TOS) + IP = vm->image[IP] - 1; + DROP DROP + break; + case VM_NE_JUMP: + IP++; + if(TOS != NOS) + IP = vm->image[IP] - 1; + DROP DROP + break; + case VM_EQ_JUMP: + IP++; + if(TOS == NOS) + IP = vm->image[IP] - 1; + DROP DROP + break; + case VM_FETCH: + TOS = vm->image[TOS]; + break; + case VM_STORE: + vm->image[TOS] = NOS; + DROP DROP + break; + case VM_ADD: + NOS += TOS; + DROP + break; + case VM_SUB: + NOS -= TOS; + DROP + break; + case VM_MUL: + NOS *= TOS; + DROP + break; + case VM_DIVMOD: + a = TOS; + b = NOS; + TOS = b / a; + NOS = b % a; + break; + case VM_AND: + a = TOS; + b = NOS; + DROP + TOS = a & b; + break; + case VM_OR: + a = TOS; + b = NOS; + DROP + TOS = a | b; + break; + case VM_XOR: + a = TOS; + b = NOS; + DROP + TOS = a ^ b; + break; + case VM_SHL: + a = TOS; + b = NOS; + DROP + TOS = b << a; + break; + case VM_SHR: + a = TOS; + DROP + TOS >>= a; + break; + case VM_ZERO_EXIT: + if (TOS == 0) { + DROP + IP = TORS; + RSP--; + } + break; + case VM_INC: + TOS += 1; + break; + case VM_DEC: + TOS -= 1; + break; + case VM_IN: + a = TOS; + TOS = vm->ports[a]; + vm->ports[a] = 0; + break; + case VM_OUT: + vm->ports[0] = 0; + vm->ports[TOS] = NOS; + DROP DROP + break; + case VM_WAIT: + rxDeviceHandler(vm); + break; + default: + RSP++; + TORS = IP; + IP = vm->image[IP] - 1; + + if (IP < 0) + IP = IMAGE_SIZE; + else { + if (vm->image[IP+1] == 0) + IP++; + if (vm->image[IP+1] == 0) + IP++; + } + if (vm->max_rsp < RSP) + vm->max_rsp = RSP; + break; + } + vm->ports[3] = 1; +} + +/* Stats ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +void rxDisplayStats(VM *vm) +{ + int s, i; + + printf("Runtime Statistics\n"); + printf("NOP: %d\n", vm->stats[VM_NOP]); + printf("LIT: %d\n", vm->stats[VM_LIT]); + printf("DUP: %d\n", vm->stats[VM_DUP]); + printf("DROP: %d\n", vm->stats[VM_DROP]); + printf("SWAP: %d\n", vm->stats[VM_SWAP]); + printf("PUSH: %d\n", vm->stats[VM_PUSH]); + printf("POP: %d\n", vm->stats[VM_POP]); + printf("LOOP: %d\n", vm->stats[VM_LOOP]); + printf("JUMP: %d\n", vm->stats[VM_JUMP]); + printf("RETURN: %d\n", vm->stats[VM_RETURN]); + printf(">JUMP: %d\n", vm->stats[VM_GT_JUMP]); + printf("stats[VM_LT_JUMP]); + printf("!JUMP: %d\n", vm->stats[VM_NE_JUMP]); + printf("=JUMP: %d\n", vm->stats[VM_EQ_JUMP]); + printf("FETCH: %d\n", vm->stats[VM_FETCH]); + printf("STORE: %d\n", vm->stats[VM_STORE]); + printf("ADD: %d\n", vm->stats[VM_ADD]); + printf("SUB: %d\n", vm->stats[VM_SUB]); + printf("MUL: %d\n", vm->stats[VM_MUL]); + printf("DIVMOD: %d\n", vm->stats[VM_DIVMOD]); + printf("AND: %d\n", vm->stats[VM_AND]); + printf("OR: %d\n", vm->stats[VM_OR]); + printf("XOR: %d\n", vm->stats[VM_XOR]); + printf("SHL: %d\n", vm->stats[VM_SHL]); + printf("SHR: %d\n", vm->stats[VM_SHR]); + printf("0;: %d\n", vm->stats[VM_ZERO_EXIT]); + printf("INC: %d\n", vm->stats[VM_INC]); + printf("DEC: %d\n", vm->stats[VM_DEC]); + printf("IN: %d\n", vm->stats[VM_IN]); + printf("OUT: %d\n", vm->stats[VM_OUT]); + printf("WAIT: %d\n", vm->stats[VM_WAIT]); + printf("CALL: %d\n", vm->stats[NUM_OPS]); + printf("Max SP: %d\n", vm->max_sp); + printf("Max RSP: %d\n", vm->max_rsp); + + for (s = i = 0; s < NUM_OPS; s++) + i += vm->stats[s]; + printf("Total opcodes processed: %d\n", i); +} + +/* Main ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +int main(int argc, char **argv) { + VM *vm; + int i, wantsStats; + + wantsStats = 0; + vm = calloc(sizeof(VM), sizeof(char)); + strcpy(vm->filename, LOCAL_FNAME); + + rxPrepareInput(vm); + + /* Parse the command line arguments */ + for (i = 1; i < argc; i++) { + if (strcmp(argv[i], "--with") == 0) + rxIncludeFile(vm, argv[++i]); + if (strcmp(argv[i], "--image") == 0) + strcpy(vm->filename, argv[++i]); + if (strcmp(argv[i], "--shrink") == 0) + vm->shrink = 1; + if (strcmp(argv[i], "--stats") == 0) + wantsStats = 1; + } + + if (rxLoadImage(vm, vm->filename) == 0) { + printf("Sorry, unable to find %s\n", vm->filename); + free(vm); + exit(1); + } + + rxPrepareOutput(vm); + for (IP = 0; IP < IMAGE_SIZE; IP++) + rxProcessOpcode(vm); + rxRestoreIO(vm); + + if (wantsStats == 1) + rxDisplayStats(vm); + + free(vm); + return 0; +} diff --git a/src/cmd/retroforth/retroImage b/src/cmd/retroforth/retroImage new file mode 100644 index 0000000000000000000000000000000000000000..0755c8deb8c794904e52bc21f2009e6f55455881 GIT binary patch literal 38228 zcmeI539y}2m8cIHkTC?pC<2!u48bs|$e@sbK~Nx!Vq`q`2FPVd0zn}Rb~`}ZAO#MH z)nJ1l9nr2h;7GN!7+XLbAOa0GVo)ExG^i*dpos7L&Ry%U{QJKFUcGv+>NUGuti9K~ z)?Ry`{|q;-(&=e=Xq9&Z)pa0H{C4Ff*5$&nsJK8@JHLwa~`4(AI6C zt=B?ZzlAoTg_iZNF;8rfTf2p}P77^P3vGiI+J-GO+T*{}?^P`{d&iMjy-k5;?Z-oN zPgVxn>Z|@=7;Uvmo_cLHO5daLt%JO_J(Sl*PoHgdwP(zynWOpHWBO{_-{h-n9@e61 zL%+t;roSBeG9YC}tA#cn2b#8@fhMSLj9&qoGWSE<2vFbqVReL?GOI!}M(sG-e91G< z(Rk+G#*?-jcp=+sAY**nrC{i+J_>!cQRr*7(DgrBFX=Ap)2xenO`7t?XNew7ze4Uu(%N1tCSmiZ2<#cUpq~F%L;pGS^r2sCum$v_ zDeHjL^DEyt_kxgd-ir)afFbwdL&$GjZ_r*Jyt9wewX(Qz`Zgt)pI_WcW zQ1>)=NoUy``cvQ66=U588GT51q`tW{b=#h;q^*eF#`85}IiOEm_x96!D%Zy5`~vU}Hf<=v-T=5QqwV_6z} zroDKTahOZfmb~o%<80#@pZ%_!d)iiy<-u3BEne&W44_=rOM5xDp4PhQzq!_qI?9W+ z;qd%SreW+EU#C(}nI;WVZ>T#7<_18@2digSp89Qk>BgcjV`=JN15Nw#cW<%pxj7WN zGT!Z}pZVk(c5j&9u`fa1=ab==An*P0&X*vs{r7}C(|-QVeB?Q_f9Xq*&wjSXo?q+T zq*-@qV(YUA`~0s5((5yR*44Uyq{xjHZ@zwO&z`@DNpny1@dfDKmB!cheo2{|TXdH| z(>JL1EVDeYv^-;Z&a~}alm6AQXEJtcyAzP_WnaVG_pYx4b_HG!>;~)(Ob7M>_66Pq z%mDTS>d@{_agzR$_c*kPEW8WsZ)>>{!72YA@Y>G3_N{^Y_y=U%D_;wxo9D{tH~nbu zA!PNVu5108=O)OHEjoy`>Kl)D>O|$i8KXAa{8>Nuuli2E<~a>JH5U6{nli5dM%#P+ zDKiz&&S9aG`}ZKhd0*GpDCHB9-;CKrv?2LQk3Pi_CUGzZvE952-h_XV2H?Ro89LtIFCBw?>UV z2{sGq&lUQ0h5qM4zrN6)E%Z+n`jdrzL!tk^(Elmui@^PSICO~o)qATy!1rt!-;>2w z?ss1oz9Vaqy{W$QrkwiM@t?G-%!kjQH?3L6VV(wY7?_Y^v z(p`U%538O+enaTv3J+Fq=xYGT=eViJRR8<3zM8mePK4c;Nngi96YR4(vToYkKWt0$ z+~(Ox8>uHheG+=d=f3Jc<$Ufu5Sz`I&o42j-=@rY$jkyxL_irw#$kS$qy3R|>-oD4 zN1k_m-BZt4y)Q4u))0`gkb2`i(A=AufM>~=+s^0S@I8m4oj2=X4Hf~~Gd^YcU+;BL zn@!*5XUyi9L;v$ICdp?~c}+cKJ{mIW*@xf8*5^xpA1rfa9NKg!e;54E78&#ZdRZ&y z_yjcd27uaww?Q}d`x-hIBRmbd&ja39j)#$vK7+Y*UymHW4EkG`F96O4y1;zE@vGn) z+ic)WU>=bCCxd?kH1*~J$~pcVyjjfEQP(k!hX7+aj`=x2<*gRHA?VWp$J#-g!+i4| zg=f2g*Eqi=+9E(qmV<;d~d1El-G}TQ+IyI`5yCF=z`Bi1TxR8*<&Gl z1-!f??Agrsso=kMJg>*l9e)X$@1>>zc}~Z@V&uFmgSL60uNL$>i04%3#vr&qhXeX@ zkMpdUt7Bs5`FbNw9c2%Uxw%P~W)C_x4V@+Em`~;+e?@xRhn}wqO}%~5Jq@t_)-7wd zd+2ya>;PRo_rP58&e<VAwS@3V#DQ=#K)uJ-Li#}|Tr4|Hph_Kd^$&ByW8 zkQ*T1lUd7C#u_?q4ZhD>C$ZL!y4J>VNAP`ike>PP7jtv1@^^>4&rsfFFQk)q+fPEz zXQJl)hndc!!T0&w*p0)zQr3O5pUlniM95x?t)!ceb7k#!$8#a)=V|6`{*F~v8MzOp z6#5a+)i>YtGa=-5E^^jIAMT0!o3a~*te?FZi~fw=v1Rb4!&9g7rUdT*cyH`U^Sl(a zBcWO2tl_RfUl?@7-w?D5p{3mPpq(CaX?MS%cSAPm2SUGX0>-GP&kc^lg7yq^X-Pi{ zx_8Ddfcmwr$=eN{v9$5_f@e;ZcWT&t6THnEytMfic=q)iz?$244*ACZcKF!~)?Jw{ zppN4`A$Kft(oY7&#*wxz37JEY*$H~){L!Fq3|-syi2FDPaQs8?w+Ozyn|ps9JnQuY z=kw^EG@r`{Z9MyMY|s`5?J?xG4cbjXyEAlC|7*~_k0JlnJ(;=Q5`3Tku%(`PRvTkh9jTe$EoPq>TiVf9_JY0PSUq(7 zPObLSf$(xYn|amCdws*u^>Z=nsh@gZY!iIHH@2VjuPx==N9{Xy47shD=WD0&=RIO= zvwwFFS)Y6Ksoi0~{nobQO(Em=rTWpIveN-=9tC9mG7jm+r>r&2*uKX;QTmRrQ7?~| zEAW520`{dnndd_P_PS#Lc=yZDuYvV=dAwYK|DP%_j@PnTEAf5U>Lag#zSiY4LFTy| z6Q5HN?SUT*tFtcH*HK?T^SOy>Z}@Vi-pYYfcg@h<3apN=uf86h3e>S33+)T3`zq%8 z-5I<+{LQNZb9MB4DByFRzTXC<{`R3i9Xu8Kiu8^B1fXeS&#-YAczgIl9fapwfL`v# znZ6HXZtN$3^)1v<^^7m|-of0@Am)R;mxlrG?5y|R+jlxY0F=}IIpFi)3w3CJ3}9`x z16*s<`s92E=CxjDhRrL%8M8Q_{qi-V3(eT749otgzDM)*cj4>P;0w?c>PS7~&$;os zUIVxpy`-m%`DQ+q=kwMNLcZ1{^{h*^eJ5-8L%myLuDyR{{!MWDQ06*l?!&`iKTq|U z(PzD^mA&rXXiiVE<{?IP~R6ntp_P!q*?d*Dy4DqmHy`?5SV(`5+A0U$3Bu zbCJyHgS`=@W&>3kAU&iyzWyrQ#jZLE`VYSa4U+}|?PdYutAKL*a2 z#s9l!U*Dtox+r`t0*`j~jkjsTHRR6M`A^zT8S~71D$jH9{g78i`NSz_EzpKPH4c3_?5XPON8#(q@RhyM6OR9+O=C~} z=05*A?5wfoOS`N5&R`?#nya}BenD#f8-d&6NgZQOok_?pMCaAT|4EqY0zMm@26#_c z&pNbaZOqa0{y2~}2e9S2*#oQ{ho5o1F6h(1gCpe5Lg;%2eLt}Gv%}B2rU(5X@Hx=( zHP_G4-VDuL-v;(fo(h=r=|CNb^!v;EOvv8=P=?MB`rf_9Zav+rcROcY*y( z#n%$!*gxi7@a&j-HkaqbXXn21NwwU(xQ}W7n^U~yF>S*MYs7Zlzx2&}-C@Aq@_x17>d@vm0M%YCmj<2*uKj*< z_*e$kp0)*TdJjnJ0^Z-!>d=RKZ@*`)eiZhe0t`-=0drUg)S+$juC{;4TH06+ z_6b#(x#!VdRnM^|FbO$(Pa5oAEwYF6wU?6jeovFXvGO-&Y++|}bRR&`?|{>WIQ8mp zuAYmyrlNBSx;_I~L-(k8HuK&vChsHdrA=$N6*jEt8^L}aa4b-VdVZ&*jB~$Ba-Q{n zJ$m-cAz;5>$vZ6jq}tN|G00grzrVC!Jm=O#-VyM$s~_j~ki7KuW@!346+8spyzN7w zxu4oQ7di1e!P?9`(#ILljU(?1W#$FV8o6%fI|$zxE&X0Mu?zOO<~{4uch znlXGBx-sOQD06wxvJaXuybr!Hdso@FW6eSPt91Z%|q~O%*L(_X%E0_#`1%(`&h$nGZ$??i;Vaw zuzOPTOCP_3mpLcx@u1cE{Q{bGUv1)F=Q9nvbyx?%__QaCK}X$$CTU zV4T@2zQ-1%*%R)8^JZVH9X@si&xdcl?Mr=#UFT;kO#372VqDhVdhLS^eVD(s$-3+X z-8CWfbDILq+ztWf9iTt+t3$hQN5tt-LC zVjhmH=|`ZiDCPz5eH~f^J_$X0=S&Thv7EVf{q2CVneVls`&F>};lAYa7}Nex*WVSW z>--hK;{j>wbJ(zUw}FS@)sa0awqC;c0BhuPyI5M<`xbWe_Ym0oA@gdUiDqnjBI|F! zq&M@mR>t`IuxXt6e9^RPjM@;oY>ay}oO6W;D3!1%EW0Q9hbYuB2*cjYb!Flu9 zM4$Hq#-U%~LJS(yKca6w>F;Xh(r*A)pXyu(t=8l3SsTNbz=QC8J~}DD+89qAel{(n zKYe~CY%Br$3^xpTZtT}OjOjsSjAIC}PWFT#?>>0qrC{rt`P{|2*7ygpR*$QoFLxVs zpDAn3+Q>csHTg|0QKx@(2*Mqu|UbvG!wTZFDXQgt^C-R*4jKvr-w}sfTXVykf8q5B7T&~xIE`JlS&!-y$scVhptq0FI zq&u(o`?C?(6zIleJ_~?mOv|Bp9*jS8+Jd<~_y(~1oco>6Mx)g^^J~^RUlX;TaUJmj zwih5*bty@^1Z{({i|AlQB|7VF;y+Tw6e+w8nA>|6sLM8n^W~?&sm#8@uz+F>2Scg{cD|!!x-ww_^r*+=(?`9 zT^|Kq{!s9(OZt|7Jaj+%GFN-S{gH0{t(PzZn(@60>=|{>tVtIzzB<(PGY0<_FZE9k z{fod0;M;5JYD+tHs6PNy{R=|>3b4AK$+G}!Qit`cf4_Ta=-mL`0m1ZZ%*N65y%bu; zd{yXv8QjzxMsBqI&{zH3`!iwZJ79H;-MiL%O8;&3^Q^gNccEiU`8l?+S)cDg_j9R? zRUi6&5I7#buoX~;dfwBI1NO~XfP0wZ;Vp9Z-w*q5sqVzatwD{f)sf&XWym^N zv-(-(Q6cv>u)S>$D&xJA{n!neGr*Sid>~8g+;K|CoEI|ofRJ*zR(1h0-XRx(-M13~ zWArYm1Cjo-sQ0I9^RX{{J{R*6)A=|wd5(I2du}dT~$7!|sIj+ikYJhti(oalpATdFMLM+Bvsx%*Q>+JjUV28cqTG{_=(L zuwUEknwPz{J9d(vd*%9d(B)49*L{@tMrgj~W=sRDjp<;p`8MCLLh6s~$*isK9kl71 zmxTWQx%OEsear|SCxKUF-|sk$BlV68y|Y{N=Hc(1K-(G0_>4E-n@P(WY5%maeJR*y z8}9;b4g%d+gZjff9hq;n^}eum12{kTuqS=ZH~?_IFR-GXHE;js)?73HkA>YYgPV2B zdl0j|VIIad0OY^H;o3XYzmcuagnmD*FMH&>=;d#lvi9nIC+y8+?wL{cYtS;be`apq zJOs|W%{;q6z87sfKb{eP7vjC?Z(y|h8*F3@`p$FI?A>1?r~IG5`F(tqufJW9{seNh z*CCAz-cDa?>zh78Ya!N>D}jAKNG-90ndi@+yh$f z>-ORI2=KP>(wDx60duX-J}i57t%GMm9}ewyp}Dqpd0t!}%Ub?$@U4C2pUB#MQ#O0S zxwT9=<2``2HM#&i$hr#{uixWu2h@@J=I&g()z(>I%bv(*1Z%FXI(oXuXlKVbL!V?V zJ@a&KPK!Ytoe>_`nB`p=@-vy&*Q39KZa)5dPkA5BL&g}q>wI3SLtDlxc3;iMeY0n* ziFD&IR_lFx(2O(dko=78R(Q(Z9kT9g=9)6!gI44IH0$170DiHxdyup59_Z`0=o#ya zt=}(0zFEKfA`X9h_+sn#P}q7g^;-|S8K*VLdaMoIJT?t}*32AJW+QmDX8w+?_gfr4 z;9}%Gv?X%qu+DpC8`j=GTY>HEyq~Odp2MjjGZ{P=dKWkyuzwx927haC+a0%8@DBp# zdpNNp*VB3{{w+pi-0P#k`Y|SB9R}=G{nvqL$DFK}bMtUse+zhM*qjgE7M^+8>*lK6 ztOe8FxS#)O%Xt0U3ZFv+``_0UdDg7ea;weW3K!o;3|`KS_VDyR!^C< znKm8>`b>D4k8(ePo@-@qVr_o@TW#*Y`_=Y7M*EB5`AlQ~xWC5u9N5~V-)EWYC;d8C z*Bq4*JcIh2#0#jeC*HaChhRO8AuVdmP%XA-8pv4s80XK?+Pi}7$I`g{8(=)D+&r(EsDy;$exmeq!r z^E&8Q3-hw3M=yo zd}SQk)oHW7vqSehF(TR*v{Q%r#+O%Uf6vMK zTMuc*lD0m;+}y4Q4#y`q!Ud%lA z@2Rl2KK9OrJ`8BbeLMuvZdmD8jJ@-l8L9G2fh;??oKWqQJq^$d{tbHz;3vTA1uZ7Unljr-~taY9} zd1oTyzNO7!=AQFQz~1Hd#+iV3Z5Ob{g7wZlHHUX2?|yt7-0XpUkX6^$1NG`K&VNM5 zdnfa}nzi5OW3KmomNJW=*?%c>1MB+P`UhF-|4ZN@ z4-4Dr&l*35jQe^zJma*s`P`GwuGXav_nGUZclT-c7{K_<>3r-k?VS^Oj@-+$;rV>S zRne==Gr~D7MwPX;a=>C?+(B2l`%=X6Po*B9o5n9 z?ICBL^$uUc+SruKJMtmc8LQ7Y-lubbI<)yG?p5)4U=!d9AlI*Ap79#1HU2%=`_39z zYq7TL(6_w->iu@xe4b*FwjO1!t#LTm0iJg1P+y%5;EN}Lj{(mG-T+Jn%*|)60l;C* zt0R}+`MO?}wa>!F;@Vnj@7vJDH-MLeDSIzA(97e$aRuy8`($(a!smeOnYEaEC)hJz zfaiVvIFRy-q4^sU`QMD5viCj9>iJr65uiPvWAgW7uD=qxX=^jq^_kG9KKDZ0R=?R{_d@WCwP|d|k+Gc{Ha-HjPqkxiZLvJvvIoXC9-t-qHZKXA zH-a-S^XvldaUJ@#zwPUrn47OO|GvN&wf{NR`P=%8`&wxB&Ju9l^BKrnTl=vN?fju7 z{*EfI8dEq0NV9{@zP;$n&zaT%v?FgSH1GcWcM_y;2F+aG2=1~r zx8@yZ|ETZq_s!1l1bjBm727l-Wc_(ziUnK4w^Mab0evM*z8 zj{gESpJtwr`olVC)8W4ny$I|xD$|bn7{e{#%=ISb+P)9GEj-Un7qA!dJlY@I0d?qO z`10rD&wBd*&SPHou`*d-=d^NX!@$WiZ|8^XH-hWlG;LL0)0Vun)%3YR_(*+qGk^Qd z{MX%V^xP5e5BI=YdH&MIYUujgps#^FkG_`q9!{_qt*M{2)Zyn|{*G!gM8UBQ`u6_o zS72vElDi>f_Xf|0=sm5U9J@g`uY%DdScXiL#%!GHv7|@jZ@nvfbB(X zXiNXj>(GYzXd~-&ROrtI8&~#PQ!jm|-pQeNK3ISDr%;DBvk%nwI|^%%Hr~nH*e?aw z*UW0enAP=jdhHo|wQ*6{xE5^u)-?B^`Py!c(w=cuJ6DFCFMzG%FyP&$%{q)hJA7== z&*R3>{nyY{XSCYu*I2U#8#A|GAKv2m{d4d1?_O9J<9RVXdk?nk*@wZWp_BW`v^Rbn z{KvrBmM^$(DbKVweipLNfagHz0@kzk*br-3m)w*NLlf60GFN4z{vf$DpO%o z*7oUcVEyO**lTr+VX=hE-8;?qMy~BwZ4Lly00%K~?HC8x56UTTkLyF9nCbV(PSEr} z3v6$n26O>)b^q${HKjW+^4(ba(Vp{Tq5C<>a^}XUZ+XHY10z1p0PDjXwe7qPW7d{^ zp}zj!Juvc}oOF9H?YdqFPnnCruI;_be=qd>P9AnoW(>5HF}7jW=Kpc9HJ=BJ_WsVe zthqU6Jg%*sYx(uN(#xT1dog$je%>EU`$Iir%Dt4)d_7mj+|swts^)$B!1I3PxzA}Y zb9DVpdnH$?C$PBSImU%$4UwselnY;$xL?G+Ww157zC#;7pZN47ton*~D z?}r0EM+^eF7xf;3+}U>E`CKs3Gw$ExI`^(~ubr<~=H6RLcb@&FjC12neb@T%{Q14N z^ZNO~l+8zCKM`zf?#VDuJ40pyf=gGE$f>1qBze3)Bf0YpglhOP@a33 zXTrGhI~@7Wm2vM!+w0FoOb>y($QhR~T0Gh@e(NLL6Z*eff&RY8%>lG;&UI+d8d+n% z5H@b(T?VWKIFzxs^(XCVeEHgwG5mtHb)AU5eJ~HOPsP61G?%7d{qRv?&+lu{+jd~Y zuW{_ay52R@p<%xB4#2+$S7r(_(z<~0I-d^Yvz+TKk;!}5^($GsCpDM#q51E7K<>p* z`(->l^V$!bc^!#d-J=!dHH==(Yc}heR~K8x<+Ew#bpkTdrURLmay746$kesid6cpq!&mx8m0@~$wSzlZLf zVlOH8an@tN-i5yJsInh{=j)hz;`4dklQZBM`;B1ZbT3W=h5`4e4(|&={|BZijsSp7DnDM{2(%H1}YG!pmIO4c?~U{GDj>Hil*oEk!qJ>p;`*Ozn+*p1x)a zU7hD5uifE$-`o4bY`}i1!_O}%O)r=Fxtg&bi@x|^aQ5FIYkQy@cp-R4z+sFtkoE5N zIY-^Mv)%!$&N+ZXxg((adXS%`OWPM(=4T!|vG%>@BU?THJZBu{Vjk{89c`bB`0s(c z-{*q!nb11qSP=a82Vc9xfcKSta-0`(mw~$whXBupvU#sC?TrhOv9CS`mOn4(iOkir zLh1Y8YrB3GVBW&zVdF-y@oFRYl4*a8WhQ9T*nFN&8<{(#-uEVlIbnPexjX}&m!o=A zK7$In{UCjM&~FL)*q|R2^lw8q&!u4F^PaM1##x84@zud!tVhQ7-Ozm)Y;UO71?t|g z?B(VEcX-u(Aas8V_O)02VZi;Ud&aV-@Bhbm)&HNNztUDC`)E%YzkA=N@BbHh)qgtl z*FxW%Qxb^t&^6y?kEZT34c*D1yBByi zLi)^eG+NF4uByiV+OTmj*x1$gJ%+Wn26Y&}!@h9t*;@;o^9jt&!?ouwdCui|Zwv=t zU1|2oIPfyS9#VG@nS3wEvd2$bsplS#4f(X6JvalN`|)0|Ic5LaQ+4P|Xv;@Ad6|c? zUxhuNfuv^~_G*nI-_tAeA>{K}pz5qB_H!flFN2%s=Rj=QAD+Xue)gVN4DSJ)8ShWA z;p?|G_Us#je{LdP6UgVbyOGNrAouH?w0i%jdmHlFzaKmfybQ>_yBFF9C@QC(dz`#) z!1H~W@zv*|8=<>jPk`Ib{R`z?`!H)@e3K^s^)oA^-upsh^Zr$44P;z5_cLQ&8UASb z{5kSbKkM3NM_YsV^EK}v?0GhQea*hKM_ [ 0 !current ] ifTrue + again ; + +: expected: + -1 !current do + getToken drop check drop + @current [ passed ] [ failed ] if ++ ; + +: testedWith: + getToken drop passed ++ ; + +: results + @failed @passed @tested "\nTested: %s\n %d passed, %d failed" puts + @passed @failed + +total + @failed +tfailed + @passed +tpassed ; +( ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +TEST: 1+ + [ 3 1+ ] expected: { 4 } + [ 13 2 1+ ] expected: { 3 13 } + [ -2 1+ ] expected: { -1 } +results + +TEST: 1- + [ 3 1- ] expected: { 2 } + [ 13 2 1- ] expected: { 1 13 } + [ 0 1- ] expected: { -1 } + [ -1 1- ] expected: { -2 } +results + +TEST: swap + [ 3 2 swap ] expected: { 3 2 } + [ 1 2 3 swap ] expected: { 2 3 1 } +results + +TEST: drop + [ 2 1 drop ] expected: { 2 } + [ 3 2 1 drop drop ] expected: { 3 } + [ 1 2 3 4 5 drop depth ] expected: { 4 4 3 2 1 } +results + +TEST: and + [ 0 0 and ] expected: { 0 } + [ -1 0 and ] expected: { 0 } + [ -1 -1 and ] expected: { -1 } +results + +TEST: or + [ 0 0 or ] expected: { 0 } + [ -1 0 or ] expected: { -1 } + [ -1 -1 or ] expected: { -1 } +results + +TEST: xor + [ 0 0 xor ] expected: { 0 } + [ -1 0 xor ] expected: { -1 } + [ -1 -1 xor ] expected: { 0 } +results + +TEST: @ + create foo 9 , + [ foo @ ] expected: { 9 } + [ base @ ] expected: { 10 } +results + +TEST: ! + create foo 9 , + [ foo @ 10 foo ! foo @ ] expected: { 10 9 } +results + +TEST: + + [ 1 2 + ] expected: { 3 } + [ 2 3 4 + + ] expected: { 9 } + [ 1 2 1 9 + ] expected: { 10 2 1 } +results + +TEST: - + [ 2 1 - ] expected: { 1 } + [ 2 4 3 - - ] expected: { 1 } + [ 1 2 1 9 - ] expected: { -8 2 1 } +results + +TEST: * + [ 1 2 * ] expected: { 2 } + [ 2 3 * ] expected: { 6 } + [ -1 10 * ] expected: { -10 } + [ -1 2 * -1 * ] expected: { 2 } +results + +TEST: /mod + [ 5 2 /mod ] expected: { 2 1 } + [ -5 2 /mod ] expected: { -2 -1 } + [ -5 -2 /mod ] expected: { 2 -1 } + [ 5 -2 /mod ] expected: { -2 1 } +results + +TEST: << + binary + [ 111000111 11 << ] expected: { 111000111000 } + decimal +results + +TEST: >> + binary + [ 111000111000 11 >> ] expected: { 111000111 } + decimal +results + +IO: tib + +TEST: dup + [ 1 dup ] expected: { 1 1 } + [ 2 1 dup ] expected: { 1 1 2 } +results + +IO: in +IO: out +IO: accept + +TEST: here + [ here heap @ = ] expected: { -1 } + [ here 1 allot here < ] expected: { -1 } + [ here -1 allot here > ] expected: { -1 } +results + +TEST: , + [ here 0 , here swap - ] expected: { 1 } + [ here 12 , @ ] expected: { 12 } + here 1 , 2 , 3 , + [ @+ swap @+ swap @ ] expected: { 3 2 1 } +results + +TEST: create + create foo + [ @last d->name "foo" compare ] expected: { -1 } + [ @last d->name "bar" compare ] expected: { 0 } + [ @last @d->class &.data = ] expected: { -1 } + [ @last @d->class &.data <> ] expected: { 0 } +results + +TEST: : + : foo 12 ; + : bar foo 2 * ; + [ foo bar ] expected: { 24 12 } +results + +TEST: header + "foo" header + [ @last d->name "foo" compare ] expected: { -1 } + [ @last d->name "bar" compare ] expected: { 0 } +results + +IO: cr +IO: putc + +TEST: remapKeys + [ 10 remapKeys ] expected: { 10 } +results + +IO: + +TEST: over + [ 3 2 over ] expected: { 3 2 3 } + [ 1 2 over over ] expected: { 2 1 2 1 } + [ 2 3 over ] expected: { 2 3 2 } +results + +TEST: not + [ -1 not ] expected: { 0 } + [ -3 not ] expected: { 2 } + [ 0 not ] expected: { -1 } + [ 2 not ] expected: { -3 } +results + +TEST: on + variable foo + [ foo @ ] expected: { 0 } + [ foo on foo @ ] expected: { -1 } +results + +TEST: off + -1 variable: foo + [ foo @ ] expected: { -1 } + [ foo off foo @ ] expected: { 0 } +results + +TEST: / + [ 5 2 / ] expected: { 2 } +results + +TEST: mod + [ 5 2 mod ] expected: { 1 } +results + +TEST: negate + [ -1 negate ] expected: { 1 } + [ 1 negate ] expected: { -1 } +results + +TEST: do + [ 100 &1+ do ] expected: { 101 } +results + +TEST: numbers + [ numbers 0 + @ ] expected: { 48 } + [ numbers 1 + @ ] expected: { 49 } + [ numbers 2 + @ ] expected: { 50 } + [ numbers 3 + @ ] expected: { 51 } + [ numbers 4 + @ ] expected: { 52 } + [ numbers 5 + @ ] expected: { 53 } + [ numbers 6 + @ ] expected: { 54 } + [ numbers 7 + @ ] expected: { 55 } + [ numbers 8 + @ ] expected: { 56 } + [ numbers 9 + @ ] expected: { 57 } + [ numbers 10 + @ ] expected: { 65 } + [ numbers 11 + @ ] expected: { 66 } + [ numbers 12 + @ ] expected: { 67 } + [ numbers 13 + @ ] expected: { 68 } + [ numbers 14 + @ ] expected: { 69 } + [ numbers 15 + @ ] expected: { 70 } +results + +IO: wait + +TEST: ' + create foo + here ' foo &= expected: { -1 } + 21 ' foo &= expected: { 0 } +results + +TEST: @+ + create a 1 , 2 , 3 , + [ a @+ swap @+ swap @+ swap drop ] expected: { 3 2 1 } +results + +TEST: !+ + create a 0 , 0 , 0 , + [ 3 2 1 a !+ !+ !+ drop + a @+ swap @+ swap @+ swap drop ] expected: { 3 2 1 } +results + +TEST: keepString + [ "hello" dup keepString <> ] expected: { -1 } +results + +TEST: getLength + [ "abc" getLength ] expected: { 3 } +results + +TEST: withLength + [ "abc" dup withLength [ = ] dip ] expected: { 3 -1 } +results + +TEST: withClass + testedWith: *implicit* +results + +TEST: .word + testedWith: *implicit* +results + +TEST: .macro + testedWith: *implicit* +results + +TEST: .data + testedWith: *implicit* +results + +TEST: d->class + d' words [ d->class @ &.word = ] expected: { -1 } +results + +TEST: d->xt + d' words [ d->xt @ &words = ] expected: { -1 } +results + +TEST: d->name + d' words [ d->name "words" compare ] expected: { -1 } +results + +IO: boot + +TEST: toNumber + [ "123" toNumber ] expected: { 123 } + [ "-123" toNumber ] expected: { -123 } +results + +TEST: isNumber? + [ "123" isNumber? ] expected: { -1 } + [ "qaz" isNumber? ] expected: { 0 } +results + +IO: ok +IO: listen +IO: putc + +TEST: find + [ &words "words" find [ @d->xt = ] dip ] expected: { -1 -1 } + [ &words "zzz" find [ @d->xt = ] dip ] expected: { 0 0 } +results + +TEST: notFound + testedWith: __@ + testedWith: __! + testedWith: __+ + testedWith: __- + testedWith: __# + testedWith: __% + testedWith: __$ + testedWith: __' +results + +TEST: + testedWith: notFound +results + +IO: puts + +TEST: compare + [ "abc" "abc" compare ] expected: { -1 } + [ "abc" "def" compare ] expected: { 0 } + [ "gobo abc" "gobo abc" compare ] expected: { -1 } + [ "fooarcabc" "defaf" compare ] expected: { 0 } +results + +IO: redraw + +TEST: if + [ -1 [ 1 ] [ 2 ] if ] expected: { 1 } + [ 0 [ 1 ] [ 2 ] if ] expected: { 2 } +results + +TEST: ifTrue + [ 9 4 [ 1+ ] ifTrue ] expected: { 10 } + [ 0 -1 [ 1+ ] ifTrue ] expected: { 1 } + [ 0 0 [ 1+ ] ifTrue ] expected: { 0 } +results + +TEST: ifFalse + [ 9 4 [ 1+ ] ifFalse ] expected: { 9 } + [ 0 -1 [ 1+ ] ifFalse ] expected: { 0 } + [ 0 0 [ 1+ ] ifFalse ] expected: { 1 } +results + +TEST: dip + [ 1 2 [ 3 ] dip ] expected: { 2 3 1 } +results + +TEST: sip + [ 1 2 [ 3 ] sip ] expected: { 2 3 2 1 } +results + +TEST: = + [ 1 2 = ] expected: { 0 } + [ 2 1 = ] expected: { 0 } + [ 1 1 = ] expected: { -1 } + [ 2 2 = ] expected: { -1 } + [ 31 121 121 = ] expected: { -1 31 } +results + +TEST: <> + [ 1 2 <> ] expected: { -1 } + [ 2 1 <> ] expected: { -1 } + [ 1 1 <> ] expected: { 0 } + [ 2 2 <> ] expected: { 0 } + [ 31 121 121 <> ] expected: { 0 31 } +results + +TEST: < + [ 1 2 < ] expected: { -1 } + [ 1 1 < ] expected: { 0 } + [ 2 1 < ] expected: { 0 } +results + +TEST: > + [ 1 2 > ] expected: { 0 } + [ 1 1 > ] expected: { 0 } + [ 2 1 > ] expected: { -1 } +results + +TEST: >= + [ 1 2 >= ] expected: { 0 } + [ 1 1 >= ] expected: { -1 } + [ 2 1 >= ] expected: { -1 } +results + +TEST: <= + [ 1 2 <= ] expected: { -1 } + [ 1 1 <= ] expected: { -1 } + [ 2 1 <= ] expected: { 0 } +results + +TEST: ; + testedWith: *implicit* +results + +TEST: ;; + testedWith: ; +results + +TEST: repeat + [ 1 10 repeat 1- 0; again ] expected: { 1 } +results + +TEST: again + testedWith: repeat +results + +TEST: 0; + testedWith: 0; +results + +TEST: push + [ 100 push 200 300 pop ] expected: { 100 300 200 } +results + +TEST: pop + testedWith: push +results + +TEST: ( + [ 1 ( 2 ) 3 ] expected: { 3 1 } +results + +TEST: [ + testedWith: --implicit-- +results + +TEST: ] + testedWith: --implicit-- +results + +TEST: last + [ last @ [ 100 last ! 10 last @ ] dip last ! ] expected: { 100 10 } +results + +TEST: compiler + [ compiler @ [ 100 compiler ! 10 compiler @ ] dip compiler ! ] expected: { 100 10 } +results + +TEST: fb + [ fb @ [ 100 fb ! 10 fb @ ] dip fb ! ] expected: { 100 10 } +results + +TEST: fw + [ fw @ [ 100 fw ! 10 fw @ ] dip fw ! ] expected: { 100 10 } +results + +TEST: fh + [ fh @ [ 100 fh ! 10 fh @ ] dip fh ! ] expected: { 100 10 } +results + +TEST: memory + [ memory @ [ 100 memory ! 10 memory @ ] dip memory ! ] expected: { 100 10 } +results + +TEST: cw + [ cw @ [ 100 cw ! 10 cw @ ] dip cw ! ] expected: { 100 10 } +results + +TEST: ch + [ ch @ [ 100 ch ! 10 ch @ ] dip ch ! ] expected: { 100 10 } +results + +TEST: heap + testedWith: here +results + +TEST: which + [ "words" find drop @which = ] expected: { -1 } + [ "puts" find drop @which = ] expected: { -1 } + [ "cr" find drop @which = ] expected: { -1 } +results + +IO: remapping + +TEST: eatLeading? + ( This is an IO word, but is used by ", so we can test it fairly easily ) + create bl 32 , 0 , + [ " " bl compare ] expected: { -1 } +results + +TEST: base + testedWith: decimal + testedWith: hex + testedWith: binary + testedWith: octal + testedWith: __# + testedWith: __# + testedWith: __% +results + +IO: update + +TEST: version + [ version @ version 1+ @ ] expected: { 49 49 } +results + +TEST: build + [ build @ toNumber time < ] expected: { -1 } +results + +IO: tabAsWhitespace + +TEST: nip + [ 1 2 3 nip ] expected: { 3 1 } +results + +TEST: rot + [ 1 2 3 rot rot rot ] expected: { 3 2 1 } +results + +TEST: tuck + [ 1 2 3 tuck ] expected: { 3 2 3 1 } +results + +TEST: +! + 10 variable: foo + [ @foo 20 foo +! @foo ] expected: { 30 10 } +results + +TEST: -! + 10 variable: foo + [ @foo 5 foo -! @foo ] expected: { 5 10 } +results + +TEST: ++ + variable foo + [ foo @ ] expected: { 0 } + [ foo ++ foo @ ] expected: { 1 } + [ foo ++ foo @ ] expected: { 2 } + [ foo ++ foo @ ] expected: { 3 } + [ foo ++ foo @ ] expected: { 4 } +results + +TEST: -- + 4 variable: foo + [ foo @ ] expected: { 4 } + [ foo -- foo @ ] expected: { 3 } + [ foo -- foo @ ] expected: { 2 } + [ foo -- foo @ ] expected: { 1 } + [ foo -- foo @ ] expected: { 0 } +results + +TEST: {{ + : a 1 ; + : b 3 ; + {{ + : a 2 ; + ---reveal--- + : b a ; + }} + [ a b ] expected: { 2 1 } +results + +TEST: ---reveal--- + testedWith: {{ +results + +TEST: }} + testedWith: {{ +results + +TEST: :devector + : a 12 ; + : b 32 ; + : c a a + ; + [ c ] expected: { 24 } + [ &b &a :is c ] expected: { 64 } + [ &a :devector c ] expected: { 24 } + &b is a + [ c ] expected: { 64 } + devector a + [ c ] expected: { 24 } + : c default: a default: a + ; + &b is a + [ c ] expected: { 24 } +results + +TEST: :is + testedWith: :devector +results + +TEST: devector + testedWith: :devector +results + +TEST: is + testedWith: :devector +results + +TEST: default: + testedWith: :devector +results + + +TEST: d' + create ooo + d' ooo last @ &= expected: { -1 } +results + +TEST: xt->d + d' words [ &words xt->d = ] expected: { -1 } +results + +TEST: hide + create foo + last @ + create bar + create boo + hide bar + [ last @ @ = ] expected: { -1 } + create zoo + last @ + hide zoo + [ last @ @ = ] expected: { 0 } +results + +TEST: __& + ' words &words [ = ] expected: { -1 } +results + +TEST: __@ + decimal + [ @base ] expected: { 10 } +results + +TEST: __! + variable foo + [ @foo 10 !foo @foo ] expected: { 10 0 } +results + +TEST: __+ + 10 variable: foo + [ @foo 20 +foo @foo ] expected: { 30 10 } +results + +TEST: __- + 10 variable: foo + [ @foo 5 -foo @foo ] expected: { 5 10 } +results + +TEST: __2 + [ 1 2 3 4 2drop ] expected: { 2 1 } + [ 0 1 2 3 4 2drop ] expected: { 2 1 0 } + [ 1 2 3 2over ] expected: { 3 2 3 2 1 } + [ 1 2 3 4 2over ] expected: { 4 3 4 3 2 1 } +results + +TEST: .primitive + testedWith: *implicit* +results + +TEST: .compiler + testedWith: *implicit* +results + +TEST: reclass + testedWith: *implicit* +results + +TEST: reclass: + testedWith: *implicit* +results + +TEST: immediate + testedWith: *implicit* +results + +TEST: compile-only + testedWith: *implicit* +results + +TEST: ` + testedWith: *implicit* +results + +TEST: jump: + : foo 12 ; + [ 3 4 jump: foo 5 6 ] expected: { 12 4 3 } +results + +TEST: [[ + [ 1 [[ 1 , 2 , ]] ] expected: { 2 1 } +results + +TEST: ]] + testedWith: [[ +results + +TEST: [] + [] expected: { } +results + +TEST: while + [ 1 2 3 4 5 [ 3 <> ] while ] expected: { 2 1 } +results + +TEST: curry + [ 5 [ 6 ] curry do ] expected: { 6 5 } +results + +TEST: take + [ 5 [ 6 ] take do ] expected: { 5 6 } +results + +TEST: bi + [ 10 &1+ &1- bi ] expected: { 9 11 } +results + +TEST: bi* + [ 1 2 [ 1+ ] [ 1- ] bi* ] expected: { 1 2 } +results + +TEST: bi@ + [ 1 2 [ 1+ ] bi@ ] expected: { 3 2 } +results + +TEST: tri + [ 10 &1+ &1- &negate tri ] expected: { -10 9 11 } +results + +TEST: tri* + [ 1 2 3 &1+ &1- &1+ tri* ] expected: { 4 1 2 } +results + +TEST: tri@ + [ 1 2 3 &1+ tri@ ] expected: { 4 3 2 } +results + +TEST: cons + [ 2 3 cons do ] expected: { 3 2 } +results + +TEST: preserve + [ base [ 19 !base ] preserve @base ] expected: { 10 } + [ @heap heap [ 1000 allot ] preserve @heap = ] expected: { -1 } +results + +TEST: when + : try ( n- ) + [ 1 = ] [ drop 100 ] when + [ 2 = ] [ drop 200 ] when + [ 3 = ] [ drop 300 ] when + drop 400 ; + [ 0 try ] expected: { 400 } + [ 1 try ] expected: { 100 } + [ 2 try ] expected: { 200 } + [ 3 try ] expected: { 300 } + [ 4 try ] expected: { 400 } + [ 91 try ] expected: { 400 } +results + +TEST: whend + : try ( n- ) + [ 1 = ] [ 100 ] whend + [ 2 = ] [ 200 ] whend + [ 3 = ] [ 300 ] whend + drop 400 ; + [ 0 try ] expected: { 400 } + [ 1 try ] expected: { 100 } + [ 2 try ] expected: { 200 } + [ 3 try ] expected: { 300 } + [ 4 try ] expected: { 400 } + [ 91 try ] expected: { 400 } +results + +TEST: times + [ 3 [ 1 ] times ] expected: { 1 1 1 } + [ 2 -5 [ 1 ] times ] expected: { 2 } + [ 2 0 [ 1 ] times ] expected: { 2 } +results + +TEST: iterd + [ 3 [] iterd ] expected: { 1 2 3 } + [ 2 -5 [] iterd ] expected: { 2 } + [ 2 0 [] iterd ] expected: { 2 } +results + +TEST: iter + [ 3 [] iter ] expected: { 2 1 0 } + [ 2 -5 [] iter ] expected: { 2 } + [ 2 0 [] iter ] expected: { 2 } +results + +TEST: + testedWith: each@ +results + +TEST: each@ + create array + 5 , ( #entries ) + 1 , 2 , 3 , 4 , 5 , 0 , + [ array [ @ ] ^types'ARRAY each@ ] expected: { 5 4 3 2 1 } + [ array 1+ [ @ ] ^types'STRING each@ ] expected: { 5 4 3 2 1 } + [ array 1+ 3 [ @ ] ^types'BUFFER each@ ] expected: { 3 2 1 } + create a + 0 , 1 , + create b + &a , 2 , + create c + &b , 3 , + create d + &c , 4 , + d variable: list + [ list [ 1+ @ ] ^types'LIST each@ ] expected: { 1 2 3 4 } +results + +TEST: copy + testedWith: tempString +results + +TEST: fill + create z 100 allot + [ z 1 20 fill z @ ] expected: { 1 } +results + +TEST: ahead + : bar 14 ; + : z ahead ; immediate + : foo z 12 ; + &bar swap ! + [ foo ] expected: { 14 } +results + +TEST: if; + [ 0 1 1 = if; ] expected: { 0 } + [ 0 1 2 = if; 3 ] expected: { 3 0 } +results + +TEST: within + [ 12 1 100 within ] expected: { -1 } + [ 1 1 100 within ] expected: { -1 } + [ 0 1 100 within ] expected: { 0 } + [ 98 1 100 within ] expected: { -1 } +results + +TEST: variable: + testedWith: +! + testedWith: -! +results + +TEST: variable + testedWith: @ + testedWith: ! +results + +TEST: constant + 10 constant foo + [ foo ] expected: { 10 } +results + +TEST: string + "Hello" string HELLO + "World" string WORLD + [ HELLO WORLD compare ] expected: { 0 } + [ HELLO HELLO compare ] expected: { -1 } +results + +TEST: allot + [ here 100 allot here swap 100 + = ] expected: { -1 } + [ here 100 allot -100 allot here = ] expected: { -1 } +results + +TEST: elements + 4 elements a b c d + [ &a 1+ &b = ] expected: { -1 } + [ 10 !a @a !d @d ] expected: { 10 } + [ a 3 + @ ] expected: { 10 } +results + +TEST: decimal + decimal [ 10 ] hex expected: { A } decimal +results + +TEST: hex + hex [ A ] decimal expected: { 10 } +results + +TEST: octal + octal [ 71 ] decimal expected: { 57 } +results + +TEST: binary + testedWith: >> + testedWith: << +results + +TEST: toString + [ 123 toString "123" compare ] expected: { -1 } + [ 3123 toString "123" compare ] expected: { 0 } +results + +IO: clear +IO: space +IO: putn + +TEST: .parse + testedWith: __$ + testedWith: __# + testedWith: __' + testedWith: __% + testedWith: __" +results + +TEST: parsing + testedWith: __$ + testedWith: __# + testedWith: __' + testedWith: __% + testedWith: __" +results + +TEST: __$ + [ $A ] expected: { 10 } +results + +TEST: __# + hex + [ #10 ] expected: { A } + decimal +results + +TEST: __\% + [ %101 ] expected: { 5 } +results + +TEST: __' + [ 'a ] expected: { 97 } +results + +TEST: dicts + [ @dicts ] expected: { 0 } + [ &strings' :with @dicts ] expected: { 1 } + [ &buffer' :with @dicts ] expected: { 2 } + [ without @dicts ] expected: { 1 } + [ &buffer' :with @dicts ] expected: { 2 } + [ global @dicts ] expected: { 0 } + with buffer' + [ @dicts ] expected: { 1 } + global with| strings' files' | + [ @dicts ] expected: { 2 } + global +results + +TEST: %% + testedWith: chain: +results + +TEST: <%> + testedWith: chain: +results + +TEST: .chain + testedWith: chain: +results + +TEST: chain: + chain: foo' + 21 variable: a + : foo.b a @ putn ; + ;chain + + [ "foo.b" &foo' findInChain nip ] expected: { -1 } + [ "foobar2" &foo' findInChain nip ] expected: { 0 } + + 50 variable: a + 100 variable: a + 200 variable: b + [ &a &foo' .chain "a" find drop d->xt %% = ] expected: { 0 } + [ ^foo'a @ ] expected: { 21 } +results + +TEST: ;chain + testedWith: chain: +results + +TEST: :with + testedWith: dicts +results + +TEST: with + testedWith: dicts +results + +TEST: without + testedWith: dicts +results + +TEST: global + testedWith: dicts +results + +TEST: findInChain + testedWith: chain: +results + +TEST: with| + testedWith: dicts +results + +TEST: rename: + create bar 300 , + create foo 200 , + create foo 100 , + [ @bar @foo ] expected: { 100 300 } + &foo rename: bar + [ @bar @foo ] expected: { 200 100 } +results + +TEST: tempString + [ "100" dup tempString over over < [ compare ] dip and ] expected: { -1 } +results + +TEST: __" + [ " hello" @ 32 = ] expected: { -1 } + [ " hello" getLength ] expected: { 6 } +results + +TEST: " + [ "hello" @ 'h = ] expected: { -1 } + [ "hello" getLength ] expected: { 5 } +results + +IO: formatted + +TEST: depth + [ 1 2 depth ] expected: { 2 2 1 } + [ depth ] expected: { 0 } + [ 1 depth ] expected: { 1 1 } +results + +TEST: reset + [ 1 2 3 reset depth ] expected: { 0 } +results + +IO: .s +IO: words +IO: save +IO: bye +IO: getToken +IO: getNumber +IO: :include +IO: include +IO: time +IO: delay +IO: getEnv + +TEST: later + : a 1 later 2 ; + : b 3 a 4 ; + [ b ] expected: { 2 4 1 3 } +results + +TEST: doc{ + : a 100 ; +doc{ : a 200 ; }doc + [ a ] expected: { 100 } +results + +TEST: __^ + testedWith: chain: +results + +IO: needs + +TEST: variables| + variables| a b c d | + 100 !a + 200 !b + 300 !c + 400 !d + [ @a @b @c @d ] expected: { 400 300 200 100 } +results + +TEST: pow + [ 2 3 pow ] expected: { 8 } + [ 3 2 pow ] expected: { 9 } +results + +TEST: abs + [ -1 abs ] expected: { 1 } + [ 1 abs ] expected: { 1 } +results + +TEST: min + [ 1 10 min ] expected: { 1 } + [ 91 10 min ] expected: { 10 } +results + +TEST: max + [ 1 10 max ] expected: { 10 } + [ 91 10 max ] expected: { 91 } +results + +TEST: random + [ random random = ] expected: { 0 } +results + +summary +bye diff --git a/src/cmd/retroforth/test/io/output.txt b/src/cmd/retroforth/test/io/output.txt new file mode 100644 index 0000000..a79cd45 --- /dev/null +++ b/src/cmd/retroforth/test/io/output.txt @@ -0,0 +1,5 @@ + +<3> 3 1 2 + +aabc def2 + 1 = 3 + diff --git a/src/cmd/retroforth/test/io_files.rx b/src/cmd/retroforth/test/io_files.rx new file mode 100644 index 0000000..acaf69f --- /dev/null +++ b/src/cmd/retroforth/test/io_files.rx @@ -0,0 +1,141 @@ +( ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +global +4 elements tested current passed failed +3 elements checked ignored io +3 elements total tpassed tfailed + +: TEST: getToken keepString !tested 0 [ !passed ] [ !failed ] bi checked ++ ; +: OMIT: getToken "\nNot Tested: %s" puts ignored ++ ; +: IO: getToken "\nNot Tested (IO): %s" puts io ++ ; + +: summary + @tfailed @tpassed @total + "\n%d tests run: %d passed, %d failed." puts + @io @ignored @checked + "\n%d words checked, %d words unchecked, %d i/o words ignored.\n" puts ; + +: check + repeat + getToken + "}" over compare if; + toNumber <> [ 0 !current ] ifTrue + again ; + +: expected: + -1 !current do + getToken drop check drop + @current [ passed ++ ] [ failed ++ ] if ; + +: testedWith: + getToken drop passed ++ ; + +: results + @failed @passed @tested "\nTested: %s\n %d passed, %d failed" puts + @passed @failed + +total + @failed +tfailed + @passed +tpassed ; +( ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +with files' + +variable fid + +TEST: :R + [ "file1.test" :R open 0 = ] expected: { -1 } +results + +TEST: :W + [ "file2.test" :W open dup !fid 0 <> ] expected: { -1 } + [ @fid close ] expected: { 0 } +results + +TEST: :A + [ "file3.test" :A open dup !fid 0 <> ] expected: { -1 } + [ @fid close ] expected: { 0 } +results + +TEST: :M + [ "file4.test" :M open dup !fid 0 = ] expected: { -1 } +results + +TEST: open + testedWith: :R + testedWith: :W + testedWith: :A + testedWith: :M +results + +TEST: write + [ "file2.test" :W open dup !fid 0 <> ] expected: { -1 } + [ 'a @fid write ] expected: { 1 } + [ 'b @fid write ] expected: { 1 } + [ 'c @fid write ] expected: { 1 } + [ 10 @fid write ] expected: { 1 } + [ @fid close ] expected: { 0 } +results + +TEST: read + [ "file2.test" :R open dup !fid 0 <> ] expected: { -1 } + [ @fid read 'a = ] expected: { -1 } + [ @fid read 'b = ] expected: { -1 } + [ @fid read 'c = ] expected: { -1 } + [ @fid read 10 = ] expected: { -1 } + [ @fid close ] expected: { 0 } +results + +TEST: pos + [ "file2.test" :R open dup !fid 0 <> ] expected: { -1 } + [ @fid read 'a = ] expected: { -1 } + [ @fid read 'b = ] expected: { -1 } + [ @fid pos ] expected: { 2 } + [ @fid read 'c = ] expected: { -1 } + [ @fid read 10 = ] expected: { -1 } + [ @fid close ] expected: { 0 } +results + +TEST: seek + [ "file2.test" :R open dup !fid 0 <> ] expected: { -1 } + 2 @fid seek drop + [ @fid read 'c = ] expected: { -1 } + [ @fid read 10 = ] expected: { -1 } + [ @fid close ] expected: { 0 } +results + +TEST: size + [ "file2.test" :R open dup !fid 0 <> ] expected: { -1 } + [ @fid size ] expected: { 4 } + [ @fid close ] expected: { 0 } +results + +TEST: slurp + [ here "file2.test" slurp 4 = ] expected: { -1 } + [ here @+ swap @ 'b = swap 'a = = ] expected: { -1 } +results + +TEST: spew + [ "Fourscore and seven years ago..." withLength + [ "file3.test" spew ] sip = ] expected: { -1 } +results + +TEST: writeLine + [ "file2.test" :W open dup !fid 0 <> ] expected: { -1 } + [ "hello" @fid writeLine depth ] expected: { 0 } + [ "world" @fid writeLine depth ] expected: { 0 } + [ @fid close ] expected: { 0 } +results + +TEST: readLine + [ "file2.test" :R open dup !fid 0 <> ] expected: { -1 } + [ @fid readLine "hello" compare ] expected: { -1 } + [ @fid readLine "world" compare ] expected: { -1 } + [ @fid close ] expected: { 0 } +results + +TEST: delete + [ "file1.test" delete 0 <> ] expected: { 0 } + [ "file2.test" delete 0 <> ] expected: { -1 } + [ "file3.test" delete 0 <> ] expected: { -1 } + [ "file4.test" delete 0 <> ] expected: { 0 } +results + +summary +bye diff --git a/src/cmd/retroforth/test/io_output.rx b/src/cmd/retroforth/test/io_output.rx new file mode 100644 index 0000000..5f75cc5 --- /dev/null +++ b/src/cmd/retroforth/test/io_output.rx @@ -0,0 +1,48 @@ +( ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +global +4 elements tested current passed failed +3 elements checked ignored io +3 elements total tpassed tfailed + +: TEST: getToken keepString !tested 0 [ !passed ] [ !failed ] bi checked ++ ; +: OMIT: getToken "\nNot Tested: %s" puts ignored ++ ; +: IO: getToken "\nNot Tested (IO): %s" puts io ++ ; + +: summary + @tfailed @tpassed @total + "\n%d tests run: %d passed, %d failed." puts + @io @ignored @checked + "\n%d words checked, %d words unchecked, %d i/o words ignored.\n" puts ; + +: check + repeat + getToken + "}" over compare if; + toNumber <> [ 0 !current ] ifTrue + again ; + +: expected: + -1 !current do + getToken drop check drop + @current [ passed ++ ] [ failed ++ ] if ; + +: testedWith: + getToken drop passed ++ ; + +: results + @failed @passed @tested "\nTested: %s\n %d passed, %d failed" puts + @passed @failed + +total + @failed +tfailed + @passed +tpassed ; +( ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +: foo + update off + 3 1 2 .s cr cr + 'a putc + "abc" space "def" + "%d + %d = %d\n" puts + update on + redraw ; +foo +bye + diff --git a/src/cmd/retroforth/test/library/array.rx b/src/cmd/retroforth/test/library/array.rx new file mode 100644 index 0000000..9e8dd66 --- /dev/null +++ b/src/cmd/retroforth/test/library/array.rx @@ -0,0 +1,97 @@ +needs assertion' +needs array' + +with assertion' + +[ [ "passed" ] [ "failed" ] if "%s\n" puts ] is postCond + +variable a + +^array'new{ 10 20 30 } !a +: a0 ( - ) + "Testing ^array'new{ : " puts + @a @ 3 assert= + @a 1 + @ 10 assert= + @a 2 + @ 20 assert= + @a 3 + @ 30 assert= ; assertion + +: a1 ( - ) + "Testing ^array'fromQuote : " puts + [ 10 20 30 ] ^array'fromQuote !a + @a 1 + @ 10 assert= + @a 2 + @ 20 assert= + @a 3 + @ 30 assert= ; assertion + +: a2 ( - ) + "Testing ^array'toQuote : " puts + [ 10 20 30 ] ^array'fromQuote ^array'toQuote do + 30 assert= + 20 assert= + 10 assert= ; assertion + +: a3 ( - ) + "Testing ^array'map : " puts + [ 10 20 30 ] ^array'fromQuote !a + @a [ 10 / 2 + ] ^array'map + @a 1 + @ 3 assert= + @a 2 + @ 4 assert= + @a 3 + @ 5 assert= ; assertion + +: a4 ( - ) + "Testing ^array'in? : " puts + [ 10 20 30 ] ^array'fromQuote !a + 1 @a ^array'in? 0 assert= + 20 @a ^array'in? -1 assert= ; assertion + +: a5 ( - ) + "Testing ^array'stringIn? : " puts + [ "test" "for" "strings" ] ^array'fromQuote !a + "foo" @a ^array'stringIn? 0 assert= + "strings" @a ^array'stringIn? -1 assert= ; assertion + +: a6 ( - ) + "Testing ^array'fromQuote : " puts + [ 10 20 30 ] ^array'fromQuote !a + @a ^array'reverse + @a 1 + @ 30 assert= + @a 2 + @ 20 assert= + @a 3 + @ 10 assert= ; assertion + +: a7 ( - ) + "Testing ^array'apply : " puts + [ 10 20 30 ] ^array'fromQuote !a + @a [ 2 - ] ^array'apply + 28 assert= 18 assert= 8 assert= ; assertion + +: a8 ( - ) + "Testing ^array'append : " puts + [ 10 20 30 ] ^array'fromQuote + [ 40 50 60 ] ^array'fromQuote ^array'append !a + @a 1 + @ 10 assert= + @a 2 + @ 20 assert= + @a 3 + @ 30 assert= + @a 4 + @ 40 assert= + @a 5 + @ 50 assert= + @a 6 + @ 60 assert= ; assertion + +: a9 ( - ) + "Testing ^array'sort: : " puts + [ 30 10 20 ] ^array'fromQuote !a + @a ^array'sort:bubble + @a 1 + @ 10 assert= + @a 2 + @ 20 assert= + @a 3 + @ 30 assert= + + [ 0 -10 30 10 86 20 ] ^array'fromQuote !a + @a ^array'sort:bubble + @a 1 + @ -10 assert= + @a 2 + @ 0 assert= + @a 3 + @ 10 assert= + @a 4 + @ 20 assert= + @a 5 + @ 30 assert= + @a 6 + @ 86 assert= ; assertion + +: go ( - ) + cr a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 bye ; + +go diff --git a/src/cmd/retroforth/test/library/bad.rx b/src/cmd/retroforth/test/library/bad.rx new file mode 100644 index 0000000..363b6b1 --- /dev/null +++ b/src/cmd/retroforth/test/library/bad.rx @@ -0,0 +1,44 @@ +needs assertion' +needs bad' + +with assertion' + +[ [ "passed" ] [ "failed" ] if "%s\n" puts ] is postCond + +: a0 ( - ) + "Testing: ^bad'pool and ^bad'newPool : " puts + 100 ^bad'pool ! + ^bad'pool @ 100 assert= + 50 ^bad'newPool + ^bad'pool @ 100 <> assert ; assertion + +: a1 ( - ) + "Testing: ^bad'pack : " puts + 'a 'b 'c 'd ^bad'pack 1684234849 assert= ; assertion + +: a2 ( - ) + "Testing: ^bad'unpack : " puts + 1684234849 ^bad'unpack + 'd assert= 'c assert= 'b assert= 'a assert= ; assertion + +: a3 ( - ) + "Testing: ^bad'b! and ^bad'b@ : " puts + 'a 0 ^bad'b! + 'b 1 ^bad'b! + 0 ^bad'b@ 'a assert= + 1 ^bad'b@ 'c = not assert + 1 ^bad'b@ 'b assert= ; assertion + +: a4 ( - ) + "Testing: ^bad'b@+ : " puts + 0 ^bad'b@+ 'a assert= ^bad'b@+ 'b assert= drop ; assertion + +: a5 ( - ) + "Testing: ^bad'b!+ : " puts + 'c 'd 'e 0 3 [ ^bad'b!+ ] times + 0 ^bad'b@+ 'e assert= ^bad'b@+ 'd assert= ^bad'b@ 'c assert= ; assertion + +: go ( - ) + cr a0 a1 a2 a3 a4 a5 bye ; + +go diff --git a/src/cmd/retroforth/test/library/bstrings.rx b/src/cmd/retroforth/test/library/bstrings.rx new file mode 100644 index 0000000..76e7a8d --- /dev/null +++ b/src/cmd/retroforth/test/library/bstrings.rx @@ -0,0 +1,43 @@ +needs assertion' +needs bstrings' + +with assertion' + +[ [ "passed" ] [ "failed" ] if "%s\n" puts ] is postCond + +: a0 + "Testing pack : " puts + "hello" ^bstrings'pack @ 'h = not assert ; assertion + +: a1 + "Testing getLength : " puts + "hello" ^bstrings'pack ^bstrings'getLength 5 assert= ; assertion + +: a2 + "Testing unpack : " puts + "hello" ^bstrings'pack dup @ 'h = not assert + ^bstrings'unpack @ 'h assert= ; assertion + +: a3 + "Testing withLength : " puts + "hello" ^bstrings'pack dup ^bstrings'withLength + 5 assert= + = assert ; assertion + +: a4 + "Not testing puts [io related] : " puts ; assertion + +: a5 + "Testing toLower : " puts + "HeLLo123#" ^bstrings'pack ^bstrings'toLower ^bstrings'unpack + "hello123#" compare assert ; assertion + +: a6 + "Testing toUpper : " puts + "HeLLo123#" ^bstrings'pack ^bstrings'toUpper ^bstrings'unpack + "HELLO123#" compare assert ; assertion + +: go + cr a0 a1 a2 a3 a4 a5 a6 bye ; + +go diff --git a/src/cmd/retroforth/test/library/char.rx b/src/cmd/retroforth/test/library/char.rx new file mode 100644 index 0000000..a7d598b --- /dev/null +++ b/src/cmd/retroforth/test/library/char.rx @@ -0,0 +1,65 @@ +needs assertion' +needs char' + +with assertion' + +[ [ "passed" ] [ "failed" ] if "%s\n" puts ] is postCond + +: a0 + "Testing isChar? : " puts + 'a ^char'isChar? assert + '1 ^char'isChar? not assert + 'z ^char'isChar? assert + 231 ^char'isChar? not assert ; assertion + +: a1 + "Testing isUpper? : " puts + 'a ^char'isUpper? not assert + 'A ^char'isUpper? assert + 'z ^char'isUpper? not assert + 'Z ^char'isUpper? assert ; assertion + +: a2 + "Testing isLower? : " puts + 'a ^char'isLower? assert + 'A ^char'isLower? not assert + 'z ^char'isLower? assert + 'Z ^char'isLower? not assert ; assertion + +: a3 + "Testing isNumeric? : " puts + 'a ^char'isNumeric? not assert + 'Z ^char'isNumeric? not assert + 'q ^char'isNumeric? not assert + 42 ^char'isNumeric? not assert + '1 ^char'isNumeric? assert + '2 ^char'isNumeric? assert + '6 ^char'isNumeric? assert + '8 ^char'isNumeric? assert + '0 ^char'isNumeric? assert ; assertion + +: a4 + "Testing isWhitespace? : " puts + 32 ^char'isWhitespace? assert + 9 ^char'isWhitespace? assert + 10 ^char'isWhitespace? assert + 13 ^char'isWhitespace? assert + 'a ^char'isWhitespace? not assert + 43 ^char'isWhitespace? not assert ; assertion + +: a5 + "Testing toUpper : " puts + '1 ^char'toUpper '1 assert= + 'a ^char'toUpper 'A assert= + 'A ^char'toUpper 'A assert= ; assertion + +: a6 + "Testing toLower : " puts + '1 ^char'toLower '1 assert= + 'a ^char'toLower 'a assert= + 'A ^char'toLower 'a assert= ; assertion + +: go + cr a0 a1 a2 a3 a4 a5 a6 bye ; + +go diff --git a/src/cmd/retroforth/test/library/decorator.rx b/src/cmd/retroforth/test/library/decorator.rx new file mode 100644 index 0000000..8ffc7c3 --- /dev/null +++ b/src/cmd/retroforth/test/library/decorator.rx @@ -0,0 +1,23 @@ +needs assertion' +needs decorator' + +with assertion' + +[ [ "passed" ] [ "failed" ] if "%s\n" puts ] is postCond + +: foo + 12 ; + +: a0 + foo 12 assert= + &foo [ 14 ] ^decorator'decorate + foo 12 assert= 14 assert= ; assertion + +: a1 + &foo ^decorator'undecorate + foo 12 assert= ; assertion + +: go + cr a0 a1 bye ; + +go diff --git a/src/cmd/retroforth/test/library/enum.rx b/src/cmd/retroforth/test/library/enum.rx new file mode 100644 index 0000000..4d75c08 --- /dev/null +++ b/src/cmd/retroforth/test/library/enum.rx @@ -0,0 +1,37 @@ +needs assertion' +needs enum' + +with| assertion' enum' | + +[ [ "passed" ] [ "failed" ] if "%s\n" puts ] is postCond + +1 enum a enum b enum c drop + +: a0 + "Testing enum : " puts + a 1 assert= + b 2 assert= + c 3 assert= ; assertion + +1 enum| d e f | + +: a1 + "Testing enum| : " puts + d 1 assert= + e 2 assert= + f 3 assert= ; assertion + +[ 10 + ] is step +0 enum| g h i | + +: a2 + "Testing step : " puts + g 00 assert= + h 10 assert= + i 20 assert= ; assertion + + +: go + cr a0 a1 a2 bye ; + +go diff --git a/src/cmd/retroforth/test/library/hash.rx b/src/cmd/retroforth/test/library/hash.rx new file mode 100644 index 0000000..3bb7fb3 --- /dev/null +++ b/src/cmd/retroforth/test/library/hash.rx @@ -0,0 +1,29 @@ +needs assertion' +needs hash' + +with assertion' + +[ [ "passed" ] [ "failed" ] if "%s\n" puts ] is postCond + +: a0 + "Testing hash-prime : " puts + ^hash'hash-prime @ 389 assert= ; assertion + +: a1 + "Testing djb2 : " puts + "hello" ^hash'djb2 261238937 assert= + "world" ^hash'djb2 279393645 assert= + "foobar" ^hash'djb2 35364674 assert= ; assertion + +: a2 + "Testing hash : " puts + "hello" ^hash'hash 152 assert= + "world" ^hash'hash 230 assert= + "booya" ^hash'hash 329 assert= ; assertion + +: go + cr a0 a1 a2 bye ; + +go + + diff --git a/src/cmd/retroforth/test/library/infix.rx b/src/cmd/retroforth/test/library/infix.rx new file mode 100644 index 0000000..53094f0 --- /dev/null +++ b/src/cmd/retroforth/test/library/infix.rx @@ -0,0 +1,39 @@ +needs assertion' +needs infix' + +with| assertion' infix' | + +[ [ "passed" ] [ "failed" ] if "%s\n" puts ] is postCond + +: a0 + "Testing + : " puts + 1 + 2 + 3 6 assert= ; assertion + +: a1 + "Testing - : " puts + 6 - 4 2 assert= ; assertion + +: a2 + "Testing * : " puts + 2 * 3 6 assert= ; assertion + +: a3 + "Testing / : " puts + 6 / 2 3 assert= ; assertion + +: a4 + "Testing mod : " puts + 7 mod 2 1 assert= ; assertion + +: a5 + "Testing /mod : " puts + 7 /mod 2 3 assert= 1 assert= ; assertion + +: a6 + "Testing ^ : " puts + 2 ^ 3 8 assert= ; assertion + +: go + cr a0 a1 a2 a3 a4 a5 a6 bye ; + +go diff --git a/src/cmd/retroforth/test/library/locals.rx b/src/cmd/retroforth/test/library/locals.rx new file mode 100644 index 0000000..6c7e73f --- /dev/null +++ b/src/cmd/retroforth/test/library/locals.rx @@ -0,0 +1,24 @@ +needs assertion' +needs locals' + +with| assertion' locals' | + +[ [ "passed" ] [ "failed" ] if "%s\n" puts ] is postCond + +: foo + locals{ a b c } + @c @b + @a * ; + +: bar + locals{ a b c } + @c @b - @a + ; + +: a0 + "Testing locals: " puts + 1 2 3 foo 9 assert= + 2 4 6 bar 4 assert= ; assertion + +: go + cr a0 bye ; + +go diff --git a/src/cmd/retroforth/test/library/math.rx b/src/cmd/retroforth/test/library/math.rx new file mode 100644 index 0000000..76c78a9 --- /dev/null +++ b/src/cmd/retroforth/test/library/math.rx @@ -0,0 +1,30 @@ +needs assertion' +needs math' + +with assertion' + +[ [ "passed" ] [ "failed" ] if "%s\n" puts ] is postCond + +: a0 + "Testing squareRoot : " puts + 144 ^math'squareRoot 12 assert= + 36 ^math'squareRoot 6 assert= ; assertion + +: a1 + "Testing gcd : " puts + 36 12 ^math'gcd 12 assert= + 44 55 ^math'gcd 11 assert= ; assertion + +: a2 + "Testing lcm : " puts + 96 144 ^math'lcm 288 assert= ; assertion + +: a3 + "Testing divisor? : " puts + 100 25 ^math'divisor? -1 assert= + 100 31 ^math'divisor? 0 assert= ; assertion + +: go + cr a0 a1 a2 a3 bye ; + +go diff --git a/src/cmd/retroforth/test/library/stack.rx b/src/cmd/retroforth/test/library/stack.rx new file mode 100644 index 0000000..3876e0b --- /dev/null +++ b/src/cmd/retroforth/test/library/stack.rx @@ -0,0 +1,67 @@ +needs assertion' +needs stack' + +with assertion' + +[ [ "passed" ] [ "failed" ] if "%s\n" puts ] is postCond + +^stack'new: foo +^stack'new: bar + +: a0 + "Testing new: : " puts + foo bar <> assert ; assertion + +variable a +variable b + +: a1 + "Testing new : " puts + ^stack'new ^stack'get !a + ^stack'new ^stack'get !b + @a @b <> assert + @a foo <> assert + @b bar <> assert ; assertion + +: a2 + "Testing get : " puts + ^stack'get @b assert= ; assertion + +: a3 + "Testing set : " puts + @a ^stack'set + @a ^stack'get assert= + foo ^stack'set + bar ^stack'get <> assert ; assertion + +: a4 + "Testing push : " puts + @a ^stack'set + 100 200 ^stack'push depth 1 assert= + ^stack'push depth 0 assert= + bar ^stack'set + 400 300 ^stack'push depth 1 assert= + ^stack'push depth 0 assert= ; assertion + +: a5 + "Testing pop : " puts + @a ^stack'set + ^stack'pop 100 assert= + ^stack'pop 200 assert= + bar ^stack'set + ^stack'pop 400 assert= + ^stack'pop 300 assert= ; assertion + +: a6 + "Testing depth : " puts + @a ^stack'set + 100 200 ^stack'push depth 1 assert= + ^stack'push depth 0 assert= + ^stack'depth 2 assert= + ^stack'pop 100 assert= + ^stack'depth 1 assert= ; assertion + +: go + cr a0 a1 a2 a3 a4 a5 a6 bye ; + +go diff --git a/src/cmd/retroforth/test/library/struct.rx b/src/cmd/retroforth/test/library/struct.rx new file mode 100644 index 0000000..854535f --- /dev/null +++ b/src/cmd/retroforth/test/library/struct.rx @@ -0,0 +1,42 @@ +needs assertion' +needs struct' + +with assertion' + +[ [ "passed" ] [ "failed" ] if "%s\n" puts ] is postCond + +with struct' + +{ + 1 field .a + 2 field .b + 3 fields 1 .c 3 .d 5 .e +} foo + +foo bar + + +: a0 + "The following are tested implicitly:\n" puts + " { } field fields\n" puts + "The code laid down by them will be used by the remaining tests.\n" puts ; + +: a1 + "Testing size : " puts + &foo size 12 assert= ; assertion + +: a2 + "Testing clone : " puts + &foo clone here swap - 12 assert= ; assertion + +: a3 + "Testing field access : " puts + 1 bar .a ! + 2 bar .c ! + bar .a @ 1 assert= + bar .c @ 2 assert= ; assertion + +: go + cr a0 a1 a2 a3 bye ; + +go diff --git a/src/cmd/retroforth/test/library/values.rx b/src/cmd/retroforth/test/library/values.rx new file mode 100644 index 0000000..c4fb62a --- /dev/null +++ b/src/cmd/retroforth/test/library/values.rx @@ -0,0 +1,32 @@ +needs assertion' +needs values' + +with| assertion' values' | + +[ [ "passed" ] [ "failed" ] if "%s\n" puts ] is postCond + +value a +value b + +: a0 + "Testing value : " puts + a 0 assert= b 0 assert= ; assertion + +: a1 + "Testing to : " puts + 100 to a + 80 to b + a b + 180 assert= + a 100 assert= + b 80 assert= ; assertion + +: a2 + "Testing .value : " puts + &a &.value withClass 100 assert= + to 3100 &a &.value withClass + &a &.value withClass 3100 assert= ; assertion + +: go + cr a0 a1 a2 bye ; + +go diff --git a/src/cmd/retroforth/test/vocabs.rx b/src/cmd/retroforth/test/vocabs.rx new file mode 100644 index 0000000..a9f7bae --- /dev/null +++ b/src/cmd/retroforth/test/vocabs.rx @@ -0,0 +1,168 @@ +( ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) +global +4 elements tested current passed failed +3 elements checked ignored io +3 elements total tpassed tfailed + +: TEST: getToken keepString !tested 0 [ !passed ] [ !failed ] bi checked ++ ; +: OMIT: getToken "\nNot Tested: %s" puts ignored ++ ; +: IO: getToken "\nNot Tested (IO): %s" puts io ++ ; + +: summary + @tfailed @tpassed @total + "\n%d tests run: %d passed, %d failed." puts + @io @ignored @checked + "\n%d words checked, %d words unchecked, %d i/o words ignored.\n" puts ; + +: check + repeat + getToken + "}" over compare if; + toNumber <> [ 0 !current ] ifTrue + again ; + +: expected: + -1 !current do + getToken drop check drop + @current [ passed ++ ] [ failed ++ ] if ; + +: testedWith: + getToken drop passed ++ ; + +: results + @failed @passed @tested "\nTested: %s\n %d passed, %d failed" puts + @passed @failed + +total + @failed +tfailed + @passed +tpassed ; +( ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) + +TEST: ^buffer'add + create buf 100 allot + [ 12 &buf ^buffer'set ] expected: { 12 } + [ ^buffer'end &buf = ] expected: { -1 } + [ 12 1 ^buffer'add ] expected: { 12 } + [ 12 2 ^buffer'add ] expected: { 12 } + [ 12 3 ^buffer'add ] expected: { 12 } + [ ^buffer'size ] expected: { 3 } + [ ^buffer'end &buf 3 + = ] expected: { -1 } + [ ^buffer'get ] expected: { 3 } + [ ^buffer'get ] expected: { 2 } + [ ^buffer'get ] expected: { 1 } + [ ^buffer'size ] expected: { 0 } + [ ^buffer'start buf = ] expected: { -1 } +results + +TEST: ^buffer'get + testedWith: ^buffer'add +results + +TEST: ^buffer'end + testedWith: ^buffer'add +results + +TEST: ^buffer'size + testedWith: ^buffer'add +results + +TEST: ^buffer'empty + testedWith: ^buffer'add +results + +TEST: ^buffer'set + testedWith: ^buffer'add +results + +TEST: ^buffer'start + testedWith: ^buffer'add +results + +TEST: ^strings'search + [ "abcdefghi" "efg" ^strings'search "efghi" compare ] expected: { -1 } + [ "abcdefghi" "qz1" ^strings'search "efghi" compare ] expected: { 0 } +results + +TEST: ^strings'findChar + [ "abcdefg" 'h ^strings'findChar ] expected: { 0 } + [ "abcdefg" dup 'd ^strings'findChar swap 3 + = ] expected: { -1 } +results + +TEST: ^strings'chop + [ "abcdef" ^strings'chop "abcde" compare ] expected: { -1 } + [ "abcdefg" ^strings'chop "abcde" compare ] expected: { 0 } +results + +TEST: ^strings'getSubset + [ "abcdefghi" 2 3 ^strings'getSubset "cde" compare ] expected: { -1 } +results + +TEST: ^strings'trimLeft + [ " abc " ^strings'trimLeft "abc " compare ] expected: { -1 } + [ " abc " ^strings'trimLeft " abc " compare ] expected: { 0 } +results + +TEST: ^strings'trimRight + [ " abc " ^strings'trimRight " abc" compare ] expected: { -1 } + [ " abc " ^strings'trimRight " abc " compare ] expected: { 0 } +results + +TEST: ^strings'append + [ "abc" "def" ^strings'append "abcdef" compare ] expected: { -1 } + [ "abcd" "efg" ^strings'append "abcdef" compare ] expected: { 0 } +results + +TEST: ^strings'appendChar + [ "abc" 'a ^strings'appendChar "abca" compare ] expected: { -1 } + [ "abcd" 'e ^strings'appendChar 'f ^strings'appendChar dup puts "abcdef" compare ] expected: { -1 } +results + +TEST: ^strings'prepend + testedWith: ^strings'append +results + +TEST: ^strings'toLower + [ "ABC" ^strings'toLower "abc" compare ] expected: { -1 } + [ "aBc" ^strings'toLower "abc" compare ] expected: { -1 } + [ "A12Bcd" ^strings'toLower "a12bcd" compare ] expected: { -1 } +results + +TEST: ^strings'toUpper + [ "abc" ^strings'toUpper "ABC" compare ] expected: { -1 } + [ "aBc" ^strings'toUpper "ABC" compare ] expected: { -1 } + [ "A12Bcd" ^strings'toUpper "A12BCD" compare ] expected: { -1 } +results + +TEST: ^strings'reverse + [ "abc" ^strings'reverse "cba" compare ] expected: { -1 } + [ "12abc3" ^strings'reverse "3cba21" compare ] expected: { -1 } +results + +TEST: ^strings'split + [ "abcdef" 3 ^strings'split "abc" compare swap "def" compare ] expected: { -1 -1 } +results + +TEST: ^strings'splitAtChar + [ "abcdef" 'c ^strings'splitAtChar "abc" compare swap "def" compare ] expected: { -1 -1 } +results + +TEST: ^strings'splitAtChar: + [ "abcdef" ^strings'splitAtChar: c "abc" compare swap "def" compare ] expected: { -1 -1 } +results + +TEST: ^types'ARRAY + [ ^types'ARRAY ] expected: { 0 } +results + +TEST: ^types'BUFFER + [ ^types'BUFFER ] expected: { 1 } +results + +TEST: ^types'STRING + [ ^types'STRING ] expected: { 2 } +results + +TEST: ^types'LIST + [ ^types'LIST ] expected: { 3 } +results + +summary +bye diff --git a/src/cmd/retroforth/tools/convert.c b/src/cmd/retroforth/tools/convert.c new file mode 100644 index 0000000..503a6ef --- /dev/null +++ b/src/cmd/retroforth/tools/convert.c @@ -0,0 +1,103 @@ +/****************************************************** + * Convert retroImage to retroImage16 and retroImage64 + * and create big endian versions of images. + ******************************************************/ + +#include +#include +#include + +int32_t input[1000000]; +int16_t output16[1000000]; +int64_t output64[1000000]; +int16_t output16BE[1000000]; +int32_t output32BE[1000000]; +int64_t output64BE[1000000]; + +#ifdef RXBE +uint32_t bitswap32(uint32_t x) +{ + return ((x << 24) & 0xff000000) | + ((x << 8) & 0x00ff0000) | + ((x << 8) & 0x0000ff00) | + ((x << 24) & 0x000000ff); +} +#endif + +int load_image(char *image) +{ + FILE *fp; + int x; + + if ((fp = fopen(image, "rb")) == NULL) + { + fprintf(stderr, "Sorry, but I couldn't open %s\n", image); + exit(-1); + } + + x = fread(input, sizeof(int32_t), 1000000, fp); + fclose(fp); + + return x; +} + +int save_image() +{ + FILE *fp[5]; + int x[5], i; + u_int32_t image_size = input[3]; + +#ifdef RXBE + image_size = bitswap32(image_size); +#endif + + if ((fp[0] = fopen("retroImage16", "w")) == NULL) exit(-1); + if ((fp[1] = fopen("retroImage64", "w")) == NULL) exit(-1); + if ((fp[2] = fopen("retroImage16BE", "w")) == NULL) exit(-1); + if ((fp[3] = fopen("retroImageBE", "w")) == NULL) exit(-1); + if ((fp[4] = fopen("retroImage64BE", "w")) == NULL) exit(-1); + + x[0] = fwrite(output16, sizeof(int16_t), image_size, fp[0]); + x[1] = fwrite(output64, sizeof(int64_t), image_size, fp[1]); + x[2] = fwrite(output16BE, sizeof(int16_t), image_size, fp[2]); + x[3] = fwrite(output32BE, sizeof(int32_t), image_size, fp[3]); + x[4] = fwrite(output64BE, sizeof(int64_t), image_size, fp[4]); + + for (i = 0; i < 5; ++i) + fclose(fp[i]); + for (i = 0; i < 5; ++i) + if (x[i] != image_size) { + fprintf(stderr, "Some images could not be written properly (%d-%d:%d).\n", i, x[i], image_size); + exit(-1); + } + + return image_size; +} + +void convert() +{ + int i, cells; + int32_t be; + fprintf(stderr, "Loading...\n"); + cells = load_image("retroImage"); + + fprintf(stderr, "Converting...\n"); + for (i = 0; i < cells; i++) + { + be = bswap32(input[i]); + output16[i] = (int16_t)input[i]; + output64[i] = (int64_t)input[i]; + output16BE[i] = (int16_t)be; + output32BE[i] = be; + output64BE[i] = (int64_t)be; + } + + fprintf(stderr, "Saving...\n\n"); + save_image(); +} + +int main(int argc, char **argv) +{ + convert(); + return 0; +} diff --git a/src/cmd/retroforth/tools/tweakterm.c b/src/cmd/retroforth/tools/tweakterm.c new file mode 100644 index 0000000..a42417f --- /dev/null +++ b/src/cmd/retroforth/tools/tweakterm.c @@ -0,0 +1,69 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#define STDIN 0 + +int setTerm(void) +{ + struct termios t; + int fd; + char fname[1024]; + if (tcgetattr(STDIN, &t)) + return 1; + fname[0] = 0; + strncat(fname, getenv("HOME"), 1000); + strcat(fname, "/.term_settings"); + fd = open(fname, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); + if (fd == -1) + return 2; + if (write(fd, &t, sizeof(struct termios)) != sizeof(struct termios)) + return 3; + if (close(fd)) + return 4; + t.c_lflag &= ~(ICANON | ECHO | ISIG); + t.c_iflag = 0; + if (tcsetattr(STDIN, TCSANOW, &t)) + return 5; + return 0; +} + +int restoreTerm(void) +{ + struct termios t; + int fd; + char fname[1024]; + fname[0] = 0; + strncat(fname, getenv("HOME"), 1000); + strcat(fname, "/.term_settings"); + fd = open(fname, O_RDWR); + if (fd == -1) + return 2; + if (read(fd, &t, sizeof(struct termios)) != sizeof(struct termios)) + return 3; + if (close(fd)) + return 4; + if (tcsetattr(STDIN, TCSANOW, &t)) + return 5; + if (unlink(fname)) + return 6; + return 0; +} + + +int main(int argc, char **argv) +{ + if (argc < 2) + return -1; + if (strcmp(argv[1], "set") == 0) + setTerm(); + if (strcmp(argv[1], "restore") == 0) + restoreTerm(); + + return 0; +} diff --git a/src/cmd/rev.c b/src/cmd/rev.c new file mode 100644 index 0000000..0d1fd26 --- /dev/null +++ b/src/cmd/rev.c @@ -0,0 +1,46 @@ +/* + * reverse lines of a file + */ +#include +#include + +#define N 256 +char line[N]; +FILE *input; + +main(argc,argv) +char **argv; +{ + register i,c; + input = stdin; + do { + if(argc>1) { + if((input=fopen(argv[1],"r"))==NULL) { + fprintf(stderr,"rev: cannot open %s\n", + argv[1]); + exit(1); + } + } + for(;;){ + for(i=0;i=0) + putc(line[i],stdout); + putc('\n',stdout); + } +eof: + fclose(input); + argc--; + argv++; + } while(argc>1); +} diff --git a/src/cmd/rm.c b/src/cmd/rm.c new file mode 100644 index 0000000..c6d4b60 --- /dev/null +++ b/src/cmd/rm.c @@ -0,0 +1,259 @@ +/* + * rm - for ReMoving files, directories & trees. + */ +#include +#include +#include +#include +#include +#include +#include + +int fflg; /* -f force - supress error messages */ +int iflg; /* -i interrogate user on each file */ +int rflg; /* -r recurse */ + +int errcode; /* true if errors occured */ + +main(argc, argv) + char *argv[]; +{ + register char *arg; + + fflg = !isatty(0); + iflg = 0; + rflg = 0; + while (argc > 1 && argv[1][0] == '-') { + arg = *++argv; + argc--; + + /* + * all files following a null option are considered file names + */ + if (arg[1] == '\0') + break; + + while (*++arg != '\0') + switch(*arg) { + case 'f': + fflg++; + break; + + case 'i': + iflg++; + break; + + case 'R': + case 'r': + rflg++; + break; + + default: + fprintf(stderr, "usage: rm [-rif] file ...\n"); + exit(1); + } + } + + if (argc < 2 && !fflg) { + fprintf(stderr, "usage: rm [-rif] file ...\n"); + exit(1); + } + + while (--argc > 0) + (void) rm(*++argv, 0); + + exit(errcode != 0); +} + +char *path; /* pointer to malloc'ed buffer for path */ +char *pathp; /* current pointer to end of path */ +int pathsz; /* size of path */ + +/* + * Return TRUE if sucessful. Recursive with -r (rflg) + */ +rm(arg, level) + char arg[]; +{ + int ok; /* true if recursive rm succeeded */ + struct stat buf; /* for finding out what a file is */ + struct direct *dp; /* for reading a directory */ + DIR *dirp; /* for reading a directory */ + char prevname[MAXNAMLEN + 1]; /* previous name for -r */ + char *cp; + + if (dotname(arg)) { + fprintf(stderr, "rm: cannot remove `.' or `..'\n"); + return (0); + } + if (lstat(arg, &buf)) { + if (!fflg) { + fprintf(stderr, "rm: %s nonexistent\n", arg); + errcode++; + } + return (0); /* error */ + } + if ((buf.st_mode&S_IFMT) == S_IFDIR) { + if (!rflg) { + if (!fflg) { + fprintf(stderr, "rm: %s directory\n", arg); + errcode++; + } + return (0); + } + if (iflg && level != 0) { + printf("rm: remove directory %s? ", arg); + if (!yes()) + return (0); /* didn't remove everything */ + } + if (access(arg, R_OK|W_OK|X_OK) != 0) { + if (rmdir(arg) == 0) + return (1); /* salvaged: removed empty dir */ + if (!fflg) { + fprintf(stderr, "rm: %s not changed\n", arg); + errcode++; + } + return (0); /* error */ + } + if ((dirp = opendir(arg)) == NULL) { + if (!fflg) { + fprintf(stderr, "rm: cannot read %s?\n", arg); + errcode++; + } + return (0); + } + if (level == 0) + append(arg); + prevname[0] = '\0'; + while ((dp = readdir(dirp)) != NULL) { + if (dotname(dp->d_name)) { + strcpy(prevname, dp->d_name); + continue; + } + append(dp->d_name); + closedir(dirp); + ok = rm(path, level + 1); + for (cp = pathp; *--cp != '/' && cp > path; ) + ; + pathp = cp; + *cp++ = '\0'; + if ((dirp = opendir(arg)) == NULL) { + if (!fflg) { + fprintf(stderr, "rm: cannot read %s?\n", arg); + errcode++; + } + break; + } + /* pick up where we left off */ + if (prevname[0] != '\0') { + while ((dp = readdir(dirp)) != NULL && + strcmp(prevname, dp->d_name) != 0) + ; + } + /* skip the one we just failed to delete */ + if (!ok) { + dp = readdir(dirp); + if (dp != NULL && strcmp(cp, dp->d_name)) { + fprintf(stderr, + "rm: internal synchronization error: %s, %s, %s\n", + arg, cp, dp->d_name); + } + strcpy(prevname, dp->d_name); + } + } + closedir(dirp); + if (level == 0) { + pathp = path; + *pathp = '\0'; + } + if (iflg) { + printf("rm: remove %s? ", arg); + if (!yes()) + return (0); + } + if (rmdir(arg) < 0) { + if (!fflg || iflg) { + fprintf(stderr, "rm: %s not removed\n", arg); + errcode++; + } + return (0); + } + return (1); + } + + if (iflg) { + printf("rm: remove %s? ", arg); + if (!yes()) + return (0); + } else if (!fflg) { + if ((buf.st_mode&S_IFMT) != S_IFLNK && access(arg, W_OK) < 0) { + printf("rm: override protection %o for %s? ", + buf.st_mode&0777, arg); + if (!yes()) + return (0); + } + } + if (unlink(arg) < 0) { + if (!fflg || iflg) { + fprintf(stderr, "rm: %s not removed\n", arg); + errcode++; + } + return (0); + } + return (1); +} + +/* + * boolean: is it "." or ".." ? + */ +dotname(s) + char *s; +{ + if (s[0] == '.') + if (s[1] == '.') + if (s[2] == '\0') + return (1); + else + return (0); + else if (s[1] == '\0') + return (1); + return (0); +} + +/* + * Get a yes/no answer from the user. + */ +yes() +{ + int i, b; + + i = b = getchar(); + while (b != '\n' && b != EOF) + b = getchar(); + return (i == 'y'); +} + +/* + * Append 'name' to 'path'. + */ +append(name) + char *name; +{ + register int n; + + n = strlen(name); + if (path == NULL) { + pathsz = MAXNAMLEN + MAXPATHLEN + 2; + if ((path = malloc(pathsz)) == NULL) { + fprintf(stderr, "rm: ran out of memory\n"); + exit(1); + } + pathp = path; + } else if (pathp + n + 2 > path + pathsz) { + fprintf(stderr, "rm: path name too long: %s\n", path); + exit(1); + } else if (pathp != path && pathp[-1] != '/') + *pathp++ = '/'; + strcpy(pathp, name); + pathp += n; +} diff --git a/src/cmd/rmail.c b/src/cmd/rmail.c new file mode 100644 index 0000000..c67214d --- /dev/null +++ b/src/cmd/rmail.c @@ -0,0 +1,120 @@ +/* +** RMAIL -- UUCP mail server. +** +** This program reads the >From ... remote from ... lines that +** UUCP is so fond of and turns them into something reasonable. +** It calls sendmail giving it a -f option built from these +** lines. +*/ +#include +#include +#include +#include +#include +#include + +typedef char bool; +#define TRUE 1 +#define FALSE 0 + +bool Debug; + +main(argc, argv) + char **argv; +{ + FILE *out; /* output to sendmail */ + char lbuf[1024]; /* one line of the message */ + char from[512]; /* accumulated path of sender */ + char ufrom[512]; /* user on remote system */ + char sys[512]; /* a system in path */ + char junk[1024]; /* scratchpad */ + char cmd[2000]; + register char *cp; + register char *uf = ufrom; /* ptr into ufrom */ + int i; + +#ifdef DEBUG + if (argc > 1 && strcmp(argv[1], "-T") == 0) + { + Debug = TRUE; + argc--; + argv++; + } +#endif + if (argc < 2) + { + fprintf(stderr, "Usage: rmail user ...\n"); + exit(EX_USAGE); + } + + (void) strcpy(from, ""); + (void) strcpy(ufrom, "/dev/null"); + + for (;;) + { + (void) fgets(lbuf, sizeof lbuf, stdin); + if (strncmp(lbuf, "From ", 5) != 0 && strncmp(lbuf, ">From ", 6) != 0) + break; + (void) sscanf(lbuf, "%s %s", junk, ufrom); + cp = lbuf; + for (;;) + { + cp = index(cp+1, 'r'); + if (cp == NULL) + { + register char *p = rindex(uf, '!'); + + if (p != NULL) + { + *p = '\0'; + (void) strcpy(sys, uf); + uf = p + 1; + break; + } + cp = "remote from somewhere"; + } +#ifdef DEBUG + if (Debug) + printf("cp='%s'\n", cp); +#endif + if (strncmp(cp, "remote from ", 12)==0) + break; + } + if (cp != NULL) + (void) sscanf(cp, "remote from %s", sys); + (void) strcat(from, sys); + (void) strcat(from, "!"); +#ifdef DEBUG + if (Debug) + printf("ufrom='%s', sys='%s', from now '%s'\n", uf, sys, from); +#endif + } + (void) strcat(from, uf); + + (void) sprintf(cmd, "%s -ee -f%s -i", _PATH_SENDMAIL, from); + while (*++argv != NULL) + { + (void) strcat(cmd, " '"); + if (**argv == '(') + (void) strncat(cmd, *argv + 1, strlen(*argv) - 2); + else + (void) strcat(cmd, *argv); + (void) strcat(cmd, "'"); + } +#ifdef DEBUG + if (Debug) + printf("cmd='%s'\n", cmd); +#endif + out = popen(cmd, "w"); + fputs(lbuf, out); + while (fgets(lbuf, sizeof lbuf, stdin)) + fputs(lbuf, out); + i = pclose(out); + if ((i & 0377) != 0) + { + fprintf(stderr, "pclose: status 0%o\n", i); + exit(EX_OSERR); + } + + exit((i >> 8) & 0377); +} diff --git a/src/cmd/rmdir.c b/src/cmd/rmdir.c new file mode 100644 index 0000000..96db2be --- /dev/null +++ b/src/cmd/rmdir.c @@ -0,0 +1,30 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +/* + * Remove directory + */ +#include +#include + +main(argc,argv) + int argc; + char **argv; +{ + int errors = 0; + + if (argc < 2) { + fprintf(stderr, "usage: %s directory ...\n", argv[0]); + exit(1); + } + while (--argc) + if (rmdir(*++argv) < 0) { + fprintf(stderr, "rmdir: "); + perror(*argv);; + errors++; + } + exit(errors != 0); +} diff --git a/src/cmd/scm/Makefile b/src/cmd/scm/Makefile new file mode 100644 index 0000000..82ca1be --- /dev/null +++ b/src/cmd/scm/Makefile @@ -0,0 +1,35 @@ +TOPSRC = $(shell cd ../../..; pwd) +include $(TOPSRC)/target.mk +#include $(TOPSRC)/cross.mk + +CFLAGS += -Os -Wall -Werror + +OBJS = scm.o func.o +TESTS = tests/*.scm + +all: scm ${MAN} + +scm: ${OBJS} + ${CC} ${LDFLAGS} -o scm.elf ${OBJS} ${LIBS} + ${OBJDUMP} -S scm.elf > scm.dis + ${SIZE} scm.elf + ${ELF2AOUT} scm.elf $@ && rm scm.elf + +clean: + rm -f *.o scm *.elf *.dis *~ tests/*.out + +install: all + install scm $(DESTDIR)/bin/ + +tests: scm $(TESTS) ALWAYS + for i in $(TESTS); do \ + base=`basename $$i .scm`;\ + ./scm -v $$i > tests/$$base.out;\ + diff tests/$$base.expected tests/$$base.out; done + +ALWAYS: + +expected: scm $(TESTS) + for i in $(TESTS); do \ + base=`basename $$i .scm`;\ + ./scm -v $$i > tests/$$base.expected; done diff --git a/src/cmd/scm/Syntax.txt b/src/cmd/scm/Syntax.txt new file mode 100644 index 0000000..a41127c --- /dev/null +++ b/src/cmd/scm/Syntax.txt @@ -0,0 +1,75 @@ +Комментарий начинаетÑÑ Ñимволом ';' и продолжаетÑÑ Ð´Ð¾ конца Ñтроки. +Пробелы, табулÑции, переводы Ñтроки и Ñтраницы + +цифра = 0123456789 +буква = +-.*/<=>!?:$%_&^~ | abcdefghijklmnopqrstuvwxyz | + ABCDEFGHIJKLMNOPQRSTUVWXYZ | '\200'...'\377' +_______________________________ +Целое чиÑло: + [+ | -] цифра цифра... +Пример: + 1234 + +5678 + -9876 +_______________________________ +ЛогичеÑÐºÐ°Ñ ÐºÐ¾Ð½Ñтанта: + #f | #t +Пример: + #f + #t +_______________________________ +Идентификатор: + + | - | буква (буква | цифра)... +Пример: + lambda + <=? +_______________________________ +Выражение: + логичеÑкое | целое | идентификатор | 'выражение | + (выражение выражение... [. выражение]) +Пример: + 123 + 'a + (p q r) + (p q . r) +_______________________________ +Защита от выполнениÑ: + (quote expr) | 'expr +Ð’ качеÑтве Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ Ð²Ñ‹Ð´Ð°ÐµÑ‚ÑÑ Ð½ÐµÐ²Ñ‹Ñ‡Ð¸Ñленный аргумент. +Пример: + (quote (a b c)) + '(a b c)) +_______________________________ +Определение переменной: + (define var expr...) +ОпределÑетÑÑ Ð¿ÐµÑ€ÐµÐ¼ÐµÐ½Ð½Ð°Ñ Ñ Ð¸Ð¼ÐµÐ½ÐµÐ¼ var, и ее значением +ÑтановитÑÑ Ñ€ÐµÐ·ÑƒÐ»ÑŒÑ‚Ð°Ñ‚ вычиÑÐ»ÐµÐ½Ð¸Ñ Ð¿Ð¾Ñледнего из expr. +Он же выдаетÑÑ Ð² качеÑтве Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ Ð²Ñего выражениÑ. +Пример: + (define x 5) + (define f (lambda (x) (x x))) +_______________________________ +Группирование выражений: + (begin expr...) +Значение поÑледнего Ð²Ñ‹Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ ÑтановитÑÑ Ñ€ÐµÐ·ÑƒÐ»ÑŒÑ‚Ð°Ñ‚Ð¾Ð¼. +Ð’Ñе переменные, определÑемые внутри Ð²Ñ‹Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ begin, +ÑвлÑÑŽÑ‚ÑÑ Ð»Ð¾ÐºÐ°Ð»ÑŒÐ½Ñ‹Ð¼Ð¸. +Пример: + (begin (define x 5) (lambda (z) (+ z x))) +_______________________________ +Создание функции (замыканиÑ): + (lambda (arg...) expr...) +ВозвращаетÑÑ Ñ„ÑƒÐ½ÐºÑ†Ð¸Ñ Ñ Ð°Ñ€Ð³ÑƒÐ¼ÐµÐ½Ñ‚Ð°Ð¼Ð¸ arg... и телом expr... +Ð’Ñе иÑпользуемые переменные припиÑываютÑÑ Ð² момент +Ð¾Ð¿Ñ€ÐµÐ´ÐµÐ»ÐµÐ½Ð¸Ñ Ñ„ÑƒÐ½ÐºÑ†Ð¸Ð¸ (контекÑÑ‚ запоминаетÑÑ). +Пример: + (lambda (x) (cons x x)) +_______________________________ +Задание локальных определений: + (let ((var val)...) expr...) +Ð’Ñ‹Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ val вычиÑлÑÑŽÑ‚ÑÑ, затем определÑÑŽÑ‚ÑÑ Ð½Ð¾Ð²Ñ‹Ðµ +переменные var, им припиÑываютÑÑ Ð²Ñ‹Ñ‡Ð¸Ñленные значениÑ, +поÑле чего приÑходит вычиÑление expr. +Значение поÑледнего Ð²Ñ‹Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ ÑтановитÑÑ Ñ€ÐµÐ·ÑƒÐ»ÑŒÑ‚Ð°Ñ‚Ð¾Ð¼. +Пример: + (let ((x 5)) (lambda (z) (+ z x))) diff --git a/src/cmd/scm/TODO.txt b/src/cmd/scm/TODO.txt new file mode 100644 index 0000000..a39ac09 --- /dev/null +++ b/src/cmd/scm/TODO.txt @@ -0,0 +1,138 @@ +1) Floats +2) Strings +3) Vectors +4) Tail recursion +5) Garbage collection +6) Delays + +f acos +f angle +f asin +f atan + + call-with-current-continuation + call-with-input-file + call-with-output-file + call/cc + case + catch +f ceiling + char->integer + char-alphabetic? + char-ci<=? + char-ci=? + char-ci>? + char-downcase + char-lower-case? + char-numeric? + char-ready + char-ready? + char-upcase + char-upper-case? + char-whitespace? + char<=? + char=? + char>? + char? + close-input-port + close-output-port + complex? +f cos + current-input-port + current-output-port + + delay +f denominator + do + + #e + eof-object? +f exact->inexact +f exact? +f exactness +f exp + +f floor + force + + #i + imag-part +f inexact-exact +f inexact? + input-port? +f int + integer->char + +s list->string +v list->vector + load +f log + +f magnitude +f make-polar +f make-rectangular +s make-string +v make-vector + +s number->string +f numerator + + open-input-file + open-output-file + output-port? + +f polar + +f rational? +f rationalize + read-char +f real-part +f real? + return +f round + +f sin +f sqrt +s string->list +s string->number +s string->symbol +s string-append +s string-ci<=? +s string-ci=? +s string-ci>? +s string-copy +s string-fill! +s string-length +s string-ref +s string-set! +s string<=? +s string=? +s string>? +s string? +s substring +s symbol->string + +f tan + transcript-off + transcript-on + truncate + +v vector +v vector->list +v vector-fill! +v vector-length +v vector-ref +v vector-set! +v vector? + + with-input-from-file + with-output-to-file + write-char diff --git a/src/cmd/scm/examples/prime.scm b/src/cmd/scm/examples/prime.scm new file mode 100644 index 0000000..46b3df2 --- /dev/null +++ b/src/cmd/scm/examples/prime.scm @@ -0,0 +1,29 @@ +(define (square n) (* n n)) + +(define (divides? a b) + (= (remainder b a) 0)) + +(define (find-divisor n test-divisor) + (cond ((> (square test-divisor) n) n) + ((divides? test-divisor n) test-divisor) + (else (find-divisor n (+ test-divisor 1))))) + +(define (smallest-divisor n) + (find-divisor n 2)) + +(define (prime? n) + (= n (smallest-divisor n))) + +(define (t n) + (display n) + (if (prime? n) + (display '-prime) + (display '-compound)) + (newline)) + +(t 2) +(t 20) +(t 23) +(t 65) +(t 67) +(t 2011) diff --git a/src/cmd/scm/func.c b/src/cmd/scm/func.c new file mode 100644 index 0000000..9642823 --- /dev/null +++ b/src/cmd/scm/func.c @@ -0,0 +1,1009 @@ +#include "scm.h" + +#define MAXARG 64 /* макÑимальное количеÑтво аргументов функции map */ + +static long divide (long a, long b) +{ + if (a > 0) + if (b > 0) return a / b; + else return - a / (-b); + else if (b > 0) return - (-a) / b; + else return (-a) / (-b); +} + +static long gcd (long a, long b) +{ + long tmp; + + if (a < 0) + a = -a; + if (b < 0) + b = -b; + if (b > a) + tmp = a, a = b, b = tmp; + for (;;) { + if (b == 0) + return a; + if (b == 1) + return b; + b = a % (tmp = b); + a = tmp; + } +} + +static long lcm (long x, long y) +{ + long r; + + if (x == 0 || y == 0) + return (0); + r = x * y / gcd (x, y); + return (r<0 ? -r : r); +} + +static long ipow (long x, long p) +{ + long r; + + if (p == 0) + return (1); + if (p < 0 || x == 0) + return (0); + r = 1; + for (;;) { + if (p & 1) + r *= x; + if (! (p >>= 1)) + return (r); + x *= x; + } +} + +#define CXR(func,op) lisp_t func (lisp_t a, lisp_t ctx) { \ + if (! istype (a, TPAIR) || ! istype (a = car (a), TPAIR)) \ + return (NIL); return (op (a)); } + +CXR (Fcar, car) +CXR (Fcdr, cdr) + +#define CXXR(func,op1,op2) lisp_t func (lisp_t a, lisp_t ctx) { \ + if (! istype (a, TPAIR) || ! istype (a = car (a), TPAIR) || \ + ! istype (a = op1 (a), TPAIR)) return (NIL); return (op2 (a)); } + +CXXR (Fcaar, car, car) +CXXR (Fcadr, cdr, car) +CXXR (Fcdar, car, cdr) +CXXR (Fcddr, cdr, cdr) + +#define CXXXR(func,op1,op2,op3) lisp_t func (lisp_t a, lisp_t ctx) { \ + if (! istype (a, TPAIR) || ! istype (a = car (a), TPAIR) || \ + ! istype (a = op1 (a), TPAIR) || ! istype (a = op2 (a), TPAIR)) \ + return (NIL); return (op3 (a)); } + +#if 0 +CXXXR (Fcaaar, car, car, car) +CXXXR (Fcaadr, cdr, car, car) +CXXXR (Fcadar, car, cdr, car) +CXXXR (Fcaddr, cdr, cdr, car) +CXXXR (Fcdaar, car, car, cdr) +CXXXR (Fcdadr, cdr, car, cdr) +CXXXR (Fcddar, car, cdr, cdr) +CXXXR (Fcdddr, cdr, cdr, cdr) + +#define CXXXXR(func,op1,op2,op3,op4) lisp_t func (lisp_t a, lisp_t ctx) { \ + if (! istype (a, TPAIR) || ! istype (a = car (a), TPAIR) || \ + ! istype (a = op1 (a), TPAIR) || ! istype (a = op2 (a), TPAIR) || \ + ! istype (a = op3 (a), TPAIR)) return (NIL); return (op4 (a)); } + +CXXXXR (Fcaaaar, car, car, car, car) +CXXXXR (Fcaaadr, cdr, car, car, car) +CXXXXR (Fcaadar, car, cdr, car, car) +CXXXXR (Fcaaddr, cdr, cdr, car, car) +CXXXXR (Fcadaar, car, car, cdr, car) +CXXXXR (Fcadadr, cdr, car, cdr, car) +CXXXXR (Fcaddar, car, cdr, cdr, car) +CXXXXR (Fcadddr, cdr, cdr, cdr, car) +CXXXXR (Fcdaaar, car, car, car, cdr) +CXXXXR (Fcdaadr, cdr, car, car, cdr) +CXXXXR (Fcdadar, car, cdr, car, cdr) +CXXXXR (Fcdaddr, cdr, cdr, car, cdr) +CXXXXR (Fcddaar, car, car, cdr, cdr) +CXXXXR (Fcddadr, cdr, car, cdr, cdr) +CXXXXR (Fcdddar, car, cdr, cdr, cdr) +CXXXXR (Fcddddr, cdr, cdr, cdr, cdr) +#endif + +/* + * Создать новую пару из двух Ñлементов. + * (cons a (b)) ==> (a b) + */ +lisp_t Fcons (lisp_t arg, lisp_t ctx) +{ + lisp_t a; + if (! istype (arg, TPAIR)) + return (NIL); + a = car (arg); + if (! istype (arg = cdr (arg), TPAIR)) + return (NIL); + return (cons (a, car (arg))); +} + +/* + * Заменить голову ÑпиÑка. + * (set-car! pair obj) ==> pair + */ +lisp_t Fsetcar (lisp_t arg, lisp_t ctx) +{ + lisp_t a; + if (! istype (arg, TPAIR)) + return (NIL); + a = car (arg); + if (istype (arg = cdr (arg), TPAIR) && istype (a, TPAIR)) + setcar (a, car (arg)); + return (a); +} + +/* + * Заменить хвоÑÑ‚ ÑпиÑка. + * (set-cdr! pair obj) ==> pair + */ +lisp_t Fsetcdr (lisp_t arg, lisp_t ctx) +{ + lisp_t a; + if (! istype (arg, TPAIR)) + return (NIL); + a = car (arg); + if (istype (arg = cdr (arg), TPAIR) && istype (a, TPAIR)) + setcdr (a, car (arg)); + return (a); +} + +/* + * ВычиÑлить логичеÑкое отрицание. + * Выдает #t еÑли аргумент равен #f или пуÑтому ÑпиÑку. + * (not (a b c)) ==> #f + */ +lisp_t Fnot (lisp_t arg, lisp_t ctx) +{ + return (istype (arg, TPAIR) && car (arg) == NIL ? T : NIL); +} + +/* + * Сравнить Ñлементы ÑпиÑка. + * (eqv? a b) ==> #f + */ +lisp_t Feqv (lisp_t arg, lisp_t ctx) +{ + lisp_t a; + if (! istype (arg, TPAIR)) + return (T); + a = car (arg); + while (istype (arg = cdr (arg), TPAIR)) + if (! eqv (a, car (arg))) + return (NIL); + return (T); +} + +/* + * Сравнить Ñлементы ÑпиÑка рекурÑивно. + * (equal? a b) ==> #f + */ +lisp_t Fequal (lisp_t arg, lisp_t ctx) +{ + lisp_t a; + if (! istype (arg, TPAIR)) + return (T); + a = car (arg); + while (istype (arg = cdr (arg), TPAIR)) + if (! equal (a, car (arg))) + return (NIL); + return (T); +} + +/* + * ВычиÑлить Ñлементы ÑпиÑка. + * (eval a [toplevel]) ==> aval + * ЕÑли toplevel не равен NIL, вычиÑление проиÑходит + * в контекÑте верхнего уровнÑ, и оператор define + * будет добавлÑть новые переменные. + */ +lisp_t Feval (lisp_t a, lisp_t ctx) +{ + if (! istype (a, TPAIR)) + return (NIL); + return (eval (car (a), ctx == TOPLEVEL || cdr (a) != NIL ? 0 : &ctx)); +} + +lisp_t Fabs (lisp_t arg, lisp_t ctx) +{ + long sum = 0; + + while (istype (arg, TPAIR)) { + lisp_t b = car (arg); + if (istype (b, TINTEGER)) { + long v = numval (b); + if (v > 0) + sum += v; + else + sum -= v; + } + arg = cdr (arg); + } + return (number (sum)); +} + +lisp_t Fadd (lisp_t arg, lisp_t ctx) +{ + long sum = 0; + + while (istype (arg, TPAIR)) { + lisp_t v = car (arg); + if (istype (v, TINTEGER)) + sum += numval (v); + arg = cdr (arg); + } + return (number (sum)); +} + +lisp_t Fmul (lisp_t arg, lisp_t ctx) +{ + long prod = 1; + + while (istype (arg, TPAIR)) { + lisp_t v = car (arg); + if (istype (v, TINTEGER)) + prod *= numval (v); + arg = cdr (arg); + } + return (number (prod)); +} + +lisp_t Fsub (lisp_t arg, lisp_t ctx) +{ + long val; + + if (! istype (arg, TPAIR)) + return (ZERO); + val = numval (car (arg)); + if (! istype (arg = cdr (arg), TPAIR)) + return (number (-val)); + do { + lisp_t v = car (arg); + if (istype (v, TINTEGER)) + val -= numval (v); + } while (istype (arg = cdr (arg), TPAIR)); + return (number (val)); +} + +lisp_t Fdiv (lisp_t arg, lisp_t ctx) +{ + long val, p; + + if (! istype (arg, TPAIR)) + return (ZERO); + val = numval (car (arg)); + if (! istype (arg = cdr (arg), TPAIR)) + return (ZERO); + do { + lisp_t v = car (arg); + if (istype (v, TINTEGER) && (p = numval (v))) + val /= p; + } while (istype (arg = cdr (arg), TPAIR)); + return (number (val)); +} + +lisp_t Feq (lisp_t arg, lisp_t ctx) +{ + long val; + + if (! istype (arg, TPAIR)) + return (T); + val = numval (car (arg)); + while (istype (arg, TPAIR)) { + lisp_t v = car (arg); + long nval = numval (v); + if (! (istype (v, TINTEGER) && val == nval)) + return (NIL); + arg = cdr (arg); + } + return (T); +} + +#define DEFLOG(func,op) lisp_t func (lisp_t a, lisp_t ctx) { \ + long v, nv; if (! istype (a, TPAIR)) return (T); v = numval (car (a)); \ + while (istype (a = cdr (a), TPAIR)) { lisp_t b = car (a); \ + if (! istype (b, TINTEGER) || ! (v op (nv = numval (b)))) return (NIL); \ + v = nv; } return (T); } + +DEFLOG (Flt, <); +DEFLOG (Fgt, >); +DEFLOG (Fle, <=); +DEFLOG (Fge, >=); + +lisp_t Fifboolean (lisp_t arg, lisp_t ctx) +{ + while (istype (arg, TPAIR)) { + lisp_t a = car (arg); + if (a != NIL && ! istype (a, TBOOL)) + return (NIL); + arg = cdr (arg); + } + return (T); +} + +lisp_t Fifsymbol (lisp_t arg, lisp_t ctx) +{ + while (istype (arg, TPAIR)) { + lisp_t a = car (arg); + if (! istype (a, TSYMBOL)) + return (NIL); + arg = cdr (arg); + } + return (T); +} + +lisp_t Fifpair (lisp_t arg, lisp_t ctx) +{ + while (istype (arg, TPAIR)) { + lisp_t a = car (arg); + if (! istype (a, TPAIR)) + return (NIL); + arg = cdr (arg); + } + return (T); +} + +#define DEFNUMLOG(func,test) lisp_t func (lisp_t arg, lisp_t ctx) { \ + while (istype (arg, TPAIR)) { lisp_t a = car (arg); \ + if (! (istype (a, TINTEGER) test)) return (NIL); \ + arg = cdr (arg); } return (T); } + +DEFNUMLOG (Fifnumber, ) +DEFNUMLOG (Fifzero, && numval (a) == 0) +DEFNUMLOG (Fifpositive, && numval (a) > 0) +DEFNUMLOG (Fifnegative, && numval (a) < 0) +DEFNUMLOG (Fifodd, && (numval (a) & 1)) +DEFNUMLOG (Fifeven, && ! (numval (a) & 1)) + +lisp_t Fmax (lisp_t arg, lisp_t ctx) +{ + long val; + + if (! istype (arg, TPAIR)) + return (ZERO); + val = numval (car (arg)); + while (istype (arg = cdr (arg), TPAIR)) { + lisp_t b = car (arg); + if (istype (b, TINTEGER)) { + long v = numval (b); + if (v > val) + v = val; + } + } + return (number (val)); +} + +lisp_t Fmin (lisp_t arg, lisp_t ctx) +{ + long val; + + if (! istype (arg, TPAIR)) + return (ZERO); + val = numval (car (arg)); + while (istype (arg = cdr (arg), TPAIR)) { + lisp_t b = car (arg); + if (istype (b, TINTEGER)) { + long v = numval (b); + if (v < val) + v = val; + } + } + return (number (val)); +} + +lisp_t Fgcd (lisp_t arg, lisp_t ctx) +{ + long val = 0; + while (istype (arg, TPAIR)) { + lisp_t b = car (arg); + if (istype (b, TINTEGER)) + val = gcd (val, numval (b)); + arg = cdr (arg); + } + return (number (val)); +} + +lisp_t Flcm (lisp_t arg, lisp_t ctx) +{ + long val = 1; + while (istype (arg, TPAIR)) { + lisp_t b = car (arg); + if (istype (b, TINTEGER)) + val = lcm (val, numval (b)); + arg = cdr (arg); + } + return (number (val)); +} + +lisp_t Fquotient (lisp_t arg, lisp_t ctx) +{ + long a, b; + + if (! istype (arg, TPAIR) || ! istype (car (arg), TINTEGER)) + return (ZERO); + a = numval (car (arg)); + if (! istype (arg = cdr (arg), TPAIR) || + ! istype (car (arg), TINTEGER) || (b = numval (car (arg))) == 0) + return (ZERO); + return (number (divide (a, b))); +} + +lisp_t Fremainder (lisp_t arg, lisp_t ctx) +{ + long a, b; + + if (! istype (arg, TPAIR) || ! istype (car (arg), TINTEGER)) + return (ZERO); + a = numval (car (arg)); + if (! istype (arg = cdr (arg), TPAIR) || + ! istype (car (arg), TINTEGER) || (b = numval (car (arg))) == 0) + return (ZERO); + return (number (a - divide (a, b) * b)); +} + +lisp_t Fmodulo (lisp_t arg, lisp_t ctx) +{ + long a, b, r; + + if (! istype (arg, TPAIR) || ! istype (car (arg), TINTEGER)) + return (ZERO); + a = numval (car (arg)); + if (! istype (arg = cdr (arg), TPAIR) || + ! istype (car (arg), TINTEGER) || (b = numval (car (arg))) == 0) + return (ZERO); + r = a - divide (a, b) * b; + if ((b>0 && r<0) || (b<0 && r>0)) + r += b; + return (number (r)); +} + +lisp_t Fexpt (lisp_t arg, lisp_t ctx) +{ + long r = 1; + + if (istype (arg, TPAIR) && istype (car (arg), TINTEGER)) { + long a = numval (car (arg)); + if (istype (arg = cdr (arg), TPAIR) && + istype (car (arg), TINTEGER)) + r = ipow (a, numval (car (arg))); + } + return (number (r)); +} + +lisp_t Fifnull (lisp_t arg, lisp_t ctx) +{ + while (istype (arg, TPAIR)) { + lisp_t a = car (arg); + if (a != NIL) + return (NIL); + arg = cdr (arg); + } + return (T); +} + +lisp_t Fifprocedure (lisp_t arg, lisp_t ctx) +{ + while (istype (arg, TPAIR)) { + lisp_t a = car (arg); + if (! istype (a, THARDW) && ! istype (a, TCLOSURE)) + return (NIL); + arg = cdr (arg); + } + return (T); +} + +lisp_t Fiflist (lisp_t arg, lisp_t ctx) +{ + while (istype (arg, TPAIR)) { + lisp_t a = car (arg); + while (istype (a, TPAIR)) + a = cdr (a); + if (a != NIL) + return (NIL); + arg = cdr (arg); + } + return (T); +} + +lisp_t Fread (lisp_t arg, lisp_t ctx) +{ + return (getexpr ()); +} + +lisp_t Fwrite (lisp_t arg, lisp_t ctx) +{ + int first = 1; + while (istype (arg, TPAIR)) { + if (first) + first = 0; + else + putc (' ', stdout); + putexpr (car (arg), stdout); + arg = cdr (arg); + } + return (NIL); +} + +lisp_t Fnewline (lisp_t arg, lisp_t ctx) +{ + putc ('\n', stdout); + return (NIL); +} + +/* + * Выдать текущий контекÑÑ‚. + */ +lisp_t Fcontext (lisp_t arg, lisp_t ctx) +{ + return (ctx==TOPLEVEL ? NIL : ctx); +} + +/* + * Выдать контекÑÑ‚ верхнего уровнÑ. + */ +lisp_t Fgcontext (lisp_t arg, lisp_t ctx) +{ + return (ENV); +} + +lisp_t Flist (lisp_t arg, lisp_t ctx) +{ + return (copy (arg, 0)); +} + +lisp_t Fappend (lisp_t arg, lisp_t ctx) +{ + lisp_t val = NIL, tail; + while (istype (arg, TPAIR)) { + if (val == NIL) + val = copy (car (arg), &tail); + else { + lisp_t newtail; + setcdr (tail, copy (car (arg), &newtail)); + tail = newtail; + } + arg = cdr (arg); + } + return (val); +} + +lisp_t Freverse (lisp_t arg, lisp_t ctx) +{ + lisp_t val = NIL; + if (! istype (arg, TPAIR)) + return (NIL); + arg = car (arg); + while (istype (arg, TPAIR)) { + val = cons (car (arg), val); + arg = cdr (arg); + } + return (val); +} + +lisp_t Flength (lisp_t arg, lisp_t ctx) +{ + long len = 0; + if (! istype (arg, TPAIR)) + return (ZERO); + for (arg=car(arg); istype (arg, TPAIR); arg=cdr(arg)) + ++len; + return (number (len)); +} + +lisp_t Flisttail (lisp_t arg, lisp_t ctx) +{ + lisp_t l; + int k; + if (! istype (arg, TPAIR)) + return (NIL); + l = car (arg); + if (! istype (arg = cdr (arg), TPAIR) || + ! istype (arg = car (arg), TINTEGER)) + return (l); + for (k=numval(arg); k>0; --k) { + if (! istype (l, TPAIR)) + return (NIL); + l = cdr (l); + } + return (l); +} + +lisp_t Flistref (lisp_t arg, lisp_t ctx) +{ + lisp_t l; + int k; + if (! istype (arg, TPAIR)) + return (NIL); + l = car (arg); + if (! istype (l = car (arg), TPAIR)) + return (NIL); + if (! istype (arg = cdr (arg), TPAIR) || + ! istype (arg = car (arg), TINTEGER)) + return (car (l)); + for (k=numval(arg); k>0; --k) { + l = cdr (l); + if (! istype (l, TPAIR)) + return (NIL); + } + return (car (l)); +} + +lisp_t member (lisp_t o, lisp_t arg, int (*compare) (lisp_t, lisp_t)) +{ + while (istype (arg, TPAIR)) { + if ((*compare) (o, car (arg))) + return (arg); + arg = cdr (arg); + } + return (NIL); +} + +lisp_t assoc (lisp_t o, lisp_t arg, int (*compare) (lisp_t, lisp_t)) +{ + lisp_t p; + while (istype (arg, TPAIR)) { + if (istype (p = car (arg), TPAIR) && (*compare) (o, car (p))) + return (p); + arg = cdr (arg); + } + return (NIL); +} + +lisp_t Fmemv (lisp_t arg, lisp_t ctx) +{ + lisp_t o; + if (! istype (arg, TPAIR)) + return (NIL); + o = car (arg); + if (! istype (arg = cdr (arg), TPAIR)) + return (NIL); + return (member (o, car (arg), eqv)); +} + +lisp_t Fmember (lisp_t arg, lisp_t ctx) +{ + lisp_t o; + if (! istype (arg, TPAIR)) + return (NIL); + o = car (arg); + if (! istype (arg = cdr (arg), TPAIR)) + return (NIL); + return (member (o, car (arg), equal)); +} + +lisp_t Fassv (lisp_t arg, lisp_t ctx) +{ + lisp_t o; + if (! istype (arg, TPAIR)) + return (NIL); + o = car (arg); + if (! istype (arg = cdr (arg), TPAIR)) + return (NIL); + return (assoc (o, car (arg), eqv)); +} + +lisp_t Fassoc (lisp_t arg, lisp_t ctx) +{ + lisp_t o; + if (! istype (arg, TPAIR)) + return (NIL); + o = car (arg); + if (! istype (arg = cdr (arg), TPAIR)) + return (NIL); + return (assoc (o, car (arg), equal)); +} + +lisp_t Fapply (lisp_t arg, lisp_t ctx) +{ + lisp_t func; + if (! istype (arg, TPAIR)) + return (NIL); + func = car (arg); + arg = istype (arg = cdr (arg), TPAIR) ? car (arg) : NIL; + return (evalfunc (func, arg, ctx)); +} + +static lisp_t makearg (int n, lisp_t *vect) +{ + lisp_t arg = NIL, v; + int i; + + for (i=n-1; i>=0; --i) { + if (istype (vect[i], TPAIR)) { + v = car (vect[i]); + vect[i] = cdr (vect[i]); + } else + v = NIL; + arg = cons (v, arg); + } + return (arg); +} + +lisp_t Fmap (lisp_t arg, lisp_t ctx) +{ + lisp_t func, vect[MAXARG], tail, val; + int n; + + if (! istype (arg, TPAIR)) + return (NIL); + func = car (arg); + if (! istype (arg = cdr (arg), TPAIR)) + return (NIL); + + /* ÑоÑтавлÑем маÑÑив ÑпиÑков аргументов */ + for (n=0; n 0) { + void *array = malloc (k); + if (! array) + fatal ("no memory for string"); + memset (array, f, k); + mem[s].string.length = k; + mem[s].string.array = array; + } + return (s); +} + +lisp_t Fstring (lisp_t arg, lisp_t ctx) +{ + lisp_t a, s = string (0, ""); + int k = 0; + + for (a=arg; istype (a, TPAIR) && istype (car (a), TCHAR); a=cdr(a)) + ++k; + if (k > 0) { + void *array = malloc (k); + char *p = array; + if (! array) + fatal ("no memory for string"); + for (a=arg; istype (a, TPAIR) && istype (car (a), TCHAR); a=cdr(a)) + *p++ = charval (car (a)); + mem[s].string.length = k; + mem[s].string.array = array; + } + return (s); +} + +lisp_t Fstringlength (lisp_t arg, lisp_t ctx) +{ + if (! istype (arg, TPAIR) || ! istype (arg = car (arg), TSTRING)) + return (ZERO); + return (number (mem[arg].string.length)); +} + +functab_t stdfunc [] = { + { "car", Fcar }, + { "cdr", Fcdr }, + + { "caar", Fcaar }, + { "cadr", Fcadr }, + { "cdar", Fcdar }, + { "cddr", Fcddr }, +#if 0 + /* Disabled to save memory. */ + { "caaar", Fcaaar }, + { "caadr", Fcaadr }, + { "cadar", Fcadar }, + { "caddr", Fcaddr }, + { "cdaar", Fcdaar }, + { "cdadr", Fcdadr }, + { "cddar", Fcddar }, + { "cdddr", Fcdddr }, + + { "caaaar", Fcaaaar }, + { "caaadr", Fcaaadr }, + { "caadar", Fcaadar }, + { "caaddr", Fcaaddr }, + { "cadaar", Fcadaar }, + { "cadadr", Fcadadr }, + { "caddar", Fcaddar }, + { "cadddr", Fcadddr }, + { "cdaaar", Fcdaaar }, + { "cdaadr", Fcdaadr }, + { "cdadar", Fcdadar }, + { "cdaddr", Fcdaddr }, + { "cddaar", Fcddaar }, + { "cddadr", Fcddadr }, + { "cdddar", Fcdddar }, + { "cddddr", Fcddddr }, +#endif + { "cons", Fcons }, + { "set-car!", Fsetcar }, + { "set-cdr!", Fsetcdr }, + { "not", Fnot }, + { "current-environment", Fcontext }, + { "global-environment", Fgcontext }, + { "eq?", Feqv }, + { "eqv?", Feqv }, + { "equal?", Fequal }, + { "eval", Feval }, + { "boolean?", Fifboolean }, + { "symbol?", Fifsymbol }, + { "pair?", Fifpair }, + { "procedure?", Fifprocedure }, + { "null?", Fifnull }, + { "list?", Fiflist }, + { "read", Fread }, + { "write", Fwrite }, + { "display", Fwrite }, + { "newline", Fnewline }, + + { "number?", Fifnumber }, + { "integer?", Fifnumber }, + { "zero?", Fifzero }, + { "positive?", Fifpositive }, + { "negative?", Fifnegative }, + { "odd?", Fifodd }, + { "even?", Fifeven }, + { "+", Fadd }, + { "-", Fsub }, + { "*", Fmul }, + { "/", Fdiv }, + { "<", Flt }, + { ">", Fgt }, + { "<=", Fle }, + { ">=", Fge }, + { "=", Feq }, + { "max", Fmax }, + { "min", Fmin }, + { "abs", Fabs }, + { "gcd", Fgcd }, + { "lcm", Flcm }, + { "quotient", Fquotient }, + { "remainder", Fremainder }, + { "modulo", Fmodulo }, + { "expt", Fexpt }, + + { "list", Flist }, + { "length", Flength }, + { "append", Fappend }, + { "reverse", Freverse }, + { "list-tail", Flisttail }, + { "list-ref", Flistref }, + + { "memq", Fmemv }, + { "memv", Fmemv }, + { "member", Fmember }, + { "assq", Fassv }, + { "assv", Fassv }, + { "assoc", Fassoc }, + { "apply", Fapply }, + { "for-each", Fforeach }, + { "map", Fmap }, + + { "string?", Fifstring }, + { "make-string", Fmakestring }, + { "string", Fstring }, + { "string-length", Fstringlength }, +#if 0 +string-ref +string-set! + +string=? +string-ci=? +string<=? +string=? +string>? +string-ci<=? +string-ci=? +string-ci>? + +substring +string-append +string->list +list->string +string-copy +string-fill! + +number->string +string->number +string->symbol +symbol->string + +vector? +make-vector +vector +vector-length +vector-ref +vector-set! +vector->list +list->vector +vector-fill! + +char->integer +char-alphabetic? +char-ci<=? +char-ci=? +char-ci>? +char-downcase +char-lower-case? +char-numeric? +char-ready +char-ready? +char-upcase +char-upper-case? +char-whitespace? +char<=? +char=? +char>? +char? +integer->char +#endif + { 0, 0 }, +}; diff --git a/src/cmd/scm/scm.c b/src/cmd/scm/scm.c new file mode 100644 index 0000000..a108c54 --- /dev/null +++ b/src/cmd/scm/scm.c @@ -0,0 +1,1409 @@ +#include +#include + +#include "scm.h" + +/* + * Global options. + */ +int trace; /* debug trace */ +int verbose; /* verbose mode */ + +/* + * Data for lexical analyser. + */ +#define MAXLEX 128 /* max size of strings */ +#define MAXVECT 64 /* max size of vectors */ +#define MEMSZ 2500 /* memory size */ + +long lexval; /* value of numeric token */ +double lexrealval; /* value of float point token */ +char lexsym[MAXLEX]; /* name of symbol token */ +int backlexflag = 0; /* flag of unget token */ +int lexlex; /* current token */ +int lexlen; /* length of string token */ + +cell_t mem[MEMSZ]; /* list memory */ +char gclabel[MEMSZ]; /* tags for garbage collector */ +unsigned memsz = MEMSZ; /* memory size */ +lisp_t firstfree; /* list of free cells */ + +lisp_t T; /* atom T */ +lisp_t ZERO; /* atom 0 */ +lisp_t ENV; /* top level context */ + +extern functab_t stdfunc []; /* standard functions */ + +void fatal (char *s) +{ + fputs (s, stderr); + fputc ('\n', stderr); + exit (-1); +} + +/* + * Allocate memory for a new pair. + */ +lisp_t alloc (int type) +{ + lisp_t p = firstfree; + if (p == NIL) + fatal ("Out of memory"); + firstfree = cdr (firstfree); + mem[p].type = type; + return (p); +} + +int isdigitx (int c, int radix) +{ + switch (c) { + case '0': case '1': + return (1); + case '2': case '3': case '4': case '5': case '6': case '7': + return (radix > 2); + case '8': case '9': + return (radix > 8); + case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': + case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': + return (radix > 10); + } + return (0); +} + +int isletterx (int c) +{ + switch (c) { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + case '+': case '-': case '.': case '*': case '/': case '<': + case '=': case '>': case '!': case '?': case ':': case '$': + case '%': case '_': case '&': case '^': case '~': + case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': + case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': + case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': + case 's': case 't': case 'u': case 'v': case 'w': case 'x': + case 'y': case 'z': + case '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': + return (1); + } + return ((unsigned char) c >= 0200); +} + +/* + * double strtodx (char *string, char **endPtr, int radix) + * This procedure converts a floating-point number from an ASCII + * decimal representation to internal double-precision format. + * + * Original sources taken from 386bsd and modified for variable radix + * by Serge Vakulenko, . + * + * Arguments: + * string + * A decimal ASCII floating-point number, optionally preceded + * by white space. Must have form "-I.FE-X", where I is the integer + * part of the mantissa, F is the fractional part of the mantissa, + * and X is the exponent. Either of the signs may be "+", "-", or + * omitted. Either I or F may be omitted, or both. The decimal point + * isn't necessary unless F is present. The "E" may actually be an "e", + * or "E", "S", "s", "F", "f", "D", "d", "L", "l". + * E and X may both be omitted (but not just one). + * + * endPtr + * If non-NULL, store terminating character's address here. + * + * radix + * Radix of floating point, one of 2, 8, 10, 16. + * + * The return value is the double-precision floating-point + * representation of the characters in string. If endPtr isn't + * NULL, then *endPtr is filled in with the address of the + * next character after the last one that was part of the + * floating-point number. + */ +double strtodx (char *string, char **endPtr, int radix) +{ + int sign = 0, expSign = 0, fracSz, fracOff, i; + double fraction, dblExp, *powTab; + register char *p; + register char c; + + /* Exponent read from "EX" field. */ + int exp = 0; + + /* Exponent that derives from the fractional part. Under normal + * circumstances, it is the negative of the number of digits in F. + * However, if I is very long, the last digits of I get dropped + * (otherwise a long I with a large negative exponent could cause an + * unnecessary overflow on I alone). In this case, fracExp is + * incremented one for each dropped digit. */ + int fracExp = 0; + + /* Number of digits in mantissa. */ + int mantSize; + + /* Number of mantissa digits BEFORE decimal point. */ + int decPt; + + /* Temporarily holds location of exponent in string. */ + char *pExp; + + /* Largest possible base 10 exponent. + * Any exponent larger than this will already + * produce underflow or overflow, so there's + * no need to worry about additional digits. */ + static int maxExponent = 307; + + /* Table giving binary powers of 10. + * Entry is 10^2^i. Used to convert decimal + * exponents into floating-point numbers. */ + static double powersOf10[] = { + 1e1, 1e2, 1e4, 1e8, 1e16, 1e32, //1e64, 1e128, 1e256, + }; + static double powersOf2[] = { + 2, 4, 16, 256, 65536, 4.294967296e9, 1.8446744073709551616e19, + //3.4028236692093846346e38, 1.1579208923731619542e77, 1.3407807929942597099e154, + }; + static double powersOf8[] = { + 8, 64, 4096, 2.81474976710656e14, 7.9228162514264337593e28, + //6.2771017353866807638e57, 3.9402006196394479212e115, 1.5525180923007089351e231, + }; + static double powersOf16[] = { + 16, 256, 65536, 1.8446744073709551616e19, + //3.4028236692093846346e38, 1.1579208923731619542e77, 1.3407807929942597099e154, + }; + + /* + * Strip off leading blanks and check for a sign. + */ + p = string; + while (*p==' ' || *p=='\t') + ++p; + if (*p == '-') { + sign = 1; + ++p; + } else if (*p == '+') + ++p; + + /* + * Count the number of digits in the mantissa (including the decimal + * point), and also locate the decimal point. + */ + decPt = -1; + for (mantSize=0; ; ++mantSize) { + c = *p; + if (!isdigitx (c, radix)) { + if (c != '.' || decPt >= 0) + break; + decPt = mantSize; + } + ++p; + } + + /* + * Now suck up the digits in the mantissa. Use two integers to + * collect 9 digits each (this is faster than using floating-point). + * If the mantissa has more than 18 digits, ignore the extras, since + * they can't affect the value anyway. + */ + pExp = p; + p -= mantSize; + if (decPt < 0) + decPt = mantSize; + else + --mantSize; /* One of the digits was the point. */ + + switch (radix) { + default: + case 10: fracSz = 9; fracOff = 1000000000; powTab = powersOf10; break; + case 2: fracSz = 30; fracOff = 1073741824; powTab = powersOf2; break; + case 8: fracSz = 10; fracOff = 1073741824; powTab = powersOf8; break; + case 16: fracSz = 7; fracOff = 268435456; powTab = powersOf16; break; + } + if (mantSize > 2 * fracSz) + mantSize = 2 * fracSz; + fracExp = decPt - mantSize; + if (mantSize == 0) { + fraction = 0.0; + p = string; + goto done; + } else { + int frac1, frac2; + + for (frac1=0; mantSize>fracSz; --mantSize) { + c = *p++; + if (c == '.') + c = *p++; + frac1 = frac1 * radix + (c - '0'); + } + for (frac2=0; mantSize>0; --mantSize) { + c = *p++; + if (c == '.') + c = *p++; + frac2 = frac2 * radix + (c - '0'); + } + fraction = (double) fracOff * frac1 + frac2; + } + + /* + * Skim off the exponent. + */ + p = pExp; + if (*p=='E' || *p=='e' || *p=='S' || *p=='s' || *p=='F' || *p=='f' || + *p=='D' || *p=='d' || *p=='L' || *p=='l') { + ++p; + if (*p == '-') { + expSign = 1; + ++p; + } else if (*p == '+') + ++p; + while (isdigitx (*p, radix)) + exp = exp * radix + (*p++ - '0'); + } + if (expSign) + exp = fracExp - exp; + else + exp = fracExp + exp; + + /* + * Generate a floating-point number that represents the exponent. + * Do this by processing the exponent one bit at a time to combine + * many powers of 2 of 10. Then combine the exponent with the + * fraction. + */ + if (exp < 0) { + expSign = 1; + exp = -exp; + } else + expSign = 0; + if (exp > maxExponent) + exp = maxExponent; + dblExp = 1.0; + for (i=0; exp; exp>>=1, ++i) + if (exp & 01) + dblExp *= powTab[i]; + if (expSign) + fraction /= dblExp; + else + fraction *= dblExp; + +done: + if (endPtr) + *endPtr = p; + + return sign ? -fraction : fraction; +} + +/* + * Initialize a free list. + */ +void initmem () +{ + register int i; + + firstfree = NIL; + for (i=0; i=0 && r 0) + free (mem[i].string.array); + break; + case TVECTOR: + if (mem[i].vector.length > 0) + free (mem[i].vector.array); + break; + } + mem[i].type = TPAIR; + mem[i].pair.a = NIL; + mem[i].pair.d = firstfree; + firstfree = i; + ++n; + } + return (n); +} + +/* + * Garbage collection. + */ +void gc () +{ + register int n; + + if (trace) + fputs ("GC...", stderr); + glabelit (T); + glabelit (ZERO); + glabelit (ENV); + n = gcollect (); + if (trace) + fprintf (stderr, "%d OK ", n); +} + +void *memcopy (void *p, int len) +{ + assert (len > 0); + char *q = malloc (len); + if (! q) + fatal ("out of dynamic memory"); + memcpy (q, p, len); + return (q); +} + +int getoct (int c) +{ + int n = c - '0'; + c = getchar (); + if (c<='7' && c>='0') { + n = (n<<3) + c - '0'; + c = getchar (); + if (c<='7' && c>='0') + n = (n<<3) + c - '0'; + else ungetc (c, stdin); + } else ungetc (c, stdin); + return (n); +} + +int getchr () +{ + int c, n; + + switch (c = getchar ()) { + default: return (c); + case '\n': return (' '); + case '\\': break; + case 's': case 'S': + n = getchar (); + if (n!='p' && n!='P') { + ungetc (n, stdin); + return (c); + } + if (((c=getchar())=='a' || c=='A') && + ((c=getchar())=='c' || c=='C') && + ((c=getchar())=='e' || c=='E')) + return (' '); + fatal ("invalid #\\space constant"); + case 'n': case 'N': + n = getchar (); + if (n!='e' && n!='E') { + ungetc (n, stdin); + return (c); + } + if (((c=getchar())=='w' || c=='W') && + ((c=getchar())=='l' || c=='L') && + ((c=getchar())=='i' || c=='I') && + ((c=getchar())=='n' || c=='N') && + ((c=getchar())=='e' || c=='E')) + return ('\n'); + fatal ("invalid #\\newline constant"); + } + switch (c = getchar ()) { + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + return (getoct (c)); + case '\n': return (' '); + case 'n': return ('\n'); + case 't': return ('\t'); + case 'r': return ('\r'); + case 'b': return ('\b'); + case 'f': return ('\f'); + } + return (c); +} + +void putchr (int c, FILE *fd) +{ + fputs ("#\\", fd); + switch (c) { + case ' ': fputs ("space", fd); return; + case '\n': fputs ("newline", fd); return; + case '\t': fputs ("\\t", fd); return; + case '\r': fputs ("\\r", fd); return; + case '\b': fputs ("\\b", fd); return; + case '\f': fputs ("\\f", fd); return; + } + if (c<' ' || c==177) + fprintf (fd, "\\%03o", c); + else + putc (c, fd); +} + +void putstring (lisp_t p, FILE *fd) +{ + int len; + char *s; + + assert (p>=0 && p= 0) { + static char mask[] = "\"\\\n\t\r\b\f", repl[] = "\"\\ntrbf"; + unsigned char c = *s++; + char *p = strchr (mask, c); + if (c && p) { + putc ('\\', fd); + putc (repl[p-mask], fd); + } else if (c<' ' || c==177) + fprintf (fd, "\\%03o", c); + else + putc (c, fd); + } + putc ('"', fd); +} + +void putvector (lisp_t p, FILE *fd) +{ + int len; + lisp_t *s; + + assert (p>=0 && p= 0) { + putexpr (*s++, fd); + if (len) + putc (' ', fd); + } + putc (')', fd); +} + +void putatom (lisp_t p, FILE *fd) +{ + if (p == NIL) { + fputs ("()", fd); + return; + } + switch (mem[p].type) { + case TSYMBOL: fputs (symname (p), fd); break; + case TBOOL: fputs ("#t", fd); break; + case TINTEGER: fprintf (fd, "%ld", numval (p)); break; + case TREAL: fprintf (fd, "%#g", realval (p)); break; + case TSTRING: putstring (p, fd); break; + case TVECTOR: putvector (p, fd); break; + case TCHAR: putchr (charval (p), fd); break; + case THARDW: fprintf (fd, "", (unsigned) hardwval (p)); break; + case TCLOSURE: fprintf (fd, "", (unsigned) p); break; + default: fputs ("", fd); break; + } +} + +void putlist (lisp_t p, FILE *fd) +{ + int first = 1; + while (istype (p, TPAIR)) { + if (first) + first = 0; + else + putc (' ', fd); + putexpr (car (p), fd); + p = cdr (p); + } + if (p != NIL) { + fputs (" . ", fd); + putatom (p, fd); + } +} + +void putexpr (lisp_t p, FILE *fd) +{ + lisp_t h, a; + + if (! istype (p, TPAIR)) { + putatom (p, fd); + return; + } + if (istype (h = car (p), TSYMBOL) && + istype (a = cdr (p), TPAIR) && + cdr (a) == NIL) { + char *funcname = symname (h); + if (!strcmp (funcname, "quote")) { + putc ('\'', fd); + putexpr (car (a), fd); + return; + } + if (!strcmp (funcname, "quasiquote")) { + putc ('`', fd); + putexpr (car (a), fd); + return; + } + if (!strcmp (funcname, "unquote")) { + putc (',', fd); + putexpr (car (a), fd); + return; + } + if (!strcmp (funcname, "unquote-splicing")) { + putc (',', fd); + putc ('@', fd); + putexpr (car (a), fd); + return; + } + } + putc ('(', fd); + putlist (p, fd); + putc (')', fd); +} + +void ungetlex () +{ + backlexflag = 1; +} + +/* + * Lexical parser: get next token. + * Side effect: saving values to lexval and lexsym. + */ +int getlex () +{ + register int c, i, radix = 10, neg = 0; + + if (backlexflag) { + backlexflag = 0; + return (lexlex); + } +loop: + switch (c = getchar ()) { + case EOF: + return (0); + case ';': + while ((c = getchar ()) >= 0 && c!='\n') + continue; + case ' ': case '\t': case '\f': case '\n': case '\r': + goto loop; + case '"': + lexlen = 0; + while ((c = getchar ()) >= 0 && c!='"') { + if (c == '\\') { + c = getchar (); + if (c < 0) + break; + switch (c) { + case '\n': continue; + case 'n': c = '\n'; break; + case 't': c = '\t'; break; + case 'r': c = '\r'; break; + case 'b': c = '\b'; break; + case 'f': c = '\f'; break; + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + c = getoct (c); + break; + } + } + lexsym[lexlen++] = c; + } + return (lexlex = TSTRING); + case '#': + c = getchar (); + switch (c) { + default: ungetc (c, stdin); return (lexlex = '#'); + case '(': return (lexlex = TVECTOR); + case '\\': lexval = getchr (); return (lexlex = TCHAR); + case 't': case 'T': lexval = 1; return (lexlex = TBOOL); + case 'f': case 'F': lexval = 0; return (lexlex = TBOOL); + case 'b': case 'B': radix = 2; break; + case 'o': case 'O': radix = 8; break; + case 'd': case 'D': radix = 10; break; + case 'x': case 'X': radix = 16; break; + } + c = getchar (); + if (! isdigitx (c, radix) && c!='-' && c!='+' && c!='.') { + ungetc (c, stdin); + lexval = 0; + return (lexlex = TINTEGER); + } + break; + } + if (c=='-' || c=='+') { + lexsym[0] = c; + c = getchar (); + if (! isdigitx (c, radix)) { + ungetc (c, stdin); + c = lexsym[0]; + goto lexsym; + } + neg = (lexsym[0] == '-'); + } + if (isdigitx (c, radix) || c=='.') { + i = 0; + while (i < MAXLEX-1 && c>=0 && isdigitx (c, radix)) { + lexsym[i++] = c; + c = getchar (); + } + if ((c=='.' || c=='E' || c=='e' || c=='S' || + c=='s' || c=='F' || c=='f' || c=='D' || + c=='d' || c=='L' || c=='l') && i=0 && isdigitx (c, radix)) { + lexsym[i++] = c; + c = getchar (); + } + } + if ((c=='E' || c=='e' || c=='S' || c=='s' || + c=='F' || c=='f' || c=='D' || c=='d' || + c=='L' || c=='l') && i=0 && isdigitx (c, radix)) { + lexsym[i++] = c; + c = getchar (); + } + } + if (c >= 0) + ungetc (c, stdin); + lexsym[i] = 0; + lexrealval = strtodx (lexsym, 0, radix); + if (neg) + lexrealval = -lexrealval; + return (lexlex = TREAL); + } + if (c >= 0) + ungetc (c, stdin); + lexsym[i] = 0; + lexval = strtol (lexsym, 0, radix); + if (neg) + lexval = -lexval; + return (lexlex = TINTEGER); + } + if (isletterx (c)) { +lexsym: i = 0; + while (i < MAXLEX-1) { + lexsym[i++] = c; + c = getchar (); + if (c < 0) + break; + if (! isletterx (c)) { + ungetc (c, stdin); + break; + } + } + if (i == 1 && lexsym[0] == '.') + return (lexlex = '.'); + lexsym[i] = 0; + return (lexlex = TSYMBOL); + } + return (lexlex = c); +} + +/* + * Read vector EXPR... + */ +lisp_t getvector () +{ + int len = 0; + lisp_t vect[MAXVECT]; + + for (;;) { + switch (getlex ()) { + case ')': + ungetlex (); + return (vector (len, vect)); + default: + if (len >= MAXVECT) + fatal ("too long vector constant"); + ungetlex (); + vect[len++] = getexpr (); + continue; + case 0: + fatal ("unexpected eof"); + } + } +} + +/* + * Read list EXPR ('.' LIST | EXPR)... + */ +lisp_t getlist () +{ + lisp_t p = cons (getexpr (), NIL); + switch (getlex ()) { + case '.': + setcdr (p, getexpr ()); + break; + case ')': + ungetlex (); + break; + default: + ungetlex (); + setcdr (p, getlist ()); + break; + case 0: + fatal ("unexpected eof"); + } + return (p); +} + +/* + * Read expression ATOM | NUMBER | '(' LIST ')' + */ +lisp_t getexpr () +{ + lisp_t p; + + switch (getlex ()) { + default: + fatal ("syntax error"); + case ')': + ungetlex (); + case 0: + return (NIL); + case '(': + if (getlex () == ')') + return (NIL); + ungetlex (); + p = getlist (); + if (getlex () != ')') + fatal ("right parence expected"); + break; + case '\'': + p = cons (symbol ("quote"), cons (getexpr (), NIL)); + break; + case '`': + p = cons (symbol ("quasiquote"), cons (getexpr (), NIL)); + break; + case ',': + if (getlex () == '@') + p = cons (symbol ("unquote-splicing"), cons (getexpr (), NIL)); + else { + ungetlex (); + p = cons (symbol ("unquote"), cons (getexpr (), NIL)); + } + break; + case TSYMBOL: + p = symbol (lexsym); + if (trace > 2) + fprintf (stderr, "%s\n", lexsym); + break; + case TBOOL: + p = lexval ? T : NIL; + if (trace > 2) + fprintf (stderr, "#%c\n", lexval ? 't' : 'f'); + break; + case TCHAR: + p = character (lexval); + if (trace > 2) + fprintf (stderr, "#\\\\%03o\n", (unsigned) lexval); + break; + case TINTEGER: + p = number (lexval); + if (trace > 2) + fprintf (stderr, "%ld\n", lexval); + break; + case TREAL: + p = real (lexrealval); + if (trace > 2) + fprintf (stderr, "%#g\n", lexrealval); + break; + case TSTRING: + p = string (lexlen, lexsym); + if (trace > 2) { + putstring (p, stderr); + fprintf (stderr, "\n"); + } + break; + case TVECTOR: + p = getvector (); + if (getlex () != ')') + fatal ("right parence expected"); + break; + } + return (p); +} + +lisp_t copy (lisp_t a, lisp_t *t) +{ + lisp_t val, tail; + if (! istype (a, TPAIR)) + return (NIL); + tail = val = cons (NIL, NIL); + for (;;) { + setcar (tail, car (a)); + if (! istype (a = cdr (a), TPAIR)) + break; + setcdr (tail, cons (NIL, NIL)); + tail = cdr (tail); + } + if (t) + *t = tail; + return (val); +} + +/* + * Compare vectors. + */ +int eqvvector (lisp_t a, lisp_t b) +{ + lisp_t *s, *t; + int len; + + assert (a>=0 && a=0 && b= 0) + if (! eqv (*s++, *t++)) + return (0); + return (1); +} + +/* + * Compare objects. + */ +int eqv (lisp_t a, lisp_t b) +{ + if (a == b) + return (1); + if (a == NIL || b == NIL) + return (0); + assert (a>=0 && a=0 && b=0 && p quasiquote unquote unquote-splicing + */ + /* Reserved names: + * delay do case + */ + func = car (expr); + if (istype (func, TSYMBOL)) { + char *funcname = symname (func); + if (!strcmp (funcname, "quote")) { + if (! istype (expr = cdr (expr), TPAIR)) + return (NIL); + return (car (expr)); + } + if (!strcmp (funcname, "define")) { + lisp_t value, atom, pair, arg = 0; + int lambda; + if (! istype (expr = cdr (expr), TPAIR)) + return (NIL); + lambda = istype (atom = car (expr), TPAIR); + if (lambda) { + /* define, combined with lambda. */ + arg = cdr (atom); + atom = car (atom); + } + if (! istype (atom, TSYMBOL) || + ! istype (expr = cdr (expr), TPAIR)) + return (NIL); + pair = findatom (atom, ctx); + if (pair == NIL) { + /* Extend the context. */ + pair = cons (atom, NIL); + if (ctxp) { + /* Local context. */ + *ctxp = ctx = cons (pair, ctx); + } else { + /* Upper level context. */ + ENV = cons (pair, ENV); + } + } + if (lambda) + value = closure (cons (arg, expr), ctx); + else + value = evalblock (expr, ctx); + setcdr (pair, value); + return (value); + } + if (!strcmp (funcname, "set!")) { + lisp_t value = NIL; + if (! istype (expr = cdr (expr), TPAIR)) + return (NIL); + if (istype (cdr (expr), TPAIR)) + value = evalblock (cdr (expr), ctx); + setatom (car (expr), value, ctx); + return (value); + } + if (!strcmp (funcname, "begin")) + return (evalblock (cdr (expr), ctx)); + if (!strcmp (funcname, "lambda")) { + lisp_t arg = NIL; + if (istype (expr = cdr (expr), TPAIR)) { + arg = car (expr); + if (! istype (expr = cdr (expr), TPAIR)) + expr = NIL; + } + return (closure (cons (arg, expr), ctx)); + } + if (!strcmp (funcname, "let")) { + lisp_t arg = NIL, oldctx = ctx; + if (istype (expr = cdr (expr), TPAIR)) { + arg = car (expr); + if (! istype (expr = cdr (expr), TPAIR)) + expr = NIL; + } + /* Extend the context by new variables. */ + while (istype (arg, TPAIR)) { + lisp_t var = car (arg); + arg = cdr (arg); + /* Compute values in old context. */ + if (istype (var, TPAIR)) + ctx = cons (cons (car (var), + evalblock (cdr (var), oldctx)), + ctx); + else if (istype (var, TSYMBOL)) + ctx = cons (cons (var, NIL), ctx); + } + return (evalblock (expr, ctx)); + } + if (!strcmp (funcname, "let*")) { + lisp_t arg = NIL; + if (istype (expr = cdr (expr), TPAIR)) { + arg = car (expr); + if (! istype (expr = cdr (expr), TPAIR)) + expr = NIL; + } + /* Extend the context by new variables. */ + while (istype (arg, TPAIR)) { + lisp_t var = car (arg); + arg = cdr (arg); + /* Compute values in the current context. */ + if (istype (var, TPAIR)) + ctx = cons (cons (car (var), + evalblock (cdr (var), ctx)), + ctx); + else if (istype (var, TSYMBOL)) + ctx = cons (cons (var, NIL), ctx); + } + return (evalblock (expr, ctx)); + } + if (!strcmp (funcname, "letrec")) { + lisp_t arg = NIL, a; + if (istype (expr = cdr (expr), TPAIR)) { + arg = car (expr); + if (! istype (expr = cdr (expr), TPAIR)) + expr = NIL; + } + /* Extend the context by new variables with NIL values.. */ + for (a=arg; istype (a, TPAIR); a=cdr(a)) { + lisp_t var = car (a); + if (istype (var, TPAIR)) + ctx = cons (cons (car (var), NIL), ctx); + else if (istype (var, TSYMBOL)) + ctx = cons (cons (var, NIL), ctx); + } + /* Compute values in the new context. */ + for (a=arg; istype (a, TPAIR); a=cdr(a)) { + lisp_t var = car (a); + if (istype (var, TPAIR)) + setatom (car (var), + evalblock (cdr (var), ctx), + ctx); + } + return (evalblock (expr, ctx)); + } + if (!strcmp (funcname, "if")) { + lisp_t iftrue = NIL, iffalse = NIL, test; + if (! istype (expr = cdr (expr), TPAIR)) + return (NIL); + test = car (expr); + if (istype (expr = cdr (expr), TPAIR)) { + iftrue = car (expr); + iffalse = cdr (expr); + } + if (eval (test, &ctx) != NIL) + return (eval (iftrue, &ctx)); + return (evalblock (iffalse, ctx)); + } + if (!strcmp (funcname, "and")) { + while (istype (expr = cdr (expr), TPAIR)) + if (eval (car (expr), &ctx) == NIL) + return (NIL); + return (T); + } + if (!strcmp (funcname, "or")) { + while (istype (expr = cdr (expr), TPAIR)) + if (eval (car (expr), &ctx) == NIL) + return (T); + return (NIL); + } + if (!strcmp (funcname, "cond")) { + lisp_t oldctx = ctx, test, clause; + while (istype (expr = cdr (expr), TPAIR)) { + if (! istype (clause = car (expr), TPAIR)) + continue; + ctx = oldctx; + if (istype (car (clause), TSYMBOL) && + ! strcmp (symname (car (clause)), "else")) + return (evalblock (cdr (clause), ctx)); + test = eval (car (clause), &ctx); + if (test == NIL || + ! istype (clause = cdr (clause), TPAIR)) + continue; + if (istype (car (clause), TSYMBOL) && + ! strcmp (symname (car (clause)), "=>")) { + clause = evalblock (cdr (clause), ctx); + if (istype (clause, THARDW)) + return ((*hardwval (clause)) (cons (test, NIL), ctx)); + if (istype (clause, TCLOSURE)) + return (evalclosure (clause, cons (test, NIL))); + return (NIL); + } + return (evalblock (clause, ctx)); + } + return (NIL); + } + if (!strcmp (funcname, "quasiquote")) { + if (! istype (expr = cdr (expr), TPAIR)) + return (NIL); + return (quasiquote (car (expr), ctx, 0)); + } + if (!strcmp (funcname, "unquote") || + !strcmp (funcname, "unquote-splicing")) { + if (! istype (expr = cdr (expr), TPAIR)) + return (NIL); + expr = car (expr); + goto again; + } + } + + /* Compute all arguments. */ + expr = evallist (expr, ctx); + return (evalfunc (car (expr), cdr (expr), ctxp ? *ctxp : TOPLEVEL)); +} + +void initcontext (functab_t *p) +{ + for (; p->name; ++p) + ENV = cons (cons (symbol (p->name), hardw (p->func)), ENV); +} + +int main (int argc, char **argv) +{ + lisp_t expr, val; + char *progname, *prog = 0; + + progname = *argv++; + for (--argc; argc>0 && **argv=='-'; --argc, ++argv) { + char *p; + + for (p=1+*argv; *p; ++p) switch (*p) { + case 'h': + fprintf (stderr, "Usage: %s [-h] [-v] [-t] prog [arg...]\n", + progname); + return (0); + case 't': + ++trace; + break; + case 'v': + ++verbose; + break; + } + } + if (argc > 0) { + prog = *argv++; + --argc; + } + + if (verbose) { + fprintf (stderr, "Micro Scheme Interpreter, Release 1.0\n"); + fprintf (stderr, "Memory size = %lu bytes\n", + (unsigned long) memsz * sizeof (cell_t)); + } + + if (prog && freopen (prog, "r", stdin) != stdin) { + fprintf (stderr, "Cannot open %s\n", prog); + return (-1); + } + + initmem (); + T = alloc (TBOOL); /* boolean true #t */ + ZERO = number (0); /* integer zero */ + ENV = cons (cons (symbol ("version"), number (10)), NIL); + initcontext (stdfunc); + for (;;) { + gc (); + if (isatty (0)) + printf ("> "); + expr = getexpr (); + if (feof (stdin)) + break; + val = eval (expr, 0); + if (verbose) { + putexpr (expr, stdout); + printf (" --> "); + putexpr (val, stdout); + putchar ('\n'); + } + } + return (0); +} diff --git a/src/cmd/scm/scm.h b/src/cmd/scm/scm.h new file mode 100644 index 0000000..2837240 --- /dev/null +++ b/src/cmd/scm/scm.h @@ -0,0 +1,230 @@ +#ifdef CROSS +# include +#else +# include +#endif +#include +#include + +#ifdef DEBUG +# define assert(x) { if (! (x)) {\ + fprintf (stderr, "assertion failed: file \"%s\", line %d\n",\ + __FILE__, __LINE__); exit (-1); } } +#else +# define assert(x) +#endif +#define INLINE static inline __attribute__((always_inline)) + +/* + * Type tags. + */ +#define TPAIR 1 /* tag "pair" */ +#define TSYMBOL 2 /* tag "symbol" */ +#define TBOOL 3 /* tag "boolean" */ +#define TCHAR 4 /* tag "character" */ +#define TINTEGER 5 /* tag "integer" */ +#define TREAL 6 /* tag "real" */ +#define TSTRING 7 /* tag "string" */ +#define TVECTOR 8 /* tag "vector" */ +#define THARDW 9 /* tag "hard-wired function" */ +#define TCLOSURE 10 /* tag "closure" */ + +#define NIL 0xffffff /* empty list */ +#define TOPLEVEL 0xfffffe /* top level context */ + +typedef unsigned lisp_t; /* address of a cell */ +typedef lisp_t (*func_t) (lisp_t, lisp_t); /* pointer to hardwired function */ + +typedef union { /* elementary cell, two words */ + unsigned type : 8; /* type */ + struct { /* pair */ + unsigned type : 8; /* type */ + unsigned a : 24; /* first element */ + size_t d; /* second element - should be... */ + } pair; /* ...large enough to keep a pointer */ + struct { /* string */ + unsigned type : 8; /* type */ + unsigned length : 24; /* length */ + char *array; /* array of bytes */ + } string; + struct { /* vector */ + unsigned type : 8; /* type */ + unsigned length : 24; /* length */ + lisp_t *array; /* array of elements */ + } vector; + struct { /* vector */ + unsigned type : 8; /* type */ + char *name; /* c string pointer */ + } symbol; + struct { /* vector */ + unsigned type : 8; /* type */ + unsigned value; /* character */ + } chr; + struct { /* vector */ + unsigned type : 8; /* type */ + long value; /* integer number, hardwired function */ + } integer; + struct { /* vector */ + unsigned type : 8; /* type */ + double value; /* real number */ + } real; +} cell_t; + +typedef struct { + char *name; + func_t func; +} functab_t; + +extern lisp_t T, ZERO, ENV; + +int eqv (lisp_t a, lisp_t b); /* compare objects */ +int equal (lisp_t a, lisp_t b); /* recursive comparison */ +lisp_t evalblock (lisp_t expr, lisp_t ctx); /* evaluation of a block */ +lisp_t evalclosure (lisp_t func, lisp_t expr); /* evaluation of a closure */ +lisp_t evalfunc (lisp_t func, lisp_t arg, lisp_t ctx); /* evaluation of a function */ +lisp_t eval (lisp_t expr, lisp_t *ctxp); /* evaluation */ +lisp_t getexpr (); /* read expression */ +void putexpr (lisp_t p, FILE *fd); /* print expression */ +lisp_t copy (lisp_t a, lisp_t *t); /* copy expression */ +lisp_t alloc (int type); /* allocate a cell */ +void fatal (char*); /* fatal error */ +int istype (lisp_t p, int type); /* check object type */ + +extern cell_t mem[]; /* main storage for cells */ +extern unsigned memsz; /* size of storage */ +extern void *memcopy (void*, int); + +INLINE lisp_t car (lisp_t p) /* get first element of a pair */ +{ + assert (p>=0 && p=0 && p=0 && p=0 && p=0 && p 0) + mem[p].string.array = memcopy (array, len); + return p; +} + +INLINE long charval (lisp_t p) /* get value of character */ +{ + assert (p>=0 && p 0) + mem[p].vector.array = memcopy (array, len * sizeof (lisp_t)); + return p; +} + +INLINE lisp_t closure (lisp_t body, lisp_t ctx) /* allocate a closure */ +{ + lisp_t p = alloc (TCLOSURE); + mem[p].pair.a = body; + mem[p].pair.d = ctx; + return p; +} + +INLINE lisp_t hardw (func_t func) /* allocate a hard-wired function */ +{ + lisp_t p = alloc (THARDW); + mem[p].integer.value = (long) func; + return p; +} + +INLINE double realval (lisp_t p) /* get value of a real number */ +{ + assert (p>=0 && p=0 && p=0 && p=0 && p=0 && p 6 +(define hypot (lambda (a b) (+ (* a a) (* b b)))) --> +(apply hypot '(3 4)) --> 25 +q 1 +w 2 +e 3 +r 4 +t 5 +y 6 +(for-each (lambda (x y) (display x y) (newline)) '(q w e r t y) '(1 2 3 4 5 6)) --> () +(map (lambda (n) (expt n n)) '(1 2 3 4 5 6)) --> (1 4 27 256 3125 46656) +(map + '(1 2 3) '(4 5 6)) --> (5 7 9) diff --git a/src/cmd/scm/tests/apply.scm b/src/cmd/scm/tests/apply.scm new file mode 100644 index 0000000..b975035 --- /dev/null +++ b/src/cmd/scm/tests/apply.scm @@ -0,0 +1,8 @@ +(apply + '(1 2 3)) +(define hypot (lambda (a b) (+ (* a a) (* b b)))) +(apply hypot '(3 4)) + +(for-each (lambda (x y) (display x y) (newline)) + '(q w e r t y) '(1 2 3 4 5 6)) +(map (lambda (n) (expt n n)) '(1 2 3 4 5 6)) +(map + '(1 2 3) '(4 5 6)) diff --git a/src/cmd/scm/tests/cxr.expected b/src/cmd/scm/tests/cxr.expected new file mode 100644 index 0000000..4df41b2 --- /dev/null +++ b/src/cmd/scm/tests/cxr.expected @@ -0,0 +1,31 @@ +(define l '((((1 2) 3 4) (5 6) 7 8) ((9 10) 11 12) (13 14) 15 16)) --> ((((1 2) 3 4) (5 6) 7 8) ((9 10) 11 12) (13 14) 15 16) +(car l) --> (((1 2) 3 4) (5 6) 7 8) +(cdr l) --> (((9 10) 11 12) (13 14) 15 16) +(caar l) --> ((1 2) 3 4) +(cadr l) --> ((9 10) 11 12) +(cdar l) --> ((5 6) 7 8) +(cddr l) --> ((13 14) 15 16) +(caaar l) --> (1 2) +(caadr l) --> (9 10) +(cadar l) --> (5 6) +(caddr l) --> (13 14) +(cdaar l) --> (3 4) +(cdadr l) --> (11 12) +(cddar l) --> (7 8) +(cdddr l) --> (15 16) +(caaaar l) --> 1 +(caaadr l) --> 9 +(caadar l) --> 5 +(caaddr l) --> 13 +(cadaar l) --> 3 +(cadadr l) --> 11 +(caddar l) --> 7 +(cadddr l) --> 15 +(cdaaar l) --> (2) +(cdaadr l) --> (10) +(cdadar l) --> (6) +(cdaddr l) --> (14) +(cddaar l) --> (4) +(cddadr l) --> (12) +(cdddar l) --> (8) +(cddddr l) --> (16) diff --git a/src/cmd/scm/tests/cxr.scm b/src/cmd/scm/tests/cxr.scm new file mode 100644 index 0000000..7b42251 --- /dev/null +++ b/src/cmd/scm/tests/cxr.scm @@ -0,0 +1,34 @@ +(define l '((((1 2) 3 4) (5 6) 7 8) ((9 10) 11 12) (13 14) 15 16)) +(car l) +(cdr l) +(caar l) +(cadr l) +(cdar l) +(cddr l) + +(caaar l) +(caadr l) +(cadar l) +(caddr l) +(cdaar l) +(cdadr l) +(cddar l) +(cdddr l) + +(caaaar l) +(caaadr l) +(caadar l) +(caaddr l) +(cadaar l) +(cadadr l) +(caddar l) +(cadddr l) + +(cdaaar l) +(cdaadr l) +(cdadar l) +(cdaddr l) +(cddaar l) +(cddadr l) +(cdddar l) +(cddddr l) diff --git a/src/cmd/scm/tests/define.expected b/src/cmd/scm/tests/define.expected new file mode 100644 index 0000000..c7939c1 --- /dev/null +++ b/src/cmd/scm/tests/define.expected @@ -0,0 +1,11 @@ +(define p (lambda () (pair 2))) --> +(define pair (lambda (x) (cons x x))) --> +(p) --> (2 . 2) +(current-environment) --> () +(pair 'z) --> (z . z) +(pair 'x) --> (x . x) +(let ((y (+ 2 3))) (pair y)) --> (5 . 5) +(define x 5) --> 5 +x --> 5 +(set! x 6) --> 6 +x --> 6 diff --git a/src/cmd/scm/tests/define.scm b/src/cmd/scm/tests/define.scm new file mode 100644 index 0000000..3fa1a0e --- /dev/null +++ b/src/cmd/scm/tests/define.scm @@ -0,0 +1,11 @@ +(define p (lambda () (pair 2))) +(define pair (lambda (x) (cons x x))) +(p) +(current-environment) +(pair 'z) +(pair 'x) +(let ((y (+ 2 3))) (pair y)) +(define x 5) +x +(set! x 6) +x diff --git a/src/cmd/scm/tests/flo.expected b/src/cmd/scm/tests/flo.expected new file mode 100644 index 0000000..79d30e7 --- /dev/null +++ b/src/cmd/scm/tests/flo.expected @@ -0,0 +1,28 @@ +123.450 --> 123.450 +-12345.0 --> -12345.0 +123.450 --> 123.450 +-1.23450e-40 --> -1.23450e-40 +1.23450e+44 --> 1.23450e+44 +-1.23450e-38 --> -1.23450e-38 +1.23450e+46 --> 1.23450e+46 +83.5781 --> 83.5781 +-5349.00 --> -5349.00 +83.5781 --> 83.5781 +-2.08043e-58 --> -2.08043e-58 +3.35762e+61 --> 3.35762e+61 +-1.33148e-56 --> -1.33148e-56 +2.14888e+63 --> 2.14888e+63 +5.25000 --> 5.25000 +-21.0000 --> -21.0000 +5.25000 --> 5.25000 +-0.00256348 --> -0.00256348 +10752.0 --> 10752.0 +-0.0102539 --> -0.0102539 +43008.0 --> 43008.0 +13398.5 --> 13398.5 +-180149984 --> -180149984 +13398.5 --> 13398.5 +-3.90353e-153 --> -3.90353e-153 +4.59888e+160 --> 4.59888e+160 +-9.99303e-151 --> -9.99303e-151 +1.17731e+163 --> 1.17731e+163 diff --git a/src/cmd/scm/tests/flo.scm b/src/cmd/scm/tests/flo.scm new file mode 100644 index 0000000..554b5e4 --- /dev/null +++ b/src/cmd/scm/tests/flo.scm @@ -0,0 +1,32 @@ +123.45 +-12345e0 +123.45 +-123.45e-42 +123.45e+42 +-12345e-42 +12345e+42 + +#o123.45 +#o-12345e0 +#o123.45 +#o-123.45e-42 +#o123.45e+42 +#o-12345e-42 +#o12345e+42 + +#b101.01 +#b-10101e0 +#b101.01 +#b-101.01e-1011 +#b101.01e+1011 +#b-10101e-1011 +#b10101e+1011 + +#xabc.de +#x-abcdee0 +#xabc.de +#x-abc.deS-42 +#xabc.deS+42 +#x-abcdeS-42 +#xabcdeS+42 + diff --git a/src/cmd/scm/tests/int.expected b/src/cmd/scm/tests/int.expected new file mode 100644 index 0000000..dfe459d --- /dev/null +++ b/src/cmd/scm/tests/int.expected @@ -0,0 +1,64 @@ +(+) --> 0 +(+ 5) --> 5 +(+ 5 6) --> 11 +(+ 5 6 7) --> 18 +(-) --> 0 +(- 5) --> -5 +(- 5 6) --> -1 +(- 5 6 7) --> -8 +(*) --> 1 +(* 5) --> 5 +(* 5 6) --> 30 +(* 5 6 7) --> 210 +(/) --> 0 +(/ 0) --> 0 +(/ 5) --> 0 +(/ 50 6) --> 8 +(/ 5000 6 7) --> 119 +(=) --> #t +(= 2) --> #t +(= 2 2 2) --> #t +(= 2 2 3) --> () +(<) --> #t +(< 2) --> #t +(< 2 3 4) --> #t +(< 2 3 3) --> () +(>) --> #t +(> 2) --> #t +(> 4 3 2) --> #t +(> 4 3 3) --> () +(<=) --> #t +(<= 2) --> #t +(<= 2 3 4) --> #t +(<= 2 3 3) --> #t +(<= 2 3 2) --> () +(>=) --> #t +(>= 2) --> #t +(>= 4 3 2) --> #t +(>= 4 3 3) --> #t +(>= 4 3 4) --> () +(abs) --> 0 +(abs -5 6) --> 11 +(abs -5 -6) --> 11 +(abs 5 6) --> 11 +(gcd 32 -36) --> 4 +(gcd) --> 0 +(lcm 32 -36) --> 288 +(lcm) --> 1 +(quotient 13 4) --> 3 +(quotient -13 4) --> -3 +(quotient 13 -4) --> -3 +(quotient -13 -4) --> 3 +(remainder 13 4) --> 1 +(remainder -13 4) --> -1 +(remainder 13 -4) --> 1 +(remainder -13 -4) --> -1 +(modulo 13 4) --> 1 +(modulo -13 4) --> 3 +(modulo 13 -4) --> -3 +(modulo -13 -4) --> -1 +(expt) --> 1 +(expt 3) --> 1 +(expt 3 5) --> 243 +(expt -3 5) --> -243 +(expt -3 -5) --> 0 diff --git a/src/cmd/scm/tests/int.scm b/src/cmd/scm/tests/int.scm new file mode 100644 index 0000000..1e0a33c --- /dev/null +++ b/src/cmd/scm/tests/int.scm @@ -0,0 +1,67 @@ +(+) +(+ 5) +(+ 5 6) +(+ 5 6 7) +(-) +(- 5) +(- 5 6) +(- 5 6 7) +(*) +(* 5) +(* 5 6) +(* 5 6 7) +(/) +(/ 0) +(/ 5) +(/ 50 6) +(/ 5000 6 7) +(=) +(= 2) +(= 2 2 2) +(= 2 2 3) +(<) +(< 2) +(< 2 3 4) +(< 2 3 3) +(>) +(> 2) +(> 4 3 2) +(> 4 3 3) +(<=) +(<= 2) +(<= 2 3 4) +(<= 2 3 3) +(<= 2 3 2) +(>=) +(>= 2) +(>= 4 3 2) +(>= 4 3 3) +(>= 4 3 4) + +(abs) +(abs -5 6) +(abs -5 -6) +(abs 5 6) +(gcd 32 -36) +(gcd) +(lcm 32 -36) +(lcm) + +(quotient 13 4) +(quotient -13 4) +(quotient 13 -4) +(quotient -13 -4) +(remainder 13 4) +(remainder -13 4) +(remainder 13 -4) +(remainder -13 -4) +(modulo 13 4) +(modulo -13 4) +(modulo 13 -4) +(modulo -13 -4) + +(expt) +(expt 3) +(expt 3 5) +(expt -3 5) +(expt -3 -5) diff --git a/src/cmd/scm/tests/list.expected b/src/cmd/scm/tests/list.expected new file mode 100644 index 0000000..57294a6 --- /dev/null +++ b/src/cmd/scm/tests/list.expected @@ -0,0 +1,20 @@ +(list) --> () +(list 1 2 3 4 5) --> (1 2 3 4 5) +(length '(1 2 3 4 5)) --> 5 +(reverse '(1 2 3 4 5)) --> (5 4 3 2 1) +(append) --> () +(append '(1) '(2 3) '() '(4 5)) --> (1 2 3 4 5) +() --> () +'() --> () +(list-ref '(1 2 3 4 5) 0) --> 1 +(list-ref '(1 2 3 4 5) 1) --> 2 +(list-ref '(1 2 3 4 5) 2) --> 3 +(list-ref '(1 2 3 4 5) 6) --> () +(list-ref '(1 2 3 4 5)) --> 1 +(list-ref) --> () +(list-tail '(1 2 3 4 5) 0) --> (1 2 3 4 5) +(list-tail '(1 2 3 4 5) 1) --> (2 3 4 5) +(list-tail '(1 2 3 4 5) 2) --> (3 4 5) +(list-tail '(1 2 3 4 5) 6) --> () +(list-tail '(1 2 3 4 5)) --> (1 2 3 4 5) +(list-tail) --> () diff --git a/src/cmd/scm/tests/list.scm b/src/cmd/scm/tests/list.scm new file mode 100644 index 0000000..cf879ae --- /dev/null +++ b/src/cmd/scm/tests/list.scm @@ -0,0 +1,20 @@ +(list) +(list 1 2 3 4 5) +(length '(1 2 3 4 5)) +(reverse '(1 2 3 4 5)) +(append) +(append '(1) '(2 3) '() '(4 5)) +() +'() +(list-ref '(1 2 3 4 5) 0) +(list-ref '(1 2 3 4 5) 1) +(list-ref '(1 2 3 4 5) 2) +(list-ref '(1 2 3 4 5) 6) +(list-ref '(1 2 3 4 5)) +(list-ref) +(list-tail '(1 2 3 4 5) 0) +(list-tail '(1 2 3 4 5) 1) +(list-tail '(1 2 3 4 5) 2) +(list-tail '(1 2 3 4 5) 6) +(list-tail '(1 2 3 4 5)) +(list-tail) diff --git a/src/cmd/scm/tests/member.expected b/src/cmd/scm/tests/member.expected new file mode 100644 index 0000000..41308c6 --- /dev/null +++ b/src/cmd/scm/tests/member.expected @@ -0,0 +1,13 @@ +(memq 'a '(a b c)) --> (a b c) +(memq 'b '(a b c)) --> (b c) +(memq 'a '(b c d)) --> () +(memq (list 'a) '(b (a) c)) --> () +(member (list 'a) '(b (a) c)) --> ((a) c) +(memv 101 '(100 101 102)) --> (101 102) +(define e '((a 1) (b 2) (c 3))) --> ((a 1) (b 2) (c 3)) +(assq 'a e) --> (a 1) +(assq 'b e) --> (b 2) +(assq 'd e) --> () +(assq (list 'a) '(((a)) ((b)) ((c)))) --> () +(assoc (list 'a) '(((a)) ((b)) ((c)))) --> ((a)) +(assv 5 '((2 3) (5 7) (11 13))) --> (5 7) diff --git a/src/cmd/scm/tests/member.scm b/src/cmd/scm/tests/member.scm new file mode 100644 index 0000000..0a8cdb1 --- /dev/null +++ b/src/cmd/scm/tests/member.scm @@ -0,0 +1,14 @@ +(memq 'a '(a b c)) +(memq 'b '(a b c)) +(memq 'a '(b c d)) +(memq (list 'a) '(b (a) c)) +(member (list 'a) '(b (a) c)) +(memv 101 '(100 101 102)) + +(define e '((a 1) (b 2) (c 3))) +(assq 'a e) +(assq 'b e) +(assq 'd e) +(assq (list 'a) '(((a)) ((b)) ((c)))) +(assoc (list 'a) '(((a)) ((b)) ((c)))) +(assv 5 '((2 3) (5 7) (11 13))) diff --git a/src/cmd/scm/tests/quote.expected b/src/cmd/scm/tests/quote.expected new file mode 100644 index 0000000..5b1c17d --- /dev/null +++ b/src/cmd/scm/tests/quote.expected @@ -0,0 +1,12 @@ +'z --> z +'z --> z +`z --> z +,'z --> z +,@'z --> z +``1 --> `1 +```1 --> ``1 +`,(+ 1 2) --> 3 +`,@(list 1 2) --> (1 2) +`(,@(list 1 2)) --> (1 2) +`(a b c ,(+ 1 2) ,@(list 3 4)) --> (a b c 3 3 4) +`(a `(b ,(+ 1 2) ,@(foo ,(+ 1 3) d) e) f) --> (a `(b ,(+ 1 2) ,@(foo 4 d) e) f) diff --git a/src/cmd/scm/tests/quote.scm b/src/cmd/scm/tests/quote.scm new file mode 100644 index 0000000..0393de0 --- /dev/null +++ b/src/cmd/scm/tests/quote.scm @@ -0,0 +1,12 @@ +'z +(quote z) +`z +,'z +,@'z +``1 +```1 +`,(+ 1 2) +`,@(list 1 2) +`(,@(list 1 2)) +`(a b c ,(+ 1 2) ,@(list 3 4)) +`(a `(b ,(+ 1 2) ,@(foo ,(+ 1 3) d) e) f) diff --git a/src/cmd/scm/tests/string.expected b/src/cmd/scm/tests/string.expected new file mode 100644 index 0000000..2750ce9 --- /dev/null +++ b/src/cmd/scm/tests/string.expected @@ -0,0 +1,20 @@ +#\a --> #\a +#\A --> #\A +#\1 --> #\1 +#\9 --> #\9 +#\( --> #\( +#\space --> #\space +#\space --> #\space +#\newline --> #\newline +#\newline --> #\newline +#\\r --> #\\r +#\\t --> #\\t +#\\b --> #\\b +#\\f --> #\\f +#\\033 --> #\\033 +"qwerty\001\002\003\004\\\"\n\r\t\b\f" --> "qwerty\001\002\003\004\\\"\n\r\t\b\f" +"Hello,\nWorld!" --> "Hello,\nWorld!" +(string? "abc") --> #t +(string? 1) --> () +(make-string 5 #\a) --> "aaaaa" +(string #\s #\c #\h #\e #\m #\e) --> "scheme" diff --git a/src/cmd/scm/tests/string.scm b/src/cmd/scm/tests/string.scm new file mode 100644 index 0000000..bc7b208 --- /dev/null +++ b/src/cmd/scm/tests/string.scm @@ -0,0 +1,21 @@ +#\a +#\A +#\1 +#\9 +#\( +#\ +#\Space +#\Newline +#\\n +#\\r +#\\t +#\\b +#\\f +#\\33 +"qwerty\1\2\3\4\\\"\n\r\t\b\f" +"Hello, +World!" +(string? "abc") +(string? 1) +(make-string 5 #\a) +(string #\s #\c #\h #\e #\m #\e) diff --git a/src/cmd/scm/tests/t.expected b/src/cmd/scm/tests/t.expected new file mode 100644 index 0000000..4dd6988 --- /dev/null +++ b/src/cmd/scm/tests/t.expected @@ -0,0 +1,20 @@ +123 --> 123 +-123 --> -123 +83 --> 83 +-83 --> -83 +1 --> 1 +23 --> 23 +-1 --> -1 +23 --> 23 +291 --> 291 +-291 --> -291 +123 --> 123 +-123 --> -123 +1.23456e+14 --> 1.23456e+14 +-1.23456e-10 --> -1.23456e-10 +(if 1 2 3) --> 2 +(if () 2 3 4) --> 4 +(cond (() 2) (() 1) (else 3)) --> 3 +(eval '(if () 'x1 'x2 'x3)) --> x3 +(define memq (lambda (obj lst) (cond ((null? lst) ()) ((eq? obj (car lst)) lst) (else (memq obj (cdr lst)))))) --> +(memq 'b '(a b c d)) --> (b c d) diff --git a/src/cmd/scm/tests/t.scm b/src/cmd/scm/tests/t.scm new file mode 100644 index 0000000..a2550ec --- /dev/null +++ b/src/cmd/scm/tests/t.scm @@ -0,0 +1,21 @@ +123 +-123 +#o123 +#o-123 +#b123 +#b-123 +#x123 +#x-123 +#d123 +#d-123 +123.456e12 +-123.456e-12 +(if 1 2 3) +(if #f 2 3 4) +(cond (#f 2) (#f 1) (else 3)) +(eval '(if #f 'x1 'x2 'x3)) +(define memq (lambda (obj lst) (cond + ((null? lst) #f) + ((eq? obj (car lst)) lst) + (else (memq obj (cdr lst))) ))) +(memq 'b '(a b c d)) diff --git a/src/cmd/sed/Makefile b/src/cmd/sed/Makefile new file mode 100644 index 0000000..7b51bfd --- /dev/null +++ b/src/cmd/sed/Makefile @@ -0,0 +1,24 @@ +TOPSRC = $(shell cd ../../..; pwd) +include $(TOPSRC)/target.mk + +CFLAGS += -Werror + +SRCS = sed0.c sed1.c +OBJS = sed0.o sed1.o + +all: sed + +sed: ${OBJS} + ${CC} ${LDFLAGS} -o sed.elf ${OBJS} ${LIBS} + ${OBJDUMP} -S sed.elf > sed.dis + ${SIZE} sed.elf + ${ELF2AOUT} sed.elf $@ && rm sed.elf + +clean: + rm -f *.o *.elf ${MAN} sed *.elf *.dis tags *~ + +install: all + install sed $(DESTDIR)/bin/ + +sed0.o: sed0.c sed.h +sed1.o: sed1.c sed.h diff --git a/src/cmd/sed/sed.h b/src/cmd/sed/sed.h new file mode 100644 index 0000000..97b081d --- /dev/null +++ b/src/cmd/sed/sed.h @@ -0,0 +1,161 @@ +/* + * sed -- stream editor + */ + +#define CBRA 1 +#define CCHR 2 +#define CDOT 4 +#define CCL 6 +#define CNL 8 +#define CDOL 10 +#define CEOF 11 +#define CKET 12 +#define CNULL 13 +#define CLNUM 14 +#define CEND 16 +#define CDONT 17 +#define CBACK 18 + +#define STAR 01 + +#define NLINES 256 +#define DEPTH 20 +#define PTRSIZE 200 +#define RESIZE 10000 +#define ABUFSIZE 20 +#define LBSIZE 4000 +#define ESIZE 256 +#define LABSIZE 50 +#define NBRA 9 + +FILE *fin; +union reptr *abuf[ABUFSIZE]; +union reptr **aptr; +char *lastre; +char ibuf[BUFSIZ]; +char *cbp; +char *ebp; +char genbuf[LBSIZE]; +char *loc1; +char *loc2; +char *locs; +char seof; +char *reend; +char *lbend; +char *hend; +char *lcomend; +union reptr *ptrend; +int eflag; +int dolflag; +int sflag; +int jflag; +int numbra; +int delflag; +long lnum; +char linebuf[LBSIZE+1]; +char holdsp[LBSIZE+1]; +char *spend; +char *hspend; +int nflag; +int gflag; +char *braelist[NBRA]; +char *braslist[NBRA]; +long tlno[NLINES]; +int nlno; +char fname[12][40]; +FILE *fcode[12]; +int nfiles; + +#define ACOM 01 +#define BCOM 020 +#define CCOM 02 +#define CDCOM 025 +#define CNCOM 022 +#define COCOM 017 +#define CPCOM 023 +#define DCOM 03 +#define ECOM 015 +#define EQCOM 013 +#define FCOM 016 +#define GCOM 027 +#define CGCOM 030 +#define HCOM 031 +#define CHCOM 032 +#define ICOM 04 +#define LCOM 05 +#define NCOM 012 +#define PCOM 010 +#define QCOM 011 +#define RCOM 06 +#define SCOM 07 +#define TCOM 021 +#define WCOM 014 +#define CWCOM 024 +#define YCOM 026 +#define XCOM 033 + +char *cp; +char *reend; +char *lbend; + +union reptr { + struct reptr1 { + char *ad1; + char *ad2; + char *re1; + char *rhs; + FILE *fcode; + char command; + char gfl; + char pfl; + char inar; + char negfl; + } A; + struct reptr2 { + char *ad1; + char *ad2; + union reptr *lb1; + char *rhs; + FILE *fcode; + char command; + char gfl; + char pfl; + char inar; + char negfl; + } B; +} ptrspace[PTRSIZE], *rep; + + +char respace[RESIZE]; + +struct label { + char asc[9]; + union reptr *chain; + union reptr *address; +} ltab[LABSIZE]; + +struct label *lab; +struct label *labend; + +int f; +int depth; + +int eargc; +char **eargv; + +extern char bittab[]; + +union reptr **cmpend[DEPTH]; +int depth; +union reptr *pending; +char *badp; +char bad; +char *compile(); +char *ycomp(); +char *address(); +char *text(); +char *compsub(); +struct label *search(); +char *gline(); +char *place(); +char compfl; diff --git a/src/cmd/sed/sed0.c b/src/cmd/sed/sed0.c new file mode 100644 index 0000000..d1785c3 --- /dev/null +++ b/src/cmd/sed/sed0.c @@ -0,0 +1,975 @@ +#include +#include +#include "sed.h" + +struct label *labtab = ltab; +char CGMES[] = "command garbled: %s\n"; +char TMMES[] = "Too much text: %s\n"; +char LTL[] = "Label too long: %s\n"; +char AD0MES[] = "No addresses allowed: %s\n"; +char AD1MES[] = "Only one address allowed: %s\n"; +char bittab[] = { + 1, + 2, + 4, + 8, + 16, + 32, + 64, + 128 + }; + +main(argc, argv) +char *argv[]; +{ + + eargc = argc; + eargv = argv; + + badp = &bad; + aptr = abuf; + lab = labtab + 1; /* 0 reserved for end-pointer */ + rep = ptrspace; + rep->A.ad1 = respace; + lbend = &linebuf[LBSIZE]; + hend = &holdsp[LBSIZE]; + lcomend = &genbuf[71]; + ptrend = &ptrspace[PTRSIZE]; + reend = &respace[RESIZE]; + labend = &labtab[LABSIZE]; + lnum = 0; + pending = 0; + depth = 0; + spend = linebuf; + hspend = holdsp; + fcode[0] = stdout; + nfiles = 1; + + if(eargc == 1) + exit(0); + + + while (--eargc > 0 && (++eargv)[0][0] == '-') + switch (eargv[0][1]) { + + case 'n': + nflag++; + continue; + + case 'f': + if(eargc-- <= 0) exit(2); + + if((fin = fopen(*++eargv, "r")) == NULL) { + fprintf(stderr, "Cannot open pattern-file: %s\n", *eargv); + exit(2); + } + + fcomp(); + fclose(fin); + continue; + + case 'e': + eflag++; + fcomp(); + eflag = 0; + continue; + + case 'g': + gflag++; + continue; + + default: + fprintf(stdout, "Unknown flag: %c\n", eargv[0][1]); + continue; + } + + + if(compfl == 0) { + eargv--; + eargc++; + eflag++; + fcomp(); + eargv++; + eargc--; + eflag = 0; + } + + if(depth) { + fprintf(stderr, "Too many {'s"); + exit(2); + } + + labtab->address = rep; + + dechain(); + +/* abort(); /*DEBUG*/ + + if(eargc <= 0) + execute((char *)NULL); + else while(--eargc >= 0) { + execute(*eargv++); + } + fclose(stdout); + exit(0); +} +fcomp() +{ + + register char *p, *op, *tp; + char *address(); + union reptr *pt, *pt1; + int i; + struct label *lpt; + + compfl = 1; + op = lastre; + + if(rline(linebuf) < 0) return; + if(*linebuf == '#') { + if(linebuf[1] == 'n') + nflag = 1; + } + else { + cp = linebuf; + goto comploop; + } + + for(;;) { + if(rline(linebuf) < 0) break; + + cp = linebuf; + +comploop: +/* fprintf(stdout, "cp: %s\n", cp); /*DEBUG*/ + while(*cp == ' ' || *cp == '\t') cp++; + if(*cp == '\0' || *cp == '#') continue; + if(*cp == ';') { + cp++; + goto comploop; + } + + p = address(rep->A.ad1); + if(p == badp) { + fprintf(stderr, CGMES, linebuf); + exit(2); + } + + if(p == rep->A.ad1) { + if(op) + rep->A.ad1 = op; + else { + fprintf(stderr, "First RE may not be null\n"); + exit(2); + } + } else if(p == 0) { + p = rep->A.ad1; + rep->A.ad1 = 0; + } else { + op = rep->A.ad1; + if(*cp == ',' || *cp == ';') { + cp++; + if((rep->A.ad2 = p) > reend) { + fprintf(stderr, TMMES, linebuf); + exit(2); + } + p = address(rep->A.ad2); + if(p == badp || p == 0) { + fprintf(stderr, CGMES, linebuf); + exit(2); + } + if(p == rep->A.ad2) + rep->A.ad2 = op; + else + op = rep->A.ad2; + + } else + rep->A.ad2 = 0; + } + + if(p > reend) { + fprintf(stderr, "Too much text: %s\n", linebuf); + exit(2); + } + + while(*cp == ' ' || *cp == '\t') cp++; + +swit: + switch(*cp++) { + + default: + fprintf(stderr, "Unrecognized command: %s\n", linebuf); + exit(2); + + case '!': + rep->A.negfl = 1; + goto swit; + + case '{': + rep->A.command = BCOM; + rep->A.negfl = !(rep->A.negfl); + cmpend[depth++] = &rep->B.lb1; + if(++rep >= ptrend) { + fprintf(stderr, "Too many commands: %s\n", linebuf); + exit(2); + } + rep->A.ad1 = p; + if(*cp == '\0') continue; + + goto comploop; + + case '}': + if(rep->A.ad1) { + fprintf(stderr, AD0MES, linebuf); + exit(2); + } + + if(--depth < 0) { + fprintf(stderr, "Too many }'s\n"); + exit(2); + } + *cmpend[depth] = rep; + + rep->A.ad1 = p; + continue; + + case '=': + rep->A.command = EQCOM; + if(rep->A.ad2) { + fprintf(stderr, AD1MES, linebuf); + exit(2); + } + break; + + case ':': + if(rep->A.ad1) { + fprintf(stderr, AD0MES, linebuf); + exit(2); + } + + while(*cp++ == ' '); + cp--; + + + tp = lab->asc; + while((*tp++ = *cp++)) + if(tp >= &(lab->asc[8])) { + fprintf(stderr, LTL, linebuf); + exit(2); + } + *--tp = '\0'; + + if(lpt = search(lab)) { + if(lpt->address) { + fprintf(stderr, "Duplicate labels: %s\n", linebuf); + exit(2); + } + } else { + lab->chain = 0; + lpt = lab; + if(++lab >= labend) { + fprintf(stderr, "Too many labels: %s\n", linebuf); + exit(2); + } + } + lpt->address = rep; + rep->A.ad1 = p; + + continue; + + case 'a': + rep->A.command = ACOM; + if(rep->A.ad2) { + fprintf(stderr, AD1MES, linebuf); + exit(2); + } + if(*cp == '\\') cp++; + if(*cp++ != '\n') { + fprintf(stderr, CGMES, linebuf); + exit(2); + } + rep->A.re1 = p; + p = text(rep->A.re1); + break; + case 'c': + rep->A.command = CCOM; + if(*cp == '\\') cp++; + if(*cp++ != ('\n')) { + fprintf(stderr, CGMES, linebuf); + exit(2); + } + rep->A.re1 = p; + p = text(rep->A.re1); + break; + case 'i': + rep->A.command = ICOM; + if(rep->A.ad2) { + fprintf(stderr, AD1MES, linebuf); + exit(2); + } + if(*cp == '\\') cp++; + if(*cp++ != ('\n')) { + fprintf(stderr, CGMES, linebuf); + exit(2); + } + rep->A.re1 = p; + p = text(rep->A.re1); + break; + + case 'g': + rep->A.command = GCOM; + break; + + case 'G': + rep->A.command = CGCOM; + break; + + case 'h': + rep->A.command = HCOM; + break; + + case 'H': + rep->A.command = CHCOM; + break; + + case 't': + rep->A.command = TCOM; + goto jtcommon; + + case 'b': + rep->A.command = BCOM; +jtcommon: + while(*cp++ == ' '); + cp--; + + if(*cp == '\0') { + if(pt = labtab->chain) { + while(pt1 = pt->B.lb1) + pt = pt1; + pt->B.lb1 = rep; + } else + labtab->chain = rep; + break; + } + tp = lab->asc; + while((*tp++ = *cp++)) + if(tp >= &(lab->asc[8])) { + fprintf(stderr, LTL, linebuf); + exit(2); + } + cp--; + *--tp = '\0'; + + if(lpt = search(lab)) { + if(lpt->address) { + rep->B.lb1 = lpt->address; + } else { + pt = lpt->chain; + while(pt1 = pt->B.lb1) + pt = pt1; + pt->B.lb1 = rep; + } + } else { + lab->chain = rep; + lab->address = 0; + if(++lab >= labend) { + fprintf(stderr, "Too many labels: %s\n", linebuf); + exit(2); + } + } + break; + + case 'n': + rep->A.command = NCOM; + break; + + case 'N': + rep->A.command = CNCOM; + break; + + case 'p': + rep->A.command = PCOM; + break; + + case 'P': + rep->A.command = CPCOM; + break; + + case 'r': + rep->A.command = RCOM; + if(rep->A.ad2) { + fprintf(stderr, AD1MES, linebuf); + exit(2); + } + if(*cp++ != ' ') { + fprintf(stderr, CGMES, linebuf); + exit(2); + } + rep->A.re1 = p; + p = text(rep->A.re1); + break; + + case 'd': + rep->A.command = DCOM; + break; + + case 'D': + rep->A.command = CDCOM; + rep->B.lb1 = ptrspace; + break; + + case 'q': + rep->A.command = QCOM; + if(rep->A.ad2) { + fprintf(stderr, AD1MES, linebuf); + exit(2); + } + break; + + case 'l': + rep->A.command = LCOM; + break; + + case 's': + rep->A.command = SCOM; + seof = *cp++; + rep->A.re1 = p; + p = compile(rep->A.re1); + if(p == badp) { + fprintf(stderr, CGMES, linebuf); + exit(2); + } + if(p == rep->A.re1) { + if(op) + rep->A.re1 = op; + else { + fprintf(stderr, + "First RE may not be null\n"); + exit(2); + } + } else { + op = rep->A.re1; + } + + if((rep->A.rhs = p) > reend) { + fprintf(stderr, TMMES, linebuf); + exit(2); + } + + if((p = compsub(rep->A.rhs)) == badp) { + fprintf(stderr, CGMES, linebuf); + exit(2); + } + if(*cp == 'g') { + cp++; + rep->A.gfl++; + } else if(gflag) + rep->A.gfl++; + + if(*cp == 'p') { + cp++; + rep->A.pfl = 1; + } + + if(*cp == 'P') { + cp++; + rep->A.pfl = 2; + } + + if(*cp == 'w') { + cp++; + if(*cp++ != ' ') { + fprintf(stderr, CGMES, linebuf); + exit(2); + } + if(nfiles >= 10) { + fprintf(stderr, "Too many files in w commands\n"); + exit(2); + } + + text(fname[nfiles]); + for(i = nfiles - 1; i >= 0; i--) + if(cmp(fname[nfiles],fname[i]) == 0) { + rep->A.fcode = fcode[i]; + goto done; + } + if((rep->A.fcode = fopen(fname[nfiles], "w")) == NULL) { + fprintf(stderr, "cannot open %s\n", fname[nfiles]); + exit(2); + } + fcode[nfiles++] = rep->A.fcode; + } + break; + + case 'w': + rep->A.command = WCOM; + if(*cp++ != ' ') { + fprintf(stderr, CGMES, linebuf); + exit(2); + } + if(nfiles >= 10){ + fprintf(stderr, "Too many files in w commands\n"); + exit(2); + } + + text(fname[nfiles]); + for(i = nfiles - 1; i >= 0; i--) + if(cmp(fname[nfiles], fname[i]) == 0) { + rep->A.fcode = fcode[i]; + goto done; + } + + if((rep->A.fcode = fopen(fname[nfiles], "w")) == NULL) { + fprintf(stderr, "Cannot create %s\n", fname[nfiles]); + exit(2); + } + fcode[nfiles++] = rep->A.fcode; + break; + + case 'x': + rep->A.command = XCOM; + break; + + case 'y': + rep->A.command = YCOM; + seof = *cp++; + rep->A.re1 = p; + p = ycomp(rep->A.re1); + if(p == badp) { + fprintf(stderr, CGMES, linebuf); + exit(2); + } + if(p > reend) { + fprintf(stderr, TMMES, linebuf); + exit(2); + } + break; + + } +done: + if(++rep >= ptrend) { + fprintf(stderr, "Too many commands, last: %s\n", linebuf); + exit(2); + } + + rep->A.ad1 = p; + + if(*cp++ != '\0') { + if(cp[-1] == ';') + goto comploop; + fprintf(stderr, CGMES, linebuf); + exit(2); + } + + } + rep->A.command = 0; + lastre = op; +} +char *compsub(rhsbuf) +char *rhsbuf; +{ + register char *p, *q; + + p = rhsbuf; + q = cp; + for(;;) { + if((*p = *q++) == '\\') { + *p = *q++; + if(*p > numbra + '0' && *p <= '9') + return(badp); + *p++ |= 0200; + continue; + } + if(*p == seof) { + *p++ = '\0'; + cp = q; + return(p); + } + if(*p++ == '\0') { + return(badp); + } + + } +} + +char *compile(expbuf) +char *expbuf; +{ + register c; + register char *ep, *sp; + char neg; + char *lastep, *cstart; + int cclcnt; + int closed; + char bracket[NBRA], *bracketp; + + if(*cp == seof) { + cp++; + return(expbuf); + } + + ep = expbuf; + lastep = 0; + bracketp = bracket; + closed = numbra = 0; + sp = cp; + if (*sp == '^') { + *ep++ = 1; + sp++; + } else { + *ep++ = 0; + } + for (;;) { + if (ep >= &expbuf[ESIZE]) { + cp = sp; + return(badp); + } + if((c = *sp++) == seof) { + if(bracketp != bracket) { + cp = sp; + return(badp); + } + cp = sp; + *ep++ = CEOF; + return(ep); + } + if(c != '*') + lastep = ep; + switch (c) { + + case '\\': + if((c = *sp++) == '(') { + if(numbra >= NBRA) { + cp = sp; + return(badp); + } + *bracketp++ = numbra; + *ep++ = CBRA; + *ep++ = numbra++; + continue; + } + if(c == ')') { + if(bracketp <= bracket) { + cp = sp; + return(badp); + } + *ep++ = CKET; + *ep++ = *--bracketp; + closed++; + continue; + } + + if(c >= '1' && c <= '9') { + if((c -= '1') >= closed) + return(badp); + + *ep++ = CBACK; + *ep++ = c; + continue; + } + if(c == '\n') { + cp = sp; + return(badp); + } + if(c == 'n') { + c = '\n'; + } + goto defchar; + + case '\0': + continue; + case '\n': + cp = sp; + return(badp); + + case '.': + *ep++ = CDOT; + continue; + + case '*': + if (lastep == 0) + goto defchar; + if(*lastep == CKET) { + cp = sp; + return(badp); + } + *lastep |= STAR; + continue; + + case '$': + if (*sp != seof) + goto defchar; + *ep++ = CDOL; + continue; + + case '[': + if(&ep[17] >= &expbuf[ESIZE]) { + fprintf(stderr, "RE too long: %s\n", linebuf); + exit(2); + } + + *ep++ = CCL; + + neg = 0; + if((c = *sp++) == '^') { + neg = 1; + c = *sp++; + } + + cstart = sp; + do { + if(c == '\0') { + fprintf(stderr, CGMES, linebuf); + exit(2); + } + if (c=='-' && sp>cstart && *sp!=']') { + for (c = sp[-2]; c<*sp; c++) + ep[c>>3] |= bittab[c&07]; + } + if(c == '\\') { + switch(c = *sp++) { + case 'n': + c = '\n'; + break; + } + } + + ep[c >> 3] |= bittab[c & 07]; + } while((c = *sp++) != ']'); + + if(neg) + for(cclcnt = 0; cclcnt < 16; cclcnt++) + ep[cclcnt] ^= -1; + ep[0] &= 0376; + + ep += 16; + + continue; + + defchar: + default: + *ep++ = CCHR; + *ep++ = c; + } + } +} +rline(lbuf) +char *lbuf; +{ + register char *p, *q; + register t; + static char *saveq; + + p = lbuf - 1; + + if(eflag) { + if(eflag > 0) { + eflag = -1; + if(eargc-- <= 0) + exit(2); + q = *++eargv; + while(*++p = *q++) { + if(*p == '\\') { + if((*++p = *q++) == '\0') { + saveq = 0; + return(-1); + } else + continue; + } + if(*p == '\n') { + *p = '\0'; + saveq = q; + return(1); + } + } + saveq = 0; + return(1); + } + if((q = saveq) == 0) return(-1); + + while(*++p = *q++) { + if(*p == '\\') { + if((*++p = *q++) == '0') { + saveq = 0; + return(-1); + } else + continue; + } + if(*p == '\n') { + *p = '\0'; + saveq = q; + return(1); + } + } + saveq = 0; + return(1); + } + + while((t = getc(fin)) != EOF) { + *++p = t; + if(*p == '\\') { + t = getc(fin); + *++p = t; + } + else if(*p == '\n') { + *p = '\0'; + return(1); + } + } + *++p = '\0'; + return(-1); +} + +char *address(expbuf) +char *expbuf; +{ + register char *rcp; + long lno; + + if(*cp == '$') { + cp++; + *expbuf++ = CEND; + *expbuf++ = CEOF; + return(expbuf); + } + + if(*cp == '/') { + seof = '/'; + cp++; + return(compile(expbuf)); + } + + rcp = cp; + lno = 0; + + while(*rcp >= '0' && *rcp <= '9') + lno = lno*10 + *rcp++ - '0'; + + if(rcp > cp) { + *expbuf++ = CLNUM; + *expbuf++ = nlno; + tlno[nlno++] = lno; + if(nlno >= NLINES) { + fprintf(stderr, "Too many line numbers\n"); + exit(2); + } + *expbuf++ = CEOF; + cp = rcp; + return(expbuf); + } + return(0); +} +cmp(a, b) +char *a,*b; +{ + register char *ra, *rb; + + ra = a - 1; + rb = b - 1; + + while(*++ra == *++rb) + if(*ra == '\0') return(0); + return(1); +} + +char *text(textbuf) +char *textbuf; +{ + register char *p, *q; + + p = textbuf; + q = cp; + while(*q == '\t' || *q == ' ') q++; + for(;;) { + + if((*p = *q++) == '\\') + *p = *q++; + if(*p == '\0') { + cp = --q; + return(++p); + } + if(*p == '\n') { + while(*q == '\t' || *q == ' ') q++; + } + p++; + } +} + + +struct label *search(ptr) +struct label *ptr; +{ + struct label *rp; + + rp = labtab; + while(rp < ptr) { + if(cmp(rp->asc, ptr->asc) == 0) + return(rp); + rp++; + } + + return(0); +} + + +dechain() +{ + struct label *lptr; + union reptr *rptr, *trptr; + + for(lptr = labtab; lptr < lab; lptr++) { + + if(lptr->address == 0) { + fprintf(stderr, "Undefined label: %s\n", lptr->asc); + exit(2); + } + + if(lptr->chain) { + rptr = lptr->chain; + while(trptr = rptr->B.lb1) { + rptr->B.lb1 = lptr->address; + rptr = trptr; + } + rptr->B.lb1 = lptr->address; + } + } +} + +char *ycomp(expbuf) +char *expbuf; +{ + register char c, *ep, *tsp; + char *sp; + + ep = expbuf; + sp = cp; + for(tsp = cp; *tsp != seof; tsp++) { + if(*tsp == '\\') + tsp++; + if(*tsp == '\n') + return(badp); + } + tsp++; + + while((c = *sp++ & 0177) != seof) { + if(c == '\\' && *sp == 'n') { + sp++; + c = '\n'; + } + if((ep[c] = *tsp++) == '\\' && *tsp == 'n') { + ep[c] = '\n'; + tsp++; + } + if(ep[c] == seof || ep[c] == '\0') + return(badp); + } + if(*tsp != seof) + return(badp); + cp = ++tsp; + + for(c = 0; !(c & 0200); c++) + if(ep[c] == 0) + ep[c] = c; + + return(ep + 0200); +} diff --git a/src/cmd/sed/sed1.c b/src/cmd/sed/sed1.c new file mode 100644 index 0000000..cd15ad7 --- /dev/null +++ b/src/cmd/sed/sed1.c @@ -0,0 +1,718 @@ +#include +#include +#include "sed.h" + +char *trans[040] = { + "\\01", + "\\02", + "\\03", + "\\04", + "\\05", + "\\06", + "\\07", + "<-", + ">-", + "\n", + "\\13", + "\\14", + "\\15", + "\\16", + "\\17", + "\\20", + "\\21", + "\\22", + "\\23", + "\\24", + "\\25", + "\\26", + "\\27", + "\\30", + "\\31", + "\\32", + "\\33", + "\\34", + "\\35", + "\\36", + "\\37" +}; +char rub[] = {"\177"}; + +execute(file) +char *file; +{ + register char *p1, *p2; + register union reptr *ipc; + int c; + char *execp; + + if (file) { + if ((f = open(file, 0)) < 0) { + fprintf(stderr, "Can't open %s\n", file); + } + } else + f = 0; + + ebp = ibuf; + cbp = ibuf; + + if(pending) { + ipc = pending; + pending = 0; + goto yes; + } + + for(;;) { + if((execp = gline(linebuf)) == badp) { + close(f); + return; + } + spend = execp; + + for(ipc = ptrspace; ipc->A.command; ) { + + p1 = ipc->A.ad1; + p2 = ipc->A.ad2; + + if(p1) { + + if(ipc->A.inar) { + if(*p2 == CEND) { + p1 = 0; + } else if(*p2 == CLNUM) { + c = p2[1]; + if(lnum > tlno[c]) { + ipc->A.inar = 0; + if(ipc->A.negfl) + goto yes; + ipc++; + continue; + } + if(lnum == tlno[c]) { + ipc->A.inar = 0; + } + } else if(match(p2, 0)) { + ipc->A.inar = 0; + } + } else if(*p1 == CEND) { + if(!dolflag) { + if(ipc->A.negfl) + goto yes; + ipc++; + continue; + } + + } else if(*p1 == CLNUM) { + c = p1[1]; + if(lnum != tlno[c]) { + if(ipc->A.negfl) + goto yes; + ipc++; + continue; + } + if(p2) + ipc->A.inar = 1; + } else if(match(p1, 0)) { + if(p2) + ipc->A.inar = 1; + } else { + if(ipc->A.negfl) + goto yes; + ipc++; + continue; + } + } + + if(ipc->A.negfl) { + ipc++; + continue; + } + yes: + command(ipc); + + if(delflag) + break; + + if(jflag) { + jflag = 0; + if((ipc = ipc->B.lb1) == 0) { + ipc = ptrspace; + break; + } + } else + ipc++; + + } + if(!nflag && !delflag) { + for(p1 = linebuf; p1 < spend; p1++) + putc(*p1, stdout); + putc('\n', stdout); + } + + if(aptr > abuf) { + arout(); + } + + delflag = 0; + + } +} +match(expbuf, gf) +char *expbuf; +{ + register char *p1, *p2, c; + + if(gf) { + if(*expbuf) return(0); + p1 = linebuf; + p2 = genbuf; + while(*p1++ = *p2++); + locs = p1 = loc2; + } else { + p1 = linebuf; + locs = 0; + } + + p2 = expbuf; + if(*p2++) { + loc1 = p1; + if(*p2 == CCHR && p2[1] != *p1) + return(0); + return(advance(p1, p2)); + } + + /* fast check for first character */ + + if(*p2 == CCHR) { + c = p2[1]; + do { + if(*p1 != c) + continue; + if(advance(p1, p2)) { + loc1 = p1; + return(1); + } + } while(*p1++); + return(0); + } + + do { + if(advance(p1, p2)) { + loc1 = p1; + return(1); + } + } while(*p1++); + return(0); +} +advance(alp, aep) +char *alp, *aep; +{ + register char *lp, *ep, *curlp; + char c; + char *bbeg; + int ct; + +/*fprintf(stderr, "*lp = %c, %o\n*ep = %c, %o\n", *lp, *lp, *ep, *ep); /*DEBUG*/ + + lp = alp; + ep = aep; + for (;;) switch (*ep++) { + + case CCHR: + if (*ep++ == *lp++) + continue; + return(0); + + case CDOT: + if (*lp++) + continue; + return(0); + + case CNL: + case CDOL: + if (*lp == 0) + continue; + return(0); + + case CEOF: + loc2 = lp; + return(1); + + case CCL: + c = *lp++ & 0177; + if(ep[c>>3] & bittab[c & 07]) { + ep += 16; + continue; + } + return(0); + + case CBRA: + braslist[*ep++] = lp; + continue; + + case CKET: + braelist[*ep++] = lp; + continue; + + case CBACK: + bbeg = braslist[*ep]; + ct = braelist[*ep++] - bbeg; + + if(ecmp(bbeg, lp, ct)) { + lp += ct; + continue; + } + return(0); + + case CBACK|STAR: + bbeg = braslist[*ep]; + ct = braelist[*ep++] - bbeg; + curlp = lp; + while(ecmp(bbeg, lp, ct)) + lp += ct; + + while(lp >= curlp) { + if(advance(lp, ep)) return(1); + lp -= ct; + } + return(0); + + + case CDOT|STAR: + curlp = lp; + while (*lp++); + goto star; + + case CCHR|STAR: + curlp = lp; + while (*lp++ == *ep); + ep++; + goto star; + + case CCL|STAR: + curlp = lp; + do { + c = *lp++ & 0177; + } while(ep[c>>3] & bittab[c & 07]); + ep += 16; + goto star; + + star: + if(--lp == curlp) { + continue; + } + + if(*ep == CCHR) { + c = ep[1]; + do { + if(*lp != c) + continue; + if(advance(lp, ep)) + return(1); + } while(lp-- > curlp); + return(0); + } + + if(*ep == CBACK) { + c = *(braslist[ep[1]]); + do { + if(*lp != c) + continue; + if(advance(lp, ep)) + return(1); + } while(lp-- > curlp); + return(0); + } + + do { + if(lp == locs) break; + if (advance(lp, ep)) + return(1); + } while (lp-- > curlp); + return(0); + + default: + fprintf(stderr, "RE botch, %o\n", *--ep); + } +} +substitute(ipc) +union reptr *ipc; +{ + if(match(ipc->A.re1, 0) == 0) return(0); + + sflag = 1; + dosub(ipc->A.rhs); + + if(ipc->A.gfl) { + while(*loc2) { + if(match(ipc->A.re1, 1) == 0) break; + dosub(ipc->A.rhs); + } + } + return(1); +} + +dosub(rhsbuf) +char *rhsbuf; +{ + register char *lp, *sp, *rp; + int c; + + lp = linebuf; + sp = genbuf; + rp = rhsbuf; + while (lp < loc1) + *sp++ = *lp++; + while(c = *rp++) { + if (c == '&') { + sp = place(sp, loc1, loc2); + continue; + } else if (c&0200 && (c &= 0177) >= '1' && c < NBRA+'1') { + sp = place(sp, braslist[c-'1'], braelist[c-'1']); + continue; + } + *sp++ = c&0177; + if (sp >= &genbuf[LBSIZE]) + fprintf(stderr, "output line too long.\n"); + } + lp = loc2; + loc2 = sp - genbuf + linebuf; + while (*sp++ = *lp++) + if (sp >= &genbuf[LBSIZE]) { + fprintf(stderr, "Output line too long.\n"); + } + lp = linebuf; + sp = genbuf; + while (*lp++ = *sp++); + spend = lp-1; +} +char *place(asp, al1, al2) +char *asp, *al1, *al2; +{ + register char *sp, *l1, *l2; + + sp = asp; + l1 = al1; + l2 = al2; + while (l1 < l2) { + *sp++ = *l1++; + if (sp >= &genbuf[LBSIZE]) + fprintf(stderr, "Output line too long.\n"); + } + return(sp); +} + +command(ipc) +union reptr *ipc; +{ + register int i; + register char *p1, *p2, *p3; + char *execp; + + + switch(ipc->A.command) { + + case ACOM: + *aptr++ = ipc; + if(aptr >= &abuf[ABUFSIZE]) { + fprintf(stderr, "Too many appends after line %ld\n", + lnum); + } + *aptr = 0; + break; + + case CCOM: + delflag = 1; + if(!ipc->A.inar || dolflag) { + for(p1 = ipc->A.re1; *p1; ) + putc(*p1++, stdout); + putc('\n', stdout); + } + break; + case DCOM: + delflag++; + break; + case CDCOM: + p1 = p2 = linebuf; + + while(*p1 != '\n') { + if(*p1++ == 0) { + delflag++; + return; + } + } + + p1++; + while(*p2++ = *p1++); + spend = p2-1; + jflag++; + break; + + case EQCOM: + fprintf(stdout, "%ld\n", lnum); + break; + + case GCOM: + p1 = linebuf; + p2 = holdsp; + while(*p1++ = *p2++); + spend = p1-1; + break; + + case CGCOM: + *spend++ = '\n'; + p1 = spend; + p2 = holdsp; + while(*p1++ = *p2++) + if(p1 >= lbend) + break; + spend = p1-1; + break; + + case HCOM: + p1 = holdsp; + p2 = linebuf; + while(*p1++ = *p2++); + hspend = p1-1; + break; + + case CHCOM: + *hspend++ = '\n'; + p1 = hspend; + p2 = linebuf; + while(*p1++ = *p2++) + if(p1 >= hend) + break; + hspend = p1-1; + break; + + case ICOM: + for(p1 = ipc->A.re1; *p1; ) + putc(*p1++, stdout); + putc('\n', stdout); + break; + + case BCOM: + jflag = 1; + break; + + case LCOM: + p1 = linebuf; + p2 = genbuf; + genbuf[72] = 0; + while(*p1) + if(*p1 >= 040) { + if(*p1 == 0177) { + p3 = rub; + while(*p2++ = *p3++) + if(p2 >= lcomend) { + *p2 = '\\'; + fprintf(stdout, "%s\n", genbuf); + p2 = genbuf; + } + p2--; + p1++; + continue; + } + *p2++ = *p1++; + if(p2 >= lcomend) { + *p2 = '\\'; + fprintf(stdout, "%s\n", genbuf); + p2 = genbuf; + } + } else { + p3 = trans[*p1-1]; + while(*p2++ = *p3++) + if(p2 >= lcomend) { + *p2 = '\\'; + fprintf(stdout, "%s\n", genbuf); + p2 = genbuf; + } + p2--; + p1++; + } + *p2 = 0; + fprintf(stdout, "%s\n", genbuf); + break; + + case NCOM: + if(!nflag) { + for(p1 = linebuf; p1 < spend; p1++) + putc(*p1, stdout); + putc('\n', stdout); + } + + if(aptr > abuf) + arout(); + if((execp = gline(linebuf)) == badp) { + pending = ipc; + delflag = 1; + break; + } + spend = execp; + + break; + case CNCOM: + if(aptr > abuf) + arout(); + *spend++ = '\n'; + if((execp = gline(spend)) == badp) { + pending = ipc; + delflag = 1; + break; + } + spend = execp; + break; + + case PCOM: + for(p1 = linebuf; p1 < spend; p1++) + putc(*p1, stdout); + putc('\n', stdout); + break; + case CPCOM: + cpcom: + for(p1 = linebuf; *p1 != '\n' && *p1 != '\0'; ) + putc(*p1++, stdout); + putc('\n', stdout); + break; + + case QCOM: + if(!nflag) { + for(p1 = linebuf; p1 < spend; p1++) + putc(*p1, stdout); + putc('\n', stdout); + } + if(aptr > abuf) arout(); + fclose(stdout); + exit(0); + case RCOM: + + *aptr++ = ipc; + if(aptr >= &abuf[ABUFSIZE]) + fprintf(stderr, "Too many reads after line%ld\n", + lnum); + + *aptr = 0; + + break; + + case SCOM: + i = substitute(ipc); + if(ipc->A.pfl && i) + if(ipc->A.pfl == 1) { + for(p1 = linebuf; p1 < spend; p1++) + putc(*p1, stdout); + putc('\n', stdout); + } + else + goto cpcom; + if(i && ipc->A.fcode) + goto wcom; + break; + + case TCOM: + if(sflag == 0) break; + sflag = 0; + jflag = 1; + break; + + wcom: + case WCOM: + fprintf(ipc->A.fcode, "%s\n", linebuf); + fflush(ipc->A.fcode); + break; + case XCOM: + p1 = linebuf; + p2 = genbuf; + while(*p2++ = *p1++); + p1 = holdsp; + p2 = linebuf; + while(*p2++ = *p1++); + spend = p2 - 1; + p1 = genbuf; + p2 = holdsp; + while(*p2++ = *p1++); + hspend = p2 - 1; + break; + + case YCOM: + p1 = linebuf; + p2 = ipc->A.re1; + while(*p1 = p2[*p1]) p1++; + break; + } + +} + +char * +gline(addr) +char *addr; +{ + register char *p1, *p2; + register c; + p1 = addr; + p2 = cbp; + for (;;) { + if (p2 >= ebp) { + if ((c = read(f, ibuf, BUFSIZ)) <= 0) { + return(badp); + } + p2 = ibuf; + ebp = ibuf+c; + } + if ((c = *p2++) == '\n') { + if(p2 >= ebp) { + if((c = read(f, ibuf, BUFSIZ)) <= 0) { + close(f); + if(eargc == 0) + dolflag = 1; + } + + p2 = ibuf; + ebp = ibuf + c; + } + break; + } + if(c) + if(p1 < lbend) + *p1++ = c; + } + lnum++; + *p1 = 0; + cbp = p2; + + return(p1); +} +ecmp(a, b, count) +char *a, *b; +{ + while(count--) + if(*a++ != *b++) return(0); + return(1); +} + +arout() +{ + register char *p1; + FILE *fi; + char c; + int t; + + aptr = abuf - 1; + while(*++aptr) { + if((*aptr)->A.command == ACOM) { + for(p1 = (*aptr)->A.re1; *p1; ) + putc(*p1++, stdout); + putc('\n', stdout); + } else { + if((fi = fopen((*aptr)->A.re1, "r")) == NULL) + continue; + while((t = getc(fi)) != EOF) { + c = t; + putc(c, stdout); + } + fclose(fi); + } + } + aptr = abuf; + *aptr = 0; +} diff --git a/src/cmd/setty/Makefile b/src/cmd/setty/Makefile new file mode 100644 index 0000000..00cce76 --- /dev/null +++ b/src/cmd/setty/Makefile @@ -0,0 +1,27 @@ +#========================================== +# Makefile: makefile for setty +# Copyright 2012 Majenko Technolohies +# (matt@majenko.co.uk +# Last Modified: 29/01/2012 +#========================================== + +TOPSRC = $(shell cd ../../..; pwd) +include $(TOPSRC)/target.mk + +OBJS = setty.o +SRCS = setty.c +LIBS += -lcurses -ltermcap + +all: setty + +setty: ${OBJS} + ${CC} ${LDFLAGS} -o setty.elf ${OBJS} ${LIBS} + ${OBJDUMP} -S setty.elf > setty.dis + ${SIZE} setty.elf + ${ELF2AOUT} setty.elf $@ && rm setty.elf + +clean: + -rm -f setty ${OBJS} setty.elf setty.dis + +install: all + install setty $(DESTDIR)/bin/ diff --git a/src/cmd/setty/setty.c b/src/cmd/setty/setty.c new file mode 100644 index 0000000..61154d8 --- /dev/null +++ b/src/cmd/setty/setty.c @@ -0,0 +1,104 @@ +#include +#include +#include +#include + +int main(int argc, char **argv) +{ + char *ttname = ttyname(0); + char *tn; + FILE *ttys; + char buffer[100]; + char found = 0; + int j,k; + char delim; + char *parts[30]; + int part; + + if(!ttname) + return 10; + if(strlen(ttname)<5) + return 10; + + tn = ttname+5; + + ttys = fopen("/etc/ttys","r"); + if(!ttys) + return 10; + while(fgets(buffer,100,ttys)) + { + if(!strncmp(tn,buffer,strlen(tn))) + { + found = 1; + break; + } + } + fclose(ttys); + if(!found) + return 10; + + // replace all tabs with spaces and remove CRLF + for(j=0; j sh.dis + ${SIZE} sh.elf + ${ELF2AOUT} sh.elf $@ && rm sh.elf + +install: all + install sh $(DESTDIR)/bin/ + +clean: + rm -f sh *.o *~ *.elf *.dis + +args.o: args.c defs.h mac.h mode.h name.h stak.h brkincr.h ctype.h +blok.o: blok.c defs.h mac.h mode.h name.h stak.h brkincr.h ctype.h +builtin.o: builtin.c +cmd.o: cmd.c defs.h mac.h mode.h name.h stak.h brkincr.h ctype.h sym.h +ctype.o: ctype.c defs.h mac.h mode.h name.h stak.h brkincr.h ctype.h +error.o: error.c defs.h mac.h mode.h name.h stak.h brkincr.h ctype.h +expand.o: expand.c defs.h mac.h mode.h name.h stak.h brkincr.h ctype.h +fault.o: fault.c defs.h mac.h mode.h name.h stak.h brkincr.h ctype.h +io.o: io.c defs.h mac.h mode.h name.h stak.h brkincr.h ctype.h +macro.o: macro.c defs.h mac.h mode.h name.h stak.h brkincr.h ctype.h sym.h +main.o: main.c defs.h mac.h mode.h name.h stak.h brkincr.h ctype.h sym.h timeout.h +msg.o: msg.c defs.h mac.h mode.h name.h stak.h brkincr.h ctype.h sym.h +name.o: name.c defs.h mac.h mode.h name.h stak.h brkincr.h ctype.h +print.o: print.c defs.h mac.h mode.h name.h stak.h brkincr.h ctype.h +service.o: service.c defs.h mac.h mode.h name.h stak.h brkincr.h ctype.h +setbrk.o: setbrk.c defs.h mac.h mode.h name.h stak.h brkincr.h ctype.h +stak.o: stak.c defs.h mac.h mode.h name.h stak.h brkincr.h ctype.h +string.o: string.c defs.h mac.h mode.h name.h stak.h brkincr.h ctype.h +word.o: word.c defs.h mac.h mode.h name.h stak.h brkincr.h ctype.h sym.h +xec.o: xec.c defs.h mac.h mode.h name.h stak.h brkincr.h ctype.h sym.h diff --git a/src/cmd/sh/args.c b/src/cmd/sh/args.c new file mode 100644 index 0000000..e51b976 --- /dev/null +++ b/src/cmd/sh/args.c @@ -0,0 +1,306 @@ +/* + * UNIX shell + * + * Bell Telephone Laboratories + */ +#include "defs.h" + +static struct dolnod *copyargs(); +static struct dolnod *freedolh(); +extern struct dolnod *freeargs(); +static struct dolnod *dolh; + +char flagadr[14]; + +char flagchar[] = +{ + 'x', + 'n', + 'v', + 't', + STDFLG, + 'i', + 'e', + 'r', + 'k', + 'u', + 'h', + 'f', + 'a', + 0 +}; + +long flagval[] = +{ + execpr, + noexec, + readpr, + oneflg, + stdflg, + intflg, + errflg, + rshflg, + keyflg, + setflg, + hashflg, + nofngflg, + exportflg, + 0 +}; + +/* ======== option handling ======== */ + + +options(argc,argv) + char **argv; + int argc; +{ + register char *cp; + register char **argp = argv; + register char *flagc; + char *flagp; + + if (argc > 1 && *argp[1] == '-') + { + /* + * if first argument is "--" then options are not + * to be changed. Fix for problems getting + * $1 starting with a "-" + */ + + cp = argp[1]; + if (cp[1] == '-') + { + /* argp[1] = argp[0]; */ + argc--; + return(argc); + } + if (cp[1] == '\0') + flags &= ~(execpr|readpr); + + /* + * Step along 'flagchar[]' looking for matches. + * 'sicr' are not legal with 'set' command. + */ + + while (*++cp) + { + flagc = flagchar; + while (*flagc && *flagc != *cp) + flagc++; + if (*cp == *flagc) + { + if (eq(argv[0], "set") && any(*cp, "sicr")) + failed(argv[1], badopt); + else + { + flags |= flagval[flagc-flagchar]; + if (flags & errflg) + eflag = errflg; + } + } + else if (*cp == 'c' && argc > 2 && comdiv == NIL) + { + comdiv = argp[2]; + /* argp[1] = argp[0]; */ + argp++; + argc--; + } + else + failed(argv[1],badopt); + } + /* argp[1] = argp[0]; */ + argc--; + } + else if (argc > 1 && *argp[1] == '+') /* unset flags x, k, t, n, v, e, u */ + { + cp = argp[1]; + while (*++cp) + { + flagc = flagchar; + while (*flagc && *flagc != *cp) + flagc++; + /* + * step through flags + */ + if (!any(*cp, "sicr") && *cp == *flagc) + { + /* + * only turn off if already on + */ + if ((flags & flagval[flagc-flagchar])) + { + flags &= ~(flagval[flagc-flagchar]); + if (*cp == 'e') + eflag = 0; + } + } + } + /* argp[1] = argp[0]; */ + argc--; + } + /* + * set up $- + */ + flagp = flagadr; + if (flags) + { + flagc = flagchar; + while (*flagc) + { + if (flags & flagval[flagc-flagchar]) + *flagp++ = *flagc; + flagc++; + } + } + *flagp = 0; + return(argc); +} + +/* + * sets up positional parameters + */ +setargs(argi) + char *argi[]; +{ + register char **argp = argi; /* count args */ + register int argn = 0; + + while (Rcheat(*argp++) != ENDARGS) + argn++; + /* + * free old ones unless on for loop chain + */ + freedolh(); + dolh = copyargs(argi, argn); + dolc = argn - 1; +} + + +static struct dolnod * +freedolh() +{ + register char **argp; + register struct dolnod *argblk; + + if (argblk = dolh) + { + if ((--argblk->doluse) == 0) + { + for (argp = argblk->dolarg; Rcheat(*argp) != ENDARGS; argp++) + free(*argp); + free(argblk); + } + } +} + +struct dolnod * +freeargs(blk) + struct dolnod *blk; +{ + register char **argp; + register struct dolnod *argr = NIL; + register struct dolnod *argblk; + int cnt; + + if (argblk = blk) + { + argr = argblk->dolnxt; + cnt = --argblk->doluse; + + if (argblk == dolh) + { + if (cnt == 1) + return(argr); + else + return(argblk); + } + else + { + if (cnt == 0) + { + for (argp = argblk->dolarg; Rcheat(*argp) != ENDARGS; argp++) + free(*argp); + free(argblk); + } + } + } + return(argr); +} + +static struct dolnod * +copyargs(from, n) + char *from[]; +{ + register struct dolnod *np = (struct dolnod *) alloc(sizeof(char**) * n + 3 * BYTESPERWORD); + register char **fp = from; + register char **pp; + + np->doluse = 1; /* use count */ + pp = np->dolarg; + dolv = pp; + + while (n--) + *pp++ = make(*fp++); + *pp++ = ENDARGS; + return(np); +} + + +struct dolnod * +clean_args(blk) + struct dolnod *blk; +{ + register char **argp; + register struct dolnod *argr = NIL; + register struct dolnod *argblk; + + if (argblk = blk) + { + argr = argblk->dolnxt; + + if (argblk == dolh) + argblk->doluse = 1; + else + { + for (argp = argblk->dolarg; Rcheat(*argp) != ENDARGS; argp++) + free(*argp); + free(argblk); + } + } + return(argr); +} + +clearup() +{ + /* + * force `for' $* lists to go away + */ + while (argfor = clean_args(argfor)) + ; + /* + * clean up io files + */ + while (pop()) + ; + + /* + * clean up tmp files + */ + while (poptemp()) + ; +} + +struct dolnod * +useargs() +{ + if (dolh) + { + if (dolh->doluse++ == 1) + { + dolh->dolnxt = argfor; + argfor = dolh; + } + } + return(dolh); +} diff --git a/src/cmd/sh/blok.c b/src/cmd/sh/blok.c new file mode 100644 index 0000000..b9344f5 --- /dev/null +++ b/src/cmd/sh/blok.c @@ -0,0 +1,187 @@ +/* + * UNIX shell + * + * Bell Telephone Laboratories + */ +#include "defs.h" + +/* + * storage allocator + * (circular first fit strategy) + */ + +#define BUSY 01 +#define busy(x) (Rcheat((x)->word) & BUSY) + +unsigned brkincr = BRKINCR; +struct blk *blokp; /*current search pointer*/ +struct blk *bloktop; /* top of arena (last blok) */ + +char *brkbegin; +char *setbrk(); + +char * +alloc(nbytes) + unsigned nbytes; +{ + register unsigned rbytes = round(nbytes+BYTESPERWORD, BYTESPERWORD); + + for (;;) + { + int c = 0; + register struct blk *p = blokp; + register struct blk *q; + + do + { + if (!busy(p)) + { + while (!busy(q = p->word)) + p->word = q->word; + if ((char *)q - (char *)p >= rbytes) + { + blokp = (struct blk *)((char *)p + rbytes); + if (q > blokp) + blokp->word = p->word; + p->word = (struct blk *)(Rcheat(blokp) | BUSY); + return((char *)(p + 1)); + } + } + q = p; + p = (struct blk *)(Rcheat(p->word) & ~BUSY); + } while (p > q || (c++) == 0); + addblok(rbytes); + } +} + +addblok(reqd) + unsigned reqd; +{ + if (stakbot == NIL) + { + extern end; + brkbegin = setbrk(BRKINCR * 5); + bloktop = (struct blk *) &end; + } + + if (stakbas != staktop) + { + register char *rndstak; + register struct blk *blokstak; + + pushstak(0); + rndstak = (char *)round(staktop, BYTESPERWORD); + blokstak = (struct blk *)(stakbas) - 1; + blokstak->word = stakbsy; + stakbsy = blokstak; + bloktop->word = (struct blk *)(Rcheat(rndstak) | BUSY); + bloktop = (struct blk *)(rndstak); + } + reqd += brkincr; + reqd &= ~(brkincr - 1); + blokp = bloktop; + bloktop = bloktop->word = (struct blk *)(Rcheat(bloktop) + reqd); + bloktop->word = (struct blk *)(brkbegin + 1); + { + register char *stakadr = (char *)(bloktop + 2); + + if (stakbot != staktop) + staktop = movstr(stakbot, stakadr); + else + staktop = stakadr; + + stakbas = stakbot = stakadr; + } +} + +free(ap) + struct blk *ap; +{ + register struct blk *p; + + if ((p = ap) && p < bloktop) + { +#ifdef DEBUG + chkbptr(p); +#endif + --p; + p->word = (struct blk *)(Rcheat(p->word) & ~BUSY); + } +} + + +#ifdef DEBUG + +chkbptr(ptr) + struct blk *ptr; +{ + int exf = 0; + register struct blk *p = (struct blk *)brkbegin; + register struct blk *q; + int us = 0, un = 0; + + for (;;) + { + q = (struct blk *)(Rcheat(p->word) & ~BUSY); + + if (p+1 == ptr) + exf++; + + if (q < (struct blk *)brkbegin || q > bloktop) + abort(3); + + if (p == bloktop) + break; + + if (busy(p)) + us += q - p; + else + un += q - p; + + if (p >= q) + abort(4); + + p = q; + } + if (exf == 0) + abort(1); +} + + +chkmem() +{ + register struct blk *p = (struct blk *)brkbegin; + register struct blk *q; + int us = 0, un = 0; + + for (;;) + { + q = (struct blk *)(Rcheat(p->word) & ~BUSY); + + if (q < (struct blk *)brkbegin || q > bloktop) + abort(3); + + if (p == bloktop) + break; + + if (busy(p)) + us += q - p; + else + un += q - p; + + if (p >= q) + abort(4); + + p = q; + } + + prs("un/used/avail "); + prn(un); + blank(); + prn(us); + blank(); + prn((char *)bloktop - brkbegin - (un + us)); + newline(); + +} +#endif diff --git a/src/cmd/sh/brkincr.h b/src/cmd/sh/brkincr.h new file mode 100644 index 0000000..2c4c254 --- /dev/null +++ b/src/cmd/sh/brkincr.h @@ -0,0 +1,2 @@ +#define BRKINCR 01000 +#define BRKMAX 04000 diff --git a/src/cmd/sh/cmd.c b/src/cmd/sh/cmd.c new file mode 100644 index 0000000..fdb11cf --- /dev/null +++ b/src/cmd/sh/cmd.c @@ -0,0 +1,560 @@ +/* + * UNIX shell + * + * Bell Telephone Laboratories + */ +#include "defs.h" +#include "sym.h" + +/* ======== storage allocation for functions ======== */ + +char * +getstor(asize) + int asize; +{ + if (fndef) + return alloc(asize); + else + return getstak(asize); +} + +/* ======== command line decoding ========*/ + +struct trenod * +makefork(flgs, i) + int flgs; + struct trenod *i; +{ + register struct forknod *t; + + t = (struct forknod *)getstor(sizeof(struct forknod)); + t->forktyp = flgs|TFORK; + t->forktre = i; + t->forkio = NIL; + return((struct trenod *)t); +} + +static int +prsym(sym) +{ + if (sym & SYMFLG) + { + register struct sysnod *sp = reserved; + + while (sp->sysval && sp->sysval != sym) + sp++; + prs(sp->sysnam); + } + else if (sym == EOFSYM) + prs(endoffile); + else + { + if (sym & SYMREP) + prc(sym); + if (sym == NL) + prs("newline or ;"); + else + prc(sym); + } +} + +static int +synbad() +{ + prp(); + prs(synmsg); + if ((flags & ttyflg) == 0) + { + prs(atline); + prn(standin->flin); + } + prs(colon); + prc(LQ); + if (wdval) + prsym(wdval); + else + prs_cntl(wdarg->argval); + prc(RQ); + prs(unexpected); + newline(); + exitsh(SYNBAD); +} + +static struct trenod * +makelist(type, i, r) + int type; + struct trenod *i, *r; +{ + register struct lstnod *t; + + if (i == NIL || r == NIL) + synbad(); + else + { + t = (struct lstnod *)getstor(sizeof(struct lstnod)); + t->lsttyp = type; + t->lstlef = i; + t->lstrit = r; + } + return((struct trenod *)t); +} + +static int +skipnl() +{ + while ((reserv++, word() == NL)) + chkpr(); + return(wdval); +} + +static int +chksym(sym) +{ + register int x = sym & wdval; + + if (((x & SYMFLG) ? x : sym) != wdval) + synbad(); +} + +static struct regnod * +syncase(esym) +register int esym; +{ + skipnl(); + if (wdval == esym) + return(NIL); + else + { + register struct regnod *r = (struct regnod *)getstor(sizeof(struct regnod)); + register struct argnod *argp; + + r->regptr = NIL; + for (;;) + { + if (fndef) + { + argp= wdarg; + wdarg = (struct argnod *)alloc(length(argp->argval) + BYTESPERWORD); + movstr(argp->argval, wdarg->argval); + } + + wdarg->argnxt = r->regptr; + r->regptr = wdarg; + if (wdval || (word() != ')' && wdval != '|')) + synbad(); + if (wdval == '|') + word(); + else + break; + } + r->regcom = cmd(0, NLFLG | MTFLG); + if (wdval == ECSYM) + r->regnxt = syncase(esym); + else + { + chksym(esym); + r->regnxt = NIL; + } + return(r); + } +} + +static int +chkword() +{ + if (word()) + synbad(); +} + +static struct ionod * +inout(lastio) + struct ionod *lastio; +{ + register int iof; + register struct ionod *iop; + register char c; + + iof = wdnum; + switch (wdval) + { + case DOCSYM: /* << */ + iof |= IODOC; + break; + + case APPSYM: /* >> */ + case '>': + if (wdnum == 0) + iof |= 1; + iof |= IOPUT; + if (wdval == APPSYM) + { + iof |= IOAPP; + break; + } + + case '<': + if ((c = nextc(0)) == '&') + iof |= IOMOV; + else if (c == '>') + iof |= IORDW; + else + peekc = c | MARK; + break; + + default: + return(lastio); + } + + chkword(); + iop = (struct ionod *)getstor(sizeof(struct ionod)); + + if (fndef) + iop->ioname = make(wdarg->argval); + else + iop->ioname = wdarg->argval; + + iop->iolink = NIL; + iop->iofile = iof; + if (iof & IODOC) + { + iop->iolst = iopend; + iopend = iop; + } + word(); + iop->ionxt = inout(lastio); + return(iop); +} + +/* + * item + * + * ( cmd ) [ < in ] [ > out ] + * word word* [ < in ] [ > out ] + * if ... then ... else ... fi + * for ... while ... do ... done + * case ... in ... esac + * begin ... end + */ +static struct trenod * +item(flag) + BOOL flag; +{ + register struct trenod *r; + register struct ionod *io; + + if (flag) + io = inout((struct ionod *)NIL); + else + io = NIL; + switch (wdval) + { + case CASYM: + { + register struct swnod *t; + + t = (struct swnod *)getstor(sizeof(struct swnod)); + r = (struct trenod *)t; + + chkword(); + if (fndef) + t->swarg = make(wdarg->argval); + else + t->swarg = wdarg->argval; + skipnl(); + chksym(INSYM | BRSYM); + t->swlst = syncase(wdval == INSYM ? ESSYM : KTSYM); + t->swtyp = TSW; + break; + } + + case IFSYM: + { + register int w; + register struct ifnod *t; + + t = (struct ifnod *)getstor(sizeof(struct ifnod)); + r = (struct trenod *)t; + + t->iftyp = TIF; + t->iftre = cmd(THSYM, NLFLG); + t->thtre = cmd(ELSYM | FISYM | EFSYM, NLFLG); + t->eltre = ((w = wdval) == ELSYM) ? cmd(FISYM, NLFLG) : + (w == EFSYM) ? (wdval = IFSYM, item(0)) : + (struct trenod *)NIL; + if (w == EFSYM) + return(r); + break; + } + + case FORSYM: + { + register struct fornod *t; + + t = (struct fornod *)getstor(sizeof(struct fornod)); + r = (struct trenod *)t; + + t->fortyp = TFOR; + t->forlst = NIL; + chkword(); + if (fndef) + t->fornam = make(wdarg->argval); + else + t->fornam = wdarg->argval; + if (skipnl() == INSYM) + { + chkword(); + + nohash++; + t->forlst = (struct comnod *)item(0); + nohash--; + + if (wdval != NL && wdval != ';') + synbad(); + if (wdval == NL) + chkpr(); + skipnl(); + } + chksym(DOSYM | BRSYM); + t->fortre = cmd(wdval == DOSYM ? ODSYM : KTSYM, NLFLG); + break; + } + + case WHSYM: + case UNSYM: + { + register struct whnod *t; + + t = (struct whnod *)getstor(sizeof(struct whnod)); + r = (struct trenod *)t; + + t->whtyp = (wdval == WHSYM ? TWH : TUN); + t->whtre = cmd(DOSYM, NLFLG); + t->dotre = cmd(ODSYM, NLFLG); + break; + } + + case BRSYM: + r = cmd(KTSYM, NLFLG); + break; + + case '(': + { + register struct parnod *p; + + p = (struct parnod *)getstor(sizeof(struct parnod)); + p->partre = cmd(')', NLFLG); + p->partyp = TPAR; + r = makefork(0, p); + break; + } + + default: + if (io == NIL) + return(NIL); + + case 0: + { + register struct comnod *t; + register struct argnod *argp; + register struct argnod **argtail; + register struct argnod **argset = (struct argnod **)NIL; + int keywd = 1; + char *com; + + if ((wdval != NL) && ((peekn = skipc()) == '(')) + { + struct fndnod *f; + struct ionod *saveio; + + saveio = iotemp; + peekn = 0; + if (skipc() != ')') + synbad(); + + f = (struct fndnod *)getstor(sizeof(struct fndnod)); + r = (struct trenod *)f; + + f->fndtyp = TFND; + if (fndef) + f->fndnam = make(wdarg->argval); + else + f->fndnam = wdarg->argval; + reserv++; + fndef++; + skipnl(); + f->fndval = (struct trenod *)item(0); + fndef--; + + if (iotemp != saveio) + { + struct ionod *ioptr = iotemp; + + while (ioptr->iolst != saveio) + ioptr = ioptr->iolst; + + ioptr->iolst = fiotemp; + fiotemp = iotemp; + iotemp = saveio; + } + return(r); + } + else + { + t = (struct comnod *)getstor(sizeof(struct comnod)); + r = (struct trenod *)t; + + t->comio = io; /*initial io chain*/ + argtail = &(t->comarg); + + while (wdval == 0) + { + if (fndef) + { + argp = wdarg; + wdarg = (struct argnod *)alloc(length(argp->argval) + BYTESPERWORD); + movstr(argp->argval, wdarg->argval); + } + + argp = wdarg; + if (wdset && keywd) + { + argp->argnxt = (struct argnod *)argset; + argset = (struct argnod **)argp; + } + else + { + *argtail = argp; + argtail = &(argp->argnxt); + keywd = flags & keyflg; + } + word(); + if (flag) + t->comio = inout(t->comio); + } + + t->comtyp = TCOM; + t->comset = (struct argnod *)argset; + *argtail = NIL; + + if (nohash == 0 && (fndef == 0 || (flags & hashflg))) + { + if (t->comarg) + { + com = t->comarg->argval; + if (*com && *com != DOLLAR) + pathlook(com, 0, t->comset); + } + } + + return(r); + } + } + + } + reserv++; + word(); + if (io = inout(io)) + { + r = makefork(0,r); + r->treio = io; + } + return(r); +} + +/* + * term + * item + * item |^ term + */ +static struct trenod * +term(flg) +{ + register struct trenod *t; + + reserv++; + if (flg & NLFLG) + skipnl(); + else + word(); + if ((t = item(TRUE)) && (wdval == '^' || wdval == '|')) + { + struct trenod *left; + struct trenod *right; + + left = makefork(FPOU, t); + right = makefork(FPIN | FPCL, term(NLFLG)); + return(makefork(0, makelist(TFIL, left, right))); + } + else + return(t); +} + +/* + * list + * term + * list && term + * list || term + */ +static struct trenod * +list(flg) +{ + register struct trenod *r; + register int b; + + r = term(flg); + while (r && ((b = (wdval == ANDFSYM)) || wdval == ORFSYM)) + r = makelist((b ? TAND : TORF), r, term(NLFLG)); + return(r); +} + +/* + * cmd + * empty + * list + * list & [ cmd ] + * list [ ; cmd ] + */ +struct trenod * +cmd(sym, flg) + register int sym; + int flg; +{ + register struct trenod *i, *e; + + i = list(flg); + if (wdval == NL) + { + if (flg & NLFLG) + { + wdval = ';'; + chkpr(); + } + } + else if (i == NIL && (flg & MTFLG) == 0) + synbad(); + + switch (wdval) + { + case '&': + if (i) + i = makefork(FINT | FPRS | FAMP, i); + else + synbad(); + + case ';': + if (e = cmd(sym, flg | MTFLG)) + i = makelist(TLST, i, e); + else if (i == NIL) + synbad(); + break; + + case EOFSYM: + if (sym == NL) + break; + + default: + if (sym) + chksym(sym); + } + return(i); +} diff --git a/src/cmd/sh/ctype.c b/src/cmd/sh/ctype.c new file mode 100644 index 0000000..1a47a44 --- /dev/null +++ b/src/cmd/sh/ctype.c @@ -0,0 +1,233 @@ +/* + * Demos 2.2 shell && sysV shell Bell Telephone Laboratories + * + * KIAE, Moscow, 1984 (KOI-8) + */ +#include "defs.h" + +char _ctype1[] = { +/* 000 001 002 003 004 005 006 007 */ + _EOF, 0, 0, 0, 0, 0, 0, 0, + +/* bs ht nl vt np cr so si */ + 0, _TAB, _EOR, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, + +/* sp ! " # $ % & ' */ + _SPC, 0, _DQU, 0, _DOL1, 0, _AMP, 0, + +/* ( ) * + , - . / */ + _BRA, _KET, 0, 0, 0, 0, 0, 0, + +/* 0 1 2 3 4 5 6 7 */ + 0, 0, 0, 0, 0, 0, 0, 0, + +/* 8 9 : ; < = > ? */ + 0, 0, 0, _SEM, _LT, 0, _GT, 0, + +/* @ A B C D E F G */ + 0, 0, 0, 0, 0, 0, 0, 0, + +/* H I J K L M N O */ + 0, 0, 0, 0, 0, 0, 0, 0, + +/* P Q R S T U V W */ + 0, 0, 0, 0, 0, 0, 0, 0, + +/* X Y Z [ \ ] ^ _ */ + 0, 0, 0, 0, _BSL, 0, _HAT, 0, + +/* ` a b c d e f g */ + _LQU, 0, 0, 0, 0, 0, 0, 0, + +/* h i j k l m n o */ + 0, 0, 0, 0, 0, 0, 0, 0, + +/* p q r s t u v w */ + 0, 0, 0, 0, 0, 0, 0, 0, + +/* x y z { | } ~ del */ + 0, 0, 0, 0, _BAR, 0, 0, 0 +}; + +char _ctype2[] = { +/* 000 001 002 003 004 005 006 007 */ + 0, 0, 0, 0, 0, 0, 0, 0, + +/* bs ht nl vt np cr so si */ + 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, + +/* sp ! " # $ % & ' */ + 0, _PCS, 0, _NUM, _DOL2, 0, 0, 0, + +/* ( ) * + , - . / */ + 0, 0, _AST, _PLS, 0, _MIN, 0, 0, + +/* 0 1 2 3 4 5 6 7 */ + _DIG, _DIG, _DIG, _DIG, _DIG, _DIG, _DIG, _DIG, + +/* 8 9 : ; < = > ? */ + _DIG, _DIG, 0, 0, 0, _EQ, 0, _QU, + +/* @ A B C D E F G */ + _AT, _UPC, _UPC, _UPC, _UPC, _UPC, _UPC, _UPC, + +/* H I J K L M N O */ + _UPC, _UPC, _UPC, _UPC, _UPC, _UPC, _UPC, _UPC, + +/* P Q R S T U V W */ + _UPC, _UPC, _UPC, _UPC, _UPC, _UPC, _UPC, _UPC, + +/* X Y Z [ \ ] ^ _ */ + _UPC, _UPC, _UPC, _SQB, 0, 0, 0, _UPC, + +/* ` a b c d e f g */ + 0, _LPC, _LPC, _LPC, _LPC, _LPC, _LPC, _LPC, + +/* h i j k l m n o */ + _LPC, _LPC, _LPC, _LPC, _LPC, _LPC, _LPC, _LPC, + +/* p q r s t u v w */ + _LPC, _LPC, _LPC, _LPC, _LPC, _LPC, _LPC, _LPC, + +/* x y z { | } ~ del */ + _LPC, _LPC, _LPC, _CBR, 0, _CKT, 0, 0, + + +/* 000 001 002 003 004 005 006 007 */ + 0, 0, 0, 0, 0, 0, 0, 0, + +/* bs ht nl vt np cr so si */ + 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, + +/* sp ! " # $ % & ' */ + 0, 0, 0, 0, 0, 0, 0, 0, + +/* ( ) * + , - . / */ + 0, 0, 0, 0, 0, 0, 0, 0, + +/* 0 1 2 3 4 5 6 7 */ + 0, 0, 0, 0, 0, 0, 0, 0, + +/* 8 9 : ; < = > ? */ + 0, 0, 0, 0, 0, 0, 0, 0, + + _UPC, _UPC, _UPC, _UPC, _UPC, _UPC, _UPC, _UPC, + _UPC, _UPC, _UPC, _UPC, _UPC, _UPC, _UPC, _UPC, + _UPC, _UPC, _UPC, _UPC, _UPC, _UPC, _UPC, _UPC, + _UPC, _UPC, _UPC, _UPC, _UPC, _UPC, _UPC, _UPC, + _LPC, _LPC, _LPC, _LPC, _LPC, _LPC, _LPC, _LPC, + _LPC, _LPC, _LPC, _LPC, _LPC, _LPC, _LPC, _LPC, + _LPC, _LPC, _LPC, _LPC, _LPC, _LPC, _LPC, _LPC, + _LPC, _LPC, _LPC, _LPC, _LPC, _LPC, _LPC, _LPC +}; + +char _ctype3[] = { +/* nul soh stx etc eot enq ack bel */ + 0200, 0201, 0202, 0203, 0204, 0205, 0206, 0207, + +/* bs ht nl vt np cr so si */ + 0210, 0211, 0212, 0213, 0214, 0215, 0, 0, + +/* dle dc1 dc2 dc3 dc4 nak syn etb */ + 0220, 0221, 0222, 0223, 0224, 0225, 0226, 0227, + +/* can em sub esc fs gs rs us */ + 0230, 0231, 0232, 0233, 0234, 0235, 0236, 0237, + +/* sp ! " # $ % & ' */ + 0240, 0241, 0242, 0243, 0244, 0245, 0246, 0247, + +/* ( ) * + , - . / */ + 0250, 0251, 0252, 0253, 0254, 0255, 0256, 0257, + +/* 0 1 2 3 4 5 6 7 */ + 0, 0, 0, 0, 0, 0, 0, 0, + +/* 8 9 : ; < = > ? */ + 0, 0, 0272, 0273, 0274, 0275, 0276, 0277, + +/* @ A B C D E F G */ + 0216, 0, 0, 0, 0, 0, 0, 0, + +/* H I J K L M N O */ + 0, 0, 0, 0, 0, 0, 0, 0, + +/* P Q R S T U V W */ + 0, 0, 0, 0, 0, 0, 0, 0, + +/* X Y Z [ \ ] ^ _ */ + 0, 0, 0, 0260, 0261, 0262, 0263, 0264, + +/* ` a b c d e f g */ + 0217, 0, 0, 0, 0, 0, 0, 0, + +/* h i j k l m n o */ + 0, 0, 0, 0, 0, 0, 0, 0, + +/* p q r s t u v w */ + 0, 0, 0, 0, 0, 0, 0, 0, + +/* x y z { | } ~ del */ + 0, 0, 0, 0265, 0266, 0267, 0270, 0271, + + +/* nul soh stx etc eot enq ack bel */ + 00, 01, 02, 03, 04, 05, 06, 07, + +/* bs ht nl vt np cr R(@) R(') */ + 010, 011, 012, 013, 014, 015, 0100, 0140, + +/* dle dc1 dc2 dc3 dc4 nak syn etb */ + 020, 021, 022, 023, 024, 025, 026, 027, + +/* can em sub esc fs gs rs us */ + 030, 031, 032, 033, 034, 035, 036, 037, + +/* sp ! " # $ % & ' */ + 040, 041, 042, 043, 044, 045, 046, 047, + +/* ( ) * + , - . / */ + 050, 051, 052, 053, 054, 055, 056, 057, + +/* 0 1 2 3 4 5 6 7 */ + 0133, 0134, 0135, 0136, 0137, 0173, 0174, 0175, + +/* 8 9 : ; < = > ? */ + 0176, 0177, 072, 073, 074, 075, 076, 077, + +/* ÑŽ а б ц д е Ñ„ г */ + 0, 0, 0, 0, 0, 0, 0, 0, + +/* Ñ… и й к л м н о */ + 0, 0, 0, 0, 0, 0, 0, 0, + +/* п Ñ Ñ€ Ñ Ñ‚ у ж в */ + 0, 0, 0, 0, 0, 0, 0, 0, + +/* ÑŒ Ñ‹ з ш Ñ Ñ‰ ч ÑŠ */ + 0, 0, 0, 0, 0, 0, 0, 0, + +/* Ю РБ Ц Д Е Ф Г */ + 0, 0, 0, 0, 0, 0, 0, 0, + +/* Ð¥ И Й К Л М РО */ + 0, 0, 0, 0, 0, 0, 0, 0, + +/* П Я Р С Т У Ж Ð’ */ + 0, 0, 0, 0, 0, 0, 0, 0, + +/* Ь Ы З Ш Э Щ Ч 0 */ + 0, 0, 0, 0, 0, 0, 0, 0, +}; diff --git a/src/cmd/sh/ctype.h b/src/cmd/sh/ctype.h new file mode 100644 index 0000000..dbfd4db --- /dev/null +++ b/src/cmd/sh/ctype.h @@ -0,0 +1,95 @@ +/* + * KIAE shell + */ + +/* table 1 */ +#define T_SUB 01 +#define T_MET 02 +#define T_SPC 04 +#define T_DIP 010 +#define T_EOF 020 +#define T_EOR 040 +#define T_QOT 0100 +#define T_ESC 0200 + +/* table 2 */ +#define T_BRC 01 +#define T_DEF 02 +#define T_AST 04 +#define T_DIG 010 +#define T_FNG 020 +#define T_SHN 040 +#define T_IDC 0100 +#define T_SET 0200 + +/* for single chars */ +#define _TAB (T_SPC) +#define _SPC (T_SPC) +#define _UPC (T_IDC) +#define _LPC (T_IDC) +#define _DIG (T_DIG) +#define _EOF (T_EOF) +#define _EOR (T_EOR) +#define _BAR (T_DIP) +#define _HAT (T_MET) +#define _BRA (T_MET) +#define _KET (T_MET) +#define _SQB (T_FNG) +#define _AMP (T_DIP) +#define _SEM (T_DIP) +#define _LT (T_DIP) +#define _GT (T_DIP) +#define _LQU (T_QOT|T_ESC) +#define _BSL (T_ESC) +#define _DQU (T_QOT) +#define _DOL1 (T_SUB|T_ESC) + +#define _CBR T_BRC +#define _CKT T_DEF +#define _AST (T_AST|T_FNG) +#define _EQ (T_DEF) +#define _MIN (T_DEF|T_SHN) +#define _PCS (T_SHN) +#define _NUM (T_SHN) +#define _DOL2 (T_SHN) +#define _PLS (T_DEF|T_SET) +#define _AT (T_AST) +#define _QU (T_DEF|T_FNG|T_SHN) + +/* abbreviations for tests */ +#define _IDCH (T_IDC|T_DIG) +#define _META (T_SPC|T_DIP|T_MET|T_EOR) + +extern char _ctype1[]; + +/* nb these args are not call by value !!!! */ +#define space(c) (((c)"E)==0 && _ctype1[c]&(T_SPC)) +#define eofmeta(c) (((c)"E)==0 && _ctype1[c]&(_META|T_EOF)) +#define qotchar(c) (((c)"E)==0 && _ctype1[c]&(T_QOT)) +#define eolchar(c) (((c)"E)==0 && _ctype1[c]&(T_EOR|T_EOF)) +#define dipchar(c) (((c)"E)==0 && _ctype1[c]&(T_DIP)) +#define subchar(c) (((c)"E)==0 && _ctype1[c]&(T_SUB|T_QOT)) +#define escchar(c) (((c)"E)==0 && _ctype1[c]&(T_ESC)) + +extern char _ctype2[]; + +#define digit(c) (((c)"E)==0 && _ctype2[c]&(T_DIG)) +#define fngchar(c) (((c)"E)==0 && _ctype2[c]&(T_FNG)) +#define dolchar(c) ( _ctype2[cii(c)]&(T_AST|T_BRC|T_DIG|T_IDC|T_SHN)) +#define defchar(c) (((c)"E)==0 && _ctype2[c]&(T_DEF)) +#define setchar(c) (((c)"E)==0 && _ctype2[c]&(T_SET)) +#define digchar(c) (((c)"E)==0 && _ctype2[c]&(T_AST|T_DIG)) +#define letter(c) ( _ctype2[cii(c)]&(T_IDC)) +#define alphanum(c) ( _ctype2[cii(c)]&(_IDCH)) +#define astchar(c) (((c)"E)==0 && _ctype2[c]&(T_AST)) + +extern char _ctype3[]; +char cj; + +#define qmask(c) (cj=(c),( (cj&0200) ||(_ctype3[cj]) ==0)? cj : _ctype3[cj]) +#define smask(c) (cj=(c),cj=QST(cj),((!(cj&0200))||(_ctype3[cii(cj)]) ==0)? cj : _ctype3[cii(cj)]) +#define ismask(c) (cii(smask(c))) + +#define QST(c) (((c & 0177) == 0) ? 0 : c) +#define isq(q) ( ((q) &0300) == 0200 ) +#define cii(c) (((int) (c))&0377) diff --git a/src/cmd/sh/defs.c b/src/cmd/sh/defs.c new file mode 100644 index 0000000..fb46f80 --- /dev/null +++ b/src/cmd/sh/defs.c @@ -0,0 +1,76 @@ +/* + * UNIX shell + */ +#include +#include "mode.h" +#include "name.h" +#include + +/* temp files and io */ + +int output = 2; +int ioset; +struct ionod *iotemp; /* files to be deleted sometime */ +struct ionod *fiotemp; /* function files to be deleted sometime */ +struct ionod *iopend; /* documents waiting to be read at NL */ +struct fdsave fdmap[NOFILE]; + +/* substitution */ +int dolc; +char **dolv; +struct dolnod *argfor; +struct argnod *gchain; + + +/* name tree and words */ +int wdval; +int wdnum; +int fndef; +int nohash; +struct argnod *wdarg; +int wdset; +BOOL reserv; + +/* special names */ +char *pcsadr; +char *pidadr; +char *cmdadr; + +/* transput */ +char *tmpnam; +int serial; +int peekc; +int peekn; +char *comdiv; + +long flags; +int rwait; /* flags read waiting */ + +/* error exits from various parts of shell */ +jmp_buf subshell; +jmp_buf errshell; + +/* fault handling */ +BOOL trapnote; + +/* execflgs */ +int exitval; +int retval; +BOOL execbrk; +int loopcnt; +int breakcnt; +int funcnt; + +int wasintr; /* used to tell if break or delete is hit + while executing a wait + */ + +int eflag; + +/* The following stuff is from stak.h */ + +char *stakbas; +char *staktop; +char *stakbot; +char *stakbsy; +char *brkend; diff --git a/src/cmd/sh/defs.h b/src/cmd/sh/defs.h new file mode 100644 index 0000000..97ed902 --- /dev/null +++ b/src/cmd/sh/defs.h @@ -0,0 +1,358 @@ +/* + * UNIX shell + */ + +/* error exits from various parts of shell */ +#define ERROR 1 +#define SYNBAD 2 +#define SIGFAIL 2000 +#define SIGFLG 0200 + +/* command tree */ +#define FPRS 0x0100 +#define FINT 0x0200 +#define FAMP 0x0400 +#define FPIN 0x0800 +#define FPOU 0x1000 +#define FPCL 0x2000 +#define FCMD 0x4000 +#define COMMSK 0x00F0 +#define CNTMSK 0x000F + +#define TCOM 0x0000 +#define TPAR 0x0010 +#define TFIL 0x0020 +#define TLST 0x0030 +#define TIF 0x0040 +#define TWH 0x0050 +#define TUN 0x0060 +#define TSW 0x0070 +#define TAND 0x0080 +#define TORF 0x0090 +#define TFORK 0x00A0 +#define TFOR 0x00B0 +#define TFND 0x00C0 + +/* execute table */ +#define SYSSET 1 +#define SYSCD 2 +#define SYSEXEC 3 + +#define SYSLOGIN 4 +#define SYSNEWGRP 29 + +#define SYSTRAP 5 +#define SYSEXIT 6 +#define SYSSHFT 7 +#define SYSWAIT 8 +#define SYSCONT 9 +#define SYSBREAK 10 +#define SYSEVAL 11 +#define SYSDOT 12 +#define SYSRDONLY 13 +#define SYSTIMES 14 +#define SYSXPORT 15 +#define SYSNULL 16 +#define SYSREAD 17 +#define SYSTST 18 + +#ifndef RES /* exclude umask code */ +#define SYSUMASK 20 +#define SYSULIMIT 21 +#endif + +#define SYSECHO 22 +#define SYSHASH 23 +#define SYSPWD 24 +#define SYSRETURN 25 +#define SYSUNS 26 +#define SYSMEM 27 +#define SYSTYPE 28 + +/* used for input and output of shell */ +#define INIO 19 +#define OTIO 18 + +/*io nodes*/ +#define USERIO 10 +#define IOUFD 15 +#define IODOC 16 +#define IOPUT 32 +#define IOAPP 64 +#define IOMOV 128 +#define IORDW 256 +#define IOSTRIP 512 +#define INPIPE 0 +#define OTPIPE 1 + +/* arg list terminator */ +#define ENDARGS 0 + +#include "mac.h" +#include "mode.h" +#include "name.h" +#include +#include + +/* error catching */ +extern int errno; + +/* result type declarations */ + +#define free afree +extern char *allat(); +extern char *make(); +extern char *alloc(); +extern char *movstr(); +extern char *movstrn(); +extern struct trenod *cmd(); +extern struct trenod *makefork(); +extern struct namnod *lookup(); +extern struct namnod *findnam(); +extern struct dolnod *useargs(); +extern float expr(); +extern char *catpath(); +extern char *getpath(); +extern char *nextpath(); +extern char **scan(); +extern char *mactrim(); +extern char *macro(); +extern int exname(); +extern int printnam(); +extern int printro(); +extern int printexp(); +extern char **setenvv(); +extern long time(); + +#define attrib(n,f) (n->namflg |= f) +#define round(a,b) (((int)(((char *)(a)+b)-1))&~((b)-1)) +#define closepipe(x) (close(x[INPIPE]), close(x[OTPIPE])) +#define eq(a,b) (cf(a,b)==0) +#define max(a,b) ((a)>(b)?(a):(b)) +#define assert(x) ; + +/* temp files and io */ +extern int output; +extern int ioset; +extern struct ionod *iotemp; /* files to be deleted sometime */ +extern struct ionod *fiotemp; /* function files to be deleted sometime */ +extern struct ionod *iopend; /* documents waiting to be read at NL */ +extern struct fdsave fdmap[]; + + +/* substitution */ +extern int dolc; +extern char **dolv; +extern struct dolnod *argfor; +extern struct argnod *gchain; + +/* stak stuff */ +#include "stak.h" + +/* string constants */ +extern char atline[]; +extern char readmsg[]; +extern char colon[]; +extern char minus[]; +extern char nullstr[]; +extern char sptbnl[]; +extern char unexpected[]; +extern char endoffile[]; +extern char synmsg[]; + +/* name tree and words */ +extern struct sysnod reserved[]; +extern int no_reserved; +extern struct sysnod commands[]; +extern int no_commands; + +extern int wdval; +extern int wdnum; +extern int fndef; +extern int nohash; +extern struct argnod *wdarg; +extern int wdset; +extern BOOL reserv; + +/* prompting */ +extern char stdprompt[]; +extern char supprompt[]; +extern char profile[]; +extern char sysprofile[]; + +/* built in names */ +extern struct namnod fngnod; +extern struct namnod cdpnod; +extern struct namnod ifsnod; +extern struct namnod homenod; +extern struct namnod mailnod; +extern struct namnod pathnod; +extern struct namnod ps1nod; +extern struct namnod ps2nod; +extern struct namnod mchknod; +extern struct namnod acctnod; +extern struct namnod mailpnod; + +/* special names */ +extern char flagadr[]; +extern char *pcsadr; +extern char *pidadr; +extern char *cmdadr; + +extern char defpath[]; + +/* names always present */ +extern char mailname[]; +extern char homename[]; +extern char pathname[]; +extern char cdpname[]; +extern char ifsname[]; +extern char ps1name[]; +extern char ps2name[]; +extern char mchkname[]; +extern char acctname[]; +extern char mailpname[]; + +/* transput */ +extern char tmpout[]; +extern char *tmpnam; +extern int serial; + +#define TMPNAM 7 + +extern struct fileblk *standin; + +#define input (standin->fdes) +#define eof (standin->feof) + +extern int peekc; +extern int peekn; +extern char *comdiv; +extern char devnull[]; + +/* flags */ +#define noexec 01 +#define sysflg 01 +#define intflg 02 +#define prompt 04 +#define setflg 010 +#define errflg 020 +#define ttyflg 040 +#define forked 0100 +#define oneflg 0200 +#define rshflg 0400 +#define waiting 01000 +#define stdflg 02000 +#define STDFLG 's' +#define execpr 04000 +#define readpr 010000 +#define keyflg 020000 +#define hashflg 040000 +#define nofngflg 0200000 +#define exportflg 0400000 + +extern long flags; +extern int rwait; /* flags read waiting */ + +/* error exits from various parts of shell */ +#include +extern jmp_buf subshell; +extern jmp_buf errshell; + +/* fault handling */ +#include "brkincr.h" + +extern unsigned brkincr; + +#define MINTRAP 0 +#define MAXTRAP 26 + +#define TRAPSET 2 +#define SIGSET 4 +#define SIGMOD 8 +#define SIGCAUGHT 16 + +extern void done(); +extern void fault(); +extern BOOL trapnote; +extern char *trapcom[]; +extern BOOL trapflg[]; + +/* name tree and words */ +extern char **environ; +extern char numbuf[]; +extern char export[]; +extern char duperr[]; +extern char readonly[]; + +/* execflgs */ +extern int exitval; +extern int retval; +extern BOOL execbrk; +extern int loopcnt; +extern int breakcnt; +extern int funcnt; + +/* messages */ +extern char mailmsg[]; +extern char coredump[]; +extern char badopt[]; +extern char badparam[]; +extern char unset[]; +extern char badsub[]; +extern char nospace[]; +extern char nostack[]; +extern char notfound[]; +extern char badtrap[]; +extern char baddir[]; +extern char badshift[]; +extern char restricted[]; +extern char execpmsg[]; +extern char notid[]; +extern char badulimit[]; +extern char wtfailed[]; +extern char badcreate[]; +extern char nofork[]; +extern char noswap[]; +extern char piperr[]; +extern char badopen[]; +extern char badnum[]; +extern char arglist[]; +extern char txtbsy[]; +extern char toobig[]; +extern char badexec[]; +extern char badfile[]; +extern char badreturn[]; +extern char badexport[]; +extern char badunset[]; +extern char nohome[]; +extern char badperm[]; + +/* 'builtin' error messages */ + +extern char btest[]; +extern char badop[]; + +/* fork constant */ + +#define FORKLIM 2 /* was 32: max retry timeout for fork() */ + +#include "ctype.h" + +extern int wasintr; /* used to tell if break or delete is hit + * while executing a wait */ +extern int eflag; + + +/* + * Find out if it is time to go away. + * `trapnote' is set to SIGSET when fault is seen and + * no trap has been set. + */ + +#define sigchk() if (trapnote & SIGSET) \ + exitsh(exitval ? exitval : SIGFAIL) + +#define exitset() retval = exitval + +#define ENDPATH 27 /* see msg.c/defpath */ diff --git a/src/cmd/sh/dup.h b/src/cmd/sh/dup.h new file mode 100644 index 0000000..7203ca3 --- /dev/null +++ b/src/cmd/sh/dup.h @@ -0,0 +1,8 @@ +/* + * UNIX shell + * + * S. R. Bourne + * Bell Telephone Laboratories + */ +#define DUPFLG 0100 +#define EXCLOSE 1 diff --git a/src/cmd/sh/echo.c b/src/cmd/sh/echo.c new file mode 100644 index 0000000..c7c1c15 --- /dev/null +++ b/src/cmd/sh/echo.c @@ -0,0 +1,88 @@ +/* + * UNIX shell + * + * Bell Telephone Laboratories + */ +#include "defs.h" + +#define Exit(a) flushb();return(a) + +extern int exitval; + +echo(argc, argv) +char **argv; +{ + register char *cp; + register int i, wd; + int j; + int nonl = 0; /* echo -n */ + + if(--argc == 0) { + prc_buff('\n'); + Exit(0); + } + + if ( cf(argv[1], "-n" ) == 0 ){ + nonl++; + argv++; + argc--; + } + + for(i = 1; i <= argc; i++) + { + sigchk(); + for(cp = argv[i]; *cp; cp++) + { + if(*cp == '\\') + switch(*++cp) + { + case 'b': + prc_buff('\b'); + continue; + + case 'c': + Exit(0); + + case 'f': + prc_buff('\f'); + continue; + + case 'n': + prc_buff('\n'); + continue; + + case 'r': + prc_buff('\r'); + continue; + + case 't': + prc_buff('\t'); + continue; + + case 'v': + prc_buff('\v'); + continue; + + case '\\': + prc_buff('\\'); + continue; + case '\0': + j = wd = 0; + while ((*++cp >= '0' && *cp <= '7') && j++ < 3) { + wd <<= 3; + wd |= (*cp - '0'); + } + prc_buff(wd); + --cp; + continue; + + default: + cp--; + } + prc_buff(*cp); + } + if( nonl ) prc_buff( ' ' ); + else prc_buff(i == argc? '\n': ' '); + } + Exit(0); +} diff --git a/src/cmd/sh/error.c b/src/cmd/sh/error.c new file mode 100644 index 0000000..662c26c --- /dev/null +++ b/src/cmd/sh/error.c @@ -0,0 +1,96 @@ +/* + * UNIX shell + * + * Bell Telephone Laboratories + */ +#include "defs.h" + +/* ======== error handling ======== */ + +failed(s1, s2) +char *s1, *s2; +{ + prp(); + prs_cntl(s1); + if (s2) + { + prs(colon); + prs(s2); + } + newline(); + exitsh(ERROR); +} + +error(s) +char *s; +{ + failed(s, NIL); +} + +exitsh(xno) +int xno; +{ + /* + * Arrive here from `FATAL' errors + * a) exit command, + * b) default trap, + * c) fault with no trap set. + * + * Action is to return to command level or exit. + */ + exitval = xno; + flags |= eflag; + if ((flags & (forked | errflg | ttyflg)) != ttyflg) + done(); + else + { + clearup(); + restore(0); + clear_buff(); + execbrk = breakcnt = funcnt = 0; + longjmp(errshell, 1); + } +} + +void +done() +{ + register char *t; + + if (t = trapcom[0]) + { + trapcom[0] = NIL; + execexp(t, 0); + free(t); + } + else + chktrap(); + + rmtemp(NIL); + rmfunctmp(); + +#ifdef ACCOUNT + doacct(); +#endif + exit(exitval); +} + +rmtemp(base) +struct ionod *base; +{ + while (iotemp > base) + { + unlink(iotemp->ioname); + free(iotemp->iolink); + iotemp = iotemp->iolst; + } +} + +rmfunctmp() +{ + while (fiotemp) + { + unlink(fiotemp->ioname); + fiotemp = fiotemp->iolst; + } +} diff --git a/src/cmd/sh/expand.c b/src/cmd/sh/expand.c new file mode 100644 index 0000000..3d05352 --- /dev/null +++ b/src/cmd/sh/expand.c @@ -0,0 +1,356 @@ +/* + * UNIX shell + * + * Bell Telephone Laboratories + */ +#include "defs.h" +#include +#include +#include + +struct direct *getdir(); + +static char entry[MAXNAMLEN+1]; + +static DIR dirbuf; + +#define XXX 0200 + +static int +addg(as1, as2, as3) +char *as1, *as2, *as3; +{ + register char *s1, *s2; + register int c; + + s2 = locstak() + BYTESPERWORD; + s1 = as1; + while (c = /* @@@ *s1++ */ cii(*s1++)) + { + if (/* @@@ (c &= STRIP)*/ (c=smask(c)) == 0) + { + *s2++ = '/'; + break; + } + *s2++ = c; + } + s1 = as2; + while (*s2 = *s1++) + s2++; + if (s1 = as3) + { + *s2++ = '/'; + while (*s2++ = *++s1); + } + makearg(endstak(s2)); +} + +/* + * globals (file name generation) + * + * "*" in params matches r.e ".*" + * "?" in params matches r.e. "." + * "[...]" in params matches character class + * "[...a-z...]" in params matches a through z. + * + */ +expand(as, rcnt) + char *as; +{ + int count, dirf; + BOOL dir = 0; + char *rescan = NIL; + register char *s, *cs; + struct argnod *schain = gchain; + struct stat statb; + BOOL slash; + + if (trapnote & SIGSET) + return(0); + s = cs = as; + + /* + * check for meta chars + */ + { + register BOOL open; + + slash = 0; + open = 0; + do + { + switch (*cs++) + { + case 0: + if (rcnt && slash) + break; + else + return(0); + + case '/': + slash++; + open = 0; + continue; + + case '[': + open++; + continue; + + case ']': + if (open == 0) + continue; + + case '?': + case '*': + if (rcnt > slash) + continue; + else + cs--; + break; + + + default: + continue; + } + break; + } while (TRUE); + } + + for (;;) + { + if (cs == s) + { + s = nullstr; + break; + } + else if (*--cs == '/') + { + *cs = 0; + if (s == cs) + s = "/"; + break; + } + } + + if ((dirf = open(*s ? s : ".", 0)) > 0) + { + if (fstat(dirf, &statb) != -1 && + (statb.st_mode & S_IFMT) == S_IFDIR) + dir++; + else + close(dirf); + } + + count = 0; + if (*cs == 0) + *cs++ = XXX; + if (dir) /* check for rescan */ + { + register char *rs; + struct direct *e; + + rs = cs; + do + { + if (*rs == '/') + { + rescan = rs; + *rs = 0; + gchain = NIL; + } + } while (*rs++); + + while ((e = getdir(dirf)) && (trapnote & SIGSET) == 0) + { + *(movstrn(e->d_name, entry, MAXNAMLEN)) = 0; + + if (entry[0] == '.' && *cs != '.') +#ifndef BOURNE + continue; +#else + { + if (entry[1] == 0) + continue; + if (entry[1] == '.' && entry[2] == 0) + continue; + } +#endif + + if (gmatch(entry, cs)) + { + addg(s, entry, rescan); + count++; + } + } + close(dirf); + reset_dir(); + + if (rescan) + { + register struct argnod *rchain; + + rchain = gchain; + gchain = schain; + if (count) + { + count = 0; + while (rchain) + { + count += expand(rchain->argval, slash + 1); + rchain = rchain->argnxt; + } + } + *rescan = '/'; + } + } + + { + register char c; + + s = as; + while (c = *s) + /* @@@ *s++ = (c & STRIP ? c : '/'); */ + *s++ = smask(c) ? c: '/'; + } + return(count); +} + + +reset_dir() +{ + dirbuf.dd_loc = 0; +} + + +/* + * read next directory entry + * and ignore inode == 0 + * + */ + +struct direct * +getdir(dirf) +{ + struct direct *dp; + for (;;) { + if (dirbuf.dd_loc == 0) { + dirbuf.dd_size = read(dirf, dirbuf.dd_buf, + DIRBLKSIZ); + if (dirbuf.dd_size <= 0) + return NULL; + } + if (dirbuf.dd_loc >= dirbuf.dd_size) { + dirbuf.dd_loc = 0; + continue; + } + dp = (struct direct *)(dirbuf.dd_buf + dirbuf.dd_loc); + if (dp->d_reclen <= 0 || + dp->d_reclen > DIRBLKSIZ + 1 - dirbuf.dd_loc) + return NULL; + dirbuf.dd_loc += dp->d_reclen; + if (dp->d_ino == 0) + continue; + return (dp); + } +} + + +gmatch(s, p) +register char *s, *p; +{ + register int scc; + char c; + + if (scc = /* @@@ *s++ */ cii( *s++)) + { + if ( /* @@@ (scc &= STRIP) */ smask(scc) == 0) + scc=XXX; + } + switch (c = /* @@@ *p++ */ cii( *p++) ) + { + case '[': + { + BOOL ok; + int lc; + int notflag = 0; + + ok = 0; + lc = 077777; + if (*p == '!') + { + notflag = 1; + p++; + } + while (c = /* @@@ *p++ */ cii(*p++)) + { + if (c == ']') + return(ok ? gmatch(s, p) : 0); + else if (c == MINUS) + { + if (notflag) + { + if (scc < lc || scc > *p++) + ok++; + else + return(0); + } + else + { + if (lc <= scc && scc <= *p++) + ok++; + } + } + else + { + /* @@@ lc = c & STRIP; */ + lc = ismask(c); + + if (notflag) + { + if (scc && scc != lc) + ok++; + else + return(0); + } + else + { + if (scc == lc) + ok++; + } + } + } + return(0); + } + + default: + if (/* @@@ (c & STRIP)*/ ismask(c) != scc) + return(0); + + case '?': + return(scc ? gmatch(s, p) : 0); + + case '*': + while (*p == '*') + p++; + + if (*p == 0) + return(1); + --s; + while (*s) + { + if (gmatch(s++, p)) + return(1); + } + return(0); + + case 0: + return(scc == 0); + } +} + +makearg(args) + register struct argnod *args; +{ + args->argnxt = gchain; + gchain = args; +} diff --git a/src/cmd/sh/fault.c b/src/cmd/sh/fault.c new file mode 100644 index 0000000..9fad232 --- /dev/null +++ b/src/cmd/sh/fault.c @@ -0,0 +1,203 @@ +/* + * UNIX shell + * + * Bell Telephone Laboratories + */ +#include "defs.h" + +char *trapcom[MAXTRAP]; + +BOOL trapflg[MAXTRAP] = +{ + 0, + 0, /* 1 hangup */ + 0, /* 2 interrupt */ + 0, /* 3 quit */ + 0, /* 4 illegal instr */ + 0, /* 5 trace trap */ + 0, /* 6 IOT */ + 0, /* 7 EMT */ + 0, /* 8 float pt. exp */ + 0, /* 9 kill */ + 0, /* 10 bus error */ + 0, /* 11 memory faults */ + 0, /* 12 bad sys call */ + 0, /* 13 bad pipe call */ + 0, /* 14 alarm */ + 0, /* 15 software termination */ + 0, /* 16 urgent */ + 0, /* 17 stop */ + 0, /* 18 tstp */ + 0, /* 19 cont */ + 0, /* 20 death or stop of child */ + 0, /* 21 ttin */ + 0, /* 22 ttou */ + 0, /* 23 tint */ +}; + +void (*sigval[])() = { + 0, + done, + fault, + fault, + done, + done, + abort, + done, + done, + SIG_DFL, + done, + done, + done, + done, + fault, + fault, + done, + SIG_DFL, + SIG_DFL, + SIG_DFL, + done, + SIG_DFL, + SIG_DFL, + SIG_DFL, +}; + +/* ======== fault handling routines ======== */ + +void +fault(sig) +register int sig; +{ + register int flag; + + signal(sig, fault); + if (sig == SIGSEGV) + { + if (setbrk(brkincr) == -1) + error(nospace); + } + else if (sig == SIGALRM) + { + if (flags & waiting) + done(); + } + else + { + flag = (trapcom[sig] ? TRAPSET : SIGSET); + trapnote |= flag; + trapflg[sig] |= flag; + if (sig == SIGINT) + wasintr++; + } +} + +stdsigs() +{ + setsig(SIGHUP); + setsig(SIGINT); + ignsig(SIGQUIT); + setsig(SIGILL); + setsig(SIGTRAP); + setsig(SIGIOT); + setsig(SIGEMT); + setsig(SIGFPE); + setsig(SIGBUS); + signal(SIGSEGV, fault); + setsig(SIGSYS); + setsig(SIGPIPE); + setsig(SIGALRM); + setsig(SIGTERM); +#ifdef SIGUSR1 + setsig(SIGUSR1); +#endif +#ifdef SIGUSR2 + setsig(SIGUSR2); +#endif +} + +ignsig(n) +{ + register int s, i; + + if ((i = n) == SIGSEGV) + { + clrsig(i); + failed(badtrap, "cannot trap 11"); + } + else if ((s = (signal(i, SIG_IGN) == SIG_IGN)) == 0) + { + trapflg[i] |= SIGMOD; + } + return(s); +} + +getsig(n) +{ + register int i; + + if (trapflg[i = n] & SIGMOD || ignsig(i) == 0) + signal(i, fault); +} + + +setsig(n) +{ + register int i; + + if (ignsig(i = n) == 0) + signal(i, sigval[i]); +} + +oldsigs() +{ + register int i; + register char *t; + + i = MAXTRAP; + while (i--) + { + t = trapcom[i]; + if (t == NIL || *t) + clrsig(i); + trapflg[i] = 0; + } + trapnote = 0; +} + +clrsig(i) +int i; +{ + free(trapcom[i]); + trapcom[i] = NIL; + if (trapflg[i] & SIGMOD) + { + trapflg[i] &= ~SIGMOD; + signal(i, sigval[i]); + } +} + +/* + * check for traps + */ +chktrap() +{ + register int i = MAXTRAP; + register char *t; + + trapnote &= ~TRAPSET; + while (--i) + { + if (trapflg[i] & TRAPSET) + { + trapflg[i] &= ~TRAPSET; + if (t = trapcom[i]) + { + int savxit = exitval; + + execexp(t, 0); + exitval = savxit; + exitset(); + } + } + } +} diff --git a/src/cmd/sh/func.c b/src/cmd/sh/func.c new file mode 100644 index 0000000..f77e4b8 --- /dev/null +++ b/src/cmd/sh/func.c @@ -0,0 +1,380 @@ +/* + * UNIX shell + * + * Bell Telephone Laboratories + */ +#include "defs.h" + +freefunc(n) + struct namnod *n; +{ + freetree((struct trenod *)(n->namenv)); +} + + +freetree(t) + register struct trenod *t; +{ + if (t) + { + register int type; + + if (t->tretyp & CNTMSK) + { + t->tretyp--; + return; + } + + type = t->tretyp & COMMSK; + + switch (type) + { + case TFND: + free(fndptr(t)->fndnam); + freetree(fndptr(t)->fndval); + break; + + case TCOM: + freeio(comptr(t)->comio); + free_arg(comptr(t)->comarg); + free_arg(comptr(t)->comset); + break; + + case TFORK: + freeio(forkptr(t)->forkio); + freetree(forkptr(t)->forktre); + break; + + case TPAR: + freetree(parptr(t)->partre); + break; + + case TFIL: + case TLST: + case TAND: + case TORF: + freetree(lstptr(t)->lstlef); + freetree(lstptr(t)->lstrit); + break; + + case TFOR: + { + struct fornod *f = (struct fornod *)t; + + free(f->fornam); + freetree(f->fortre); + if (f->forlst) + { + freeio(f->forlst->comio); + free_arg(f->forlst->comarg); + free_arg(f->forlst->comset); + free(f->forlst); + } + } + break; + + case TWH: + case TUN: + freetree(whptr(t)->whtre); + freetree(whptr(t)->dotre); + break; + + case TIF: + freetree(ifptr(t)->iftre); + freetree(ifptr(t)->thtre); + freetree(ifptr(t)->eltre); + break; + + case TSW: + free(swptr(t)->swarg); + freereg(swptr(t)->swlst); + break; + } + free(t); + } +} + +free_arg(argp) + register struct argnod *argp; +{ + register struct argnod *sav; + + while (argp) + { + sav = argp->argnxt; + free(argp); + argp = sav; + } +} + + +freeio(iop) + register struct ionod *iop; +{ + register struct ionod *sav; + + while (iop) + { + if (iop->iofile & IODOC) + { + +#ifdef DEBUG + prs("unlinking "); + prs(iop->ioname); + newline(); +#endif + + unlink(iop->ioname); + + if (fiotemp == iop) + fiotemp = iop->iolst; + else + { + struct ionod *fiop = fiotemp; + + while (fiop->iolst != iop) + fiop = fiop->iolst; + + fiop->iolst = iop->iolst; + } + } + free(iop->ioname); + free(iop->iolink); + sav = iop->ionxt; + free(iop); + iop = sav; + } +} + + +freereg(regp) + register struct regnod *regp; +{ + register struct regnod *sav; + + while (regp) + { + free_arg(regp->regptr); + freetree(regp->regcom); + sav = regp->regnxt; + free(regp); + regp = sav; + } +} + + +prf(t) + register struct trenod *t; +{ + sigchk(); + + if (t) + { + register int type; + + type = t->tretyp & COMMSK; + + switch(type) + { + case TFND: + { + register struct fndnod *f = (struct fndnod *)t; + + prs_buff(f->fndnam); + prs_buff("(){\n"); + prf(f->fndval); + prs_buff("\n}"); + break; + } + + case TCOM: + { + prarg(comptr(t)->comset); + prarg(comptr(t)->comarg); + prio(comptr(t)->comio); + break; + } + + case TFORK: + prf(forkptr(t)->forktre); + prio(forkptr(t)->forkio); + if (forkptr(t)->forktyp & FAMP) + prs_buff(" &"); + break; + + case TPAR: + prs_buff("( "); + prf(parptr(t)->partre); + prs_buff(" )"); + break; + + case TFIL: + prf(lstptr(t)->lstlef); + prs_buff(" | "); + prf(lstptr(t)->lstrit); + break; + + case TLST: + prf(lstptr(t)->lstlef); + prc_buff(NL); + prf(lstptr(t)->lstrit); + break; + + case TAND: + prf(lstptr(t)->lstlef); + prs_buff(" && "); + prf(lstptr(t)->lstrit); + break; + + case TORF: + prf(lstptr(t)->lstlef); + prs_buff(" || "); + prf(lstptr(t)->lstrit); + break; + + case TFOR: + { + register struct argnod *arg; + register struct fornod *f = (struct fornod *)t; + + prs_buff("for "); + prs_buff(f->fornam); + + if (f->forlst) + { + arg = f->forlst->comarg; + prs_buff(" in"); + + while(arg != ENDARGS) + { + prc_buff(SP); + prs_buff(arg->argval); + arg = arg->argnxt; + } + } + + prs_buff("\ndo\n"); + prf(f->fortre); + prs_buff("\ndone"); + } + break; + + case TWH: + case TUN: + if (type == TWH) + prs_buff("while "); + else + prs_buff("until "); + prf(whptr(t)->whtre); + prs_buff("\ndo\n"); + prf(whptr(t)->dotre); + prs_buff("\ndone"); + break; + + case TIF: + { + struct ifnod *f = (struct ifnod *)t; + + prs_buff("if "); + prf(f->iftre); + prs_buff("\nthen\n"); + prf(f->thtre); + + if (f->eltre) + { + prs_buff("\nelse\n"); + prf(f->eltre); + } + + prs_buff("\nfi"); + break; + } + + case TSW: + { + register struct regnod *swl; + + prs_buff("case "); + prs_buff(swptr(t)->swarg); + + swl = swptr(t)->swlst; + while(swl) + { + struct argnod *arg = swl->regptr; + + if (arg) + { + prs_buff(arg->argval); + arg = arg->argnxt; + } + + while(arg) + { + prs_buff(" | "); + prs_buff(arg->argval); + arg = arg->argnxt; + } + + prs_buff(")"); + prf(swl->regcom); + prs_buff(";;"); + swl = swl->regnxt; + } + } + break; + } + } + + sigchk(); +} + +prarg(argp) + register struct argnod *argp; +{ + while (argp) + { + prs_buff(argp->argval); + prc_buff(SP); + argp=argp->argnxt; + } +} + + +prio(iop) + register struct ionod *iop; +{ + register int iof; + register char *ion; + + while (iop) + { + iof = iop->iofile; + ion = iop->ioname; + + if (*ion) + { + prn_buff(iof & IOUFD); + + if (iof & IODOC) + prs_buff("<<"); + else if (iof & IOMOV) + { + if (iof & IOPUT) + prs_buff(">&"); + else + prs_buff("<&"); + + } + else if ((iof & IOPUT) == 0) + prc_buff('<'); + else if (iof & IOAPP) + prs_buff(">>"); + else + prc_buff('>'); + + prs_buff(ion); + prc_buff(SP); + } + iop = iop->ionxt; + } +} diff --git a/src/cmd/sh/hash.c b/src/cmd/sh/hash.c new file mode 100644 index 0000000..7abe2e1 --- /dev/null +++ b/src/cmd/sh/hash.c @@ -0,0 +1,144 @@ +#include "hash.h" +#include "defs.h" + +#define STRCMP(A, B) (cf(A, B) != 0) +#define FACTOR 035761254233 /* Magic multiplication factor */ +#define TABLENGTH 64 /* must be multiple of 2 */ +#define LOG2LEN 6 /* log2 of TABLENGTH */ + +/* + NOTE: The following algorithm only works on machines where + the results of multiplying two integers is the least + significant part of the double word integer required to hold + the result. It is adapted from Knuth, Volume 3, section 6.4. +*/ + +#define hash(str) (int) (((unsigned) (crunch(str) * FACTOR)) >> shift) + +struct node +{ + ENTRY item; + struct node *Next; +}; + +static struct node **last; +static struct node *next; +static struct node **table; + +static unsigned int bitsper; /* Bits per byte */ +static unsigned int shift; + +static unsigned int crunch(); + +hcreate() +{ +#ifdef NOTDEF + unsigned char c = ~0; /* A byte full of 1's */ +#endif + int j; + + table = (struct node **) alloc(TABLENGTH * sizeof(struct node *)); + + for (j=0; j < TABLENGTH; ++j) + { + table[j] = (struct node *)NIL; + } + + bitsper = 0; /* чиÑло битов в байте */ +#ifdef NOTDEF + while (c) + { + c >>= 1; + bitsper++; + } + +#else + bitsper = 8; +#endif + shift = (bitsper * sizeof(int)) - LOG2LEN; +} + + +void hscan(uscan) + void (*uscan)(); +{ + struct node *p, *nxt; + int j; + + for (j=0; j < TABLENGTH; ++j) + { + p = table[j]; + while (p) + { + nxt = p->Next; + (*uscan)(&p->item); + p = nxt; + } + } +} + + + +ENTRY * +hfind(str) + char *str; +{ + struct node *p; + struct node **q; + unsigned int i; + int res; + + i = hash(str); + + if(table[i] == NIL) + { + last = &table[i]; + next = NIL; + return(NIL); + } + else + { + q = &table[i]; + p = table[i]; + while (p != NIL && (res = STRCMP(str, p->item.key))) + { + q = &(p->Next); + p = p->Next; + } + + if (p != NIL && res == 0) + return(&(p->item)); + else + { + last = q; + next = p; + return(NIL); + } + } +} + +ENTRY * +henter(item) + ENTRY item; +{ + struct node *p = (struct node *)alloc(sizeof(struct node)); + + p->item = item; + *last = p; + p->Next = next; + return(&(p->item)); +} + + +static unsigned int +crunch(key) + char *key; +{ + unsigned int sum = 0; + int s; + + for (s = 0; *key; s++) /* Simply add up the bytes */ + sum += *key++; + + return(sum + s); +} diff --git a/src/cmd/sh/hash.h b/src/cmd/sh/hash.h new file mode 100644 index 0000000..855c5db --- /dev/null +++ b/src/cmd/sh/hash.h @@ -0,0 +1,34 @@ +/* + * UNIX shell + * + * Bell Telephone Laboratories + * + */ + +#define HASHZAP 0x03FF +#define CDMARK 0x8000 + +#define NOTFOUND 0x0000 +#define BUILTIN 0x0100 +#define FUNCTION 0x0200 +#define COMMAND 0x0400 +#define REL_COMMAND 0x0800 +#define PATH_COMMAND 0x1000 +#define DOT_COMMAND 0x8800 /* CDMARK | REL_COMMAND */ + +#define hashtype(x) (x & 0x1F00) +#define hashdata(x) (x & 0x00FF) + + +typedef struct entry +{ + char *key; + short data; + char hits; + char cost; + struct entry *next; +} ENTRY; + +extern ENTRY *hfind(); +extern ENTRY *henter(); +extern int hcreate(); diff --git a/src/cmd/sh/hashserv.c b/src/cmd/sh/hashserv.c new file mode 100644 index 0000000..c5a294b --- /dev/null +++ b/src/cmd/sh/hashserv.c @@ -0,0 +1,467 @@ +/* + * UNIX shell + * + * Bell Telephone Laboratories + */ +#include "hash.h" +#include "defs.h" +#include +#include +#include + +#define EXECUTE 01 + +static char cost; +static int dotpath; +static int multrel; +static struct entry *relcmd = NIL; + +static int +argpath(arg) + register struct argnod *arg; +{ + register char *s; + register char *start; + + while (arg) + { + s = arg->argval; + start = s; + + if (letter(*s)) + { + while (alphanum(*s)) + s++; + + if (*s == '=') + { + *s = 0; + + if (eq(start, pathname)) + { + *s = '='; + return(1); + } + else + *s = '='; + } + } + arg = arg->argnxt; + } + + return(0); +} + +short +pathlook(com, flg, arg) + char *com; + int flg; + register struct argnod *arg; +{ + register char *name = com; + register ENTRY *h; + + ENTRY hentry; + int count = 0; + int i; + int pathset = 0; + int oldpath = 0; + struct namnod *n; + + + hentry.data = 0; + + if (any('/', name)) + return(COMMAND); + + h = hfind(name); + + if (h) + { + if (h->data & (BUILTIN | FUNCTION)) + { + if (flg) + h->hits++; + return(h->data); + } + + if (arg && (pathset = argpath(arg))) + return(PATH_COMMAND); + + if ((h->data & DOT_COMMAND) == DOT_COMMAND) + { + if (multrel == 0 && hashdata(h->data) > dotpath) + oldpath = hashdata(h->data); + else + oldpath = dotpath; + + h->data = 0; + goto pathsrch; + } + + if (h->data & (COMMAND | REL_COMMAND)) + { + if (flg) + h->hits++; + return(h->data); + } + + h->data = 0; + h->cost = 0; + } + + if (i = syslook(name, commands, no_commands)) + { + hentry.data = (BUILTIN | i); + count = 1; + } + else + { + if (arg && (pathset = argpath(arg))) + return(PATH_COMMAND); +pathsrch: + count = findpath(name, oldpath); + } + + if (count > 0) + { + if (h == NIL) + { + hentry.cost = 0; + hentry.key = make(name); + h = henter(hentry); + } + + if (h->data == 0) + { + if (count < dotpath) + h->data = COMMAND | count; + else + { + h->data = REL_COMMAND | count; + h->next = relcmd; + relcmd = h; + } + } + + + h->hits = flg; + h->cost += cost; + return(h->data); + } + else + { + return(-count); + } +} + + +static void +zapentry(h) + ENTRY *h; +{ + h->data &= HASHZAP; +} + +void +zaphash() +{ + hscan(zapentry); + relcmd = 0; +} + +void +zapcd() +{ + while (relcmd) + { + relcmd->data |= CDMARK; + relcmd = relcmd->next; + } +} + + +static void +hashout(h) + ENTRY *h; +{ + sigchk(); + + if (hashtype(h->data) == NOTFOUND) + return; + + if (h->data & (BUILTIN | FUNCTION)) + return; + + prn_buff(h->hits); + + if (h->data & REL_COMMAND) + prc_buff('*'); + + + prc_buff(TAB); + prn_buff(h->cost); + prc_buff(TAB); + + pr_path(h->key, hashdata(h->data)); + prc_buff(NL); +} + +void +hashpr() +{ + prs_buff("hits cost command\n"); + hscan(hashout); +} + + +set_dotpath() +{ + register char *path; + register int cnt = 1; + + dotpath = 10000; + path = getpath(""); + + while (path && *path) + { + if (*path == '/') + cnt++; + else + { + if (dotpath == 10000) + dotpath = cnt; + else + { + multrel = 1; + return; + } + } + + path = nextpath(path); + } + + multrel = 0; +} + + +hash_func(name) + char *name; +{ + ENTRY *h; + ENTRY hentry; + + h = hfind(name); + + if (h) + { + + if (h->data & (BUILTIN | FUNCTION)) + return; + else + h->data = FUNCTION; + } + else + { + int i; + + if (i = syslook(name, commands, no_commands)) + hentry.data = (BUILTIN | i); + else + hentry.data = FUNCTION; + + hentry.key = make(name); + hentry.cost = 0; + hentry.hits = 0; + + henter(hentry); + } +} + +func_unhash(name) + char *name; +{ + ENTRY *h; + + h = hfind(name); + + if (h && (h->data & FUNCTION)) + h->data = NOTFOUND; +} + + +short +hash_cmd(name) + char *name; +{ + ENTRY *h; + + if (any('/', name)) + return(COMMAND); + + h = hfind(name); + + if (h) + { + if (h->data & (BUILTIN | FUNCTION)) + return(h->data); + else + zapentry(h); + } + + return(pathlook(name, 0, NIL)); +} + + +what_is_path(name) + register char *name; +{ + register ENTRY *h; + int cnt; + short hashval; + + h = hfind(name); + + prs_buff(name); + if (h) + { + hashval = hashdata(h->data); + + switch (hashtype(h->data)) + { + case BUILTIN: + prs_buff(" is a shell builtin\n"); + return; + + case FUNCTION: + { + struct namnod *n = lookup(name); + + prs_buff(" is a function\n"); + prs_buff(name); + prs_buff("(){\n"); + prf(n->namenv); + prs_buff("\n}\n"); + return; + } + + case REL_COMMAND: + { + short hash; + + if ((h->data & DOT_COMMAND) == DOT_COMMAND) + { + hash = pathlook(name, 0, NIL); + if (hashtype(hash) == NOTFOUND) + { + prs_buff(" not found\n"); + return; + } + else + hashval = hashdata(hash); + } + } + + case COMMAND: + prs_buff(" is hashed ("); + pr_path(name, hashval); + prs_buff(")\n"); + return; + } + } + + if (syslook(name, commands, no_commands)) + { + prs_buff(" is a shell builtin\n"); + return; + } + + if ((cnt = findpath(name, 0)) > 0) + { + prs_buff(" is "); + pr_path(name, cnt); + prc_buff(NL); + } + else + prs_buff(" not found\n"); +} + + +findpath(name, oldpath) + register char *name; + int oldpath; +{ + register char *path; + register int count = 1; + + char *p; + int ok = 1; + int e_code = 1; + + cost = 0; + path = getpath(name); + + if (oldpath) + { + count = dotpath; + while (--count) + path = nextpath(path); + + if (oldpath > dotpath) + { + catpath(path, name); + p = curstak(); + cost = 1; + + if ((ok = chk_access(p)) == 0) + return(dotpath); + else + return(oldpath); + } + else + count = dotpath; + } + + while (path) + { + path = catpath(path, name); + cost++; + p = curstak(); + + if ((ok = chk_access(p)) == 0) + break; + else + e_code = max(e_code, ok); + + count++; + } + + return(ok ? -e_code : count); +} + + +chk_access(name) + register char *name; +{ + + if (access(name, EXECUTE) == 0) + return(0); + + return(errno == EACCES ? 3 : 1); +} + + +pr_path(name, count) + register char *name; + int count; +{ + register char *path; + + path = getpath(name); + + while (--count && path) + path = nextpath(path, name); + + catpath(path, name); + prs_buff(curstak()); +} diff --git a/src/cmd/sh/io.c b/src/cmd/sh/io.c new file mode 100644 index 0000000..2a3ad90 --- /dev/null +++ b/src/cmd/sh/io.c @@ -0,0 +1,313 @@ +/* + * UNIX shell + * + * Bell Telephone Laboratories + */ +#include "defs.h" +#include "dup.h" +#include +#include + +short topfd; + +/* ======== input output and file copying ======== */ + +initf(fd) +int fd; +{ + register struct fileblk *f = standin; + + f->fdes = fd; + f->fsiz = ((flags & oneflg) == 0 ? BUFSIZ : 1); + f->fnxt = f->fend = f->fbuf; + f->feval = (char **)NIL; + f->flin = 1; + f->feof = FALSE; +} + +estabf(s) +register char *s; +{ + register struct fileblk *f; + + (f = standin)->fdes = -1; + f->fend = length(s) + (f->fnxt = s); + f->flin = 1; + return(f->feof = (s == NIL)); +} + +push(af) +struct fileblk *af; +{ + register struct fileblk *f; + + (f = af)->fstak = standin; + f->feof = 0; + f->feval = (char **)NIL; + standin = f; +} + +pop() +{ + register struct fileblk *f; + + if ((f = standin)->fstak) + { + if (f->fdes >= 0) + close(f->fdes); + standin = f->fstak; + return(TRUE); + } + else + return(FALSE); +} + +struct tempblk *tmpfptr; + +pushtemp(fd,tb) + int fd; + struct tempblk *tb; +{ + tb->fdes = fd; + tb->Fstak = tmpfptr; + tmpfptr = tb; +} + +poptemp() +{ + if (tmpfptr) + { + close(tmpfptr->fdes); + tmpfptr = tmpfptr->Fstak; + return(TRUE); + } + else + return(FALSE); +} + +chkpipe(pv) +int *pv; +{ + if (pipe(pv) < 0 || pv[INPIPE] < 0 || pv[OTPIPE] < 0) + error(piperr); +} + +chkopen(idf) +char *idf; +{ + register int rc; + + if ((rc = open(idf, 0)) < 0) + failed(idf, badopen); + else + return(rc); +} + +rename(f1, f2) +register int f1, f2; +{ +#if defined(RES) || defined(pdp11) + if (f1 != f2) + { + dup(f1 | DUPFLG, f2); + close(f1); + if (f2 == 0) + ioset |= 1; + } +#else + int fs; + + if (f1 != f2) + { + fs = fcntl(f2, F_GETFD, 0); + close(f2); + fcntl(f1, F_DUPFD, f2); + close(f1); + if (fs == 1) + fcntl(f2, F_SETFD, EXCLOSE); + if (f2 == 0) + ioset |= 1; + } +#endif +} + +create(s) +char *s; +{ + register int rc; + + if ((rc = creat(s, 0666)) < 0) + failed(s, badcreate); + else + return(rc); +} + +tmpfil(tb) + struct tempblk *tb; +{ + int fd; + + itos(serial++); + movstr(numbuf, tmpnam); + fd = create(tmpout); + pushtemp(fd,tb); + return(fd); +} + +/* + * set by trim + */ +extern BOOL nosubst; +#define CPYSIZ 512 + +copy(ioparg) +struct ionod *ioparg; +{ + register char *cline; + register char *clinep; + register struct ionod *iop; + char c; + char *ends; + char *start; + int fd; + int i; + int stripflg; + + + if (iop = ioparg) + { + struct tempblk tb; + + copy(iop->iolst); + ends = mactrim(iop->ioname); + stripflg = iop->iofile & IOSTRIP; + if (nosubst) + iop->iofile &= ~IODOC; + fd = tmpfil(&tb); + + if (fndef) + iop->ioname = make(tmpout); + else + iop->ioname = cpystak(tmpout); + + iop->iolst = iotemp; + iotemp = iop; + + cline = clinep = start = locstak(); + if (stripflg) + { + iop->iofile &= ~IOSTRIP; + while (*ends == '\t') + ends++; + } + for (;;) + { + chkpr(); + if (nosubst) + { + c = readc(); + if (stripflg) + while (c == '\t') + c = readc(); + + while (!eolchar(c)) + { + *clinep++ = c; + c = readc(); + } + } + else + { + c = nextc(*ends); + if (stripflg) + while (c == '\t') + c = nextc(*ends); + + while (!eolchar(c)) + { + *clinep++ = c; + c = nextc(*ends); + } + } + + *clinep = 0; + if (eof || eq(cline, ends)) + { + if ((i = cline - start) > 0) + write(fd, start, i); + break; + } + else + *clinep++ = NL; + + if ((i = clinep - start) < CPYSIZ) + cline = clinep; + else + { + write(fd, start, i); + cline = clinep = start; + } + } + + poptemp(); /* pushed in tmpfil -- bug fix for problem + deleting in-line scripts */ + } +} + + +link_iodocs(i) + struct ionod *i; +{ + while(i) + { + free(i->iolink); + + itos(serial++); + movstr(numbuf, tmpnam); + i->iolink = make(tmpout); + link(i->ioname, i->iolink); + + i = i->iolst; + } +} + + +swap_iodoc_nm(i) + struct ionod *i; +{ + while(i) + { + free(i->ioname); + i->ioname = i->iolink; + i->iolink = NIL; + + i = i->iolst; + } +} + + +savefd(fd) + int fd; +{ + register int f; + + f = fcntl(fd, F_DUPFD, 10); + return(f); +} + + +restore(last) + register int last; +{ + register int i; + register int dupfd; + + for (i = topfd - 1; i >= last; i--) + { + if ((dupfd = fdmap[i].dup_fd) > 0) + rename(dupfd, fdmap[i].org_fd); + else + close(fdmap[i].org_fd); + } + topfd = last; +} diff --git a/src/cmd/sh/mac.h b/src/cmd/sh/mac.h new file mode 100644 index 0000000..241e060 --- /dev/null +++ b/src/cmd/sh/mac.h @@ -0,0 +1,26 @@ +/* + * UNIX shell + * + * Bell Telephone Laboratories + */ + +#define TRUE (-1) +#define FALSE 0 +#define LOBYTE 0377 +#define STRIP 0177 +#define QUOTE 0200 + +#define EOF 0 +#define NL '\n' +#define SP ' ' +#define LQ '`' +#define RQ '\'' +#define MINUS '-' +#define COLON ':' +#define TAB '\t' + +#define MAX(a,b) ((a)>(b)?(a):(b)) + +#define blank() prc(SP) +#define tab() prc(TAB) +#define newline() prc(NL) diff --git a/src/cmd/sh/macro.c b/src/cmd/sh/macro.c new file mode 100644 index 0000000..6534f7e --- /dev/null +++ b/src/cmd/sh/macro.c @@ -0,0 +1,340 @@ +/* + * UNIX shell + * + * Bell Telephone Laboratories + */ +#include "defs.h" +#include "sym.h" + +static char quote; /* used locally */ +static char quoted; /* used locally */ + +static int getch(); + +static char * +copyto(endch) +register char endch; +{ + register char c; + + while ((c = getch(endch)) != endch && c) + pushstak( quote ? qmask(c) : c ); /* c | quote @@@ */ + zerostak(); + if (c != endch) + error(badsub); +} + +static +skipto(endch) +register char endch; +{ + /* + * skip chars up to } + */ + register char c; + + while ((c = readc()) && c != endch) + { + switch (c) + { + case SQUOTE: + skipto(SQUOTE); + break; + + case DQUOTE: + skipto(DQUOTE); + break; + + case DOLLAR: + if (readc() == BRACE) + skipto('}'); + } + } + if (c != endch) + error(badsub); +} + +static +comsubst() +{ + /* + * command substn + */ + struct fileblk cb; + register char d; + register char *savptr = fixstak(); + + usestak(); + while ((d = readc()) != SQUOTE && d) + pushstak(d); + { + register char *argc; + + trim(argc = fixstak()); + push(&cb); + estabf(argc); + } + { + register struct trenod *t = makefork(FPOU, cmd(EOFSYM, MTFLG | NLFLG)); + int pv[2]; + + /* + * this is done like this so that the pipe + * is open only when needed + */ + chkpipe(pv); + initf(pv[INPIPE]); + execute(t, 0, (int)(flags & errflg), NIL, pv); + close(pv[OTPIPE]); + } + tdystak(savptr); + staktop = movstr(savptr, stakbot); + while (d = readc()) + /* @@@ pushstak(d | quote); */ + pushstak( quote ? qmask(d) : d ); + + await(0, 0); + while (stakbot != staktop) + { + /* @@@ if ((*--staktop & STRIP) != NL) */ + if (ismask(*--staktop)!= NL) + { + ++staktop; + break; + } + } + pop(); +} + +static int +getch(endch) +char endch; +{ + register char d; + +retry: + d = readc(); + if (!subchar(d)) + return(d); + if (d == DOLLAR) + { + register int c; + + if ((c = cii(readc()), dolchar(c))) /* @@@ */ + { + struct namnod *n = (struct namnod *)NIL; + int dolg = 0; + BOOL bra; + BOOL nulflg; + register char *argp, *v; + char idb[2]; + char *id = idb; + + if (bra = (c == BRACE)) + c = cii(readc()); /* @@@ */ + if (letter(c)) + { + argp = (char *)relstak(); + while (alphanum(c)) + { + pushstak(c); + c = cii(readc()); /* @@@ */ + } + zerostak(); + n = lookup(absstak(argp)); + setstak(argp); + if (n->namflg & N_FUNCTN) + error(badsub); + v = n->namval; + id = n->namid; + peekc = c | MARK; + } + else if (digchar(c)) + { + *id = c; + idb[1] = '\0'; + if (astchar(c)) + { + dolg = 1; + c = '1'; + } + c -= '0'; + v = ((c == 0) ? cmdadr : (c <= dolc) ? dolv[c] : (char *)(dolg = 0)); + } + else if (c == '$') + v = pidadr; + else if (c == '!') + v = pcsadr; + else if (c == '#') + { + itos(dolc); + v = numbuf; + } + else if (c == '?') + { + itos(retval); + v = numbuf; + } + else if (c == '-') + v = flagadr; + else if (bra) + error(badsub); + else + goto retry; + c = cii(readc()); /* @@@ */ + if (c == ':' && bra) /* null and unset fix */ + { + nulflg = 1; + c = cii(readc()); /* @@@ */ + } + else + nulflg = 0; + if (!defchar(c) && bra) + error(badsub); + argp = NIL; + if (bra) + { + if (c != '}') + { + argp = (char *)relstak(); + if ((v == NIL || (nulflg && *v == 0)) ^ (setchar(c))) + copyto('}'); + else + skipto('}'); + argp = absstak(argp); + } + } + else + { + peekc = c | MARK; + c = 0; + } + if (v && (!nulflg || *v)) + { + char tmp = (*id == '*' ? SP | quote : SP); + + if (c != '+') + { + for (;;) + { + if (*v == 0 && quote) + pushstak(QUOTE); + else + { + while (c = *v++) + /* @@@ pushstak(c | quote); */ + pushstak( quote ? qmask(c) : c ); + } + + if (dolg == 0 || (++dolg > dolc)) + break; + else + { + v = dolv[dolg]; + pushstak(tmp); + } + } + } + } + else if (argp) + { + if (c == '?') + failed(id, *argp ? argp : badparam); + else if (c == '=') + { + if (n) + { + trim(argp); + assign(n, argp); + } + else + error(badsub); + } + } + else if (flags & setflg) + failed(id, unset); + goto retry; + } + else + peekc = c | MARK; + } + else if (d == endch) + return(d); + else if (d == SQUOTE) + { + comsubst(); + goto retry; + } + else if (d == DQUOTE) + { + quoted++; + quote ^= QUOTE; + goto retry; + } + return(d); +} + +char * +macro(as) +char *as; +{ + /* + * Strip "" and do $ substitution + * Leaves result on top of stack + */ + register BOOL savqu = quoted; + register char savq = quote; + struct filehdr fb; + + push(&fb); + estabf(as); + usestak(); + quote = 0; + quoted = 0; + copyto(0); + pop(); + if (quoted && (stakbot == staktop)) + pushstak(QUOTE); +/* + * above is the fix for *'.c' bug + */ + quote = savq; + quoted = savqu; + return(fixstak()); +} + +static +flush(ot) +{ + write(ot, stakbot, staktop - stakbot); + if (flags & execpr) + write(output, stakbot, staktop - stakbot); + staktop = stakbot; +} + +#define CPYSIZ 512 + +subst(in, ot) +int in, ot; +{ + register char c; + struct fileblk fb; + register int count = CPYSIZ; + + push(&fb); + initf(in); + /* + * DQUOTE used to stop it from quoting + */ + while (c = /* @@@ (getch(DQUOTE) & STRIP)*/ smask(getch(DQUOTE)) ) + { + pushstak(c); + if (--count == 0) + { + flush(ot); + count = CPYSIZ; + } + } + flush(ot); + pop(); +} diff --git a/src/cmd/sh/main.c b/src/cmd/sh/main.c new file mode 100644 index 0000000..6ecf6e4 --- /dev/null +++ b/src/cmd/sh/main.c @@ -0,0 +1,411 @@ +/* + * UNIX shell + * + * Bell Telephone Laboratories + */ +#include "defs.h" +#include "sym.h" +#include "timeout.h" +#include +#include +#include "dup.h" +#include +#include + +#ifdef RES +#include +#endif + +static BOOL beenhere = FALSE; +char tmpout[20] = "/tmp/sh-"; +struct fileblk stdfile; +struct fileblk *standin = &stdfile; +int mailchk = 0; + +static char *mailp; +static long *mod_time = (long *)NIL; + +#ifdef pdp11 +#include +#include +#endif + +extern char *simple(); + +static int +exfile(prof) +BOOL prof; +{ + long mailtime = 0; /* Must not be a register variable */ + long curtime = 0; + register int userid; + + /* + * move input + */ + if (input > 0) + { + Ldup(input, INIO); + input = INIO; + } + + userid = geteuid(); + if( userid ) defpath[ENDPATH] = '\0'; /* no /etc */ + + /* + * decide whether interactive + */ + if ((flags & intflg) || + ((flags&oneflg) == 0 && + isatty(output) && + isatty(input)) ) + + { + dfault(&ps1nod, (userid ? stdprompt : supprompt)); + dfault(&ps2nod, readmsg); + flags |= ttyflg | prompt; + ignsig(SIGTERM); + if (mailpnod.namflg != N_DEFAULT) + setmail(mailpnod.namval); + else + setmail(mailnod.namval); + } + else + { + flags |= prof; + flags &= ~prompt; + } + + if (setjmp(errshell) && prof) + { + close(input); + return; + } + /* + * error return here + */ + + loopcnt = peekc = peekn = 0; + fndef = 0; + nohash = 0; + iopend = 0; + + if (input >= 0) + initf(input); + /* + * command loop + */ + for (;;) + { + tdystak(NIL); + stakchk(); /* may reduce sbrk */ + exitset(); + + if ((flags & prompt) && standin->fstak == NIL && !eof) + { + + if (mailp) + { + time(&curtime); + + if ((curtime - mailtime) >= mailchk) + { + chkmail(); + mailtime = curtime; + } + } + + prprompt(ps1nod.namval); + +#ifdef TIME_OUT + alarm(TIMEOUT); +#endif + + flags |= waiting; + } + + trapnote = 0; + peekc = cii(readc()); /* @@@ */ + if (eof) + return; + +#ifdef TIME_OUT + alarm(0); +#endif + + flags &= ~waiting; + + execute(cmd(NL, MTFLG), 0, eflag); + eof |= (flags & oneflg); + } +} + +main(c, v, e) +int c; +char **v; +char **e; +{ + register int rflag = ttyflg; + int rsflag = 1; /* local restricted flag */ + struct namnod *n; + + stdsigs(); + + /* + * initialise storage allocation + */ + + stakbot = NIL; + addblok((unsigned)0); + + /* + * set names from userenv + */ + + setup_env(); + + /* + * 'rsflag' is non-zero if SHELL variable is + * set in environment and contains an'r' in + * the simple file part of the value. + */ + if (n = findnam("SHELL")) + { + if (any('r', simple(n->namval))) + rsflag = 0; + } + + /* + * a shell is also restricted if argv(0) has + * an 'r' in its simple name + */ + +#ifndef RES + if (c > 0 && any('r', simple(*v))) + rflag = 0; +#endif + + hcreate(); + set_dotpath(); + + /* + * look for options + * dolc is $# + */ + dolc = options(c, v); + + if (dolc < 2) + { + flags |= stdflg; + { + register char *flagc = flagadr; + + while (*flagc) + flagc++; + *flagc++ = STDFLG; + *flagc = 0; + } + } + if ((flags & stdflg) == 0) + dolc--; + dolv = v + c - dolc; + dolc--; + + /* + * return here for shell file execution + * but not for parenthesis subshells + */ + setjmp(subshell); + + /* + * number of positional parameters + */ + replace(&cmdadr, dolv[0]); /* cmdadr is $0 */ + + /* + * set pidname '$$' + */ + assnum(&pidadr, getpid()); + + /* + * set up temp file names + */ + settmp(); + + /* + * default internal field separators - $IFS + */ + dfault(&ifsnod, sptbnl); + + dfault(&mchknod, MAILCHECK); + mailchk = stoi(mchknod.namval); + + if ((beenhere++) == FALSE) /* ? profile */ + { + if (*(simple(cmdadr)) == '-') + { /* system profile */ + +#ifndef RES + if ((input = pathopen(nullstr, sysprofile)) >= 0) + exfile(rflag); /* file exists */ +#endif + + if ((input = pathopen(nullstr, profile)) >= 0) + { + exfile(rflag); + flags &= ~ttyflg; + } + } + if (rsflag == 0 || rflag == 0) + flags |= rshflg; + /* + * open input file if specified + */ + if (comdiv) + { + estabf(comdiv); + input = -1; + } + else + { + input = ((flags & stdflg) ? 0 : chkopen(cmdadr)); + +#ifdef ACCOUNT + if (input != 0) + preacct(cmdadr); +#endif + comdiv--; + } + } +#ifdef pdp11 + else + *execargs = (char *)dolv; /* for `ps' cmd */ +#endif + exfile(0); + done(); +} + +chkpr() +{ + if ((flags & prompt) && standin->fstak == NIL) + prs(ps2nod.namval); +} + +settmp() +{ + itos(getpid()); + serial = 0; + tmpnam = movstr(numbuf, &tmpout[TMPNAM]); +} + +Ldup(fa, fb) +register int fa, fb; +{ +#if defined(RES) || defined(pdp11) + + dup(fa | DUPFLG, fb); + close(fa); + ioctl(fb, FIOCLEX, 0); +#else + if (fa >= 0) + { close(fb); + fcntl(fa,F_DUPFD,fb); /* normal dup */ + close(fa); + fcntl(fb, F_SETFD, EXCLOSE); /* autoclose for fb */ + } +#endif +} + + +chkmail() +{ + register char *s = mailp; + register char *save; + + long *ptr = mod_time; + char *start; + BOOL flg; + struct stat statb; + + while (*s) + { + start = s; + save = NIL; + flg = 0; + + while (*s) + { + if (*s != COLON) + { + if (*s == '%' && save == NIL) + save = s; + + s++; + } + else + { + flg = 1; + *s = 0; + } + } + + if (save) + *save = 0; + + if (*start && stat(start, &statb) >= 0) + { + if(statb.st_size && *ptr + && statb.st_mtime != *ptr) + { + if (save) + { + prs(save+1); + newline(); + } + else + prs(mailmsg); + } + *ptr = statb.st_mtime; + } + else if (*ptr == 0) + *ptr = 1; + + if (save) + *save = '%'; + + if (flg) + *s++ = COLON; + + ptr++; + } +} + +setmail(mailpath) + char *mailpath; +{ + register char *s = mailpath; + register int cnt = 1; + + long *ptr; + + free(mod_time); + if (mailp = mailpath) + { + while (*s) + { + if (*s == COLON) + cnt += 1; + + s++; + } + + ptr = mod_time = (long *)alloc(sizeof(long) * cnt); + + while (cnt) + { + *ptr = 0; + ptr++; + cnt--; + } + } +} diff --git a/src/cmd/sh/mode.h b/src/cmd/sh/mode.h new file mode 100644 index 0000000..77f08ec --- /dev/null +++ b/src/cmd/sh/mode.h @@ -0,0 +1,202 @@ +/* + * UNIX shell + */ +typedef int BOOL; + +#define uchar unsigned char + +#define BYTESPERWORD (sizeof (char *)) +#define NIL 0 + +/* + * the following nonsense is required + * because casts turn an Lvalue + * into an Rvalue so two cheats + * are necessary, one for each context. + */ +#define Lcheat(a) (*(int*)&(a)) +#define Rcheat(a) ((int)(a)) + + +/* address puns for storage allocation */ +typedef union +{ + struct forknod *_forkptr; + struct comnod *_comptr; + struct fndnod *_fndptr; + struct parnod *_parptr; + struct ifnod *_ifptr; + struct whnod *_whptr; + struct fornod *_forptr; + struct lstnod *_lstptr; + struct blk *_blkptr; + struct namnod *_namptr; + char *_bytptr; +} address; + + +/* heap storage */ +struct blk +{ + struct blk *word; +}; + +#define BUFSIZ 128 +struct fileblk +{ + int fdes; + unsigned flin; + BOOL feof; + uchar fsiz; + char *fnxt; + char *fend; + char **feval; + struct fileblk *fstak; + char fbuf[BUFSIZ]; +}; + +struct tempblk +{ + int fdes; + struct tempblk *Fstak; +}; + + +/* for files not used with file descriptors */ +struct filehdr +{ + int fdes; + unsigned flin; + BOOL feof; + uchar fsiz; + char *fnxt; + char *fend; + char **feval; + struct fileblk *fstak; + char _fbuf[1]; +}; + +struct sysnod +{ + char *sysnam; + int sysval; +}; + +/* this node is a proforma for those that follow */ +struct trenod +{ + int tretyp; + struct ionod *treio; +}; + +/* dummy for access only */ +struct argnod +{ + struct argnod *argnxt; + char argval[1]; +}; + +struct dolnod +{ + struct dolnod *dolnxt; + int doluse; + char *dolarg[1]; +}; + +struct forknod +{ + int forktyp; + struct ionod *forkio; + struct trenod *forktre; +}; + +struct comnod +{ + int comtyp; + struct ionod *comio; + struct argnod *comarg; + struct argnod *comset; +}; + +struct fndnod +{ + int fndtyp; + char *fndnam; + struct trenod *fndval; +}; + +struct ifnod +{ + int iftyp; + struct trenod *iftre; + struct trenod *thtre; + struct trenod *eltre; +}; + +struct whnod +{ + int whtyp; + struct trenod *whtre; + struct trenod *dotre; +}; + +struct fornod +{ + int fortyp; + struct trenod *fortre; + char *fornam; + struct comnod *forlst; +}; + +struct swnod +{ + int swtyp; + char *swarg; + struct regnod *swlst; +}; + +struct regnod +{ + struct argnod *regptr; + struct trenod *regcom; + struct regnod *regnxt; +}; + +struct parnod +{ + int partyp; + struct trenod *partre; +}; + +struct lstnod +{ + int lsttyp; + struct trenod *lstlef; + struct trenod *lstrit; +}; + +struct ionod +{ + int iofile; + char *ioname; + char *iolink; + struct ionod *ionxt; + struct ionod *iolst; +}; + +struct fdsave +{ + int org_fd; + int dup_fd; +}; + + +#define fndptr(x) ((struct fndnod *)x) +#define comptr(x) ((struct comnod *)x) +#define forkptr(x) ((struct forknod *)x) +#define parptr(x) ((struct parnod *)x) +#define lstptr(x) ((struct lstnod *)x) +#define forptr(x) ((struct fornod *)x) +#define whptr(x) ((struct whnod *)x) +#define ifptr(x) ((struct ifnod *)x) +#define swptr(x) ((struct swnod *)x) diff --git a/src/cmd/sh/msg.c b/src/cmd/sh/msg.c new file mode 100644 index 0000000..553413f --- /dev/null +++ b/src/cmd/sh/msg.c @@ -0,0 +1,192 @@ +/* + * UNIX shell + * + * Bell Telephone Laboratories + */ +#include "defs.h" +#include "sym.h" + +/* + * error messages + */ +char badopt[] = "bad option(s)"; +char mailmsg[] = "you have mail\n"; +char nospace[] = "no space"; +char nostack[] = "no stack space"; +char synmsg[] = "syntax error"; + +char badnum[] = "bad number"; +char badparam[] = "parameter null or not set"; +char unset[] = "parameter not set"; +char badsub[] = "bad substitution"; +char badcreate[] = "cannot create"; +char nofork[] = "fork failed - too many processes"; +char noswap[] = "cannot fork: no swap space"; +char restricted[] = "restricted"; +char piperr[] = "cannot make pipe"; +char badopen[] = "cannot open"; +char coredump[] = " - core dumped"; +char arglist[] = "arg list too long"; +char txtbsy[] = "text busy"; +char toobig[] = "too big"; +char badexec[] = "cannot execute"; +char notfound[] = "not found"; +char badfile[] = "bad file number"; +char badshift[] = "cannot shift"; +char baddir[] = "bad directory"; +char badtrap[] = "bad trap"; +char wtfailed[] = "is read only"; +char notid[] = "is not an identifier"; +char badulimit[] = "Bad ulimit"; +char badreturn[] = "cannot return when not in function"; +char badexport[] = "cannot export functions"; +char badunset[] = "cannot unset"; +char nohome[] = "no home directory"; +char badperm[] = "execute permission denied"; +char longpwd[] = "sh error: pwd too long"; +/* + * messages for 'builtin' functions + */ +char btest[] = "test"; +char badop[] = "unknown operator "; +/* + * built in names + */ +char pathname[] = "PATH"; +char cdpname[] = "CDPATH"; +char homename[] = "HOME"; +char mailname[] = "MAIL"; +char ifsname[] = "IFS"; +char ps1name[] = "PS1"; +char ps2name[] = "PS2"; +char mchkname[] = "MAILCHECK"; +char acctname[] = "SHACCT"; +char mailpname[] = "MAILPATH"; + +/* + * string constants + */ +char nullstr[] = ""; +char sptbnl[] = " \t\n"; +char defpath[] = ":/bin:/usr/bin:/usr/ucb/bin:/etc"; +char colon[] = ": "; +char minus[] = "-"; +char endoffile[] = "end of file"; +char unexpected[] = " unexpected"; +char atline[] = " at line "; +char devnull[] = "/dev/null"; +char execpmsg[] = "+ "; +char readmsg[] = "> "; +char stdprompt[] = "$ "; +char supprompt[] = "# "; +char profile[] = ".profile"; +char sysprofile[] = "/etc/profile"; + +/* + * tables + */ + +struct sysnod reserved[] = +{ + { "case", CASYM }, + { "do", DOSYM }, + { "done", ODSYM }, + { "elif", EFSYM }, + { "else", ELSYM }, + { "esac", ESSYM }, + { "fi", FISYM }, + { "for", FORSYM }, + { "if", IFSYM }, + { "in", INSYM }, + { "then", THSYM }, + { "until", UNSYM }, + { "while", WHSYM }, + { "{", BRSYM }, + { "}", KTSYM } +}; + +int no_reserved = 15; + +char *sysmsg[] = +{ + 0, + "Hangup", + 0, /* Interrupt */ + "Quit", + "Illegal instruction", + "Trace/BPT trap", + "abort", + "EMT trap", + "Floating exception", + "Killed", + "Bus error", + "Memory fault", + "Bad system call", + "Broken pipe", + "Alarm call", + "Terminated", + "Urgent cond.", + "Stopped", + "Ctrl Z", + "Continued", + "Child death", + "Tty input", + "Tty output", + "Keyboard", + /* "Power Fail" */ +}; + +char export[] = "export"; +char duperr[] = "cannot dup"; +char readonly[] = "readonly"; + +struct sysnod commands[] = +{ + { ".", SYSDOT }, + { ":", SYSNULL }, + +#ifndef RES + { "[", SYSTST }, +#endif + + { "break", SYSBREAK }, + { "cd", SYSCD }, + { "continue", SYSCONT }, + { "echo", SYSECHO }, + { "eval", SYSEVAL }, + { "exec", SYSEXEC }, + { "exit", SYSEXIT }, + { "export", SYSXPORT }, + { "hash", SYSHASH }, + +#ifdef RES + { "login", SYSLOGIN }, + { "newgrp", SYSLOGIN }, +#else + { "login", SYSLOGIN }, + { "newgrp", SYSNEWGRP }, +#endif + { "pwd", SYSPWD }, + { "read", SYSREAD }, + { "readonly", SYSRDONLY }, + { "return", SYSRETURN }, + { "set", SYSSET }, + { "shift", SYSSHFT }, + { "test", SYSTST }, + { "times", SYSTIMES }, + { "trap", SYSTRAP }, + { "type", SYSTYPE }, + +#ifndef RES + { "ulimit", SYSULIMIT }, + { "umask", SYSUMASK }, +#endif + { "unset", SYSUNS }, + { "wait", SYSWAIT } +}; + +#ifdef RES + int no_commands = 26; +#else + int no_commands = 28; +#endif diff --git a/src/cmd/sh/name.c b/src/cmd/sh/name.c new file mode 100644 index 0000000..c110652 --- /dev/null +++ b/src/cmd/sh/name.c @@ -0,0 +1,591 @@ +/* + * UNIX shell + * + * Bell Telephone Laboratories + */ +#include "defs.h" + +extern BOOL chkid(); +extern char *simple(); +extern int mailchk; + +struct namnod ps2nod = +{ + (struct namnod *)NIL, + &acctnod, + ps2name +}; +struct namnod cdpnod = +{ + (struct namnod *)NIL, + (struct namnod *)NIL, + cdpname +}; +struct namnod pathnod = +{ + &mailpnod, + (struct namnod *)NIL, + pathname +}; +struct namnod ifsnod = +{ + &homenod, + &mailnod, + ifsname +}; +struct namnod ps1nod = +{ + &pathnod, + &ps2nod, + ps1name +}; +struct namnod homenod = +{ + &cdpnod, + (struct namnod *)NIL, + homename +}; +struct namnod mailnod = +{ + (struct namnod *)NIL, + (struct namnod *)NIL, + mailname +}; +struct namnod mchknod = +{ + &ifsnod, + &ps1nod, + mchkname +}; +struct namnod acctnod = +{ + (struct namnod *)NIL, + (struct namnod *)NIL, + acctname +}; +struct namnod mailpnod = +{ + (struct namnod *)NIL, + (struct namnod *)NIL, + mailpname +}; + + +struct namnod *namep = &mchknod; + +/* ======== variable and string handling ======== */ + +syslook(w, syswds, n) + register char *w; + register struct sysnod syswds[]; + int n; +{ + int low; + int high; + int mid; + register int cond; + + if (w == NIL || *w == 0) + return(0); + + low = 0; + high = n - 1; + + while (low <= high) + { + mid = (low + high) / 2; + + if ((cond = cf(w, syswds[mid].sysnam)) < 0) + high = mid - 1; + else if (cond > 0) + low = mid + 1; + else + return(syswds[mid].sysval); + } + return(0); +} + +setlist(arg, xp) +register struct argnod *arg; +int xp; +{ + if (flags & exportflg) + xp |= N_EXPORT; + + while (arg) + { + register char *s = mactrim(arg->argval); + setname(s, xp); + arg = arg->argnxt; + if (flags & execpr) + { + prs(s); + if (arg) + blank(); + else + newline(); + } + } +} + + +setname(argi, xp) /* does parameter assignments */ +char *argi; +int xp; +{ + register char *argscan = argi; + register struct namnod *n; + + if (letter(*argscan)) + { + while (alphanum(*argscan)) + argscan++; + + if (*argscan == '=') + { + *argscan = 0; /* make name a cohesive string */ + + n = lookup(argi); + *argscan++ = '='; + attrib(n, xp); + if (xp & N_ENVNAM) + n->namenv = n->namval = argscan; + else + assign(n, argscan); + return; + } + } + failed(argi, notid); +} + +replace(a, v) +register char **a; +char *v; +{ + free(*a); + *a = make(v); +} + +dfault(n, v) +struct namnod *n; +char *v; +{ + if (n->namval == NIL) + assign(n, v); +} + +assign(n, v) +struct namnod *n; +char *v; +{ + if (n->namflg & N_RDONLY) + failed(n->namid, wtfailed); + +#ifndef RES + + else if (flags & rshflg) + { + if (n == &pathnod || eq(n->namid, "SHELL")) + failed(n->namid, restricted); + } + +#endif + + else if (n->namflg & N_FUNCTN) + { + func_unhash(n->namid); + freefunc(n); + + n->namenv = NIL; + n->namflg = N_DEFAULT; + } + + if (n == &mchknod) + { + mailchk = stoi(v); + } + + replace(&n->namval, v); + attrib(n, N_ENVCHG); + + if (n == &pathnod) + { + zaphash(); + set_dotpath(); + return; + } + + if (flags & prompt) + { + if ((n == &mailpnod) || (n == &mailnod && mailpnod.namflg == N_DEFAULT)) + setmail(n->namval); + } +} + +readvar(names) +char **names; +{ + struct fileblk fb; + register struct fileblk *f = &fb; + register char c; + register int rc = 0; + struct namnod *n = lookup(*names++); /* done now to avoid storage mess */ + char *rel = (char *)relstak(); + + push(f); + initf(dup(0)); + + if (lseek(0, 0L, 1) == -1) + f->fsiz = 1; + + /* + * strip leading IFS characters + */ + while ((any((c = nextc(0)), ifsnod.namval)) && !(eolchar(c))) + ; + for (;;) + { + if ((*names && any(c, ifsnod.namval)) || eolchar(c)) + { + zerostak(); + assign(n, absstak(rel)); + setstak(rel); + if (*names) + n = lookup(*names++); + else + n = NIL; + if (eolchar(c)) + { + break; + } + else /* strip imbedded IFS characters */ + { + while ((any((c = nextc(0)), ifsnod.namval)) && + !(eolchar(c))) + ; + } + } + else + { + pushstak(c); + c = nextc(0); + + if (eolchar(c)) + { + char *top = staktop; + + while (any(*(--top), ifsnod.namval)) + ; + staktop = top + 1; + } + + + } + } + while (n) + { + assign(n, nullstr); + if (*names) + n = lookup(*names++); + else + n = NIL; + } + + if (eof) + rc = 1; + lseek(0, (long)(f->fnxt - f->fend), 1); + pop(); + return(rc); +} + +assnum(p, i) +char **p; +int i; +{ + itos(i); + replace(p, numbuf); +} + +char * +make(v) +char *v; +{ + register char *p; + + if (v) + { + movstr(v, p = alloc(length(v))); + return(p); + } + else + return(NIL); +} + + +struct namnod * +lookup(nam) + register char *nam; +{ + register struct namnod *nscan = namep; + register struct namnod **prev; + int LR; + + if (!chkid(nam)) + failed(nam, notid); + while (nscan) + { + if ((LR = cf(nam, nscan->namid)) == 0) + return(nscan); + + else if (LR < 0) + prev = &(nscan->namlft); + else + prev = &(nscan->namrgt); + nscan = *prev; + } + /* + * add name node + */ + nscan = (struct namnod *)alloc(sizeof *nscan); + nscan->namlft = nscan->namrgt = (struct namnod *)NIL; + nscan->namid = make(nam); + nscan->namval = NIL; + nscan->namflg = N_DEFAULT; + nscan->namenv = NIL; + + return(*prev = nscan); +} + +BOOL +chkid(nam) +char *nam; +{ + register char *cp = nam; + + if (!letter(*cp)) + return(FALSE); + else + { + while (*++cp) + { + if (!alphanum(*cp)) + return(FALSE); + } + } + return(TRUE); +} + +static int (*namfn)(); + +static int +namwalk(np) +register struct namnod *np; +{ + if (np) + { + namwalk(np->namlft); + (*namfn)(np); + namwalk(np->namrgt); + } +} + +namscan(fn) + int (*fn)(); +{ + namfn = fn; + namwalk(namep); +} + +printnam(n) +struct namnod *n; +{ + register char *s; + + sigchk(); + + if (n->namflg & N_FUNCTN) + { + prs_buff(n->namid); + prs_buff("(){\n"); + prf(n->namenv); + prs_buff("\n}\n"); + } + else if (s = n->namval) + { + prs_buff(n->namid); + prc_buff('='); + prs_buff(s); + prc_buff(NL); + } +} + +static char * +staknam(n) +register struct namnod *n; +{ + register char *p; + + p = movstr(n->namid, staktop); + p = movstr("=", p); + p = movstr(n->namval, p); + return(getstak(p + 1 - (char *)(stakbot))); +} + +static int namec; + +exname(n) + register struct namnod *n; +{ + register int flg = n->namflg; + + if (flg & N_ENVCHG) + { + + if (flg & N_EXPORT) + { + free(n->namenv); + n->namenv = make(n->namval); + } + else + { + free(n->namval); + n->namval = make(n->namenv); + } + } + + + if (!(flg & N_FUNCTN)) + n->namflg = N_DEFAULT; + + if (n->namval) + namec++; + +} + +printro(n) +register struct namnod *n; +{ + if (n->namflg & N_RDONLY) + { + prs_buff(readonly); + prc_buff(SP); + prs_buff(n->namid); + prc_buff(NL); + } +} + +printexp(n) +register struct namnod *n; +{ + if (n->namflg & N_EXPORT) + { + prs_buff(export); + prc_buff(SP); + prs_buff(n->namid); + prc_buff(NL); + } +} + +setup_env() +{ + register char **e = environ; + + while (*e) + setname(*e++, N_ENVNAM); +} + + +static char **argnam; + +pushnam(n) +struct namnod *n; +{ + if (n->namval) + *argnam++ = staknam(n); +} + +char ** +setenvv() +{ + register char **er; + + namec = 0; + namscan(exname); + + argnam = er = (char **)getstak(namec * BYTESPERWORD + BYTESPERWORD); + namscan(pushnam); + *argnam++ = NIL; + return(er); +} + +struct namnod * +findnam(nam) + register char *nam; +{ + register struct namnod *nscan = namep; + int LR; + + if (!chkid(nam)) + return(NIL); + while (nscan) + { + if ((LR = cf(nam, nscan->namid)) == 0) + return(nscan); + else if (LR < 0) + nscan = nscan->namlft; + else + nscan = nscan->namrgt; + } + return(NIL); +} + + +unset_name(name) + register char *name; +{ + register struct namnod *n; + + if (n = findnam(name)) + { + if (n->namflg & N_RDONLY) + failed(name, wtfailed); + + if (n == &pathnod || + n == &ifsnod || + n == &ps1nod || + n == &ps2nod || + n == &mchknod) + { + failed(name, badunset); + } + +#ifndef RES + + if ((flags & rshflg) && eq(name, "SHELL")) + failed(name, restricted); + +#endif + + if (n->namflg & N_FUNCTN) + { + func_unhash(name); + freefunc(n); + } + else + { + free(n->namval); + free(n->namenv); + } + + n->namval = n->namenv = NIL; + n->namflg = N_DEFAULT; + + if (flags & prompt) + { + if (n == &mailpnod) + setmail(mailnod.namval); + else if (n == &mailnod && mailpnod.namflg == N_DEFAULT) + setmail(NIL); + } + } +} diff --git a/src/cmd/sh/name.h b/src/cmd/sh/name.h new file mode 100644 index 0000000..d776dc5 --- /dev/null +++ b/src/cmd/sh/name.h @@ -0,0 +1,22 @@ +/* + * UNIX shell + * + * Bell Telephone Laboratories + */ +#define N_ENVCHG 0020 +#define N_RDONLY 0010 +#define N_EXPORT 0004 +#define N_ENVNAM 0002 +#define N_FUNCTN 0001 + +#define N_DEFAULT 0 + +struct namnod +{ + struct namnod *namlft; + struct namnod *namrgt; + char *namid; + char *namval; + char *namenv; + int namflg; +}; diff --git a/src/cmd/sh/print.c b/src/cmd/sh/print.c new file mode 100644 index 0000000..7ccf0cc --- /dev/null +++ b/src/cmd/sh/print.c @@ -0,0 +1,250 @@ +/* + * UNIX shell + * + * Bell Telephone Laboratories + */ +#include "defs.h" +#include + +extern char *getenv(); + +#define BUFLEN 256 + +int hz = (-1); + +static char buffer[BUFLEN]; +static int index = 0; +char numbuf[12]; + +extern void prc_buff(); +extern void prs_buff(); +extern void prn_buff(); +extern void prs_cntl(); +extern void prn_buff(); + +/* + * printing and io conversion + */ +prp() +{ + if ((flags & prompt) == 0 && cmdadr) + { + prs_cntl(cmdadr); + prs(colon); + } +} + +prs(as) +char *as; +{ + register char *s; + + if (s = as) + write(output, s, length(s) - 1); +} + +/* print a prompt */ +/* it's a subject for future expansion @@@ */ +prprompt(as) +char *as; +{ + prs(as); +} + +prc(c) +char c; +{ + if (c) + write(output, &c, 1); +} + +prt(t) +long t; +{ + register int hr, min, sec; + char *s; + + if( hz < 0 ){ + s = getenv( "HZ" ); + if( s ) hz = atoi( s ); + else hz = HZ; + } + + t += hz / 2; + t /= hz; + sec = t % hz; + t /= HZ; + min = t % hz; + + if (hr = t / hz) + { + prn_buff(hr); + prc_buff('h'); + } + + prn_buff(min); + prc_buff('m'); + prn_buff(sec); + prc_buff('s'); +} + +prn(n) + int n; +{ + itos(n); + + prs(numbuf); +} + +itos(n) +{ + register char *abuf; + register unsigned a, i; + int pr, d; + + abuf = numbuf; + + pr = FALSE; + a = n; + for (i = 10000; i != 1; i /= 10) + { + if ((pr |= (d = a / i))) + *abuf++ = d + '0'; + a %= i; + } + *abuf++ = a + '0'; + *abuf++ = 0; +} + +stoi(icp) +char *icp; +{ + register char *cp = icp; + register int r = 0; + register char c; + + while ((c = *cp, digit(c)) && c && r >= 0) + { + r = r * 10 + c - '0'; + cp++; + } + if (r < 0 || cp == icp) + failed(icp, badnum); + else + return(r); +} + +prl(n) +long n; +{ + int i; + + i = 11; + while (n > 0 && --i >= 0) + { + numbuf[i] = n % 10 + '0'; + n /= 10; + } + numbuf[11] = '\0'; + prs_buff(&numbuf[i]); +} + +void +flushb() +{ + if (index) + { + buffer[index] = '\0'; + write(1, buffer, length(buffer) - 1); + index = 0; + } +} + +void +prc_buff(c) + char c; +{ + if (c) + { + if (index + 1 >= BUFLEN) + flushb(); + + buffer[index++] = c; + } + else + { + flushb(); + write(1, &c, 1); + } +} + +void +prs_buff(s) + char *s; +{ + register int len = length(s) - 1; + + if (index + len >= BUFLEN) + flushb(); + + if (len >= BUFLEN) + write(1, s, len); + else + { + movstr(s, &buffer[index]); + index += len; + } +} + + +clear_buff() +{ + index = 0; +} + + +void +prs_cntl(s) + char *s; +{ + register char *ptr = buffer; + int c; + + while (*s != '\0') + { + c = *s; + c &= 0377; + + /* translate a control character into a printable sequence */ + + if (c < ' ') + { /* assumes ASCII char */ + *ptr++ = '^'; + *ptr++ = (c + '@'); /* assumes ASCII char */ + } + else if (c == 0177 || (c>=0200 && c<0300 )) + { /* '\0177' does not work */ + *ptr++ = '^'; + *ptr++ = '?'; + } + else + { /* printable character */ + *ptr++ = c; + } + + ++s; + } + + *ptr = '\0'; + prs(buffer); +} + + +void +prn_buff(n) + int n; +{ + itos(n); + + prs_buff(numbuf); +} diff --git a/src/cmd/sh/profile.c b/src/cmd/sh/profile.c new file mode 100644 index 0000000..6cd0e91 --- /dev/null +++ b/src/cmd/sh/profile.c @@ -0,0 +1,32 @@ +char *mktemp(); + +monitor(lowpc, highpc, buf, bufsiz, cntsiz) +char *lowpc, *highpc; +int *buf, bufsiz; +{ + register o; + static *sbuf, ssiz; + + if (lowpc == NIL) { + profil(NIL, 0, NIL, 0); + o = creat(mktemp("profXXXXXX"), 0666); + write(o, sbuf, ssiz<<1); + close(o); + return; + } + ssiz = bufsiz; + buf[0] = (int) lowpc; + buf[1] = (int) highpc; + buf[2] = cntsiz; + sbuf = buf; + buf += 3*(cntsiz+1); + bufsiz -= 3*(cntsiz+1); + if (bufsiz<=0) + return; + o = ((highpc - lowpc)>>1) & 077777; + if(bufsiz < o) + o = ((long)bufsiz<<15) / o; + else + o = 077777; + profil(buf, bufsiz<<1, lowpc, o<<1); +} diff --git a/src/cmd/sh/pushd b/src/cmd/sh/pushd new file mode 100644 index 0000000..d7d966a --- /dev/null +++ b/src/cmd/sh/pushd @@ -0,0 +1,72 @@ + +DIRSTAK="" + +dirs() { + echo `pwd` $DIRSTAK +} + +pushdir() { + if test $# -eq 0 + then + if test "$DIRSTAK" = "" + then + echo "directory stack empty." + else + OLDPWD=`pwd` + popdir + DIRSTAK="$OLDPWD $DIRSTAK" + fi + else + while test "$*" != "" + do + OLDPWD=`pwd` + if cd "$1" + then + DIRSTAK="$OLDPWD $DIRSTAK" + fi + shift + done + fi +} + +listhead() { + echo $1 +} + +listtail() { + shift + echo $* +} + +popdir() { + if test $# -ne 0 + then + echo "No parameters allowed with popdir" + else + if test "$DIRSTAK" = "" + then + echo "directory stack empty." + else + TMP1=`listhead $DIRSTAK` + DIRSTAK=`listtail $DIRSTAK` + if test "$TMP1" != "" + then + cd "$TMP1" + fi + fi + fi +} + +pushd() { + if pushdir $* + then + dirs + fi +} + +popd() { + if popdir $* + then + dirs + fi +} diff --git a/src/cmd/sh/pwd.c b/src/cmd/sh/pwd.c new file mode 100644 index 0000000..ae72c7b --- /dev/null +++ b/src/cmd/sh/pwd.c @@ -0,0 +1,284 @@ +/* + * UNIX shell + * + * Bell Telephone Laboratories + */ +#include "mac.h" +#include "defs.h" + +#define DOT '.' +#define NULL 0 +#define SLASH '/' +#define MAXPWD 256 + +extern char longpwd[]; + +static char cwdname[MAXPWD]; +static int didpwd = FALSE; + +/* + * This routine will remove repeated slashes from string. + */ +static +rmslash(string) + char *string; +{ + register char *pstring; + + pstring = string; + while(*pstring) + { + if(*pstring==SLASH && *(pstring+1)==SLASH) + { + /* Remove repeated SLASH's */ + + movstr(pstring+1, pstring); + continue; + } + pstring++; + } + + --pstring; + if(pstring>string && *pstring==SLASH) + { + /* Remove trailing / */ + + *pstring = NULL; + } + return; +} + +cwd(dir) + register char *dir; +{ + register char *pcwd; + register char *pdir; + + /* First remove extra /'s */ + + rmslash(dir); + + /* Now remove any .'s */ + + pdir = dir; + while(*pdir) /* remove /./ by itself */ + { + if((*pdir==DOT) && (*(pdir+1)==SLASH)) + { + movstr(pdir+2, pdir); + continue; + } + pdir++; + while ((*pdir) && (*pdir != SLASH)) + pdir++; + if (*pdir) + pdir++; + } + if(*(--pdir)==DOT && pdir>dir && *(--pdir)==SLASH) + *pdir = NULL; + + + /* Remove extra /'s */ + + rmslash(dir); + + /* Now that the dir is canonicalized, process it */ + + if(*dir==DOT && *(dir+1)==NULL) + { + return; + } + + if(*dir==SLASH) + { + /* Absolute path */ + + pcwd = cwdname; + didpwd = TRUE; + } + else + { + /* Relative path */ + + if (didpwd == FALSE) + return; + + pcwd = cwdname + length(cwdname) - 1; + if(pcwd != cwdname+1) + { + *pcwd++ = SLASH; + } + } + while(*dir) + { + if(*dir==DOT && + *(dir+1)==DOT && + (*(dir+2)==SLASH || *(dir+2)==NULL)) + { + /* Parent directory, so backup one */ + + if( pcwd > cwdname+2 ) + --pcwd; + while(*(--pcwd) != SLASH) + ; + pcwd++; + dir += 2; + if(*dir==SLASH) + { + dir++; + } + continue; + } + *pcwd++ = *dir++; + while((*dir) && (*dir != SLASH)) + *pcwd++ = *dir++; + if (*dir) + *pcwd++ = *dir++; + } + *pcwd = NULL; + + --pcwd; + if(pcwd>cwdname && *pcwd==SLASH) + { + /* Remove trailing / */ + + *pcwd = NULL; + } + return; +} + +/* + * Find the current directory the hard way. + */ +#include +#include +#include + +static char dotdots[] = +"../../../../../../../../../../../../../../../../../../../../../../../.."; + +extern struct direct *getdir(); +extern char *movstrn(); + +static +pwd() +{ + struct stat cdir; /* current directory status */ + struct stat tdir; + struct stat pdir; /* parent directory status */ + int pdfd; /* parent directory file descriptor */ + + struct direct *dir; + char *dot = dotdots + sizeof(dotdots) - 3; + int index = sizeof(dotdots) - 2; + int cwdindex = MAXPWD - 1; + int i; + + cwdname[cwdindex] = 0; + dotdots[index] = 0; + + if(stat(dot, &pdir) < 0) + { + error("pwd: cannot stat ."); + } + + dotdots[index] = '.'; + + for(;;) + { + cdir = pdir; + + if ((pdfd = open(dot, 0)) < 0) + { + error("pwd: cannot open .."); + } + + if(fstat(pdfd, &pdir) < 0) + { + close(pdfd); + error("pwd: cannot stat .."); + } + + if(cdir.st_dev == pdir.st_dev) + { + if(cdir.st_ino == pdir.st_ino) + { + didpwd = TRUE; + close(pdfd); + if (cwdindex == (MAXPWD - 1)) + cwdname[--cwdindex] = SLASH; + + movstr(&cwdname[cwdindex], cwdname); + return; + } + + do + { + if ((dir = getdir(pdfd)) == NIL) + { + close(pdfd); + reset_dir(); + error("pwd: read error in .."); + } + } + while (dir->d_ino != cdir.st_ino); + } + else + { + char name[512]; + + movstr(dot, name); + i = length(name) - 1; + + name[i++] = '/'; + + do + { + if ((dir = getdir(pdfd)) == NIL) + { + close(pdfd); + reset_dir(); + error("pwd: read error in .."); + } + *(movstrn(dir->d_name, &name[i], MAXNAMLEN)) = 0; + stat(name, &tdir); + } + while(tdir.st_ino != cdir.st_ino || tdir.st_dev != cdir.st_dev); + } + close(pdfd); + reset_dir(); + + for (i = 0; i < MAXNAMLEN; i++) + if (dir->d_name[i] == 0) + break; + + if (i > cwdindex - 1) + error(longpwd); + else + { + cwdindex -= i; + movstrn(dir->d_name, &cwdname[cwdindex], i); + cwdname[--cwdindex] = SLASH; + } + + dot -= 3; + if (dot +#include + +#define ARGMK 01 + +extern char *sysmsg[]; +extern short topfd; + + +/* + * service routines for `execute' + */ +initio(iop, save) + struct ionod *iop; + int save; +{ + register char *ion; + register int iof, fd; + int ioufd; + short lastfd; + + lastfd = topfd; + while (iop) + { + iof = iop->iofile; + ion = mactrim(iop->ioname); + ioufd = iof & IOUFD; + + if (*ion && (flags&noexec) == 0) + { + if (save) + { + fdmap[topfd].org_fd = ioufd; + fdmap[topfd++].dup_fd = savefd(ioufd); + } + + if (iof & IODOC) + { + struct tempblk tb; + + subst(chkopen(ion), (fd = tmpfil(&tb))); + + poptemp(); /* pushed in tmpfil() -- + bug fix for problem with + in-line scripts + */ + + fd = chkopen(tmpout); + unlink(tmpout); + } + else if (iof & IOMOV) + { + if (eq(minus, ion)) + { + fd = -1; + close(ioufd); + } + else if ((fd = stoi(ion)) >= USERIO) + failed(ion, badfile); + else + fd = dup(fd); + } + else if ((iof & IOPUT) == 0) + fd = chkopen(ion); + else if (flags & rshflg) + failed(ion, restricted); + else if (iof & IOAPP && (fd = open(ion, 1)) >= 0) + lseek(fd, 0L, 2); + else + fd = create(ion); + if (fd >= 0) + rename(fd, ioufd); + } + + iop = iop->ionxt; + } + return(lastfd); +} + +char * +simple(s) +char *s; +{ + char *sname; + + sname = s; + while (1) + { + if (any('/', sname)) + while (*sname++ != '/') + ; + else + return(sname); + } +} + +char * +getpath(s) + char *s; +{ + register char *path; + + if (any('/', s) || any(('/' | QUOTE), s)) + { + if (flags & rshflg) + failed(s, restricted); + else + return(nullstr); + } + else if ((path = pathnod.namval) == NIL) + return(defpath); + else + return(cpystak(path)); +} + +pathopen(path, name) +register char *path, *name; +{ + register int f; + + do + { + path = catpath(path, name); + } while ((f = open(curstak(), 0)) < 0 && path); + return(f); +} + +char * +catpath(path, name) +register char *path; +char *name; +{ + /* + * leaves result on top of stack + */ + register char *scanp = path; + register char *argp = locstak(); + + while (*scanp && *scanp != COLON) + *argp++ = *scanp++; + if (scanp != path) + *argp++ = '/'; + if (*scanp == COLON) + scanp++; + path = (*scanp ? scanp : NIL); + scanp = name; + while ((*argp++ = *scanp++)) + ; + return(path); +} + +char * +nextpath(path) + register char *path; +{ + register char *scanp = path; + + while (*scanp && *scanp != COLON) + scanp++; + + if (*scanp == COLON) + scanp++; + + return(*scanp ? scanp : NIL); +} + +static char *xecmsg; +static char **xecenv; + +static char * +execs(ap, t) +char *ap; +register char *t[]; +{ + register char *p, *prefix; + + prefix = catpath(ap, t[0]); + trim(p = curstak()); + sigchk(); + + execve(p, &t[0] ,xecenv); + switch (errno) + { + case ENOEXEC: /* could be a shell script */ + funcnt = 0; + flags = 0; + *flagadr = 0; + comdiv = 0; + ioset = 0; + clearup(); /* remove open files and for loop junk */ + if (input) + close(input); + input = chkopen(p); + + { + /* if the command file begins with # + * then we must call csh, + * else sh + */ + char s[2]; + if( !isatty(input)){ + s[1] = 0; s[0] = 0; + read ( input, s, 2 ); + if( s[0] == '#' && s[1] != '!' ) + gocsh( t, p, xecenv ); + lseek( input, (long)0, 0 ); + } + } + +#ifdef ACCOUNT + preacct(p); /* reset accounting */ +#endif + + /* + * set up new args + */ + + setargs(t); + longjmp(subshell, 1); + + case ENOMEM: + failed(p, toobig); + + case E2BIG: + failed(p, arglist); + + case ETXTBSY: + failed(p, txtbsy); + + default: + xecmsg = badexec; + case ENOENT: + return(prefix); + } +} + +int execa(at, pos) + char *at[]; + short pos; +{ + register char *path; + register char **t = at; + int cnt; + + if ((flags & noexec) == 0) + { + xecmsg = notfound; + path = getpath(*t); + xecenv = setenvv(); + + if (pos > 0) + { + cnt = 1; + while (cnt != pos) + { + ++cnt; + path = nextpath(path); + } + execs(path, t); + path = getpath(*t); + } + while (path = execs(path,t)) + ; + failed(*t, xecmsg); + } +} + +gocsh( t, cp, xecenv ) + register char **t, *cp, **xecenv; +{ + char *newt[ 1000 ]; + register char **p; + register int i; + + for( i=0; t[i] ; i++ ) + newt[ i+1 ] = t[ i ]; + newt[ i+1 ] = NIL; + newt[ 0 ] = "/bin/csh"; + newt[ 1 ] = cp; + execve( "/bin/csh", newt, xecenv ); + exit(33); +} + +/* + * for processes to be waited for + */ +#define MAXP 20 +static int pwlist[MAXP]; +static int pwc; + +postclr() +{ + register int *pw = pwlist; + + while (pw <= &pwlist[pwc]) + *pw++ = 0; + pwc = 0; +} + +post(pcsid) +int pcsid; +{ + register int *pw = pwlist; + + if (pcsid) + { + while (*pw) + pw++; + if (pwc >= MAXP - 1) + pw--; + else + pwc++; + *pw = pcsid; + } +} + +await(i, bckg) +int i, bckg; +{ + int rc = 0, wx = 0; + union wait w; + int ipwc = pwc; + + post(i); + while (pwc) + { + register int p; + register int sig; + int w_hi; + int found = 0; + + { + register int *pw = pwlist; + + p = wait(&w.w_status); + if (wasintr) + { + wasintr = 0; + if (bckg) + { + break; + } + } + while (pw <= &pwlist[ipwc]) + { + if (*pw == p) + { + *pw = 0; + pwc--; + found++; + } + else + pw++; + } + } + if (p == -1) + { + if (bckg) + { + register int *pw = pwlist; + + while (pw <= &pwlist[ipwc] && i != *pw) + pw++; + if (i == *pw) + { + *pw = 0; + pwc--; + } + } + continue; + } + w_hi = w.w_retcode; + if (sig = w.w_termsig) + { + if (sig == 0177) /* ptrace! return */ + { + prs("ptrace: "); + sig = w_hi; + } + if (sysmsg[sig]) + { + if (i != p || (flags & prompt) == 0) + { + prp(); + prn(p); + blank(); + } + prs(sysmsg[sig]); + if (w.w_coredump) + prs(coredump); + } + newline(); + } + if (rc == 0 && found != 0) + rc = (sig ? sig | SIGFLG : w_hi); + wx |= w.w_status; + if (p == i) + { + break; + } + } + if (wx && flags & errflg) + exitsh(rc); + flags |= eflag; + exitval = rc; + exitset(); +} + +BOOL nosubst; + +trim(at) +char *at; +{ + register char *p; + register char *ptr; + register char c; + register char q = 0; + + if (p = at) + { + ptr = p; + while (c = *p++) + { + /* @@@ if (*ptr = c & STRIP) */ + if( *ptr = smask(c)) + ++ptr; + q |= c; + } + + *ptr = 0; + } + /* @@@ nosubst = q & QUOTE; */ + nosubst = isq(q); +} + +char * +mactrim(s) +char *s; +{ + register char *t = macro(s); + + trim(t); + return(t); +} + +static int +gsort(from, to) +char *from[], *to[]; +{ + int k, m, n; + register int i, j; + + if ((n = to - from) <= 1) + return; + for (j = 1; j <= n; j *= 2) + ; + for (m = 2 * j - 1; m /= 2; ) + { + k = n - m; + for (j = 0; j < k; j++) + { + for (i = j; i >= 0; i -= m) + { + register char **fromi; + + fromi = &from[i]; + if (cf(fromi[m], fromi[0]) > 0) + { + break; + } + else + { + char *s; + + s = fromi[m]; + fromi[m] = fromi[0]; + fromi[0] = s; + } + } + } + } +} + +char ** +scan(argn) +int argn; +{ + register struct argnod *argp = (struct argnod *)(Rcheat(gchain) & ~ARGMK); + register char **comargn, **comargm; + + comargn = (char **)getstak(BYTESPERWORD * argn + BYTESPERWORD); + comargm = comargn += argn; + *comargn = ENDARGS; + while (argp) + { + *--comargn = argp->argval; + + trim(*comargn); + argp = argp->argnxt; + + if (argp == NIL || Rcheat(argp) & ARGMK) + { + gsort(comargn, comargm); + comargm = comargn; + } + /* Lcheat(argp) &= ~ARGMK; */ + argp = (struct argnod *)(Rcheat(argp) & ~ARGMK); + } + return(comargn); +} + +static int +split(s) /* blank interpretation routine */ +register char *s; +{ + register char *argp; + register int c; + int count = 0; + + for (;;) + { + sigchk(); + argp = locstak() + BYTESPERWORD; + while ((c = *s++, !any(c, ifsnod.namval) && c)) + *argp++ = c; + if (argp == staktop + BYTESPERWORD) + { + if (c) + { + continue; + } + else + { + return(count); + } + } + else if (c == 0) + s--; + /* + * file name generation + */ + + argp = endstak(argp); + + if ((flags & nofngflg) == 0 && + (c = expand(((struct argnod *)argp)->argval, 0))) + count += c; + else + { + makearg(argp); + count++; + } + gchain = (struct argnod *)((int)gchain | ARGMK); + } +} + +/* + * Argument list generation + */ +getarg(ac) +struct comnod *ac; +{ + register struct argnod *argp; + register int count = 0; + register struct comnod *c; + + if (c = ac) + { + argp = c->comarg; + while (argp) + { + count += split(macro(argp->argval)); + argp = argp->argnxt; + } + } + return(count); +} + +#ifdef ACCOUNT +#include +#include "acctdef.h" +#include +#include + +struct acct sabuf; +struct tms buffer; +extern long times(); +static long before; +static int shaccton; /* 0 implies do not write record on exit + 1 implies write acct record on exit + */ + + +/* + * suspend accounting until turned on by preacct() + */ + +suspacct() +{ + shaccton = 0; +} + +preacct(cmdadr) + char *cmdadr; +{ + char *simple(); + + if (acctnod.namval && *acctnod.namval) + { + sabuf.ac_btime = time((long *)NUL); + before = times(&buffer); + sabuf.ac_uid = getuid(); + sabuf.ac_gid = getgid(); + movstrn(simple(cmdadr), sabuf.ac_comm, sizeof(sabuf.ac_comm)); + shaccton = 1; + } +} + +#include + +doacct() +{ + int fd; + long int after; + + if (shaccton) + { + after = times(&buffer); + sabuf.ac_utime = compress(buffer.tms_utime + buffer.tms_cutime); + sabuf.ac_stime = compress(buffer.tms_stime + buffer.tms_cstime); + sabuf.ac_etime = compress(after - before); + + if ((fd = open(acctnod.namval, O_WRONLY | O_APPEND | O_CREAT, 0666)) != -1) + { + write(fd, &sabuf, sizeof(sabuf)); + close(fd); + } + } +} + +/* + * Produce a pseudo-floating point representation + * with 3 bits base-8 exponent, 13 bits fraction + */ + +compress(t) + register time_t t; +{ + register exp = 0; + register rund = 0; + + while (t >= 8192) + { + exp++; + rund = t & 04; + t >>= 3; + } + + if (rund) + { + t++; + if (t >= 8192) + { + t >>= 3; + exp++; + } + } + + return((exp << 13) + t); +} +#endif diff --git a/src/cmd/sh/setbrk.c b/src/cmd/sh/setbrk.c new file mode 100644 index 0000000..0b637be --- /dev/null +++ b/src/cmd/sh/setbrk.c @@ -0,0 +1,18 @@ +/* + * UNIX shell + * + * Bell Telephone Laboratories + */ +#include "defs.h" + +char *sbrk(); + +char* +setbrk(incr) +{ + + register char *a = sbrk(incr); + + brkend = a + incr; + return(a); +} diff --git a/src/cmd/sh/stak.c b/src/cmd/sh/stak.c new file mode 100644 index 0000000..47d103a --- /dev/null +++ b/src/cmd/sh/stak.c @@ -0,0 +1,82 @@ +/* + * UNIX shell + * + * Bell Telephone Laboratories + */ +#include "defs.h" + +/* ======== storage allocation ======== */ + +char * +getstak(asize) /* allocate requested stack */ +int asize; +{ + register char *oldstak; + register int size; + + size = round(asize, BYTESPERWORD); + oldstak = stakbot; + staktop = stakbot += size; + return(oldstak); +} + +/* + * set up stack for local use + * should be followed by `endstak' + */ +char * +locstak() +{ + if (brkend - stakbot < BRKINCR) + { + if (setbrk(brkincr) == -1) + error(nostack); + if (brkincr < BRKMAX) + brkincr += 256; + } + return(stakbot); +} + +char * +savstak() +{ + assert(staktop == stakbot); + return(stakbot); +} + +char * +endstak(argp) /* tidy up after `locstak' */ +register char *argp; +{ + register char *oldstak; + + *argp++ = 0; + oldstak = stakbot; + stakbot = staktop = (char *)round(argp, BYTESPERWORD); + return(oldstak); +} + +tdystak(x) /* try to bring stack back to x */ +register char *x; +{ + while ((char *)(stakbsy) > (char *)(x)) + { + free(stakbsy); + stakbsy = stakbsy->word; + } + staktop = stakbot = max((char *)(x), (char *)(stakbas)); + rmtemp(x); +} + +stakchk() +{ + if ((brkend - stakbas) > BRKINCR + BRKINCR) + setbrk(-BRKINCR); +} + +char * +cpystak(x) +char *x; +{ + return(endstak(movstr(x, locstak()))); +} diff --git a/src/cmd/sh/stak.h b/src/cmd/sh/stak.h new file mode 100644 index 0000000..889cd53 --- /dev/null +++ b/src/cmd/sh/stak.h @@ -0,0 +1,73 @@ +/* + * UNIX shell + * + * Bell Telephone Laboratories + */ + +/* To use stack as temporary workspace across + * possible storage allocation (eg name lookup) + * a) get ptr from `relstak' + * b) can now use `pushstak' + * c) then reset with `setstak' + * d) `absstak' gives real address if needed + */ +#define relstak() (staktop-stakbot) +#define absstak(x) (stakbot+Rcheat(x)) +#define setstak(x) (staktop=absstak(x)) +#define pushstak(c) (*staktop++=(c)) +#define zerostak() (*staktop=0) + +/* Used to address an item left on the top of + * the stack (very temporary) + */ +#define curstak() (staktop) + +/* `usestak' before `pushstak' then `fixstak' + * These routines are safe against heap + * being allocated. + */ +#define usestak() {locstak();} + +/* for local use only since it hands + * out a real address for the stack top + */ +extern char *locstak(); + +/* Will allocate the item being used and return its + * address (safe now). + */ +#define fixstak() endstak(staktop) + +/* For use after `locstak' to hand back + * new stack top and then allocate item + */ +extern char *endstak(); + +/* Copy a string onto the stack and + * allocate the space. + */ +extern char *cpystak(); + +/* Allocate given ammount of stack space */ +extern char *getstak(); + +/* A chain of ptrs of stack blocks that + * have become covered by heap allocation. + * `tdystak' will return them to the heap. + */ +extern struct blk *stakbsy; + +/* Base of the entire stack */ +extern char *stakbas; + +/* Top of entire stack */ +extern char *brkend; + +/* Base of current item */ +extern char *stakbot; + +/* Top of current item */ +extern char *staktop; + +/* Used with tdystak */ +extern char *savstak(); diff --git a/src/cmd/sh/string.c b/src/cmd/sh/string.c new file mode 100644 index 0000000..f00df75 --- /dev/null +++ b/src/cmd/sh/string.c @@ -0,0 +1,60 @@ +/* + * UNIX shell + * + * Bell Telephone Laboratories + */ +#include "defs.h" + +/* ======== general purpose string handling ======== */ + +char * +movstr(a, b) +register char *a, *b; +{ + while (*b++ = *a++); + return(--b); +} + +any(c, s) +register char c; +char *s; +{ + register char d; + + while (d = *s++) + { + if (d == c) + return(TRUE); + } + return(FALSE); +} + +cf(s1, s2) +register char *s1, *s2; +{ + while (*s1++ == *s2) + if (*s2++ == '\0') + return(0); + return *--s1 - *s2; +} + +length(as) +char *as; +{ + register char *s; + + if (s = as) + while (*s++); + return(s - as); +} + +char * +movstrn(a, b, n) + register char *a, *b; + register int n; +{ + while ((n-- > 0) && *a) + *b++ = *a++; + + return(b); +} diff --git a/src/cmd/sh/sym.h b/src/cmd/sh/sym.h new file mode 100644 index 0000000..3dff02f --- /dev/null +++ b/src/cmd/sh/sym.h @@ -0,0 +1,45 @@ +/* + * UNIX shell + */ + +/* symbols for parsing */ +#define DOSYM 0405 +#define FISYM 0420 +#define EFSYM 0422 +#define ELSYM 0421 +#define INSYM 0412 +#define BRSYM 0406 +#define KTSYM 0450 +#define THSYM 0444 +#define ODSYM 0441 +#define ESSYM 0442 +#define IFSYM 0436 +#define FORSYM 0435 +#define WHSYM 0433 +#define UNSYM 0427 +#define CASYM 0417 + +#define SYMREP 04000 +#define ECSYM (SYMREP|';') +#define ANDFSYM (SYMREP|'&') +#define ORFSYM (SYMREP|'|') +#define APPSYM (SYMREP|'>') +#define DOCSYM (SYMREP|'<') +#define EOFSYM 02000 +#define SYMFLG 0400 + +/* arg to `cmd' */ +#define NLFLG 1 +#define MTFLG 2 + +/* for peekc */ +#define MARK 0100000 + +/* odd chars */ +#define DQUOTE '"' +#define SQUOTE '`' +#define LITERAL '\'' +#define DOLLAR '$' +#define ESCAPE '\\' +#define BRACE '{' +#define COMCHAR '#' diff --git a/src/cmd/sh/test.c b/src/cmd/sh/test.c new file mode 100644 index 0000000..c7f6422 --- /dev/null +++ b/src/cmd/sh/test.c @@ -0,0 +1,247 @@ +/* + * test expression + * [ expression ] + */ +#include "defs.h" +#include +#include + +int ap, ac; +char **av; + +test(argn, com) +char *com[]; +int argn; +{ + ac = argn; + av = com; + ap = 1; + if (eq(com[0],"[")) + { + if (!eq(com[--ac], "]")) + failed("test", "] missing"); + } + com[ac] = NIL; + if (ac <= 1) + return(1); + return(exp0() ? 0 : 1); +} + +char * +nxtarg(mt) +{ + if (ap >= ac) + { + if (mt) + { + ap++; + return(NIL); + } + failed("test", "argument expected"); + } + return(av[ap++]); +} + +exp0() +{ + int p1; + char *p2; + + p1 = e1(); + p2 = nxtarg(1); + if (p2 != NIL) + { + if (eq(p2, "-o")) + return(p1 | exp0()); + + if (eq(p2, "]") && !eq(p2, ")")) + failed("test", synmsg); + } + ap--; + return(p1); +} + +e1() +{ + int p1; + char *p2; + + p1 = e2(); + p2 = nxtarg(1); + + if ((p2 != NIL) && eq(p2, "-a")) + return(p1 & e1()); + ap--; + return(p1); +} + +e2() +{ + if (eq(nxtarg(0), "!")) + return(!e3()); + ap--; + return(e3()); +} + +e3() +{ + int p1; + register char *a; + char *p2; + long atol(); + long int1, int2; + + a = nxtarg(0); + if (eq(a, "(")) + { + p1 = exp0(); + if (!eq(nxtarg(0), ")")) + failed("test",") expected"); + return(p1); + } + p2 = nxtarg(1); + ap--; + if ((p2 == NIL) || (!eq(p2, "=") && !eq(p2, "!="))) + { + if (eq(a, "-r")) + return(tio(nxtarg(0), 4)); + if (eq(a, "-w")) + return(tio(nxtarg(0), 2)); + if (eq(a, "-x")) + return(tio(nxtarg(0), 1)); + if (eq(a, "-d")) + return(filtyp(nxtarg(0), S_IFDIR)); + if (eq(a, "-c")) + return(filtyp(nxtarg(0), S_IFCHR)); + if (eq(a, "-b")) + return(filtyp(nxtarg(0), S_IFBLK)); + if (eq(a, "-f")) + return(filtyp(nxtarg(0), S_IFREG)); + if (eq(a, "-u")) + return(ftype(nxtarg(0), S_ISUID)); + if (eq(a, "-g")) + return(ftype(nxtarg(0), S_ISGID)); + if (eq(a, "-k")) + return(ftype(nxtarg(0), S_ISVTX)); + if (eq(a, "-p")) + return(filtyp(nxtarg(0),S_IFIFO)); + if (eq(a, "-s")) + return(fsizep(nxtarg(0))); + if (eq(a, "-t")) + { + if (ap >= ac) /* no args */ + return(isatty(1)); + else if (eq((a = nxtarg(0)), "-a") || eq(a, "-o")) + { + ap--; + return(isatty(1)); + } + else + return(isatty(atoi(a))); + } + if (eq(a, "-n")) + return(!eq(nxtarg(0), "")); + if (eq(a, "-z")) + return(eq(nxtarg(0), "")); + } + + p2 = nxtarg(1); + if (p2 == NIL) + return(!eq(a, "")); + if (eq(p2, "-a") || eq(p2, "-o")) + { + ap--; + return(!eq(a, "")); + } + if (eq(p2, "=")) + return(eq(nxtarg(0), a)); + if (eq(p2, "!=")) + return(!eq(nxtarg(0), a)); + int1 = atol(a); + int2 = atol(nxtarg(0)); + if (eq(p2, "-eq")) + return(int1 == int2); + if (eq(p2, "-ne")) + return(int1 != int2); + if (eq(p2, "-gt")) + return(int1 > int2); + if (eq(p2, "-lt")) + return(int1 < int2); + if (eq(p2, "-ge")) + return(int1 >= int2); + if (eq(p2, "-le")) + return(int1 <= int2); + + bfailed(btest, badop, p2); +/* NOTREACHED */ +} + +tio(a, f) +char *a; +int f; +{ + if (access(a, f) == 0) + return(1); + else + return(0); +} + +ftype(f, field) +char *f; +int field; +{ + struct stat statb; + + if (stat(f, &statb) < 0) + return(0); + if ((statb.st_mode & field) == field) + return(1); + return(0); +} + +filtyp(f,field) +char *f; +int field; +{ + struct stat statb; + + if (stat(f, &statb) < 0) + return(0); + if ((statb.st_mode & S_IFMT) == field) + return(1); + else + return(0); +} + + + +fsizep(f) +char *f; +{ + struct stat statb; + + if (stat(f, &statb) < 0) + return(0); + return(statb.st_size > 0L); +} + +/* + * fake diagnostics to continue to look like original + * test(1) diagnostics + */ +bfailed(s1, s2, s3) +char *s1; +char *s2; +char *s3; +{ + prp(); + prs(s1); + if (s2) + { + prs(colon); + prs(s2); + prs(s3); + } + newline(); + exitsh(ERROR); +} diff --git a/src/cmd/sh/timeout.h b/src/cmd/sh/timeout.h new file mode 100644 index 0000000..d927b5d --- /dev/null +++ b/src/cmd/sh/timeout.h @@ -0,0 +1,7 @@ +/* + * UNIX shell + * + * Bell Telephone Laboratories + */ +#define TIMEOUT 0 /* seconds elapsing before log-off (normal) */ +#define MAILCHECK "600" /* 10 minutes */ diff --git a/src/cmd/sh/trace.c b/src/cmd/sh/trace.c new file mode 100644 index 0000000..7c1407f --- /dev/null +++ b/src/cmd/sh/trace.c @@ -0,0 +1,32 @@ +#include +#include +#include +#include "dup.h" + +/* Debugging routines */ +#define TRACEF "/usr/abs/sh/trace" + +static int fp = (-1); +unsigned was_traced = 0; + +trace( fmt, va_alist ) +char *fmt; +va_dcl +{ + va_list args; + char buf[256]; + + if( fp < 0){ + fp = creat( TRACEF, 0644 ); + if( fp < 0 ) exit(13); + fcntl( fp, F_SETFD, EXCLOSE ); + } + + va_start( args ); +/* vsprintf( buf, fmt, args ); */ + strcpy( buf, fmt ); + write( fp, buf, strlen(buf)); + va_end( args ); + was_traced++; +} + diff --git a/src/cmd/sh/word.c b/src/cmd/sh/word.c new file mode 100644 index 0000000..bf81ee9 --- /dev/null +++ b/src/cmd/sh/word.c @@ -0,0 +1,243 @@ +/* + * UNIX shell + * + * Bell Telephone Laboratories + */ +#include "defs.h" +#include "sym.h" + +/* ======== character handling for command lines ========*/ + +word() +{ + register char c, d; + struct argnod *arg = (struct argnod *)locstak(); + register char *argp = arg->argval; + int alpha = 1; + + wdnum = 0; + wdset = 0; + + while (1) + { + while (c = nextc(0), space(c)) /* skipc() */ + ; + + if (c == COMCHAR) + { + while ((c = readc()) != NL && c != EOF); + peekc = c; + } + else + { + break; /* out of comment - white space loop */ + } + } + if (!eofmeta(c)) + { + do + { + if (c == LITERAL) + { + *argp++ = (DQUOTE); + while ((c = readc()) && c != LITERAL) + { + /* @@@ *argp++ = (c | QUOTE); */ + *argp++ = qmask(c); + + if (c == NL) + chkpr(); + } + *argp++ = (DQUOTE); + } + else + { + *argp++ = (c); + if (c == '=') + wdset |= alpha; + if (!alphanum(c)) + alpha = 0; + if (qotchar(c)) + { + d = c; + while ((*argp++ = (c = nextc(d))) && c != d) + { + if (c == NL) + chkpr(); + } + } + } + } while ((c = nextc(0), !eofmeta(c))); + argp = endstak(argp); + if (!letter(arg->argval[0])) + wdset = 0; + + peekn = c | MARK; + if (arg->argval[1] == 0 && + (d = arg->argval[0], digit(d)) && + (c == '>' || c == '<')) + { + word(); + wdnum = d - '0'; + } + else /*check for reserved words*/ + { + if (reserv == FALSE || (wdval = syslook(arg->argval,reserved, no_reserved)) == 0) + { + wdarg = arg; + wdval = 0; + } + } + } + else if (dipchar(c)) + { + if ((d = nextc(0)) == c) + { + wdval = c | SYMREP; + if (c == '<') + { + if ((d = nextc(0)) == '-') + wdnum |= IOSTRIP; + else + peekn = d | MARK; + } + } + else + { + peekn = d | MARK; + wdval = c; + } + } + else + { + if ((wdval = c) == EOF) + wdval = EOFSYM; + if (iopend && eolchar(c)) + { + copy(iopend); + iopend = 0; + } + } + reserv = FALSE; + return(wdval); +} + +skipc() +{ + register char c; + + while (c = nextc(0), space(c)) + ; + return(c); +} + +nextc(quote) +char quote; +{ + register char c, d; + +retry: + if ((d = readc()) == ESCAPE) + { + if ((c = readc()) == NL) + { + chkpr(); + goto retry; + } + else if (quote && c != quote && !escchar(c)) + peekc = c | MARK; + else + /* @@@ d = c | QUOTE; */ + d = qmask(c); + } + return(d); +} + +readc() +{ + register char c; + register int len; + register struct fileblk *f; + + if (peekn) + { + peekc = peekn; + peekn = 0; + } + if (peekc) + { + c = peekc; + peekc = 0; + return(c); + } + f = standin; +retry: + if (f->fnxt != f->fend) + { + if ((c = *f->fnxt++) == 0) + { + if (f->feval) + { + if (estabf(*f->feval++)) + c = EOF; + else + c = SP; + } + else + goto retry; /* = c = readc(); */ + } + if (flags & readpr && standin->fstak == NIL) + prc(c); + if (c == NL) + f->flin++; + } + else if (f->feof || f->fdes < 0) + { + c = EOF; + f->feof++; + } + else if ((len = readb()) <= 0) + { + close(f->fdes); + f->fdes = -1; + c = EOF; + f->feof++; + } + else + { + f->fend = (f->fnxt = f->fbuf) + len; + goto retry; + } + return(c); +} + +readb() +{ + register struct fileblk *f = standin; + register int len; + + do + { + if (trapnote & SIGSET) + { + newline(); + sigchk(); + } + else if ((trapnote & TRAPSET) && (rwait > 0)) + { + newline(); + chktrap(); + clearup(); + } + + len = read(f->fdes, f->fbuf, (f->fsiz) & 0377); + + /* @@@ &0377 HACK, because of fsiz is unsigned char, + * which is not supported on pdp11-unix. + * Then the sign extension happens ! + */ + + } while ( len < 0 && trapnote ); + + return(len); +} diff --git a/src/cmd/sh/xec.c b/src/cmd/sh/xec.c new file mode 100644 index 0000000..7060460 --- /dev/null +++ b/src/cmd/sh/xec.c @@ -0,0 +1,877 @@ +/* + * UNIX shell + * + * Bell Telephone Laboratories + */ +#include "defs.h" +#include +#include "sym.h" +#include "hash.h" + +static int parent; + +/* ======== command execution ========*/ + +execute(argt, exec_link, errorflg, pf1, pf2) +struct trenod *argt; +int *pf1, *pf2; +{ + /* + * `stakbot' is preserved by this routine + */ + register struct trenod *t; + char *sav = savstak(); + + sigchk(); + if (!errorflg) + flags &= ~errflg; + + if ((t = argt) && execbrk == 0) + { + register int treeflgs; + int type; + register char **com; + short pos; + int linked; + int execflg; + + linked = exec_link >> 1; + execflg = exec_link & 01; + + treeflgs = t->tretyp; + type = treeflgs & COMMSK; + + switch (type) + { + case TFND: + { + struct fndnod *f = (struct fndnod *)t; + struct namnod *n = lookup(f->fndnam); + + exitval = 0; + + if (n->namflg & N_RDONLY) + failed(n->namid, wtfailed); + + if (n->namflg & N_FUNCTN) + freefunc(n); + else + { + free(n->namval); + free(n->namenv); + + n->namval = NIL; + n->namflg &= ~(N_EXPORT | N_ENVCHG); + } + + if (funcnt) + f->fndval->tretyp++; + + n->namenv = (char *)f->fndval; + attrib(n, N_FUNCTN); + hash_func(n->namid); + break; + } + + case TCOM: + { + char *a1; + int argn, internal; + struct argnod *schain = gchain; + struct ionod *io = t->treio; + short cmdhash; + short comtype; + + exitval = 0; + + gchain = NIL; + argn = getarg(t); + com = scan(argn); + a1 = com[1]; + gchain = schain; + + if (argn != 0) + cmdhash = pathlook(com[0], 1, comptr(t)->comset); + + if (argn == 0 || (comtype = hashtype(cmdhash)) == BUILTIN) + setlist(comptr(t)->comset, 0); + + if (argn && (flags&noexec) == 0) + { + /* print command if execpr */ + + if (flags & execpr) + execprint(com); + + if (comtype == NOTFOUND) + { + pos = hashdata(cmdhash); + if (pos == 1) + failed(*com, notfound); + else if (pos == 2) + failed(*com, badexec); + else + failed(*com, badperm); + break; + } + + else if (comtype == PATH_COMMAND) + { + pos = -1; + } + + else if (comtype & (COMMAND | REL_COMMAND)) + { + pos = hashdata(cmdhash); + } + + else if (comtype == BUILTIN) + { + short index; + + internal = hashdata(cmdhash); + index = initio(io, (internal != SYSEXEC)); + + switch (internal) + { + case SYSDOT: + if (a1) + { + register int f; + + if ((f = pathopen(getpath(a1), a1)) < 0) + failed(a1, notfound); + else + execexp(NIL, f); + } + break; + + case SYSTIMES: + { + long int t[4]; + + times(t); + prt(t[2]); + prc_buff(SP); + prt(t[3]); + prc_buff(NL); + } + break; + + case SYSEXIT: + flags |= forked; /* force exit */ + exitsh(a1 ? stoi(a1) : retval); + + case SYSNULL: + io = NIL; + break; + + case SYSCONT: + if (loopcnt) + { + execbrk = breakcnt = 1; + if (a1) + breakcnt = stoi(a1); + if (breakcnt > loopcnt) + breakcnt = loopcnt; + else + breakcnt = -breakcnt; + } + break; + + case SYSBREAK: + if (loopcnt) + { + execbrk = breakcnt = 1; + if (a1) + breakcnt = stoi(a1); + if (breakcnt > loopcnt) + breakcnt = loopcnt; + } + break; + + case SYSTRAP: + if (a1) + { + BOOL clear; + + if ((clear = digit(*a1)) == 0) + ++com; + while (*++com) + { + int i; + + if ((i = stoi(*com)) >= MAXTRAP || i < MINTRAP) + failed(*com, badtrap); + else if (clear) + clrsig(i); + else + { + replace(&trapcom[i], a1); + if (*a1) + getsig(i); + else + ignsig(i); + } + } + } + else /* print out current traps */ + { + int i; + + for (i = 0; i < MAXTRAP; i++) + { + if (trapcom[i]) + { + prn_buff(i); + prs_buff(colon); + prs_buff(trapcom[i]); + prc_buff(NL); + } + } + } + break; + + case SYSEXEC: + com++; + ioset = 0; + io = NIL; + if (a1 == NIL) + { + break; + } + + case SYSLOGIN: + oldsigs(); + execa(com, -1); + done(); + + case SYSNEWGRP: + if (flags & rshflg) + failed(com[0], restricted); + else + { + flags |= forked; /* force bad exec to terminate shell */ + oldsigs(); + execa(com, -1); + done(); + } + + case SYSCD: + if (flags & rshflg) + failed(com[0], restricted); + else if ((a1 && *a1) || (a1 == NIL && (a1 = homenod.namval))) + { + char *cdpath; + char *dir; + int f; + + if ((cdpath = cdpnod.namval) == NIL || + *a1 == '/' || + cf(a1, ".") == 0 || + cf(a1, "..") == 0 || + (*a1 == '.' && (a1[1] == '/' || a1[1] == '.' && a1[2] == '/'))) + cdpath = nullstr; + + do + { + dir = cdpath; + cdpath = catpath(cdpath,a1); + } + while ((f = (chdir(curstak()) < 0)) && cdpath); + + if (f) + failed(a1, baddir); + else + { + cwd(curstak()); + if (cf(nullstr, dir) && + *dir != ':' && + any('/', curstak()) && + flags & prompt) + { + prs_buff(curstak()); + prc_buff(NL); + } + } + zapcd(); + } + else + { + if (a1) + failed(a1, baddir); + else + error(nohome); + } + + break; + + case SYSSHFT: + { + int places; + + places = a1 ? stoi(a1) : 1; + + if ((dolc -= places) < 0) + { + dolc = 0; + error(badshift); + } + else + dolv += places; + } + + break; + + case SYSWAIT: + await(a1 ? stoi(a1) : -1, 1); + break; + + case SYSREAD: + rwait = 1; + exitval = readvar(&com[1]); + rwait = 0; + break; + + case SYSSET: + if (a1) + { + int argc; + + argc = options(argn, com); + if (argc > 1) + setargs(com + argn - argc); + } + else if (comptr(t)->comset == NIL) + { + /* + * scan name chain and print + */ + namscan(printnam); + } + break; + + case SYSRDONLY: + exitval = 0; + if (a1) + { + while (*++com) + attrib(lookup(*com), N_RDONLY); + } + else + namscan(printro); + + break; + + case SYSXPORT: + { + struct namnod *n; + + exitval = 0; + if (a1) + { + while (*++com) + { + n = lookup(*com); + if (n->namflg & N_FUNCTN) + error(badexport); + else + attrib(n, N_EXPORT); + } + } + else + namscan(printexp); + } + break; + + case SYSEVAL: + if (a1) + execexp(a1, &com[2]); + break; + +#ifndef RES +#ifdef ACCOUNT + case SYSULIMIT: + { + long int i; + long ulimit(); + int command = 2; + + if (*a1 == '-') + { switch(a1[1]) + { + case 'f': + command = 2; + break; + +#ifdef rt + case 'p': + command = 5; + break; + +#endif + + default: + error(badopt); + } + a1 = com[2]; + } + if (a1) + { + int c; + + i = 0; + while ((c = *a1++) >= '0' && c <= '9') + { + i = (i * 10) + (long)(c - '0'); + if (i < 0) + error(badulimit); + } + if (c || i < 0) + error(badulimit); + } + else + { + i = -1; + command--; + } + + if ((i = ulimit(command,i)) < 0) + error(badulimit); + + if (command == 1 || command == 4) + { + prl(i); + prc_buff('\n'); + } + break; + } +#endif + case SYSUMASK: + if (a1) + { + int c, i; + + i = 0; + while ((c = *a1++) >= '0' && c <= '7') + i = (i << 3) + c - '0'; + umask(i); + } + else + { + int i, j; + + umask(i = umask(0)); + prc_buff('0'); + for (j = 6; j >= 0; j -= 3) + prc_buff(((i >> j) & 07) +'0'); + prc_buff(NL); + } + break; + +#endif + + case SYSTST: + exitval = test(argn, com); + break; + + case SYSECHO: + exitval = echo(argn, com); + break; + + case SYSHASH: + exitval = 0; + + if (a1) + { + if (a1[0] == '-') + { + if (a1[1] == 'r') + zaphash(); + else + error(badopt); + } + else + { + while (*++com) + { + if (hashtype(hash_cmd(*com)) == NOTFOUND) + failed(*com, notfound); + } + } + } + else + hashpr(); + + break; + + case SYSPWD: + { + exitval = 0; + cwdprint(); + } + break; + + case SYSRETURN: + if (funcnt == 0) + error(badreturn); + + execbrk = 1; + exitval = (a1 ? stoi(a1) : retval); + break; + + case SYSTYPE: + exitval = 0; + if (a1) + { + while (*++com) + what_is_path(*com); + } + break; + + case SYSUNS: + exitval = 0; + if (a1) + { + while (*++com) + unset_name(*com); + } + break; + + default: + prs_buff("unknown builtin\n"); + } + + + flushb(); + restore(index); + chktrap(); + break; + } + + else if (comtype == FUNCTION) + { + struct namnod *n; + short index; + + n = findnam(com[0]); + + funcnt++; + index = initio(io, 1); + setargs(com); + execute((struct trenod *)(n->namenv), exec_link, errorflg, pf1, pf2); + execbrk = 0; + restore(index); + funcnt--; + + break; + } + } + else if (t->treio == NIL) + { + chktrap(); + break; + } + + } + + case TFORK: + exitval = 0; + if (execflg && (treeflgs & (FAMP | FPOU)) == 0) + parent = 0; + else + { + int forkcnt = 1; + + if (treeflgs & (FAMP | FPOU)) + { + link_iodocs(iotemp); + linked = 1; + } + + + /* + * FORKLIM is the max period between forks - + * power of 2 usually. Currently shell tries after + * 2,4,8,16, and 32 seconds and then quits + */ + + while ((parent = fork()) == -1) + { + if ((forkcnt = (forkcnt * 2)) > FORKLIM) /* 32 */ + { + switch (errno) + { + case ENOMEM: + error(noswap); + break; + default: + case EAGAIN: + error(nofork); + break; + } + } + sigchk(); + alarm(forkcnt); + pause(); + } + } + if (parent) + { + /* + * This is the parent branch of fork; + * it may or may not wait for the child + */ + if (treeflgs & FPRS && flags & ttyflg) + { + prn(parent); + newline(); + } + if (treeflgs & FPCL) + closepipe(pf1); + if ((treeflgs & (FAMP | FPOU)) == 0) + await(parent, 0); + else if ((treeflgs & FAMP) == 0) + post(parent); + else + assnum(&pcsadr, parent); + chktrap(); + break; + } + else /* this is the forked branch (child) of execute */ + { + flags |= forked; + fiotemp = NIL; + + if (linked == 1) + { + swap_iodoc_nm(iotemp); + exec_link |= 06; + } + else if (linked == 0) + iotemp = NIL; + +#ifdef ACCOUNT + suspacct(); +#endif + + postclr(); + settmp(); + /* + * Turn off INTR and QUIT if `FINT' + * Reset ramaining signals to parent + * except for those `lost' by trap + */ + oldsigs(); + if (treeflgs & FINT) + { + signal(SIGINT, SIG_IGN); + signal(SIGQUIT, SIG_IGN); + +#ifdef NICE + nice(NICEVAL); +#endif + + } + /* + * pipe in or out + */ + if (treeflgs & FPIN) + { + rename(pf1[INPIPE], 0); + close(pf1[OTPIPE]); + } + if (treeflgs & FPOU) + { + close(pf2[INPIPE]); + rename(pf2[OTPIPE], 1); + } + /* + * default std input for & + */ + if (treeflgs & FINT && ioset == 0) + rename(chkopen(devnull), 0); + /* + * io redirection + */ + initio(t->treio, 0); + + if (type != TCOM) + { + execute(forkptr(t)->forktre, exec_link | 01, errorflg); + } + else if (com[0] != ENDARGS) + { + eflag = 0; + setlist(comptr(t)->comset, N_EXPORT); + rmtemp(NIL); + execa(com, pos); + } + done(); + } + + case TPAR: + execute(parptr(t)->partre, exec_link, errorflg); + done(); + + case TFIL: + { + int pv[2]; + + chkpipe(pv); + if (execute(lstptr(t)->lstlef, 0, errorflg, pf1, pv) == 0) + execute(lstptr(t)->lstrit, exec_link, errorflg, pv, pf2); + else + closepipe(pv); + } + break; + + case TLST: + execute(lstptr(t)->lstlef, 0, errorflg); + execute(lstptr(t)->lstrit, exec_link, errorflg); + break; + + case TAND: + if (execute(lstptr(t)->lstlef, 0, 0) == 0) + execute(lstptr(t)->lstrit, exec_link, errorflg); + break; + + case TORF: + if (execute(lstptr(t)->lstlef, 0, 0) != 0) + execute(lstptr(t)->lstrit, exec_link, errorflg); + break; + + case TFOR: + { + struct namnod *n = lookup(forptr(t)->fornam); + char **args; + struct dolnod *argsav = NIL; + + if (forptr(t)->forlst == NIL) + { + args = dolv + 1; + argsav = useargs(); + } + else + { + struct argnod *schain = gchain; + + gchain = NIL; + trim((args = scan(getarg(forptr(t)->forlst)))[0]); + gchain = schain; + } + loopcnt++; + while (*args != ENDARGS && execbrk == 0) + { + assign(n, *args++); + execute(forptr(t)->fortre, 0, errorflg); + if (breakcnt < 0) + execbrk = (++breakcnt != 0); + } + if (breakcnt > 0) + execbrk = (--breakcnt != 0); + + loopcnt--; + argfor = (struct dolnod *)freeargs(argsav); + } + break; + + case TWH: + case TUN: + { + int i = 0; + + loopcnt++; + while (execbrk == 0 && (execute(whptr(t)->whtre, 0, 0) == 0) == (type == TWH)) + { + i = execute(whptr(t)->dotre, 0, errorflg); + if (breakcnt < 0) + execbrk = (++breakcnt != 0); + } + if (breakcnt > 0) + execbrk = (--breakcnt != 0); + + loopcnt--; + exitval = i; + } + break; + + case TIF: + if (execute(ifptr(t)->iftre, 0, 0) == 0) + execute(ifptr(t)->thtre, exec_link, errorflg); + else if (ifptr(t)->eltre) + execute(ifptr(t)->eltre, exec_link, errorflg); + else + exitval = 0; /* force zero exit for if-then-fi */ + break; + + case TSW: + { + register char *r = mactrim(swptr(t)->swarg); + register struct regnod *regp; + + regp = swptr(t)->swlst; + while (regp) + { + struct argnod *rex = regp->regptr; + + while (rex) + { + register char *s; + + if (gmatch(r, s = macro(rex->argval)) || (trim(s), eq(r, s))) + { + execute(regp->regcom, 0, errorflg); + regp = NIL; + break; + } + else + rex = rex->argnxt; + } + if (regp) + regp = regp->regnxt; + } + } + break; + } + exitset(); + } + sigchk(); + tdystak(sav); + flags |= eflag; + return(exitval); +} + +execexp(s, f) +char *s; +int f; +{ + struct fileblk fb; + + push(&fb); + if (s) + { + estabf(s); + fb.feval = (char **)(f); + } + else if (f >= 0) + initf(f); + execute(cmd(NL, NLFLG | MTFLG), 0, (int)(flags & errflg)); + pop(); +} + +execprint(com) + char **com; +{ + register int argn = 0; + + prs(execpmsg); + + while(com[argn] != ENDARGS) + { + prs(com[argn++]); + blank(); + } + + newline(); +} diff --git a/src/cmd/shutdown/Makefile b/src/cmd/shutdown/Makefile new file mode 100644 index 0000000..50ee1e9 --- /dev/null +++ b/src/cmd/shutdown/Makefile @@ -0,0 +1,43 @@ +# +# Public Domain. 1996/11/16 - Steven Schultz +# Should be installed with group operator. +# +TOPSRC = $(shell cd ../../..; pwd) +include $(TOPSRC)/target.mk + +CFLAGS += -Werror + +SRCS = shutdown.c +OBJS = shutdown.o +MAN = shutdown.0 +MANSRC = shutdown.8 + +all: shutdown ${MAN} + +shutdown: ${OBJS} + ${CC} ${LDFLAGS} -o shutdown.elf ${OBJS} ${LIBS} + ${OBJDUMP} -S shutdown.elf > shutdown.dis + ${SIZE} shutdown.elf + ${ELF2AOUT} shutdown.elf $@ && rm shutdown.elf + +${MAN}: ${MANSRC} + ${MANROFF} ${MANSRC} > ${MAN} + +clean: + rm -f *.o *.elf ${MAN} shutdown *.elf *.dis tags *~ + +depend: ${SRCS} + mkdep ${CFLAGS} ${SRCS} + +install: all + cp ${MAN} ${DESTDIR}/share/man/cat8/ + install -m 4750 shutdown ${DESTDIR}/sbin/shutdown + +lint: ${SRCS} + lint -hax ${SRCS} + +tags: ${SRCS} + ctags ${SRCS} + +# DO NOT DELETE THIS LINE -- mkdep uses it. +# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY. diff --git a/src/cmd/shutdown/shutdown.8 b/src/cmd/shutdown/shutdown.8 new file mode 100644 index 0000000..cc40ba1 --- /dev/null +++ b/src/cmd/shutdown/shutdown.8 @@ -0,0 +1,112 @@ +.\" Copyright (c) 1980 Regents of the University of California. +.\" All rights reserved. The Berkeley software License Agreement +.\" specifies the terms and conditions for redistribution. +.\" +.\" @(#)shutdown.8 6.4.1 (2.11BSD) 1996/11/16 +.\" +.TH SHUTDOWN 8 "November 16, 1996" +.UC 4 +.SH NAME +shutdown \- close down the system at a given time +.SH SYNOPSIS +.B shutdown +[ +.B \-k +] [ +.B \-r +] [ +.B \-h +] [ +.B \-f +] [ +.B \-n +] +time [ warning-message ... ] +.SH DESCRIPTION +.I Shutdown +provides an automated shutdown procedure which a super-user +can use to notify users +nicely when the system is shutting down, saving them from +system administrators, hackers, and gurus, who would otherwise +not bother with niceties. +.LP +.I Time +is the time at which +.I shutdown +will bring the system down and +may be the word +.B now +(indicating an immediate shutdown) +or specify a future time in one of two formats: +.BR + number +and +.RB hour : min. +The first form brings the system down in +.I number +minutes +and the second brings the system down at the time of day indicated +(as a 24\-hour clock). +.PP +At intervals which get closer together as apocalypse approaches, +warning messages are displayed at the terminals of all users on the +system. Five minutes before shutdown, or immediately if +shutdown is in less than 5 minutes, logins are disabled by +creating +/etc/nologin +and writing a message there. +If this file exists when a user attempts to log in, +.IR login (1) +prints its contents +and exits. +The file is removed just before +.I shutdown +exits. +.PP +At shutdown time a +message is written in the system log, containing the +time of shutdown, who ran shutdown and the reason. +Then a terminate signal is sent to +.I init +to bring the system down to single-user state. +Alternatively, if +.B \-r, +.B \-h, +or +.B \-k +was used, then +.I shutdown +will exec +.IR reboot (8), +.IR halt (8), +or avoid shutting the system down (respectively). +(If it isn't obvious, +.B \-k +is to make people +.I think +the system is going down!) +.PP +With the +.B \-f +option, +.I shutdown +arranges, in the manner of +.IR fastboot (8), +that when the system is rebooted the file systems will not +be checked. The +.B \-n +option prevents the normal +.IR sync (2) +before stopping. +.PP +The time of the shutdown and the warning message +are placed in /etc/nologin and should be used to +inform the users about when the system will be back up +and why it is going down (or anything else). +.SH FILES +.DT +/etc/nologin tells login not to let anyone log in +.SH "SEE ALSO" +login(1), reboot(8), fastboot(8) +.SH BUGS +Only allows you to kill the system between now and 23:59 if +you use the absolute time for shutdown. diff --git a/src/cmd/shutdown/shutdown.c b/src/cmd/shutdown/shutdown.c new file mode 100644 index 0000000..52bd9e9 --- /dev/null +++ b/src/cmd/shutdown/shutdown.c @@ -0,0 +1,392 @@ +/* + * shutdown when [messages] + * + * allow super users to tell users and remind users + * of imminent shutdown of unix + * and shut it down automatically + * and even reboot or halt the machine if they desire + * + * Copyright (c) 1983,1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define REBOOT "/sbin/reboot" +#define HALT "/sbin/halt" +#define MAXINTS 20 +#define HOURS *3600 +#define MINUTES *60 +#define SECONDS +#define NLOG 600 /* no of bytes possible for message */ +#define NOLOGTIME 5 MINUTES +#define IGNOREUSER "sleeper" + +char hostname[MAXHOSTNAMELEN]; + +time_t getsdt(); + +struct utmp utmp; +int sint; +long stogo; +char tpath[] = "/dev/"; +int nlflag = 1; /* nolog yet to be done */ +int killflg = 1; +int doreboot = 0; +int halt = 0; +int fast = 0; +char *nosync = NULL; +char nosyncflag[] = "-n"; +char term[sizeof tpath + sizeof utmp.ut_line]; +char tbuf[BUFSIZ]; +char nolog1[] = "\n\nNO LOGINS: System going down at %5.5s\n\n"; +char nolog2[NLOG+1]; +#ifdef DEBUG +char nologin[] = "nologin"; +char fastboot[] = "fastboot"; +#else +char nologin[] = _PATH_NOLOGIN; +char fastboot[] = "/fastboot"; +#endif +time_t nowtime; +jmp_buf alarmbuf; + +struct interval { + int stogo; + int sint; +} interval[] = { + 4 HOURS, 1 HOURS, + 2 HOURS, 30 MINUTES, + 1 HOURS, 15 MINUTES, + 30 MINUTES, 10 MINUTES, + 15 MINUTES, 5 MINUTES, + 10 MINUTES, 5 MINUTES, + 5 MINUTES, 3 MINUTES, + 2 MINUTES, 1 MINUTES, + 1 MINUTES, 30 SECONDS, + 0 SECONDS, 0 SECONDS +}; + +char *shutter; + +void finish(sig) + int sig; +{ + (void) signal(SIGTERM, SIG_IGN); + (void) unlink(nologin); + exit(0); +} + +void timeout(sig) + int sig; +{ + longjmp(alarmbuf, 1); +} + +warning(term, sdt, now, type) + FILE *term; + time_t sdt, now; + char *type; +{ + char *ts; + register delay = sdt - now; + + if (delay > 8) + while (delay % 5) + delay++; + + fprintf(term, + "\007\007\t*** %sSystem shutdown message from %s@%s ***\r\n\n", + type, shutter, hostname); + + ts = ctime(&sdt); + if (delay > 10 MINUTES) + fprintf(term, "System going down at %5.5s\r\n", ts+11); + else if (delay > 95 SECONDS) { + fprintf(term, "System going down in %d minute%s\r\n", + (delay+30)/60, (delay+30)/60 != 1 ? "s" : ""); + } else if (delay > 0) { + fprintf(term, "System going down in %d second%s\r\n", + delay, delay != 1 ? "s" : ""); + } else + fprintf(term, "System going down IMMEDIATELY\r\n"); +} + +main(argc,argv) + int argc; + char **argv; +{ + register i, ufd; + register char *f; + char *ts; + time_t sdt; + int h, m; + int first; + FILE *termf; + struct passwd *pw; + + shutter = getlogin(); + if (shutter == 0 && (pw = getpwuid(getuid()))) + shutter = pw->pw_name; + if (shutter == 0) + shutter = "???"; + (void) gethostname(hostname, sizeof (hostname)); + openlog("shutdown", 0, LOG_AUTH); + argc--, argv++; + while (argc > 0 && (f = argv[0], *f++ == '-')) { + while (i = *f++) switch (i) { + case 'k': + killflg = 0; + continue; + case 'n': + nosync = nosyncflag; + continue; + case 'f': + fast = 1; + continue; + case 'r': + doreboot = 1; + continue; + case 'h': + halt = 1; + continue; + default: + fprintf(stderr, "shutdown: '%c' - unknown flag\n", i); + exit(1); + } + argc--, argv++; + } + if (argc < 1) { + /* argv[0] is not available after the argument handling. */ + printf("Usage: shutdown [ -krhfn ] shutdowntime [ message ]\n"); + finish(0); + } + if (fast && (nosync == nosyncflag)) { + printf ("shutdown: Incompatible switches 'fast' & 'nosync'\n"); + finish(0); + } + if (geteuid()) { + fprintf(stderr, "NOT super-user\n"); + finish(0); + } + nowtime = time((long *)0); + sdt = getsdt(argv[0]); + argc--, argv++; + nolog2[0] = '\0'; + while (argc-- > 0) { + (void) strcat(nolog2, " "); + (void) strcat(nolog2, *argv++); + } + m = ((stogo = sdt - nowtime) + 30)/60; + h = m/60; + m %= 60; + ts = ctime(&sdt); + printf("Shutdown at %5.5s (in ", ts+11); + if (h > 0) + printf("%d hour%s ", h, h != 1 ? "s" : ""); + printf("%d minute%s) ", m, m != 1 ? "s" : ""); +#ifndef DEBUG + (void) signal(SIGHUP, SIG_IGN); + (void) signal(SIGQUIT, SIG_IGN); + (void) signal(SIGINT, SIG_IGN); +#endif + (void) signal(SIGTTOU, SIG_IGN); + (void) signal(SIGTERM, finish); + (void) signal(SIGALRM, timeout); + (void) setpriority(PRIO_PROCESS, 0, PRIO_MIN); + (void) fflush(stdout); +#ifndef DEBUG + if (i = fork()) { + printf("[pid %d]\n", i); + exit(0); + } +#else + (void) putc('\n', stdout); +#endif + sint = 1 HOURS; + f = ""; + ufd = open(_PATH_UTMP,0); + if (ufd < 0) { + err(1, "%s", _PATH_UTMP); + /* NOTREACHED */ + } + first = 1; + for (;;) { + for (i = 0; stogo <= interval[i].stogo && interval[i].sint; i++) + sint = interval[i].sint; + if (stogo > 0 && (stogo-sint) < interval[i].stogo) + sint = stogo - interval[i].stogo; + if (stogo <= NOLOGTIME && nlflag) { + nlflag = 0; + nolog(sdt); + } + if (sint >= stogo || sint == 0) + f = "FINAL "; + nowtime = time((long *)0); + (void) lseek(ufd, 0L, 0); + while (read(ufd,(char *)&utmp,sizeof utmp)==sizeof utmp) + if (utmp.ut_name[0] && + strncmp(utmp.ut_name, IGNOREUSER, sizeof(utmp.ut_name))) { + if (setjmp(alarmbuf)) + continue; + (void) strcpy(term, tpath); + (void) strncat(term, utmp.ut_line, sizeof utmp.ut_line); + (void) alarm(3); +#ifdef DEBUG + if ((termf = stdout) != NULL) +#else + if ((termf = fopen(term, "w")) != NULL) +#endif + { + (void) alarm(0); + setbuf(termf, tbuf); + fprintf(termf, "\n\r\n"); + warning(termf, sdt, nowtime, f); + if (first || sdt - nowtime > 1 MINUTES) { + if (*nolog2) + fprintf(termf, "\t...%s", nolog2); + } + (void) fputc('\r', termf); + (void) fputc('\n', termf); + (void) alarm(5); +#ifdef DEBUG + (void) fflush(termf); +#else + (void) fclose(termf); +#endif + (void) alarm(0); + } + } + if (stogo <= 0) { + printf("\n\007\007System shutdown time has arrived\007\007\n"); + syslog(LOG_CRIT, "%s by %s: %s", + doreboot ? "reboot" : halt ? "halt" : "shutdown", + shutter, nolog2); + sleep(2); + (void) unlink(nologin); + if (!killflg) { + printf("but you'll have to do it yourself\n"); + finish(0); + } + if (fast) + doitfast(); +#ifndef DEBUG + if (doreboot) + execle(REBOOT, "reboot", "-l", nosync, 0, 0); + if (halt) + execle(HALT, "halt", "-l", nosync, 0, 0); + (void) kill(1, SIGTERM); /* to single user */ +#else + if (doreboot) + printf("REBOOT"); + if (halt) + printf(" HALT"); + if (fast) + printf(" -l %s (without fsck's)\n", nosync); + else + printf(" -l %s\n", nosync); + else + printf("kill -HUP 1\n"); + +#endif + finish(0); + } + stogo = sdt - time((long *) 0); + if (stogo > 0 && sint > 0) + sleep((unsigned)(sint 2 && isdigit(*s)) + t = t * 10 + *s++ - '0'; + if (*s == ':') + s++; + if (t > 23) + goto badform; + tim = t*60; + t = 0; + while (isdigit(*s)) + t = t * 10 + *s++ - '0'; + if (t > 59) + goto badform; + tim += t; + tim *= 60; + t1 = time((long *) 0); + lt = localtime(&t1); + t = lt->tm_sec + lt->tm_min*60 + (long)lt->tm_hour*3600; + if (tim < t || tim >= ((long)24*3600)) { + /* before now or after midnight */ + printf("That must be tomorrow\nCan't you wait till then?\n"); + finish(0); + } + return (t1 + tim - t); +badform: + printf("Bad time format\n"); + finish(0); + /*NOTREACHED*/ +} + +doitfast() +{ + register FILE *fastd; + + if ((fastd = fopen(fastboot, "w")) != NULL) { + putc('\n', fastd); + (void) fclose(fastd); + } +} + +nolog(sdt) + time_t sdt; +{ + register FILE *nologf; + + (void) unlink(nologin); /* in case linked to std file */ + if ((nologf = fopen(nologin, "w")) != NULL) { + fprintf(nologf, nolog1, (ctime(&sdt)) + 11); + if (*nolog2) + fprintf(nologf, "\t%s\n", nolog2 + 1); + (void) fclose(nologf); + } +} diff --git a/src/cmd/size.c b/src/cmd/size.c new file mode 100644 index 0000000..6aee5d1 --- /dev/null +++ b/src/cmd/size.c @@ -0,0 +1,67 @@ +/* + * size + */ +#ifdef CROSS +# include +#else +# include +#endif +#include +#include +#include + +int header; + +int +main(argc, argv) +char **argv; +{ + struct exec buf; + long sum; + int nfiles, ch, err = 0; + FILE *f; + + while ((ch = getopt(argc, argv, "h")) != EOF) { + switch(ch) { + case 'h': + default: + fprintf(stderr, "Usage:\n"); + fprintf(stderr, " size file...\n"); + return(1); + } + } + argc -= optind; + argv += optind; + + if (argc == 0) { + *argv = "a.out"; + argc++; + } + + for (nfiles=argc; argc--; argv++) { + if ((f = fopen(*argv, "r"))==NULL) { + printf("size: %s not found\n", *argv); + err++; + continue; + } + if (fread((char *)&buf, sizeof(buf), 1, f) != 1 || + N_BADMAG(buf)) { + printf("size: %s not an object file\n", *argv); + fclose(f); + err++; + continue; + } + if (header == 0) { + printf("text\tdata\tbss\tdec\thex\n"); + header = 1; + } + printf("%u\t%u\t%u\t", buf.a_text,buf.a_data,buf.a_bss); + sum = (long) buf.a_text + (long) buf.a_data + (long) buf.a_bss; + printf("%ld\t%lx", sum, sum); + if (nfiles > 1) + printf("\t%s", *argv); + printf("\n"); + fclose(f); + } + exit(err); +} diff --git a/src/cmd/sl/Makefile b/src/cmd/sl/Makefile new file mode 100644 index 0000000..44dc660 --- /dev/null +++ b/src/cmd/sl/Makefile @@ -0,0 +1,27 @@ +#========================================== +# Makefile: makefile for sl +# Copyright 1993,1998 Toyoda Masashi +# (toyoda@is.titech.ac.jp) +# Last Modified: 1998/ 7/22 +#========================================== + +TOPSRC = $(shell cd ../../..; pwd) +include $(TOPSRC)/target.mk + +OBJS = sl.o +SRCS = sl.c +LIBS += -lcurses -ltermcap -lc + +all: sl + +sl: ${OBJS} + ${CC} ${LDFLAGS} -o sl.elf ${OBJS} ${LIBS} + ${OBJDUMP} -S sl.elf > sl.dis + ${SIZE} sl.elf + ${ELF2AOUT} sl.elf $@ && rm sl.elf + +clean: + -rm -f sl ${OBJS} sl.elf sl.dis + +install: all + install sl $(DESTDIR)/bin/ diff --git a/src/cmd/sl/README b/src/cmd/sl/README new file mode 100644 index 0000000..768ed72 --- /dev/null +++ b/src/cmd/sl/README @@ -0,0 +1,12 @@ +=========================================== + SL: $B%-!<%?%$%W6:@5%=%U%H(B + Copyright 1993,1998 Toyoda Masashi + (toyoda@is.titech.ac.jp) +=========================================== + +$B$`$+$7$K$bEj9F$5$l$?>iCL%=%U%H$N(B sl $B$N9k2ZHG$G$9!#(B +$B%"%$%G%"$O>N(J +sl \- $@%-!<%?%$%W$r6:@5$7$^$9!#(J +.SH $@7A<0(J +.B sl +[ +.B \-alF +] +.SH $@2r@b(J +.B sl +$@$O!"9bEY$KH/E8$7$?!"%-!<%?%$%W6:@5$rL\E*$H$9$k%"%K%a!<%7%g%s%W%m%0%i%`$G$9!#(J +.PP +$@.$5$/$J$j$^$9!#(J +.TP +.B \-F +$@Ht$S$^$9!#(J +.PP +.SH $@4XO";v9`(J +.BR ls (1) +.SH $@%P%0(J +$@%+%l%s%H%G%#%l%/%H%j$NFbMF$,I=<($5$l$k$3$H$,$"$j$^$9!#(J +.SH $@Cx +#include +#include +#include "sl.h" + +int ACCIDENT = 0; +int LOGO = 0; +int FLY = 0; + +int my_mvaddstr(int y, int x, char *str) +{ + for ( ; x < 0; ++x, ++str) + if (*str == '\0') return ERR; + for ( ; *str != '\0'; ++str, ++x) + if (mvaddch(y, x, *str) == ERR) return ERR; + return OK; +} + +void option(char *str) +{ + extern int ACCIDENT, FLY, LONG; + + while (*str != '\0') { + switch (*str++) { + case 'a': ACCIDENT = 1; break; + case 'F': FLY = 1; break; + case 'l': LOGO = 1; break; + default: break; + } + } +} + +void main(int argc, char *argv[]) +{ + int x, i; + + for (i = 1; i < argc; ++i) { + if (*argv[i] == '-') { + option(argv[i] + 1); + } + } + initscr(); + signal(SIGINT, SIG_IGN); + noecho(); + leaveok(stdscr, TRUE); + scrollok(stdscr, FALSE); + + for (x = COLS - 1; ; --x) { + if (LOGO == 0) { + if (add_D51(x) == ERR) break; + } else { + if (add_sl(x) == ERR) break; + } + refresh(); + usleep(20000); + } + mvcur(0, COLS - 1, LINES - 1, 0); + endwin(); +} + + +int add_sl(int x) +{ + static char *sl[LOGOPATTERNS][LOGOHIGHT + 1] + = {{LOGO1, LOGO2, LOGO3, LOGO4, LWHL11, LWHL12, DELLN}, + {LOGO1, LOGO2, LOGO3, LOGO4, LWHL21, LWHL22, DELLN}, + {LOGO1, LOGO2, LOGO3, LOGO4, LWHL31, LWHL32, DELLN}, + {LOGO1, LOGO2, LOGO3, LOGO4, LWHL41, LWHL42, DELLN}, + {LOGO1, LOGO2, LOGO3, LOGO4, LWHL51, LWHL52, DELLN}, + {LOGO1, LOGO2, LOGO3, LOGO4, LWHL61, LWHL62, DELLN}}; + + static char *coal[LOGOHIGHT + 1] + = {LCOAL1, LCOAL2, LCOAL3, LCOAL4, LCOAL5, LCOAL6, DELLN}; + + static char *car[LOGOHIGHT + 1] + = {LCAR1, LCAR2, LCAR3, LCAR4, LCAR5, LCAR6, DELLN}; + + int i, y, py1 = 0, py2 = 0, py3 = 0; + + if (x < - LOGOLENGTH) return ERR; + y = LINES / 2 - 3; + + if (FLY == 1) { + y = (x / 6) + LINES - (COLS / 6) - LOGOHIGHT; + py1 = 2; py2 = 4; py3 = 6; + } + for (i = 0; i <= LOGOHIGHT; ++i) { + my_mvaddstr(y + i, x, sl[(LOGOLENGTH + x) / 3 % LOGOPATTERNS][i]); + my_mvaddstr(y + i + py1, x + 21, coal[i]); + my_mvaddstr(y + i + py2, x + 42, car[i]); + my_mvaddstr(y + i + py3, x + 63, car[i]); + } + if (ACCIDENT == 1) { + add_man(y + 1, x + 14); + add_man(y + 1 + py2, x + 45); add_man(y + 1 + py2, x + 53); + add_man(y + 1 + py3, x + 66); add_man(y + 1 + py3, x + 74); + } + add_smoke(y - 1, x + LOGOFUNNEL); + return OK; +} + + +add_D51(int x) +{ + static char *d51[D51PATTERNS][D51HIGHT + 1] + = {{D51STR1, D51STR2, D51STR3, D51STR4, D51STR5, D51STR6, D51STR7, + D51WHL11, D51WHL12, D51WHL13, D51DEL}, + {D51STR1, D51STR2, D51STR3, D51STR4, D51STR5, D51STR6, D51STR7, + D51WHL21, D51WHL22, D51WHL23, D51DEL}, + {D51STR1, D51STR2, D51STR3, D51STR4, D51STR5, D51STR6, D51STR7, + D51WHL31, D51WHL32, D51WHL33, D51DEL}, + {D51STR1, D51STR2, D51STR3, D51STR4, D51STR5, D51STR6, D51STR7, + D51WHL41, D51WHL42, D51WHL43, D51DEL}, + {D51STR1, D51STR2, D51STR3, D51STR4, D51STR5, D51STR6, D51STR7, + D51WHL51, D51WHL52, D51WHL53, D51DEL}, + {D51STR1, D51STR2, D51STR3, D51STR4, D51STR5, D51STR6, D51STR7, + D51WHL61, D51WHL62, D51WHL63, D51DEL}}; + static char *coal[D51HIGHT + 1] + = {COAL01, COAL02, COAL03, COAL04, COAL05, + COAL06, COAL07, COAL08, COAL09, COAL10, COALDEL}; + + int y, i, dy = 0; + + if (x < - D51LENGTH) return ERR; + y = LINES / 2 - 5; + + if (FLY == 1) { + y = (x / 7) + LINES - (COLS / 7) - D51HIGHT; + dy = 1; + } + for (i = 0; i <= D51HIGHT; ++i) { + my_mvaddstr(y + i, x, d51[(D51LENGTH + x) % D51PATTERNS][i]); + my_mvaddstr(y + i + dy, x + 53, coal[i]); + } + if (ACCIDENT == 1) { + add_man(y + 2, x + 43); + add_man(y + 2, x + 47); + } + add_smoke(y - 1, x + D51FUNNEL); + return OK; +} + + +int add_man(int y, int x) +{ + static char *man[2][2] = {{"", "(O)"}, {"Help!", "\\O/"}}; + int i; + + for (i = 0; i < 2; ++i) { + my_mvaddstr(y + i, x, man[(LOGOLENGTH + x) / 12 % 2][i]); + } +} + + +int add_smoke(int y, int x) +#define SMOKEPTNS 16 +{ + static struct smokes { + int y, x; + int ptrn, kind; + } S[1000]; + static int sum = 0; + static char *Smoke[2][SMOKEPTNS] + = {{"( )", "( )", "( )", "( )", "( )", + "( )" , "( )" , "( )" , "()" , "()" , + "O" , "O" , "O" , "O" , "O" , + " " }, + {"(@@@)", "(@@@@)", "(@@@@)", "(@@@)", "(@@)", + "(@@)" , "(@)" , "(@)" , "@@" , "@@" , + "@" , "@" , "@" , "@" , "@" , + " " }}; + static char *Eraser[SMOKEPTNS] + = {" ", " ", " ", " ", " ", + " " , " " , " " , " " , " " , + " " , " " , " " , " " , " " , + " " }; + static int dy[SMOKEPTNS] = { 2, 1, 1, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0 }; + static int dx[SMOKEPTNS] = {-2, -1, 0, 1, 1, 1, 1, 1, 2, 2, + 2, 2, 2, 3, 3, 3 }; + int i; + + if (x % 4 == 0) { + for (i = 0; i < sum; ++i) { + my_mvaddstr(S[i].y, S[i].x, Eraser[S[i].ptrn]); + S[i].y -= dy[S[i].ptrn]; + S[i].x += dx[S[i].ptrn]; + S[i].ptrn += (S[i].ptrn < SMOKEPTNS - 1) ? 1 : 0; + my_mvaddstr(S[i].y, S[i].x, Smoke[S[i].kind][S[i].ptrn]); + } + my_mvaddstr(y, x, Smoke[sum % 2][0]); + S[sum].y = y; S[sum].x = x; + S[sum].ptrn = 0; S[sum].kind = sum % 2; + sum ++; + } +} diff --git a/src/cmd/sl/sl.h b/src/cmd/sl/sl.h new file mode 100644 index 0000000..fd5055c --- /dev/null +++ b/src/cmd/sl/sl.h @@ -0,0 +1,104 @@ +/*======================================== + * sl.h: Text data of SL version 3.01 + * Copyright 1993 Toyoda Masashi + * (toyoda@is.titech.ac.jp) + * Last Modified: 1992/12/23 + *======================================== + */ + +#define D51HIGHT 10 +#define D51FUNNEL 7 +#define D51LENGTH 83 +#define D51PATTERNS 6 + + +#define D51STR1 " ==== ________ ___________ " +#define D51STR2 " _D _| |_______/ \\__I_I_____===__|_________| " +#define D51STR3 " |(_)--- | H\\________/ | | =|___ ___| " +#define D51STR4 " / | | H | | | | ||_| |_|| " +#define D51STR5 " | | | H |__--------------------| [___] | " +#define D51STR6 " | ________|___H__/__|_____/[][]~\\_______| | " +#define D51STR7 " |/ | |-----------I_____I [][] [] D |=======|__ " + +#define D51WHL11 "__/ =| o |=-~~\\ /~~\\ /~~\\ /~~\\ ____Y___________|__ " +#define D51WHL12 " |/-=|___|= || || || |_____/~\\___/ " +#define D51WHL13 " \\_/ \\O=====O=====O=====O_/ \\_/ " + +#define D51WHL21 "__/ =| o |=-~~\\ /~~\\ /~~\\ /~~\\ ____Y___________|__ " +#define D51WHL22 " |/-=|___|=O=====O=====O=====O |_____/~\\___/ " +#define D51WHL23 " \\_/ \\__/ \\__/ \\__/ \\__/ \\_/ " + +#define D51WHL31 "__/ =| o |=-O=====O=====O=====O \\ ____Y___________|__ " +#define D51WHL32 " |/-=|___|= || || || |_____/~\\___/ " +#define D51WHL33 " \\_/ \\__/ \\__/ \\__/ \\__/ \\_/ " + +#define D51WHL41 "__/ =| o |=-~O=====O=====O=====O\\ ____Y___________|__ " +#define D51WHL42 " |/-=|___|= || || || |_____/~\\___/ " +#define D51WHL43 " \\_/ \\__/ \\__/ \\__/ \\__/ \\_/ " + +#define D51WHL51 "__/ =| o |=-~~\\ /~~\\ /~~\\ /~~\\ ____Y___________|__ " +#define D51WHL52 " |/-=|___|= O=====O=====O=====O|_____/~\\___/ " +#define D51WHL53 " \\_/ \\__/ \\__/ \\__/ \\__/ \\_/ " + +#define D51WHL61 "__/ =| o |=-~~\\ /~~\\ /~~\\ /~~\\ ____Y___________|__ " +#define D51WHL62 " |/-=|___|= || || || |_____/~\\___/ " +#define D51WHL63 " \\_/ \\_O=====O=====O=====O/ \\_/ " + +#define D51DEL " " + +#define COAL01 " " +#define COAL02 " " +#define COAL03 " _________________ " +#define COAL04 " _| \\_____A " +#define COAL05 " =| | " +#define COAL06 " -| | " +#define COAL07 "__|________________________|_ " +#define COAL08 "|__________________________|_ " +#define COAL09 " |_D__D__D_| |_D__D__D_| " +#define COAL10 " \\_/ \\_/ \\_/ \\_/ " + +#define COALDEL " " + +#define LOGOHIGHT 6 +#define LOGOFUNNEL 4 +#define LOGOLENGTH 84 +#define LOGOPATTERNS 6 + +#define LOGO1 " ++ +------ " +#define LOGO2 " || |+-+ | " +#define LOGO3 " /---------|| | | " +#define LOGO4 " + ======== +-+ | " + +#define LWHL11 " _|--O========O~\\-+ " +#define LWHL12 "//// \\_/ \\_/ " + +#define LWHL21 " _|--/O========O\\-+ " +#define LWHL22 "//// \\_/ \\_/ " + +#define LWHL31 " _|--/~O========O-+ " +#define LWHL32 "//// \\_/ \\_/ " + +#define LWHL41 " _|--/~\\------/~\\-+ " +#define LWHL42 "//// \\_O========O " + +#define LWHL51 " _|--/~\\------/~\\-+ " +#define LWHL52 "//// \\O========O/ " + +#define LWHL61 " _|--/~\\------/~\\-+ " +#define LWHL62 "//// O========O_/ " + +#define LCOAL1 "____ " +#define LCOAL2 "| \\@@@@@@@@@@@ " +#define LCOAL3 "| \\@@@@@@@@@@@@@_ " +#define LCOAL4 "| | " +#define LCOAL5 "|__________________| " +#define LCOAL6 " (O) (O) " + +#define LCAR1 "____________________ " +#define LCAR2 "| ___ ___ ___ ___ | " +#define LCAR3 "| |_| |_| |_| |_| | " +#define LCAR4 "|__________________| " +#define LCAR5 "|__________________| " +#define LCAR6 " (O) (O) " + +#define DELLN " " diff --git a/src/cmd/sl/sl.txt b/src/cmd/sl/sl.txt new file mode 100644 index 0000000..9af080d --- /dev/null +++ b/src/cmd/sl/sl.txt @@ -0,0 +1,23 @@ +------------------------------------------------------------------------------- + ==== ________ ___________ + _D _| |_______/ \__I_I_____===__|_________| + |(_)--- | H\________/ | | =|___ ___| + / | | H | | | | ||_| |_|| + | | | H |__--------------------| [___] | + | ________|___H__/__|_____/[][]~\_______| | + |/ | |-----------I_____I [][] [] D |=======|__ +__/ =| o |=-~~\ /~~\ /~~\ /~~\ ____Y___________|__ + |/-=|___|| || || || |_____/~\___/ + \_/ \__/ \__/ \__/ \__/ \_/ +------------------------------------------------------------------------------- + + + _________________ + _| \_____A + =| | + -| | +__|________________________|_ +|__________________________|_ + |_D__D__D_| |_D__D__D_| + \_/ \_/ \_/ \_/ +------------------------------------------------------------------------------- \ No newline at end of file diff --git a/src/cmd/sleep.c b/src/cmd/sleep.c new file mode 100644 index 0000000..d6d5497 --- /dev/null +++ b/src/cmd/sleep.c @@ -0,0 +1,24 @@ +#include +#include + +main(argc, argv) +char **argv; +{ + int c, n; + char *s; + + n = 0; + if(argc < 2) { + printf("arg count\n"); + exit(0); + } + s = argv[1]; + while(c = *s++) { + if(c<'0' || c>'9') { + printf("bad character\n"); + exit(0); + } + n = n*10 + c - '0'; + } + sleep(n); +} diff --git a/src/cmd/smallc/6809/ccstart.u b/src/cmd/smallc/6809/ccstart.u new file mode 100644 index 0000000..ffeb176 --- /dev/null +++ b/src/cmd/smallc/6809/ccstart.u @@ -0,0 +1,25 @@ +| Run-time start off for ccv1 on the Physics 6809 +.globl _edata +.globl _main +| Initialize stack + lds #/1000 + ldx #_edata | clear all of memory +l2: clr (x)+ + cmpx #/0fff + bne l2 +| Circumvent EPROM bug + ldx #/ff3b + ldb #6 +l1: pshs x + decb + bne l1 +| clear everything so that start conds are +| always same + clra + clrb + tfr a,dp + tfr d,x + tfr d,y + tfr d,u + jsr _main + jmp /fc00 diff --git a/src/cmd/smallc/6809/crunas09.u b/src/cmd/smallc/6809/crunas09.u new file mode 100644 index 0000000..4b20f81 --- /dev/null +++ b/src/cmd/smallc/6809/crunas09.u @@ -0,0 +1,85 @@ +| csa09 Small C v1 comparison support +| All are dyadic except for lneg. +.globl eq +.globl ne +.globl lt +.globl le +.globl gt +.globl ge +.globl ult +.globl ule +.globl ugt +.globl uge +.globl lneg +.globl bool +.globl _eend,_edata,_etext +.globl _Xstktop,_brkend + +eq: cmpd 2(s) + lbeq true + lbra false + +ne: cmpd 2(s) + lbne true + lbra false + +lt: cmpd 2(s) + bgt true + bra false + +le: cmpd 2(s) + bge true + bra false + +gt: cmpd 2(s) + blt true + bra false + +ge: cmpd 2(s) + ble true + bra false + +ult: cmpd 2(s) + bhi true + bra false + +ule: cmpd 2(s) + bhs true + bra false + +ugt: cmpd 2(s) + blo true + bra false + +uge: cmpd 2(s) + bls true + bra false + +lneg: cmpd #0 + beq ltrue + ldd #0 + rts +ltrue: ldd #1 + rts + +bool: bsr lneg + bra lneg + +true: ldd #1 + ldx (s) + leas 4(s) + jmp (x) + +false: clra + clrb + ldx (s) + leas 4(s) + jmp (x) +_Xstktop: tfr s,d + rts +_etext = . + .bss +_eend = . + .data +_brkend: .wval _eend +_edata = . diff --git a/src/cmd/smallc/6809/exit.u b/src/cmd/smallc/6809/exit.u new file mode 100644 index 0000000..423fd67 --- /dev/null +++ b/src/cmd/smallc/6809/exit.u @@ -0,0 +1,3 @@ +| Small C v1 exit routine (physics computer) +.globl _exit +_exit: jmp /fc00 diff --git a/src/cmd/smallc/6809/faults.u b/src/cmd/smallc/6809/faults.u new file mode 100644 index 0000000..6e7db80 --- /dev/null +++ b/src/cmd/smallc/6809/faults.u @@ -0,0 +1,10 @@ +| MC6809 Concurrent Euclid fault codes +ASSERTFAIL = 0 +RANGECHECK = 1 +CASERANGE = 2 +| fault codes for runtime routines +OUTOFSPACE = 20 +.globl ASSERTFAIL +.globl RANGECHECK +.globl CASERANGE +.globl OUTOFSPACE diff --git a/src/cmd/smallc/6809/io.u b/src/cmd/smallc/6809/io.u new file mode 100644 index 0000000..1f3a63f --- /dev/null +++ b/src/cmd/smallc/6809/io.u @@ -0,0 +1,28 @@ +| Small C v1 io (putchar) for physics machine +.globl _putchar +_putchar=. + lda /9000 + bita #2 + beq _putchar + lda 3(s) + sta /9001 + cmpa #10. + bne out + ldd #13. + pshs d + lbsr _putchar + leas 2(s) +out: rts + +.globl _getchar +_getchar=. + lda /9000 + bita #1 + beq _getchar + ldb /9001 + clra + andb #/7F + cmpb #04 + bne noteot + ldd #-1 +noteot: rts diff --git a/src/cmd/smallc/6809/mrabs.u b/src/cmd/smallc/6809/mrabs.u new file mode 100644 index 0000000..97f0662 --- /dev/null +++ b/src/cmd/smallc/6809/mrabs.u @@ -0,0 +1,26 @@ +| mrabs. converts both args to unsigned, and +| remembers result sign as the sign of the left +| argument. (for signed modulo) +| result d contains right, sign is non-zero +| if result (from mod) should be negative. +| +| +.globl mrabs + left=8. + right=4. + sign=3. +mrabs: clr sign(s) + ldd left(s) + bge tryr + nega + negb + sbca #0 + std left(s) + inc sign(s) +tryr: ldd right(s) + bge done + nega + negb + sbca #0 + std right(s) +done: rts diff --git a/src/cmd/smallc/6809/prabs.u b/src/cmd/smallc/6809/prabs.u new file mode 100644 index 0000000..40b6dc8 --- /dev/null +++ b/src/cmd/smallc/6809/prabs.u @@ -0,0 +1,27 @@ +| prabs. converts both args to unsigned, and +| remembers result sign as sign a eor sign b +| used only by divide support +| result d contains right, sign is non-zero +| if result (from divide) should be negative. +| +| +.globl prabs + left=8. + right=4. + sign=3. +prabs: clr sign(s) + ldd left(s) + bge tryr + nega + negb + sbca #0 + std left(s) + inc sign(s) +tryr: ldd right(s) + bge done + nega + negb + sbca #0 + dec sign(s) + std right(s) +done: rts diff --git a/src/cmd/smallc/6809/sdiv.u b/src/cmd/smallc/6809/sdiv.u new file mode 100644 index 0000000..3b17770 --- /dev/null +++ b/src/cmd/smallc/6809/sdiv.u @@ -0,0 +1,55 @@ +| signed divide +| calling: (left / right) +| push left +| ldd right +| jsr sdiv +| result in d, arg popped. +| + left=6 + right=2 + sign=1 + count=0 + return=4 + CARRY=1 +.globl sdiv,div,ASSERTFAIL +.globl prabs +sdiv: leas -4(s) + std right(s) + bne nozero + swi2 + .byte ASSERTFAIL +nozero: jsr prabs +div: clr count(s) | prescale divisor + inc count(s) +mscl: inc count(s) + aslb + rola + bpl mscl + std right(s) + ldd left(s) + clr left(s) + clr left+1 (s) +div1: subd right(s) | check subtract + bcc div2 + addd right(s) + andcc #~CARRY + bra div3 +div2: orcc #CARRY +div3: rol left+1 (s) | roll in carry + rol left(s) + lsr right(s) + ror right+1 (s) + dec count(s) + bne div1 + ldd left(s) + tst sign(s) | sign fiddle + beq nochg + nega + negb + sbca #0 +nochg: std right(s) | move return addr + ldd return(s) + std left(s) + ldd right(s) + leas 6(s) + rts diff --git a/src/cmd/smallc/6809/shift.u b/src/cmd/smallc/6809/shift.u new file mode 100644 index 0000000..0ced5ec --- /dev/null +++ b/src/cmd/smallc/6809/shift.u @@ -0,0 +1,32 @@ +| Shift support for Small C v1 sa09 +.globl asr +asr: tstb + bge okr + negb + bra asl +okr: incb + pshs b + ldd 3(s) +asrl: dec (s) + beq return + asra + rorb + bra asrl + +.globl asl +asl: tstb + bge okl + negb + bra asr +okl: incb + pshs b + ldd 3(s) +asll: dec (s) + beq return + aslb + rola + bra asll + +return: ldx 1(s) + leas 5(s) + jmp (x) diff --git a/src/cmd/smallc/6809/smod.u b/src/cmd/smallc/6809/smod.u new file mode 100644 index 0000000..737cb90 --- /dev/null +++ b/src/cmd/smallc/6809/smod.u @@ -0,0 +1,54 @@ +| signed mod +| calling: (left / right) +| push left +| ldd right +| jsr smod +| result in d, arg popped. +| + left=6 + right=2 + sign=1 + count=0 + return=4 + CARRY=1 +.globl smod,mod,ASSERTFAIL +.globl mrabs +smod: leas -4(s) + std right(s) + bne nozero + swi2 + .byte ASSERTFAIL +nozero: jsr mrabs +mod: clr count(s) | prescale divisor + inc count(s) +mscl: inc count(s) + aslb + rola + bpl mscl + std right(s) + ldd left(s) + clr left(s) + clr left+1 (s) +mod1: subd right(s) | check subtract + bcc mod2 + addd right(s) + andcc #~CARRY + bra mod3 +mod2: orcc #CARRY +mod3: rol left+1 (s) | roll in carry + rol left(s) + lsr right(s) + ror right+1 (s) + dec count(s) + bne mod1 + tst sign(s) | sign fiddle + beq nochg + nega + negb + sbca #0 +nochg: std right(s) | move return addr + ldd return(s) + std left(s) + ldd right(s) + leas 6(s) + rts diff --git a/src/cmd/smallc/6809/sumul.u b/src/cmd/smallc/6809/sumul.u new file mode 100644 index 0000000..806c9ca --- /dev/null +++ b/src/cmd/smallc/6809/sumul.u @@ -0,0 +1,32 @@ +| signed/unsigned multiply +| calling (left * right) +| push left +| ldd right +| jsr [u|s]mul (same entry point) +| result in d, stack is popped +.globl smul,umul +smul=. +umul: pshs d + lda 2+2 (s) + mul | left msb * right lsb + pshs b | save high order + ldb -1+3 (s) | right lsb + lda 3+3 (s) | left lsb + mul + pshs d + lda 3+5 (s) | left lsb + ldb -2+5 (s) | right msb + beq small | is zero? + mul | no, gotta do it too + tfr b,a + clrb + addd (s)++ | partial prod + bra big +small: puls d | aha! don't need third mul +big: adda (s)+ + pshs d + ldd 4(s) | rearrange return address + std 6(s) + puls d + leas 4(s) + rts diff --git a/src/cmd/smallc/8080/Makefile b/src/cmd/smallc/8080/Makefile new file mode 100644 index 0000000..f256081 --- /dev/null +++ b/src/cmd/smallc/8080/Makefile @@ -0,0 +1,8 @@ +.SUFFIXES: .o .c .asm + +ASSEMS = bdos.asm bdos1.asm chio8080.asm exit.asm io8080.asm sbrk.asm + +.c.asm: + tscc $*.c + +all: $(ASSEMS) diff --git a/src/cmd/smallc/8080/arglist.c b/src/cmd/smallc/8080/arglist.c new file mode 100644 index 0000000..f747b46 --- /dev/null +++ b/src/cmd/smallc/8080/arglist.c @@ -0,0 +1,34 @@ +/* Interpret CPM argument list to produce C style + argc/argv + default dma buffer has it, form: + --------------------------------- + |count|characters ... | + --------------------------------- +*/ +int Xargc; +int Xargv[30]; +Xarglist(ap) char *ap; { + char qc; + Xargc = 0; + ap[(*ap)+1 ] = '\0'; + ap++; + while (isspace(*ap)) ap++; + Xargv[Xargc++] = "arg0"; + if (*ap) + do { + if (*ap == '\'' || *ap == '\"') { + qc = *ap; + Xargv[Xargc++] = ++ap; + while (*ap&&*ap != qc) ap++; + } else { + Xargv[Xargc++] = ap; + while (*ap&&!isspace(*ap)) ap++; + } + if (!*ap) break; + *ap++='\0'; + while (isspace(*ap)) ap++; + } while(*ap); + Xargv[Xargc] = 0; + +} + diff --git a/src/cmd/smallc/8080/bdos.c b/src/cmd/smallc/8080/bdos.c new file mode 100644 index 0000000..b475f18 --- /dev/null +++ b/src/cmd/smallc/8080/bdos.c @@ -0,0 +1,18 @@ +bdos (c, de) int c, de; { +#asm +; CP/M support routine +; bdos(C,DE); +; char *DE; int C; +; returns H=B,L=A per CPM standard + pop h ; hold return address + pop d ; get bdos function number + pop b ; get DE register argument + push d + push b + push h + call 5 + mov h,b + mov l,a +#endasm +} + diff --git a/src/cmd/smallc/8080/bdos1.c b/src/cmd/smallc/8080/bdos1.c new file mode 100644 index 0000000..aa00c93 --- /dev/null +++ b/src/cmd/smallc/8080/bdos1.c @@ -0,0 +1,5 @@ +bdos1(c, de) int c, de; { + /* returns only single byte (top half is 0) */ + return (255 & bdos(c, de)); +} + diff --git a/src/cmd/smallc/8080/chio8080.c b/src/cmd/smallc/8080/chio8080.c new file mode 100644 index 0000000..4cdd2e2 --- /dev/null +++ b/src/cmd/smallc/8080/chio8080.c @@ -0,0 +1,12 @@ +#define EOL 10 +getchar() { + return (bdos(1,1)); + +} + +putchar (c) char c; { + if (c == EOL) bdos(2,13); + bdos(2,c); + return c; +} + diff --git a/src/cmd/smallc/8080/cret.asm b/src/cmd/smallc/8080/cret.asm new file mode 100644 index 0000000..ea3d06c --- /dev/null +++ b/src/cmd/smallc/8080/cret.asm @@ -0,0 +1,27 @@ +; Run time start off for Small C. + cseg + sphl ; save the stack pointer + shld ?stksav + lhld 6 ; pick up core top + lxi d,-10 ; decrease by 10 for safety + dad d + sphl ; set stack pointer + call stdioinit ; initialize stdio + call Xarglist + lhld Xargc + push h + lxi h,Xargv + push h + call main ; call main program + pop d + pop d + lhld ?stksav ; restore stack pointer + ret ; go back to CCP + dseg +?stksav ds 2 + extrn stdioinit + extrn Xarglist + extrn Xargc + extrn Xargv + extrn main + end diff --git a/src/cmd/smallc/8080/crun.asm b/src/cmd/smallc/8080/crun.asm new file mode 100644 index 0000000..d60070a --- /dev/null +++ b/src/cmd/smallc/8080/crun.asm @@ -0,0 +1,352 @@ +; +;***************************************************** +; * +; runtime library for small C compiler * +; * +; c.s - runtime routine for basic C code * +; * +; Ron Cain * +; * +;***************************************************** +; + cseg +; + public ?gchar,?gint,?pchar,?pint + public ?sxt + public ?or,?and,?xor + public ?eq,?ne,?gt,?le,?ge,?lt,?uge,?ult,?ugt,?ule + public ?asr,?asl + public ?sub,?neg,?com,?lneg,?bool,?mul,?div + public ?case,brkend,Xstktop + public etext + public edata +; +; fetch char from (HL) and sign extend into HL +?gchar: mov a,m +?sxt: mov l,a + rlc + sbb a + mov h,a + ret +; fetch int from (HL) +?gint: mov a,m + inx h + mov h,m + mov l,a + ret +; store char from HL into (DE) +?pchar: mov a,l + stax d + ret +; store int from HL into (DE) +?pint: mov a,l + stax d + inx d + mov a,h + stax d + ret +; "or" HL and DE into HL +?or: mov a,l + ora e + mov l,a + mov a,h + ora d + mov h,a + ret +; "xor" HL and DE into HL +?xor: mov a,l + xra e + mov l,a + mov a,h + xra d + mov h,a + ret +; "and" HL and DE into HL +?and: mov a,l + ana e + mov l,a + mov a,h + ana d + mov h,a + ret +; +;......logical operations: HL set to 0 (false) or 1 (true) +; +; DE == HL +?eq: call ?cmp + rz + dcx h + ret +; DE != HL +?ne: call ?cmp + rnz + dcx h + ret +; DE > HL [signed] +?gt: xchg + call ?cmp + rc + dcx h + ret +; DE <= HL [signed] +?le: call ?cmp + rz + rc + dcx h + ret +; DE >= HL [signed] +?ge: call ?cmp + rnc + dcx h + ret +; DE < HL [signed] +?lt: call ?cmp + rc + dcx h + ret +; DE >= HL [unsigned] +?uge: call ?ucmp + rnc + dcx h + ret +; DE < HL [unsigned] +?ult: call ?ucmp + rc + dcx h + ret +; DE > HL [unsigned] +?ugt: xchg + call ?ucmp + rc + dcx h + ret +; DE <= HL [unsigned] +?ule: call ?ucmp + rz + rc + dcx h + ret +; signed compare of DE and HL +; carry is sign of difference [set => DE < HL] +; zero is zero/non-zero +?cmp: mov a,e + sub l + mov e,a + mov a,d + sbb h + lxi h,1 ;preset true + jm ?cmp1 + ora e ;resets carry + ret +?cmp1: ora e + stc + ret +; unsigned compare of DE and HL +; carry is sign of difference [set => DE < HL] +; zero is zero/non-zero +?ucmp: mov a,d + cmp h + jnz ?ucmp1 + mov a,e + cmp l +?ucmp1: lxi h,1 ;preset true + ret +; shift DE right arithmetically by HL, move to HL +?asr: xchg +?asr1: dcr e + rm + mov a,h + ral + mov a,h + rar + mov h,a + mov a,l + rar + mov l,a + jmp ?asr1 +; shift DE left arithmetically by HL, move to HL +?asl: xchg +?asl1: dcr e + rm + dad h + jmp ?asl1 +; HL = DE - HL +?sub: mov a,e + sub l + mov l,a + mov a,d + sbb h + mov h,a + ret +; HL = -HL +?neg: call ?com + inx h + ret +; HL = ~HL +?com: mov a,h + cma + mov h,a + mov a,l + cma + mov l,a + ret +; HL = !HL +?lneg: mov a,h + ora l + jz ?lneg1 + lxi h,0 + ret +?lneg1: inx h + ret +; HL = !!HL +?bool: call ?lneg + jmp ?lneg +; +; HL = DE * HL [signed] +?mul: mov b,h + mov c,l + lxi h,0 +?mul1: mov a,c + rrc + jnc ?mul2 + dad d +?mul2: xra a + mov a,b + rar + mov b,a + mov a,c + rar + mov c,a + ora b + rz + xra a + mov a,e + ral + mov e,a + mov a,d + ral + mov d,a + ora e + rz + jmp ?mul1 +; HL = DE / HL, DE = DE % HL +?div: mov b,h + mov c,l + mov a,d + xra b + push psw + mov a,d + ora a + cm ?deneg + mov a,b + ora a + cm ?bcneg + mvi a,16 + push psw + xchg + lxi d,0 +?div1: dad h + call ?rdel + jz ?div2 + call ?cmpbd + jm ?div2 + mov a,l + ori 1 + mov l,a + mov a,e + sub c + mov e,a + mov a,d + sbb b + mov d,a +?div2: pop psw + dcr a + jz ?div3 + push psw + jmp ?div1 +?div3: pop psw + rp + call ?deneg + xchg + call ?deneg + xchg + ret +; {DE = -DE} +?deneg: mov a,d + cma + mov d,a + mov a,e + cma + mov e,a + inx d + ret +; {BC = -BC} +?bcneg: mov a,b + cma + mov b,a + mov a,c + cma + mov c,a + inx b + ret +; {DE +ininst in 0 ; self modifying code... + mov l,a + xra a + mov h,a + ret +#endasm + +} + +outp(pno, val) char pno, val; { + pno; +#asm + mov a,l + sta outinst+1 +#endasm + val; +#asm + mov a,l +outinst out 0 + ret +#endasm +} + diff --git a/src/cmd/smallc/8080/io8080.c b/src/cmd/smallc/8080/io8080.c new file mode 100644 index 0000000..f6c457f --- /dev/null +++ b/src/cmd/smallc/8080/io8080.c @@ -0,0 +1,305 @@ +/* Basic CP/M file I/O: +fopen,fclose,fgetc,fputc,feof + +Original: Paul Tarvydas +Fixed by: Chris Lewis +*/ +#include + +#define EOL 10 +#define EOL2 13 +#define CPMEOF 26 +#define CPMERR 255 +#define UNIT_OFFSET 3 +#define CPMCIN 1 +#define CPMCOUT 2 +#define READ_EOF 3 +#define SETDMA 26 +#define DEFAULT_DMA 128 +#define CPMREAD 20 +#define CPMWR 21 +#define WRITE 2 +#define READ 1 +#define FREE 0 +#define NBUFFS 4 +#define BUFSIZ 512 +#define FCBSIZ 33 +#define ALLBUFFS 2048 +#define ALLFCBS 132 +#define CPMERA 19 +#define CPMCREAT 22 +#define CPMOPEN 15 +#define NBLOCKS 4 +#define BLKSIZ 128 +#define BKSP 8 +#define CTRLU 21 +#define FWSP ' ' +#define CPMCLOSE 16 + +char buffs[ALLBUFFS], /* disk buffers */ +fcbs[ALLFCBS]; /* fcbs for buffers */ +int bptr[NBUFFS]; /* ptrs into buffers */ +int modes[NBUFFS]; /* mode for each open file */ +int eptr[NBUFFS]; /* buffers' ends */ +char eofstdin; /* flag end of file on stdin */ + +fgetc(unit) int unit; +{ + int c; + while ((c = Xfgetc(unit)) == EOL2); + return c; + +} + +Xfgetc(unit) int unit; +{ + int i; + int c; + char *buff; + char *fcba; + if ((unit == stdin) & !eofstdin) { + c = bdos1(CPMCIN, 0); + if (c == 4) { + eofstdin = 1; + return (EOF); + } + else if (c == 3) + exit (1); + else { + if (c == EOL2) { + c = EOL; + bdos (CPMCOUT, EOL); + } + return (c); + } + } + if (modes[unit = unit - UNIT_OFFSET] == READ) { + if (bptr[unit] >= eptr[unit]) { + fcba = fcbaddr(unit); + /* fill da buffer again */ + i = 0; /* block counter */ + buff = buffaddr(unit); /* dma ptr */ + /* if buffer wasn't totally + filled last time, we already + eof */ + if (eptr[unit] == buffaddr(unit + 1)) + do { + bdos(SETDMA, buff); + if (0!=bdos1(CPMREAD, fcba)) + break; + buff = buff + BLKSIZ; + } + while (++ieof*/ + if (i==0) { + modes[unit] = READ_EOF; + return EOF; + } + /* o.k. set start & end ptrs */ + eptr[unit] = + (bptr[unit]=buffaddr(unit)) + + (i * BLKSIZ); + } + c = (*(bptr[unit]++)) & 0xff; + if (c == CPMEOF) { + c = EOF; + modes[unit] = READ_EOF; + } + return c; + } + return EOF; + +} + +fclose(unit) int unit; +{ + int i; + if ((unit==stdin)|(unit==stdout)|(unit==stderr)) + return NULL; + if (modes[unit = unit - UNIT_OFFSET] != FREE) { + if (modes[unit] == WRITE) + fflush(unit + UNIT_OFFSET); + modes[unit] = FREE; + return bdos1(CPMCLOSE, fcbaddr(unit)); + } + return EOF; + +} + +fflush(unit) int unit; +{ + char *buffa; + char *fcba; + if ((unit!=stdin)|(unit!=stdout)|(unit!=stderr)) { + /* put an eof at end of file */ + fputc(CPMEOF, unit); + if (bptr[unit = unit - UNIT_OFFSET] != + (buffa = buffaddr(unit))) { + /* some chars in buffer - flush them */ + fcba = fcbaddr(unit); + do { + bdos(SETDMA, buffa); + if (0 != bdos1(CPMWR, fcba)) + return (EOF); + } + while (bptr[unit] > + (buffa=buffa+BLKSIZ)); + bdos(SETDMA, DEFAULT_DMA); + } + } + return NULL; + +} + +fputc(c, unit) char c; +int unit; +{ + char *buffa; + char *fcba; + if (c == EOL) fputc(EOL2, unit); + if ((unit == stdout) | (unit == stderr)) { + bdos(CPMCOUT, c); + return c; + } + if (WRITE == modes[unit = unit - UNIT_OFFSET]) { + if (bptr[unit] >= eptr[unit]) { + /* no room - dump buffer */ + fcba = fcbaddr(unit); + buffa=buffaddr(unit); + while (buffa < eptr[unit]) { + bdos(SETDMA, buffa); + if (0 != bdos1(CPMWR, fcba)) break; + buffa = buffa + BLKSIZ; + } + bdos(SETDMA, DEFAULT_DMA); + bptr[unit] = buffaddr(unit); + if (buffa < eptr[unit]) return EOF; + } + *(bptr[unit]++) = c; + return c; + } + return EOF; + +} + +allocunitno() { + int i; + /* returns # of first free buffer, EOF if none */ + /* buffer is not reserved (ie. mode remains FREE) */ + for (i = 0; i < NBUFFS; ++i) + if (modes[i] == FREE) break; + if (i >= NBUFFS) return EOF; + else return (i + UNIT_OFFSET); + +} + +fopen(name, mode) char *name, *mode; +{ + int fileno, fno2; + if (EOF != (fileno = allocunitno())) { + /* internal file # excludes units 0,1 & 2 + since there's no buffers associated with + these units */ + movname(clearfcb(fcbaddr(fno2 = fileno + - UNIT_OFFSET)), name); + if ('r' == *mode) { + if (bdos1(CPMOPEN, fcbaddr(fno2)) != CPMERR) + { + modes[fno2] = READ; + /* ptr>bufsiz => buffer empty*/ + eptr[fno2] = + bptr[fno2] = buffaddr(fno2+1 ); + return fileno; + } + } + else if ('w' == *mode) { + bdos(CPMERA, fcbaddr(fno2)); + if (bdos1(CPMCREAT, fcbaddr(fno2)) != CPMERR){ + modes[fno2] = WRITE; + bptr[fno2] = buffaddr(fno2); + eptr[fno2] = buffaddr(fno2+1 ); + return fileno; + } + } + } + return NULL; + +} + +clearfcb(fcb) char fcb[]; +{ + int i; + for (i=0; i= c)) { + *fcb = (c - 'A' + 1); + str++; + str++; + } + } + while ((NULL != *str) & (i<9)) { + /* up to 8 chars into file name field */ + if ('.' == *str) break; + fcb[i++] = toupper(*str++); + } + /* strip off excess chars - up to '.' (beginning of + extension name ) */ + while ((NULL != *str) & ((*str) != '.')) ++str; + if (*str) + /* '.' is first char of *str now */ + /* copy 3 chars of ext. if there */ + for ( /* first char of ext @ pos 9 (8+1 )*/ +i = 8; +/* '.' is stripped by ++ 1st time */ +/* around */ +(NULL != *++str) & (12 > ++i); +fcb[i] = toupper(*str) +); + return fcb; + +} + +stdioinit() { + int i; + eofstdin = 0; + for (i=0; i $@.dis + ${SIZE} $@.elf + ${ELF2AOUT} $@.elf $@ + +install: smallc + cp smallc $(TOPSRC)/libexec/ + + +clean: + rm -f *.o smallc smallc.dis smallc.elf +### +code8080.o: code8080.c defs.h data.h +codeas09.o: codeas09.c defs.h data.h +codem68k.o: codem68k.c defs.h data.h +codemips.o: codemips.c defs.h data.h +codevax.o: codevax.c defs.h data.h +data.o: data.c defs.h +error.o: error.c defs.h data.h +expr.o: expr.c defs.h data.h +function.o: function.c defs.h data.h +gen.o: gen.c defs.h data.h +initialise.o: initialise.c defs.h data.h +io.o: io.c defs.h data.h +lex.o: lex.c defs.h data.h +main.o: main.c defs.h data.h +preproc.o: preproc.c defs.h data.h +primary.o: primary.c defs.h data.h +stmt.o: stmt.c defs.h data.h +sym.o: sym.c defs.h data.h +while.o: while.c defs.h data.h diff --git a/src/cmd/smallc/README b/src/cmd/smallc/README new file mode 100644 index 0000000..2b3ee6e --- /dev/null +++ b/src/cmd/smallc/README @@ -0,0 +1,98 @@ +This version is derived from https://github.com/begoon/smallc-85 and adds +a mips code generator that works with the retrobsd as command. Some bug +fixes have also been applied. + +--------------------- previous readme ---------------------------------- +This fork from https://github.com/ncb85/SmallC-85 has no functional +changes, only a few build scripts. + +To build on Windows: + + cd windows + nmake + +- - - + +Revived version of SmallC based on Chris Lewis' port to UNIX V. I have +mainly rewritten code to use structures and to make it compile using GCC +silently without warnigns. + +Support for one line comments from C99 specification was added as well +as capability to handle Windows EOLs. + +Initialisation of global variables is also possible. When not initialised +global var is assigned zero at compile time. + +Furthermore support for ANSI style method declaration has been added. + +Generated code is suitable for ASXXXX assembler/linker. + +***** update ***** +Support for unsigned types +Support for undocumented 8085 istructions LHLX, SHLX, LDSI, ARHL + +-------------------------- original posting ------------------------------ + +Small C version C3.0R1.1 + (SCC3) + + Chris Lewis + +This directory contains the source for a version of Ron Cain's Small C +compiler that I have heavily modified - beyond the Small-C V2.0 later +published in Dr. Dobbs. This compiler generates assembler source code that +needs to be assembled and linked to make a running program. + +Small C is a public domain compiler for a subset of C. The main things +lacking are "#if", structs/unions, doubles/floats/longs and more than +one level of indirection. Even so, it's powerful enough to be able to +compile itself. It's also lots of fun to play around with. It could +use lots of more work (eg: a real scanner), but what the heck... +Retargetting the compiler requires only relinking the frontend with a new +code generator. + +Code generators for 6809 (MIT UNIX-like assembler), M68K (Motorola V/68 +UNIX +assembler), VAX (BSD 4.1 assembler), and 8080 (RMAC assembler) are +provided. + +Users having access to System V make should be able to use the Makefile +without any modification except for INCDIR and LIBDIR (where you'd like +to put the compiler itself). + +Users not having access to System V will probably have to rewrite the +Makefile. +[ I have provided a Makefile that seems to work with bsd systems - mod] + +WARNING: you will probably see a great deal of compilation warnings when +you compile this compiler with a "real" UNIX C. Don't worry - this is +*perfectly* normal - Small C is a subset of real C, and in order to +keep the compiler in this subset you have to bend the rules somewhat. +The only time where this might cause a problem is where pointers are +"different" from ints (ie: different length or on non-byte-addressible +machines). Small C assumes that ints are the same as pointers. + +Invocation: + scc<6809|vax|m68k|8080> filename + +There are other options available - see main.c for details. + +The code generated by these compilers need a run-time support library +for two things: operations that are "hard" on a particular processor +(eg: 16 bit multiply on an 8080), or O/S interface (vax is BSD 4.1, +6809 is FLEX, 8080 is CPM, never had one for M68k). + +Status: the 6809, VAX and 8080 versions work last I checked - a problem or +two may have crept in during the implementation of the compile/assemble/and +link code for machines that support it. The M68k version has never been +tested. I don't have a Pyramid version because Pyrcorp seems reluctant +to publish instruction set information. + +So you want to write a new coder do you? Well, it's easy - read the +comments in one of the coders. You should not have to modify *any* of +the existing files, just write a new codexxx.c file. Please contact +me if you run into trouble. I would be greatly interested in any new +coders or bug reports in the compilers. As far as I am aware, the +major restriction on porting this thing for different targets is that +pointers and integers *must* be the same length, alignment, and be +interchangeable. \ No newline at end of file diff --git a/src/cmd/smallc/code8080.c b/src/cmd/smallc/code8080.c new file mode 100644 index 0000000..f4cb12e --- /dev/null +++ b/src/cmd/smallc/code8080.c @@ -0,0 +1,752 @@ +/* File code8080.c: 2.2 (84/08/31,10:05:09) */ +/*% cc -O -c % + * + */ + +#include +#include "defs.h" +#include "data.h" + +/* Define ASNM and LDNM to the names of the assembler and linker + respectively */ + +/* + * Some predefinitions: + * + * INTSIZE is the size of an integer in the target machine + * BYTEOFF is the offset of an byte within an integer on the + * target machine. (ie: 8080,pdp11 = 0, 6809 = 1, + * 360 = 3) + * This compiler assumes that an integer is the SAME length as + * a pointer - in fact, the compiler uses INTSIZE for both. + */ + +/** + * print all assembler info before any code is generated + */ +void header () { + output_string ("; Small C 8080;\n;\tCoder (2.4,84/11/27)\n;"); + frontend_version(); + newline (); + output_line ("\t;program area SMALLC_GENERATED is RELOCATABLE"); + output_line ("\t.area\tSMALLC_GENERATED\t(REL,CON)"); + output_line ("\t.module SMALLC_GENERATED"); + output_line ("\t.list (err, loc, bin, eqt, cyc, lin, src, lst, md)"); + output_line ("\t.nlist (pag)"); +} + +/** + * prints new line + * @return + */ +newline () { +#if __CYGWIN__ == 1 + output_byte (CR); +#endif + output_byte (LF); +} + +void initmac() { + //defmac("cpm\t1"); + defmac("I8080\t1"); + defmac("RMAC\t1"); + defmac("smallc\t1"); +} + +/** + * Output internal generated label prefix + */ +void output_label_prefix() { + output_byte('$'); +} + +/** + * Output a label definition terminator + */ +void output_label_terminator () { + output_byte (':'); +} + +/** + * begin a comment line for the assembler + */ +void gen_comment() { + output_byte (';'); +} + +/** + * print any assembler stuff needed after all code + */ +void trailer() { + output_line (";\t.end"); +} + +/** + * text (code) segment + */ +void code_segment_gtext() { + output_line ("\t.area SMALLC_GENERATED (REL,CON,CSEG)"); +} + +/** + * data segment + */ +void data_segment_gdata() { + output_line ("\t.area SMALLC_GENERATED_DATA (REL,CON,DSEG)"); +} + +/** + * Output the variable symbol at scptr as an extrn or a public + * @param scptr + */ +void ppubext(symbol_t *scptr) { + if (symbol_table[current_symbol_table_idx].storage == STATIC) return; + output_with_tab (scptr->storage == EXTERN ? ";extrn\t" : ".globl\t"); + output_string (scptr->name); + newline(); +} + +/** + * Output the function symbol at scptr as an extrn or a public + * @param scptr + */ +void fpubext(symbol_t *scptr) { + if (scptr->storage == STATIC) return; + output_with_tab (scptr->offset == FUNCTION ? ".globl\t" : ";extrn\t"); + output_string (scptr->name); + newline (); +} + +/** + * Output a decimal number to the assembler file, with # prefix + * @param num + */ +void output_number(num) int num; { + output_byte('#'); + output_decimal(num); +} + +/** + * fetch a static memory cell into the primary register + * @param sym + */ +void gen_get_memory(symbol_t *sym) { + if ((sym->identity != POINTER) && (sym->type == CCHAR)) { + output_with_tab ("lda\t"); + output_string (sym->name); + newline (); + gen_call ("ccsxt"); + } else if ((sym->identity != POINTER) && (sym->type == UCHAR)) { + output_with_tab("lda\t"); + output_string(sym->name); + newline(); + output_line("mov \tl,a"); + output_line("mvi \th,0"); + } else { + output_with_tab ("lhld\t"); + output_string (sym->name); + newline (); + } +} + +/** + * asm - fetch the address of the specified symbol into the primary register + * @param sym the symbol name + * @return which register pair contains result + */ +int gen_get_location(symbol_t *sym) { + /*gen_immediate (); + if (sym->storage == LSTATIC) { + print_label(sym->offset); + newline(); + } else { + output_number (sym->offset - stkp); + newline (); + output_line ("dad\tsp"); + }*/ + if (sym->storage == LSTATIC) { + gen_immediate(); + print_label(sym->offset); + newline(); + return HL_REG; + } else { + if (uflag) { + output_with_tab("ldsi\t"); + output_number(sym->offset - stkp); + newline (); + //gen_swap(); + return DE_REG; + } else { + gen_immediate(); + output_number(sym->offset - stkp); + newline (); + output_line ("dad \tsp"); + return HL_REG; + } + } +} + +/** + * asm - store the primary register into the specified static memory cell + * @param sym + */ +void gen_put_memory(symbol_t *sym) { + if ((sym->identity != POINTER) && (sym->type & CCHAR)) { + output_line ("mov \ta,l"); + output_with_tab ("sta \t"); + } else { + output_with_tab ("shld\t"); + } + output_string (sym->name); + newline (); +} + +/** + * store the specified object type in the primary register + * at the address in secondary register (on the top of the stack) + * @param typeobj + */ +void gen_put_indirect(char typeobj) { + gen_pop (); + if (typeobj & CCHAR) { + //gen_call("ccpchar"); + output_line("mov \ta,l"); + output_line("stax\td"); + } else { + if (uflag) { + output_line("shlx"); + } else { + gen_call("ccpint"); + } + } +} + +/** + * fetch the specified object type indirect through the primary + * register into the primary register + * @param typeobj object type + */ +void gen_get_indirect(char typeobj, int reg) { + if (typeobj == CCHAR) { + if (reg == DE_REG) { + gen_swap(); + } + gen_call("ccgchar"); + } else if (typeobj == UCHAR) { + if (reg == DE_REG) { + gen_swap(); + } + //gen_call("cguchar"); + output_line("mov \tl,m"); + output_line("mvi \th,0"); + } else { + if (uflag) { + if (reg == HL_REG) { + gen_swap(); + } + output_line("lhlx"); + } else { + if (reg == DE_REG) { + gen_swap(); + } + gen_call("ccgint"); + } + } +} + +/** + * swap the primary and secondary registers + */ +gen_swap() { + output_line("xchg"); +} + +/** + * print partial instruction to get an immediate value into + * the primary register + */ +gen_immediate() { + output_with_tab ("lxi \th,"); +} + +/** + * push the primary register onto the stack + */ +gen_push(int reg) { + if (reg == DE_REG) { + output_line ("push\td"); + stkp = stkp - INTSIZE; + } else { + output_line ("push\th"); + stkp = stkp - INTSIZE; + } +} + +/** + * pop the top of the stack into the secondary register + */ +gen_pop() { + output_line ("pop \td"); + stkp = stkp + INTSIZE; +} + +/** + * swap the primary register and the top of the stack + */ +gen_swap_stack() { + output_line ("xthl"); +} + +/** + * call the specified subroutine name + * @param sname subroutine name + */ +gen_call(char *sname) { + output_with_tab ("call\t"); + output_string (sname); + newline (); +} + +/** + * declare entry point + */ +declare_entry_point(char *symbol_name) { + output_string(symbol_name); + output_label_terminator(); + //newline(); +} + +/** + * return from subroutine + */ +gen_ret() { + output_line ("ret"); +} + +/** + * perform subroutine call to value on top of stack + */ +callstk() { + gen_immediate (); + output_string ("#.+5"); + newline (); + gen_swap_stack (); + output_line ("pchl"); + stkp = stkp + INTSIZE; +} + +/** + * jump to specified internal label number + * @param label the label + */ +gen_jump(label) +int label; +{ + output_with_tab ("jmp \t"); + print_label (label); + newline (); +} + +/** + * test the primary register and jump if false to label + * @param label the label + * @param ft if true jnz is generated, jz otherwise + */ +gen_test_jump(label, ft) +int label, + ft; +{ + output_line ("mov \ta,h"); + output_line ("ora \tl"); + if (ft) + output_with_tab ("jnz \t"); + else + output_with_tab ("jz \t"); + print_label (label); + newline (); +} + +/** + * print pseudo-op to define a byte + */ +gen_def_byte() { + output_with_tab (".db\t"); +} + +/** + * print pseudo-op to define storage + */ +gen_def_storage() { + output_with_tab (".ds\t"); +} + +/** + * print pseudo-op to define a word + */ +gen_def_word() { + output_with_tab (".dw\t"); +} + +/** + * modify the stack pointer to the new value indicated + * @param newstkp new value + */ +gen_modify_stack(int newstkp) { + int k; + + k = newstkp - stkp; + if (k == 0) + return (newstkp); + if (k > 0) { + if (k < 7) { + if (k & 1) { + output_line ("inx \tsp"); + k--; + } + while (k) { + output_line ("pop \tb"); + k = k - INTSIZE; + } + return (newstkp); + } + } else { + if (k > -7) { + if (k & 1) { + output_line ("dcx \tsp"); + k++; + } + while (k) { + output_line ("push\tb"); + k = k + INTSIZE; + } + return (newstkp); + } + } + gen_swap (); + gen_immediate (); + output_number (k); + newline (); + output_line ("dad \tsp"); + output_line ("sphl"); + gen_swap (); + return (newstkp); +} + +/** + * multiply the primary register by INTSIZE + */ +gen_multiply_by_two() { + output_line ("dad \th"); +} + +/** + * divide the primary register by INTSIZE, never used + */ +gen_divide_by_two() { + gen_push(HL_REG); /* push primary in prep for gasr */ + gen_immediate (); + output_number (1); + newline (); + gen_arithm_shift_right (); /* divide by two */ +} + +/** + * Case jump instruction + */ +gen_jump_case() { + output_with_tab ("jmp \tcccase"); + newline (); +} + +/** + * add the primary and secondary registers + * if lval2 is int pointer and lval is not, scale lval + * @param lval + * @param lval2 + */ +gen_add(lval,lval2) int *lval,*lval2; { + gen_pop (); + if (dbltest (lval2, lval)) { + gen_swap (); + gen_multiply_by_two (); + gen_swap (); + } + output_line ("dad \td"); +} + +/** + * subtract the primary register from the secondary + */ +gen_sub() { + gen_pop (); + gen_call ("ccsub"); +} + +/** + * multiply the primary and secondary registers (result in primary) + */ +gen_mult() { + gen_pop(); + gen_call ("ccmul"); +} + +/** + * divide the secondary register by the primary + * (quotient in primary, remainder in secondary) + */ +gen_div() { + gen_pop(); + gen_call ("ccdiv"); +} + +/** + * unsigned divide the secondary register by the primary + * (quotient in primary, remainder in secondary) + */ +gen_udiv() { + gen_pop(); + gen_call ("ccudiv"); +} + +/** + * compute the remainder (mod) of the secondary register + * divided by the primary register + * (remainder in primary, quotient in secondary) + */ +gen_mod() { + gen_div (); + gen_swap (); +} + +/** + * compute the remainder (mod) of the secondary register + * divided by the primary register + * (remainder in primary, quotient in secondary) + */ +gen_umod() { + gen_udiv (); + gen_swap (); +} + +/** + * inclusive 'or' the primary and secondary registers + */ +gen_or() { + gen_pop(); + gen_call ("ccor"); +} + +/** + * exclusive 'or' the primary and secondary registers + */ +gen_xor() { + gen_pop(); + gen_call ("ccxor"); +} + +/** + * 'and' the primary and secondary registers + */ +gen_and() { + gen_pop(); + gen_call ("ccand"); +} + +/** + * arithmetic shift right the secondary register the number of + * times in the primary register (results in primary register) + */ +gen_arithm_shift_right() { + gen_pop(); + gen_call ("ccasr"); +} + +/** + * arithmetic shift left the secondary register the number of + * times in the primary register (results in primary register) + */ +gen_arithm_shift_left() { + gen_pop (); + gen_call ("ccasl"); +} + +/** + * two's complement of primary register + */ +gen_twos_complement() { + gen_call ("ccneg"); +} + +/** + * logical complement of primary register + */ +gen_logical_negation() { + gen_call ("cclneg"); +} + +/** + * one's complement of primary register + */ +gen_complement() { + gen_call ("cccom"); +} + +/** + * Convert primary value into logical value (0 if 0, 1 otherwise) + */ +gen_convert_primary_reg_value_to_bool() { + gen_call ("ccbool"); +} + +/** + * increment the primary register by 1 if char, INTSIZE if int + */ +gen_increment_primary_reg(lvalue_t *lval) { + output_line ("inx \th"); + if (lval->ptr_type & CINT) + output_line ("inx \th"); +} + +/** + * decrement the primary register by one if char, INTSIZE if int + */ +gen_decrement_primary_reg(lvalue_t *lval) { + output_line ("dcx \th"); + if (lval->ptr_type & CINT) + output_line("dcx \th"); +} + +/* + * following are the conditional operators. + * they compare the secondary register against the primary register + * and put a literl 1 in the primary if the condition is true, + * otherwise they clear the primary register + * + */ + +/** + * equal + */ +gen_equal() { + gen_pop(); + gen_call ("cceq"); +} + +/** + * not equal + */ +gen_not_equal() { + gen_pop(); + gen_call ("ccne"); +} + +/** + * less than (signed) + */ +gen_less_than() { + gen_pop(); + gen_call ("cclt"); +} + +/** + * less than or equal (signed) + */ +gen_less_or_equal() { + gen_pop(); + gen_call ("ccle"); +} + +/** + * greater than (signed) + */ +gen_greater_than() { + gen_pop(); + gen_call ("ccgt"); +} + +/** + * greater than or equal (signed) + */ +gen_greater_or_equal() { + gen_pop(); + gen_call ("ccge"); +} + +/** + * less than (unsigned) + */ +gen_unsigned_less_than() { + gen_pop(); + gen_call ("ccult"); +} + +/** + * less than or equal (unsigned) + */ +gen_unsigned_less_or_equal() { + gen_pop(); + gen_call ("ccule"); +} + +/** + * greater than (unsigned) + */ +gen_usigned_greater_than() { + gen_pop(); + gen_call ("ccugt"); +} + +/** + * greater than or equal (unsigned) + */ +gen_unsigned_greater_or_equal() { + gen_pop(); + gen_call ("ccuge"); +} + +char *inclib() { +#ifdef cpm + return("B:"); +#endif +#ifdef unix +#ifdef INCDIR + return(INCDIR); +#else + return ""; +#endif +#endif +} + +/** + * Squirrel away argument count in a register that modstk doesn't touch. + * @param d + */ +gnargs(d) +int d; { + output_with_tab ("mvi \ta,"); + output_number(d); + newline (); +} + +int assemble(s) +char *s; { +#ifdef ASNM + char buf[100]; + strcpy(buf, ASNM); + strcat(buf, " "); + strcat(buf, s); + buf[strlen(buf)-1] = 's'; + return(system(buf)); +#else + return(0); +#endif + +} + +int link() { +#ifdef LDNM + fputs("I don't know how to link files yet\n", stderr); +#else + return(0); +#endif +} diff --git a/src/cmd/smallc/codeas09.c b/src/cmd/smallc/codeas09.c new file mode 100644 index 0000000..1703f6d --- /dev/null +++ b/src/cmd/smallc/codeas09.c @@ -0,0 +1,671 @@ +#include +#include "defs.h" +#include "data.h" + +/* + * Some predefinitions: + * + * INTSIZE is the size of an integer in the target machine + * BYTEOFF is the offset of an byte within an integer on the + * target machine. (ie: 8080,pdp11 = 0, 6809 = 1, + * 360 = 3) + * This compiler assumes that an integer is the SAME length as + * a pointer - in fact, the compiler uses INTSIZE for both. + */ +#define INTSIZE 2 +#define BYTEOFF 1 + +/* + * print all assembler info before any code is generated + */ +header () +{ + outstr("|\tSmall C MC6809\n|\tCoder (2.4,84/11/27)\n|"); + FEvers(); + nl (); + ol (".globl\tsmul,sdiv,smod,asr,asl,neg,lneg,case"); + ol (".globl\teq,ne,lt,le,gt,ge,ult,ule,ugt,uge,bool"); +} + +nl () +{ + outbyte (EOL); +} + +galign(t) + int t; +{ + return (t); +} + +/* + * return size of an integer + */ +intsize() +{ + return(INTSIZE); +} + +/* + * return offset of ls byte within word + * (ie: 8080 & pdp11 is 0, 6809 is 1, 360 is 3) + */ +byteoff() +{ + return(BYTEOFF); +} + +/* + * Output internal generated label prefix + */ +olprfix() +{ + outstr("LL"); +} + +/* + * Output a label definition terminator + */ +col () +{ + outstr ("=.\n"); +} + +/* + * begin a comment line for the assembler + */ +comment () +{ + outbyte ('|'); +} + +/* + * Output a prefix in front of user labels + */ +prefix () +{ + outbyte ('_'); +} + +/* + * print any assembler stuff needed after all code + */ +trailer () +{ + ol (".end"); +} + +/* + * function prologue + */ +prologue () +{ +} + +/* + * text (code) segment + */ +gtext () +{ + ol (".text"); +} + +/* + * data segment + */ +gdata () +{ + ol (".data"); +} + +/* + * Output the variable symbol at scptr as an extrn or a public + */ +ppubext(scptr) + char *scptr; +{ + if (scptr[STORAGE] == STATIC) + return; + ot (".globl\t"); + prefix (); + outstr (scptr); + nl(); +} + +/* + * Output the function symbol at scptr as an extrn or a public + */ +fpubext(scptr) + char *scptr; +{ + ppubext(scptr); +} + +/* + * Output a decimal number to the assembler file + */ +onum(num) + int num; +{ + outdec(num); /* pdp11 needs a "." here */ + outbyte('.'); +} + +/* + * fetch a static memory cell into the primary register + */ +getmem (sym) + char *sym; +{ + if ((sym[IDENT] != POINTER) & (sym[TYPE] == CCHAR)) { + ot ("ldb\t"); + prefix (); + outstr (sym + NAME); + nl (); + ot ("sex"); + nl (); + } else { + ot ("ldd\t"); + prefix (); + outstr (sym + NAME); + nl (); + } +} + +/* + * fetch the address of the specified symbol into the primary register + * + */ +getloc (sym) + char *sym; +{ + if (sym[STORAGE] == LSTATIC) { + immed(); + printlabel(glint(sym)); + nl(); + } else { + ot ("leay\t"); + onum (glint(sym) - stkp); + outstr ("(s)\n\ttfr\ty,d\n"); + } +} + +/* + * store the primary register into the specified static memory cell + */ +putmem (sym) + char *sym; +{ + if ((sym[IDENT] != POINTER) & (sym[TYPE] == CCHAR)) { + ot ("stb\t"); + } else + ot ("std\t"); + prefix (); + outstr (sym + NAME); + nl (); +} + +/* + * store the specified object type in the primary register + * at the address on the top of the stack + */ +putstk (typeobj) + char typeobj; +{ + if (typeobj == CCHAR) + ol ("stb\t@(s)++"); + else + ol ("std\t@(s)++"); + stkp = stkp + INTSIZE; +} + +/* + * fetch the specified object type indirect through the primary + * register into the primary register + */ +indirect (typeobj) + char typeobj; +{ + ol("tfr\td,y"); + if (typeobj == CCHAR) + ol ("ldb\t(y)\n\tsex"); + else + ol ("ldd\t(y)"); +} + +/* + * swap the primary and secondary registers + */ +swap () +{ + ol ("exg\td,x"); +} + +/* + * print partial instruction to get an immediate value into + * the primary register + */ +immed () +{ + ot ("ldd\t#"); +} + +/* + * push the primary register onto the stack + */ +gpush () +{ + ol ("pshs\td"); + stkp = stkp - INTSIZE; +} + +/* + * pop the top of the stack into the secondary register + */ +gpop () +{ + ol ("puls\td"); + stkp = stkp + INTSIZE; +} + +/* + * swap the primary register and the top of the stack + */ +swapstk () +{ + ol ("ldy\t(s)\nstd\t(s)\n\ttfr\ty,d"); +} + +/* + * call the specified subroutine name + */ +gcall (sname) + char *sname; +{ + ot ("jsr\t"); + if (*sname == '^') + outstr (++sname); + else { + prefix (); + outstr (sname); + } + nl (); +} + +/* + * return from subroutine + */ +gret () +{ + ol ("rts"); +} + +/* + * perform subroutine call to value on top of stack + */ +callstk () +{ + gpop(); + ol ("jsr\t(x)"); +} + +/* + * jump to specified internal label number + */ +jump (label) + int label; +{ + ot ("lbra\t"); + printlabel (label); + nl (); +} + +/* + * test the primary register and jump if false to label + */ +testjump (label, ft) + int label; + int ft; +{ + ol ("cmpd\t#0"); + if (ft) + ot ("lbne\t"); + else + ot ("lbeq\t"); + printlabel (label); + nl (); +} + +/* + * print pseudo-op to define a byte + */ +defbyte () +{ + ot (".byte\t"); +} + +/* + * print pseudo-op to define storage + */ +defstorage () +{ + ot (".blkb\t"); +} + +/* + * print pseudo-op to define a word + */ +defword () +{ + ot (".word\t"); +} + +/* + * modify the stack pointer to the new value indicated + */ +modstk (newstkp) + int newstkp; +{ + int k; + + k = galign(newstkp - stkp); + if (k == 0) + return (newstkp); + ot ("leas\t"); + onum (k); + outstr ("(s)\n"); + return (newstkp); +} + +/* + * multiply the primary register by INTSIZE + */ +gaslint () +{ + ol ("aslb\n\trola"); +} + +/* + * divide the primary register by INTSIZE + */ +gasrint() +{ + ol ("asra\n\trorb"); +} + +/* + * Case jump instruction + */ +gjcase() +{ + ot ("jmp\tcase"); + nl (); +} + +/* + * add the primary and secondary registers + * if lval2 is int pointer and lval is int, scale lval + */ +gadd (lval, lval2) + int *lval, *lval2; +{ + if (dbltest (lval2, lval)) { + ol ("asl\t1(s)\n\trol\t(s)"); + } + ol ("addd\t(s)++"); + stkp = stkp + INTSIZE; +} + +/* + * subtract the primary register from the secondary + */ +gsub () +{ + ol ("subd\t(s)++\n\tcoma\n\tcomb\n\taddd\t#1"); + stkp = stkp + INTSIZE; +} + +/* + * multiply the primary and secondary registers + * (result in primary) + */ +gmult () +{ + gcall ("^smul"); + stkp = stkp + INTSIZE; +} + +/* + * divide the secondary register by the primary + * (quotient in primary, remainder in secondary) + */ +gdiv () +{ + gcall ("^sdiv"); + stkp = stkp + INTSIZE; +} + +/* + * compute the remainder (mod) of the secondary register + * divided by the primary register + * (remainder in primary, quotient in secondary) + */ +gmod () +{ + gcall ("^smod"); + stkp = stkp + INTSIZE; +} + +/* + * inclusive 'or' the primary and secondary registers + */ +gor () +{ + ol ("ora\t(s)+\n\torb\t(s)+"); + stkp = stkp + INTSIZE; +} + +/* + * exclusive 'or' the primary and secondary registers + */ +gxor () +{ + ol ("eora\t(s)+\n\teorb\t(s)+"); + stkp = stkp + INTSIZE; +} + +/* + * 'and' the primary and secondary registers + */ +gand () +{ + ol ("anda\t(s)+\n\tandb\t(s)+"); + stkp = stkp + INTSIZE; +} + +/* + * arithmetic shift right the secondary register the number of + * times in the primary register + * (results in primary register) + */ +gasr () +{ + gcall ("^asr"); + stkp = stkp + INTSIZE; +} + +/* + * arithmetic shift left the secondary register the number of + * times in the primary register + * (results in primary register) + */ +gasl () +{ + gcall ("^asl"); + stkp = stkp + INTSIZE; +} + +/* + * two's complement of primary register + */ +gneg () +{ + gcall ("^neg"); +} + +/* + * logical complement of primary register + */ +glneg () +{ + gcall ("^lneg"); +} + +/* + * one's complement of primary register + */ +gcom () +{ + ol ("coma\n\tcomb"); +} + +/* + * convert primary register into logical value + */ +gbool () +{ + gcall ("^bool"); +} + +/* + * increment the primary register by 1 if char, INTSIZE if int + */ +ginc (lval) + int lval[]; +{ + if (lval[2] == CINT) + ol ("addd\t#2"); + else + ol ("addd\t#1"); +} + +/* + * decrement the primary register by one if char, INTSIZE if int + */ +gdec (lval) + int lval[]; +{ + if (lval[2] == CINT) + ol ("subd\t#2"); + else + ol ("subd\t#1"); +} + +/* + * following are the conditional operators. + * they compare the secondary register against the primary register + * and put a literl 1 in the primary if the condition is true, + * otherwise they clear the primary register + */ + +/* + * equal + */ +geq () +{ + gcall ("^eq"); + stkp = stkp + INTSIZE; +} + +/* + * not equal + */ +gne () +{ + gcall ("^ne"); + stkp = stkp + INTSIZE; +} + +/* + * less than (signed) + */ +glt () +{ + gcall ("^lt"); + stkp = stkp + INTSIZE; +} + +/* + * less than or equal (signed) + */ +gle () +{ + gcall ("^le"); + stkp = stkp + INTSIZE; +} + +/* + * greater than (signed) + */ +ggt () +{ + gcall ("^gt"); + stkp = stkp + INTSIZE; +} + +/* + * greater than or equal (signed) + */ +gge () +{ + gcall ("^ge"); + stkp = stkp + INTSIZE; +} + +/* + * less than (unsigned) + */ +gult () +{ + gcall ("^ult"); + stkp = stkp + INTSIZE; +} + +/* + * less than or equal (unsigned) + */ +gule () +{ + gcall ("^ule"); + stkp = stkp + INTSIZE; +} + +/* + * greater than (unsigned) + */ +gugt () +{ + gcall ("^ugt"); + stkp = stkp + INTSIZE; +} + +/* + * greater than or equal (unsigned) + */ +guge () +{ + gcall ("^uge"); + stkp = stkp + INTSIZE; +} + +/* + * Squirrel away argument count in a register that modstk/getloc/stloc + * doesn't touch. + */ +gnargs (d) + int d; +{ + ot ("ldu\t#"); + onum(d); + nl (); +} diff --git a/src/cmd/smallc/codem68k.c b/src/cmd/smallc/codem68k.c new file mode 100644 index 0000000..57455be --- /dev/null +++ b/src/cmd/smallc/codem68k.c @@ -0,0 +1,722 @@ +#include +#include "defs.h" +#include "data.h" + +int needr0; +int needh; + +/* + * Some predefinitions: + * + * INTSIZE is the size of an integer in the target machine + * BYTEOFF is the offset of an byte within an integer on the + * target machine. (ie: 8080,pdp11 = 0, 6809 = 1, + * 360 = 3) + * This compiler assumes that an integer is the SAME length as + * a pointer - in fact, the compiler uses INTSIZE for both. + */ +#define INTSIZE 4 +#define BYTEOFF 3 + +/* + * print all assembler info before any code is generated + * + */ +header () +{ + outstr("#\tSmall C M68000\n#\tCoder (1.2,84/11/28)\n#"); + FEvers(); + nl (); + ol ("global\tTlneg"); + ol ("global\tTcase"); + ol ("global\tTeq"); + ol ("global\tTne"); + ol ("global\tTlt"); + ol ("global\tTle"); + ol ("global\tTgt"); + ol ("global\tTge"); + ol ("global\tTult"); + ol ("global\tTule"); + ol ("global\tTugt"); + ol ("global\tTuge"); + ol ("global\tTbool"); + ol ("global\tTmult"); + ol ("global\tTdiv"); + ol ("global\tTmod"); +} + +nl() +{ + if (needh) { + ol ("word\t0"); + needh = 0; + } + if (needr0) { + needr0 = 0; + outstr(",%d0"); + } + outbyte(EOL); +} + +galign(t) + int t; +{ + int sign; + if (t < 0) { + sign = 1; + t = -t; + } else + sign = 0; + t = (t + INTSIZE - 1) & ~(INTSIZE - 1); + t = sign? -t: t; + return (t); +} + +/* + * return size of an integer + */ +intsize() +{ + return(INTSIZE); +} + +/* + * return offset of ls byte within word + * (ie: 8080 & pdp11 is 0, 6809 is 1, 360 is 3) + */ +byteoff() +{ + return(BYTEOFF); +} + +/* + * Output internal generated label prefix + */ +olprfix() +{ + outstr("LL"); +} + +/* + * Output a label definition terminator + */ +col () +{ + outstr (":\n"); +} + +/* + * begin a comment line for the assembler + * + */ +comment () +{ + outbyte ('#'); +} + +/* + * Output a prefix in front of user labels + */ +prefix () +{ +/* outbyte ('_'); */ +} + +/* + * print any assembler stuff needed after all code + * + */ +trailer () +{ +} + +/* + * function prologue + */ +prologue () +{ + /* this is where we'd put splimit stuff */ +} + +/* + * text (code) segment + */ +gtext () +{ + ol ("text"); +} + +/* + * data segment + */ +gdata () +{ + ol ("data"); +} + +/* + * Output the variable symbol at scptr as an extrn or a public + */ +ppubext(scptr) + char *scptr; +{ + if (scptr[STORAGE] == STATIC) + return; + ot ("global\t"); + prefix (); + outstr (scptr); + nl(); +} + +/* + * Output the function symbol at scptr as an extrn or a public + */ +fpubext(scptr) + char *scptr; +{ + ppubext(scptr); +} + +/* + * Output a decimal number to the assembler file + */ +onum(num) + int num; +{ + outdec(num); /* pdp11 needs a "." here */ +} + +/* + * fetch a static memory cell into the primary register + */ +getmem (sym) + char *sym; +{ + int ischr; + if ((sym[IDENT] != POINTER) & (sym[TYPE] == CCHAR)) { + ischr = 1; + ot ("mov.b\t"); + prefix (); + outstr (sym + NAME); + } else { + ischr = 0; + ot ("mov.l\t"); + prefix (); + outstr (sym + NAME); + } + outstr(",%d0\n"); + if (ischr) + ol ("ext.b\t%d0"); +} + +/* + * fetch the address of the specified symbol into the primary register + */ +getloc (sym) + char *sym; +{ + if (sym[STORAGE] == LSTATIC) { + immed(); + printlabel(glint(sym)); + nl(); + } else { + ot ("lea.l\t"); + onum (glint(sym) - stkp); + outstr (",%a0\n"); + ol ("mov.l\t%a0,%d0"); + } +} + +/* + * store the primary register into the specified static memory cell + */ +putmem (sym) + char *sym; +{ + if ((sym[IDENT] != POINTER) & (sym[TYPE] == CCHAR)) { + ot ("mov.b\t%d0,"); + } else + ot ("mov.l\t%d0,"); + prefix (); + outstr (sym + NAME); + nl (); +} + +/* + * store the specified object type in the primary register + * at the address on the top of the stack + */ +putstk (typeobj) + char typeobj; +{ + ol ("mov.l\t(%sp)+,%a0"); + if (typeobj == CCHAR) + ol ("mov.b\t%d0,(%a0)"); + else + ol ("mov.l\t%d0,(%a0)"); + stkp = stkp + INTSIZE; +} + +/* + * fetch the specified object type indirect through the primary + * register into the primary register + */ +indirect (typeobj) + char typeobj; +{ + ol ("mov.l\t%d0,%a0"); + if (typeobj == CCHAR) + ol ("mov.b\t(%a0),%d0"); + else + ol ("mov.l\t(%a0),%d0"); +} + +/* + * swap the primary and secondary registers + */ +swap () +{ + ol ("mov.l\t%d0,%d2\n\tmov.l\t%d1,%d0\n\tmov.l\t%d2,%d1"); +} + +/* + * print partial instruction to get an immediate value into + * the primary register + */ +immed () +{ + ot ("mov.l\t&"); + needr0 = 1; +} + +/* + * push the primary register onto the stack + */ +gpush () +{ + ol ("mov.l\t%d0,-(%sp)"); + stkp = stkp - INTSIZE; +} + +/* + * pop the top of the stack into the secondary register + */ +gpop () +{ + ol ("mov.l\t(%sp)+,%d1"); + stkp = stkp + INTSIZE; +} + +/* + * swap the primary register and the top of the stack + */ +swapstk () +{ + ol ("mov.l\t(%sp)+,%d2\nmov.l\t%d0,-(%sp)\nmov.l\t%d2,%d0"); +} + +/* + * call the specified subroutine name + */ +gcall (sname) + char *sname; +{ + if (*sname == '^') { + ot ("jsr\tT"); + outstr (++sname); + } else { + ot ("jsr\t"); + prefix (); + outstr (sname); + } + nl (); +} + +/* + * return from subroutine + */ +gret () +{ + ol ("rts"); +} + +/* + * perform subroutine call to value on top of stack + */ +callstk () +{ + ol ("jsr\t(%sp)+"); + stkp = stkp + INTSIZE; +} + +/* + * jump to specified internal label number + */ +jump (label) + int label; +{ + ot ("jmp\t"); + printlabel (label); + nl (); +} + +/* + * test the primary register and jump if false to label + * + */ +testjump (label, ft) + int label; + int ft; +{ + ol ("cmp.l\t%d0,&0"); + if (ft) + ot ("beq\t"); + else + ot ("bne\t"); + printlabel (label); + nl (); +} + +/* + * print pseudo-op to define a byte + */ +defbyte () +{ + ot ("byte\t"); +} + +/* + * print pseudo-op to define storage + */ +defstorage () +{ + ot ("space\t"); +} + +/* + * print pseudo-op to define a word + */ +defword () +{ + ot ("long\t"); +} + +/* + * modify the stack pointer to the new value indicated + */ +modstk (newstkp) + int newstkp; +{ + int k; + + k = newstkp - stkp; + if (k % INTSIZE) + error("Bad stack alignment (compiler error)"); + if (k == 0) + return (newstkp); + ot ("add.l\t&"); + onum (k); + outstr (",sp"); + nl(); + return (newstkp); +} + +/* + * multiply the primary register by INTSIZE + */ +gaslint () +{ + ol ("asl.l\t&2,%d0"); +} + +/* + * divide the primary register by INTSIZE + */ +gasrint() +{ + ol ("asr.l\t&2,%d0"); +} + +/* + * Case jump instruction + */ +gjcase() +{ + gcall ("^case"); +} + +/* + * add the primary and secondary registers + * if lval2 is int pointer and lval is int, scale lval + */ +gadd (lval, lval2) + int *lval, *lval2; +{ + if (dbltest (lval2, lval)) { + ol ("asl.l\t&2,(%sp)"); + } + ol ("add.l\t(%sp)+,%d0"); + stkp = stkp + INTSIZE; + +} + +/* + * subtract the primary register from the secondary + */ +gsub () +{ + ol ("mov.l\t(%sp)+,%d2"); + ol ("sub.l\t%d0,%d2"); + ol ("mov.l\t%d2,%d0"); + stkp = stkp + INTSIZE; +} + +/* + * multiply the primary and secondary registers + * (result in primary) + */ +gmult () +{ + gcall ("^mult"); + stkp = stkp + INTSIZE; +} + +/* + * divide the secondary register by the primary + * (quotient in primary, remainder in secondary) + */ +gdiv () +{ + gcall ("^div"); + stkp = stkp + INTSIZE; +} + +/* + * compute the remainder (mod) of the secondary register + * divided by the primary register + * (remainder in primary, quotient in secondary) + */ +gmod () +{ + gcall ("^mod"); + stkp = stkp + INTSIZE; +} + +/* + * inclusive 'or' the primary and secondary registers + */ +gor () +{ + ol ("or.l\t(%sp)+,%d0"); + stkp = stkp + INTSIZE; +} + +/* + * exclusive 'or' the primary and secondary registers + */ +gxor () +{ + ol ("mov.l\t(%sp)+,%d1"); + ol ("eor.l\t%d1,%d0"); + stkp = stkp + INTSIZE; +} + +/* + * 'and' the primary and secondary registers + */ +gand () +{ + ol ("and.l\t(%sp)+,%d0"); + stkp = stkp + INTSIZE; +} + +/* + * arithmetic shift right the secondary register the number of + * times in the primary register + * (results in primary register) + */ +gasr () +{ + ol ("mov.l\t(%sp)+,%d1"); + ol ("asr.l\t%d0,%d1"); + ol ("mov.l\t%d1,%d0"); + stkp = stkp + INTSIZE; +} + +/* + * arithmetic shift left the secondary register the number of + * times in the primary register + * (results in primary register) + */ +gasl () +{ + ol ("mov.l\t(%sp)+,%d1"); + ol ("asl.l\t%d0,%d1"); + ol ("mov.l\t%d1,%d0"); + stkp = stkp + INTSIZE; +} + +/* + * two's complement of primary register + */ +gneg () +{ + ol ("neg.l\t%d0"); +} + +/* + * logical complement of primary register + */ +glneg () +{ + gcall ("^lneg"); +} + +/* + * one's complement of primary register + */ +gcom () +{ + ol ("not\t%d0"); +} + +/* + * convert primary register into logical value + */ +gbool () +{ + gcall ("^bool"); +} + +/* + * increment the primary register by 1 if char, INTSIZE if int + */ +ginc (lval) + int lval[]; +{ + if (lval[2] == CINT) + ol ("addq.l\t&4,%d0"); + else + ol ("addq.l\t&1,%d0"); +} + +/* + * decrement the primary register by one if char, INTSIZE if int + */ +gdec (lval) + int lval[]; +{ + if (lval[2] == CINT) + ol ("subq.l\t&4,%d0"); + else + ol ("subq.l\t&1,%d0"); +} + +/* + * following are the conditional operators. + * they compare the secondary register against the primary register + * and put a literl 1 in the primary if the condition is true, + * otherwise they clear the primary register + */ + +/* + * equal + */ +geq () +{ + gcall ("^eq"); + stkp = stkp + INTSIZE; +} + +/* + * not equal + */ +gne () +{ + gcall ("^ne"); + stkp = stkp + INTSIZE; +} + +/* + * less than (signed) + */ +glt () +{ + gcall ("^lt"); + stkp = stkp + INTSIZE; +} + +/* + * less than or equal (signed) + */ +gle () +{ + gcall ("^le"); + stkp = stkp + INTSIZE; +} + +/* + * greater than (signed) + */ +ggt () +{ + gcall ("^gt"); + stkp = stkp + INTSIZE; +} + +/* + * greater than or equal (signed) + */ +gge () +{ + gcall ("^ge"); + stkp = stkp + INTSIZE; +} + +/* + * less than (unsigned) + */ +gult () +{ + gcall ("^ult"); + stkp = stkp + INTSIZE; +} + +/* + * less than or equal (unsigned) + */ +gule () +{ + gcall ("^ule"); + stkp = stkp + INTSIZE; +} + +/* + * greater than (unsigned) + */ +gugt () +{ + gcall ("^ugt"); + stkp = stkp + INTSIZE; +} + +/* + * greater than or equal (unsigned) + */ +guge () +{ + gcall ("^uge"); + stkp = stkp + INTSIZE; +} + +/* + * Squirrel away argument count in a register that modstk/getloc/stloc + * doesn't touch. + */ +gnargs (d) + int d; +{ + ot ("mov.l\t&"); + onum(d); + outstr(",%d3\n"); +} diff --git a/src/cmd/smallc/codemips.c b/src/cmd/smallc/codemips.c new file mode 100644 index 0000000..5d92c73 --- /dev/null +++ b/src/cmd/smallc/codemips.c @@ -0,0 +1,824 @@ +#include +#include "defs.h" +#include "data.h" + +/* + * Some predefinitions: + * + * INTSIZE is the size of an integer in the target machine + * BYTEOFF is the offset of an byte within an integer on the + * target machine. (ie: 8080,pdp11 = 0, 6809 = 1, + * 360 = 3) + * This compiler assumes that an integer is the SAME length as + * a pointer - in fact, the compiler uses INTSIZE for both. + */ +#define BYTEOFF 0 + +/* + * Print all assembler info before any code is generated. + */ +header() +{ + output_string ("#\tSmall C for MIPS32\n"); + output_string ("#\tRetroBSD Project\n"); + output_string ("#\n"); + output_string ("\t.set\tnoreorder\n"); + //output_line ("global\tTlneg"); + //output_line ("global\tTcase"); + //output_line ("global\tTeq"); + //output_line ("global\tTne"); + //output_line ("global\tTlt"); + //output_line ("global\tTle"); + //output_line ("global\tTgt"); + //output_line ("global\tTge"); + //output_line ("global\tTult"); + //output_line ("global\tTule"); + //output_line ("global\tTugt"); + //output_line ("global\tTuge"); + //output_line ("global\tTbool"); + //output_line ("global\tTmult"); + //output_line ("global\tTdiv"); + //output_line ("global\tTmod"); +} + +newline() +{ + output_byte ('\n'); +} + +galign(t) + int t; +{ + int sign; + if (t < 0) { + sign = 1; + t = -t; + } else + sign = 0; + t = (t + INTSIZE - 1) & ~(INTSIZE - 1); + t = sign? -t: t; + return (t); +} + +/* + * Return size of an integer. + */ +intsize() +{ + return INTSIZE; +} + +/* + * Return offset of ls byte within word. + * (ie: 8080 & pdp11 is 0, 6809 is 1, 360 is 3) + */ +byteoff() +{ + return BYTEOFF; +} + +/* + * Output internal generated label prefix. + */ +void output_label_prefix() +{ + output_string (".L"); +} + +/* + * Output a label definition terminator. + */ +void output_label_terminator() +{ + output_string (":"); +} + +/* + * Begin a comment line for the assembler. + */ +void gen_comment() { + output_byte ('#'); +} + +/* + * Print any assembler stuff needed after all code. + */ +trailer() +{ +} + +/* + * Function prologue. + */ +fentry(int argtop) +{ + int i; + + /* Save register arguments to stack. */ + for (i=0; i>2, i); + + /* Allocate an empty call frame for 4 args. + * Plus additional 4 bytes to save RA. */ + output_line("addiu\t$sp, -20"); + output_line("sw\t$ra, 16($sp)"); +} + +/* + * Text (code) segment. + */ +code_segment_gtext() +{ + output_line (".text"); +} + +/* + * Data segment. + */ +data_segment_gdata() +{ + output_line (".data"); +} + +char *inclib() { +#ifdef cpm + return("B:"); +#endif +#ifdef unix +#ifdef INCDIR + return(INCDIR); +#else + return ""; +#endif +#endif +} +/* + * Output the variable symbol at scptr as an extrn or a public. + */ +void ppubext (symbol_t *scptr) +{ + if( scptr->storage == STATIC ) + return; + output_string ("\t.globl\t"); + output_string (scptr); + newline(); +} + +/* + * Output the function symbol at scptr as an extrn or a public + */ +void fpubext (symbol_t *scptr) +{ + ppubext (scptr); +} + +/* + * Output a decimal number to the assembler file. + */ +void output_number(int num) +{ + fprintf(output, "%d", num); +} + +/* + * Fetch a static memory cell into the primary register. + */ +void gen_get_memory(symbol_t *sym) +{ + output_string ("\tla\t$t0, "); + output_string (sym->name); + newline(); + if ((sym->identity != POINTER) & (sym->type & CCHAR)) { + if(sym->type & UNSIGNED ) { + output_line ("lbu\t$v0, 0($t0)"); + } else { + output_line ("lb\t$v0, 0($t0)"); + } + } else { + output_line ("lw\t$v0, 0($t0)"); + } +} + + +/* + * Fetch the address of the specified symbol into the primary register. + */ +int gen_get_location(symbol_t *sym) +{ + if( sym->storage == LSTATIC) { + output_string ("\tla $v0, "); + print_label(sym->offset); + newline(); + } else { + output_string("\taddiu\t$v0, $sp, "); + output_number (sym->offset - stkp); + newline(); + } +} + +/* + * Store the primary register into the specified static memory cell. + */ +void gen_put_memory(symbol_t *sym) +{ + output_string ("\tla\t$t0, "); + output_string (sym->name); + newline(); + if ((sym->identity != POINTER) & (sym->type & CCHAR)) { + output_line ("sb\t$v0, 0($t0)"); + } else { + output_line ("sw\t$v0, 0($t0)"); + } +} + +/* + * Store the specified object type in the primary register + * at the address on the top of the stack. + */ +void gen_put_indirect(char typeobj) +{ + output_line ("lw\t$t1, 16($sp)"); + output_line ("addiu\t$sp, 4"); + if (typeobj & CCHAR) + output_line ("sb\t$v0, 0($t1)"); + else + output_line ("sw\t$v0, 0($t1)"); + stkp = stkp + INTSIZE; +} + +/* + * Fetch the specified object type indirect through the primary + * register into the primary register. + */ +void gen_get_indirect(char typeobj, int reg) +{ + if (typeobj & CCHAR) { + if( typeobj & UNSIGNED ) { + output_line ("lbu\t$v0, 0($v0)"); + } else { + output_line ("lb\t$v0, 0($v0)"); + } + } else { + output_line ("lw\t$v0, 0($v0)"); + } +} + +/* + * Swap the primary and secondary registers. + */ +gen_swap() +{ + output_line ("move\t$at, $v0\n\tmove\t$v0, $v1\n\tmove\t$v1, $at"); +} + +/* + * Print partial instruction to get an immediate value into + * the primary register. + */ +gen_immediate_a() +{ + output_string ("\tla\t$v0, "); +} + +gen_immediate_c() +{ + output_string ("\tli\t$v0, "); +} + +/* + * Push the primary register onto the stack. + */ +gen_push() +{ + output_line ("addiu\t$sp, -4"); + output_line ("sw\t$v0, 16($sp)"); + stkp = stkp - INTSIZE; +} + +/* + * Pop the top of the stack into the secondary register. + */ +gen_pop() +{ + output_line ("lw\t$v1, 16($sp)"); + output_line ("addiu\t$sp, 4"); + stkp = stkp + INTSIZE; +} + +/* + * Swap the primary register and the top of the stack. + */ +gen_swap_stack() +{ + output_line ("move\t$t1, $v0"); + output_line ("lw\t$v0, 16($sp)"); + output_line ("sw\t$t1, 16($sp)"); +} + +/* + * Call the specified subroutine name. + */ +gen_call (char * sname) +{ + output_string ("\tjal\t"); + if (*sname == '^') { + output_string ("__sc_"); + sname++; + } + output_string (sname); + newline(); + output_line ("nop"); /* fill delay slot */ +} + +/* + * Return from subroutine. + */ +gen_ret() +{ + output_line("lw\t$ra, 16($sp)"); + output_line("jr\t$ra"); + output_line("addiu\t$sp, 20"); +} + +/* + * Perform subroutine call to value on top of stack. + */ +callstk() +{ + output_line ("lw\t$t1, 16($sp)"); + output_line("jr\t$t1"); + output_line ("addiu\t$sp, 4"); + stkp = stkp + INTSIZE; +} + +/* + * Jump to specified internal label number. + */ +gen_jump (int label) +{ + output_string ("\tj\t"); + print_label (label); + newline(); + output_line ("nop"); +} + +/* + * Test the primary register and jump if false to label. + */ +gen_test_jump (int label, int ft) +{ + if (ft) + output_string("\tbne\t$v0, $zero, "); + else + output_string("\tbeq\t$v0, $zero, "); + print_label (label); + newline(); + output_line("nop"); // fill delay slot +} + +/* + * Print pseudo-op to define a byte. + */ +gen_def_byte() +{ + output_string ("\t.byte\t"); +} + +/* + * Print pseudo-op to define storage. + */ +gen_def_storage() +{ + output_string ("\t.space\t"); +} + +/* + * Print pseudo-op to define a word. + */ +gen_def_word() +{ + output_string ("\t.word\t"); +} + +/* + * Generate alignment to a word boundary. + */ +gen_align_word() +{ + output_string ("\t.align\t2\n"); +} + +/* + * Modify the stack pointer to the new value indicated. + */ +gen_modify_stack (int newstkp) +{ + int k; + + k = newstkp - stkp; + if (k % INTSIZE) + error("Bad stack alignment (compiler error)"); + if (k == 0) + return (newstkp); + output_string ("\taddiu\t$sp, "); + output_number (k); + newline(); + return (newstkp); +} + +/* + * Multiply the primary register by INTSIZE. + */ +gen_multiply_by_two() +{ + output_line ("sll\t$v0, 2"); +} + +/* + * Divide the primary register by INTSIZE. + */ +gen_divide_by_two() +{ + output_line ("sra\t$v0, 2"); +} + +/* + * Case jump instruction. + */ +gen_jump_case() +{ + gen_call("^case"); +} + +/* + * Add the primary and secondary registers. + * If lval2 is int pointer and lval is int, scale lval. + */ +gen_add (int *lval, int *lval2) +{ + output_line ("lw\t$t1, 16($sp)"); + output_line ("addiu\t$sp, 4"); + if (dbltest (lval2, lval)) { + output_line("sll\t$t1, 2"); + } + output_line ("add\t$v0, $t1"); + stkp = stkp + INTSIZE; +} + +/* + * Subtract the primary register from the secondary. // *** from TOS + */ +gen_sub() +{ + output_line ("lw\t$t1, 16($sp)"); + output_line ("addiu\t$sp, 4"); + output_line ("sub\t$v0, $t1, $v0"); + stkp = stkp + INTSIZE; +} + +/* + * Multiply the primary and secondary registers. + * (result in primary) + */ +gen_mult() +{ + output_line ("lw\t$t1, 16($sp)"); + output_line ("addiu\t$sp, 4"); + output_line ("mult\t$v0, $t1"); + output_line ("mflo\t$v0"); + //gcall ("^mult"); + stkp = stkp + INTSIZE; +} + +/* + * Divide the secondary register by the primary. + * (quotient in primary, remainder in secondary) + */ +gen_div() +{ + output_line ("lw\t$t1, 16($sp)"); + output_line ("addiu\t$sp, 4"); + output_line ("div\t$t1, $v0"); + output_line ("mflo\t$v0"); + output_line ("mfhi\t$t1"); + //gcall ("^div"); + stkp = stkp + INTSIZE; +} + +gen_udiv() +{ + output_line ("#FIXME genudiv"); + output_line ("lw\t$t1, 16($sp)"); + output_line ("addiu\t$sp, 4"); + output_line ("divu\t$t1, $v0"); + output_line ("mflo\t$v0"); + output_line ("mfhi\t$t1"); + //gcall ("^div"); + stkp = stkp + INTSIZE; +} + +/* + * Compute the remainder (mod) of the secondary register + * divided by the primary register. + * (remainder in primary, quotient in secondary) + */ +gen_mod() +{ + output_line ("lw\t$t1, 16($sp)"); + output_line ("addiu\t$sp, 4"); + output_line ("div\t$t1, $v0"); + output_line ("mflo\t$t1"); + output_line ("mfhi\t$v0"); + //gcall ("^mod"); + stkp = stkp + INTSIZE; +} + +gen_umod() +{ + output_line ("#FIXME genumod"); + output_line ("lw\t$t1, 16($sp)"); + output_line ("addiu\t$sp, 4"); + output_line ("divu\t$t1, $v0"); + output_line ("mflo\t$t1"); + output_line ("mfhi\t$v0"); + //gcall ("^mod"); + stkp = stkp + INTSIZE; +} + +/* + * Inclusive 'or' the primary and secondary registers. + */ +gen_or() +{ + output_line ("lw\t$t1, 16($sp)"); + output_line ("addiu\t$sp, 4"); + output_line ("or\t$v0, $t1"); + //output_line ("or.l\t(%sp)+,%d0"); + stkp = stkp + INTSIZE; +} + +/* + * Exclusive 'or' the primary and secondary registers. + */ +gen_xor() +{ + output_line ("lw\t$t1, 16($sp)"); + output_line ("addiu\t$sp, 4"); + output_line ("xor\t$v0, $t1"); + //output_line ("mov.l\t(%sp)+,%d1"); + //output_line ("eor.l\t%d1,%d0"); + stkp = stkp + INTSIZE; +} + +/* + * 'And' the primary and secondary registers. + */ +gen_and() +{ + //output_line ("and.l\t(%sp)+,%d0"); + output_line ("lw\t$t1, 16($sp)"); + output_line ("addiu\t$sp, 4"); + output_line ("and\t$v0, $t1"); + stkp = stkp + INTSIZE; +} + +/* + * Arithmetic shift right the secondary register the number of + * times in the primary register. + * (results in primary register) + */ +gen_arithm_shift_right() +{ + output_line ("lw\t$t1, 16($sp)"); + output_line ("addiu\t$sp, 4"); + output_line ("srav\t$v0, $t1, $v0"); + stkp = stkp + INTSIZE; +} + +/* + * Arithmetic shift left the secondary register the number of + * times in the primary register. + * (results in primary register) + */ +gen_arithm_shift_left() +{ + output_line ("lw\t$t1, 16($sp)"); + output_line ("addiu\t$sp, 4"); + output_line ("sllv\t$v0, $t1, $v0"); + stkp = stkp + INTSIZE; +} + +/* + * Two's complement of primary register. + */ +gen_twos_complement() +{ + output_line ("sub\t$v0, $zero, $v0"); +} + +/* + * Logical complement of primary register. + */ +gen_logical_negation() +{ + //gcall ("^lneg"); + output_line ("sltu\t$t1, $v0, $zero"); + output_line ("sltu\t$t2, $zero, $v0"); + output_line ("or\t$v0, $t1, $t2"); + output_line ("xori\t$v0, 1"); +} + +/* + * One's complement of primary register. + */ +gen_complement() +{ + output_line ("addiu\t$t1, $zero, -1"); + output_line ("xor\t$v0, $t1"); +} + +/* + * Convert primary register into logical value. + */ +gen_convert_primary_reg_value_to_bool() +{ + output_line ("sltu\t$t1, $v0, $zero"); + output_line ("sltu\t$t2, $zero, $v0"); + output_line ("or\t$v0, $t1, $t2"); + //gcall ("^bool"); +} + +/* + * Increment the primary register by 1 if char, INTSIZE if int. + */ +gen_increment_primary_reg (lvalue_t *lval) +{ + if (lval->ptr_type & CINT) + output_line("addiu\t$v0, 4"); + else + output_line("addiu\t$v0, 1"); +} + +/* + * Decrement the primary register by one if char, INTSIZE if int. + */ +gen_decrement_primary_reg (lvalue_t *lval) +{ + if (lval->ptr_type & CINT) + output_line("addiu\t$v0, -4"); + else + output_line("addiu\t$v0, -1"); +} + +/* + * Following are the conditional operators. + * They compare the secondary register against the primary register + * and put a literl 1 in the primary if the condition is true, + * otherwise they clear the primary register. + */ +///// BEEP BEEP actually, compare tos +/* + * equal + */ +gen_equal() +{ + output_line("lw\t$t1, 16($sp)"); + output_line("sltu\t$t2, $v0, $t1"); + output_line("sltu\t$v0, $t1, $v0"); + output_line("or\t$v0, $t2"); + output_line("xori\t$v0, 1"); + output_line("addiu\t$sp, 4"); + //gcall ("^eq"); + stkp = stkp + INTSIZE; +} + +/* + * not equal + */ +gen_not_equal() +{ + output_line("lw\t$t1, 16($sp)"); + output_line("sltu\t$t2, $v0, $t1"); + output_line("sltu\t$v0, $t1, $v0"); + output_line("or\t$v0, $t2"); + output_line("addiu\t$sp, 4"); + //gcall ("^ne"); + stkp = stkp + INTSIZE; +} + +/* + * less than (signed) - TOS < primary + */ +gen_less_than() +{ + output_line("lw\t$t1, 16($sp)"); + output_line("addiu\t$sp, 4"); + output_line("slt\t$v0, $t1, $v0"); + //gcall ("^lt"); + stkp = stkp + INTSIZE; +} + +/* + * less than or equal (signed) TOS <= primary + */ +gen_less_or_equal() +{ + output_line("lw\t$t1, 16($sp)"); + output_line("addiu\t$sp, 4"); + output_line("slt\t$v0, $v0, $t1"); // primary < tos + output_line("xori\t$v0, 1"); // primary >= tos + //gcall ("^le"); + stkp = stkp + INTSIZE; +} + +/* + * greater than (signed) TOS > primary + */ +gen_greater_than() +{ + output_line("lw\t$t1, 16($sp)"); + output_line("addiu\t$sp, 4"); + output_line("slt\t$v0, $v0, $t1"); //pimary < TOS + //output_line("xori\t$v0, 1"); + //gcall ("^gt"); + stkp = stkp + INTSIZE; +} + +/* + * greater than or equal (signed) TOS >= primary + */ +gen_greater_or_equal() +{ + output_line("lw\t$t1, 16($sp)"); + output_line("addiu\t$sp, 4"); + output_line("slt\t$v0, $t1, $v0"); //tos < primary + output_line("xori\t$v0, 1"); //tos >= primary + //gcall ("^ge"); + stkp = stkp + INTSIZE; +} + +/* + * less than (unsigned) + */ +gen_unsigned_less_than() +{ + output_line("lw\t$t1, 16($sp)"); + output_line("addiu\t$sp, 4"); + output_line("sltu\t$v0, $t1, $v0"); + //gcall ("^ult"); + stkp = stkp + INTSIZE; +} + +/* + * less than or equal (unsigned) + */ +gen_unsigned_less_or_equal() +{ + output_line("lw\t$t1, 16($sp)"); + output_line("addiu\t$sp, 4"); + output_line("sltu\t$v0, $v0, $t1"); // primary < tos + output_line("xori\t$v0, 1"); // primary >= tos + //gcall ("^ule"); + stkp = stkp + INTSIZE; +} + +/* + * greater than (unsigned) + */ +gen_usigned_greater_than() +{ + output_line("lw\t$t1, 16($sp)"); + output_line("addiu\t$sp, 4"); + output_line("sltu\t$v0, $v0, $t1"); //pimary < TOS + //gcall ("^ugt"); + stkp = stkp + INTSIZE; +} + +/* + * greater than or equal (unsigned) + */ +gen_unsigned_greater_or_equal() +{ + output_line("lw\t$t1, 16($sp)"); + output_line("addiu\t$sp, 4"); + output_line("sltu\t$v0, $t1, $v0"); //tos < primary + output_line("xori\t$v0, 1"); //tos >= primary + //gcall ("^uge"); + stkp = stkp + INTSIZE; +} + +/* + * Put first 4 arguments to registers a0-a3. + */ +gnargs (nargs) + int nargs; +{ + int i; + + if (nargs > 4) { + error("Too many arguments in a function call (max 4 args supported)"); + nargs = 4; + } + for (i=0; i +#include "defs.h" +#include "data.h" + +int needr0; +int needh; + +/* + * Some predefinitions: + * + * INTSIZE is the size of an integer in the target machine + * BYTEOFF is the offset of an byte within an integer on the + * target machine. (ie: 8080,pdp11 = 0, 6809 = 1, + * 360 = 3) + * This compiler assumes that an integer is the SAME length as + * a pointer - in fact, the compiler uses INTSIZE for both. + */ +#define INTSIZE 4 +#define BYTEOFF 0 + +/* + * print all assembler info before any code is generated + */ +header () +{ + outstr("#\tSmall C VAX\n#\tCoder (2.4,84/11/27)\n#"); + FEvers(); + nl (); + ol (".globl\tlneg"); + ol (".globl\tcase"); + ol (".globl\teq"); + ol (".globl\tne"); + ol (".globl\tlt"); + ol (".globl\tle"); + ol (".globl\tgt"); + ol (".globl\tge"); + ol (".globl\tult"); + ol (".globl\tule"); + ol (".globl\tugt"); + ol (".globl\tuge"); + ol (".globl\tbool"); +} + +nl() +{ + if (needh) { + ol (".word\t0"); + needh = 0; + } + if (needr0) { + needr0 = 0; + outstr(",r0"); + } + outbyte(EOL); +} + +galign(t) + int t; +{ + int sign; + if (t < 0) { + sign = 1; + t = -t; + } else + sign = 0; + t = (t + INTSIZE - 1) & ~(INTSIZE - 1); + t = sign? -t: t; + return (t); +} + +/* + * return size of an integer + */ +intsize() +{ + return(INTSIZE); +} + +/* + * return offset of ls byte within word + * (ie: 8080 & pdp11 is 0, 6809 is 1, 360 is 3) + */ +byteoff() +{ + return(BYTEOFF); +} + +/* + * Output internal generated label prefix + */ +olprfix() +{ + outstr("LL"); +} + +/* + * Output a label definition terminator + */ +col () +{ + outstr (":\n"); +} + +/* + * begin a comment line for the assembler + */ +comment () +{ + outbyte ('#'); +} + +/* + * Output a prefix in front of user labels + */ +prefix () +{ + outbyte ('_'); +} + +/* + * print any assembler stuff needed after all code + */ +trailer () +{ +} + +/* + * function prologue + */ +prologue () +{ + ol (".align\t1"); +} + +/* + * text (code) segment + */ +gtext () +{ + ol (".text"); +} + +/* + * data segment + */ +gdata () +{ + ol (".data"); +} + +/* + * Output the variable symbol at scptr as an extrn or a public + */ +ppubext(scptr) + char *scptr; +{ + if (scptr[STORAGE] == STATIC) + return; + ot (".globl\t"); + prefix (); + outstr (scptr); + nl(); +} + +/* + * Output the function symbol at scptr as an extrn or a public + */ +fpubext(scptr) + char *scptr; +{ + ppubext(scptr); +} + +/* + * Output a decimal number to the assembler file + */ +onum(num) + int num; +{ + outdec(num); /* pdp11 needs a "." here */ +} + +/* + * fetch a static memory cell into the primary register + */ +getmem (sym) + char *sym; +{ + if ((sym[IDENT] != POINTER) & (sym[TYPE] == CCHAR)) { + ot ("cvtbl\t"); + prefix (); + outstr (sym + NAME); + } else { + ot ("movl\t"); + prefix (); + outstr (sym + NAME); + } + outstr(",r0\n"); +} + +/* + * fetch the address of the specified symbol into the primary register + */ +getloc (sym) + char *sym; +{ + if (sym[STORAGE] == LSTATIC) { + immed(); + printlabel(glint(sym)); + nl(); + } else { + ot ("moval\t"); + onum (glint(sym) - stkp); + outstr ("(sp),r0\n"); + } +} + +/* + * store the primary register into the specified static memory cell + */ +putmem (sym) + char *sym; +{ + if ((sym[IDENT] != POINTER) & (sym[TYPE] == CCHAR)) { + ot ("cvtlb\tr0,"); + } else + ot ("movl\tr0,"); + prefix (); + outstr (sym + NAME); + nl (); +} + +/* + * store the specified object type in the primary register + * at the address on the top of the stack + */ +putstk (typeobj) + char typeobj; +{ + if (typeobj == CCHAR) + ol ("cvtlb\tr0,*(sp)+"); + else + ol ("movl\tr0,*(sp)+"); + stkp = stkp + INTSIZE; +} + +/* + * fetch the specified object type indirect through the primary + * register into the primary register + */ +indirect (typeobj) + char typeobj; +{ + if (typeobj == CCHAR) + ol ("cvtbl\t(r0),r0"); + else + ol ("movl\t(r0),r0"); +} + +/* + * swap the primary and secondary registers + */ +swap () +{ + ol ("movl\tr0,r2\n\tmovl\tr1,r0\n\tmovl\tr2,r1"); +} + +/* + * print partial instruction to get an immediate value into + * the primary register + */ +immed () +{ + ot ("movl\t$"); + needr0 = 1; +} + +/* + * push the primary register onto the stack + */ +gpush () +{ + ol ("pushl\tr0"); + stkp = stkp - INTSIZE; +} + +/* + * pop the top of the stack into the secondary register + */ +gpop () +{ + ol ("movl\t(sp)+,r1"); + stkp = stkp + INTSIZE; +} + +/* + * swap the primary register and the top of the stack + */ +swapstk () +{ + ol ("popl\tr2\npushl\tr0\nmovl\tr2,r0"); +} + +/* + * call the specified subroutine name + */ +gcall (sname) + char *sname; +{ + if (*sname == '^') { + ot ("jsb\t"); + outstr (++sname); + } else { + ot ("jsb\t"); + prefix (); + outstr (sname); + } + nl (); +} + +/* + * return from subroutine + */ +gret () +{ + ol ("rsb"); +} + +/* + * perform subroutine call to value on top of stack + */ +callstk () +{ + ol ("jsb\t(sp)+"); + stkp = stkp + INTSIZE; +} + +/* + * jump to specified internal label number + * + */ +jump (label) + int label; +{ + ot ("jmp\t"); + printlabel (label); + nl (); +} + +/* + * test the primary register and jump if false to label + */ +testjump (label, ft) + int label; + int ft; +{ + ol ("cmpl\tr0,$0"); + if (ft) + ot ("jneq\t"); + else + ot ("jeql\t"); + printlabel (label); + nl (); +} + +/* + * print pseudo-op to define a byte + */ +defbyte () +{ + ot (".byte\t"); +} + +/* + * print pseudo-op to define storage + */ +defstorage () +{ + ot (".space\t"); +} + +/* + * print pseudo-op to define a word + */ +defword () +{ + ot (".long\t"); +} + +/* + * modify the stack pointer to the new value indicated + */ +modstk (newstkp) + int newstkp; +{ + int k; + + k = newstkp - stkp; + if (k % INTSIZE) + error("Bad stack alignment (compiler error)"); + if (k == 0) + return (newstkp); + ot ("addl2\t$"); + onum (k); + outstr (",sp"); + nl(); + return (newstkp); +} + +/* + * multiply the primary register by INTSIZE + */ +gaslint () +{ + ol ("ashl\t$2,r0,r0"); +} + +/* + * divide the primary register by INTSIZE + */ +gasrint() +{ + ol ("ashl\t$-2,r0,r0"); +} + +/* + * Case jump instruction + */ +gjcase() +{ + ot ("jmp\tcase"); + nl (); +} + +/* + * add the primary and secondary registers + * if lval2 is int pointer and lval is int, scale lval + */ +gadd (lval, lval2) + int *lval, *lval2; +{ + if (dbltest (lval2, lval)) { + ol ("ashl\t$2,(sp),(sp)"); + } + ol ("addl2\t(sp)+,r0"); + stkp = stkp + INTSIZE; +} + +/* + * subtract the primary register from the secondary + */ +gsub () +{ + ol ("subl3\tr0,(sp)+,r0"); + stkp = stkp + INTSIZE; +} + +/* + * multiply the primary and secondary registers + * (result in primary) + */ +gmult () +{ + ol ("mull2\t(sp)+,r0"); + stkp = stkp + INTSIZE; +} + +/* + * divide the secondary register by the primary + * (quotient in primary, remainder in secondary) + */ +gdiv () +{ + ol ("divl3\tr0,(sp)+,r0"); + stkp = stkp + INTSIZE; +} + +/* + * compute the remainder (mod) of the secondary register + * divided by the primary register + * (remainder in primary, quotient in secondary) + */ +gmod () +{ + ol ("movl\t(sp)+,r2\n\tmovl\t$0,r3\nediv\tr0,r2,r1,r0"); + stkp = stkp + INTSIZE; +} + +/* + * inclusive 'or' the primary and secondary registers + */ +gor () +{ + ol ("bisl2\t(sp)+,r0"); + stkp = stkp + INTSIZE; +} + +/* + * exclusive 'or' the primary and secondary registers + */ +gxor () +{ + ol ("xorl2\t(sp)+,r0"); + stkp = stkp + INTSIZE; +} + +/* + * 'and' the primary and secondary registers + */ +gand () +{ + ol ("mcoml\t(sp)+,r1\n\tbicl2\tr1,r0"); + stkp = stkp + INTSIZE; +} + +/* + * arithmetic shift right the secondary register the number of + * times in the primary register + * (results in primary register) + */ +gasr () +{ + ol("mnegl\tr0,r0\n\tashl\tr0,(sp)+,r0"); + stkp = stkp + INTSIZE; +} + +/* + * arithmetic shift left the secondary register the number of + * times in the primary register + * (results in primary register) + */ +gasl () +{ + ol ("ashl\tr0,(sp)+,r0"); + stkp = stkp + INTSIZE; +} + +/* + * two's complement of primary register + */ +gneg () +{ + ol ("mnegl\tr0,r0"); +} + +/* + * logical complement of primary register + * + */ +glneg () +{ + gcall ("^lneg"); +} + +/* + * one's complement of primary register + */ +gcom () +{ + ol ("mcoml\tr0,r0"); +} + +/* + * convert primary register into logical value + */ +gbool () +{ + gcall ("^bool"); +} + +/* + * increment the primary register by 1 if char, INTSIZE if int + */ +ginc (lval) + int lval[]; +{ + if (lval[2] == CINT) + ol ("addl2\t$4,r0"); + else + ol ("incl\tr0"); +} + +/* + * decrement the primary register by one if char, INTSIZE if int + */ +gdec (lval) + int lval[]; +{ + if (lval[2] == CINT) + ol ("subl2\t$4,r0"); + else + ol ("decl\tr0"); +} + +/* + * following are the conditional operators. + * they compare the secondary register against the primary register + * and put a literl 1 in the primary if the condition is true, + * otherwise they clear the primary register + */ + +/* + * equal + */ +geq () +{ + gcall ("^eq"); + stkp = stkp + INTSIZE; +} + +/* + * not equal + */ +gne () +{ + gcall ("^ne"); + stkp = stkp + INTSIZE; +} + +/* + * less than (signed) + */ +glt () +{ + gcall ("^lt"); + stkp = stkp + INTSIZE; +} + +/* + * less than or equal (signed) + */ +gle () +{ + gcall ("^le"); + stkp = stkp + INTSIZE; +} + +/* + * greater than (signed) + * + */ +ggt () +{ + gcall ("^gt"); + stkp = stkp + INTSIZE; +} + +/* + * greater than or equal (signed) + */ +gge () +{ + gcall ("^ge"); + stkp = stkp + INTSIZE; +} + +/* + * less than (unsigned) + */ +gult () +{ + gcall ("^ult"); + stkp = stkp + INTSIZE; +} + +/* + * less than or equal (unsigned) + */ +gule () +{ + gcall ("^ule"); + stkp = stkp + INTSIZE; +} + +/* + * greater than (unsigned) + */ +gugt () +{ + gcall ("^ugt"); + stkp = stkp + INTSIZE; +} + +/* + * greater than or equal (unsigned) + * + */ +guge () +{ + gcall ("^uge"); + stkp = stkp + INTSIZE; +} + +/* + * Squirrel away argument count in a register that modstk + * doesn't touch. + */ +gnargs(d) + int d; +{ + ot ("movl\t$"); + onum(d); + outstr (",r6\n"); +} diff --git a/src/cmd/smallc/data.c b/src/cmd/smallc/data.c new file mode 100644 index 0000000..07d91e3 --- /dev/null +++ b/src/cmd/smallc/data.c @@ -0,0 +1,47 @@ +/* + * File data.c: 2.2 (84/11/27,16:26:13) + */ +#include +#include "defs.h" + +/* storage words */ +symbol_t symbol_table[NUMBER_OF_GLOBALS + NUMBER_OF_LOCALS]; +int global_table_index, rglobal_table_index; +int local_table_index; + +loop_t loopstack[WSTABSZ]; +int loop_table_index; + +int swstcase[SWSTSZ]; +int swstlab[SWSTSZ]; +int swstp; +char litq[LITABSZ]; +int litptr; +char line[LINESIZE]; +int lptr; + +/* miscellaneous storage */ + +int nxtlab, + litlab, + stkp, + argstk, + ncmp, + errcnt, + glbflag, + verbose, + ctext, + cmode, + lastst; + +FILE *input, *output; +int inclsp; + +int current_symbol_table_idx; +int *iptr; +int fexitlab; +int errfile; +int errs; + +char initials_table[INITIALS_SIZE]; // 5kB space for initialisation data +char *initials_table_ptr = 0; diff --git a/src/cmd/smallc/data.h b/src/cmd/smallc/data.h new file mode 100644 index 0000000..5431e6f --- /dev/null +++ b/src/cmd/smallc/data.h @@ -0,0 +1,44 @@ +/* File data.h: 2.2 (84/11/27,16:26:11) */ + +/* storage words */ + +extern symbol_t symbol_table[]; +extern int global_table_index, rglobal_table_index; +extern int local_table_index; + +extern loop_t loopstack[]; +extern int loop_table_index; + +extern int swstcase[]; +extern int swstlab[]; +extern int swstp; +extern char litq[]; +extern int litptr; +extern char line[]; +extern int lptr; + +/* miscellaneous storage */ + +extern int nxtlab, + litlab, + stkp, + argstk, + ncmp, + errcnt, + glbflag, + verbose, + ctext, + cmode, + lastst; + +extern FILE *input, *output; +extern int inclsp; + +extern int current_symbol_table_idx; +extern int *iptr; +extern int fexitlab; +extern int errfile; +extern int errs; + +extern char initials_table[]; +extern char *initials_table_ptr; diff --git a/src/cmd/smallc/defs.h b/src/cmd/smallc/defs.h new file mode 100644 index 0000000..6e4bbb4 --- /dev/null +++ b/src/cmd/smallc/defs.h @@ -0,0 +1,262 @@ +/* + * File defs.h: 2.1 (83/03/21,02:07:20) + */ + +/* MIPS architecture defs */ +#define INTSIZE 4 + +/* miscellaneous */ +#define FALSE 0 +#define TRUE 1 +#define NO 0 +#define YES 1 + +#define EOS 0 +#define LF 10 +#define BKSP 8 +#define CR 13 +#define FFEED 12 +#define TAB 9 + +/* system-wide name size (for symbols) */ + +#define NAMESIZE 33 +#define NAMEMAX 32 + +typedef struct { + char name[NAMESIZE]; // symbol name + int identity; // variable, array, pointer, function + int type; // char, int + int storage; // public, auto, extern, static, lstatic, defauto + int offset; // offset + int count; // count of elements (for arrays) +} symbol_t; + +#define NUMBER_OF_GLOBALS 150 +#define NUMBER_OF_LOCALS 50 + +/* possible entries for "ident" */ +#define VARIABLE 1 +#define ARRAY 2 +#define POINTER 3 +#define FUNCTION 4 + +/** + * possible entries for "type" + * high order 14 bits give length of object + * low order 2 bits make type unique within length + */ +#define UNSIGNED 1 +#define CCHAR (1 << 2) +#define UCHAR ((1 << 2) + 1) +#define CINT (2 << 2) +#define UINT ((2 << 2) + 1) + +/* possible entries for storage */ +#define PUBLIC 1 +#define AUTO 2 +#define EXTERN 3 + +#define STATIC 4 +#define LSTATIC 5 +#define DEFAUTO 6 + +/* "do"/"for"/"while"/"switch" statement stack */ +#define WSTABSZ 100 + +/* entry offsets in "do"/"for"/"while"/"switch" stack */ +#define WSSYM 0 +#define WSSP 1 +#define WSTYP 2 +#define WSCASEP 3 +#define WSTEST 3 +#define WSINCR 4 +#define WSDEF 4 +#define WSBODY 5 +#define WSTAB 5 +#define WSEXIT 6 + +typedef struct { + int symbol_idx; // symbol table address + int stack_pointer; // stack pointer + int type; // type + int test_label; // case or test + int cont_label; // continue or default label + int body_label; // body of loop, switch ? + int exit_label; // exit label +} loop_t; + +/* possible entries for "wstyp" */ +#define WSWHILE 0 +#define WSFOR 1 +#define WSDO 2 +#define WSSWITCH 3 + +/* "switch" label stack */ +#define SWSTSZ 100 + +/* literal pool */ +#define LITABSZ 5000 +#define LITMAX LITABSZ-1 + +/* input line */ +#define LINESIZE 512 +#define LINEMAX (LINESIZE-1) +#define MPMAX LINEMAX + +/* statement types (tokens) */ +#define STIF 1 +#define STWHILE 2 +#define STRETURN 3 +#define STBREAK 4 +#define STCONT 5 +#define STASM 6 +#define STEXP 7 +#define STDO 8 +#define STFOR 9 +#define STSWITCH 10 + +#define DEFLIB inclib() + +#define HL_REG 1 +#define DE_REG 2 + +typedef struct lvalue { + symbol_t *symbol; // symbol table address, or 0 for constant + int indirect; // type of indirect object, 0 for static object + int ptr_type; // type of pointer or array, 0 for other idents +} lvalue_t; + +/** + * path to include directories. set at compile time on host machine + * @return + */ +char *inclib(); + +/** + * try to find symbol in local symbol table + * @param sname symbol name + * @return + */ +int findloc (char sname[]); + +/** + * try to find symbol in global symbol table + * @param sname + * @return + */ +int findglb (char sname[]); + +/** + * adds global symbol to the symbol table + * @param sname + * @param id + * @param typ + * @param value + * @param stor + * @return + */ +int add_global (char sname[], int id, int typ, int value, int stor, int count); + +/** + * adds local symbol to the symbol table + * @param sname symbol name + * @param id identity - possible entries, VARIABLE, ARRAY, POINTER, FUNCTION + * @param typ type - possible entries, CCHAR, CINT + * @param value offset field, it is stack frame offset for local objects + * @param stclass storage - possible entries, PUBLIC, AUTO, EXTERN, STATIC, LSTATIC, DEFAUTO + * @return + */ +int add_local (char sname[], int id, int typ, int value, int stclass, int count); + +loop_t *readloop(); +loop_t *findloop(); +loop_t *readswitch(); + +/** + * Output the variable symbol at scptr as an extrn or a public + * @param scptr + */ +void ppubext(symbol_t *scptr); + +/** + * Output the function symbol at scptr as an extrn or a public + * @param scptr + */ +void fpubext(symbol_t *scptr); + +/** + * fetch a static memory cell into the primary register + * @param sym + */ +void gen_get_memory (symbol_t *sym); + +/** + * fetch the specified object type indirect through the primary + * register into the primary register + * @param typeobj object type + */ +void gen_get_indirect(char typeobj, int reg); + +/** + * asm - fetch the address of the specified symbol into the primary register + * @param sym the symbol name + */ +int gen_get_location (symbol_t *sym); + +/** + * asm - store the primary register into the specified static memory cell + * @param sym + */ +void gen_put_memory (symbol_t *sym); + +// intialisation of global variables +#define INIT_TYPE NAMESIZE +#define INIT_LENGTH NAMESIZE+1 +#define INITIALS_SIZE 5*1024 + +/** + * a constructor :-) + */ +void create_initials(); + +/** + * add new symbol to table + * @param symbol_name + */ +void add_symbol(char *symbol_name, char type); + +/** + * find symbol in table + * @param symbol_name + * @return + */ +int find_symbol(char *symbol_name); + +/** + * add data to table for given symbol + * @param symbol_name + * @param type + * @param value + */ +void add_data(char *symbol_name, int type, int value); + +/** + * get number of data items for given symbol + * @param symbol_name + * @return + */ +int get_size(char *symbol_name); + +/** + * get item at position + * @param symbol_name + * @param position + * @return + */ +int get_item_at(char *symbol_name, int position); + +/** + * push the primary register onto the stack + */ +//void gen_push(); diff --git a/src/cmd/smallc/error.c b/src/cmd/smallc/error.c new file mode 100644 index 0000000..9420bee --- /dev/null +++ b/src/cmd/smallc/error.c @@ -0,0 +1,45 @@ +/* File error.c: 2.1 (83/03/20,16:02:00) */ +/*% cc -O -c % + * + */ + +#include +#include "defs.h" +#include "data.h" + +error (ptr) +char ptr[]; +{ + FILE *tempfile; + + tempfile = output; + output = stdout; + doerror(ptr); + output = tempfile; + doerror(ptr); + errcnt++; +} + +doerror(ptr) char *ptr; { + int k; + gen_comment (); + output_string (line); + newline (); + gen_comment (); + k = 0; + while (k < lptr) { + if (line[k] == 9) + print_tab (); + else + output_byte (' '); + k++; + } + output_byte ('^'); + newline (); + gen_comment (); + output_string ("****** "); + output_string (ptr); + output_string (" ******"); + newline (); +} + diff --git a/src/cmd/smallc/expr.c b/src/cmd/smallc/expr.c new file mode 100644 index 0000000..b445035 --- /dev/null +++ b/src/cmd/smallc/expr.c @@ -0,0 +1,730 @@ +/* + * File expr.c: 2.2 (83/06/21,11:24:26) + */ + +#include +#include "defs.h" +#include "data.h" + +//struct lvalue { +// symbol_t *symbol ; // symbol table address, or 0 for constant +// int indirect ; // type of indirect object, 0 for static object +// int ptr_type ; // type of pointer or array, 0 for other idents +// int is_const ; // true if constant expression +// int const_val ; // value of constant expression (& other uses) +// TAG_SYMBOL *tagsym ; // tag symbol address, 0 if not struct +// int (*binop)() ; // function address of highest/last binary operator +// char *stage_add ; // stage addess of "oper 0" code, else 0 +// int val_type ; // type of value calculated +//} ; + +//#define LVALUE struct lvalue + +/** + * unsigned operand ? + */ +nosign(lvalue_t *is) { + symbol_t *ptr; + + if((is->ptr_type) || + ((ptr = is->symbol) && (ptr->type & UNSIGNED))) { + return 1; + } + return 0; +} + +/** + * lval[0] - symbol table address, else 0 for constant + * lval[1] - type indirect object to fetch, else 0 for static object + * lval[2] - type pointer or array, else 0 + * @param comma + * @return + */ +expression(int comma) { + lvalue_t lval; + int k; + + do { + if (k = hier1 (&lval)) + rvalue(&lval, k); + if (!comma) + return; + } while (match (",")); +} + +/** + * assignment operators + * @param lval + * @return + */ +hier1 (lvalue_t *lval) { + int k; + lvalue_t lval2[1]; + char fc; + + k = hier1a (lval); + if (match ("=")) { + if (k == 0) { + needlval (); + return (0); + } + if (lval->indirect) + gen_push(k); + if (k = hier1 (lval2)) + k = rvalue(lval2, k); + store (lval); + return (0); + } else { + fc = ch(); + if (match ("-=") || + match ("+=") || + match ("*=") || + match ("/=") || + match ("%=") || + match (">>=") || + match ("<<=") || + match ("&=") || + match ("^=") || + match ("|=")) { + if (k == 0) { + needlval (); + return (0); + } + if (lval->indirect) + gen_push(k); + k = rvalue(lval, k); + gen_push(k); + if (k = hier1 (lval2)) + k = rvalue(lval2, k); + switch (fc) { + case '-': { + if (dbltest(lval,lval2)) + gen_multiply_by_two(); + gen_sub(); + result (lval, lval2); + break; + } + case '+': { + if (dbltest(lval,lval2)) + gen_multiply_by_two(); + gen_add (lval,lval2); + result(lval,lval2); + break; + } + case '*': gen_mult (); break; + case '/': + if(nosign(lval) || nosign(lval2)) { + gen_udiv(); + } else { + gen_div(); + } + break; + case '%': + if(nosign(lval) || nosign(lval2)) { + gen_umod(); + } else { + gen_mod(); + } + break; + case '>': gen_arithm_shift_right (); break; + case '<': gen_arithm_shift_left(); break; + case '&': gen_and (); break; + case '^': gen_xor (); break; + case '|': gen_or (); break; + } + store (lval); + return (0); + } else + return (k); + } +} + +/** + * processes ? : expression + * @param lval + * @return 0 or 1, fetch or no fetch + */ +hier1a (lvalue_t *lval) { + int k, lab1, lab2; + lvalue_t lval2[1]; + + k = hier1b (lval); + blanks (); + if (ch () != '?') + return (k); + if (k) + k = rvalue(lval, k); + for (;;) + if (match ("?")) { + gen_test_jump (lab1 = getlabel (), FALSE); + if (k = hier1b (lval2)) + k = rvalue(lval2, k); + gen_jump (lab2 = getlabel ()); + print_label (lab1); + output_label_terminator (); + newline (); + blanks (); + if (!match (":")) { + error ("missing colon"); + return (0); + } + if (k = hier1b (lval2)) + k = rvalue(lval2, k); + print_label (lab2); + output_label_terminator (); + newline (); + } else + return (0); +} + +/** + * processes logical or || + * @param lval + * @return 0 or 1, fetch or no fetch + */ +hier1b (lvalue_t *lval) { + int k, lab; + lvalue_t lval2[1]; + + k = hier1c (lval); + blanks (); + if (!sstreq ("||")) + return (k); + if (k) + k = rvalue(lval, k); + for (;;) + if (match ("||")) { + gen_test_jump (lab = getlabel (), TRUE); + if (k = hier1c (lval2)) + k = rvalue(lval2, k); + print_label (lab); + output_label_terminator (); + newline (); + gen_convert_primary_reg_value_to_bool(); + } else + return (0); +} + +/** + * processes logical and && + * @param lval + * @return 0 or 1, fetch or no fetch + */ +hier1c (lvalue_t *lval) { + int k, lab; + lvalue_t lval2[1]; + + k = hier2 (lval); + blanks (); + if (!sstreq ("&&")) + return (k); + if (k) + k = rvalue(lval, k); + for (;;) + if (match ("&&")) { + gen_test_jump (lab = getlabel (), FALSE); + if (k = hier2 (lval2)) + k = rvalue(lval2, k); + print_label (lab); + output_label_terminator (); + newline (); + gen_convert_primary_reg_value_to_bool(); + } else + return (0); +} + +/** + * processes bitwise or | + * @param lval + * @return 0 or 1, fetch or no fetch + */ +hier2 (lvalue_t *lval) { + int k; + lvalue_t lval2[1]; + + k = hier3 (lval); + blanks (); + if ((ch() != '|') | (nch() == '|') | (nch() == '=')) + return (k); + if (k) + k = rvalue(lval, k); + for (;;) { + if ((ch() == '|') & (nch() != '|') & (nch() != '=')) { + inbyte (); + gen_push(k); + if (k = hier3 (lval2)) + k = rvalue(lval2, k); + gen_or (); + blanks(); + } else + return (0); + } +} + +/** + * processes bitwise exclusive or + * @param lval + * @return 0 or 1, fetch or no fetch + */ +hier3 (lvalue_t *lval) { + int k; + lvalue_t lval2[1]; + + k = hier4 (lval); + blanks (); + if ((ch () != '^') | (nch() == '=')) + return (k); + if (k) + k = rvalue(lval, k); + for (;;) { + if ((ch() == '^') & (nch() != '=')){ + inbyte (); + gen_push(k); + if (k = hier4 (lval2)) + k = rvalue(lval2, k); + gen_xor (); + blanks(); + } else + return (0); + } +} + +/** + * processes bitwise and & + * @param lval + * @return 0 or 1, fetch or no fetch + */ +hier4 (lvalue_t *lval) { + int k; + lvalue_t lval2[1]; + + k = hier5 (lval); + blanks (); + if ((ch() != '&') | (nch() == '|') | (nch() == '=')) + return (k); + if (k) + k = rvalue(lval, k); + for (;;) { + if ((ch() == '&') & (nch() != '&') & (nch() != '=')) { + inbyte (); + gen_push(k); + if (k = hier5 (lval2)) + k = rvalue(lval2, k); + gen_and (); + blanks(); + } else + return (0); + } + +} + +/** + * processes equal and not equal operators + * @param lval + * @return 0 or 1, fetch or no fetch + */ +hier5 (lvalue_t *lval) { + int k; + lvalue_t lval2[1]; + + k = hier6 (lval); + blanks (); + if (!sstreq ("==") & + !sstreq ("!=")) + return (k); + if (k) + k = rvalue(lval, k); + for (;;) { + if (match ("==")) { + gen_push(k); + if (k = hier6 (lval2)) + k = rvalue(lval2, k); + gen_equal (); + } else if (match ("!=")) { + gen_push(k); + if (k = hier6 (lval2)) + k = rvalue(lval2, k); + gen_not_equal (); + } else + return (0); + } + +} + +/** + * comparison operators + * @param lval + * @return 0 or 1, fetch or no fetch + */ +hier6 (lvalue_t *lval) { + int k; + lvalue_t lval2[1]; + + k = hier7 (lval); + blanks (); + if (!sstreq ("<") && + !sstreq ("<=") && + !sstreq (">=") && + !sstreq (">")) + return (k); + if (sstreq ("<<") || sstreq (">>")) + return (k); + if (k) + k = rvalue(lval, k); + for (;;) { + if (match ("<=")) { + gen_push(k); + if (k = hier7 (lval2)) + k = rvalue(lval2, k); + if (nosign(lval) || nosign(lval2)) { + gen_unsigned_less_or_equal (); + continue; + } + gen_less_or_equal (); + } else if (match (">=")) { + gen_push(k); + if (k = hier7 (lval2)) + k = rvalue(lval2, k); + if (nosign(lval) || nosign(lval2)) { + gen_unsigned_greater_or_equal (); + continue; + } + gen_greater_or_equal(); + } else if ((sstreq ("<")) && + !sstreq ("<<")) { + inbyte (); + gen_push(k); + if (k = hier7 (lval2)) + k = rvalue(lval2, k); + if (nosign(lval) || nosign(lval2)) { + gen_unsigned_less_than (); + continue; + } + gen_less_than (); + } else if ((sstreq (">")) && + !sstreq (">>")) { + inbyte (); + gen_push(k); + if (k = hier7 (lval2)) + k = rvalue(lval2, k); + if (nosign(lval) || nosign(lval2)) { + gen_usigned_greater_than (); + continue; + } + gen_greater_than(); + } else + return (0); + blanks (); + } + +} + +/** + * bitwise left, right shift + * @param lval + * @return 0 or 1, fetch or no fetch + */ +hier7 (lvalue_t *lval) { + int k; + lvalue_t lval2[1]; + + k = hier8 (lval); + blanks (); + if (!sstreq (">>") && + !sstreq ("<<") || sstreq(">>=") || sstreq("<<=")) + return (k); + if (k) + k = rvalue(lval, k); + for (;;) { + if (sstreq(">>") && ! sstreq(">>=")) { + inbyte(); inbyte(); + gen_push(k); + if (k = hier8 (lval2)) + k = rvalue(lval2, k); + gen_arithm_shift_right (); + } else if (sstreq("<<") && ! sstreq("<<=")) { + inbyte(); inbyte(); + gen_push(k); + if (k = hier8 (lval2)) + k = rvalue(lval2, k); + gen_arithm_shift_left(); + } else + return (0); + blanks(); + } + +} + +/** + * addition, subtraction + * @param lval + * @return 0 or 1, fetch or no fetch + */ +hier8 (lvalue_t *lval) { + int k; + lvalue_t lval2[1]; + + k = hier9 (lval); + blanks (); + if ((ch () != '+') & (ch () != '-') | nch() == '=') + return (k); + if (k) + k = rvalue(lval, k); + for (;;) { + if (match ("+")) { + gen_push(k); + if (k = hier9 (lval2)) + k = rvalue(lval2, k); + /* if left is pointer and right is int, scale right */ + if (dbltest (lval, lval2)) + gen_multiply_by_two (); + /* will scale left if right int pointer and left int */ + gen_add (lval,lval2); + result (lval, lval2); + } else if (match ("-")) { + gen_push(k); + if (k = hier9 (lval2)) + k = rvalue(lval2, k); + /* if dbl, can only be: pointer - int, or + pointer - pointer, thus, + in first case, int is scaled up, + in second, result is scaled down. */ + if (dbltest (lval, lval2)) + gen_multiply_by_two (); + gen_sub (); + /* if both pointers, scale result */ + + /* the second major condition was added to fix &a[n]-&a[n] where a is an int array + * this was done be inspection and may cause other conditions to fail + * more testing is needed. + * Really, there are multiple problems when taking addresses of arrays + * This needs a lot more work, but it seems to fix the specific problem + * and does not introduce any bugs that I can assign to it */ + if (((lval->ptr_type & CINT) && (lval2->ptr_type & CINT)) + ||((!lval->symbol)&&(!lval2->symbol)&&(lval->ptr_type&CCHAR)&&(lval2->ptr_type&CCHAR)&&(lval->indirect & CINT) && (lval2->indirect & CINT))) { + gen_divide_by_two(); /* divide by intsize */ + } + result (lval, lval2); + } else + return (0); + } +} + +/** + * multiplication, division, modulus + * @param lval + * @return 0 or 1, fetch or no fetch + */ +hier9 (lvalue_t *lval) { + int k; + lvalue_t lval2[1]; + + k = hier10 (lval); + blanks (); + if (((ch () != '*') && (ch () != '/') && + (ch () != '%')) || (nch() == '=')) + return (k); + if (k) + k = rvalue(lval, k); + for (;;) { + if (match ("*")) { + gen_push(k); + if (k = hier10 (lval2)) + k = rvalue(lval2, k); + gen_mult (); + } else if (match ("/")) { + gen_push(k); + if (k = hier10 (lval2)) + k = rvalue(lval2, k); + if(nosign(lval) || nosign(lval2)) { + gen_udiv(); + } else { + gen_div (); + } + } else if (match ("%")) { + gen_push(k); + if (k = hier10 (lval2)) + k = rvalue(lval2, k); + if(nosign(lval) || nosign(lval2)) { + gen_umod(); + } else { + gen_mod (); + } + } else + return (0); + } + +} + +/** + * increment, decrement, negation operators + * @param lval + * @return 0 or 1, fetch or no fetch + */ +hier10 (lvalue_t *lval) { + int k; + symbol_t *ptr; + + if (match ("++")) { + if ((k = hier10 (lval)) == 0) { + needlval (); + return (0); + } + if (lval->indirect) + gen_push(k); + k = rvalue(lval, k); + gen_increment_primary_reg (lval); + store (lval); + return (0); + } else if (match ("--")) { + if ((k = hier10 (lval)) == 0) { + needlval (); + return (0); + } + if (lval->indirect) + gen_push(k); + k = rvalue(lval, k); + gen_decrement_primary_reg (lval); + store (lval); + return (0); + } else if (match ("-")) { + k = hier10 (lval); + if (k) + k = rvalue(lval, k); + gen_twos_complement(); + return (0); + } else if (match ("~")) { + k = hier10 (lval); + if (k) + k = rvalue(lval, k); + gen_complement (); + return (0); + } else if (match ("!")) { + k = hier10 (lval); + if (k) + k = rvalue(lval, k); + gen_logical_negation(); + return (0); + } else if (ch()=='*' && nch() != '=') { + inbyte(); + k = hier10 (lval); + if (k) + k = rvalue(lval, k); + if (ptr = lval->symbol) + lval->indirect = ptr->type; + else + lval->indirect = CINT; + lval->ptr_type = 0; // flag as not pointer or array + return (1); + } else if (ch()=='&' && nch()!='&' && nch()!='=') { + inbyte(); + k = hier10 (lval); + if (k == 0) { + error ("illegal address"); + return (0); + } + ptr = lval->symbol; + if( ptr ) { + lval->ptr_type = ptr->type; + if (lval->indirect) + return (0); + /* global and non-array */ + gen_immediate_a (); + output_string ((ptr = lval->symbol)->name); + newline (); + lval->indirect = ptr->type; + } else { + lval->ptr_type = lval->indirect; + lval->indirect = 0; + } + return (0); + } else { + k = hier11 (lval); + if (match ("++")) { + if (k == 0) { + needlval (); + return (0); + } + if (lval->indirect) + gen_push(k); + k = rvalue(lval, k); + gen_increment_primary_reg (lval); + store (lval); + gen_decrement_primary_reg (lval); + return (0); + } else if (match ("--")) { + if (k == 0) { + needlval (); + return (0); + } + if (lval->indirect) + gen_push(k); + k = rvalue(lval, k); + gen_decrement_primary_reg (lval); + store (lval); + gen_increment_primary_reg (lval); + return (0); + } else + return (k); + } + +} + +/** + * array subscripting + * @param lval + * @return 0 or 1, fetch or no fetch + */ +hier11 (lvalue_t *lval) { + int k; + symbol_t *ptr; + + k = primary (lval); + ptr = lval->symbol; + blanks (); + if ((ch () == '[') | (ch () == '(')) + for (;;) { + if (match ("[")) { + if (ptr == 0) { + error ("can't subscript"); + junk (); + needbrack ("]"); + return (0); + } else if (ptr->identity == POINTER) + k = rvalue(lval, k); + else if (ptr->identity != ARRAY) { + error ("can't subscript"); + k = 0; + } + gen_push(k); + expression (YES); + needbrack ("]"); + if (ptr->type & CINT) + gen_multiply_by_two (); + gen_add (NULL,NULL); + lval->symbol = 0; + lval->indirect = ptr->type; + k = HL_REG; + } else if (match ("(")) { + if (ptr == 0) + callfunction (0); + else if (ptr->identity != FUNCTION) { + k = rvalue(lval, k); + callfunction (0); + } else + callfunction (ptr); + lval->symbol = 0; + k = 0; + } else + return (k); + } + if (ptr == 0) + return (k); + if (ptr->identity == FUNCTION) { + gen_immediate_a (); + output_string (ptr); + newline (); + return (0); + } + return (k); +} diff --git a/src/cmd/smallc/function.c b/src/cmd/smallc/function.c new file mode 100644 index 0000000..e7cfe31 --- /dev/null +++ b/src/cmd/smallc/function.c @@ -0,0 +1,194 @@ +/* + * File function.c: 2.1 (83/03/20,16:02:04) + */ + +#include +#include "defs.h" +#include "data.h" + +int argtop; + +#define ARGOFFSET 20 /* for MIPS32 */ + +/** + * begin a function + * called from "parse", this routine tries to make a function out + * of what follows + * modified version. p.l. woods + */ +newfunc() { + char n[NAMESIZE]; + int idx, type; + fexitlab = getlabel(); + + if (!symname(n)) { + error("illegal function or declaration"); + kill(); + return; + } + if (idx = findglb(n)) { + if (symbol_table[idx].identity != FUNCTION) + multidef(n); + else if (symbol_table[idx].offset == FUNCTION) + multidef(n); + else + symbol_table[idx].offset = FUNCTION; + } else + add_global(n, FUNCTION, CINT, FUNCTION, PUBLIC, 1); + + if (!match("(")) + error("missing open paren"); + + output_string(n); + output_label_terminator(); + newline(); + local_table_index = NUMBER_OF_GLOBALS; //locptr = STARTLOC; + argstk = 0; + + // ANSI style argument declaration + if (doAnsiArguments() == 0) { + // K&R style argument declaration + while (! match(")")) { + if (symname(n)) { + if (findloc(n)) + multidef(n); + else { + add_local(n, 0, 0, ARGOFFSET + argstk, AUTO, 1); + argstk = argstk + INTSIZE; + } + } else { + error("illegal argument name"); + junk(); + } + blanks(); + if (!streq(line + lptr, ")")) { + if (!match(",")) + error("expected comma"); + } + if (endst()) + break; + } + stkp = 0; + argtop = argstk; + while (argstk) { + if (type = get_type()) { + getarg(type); + need_semicolon(); + } else { + error("wrong number args"); + break; + } + } + } + fentry(argtop); + statement(YES); + print_label(fexitlab); + output_label_terminator(); + newline(); + gen_modify_stack(0); + gen_ret(); + stkp = 0; + local_table_index = NUMBER_OF_GLOBALS; //locptr = STARTLOC; +} + +/** + * declare argument types + * called from "newfunc", this routine adds an entry in the local + * symbol table for each named argument + * completely rewritten version. p.l. woods + * @param t argument type (char, int) + * @return + */ +getarg(int t) { + int j, legalname, argptr; + char n[NAMESIZE]; + + for (;;) { + if (argstk == 0) + return; + + if (match("*")) + j = POINTER; + else + j = VARIABLE; + + if (! (legalname = symname(n))) + illname(); + + if (match("[")) { + while (inbyte() != ']') + if (endst()) + break; + j = POINTER; + } + if (legalname) { + if (argptr = findloc(n)) { + symbol_table[argptr].identity = j; + symbol_table[argptr].type = t; + } else + error("expecting argument name"); + } + argstk = argstk - INTSIZE; + if (endst()) + return; + if (! match(",")) + error("expected comma"); + } +} + +doAnsiArguments() { + int type; + type = get_type(); + if (type == 0) { + return 0; // no type detected, revert back to K&R style + } + argstk = 0; + for (;;) + { + if (type) { + doLocalAnsiArgument(type); + } else { + error("wrong number args"); + break; + } + if (match(",")) { + type = get_type(); + continue; + } + if (match(")")) { + break; + } + } + argtop = argstk; +} + +doLocalAnsiArgument(int type) { + char symbol_name[NAMESIZE]; + int identity, argptr, ptr; + + if (match("*")) { + identity = POINTER; + } else { + identity = VARIABLE; + } + if (symname(symbol_name)) { + if (findloc(symbol_name)) { + multidef(symbol_name); + } else { + argptr = add_local (symbol_name, identity, type, ARGOFFSET + argstk, AUTO, 1); + argstk += INTSIZE; + } + } else { + error("illegal argument name"); + junk(); + } + if (match("[")) { + while (inbyte() != ']') { + if (endst()) { + break; + } + } + identity = POINTER; + symbol_table[argptr].identity = identity; + } +} diff --git a/src/cmd/smallc/gen.c b/src/cmd/smallc/gen.c new file mode 100644 index 0000000..c966237 --- /dev/null +++ b/src/cmd/smallc/gen.c @@ -0,0 +1,163 @@ +/* File gen.c: 2.1 (83/03/20,16:02:06) */ +/*% cc -O -c % + * + */ + +#include +#include "defs.h" +#include "data.h" + +/* + * return next available internal label number + * + */ +getlabel () +{ + return (nxtlab++); + +} + +/** + * print specified number as label + * @param label + */ +print_label (label) +int label; +{ + output_label_prefix (); + output_decimal (label); +} + +/** + * glabel - generate label + * not used ? + * @param lab label number + */ +glabel (lab) +char *lab; +{ + output_string (lab); + output_label_terminator (); + newline (); +} + +/** + * gnlabel - generate numeric label + * @param nlab label number + * @return + */ +generate_label (nlab) +int nlab; +{ + print_label (nlab); + output_label_terminator (); + newline (); +} + +/** + * outputs one byte + * @param c + * @return + */ +output_byte (c) +char c; +{ + if (c == 0) + return (0); + fputc (c, output); + return (c); +} + +/** + * outputs a string + * @param ptr the string + * @return + */ +output_string (ptr) +char ptr[]; +{ + int k; + k = 0; + while (output_byte (ptr[k++])); +} + +/** + * outputs a tab + * @return + */ +print_tab () +{ + output_byte ('\t'); +} + +/** + * output line + * @param ptr + * @return + */ +output_line (ptr) +char ptr[]; +{ + output_with_tab (ptr); + newline (); +} + +/** + * tabbed output + * @param ptr + * @return + */ +output_with_tab (ptr) +char ptr[]; +{ + print_tab (); + output_string (ptr); +} + +/** + * output decimal number + * @param number + * @return + */ +output_decimal (int number) +{ + fprintf(output, "%d", number); +} + +/** + * stores values into memory + * @param lval TODO + * @return + */ +store (lvalue_t *lval) +{ + if (lval->indirect == 0) + gen_put_memory (lval->symbol); + else + gen_put_indirect (lval->indirect); +} + +rvalue (lvalue_t *lval, int reg) +{ + if ((lval->symbol != 0) & (lval->indirect == 0)) + gen_get_memory (lval->symbol); + else + gen_get_indirect (lval->indirect, reg); + return HL_REG; +} + +/** + * parses test part "(expression)" input and generates assembly for jump + * @param label + * @param ft + * @return + */ +test (label, ft) +int label, + ft; +{ + needbrack ("("); + expression (YES); + needbrack (")"); + gen_test_jump (label, ft); +} diff --git a/src/cmd/smallc/includes/ctype.h b/src/cmd/smallc/includes/ctype.h new file mode 100644 index 0000000..07c42f3 --- /dev/null +++ b/src/cmd/smallc/includes/ctype.h @@ -0,0 +1 @@ +/* Nothing needed in this file */ diff --git a/src/cmd/smallc/includes/hello.c b/src/cmd/smallc/includes/hello.c new file mode 100644 index 0000000..e0a56e4 --- /dev/null +++ b/src/cmd/smallc/includes/hello.c @@ -0,0 +1,4 @@ +main() +{ + printf("hello\n"); +} diff --git a/src/cmd/smallc/includes/stdio.h b/src/cmd/smallc/includes/stdio.h new file mode 100644 index 0000000..fcc9f11 --- /dev/null +++ b/src/cmd/smallc/includes/stdio.h @@ -0,0 +1,6 @@ +#define stdin 0 +#define stdout 1 +#define stderr 2 +#define NULL 0 +#define EOF (-1) +#define FILE char diff --git a/src/cmd/smallc/initialise.c b/src/cmd/smallc/initialise.c new file mode 100644 index 0000000..fae24c8 --- /dev/null +++ b/src/cmd/smallc/initialise.c @@ -0,0 +1,103 @@ +#include +#include +#include "defs.h" +#include "data.h" + +/* + * SYMBOL_NAME 32 + * TYPE 1 + * LENGTH 2 + * initialisation + */ + +/** + * a constructor :-) + */ +void create_initials() { + int i; + for (i=0; i> 8; + initials_table_ptr[index + 1] = 0xff & value; + length++; + initials_table_ptr[INIT_LENGTH] = (0xff00 & length) >> 8; + initials_table_ptr[INIT_LENGTH+1] = 0xff & length; +} + +/** + * get number of data items for given symbol + * @param symbol_name + * @return + */ +int get_size(char *symbol_name) { + int result = 0; + if (find_symbol(symbol_name) != 0) { + result = ((unsigned char)initials_table_ptr[INIT_LENGTH] << 8) + (unsigned char)initials_table_ptr[INIT_LENGTH+1]; + } + return result; +} + +/** + * get item at position + * @param symbol_name + * @param position + * @return + */ +int get_item_at(char *symbol_name, int position) { + int result = 0; + if (find_symbol(symbol_name) != 0) { + int index = NAMESIZE + 1 + 2 + (2 * position); + result = (initials_table_ptr[index] << 8) + (unsigned char)initials_table_ptr[index+1]; + } + return result; +} diff --git a/src/cmd/smallc/io.c b/src/cmd/smallc/io.c new file mode 100644 index 0000000..699c8ef --- /dev/null +++ b/src/cmd/smallc/io.c @@ -0,0 +1,94 @@ +/* File io.c: 2.1 (83/03/20,16:02:07) */ +/*% cc -O -c % + * + */ + +#include +#include +#include "defs.h" +#include "data.h" + +kill () +{ + lptr = 0; + line[lptr] = 0; +} + +readline () +{ + int k; + + for (;;) { + if (feof (input)) + return; + kill (); + while ((k = fgetc (input)) != EOF) { + if ((k == CR) || (k == LF) || (lptr >= LINEMAX)) + break; + line[lptr++] = k; + } + line[lptr] = 0; + if (lptr) { + if ((ctext) & (cmode)) { + gen_comment (); + output_string (line); + newline (); + } + lptr = 0; + return; + } + } +} + +inbyte () +{ + while (ch () == 0) { + if (feof (input)) + return (0); + readline (); + } + return (gch ()); +} + +inchar () +{ + if (ch () == 0) + readline (); + if (feof (input)) + return (0); + return (gch ()); +} + +/** + * gets current char from input line and moves to the next one + * @return current char + */ +gch () +{ + int c = line[lptr]; + if (c == 0) + return 0; + lptr++; + return c; +} + +/** + * returns next char + * @return next char + */ +nch () +{ + int c = line[lptr]; + if (c == 0) + return 0; + return line[lptr+1]; +} + +/** + * returns current char + * @return current char + */ +ch () +{ + return line[lptr]; +} diff --git a/src/cmd/smallc/lex.c b/src/cmd/smallc/lex.c new file mode 100644 index 0000000..db574aa --- /dev/null +++ b/src/cmd/smallc/lex.c @@ -0,0 +1,228 @@ +/* File lex.c: 2.1 (83/03/20,16:02:09) */ +/*% cc -O -c % + * + */ + +#include +#include "defs.h" +#include "data.h" + +/** + * test if given character is alpha + * @param c + * @return + */ +alpha(char c) { + if (c > 127) + return 0; + return (((c >= 'a') && (c <= 'z')) || + ((c >= 'A') && (c <= 'Z')) || + (c == '_')); +} + +/** + * test if given character is numeric + * @param c + * @return + */ +numeric(char c) { + if (c > 127) + return 0; + return ((c >= '0') && (c <= '9')); +} + +/** + * test if given character is alphanumeric + * @param c + * @return + */ +alphanumeric(char c) { + return ((alpha (c)) || (numeric (c))); +} + +/** + * semicolon enforcer + * called whenever syntax requires a semicolon + */ +need_semicolon() { + if (!match (";")) + error ("missing semicolon"); +} + +junk() { + if (alphanumeric (inbyte ())) + while (alphanumeric (ch ())) + gch (); + else + while (alphanumeric (ch ())) { + if (ch () == 0) + break; + gch (); + } + blanks (); +} + +endst() { + blanks (); + return ((streq (line + lptr, ";") | (ch () == 0))); +} + +/** + * enforces bracket + * @param str + * @return + */ +needbrack(char *str) { + if (!match (str)) { + error ("missing bracket"); + gen_comment (); + output_string (str); + newline (); + } +} + +/** + * + * @param str1 + * @return + */ +sstreq(str1) char *str1; { + return (streq(line + lptr, str1)); +} + +/** + * indicates whether or not the current substring in the source line matches a + * literal string + * accepts the address of the current character in the source + * line and the address of the a literal string, and returns the substring length + * if a match occurs and zero otherwise + * @param str1 address1 + * @param str2 address2 + * @return + */ +streq(char str1[], char str2[]) { + int k; + k = 0; + while (str2[k]) { + if ((str1[k] != str2[k])) + return (0); + k++; + } + return (k); +} + +/** + * compares two string both must be zero ended, otherwise no match found + * ensures that the entire token is examined + * @param str1 + * @param str2 + * @param len + * @return + */ +astreq (char str1[], char str2[], int len) { + int k; + k = 0; + while (k < len) { + if ((str1[k] != str2[k])) + break; + if (str1[k] == 0) + break; + if (str2[k] == 0) + break; + k++; + } + if (alphanumeric (str1[k])) + return (0); + if (alphanumeric (str2[k])) + return (0); + return (k); +} + +/** + * looks for a match between a literal string and the current token in + * the input line. It skips over the token and returns true if a match occurs + * otherwise it retains the current position in the input line and returns false + * there is no verification that all of the token was matched + * @param lit + * @return + */ +match (char *lit) { + int k; + blanks(); + if (k = streq (line + lptr, lit)) { + lptr = lptr + k; + return (1); + } + return (0); +} + +/** + * compares two string both must be zero ended, otherwise no match found + * advances line pointer only if match found + * it assumes that an alphanumeric (including underscore) comparison + * is being made and guarantees that all of the token in the source line is + * scanned in the process + * @param lit + * @param len + * @return + */ +amatch(char *lit, int len) { + int k; + + blanks(); + if (k = astreq (line + lptr, lit, len)) { + lptr = lptr + k; + while (alphanumeric (ch ())) + inbyte (); + return (1); + } + return (0); +} + +blanks() { + for (;;) { + while (ch () == 0) { + readline (); + if (feof (input)) + break; + } + if (ch () == ' ') + gch (); + else if (ch () == 9) + gch (); + else + return; + } +} + +/** + * returns declaration type + * @return CCHAR, CINT, UCHAR, UINT + */ +int get_type() { + if (amatch ("register", 8)) { + if (amatch("char", 4)) + return CCHAR; + else if (amatch ("int", 3)) + return CINT; + else + return CINT; + } else if(amatch("unsigned", 8)) { + if (amatch("char", 4)) { + return UCHAR; + } else if (amatch("int", 3)) { + return UINT; + } + } else if(amatch("signed", 8)) { + if (amatch("char", 4)) { + return CCHAR; + } else if (amatch("int", 3)) { + return CINT; + } + } else if (amatch ("char", 4)) { + return CCHAR; + } else if (amatch ("int", 3)) { + return CINT; + } + return 0; +} diff --git a/src/cmd/smallc/lib/Makefile b/src/cmd/smallc/lib/Makefile new file mode 100644 index 0000000..37c767a --- /dev/null +++ b/src/cmd/smallc/lib/Makefile @@ -0,0 +1,34 @@ +.SUFFIXES: .o .obj .c .asm + +.c.o: + ../src/sccvax $*.c + as -o $*.o $*.s + rm $*.s +ASSEMS =\ + abs.asm atoi.asm binary.asm\ + charclass.asm fgets.asm fputs.asm\ + getchar.asm gets.asm index.asm\ + itoa.asm printn.asm putchar.asm\ + puts.asm reverse.asm shell.asm\ + strcat.asm strcmp.asm strcpy.asm\ + strlen.asm rand.asm \ + strncat.asm strncmp.asm strncpy.asm + +OBJ =\ + abs.o atoi.o binary.o\ + charclass.o fgets.o fputs.o\ + getchar.o gets.o index.o\ + itoa.o printn.o putchar.o\ + puts.o reverse.o shell.o\ + strcat.o strcmp.o strcpy.o\ + strlen.o rand.o \ + strncat.o strncmp.o strncpy.o +.c.asm: + ../src/scc8080 $*.c + mv $*.s $*.asm + +all: $(ASSEMS) + +vaxlibc.a: $(OBJ) + ar ur vaxlibc.a $(OBJ) + ranlib vaxlibc.a diff --git a/src/cmd/smallc/lib/abs.c b/src/cmd/smallc/lib/abs.c new file mode 100644 index 0000000..9a0adfe --- /dev/null +++ b/src/cmd/smallc/lib/abs.c @@ -0,0 +1,5 @@ +/* abs (num) return absolute value */ +abs(num) int num;{ + if (num < 0) return (-num); + else return (num); + } diff --git a/src/cmd/smallc/lib/atoi.c b/src/cmd/smallc/lib/atoi.c new file mode 100644 index 0000000..265e3f2 --- /dev/null +++ b/src/cmd/smallc/lib/atoi.c @@ -0,0 +1,21 @@ +#include +#define EOL 10 +atoi(s) char s[];{ + int i,n,sign; + for (i=0; + (s[i] == ' ') | (s[i] == EOL) | (s[i] == '\t'); + ++i) ; + sign = 1; + switch(s[i]){ + case '-': sign = -1; /* and fall through */ + case '+': ++i; + break; + } + for(n = 0; + isdigit(s[i]); + ++i) + n = 10 * n + s[i] - '0'; + return (sign * n); + +} + diff --git a/src/cmd/smallc/lib/binary.c b/src/cmd/smallc/lib/binary.c new file mode 100644 index 0000000..8b6cea5 --- /dev/null +++ b/src/cmd/smallc/lib/binary.c @@ -0,0 +1,22 @@ +/* binary search for string word in table[0] .. table[n-1] + * reference CPL pg. 125 + */ +#include +binary(word, table, n) +char *word; +int table[]; +int n;{ + int low, high, mid, cond; + low = 0; + high = n - 1; + while (low <= high){ + mid = (low + high) / 2; + if ((cond = strcmp(word, table[mid])) < 0) + high = mid - 1; + else if (cond > 0) + low = mid + 1; + else + return (mid); + } + return (-1); + } diff --git a/src/cmd/smallc/lib/charclass.c b/src/cmd/smallc/lib/charclass.c new file mode 100644 index 0000000..39fb873 --- /dev/null +++ b/src/cmd/smallc/lib/charclass.c @@ -0,0 +1,33 @@ +isalpha(c) char c;{ + if ((c >= 'a' & c <= 'z') | + (c >= 'A' & c <= 'Z')) return(1); + else return(0); + } + +isupper(c) char c;{ + if (c >= 'A' & c <= 'Z') return(1); + else return(0); + } + +islower(c) char c;{ + if (c >= 'a' & c <= 'z') return(1); + else return(0); + } + +isdigit(c) char c;{ + if (c >= '0' & c <= '9') return(1); + else return(0); + } + +isspace(c) char c;{ + if (c == ' ' | c == '\t' | c == '\n') return(1); + else return(0); + } + +toupper(c) char c;{ + return ((c >= 'a' && c <= 'z') ? c - 32: c); + } + +tolower(c) char c;{ + return((c >= 'A' && c <= 'Z') ? c + 32: c); + } diff --git a/src/cmd/smallc/lib/fgets.c b/src/cmd/smallc/lib/fgets.c new file mode 100644 index 0000000..82e44d2 --- /dev/null +++ b/src/cmd/smallc/lib/fgets.c @@ -0,0 +1,27 @@ +/* +#include +*/ +#define NULL 0 +#define FILE char + +fgets(s, n, iop) +int n; +char *s; +register FILE *iop; +{ + register c; + register char *cs; + + cs = s; + while (--n>0 && (c = fgetc(iop))>=0) { + *cs++ = c; + if (c=='\n') + break; + } + if (c<0 && cs==s) + return(NULL); + *cs++ = '\0'; + return(s); + +} + diff --git a/src/cmd/smallc/lib/fputs.c b/src/cmd/smallc/lib/fputs.c new file mode 100644 index 0000000..1f916b5 --- /dev/null +++ b/src/cmd/smallc/lib/fputs.c @@ -0,0 +1,7 @@ +#include + +fputs(str, fp) FILE *fp; char *str; { + while(*str) fputc(*str++, fp); + +} + diff --git a/src/cmd/smallc/lib/getchar.c b/src/cmd/smallc/lib/getchar.c new file mode 100644 index 0000000..48fedfb --- /dev/null +++ b/src/cmd/smallc/lib/getchar.c @@ -0,0 +1,5 @@ +#include +getchar() { + return(fgetc(stdin)); +} + diff --git a/src/cmd/smallc/lib/gets.c b/src/cmd/smallc/lib/gets.c new file mode 100644 index 0000000..21385ae --- /dev/null +++ b/src/cmd/smallc/lib/gets.c @@ -0,0 +1,28 @@ +#include +#define EOL 10 +#define BKSP 8 +#define CTRLU 0x15 +gets(s) char *s; { + char c, *ts; + ts = s; + while ((c = getchar()) != EOL && (c != EOF)) { + if (c == BKSP) { + if (ts > s) { + --ts; + /* CPM already echoed */ + putchar(' '); + putchar(BKSP); + } + } + else if (c == CTRLU) { + ts = s; + putchar(EOL); + putchar('#'); + } + else (*ts++) = c; + } + if ((c == EOF) && (ts == s)) return NULL; + (*ts) = NULL; + return s; +} + diff --git a/src/cmd/smallc/lib/index.c b/src/cmd/smallc/lib/index.c new file mode 100644 index 0000000..26c7204 --- /dev/null +++ b/src/cmd/smallc/lib/index.c @@ -0,0 +1,18 @@ +/* index - find index of string t in s + * reference CPL 67. + */ +#include +#define EOS 0 +index(s, t) +char s[], t[];{ + int i, j, k; + for (i = 0; s[i] != EOS; i++){ + k=0; + for (j=i;t[k]!=EOS & s[j]==t[k]; i++) + j++; + ; + if (t[k] == EOS) + return(i); + } + return(-1); + } diff --git a/src/cmd/smallc/lib/itoa.c b/src/cmd/smallc/lib/itoa.c new file mode 100644 index 0000000..7411dd9 --- /dev/null +++ b/src/cmd/smallc/lib/itoa.c @@ -0,0 +1,14 @@ +#include +#define EOS 0 +itoa(n,s) char s[];int n;{ + int i,sign; + if((sign = n) < 0) n = -n; + i = 0; + do { + s[i++] = n % 10 + '0'; + }while ((n = n/10) > 0); + if (sign < 0) s[i++] = '-'; + s[i] = EOS; + reverse(s); +} + diff --git a/src/cmd/smallc/lib/lorder8080 b/src/cmd/smallc/lib/lorder8080 new file mode 100644 index 0000000..e36c585 --- /dev/null +++ b/src/cmd/smallc/lib/lorder8080 @@ -0,0 +1,12 @@ +grep public $* | sed 's/: public// +/?/d +s?\([^ ]*\)[ ]*\(.*\)?\2 \1? +s/\.asm//'> /tmp/symdef$$ +grep extrn $* | sed 's/: extrn// +s/\.asm// +s?\([^ ]*\)[ ]*\(.*\)?\2 \1? +/?/d' > /tmp/symref$$ +sort /tmp/symdef$$ -o /tmp/symdef$$ +sort /tmp/symref$$ -o /tmp/symref$$ +join /tmp/symref$$ /tmp/symdef$$ | sed 's/[^ ]* *//' +rm /tmp/symdef$$ /tmp/symref$$ diff --git a/src/cmd/smallc/lib/printn.c b/src/cmd/smallc/lib/printn.c new file mode 100644 index 0000000..be26340 --- /dev/null +++ b/src/cmd/smallc/lib/printn.c @@ -0,0 +1,16 @@ +#include +/* print a number in any radish */ +#define DIGARR "0123456789ABCDEF" +printn(number, radix, file) +int number, radix; FILE *file;{ + int i; + char *digitreps; + if (number < 0 & radix == 10){ + fputc('-', file); + number = -number; + } + if ((i = number / radix) != 0) + printn(i, radix, file); + digitreps=DIGARR; + fputc(digitreps[number % radix], file); + } diff --git a/src/cmd/smallc/lib/putchar.c b/src/cmd/smallc/lib/putchar.c new file mode 100644 index 0000000..a96a6e3 --- /dev/null +++ b/src/cmd/smallc/lib/putchar.c @@ -0,0 +1,5 @@ +#include +putchar(c) char c; { + return fputc(c, stdout); +} + diff --git a/src/cmd/smallc/lib/puts.c b/src/cmd/smallc/lib/puts.c new file mode 100644 index 0000000..7d5511f --- /dev/null +++ b/src/cmd/smallc/lib/puts.c @@ -0,0 +1,6 @@ +#include +#define EOL 10 +puts(str) char *str;{ + while (*str) putchar(*str++); + putchar(EOL); + } diff --git a/src/cmd/smallc/lib/rand.c b/src/cmd/smallc/lib/rand.c new file mode 100644 index 0000000..97112d1 --- /dev/null +++ b/src/cmd/smallc/lib/rand.c @@ -0,0 +1,20 @@ + +int xxseed; + +srand (x) int x; { + xxseed = x; + +} + +rand () { + xxseed = xxseed * 251 + 123; + if (xxseed < 0) xxseed = - xxseed; + return (xxseed); + +} + +getrand () { + puts ("Type a character"); + return (getchar() * 123); +} + diff --git a/src/cmd/smallc/lib/reverse.c b/src/cmd/smallc/lib/reverse.c new file mode 100644 index 0000000..c77151a --- /dev/null +++ b/src/cmd/smallc/lib/reverse.c @@ -0,0 +1,17 @@ +#include +/* Reverse a character string, reference CPL p 59 */ +reverse(s) +char *s;{ + int i, j; + char c; + i = 0; + j = strlen(s) - 1; + while (i < j){ + c = s[i]; + s[i] = s[j]; + s[j] = c; + i++; + j--; + } + return(s); + } diff --git a/src/cmd/smallc/lib/sbrk.c b/src/cmd/smallc/lib/sbrk.c new file mode 100644 index 0000000..65ea2fc --- /dev/null +++ b/src/cmd/smallc/lib/sbrk.c @@ -0,0 +1,17 @@ +extern char *brkend; +sbrk (incr) char *incr; { + char *stktop; + + stktop = Xstktop() - 200; + + /* do we have enough space? */ + if (brkend + incr < stktop) { + stktop = brkend; + brkend = brkend + incr; + return (stktop); + } + else + return (-1); + +} + diff --git a/src/cmd/smallc/lib/shell.c b/src/cmd/smallc/lib/shell.c new file mode 100644 index 0000000..13ad456 --- /dev/null +++ b/src/cmd/smallc/lib/shell.c @@ -0,0 +1,21 @@ +/* Shell sort of string v[0] .... v[n-1] into increasing + * order. + * Reference CPL pg. 108. + */ + +shellsort(v, n) +int v[]; +int n; + { + int gap, i, j; + char *temp; + for (gap = n/2; gap > 0; gap = gap / 2) + for (i = gap; i < n; i++) + for (j = i - gap; j >= 0; j = j - gap){ + if (strcmp(v[j], v[j+gap]) <= 0) + break; + temp = v[j]; + v[j] = v[j + gap]; + v[j + gap] = temp; + } + } diff --git a/src/cmd/smallc/lib/strcat.c b/src/cmd/smallc/lib/strcat.c new file mode 100644 index 0000000..811667e --- /dev/null +++ b/src/cmd/smallc/lib/strcat.c @@ -0,0 +1,20 @@ +/* + * Concatenate s2 on the end of s1. S1's space must be large enough. + * Return s1. + */ + +strcat(s1, s2) +char *s1, *s2; +{ + char *os1; + + os1 = s1; + while (*s1++) + ; + *--s1; + while (*s1++ = *s2++) + ; + return(os1); + +} + diff --git a/src/cmd/smallc/lib/strcmp.c b/src/cmd/smallc/lib/strcmp.c new file mode 100644 index 0000000..d543d39 --- /dev/null +++ b/src/cmd/smallc/lib/strcmp.c @@ -0,0 +1,13 @@ +/* + * Compare strings: s1>s2: >0 s1==s2: 0 s1 +/* + * Copy string s2 to s1. s1 must be large enough. + * return s1 + */ + +strcpy(s1, s2) +char *s1, *s2; +{ + char *os1; + + os1 = s1; + while (*s1++ = *s2++) + ; + return(os1); + +} + diff --git a/src/cmd/smallc/lib/strlen.c b/src/cmd/smallc/lib/strlen.c new file mode 100644 index 0000000..e3bd9d4 --- /dev/null +++ b/src/cmd/smallc/lib/strlen.c @@ -0,0 +1,8 @@ +#include +/* return length of string, reference CPL p 36 */ +strlen(s) char *s;{ + int i; + i = 0; + while (*s++) i++; + return (i); + } diff --git a/src/cmd/smallc/lib/strncat.c b/src/cmd/smallc/lib/strncat.c new file mode 100644 index 0000000..c166216 --- /dev/null +++ b/src/cmd/smallc/lib/strncat.c @@ -0,0 +1,25 @@ +/* + * Concatenate s2 on the end of s1. S1's space must be large enough. + * At most n characters are moved. + * Return s1. + */ + +strncat(s1, s2, n) +register char *s1, *s2; +register n; +{ + register char *os1; + + os1 = s1; + while (*s1++) + ; + --s1; + while (*s1++ = *s2++) + if (--n < 0) { + *--s1 = '\0'; + break; + } + return(os1); + +} + diff --git a/src/cmd/smallc/lib/strncmp.c b/src/cmd/smallc/lib/strncmp.c new file mode 100644 index 0000000..bdd5a30 --- /dev/null +++ b/src/cmd/smallc/lib/strncmp.c @@ -0,0 +1,16 @@ +/* + * Compare strings (at most n bytes): s1>s2: >0 s1==s2: 0 s1= 0 && *s1 == *s2++) + if (*s1++ == '\0') + return(0); + return(n<0 ? 0 : *s1 - *--s2); + +} + diff --git a/src/cmd/smallc/lib/strncpy.c b/src/cmd/smallc/lib/strncpy.c new file mode 100644 index 0000000..e14cd4c --- /dev/null +++ b/src/cmd/smallc/lib/strncpy.c @@ -0,0 +1,23 @@ +/* + * Copy s2 to s1, truncating or null-padding to always copy n bytes + * return s1 + */ + +strncpy(s1, s2, n) +char *s1, *s2; +int n; +{ + register i; + register char *os1; + + os1 = s1; + for (i = 0; i < n; i++) + if ((*s1++ = *s2++) == '\0') { + while (++i < n) + *s1++ = '\0'; + return(os1); + } + return(os1); + +} + diff --git a/src/cmd/smallc/main.c b/src/cmd/smallc/main.c new file mode 100644 index 0000000..bb467a9 --- /dev/null +++ b/src/cmd/smallc/main.c @@ -0,0 +1,314 @@ +/* + * File main.c: 2.7 (84/11/28,10:14:56) + */ + +#include +#include +#include +#include "defs.h" +#include "data.h" + +main(int argc, char *argv[]) +{ + char *param = NULL; + char *infile = NULL; + char *outfile = NULL; + int i; + ctext = 0; + errs = 0; + for (i=1; i= litptr)) { + newline(); + break; + } + output_byte(','); + } + } +} + +/** + * dump all static variables + */ +dumpglbs() +{ + int dim, i, list_size, line_count, value; + + if (!glbflag) + return; + current_symbol_table_idx = rglobal_table_index; + while (current_symbol_table_idx < global_table_index) { + symbol_t *symbol = &symbol_table[current_symbol_table_idx]; + if (symbol->identity != FUNCTION) { + ppubext(symbol); + if (symbol->storage != EXTERN) { + if ((symbol->type & CINT) || (symbol->identity == POINTER)) + gen_align_word(); + output_string(symbol->name); + output_label_terminator(); + dim = symbol->offset; + list_size = 0; + line_count = 0; + if (find_symbol(symbol->name)) { // has initials + list_size = get_size(symbol->name); + if (dim == -1) { + dim = list_size; + } + } + for (i=0; itype & CINT) || (symbol->identity == POINTER)) { + gen_def_word(); + } else { + gen_def_byte(); + } + } + if (i < list_size) { + // dump data + value = get_item_at(symbol->name, i); + output_number(value); + } else { + // dump zero, no more data available + output_number(0); + } + line_count++; + if (line_count % 10 == 0) { + line_count = 0; + } else { + if (i < dim-1) { + output_byte( ',' ); + } + } + } + newline(); + } + } else { + fpubext(symbol); + } + current_symbol_table_idx++; + } +} + +/* + * report errors + */ +errorsummary() +{ + if (ncmp) + error("missing closing bracket"); + gen_comment(); + newline(); + gen_comment(); + output_with_tab(""); + output_decimal(errcnt); + if (errcnt) errfile = YES; + output_string(" error(s) in compilation"); + newline(); + gen_comment(); + output_with_tab("literal pool: "); + output_decimal(litptr); + newline(); + gen_comment(); + output_with_tab("global pool: "); + output_decimal(global_table_index - rglobal_table_index); + newline(); + if (errcnt > 0) + printf("Compilation failed: %d error(s)\n", errcnt); +} diff --git a/src/cmd/smallc/preproc.c b/src/cmd/smallc/preproc.c new file mode 100644 index 0000000..4c834fe --- /dev/null +++ b/src/cmd/smallc/preproc.c @@ -0,0 +1,291 @@ +/* File preproc.c: 2.3 (84/11/27,11:47:40) */ +/*% cc -O -c % + * + */ + +#include +#include +#include "defs.h" +#include "data.h" + +dodefine () +{ + addmac(); +} + +doundef () +{ + int mp; + char sname[NAMESIZE]; + + if (!symname(sname)) { + illname(); + kill(); + return; + } + + if (mp = findmac(sname)) + delmac(mp); + kill(); + +} + +preprocess () +{ + if (ifline()) return; + while (cpp()); +} + +doifdef (ifdef) +int ifdef; +{ + char sname[NAMESIZE]; + int k; + + blanks(); + ++iflevel; + if (skiplevel) return; + k = symname(sname) && findmac(sname); + if (k != ifdef) skiplevel = iflevel; + +} + +ifline() +{ + for (;;) { + readline(); + if (feof(input)) return(1); + if (match("#ifdef")) { + doifdef(YES); + continue; + } else if (match("#ifndef")) { + doifdef(NO); + continue; + } else if (match("#else")) { + if (iflevel) { + if (skiplevel == iflevel) skiplevel = 0; + else if (skiplevel == 0) skiplevel = iflevel; + } else noiferr(); + continue; + } else if (match("#endif")) { + if (iflevel) { + if (skiplevel == iflevel) skiplevel = 0; + --iflevel; + } else noiferr(); + continue; + } + if (!skiplevel) return(0); + } +} + +noiferr() +{ + error("no matching #if..."); +} + +/** + * preprocess - copies mline to line with special treatment of preprocess cmds + * @return + */ +cpp () +{ + int k; + char c, sname[NAMESIZE]; + int tog; + int cpped; /* non-zero if something expanded */ + + cpped = 0; + /* don't expand lines with preprocessor commands in them */ + if (!cmode || line[0] == '#') return(0); + + mptr = lptr = 0; + while (ch ()) { + if ((ch () == ' ') | (ch () == 9)) { + keepch (' '); + while ((ch () == ' ') | (ch () == 9)) + gch (); + } else if (ch () == '"') { + keepch (ch ()); + gch (); + while (ch () != '"') { + if (ch () == 0) { + error ("missing quote"); + break; + } + if (ch() == '\\') keepch(gch()); + keepch (gch ()); + } + gch (); + keepch ('"'); + } else if (ch () == '\'') { + keepch ('\''); + gch (); + while (ch () != '\'') { + if (ch () == 0) { + error ("missing apostrophe"); + break; + } + if (ch() == '\\') keepch(gch()); + keepch (gch ()); + } + gch (); + keepch ('\''); + } else if ((ch () == '/') & (nch () == '*')) { + inchar (); + inchar (); + while ((((c = ch ()) == '*') & (nch () == '/')) == 0) + if (c == '$') { + inchar (); + tog = TRUE; + if (ch () == '-') { + tog = FALSE; + inchar (); + } + if (alpha (c = ch ())) { + inchar (); + toggle (c, tog); + } + } else { + if (ch () == 0) + readline (); + else + inchar (); + if (feof (input)) + break; + } + inchar (); + inchar (); + } else if ((ch () == '/') & (nch () == '/')) { // one line comment + while(gch()); + } else if (alphanumeric(ch ())) { + k = 0; + while (alphanumeric(ch ())) { + if (k < NAMEMAX) + sname[k++] = ch (); + gch (); + } + sname[k] = 0; + if (k = findmac (sname)) { + cpped = 1; + while (c = macq[k++]) + keepch (c); + } else { + k = 0; + while (c = sname[k++]) + keepch (c); + } + } else + keepch (gch ()); + } + keepch (0); + if (mptr >= MPMAX) + error ("line too long"); + lptr = mptr = 0; + while (line[lptr++] = mline[mptr++]); + lptr = 0; + return(cpped); + +} + +keepch (c) +char c; +{ + mline[mptr] = c; + if (mptr < MPMAX) + mptr++; + return (c); + +} + +defmac(s) +char *s; +{ + kill(); + strcpy(line, s); + addmac(); +} + +addmac () +{ + char sname[NAMESIZE]; + int k; + int mp; + + if (!symname (sname)) { + illname (); + kill (); + return; + } + if (mp = findmac(sname)) { + error("Duplicate define"); + delmac(mp); + } + k = 0; + while (putmac (sname[k++])); + while (ch () == ' ' | ch () == 9) + gch (); + //while (putmac (gch ())); + while (putmac(remove_one_line_comment(gch ()))); + if (macptr >= MACMAX) + error ("macro table full"); + +} + +/** + * removes one line comments from defines + * @param c + * @return + */ +remove_one_line_comment(c) char c; { + if ((c == '/') && (ch() == '/')) { + while(gch()); + return 0; + } else { + return c; + } +} + +delmac(mp) int mp; { + --mp; --mp; /* step over previous null */ + while (mp >= 0 && macq[mp]) macq[mp--] = '%'; + +} + +putmac (c) +char c; +{ + macq[macptr] = c; + if (macptr < MACMAX) + macptr++; + return (c); + +} + +findmac (sname) +char *sname; +{ + int k; + + k = 0; + while (k < macptr) { + if (astreq (sname, macq + k, NAMEMAX)) { + while (macq[k++]); + return (k); + } + while (macq[k++]); + while (macq[k++]); + } + return (0); + +} + +toggle (name, onoff) +char name; +int onoff; +{ + switch (name) { + case 'C': + ctext = onoff; + break; + } +} diff --git a/src/cmd/smallc/primary.c b/src/cmd/smallc/primary.c new file mode 100644 index 0000000..587b908 --- /dev/null +++ b/src/cmd/smallc/primary.c @@ -0,0 +1,332 @@ +/* + * File primary.c: 2.4 (84/11/27,16:26:07) + */ +#include +#include "defs.h" +#include "data.h" + +primary (lvalue_t *lval) +{ + char sname[NAMESIZE]; + int num[1], k, symbol_table_idx, offset, reg; + symbol_t *symbol; + + lval->ptr_type = 0; /* clear pointer/array type */ + if (match ("(")) { + k = hier1 (lval); + needbrack (")"); + return (k); + } + if (amatch("sizeof", 6)) { + needbrack("("); + gen_immediate_c(); + if (amatch("int", 3)) output_number(INTSIZE); + else if (amatch("char", 4)) output_number(1); + else if (symname(sname)) { + if ((symbol_table_idx = findloc(sname)) || + (symbol_table_idx = findglb(sname))) { + symbol = &symbol_table[symbol_table_idx]; + if (symbol->storage == LSTATIC) + error("sizeof local static"); + offset = symbol->count; + if ((symbol->type & CINT) || + (symbol->identity == POINTER)) + offset *= INTSIZE; + output_number(offset); + } else { + error("sizeof undeclared variable"); + output_number(0); + } + } else { + error("sizeof only on simple type or variable"); + } + needbrack(")"); + newline(); + lval->symbol = 0; + lval->indirect = 0; + return(0); + } + if (symname (sname)) { + if (symbol_table_idx = findloc (sname)) { + symbol = &symbol_table[symbol_table_idx]; + reg = gen_get_location (symbol); + lval->symbol = symbol; + lval->indirect = symbol->type; + if (symbol->identity == ARRAY) { + //lval->ptr_type = symbol->type; + lval->ptr_type = 0; + return 0; + } + if (symbol->identity == POINTER) { + lval->indirect = UINT; + lval->ptr_type = symbol->type; + } + return reg; + } + if (symbol_table_idx = findglb (sname)) { + symbol = &symbol_table[symbol_table_idx]; + lval->symbol = symbol; + switch (symbol->identity) { + case ARRAY: + gen_immediate_a (); + output_string (symbol->name); + newline (); + /* Fall through */ + case FUNCTION: + lval->indirect = lval->ptr_type = symbol_table[symbol_table_idx].type; + lval->ptr_type = 0; + return 0; + default: + lval->indirect = 0; + if (symbol->identity == POINTER) { + lval->ptr_type = symbol->type; + } + return 1; + } + } + blanks (); + if (ch() != '(') + error("undeclared variable"); + symbol_table_idx = add_global (sname, FUNCTION, CINT, 0, PUBLIC, 1); + symbol = &symbol_table[symbol_table_idx]; + lval->symbol = symbol; + lval->indirect = 0; + return 0; + } + if (constant (num)) { + lval->symbol = 0; + lval->indirect = 0; + return 0; + } + error ("invalid expression"); + gen_immediate_c (); + output_number(0); + newline (); + junk (); + return 0; +} + +/** + * true if val1 -> int pointer or int array and val2 not pointer or array + * @param val1 + * @param val2 + * @return + */ +dbltest (lvalue_t *val1, lvalue_t *val2) +{ + if (val1 == NULL) + return (FALSE); + if (!(val1->ptr_type & CINT)) + return (FALSE); + if (val2->ptr_type) + return (FALSE); + return (TRUE); +} + +/** + * determine type of binary operation + * @param lval + * @param lval2 + * @return + */ +result (lvalue_t *lval, lvalue_t *lval2) +{ + if (lval->ptr_type && lval2->ptr_type) + lval->ptr_type = 0; + else if (lval2->ptr_type) { + lval->symbol = lval2->symbol; + lval->indirect = lval2->indirect; + lval->ptr_type = lval2->ptr_type; + } +} + +constant (val) + int val[]; +{ + if (number (val)) + gen_immediate_c (); + else if (quoted_char (val)) + gen_immediate_c (); + else if (quoted_string (val)) { + gen_immediate_a (); + print_label (litlab); + output_byte ('+'); + } else + return (0); + output_number (val[0]); + newline (); + return (1); + +} + +number (val) + int val[]; +{ + int k, minus, base; + char c; + + k = minus = 1; + while (k) { + k = 0; + if (match ("+")) + k = 1; + if (match ("-")) { + minus = (-minus); + k = 1; + } + } + if (!numeric (c = ch ())) + return (0); + if (match ("0x") || match ("0X")) + while (numeric (c = ch ()) || + (c >= 'a' && c <= 'f') || + (c >= 'A' && c <= 'F')) { + inbyte (); + k = k * 16 + + (numeric (c) ? (c - '0') : ((c & 07) + 9)); + } + else { + base = (c == '0') ? 8 : 10; + while (numeric (ch ())) { + c = inbyte (); + k = k * base + (c - '0'); + } + } + if (minus < 0) + k = (-k); + val[0] = k; + if(k < 0) { + return (UINT); + } else { + return (CINT); + } +} + +/** + * Test if we have one char enclosed in single quotes + * @param value returns the char found + * @return 1 if we have, 0 otherwise + */ +quoted_char (int *value) +{ + int k; + char c; + + k = 0; + if (!match ("'")) + return (0); + while ((c = gch ()) != '\'') { + c = (c == '\\') ? spechar(): c; + k = (k & 255) << 8 | (c & 255); + } + *value = k; + return (1); +} + +/** + * Test if we have string enclosed in double quotes. e.g. "abc". + * Load the string into literal pool. + * @param position returns beginning of the string + * @return 1 if such string found, 0 otherwise + */ +quoted_string (int *position) +{ + char c; + + if (!match ("\"")) + return (0); + *position = litptr; + while (ch () != '"') { + if (ch () == 0) + break; + if (litptr >= LITMAX) { + error ("string space exhausted"); + while (!match ("\"")) + if (gch () == 0) + break; + return (1); + } + c = gch(); + litq[litptr++] = (c == '\\') ? spechar(): c; + } + gch (); + litq[litptr++] = 0; + return (1); +} + +/** + * decode special characters (preceeded by back slashes) + */ +spechar() +{ + char c; + c = ch(); + + if (c == EOS) return 0; + else if (c == 'n') c = LF; + else if (c == 't') c = TAB; + else if (c == 'r') c = CR; + else if (c == 'f') c = FFEED; + else if (c == 'b') c = BKSP; + else if (c >= '0' && c <= '7') { + int n = c - '0'; + gch(); + c = ch(); + if (c < '0' || c > '7') + return n; + n = (n << 3) + c - '0'; + gch(); + c = ch(); + if (c < '0' || c > '7') + return n; + n = (n << 3) + c - '0'; + gch(); + return n; + } + gch(); + return c; +} + +/** + * perform a function call + * called from "hier11", this routine will either call the named + * function, or if the supplied ptr is zero, will call the contents + * of HL + * @param ptr name of the function + */ +void callfunction (ptr) + char *ptr; +{ + int nargs; + + nargs = 0; + blanks (); + if (ptr == 0) + gen_push (HL_REG); + while (!streq (line + lptr, ")")) { + if (endst ()) + break; + expression (NO); + if (ptr == 0) + gen_swap_stack (); + gen_push (HL_REG); + nargs = nargs + INTSIZE; + if (!match (",")) + break; + } + needbrack (")"); + // Generate an argument count to function calls. + // This feature is arch-specific, disable it for now. + // if (aflag) + gnargs(nargs / INTSIZE); + if (ptr) + gen_call (ptr); + else + callstk (); + stkp = gen_modify_stack (stkp + nargs); +} + +needlval () +{ + error ("must be lvalue"); +} diff --git a/src/cmd/smallc/stmt.c b/src/cmd/smallc/stmt.c new file mode 100644 index 0000000..c3292c7 --- /dev/null +++ b/src/cmd/smallc/stmt.c @@ -0,0 +1,406 @@ +/* + * File stmt.c: 2.1 (83/03/20,16:02:17) + */ + +#include +#include "defs.h" +#include "data.h" + +/** + * statement parser + * called whenever syntax requires a statement. this routine + * performs that statement and returns a number telling which one + * @param func func is true if we require a "function_statement", which + * must be compound, and must contain "statement_list" (even if + * "declaration_list" is omitted) + * @return statement type + */ +statement (int func) { + if ((ch () == 0) & feof (input)) + return (0); + lastst = 0; + if (func) + if (match ("{")) { + do_compound (YES); + return (lastst); + } else + error ("function requires compound statement"); + if (match ("{")) + do_compound (NO); + else + do_statement (); + return (lastst); +} + +/** + * declaration + */ +statement_declare() { + if (amatch("register", 8)) + do_local_declares(DEFAUTO); + else if (amatch("auto", 4)) + do_local_declares(DEFAUTO); + else if (amatch("static", 6)) + do_local_declares(LSTATIC); + else if (do_local_declares(AUTO)) ; + else + return (NO); + return (YES); +} + +/** + * local declarations + * @param stclass + * @return + */ +do_local_declares(int stclass) { + int type = 0; + blanks(); + if (type = get_type()) { + declare_local(type, stclass); + } else if (stclass == LSTATIC || stclass == DEFAUTO) { + declare_local(CINT, stclass); + } else { + return(0); + } + need_semicolon(); + return(1); +} + +/** + * non-declaration statement + */ +do_statement () { + if (amatch ("if", 2)) { + doif (); + lastst = STIF; + } else if (amatch ("while", 5)) { + dowhile (); + lastst = STWHILE; + } else if (amatch ("switch", 6)) { + doswitch (); + lastst = STSWITCH; + } else if (amatch ("do", 2)) { + dodo (); + need_semicolon (); + lastst = STDO; + } else if (amatch ("for", 3)) { + dofor (); + lastst = STFOR; + } else if (amatch ("return", 6)) { + doreturn (); + need_semicolon (); + lastst = STRETURN; + } else if (amatch ("break", 5)) { + dobreak (); + need_semicolon (); + lastst = STBREAK; + } else if (amatch ("continue", 8)) { + docont (); + need_semicolon (); + lastst = STCONT; + } else if (match (";")) + ; + else if (amatch ("case", 4)) { + docase (); + lastst = statement (NO); + } else if (amatch ("default", 7)) { + dodefault (); + lastst = statement (NO); + } else if (match ("__asm__")) { + doasm (); + lastst = STASM; + } else if (match("#")) { + kill(); + } else if (match ("{")) + do_compound (NO); + else { + expression (YES); +/* if (match (":")) { + dolabel (); + lastst = statement (NO); + } else { +*/ need_semicolon (); + lastst = STEXP; +/* } +*/ } +} + +/** + * compound statement + * allow any number of statements to fall between "{" and "}" + * 'func' is true if we are in a "function_statement", which + * must contain "statement_list" + */ +do_compound(int func) { + int decls; + + decls = YES; + ncmp++; + while (!match ("}")) { + if (feof (input)) + return; + if (decls) { + if (!statement_declare ()) + decls = NO; + } else + do_statement (); + } + ncmp--; +} + +/** + * "if" statement + */ +doif() { + int fstkp, flab1, flab2; + int flev; + + flev = local_table_index; + fstkp = stkp; + flab1 = getlabel (); + test (flab1, FALSE); + statement (NO); + stkp = gen_modify_stack (fstkp); + local_table_index = flev; + if (!amatch ("else", 4)) { + generate_label (flab1); + return; + } + gen_jump (flab2 = getlabel ()); + generate_label (flab1); + statement (NO); + stkp = gen_modify_stack (fstkp); + local_table_index = flev; + generate_label (flab2); +} + +/** + * "while" statement + */ +dowhile() { + loop_t loop; + + loop.symbol_idx = local_table_index; + loop.stack_pointer = stkp; + loop.type = WSWHILE; + loop.test_label = getlabel (); + loop.exit_label = getlabel (); + addloop (&loop); + generate_label (loop.test_label); + test (loop.exit_label, FALSE); + statement (NO); + gen_jump (loop.test_label); + generate_label (loop.exit_label); + local_table_index = loop.symbol_idx; + stkp = gen_modify_stack (loop.stack_pointer); + delloop (); +} + +/** + * "do" statement + */ +dodo() { + loop_t loop; + + loop.symbol_idx = local_table_index; + loop.stack_pointer = stkp; + loop.type = WSDO; + loop.body_label = getlabel (); + loop.test_label = getlabel (); + loop.exit_label = getlabel (); + addloop (&loop); + generate_label (loop.body_label); + statement (NO); + if (!match ("while")) { + error ("missing while"); + return; + } + generate_label (loop.test_label); + test (loop.body_label, TRUE); + generate_label (loop.exit_label); + local_table_index = loop.symbol_idx; + stkp = gen_modify_stack (loop.stack_pointer); + delloop (); +} + +/** + * "for" statement + */ +dofor() { + loop_t loop; + loop_t *p; + + loop.symbol_idx = local_table_index; + loop.stack_pointer = stkp; + loop.type = WSFOR; + loop.test_label = getlabel (); + loop.cont_label = getlabel (); + loop.body_label = getlabel (); + loop.exit_label = getlabel (); + addloop (&loop); + p = readloop (); + needbrack ("("); + if (!match (";")) { + expression (YES); + need_semicolon (); + } + generate_label (p->test_label); + if (!match (";")) { + expression (YES); + gen_test_jump (p->body_label, TRUE); + gen_jump (p->exit_label); + need_semicolon (); + } else + p->test_label = p->body_label; + generate_label (p->cont_label); + if (!match (")")) { + expression (YES); + needbrack (")"); + gen_jump (p->test_label); + } else + p->cont_label = p->test_label; + generate_label (p->body_label); + statement (NO); + gen_jump (p->cont_label); + generate_label (p->exit_label); + local_table_index = p->symbol_idx; + stkp = gen_modify_stack (p->stack_pointer); + delloop (); +} + +/** + * "switch" statement + */ +doswitch() { + loop_t loop; + loop_t *ptr; + + loop.symbol_idx = local_table_index; + loop.stack_pointer = stkp; + loop.type = WSSWITCH; + loop.test_label = swstp; + loop.body_label = getlabel (); + loop.cont_label = loop.exit_label = getlabel (); + addloop (&loop); + gen_immediate_a (); + print_label (loop.body_label); + newline (); + gen_push (); + needbrack ("("); + expression (YES); + needbrack (")"); + stkp = stkp + INTSIZE; // '?case' will adjust the stack + gen_jump_case (); + statement (NO); + ptr = readswitch (); + gen_jump (ptr->exit_label); + dumpsw (ptr); + generate_label (ptr->exit_label); + local_table_index = ptr->symbol_idx; + stkp = gen_modify_stack (ptr->stack_pointer); + swstp = ptr->test_label; + delloop (); +} + +/** + * "case" label + */ +docase() { + int val; + + val = 0; + if (readswitch ()) { + if (!number (&val)) + if (!quoted_char (&val)) + error ("bad case label"); + addcase (val); + if (!match (":")) + error ("missing colon"); + } else + error ("no active switch"); +} + +/** + * "default" label + */ +dodefault() { + loop_t *ptr; + int lab; + + if (ptr = readswitch ()) { + ptr->cont_label = lab = getlabel (); + generate_label (lab); + if (!match (":")) + error ("missing colon"); + } else + error ("no active switch"); +} + +/** + * "return" statement + */ +doreturn() { + if (endst () == 0) + expression (YES); + gen_jump(fexitlab); +} + +/** + * "break" statement + */ +dobreak() { + loop_t *ptr; + + if ((ptr = readloop ()) == 0) + return; + gen_modify_stack (ptr->stack_pointer); + gen_jump (ptr->exit_label); +} + +/** + * "continue" statement + */ +docont() { + loop_t *ptr; + + if ((ptr = findloop ()) == 0) + return; + gen_modify_stack (ptr->stack_pointer); + if (ptr->type == WSFOR) + gen_jump (ptr->cont_label); + else + gen_jump (ptr->test_label); +} + +/** + * dump switch table + */ +dumpsw(loop_t *loop) { + int i,j; + + data_segment_gdata (); + generate_label (loop->body_label); + if (loop->test_label != swstp) { + j = loop->test_label; + while (j < swstp) { + gen_def_word (); + i = 4; + while (i--) { + output_number (swstcase[j]); + output_byte (','); + print_label (swstlab[j++]); + if ((i == 0) | (j >= swstp)) { + newline (); + break; + } + output_byte (','); + } + } + } + gen_def_word (); + print_label (loop->cont_label); + output_string (",0"); + newline (); + code_segment_gtext (); +} diff --git a/src/cmd/smallc/sym.c b/src/cmd/smallc/sym.c new file mode 100644 index 0000000..f6e89cb --- /dev/null +++ b/src/cmd/smallc/sym.c @@ -0,0 +1,345 @@ +/* + * File sym.c: 2.1 (83/03/20,16:02:19) + */ + +#include +#include "defs.h" +#include "data.h" + +#define LOCALOFFSET 16 /* for MIPS32 */ + +/** + * declare a static variable + * @param type + * @param storage + * @return + */ +declare_global(int type, int storage) { + int k, j, count; + char sname[NAMESIZE]; + + for (;;) { + for (;;) { + if (endst ()) + return; + k = 1; + if (match ("*")) + j = POINTER; + else + j = VARIABLE; + if (!symname (sname)) + illname (); + if (findglb (sname)) + multidef (sname); + count = 1; + if (match ("[")) { + k = needsub (); + count = k; + //if (k || storage == EXTERN) + j = ARRAY; + //else + // j = POINTER; + } + j = initials(sname, type, j, k); + add_global (sname, j, type, (k == 0 ? -1 : k), storage, count); + break; + } + if (!match (",")) + return; + } +} + +/** + * declare local variables + * works just like "declglb", but modifies machine stack and adds + * symbol table entry with appropriate stack offset to find it again + * @param typ + * @param stclass + */ +declare_local (typ, stclass) +int typ, stclass; +{ + int k, j, count; + char sname[NAMESIZE]; + + for (;;) { + for (;;) { + if (endst ()) + return; + if (match ("*")) + j = POINTER; + else + j = VARIABLE; + if (!symname (sname)) + illname (); + if (findloc (sname)) + multidef (sname); + count = 1; + if (match ("[")) { + k = needsub (); + count = k; + if (k) { + j = ARRAY; + if (typ & CINT) + k = k * INTSIZE; + } else { + j = POINTER; + k = INTSIZE; + } + } else + if ((typ & CCHAR) && (j != POINTER)) + k = 1; + else + k = INTSIZE; + if (stclass != LSTATIC) { + k = galign(k); + stkp = gen_modify_stack (stkp - k); + add_local (sname, j, typ, stkp + LOCALOFFSET, AUTO, count); + } else + add_local( sname, j, typ, k, LSTATIC, count); + break; + } + if (!match (",")) + return; + } +} + +/** + * initialize global objects + * @param symbol_name + * @param size char 1 or integer 2 + * @param identity + * @param dim + * @return 1 if variable is initialized + */ +int initials(char *symbol_name, int size, int identity, int dim) { + int dim_unknown = 0; + litptr = 0; + if(dim == 0) { // allow for xx[] = {..}; declaration + dim_unknown = 1; + } + if (!(size & CCHAR) && !(size & CINT)) { + error("unsupported storage size"); + } + if(match("=")) { + // an array + if(match("{")) { + while((dim > 0) || (dim_unknown)) { + if (init(symbol_name, size, identity, &dim) && dim_unknown) { + dim_unknown++; + } + if(match(",") == 0) { + break; + } + } + needbrack("}"); + if(--dim_unknown == 0) + identity = POINTER; + // single constant + } else { + init(symbol_name, size, identity, &dim); + } + } + return identity; +} + +/** + * evaluate one initializer, add data to table + * @param size + * @param ident + * @param dim + * @return + */ +init(char *symbol_name, int size, int ident, int *dim) { + int value, number_of_chars; + if(ident == POINTER) { + error("cannot assign to pointer"); + } + if(quoted_string(&value)) { + if((ident == VARIABLE) || (size != 1)) + error("found string: must assign to char pointer or array"); + number_of_chars = litptr - value; + *dim = *dim - number_of_chars; + while (number_of_chars > 0) { + add_data(symbol_name, CCHAR, litq[value++]); + number_of_chars = number_of_chars - 1; + } + } else if (number(&value)) { + add_data(symbol_name, CINT, value); + *dim = *dim - 1; + } else if(quoted_char(&value)) { + add_data(symbol_name, CCHAR, value); + *dim = *dim - 1; + } else { + return 0; + } + return 1; +} + +/** + * get required array size. [xx] + * @return array size + */ +needsub () { + int num[1]; + + if (match ("]")) + return (0); + if (!number (num)) { + error ("must be constant"); + num[0] = 1; + } + if (num[0] < 0) { + error ("negative size illegal"); + num[0] = (-num[0]); + } + needbrack ("]"); + return (num[0]); +} + +/** + * search global table for given symbol name + * @param sname + * @return table index + */ +int findglb (char *sname) { + int idx; + + idx = 1; + while (idx < global_table_index) { + if (astreq (sname, symbol_table[idx].name, NAMEMAX)) + return (idx); + idx++; + } + return (0); +} + +/** + * search local table for given symbol name + * @param sname + * @return table index + */ +int findloc (char *sname) { + int idx; + + idx = local_table_index; + while (idx >= NUMBER_OF_GLOBALS) { + idx--; + if (astreq (sname, symbol_table[idx].name, NAMEMAX)) + return (idx); + } + return (0); +} + +/** + * add new symbol to global table + * @param sname + * @param identity + * @param type + * @param value + * @param storage + * @return new index + */ +int add_global (char *sname, int identity, int type, int offset, int storage, int count) +{ + symbol_t *symbol; + char *buffer_ptr; + + current_symbol_table_idx = findglb (sname); + if (current_symbol_table_idx != 0) { + return (current_symbol_table_idx); + } + if (global_table_index >= NUMBER_OF_GLOBALS) { + error ("global symbol table overflow"); + return (0); + } + current_symbol_table_idx = global_table_index; + symbol = &symbol_table[current_symbol_table_idx]; + buffer_ptr = symbol->name; + while (alphanumeric(*buffer_ptr++ = *sname++)); + symbol->identity = identity; + symbol->type = type; + symbol->storage = storage; + symbol->count = count; + symbol->offset = offset; + global_table_index++; + return (current_symbol_table_idx); +} + +/** + * add new symbol to local table + * @param sname + * @param identity + * @param type + * @param value + * @param storage_class + * @return + */ +int add_local (char *sname, int identity, int type, int offset, int storage_class, int count) { + int k; + symbol_t *symbol; + char *buffer_ptr; +//printf("local - symbol: %s offset: %d count: %d\n", sname, offset, count); + + if (current_symbol_table_idx = findloc (sname)) { + return (current_symbol_table_idx); + } + if (local_table_index >= NUMBER_OF_GLOBALS + NUMBER_OF_LOCALS) { + error ("local symbol table overflow"); + return (0); + } + current_symbol_table_idx = local_table_index; + symbol = &symbol_table[current_symbol_table_idx]; + buffer_ptr = symbol->name; + while (alphanumeric(*buffer_ptr++ = *sname++)); + symbol->identity = identity; + symbol->type = type; + symbol->storage = storage_class; + symbol->count = count; + if (storage_class == LSTATIC) { + data_segment_gdata(); + print_label(k = getlabel()); + output_label_terminator(); + gen_def_storage(); + output_number(offset); + newline(); + code_segment_gtext(); + offset = k; + } + symbol->offset = offset; + local_table_index++; + return (current_symbol_table_idx); +} + +/* + * test if next input string is legal symbol name + * + */ +symname(char *sname) { + int k; + + blanks(); + if (!alpha (ch ())) + return (0); + k = 0; + while (alphanumeric(ch ())) + sname[k++] = gch (); + sname[k] = 0; + return (1); +} + +illname() { + error ("illegal symbol name"); +} + +/** + * print error message + * @param symbol_name + * @return + */ +multidef (char *symbol_name) { + error ("already defined"); + gen_comment (); + output_string (symbol_name); + newline (); +} diff --git a/src/cmd/smallc/vax/B2test.c b/src/cmd/smallc/vax/B2test.c new file mode 100644 index 0000000..5187de6 --- /dev/null +++ b/src/cmd/smallc/vax/B2test.c @@ -0,0 +1,31 @@ +#include + +main () { + FILE *infile; FILE *outfile; + int c; + puts("Starting input only"); + if ((infile = fopen("b2test.dat","r")) == NULL ) { + puts("could not open input file"); + exit(1); + } + while (putchar(fgetc(infile)) != EOF); + puts("end of input file"); + fclose(infile); + puts("starting copy"); + if ((infile = fopen("b2test.dat","r")) == NULL) { + puts("could not open input file for copy"); + exit(1); + } + if ((outfile = fopen("b2test.out","w")) == NULL) { + puts("could not open output file"); + exit(1); + } + while ((c = fgetc(infile)) != EOF) { + fputc(c, outfile); + } + puts("finished output file"); + fclose(infile); + fclose(outfile); + +} + diff --git a/src/cmd/smallc/vax/Makefile b/src/cmd/smallc/vax/Makefile new file mode 100644 index 0000000..037b567 --- /dev/null +++ b/src/cmd/smallc/vax/Makefile @@ -0,0 +1,11 @@ +.SUFFIXES: .o .c + +.c.o: + /u/clewis/lib/sccvax -c $*.c + as -o $*.o $*.s + +OBJ = crunvax.o chiovax.o iovax.o + +libl.a: $(OBJ) crt0.o + ar ru libl.a $(OBJ) + ucb ranlib libl.a diff --git a/src/cmd/smallc/vax/b2test.dat b/src/cmd/smallc/vax/b2test.dat new file mode 100644 index 0000000..57316e4 --- /dev/null +++ b/src/cmd/smallc/vax/b2test.dat @@ -0,0 +1,2 @@ +ehllo +hello diff --git a/src/cmd/smallc/vax/chiovax.c b/src/cmd/smallc/vax/chiovax.c new file mode 100644 index 0000000..4f0f77f --- /dev/null +++ b/src/cmd/smallc/vax/chiovax.c @@ -0,0 +1,51 @@ +#define EOL 10 +getchar() { +#asm + movl $0,r0 + pushl $1 + pushal buff + pushl $0 + calls $3,Xread + cvtbl buff,r0 + .data +buff: .space 1 + .text +#endasm + +} + +#asm + .set read,3 +Xread: + .word 0x0000 + chmk $read + bcc noerror2 + jmp cerror +noerror2: + ret +cerror: bpt +#endasm + +putchar (c) char c; { + c; +#asm + cvtlb r0,buff + pushl $1 + pushal buff + pushl $1 + calls $3,Xwrite + cvtbl buff,r0 +#endasm + +} + +#asm + .set write,4 +Xwrite: + .word 0x0000 + chmk $write + bcc noerror + jmp cerror +noerror: + ret +#endasm diff --git a/src/cmd/smallc/vax/crt0.c b/src/cmd/smallc/vax/crt0.c new file mode 100644 index 0000000..920030a --- /dev/null +++ b/src/cmd/smallc/vax/crt0.c @@ -0,0 +1,34 @@ +#asm +# C runtime startoff + + .set exit,1 +.globl start +.globl _main +.globl _exit + +# +# C language startup routine + +start: + .word 0x0000 + subl2 $8,sp + movl 8(sp),4(sp) # argc + movab 12(sp),r0 + movl r0,(sp) # argv + jsb _main + addl2 $8,sp + pushl r0 + chmk $exit +#endasm +exit(x) int x; { + x; +#asm + pushl r0 + calls $1,exit2 +exit2: + .word 0x0000 + chmk $exit +#endasm + +} + diff --git a/src/cmd/smallc/vax/crt0.s b/src/cmd/smallc/vax/crt0.s new file mode 100644 index 0000000..d528216 --- /dev/null +++ b/src/cmd/smallc/vax/crt0.s @@ -0,0 +1,61 @@ +# Small C VAX +# Coder (2.1,83/04/05) +# Front End (2.1,83/03/20) + .globl lneg + .globl case + .globl eq + .globl ne + .globl lt + .globl le + .globl gt + .globl ge + .globl ult + .globl ule + .globl ugt + .globl uge + .globl bool + .text +##asm +# C runtime startoff + .set exit,1 +.globl start +.globl _main +.globl _exit +# +# C language startup routine +start: + .word 0x0000 + subl2 $8,sp + movl 8(sp),4(sp) # argc + movab 12(sp),r0 + movl r0,(sp) # argv + jsb _main + addl2 $8,sp + pushl r0 + chmk $exit +#exit(x) int x; { + .align 1 +_exit: + +# x; + moval 4(sp),r0 + movl (r0),r0 +##asm + pushl r0 + calls $1,exit2 +exit2: + .word 0x0000 + chmk $exit +#} +LL1: + + rsb + .data + .globl _etext + .globl _edata + .globl _exit + +#0 error(s) in compilation +# literal pool:0 +# global pool:42 +# Macro pool:43 diff --git a/src/cmd/smallc/vax/crunvax.c b/src/cmd/smallc/vax/crunvax.c new file mode 100644 index 0000000..d2add76 --- /dev/null +++ b/src/cmd/smallc/vax/crunvax.c @@ -0,0 +1,90 @@ +#asm +# csa09 Small C v1 comparison support +# All are dyadic except for lneg. +.globl eq +.globl ne +.globl lt +.globl le +.globl gt +.globl ge +.globl ult +.globl ule +.globl ugt +.globl uge +.globl lneg +.globl bool +.globl case +.globl _Xstktop + +eq: cmpl r0,4(sp) + jeql true + jbr false + +ne: cmpl r0,4(sp) + jneq true + jbr false + +lt: cmpl r0,4(sp) + jgtr true + jbr false + +le: cmpl r0,4(sp) + jgeq true + jbr false + +gt: cmpl r0,4(sp) + jlss true + jbr false + +ge: cmpl r0,4(sp) + jleq true + jbr false + +ult: cmpl r0,4(sp) + jgtru true + jbr false + +ule: cmpl r0,4(sp) + jgequ true + jbr false + +ugt: cmpl r0,4(sp) + jlequ true + jbr false + +uge: cmpl r0,4(sp) + jlssu true + jbr false + +lneg: cmpl r0,$0 + jeql ltrue + movl $0,r0 + rsb +ltrue: movl $1,r0 + rsb + +bool: jsb lneg + jbr lneg + +true: movl $1,r0 + movl (sp),r3 + addl2 $8,sp + jmp (r3) + +false: movl $0,r0 + movl (sp),r3 + addl2 $8,sp + jmp (r3) +_Xstktop: movl sp,r0 + rsb +# Case jump, value is in r0, case table in (sp) +case: movl (sp)+,r1 # pick up case pointer +casl: + movl (r1)+,r2 # pick up value. + movl (r1)+,r3 # pick up label. + bneq notdef # if not default, check it + jmp (r2) # is default, go do it. +notdef: cmpl r0,r2 # compare table value with switch value + bneq casl # go for next table ent if not + jmp (r3) # otherwise, jump to it. +#endasm diff --git a/src/cmd/smallc/vax/iovax.c b/src/cmd/smallc/vax/iovax.c new file mode 100644 index 0000000..b35deae --- /dev/null +++ b/src/cmd/smallc/vax/iovax.c @@ -0,0 +1,129 @@ +/* VAX fopen, fclose, fgetc, fputc, feof + * gawd is this gross - no buffering! +*/ +#include + +static feofed[20]; +static char charbuf[1]; +static retcode; + +fopen(filnam, mod) char *filnam, *mod; { + if (*mod == 'w') { + filnam; +#asm + pushl r0 + calls $1,zunlink +#endasm + filnam; +#asm + pushl $0644 + pushl r0 + calls $2,zcreat + movl r0,_retcode +#endasm + if (retcode < 0) { + return(NULL); + } else return(retcode); + } + filnam; +#asm + pushl $0 # read mode + pushl r0 + calls $2,zopen + movl r0,_retcode +#endasm + feofed[retcode] = 0; + if (retcode < 0) return (NULL); + else return(retcode); + +} + +fclose(unit) int unit; { + unit; +#asm + pushl r0 + calls $1,zclose +#endasm + +} + +fgetc(unit) int unit; { + unit; +#asm + pushl $1 + pushl $_charbuf + pushl r0 + calls $3,zread + movl r0,_retcode +#endasm + if (retcode <= 0) { + feofed[unit] = 1; + return(EOF); + } else + return(charbuf[0]); + +} + +fputc(c, unit) int c, unit; { + charbuf[0] = c; + unit; +#asm + pushl $1 + pushl $_charbuf + pushl r0 + calls $3,zwrite +#endasm + return(c); + +} + +feof(unit) int unit; { + if (feofed[unit]) return(1); + else return(NULL); + +} + +/* Assembler assists */ +#asm + .set unlink,10 + .set creat,8 + .set open,5 + .set close,6 + .set read,3 + .set write,4 +zunlink: + .word 0x0000 + chmk $unlink + bcc noerr + jmp cerror +zcreat: + .word 0x0000 + chmk $creat + bcc noerr + jmp cerror +zopen: + .word 0x0000 + chmk $open + bcc noerr + jmp cerror +zclose: + .word 0x0000 + chmk $close + bcc noerr + jmp cerror +zread: + .word 0x0000 + chmk $read + bcc noerr + jmp cerror +zwrite: + .word 0x0000 + chmk $write + bcc noerr + jmp cerror + +cerror: + mnegl $1,r0 + ret +noerr: ret +#endasm diff --git a/src/cmd/smallc/vax/optest.c b/src/cmd/smallc/vax/optest.c new file mode 100644 index 0000000..80ddf79 --- /dev/null +++ b/src/cmd/smallc/vax/optest.c @@ -0,0 +1,103 @@ +#include +#define chkstk 1 +#define NOSUP 1 +int address; +int ret; +int locaddr; +int i; +int *temp; +#ifdef vax +#define INTSIZE 4 +#else +#define INTSIZE 2 +#endif +int fred[30]; +main(){ + int x; + puts("Starting test"); + i = 1; + address = &x; + locaddr = 0; + address = address + INTSIZE; + temp = address; + ret = *temp; + fred[3] = 3; + test(fred[3], 3, "fred[3] = 3"); + test(INTSIZE, sizeof(int), "INTSIZE"); + test(sizeof(char), 1, "sizeof char"); + test(1 + 4, 1, "(should fail) 1+4 "); + test(1022 + 5, 1027, "1022 + 5"); + test(4 + 5, 9, "4 + 5"); + test(1022 * 3, 3066, "1022 * 3"); + test(4 * - 1, -4, "4 * - 1"); + test(4 * 5, 20, "4 * 5"); + test(1000 - 999, 1, "1000 - 999"); + test(1000 - 1200, -200, "1000 - 1200"); + test(-1 - -1, 0, "-1 - -1"); + test(4 >> 2, 1, "4 >> 2"); + test(1234 >> 1, 617, "1234 >> 1"); + test(4 << 2, 16, "4 << 2"); + test(1000 << 1, 2000, "1000 << 1"); + test(1001 % 10, 1, "1001 % 10"); + test(3 % 10, 3, "3 % 10"); + test(10 % 4, 2, "10 % 4"); + test(1000 / 5, 200, "1000 / 5"); + test(3 / 10, 0, "3 / 10"); + test(10 / 3, 3, "10 / 3"); + test(1000 == 32767, 0, "1000 == 32767"); + test(1000 == 1000, 1, "1000 == 1000"); + test(1 != 0, 1, "1 != 0"); + test(1 < -1, 0, "1 < -1"); + test(1 < 2, 1, "1 < 2"); + test(1 != 1, 0, "1 != 1"); + test(2 && 1, 1, "2 && 1"); + test(0 && 1, 0, "0 && 1"); + test(1 && 0, 0, "1 && 0"); + test(0 && 0, 0, "0 && 0"); + test(1000 || 1, 1, "1000 || 1"); + test(1000 || 0, 1, "1000 || 0"); + test(0 || 1, 1, "0 || 1"); + test(0 || 0, 0, "0 || 0"); + test(!2, 0, "!2"); + test(!0, 1, "!0"); + test(~1, -2, "~1"); + test(2 ^ 1, 3, "2 ^ 1"); + test(0 ^ 0, 0, "0 ^ 0"); + test(1 ^ 1, 0, "1 ^ 1"); + test(5 ^ 6, 3, "5 ^ 6"); + test((0 < 1) ? 1 : 0, 1, "(0 < 1) ? 1 : 0"); + test((1000 > 1000) ? 0: 1, 1, "(1000 > 1000) ? 0 : 1"); + puts("ending test"); + } +test(t, real, testn) int t; char *testn; int real;{ + if (t != real) { + fputs(testn, stdout); + fputs(" failed\n", stdout); + fputs("Should be: ", stdout); + printn(real, 10, stdout); + fputs(" was: ", stdout); + printn(t, 10, stdout); + putchar('\n'); + prompt(); + } + if (*temp != ret) { + puts("retst"); + prompt(); + } +#ifdef chkstk + if (locaddr == 0) locaddr = &t; + else if (locaddr != &t) { + puts("locst during"); + puts(testn); + prompt(); + } +#endif + +} + +prompt() { + puts("hit any key to continue"); + getchar(); + +} + diff --git a/src/cmd/smallc/vax/vscc b/src/cmd/smallc/vax/vscc new file mode 100644 index 0000000..8ece2fd --- /dev/null +++ b/src/cmd/smallc/vax/vscc @@ -0,0 +1,9 @@ +if ../src/sccvax -c $1.c + then + if as -o $1.o $1.s + then + rm $1.s + ld -o $1 ../crunvax/crt0.o $1.o ../libc/vaxlibc.a +../crunvax/libl.a + fi +fi diff --git a/src/cmd/smallc/while.c b/src/cmd/smallc/while.c new file mode 100644 index 0000000..4fbef35 --- /dev/null +++ b/src/cmd/smallc/while.c @@ -0,0 +1,70 @@ +/* + * File while.c: 2.1 (83/03/20,16:02:22) + */ +#include +#include "defs.h" +#include "data.h" + +addloop (loop_t *ptr) +{ + if (loop_table_index == WSTABSZ) { + error ("too many active loops"); + return; + } + loopstack[loop_table_index++] = *ptr; +} + +delloop () +{ + if (readloop ()) { + loop_table_index--; + } +} + +loop_t *readloop () +{ + if (loop_table_index == 0) { + error ("no active do/for/while/switch"); + return 0; + } + return &loopstack[loop_table_index - 1]; +} + +loop_t *findloop () +{ + int i; + + for (i=loop_table_index; --i>= 0;) { + if (loopstack[i].type != WSSWITCH) + return &loopstack[i]; + } + error ("no active do/for/while"); + return 0; +} + +loop_t *readswitch () +{ + loop_t *ptr; + + if (ptr = readloop ()) { + if (ptr->type == WSSWITCH) { + return ptr; + } + } + return 0; +} + +addcase (int val) +{ + int lab; + + if (swstp == SWSTSZ) { + error ("too many case labels"); + return; + } + swstcase[swstp] = val; + swstlab[swstp++] = lab = getlabel (); + print_label (lab); + output_label_terminator (); + newline (); +} diff --git a/src/cmd/smlrc/Makefile b/src/cmd/smlrc/Makefile new file mode 100644 index 0000000..4ba8a75 --- /dev/null +++ b/src/cmd/smlrc/Makefile @@ -0,0 +1,30 @@ +TOPSRC = $(shell cd ../../..; pwd) +include $(TOPSRC)/target.mk +#include $(TOPSRC)/cross.mk + +CFLAGS = -Os -Wall -DMIPS -DNO_ANNOTATIONS -DNO_PREPROCESSOR \ + -DNO_PPACK -D_RETROBSD -D__SMALLER_C_SCHAR__ \ + -D__SMALLER_C__ -D__SMALLER_C_32__ + +LIBS = -lc + +ARCH = mips + +OBJS = smlrc.o lb.o + +all: smlrc + +smlrc: $(OBJS) + ${CC} ${LDFLAGS} -o $@.elf ${OBJS} ${LIBS} + ${OBJDUMP} -S $@.elf > $@.dis + ${SIZE} $@.elf + ${ELF2AOUT} $@.elf $@ + +install: smlrc + cp smlrc $(TOPSRC)/libexec/ + + +clean: + rm -f *.o smlrc smlrc.dis smlrc.elf +### +smlrc.o: smlrc.c cgmips.c diff --git a/src/cmd/smlrc/cgmips.c b/src/cmd/smlrc/cgmips.c new file mode 100644 index 0000000..5991d6f --- /dev/null +++ b/src/cmd/smlrc/cgmips.c @@ -0,0 +1,1610 @@ +/* +Copyright (c) 2012-2014, Alexey Frunze +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +The views and conclusions contained in the software and documentation are those +of the authors and should not be interpreted as representing official policies, +either expressed or implied, of the FreeBSD Project. +*/ + +/*****************************************************************************/ +/* */ +/* Smaller C */ +/* */ +/* A simple and small single-pass C compiler ("small C" class). */ +/* */ +/* MIPS code generator */ +/* */ +/*****************************************************************************/ + +int UseGp = 0; + +void GenInit(void) +{ + // initialization of target-specific code generator + SizeOfWord = 4; + OutputFormat = FormatSegmented; + CodeHeader = "\t.text"; + DataHeader = "\t.data"; + UseLeadingUnderscores = 0; +#ifndef NO_REORDER_WORKAROUND + FileHeader = "\t.set\tnoreorder"; +#else + FileHeader = "\t.set\treorder"; +#endif +} + +int GenInitParams(int argc, char** argv, int* idx) +{ + (void)argc; + // initialization of target-specific code generator with parameters + if (!strcmp(argv[*idx], "-use-gp")) + { + UseGp = 1; + return 1; + } + return 0; +} + +void GenInitFinalize(void) +{ + // finalization of initialization of target-specific code generator +} + +void GenStartCommentLine(void) +{ + printf2(" # "); +} + +void GenWordAlignment(void) +{ + printf2("\t.align 2\n"); +} + +void GenLabel(char* Label, int Static) +{ + { + if (OutputFormat != FormatFlat && !Static && GenExterns) + printf2("\t.globl\t%s\n", Label); + printf2("%s:\n", Label); + } +} + +void GenPrintLabel(char* Label) +{ + { + if (isdigit(*Label)) + printf2("$L%s", Label); + else + printf2("%s", Label); + } +} + +void GenNumLabel(int Label) +{ + printf2("$L%d:\n", Label); +} + +void GenPrintNumLabel(int label) +{ + printf2("$L%d", label); +} + +void GenZeroData(unsigned Size) +{ + printf2("\t.space\t%u\n", truncUint(Size)); // or ".fill size" +} + +void GenIntData(int Size, int Val) +{ + Val = truncInt(Val); + if (Size == 1) + printf2("\t.byte\t%d\n", Val); + else if (Size == 2) + printf2("\t.half\t%d\n", Val); + else if (Size == 4) + printf2("\t.word\t%d\n", Val); +} + +void GenStartAsciiString(void) +{ + printf2("\t.ascii\t"); +} + +void GenAddrData(int Size, char* Label) +{ + if (Size == 1) + printf2("\t.byte\t"); + else if (Size == 2) + printf2("\t.half\t"); + else if (Size == 4) + printf2("\t.word\t"); + GenPrintLabel(Label); puts2(""); +} + +#define MipsInstrNop 0x00 +#define MipsInstrMov 0x01 +#define MipsInstrMfLo 0x02 +#define MipsInstrMfHi 0x03 +//#define MipsInstrMovZ 0x04 +//#define MipsInstrMovN 0x05 +#define MipsInstrLA 0x06 +#define MipsInstrLI 0x07 +//#define MipsInstrLUI 0x08 +#define MipsInstrLB 0x09 +#define MipsInstrLBU 0x0A +#define MipsInstrLH 0x0B +#define MipsInstrLHU 0x0C +#define MipsInstrLW 0x0D +#define MipsInstrSB 0x0E +#define MipsInstrSH 0x0F +#define MipsInstrSW 0x10 +#define MipsInstrAddU 0x11 +#define MipsInstrSubU 0x12 +#define MipsInstrAnd 0x13 +#define MipsInstrOr 0x14 +#define MipsInstrXor 0x15 +#define MipsInstrNor 0x16 +#define MipsInstrSLL 0x17 +#define MipsInstrSRL 0x18 +#define MipsInstrSRA 0x19 +#define MipsInstrMul 0x1A +#define MipsInstrDiv 0x1B +#define MipsInstrDivU 0x1C +#define MipsInstrSLT 0x1D +#define MipsInstrSLTU 0x1E +#define MipsInstrJ 0x1F +#define MipsInstrJAL 0x20 +#define MipsInstrBEQ 0x21 +#define MipsInstrBNE 0x22 +//#define MipsInstrBLTZ 0x23 +//#define MipsInstrBGEZ 0x24 +//#define MipsInstrBLEZ 0x25 +//#define MipsInstrBGTZ 0x26 +//#define MipsInstrBreak 0x27 + +void GenPrintInstr(int instr, int val) +{ + char* p = ""; + + (void)val; + + switch (instr) + { + case MipsInstrNop : p = "nop"; break; + case MipsInstrMov : p = "move"; break; + case MipsInstrMfLo : p = "mflo"; break; + case MipsInstrMfHi : p = "mfhi"; break; +// case MipsInstrMovZ : p = "movz"; break; +// case MipsInstrMovN : p = "movn"; break; + case MipsInstrLA : p = "la"; break; + case MipsInstrLI : p = "li"; break; +// case MipsInstrLUI : p = "lui"; break; + case MipsInstrLB : p = "lb"; break; + case MipsInstrLBU : p = "lbu"; break; + case MipsInstrLH : p = "lh"; break; + case MipsInstrLHU : p = "lhu"; break; + case MipsInstrLW : p = "lw"; break; + case MipsInstrSB : p = "sb"; break; + case MipsInstrSH : p = "sh"; break; + case MipsInstrSW : p = "sw"; break; + case MipsInstrAddU : p = "addu"; break; + case MipsInstrSubU : p = "subu"; break; + case MipsInstrAnd : p = "and"; break; + case MipsInstrOr : p = "or"; break; + case MipsInstrXor : p = "xor"; break; + case MipsInstrNor : p = "nor"; break; + case MipsInstrSLL : p = "sll"; break; + case MipsInstrSRL : p = "srl"; break; + case MipsInstrSRA : p = "sra"; break; + case MipsInstrMul : p = "mul"; break; + case MipsInstrDiv : p = "div"; break; + case MipsInstrDivU : p = "divu"; break; + case MipsInstrSLT : p = "slt"; break; + case MipsInstrSLTU : p = "sltu"; break; + case MipsInstrJ : p = "j"; break; + case MipsInstrJAL : p = "jal"; break; + case MipsInstrBEQ : p = "beq"; break; + case MipsInstrBNE : p = "bne"; break; +// case MipsInstrBLTZ : p = "bltz"; break; +// case MipsInstrBGEZ : p = "bgez"; break; +// case MipsInstrBLEZ : p = "blez"; break; +// case MipsInstrBGTZ : p = "bgtz"; break; +// case MipsInstrBreak: p = "break"; break; + } + + printf2("\t%s\t", p); +} + +#define MipsOpRegZero 0x00 +#define MipsOpRegAt 0x01 +#define MipsOpRegV0 0x02 +#define MipsOpRegV1 0x03 +#define MipsOpRegA0 0x04 +#define MipsOpRegA1 0x05 +#define MipsOpRegA2 0x06 +#define MipsOpRegA3 0x07 +#define MipsOpRegT0 0x08 +#define MipsOpRegT1 0x09 +#define MipsOpRegT2 0x0A +#define MipsOpRegT3 0x0B +#define MipsOpRegT4 0x0C +#define MipsOpRegT5 0x0D +#define MipsOpRegT6 0x0E +#define MipsOpRegT7 0x0F +#define MipsOpRegS0 0x10 +#define MipsOpRegS1 0x11 +#define MipsOpRegS2 0x12 +#define MipsOpRegS3 0x13 +#define MipsOpRegS4 0x14 +#define MipsOpRegS5 0x15 +#define MipsOpRegS6 0x16 +#define MipsOpRegS7 0x17 +#define MipsOpRegT8 0x18 +#define MipsOpRegT9 0x19 +#define MipsOpRegSp 0x1D +#define MipsOpRegFp 0x1E +#define MipsOpRegRa 0x1F + +#define MipsOpIndRegZero 0x20 +#define MipsOpIndRegAt 0x21 +#define MipsOpIndRegV0 0x22 +#define MipsOpIndRegV1 0x23 +#define MipsOpIndRegA0 0x24 +#define MipsOpIndRegA1 0x25 +#define MipsOpIndRegA2 0x26 +#define MipsOpIndRegA3 0x27 +#define MipsOpIndRegT0 0x28 +#define MipsOpIndRegT1 0x29 +#define MipsOpIndRegSp 0x3D +#define MipsOpIndRegFp 0x3E +#define MipsOpIndRegRa 0x3F + +#define MipsOpConst 0x80 +#define MipsOpLabel 0x81 +#define MipsOpNumLabel 0x82 +#define MipsOpLabelGpOption 0x83 +#define MipsOpIndLocal MipsOpIndRegFp + +#ifndef NO_REORDER_WORKAROUND +void GenNop(void) +{ + puts2("\tnop"); +} +#endif + +void GenPrintOperand(int op, int val) +{ + if (op >= MipsOpRegZero && op <= MipsOpRegRa) + { + printf2("$%d", op); + } + else if (op >= MipsOpIndRegZero && op <= MipsOpIndRegRa) + { + printf2("%d($%d)", truncInt(val), op - MipsOpIndRegZero); + } + else + { + switch (op) + { + case MipsOpConst: printf2("%d", truncInt(val)); break; + case MipsOpLabelGpOption: + if (UseGp) + { + printf2("%%gp_rel("); + GenPrintLabel(IdentTable + val); + printf2(")($28)"); + } + else + { + printf2("%%lo("); + GenPrintLabel(IdentTable + val); + printf2(")($1)"); + } + break; + case MipsOpLabel: GenPrintLabel(IdentTable + val); break; + case MipsOpNumLabel: GenPrintNumLabel(val); break; + + default: + //error("WTF!\n"); + errorInternal(100); + break; + } + } +} + +void GenPrintOperandSeparator(void) +{ + printf2(", "); +} + +void GenPrintNewLine(void) +{ + puts2(""); +} + +void GenPrintInstrNoOperand(int instr) +{ + GenPrintInstr(instr, 0); + GenPrintNewLine(); +} + +void GenPrintInstr1Operand(int instr, int instrval, int operand, int operandval) +{ + GenPrintInstr(instr, instrval); + GenPrintOperand(operand, operandval); + GenPrintNewLine(); + +#ifndef NO_REORDER_WORKAROUND + if (instr == MipsInstrJ || instr == MipsInstrJAL) + GenNop(); +#endif +} + +void GenPrintInstr2Operands(int instr, int instrval, int operand1, int operand1val, int operand2, int operand2val) +{ + if (operand2 == MipsOpConst && operand2val == 0 && + (instr == MipsInstrAddU || instr == MipsInstrSubU)) + return; + + GenPrintInstr(instr, instrval); + GenPrintOperand(operand1, operand1val); + GenPrintOperandSeparator(); + GenPrintOperand(operand2, operand2val); + GenPrintNewLine(); +} + +void GenPrintInstr3Operands(int instr, int instrval, + int operand1, int operand1val, + int operand2, int operand2val, + int operand3, int operand3val) +{ + if (operand3 == MipsOpConst && operand3val == 0 && + (instr == MipsInstrAddU || instr == MipsInstrSubU)) + return; + + GenPrintInstr(instr, instrval); + GenPrintOperand(operand1, operand1val); + GenPrintOperandSeparator(); + GenPrintOperand(operand2, operand2val); + GenPrintOperandSeparator(); + GenPrintOperand(operand3, operand3val); + GenPrintNewLine(); + +#ifndef NO_REORDER_WORKAROUND + if (instr == MipsInstrBEQ || instr == MipsInstrBNE) + GenNop(); +#endif +} + +void GenExtendRegIfNeeded(int reg, int opSz) +{ + if (opSz == -1) + { + GenPrintInstr3Operands(MipsInstrSLL, 0, + reg, 0, + reg, 0, + MipsOpConst, 24); + GenPrintInstr3Operands(MipsInstrSRA, 0, + reg, 0, + reg, 0, + MipsOpConst, 24); + } + else if (opSz == 1) + { + GenPrintInstr3Operands(MipsInstrAnd, 0, + reg, 0, + reg, 0, + MipsOpConst, 0xFF); + } + else if (opSz == -2) + { + GenPrintInstr3Operands(MipsInstrSLL, 0, + reg, 0, + reg, 0, + MipsOpConst, 16); + GenPrintInstr3Operands(MipsInstrSRA, 0, + reg, 0, + reg, 0, + MipsOpConst, 16); + } + else if (opSz == 2) + { + GenPrintInstr3Operands(MipsInstrAnd, 0, + reg, 0, + reg, 0, + MipsOpConst, 0xFFFF); + } +} + +void GenJumpUncond(int label) +{ + GenPrintInstr1Operand(MipsInstrJ, 0, + MipsOpNumLabel, label); +} + +void GenJumpIfNotEqual(int val, int label) +{ + GenPrintInstr2Operands(MipsInstrLI, 0, + MipsOpRegT1, 0, + MipsOpConst, val); + GenPrintInstr3Operands(MipsInstrBNE, 0, + MipsOpRegV0, 0, + MipsOpRegT1, 0, + MipsOpNumLabel, label); +} + +void GenJumpIfZero(int label) +{ +#ifndef NO_ANNOTATIONS + printf2(" # JumpIfZero\n"); +#endif + GenPrintInstr3Operands(MipsInstrBEQ, 0, + MipsOpRegV0, 0, + MipsOpRegZero, 0, + MipsOpNumLabel, label); +} + +void GenJumpIfNotZero(int label) +{ +#ifndef NO_ANNOTATIONS + printf2(" # JumpIfNotZero\n"); +#endif + GenPrintInstr3Operands(MipsInstrBNE, 0, + MipsOpRegV0, 0, + MipsOpRegZero, 0, + MipsOpNumLabel, label); +} + +void GenFxnProlog(void) +{ + GenPrintInstr3Operands(MipsInstrSubU, 0, + MipsOpRegSp, 0, + MipsOpRegSp, 0, + MipsOpConst, 8); + + GenPrintInstr2Operands(MipsInstrSW, 0, + MipsOpRegRa, 0, + MipsOpIndRegSp, 4); + + GenPrintInstr2Operands(MipsInstrSW, 0, + MipsOpRegFp, 0, + MipsOpIndRegSp, 0); + + GenPrintInstr2Operands(MipsInstrMov, 0, + MipsOpRegFp, 0, + MipsOpRegSp, 0); + + if (CurFxnParamCntMax) + { + int i, cnt = CurFxnParamCntMax; + if (cnt > 4) + cnt = 4; + for (i = 0; i < cnt; i++) + GenPrintInstr2Operands(MipsInstrSW, 0, + MipsOpRegA0 + i, 0, + MipsOpIndRegFp, 8 + 4 * i); + } +} + +void GenLocalAlloc(int size) +{ + GenPrintInstr3Operands(MipsInstrSubU, 0, + MipsOpRegSp, 0, + MipsOpRegSp, 0, + MipsOpConst, size); +} + +void GenFxnEpilog(void) +{ + GenPrintInstr2Operands(MipsInstrMov, 0, + MipsOpRegSp, 0, + MipsOpRegFp, 0); + + GenPrintInstr2Operands(MipsInstrLW, 0, + MipsOpRegFp, 0, + MipsOpIndRegSp, 0); + + GenPrintInstr2Operands(MipsInstrLW, 0, + MipsOpRegRa, 0, + MipsOpIndRegSp, 4); + + GenPrintInstr3Operands(MipsInstrAddU, 0, + MipsOpRegSp, 0, + MipsOpRegSp, 0, + MipsOpConst, 8); + + GenPrintInstr1Operand(MipsInstrJ, 0, + MipsOpRegRa, 0); +} + +int GenGetBinaryOperatorInstr(int tok) +{ + switch (tok) + { + case tokPostAdd: + case tokAssignAdd: + case '+': + return MipsInstrAddU; + case tokPostSub: + case tokAssignSub: + case '-': + return MipsInstrSubU; + case '&': + case tokAssignAnd: + return MipsInstrAnd; + case '^': + case tokAssignXor: + return MipsInstrXor; + case '|': + case tokAssignOr: + return MipsInstrOr; + case '<': + case '>': + case tokLEQ: + case tokGEQ: + case tokEQ: + case tokNEQ: + case tokULess: + case tokUGreater: + case tokULEQ: + case tokUGEQ: + return MipsInstrNop; + case '*': + case tokAssignMul: + return MipsInstrMul; + case '/': + case '%': + case tokAssignDiv: + case tokAssignMod: + return MipsInstrDiv; + case tokUDiv: + case tokUMod: + case tokAssignUDiv: + case tokAssignUMod: + return MipsInstrDivU; + case tokLShift: + case tokAssignLSh: + return MipsInstrSLL; + case tokRShift: + case tokAssignRSh: + return MipsInstrSRA; + case tokURShift: + case tokAssignURSh: + return MipsInstrSRL; + + default: + //error("Error: Invalid operator\n"); + errorInternal(101); + return 0; + } +} + +void GenPreIdentAccess(int label) +{ + if (UseGp) + return; + printf2("\t.set\tnoat\n\tlui\t$1, %%hi("); + GenPrintLabel(IdentTable + label); + puts2(")"); +} + +void GenPostIdentAccess(void) +{ + if (UseGp) + return; + puts2("\t.set\tat"); +} + +void GenReadIdent(int regDst, int opSz, int label) +{ + int instr = MipsInstrLW; + GenPreIdentAccess(label); + if (opSz == -1) + { + instr = MipsInstrLB; + } + else if (opSz == 1) + { + instr = MipsInstrLBU; + } + else if (opSz == -2) + { + instr = MipsInstrLH; + } + else if (opSz == 2) + { + instr = MipsInstrLHU; + } + GenPrintInstr2Operands(instr, 0, + regDst, 0, + MipsOpLabelGpOption, label); + GenPostIdentAccess(); +} + +void GenReadLocal(int regDst, int opSz, int ofs) +{ + int instr = MipsInstrLW; + if (opSz == -1) + { + instr = MipsInstrLB; + } + else if (opSz == 1) + { + instr = MipsInstrLBU; + } + else if (opSz == -2) + { + instr = MipsInstrLH; + } + else if (opSz == 2) + { + instr = MipsInstrLHU; + } + GenPrintInstr2Operands(instr, 0, + regDst, 0, + MipsOpIndRegFp, ofs); +} + +void GenReadIndirect(int regDst, int regSrc, int opSz) +{ + int instr = MipsInstrLW; + if (opSz == -1) + { + instr = MipsInstrLB; + } + else if (opSz == 1) + { + instr = MipsInstrLBU; + } + else if (opSz == -2) + { + instr = MipsInstrLH; + } + else if (opSz == 2) + { + instr = MipsInstrLHU; + } + GenPrintInstr2Operands(instr, 0, + regDst, 0, + regSrc + MipsOpIndRegZero, 0); +} + +void GenWriteIdent(int regSrc, int opSz, int label) +{ + int instr = MipsInstrSW; + GenPreIdentAccess(label); + if (opSz == -1 || opSz == 1) + { + instr = MipsInstrSB; + } + else if (opSz == -2 || opSz == 2) + { + instr = MipsInstrSH; + } + GenPrintInstr2Operands(instr, 0, + regSrc, 0, + MipsOpLabelGpOption, label); + GenPostIdentAccess(); +} + +void GenWriteLocal(int regSrc, int opSz, int ofs) +{ + int instr = MipsInstrSW; + if (opSz == -1 || opSz == 1) + { + instr = MipsInstrSB; + } + else if (opSz == -2 || opSz == 2) + { + instr = MipsInstrSH; + } + GenPrintInstr2Operands(instr, 0, + regSrc, 0, + MipsOpIndRegFp, ofs); +} + +void GenWriteIndirect(int regDst, int regSrc, int opSz) +{ + int instr = MipsInstrSW; + if (opSz == -1 || opSz == 1) + { + instr = MipsInstrSB; + } + else if (opSz == -2 || opSz == 2) + { + instr = MipsInstrSH; + } + GenPrintInstr2Operands(instr, 0, + regSrc, 0, + regDst + MipsOpIndRegZero, 0); +} + +void GenIncDecIdent(int regDst, int opSz, int label, int tok) +{ + int instr = MipsInstrAddU; + + if (tok != tokInc) + instr = MipsInstrSubU; + + GenReadIdent(regDst, opSz, label); + GenPrintInstr3Operands(instr, 0, + regDst, 0, + regDst, 0, + MipsOpConst, 1); + GenWriteIdent(regDst, opSz, label); + GenExtendRegIfNeeded(regDst, opSz); +} + +void GenIncDecLocal(int regDst, int opSz, int ofs, int tok) +{ + int instr = MipsInstrAddU; + + if (tok != tokInc) + instr = MipsInstrSubU; + + GenReadLocal(regDst, opSz, ofs); + GenPrintInstr3Operands(instr, 0, + regDst, 0, + regDst, 0, + MipsOpConst, 1); + GenWriteLocal(regDst, opSz, ofs); + GenExtendRegIfNeeded(regDst, opSz); +} + +void GenIncDecIndirect(int regDst, int regSrc, int opSz, int tok) +{ + int instr = MipsInstrAddU; + + if (tok != tokInc) + instr = MipsInstrSubU; + + GenReadIndirect(regDst, regSrc, opSz); + GenPrintInstr3Operands(instr, 0, + regDst, 0, + regDst, 0, + MipsOpConst, 1); + GenWriteIndirect(regSrc, regDst, opSz); + GenExtendRegIfNeeded(regDst, opSz); +} + +void GenPostIncDecIdent(int regDst, int opSz, int label, int tok) +{ + int instr = MipsInstrAddU; + + if (tok != tokPostInc) + instr = MipsInstrSubU; + + GenReadIdent(regDst, opSz, label); + GenPrintInstr3Operands(instr, 0, + regDst, 0, + regDst, 0, + MipsOpConst, 1); + GenWriteIdent(regDst, opSz, label); + GenPrintInstr3Operands(instr, 0, + regDst, 0, + regDst, 0, + MipsOpConst, -1); + GenExtendRegIfNeeded(regDst, opSz); +} + +void GenPostIncDecLocal(int regDst, int opSz, int ofs, int tok) +{ + int instr = MipsInstrAddU; + + if (tok != tokPostInc) + instr = MipsInstrSubU; + + GenReadLocal(regDst, opSz, ofs); + GenPrintInstr3Operands(instr, 0, + regDst, 0, + regDst, 0, + MipsOpConst, 1); + GenWriteLocal(regDst, opSz, ofs); + GenPrintInstr3Operands(instr, 0, + regDst, 0, + regDst, 0, + MipsOpConst, -1); + GenExtendRegIfNeeded(regDst, opSz); +} + +void GenPostIncDecIndirect(int regDst, int regSrc, int opSz, int tok) +{ + int instr = MipsInstrAddU; + + if (tok != tokPostInc) + instr = MipsInstrSubU; + + GenReadIndirect(regDst, regSrc, opSz); + GenPrintInstr3Operands(instr, 0, + regDst, 0, + regDst, 0, + MipsOpConst, 1); + GenWriteIndirect(regSrc, regDst, opSz); + GenPrintInstr3Operands(instr, 0, + regDst, 0, + regDst, 0, + MipsOpConst, -1); + GenExtendRegIfNeeded(regDst, opSz); +} + +int CanUseTempRegs; +int TempsUsed; + +void GenPushReg(int reg) +{ + if (CanUseTempRegs && TempsUsed < 6) + { + GenPrintInstr2Operands(MipsInstrMov, 0, + MipsOpRegT2 + TempsUsed, 0, + reg, 0); + TempsUsed++; + return; + } + + GenPrintInstr3Operands(MipsInstrSubU, 0, + MipsOpRegSp, 0, + MipsOpRegSp, 0, + MipsOpConst, 4); + + GenPrintInstr2Operands(MipsInstrSW, 0, + reg, 0, + MipsOpIndRegSp, 0); + + TempsUsed++; +} + +int GenPopReg(int reg) +{ + TempsUsed--; + + if (CanUseTempRegs && TempsUsed < 6) + { + return MipsOpRegT2 + TempsUsed; + } + + GenPrintInstr2Operands(MipsInstrLW, 0, + reg, 0, + MipsOpIndRegSp, 0); + + GenPrintInstr3Operands(MipsInstrAddU, 0, + MipsOpRegSp, 0, + MipsOpRegSp, 0, + MipsOpConst, 4); + return reg; +} + +// Original, primitive stack-based code generator +// DONE: test 32-bit code generation +void GenExpr0(void) +{ + int i; + int gotUnary = 0; + int maxCallDepth = 0; + int callDepth = 0; + int paramOfs = 0; + + for (i = 0; i < sp; i++) + if (stack[i][0] == '(') + { + if (++callDepth > maxCallDepth) + maxCallDepth = callDepth; + } + else if (stack[i][0] == ')') + { + callDepth--; + } + + CanUseTempRegs = maxCallDepth == 0; + TempsUsed = 0; + + for (i = 0; i < sp; i++) + { + int tok = stack[i][0]; + int v = stack[i][1]; + +#ifndef NO_ANNOTATIONS + switch (tok) + { + case tokNumInt: printf2(" # %d\n", truncInt(v)); break; + case tokNumUint: printf2(" # %uu\n", truncUint(v)); break; + case tokIdent: printf2(" # %s\n", IdentTable + v); break; + case tokLocalOfs: printf2(" # local ofs\n"); break; + case ')': printf2(" # ) fxn call\n"); break; + case tokUnaryStar: printf2(" # * (read dereference)\n"); break; + case '=': printf2(" # = (write dereference)\n"); break; + case tokShortCirc: printf2(" # short-circuit "); break; + case tokGoto: printf2(" # sh-circ-goto "); break; + case tokLogAnd: printf2(" # short-circuit && target\n"); break; + case tokLogOr: printf2(" # short-circuit || target\n"); break; + case tokIf: case tokIfNot: break; + default: printf2(" # %s\n", GetTokenName(tok)); break; + } +#endif + + switch (tok) + { + case tokNumInt: + case tokNumUint: + if (!(i + 1 < sp && (strchr("+-&^|", stack[i + 1][0]) || + stack[i + 1][0] == tokLShift || + stack[i + 1][0] == tokRShift || + stack[i + 1][0] == tokURShift))) + { + if (gotUnary) + GenPushReg(MipsOpRegV0); + + GenPrintInstr2Operands(MipsInstrLI, 0, + MipsOpRegV0, 0, + MipsOpConst, v); + } + gotUnary = 1; + break; + + case tokIdent: + if (gotUnary) + GenPushReg(MipsOpRegV0); + if (!(i + 1 < sp && (stack[i + 1][0] == ')' || + stack[i + 1][0] == tokUnaryStar || + stack[i + 1][0] == tokInc || + stack[i + 1][0] == tokDec || + stack[i + 1][0] == tokPostInc || + stack[i + 1][0] == tokPostDec))) + { + GenPrintInstr2Operands(MipsInstrLA, 0, + MipsOpRegV0, 0, + MipsOpLabel, v); + } + gotUnary = 1; + break; + + case tokLocalOfs: + if (gotUnary) + GenPushReg(MipsOpRegV0); + if (!(i + 1 < sp && (stack[i + 1][0] == tokUnaryStar || + stack[i + 1][0] == tokInc || + stack[i + 1][0] == tokDec || + stack[i + 1][0] == tokPostInc || + stack[i + 1][0] == tokPostDec))) + { + GenPrintInstr3Operands(MipsInstrAddU, 0, + MipsOpRegV0, 0, + MipsOpRegFp, 0, + MipsOpConst, v); + } + gotUnary = 1; + break; + + case '(': + if (gotUnary) + GenPushReg(MipsOpRegV0); + gotUnary = 0; + if (v < 16) + GenLocalAlloc(16 - v); + paramOfs = v - 4; + break; + + case ',': + if (maxCallDepth == 1) + { + if (paramOfs == 16) + { + GenPushReg(MipsOpRegV0); + gotUnary = 0; + } + if (paramOfs >= 0 && paramOfs <= 12) + { + GenPrintInstr2Operands(MipsInstrMov, 0, + MipsOpRegA0 + paramOfs / 4, 0, + MipsOpRegV0, 0); + gotUnary = 0; + } + paramOfs -= 4; + } + break; + + case ')': + if (maxCallDepth != 1) + { + if (v >= 4) + GenPrintInstr2Operands(MipsInstrLW, 0, + MipsOpRegA0, 0, + MipsOpIndRegSp, 0); + if (v >= 8) + GenPrintInstr2Operands(MipsInstrLW, 0, + MipsOpRegA1, 0, + MipsOpIndRegSp, 4); + if (v >= 12) + GenPrintInstr2Operands(MipsInstrLW, 0, + MipsOpRegA2, 0, + MipsOpIndRegSp, 8); + if (v >= 16) + GenPrintInstr2Operands(MipsInstrLW, 0, + MipsOpRegA3, 0, + MipsOpIndRegSp, 12); + } + else + { + int vv = v; + if (vv > 16) + vv = 16; + if (vv) + GenLocalAlloc(vv); + } + if (stack[i - 1][0] == tokIdent) + { + GenPrintInstr1Operand(MipsInstrJAL, 0, + MipsOpLabel, stack[i - 1][1]); + } + else + { + GenPrintInstr1Operand(MipsInstrJAL, 0, + MipsOpRegV0, 0); + } + if (v < 16) + v = 16; + GenLocalAlloc(-v); + break; + + case tokUnaryStar: + if (stack[i - 1][0] == tokIdent) + GenReadIdent(MipsOpRegV0, v, stack[i - 1][1]); + else if (stack[i - 1][0] == tokLocalOfs) + GenReadLocal(MipsOpRegV0, v, stack[i - 1][1]); + else + GenReadIndirect(MipsOpRegV0, MipsOpRegV0, v); + break; + + case tokUnaryPlus: + break; + case '~': + GenPrintInstr3Operands(MipsInstrNor, 0, + MipsOpRegV0, 0, + MipsOpRegV0, 0, + MipsOpRegV0, 0); + break; + case tokUnaryMinus: + GenPrintInstr3Operands(MipsInstrSubU, 0, + MipsOpRegV0, 0, + MipsOpRegZero, 0, + MipsOpRegV0, 0); + break; + + case '+': + case '-': + case '*': + case '&': + case '^': + case '|': + case tokLShift: + case tokRShift: + case tokURShift: + if ((stack[i - 1][0] == tokNumInt || stack[i - 1][0] == tokNumUint) && tok != '*') + { + int instr = GenGetBinaryOperatorInstr(tok); + GenPrintInstr3Operands(instr, 0, + MipsOpRegV0, 0, + MipsOpRegV0, 0, + MipsOpConst, stack[i - 1][1]); + } + else + { + int instr = GenGetBinaryOperatorInstr(tok); + int reg = GenPopReg(MipsOpRegT0); + GenPrintInstr3Operands(instr, 0, + MipsOpRegV0, 0, + reg, 0, + MipsOpRegV0, 0); + } + break; + + case '/': + case tokUDiv: + case '%': + case tokUMod: + { + int reg = GenPopReg(MipsOpRegT0); + if (tok == '/' || tok == '%') + GenPrintInstr2Operands(MipsInstrDiv, 0, + reg, 0, + MipsOpRegV0, 0); + else + GenPrintInstr2Operands(MipsInstrDivU, 0, + reg, 0, + MipsOpRegV0, 0); + if (tok == '%' || tok == tokUMod) + GenPrintInstr1Operand(MipsInstrMfHi, 0, + MipsOpRegV0, 0); + else + GenPrintInstr1Operand(MipsInstrMfLo, 0, + MipsOpRegV0, 0); + } + break; + + case tokInc: + case tokDec: + if (stack[i - 1][0] == tokIdent) + { + GenIncDecIdent(MipsOpRegV0, v, stack[i - 1][1], tok); + } + else if (stack[i - 1][0] == tokLocalOfs) + { + GenIncDecLocal(MipsOpRegV0, v, stack[i - 1][1], tok); + } + else + { + GenPrintInstr2Operands(MipsInstrMov, 0, + MipsOpRegT0, 0, + MipsOpRegV0, 0); + GenIncDecIndirect(MipsOpRegV0, MipsOpRegT0, v, tok); + } + break; + case tokPostInc: + case tokPostDec: + if (stack[i - 1][0] == tokIdent) + { + GenPostIncDecIdent(MipsOpRegV0, v, stack[i - 1][1], tok); + } + else if (stack[i - 1][0] == tokLocalOfs) + { + GenPostIncDecLocal(MipsOpRegV0, v, stack[i - 1][1], tok); + } + else + { + GenPrintInstr2Operands(MipsInstrMov, 0, + MipsOpRegT0, 0, + MipsOpRegV0, 0); + GenPostIncDecIndirect(MipsOpRegV0, MipsOpRegT0, v, tok); + } + break; + + case tokPostAdd: + case tokPostSub: + { + int instr = GenGetBinaryOperatorInstr(tok); + int reg = GenPopReg(MipsOpRegT0); + GenPrintInstr2Operands(MipsInstrMov, 0, + MipsOpRegT1, 0, + MipsOpRegV0, 0); + + GenReadIndirect(MipsOpRegV0, reg, v); + GenPrintInstr3Operands(instr, 0, + MipsOpRegT1, 0, + MipsOpRegT1, 0, + MipsOpRegV0, 0); + GenWriteIndirect(reg, MipsOpRegT1, v); + } + break; + + case tokAssignAdd: + case tokAssignSub: + case tokAssignMul: + case tokAssignAnd: + case tokAssignXor: + case tokAssignOr: + case tokAssignLSh: + case tokAssignRSh: + case tokAssignURSh: + { + int instr = GenGetBinaryOperatorInstr(tok); + int reg = GenPopReg(MipsOpRegT0); + GenPrintInstr2Operands(MipsInstrMov, 0, + MipsOpRegT1, 0, + MipsOpRegV0, 0); + + GenReadIndirect(MipsOpRegV0, reg, v); + GenPrintInstr3Operands(instr, 0, + MipsOpRegV0, 0, + MipsOpRegV0, 0, + MipsOpRegT1, 0); + GenWriteIndirect(reg, MipsOpRegV0, v); + + GenExtendRegIfNeeded(MipsOpRegV0, v); + } + break; + + case tokAssignDiv: + case tokAssignUDiv: + case tokAssignMod: + case tokAssignUMod: + { + int reg = GenPopReg(MipsOpRegT0); + + GenReadIndirect(MipsOpRegT1, reg, v); + if (tok == tokAssignDiv || tok == tokAssignMod) + GenPrintInstr2Operands(MipsInstrDiv, 0, + MipsOpRegT1, 0, + MipsOpRegV0, 0); + else + GenPrintInstr2Operands(MipsInstrDivU, 0, + MipsOpRegT1, 0, + MipsOpRegV0, 0); + if (tok == tokAssignMod || tok == tokAssignUMod) + GenPrintInstr1Operand(MipsInstrMfHi, 0, + MipsOpRegV0, 0); + else + GenPrintInstr1Operand(MipsInstrMfLo, 0, + MipsOpRegV0, 0); + GenWriteIndirect(reg, MipsOpRegV0, v); + + GenExtendRegIfNeeded(MipsOpRegV0, v); + } + break; + + case '=': + { + int reg = GenPopReg(MipsOpRegT0); + GenWriteIndirect(reg, MipsOpRegV0, v); + GenExtendRegIfNeeded(MipsOpRegV0, v); + } + break; + +/* + i = il < ir; // i = slt(il, ir); + i = il <= ir; // i = slt(ir, il) ^ 1; + i = il > ir; // i = slt(ir, il); + i = il >= ir; // i = slt(il, ir) ^ 1; + i = il == ir; // i = sltu(il ^ ir, 1); + i = il != ir; // i = sltu(0, il ^ ir); +*/ + case '<': + { + int reg = GenPopReg(MipsOpRegT0); + GenPrintInstr3Operands(MipsInstrSLT, 0, + MipsOpRegV0, 0, + reg, 0, + MipsOpRegV0, 0); + } + break; + case tokULess: + { + int reg = GenPopReg(MipsOpRegT0); + GenPrintInstr3Operands(MipsInstrSLTU, 0, + MipsOpRegV0, 0, + reg, 0, + MipsOpRegV0, 0); + } + break; + case '>': + { + int reg = GenPopReg(MipsOpRegT0); + GenPrintInstr3Operands(MipsInstrSLT, 0, + MipsOpRegV0, 0, + MipsOpRegV0, 0, + reg, 0); + } + break; + case tokUGreater: + { + int reg = GenPopReg(MipsOpRegT0); + GenPrintInstr3Operands(MipsInstrSLTU, 0, + MipsOpRegV0, 0, + MipsOpRegV0, 0, + reg, 0); + } + break; + case tokLEQ: + { + int reg = GenPopReg(MipsOpRegT0); + GenPrintInstr3Operands(MipsInstrSLT, 0, + MipsOpRegV0, 0, + MipsOpRegV0, 0, + reg, 0); + GenPrintInstr3Operands(MipsInstrXor, 0, + MipsOpRegV0, 0, + MipsOpRegV0, 0, + MipsOpConst, 1); + } + break; + case tokULEQ: + { + int reg = GenPopReg(MipsOpRegT0); + GenPrintInstr3Operands(MipsInstrSLTU, 0, + MipsOpRegV0, 0, + MipsOpRegV0, 0, + reg, 0); + GenPrintInstr3Operands(MipsInstrXor, 0, + MipsOpRegV0, 0, + MipsOpRegV0, 0, + MipsOpConst, 1); + } + break; + case tokGEQ: + { + int reg = GenPopReg(MipsOpRegT0); + GenPrintInstr3Operands(MipsInstrSLT, 0, + MipsOpRegV0, 0, + reg, 0, + MipsOpRegV0, 0); + GenPrintInstr3Operands(MipsInstrXor, 0, + MipsOpRegV0, 0, + MipsOpRegV0, 0, + MipsOpConst, 1); + } + break; + case tokUGEQ: + { + int reg = GenPopReg(MipsOpRegT0); + GenPrintInstr3Operands(MipsInstrSLTU, 0, + MipsOpRegV0, 0, + reg, 0, + MipsOpRegV0, 0); + GenPrintInstr3Operands(MipsInstrXor, 0, + MipsOpRegV0, 0, + MipsOpRegV0, 0, + MipsOpConst, 1); + } + break; + case tokEQ: + { + int reg = GenPopReg(MipsOpRegT0); + GenPrintInstr3Operands(MipsInstrXor, 0, + MipsOpRegV0, 0, + reg, 0, + MipsOpRegV0, 0); + GenPrintInstr3Operands(MipsInstrSLTU, 0, + MipsOpRegV0, 0, + MipsOpRegV0, 0, + MipsOpConst, 1); + } + break; + case tokNEQ: + { + int reg = GenPopReg(MipsOpRegT0); + GenPrintInstr3Operands(MipsInstrXor, 0, + MipsOpRegV0, 0, + reg, 0, + MipsOpRegV0, 0); + GenPrintInstr3Operands(MipsInstrSLTU, 0, + MipsOpRegV0, 0, + MipsOpRegZero, 0, + MipsOpRegV0, 0); + } + break; + + case tok_Bool: + GenPrintInstr3Operands(MipsInstrSLTU, 0, + MipsOpRegV0, 0, + MipsOpRegZero, 0, + MipsOpRegV0, 0); + break; + + case tokSChar: + GenPrintInstr3Operands(MipsInstrSLL, 0, + MipsOpRegV0, 0, + MipsOpRegV0, 0, + MipsOpConst, 24); + GenPrintInstr3Operands(MipsInstrSRA, 0, + MipsOpRegV0, 0, + MipsOpRegV0, 0, + MipsOpConst, 24); + break; + case tokUChar: + GenPrintInstr3Operands(MipsInstrAnd, 0, + MipsOpRegV0, 0, + MipsOpRegV0, 0, + MipsOpConst, 0xFF); + break; + case tokShort: + GenPrintInstr3Operands(MipsInstrSLL, 0, + MipsOpRegV0, 0, + MipsOpRegV0, 0, + MipsOpConst, 16); + GenPrintInstr3Operands(MipsInstrSRA, 0, + MipsOpRegV0, 0, + MipsOpRegV0, 0, + MipsOpConst, 16); + break; + case tokUShort: + GenPrintInstr3Operands(MipsInstrAnd, 0, + MipsOpRegV0, 0, + MipsOpRegV0, 0, + MipsOpConst, 0xFFFF); + break; + + case tokShortCirc: +#ifndef NO_ANNOTATIONS + if (v >= 0) + printf2("&&\n"); + else + printf2("||\n"); +#endif + if (v >= 0) + GenJumpIfZero(v); // && + else + GenJumpIfNotZero(-v); // || + gotUnary = 0; + break; + case tokGoto: +#ifndef NO_ANNOTATIONS + printf2("goto\n"); +#endif + GenJumpUncond(v); + gotUnary = 0; + break; + case tokLogAnd: + case tokLogOr: + GenNumLabel(v); + break; + + case tokVoid: + gotUnary = 0; + break; + + case tokComma: + break; + + case tokIf: + GenJumpIfNotZero(stack[i][1]); + break; + case tokIfNot: + GenJumpIfZero(stack[i][1]); + break; + + default: + //error("Error: Internal Error: GenExpr0(): unexpected token %s\n", GetTokenName(tok)); + errorInternal(102); + break; + } + } +} + +unsigned GenStrData(int generatingCode, unsigned requiredLen) +{ + int i; + unsigned total = 0; + + // insert string literals into the code + for (i = 0; i < sp; i++) + { + int tok = stack[i][0]; + char* p = IdentTable + stack[i][1]; + if (tok == tokIdent && isdigit(*p)) + { + int label = atoi(p); + unsigned len; + + p = FindString(label); + len = *p++; + + // If this is a string literal initializing an array of char, + // truncate or pad it as necessary. + if (requiredLen) + { + if (len >= requiredLen) + { + len = requiredLen; // copy count + requiredLen = 0; // count to be zeroed out + } + else + { + requiredLen -= len; // count to be zeroed out + } + } + // Also, calculate its real size for incompletely typed arrays. + total = len + requiredLen; + + if (generatingCode) + { + if (OutputFormat == FormatFlat) + { + GenJumpUncond(label + 1); + } + else + { + puts2(CodeFooter); + puts2(DataHeader); + } + } + + GenNumLabel(label); + + GenStartAsciiString(); + printf2("\""); + while (len--) + { + // quote ASCII chars for better readability + if (*p >= 0x20 && *p <= 0x7E) + { + if (*p == '\"' || *p == '\\') + printf2("\\"); + printf2("%c", *p); + } + else + { + printf2("\\%03o", *p & 0xFFu); + } + p++; + } + while (requiredLen) + { + printf2("\\000"); + requiredLen--; + } + printf2("\""); + puts2(""); + + if (generatingCode) + { + if (OutputFormat == FormatFlat) + { + GenNumLabel(label + 1); + } + else + { + puts2(DataFooter); + puts2(CodeHeader); + } + } + } + } + + return total; +} + +void GenExpr(void) +{ + GenStrData(1, 0); + GenExpr0(); +} + +void GenFin(void) +{ + if (StructCpyLabel) + { + char s[1 + 2 + (2 + CHAR_BIT * sizeof StructCpyLabel) / 3]; + char *p = s + sizeof s; + int lbl = LabelCnt++; + + *--p = '\0'; + p = lab2str(p, StructCpyLabel); + *--p = '_'; + *--p = '_'; + + if (OutputFormat != FormatFlat) + puts2(CodeHeader); + + GenLabel(p, 1); + + puts2("\tmove\t$2, $6\n" + "\tmove\t$3, $6"); + GenNumLabel(lbl); + puts2("\tlbu\t$6, 0($5)\n" + "\taddiu\t$5, $5, 1\n" + "\taddiu\t$4, $4, -1\n" + "\tsb\t$6, 0($3)\n" + "\taddiu\t$3, $3, 1"); + printf2("\tbne\t$4, $0, "); GenPrintNumLabel(lbl); + puts2(""); +#ifndef NO_REORDER_WORKAROUND + GenNop(); +#endif + puts2("\tj\t$31"); +#ifndef NO_REORDER_WORKAROUND + GenNop(); +#endif + + if (OutputFormat != FormatFlat) + puts2(CodeFooter); + } +} diff --git a/src/cmd/smlrc/cgx86.c b/src/cmd/smlrc/cgx86.c new file mode 100644 index 0000000..250dcab --- /dev/null +++ b/src/cmd/smlrc/cgx86.c @@ -0,0 +1,3221 @@ +/* +Copyright (c) 2012-2014, Alexey Frunze +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +The views and conclusions contained in the software and documentation are those +of the authors and should not be interpreted as representing official policies, +either expressed or implied, of the FreeBSD Project. +*/ + +/*****************************************************************************/ +/* */ +/* Smaller C */ +/* */ +/* A simple and small single-pass C compiler ("small C" class). */ +/* */ +/* x86 code generator */ +/* */ +/*****************************************************************************/ + +// TBD!!! compress/clean up + +#define MAX_GLOBALS_TABLE_LEN MAX_IDENT_TABLE_LEN + +/* + Globals table entry format: + use char: use: bit 0 = defined, bit 1 = used + idlen char: string length (<= 127) + id char[idlen]: string (ASCIIZ) +*/ +char GlobalsTable[MAX_GLOBALS_TABLE_LEN]; +int GlobalsTableLen = 0; + +void GenAddGlobal(char* s, int use) +{ + int i = 0; + int l; + if (OutputFormat != FormatFlat && GenExterns) + { + while (i < GlobalsTableLen) + { + if (!strcmp(GlobalsTable + i + 2, s)) + { + GlobalsTable[i] |= use; + return; + } + i += GlobalsTable[i + 1] + 2; + } + l = strlen(s) + 1; + if (GlobalsTableLen + l + 2 > MAX_GLOBALS_TABLE_LEN) + error("Table of globals exhausted\n"); + GlobalsTable[GlobalsTableLen++] = use; + GlobalsTable[GlobalsTableLen++] = l; + memcpy(GlobalsTable + GlobalsTableLen, s, l); + GlobalsTableLen += l; + } +} + +void GenInit(void) +{ + // initialization of target-specific code generator + SizeOfWord = 2; + OutputFormat = FormatSegTurbo; + UseLeadingUnderscores = 1; +} + +int GenInitParams(int argc, char** argv, int* idx) +{ + (void)argc; + // initialization of target-specific code generator with parameters + + if (!strcmp(argv[*idx], "-seg16t")) + { + // this is the default option for x86 + OutputFormat = FormatSegTurbo; SizeOfWord = 2; + return 1; + } + else if (!strcmp(argv[*idx], "-seg16")) + { + OutputFormat = FormatSegmented; SizeOfWord = 2; + return 1; + } + else if (!strcmp(argv[*idx], "-flat16")) + { + OutputFormat = FormatFlat; SizeOfWord = 2; + return 1; + } +#ifdef CAN_COMPILE_32BIT + else if (!strcmp(argv[*idx], "-seg32")) + { + OutputFormat = FormatSegmented; SizeOfWord = 4; + return 1; + } + else if (!strcmp(argv[*idx], "-flat32")) + { + OutputFormat = FormatFlat; SizeOfWord = 4; + return 1; + } + else if (!strcmp(argv[*idx], "-huge")) + { + OutputFormat = FormatSegHuge; SizeOfWord = 4; + return 1; + } +#endif + + return 0; +} + +void GenInitFinalize(void) +{ + // finalization of initialization of target-specific code generator + + // Change the output assembly format/content according to the options + if (OutputFormat == FormatSegTurbo) + { + FileHeader = "SEGMENT _TEXT PUBLIC CLASS=CODE USE16\n" + "SEGMENT _DATA PUBLIC CLASS=DATA\n"; + CodeHeader = "SEGMENT _TEXT"; + CodeFooter = "; SEGMENT _TEXT"; + DataHeader = "SEGMENT _DATA"; + DataFooter = "; SEGMENT _DATA"; + } + else + { + if (OutputFormat == FormatSegmented || OutputFormat == FormatSegHuge) + { + CodeHeader = "section .text"; + DataHeader = "section .data"; + } + if (SizeOfWord == 2 || OutputFormat == FormatSegHuge) + FileHeader = "bits 16\n"; + else + FileHeader = "bits 32\n"; + } +} + +void GenStartCommentLine(void) +{ + printf2("; "); +} + +void GenWordAlignment(void) +{ + printf2("\talign %d\n", SizeOfWord); +} + +void GenLabel(char* Label, int Static) +{ + if (UseLeadingUnderscores) + { + if (OutputFormat != FormatFlat && !Static && GenExterns) + printf2("\tglobal\t_%s\n", Label); + printf2("_%s:\n", Label); + } + else + { + if (OutputFormat != FormatFlat && !Static && GenExterns) + printf2("\tglobal\t$%s\n", Label); + printf2("$%s:\n", Label); + } + GenAddGlobal(Label, 1); +} + +void GenPrintLabel(char* Label) +{ + if (UseLeadingUnderscores) + { + if (isdigit(*Label)) + printf2("L%s", Label); + else + printf2("_%s", Label); + } + else + { + if (isdigit(*Label)) + printf2("..@L%s", Label); + else + printf2("$%s", Label); + } +} + +void GenNumLabel(int Label) +{ + if (UseLeadingUnderscores) + printf2("L%d:\n", Label); + else + printf2("..@L%d:\n", Label); +} + +void GenPrintNumLabel(int label) +{ + if (UseLeadingUnderscores) + printf2("L%d", label); + else + printf2("..@L%d", label); +} + +void GenZeroData(unsigned Size) +{ + printf2("\ttimes\t%u db 0\n", truncUint(Size)); +} + +void GenIntData(int Size, int Val) +{ + Val = truncInt(Val); + if (Size == 1) + printf2("\tdb\t%d\n", Val); + else if (Size == 2) + printf2("\tdw\t%d\n", Val); +#ifdef CAN_COMPILE_32BIT + else if (Size == 4) + printf2("\tdd\t%d\n", Val); +#endif +} + +void GenStartAsciiString(void) +{ + printf2("\tdb\t"); +} + +void GenAddrData(int Size, char* Label) +{ +#ifdef CAN_COMPILE_32BIT + if (OutputFormat == FormatSegHuge) + { + int lab = LabelCnt++; + printf2("section .relod\n\tdd\t"); GenPrintNumLabel(lab); puts2(""); + puts2(DataHeader); + GenNumLabel(lab); + } +#endif + if (Size == 1) + printf2("\tdb\t"); + else if (Size == 2) + printf2("\tdw\t"); +#ifdef CAN_COMPILE_32BIT + else if (Size == 4) + printf2("\tdd\t"); +#endif + GenPrintLabel(Label); puts2(""); + if (!isdigit(*Label)) + GenAddGlobal(Label, 2); +} + +#define X86InstrMov 0x00 +#define X86InstrMovSx 0x01 +#define X86InstrMovZx 0x02 +#define X86InstrXchg 0x03 +#define X86InstrLea 0x04 +#define X86InstrPush 0x05 +#define X86InstrPop 0x06 +#define X86InstrInc 0x07 +#define X86InstrDec 0x08 +#define X86InstrAdd 0x09 +#define X86InstrSub 0x0A +#define X86InstrAnd 0x0B +#define X86InstrXor 0x0C +#define X86InstrOr 0x0D +#define X86InstrCmp 0x0E +#define X86InstrTest 0x0F +#define X86InstrMul 0x10 +#define X86InstrImul 0x11 +#define X86InstrIdiv 0x12 +#define X86InstrDiv 0x13 +#define X86InstrShl 0x14 +#define X86InstrSar 0x15 +#define X86InstrShr 0x16 +#define X86InstrNeg 0x17 +#define X86InstrNot 0x18 +#define X86InstrCbw 0x19 +#define X86InstrCwd 0x1A +#define X86InstrCdq 0x1B +#define X86InstrSetCc 0x1C +#define X86InstrJcc 0x1D +#define X86InstrJNotCc 0x1E +#define X86InstrLeave 0x1F +#define X86InstrCall 0x20 +#define X86InstrRet 0x21 +#define X86InstrJmp 0x22 + +char* winstrs[] = +{ + "mov", + "movsx", + "movzx", + "xchg", + "lea", + "push", + "pop", + "inc", + "dec", + "add", + "sub", + "and", + "xor", + "or", + "cmp", + "test", + "mul", + "imul", + "idiv", + "div", + "shl", + "sar", + "shr", + "neg", + "not", + "cbw", + "cwd", + "cdq", + 0, // setcc + 0, // jcc + 0, // j!cc + 0, // leave + "call", + 0, // ret + "jmp", +}; + +void GenPrintInstr(int instr, int val) +{ + char* p = ""; + + switch (instr) + { + case X86InstrLeave: p = (OutputFormat != FormatSegHuge) ? "leave" : "db\t0x66\n\tleave"; break; + + case X86InstrRet: p = (OutputFormat != FormatSegHuge) ? "ret" : "retf"; break; + + case X86InstrJcc: + switch (val) + { + case '<': p = "jl"; break; + case tokULess: p = "jb"; break; + case '>': p = "jg"; break; + case tokUGreater: p = "ja"; break; + case tokLEQ: p = "jle"; break; + case tokULEQ: p = "jbe"; break; + case tokGEQ: p = "jge"; break; + case tokUGEQ: p = "jae"; break; + case tokEQ: p = "je"; break; + case tokNEQ: p = "jne"; break; + } + break; + case X86InstrJNotCc: + switch (val) + { + case '<': p = "jge"; break; + case tokULess: p = "jae"; break; + case '>': p = "jle"; break; + case tokUGreater: p = "jbe"; break; + case tokLEQ: p = "jg"; break; + case tokULEQ: p = "ja"; break; + case tokGEQ: p = "jl"; break; + case tokUGEQ: p = "jb"; break; + case tokEQ: p = "jne"; break; + case tokNEQ: p = "je"; break; + } + break; + + case X86InstrSetCc: + switch (val) + { + case '<': p = "setl"; break; + case tokULess: p = "setb"; break; + case '>': p = "setg"; break; + case tokUGreater: p = "seta"; break; + case tokLEQ: p = "setle"; break; + case tokULEQ: p = "setbe"; break; + case tokGEQ: p = "setge"; break; + case tokUGEQ: p = "setae"; break; + case tokEQ: p = "sete"; break; + case tokNEQ: p = "setne"; break; + } + break; + + default: + p = winstrs[instr]; + break; + } + + switch (instr) + { + case X86InstrCbw: + case X86InstrCwd: +#ifdef CAN_COMPILE_32BIT + case X86InstrCdq: +#endif + case X86InstrLeave: + case X86InstrRet: + printf2("\t%s", p); + break; + default: + printf2("\t%s\t", p); + break; + } +} + +#define X86OpRegAByte 0x00 +#define X86OpRegAByteHigh 0x01 +#define X86OpRegCByte 0x02 +#define X86OpRegAWord 0x03 +#define X86OpRegBWord 0x04 +#define X86OpRegCWord 0x05 +#define X86OpRegDWord 0x06 +#define X86OpRegAHalfWord 0x07 +#define X86OpRegCHalfWord 0x08 +#define X86OpRegBpWord 0x09 +#define X86OpRegSpWord 0x0A +#define X86OpRegAByteOrWord 0x0B +#define X86OpRegCByteOrWord 0x0C +#define X86OpConst 0x0D +#define X86OpLabel 0x0E +#define X86OpNumLabel 0x0F +#define X86OpIndLabel 0x10 +#define X86OpIndLabelExplicitByte 0x11 +#define X86OpIndLabelExplicitWord 0x12 +#define X86OpIndLabelExplicitHalfWord 0x13 +#define X86OpIndLabelExplicitByteOrWord 0x14 +#define X86OpIndLocal 0x15 +#define X86OpIndLocalExplicitByte 0x16 +#define X86OpIndLocalExplicitWord 0x17 +#define X86OpIndLocalExplicitHalfWord 0x18 +#define X86OpIndLocalExplicitByteOrWord 0x19 +#define X86OpIndRegB 0x1A +#define X86OpIndRegBExplicitByte 0x1B +#define X86OpIndRegBExplicitWord 0x1C +#define X86OpIndRegBExplicitHalfWord 0x1D +#define X86OpIndRegBExplicitByteOrWord 0x1E + +int GenSelectByteOrWord(int op, int opSz) +{ + switch (op) + { + case X86OpRegAByteOrWord: + op = X86OpRegAByte; + if (opSz == SizeOfWord) + op = X86OpRegAWord; +#ifdef CAN_COMPILE_32BIT + else if (opSz == 2 || opSz == -2) + op = X86OpRegAHalfWord; +#endif + break; + case X86OpRegCByteOrWord: + op = X86OpRegCByte; + if (opSz == SizeOfWord) + op = X86OpRegCWord; +#ifdef CAN_COMPILE_32BIT + else if (opSz == 2 || opSz == -2) + op = X86OpRegCHalfWord; +#endif + break; + case X86OpIndLabelExplicitByteOrWord: + op = X86OpIndLabelExplicitByte; + if (opSz == SizeOfWord) + op = X86OpIndLabelExplicitWord; +#ifdef CAN_COMPILE_32BIT + else if (opSz == 2 || opSz == -2) + op = X86OpIndLabelExplicitHalfWord; +#endif + break; + case X86OpIndLocalExplicitByteOrWord: + op = X86OpIndLocalExplicitByte; + if (opSz == SizeOfWord) + op = X86OpIndLocalExplicitWord; +#ifdef CAN_COMPILE_32BIT + else if (opSz == 2 || opSz == -2) + op = X86OpIndLocalExplicitHalfWord; +#endif + break; + case X86OpIndRegBExplicitByteOrWord: + op = X86OpIndRegBExplicitByte; + if (opSz == SizeOfWord) + op = X86OpIndRegBExplicitWord; +#ifdef CAN_COMPILE_32BIT + else if (opSz == 2 || opSz == -2) + op = X86OpIndRegBExplicitHalfWord; +#endif + break; + } + return op; +} + +void GenPrintOperand(int op, int val) +{ + if (SizeOfWord == 2) + { + switch (op) + { + case X86OpRegAByte: printf2("al"); break; + case X86OpRegAByteHigh: printf2("ah"); break; + case X86OpRegCByte: printf2("cl"); break; + case X86OpRegAWord: printf2("ax"); break; + case X86OpRegBWord: printf2("bx"); break; + case X86OpRegCWord: printf2("cx"); break; + case X86OpRegDWord: printf2("dx"); break; + case X86OpRegBpWord: printf2("bp"); break; + case X86OpRegSpWord: printf2("sp"); break; + case X86OpConst: printf2("%d", truncInt(val)); break; + case X86OpLabel: GenPrintLabel(IdentTable + val); break; + case X86OpNumLabel: GenPrintNumLabel(val); break; + case X86OpIndLabel: printf2("["); GenPrintLabel(IdentTable + val); printf2("]"); break; + case X86OpIndLabelExplicitByte: printf2("byte ["); GenPrintLabel(IdentTable + val); printf2("]"); break; + case X86OpIndLabelExplicitWord: printf2("word ["); GenPrintLabel(IdentTable + val); printf2("]"); break; + case X86OpIndLocal: printf2("[bp%+d]", truncInt(val)); break; + case X86OpIndLocalExplicitByte: printf2("byte [bp%+d]", truncInt(val)); break; + case X86OpIndLocalExplicitWord: printf2("word [bp%+d]", truncInt(val)); break; + case X86OpIndRegB: printf2("[bx]"); break; + case X86OpIndRegBExplicitByte: printf2("byte [bx]"); break; + case X86OpIndRegBExplicitWord: printf2("word [bx]"); break; + } + } +#ifdef CAN_COMPILE_32BIT + else + { + char* frame = (OutputFormat == FormatSegHuge) ? "bp" : "ebp"; + char* base = (OutputFormat == FormatSegHuge) ? "bx" : "ebx"; + switch (op) + { + case X86OpRegAByte: printf2("al"); break; + case X86OpRegAByteHigh: printf2("ah"); break; + case X86OpRegCByte: printf2("cl"); break; + case X86OpRegAWord: printf2("eax"); break; + case X86OpRegBWord: printf2("ebx"); break; + case X86OpRegCWord: printf2("ecx"); break; + case X86OpRegDWord: printf2("edx"); break; + case X86OpRegAHalfWord: printf2("ax"); break; + case X86OpRegCHalfWord: printf2("cx"); break; + case X86OpRegBpWord: printf2("ebp"); break; + case X86OpRegSpWord: printf2("esp"); break; + case X86OpConst: printf2("%d", truncInt(val)); break; + case X86OpLabel: GenPrintLabel(IdentTable + val); break; + case X86OpNumLabel: GenPrintNumLabel(val); break; + case X86OpIndLabel: printf2("["); GenPrintLabel(IdentTable + val); printf2("]"); break; + case X86OpIndLabelExplicitByte: printf2("byte ["); GenPrintLabel(IdentTable + val); printf2("]"); break; + case X86OpIndLabelExplicitWord: printf2("dword ["); GenPrintLabel(IdentTable + val); printf2("]"); break; + case X86OpIndLabelExplicitHalfWord: printf2("word ["); GenPrintLabel(IdentTable + val); printf2("]"); break; + case X86OpIndLocal: printf2("[%s%+d]", frame, truncInt(val)); break; + case X86OpIndLocalExplicitByte: printf2("byte [%s%+d]", frame, truncInt(val)); break; + case X86OpIndLocalExplicitWord: printf2("dword [%s%+d]", frame, truncInt(val)); break; + case X86OpIndLocalExplicitHalfWord: printf2("word [%s%+d]", frame, truncInt(val)); break; + case X86OpIndRegB: printf2("[%s]", base); break; + case X86OpIndRegBExplicitByte: printf2("byte [%s]", base); break; + case X86OpIndRegBExplicitWord: printf2("dword [%s]", base); break; + case X86OpIndRegBExplicitHalfWord: printf2("word [%s]", base); break; + } + } +#endif +} + +void GenPrintOperandSeparator(void) +{ + printf2(", "); +} + +void GenPrintNewLine(void) +{ + puts2(""); +} + +void GenPrintInstrNoOperand(int instr) +{ + GenPrintInstr(instr, 0); + GenPrintNewLine(); +} + +#ifdef CAN_COMPILE_32BIT +void GenSaveRestoreRegB(int restore) +{ + if (OutputFormat == FormatSegHuge) + puts2(restore ? "\tpop\tebx" : "\tpush\tebx"); +} + +void GenRegB2Seg(void) +{ + if (OutputFormat == FormatSegHuge) + puts2("\tror\tebx, 4\n\tmov\tds, bx\n\tshr\tebx, 28"); +} +#endif + +void GenPrintInstr1Operand(int instr, int instrval, int operand, int operandval) +{ +#ifdef CAN_COMPILE_32BIT + if (OutputFormat == FormatSegHuge && instr == X86InstrPush) + { + if (operand == X86OpConst) + { + printf2("\tpush\tdword %d\n", truncInt(operandval)); + return; + } + else if (operand == X86OpLabel) + { + int lab = LabelCnt++; + printf2("section .relod\n\tdd\t"); GenPrintNumLabel(lab); puts2(""); + puts2(CodeHeader); + puts2("\tdb\t0x66, 0x68"); // push dword const + GenNumLabel(lab); + printf2("\tdd\t"); GenPrintLabel(IdentTable + operandval); puts2(""); + return; + } + } +#endif + + GenPrintInstr(instr, instrval); + GenPrintOperand(operand, operandval); + GenPrintNewLine(); +} + +void GenPrintInstr2Operands(int instr, int instrval, int operand1, int operand1val, int operand2, int operand2val) +{ + if (operand2 == X86OpConst && truncUint(operand2val) == 0 && + (instr == X86InstrAdd || instr == X86InstrSub)) + return; + +#ifdef CAN_COMPILE_32BIT + if (OutputFormat == FormatSegHuge) + { + if (instr == X86InstrLea) + { + if (operand2 == X86OpIndLocal) + { + if (operand1 == X86OpRegAWord) + { + puts2("\txor\teax, eax\n\tmov\tax, ss"); // mov r32, sreg leaves top 16 bits undefined on pre-Pentium CPUs + printf2("\tshl\teax, 4\n\tlea\teax, [ebp+eax%+d]\n", truncInt(operand2val)); + return; + } + else if (operand1 == X86OpRegCWord) + { + puts2("\txor\tecx, ecx\n\tmov\tcx, ss"); // mov r32, sreg leaves top 16 bits undefined on pre-Pentium CPUs + printf2("\tshl\tecx, 4\n\tlea\tecx, [ebp+ecx%+d]\n", truncInt(operand2val)); + return; + } + } + errorInternal(106); + } + if (instr == X86InstrMov) + { + if (operand1 == X86OpRegAWord && operand2 == X86OpLabel) + { + int lab = LabelCnt++; + printf2("section .relod\n\tdd\t"); GenPrintNumLabel(lab); puts2(""); + puts2(CodeHeader); + puts2("\tdb\t0x66, 0xB8"); // mov eax, const + GenNumLabel(lab); + printf2("\tdd\t"); GenPrintLabel(IdentTable + operand2val); puts2(""); + return; + } + } + } +#endif + + if (operand2 == X86OpConst && + (operand2val == 1 || operand2val == -1) && + (instr == X86InstrAdd || instr == X86InstrSub)) + { + if ((operand2val == 1 && instr == X86InstrAdd) || + (operand2val == -1 && instr == X86InstrSub)) + GenPrintInstr(X86InstrInc, 0); + else + GenPrintInstr(X86InstrDec, 0); + GenPrintOperand(operand1, operand1val); + GenPrintNewLine(); + return; + } + + GenPrintInstr(instr, instrval); + GenPrintOperand(operand1, operand1val); + GenPrintOperandSeparator(); + GenPrintOperand(operand2, operand2val); + GenPrintNewLine(); +} + +void GenPrintInstr3Operands(int instr, int instrval, + int operand1, int operand1val, + int operand2, int operand2val, + int operand3, int operand3val) +{ + GenPrintInstr(instr, instrval); + GenPrintOperand(operand1, operand1val); + GenPrintOperandSeparator(); + GenPrintOperand(operand2, operand2val); + GenPrintOperandSeparator(); + GenPrintOperand(operand3, operand3val); + GenPrintNewLine(); +} + +void GenExtendRegAIfNeeded(int opSz) +{ + if (SizeOfWord == 2) + { + if (opSz == -1) + GenPrintInstrNoOperand(X86InstrCbw); + else if (opSz == 1) + GenPrintInstr2Operands(X86InstrMov, 0, + X86OpRegAByteHigh, 0, + X86OpConst, 0); + } +#ifdef CAN_COMPILE_32BIT + else + { + if (opSz == -1) + GenPrintInstr2Operands(X86InstrMovSx, 0, + X86OpRegAWord, 0, + X86OpRegAByte, 0); + else if (opSz == 1) + GenPrintInstr2Operands(X86InstrMovZx, 0, + X86OpRegAWord, 0, + X86OpRegAByte, 0); + else if (opSz == -2) + GenPrintInstr2Operands(X86InstrMovSx, 0, + X86OpRegAWord, 0, + X86OpRegAHalfWord, 0); + else if (opSz == 2) + GenPrintInstr2Operands(X86InstrMovZx, 0, + X86OpRegAWord, 0, + X86OpRegAHalfWord, 0); + } +#endif +} + +void GenJumpUncond(int label) +{ + GenPrintInstr1Operand(X86InstrJmp, 0, + X86OpNumLabel, label); +} + +void GenJumpIfNotEqual(int val, int label) +{ + GenPrintInstr2Operands(X86InstrCmp, 0, + X86OpRegAWord, 0, + X86OpConst, val); + GenPrintInstr1Operand(X86InstrJcc, tokNEQ, + X86OpNumLabel, label); +} + +void GenJumpIfZero(int label) +{ +#ifndef NO_ANNOTATIONS + GenStartCommentLine(); printf2("JumpIfZero\n"); +#endif + GenPrintInstr2Operands(X86InstrTest, 0, + X86OpRegAWord, 0, + X86OpRegAWord, 0); + GenPrintInstr1Operand(X86InstrJcc, tokEQ, + X86OpNumLabel, label); +} + +void GenJumpIfNotZero(int label) +{ +#ifndef NO_ANNOTATIONS + GenStartCommentLine(); printf2("JumpIfNotZero\n"); +#endif + GenPrintInstr2Operands(X86InstrTest, 0, + X86OpRegAWord, 0, + X86OpRegAWord, 0); + GenPrintInstr1Operand(X86InstrJcc, tokNEQ, + X86OpNumLabel, label); +} + +void GenFxnProlog(void) +{ + GenPrintInstr1Operand(X86InstrPush, 0, + X86OpRegBpWord, 0); + GenPrintInstr2Operands(X86InstrMov, 0, + X86OpRegBpWord, 0, + X86OpRegSpWord, 0); +} + +void GenLocalAlloc(int size) +{ + GenPrintInstr2Operands(X86InstrSub, 0, + X86OpRegSpWord, 0, + X86OpConst, size); +} + +void GenFxnEpilog(void) +{ + GenPrintInstrNoOperand(X86InstrLeave); + GenPrintInstrNoOperand(X86InstrRet); +} + +void GenReadIdent(int opSz, int label) +{ + GenPrintInstr2Operands(X86InstrMov, 0, + GenSelectByteOrWord(X86OpRegAByteOrWord, opSz), 0, + X86OpIndLabel, label); + GenExtendRegAIfNeeded(opSz); +} + +void GenReadLocal(int opSz, int ofs) +{ + GenPrintInstr2Operands(X86InstrMov, 0, + GenSelectByteOrWord(X86OpRegAByteOrWord, opSz), 0, + X86OpIndLocal, ofs); + GenExtendRegAIfNeeded(opSz); +} + +void GenReadIndirect(int opSz) +{ + GenPrintInstr2Operands(X86InstrMov, 0, + X86OpRegBWord, 0, + X86OpRegAWord, 0); +#ifdef CAN_COMPILE_32BIT + GenSaveRestoreRegB(0); + GenRegB2Seg(); +#endif + GenPrintInstr2Operands(X86InstrMov, 0, + GenSelectByteOrWord(X86OpRegAByteOrWord, opSz), 0, + X86OpIndRegB, 0); +#ifdef CAN_COMPILE_32BIT + GenSaveRestoreRegB(1); +#endif + GenExtendRegAIfNeeded(opSz); +} + +void GenReadCRegIdent(int opSz, int label) +{ + if (opSz == -1) + GenPrintInstr2Operands(X86InstrMovSx, 0, + X86OpRegCWord, 0, + X86OpIndLabelExplicitByte, label); + else if (opSz == 1) + GenPrintInstr2Operands(X86InstrMovZx, 0, + X86OpRegCWord, 0, + X86OpIndLabelExplicitByte, label); +#ifdef CAN_COMPILE_32BIT + else if (opSz != SizeOfWord && -opSz != SizeOfWord) + { + if (opSz == -2) + GenPrintInstr2Operands(X86InstrMovSx, 0, + X86OpRegCWord, 0, + X86OpIndLabelExplicitHalfWord, label); + else if (opSz == 2) + GenPrintInstr2Operands(X86InstrMovZx, 0, + X86OpRegCWord, 0, + X86OpIndLabelExplicitHalfWord, label); + } +#endif + else + GenPrintInstr2Operands(X86InstrMov, 0, + X86OpRegCWord, 0, + X86OpIndLabel, label); +} + +void GenReadCRegLocal(int opSz, int ofs) +{ + if (opSz == -1) + GenPrintInstr2Operands(X86InstrMovSx, 0, + X86OpRegCWord, 0, + X86OpIndLocalExplicitByte, ofs); + else if (opSz == 1) + GenPrintInstr2Operands(X86InstrMovZx, 0, + X86OpRegCWord, 0, + X86OpIndLocalExplicitByte, ofs); +#ifdef CAN_COMPILE_32BIT + else if (opSz != SizeOfWord && -opSz != SizeOfWord) + { + if (opSz == -2) + GenPrintInstr2Operands(X86InstrMovSx, 0, + X86OpRegCWord, 0, + X86OpIndLocalExplicitHalfWord, ofs); + else if (opSz == 2) + GenPrintInstr2Operands(X86InstrMovZx, 0, + X86OpRegCWord, 0, + X86OpIndLocalExplicitHalfWord, ofs); + } +#endif + else + GenPrintInstr2Operands(X86InstrMov, 0, + X86OpRegCWord, 0, + X86OpIndLocal, ofs); +} + +void GenReadCRegIndirect(int opSz) +{ + GenPrintInstr2Operands(X86InstrMov, 0, + X86OpRegBWord, 0, + X86OpRegAWord, 0); +#ifdef CAN_COMPILE_32BIT + GenSaveRestoreRegB(0); + GenRegB2Seg(); +#endif + if (opSz == -1) + GenPrintInstr2Operands(X86InstrMovSx, 0, + X86OpRegCWord, 0, + X86OpIndRegBExplicitByte, 0); + else if (opSz == 1) + GenPrintInstr2Operands(X86InstrMovZx, 0, + X86OpRegCWord, 0, + X86OpIndRegBExplicitByte, 0); +#ifdef CAN_COMPILE_32BIT + else if (opSz != SizeOfWord && -opSz != SizeOfWord) + { + if (opSz == -2) + GenPrintInstr2Operands(X86InstrMovSx, 0, + X86OpRegCWord, 0, + X86OpIndRegBExplicitHalfWord, 0); + else if (opSz == 2) + GenPrintInstr2Operands(X86InstrMovZx, 0, + X86OpRegCWord, 0, + X86OpIndRegBExplicitHalfWord, 0); + } +#endif + else + GenPrintInstr2Operands(X86InstrMov, 0, + X86OpRegCWord, 0, + X86OpIndRegB, 0); +#ifdef CAN_COMPILE_32BIT + GenSaveRestoreRegB(1); +#endif +} + +void GenIncDecIdent(int opSz, int label, int tok) +{ + int instr = X86InstrInc; + + if (tok != tokInc) + instr = X86InstrDec; + + GenPrintInstr1Operand(instr, 0, + GenSelectByteOrWord(X86OpIndLabelExplicitByteOrWord, opSz), label); + GenPrintInstr2Operands(X86InstrMov, 0, + GenSelectByteOrWord(X86OpRegAByteOrWord, opSz), 0, + X86OpIndLabel, label); + GenExtendRegAIfNeeded(opSz); +} + +void GenIncDecLocal(int opSz, int ofs, int tok) +{ + int instr = X86InstrInc; + + if (tok != tokInc) + instr = X86InstrDec; + + GenPrintInstr1Operand(instr, 0, + GenSelectByteOrWord(X86OpIndLocalExplicitByteOrWord, opSz), ofs); + GenPrintInstr2Operands(X86InstrMov, 0, + GenSelectByteOrWord(X86OpRegAByteOrWord, opSz), 0, + X86OpIndLocal, ofs); + GenExtendRegAIfNeeded(opSz); +} + +void GenIncDecIndirect(int opSz, int tok) +{ + int instr = X86InstrInc; + + if (tok != tokInc) + instr = X86InstrDec; + + GenPrintInstr2Operands(X86InstrMov, 0, + X86OpRegBWord, 0, + X86OpRegAWord, 0); +#ifdef CAN_COMPILE_32BIT + GenSaveRestoreRegB(0); + GenRegB2Seg(); +#endif + GenPrintInstr1Operand(instr, 0, + GenSelectByteOrWord(X86OpIndRegBExplicitByteOrWord, opSz), 0); + GenPrintInstr2Operands(X86InstrMov, 0, + GenSelectByteOrWord(X86OpRegAByteOrWord, opSz), 0, + X86OpIndRegB, 0); +#ifdef CAN_COMPILE_32BIT + GenSaveRestoreRegB(1); +#endif + GenExtendRegAIfNeeded(opSz); +} + +void GenPostIncDecIdent(int opSz, int label, int tok) +{ + int instr = X86InstrInc; + + if (tok != tokPostInc) + instr = X86InstrDec; + + GenPrintInstr2Operands(X86InstrMov, 0, + GenSelectByteOrWord(X86OpRegAByteOrWord, opSz), 0, + X86OpIndLabel, label); + GenExtendRegAIfNeeded(opSz); + GenPrintInstr1Operand(instr, 0, + GenSelectByteOrWord(X86OpIndLabelExplicitByteOrWord, opSz), label); +} + +void GenPostIncDecLocal(int opSz, int ofs, int tok) +{ + int instr = X86InstrInc; + + if (tok != tokPostInc) + instr = X86InstrDec; + + GenPrintInstr2Operands(X86InstrMov, 0, + GenSelectByteOrWord(X86OpRegAByteOrWord, opSz), 0, + X86OpIndLocal, ofs); + GenExtendRegAIfNeeded(opSz); + GenPrintInstr1Operand(instr, 0, + GenSelectByteOrWord(X86OpIndLocalExplicitByteOrWord, opSz), ofs); +} + +void GenPostIncDecIndirect(int opSz, int tok) +{ + int instr = X86InstrInc; + + if (tok != tokPostInc) + instr = X86InstrDec; + + GenPrintInstr2Operands(X86InstrMov, 0, + X86OpRegBWord, 0, + X86OpRegAWord, 0); +#ifdef CAN_COMPILE_32BIT + GenSaveRestoreRegB(0); + GenRegB2Seg(); +#endif + GenPrintInstr2Operands(X86InstrMov, 0, + GenSelectByteOrWord(X86OpRegAByteOrWord, opSz), 0, + X86OpIndRegB, 0); + GenExtendRegAIfNeeded(opSz); + GenPrintInstr1Operand(instr, 0, + GenSelectByteOrWord(X86OpIndRegBExplicitByteOrWord, opSz), 0); +#ifdef CAN_COMPILE_32BIT + GenSaveRestoreRegB(1); +#endif +} + +void GenPostAddSubIdent(int opSz, int val, int label, int tok) +{ + int instr = X86InstrAdd; + + if (tok != tokPostAdd) + instr = X86InstrSub; + + GenPrintInstr2Operands(X86InstrMov, 0, + GenSelectByteOrWord(X86OpRegAByteOrWord, opSz), 0, + X86OpIndLabel, label); + GenExtendRegAIfNeeded(opSz); + GenPrintInstr2Operands(instr, 0, + GenSelectByteOrWord(X86OpIndLabelExplicitByteOrWord, opSz), label, + X86OpConst, val); +} + +void GenPostAddSubLocal(int opSz, int val, int ofs, int tok) +{ + int instr = X86InstrAdd; + + if (tok != tokPostAdd) + instr = X86InstrSub; + + GenPrintInstr2Operands(X86InstrMov, 0, + GenSelectByteOrWord(X86OpRegAByteOrWord, opSz), 0, + X86OpIndLocal, ofs); + GenExtendRegAIfNeeded(opSz); + GenPrintInstr2Operands(instr, 0, + GenSelectByteOrWord(X86OpIndLocalExplicitByteOrWord, opSz), ofs, + X86OpConst, val); +} + +void GenPostAddSubIndirect(int opSz, int val, int tok) +{ + int instr = X86InstrAdd; + + if (tok != tokPostAdd) + instr = X86InstrSub; + + GenPrintInstr2Operands(X86InstrMov, 0, + X86OpRegBWord, 0, + X86OpRegAWord, 0); +#ifdef CAN_COMPILE_32BIT + GenSaveRestoreRegB(0); + GenRegB2Seg(); +#endif + GenPrintInstr2Operands(X86InstrMov, 0, + GenSelectByteOrWord(X86OpRegAByteOrWord, opSz), 0, + X86OpIndRegB, 0); + GenExtendRegAIfNeeded(opSz); + GenPrintInstr2Operands(instr, 0, + GenSelectByteOrWord(X86OpIndRegBExplicitByteOrWord, opSz), 0, + X86OpConst, val); +#ifdef CAN_COMPILE_32BIT + GenSaveRestoreRegB(1); +#endif +} + +#define tokOpNumInt 0x100 +#define tokOpNumUint 0x101 +#define tokOpIdent 0x102 +#define tokOpLocalOfs 0x103 +#define tokOpAcc 0x104 +#define tokOpIndIdent 0x105 +#define tokOpIndLocalOfs 0x106 +#define tokOpIndAcc 0x107 +#define tokOpStack 0x108 +#define tokOpIndStack 0x109 + +#define tokPushAcc 0x200 + +int GetOperandInfo(int idx, int lvalSize, int* val, int* size, int* delDeref) +{ + int idx0 = idx; + + *delDeref = 0; + + while (stack[idx][0] >= tokOpNumInt && stack[idx][0] <= tokOpIndAcc) + idx--; + + if (stack[idx][0] == tokUnaryStar) + { + if (lvalSize) + { + // lvalue dereference is implied for the left operand of = + // and for operands of ++/--, these operands contain the + // lvalue address + *size = lvalSize; + *val = 0; + return tokOpIndAcc; + } + + *size = stack[idx][1]; // take size from tokUnaryStar + + *delDeref = 1; + *val = stack[idx + 1][1]; // operand "value" is in tokUnaryStar's operand + return stack[idx + 1][0] + tokOpIndIdent - tokOpIdent; // add indirection + } + + idx = idx0; + + if (lvalSize) + { + // lvalue dereference is implied for the left operand of = + // and for operands of ++/-- + *size = lvalSize; + *val = stack[idx][1]; + + switch (stack[idx][0]) + { + case tokIdent: +#ifdef CAN_COMPILE_32BIT + if (OutputFormat == FormatSegHuge) + goto l1; +#endif + return tokOpIndIdent; + case tokLocalOfs: + return tokOpIndLocalOfs; + + default: +#ifdef CAN_COMPILE_32BIT +l1: +#endif + *val = 0; + return tokOpIndAcc; + } + } + + *size = SizeOfWord; + *val = stack[idx][1]; + + switch (stack[idx][0]) + { + case tokNumInt: + return tokOpNumInt; + case tokNumUint: + return tokOpNumUint; + case tokIdent: +#ifdef CAN_COMPILE_32BIT + if (OutputFormat == FormatSegHuge) + goto l2; +#endif + return tokOpIdent; + case tokLocalOfs: + return tokOpLocalOfs; + + default: +#ifdef CAN_COMPILE_32BIT +l2: +#endif + *val = 0; + return tokOpAcc; + } +} + +void GenFuse(int* idx) +{ + int tok; + int oldIdxRight, oldSpRight; + int oldIdxLeft, oldSpLeft; + int opSzRight, opSzLeft; + int opTypRight, opTypLeft; + int opValRight, opValLeft; + int delDerefRight, delDerefLeft; + int num, lvalSize; + + if (*idx < 0) + //error("GenFuse(): idx < 0\n"); + errorInternal(100); + + tok = stack[*idx][0]; + + --*idx; + + oldIdxRight = *idx; + oldSpRight = sp; + + switch (tok) + { + case tokNumInt: + case tokNumUint: + case tokIdent: + case tokLocalOfs: + break; + + case tokShortCirc: + case tokGoto: + GenFuse(idx); + break; + + case tokUnaryStar: + opSzRight = stack[*idx + 1][1]; + GenFuse(idx); + oldIdxRight -= oldSpRight - sp; + + switch (stack[oldIdxRight][0]) + { + case tokIdent: +#ifdef CAN_COMPILE_32BIT + if (OutputFormat == FormatSegHuge) + goto l1; +#endif + case tokLocalOfs: + if (stack[oldIdxRight][0] == tokIdent) + stack[oldIdxRight + 1][0] = tokOpIdent; + else + stack[oldIdxRight + 1][0] = tokOpLocalOfs; + stack[oldIdxRight + 1][1] = stack[oldIdxRight][1]; + stack[oldIdxRight][0] = tok; + stack[oldIdxRight][1] = opSzRight; + break; + default: +#ifdef CAN_COMPILE_32BIT +l1: +#endif + ins(oldIdxRight + 2, tokOpAcc); + break; + } + break; + + case tokInc: + case tokDec: + case tokPostInc: + case tokPostDec: + opSzRight = stack[*idx + 1][1]; + GenFuse(idx); + oldIdxRight -= oldSpRight - sp; + + switch (stack[oldIdxRight][0]) + { + case tokIdent: +#ifdef CAN_COMPILE_32BIT + if (OutputFormat == FormatSegHuge) + goto l2; +#endif + case tokLocalOfs: + if (stack[oldIdxRight][0] == tokIdent) + stack[oldIdxRight + 1][0] = tokOpIndIdent; + else + stack[oldIdxRight + 1][0] = tokOpIndLocalOfs; + stack[oldIdxRight + 1][1] = stack[oldIdxRight][1]; + stack[oldIdxRight][0] = tok; + stack[oldIdxRight][1] = opSzRight; + break; + default: +#ifdef CAN_COMPILE_32BIT +l2: +#endif + ins(oldIdxRight + 2, tokOpIndAcc); + break; + } + break; + + case '~': + case tokUnaryPlus: + case tokUnaryMinus: + case tok_Bool: + case tokVoid: + case tokUChar: + case tokSChar: +#ifdef CAN_COMPILE_32BIT + case tokShort: + case tokUShort: +#endif + GenFuse(idx); + oldIdxRight -= oldSpRight - sp; + if (tok == tokUnaryPlus) + del(oldIdxRight + 1, 1); + break; + + case tokPostAdd: + case tokPostSub: + opSzRight = stack[*idx + 1][1]; + num = stack[*idx][1]; + oldIdxRight = --*idx; // skip tokNum + GenFuse(idx); + oldIdxRight -= oldSpRight - sp; + switch (stack[oldIdxRight][0]) + { + case tokIdent: +#ifdef CAN_COMPILE_32BIT + if (OutputFormat == FormatSegHuge) + goto l3; +#endif + case tokLocalOfs: + stack[oldIdxRight + 2][0] = tokOpNumInt; + stack[oldIdxRight + 2][1] = num; + if (stack[oldIdxRight][0] == tokIdent) + stack[oldIdxRight + 1][0] = tokOpIndIdent; + else + stack[oldIdxRight + 1][0] = tokOpIndLocalOfs; + stack[oldIdxRight + 1][1] = stack[oldIdxRight][1]; + stack[oldIdxRight][0] = tok; + stack[oldIdxRight][1] = opSzRight; + break; + default: +#ifdef CAN_COMPILE_32BIT +l3: +#endif + stack[oldIdxRight + 1][0] = tok; + stack[oldIdxRight + 1][1] = opSzRight; + stack[oldIdxRight + 2][0] = tokOpIndAcc; + ins2(oldIdxRight + 3, tokOpNumInt, num); + break; + } + break; + +/* + Operator-operand fusion: + + ac = lft: ac op= rht: lft = ac: + (load) ("execute") (store) + + *(id/l) *(id/l) *(id/l) + mov a?,mlft op a?,mrht mov mlft,a? + --- + mov cl,mrht + shift ax,cl + --- + mov c?,mrht + cwd + idiv cx + opt: mov ax,dx + + *ac *ac *ac + mov bx,ax < mov bx,ax ; bx preserved + mov a?,[bx] < mov c?,[bx] mov [bx],a? + op ax,cx(cl) + + *ac-stack n/a *ac-stack + pop bx ; bx preserved + mov a?,[bx] mov [bx],a? + + id/num id/num + mov ax,ilft op ax,irht + --- + mov cx,irht + op ax,cx + + l l + lea ax,llft lea cx,lrht + op ax,cx + + ac ac + nop < mov cx,ax + op ax,cx + + ac-stack n/a + pop ax + + lft (*)ac -> lft (*)ac-stack IFF rht is (*)ac + + Legend: + - lft/rht - left/right operand + - num - number + - id - global/static identifier/location + - l - local variable location + - * - dereference operator + - m - memory operand at address id/l + - i - immediate/number/constant operand + - ac - accumulator (al or ax) + - a? - accumulator (al or ax), depending on operand size + - b? - bl or bx, depending on operand size + - >push axlft - need to insert "push ax" at the end of the left operand evaluation + + instruction operand combinations (dst/lft, src/rht): + - r/m, r/imm + - r, m + + special instructions: + - lea r, m + - shl/sar + - mul/imul/idiv + - cbw/cwd + - movsx/movzx +*/ + + case '=': + case tokAssignAdd: + case tokAssignSub: + case tokAssignMul: + case tokAssignDiv: + case tokAssignUDiv: + case tokAssignMod: + case tokAssignUMod: + case tokAssignLSh: + case tokAssignRSh: + case tokAssignURSh: + case tokAssignAnd: + case tokAssignXor: + case tokAssignOr: + case '+': + case '-': + case '*': + case '/': + case tokUDiv: + case '%': + case tokUMod: + case tokLShift: + case tokRShift: + case tokURShift: + case '&': + case '^': + case '|': + case '<': + case '>': + case tokLEQ: + case tokGEQ: + case tokEQ: + case tokNEQ: + case tokULess: + case tokUGreater: + case tokULEQ: + case tokUGEQ: + case tokLogAnd: + case tokLogOr: + case tokComma: + switch (tok) + { + case '=': + case tokAssignAdd: + case tokAssignSub: + case tokAssignMul: + case tokAssignDiv: + case tokAssignUDiv: + case tokAssignMod: + case tokAssignUMod: + case tokAssignLSh: + case tokAssignRSh: + case tokAssignURSh: + case tokAssignAnd: + case tokAssignXor: + case tokAssignOr: + lvalSize = stack[*idx + 1][1]; + break; + default: + lvalSize = 0; + break; + } + + GenFuse(idx); + oldIdxRight -= oldSpRight - sp; + opTypRight = GetOperandInfo(oldIdxRight, 0, &opValRight, &opSzRight, &delDerefRight); + + oldIdxLeft = *idx; oldSpLeft = sp; + GenFuse(idx); + oldIdxLeft -= oldSpLeft - sp; + oldIdxRight -= oldSpLeft - sp; + opTypLeft = GetOperandInfo(oldIdxLeft, lvalSize, &opValLeft, &opSzLeft, &delDerefLeft); + + // operands of &&, || and comma aren't to be fused into &&, || and comma + if (tok == tokLogAnd || tok == tokLogOr || tok == tokComma) + break; + + if (opTypLeft != tokOpAcc && opTypLeft != tokOpIndAcc) + { + // the left operand will be fully fused into the operator, remove it + int cnt = oldIdxLeft - *idx; + del(*idx + 1, cnt); + oldIdxLeft -= cnt; + oldIdxRight -= cnt; + } + else if (opTypRight == tokOpAcc || opTypRight == tokOpIndAcc) + { + // preserve ax after the evaluation of the left operand + // because the right operand's value ends up in ax as well + ins(++oldIdxLeft, tokPushAcc); + oldIdxRight++; + // adjust the left operand "type"/location + if (opTypLeft == tokOpAcc) + opTypLeft = tokOpStack; + else + opTypLeft = tokOpIndStack; + if (delDerefLeft) + { + // remove the dereference, fusing will take care of it + del(oldIdxLeft -= 2, 2); + oldIdxRight -= 2; + } + } + else if (delDerefLeft) + { + // remove the dereference, fusing will take care of it + del(oldIdxLeft - 1, 2); + oldIdxLeft -= 2; + oldIdxRight -= 2; + } + + if (opTypRight != tokOpAcc && opTypRight != tokOpIndAcc) + { + // the right operand will be fully fused into the operator, remove it + int cnt = oldIdxRight - oldIdxLeft; + del(oldIdxLeft + 1, cnt); + oldIdxRight -= cnt; + } + else if (delDerefRight) + { + // remove the dereference, fusing will take care of it + del(oldIdxRight - 1, 2); + oldIdxRight -= 2; + } + + // store the operand sizes into the operator + stack[oldIdxRight + 1][1] = (opSzLeft + 8) * 16 + (opSzRight + 8); + + // fuse the operands into the operator + ins2(oldIdxRight + 2, opTypRight, opValRight); + ins2(oldIdxRight + 2, opTypLeft, opValLeft); + break; + + case ')': + while (stack[*idx][0] != '(') + { + GenFuse(idx); + if (stack[*idx][0] == ',') + --*idx; + } + --*idx; + break; + + default: + //error("GenFuse: unexpected token %s\n", GetTokenName(tok)); + errorInternal(101); + } +} + +int GenGetBinaryOperatorInstr(int tok) +{ + switch (tok) + { + case tokPostAdd: + case tokAssignAdd: + case '+': + return X86InstrAdd; + case tokPostSub: + case tokAssignSub: + case '-': + return X86InstrSub; + case '&': + case tokAssignAnd: + return X86InstrAnd; + case '^': + case tokAssignXor: + return X86InstrXor; + case '|': + case tokAssignOr: + return X86InstrOr; + case '<': + case '>': + case tokLEQ: + case tokGEQ: + case tokEQ: + case tokNEQ: + case tokULess: + case tokUGreater: + case tokULEQ: + case tokUGEQ: + return X86InstrCmp; + case '*': + case tokAssignMul: + return X86InstrMul; + case '/': + case '%': + case tokAssignDiv: + case tokAssignMod: + return X86InstrIdiv; + case tokUDiv: + case tokUMod: + case tokAssignUDiv: + case tokAssignUMod: + return X86InstrDiv; + case tokLShift: + case tokAssignLSh: + return X86InstrShl; + case tokRShift: + case tokAssignRSh: + return X86InstrSar; + case tokURShift: + case tokAssignURSh: + return X86InstrShr; + + default: + //error("Error: Invalid operator\n"); + errorInternal(102); + return 0; + } +} + +// Newer, less stack-dependent code generator, +// generates more compact code (~30% less) than the stack-based generator +#ifndef CG_STACK_BASED +void GenExpr1(void) +{ + int s = sp - 1; + int i; + + if (stack[s][0] == tokIf || stack[s][0] == tokIfNot) + s--; + GenFuse(&s); + +#ifndef NO_ANNOTATIONS + printf2("; Fused expression: \""); + for (i = 0; i < sp; i++) + { + int tok = stack[i][0]; + switch (tok) + { + case tokNumInt: + case tokOpNumInt: + printf2("%d", truncInt(stack[i][1])); + break; + case tokNumUint: + case tokOpNumUint: + printf2("%uu", truncUint(stack[i][1])); + break; + case tokIdent: + case tokOpIdent: + { + char* p = IdentTable + stack[i][1]; + if (isdigit(*p)) + printf2("L"); + printf2("%s", p); + } + break; + case tokOpIndIdent: + printf2("*%s", IdentTable + stack[i][1]); + break; + case tokShortCirc: + if (stack[i][1] >= 0) + printf2("[sh&&->%d]", stack[i][1]); + else + printf2("[sh||->%d]", -stack[i][1]); + break; + case tokGoto: + printf2("[goto->%d]", stack[i][1]); + break; + case tokLocalOfs: + case tokOpLocalOfs: + printf2("(@%d)", truncInt(stack[i][1])); + break; + case tokOpIndLocalOfs: + printf2("*(@%d)", truncInt(stack[i][1])); + break; + case tokUnaryStar: + printf2("*(%d)", stack[i][1]); + break; + case '(': case ',': + printf2("%c", tok); + break; + case ')': + printf2(")%d", stack[i][1]); + break; + case tokOpAcc: + printf2("ax"); + break; + case tokOpIndAcc: + printf2("*ax"); + break; + case tokOpStack: + printf2("*sp"); + break; + case tokOpIndStack: + printf2("**sp"); + break; + case tokPushAcc: + printf2("push-ax"); + break; + case tokIf: + printf2("IF"); + break; + case tokIfNot: + printf2("IF!"); + break; + default: + printf2("%s", GetTokenName(tok)); + switch (tok) + { + case tokLogOr: case tokLogAnd: + printf2("[%d]", stack[i][1]); + break; + case '=': + case tokInc: case tokDec: + case tokPostInc: case tokPostDec: + case tokAssignAdd: case tokAssignSub: + case tokPostAdd: case tokPostSub: + case tokAssignMul: case tokAssignDiv: case tokAssignMod: + case tokAssignUDiv: case tokAssignUMod: + case tokAssignLSh: case tokAssignRSh: case tokAssignURSh: + case tokAssignAnd: case tokAssignXor: case tokAssignOr: + printf2("(%d)", stack[i][1]); + break; + } + break; + } + printf2(" "); + } + printf2("\"\n"); +#endif + + for (i = 0; i < sp; i++) + { + int tok = stack[i][0]; + int v = stack[i][1]; + int instr; + + switch (tok) + { + case tokNumInt: + case tokNumUint: + // Don't load operand into ax when ax is going to be pushed next, push it directly + if (!(i + 1 < sp && stack[i + 1][0] == ',')) + GenPrintInstr2Operands(X86InstrMov, 0, + X86OpRegAWord, 0, + X86OpConst, v); + break; + case tokIdent: + // Don't load operand into ax when ax is going to be pushed next, push it directly + if (!(i + 1 < sp && (stack[i + 1][0] == ',' || stack[i + 1][0] == ')'))) + GenPrintInstr2Operands(X86InstrMov, 0, + X86OpRegAWord, 0, + X86OpLabel, v); + break; + case tokLocalOfs: + GenPrintInstr2Operands(X86InstrLea, 0, + X86OpRegAWord, 0, + X86OpIndLocal, v); + break; + + case '~': + GenPrintInstr1Operand(X86InstrNot, 0, + X86OpRegAWord, 0); + break; + case tokUnaryMinus: + GenPrintInstr1Operand(X86InstrNeg, 0, + X86OpRegAWord, 0); + break; + case tok_Bool: + GenPrintInstr2Operands(X86InstrTest, 0, + X86OpRegAWord, 0, + X86OpRegAWord, 0); + GenPrintInstr1Operand(X86InstrSetCc, tokNEQ, + X86OpRegAByte, 0); + // fallthrough + case tokSChar: + if (SizeOfWord == 2) + GenPrintInstrNoOperand(X86InstrCbw); +#ifdef CAN_COMPILE_32BIT + else + GenPrintInstr2Operands(X86InstrMovSx, 0, + X86OpRegAWord, 0, + X86OpRegAByte, 0); +#endif + break; + case tokUChar: + GenPrintInstr2Operands(X86InstrAnd, 0, + X86OpRegAWord, 0, + X86OpConst, 0xFF); + break; +#ifdef CAN_COMPILE_32BIT + case tokShort: + GenPrintInstr2Operands(X86InstrMovSx, 0, + X86OpRegAWord, 0, + X86OpRegAHalfWord, 0); + break; + case tokUShort: + GenPrintInstr2Operands(X86InstrMovZx, 0, + X86OpRegAWord, 0, + X86OpRegAHalfWord, 0); + break; +#endif + + case tokShortCirc: + if (v >= 0) + GenJumpIfZero(v); // && + else + GenJumpIfNotZero(-v); // || + break; + case tokGoto: + GenJumpUncond(v); + break; + case tokLogAnd: + case tokLogOr: + GenNumLabel(v); + break; + + case tokPushAcc: + // TBD??? handle similarly to ','??? + GenPrintInstr1Operand(X86InstrPush, 0, + X86OpRegAWord, 0); + break; + + case ',': + // push operand directly if it hasn't been loaded into ax + if (stack[i - 2][0] == tokUnaryStar && stack[i - 2][1] == SizeOfWord) + { + switch (stack[i - 1][0]) + { + case tokOpIdent: + GenPrintInstr1Operand(X86InstrPush, 0, + X86OpIndLabelExplicitWord, stack[i - 1][1]); + break; + case tokOpLocalOfs: + GenPrintInstr1Operand(X86InstrPush, 0, + X86OpIndLocalExplicitWord, stack[i - 1][1]); + break; + case tokOpAcc: + GenPrintInstr2Operands(X86InstrMov, 0, + X86OpRegBWord, 0, + X86OpRegAWord, 0); +#ifdef CAN_COMPILE_32BIT + GenRegB2Seg(); +#endif + GenPrintInstr1Operand(X86InstrPush, 0, + X86OpIndRegBExplicitWord, 0); + break; + } + } + else + { + switch (stack[i - 1][0]) + { + case tokNumInt: + case tokNumUint: + GenPrintInstr1Operand(X86InstrPush, 0, + X86OpConst, stack[i - 1][1]); + break; + case tokIdent: + GenPrintInstr1Operand(X86InstrPush, 0, + X86OpLabel, stack[i - 1][1]); + break; + default: + GenPrintInstr1Operand(X86InstrPush, 0, + X86OpRegAWord, 0); + break; + } + } + break; + + case tokUnaryStar: + // Don't load operand into ax when ax is going to be pushed next, push it directly + if (!(v == SizeOfWord && i + 2 < sp && stack[i + 2][0] == ',')) + { + switch (stack[i + 1][0]) + { + case tokOpIdent: + GenReadIdent(v, stack[i + 1][1]); + break; + case tokOpLocalOfs: + GenReadLocal(v, stack[i + 1][1]); + break; + case tokOpAcc: + GenReadIndirect(v); + break; + } + } + i++; + break; + + case tokInc: + case tokDec: + switch (stack[i + 1][0]) + { + case tokOpIndIdent: + GenIncDecIdent(v, stack[i + 1][1], tok); + break; + case tokOpIndLocalOfs: + GenIncDecLocal(v, stack[i + 1][1], tok); + break; + case tokOpIndAcc: + GenIncDecIndirect(v, tok); + break; + } + i++; + break; + + case tokPostInc: + case tokPostDec: + switch (stack[i + 1][0]) + { + case tokOpIndIdent: + GenPostIncDecIdent(v, stack[i + 1][1], tok); + break; + case tokOpIndLocalOfs: + GenPostIncDecLocal(v, stack[i + 1][1], tok); + break; + case tokOpIndAcc: + GenPostIncDecIndirect(v, tok); + break; + } + i++; + break; + + case tokPostAdd: + case tokPostSub: + switch (stack[i + 1][0]) + { + case tokOpIndIdent: + GenPostAddSubIdent(v, stack[i + 2][1], stack[i + 1][1], tok); + break; + case tokOpIndLocalOfs: + GenPostAddSubLocal(v, stack[i + 2][1], stack[i + 1][1], tok); + break; + case tokOpIndAcc: + GenPostAddSubIndirect(v, stack[i + 2][1], tok); + break; + } + i += 2; + break; + + case '=': + case tokAssignAdd: + case tokAssignSub: + case tokAssignMul: + case tokAssignDiv: + case tokAssignUDiv: + case tokAssignMod: + case tokAssignUMod: + case tokAssignLSh: + case tokAssignRSh: + case tokAssignURSh: + case tokAssignAnd: + case tokAssignXor: + case tokAssignOr: + case '+': + case '-': + case '*': + case '/': + case tokUDiv: + case '%': + case tokUMod: + case tokLShift: + case tokRShift: + case tokURShift: + case '&': + case '^': + case '|': + case '<': + case '>': + case tokLEQ: + case tokGEQ: + case tokEQ: + case tokNEQ: + case tokULess: + case tokUGreater: + case tokULEQ: + case tokUGEQ: + // save the right operand from ax in cx, so it's not + // overwritten by the left operand in ax + if (tok != '=') + { + if (stack[i + 2][0] == tokOpAcc) + { + GenPrintInstr2Operands(X86InstrMov, 0, + X86OpRegCWord, 0, + X86OpRegAWord, 0); + } + else if (stack[i + 2][0] == tokOpIndAcc) + { + GenReadCRegIndirect(v % 16 - 8); + } + } + + // load the left operand into ax (or the right operand if it's '=') + + if (tok == '=') + { + if (stack[i + 1][0] == tokOpIndAcc) + GenPrintInstr2Operands(X86InstrMov, 0, + X86OpRegBWord, 0, + X86OpRegAWord, 0); + // "swap" left and right operands + i++; + v = v / 16 + v % 16 * 16; + } + + switch (stack[i + 1][0]) + { + case tokOpNumInt: + case tokOpNumUint: + GenPrintInstr2Operands(X86InstrMov, 0, + X86OpRegAWord, 0, + X86OpConst, stack[i + 1][1]); + break; + case tokOpIdent: + GenPrintInstr2Operands(X86InstrMov, 0, + X86OpRegAWord, 0, + X86OpLabel, stack[i + 1][1]); + break; + case tokOpLocalOfs: + GenPrintInstr2Operands(X86InstrLea, 0, + X86OpRegAWord, 0, + X86OpIndLocal, stack[i + 1][1]); + break; + case tokOpAcc: + break; + case tokOpIndIdent: + GenReadIdent(v / 16 - 8, stack[i + 1][1]); + break; + case tokOpIndLocalOfs: + GenReadLocal(v / 16 - 8, stack[i + 1][1]); + break; + case tokOpIndAcc: + GenReadIndirect(v / 16 - 8); + break; + case tokOpStack: + GenPrintInstr1Operand(X86InstrPop, 0, + X86OpRegAWord, 0); + break; + case tokOpIndStack: + GenPrintInstr1Operand(X86InstrPop, 0, + X86OpRegBWord, 0); +#ifdef CAN_COMPILE_32BIT + GenSaveRestoreRegB(0); + GenRegB2Seg(); +#endif + GenPrintInstr2Operands(X86InstrMov, 0, + GenSelectByteOrWord(X86OpRegAByteOrWord, v / 16 - 8), 0, + X86OpIndRegB, 0); +#ifdef CAN_COMPILE_32BIT + GenSaveRestoreRegB(1); +#endif + GenExtendRegAIfNeeded(v / 16 - 8); + break; + } + + if (tok == '=') + { + // "unswap" left and right operands + i--; + v = v / 16 + v % 16 * 16; + + if (stack[i + 1][0] == tokOpIndStack) + GenPrintInstr1Operand(X86InstrPop, 0, + X86OpRegBWord, 0); + } + + // operator + switch (tok) + { + case tokAssignAdd: + case tokAssignSub: + case tokAssignAnd: + case tokAssignXor: + case tokAssignOr: + case '+': + case '-': + case '&': + case '^': + case '|': + case '<': + case '>': + case tokLEQ: + case tokGEQ: + case tokEQ: + case tokNEQ: + case tokULess: + case tokUGreater: + case tokULEQ: + case tokUGEQ: + instr = GenGetBinaryOperatorInstr(tok); + + switch (stack[i + 2][0]) + { + case tokOpNumInt: + case tokOpNumUint: + GenPrintInstr2Operands(instr, 0, + X86OpRegAWord, 0, + X86OpConst, stack[i + 2][1]); + break; + case tokOpIdent: + GenPrintInstr2Operands(instr, 0, + X86OpRegAWord, 0, + X86OpLabel, stack[i + 2][1]); + break; + case tokOpLocalOfs: + GenPrintInstr2Operands(X86InstrLea, 0, + X86OpRegCWord, 0, + X86OpIndLocal, stack[i + 2][1]); + GenPrintInstr2Operands(instr, 0, + X86OpRegAWord, 0, + X86OpRegCWord, 0); + break; + case tokOpAcc: + case tokOpIndAcc: + // right operand in cx already + GenPrintInstr2Operands(instr, 0, + X86OpRegAWord, 0, + X86OpRegCWord, 0); + break; + case tokOpIndIdent: + if (v % 16 - 8 != SizeOfWord) + { + GenReadCRegIdent(v % 16 - 8, stack[i + 2][1]); + GenPrintInstr2Operands(instr, 0, + X86OpRegAWord, 0, + X86OpRegCWord, 0); + } + else + { + GenPrintInstr2Operands(instr, 0, + X86OpRegAWord, 0, + X86OpIndLabel, stack[i + 2][1]); + } + break; + case tokOpIndLocalOfs: + if (v % 16 - 8 != SizeOfWord) + { + GenReadCRegLocal(v % 16 - 8, stack[i + 2][1]); + GenPrintInstr2Operands(instr, 0, + X86OpRegAWord, 0, + X86OpRegCWord, 0); + } + else + { + GenPrintInstr2Operands(instr, 0, + X86OpRegAWord, 0, + X86OpIndLocal, stack[i + 2][1]); + } + break; + } + + if (i + 3 < sp && (stack[i + 3][0] == tokIf || stack[i + 3][0] == tokIfNot)) + { + switch (tok) + { + case '<': + case tokULess: + case '>': + case tokUGreater: + case tokLEQ: + case tokULEQ: + case tokGEQ: + case tokUGEQ: + case tokEQ: + case tokNEQ: + if (stack[i + 3][0] == tokIf) + GenPrintInstr1Operand(X86InstrJcc, tok, + X86OpNumLabel, stack[i + 3][1]); + else + GenPrintInstr1Operand(X86InstrJNotCc, tok, + X86OpNumLabel, stack[i + 3][1]); + break; + } + } + else + { + switch (tok) + { + case '<': + case tokULess: + case '>': + case tokUGreater: + case tokLEQ: + case tokULEQ: + case tokGEQ: + case tokUGEQ: + case tokEQ: + case tokNEQ: + GenPrintInstr1Operand(X86InstrSetCc, tok, + X86OpRegAByte, 0); + if (SizeOfWord == 2) + GenPrintInstrNoOperand(X86InstrCbw); +#ifdef CAN_COMPILE_32BIT + else + GenPrintInstr2Operands(X86InstrMovZx, 0, + X86OpRegAWord, 0, + X86OpRegAByte, 0); +#endif + break; + } + } + break; + + case '*': + case tokAssignMul: + instr = GenGetBinaryOperatorInstr(tok); + + switch (stack[i + 2][0]) + { + case tokOpNumInt: + case tokOpNumUint: + GenPrintInstr3Operands(X86InstrImul, 0, + X86OpRegAWord, 0, + X86OpRegAWord, 0, + X86OpConst, stack[i + 2][1]); + break; + case tokOpIdent: + GenPrintInstr3Operands(X86InstrImul, 0, + X86OpRegAWord, 0, + X86OpRegAWord, 0, + X86OpLabel, stack[i + 2][1]); + break; + case tokOpLocalOfs: + GenPrintInstr2Operands(X86InstrLea, 0, + X86OpRegCWord, 0, + X86OpIndLocal, stack[i + 2][1]); + GenPrintInstr1Operand(instr, 0, + X86OpRegCWord, 0); + break; + case tokOpAcc: + case tokOpIndAcc: + // right operand in cx already + GenPrintInstr1Operand(instr, 0, + X86OpRegCWord, 0); + break; + case tokOpIndIdent: + if (v % 16 - 8 != SizeOfWord) + { + GenReadCRegIdent(v % 16 - 8, stack[i + 2][1]); + GenPrintInstr1Operand(instr, 0, + X86OpRegCWord, 0); + } + else + { + GenPrintInstr1Operand(instr, 0, + X86OpIndLabelExplicitWord, stack[i + 2][1]); + } + break; + case tokOpIndLocalOfs: + if (v % 16 - 8 != SizeOfWord) + { + GenReadCRegLocal(v % 16 - 8, stack[i + 2][1]); + GenPrintInstr1Operand(instr, 0, + X86OpRegCWord, 0); + } + else + { + GenPrintInstr1Operand(instr, 0, + X86OpIndLocalExplicitWord, stack[i + 2][1]); + } + break; + } + break; + + case '/': + case tokUDiv: + case '%': + case tokUMod: + case tokAssignDiv: + case tokAssignUDiv: + case tokAssignMod: + case tokAssignUMod: + instr = GenGetBinaryOperatorInstr(tok); + + switch (tok) + { + case '/': + case '%': + case tokAssignDiv: + case tokAssignMod: + if (SizeOfWord == 2) + GenPrintInstrNoOperand(X86InstrCwd); +#ifdef CAN_COMPILE_32BIT + else + GenPrintInstrNoOperand(X86InstrCdq); +#endif + break; + default: + GenPrintInstr2Operands(X86InstrMov, 0, + X86OpRegDWord, 0, + X86OpConst, 0); + break; + } + + switch (stack[i + 2][0]) + { + case tokOpNumInt: + case tokOpNumUint: + GenPrintInstr2Operands(X86InstrMov, 0, + X86OpRegCWord, 0, + X86OpConst, stack[i + 2][1]); + GenPrintInstr1Operand(instr, 0, + X86OpRegCWord, 0); + break; + case tokOpIdent: + GenPrintInstr2Operands(X86InstrMov, 0, + X86OpRegCWord, 0, + X86OpLabel, stack[i + 2][1]); + GenPrintInstr1Operand(instr, 0, + X86OpRegCWord, 0); + break; + case tokOpLocalOfs: + GenPrintInstr2Operands(X86InstrLea, 0, + X86OpRegCWord, 0, + X86OpIndLocal, stack[i + 2][1]); + GenPrintInstr1Operand(instr, 0, + X86OpRegCWord, 0); + break; + case tokOpAcc: + case tokOpIndAcc: + // right operand in cx already + GenPrintInstr1Operand(instr, 0, + X86OpRegCWord, 0); + break; + case tokOpIndIdent: + if (v % 16 - 8 != SizeOfWord) + { + GenReadCRegIdent(v % 16 - 8, stack[i + 2][1]); + GenPrintInstr1Operand(instr, 0, + X86OpRegCWord, 0); + } + else + { + GenPrintInstr1Operand(instr, 0, + X86OpIndLabelExplicitWord, stack[i + 2][1]); + } + break; + case tokOpIndLocalOfs: + if (v % 16 - 8 != SizeOfWord) + { + GenReadCRegLocal(v % 16 - 8, stack[i + 2][1]); + GenPrintInstr1Operand(instr, 0, + X86OpRegCWord, 0); + } + else + { + GenPrintInstr1Operand(instr, 0, + X86OpIndLocalExplicitWord, stack[i + 2][1]); + } + } + + if (tok == '%' || tok == tokAssignMod || + tok == tokUMod || tok == tokAssignUMod) + GenPrintInstr2Operands(X86InstrMov, 0, + X86OpRegAWord, 0, + X86OpRegDWord, 0); + break; + + case tokLShift: + case tokRShift: + case tokURShift: + case tokAssignLSh: + case tokAssignRSh: + case tokAssignURSh: + instr = GenGetBinaryOperatorInstr(tok); + + switch (stack[i + 2][0]) + { + case tokOpNumInt: + case tokOpNumUint: + GenPrintInstr2Operands(instr, 0, + X86OpRegAWord, 0, + X86OpConst, stack[i + 2][1]); + break; + case tokOpIdent: + GenPrintInstr2Operands(instr, 0, + X86OpRegAWord, 0, + X86OpLabel, stack[i + 2][1]); + break; + case tokOpLocalOfs: + GenPrintInstr2Operands(X86InstrLea, 0, + X86OpRegCWord, 0, + X86OpIndLocal, stack[i + 2][1]); + GenPrintInstr2Operands(instr, 0, + X86OpRegAWord, 0, + X86OpRegCByte, 0); + break; + case tokOpAcc: + case tokOpIndAcc: + // right operand in cx already + GenPrintInstr2Operands(instr, 0, + X86OpRegAWord, 0, + X86OpRegCByte, 0); + break; + case tokOpIndIdent: + GenPrintInstr2Operands(X86InstrMov, 0, + X86OpRegCByte, 0, + X86OpIndLabel, stack[i + 2][1]); + GenPrintInstr2Operands(instr, 0, + X86OpRegAWord, 0, + X86OpRegCByte, 0); + break; + case tokOpIndLocalOfs: + GenPrintInstr2Operands(X86InstrMov, 0, + X86OpRegCByte, 0, + X86OpIndLocal, stack[i + 2][1]); + GenPrintInstr2Operands(instr, 0, + X86OpRegAWord, 0, + X86OpRegCByte, 0); + break; + } + break; + + case '=': + break; + + default: + //error("Error: Internal Error: GenExpr1() a: unexpected token %s\n", GetTokenName(tok)); + errorInternal(103); + break; + } + + // store ax into the left operand, if needed + switch (tok) + { + case '=': + case tokAssignAdd: + case tokAssignSub: + case tokAssignMul: + case tokAssignDiv: + case tokAssignUDiv: + case tokAssignMod: + case tokAssignUMod: + case tokAssignLSh: + case tokAssignRSh: + case tokAssignURSh: + case tokAssignAnd: + case tokAssignXor: + case tokAssignOr: + switch (stack[i + 1][0]) + { + case tokOpIndIdent: + GenPrintInstr2Operands(X86InstrMov, 0, + X86OpIndLabel, stack[i + 1][1], + GenSelectByteOrWord(X86OpRegAByteOrWord, v / 16 - 8), 0); + break; + case tokOpIndLocalOfs: + GenPrintInstr2Operands(X86InstrMov, 0, + X86OpIndLocal, stack[i + 1][1], + GenSelectByteOrWord(X86OpRegAByteOrWord, v / 16 - 8), 0); + break; + case tokOpIndAcc: + case tokOpIndStack: +#ifdef CAN_COMPILE_32BIT + GenSaveRestoreRegB(0); + GenRegB2Seg(); +#endif + GenPrintInstr2Operands(X86InstrMov, 0, + X86OpIndRegB, 0, + GenSelectByteOrWord(X86OpRegAByteOrWord, v / 16 - 8), 0); +#ifdef CAN_COMPILE_32BIT + GenSaveRestoreRegB(1); +#endif + break; + } + // the result of the expression is of type of the + // left lvalue operand, so, "truncate" it if needed + GenExtendRegAIfNeeded(v / 16 - 8); + } + i += 2; + break; + + case ')': + // DONE: "call ident" + if (stack[i - 1][0] == tokIdent) + { +#ifdef CAN_COMPILE_32BIT + if (OutputFormat == FormatSegHuge) + { + int lab = LabelCnt++; + puts2("\tdb\t0x9A"); // call far seg:ofs + printf2("section .relot\n\tdd\t"); GenPrintNumLabel(lab); puts2(""); + puts2(CodeHeader); + GenNumLabel(lab); + printf2("\tdd\t"); GenPrintLabel(IdentTable + stack[i - 1][1]); puts2(""); + } + else // fallthrough +#endif + GenPrintInstr1Operand(X86InstrCall, 0, + X86OpLabel, stack[i - 1][1]); + } + else + { +#ifdef CAN_COMPILE_32BIT + if (OutputFormat == FormatSegHuge) + { + int lab = (LabelCnt += 3) - 3; + puts2("\tdb\t0x9A"); // call far seg:ofs (only to generate return address) + printf2("section .relot\n\tdd\t"); GenPrintNumLabel(lab); puts2(""); + puts2(CodeHeader); + GenNumLabel(lab); + printf2("\tdd\t"); GenPrintNumLabel(lab + 1); puts2(""); + GenNumLabel(lab + 1); + printf2("\tadd\tword [esp], "); GenPrintNumLabel(lab + 2); printf2(" - "); GenPrintNumLabel(lab + 1); puts2(""); // adjust return address + puts2("\tshl\teax, 12\n\trol\tax, 4\n\tpush\teax\n\tretf"); + GenNumLabel(lab + 2); + } + else // fallthrough +#endif + GenPrintInstr1Operand(X86InstrCall, 0, + X86OpRegAWord, 0); + } + if (v) + GenLocalAlloc(-v); + break; + + case '(': + case tokIf: + case tokIfNot: + break; + + case tokVoid: + case tokComma: + break; + + default: + //error("Error: Internal Error: GenExpr1() b: unexpected token %s\n", GetTokenName(tok)); + errorInternal(104); + break; + } + } +} +#else // #ifndef CG_STACK_BASED +// Original, primitive stack-based code generator +// DONE: test 32-bit code generation +void GenExpr0(void) +{ + int i; + int gotUnary = 0; + + for (i = 0; i < sp; i++) + { + int tok = stack[i][0]; + int v = stack[i][1]; + +#ifndef NO_ANNOTATIONS + switch (tok) + { + case tokNumInt: printf2("; %d\n", truncInt(v)); break; + case tokNumUint: printf2("; %uu\n", truncUint(v)); break; + case tokIdent: printf2("; %s\n", IdentTable + v); break; + case tokLocalOfs: printf2("; local ofs\n"); break; + case ')': printf2("; ) fxn call\n"); break; + case tokUnaryStar: printf2("; * (read dereference)\n"); break; + case '=': printf2("; = (write dereference)\n"); break; + case tokShortCirc: printf2("; short-circuit "); break; + case tokGoto: printf2("; sh-circ-goto "); break; + case tokLogAnd: printf2("; short-circuit && target\n"); break; + case tokLogOr: printf2("; short-circuit || target\n"); break; + case tokIf: case tokIfNot: break; + default: printf2("; %s\n", GetTokenName(tok)); break; + } +#endif + + switch (tok) + { + case tokNumInt: + case tokNumUint: + if (gotUnary) + GenPrintInstr1Operand(X86InstrPush, 0, + X86OpRegAWord, 0); + GenPrintInstr2Operands(X86InstrMov, 0, + X86OpRegAWord, 0, + X86OpConst, v); + gotUnary = 1; + break; + + case tokIdent: + if (gotUnary) + GenPrintInstr1Operand(X86InstrPush, 0, + X86OpRegAWord, 0); + GenPrintInstr2Operands(X86InstrMov, 0, + X86OpRegAWord, 0, + X86OpLabel, v); + gotUnary = 1; + break; + + case tokLocalOfs: + if (gotUnary) + GenPrintInstr1Operand(X86InstrPush, 0, + X86OpRegAWord, 0); + GenPrintInstr2Operands(X86InstrLea, 0, + X86OpRegAWord, 0, + X86OpIndLocal, v); + gotUnary = 1; + break; + + case ')': +#ifdef CAN_COMPILE_32BIT + if (OutputFormat == FormatSegHuge) + { + int lab = (LabelCnt += 3) - 3; + puts2("\tdb\t0x9A"); // call far seg:ofs (only to generate return address) + printf2("section .relot\n\tdd\t"); GenPrintNumLabel(lab); puts2(""); + puts2(CodeHeader); + GenNumLabel(lab); + printf2("\tdd\t"); GenPrintNumLabel(lab + 1); puts2(""); + GenNumLabel(lab + 1); + printf2("\tadd\tword [esp], "); GenPrintNumLabel(lab + 2); printf2(" - "); GenPrintNumLabel(lab + 1); puts2(""); // adjust return address + puts2("\tshl\teax, 12\n\trol\tax, 4\n\tpush\teax\n\tretf"); + GenNumLabel(lab + 2); + } + else // fallthrough +#endif + GenPrintInstr1Operand(X86InstrCall, 0, + X86OpRegAWord, 0); + if (v) + GenLocalAlloc(-v); + break; + + case tokUnaryStar: + GenReadIndirect(v); + break; + + case tokUnaryPlus: + break; + case '~': + GenPrintInstr1Operand(X86InstrNot, 0, + X86OpRegAWord, 0); + break; + case tokUnaryMinus: + GenPrintInstr1Operand(X86InstrNeg, 0, + X86OpRegAWord, 0); + break; + + case '+': + case '-': + case '*': + case '&': + case '^': + case '|': + { + int instr = GenGetBinaryOperatorInstr(tok); + GenPrintInstr1Operand(X86InstrPop, 0, + X86OpRegBWord, 0); + if (tok == '-') + GenPrintInstr2Operands(X86InstrXchg, 0, + X86OpRegAWord, 0, + X86OpRegBWord, 0); + if (tok != '*') + GenPrintInstr2Operands(instr, 0, + X86OpRegAWord, 0, + X86OpRegBWord, 0); + else + GenPrintInstr1Operand(instr, 0, + X86OpRegBWord, 0); + } + break; + + case '/': + case tokUDiv: + case '%': + case tokUMod: + GenPrintInstr1Operand(X86InstrPop, 0, + X86OpRegBWord, 0); + GenPrintInstr2Operands(X86InstrXchg, 0, + X86OpRegAWord, 0, + X86OpRegBWord, 0); + if (tok == '/' || tok == '%') + { + if (SizeOfWord == 2) + GenPrintInstrNoOperand(X86InstrCwd); +#ifdef CAN_COMPILE_32BIT + else + GenPrintInstrNoOperand(X86InstrCdq); +#endif + GenPrintInstr1Operand(X86InstrIdiv, 0, + X86OpRegBWord, 0); + } + else + { + GenPrintInstr2Operands(X86InstrMov, 0, + X86OpRegDWord, 0, + X86OpConst, 0); + GenPrintInstr1Operand(X86InstrDiv, 0, + X86OpRegBWord, 0); + } + if (tok == '%' || tok == tokUMod) + GenPrintInstr2Operands(X86InstrMov, 0, + X86OpRegAWord, 0, + X86OpRegDWord, 0); + break; + + case tokLShift: + case tokRShift: + case tokURShift: + { + int instr = GenGetBinaryOperatorInstr(tok); + GenPrintInstr1Operand(X86InstrPop, 0, + X86OpRegCWord, 0); + GenPrintInstr2Operands(X86InstrXchg, 0, + X86OpRegAWord, 0, + X86OpRegCWord, 0); + GenPrintInstr2Operands(instr, 0, + X86OpRegAWord, 0, + X86OpRegCByte, 0); + } + break; + + case tokInc: + GenIncDecIndirect(v, tok); + break; + case tokDec: + GenIncDecIndirect(v, tok); + break; + case tokPostInc: + GenPostIncDecIndirect(v, tok); + break; + case tokPostDec: + GenPostIncDecIndirect(v, tok); + break; + + case tokPostAdd: + case tokPostSub: + { + int instr = GenGetBinaryOperatorInstr(tok); + GenPrintInstr1Operand(X86InstrPop, 0, + X86OpRegBWord, 0); +#ifdef CAN_COMPILE_32BIT + GenSaveRestoreRegB(0); + GenRegB2Seg(); +#endif + GenPrintInstr2Operands(X86InstrMov, 0, + X86OpRegCWord, 0, + X86OpRegAWord, 0); + GenPrintInstr2Operands(X86InstrMov, 0, + GenSelectByteOrWord(X86OpRegAByteOrWord, v), 0, + X86OpIndRegB, 0); + GenPrintInstr2Operands(instr, 0, + X86OpIndRegB, 0, + GenSelectByteOrWord(X86OpRegCByteOrWord, v), 0); +#ifdef CAN_COMPILE_32BIT + GenSaveRestoreRegB(1); +#endif + GenExtendRegAIfNeeded(v); + } + break; + + case tokAssignAdd: + case tokAssignSub: + case tokAssignMul: + case tokAssignAnd: + case tokAssignXor: + case tokAssignOr: + { + int instr = GenGetBinaryOperatorInstr(tok); + GenPrintInstr1Operand(X86InstrPop, 0, + X86OpRegBWord, 0); +#ifdef CAN_COMPILE_32BIT + GenSaveRestoreRegB(0); + GenRegB2Seg(); +#endif + if (tok != tokAssignMul) + { + GenPrintInstr2Operands(instr, 0, + X86OpIndRegB, 0, + GenSelectByteOrWord(X86OpRegAByteOrWord, v), 0); + GenPrintInstr2Operands(X86InstrMov, 0, + GenSelectByteOrWord(X86OpRegAByteOrWord, v), 0, + X86OpIndRegB, 0); + } + else + { + GenPrintInstr1Operand(instr, 0, + GenSelectByteOrWord(X86OpIndRegBExplicitByteOrWord, v), 0); + GenPrintInstr2Operands(X86InstrMov, 0, + X86OpIndRegB, 0, + GenSelectByteOrWord(X86OpRegAByteOrWord, v), 0); + } +#ifdef CAN_COMPILE_32BIT + GenSaveRestoreRegB(1); +#endif + GenExtendRegAIfNeeded(v); + } + break; + + case tokAssignDiv: + case tokAssignUDiv: + case tokAssignMod: + case tokAssignUMod: + GenPrintInstr1Operand(X86InstrPop, 0, + X86OpRegBWord, 0); +#ifdef CAN_COMPILE_32BIT + GenSaveRestoreRegB(0); + GenRegB2Seg(); +#endif + GenPrintInstr2Operands(X86InstrMov, 0, + X86OpRegCWord, 0, + X86OpRegAWord, 0); + GenPrintInstr2Operands(X86InstrMov, 0, + GenSelectByteOrWord(X86OpRegAByteOrWord, v), 0, + X86OpIndRegB, 0); + GenExtendRegAIfNeeded(v); + if (tok == tokAssignDiv || tok == tokAssignMod) + { + if (SizeOfWord == 2) + GenPrintInstrNoOperand(X86InstrCwd); +#ifdef CAN_COMPILE_32BIT + else + GenPrintInstrNoOperand(X86InstrCdq); +#endif + GenPrintInstr1Operand(X86InstrIdiv, 0, + X86OpRegCWord, 0); + } + else + { + GenPrintInstr2Operands(X86InstrMov, 0, + X86OpRegDWord, 0, + X86OpConst, 0); + GenPrintInstr1Operand(X86InstrDiv, 0, + X86OpRegCWord, 0); + } + if (tok == tokAssignMod || tok == tokAssignUMod) + GenPrintInstr2Operands(X86InstrMov, 0, + X86OpRegAWord, 0, + X86OpRegDWord, 0); + GenPrintInstr2Operands(X86InstrMov, 0, + X86OpIndRegB, 0, + GenSelectByteOrWord(X86OpRegAByteOrWord, v), 0); +#ifdef CAN_COMPILE_32BIT + GenSaveRestoreRegB(1); +#endif + GenExtendRegAIfNeeded(v); + break; + + case tokAssignLSh: + case tokAssignRSh: + case tokAssignURSh: + { + int instr = GenGetBinaryOperatorInstr(tok); + GenPrintInstr1Operand(X86InstrPop, 0, + X86OpRegBWord, 0); +#ifdef CAN_COMPILE_32BIT + GenSaveRestoreRegB(0); + GenRegB2Seg(); +#endif + GenPrintInstr2Operands(X86InstrMov, 0, + X86OpRegCWord, 0, + X86OpRegAWord, 0); + GenPrintInstr2Operands(instr, 0, + GenSelectByteOrWord(X86OpIndRegBExplicitByteOrWord, v), 0, + X86OpRegCByte, 0); + GenPrintInstr2Operands(X86InstrMov, 0, + GenSelectByteOrWord(X86OpRegAByteOrWord, v), 0, + X86OpIndRegB, 0); +#ifdef CAN_COMPILE_32BIT + GenSaveRestoreRegB(1); +#endif + GenExtendRegAIfNeeded(v); + } + break; + + case '=': + GenPrintInstr1Operand(X86InstrPop, 0, + X86OpRegBWord, 0); +#ifdef CAN_COMPILE_32BIT + GenSaveRestoreRegB(0); + GenRegB2Seg(); +#endif + GenPrintInstr2Operands(X86InstrMov, 0, + X86OpIndRegB, 0, + GenSelectByteOrWord(X86OpRegAByteOrWord, v), 0); +#ifdef CAN_COMPILE_32BIT + GenSaveRestoreRegB(1); +#endif + GenExtendRegAIfNeeded(v); + break; + + case '<': + case tokULess: + case '>': + case tokUGreater: + case tokLEQ: + case tokULEQ: + case tokGEQ: + case tokUGEQ: + case tokEQ: + case tokNEQ: + GenPrintInstr1Operand(X86InstrPop, 0, + X86OpRegBWord, 0); + GenPrintInstr2Operands(X86InstrCmp, 0, + X86OpRegBWord, 0, + X86OpRegAWord, 0); + GenPrintInstr1Operand(X86InstrSetCc, tok, + X86OpRegAByte, 0); + if (SizeOfWord == 2) + GenPrintInstrNoOperand(X86InstrCbw); +#ifdef CAN_COMPILE_32BIT + else + GenPrintInstr2Operands(X86InstrMovZx, 0, + X86OpRegAWord, 0, + X86OpRegAByte, 0); +#endif + break; + + case tok_Bool: + GenPrintInstr2Operands(X86InstrTest, 0, + X86OpRegAWord, 0, + X86OpRegAWord, 0); + GenPrintInstr1Operand(X86InstrSetCc, tokNEQ, + X86OpRegAByte, 0); + // fallthrough + case tokSChar: + if (SizeOfWord == 2) + GenPrintInstrNoOperand(X86InstrCbw); +#ifdef CAN_COMPILE_32BIT + else + GenPrintInstr2Operands(X86InstrMovSx, 0, + X86OpRegAWord, 0, + X86OpRegAByte, 0); +#endif + break; + case tokUChar: + GenPrintInstr2Operands(X86InstrAnd, 0, + X86OpRegAWord, 0, + X86OpConst, 0xFF); + break; + + case tokShortCirc: +#ifndef NO_ANNOTATIONS + if (v >= 0) + printf2("&&\n"); + else + printf2("||\n"); +#endif + if (v >= 0) + GenJumpIfZero(v); // && + else + GenJumpIfNotZero(-v); // || + gotUnary = 0; + break; + case tokGoto: +#ifndef NO_ANNOTATIONS + printf2("goto\n"); +#endif + GenJumpUncond(v); + gotUnary = 0; + break; + case tokLogAnd: + case tokLogOr: + GenNumLabel(v); + break; + + case tokVoid: + gotUnary = 0; + break; + + case tokComma: + case ',': + case '(': + break; + + case tokIf: + GenJumpIfNotZero(stack[i][1]); + break; + case tokIfNot: + GenJumpIfZero(stack[i][1]); + break; + + default: + //error("Error: Internal Error: GenExpr0(): unexpected token %s\n", GetTokenName(tok)); + errorInternal(105); + break; + } + } +} +#endif // #ifndef CG_STACK_BASED + +unsigned GenStrData(int generatingCode, unsigned requiredLen) +{ + int i; + unsigned total = 0; + + // insert string literals into the code + for (i = 0; i < sp; i++) + { + int tok = stack[i][0]; + char* p = IdentTable + stack[i][1]; + if (tok == tokIdent && isdigit(*p)) + { + int label = atoi(p); + int quot = 0; + unsigned len; + + p = FindString(label); + len = *p++; + + // If this is a string literal initializing an array of char, + // truncate or pad it as necessary. + if (requiredLen) + { + if (len >= requiredLen) + { + len = requiredLen; // copy count + requiredLen = 0; // count to be zeroed out + } + else + { + requiredLen -= len; // count to be zeroed out + } + } + // Also, calculate its real size for incompletely typed arrays. + total = len + requiredLen; + + if (generatingCode) + { + if (OutputFormat == FormatFlat) + { + GenJumpUncond(label + 1); + } + else + { + puts2(CodeFooter); + puts2(DataHeader); + } + } + + GenNumLabel(label); + + GenStartAsciiString(); + while (len--) + { + // quote ASCII chars for better readability + if (*p >= 0x20 && *p <= 0x7E && *p != '\"') + { + if (!quot) + { + quot = 1; + printf2("\""); + } + printf2("%c", *p); + } + else + { + if (quot) + { + quot = 0; + printf2("\","); + } + printf2("%u", *p & 0xFFu); + if (len || requiredLen) + printf2(","); + } + p++; + } + if (quot) + { + printf2("\""); + if (requiredLen) + printf2(","); + } + while (requiredLen) + { + printf2("0"); + if (--requiredLen) + printf2(","); + } + puts2(""); + + if (generatingCode) + { + if (OutputFormat == FormatFlat) + { + GenNumLabel(label + 1); + } + else + { + puts2(DataFooter); + puts2(CodeHeader); + } + } + } + } + + return total; +} + +void GenExpr(void) +{ + if (OutputFormat != FormatFlat && GenExterns) + { + int i; + for (i = 0; i < sp; i++) + if (stack[i][0] == tokIdent && !isdigit(IdentTable[stack[i][1]])) + GenAddGlobal(IdentTable + stack[i][1], 2); + } + GenStrData(1, 0); +#ifndef CG_STACK_BASED + GenExpr1(); +#else + GenExpr0(); +#endif +} + +void GenFin(void) +{ + if (StructCpyLabel) + { + char s[1 + 2 + (2 + CHAR_BIT * sizeof StructCpyLabel) / 3]; + char *p = s + sizeof s; + + *--p = '\0'; + p = lab2str(p, StructCpyLabel); + *--p = '_'; + *--p = '_'; + + if (OutputFormat != FormatFlat) + puts2(CodeHeader); + + GenLabel(p, 1); + GenFxnProlog(); + + if (SizeOfWord == 2) + { + puts2("\tmov\tdi, [bp+8]\n" + "\tmov\tsi, [bp+6]\n" + "\tmov\tcx, [bp+4]\n" + "\tcld\n" + "\trep\tmovsb\n" + "\tmov\tax, [bp+8]"); + } +#ifdef CAN_COMPILE_32BIT + else if (OutputFormat != FormatSegHuge) + { + puts2("\tmov\tedi, [ebp+16]\n" + "\tmov\tesi, [ebp+12]\n" + "\tmov\tecx, [ebp+8]\n" + "\tcld\n" + "\trep\tmovsb\n" + "\tmov\teax, [ebp+16]"); + } + else + { + int lbl = (LabelCnt += 2) - 2; + + puts2("\tmov\tedi, [ebp+16]\n" + "\tror\tedi, 4\n" + "\tmov\tes, di\n" + "\tshr\tedi, 28\n" + "\tmov\tesi, [ebp+12]\n" + "\tror\tesi, 4\n" + "\tmov\tds, si\n" + "\tshr\tesi, 28"); + puts2("\tmov\tebx, [ebp+8]\n" + "\tcld"); + + GenNumLabel(lbl); // L1: + + puts2("\tmov\tecx, 32768\n" + "\tcmp\tebx, ecx"); + + printf2("\tjc\t"); GenPrintNumLabel(lbl + 1); // jc L2 + + puts2("\n" + "\tsub\tebx, ecx\n" + "\trep\tmovsb\n" + "\tand\tdi, 15\n" + "\tmov\tax, es\n" + "\tadd\tax, 2048\n" + "\tmov\tes, ax\n" + "\tand\tsi, 15\n" + "\tmov\tax, ds\n" + "\tadd\tax, 2048\n" + "\tmov\tds, ax"); + + printf2("\tjmp\t"); GenPrintNumLabel(lbl); // jmp L1 + puts2(""); + + GenNumLabel(lbl + 1); // L2: + + puts2("\tmov\tcx, bx\n" + "\trep\tmovsb\n" + "\tmov\teax, [ebp+16]"); + } +#endif + + GenFxnEpilog(); + + if (OutputFormat != FormatFlat) + puts2(CodeFooter); + } + + if (OutputFormat != FormatFlat && GenExterns) + { + int i = 0; + + puts2(""); + while (i < GlobalsTableLen) + { + if (GlobalsTable[i] == 2) + { + printf2("\textern\t"); + GenPrintLabel(GlobalsTable + i + 2); + puts2(""); + } + i += GlobalsTable[i + 1] + 2; + } + } +} diff --git a/src/cmd/smlrc/lb.c b/src/cmd/smlrc/lb.c new file mode 100644 index 0000000..897e526 --- /dev/null +++ b/src/cmd/smlrc/lb.c @@ -0,0 +1,1399 @@ +/* +Copyright (c) 2013-2014, Alexey Frunze +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +The views and conclusions contained in the software and documentation are those +of the authors and should not be interpreted as representing official policies, +either expressed or implied, of the FreeBSD Project. +*/ + +/*****************************************************************************/ +/* */ +/* minimal stdlibc */ +/* */ +/* Just enough code for Smaller C to compile into a */ +/* 16/32-bit DOS/Windows/Linux/RetroBSD "EXE". */ +/* */ +/*****************************************************************************/ + +#ifndef __SMALLER_C__ +#error must be compiled with Smaller C +#endif + +#ifndef __SMALLER_C_SCHAR__ +#ifndef __SMALLER_C_UCHAR__ +#error __SMALLER_C_SCHAR__ or __SMALLER_C_UCHAR__ must be defined +#endif +#endif + +#ifndef __SMALLER_C_16__ +#ifndef __SMALLER_C_32__ +#error __SMALLER_C_16__ or __SMALLER_C_32__ must be defined +#endif +#endif + +#ifndef _RETROBSD +#ifndef _LINUX +#ifndef _WIN32 +#ifndef _DOS +#define _DOS +#endif +#endif +#endif +#endif + +#define NULL 0 +#define EOF (-1) +#define FILE void + +extern int main(int argc, char** argv); +void exit(int); + +#ifdef _RETROBSD +void __start__(int argc, char** argv) +{ + exit(main(argc, argv)); +} +#else +#ifdef _LINUX +void __start__(int argc, char** argv) +{ + exit(main(argc, argv)); +} +#else +void __setargs__(int* pargc, char*** pargv); + +void __start__(void) +{ + int argc; + char** argv; + __setargs__(&argc, &argv); + exit(main(argc, argv)); +} +#endif +#endif + +unsigned char __chartype__[1 + 256] = +{ + 0x00, // for EOF=-1 + 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, 0x01,0x03,0x03,0x03,0x03,0x03,0x01,0x01, + 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, + 0x02,0x04,0x04,0x04,0x04,0x04,0x04,0x04, 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, + 0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08, 0x08,0x08,0x04,0x04,0x04,0x04,0x04,0x04, + 0x04,0x50,0x50,0x50,0x50,0x50,0x50,0x10, 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, + 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, 0x10,0x10,0x10,0x04,0x04,0x04,0x04,0x04, + 0x04,0x60,0x60,0x60,0x60,0x60,0x60,0x20, 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, + 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, 0x20,0x20,0x20,0x04,0x04,0x04,0x04,0x01, +}; + +int isspace(int c) +{ + return __chartype__[c + 1] & 0x02; +} + +int isdigit(int c) +{ + return __chartype__[c + 1] & 0x08; +} + +int isalpha(int c) +{ + return __chartype__[c + 1] & 0x30; +} + +int isalnum(int c) +{ + return __chartype__[c + 1] & 0x38; +} + +int atoi(char* s) +{ + // simplified version + int r = 0; + int neg = 0; + if (*s == '-') + { + neg = 1; + ++s; + } + else if (*s == '+') + { + ++s; + } + while (isdigit(*s & 0xFFu)) + r = r * 10u + *s++ - '0'; + if (neg) + r = -r; + return r; +} + +unsigned strlen(char* str) +{ +#ifndef __SMALLER_C_16__ + char* s; + + if (str == NULL) + return 0; + + for (s = str; *s; ++s); + + return s - str; +#else + asm("mov di, [bp+4]\n" + "mov cx, -1\n" + "xor al, al\n" + "cld\n" + "repnz scasb\n" + "mov ax, cx\n" + "not ax\n" + "dec ax"); +#endif +} + +char* strcpy(char* dst, char* src) +{ +#ifndef __SMALLER_C_16__ + char* p = dst; + + while ((*p++ = *src++) != 0); +#else + asm("mov di, [bp+6]\n" + "mov si, di\n" + "mov cx, -1\n" + "xor al, al\n" + "cld\n" + "repnz scasb\n" + "not cx\n" + "mov di, [bp+4]\n" + "rep movsb"); +#endif + + return dst; +} + +char* strchr(char* s, int c) +{ +#ifndef __SMALLER_C_16__ + char ch = c; + + while (*s) + { + if (*s == ch) + return s; + ++s; + } + + if (!ch) + return s; + + return NULL; +#else + asm("mov si, [bp+4]\n" + "mov bl, [bp+6]\n" + "xor ax, ax\n" + "cld\n" + "strchrlp:\n" + "lodsb\n" + "cmp al, bl\n" + "je strchrmch\n" + "or al, al\n" + "jnz strchrlp\n" + "jmp strchrend"); + asm("strchrmch:\n" + "lea ax, [si-1]\n" + "strchrend:"); +#endif +} + +int strcmp(char* s1, char* s2) +{ +#ifndef __SMALLER_C_16__ + while (*s1 == *s2) + { + if (!*s1) + return 0; + ++s1; + ++s2; + } + + return (*s1 & 0xFF) - (*s2 & 0xFF); +#else + asm("mov di, [bp+6]\n" + "mov si, di\n" + "mov cx, -1\n" + "xor ax, ax\n" + "mov bx, ax\n" + "cld\n" + "repnz scasb\n" + "not cx"); + asm("mov di, [bp+4]\n" + "repe cmpsb\n" + "mov al, [di-1]\n" + "mov bl, [si-1]\n" + "sub ax, bx"); +#endif +} + +int strncmp(char* s1, char* s2, unsigned n) +{ +#ifndef __SMALLER_C_16__ + if (!n) + return 0; + + do + { + if (*s1 != *s2++) + return (*s1 & 0xFF) - (*--s2 & 0xFF); + if (!*s1++) + break; + } while (--n); + + return 0; +#else + asm("mov cx, [bp+8]\n" + "xor ax, ax\n" + "jcxz strncmpend\n" + "mov bx, ax\n" + "mov di, [bp+6]\n" + "mov si, di\n" + "cld\n" + "repnz scasb\n" + "sub cx, [bp+8]\n" + "neg cx"); + asm("mov di, [bp+4]\n" + "repe cmpsb\n" + "mov al, [di-1]\n" + "mov bl, [si-1]\n" + "sub ax, bx\n" + "strncmpend:"); +#endif +} + +void* memmove(void* dst, void* src, unsigned n) +{ +#ifndef __SMALLER_C_16__ + char* d = dst; + char* s = src; + + if (s < d) + { + s += n; + d += n; + while (n--) + *--d = *--s; + } + else + { + while (n--) + *d++ = *s++; + } +#else + if (src < dst) + { + asm("mov di, [bp+4]\n" + "mov si, [bp+6]\n" + "mov cx, [bp+8]\n" + "add di, cx\n" + "dec di\n" + "add si, cx\n" + "dec si\n" + "std\n" + "rep movsb"); + } + else + { + asm("mov di, [bp+4]\n" + "mov si, [bp+6]\n" + "mov cx, [bp+8]\n" + "cld\n" + "rep movsb"); + } +#endif + return dst; +} + +void* memcpy(void* dst, void* src, unsigned n) +{ +#ifndef __SMALLER_C_16__ + char* p1 = dst; + char* p2 = src; + + while (n--) + *p1++ = *p2++; +#else + asm("mov di, [bp+4]\n" + "mov si, [bp+6]\n" + "mov cx, [bp+8]\n" + "shr cx, 1\n" + "cld\n" + "rep movsw\n" + "rcl cx, 1\n" + "rep movsb"); +#endif + return dst; +} + +void* memset(void* s, int c, unsigned n) +{ +#ifndef __SMALLER_C_16__ + char* p = s; + + while (n--) + *p++ = c; +#else + asm("mov di, [bp+4]\n" + "mov al, [bp+6]\n" + "mov ah, al\n" + "mov cx, [bp+8]\n" + "shr cx, 1\n" + "cld\n" + "rep stosw\n" + "rcl cx, 1\n" + "rep stosb"); +#endif + return s; +} + +int fputc(int c, FILE* stream); +int putchar(int c); + +int __putchar__(char** buf, FILE* stream, int c) +{ + if (buf) + { + *(*buf)++ = c; + } + else if (stream) + { + fputc(c, stream); + } + else + { + putchar(c); + } + return 1; +} + +int __vsprintf__(char** buf, FILE* stream, char* fmt, void* vl) +{ + // Simplified version! + // No I/O error checking! + int* pp = vl; + int cnt = 0; + char* p; + char* phex; + char s[1/*sign*/+10/*magnitude*/+1/*\0*/]; // up to 11 octal digits in 32-bit numbers + char* pc; + int n, sign, msign; + int minlen, len; + int leadchar = ' '; + + for (p = fmt; *p != '\0'; ++p) + { + if (*p != '%' || p[1] == '%') + { + __putchar__(buf, stream, *p); + p = p + (*p == '%'); + ++cnt; + continue; + } + ++p; + minlen = 0; + msign = 0; + if (*p == '+') { msign = 1; ++p; } + else if (*p == '-') { msign = -1; ++p; } + if (isdigit(*p & 0xFFu)) + { + if (*p == '0') + leadchar = '0'; + else + leadchar = ' '; + while (isdigit(*p & 0xFFu)) + minlen = minlen * 10 + *p++ - '0'; + if (msign < 0) + minlen = -minlen; + msign = 0; + } + if (!msign) + { + if (*p == '+') { msign = 1; ++p; } + else if (*p == '-') { msign = -1; ++p; } + } + phex = "0123456789abcdef"; + switch (*p) + { + case 'c': + while (minlen > 1) { __putchar__(buf, stream, ' '); ++cnt; --minlen; } + __putchar__(buf, stream, *pp++); + while (-minlen > 1) { __putchar__(buf, stream, ' '); ++cnt; ++minlen; } + ++cnt; + break; + case 's': + pc = (char*)*pp++; + len = 0; + if (pc) + len = strlen(pc); + while (minlen > len) { __putchar__(buf, stream, ' '); ++cnt; --minlen; } + if (len) + while (*pc != '\0') + { + __putchar__(buf, stream, *pc++); + ++cnt; + } + while (-minlen > len) { __putchar__(buf, stream, ' '); ++cnt; ++minlen; } + break; + case 'i': + case 'd': + pc = &s[sizeof s - 1]; + *pc = '\0'; + len = 0; + n = *pp++; + sign = 1 - 2 * (n < 0); + do + { + *--pc = '0' + (n - n / 10 * 10) * sign; + n = n / 10; + ++len; + } while (n); + if (sign < 0) + { + *--pc = '-'; + ++len; + } + else if (msign > 0) + { + *--pc = '+'; + ++len; + msign = 0; + } + while (minlen > len) { __putchar__(buf, stream, leadchar); ++cnt; --minlen; } + while (*pc != '\0') + { + __putchar__(buf, stream, *pc++); + ++cnt; + } + while (-minlen > len) { __putchar__(buf, stream, ' '); ++cnt; ++minlen; } + break; + case 'u': + pc = &s[sizeof s - 1]; + *pc = '\0'; + len = 0; + n = *pp++; + do + { + unsigned nn = n; + *--pc = '0' + nn % 10; + n = nn / 10; + ++len; + } while (n); + if (msign > 0) + { + *--pc = '+'; + ++len; + msign = 0; + } + while (minlen > len) { __putchar__(buf, stream, leadchar); ++cnt; --minlen; } + while (*pc != '\0') + { + __putchar__(buf, stream, *pc++); + ++cnt; + } + while (-minlen > len) { __putchar__(buf, stream, ' '); ++cnt; ++minlen; } + break; + case 'X': + phex = "0123456789ABCDEF"; + // fallthrough + case 'p': + case 'x': + pc = &s[sizeof s - 1]; + *pc = '\0'; + len = 0; + n = *pp++; + do + { + *--pc = phex[n & 0xF]; + n = (n >> 4) & ((1 << (8 * sizeof n - 4)) - 1); // drop sign-extended bits + ++len; + } while (n); + while (minlen > len) { __putchar__(buf, stream, leadchar); ++cnt; --minlen; } + while (*pc != '\0') + { + __putchar__(buf, stream, *pc++); + ++cnt; + } + while (-minlen > len) { __putchar__(buf, stream, ' '); ++cnt; ++minlen; } + break; + case 'o': + pc = &s[sizeof s - 1]; + *pc = '\0'; + len = 0; + n = *pp++; + do + { + *--pc = '0' + (n & 7); + n = (n >> 3) & ((1 << (8 * sizeof n - 3)) - 1); // drop sign-extended bits + ++len; + } while (n); + while (minlen > len) { __putchar__(buf, stream, leadchar); ++cnt; --minlen; } + while (*pc != '\0') + { + __putchar__(buf, stream, *pc++); + ++cnt; + } + while (-minlen > len) { __putchar__(buf, stream, ' '); ++cnt; ++minlen; } + break; + default: + return -1; + } + } + + return cnt; +} + +int vprintf(char* fmt, void* vl) +{ + return __vsprintf__(NULL, NULL, fmt, vl); +} + +int printf(char* fmt, ...) +{ + void** pp = (void**)&fmt; + return vprintf(fmt, pp + 1); +} + +int vsprintf(char* buf, char* fmt, void* vl) +{ + return __vsprintf__(&buf, NULL, fmt, vl); +} + +int sprintf(char* buf, char* fmt, ...) +{ + void** pp = (void**)&fmt; + return vsprintf(buf, fmt, pp + 1); +} + +#ifdef _DOS +void pokeb(unsigned seg, unsigned ofs, unsigned char val) +{ +#ifndef __SMALLER_C_16__ + *((unsigned char*)(seg * 16 + ofs)) = val; +#else + asm("push ds\n" + "mov ds, [bp + 4]\n" + "mov bx, [bp + 6]\n" + "mov al, [bp + 8]\n" + "mov [bx], al\n" + "pop ds"); +#endif +} + +unsigned char peekb(unsigned seg, unsigned ofs) +{ +#ifndef __SMALLER_C_16__ + return *((unsigned char*)(seg * 16 + ofs)); +#else + asm("push ds\n" + "mov ds, [bp + 4]\n" + "mov bx, [bp + 6]\n" + "mov al, [bx]\n" + "mov ah, 0\n" + "pop ds"); +#endif +} + +void poke(unsigned seg, unsigned ofs, unsigned val) +{ +#ifndef __SMALLER_C_16__ + *((unsigned short*)(seg * 16 + ofs)) = val; +#else + asm("push ds\n" + "mov ds, [bp + 4]\n" + "mov bx, [bp + 6]\n" + "mov ax, [bp + 8]\n" + "mov [bx], ax\n" + "pop ds"); +#endif +} + +unsigned peek(unsigned seg, unsigned ofs) +{ +#ifndef __SMALLER_C_16__ + return *((unsigned short*)(seg * 16 + ofs)); +#else + asm("push ds\n" + "mov ds, [bp + 4]\n" + "mov bx, [bp + 6]\n" + "mov ax, [bx]\n" + "pop ds"); +#endif +} +#endif // _DOS + +#ifdef _WIN32 +#define INVALID_HANDLE_VALUE (-1) +#define GENERIC_WRITE 0x40000000u +#define GENERIC_READ 0x80000000u +#define FILE_SHARE_READ 1 +#define CREATE_ALWAYS 2 +#define OPEN_EXISTING 3 +#define FILE_ATTRIBUTE_NORMAL 0x80 +#define STD_OUTPUT_HANDLE (-11u) + +extern void (*_imp__ExitProcess)(unsigned ExitCode); +void ExitProcess(unsigned ExitCode) +{ + asm("push dword [ebp+8]\n" + "call [__imp__ExitProcess]"); +} + +extern char* (*_imp__GetCommandLineA)(void); +char* GetCommandLineA(void) +{ + asm("call [__imp__GetCommandLineA]"); +} + +extern unsigned (*_imp__GetStdHandle)(unsigned nStdHandle); +unsigned GetStdHandle(unsigned nStdHandle) +{ + asm("push dword [ebp+8]\n" + "call [__imp__GetStdHandle]"); +} + +extern unsigned (*_imp__CreateFileA)(char* FileName, + unsigned DesiredAccess, + unsigned ShareMode, + void* SecurityAttributes, + unsigned CreationDisposition, + unsigned FlagsAndAttributes, + unsigned TemplateFile); +unsigned CreateFileA(char* FileName, + unsigned DesiredAccess, + unsigned ShareMode, + void* SecurityAttributes, + unsigned CreationDisposition, + unsigned FlagsAndAttributes, + unsigned TemplateFile) +{ + asm("push dword [ebp+32]\n" + "push dword [ebp+28]\n" + "push dword [ebp+24]\n" + "push dword [ebp+20]"); + asm("push dword [ebp+16]\n" + "push dword [ebp+12]\n" + "push dword [ebp+8]\n" + "call [__imp__CreateFileA]"); +} + +extern int (*_imp__CloseHandle)(unsigned Handle); +int CloseHandle(unsigned Handle) +{ + asm("push dword [ebp+8]\n" + "call [__imp__CloseHandle]"); +} + +extern int (*_imp__ReadFile)(unsigned Handle, + void* Buffer, + unsigned NumberOfBytesToRead, + unsigned* NumberOfBytesRead, + void* Overlapped); +int ReadFile(unsigned Handle, + void* Buffer, + unsigned NumberOfBytesToRead, + unsigned* NumberOfBytesRead, + void* Overlapped) +{ + asm("push dword [ebp+24]\n" + "push dword [ebp+20]\n" + "push dword [ebp+16]\n" + "push dword [ebp+12]\n" + "push dword [ebp+8]\n" + "call [__imp__ReadFile]"); +} + +extern int (*_imp__WriteFile)(unsigned Handle, + void* Buffer, + unsigned NumberOfBytesToWrite, + unsigned* NumberOfBytesWritten, + void* Overlapped); +int WriteFile(unsigned Handle, + void* Buffer, + unsigned NumberOfBytesToWrite, + unsigned* NumberOfBytesWritten, + void* Overlapped) +{ + asm("push dword [ebp+24]\n" + "push dword [ebp+20]\n" + "push dword [ebp+16]\n" + "push dword [ebp+12]\n" + "push dword [ebp+8]\n" + "call [__imp__WriteFile]"); +} +#endif // _WIN32 + +#ifdef _RETROBSD +// flags for RetroBSD's open(): +#define O_RDONLY 0x0000 +#define O_WRONLY 0x0001 +#define O_RDWR 0x0002 +#define O_APPEND 0x0008 +#define O_CREAT 0x0200 +#define O_TRUNC 0x0400 +#define O_TEXT 0x0000 +#define O_BINARY 0x0000 +#endif + +int OsCreateOrTruncate(char* name) +{ +#ifdef _RETROBSD + int fd; + int oflags = O_TRUNC | O_CREAT | O_WRONLY; + int mode = 0664; // rw-rw-r-- + asm volatile ("move $4, %1\n" + "move $5, %2\n" + "move $6, %3\n" + "syscall 5\n" // SYS_open + "nop\n" + "nop\n" + "move %0, $2\n" + : "=r" (fd) + : "r" (name), "r" (oflags), "r" (mode) + : "$2", "$4", "$5", "$6"); + if (fd < 0) + fd = -1; + return fd; +#else +#ifdef _LINUX + asm("mov eax, 5\n" // sys_open + "mov ebx, [ebp + 8]\n" + "mov ecx, 0x641\n" // truncate if exists, else create, writing only + "mov edx, 664o\n" // rw-rw-r-- + "int 0x80\n" + "mov ebx, eax\n" + "sar ebx, 31\n" + "or eax, ebx"); +#else +#ifdef _WIN32 + unsigned h = CreateFileA(name, + GENERIC_WRITE, + FILE_SHARE_READ, + NULL, + CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, + NULL); + return h; +#else +#ifndef __SMALLER_C_16__ + asm("mov ah, 0x3c\n" + "xor cx, cx\n" + "mov edx, [bp + 8]\n" + "ror edx, 4\n" + "mov ds, dx\n" + "shr edx, 28\n" + "int 0x21\n" + "sbb ebx, ebx\n" + "and eax, 0xffff\n" + "or eax, ebx"); +#else + asm("mov ah, 0x3c\n" + "xor cx, cx\n" + "mov dx, [bp + 4]\n" + "int 0x21\n" + "sbb bx, bx\n" + "or ax, bx"); +#endif +#endif +#endif +#endif +} + +int OsOpen(char* name) +{ +#ifdef _RETROBSD + int fd; + int oflags = O_RDONLY; + int mode = 0444; // r--r--r-- (ignored) + asm volatile ("move $4, %1\n" + "move $5, %2\n" + "move $6, %3\n" + "syscall 5\n" // SYS_open + "nop\n" + "nop\n" + "move %0, $2\n" + : "=r" (fd) + : "r" (name), "r" (oflags), "r" (mode) + : "$2", "$4", "$5", "$6"); + if (fd < 0) + fd = -1; + return fd; +#else +#ifdef _LINUX + asm("mov eax, 5\n" // sys_open + "mov ebx, [ebp + 8]\n" + "mov ecx, 0\n" // reading only + "mov edx, 444o\n" // r--r--r-- (ignored) + "int 0x80\n" + "mov ebx, eax\n" + "sar ebx, 31\n" + "or eax, ebx"); +#else +#ifdef _WIN32 + unsigned h = CreateFileA(name, + GENERIC_READ, + FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + return h; +#else +#ifndef __SMALLER_C_16__ + asm("mov ax, 0x3d00\n" + "mov edx, [bp + 8]\n" + "ror edx, 4\n" + "mov ds, dx\n" + "shr edx, 28\n" + "int 0x21\n" + "sbb ebx, ebx\n" + "and eax, 0xffff\n" + "or eax, ebx"); +#else + asm("mov ax, 0x3d00\n" + "mov dx, [bp + 4]\n" + "int 0x21\n" + "sbb bx, bx\n" + "or ax, bx"); +#endif +#endif +#endif +#endif +} + +int OsClose(int fd) +{ +#ifdef _RETROBSD + int err; + asm volatile ("move $4, %1\n" + "syscall 6\n" // SYS_close + "nop\n" + "nop\n" + "move %0, $2\n" + : "=r" (err) + : "r" (fd) + : "$2", "$4"); + return err; +#else +#ifdef _LINUX + asm("mov eax, 6\n" // sys_close + "mov ebx, [ebp + 8]\n" + "int 0x80"); +#else +#ifdef _WIN32 + return CloseHandle(fd) ? 0 : -1; +#else +#ifndef __SMALLER_C_16__ + asm("mov ah, 0x3e\n" + "mov bx, [bp + 8]\n" + "int 0x21\n" + "sbb eax, eax"); +#else + asm("mov ah, 0x3e\n" + "mov bx, [bp + 4]\n" + "int 0x21\n" + "sbb ax, ax"); +#endif +#endif +#endif +#endif +} + +int OsRead(int fd, void* p, unsigned s) +{ +#ifdef _RETROBSD + int sz; + asm volatile ("move $4, %1\n" + "move $5, %2\n" + "move $6, %3\n" + "syscall 3\n" // SYS_read + "nop\n" + "nop\n" + "move %0, $2\n" + : "=r" (sz) + : "r" (fd), "r" (p), "r" (s) + : "$2", "$4", "$5", "$6", "memory"); + return sz; +#else +#ifdef _LINUX + asm("mov eax, 3\n" // sys_read + "mov ebx, [ebp + 8]\n" + "mov ecx, [ebp + 12]\n" + "mov edx, [ebp + 16]\n" + "int 0x80"); +#else +#ifdef _WIN32 + unsigned NumberOfBytesRead; + ReadFile(fd, + p, + s, + &NumberOfBytesRead, + NULL); + return NumberOfBytesRead; +#else +#ifndef __SMALLER_C_16__ + asm("mov ah, 0x3f\n" + "mov bx, [bp + 8]\n" + "mov edx, [bp + 12]\n" + "ror edx, 4\n" + "mov ds, dx\n" + "shr edx, 28\n" + "mov cx, [bp + 16]\n" + "int 0x21"); + asm("sbb ebx, ebx\n" + "and eax, 0xffff\n" + "or eax, ebx"); +#else + asm("mov ah, 0x3f\n" + "mov bx, [bp + 4]\n" + "mov dx, [bp + 6]\n" + "mov cx, [bp + 8]\n" + "int 0x21\n" + "sbb bx, bx\n" + "or ax, bx"); +#endif +#endif +#endif +#endif +} + +int OsWrite(int fd, void* p, unsigned s) +{ +#ifdef _RETROBSD + int sz; + asm volatile ("move $4, %1\n" + "move $5, %2\n" + "move $6, %3\n" + "syscall 4\n" // SYS_write + "nop\n" + "nop\n" + "move %0, $2\n" + : "=r" (sz) + : "r" (fd), "r" (p), "r" (s) + : "$2", "$4", "$5", "$6", "memory"); // WTF? I shouldn't need "memory" here !!! + return sz; +#else +#ifdef _LINUX + asm("mov eax, 4\n" // sys_write + "mov ebx, [ebp + 8]\n" + "mov ecx, [ebp + 12]\n" + "mov edx, [ebp + 16]\n" + "int 0x80"); +#else +#ifdef _WIN32 + unsigned NumberOfBytesWritten; + WriteFile(fd, + p, + s, + &NumberOfBytesWritten, + NULL); + return NumberOfBytesWritten; +#else +#ifndef __SMALLER_C_16__ + asm("mov cx, [bp + 16]\n" + "test cx, cx\n" + "jnz DosWriteCont\n" + "xor eax, eax\n" + "jmp DosWriteEnd"); + asm("DosWriteCont:\n" + "mov ah, 0x40\n" + "mov bx, [bp + 8]\n" + "mov edx, [bp + 12]\n" + "ror edx, 4\n" + "mov ds, dx\n" + "shr edx, 28\n" + "int 0x21"); + asm("sbb ebx, ebx\n" + "and eax, 0xffff\n" + "or eax, ebx\n" + "DosWriteEnd:"); +#else + asm("mov cx, [bp + 8]\n" + "test cx, cx\n" + "jnz DosWriteCont\n" + "xor ax, ax\n" + "jmp DosWriteEnd"); + asm("DosWriteCont:\n" + "mov ah, 0x40\n" + "mov bx, [bp + 4]\n" + "mov dx, [bp + 6]\n" + "int 0x21\n" + "sbb bx, bx\n" + "or ax, bx\n" + "DosWriteEnd:"); +#endif +#endif +#endif +#endif +} + +#ifdef _DOS +unsigned DosGetPspSeg(void) +{ +#ifndef __SMALLER_C_16__ + asm("mov ah, 0x51\n" + "int 0x21\n" + "movzx eax, bx"); +#else + asm("mov ah, 0x51\n" + "int 0x21\n" + "mov ax, bx"); +#endif +} +#endif // _DOS + +void exit(int e) +{ +#ifdef _RETROBSD + asm volatile ("move $4, %0\n" + "syscall 1" // SYS_exit + : + : "r" (e) + : "$2", "$4"); + __builtin_unreachable(); +#else +#ifdef _LINUX + asm("mov eax, 1\n" + "mov ebx, [ebp + 8]\n" + "int 0x80"); +#else +#ifdef _WIN32 + ExitProcess(e); +#else +#ifndef __SMALLER_C_16__ + asm("mov ah, 0x4c\n" + "mov al, [bp + 8]\n" + "int 0x21"); +#else + asm("mov ah, 0x4c\n" + "mov al, [bp + 4]\n" + "int 0x21"); +#endif +#endif +#endif +#endif +} + +#ifdef _DOS +char __ProgName__[128]; +char __ProgParams__[128]; +int __argc__ = 1; +char* __argv__[64] = { "" }; +#endif +#ifdef _WIN32 +char __ProgParams__[1024]; +int __argc__ = 1; +char* __argv__[512] = { "" }; +#endif + +int __StdOutHandle__ = 1; // 1 for DOS/Linux/RetroBSD, GetStdHandle(STD_OUTPUT_HANDLE) for Windows + +#ifdef _DOS +void __setargs__(int* pargc, char*** pargv) +{ + unsigned psp = DosGetPspSeg(); + unsigned env = peek(psp, 0x2c); + unsigned i, j, len; + + // First, try to extract the full program name. + + // Skip past the environment strings. + i = 0; + for (;;) + { + if ((peekb(env, i) | peekb(env, i + 1)) == 0) + { + i += 2; + break; + } + ++i; + } + + // Are there any other strings afterwards? + if (peekb(env, i) | peekb(env, i + 1)) + { + j = 0; + i += 2; + // The first one is the full program name. + while ((__ProgName__[j++] = peekb(env, i++)) != 0); + __argv__[0] = __ProgName__; + } + + // Next, extract program arguments from the PSP. + + j = i = 0; + len = peekb(psp, 0x80); + while (i < len) + { + char c; + if ((c = peekb(psp, 0x81 + i)) == ' ') + { + ++i; + continue; + } + __argv__[__argc__++] = __ProgParams__ + j; + __ProgParams__[j++] = c; + ++i; + while (i < len) + { + if ((c = peekb(psp, 0x81 + i)) == ' ') + break; + __ProgParams__[j++] = c; + ++i; + } + __ProgParams__[j++] = 0; + } + + *pargc = __argc__; + *pargv = __argv__; +} +#endif +#ifdef _WIN32 +void __setargs__(int* pargc, char*** pargv) +{ + unsigned i, j, len; + char* p = GetCommandLineA(); + j = i = 0; + len = strlen(p); + __argc__ = 0; + while (i < len) + { + char c; + if ((c = p[i]) == ' ') + { + ++i; + continue; + } + __argv__[__argc__++] = __ProgParams__ + j; + __ProgParams__[j++] = c; + ++i; + while (i < len) + { + if ((c = p[i]) == ' ') + break; + __ProgParams__[j++] = c; + ++i; + } + __ProgParams__[j++] = 0; + } + + *pargc = __argc__; + *pargv = __argv__; + + __StdOutHandle__ = GetStdHandle(STD_OUTPUT_HANDLE); +} +#endif + +// TBD??? Not sure if this limited buffering actually improves performance. +#ifndef NO_PREPROCESSOR +#define MAX_FILES 10 +#else +#define MAX_FILES 2 +#endif +#define FILE_BUF_SIZE (512*1) +unsigned __FileCnt__ = 0; +unsigned __FileHandles__[MAX_FILES]; +unsigned char __FileBufs__[MAX_FILES][FILE_BUF_SIZE]; +char __FileBufDirty__[MAX_FILES]; +unsigned __FileBufSize__[MAX_FILES]; +unsigned __FileBufPos__[MAX_FILES]; + +FILE* fopen(char* name, char* mode) +{ + FILE* f = NULL; + unsigned i, fd = -1; + + if (strchr(mode, 'a') || strchr(mode, '+') || strchr(mode, 'b')) + return f; + + if (__FileCnt__ >= MAX_FILES) + return f; + + if (strchr(mode, 'r')) + { + fd = OsOpen(name); + } + else if (strchr(mode, 'w')) + { + fd = OsCreateOrTruncate(name); + } + + if (fd != (unsigned)-1) + { + for (i = 0; i < MAX_FILES; ++i) + if (!__FileHandles__[i]) + { + __FileHandles__[i] = fd; + __FileBufDirty__[i] = 0; + __FileBufSize__[i] = 0; + __FileBufPos__[i] = 0; + ++__FileCnt__; + f = (FILE*)(i + 1); + break; + } + } + + return f; +} + +int putchar(int c) +{ + unsigned char ch = c; + +#ifndef _RETROBSD +#ifndef _LINUX + if (c == '\n') + { + if (putchar('\r') == EOF) + return EOF; + } +#endif +#endif + + if (OsWrite(__StdOutHandle__, &ch, 1) != 1) + return EOF; + + return ch; +} + +int puts(char *s) +{ + int c; + + while ((c = *s++) != '\0') + if (putchar(c) == EOF) + return EOF; + + return putchar('\n'); +} + +int fputs(char* s, FILE* stream) +{ + int c; + + while ((c = *s++) != '\0') + if (fputc(c, stream) == EOF) + return EOF; + + return 0; +} + +int vfprintf(FILE* stream, char* fmt, void* vl) +{ + return __vsprintf__(NULL, stream, fmt, vl); +} + +int fprintf(FILE* stream, char* fmt, ...) +{ + void** pp = (void**)&fmt; + return vfprintf(stream, fmt, pp + 1); +} + +int fgetc(FILE* stream) +{ + unsigned char ch; + unsigned i = (unsigned)stream, fd, pos; + + fd = __FileHandles__[--i]; + + if ((pos = __FileBufPos__[i]) >= __FileBufSize__[i]) + { + unsigned sz; + sz = OsRead(fd, __FileBufs__[i], FILE_BUF_SIZE); + if (!sz || sz == (unsigned)-1) + return EOF; + __FileBufSize__[i] = sz; + pos = 0; + } + + ch = __FileBufs__[i][pos++]; + __FileBufPos__[i] = pos; + + return ch; +} + +int fputc(int c, FILE* stream) +{ + unsigned char ch = c; + unsigned i = (unsigned)stream, fd, pos; + +#ifndef _RETROBSD +#ifndef _LINUX + if (c == '\n') + { + if (fputc('\r', stream) == EOF) + return EOF; + } +#endif +#endif + + fd = __FileHandles__[--i]; + + __FileBufDirty__[i] = 1; + pos = __FileBufPos__[i]; + __FileBufs__[i][pos++] = ch; + + if (pos >= FILE_BUF_SIZE) + { + if (OsWrite(fd, __FileBufs__[i], FILE_BUF_SIZE) != FILE_BUF_SIZE) + return EOF; + __FileBufDirty__[i] = 0; + __FileBufSize__[i] = -1; + __FileBufPos__[i] = -1; + } + + ++__FileBufSize__[i]; + ++__FileBufPos__[i]; + + return ch; +} + +int fclose(FILE* stream) +{ + unsigned i = (unsigned)stream, fd; + + fd = __FileHandles__[--i]; + + if (__FileBufDirty__[i]) + { + unsigned sz = __FileBufSize__[i]; + if ((unsigned)OsWrite(fd, __FileBufs__[i], sz) != sz) + { + __FileHandles__[i] = 0; + --__FileCnt__; + OsClose(fd); + return EOF; + } + } + + __FileHandles__[i] = 0; + --__FileCnt__; + return OsClose(fd); +} diff --git a/src/cmd/smlrc/license.txt b/src/cmd/smlrc/license.txt new file mode 100644 index 0000000..18e7bf9 --- /dev/null +++ b/src/cmd/smlrc/license.txt @@ -0,0 +1,26 @@ +Copyright (c) 2012, Alexey Frunze +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +The views and conclusions contained in the software and documentation are those +of the authors and should not be interpreted as representing official policies, +either expressed or implied, of the FreeBSD Project. diff --git a/src/cmd/smlrc/readme.txt b/src/cmd/smlrc/readme.txt new file mode 100644 index 0000000..e349681 --- /dev/null +++ b/src/cmd/smlrc/readme.txt @@ -0,0 +1,20 @@ +Smaller C is a simple and small single-pass C compiler, +currently supporting most of the C language common between C89/ANSI C +and C99 (minus some C89 and plus some C99 features). + +Currently it generates 16-bit and 32-bit 80386+ assembly code for NASM +that can then be assembled and linked into DOS, Windows and Linux programs. + +Code generation for MIPS CPUs is also supported (primarily for RetroBSD). + +The compiler is capable of compiling its own source code. + +You can fully recompile the compiler only with itself and NASM for the +x86 platform (no linker is necessary). + +See the Wiki for more up-to-date details: +http://github.com/alexfru/SmallerC/wiki + +Links: +NASM: http://nasm.us/ +RetroBSD: http://retrobsd.org/ diff --git a/src/cmd/smlrc/smlrc.c b/src/cmd/smlrc/smlrc.c new file mode 100644 index 0000000..926a974 --- /dev/null +++ b/src/cmd/smlrc/smlrc.c @@ -0,0 +1,7385 @@ +/* +Copyright (c) 2012-2014, Alexey Frunze +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +The views and conclusions contained in the software and documentation are those +of the authors and should not be interpreted as representing official policies, +either expressed or implied, of the FreeBSD Project. +*/ + +/*****************************************************************************/ +/* */ +/* Smaller C */ +/* */ +/* A simple and small single-pass C compiler ("small C" class). */ +/* */ +/* Produces 16/32-bit 80386 assembly output for NASM. */ +/* Produces 32-bit MIPS assembly output for gcc/as. */ +/* */ +/* Main file */ +/* */ +/*****************************************************************************/ + +// You need to declare __setargv__ as an extern symbol when bootstrapping with +// Turbo C++ in order to access main()'s argc and argv params. +// +// This is no longer supported since the compiler is too big to be compiled +// with itself into object files and then linked with Turbo C++'s standard C library. +// +// extern char _setargv__; + +#ifdef NO_EXTRAS +#define NO_PPACK +#define NO_TYPEDEF_ENUM +#define NO_FUNC_ +#endif + +#ifndef __SMALLER_C__ + +#include +#include +#include +#include +#include +#include + +#if UINT_MAX >= 0xFFFFFFFF +#define CAN_COMPILE_32BIT +#endif + +#else // #ifndef __SMALLER_C__ + +#define NULL 0 +#define size_t unsigned int + +#define CHAR_BIT (8) + +#ifdef __SMALLER_C_SCHAR__ +#define CHAR_MIN (-128) +#define CHAR_MAX (127) +#endif +#ifdef __SMALLER_C_UCHAR__ +#define CHAR_MIN (0) +#define CHAR_MAX (255) +#endif + +#ifndef __SMALLER_C_SCHAR__ +#ifndef __SMALLER_C_UCHAR__ +#error __SMALLER_C_SCHAR__ or __SMALLER_C_UCHAR__ must be defined +#endif +#endif + +#ifdef __SMALLER_C_16__ +#define INT_MAX (32767) +#define INT_MIN (-32767-1) +#define UINT_MAX (65535u) +#define UINT_MIN (0u) +#endif +#ifdef __SMALLER_C_32__ +#define INT_MAX (2147483647) +#define INT_MIN (-2147483647-1) +#define UINT_MAX (4294967295u) +#define UINT_MIN (0u) +#define CAN_COMPILE_32BIT +#endif + +#ifndef __SMALLER_C_16__ +#ifndef __SMALLER_C_32__ +#error __SMALLER_C_16__ or __SMALLER_C_32__ must be defined +#endif +#endif + +void exit(int); +int atoi(char*); + +size_t strlen(char*); +char* strcpy(char*, char*); +char* strchr(char*, int); +int strcmp(char*, char*); +int strncmp(char*, char*, size_t); +void* memmove(void*, void*, size_t); +void* memcpy(void*, void*, size_t); +void* memset(void*, int, size_t); + +int isspace(int); +int isdigit(int); +int isalpha(int); +int isalnum(int); + +#define FILE void +#define EOF (-1) +FILE* fopen(char*, char*); +int fclose(FILE*); +int putchar(int); +int fputc(int, FILE*); +int fgetc(FILE*); +int puts(char*); +int fputs(char*, FILE*); +int sprintf(char*, char*, ...); +//int vsprintf(char*, char*, va_list); +int vsprintf(char*, char*, void*); +int printf(char*, ...); +int fprintf(FILE*, char*, ...); +//int vprintf(char*, va_list); +int vprintf(char*, void*); +//int vfprintf(FILE*, char*, va_list); +int vfprintf(FILE*, char*, void*); + +#endif // #ifndef __SMALLER_C__ + + +//////////////////////////////////////////////////////////////////////////////// + +// all public macros + +#ifndef MAX_IDENT_LEN +#define MAX_IDENT_LEN 31 +#endif +#define MAX_STRING_LEN 127 +#define MAX_CHAR_QUEUE_LEN 256 + +#ifndef MAX_MACRO_TABLE_LEN +#define MAX_MACRO_TABLE_LEN 4096 +#endif + +#ifndef MAX_STRING_TABLE_LEN +#define MAX_STRING_TABLE_LEN 512 +#endif + +#ifndef MAX_IDENT_TABLE_LEN +#define MAX_IDENT_TABLE_LEN (4096+656) +#endif + +#ifndef SYNTAX_STACK_MAX +#define SYNTAX_STACK_MAX (2048+480) +#endif + +#ifndef MAX_FILE_NAME_LEN +#define MAX_FILE_NAME_LEN 95 +#endif + +#ifndef NO_PREPROCESSOR +#define MAX_INCLUDES 8 +#define PREP_STACK_SIZE 8 +#define MAX_SEARCH_PATH 256 +#else +#define MAX_INCLUDES 1 +#define PREP_STACK_SIZE 1 +#define MAX_SEARCH_PATH 1 +#endif + +/* +-~* /% &|^! << >> && || < <= > >= == != () *[] ++ -- = += -= ~= *= /= %= &= |= ^= <<= >>= {} ,;: -> ... */ + +#define tokEof 0 +#define tokNumInt 1 +#define tokNumUint 2 +#define tokLitStr 3 + +#define tokLShift 4 +#define tokRShift 5 +#define tokLogAnd 6 +#define tokLogOr 7 +#define tokEQ 8 +#define tokNEQ 9 +#define tokLEQ 10 +#define tokGEQ 11 +#define tokInc 12 +#define tokDec 13 +#define tokArrow 14 +#define tokEllipsis 15 + +#define tokIdent 16 +#define tokVoid 17 +#define tokChar 18 +#define tokInt 19 +#define tokReturn 20 +#define tokGoto 21 +#define tokIf 22 +#define tokElse 23 +#define tokWhile 24 +#define tokCont 25 +#define tokBreak 26 +#define tokSizeof 27 + +#define tokAssignMul 'A' +#define tokAssignDiv 'B' +#define tokAssignMod 'C' +#define tokAssignAdd 'D' +#define tokAssignSub 'E' +#define tokAssignLSh 'F' +#define tokAssignRSh 'G' +#define tokAssignAnd 'H' +#define tokAssignXor 'I' +#define tokAssignOr 'J' + +#define tokFloat 'a' +#define tokDouble 'b' +#define tokLong 'c' +#define tokShort 'd' +#define tokUnsigned 'e' +#define tokSigned 'f' +#define tokConst 'g' +#define tokVolatile 'h' +#define tokRestrict 'i' +#define tokStatic 'j' +#define tokInline 'k' +#define tokExtern 'l' +#define tokAuto 'm' +#define tokRegister 'n' +#define tokTypedef 'o' +#define tokEnum 'p' +#define tokStruct 'q' +#define tokUnion 'r' +#define tokDo 's' +#define tokFor 't' +#define tokSwitch 'u' +#define tokCase 'v' +#define tokDefault 'w' +#define tok_Bool 'x' +#define tok_Complex 'y' +#define tok_Imagin 'z' + +#define tok_Asm '`' + +/* Pseudo-tokens (converted from others or generated) */ +#define tokURShift 28 +#define tokUDiv 29 +#define tokUMod 30 +#define tokAssignURSh 31 +#define tokAssignUDiv '@' +#define tokAssignUMod 'K' +#define tokComma '0' + +#define tokIfNot 'L' + +#define tokUnaryAnd 'M' +#define tokUnaryStar 'N' +#define tokUnaryPlus 'O' +#define tokUnaryMinus 'P' + +#define tokPostInc 'Q' +#define tokPostDec 'R' +#define tokPostAdd 'S' +#define tokPostSub 'T' + +#define tokULess 'U' +#define tokUGreater 'V' +#define tokULEQ 'W' +#define tokUGEQ 'X' + +#define tokLocalOfs 'Y' +#define tokShortCirc 'Z' + +#define tokSChar 0x80 +#define tokUChar 0x81 +#define tokUShort 0x82 +#define tokULong 0x83 +//#define tokLongLong 0x84 +//#define tokULongLong 0x85 +//#define tokLongDbl 0x86 +#define tokGotoLabel 0x8F +#define tokStructPtr 0x90 +#define tokTag 0x91 +#define tokMemberIdent 0x92 +#define tokEnumPtr 0x93 + +#define FormatFlat 0 +#define FormatSegmented 1 +#define FormatSegTurbo 2 +#define FormatSegHuge 3 + +#define SymVoidSynPtr 0 +#define SymIntSynPtr 1 +#define SymUintSynPtr 2 +#define SymFuncPtr 3 + +#ifndef STACK_SIZE +#define STACK_SIZE 128 +#endif + +#define SymFxn 1 +#define SymGlobalVar 2 +#define SymGlobalArr 3 +#define SymLocalVar 4 +#define SymLocalArr 5 + +// all public prototypes +int uint2int(unsigned); +unsigned truncUint(unsigned); +int truncInt(int); + +int GetToken(void); +char* GetTokenName(int token); + +int GetTokenValueInt(void); + +char* GetTokenValueString(void); +int GetTokenValueStringLength(void); + +char* GetTokenIdentName(void); + +#ifndef NO_PREPROCESSOR +void DumpMacroTable(void); +#endif + +void PurgeStringTable(void); +void AddString(int label, char* str, int len); +char* FindString(int label); + +int AddIdent(char* name); +int FindIdent(char* name); +void DumpIdentTable(void); +char* lab2str(char* p, int n); + +void GenInit(void); +void GenFin(void); +int GenInitParams(int argc, char** argv, int* idx); +void GenInitFinalize(void); +void GenStartCommentLine(void); +void GenWordAlignment(void); +void GenLabel(char* Label, int Static); +void GenNumLabel(int Label); +void GenZeroData(unsigned Size); +void GenIntData(int Size, int Val); +void GenStartAsciiString(void); +void GenAddrData(int Size, char* Label); + +void GenJumpUncond(int Label); +void GenJumpIfZero(int Label); +void GenJumpIfNotZero(int Label); +void GenJumpIfNotEqual(int val, int Label); + +void GenFxnProlog(void); +void GenFxnEpilog(void); + +void GenLocalAlloc(int Size); + +unsigned GenStrData(int generatingCode, unsigned requiredLen); +void GenExpr(void); + +void PushSyntax(int t); +void PushSyntax2(int t, int v); + +void DumpSynDecls(void); + +void push2(int v, int v2); +void ins2(int pos, int v, int v2); +void ins(int pos, int v); +void del(int pos, int cnt); + +int TokenStartsDeclaration(int t, int params); +int ParseDecl(int tok, unsigned structInfo[4], int cast, int label); + +void ShiftChar(void); +int puts2(char*); +int printf2(char*, ...); + +void error(char* format, ...); +void warning(char* format, ...); +void errorFile(char* n); +void errorFileName(void); +void errorInternal(int n); +void errorChrStr(void); +void errorUnexpectedToken(int tok); +void errorDirective(void); +void errorCtrlOutOfScope(void); +void errorDecl(void); +void errorVarSize(void); +void errorInit(void); +void errorUnexpectedVoid(void); +void errorOpType(void); +void errorNotLvalue(void); +void errorNotConst(void); +void errorLongExpr(void); + +int FindSymbol(char* s); +int SymType(int SynPtr); +int FindTaggedDecl(char* s, int start, int* CurScope); +#ifndef NO_TYPEDEF_ENUM +int FindTypedef(char* s, int* CurScope, int forUse); +#endif +int GetDeclSize(int SyntaxPtr, int SizeForDeref); + +int ParseExpr(int tok, int* GotUnary, int* ExprTypeSynPtr, int* ConstExpr, int* ConstVal, int commaSeparator, int label); +int GetFxnInfo(int ExprTypeSynPtr, int* MinParams, int* MaxParams, int* ReturnExprTypeSynPtr); + +// all data + +int verbose = 0; +int warnCnt = 0; + +// prep.c data + +int TokenValueInt = 0; +char TokenIdentName[MAX_IDENT_LEN + 1]; +int TokenIdentNameLen = 0; +char TokenValueString[MAX_STRING_LEN + 1]; +int TokenStringLen = 0; +int LineNo = 1; +int LinePos = 1; +char CharQueue[MAX_CHAR_QUEUE_LEN]; +int CharQueueLen = 0; + +#ifndef NO_PREPROCESSOR +/* + Macro table entry format: + idlen char: identifier length (<= 127) + id char[idlen]: identifier (ASCIIZ) + exlen char: length of what the identifier expands into (<= 127) + ex char[exlen]: what the identifier expands into (ASCII) +*/ +char MacroTable[MAX_MACRO_TABLE_LEN]; +int MacroTableLen = 0; +#endif + +/* + String table entry format: + labell uchar: temporary identifier's (char*) label number low 8 bits + labelh uchar: temporary identifier's (char*) label number high 8 bits + len char: string length (<= 127) + str char[len]: string (ASCII) +*/ +char StringTable[MAX_STRING_TABLE_LEN]; +int StringTableLen = 0; + +/* + Identifier table entry format: + id char[idlen]: string (ASCIIZ) + idlen char: string length (<= 127) +*/ +char IdentTable[MAX_IDENT_TABLE_LEN]; +int IdentTableLen = 0; + +#ifndef MAX_GOTO_LABELS +#define MAX_GOTO_LABELS 16 +#endif +int gotoLabels[MAX_GOTO_LABELS][2]; +// gotoLabStat[]: bit 1 = used (by "goto label;"), bit 0 = defined (with "label:") +char gotoLabStat[MAX_GOTO_LABELS]; +int gotoLabCnt = 0; + +// Data structures to support #include +int FileCnt = 0; +char FileNames[MAX_INCLUDES][MAX_FILE_NAME_LEN + 1]; +FILE* Files[MAX_INCLUDES]; +FILE* OutFile; +char CharQueues[MAX_INCLUDES][3]; +int LineNos[MAX_INCLUDES]; +int LinePoss[MAX_INCLUDES]; +char SearchPaths[MAX_SEARCH_PATH]; +int SearchPathsLen = 0; + +// Data structures to support #ifdef/#ifndef,#else,#endif +int PrepDontSkipTokens = 1; +int PrepStack[PREP_STACK_SIZE][2]; +int PrepSp = 0; + +// Data structures to support #pragma pack(...) +#ifndef NO_PPACK +#define PPACK_STACK_SIZE 16 +int PragmaPackValue; +int PragmaPackValues[PPACK_STACK_SIZE]; +int PragmaPackSp = 0; +#endif + +// expr.c data + +int ExprLevel = 0; + +// TBD??? merge expression and operator stacks into one +int stack[STACK_SIZE][2]; +int sp = 0; + +#define OPERATOR_STACK_SIZE STACK_SIZE +int opstack[OPERATOR_STACK_SIZE][2]; +int opsp = 0; + +// smc.c data + +int OutputFormat = FormatSegmented; +int GenExterns = 1; + +#ifdef CAN_COMPILE_32BIT +// Name of the function to call in main()'s prolog to construct C++ objects/init data. +// gcc calls __main(). +char* MainPrologCtorFxn = NULL; +#endif + +// Names of C functions and variables are usually prefixed with an underscore. +// One notable exception is the ELF format used by gcc in Linux. +// Global C identifiers in the ELF format should not be predixed with an underscore. +int UseLeadingUnderscores = 1; + +char* FileHeader = ""; +char* CodeHeader = ""; +char* CodeFooter = ""; +char* DataHeader = ""; +char* DataFooter = ""; + +int CharIsSigned = 1; +int SizeOfWord = 2; // in chars (char can be a multiple of octets); ints and pointers are of word size + +// TBD??? implement a function to allocate N labels with overflow checks +int LabelCnt = 1; // label counter for jumps +int StructCpyLabel = 0; // label of the function to copy structures/unions + +// call stack (from higher to lower addresses): +// param n +// ... +// param 1 +// return address +// saved xbp register +// local var 1 +// ... +// local var n +int CurFxnSyntaxPtr = 0; +int CurFxnParamCnt = 0; +int CurFxnParamCntMin = 0; +int CurFxnParamCntMax = 0; +int CurFxnParamOfs = 0; // positive +int CurFxnLocalOfs = 0; // negative +int CurFxnMinLocalOfs = 0; // negative + +int CurFxnReturnExprTypeSynPtr = 0; +int CurFxnEpilogLabel = 0; + +char* CurFxnName = NULL; +#ifndef NO_FUNC_ +int CurFxnNameLabel = 0; +#endif + +int ParseLevel = 0; // Parse level/scope (file:0, fxn:1+) +int ParamLevel = 0; // 1+ if parsing params, 0 otherwise + +int SyntaxStack[SYNTAX_STACK_MAX][2]; +int SyntaxStackCnt = 0; + +// all code + +int uint2int(unsigned n) +{ + int r; + // Convert n to (int)n in such a way that (unsigned)(int)n == n, + // IOW, avoid signed overflows in (int)n. + // We're assuming ints are 2's complement. + + // "n < INT_MAX + 1u" is equivalent to "n <= INT_MAX" without the + // possible warning about comparing signed and unsigned types + if (n < INT_MAX + 1u) + { + r = n; + } + else + { + n = n - INT_MAX - 1; // Now, 0 <= n <= INT_MAX, n is representable in int + r = n; + r = r - INT_MAX - 1; // Now, INT_MIN <= r <= -1 + } + + return r; +} + +unsigned truncUint(unsigned n) +{ + // Truncate n to SizeOfWord * 8 bits + if (SizeOfWord == 2) + n &= ~(~0u << 8 << 8); + else if (SizeOfWord == 4) + n &= ~(~0u << 8 << 12 << 12); + return n; +} + +int truncInt(int n) +{ + // Truncate n to SizeOfWord * 8 bits and then sign-extend it + unsigned un = n; + if (SizeOfWord == 2) + { + un &= ~(~0u << 8 << 8); + un |= (((un >> 8 >> 7) & 1) * ~0u) << 8 << 8; + } + else if (SizeOfWord == 4) + { + un &= ~(~0u << 8 << 12 << 12); + un |= (((un >> 8 >> 12 >> 11) & 1) * ~0u) << 8 << 12 << 12; + } + return uint2int(un); +} + +// prep.c code + +#ifndef NO_PREPROCESSOR +int FindMacro(char* name) +{ + int i; + + for (i = 0; i < MacroTableLen; ) + { + if (!strcmp(MacroTable + i + 1, name)) + return i + 1 + MacroTable[i]; + + i = i + 1 + MacroTable[i]; // skip id + i = i + 1 + MacroTable[i]; // skip ex + } + + return -1; +} + +int UndefineMacro(char* name) +{ + int i; + + for (i = 0; i < MacroTableLen; ) + { + if (!strcmp(MacroTable + i + 1, name)) + { + int len = 1 + MacroTable[i]; // id part len + len = len + 1 + MacroTable[i + len]; // + ex part len + + memmove(MacroTable + i, + MacroTable + i + len, + MacroTableLen - i - len); + MacroTableLen -= len; + + return 1; + } + + i = i + 1 + MacroTable[i]; // skip id + i = i + 1 + MacroTable[i]; // skip ex + } + + return 0; +} + +void AddMacroIdent(char* name) +{ + int l = strlen(name); + + if (l >= 127) + error("Macro identifier too long '%s'\n", name); + + if (MAX_MACRO_TABLE_LEN - MacroTableLen < l + 3) + error("Macro table exhausted\n"); + + MacroTable[MacroTableLen++] = l + 1; // idlen + strcpy(MacroTable + MacroTableLen, name); + MacroTableLen += l + 1; + + MacroTable[MacroTableLen] = 0; // exlen +} + +void AddMacroExpansionChar(char e) +{ + if (e == '\0') + { + // finalize macro definition entry + // remove trailing space first + while (MacroTable[MacroTableLen] && + strchr(" \t", MacroTable[MacroTableLen + MacroTable[MacroTableLen]])) + MacroTable[MacroTableLen]--; + MacroTableLen += 1 + MacroTable[MacroTableLen]; + return; + } + + if (MacroTableLen + 1 + MacroTable[MacroTableLen] >= MAX_MACRO_TABLE_LEN) + error("Macro table exhausted\n"); + + if (MacroTable[MacroTableLen] >= 127) + error("Macro definition too long\n"); + + MacroTable[MacroTableLen + 1 + MacroTable[MacroTableLen]] = e; + MacroTable[MacroTableLen]++; +} + +void DefineMacro(char* name, char* expansion) +{ + AddMacroIdent(name); + while (*expansion != '\0') + AddMacroExpansionChar(*expansion++); + AddMacroExpansionChar('\0'); +} + +void DumpMacroTable(void) +{ +#ifndef NO_ANNOTATIONS + int i, j; + + puts2(""); + GenStartCommentLine(); printf2("Macro table:\n"); + for (i = 0; i < MacroTableLen; ) + { + GenStartCommentLine(); printf2("Macro %s = ", MacroTable + i + 1); + i = i + 1 + MacroTable[i]; // skip id + printf2("`"); + j = MacroTable[i++]; + while (j--) + printf2("%c", MacroTable[i++]); + printf2("`\n"); + } + GenStartCommentLine(); printf2("Bytes used: %d/%d\n\n", MacroTableLen, MAX_MACRO_TABLE_LEN); +#endif +} +#endif // #ifndef NO_PREPROCESSOR + +int KeepStringTable = 0; + +void PurgeStringTable(void) +{ + if (!KeepStringTable) + StringTableLen = 0; +} + +void AddString(int label, char* str, int len) +{ + if (len > 127) + error("String literal too long\n"); + + if (MAX_STRING_TABLE_LEN - StringTableLen < 2 + 1 + len) + error("String table exhausted\n"); + + StringTable[StringTableLen++] = label & 0xFF; + StringTable[StringTableLen++] = (label >> 8) & 0xFF; + + StringTable[StringTableLen++] = len; + memcpy(StringTable + StringTableLen, str, len); + StringTableLen += len; +} + +char* FindString(int label) +{ + int i; + + for (i = 0; i < StringTableLen; ) + { + int lab; + + lab = StringTable[i] & 0xFF; + lab += (StringTable[i + 1] & 0xFFu) << 8; + + if (lab == label) + return StringTable + i + 2; + + i += 2; + i += 1 + StringTable[i]; + } + + return NULL; +} + +int FindIdent(char* name) +{ + int i; + for (i = IdentTableLen; i > 0; ) + { + i -= 1 + IdentTable[i - 1]; + if (!strcmp(IdentTable + i, name)) + return i; + } + return -1; +} + +int AddIdent(char* name) +{ + int i, len; + + if ((i = FindIdent(name)) >= 0) + return i; + + i = IdentTableLen; + len = strlen(name); + + if (len >= 127) + error("Identifier too long\n"); + + if (MAX_IDENT_TABLE_LEN - IdentTableLen < len + 2) + error("Identifier table exhausted\n"); + + strcpy(IdentTable + IdentTableLen, name); + IdentTableLen += len + 1; + IdentTable[IdentTableLen++] = len + 1; + + return i; +} + +int AddGotoLabel(char* name, int label) +{ + int i; + for (i = 0; i < gotoLabCnt; i++) + { + if (!strcmp(IdentTable + gotoLabels[i][0], name)) + { + if (gotoLabStat[i] & label) + error("Redefinition of label '%s'\n", name); + gotoLabStat[i] |= 2*!label + label; + return gotoLabels[i][1]; + } + } + if (gotoLabCnt >= MAX_GOTO_LABELS) + error("Goto table exhausted\n"); + gotoLabels[gotoLabCnt][0] = AddIdent(name); + gotoLabels[gotoLabCnt][1] = LabelCnt++; + gotoLabStat[gotoLabCnt] = 2*!label + label; + return gotoLabels[gotoLabCnt++][1]; +} + +void UndoNonLabelIdents(int len) +{ + int i; + IdentTableLen = len; + for (i = 0; i < gotoLabCnt; i++) + if (gotoLabels[i][0] >= len) + { + char* pfrom = IdentTable + gotoLabels[i][0]; + char* pto = IdentTable + IdentTableLen; + int l = strlen(pfrom) + 2; + memmove(pto, pfrom, l); + IdentTableLen += l; + gotoLabels[i][0] = pto - IdentTable; + } +} + +void DumpIdentTable(void) +{ +#ifndef NO_ANNOTATIONS + int i; + puts2(""); + GenStartCommentLine(); printf2("Identifier table:\n"); + for (i = 0; i < IdentTableLen; ) + { + GenStartCommentLine(); printf2("Ident %s\n", IdentTable + i); + i += strlen(IdentTable + i) + 2; + } + GenStartCommentLine(); printf2("Bytes used: %d/%d\n\n", IdentTableLen, MAX_IDENT_TABLE_LEN); +#endif +} + +char* rws[] = +{ + "break", "case", "char", "continue", "default", "do", "else", + "extern", "for", "if", "int", "return", "signed", "sizeof", + "static", "switch", "unsigned", "void", "while", "asm", "auto", + "const", "double", "enum", "float", "goto", "inline", "long", + "register", "restrict", "short", "struct", "typedef", "union", + "volatile", "_Bool", "_Complex", "_Imaginary" +}; + +unsigned char rwtk[] = +{ + tokBreak, tokCase, tokChar, tokCont, tokDefault, tokDo, tokElse, + tokExtern, tokFor, tokIf, tokInt, tokReturn, tokSigned, tokSizeof, + tokStatic, tokSwitch, tokUnsigned, tokVoid, tokWhile, tok_Asm, tokAuto, + tokConst, tokDouble, tokEnum, tokFloat, tokGoto, tokInline, tokLong, + tokRegister, tokRestrict, tokShort, tokStruct, tokTypedef, tokUnion, + tokVolatile, tok_Bool, tok_Complex, tok_Imagin +}; + +int GetTokenByWord(char* word) +{ + unsigned i; + + for (i = 0; i < sizeof rws / sizeof rws[0]; i++) + if (!strcmp(rws[i], word)) + return rwtk[i]; + + return tokIdent; +} + +char* GetTokenName(int token) +{ + unsigned i; + + switch (token) + { + case tokEof: return ""; +/* +-~* /% &|^! << >> && || < <= > >= == != () *[] ++ -- = += -= ~= *= /= %= &= |= ^= <<= >>= {} ,;: -> ... */ + // Single-character operators and punctuators: + case '+': return "+"; case '-': return "-"; + case '~': return "~"; case '*': return "*"; + case '/': return "/"; case '%': return "%"; + case '&': return "&"; case '|': return "|"; + case '^': return "^"; case '!': return "!"; + case '<': return "<"; case '>': return ">"; + case '(': return "("; case ')': return ")"; + case '[': return "["; case ']': return "]"; + case '{': return "{"; case '}': return "}"; + case '=': return "="; case ',': return ","; + case ';': return ";"; case ':': return ":"; + case '.': return "."; case '?': return "?"; + // Multi-character operators and punctuators: + case tokLShift: return "<<"; case tokRShift: return ">>"; + case tokLogAnd: return "&&"; case tokLogOr: return "||"; + case tokEQ: return "=="; case tokNEQ: return "!="; + case tokLEQ: return "<="; case tokGEQ: return ">="; + case tokInc: return "++"; case tokDec: return "--"; + case tokArrow: return "->"; case tokEllipsis: return "..."; + case tokAssignMul: return "*="; case tokAssignDiv: return "/="; + case tokAssignMod: return "%="; case tokAssignAdd: return "+="; + case tokAssignSub: return "-="; case tokAssignLSh: return "<<="; + case tokAssignRSh: return ">>="; case tokAssignAnd: return "&="; + case tokAssignXor: return "^="; case tokAssignOr: return "|="; + + // Some of the above tokens get converted into these in the process: + case tokUnaryAnd: return "&u"; case tokUnaryStar: return "*u"; + case tokUnaryPlus: return "+u"; case tokUnaryMinus: return "-u"; + case tokPostInc: return "++p"; case tokPostDec: return "--p"; + case tokPostAdd: return "+=p"; case tokPostSub: return "-=p"; + case tokULess: return "u"; + case tokULEQ: return "<=u"; case tokUGEQ: return ">=u"; + case tokURShift: return ">>u"; case tokAssignURSh: return ">>=u"; + case tokUDiv: return "/u"; case tokAssignUDiv: return "/=u"; + case tokUMod: return "%u"; case tokAssignUMod: return "%=u"; + case tokComma: return ",b"; + + // Helper (pseudo-)tokens: + case tokNumInt: return ""; case tokNumUint: return ""; + case tokLitStr: return ""; case tokIdent: return ""; + case tokLocalOfs: return ""; case tokShortCirc: return ""; + + case tokSChar: return "signed char"; case tokUChar: return "unsigned char"; + case tokShort: return "short"; case tokUShort: return "unsigned short"; + case tokLong: return "long"; case tokULong: return "unsigned long"; + } + + // Reserved keywords: + for (i = 0; i < sizeof rws / sizeof rws[0]; i++) + if (rwtk[i] == token) + return rws[i]; + + //error("Internal Error: GetTokenName(): Invalid token %d\n", token); + errorInternal(1); + return ""; +} + +int GetTokenValueInt(void) +{ + return TokenValueInt; +} + +char* GetTokenValueString(void) +{ + return TokenValueString; +} + +int GetTokenValueStringLength(void) +{ + return TokenStringLen; +} + +char* GetTokenIdentName(void) +{ + return TokenIdentName; +} + +int GetNextChar(void) +{ + int ch = EOF; + + if (FileCnt && Files[FileCnt - 1]) + { + if ((ch = fgetc(Files[FileCnt - 1])) == EOF) + { + fclose(Files[FileCnt - 1]); + Files[FileCnt - 1] = NULL; + + // store the last line/pos, they may still be needed later + LineNos[FileCnt - 1] = LineNo; + LinePoss[FileCnt - 1] = LinePos; + + // don't drop the file record just yet + } + } + + return ch; +} + +void ShiftChar(void) +{ + if (CharQueueLen) + memmove(CharQueue, CharQueue + 1, --CharQueueLen); + + // make sure there always are at least 3 chars in the queue + while (CharQueueLen < 3) + { + int ch = GetNextChar(); + if (ch == EOF) + ch = '\0'; + CharQueue[CharQueueLen++] = ch; + } +} + +void ShiftCharN(int n) +{ + while (n-- > 0) + { + ShiftChar(); + LinePos++; + } +} + +#ifndef NO_PREPROCESSOR +void IncludeFile(int quot) +{ + int nlen = strlen(TokenValueString); + + if (CharQueueLen != 3) + //error("#include parsing error\n"); + errorInternal(2); + + if (FileCnt >= MAX_INCLUDES) + error("Too many include files\n"); + + // store the including file's position and buffered chars + LineNos[FileCnt - 1] = LineNo; + LinePoss[FileCnt - 1] = LinePos; + memcpy(CharQueues[FileCnt - 1], CharQueue, CharQueueLen); + + // open the included file + + if (nlen > MAX_FILE_NAME_LEN) + //error("File name too long\n"); + errorFileName(); + + // DONE: differentiate between quot == '\"' and quot == '<' + + // first, try opening "file" in the current directory + if (quot == '\"') + { + strcpy(FileNames[FileCnt], TokenValueString); + Files[FileCnt] = fopen(FileNames[FileCnt], "r"); + } + + // next, iterate the search paths trying to open "file" or + if (Files[FileCnt] == NULL) + { + int i; + for (i = 0; i < SearchPathsLen; ) + { + int plen = strlen(SearchPaths + i); + if (plen + 1 + nlen < MAX_FILE_NAME_LEN) + { + strcpy(FileNames[FileCnt], SearchPaths + i); + strcpy(FileNames[FileCnt] + plen + 1, TokenValueString); + // first, try '/' as a separator (Linux/Unix) + FileNames[FileCnt][plen] = '/'; + if ((Files[FileCnt] = fopen(FileNames[FileCnt], "r")) == NULL) + { + // next, try '\\' as a separator (DOS/Windows) + FileNames[FileCnt][plen] = '\\'; + Files[FileCnt] = fopen(FileNames[FileCnt], "r"); + } + if (Files[FileCnt]) + break; + } + i += plen + 1; + } + } + + if (Files[FileCnt] == NULL) + { + //if (quot == '<' && !SearchPathsLen) + // error("Cannot open file \"%s\", include search path unspecified\n", TokenValueString); + + //error("Cannot open file \"%s\"\n", TokenValueString); + errorFile(TokenValueString); + } + + // reset line/pos and empty the char queue + CharQueueLen = 0; + LineNo = LinePos = 1; + FileCnt++; + + // fill the char queue with file data + ShiftChar(); +} +#endif // #ifndef NO_PREPROCESSOR + +int EndOfFiles(void) +{ + // if there are no including files, we're done + if (!--FileCnt) + return 1; + + // restore the including file's position and buffered chars + LineNo = LineNos[FileCnt - 1]; + LinePos = LinePoss[FileCnt - 1]; + CharQueueLen = 3; + memcpy(CharQueue, CharQueues[FileCnt - 1], CharQueueLen); + + return 0; +} + +void SkipSpace(int SkipNewLines) +{ + char* p = CharQueue; + + while (*p != '\0') + { + if (strchr(" \t\f\v", *p)) + { + ShiftCharN(1); + continue; + } + + if (strchr("\r\n", *p)) + { + if (!SkipNewLines) + return; + + if (*p == '\r' && p[1] == '\n') + ShiftChar(); + + ShiftChar(); + LineNo++; + LinePos = 1; + continue; + } + +#ifndef NO_PREPROCESSOR + if (*p == '/') + { + if (p[1] == '/') + { + // // comment + ShiftCharN(2); + while (!strchr("\r\n", *p)) + ShiftCharN(1); + continue; + } + else if (p[1] == '*') + { + // /**/ comment + ShiftCharN(2); + while (*p != '\0' && !(*p == '*' && p[1] == '/')) + { + if (strchr("\r\n", *p)) + { + if (!SkipNewLines) + error("Invalid comment\n"); + + if (*p == '\r' && p[1] == '\n') + ShiftChar(); + + ShiftChar(); + LineNo++; + LinePos = 1; + } + else + { + ShiftCharN(1); + } + } + if (*p == '\0') + error("Invalid comment\n"); + ShiftCharN(2); + continue; + } + } // endof if (*p == '/') +#endif + + break; + } // endof while (*p != '\0') +} + +#ifndef NO_PREPROCESSOR +void SkipLine(void) +{ + char* p = CharQueue; + + while (*p != '\0') + { + if (strchr("\r\n", *p)) + { + if (*p == '\r' && p[1] == '\n') + ShiftChar(); + + ShiftChar(); + LineNo++; + LinePos = 1; + break; + } + else + { + ShiftCharN(1); + } + } +} +#endif + +void GetIdent(void) +{ + char* p = CharQueue; + + if (*p != '_' && !isalpha(*p & 0xFFu)) + error("Identifier expected\n"); + + if (*p == 'L' && + (p[1] == '\'' || p[1] == '\"')) + //error("Wide characters and strings not supported\n"); + errorChrStr(); + + TokenIdentNameLen = 0; + TokenIdentName[TokenIdentNameLen++] = *p; + TokenIdentName[TokenIdentNameLen] = '\0'; + ShiftCharN(1); + + while (*p == '_' || isalnum(*p & 0xFFu)) + { + if (TokenIdentNameLen == MAX_IDENT_LEN) + error("Identifier too long '%s'\n", TokenIdentName); + TokenIdentName[TokenIdentNameLen++] = *p; + TokenIdentName[TokenIdentNameLen] = '\0'; + ShiftCharN(1); + } +} + +void GetString(char terminator, int SkipNewLines) +{ + char* p = CharQueue; + char ch; + + TokenStringLen = 0; + TokenValueString[TokenStringLen] = '\0'; + + for (;;) + { + ShiftCharN(1); + while (!(*p == terminator || strchr("\a\b\f\n\r\t\v", *p))) + { + ch = *p; + if (ch == '\\') + { + ShiftCharN(1); + ch = *p; + if (strchr("\a\b\f\n\r\t\v", ch)) + break; + switch (ch) + { + case 'a': ch = '\a'; ShiftCharN(1); break; + case 'b': ch = '\b'; ShiftCharN(1); break; + case 'f': ch = '\f'; ShiftCharN(1); break; + case 'n': ch = '\n'; ShiftCharN(1); break; + case 'r': ch = '\r'; ShiftCharN(1); break; + case 't': ch = '\t'; ShiftCharN(1); break; + case 'v': ch = '\v'; ShiftCharN(1); break; + // DONE: \nnn, \xnn + case 'x': + { + // hexadecimal character codes \xN+ + int cnt = 0; + int c = 0; + ShiftCharN(1); + while (*p != '\0' && (isdigit(*p & 0xFFu) || strchr("abcdefABCDEF", *p))) + { + c = (c * 16) & 0xFF; + if (*p >= 'a') c += *p - 'a' + 10; + else if (*p >= 'A') c += *p - 'A' + 10; + else c += *p - '0'; + ShiftCharN(1); + cnt++; + } + if (!cnt) + //error("Unsupported or invalid character/string constant\n"); + errorChrStr(); + c -= (c >= 0x80 && CHAR_MIN) * 0x100; + ch = c; + } + break; + default: + if (*p >= '0' && *p <= '7') + { + // octal character codes \N+ + int cnt = 0; + int c = 0; + while (*p >= '0' && *p <= '7') + { + c = (c * 8) & 0xFF; + c += *p - '0'; + ShiftCharN(1); + cnt++; + } + if (!cnt) + //error("Unsupported or invalid character/string constant\n"); + errorChrStr(); + c -= (c >= 0x80 && CHAR_MIN) * 0x100; + ch = c; + } + else + { + ShiftCharN(1); + } + break; + } // endof switch (ch) + } // endof if (ch == '\\') + else + { + ShiftCharN(1); + } + + if (terminator == '\'') + { + if (TokenStringLen != 0) + //error("Character constant too long\n"); + errorChrStr(); + } + else if (TokenStringLen == MAX_STRING_LEN) + error("String literal too long\n"); + + TokenValueString[TokenStringLen++] = ch; + TokenValueString[TokenStringLen] = '\0'; + } // endof while (!(*p == '\0' || *p == terminator || strchr("\a\b\f\n\r\t\v", *p))) + + if (*p != terminator) + //error("Unsupported or invalid character/string constant\n"); + errorChrStr(); + + ShiftCharN(1); + + if (terminator != '\"') + break; // done with character constants + + // Concatenate this string literal with all following ones, if any + SkipSpace(SkipNewLines); + if (*p != '\"') + break; // nothing to concatenate with + // Continue consuming string characters + } // endof for (;;) +} + +#ifndef NO_PREPROCESSOR +void pushPrep(int NoSkip) +{ + if (PrepSp >= PREP_STACK_SIZE) + error("Too many #if(n)def's\n"); + PrepStack[PrepSp][0] = PrepDontSkipTokens; + PrepStack[PrepSp++][1] = NoSkip; + PrepDontSkipTokens &= NoSkip; +} + +int popPrep(void) +{ + if (PrepSp <= 0) + error("#else or #endif without #if(n)def\n"); + PrepDontSkipTokens = PrepStack[--PrepSp][0]; + return PrepStack[PrepSp][1]; +} +#endif + +int GetNumber(void) +{ + char* p = CharQueue; + int ch = *p; + unsigned n = 0; + int type = 0; + int uSuffix = 0; +#ifdef CAN_COMPILE_32BIT + int lSuffix = 0; +#endif + char* eTooBig = "Constant too big\n"; + + if (ch == '0') + { + // this is either an octal or a hex constant + type = 'o'; + ShiftCharN(1); + if ((ch = *p) == 'x' || ch == 'X') + { + // this is a hex constant + int cnt = 0; + ShiftCharN(1); + while ((ch = *p) != '\0' && (isdigit(ch & 0xFFu) || strchr("abcdefABCDEF", ch))) + { + if (ch >= 'a') ch -= 'a' - 10; + else if (ch >= 'A') ch -= 'A' - 10; + else ch -= '0'; + if (PrepDontSkipTokens && (n * 16 / 16 != n || n * 16 + ch < n * 16)) + error(eTooBig); + n = n * 16 + ch; + ShiftCharN(1); + cnt++; + } + if (!cnt) + error("Invalid hexadecimal constant\n"); + type = 'h'; + } + // this is an octal constant + else while ((ch = *p) >= '0' && ch <= '7') + { + ch -= '0'; + if (PrepDontSkipTokens && (n * 8 / 8 != n || n * 8 + ch < n * 8)) + error(eTooBig); + n = n * 8 + ch; + ShiftCharN(1); + } + } + // this is a decimal constant + else + { + type = 'd'; + while ((ch = *p) >= '0' && ch <= '9') + { + ch -= '0'; + if (PrepDontSkipTokens && (n * 10 / 10 != n || n * 10 + ch < n * 10)) + error(eTooBig); + n = n * 10 + ch; + ShiftCharN(1); + } + } + + // possible combinations of suffixes: + // none + // U + // UL + // L + // LU + if ((ch = *p) == 'u' || ch == 'U') + { + uSuffix = 1; + ShiftCharN(1); + } +#ifdef CAN_COMPILE_32BIT + if ((ch = *p) == 'l' || ch == 'L') + { + lSuffix = 1; + ShiftCharN(1); + if (!uSuffix && ((ch = *p) == 'u' || ch == 'U')) + { + uSuffix = 1; + ShiftCharN(1); + } + } +#endif + + if (!PrepDontSkipTokens) + { + // Don't fail on big constants when skipping tokens under #if + TokenValueInt = 0; + return tokNumInt; + } + + // Ensure the constant fits into 16(32) bits + if ((SizeOfWord == 2 && n >> 8 >> 8) || // equiv. to SizeOfWord == 2 && n > 0xFFFF +#ifdef CAN_COMPILE_32BIT + (SizeOfWord == 2 && lSuffix) || // long (which must have at least 32 bits) isn't supported in 16-bit models +#endif + (SizeOfWord == 4 && n >> 8 >> 12 >> 12)) // equiv. to SizeOfWord == 4 && n > 0xFFFFFFFF + error("Constant too big for %d-bit type\n", SizeOfWord * 8); + + TokenValueInt = uint2int(n); + + // Unsuffixed (with 'u') integer constants (octal, decimal, hex) + // fitting into 15(31) out of 16(32) bits are signed ints + if (!uSuffix && + ((SizeOfWord == 2 && !(n >> 8 >> 7)) || // equiv. to SizeOfWord == 2 && n <= 0x7FFF + (SizeOfWord == 4 && !(n >> 8 >> 12 >> 11)))) // equiv. to SizeOfWord == 4 && n <= 0x7FFFFFFF + return tokNumInt; + + // Unlike octal and hex constants, decimal constants are always + // a signed type. Error out when a decimal constant doesn't fit + // into an int since currently there's no next bigger signed type + // (e.g. long) to use instead of int. + if (!uSuffix && type == 'd') + error("Constant too big for %d-bit signed type\n", SizeOfWord * 8); + + return tokNumUint; +} + +int GetTokenInner(void) +{ + char* p = CharQueue; + int ch = *p; + + // these single-character tokens/operators need no further processing + if (strchr(",;:()[]{}~?", ch)) + { + ShiftCharN(1); + return ch; + } + + // parse multi-character tokens/operators + + // DONE: other assignment operators + switch (ch) + { + case '+': + if (p[1] == '+') { ShiftCharN(2); return tokInc; } + if (p[1] == '=') { ShiftCharN(2); return tokAssignAdd; } + ShiftCharN(1); return ch; + case '-': + if (p[1] == '-') { ShiftCharN(2); return tokDec; } + if (p[1] == '=') { ShiftCharN(2); return tokAssignSub; } + if (p[1] == '>') { ShiftCharN(2); return tokArrow; } + ShiftCharN(1); return ch; + case '!': + if (p[1] == '=') { ShiftCharN(2); return tokNEQ; } + ShiftCharN(1); return ch; + case '=': + if (p[1] == '=') { ShiftCharN(2); return tokEQ; } + ShiftCharN(1); return ch; + case '<': + if (p[1] == '=') { ShiftCharN(2); return tokLEQ; } + if (p[1] == '<') { ShiftCharN(2); if (p[0] != '=') return tokLShift; ShiftCharN(1); return tokAssignLSh; } + ShiftCharN(1); return ch; + case '>': + if (p[1] == '=') { ShiftCharN(2); return tokGEQ; } + if (p[1] == '>') { ShiftCharN(2); if (p[0] != '=') return tokRShift; ShiftCharN(1); return tokAssignRSh; } + ShiftCharN(1); return ch; + case '&': + if (p[1] == '&') { ShiftCharN(2); return tokLogAnd; } + if (p[1] == '=') { ShiftCharN(2); return tokAssignAnd; } + ShiftCharN(1); return ch; + case '|': + if (p[1] == '|') { ShiftCharN(2); return tokLogOr; } + if (p[1] == '=') { ShiftCharN(2); return tokAssignOr; } + ShiftCharN(1); return ch; + case '^': + if (p[1] == '=') { ShiftCharN(2); return tokAssignXor; } + ShiftCharN(1); return ch; + case '.': + if (p[1] == '.' && p[2] == '.') { ShiftCharN(3); return tokEllipsis; } + ShiftCharN(1); return ch; + case '*': + if (p[1] == '=') { ShiftCharN(2); return tokAssignMul; } + ShiftCharN(1); return ch; + case '%': + if (p[1] == '=') { ShiftCharN(2); return tokAssignMod; } + ShiftCharN(1); return ch; + case '/': + if (p[1] == '=') { ShiftCharN(2); return tokAssignDiv; } + // if (p[1] == '/' || p[1] == '*') { SkipSpace(1); continue; } // already taken care of + ShiftCharN(1); return ch; + } + + // DONE: hex and octal constants + if (isdigit(ch & 0xFFu)) + return GetNumber(); + + // parse character and string constants + if (ch == '\'' || ch == '\"') + { + GetString(ch, 1); + + if (ch == '\'') + { + if (TokenStringLen != 1) + //error("Character constant too short\n"); + errorChrStr(); + + TokenValueInt = TokenValueString[0] & 0xFF; + TokenValueInt -= (CharIsSigned && TokenValueInt >= 0x80) * 0x100; + return tokNumInt; + } + + return tokLitStr; + } // endof if (ch == '\'' || ch == '\"') + + return tokEof; +} + +// TBD??? implement file I/O for input source code and output code (use fxn ptrs/wrappers to make librarization possible) +// DONE: support string literals +int GetToken(void) +{ + char* p = CharQueue; + int ch; + int tok; + + for (;;) + { +/* +-~* /% &|^! << >> && || < <= > >= == != () *[] ++ -- = += -= ~= *= /= %= &= |= ^= <<= >>= {} ,;: -> ... */ + + // skip white space and comments + SkipSpace(1); + + if ((ch = *p) == '\0') + { + // done with the current file, drop its record, + // pick up the including files (if any) or terminate + if (EndOfFiles()) + break; + continue; + } + + if ((tok = GetTokenInner()) != tokEof) + { + if (PrepDontSkipTokens) + return tok; + continue; + } + + // parse identifiers and reserved keywords + if (ch == '_' || isalpha(ch & 0xFFu)) + { +#ifndef NO_PREPROCESSOR + int midx; +#endif + + GetIdent(); + + if (!PrepDontSkipTokens) + continue; + + tok = GetTokenByWord(TokenIdentName); + +#ifndef NO_PREPROCESSOR + // TBD!!! think of expanding macros in the context of concatenating string literals, + // maybe factor out this piece of code + if ((midx = FindMacro(TokenIdentName)) >= 0) + { + // this is a macro identifier, need to expand it + int len = MacroTable[midx]; + + if (MAX_CHAR_QUEUE_LEN - CharQueueLen < len + 1) + error("Too long expansion of macro '%s'\n", TokenIdentName); + + memmove(CharQueue + len + 1, CharQueue, CharQueueLen); + + memcpy(CharQueue, MacroTable + midx + 1, len); + CharQueue[len] = ' '; // space to avoid concatenation + + CharQueueLen += len + 1; + + continue; + } +#endif + + // treat keywords auto, const, register, restrict and volatile as white space for now + if (tok == tokConst || tok == tokVolatile || + tok == tokAuto || tok == tokRegister || + tok == tokRestrict) + continue; + + return tok; + } // endof if (ch == '_' || isalpha(ch)) + + // parse preprocessor directives + if (ch == '#') + { + int line = 0; + + ShiftCharN(1); + + // Skip space + SkipSpace(0); + + // Allow # not followed by a directive + if (strchr("\r\n", *p)) + continue; + + // Get preprocessor directive + if (isdigit(*p & 0xFFu)) + { + // gcc-style #line directive without "line" + line = 1; + } + else + { + GetIdent(); + if (!strcmp(TokenIdentName, "line")) + { + // C89-style #line directive + SkipSpace(0); + if (!isdigit(*p & 0xFFu)) + errorDirective(); + line = 1; + } + } + + if (line) + { + // Support for external, gcc-like, preprocessor output: + // # linenum filename flags + // + // no flags, flag = 1 -- start of a file + // flag = 2 -- return to a file after #include + // other flags -- uninteresting + + // DONE: should also support the following C89 form: + // # line linenum filename-opt + + if (GetNumber() != tokNumInt) + //error("Invalid line number in preprocessor output\n"); + errorDirective(); + line = GetTokenValueInt(); + + SkipSpace(0); + + if (*p == '\"' || *p == '<') + { + if (*p == '\"') + GetString('\"', 0); + else + GetString('>', 0); + + if (strlen(GetTokenValueString()) > MAX_FILE_NAME_LEN) + //error("File name too long in preprocessor output\n"); + errorFileName(); + strcpy(FileNames[FileCnt - 1], GetTokenValueString()); + } + + // Ignore gcc-style #line's flags, if any + while (!strchr("\r\n", *p)) + ShiftCharN(1); + + LineNo = line - 1; // "line" is the number of the next line + LinePos = 1; + + continue; + } // endof if (line) + +#ifndef NO_PPACK + if (!strcmp(TokenIdentName, "pragma")) + { + int canHaveNumber = 1, hadNumber = 0; + + if (!PrepDontSkipTokens) + { + while (!strchr("\r\n", *p)) + ShiftCharN(1); + continue; + } + + SkipSpace(0); + GetIdent(); + if (strcmp(TokenIdentName, "pack")) + errorDirective(); + // TBD??? fail if inside a structure declaration + SkipSpace(0); + if (*p == '(') + ShiftCharN(1); + SkipSpace(0); + + if (*p == 'p') + { + GetIdent(); + if (!strcmp(TokenIdentName, "push")) + { + SkipSpace(0); + if (*p == ',') + { + ShiftCharN(1); + SkipSpace(0); + if (!isdigit(*p & 0xFFu) || GetNumber() != tokNumInt) + errorDirective(); + hadNumber = 1; + } + if (PragmaPackSp >= PPACK_STACK_SIZE) + error("#pragma pack stack overflow\n"); + PragmaPackValues[PragmaPackSp++] = PragmaPackValue; + } + else if (!strcmp(TokenIdentName, "pop")) + { + if (PragmaPackSp <= 0) + error("#pragma pack stack underflow\n"); + PragmaPackValue = PragmaPackValues[--PragmaPackSp]; + } + else + errorDirective(); + SkipSpace(0); + canHaveNumber = 0; + } + + if (canHaveNumber && isdigit(*p & 0xFFu)) + { + if (GetNumber() != tokNumInt) + errorDirective(); + hadNumber = 1; + SkipSpace(0); + } + + if (hadNumber) + { + PragmaPackValue = GetTokenValueInt(); + if (PragmaPackValue <= 0 || + PragmaPackValue > SizeOfWord || + PragmaPackValue & (PragmaPackValue - 1)) + error("Invalid alignment value\n"); + } + else if (canHaveNumber) + { + PragmaPackValue = SizeOfWord; + } + + if (*p != ')') + errorDirective(); + ShiftCharN(1); + + SkipSpace(0); + if (!strchr("\r\n", *p)) + errorDirective(); + continue; + } +#endif + +#ifndef NO_PREPROCESSOR + if (!strcmp(TokenIdentName, "define")) + { + // Skip space and get macro name + SkipSpace(0); + GetIdent(); + + if (!PrepDontSkipTokens) + { + SkipSpace(0); + while (!strchr("\r\n", *p)) + ShiftCharN(1); + continue; + } + + if (FindMacro(TokenIdentName) >= 0) + error("Redefinition of macro '%s'\n", TokenIdentName); + if (*p == '(') + //error("Unsupported type of macro '%s'\n", TokenIdentName); + errorDirective(); + + AddMacroIdent(TokenIdentName); + + SkipSpace(0); + + // accumulate the macro expansion text + while (!strchr("\r\n", *p)) + { + AddMacroExpansionChar(*p); + ShiftCharN(1); + if (*p != '\0' && (strchr(" \t", *p) || (*p == '/' && (p[1] == '/' || p[1] == '*')))) + { + SkipSpace(0); + AddMacroExpansionChar(' '); + } + } + AddMacroExpansionChar('\0'); + + continue; + } + else if (!strcmp(TokenIdentName, "undef")) + { + // Skip space and get macro name + SkipSpace(0); + GetIdent(); + + if (PrepDontSkipTokens) + UndefineMacro(TokenIdentName); + + SkipSpace(0); + if (!strchr("\r\n", *p)) + //error("Invalid preprocessor directive\n"); + errorDirective(); + continue; + } + else if (!strcmp(TokenIdentName, "include")) + { + int quot; + + // Skip space and get file name + SkipSpace(0); + + quot = *p; + if (*p == '\"') + GetString('\"', 0); + else if (*p == '<') + GetString('>', 0); + else + //error("Invalid file name\n"); + errorFileName(); + + SkipSpace(0); + if (!strchr("\r\n", *p)) + //error("Unsupported or invalid preprocessor directive\n"); + errorDirective(); + + if (PrepDontSkipTokens) + IncludeFile(quot); + + continue; + } + else if (!strcmp(TokenIdentName, "ifdef")) + { + int def; + // Skip space and get macro name + SkipSpace(0); + GetIdent(); + def = FindMacro(TokenIdentName) >= 0; + SkipSpace(0); + if (!strchr("\r\n", *p)) + //error("Invalid preprocessor directive\n"); + errorDirective(); + pushPrep(def); + continue; + } + else if (!strcmp(TokenIdentName, "ifndef")) + { + int def; + // Skip space and get macro name + SkipSpace(0); + GetIdent(); + def = FindMacro(TokenIdentName) >= 0; + SkipSpace(0); + if (!strchr("\r\n", *p)) + //error("Invalid preprocessor directive\n"); + errorDirective(); + pushPrep(!def); + continue; + } + else if (!strcmp(TokenIdentName, "else")) + { + int def; + SkipSpace(0); + if (!strchr("\r\n", *p)) + //error("Invalid preprocessor directive\n"); + errorDirective(); + def = popPrep(); + if (def >= 2) + error("#else or #endif without #if(n)def\n"); + pushPrep(2 + !def); // #else works in opposite way to its preceding #if(n)def + continue; + } + else if (!strcmp(TokenIdentName, "endif")) + { + SkipSpace(0); + if (!strchr("\r\n", *p)) + //error("Invalid preprocessor directive\n"); + errorDirective(); + popPrep(); + continue; + } + + if (!PrepDontSkipTokens) + { + // If skipping code and directives under #ifdef/#ifndef/#else, + // ignore unsupported directives #if, #elif, #error (no error checking) + if (!strcmp(TokenIdentName, "if")) + pushPrep(0); + else if (!strcmp(TokenIdentName, "elif")) + popPrep(), pushPrep(0); + SkipLine(); + continue; + } +#endif // #ifndef NO_PREPROCESSOR + + //error("Unsupported or invalid preprocessor directive\n"); + errorDirective(); + } // endof if (ch == '#') + + error("Invalid or unsupported character with code 0x%02X\n", *p & 0xFFu); + } // endof for (;;) + + return tokEof; +} + +#ifdef MIPS +#ifndef CAN_COMPILE_32BIT +#error MIPS target requires a 32-bit compiler +#endif +#include "cgmips.c" +#else +#include "cgx86.c" +#endif // #ifdef MIPS + +// expr.c code + +void push2(int v, int v2) +{ + if (sp >= STACK_SIZE) + //error("expression stack overflow!\n"); + errorLongExpr(); + stack[sp][0] = v; + stack[sp++][1] = v2; +} + +void push(int v) +{ + push2(v, 0); +} + +int stacktop() +{ + if (sp == 0) + //error("expression stack underflow!\n"); + errorInternal(3); + return stack[sp - 1][0]; +} + +int pop2(int* v2) +{ + int v = stacktop(); + *v2 = stack[sp - 1][1]; + sp--; + return v; +} + +int pop() +{ + int v2; + return pop2(&v2); +} + +void ins2(int pos, int v, int v2) +{ + if (sp >= STACK_SIZE) + //error("expression stack overflow!\n"); + errorLongExpr(); + memmove(&stack[pos + 1], &stack[pos], sizeof(stack[0]) * (sp - pos)); + stack[pos][0] = v; + stack[pos][1] = v2; + sp++; +} + +void ins(int pos, int v) +{ + ins2(pos, v, 0); +} + +void del(int pos, int cnt) +{ + memmove(stack[pos], + stack[pos + cnt], + sizeof(stack[0]) * (sp - (pos + cnt))); + sp -= cnt; +} + +void pushop2(int v, int v2) +{ + if (opsp >= OPERATOR_STACK_SIZE) + //error("operator stack overflow!\n"); + errorLongExpr(); + opstack[opsp][0] = v; + opstack[opsp++][1] = v2; +} + +void pushop(int v) +{ + pushop2(v, 0); +} + +int opstacktop() +{ + if (opsp == 0) + //error("operator stack underflow!\n"); + errorInternal(4); + return opstack[opsp - 1][0]; +} + +int popop2(int* v2) +{ + int v = opstacktop(); + *v2 = opstack[opsp - 1][1]; + opsp--; + return v; +} + +int popop() +{ + int v2; + return popop2(&v2); +} + +int isop(int tok) +{ + switch (tok) + { + case '!': + case '~': + case '&': + case '*': + case '/': case '%': + case '+': case '-': + case '|': case '^': + case '<': case '>': + case '=': + case tokLogOr: case tokLogAnd: + case tokEQ: case tokNEQ: + case tokLEQ: case tokGEQ: + case tokLShift: case tokRShift: + case tokInc: case tokDec: + case tokSizeof: + case tokAssignMul: case tokAssignDiv: case tokAssignMod: + case tokAssignAdd: case tokAssignSub: + case tokAssignLSh: case tokAssignRSh: + case tokAssignAnd: case tokAssignXor: case tokAssignOr: + case tokComma: + case '?': + return 1; + default: + return 0; + } +} + +int isunary(int tok) +{ + return tok == '!' || tok == '~' || tok == tokInc || tok == tokDec || tok == tokSizeof; +} + +int preced(int tok) +{ + switch (tok) + { + case '*': case '/': case '%': return 13; + case '+': case '-': return 12; + case tokLShift: case tokRShift: return 11; + case '<': case '>': case tokLEQ: case tokGEQ: return 10; + case tokEQ: case tokNEQ: return 9; + case '&': return 8; + case '^': return 7; + case '|': return 6; + case tokLogAnd: return 5; + case tokLogOr: return 4; + case '?': case ':': return 3; + case '=': + case tokAssignMul: case tokAssignDiv: case tokAssignMod: + case tokAssignAdd: case tokAssignSub: + case tokAssignLSh: case tokAssignRSh: + case tokAssignAnd: case tokAssignXor: case tokAssignOr: + return 2; + case tokComma: + return 1; + } + return 0; +} + +int precedGEQ(int lfttok, int rhttok) +{ + // DONE: rethink the comma operator as it could be implemented similarly + // DONE: is this correct:??? + int pl = preced(lfttok); + int pr = preced(rhttok); + // ternary/conditional operator ?: is right-associative + if (pl == 3 && pr >= 3) + pl = 0; + // assignment is right-associative + if (pl == 2 && pr >= 2) + pl = 0; + return pl >= pr; +} + +int expr(int tok, int* gotUnary, int commaSeparator); + +char* lab2str(char* p, int n) +{ + do + { + *--p = '0' + n % 10; + n /= 10; + } while (n); + + return p; +} + +int exprUnary(int tok, int* gotUnary, int commaSeparator, int argOfSizeOf) +{ + int decl = 0; + *gotUnary = 0; + + if (isop(tok) && (isunary(tok) || strchr("&*+-", tok))) + { + int lastTok = tok; + tok = exprUnary(GetToken(), gotUnary, commaSeparator, lastTok == tokSizeof); + if (!*gotUnary) + //error("exprUnary(): primary expression expected after token %s\n", GetTokenName(lastTok)); + errorUnexpectedToken(tok); + switch (lastTok) + { + // DONE: remove all collapsing of all unary operators. + // It's wrong because type checking must occur before any optimizations. + // WRONG: DONE: collapse alternating & and * (e.g. "*&*&x" "&*&*x") + // WRONGISH: DONE: replace prefix ++/-- with +=1/-=1 + case '&': + push(tokUnaryAnd); + break; + case '*': + push(tokUnaryStar); + break; + case '+': + push(tokUnaryPlus); + break; + case '-': + push(tokUnaryMinus); + break; + case '!': + // replace "!" with "== 0" + push(tokNumInt); + push(tokEQ); + break; + default: + push(lastTok); + break; + } + } + else + { + int inspos = sp; + + if (tok == tokNumInt || tok == tokNumUint) + { + push2(tok, GetTokenValueInt()); + *gotUnary = 1; + tok = GetToken(); + } + else if (tok == tokLitStr) + { + int lbl = (LabelCnt += 2) - 2; // 1 extra label for the jump over the string + int len, id; + char s[1 + (2 + CHAR_BIT * sizeof lbl) / 3]; + char *p = s + sizeof s; + + // imitate definition: char #[len] = "..."; + + AddString(lbl, GetTokenValueString(), len = 1 + GetTokenValueStringLength()); + + *--p = '\0'; + p = lab2str(p, lbl); + + // DONE: can this break incomplete yet declarations???, e.g.: int x[sizeof("az")][5]; + PushSyntax2(tokIdent, id = AddIdent(p)); + PushSyntax('['); + PushSyntax2(tokNumUint, len); + PushSyntax(']'); + PushSyntax(tokChar); + + push2(tokIdent, id); + *gotUnary = 1; + tok = GetToken(); + } + else if (tok == tokIdent) + { + push2(tok, AddIdent(GetTokenIdentName())); + *gotUnary = 1; + tok = GetToken(); + } + else if (tok == '(') + { + tok = GetToken(); + decl = TokenStartsDeclaration(tok, 1); + + if (decl) + { + int synPtr; + int lbl = LabelCnt++; + char s[1 + (2 + CHAR_BIT * sizeof lbl) / 3 + sizeof "" - 1]; + char *p = s + sizeof s; + + tok = ParseDecl(tok, NULL, !argOfSizeOf, 0); + if (tok != ')') + //error("exprUnary(): ')' expected, unexpected token %s\n", GetTokenName(tok)); + errorUnexpectedToken(tok); + synPtr = FindSymbol(""); + + // Rename "" to "", where # is lbl. + // This makes the nameless declaration uniquely identifiable by name. + + *--p = '\0'; + *--p = ")>"[argOfSizeOf]; // differentiate casts (something#) from not casts + + p = lab2str(p, lbl); + + p -= sizeof "" - 2 - 1; + memcpy(p, "something", sizeof "something" - 1); + + *--p = "(<"[argOfSizeOf]; // differentiate casts (something#) from not casts + + SyntaxStack[synPtr][1] = AddIdent(p); + tok = GetToken(); + if (argOfSizeOf) + { + // expression: sizeof(type) + *gotUnary = 1; + } + else + { + // unary type cast operator: (type) + decl = 0; + tok = exprUnary(tok, gotUnary, commaSeparator, 0); + if (!*gotUnary) + //error("exprUnary(): primary expression expected after '(type)'\n"); + errorUnexpectedToken(tok); + } + push2(tokIdent, SyntaxStack[synPtr][1]); + } + else + { + tok = expr(tok, gotUnary, 0); + if (tok != ')') + //error("exprUnary(): ')' expected, unexpected token %s\n", GetTokenName(tok)); + errorUnexpectedToken(tok); + if (!*gotUnary) + //error("exprUnary(): primary expression expected in '()'\n"); + errorUnexpectedToken(tok); + tok = GetToken(); + } + } + + while (*gotUnary && !decl) + { + // DONE: f(args1)(args2) and the like: need stack order: args2, args1, f, (), () + // DONE: reverse the order of evaluation of groups of args in + // f(args1)(args2)(args3) + // DONE: reverse the order of function argument evaluation for variadic functions + // we want 1st arg to be the closest to the stack top. + // DONE: (args)[index] can be repeated interchangeably indefinitely + // DONE: (expr)() & (expr)[] + // DONE: [index] can be followed by ++/--, which can be followed by [index] and so on... + // DONE: postfix ++/-- & differentiate from prefix ++/-- + + if (tok == '(') + { + int acnt = 0; + ins(inspos, '('); + for (;;) + { + int pos2 = sp; + + tok = GetToken(); + tok = expr(tok, gotUnary, 1); + + // Reverse the order of argument evaluation, which is important for + // variadic functions like printf(): + // we want 1st arg to be the closest to the stack top. + // This also reverses the order of evaluation of all groups of + // arguments. + while (pos2 < sp) + { + // TBD??? not quite efficient + int v, v2; + v = pop2(&v2); + ins2(inspos + 1, v, v2); + pos2++; + } + + if (tok == ',') + { + if (!*gotUnary) + //error("exprUnary(): primary expression (fxn argument) expected before ','\n"); + errorUnexpectedToken(tok); + acnt++; + ins(inspos + 1, ','); // helper argument separator (hint for expression evaluator) + continue; // off to next arg + } + if (tok == ')') + { + if (acnt && !*gotUnary) + //error("exprUnary(): primary expression (fxn argument) expected between ',' and ')'\n"); + errorUnexpectedToken(tok); + *gotUnary = 1; // don't fail for 0 args in () + break; // end of args + } + // DONE: think of inserting special arg pseudo tokens for verification purposes + //error("exprUnary(): ',' or ')' expected, unexpected token %s\n", GetTokenName(tok)); + errorUnexpectedToken(tok); + } // endof for(;;) for fxn args + push(')'); + } + else if (tok == '[') + { + tok = GetToken(); + tok = expr(tok, gotUnary, 0); + if (!*gotUnary) + //error("exprUnary(): primary expression expected in '[]'\n"); + errorUnexpectedToken(tok); + if (tok != ']') + //error("exprUnary(): ']' expected, unexpected token %s\n", GetTokenName(tok)); + errorUnexpectedToken(tok); + // TBD??? add implicit casts to size_t of array indicies. + // E1[E2] -> *(E1 + E2) + // push('['); + push('+'); + push(tokUnaryStar); + } + // WRONG: DONE: replace postfix ++/-- with (+=1)-1/(-=1)+1 + else if (tok == tokInc) + { + push(tokPostInc); + } + else if (tok == tokDec) + { + push(tokPostDec); + } + else if (tok == '.' || tok == tokArrow) + { + // transform a.b into (&a)->b + if (tok == '.') + push(tokUnaryAnd); + tok = GetToken(); + if (tok != tokIdent) + errorUnexpectedToken(tok); + push2(tok, AddIdent(GetTokenIdentName())); + // "->" in "a->b" will function as "+" in "*(type_of_b*)((char*)a + offset_of_b_in_a)" + push(tokArrow); + push(tokUnaryStar); + } + else + { + break; + } + tok = GetToken(); + } // endof while (*gotUnary) + } + + if (tok == ',' && !commaSeparator) + tok = tokComma; + + return tok; +} + +int expr(int tok, int* gotUnary, int commaSeparator) +{ + *gotUnary = 0; + + pushop(tokEof); + + tok = exprUnary(tok, gotUnary, commaSeparator, 0); + + while (tok != tokEof && strchr(",;:)]}", tok) == NULL && *gotUnary) + { + if (isop(tok) && !isunary(tok)) + { + //int lastTok = tok; + + while (precedGEQ(opstacktop(), tok)) + { + int v, v2; + int c = 0; + // move ?expr: as a whole to the expression stack as "expr?" + do + { + v = popop2(&v2); + if (v != ':') + push2(v, v2); + c += (v == ':') - (v == '?'); + } while (c); + } + + // here: preced(postacktop()) < preced(tok) + pushop(tok); + + // treat the ternary/conditional operator ?expr: as a pseudo binary operator + if (tok == '?') + { + int ssp = sp; + + tok = expr(GetToken(), gotUnary, 0); + if (!*gotUnary || tok != ':') + errorUnexpectedToken(tok); + + // move ?expr: as a whole to the operator stack + // this is beautiful and ugly at the same time + while (sp > ssp) + { + int v, v2; + v = pop2(&v2); + pushop2(v, v2); + } + + pushop(tok); + } + + tok = exprUnary(GetToken(), gotUnary, commaSeparator, 0); + // DONE: figure out a check to see if exprUnary() fails to add a rhs operand + if (!*gotUnary) + //error("expr(): primary expression expected after token %s\n", GetTokenName(lastTok)); + errorUnexpectedToken(tok); + + continue; + } + + //error("expr(): Unexpected token %s\n", GetTokenName(tok)); + errorUnexpectedToken(tok); + } + + while (opstacktop() != tokEof) + { + int v, v2; + v = popop2(&v2); + if (v != ':') + push2(v, v2); + } + + popop(); + + return tok; +} + +void decayArray(int* ExprTypeSynPtr, int arithmetic) +{ + // Dacay arrays to pointers to their first elements in + // binary + and - operators + if (*ExprTypeSynPtr >= 0 && SyntaxStack[*ExprTypeSynPtr][0] == '[') + { + while (SyntaxStack[*ExprTypeSynPtr][0] != ']') + ++*ExprTypeSynPtr; + ++*ExprTypeSynPtr; + *ExprTypeSynPtr = -*ExprTypeSynPtr; + } + // Also, to simplify code, return all other pointers as + // negative expression stack syntax indices/pointers + else if (*ExprTypeSynPtr >= 0 && SyntaxStack[*ExprTypeSynPtr][0] == '*') + { + ++*ExprTypeSynPtr; + *ExprTypeSynPtr = -*ExprTypeSynPtr; + } + + // DONE: disallow arithmetic on pointers to void + // DONE: disallow function pointers + if (arithmetic) + { + if (*ExprTypeSynPtr < 0) + { + if (SyntaxStack[-*ExprTypeSynPtr][0] == tokVoid) + //error("decayArray(): cannot do pointer arithmetic on a pointer to 'void'\n"); + errorUnexpectedVoid(); + if (SyntaxStack[-*ExprTypeSynPtr][0] == '(' || + !GetDeclSize(-*ExprTypeSynPtr, 0)) + //error("decayArray(): cannot do pointer arithmetic on a pointer to a function\n"); + errorOpType(); + } + else + { + if (SyntaxStack[*ExprTypeSynPtr][0] == '(') + //error("decayArray(): cannot do arithmetic on a function\n"); + errorOpType(); + } + } +} + +void nonVoidTypeCheck(int ExprTypeSynPtr) +{ + if (ExprTypeSynPtr >= 0 && SyntaxStack[ExprTypeSynPtr][0] == tokVoid) + //error("nonVoidTypeCheck(): unexpected operand type 'void' for operator '%s'\n", GetTokenName(tok)); + errorUnexpectedVoid(); +} + +void scalarTypeCheck(int ExprTypeSynPtr) +{ + nonVoidTypeCheck(ExprTypeSynPtr); + + if (ExprTypeSynPtr >= 0 && SyntaxStack[ExprTypeSynPtr][0] == tokStructPtr) + errorOpType(); +} + +void numericTypeCheck(int ExprTypeSynPtr) +{ + if (ExprTypeSynPtr >= 0 && + (SyntaxStack[ExprTypeSynPtr][0] == tokChar || + SyntaxStack[ExprTypeSynPtr][0] == tokSChar || + SyntaxStack[ExprTypeSynPtr][0] == tokUChar || +#ifdef CAN_COMPILE_32BIT + SyntaxStack[ExprTypeSynPtr][0] == tokShort || + SyntaxStack[ExprTypeSynPtr][0] == tokUShort || +#endif + SyntaxStack[ExprTypeSynPtr][0] == tokInt || + SyntaxStack[ExprTypeSynPtr][0] == tokUnsigned)) + return; + //error("numericTypeCheck(): unexpected operand type for operator '%s', numeric type expected\n", GetTokenName(tok)); + errorOpType(); +} + +void compatCheck(int* ExprTypeSynPtr, int TheOtherExprTypeSynPtr, int ConstExpr[2], int lidx, int ridx) +{ + int exprTypeSynPtr = *ExprTypeSynPtr; + int c = 0; + int lptr, rptr, lnum, rnum; + + // convert functions to pointers to functions + if (exprTypeSynPtr >= 0 && SyntaxStack[exprTypeSynPtr][0] == '(') + *ExprTypeSynPtr = exprTypeSynPtr = -exprTypeSynPtr; + if (TheOtherExprTypeSynPtr >= 0 && SyntaxStack[TheOtherExprTypeSynPtr][0] == '(') + TheOtherExprTypeSynPtr = -TheOtherExprTypeSynPtr; + + lptr = exprTypeSynPtr < 0; + rptr = TheOtherExprTypeSynPtr < 0; + lnum = !lptr && (SyntaxStack[exprTypeSynPtr][0] == tokInt || + SyntaxStack[exprTypeSynPtr][0] == tokUnsigned); + rnum = !rptr && (SyntaxStack[TheOtherExprTypeSynPtr][0] == tokInt || + SyntaxStack[TheOtherExprTypeSynPtr][0] == tokUnsigned); + + // both operands have arithmetic type + // (arithmetic operands have been already promoted): + if (lnum && rnum) + return; + + // both operands have void type: + if (!lptr && SyntaxStack[exprTypeSynPtr][0] == tokVoid && + !rptr && SyntaxStack[TheOtherExprTypeSynPtr][0] == tokVoid) + return; + + // TBD??? check for exact 0? + // one operand is a pointer and the other is NULL constant + // ((void*)0 is also a valid null pointer constant), + // the type of the expression is that of the pointer: + if (lptr && + ((rnum && ConstExpr[1]) || + (rptr && SyntaxStack[-TheOtherExprTypeSynPtr][0] == tokVoid && + stack[ridx][0] == tokUnaryPlus && // "(type*)constant" appears as "constant +(unary)" + (stack[ridx - 1][0] == tokNumInt || stack[ridx - 1][0] == tokNumUint)))) + return; + if (rptr && + ((lnum && ConstExpr[0]) || + (lptr && SyntaxStack[-exprTypeSynPtr][0] == tokVoid && + stack[lidx][0] == tokUnaryPlus && // "(type*)constant" appears as "constant +(unary)" + (stack[lidx - 1][0] == tokNumInt || stack[lidx - 1][0] == tokNumUint)))) + { + *ExprTypeSynPtr = TheOtherExprTypeSynPtr; + return; + } + + // not expecting non-pointers beyond this point + if (!(lptr && rptr)) + errorOpType(); + + // one operand is a pointer and the other is a pointer to void + // (except (void*)0, which is different from other pointers to void), + // the type of the expression is pointer to void: + if (SyntaxStack[-exprTypeSynPtr][0] == tokVoid) + return; + if (SyntaxStack[-TheOtherExprTypeSynPtr][0] == tokVoid) + { + *ExprTypeSynPtr = TheOtherExprTypeSynPtr; + return; + } + + // both operands are pointers to compatible types: + + if (exprTypeSynPtr == TheOtherExprTypeSynPtr) + return; + + exprTypeSynPtr = -exprTypeSynPtr; + TheOtherExprTypeSynPtr = -TheOtherExprTypeSynPtr; + + for (;;) + { + int tok = SyntaxStack[exprTypeSynPtr][0]; + if (tok != SyntaxStack[TheOtherExprTypeSynPtr][0]) + errorOpType(); + + if (tok != tokIdent && + SyntaxStack[exprTypeSynPtr][1] != SyntaxStack[TheOtherExprTypeSynPtr][1]) + errorOpType(); + + c += (tok == '(') - (tok == ')') + (tok == '[') - (tok == ']'); + + if (!c) + { + switch (tok) + { + case tokVoid: + case tokChar: case tokSChar: case tokUChar: +#ifdef CAN_COMPILE_32BIT + case tokShort: case tokUShort: +#endif + case tokInt: case tokUnsigned: + case tokStructPtr: + return; + } + } + + exprTypeSynPtr++; + TheOtherExprTypeSynPtr++; + } +} + +void shiftCountCheck(int *psr, int idx, int ExprTypeSynPtr) +{ + int sr = *psr; + // can't shift by a negative count and by a count exceeding + // the number of bits in int + if ((SyntaxStack[ExprTypeSynPtr][0] != tokUnsigned && sr < 0) || + (sr + 0u) >= CHAR_BIT * sizeof(int) || + (sr + 0u) >= 8u * SizeOfWord) + { + //error("exprval(): Invalid shift count\n"); + warning("Shift count out of range\n"); + // truncate the count, so the assembler doesn't get an invalid count + sr &= SizeOfWord * 8 - 1; + *psr = sr; + stack[idx][1] = sr; + } +} + +int divCheckAndCalc(int tok, int* psl, int sr, int Unsigned, int ConstExpr[2]) +{ + int div0 = 0; + int sl = *psl; + + if (!ConstExpr[1]) + return !div0; + + if (Unsigned) + { + sl = uint2int(truncUint(sl)); + sr = uint2int(truncUint(sr)); + } + else + { + sl = truncInt(sl); + sr = truncInt(sr); + } + + if (sr == 0) + { + div0 = 1; + } + else if (!ConstExpr[0]) + { + return !div0; + } + else if (!Unsigned && ((sl == INT_MIN && sr == -1) || sl / sr != truncInt(sl / sr))) + { + div0 = 1; + } + else + { + if (Unsigned) + { + if (tok == '/') + sl = uint2int((sl + 0u) / sr); + else + sl = uint2int((sl + 0u) % sr); + } + else + { + // TBD!!! C89 gives freedom in how exactly division of negative integers + // can be implemented w.r.t. rounding and w.r.t. the sign of the remainder. + // A stricter, C99-conforming implementation, non-dependent on the + // compiler used to compile Smaller C is needed. + if (tok == '/') + sl /= sr; + else + sl %= sr; + } + *psl = sl; + } + + if (div0) + warning("Division by 0 or division overflow\n"); + + return !div0; +} + +void promoteType(int* ExprTypeSynPtr, int* TheOtherExprTypeSynPtr) +{ + // chars must be promoted to ints in expressions as the very first thing + if (*ExprTypeSynPtr >= 0 && + (SyntaxStack[*ExprTypeSynPtr][0] == tokChar || +#ifdef CAN_COMPILE_32BIT + SyntaxStack[*ExprTypeSynPtr][0] == tokShort || + SyntaxStack[*ExprTypeSynPtr][0] == tokUShort || +#endif + SyntaxStack[*ExprTypeSynPtr][0] == tokSChar || + SyntaxStack[*ExprTypeSynPtr][0] == tokUChar)) + *ExprTypeSynPtr = SymIntSynPtr; + + // ints must be converted to unsigned ints if they are used in binary + // operators whose other operand is unsigned int (except <<,>>,<<=,>>=) + if (*ExprTypeSynPtr >= 0 && SyntaxStack[*ExprTypeSynPtr][0] == tokInt && + *TheOtherExprTypeSynPtr >= 0 && SyntaxStack[*TheOtherExprTypeSynPtr][0] == tokUnsigned) + *ExprTypeSynPtr = SymUintSynPtr; +} + +int GetFxnInfo(int ExprTypeSynPtr, int* MinParams, int* MaxParams, int* ReturnExprTypeSynPtr) +{ + int ptr = 0; + + *MaxParams = *MinParams = 0; + + if (ExprTypeSynPtr < 0) + { + ptr = 1; + ExprTypeSynPtr = -ExprTypeSynPtr; + } + + while (SyntaxStack[ExprTypeSynPtr][0] == tokIdent || SyntaxStack[ExprTypeSynPtr][0] == tokLocalOfs) + ExprTypeSynPtr++; + + if (!(SyntaxStack[ExprTypeSynPtr][0] == '(' || + (!ptr && SyntaxStack[ExprTypeSynPtr][0] == '*' && SyntaxStack[ExprTypeSynPtr + 1][0] == '('))) + return 0; + + // DONE: return syntax pointer to the function's return type + + // Count params + + while (SyntaxStack[ExprTypeSynPtr][0] != '(') + ExprTypeSynPtr++; + ExprTypeSynPtr++; + + if (SyntaxStack[ExprTypeSynPtr][0] == ')') + { + // "fxn()": unspecified parameters, so, there can be any number of them + *MaxParams = 32767; // INT_MAX; + *ReturnExprTypeSynPtr = ExprTypeSynPtr + 1; + return 1; + } + + if (SyntaxStack[ExprTypeSynPtr + 1][0] == tokVoid) + { + // "fxn(void)": 0 parameters + *ReturnExprTypeSynPtr = ExprTypeSynPtr + 3; + return 1; + } + + for (;;) + { + int tok = SyntaxStack[ExprTypeSynPtr][0]; + + if (tok == tokIdent) + { + if (SyntaxStack[ExprTypeSynPtr + 1][0] != tokEllipsis) + { + ++*MinParams; + ++*MaxParams; + } + else + { + *MaxParams = 32767; // INT_MAX; + } + } + else if (tok == '(') + { + // skip parameters in parameters + int c = 1; + while (c && ExprTypeSynPtr < SyntaxStackCnt) + { + tok = SyntaxStack[++ExprTypeSynPtr][0]; + c += (tok == '(') - (tok == ')'); + } + } + else if (tok == ')') + { + ExprTypeSynPtr++; + break; + } + + ExprTypeSynPtr++; + } + + // get the function's return type + *ReturnExprTypeSynPtr = ExprTypeSynPtr; + + return 1; +} + +void simplifyConstExpr(int val, int isConst, int* ExprTypeSynPtr, int top, int bottom) +{ + if (!isConst || stack[top][0] == tokNumInt || stack[top][0] == tokNumUint) + return; + + if (SyntaxStack[*ExprTypeSynPtr][0] == tokUnsigned) + stack[top][0] = tokNumUint; + else + stack[top][0] = tokNumInt; + stack[top][1] = val; + + del(bottom, top - bottom); +} + +// DONE: sizeof(type) +// DONE: "sizeof expr" +// DONE: constant expressions +// DONE: collapse constant subexpressions into constants +int exprval(int* idx, int* ExprTypeSynPtr, int* ConstExpr) +{ + int tok; + int s; + int RightExprTypeSynPtr; + int oldIdxRight; + int oldSpRight; + int constExpr[3]; + + if (*idx < 0) + //error("exprval(): idx < 0\n"); + errorInternal(5); + + tok = stack[*idx][0]; + s = stack[*idx][1]; + + --*idx; + + oldIdxRight = *idx; + oldSpRight = sp; + + switch (tok) + { + // Constants + case tokNumInt: + // return the constant's type: int + *ExprTypeSynPtr = SymIntSynPtr; + *ConstExpr = 1; + break; + case tokNumUint: + // return the constant's type: unsigned int + *ExprTypeSynPtr = SymUintSynPtr; + *ConstExpr = 1; + break; + + // Identifiers + case tokIdent: + { + // DONE: support __func__ + char* ident = IdentTable + s; + int synPtr, type; +#ifndef NO_FUNC_ + if (CurFxnName && !strcmp(ident, "__func__")) + { + if (CurFxnNameLabel >= 0) + CurFxnNameLabel = -CurFxnNameLabel; + stack[*idx + 1][1] = SyntaxStack[SymFuncPtr][1]; + synPtr = SymFuncPtr; + } + else +#endif + { + synPtr = FindSymbol(ident); + } + + if (synPtr < 0) + { + if ((*idx + 2 >= sp) || stack[*idx + 2][0] != ')') + error("Undeclared identifier '%s'\n", ident); + else + { + warning("Call to undeclared function '%s()'\n", ident); + // Implicitly declare "extern int ident();" + PushSyntax2(tokIdent, s); + PushSyntax('('); + PushSyntax(')'); + PushSyntax(tokInt); + synPtr = FindSymbol(ident); + } + } + +#ifndef NO_TYPEDEF_ENUM + if (synPtr + 1 < SyntaxStackCnt && + SyntaxStack[synPtr + 1][0] == tokNumInt) + { + // this is an enum constant + stack[*idx + 1][0] = tokNumInt; + s = stack[*idx + 1][1] = SyntaxStack[synPtr + 1][1]; + *ExprTypeSynPtr = SymIntSynPtr; + *ConstExpr = 1; + break; + } +#endif + + // DONE: this declaration is actually a type cast + if (!strncmp(IdentTable + SyntaxStack[synPtr][1], "(something", sizeof "(something)" - 1 - 1)) + { + int castSize; + + if (SyntaxStack[++synPtr][0] == tokLocalOfs) // TBD!!! is this really needed??? + synPtr++; + + s = exprval(idx, ExprTypeSynPtr, ConstExpr); + + // can't cast void or structure/union to anything (except void) + if (*ExprTypeSynPtr >= 0 && + (SyntaxStack[*ExprTypeSynPtr][0] == tokVoid || + SyntaxStack[*ExprTypeSynPtr][0] == tokStructPtr) && + SyntaxStack[synPtr][0] != tokVoid) + errorOpType(); + + // can't cast to function, array or structure/union + if (SyntaxStack[synPtr][0] == '(' || + SyntaxStack[synPtr][0] == '[' || + SyntaxStack[synPtr][0] == tokStructPtr) + errorOpType(); + + // will try to propagate constants through casts + if (!*ConstExpr && + (stack[oldIdxRight - (oldSpRight - sp)][0] == tokNumInt || + stack[oldIdxRight - (oldSpRight - sp)][0] == tokNumUint)) + { + s = stack[oldIdxRight - (oldSpRight - sp)][1]; + *ConstExpr = 1; + } + + castSize = GetDeclSize(synPtr, 1); + + // insertion of tokUChar, tokSChar and tokUnaryPlus transforms + // lvalues (values formed by dereferences) into rvalues + // (by hiding the dereferences), just as casts should do + switch (castSize) + { + case 1: + // cast to unsigned char + stack[oldIdxRight + 1 - (oldSpRight - sp)][0] = tokUChar; + s &= 0xFFu; + break; + case -1: + // cast to signed char + stack[oldIdxRight + 1 - (oldSpRight - sp)][0] = tokSChar; + if ((s &= 0xFFu) >= 0x80) + s -= 0x100; + break; + default: +#ifdef CAN_COMPILE_32BIT + if (castSize && castSize != SizeOfWord && -castSize != SizeOfWord) + { + if (castSize == 2) + { + // cast to unsigned short + stack[oldIdxRight + 1 - (oldSpRight - sp)][0] = tokUShort; + s &= 0xFFFFu; + } + else + { + // cast to signed short + stack[oldIdxRight + 1 - (oldSpRight - sp)][0] = tokShort; + if ((s &= 0xFFFFu) >= 0x8000) + s -= 0x10000; + } + } + else +#endif + { + // cast to int/unsigned/pointer + if (stack[oldIdxRight - (oldSpRight - sp)][0] == tokUnaryStar) + // hide the dereference + stack[oldIdxRight + 1 - (oldSpRight - sp)][0] = tokUnaryPlus; + else + // nothing to hide, remove the cast + del(oldIdxRight + 1 - (oldSpRight - sp), 1); + } + break; + } + + switch (SyntaxStack[synPtr][0]) + { + case tokChar: + case tokSChar: + case tokUChar: +#ifdef CAN_COMPILE_32BIT + case tokShort: + case tokUShort: +#endif + case tokInt: + case tokUnsigned: + break; + default: + *ConstExpr = 0; + break; + } + + *ExprTypeSynPtr = synPtr; + simplifyConstExpr(s, *ConstExpr, ExprTypeSynPtr, oldIdxRight + 1 - (oldSpRight - sp), *idx + 1); + break; + } + + type = SymType(synPtr); + + if (type == SymLocalVar || type == SymLocalArr) + { + // replace local variables/arrays with their local addresses + // (global variables/arrays' addresses are their names) + stack[*idx + 1][0] = tokLocalOfs; + stack[*idx + 1][1] = SyntaxStack[synPtr + 1][1]; + } + if (type == SymLocalVar || type == SymGlobalVar) + { + // add implicit dereferences for local/global variables + ins2(*idx + 2, tokUnaryStar, GetDeclSize(synPtr, 1)); + } + + // return the identifier's type + while (SyntaxStack[synPtr][0] == tokIdent || SyntaxStack[synPtr][0] == tokLocalOfs) + synPtr++; + *ExprTypeSynPtr = synPtr; + } + *ConstExpr = 0; + break; + + // sizeof operator + case tokSizeof: + s = exprval(idx, ExprTypeSynPtr, ConstExpr); + + if (*ExprTypeSynPtr >= 0) + s = GetDeclSize(*ExprTypeSynPtr, 0); + else + s = SizeOfWord; + if (s == 0) + error("sizeof of incomplete type\n"); + + // replace sizeof with its numeric value + stack[oldIdxRight + 1 - (oldSpRight - sp)][0] = tokNumUint; + stack[oldIdxRight + 1 - (oldSpRight - sp)][1] = s; + + // remove the sizeof's subexpression + del(*idx + 1, oldIdxRight - (oldSpRight - sp) - *idx); + + *ExprTypeSynPtr = SymUintSynPtr; + *ConstExpr = 1; + break; + + // Address unary operator + case tokUnaryAnd: + exprval(idx, ExprTypeSynPtr, ConstExpr); + + if (*ExprTypeSynPtr >= 0 && SyntaxStack[*ExprTypeSynPtr][0] == '[') + { + // convert an array into a pointer to the array, + // remove the reference + *ExprTypeSynPtr = -*ExprTypeSynPtr; + del(oldIdxRight + 1 - (oldSpRight - sp), 1); + } + else if (*ExprTypeSynPtr >= 0 && SyntaxStack[*ExprTypeSynPtr][0] == '(') + { + // convert a function into a pointer to the function, + // remove the reference + *ExprTypeSynPtr = -*ExprTypeSynPtr; + del(oldIdxRight + 1 - (oldSpRight - sp), 1); + } + else if (*ExprTypeSynPtr >= 0 && + oldIdxRight - (oldSpRight - sp) >= 0 && + stack[oldIdxRight - (oldSpRight - sp)][0] == tokUnaryStar) + { + // it's an lvalue (with implicit or explicit dereference), + // convert it into its address, + // collapse/remove the reference and the dereference + *ExprTypeSynPtr = -*ExprTypeSynPtr; + del(oldIdxRight - (oldSpRight - sp), 2); + } + else + //error("exprval(): lvalue expected after '&'\n"); + errorNotLvalue(); + + *ConstExpr = 0; + break; + + // Indirection unary operator + case tokUnaryStar: + exprval(idx, ExprTypeSynPtr, ConstExpr); + + if (*ExprTypeSynPtr < 0 || SyntaxStack[*ExprTypeSynPtr][0] == '*') + { + // type is a pointer to something, + // transform it into that something + if (*ExprTypeSynPtr < 0) + *ExprTypeSynPtr = -*ExprTypeSynPtr; + else + ++*ExprTypeSynPtr; + nonVoidTypeCheck(*ExprTypeSynPtr); + if (SyntaxStack[*ExprTypeSynPtr][0] == tokStructPtr && !GetDeclSize(*ExprTypeSynPtr, 0)) + // incomplete structure/union type + errorOpType(); + // remove the dereference if that something is an array or a function + if (SyntaxStack[*ExprTypeSynPtr][0] == '[' || + SyntaxStack[*ExprTypeSynPtr][0] == '(') + del(oldIdxRight + 1 - (oldSpRight - sp), 1); + // else add dereference size in bytes + else + stack[oldIdxRight + 1 - (oldSpRight - sp)][1] = GetDeclSize(*ExprTypeSynPtr, 1); + } + else if (SyntaxStack[*ExprTypeSynPtr][0] == '[') + { + // type is an array, + // transform it into the array's first element + // (a subarray, if type is a multidimensional array) + while (SyntaxStack[*ExprTypeSynPtr][0] != ']') + ++*ExprTypeSynPtr; + ++*ExprTypeSynPtr; + // remove the dereference if that element is an array + if (SyntaxStack[*ExprTypeSynPtr][0] == '[') + del(oldIdxRight + 1 - (oldSpRight - sp), 1); + // else add dereference size in bytes + else + stack[oldIdxRight + 1 - (oldSpRight - sp)][1] = GetDeclSize(*ExprTypeSynPtr, 1); + } + else + //error("exprval(): pointer/array expected after '*' / before '[]'\n"); + errorOpType(); + + *ConstExpr = 0; + break; + + // Additive binary operators + case '+': + case '-': + // WRONGISH: DONE: replace prefix ++/-- with +=1/-=1 + // WRONG: DONE: replace postfix ++/-- with (+=1)-1/(-=1)+1 + { + int ptrmask; + int oldIdxLeft, oldSpLeft; + int sl, sr; + int incSize; + sr = exprval(idx, &RightExprTypeSynPtr, &constExpr[1]); + oldIdxLeft = *idx; + oldSpLeft = sp; + sl = exprval(idx, ExprTypeSynPtr, &constExpr[0]); + + if (tok == '+') + s = uint2int(sl + 0u + sr); + else + s = uint2int(sl + 0u - sr); + + scalarTypeCheck(RightExprTypeSynPtr); + scalarTypeCheck(*ExprTypeSynPtr); + + // Decay arrays to pointers to their first elements + decayArray(&RightExprTypeSynPtr, 1); + decayArray(ExprTypeSynPtr, 1); + + ptrmask = (RightExprTypeSynPtr < 0) + (*ExprTypeSynPtr < 0) * 2; + + // DONE: index/subscript scaling + if (ptrmask == 1 && tok == '+') // pointer in right-hand expression + { + incSize = GetDeclSize(-RightExprTypeSynPtr, 0); + + if (constExpr[0]) // integer constant in left-hand expression + { + s = uint2int((sl + 0u) * incSize); + stack[oldIdxLeft - (oldSpLeft - sp)][1] = s; + // optimize a little if possible + { + int i = oldIdxRight - (oldSpRight - sp); + // Skip any type cast markers + while (stack[i][0] == tokUnaryPlus || stack[i][0] == '+') + i--; + // See if the pointer is an integer constant or a local variable offset + // and if it is, adjust it here instead of generating code for + // addition/subtraction + if (stack[i][0] == tokNumInt || stack[i][0] == tokNumUint || stack[i][0] == tokLocalOfs) + { + s = uint2int(stack[i][1] + 0u + s); + stack[i][1] = s; // TBD!!! need extra truncation? + del(oldIdxLeft - (oldSpLeft - sp), 1); + del(oldIdxRight - (oldSpRight - sp) + 1, 1); + } + } + } + else if (incSize != 1) + { + ins2(oldIdxLeft + 1 - (oldSpLeft - sp), tokNumInt, incSize); + ins(oldIdxLeft + 1 - (oldSpLeft - sp), '*'); + } + + *ExprTypeSynPtr = RightExprTypeSynPtr; + } + else if (ptrmask == 2) // pointer in left-hand expression + { + incSize = GetDeclSize(-*ExprTypeSynPtr, 0); + if (constExpr[1]) // integer constant in right-hand expression + { + s = uint2int((sr + 0u) * incSize); + stack[oldIdxRight - (oldSpRight - sp)][1] = s; + // optimize a little if possible + { + int i = oldIdxLeft - (oldSpLeft - sp); + // Skip any type cast markers + while (stack[i][0] == tokUnaryPlus || stack[i][0] == '+') + i--; + // See if the pointer is an integer constant or a local variable offset + // and if it is, adjust it here instead of generating code for + // addition/subtraction + if (stack[i][0] == tokNumInt || stack[i][0] == tokNumUint || stack[i][0] == tokLocalOfs) + { + if (tok == '-') + s = uint2int(-(s + 0u)); + s = uint2int(stack[i][1] + 0u + s); + stack[i][1] = s; // TBD!!! need extra truncation? + del(oldIdxRight - (oldSpRight - sp), 2); + } + } + } + else if (incSize != 1) + { + ins2(oldIdxRight + 1 - (oldSpRight - sp), tokNumInt, incSize); + ins(oldIdxRight + 1 - (oldSpRight - sp), '*'); + } + } + else if (ptrmask == 3 && tok == '-') // pointers in both expressions + { + incSize = GetDeclSize(-*ExprTypeSynPtr, 0); + // TBD!!! "ptr1-ptr2": better pointer type compatibility test needed, like compatCheck()? + if (incSize != GetDeclSize(-RightExprTypeSynPtr, 0)) + //error("exprval(): incompatible pointers\n"); + errorOpType(); + if (incSize != 1) + { + ins2(oldIdxRight + 2 - (oldSpRight - sp), tokNumInt, incSize); + ins(oldIdxRight + 2 - (oldSpRight - sp), '/'); + } + *ExprTypeSynPtr = SymIntSynPtr; + } + else if (ptrmask) + //error("exprval(): invalid combination of operands for '+' or '-'\n"); + errorOpType(); + + // Promote the result from char to int (and from int to unsigned) if necessary + promoteType(ExprTypeSynPtr, &RightExprTypeSynPtr); + + *ConstExpr = constExpr[0] && constExpr[1]; + simplifyConstExpr(s, *ConstExpr, ExprTypeSynPtr, oldIdxRight + 1 - (oldSpRight - sp), *idx + 1); + } + break; + + // Prefix/postfix increment/decrement unary operators + case tokInc: + case tokDec: + case tokPostInc: + case tokPostDec: + { + int incSize = 1; + int inc = tok == tokInc || tok == tokPostInc; + int post = tok == tokPostInc || tok == tokPostDec; + int opSize; + + exprval(idx, ExprTypeSynPtr, ConstExpr); + + scalarTypeCheck(*ExprTypeSynPtr); + + decayArray(ExprTypeSynPtr, 1); + + // lvalue check for ++, -- + if (!(oldIdxRight - (oldSpRight - sp) >= 0 && + stack[oldIdxRight - (oldSpRight - sp)][0] == tokUnaryStar)) + //error("exprval(): lvalue expected for '++' or '--'\n"); + errorNotLvalue(); + + // "remove" the lvalue dereference as we don't need + // to read the value and forget its location. We need to + // keep the lvalue location. + // Remember the operand size. + opSize = stack[oldIdxRight - (oldSpRight - sp)][1]; + del(oldIdxRight - (oldSpRight - sp), 1); + + if (*ExprTypeSynPtr < 0) + incSize = GetDeclSize(-*ExprTypeSynPtr, 0); + + if (incSize == 1) + { + // store the operand size in the operator + stack[oldIdxRight + 1 - (oldSpRight - sp)][1] = opSize; + } + else + { + // replace ++/-- with "postfix" +=/-= incSize when incSize != 1 + if (inc) + { + if (post) + stack[oldIdxRight + 1 - (oldSpRight - sp)][0] = tokPostAdd; + else + stack[oldIdxRight + 1 - (oldSpRight - sp)][0] = tokAssignAdd; + } + else + { + if (post) + stack[oldIdxRight + 1 - (oldSpRight - sp)][0] = tokPostSub; + else + stack[oldIdxRight + 1 - (oldSpRight - sp)][0] = tokAssignSub; + } + // store the operand size in the operator + stack[oldIdxRight + 1 - (oldSpRight - sp)][1] = opSize; + + ins2(oldIdxRight + 1 - (oldSpRight - sp), tokNumInt, incSize); + } + + *ConstExpr = 0; + } + break; + + // Simple assignment binary operator + case '=': + { + int oldIdxLeft, oldSpLeft; + int opSize; + int structs; + + exprval(idx, &RightExprTypeSynPtr, ConstExpr); + oldIdxLeft = *idx; + oldSpLeft = sp; + exprval(idx, ExprTypeSynPtr, ConstExpr); + + nonVoidTypeCheck(RightExprTypeSynPtr); + nonVoidTypeCheck(*ExprTypeSynPtr); + + decayArray(&RightExprTypeSynPtr, 0); + decayArray(ExprTypeSynPtr, 0); + + if (!(oldIdxLeft - (oldSpLeft - sp) >= 0 && + stack[oldIdxLeft - (oldSpLeft - sp)][0] == tokUnaryStar)) + //error("exprval(): lvalue expected before '='\n"); + errorNotLvalue(); + + structs = (RightExprTypeSynPtr >= 0 && SyntaxStack[RightExprTypeSynPtr][0] == tokStructPtr) + + (*ExprTypeSynPtr >= 0 && SyntaxStack[*ExprTypeSynPtr][0] == tokStructPtr) * 2; + if (structs) + { + char s[1 + 2 + (2 + CHAR_BIT * sizeof StructCpyLabel) / 3]; + char *p = s + sizeof s; + int sz; + + if (structs != 3 || + SyntaxStack[RightExprTypeSynPtr][1] != SyntaxStack[*ExprTypeSynPtr][1]) + errorOpType(); + + // TBD??? (a = b) should be an rvalue and so &(a = b) and (&(a = b))->c shouldn't be + // allowed, while (a = b).c should be allowed. + + // transform "*psleft = *psright" into "*fxn(sizeof *psright, psright, psleft)" + + if (stack[oldIdxLeft - (oldSpLeft - sp)][0] != tokUnaryStar || + stack[oldIdxRight - (oldSpRight - sp)][0] != tokUnaryStar) + errorInternal(18); + + stack[oldIdxLeft - (oldSpLeft - sp)][0] = ','; // replace '*' with ',' + stack[oldIdxRight - (oldSpRight - sp)][0] = ','; // replace '*' with ',' + + sz = GetDeclSize(RightExprTypeSynPtr, 0); + + stack[oldIdxRight + 1 - (oldSpRight - sp)][0] = tokNumUint; // replace '=' with "sizeof *psright" + stack[oldIdxRight + 1 - (oldSpRight - sp)][1] = sz; + + ins(oldIdxRight + 2 - (oldSpRight - sp), ','); + + if (!StructCpyLabel) + StructCpyLabel = LabelCnt++; + *--p = '\0'; + p = lab2str(p, StructCpyLabel); + *--p = '_'; + *--p = '_'; + ins2(oldIdxRight + 2 - (oldSpRight - sp), tokIdent, AddIdent(p)); + + ins2(oldIdxRight + 2 - (oldSpRight - sp), ')', SizeOfWord * 3); + ins2(oldIdxRight + 2 - (oldSpRight - sp), tokUnaryStar, 0); // use 0 deref size to drop meaningless dereferences + + ins2(*idx + 1, '(', SizeOfWord * 3); + } + else + { + // "remove" the lvalue dereference as we don't need + // to read the value and forget its location. We need to + // keep the lvalue location. + opSize = stack[oldIdxLeft - (oldSpLeft - sp)][1]; + // store the operand size in the operator + stack[oldIdxRight + 1 - (oldSpRight - sp)][1] = opSize; + del(oldIdxLeft - (oldSpLeft - sp), 1); + } + + *ConstExpr = 0; + } + break; + + // DONE: other assignment operators + + // Arithmetic and bitwise unary operators + case '~': + case tokUnaryPlus: + case tokUnaryMinus: + s = exprval(idx, ExprTypeSynPtr, ConstExpr); + scalarTypeCheck(*ExprTypeSynPtr); + numericTypeCheck(*ExprTypeSynPtr); + switch (tok) + { + case '~': s = ~s; break; + case tokUnaryPlus: s = +s; break; + case tokUnaryMinus: s = uint2int(~(s - 1u)); break; + } + promoteType(ExprTypeSynPtr, ExprTypeSynPtr); + simplifyConstExpr(s, *ConstExpr, ExprTypeSynPtr, oldIdxRight + 1 - (oldSpRight - sp), *idx + 1); + break; + + // Arithmetic and bitwise binary operators + case '*': + case '/': + case '%': + case tokLShift: + case tokRShift: + case '&': + case '^': + case '|': + { + // int oldIdxLeft, oldSpLeft; + int sr, sl; + int Unsigned; + sr = exprval(idx, &RightExprTypeSynPtr, &constExpr[1]); + // oldIdxLeft = *idx; + // oldSpLeft = sp; + sl = exprval(idx, ExprTypeSynPtr, &constExpr[0]); + + scalarTypeCheck(RightExprTypeSynPtr); + scalarTypeCheck(*ExprTypeSynPtr); + + numericTypeCheck(RightExprTypeSynPtr); + numericTypeCheck(*ExprTypeSynPtr); + + *ConstExpr = constExpr[0] && constExpr[1]; + + Unsigned = SyntaxStack[*ExprTypeSynPtr][0] == tokUnsigned || SyntaxStack[RightExprTypeSynPtr][0] == tokUnsigned; + + switch (tok) + { + // DONE: check for division overflows + case '/': + case '%': + *ConstExpr &= divCheckAndCalc(tok, &sl, sr, Unsigned, constExpr); + + if (Unsigned) + { + if (tok == '/') + stack[oldIdxRight + 1 - (oldSpRight - sp)][0] = tokUDiv; + else + stack[oldIdxRight + 1 - (oldSpRight - sp)][0] = tokUMod; + } + break; + + case '*': + sl = uint2int((sl + 0u) * sr); + break; + + case tokLShift: + case tokRShift: + if (constExpr[1]) + { + if (SyntaxStack[RightExprTypeSynPtr][0] != tokUnsigned) + sr = truncInt(sr); + else + sr = uint2int(truncUint(sr)); + shiftCountCheck(&sr, oldIdxRight - (oldSpRight - sp), RightExprTypeSynPtr); + } + if (*ConstExpr) + { + if (tok == tokLShift) + { + // left shift is the same for signed and unsigned ints + sl = uint2int((sl + 0u) << sr); + } + else + { + if (SyntaxStack[*ExprTypeSynPtr][0] == tokUnsigned) + { + // right shift for unsigned ints + sl = uint2int(truncUint(sl) >> sr); + } + else if (sr) + { + // right shift for signed ints is arithmetic, sign-bit-preserving + // don't depend on the compiler's implementation, do it "manually" + sl = truncInt(sl); + sl = uint2int((truncUint(sl) >> sr) | + ((sl < 0) * (~0u << (8 * SizeOfWord - sr)))); + } + } + } + + if (SyntaxStack[*ExprTypeSynPtr][0] == tokUnsigned && tok == tokRShift) + stack[oldIdxRight + 1 - (oldSpRight - sp)][0] = tokURShift; + + // ignore RightExprTypeSynPtr for the purpose of promotion/conversion of the result of <> + RightExprTypeSynPtr = SymIntSynPtr; + break; + + case '&': sl &= sr; break; + case '^': sl ^= sr; break; + case '|': sl |= sr; break; + } + + s = sl; + promoteType(ExprTypeSynPtr, &RightExprTypeSynPtr); + simplifyConstExpr(s, *ConstExpr, ExprTypeSynPtr, oldIdxRight + 1 - (oldSpRight - sp), *idx + 1); + } + break; + + // Relational binary operators + // DONE: add (sub)tokens for unsigned >, >=, <, <= for pointers + case '<': + case '>': + case tokLEQ: + case tokGEQ: + case tokEQ: + case tokNEQ: + { + int ptrmask; + int sr, sl; + int Unsigned; + sr = exprval(idx, &RightExprTypeSynPtr, &constExpr[1]); + sl = exprval(idx, ExprTypeSynPtr, &constExpr[0]); + + scalarTypeCheck(RightExprTypeSynPtr); + scalarTypeCheck(*ExprTypeSynPtr); + + decayArray(&RightExprTypeSynPtr, 0); + decayArray(ExprTypeSynPtr, 0); + + ptrmask = (RightExprTypeSynPtr < 0) + (*ExprTypeSynPtr < 0) * 2; + + // Disallow >, <, >=, <= between a pointer and a number + if (ptrmask >= 1 && ptrmask <= 2 && + tok != tokEQ && tok != tokNEQ) + //error("exprval(): Invalid/unsupported combination of compared operands\n"); + errorOpType(); + + *ConstExpr = constExpr[0] && constExpr[1]; + + Unsigned = !ptrmask && + (SyntaxStack[*ExprTypeSynPtr][0] == tokUnsigned || SyntaxStack[RightExprTypeSynPtr][0] == tokUnsigned); + + if (*ConstExpr) + { + if (!Unsigned) + { + sl = truncInt(sl); + sr = truncInt(sr); + switch (tok) + { + case '<': sl = sl < sr; break; + case '>': sl = sl > sr; break; + case tokLEQ: sl = sl <= sr; break; + case tokGEQ: sl = sl >= sr; break; + case tokEQ: sl = sl == sr; break; + case tokNEQ: sl = sl != sr; break; + } + } + else + { + sl = uint2int(truncUint(sl)); + sr = uint2int(truncUint(sr)); + switch (tok) + { + case '<': sl = sl + 0u < sr + 0u; break; + case '>': sl = sl + 0u > sr + 0u; break; + case tokLEQ: sl = sl + 0u <= sr + 0u; break; + case tokGEQ: sl = sl + 0u >= sr + 0u; break; + case tokEQ: sl = sl == sr; break; + case tokNEQ: sl = sl != sr; break; + } + } + } + + if (ptrmask || Unsigned) + { + // Pointer comparison should be unsigned + int t = tok; + switch (tok) + { + case '<': t = tokULess; break; + case '>': t = tokUGreater; break; + case tokLEQ: t = tokULEQ; break; + case tokGEQ: t = tokUGEQ; break; + } + if (t != tok) + stack[oldIdxRight + 1 - (oldSpRight - sp)][0] = t; + } + + s = sl; + *ExprTypeSynPtr = SymIntSynPtr; + simplifyConstExpr(s, *ConstExpr, ExprTypeSynPtr, oldIdxRight + 1 - (oldSpRight - sp), *idx + 1); + } + break; + + // implicit pseudo-conversion to _Bool of operands of && and || + case tok_Bool: + s = exprval(idx, ExprTypeSynPtr, ConstExpr); + s = truncInt(s) != 0; + scalarTypeCheck(*ExprTypeSynPtr); + decayArray(ExprTypeSynPtr, 0); + *ExprTypeSynPtr = SymIntSynPtr; + simplifyConstExpr(s, *ConstExpr, ExprTypeSynPtr, oldIdxRight + 1 - (oldSpRight - sp), *idx + 1); + break; + + // Logical binary operators + case tokLogAnd: // DONE: short-circuit + case tokLogOr: // DONE: short-circuit + { + int sr, sl; + + // DONE: think of pushing a special short-circuit (jump-to) token + // to skip the rhs operand evaluation in && and || + // DONE: add implicit "casts to _Bool" of && and || operands, + // do the same for control statements of if() while() and for(;;). + + int sc = LabelCnt++; + // tag the logical operator as a numbered short-circuit jump target + stack[*idx + 1][1] = sc; + + // insert "!= 0" for right-hand operand + switch (stack[*idx][0]) + { + case '<': + case tokULess: + case '>': + case tokUGreater: + case tokLEQ: + case tokULEQ: + case tokGEQ: + case tokUGEQ: + case tokEQ: + case tokNEQ: + break; + default: + ins(++*idx, tok_Bool); + break; + } + + sr = exprval(idx, &RightExprTypeSynPtr, &constExpr[1]); + + // insert a reference to the short-circuit jump target + if (tok == tokLogAnd) + ins2(++*idx, tokShortCirc, sc); + else + ins2(++*idx, tokShortCirc, -sc); + // insert "!= 0" for left-hand operand + switch (stack[*idx - 1][0]) + { + case '<': + case tokULess: + case '>': + case tokUGreater: + case tokLEQ: + case tokULEQ: + case tokGEQ: + case tokUGEQ: + case tokEQ: + case tokNEQ: + --*idx; + break; + default: + ins(*idx, tok_Bool); + break; + } + + sl = exprval(idx, ExprTypeSynPtr, &constExpr[0]); + + if (tok == tokLogAnd) + s = sl && sr; + else + s = sl || sr; + + *ExprTypeSynPtr = SymIntSynPtr; + *ConstExpr = constExpr[0] && constExpr[1]; + if (constExpr[0]) + { + if (tok == tokLogAnd) + { + if (!sl) + *ConstExpr = 1, s = 0; + // TBD??? else can drop LHS expression + } + else + { + if (sl) + *ConstExpr = s = 1; + // TBD??? else can drop LHS expression + } + } + simplifyConstExpr(s, *ConstExpr, ExprTypeSynPtr, oldIdxRight + 1 - (oldSpRight - sp), *idx + 1); + } + break; + + // Function call + case ')': + { + int tmpSynPtr, c; + int minParams, maxParams; + exprval(idx, ExprTypeSynPtr, ConstExpr); + + if (!GetFxnInfo(*ExprTypeSynPtr, &minParams, &maxParams, ExprTypeSynPtr)) + //error("exprval(): function or function pointer expected\n"); + errorOpType(); + + // DONE: validate the number of function parameters + // TBD??? warnings/errors on int<->pointer substitution in params + + // evaluate function parameters + c = 0; + while (stack[*idx][0] != '(') + { + // add a comma after the first (last to be pushed) parameter, + // so all parameters can be pushed whenever a comma is encountered + if (!c) + ins(*idx + 1, ','); + + exprval(idx, &tmpSynPtr, ConstExpr); + //error("exprval(): function parameters cannot be of type 'void'\n"); + scalarTypeCheck(tmpSynPtr); + + if (++c > maxParams) + error("Too many function parameters\n"); + + if (stack[*idx][0] == ',') + --*idx; + } + --*idx; + + if (c < minParams) + error("Too few function parameters\n"); + + // store the cumulative parameter size in the function call operators + stack[1 + *idx][1] = stack[oldIdxRight + 1 - (oldSpRight - sp)][1] = c * SizeOfWord; + + *ConstExpr = 0; + } + break; + + // Binary comma operator + case tokComma: + { + int oldIdxLeft, oldSpLeft; + s = exprval(idx, &RightExprTypeSynPtr, &constExpr[1]); + oldIdxLeft = *idx; + oldSpLeft = sp; + + // Signify uselessness of the result of the left operand's value + ins(*idx + 1, tokVoid); + + exprval(idx, ExprTypeSynPtr, &constExpr[0]); + *ConstExpr = constExpr[0] && constExpr[1]; + *ExprTypeSynPtr = RightExprTypeSynPtr; + if (*ConstExpr) + { + // both subexprs are const, remove both and comma + simplifyConstExpr(s, *ConstExpr, ExprTypeSynPtr, oldIdxRight + 1 - (oldSpRight - sp), *idx + 1); + } + else if (constExpr[0]) + { + // only left subexpr is const, remove it and comma + del(*idx + 1, oldIdxLeft - (oldSpLeft - sp) - *idx); + del(oldIdxRight + 1 - (oldSpRight - sp), 1); + } + } + break; + + // Compound assignment operators + case tokAssignMul: case tokAssignDiv: case tokAssignMod: + case tokAssignAdd: case tokAssignSub: + case tokAssignLSh: case tokAssignRSh: + case tokAssignAnd: case tokAssignXor: case tokAssignOr: + { + int ptrmask; + int oldIdxLeft, oldSpLeft; + int incSize; + int opSize; + int Unsigned; + int sr = exprval(idx, &RightExprTypeSynPtr, &constExpr[1]); + oldIdxLeft = *idx; + oldSpLeft = sp; + exprval(idx, ExprTypeSynPtr, &constExpr[0]); + + scalarTypeCheck(RightExprTypeSynPtr); + scalarTypeCheck(*ExprTypeSynPtr); + + decayArray(&RightExprTypeSynPtr, 1); + decayArray(ExprTypeSynPtr, 1); + + if (!(oldIdxLeft - (oldSpLeft - sp) >= 0 && + stack[oldIdxLeft - (oldSpLeft - sp)][0] == tokUnaryStar)) + //error("exprval(): lvalue expected before %s\n", GetTokenName(tok)); + errorNotLvalue(); + + // "remove" the lvalue dereference as we don't need + // to read the value and forget its location. We need to + // keep the lvalue location. + opSize = stack[oldIdxLeft - (oldSpLeft - sp)][1]; + // store the operand size in the operator + stack[oldIdxRight + 1 - (oldSpRight - sp)][1] = opSize; + del(oldIdxLeft - (oldSpLeft - sp), 1); + + ptrmask = (RightExprTypeSynPtr < 0) + (*ExprTypeSynPtr < 0) * 2; + + Unsigned = !ptrmask && + (SyntaxStack[*ExprTypeSynPtr][0] == tokUnsigned || SyntaxStack[RightExprTypeSynPtr][0] == tokUnsigned); + + if (tok != tokAssignAdd && tok != tokAssignSub) + { + if (ptrmask) + //error("exprval(): invalid combination of operands for %s\n", GetTokenName(tok)); + errorOpType(); + } + else + { + // No pointer to the right of += and -= + if (ptrmask & 1) + //error("exprval(): invalid combination of operands for %s\n", GetTokenName(tok)); + errorOpType(); + } + + if (tok == tokAssignLSh || tok == tokAssignRSh) + { + if (constExpr[1]) + { + if (SyntaxStack[RightExprTypeSynPtr][0] != tokUnsigned) + sr = truncInt(sr); + else + sr = uint2int(truncUint(sr)); + shiftCountCheck(&sr, oldIdxRight - (oldSpRight - sp), RightExprTypeSynPtr); + } + } + + if (tok == tokAssignDiv || tok == tokAssignMod) + { + int t, sl = 0; + if (tok == tokAssignDiv) + t = '/'; + else + t = '%'; + divCheckAndCalc(t, &sl, sr, 1, constExpr); + } + + // TBD??? replace +=/-= with prefix ++/-- if incSize == 1 + if (ptrmask == 2) // left-hand expression + { + incSize = GetDeclSize(-*ExprTypeSynPtr, 0); + if (constExpr[1]) + { + int t = uint2int(stack[oldIdxRight - (oldSpRight - sp)][1] * (incSize + 0u)); + stack[oldIdxRight - (oldSpRight - sp)][1] = t; + } + else if (incSize != 1) + { + ins2(oldIdxRight + 1 - (oldSpRight - sp), tokNumInt, incSize); + ins(oldIdxRight + 1 - (oldSpRight - sp), '*'); + } + } + else if (Unsigned) + { + int t = tok; + switch (tok) + { + case tokAssignDiv: t = tokAssignUDiv; break; + case tokAssignMod: t = tokAssignUMod; break; + case tokAssignRSh: t = tokAssignURSh; break; + } + if (t != tok) + stack[oldIdxRight + 1 - (oldSpRight - sp)][0] = t; + } + + *ConstExpr = 0; + } + break; + + // Ternary/conditional operator + case '?': + { + int oldIdxLeft, oldSpLeft; + int sr, sl, smid; + int condTypeSynPtr; + int sc = (LabelCnt += 2) - 2; + int structs; + + // "exprL ? exprMID : exprR" appears on the stack as + // "exprL exprR exprMID ?" + + stack[*idx + 1][0] = tokLogAnd; // piggyback on && for CG (ugly, but simple) + stack[*idx + 1][1] = sc + 1; + smid = exprval(idx, ExprTypeSynPtr, &constExpr[1]); + + ins2(*idx + 1, tokLogAnd, sc); // piggyback on && for CG (ugly, but simple) + + ins2(*idx + 1, tokGoto, sc + 1); // jump to end of ?: + oldIdxLeft = *idx; + oldSpLeft = sp; + sr = exprval(idx, &RightExprTypeSynPtr, &constExpr[2]); + + ins2(*idx + 1, tokShortCirc, -sc); // jump to mid if left is non-zero + sl = exprval(idx, &condTypeSynPtr, &constExpr[0]); + + scalarTypeCheck(condTypeSynPtr); + + decayArray(&RightExprTypeSynPtr, 0); + decayArray(ExprTypeSynPtr, 0); + promoteType(&RightExprTypeSynPtr, ExprTypeSynPtr); + promoteType(ExprTypeSynPtr, &RightExprTypeSynPtr); + + // TBD??? move struct/union-related checks into compatChecks() + + structs = (RightExprTypeSynPtr >= 0 && SyntaxStack[RightExprTypeSynPtr][0] == tokStructPtr) + + (*ExprTypeSynPtr >= 0 && SyntaxStack[*ExprTypeSynPtr][0] == tokStructPtr) * 2; + if (structs) + { + if (structs != 3 || + SyntaxStack[RightExprTypeSynPtr][1] != SyntaxStack[*ExprTypeSynPtr][1]) + errorOpType(); + + // transform "cond ? a : b" into "*(cond ? &a : &b)" + + if (stack[oldIdxLeft - (oldSpLeft - sp)][0] != tokUnaryStar || + stack[oldIdxRight - (oldSpRight - sp)][0] != tokUnaryStar) + errorInternal(19); + + del(oldIdxLeft - (oldSpLeft - sp), 1); // delete '*' + del(oldIdxRight - (oldSpRight - sp), 1); // delete '*' + ins2(oldIdxRight + 2 - (oldSpRight - sp), tokUnaryStar, 0); // use 0 deref size to drop meaningless dereferences + } + else + { + compatCheck(ExprTypeSynPtr, + RightExprTypeSynPtr, + &constExpr[1], + oldIdxRight - (oldSpRight - sp), + oldIdxLeft - (oldSpLeft - sp)); + } + + *ConstExpr = s = 0; + + if (constExpr[0]) + { + if (truncUint(sl)) + { + if (constExpr[1]) + *ConstExpr = 1, s = smid; + // TBD??? else can drop LHS and RHS expressions + } + else + { + if (constExpr[2]) + *ConstExpr = 1, s = sr; + // TBD??? else can drop LHS and MID expressions + } + } + simplifyConstExpr(s, *ConstExpr, ExprTypeSynPtr, oldIdxRight + 1 - (oldSpRight - sp), *idx + 1); + } + break; + + // Postfix indirect structure/union member selection operator + case tokArrow: + { + int member, i, j = 0, c = 1, ofs = 0; + + stack[*idx + 1][0] = '+'; // replace -> with + + member = stack[*idx][1]; // keep the member name, it will be replaced with member offset + stack[*idx][0] = tokNumInt; + + --*idx; + exprval(idx, ExprTypeSynPtr, ConstExpr); + + if (*ExprTypeSynPtr >= 0 && SyntaxStack[*ExprTypeSynPtr][0] == '*') + *ExprTypeSynPtr = -(*ExprTypeSynPtr + 1); // TBD!!! shouldn't this be done elsewhere? + + if (*ExprTypeSynPtr >= 0 || + SyntaxStack[-*ExprTypeSynPtr][0] != tokStructPtr) + error("Pointer to or structure or union expected\n"); + + i = SyntaxStack[-*ExprTypeSynPtr][1]; + if (i + 2 > SyntaxStackCnt || + (SyntaxStack[i][0] != tokStruct && SyntaxStack[i][0] != tokUnion) || + SyntaxStack[i + 1][0] != tokTag) + errorInternal(20); + + if (!GetDeclSize(i, 0)) + // incomplete structure/union type + errorOpType(); + + i += 5; // step inside the {} body of the struct/union + while (c) + { + int t = SyntaxStack[i][0]; + c += (t == '(') - (t == ')') + (t == '{') - (t == '}'); + if (c == 1 && + t == tokMemberIdent && SyntaxStack[i][1] == member && + SyntaxStack[i + 1][0] == tokLocalOfs) + { + j = i; + ofs = SyntaxStack[i + 1][1]; + } + i++; + } + if (!j) + error("Undefined structure or union member '%s'\n", IdentTable + member); + + j += 2; + *ExprTypeSynPtr = -j; // type: pointer to member's type + + stack[oldIdxRight - (oldSpRight - sp)][1] = ofs; // member offset within structure/union + + // optimize a little, if possible + { + int i = oldIdxRight - (oldSpRight - sp) - 1; + // Skip any type cast markers + while (stack[i][0] == tokUnaryPlus) + i--; + // See if the pointer is an integer constant or a local variable offset + // and if it is, adjust it here instead of generating code for + // addition/subtraction + if (stack[i][0] == tokNumInt || stack[i][0] == tokNumUint || stack[i][0] == tokLocalOfs) + { + stack[i][1] = uint2int(stack[i][1] + 0u + ofs); // TBD!!! need extra truncation? + del(oldIdxRight - (oldSpRight - sp), 2); + } + } + + *ConstExpr = 0; + } + break; + + default: + //error("exprval(): Unexpected token %s\n", GetTokenName(tok)); + errorUnexpectedToken(tok); + } + + return s; +} + +int ParseExpr(int tok, int* GotUnary, int* ExprTypeSynPtr, int* ConstExpr, int* ConstVal, int commaSeparator, int label) +{ + int identFirst = tok == tokIdent; + *ConstVal = *ConstExpr = 0; + *ExprTypeSynPtr = SymVoidSynPtr; + + if (!ExprLevel++) + { + opsp = sp = 0; + PurgeStringTable(); + } + + tok = expr(tok, GotUnary, commaSeparator); + + if (tok == tokEof || strchr(",;:)]}", tok) == NULL) + //error("ParseExpr(): Unexpected token %s\n", GetTokenName(tok)); + errorUnexpectedToken(tok); + + if (label && identFirst && tok == ':' && *GotUnary && sp == 1 && stack[sp - 1][0] == tokIdent) + { + // This is a label. + ExprLevel--; + return tokGotoLabel; + } + + if (*GotUnary) + { + int j; + // Do this twice so we can see the stack before + // and after manipulations + for (j = 0; j < 2; j++) + { +#ifndef NO_ANNOTATIONS + int i; + GenStartCommentLine(); + if (j) printf2("Expanded"); + else printf2("RPN'ized"); + printf2(" expression: \""); + for (i = 0; i < sp; i++) + { + int tok = stack[i][0]; + switch (tok) + { + case tokNumInt: + printf2("%d", truncInt(stack[i][1])); + break; + case tokNumUint: + printf2("%uu", truncUint(stack[i][1])); + break; + case tokIdent: + { + char* p = IdentTable + stack[i][1]; + if (isdigit(*p)) + printf2("L"); + printf2("%s", p); + } + break; + case tokShortCirc: + if (stack[i][1] >= 0) + printf2("[sh&&->%d]", stack[i][1]); + else + printf2("[sh||->%d]", -stack[i][1]); + break; + case tokLocalOfs: + printf2("(@%d)", truncInt(stack[i][1])); + break; + case tokUnaryStar: + if (j) printf2("*(%d)", stack[i][1]); + else printf2("*u"); + break; + case '(': case ',': + if (!j) printf2("%c", tok); + // else printf2("\b"); + break; + case ')': + if (j) printf2("("); + printf2("%c", tok); + if (j) printf2("%d", stack[i][1]); + break; + default: + printf2("%s", GetTokenName(tok)); + if (j) + { + switch (tok) + { + case tokLogOr: case tokLogAnd: + printf2("[%d]", stack[i][1]); + break; + case '=': + case tokInc: case tokDec: + case tokPostInc: case tokPostDec: + case tokAssignAdd: case tokAssignSub: + case tokPostAdd: case tokPostSub: + case tokAssignMul: + case tokAssignDiv: case tokAssignMod: + case tokAssignUDiv: case tokAssignUMod: + case tokAssignLSh: case tokAssignRSh: case tokAssignURSh: + case tokAssignAnd: case tokAssignXor: case tokAssignOr: + printf2("(%d)", stack[i][1]); + break; + } + } + break; + } + printf2(" "); + } + printf2("\"\n"); +#endif + if (!j) + { + int idx = sp - 1; + *ConstVal = exprval(&idx, ExprTypeSynPtr, ConstExpr); + // remove the unneeded unary +'s that have served their cast-substitute purpose + // also remove dereferences of size 0 (dereferences of pointers to structures) + for (idx = sp - 1; idx >= 0; idx--) + if (stack[idx][0] == tokUnaryPlus || + (stack[idx][0] == tokUnaryStar && !stack[idx][1])) + del(idx, 1); + } +#ifndef NO_ANNOTATIONS + else if (*ConstExpr) + { + GenStartCommentLine(); + + switch (SyntaxStack[*ExprTypeSynPtr][0]) + { + case tokChar: + case tokSChar: + case tokUChar: +#ifdef CAN_COMPILE_32BIT + case tokShort: + case tokUShort: +#endif + case tokInt: + printf2("Expression value: %d\n", truncInt(*ConstVal)); + break; + default: + case tokUnsigned: + printf2("Expression value: %uu\n", truncUint(*ConstVal)); + break; + } + } +#endif + } + } + + ExprLevel--; + + return tok; +} + +// smc.c code + +#ifdef __SMALLER_C__ +// 2 if va_list is a one-element array containing a pointer +// (typical for x86 Open Watcom C/C++) +// 1 if va_list is a pointer +// (typical for Turbo C++, x86 gcc) +// 0 if va_list is something else, and +// the code may have long crashed by now +int VaListType = 0; + +// Attempts to determine the type of va_list as +// expected by the standard library +void DetermineVaListType(void) +{ + void* testptr[2]; + // hopefully enough space to sprintf() 3 pointers using "%p" + char testbuf[3][CHAR_BIT * sizeof(void*) + 1]; + + // TBD!!! This is not good. Really need the va_something macros. + // Test whether va_list is a pointer to the first optional parameter or + // an array of one element containing said pointer + testptr[0] = &testptr[1]; + testptr[1] = &testptr[0]; + memset(testbuf, '\0', sizeof(testbuf)); + sprintf(testbuf[0], "%p", testptr[0]); + sprintf(testbuf[1], "%p", testptr[1]); + vsprintf(testbuf[2], "%p", &testptr[0]); + if (!strcmp(testbuf[2], testbuf[0])) + { + // va_list is a pointer + VaListType = 1; + } + else if (!strcmp(testbuf[2], testbuf[1])) + { + // va_list is a one-element array containing a pointer + VaListType = 2; + } + else + { + // va_list is something else, and + // the code may have long crashed by now + printf("Internal error: Indeterminate underlying type of va_list\n"); + exit(-1); + } +} +#endif + +// Equivalent to puts() but outputs to OutFile +// if it's not NULL. +int puts2(char* s) +{ + int res; + if (OutFile) + { + // Turbo C++ 1.01's fputs() returns EOF if s is empty, which is wrong. + // Hence the workaround. + if (*s == '\0' || (res = fputs(s, OutFile)) >= 0) + { + // unlike puts(), fputs() doesn't append '\n', append it manually + res = fputc('\n', OutFile); + } + } + else + { + res = puts(s); + } + return res; +} + +// Equivalent to printf() but outputs to OutFile +// if it's not NULL. +int printf2(char* format, ...) +{ + int res; + +#ifndef __SMALLER_C__ + va_list vl; + va_start(vl, format); +#else + void* vl = &format + 1; +#endif + +#ifndef __SMALLER_C__ + if (OutFile) + res = vfprintf(OutFile, format, vl); + else + res = vprintf(format, vl); +#else + // TBD!!! This is not good. Really need the va_something macros. + if (VaListType == 1) + { + // va_list is a pointer + if (OutFile) + res = vfprintf(OutFile, format, vl); + else + res = vprintf(format, vl); + } + else // if (VaListType == 2) + { + // va_list is a one-element array containing a pointer + if (OutFile) + res = vfprintf(OutFile, format, &vl); + else + res = vprintf(format, &vl); + } +#endif + +#ifndef __SMALLER_C__ + va_end(vl); +#endif + + return res; +} + +void error(char* format, ...) +{ + int i, fidx = FileCnt - 1 + !FileCnt; +#ifndef __SMALLER_C__ + va_list vl; + va_start(vl, format); +#else + void* vl = &format + 1; +#endif + + for (i = 0; i < FileCnt; i++) + if (Files[i]) + fclose(Files[i]); + + puts2(""); + + DumpSynDecls(); +#ifndef NO_PREPROCESSOR + DumpMacroTable(); +#endif + DumpIdentTable(); + + // using stdout implicitly instead of stderr explicitly because: + // - stderr can be a macro and it's unknown if standard headers + // aren't included (which is the case when SmallerC is compiled + // with itself and linked with some other compiler's standard + // libraries) + // - output to stderr can interfere/overlap with buffered + // output to stdout and the result may literally look ugly + + GenStartCommentLine(); printf2("Compilation failed.\n"); + + if (OutFile) + fclose(OutFile); + + printf("Error in \"%s\" (%d:%d)\n", FileNames[fidx], LineNo, LinePos); + +#ifndef __SMALLER_C__ + vprintf(format, vl); +#else + // TBD!!! This is not good. Really need the va_something macros. + if (VaListType == 1) + { + // va_list is a pointer + vprintf(format, vl); + } + else // if (VaListType == 2) + { + // va_list is a one-element array containing a pointer + vprintf(format, &vl); + } +#endif + +#ifndef __SMALLER_C__ + va_end(vl); +#endif + + exit(-1); +} + +void warning(char* format, ...) +{ + int fidx = FileCnt - 1 + !FileCnt; +#ifndef __SMALLER_C__ + va_list vl; + va_start(vl, format); +#else + void* vl = &format + 1; +#endif + + warnCnt++; + + if (!(verbose && OutFile)) + return; + + printf("Warning in \"%s\" (%d:%d)\n", FileNames[fidx], LineNo, LinePos); + +#ifndef __SMALLER_C__ + vprintf(format, vl); +#else + // TBD!!! This is not good. Really need the va_something macros. + if (VaListType == 1) + { + // va_list is a pointer + vprintf(format, vl); + } + else // if (VaListType == 2) + { + // va_list is a one-element array containing a pointer + vprintf(format, &vl); + } +#endif + +#ifndef __SMALLER_C__ + va_end(vl); +#endif +} + +void errorFile(char* n) +{ + error("Unable to open, read, write or close file \"%s\"\n", n); +} + +void errorFileName(void) +{ + error("Invalid or too long file name or path name\n"); +} + +void errorInternal(int n) +{ + error("%d (internal)\n", n); +} + +void errorChrStr(void) +{ + error("Invalid or unsupported character constant or string literal\n"); +} + +void errorUnexpectedToken(int tok) +{ + error("Unexpected token %s\n", GetTokenName(tok)); +} + +void errorDirective(void) +{ + error("Invalid or unsupported preprocessor directive\n"); +} + +void errorCtrlOutOfScope(void) +{ + error("break, continue, case or default in wrong scope\n"); +} + +void errorDecl(void) +{ + error("Invalid or unsupported declaration\n"); +} + +void errorTagRedef(int ident) +{ + error("Redefinition of type tagged '%s'\n", IdentTable + ident); +} + +void errorRedef(char* s) +{ + error("Redefinition of identifier '%s'\n", s); +} + +void errorVarSize(void) +{ + error("Variable(s) take(s) too much space\n"); +} + +void errorInit(void) +{ + error("Invalid or unsupported initialization\n"); +} + +void errorUnexpectedVoid(void) +{ + error("Unexpected declaration or expression of type void\n"); +} + +void errorOpType(void) +{ + error("Unexpected operand type\n"); +} + +void errorNotLvalue(void) +{ + error("lvalue expected\n"); +} + +void errorNotConst(void) +{ + error("Non-constant expression\n"); +} + +void errorLongExpr(void) +{ + error("Too long expression\n"); +} + +int tsd[] = +{ + tokVoid, tokChar, tokInt, + tokSigned, tokUnsigned, tokShort, + tokStruct, tokUnion, +}; + +int TokenStartsDeclaration(int t, int params) +{ +#ifndef NO_TYPEDEF_ENUM + int CurScope; +#endif + unsigned i; + + for (i = 0; i < sizeof tsd / sizeof tsd[0]; i++) + if (tsd[i] == t) + return 1; + + return +#ifdef CAN_COMPILE_32BIT + (SizeOfWord != 2 && t == tokLong) || +#endif +#ifndef NO_TYPEDEF_ENUM + t == tokEnum || + (t == tokIdent && + FindTypedef(GetTokenIdentName(), &CurScope, 1) >= 0) || +#endif + (!params && (t == tokExtern || +#ifndef NO_TYPEDEF_ENUM + t == tokTypedef || +#endif + t == tokStatic)); +} + +void PushSyntax2(int t, int v) +{ + if (SyntaxStackCnt >= SYNTAX_STACK_MAX) + error("Symbol table exhausted\n"); + SyntaxStack[SyntaxStackCnt][0] = t; + SyntaxStack[SyntaxStackCnt++][1] = v; +} + +void PushSyntax(int t) +{ + PushSyntax2(t, 0); +} + +void InsertSyntax2(int pos, int t, int v) +{ + if (SyntaxStackCnt >= SYNTAX_STACK_MAX) + error("Symbol table exhausted\n"); + memmove(SyntaxStack[pos + 1], + SyntaxStack[pos], + sizeof(SyntaxStack[0]) * (SyntaxStackCnt - pos)); + SyntaxStack[pos][0] = t; + SyntaxStack[pos][1] = v; + SyntaxStackCnt++; +} + +void InsertSyntax(int pos, int t) +{ + InsertSyntax2(pos, t, 0); +} + +void DeleteSyntax(int pos, int cnt) +{ + memmove(SyntaxStack[pos], + SyntaxStack[pos + cnt], + sizeof(SyntaxStack[0]) * (SyntaxStackCnt - (pos + cnt))); + SyntaxStackCnt -= cnt; +} + +int FindSymbol(char* s) +{ + int i; + + // TBD!!! return declaration scope number so + // redeclarations can be reported if occur in the same scope. + + // TBD??? Also, I could first use FindIdent() and then just look for the + // index into IdentTable[] instead of doing strcmp() + + for (i = SyntaxStackCnt - 1; i >= 0; i--) + { + int t = SyntaxStack[i][0]; + if (t == tokIdent && + !strcmp(IdentTable + SyntaxStack[i][1], s)) + { + return i; + } + + if (t == ')') + { + // Skip over the function params + int c = -1; + while (c) + { + t = SyntaxStack[--i][0]; + c += (t == '(') - (t == ')'); + } + } + } + + return -1; +} + +int SymType(int SynPtr) +{ + int local = 0; + + if (SyntaxStack[SynPtr][0] == tokIdent) + SynPtr++; + + if ((local = SyntaxStack[SynPtr][0] == tokLocalOfs) != 0) + SynPtr++; + + switch (SyntaxStack[SynPtr][0]) + { + case '(': + return SymFxn; + + case '[': + if (local) + return SymLocalArr; + return SymGlobalArr; + + default: + if (local) + return SymLocalVar; + return SymGlobalVar; + } +} + +int FindTaggedDecl(char* s, int start, int* CurScope) +{ + int i; + + *CurScope = 1; + + for (i = start; i >= 0; i--) + { + int t = SyntaxStack[i][0]; + if (t == tokTag && + !strcmp(IdentTable + SyntaxStack[i][1], s)) + { + return i - 1; + } + else if (t == ')') + { + // Skip over the function params + int c = -1; + while (c) + { + t = SyntaxStack[--i][0]; + c += (t == '(') - (t == ')'); + } + } + else if (t == '#') + { + // the scope has changed to the outer scope + *CurScope = 0; + } + } + + return -1; +} + +#ifndef NO_TYPEDEF_ENUM +// TBD??? rename this fxn? Cleanup/unify search functions? +int FindTypedef(char* s, int* CurScope, int forUse) +{ + int i; + + *CurScope = 1; + + for (i = SyntaxStackCnt - 1; i >= 0; i--) + { + int t = SyntaxStack[i][0]; + if ((t == tokTypedef || t == tokIdent) && + !strcmp(IdentTable + SyntaxStack[i][1], s)) + { + // if the closest declaration isn't from typedef, + // (i.e. if it's a variable/function declaration), + // then the type is unknown for the purpose of + // declaring a variable of this type + if (forUse && t == tokIdent) + return -1; + return i; + } + + if (t == ')') + { + // Skip over the function params + int c = -1; + while (c) + { + t = SyntaxStack[--i][0]; + c += (t == '(') - (t == ')'); + } + } + else if (t == '#') + { + // the scope has changed to the outer scope + *CurScope = 0; + } + } + + return -1; +} +#endif + +int GetDeclSize(int SyntaxPtr, int SizeForDeref) +{ + int i; + unsigned size = 1; + int arr = 0; + + if (SyntaxPtr < 0) + errorInternal(10); + + for (i = SyntaxPtr; i < SyntaxStackCnt; i++) + { + int tok = SyntaxStack[i][0]; + switch (tok) + { + case tokIdent: // skip leading identifiers, if any + case tokLocalOfs: // skip local var offset, too + break; + case tokChar: + case tokSChar: + if (!arr && ((tok == tokSChar) || CharIsSigned) && SizeForDeref) + return -1; // 1 byte, needing sign extension when converted to int/unsigned int + // fallthrough + case tokUChar: + return uint2int(size); +#ifdef CAN_COMPILE_32BIT + case tokShort: + if (!arr && SizeForDeref) + return -2; // 2 bytes, needing sign extension when converted to int/unsigned int + // fallthrough + case tokUShort: + if (size * 2 / 2 != size) + //error("Variable too big\n"); + errorVarSize(); + size *= 2; + if (size != truncUint(size)) + //error("Variable too big\n"); + errorVarSize(); + return uint2int(size); +#endif + case tokInt: + case tokUnsigned: + case '*': + case '(': // size of fxn = size of ptr for now + if (size * SizeOfWord / SizeOfWord != size) + //error("Variable too big\n"); + errorVarSize(); + size *= SizeOfWord; + if (size != truncUint(size)) + //error("Variable too big\n"); + errorVarSize(); + return uint2int(size); + case '[': + if (SyntaxStack[i + 1][0] != tokNumInt && SyntaxStack[i + 1][0] != tokNumUint) + errorInternal(11); + if (SyntaxStack[i + 1][1] && + size * SyntaxStack[i + 1][1] / SyntaxStack[i + 1][1] != size) + //error("Variable too big\n"); + errorVarSize(); + size *= SyntaxStack[i + 1][1]; + if (size != truncUint(size)) + //error("Variable too big\n"); + errorVarSize(); + i += 2; + arr = 1; + break; + case tokStructPtr: + // follow the "type pointer" + i = SyntaxStack[i][1] - 1; + break; + case tokStruct: + case tokUnion: + if (i + 2 < SyntaxStackCnt && SyntaxStack[i + 2][0] == tokSizeof && !SizeForDeref) + { + unsigned s = SyntaxStack[i + 2][1]; + if (s && size * s / s != size) + errorVarSize(); + size *= s; + if (size != truncUint(size)) + errorVarSize(); + return uint2int(size); + } + return 0; + case tokVoid: + return 0; + default: + errorInternal(12); + } + } + + errorInternal(13); + return 0; +} + +int GetDeclAlignment(int SyntaxPtr) +{ + int i; + + if (SyntaxPtr < 0) + errorInternal(14); + + for (i = SyntaxPtr; i < SyntaxStackCnt; i++) + { + int tok = SyntaxStack[i][0]; + switch (tok) + { + case tokIdent: // skip leading identifiers, if any + case tokLocalOfs: // skip local var offset, too + break; + case tokChar: + case tokSChar: + case tokUChar: + return 1; +#ifdef CAN_COMPILE_32BIT + case tokShort: + case tokUShort: + return 2; +#endif + case tokInt: + case tokUnsigned: + case '*': + case '(': + return SizeOfWord; + case '[': + if (SyntaxStack[i + 1][0] != tokNumInt && SyntaxStack[i + 1][0] != tokNumUint) + errorInternal(15); + i += 2; + break; + case tokStructPtr: + // follow the "type pointer" + i = SyntaxStack[i][1] - 1; + break; + case tokStruct: + case tokUnion: + if (i + 3 < SyntaxStackCnt && SyntaxStack[i + 2][0] == tokSizeof) + { + return SyntaxStack[i + 3][1]; + } + return 1; + case tokVoid: + return 1; + default: + errorInternal(16); + } + } + + errorInternal(17); + return 0; +} + +void DumpDecl(int SyntaxPtr, int IsParam) +{ +#ifndef NO_ANNOTATIONS + int i; + int icnt = 0; + + if (SyntaxPtr < 0) + return; + + for (i = SyntaxPtr; i < SyntaxStackCnt; i++) + { + int tok = SyntaxStack[i][0]; + int v = SyntaxStack[i][1]; + switch (tok) + { + case tokLocalOfs: + printf2("(@%d): ", truncInt(v)); + break; + + case tokIdent: + if (++icnt > 1 && !IsParam) // show at most one declaration, except params + return; + + GenStartCommentLine(); + + if (ParseLevel == 0) + printf2("glb "); + else if (IsParam) + printf2("prm "); + else + printf2("loc "); + + { + int j; + for (j = 0; j < ParseLevel * 4; j++) + printf2(" "); + } + + if (IsParam && !strcmp(IdentTable + v, "") && (i + 1 < SyntaxStackCnt)) + { + if (SyntaxStack[i + 1][0] == tokEllipsis) + continue; + } + + printf2("%s : ", IdentTable + v); + break; + + case '[': + printf2("["); + break; + + case tokNumInt: + printf2("%d", truncInt(v)); + break; + case tokNumUint: + printf2("%uu", truncUint(v)); + break; + + case ']': + printf2("] "); + break; + + case '(': + { + int noparams; + // Skip over the params to the base type + int j = ++i, c = 1; + while (c) + { + int t = SyntaxStack[j++][0]; + c += (t == '(') - (t == ')'); + } + + noparams = (i + 1 == j) || (SyntaxStack[i + 1][0] == tokVoid); + + printf2("("); + + // Print the params (recursively) + if (noparams) + { + // Don't recurse if it's "fxn()" or "fxn(void)" + if (i + 1 != j) + printf2("void"); + } + else + { + puts2(""); + ParseLevel++; + DumpDecl(i, 1); + ParseLevel--; + } + + // Continue normally + i = j - 1; + if (!noparams) + { + GenStartCommentLine(); + printf2(" "); + { + int j; + for (j = 0; j < ParseLevel * 4; j++) + printf2(" "); + } + } + + printf2(") "); + } + break; + + case ')': // end of param list + return; + + case tokStructPtr: + DumpDecl(v, 0); + break; + + default: + switch (tok) + { + case tokVoid: + case tokChar: + case tokSChar: + case tokUChar: +#ifdef CAN_COMPILE_32BIT + case tokShort: + case tokUShort: +#endif + case tokInt: + case tokUnsigned: + case tokEllipsis: + printf2("%s\n", GetTokenName(tok)); + break; + default: + printf2("%s ", GetTokenName(tok)); + break; + case tokTag: + printf2("%s\n", IdentTable + v); + return; + } + break; + } + } +#endif + (void)SyntaxPtr; + (void)IsParam; +} + +void DumpSynDecls(void) +{ +#ifndef NO_ANNOTATIONS + int used = SyntaxStackCnt * sizeof SyntaxStack[0]; + int total = SYNTAX_STACK_MAX * sizeof SyntaxStack[0]; + puts2(""); + GenStartCommentLine(); printf2("Syntax/declaration table/stack:\n"); + GenStartCommentLine(); printf2("Bytes used: %d/%d\n\n", used, total); +#endif +} + +int ParseArrayDimension(int AllowEmptyDimension) +{ + int tok; + int gotUnary, synPtr, constExpr, exprVal; + unsigned exprValU; + int oldssp, oldesp, undoIdents; + + tok = GetToken(); + // DONE: support arbitrary constant expressions + oldssp = SyntaxStackCnt; + oldesp = sp; + undoIdents = IdentTableLen; + tok = ParseExpr(tok, &gotUnary, &synPtr, &constExpr, &exprVal, 0, 0); + IdentTableLen = undoIdents; // remove all temporary identifier names from e.g. "sizeof" + SyntaxStackCnt = oldssp; // undo any temporary declarations from e.g. "sizeof" in the expression + sp = oldesp; + + if (tok != ']') + //error("ParseArrayDimension(): Unsupported or invalid array dimension (token %s)\n", GetTokenName(tok)); + errorUnexpectedToken(tok); + + if (!gotUnary) + { + if (!AllowEmptyDimension) + //error("ParseArrayDimension(): missing array dimension\n"); + errorUnexpectedToken(tok); + // Empty dimension is dimension of 0 + exprVal = 0; + } + else + { + if (!constExpr) + //error("ParseArrayDimension(): non-constant array dimension\n"); + errorNotConst(); + + exprValU = truncUint(exprVal); + exprVal = truncInt(exprVal); + + promoteType(&synPtr, &synPtr); + if ((SyntaxStack[synPtr][0] == tokInt && exprVal < 1) || (SyntaxStack[synPtr][0] == tokUnsigned && exprValU < 1)) + error("Array dimension less than 1\n"); + + exprVal = uint2int(exprValU); + } + + PushSyntax2(tokNumUint, exprVal); + return tok; +} + +void ParseFxnParams(int tok); +int ParseBlock(int BrkCntSwchTarget[4], int switchBody); +void AddFxnParamSymbols(int SyntaxPtr); + +int ParseBase(int tok, int base[2]) +{ +#ifndef NO_TYPEDEF_ENUM + int CurScope; +#endif + int valid = 1; + base[1] = 0; + + if (tok == tokVoid || + tok == tokChar || + tok == tokInt) + { + *base = tok; + tok = GetToken(); + } + else if (tok == tokShort +#ifdef CAN_COMPILE_32BIT + || tok == tokLong +#endif + ) + { + *base = tok; + tok = GetToken(); + if (tok == tokInt) + tok = GetToken(); + } + else if (tok == tokSigned || + tok == tokUnsigned) + { + int sign = tok; + tok = GetToken(); + + if (tok == tokChar) + { + if (sign == tokUnsigned) + *base = tokUChar; + else + *base = tokSChar; + tok = GetToken(); + } + else if (tok == tokShort) + { + if (sign == tokUnsigned) + *base = tokUShort; + else + *base = tokShort; + tok = GetToken(); + if (tok == tokInt) + tok = GetToken(); + } +#ifdef CAN_COMPILE_32BIT + else if (tok == tokLong) + { + if (sign == tokUnsigned) + *base = tokULong; + else + *base = tokLong; + tok = GetToken(); + if (tok == tokInt) + tok = GetToken(); + } +#endif + else + { + if (sign == tokUnsigned) + *base = tokUnsigned; + else + *base = tokInt; + if (tok == tokInt) + tok = GetToken(); + } + } + else if (tok == tokStruct || + tok == tokUnion +#ifndef NO_TYPEDEF_ENUM + || tok == tokEnum +#endif + ) + { + int structType = tok; + int empty = 1; + int typePtr = SyntaxStackCnt; + int gotTag = 0, tagIdent = 0, declPtr = -1, curScope = 0; + + tok = GetToken(); + + if (tok == tokIdent) + { + // this is a structure/union/enum tag + gotTag = 1; + declPtr = FindTaggedDecl(GetTokenIdentName(), SyntaxStackCnt - 1, &curScope); + tagIdent = AddIdent(GetTokenIdentName()); + + if (declPtr >= 0) + { + // Within the same scope we can't declare more than one union, structure or enum + // with the same tag. + // There's one common tag namespace for structures, unions and enumerations. + if (curScope && SyntaxStack[declPtr][0] != structType) + errorTagRedef(tagIdent); + } + else if (ParamLevel) + { + // structure/union/enum declarations aren't supported in function parameters + errorDecl(); + } + + tok = GetToken(); + } + else + { + // structure/union/enum declarations aren't supported in expressions + if (ExprLevel) + errorDecl(); + PushSyntax(structType); + PushSyntax2(tokTag, AddIdent("")); + } + + if (tok == '{') + { + unsigned structInfo[4], sz, alignment, tmp; + + // structure/union/enum declarations aren't supported in expressions and function parameters + if (ExprLevel || ParamLevel) + errorDecl(); + + if (gotTag) + { + // Cannot redefine a tagged structure/union/enum within the same scope + if (declPtr >= 0 && + curScope && + ((declPtr + 2 < SyntaxStackCnt && SyntaxStack[declPtr + 2][0] == tokSizeof) +#ifndef NO_TYPEDEF_ENUM + || structType == tokEnum +#endif + )) + errorTagRedef(tagIdent); + + PushSyntax(structType); + PushSyntax2(tokTag, tagIdent); + } + +#ifndef NO_TYPEDEF_ENUM + if (structType == tokEnum) + { + int val = 0; + int CurScope; + + tok = GetToken(); + while (tok != '}') + { + char* s; + int ident; + + if (tok != tokIdent) + errorUnexpectedToken(tok); + + s = GetTokenIdentName(); + if (FindTypedef(s, &CurScope, 0) >= 0 && CurScope) + errorRedef(s); + + ident = AddIdent(s); + + empty = 0; + + tok = GetToken(); + if (tok == '=') + { + int gotUnary, synPtr, constExpr; + int oldssp, oldesp, undoIdents; + + oldssp = SyntaxStackCnt; + oldesp = sp; + undoIdents = IdentTableLen; + + tok = ParseExpr(GetToken(), &gotUnary, &synPtr, &constExpr, &val, 1, 0); + + IdentTableLen = undoIdents; // remove all temporary identifier names from e.g. "sizeof" + SyntaxStackCnt = oldssp; // undo any temporary declarations from e.g. "sizeof" in the expression + sp = oldesp; + + if (!gotUnary) + errorUnexpectedToken(tok); + if (!constExpr) + errorNotConst(); + } + + PushSyntax2(tokIdent, ident); + PushSyntax2(tokNumInt, val); + val = uint2int(val + 1u); + + if (tok == ',') + tok = GetToken(); + else if (tok != '}') + errorUnexpectedToken(tok); + } + + if (empty) + errorDecl(); + + base[0] = tokEnumPtr; + base[1] = typePtr; + + tok = GetToken(); + return tok; + } + else +#endif + { + structInfo[0] = structType; + structInfo[1] = 1; // initial member alignment + structInfo[2] = 0; // initial member offset + structInfo[3] = 0; // initial max member size (for unions) + + PushSyntax(tokSizeof); // 0 = initial structure/union size, to be updated + PushSyntax2(tokSizeof, 1); // 1 = initial structure/union alignment, to be updated + + PushSyntax('{'); + + tok = GetToken(); + while (tok != '}') + { + if (!TokenStartsDeclaration(tok, 1)) + errorUnexpectedToken(tok); + tok = ParseDecl(tok, structInfo, 0, 0); + empty = 0; + } + + PushSyntax('}'); + + // Update structure/union alignment + alignment = structInfo[1]; + SyntaxStack[typePtr + 3][1] = alignment; + + // Update structure/union size and include trailing padding if needed + sz = structInfo[2] + structInfo[3]; + tmp = sz; + sz = (sz + alignment - 1) & ~(alignment - 1); + if (sz < tmp || sz != truncUint(sz)) + errorVarSize(); + SyntaxStack[typePtr + 2][1] = uint2int(sz); + + tok = GetToken(); + } + } + else + { +#ifndef NO_TYPEDEF_ENUM + if (structType == tokEnum) + { + if (!gotTag || declPtr < 0) + errorDecl(); // TBD!!! different error when enum tag is not found + + base[0] = tokEnumPtr; + base[1] = declPtr; + return tok; + } +#endif + + if (gotTag) + { + if (declPtr >= 0 && + SyntaxStack[declPtr][0] == structType) + { + base[0] = tokStructPtr; + base[1] = declPtr; + return tok; + } + + PushSyntax(structType); + PushSyntax2(tokTag, tagIdent); + + empty = 0; + } + } + + if (empty) + errorDecl(); + + base[0] = tokStructPtr; + base[1] = typePtr; + + // If we've just defined a structure/union and there are + // preceding references to this tag within this scope, + // IOW references to an incomplete type, complete the + // type in the references + if (gotTag && SyntaxStack[SyntaxStackCnt - 1][0] == '}') + { + int i; + for (i = SyntaxStackCnt - 1; i >= 0; i--) + if (SyntaxStack[i][0] == tokStructPtr) + { + int j = SyntaxStack[i][1]; + if (SyntaxStack[j + 1][1] == tagIdent) + SyntaxStack[i][1] = typePtr; + } + else if (SyntaxStack[i][0] == '#') + { + // reached the beginning of the current scope + break; + } + } + } +#ifndef NO_TYPEDEF_ENUM + else if (tok == tokIdent && + (base[1] = FindTypedef(GetTokenIdentName(), &CurScope, 1)) >= 0) + { + base[0] = tokTypedef; + tok = GetToken(); + } +#endif + else + { + valid = 0; + } + +#ifdef CAN_COMPILE_32BIT + if (SizeOfWord == 2 && + (*base == tokLong || *base == tokULong)) + valid = 0; + // to simplify matters, treat long and unsigned long as aliases for int and unsigned int + // in 32-bit and huge mode(l)s + if (*base == tokLong) + *base = tokInt; + if (*base == tokULong) + *base = tokUnsigned; +#endif + + if (SizeOfWord == 2) + { + // to simplify matters, treat short and unsigned short as aliases for int and unsigned int + // in 16-bit mode + if (*base == tokShort) + *base = tokInt; + if (*base == tokUShort) + *base = tokUnsigned; + } + + // TBD!!! review/test this fxn +// if (!valid || !tok || !(strchr("*([,)", tok) || tok == tokIdent)) + if (!valid || !tok) + //error("ParseBase(): Invalid or unsupported type\n"); + error("Invalid or unsupported type\n"); + + return tok; +} + +/* + base * name [] -> name : [] * base + base *2 (*1 name []1) []2 -> name : []1 *1 []2 *2 base + base *3 (*2 (*1 name []1) []2) []3 -> name : []1 *1 []2 *2 []3 *3 base +*/ + +int ParseDerived(int tok) +{ + int stars = 0; + int params = 0; + + while (tok == '*') + { + stars++; + tok = GetToken(); + } + + if (tok == '(') + { + tok = GetToken(); + if (tok != ')' && !TokenStartsDeclaration(tok, 1)) + { + tok = ParseDerived(tok); + if (tok != ')') + //error("ParseDerived(): ')' expected\n"); + errorUnexpectedToken(tok); + tok = GetToken(); + } + else + { + params = 1; + } + } + else if (tok == tokIdent) + { + PushSyntax2(tok, AddIdent(GetTokenIdentName())); + tok = GetToken(); + } + else + { + PushSyntax2(tokIdent, AddIdent("")); + } + + if (params || tok == '(') + { + int t = SyntaxStack[SyntaxStackCnt - 1][0]; + if (t == ')' || t == ']') + errorUnexpectedToken('('); // array of functions or function returning function + if (!params) + tok = GetToken(); + else + PushSyntax2(tokIdent, AddIdent("")); + PushSyntax('('); + ParseLevel++; + ParamLevel++; + ParseFxnParams(tok); + ParamLevel--; + ParseLevel--; + PushSyntax(')'); + tok = GetToken(); + } + else if (tok == '[') + { + // DONE!!! allow the first [] without the dimension in function parameters + int allowEmptyDimension = 1; + if (SyntaxStack[SyntaxStackCnt - 1][0] == ')') + errorUnexpectedToken('['); // function returning array + while (tok == '[') + { + int oldsp = SyntaxStackCnt; + PushSyntax(tokVoid); // prevent cases like "int arr[arr];" and "int arr[arr[0]];" + PushSyntax(tok); + tok = ParseArrayDimension(allowEmptyDimension); + if (tok != ']') + //error("ParseDerived(): ']' expected\n"); + errorUnexpectedToken(tok); + PushSyntax(']'); + tok = GetToken(); + DeleteSyntax(oldsp, 1); + allowEmptyDimension = 0; + } + } + + while (stars--) + PushSyntax('*'); + + if (!tok || !strchr(",;{=)", tok)) + //error("ParseDerived(): unexpected token %s\n", GetTokenName(tok)); + errorUnexpectedToken(tok); + + return tok; +} + +void PushBase(int base[2]) +{ +#ifndef NO_TYPEDEF_ENUM + if (base[0] == tokTypedef) + { + int ptr = base[1]; + int c = 0, copying = 1; + + while (copying) + { + int tok = SyntaxStack[++ptr][0]; + int t = SyntaxStack[SyntaxStackCnt - 1][0]; + + // Cannot have: + // function returning function + // array of functions + // function returning array + if (((t == ')' || t == ']') && tok == '(') || + (t == ')' && tok == '[')) + errorDecl(); + + PushSyntax2(tok, SyntaxStack[ptr][1]); + + c += (tok == '(') - (tok == ')') + (tok == '[') - (tok == ']'); + + if (!c) + { + switch (tok) + { + case tokVoid: + case tokChar: case tokSChar: case tokUChar: +#ifdef CAN_COMPILE_32BIT + case tokShort: case tokUShort: +#endif + case tokInt: case tokUnsigned: + case tokStructPtr: + copying = 0; + } + } + } + } + else +#endif + { + PushSyntax2(base[0], base[1]); + } + + // Cannot have array of void + if (SyntaxStack[SyntaxStackCnt - 1][0] == tokVoid && + SyntaxStack[SyntaxStackCnt - 2][0] == ']') + errorUnexpectedVoid(); +} + +// DONE: support extern +// DONE: support static +// DONE: support basic initialization +// DONE: support simple non-array initializations with string literals +// DONE: support basic 1-d array initialization +// DONE: global/static data allocations +int ParseDecl(int tok, unsigned structInfo[4], int cast, int label) +{ + int base[2]; + int lastSyntaxPtr; + int external = tok == tokExtern; + int Static = tok == tokStatic; +#ifndef NO_TYPEDEF_ENUM + int typeDef = tok == tokTypedef; +#endif + + if (external || +#ifndef NO_TYPEDEF_ENUM + typeDef || +#endif + Static) + { + tok = GetToken(); + if (!TokenStartsDeclaration(tok, 1)) + //error("ParseDecl(): unexpected token %s\n", GetTokenName(tok)); + errorUnexpectedToken(tok); + } + tok = ParseBase(tok, base); + +#ifndef NO_TYPEDEF_ENUM + if (label && tok == ':' && base[0] == tokTypedef && + !(external | Static | typeDef) && ParseLevel > 0) + { + // This is a label. + return tokGotoLabel; + } +#endif + + for (;;) + { + lastSyntaxPtr = SyntaxStackCnt; + + /* derived type */ + tok = ParseDerived(tok); + + /* base type */ + PushBase(base); + + if ((tok && strchr(",;{=", tok)) || (tok == ')' && ExprLevel)) + { + int localAllocSize = 0; + int globalAllocSize = 0; + int isFxn, isArray, isMultiDimArray, isIncompleteArr; + unsigned elementSz = 0; + unsigned alignment = 0; + + // Disallow void variables + if (SyntaxStack[SyntaxStackCnt - 1][0] == tokVoid) + { + if (SyntaxStack[SyntaxStackCnt - 2][0] == tokIdent && + !(cast +#ifndef NO_TYPEDEF_ENUM + || typeDef +#endif + )) + //error("ParseDecl(): Cannot declare a variable ('%s') of type 'void'\n", IdentTable + SyntaxStack[lastSyntaxPtr][1]); + errorUnexpectedVoid(); + } + + isFxn = SyntaxStack[lastSyntaxPtr + 1][0] == '('; + + if (isFxn && + SyntaxStack[SyntaxStackCnt - 1][0] == tokStructPtr && + SyntaxStack[SyntaxStackCnt - 2][0] == ')') + // structure returning isn't supported currently + errorDecl(); + + isArray = SyntaxStack[lastSyntaxPtr + 1][0] == '['; + isMultiDimArray = isArray && SyntaxStack[lastSyntaxPtr + 4][0] == '['; + isIncompleteArr = isArray && SyntaxStack[lastSyntaxPtr + 2][1] == 0; + + if (!ExprLevel && + !external && !Static && +#ifndef NO_TYPEDEF_ENUM + !typeDef && +#endif + !structInfo && + !strcmp(IdentTable + SyntaxStack[lastSyntaxPtr][1], "") && + tok == ';') + { + if (SyntaxStack[lastSyntaxPtr + 1][0] == tokStructPtr) + { + // This is either an incomplete tagged structure/union declaration, e.g. "struct sometag;", + // or a tagged complete structure/union declaration, e.g. "struct sometag { ... };", without an instance variable, + // or an untagged complete structure/union declaration, e.g. "struct { ... };", without an instance variable + int declPtr, curScope; + int j = SyntaxStack[lastSyntaxPtr + 1][1]; + + if (j + 2 < SyntaxStackCnt && + IdentTable[SyntaxStack[j + 1][1]] == '<' && // without tag + SyntaxStack[j + 2][0] == tokSizeof) // but with the {} "body" + errorDecl(); + + // If a structure/union with this tag has been declared in an outer scope, + // this new declaration should override it + declPtr = FindTaggedDecl(IdentTable + SyntaxStack[j + 1][1], lastSyntaxPtr - 1, &curScope); + if (declPtr >= 0 && !curScope) + { + // If that's the case, unbind this declaration from the old declaration + // and make it a new incomplete declaration + PushSyntax(SyntaxStack[j][0]); // tokStruct or tokUnion + PushSyntax2(tokTag, SyntaxStack[j + 1][1]); + SyntaxStack[lastSyntaxPtr + 1][1] = SyntaxStackCnt - 2; + } + return GetToken(); + } +#ifndef NO_TYPEDEF_ENUM + else if (SyntaxStack[lastSyntaxPtr + 1][0] == tokEnumPtr) + { + return GetToken(); + } +#endif + } + +#ifndef NO_TYPEDEF_ENUM + // Convert enums into ints + if (SyntaxStack[SyntaxStackCnt - 1][0] == tokEnumPtr) + { + SyntaxStack[SyntaxStackCnt - 1][0] = tokInt; + SyntaxStack[SyntaxStackCnt - 1][1] = 0; + } +#endif + + // Structure/union members can't be initialized nor be functions nor + // be incompletely typed arrays inside structure/union declarations + if (structInfo && (tok == '=' || isFxn || tok == '{' || isIncompleteArr)) + errorDecl(); + +#ifndef NO_TYPEDEF_ENUM + if (typeDef && (tok == '=' || tok == '{')) + errorDecl(); +#endif + + // Error conditions in declarations(/definitions/initializations): + // Legend: + // + error + // - no error + // + // file scope fxn fxn {} var arr[] arr[]...[] arr[incomplete] arr[incomplete]...[] + // - - - - - + + + // file scope fxn= var= arr[]= arr[]...[]= arr[incomplete]= arr[incomplete]...[]= + // + - - + - + + // file scope extern fxn fxn {} var arr[] arr[]...[] arr[incomplete] arr[incomplete]...[] + // - - - - - - - + // file scope extern fxn= var= arr[]= arr[]...[]= arr[incomplete]= arr[incomplete]...[]= + // + + + + + + + // file scope static fxn fxn {} var arr[] arr[]...[] arr[incomplete] arr[incomplete]...[] + // - - - - - + + + // file scope static fxn= var= arr[]= arr[]...[]= arr[incomplete]= arr[incomplete]...[]= + // + - - + - + + // fxn scope fxn fxn {} var arr[] arr[]...[] arr[incomplete] arr[incomplete]...[] + // - + - - - + + + // fxn scope fxn= var= arr[]= arr[]...[]= arr[incomplete]= arr[incomplete]...[]= + // + - + + + + + // fxn scope extern fxn fxn {} var arr[] arr[]...[] arr[incomplete] arr[incomplete]...[] + // - + - - - - - + // fxn scope extern fxn= var= arr[]= arr[]...[]= arr[incomplete]= arr[incomplete]...[]= + // + + + + + + + // fxn scope static fxn fxn {} var arr[] arr[]...[] arr[incomplete] arr[incomplete]...[] + // + + + + + + + + // fxn scope static fxn= var= arr[]= arr[]...[]= arr[incomplete]= arr[incomplete]...[]= + // + + + + + + + + if (isFxn && tok == '=') + //error("ParseDecl(): cannot initialize a function\n"); + errorInit(); + + if (isFxn && tok == '{' && ParseLevel) + //error("ParseDecl(): cannot define a nested function\n"); + errorDecl(); + + if (isFxn && Static && ParseLevel) + //error("ParseDecl(): cannot declare a static function in this scope\n"); + errorDecl(); + + if (external && tok == '=') + //error("ParseDecl(): cannot initialize an external variable\n"); + errorInit(); + + if (isIncompleteArr && !(external || +#ifndef NO_TYPEDEF_ENUM + typeDef || +#endif + tok == '=')) + //error("ParseDecl(): cannot define an array of incomplete type\n"); + errorDecl(); + + if (Static && ParseLevel) + //error("ParseDecl(): static not supported in this scope\n"); + errorDecl(); + + if (isMultiDimArray && tok == '=') + //error("ParseDecl(): multidimensional array initialization not supported\n"); + errorInit(); + + if (isArray && tok == '=' && ParseLevel) + //error("ParseDecl(): array initialization not supported in this scope\n"); + errorInit(); + + // TBD!!! de-uglify + if (!strcmp(IdentTable + SyntaxStack[lastSyntaxPtr][1], "")) + { + // Disallow nameless variables, prototypes, structure/union members and typedefs. + if (structInfo || +#ifndef NO_TYPEDEF_ENUM + typeDef || +#endif + !ExprLevel) + error("Identifier expected in declaration\n"); + } + else + { + // Disallow named variables and prototypes. + if (ExprLevel && !structInfo) + error("Identifier unexpected in declaration\n"); + } + + if (!isFxn +#ifndef NO_TYPEDEF_ENUM + && !typeDef +#endif + ) + { + int sz = GetDeclSize(lastSyntaxPtr, 0); + + if (!sz && !isIncompleteArr && !ExprLevel) // incomplete type + errorDecl(); // TBD!!! different error when struct/union tag is not found + + elementSz = sz; + if (isArray) + { + elementSz = GetDeclSize(lastSyntaxPtr + 4, 0); + if (!elementSz) // incomplete type of element (e.g. struct/union) + errorDecl(); + } + + alignment = GetDeclAlignment(lastSyntaxPtr); + + if (structInfo) + { + unsigned tmp; + unsigned newAlignment = alignment; +#ifndef NO_PPACK + if (alignment > PragmaPackValue + 0u) + newAlignment = PragmaPackValue; +#endif + // Update structure/union alignment + if (structInfo[1] < newAlignment) + structInfo[1] = newAlignment; + // Align structure member + tmp = structInfo[2]; + structInfo[2] = (structInfo[2] + newAlignment - 1) & ~(newAlignment - 1); + if (structInfo[2] < tmp || structInfo[2] != truncUint(structInfo[2])) + errorVarSize(); + // Change tokIdent to tokMemberIdent and insert a local var offset token + SyntaxStack[lastSyntaxPtr][0] = tokMemberIdent; + InsertSyntax2(lastSyntaxPtr + 1, tokLocalOfs, uint2int(structInfo[2])); + + // Advance member offset for structures, keep it zero for unions + if (structInfo[0] == tokStruct) + { + tmp = structInfo[2]; + structInfo[2] += sz; + if (structInfo[2] < tmp || structInfo[2] != truncUint(structInfo[2])) + errorVarSize(); + } + // Update max member size for unions + else if (structInfo[3] < sz + 0u) + { + structInfo[3] = sz; + } + } + else if (ParseLevel && !external && !Static && !ExprLevel) + { + int oldOfs; + // It's a local variable, let's calculate its relative on-stack location + oldOfs = CurFxnLocalOfs; + + // Note: local vars are word-aligned on the stack + CurFxnLocalOfs = uint2int((CurFxnLocalOfs + 0u - sz) & ~(SizeOfWord - 1u)); + if (CurFxnLocalOfs >= oldOfs || CurFxnLocalOfs != truncInt(CurFxnLocalOfs)) + //error("ParseDecl(): Local variables take too much space\n"); + errorVarSize(); +#ifdef CAN_COMPILE_32BIT + if (OutputFormat == FormatSegHuge && CurFxnLocalOfs < -0x7FFF) + errorVarSize(); +#endif + + // Insert a local var offset token + InsertSyntax2(lastSyntaxPtr + 1, tokLocalOfs, CurFxnLocalOfs); + + localAllocSize = oldOfs - CurFxnLocalOfs; + if (CurFxnMinLocalOfs > CurFxnLocalOfs) + CurFxnMinLocalOfs = CurFxnLocalOfs; + } + else + { + // It's a global variable + globalAllocSize = sz; + } + } + + if (!structInfo) + DumpDecl(lastSyntaxPtr, 0); + + if (ExprLevel && !structInfo) + return tok; + + if ((globalAllocSize || isIncompleteArr) && +#ifndef NO_TYPEDEF_ENUM + !typeDef && +#endif + !external) + { + if (OutputFormat != FormatFlat) + puts2(DataHeader); + // DONE: imperfect condition for alignment + if (alignment != 1) + GenWordAlignment(); + GenLabel(IdentTable + SyntaxStack[lastSyntaxPtr][1], Static); + } + +#ifndef NO_TYPEDEF_ENUM + if (typeDef) + { + int CurScope; + char* s = IdentTable + SyntaxStack[lastSyntaxPtr][1]; + SyntaxStack[lastSyntaxPtr][0] = 0; // hide tokIdent for now + if (FindTypedef(s, &CurScope, 0) >= 0 && CurScope) + errorRedef(s); + SyntaxStack[lastSyntaxPtr][0] = tokTypedef; // change tokIdent to tokTypedef + } + else + // fallthrough +#endif + if (external && !(isFxn && tok == '{')) + { + } + // Handle initialization + else if (tok == '=') + { + int gotUnary, synPtr, constExpr, exprVal; + int p, p2; + int oldssp, undoIdents; + int braces = 0; + unsigned elementCnt = 0; + unsigned elementsRequired = 0; + int strLitAllowed = 1; + int nonStrLitAllowed = 1; + int arrOfChar = isArray && elementSz == 1; +#ifndef NO_ANNOTATIONS + GenStartCommentLine(); printf2("=\n"); +#endif + + p = lastSyntaxPtr; + while (SyntaxStack[p][0] == tokIdent || SyntaxStack[p][0] == tokLocalOfs) + p++; + + // explicit structure/union initialization with '=' isn't supported + p2 = p; + while (SyntaxStack[p2][0] == '[') + p2 += 3; + if (SyntaxStack[p2][0] == tokStructPtr) + errorInit(); + + oldssp = SyntaxStackCnt; + undoIdents = IdentTableLen; + + if (isArray) + elementsRequired = SyntaxStack[p + 1][1]; + + tok = GetToken(); + // Interestingly, scalars can be legally initialized with braced + // initializers just like arrays, e.g. "int a = { 1 };". + // Also, "int i[];" must have 1 element. + // Let's not support that! + if (isArray && tok == '{') + { + braces = 1; + tok = GetToken(); + } + + PurgeStringTable(); + KeepStringTable = 1; + + for (;;) + { + int strLitInitializer; + + if (braces && tok == '}') + { + tok = GetToken(); + if (!tok || !strchr(",;", tok)) + //error("ParseDecl(): unexpected token %s\n", GetTokenName(tok)); + errorUnexpectedToken(tok); + break; + } + + tok = ParseExpr(tok, &gotUnary, &synPtr, &constExpr, &exprVal, 1, 0); + if (!gotUnary) + //error("ParseDecl(): missing initialization expression\n"); + errorUnexpectedToken(tok); + + scalarTypeCheck(synPtr); + + if (!tok || + (braces && !strchr(",}", tok)) || + (!braces && !strchr(",;", tok))) + //error("ParseDecl(): unexpected token %s\n", GetTokenName(tok)); + errorUnexpectedToken(tok); + + strLitInitializer = stack[sp - 1][0] == tokIdent && + isdigit(IdentTable[stack[sp - 1][1]]); + + // Prohibit initializers like in "int a[1] = 1;" and "char* a[1] = "abc";" + if (isArray && !braces && (!strLitInitializer || !arrOfChar)) + //error("ParseDecl(): array initializers must be in braces\n"); + errorInit(); + + // Prohibit the following character array initializations: + // char a[] = { 'a', "b" }; + // char a[] = { "a", 'b' }; + // char a[] = { "a", "b" }; + if (arrOfChar) + { + if (!strLitInitializer) + strLitAllowed = 0; + else + nonStrLitAllowed = 0; + if ((strLitInitializer && !strLitAllowed) || + (!strLitInitializer && !nonStrLitAllowed)) + //error("ParseDecl(): invalid initialization\n"); + errorInit(); + if (strLitInitializer) + strLitAllowed = 0; + } + + elementCnt++; + + if (braces && elementsRequired && elementCnt > elementsRequired) + error("Too many array initializers\n"); + + if (!ParseLevel) + { + if (constExpr) + { + GenIntData(elementSz, exprVal); + } + else if (elementSz == SizeOfWord + 0u && stack[sp - 1][0] == tokIdent) + { + GenAddrData(elementSz, IdentTable + stack[sp - 1][1]); + // Defer storage of string literal data (if any) until the end. + // This will let us generate the contiguous array of pointers to + // string literals unperturbed by the string literal data + // (e.g. "char* colors[] = { "red", "green", "blue" };"). + } + else if (arrOfChar && strLitInitializer) + { + // Defer storage of string literal data until the end. + // Now simply remember that the character array has buffered string data. + arrOfChar++; + } + else + //error("ParseDecl(): cannot initialize a global variable with a non-constant expression\n"); + errorNotConst(); + } + else + { + //error("ParseDecl(): cannot initialize a variable with a 'void' expression\n"); + nonVoidTypeCheck(synPtr); + // transform the current expression stack into: + // tokLocalOfs(...), original expression stack, =(localAllocSize) + // this will simulate assignment + ins2(0, tokLocalOfs, SyntaxStack[lastSyntaxPtr + 1][1]); + push2('=', localAllocSize); // TBD??? should use elementSz instead? + // Storage of string literal data from the initializing expression + // occurs here. + GenExpr(); + } + + if (braces) + { + if (tok == ',') + tok = GetToken(); + } + else + break; + } // for (;;) + + if (!ParseLevel) + { + if (arrOfChar == 2) + elementCnt = GenStrData(0, elementsRequired); + + if (isArray) + { + // Implicit initialization with 0 of what's not initialized explicitly + if (elementCnt < elementsRequired) + GenZeroData((elementsRequired - elementCnt) * elementSz); + + // The number of elements is now known + if (isIncompleteArr) + SyntaxStack[p + 1][1] = elementCnt; + } + + if (!arrOfChar) + { + int lab; + char s[1 + (2 + CHAR_BIT * sizeof lab) / 3]; + int i = 0; + + // Construct an expression for each buffered string for GenStrData() + sp = 1; + stack[0][0] = tokIdent; + + // Dump all buffered strings, one by one, the ugly way + while (i < StringTableLen) + { + char *p = s + sizeof s; + + lab = StringTable[i] & 0xFF; + lab += (StringTable[i + 1] & 0xFFu) << 8; + + // Reconstruct the identifier for the definition: char #[len] = "..."; + *--p = '\0'; + p = lab2str(p, lab); + stack[0][1] = AddIdent(p); + + GenStrData(0, 0); + + // Drop the identifier from the identifier table so as not to + // potentially overflow it when there are many initializing + // string literals and the table is nearly full. + IdentTableLen = undoIdents; // remove all temporary identifier names from e.g. "sizeof" or "str" + + i += 2; + i += 1 + StringTable[i]; + } + } + } + + PurgeStringTable(); + KeepStringTable = 0; + + if (!ParseLevel && OutputFormat != FormatFlat) + puts2(DataFooter); + + IdentTableLen = undoIdents; // remove all temporary identifier names from e.g. "sizeof" or "str" + SyntaxStackCnt = oldssp; // undo any temporary declarations from e.g. "sizeof" or "str" in the expression + } + else if (globalAllocSize) + { + GenZeroData(globalAllocSize); + if (OutputFormat != FormatFlat) + puts2(DataFooter); + } + else if (tok == '{') + { + // It's a function body. Let's add function parameters as + // local variables to the symbol table and parse the body. + int undoSymbolsPtr = SyntaxStackCnt; + int undoIdents = IdentTableLen; + int locAllocLabel = (LabelCnt += 2) - 2; + int i; + int Main; + + CurFxnName = IdentTable + SyntaxStack[lastSyntaxPtr][1]; + Main = !strcmp(CurFxnName, "main"); + + gotoLabCnt = 0; + + if (verbose && OutFile) + printf("%s()\n", CurFxnName); + + ParseLevel++; + GetFxnInfo(lastSyntaxPtr, &CurFxnParamCntMin, &CurFxnParamCntMax, &CurFxnReturnExprTypeSynPtr); // get return type + + if (OutputFormat != FormatFlat) + puts2(CodeHeader); + + GenLabel(IdentTable + SyntaxStack[lastSyntaxPtr][1], Static); + CurFxnEpilogLabel = LabelCnt++; + GenFxnProlog(); + GenJumpUncond(locAllocLabel + 1); + GenNumLabel(locAllocLabel); + + AddFxnParamSymbols(lastSyntaxPtr); + +#ifndef NO_FUNC_ + { + char s[1 + 2 + (2 + CHAR_BIT * sizeof CurFxnNameLabel) / 3]; + char *p = s + sizeof s; + CurFxnNameLabel = LabelCnt++; + *--p = '\0'; + p = lab2str(p, CurFxnNameLabel); + *--p = '_'; + *--p = '_'; + SyntaxStack[SymFuncPtr][1] = AddIdent(p); + SyntaxStack[SymFuncPtr + 2][1] = strlen(CurFxnName) + 1; + } +#endif + +#ifdef CAN_COMPILE_32BIT + if (MainPrologCtorFxn && + Main && + OutputFormat == FormatSegmented && SizeOfWord == 4) + { + sp = 0; + push('('); + push2(tokIdent, AddIdent(MainPrologCtorFxn)); + push(')'); + GenExpr(); + } +#endif + + tok = ParseBlock(NULL, 0); + ParseLevel--; + if (tok != '}') + //error("ParseDecl(): '}' expected\n"); + errorUnexpectedToken(tok); + + for (i = 0; i < gotoLabCnt; i++) + if (gotoLabStat[i] == 2) + error("Undeclared label '%s'\n", IdentTable + gotoLabels[i][0]); + + // DONE: if execution of main() reaches here, before the epilog (i.e. without using return), + // main() should return 0. + if (Main) + { + sp = 0; + push(tokNumInt); + GenExpr(); + } + + GenNumLabel(CurFxnEpilogLabel); + GenFxnEpilog(); + GenNumLabel(locAllocLabel + 1); + if (CurFxnMinLocalOfs) + GenLocalAlloc(-CurFxnMinLocalOfs); + GenJumpUncond(locAllocLabel); + if (OutputFormat != FormatFlat) + puts2(CodeFooter); + +#ifndef NO_FUNC_ + if (CurFxnNameLabel < 0) + { + PurgeStringTable(); + AddString(-CurFxnNameLabel, CurFxnName, SyntaxStack[SymFuncPtr + 2][1]); + + if (OutputFormat != FormatFlat) + puts2(DataHeader); + + GenLabel(IdentTable + SyntaxStack[SymFuncPtr][1], 1); + + sp = 1; + stack[0][0] = tokIdent; + stack[0][1] = SyntaxStack[SymFuncPtr][1] + 2; + GenStrData(0, 0); + + if (OutputFormat != FormatFlat) + puts2(DataFooter); + + CurFxnNameLabel = 0; + } +#endif + + CurFxnName = NULL; + IdentTableLen = undoIdents; // remove all identifier names + SyntaxStackCnt = undoSymbolsPtr; // remove all params and locals + } + + if (tok == ';' || tok == '}') + break; + + tok = GetToken(); + continue; + } + + //error("ParseDecl(): unexpected token %s\n", GetTokenName(tok)); + errorUnexpectedToken(tok); + } + + tok = GetToken(); + return tok; +} + +void ParseFxnParams(int tok) +{ + int base[2]; + int lastSyntaxPtr; + int cnt = 0; + int ellCnt = 0; + + for (;;) + { + lastSyntaxPtr = SyntaxStackCnt; + + if (tok == ')') /* unspecified params */ + break; + + if (!TokenStartsDeclaration(tok, 1)) + { + if (tok == tokEllipsis) + { + // "..." cannot be the first parameter and + // it can be only one + if (!cnt || ellCnt) + //error("ParseFxnParams(): '...' unexpected here\n"); + errorUnexpectedToken(tok); + ellCnt++; + } + else + //error("ParseFxnParams(): Unexpected token %s\n", GetTokenName(tok)); + errorUnexpectedToken(tok); + base[0] = tok; // "..." + base[1] = 0; + PushSyntax2(tokIdent, AddIdent("")); + tok = GetToken(); + } + else + { + if (ellCnt) + //error("ParseFxnParams(): '...' must be the last in the parameter list\n"); + errorUnexpectedToken(tok); + + /* base type */ + tok = ParseBase(tok, base); + + /* derived type */ + tok = ParseDerived(tok); + } + + /* base type */ + PushBase(base); + +#ifndef NO_TYPEDEF_ENUM + // Convert enums into ints + if (SyntaxStack[SyntaxStackCnt - 1][0] == tokEnumPtr) + { + SyntaxStack[SyntaxStackCnt - 1][0] = tokInt; + SyntaxStack[SyntaxStackCnt - 1][1] = 0; + } +#endif + + /* Decay arrays to pointers */ + lastSyntaxPtr++; /* skip name */ + if (SyntaxStack[lastSyntaxPtr][0] == '[') + { + int t; + DeleteSyntax(lastSyntaxPtr, 1); + t = SyntaxStack[lastSyntaxPtr][0]; + if (t == tokNumInt || t == tokNumUint) + DeleteSyntax(lastSyntaxPtr, 1); + SyntaxStack[lastSyntaxPtr][0] = '*'; + } + /* "(Un)decay" functions to function pointers */ + else if (SyntaxStack[lastSyntaxPtr][0] == '(') + { + InsertSyntax(lastSyntaxPtr, '*'); + } + lastSyntaxPtr--; /* "unskip" name */ + + cnt++; + + if (tok == ')' || tok == ',') + { + int t = SyntaxStack[SyntaxStackCnt - 2][0]; + if (SyntaxStack[SyntaxStackCnt - 1][0] == tokVoid) + { + // Disallow void variables. TBD!!! de-uglify + if (t == tokIdent && + !(!strcmp(IdentTable + SyntaxStack[SyntaxStackCnt - 2][1], "") && + cnt == 1 && tok == ')')) + //error("ParseFxnParams(): Cannot declare a variable ('%s') of type 'void'\n", IdentTable + SyntaxStack[lastSyntaxPtr][1]); + errorUnexpectedVoid(); + } + + if (SyntaxStack[SyntaxStackCnt - 1][0] == tokStructPtr && + t != '*' && + t != ']') + // structure passing and returning isn't supported currently + errorDecl(); + + if (tok == ')') + break; + + tok = GetToken(); + continue; + } + + //error("ParseFxnParams(): Unexpected token %s\n", GetTokenName(tok)); + errorUnexpectedToken(tok); + } +} + +void AddFxnParamSymbols(int SyntaxPtr) +{ + int i; + + if (SyntaxPtr < 0 || + SyntaxPtr > SyntaxStackCnt - 3 || + SyntaxStack[SyntaxPtr][0] != tokIdent || + SyntaxStack[SyntaxPtr + 1][0] != '(') + //error("Internal error: AddFxnParamSymbols(): Invalid input\n"); + errorInternal(6); + + CurFxnSyntaxPtr = SyntaxPtr; + CurFxnParamCnt = 0; + CurFxnParamOfs = 2 * SizeOfWord; // ret addr, xbp + CurFxnLocalOfs = 0; + CurFxnMinLocalOfs = 0; + + SyntaxPtr += 2; // skip "ident(" + + for (i = SyntaxPtr; i < SyntaxStackCnt; i++) + { + int tok = SyntaxStack[i][0]; + + if (tok == tokIdent) + { + int sz; + int paramPtr; + + if (i + 1 >= SyntaxStackCnt) + //error("Internal error: AddFxnParamSymbols(): Invalid input\n"); + errorInternal(7); + + if (SyntaxStack[i + 1][0] == tokVoid) // "ident(void)" = no params + break; + if (SyntaxStack[i + 1][0] == tokEllipsis) // "ident(something,...)" = no more params + break; + + sz = GetDeclSize(i, 0); + if (sz == 0) + //error("Internal error: AddFxnParamSymbols(): GetDeclSize() = 0\n"); + errorInternal(8); + + // Let's calculate this parameter's relative on-stack location + CurFxnParamOfs = (CurFxnParamOfs + SizeOfWord - 1) / SizeOfWord * SizeOfWord; + paramPtr = SyntaxStackCnt; + PushSyntax2(SyntaxStack[i][0], SyntaxStack[i][1]); + PushSyntax2(tokLocalOfs, CurFxnParamOfs); + CurFxnParamOfs += sz; + + // Duplicate this parameter in the symbol table + i++; + while (i < SyntaxStackCnt) + { + tok = SyntaxStack[i][0]; + if (tok == tokIdent || tok == ')') + { + CurFxnParamCnt++; + DumpDecl(paramPtr, 0); + i--; + break; + } + else if (tok == '(') + { + int c = 1; + i++; + PushSyntax(tok); + while (c && i < SyntaxStackCnt) + { + tok = SyntaxStack[i][0]; + c += (tok == '(') - (tok == ')'); + PushSyntax2(SyntaxStack[i][0], SyntaxStack[i][1]); + i++; + } + } + else + { + PushSyntax2(SyntaxStack[i][0], SyntaxStack[i][1]); + i++; + } + } + } + else if (tok == ')') // endof "ident(" ... ")" + break; + else + //error("Internal error: AddFxnParamSymbols(): Unexpected token %s\n", GetTokenName(tok)); + errorInternal(9); + } +} + +int ParseStatement(int tok, int BrkCntSwchTarget[4], int switchBody) +{ +/* + labeled statements: + + ident : statement + + case const-expr : statement + + default : statement + + compound statement: + + { declaration(s)/statement(s)-opt } + + expression statement: + + expression-opt ; + + selection statements: + + if ( expression ) statement + + if ( expression ) statement else statement + + switch ( expression ) { statement(s)-opt } + + iteration statements: + + while ( expression ) statement + + do statement while ( expression ) ; + + for ( expression-opt ; expression-opt ; expression-opt ) statement + + jump statements: + + goto ident ; + + continue ; + + break ; + + return expression-opt ; +*/ + int gotUnary, synPtr, constExpr, exprVal; + int brkCntSwchTarget[4]; + int statementNeeded; + + do + { + statementNeeded = 0; + + if (tok == ';') + { + tok = GetToken(); + } + else if (tok == '{') + { + // A new {} block begins in the function body + int undoSymbolsPtr = SyntaxStackCnt; + int undoLocalOfs = CurFxnLocalOfs; + int undoIdents = IdentTableLen; +#ifndef NO_ANNOTATIONS + GenStartCommentLine(); printf2("{\n"); +#endif + ParseLevel++; + tok = ParseBlock(BrkCntSwchTarget, switchBody / 2); + ParseLevel--; + if (tok != '}') + //error("ParseStatement(): '}' expected. Unexpected token %s\n", GetTokenName(tok)); + errorUnexpectedToken(tok); + UndoNonLabelIdents(undoIdents); // remove all identifier names, except those of labels + SyntaxStackCnt = undoSymbolsPtr; // remove all params and locals + CurFxnLocalOfs = undoLocalOfs; // destroy on-stack local variables +#ifndef NO_ANNOTATIONS + GenStartCommentLine(); printf2("}\n"); +#endif + tok = GetToken(); + } + else if (tok == tokReturn) + { + // DONE: functions returning void vs non-void + // TBD??? functions returning void should be able to return void + // return values from other functions returning void + int retVoid = CurFxnReturnExprTypeSynPtr >= 0 && + SyntaxStack[CurFxnReturnExprTypeSynPtr][0] == tokVoid; +#ifndef NO_ANNOTATIONS + GenStartCommentLine(); printf2("return\n"); +#endif + tok = GetToken(); + if (tok == ';') + { + gotUnary = 0; + if (!retVoid) + //error("ParseStatement(): missing return value\n"); + errorUnexpectedToken(tok); + } + else + { + if (retVoid) + //error("Error: ParseStatement(): cannot return a value from a function returning 'void'\n"); + errorUnexpectedToken(tok); + if ((tok = ParseExpr(tok, &gotUnary, &synPtr, &constExpr, &exprVal, 0, 0)) != ';') + //error("ParseStatement(): ';' expected\n"); + errorUnexpectedToken(tok); + if (gotUnary) + //error("ParseStatement(): cannot return a value of type 'void'\n"); + scalarTypeCheck(synPtr); + } + if (gotUnary) + GenExpr(); + GenJumpUncond(CurFxnEpilogLabel); + tok = GetToken(); + } + else if (tok == tokWhile) + { + int labelBefore = LabelCnt++; + int labelAfter = LabelCnt++; +#ifndef NO_ANNOTATIONS + GenStartCommentLine(); printf2("while\n"); +#endif + + tok = GetToken(); + if (tok != '(') + //error("ParseStatement(): '(' expected after 'while'\n"); + errorUnexpectedToken(tok); + + tok = GetToken(); + if ((tok = ParseExpr(tok, &gotUnary, &synPtr, &constExpr, &exprVal, 0, 0)) != ')') + //error("ParseStatement(): ')' expected after 'while ( expression'\n"); + errorUnexpectedToken(tok); + + if (!gotUnary) + //error("ParseStatement(): expression expected in 'while ( expression )'\n"); + errorUnexpectedToken(tok); + + // DONE: void control expressions + //error("ParseStatement(): unexpected 'void' expression in 'while ( expression )'\n"); + scalarTypeCheck(synPtr); + + GenNumLabel(labelBefore); + + switch (stack[sp - 1][0]) + { + case '<': + case '>': + case tokEQ: + case tokNEQ: + case tokLEQ: + case tokGEQ: + case tokULess: + case tokUGreater: + case tokULEQ: + case tokUGEQ: + push2(tokIfNot, labelAfter); + GenExpr(); + break; + default: + GenExpr(); + GenJumpIfZero(labelAfter); + break; + } + + tok = GetToken(); + brkCntSwchTarget[0] = labelAfter; // break target + brkCntSwchTarget[1] = labelBefore; // continue target + tok = ParseStatement(tok, brkCntSwchTarget, 0); + + GenJumpUncond(labelBefore); + GenNumLabel(labelAfter); + } + else if (tok == tokDo) + { + int labelBefore = LabelCnt++; + int labelWhile = LabelCnt++; + int labelAfter = LabelCnt++; +#ifndef NO_ANNOTATIONS + GenStartCommentLine(); printf2("do\n"); +#endif + GenNumLabel(labelBefore); + + tok = GetToken(); + brkCntSwchTarget[0] = labelAfter; // break target + brkCntSwchTarget[1] = labelWhile; // continue target + tok = ParseStatement(tok, brkCntSwchTarget, 0); + if (tok != tokWhile) + //error("ParseStatement(): 'while' expected after 'do statement'\n"); + errorUnexpectedToken(tok); + +#ifndef NO_ANNOTATIONS + GenStartCommentLine(); printf2("while\n"); +#endif + tok = GetToken(); + if (tok != '(') + //error("ParseStatement(): '(' expected after 'while'\n"); + errorUnexpectedToken(tok); + + tok = GetToken(); + if ((tok = ParseExpr(tok, &gotUnary, &synPtr, &constExpr, &exprVal, 0, 0)) != ')') + //error("ParseStatement(): ')' expected after 'while ( expression'\n"); + errorUnexpectedToken(tok); + + if (!gotUnary) + //error("ParseStatement(): expression expected in 'while ( expression )'\n"); + errorUnexpectedToken(tok); + + tok = GetToken(); + if (tok != ';') + //error("ParseStatement(): ';' expected after 'do statement while ( expression )'\n"); + errorUnexpectedToken(tok); + + // DONE: void control expressions + //error("ParseStatement(): unexpected 'void' expression in 'while ( expression )'\n"); + scalarTypeCheck(synPtr); + + GenNumLabel(labelWhile); + + switch (stack[sp - 1][0]) + { + case '<': + case '>': + case tokEQ: + case tokNEQ: + case tokLEQ: + case tokGEQ: + case tokULess: + case tokUGreater: + case tokULEQ: + case tokUGEQ: + push2(tokIf, labelBefore); + GenExpr(); + break; + default: + GenExpr(); + GenJumpIfNotZero(labelBefore); + break; + } + + GenNumLabel(labelAfter); + + tok = GetToken(); + } + else if (tok == tokIf) + { + int labelAfterIf = LabelCnt++; + int labelAfterElse = LabelCnt++; +#ifndef NO_ANNOTATIONS + GenStartCommentLine(); printf2("if\n"); +#endif + + tok = GetToken(); + if (tok != '(') + //error("ParseStatement(): '(' expected after 'if'\n"); + errorUnexpectedToken(tok); + + tok = GetToken(); + if ((tok = ParseExpr(tok, &gotUnary, &synPtr, &constExpr, &exprVal, 0, 0)) != ')') + //error("ParseStatement(): ')' expected after 'if ( expression'\n"); + errorUnexpectedToken(tok); + + if (!gotUnary) + //error("ParseStatement(): expression expected in 'if ( expression )'\n"); + errorUnexpectedToken(tok); + + // DONE: void control expressions + //error("ParseStatement(): unexpected 'void' expression in 'if ( expression )'\n"); + scalarTypeCheck(synPtr); + + switch (stack[sp - 1][0]) + { + case '<': + case '>': + case tokEQ: + case tokNEQ: + case tokLEQ: + case tokGEQ: + case tokULess: + case tokUGreater: + case tokULEQ: + case tokUGEQ: + push2(tokIfNot, labelAfterIf); + GenExpr(); + break; + default: + GenExpr(); + GenJumpIfZero(labelAfterIf); + break; + } + + tok = GetToken(); + tok = ParseStatement(tok, BrkCntSwchTarget, 0); + + // DONE: else + if (tok == tokElse) + { + GenJumpUncond(labelAfterElse); + GenNumLabel(labelAfterIf); +#ifndef NO_ANNOTATIONS + GenStartCommentLine(); printf2("else\n"); +#endif + tok = GetToken(); + tok = ParseStatement(tok, BrkCntSwchTarget, 0); + GenNumLabel(labelAfterElse); + } + else + { + GenNumLabel(labelAfterIf); + } + } + else if (tok == tokFor) + { + int labelBefore = LabelCnt++; + int labelExpr3 = LabelCnt++; + int labelBody = LabelCnt++; + int labelAfter = LabelCnt++; +#ifndef NO_ANNOTATIONS + GenStartCommentLine(); printf2("for\n"); +#endif + tok = GetToken(); + if (tok != '(') + //error("ParseStatement(): '(' expected after 'for'\n"); + errorUnexpectedToken(tok); + + tok = GetToken(); + if ((tok = ParseExpr(tok, &gotUnary, &synPtr, &constExpr, &exprVal, 0, 0)) != ';') + //error("ParseStatement(): ';' expected after 'for ( expression'\n"); + errorUnexpectedToken(tok); + if (gotUnary) + { + GenExpr(); + } + + GenNumLabel(labelBefore); + tok = GetToken(); + if ((tok = ParseExpr(tok, &gotUnary, &synPtr, &constExpr, &exprVal, 0, 0)) != ';') + //error("ParseStatement(): ';' expected after 'for ( expression ; expression'\n"); + errorUnexpectedToken(tok); + if (gotUnary) + { + // DONE: void control expressions + //error("ParseStatement(): unexpected 'void' expression in 'for ( ; expression ; )'\n"); + scalarTypeCheck(synPtr); + + switch (stack[sp - 1][0]) + { + case '<': + case '>': + case tokEQ: + case tokNEQ: + case tokLEQ: + case tokGEQ: + case tokULess: + case tokUGreater: + case tokULEQ: + case tokUGEQ: + push2(tokIfNot, labelAfter); + GenExpr(); + break; + default: + GenExpr(); + GenJumpIfZero(labelAfter); + break; + } + } + GenJumpUncond(labelBody); + + GenNumLabel(labelExpr3); + tok = GetToken(); + if ((tok = ParseExpr(tok, &gotUnary, &synPtr, &constExpr, &exprVal, 0, 0)) != ')') + //error("ParseStatement(): ')' expected after 'for ( expression ; expression ; expression'\n"); + errorUnexpectedToken(tok); + if (gotUnary) + { + GenExpr(); + } + GenJumpUncond(labelBefore); + + GenNumLabel(labelBody); + tok = GetToken(); + brkCntSwchTarget[0] = labelAfter; // break target + brkCntSwchTarget[1] = labelExpr3; // continue target + tok = ParseStatement(tok, brkCntSwchTarget, 0); + GenJumpUncond(labelExpr3); + + GenNumLabel(labelAfter); + } + else if (tok == tokBreak) + { +#ifndef NO_ANNOTATIONS + GenStartCommentLine(); printf2("break\n"); +#endif + if ((tok = GetToken()) != ';') + //error("ParseStatement(): ';' expected\n"); + errorUnexpectedToken(tok); + tok = GetToken(); + if (BrkCntSwchTarget == NULL) + //error("ParseStatement(): 'break' must be within 'while', 'for' or 'switch' statement\n"); + errorCtrlOutOfScope(); + GenJumpUncond(BrkCntSwchTarget[0]); + } + else if (tok == tokCont) + { +#ifndef NO_ANNOTATIONS + GenStartCommentLine(); printf2("continue\n"); +#endif + if ((tok = GetToken()) != ';') + //error("ParseStatement(): ';' expected\n"); + errorUnexpectedToken(tok); + tok = GetToken(); + if (BrkCntSwchTarget == NULL || BrkCntSwchTarget[1] == 0) + //error("ParseStatement(): 'continue' must be within 'while' or 'for' statement\n"); + errorCtrlOutOfScope(); + GenJumpUncond(BrkCntSwchTarget[1]); + } + else if (tok == tokSwitch) + { +#ifndef NO_ANNOTATIONS + GenStartCommentLine(); printf2("switch\n"); +#endif + + tok = GetToken(); + if (tok != '(') + //error("ParseStatement(): '(' expected after 'switch'\n"); + errorUnexpectedToken(tok); + + tok = GetToken(); + if ((tok = ParseExpr(tok, &gotUnary, &synPtr, &constExpr, &exprVal, 0, 0)) != ')') + //error("ParseStatement(): ')' expected after 'switch ( expression'\n"); + errorUnexpectedToken(tok); + + if (!gotUnary) + //error("ParseStatement(): expression expected in 'switch ( expression )'\n"); + errorUnexpectedToken(tok); + + // DONE: void control expressions + //error("ParseStatement(): unexpected 'void' expression in 'switch ( expression )'\n"); + scalarTypeCheck(synPtr); + + GenExpr(); + + tok = GetToken(); + if (tok != '{') + //error("ParseStatement(): '{' expected after 'switch ( expression )'\n"); + errorUnexpectedToken(tok); + + brkCntSwchTarget[0] = LabelCnt++; // break target + brkCntSwchTarget[1] = 0; // continue target + if (BrkCntSwchTarget) + { + // preserve the continue target + brkCntSwchTarget[1] = BrkCntSwchTarget[1]; // continue target + } + brkCntSwchTarget[2] = LabelCnt++; // default target + brkCntSwchTarget[3] = (LabelCnt += 2) - 2; // next case target +/* + ParseBlock(0) + ParseStatement(0) + switch + ParseStatement(2) // 2 needed to disallow new locals + { // { in switch(expr){ + ParseBlock(1) // new locals are allocated here + ParseStatement(1) // 1 needed for case/default + { // inner {} in switch(expr){{}} + ParseBlock(0) + ... + switch // another switch + ParseStatement(2) // needed to disallow new locals + ... +*/ + GenJumpUncond(brkCntSwchTarget[3]); // next case target + + tok = ParseStatement(tok, brkCntSwchTarget, 2); + + // force 'break' if the last 'case'/'default' doesn't end with 'break' + GenJumpUncond(brkCntSwchTarget[0]); + + // next, non-existent case (reached after none of the 'cases' have matched) + GenNumLabel(brkCntSwchTarget[3]); + + // if there's 'default', 'goto default;' after all unmatched 'cases' + if (brkCntSwchTarget[2] < 0) + GenJumpUncond(-brkCntSwchTarget[2]); + + GenNumLabel(brkCntSwchTarget[0]); // break label + } + else if (tok == tokCase) + { + int lnext; +#ifndef NO_ANNOTATIONS + GenStartCommentLine(); printf2("case\n"); +#endif + + if (!switchBody) + //error("ParseStatement(): 'case' must be within 'switch' statement\n"); + errorCtrlOutOfScope(); + + tok = GetToken(); + if ((tok = ParseExpr(tok, &gotUnary, &synPtr, &constExpr, &exprVal, 0, 0)) != ':') + //error("ParseStatement(): ':' expected after 'case expression'\n"); + errorUnexpectedToken(tok); + + if (!gotUnary || !constExpr || (synPtr >= 0 && SyntaxStack[synPtr][0] == tokVoid)) // TBD??? + //error("ParseStatement(): constant integer expression expected in 'case expression :'\n"); + errorNotConst(); + + tok = GetToken(); + + lnext = (LabelCnt += 2) - 2; + + GenJumpUncond(BrkCntSwchTarget[3] + 1); // fallthrough + GenNumLabel(BrkCntSwchTarget[3]); + GenJumpIfNotEqual(exprVal, lnext); + GenNumLabel(BrkCntSwchTarget[3] + 1); + + BrkCntSwchTarget[3] = lnext; + + // a statement is needed after "case:" + statementNeeded = 1; + } + else if (tok == tokDefault) + { +#ifndef NO_ANNOTATIONS + GenStartCommentLine(); printf2("default\n"); +#endif + + if (!switchBody) + //error("ParseStatement(): 'default' must be within 'switch' statement\n"); + errorCtrlOutOfScope(); + + tok = GetToken(); + if (tok != ':') + //error("ParseStatement(): ':' expected after 'default'\n"); + errorUnexpectedToken(tok); + + if (BrkCntSwchTarget[2] < 0) + //error("ParseStatement(): only one 'default' allowed in 'switch'\n"); + errorUnexpectedToken(tokDefault); + + tok = GetToken(); + + GenNumLabel(BrkCntSwchTarget[2]); // default: + + BrkCntSwchTarget[2] *= -1; // remember presence of default: + + // a statement is needed after "default:" + statementNeeded = 1; + } + else if (tok == tok_Asm) + { + tok = GetToken(); + if (tok != '(') + //error("ParseStatement(): '(' expected after 'asm'\n"); + errorUnexpectedToken(tok); + + tok = GetToken(); + if (tok != tokLitStr) + //error("ParseStatement(): string literal expression expected in 'asm ( expression )'\n"); + errorUnexpectedToken(tok); + + puts2(GetTokenValueString()); + + tok = GetToken(); + if (tok != ')') + //error("ParseStatement(): ')' expected after 'asm ( expression'\n"); + errorUnexpectedToken(tok); + + tok = GetToken(); + if (tok != ';') + //error("ParseStatement(): ';' expected after 'asm ( expression )'\n"); + errorUnexpectedToken(tok); + + tok = GetToken(); + } + else if (tok == tokGoto) + { + if ((tok = GetToken()) != tokIdent) + errorUnexpectedToken(tok); +#ifndef NO_ANNOTATIONS + GenStartCommentLine(); printf2("goto %s\n", GetTokenIdentName()); +#endif + GenJumpUncond(AddGotoLabel(GetTokenIdentName(), 0)); + if ((tok = GetToken()) != ';') + errorUnexpectedToken(tok); + tok = GetToken(); + } + else + { + tok = ParseExpr(tok, &gotUnary, &synPtr, &constExpr, &exprVal, 0, 1); + if (tok == tokGotoLabel) + { + // found a label +#ifndef NO_ANNOTATIONS + GenStartCommentLine(); printf2("%s:\n", IdentTable + stack[0][1]); +#endif + GenNumLabel(AddGotoLabel(IdentTable + stack[0][1], 1)); + // a statement is needed after "label:" + statementNeeded = 1; + } + else + { + if (tok != ';') + //error("ParseStatement(): ';' expected\n"); + errorUnexpectedToken(tok); + if (gotUnary) + GenExpr(); + } + tok = GetToken(); + } + } while (statementNeeded); + + return tok; +} + +// TBD!!! think of ways of getting rid of switchBody +int ParseBlock(int BrkCntSwchTarget[4], int switchBody) +{ + int tok = GetToken(); + + PushSyntax('#'); // mark the beginning of a new scope + + for (;;) + { + if (tok == 0) + return tok; + + if (tok == '}' && ParseLevel > 0) + return tok; + + if (TokenStartsDeclaration(tok, 0)) + { + tok = ParseDecl(tok, NULL, 0, 1); +#ifndef NO_TYPEDEF_ENUM + if (tok == tokGotoLabel) + { + // found a label +#ifndef NO_ANNOTATIONS + GenStartCommentLine(); printf2("%s:\n", GetTokenIdentName()); +#endif + GenNumLabel(AddGotoLabel(GetTokenIdentName(), 1)); + tok = GetToken(); + // a statement is needed after "label:" + tok = ParseStatement(tok, BrkCntSwchTarget, switchBody); + } +#endif + } + else if (ParseLevel > 0 || tok == tok_Asm) + { + tok = ParseStatement(tok, BrkCntSwchTarget, switchBody); + } + else + //error("ParseBlock(): Unexpected token %s\n", GetTokenName(tok)); + errorUnexpectedToken(tok); + } +} + +int main(int argc, char** argv) +{ + // gcc/MinGW inserts a call to __main() here. + int i; + +#ifdef __SMALLER_C__ + DetermineVaListType(); +#endif + + GenInit(); + + // Parse the command line parameters + for (i = 1; i < argc; i++) + { + // DONE: move code-generator-specific options to + // the code generator + if (GenInitParams(argc, argv, &i)) + { + continue; + } + else if (!strcmp(argv[i], "-signed-char")) + { + // this is the default option + CharIsSigned = 1; + continue; + } + else if (!strcmp(argv[i], "-unsigned-char")) + { + CharIsSigned = 0; + continue; + } +#ifdef CAN_COMPILE_32BIT + else if (!strcmp(argv[i], "-ctor-fxn")) + { + if (i + 1 < argc) + { + MainPrologCtorFxn = argv[++i]; + continue; + } + } +#endif + else if (!strcmp(argv[i], "-leading-underscore")) + { + // this is the default option for x86 + UseLeadingUnderscores = 1; + continue; + } + else if (!strcmp(argv[i], "-no-leading-underscore")) + { + // this is the default option for MIPS + UseLeadingUnderscores = 0; + continue; + } + else if (!strcmp(argv[i], "-label")) + { + if (i + 1 < argc) + { + LabelCnt = atoi(argv[++i]); + continue; + } + } + else if (!strcmp(argv[i], "-no-externs")) + { + GenExterns = 0; + continue; + } + else if (!strcmp(argv[i], "-verbose")) + { + verbose = 1; + continue; + } +#ifndef NO_PREPROCESSOR + else if (!strcmp(argv[i], "-I")) + { + if (i + 1 < argc) + { + int len = strlen(argv[++i]); + if (MAX_SEARCH_PATH - SearchPathsLen < len + 1) + //error("Path name too long\n"); + errorFileName(); + strcpy(SearchPaths + SearchPathsLen, argv[i]); + SearchPathsLen += len + 1; + continue; + } + } + // DONE: '-D macro[=expansion]': '#define macro 1' when there's no '=expansion' + else if (!strcmp(argv[i], "-D")) + { + if (i + 1 < argc) + { + char id[MAX_IDENT_LEN + 1]; + char* e = strchr(argv[++i], '='); + int len; + if (e) + { + len = e - argv[i]; + e++; + } + else + { + len = strlen(argv[i]); + e = "1"; + } + if (len > 0 && len <= MAX_IDENT_LEN) + { + int j, bad = 1; + memcpy(id, argv[i], len); + id[len] = '\0'; + for (j = 0; j < len; j++) + if ((bad = !(id[j] == '_' || (!j * isalpha(id[j] & 0xFFu) + j * isalnum(id[j] & 0xFFu)))) != 0) + break; + if (!bad) + { + DefineMacro(id, e); + continue; + } + } + } + } +#endif // #ifndef NO_PREPROCESSOR + else if (argv[i][0] == '-') + { + // unknown option + } + else if (FileCnt == 0) + { + // If it's none of the known options, + // assume it's the source code file name + if (strlen(argv[i]) > MAX_FILE_NAME_LEN) + //error("File name too long\n"); + errorFileName(); + strcpy(FileNames[0], argv[i]); + if ((Files[0] = fopen(FileNames[0], "r")) == NULL) + //error("Cannot open file \"%s\"\n", FileNames[0]); + errorFile(FileNames[0]); + LineNos[0] = LineNo; + LinePoss[0] = LinePos; + FileCnt++; + continue; + } + else if (FileCnt == 1 && OutFile == NULL) + { + // This should be the output file name + if ((OutFile = fopen(argv[i], "w")) == NULL) + //error("Cannot open output file \"%s\"\n", argv[i]); + errorFile(argv[i]); + continue; + } + + error("Invalid or unsupported command line option\n"); + } + + if (!FileCnt) + error("Input file not specified\n"); + + GenInitFinalize(); + + // some manual initialization because there's no 2d array initialization yet + PushSyntax(tokVoid); // SymVoidSynPtr + PushSyntax(tokInt); // SymIntSynPtr + PushSyntax(tokUnsigned); // SymUintSynPtr + PushSyntax(tokIdent); // SymFuncPtr + PushSyntax('['); + PushSyntax(tokNumUint); + PushSyntax(']'); + PushSyntax(tokChar); + +#ifndef NO_PREPROCESSOR + // Define a few macros useful for conditional compilation + DefineMacro("__SMALLER_C__", "0x0100"); + if (SizeOfWord == 2) + DefineMacro("__SMALLER_C_16__", ""); + else if (SizeOfWord == 4) + DefineMacro("__SMALLER_C_32__", ""); + if (CharIsSigned) + DefineMacro("__SMALLER_C_SCHAR__", ""); + else + DefineMacro("__SMALLER_C_UCHAR__", ""); +#endif + + // populate CharQueue[] with the initial file characters + ShiftChar(); + + puts2(FileHeader); + + // compile +#ifndef NO_PPACK + PragmaPackValue = SizeOfWord; +#endif + ParseBlock(NULL, 0); + + GenFin(); + + DumpSynDecls(); +#ifndef NO_PREPROCESSOR + DumpMacroTable(); +#endif + DumpIdentTable(); + + GenStartCommentLine(); printf2("Next label number: %d\n", LabelCnt); + + if (verbose && warnCnt && OutFile) + printf("%d warnings\n", warnCnt); + GenStartCommentLine(); printf2("Compilation succeeded.\n"); + + if (OutFile) + fclose(OutFile); + + return 0; +} diff --git a/src/cmd/smux/Makefile b/src/cmd/smux/Makefile new file mode 100644 index 0000000..24ba798 --- /dev/null +++ b/src/cmd/smux/Makefile @@ -0,0 +1,10 @@ +all: + make -C retro + make -C linux + +install: + make -C retro install + +clean: + make -C retro clean + make -C linux clean diff --git a/src/cmd/smux/common/packet.h b/src/cmd/smux/common/packet.h new file mode 100644 index 0000000..fc45a15 --- /dev/null +++ b/src/cmd/smux/common/packet.h @@ -0,0 +1,45 @@ +#ifndef _PACKET_H +#define _PACKET_H + +/* + * This is the core definition of a TMUX data packet. + * The format is very simple and light. A single byte + * defines the type of the packet - this can be thought + * of as the command. + * The stream indicates which endpoint to communicate + * with. A stream of 0 is the "system" stream and is + * used to control the connection. + * A single byte defines the length of the data segment, + * so up to 255 bytes can be transmitted in one packet. + */ +struct smux_packet { + unsigned char type; + unsigned char stream; + unsigned char len; + char data[255]; +}; + +// Initiate a connection +#define C_CONNECT 0x01 + +// Connection established, here is the stream id +#define C_CONNECTOK 0x02 +#define C_CONNECTFAIL 0x03 + +// Disconnect a stream +#define C_DISCONNECT 0x04 + +// Data transmission +#define C_DATA 0x05 + +// Proxy is terminating, close everything down. +#define C_QUIT 0x06 + +// If we don't see a PING every 10 seconds, the +// link must have died - abort. +#define C_PING 0x07 +#define C_PONG 0x08 + +#define C_MAX 0x08 + +#endif diff --git a/src/cmd/smux/linux/Makefile b/src/cmd/smux/linux/Makefile new file mode 100644 index 0000000..4f5e23d --- /dev/null +++ b/src/cmd/smux/linux/Makefile @@ -0,0 +1,9 @@ +OBJS = smux.o +BIN = smux +CFLAGS = -O -Wall -Werror + +$(BIN): $(OBJS) + $(CC) -o $(BIN) $(OBJS) + +clean: + rm -f smux.o smux diff --git a/src/cmd/smux/linux/smux.c b/src/cmd/smux/linux/smux.c new file mode 100644 index 0000000..f23c777 --- /dev/null +++ b/src/cmd/smux/linux/smux.c @@ -0,0 +1,469 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define TELOPTS +#define TELCMDS + +#include +#include + +#include "../common/packet.h" + +struct smux_packet rx; +struct smux_packet tx; + +int pipe_fd; + +int string_contains(char *haystack, char *needle, int len) +{ + char *p; + for (p = haystack; p < (haystack + len) - strlen(needle); p++) { + if(!strncmp(p, needle, strlen(needle))) { + return 1; + } + } + return 0; +} + +void send_tx() +{ + int rv __attribute__((unused)); + rv = write(pipe_fd, &tx, tx.len + 3); + fsync(pipe_fd); +} + +int fdgetline(int fd, char *buffer, int maxlen) +{ + fd_set rfd; + struct timeval tv; + int nr = 0; + int rc = 0; + char inch[2]; + int rv __attribute__((unused)); + + for (;;) { + tv.tv_sec = 0; + tv.tv_usec = 1000; + FD_ZERO(&rfd); + FD_SET(fd, &rfd); + rc = select(fd+1, &rfd, NULL, NULL, &tv); + if (rc <= 0) { + return nr; + } + + if (FD_ISSET(fd, &rfd)) { + rv = read(fd, inch, 1); + if (inch[0] == '\n') { + return nr; + } + if (inch[0] != '\r') { + buffer[nr++] = inch[0]; + buffer[nr] = 0; + } + if (nr == maxlen) { + return maxlen; + } + } + } +} + +int read_chunk(int fd, void *buf, int ml) +{ + fd_set rfd; + struct timeval tv; + tv.tv_sec = 1; + tv.tv_usec = 0; + int rv __attribute__((unused)); + + FD_ZERO(&rfd); + FD_SET(fd, &rfd); + + rv = select(9999, &rfd, NULL, NULL, &tv); + + if (FD_ISSET(fd, &rfd)) { + return read(fd, buf, ml); + } + return -1; +} + +int rx_link_data() +{ + static unsigned char phase = 0; + static unsigned int pos = 0; + char inch[2]; + int res; + + res = read(pipe_fd, inch, 1); + + if (res<0) + return 0; + + switch(phase) { + case 0: + if (inch[0] > C_MAX) + return 0; + rx.type = inch[0]; + phase++; + break; + case 1: + rx.stream = inch[0]; + phase++; + break; + case 2: + rx.len = inch[0]; + phase++; + pos = 0; + if (rx.len == 0) { + phase = 0; + return 1; + } + break; + case 3: + rx.data[pos++] = inch[0]; + if (pos == rx.len) { + phase = 0; + return 1; + } + break; + } + + return 0; +} + + +#define MAXFD 10 + +#define M_NORM 0 +#define M_IAC 1 +#define M_SUB 2 + +int main(int argc, char *argv[]) +{ + char *username = "smux"; + char *password = ""; + char *device = "/dev/ttyACM0"; + int nr; + char buffer[300]; + struct termios tty; + int i; + int maxfd; + fd_set rfd; + fd_set efd; + struct timeval tv; + unsigned int doping = time(NULL) + 5; + unsigned int nextping = time(NULL) + 10; + int sockfd; + struct sockaddr_in sa; + int infd; + int stream; + int rv __attribute__((unused)); + + int ready[MAXFD]; + int fds[MAXFD]; + + int opt; + + signal(SIGPIPE, SIG_IGN); + + + for (i=0; i 0) { + printf("%s\n", buffer); + if(string_contains(buffer, "ogin:", nr)) { + sprintf(buffer, "%s\r", username); + rv = write(pipe_fd, buffer, strlen(buffer)); + } + if(string_contains(buffer, "assword:", nr)) { + sprintf(buffer, "%s\r", password); + rv = write(pipe_fd, buffer, strlen(buffer)); + } + if(string_contains(buffer, "Welcome to RetroBSD", nr)) { + break; + } + } + } + + printf("Logged in - starting main loop\n"); + + doping = time(NULL) + 5; + nextping = time(NULL) + 10; + + // Main loop. Do this forever. + for (;;) { + + + maxfd = 0; + FD_ZERO(&rfd); + for (i=0; i maxfd) + maxfd = fds[i]; + } + } + tv.tv_sec = 0; + tv.tv_usec = 1000; + select(maxfd+1, &rfd, NULL, &efd, &tv); + + + + for (stream = 0; stream < MAXFD; stream++) { + if (ready[stream] == 1) { + tx.type = C_CONNECT; + tx.stream = stream; + tx.len = 0; + send_tx(); + ready[stream] = 0; + printf("Attempting to connect stream %d\n", stream); + } + if (fds[stream] != -1) { + + if (FD_ISSET(fds[stream], &efd)) { + if (fds[stream] == sockfd) { + printf("Socket died\n"); + return 10; + } + if (fds[stream] == pipe_fd) { + printf("Pipe died\n"); + return 10; + } + close(fds[stream]); + FD_CLR(fds[stream], &rfd); + printf("Connection closed on stream %d\n", i); + fds[stream] = -1; + } + + if (FD_ISSET(fds[stream], &rfd)) { + if (fds[stream] == sockfd) { + if ((infd = accept(sockfd,NULL,NULL)) >= 0) { + for (i=0; i IAC DO LINEMODE IAC WILL ECHO\n"); + rv = write(infd, buffer, 6); + fsync(infd); + ready[i] = 1; + } + } + } else if (fds[stream] == pipe_fd) { + if (rx_link_data()) { + // We have a complete packet + switch (rx.type) { + case C_PONG: + nextping = time(NULL) + 10; + break; + case C_DATA: + nextping = time(NULL) + 10; + rv = write(fds[rx.stream], rx.data, rx.len); + //printf("%d>%s", rx.stream, rx.data); + break; + case C_CONNECTOK: + printf("Connected OK, stream ID is %d\n", rx.stream); + tx.type = C_DATA; + tx.len = 1; + tx.stream = stream; + sprintf(tx.data, "\r"); + send_tx(); + break; + case C_CONNECTFAIL: + //printf("Connect failed on stream %d\n", rx.stream); + break; + } + } + } else { + tx.type = C_DATA; + tx.stream = stream; + nr = read(fds[stream], buffer, 255); + + if (nr <= 0) { + tx.type = C_DISCONNECT; + tx.stream = stream; + tx.len = 0; + send_tx(); + close(fds[stream]); + fds[stream] = -1; + printf("Connection %d closed\n", stream); + } else { + buffer[nr] = 0; + //printf("Got %d bytes\n", nr); + int j = 0; + char iac[100]; + for (i=0; i 0) { + tx.stream = stream; + tx.len = j; + tx.data[j] = 0; + send_tx(); + } + } + } + } + } + } + + if (doping < time(NULL)) { + doping = time(NULL) + 5; + tx.type = C_PING; + tx.stream = 0; + tx.len = 0; + send_tx(); + } + + if (nextping < time(NULL)) { + close(pipe_fd); + printf("Timeout\n"); + return(10); + } + } + + close(pipe_fd); +} diff --git a/src/cmd/smux/retro/Makefile b/src/cmd/smux/retro/Makefile new file mode 100644 index 0000000..42ed19f --- /dev/null +++ b/src/cmd/smux/retro/Makefile @@ -0,0 +1,34 @@ +# +# Public Domain. 1995/03/13 - Steven Schultz +# +TOPSRC = $(shell cd ../../../..; pwd) +include $(TOPSRC)/target.mk + +CFLAGS += -Wall -Werror -I../../../../sys/include + +BIN = smux +SRCS = smux.c +OBJS = smux.o + +all: smux + +smux: $(OBJS) + ${CC} ${LDFLAGS} -o $@.elf ${OBJS} ${LIBS} + ${OBJDUMP} -S $@.elf > $@.dis + ${SIZE} $@.elf + ${ELF2AOUT} $@.elf $@ + +clean: + rm -f *.o *.elf *.elf *.dis tags *~ $(BIN) + +depend: ${SRCS} + mkdep ${CFLAGS} ${SRCS} + +install: all + install -m 755 $(BIN) ${DESTDIR}/bin + +lint: ${SRCS} + lint -hax ${SRCS} + +tags: ${SRCS} + ctags ${SRCS} diff --git a/src/cmd/smux/retro/smux.c b/src/cmd/smux/retro/smux.c new file mode 100644 index 0000000..a8ba40e --- /dev/null +++ b/src/cmd/smux/retro/smux.c @@ -0,0 +1,232 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../common/packet.h" + +#define MAXFD 20 +#define MAXPTY 10 + +struct smux_packet rx; +struct smux_packet tx; + +#define termios sgttyb +static struct termios term_orig, term_smux; + +void send_tx() +{ + write(0, &tx, tx.len + 3); + fflush(stdout); +} + +int allocate_pty() +{ + int i; + int fd = -1; + char dev[20]; + struct stat sb; + + for (i = 0; i < MAXPTY; i++) { + sprintf(dev, "/dev/ptyp%d", i); + if (stat(dev, &sb) == -1) { + return -1; + } + fd = open(dev, O_RDWR | O_EXCL); + if (fd > 0) { + return fd; + } + } + return -1; +} + +void close_pty(int fd) +{ + close(fd); +} + +void raw() +{ + ioctl(0, TIOCGETP, &term_orig); + term_smux = term_orig; + + term_smux.sg_flags &= ~(ECHO | CRMOD | XTABS | RAW); + term_smux.sg_flags |= CBREAK | RAW; + + ioctl(0, TIOCSETP, &term_smux); + + //signal(SIGINT, SIG_IGN); +} + +void cooked() +{ + ioctl(0, TIOCSETP, &term_orig); +} + +int rx_link_data() +{ + static unsigned char phase = 0; + static unsigned int pos = 0; + char inch[2]; + int res; + + res = read(0, inch, 1); + + switch(phase) { + case 0: + if (inch[0] > C_MAX) + return 0; + rx.type = inch[0]; + phase++; + break; + case 1: + rx.stream = inch[0]; + phase++; + break; + case 2: + rx.len = inch[0]; + phase++; + pos = 0; + if (rx.len == 0) { + phase = 0; + return 1; + } + break; + case 3: + rx.data[pos++] = inch[0]; + if (pos == rx.len) { + phase = 0; + return 1; + } + break; + } + + return 0; +} + +int main(int argc, char *argv[]) +{ + // Storage for all the FDs for the various streams + int fds[MAXFD]; + fd_set rfd; + unsigned int nextping = time(NULL) + 10; + fds[0] = 0; + int i; + struct timeval tv; + int fd; + int maxfd; + + tv.tv_sec = 1; + tv.tv_usec = 0; + + for (i=0; i maxfd) + maxfd = fds[i]; + } + } + select(maxfd+1, &rfd, NULL, NULL, &tv); + + for (i = 0; i < MAXFD; i++) { + if (fds[i] != -1) { + if (FD_ISSET(fds[i], &rfd)) { + + if (fds[i] == 0) { + if (rx_link_data()) { + // We have a complete packet + + // Any packet counts as a ping - reset the + // ping time. + nextping = time(NULL) + 10; + + switch (rx.type) { + case C_PING: + // This was a ping - we should respond to confirm + // we got it. + tx.type = C_PONG; + tx.stream = 0; + tx.len = 0; + send_tx(); + break; + + case C_CONNECT: + // We want to create a new channel. First off, get a ptyp + // device. + + fd = allocate_pty(); + if (fd < 0) { + tx.type = C_CONNECTFAIL; + tx.stream = 0; + tx.len = 0; + send_tx(); + break; + } + i = rx.stream; + if (fds[i] == -1) { + fds[i] = fd; + tx.type = C_CONNECTOK; + tx.stream = i; + tx.len = 0; + send_tx(); + break; + } + if (i == MAXFD) { + close_pty(fd); + tx.type = C_CONNECTFAIL; + tx.stream = rx.stream; + tx.len = 0; + send_tx(); + } + break; + + case C_DISCONNECT: + close_pty(fds[rx.stream]); + fds[rx.stream] = -1; + break; + + case C_DATA: + if (fds[rx.stream] > -1) { + write(fds[rx.stream], rx.data, rx.len); + } + break; + + case C_QUIT: + cooked(); + return(0); + + } + } + } else { + tx.type = C_DATA; + tx.stream = i; + tx.len = read(fds[i], tx.data, 255); + send_tx(); + } + } + } + } + if (time(NULL) > nextping) { + cooked(); + exit(10); + } + } + return 0; +} diff --git a/src/cmd/sort.c b/src/cmd/sort.c new file mode 100644 index 0000000..9ec7b96 --- /dev/null +++ b/src/cmd/sort.c @@ -0,0 +1,911 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define L 1024 +#define N 7 +#define C 20 +#ifndef pdp11 +#define MEM (32*2048) +#else +#define MEM (16*2048) +#endif +#define NF 10 + +#define rline(mp) (fgets((mp)->l, L, (mp)->b) == NULL) + +FILE *is, *os; +char *dirtry[] = {_PATH_USRTMP, _PATH_TMP, NULL}; +char **dirs; +char file1[30]; +char *file = file1; +char *filep; +int nfiles; +unsigned nlines; +unsigned ntext; +int *lspace; +char *tspace; +int cmp(), cmpa(); +int (*compare)() = cmpa; +char *eol(); +void term(int); +int mflg; +int cflg; +int uflg; +char *outfil; +int unsafeout; /*kludge to assure -m -o works*/ +char tabchar; +int eargc; +char **eargv; + +char zero[256]; + +char fold[256] = { + 0200,0201,0202,0203,0204,0205,0206,0207, + 0210,0211,0212,0213,0214,0215,0216,0217, + 0220,0221,0222,0223,0224,0225,0226,0227, + 0230,0231,0232,0233,0234,0235,0236,0237, + 0240,0241,0242,0243,0244,0245,0246,0247, + 0250,0251,0252,0253,0254,0255,0256,0257, + 0260,0261,0262,0263,0264,0265,0266,0267, + 0270,0271,0272,0273,0274,0275,0276,0277, + 0300,0301,0302,0303,0304,0305,0306,0307, + 0310,0311,0312,0313,0314,0315,0316,0317, + 0320,0321,0322,0323,0324,0325,0326,0327, + 0330,0331,0332,0333,0334,0335,0336,0337, + 0340,0341,0342,0343,0344,0345,0346,0347, + 0350,0351,0352,0353,0354,0355,0356,0357, + 0360,0361,0362,0363,0364,0365,0366,0367, + 0370,0371,0372,0373,0374,0375,0376,0377, + 0000,0001,0002,0003,0004,0005,0006,0007, + 0010,0011,0012,0013,0014,0015,0016,0017, + 0020,0021,0022,0023,0024,0025,0026,0027, + 0030,0031,0032,0033,0034,0035,0036,0037, + 0040,0041,0042,0043,0044,0045,0046,0047, + 0050,0051,0052,0053,0054,0055,0056,0057, + 0060,0061,0062,0063,0064,0065,0066,0067, + 0070,0071,0072,0073,0074,0075,0076,0077, + 0100,0101,0102,0103,0104,0105,0106,0107, + 0110,0111,0112,0113,0114,0115,0116,0117, + 0120,0121,0122,0123,0124,0125,0126,0127, + 0130,0131,0132,0133,0134,0135,0136,0137, + 0140,0101,0102,0103,0104,0105,0106,0107, + 0110,0111,0112,0113,0114,0115,0116,0117, + 0120,0121,0122,0123,0124,0125,0126,0127, + 0130,0131,0132,0173,0174,0175,0176,0177 +}; +char nofold[256] = { + 0200,0201,0202,0203,0204,0205,0206,0207, + 0210,0211,0212,0213,0214,0215,0216,0217, + 0220,0221,0222,0223,0224,0225,0226,0227, + 0230,0231,0232,0233,0234,0235,0236,0237, + 0240,0241,0242,0243,0244,0245,0246,0247, + 0250,0251,0252,0253,0254,0255,0256,0257, + 0260,0261,0262,0263,0264,0265,0266,0267, + 0270,0271,0272,0273,0274,0275,0276,0277, + 0300,0301,0302,0303,0304,0305,0306,0307, + 0310,0311,0312,0313,0314,0315,0316,0317, + 0320,0321,0322,0323,0324,0325,0326,0327, + 0330,0331,0332,0333,0334,0335,0336,0337, + 0340,0341,0342,0343,0344,0345,0346,0347, + 0350,0351,0352,0353,0354,0355,0356,0357, + 0360,0361,0362,0363,0364,0365,0366,0367, + 0370,0371,0372,0373,0374,0375,0376,0377, + 0000,0001,0002,0003,0004,0005,0006,0007, + 0010,0011,0012,0013,0014,0015,0016,0017, + 0020,0021,0022,0023,0024,0025,0026,0027, + 0030,0031,0032,0033,0034,0035,0036,0037, + 0040,0041,0042,0043,0044,0045,0046,0047, + 0050,0051,0052,0053,0054,0055,0056,0057, + 0060,0061,0062,0063,0064,0065,0066,0067, + 0070,0071,0072,0073,0074,0075,0076,0077, + 0100,0101,0102,0103,0104,0105,0106,0107, + 0110,0111,0112,0113,0114,0115,0116,0117, + 0120,0121,0122,0123,0124,0125,0126,0127, + 0130,0131,0132,0133,0134,0135,0136,0137, + 0140,0141,0142,0143,0144,0145,0146,0147, + 0150,0151,0152,0153,0154,0155,0156,0157, + 0160,0161,0162,0163,0164,0165,0166,0167, + 0170,0171,0172,0173,0174,0175,0176,0177 +}; + +char nonprint[256] = { + 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,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,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,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 +}; + +char dict[256] = { + 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,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,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,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1, + 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1, + 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1 +}; + +struct field { + char *code; + char *ignore; + int nflg; + int rflg; + int bflg[2]; + int m[2]; + int n[2]; +} fields[NF]; +struct field proto = { + nofold+128, + zero+128, + 0, + 1, + 0,0, + 0,-1, + 0,0 +}; +int nfields; +int error = 1; +char *setfil(); + +#define blank(c) ((c) == ' ' || (c) == '\t') + +main(argc, argv) +char **argv; +{ + register a; + extern char end[1]; + char *ep; + char *arg; + struct field *p, *q; + int i; + + copyproto(); + eargv = argv; + while (--argc > 0) { + if(**++argv == '-') for(arg = *argv;;) { + switch(*++arg) { + case '\0': + if(arg[-1] == '-') + eargv[eargc++] = "-"; + break; + + case 'o': + if(--argc > 0) + outfil = *++argv; + continue; + + case 'T': + if (--argc > 0) + dirtry[0] = *++argv; + continue; + + default: + field(++*argv,nfields>0); + break; + } + break; + } else if (**argv == '+') { + if(++nfields>=NF) { + diag("too many keys",""); + exit(1); + } + copyproto(); + field(++*argv,0); + } else + eargv[eargc++] = *argv; + } + q = &fields[0]; + for(a=1; a<=nfields; a++) { + p = &fields[a]; + if(p->code != proto.code) continue; + if(p->ignore != proto.ignore) continue; + if(p->nflg != proto.nflg) continue; + if(p->rflg != proto.rflg) continue; + if(p->bflg[0] != proto.bflg[0]) continue; + if(p->bflg[1] != proto.bflg[1]) continue; + p->code = q->code; + p->ignore = q->ignore; + p->nflg = q->nflg; + p->rflg = q->rflg; + p->bflg[0] = p->bflg[1] = q->bflg[0]; + } + if(eargc == 0) + eargv[eargc++] = "-"; + if(cflg && eargc>1) { + diag("can check only 1 file",""); + exit(1); + } + safeoutfil(); + + ep = end + MEM; + lspace = (int *)sbrk(0); + while((int)brk(ep) == -1) + ep -= 512; +#ifndef vax + brk(ep -= 512); /* for recursion */ +#endif + a = ep - (char*)lspace; + nlines = (a-L); + nlines /= (5*(sizeof(char *)/sizeof(char))); + ntext = nlines * 4 * (sizeof(char *)/sizeof(char)); + tspace = (char *)(lspace + nlines); + a = -1; + for(dirs=dirtry; *dirs; dirs++) { + sprintf(filep=file1, "%s/stm%05uaa", *dirs, getpid()); + while (*filep) + filep++; + filep -= 2; + if ( (a=creat(file, 0600)) >=0) + break; + } + if(a < 0) { + diag("can't locate temp",""); + exit(1); + } + close(a); + unlink(file); + if (signal(SIGHUP, SIG_IGN) != SIG_IGN) + signal(SIGHUP, term); + if (signal(SIGINT, SIG_IGN) != SIG_IGN) + signal(SIGINT, term); + signal(SIGPIPE, term); + if (signal(SIGTERM, SIG_IGN) != SIG_IGN) + signal(SIGTERM, term); + nfiles = eargc; + if(!mflg && !cflg) { + sort(); + fclose(stdin); + } + for(a = mflg|cflg?0:eargc; a+N=nfiles) + i = nfiles; + newfile(); + merge(a, i); + } + if(a != nfiles) { + oldfile(); + merge(a, nfiles); + } + error = 0; + term(0); +} + +sort() +{ + register char *cp; + register char **lp; + register lines, text, len; + int done = 0; + int i = 0; + char *f; + char c; + + if((f = setfil(i++)) == NULL) + is = stdin; + else if((is = fopen(f, "r")) == NULL) + cant(f); + + do { + cp = tspace; + lp = (char **)lspace; + lines = nlines; + text = ntext; + while(lines > 0 && text > 0) { + if(fgets(cp, L, is) == NULL) { + if(i >= eargc) { + ++done; + break; + } + fclose(is); + if((f = setfil(i++)) == NULL) + is = stdin; + else if((is = fopen(f, "r")) == NULL) + cant(f); + continue; + } + *lp++ = cp; + len = strlen(cp) + 1; /* null terminate */ + if(cp[len - 2] != '\n') + if (len == L) { + diag("line too long (skipped): ", cp); + while((c=getc(is)) != EOF && c != '\n') + /* throw it away */; + --lp; + continue; + } else { + diag("missing newline before EOF in ", + f ? f : "standard input"); + /* be friendly, append a newline */ + ++len; + cp[len - 2] = '\n'; + cp[len - 1] = '\0'; + } + cp += len; + --lines; + text -= len; + } + qusort((char **)lspace, lp); + if(done == 0 || nfiles != eargc) + newfile(); + else + oldfile(); + clearerr(os); + while(lp > (char **)lspace) { + cp = *--lp; + if(*cp) + fputs(cp, os); + if (ferror(os)) { + error = 1; + term(0); + } + } + fclose(os); + } while(done == 0); +} + +struct merg +{ + char l[L]; + FILE *b; +} *ibuf[256]; + +merge(a,b) +{ + struct merg *p; + register char *cp, *dp; + register i; + struct merg **ip, *jp; + char *f; + int j; + int k, l; + int muflg; + + p = (struct merg *)lspace; + j = 0; + for(i=a; i < b; i++) { + f = setfil(i); + if(f == 0) + p->b = stdin; + else if((p->b = fopen(f, "r")) == NULL) + cant(f); + ibuf[j] = p; + if(!rline(p)) j++; + p++; + } + + do { + i = j; + qusort((char **)ibuf, (char **)(ibuf+i)); + l = 0; + while(i--) { + cp = ibuf[i]->l; + if(*cp == '\0') { + l = 1; + if(rline(ibuf[i])) { + k = i; + while(++k < j) + ibuf[k-1] = ibuf[k]; + j--; + } + } + } + } while(l); + + clearerr(os); + muflg = mflg & uflg | cflg; + i = j; + while(i > 0) { + cp = ibuf[i-1]->l; + if (!cflg && (uflg == 0 || muflg || i == 1 || + (*compare)(ibuf[i-1]->l,ibuf[i-2]->l))) { + fputs(cp, os); + if (ferror(os)) { + error = 1; + term(0); + } + } + if(muflg){ + cp = ibuf[i-1]->l; + dp = p->l; + do { + } while((*dp++ = *cp++) != '\n'); + } + for(;;) { + if(rline(ibuf[i-1])) { + i--; + if(i == 0) + break; + if(i == 1) + muflg = uflg; + } + ip = &ibuf[i]; + while(--ip>ibuf&&(*compare)(ip[0]->l,ip[-1]->l)<0){ + jp = *ip; + *ip = *(ip-1); + *(ip-1) = jp; + } + if(!muflg) + break; + j = (*compare)(ibuf[i-1]->l,p->l); + if(cflg) { + if(j > 0) + disorder("disorder:",ibuf[i-1]->l); + else if(uflg && j==0) + disorder("nonunique:",ibuf[i-1]->l); + } else if(j == 0) + continue; + break; + } + } + p = (struct merg *)lspace; + for(i=a; ib); + p++; + if(i >= eargc) + unlink(setfil(i)); + } + fclose(os); +} + +disorder(s,t) +char *s, *t; +{ + register char *u; + for(u=t; *u!='\n';u++) ; + *u = 0; + diag(s,t); + term(0); +} + +newfile() +{ + register char *f; + + f = setfil(nfiles); + if((os=fopen(f, "w")) == NULL) { + diag("can't create ",f); + term(0); + } + nfiles++; +} + +char * +setfil(i) +{ + + if(i < eargc) + if(eargv[i][0] == '-' && eargv[i][1] == '\0') + return(0); + else + return(eargv[i]); + i -= eargc; + filep[0] = i/26 + 'a'; + filep[1] = i%26 + 'a'; + return(file); +} + +oldfile() +{ + + if(outfil) { + if((os=fopen(outfil, "w")) == NULL) { + diag("can't create ",outfil); + term(0); + } + } else + os = stdout; +} + +safeoutfil() +{ + register int i; + struct stat obuf,ibuf; + + if(!mflg||outfil==0) + return; + if(stat(outfil,&obuf)==-1) + return; + for(i=eargc-N;i0; k<=nfields; k++) { + fp = &fields[k]; + pa = i; + pb = j; + if(k) { + la = skip(pa, fp, 1); + pa = skip(pa, fp, 0); + lb = skip(pb, fp, 1); + pb = skip(pb, fp, 0); + } else { + la = eol(pa); + lb = eol(pb); + } + if(fp->nflg) { + if(tabchar) { + if(parflg; + if(*pa == '-') { + pa++; + sa = -sa; + } + if(*pb == '-') { + pb++; + sb = -sb; + } + for(ipa = pa; ipa pa && ipb > pb) + if(b = *--ipb - *--ipa) + a = b; + while(ipa > pa) + if(*--ipa != '0') + return(-sa); + while(ipb > pb) + if(*--ipb != '0') + return(sb); + if(a) return(a*sa); + if(*(pa=jpa) == '.') + pa++; + if(*(pb=jpb) == '.') + pb++; + if(sa==sb) + while(pacode; + ignore = fp->ignore; +loop: + while(ignore[*pa]) + pa++; + while(ignore[*pb]) + pb++; + if(pa>=la || *pa=='\n') + if(pbrflg); + else continue; + if(pb>=lb || *pb=='\n') + return(-fp->rflg); + if((sa = code[*pb++]-code[*pa++]) == 0) + goto loop; + return(sa*fp->rflg); + } + if(uflg) + return(0); + return(cmpa(i, j)); +} + +cmpa(pa, pb) +register char *pa, *pb; +{ + while(*pa == *pb) { + if(*pa++ == '\n') + return(0); + pb++; + } + return( + *pa == '\n' ? fields[0].rflg: + *pb == '\n' ?-fields[0].rflg: + *pb > *pa ? fields[0].rflg: + -fields[0].rflg + ); +} + +char * +skip(pp, fp, j) +struct field *fp; +char *pp; +{ + register i; + register char *p; + + p = pp; + if( (i=fp->m[j]) < 0) + return(eol(p)); + while(i-- > 0) { + if(tabchar != 0) { + while(*p != tabchar) + if(*p != '\n') + p++; + else goto ret; + if(i>0||j==0) + p++; + } else { + while(blank(*p)) + p++; + while(!blank(*p)) + if(*p != '\n') + p++; + else goto ret; + } + } + if(tabchar==0||fp->bflg[j]) + while(blank(*p)) + p++; + i = fp->n[j]; + while(i-- > 0) { + if(*p != '\n') + p++; + else goto ret; + } +ret: + return(p); +} + +char * +eol(p) +register char *p; +{ + while(*p != '\n') p++; + return(p); +} + +copyproto() +{ + register i; + register int *p, *q; + + p = (int *)&proto; + q = (int *)&fields[nfields]; + for(i=0; ibflg[k]++; + break; + + case 'd': + p->ignore = dict+128; + break; + + case 'f': + p->code = fold+128; + break; + case 'i': + p->ignore = nonprint+128; + break; + + case 'c': + cflg = 1; + continue; + + case 'm': + mflg = 1; + continue; + + case 'n': + p->nflg++; + break; + case 't': + tabchar = *++s; + if(tabchar == 0) s--; + continue; + + case 'r': + p->rflg = -1; + continue; + case 'u': + uflg = 1; + break; + + case '.': + if(p->m[k] == -1) /* -m.n with m missing */ + p->m[k] = 0; + d = &fields[0].n[0]-&fields[0].m[0]; + + default: + p->m[k+d] = number(&s); + } + compare = cmp; + } +} + +number(ppa) +char **ppa; +{ + int n; + register char *pa; + pa = *ppa; + n = 0; + while(isdigit(*pa)) { + n = n*10 + *pa - '0'; + *ppa = pa++; + } + return(n); +} + +#define qsexc(p,q) t= *p;*p= *q;*q=t +#define qstexc(p,q,r) t= *p;*p= *r;*r= *q;*q=t + +qusort(a,l) +char **a, **l; +{ + register char **i, **j; + char **k; + char **lp, **hp; + int c; + char *t; + unsigned n; + +start: + if((n=l-a) <= 1) + return; + + + n /= 2; + hp = lp = a+n; + i = a; + j = l-1; + + + for(;;) { + if(i < lp) { + if((c = (*compare)(*i, *lp)) == 0) { + --lp; + qsexc(i, lp); + continue; + } + if(c < 0) { + ++i; + continue; + } + } + +loop: + if(j > hp) { + if((c = (*compare)(*hp, *j)) == 0) { + ++hp; + qsexc(hp, j); + goto loop; + } + if(c > 0) { + if(i == lp) { + ++hp; + qstexc(i, hp, j); + i = ++lp; + goto loop; + } + qsexc(i, j); + --j; + ++i; + continue; + } + --j; + goto loop; + } + + + if(i == lp) { + if(uflg) + for(k=lp+1; k<=hp;) **k++ = '\0'; + if(lp-a >= l-hp) { + qusort(hp+1, l); + l = lp; + } else { + qusort(a, lp); + a = hp+1; + } + goto start; + } + + + --lp; + qstexc(j, lp, i); + j = --hp; + } +} diff --git a/src/cmd/split.c b/src/cmd/split.c new file mode 100644 index 0000000..b7fbe7f --- /dev/null +++ b/src/cmd/split.c @@ -0,0 +1,82 @@ +#include +#include + +unsigned count = 1000; +int fnumber; +char fname[100]; +char *ifil; +char *ofil; +FILE *is; +FILE *os; + +main(argc, argv) +char *argv[]; +{ + register i, c, f; + int iflg = 0; + + for(i=1; i. +*/ +#include +#include +#include +#include +#include +#include +#include + +#include "edit.h" + +extern globalStruct globalData; + +/* Only "cmd" that does not take args */ +int startArgCmd() +{ +char tmp[512]; + + if( globalData.argMode != 0 ) + return(0); + globalData.argMode = 1; + globalData.argPtr = 0; + if( globalData.argBufferSize == 0 ) + { + globalData.argBufferSize = 50; + globalData.argBuffer = malloc(50); + } + /* Put on screen display in status area */ + memset(tmp, ' ', globalData.winWidth/2); + tmp[globalData.winWidth/2] = '\0'; + printf("\033[%d;1H%s", globalData.winHeight, tmp); + printf("\033[%d;1HCMD: ", globalData.winHeight); +} + +redrawCmd() +{ + redrawScreen(); +} + +/* When lines are added or deleted, need to validate the alternate files */ +/* other windows and ranges are not adversely affected */ +/* firstLine is the beginning of the change. numLines is how many lines (+/-) */ +/* that were added or deleted. ls is the first line of the change */ +checkUpdateAlternate(windowStruct *chgWin, windowStruct *chkWin, + long long firstLine, long long numLines, int delete) +{ +long long cnt; +int i; +fileWinParams *fw; +fileStruct *fs; + + fs = chgWin->fileInfo; + for(i=0; icurParamSet == i ) + continue; + fw = &(chkWin->editStack[i]); + if( fw->fileInfo != fs ) + continue; + if( delete ) + { /* May need to fix up ranges */ + if( firstLine <= fw->rangeTopNum ) + { + if( firstLine + numLines > fw->rangeTopNum ) + { + fw->rangeTopNum = 0; + } + else + { + fw->rangeTopNum -= numLines; + } + } + if( firstLine <= fw->rangeBotNum ) + { + if( firstLine + numLines > fw->rangeBotNum ) + { + fw->rangeBotNum = 0; + } + else + { + fw->rangeBotNum -= numLines; + } + } + } + else + { /* Adding lines */ + if( fw->rangeTopNum >= firstLine ) + fw->rangeTopNum += numLines; + if( fw->rangeBotNum >= firstLine ) + fw->rangeBotNum += numLines; + } + } +} + +checkUpdate(long long firstLine, long long numLines, int delete) +{ +windowStruct *cw, *w; +long long cnt; +int dirty=0; + + cw = globalData.activeWindow; + for(w=globalData.windowList; w; w=w->next) + { + /* Do any of the alternate files need fixing up ? */ + checkUpdateAlternate(cw, w, firstLine, numLines, delete); + /* Main window may need range fixup */ + if( w == cw ) + { + if( delete ) + { /* May need to fix up ranges */ + if( firstLine <= w->rangeTopNum ) + { + if( firstLine + numLines > w->rangeTopNum ) + { + w->rangeTopNum = 0; + } + else + { + w->rangeTopNum -= numLines; + } + } + if( firstLine <= w->rangeBotNum ) + { + if( firstLine + numLines > w->rangeBotNum ) + { + w->rangeBotNum = 0; + } + else + { + w->rangeBotNum -= numLines; + } + } + } + else + { /* Adding lines */ + if( w->rangeTopNum >= firstLine ) + w->rangeTopNum += numLines; + if( w->rangeBotNum >= firstLine ) + w->rangeBotNum += numLines; + } + } + else if(w->fileInfo == cw->fileInfo ) + { /* May interact */ + if( delete ) + { /* Deleting, did we eat the top line, range etc */ + if( firstLine <= w->topOffset + 1 ) + { + if( firstLine + numLines >= w->topOffset +1 ) + { /* Delete includes top line, reset top line to start of delete */ + w->topOffset = firstLine-1; + w->topLine = NULL; /* Mark invalid */ + dirty = 1; + } + else /* Delete completely before our top, just subtract */ + w->topOffset -= numLines; + if( w->topOffset < 0 ) + w->topOffset = 0; + } + if( firstLine <= w->rangeTopNum ) + { + if( firstLine + numLines > w->rangeTopNum ) + { + w->rangeTopNum = 0; + } + else + { + w->rangeTopNum -= numLines; + } + } + if( firstLine <= w->rangeBotNum ) + { + if( firstLine + numLines > w->rangeBotNum ) + { + w->rangeBotNum = 0; + } + else + { + w->rangeBotNum -= numLines; + } + } + } + else + { /* Adding lines */ + /* Note topOffset is 0 based, ranges are 1 based */ + if( w->topOffset >= firstLine-1 ) + w->topOffset += numLines; + if( w->rangeTopNum >= firstLine ) + w->rangeTopNum += numLines; + if( w->rangeBotNum >= firstLine ) + w->rangeBotNum += numLines; + } + } + } + return(dirty); +} + +/* They have specified a full command on the command line */ +/* or just a number for a goto line command */ +processCmd(char *execString) +{ +char *cmdPtrs[20], *originalArgs; +int inArg, inQuote, numArgs, cmdIsInt=1, i, c, len; +cmdStruct *cmd; + + if( execString[0] == '\0' ) + { + updateCursor(globalData.activeWindow); + return(1); + } + inArg=numArgs=inQuote = 0; + cmdPtrs[1] = ""; + len = strlen(execString); + originalArgs = (char *) alloca(len); + originalArgs[0] = '\0'; + for(i=0; i 0 ) + { + if( globalData.markSet && cmd->flags & ILLEGAL_IN_MARK ) + dingMsg("Can't do that with marks set"); + else if( cmd->flags & ORIGINAL_ARGS ) + { + cmdPtrs[1] = originalArgs; + return((*cmd->func)(2, cmdPtrs)); + } + else + return((*cmd->func)(numArgs, cmdPtrs)); + } + else + { + char tmp[30]; + + if( strlen(cmdPtrs[0]) > 15 ) + cmdPtrs[0][15] = '\0'; + sprintf(tmp, "%s: not defined", cmdPtrs[0]); + emsg(tmp); + } + return(0); +} + +/* Goto cmd always expects just the one arg, skip the argc/argv option */ +gotoCmd(int argc, char **argv) +{ +char *arg; +long long lnum; +windowStruct *w; + + w = globalData.activeWindow; + if( argc != 2 || !(arg=argv[1]) ) + { + emsg("Need a single argument to goto"); + updateCursor(w); + return(1); + } + + lnum = atoll(arg); + return(gotoline(w, lnum)); +} + +/* "0" is the 1st line of the file, etc, to numLines-1 */ +/* if current topLine is NULL, must use bottom or top only */ +getLine(windowStruct *w, fileStruct *fs, long long lnum, lineStruct **lsp) +{ +long long midline, midc, middiff, taildiff, i; +lineStruct *ls, *ns; +char tmp[20]; + + if( w->topLine == NULL ) + { + if( lnum >= fs->numLines ) /* Extending file */ + goto EXTEND; + if( lnum < fs->numLines - lnum ) + goto HEAD; + goto TAIL; + } + + if( w->topOffset == lnum ) + { + *lsp = w->topLine; + return(1); + } + + middiff = lnum - w->topOffset; + if( middiff < 0 ) + midc = -middiff; + else + midc = middiff; + if( midc <= lnum ) /* Cheaper to start at top offset */ + { + if( lnum >= fs->numLines ) /* Extending file */ + { +EXTEND: +/*emsg("EXTEND");*/ + ls = fs->tail; + for(i=fs->numLines; i<=lnum; i++) + { + ns = (lineStruct *) calloc(1, sizeof(lineStruct)); + ns->flags = 1; + ls->next = ns; + ns->prev = ls; + ls = ns; + fs->tail = ns; + fs->numLines++; + } + } + else if( fs->numLines - lnum < midc ) + { /* Cheaper to start at EOF */ +TAIL: +/*sprintf(tmp, "TAIL %lld", lnum); +emsg(tmp);*/ + ls = fs->tail; + for(i=fs->numLines-1; i>lnum; i--) + ls = ls->prev; + } + else if( middiff > 0 ) + { +/*emsg("mid-dn");*/ + ls = w->topLine; + for(i=w->topOffset; inext; + } + else /* Go backwards from top offset */ + { +/*emsg("mid-up");*/ + ls = w->topLine; + for(i=w->topOffset; i>lnum; i--) + ls = ls->prev; + } + } + else /* Cheaper to start in the beginning */ + { +HEAD: +/*emsg("HEAD");*/ + ls = fs->head; + for(i=0; inext; + } + *lsp = ls; + return(1); +} + +/* get the pointer to the current line struct at the current cursor position */ +/* If line does not exist, create */ +getCursorLine(windowStruct *w, lineStruct **lsp) +{ +fileStruct *fs; +lineStruct *ls, *ns; +int i; + + /* Do we have it already ? */ + if( (*lsp = w->cursorLine) ) + return(1); /* Yes */ + + for(ls=w->topLine, i=1; icursorLineNo; i++) + { + if( ls->next ) + ls = ls->next; + else + { + ns = (lineStruct *) calloc(1, sizeof(lineStruct)); + ns->flags = 1; + ls->next = ns; + ns->prev = ls; + ls = ns; + fs = w->fileInfo; + fs->tail = ns; + fs->numLines++; + } + } + *lsp = ls; + w->cursorLine = ls; /* Also update so we can get it fast */ + return(1); +} + +gotoline(windowStruct *w, long long lnum) +{ +long long curLine, newTopLineOffset; +int i; +fileStruct *fs; +lineStruct *ls; + + if( (fs=w->fileInfo) == NULL ) + return(0); + + w->cursorLine = NULL; + curLine = w->topOffset + w->cursorLineNo; + if( lnum < 0 ) + { + if( curLine + lnum < 1 ) + { + w->topOffset = 0; + w->cursorLineNo = 1; + w->topLine = fs->head; + redrawWindow(w); + goto CHECKR; + } + lnum = curLine + lnum; + } + else if( lnum == 0 ) + { + updateCursor(w); + return(1); + } + + if( lnum == 1) /* Beginning of file */ + { + w->topOffset = 0; + w->cursorLineNo = 1; + w->topLine = fs->head; + redrawWindow(w); + goto CHECKR; + } + + if( lnum > w->topOffset && lnum < w->topOffset + w->height ) + { + w->cursorLineNo = lnum - w->topOffset; + updateStatus(); + updateCursor(w); + goto CHECKR; + } + + newTopLineOffset = lnum - (w->height -2)/2; + if( newTopLineOffset < 0 ) + newTopLineOffset = 0; + if( getLine(w, fs, newTopLineOffset, &ls) ) + { + w->topLine = ls; + w->topOffset = newTopLineOffset; + w->cursorLineNo = lnum - newTopLineOffset; + redrawWindow(w); +CHECKR: + if( w->rangeTopNum && + w->rangeTopNum > lnum ) + dingMsg("Out of range"); + if( w->rangeBotNum && + w->rangeBotNum < lnum ) + dingMsg("Out of range"); + return(1); + } + return(0); +} + +/* Cursor commands, move up, down, right left one or more spots */ +/* The first set is the actual command, the 2n the I/F to the user */ +cursorUp(int cnt) +{ +int i; +long long lnum; +windowStruct *w=globalData.activeWindow; +fileStruct *fs; + + if( !(fs=w->fileInfo) ) + return(0); + + w->cursorLine = NULL; + if( w->rangeTopNum ) + { /* Did we go out of bounds ? */ + if( w->rangeTopNum > w->topOffset + w->cursorLineNo - cnt ) + { + dingMsg("Range limited"); + return(1); + } + } + if( cnt == 0 ) + { + if( w->rangeTopNum && + w->rangeTopNum > w->topOffset ) + w->cursorLineNo = w->rangeTopNum - w->topOffset; + else + w->cursorLineNo = 1; + updateStatus(); + printf("\033[%d;%dH", w->y+w->cursorLineNo, w->x+w->cursorX); + } + else if( cnt >= w->cursorLineNo ) + { + i = w->cursorLineNo - 1; + w->cursorLineNo -= i; + cnt -= i; + for(i=0; itopOffset > 0; i++) + { + w->topLine = w->topLine->prev; + w->topOffset--; + } + redrawWindow(w); + } + else + { + w->cursorLineNo -= cnt; + updateStatus(); + printf("\033[%d;%dH", w->y+w->cursorLineNo, w->x+w->cursorX); + } + return(1); +} + +cursorDn(int cnt) +{ +int i; +windowStruct *w=globalData.activeWindow; +fileStruct *fs; +lineStruct *ls, *ns; + + if( !(fs=w->fileInfo) ) + return(0); + + w->cursorLine = NULL; + if( w->rangeBotNum ) + { /* Did we go out of bounds ? */ + if( w->rangeBotNum < w->topOffset + w->cursorLineNo + cnt ) + { + dingMsg("Range limited"); + return(1); + } + } + if( cnt == 0 ) + { + if( w->rangeBotNum && + w->topOffset + w->height - 1 > w->rangeBotNum ) + w->cursorLineNo = w->rangeBotNum - w->topOffset; + else + w->cursorLineNo = w->height-1; + updateStatus(); + printf("\033[%d;%dH", w->y+w->cursorLineNo, w->x+w->cursorX); + } + else if( cnt >= w->height - w->cursorLineNo ) + { + i = w->height - w->cursorLineNo - 1; + w->cursorLineNo += i; + cnt -= i; + for(i=0, ls=w->topLine; itopOffset++; + if( ls->next ) + ls = w->topLine = ls->next; + else + { + ns = (lineStruct *) calloc(1, sizeof(lineStruct)); + ns->flags = 1; + ls->next = ns; + ns->prev = ls; + ls = w->topLine = ns; + fs->tail = ns; + fs->numLines++; + } + } + redrawWindow(w); + } + else + { + w->cursorLineNo += cnt; + updateStatus(); + printf("\033[%d;%dH", w->y+w->cursorLineNo, w->x+w->cursorX); + } + return(1); +} + +cursorUpCmd(int argc, char **argv) +{ +char *arg; +int cnt=1; +windowStruct *w; + + w = globalData.activeWindow; + if( argc > 2 ) + { + emsg("At most one arg to cursor command"); + updateCursor(w); + return(1); + } + if( argc == 2 && (arg=argv[1]) ) + { + if( arg[0] ) + cnt = atoi(arg); + else + cnt = 0; + } + if( cnt >= 0 ) + cursorUp(cnt); + else if( cnt < 0 ) + cursorDn(-cnt); +} +cursorDnCmd(int argc, char **argv) +{ +char *arg; +int cnt=1; +windowStruct *w; + + w = globalData.activeWindow; + if( argc > 2 ) + { + emsg("At most one arg to cursor command"); + updateCursor(w); + return(1); + } + if( argc == 2 && (arg=argv[1]) ) + { + if( arg[0] ) + cnt = atoi(arg); + else + cnt = 0; + } + if( cnt >= 0 ) + cursorDn(cnt); + else if( cnt < 0 ) + cursorUp(-cnt); +} + +/* Move at most cnt spaces leftward; Adjust leftOffset if needed */ +cursorLeft(int cnt) +{ +int i; +windowStruct *w=globalData.activeWindow; +fileStruct *fs; +lineStruct *ls, *ns; + + if( !(fs=w->fileInfo) ) + return(0); + + if( cnt == 0 ) + { + w->cursorX = 1; + updateStatus(); + printf("\033[%d;%dH", w->y+w->cursorLineNo, w->x+w->cursorX); + } + else if( cnt > w->cursorX - 1 ) + { + if( w->leftOffset == 0 ) + { + w->cursorX = 1; + updateStatus(); + updateCursor(w); + } + else + { + i = w->cursorX - 1; + w->cursorX -= i; + cnt -= i; + if( cnt > w->leftOffset ) + w->leftOffset = 0; + else + w->leftOffset -= cnt; + redrawWindow(w); + } + } + else + { + w->cursorX -= cnt; + updateStatus(); + printf("\033[%d;%dH", w->y+w->cursorLineNo, w->x+w->cursorX); + } + return(1); +} + +cursorRight(int cnt) +{ +int i; +windowStruct *w=globalData.activeWindow; +fileStruct *fs; +lineStruct *ls, *ns; +char *line; + + if( !(fs=w->fileInfo) ) + return(0); + + if( cnt == 0 ) + { + getCursorLine(w, &ls); + i = getChars(fs, ls, ls->numChars+1, &line); + /* Backup to first non-blank */ + for( ; i>0; i--) + if( line[i-1] != ' ') + break; + if( i < w->leftOffset + w->cursorX ) + w->cursorX = w->width - 1; + else + { + if( i - w->leftOffset < w->width-1 ) + w->cursorX = 1 + i - w->leftOffset; + else + { + w->leftOffset = i - w->width + 5; + w->cursorX = 1 + i - w->leftOffset; + redrawWindow(w); + } + } + updateStatus(); + printf("\033[%d;%dH", w->y+w->cursorLineNo, w->x+w->cursorX); + } + else if( cnt >= w->width - w->cursorX ) + { + i = w->width - w->cursorX - 1; + w->cursorX += i; + cnt -= i; + w->leftOffset += cnt; + redrawWindow(w); + } + else + { + w->cursorX += cnt; + updateStatus(); + printf("\033[%d;%dH", w->y+w->cursorLineNo, w->x+w->cursorX); + } + return(1); +} + +cursorLeftCmd(int argc, char **argv) +{ +char *arg; +int cnt=1; +windowStruct *w; + + w = globalData.activeWindow; + if( argc > 2 ) + { + emsg("At most one arg to cursor command"); + updateCursor(w); + return(1); + } + if( argc == 2 && (arg=argv[1]) ) + { + if( arg[0] ) + cnt = atoi(arg); + else + cnt = 0; + } + if( cnt >= 0 ) + cursorLeft(cnt); + else if( cnt < 0 ) + cursorRight(-cnt); +} +cursorRightCmd(int argc, char **argv) +{ +char *arg; +int cnt=1; +windowStruct *w; + + w = globalData.activeWindow; + if( argc > 2 ) + { + emsg("At most one arg to cursor command"); + updateCursor(w); + return(1); + } + if( argc == 2 && (arg=argv[1]) ) + { + if( arg[0] ) + cnt = atoi(arg); + else + cnt = 0; + } + if( cnt >= 0 ) + cursorRight(cnt); + else if( cnt < 0 ) + cursorLeft(-cnt); +} + +tabRightCmd(int argc, char **argv) +{ +char *arg; +int tcnt=1, cnt, pos; +windowStruct *w = globalData.activeWindow; + + if( argc > 2 ) + { + emsg("At most one arg to tab command"); + updateCursor(w); + return(1); + } + if( argc == 2 && (arg=argv[1]) ) + tcnt = atoi(arg); + + pos = w->leftOffset + w->cursorX - 1; + if( tcnt > 0 ) + { + cnt = tcnt*globalData.tabSpace - (pos%globalData.tabSpace); + cursorRight(cnt); + } + else if( tcnt < 0 ) + { + cnt = (pos%globalData.tabSpace); + if( cnt == 0 ) + cnt = 4; + cnt += (-1-tcnt)*globalData.tabSpace; + cursorLeft(cnt); + } +} + +tabLeftCmd(int argc, char **argv) +{ +char *arg; +int tcnt=1, cnt, pos; +windowStruct *w; + + w = globalData.activeWindow; + if( argc > 2 ) + { + emsg("At most one arg to tab command"); + updateCursor(w); + return(1); + } + if( argc == 2 && (arg=argv[1]) ) + tcnt = atoi(arg); + tcnt = -tcnt; + pos = w->leftOffset + w->cursorX -1; + if( tcnt > 0 ) + { + cnt = tcnt*globalData.tabSpace - (pos%globalData.tabSpace); + cursorRight(cnt); + } + else if( tcnt < 0 ) + { + cnt = (pos%globalData.tabSpace); + if( cnt == 0 ) + cnt = 4; + cnt += (-1-tcnt)*globalData.tabSpace; + cursorLeft(cnt); + } +} + +returnCmd(int argc, char **argv) +{ +char *arg; +int cnt=1; +windowStruct *w = globalData.activeWindow; + + if( argc > 2 ) + { + emsg("At most one arg to goto command"); + updateCursor(w); + return(1); + } + if( argc == 2 && (arg=argv[1]) ) + cnt = atoi(arg); + if( cnt <= 0 ) + return(0); + cursorDn(cnt); + cursorLeft(w->leftOffset+w->cursorX); + return(1); +} + +/* Move cnt lines up the file */ +/* Move the cursor with it is unless we cannot go higher */ +scrollUp(int cnt) +{ +windowStruct *w = globalData.activeWindow; +fileStruct *fs; +int ii; +long long i, j; + + if( !(fs=w->fileInfo) ) + return(0); + + w->cursorLine = NULL; + if( cnt == 0) + { /* Make this line the bottom line of the window */ + cnt = w->height-w->cursorLineNo-1; + /* unless we are limited by top of file */ + if( w->topOffset + w->cursorLineNo < w->height ) + { /* Yep we are limited to no more than moving w->topOffset */ + i = w->topOffset + w->cursorLineNo; + w->topOffset = 0; + w->topLine = fs->head; + w->cursorLineNo = i; + redrawWindow(w); + return(1); + } + } + else if( w->rangeTopNum > w->topOffset + w->cursorLineNo - cnt ) + { + if( w->rangeTopNum ) + dingMsg("Range limited" ); + cnt = w->topOffset + w->cursorLineNo - w->rangeTopNum; + if( cnt <= 0 ) + return(1); + } + if(w->topOffset-cnt<0) + { /* Up to top **/ + i = cnt - w->topOffset; + w->topOffset = 0; + w->topLine = fs->head; + j = w->cursorLineNo - i; + if( j < 1 ) + w->cursorLineNo = 1; + else + w->cursorLineNo = j; + } + else + { + w->topOffset -= cnt; + for(ii=0; iitopLine = w->topLine->prev; + if( w->height > w->cursorLineNo + cnt ) + w->cursorLineNo += cnt; + } + redrawWindow(w); + return(1); +} + +scrollDn(int cnt) +{ +windowStruct *w = globalData.activeWindow; +fileStruct *fs; +int i; +lineStruct *ls, *ns; + + if( !(fs=w->fileInfo) ) + return(0); + + w->cursorLine = NULL; + if( cnt == 0) + { /* Make this line the top line */ + cnt = w->cursorLineNo-1; + } + else if( w->rangeBotNum && + w->rangeBotNum < w->topOffset + w->cursorLineNo + cnt ) + { + cnt = w->rangeBotNum - (w->topOffset + w->cursorLineNo); + if( cnt <= 0 ) + { + dingMsg("Range limited"); + return(1); + } + } + ls = w->topLine; + for(i=0; inext ) + ls = ls->next; + else + { + ns = (lineStruct *) calloc(1, sizeof(lineStruct)); + ns->flags = 1; + ns->prev = ls; + ls->next = ns; + fs->tail = ns; + ls = ns; + fs->numLines++; + } + } + w->topOffset += cnt; + if( w->cursorLineNo > cnt ) + w->cursorLineNo -= cnt; + w->topLine = ls; + redrawWindow(w); + return(1); +} + +scrollUpCmd(int argc, char **argv) +{ +char *arg; +windowStruct *w = globalData.activeWindow; +int cnt=0; + + if( argc > 2 ) + { + emsg("At most one arg to scroll command"); + updateCursor(w); + return(1); + } + if( argc == 2 && (arg=argv[1]) ) + cnt = atoi(arg); + else + cnt = w->height/2; + if( cnt >= 0) + scrollUp(cnt); + else if( cnt < 0 ) + scrollDn(-cnt); +} +scrollDnCmd(int argc, char **argv) +{ +char *arg; +windowStruct *w = globalData.activeWindow; +int cnt=0; + + if( argc > 2 ) + { + emsg("At most one arg to scroll command"); + updateCursor(w); + return(1); + } + if( argc == 2 && (arg=argv[1]) ) + cnt = atoi(arg); + else + cnt = w->height/2; + if( cnt >= 0) + scrollDn(cnt); + else if( cnt < 0 ) + scrollUp(-cnt); +} + +/* Move cnt whole pages upwards. A cnt of 0 implies goto to top of file */ +pageUp(int cnt) +{ +windowStruct *w = globalData.activeWindow; +fileStruct *fs; +long long lcnt, i, effTopLine; + + if( !(fs=w->fileInfo) ) + return(0); + + if( w->rangeTopNum ) + effTopLine = w->rangeTopNum; + else + effTopLine = 1; + if( cnt == 0 ) + return(gotoline(w, effTopLine)); + + w->cursorLine = NULL; + lcnt = ((long long)cnt) * (w->height-1); + if( w->topOffset + w->cursorLineNo - lcnt <= effTopLine ) + { + if( w->topOffset == effTopLine ) + { + w->cursorLineNo = 1; + updateStatus(); + updateCursor(w); + } + return(gotoline(w, effTopLine)); + } + + i = w->topOffset - lcnt; + if( i <= w->cursorLineNo ) + return(gotoline(w, w->topOffset + w->cursorLineNo - lcnt)); + + for(i=0; itopOffset>0; i++) + { + w->topOffset--; + w->topLine = w->topLine->prev; + } + redrawWindow(w); + return(1); +} + +pageDn(int cnt) +{ +windowStruct *w = globalData.activeWindow; +fileStruct *fs; +lineStruct *ls, *ns; +long long lcnt, numLines, topOffset, i, effBotLine; +int j; + + if( !(fs=w->fileInfo) ) + return(0); + w->cursorLine = NULL; + if( cnt == 0 ) + { /* Goto EOF, harder than it seems b/c we may have added empties */ + if( w->rangeBotNum ) + return(gotoline(w, w->rangeBotNum)); + ls = fs->tail; + numLines = fs->numLines; + /* Skip any fillers */ + while( (ls->flags & 1) && ls->prev ) + { + numLines--; + ls = ls->prev; + } + if( numLines < w->height ) /* Small file check, easier */ + { + i= fs->numLines; + return(gotoline(w, i)); + } + /* Now skip back another 1/2 page, but we already have moved 1 more line */ + for(topOffset=numLines-1,j=2; jheight/2; j++) + { + ls=ls->prev; + topOffset--; + } + w->topLine = ls; + w->topOffset = topOffset; + w->cursorLineNo = j; + redrawWindow(w); + return(1); + } + + lcnt = ((long long)cnt) * (w->height-1); + if( w->rangeBotNum ) + { + if( w->rangeBotNum < w->topOffset + w->cursorLineNo + lcnt ) + return(gotoline(w, w->rangeBotNum)); + } + ls = w->topLine; + for(i=0; inext ) + ls = ls->next; + else + { + ns = (lineStruct *) calloc(sizeof(lineStruct), 1); + ns->flags = 1; + ns->prev = ls; + ls->next = ns; + ls = ns; + fs->tail = ls; + fs->numLines++; + } + } + w->topOffset+=lcnt; + w->topLine = ls; + redrawWindow(w); + return(1); +} + +pageUpCmd(int argc, char **argv) +{ +char *arg; +int cnt=1; +windowStruct *w; + + w = globalData.activeWindow; + if( argc > 2 ) + { + emsg("At most one arg to page command"); + updateCursor(w); + return(1); + } + if( argc == 2 && (arg=argv[1]) ) + cnt = atoi(arg); + if( cnt >= 0 ) + pageUp(cnt); + else if( cnt < 0 ) + pageDn(-cnt); +} +pageDnCmd(int argc, char **argv) +{ +char *arg; +int cnt=1; +windowStruct *w; + + w = globalData.activeWindow; + if( argc > 2 ) + { + emsg("At most one arg to page command"); + updateCursor(w); + return(1); + } + if( argc == 2 && (arg=argv[1]) ) + cnt = atoi(arg); + if( cnt >= 0 ) + pageDn(cnt); + else if( cnt < 0 ) + pageUp(-cnt); +} + +pageLeft(int charCnt) +{ +windowStruct *w = globalData.activeWindow; + + if( charCnt == 0 ) + w->leftOffset = 0; + if( w->leftOffset < charCnt ) + w->leftOffset = 0; + else + w->leftOffset -= charCnt; + redrawWindow(w); + return(1); +} + +pageRight(int charCnt) +{ +windowStruct *w = globalData.activeWindow; + + w->leftOffset += charCnt; + redrawWindow(w); + return(1); +} + +pageLeftCmd(int argc, char **argv) +{ +char *arg; +int cnt=1; +windowStruct *w; + + w = globalData.activeWindow; + if( argc > 2 ) + { + emsg("At most one arg to page command"); + updateCursor(w); + return(1); + } + if( argc == 2 && (arg=argv[1]) ) + cnt = atoi(arg); + else + cnt = 8; + if( cnt >= 0 ) + pageLeft(cnt); + else if( cnt < 0 ) + pageRight(-cnt); +} +pageRightCmd(int argc, char **argv) +{ +char *arg; +int cnt=1; +windowStruct *w; + + w = globalData.activeWindow; + if( argc > 2 ) + { + emsg("At most one arg to page command"); + updateCursor(w); + return(1); + } + if( argc == 2 && (arg=argv[1]) ) + cnt = atoi(arg); + else + cnt = 8; + if( cnt > 0 ) + pageRight(cnt); + else if( cnt < 0 ) + pageLeft(-cnt); + else + updateCursor(globalData.activeWindow); +} + +statusCmd(int argc, char **argv) +{ +windowStruct *w; +fileStruct *fs; +int i, j, k; + + /* Clear screen */ + printf("\033[2J\033[1;1H"); + for(w=globalData.windowList; w; w=w->next) + { + printf("Window %d: xy %d %d w/h %d %d\r\n", w->winNum, + w->x, w->y, w->width, w->height); + printf(" left offset %d top offset %lld cursor offset %d down %d\n\r", + w->leftOffset, w->topOffset, w->cursorX, w->cursorLineNo); + if( w->rangeTopNum || w->rangeBotNum ) + printf(" Range set from %lld to %lld\n", + w->rangeTopNum, w->rangeBotNum); + if( (fs=w->fileInfo) ) + { + for(j=0; jcurParamSet ) + { + fs = w->fileInfo; + printf("Main file(%d): %s\n\r", j, fs->fileName); + } + else if( !(fs=w->editStack[j].fileInfo) ) + continue; + else + printf("Alternate file(%d): %s\n\r", j, fs->fileName); + printf(" backed up? %d nosave? %d new? %d ro? %d modified? %d #lines %lld\n\r", + fs->backupWritten, fs->nosave, fs->created, + fs->ro, fs->modified, fs->numLines); + } + } + } + if( globalData.cutBuffer ) + { + if( globalData.cutBuffer->mode == 0 ) + printf("Cut buffer has %d lines\n\r", globalData.cutBuffer->numLines); + else + printf("Cut buffer has %dx%d block\n\r", globalData.cutBuffer->numLines, + globalData.cutBuffer->width); + } + if( globalData.getBuffer ) + { + if( globalData.getBuffer->mode == 0 ) + printf("Get buffer has %d lines\n\r", globalData.getBuffer->numLines); + else + printf("Get buffer has %dx%d block\n\r", globalData.getBuffer->numLines, + globalData.getBuffer->width); + } + /* Because now we are non-blocking, wait for a real char */ + while( getc(stdin) == EOF) + ; + redrawScreen(); + return(1); +} + +saveEditStack(windowStruct *w, int k) +{ + memcpy( &w->editStack[k], &w->topOffset, sizeof(fileWinParams)); + return(1); +} +/* With no args, switch to next file in window stack. With 1 arg, open file and + push onto edit stack */ +/* arg 2 is top offset, 3 is left offset 4 cursorY, 5, is cursorX */ +editFileCmd(int argc, char **argv) +{ +windowStruct *w = globalData.activeWindow; +fileStruct *fs; +lineStruct *ls; +long long lnum; +int j, k; + + w->cursorLine = NULL; + if( argc == 1 ) + { /* Switch files */ + k = w->curParamSet; + for(j=(k+1)%NUM_ALT_FILES; j!=k; j = (j+1)%NUM_ALT_FILES) + if( w->editStack[j].fileInfo ) + break; + if( j == k ) + { + dingMsg("No alternate file"); + updateCursor(w); + return(0); + } + /* Copy the params to save and switch files */ + saveEditStack(w, k); + /* Now, push the old file as current */ + w->curParamSet = j; + w->leftOffset = w->editStack[j].leftOffset; + if( w->editStack[j].cursorX < w->width-1 ) + w->cursorX = w->editStack[j].cursorX; + else + w->cursorX = w->width-1; + if( w->editStack[j].cursorLineNo < w->height-1) + w->cursorLineNo = w->editStack[j].cursorLineNo; + else + w->cursorLineNo = w->height - 1; + fs = w->fileInfo = w->editStack[j].fileInfo; + if( w->editStack[j].topOffset < fs->numLines ) + w->topOffset = w->editStack[j].topOffset; + else + w->topOffset = fs->numLines-4; + w->fileInfo = w->editStack[j].fileInfo; + w->rangeTopNum = w->editStack[j].rangeTopNum; + w->rangeBotNum = w->editStack[j].rangeBotNum; + w->topLine = NULL; /* So getline knows it can't use topLine */ + /* Jump to top line */ + getLine(w, w->fileInfo, w->topOffset, &ls); + w->topLine = ls; + redrawWindow(w); + return(1); + } + saveEditStack(w, w->curParamSet); + if( openFile(argv[1], w) == 0 ) + return(0); + fs = w->fileInfo; + /* Update param set number */ + j = (w->curParamSet+1) % NUM_ALT_FILES; + w->curParamSet = j; + if( argc > 2 ) + { + lnum = atoll(argv[2]); + if( lnum >= fs->numLines-4 ) + lnum = fs->numLines-4; + if( lnum < 0 ) + lnum = 0; + getLine(w, fs, lnum, &ls); + w->topOffset = lnum; + w->topLine = ls; + } + if( argc > 3 ) + { + j = atoi(argv[3]); + if( j > 0 ) + w->leftOffset = j; + } + if( argc > 4 ) + { + j = atoi(argv[4]); + if( j > 0 && j < w->height ) + w->cursorLineNo = j; + } + if( argc > 5 ) + { + j = atoi(argv[5]); + if( j > 0 && j < w->width ) + w->cursorX = j; + } + w->rangeTopNum = w->rangeBotNum = 0; + redrawWindow(w); + return(1); +} + +/* Just unload the current file from the list of files for the window */ +/* Takes no args */ +uneditFileCmd(int argc, char **argv) +{ +windowStruct *w = globalData.activeWindow; +fileStruct *fs; +lineStruct *ls; +long long lnum; +int j, k; + + if( argc != 1 ) + { + emsg("-edit takes no args"); + updateCursor(w); + return(0); + } + + /* Make sure there is an alternate to switch to */ + k = w->curParamSet; + for(j=(k+1)%NUM_ALT_FILES; j!=k; j = (j+1)%NUM_ALT_FILES) + if( w->editStack[j].fileInfo ) + break; + if( j == k ) + { + dingMsg("No alternate file"); + updateCursor(w); + return(0); + } + w->cursorLine = NULL; + /* Unload the file from the edit stack */ + w->editStack[k].fileInfo = NULL; + + /* Now, push the old file as current */ + w->curParamSet = j; + w->leftOffset = w->editStack[j].leftOffset; + if( w->editStack[j].cursorX < w->width-1 ) + w->cursorX = w->editStack[j].cursorX; + else + w->cursorX = w->width-1; + if( w->editStack[j].cursorLineNo < w->height-1) + w->cursorLineNo = w->editStack[j].cursorLineNo; + else + w->cursorLineNo = w->height - 1; + fs = w->fileInfo = w->editStack[j].fileInfo; + if( w->editStack[j].topOffset < fs->numLines ) + w->topOffset = w->editStack[j].topOffset; + else + w->topOffset = fs->numLines-4; + w->fileInfo = w->editStack[j].fileInfo; + w->rangeTopNum = w->editStack[j].rangeTopNum; + w->rangeBotNum = w->editStack[j].rangeBotNum; + w->topLine = NULL; /* So getline knows it can't use topLine */ + /* Jump to top line */ + getLine(w, w->fileInfo, w->topOffset, &ls); + w->topLine = ls; + redrawWindow(w); + return(1); +} + +/* With no args, just split the window. With an arg, split and open new file */ +addWindowCmd(int argc, char **argv) +{ +windowStruct *w = globalData.activeWindow; +fileStruct *fs; +lineStruct *ls; +windowStruct *wnew; +int row, col; +char *fName = NULL; + + w->cursorLine = NULL; + if( argc > 1 && argv[1] && argv[1][0] != '\0') + { + if( argv[1][0] == '"' && argv[1][1] == '"' ) + ; /* Special case of "" seen at startup */ + else + fName = argv[1]; + } + if( argc > 3 ) + { /* row col spec'ed */ + row = atoi(argv[2]); + col = atoi(argv[3]); + } + else + { + row = w->cursorLineNo; + col = w->cursorX; + } + fs = w->fileInfo; + if( col == 1 ) + { + if( row <= 1 || row >= w->height-1) + { + dingMsg("Can't put a window there"); + updateCursor(w); + return(0); + } + /* Add a horizontal window */ + wnew = (windowStruct *) malloc(sizeof(windowStruct)); + memcpy(wnew, w, sizeof(windowStruct)); + wnew->cutPosition = row; + wnew->parent = w; + wnew->splitVertical = 0; + wnew->y = w->y + wnew->cutPosition; + w->cursorLineNo = row-1; + wnew->cursorLineNo = 1; + /* Ensure the line exists */ + if( fs ) + { + wnew->topOffset = w->topOffset + w->cursorLineNo+1; + getLine(w, fs, wnew->topOffset, &ls); + wnew->topLine = ls; + } + wnew->height = 1 + w->height - (1+wnew->cutPosition); + w->height -= wnew->height; + wnew->next = globalData.windowList; + globalData.windowList = wnew; + globalData.activeWindow = wnew; + } + else if( row != 1 ) + { + dingMsg("Can't put a window there"); + updateCursor(w); + return(0); + } + else + { /* Add a vertical window */ + if( col <= 1 || col >= w->width-1) + { + dingMsg("Can't put a window there"); + updateCursor(w); + return(0); + } + wnew = (windowStruct *) malloc(sizeof(windowStruct)); + memcpy(wnew, w, sizeof(windowStruct)); + wnew->cutPosition = col; + wnew->parent = w; + wnew->cursorX = 1; + wnew->splitVertical = 1; + wnew->x = w->x + wnew->cutPosition; + w->cursorX = col - 1; + wnew->width = 1 + w->width - (wnew->cutPosition+1); + w->width -= wnew->width; + wnew->next = globalData.windowList; + globalData.windowList = wnew; + globalData.activeWindow = wnew; + } + wnew->winNum = wnew->next->winNum+1; + if( fName ) + { + char *argvx[2]; + + argvx[0] = "editFileCmd"; + argvx[1] = fName; + editFileCmd(2, argvx); + } + redrawScreen(); + return(1); +} + +/* Delete the last added window. No args */ +delWindowCmd(int argc, char **argv) +{ +windowStruct *w = globalData.windowList; +windowStruct *wp = w->parent; + + if( w->next == NULL ) + { + dingMsg("Can't delete last window"); + updateCursor(w); + return(0); + } + if( w->splitVertical ) + wp->width += w->width; + else + wp->height += w->height; + if( globalData.activeWindow == w ) + globalData.activeWindow = wp; + globalData.windowList = w->next; + free(w); + redrawScreen(); + return(1); +} + +chgWindowCmd(int argc, char **argv) +{ +windowStruct *w=globalData.activeWindow; +int wNum; + + /* With no args, just jump to the next window in line */ + if( argc < 2 ) + { + if( w->next ) + globalData.activeWindow = w->next; + else + globalData.activeWindow = globalData.windowList; + redrawScreen(); + updateCursor(globalData.activeWindow); + return(1); + } + wNum = atoi(argv[1]); + /* Change to this window number */ + for(w=globalData.windowList; w; w=w->next ) + if( w->winNum == wNum ) + break; + if( w ) + { + globalData.activeWindow = w; + redrawScreen(); + updateCursor(w); + } + return(0); +} + +/* Line edit commands (addChar is in main.c) */ +/* Delete the character under the cursor and move remaininf character left */ +/* This is a destructive delete */ +wipeCharCmd(int argc, char **argv) +{ +int i, ix, ixx, cnt=1; +windowStruct *w = globalData.activeWindow; +fileStruct *fs = w->fileInfo; +lineStruct *ls; +char *line; + + if( fs == NULL ) + { + dingMsg("No file open"); + return(0); + } + if( argc > 1 && argv[1][0] ) + cnt = atoi(argv[1]); + if( cnt <= 0 ) + return(0); + + /* Get the correct line */ + if( !getCursorLine(w, &ls) ) + return(0); + /* remove test for short lines. Because if tabs, we don't know how long */ + /* the line really is */ + if( ls->numCharsAvail == 0 ) /* Not in memory */ + unpackDiskLine(fs, ls); + /* After line is unpacked, we know the real char count */ + if( ls->numChars < w->cursorX + w->leftOffset ) + return(0); /* Nothing to do */ + + if( !canModifyFile(fs) ) + return(0); + + fs->head->flags = fs->head->flags & ~1; + ix = w->cursorX + w->leftOffset-1; + ixx = ix + cnt; + if( ixx >= ls->numChars ) + { + ls->numChars = ix; + ls->data.line[ix] = '\0'; + } + else + { + memmove( &(ls->data.line[ix]), + &(ls->data.line[ixx]), 1+ls->numChars - ixx); + ls->numChars -= cnt; + } + redrawLine(w, w->cursorLineNo, ls); + updateCursor(w); + return(1); +} + +/* Delete the character before the cursor and move remaining character left */ +/* if in insert mode, or if overwrite, just delete prev char and move */ +/* This command does not accept a cnt, maybe it should? */ +deleteCharCmd(int argc, char **argv) +{ +int i, ix; +windowStruct *w = globalData.activeWindow; +fileStruct *fs = w->fileInfo; +lineStruct *ls; +char *line; + + if( fs == NULL ) + { + dingMsg("No file open"); + return(0); + } + + if( w->leftOffset + w->cursorX <= 1 ) + return(0); /* Can't go any further left */ + if( !getCursorLine(w, &ls) ) + return(0); + + if( ls->numCharsAvail == 0 ) /* Not in memory */ + unpackDiskLine(fs, ls); + if( ls->numChars+1 < w->cursorX + w->leftOffset ) + { + return(cursorLeft(1)); /* Nothing to do but move */ + } + + if( !canModifyFile(fs) ) + return(0); + fs->head->flags = fs->head->flags & ~1; + ix = w->cursorX + w->leftOffset-1; + + if( globalData.insertMode ) + { + memmove(&(ls->data.line[ix-1]), &ls->data.line[ix], + 1+ls->numChars-ix); + ls->numChars--; + } + else + ls->data.line[ix-1] = ' '; + + if( w->cursorX == 1) + { /* Need to redraw window from shift left 1 */ + w->leftOffset--; + redrawWindow(w); + } + else + { + w->cursorX--; + redrawLine(w, w->cursorLineNo, ls); + } + updateCursor(w); + return(1); +} + +/* If we are in mark, switch, if we have an arg to mark, cancel mark */ +/* Mark is tightly integrated with cut, get, open commands below */ +markCmd(int argc, char **argv) +{ +windowStruct *w = globalData.activeWindow; +int dx, x, cx; +long long dy, y, cy; + + if( argc > 1 ) /* We ignore any value */ + globalData.markSet = 0; + else if( globalData.markSet == 0 ) + { + globalData.markSet = 1; + globalData.markRefX = w->leftOffset + w->cursorX; + globalData.markRefY = w->topOffset + w->cursorLineNo; + } + else + { + w->cursorLine = NULL; + x = w->leftOffset + w->cursorX; + y = w->topOffset + w->cursorLineNo; + cx = globalData.markRefX; + cy = globalData.markRefY; + globalData.markRefX = x; + globalData.markRefY = y; + dx = cx - w->leftOffset; + dy = cy - w->topOffset; + if( dx > 0 && dx < w->width && dy > 0 && dy < w->height-1 ) + { + w->cursorX = dx; + w->cursorLineNo = dy; + } + else + { + if( dx <= 0 || dx >= w->width ) + { /* Need to fix left offset */ + if( cx < w->width ) + { /* Set offset to 0 */ + w->leftOffset = 0; + w->cursorX = cx; + } + else /* Center it */ + { /* Try to offset by 8's */ + w->leftOffset = cx - w->width/2; + w->cursorX = cx - w->leftOffset; + } + } + else /* Don't adjust leftoffset */ + w->cursorX = dx; + if( dy <= 0 || dy >= w->height ) + { /* Need to goto line, it does a redraw */ + gotoline(w, cy); + } + else + { + w->cursorLineNo = dy; + redrawWindow(w); + } + } + } + updateStatus(); + updateCursor(w); + return(1); +} + +/* Open up (insert) blank lines or a rectangular area if marks set */ +openCmd(int argc, char **argv) +{ +windowStruct *w = globalData.activeWindow; +fileStruct *fs; +lineStruct *ls, *ns, *head, *tail; +int i, cnt, startX, width, needRestoreCursor, dirty; +long long startLineNo, startCheckNo; + + if( !(fs=w->fileInfo) ) + { + dingMsg("No file open;Use ^space edit to open"); + return(0); + } + if( !canModifyFile(fs) ) + return(0); + + needRestoreCursor = 0; + if( globalData.markSet ) + { + cnt = w->topOffset + w->cursorLineNo - globalData.markRefY; + if( cnt < 0 ) + { + startLineNo = w->topOffset + w->cursorLineNo; + getLine(w, fs, startLineNo-1, &ls); + cnt = 1 - cnt; + } + else + { + startLineNo = globalData.markRefY; + getLine(w, fs, startLineNo-1, &ls); + cnt = 1 + cnt; + } + startCheckNo = startLineNo; + globalData.markSet = 0; + needRestoreCursor = 1; + clearArgDisplay(); + width = w->leftOffset + w->cursorX - globalData.markRefX; + if( width == 0 ) + { /* No dx */ + goto LINE_MODE; + } + if( width < 0 ) + { + width = -width; + startX = w->leftOffset + w->cursorX; + } + else + { + startX = globalData.markRefX; + } + /* insert width blanks starting at startX for cnt lines */ + /* May need to create and/or unpack the lines */ + startX--; /* convert to 0 based indexing */ + for(i=0; inext) + { + if( !ls ) + { + ls = (lineStruct *) calloc(sizeof(lineStruct), 1); + ls->flags = 1; + tail->next = ls; + ls->prev = tail; + fs->tail = ls; + fs->numLines++; + } + if( ls->flags & 1 ) + { /* Filler only line, create at least 80, more if needed */ + ls->numChars = startX + width; + if( ls->numChars < 80 ) + ls->numCharsAvail = 80; + else + ls->numCharsAvail = ls->numChars + 20; + ls->data.line = (char *) malloc(ls->numCharsAvail+1); + + memset(ls->data.line, ' ', ls->numChars); + ls->data.line[ls->numChars] = '\0'; + } + else + { + if( ls->numCharsAvail == 0 ) + unpackDiskLine(fs, ls); + if( ls->numChars < startX ) + { /* Really a do nothing as we don't add blanks with no reason at the EOL */ + } + else + { /* Move the last chars of line past startX width to the right & blank fill */ + if( ls->numCharsAvail < ls->numChars + width ) + { + ls->numCharsAvail = ls->numChars + width + 20; + ls->data.line = (char *) realloc(ls->data.line, + ls->numCharsAvail+1); + } + memmove(&(ls->data.line[startX+width]), + &(ls->data.line[startX]), + ls->numChars - startX); + memset(&(ls->data.line[startX]), ' ', width); + ls->numChars += width; + ls->data.line[ls->numChars] = '\0'; + } + } + } + restoreToMark(w); + w->cursorLine = NULL; + redrawWindow(w); + return(0); + } + else + startCheckNo = w->topOffset + w->cursorLineNo; + + if( argc > 1 && argv[1][0] ) + { + cnt = atoi(argv[1]); + if( cnt <= 0 ) + { + emsg("Invalid number of lines to open"); + updateCursor(w); + return(0); + } + } + else + cnt = 1; + + for(i=1,ls=w->topLine; icursorLineNo; i++) + { + if( ls->next ) + ls = ls->next; + else + { + ns = (lineStruct *) calloc(1, sizeof(lineStruct)); + ns->flags = 1; + ls->next = ns; + ns->prev = ls; + ls = ns; + fs->tail = ns; + fs->numLines++; + } + } + +LINE_MODE: + dirty = checkUpdate(startCheckNo, (long long) cnt, 0); + + fs->head->flags = fs->head->flags & ~1; + /* Create a new group of cnt lines */ + for(i=0; inumCharsAvail = 80; + ns->data.line = (char *) malloc(81); + ns->data.line[0] = '\0'; + if( i == 0 ) + head = ns; + else + { + ns->prev = tail; + tail->next = ns; + } + tail = ns; + } + fs->numLines += cnt; + + /* Add if necessary to fill down to the current cursor pos */ + if( ls == w->topLine ) + { /* The linked list starts at top line now */ + w->topLine = head; + } + if( ls == fs->head ) /* We are at top of file */ + fs->head = head; + else + { + ls->prev->next = head; + head->prev = ls->prev; + } + tail->next = ls; + ls->prev = tail; + w->cursorLine = NULL; /* Reset current line */ + + /* fs tail is never updated */ + globalData.markSet = 0; + if( dirty ) + redrawScreen(); + else + redrawWindow(w); + return(1); +} + +/* Frees the buffer if something in there, then converts lines to buffer */ +/* In cut mode, stuff is freed, in get mode, stuff is not freed */ +/* May need to pad if cnt is more than lines. Can happen with a EOF */ +convertToLineBuffer(fileStruct *fs, lineStruct *head, int cnt, + bufferStruct **bufPtrP, int freeLines) +{ +bufferStruct *bufPtr; +lineStruct *ls, *xs; +int i; + + if( (bufPtr = *bufPtrP) ) + { /* Must free old */ + for(i=0; inumLines; i++) + free(bufPtr->lines[i]); + free(bufPtr); + *bufPtrP = NULL; + } + *bufPtrP = bufPtr = (bufferStruct *) malloc(sizeof(bufferStruct) + + (cnt-1) * sizeof(char *)); + bufPtr->mode = 0; + bufPtr->numLines = cnt; + for(i=0, ls=head; inumCharsAvail == 0 ) + unpackDiskLine(fs, ls); + if( freeLines ) + bufPtr->lines[i] = ls->data.line; + else + { + bufPtr->lines[i] = (char *) malloc(ls->numChars+1); + strcpy(bufPtr->lines[i], ls->data.line); + } + xs = ls; + ls =ls->next; + if( freeLines ) + free(xs); + } + else + { + bufPtr->lines[i] = (char *) malloc(1); + bufPtr->lines[i][0] = '\0'; + } + } + return(1); +} + +/* Frees the buffer if something in there, then converts lines to rect buffer */ +/* Buffer begins in start col (1 index) and countains width chars */ +/* May need to pad if cnt is more than lines. Can happen with a EOF */ +convertToRectBuffer(fileStruct *fs, lineStruct *head, int cnt, + int startX, int width, int createLines, + bufferStruct **bufPtrP) +{ +bufferStruct *bufPtr; +lineStruct *ls, *tail; +int i, col, j; + + if( (bufPtr = *bufPtrP) ) + { /* Must free old */ + for(i=0; inumLines; i++) + free(bufPtr->lines[i]); + free(bufPtr); + *bufPtrP = NULL; + } + *bufPtrP = bufPtr = (bufferStruct *) malloc(sizeof(bufferStruct) + + (cnt-1) * sizeof(char *)); + bufPtr->mode = 1; + bufPtr->numLines = cnt; + bufPtr->width = width; + for(i=0, ls=head; ilines[i] = (char *) malloc(width+1); + if( ls ) + { + if( ls->numCharsAvail == 0 ) + unpackDiskLine(fs, ls); + for(col=startX-1,j=0; jnumChars ) + bufPtr->lines[i][j] = ls->data.line[col]; + else + bufPtr->lines[i][j] = ' '; + } + bufPtr->lines[i][j] = '\0'; + tail = ls; + ls =ls->next; + } + else + { + memset(bufPtr->lines[i], ' ', width); + bufPtr->lines[i][width] = '\0'; + if( createLines ) + { /* For cut version, need the line to exist */ + ls = (lineStruct *) calloc(sizeof(lineStruct), 1); + ls->numCharsAvail = 80; + ls->data.line = (char *) malloc(81); + ls->prev = tail; + tail->next = ls; + tail = fs->tail = ls; + fs->numLines++; + ls = NULL; + } + } + } + return(1); +} + +/* Move the cursor back to the marked location */ +/* Try to keep it on the same page */ +restoreToMark(windowStruct *w) +{ +int dx, x, cx; +long long dy, y, cy; + + cx = globalData.markRefX; + cy = globalData.markRefY; + dx = cx - w->leftOffset; + dy = cy - w->topOffset; + if( dx > 0 && dx < w->width && dy > 0 && dy < w->height-1 ) + { + w->cursorX = dx; + w->cursorLineNo = dy; + } + else + { + if( dx <= 0 || dx >= w->width ) + { /* Need to fix left offset */ + if( cx < w->width ) + { /* Set offset to 0 */ + w->leftOffset = 0; + w->cursorX = cx; + } + else /* Center it */ + { /* Try to offset by 8's */ + w->leftOffset = cx - w->width/2; + w->cursorX = cx - w->leftOffset; + } + } + else /* Don't adjust leftoffset */ + w->cursorX = dx; + if( dy <= 0 || dy >= w->height ) + { /* Need to goto line, it does a redraw */ + gotoline(w, cy); + } + else + { + w->cursorLineNo = dy; + } + } +} + + +/* Cut line(s) or a rectangular area */ +cutCmd(int argc, char **argv) +{ +windowStruct *w = globalData.activeWindow; +fileStruct *fs; +lineStruct *ls, *head, *tail; +long long startLineNo, startCheckNo; +int i, cnt, dcnt, startX, width, dirty; +int needRestoreCursor=0; +char tmp[20]; + + if( !(fs=w->fileInfo) ) + { + dingMsg("No file open;Use ^space edit to open"); + return(0); + } + if( !canModifyFile(fs) ) + return(0); + + w->cursorLine = NULL; + if( globalData.markSet ) + { + cnt = w->topOffset + w->cursorLineNo - globalData.markRefY; + if( cnt < 0 ) + { + startLineNo = w->topOffset + w->cursorLineNo; + getLine(w, fs, startLineNo-1, &ls); + cnt = 1 - cnt; + } + else + { + startLineNo = globalData.markRefY; + getLine(w, fs, startLineNo-1, &ls); + cnt = 1 + cnt; + } + startCheckNo = startLineNo; + globalData.markSet = 0; + needRestoreCursor = 1; + clearArgDisplay(); + width = w->leftOffset + w->cursorX - globalData.markRefX; + if( width == 0 ) + { /* No dx */ + goto LINE_MODE; + } + if( width < 0 ) + { + width = -width; + startX = w->leftOffset + w->cursorX; + } + else + { + startX = globalData.markRefX; + } + /* Conversion also forces the lines to go into memory */ + convertToRectBuffer(w->fileInfo, ls, cnt, startX, width, + 1, &(globalData.cutBuffer)); + /* Delete the characters in the region */ + startX--; /* convert to 0 based indexing */ + for(i=0; inext) + { + if( startX+width >= ls->numChars ) + { /* Easy we are trucating the end of the line */ + if( ls->numChars > startX ) + { + ls->numChars = startX; + ls->data.line[startX] = '\0'; + } + } + else + { + memmove( &(ls->data.line[startX]), + &(ls->data.line[startX+width]), + 1 + ls->numChars -(startX+width)); + ls->numChars -= width; + } + } + restoreToMark(w); + redrawWindow(w); + sprintf(tmp, "del/got %dx%d", cnt, width); + emsg(tmp); + return(0); + } + else + startCheckNo = w->topOffset + w->cursorLineNo; + if( argc > 1 ) + { + if( argv[1][0] == '\0' ) + { /* uncut */ + return(uncutCmd(1, NULL)); + } + cnt = atoi(argv[1]); + if( cnt <= 0 ) + { + emsg("Invalid number of lines to cut"); + updateCursor(w); + return(0); + } + } + else + cnt = 1; + + fs->head->flags = fs->head->flags & ~1; + + /* skip down to current cursor position */ + for(i=1, ls=w->topLine; icursorLineNo; i++) + { + if( ls->next == NULL ) + { /* Nothing to delete really, already at EOF */ + head = NULL; + dcnt = 0; + goto BUFFER; + } + ls = ls->next; + } + startLineNo = -1; /* B/c in cnt mode we don't need to adj line */ + /* Delete from line ls to ls + cnt-1 lines */ +LINE_MODE: + head = ls; + for(i=0; inext ) + ls = ls->next; + else + break; + } + fs->numLines -= i; /* May be less than cnt */ + dcnt = i; + if( i != cnt ) /* We were short */ + { /* We must update file tail */ + if( fs->head == head ) + { /* all lines are now deleted, put in a fake one */ + fs->head = fs->tail = (lineStruct *) calloc(1, sizeof(lineStruct)); + w->topLine = fs->head; + w->topLine->flags = 1; + fs->numLines = 1; + w->topOffset = 0; + w->cursorLineNo = 1; + goto BUFFER; + } +/* Ok, we could make the tail of the file safely be the line above the head */ +/* but that causes a line shift if the start of the delete is the top line */ +/* of the window, so add a fake line to the bottom of the file */ + ls = fs->tail = (lineStruct *) calloc(1, sizeof(lineStruct)); + ls->flags = 1; + } + if( w->topLine == head ) + w->topLine = ls; + if( fs->head == head ) + { + ls->prev = NULL; + fs->head = ls; + } + else + head->prev->next = ls; + ls->prev = head->prev; + /* Now convert lines to buffer format */ + tail->next = NULL; +BUFFER: + dirty = checkUpdate(startCheckNo, (long long) cnt, 1); + convertToLineBuffer(w->fileInfo, head, cnt, &(globalData.cutBuffer), 1); + sprintf(tmp, "del %d got %d", dcnt, cnt); + emsg(tmp); + if( startLineNo >= 0 ) + { + if( startLineNo > w->topOffset && startLineNo < w->topOffset + w->height ) + w->cursorLineNo = startLineNo - w->topOffset; + else + { /* goto will do a redraw since we are out of cur window */ + gotoline(w, startLineNo); + emsg(tmp); + return(1); + } + } + if( dirty ) + redrawScreen(); + else + redrawWindow(w); + return(1); +} + +/* A side effect of a get is that lines are put in memory instead of + pointing to disk offsets */ +getCmd(int argc, char **argv) +{ +windowStruct *w = globalData.activeWindow; +fileStruct *fs; +lineStruct *ls, *head, *tail; +int i, cnt, startX, width; +int needRestoreCursor; +char tmp[20]; + + if( !(fs=w->fileInfo) ) + { + dingMsg("No file open;Use ^space edit to open"); + return(0); + } + needRestoreCursor = 0; + if( globalData.markSet ) + { + w->cursorLine = NULL; + cnt = w->topOffset + w->cursorLineNo - globalData.markRefY; + if( cnt < 0 ) + { + getLine(w, fs, w->topOffset + w->cursorLineNo-1, &head); + cnt = 1 - cnt; + } + else + { + getLine(w, fs, globalData.markRefY-1, &head); + cnt = 1 + cnt; + } + globalData.markSet = 0; + needRestoreCursor = 1; + clearArgDisplay(); + width = w->leftOffset + w->cursorX - globalData.markRefX; + if( width == 0 ) + { /* No dx */ + goto BUFFER; + } + /* Rectangular get */ + if( width < 0 ) + { + width = -width; + startX = w->leftOffset + w->cursorX; + } + else + { + startX = globalData.markRefX; + } + convertToRectBuffer(w->fileInfo, head, cnt, startX, width, + 0, &(globalData.getBuffer)); + sprintf(tmp, "Got %dx%d rect", cnt, width); + emsg(tmp); + /* Restore cursor to original mark location */ + restoreToMark(w); + updateCursor(w); + return(1); + } + + if( argc > 1 ) + { + if( argv[1][0] == '\0' ) + { /* put */ + return(putCmd(1, NULL)); + } + cnt = atoi(argv[1]); + if( cnt <= 0 ) + { + emsg("Invalid number of lines to get"); + updateCursor(w); + return(0); + } + } + else + cnt = 1; + + /* skip down to current cursor position */ + for(i=1, head=ls=w->topLine; icursorLineNo; i++) + { + if( ls->next == NULL ) + { /* At EOF, just update buffer */ + head = NULL; + goto BUFFER; + } + ls = ls->next; + } + head = ls; + /* get from line ls to ls + cnt-1 lines */ +BUFFER: + convertToLineBuffer(w->fileInfo, head, cnt, &(globalData.getBuffer), 0); + sprintf(tmp, "Got %d lines", cnt); + emsg(tmp); + if( needRestoreCursor ) + restoreToMark(w); + updateCursor(w); + return(1); +} + +uncutCmd(int argc, char **argv) +{ +windowStruct *w = globalData.activeWindow; +fileStruct *fs; +lineStruct *ls, *head, *tail; +int i, cnt; + + if( !(fs=w->fileInfo) ) + { + dingMsg("No file open;Use ^space edit to open"); + return(0); + } + if( globalData.cutBuffer == NULL || globalData.cutBuffer->numLines == 0) + { + dingMsg("Cut buffer is empty"); + updateCursor(w); + return(0); + } + w->cursorLine = NULL; + if( globalData.cutBuffer->mode == 1 ) + return(bufferRectPut(w, fs, globalData.cutBuffer)); + else + return(bufferPut(w, fs, globalData.cutBuffer)); +} + +putCmd(int argc, char **argv) +{ +windowStruct *w = globalData.activeWindow; +fileStruct *fs; + + if( !(fs=w->fileInfo) ) + { + dingMsg("No file open;Use ^space edit to open"); + return(0); + } + if( globalData.getBuffer == NULL || globalData.getBuffer->numLines == 0) + { + dingMsg("Get buffer is empty"); + updateCursor(w); + return(0); + } + if( globalData.getBuffer->mode == 1 ) + return(bufferRectPut(w, fs, globalData.getBuffer)); + else + return(bufferPut(w, fs, globalData.getBuffer)); +} + +/* Put the specified buffer into the current window */ +bufferPut(windowStruct *w, fileStruct *fs, bufferStruct *buffer) +{ +lineStruct *ls, *ns, *head, *tail; +int i, cnt, len, alen, dirty; + + if( !canModifyFile(fs) ) + return(0); + dirty = checkUpdate(w->topOffset + w->cursorLineNo, + (long long)buffer->numLines , 0); + fs->head->flags = fs->head->flags & ~1; + /* Create a new group of lines */ + for(i=0; inumLines; i++) + { + ns = (lineStruct *)calloc(1, sizeof(lineStruct)); + len = strlen(buffer->lines[i]); + if( len < 80 ) + alen = 80; + else + alen = len + 20; + ns->numCharsAvail = alen; + ns->numChars = len; + ns->data.line = (char *) malloc(alen+1); + strcpy(ns->data.line, buffer->lines[i]); + if( i == 0 ) + head = ns; + else + { + ns->prev = tail; + tail->next = ns; + } + tail = ns; + } + fs->numLines += buffer->numLines; + + /* Add if necessary to fill down to the current cursor pos */ + for(i=1,ls=w->topLine; icursorLineNo; i++) + { + if( ls->next ) + ls = ls->next; + else + { /* These are real unallocated lines */ + ns = (lineStruct *) calloc(1, sizeof(lineStruct)); + ls->next = ns; + ns->prev = ls; + ls = ns; + fs->tail = ns; + fs->numLines++; + } + } + if( ls == w->topLine ) + { /* The linked list starts at top line now */ + w->topLine = head; + } + if( ls == fs->head ) /* We are at top of file */ + fs->head = head; + else + { + ls->prev->next = head; + head->prev = ls->prev; + } + tail->next = ls; + ls->prev = tail; + + /* fs tail is never updated */ + if( dirty ) + redrawScreen(); + else + redrawWindow(w); + return(1); +} + +/* Put the specified rectangular buffer into the current window */ +/* May need to create lines if buffer goes past EOF */ +bufferRectPut(windowStruct *w, fileStruct *fs, bufferStruct *buffer) +{ +lineStruct *ls, *ns, *tail; +int i, len, allocLen, offsetX, wReq, width; +long long curLineNo; + + if( !canModifyFile(fs) ) + return(0); + + fs->head->flags = fs->head->flags & ~1; + curLineNo = w->topOffset + w->cursorLineNo; + getLine(w, fs, curLineNo-1, &ls); + offsetX = w->leftOffset + w->cursorX - 1; + width = buffer->width; + wReq = offsetX + width; + for(i=0; inumLines; i++, tail=ls, ls=ls->next) + { + if( !ls ) /* Need to create a line */ + { + ls = (lineStruct *) calloc(1, sizeof(lineStruct)); + fs->numLines++; + fs->tail = ls; + ls->prev = tail; + tail->next = ls; + ls->flags = 1; + } + + if( ls->flags & 1 ) + { /* But it is a filler, easy allocate enough space for the buffer */ + if( (allocLen=wReq) < 80 ) + allocLen = 80; + ls->numCharsAvail = allocLen; + ls->data.line = (char *) malloc(allocLen+1); + ls->flags = ls->flags & ~1; + if( offsetX ) + memset(ls->data.line, ' ', offsetX); + /* Pick up trailing NULL */ + memcpy(&ls->data.line[offsetX], buffer->lines[i], 1+width); + ls->numChars = offsetX + width; + } + else + { + if( ls->numCharsAvail == 0 ) + { /* On disk still, pull it in */ + unpackDiskLine(fs, ls); + } + /* We are always inserting, so we need at laeast width more chars */ + if( ls->numChars + width > wReq ) + allocLen = ls->numChars + width; + else + allocLen = wReq; + if( allocLen > ls->numCharsAvail ) + { + if( allocLen < 80 ) + allocLen = 80; + else + allocLen += 20; + ls->data.line = (char *) realloc(ls->data.line, allocLen+1); + ls->numCharsAvail = allocLen; + } + if( offsetX >= ls->numChars ) + { /* We are adding to the right */ + if( offsetX > ls->numChars ) + memset(&(ls->data.line[ls->numChars]), + ' ', offsetX - ls->numChars); + ls->numChars = offsetX; + } + else + memmove(&(ls->data.line[offsetX+width]), + &(ls->data.line[offsetX]), + ls->numChars - offsetX); + memcpy(&(ls->data.line[offsetX]), + buffer->lines[i], width); + ls->numChars += width; + ls->data.line[ls->numChars] = '\0'; + } +if( ls->numChars > ls->numCharsAvail ) +emsg("OVERRUN"); + } + redrawWindow(w); + return(1); +} + +checkCmd() +{ +windowStruct *w = globalData.activeWindow; +fileStruct *fs; +lineStruct *ls, *prev; +int cnt=0; + + if( !(fs=w->fileInfo) ) + return(0); + + if( fs->head->prev ) + printf("Head ptr has a prev!\n\r"); + if( fs->tail->next ) + printf("Tail ptr has a next!\n\r"); + for(ls=fs->head; ls; ls=ls->next, cnt++) + { + if( cnt != 0 ) + if( ls->prev != prev ) + printf("At line %d, line ptr prev invalid is %p\n\r", + cnt, ls->prev); + prev = ls; + } + if( cnt != fs->numLines ) + printf("\n\r line count wrong; expected %lld got %d\n\r", + fs->numLines, cnt); + return(0); +} + +/* Split the line. The end of the current line is just before the cursor */ +splitCmd(int argc, char **argv) +{ +windowStruct *w=globalData.activeWindow; +fileStruct *fs; +lineStruct *ls, *ns, *tail; +int len, dirty; + + if( !(fs=w->fileInfo) ) + { + dingMsg("No file open;Use ^space edit to open"); + return(0); + } + + if( !canModifyFile(fs) ) + return(0); + + /* Need this minor tweak so that a split of the top of range keeps */ + /* The top of range at beginning of split */ + dirty = checkUpdate(w->topOffset + w->cursorLineNo +1, + (long long)1, 0); + getCursorLine(w, &ls); + if( ls->numCharsAvail == 0 ) /* Not in memory */ + unpackDiskLine(fs, ls); + /* Allocate a new line */ + ns = (lineStruct *)calloc(sizeof(lineStruct), 1); + tail = ns->next = ls->next; + ls->next = ns; + ns->prev = ls; + if( tail ) + tail->prev = ns; + else + fs->tail = ns; + fs->numLines++; + + /* And cut up the line */ + len = strlen(ls->data.line) - (w->leftOffset + w->cursorX); + if( len < 80 ) + ns->numCharsAvail = 80; + else + ns->numCharsAvail = len + 20; + ns->data.line = (char *) malloc(ns->numCharsAvail+1); + strcpy(ns->data.line, &(ls->data.line[w->leftOffset+w->cursorX-1])); + ns->numChars = strlen(ns->data.line); + ls->data.line[w->leftOffset+w->cursorX-1] = '\0'; + ls->numChars = strlen(ls->data.line); + redrawWindow(w); + return(1); +} + +joinCmd(int argc, char **argv) +{ +windowStruct *w=globalData.activeWindow; +fileStruct *fs; +lineStruct *ls, *ns, *ps; +int len, dirty; + + if( !(fs=w->fileInfo) ) + { + dingMsg("No file open;Use ^space edit to open"); + return(0); + } + if( !canModifyFile(fs) ) + return(0); + + dirty = checkUpdate(w->topOffset + w->cursorLineNo +1, + (long long)1, 1); + getCursorLine(w, &ls); + getLine(w, fs, w->topOffset + w->cursorLineNo, &ns); + if( ls->flags & 1 || ns->flags & 1 || ls->numChars == 0 || ns->numChars == 0 ) + { + if( ns->flags & 1 || ns->numChars == 0 ) /* keep ls */ + { + if( ns->numCharsAvail ) + free(ns->data.line); + ls->next = ns->next; + if( ns->next ) + ns->next->prev = ls; + else + fs->tail = ls; + free(ns); + } + else + { + if( ls->numCharsAvail ) + free(ls->data.line); + ns->prev = ls->prev; + if( ls->prev ) + ls->prev->next = ns; + else + fs->head = ns; + /* Do we need to update topLine ? */ + if( w->topLine == ls ) + w->topLine = ns; /* But the line no did not change, since we deleted current */ + if( w->cursorLine == ls ) /* And what about cursorLine */ + w->cursorLine = ns; + free(ls); + } + } + else + { /* both have at least 1 char so we must join */ + if( ls->numCharsAvail ==0 ) + unpackDiskLine(fs, ls); + if( ns->numCharsAvail ==0 ) + unpackDiskLine(fs, ns); + len = ls->numChars + ns->numChars; + if( len > ls->numCharsAvail ) + { + ls->numCharsAvail = len + 20; + ls->data.line = (char *) realloc(ls->data.line, + ls->numCharsAvail+1); + } + strcpy( &(ls->data.line[ls->numChars]), ns->data.line); + ls->numChars += ns->numChars; + ls->next = ns->next; + if( ns->next ) + ns->next->prev = ls; + else + fs->tail = ls; + free(ns->data.line); + free(ns); + } + fs->numLines--; + if( dirty ) + redrawScreen(); + else + redrawWindow(w); + return(1); +} + +/* Disable range command */ +mrangeCmd(int argc, char **argv) +{ +windowStruct *w=globalData.activeWindow; +fileStruct *fs; + + if( !(fs=w->fileInfo) ) + { + dingMsg("No file open;Use ^space edit to open"); + return(0); + } + w->rangeBotNum = w->rangeTopNum = 0; + redrawScreen(); + return(1); +} + +rangeCmd(int argc, char **argv) +{ +windowStruct *w=globalData.activeWindow; +fileStruct *fs; + + if( !(fs=w->fileInfo) ) + { + dingMsg("No file open;Use ^space edit to open"); + return(0); + } + if( !globalData.markSet ) + { + dingMsg("Mark area before command"); + return(0); + } + + if( globalData.markRefY < w->topOffset + w->cursorLineNo ) + { + w->rangeTopNum = globalData.markRefY; + w->rangeBotNum = w->topOffset + w->cursorLineNo; + } + else + { + w->rangeBotNum = globalData.markRefY; + w->rangeTopNum = w->topOffset + w->cursorLineNo; + } + globalData.markSet = 0; + redrawScreen(); + emsg("Range set"); + return(1); +} diff --git a/src/cmd/sre/edit.h b/src/cmd/sre/edit.h new file mode 100644 index 0000000..2cd9f33 --- /dev/null +++ b/src/cmd/sre/edit.h @@ -0,0 +1,155 @@ +/* A weekend project to try to emulate the original RAND text editor + Copyright (C) 2011 Mike Stabenfeldt + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#define NUM_ALT_FILES 4 + +typedef struct lineStruct { + unsigned short numCharsAvail; /* 0 if it is an index into the file */ + unsigned short numChars; + unsigned char flags; /* 1 implies filler */ + union { + char *line; + unsigned long long offset; + } data; + struct lineStruct *prev; + struct lineStruct *next; + } lineStruct; + +/* Can be in more than one window */ +typedef struct fileStruct { + unsigned int created:1; /* New file */ + unsigned int modified:1; /* Since last save */ + unsigned int nosave:1; + unsigned int backupWritten:1; /* So we only write 1 comma file */ + unsigned int ro:1; + unsigned int accessMode; + long long numLines; + char *fileName; + int devNo; + long long inode; + FILE *fp; + lineStruct *head; + lineStruct *tail; + struct fileStruct *next; + } fileStruct; + +/* We do not store topLine as another window or stack could have changed it */ +/* Even the cursorX/cursorLineNo may have to be adjusted if windows were */ +/* opened or closed */ +typedef struct fileWinParams { + long long topOffset; + unsigned short leftOffset; + unsigned short cursorX; + unsigned short cursorLineNo; + long long rangeTopNum; /* If non-z, top of range */ + long long rangeBotNum; /* If non-z, bottom of range */ + fileStruct *fileInfo; + } fileWinParams; + +typedef struct windowStruct { + unsigned char curParamSet; + unsigned char splitVertical; + unsigned char rangeMode; /* If set, cmd's are limited to range */ + unsigned char winNum; /* 0 is root */ + unsigned short x; /* Beginning of window including decoration */ + unsigned short y; + unsigned short width; /* Size includes decoration */ + unsigned short height; + unsigned short cutPosition; /* How we came about for startup */ + lineStruct *topLine; /* In window */ + lineStruct *cursorLine; /* For faster access. Gets reset to NULL alot */ + /* Start same as fileWinParams */ + long long topOffset; /* On screen offset to top line */ + /* 0 means top line is 1st line of file */ + unsigned short leftOffset; + unsigned short cursorX; /* On screen offset, does not include left offset */ + unsigned short cursorLineNo; /* On screen offset from topLine */ + long long rangeTopNum; /* If non-z, top of range */ + long long rangeBotNum; /* If non-z, bottom of range */ + fileStruct *fileInfo; + /* End same as fileWinParams */ + fileWinParams editStack[NUM_ALT_FILES]; /* Allow up to N files on stack */ + /* Original was only 2 */ + struct windowStruct *parent; /* Who we came from */ + struct windowStruct *next; + } windowStruct; + +typedef struct bufferStruct { + unsigned char mode; /* 0 is lines, 1 is rectangle */ + unsigned short width; /* only meaningful in rect mode */ + int numLines; + char *lines[1]; + } bufferStruct; + +typedef struct cmdStruct { + char *funcName; + int (*func)(); + unsigned int flags; + } cmdStruct; + +/* A "user" defined one. Really just a predefined with args */ +/* Note the entire struct is alloc'ed as one chunk for easy free */ +typedef struct ucmdStruct { + char *funcName; /* NULL as a marker for user defined */ + int (*func)(); /* Func to call */ + unsigned int flags; + int argc; /* How many args, func counts as 1 */ + char *argv[1]; /* The argument vector for the callee */ + } ucmdStruct; + +/* For keys that send escape sequences */ +typedef struct multiCharKeyDef { + char *charSeq; + cmdStruct *cmd; + struct multiCharKeyDef *next; + } multiCharKeyDef; + +/* Keeps track of all top level info and is global */ +typedef struct globalStruct { + unsigned char tabSpace; /* Number of spaces between tabs */ + unsigned char mode; /* 0 is not setup yet */ + unsigned char argMode; + unsigned char insertMode; /* 1 if insert, 0 for overwrite */ + unsigned char searchMode; /* 1 if pattern, 0 for literal */ + unsigned char markSet; /* 1 if we have a mark set */ + unsigned char ringBellOnErr; + unsigned short winWidth; /* In chars */ + unsigned short winHeight; /* In lines */ + unsigned short argPtr; + unsigned short srchBufferSize; + unsigned short argBufferSize; + unsigned short lineBufferSize; + unsigned short wordBufferSize; + unsigned short markRefX; /* absolute pos 1 is 1st char */ + long long markRefY; /* absolute pos, 1 is 1st line */ + windowStruct *windowList; /* Deleted in reverse order */ + windowStruct *activeWindow; + fileStruct *fileList; + bufferStruct *cutBuffer; + bufferStruct *getBuffer; + char *srchBuffer; + char *argBuffer; + char *lineBuffer; + char *wordBuffer; + cmdStruct *keyMap[256]; /* Simple single char mappings */ + multiCharKeyDef *multiList; + } globalStruct; + +/* For cmdStruct flags */ +#define ILLEGAL_IN_MARK 1 /* Set when the cmd is an error with marks set */ +#define IGNORE_IN_ARG 2 /* Set when a kbd sequence should be skipped in argmode */ +#define ORIGINAL_ARGS 4 /* Command parses args itself */ diff --git a/src/cmd/sre/file.c b/src/cmd/sre/file.c new file mode 100644 index 0000000..965b599 --- /dev/null +++ b/src/cmd/sre/file.c @@ -0,0 +1,422 @@ +/* A weekend project to try to emulate the original RAND text editor + Copyright (C) 2011 Mike Stabenfeldt + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "edit.h" +extern globalStruct globalData; + +exitCmd(int argc, char **argv) +{ +char *arg; +fileStruct *fs; +int mode=0; + + if( argc > 2 ) + goto INVALID; + arg = argv[1]; + if( argc > 1 ) + { /* Precheck arg */ + if( strncasecmp(arg, "nosave", strlen(arg)) == 0 ) + ; /* Don;t save any files */ + else if( strcasecmp(arg, "abort") == 0 ) + ; /* Don't save files or write init */ + else if( strcasecmp(arg, "stop") == 0 ) + ; /* Suspend */ + else + { /* Invalid */ +INVALID: + dingMsg("exit [nosave|abort|stop]"); + updateCursor(globalData.activeWindow); + return(0); + } + } + /* Go thru all files that have been touched and save as necessary */ + printf("\033[2J\033[1;1H\n\r"); + restoreTerm(); + globalData.mode = 0; /* So emsg just prints */ + + if( argc > 1 ) + { + if( strncasecmp(arg, "nosave", strlen(arg)) == 0 ) + mode = 1; + else if( strncasecmp(arg, "abort", strlen(arg)) == 0 ) + goto SKIP; + else if( strcasecmp(arg, "stop") == 0 ) + { + /* Can't seem to get timing right to restore the screen */ + restoreTerm(); + printf("\n"); /* Force a flush for restore screen */ + sleep(1); + kill(getpid(), SIGSTOP); + sleep(1); + setupTerm(); + globalData.mode = 1; + redrawScreen(); + return(0); + } + } + writeStartup(); + if( mode == 1) + goto SKIP; + for(fs=globalData.fileList; fs; fs=fs->next) + { + if( fs->ro ) + printf("Read only %s\n", fs->fileName); + else if( fs->modified && !fs->nosave ) + { + printf("Saving %s\n", fs->fileName); + if( fs->backupWritten == 0 && fs->created == 0) + writeBackup(fs); + writeFile(fs, fs->fileName, 0); + } + } +SKIP: + exit(0); +} + +saveCmd(int argc, char **argv) +{ +windowStruct *w = globalData.activeWindow; +fileStruct *fs; +char tmp[512]; +char *fName, *s; +int i, wrotePrimary=0, isNew=0; + + if( !(fs=w->fileInfo) ) + { + emsg("No file in window to save"); + updateCursor(w); + return(0); + } + if( argc == 1 ) + { /* Save to existing name */ +PRIMARY: + if( fs->ro ) + { + dingMsg("Read Only"); + updateCursor(w); + return(0); + } + fName = fs->fileName; + if( fs->modified == 0 ) + { + dingMsg("Nothing to save"); + updateCursor(w); + return(0); + } + if( fs->backupWritten == 0 && fs->created == 0 ) + writeBackup(fs); + wrotePrimary = 1; + } + else if(argc != 2 ) + { + dingMsg("save command has 0 or 1 arguments"); + updateCursor(w); + return(0); + } + else + { + if( argv[1][0] == '\0' ) + goto PRIMARY; + fName = argv[1]; + for(s=argv[1]; *s; s++) + if( iscntrl(*s) || isspace(*s) ) + { + emsg("Filename has control or spaces; save skipped"); + updateCursor(w); + return(0); + } + isNew = 1; + } + strcpy(tmp, "SAVE: "); + for(s=fName, i=6; *s && imodified = 0; + strcpy(tmp, "SAVED"); + tmp[5] = ' '; + emsg(tmp); + return(1); + } + return(0); +} + +openFile(char *fileName, windowStruct *w) +{ +FILE *fp; +fileStruct *fs; +lineStruct *cur, *prev; +int isNew = 0, c, newNeeded; +unsigned long long offset; +struct stat statbuf; + +AGAIN: + if( stat(fileName, &statbuf) != 0 ) + { + if( errno == ENOENT ) + { + emsg("File does not exist; create?"); + while( (c=getc(stdin)) ) + { + if( c == 'y' || c == 'Y' ) + { + if( (fp=fopen(fileName, "w")) == NULL ) + { + dingMsg("File create failed; sorry"); + return(0); + } + fclose(fp); + emsg("Create file succeeded ......"); + stat(fileName, &statbuf); + isNew = 1; + goto AGAIN; + } + else if( c != EOF ) + { + emsg("Canceled edit"); + return(0); + } + } + } + emsg("File could not be opened"); + return(0); + } + + for(fs=globalData.fileList; fs; fs=fs->next) + if( fs->inode == statbuf.st_ino && fs->devNo == statbuf.st_dev) + break; + if( fs ) + goto WIN_ATTACH; + + if( (fp=fopen(fileName, "r")) == NULL ) + { + emsg("Could not open file"); + return(0); + } + fs = (fileStruct *) calloc(1, sizeof(fileStruct)); + fs->devNo = statbuf.st_dev; + fs->inode = statbuf.st_ino; + fs->created = isNew; + fs->accessMode = statbuf.st_mode; + if( statbuf.st_uid == getuid() && (statbuf.st_mode & S_IWUSR) ) + fs->ro = 0; + else if( statbuf.st_gid == getgid() && (statbuf.st_mode & S_IWGRP) ) + fs->ro = 0; + else if( statbuf.st_mode & S_IWOTH ) + fs->ro = 0; + else + { + fs->ro = 1; + dingMsg("Read only"); + } + fs->fileName = strdup(fileName); + fs->next = globalData.fileList; + globalData.fileList = fs; + + /* Read in the file into the buffer */ + newNeeded = 1; + offset = 0; + prev = NULL; + while( (c=getc(fp)) != EOF ) + { + if( newNeeded ) + { + cur = (lineStruct *) calloc(sizeof(lineStruct), 1); + cur->data.offset = offset; + newNeeded = 0; + cur->prev = prev; + if( prev ) + prev->next = cur; + else + fs->head = cur; + prev = cur; + } + if( c == '\n' ) + { + fs->numLines++; + newNeeded = 1; + } + else + cur->numChars++; + offset++; + } + if( !newNeeded ) /* File did not end w/newline */ + fs->numLines++; + if( fs->numLines == 0 ) /* Empty file, need something */ + { + w->topLine = fs->head = fs->tail = + (lineStruct *) calloc(sizeof(lineStruct), 1); + w->topLine->flags = 1; + fs->numLines = 1; + } + else + fs->tail = cur; + fs->fp = fp; + +WIN_ATTACH: + w->fileInfo = fs; + w->cursorX = w->cursorLineNo = 1; + w->topLine = fs->head; + w->topOffset = 0; + w->cursorX = w->cursorLineNo = 1; + w->leftOffset = 0; + + return(1); +} + +/* Really just a rename */ +writeBackup(fileStruct *fs) +{ +char backupFileName[2048], *p, *src; +int i, j; + + if(fs->backupWritten ) + return(0); + if( strlen(fs->fileName) >= 2040 ) + return(0); + fs->backupWritten = 1; + if( (p=rindex(fs->fileName, '/')) ) + { /* Has path */ + for(i=0, src=fs->fileName; src != p; i++, src++) + backupFileName[i] = *src; + backupFileName[i++] = '/'; + backupFileName[i++] = ','; + src++; + for(; i<2048 && *src; i++, src++) + backupFileName[i] = *src; + if( i >= 2040 ) + return(0); + backupFileName[i] = '\0'; + } + else + { + backupFileName[0] = ','; + strcpy(&backupFileName[1], fs->fileName); + } + return(1+rename(fs->fileName, backupFileName)); +} + +/* Never bother to free as files are never really closed once opened */ +/* Convert leading blanks to tabs if possible and */ +/* remove trailing blanks on lines in memory. Disk */ +/* lines are written unmodified */ +writeFile(fileStruct *fs, char *fName, int isNew) +{ +FILE *fp; +lineStruct *ls, *ps; +int i, c, j, tabCnt, blankCnt, hadNonblank; +struct stat statbuf; + + if( fs->ro && !isNew ) + { + dingMsg("File is Read-Only"); + return(0); + } + fp = fopen(fName, "w"); + if( fp == NULL ) + { + dingMsg("Failed to open file"); + return(0); + } + fchmod(fileno(fp), fs->accessMode); + ps = NULL; + for(ls=fs->head; ls; ls=ls->next) + { + if( ps ) /* Was it a filler fake ? */ + { + if( !(ls->flags & 1)) + { /* It was interim filler, put in the blank lines */ + for( ; ps != ls; ps=ps->next) + putc('\n', fp); + ps = NULL; + } + } + if( ls->numCharsAvail == 0 ) + { /* On disk still, just copy from disk */ + if( ls->flags & 1) /* A filler line */ + { + if( !ps ) + ps = ls; + } + else + { + fseek(fs->fp, ls->data.offset, SEEK_SET); + for(i=0; inumChars; i++) + if( (c=getc(fs->fp)) == EOF ) + { + emsg("Unexpected EOF on read"); + break; + } + else + putc(c, fp); + putc('\n', fp); + } + } + else + { + hadNonblank = blankCnt = 0; + for(i=0; inumChars; i++) + { + if( ls->data.line[i] == ' ' ) + blankCnt++; + else + { + if( blankCnt ) + { + if( hadNonblank == 0 ) + { /* no chars yet, convert as many as possible to tabs */ + tabCnt = blankCnt / 8; + for(j = 0; jdata.line[i], fp); + } + } + putc('\n', fp); + } + } + /* Every time we write, need to update the file info's inode info so */ + /* a subsequent open does not create a new file entry */ + if( fstat(fileno(fp), &statbuf) == 0 ) + { + fs->devNo = statbuf.st_dev; + fs->inode = statbuf.st_ino; + } + fclose(fp); + return(1); +} + + diff --git a/src/cmd/sre/init.c b/src/cmd/sre/init.c new file mode 100644 index 0000000..697774d --- /dev/null +++ b/src/cmd/sre/init.c @@ -0,0 +1,133 @@ +/* A weekend project to try to emulate the original RAND text editor + Copyright (C) 2011 Mike Stabenfeldt + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +/* Startup related stuff */ + +#include +#include +#include +#include +#include +#include +#include + +#include "edit.h" +extern globalStruct globalData; + +/* Read the .srerc file if it exists */ +readRC() +{ +char *s; +char line[1024]; +FILE *fp; + + if( (s=getenv("HOME")) == NULL ) + return(0); + sprintf(line, "%s/.srerc", s); + if( !(fp=fopen(line, "r")) ) + return(0); + while(fgets(line, 1000, fp) != NULL) + if( processCmd(line) == 0) + { + printf("Bad .srerc init file; correct and restart\n"); + exit(0); + } + fclose(fp); + return(1); +} + +readStartup() +{ +FILE *fp; +char line[1024]; + + if( !(fp=fopen(".sre_init", "r")) ) + return(0); + + while(fgets(line, 1000, fp) != NULL) + processCmd(line); + fclose(fp); +} + +writeStartup() +{ +FILE *fp; +windowStruct *w; + + if( !(fp=fopen(".sre_init", "w")) ) + return(0); + + writeWindowStartup(fp); + if( globalData.insertMode ) + fprintf(fp, "set insertMode 1\n"); + if( globalData.srchBuffer ) + fprintf(fp, "set searchKey \"%s\"\n", globalData.srchBuffer); + fclose(fp); +} + +writeWindowStartup(FILE *fp) +{ +fileStruct *fs; +fileWinParams *fw; +int i, j, wcnt; +windowStruct **warray, *ww, *w; + + /* create a list of the windows */ + for(wcnt=0, ww=globalData.windowList; ww; ww=ww->next) + wcnt++; + warray = (windowStruct **) alloca(sizeof(windowStruct *) * wcnt); + for(i=1, ww=globalData.windowList; ww; ww=ww->next, i++) + warray[wcnt-i] = ww; + + for(j=0; jparent->winNum); + if( w->splitVertical == 0 ) + fprintf(fp, "win \"\" %d 1\n", w->cutPosition); + else + fprintf(fp, "win \"\" 1 %d\n", w->cutPosition); + } + /* Write out the commands to open the existing files in the window */ + for(i=0; icurParamSet == i ) + continue; + fw=&w->editStack[i]; + if( (fs=fw->fileInfo) ) + { + fprintf(fp, "edit %s %lld %d %d %d\n", + fs->fileName, + fw->topOffset, fw->leftOffset, fw->cursorLineNo, fw->cursorX); + fprintf(fp, "set rangeTop %lld\n", w->editStack[i].rangeTopNum); + fprintf(fp, "set rangeBot %lld\n", w->editStack[i].rangeBotNum); + } + } + /* Write the primary last so it is current */ + if( (fs = w->fileInfo) ) + { + fprintf(fp, "edit %s %lld %d %d %d\n", + fs->fileName, + w->topOffset, w->leftOffset, w->cursorLineNo, w->cursorX); + fprintf(fp, "set rangeTop %lld\n", w->rangeTopNum); + fprintf(fp, "set rangeBot %lld\n", w->rangeBotNum); + } + } + fprintf(fp, "cwin %d\n", globalData.activeWindow->winNum); + return(1); +} diff --git a/src/cmd/sre/main.c b/src/cmd/sre/main.c new file mode 100644 index 0000000..e6bcd74 --- /dev/null +++ b/src/cmd/sre/main.c @@ -0,0 +1,572 @@ +/* A weekend project to try to emulate the original RAND text editor + Copyright (C) 2011 Mike Stabenfeldt + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#include +#include +#include +#include +#include +#include +#include + +#include "edit.h" + +globalStruct globalData; + +extern int startArgCmd(); +extern int redrawCmd(); + +extern int cursorLeftCmd(); +extern int cursorRightCmd(); +extern int cursorUpCmd(); +extern int cursorDnCmd(); +extern int tabRightCmd(); +extern int tabLeftCmd(); +extern int returnCmd(); + +extern int pageUpCmd(); +extern int pageDnCmd(); +extern int scrollUpCmd(); +extern int scrollDnCmd(); +extern int pageLeftCmd(); +extern int pageRightCmd(); +extern int gotoCmd(); +extern int rangeCmd(); +extern int mrangeCmd(); + +extern int searchUpCmd(); +extern int searchDnCmd(); +extern int matchCmd(); +extern int replaceCmd(); + +extern int wipeCharCmd(); +extern int deleteCharCmd(); + +extern int splitCmd(); +extern int joinCmd(); + +extern int markCmd(); +extern int openCmd(); /* Open up line(s), or rectangular area */ +extern int cutCmd(); /* Cut line(s), or rectangular area */ +extern int getCmd(); /* Copy line(s), or rectangular area */ +extern int uncutCmd(); /* Uncut line(s), or rectangular area */ +extern int putCmd(); /* Put gotten line(s), or rectangular area */ + +extern int editFileCmd(); +extern int uneditFileCmd(); /* Unload the file from the window edit list */ +extern int addWindowCmd(); +extern int chgWindowCmd(); +extern int delWindowCmd(); + +extern int statusCmd(); +extern int saveCmd(); +extern int exitCmd(); + +extern int tabsCmd(); +extern int updateCmd(); +extern int noupdateCmd(); +extern int insertModeCmd(); +extern int defineKeyCmd(); +extern int tagCmd(); +extern int setCmd(); + +extern int checkCmd(); +cmdStruct globalCmd[] = { + {"arg", startArgCmd, 0}, + {"redraw", redrawCmd, 0}, + {"cursorLeft", cursorLeftCmd, 0}, + {"cursorRight", cursorRightCmd, 0}, + {"cursorUp", cursorUpCmd, 0}, + {"cursorDn", cursorDnCmd, 0}, + {"tabRight", tabRightCmd, IGNORE_IN_ARG}, + {"tabLeft", tabLeftCmd, IGNORE_IN_ARG}, + {"return", returnCmd, 0}, + + {"scrollUp", scrollUpCmd, 0}, /* The scroll cmds do 1/2 height */ + {"scrollDn", scrollDnCmd, 0}, /* if arg specified, that number */ + {"pageUp", pageUpCmd, 0}, + {"pageDn", pageDnCmd, 0}, + {"pageLeft", pageLeftCmd, 0}, /* An 8 char shift by default */ + {"pageRight", pageRightCmd, 0}, + {"goto", gotoCmd, 0}, + {"range", rangeCmd, 0}, + {"-range", mrangeCmd, 0}, + + {"searchUp", searchUpCmd, 0}, + {"searchDn", searchDnCmd, 0}, + {"match", matchCmd, 0}, + {"replace", replaceCmd, ORIGINAL_ARGS}, + + {"join", joinCmd, ILLEGAL_IN_MARK|IGNORE_IN_ARG}, + {"split", splitCmd, ILLEGAL_IN_MARK|IGNORE_IN_ARG}, + + {"wipeChar", wipeCharCmd, IGNORE_IN_ARG}, + {"deleteChar", deleteCharCmd, IGNORE_IN_ARG}, + + {"mark", markCmd, 0}, /* An empty arg is used to cancel the mark */ + {"open", openCmd, 0}, /* An empty arg is one line */ + {"cut", cutCmd, 0}, /* An empty arg is an uncut */ + {"get", getCmd, 0}, /* An empty arg is a put */ + /* The paste commands. 2, one for cut, one for get buffer */ + {"uncut", uncutCmd, ILLEGAL_IN_MARK|IGNORE_IN_ARG}, + {"put", putCmd, ILLEGAL_IN_MARK|IGNORE_IN_ARG}, + + {"edit", editFileCmd, ILLEGAL_IN_MARK|IGNORE_IN_ARG}, + {"-edit", uneditFileCmd, ILLEGAL_IN_MARK|IGNORE_IN_ARG}, + {"e", editFileCmd, ILLEGAL_IN_MARK|IGNORE_IN_ARG}, /* Duplicate shorthand */ + {"win", addWindowCmd, ILLEGAL_IN_MARK|IGNORE_IN_ARG}, + {"-win", delWindowCmd, ILLEGAL_IN_MARK|IGNORE_IN_ARG}, + {"cwin", chgWindowCmd, ILLEGAL_IN_MARK}, + {"status", statusCmd, ILLEGAL_IN_MARK|IGNORE_IN_ARG}, + {"save", saveCmd, IGNORE_IN_ARG}, + {"exit", exitCmd, ILLEGAL_IN_MARK|IGNORE_IN_ARG}, + + {"tabs", tabsCmd, IGNORE_IN_ARG}, + {"-update", noupdateCmd, IGNORE_IN_ARG}, + {"update", updateCmd, IGNORE_IN_ARG}, + {"insertMode", insertModeCmd, 0}, + {"defineKey", defineKeyCmd, 0}, + {"tag", tagCmd, ILLEGAL_IN_MARK}, + {"check", checkCmd, 0}, + {"set", setCmd, IGNORE_IN_ARG}, + {NULL, NULL}}; + +findCmd(char *cmdName, cmdStruct **cmdPtr, int startup) +{ +int i, best=-1, l1; + + l1 = strlen(cmdName); + for(i=0; globalCmd[i].funcName; i++) + { + if( strncmp(cmdName, globalCmd[i].funcName, l1) == 0 ) + { /* Check exact match */ + if( strlen(globalCmd[i].funcName) == l1) + { + *cmdPtr = &globalCmd[i]; + return(i); + } + + if( best == -1 ) + best = i; + else if(startup == 0) + { + emsg("ambiguous command"); + return(-1); + } + } + } + if( best != -1 ) + *cmdPtr = &globalCmd[best]; + return(best); +} + +main(int argc, char *argv[]) +{ +char *startFile[NUM_ALT_FILES]; +char escapeString[12]; +multiCharKeyDef *mk; +cmdStruct *cptr; +ucmdStruct *ucptr; +char *emptyArgSet[2], *oneArgSet[3]; +int i, j, c; + + oneArgSet[2] = emptyArgSet[1] = NULL; + globalData.tabSpace = 4; + globalData.ringBellOnErr = 1; + memset(startFile, 0, sizeof(char *) * NUM_ALT_FILES ); + for(j=0,i=1; icurParamSet); + globalData.activeWindow->curParamSet = i; + openFile(startFile[i], globalData.activeWindow); + } + } + else + readStartup(); + + redrawScreen(); + while( 1) + { + c = getc(stdin); + if( c == -1) + continue; + cptr = NULL; + if( c == '\033' ) + { /* Escape sequence; next char should be a [ */ + /* followed by either a single non-digit or */ + /* one or more digits terminated by a ~ */ + if( (c=getc(stdin)) == EOF ) + { +BAD_ESC: + dingMsg("Illegal char escape"); + continue; /* Data should be ready immediately */ + } + + j = 0; + escapeString[j++] = c; + if( (c=getc(stdin)) == EOF ) + goto BAD_ESC; + escapeString[j++] = c; + if( isdigit(c) ) + { /* Collect to trailing ~ */ + while( jnext) + if( strcmp(mk->charSeq, escapeString) == 0) + break; + if( !mk ) + { + char tmpe[512]; + sprintf(tmpe, "Unknown escape %s", escapeString); + dingMsg(tmpe); + continue; + } + cptr = mk->cmd; + c = 256; /* Make it out there */ + } + + if( globalData.argMode ) + { + if( c == '\r' ) + { + globalData.argBuffer[globalData.argPtr] = '\0'; + clearArgDisplay(); + processCmd(globalData.argBuffer); + globalData.argPtr = 0; + globalData.argMode = 0; + continue; + } + else if( c == 127 ) /* Backspace 1 */ + { + if( globalData.argPtr ) + { + globalData.argPtr--; + printf("\033[D \033[D"); + } + continue; + } + else if( cptr || (cptr=globalData.keyMap[c]) ) + { /* It should be an arg to the keymap's func */ + if( cptr->flags & IGNORE_IN_ARG ) + continue; /* Quietly ignore */ + globalData.argBuffer[globalData.argPtr] = '\0'; + clearArgDisplay(); + oneArgSet[0] = cptr->funcName; + oneArgSet[1] = globalData.argBuffer; + (cptr->func)(2, oneArgSet); + globalData.argPtr = 0; + globalData.argMode = 0; + continue; + } + else if( globalData.argPtr +1 >= globalData.argBufferSize ) + { + globalData.argBuffer = realloc(globalData.argBuffer, + globalData.argBufferSize + 50); + globalData.argBufferSize += 50; + } + globalData.argBuffer[globalData.argPtr++] = c; + putchar(c); + } + else if( cptr || (cptr=globalData.keyMap[c]) ) + { + if( globalData.markSet && cptr->flags & ILLEGAL_IN_MARK ) + { + dingMsg("Can't do that with marks set"); + updateCursor(globalData.activeWindow); + } + else if( cptr->funcName == NULL ) + { /* pre-packaged */ + ucptr = (ucmdStruct *)cptr; + (*ucptr->func)(ucptr->argc, ucptr->argv); + continue; + } + else + { + emptyArgSet[0] = cptr->funcName; + (*cptr->func)(1, emptyArgSet); + } + } + else if( isprint(c) ) + addChar(c); + else + { + char tmpe[20]; + sprintf(tmpe, "key %d undefined", c); + dingMsg(tmpe); + } + } + exit(0); +} + +/* Simple create for 1st window which is mandatory */ +createInitialWindow(int x, int y, int width, int height) +{ +windowStruct *w; + + w = (windowStruct *) calloc(1, sizeof(windowStruct)); + w->x = x; + w->y = y; + w->width = width; + w->height = height; + w->next = globalData.windowList; + globalData.windowList = w; + globalData.activeWindow = w; + return(1); +} + +/* Add a character at the current cursor position. May need to */ +/* Convert the line from disk to memory or extend it. Also, must pay */ +/* attention if insert mode is on or off */ +addChar(int c) +{ +windowStruct *w = globalData.activeWindow; +fileStruct *fs = w->fileInfo; +lineStruct *ls, *ns; +char *line; +int i, cnt, lc, edge, col; + + if( fs == NULL ) + { + emsg("No file open"); + return(0); + } + + /* Get correct line */ + if( !getCursorLine(w, &ls) ) + return(0); + if( !canModifyFile(fs) ) + return(0); + fs->head->flags = fs->head->flags & ~1; + if( ls->numCharsAvail == 0) /* Not In memory */ + unpackDiskLine(fs, ls); + + if( ls->numChars < w->leftOffset + w->cursorX ) + { /* We are end of the line */ + if( isspace(c) ) + return(cursorRight(1)); /* Do nothing but move the cursor */ + /* We are right, so insert mode makes no diff */ + /* But we could need ALOT more space */ + if( ls->numCharsAvail < w->leftOffset + w->cursorX ) + { + cnt = w->leftOffset + w->cursorX + 40; + ls->data.line = (char *) realloc(ls->data.line, + cnt+1); + ls->numCharsAvail = cnt; + } + for(i=ls->numChars; ileftOffset + w->cursorX-1; i++) + ls->data.line[i] = ' '; + ls->data.line[i] = c; + ls->data.line[i+1] = '\0'; + ls->numChars = i+1; + if( w->cursorX + 1 >= w->width ) + return(cursorRight(1)); + w->cursorX++; + putchar(c); + return(1); + } + + if( globalData.insertMode ) + { /* Adds a char at this position */ + if( ls->numCharsAvail < ls->numChars+1 ) + { /* Need to reallocate */ + ls->data.line = (char *)realloc(ls->data.line, + ls->numCharsAvail+41); + ls->numCharsAvail += 40; + } + i=w->leftOffset+w->cursorX-1; + col = w->cursorX; + if( col + 1 >= w->width ) + edge = 1; + else + edge = 0; + for(; ls->data.line[i]; i++) + { + lc = ls->data.line[i]; + ls->data.line[i] = c; + if( !edge ) + { + if( col < w->width ) + putchar(c); + else if( col == w->width ) + putchar('>'); + col++; + } + c = lc; + } + ls->data.line[i++] = c; + ls->data.line[i] = '\0'; + ls->numChars++; + if( !edge ) + { + if( col < w->width ) + putchar(c); + else if( col == w->width ) + putchar('>'); + w->cursorX++; + updateCursor(w); + } + else + return(cursorRight(1)); + } + else /* Overstrike, never adds a char */ + { + ls->data.line[w->leftOffset+w->cursorX-1] = c; + + /* Check if we are at the right edge */ + if( w->cursorX + 1 >= w->width ) + return(cursorRight(1)); + /* Nope, do it cheap */ + w->cursorX++; + putchar(c); + } + return(1); +} + +unpackDiskLine(fileStruct *fs, lineStruct *ls) +{ +char *line; + + ls->flags = ls->flags & ~1; /* A real line now */ + if( ls->numChars == 0 ) + { /* Nothing or new area */ + ls->numCharsAvail = 80; + ls->data.line = (char *) malloc(81); + ls->data.line[0] = '\0'; + return(1); + } + + /* Get the line */ + ls->numChars = getChars(fs, ls, ls->numChars+1, &line); + if( ls->numChars < 80 ) + ls->numCharsAvail = 80; + else + ls->numCharsAvail = ls->numChars + 20; + ls->data.line = (char *) malloc(ls->numCharsAvail+1); + strcpy(ls->data.line, line); + return(1); +} + +/* Get at least numchars and return a ptr to them. */ +/* Returns number of chars */ +getChars(fileStruct *fs, lineStruct *ls, int numChars, char **s) +{ +int i, j, k, ix, tcnt; +char *line; + + if( ls->numCharsAvail ) + { + *s = ls->data.line; +/* For debug */ +#if 0 + if( strlen(ls->data.line) != ls->numChars ) + { + char tmpe[12]; + sprintf(tmpe, "%d != %d", strlen(ls->data.line), ls->numChars); + emsg(tmpe); + ls->numChars = strlen(ls->data.line); + } +#endif + return(ls->numChars); + } + else if( ls->numChars == 0 ) + { + *s = ""; + return(0); + } + fseek(fs->fp, ls->data.offset, SEEK_SET); + if( numChars < ls->numChars ) + i = numChars; + else + i = ls->numChars; + line = (char *) alloca(i+1); + fread(line, 1, i, fs->fp); + line[i] = '\0'; + + /* How many tab expansion chars ? */ + for(i=0, ix=0; line[i]; i++) + { + if( line[i] == '\t' ) + ix += 8 - (ix % 8); + else + ix++; + } + + if( ix+1 > globalData.lineBufferSize ) + { + if( globalData.lineBufferSize ) + free(globalData.lineBuffer); + globalData.lineBufferSize = ix + 128; + if( globalData.lineBufferSize < 1024 ) + globalData.lineBufferSize = 1024; + globalData.lineBuffer = (char *) malloc(globalData.lineBufferSize); + } + + /* Put the data in final blank expanded format */ + for(i=j=0, ix=0; line[i]; i++) + { + if( line[i] == '\t' ) + { + tcnt = 8 - (ix % 8); + for(k=0; kro ) + { + dingMsg("Read Only"); + return(0); + } + fs->modified = 1; + return(1); +} diff --git a/src/cmd/sre/misc.c b/src/cmd/sre/misc.c new file mode 100644 index 0000000..d9287d5 --- /dev/null +++ b/src/cmd/sre/misc.c @@ -0,0 +1,168 @@ +/* A weekend project to try to emulate the original RAND text editor + Copyright (C) 2011 Mike Stabenfeldt + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "edit.h" +extern globalStruct globalData; + +updateCmd(int argc, char **argv) +{ +windowStruct *w = globalData.activeWindow; +fileStruct *fs; + + if( !(fs=w->fileInfo) ) + { + emsg("No file open;Use ^space edit to open"); + updateCursor(w); + return(0); + } + emsg("INFO: Changes to file will be saved"); + updateCursor(w); + fs->nosave = 0; + return(1); +} + +noupdateCmd(int argc, char **argv) +{ +windowStruct *w = globalData.activeWindow; +fileStruct *fs; + + if( !(fs=w->fileInfo) ) + { + emsg("No file open;Use ^space edit to open"); + updateCursor(w); + return(0); + } + emsg("INFO: Changes to file will NOT be saved"); + updateCursor(w); + fs->nosave = 1; + return(1); +} + +insertModeCmd(int argc, char **argv) +{ +windowStruct *w = globalData.activeWindow; +fileStruct *fs; + + if( !(fs=w->fileInfo) ) + { + emsg("No file open;Use ^space edit to open"); + updateCursor(w); + return(0); + } + globalData.insertMode = 1 - globalData.insertMode; + redrawWindow(w); + return(1); +} + +/* Set number of spaces between tabs */ +/* RE was more versatile, it was like a typewriter and */ +/* tab could be set randomly. the tabs in RE just set each tabstop */ +tabsCmd(int argc, char **argv) +{ +windowStruct *w = globalData.activeWindow; +int cnt; + + if( argc != 2 ) + { + emsg("Need an argument to tabs"); + updateCursor(w); + return(0); + } + cnt = atoi(argv[1]); + if( cnt <= 1 ) + { + emsg("tabs arg must be > 1"); + updateCursor(w); + return(0); + } + globalData.tabSpace = cnt; + redrawWindow(w); + return(1); +} + +setCmd(int argc, char **argv) +{ +int i; +windowStruct *w = globalData.activeWindow; +lineStruct *ls; + + if( argc != 3 ) + { + emsg("set var value"); + updateCursor(globalData.activeWindow); + return(0); + } + + if( strcasecmp(argv[1], "insertMode") == 0) + { + if( atoi(argv[2]) == 0 ) + globalData.insertMode = 0; + else + globalData.insertMode = 1; + } + else if( strcasecmp(argv[1], "bell") == 0 ) + { + if( atoi(argv[2]) == 0 ) + globalData.ringBellOnErr = 0; + else + globalData.ringBellOnErr = 1; + } + else if(strcasecmp(argv[1], "searchKey") == 0) + { + if( (i=(strlen(argv[2])+1)) >= globalData.srchBufferSize ) + { + if( globalData.srchBuffer ) + free(globalData.srchBuffer); + if( i < 128 ) + i = 128; + globalData.srchBufferSize = i; + globalData.srchBuffer = (char *) malloc(i); + } + /* set demands a quoted string, strip start/end quotes */ + strcpy(globalData.srchBuffer, &argv[2][1]); + globalData.srchBuffer[strlen(globalData.srchBuffer)-1] = '\0'; + } + else if( strcasecmp(argv[1], "rangetop") == 0 ) + { + if( w ) + { + w->rangeTopNum = atoi(argv[2]); + } + } + else if( strcasecmp(argv[1], "rangebot") == 0 ) + { + if( w ) + { + w->rangeBotNum = atoi(argv[2]); + } + } + else + emsg("Unknown var"); + + updateCursor(globalData.activeWindow); + return(0); +} diff --git a/src/cmd/sre/render.c b/src/cmd/sre/render.c new file mode 100644 index 0000000..2660fb4 --- /dev/null +++ b/src/cmd/sre/render.c @@ -0,0 +1,413 @@ +/* A weekend project to try to emulate the original RAND text editor + + Copyright (C) 2011 Mike Stabenfeldt + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#include +#include +#include +#include +#include +#include + +#include "edit.h" + +extern globalStruct globalData; + +refreshScreen() +{ +int i; + + /* Clear screen */ + printf("\033[2J"); + for(i=0; ifileInfo) + { + updateStatus(); + updateCursor(globalData.activeWindow); + } + else + { + printf(" No file open;Use ^space edit to open"); + printf("\033[%d;%dH", 4, 4); + printf("sre Copyright (C) 2011 Mike Stabenfeldt\n\r"); + printf("\033[%d;%dH", 5, 4); + printf("This program comes with ABSOLUTELY NO WARRANTY;\n\r"); + printf("\033[%d;%dH", 7, 4); + printf("This is free software, and you are welcome\n\r"); + printf("\033[%d;%dH", 8, 4); + printf("to redistribute it under certain conditions;\n\r"); + printf("\033[%d;%dH", 9, 4); + printf("goto http://www.gnu.org/licenses for details.\n\r"); + + printf("\033[%d;%dH", 12, 4); + printf("Exit with X\n\r"); + } + + +} + +redrawWindow(windowStruct *w) +{ +int i, j, k, l, active, six; +lineStruct *ls; +char *s, *screen; + + if( !w->fileInfo ) + return(0); + active = 0; + i = w->width + 5; + screen = (char *) alloca(i); + if( w == globalData.activeWindow ) + active = 1; + if( !w->topLine ) /* Ah, dirty from another window delete */ + { + if( w->fileInfo->numLines < w->topOffset-2 ) + w->topOffset = w->fileInfo->numLines-2; + if( w->topOffset < 0 ) + w->topOffset = 0; + getLine(w, w->fileInfo, w->topOffset, &w->topLine); + } + ls = w->topLine; + /* Top decoration */ + printf("\033[%d;%dH", w->y, w->x); + if( active ) + { + i=0; + if( globalData.insertMode ) + screen[i++] = 'I'; + else + screen[i++] = 'O'; + for(; iwidth; i++) + { + if( i != 1 && (i-1 + w->leftOffset) % globalData.tabSpace == 0 ) + screen[i] = 'T'; + else if( i == 1 && ( w->rangeTopNum || w->rangeBotNum) ) + screen[i] = 'R'; + else + screen[i] = '-'; + } + } + else + { + for(i=0; iwidth; i++) + screen[i] = '.'; + } + screen[i] = '\0'; + printf("%s", screen); + for(i=0; iheight-1; i++) + { /* set to start & put out decoration */ + six=0; + printf("\033[%d;%dH", i+w->y+1, w->x); + if( active ) + { + if( ls ) + { + if( w->leftOffset == 0 ) + { + if( ls->flags & 1) /* Internal Filler line */ + screen[six++] = ':'; + else if( w->rangeTopNum || w->rangeBotNum ) + { + screen[six] = '*'; + if( w->rangeTopNum == 0 ) + { + if( w->topOffset + i < w->rangeBotNum ) + screen[six] = '|'; + } + else if( w->rangeBotNum == 0 ) + { + if( w->topOffset + i + 1 >= w->rangeTopNum ) + screen[six] = '|'; + } + else + { + if( w->topOffset + i < w->rangeBotNum && + w->topOffset + i + 1 >= w->rangeTopNum ) + screen[six] = '|'; + } + six++; + } + else + screen[six++] = '|'; + } + else + screen[six++] = '<'; + } + else + screen[six++] = ';'; + } + else + screen[six++] = '.'; + if( ls ) + { + getChars(w->fileInfo, ls, w->leftOffset + w->width+1, &s); + for(j=k=0; jleftOffset+w->width-1; ) + { + if( s[k] == '\0') + { + if( j >= w->leftOffset ) + screen[six++] = ' '; + j++; + } + else if( s[k] == '\t' ) + { + k++; + for(l=0; j < w->width-1 && l < 8; j++, l++) + if( j >= w->leftOffset ) + screen[six++] = ' '; + } + else + { + if( j >= w->leftOffset ) + screen[six++] = s[k]; + k++; + j++; + } + } + if( active ) + { + if( s[k] != '\0' ) + screen[six++] = '>'; + else if(active) + screen[six++] = '|'; + else + screen[six++] = ';'; + } + else + screen[six++] = '.'; + + ls = ls->next; + } + else + { + for(j=0; jwidth-1; j++) + screen[six++] = ' '; + if( active ) + screen[six++] = ';'; + else + screen[six++] = '.'; + } + screen[six] = '\0'; + printf("%s", screen); + } + /* Bottom decoration and status display update */ + if( active ) + { + if( globalData.searchMode == 0 ) + screen[0] = 'L'; + else if( globalData.searchMode == 1 ) + screen[0] = 'C'; + else + screen[0] = 'R'; + for(i=1; iwidth; i++) + screen[i] = '-'; + if( globalData.activeWindow->fileInfo && + globalData.activeWindow->fileInfo->modified ) + screen[i++] = '*'; + else + screen[i++] = '+'; + screen[i] = '\0'; + printf("\033[%d;%dH%s", w->y+w->height, w->x, screen); + updateStatus(); + updateCursor(w); + } + else + { + for(i=0; iwidth; i++) + screen[i] = '.'; + screen[i] = '\0'; + printf("\033[%d;%dH%s", w->y+w->height, w->x, screen); + } + return(1); +} + + +redrawLine(windowStruct *w, int offset, lineStruct *ls) +{ +int i, j, k, l, active, six; +char *s, *screen; + + active = 0; + i = w->width + 5; + screen = (char *) alloca(i); + if( w == globalData.activeWindow ) + active = 1; + + six=0; + printf("\033[%d;%dH", offset+w->y, w->x); + if( active ) + { + if( ls ) + { + if( w->leftOffset == 0) + { + if( ls->flags & 1 ) + screen[six++] = ':'; + else + screen[six++] = '|'; + } + else + screen[six++] = '<'; + } + else + screen[six++] = ';'; + } + else + screen[six++] = '.'; + if( ls ) + { + getChars(w->fileInfo, ls, w->leftOffset + w->width+1, &s); + for(j=k=0; jleftOffset+w->width-1; ) + { + if( s[k] == '\0') + { + if( j >= w->leftOffset ) + screen[six++] = ' '; + j++; + } + else if( s[k] == '\t' ) + { + k++; + for(l=0; j < w->width-1 && l < 8; j++, l++) + if( j >= w->leftOffset ) + screen[six++] = ' '; + } + else + { + if( j >= w->leftOffset ) + screen[six++] = s[k]; + k++; + j++; + } + } + if( active ) + { + if( s[k] != '\0' ) + screen[six++] = '>'; + else if(active) + screen[six++] = '|'; + else + screen[six++] = ';'; + } + else + screen[six++] = '.'; + } + else + { + for(j=0; jwidth-1; j++) + screen[six++] = ' '; + if( active ) + screen[six++] = ';'; + else + screen[six++] = '.'; + } + screen[six] = '\0'; + printf("%s", screen); +} + +/* Redraw everything */ +redrawScreen() +{ +windowStruct *w; + + refreshScreen(); + for(w=globalData.windowList; w; w=w->next) + if( w != globalData.activeWindow ) + redrawWindow(w); + redrawWindow(globalData.activeWindow); +} + +/* Update the current cursor position on the screen */ +updateCursor(windowStruct *w) +{ + printf("\033[%d;%dH", + w->y+w->cursorLineNo, + w->x+w->cursorX); +} + +updateStatus() +{ +windowStruct *w=globalData.activeWindow; +char statusLine[256]; +int len, flen, avail, cnt; + + if( w->fileInfo) + { + /* Set cursor pos and erase to right */ + /* May not have enough room for full file name */ + printf("\033[%d;%dH\033[0K", + globalData.winHeight, + globalData.winWidth/2); + avail = globalData.winWidth/2; + len = sprintf(statusLine, " %-4lldx%d in ", + w->cursorLineNo + + w->topOffset, + w->cursorX + + w->leftOffset); + if( len+3 > avail ) + statusLine[avail] = '\0'; + else + { /* Otherwise no room at all */ + flen = strlen(w->fileInfo->fileName); + if( flen + len < globalData.winWidth/2 ) + strcpy(&statusLine[len], w->fileInfo->fileName); + else + { + statusLine[len++] = '.'; + statusLine[len++] = '.'; + cnt = avail - len; + strcpy( &statusLine[len], + &(w->fileInfo->fileName[flen - cnt])); + } + } + fputs(statusLine, stdout); + } + if( globalData.markSet ) + { + int dx, len; + long long dy; + char tmp[512]; + + dx = w->leftOffset + w->cursorX - globalData.markRefX; + dy = w->topOffset + w->cursorLineNo - globalData.markRefY; + if( dx == 0 ) + len = sprintf(tmp, "MARK: %lld", dy); + else + len = sprintf(tmp, "MARK: %lldx%d", dy, dx); + for(; len. +*/ +#include +#include +#include +#include +#include +#include + +#include "edit.h" + +extern globalStruct globalData; + +/* key is ^X etc for a control char */ +/* ^A is one, ^space is 0 */ + +defineKeyCmd(int argc, char **argv) +{ +int i, c, len; +char escapeSequence[10]; +cmdStruct *cmd, *cmdx; +ucmdStruct *ucmd; + + if( argc < 3 ) + { + emsg("defineKey: key cmd [args]"); + return(0); + } + /* parse the key part */ + if( argv[1][0] == '^' ) + { + if( strlen(argv[1]) == 2 ) + { + c = argv[1][1]; + if( c >= 64 && c < 96 ) + c = c-64; + else if( c >= 97 && c <= 122 ) + c = c - 96; /* Lower case a-z */ + else + { +BADCTL: + printf("Unknown control character %c\n\r", c); + printf("Value specified is in decimal\n\r"); + printf("Must be a single character or backspace.\n"); + return(0); + } + } + else if( strcasecmp(&argv[1][1], "bs") == 0 || + strcasecmp(&argv[1][1], "backspace") == 0 ) + c = 127; + else + goto BADCTL; + } + else + { /* An escape sequence, escape is assumed */ + if( strlen(argv[1]) > 6 ) + { + printf("Escape sequence should never be more than 6 characters\n"); + return(0); + } + strcpy(escapeSequence, argv[1]); + c = -1; + } + + /* If there are more than 2 args, then we need to convert it to a string type command */ + /* In any event, argv[2], must be a known command */ + if( findCmd(argv[2], &cmd, 0) == -1 ) + { + printf("No command named %s; ignore binding\n", argv[2]); + return(0); + } + if( argc == 3 ) /* Simple atomic command */ + cmdx = cmd; + else + { /* Need to create a command string that will get executed by processCmd */ + ucmd = (ucmdStruct *) calloc(1, sizeof(ucmdStruct) + sizeof(char *)*(argc-2)); + ucmd->func = cmd->func; + ucmd->flags = ILLEGAL_IN_MARK | IGNORE_IN_ARG; + ucmd->argc = argc-2; + for(i=2; iargv[i-2] = (char *)malloc(strlen(argv[i])+1); + strcpy(ucmd->argv[i-2], argv[i]); + } + cmdx = (cmdStruct *) ucmd; + } + if( c == -1 ) + { /* Multi key definition */ + defineMultiCharKey(escapeSequence, cmdx); + } + else + globalData.keyMap[c] = cmdx; + return(1); +} + +defineMultiCharKey(char *keySeq, cmdStruct *cptr) +{ +multiCharKeyDef *mk; + + mk = (multiCharKeyDef *)calloc(1, sizeof(multiCharKeyDef)); + mk->charSeq = strdup(keySeq); + mk->cmd = cptr; + mk->next = globalData.multiList; + globalData.multiList = mk; + return(1); +} + +setupCmdMap() +{ +cmdStruct *cptr; + + findCmd("arg", &globalData.keyMap[0], 0); + findCmd("pageLeft", &globalData.keyMap[1], 0); /* A */ + findCmd("edit", &globalData.keyMap[2], 0); /* B */ + findCmd("open", &globalData.keyMap[4], 0); /* D */ + findCmd("searchUp", &globalData.keyMap[5], 0); /* E */ + findCmd("cut", &globalData.keyMap[6], 0); /* F */ + /* Note that an empty arg with a cut is an uncut */ + findCmd("mark", &globalData.keyMap[7], 0); /* G */ + findCmd("cursorLeft", &globalData.keyMap[8], 0); /* H */ + findCmd("tabRight", &globalData.keyMap[9], 0); /* I */ + findCmd("cursorDn", &globalData.keyMap[10], 0); /* J */ + findCmd("cursorRight", &globalData.keyMap[11], 0); /* K */ + findCmd("get", &globalData.keyMap[12], 0); /* L */ + /* Note that an empty arg with a get is a put */ + findCmd("return", &globalData.keyMap[13], 0); /* M */ + findCmd("cursorUp", &globalData.keyMap[14], 0); /* N */ + findCmd("insertMode", &globalData.keyMap[15], 0); /* O */ + findCmd("pageUp", &globalData.keyMap[16], 0); /* P */ + findCmd("searchDn", &globalData.keyMap[18], 0); /* R */ + findCmd("save", &globalData.keyMap[19], 0); /* S */ + findCmd("scrollDn", &globalData.keyMap[20], 0); /* T */ + findCmd("wipeChar", &globalData.keyMap[21], 0); /* U */ + findCmd("pageRight", &globalData.keyMap[22], 0); /* V */ + findCmd("scrollUp", &globalData.keyMap[23], 0); /* W */ + findCmd("exit", &globalData.keyMap[24], 0); /* X */ + findCmd("pageDn", &globalData.keyMap[25], 0); /* Y */ + findCmd("cwin", &globalData.keyMap[26], 0); /* Z */ + findCmd("tabLeft", &globalData.keyMap[29], 0); /* ] */ + findCmd("deleteChar", &globalData.keyMap[127], 0); /* del/bs */ + + /* Default multi-char keys */ + findCmd("cursorDn", &cptr, 0); /* arrow keys */ + defineMultiCharKey("[B", cptr); + findCmd("cursorUp", &cptr, 0); + defineMultiCharKey("[A", cptr); + findCmd("cursorLeft", &cptr, 0); + defineMultiCharKey("[D", cptr); + findCmd("cursorRight", &cptr, 0); + defineMultiCharKey("[C", cptr); + + findCmd("match", &cptr, 0); + defineMultiCharKey("[E", cptr); + + findCmd("pageUp", &cptr, 0); + defineMultiCharKey("[5~", cptr); + findCmd("pageDn", &cptr, 0); + defineMultiCharKey("[6~", cptr); + + + findCmd("deleteChar", &cptr, 0); + defineMultiCharKey("[3~", cptr); +} + +struct termios tioOrigIn; +struct termios tioOrigOut; + +restoreTerm() +{ + /* Restore main screen */ + printf("\033[?47l"); + printf("\033[%d;1H", globalData.winHeight); + tcsetattr(fileno(stdin), TCSANOW, &tioOrigIn); + tcsetattr(fileno(stdout), TCSANOW, &tioOrigOut); +} + +setupTerm() +{ +int c, w, h, i; +char tmp[20]; +struct termios tio; + + /* These appear to be tied together, as a req for stdout is modified */ + /* by the stdin request */ + tcgetattr(fileno(stdout), &tioOrigOut); + tcgetattr(fileno(stdin), &tio); + memcpy( &tioOrigIn, &tio, sizeof(struct termios)); + cfmakeraw(&tio); + tcsetattr(fileno(stdin), TCSAFLUSH, &tio); + tcgetattr(fileno(stdout), &tio); + cfmakeraw(&tio); + /* Make the terminal non-blocking and wait 1/10th of a second for a char */ + tio.c_cc[VMIN] = 0; + tio.c_cc[VTIME] = 1; + tcsetattr(fileno(stdout), TCSADRAIN, &tio); + tcgetattr(fileno(stdout), &tio); + /* Get terminal height/width */ + printf("\033[18t"); + i = 0; + while((c=getc(stdin)) != EOF && i < 20 ) + { + if( c == 't' ) + { + tmp[i] = '\0'; + break; + } + tmp[i++] = c; + } + if( i == 20 ) + { + globalData.winHeight = 24; + globalData.winWidth = 80; + emsg("Failed to get terminal width/height\n"); + } + else + { + sscanf(&tmp[4], "%d;%d", &h, &w); + globalData.winHeight = h; + globalData.winWidth = w; + /* switch to alternate screen */ + printf("\033[?47h"); + } +} + +emsg(char *s) +{ +int i, j; + + if( globalData.mode == 0 ) + printf("%s\n", s); + else + { + printf("\033[%d;%dH", + globalData.winHeight, 1); + for(i=j=0; i. +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "edit.h" +extern globalStruct globalData; + +getWordUnderCursor(windowStruct *w, char **wordP) +{ +int i, j, len, wlen; +fileStruct *fs; +lineStruct *ls; +char *line; + + fs = w->fileInfo; + getCursorLine(w, &ls); + len = getChars(fs, ls, ls->numChars+1, &line); + if( len < w->cursorX ) + { +NOTHING: + dingMsg("No word under cursor"); + return(-1); + } + + if( !isalnum(line[w->cursorX-1]) ) + goto NOTHING; + + /* Backup to beginning of word */ + for(i=w->cursorX-1; i>0; i--) + if( !isalnum(line[i]) ) + { + i++; + break; + } + + for(j=i+1; j globalData.wordBufferSize ) + { + if( wlen < 80 ) + wlen = 80; + if( globalData.wordBuffer ) + free(globalData.wordBuffer); + globalData.wordBuffer = (char *) malloc(wlen); + globalData.wordBufferSize = wlen; + } + + wlen = j-i; + memcpy(globalData.wordBuffer, &line[i], wlen); + globalData.wordBuffer[wlen] = '\0'; + *wordP = globalData.wordBuffer; + return(i); +} + +searchDnCmd(int argc, char **argv) +{ +windowStruct *w=globalData.activeWindow; +fileStruct *fs; +lineStruct *ls; +int i, cx, startLineNo, startX, foundLineNo, foundX; +int keyLen, lineLen, needRedraw=0; +char *tmp, *line; + + if( !(fs=w->fileInfo) ) + { + emsg("Open a file before search"); + return(0); + } + if( argc > 1 ) + { + if( argv[1][0] ) + { + if( (i=strlen(argv[1])+1) >= globalData.srchBufferSize ) + { + if( globalData.srchBuffer ) + free(globalData.srchBuffer); + if( i < 128 ) + i = 128; + globalData.srchBufferSize = i; + globalData.srchBuffer = (char *)malloc(i); + } + strcpy(globalData.srchBuffer, argv[1]); + } + else /* Search for word under cursor */ + { + if( getWordUnderCursor(w, &tmp) == -1) + { + updateCursor(w); + return(0); + } + if( (i=strlen(tmp)+1) >= globalData.srchBufferSize ) + { + if( globalData.srchBuffer ) + free(globalData.srchBuffer); + if( i < 128 ) + i = 128; + globalData.srchBufferSize = i; + globalData.srchBuffer = (char *)malloc(i); + } + strcpy(globalData.srchBuffer, tmp); + } + } + + if( !globalData.srchBuffer || globalData.srchBuffer[0] == '\0' ) + { + dingMsg("Nothing to search for"); + updateCursor(w); + return(0); + } + + tmp = (char *) alloca(strlen(globalData.srchBuffer) + 8); + strcpy(tmp, "+SRCH: "); + strcpy(&tmp[7], globalData.srchBuffer); + emsg(tmp); + + foundLineNo = startLineNo = w->cursorLineNo; + startX = w->leftOffset + w->cursorX -1; + for(i=1, ls=w->topLine; inext) + if( !ls ) + goto NOTFOUND; + + keyLen = strlen(globalData.srchBuffer); + cx = startX+1; + for( ; ls; foundLineNo++, ls=ls->next) + { + if( w->rangeBotNum && foundLineNo + w->topOffset > w->rangeBotNum ) + break; + if( ls->numChars != 0 ) + { + lineLen = getChars(fs, ls, ls->numChars+1, &line); + for( ; cxleftOffset >= w->width-1 || + foundX < w->leftOffset ) + { + needRedraw = 1; + /* Can we right the screen */ + if( foundX < w->width-1 ) + w->leftOffset = 0; + else + w->leftOffset = 2+foundX - w->width; + w->cursorX = 1+foundX - w->leftOffset; + } + else + w->cursorX = 1+foundX - w->leftOffset; + /* Do we need to adjust vertical ? */ + if( w->cursorLineNo != foundLineNo ) + w->cursorLine = NULL; + if( foundLineNo < w->height ) + { /* Nope */ + w->cursorLineNo = foundLineNo; + updateStatus(); + if( needRedraw ) + redrawWindow(w); + else + updateCursor(w); + } + else + gotoline(w, w->topOffset + foundLineNo); +/* emsg("srch key found"); */ + return(1); +} + +searchUpCmd(int argc, char **argv) +{ +windowStruct *w=globalData.activeWindow; +fileStruct *fs; +lineStruct *ls; +int i, cx, startLineNo, startX, foundLineNo, foundX; +int keyLen, lineLen, needRedraw=0; +char *tmp, *line; + + if( !(fs=w->fileInfo) ) + { + emsg("Open a file before search"); + return(0); + } + + if( argc > 1 ) + { + if( argv[1][0] ) + { + if( (i=strlen(argv[1])+1) >= globalData.srchBufferSize ) + { + if( globalData.srchBuffer ) + free(globalData.srchBuffer); + if( i < 128 ) + i = 128; + globalData.srchBufferSize = i; + globalData.srchBuffer = (char *)malloc(i); + } + strcpy(globalData.srchBuffer, argv[1]); + } + else /* Search for word under cursor */ + { + if( getWordUnderCursor(w, &tmp) == -1) + { + updateCursor(w); + return(0); + } + if( (i=strlen(tmp)+1) >= globalData.srchBufferSize ) + { + if( globalData.srchBuffer ) + free(globalData.srchBuffer); + if( i < 128 ) + i = 128; + globalData.srchBufferSize = i; + globalData.srchBuffer = (char *)malloc(i); + } + strcpy(globalData.srchBuffer, tmp); + } + } + + if( !globalData.srchBuffer || globalData.srchBuffer[0] == '\0' ) + { + dingMsg("Nothing to search for"); + updateCursor(w); + return(0); + } + + tmp = (char *) alloca(strlen(globalData.srchBuffer) + 8); + strcpy(tmp, "-SRCH: "); + strcpy(&tmp[7], globalData.srchBuffer); + emsg(tmp); + + startX = w->leftOffset + w->cursorX -1; + /* Get down to current line, or last avail line */ + for(i=1, ls=w->topLine; icursorLineNo; i++, ls=ls->next) + if( !ls->next ) + break; + foundLineNo = startLineNo = i; + + keyLen = strlen(globalData.srchBuffer); + cx = startX-1; + for( ; ls; foundLineNo--, ls=ls->prev) + { + if( foundLineNo + w->topOffset < w->rangeTopNum ) + break; + if( ls->numChars != 0 ) + { + lineLen = getChars(fs, ls, ls->numChars+1, &line); + if( cx == 0 ) + cx = lineLen-keyLen; + for( ; cx>=0; cx--) + { + if( strncmp(&line[cx], globalData.srchBuffer, keyLen) == 0) + { + foundX = cx; + goto FOUND; + } + } + } + cx = 0; + } +NOTFOUND: + dingMsg("Search failed"); + updateCursor(w); + return(0); + +FOUND: + if( 1+foundX - w->leftOffset >= w->width-1 || + foundX < w->leftOffset ) + { + needRedraw = 1; + /* Can we right the screen */ + if( foundX < w->width-1 ) + w->leftOffset = 0; + else + w->leftOffset = 2+foundX - w->width; + w->cursorX = 1+foundX - w->leftOffset; + } + else + w->cursorX = 1+foundX - w->leftOffset; + /* Do we need to adjust vertical ? */ + + if( foundLineNo >= 1 ) + { /* Nope */ + if( w->cursorLineNo != foundLineNo ) + { + w->cursorLine = NULL; + w->cursorLineNo = foundLineNo; + } + updateStatus(); + if( needRedraw ) + redrawWindow(w); + updateCursor(w); + } + else + gotoline(w, w->topOffset + foundLineNo); + return(1); +} + +matchCmd(int argc, char **argv) +{ +windowStruct *w=globalData.activeWindow; +fileStruct *fs; +lineStruct *ls; +char *line; +int i, len, searchC[2], cnt; +int startLineNo, foundLineNo, startX, foundX; +int lineLen, needRedraw; +char msg[20]; + + if( !(fs=w->fileInfo) ) + { + emsg("Open a file before match"); + return(0); + } + + getCursorLine(w, &ls); + + /* Get character under cursor */ + len = getChars(fs, ls, ls->numChars+1, &line); + i = w->cursorX + w->leftOffset - 1; + if( len < i ) + { +NOTHING: + dingMsg("No []{}() under cursor"); + updateCursor(w); + return(-1); + } + + if( line[i] == '(' ) + { + searchC[0] = '('; + searchC[1] = ')'; + cnt = 1; + } + else if( line[i] == ')' ) + { + searchC[0] = '('; + searchC[1] = ')'; + cnt = -1; + } + else if( line[i] == '[' ) + { + searchC[0] = '['; + searchC[1] = ']'; + cnt = 1; + } + else if( line[i] == ']' ) + { + searchC[0] = '['; + searchC[1] = ']'; + cnt = -1; + } + else if( line[i] == '{' ) + { + searchC[0] = '{'; + searchC[1] = '}'; + cnt = 1; + } + else if( line[i] == '}' ) + { + searchC[0] = '{'; + searchC[1] = '}'; + cnt = -1; + } + else + goto NOTHING; + + sprintf(msg, "match %c%c", searchC[0], searchC[1]); + emsg(msg); + + startX = w->leftOffset + w->cursorX -1; + foundLineNo = startLineNo = w->cursorLineNo; + + if( cnt < 0 ) /* looking backward */ + { + for( ; ls; foundLineNo--, ls=ls->prev) + { + if( foundLineNo + w->topOffset < w->rangeTopNum ) + break; + if( ls->numChars != 0 ) + { + lineLen = getChars(fs, ls, ls->numChars+1, &line); + if( startX >= 0 ) + foundX = startX-1; + else + foundX = lineLen - 1; + for( ; foundX>=0; foundX--) + { + if( line[foundX] == searchC[0] ) + cnt++; + else if( line[foundX] == searchC[1] ) + cnt--; + if( cnt == 0 ) + goto FOUND; + } + } + startX = -1; + } + } + else + { + for( ; ls; foundLineNo++, ls=ls->next) + { + if( w->rangeBotNum && foundLineNo + w->topOffset > w->rangeBotNum ) + break; + if( ls->numChars != 0 ) + { + lineLen = getChars(fs, ls, ls->numChars+1, &line); + if( startX >= 0 ) + foundX = startX+1; + else + foundX = 0; + for( ; foundXleftOffset >= w->width-1 || + foundX < w->leftOffset ) + { + needRedraw = 1; + /* Can we right the screen */ + if( foundX < w->width-1 ) + w->leftOffset = 0; + else + w->leftOffset = 2+foundX - w->width; + w->cursorX = 1+foundX - w->leftOffset; + } + else + w->cursorX = 1+foundX - w->leftOffset; + if( foundLineNo != w->cursorLineNo ) + w->cursorLine = NULL; + /* Do we need to adjust vertical ? */ + if( foundLineNo >= 1 && foundLineNo < w->height ) + { /* Nope */ + w->cursorLineNo = foundLineNo; + updateStatus(); + if( needRedraw ) + redrawWindow(w); + updateCursor(w); + } + else + gotoline(w, w->topOffset + foundLineNo); + return(1); +} + +/* Assume caller allocated reference/replacement based on size of inString */ +static int cutRplString(char *inString, char *reference, char *replace) +{ +char delim; +int i, j; + + if( strlen(inString) < 3 ) + { +BAD: + dingMsg("Bad /ref/replace/"); + return(0); + } + delim = inString[0]; + for(i=1, j=0; inString[i]; i++) + { + if( inString[i] == delim ) + { + reference[j] = '\0'; + break; + } + reference[j++] = inString[i]; + } + /* Must have hit delimiter and reference must be non-null */ + if( ! inString[i] || j == 0 ) + goto BAD; + + for(i++, j=0; inString[i]; i++) + { + if( inString[i] == delim ) + { + replace[j] = '\0'; + break; + } + replace[j++] = inString[i]; + } + /* Must have hit delimiter and must be end of string */ + if( ! inString[i] || inString[i+1] ) + goto BAD; + return(1); +} + +/* Replace the ref with the new */ +/* If marks are set, limit to marked area */ +/* If range is set, limit from cursor to end of range */ +/* If no range, limit from cursor to end of file */ +replaceCmd(int argc, char **argv) +{ +windowStruct *w=globalData.activeWindow; +fileStruct *fs; +lineStruct *ls, *last = NULL; +int i, start, refLen, replLen, cnt=0; +char *reference, *replace, *line, *s, tmp[50]; + + if( !(fs=w->fileInfo) ) + { + emsg("Open a file before replace"); + return(0); + } + if( argc != 2 ) + { + dingMsg("Specify one arg"); + return(0); + } + + i = strlen(argv[1]); + reference = (char *) alloca(i+1); + replace = (char *) alloca(i+1); + if( !cutRplString(argv[1], reference, replace) ) + return(0); + refLen = strlen(reference); + replLen = strlen(replace); + + getCursorLine(w, &ls); + if( globalData.markSet ) + { + if( w->leftOffset + w->cursorX != globalData.markRefX ) + { + dingMsg("Can't replace in rect region"); + return(0); + } + if( w->topOffset + w->cursorLineNo < globalData.markRefY ) + { + getLine(w, fs, globalData.markRefY-1, &last); + } + else + { + last = ls; + getLine(w, fs, globalData.markRefY-1, &ls); + } + } + else if( w->rangeBotNum ) + getLine(w, fs, w->rangeBotNum-1, &last); + + if( !canModifyFile(fs) ) + return(0); + + /* We will need to unpack all the lines we are changing */ + for( ; ls ; ls=ls->next) + { + if( getChars(fs, ls, ls->numChars+1, &line) < refLen ) + goto CHK; + if( strstr(line, reference) ) + { /* Replacement needed, must unpack */ + unpackDiskLine(fs, ls); + start = 0; + while( (s = strstr( &(ls->data.line[start]), reference)) ) + { + if( refLen < replLen ) + { /* May need to re-alloc */ + if( ls->numCharsAvail < replLen - refLen + ls->numChars ) + { /* Re-alloc */ + ls->numCharsAvail = 20 + ls->numChars + replLen - refLen; + ls->data.line = (char *) realloc(ls->data.line, + ls->numCharsAvail+1); + /* Refetch ptr to start of reference */ + s = strstr( &(ls->data.line[start]), reference); + } + } + if( refLen != replLen ) + { + memmove( &(s[replLen]), + &(s[refLen]), + 1+strlen(&(s[refLen]) )); + ls->numChars += replLen - refLen; + } + /* Copy in the replacement chars */ + if( replLen ) + memcpy(s, replace, replLen); + cnt++; + start = s - ls->data.line; + } + } +CHK: + if( last == ls ) + break; + } + + if( cnt ) + redrawWindow(w); + + sprintf(tmp,"Replaced %d", cnt); + emsg(tmp); + return(0); +} diff --git a/src/cmd/sre/srerc_example b/src/cmd/sre/srerc_example new file mode 100644 index 0000000..bb52857 --- /dev/null +++ b/src/cmd/sre/srerc_example @@ -0,0 +1,2 @@ +defineKey ^Q exit nosave +defineKey [4~ pageDn "" diff --git a/src/cmd/sre/tag.c b/src/cmd/sre/tag.c new file mode 100644 index 0000000..d738842 --- /dev/null +++ b/src/cmd/sre/tag.c @@ -0,0 +1,175 @@ +/* A weekend project to try to emulate the original RAND text editor + Copyright (C) 2011 Mike Stabenfeldt + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "edit.h" +extern globalStruct globalData; + +/* Can modify dirPath */ +scanTags(char *funcName, char *dirPath, int ix, int *fcnt) +{ +int i, j, bol, eol; +FILE *tagfp; +char bigLine[4096]; +char *argv[2]; + + argv[0] = "edit"; + strcpy(&dirPath[ix], "/tags"); + if( (tagfp=fopen(dirPath, "r")) == NULL ) + return(0); + (*fcnt)++; + while( fgets(bigLine, 4095, tagfp) ) + { + for(i=0; funcName[i]; i++) + if( bigLine[i] != funcName[i] ) + break; + if( funcName[i] != '\0' || bigLine[i] != '\t' ) + continue; + + /* Matched next token is file name */ + dirPath[ix] = '/'; + for(i++, j=ix+1; bigLine[i]; i++, j++) + if( bigLine[i] == '\t') + break; + else + dirPath[j] = bigLine[i]; + dirPath[j] = '\0'; + argv[1] = dirPath; + if( editFileCmd(2, argv) == 0) + { + fclose(tagfp); + return(0); + } + fclose(tagfp); + /* Next search for string in the file, editCmd has setup everything */ + i+=2; /* skip over tab and leading slash */ + bol = eol = 0; + if( bigLine[i] == '^' ) + { + bol=1; + i++; + } + for(j=i+1; bigLine[j]; j++) + ; + if( bigLine[j-1] == '\n' ) + j--; + if( bigLine[j-1] == '/' ) + j--; + if( bigLine[j-1] == '$' ) + { + eol = 1; + bigLine[j-1] = '\0'; + } + else + bigLine[j] = '\0'; + argv[1] = &bigLine[i]; + /* TODO, use bol/eol and make specific search command */ + searchDnCmd(2, argv); + return(1); + } + return(0); +} + +/* for tag command. Searches TAGPATH for all entries to find func */ +tagCmd(int argc, char **argv) +{ +windowStruct *w=globalData.activeWindow; +char *funcName, *tagPath, tagFile[4096]; +struct stat buf; +DIR *dirp; +struct dirent *de; +int i, j, k, cnt=0; + + + if( argc == 1 ) + { + if( getWordUnderCursor(w, &funcName) == -1) + { + emsg("Need an argument to tag"); + updateCursor(w); + return(0); + } + } + else + funcName = argv[1]; + + /* If none set, use current dir */ + if( !(tagPath = getenv("TAGPATH")) ) + tagPath = "."; + + for(i=j=0; 1; i++) + { + if( tagPath[i] != ':' && tagPath[i] != '\0' ) + { + tagFile[j++] = tagPath[i]; + continue; + } + + if( tagFile[j-1] == '*' ) + { /* Scan all subdirs of this directory for ctags files */ + j--; + tagFile[j] = '\0'; + if( (dirp = opendir(tagFile)) == NULL) + { + dingMsg("Bad Tag Path"); + continue; + } + while( (de=readdir(dirp)) ) + { + strcpy(&tagFile[j], de->d_name); + k = strlen(tagFile); + if( stat(tagFile, &buf) != 0) + continue; + if( S_ISDIR(buf.st_mode) ) + { + if( scanTags(funcName, tagFile, k, &cnt) ) + { + closedir(dirp); + goto FOUND; + } + } + } + } + else + { + tagFile[j] = '\0'; + if( scanTags(funcName, tagFile, j, &cnt) ) + goto FOUND; + } + j=0; + if( tagPath[i] == '\0' ) + break; + } + if( cnt == 0 ) + emsg("No tag files; run ctags"); + else + emsg("tag not found"); + updateCursor(w); + return(0); +FOUND: + return(1); +} diff --git a/src/cmd/sre/tutorial b/src/cmd/sre/tutorial new file mode 100644 index 0000000..11cced3 --- /dev/null +++ b/src/cmd/sre/tutorial @@ -0,0 +1,206 @@ + + This document describes my effort to create a facsimile +of the very old text editor created by the Rand Corporation +in the 70's. I had used the editor for decades and it was +always my favorite. I finally thought I would try to build +what I remembered of it. The hot keys are probably wrong +and I am sure some of the nuances are wrong but it does +multi-window (vertical and horizontal) has cut and get +buffers, can cut, open and copy rectangular areas and can +shift the screen right and left. So on to the tutorial. + +Note if you cannot start the editor, you may need to use +control-right-mouse and enable window-ops. Some linuces +disable this in an xterm. + +Lets begin with the basics, cursor control. Oh I should mention +for this tutorial to really work, adjust the screen to a 80 character +wide, 24 character tall terminal... now lets begin. When you +first invoked the program with this file as an argument, the +cursor should be in the upper left corner. You will see +in the bottom right of the screen the current line number, +a few spaces and an x1 to indicate column 1. Then the file name. +To move the cursor down, use either the arrow key or hold the +control key down and the letter j. Move the cursor down enough +so you can keep reading. Next try the other cursor directions. + +^N: up +^J: down +^H: left +^K: right + +Next lets do a simple argument to the movement. To provide +an argument to a command, do ^space, then type a number like +5, and then press the ^N key. Note the cursor moved up 5 rows. +A trick is if you do ^space ^N, the cursor will jump to the top +of the screen. Similarly, ^space ^K will jump to the last character +on the line, and if you are already past all the characters on the line, +it will jump to the right edge. + +Next move the cursor all the way to the right edge. Note how +the entire window started to scroll left to keep the cursor on +screen. Scroll back left to get the text back. A quick way to +move left and right are the shift screen commands. These are +^A: Move screen left 8 spaces +^V: Move screen right 8 spaces. + +Similarly, we can move up a whole page by using ^Y. Back a page is +^P. Use these to scroll up/down some. Again, you can provide an +argument to all of these skip multiple pages. To jump to the +end of the file, you can use ^space ^Y and the beginning is +^space ^P. To scroll about a half a page use ^T to go up and +^W to go back. If you do ^space, enter a number, then ^T or ^W +then you will scroll that number of lines. To jump to the top +line of the screen you can use ^space ^W while the bottom line +is ^space ^T. + +Now that we have the basics, a little about the window decorations. +Along the top edge the first character is either I or O to indicate +overstrike or insert mode. In overstrike mode, wherever the cursor +is, and you press a key, that key will replace whatver was under +the cursor. In Insert mode, the key pressed is inserted under the +cursor and everything shifts right one character. You can toggle insert +mode with ^O. Generally, I use overstrike more than insert. One of +the reasons I always like re, was vi forced insert mode. Continuing +along the top is either a - or a T. T's are tab stops. If you press +the tab key, note the cursor moves along to the next tab. To go backwards +use ^]. Tab-ing does not change the file, just another way to move +the cursor. The editor uses blanks underneath, so sre (&re) are not +exactly verbatim editors. More on that later, just be aware, white +space can change on saves. You can change the tab spacing by doing +^space tabs 8 + +Exiting the editor can be done with just ^X. Note that if you +exit with the ^X key, any files edited will be saved and the +original copy of the file will be moved to the file ,. +The original editor had no undo, and neither does this one. +Only a backup of the file is available. + +One of the coolest features of re, was multi-window editing. Windows +can be horizontal or vertical. To create a horizontal window, place +the cursor at the left edge of the window about halfway down the screen +and then do ^space win +The screen will split into two windows and the lower one will +be the active one. You can switch windows with the key ^Z. +You can then split either of those windows by repeating the process. +Change windows with ^Z. Windows can be removed with the command +^space -win +This removes the last window added. You can only remove windows in +the reverse order of creation. +Similarly, vertical windows can be created by putting the cursor at the +top of the screen and issueing the ^space win sequence. + +You can have up to 4 files active in each window. To add another +file, do ^space e filename +and if the file exists, it will become the current active file. +To switch active files, do either ^B or ^space e +with no file name. +You can save the active file in a window at any time with ^S +or ^space save +To save a file as a different name do +^space save newfilename +To "unload" a file from the list of alternate files, make that +file the current one using the "e" command, then do +^space -edit +That file will be dropped from the list of alternate files. +The file will be saved at exit unless you use exit nosave. +The -edit is not in the original re, but with 4 alternate +files, sometimes it is useful to remove a file from +the alternate file list. + +If you just want to look at a file and not write it out on +exit no matter what, just do ^space -update +To re-enable saving, do ^space update + +To get a report of what files/windows are open, do +^space status + +For basic editing, just type. If insert mode is on, +characters typed are inserted into the line, and a backspace +or delete destructive deletes characters. You can also use +the wipe character command (^U) to delete the character under +the cursor without moving the cursor. + +There are 2 buffers in the editor, the get buffer and the delete buffer. +To grab a line into the get buffer, just do ^L +The line is now in buffer. You can put a copy of the line by doing +^space ^L +To grab more than one line, just do +^space 5 ^L +and 5 lines will be grabbed. +Alternatively, you can grab lines graphically by doing ^G, move the +cursor down or up until you reach the last line you want to grab +and then do ^L. If you want to grab the area as a rectangular area, +instead of just moving the cursor up or down after ^G, move it right or +left as well. Note the area does not include the rightmost character under +the pair of cursor locations. You can reverse the location pair with a +second ^G. You can cancel the mark completely with a ^space ^G. +Note putting a rectangular area will add a square of text without +adding lines. + +The delete buffer works exactly the same way as the get operations except +the lines or area is removed after the get. The delete command is ^F. To +place a copy of the delete buffer use ^space ^F instead of ^space ^L. + +The editor also supports searching with the sequence ^space search key ^R +for forward searching and ^space search key ^E for backward searching. +If you just do ^E or ^R the search is repeated with the last search key. +You can also "grab" a search key from the text by doing ^G then ^R or +^E. The cursor must be on top of a word before the ^G is pressed. Search +will search for the word under the cursor. + + +Update 3/6/11 +Added commands split and join to split and join lines. +^space split +will split the line at the current cursor position. +^space join +joins the current line with the next line. + +Also added a rudimentary way to define your own keys. +Doing +defineKey ^Q exit nosave +will define the key ctrl+Q to be the command exit nosave. +You can create a file called .srerc in your home directory +with these commands to setup hotkeys as you like. +If the key is an escape sequence, then do +defineKey [4~ pageDn "" +which will jump to the end of the file. The [4~ is usually +the escape sequence sent when pressing a "end" key. Note +the leading escape is assumed in the 1st arg to defineKey. + +Update 3/13/2011 +I could not live without tags either. If you have source +code only in the current directory, then do ctags *.c +at the shell prompt to build the ctags file. Then inside +the editor you can either do +^space tag funcName +or if the cursor is over a call to the function you can +shorten the sequence to ^space tag +The editor will search the tags file, find the file the function is +defined in, open it as an alternate file, and jump to the function. +If you have source files in multiple directories, you can +set a environment variable TAGPATH with a list of the directories. +For example +setenv TAGPATH ~/src1:~/src2:~/src3 +will search the 3 directories in order for tags files and +open/search accordingly. You can also do +setenv TAGPATH ~/srdir1/*:~/srdir2/*:~/srcdir3/* +to search all the subdirectories of the list elements. The * +wildcard only works as the last element in the path component. +Feel free to mod the source as needed. This feature +is in the file tag.c + +Update 6/1/11 +Add command to restrict the range of lines the editor +will operate on. Set a range by marking an area with ^G, +then enter ^space to get the command prompt, then enter +the command range. After a range is established, the cursor +is restricted to the range. Searched, etc are also restructed. +Only a goto a specific line is allowed to go out of range. +Ranges are useful to limit editing to a specific long +function. By enforcing the range to be limited to the +function of interest, you cannot modify a part of the file +you do not want to by accident. Disable the range with the +-range command. You can use the match command to quickly +set the marked area to an entire function definition. diff --git a/src/cmd/strip.c b/src/cmd/strip.c new file mode 100644 index 0000000..5fa9970 --- /dev/null +++ b/src/cmd/strip.c @@ -0,0 +1,87 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#ifdef CROSS +# include +#else +# include +#endif +#include +#include +#include +#include +#include + +struct exec head; +int status; + +void +strip(name) + char *name; +{ + register int f; + long size; + + f = open(name, O_RDWR); + if (f < 0) { + fprintf(stderr, "strip: "); perror(name); + status = 1; + goto out; + } + if (read(f, (char *)&head, sizeof (head)) < 0 || N_BADMAG(head)) { + printf("strip: %s not in a.out format\n", name); + status = 1; + goto out; + } + if (head.a_syms == 0 && head.a_magic != RMAGIC) + goto out; + + size = N_DATOFF(head) + head.a_data; + if (ftruncate(f, size) < 0) { + fprintf(stderr, "strip: "); + perror(name); + status = 1; + goto out; + } + head.a_magic = OMAGIC; + head.a_reltext = 0; + head.a_reldata = 0; + head.a_syms = 0; + (void) lseek(f, (off_t)0, SEEK_SET); + (void) write(f, (char *)&head, sizeof (head)); +out: + close(f); +} + +int +main(argc, argv) + char *argv[]; +{ + register int i; + + while ((i = getopt(argc, argv, "h")) != EOF) { + switch(i) { + case 'h': + default: +usage: fprintf(stderr, "Usage:\n"); + fprintf(stderr, " strip file...\n"); + return(1); + } + } + argc -= optind; + argv += optind; + if (argc == 0) + goto usage; + + signal(SIGHUP, SIG_IGN); + signal(SIGINT, SIG_IGN); + signal(SIGQUIT, SIG_IGN); + for (i = 0; i < argc; i++) { + strip(argv[i]); + if (status > 1) + break; + } + return(status); +} diff --git a/src/cmd/stty/Makefile b/src/cmd/stty/Makefile new file mode 100644 index 0000000..4fa4bee --- /dev/null +++ b/src/cmd/stty/Makefile @@ -0,0 +1,42 @@ +# +# Public Domain. 1997/3/27 - Steven Schultz +# +TOPSRC = $(shell cd ../../..; pwd) +include $(TOPSRC)/target.mk + +CFLAGS = -O -Werror -g + +SRCS = stty.c +OBJS = stty.o +MAN = stty.0 +MANSRC = stty.1 + +all: stty ${MAN} + +stty: ${OBJS} + ${CC} ${LDFLAGS} -o stty.elf ${OBJS} ${LIBS} + ${OBJDUMP} -S stty.elf > stty.dis + ${SIZE} stty.elf + ${ELF2AOUT} stty.elf $@ && rm stty.elf + +${MAN}: ${MANSRC} + ${MANROFF} ${MANSRC} > ${MAN} + +clean: + rm -f *.o *.elf ${MAN} stty *.elf *.dis tags *~ + +depend: ${SRCS} + mkdep ${CFLAGS} ${SRCS} + +install: all + cp ${MAN} ${DESTDIR}/share/man/cat1/ + install stty ${DESTDIR}/bin/stty + +lint: ${SRCS} + lint -hax ${SRCS} + +tags: ${SRCS} + ctags ${SRCS} + +# DO NOT DELETE THIS LINE -- mkdep uses it. +# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY. diff --git a/src/cmd/stty/stty.1 b/src/cmd/stty/stty.1 new file mode 100644 index 0000000..d92eec6 --- /dev/null +++ b/src/cmd/stty/stty.1 @@ -0,0 +1,409 @@ +.\" Copyright (c) 1983 Regents of the University of California. +.\" All rights reserved. The Berkeley software License Agreement +.\" specifies the terms and conditions for redistribution. +.\" +.\" @(#)stty.1 6.4.1 (2.11BSD) 1997/5/2 +.\" +.TH STTY 1 "March 27, 1997" +.UC 4 +.SH NAME +stty \- set terminal options +.SH SYNOPSIS +.B stty +[\fB\-a | \-e\fP] +[\fB-f\fP \fIfile\fP] +[operands] +.SH DESCRIPTION +.I Stty +sets certain I/O options on the current output terminal, +placing its output on the diagnostic output. +With no argument, it reports the speed of the terminal and the +settings of the options which are different from their defaults. +.PP +The following options are available: +.TP 10 +\fB\-a\fP +Display everything \fIstty\fP knows. This has the same effect +as using the operand \fBall\fP or \fBeverything\fP. The distinction between +\fBall\fP and \fBeverything\fP has been removed. +.TP 10 +\fB\-e\fP +Same a \fB\-a\fP above. +.TP 10 +\fB\-f\fP +Open and use the terminal named by \fIfile\fP rather than using standard +output. The file is opened using the O_NONBLOCK flag of \fBopen\fP(), +making it possible to set or display settings on a terminal that might +otherwise block on the open. +.PP +The following operands are special: +.TP 12 +.B all +Everything +.I stty +knows about is printed. +.TP 12 +.B everything +Same as \fBall\fP above. +.TP 12 +.B flushout +Flush the queues for the device. This is most useful when an exiting +process is stuck waiting for terminal output to drain. +.TP 12 +.B speed +The terminal speed alone is printed on the standard output. +.TP 12 +.B size +The terminal (window) sizes are printed on the standard output, +first rows and then columns. +.PP +\fIOperands\fP are selected from the following: +.TP 10 +.B even +allow even parity input +.br +.ns +.TP 10 +.B \-even +disallow even parity input +.TP 10 +.B odd +allow odd parity input +.br +.ns +.TP 10 +.B \-odd +disallow odd parity input +.TP 10 +.B raw +raw mode input +(\fBno\fR input processing (erase, kill, interrupt, ...); parity bit passed back) +.br +.ns +.TP 10 +.B \-raw +negate raw mode +.TP 10 +.B cooked +same as `\-raw' +.TP 10 +.B cbreak +make each character available to +.IR read (2) +as received; no erase and kill processing, +but all other processing (interrupt, suspend, ...) is performed +.br +.ns +.TP 10 +.B \-cbreak +make characters available to +.I read +only when newline is received +.TP 10 +.B \-nl +allow carriage return for new-line, +and output CR-LF for carriage return or new-line +.br +.ns +.TP 10 +.B nl +accept only new-line to end lines +.TP 10 +.B echo +echo back every character typed +.br +.ns +.TP 10 +.B \-echo +do not echo characters +.TP 10 +.B tandem +enable inbound software (xon/xoff) flow control, so that the system sends +out the stop character when +its internal queue is in danger of overflowing on input, and sends the +start character when it is ready to accept further input +.br +.ns +.TP 10 +.B \-tandem +disable inbound software (xon/xoff) flow control +.TP 10 +.B \-tabs +replace tabs by spaces when printing +.br +.ns +.TP 10 +.B tabs +preserve tabs +.br +.PP +For the following commands which take a character argument \fIc\fR, +you may also specify \fIc\fR as ``undef'', to set the value +to be undefined. A value of ``^x'', a 2 character sequence, is also +interpreted as a control character, with ``^?'' representing delete. +.TP 10 +.BI erase \ c\fR +set erase character to +.I c +(default `#', but often reset to ^H.) +.br +.ns +.TP 10 +.BI kill \ c\fR +set kill character to +.I c +(default `@', but often reset to ^U.) +.br +.ns +.TP 10 +.BI intr \ c\fR +set interrupt character to +.I c +(default DEL or ^? (delete), but often reset to ^C.) +.br +.ns +.TP 10 +.BI quit \ c\fR +set quit character to +.I c +(default control \e.) +.br +.ns +.TP 10 +.BI start \ c\fR +set start character to +.I c +(default control Q.) +.br +.ns +.TP 10 +.BI stop \ c\fR +set stop character to +.I c +(default control S.) +.br +.ns +.TP 10 +.BI eof \ c\fR +set end of file character to +.I c +(default control D.) +.br +.ns +.TP 10 +.BI brk \ c\fR +set break character to +.I c +(default undefined.) +This character is an additional character causing wakeup. +.br +.ns +.TP 10 +.B dec +set all modes suitable for Digital Equipment Corp. operating systems +users; (erase, kill, and interrupt characters to ^?, ^U, and ^C, +decctlq and ``newcrt''.) +.ns +.TP 10 +.B 0 +hang up phone line immediately +.br +.ns +.TP 10 +.B "50 75 110 134 150 200 300 600 1200 1800 2400 4800 9600 exta extb" +.br +Set terminal baud rate to the number given, if possible. +(These are the speeds supported by the DH-11 interface). +.TP 10 +.BI rows \ n\fR +The terminal size is recorded as having +.I n +rows. +.TP 10 +.BI columns \ n\fR +The terminal size is recorded as having +.I n +columns. +.TP 10 +.BI cols \ n\fR +is an alias for +.IR columns . +.PP +A teletype driver which supports the job control processing of +.IR csh (1) +and more functionality than the basic driver is fully described in +.IR tty (4). +The following options apply only to it. +.TP 10 +.B new +Use new driver (switching flushes typeahead). +.br +.ns +.TP 10 +.B crt +Set options for a CRT (crtbs, ctlecho and, if >= 1200 baud, +crterase and crtkill.) +.TP 10 +.B crtbs +Echo backspaces on erase characters. +.TP 10 +.B prterase +For printing terminal echo erased characters backwards within ``\e'' and ``/''. +.TP 10 +.B crterase +Wipe out erased characters with ``backspace-space-backspace.'' +.br +.ns +.TP 10 +.B \-crterase +Leave erased characters visible; just backspace. +.TP 10 +.B crtkill +Wipe out input on like kill ala \fBcrterase\fP. +.br +.ns +.TP 10 +.B \-crtkill +Just echo line kill character and a newline on line kill. +.TP 10 +.B ctlecho +Echo control characters as ``^\fIx\fR'' (and delete as ``^?''.) +Print two backspaces following the EOT character (control D). +.br +.ns +.TP 10 +.B \-ctlecho +Control characters echo as themselves; in cooked mode EOT (control-D) +is not echoed. +.TP 10 +.B decctlq +After output is suspended (normally by ^S), only a start character +(normally ^Q) will restart it. This is compatible with DEC's vendor +supplied systems. +.br +.ns +.TP 10 +.B \-decctlq +After output is suspended, any character typed will restart it; +the start character will restart output without providing any input. +(This is the default.) +.TP 10 +.B tostop +Background jobs stop if they attempt terminal output. +.br +.ns +.TP 10 +.B \-tostop +Output from background jobs to the terminal is allowed. +.TP 10 +.B flusho +Output is being discarded usually because user hit control O (internal state bit). +.br +.ns +.TP 10 +.B \-flusho +Output is not being discarded. +.TP 10 +.B pendin +Input is pending after a switch from cbreak to cooked +and will be re-input when a read becomes pending or more input arrives +(internal state bit). +.br +.ns +.TP 10 +.B \-pendin +Input is not pending. +.TP 10 +.B pass8 +Passes all 8 bits through on input, in any mode. +.br +.ns +.TP 10 +.B \-pass8 +Strips the 0200 bit on input except in raw mode. +.TP 10 +.B mdmbuf +Start/stop output on carrier transitions (not implemented). +.br +.ns +.TP 10 +.B \-mdmbuf +Return error if write attempted after carrier drops. +.TP 10 +.B litout +Send output characters without any processing. +.br +.ns +.TP 10 +.B \-litout +Do normal output processing, inserting delays, etc. +.TP 10 +.B nohang +Don't send hangup signal if carrier drops. +.br +.ns +.TP 10 +.B \-nohang +Send hangup signal to control process group when carrier drops. +.PP +The following special characters are applicable only to the new +teletype driver +and are not normally changed. +.TP 10 +.BI susp \ c\fR +set suspend process character to \fIc\fR (default control Z). +.br +.ns +.TP 10 +.BI dsusp \ c\fR +set delayed suspend process character to \fIc\fR (default control Y). +.br +.ns +.TP 10 +.BI rprnt \ c\fR +set reprint line character to \fIc\fR (default control R). +.br +.ns +.TP 10 +.BI flush \ c\fR +set flush output character to \fIc\fR (default control O). +.br +.ns +.TP 10 +.BI werase \ c\fR +set word erase character to \fIc\fR (default control W). +.br +.ns +.TP 10 +.BI lnext \ c\fR +set literal next character to \fIc\fR (default control V). +.PP +.B Modem Control Status: +.sp +These display the current state of modem control. +They are only displayed for actual tty lines and not for pseudo tty +lines (more precisely, it is only displayed for lines which support +the TIOCMGET ioctl. See tty(4). +.br +.ns +While it is possible to change the state of the modem control lines, +the hardware or other software may prevent the change from actually +taking place, +or may cause the state to immediately revert to the original state. +.TP 15 +\fBdcd\fP (\fB\-dcd\fP) +State of Data Carrier Detect. +.TP 15 +\fBdsr\fP (\fB\-dsr\fP) +State of Data Set Ready. +.TP 15 +\fBdtr\fP (\fB\-dtr\fP) +State of Data Terminal Ready. +.TP 15 +\fBcts\fP (\fB\-cts\fP) +State of Clear To Send. +.TP 15 +\fBrts\fP (\fB\-rts\fP) +State of Request To Send. +.SH "SEE ALSO" +ioctl(2), tabs(1), tset(1), tty(4) diff --git a/src/cmd/stty/stty.c b/src/cmd/stty/stty.c new file mode 100644 index 0000000..dee6d36 --- /dev/null +++ b/src/cmd/stty/stty.c @@ -0,0 +1,520 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +/* + * set teletype modes + */ +#include +#include +#include +#include +#include +#include +#include + +const struct { + char *string; + int bval; + unsigned baud; +} speeds[] = { + "0", B0, 0, + "50", B50, 50, + "75", B75, 75, + "150", B150, 150, + "200", B200, 200, + "300", B300, 300, + "600", B600, 600, + "1200", B1200, 1200, + "1800", B1800, 1800, + "2400", B2400, 2400, + "4800", B4800, 4800, + "9600", B9600, 9600, + "19200", B19200, 19200, + "38400", B38400, 38400, + "57600", B57600, 57600, + "115200", B115200, 115200, + "230400", B230400, 230400, + "460800", B460800, 460800, + "500000", B500000, 500000, + "576000", B576000, 576000, + "921600", B921600, 921600, + "1000000", B1000000, 1000000, + "1152000", B1152000, 1152000, + "1500000", B1500000, 1500000, + "2000000", B2000000, 2000000, + "2500000", B2500000, 2500000, + "3000000", B3000000, 3000000, + "3500000", B3500000, 3500000, + "4000000", B4000000, 4000000, + 0, +}; + +struct MODES { + char *string; + int set; + int reset; +}; + +struct MODES modes[] = { + "even", EVENP, 0, + "-even", 0, EVENP, + "odd", ODDP, 0, + "-odd", 0, ODDP, + "raw", RAW, 0, + "-raw", 0, RAW, + "cooked", 0, RAW, + "-nl", CRMOD, 0, + "nl", 0, CRMOD, + "echo", ECHO, 0, + "-echo", 0, ECHO, + "-tabs", XTABS, 0, + "tabs", 0, XTABS, + "tandem", TANDEM, 0, + "-tandem", 0, TANDEM, + "cbreak", CBREAK, 0, + "-cbreak", 0, CBREAK, + 0 +}; + +struct MODES lmodes[] = { + "rtscts", LRTSCTS, 0, + "-rtscts", 0, LRTSCTS, + "crtbs", LCRTBS, LPRTERA, + "-crtbs", 0, LCRTBS, + "prterase", LPRTERA, LCRTBS+LCRTKIL+LCRTERA, + "-prterase", 0, LPRTERA, + "crterase", LCRTERA, LPRTERA, + "-crterase", 0, LCRTERA, + "crtkill", LCRTKIL, LPRTERA, + "-crtkill", 0, LCRTKIL, + "mdmbuf", LMDMBUF, 0, + "-mdmbuf", 0, LMDMBUF, + "litout", LLITOUT, 0, + "-litout", 0, LLITOUT, + "pass8", LPASS8, 0, + "-pass8", 0, LPASS8, + "tostop", LTOSTOP, 0, + "-tostop", 0, LTOSTOP, + "flusho", LFLUSHO, 0, + "-flusho", 0, LFLUSHO, + "nohang", LNOHANG, 0, + "-nohang", 0, LNOHANG, + "ctlecho", LCTLECH, 0, + "-ctlecho", 0, LCTLECH, + "pendin", LPENDIN, 0, + "-pendin", 0, LPENDIN, + "decctlq", LDECCTQ, 0, + "-decctlq", 0, LDECCTQ, + "noflsh", LNOFLSH, 0, + "-noflsh", 0, LNOFLSH, + 0 +}; + +struct MODES mmodes[] = { + "dcd", TIOCM_CD, 0, + "-dcd", 0, TIOCM_CD, + "dsr", TIOCM_DSR, 0, + "-dsr", 0, TIOCM_DSR, + "dtr", TIOCM_DTR, 0, + "-dtr", 0, TIOCM_DTR, + "cts", TIOCM_CTS, 0, + "-cts", 0, TIOCM_CTS, + "rts", TIOCM_RTS, 0, + "-rts", 0, TIOCM_RTS, + 0, +}; + +struct tchars tc; +struct ltchars ltc; +struct sgttyb mode; +struct winsize win; +int lmode; +int ldisc; +int mstate, nmstate; + +struct special { + char *name; + char *cp; + char def; +} special[] = { + "erase", &mode.sg_erase, CERASE, + "kill", &mode.sg_kill, CKILL, + "intr", &tc.t_intrc, CINTR, + "quit", &tc.t_quitc, CQUIT, + "start", &tc.t_startc, CSTART, + "stop", &tc.t_stopc, CSTOP, + "eof", &tc.t_eofc, CEOF, + "brk", &tc.t_brkc, CBRK, + "susp", <c.t_suspc, CSUSP, + "dsusp", <c.t_dsuspc, CDSUSP, + "rprnt", <c.t_rprntc, CRPRNT, + "flush", <c.t_flushc, CFLUSH, + "werase", <c.t_werasc, CWERASE, + "lnext", <c.t_lnextc, CLNEXT, + 0 +}; + +char *arg; +char *Nfmt = "%-8s"; + +main(argc, argv) + int argc; + register char **argv; +{ + int i, fmt = 0, ch, zero = 0; + register struct special *sp; + char obuf[BUFSIZ]; + char *arg2; + + setbuf(stderr, obuf); + + opterr = 0; + while (optind < argc && strspn(argv[optind], "-aef") == strlen(argv[optind]) && + (ch = getopt(argc, argv, "aef:")) != EOF) + { + switch (ch) { + case 'e': + case 'a': + fmt = 2; + break; + case 'f': + i = open(optarg, O_RDONLY|O_NONBLOCK); + if (i < 0) + err(1, "%s", optarg); + if (dup2(i, 1) < 0) + err(1, "dup2(%d,1)", i); + break; + case '?': + default: + goto args; + } + } +args: + argc -= optind; + argv += optind; + + ioctl(1, TIOCGETP, &mode); + ioctl(1, TIOCGETD, &ldisc); + ioctl(1, TIOCGETC, &tc); + ioctl(1, TIOCLGET, &lmode); + ioctl(1, TIOCGLTC, <c); + ioctl(1, TIOCGWINSZ, &win); + if (ioctl(1, TIOCMGET, &mstate) < 0) { + if (errno == ENOTTY) + mstate = -1; + else + warn("TIOCMGET"); + } + nmstate = mstate; + + if (argc == 0) { + prmodes(fmt); + exit(0); + } + arg = argv[1]; + if (argc == 1 && arg != 0 && (strcmp(arg, "everything") == 0 || + strcmp(arg, "all") == 0)) { + prmodes(2); + exit(0); + } + + while (argc-- > 0) { + arg = *argv++; + if (eq("new")){ + ldisc = NTTYDISC; + if (ioctl(1, TIOCSETD, &ldisc)<0) + perror("ioctl"); + continue; + } + if (eq("newcrt")){ + ldisc = NTTYDISC; + lmode &= ~LPRTERA; + lmode |= LCRTBS|LCTLECH; + if (mode.sg_ospeed >= B1200) + lmode |= LCRTERA|LCRTKIL; + if (ioctl(1, TIOCSETD, &ldisc)<0) + perror("ioctl"); + continue; + } + if (eq("crt")){ + lmode &= ~LPRTERA; + lmode |= LCRTBS|LCTLECH; + if (mode.sg_ospeed >= B1200) + lmode |= LCRTERA|LCRTKIL; + continue; + } + if (eq("old")){ + ldisc = 0; + if (ioctl(1, TIOCSETD, &ldisc)<0) + perror("ioctl"); + continue; + } + if (eq("sane")){ + mode.sg_flags &= ~CBREAK; + mode.sg_flags |= ECHO | CRMOD | XTABS; + continue; + } + if (eq("dec")){ + mode.sg_erase = 0177; + mode.sg_kill = CTRL('u'); + tc.t_intrc = CTRL('c'); + ldisc = NTTYDISC; + lmode &= ~LPRTERA; + lmode |= LCRTBS|LCTLECH|LDECCTQ; + if (mode.sg_ospeed >= B1200) + lmode |= LCRTERA|LCRTKIL; + if (ioctl(1, TIOCSETD, &ldisc)<0) + perror("ioctl"); + continue; + } + for (sp = special; sp->name; sp++) + if (eq(sp->name)) { + if (argc-- == 0) + goto done; + arg2 = *argv++; + if (strcmp(arg2, "undef") == 0) + *sp->cp = 0377; + else if (*arg2 == '^') { + arg2++; + *sp->cp = (*arg2 == '?') ? + 0177 : *arg2 & 037; + } else + *sp->cp = *arg2; + goto cont; + } + if (eq("flushout")) { + ioctl(1, TIOCFLUSH, &zero); + continue; + } + if (eq("hup")) { + ioctl(1, TIOCHPCL, NULL); + continue; + } + if (eq("rows")) { + if (argc-- == 0) + goto done; + win.ws_row = atoi(*argv++); + } + if (eq("cols") || eq("columns")) { + if (argc-- == 0) + goto done; + win.ws_col = atoi(*argv++); + } + if (eq("size")) { + printf("%d %d\n", win.ws_row, win.ws_col); + exit(0); + } + for(i=0; speeds[i].string; i++) + if(eq(speeds[i].string)) { + mode.sg_ispeed = mode.sg_ospeed = speeds[i].bval; + goto cont; + } + if (eq("speed")) { + for(i=0; speeds[i].string; i++) + if (mode.sg_ospeed == speeds[i].bval) { + printf("%s\n", speeds[i].string); + exit(0); + } + printf("unknown\n"); + exit(1); + } + for (i = 0; modes[i].string; i++) { + if (eq(modes[i].string)) { + mode.sg_flags &= ~modes[i].reset; + mode.sg_flags |= modes[i].set; + goto cont; + } + } + for (i = 0; lmodes[i].string; i++) { + if (eq(lmodes[i].string)) { + lmode &= ~lmodes[i].reset; + lmode |= lmodes[i].set; + goto cont; + } + } + for (i = 0; mmodes[i].string; i++) { + if (eq(mmodes[i].string)) { + nmstate &= ~mmodes[i].reset; + nmstate |= mmodes[i].set; + goto cont; + } + } + if(arg) + fprintf(stderr,"unknown mode: %s\n", arg); +cont: + ; + } +done: + ioctl(1, TIOCSETN, &mode); + ioctl(1, TIOCSETC, &tc); + ioctl(1, TIOCSLTC, <c); + ioctl(1, TIOCLSET, &lmode); + ioctl(1, TIOCSWINSZ, &win); + if (mstate != -1 && nmstate != mstate) { + if (ioctl(1, TIOCMSET, &nmstate) < 0) + warn("TIOCMSET"); + } +} + +eq(string) +char *string; +{ + if (!arg) + return(0); + if (strcmp(arg, string)) + return(0); + arg = 0; + return(1); +} + +#define lpit(what,str) \ + if (all || (lmode & what)) { \ + fprintf(stderr, str + ((lmode & what) != 0)); any++; \ + } + +prmodes(all) + int all; /* 0 for short display, !0 for long display */ +{ + register m; + int any, i; + register struct special *sp; + +#ifdef NETLDISC + if (ldisc==NETLDISC) + fprintf(stderr, "net discipline, "); + else +#endif + if (ldisc==NTTYDISC) + fprintf(stderr, "new tty, "); + else if (ldisc == 0) + fprintf(stderr, "old tty, "); + else + fprintf(stderr, "discipline %d, "); + + if(mode.sg_ispeed != mode.sg_ospeed) { + fprintf(stderr,"input speed %u baud", speeds[mode.sg_ispeed].baud); + fprintf(stderr,"output speed %u baud", speeds[mode.sg_ospeed].baud); + } else + fprintf(stderr,"speed %u baud", speeds[mode.sg_ispeed].baud); + + if (all) + fprintf(stderr, ", %d rows, %d columns", win.ws_row, win.ws_col); + + fprintf(stderr, all ? "\n" : "; "); + m = mode.sg_flags; + if (all) { + if(m & EVENP) fprintf(stderr,"even "); + if(m & ODDP) fprintf(stderr,"odd "); + } + if (all || m & RAW) + fprintf(stderr, "-raw " + ((m & RAW) != 0)); + if (all || (m & CRMOD) == 0) + fprintf(stderr, "-nl " + ((m & CRMOD) == 0)); + if (all || (m & ECHO) == 0) + fprintf(stderr, "-echo " + ((m & ECHO) != 0)); + if (all || (m & TANDEM)) + fprintf(stderr, "-tandem " + ((m & TANDEM) != 0)); + fprintf(stderr, "-tabs "+((m & XTABS) != XTABS)); + if (all || (m & CBREAK)) + fprintf(stderr, "-cbreak " + ((m & CBREAK) != 0)); + lpit(LRTSCTS, "-rtscts "); + if (all) { + fputc('\n', stderr); + if (mstate != -1) { + fprintf(stderr, "modem control: "); + fprintf(stderr, "-dcd " + ((mstate & TIOCM_CD) != 0)); + fprintf(stderr, "-dsr " + ((mstate & TIOCM_DSR) != 0)); + fprintf(stderr, "-dtr " + ((mstate & TIOCM_DTR) != 0)); + fprintf(stderr, "-cts " + ((mstate & TIOCM_CTS) != 0)); + fprintf(stderr, "-rts " + ((mstate & TIOCM_RTS) != 0)); + fputc('\n', stderr); + } + } + if (ldisc == NTTYDISC) { + int newcrt = (lmode & (LCTLECH|LCRTBS)) == (LCTLECH|LCRTBS) && + (lmode & (LCRTERA|LCRTKIL)) == + ((mode.sg_ospeed > B300) ? LCRTERA|LCRTKIL : 0); + int nothing = 1; + if (newcrt) { + if (all) + fprintf(stderr, "crt: (crtbs crterase crtkill ctlecho) "); + else + fprintf(stderr, "crt "); + any++; + } else { + lpit(LCRTBS, "-crtbs "); + lpit(LCRTERA, "-crterase "); + lpit(LCRTKIL, "-crtkill "); + lpit(LCTLECH, "-ctlecho "); + lpit(LPRTERA, "-prterase "); + } + lpit(LTOSTOP, "-tostop "); + if (all) { + fputc('\n', stderr); + any = 0; + nothing = 0; + } + lpit(LFLUSHO, "-flusho "); + lpit(LMDMBUF, "-mdmbuf "); + lpit(LLITOUT, "-litout "); + lpit(LPASS8, "-pass8 "); + lpit(LNOHANG, "-nohang "); + if (any) { + fputc('\n', stderr); + any = 0; + nothing = 0; + } + lpit(LPENDIN, "-pendin "); + lpit(LDECCTQ, "-decctlq "); + lpit(LNOFLSH, "-noflsh "); + if (any || nothing) + fputc('\n', stderr); + } else if (!all) + fputc('\n', stderr); + + if (all) { + for (i = 0, sp = special; i < 9; i++, sp++) + fprintf(stderr, Nfmt, sp->name); + fputc('\n', stderr); + for (i = 0, sp = special; i < 9; i++, sp++) + pit(sp); + fputc('\n', stderr); + for (i = 9, sp = &special[9]; sp->name; i++, sp++) + fprintf(stderr, Nfmt, sp->name); + fputc('\n', stderr); + for (i = 9, sp = &special[9]; sp->name; i++, sp++) + pit(sp); + fputc('\n', stderr); + } +} + +pit(sp) + struct special *sp; +{ + register int c = *sp->cp & 0xff; + char junk[6]; + register char *p = junk; + + if (c == 0xff) { + fprintf(stderr, Nfmt, ""); + return; + } + if (c & 0200) { + *p++ = 'M'; + *p++ = '-'; + c &= ~ 0200; + } + if (c == 0177) { + *p++ = '^'; + *p++ = '?'; + } + else if (c < ' ') { + *p++ = '^'; + *p++ = c += '@'; + } + *p++ = '\0'; + fprintf(stderr, Nfmt, junk); +} diff --git a/src/cmd/su.c b/src/cmd/su.c new file mode 100644 index 0000000..ed7496d --- /dev/null +++ b/src/cmd/su.c @@ -0,0 +1,176 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +char userbuf[64] = "USER="; +char homebuf[128] = "HOME="; +char shellbuf[128] = "SHELL="; +char pathbuf[128] = "PATH=" _PATH_STDPATH; +char *cleanenv[] = { userbuf, homebuf, shellbuf, pathbuf, 0, 0 }; +char *user = "root"; +char *shell = _PATH_BSHELL; +int fulllogin; +int fastlogin; + +extern char **environ; +struct passwd *pwd; + +setenvv(ename, eval, buf) + char *ename, *eval, *buf; +{ + register char *cp, *dp; + register char **ep = environ; + + /* + * this assumes an environment variable "ename" already exists + */ + while (dp = *ep++) { + for (cp = ename; *cp == *dp && *cp; cp++, dp++) + continue; + if (*cp == 0 && (*dp == '=' || *dp == 0)) { + strcat(buf, eval); + *--ep = buf; + return; + } + } +} + +char * +getenvv(ename) + char *ename; +{ + register char *cp, *dp; + register char **ep = environ; + + while (dp = *ep++) { + for (cp = ename; *cp == *dp && *cp; cp++, dp++) + continue; + if (*cp == 0 && (*dp == '=' || *dp == 0)) + return (*--ep); + } + return ((char *)0); +} + +main(argc,argv) + int argc; + char *argv[]; +{ + char *password; + char buf[1000]; + FILE *fp; + register char *p; + + openlog("su", LOG_ODELAY, LOG_AUTH); + +again: + if (argc > 1 && strcmp(argv[1], "-f") == 0) { + fastlogin++; + argc--, argv++; + goto again; + } + if (argc > 1 && strcmp(argv[1], "-") == 0) { + fulllogin++; + argc--, argv++; + goto again; + } + if (argc > 1 && argv[1][0] != '-') { + user = argv[1]; + argc--, argv++; + } + if ((pwd = getpwuid(getuid())) == NULL) { + fprintf(stderr, "Who are you?\n"); + exit(1); + } + strcpy(buf, pwd->pw_name); + if ((pwd = getpwnam(user)) == NULL) { + fprintf(stderr, "Unknown login: %s\n", user); + exit(1); + } + /* + * Only allow those in group zero to su to root. + */ + if (pwd->pw_uid == 0) { + struct group *gr; + int i; + + if ((gr = getgrgid(0)) != NULL) { + for (i = 0; gr->gr_mem[i] != NULL; i++) + if (strcmp(buf, gr->gr_mem[i]) == 0) + goto userok; + fprintf(stderr, "You do not have permission to su %s\n", + user); + exit(1); + } + userok: + setpriority(PRIO_PROCESS, 0, -2); + } + +#define Getlogin() (((p = getlogin()) && *p) ? p : buf) + if (pwd->pw_passwd[0] == '\0' || getuid() == 0) + goto ok; + password = getpass("Password:"); + if (strcmp(pwd->pw_passwd, crypt(password, pwd->pw_passwd)) != 0) { + fprintf(stderr, "Sorry\n"); + if (pwd->pw_uid == 0) { + syslog(LOG_CRIT, "BAD SU %s on %s", + Getlogin(), ttyname(2)); + } + exit(2); + } +ok: + endpwent(); + if (pwd->pw_uid == 0) { + syslog(LOG_NOTICE, "%s on %s", Getlogin(), ttyname(2)); + closelog(); + } + if (setgid(pwd->pw_gid) < 0) { + perror("su: setgid"); + exit(3); + } + if (initgroups(user, pwd->pw_gid)) { + fprintf(stderr, "su: initgroups failed\n"); + exit(4); + } + if (setuid(pwd->pw_uid) < 0) { + perror("su: setuid"); + exit(5); + } + if (pwd->pw_shell && *pwd->pw_shell) + shell = pwd->pw_shell; + if (fulllogin) { + cleanenv[4] = getenvv("TERM"); + environ = cleanenv; + } + if (strcmp(user, "root")) + setenvv("USER", pwd->pw_name, userbuf); + setenvv("SHELL", shell, shellbuf); + setenvv("HOME", pwd->pw_dir, homebuf); + setpriority(PRIO_PROCESS, 0, 0); + if (fastlogin) { + *argv-- = "-f"; + *argv = "su"; + } else if (fulllogin) { + if (chdir(pwd->pw_dir) < 0) { + fprintf(stderr, "No directory\n"); + exit(6); + } + *argv = "-su"; + } else + *argv = "su"; + execv(shell, argv); + fprintf(stderr, "No shell\n"); + exit(7); +} diff --git a/src/cmd/sum.c b/src/cmd/sum.c new file mode 100644 index 0000000..0b30496 --- /dev/null +++ b/src/cmd/sum.c @@ -0,0 +1,48 @@ +/* + * Sum bytes in file mod 2^16 + */ +#include +#include + +main(argc,argv) +char **argv; +{ + register unsigned sum; + register i, c; + register FILE *f; + register long nbytes; + int errflg = 0; + + i = 1; + do { + if(i < argc) { + if ((f = fopen(argv[i], "r")) == NULL) { + fprintf(stderr, "sum: Can't open %s\n", argv[i]); + errflg += 10; + continue; + } + } else + f = stdin; + sum = 0; + nbytes = 0; + while ((c = getc(f)) != EOF) { + nbytes++; + if (sum&01) + sum = (sum>>1) + 0x8000; + else + sum >>= 1; + sum += c; + sum &= 0xFFFF; + } + if (ferror(f)) { + errflg++; + fprintf(stderr, "sum: read error on %s\n", argc>1?argv[i]:"-"); + } + printf("%05u%6ld", sum, (nbytes+BUFSIZ-1)/BUFSIZ); + if(argc > 2) + printf(" %s", argv[i]); + printf("\n"); + fclose(f); + } while(++i < argc); + exit(errflg); +} diff --git a/src/cmd/sync.c b/src/cmd/sync.c new file mode 100644 index 0000000..6803c99 --- /dev/null +++ b/src/cmd/sync.c @@ -0,0 +1,5 @@ +int main() +{ + sync(); + return 0; +} diff --git a/src/cmd/sysctl/Makefile b/src/cmd/sysctl/Makefile new file mode 100644 index 0000000..7050af1 --- /dev/null +++ b/src/cmd/sysctl/Makefile @@ -0,0 +1,42 @@ +# +# Public Domain. 1/15/1995 - Steven Schultz +# +TOPSRC = $(shell cd ../../..; pwd) +include $(TOPSRC)/target.mk + +CFLAGS += -Werror + +SRCS = sysctl.c +OBJS = sysctl.o +MAN = sysctl.0 +MANSRC = sysctl.8 + +all: sysctl $(MAN) + +sysctl: ${OBJS} + ${CC} ${LDFLAGS} -o sysctl.elf ${OBJS} ${LIBS} + ${OBJDUMP} -S sysctl.elf > sysctl.dis + ${SIZE} sysctl.elf + ${ELF2AOUT} sysctl.elf $@ && rm sysctl.elf + +$(MAN): ${MANSRC} + ${MANROFF} $< > $@ + +clean: + rm -f *.o *.elf ${MAN} sysctl *.elf *.dis tags *~ + +depend: ${SRCS} + mkdep ${CFLAGS} ${SRCS} + +install: all + install sysctl ${DESTDIR}/bin/sysctl + cp ${MAN} $(DESTDIR)/share/man/cat8/ + +lint: ${SRCS} + lint -hax ${SRCS} + +tags: ${SRCS} + ctags ${SRCS} + +# DO NOT DELETE THIS LINE -- mkdep uses it. +# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY. diff --git a/src/cmd/sysctl/sysctl.8 b/src/cmd/sysctl/sysctl.8 new file mode 100644 index 0000000..a91f2da --- /dev/null +++ b/src/cmd/sysctl/sysctl.8 @@ -0,0 +1,238 @@ +.\" 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. +.\" +.\" @(#)sysctl.8 8.1.5 (2.11BSD) 1999/4/29 +.\" +.TH SYSCTL 8 "April 24, 1999" +.UC 4 +.SH NAME +sysctl \- get or set kernel state +.SH SYNOPSIS +.B sysctl +[ +.B \-n +] +.I name ... +.br +.B sysctl +[ +.B \-n +] +.B \-w +.I name=value ... +.br +.B sysctl +[ +.B \-n +] +.B \-aA +.SH DESCRIPTION +The +.B sysctl +utility retrieves kernel state and allows processes with +appropriate privilege to set kernel state. +The state to be retrieved or set is described using a +``Management Information Base'' (``MIB'') style name, +described as a dotted set of components. +The +.B \-a +flag can be used to list all the currently available string or integer values. +The +.B \-A +flag will list all the known MIB names including tables. +Those with string or integer values will be printed as with the +.B \-a +flag; for the table values, +the name of the utility to retrieve them is given. +.PP +The +.B \-n +flag specifies that the printing of the field name should be +suppressed and that only its value should be output. +This flag is useful for setting shell variables. +For example, to save the pagesize in variable psize, use: +.sp +.in +1.0 +set psize=`sysctl -n hw.pagesize` +.in -1.0 +.PP +If just a MIB style name is given, +the corresponding value is retrieved. +If a value is to be set, the +.B \-w +flag must be specified and the MIB name followed +by an equal sign and the new value to be used. +.PP +The information available from +.B sysctl +consists of integers, strings, and tables. +The tabular information can only be retrieved by special +purpose programs such as +\fBps\fP, +\fBsystat\fP, +and +\fBnetstat\fP. +The string and integer information is summaried below. +For a detailed description of these variable see +\fBsysctl(3)\fP. +The changeable column indicates whether a process with appropriate +privilege can change the value. +.sp +.ta 0.5i 3.0i 4.0i +.nf + Name Type Changeable + kern.acctthresh int yes + kern.ostype string no + kern.osrelease string no + kern.osrevision long no + kern.version string no + kern.maxinodes integer no + kern.maxproc integer no + kern.maxfiles integer no + kern.maxtext integer no + kern.argmax integer no + kern.securelevel integer raise only + kern.hostname string yes + kern.hostid long yes + kern.clockrate struct no + kern.posix1version integer no + kern.ngroups integer no + kern.job_control integer no + kern.saved_ids integer no +.\" kern.link_max integer no +.\" kern.max_canon integer no +.\" kern.max_input integer no +.\" kern.name_max integer no +.\" kern.path_max integer no +.\" kern.pipe_buf integer no +.\" kern.chown_restricted integer no +.\" kern.no_trunc integer no +.\" kern.vdisable integer no + kern.boottime struct no + vm.loadavg struct no + machdep.console_device dev_t no + machdep.mscp.printf integer yes + machdep.tmscp.cache integer yes + machdep.tmscp.printf integer yes + net.inet.ip.forwarding integer yes + net.inet.ip.redirect integer yes + net.inet.ip.ttl integer yes + net.inet.icmp.maskrepl integer yes + net.inet.udp.checksum integer yes + hw.machine string no + hw.model string no + hw.ncpu integer no + hw.byteorder integer no + hw.physmem long no + hw.usermem long no + hw.pagesize integer no + user.cs_path string no + user.bc_base_max integer no + user.bc_dim_max integer no + user.bc_scale_max integer no + user.bc_string_max integer no + user.coll_weights_max integer no + user.expr_nest_max integer no + user.line_max integer no + user.re_dup_max integer no + user.posix2_version integer no + user.posix2_c_bind integer no + user.posix2_c_dev integer no + user.posix2_char_term integer no + user.posix2_fort_dev integer no + user.posix2_fort_run integer no + user.posix2_localedef integer no + user.posix2_sw_dev integer no + user.posix2_upe integer no +.fi +.SH EXAMPLES +.PP +For example, to retrieve the maximum number of processes allowed +in the system, one would use the follow request: +.sp +.in +1.0i +sysctl kern.maxproc +.br +.in -1.0i +.PP +To set the hostname of the system +to foo.bar.com, one would use the follow request: +.sp +.in +1.0i +sysctl -w kern.hostname=foo.bar.com +.in -1.0i +.br +.PP +Information about the system clock rate may be obtained with: +.sp +.in +1.0i +sysctl kern.clockrate +.br +.in -1.0i +.PP +Information about the load average history may be obtained with +.sp +.in +1.0i +sysctl vm.loadavg +.br +.in -1.0i +.SH FILES +.TP 15 + +definitions for top level identifiers, second level kernel and hardware +identifiers, and user level identifiers +.TP 15 + +definitions for second level network identifiers +.TP 15 + +definitions for third level profiling identifiers +.TP 15 + +definitions for second and third level machine dependent identifiers +.TP 15 + +definitions for second level virtual memory identifiers +.TP 15 + +definitions for third level Internet identifiers and +fourth level IP identifiers +.TP 15 + +definitions for fourth level ICMP identifiers +.TP 15 + +definitions for fourth level UDP identifiers +.SH SEE ALSO +sysctl(3) +.SH HISTORY +.B sysctl +first appeared in 4.4BSD. diff --git a/src/cmd/sysctl/sysctl.c b/src/cmd/sysctl/sysctl.c new file mode 100644 index 0000000..7f70fde --- /dev/null +++ b/src/cmd/sysctl/sysctl.c @@ -0,0 +1,556 @@ +/* + * 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. + */ +#include +#include +#include +#include + +#include +#if 0 +#include +#include +#include +#include +#include +#include +#include +#include +#endif +#include +#include +#include +#include +#include + +struct ctlname topname[] = CTL_NAMES; +struct ctlname kernname[] = CTL_KERN_NAMES; +struct ctlname vmname[] = CTL_VM_NAMES; +#ifdef CTL_NET_NAMES +struct ctlname netname[] = CTL_NET_NAMES; +#endif +struct ctlname hwname[] = CTL_HW_NAMES; +struct ctlname username[] = CTL_USER_NAMES; +struct ctlname debugname[CTL_DEBUG_MAXID]; +struct ctlname machdepname[] = CTL_MACHDEP_NAMES; +char names[BUFSIZ]; + +struct list { + struct ctlname *list; + int size; +}; +struct list toplist = { topname, CTL_MAXID }; +struct list secondlevel[] = { + { 0, 0 }, /* CTL_UNSPEC */ + { kernname, KERN_MAXID }, /* CTL_KERN */ + { vmname, VM_MAXID }, /* CTL_VM */ + { 0, 0 }, /* CTL_FS */ +#ifdef CTL_NET_NAMES + { netname, NET_MAXID }, /* CTL_NET */ +#else + { 0, 0 }, +#endif + { 0, CTL_DEBUG_MAXID }, /* CTL_DEBUG */ + { hwname, HW_MAXID }, /* CTL_HW */ + { machdepname, CPU_MAXID }, /* CTL_MACHDEP */ + { username, USER_MAXID }, /* CTL_USER_NAMES */ +}; + +int Aflag, aflag, nflag, wflag; + +extern char *optarg; +extern int optind, errno; + +/* + * Variables requiring special processing. + */ +#define CLOCK 0x0001 +#define BOOTTIME 0x0002 +#define CONSDEV 0x0004 + +int +main(argc, argv) + int argc; + char *argv[]; +{ + int ch, lvl1; + + while ((ch = getopt(argc, argv, "Aanw")) != EOF) { + switch (ch) { + + case 'A': + Aflag = 1; + break; + + case 'a': + aflag = 1; + break; + + case 'n': + nflag = 1; + break; + + case 'w': + wflag = 1; + break; + + default: + usage(); + } + } + argc -= optind; + argv += optind; + + if (Aflag || aflag) { + debuginit(); + for (lvl1 = 1; lvl1 < CTL_MAXID; lvl1++) + listall(topname[lvl1].ctl_name, &secondlevel[lvl1]); + exit(0); + } + if (argc == 0) + usage(); + while (argc-- > 0) + parse(*argv, 1); + exit(0); +} + +/* + * List all variables known to the system. + */ +listall(prefix, lp) + char *prefix; + struct list *lp; +{ + int lvl2; + char *cp, name[BUFSIZ]; + + if (lp->list == 0) + return; + strcpy(name, prefix); + cp = &name[strlen(name)]; + *cp++ = '.'; + for (lvl2 = 0; lvl2 < lp->size; lvl2++) { + if (lp->list[lvl2].ctl_name == 0) + continue; + strcpy(cp, lp->list[lvl2].ctl_name); + parse(name, Aflag); + } +} + +/* + * Parse a name into a MIB entry. + * Lookup and print out the MIB entry if it exists. + * Set a new value if requested. + */ +parse(string, flags) + char *string; + int flags; +{ + int indx, type, state, size, len; + int special = 0; + void *newval = (void *)0; + int intval, newsize = 0; + long longval; + struct list *lp; + int mib[CTL_MAXNAME]; + char *cp, *bufp, buf[BUFSIZ], strval[BUFSIZ]; + + bufp = buf; + strcpy(buf, string); + if ((cp = strchr(string, '=')) != NULL) { + if (!wflag) { + fprintf(stderr, "Must specify -w to set variables\n"); + exit(2); + } + *strchr(buf, '=') = '\0'; + *cp++ = '\0'; + while (isspace(*cp)) + cp++; + newval = (void *)cp; + newsize = strlen(cp); + } + if ((indx = findname(string, "top", &bufp, &toplist)) == -1) + return; + mib[0] = indx; + if (indx == CTL_DEBUG) + debuginit(); + lp = &secondlevel[indx]; + if (lp->list == 0) { + fprintf(stderr, "%s: class is not implemented\n", + topname[indx]); + return; + } + if (bufp == NULL) { + listall(topname[indx].ctl_name, lp); + return; + } + if ((indx = findname(string, "second", &bufp, lp)) == -1) + return; + mib[1] = indx; + type = lp->list[indx].ctl_type; + len = 2; + switch (mib[0]) { + + case CTL_KERN: + switch (mib[1]) { + case KERN_PROF: + fprintf(stderr, + "kern.prof = not supported in 2.11BSD\n"); + return; + case KERN_INODE: + case KERN_FILE: + case KERN_TEXT: + if (flags == 0) + return; + fprintf(stderr, + "Use pstat to view %s information\n", string); + return; + case KERN_PROC: + if (flags == 0) + return; + fprintf(stderr, + "Use ps to view %s information\n", string); + return; + case KERN_CLOCKRATE: + special |= CLOCK; + break; + case KERN_BOOTTIME: + special |= BOOTTIME; + break; + } + break; + + case CTL_HW: + break; + + case CTL_VM: + if (mib[1] == VM_LOADAVG) { + unsigned loads[3]; + + getloadavg(loads, 3); + if (!nflag) + fprintf(stdout, "%s: ", string); + fprintf(stdout, "%u.%02u %u.%02u %u.02u\n", + loads[0] / 100, loads[0] % 100, + loads[1] / 100, loads[1] % 100, + loads[2] / 100, loads[2] % 100); + return; + } + if (flags == 0) + return; + fprintf(stderr, + "Use vmstat or pstat to view %s information\n", string); + return; + + case CTL_NET: +#ifdef PF_INET + if (mib[1] == PF_INET) { + len = sysctl_inet(string, &bufp, mib, flags, &type); + if (len >= 0) + break; + return; + } +#endif + if (flags == 0) + return; + fprintf(stderr, "Use netstat to view %s information\n", string); + return; + + case CTL_DEBUG: + mib[2] = CTL_DEBUG_VALUE; + len = 3; + break; + + case CTL_MACHDEP: + if (mib[1] == CPU_CONSDEV) + special |= CONSDEV; + break; + + case CTL_FS: + case CTL_USER: + break; + + default: + fprintf(stderr, "Illegal top level value: %d\n", mib[0]); + return; + + } +doit: + if (bufp) { + fprintf(stderr, "name %s in %s is unknown\n", *bufp, string); + return; + } + if (newsize > 0) { + switch (type) { + case CTLTYPE_INT: + intval = atoi(newval); + newval = (void *)&intval; + newsize = sizeof intval; + break; + + case CTLTYPE_LONG: + sscanf(newval, "%ld", &longval); + newval = (void *)&longval; + newsize = sizeof longval; + break; + } + } + size = BUFSIZ; + if (sysctl(mib, len, buf, &size, newsize ? newval : (void *)0, newsize) == -1) { + if (flags == 0) + return; + switch (errno) { + case EOPNOTSUPP: + fprintf(stderr, "%s: value is not available\n", string); + return; + case ENOTDIR: + fprintf(stderr, "%s: specification is incomplete\n", + string); + return; + case ENOMEM: + fprintf(stderr, "%s: type is unknown to this program\n", + string); + return; + default: + perror(string); + return; + } + } + if (special & CLOCK) { + struct clockinfo *clkp = (struct clockinfo *)buf; + + if (!nflag) + fprintf(stdout, "%s: ", string); + fprintf(stdout, + "hz = %d, tick = %d, profhz = %d, stathz = %d\n", + clkp->hz, clkp->tick, clkp->profhz, clkp->stathz); + return; + } + if (special & BOOTTIME) { + struct timeval *btp = (struct timeval *)buf; + + if (!nflag) + fprintf(stdout, "%s = %s", string, + ctime(&btp->tv_sec)); + else + fprintf(stdout, "%d\n", btp->tv_sec); + return; + } + if (special & CONSDEV) { + dev_t dev = *(dev_t *)buf; + + if (!nflag) + fprintf(stdout, "%s = %s\n", string, + devname(dev, S_IFCHR)); + else + fprintf(stdout, "0x%x\n", dev); + return; + } + switch (type) { + case CTLTYPE_INT: + if (newsize == 0) { + if (!nflag) + fprintf(stdout, "%s = ", string); + fprintf(stdout, "%d\n", *(int *)buf); + } else { + if (!nflag) + fprintf(stdout, "%s: %d -> ", string, + *(int *)buf); + fprintf(stdout, "%d\n", *(int *)newval); + } + return; + + case CTLTYPE_STRING: + if (newsize == 0) { + if (!nflag) + fprintf(stdout, "%s = ", string); + fprintf(stdout, "%s\n", buf); + } else { + if (!nflag) + fprintf(stdout, "%s: %s -> ", string, buf); + fprintf(stdout, "%s\n", newval); + } + return; + + case CTLTYPE_LONG: + if (newsize == 0) { + if (!nflag) + fprintf(stdout, "%s = ", string); + fprintf(stdout, "%ld\n", *(long *)buf); + } else { + if (!nflag) + fprintf(stdout, "%s: %ld -> ", string, + *(long *)buf); + fprintf(stdout, "%ld\n", *(long *)newval); + } + return; + + case CTLTYPE_STRUCT: + fprintf(stderr, "%s: unknown structure returned\n", + string); + return; + + default: + case CTLTYPE_NODE: + fprintf(stderr, "%s: unknown type returned\n", + string); + return; + } +} + +/* + * Initialize the set of debugging names + */ +debuginit() +{ + int mib[3], size, loc, i; + + if (secondlevel[CTL_DEBUG].list != 0) + return; + secondlevel[CTL_DEBUG].list = debugname; + mib[0] = CTL_DEBUG; + mib[2] = CTL_DEBUG_NAME; + for (loc = 0, i = 0; i < CTL_DEBUG_MAXID; i++) { + mib[1] = i; + size = BUFSIZ - loc; + if (sysctl(mib, 3, &names[loc], &size, NULL, 0) == -1) + continue; + debugname[i].ctl_name = &names[loc]; + debugname[i].ctl_type = CTLTYPE_INT; + loc += size; + } +} + +#ifdef PF_INET +struct ctlname inetname[] = CTL_IPPROTO_NAMES; +struct ctlname ipname[] = IPCTL_NAMES; +struct ctlname icmpname[] = ICMPCTL_NAMES; +struct ctlname udpname[] = UDPCTL_NAMES; +struct list inetlist = { inetname, IPPROTO_MAXID }; +struct list inetvars[] = { + { ipname, IPCTL_MAXID }, /* ip */ + { icmpname, ICMPCTL_MAXID }, /* icmp */ + { 0, 0 }, /* igmp */ + { 0, 0 }, /* ggmp */ + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, /* tcp */ + { 0, 0 }, + { 0, 0 }, /* egp */ + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, /* pup */ + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { udpname, UDPCTL_MAXID }, /* udp */ +}; + +/* + * handle internet requests + */ +sysctl_inet(string, bufpp, mib, flags, typep) + char *string; + char **bufpp; + int mib[]; + int flags; + int *typep; +{ + struct list *lp; + int indx; + + if (*bufpp == NULL) { + listall(string, &inetlist); + return (-1); + } + if ((indx = findname(string, "third", bufpp, &inetlist)) == -1) + return (-1); + mib[2] = indx; + if (indx <= IPPROTO_UDP && inetvars[indx].list != NULL) + lp = &inetvars[indx]; + else if (!flags) + return (-1); + else { + fprintf(stderr, "%s: no variables defined for this protocol\n", + string); + return (-1); + } + if (*bufpp == NULL) { + listall(string, lp); + return (-1); + } + if ((indx = findname(string, "fourth", bufpp, lp)) == -1) + return (-1); + mib[3] = indx; + *typep = lp->list[indx].ctl_type; + return (4); +} +#endif /* PF_INET */ + +/* + * Scan a list of names searching for a particular name. + */ +findname(string, level, bufp, namelist) + char *string; + char *level; + char **bufp; + struct list *namelist; +{ + char *name; + int i; + + if (namelist->list == 0 || (name = strsep(bufp, ".")) == NULL) { + fprintf(stderr, "%s: incomplete specification\n", string); + return (-1); + } + for (i = 0; i < namelist->size; i++) + if (namelist->list[i].ctl_name != NULL && + strcmp(name, namelist->list[i].ctl_name) == 0) + break; + if (i == namelist->size) { + fprintf(stderr, "%s level name %s in %s is invalid\n", + level, name, string); + return (-1); + } + return (i); +} + +usage() +{ + + (void)fprintf(stderr, "usage:\t%s\n\t%s\n\t%s\n\t%s\n", + "sysctl [-n] variable ...", "sysctl [-n] -w variable=value ...", + "sysctl [-n] -a", "sysctl [-n] -A"); + exit(1); +} diff --git a/src/cmd/tail.c b/src/cmd/tail.c new file mode 100644 index 0000000..cab8a22 --- /dev/null +++ b/src/cmd/tail.c @@ -0,0 +1,232 @@ +/* + * tail command + * + * tail where [file] + * where is +/-n[type] + * - means n lines before end + * + means nth line from beginning + * type 'b' means tail n blocks, not lines + * type 'c' means tail n characters + * Type 'r' means in lines in reverse order from end + * (for -r, default is entire buffer ) + * option 'f' means loop endlessly trying to read more + * characters after the end of file, on the assumption + * that the file is growing + * + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include +#include +#include +#include +#include +#include +#include + +#ifdef pdp11 +#define LBIN 16385 +#else +#define LBIN 32769 +#endif + +#undef BUFSIZ +#define BUFSIZ 8192 + +struct stat statb; +int follow; +int piped; +char bin[LBIN]; +int errno; + +main(argc,argv) +char **argv; +{ + long n,di; + register i,j,k; + char *arg; + int partial,bylines,bkwds,fromend,lastnl; + char *p; + + arg = argv[1]; + if(argc<=1 || *arg!='-'&&*arg!='+') { + arg = "-10l"; + argc++; + argv--; + } + fromend = *arg=='-'; + arg++; + if (isdigit(*arg)) { + n = 0; + while(isdigit(*arg)) + n = n*10 + *arg++ - '0'; + } else + n = -1; + if(!fromend&&n>0) + n--; + if(argc>2) { + (void)close(0); + if(open(argv[2],0)!=0) { + perror(argv[2]); + exit(1); + } + } + (void)lseek(0,(off_t)0,L_INCR); + piped = errno==ESPIPE; + bylines = -1; bkwds = 0; + while(*arg) + switch(*arg++) { + + case 'b': + if (n == -1) n = 1; + n <<= 9; + if(bylines!=-1) goto errcom; + bylines=0; + break; + case 'c': + if(bylines!=-1) goto errcom; + bylines=0; + break; + case 'f': + follow = 1; + break; + case 'r': + if(n==-1) n = LBIN; + bkwds = 1; fromend = 1; bylines = 1; + break; + case 'l': + if(bylines!=-1) goto errcom; + bylines = 1; + break; + default: + goto errcom; + } + if (n==-1) n = 10; + if(bylines==-1) bylines = 1; + if(bkwds) follow=0; + if(fromend) + goto keep; + + /*seek from beginning */ + + if(bylines) { + j = 0; + while(n-->0) { + do { + if(j--<=0) { + p = bin; + j = read(0,p,BUFSIZ); + if(j--<=0) + fexit(); + } + } while(*p++ != '\n'); + } + (void)write(1,p,j); + } else if(n>0) { + if(!piped) + (void)fstat(0,&statb); + if(piped||(statb.st_mode&S_IFMT)==S_IFCHR) + while(n>0) { + i = n>BUFSIZ?BUFSIZ:n; + i = read(0,bin,i); + if(i<=0) + fexit(); + n -= i; + } + else + (void)lseek(0,(off_t)n,L_SET); + } +copy: + while((i=read(0,bin,BUFSIZ))>0) + (void)write(1,bin,i); + fexit(); + + /*seek from end*/ + +keep: + if(n <= 0) + fexit(); + if(!piped) { + (void)fstat(0,&statb); + /* If by lines, back up 1 buffer: else back up as needed */ + di = bylines?LBIN-1:n; + if(statb.st_size > di) + (void)lseek(0,(off_t)-di,L_XTND); + if(!bylines) + goto copy; + } + partial = 1; + for(;;) { + i = 0; + do { + j = read(0,&bin[i],LBIN-i); + if(j<=0) + goto brka; + i += j; + } while(i=LBIN ? i+1: + i-n+LBIN; + k--; + } else { + if(bkwds && bin[i==0?LBIN-1:i-1]!='\n'){ /* force trailing newline */ + bin[i]='\n'; + if(++i>=LBIN) {i = 0; partial = 0;} + } + k = i; + j = 0; + do { + lastnl = k; + do { + if(--k<0) { + if(partial) { + if(bkwds) + (void)write(1,bin,lastnl+1); + goto brkb; + } + k = LBIN -1; + } + } while(bin[k]!='\n'&&k!=i); + if(bkwds && j>0){ + if(k=LBIN) + k = 0; + } while(bin[k]!='\n'&&k!=i); + } + if(k 0) + (void)write (1, bin, n); + } +} diff --git a/src/cmd/talloc/Makefile b/src/cmd/talloc/Makefile new file mode 100644 index 0000000..0efa520 --- /dev/null +++ b/src/cmd/talloc/Makefile @@ -0,0 +1,41 @@ +# +# Public Domain. 1995/03/13 - Steven Schultz +# +TOPSRC = $(shell cd ../../..; pwd) +include $(TOPSRC)/target.mk + +CFLAGS += -Werror -I../../../sys/include + +BIN = talloc +SRCS = $(BIN).c +OBJS = $(BIN).o +MAN = $(BIN).0 + +all: $(BIN) ${MAN} + +$(BIN): ${OBJS} + ${CC} ${LDFLAGS} -o $@.elf ${OBJS} ${LIBS} + ${OBJDUMP} -S $@.elf > $@.dis + ${SIZE} $@.elf + ${ELF2AOUT} $@.elf $@ + +.SUFFIXES: .0 .1 + +.1.0: + ${MANROFF} $*.1 > $@ + +clean: + rm -f *.o *.elf ${MAN} *.elf *.dis tags *~ $(BIN) + +depend: ${SRCS} + mkdep ${CFLAGS} ${SRCS} + +install: all + install -m 755 $(BIN) ${DESTDIR}/sbin + install -m 755 $(MAN) ${DESTDIR}/share/man/cat8 + +lint: ${SRCS} + lint -hax ${SRCS} + +tags: ${SRCS} + ctags ${SRCS} diff --git a/src/cmd/talloc/talloc.1 b/src/cmd/talloc/talloc.1 new file mode 100644 index 0000000..e69de29 diff --git a/src/cmd/talloc/talloc.c b/src/cmd/talloc/talloc.c new file mode 100644 index 0000000..f213cd2 --- /dev/null +++ b/src/cmd/talloc/talloc.c @@ -0,0 +1,36 @@ +#include +#include +#include +#include +#include +#include + +void usage() +{ + printf("Usage: talloc /dev/tempX \n"); +} + +int main(int argc, char *argv[]) +{ + int fd; + int size; + + if (argc != 3) { + usage(); + return 10; + } + + fd = open(argv[1], O_RDONLY); + if (!fd) { + printf("Unable to open %s\n", argv[0]); + return 10; + } + + size = atoi(argv[2]); + + ioctl(fd, TFALLOC, &size); + + close(fd); + + return 0; +} diff --git a/src/cmd/tar.c b/src/cmd/tar.c new file mode 100644 index 0000000..4f1d564 --- /dev/null +++ b/src/cmd/tar.c @@ -0,0 +1,1407 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +/* + * Tape Archival Program + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define TBLOCK 512 +#define NBLOCK 20 +#define NAMSIZ 100 + +#define writetape(b) writetbuf(b, 1) +#define min(a,b) ((a) < (b) ? (a) : (b)) +#define max(a,b) ((a) > (b) ? (a) : (b)) + +union hblock { + char dummy[TBLOCK]; + struct header { + char name[NAMSIZ]; + char mode[8]; + char uid[8]; + char gid[8]; + char size[12]; + char mtime[12]; + char chksum[8]; + char linkflag; + char linkname[NAMSIZ]; + } dbuf; +}; + +struct linkbuf { + ino_t inum; + dev_t devnum; + int count; + char pathname[NAMSIZ]; + struct linkbuf *nextp; +}; + +union hblock dblock; +union hblock *tbuf; +struct linkbuf *ihead; +struct stat stbuf; + +int rflag; +int xflag; +int vflag; +int tflag; +int cflag; +int mflag; +int fflag; +int iflag; +int oflag; +int pflag; +int wflag; +int hflag; +int Bflag; +int Fflag; + +int mt; +int term; +int chksum; +int recno; +int first; +int prtlinkerr; +int freemem = 1; +int nblock = 0; + +daddr_t low; +daddr_t high; +daddr_t bsrch(); + +FILE *vfile = stdout; +FILE *tfile; +char tname[] = "/tmp/tarXXXXXX"; +char *usefile; +char magtape[] = "/dev/rmt8"; + +void +onintr (sig) + int sig; +{ + (void) signal(SIGINT, SIG_IGN); + term++; +} + +void +onquit (sig) + int sig; +{ + (void) signal(SIGQUIT, SIG_IGN); + term++; +} + +void +onhup (sig) + int sig; +{ + (void) signal(SIGHUP, SIG_IGN); + term++; +} + +#ifdef notdef +void +onterm (sig) + int sig; +{ + (void) signal(SIGTERM, SIG_IGN); + term++; +} +#endif + +main(argc, argv) +int argc; +char *argv[]; +{ + char *cp; + + if (argc < 2) + usage(); + + tfile = NULL; + usefile = magtape; + argv[argc] = 0; + argv++; + for (cp = *argv++; *cp; cp++) + switch(*cp) { + + case 'f': + if (*argv == 0) { + fprintf(stderr, + "tar: tapefile must be specified with 'f' option\n"); + usage(); + } + usefile = *argv++; + fflag++; + break; + + case 'c': + cflag++; + rflag++; + break; + + case 'o': + oflag++; + break; + + case 'p': + pflag++; + break; + + case 'u': + mktemp(tname); + if ((tfile = fopen(tname, "w")) == NULL) { + fprintf(stderr, + "tar: cannot create temporary file (%s)\n", + tname); + done(1); + } + fprintf(tfile, "!!!!!/!/!/!/!/!/!/! 000\n"); + /*FALL THRU*/ + + case 'r': + rflag++; + break; + + case 'v': + vflag++; + break; + + case 'w': + wflag++; + break; + + case 'x': + xflag++; + break; + + case 't': + tflag++; + break; + + case 'm': + mflag++; + break; + + case '-': + break; + + case '0': + case '1': + case '4': + case '5': + case '7': + case '8': + magtape[8] = *cp; + usefile = magtape; + break; + + case 'b': + if (*argv == 0) { + fprintf(stderr, + "tar: blocksize must be specified with 'b' option\n"); + usage(); + } + nblock = atoi(*argv); + if (nblock <= 0) { + fprintf(stderr, + "tar: invalid blocksize \"%s\"\n", *argv); + done(1); + } + argv++; + break; + + case 'l': + prtlinkerr++; + break; + + case 'h': + hflag++; + break; + + case 'i': + iflag++; + break; + + case 'B': + Bflag++; + break; + + case 'F': + Fflag++; + break; + + default: + fprintf(stderr, "tar: %c: unknown option\n", *cp); + usage(); + } + + if (!rflag && !xflag && !tflag) + usage(); + if (rflag) { + if (cflag && tfile != NULL) + usage(); + if (signal(SIGINT, SIG_IGN) != SIG_IGN) + (void) signal(SIGINT, onintr); + if (signal(SIGHUP, SIG_IGN) != SIG_IGN) + (void) signal(SIGHUP, onhup); + if (signal(SIGQUIT, SIG_IGN) != SIG_IGN) + (void) signal(SIGQUIT, onquit); +#ifdef notdef + if (signal(SIGTERM, SIG_IGN) != SIG_IGN) + (void) signal(SIGTERM, onterm); +#endif + mt = openmt(usefile, 1); + dorep(argv); + done(0); + } + mt = openmt(usefile, 0); + if (xflag) + doxtract(argv); + else + dotable(argv); + done(0); +} + +usage() +{ + fprintf(stderr, +"tar: usage: tar -{txru}[cvfblmhopwBi] [tapefile] [blocksize] file1 file2...\n"); + done(1); +} + +int +openmt(tape, writing) + char *tape; + int writing; +{ + + if (strcmp(tape, "-") == 0) { + /* + * Read from standard input or write to standard output. + */ + if (writing) { + if (cflag == 0) { + fprintf(stderr, + "tar: can only create standard output archives\n"); + done(1); + } + vfile = stderr; + setlinebuf(vfile); + mt = dup(1); + } else { + mt = dup(0); + Bflag++; + } + } else { + /* + * Use file or tape on local machine. + */ + if (writing) { + if (cflag) + mt = open(tape, O_RDWR|O_CREAT|O_TRUNC, 0666); + else + mt = open(tape, O_RDWR); + } else + mt = open(tape, O_RDONLY); + if (mt < 0) { + fprintf(stderr, "tar: "); + perror(tape); + done(1); + } + } + return(mt); +} + +char * +getcwd(buf) + char *buf; +{ + if (getwd(buf) == NULL) { + fprintf(stderr, "tar: %s\n", buf); + exit(1); + } + return (buf); +} + +dorep(argv) + char *argv[]; +{ + register char *cp, *cp2; + char wdir[MAXPATHLEN], tempdir[MAXPATHLEN], *parent; + + if (!cflag) { + getdir(); + do { + passtape(); + if (term) + done(0); + getdir(); + } while (!endtape()); + backtape(); + if (tfile != NULL) { + char buf[200]; + + sprintf(buf, +"sort +0 -1 +1nr %s -o %s; awk '$1 != prev {print; prev=$1}' %s >%sX; mv %sX %s", + tname, tname, tname, tname, tname, tname); + fflush(tfile); + system(buf); + freopen(tname, "r", tfile); + fstat(fileno(tfile), &stbuf); + high = stbuf.st_size; + } + } + + (void) getcwd(wdir); + while (*argv && ! term) { + cp2 = *argv; + if (!strcmp(cp2, "-C") && argv[1]) { + argv++; + if (chdir(*argv) < 0) { + fprintf(stderr, "tar: can't change directories to "); + perror(*argv); + } else + (void) getcwd(wdir); + argv++; + continue; + } + + if (*argv[0] == '/'){ + parent = ""; + } else { + parent = wdir; + } + + for (cp = *argv; *cp; cp++) + if (*cp == '/') + cp2 = cp; + if (cp2 != *argv) { + *cp2 = '\0'; + if (chdir(*argv) < 0) { + fprintf(stderr, "tar: can't change directories to "); + perror(*argv); + continue; + } + parent = getcwd(tempdir); + *cp2 = '/'; + cp2++; + } + putfile(*argv++, cp2, parent); + if (chdir(wdir) < 0) { + fprintf(stderr, "tar: cannot change back?: "); + perror(wdir); + } + } + putempty(); + putempty(); + flushtape(); + if (prtlinkerr == 0) + return; + for (; ihead != NULL; ihead = ihead->nextp) { + if (ihead->count == 0) + continue; + fprintf(stderr, "tar: missing links to %s\n", ihead->pathname); + } +} + +endtape() +{ + return (dblock.dbuf.name[0] == '\0'); +} + +getdir() +{ + register struct stat *sp; + int i; +top: + readtape((char *)&dblock); + if (dblock.dbuf.name[0] == '\0') + return; + sp = &stbuf; + sscanf(dblock.dbuf.mode, "%o", &i); + sp->st_mode = i; + sscanf(dblock.dbuf.uid, "%o", &i); + sp->st_uid = i; + sscanf(dblock.dbuf.gid, "%o", &i); + sp->st_gid = i; + sscanf(dblock.dbuf.size, "%lo", &sp->st_size); + sscanf(dblock.dbuf.mtime, "%lo", &sp->st_mtime); + sscanf(dblock.dbuf.chksum, "%o", &chksum); + if (chksum != (i = checksum())) { + fprintf(stderr, "tar: directory checksum error (%d != %d)\n", + chksum, i); + if (iflag) + goto top; + done(2); + } + if (tfile != NULL) + fprintf(tfile, "%s %s\n", dblock.dbuf.name, dblock.dbuf.mtime); +} + +passtape() +{ + long blocks; + char *bufp; + + if (dblock.dbuf.linkflag == '1') + return; + blocks = stbuf.st_size; + blocks += TBLOCK-1; + blocks /= TBLOCK; + + while (blocks-- > 0) + (void) readtbuf(&bufp, TBLOCK); +} + +char * +getmem(size) +{ + char *p = malloc((unsigned) size); + + if (p == NULL && freemem) { + fprintf(stderr, + "tar: out of memory, link and directory modtime info lost\n"); + freemem = 0; + } + return (p); +} + +putfile(longname, shortname, parent) + char *longname; + char *shortname; + char *parent; +{ + int infile = 0; + long blocks; + char buf[TBLOCK]; + char *bigbuf; + register char *cp; + struct direct *dp; + DIR *dirp; + register int i; + long l; + char newparent[NAMSIZ+64]; + extern int errno; + int maxread; + int hint; /* amount to write to get "in sync" */ + + if (!hflag) + i = lstat(shortname, &stbuf); + else + i = stat(shortname, &stbuf); + if (i < 0) { + fprintf(stderr, "tar: "); + perror(longname); + return; + } + if (tfile != NULL && checkupdate(longname) == 0) + return; + if (checkw('r', longname) == 0) + return; + if (Fflag && checkf(shortname, stbuf.st_mode, Fflag) == 0) + return; + + switch (stbuf.st_mode & S_IFMT) { + case S_IFDIR: + for (i = 0, cp = buf; *cp++ = longname[i++];) + ; + *--cp = '/'; + *++cp = 0 ; + if (!oflag) { + if ((cp - buf) >= NAMSIZ) { + fprintf(stderr, "tar: %s: file name too long\n", + longname); + return; + } + stbuf.st_size = 0; + tomodes(&stbuf); + strcpy(dblock.dbuf.name,buf); + sprintf(dblock.dbuf.chksum, "%6o", checksum()); + (void) writetape((char *)&dblock); + } + sprintf(newparent, "%s/%s", parent, shortname); + if (chdir(shortname) < 0) { + perror(shortname); + return; + } + if ((dirp = opendir(".")) == NULL) { + fprintf(stderr, "tar: %s: directory read error\n", + longname); + if (chdir(parent) < 0) { + fprintf(stderr, "tar: cannot change back?: "); + perror(parent); + } + return; + } + while ((dp = readdir(dirp)) != NULL && !term) { + if (dp->d_ino == 0) + continue; + if (!strcmp(".", dp->d_name) || + !strcmp("..", dp->d_name)) + continue; + strcpy(cp, dp->d_name); + l = telldir(dirp); + closedir(dirp); + putfile(buf, cp, newparent); + dirp = opendir("."); + seekdir(dirp, l); + } + closedir(dirp); + if (chdir(parent) < 0) { + fprintf(stderr, "tar: cannot change back?: "); + perror(parent); + } + break; + + case S_IFLNK: + tomodes(&stbuf); + if (strlen(longname) >= NAMSIZ) { + fprintf(stderr, "tar: %s: file name too long\n", + longname); + return; + } + strcpy(dblock.dbuf.name, longname); + if (stbuf.st_size + 1 >= NAMSIZ) { + fprintf(stderr, "tar: %s: symbolic link too long\n", + longname); + return; + } + i = readlink(shortname, dblock.dbuf.linkname, NAMSIZ - 1); + if (i < 0) { + fprintf(stderr, "tar: can't read symbolic link "); + perror(longname); + return; + } + dblock.dbuf.linkname[i] = '\0'; + dblock.dbuf.linkflag = '2'; + if (vflag) + fprintf(vfile, "a %s symbolic link to %s\n", + longname, dblock.dbuf.linkname); + sprintf(dblock.dbuf.size, "%11lo", 0L); + sprintf(dblock.dbuf.chksum, "%6o", checksum()); + (void) writetape((char *)&dblock); + break; + + case S_IFREG: + if ((infile = open(shortname, 0)) < 0) { + fprintf(stderr, "tar: "); + perror(longname); + return; + } + tomodes(&stbuf); + if (strlen(longname) >= NAMSIZ) { + fprintf(stderr, "tar: %s: file name too long\n", + longname); + close(infile); + return; + } + strcpy(dblock.dbuf.name, longname); + if (stbuf.st_nlink > 1) { + struct linkbuf *lp; + int found = 0; + + for (lp = ihead; lp != NULL; lp = lp->nextp) + if (lp->inum == stbuf.st_ino && + lp->devnum == stbuf.st_dev) { + found++; + break; + } + if (found) { + strcpy(dblock.dbuf.linkname, lp->pathname); + dblock.dbuf.linkflag = '1'; + sprintf(dblock.dbuf.chksum, "%6o", checksum()); + (void) writetape( (char *) &dblock); + if (vflag) + fprintf(vfile, "a %s link to %s\n", + longname, lp->pathname); + lp->count--; + close(infile); + return; + } + lp = (struct linkbuf *) getmem(sizeof(*lp)); + if (lp != NULL) { + lp->nextp = ihead; + ihead = lp; + lp->inum = stbuf.st_ino; + lp->devnum = stbuf.st_dev; + lp->count = stbuf.st_nlink - 1; + strcpy(lp->pathname, longname); + } + } + blocks = (stbuf.st_size + (TBLOCK-1)) / TBLOCK; + if (vflag) + fprintf(vfile, "a %s %ld blocks\n", longname, blocks); + sprintf(dblock.dbuf.chksum, "%6o", checksum()); + hint = writetape((char *)&dblock); + maxread = max(stbuf.st_blksize, (nblock * TBLOCK)); + if ((bigbuf = malloc((unsigned)maxread)) == 0) { + maxread = TBLOCK; + bigbuf = buf; + } + + while ((i = read(infile, bigbuf, min((hint*TBLOCK), maxread))) > 0 + && blocks > 0) { + register int nblks; + + nblks = ((i-1)/TBLOCK)+1; + if (nblks > blocks) + nblks = blocks; + hint = writetbuf(bigbuf, nblks); + blocks -= nblks; + } + close(infile); + if (bigbuf != buf) + free(bigbuf); + if (i < 0) { + fprintf(stderr, "tar: Read error on "); + perror(longname); + } else if (blocks != 0 || i != 0) + fprintf(stderr, "tar: %s: file changed size\n", + longname); + while (--blocks >= 0) + putempty(); + break; + + default: + fprintf(stderr, "tar: %s is not a file. Not dumped\n", + longname); + break; + } +} + +doxtract(argv) + char *argv[]; +{ + long blocks, bytes; + int ofile, i; + extern int errno; + + for (;;) { + if ((i = wantit(argv)) == 0) + continue; + if (i == -1) + break; /* end of tape */ + if (checkw('x', dblock.dbuf.name) == 0) { + passtape(); + continue; + } + if (Fflag) { + char *s; + + if ((s = rindex(dblock.dbuf.name, '/')) == 0) + s = dblock.dbuf.name; + else + s++; + if (checkf(s, stbuf.st_mode, Fflag) == 0) { + passtape(); + continue; + } + } + if (checkdir(dblock.dbuf.name)) { /* have a directory */ + if (mflag == 0) + dodirtimes(&dblock); + continue; + } + if (dblock.dbuf.linkflag == '2') { /* symlink */ + /* + * only unlink non directories or empty + * directories + */ + if (rmdir(dblock.dbuf.name) < 0) { + if (errno == ENOTDIR) + unlink(dblock.dbuf.name); + } + if (symlink(dblock.dbuf.linkname, dblock.dbuf.name)<0) { + fprintf(stderr, "tar: %s: symbolic link failed: ", + dblock.dbuf.name); + perror(""); + continue; + } + if (vflag) + fprintf(vfile, "x %s symbolic link to %s\n", + dblock.dbuf.name, dblock.dbuf.linkname); +#ifdef notdef + /* ignore alien orders */ + chown(dblock.dbuf.name, stbuf.st_uid, stbuf.st_gid); + if (mflag == 0) + setimes(dblock.dbuf.name, stbuf.st_mtime); + if (pflag) + chmod(dblock.dbuf.name, stbuf.st_mode & 07777); +#endif + continue; + } + if (dblock.dbuf.linkflag == '1') { /* regular link */ + /* + * only unlink non directories or empty + * directories + */ + if (rmdir(dblock.dbuf.name) < 0) { + if (errno == ENOTDIR) + unlink(dblock.dbuf.name); + } + if (link(dblock.dbuf.linkname, dblock.dbuf.name) < 0) { + fprintf(stderr, "tar: can't link %s to %s: ", + dblock.dbuf.name, dblock.dbuf.linkname); + perror(""); + continue; + } + if (vflag) + fprintf(vfile, "%s linked to %s\n", + dblock.dbuf.name, dblock.dbuf.linkname); + continue; + } + if ((ofile = creat(dblock.dbuf.name,stbuf.st_mode&0xfff)) < 0) { + fprintf(stderr, "tar: can't create %s: ", + dblock.dbuf.name); + perror(""); + passtape(); + continue; + } + chown(dblock.dbuf.name, stbuf.st_uid, stbuf.st_gid); + blocks = ((bytes = stbuf.st_size) + TBLOCK-1)/TBLOCK; + if (vflag) + fprintf(vfile, "x %s, %ld bytes, %ld tape blocks\n", + dblock.dbuf.name, bytes, blocks); + for (; blocks > 0;) { + register int nread; + char *bufp; + register int nwant; + + nwant = NBLOCK*TBLOCK; + if (nwant > (blocks*TBLOCK)) + nwant = (blocks*TBLOCK); + nread = readtbuf(&bufp, nwant); + if (write(ofile, bufp, (int)min(nread, bytes)) < 0) { + fprintf(stderr, + "tar: %s: HELP - extract write error", + dblock.dbuf.name); + perror(""); + done(2); + } + bytes -= nread; + blocks -= (((nread-1)/TBLOCK)+1); + } + close(ofile); + if (mflag == 0) + setimes(dblock.dbuf.name, stbuf.st_mtime); + if (pflag) + chmod(dblock.dbuf.name, stbuf.st_mode & 07777); + } + if (mflag == 0) { + dblock.dbuf.name[0] = '\0'; /* process the whole stack */ + dodirtimes(&dblock); + } +} + +dotable(argv) + char *argv[]; +{ + register int i; + + for (;;) { + if ((i = wantit(argv)) == 0) + continue; + if (i == -1) + break; /* end of tape */ + if (vflag) + longt(&stbuf); + printf("%s", dblock.dbuf.name); + if (dblock.dbuf.linkflag == '1') + printf(" linked to %s", dblock.dbuf.linkname); + if (dblock.dbuf.linkflag == '2') + printf(" symbolic link to %s", dblock.dbuf.linkname); + printf("\n"); + passtape(); + } +} + +putempty() +{ + char buf[TBLOCK]; + + bzero(buf, sizeof (buf)); + (void) writetape(buf); +} + +longt(st) + register struct stat *st; +{ + register char *cp; + char *ctime(); + + pmode(st); + printf("%3d/%1d", st->st_uid, st->st_gid); + printf("%7ld", st->st_size); + cp = ctime(&st->st_mtime); + printf(" %-12.12s %-4.4s ", cp+4, cp+20); +} + +#define SUID 04000 +#define SGID 02000 +#define ROWN 0400 +#define WOWN 0200 +#define XOWN 0100 +#define RGRP 040 +#define WGRP 020 +#define XGRP 010 +#define ROTH 04 +#define WOTH 02 +#define XOTH 01 +#define STXT 01000 +int m1[] = { 1, ROWN, 'r', '-' }; +int m2[] = { 1, WOWN, 'w', '-' }; +int m3[] = { 2, SUID, 's', XOWN, 'x', '-' }; +int m4[] = { 1, RGRP, 'r', '-' }; +int m5[] = { 1, WGRP, 'w', '-' }; +int m6[] = { 2, SGID, 's', XGRP, 'x', '-' }; +int m7[] = { 1, ROTH, 'r', '-' }; +int m8[] = { 1, WOTH, 'w', '-' }; +int m9[] = { 2, STXT, 't', XOTH, 'x', '-' }; + +int *m[] = { m1, m2, m3, m4, m5, m6, m7, m8, m9}; + +pmode(st) + register struct stat *st; +{ + register int **mp; + + for (mp = &m[0]; mp < &m[9];) + selectbits(*mp++, st); +} + +selectbits(pairp, st) + int *pairp; + struct stat *st; +{ + register int n, *ap; + + ap = pairp; + n = *ap++; + while (--n>=0 && (st->st_mode&*ap++)==0) + ap++; + putchar(*ap); +} + +/* + * Make all directories needed by `name'. If `name' is itself + * a directory on the tar tape (indicated by a trailing '/'), + * return 1; else 0. + */ +checkdir(name) + register char *name; +{ + register char *cp; + + /* + * Quick check for existence of directory. + */ + if ((cp = rindex(name, '/')) == 0) + return (0); + *cp = '\0'; + if (access(name, 0) == 0) { /* already exists */ + *cp = '/'; + return (cp[1] == '\0'); /* return (lastchar == '/') */ + } + *cp = '/'; + + /* + * No luck, try to make all directories in path. + */ + for (cp = name; *cp; cp++) { + if (*cp != '/') + continue; + *cp = '\0'; + if (access(name, 0) < 0) { + if (mkdir(name, 0777) < 0) { + perror(name); + *cp = '/'; + return (0); + } + chown(name, stbuf.st_uid, stbuf.st_gid); + if (pflag && cp[1] == '\0') /* dir on the tape */ + chmod(name, stbuf.st_mode & 07777); + } + *cp = '/'; + } + return (cp[-1]=='/'); +} + +tomodes(sp) +register struct stat *sp; +{ + register char *cp; + + for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; cp++) + *cp = '\0'; + sprintf(dblock.dbuf.mode, "%6o ", sp->st_mode & 07777); + sprintf(dblock.dbuf.uid, "%6o ", sp->st_uid); + sprintf(dblock.dbuf.gid, "%6o ", sp->st_gid); + sprintf(dblock.dbuf.size, "%11lo ", sp->st_size); + sprintf(dblock.dbuf.mtime, "%11lo ", sp->st_mtime); +} + +checksum() +{ + register i; + register char *cp; + + for (cp = dblock.dbuf.chksum; + cp < &dblock.dbuf.chksum[sizeof(dblock.dbuf.chksum)]; cp++) + *cp = ' '; + i = 0; + for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; cp++) + i += *cp; + return (i); +} + +checkw(c, name) + char *name; +{ + if (!wflag) + return (1); + printf("%c ", c); + if (vflag) + longt(&stbuf); + printf("%s: ", name); + return (response() == 'y'); +} + +response() +{ + char c; + + c = getchar(); + if (c != '\n') + while (getchar() != '\n') + ; + else + c = 'n'; + return (c); +} + +checkf(name, mode, howmuch) + char *name; + int mode, howmuch; +{ + int l; + + if ((mode & S_IFMT) == S_IFDIR){ + if ((strcmp(name, "SCCS")==0) || (strcmp(name, "RCS")==0)) + return(0); + return(1); + } + if ((l = strlen(name)) < 3) + return (1); + if (howmuch > 1 && name[l-2] == '.' && name[l-1] == 'o') + return (0); + if (strcmp(name, "core") == 0 || + strcmp(name, "errs") == 0 || + (howmuch > 1 && strcmp(name, "a.out") == 0)) + return (0); + /* SHOULD CHECK IF IT IS EXECUTABLE */ + return (1); +} + +/* Is the current file a new file, or the newest one of the same name? */ +checkupdate(arg) + char *arg; +{ + char name[100]; + long mtime; + daddr_t seekp; + daddr_t lookup(); + + rewind(tfile); + for (;;) { + if ((seekp = lookup(arg)) < 0) + return (1); + fseek(tfile, seekp, 0); + fscanf(tfile, "%s %lo", name, &mtime); + return (stbuf.st_mtime > mtime); + } +} + +done(n) +{ + unlink(tname); + exit(n); +} + +/* + * Do we want the next entry on the tape, i.e. is it selected? If + * not, skip over the entire entry. Return -1 if reached end of tape. + */ +wantit(argv) + char *argv[]; +{ + register char **cp; + + getdir(); + if (endtape()) + return (-1); + if (*argv == 0) + return (1); + for (cp = argv; *cp; cp++) + if (prefix(*cp, dblock.dbuf.name)) + return (1); + passtape(); + return (0); +} + +/* + * Does s2 begin with the string s1, on a directory boundary? + */ +prefix(s1, s2) + register char *s1, *s2; +{ + while (*s1) + if (*s1++ != *s2++) + return (0); + if (*s2) + return (*s2 == '/'); + return (1); +} + +#define N 200 +int njab; + +daddr_t +lookup(s) + char *s; +{ + register i; + daddr_t a; + + for(i=0; s[i]; i++) + if (s[i] == ' ') + break; + a = bsrch(s, i, low, high); + return (a); +} + +daddr_t +bsrch(s, n, l, h) + daddr_t l, h; + char *s; +{ + register i, j; + char b[N]; + daddr_t m, m1; + + njab = 0; + +loop: + if (l >= h) + return ((daddr_t) -1); + m = l + (h-l)/2 - N/2; + if (m < l) + m = l; + fseek(tfile, m, 0); + fread(b, 1, N, tfile); + njab++; + for(i=0; i= h) + return ((daddr_t) -1); + m1 = m; + j = i; + for(i++; i 0) { + l = m1; + goto loop; + } + return (m); +} + +cmp(b, s, n) + char *b, *s; +{ + register i; + + if (b[0] != '\n') + exit(2); + for(i=0; i s[i]) + return (-1); + if (b[i+1] < s[i]) + return (1); + } + return (b[i+1] == ' '? 0 : -1); +} + +readtape(buffer) + char *buffer; +{ + char *bufp; + + if (first == 0) + getbuf(); + (void) readtbuf(&bufp, TBLOCK); + bcopy(bufp, buffer, TBLOCK); + return(TBLOCK); +} + +readtbuf(bufpp, size) + char **bufpp; + int size; +{ + register int i; + + if (recno >= nblock || first == 0) { + if ((i = bread(mt, (char *)tbuf, TBLOCK*nblock)) < 0) + mterr("read", i, 3); + if (first == 0) { + if ((i % TBLOCK) != 0) { + fprintf(stderr, "tar: tape blocksize error\n"); + done(3); + } + i /= TBLOCK; + if (i != nblock) { + fprintf(stderr, "tar: blocksize = %d\n", i); + nblock = i; + } + first = 1; + } + recno = 0; + } + if (size > ((nblock-recno)*TBLOCK)) + size = (nblock-recno)*TBLOCK; + *bufpp = (char *)&tbuf[recno]; + recno += (size/TBLOCK); + return (size); +} + +writetbuf(buffer, n) + register char *buffer; + register int n; +{ + int i; + + if (first == 0) { + getbuf(); + first = 1; + } + if (recno >= nblock) { + i = write(mt, (char *)tbuf, TBLOCK*nblock); + if (i != TBLOCK*nblock) + mterr("write", i, 2); + recno = 0; + } + + /* + * Special case: We have an empty tape buffer, and the + * users data size is >= the tape block size: Avoid + * the bcopy and dma direct to tape. BIG WIN. Add the + * residual to the tape buffer. + */ + while (recno == 0 && n >= nblock) { + i = write(mt, buffer, TBLOCK*nblock); + if (i != TBLOCK*nblock) + mterr("write", i, 2); + n -= nblock; + buffer += (nblock * TBLOCK); + } + + while (n-- > 0) { + bcopy(buffer, (char *)&tbuf[recno++], TBLOCK); + buffer += TBLOCK; + if (recno >= nblock) { + i = write(mt, (char *)tbuf, TBLOCK*nblock); + if (i != TBLOCK*nblock) + mterr("write", i, 2); + recno = 0; + } + } + + /* Tell the user how much to write to get in sync */ + return (nblock - recno); +} + +backtape() +{ + static int mtdev = 1; + static struct mtop mtop = {MTBSR, 1}; + struct mtget mtget; + + if (mtdev == 1) + mtdev = ioctl(mt, MTIOCGET, (char *)&mtget); + if (mtdev == 0) { + if (ioctl(mt, MTIOCTOP, (char *)&mtop) < 0) { + fprintf(stderr, "tar: tape backspace error: "); + perror(""); + done(4); + } + } else + lseek(mt, (daddr_t) -TBLOCK*nblock, 1); + recno--; +} + +flushtape() +{ + int i; + + i = write(mt, (char *)tbuf, TBLOCK*nblock); + if (i != TBLOCK*nblock) + mterr("write", i, 2); +} + +mterr(operation, i, exitcode) + char *operation; + int i; +{ + fprintf(stderr, "tar: tape %s error: ", operation); + if (i < 0) + perror(""); + else + fprintf(stderr, "unexpected EOF\n"); + done(exitcode); +} + +bread(fd, buf, size) + int fd; + char *buf; + int size; +{ + int count; + static int lastread = 0; + + if (!Bflag) + return (read(fd, buf, size)); + + for (count = 0; count < size; count += lastread) { + lastread = read(fd, buf, size - count); + if (lastread <= 0) { + if (count > 0) + return (count); + return (lastread); + } + buf += lastread; + } + return (count); +} + +getbuf() +{ + + if (nblock == 0) { + fstat(mt, &stbuf); + if ((stbuf.st_mode & S_IFMT) == S_IFCHR) + nblock = NBLOCK; + else { + nblock = stbuf.st_blksize / TBLOCK; + if (nblock == 0) + nblock = NBLOCK; + } + } + tbuf = (union hblock *)malloc((unsigned)nblock*TBLOCK); + if (tbuf == NULL) { + fprintf(stderr, "tar: blocksize %d too big, can't get memory\n", + nblock); + done(1); + } +} + +/* + * Save this directory and its mtime on the stack, popping and setting + * the mtimes of any stacked dirs which aren't parents of this one. + * A null directory causes the entire stack to be unwound and set. + * + * Since all the elements of the directory "stack" share a common + * prefix, we can make do with one string. We keep only the current + * directory path, with an associated array of mtime's, one for each + * '/' in the path. A negative mtime means no mtime. The mtime's are + * offset by one (first index 1, not 0) because calling this with a null + * directory causes mtime[0] to be set. + * + * This stack algorithm is not guaranteed to work for tapes created + * with the 'r' option, but the vast majority of tapes with + * directories are not. This avoids saving every directory record on + * the tape and setting all the times at the end. + */ +char dirstack[NAMSIZ]; +#define NTIM (NAMSIZ/2+1) /* a/b/c/d/... */ +time_t mtime[NTIM]; + +dodirtimes(hp) + union hblock *hp; +{ + register char *p = dirstack; + register char *q = hp->dbuf.name; + register int ndir = 0; + char *savp; + int savndir; + + /* Find common prefix */ + while (*p == *q) { + if (*p++ == '/') + ++ndir; + q++; + } + + savp = p; + savndir = ndir; + while (*p) { + /* + * Not a child: unwind the stack, setting the times. + * The order we do this doesn't matter, so we go "forward." + */ + if (*p++ == '/') + if (mtime[++ndir] >= 0) { + *--p = '\0'; /* zap the slash */ + setimes(dirstack, mtime[ndir]); + *p++ = '/'; + } + } + p = savp; + ndir = savndir; + + /* Push this one on the "stack" */ + while (*p = *q++) /* append the rest of the new dir */ + if (*p++ == '/') + mtime[++ndir] = -1; + mtime[ndir] = stbuf.st_mtime; /* overwrite the last one */ +} + +setimes(path, mt) + char *path; + time_t mt; +{ + struct timeval tv[2]; + + tv[0].tv_sec = time((time_t *) 0); + tv[1].tv_sec = mt; + tv[0].tv_usec = tv[1].tv_usec = 0; + if (utimes(path, tv) < 0) { + fprintf(stderr, "tar: can't set time on %s: ", path); + perror(""); + } +} diff --git a/src/cmd/tcl/Makefile b/src/cmd/tcl/Makefile new file mode 100644 index 0000000..2514d51 --- /dev/null +++ b/src/cmd/tcl/Makefile @@ -0,0 +1,46 @@ +TOPSRC = $(shell cd ../../..; pwd) +include $(TOPSRC)/target.mk +#include $(TOPSRC)/cross.mk + +CFLAGS += -Os -Wall -Werror -Wno-error=pointer-sign -Wno-pointer-sign + +LDFLAGS += + +OBJS = tclsh.o +LIBS = -ltcl + +all: tcl + +tcl: ${OBJS} + ${CC} ${LDFLAGS} -o tcl.elf ${OBJS} ${LIBS} + ${OBJDUMP} -S tcl.elf > tcl.dis + ${SIZE} tcl.elf + ${ELF2AOUT} tcl.elf $@ && rm tcl.elf + +clean: + rm -f *.o *.0 *.elf tcl *.elf *.dis a.out tags *~ + +install: all + install tcl $(DESTDIR)/bin/ + +### +regexp.o: regexp.c regexp.h regpriv.h +regsub.o: regsub.c regexp.h regpriv.h +tclassem.o: tclassem.c internal.h tcl.h hash.h +tclbasic.o: tclbasic.c internal.h tcl.h hash.h +tclcmdah.o: tclcmdah.c internal.h tcl.h hash.h +tclcmdil.o: tclcmdil.c internal.h tcl.h hash.h +tclcmdmz.o: tclcmdmz.c internal.h tcl.h hash.h regexp.h regpriv.h +tclenv.o: tclenv.c internal.h tcl.h hash.h +tclexpr.o: tclexpr.c internal.h tcl.h hash.h +tclget.o: tclget.c internal.h tcl.h hash.h +tclglob.o: tclglob.c internal.h tcl.h hash.h +tclhash.o: tclhash.c internal.h tcl.h hash.h +tclparse.o: tclparse.c internal.h tcl.h hash.h +tclproc.o: tclproc.c internal.h tcl.h hash.h +tclsh.o: tclsh.c +tclunxaz.o: tclunxaz.c internal.h tcl.h hash.h +tclutil.o: tclutil.c internal.h tcl.h hash.h regexp.h +tcluxstr.o: tcluxstr.c internal.h tcl.h hash.h +tcluxutl.o: tcluxutl.c internal.h tcl.h hash.h +tclvar.o: tclvar.c internal.h tcl.h hash.h diff --git a/src/cmd/tcl/tclsh.c b/src/cmd/tcl/tclsh.c new file mode 100644 index 0000000..1e01400 --- /dev/null +++ b/src/cmd/tcl/tclsh.c @@ -0,0 +1,221 @@ +/* + * TCL shell for RetroBSD. + * Copyright (C) 2011 Serge Vakulenko, + */ +#ifdef CROSS +# include +#else +# include +#endif +#include +#include + +/* + * Implement the TCL loop command: + * loop var start end [increment] command + */ +static int +loop_cmd (void *arg, Tcl_Interp *interp, int argc, unsigned char **argv) +{ + int result = TCL_OK; + int i, first, limit, incr = 1; + unsigned char *command; + unsigned char itxt [12]; + + if ((argc < 5) || (argc > 6)) { + Tcl_AppendResult (interp, "bad # args: ", argv [0], + " var first limit [incr] command", 0); + return TCL_ERROR; + } + + if (Tcl_GetInt (interp, argv[2], &first) != TCL_OK) + return TCL_ERROR; + + if (Tcl_GetInt (interp, argv[3], &limit) != TCL_OK) + return TCL_ERROR; + + if (argc == 5) + command = argv[4]; + else { + if (Tcl_GetInt (interp, argv[4], &incr) != TCL_OK) + return TCL_ERROR; + command = argv[5]; + } + + for (i = first; + (((i < limit) && (incr > 0)) || ((i > limit) && (incr < 0))); + i += incr) { + sprintf (itxt, "%d", i); + if (! Tcl_SetVar (interp, argv [1], itxt, TCL_LEAVE_ERR_MSG)) + return TCL_ERROR; + + result = Tcl_Eval (interp, command, 0, 0); + if (result != TCL_OK) { + if (result == TCL_CONTINUE) { + result = TCL_OK; + } else if (result == TCL_BREAK) { + result = TCL_OK; + break; + } else if (result == TCL_ERROR) { + unsigned char buf [64]; + + sprintf (buf, "\n (\"loop\" body line %d)", + interp->errorLine); + Tcl_AddErrorInfo (interp, buf); + break; + } else { + break; + } + } + } + + /* + * Set variable to its final value. + */ + sprintf (itxt, "%d", i); + if (! Tcl_SetVar (interp, argv [1], itxt, TCL_LEAVE_ERR_MSG)) + return TCL_ERROR; + + return result; +} + +/* + * Implement the TCL echo command: + * echo arg ... + */ +static int +echo_cmd (void *arg, Tcl_Interp *interp, int argc, unsigned char **argv) +{ + FILE *output = arg; + int i; + + for (i=1; ; i++) { + if (! argv[i]) { + if (i != argc) +echoError: sprintf (interp->result, + "argument list wasn't properly NULL-terminated in \"%s\" command", + argv[0]); + break; + } + if (i >= argc) + goto echoError; + + if (i > 1) + putc (' ', output); + fputs ((char*) argv[i], output); + } + putc ('\n', output); + return TCL_OK; +} + +static int +help_cmd (void *arg, Tcl_Interp *interp, int argc, unsigned char **argv) +{ + FILE *output = arg; + + fputs ("Available commands:\n", output); + fputs (" loop var first limit [incr] command\n", output); + fputs (" echo [param...]\n", output); + return TCL_OK; +} + +/* + * Read a newline-terminated string from stream. + */ +static unsigned char * +getlin (FILE *input, FILE *output, unsigned char *buf, int len) +{ + int c; + unsigned char *s; + + s = buf; + while (--len > 0) { + fflush (output); + c = getc (input); + if (feof (input)) + return 0; + if (c == '\b') { + if (s > buf) { + --s; + fputs ("\b \b", output); + } + continue; + } + if (c == '\r') + c = '\n'; + putc (c, output); + *s++ = c; + if (c == '\n') + break; + } + *s = '\0'; + return buf; +} + +void tcl_main () +{ + FILE *input = stdin; + FILE *output = stdout; + Tcl_Interp *interp; + Tcl_CmdBuf buffer; + unsigned char line [200], *cmd; + int result, got_partial, quit_flag; + + fputs ("\n\nTCL Shell\n", stdout); + fputs ("~~~~~~~~~\n", stdout); + fputs ("\nEnter \"help\" for a list of commands\n\n", stdout); + + interp = Tcl_CreateInterp (); + Tcl_CreateCommand (interp, (unsigned char*) "loop", loop_cmd, output, 0); + Tcl_CreateCommand (interp, (unsigned char*) "echo", echo_cmd, output, 0); + Tcl_CreateCommand (interp, (unsigned char*) "help", help_cmd, output, 0); + + buffer = Tcl_CreateCmdBuf (); + got_partial = 0; + quit_flag = 0; + while (! quit_flag) { + /*clearerr (input);*/ + if (! got_partial) { + fputs ("% ", output); + } + if (! getlin (input, output, line, sizeof (line))) { + if (! got_partial) + break; + + line[0] = 0; + } + cmd = Tcl_AssembleCmd (buffer, line); + if (! cmd) { + got_partial = 1; + continue; + } + + got_partial = 0; + result = Tcl_Eval (interp, cmd, 0, 0); + + if (result != TCL_OK) { + fputs ("Error", output); + + if (result != TCL_ERROR) + fprintf (output, " %d", result); + + if (*interp->result != 0) + fprintf (output, ": %s", interp->result); + + putc ('\n', output); + continue; + } + + if (*interp->result != 0) + fprintf (output, "%s\n", interp->result); + } + fflush (output); + Tcl_DeleteInterp (interp); + Tcl_DeleteCmdBuf (buffer); +} + +int main (void) +{ + for (;;) + tcl_main (); +} diff --git a/src/cmd/tee.c b/src/cmd/tee.c new file mode 100644 index 0000000..df5f8da --- /dev/null +++ b/src/cmd/tee.c @@ -0,0 +1,95 @@ +/* + * tee-- pipe fitting + */ +#include +#include +#include +#include +#include + +#define BUFSIZ 8192 + +int openf[20] = { 1 }; +int n = 1; +int t = 0; +int aflag; + +char in[BUFSIZ]; + +char out[BUFSIZ]; + +putstr(s) +char *s; +{ + while(*s) + write(2,s++,1); +} + +main(argc,argv) +char **argv; +{ + int register r,w,p; + struct stat buf; + while(argc>1&&argv[1][0]=='-') { + switch(argv[1][1]) { + case 'a': + aflag++; + break; + case 'i': + case 0: + signal(SIGINT, SIG_IGN); + } + argv++; + argc--; + } + fstat(1,&buf); + t = (buf.st_mode&S_IFMT)==S_IFCHR; + if(lseek(1,0L,1)==-1&&errno==ESPIPE) + t++; + while(argc-->1) { + if(aflag) { + openf[n] = open(argv[1],1); + if(openf[n] < 0) + openf[n] = creat(argv[1],0666); + lseek(openf[n++],0L,2); + } else + openf[n++] = creat(argv[1],0666); + if(stat(argv[1],&buf)>=0) { + if((buf.st_mode&S_IFMT)==S_IFCHR) + t++; + } else { + putstr("tee: cannot open "); + putstr(argv[1]); + putstr("\n"); + n--; + } + argv++; + } + r = w = 0; + for(;;) { + for(p=0;p=w) { + if(t>0&&p>0) break; + w = read(0,in,BUFSIZ); + r = 0; + if(w<=0) { + stash(p); + exit(0); + } + } + out[p++] = in[r++]; + } + stash(p); + } +} + +stash(p) +{ + int k; + int i; + int d; + d = t ? 16 : p; + for(i=0; i test.dis + ${SIZE} test.elf + ${ELF2AOUT} test.elf $@ && rm test.elf + +$(MAN): ${MANSRC} + ${MANROFF} $< > $@ + +clean: + rm -f *.o *.elf ${MAN} test *.elf *.dis tags *~ + +install: all + install test ${DESTDIR}/bin/ + @rm -f ${DESTDIR}/bin/[ + ln ${DESTDIR}/bin/test ${DESTDIR}/bin/[ + cp $(MAN) ${DESTDIR}/share/man/cat1/ diff --git a/src/cmd/test/TEST.csh b/src/cmd/test/TEST.csh new file mode 100755 index 0000000..ad2b452 --- /dev/null +++ b/src/cmd/test/TEST.csh @@ -0,0 +1,153 @@ +# @(#)TEST.csh 5.2 (Berkeley) 4/30/93 +# TEST.csh,v 1.3 1994/09/24 02:59:11 davidg Exp + +#alias t '/usr/src/bin/test/obj/test \!*; echo $status' +alias t '/bin/test \!*; echo $status' +#alias t '/u1/robin/progs/test/test \!*; echo $status' + +echo 't -b /dev/ttyp2' +t -b /dev/ttyp2 +echo 't -b /dev/jb1a' +t -b /dev/jb1a + +echo 't -c test.c' +t -c test.c +echo 't -c /dev/tty' +t -c /dev/tty + +echo 't -d test.c' +t -d test.c +echo 't -d /etc' +t -d /etc + +echo 't -e noexist' +t -e noexist +echo 't -e test.c' +t -e test.c + +echo 't -f noexist' +t -f noexist +echo 't -f /dev/tty' +t -f /dev/tty +echo 't -f test.c' +t -f test.c + +echo 't -g test.c' +t -g test.c +echo 't -g /bin/ps' +t -g /bin/ps + +echo 't -n ""' +t -n "" +echo 't -n "hello"' +t -n "hello" + +echo 't -p test.c' +t -p test.c + +echo 't -r noexist' +t -r noexist +echo 't -r /etc/master.passwd' +t -r /etc/master.passwd +echo 't -r test.c' +t -r test.c + +echo 't -s noexist' +t -s noexist +echo 't -s /dev/null' +t -s /dev/null +echo 't -s test.c' +t -s test.c + +echo 't -t 20' +t -t 20 +echo 't -t 0' +t -t 0 + +echo 't -u test.c' +t -u test.c +echo 't -u /bin/rcp' +t -u /bin/rcp + +echo 't -w noexist' +t -w noexist +echo 't -w /etc/master.passwd' +t -w /etc/master.passwd +echo 't -w /dev/null' +t -w /dev/null + +echo 't -x noexist' +t -x noexist +echo 't -x /bin/ps' +t -x /bin/ps +echo 't -x /etc/motd' +t -x /etc/motd + +echo 't -z ""' +t -z "" +echo 't -z "foo"' +t -z "foo" + +echo 't "foo"' +t "foo" +echo 't ""' +t "" + +echo 't "hello" = "hello"' +t "hello" = "hello" +echo 't "hello" = "goodbye"' +t "hello" = "goodbye" + +echo 't "hello" != "hello"' +t "hello" != "hello" +echo 't "hello" != "goodbye"' +t "hello" != "goodbye" + +echo 't 200 -eq 200' +t 200 -eq 200 +echo 't 34 -eq 222' +t 34 -eq 222 + +echo 't 200 -ne 200' +t 200 -ne 200 +echo 't 34 -ne 222' +t 34 -ne 222 + +echo 't 200 -gt 200' +t 200 -gt 200 +echo 't 340 -gt 222' +t 340 -gt 222 + +echo 't 200 -ge 200' +t 200 -ge 200 +echo 't 34 -ge 222' +t 34 -ge 222 + +echo 't 200 -lt 200' +t 200 -lt 200 +echo 't 34 -lt 222' +t 34 -lt 222 + +echo 't 200 -le 200' +t 200 -le 200 +echo 't 340 -le 222' +t 340 -le 222 + +echo 't 700 -le 1000 -a -n "1" -a "20" = "20"' +t 700 -le 1000 -a -n "1" -a "20" = "20" +echo 't ! \( 700 -le 1000 -a -n "1" -a "20" = "20" \)' +t ! \( 700 -le 1000 -a -n "1" -a "20" = "20" \) + +echo 't -5 -eq 5' +t -5 -eq 5 + + +echo 't foo -a ""' +t foo -a "" +echo 't "" -a foo' +t "" -a foo +echo 't "" -a ""' +t "" -a "" +echo 't "" -o ""' +t "" -o "" + diff --git a/src/cmd/test/operators.c b/src/cmd/test/operators.c new file mode 100644 index 0000000..af959a2 --- /dev/null +++ b/src/cmd/test/operators.c @@ -0,0 +1,158 @@ +/*- + * Copyright (c) 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * operators.c,v 1.3 1994/09/24 02:59:12 davidg Exp + */ + +#if defined(DOSCCS) & !defined(lint) +static char sccsid[] = "@(#)operators.c 8.3 (Berkeley) 4/2/94"; +#endif /* not lint */ + +/* + * Operators used in the test command. + */ + +#include + +#include "operators.h" + +char unary_op[][4] = { + "!", + "-b", + "-c", + "-d", + "-e", + "-f", + "-g", + "-h", + "-k", + "-n", + "-p", + "-r", + "-s", + "-t", + "-u", + "-w", + "-x", + "-z", + "ZZZ" +}; + +char binary_op[][4] = { + "-o", + "|", + "-a", + "&", + "=", + "!=", + "-eq", + "-ne", + "-gt", + "-lt", + "-le", + "-ge", + "ZZZ" +}; + +char andor_op[][4] = { + "-o", + "|", + "-a", + "&", + "ZZZ" +}; + +int op_priority[] = { + 3, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 1, + 1, + 2, + 2, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, +}; + +int op_argflag[] = { + 0, + OP_FILE, + OP_FILE, + OP_FILE, + OP_FILE, + OP_FILE, + OP_FILE, + OP_FILE, + OP_FILE, + OP_STRING, + OP_FILE, + OP_FILE, + OP_FILE, + OP_INT, + OP_FILE, + OP_FILE, + OP_FILE, + OP_STRING, + 0, + 0, + 0, + 0, + OP_STRING, + OP_STRING, + OP_INT, + OP_INT, + OP_INT, + OP_INT, + OP_INT, + OP_INT, +}; diff --git a/src/cmd/test/operators.h b/src/cmd/test/operators.h new file mode 100644 index 0000000..b5b6917 --- /dev/null +++ b/src/cmd/test/operators.h @@ -0,0 +1,73 @@ +/*- + * Copyright (c) 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)operators.h 8.3 (Berkeley) 4/2/94 + * operators.h,v 1.3 1994/09/24 02:59:13 davidg Exp + */ + +#define NOT 0 +#define ISBLOCK 1 +#define ISCHAR 2 +#define ISDIR 3 +#define ISEXIST 4 +#define ISFILE 5 +#define ISSETGID 6 +#define ISSYMLINK 7 +#define ISSTICKY 8 +#define STRLEN 9 +#define ISFIFO 10 +#define ISREAD 11 +#define ISSIZE 12 +#define ISTTY 13 +#define ISSETUID 14 +#define ISWRITE 15 +#define ISEXEC 16 +#define NULSTR 17 + +#define FIRST_BINARY_OP 18 +#define OR1 18 +#define OR2 19 +#define AND1 20 +#define AND2 21 +#define STREQ 22 +#define STRNE 23 +#define EQ 24 +#define NE 25 +#define GT 26 +#define LT 27 +#define LE 28 +#define GE 29 + + +#define OP_INT 1 /* arguments to operator are integer */ +#define OP_STRING 2 /* arguments to operator are string */ +#define OP_FILE 3 /* argument is a file name */ diff --git a/src/cmd/test/test.1 b/src/cmd/test/test.1 new file mode 100644 index 0000000..58d809d --- /dev/null +++ b/src/cmd/test/test.1 @@ -0,0 +1,284 @@ +.\" 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. +.\" +.\" @(#)test.1 8.1.2 (2.11BSD) 1995/03/13 +.\" test.1,v 1.2 1994/09/24 02:59:14 davidg Exp +.\" +.TH TEST 1 "March 13, 1995" +.AT 3 +.SH NAME +test \- condition evaluation utility +.SH SYNOPSIS +.B test +.I expression +.SH DESCRIPTION +The +.I test +utility evaluates the expression and, if it evaluates +to true, returns a zero (true) exit status; otherwise +it returns 1 (false). +If there is no expression, test also +returns 1 (false). +.PP +All operators and flags are separate arguments to the +.I test +utility. +.PP +The following primaries are used to construct expression: +.TP +\fB \-b \fP \fI file \fP +True if +.I file +exists and is a block special +file. +.TP +\fB \-c \fP \fI file \fP +True if +.I file +exists and is a character +special file. +.TP +\fB \-d \fP \fI file \fP +True if +.I file +exists and is a directory. +.TP +\fB \-e \fP \fI file \fP +True if +.I file +exists (regardless of type). +.TP +\fB \-f \fP \fI file \fP +True if +.I file +exists and is a regular file. +.TP +\fB \-g \fP \fI file \fP +True if +.I file +exists and its set group ID flag +is set. +.TP +\fB \-h \fP \fI file \fP +True if +.I file +exists and is a symbolic link. +.TP +\fB \-n \fP \fI string \fP +True if the length of +.I string +is nonzero. +.TP +\fB \-p \fP \fI file \fP +True if +.I file +is a named pipe +.Po Tn FIFO Pc . +.TP +\fB \-r \fP \fI file \fP +True if +.I file +exists and is readable. +.TP +\fB \-s \fP \fI file \fP +True if +.I file +exists and has a size greater +than zero. +.TP +\fB \-t \fp \fI [file_descriptor] \fP +True if the file whose file descriptor number +is +.I file_descriptor +(default 1) is open and is +associated with a terminal. +.TP +\fB \-u \fP \fI file \fP +True if +.I file +exists and its set user ID flag +is set. +.TP +\fB \-w \fP \fI file \fP +True if +.I file +exists and is writable. +True indicates only that the write flag is on. +The file is not writable on a read-only file +system even if this test indicates true. +.TP +\fB \-x \fP \fI file \fP +True if +.I file +exists and is executable. +True indicates only that the execute flag is on. +If +.I file +is a directory, true +indicates that +.I file +can be searched. +.TP +\fB \-z \fP \fI string \fP +True if the length of +.I string +is zero. +.TP +\fI string \fP +True if +.I string +is not the null +string. +.TP +\fI s1 \fP \fB = \fP \fI s2 \fP +True if the strings +.I s1 +and +.I s2 +are identical. +.TP +\fI s1 \fP \fB != \fP \fI s2 \fP +True if the strings +.I s1 +and +.I s2 +are not identical. +.TP +\fI n1 \fP \fB \-eq \fP \fI n2 \fP +True if the integers +.I n1 +and +.I n2 +are algebraically +equal. +.TP +\fI n1 \fP \fB \-ne \fP \fI n2 \fP +True if the integers +.I n1 +and +.I n2 +are not +algebraically equal. +.TP +\fI n1 \fP \fB \-gt \fP \fI n2 \fP +True if the integer +.I n1 +is algebraically +greater than the integer +.I n2 . +.TP +\fI n1 \fP \fB \-ge \fP \fI n2 \fP +True if the integer +.I n1 +is algebraically +greater than or equal to the integer +.I n2 . +.TP +\fI n1 \fP \fB \-lt \fP \fI n2 \fP +True if the integer +.I n1 +is algebraically less +than the integer +.I n2 . +.TP +\fI n1 \fP \fB \-le \fP \fI n2 \fP +True if the integer +.I n1 +is algebraically less +than or equal to the integer +.I n2 . +.TP +.PP +These primaries can be combined with the following operators: +.TP +.B ! expression +True if +.I expression +is false. +.TP +\fI expression1 \fP \fB \-a \fP \fI expression2 \fP +True if both +.I expression1 +and +.I expression2 +are true. +.TP +\fI expression1 \fP \fB \-o \fP \fI expression2 \fP +True if either +.I expression1 +or +.I expression2 +are true. +.TP +\fI (expression) \fP +True if expression is true. +.TP +.PP +The +.B \-a +operator has higher precedence than the +.B \-o +operator. +.SH GRAMMAR AMBIGUITY +The +.B test +grammar is inherently ambiguous. In order to assure a degree of consistency, +the cases described in the +IEEE Std 1003.2 ("POSIX"), +section D11.2/4.62.4, standard +are evaluated consistently according to the rules specified in the +standards document. All other cases are subject to the ambiguity in the +command semantics. +.SH RETURN VALUES +The +.B test +utility exits with one of the following values: +.TP +.B 0 +expression evaluated to true. +.TP +.B 1 +expression evaluated to false or expression was +missing. +.TP +.B >1 +An error occurred. +.SH BUGS +Named pipes are not implemented in 2.11BSD. +.SH STANDARDS +The +.B test +function is expected to be +IEEE Std 1003.2 ("POSIX") +compatible. diff --git a/src/cmd/test/test.c b/src/cmd/test/test.c new file mode 100644 index 0000000..038a7b2 --- /dev/null +++ b/src/cmd/test/test.c @@ -0,0 +1,558 @@ +/*- + * 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 + * Kenneth Almquist. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "operators.h" + +#define STACKSIZE 12 +#define NESTINCR 16 + +/* data types */ +#define STRING 0 +#define INTEGER 1 +#define BOOLEAN 2 + +#define IS_BANG(s) (s[0] == '!' && s[1] == '\0') + +/* + * This structure hold a value. The type keyword specifies the type of + * the value, and the union u holds the value. The value of a boolean + * is stored in u.num (1 = TRUE, 0 = FALSE). + */ +struct value { + int type; + union { + char *string; + long num; + } u; +}; + +struct operator { + short op; /* Which operator. */ + short pri; /* Priority of operator. */ +}; + +struct filestat { + char *name; /* Name of file. */ + int rcode; /* Return code from stat. */ + struct stat stat; /* Status info on file. */ +}; + +extern char unary_op[][4]; +extern char binary_op[][4]; +extern char andor_op[][4]; +extern int op_priority[]; +extern int op_argflag[]; +extern long atol(); + +/* + * Execute an operator. Op is the operator. Sp is the stack pointer; + * sp[0] refers to the first operand, sp[1] refers to the second operand + * (if any), and the result is placed in sp[0]. The operands are converted + * to the type expected by the operator before expr_operator is called. + * Fs is a pointer to a structure which holds the value of the last call + * to stat, to avoid repeated stat calls on the same file. + */ +void +expr_operator(op, sp, fs) + int op; + register struct value *sp; + struct filestat *fs; +{ + register int i; + + switch (op) { + case NOT: + sp->u.num = expr_is_false(sp); + sp->type = BOOLEAN; + break; + case ISEXIST: +exist: + if (fs == NULL || fs->rcode == -1) + goto false; + else + goto true; + case ISREAD: + if (geteuid() == 0) + goto exist; + i = S_IROTH; + goto permission; + case ISWRITE: + if (geteuid() != 0) + i = S_IWOTH; + else { + i = S_IWOTH|S_IWGRP|S_IWUSR; + goto filebit; + } + goto permission; + case ISEXEC: + if (geteuid() != 0) { + i = S_IXOTH; +permission: if (fs->stat.st_uid == geteuid()) + i <<= 6; + else { + gid_t grlist[NGROUPS]; + int ngroups, j; + + ngroups = getgroups(NGROUPS, grlist); + for (j = 0; j < ngroups; j++) + if (fs->stat.st_gid == grlist[j]) { + i <<= 3; + goto filebit; + } + } + } else + i = S_IXOTH|S_IXGRP|S_IXUSR; + goto filebit; /* true if (stat.st_mode & i) != 0 */ + case ISFILE: + i = S_IFREG; + goto filetype; + case ISDIR: + i = S_IFDIR; + goto filetype; + case ISCHAR: + i = S_IFCHR; + goto filetype; + case ISBLOCK: + i = S_IFBLK; + goto filetype; + case ISSYMLINK: + i = S_IFLNK; + (void)lstat(sp->u.string, &fs->stat); + goto filetype; + case ISFIFO: + i = S_IFIFO; + goto filetype; +filetype: if ((fs->stat.st_mode & S_IFMT) == i && fs->rcode >= 0) +true: sp->u.num = 1; + else +false: sp->u.num = 0; + sp->type = BOOLEAN; + break; + case ISSETUID: + i = S_ISUID; + goto filebit; + case ISSETGID: + i = S_ISGID; + goto filebit; + case ISSTICKY: + i = S_ISVTX; +filebit: if (fs->stat.st_mode & i && fs->rcode >= 0) + goto true; + goto false; + case ISSIZE: + sp->u.num = fs->rcode >= 0 ? fs->stat.st_size : 0L; + sp->type = INTEGER; + break; + case ISTTY: + sp->u.num = isatty(sp->u.num); + sp->type = BOOLEAN; + break; + case NULSTR: + if (sp->u.string[0] == '\0') + goto true; + goto false; + case STRLEN: + sp->u.num = strlen(sp->u.string); + sp->type = INTEGER; + break; + case OR1: + case AND1: + /* + * These operators are mostly handled by the parser. If we + * get here it means that both operands were evaluated, so + * the value is the value of the second operand. + */ + *sp = *(sp + 1); + break; + case STREQ: + case STRNE: + i = 0; + if (!strcmp(sp->u.string, (sp + 1)->u.string)) + i++; + if (op == STRNE) + i = 1 - i; + sp->u.num = i; + sp->type = BOOLEAN; + break; + case EQ: + if (sp->u.num == (sp + 1)->u.num) + goto true; + goto false; + case NE: + if (sp->u.num != (sp + 1)->u.num) + goto true; + goto false; + case GT: + if (sp->u.num > (sp + 1)->u.num) + goto true; + goto false; + case LT: + if (sp->u.num < (sp + 1)->u.num) + goto true; + goto false; + case LE: + if (sp->u.num <= (sp + 1)->u.num) + goto true; + goto false; + case GE: + if (sp->u.num >= (sp + 1)->u.num) + goto true; + goto false; + + } +} + +/* + * Integer type checking. + */ +void +get_int(v, lp) + register char *v; + long *lp; +{ + + for (; *v && isspace(*v); ++v); + + if(!*v) { + *lp = 0; + return; + } + + if (isdigit(*v) || ((*v == '-' || *v == '+') && isdigit(*(v+1)))) { + *lp = atol(v); + return; + } + errx(2, "%s: expected integer", v); +} + +void +syntax() +{ + err(2, "syntax error"); +} + +void +overflow() +{ + err(2, "expression is too complex"); +} + +main(argc, argv) + int argc; + char *argv[]; +{ + + struct operator opstack[STACKSIZE]; + register struct operator *opsp; + struct value valstack[STACKSIZE + 1]; + register struct value *valsp; + struct filestat fs; + char c, **ap, *opname, *p; + int binary, nest, op, pri, ret_val, skipping; + + if ((p = argv[0]) == NULL) + errx(2, "test: argc is zero"); + + if (*p != '\0' && p[strlen(p) - 1] == '[') { + if (strcmp(argv[--argc], "]")) + errx(2, "missing ]"); + argv[argc] = NULL; + } + ap = argv + 1; + fs.name = NULL; + + /* + * Test(1) implements an inherently ambiguous grammer. In order to + * assure some degree of consistency, we special case the POSIX 1003.2 + * requirements to assure correct evaluation for POSIX scripts. The + * following special cases comply with POSIX P1003.2/D11.2 Section + * 4.62.4. + */ + switch(argc - 1) { + case 0: /* % test */ + return (1); + break; + case 1: /* % test arg */ + return (argv[1] == NULL || *argv[1] == '\0') ? 1 : 0; + break; + case 2: /* % test op arg */ + opname = argv[1]; + if (IS_BANG(opname)) + return (*argv[2] == '\0') ? 0 : 1; + else { + ret_val = posix_unary_op(&argv[1]); + if (ret_val >= 0) + return (ret_val); + } + break; + case 3: /* % test arg1 op arg2 */ + if (IS_BANG(argv[1])) { + ret_val = posix_unary_op(&argv[1]); + if (ret_val >= 0) + return (!ret_val); + } else { + ret_val = posix_binary_op(&argv[1]); + if (ret_val >= 0) + return (ret_val); + } + break; + case 4: /* % test ! arg1 op arg2 */ + if (IS_BANG(argv[1]) && lookup_op(argv[3], andor_op) < 0 ) { + ret_val = posix_binary_op(&argv[2]); + if (ret_val >= 0) + return (!ret_val); + } + break; + default: + break; + } + + /* + * We use operator precedence parsing, evaluating the expression as + * we parse it. Parentheses are handled by bumping up the priority + * of operators using the variable "nest." We use the variable + * "skipping" to turn off evaluation temporarily for the short + * circuit boolean operators. (It is important do the short circuit + * evaluation because under NFS a stat operation can take infinitely + * long.) + */ + opsp = opstack + STACKSIZE; + valsp = valstack; + nest = skipping = 0; + if (*ap == NULL) { + valstack[0].type = BOOLEAN; + valstack[0].u.num = 0; + goto done; + } + for (;;) { + opname = *ap++; + if (opname == NULL) + syntax(); + if (opname[0] == '(' && opname[1] == '\0') { + nest += NESTINCR; + continue; + } else if (*ap && (op = lookup_op(opname, unary_op)) >= 0) { + if (opsp == &opstack[0]) + overflow(); + --opsp; + opsp->op = op; + opsp->pri = op_priority[op] + nest; + continue; + } else { + valsp->type = STRING; + valsp->u.string = opname; + valsp++; + } + for (;;) { + opname = *ap++; + if (opname == NULL) { + if (nest != 0) + syntax(); + pri = 0; + break; + } + if (opname[0] != ')' || opname[1] != '\0') { + if ((op = lookup_op(opname, binary_op)) < 0) + syntax(); + op += FIRST_BINARY_OP; + pri = op_priority[op] + nest; + break; + } + if ((nest -= NESTINCR) < 0) + syntax(); + } + while (opsp < &opstack[STACKSIZE] && opsp->pri >= pri) { + binary = opsp->op; + for (;;) { + valsp--; + c = op_argflag[opsp->op]; + if (c == OP_INT) { + if (valsp->type == STRING) + get_int(valsp->u.string, + &valsp->u.num); + valsp->type = INTEGER; + } else if (c >= OP_STRING) { + /* OP_STRING or OP_FILE */ + if (valsp->type == INTEGER) { + if ((p = (char *)malloc(32)) == NULL) + err(2, NULL); +#ifdef SHELL + fmtstr(p, 32, "%d", + valsp->u.num); +#else + (void)sprintf(p, + "%d", valsp->u.num); +#endif + valsp->u.string = p; + } else if (valsp->type == BOOLEAN) { + if (valsp->u.num) + valsp->u.string = + "true"; + else + valsp->u.string = ""; + } + valsp->type = STRING; + if (c == OP_FILE && (fs.name == NULL || + strcmp(fs.name, valsp->u.string))) { + fs.name = valsp->u.string; + fs.rcode = + stat(valsp->u.string, + &fs.stat); + } + } + if (binary < FIRST_BINARY_OP) + break; + binary = 0; + } + if (!skipping) + expr_operator(opsp->op, valsp, &fs); + else if (opsp->op == AND1 || opsp->op == OR1) + skipping--; + valsp++; /* push value */ + opsp++; /* pop operator */ + } + if (opname == NULL) + break; + if (opsp == &opstack[0]) + overflow(); + if (op == AND1 || op == AND2) { + op = AND1; + if (skipping || expr_is_false(valsp - 1)) + skipping++; + } + if (op == OR1 || op == OR2) { + op = OR1; + if (skipping || !expr_is_false(valsp - 1)) + skipping++; + } + opsp--; + opsp->op = op; + opsp->pri = pri; + } +done: return (expr_is_false(&valstack[0])); +} + +int +expr_is_false(val) + register struct value *val; +{ + + if (val->type == STRING) { + if (val->u.string[0] == '\0') + return (1); + } else { /* INTEGER or BOOLEAN */ + if (val->u.num == 0) + return (1); + } + return (0); +} + +int +lookup_op(name, table) + char *name; + char *table; +{ + char *tp; + char c; + int i; + + c = name[1]; + tp = table; + for(i = 0; strcmp((char *)(tp + i),"ZZZ") ; i=i+4){ + if ((char)(tp + i)[1] == c && !strcmp((char *)(tp + i), name)) + return (i/4); + } + return (-1); +} + +int +posix_unary_op(argv) + char **argv; +{ + struct filestat fs; + struct value valp; + int op, c; + char *opname; + + opname = *argv; + if ((op = lookup_op(opname, unary_op)) < 0) + return (-1); + c = op_argflag[op]; + opname = argv[1]; + valp.u.string = opname; + if (c == OP_FILE) { + fs.name = opname; + fs.rcode = stat(opname, &fs.stat); + } else if (c != OP_STRING) + return (-1); + + expr_operator(op, &valp, &fs); + return (valp.u.num == 0); +} + +int +posix_binary_op(argv) + char **argv; +{ + struct value v[2]; + int op, c; + char *opname; + + opname = argv[1]; + if ((op = lookup_op(opname, binary_op)) < 0) + return (-1); + op += FIRST_BINARY_OP; + c = op_argflag[op]; + + if (c == OP_INT) { + get_int(argv[0], &v[0].u.num); + get_int(argv[2], &v[1].u.num); + } else { + v[0].u.string = argv[0]; + v[1].u.string = argv[2]; + } + expr_operator(op, v, NULL); + return (v[0].u.num == 0); +} diff --git a/src/cmd/time.c b/src/cmd/time.c new file mode 100644 index 0000000..f87a494 --- /dev/null +++ b/src/cmd/time.c @@ -0,0 +1,57 @@ +/* + * time + */ +#include +#include +#include +#include +#include +#include + +main(argc, argv) + int argc; + char **argv; +{ + int status; + register int p; + struct timeval before, after; + struct rusage ru; + + if (argc<=1) + exit(0); + gettimeofday(&before, 0); + p = fork(); + if (p < 0) { + perror("time"); + exit(1); + } + if (p == 0) { + execvp(argv[1], &argv[1]); + perror(argv[1]); + exit(1); + } + signal(SIGINT, SIG_IGN); + signal(SIGQUIT, SIG_IGN); + while (wait3(&status, 0, &ru) != p) + ; + gettimeofday(&after, 0); + if ((status&0377) != 0) + 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; + printt("real", &after); + printt("user", &ru.ru_utime); + printt("sys ", &ru.ru_stime); + fprintf(stderr, "\n"); + exit (status>>8); +} + +printt(s, tv) + char *s; + struct timeval *tv; +{ + + fprintf(stderr, "%9ld.%01ld %s ", tv->tv_sec, tv->tv_usec/100000, s); +} diff --git a/src/cmd/tip/Makefile b/src/cmd/tip/Makefile new file mode 100644 index 0000000..bbccde6 --- /dev/null +++ b/src/cmd/tip/Makefile @@ -0,0 +1,103 @@ +TOPSRC = $(shell cd ../../..; pwd) +include $(TOPSRC)/target.mk + +# +# Copyright (c) 1987 Regents of the University of California. +# All rights reserved. The Berkeley software License Agreement +# specifies the terms and conditions for redistribution. +# +# @(#)Makefile 5.4.1 (2.11BSD) 1996/12/1 +# +# make file for intermachine communications package +# +# Files are: +# /etc/remote remote host description file +# /etc/phones phone number file, owned by ${OWNER} and +# mode 6?? +# ${ADM}/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 +# PENRIL autodialer +# USR COURIER (2400 baud) +# VENTEL 212+ +# VADIC 831 RS232 adaptor +# VADIC 3451 +# (drivers are located in aculib.a) +# +# Configuration defines: +# DF02, DF03, DN11 ACU's supported +# BIZ1031, BIZ1022, VENTEL, V831, V3451, HAYES, COURIER, PENRIL +# 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 +ADM = var/log +OWNER = uucp +GROUP = daemon +CONFIG = -DHAYES +LIBS += -lacu -L./aculib +CFLAGS += -DDEFBR=1200 -DDEFFS=BUFSIZ -DACULOG -DPRISTINE -Wall -Werror +SRCS = acu.c acutab.c cmds.c cmdtab.c cu.c hunt.c log.c partab.c remcap.c \ + remote.c tip.c tipout.c uucplock.c value.c vars.c +OBJS = acu.o acutab.o cmds.o cmdtab.o cu.o hunt.o log.o partab.o remcap.o \ + remote.o tip.o tipout.o uucplock.o value.o vars.o + +all: aculib tip + +tip: ${OBJS} + ${CC} ${LDFLAGS} -o tip.elf ${OBJS} ${LIBS} + ${OBJDUMP} -S tip.elf > tip.dis + ${SIZE} tip.elf + ${ELF2AOUT} tip.elf $@ + +# acutab is configuration dependent, and so depends on the makefile +acutab.o: Makefile +acutab.o: acutab.c + ${CC} -c ${CFLAGS} ${CONFIG} acutab.c + +# remote.o depends on the makefile because of DEFBR and DEFFS +# log.o depends on the makefile because of ACULOG +log.o remote.o: Makefile + +aculib: FRC + cd aculib; make ${MFLAGS} + +clean: FRC + rm -f ${OBJS} core tip tip.elf tip.dis + cd aculib; make ${MFLAGS} clean + +depend: FRC + mkdep ${CFLAGS} ${SRCS} + cd aculib; make ${MFLAGS} depend + +install: aculib tip + cd aculib; make ${MFLAGS} install + cp tip ${DESTDIR}/bin/tip + rm -f ${DESTDIR}/bin/cu + touch ${DESTDIR}/${ADM}/aculog + chmod 600 ${DESTDIR}/${ADM}/aculog + -mkdir -p ${DESTDIR}/var/lock + @echo "create /etc/remote and /etc/phones" + cp remote-file ${DESTDIR}/etc/remote + cp phones-file ${DESTDIR}/etc/phones + +lint: FRC + lint ${CFLAGS} ${SRCS} + +tags: FRC + ctags ${SRCS} + +FRC: + +# DO NOT DELETE THIS LINE -- mkdep uses it. +# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY. + +# IF YOU PUT ANYTHING HERE IT WILL GO AWAY diff --git a/src/cmd/tip/README b/src/cmd/tip/README new file mode 100644 index 0000000..a6bb99b --- /dev/null +++ b/src/cmd/tip/README @@ -0,0 +1,61 @@ +Tip can be configured in a number of ways: + +ACU's: +----- + +ACU Define in makefile +-------------------- --------------- +BIZCOMP 1022, 1031 BIZ1022, BIZ1031 +DEC DF02-AC, DF03-AC DF02, DF03 +DEC DN-11/Able Quadracall DN11 +Ventel VENTEL +Vadic 831 V831 + +New ACU's may be added by editing the ACU description table +in acutab.c and writing a ``driver''. + +ACU usage can be monitored by defining ACULOG in the makefile. +If this is done and no phone numbers should appear in the +log file, define PRISTINE in the makefile. + +Variables: +--------- + +Tip's internal workings revolve around a set of (possibly) +user defined variables. These are statically initialized +in vars.c, and from the remote file. + +Note that adding or deleting variables requires tip to be completedly +recompiled, as indexes into the variable table are used to avoid +expensive lookups. These defines are set in tip.h. + +Commands: +-------- + +The command dispatch table is defined in cmdtab.c. Commands +may have attributes such as EXPerimental and PRIVileged (only +root may execute). + + + +-------------------------------------------------------------------------- + +Recent changes about Jan 82 + +A new, improved version of tip is now available. The most important +addition is the capacility to specify a phone number with tip. The +default baud rate is 1200. To use it do: + + tip phone-number +or + tip -300 phone-number + +for 300 baud. + +A ~^Z command has been added to tip as well. + +A new cu program is available that interfaces to the tip program. +It attempts to give the same user interface as cu but it is really +the tip program so you have all the advantages of tip. This allows +cu (actually tip) to search for a free ACU instead of having the +user specify which one he wants. diff --git a/src/cmd/tip/TODO b/src/cmd/tip/TODO new file mode 100644 index 0000000..8d52247 --- /dev/null +++ b/src/cmd/tip/TODO @@ -0,0 +1,18 @@ +1. Rethink protection glitches on REMOTE & PHONES + files (setuid/setgid??). + +2. Make clean fix for scripting being set in .tiprc + +3. change EOFREAD to recognize more general strings. + +4. add an option that returns an exit status based on + whether resources for the requested operation are available. + +5. write a program to list known systems (a quick shell script + should do it); people keep forgetting the names. + +6. change remote file descriptions so that acu attributes are + are attached to a device so that several different devices + can be used to get to the same system (perhaps hardwired + and phone line). got any ideas here? I'm looking at something + like dv=cua1,cul1,dn11;cua2,,df03. diff --git a/src/cmd/tip/acu.c b/src/cmd/tip/acu.c new file mode 100644 index 0000000..3beeb74 --- /dev/null +++ b/src/cmd/tip/acu.c @@ -0,0 +1,162 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "tip.h" + +static acu_t *acu = NOACU; +static int conflag; +static acu_t *acutype(); +static jmp_buf jmpbuf; + +static void +acuabort(int s) +{ + signal(s, SIG_IGN); + longjmp(jmpbuf, 1); +} + +/* + * 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'; + + conflag = (*acu->acu_dialer)(phnum, CU); + if (conflag) { + 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'; + + conflag = (*acu->acu_dialer)(phnum, CU); + if (conflag) { + fclose(fd); + 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"); +} + +void 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 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/src/cmd/tip/aculib/.depend b/src/cmd/tip/aculib/.depend new file mode 100644 index 0000000..6f4c4fb --- /dev/null +++ b/src/cmd/tip/aculib/.depend @@ -0,0 +1,552 @@ +biz22.o: biz22.c ../tip.h /usr/include/i386-linux-gnu/sys/types.h \ + /usr/include/features.h /usr/include/i386-linux-gnu/bits/predefs.h \ + /usr/include/i386-linux-gnu/sys/cdefs.h \ + /usr/include/i386-linux-gnu/bits/wordsize.h \ + /usr/include/i386-linux-gnu/gnu/stubs.h \ + /usr/include/i386-linux-gnu/gnu/stubs-32.h \ + /usr/include/i386-linux-gnu/bits/types.h \ + /usr/include/i386-linux-gnu/bits/typesizes.h /usr/include/time.h \ + /usr/lib/gcc/i686-linux-gnu/4.6.1/include/stddef.h /usr/include/endian.h \ + /usr/include/i386-linux-gnu/bits/endian.h \ + /usr/include/i386-linux-gnu/bits/byteswap.h \ + /usr/include/i386-linux-gnu/sys/select.h \ + /usr/include/i386-linux-gnu/bits/select.h \ + /usr/include/i386-linux-gnu/bits/sigset.h \ + /usr/include/i386-linux-gnu/bits/time.h \ + /usr/include/i386-linux-gnu/sys/sysmacros.h \ + /usr/include/i386-linux-gnu/bits/pthreadtypes.h \ + /usr/include/i386-linux-gnu/sys/file.h /usr/include/fcntl.h \ + /usr/include/i386-linux-gnu/bits/fcntl.h \ + /usr/include/i386-linux-gnu/bits/stat.h \ + /usr/include/i386-linux-gnu/bits/fcntl2.h /usr/include/sgtty.h \ + /usr/include/i386-linux-gnu/sys/ioctl.h \ + /usr/include/i386-linux-gnu/bits/ioctls.h \ + /usr/include/i386-linux-gnu/asm/ioctls.h \ + /usr/include/asm-generic/ioctls.h /usr/include/linux/ioctl.h \ + /usr/include/i386-linux-gnu/asm/ioctl.h /usr/include/asm-generic/ioctl.h \ + /usr/include/i386-linux-gnu/bits/ioctl-types.h \ + /usr/include/i386-linux-gnu/sys/ttydefaults.h /usr/include/signal.h \ + /usr/include/i386-linux-gnu/bits/signum.h \ + /usr/include/i386-linux-gnu/bits/siginfo.h \ + /usr/include/i386-linux-gnu/bits/sigaction.h \ + /usr/include/i386-linux-gnu/bits/sigcontext.h \ + /usr/include/i386-linux-gnu/asm/sigcontext.h /usr/include/linux/types.h \ + /usr/include/i386-linux-gnu/asm/types.h /usr/include/asm-generic/types.h \ + /usr/include/asm-generic/int-ll64.h \ + /usr/include/i386-linux-gnu/asm/bitsperlong.h \ + /usr/include/asm-generic/bitsperlong.h /usr/include/linux/posix_types.h \ + /usr/include/linux/stddef.h \ + /usr/include/i386-linux-gnu/asm/posix_types.h \ + /usr/include/i386-linux-gnu/asm/posix_types_32.h \ + /usr/include/i386-linux-gnu/bits/sigstack.h \ + /usr/include/i386-linux-gnu/sys/ucontext.h \ + /usr/include/i386-linux-gnu/bits/sigthread.h /usr/include/stdio.h \ + /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \ + /usr/lib/gcc/i686-linux-gnu/4.6.1/include/stdarg.h \ + /usr/include/i386-linux-gnu/bits/stdio_lim.h \ + /usr/include/i386-linux-gnu/bits/sys_errlist.h \ + /usr/include/i386-linux-gnu/bits/stdio.h \ + /usr/include/i386-linux-gnu/bits/stdio2.h /usr/include/pwd.h \ + /usr/include/ctype.h /usr/include/xlocale.h /usr/include/setjmp.h \ + /usr/include/i386-linux-gnu/bits/setjmp.h \ + /usr/include/i386-linux-gnu/bits/setjmp2.h /usr/include/errno.h \ + /usr/include/i386-linux-gnu/bits/errno.h /usr/include/linux/errno.h \ + /usr/include/i386-linux-gnu/asm/errno.h /usr/include/asm-generic/errno.h \ + /usr/include/asm-generic/errno-base.h +biz31.o: biz31.c ../tip.h /usr/include/i386-linux-gnu/sys/types.h \ + /usr/include/features.h /usr/include/i386-linux-gnu/bits/predefs.h \ + /usr/include/i386-linux-gnu/sys/cdefs.h \ + /usr/include/i386-linux-gnu/bits/wordsize.h \ + /usr/include/i386-linux-gnu/gnu/stubs.h \ + /usr/include/i386-linux-gnu/gnu/stubs-32.h \ + /usr/include/i386-linux-gnu/bits/types.h \ + /usr/include/i386-linux-gnu/bits/typesizes.h /usr/include/time.h \ + /usr/lib/gcc/i686-linux-gnu/4.6.1/include/stddef.h /usr/include/endian.h \ + /usr/include/i386-linux-gnu/bits/endian.h \ + /usr/include/i386-linux-gnu/bits/byteswap.h \ + /usr/include/i386-linux-gnu/sys/select.h \ + /usr/include/i386-linux-gnu/bits/select.h \ + /usr/include/i386-linux-gnu/bits/sigset.h \ + /usr/include/i386-linux-gnu/bits/time.h \ + /usr/include/i386-linux-gnu/sys/sysmacros.h \ + /usr/include/i386-linux-gnu/bits/pthreadtypes.h \ + /usr/include/i386-linux-gnu/sys/file.h /usr/include/fcntl.h \ + /usr/include/i386-linux-gnu/bits/fcntl.h \ + /usr/include/i386-linux-gnu/bits/stat.h \ + /usr/include/i386-linux-gnu/bits/fcntl2.h /usr/include/sgtty.h \ + /usr/include/i386-linux-gnu/sys/ioctl.h \ + /usr/include/i386-linux-gnu/bits/ioctls.h \ + /usr/include/i386-linux-gnu/asm/ioctls.h \ + /usr/include/asm-generic/ioctls.h /usr/include/linux/ioctl.h \ + /usr/include/i386-linux-gnu/asm/ioctl.h /usr/include/asm-generic/ioctl.h \ + /usr/include/i386-linux-gnu/bits/ioctl-types.h \ + /usr/include/i386-linux-gnu/sys/ttydefaults.h /usr/include/signal.h \ + /usr/include/i386-linux-gnu/bits/signum.h \ + /usr/include/i386-linux-gnu/bits/siginfo.h \ + /usr/include/i386-linux-gnu/bits/sigaction.h \ + /usr/include/i386-linux-gnu/bits/sigcontext.h \ + /usr/include/i386-linux-gnu/asm/sigcontext.h /usr/include/linux/types.h \ + /usr/include/i386-linux-gnu/asm/types.h /usr/include/asm-generic/types.h \ + /usr/include/asm-generic/int-ll64.h \ + /usr/include/i386-linux-gnu/asm/bitsperlong.h \ + /usr/include/asm-generic/bitsperlong.h /usr/include/linux/posix_types.h \ + /usr/include/linux/stddef.h \ + /usr/include/i386-linux-gnu/asm/posix_types.h \ + /usr/include/i386-linux-gnu/asm/posix_types_32.h \ + /usr/include/i386-linux-gnu/bits/sigstack.h \ + /usr/include/i386-linux-gnu/sys/ucontext.h \ + /usr/include/i386-linux-gnu/bits/sigthread.h /usr/include/stdio.h \ + /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \ + /usr/lib/gcc/i686-linux-gnu/4.6.1/include/stdarg.h \ + /usr/include/i386-linux-gnu/bits/stdio_lim.h \ + /usr/include/i386-linux-gnu/bits/sys_errlist.h \ + /usr/include/i386-linux-gnu/bits/stdio.h \ + /usr/include/i386-linux-gnu/bits/stdio2.h /usr/include/pwd.h \ + /usr/include/ctype.h /usr/include/xlocale.h /usr/include/setjmp.h \ + /usr/include/i386-linux-gnu/bits/setjmp.h \ + /usr/include/i386-linux-gnu/bits/setjmp2.h /usr/include/errno.h \ + /usr/include/i386-linux-gnu/bits/errno.h /usr/include/linux/errno.h \ + /usr/include/i386-linux-gnu/asm/errno.h /usr/include/asm-generic/errno.h \ + /usr/include/asm-generic/errno-base.h +courier.o: courier.c ../tip.h /usr/include/i386-linux-gnu/sys/types.h \ + /usr/include/features.h /usr/include/i386-linux-gnu/bits/predefs.h \ + /usr/include/i386-linux-gnu/sys/cdefs.h \ + /usr/include/i386-linux-gnu/bits/wordsize.h \ + /usr/include/i386-linux-gnu/gnu/stubs.h \ + /usr/include/i386-linux-gnu/gnu/stubs-32.h \ + /usr/include/i386-linux-gnu/bits/types.h \ + /usr/include/i386-linux-gnu/bits/typesizes.h /usr/include/time.h \ + /usr/lib/gcc/i686-linux-gnu/4.6.1/include/stddef.h /usr/include/endian.h \ + /usr/include/i386-linux-gnu/bits/endian.h \ + /usr/include/i386-linux-gnu/bits/byteswap.h \ + /usr/include/i386-linux-gnu/sys/select.h \ + /usr/include/i386-linux-gnu/bits/select.h \ + /usr/include/i386-linux-gnu/bits/sigset.h \ + /usr/include/i386-linux-gnu/bits/time.h \ + /usr/include/i386-linux-gnu/sys/sysmacros.h \ + /usr/include/i386-linux-gnu/bits/pthreadtypes.h \ + /usr/include/i386-linux-gnu/sys/file.h /usr/include/fcntl.h \ + /usr/include/i386-linux-gnu/bits/fcntl.h \ + /usr/include/i386-linux-gnu/bits/stat.h \ + /usr/include/i386-linux-gnu/bits/fcntl2.h /usr/include/sgtty.h \ + /usr/include/i386-linux-gnu/sys/ioctl.h \ + /usr/include/i386-linux-gnu/bits/ioctls.h \ + /usr/include/i386-linux-gnu/asm/ioctls.h \ + /usr/include/asm-generic/ioctls.h /usr/include/linux/ioctl.h \ + /usr/include/i386-linux-gnu/asm/ioctl.h /usr/include/asm-generic/ioctl.h \ + /usr/include/i386-linux-gnu/bits/ioctl-types.h \ + /usr/include/i386-linux-gnu/sys/ttydefaults.h /usr/include/signal.h \ + /usr/include/i386-linux-gnu/bits/signum.h \ + /usr/include/i386-linux-gnu/bits/siginfo.h \ + /usr/include/i386-linux-gnu/bits/sigaction.h \ + /usr/include/i386-linux-gnu/bits/sigcontext.h \ + /usr/include/i386-linux-gnu/asm/sigcontext.h /usr/include/linux/types.h \ + /usr/include/i386-linux-gnu/asm/types.h /usr/include/asm-generic/types.h \ + /usr/include/asm-generic/int-ll64.h \ + /usr/include/i386-linux-gnu/asm/bitsperlong.h \ + /usr/include/asm-generic/bitsperlong.h /usr/include/linux/posix_types.h \ + /usr/include/linux/stddef.h \ + /usr/include/i386-linux-gnu/asm/posix_types.h \ + /usr/include/i386-linux-gnu/asm/posix_types_32.h \ + /usr/include/i386-linux-gnu/bits/sigstack.h \ + /usr/include/i386-linux-gnu/sys/ucontext.h \ + /usr/include/i386-linux-gnu/bits/sigthread.h /usr/include/stdio.h \ + /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \ + /usr/lib/gcc/i686-linux-gnu/4.6.1/include/stdarg.h \ + /usr/include/i386-linux-gnu/bits/stdio_lim.h \ + /usr/include/i386-linux-gnu/bits/sys_errlist.h \ + /usr/include/i386-linux-gnu/bits/stdio.h \ + /usr/include/i386-linux-gnu/bits/stdio2.h /usr/include/pwd.h \ + /usr/include/ctype.h /usr/include/xlocale.h /usr/include/setjmp.h \ + /usr/include/i386-linux-gnu/bits/setjmp.h \ + /usr/include/i386-linux-gnu/bits/setjmp2.h /usr/include/errno.h \ + /usr/include/i386-linux-gnu/bits/errno.h /usr/include/linux/errno.h \ + /usr/include/i386-linux-gnu/asm/errno.h /usr/include/asm-generic/errno.h \ + /usr/include/asm-generic/errno-base.h \ + /usr/include/i386-linux-gnu/sys/time.h +df.o: df.c ../tip.h /usr/include/i386-linux-gnu/sys/types.h \ + /usr/include/features.h /usr/include/i386-linux-gnu/bits/predefs.h \ + /usr/include/i386-linux-gnu/sys/cdefs.h \ + /usr/include/i386-linux-gnu/bits/wordsize.h \ + /usr/include/i386-linux-gnu/gnu/stubs.h \ + /usr/include/i386-linux-gnu/gnu/stubs-32.h \ + /usr/include/i386-linux-gnu/bits/types.h \ + /usr/include/i386-linux-gnu/bits/typesizes.h /usr/include/time.h \ + /usr/lib/gcc/i686-linux-gnu/4.6.1/include/stddef.h /usr/include/endian.h \ + /usr/include/i386-linux-gnu/bits/endian.h \ + /usr/include/i386-linux-gnu/bits/byteswap.h \ + /usr/include/i386-linux-gnu/sys/select.h \ + /usr/include/i386-linux-gnu/bits/select.h \ + /usr/include/i386-linux-gnu/bits/sigset.h \ + /usr/include/i386-linux-gnu/bits/time.h \ + /usr/include/i386-linux-gnu/sys/sysmacros.h \ + /usr/include/i386-linux-gnu/bits/pthreadtypes.h \ + /usr/include/i386-linux-gnu/sys/file.h /usr/include/fcntl.h \ + /usr/include/i386-linux-gnu/bits/fcntl.h \ + /usr/include/i386-linux-gnu/bits/stat.h \ + /usr/include/i386-linux-gnu/bits/fcntl2.h /usr/include/sgtty.h \ + /usr/include/i386-linux-gnu/sys/ioctl.h \ + /usr/include/i386-linux-gnu/bits/ioctls.h \ + /usr/include/i386-linux-gnu/asm/ioctls.h \ + /usr/include/asm-generic/ioctls.h /usr/include/linux/ioctl.h \ + /usr/include/i386-linux-gnu/asm/ioctl.h /usr/include/asm-generic/ioctl.h \ + /usr/include/i386-linux-gnu/bits/ioctl-types.h \ + /usr/include/i386-linux-gnu/sys/ttydefaults.h /usr/include/signal.h \ + /usr/include/i386-linux-gnu/bits/signum.h \ + /usr/include/i386-linux-gnu/bits/siginfo.h \ + /usr/include/i386-linux-gnu/bits/sigaction.h \ + /usr/include/i386-linux-gnu/bits/sigcontext.h \ + /usr/include/i386-linux-gnu/asm/sigcontext.h /usr/include/linux/types.h \ + /usr/include/i386-linux-gnu/asm/types.h /usr/include/asm-generic/types.h \ + /usr/include/asm-generic/int-ll64.h \ + /usr/include/i386-linux-gnu/asm/bitsperlong.h \ + /usr/include/asm-generic/bitsperlong.h /usr/include/linux/posix_types.h \ + /usr/include/linux/stddef.h \ + /usr/include/i386-linux-gnu/asm/posix_types.h \ + /usr/include/i386-linux-gnu/asm/posix_types_32.h \ + /usr/include/i386-linux-gnu/bits/sigstack.h \ + /usr/include/i386-linux-gnu/sys/ucontext.h \ + /usr/include/i386-linux-gnu/bits/sigthread.h /usr/include/stdio.h \ + /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \ + /usr/lib/gcc/i686-linux-gnu/4.6.1/include/stdarg.h \ + /usr/include/i386-linux-gnu/bits/stdio_lim.h \ + /usr/include/i386-linux-gnu/bits/sys_errlist.h \ + /usr/include/i386-linux-gnu/bits/stdio.h \ + /usr/include/i386-linux-gnu/bits/stdio2.h /usr/include/pwd.h \ + /usr/include/ctype.h /usr/include/xlocale.h /usr/include/setjmp.h \ + /usr/include/i386-linux-gnu/bits/setjmp.h \ + /usr/include/i386-linux-gnu/bits/setjmp2.h /usr/include/errno.h \ + /usr/include/i386-linux-gnu/bits/errno.h /usr/include/linux/errno.h \ + /usr/include/i386-linux-gnu/asm/errno.h /usr/include/asm-generic/errno.h \ + /usr/include/asm-generic/errno-base.h +dn11.o: dn11.c ../tip.h /usr/include/i386-linux-gnu/sys/types.h \ + /usr/include/features.h /usr/include/i386-linux-gnu/bits/predefs.h \ + /usr/include/i386-linux-gnu/sys/cdefs.h \ + /usr/include/i386-linux-gnu/bits/wordsize.h \ + /usr/include/i386-linux-gnu/gnu/stubs.h \ + /usr/include/i386-linux-gnu/gnu/stubs-32.h \ + /usr/include/i386-linux-gnu/bits/types.h \ + /usr/include/i386-linux-gnu/bits/typesizes.h /usr/include/time.h \ + /usr/lib/gcc/i686-linux-gnu/4.6.1/include/stddef.h /usr/include/endian.h \ + /usr/include/i386-linux-gnu/bits/endian.h \ + /usr/include/i386-linux-gnu/bits/byteswap.h \ + /usr/include/i386-linux-gnu/sys/select.h \ + /usr/include/i386-linux-gnu/bits/select.h \ + /usr/include/i386-linux-gnu/bits/sigset.h \ + /usr/include/i386-linux-gnu/bits/time.h \ + /usr/include/i386-linux-gnu/sys/sysmacros.h \ + /usr/include/i386-linux-gnu/bits/pthreadtypes.h \ + /usr/include/i386-linux-gnu/sys/file.h /usr/include/fcntl.h \ + /usr/include/i386-linux-gnu/bits/fcntl.h \ + /usr/include/i386-linux-gnu/bits/stat.h \ + /usr/include/i386-linux-gnu/bits/fcntl2.h /usr/include/sgtty.h \ + /usr/include/i386-linux-gnu/sys/ioctl.h \ + /usr/include/i386-linux-gnu/bits/ioctls.h \ + /usr/include/i386-linux-gnu/asm/ioctls.h \ + /usr/include/asm-generic/ioctls.h /usr/include/linux/ioctl.h \ + /usr/include/i386-linux-gnu/asm/ioctl.h /usr/include/asm-generic/ioctl.h \ + /usr/include/i386-linux-gnu/bits/ioctl-types.h \ + /usr/include/i386-linux-gnu/sys/ttydefaults.h /usr/include/signal.h \ + /usr/include/i386-linux-gnu/bits/signum.h \ + /usr/include/i386-linux-gnu/bits/siginfo.h \ + /usr/include/i386-linux-gnu/bits/sigaction.h \ + /usr/include/i386-linux-gnu/bits/sigcontext.h \ + /usr/include/i386-linux-gnu/asm/sigcontext.h /usr/include/linux/types.h \ + /usr/include/i386-linux-gnu/asm/types.h /usr/include/asm-generic/types.h \ + /usr/include/asm-generic/int-ll64.h \ + /usr/include/i386-linux-gnu/asm/bitsperlong.h \ + /usr/include/asm-generic/bitsperlong.h /usr/include/linux/posix_types.h \ + /usr/include/linux/stddef.h \ + /usr/include/i386-linux-gnu/asm/posix_types.h \ + /usr/include/i386-linux-gnu/asm/posix_types_32.h \ + /usr/include/i386-linux-gnu/bits/sigstack.h \ + /usr/include/i386-linux-gnu/sys/ucontext.h \ + /usr/include/i386-linux-gnu/bits/sigthread.h /usr/include/stdio.h \ + /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \ + /usr/lib/gcc/i686-linux-gnu/4.6.1/include/stdarg.h \ + /usr/include/i386-linux-gnu/bits/stdio_lim.h \ + /usr/include/i386-linux-gnu/bits/sys_errlist.h \ + /usr/include/i386-linux-gnu/bits/stdio.h \ + /usr/include/i386-linux-gnu/bits/stdio2.h /usr/include/pwd.h \ + /usr/include/ctype.h /usr/include/xlocale.h /usr/include/setjmp.h \ + /usr/include/i386-linux-gnu/bits/setjmp.h \ + /usr/include/i386-linux-gnu/bits/setjmp2.h /usr/include/errno.h \ + /usr/include/i386-linux-gnu/bits/errno.h /usr/include/linux/errno.h \ + /usr/include/i386-linux-gnu/asm/errno.h /usr/include/asm-generic/errno.h \ + /usr/include/asm-generic/errno-base.h +hayes.o: hayes.c ../tip.h /usr/include/i386-linux-gnu/sys/types.h \ + /usr/include/features.h /usr/include/i386-linux-gnu/bits/predefs.h \ + /usr/include/i386-linux-gnu/sys/cdefs.h \ + /usr/include/i386-linux-gnu/bits/wordsize.h \ + /usr/include/i386-linux-gnu/gnu/stubs.h \ + /usr/include/i386-linux-gnu/gnu/stubs-32.h \ + /usr/include/i386-linux-gnu/bits/types.h \ + /usr/include/i386-linux-gnu/bits/typesizes.h /usr/include/time.h \ + /usr/lib/gcc/i686-linux-gnu/4.6.1/include/stddef.h /usr/include/endian.h \ + /usr/include/i386-linux-gnu/bits/endian.h \ + /usr/include/i386-linux-gnu/bits/byteswap.h \ + /usr/include/i386-linux-gnu/sys/select.h \ + /usr/include/i386-linux-gnu/bits/select.h \ + /usr/include/i386-linux-gnu/bits/sigset.h \ + /usr/include/i386-linux-gnu/bits/time.h \ + /usr/include/i386-linux-gnu/sys/sysmacros.h \ + /usr/include/i386-linux-gnu/bits/pthreadtypes.h \ + /usr/include/i386-linux-gnu/sys/file.h /usr/include/fcntl.h \ + /usr/include/i386-linux-gnu/bits/fcntl.h \ + /usr/include/i386-linux-gnu/bits/stat.h \ + /usr/include/i386-linux-gnu/bits/fcntl2.h /usr/include/sgtty.h \ + /usr/include/i386-linux-gnu/sys/ioctl.h \ + /usr/include/i386-linux-gnu/bits/ioctls.h \ + /usr/include/i386-linux-gnu/asm/ioctls.h \ + /usr/include/asm-generic/ioctls.h /usr/include/linux/ioctl.h \ + /usr/include/i386-linux-gnu/asm/ioctl.h /usr/include/asm-generic/ioctl.h \ + /usr/include/i386-linux-gnu/bits/ioctl-types.h \ + /usr/include/i386-linux-gnu/sys/ttydefaults.h /usr/include/signal.h \ + /usr/include/i386-linux-gnu/bits/signum.h \ + /usr/include/i386-linux-gnu/bits/siginfo.h \ + /usr/include/i386-linux-gnu/bits/sigaction.h \ + /usr/include/i386-linux-gnu/bits/sigcontext.h \ + /usr/include/i386-linux-gnu/asm/sigcontext.h /usr/include/linux/types.h \ + /usr/include/i386-linux-gnu/asm/types.h /usr/include/asm-generic/types.h \ + /usr/include/asm-generic/int-ll64.h \ + /usr/include/i386-linux-gnu/asm/bitsperlong.h \ + /usr/include/asm-generic/bitsperlong.h /usr/include/linux/posix_types.h \ + /usr/include/linux/stddef.h \ + /usr/include/i386-linux-gnu/asm/posix_types.h \ + /usr/include/i386-linux-gnu/asm/posix_types_32.h \ + /usr/include/i386-linux-gnu/bits/sigstack.h \ + /usr/include/i386-linux-gnu/sys/ucontext.h \ + /usr/include/i386-linux-gnu/bits/sigthread.h /usr/include/stdio.h \ + /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \ + /usr/lib/gcc/i686-linux-gnu/4.6.1/include/stdarg.h \ + /usr/include/i386-linux-gnu/bits/stdio_lim.h \ + /usr/include/i386-linux-gnu/bits/sys_errlist.h \ + /usr/include/i386-linux-gnu/bits/stdio.h \ + /usr/include/i386-linux-gnu/bits/stdio2.h /usr/include/pwd.h \ + /usr/include/ctype.h /usr/include/xlocale.h /usr/include/setjmp.h \ + /usr/include/i386-linux-gnu/bits/setjmp.h \ + /usr/include/i386-linux-gnu/bits/setjmp2.h /usr/include/errno.h \ + /usr/include/i386-linux-gnu/bits/errno.h /usr/include/linux/errno.h \ + /usr/include/i386-linux-gnu/asm/errno.h /usr/include/asm-generic/errno.h \ + /usr/include/asm-generic/errno-base.h +ventel.o: ventel.c ../tip.h /usr/include/i386-linux-gnu/sys/types.h \ + /usr/include/features.h /usr/include/i386-linux-gnu/bits/predefs.h \ + /usr/include/i386-linux-gnu/sys/cdefs.h \ + /usr/include/i386-linux-gnu/bits/wordsize.h \ + /usr/include/i386-linux-gnu/gnu/stubs.h \ + /usr/include/i386-linux-gnu/gnu/stubs-32.h \ + /usr/include/i386-linux-gnu/bits/types.h \ + /usr/include/i386-linux-gnu/bits/typesizes.h /usr/include/time.h \ + /usr/lib/gcc/i686-linux-gnu/4.6.1/include/stddef.h /usr/include/endian.h \ + /usr/include/i386-linux-gnu/bits/endian.h \ + /usr/include/i386-linux-gnu/bits/byteswap.h \ + /usr/include/i386-linux-gnu/sys/select.h \ + /usr/include/i386-linux-gnu/bits/select.h \ + /usr/include/i386-linux-gnu/bits/sigset.h \ + /usr/include/i386-linux-gnu/bits/time.h \ + /usr/include/i386-linux-gnu/sys/sysmacros.h \ + /usr/include/i386-linux-gnu/bits/pthreadtypes.h \ + /usr/include/i386-linux-gnu/sys/file.h /usr/include/fcntl.h \ + /usr/include/i386-linux-gnu/bits/fcntl.h \ + /usr/include/i386-linux-gnu/bits/stat.h \ + /usr/include/i386-linux-gnu/bits/fcntl2.h /usr/include/sgtty.h \ + /usr/include/i386-linux-gnu/sys/ioctl.h \ + /usr/include/i386-linux-gnu/bits/ioctls.h \ + /usr/include/i386-linux-gnu/asm/ioctls.h \ + /usr/include/asm-generic/ioctls.h /usr/include/linux/ioctl.h \ + /usr/include/i386-linux-gnu/asm/ioctl.h /usr/include/asm-generic/ioctl.h \ + /usr/include/i386-linux-gnu/bits/ioctl-types.h \ + /usr/include/i386-linux-gnu/sys/ttydefaults.h /usr/include/signal.h \ + /usr/include/i386-linux-gnu/bits/signum.h \ + /usr/include/i386-linux-gnu/bits/siginfo.h \ + /usr/include/i386-linux-gnu/bits/sigaction.h \ + /usr/include/i386-linux-gnu/bits/sigcontext.h \ + /usr/include/i386-linux-gnu/asm/sigcontext.h /usr/include/linux/types.h \ + /usr/include/i386-linux-gnu/asm/types.h /usr/include/asm-generic/types.h \ + /usr/include/asm-generic/int-ll64.h \ + /usr/include/i386-linux-gnu/asm/bitsperlong.h \ + /usr/include/asm-generic/bitsperlong.h /usr/include/linux/posix_types.h \ + /usr/include/linux/stddef.h \ + /usr/include/i386-linux-gnu/asm/posix_types.h \ + /usr/include/i386-linux-gnu/asm/posix_types_32.h \ + /usr/include/i386-linux-gnu/bits/sigstack.h \ + /usr/include/i386-linux-gnu/sys/ucontext.h \ + /usr/include/i386-linux-gnu/bits/sigthread.h /usr/include/stdio.h \ + /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \ + /usr/lib/gcc/i686-linux-gnu/4.6.1/include/stdarg.h \ + /usr/include/i386-linux-gnu/bits/stdio_lim.h \ + /usr/include/i386-linux-gnu/bits/sys_errlist.h \ + /usr/include/i386-linux-gnu/bits/stdio.h \ + /usr/include/i386-linux-gnu/bits/stdio2.h /usr/include/pwd.h \ + /usr/include/ctype.h /usr/include/xlocale.h /usr/include/setjmp.h \ + /usr/include/i386-linux-gnu/bits/setjmp.h \ + /usr/include/i386-linux-gnu/bits/setjmp2.h /usr/include/errno.h \ + /usr/include/i386-linux-gnu/bits/errno.h /usr/include/linux/errno.h \ + /usr/include/i386-linux-gnu/asm/errno.h /usr/include/asm-generic/errno.h \ + /usr/include/asm-generic/errno-base.h +v831.o: v831.c /usr/include/i386-linux-gnu/sys/time.h \ + /usr/include/features.h /usr/include/i386-linux-gnu/bits/predefs.h \ + /usr/include/i386-linux-gnu/sys/cdefs.h \ + /usr/include/i386-linux-gnu/bits/wordsize.h \ + /usr/include/i386-linux-gnu/gnu/stubs.h \ + /usr/include/i386-linux-gnu/gnu/stubs-32.h \ + /usr/include/i386-linux-gnu/bits/types.h \ + /usr/include/i386-linux-gnu/bits/typesizes.h /usr/include/time.h \ + /usr/include/i386-linux-gnu/bits/time.h \ + /usr/include/i386-linux-gnu/sys/select.h \ + /usr/include/i386-linux-gnu/bits/select.h \ + /usr/include/i386-linux-gnu/bits/sigset.h ../tip.h \ + /usr/include/i386-linux-gnu/sys/types.h \ + /usr/lib/gcc/i686-linux-gnu/4.6.1/include/stddef.h /usr/include/endian.h \ + /usr/include/i386-linux-gnu/bits/endian.h \ + /usr/include/i386-linux-gnu/bits/byteswap.h \ + /usr/include/i386-linux-gnu/sys/sysmacros.h \ + /usr/include/i386-linux-gnu/bits/pthreadtypes.h \ + /usr/include/i386-linux-gnu/sys/file.h /usr/include/fcntl.h \ + /usr/include/i386-linux-gnu/bits/fcntl.h \ + /usr/include/i386-linux-gnu/bits/stat.h \ + /usr/include/i386-linux-gnu/bits/fcntl2.h /usr/include/sgtty.h \ + /usr/include/i386-linux-gnu/sys/ioctl.h \ + /usr/include/i386-linux-gnu/bits/ioctls.h \ + /usr/include/i386-linux-gnu/asm/ioctls.h \ + /usr/include/asm-generic/ioctls.h /usr/include/linux/ioctl.h \ + /usr/include/i386-linux-gnu/asm/ioctl.h /usr/include/asm-generic/ioctl.h \ + /usr/include/i386-linux-gnu/bits/ioctl-types.h \ + /usr/include/i386-linux-gnu/sys/ttydefaults.h /usr/include/signal.h \ + /usr/include/i386-linux-gnu/bits/signum.h \ + /usr/include/i386-linux-gnu/bits/siginfo.h \ + /usr/include/i386-linux-gnu/bits/sigaction.h \ + /usr/include/i386-linux-gnu/bits/sigcontext.h \ + /usr/include/i386-linux-gnu/asm/sigcontext.h /usr/include/linux/types.h \ + /usr/include/i386-linux-gnu/asm/types.h /usr/include/asm-generic/types.h \ + /usr/include/asm-generic/int-ll64.h \ + /usr/include/i386-linux-gnu/asm/bitsperlong.h \ + /usr/include/asm-generic/bitsperlong.h /usr/include/linux/posix_types.h \ + /usr/include/linux/stddef.h \ + /usr/include/i386-linux-gnu/asm/posix_types.h \ + /usr/include/i386-linux-gnu/asm/posix_types_32.h \ + /usr/include/i386-linux-gnu/bits/sigstack.h \ + /usr/include/i386-linux-gnu/sys/ucontext.h \ + /usr/include/i386-linux-gnu/bits/sigthread.h /usr/include/stdio.h \ + /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \ + /usr/lib/gcc/i686-linux-gnu/4.6.1/include/stdarg.h \ + /usr/include/i386-linux-gnu/bits/stdio_lim.h \ + /usr/include/i386-linux-gnu/bits/sys_errlist.h \ + /usr/include/i386-linux-gnu/bits/stdio.h \ + /usr/include/i386-linux-gnu/bits/stdio2.h /usr/include/pwd.h \ + /usr/include/ctype.h /usr/include/xlocale.h /usr/include/setjmp.h \ + /usr/include/i386-linux-gnu/bits/setjmp.h \ + /usr/include/i386-linux-gnu/bits/setjmp2.h /usr/include/errno.h \ + /usr/include/i386-linux-gnu/bits/errno.h /usr/include/linux/errno.h \ + /usr/include/i386-linux-gnu/asm/errno.h /usr/include/asm-generic/errno.h \ + /usr/include/asm-generic/errno-base.h +v3451.o: v3451.c ../tip.h /usr/include/i386-linux-gnu/sys/types.h \ + /usr/include/features.h /usr/include/i386-linux-gnu/bits/predefs.h \ + /usr/include/i386-linux-gnu/sys/cdefs.h \ + /usr/include/i386-linux-gnu/bits/wordsize.h \ + /usr/include/i386-linux-gnu/gnu/stubs.h \ + /usr/include/i386-linux-gnu/gnu/stubs-32.h \ + /usr/include/i386-linux-gnu/bits/types.h \ + /usr/include/i386-linux-gnu/bits/typesizes.h /usr/include/time.h \ + /usr/lib/gcc/i686-linux-gnu/4.6.1/include/stddef.h /usr/include/endian.h \ + /usr/include/i386-linux-gnu/bits/endian.h \ + /usr/include/i386-linux-gnu/bits/byteswap.h \ + /usr/include/i386-linux-gnu/sys/select.h \ + /usr/include/i386-linux-gnu/bits/select.h \ + /usr/include/i386-linux-gnu/bits/sigset.h \ + /usr/include/i386-linux-gnu/bits/time.h \ + /usr/include/i386-linux-gnu/sys/sysmacros.h \ + /usr/include/i386-linux-gnu/bits/pthreadtypes.h \ + /usr/include/i386-linux-gnu/sys/file.h /usr/include/fcntl.h \ + /usr/include/i386-linux-gnu/bits/fcntl.h \ + /usr/include/i386-linux-gnu/bits/stat.h \ + /usr/include/i386-linux-gnu/bits/fcntl2.h /usr/include/sgtty.h \ + /usr/include/i386-linux-gnu/sys/ioctl.h \ + /usr/include/i386-linux-gnu/bits/ioctls.h \ + /usr/include/i386-linux-gnu/asm/ioctls.h \ + /usr/include/asm-generic/ioctls.h /usr/include/linux/ioctl.h \ + /usr/include/i386-linux-gnu/asm/ioctl.h /usr/include/asm-generic/ioctl.h \ + /usr/include/i386-linux-gnu/bits/ioctl-types.h \ + /usr/include/i386-linux-gnu/sys/ttydefaults.h /usr/include/signal.h \ + /usr/include/i386-linux-gnu/bits/signum.h \ + /usr/include/i386-linux-gnu/bits/siginfo.h \ + /usr/include/i386-linux-gnu/bits/sigaction.h \ + /usr/include/i386-linux-gnu/bits/sigcontext.h \ + /usr/include/i386-linux-gnu/asm/sigcontext.h /usr/include/linux/types.h \ + /usr/include/i386-linux-gnu/asm/types.h /usr/include/asm-generic/types.h \ + /usr/include/asm-generic/int-ll64.h \ + /usr/include/i386-linux-gnu/asm/bitsperlong.h \ + /usr/include/asm-generic/bitsperlong.h /usr/include/linux/posix_types.h \ + /usr/include/linux/stddef.h \ + /usr/include/i386-linux-gnu/asm/posix_types.h \ + /usr/include/i386-linux-gnu/asm/posix_types_32.h \ + /usr/include/i386-linux-gnu/bits/sigstack.h \ + /usr/include/i386-linux-gnu/sys/ucontext.h \ + /usr/include/i386-linux-gnu/bits/sigthread.h /usr/include/stdio.h \ + /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \ + /usr/lib/gcc/i686-linux-gnu/4.6.1/include/stdarg.h \ + /usr/include/i386-linux-gnu/bits/stdio_lim.h \ + /usr/include/i386-linux-gnu/bits/sys_errlist.h \ + /usr/include/i386-linux-gnu/bits/stdio.h \ + /usr/include/i386-linux-gnu/bits/stdio2.h /usr/include/pwd.h \ + /usr/include/ctype.h /usr/include/xlocale.h /usr/include/setjmp.h \ + /usr/include/i386-linux-gnu/bits/setjmp.h \ + /usr/include/i386-linux-gnu/bits/setjmp2.h /usr/include/errno.h \ + /usr/include/i386-linux-gnu/bits/errno.h /usr/include/linux/errno.h \ + /usr/include/i386-linux-gnu/asm/errno.h /usr/include/asm-generic/errno.h \ + /usr/include/asm-generic/errno-base.h +penril.o: penril.c ../tip.h /usr/include/i386-linux-gnu/sys/types.h \ + /usr/include/features.h /usr/include/i386-linux-gnu/bits/predefs.h \ + /usr/include/i386-linux-gnu/sys/cdefs.h \ + /usr/include/i386-linux-gnu/bits/wordsize.h \ + /usr/include/i386-linux-gnu/gnu/stubs.h \ + /usr/include/i386-linux-gnu/gnu/stubs-32.h \ + /usr/include/i386-linux-gnu/bits/types.h \ + /usr/include/i386-linux-gnu/bits/typesizes.h /usr/include/time.h \ + /usr/lib/gcc/i686-linux-gnu/4.6.1/include/stddef.h /usr/include/endian.h \ + /usr/include/i386-linux-gnu/bits/endian.h \ + /usr/include/i386-linux-gnu/bits/byteswap.h \ + /usr/include/i386-linux-gnu/sys/select.h \ + /usr/include/i386-linux-gnu/bits/select.h \ + /usr/include/i386-linux-gnu/bits/sigset.h \ + /usr/include/i386-linux-gnu/bits/time.h \ + /usr/include/i386-linux-gnu/sys/sysmacros.h \ + /usr/include/i386-linux-gnu/bits/pthreadtypes.h \ + /usr/include/i386-linux-gnu/sys/file.h /usr/include/fcntl.h \ + /usr/include/i386-linux-gnu/bits/fcntl.h \ + /usr/include/i386-linux-gnu/bits/stat.h \ + /usr/include/i386-linux-gnu/bits/fcntl2.h /usr/include/sgtty.h \ + /usr/include/i386-linux-gnu/sys/ioctl.h \ + /usr/include/i386-linux-gnu/bits/ioctls.h \ + /usr/include/i386-linux-gnu/asm/ioctls.h \ + /usr/include/asm-generic/ioctls.h /usr/include/linux/ioctl.h \ + /usr/include/i386-linux-gnu/asm/ioctl.h /usr/include/asm-generic/ioctl.h \ + /usr/include/i386-linux-gnu/bits/ioctl-types.h \ + /usr/include/i386-linux-gnu/sys/ttydefaults.h /usr/include/signal.h \ + /usr/include/i386-linux-gnu/bits/signum.h \ + /usr/include/i386-linux-gnu/bits/siginfo.h \ + /usr/include/i386-linux-gnu/bits/sigaction.h \ + /usr/include/i386-linux-gnu/bits/sigcontext.h \ + /usr/include/i386-linux-gnu/asm/sigcontext.h /usr/include/linux/types.h \ + /usr/include/i386-linux-gnu/asm/types.h /usr/include/asm-generic/types.h \ + /usr/include/asm-generic/int-ll64.h \ + /usr/include/i386-linux-gnu/asm/bitsperlong.h \ + /usr/include/asm-generic/bitsperlong.h /usr/include/linux/posix_types.h \ + /usr/include/linux/stddef.h \ + /usr/include/i386-linux-gnu/asm/posix_types.h \ + /usr/include/i386-linux-gnu/asm/posix_types_32.h \ + /usr/include/i386-linux-gnu/bits/sigstack.h \ + /usr/include/i386-linux-gnu/sys/ucontext.h \ + /usr/include/i386-linux-gnu/bits/sigthread.h /usr/include/stdio.h \ + /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \ + /usr/lib/gcc/i686-linux-gnu/4.6.1/include/stdarg.h \ + /usr/include/i386-linux-gnu/bits/stdio_lim.h \ + /usr/include/i386-linux-gnu/bits/sys_errlist.h \ + /usr/include/i386-linux-gnu/bits/stdio.h \ + /usr/include/i386-linux-gnu/bits/stdio2.h /usr/include/pwd.h \ + /usr/include/ctype.h /usr/include/xlocale.h /usr/include/setjmp.h \ + /usr/include/i386-linux-gnu/bits/setjmp.h \ + /usr/include/i386-linux-gnu/bits/setjmp2.h /usr/include/errno.h \ + /usr/include/i386-linux-gnu/bits/errno.h /usr/include/linux/errno.h \ + /usr/include/i386-linux-gnu/asm/errno.h /usr/include/asm-generic/errno.h \ + /usr/include/asm-generic/errno-base.h diff --git a/src/cmd/tip/aculib/Makefile b/src/cmd/tip/aculib/Makefile new file mode 100644 index 0000000..0a147e0 --- /dev/null +++ b/src/cmd/tip/aculib/Makefile @@ -0,0 +1,53 @@ +TOPSRC = $(shell cd ../../../..; pwd) +include $(TOPSRC)/target.mk + +# +# Copyright (c) 1987 Regents of the University of California. +# All rights reserved. The Berkeley software License Agreement +# specifies the terms and conditions for redistribution. +# +# @(#)Makefile 5.3.2 (2.11BSD GTE) 1996/12/1 +# +# make file for tip device drivers +# +# Current drivers: +# BIZCOMP +# USR COURIER (2400 baud) +# DEC DF02-AC, DF03-AC +# DEC DN-11/Able Quadracall +# HAYES and Hayes emulators +# PENRIL auto-dialer +# VENTEL 212+ (w/o echo) +# VADIC 831 RS232 adaptor +# VADIC 3451 +CFLAGS += -I.. -Wall -Werror +SRCS= biz22.c biz31.c courier.c df.c dn11.c hayes.c ventel.c v831.c \ + v3451.c penril.c +OBJS= biz22.o biz31.o courier.o df.o dn11.o hayes.o ventel.o v831.o \ + v3451.o penril.o + +all: libacu.a + +libacu.a: ${OBJS} + $(AR) -rc libacu.a ${OBJS} + $(RANLIB) libacu.a + +clean: FRC + rm -f ${OBJS} core libacu.a + +depend: FRC + mkdep ${CFLAGS} ${SRCS} + +lint: FRC + lint ${CFLAGS} ${SRCS} + +tags: FRC + ctags ${SRCS} + +install: +FRC: + +# DO NOT DELETE THIS LINE -- mkdep uses it. +# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY. + +# IF YOU PUT ANYTHING HERE IT WILL GO AWAY diff --git a/src/cmd/tip/aculib/biz22.c b/src/cmd/tip/aculib/biz22.c new file mode 100644 index 0000000..2b95177 --- /dev/null +++ b/src/cmd/tip/aculib/biz22.c @@ -0,0 +1,154 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include +#include +#include "tip.h" + + +#define DISCONNECT_CMD "\20\04" /* disconnection string */ + +static int timeout = 0; +static jmp_buf timeoutbuf; +static int detect(register char *s); +static int cmd(register char *s); + +void biz22_disconnect() +{ + int rw = 2; + + write(FD, DISCONNECT_CMD, 4); + sleep(2); + ioctl(FD, TIOCFLUSH, &rw); +} + +/* + * 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]; + + 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); +} + +int biz22w_dialer(num, acu) + char *num, *acu; +{ + return (biz_dialer(num, "W")); +} + +int biz22f_dialer(num, acu) + char *num, *acu; +{ + return (biz_dialer(num, "V")); +} + +void biz22_abort() +{ + write(FD, "\02", 1); +} + +static void +sigALRM(int i) +{ + + timeout = 1; + longjmp(timeoutbuf, 1); +} + +static int +cmd(s) + register char *s; +{ + char c; + sig_t f; + + 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; +{ + char c; + sig_t f; + + 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/src/cmd/tip/aculib/biz31.c b/src/cmd/tip/aculib/biz31.c new file mode 100644 index 0000000..f66e856 --- /dev/null +++ b/src/cmd/tip/aculib/biz31.c @@ -0,0 +1,212 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "tip.h" + +#define MAXRETRY 3 /* sync up retry count */ +#define DISCONNECT_CMD "\21\25\11\24" /* disconnection string */ + +static int timeout = 0; +static jmp_buf timeoutbuf; +static int bizsync(int fd); +static int detect(register char *s); + +void biz31_disconnect() +{ + write(FD, DISCONNECT_CMD, 4); + sleep(2); + ioctl(FD, TIOCFLUSH); +} + +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(int i) +{ + timeout = 1; + longjmp(timeoutbuf, 1); +} + +static void +flush(s) + register char *s; +{ + char c; + sig_t f; + + 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 */ +} + +/* + * 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); +} + +int biz31w_dialer(num, acu) + char *num, *acu; +{ + return (biz_dialer(num, "w")); +} + +int biz31f_dialer(num, acu) + char *num, *acu; +{ + return (biz_dialer(num, "f")); +} + +void biz31_abort() +{ + write(FD, "\33", 1); +} + +static int +detect(s) + register char *s; +{ + char c; + sig_t f; + + 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); +} + +/* + * 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/src/cmd/tip/aculib/courier.c b/src/cmd/tip/aculib/courier.c new file mode 100644 index 0000000..c4eb134 --- /dev/null +++ b/src/cmd/tip/aculib/courier.c @@ -0,0 +1,353 @@ +/* + * Copyright (c) 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#define write cour_write + +/* + * Routines for calling up on a Courier modem. + * Derived from Hayes driver. + */ +#include "tip.h" + +#define MAXRETRY 5 + +static int timeout = 0; +static int connected = 0; +static jmp_buf timeoutbuf; +static void cour_napx(); +void cour_nap(void); +static int coursync(); +static int cour_connect(); +static int cour_swallow(register char *match); + +void cour_disconnect() +{ + /* first hang up the modem*/ + ioctl(FD, TIOCCDTR, 0); + sleep(1); + ioctl(FD, TIOCSDTR, 0); + coursync(); /* reset */ + close(FD); +} + +int cour_dialer(num, acu) + register char *num; + char *acu; +{ + register char *cp; +#ifdef ACULOG + char line[80]; +#endif + 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); + } + write(FD, "AT E0\r", 6); /* turn off echoing */ + sleep(1); +#ifdef DEBUG + if (boolean(value(VERBOSE))) + verbose_read(); +#endif + ioctl(FD, TIOCFLUSH, 0); /* flush any clutter */ + write(FD, "AT C1 E0 H0 Q0 X6 V1\r", 21); + if (!cour_swallow("\r\nOK\r\n")) + goto badsynch; + fflush(stdout); + write(FD, "AT D", 4); + for (cp = num; *cp; cp++) + if (*cp == '=') + *cp = ','; + write(FD, num, strlen(num)); + 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); +} + +void cour_abort() +{ + write(FD, "\r", 1); /* send anything to abort the call */ + cour_disconnect(); +} + +static void +sigALRM(int i) +{ + printf("\07timeout waiting for reply\n"); + timeout = 1; + longjmp(timeoutbuf, 1); +} + +static int +cour_swallow(match) + register char *match; +{ + char c; + sig_t f; + + 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); +} + +static struct baud_msg { + char *msg; + int baud; +} baud_msg[] = { + { "", B300 }, + { " 1200", B1200 }, + { " 2400", B2400 }, + { 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 ; 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 + } + 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, len; + long nread; + char buf[40]; + + for (already=0; already + +#define mask(s) sigmask(s) +#define setvec(vec, a) \ + vec.sv_handler = a; vec.sv_mask = vec.sv_onstack = 0 + +static int napms = 50; /* Give the courier 50 milliseconds between characters */ + +static int ringring; + +void cour_nap() +{ + long 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/src/cmd/tip/aculib/df.c b/src/cmd/tip/aculib/df.c new file mode 100644 index 0000000..2ba0b30 --- /dev/null +++ b/src/cmd/tip/aculib/df.c @@ -0,0 +1,93 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +/* + * Dial the DF02-AC or DF03-AC + */ +#include "tip.h" + +static jmp_buf Sjbuf; + +static void +timeout(int sig) +{ + longjmp(Sjbuf, 1); +} + +void df_disconnect() +{ + int rw = 2; + + write(FD, "\001", 1); + sleep(1); + ioctl(FD, TIOCFLUSH, &rw); +} + +int 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'); +} + +int df02_dialer(num, acu) + char *num, *acu; +{ + return (df_dialer(num, acu, 0)); +} + +int df03_dialer(num, acu) + char *num, *acu; +{ + return (df_dialer(num, acu, 1)); +} + +void df_abort() +{ + df_disconnect(); +} diff --git a/src/cmd/tip/aculib/dn11.c b/src/cmd/tip/aculib/dn11.c new file mode 100644 index 0000000..8a9a773 --- /dev/null +++ b/src/cmd/tip/aculib/dn11.c @@ -0,0 +1,106 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +/* + * Routines for dialing up on DN-11 + */ +#include "tip.h" +#include +#include + +static jmp_buf jmpbuf; +static int child = -1, dn; + +void alarmtr(int sig) +{ + alarm(0); + longjmp(jmpbuf, 1); +} + +int dn_dialer(num, acu) + char *num, *acu; +{ + int lt, nw; + 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); +} + +/* + * Insurance, for some reason we don't seem to be + * hanging up... + */ +void dn_disconnect() +{ + sleep(2); + if (FD > 0) + ioctl(FD, TIOCCDTR, 0); + close(FD); +} + +void 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/src/cmd/tip/aculib/hayes.c b/src/cmd/tip/aculib/hayes.c new file mode 100644 index 0000000..98ef157 --- /dev/null +++ b/src/cmd/tip/aculib/hayes.c @@ -0,0 +1,268 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +/* + * 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 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; + +static void sigALRM(int sig) +{ + printf("\07timeout waiting for reply\n\r"); + timeout = 1; + longjmp(timeoutbuf, 1); +} + +#define MAXRETRY 5 + +int hay_sync() +{ + int len, retry = 0; + long llen; + + while (retry++ <= MAXRETRY) { + write(FD, "AT\r", 3); + sleep(1); + ioctl(FD, FIONREAD, &llen); + len = llen; + if (len) { + len = read(FD, dumbuf, min(len, DUMBUFLEN)); + if (strchr(dumbuf, '0') || + (strchr(dumbuf, 'O') && strchr(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); +} + +void 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"); +} + +/* + * set modem back to normal verbose status codes. + */ +void goodbye() +{ + int len; + int zero = 0; + long llen; + char c; + + ioctl(FD, TIOCFLUSH, &zero); /* get rid of trash */ + if (hay_sync()) { + sleep(1); +#ifndef DEBUG + ioctl(FD, TIOCFLUSH, &zero); +#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, &llen); + len = llen; +#ifdef DEBUG + printf("goodbye1: len=%d -- ", len); + int 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, &llen); + len = llen; + 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, &zero); /* clear the input buffer */ + ioctl(FD, TIOCCDTR, 0); /* clear DTR (insurance) */ + close(FD); +} + +void hay_disconnect() +{ + /* first hang up the modem*/ +#ifdef DEBUG + printf("\rdisconnecting modem....\n\r"); +#endif + ioctl(FD, TIOCCDTR, 0); + sleep(1); + ioctl(FD, TIOCSDTR, 0); + goodbye(); +} + +int hay_dialer(num, acu) + register char *num; + char *acu; +{ + register int connected = 0; + int zero = 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, &zero); + write(FD, "ATV0E0X0\r", 9); /* numeric codes,noecho,base cmds */ + sleep(1); + ioctl(FD, TIOCFLUSH, &zero); /* get rid of garbage */ + + write(FD, "ATDT", 4); /* send dial command */ + write(FD, num, strlen(num)); + state = DIALING; + write(FD, "\r", 1); + connected = 0; + 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, &zero); +#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); +} + +void hay_abort() +{ + write(FD, "\r", 1); /* send anything to abort the call */ + hay_disconnect(); +} + +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); +} diff --git a/src/cmd/tip/aculib/penril.c b/src/cmd/tip/aculib/penril.c new file mode 100644 index 0000000..6264d5a --- /dev/null +++ b/src/cmd/tip/aculib/penril.c @@ -0,0 +1,224 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +/* + * Routines for calling up on a Penril Modem + * The Penril is expected to be strapped for local echo (just like uucp) + */ +#include "tip.h" + +#define MAXRETRY 5 + +static void sigALRM(int); +static int timeout = 0; +static jmp_buf buftimeout; +static int pensync(int fd); +static int gobble(register char match, char response[]); + +/* + * some sleep calls have been replaced by this macro + * because some penril 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 */ + +void busyloop(n) +{ + while (--n > 0) + ; +} + +void pen_disconnect() +{ + 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); + } +} + +int pen_dialer(num, acu) + register char *num; + char *acu; +{ + register char *cp; + register int connected = 0; + char *msg, *index(), line[80]; + + /* + * Get in synch with a couple of carriage returns + */ + if (!pensync(FD)) { + printf("can't synchronize with penril\n"); +#ifdef ACULOG + logent(value(HOST), num, "penril", "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('O', line) && gobble('K', line); + ioctl(FD, TIOCFLUSH); +#ifdef ACULOG + if (timeout) { + sprintf(line, "%d second dial timeout", + number(value(DIALTIMEOUT))); + logent(value(HOST), num, "penril", line); + } +#endif + if (timeout) + pen_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); +} + +void pen_abort() +{ + write(FD, "\03", 1); + close(FD); +} + +static void +sigALRM(int i) +{ + printf("\07timeout waiting for reply\n"); + timeout = 1; + longjmp(buftimeout, 1); +} + +static int +gobble(match, response) + register char match; + char response[]; +{ + register char *cp = response; + char c; + sig_t f; + + f = signal(SIGALRM, sigALRM); + timeout = 0; + do { + if (setjmp(buftimeout)) { + 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 penril in sync. If you don't have FIONREAD + * there are gory ways to simulate this. + */ +static int +pensync(fd) +{ + int already = 0, nread; + long temp; + 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); + sleep(2); + if (ioctl(fd, FIONREAD, &temp) < 0) { + perror("tip: ioctl"); + continue; + } + nread = temp; + while (nread > 0) { + read(fd, buf, min(nread, 70)); + if (((buf[nread - 6] & 0177) == 'B') && + ((buf[nread - 5] & 0177) == 'P') && + ((buf[nread - 4] & 0177) == 'S') && + ((buf[nread - 1] & 0177) == '>')) + return (1); + nread -= min(nread, 70); + } + sleep(1); + already++; + } + return (0); +} diff --git a/src/cmd/tip/aculib/v3451.c b/src/cmd/tip/aculib/v3451.c new file mode 100644 index 0000000..cc19e1f --- /dev/null +++ b/src/cmd/tip/aculib/v3451.c @@ -0,0 +1,179 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +/* + * Routines for calling up on a Vadic 3451 Modem + */ +#include +#include "tip.h" + +static jmp_buf Sjbuf; +static int prefix(register char *s1, register char *s2); +static int notin(char *sh, char *lg); +static int expect(register char *cp); + +static void +vawrite(cp, delay) + register char *cp; + int delay; +{ + for (; *cp; sleep(delay), cp++) + write(FD, cp, 1); +} + +int v3451_dialer(num, acu) + register char *num; + char *acu; +{ + int ok; + sig_t func; + int slow = number(value(BAUDRATE)) < 1200, rw = 2; + char phone[50]; +#ifdef ACULOG + char line[80]; +#endif + + /* + * 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); +} + +void v3451_disconnect() +{ + close(FD); +} + +void v3451_abort() +{ + close(FD); +} + +static void +alarmtr() +{ + longjmp(Sjbuf, 1); +} + +static int +expect(cp) + register char *cp; +{ + char buf[300]; + register char *rp = buf; + int timeout = 30, online = 0; + + 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 int +notin(sh, lg) + char *sh, *lg; +{ + + for (; *lg; lg++) + if (prefix(sh, lg)) + return (0); + return (1); +} + +static int +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/src/cmd/tip/aculib/v831.c b/src/cmd/tip/aculib/v831.c new file mode 100644 index 0000000..ec4733f --- /dev/null +++ b/src/cmd/tip/aculib/v831.c @@ -0,0 +1,226 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +/* + * Routines for dialing up on Vadic 831 + */ +#include +#include +#include + +#include "tip.h" + +static jmp_buf jmpbuf; +static int child = -1; + +/* + * 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 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); +} + +/* + * Insurance, for some reason we don't seem to be + * hanging up... + */ +void 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); +} + +static int +dialit(phonenum, acu) + register char *phonenum; + char *acu; +{ + register struct vaconfig *vp; + struct sgttyb cntrl; + char c; + int i, two = 2; + + 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 void +alarmtr(int sig) +{ + alarm(0); + longjmp(jmpbuf, 1); +} + +int v831_dialer(num, acu) + char *num, *acu; +{ + int status, pid; + register int timelim; + + 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); +} + +void 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); +} diff --git a/src/cmd/tip/aculib/ventel.c b/src/cmd/tip/aculib/ventel.c new file mode 100644 index 0000000..6aa231c --- /dev/null +++ b/src/cmd/tip/aculib/ventel.c @@ -0,0 +1,220 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +/* + * 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 int timeout = 0; +static jmp_buf timeoutbuf; +static int vensync(int fd); +static int gobble(register char match, char response[]); + +/* + * 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 */ + +void busyloop(n) +{ + while (--n > 0) + ; +} + +void ven_disconnect() +{ + 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); + } +} + +int ven_dialer(num, acu) + register char *num; + char *acu; +{ + register char *cp; + register int connected = 0; + char *msg, *index(), line[80]; + + /* + * 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); +} + +void ven_abort() +{ + write(FD, "\03", 1); + close(FD); +} + +static void +sigALRM(int i) +{ + 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; + char c; + sig_t f; + + 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/src/cmd/tip/acutab.c b/src/cmd/tip/acutab.c new file mode 100644 index 0000000..c11740e --- /dev/null +++ b/src/cmd/tip/acutab.c @@ -0,0 +1,64 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#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(), + v3451_dialer(), v3451_disconnect(), v3451_abort(), + v831_dialer(), v831_disconnect(), v831_abort(), + pen_dialer(), pen_disconnect(), pen_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 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 +#ifdef PENRIL + { "penril", pen_dialer, pen_disconnect, pen_abort }, +#endif + { 0, 0, 0, 0 }, +}; diff --git a/src/cmd/tip/cmds.c b/src/cmd/tip/cmds.c new file mode 100644 index 0000000..06a2695 --- /dev/null +++ b/src/cmd/tip/cmds.c @@ -0,0 +1,862 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include +#include +#include +#include +#include +#include "tip.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 */ +static jmp_buf intbuf; + +int intprompt(); /* used in handling SIG_INT during prompt */ + +/* + * interrupt routine for file transfers + */ +void +intcopy(int sig) +{ + raw(); + quit = 1; + longjmp(intbuf, 1); +} + +/* + * Interrupt service routine for FTP + */ +void +stopsnd(int sig) +{ + stop = 1; + signal(SIGINT, SIG_IGN); +} + +/* + * timeout function called on alarm + */ +void +timeout(int sig) +{ + signal(SIGALRM, timeout); + timedout = 1; +} + +static void prtime(s, a) + char *s; + time_t a; +{ + register int 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"); +} + +/* + * Bulk transfer routine -- + * used by getfl(), cu_take(), and pipefile() + */ +static void 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; + + pwrite(FD, buf, size(buf)); + quit = 0; + kill(pid, SIGIOT); + read(repdes[0], (char *)&ccc, 1); /* Wait until read process stops */ + + /* + * finish command + */ + 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; + } + } + cnt = p - buffer; + if (cnt > 0) + 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 + * get a file from the remote host + */ +void getfl(c) + int 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)); +} + +static int 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); +} + +/* + * Cu-like take command + */ +void cu_take(cc) + char cc; +{ + int fd, argc; + char line[BUFSIZ], *expand(), *cp; + + if (prompt("[take] ", copyname)) + return; + argc = args(copyname, argv); + if (argc < 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 void execute(s) + char *s; +{ + register char *cp; + + if ((cp = strrchr(value(SHELL), '/')) == NULL) + cp = value(SHELL); + else + cp++; + user_uid(); + execl(value(SHELL), cp, "-c", s, (char*)0); +} + +/* + * FTP - remote ==> local process + * send remote input to local process via pipe + */ +void pipefile() +{ + int cpid, pdes[2]; + char buf[256]; + int status, p; + + 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); + } +} + +/* + * FTP - send single character + * wait for echo & handle timeout + */ +static void send(c) + int 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(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; + } +} + +/* + * Bulk transfer routine to remote host -- + * used by sendfile() and cu_put() + */ +void 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(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); +} + +/* + * FTP - local ==> remote + * send local file to remote host + * terminate transmission with pseudo EOF sequence + */ +void 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 */ + } +} + +/* + * Cu-like put command + */ +void cu_put(cc) + int cc; +{ + FILE *fd; + char line[BUFSIZ]; + int argc; + char *expand(); + char *cpynamex; + + if (prompt("[put] ", copyname)) + return; + argc = args(copyname, argv); + if (argc < 1 || argc > 2) { + printf("usage: from [to]\r\n"); + return; + } + if (argc == 1) + argv[1] = argv[0]; + cpynamex = expand(argv[0]); + if ((fd = fopen(cpynamex, "r")) == NULL) { + printf("%s: cannot open\r\n", cpynamex); + 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); +} + +/* + * Stolen from consh() -- puts a remote file on the output of a local command. + * Identical to consh() except for where stdout goes. + */ +void 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... + */ + cpid = fork(); + if (cpid < 0) + printf("can't fork!\r\n"); + else if (cpid) { + start = time(0); + while ((p = wait(&status)) > 0 && p != cpid) + ; + if (boolean(value(VERBOSE))) + prtime("away for ", time(0)-start); + } 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); + } + 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 <-> local tty in + * 1 <-> local tty out + * 2 <-> local tty out + * 3 <-> remote tty in + * 4 <-> remote tty out + */ +void 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) + ; + if (boolean(value(VERBOSE))) + prtime("away for ", time(0)-start); + } else { + register int i; + + dup2(FD, 3); + dup2(3, 4); + for (i = 5; 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); + } + write(fildes[1], (char *)&ccc, 1); + ioctl(0, TIOCSETC, &tchars); + signal(SIGINT, SIG_DFL); + signal(SIGQUIT, SIG_DFL); +} +#endif + +/* + * Escape to local shell + */ +void shell() +{ + int shpid, status; + char *cp; + + printf("[sh]\r\n"); + signal(SIGINT, SIG_IGN); + signal(SIGQUIT, SIG_IGN); + unraw(); + shpid = fork(); + if (shpid != 0) { + 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 = strrchr(value(SHELL), '/')) == NULL) + cp = value(SHELL); + else + cp++; + shell_uid(); + execl(value(SHELL), cp, (char*) 0); + printf("\r\ncan't execl!\r\n"); + exit(1); + } +} + +/* + * TIPIN portion of scripting + * initiate the conversation with TIPOUT + */ +void 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 + */ +void 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"); +} + +void 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(); + delock(uucplock); + unraw(); + exit(0); +} + +void finish() +{ + char *dismsg; + + if ((dismsg = value(DISCONNECT)) != NOSTR) { + write(FD, dismsg, strlen(dismsg)); + sleep(5); + } + tipabort(NOSTR); +} + +/* + * Turn tandem mode on or off for remote tty. + */ +static void 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); +} + +void 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(NOSTR); + } +} + +/* + * Send a break. + */ +void genbrk() +{ + ioctl(FD, TIOCSBRK, NULL); + sleep(1); + ioctl(FD, TIOCCBRK, NULL); +} + +/* + * Suspend tip + */ +void suspend(c) + int c; +{ + unraw(); + kill(c == CTRL(y) ? getpid() : 0, SIGTSTP); + raw(); +} + + +/* + * Are any of the characters in the two strings the same? + */ +static int anyof(s1, s2) + register char *s1, *s2; +{ + register int c; + + while ((c = *s1++)) + if (any(c, s2)) + return(1); + return(0); +} +/* + * 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; + register char *cp, *Shell; + int s, pivec[2]; + + 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 = "/bin/sh"; + close(pivec[0]); + close(1); + dup(pivec[1]); + close(pivec[1]); + close(2); + shell_uid(); + execl(Shell, Shell, "-c", cmdbuf, (char*)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); +} diff --git a/src/cmd/tip/cmdtab.c b/src/cmd/tip/cmdtab.c new file mode 100644 index 0000000..554c891 --- /dev/null +++ b/src/cmd/tip/cmdtab.c @@ -0,0 +1,32 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "tip.h" + +extern int shell(), getfl(), sendfile(), chdirectory(); +extern int 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", (int(*)())finish }, + {CTRL(d),NORM, "exit from tip", (int(*)())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/src/cmd/tip/cu.c b/src/cmd/tip/cu.c new file mode 100644 index 0000000..d9d1d3c --- /dev/null +++ b/src/cmd/tip/cu.c @@ -0,0 +1,101 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "tip.h" + +void cleanup(int); +int timeout(); + +/* + * Botch the interface to look like cu's + */ +void 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"); + delock(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(); + delock(uucplock); + exit(1); + } + if (!HW) + ttysetup(speed(BR)); +} diff --git a/src/cmd/tip/hunt.c b/src/cmd/tip/hunt.c new file mode 100644 index 0000000..854f29d --- /dev/null +++ b/src/cmd/tip/hunt.c @@ -0,0 +1,67 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "tip.h" +#include + +extern char *getremote(); +extern char *rindex(); + +static jmp_buf deadline; +static int deadfl; + +void +dead(int sig) +{ + deadfl = 1; + longjmp(deadline, 1); +} + +int hunt(name) + char *name; +{ + register char *cp; + sig_t f; + + f = signal(SIGALRM, dead); + while ((cp = getremote(name))) { + printf("hunt: cp = %s\n",cp); + deadfl = 0; + uucplock = rindex(cp, '/')+1; + printf("hunt: uucplock = %s\n",uucplock); + if (mlock(uucplock) < 0) { + printf("hunt: mlock(uucplock)<0\n"); + delock(uucplock); + 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); + } + delock(uucplock); + } + signal(SIGALRM, f); + return (deadfl ? -1 : (int)cp); +} diff --git a/src/cmd/tip/log.c b/src/cmd/tip/log.c new file mode 100644 index 0000000..54260a7 --- /dev/null +++ b/src/cmd/tip/log.c @@ -0,0 +1,56 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "tip.h" +#include + +#ifdef ACULOG +static FILE *flog = NULL; + +/* + * Log file maintenance routines + */ +void 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; + } + user = getlogin(); + if (user == 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); +} + +void 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/src/cmd/tip/m b/src/cmd/tip/m new file mode 100644 index 0000000..19c4dd2 --- /dev/null +++ b/src/cmd/tip/m @@ -0,0 +1,5 @@ +cd aculib; make +make[1]: Entering directory `/home/matt/retrobsd/src/cmd/tip/aculib' +make[1]: Nothing to be done for `all'. +make[1]: Leaving directory `/home/matt/retrobsd/src/cmd/tip/aculib' +/usr/local/pic32-tools/bin/pic32-gcc -mips32r2 -EL -nostdinc -fshort-double -I/home/matt/retrobsd/include -I/usr/local/pic32-tools/lib/gcc/pic32mx/4.5.1/include -o tip acu.o acutab.o cmds.o cmdtab.o cu.o hunt.o log.o partab.o remcap.o remote.o tip.o tipout.o uucplock.o value.o vars.o aculib/aculib.a diff --git a/src/cmd/tip/partab.c b/src/cmd/tip/partab.c new file mode 100644 index 0000000..1ccea0a --- /dev/null +++ b/src/cmd/tip/partab.c @@ -0,0 +1,27 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +/* + * 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/src/cmd/tip/phones-file b/src/cmd/tip/phones-file new file mode 100644 index 0000000..96d4961 --- /dev/null +++ b/src/cmd/tip/phones-file @@ -0,0 +1,17 @@ +bert 004156427750-< +ernie 004156427652 +lbl 004154864979-< +ames 009699129 +decvax 00603-884-1241 +decvax 006038841230 +case 002163683923 +casevax 002163683240 +cwrunix 002163683240 +cwruecmp 002163683906 +ecmp 002163683906 +navy 423012273700 +gi 006028997900 +gi750 008015823032 +texas 512-474-5511 +sri 415-326-7005 +texas-20 512-477-6542 diff --git a/src/cmd/tip/remcap.c b/src/cmd/tip/remcap.c new file mode 100644 index 0000000..d8ef62f --- /dev/null +++ b/src/cmd/tip/remcap.c @@ -0,0 +1,394 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +/* + * remcap - routines for dealing with the remote host data base + * + * derived from termcap + */ +#include +#include +#include +#include +#include +#include + +#ifndef BUFSIZ +#define BUFSIZ 1024 +#endif +#define MAXHOP 32 /* max number of tc= indirections */ +#define SYSREMOTE "/etc/remote" /* system remote file */ + +#define tgetent rgetent +#define tnchktc rnchktc +#define tnamatch rnamatch +#define tgetnum rgetnum +#define tgetflag rgetflag +#define tgetstr rgetstr +#define E_TERMCAP RM = SYSREMOTE +#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 *remotefile; +static int tnchktc (void); + +/* + * 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. + */ +static int 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++; + } +} + +static int 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. + */ +static int 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 (getent(tcbuf, tcname, remotefile) != 1) { + if (strcmp(remotefile, SYSREMOTE) == 0) + return (0); + else if (getent(tcbuf, tcname, SYSREMOTE) != 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); +} + +/* + * Get an entry for terminal name in buffer bp, + * from the termcap file. Parse is very rudimentary; + * we just notice escaped newlines. + */ +int 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, SYSREMOTE) == 0) { + remotefile = cp = SYSREMOTE; + return (getent(bp, name, cp)); + } else { + if ((rc1 = getent(bp, name, cp)) != 1) + *bp = '\0'; + remotefile = cp = SYSREMOTE; + 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); + } +} + +/* + * 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++; + while (*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. + */ +int 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. + */ +int 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); + } + } +} + +/* + * 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); +} + +/* + * 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)); + } +} diff --git a/src/cmd/tip/remote-file b/src/cmd/tip/remote-file new file mode 100644 index 0000000..c3bd40a --- /dev/null +++ b/src/cmd/tip/remote-file @@ -0,0 +1,104 @@ +# +# General dialer definitions used below +# +local|Local PTY connection:\ + :dv=/dev/ptyp0,/dev/ptyp1,/dev/ptyp2,/dev/ptyp3:\ + :br#115200: + +dial1200|1200 Baud Able Quadracall attributes:\ + :dv=/dev/cul1:br#1200:cu=/dev/cua1:at=dn11:du: +dial300|300 Bizcomp 1022 attributes:\ + :dv=/dev/cul0:br#300:cu=/dev/cua0:at=dn11:du: +# +# UNIX system definitions +# +unix1200|1200 Baud dial-out to another UNIX system:\ + :el=^U^C^R^O^D^S^Q:ie=%$:oe=^D:tc=dial1200: +unix300|300 Baud dial-out to another UNIX system:\ + :el=^U^C^R^O^D^S^Q:ie=%$:oe=^D:tc=dial300: +# +# System descriptions +# +45|Sytek PDP-11/45:dv=/dev/ttyh1:br#9600:hw:el=^U^C^R^O^D^S^Q:ie=%$:oe=^D: + +bert|CSRG ARPA VAX-11/780:pn=@:tc=unix1200: +ernie|UCB VAX-11/780:pn=@:tc=unix1200: +lbl|LBL VAX-11/780:pn=@:tc=unix1200: +decvax|DEC VAX-11/780:pn=@:tc=unix1200: + +casevax|cwrunix|CWRU VAX-11/750:pn=@:tc=unix1200: +cwruecmp|ecmp|CWRU VAX-11/780:pn=@:tc=unix1200: +case|CWRU DEC-20:pn=@:tc=unix1200: + +ames|Ames TIP:pn=@:tc=unix1200: +navy|navy PWB 11/70:pn=@:tc=unix300: + +gi750|General Instruments VAX-11/750, Arizona:pn=@:tc=unix1200: +gi|General Instruments VAX-11/780, Utah:pn=@:tc=unix1200: + +video:dv=/dev/tty04:br#4800: + + + + +Second example: + +45z|PDP-11/45Z system:\ + :dv=/dev/tty32:br#9600:el=^U^C^S^Q^D:ie=%$:oe=^D: +decvax|DEC VAX-11/780:\ + :pn=41148:tc=UNIX-300: +decvax-1200|DEC VAX-11/780:\ + :pn=41230:tc=UNIX-1200: +decmail:\ + :pn=42311:tc=VMS-1200: +ems:\ + :pn=41991:tc=VMS-1200: +vms750|nymph|NPG 750:\ + :dv=/dev/tty36,/dev/tty37:br#9600:el=^Z^U^C^S^Q^O:ie=$@:oe=^Z: +spa|SPA VAX-11/780:\ + :pn=8=2270513:tc=UNIX-300: +vax4|DECnet hub:\ + :pn=41662:tc=VMS-1200: +star|VMS development system:\ + :pn=41701:tc=VMS-1200: +sultan|Software Tools:\ + :pn=41701:tc=UNIX-1200: +cghub|demo room timesharing VAX:\ + :pn=41023,41024:tc=VMS-300 +phenix|phenix-300|Distributed systems:\ + :pn=8=2472765,8=2472766,8=2472767,8=2472768:tc=VMS-300 +market|arpanet:\ + :pn=8=2317437,8=2317438,8=2317447,8=2317447,8=2317448,8=2317449,\ + :8=2317450,8=2317451:tc=TOPS20-1200 +market300|arpanet300:\ + :pn=8=2311120,8=2311125,8=2311128:tc=TOPS20-300 +tip0|tip1200:tc=UNIX-1200: +tip300:tc=UNIX-300: +cu0|cu300:tc=UNIX-300: +cu1200:tc=UNIX-1200: +UNIX-300:\ + :dv=/dev/cua0:el=^D^U^C^S^Q^O@:du:at=df02:ie=#$%:oe=^D:br#300: +UNIX-1200:\ + :dv=/dev/cua1,/dev/cua2,/dev/cua4:el=^D^U^C^S^Q^O@:du:at=df03:\ + :ie=#$%:oe=^D:br#1200: +VMS-300|TOPS20-300:\ + :dv=/dev/cua0:el=^Z^U^C^S^Q^O:du:at=df02:ie=$@:oe=^Z:br#300: +VMS-1200|TOPS20-1200:\ + :dv=/dev/cua1,/dev/cua2,/dev/cua4:el=^Z^U^C^S^Q^O:du:at=df03:\ + :ie=$@:oe=^Z:br#1200: +-------------------------------------------------------------------- +The attributes are: + +dv device to use for the tty +el EOL marks (default is NULL) +du make a call flag (dial up) +pn phone numbers (@ =>'s search phones file; possibly taken from + PHONES environment variable) +at ACU type +ie input EOF marks (default is NULL) +oe output EOF string (default is NULL) +cu call unit (default is dv) +br baud rate (defaults to 300) +fs frame size (default is BUFSIZ) -- used in buffering writes + on receive operations +tc to continue a capability diff --git a/src/cmd/tip/remote.c b/src/cmd/tip/remote.c new file mode 100644 index 0000000..055e92f --- /dev/null +++ b/src/cmd/tip/remote.c @@ -0,0 +1,160 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#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 void +getremcap(host) + register char *host; +{ + int stat; + char tbuf[BUFSIZ]; + static char buf[BUFSIZ/2]; + char *bp = buf; + register char **p, ***q; + + if ((stat = rgetent(tbuf, 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; + } + fprintf(stderr, stat == 0 ? + "tip: unknown host %s\n" : + "tip: can't open host description file\n", host); + exit(3); + } + + for (p = capstrings, q = caps; *p != NULL; p++, q++) + if (**q == NULL) + **q = rgetstr(*p, &bp); + if (!BR && (BR = rgetnum("br")) < 0) + BR = DEFBR; + if ((FS = rgetnum("fs")) < 0) + FS = DEFFS; + if (DU < 0) + DU = 0; + else + DU = rgetflag("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 = rgetflag("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 (rgetflag("ra")) + boolean(value(RAISE)) = 1; + if (rgetflag("ec")) + boolean(value(ECHOCHECK)) = 1; + if (rgetflag("be")) + boolean(value(BEAUTIFY)) = 1; + if (rgetflag("nb")) + boolean(value(BEAUTIFY)) = 0; + if (rgetflag("sc")) + boolean(value(SCRIPT)) = 1; + if (rgetflag("tb")) + boolean(value(TABEXPAND)) = 1; + if (rgetflag("vb")) + boolean(value(VERBOSE)) = 1; + if (rgetflag("nv")) + boolean(value(VERBOSE)) = 0; + if (rgetflag("ta")) + boolean(value(TAND)) = 1; + if (rgetflag("nt")) + boolean(value(TAND)) = 0; + if (rgetflag("rw")) + boolean(value(RAWFTP)) = 1; + if (rgetflag("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 ((DL = rgetnum("dl")) < 0) + DL = 0; + if ((CL = rgetnum("cl")) < 0) + CL = 0; + if ((ET = rgetnum("et")) < 0) + 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 = strchr(next, ',')) == NULL) { + DV = next; + next = NOSTR; + } else { + *cp++ = '\0'; + DV = next; + next = cp; + } + return (DV); +} diff --git a/src/cmd/tip/tip.c b/src/cmd/tip/tip.c new file mode 100644 index 0000000..118c8a8 --- /dev/null +++ b/src/cmd/tip/tip.c @@ -0,0 +1,568 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +/* + * tip - UNIX link to other systems + * tip [-v] [-speed] system-name + * or + * cu phone-number [-s speed] [-l line] [-a acu] + */ +#include +#include +#include "tip.h" + +/* + * Baud rate mapping table + */ + +int bauds[] = { + 0, 50, 75, 150, 200, 300, 600, + 1200, 1800, 2400, 4800, 9600, 19200, + 38400, 57600, 115200, 230400, 460800, + 500000, 576000, 921600, 1000000, 1152000, + 1500000, 2000000, 2500000, 3000000, + 3500000, 4000000, -1 +}; + +int disc = 0; // OTTYDISC; /* tip normally runs this way */ +void intprompt(int i); +void timeout(int i); +void cleanup(int i); +char *sname(); +char PNbuf[256]; /* This limits the size of a number */ + +/* + * ****TIPIN TIPIN**** + */ +static void 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); + } +} + +int 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 = %ld bytes)\n", + (long) 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: + signal(SIGINT, cleanup); + signal(SIGQUIT, cleanup); + signal(SIGHUP, cleanup); + signal(SIGTERM, cleanup); + + if ((i = hunt(system)) == 0) { + printf("all ports busy\n"); + exit(3); + } + if (i == -1) { + printf("link down\n"); + delock(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 = "/etc/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))); + delock(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); + p = connect(); + if (p) { + printf("\07%s\n[EOT]\n", p); + daemon_uid(); + delock(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); + 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"); + pid = fork(); + if (pid) + tipin(); + else + tipout(); + /*NOTREACHED*/ + return 0; +} + +void cleanup(int i) +{ + daemon_uid(); + delock(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; + +void user_uid() +{ + if (uidswapped == 0) { + setregid(egid, gid); + setreuid(euid, uid); + uidswapped = 1; + } +} + +void daemon_uid() +{ + + if (uidswapped) { + setreuid(uid, euid); + setregid(gid, egid); + uidswapped = 0; + } +} + +void shell_uid() +{ + setreuid(uid, uid); + setregid(gid, gid); +} + +/* + * put the controlling keyboard into raw mode + */ +void raw() +{ + ioctl(0, TIOCSETP, &arg); + ioctl(0, TIOCSETC, &tchars); + ioctl(0, TIOCSLTC, <chars); + ioctl(0, TIOCSETD, (char *)&disc); +} + + +/* + * return keyboard to normal mode + */ +void 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. + */ +int prompt(s, p) + char *s; + register char *p; +{ + register char *b = p; + sig_t oint; + + stoprompt = 0; + oint = signal(SIGINT, intprompt); + oint = signal(SIGQUIT, SIG_IGN); + unraw(); + printf("%s", s); + if (setjmp(promptbuf) == 0) + while ((*p = getchar()) != EOF && *p != '\n') + p++; + *p = '\0'; + + raw(); + signal(SIGINT, oint); + signal(SIGQUIT, oint); + return (stoprompt || p == b); +} + +/* + * Interrupt service routine during prompting + */ +void intprompt(int i) +{ + + signal(SIGINT, SIG_IGN); + stoprompt = 1; + printf("\r\n"); + longjmp(promptbuf, 1); +} + +/* + * Escape handler -- + * called on recognition of ``escapec'' at the beginning of a line + */ +int escape() +{ + register int gch; + register esctable_t *p; + char c = character(value(ESCAPE)); + extern esctable_t etable[]; + + 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); +} + +int speed(n) + int n; +{ + register int *p; + + for (p = bauds; *p != -1; p++) + if (*p == n) + return (p - bauds); + return (NULL); +} + +int any(c, p) + register int c; + register char *p; +{ + while (p && *p) + if (*p++ == c) + return (1); + return (0); +} + +int 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) + int 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 + */ +void help(c) + char c; +{ + register esctable_t *p; + extern esctable_t etable[]; + + 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 + */ +void 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]; + +/* + * 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. + */ +void pwrite(fd, buf, n) + int fd; + char *buf; + register int n; +{ + //register int i; + register char *bp; + extern int errno; + + bp = buf; + //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. + */ +void setparity(defparity) + char *defparity; +{ + register int i; + char *parity; + extern char evenpartab[]; + + if (defparity != NOSTR && value(PARITY) == NOSTR) + value(PARITY) = defparity; + parity = value(PARITY); + for (i = 0; i < 0200; i++) + partab[i] = evenpartab[i]; + if (equal(parity, "even")) + return; + if (equal(parity, "odd")) { + for (i = 0; i < 0200; i++) + partab[i] ^= 0200; /* reverse bit 7 */ + return; + } + if (equal(parity, "none") || equal(parity, "zero")) { + for (i = 0; i < 0200; i++) + partab[i] &= ~0200; /* turn off bit 7 */ + return; + } + if (equal(parity, "one")) { + for (i = 0; i < 0200; i++) + partab[i] |= 0200; /* turn on bit 7 */ + return; + } + fprintf(stderr, "%s: unknown parity value\n", PA); + fflush(stderr); +} diff --git a/src/cmd/tip/tip.h b/src/cmd/tip/tip.h new file mode 100644 index 0000000..b9e92c8 --- /dev/null +++ b/src/cmd/tip/tip.h @@ -0,0 +1,266 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + * + * @(#)tip.h 5.3.1 (2.11BSD GTE) 1/1/94 + */ + +/* + * tip - terminal interface program + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CTRL +#undef CTRL +#endif +#define CTRL(c) ('c' & 037) + +/* + * 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 */ + +int BR; /* line speed for conversation */ +int 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 */ +int DL; /* line delay for file transfers to remote */ +int CL; /* char delay for file transfers to remote */ +int 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; + char zz_character; + int *zz_address; +} zzhack; + +#define value(v) vtable[v].v_value + +#define boolean(v) ((((zzhack *)(&(v))))->zz_boolean) +#define number(v) ((((zzhack *)(&(v))))->zz_number) +#define character(v) ((((zzhack *)(&(v))))->zz_character) +#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 */ + +/* + * 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 */ + +char *ctrl (int c); +char *connect (void); +void delock (char *s); +void pwrite (int fd, char *buf, int n); +int size (char *s); +void disconnect (char *reason); +void loginit (void); +void logent (char *group, char *num, char *acu, char *message); +int any (int c, char *p); +void raw (void); +void unraw (void); +int prompt (char *s, char *p); +void user_uid (void); +void shell_uid (void); +void daemon_uid (void); +void vinit (void); +void vlex (char *s); +int vstring (char *s, char *v); +void setparity (char *defparity); +int speed (int n); +int hunt (char *name); +void ttysetup (int speed); +int mlock (char *sys); +int rgetent (char *bp, char *name); +char *rgetstr (char *id, char **area); +int rgetnum (char *id); +int rgetflag (char *id); +void cumain (int argc, char *argv[]); +void tipout (void); +void setscript (void); +int escape (void); +void tipabort (char *msg); +void finish (void); + +#ifndef ACULOG +#define logent(a, b, c, d) +#define loginit() +#endif diff --git a/src/cmd/tip/tipout.c b/src/cmd/tip/tipout.c new file mode 100644 index 0000000..9f1e627 --- /dev/null +++ b/src/cmd/tip/tipout.c @@ -0,0 +1,120 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#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(int sig) +{ + 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(int sig) +{ + 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(int sig) +{ + if (boolean(value(SCRIPT)) && fscript != NULL) + fclose(fscript); + exit(0); +} + +void intSYS(int sig) +{ + boolean(value(BEAUTIFY)) = !boolean(value(BEAUTIFY)); + longjmp(sigbuf, 1); +} + +/* + * ****TIPOUT TIPOUT**** + */ +void tipout() +{ + char buf[BUFSIZ]; + register char *cp; + register int cnt; + extern int errno; + long 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(0); + /*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/src/cmd/tip/uucplock.c b/src/cmd/tip/uucplock.c new file mode 100644 index 0000000..39ac21f --- /dev/null +++ b/src/cmd/tip/uucplock.c @@ -0,0 +1,199 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +/* + * defs that come from uucp.h + */ +#define NAMESIZE 32 +#define FAIL -1 +#define SAME 0 +#define SLCKTIME 28800 /* system/device timeout (LCK.. files) in seconds (8 hours) */ +#define ASSERT(e, f, v) if (!(e)) {\ + fprintf(stderr, "AERROR - (%s) ", "e");\ + fprintf(stderr, f, v);\ + finish();\ +} + +#define LOCKPRE "/var/lock/LCK." + +/* + * This code is taken almost directly from uucp and follows the same + * conventions. This is important since uucp and tip should + * respect each others locks. + */ + + /* ulockf 3.2 10/26/79 11:40:29 */ +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAXLOCKS 10 /* maximum number of lock files */ +char *Lockfile[MAXLOCKS]; +int Nlocks = 0; + +void finish (void); + +/*** + * stlock(name) put name in list of lock files + * char *name; + * + * return codes: none + */ +static void +stlock(name) + char *name; +{ + char *p; + int i; + + for (i = 0; i < Nlocks; i++) { + if (Lockfile[i] == NULL) + break; + } + ASSERT(i < MAXLOCKS, "TOO MANY LOCKS %d", i); + if (i >= Nlocks) + i = Nlocks++; + p = calloc(strlen(name) + 1, sizeof (char)); + ASSERT(p != NULL, "CAN NOT ALLOCATE FOR %s", name); + strcpy(p, name); + Lockfile[i] = p; +} + +/* + * this stuff from pjw + * /usr/pjw/bin/recover - check pids to remove unnecessary locks + * + * onelock(pid,tempfile,name) makes lock a name + * on behalf of pid. Tempfile must be in the same + * file system as name. + * + * lock(pid,tempfile,names) either locks all the + * names or none of them + */ +static int +onelock(pid, tempfile, name) + char *tempfile, *name; +{ + int fd; + + fd = creat(tempfile, 0444); + if (fd < 0) + return (-1); + write(fd,(char *)&pid, sizeof(int)); + close(fd); + if (link(tempfile, name) < 0) { + unlink(tempfile); + return (-1); + } + unlink(tempfile); + return (0); +} + +/******* + * ulockf(file, atime) + * char *file; + * time_t atime; + * + * ulockf - this routine will create a lock file (file). + * If one already exists, the create time is checked for + * older than the age time (atime). + * If it is older, an attempt will be made to unlink it + * and create a new one. + * + * return codes: 0 | FAIL + */ +static int +ulockf(file, atime) + char *file; + time_t atime; +{ + struct stat stbuf; + time_t ptime; + int ret; + static int pid = -1; + static char tempfile[NAMESIZE]; + + if (pid < 0) { + pid = getpid(); + sprintf(tempfile, "/var/lock/LTMP.%d", pid); + } + if (onelock(pid, tempfile, file) == -1) { + /* lock file exists */ + /* get status to check age of the lock file */ + ret = stat(file, &stbuf); + if (ret != -1) { + time(&ptime); + if ((ptime - stbuf.st_ctime) < atime) { + /* file not old enough to delete */ + return (FAIL); + } + } + ret = unlink(file); + ret = onelock(pid, tempfile, file); + if (ret != 0) + return (FAIL); + } + stlock(file); + return (0); +} + +/*** + * rmlock(name) remove all lock files in list + * char *name; or name + * + * return codes: none + */ +static void +rmlock(name) + char *name; +{ + int i; + + for (i = 0; i < Nlocks; i++) { + if (Lockfile[i] == NULL) + continue; + if (name == NULL || strcmp(name, Lockfile[i]) == SAME) { + unlink(Lockfile[i]); + free(Lockfile[i]); + Lockfile[i] = NULL; + } + } +} + +/*** + * delock(s) remove a lock file + * char *s; + * + * return codes: 0 | FAIL + */ +void +delock(s) + char *s; +{ + char ln[30]; + + sprintf(ln, "%s.%s", LOCKPRE, s); + rmlock(ln); +} + +/*** + * mlock(sys) create system lock + * char *sys; + * + * return codes: 0 | FAIL + */ +int mlock(sys) + char *sys; +{ + char lname[30]; + sprintf(lname, "%s.%s", LOCKPRE, sys); + return (ulockf(lname, (time_t) SLCKTIME ) < 0 ? FAIL : 0); +} diff --git a/src/cmd/tip/value.c b/src/cmd/tip/value.c new file mode 100644 index 0000000..99f8555 --- /dev/null +++ b/src/cmd/tip/value.c @@ -0,0 +1,318 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "tip.h" + +#define MIDDLE 35 + +static int col = 0; + +/* + * Variable manipulation + */ +void 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) { + cp = getenv(p->v_name); + if (cp) + 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); + tp = strrchr(file, '\n'); + if (tp) + *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 (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 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); +} + +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"); + } +} + +static value_t * +vlookup(s) + register char *s; +{ + register value_t *p; + + for (p = vtable; p->v_name; p++) + if (equal(p->v_name, s) || (p->v_abrev && equal(p->v_abrev, s))) + return (p); + return (NULL); +} + +static void +vtoken(s) + register char *s; +{ + register value_t *p; + register char *cp; + char *expand(); + + cp = strchr(s, '='); + if (cp) { + *cp = '\0'; + p = vlookup(s); + if (p) { + 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 = strchr(s, '?'))) { + *cp = '\0'; + p = vlookup(s); + if (p && 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); +} + +void vlex(s) + register char *s; +{ + register value_t *p; + + if (equal(s, "all")) { + for (p = vtable; p->v_name; p++) + if (vaccess(p->v_access, READ)) + vprint(p); + } else { + register char *cp; + + do { + cp = vinterp(s, ' '); + if (cp) + cp++; + vtoken(s); + s = cp; + } while (s); + } + if (col > 0) { + printf("\r\n"); + col = 0; + } +} + +/* + * assign variable s with value v (for NUMBER or STRING or CHAR types) + */ +int 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/src/cmd/tip/vars.c b/src/cmd/tip/vars.c new file mode 100644 index 0000000..4772a51 --- /dev/null +++ b/src/cmd/tip/vars.c @@ -0,0 +1,79 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "tip.h" + +/* + * Definition of variables + */ +value_t vtable[] = { + { "beautify", BOOL, (READ|WRITE)< +#include +#include +#include + +int dontcreate; /* set if -c option */ +int force; /* set if -f option */ + +char *whoami = "touch"; + +main(argc,argv) + int argc; + char **argv; +{ + char *argp; + + dontcreate = 0; + force = 0; + for (argv++; **argv == '-'; argv++) { + for (argp = &(*argv)[1]; *argp; argp++) { + switch (*argp) { + case 'c': + dontcreate = 1; + break; + case 'f': + force = 1; + break; + default: + fprintf(stderr, "%s: bad option -%c\n", + whoami, *argp); + exit(1); + } + } + } + for (/*void*/; *argv; argv++) { + touch(*argv); + } +} + +touch(filename) + char *filename; +{ + struct stat statbuffer; + + if (stat(filename,&statbuffer) == -1) { + if (!dontcreate) { + readwrite(filename,0L); + } else { + fprintf(stderr, "%s: %s: does not exist\n", + whoami, filename); + } + return; + } + if ((statbuffer.st_mode & S_IFMT) != S_IFREG) { + fprintf(stderr, "%s: %s: can only touch regular files\n", + whoami, filename); + return; + } + if (!access(filename,4|2)) { + readwrite(filename,statbuffer.st_size); + return; + } + if (force) { + if (chmod(filename,0666)) { + fprintf(stderr, "%s: %s: couldn't chmod: ", + whoami, filename); + perror(""); + return; + } + readwrite(filename,statbuffer.st_size); + if (chmod(filename,statbuffer.st_mode)) { + fprintf(stderr, "%s: %s: couldn't chmod back: ", + whoami, filename); + perror(""); + return; + } + } else { + fprintf(stderr, "%s: %s: cannot touch\n", whoami, filename); + } +} + +readwrite(filename,size) + char *filename; + off_t size; +{ + int filedescriptor; + char first; + + if (size) { + filedescriptor = open(filename,2); + if (filedescriptor == -1) { +error: + fprintf(stderr, "%s: %s: ", whoami, filename); + perror(""); + return; + } + if (read(filedescriptor, &first, 1) != 1) { + goto error; + } + if (lseek(filedescriptor,0l,0) == -1) { + goto error; + } + if (write(filedescriptor, &first, 1) != 1) { + goto error; + } + } else { + filedescriptor = creat(filename,0666); + if (filedescriptor == -1) { + goto error; + } + } + if (close(filedescriptor) == -1) { + goto error; + } +} diff --git a/src/cmd/tr.c b/src/cmd/tr.c new file mode 100644 index 0000000..0490b6a --- /dev/null +++ b/src/cmd/tr.c @@ -0,0 +1,139 @@ +/* + * tr - transliterate data stream + */ +#include +#include + +int dflag = 0; +int sflag = 0; +int cflag = 0; +int save = 0; +char code[256]; +char squeez[256]; +char vect[256]; +struct string { int last, max; char *p; } string1, string2; + +main(argc,argv) +char **argv; +{ + register i; + int j; + register c, d; + char *compl; + int lastd; + + string1.last = string2.last = 0; + string1.max = string2.max = 0; + string1.p = string2.p = ""; + + if(--argc>0) { + argv++; + if(*argv[0]=='-'&&argv[0][1]!=0) { + while(*++argv[0]) + switch(*argv[0]) { + case 'c': + cflag++; + continue; + case 'd': + dflag++; + continue; + case 's': + sflag++; + continue; + } + argc--; + argv++; + } + } + if(argc>0) string1.p = argv[0]; + if(argc>1) string2.p = argv[1]; + for(i=0; i<256; i++) + code[i] = vect[i] = 0; + if(cflag) { + while(c = next(&string1)) + vect[c&0377] = 1; + j = 0; + for(i=1; i<256; i++) + if(vect[i]==0) vect[j++] = i; + vect[j] = 0; + compl = vect; + } + for(i=0; i<256; i++) + squeez[i] = 0; + lastd = 0; + for(;;){ + if(cflag) c = *compl++; + else c = next(&string1); + if(c==0) break; + d = next(&string2); + if(d==0) d = lastd; + else lastd = d; + squeez[d&0377] = 1; + code[c&0377] = dflag?1:d; + } + while(d = next(&string2)) + squeez[d&0377] = 1; + squeez[0] = 1; + for(i=0;i<256;i++) { + if(code[i]==0) code[i] = i; + else if(dflag) code[i] = 0; + } + + clearerr(stdout); + while((c=getc(stdin)) != EOF ) { + if(c == 0) continue; + if(c = code[c&0377]&0377) + if(!sflag || c!=save || !squeez[c&0377]) { + putchar(save = c); + if(ferror(stdout)) + exit(1); + } + } + exit(0); +} + +next(s) +struct string *s; +{ + +again: + if(s->max) { + if(s->last++ < s->max) + return(s->last); + s->max = s->last = 0; + } + if(s->last && *s->p=='-') { + nextc(s); + s->max = nextc(s); + if(s->max==0) { + s->p--; + return('-'); + } + if(s->max < s->last) { + s->last = s->max-1; + return('-'); + } + goto again; + } + return(s->last = nextc(s)); +} + +nextc(s) +struct string *s; +{ + register c, i, n; + + c = *s->p++; + if(c=='\\') { + i = n = 0; + while(i<3 && (c = *s->p)>='0' && c<='7') { + n = n*8 + c - '0'; + i++; + s->p++; + } + if(i>0) c = n; + else c = *s->p++; + } + if(c==0) *--s->p = 0; + return(c&0377); +} diff --git a/src/cmd/true.sh b/src/cmd/true.sh new file mode 100644 index 0000000..ca916d0 --- /dev/null +++ b/src/cmd/true.sh @@ -0,0 +1 @@ +exit 0 diff --git a/src/cmd/tsort.c b/src/cmd/tsort.c new file mode 100644 index 0000000..395bdc5 --- /dev/null +++ b/src/cmd/tsort.c @@ -0,0 +1,207 @@ +/* + * topological sort + * input is sequence of pairs of items (blank-free strings) + * nonidentical pair is a directed edge in graph + * identical pair merely indicates presence of node + * output is ordered list of items consistent with + * the partial ordering specified by the graph + */ +#include +#include + +/* the nodelist always has an empty element at the end to + * make it easy to grow in natural order + * states of the "live" field: + */ +#define DEAD 0 /* already printed*/ +#define LIVE 1 /* not yet printed*/ +#define VISITED 2 /*used only in findloop()*/ + +/* a predecessor list tells all the immediate + * predecessors of a given node + */ +struct predlist { + struct predlist *nextpred; + struct nodelist *pred; +}; + +struct nodelist { + struct nodelist *nextnode; + struct predlist *inedges; + char *name; + int live; +} firstnode = {NULL, NULL, NULL, DEAD}; + +struct nodelist *nindex(); +struct nodelist *findloop(); +struct nodelist *mark(); +char *empty = ""; + +/* the first for loop reads in the graph, + * the second prints out the ordering + */ +main(argc,argv) +char **argv; +{ + register struct predlist *t; + FILE *input = stdin; + register struct nodelist *i, *j; + int x; + char precedes[50], follows[50]; + if(argc>1) { + input = fopen(argv[1],"r"); + if(input==NULL) + error("cannot open ", argv[1]); + } + for(;;) { + x = fscanf(input,"%s%s",precedes, follows); + if(x==EOF) + break; + if(x!=2) + error("odd data",empty); + i = nindex(precedes); + j = nindex(follows); + if(i==j||present(i,j)) + continue; + t = (struct predlist *)malloc(sizeof(struct predlist)); + t->nextpred = j->inedges; + t->pred = i; + j->inedges = t; + } + for(;;) { + x = 0; /*anything LIVE on this sweep?*/ + for(i= &firstnode; i->nextnode!=NULL; i=i->nextnode) { + if(i->live==LIVE) { + x = 1; + if(!anypred(i)) + break; + } + } + if(x==0) + break; + if(i->nextnode==NULL) + i = findloop(); + printf("%s\n",i->name); + i->live = DEAD; + } +} + +/* is i present on j's predecessor list? + */ +present(i,j) +struct nodelist *i, *j; +{ + register struct predlist *t; + for(t=j->inedges; t!=NULL; t=t->nextpred) + if(t->pred==i) + return(1); + return(0); +} + +/* is there any live predecessor for i? + */ +anypred(i) +struct nodelist *i; +{ + register struct predlist *t; + for(t=i->inedges; t!=NULL; t=t->nextpred) + if(t->pred->live==LIVE) + return(1); + return(0); +} + +/* turn a string into a node pointer + */ +struct nodelist * +nindex(s) +register char *s; +{ + register struct nodelist *i; + register char *t; + for(i= &firstnode; i->nextnode!=NULL; i=i->nextnode) + if(cmp(s,i->name)) + return(i); + for(t=s; *t; t++) ; + t = malloc((unsigned)(t+1-s)); + i->nextnode = (struct nodelist *)malloc(sizeof(struct nodelist)); + if(i->nextnode==NULL||t==NULL) + error("too many items",empty); + i->name = t; + i->live = LIVE; + i->nextnode->nextnode = NULL; + i->nextnode->inedges = NULL; + i->nextnode->live = DEAD; + while(*t++ = *s++); + return(i); +} + +cmp(s,t) +register char *s, *t; +{ + while(*s==*t) { + if(*s==0) + return(1); + s++; + t++; + } + return(0); +} + +error(s,t) +char *s, *t; +{ + note(s,t); + exit(1); +} + +note(s,t) +char *s,*t; +{ + fprintf(stderr,"tsort: %s%s\n",s,t); +} + +/* given that there is a cycle, find some + * node in it + */ +struct nodelist * +findloop() +{ + register struct nodelist *i, *j; + for(i= &firstnode; i->nextnode!=NULL; i=i->nextnode) + if(i->live==LIVE) + break; + note("cycle in data",empty); + i = mark(i); + if(i==NULL) + error("program error",empty); + for(j= &firstnode; j->nextnode!=NULL; j=j->nextnode) + if(j->live==VISITED) + j->live = LIVE; + return(i); +} + +/* depth-first search of LIVE predecessors + * to find some element of a cycle; + * VISITED is a temporary state recording the + * visits of the search + */ +struct nodelist * +mark(i) +register struct nodelist *i; +{ + register struct nodelist *j; + register struct predlist *t; + if(i->live==DEAD) + return(NULL); + if(i->live==VISITED) + return(i); + i->live = VISITED; + for(t=i->inedges; t!=NULL; t=t->nextpred) { + j = mark(t->pred); + if(j!=NULL) { + note(i->name,empty); + return(j); + } + } + return(NULL); +} diff --git a/src/cmd/tty.c b/src/cmd/tty.c new file mode 100644 index 0000000..05ab425 --- /dev/null +++ b/src/cmd/tty.c @@ -0,0 +1,19 @@ +/* + * Type tty name + */ +#include +#include +#include + +main(argc, argv) +char **argv; +{ + register char *p; + + p = ttyname(0); + if(argc==2 && !strcmp(argv[1], "-s")) + ; + else + printf("%s\n", (p? p: "not a tty")); + exit(p? 0: 1); +} diff --git a/src/cmd/umount/Makefile b/src/cmd/umount/Makefile new file mode 100644 index 0000000..42af541 --- /dev/null +++ b/src/cmd/umount/Makefile @@ -0,0 +1,42 @@ +# +# Public Domain. 1996/1/15 - Steven Schultz +# +TOPSRC = $(shell cd ../../..; pwd) +include $(TOPSRC)/target.mk + +CFLAGS += -Werror + +SRCS = umount.c +OBJS = umount.o +MAN = umount.0 +MANSRC = umount.8 + +all: umount umount.0 + +umount: ${OBJS} + ${CC} ${LDFLAGS} -o umount.elf ${OBJS} ${LIBS} + ${OBJDUMP} -S umount.elf > umount.dis + ${SIZE} umount.elf + ${ELF2AOUT} umount.elf $@ && rm umount.elf + +umount.0: ${MANSRC} + ${MANROFF} ${MANSRC} > ${MAN} + +clean: + rm -f *.o *.elf ${MAN} umount *.elf *.dis tags *~ + +depend: ${SRCS} + mkdep ${CFLAGS} ${SRCS} + +install: all + cp ${MAN} ${DESTDIR}/share/man/cat8/ + install umount ${DESTDIR}/sbin/umount + +lint: ${SRCS} + lint -hax ${SRCS} + +tags: ${SRCS} + ctags ${SRCS} + +# DO NOT DELETE THIS LINE -- mkdep uses it. +# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY. diff --git a/src/cmd/umount/umount.8 b/src/cmd/umount/umount.8 new file mode 100644 index 0000000..ccd99e7 --- /dev/null +++ b/src/cmd/umount/umount.8 @@ -0,0 +1,115 @@ +.\" Copyright (c) 1980, 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. +.\" +.\" @(#)umount.8 8.1.1 (2.11BSD) 1996/1/16 +.\" +.TH UMOUNT 8 "January 16, 1996" +.UC 7 +.SH NAME +\fBumount\fP \- unmount file systems +.SH SYNOPSIS +.B umount +[ \fB\-fv\fP ] +\fIspecial\fP | \fInode\fP +.br +.B umount \-a +[ \fB\-fv\fP ] +[ \fB\-t\fP \fIufs\fP | \fIexternal_type\fP ] +.SH DESCRIPTION +The +.B umount +command +calls the +umount(2) +system call to remove a +.I "special device" +from the file system tree at the point +.IR node . +If either +.I special +or +.I node +are not provided, the appropriate information is taken from the +fstab(5) +file. +.PP +The options are as follows: +.sp +.TP 10 +.B \-a +All of the file systems described in +fstab(5) +are unmounted. +.TP 10 +.B \-f +The file system is forcibly unmounted. +Active special devices continue to work, +but all other files return errors if further accesses are attempted. +The root file system cannot be forcibly unmounted. +This is not currently implemented in 2.11BSD. +.TP 10 +\fB\-t\fP \fIufs\fP | \fIexternal type\fP +Is used to indicate the actions should only be taken on +filesystems of the specified type. +More than one type may be specified in a comma separated list. +The list of filesystem types can be prefixed with +.B no +to specify the filesystem types for which action should +.B not +be taken. +For example, the +.B umount +command: +.sp +umount -a -t nfs,mfs +.sp +umounts all filesystems of the type +NFS and MFS. +.sp +\fBNOTE\fP: Only UFS is supported by 2.11BSD. The example is for illustrative +purposes only. +.TP 10 +.B \-v +Verbose, additional information is printed out as each file system +is unmounted. +.SH FILES +.TP 15 +/etc/fstab +file system table +.SH SEE ALSO +umount(2), +fstab(5), +mount(8) +.SH HISTORY +A +.B umount +command appeared in +Version 6 AT&T UNIX. diff --git a/src/cmd/umount/umount.c b/src/cmd/umount/umount.c new file mode 100644 index 0000000..e7a2c51 --- /dev/null +++ b/src/cmd/umount/umount.c @@ -0,0 +1,299 @@ +/*- + * Copyright (c) 1980, 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. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +typedef enum { MNTON, MNTFROM } mntwhat; + +int fake, fflag, vflag, allflag, *typelist; +char *nfshost; + +int fsnametotype(); +char *getmntname(); +void maketypelist(); +int selected(); +int namematch(); +int umountall(); +int umountfs(); +void usage(); + +int +main(argc, argv) + int argc; + register char *argv[]; +{ + int ch, errs; + + /* Start disks transferring immediately. */ + sync(); + + while ((ch = getopt(argc, argv, "aFft:v")) != EOF) + switch (ch) { + case 'a': + allflag = 1; + break; + case 'F': + fake = 1; + break; + case 'f': +#ifdef notnow + fflag = MNT_FORCE; +#endif + break; + case 't': + maketypelist(optarg); + break; + case 'v': + vflag = 1; + break; + default: + usage(); + /* NOTREACHED */ + } + argc -= optind; + argv += optind; + + if (argc == 0 && !allflag || argc != 0 && allflag) + usage(); + + if (allflag) { + if (setfsent() == 0) + err(1, "%s", _PATH_FSTAB); + errs = umountall(); + } else + for (errs = 0; *argv != NULL; ++argv) + if (umountfs(*argv) == 0) + errs = 1; + exit(errs); +} + +int +umountall() +{ + register struct fstab *fs; + int rval, type; + register char *cp; + + while ((fs = getfsent()) != NULL) { + /* Ignore the root. */ + if (strcmp(fs->fs_file, "/") == 0) + continue; + /* + * !!! + * Historic practice: ignore unknown FSTAB_* fields. + */ + if (strcmp(fs->fs_type, FSTAB_RW) && + strcmp(fs->fs_type, FSTAB_RO) && + strcmp(fs->fs_type, FSTAB_RQ)) + continue; + /* If an unknown file system type, complain. */ + if ((type = fsnametotype(fs->fs_vfstype)) == MOUNT_NONE) { + warnx("%s: unknown mount type", fs->fs_vfstype); + continue; + } + if (!selected(type)) + continue; + + /* + * We want to unmount the file systems in the reverse order + * that they were mounted. So, we save off the file name + * in some allocated memory, and then call recursively. + */ + cp = (char *)malloc((size_t)strlen(fs->fs_file) + 1); + if (cp == NULL) + err(1, NULL); + (void)strcpy(cp, fs->fs_file); + rval = umountall(); + return (umountfs(cp) || rval); + } + return (0); +} + +int +umountfs(name) + char *name; +{ + struct stat sb; + int type; + register char *mntpt; + + if (stat(name, &sb) < 0) { + if (((mntpt = getmntname(name, MNTFROM, &type)) == NULL) && + ((mntpt = getmntname(name, MNTON, &type)) == NULL)) { + warnx("%s: not currently mounted", name); + return (1); + } + } else if ((sb.st_mode & S_IFMT) == S_IFBLK) { + if ((mntpt = getmntname(name, MNTON, &type)) == NULL) { + warnx("%s: not currently mounted", name); + return (1); + } + } else if ((sb.st_mode & S_IFMT) == S_IFDIR) { + mntpt = name; + if ((name = getmntname(mntpt, MNTFROM, &type)) == NULL) { + if (! allflag || vflag) + warnx("%s: not currently mounted", mntpt); + return (1); + } + } else { + warnx("%s: not a directory or special device", name); + return (1); + } + + if (!selected(type)) + return (0); + + if (vflag) + (void)printf("%s: unmount from %s\n", name, mntpt); + if (fake) + return (0); + + if (umount(name) < 0) { + warn("%s on %s", name, mntpt); + return (1); + } + + return (0); +} + +char * +getmntname(name, what, type) + char *name; + mntwhat what; + int *type; +{ + struct statfs *mntbuf; + register int i, mntsize; + + if ((mntsize = getmntinfo(&mntbuf, MNT_NOWAIT)) == 0) { + warn("getmntinfo"); + return (NULL); + } + for (i = 0; i < mntsize; i++) { + if ((what == MNTON) && !strcmp(mntbuf[i].f_mntfromname, name)) { + if (type) + *type = mntbuf[i].f_type; + return (mntbuf[i].f_mntonname); + } + if ((what == MNTFROM) && !strcmp(mntbuf[i].f_mntonname, name)) { + if (type) + *type = mntbuf[i].f_type; + return (mntbuf[i].f_mntfromname); + } + } + return (NULL); +} + +static enum { IN_LIST, NOT_IN_LIST } which; + +int +selected(type) + int type; +{ + /* If no type specified, it's always selected. */ + if (typelist == NULL) + return (1); + for (; *typelist != MOUNT_NONE; ++typelist) + if (type == *typelist) + return (which == IN_LIST ? 1 : 0); + return (which == IN_LIST ? 0 : 1); +} + +void +maketypelist(fslist) + register char *fslist; +{ + register int *av, i; + char *nextcp; + + if ((fslist == NULL) || (fslist[0] == '\0')) + errx(1, "empty type list"); + + /* + * XXX + * Note: the syntax is "noxxx,yyy" for no xxx's and + * no yyy's, not the more intuitive "noyyy,noyyy". + */ + if (fslist[0] == 'n' && fslist[1] == 'o') { + fslist += 2; + which = NOT_IN_LIST; + } else + which = IN_LIST; + + /* Count the number of types. */ + for (i = 0, nextcp = fslist; *nextcp != NULL; ++nextcp) + if (*nextcp == ',') + i++; + + /* Build an array of that many types. */ + if ((av = typelist = (int *)malloc((i + 2) * sizeof(int))) == NULL) + err(1, NULL); + for (i = 0; fslist != NULL; fslist = nextcp, ++i) { + if ((nextcp = strchr(fslist, ',')) != NULL) + *nextcp++ = '\0'; + av[i] = fsnametotype(fslist); + if (av[i] == MOUNT_NONE) + errx(1, "%s: unknown mount type", fslist); + } + /* Terminate the array. */ + av[i++] = MOUNT_NONE; +} + +int +fsnametotype(name) + char *name; +{ + static char *namelist[] = INITMOUNTNAMES; + register char **cp; + + for (cp = namelist; *cp; ++cp) + if (strcmp(name, *cp) == 0) + return (cp - namelist); + return (MOUNT_NONE); +} + +void +usage() +{ + (void)fprintf(stderr, + "usage: %s\n %s\n", + "umount [-fv] [-t fstypelist] special | node", + "umount -a[fv] [-t fstypelist]"); + exit(1); +} diff --git a/src/cmd/uname/Makefile b/src/cmd/uname/Makefile new file mode 100644 index 0000000..3615de3 --- /dev/null +++ b/src/cmd/uname/Makefile @@ -0,0 +1,42 @@ +# +# Public Domain. 2/4/1995 - Steven Schultz +# +TOPSRC = $(shell cd ../../..; pwd) +include $(TOPSRC)/target.mk + +CFLAGS += -Werror + +SRCS = uname.c +OBJS = uname.o +MAN = uname.0 +MANSRC = uname.1 + +all: uname uname.0 + +uname: ${OBJS} + ${CC} ${LDFLAGS} -o uname.elf ${OBJS} ${LIBS} + ${OBJDUMP} -S uname.elf > uname.dis + ${SIZE} uname.elf + ${ELF2AOUT} uname.elf $@ && rm uname.elf + +uname.0: ${MANSRC} + ${MANROFF} ${MANSRC} > ${MAN} + +clean: + rm -f *.o *.elf ${MAN} uname *.elf *.dis tags *~ + +depend: ${SRCS} + mkdep ${CFLAGS} ${SRCS} + +install: all + cp ${MAN} ${DESTDIR}/share/man/cat1/ + install uname ${DESTDIR}/bin/uname + +lint: ${SRCS} + lint -hax ${SRCS} + +tags: ${SRCS} + ctags ${SRCS} + +# DO NOT DELETE THIS LINE -- mkdep uses it. +# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY. diff --git a/src/cmd/uname/uname.1 b/src/cmd/uname/uname.1 new file mode 100644 index 0000000..c746830 --- /dev/null +++ b/src/cmd/uname/uname.1 @@ -0,0 +1,90 @@ +.\" 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.1 (2.11BSD GTE) 2/4/95 +.\" +.TH UNAME 1 "February 4, 1995" +.UC 4 +.SH NAME +uname \- display information about the system +.SH SYNOPSIS +.B uname [\-amnrsv] +.SH DESCRIPTION +The +.B 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: +.TP 10 +\-a +Behave as though the options +\-m, \-n, \-r , \-s, and \-v were specified. +.TP 10 +\-m +Write the type of the current hardware platform to standard output. +.TP 10 +\-n +Write the name of the system to standard output. +.TP 10 +\-r +Write the current release level of the operating system +to standard output. +.TP 10 +\-s +Write the name of the operating system implementation to standard output. +.TP 10 +\-v +Write the version level of this release of the operating system +to standard output. +.PP +If the +\-a +flag is specified, or multiple flags are specified, all +output is written on a single line, separated by spaces. +.PP +The +.B uname +utility exits 0 on success, and >0 if an error occurs. +.SH SEE ALSO +sysctl(8), sysctl(3), uname(3) +.SH HISTORY +The +.B uname +command appeared in 4.4BSD. +.SH STANDARDS +The +.Nm uname +command is expected to conform to the +IEEE Std1003.2 (``POSIX'') +specification. diff --git a/src/cmd/uname/uname.c b/src/cmd/uname/uname.c new file mode 100644 index 0000000..e4a56f8 --- /dev/null +++ b/src/cmd/uname/uname.c @@ -0,0 +1,152 @@ +/*- + * 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. + */ +#include +#include +#include +#include + +extern int optind; + +void usage(); + +int +main(argc, argv) + int argc; + char *argv[]; +{ +#define MFLAG 0x01 +#define NFLAG 0x02 +#define RFLAG 0x04 +#define SFLAG 0x08 +#define VFLAG 0x10 + register u_int flags; + int ch, mib[2]; + size_t len, tlen; + register char *p, *prefix; + char 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/src/cmd/uniq.c b/src/cmd/uniq.c new file mode 100644 index 0000000..9e0fa76 --- /dev/null +++ b/src/cmd/uniq.c @@ -0,0 +1,144 @@ +/* + * Deal with duplicated lines in a file + */ +#include +#include +#include + +int fields; +int letters; +int linec; +char mode; +int uniq; +char *skip(); + +main(argc, argv) +int argc; +char *argv[]; +{ + static char b1[1000], b2[1000]; + + while(argc > 1) { + if(*argv[1] == '-') { + if (isdigit(argv[1][1])) + fields = atoi(&argv[1][1]); + else mode = argv[1][1]; + argc--; + argv++; + continue; + } + if(*argv[1] == '+') { + letters = atoi(&argv[1][1]); + argc--; + argv++; + continue; + } + if (freopen(argv[1], "r", stdin) == NULL) + printe("cannot open %s\n", argv[1]); + break; + } + if(argc > 2 && freopen(argv[2], "w", stdout) == NULL) + printe("cannot create %s\n", argv[2]); + + if(gline(b1)) + exit(0); + for(;;) { + linec++; + if(gline(b2)) { + pline(b1); + exit(0); + } + if(!equal(b1, b2)) { + pline(b1); + linec = 0; + do { + linec++; + if(gline(b1)) { + pline(b2); + exit(0); + } + } while(equal(b1, b2)); + pline(b2); + linec = 0; + } + } +} + +gline(buf) +register char buf[]; +{ + register c; + + while((c = getchar()) != '\n') { + if(c == EOF) + return(1); + *buf++ = c; + } + *buf = 0; + return(0); +} + +pline(buf) +register char buf[]; +{ + + switch(mode) { + + case 'u': + if(uniq) { + uniq = 0; + return; + } + break; + + case 'd': + if(uniq) break; + return; + + case 'c': + printf("%4d ", linec); + } + uniq = 0; + fputs(buf, stdout); + putchar('\n'); +} + +equal(b1, b2) +register char b1[], b2[]; +{ + register char c; + + b1 = skip(b1); + b2 = skip(b2); + while((c = *b1++) != 0) + if(c != *b2++) return(0); + if(*b2 != 0) + return(0); + uniq++; + return(1); +} + +char * +skip(s) +register char *s; +{ + register nf, nl; + + nf = nl = 0; + while(nf++ < fields) { + while(*s == ' ' || *s == '\t') + s++; + while( !(*s == ' ' || *s == '\t' || *s == 0) ) + s++; + } + while(nl++ < letters && *s != 0) + s++; + return(s); +} + +printe(p,s) +char *p,*s; +{ + fprintf(stderr, p, s); + exit(1); +} diff --git a/src/cmd/unixbench/Makefile b/src/cmd/unixbench/Makefile new file mode 100644 index 0000000..eb6c991 --- /dev/null +++ b/src/cmd/unixbench/Makefile @@ -0,0 +1,331 @@ +############################################################################## +# UnixBench v4.0 +# Based on The BYTE UNIX Benchmarks - Release 3 +# Module: Makefile SID: 3.9 5/15/91 19:30:15 +# +############################################################################## +# Bug reports, patches, comments, suggestions should be sent to: +# David C Niemi +# +# Original Contacts at Byte Magazine: +# Ben Smith or Tom Yager at BYTE Magazine +# bensmith@bytepb.byte.com tyager@bytepb.byte.com +# +############################################################################## +# Modification Log: 7/28/89 cleaned out workload files +# 4/17/90 added routines for installing from shar mess +# 7/23/90 added compile for dhrystone version 2.1 +# (this is not part of Run file. still use old) +# removed HZ from everything but dhry. +# HZ is read from the environment, if not +# there, you must define it in this file +# 10/30/90 moved new dhrystone into standard set +# new pgms (dhry included) run for a specified +# time rather than specified number of loops +# 4/5/91 cleaned out files not needed for +# release 3 -- added release 3 files -ben +# 10/22/97 added compiler options for strict ANSI C +# checking for gcc and DEC's cc on +# Digital Unix 4.x (kahn@zk3.dec.com) +############################################################################## +TOPSRC = $(shell cd ../../..; pwd) +include $(TOPSRC)/target.mk + +ID="@(#)Makefile:3.9 -- 5/15/91 19:30:15"; +SHELL = /bin/sh +HZ = 20 +CFLAGS += -DTIME +#CC=gcc + +## For Linux 486/Pentium, GCC 2.7.x and 2.8.x +#OPTON = -O2 -fomit-frame-pointer -fforce-addr -fforce-mem -ffast-math \ +# -m486 -malign-loops=2 -malign-jumps=2 -malign-functions=2 +## For Linux, GCC previous to 2.7.0 +#OPTON = -O2 -fomit-frame-pointer -fforce-addr -fforce-mem -ffast-math -m486 + +#OPTON = -O2 -fomit-frame-pointer -fforce-addr -fforce-mem -ffast-math \ +# -m386 -malign-loops=1 -malign-jumps=1 -malign-functions=1 + +## For Solaris 2, or general-purpose GCC 2.7.x +OPTON = -O2 -fomit-frame-pointer -fforce-addr -ffast-math -Wall + +## Very generic +#OPTON = -O + +## For Digital Unix v4.x, with DEC cc v5.x +#OPTON = -O4 +#CFLAGS = -DTIME -std1 -verbose -w0 + +## generic gcc CFLAGS. -DTIME must be included +CFLAGS = -DTIME -Wall -pedantic -ansi + +# local directories +PROGDIR = ./pgms +SRCDIR = ./src +TESTDIR = ./testdir +RESULTDIR = ./results +TMPDIR = ./tmp +# other directories +INCLDIR = /usr/include +LIBDIR = /lib +SCRIPTS = unixbench.logo cleanup.sh \ + fs.awk multi.sh tst.sh index.sh index.base \ + index.awk loops.awk loopm.awk mwips.awk \ + report.sh report.awk perlbench +SOURCES = arith.c big.c context1.c \ + dummy.c execl.c \ + fstime.c getopt.c hanoi.c \ + pipe.c spawn.c limit.c \ + syscall.c looper.c timeit.c \ + dhry_1.c dhry_2.c dhry.h +TESTS = sort.src cctest.c dc.dat +RESULTS = reports.shar +BINS = $(PROGDIR)/arithoh $(PROGDIR)/register $(PROGDIR)/short \ + $(PROGDIR)/int $(PROGDIR)/long $(PROGDIR)/float $(PROGDIR)/double \ + $(PROGDIR)/hanoi $(PROGDIR)/syscall $(PROGDIR)/context1 \ + $(PROGDIR)/pipe $(PROGDIR)/spawn $(PROGDIR)/execl \ + $(PROGDIR)/dhry2 $(PROGDIR)/dhry2reg $(PROGDIR)/looper \ + $(PROGDIR)/fstime $(PROGDIR)/fsbuffer $(PROGDIR)/fsdisk \ + $(PROGDIR)/whetstone-double +## These compile only on some platforms... +# $(PROGDIR)/poll $(PROGDIR)/poll2 $(PROGDIR)/select +REQD = $(BINS) $(PROGDIR)/unixbench.logo $(PROGDIR)/cleanup.sh \ + $(PROGDIR)/fs.awk $(PROGDIR)/multi.sh \ + $(PROGDIR)/tst.sh $(PROGDIR)/index.sh $(PROGDIR)/index.base \ + $(PROGDIR)/index.awk $(PROGDIR)/loops.awk $(PROGDIR)/loopm.awk \ + $(PROGDIR)/mwips.awk $(PROGDIR)/lps.awk $(PROGDIR)/perlbench \ + $(PROGDIR)/report.sh $(PROGDIR)/report.awk \ + $(TESTDIR)/sort.src $(TESTDIR)/cctest.c $(TESTDIR)/dc.dat + +# ######################### the big ALL ############################ +all: distr programs +## Ick!!! What is this about??? How about let's not chmod everything bogusly. +# @chmod 744 * $(SRCDIR)/* $(PROGDIR)/* $(TESTDIR)/* $(DOCDIR)/* + +# ####################### a check for Run ###################### +check: $(REQD) + make all +# ############################################################## +# distribute the files out to subdirectories if they are in this one +distr: + @echo "Checking distribution of files" +# scripts + @if test ! -d $(PROGDIR) \ + ; then \ + mkdir $(PROGDIR) \ + ; mv $(SCRIPTS) $(PROGDIR) \ + ; else \ + echo "$(PROGDIR) exists" \ + ; fi +# C sources + @if test ! -d $(SRCDIR) \ + ; then \ + mkdir $(SRCDIR) \ + ; mv $(SOURCES) $(SRCDIR) \ + ; else \ + echo "$(SRCDIR) exists" \ + ; fi +# test data + @if test ! -d $(TESTDIR) \ + ; then \ + mkdir $(TESTDIR) \ + ; mv $(TESTS) $(TESTDIR) \ + ; else \ + echo "$(TESTDIR) exists" \ + ; fi +# temporary work directory + @if test ! -d $(TMPDIR) \ + ; then \ + mkdir $(TMPDIR) \ + ; else \ + echo "$(TMPDIR) exists" \ + ; fi +# directory for results + @if test ! -d $(RESULTDIR) \ + ; then \ + mkdir $(RESULTDIR) \ + ; mv $(RESULTS) $(RESULTDIR) \ + ; else \ + echo "$(RESULTDIR) exists" \ + ; fi + +programs: $(BINS) + +# Individual programs +$(PROGDIR)/arithoh: $(SRCDIR)/arith.c + ${CC} ${LDFLAGS} -o $@.elf $< ${LIBS} ${OPTON} -Darithoh + ${OBJDUMP} -S $@.elf > $@.dis + ${SIZE} $@.elf + ${ELF2AOUT} $@.elf $@ + +$(PROGDIR)/register: $(SRCDIR)/arith.c + ${CC} ${LDFLAGS} -o $@.elf $< ${LIBS} ${OPTON} -Ddatum='register int' + ${OBJDUMP} -S $@.elf > $@.dis + ${SIZE} $@.elf + ${ELF2AOUT} $@.elf $@ + +$(PROGDIR)/short: $(SRCDIR)/arith.c + ${CC} ${LDFLAGS} -o $@.elf $< ${LIBS} ${OPTON} -Ddatum=short + ${OBJDUMP} -S $@.elf > $@.dis + ${SIZE} $@.elf + ${ELF2AOUT} $@.elf $@ + +$(PROGDIR)/int: $(SRCDIR)/arith.c + ${CC} ${LDFLAGS} -o $@.elf $< ${LIBS} ${OPTON} -Ddatum=int + ${OBJDUMP} -S $@.elf > $@.dis + ${SIZE} $@.elf + ${ELF2AOUT} $@.elf $@ + +$(PROGDIR)/long: $(SRCDIR)/arith.c + ${CC} ${LDFLAGS} -o $@.elf $< ${LIBS} ${OPTON} -Ddatum=long + ${OBJDUMP} -S $@.elf > $@.dis + ${SIZE} $@.elf + ${ELF2AOUT} $@.elf $@ + +$(PROGDIR)/float: $(SRCDIR)/arith.c + ${CC} ${LDFLAGS} -o $@.elf $< ${LIBS} ${OPTON} -Ddatum=float + ${OBJDUMP} -S $@.elf > $@.dis + ${SIZE} $@.elf + ${ELF2AOUT} $@.elf $@ + +$(PROGDIR)/double: $(SRCDIR)/arith.c + ${CC} ${LDFLAGS} -o $@.elf $< ${LIBS} ${OPTON} -Ddatum=double + ${OBJDUMP} -S $@.elf > $@.dis + ${SIZE} $@.elf + ${ELF2AOUT} $@.elf $@ + + + +$(PROGDIR)/whetstone-double: $(SRCDIR)/whets.c + ${CC} ${LDFLAGS} -o $@.elf $< ${LIBS} ${OPTON} -DDP -DUNIX -DUNIXBENCH -lm -lc + ${OBJDUMP} -S $@.elf > $@.dis + ${SIZE} $@.elf + ${ELF2AOUT} $@.elf $@ + +$(PROGDIR)/hanoi: $(SRCDIR)/hanoi.c + ${CC} ${LDFLAGS} -o $@.elf $< ${LIBS} ${OPTON} + ${OBJDUMP} -S $@.elf > $@.dis + ${SIZE} $@.elf + ${ELF2AOUT} $@.elf $@ + + +$(PROGDIR)/poll: $(SRCDIR)/time-polling.c + ${CC} ${LDFLAGS} -o $@.elf $< ${LIBS} ${OPTON} + ${OBJDUMP} -S $@.elf > $@.dis + ${SIZE} $@.elf + ${ELF2AOUT} $@.elf $@ + +$(PROGDIR)/poll2: $(SRCDIR)/time-polling.c + ${CC} ${LDFLAGS} -o $@.elf $< ${LIBS} ${OPTON} + ${OBJDUMP} -S $@.elf > $@.dis + ${SIZE} $@.elf + ${ELF2AOUT} $@.elf $@ + $(CC) -DHAS_POLL2 -DUNIXBENCH -o $(PROGDIR)/poll2 ${CFLAGS} ${OPTON} $(SRCDIR)/time-polling.c + +$(PROGDIR)/select: $(SRCDIR)/time-polling.c + ${CC} ${LDFLAGS} -o $@.elf $< ${LIBS} ${OPTON} + ${OBJDUMP} -S $@.elf > $@.dis + ${SIZE} $@.elf + ${ELF2AOUT} $@.elf $@ + $(CC) -DHAS_SELECT -DUNIXBENCH -o $(PROGDIR)/select ${CFLAGS} ${OPTON} $(SRCDIR)/time-polling.c + +$(PROGDIR)/fstime: $(SRCDIR)/fstime.c + ${CC} ${LDFLAGS} -o $@.elf $< ${LIBS} ${OPTON} -Dawk=1 + ${OBJDUMP} -S $@.elf > $@.dis + ${SIZE} $@.elf + ${ELF2AOUT} $@.elf $@ + +$(PROGDIR)/fsbuffer: $(SRCDIR)/fstime.c + ${CC} ${LDFLAGS} -o $@.elf $< ${LIBS} ${OPTON} -Dawk=1 -DFSBUFFER + ${OBJDUMP} -S $@.elf > $@.dis + ${SIZE} $@.elf + ${ELF2AOUT} $@.elf $@ + +$(PROGDIR)/fsdisk: $(SRCDIR)/fstime.c + ${CC} ${LDFLAGS} -o $@.elf $< ${LIBS} ${OPTON} -Dawk=1 -DFSDISK + ${OBJDUMP} -S $@.elf > $@.dis + ${SIZE} $@.elf + ${ELF2AOUT} $@.elf $@ + +$(PROGDIR)/syscall: $(SRCDIR)/syscall.c + ${CC} ${LDFLAGS} -o $@.elf $< ${LIBS} ${OPTON} + ${OBJDUMP} -S $@.elf > $@.dis + ${SIZE} $@.elf + ${ELF2AOUT} $@.elf $@ + +$(PROGDIR)/context1: $(SRCDIR)/context1.c + ${CC} ${LDFLAGS} -o $@.elf $< ${LIBS} ${OPTON} + ${OBJDUMP} -S $@.elf > $@.dis + ${SIZE} $@.elf + ${ELF2AOUT} $@.elf $@ + +$(PROGDIR)/pipe: $(SRCDIR)/pipe.c + ${CC} ${LDFLAGS} -o $@.elf $< ${LIBS} ${OPTON} + ${OBJDUMP} -S $@.elf > $@.dis + ${SIZE} $@.elf + ${ELF2AOUT} $@.elf $@ + +$(PROGDIR)/spawn: $(SRCDIR)/spawn.c + ${CC} ${LDFLAGS} -o $@.elf $< ${LIBS} ${OPTON} + ${OBJDUMP} -S $@.elf > $@.dis + ${SIZE} $@.elf + ${ELF2AOUT} $@.elf $@ + +$(PROGDIR)/execl: $(SRCDIR)/execl.c $(SRCDIR)/big.c + ${CC} ${LDFLAGS} -o $@.elf $< ${LIBS} ${OPTON} + ${OBJDUMP} -S $@.elf > $@.dis + ${SIZE} $@.elf + ${ELF2AOUT} $@.elf $@ + +$(PROGDIR)/dhry2: $(SRCDIR)/dhry_1.c $(SRCDIR)/dhry_2.c $(SRCDIR)/dhry.h + cd $(SRCDIR); $(CC) -c ${CFLAGS} -DHZ=${HZ} ${OPTON} dhry_1.c + cd $(SRCDIR); $(CC) -c ${CFLAGS} -DHZ=${HZ} ${OPTON} dhry_2.c + ${CC} ${LDFLAGS} -o $@.elf $(SRCDIR)/dhry_1.o $(SRCDIR)/dhry_2.o ${LIBS} ${OPTON} + ${OBJDUMP} -S $@.elf > $@.dis + ${SIZE} $@.elf + ${ELF2AOUT} $@.elf $@ + cd $(SRCDIR); rm -f dhry_1.o dhry_2.o + +$(PROGDIR)/dhry2reg: $(SRCDIR)/dhry_1.c $(SRCDIR)/dhry_2.c $(SRCDIR)/dhry.h + cd $(SRCDIR); $(CC) -c ${CFLAGS} -DHZ=${HZ} ${OPTON} dhry_1.c -DREG=register + cd $(SRCDIR); $(CC) -c ${CFLAGS} -DHZ=${HZ} ${OPTON} dhry_2.c -DREG=register + ${CC} ${LDFLAGS} -o $@.elf $(SRCDIR)/dhry_1.o $(SRCDIR)/dhry_2.o ${LIBS} ${OPTON} + ${OBJDUMP} -S $@.elf > $@.dis + ${SIZE} $@.elf + ${ELF2AOUT} $@.elf $@ + cd $(SRCDIR); rm -f dhry_1.o dhry_2.o + + +dhry2reg: $(SRCDIR)/dhry_1.c $(SRCDIR)/dhry_2.c $(SRCDIR)/dhry.h + cd $(SRCDIR); $(CC) -c ${CFLAGS} -DHZ=${HZ} ${OPTON} $(OPT3) dhry_1.c -DREG=register + cd $(SRCDIR); $(CC) -c ${CFLAGS} -DHZ=${HZ} ${OPTON} $(OPT3) dhry_2.c -DREG=register + ${CC} ${LDFLAGS} -o $@.elf $(SRCDIR)/dhry_1.o $(SRCDIR)/dhry_2.o ${LIBS} ${OPTON} + ${OBJDUMP} -S $@.elf > $@.dis + ${SIZE} $@.elf + ${ELF2AOUT} $@.elf $@ + cd $(SRCDIR); rm -f dhry_1.o dhry_2.o + +$(PROGDIR)/looper: $(SRCDIR)/looper.c + ${CC} ${LDFLAGS} -o $@.elf $< ${LIBS} ${OPTON} + ${OBJDUMP} -S $@.elf > $@.dis + ${SIZE} $@.elf + ${ELF2AOUT} $@.elf $@ + +# Run the benchmarks and create the reports +run: + sh ./Run + +report: + sh pgms/report.sh results/log > results/report + sh pgms/index.sh pgms/index.base results/log >> results/report + cat results/report + +clean: + rm -f $(BINS) pgms/*.elf pgms/*.dis + +install: + mkdir -p $(DESTDIR)/share/unixbench + cp $(REQD) $(DESTDIR)/share/unixbench + cp Run $(DESTDIR)/share/unixbench + +## END ## diff --git a/src/cmd/unixbench/README b/src/cmd/unixbench/README new file mode 100644 index 0000000..00f98df --- /dev/null +++ b/src/cmd/unixbench/README @@ -0,0 +1,303 @@ +Version 4.1.0 -- 1997.08.26 + +================================================================ +To use Unixbench: + + make + Run + +================================================================ +You may run individual benchmark programs and groups of programs. +There are also a few options. + + Run [ ...] [ ...] [-qvd] + + -q quiet no output to standard out + -v verbose extra output to standard out + -d debug Run is displayed as it is run + - Use as maximum number of iterations + (e.g. Run -1 index) + + GROUP BENCHMARK EXPLANATION SOURCE + -------- ----------- -------------------- ------------- + index only those need for + generating the BYTE + index + + dhry2reg dhrystone 2 with regs src/dhry_1.c + src/dhry_2.c + src/dhry.h + whetstone-double double-prec. whetstone src/whets.c + execl execl call src/execl.c + src/big.c + fstime filesystem throughput src/fstime.c + fsbuffer filesystem throughput src/fstime.c + fsdisk filesystem throughput src/fstime.c + pipe pipe throughput src/pipe.c + context1 pipe context switch src/context1.c + spawn process creation src/spawn.c + shell load system with pgms/multi.sh + concurrent shell pgms/tst.sh + scripts src/looper.c + syscall system call overhead src/syscall.c + + arithmetic + whetstone-double double-prec. whetstone src/whets.c + arithoh arithmetic overhead src/arith.c + register register arithmetic src/arith.c + short short arithmetic src/arith.c + int int arithmetic src/arith.c + long long arithmetic src/arith.c + float float arithmetic src/arith.c + double double arithmetic src/arith.c + + system + syscall system call overhead src/syscall.c + pipe pipe throughput src/pipe.c + context1 pipe context switch src/context1.c + spawn process creation src/spawn.c + execl execl call src/execl.c + fstime filesystem throughput src/fstime.c + fsbuffer filesystem throughput src/fstime.c + fsdisk filesystem throughput src/fstime.c + shell load system with pgms/multi.sh + concurrent shell pgms/tst.sh + scripts src/looper.c + + misc + C compile and link /bin/cc + src/looper.c + dc calculations with dc testdir/dc.dat + src/looper.c + hanoi recursion src/hanoi.c + src/looper.c + + dhry + dhry2 dhrystone 2 w/o regs src/dhry_1.c + src/dhry_2.c + src/dhry.h + dhry2reg dhrystone 2 with regs src/dhry_1.c + src/dhry_2.c + src/dhry.h + shell load system with pgms/multi.sh + concurrent shell pgms/tst.sh + scripts + ** Most C programs also include src/timeit.c + +===================== RELEASE NOTES ===================================== + +v4.1.0 + +Double precision Whetstone put in place instead of the old "double" benchmark. + +Removal of some obsolete files. + +"system" suite adds shell8. + +perlbench and poll added as "exhibition" (non-index) benchmarks. + +Incorporates several suggestions by Andre Derrick Balsa + +Code cleanups to reduce compiler warnings by David C Niemi +and Andy Kahn ; Digital Unix options by Andy Kahn. + +======================== Jun 97 ========================== + +v4.0.1 + +Minor change to fstime.c to fix overflow problems on fast machines. Counting +is now done in units of 256 (smallest BUFSIZE) and unsigned longs are used, +giving another 23 dB or so of headroom ;^) Results should be virtually +identical aside from very small rounding errors. + +======================== Dec 95 ========================== + +v4.0 + +Byte no longer seems to have anything to do with this benchmark, and I was +unable to reach any of the original authors; so I have taken it upon myself +to clean it up. + +This is version 4. Major assumptions made in these benchmarks have changed +since they were written, but they are nonetheless popular (particularly for +measuring hardware for Linux). Some changes made: + +- The biggest change is to put a lot more operating system-oriented + tests into the index. I experimented for a while with a decibel-like + logarithmic scale, but finally settled on using a geometric mean for + the final index (the individual scores are a normalized, and their + logs are averaged; the resulting value is exponentiated). + + "George", certain SPARCstation 20-61 with 128 MB RAM, a SPARC Storage + Array, and Solaris 2.3 is my new baseline; it is rated at 10.0 in each + of the index scores for a final score of 10.0. + + Overall I find the geometric averaging is a big improvement for + avoiding the skew that was once possible (e.g. a Pentium-75 which got + 40 on the buggy version of fstime, such that fstime accounted for over + half of its total score and hence wildly skewed its average). + + I also expect that the new numbers look different enough from the old + ones that no one is too likely to casually mistake them for each other. + + I am finding new SPARCs running Solaris 2.4 getting about 15-20, and + my 486 DX2-66 Compaq running Linux 1.3.45 got a 9.1. It got + understandably poor scores on CPU and FPU benchmarks (a horrible + 1.8 on "double" and 1.3 on "fsdisk"); but made up for it by averaging + over 20 on the OS-oriented benchmarks. The Pentium-75 running + Linux gets about 20 (and it *still* runs Windows 3.1 slowly. Oh well). + +- It is difficult to get a modern compiler to even consider making + dhry2 without registers, short of turning off *all* optimizations. + This is also not a terribly meaningful test, even if it were possible, + as noone compiles without registers nowadays. Replaced this benchmark + with dhry2reg in the index, and dropped it out of usage in general as + it is so hard to make a legitimate one. + +- fstime: this had some bugs when compiled on modern systems which return + the number of bytes read/written for read(2)/write(2) calls. The code + assumed that a negative return code was given for EOF, but most modern + systems return 0 (certainly on SunOS 4, Solaris2, and Linux, which is + what counts for me). The old code yielded wildly inflated read scores, + would eat up tens of MB of disk space on fast systems, and yielded + roughly 50% lower than normal copy scores than it should have. + + Also, it counted partial blocks *fully*; made it count the proportional + part of the block which was actually finished. + + Made bigger and smaller variants of fstime which are designed to beat + up the disk I/O and the buffer cache, respectively. Adjusted the + sleeps so that they are short for short benchmarks. + +- Instead of 1,2,4, and 8-shell benchmarks, went to 1, 8, and 16 to + give a broader range of information (and to run 1 fewer test). + The only real problem with this is that not many iterations get + done with 16 at a time on slow systems, so there are some significant + rounding errors; 8 therefore still used for the benchmark. There is + also the problem that the last (uncompleted) loop is counted as a full + loop, so it is impossible to score below 1.0 lpm (which gave my laptop + a break). Probably redesigning Shell to do each loop a bit more + quickly (but with less intensity) would be a good idea. + + This benchmark appears to be very heavily influenced by the speed + of the loader, by which shell is being used as /bin/sh, and by how + well-compiled some of the common shell utilities like grep, sed, and + sort are. With a consistent tool set it is also a good indicator of + the bandwidth between main memory and the CPU (e.g. Pentia score about + twice as high as 486es due to their 64-bit bus). Small, sometimes + broken shells like "ash-linux" do particularly well here, while big, + robust shells like bash do not. + +- "dc" is a somewhat iffy benchmark, because there are two versions of + it floating around, one being small, very fast, and buggy, and one + being more correct but slow. It was never in the index anyway. + +- Execl is a somewhat troubling benchmark in that it yields much higher + scores if compiled statically. I frown on this practice because it + distorts the scores away from reflecting how programs are really used + (i.e. dynamically linked). + +- Arithoh is really more an indicator of the compiler quality than of + the computer itself. For example, GCC 2.7.x with -O2 and a few extra + options optimizes much of it away, resulting in about a 1200% boost + to the score. Clearly not a good one for the index. + +I am still a bit unhappy with the variance in some of the benchmarks, most +notably the fstime suite; and with how long it takes to run. But I think +it gets significantly more reliable results than the older version in less +time. + +If anyone has ideas on how to make these benchmarks faster, lower-variance, +or more meaningful; or has nice, new, portable benchmarks to add, don't +hesitate to e-mail me. + +David C Niemi 7 Dec 1995 + +======================== May 91 ========================== +This is version 3. This set of programs should be able to determine if +your system is BSD or SysV. (It uses the output format of time (1) +to see. If you have any problems, contact me (by email, +preferably): ben@bytepb.byte.com + +--- + +The document doc/bench.doc describes the basic flow of the +benchmark system. The document doc/bench3.doc describes the major +changes in design of this version. As a user of the benchmarks, +you should understand some of the methods that have been +implemented to generate loop counts: + +Tests that are compiled C code: + The function wake_me(second, func) is included (from the file +timeit.c). This function uses signal and alarm to set a countdown +for the time request by the benchmark administration script +(Run). As soon as the clock is started, the test is run with a +counter keeping track of the number of loops that the test makes. +When alarm sends its signal, the loop counter value is sent to stderr +and the program terminates. Since the time resolution, signal +trapping and other factors don't insure that the test is for the +precise time that was requested, the test program is also run +from the time (1) command. The real time value returned from time +(1) is what is used in calculating the number of loops per second +(or minute, depending on the test). As is obvious, there is some +overhead time that is not taken into account, therefore the +number of loops per second is not absolute. The overhead of the +test starting and stopping and the signal and alarm calls is +common to the overhead of real applications. If a program loads +quickly, the number of loops per second increases; a phenomenon +that favors systems that can load programs quickly. (Setting the +sticky bit of the test programs is not considered fair play.) + +Test that use existing UNIX programs or shell scripts: + The concept is the same as that of compiled tests, except the +alarm and signal are contained in separate compiled program, +looper (source is looper.c). Looper uses an execvp to invoke the +test with its arguments. Here, the overhead includes the +invocation and execution of looper. + +-- + +The index numbers are generated from a baseline file that is in +pgms/index.base. You can put tests that you wish in this file. +All you need to do is take the results/log file from your +baseline machine, edit out the comment and blank lines, and sort +the result (vi/ex command: 1,$!sort). The sort in necessary +because the process of generating the index report uses join (1). +You can regenerate the reports by running "make report." + +-- + +========================= Jan 90 ============================= +Tom Yager has joined the effort here at BYTE; he is responsible +for many refinements in the UNIX benchmarks. + +The memory access tests have been deleted from the benchmarks. +The file access tests have been reversed so that the test is run +for a fixed time. The amount of data transfered (written, read, +and copied) is the variable. !WARNING! This test can eat up a +large hunk of disk space. + +The initial line of all shell scripts has been changed from the +SCO and XENIX form (:) to the more standard form "#! /bin/sh". +But different systems handle shell switching differently. Check +the documentation on your system and find out how you are +supposed to do it. Or, simpler yet, just run the benchmarks from +the Bourne shell. (You may need to set SHELL=/bin/sh as well.) + +The options to Run have not been checked in a while. They may no +longer function. Next time, I'll get back on them. There needs to +be another option added (next time) that halts testing between +each test. !WARNING! Some systems have caches that are not getting flushed +before the next test or iteration is run. This can cause +erroneous values. + +========================= Sept 89 ============================= +The database (db) programs now have a tuneable message queue space. +queue space. The default set in the Run script is 1024 bytes. +Other major changes are in the format of the times. We now show +Arithmetic and Geometric mean and standard deviation for User +Time, System Time, and Real Time. Generally, in reporting, we +plan on using the Real Time values with the benchs run with one +active user (the bench user). Comments and arguments are requested. + +contact: BIX bensmith or rick_g diff --git a/src/cmd/unixbench/Run b/src/cmd/unixbench/Run new file mode 100755 index 0000000..43378b2 --- /dev/null +++ b/src/cmd/unixbench/Run @@ -0,0 +1,320 @@ +#!/bin/sh -v +FLAVOR=BSD +FULL_SUITE="dhry2reg whetstone-double syscall pipe context1 spawn execl \ + fstime fsbuffer fsdisk shell short int long float double arithoh \ + C dc hanoi" +ID="Run:4.1.0 -- 19970824"; +version="4.1.0" +export FLAVOR +TIME=" %e real %U user %S sys" +export TIME +UNAME="hostname" + +HOMEDIR=/share/unixbench +BINDIR=${HOMEDIR} +TMPDIR=${HOMEDIR}/tmp +RESULTDIR=${HOMEDIR}/results +TIMEACCUM=${RESULTDIR}/times +TESTDIR=${HOMEDIR}/testdir +export BINDIR TMPDIR RESULTDIR PATH TESTDIR TIMEACCUM + +cat ${BINDIR}/unixbench.logo +rm -f ${TIMEACCUM} +echo "kill -9 $$" > ${TMPDIR}/kill_run ; chmod u+x ${TMPDIR}/kill_run + +date=`date` +TMPTIMES=${TMPDIR}/$$.tmp +LOGFILE=${RESULTDIR}/log +REPORTLOG=${RESULTDIR}/report +if [ -w ${RESULTDIR}/log ]; then + if [ -w ${RESULTDIR}/log.accum ]; then + cat ${RESULTDIR}/log >> ${RESULTDIR}/log.accum + rm ${RESULTDIR}/log + else + mv ${RESULTDIR}/log ${RESULTDIR}/log.accum + fi +fi +echo "| BYTE UNIX Benchmarks (Version $version)" >>$LOGFILE +echo "| System --" `$UNAME` >>$LOGFILE +echo "| Start Benchmark Run: `date`" >>$LOGFILE +echo "| " `who | wc -l` "interactive users." >>$LOGFILE +echo "| 13:11:51 up 3:05, 3 users, load average: 0.01, 0.03, 0.06" >> $LOGFILE +echo "| `ls -l /bin/sh`" >> $LOGFILE +echo "| `file /bin/sh`" >> $LOGFILE +echo "| `df . | tail -1`" >> $LOGFILE +iter=${iterations-10} +short=`expr \( $iter + 1 \) / 3` +if [ "$short" -lt 1 ]; then + short=1 +fi +longloop= +shortloop= +while [ $iter -gt 0 ]; do + + longloop="$iter $longloop" + if [ "$iter" -le "$short" ]; then + shortloop="$iter $shortloop" + fi + iter=`expr $iter - 1` +done + +for bench in ${FULL_SUITE} +do + + + prog=${BINDIR}/$bench + paramlist="#" + testdir=$TESTDIR + prepcmd= + parammsg= + repeat=$shortloop + stdout="$LOGFILE" + stdin= + options= + logmsg= + cleanopt="-l $TMPTIMES" + bgnumber= + trap "${SCRPDIR}/cleanup.sh -L $LOGFILE -a; exit" 1 2 3 15 + echo >>$LOGFILE + case $bench in + dhry2reg) + options=${dhrytime-10} + logmsg="Dhrystone 2 using register variables" + repeat=$longloop + ;; + + whetstone-double) + cleanopt="-w $TMPTIMES" + logmsg="Double-Precision Whetstone" + repeat=$longloop + ;; + + syscall) + repeat=$longloop + options=${systime-10} + logmsg="System Call Overhead" + ;; + + context1) + repeat=$longloop + options=${systime-10} + logmsg="Pipe-based Context Switching" + ;; + + pipe) + repeat=$longloop + options=${systime-10} + logmsg="Pipe Throughput" + ;; + + spawn) + options=${systime-30} + logmsg="Process Creation" + ;; + + execl) + options=${systime-30} + logmsg="Execl Throughput" + ;; + + fstime) + logmsg='Filesystem Throughput 1024 bufsize 2000 maxblocks' + where=${where-${TMPDIR}} + cleanopt="-f $TMPTIMES" + options='$param '"$where" + paramlist=${seconds:-30} + parammsg='Test Time: $param secs' + ;; + + fsbuffer) + logmsg='Filesystem Throughput 256 bufsize 500 maxblocks' + where=${where-${TMPDIR}} + cleanopt="-f $TMPTIMES" + options='$param '"$where" + paramlist=${seconds:-30} + parammsg='Test Time: $param secs' + ;; + + fsdisk) + logmsg='Filesystem Throughput 4096 bufsize 8000 maxblocks' + where=${where-${TMPDIR}} + cleanopt="-f $TMPTIMES" + options='$param '"$where" + paramlist=${seconds:-30} + parammsg='Test Time: $param secs' + ;; + + shell) + logmsg='Shell Scripts ($param concurrent)' + prog="looper ${looper-60} multi.sh" + stdout=/dev/null + if [ -n "${JUSTINDEX-}" ]; then + paramlist=${background-"8 "} + else + paramlist=${background-"1 8 16 "} + fi + parammsg='$param concurrent background processes' + bgnumber='$param' + cleanopt="-m $TMPTIMES" + ;; + + + C) + logmsg="C Compiler Throughput" + prog="looper ${looper-60} ${CC} cctest.c" + stdout=/dev/null + repeat="$shortloop" + cleanopt="-m $TMPTIMES" + rm -f ${TESTDIR}/cctest.o ${TESTDIR}/a.out + ;; + + arithoh) + logmsg="Arithoh" + options=${arithtime-10} + ;; + + short|int|long|float|double) + logmsg="Arithmetic Test (type = $bench)" + options=${arithtime-10} + ;; + + dc) + logmsg="Dc: sqrt(2) to 99 decimal places" + prog="looper ${looper-30} dc" + stdin=dc.dat + stdout=/dev/null + cleanopt="-m $TMPTIMES" + ;; + + hanoi) + options=${systime-20} + stdout=/dev/null + logmsg="Recursion Test--Tower of Hanoi" + parammsg='$param Disk Problem:' + ;; + + perlbench) + cleanopt="-t $TMPTIMES" + options=${systime-2} + logmsg="PerlBench" + ;; + + select) + cleanopt="-t $TMPTIMES" + options= + logmsg="select()" + ;; + + *) + ${BINDIR}/cleanup.sh -L $LOGFILE -r \ +"run: unknown benchmark \"$bench\" \n Known benchmarks are: \n $FULL_SUITE" -a + exit 1 + ;; + esac + + + for param in $paramlist + do + param=`echo $param | sed 's/_/ /g'` + eval Lmsg='"'$logmsg'"' + eval opt='"'$options'"' + eval prep='"'$prepcmd'"' + eval bg='"'$bgnumber'"' + rm -f $TMPTIMES + + echo "TEST|$Lmsg" >>$TMPTIMES + echo "FLAVOR|${FLAVOR}" >>$TMPTIMES + if [ "$runoption" != 'Q' ] + then + echo "" + if [ $FLAVOR = "SysV" ] + then echo "$Lmsg \c" + else echo -n "$Lmsg " + fi + + fi + for i in $repeat + do + if [ "$runoption" != 'D' ] + then + + trap "${BINDIR}/cleanup.sh -L $LOGFILE -i $i $cleanopt -a; exit" 1 2 3 15 + else + trap "exit" 1 2 3 15 + fi + + sync; sleep 1; sync; sleep 2 + + if [ "$runoption" != Q ]; then + if [ $FLAVOR = "SysV" ]; then + echo " $i\c" + else + echo -n " $i" + fi + fi + pwd=`pwd` + cd $testdir + if [ "${runoption-}" = V ]; then + echo + echo "BENCH COMMAND TO BE EXECUTED:" + echo "$prog $opt" + fi + + + if [ -n "$prep" ]; then + $prep 2>&1 >>$stdout + fi + if [ -z "${stdin-}" ]; then + + /usr/bin/time $prog $opt $bg 2>>$TMPTIMES >>$stdout + else + + /usr/bin/time $prog $opt $bg <$stdin 2>>$TMPTIMES >>$stdout + fi + cd $pwd + status=$? + if [ $status != 0 ]; then + if [ -f $TMPTIMES ]; then + cp $TMPTIMES ${TMPDIR}/save.$bench.$param + ${SCRPDIR}/cleanup.sh -L $LOGFILE -i $i $cleanopt -r \ + "run: bench=$bench param=$param fatalstatus=$status" -a + else + ${SCRPDIR}/cleanup.sh -L $LOGFILE -r \ + "run: bench=$bench param=$param fatalstatus=$status" -a + fi + exit + fi + done + if [ "$runoption" != D ]; then + ${SCRPDIR}/cleanup.sh -L $LOGFILE $cleanopt + + + fi + done + + case $bench in + C) + rm -f ${TESTDIR}/cctest.o ${TESTDIR}/a.out + ;; + + fstime | fsbuffer | fsdisk) + sync; sleep 1; sync; sleep 1 + ;; + esac + if [ "$runoption" != Q ]; then + echo + fi +done +echo >>$LOGFILE +echo "End Benchmark Run: `date`" >>$LOGFILE +echo " " `who | wc -l` "interactive users." >>$LOGFILE + +${SCRPDIR}/report.sh $LOGFILE > $REPORTLOG +${SCRPDIR}/index.sh ${SCRPDIR}/index.base $LOGFILE >> $REPORTLOG +if [ "$runoption" != Q ]; then + echo + echo "==============================================================" + cat $REPORTLOG +fi + +exit 0 diff --git a/src/cmd/unixbench/pgms/cleanup.sh b/src/cmd/unixbench/pgms/cleanup.sh new file mode 100755 index 0000000..2bed0ad --- /dev/null +++ b/src/cmd/unixbench/pgms/cleanup.sh @@ -0,0 +1,137 @@ +#!/bin/sh +############################################################################### +## +## UnixBench +## pgms/cleanup.sh +## +## Originally based on: +# The BYTE UNIX Benchmarks - Release 3 +# Module: cleanup.sh SID: 3.5 5/15/91 19:30:26 +# +############################################################################### +# Bug reports, patches, comments, suggestions should be sent to: +# +# Ben Smith or Rick Grehan at BYTE Magazine +# ben@bytepb.UUCP rick_g@bytepb.UUCP +# +############################################################################### +# Modification Log: +# added report for dhrystones 6/89 - ben +# +############################################################################### +ID="@(#)cleanup.sh:3.5 -- 5/15/91 19:30:26"; +# +# $Header: cleanup,v 5.2 88/01/07 10:58:24 kenj Exp $ +# +# Cleanup when an iterative test terminates +# + +BINDIR=${BINDIR-./pgms} +log=${LOG-./results/log} +timeaccum=${TIMEACCUM-./results/times} +flavor="${FLAVOR-SysV}" +while ( test $# -ge 1 ) +do + opt=$1 + shift + case $opt + in + + -a) # abort + echo '' >>$LOGFILE + echo '**************************' >>$LOGFILE + echo '* Benchmark Aborted .... *' >>$LOGFILE + echo '**************************' >>$LOGFILE + echo + echo 'Benchmark Aborted ....' # notice displayed on screen + echo "" >>$LOGFILE + echo " " `who | wc -l` "interactive users." >>$LOGFILE + echo "" >>$LOGFILE + date=`date` + echo "End Benchmark Run ($date) ...." >>$LOGFILE + echo "End Benchmark Run ($date) ...." + ;; + + + -f) # filesystem throughput + awk -f ${BINDIR}/fs.awk <$1 >>$LOGFILE + cat $1 >> $timeaccum 2>/dev/null + rm -f $1 + shift + ;; + + -d) # Dhrystone evaluation + awk -f ${BINDIR}/dhry.awk <$1 >>$LOGFILE + cat $1 >> $timeaccum 2>/dev/null + rm -f $1 + shift + ;; + + -t) # self-timing benchmarks in loops per second + awk -f ${BINDIR}/lps.awk <$1 >>$LOGFILE + cat $1 >> $timeaccum 2>/dev/null + rm -f $1 + shift + ;; + + -w) # MWIPS, precalculated and pretimed + awk -f ${BINDIR}/mwips.awk <$1 >>$LOGFILE + cat $1 >> $timeaccum 2>/dev/null + rm -f $1 + shift + ;; + + -l) # loops per second for a specified time evaluation + awk -f ${BINDIR}/loops.awk <$1 >>$LOGFILE + cat $1 >> $timeaccum 2>/dev/null + rm -f $1 + shift + ;; + + + -m) # loops per minute for a specified time evaluation + awk -f ${BINDIR}/loopm.awk <$1 >>$LOGFILE + cat $1 >> $timeaccum 2>/dev/null + rm -f $1 + shift + ;; + + -i) # report last iteration + echo "Terminated during iteration $1" >>$LOGFILE + shift + ;; + + -L) # logfile + LOGFILE=$1 + shift + ;; + + -r) # reason for failure + echo $1 + echo $1 >>$LOGFILE + shift + ;; + + -m) # mem throughput tests + awk -f ${BINDIR}/mem.awk <$1 >>$LOGFILE + cat $1 >> $timeaccum 2>/dev/null + rm -f $1 + shift + ;; + + -t) # timing with /bin/time + awk -f ${BINDIR}/time.awk <$1 >>$LOGFILE + cat $1 >> $timeaccum 2>/dev/null + rm -f $1 + shift + ;; + + + '') # 'skip it (residual effect of shifts)' + ;; + + *) + echo "cleanup: bad option ($opt)" >>$LOGFILE +esac +done +exit diff --git a/src/cmd/unixbench/pgms/fs.awk b/src/cmd/unixbench/pgms/fs.awk new file mode 100755 index 0000000..d8f8452 --- /dev/null +++ b/src/cmd/unixbench/pgms/fs.awk @@ -0,0 +1,71 @@ +############################################################################### +# The BYTE UNIX Benchmarks - Release 3 +# Module: fs.awk SID: 3.4 5/15/91 19:30:24 +# +############################################################################### +# Bug reports, patches, comments, suggestions should be sent to: +# +# Ben Smith or Tom Yager at BYTE Magazine +# ben@bytepb.byte.com tyager@bytepb.byte.com +# +############################################################################### +# Modification Log: +# added geometric mean 8/6/89 -ben +# modified for new version of fstime 11/15/89 -ben +# removed variance 10/23/90 -ben +# +############################################################################### +BEGIN { w_product = 0.0000; + r_product = 0.0000; + c_product = 0.0000; + iter=0; + w_too_quick=0; + r_too_quick=0; + c_too_quick=0; + } +/FLAVOR\|/ { split($0, junk,"|"); + flavor = junk[2]; + } +/TEST\|/ { split($0, junk," "); + bufsize = junk[3]; + maxblocks = junk[5]; + } +/real/ { iter++; ok++; next; } +/user/ { if (flavor == "SysV") {next;} } +/sys/ { if (flavor == "SysV") {next;} } +/^$/ { next; } +/^#/ { next; } +/sample/ { sample = $1; next; } +/fstime/ { + print "** Iteration ",iter," Failed: ",$0; + ok--; + fail=1; + } +/write/ { if (!fail) { + w+=$1; + w2+=$1*$1; + w_product += log($1); + } + } +/read/ { if (!fail) { + r+=$1; + r2+=$1*$1; + r_product += log($1); + } + } +/copy/ { if (!fail) { + c+=$1; + c2+=$1*$1; + c_product += log($1); + } + } +END { + if (ok > 0) { +# TestName|Sample(seconds)|Unit(KiloBytes/sec)|ArithMean|GeoMean|DataPoints + printf "File Read %d bufsize %d maxblocks|%d|KBps|%.0f|%.0f|%d\n", bufsize, maxblocks, sample, r/ok, exp(r_product/ok), ok; + printf "File Write %d bufsize %d maxblocks|%d|KBps|%.0f|%.0f|%d\n", bufsize, maxblocks, sample, w/ok, exp(w_product/ok), ok; + printf "File Copy %d bufsize %d maxblocks|%d|KBps|%.0f|%.0f|%d\n", bufsize, maxblocks, sample, c/ok, exp(c_product/ok), ok; + } else { + print "File I/O| no measured results|" + } + } diff --git a/src/cmd/unixbench/pgms/index.awk b/src/cmd/unixbench/pgms/index.awk new file mode 100644 index 0000000..f758d8d --- /dev/null +++ b/src/cmd/unixbench/pgms/index.awk @@ -0,0 +1,19 @@ +BEGIN { + FS="|" ; + sum=0.00; + n=0; + printf("\n INDEX VALUES \n"); + printf("TEST%40sBASELINE RESULT INDEX\n\n",""); + + } + + { # process all lines + sum += log($10/$5) + ++n; + printf("%-40s %10.1f %10.1f %10.1f\n", $1, $5, $10, 10*$10/$5); + } + +END { + printf(" %30s =========\n", ""); + printf(" FINAL SCORE %30s %20.1f\n","",(10*exp(sum/n))); + } diff --git a/src/cmd/unixbench/pgms/index.base b/src/cmd/unixbench/pgms/index.base new file mode 100644 index 0000000..e1dee37 --- /dev/null +++ b/src/cmd/unixbench/pgms/index.base @@ -0,0 +1,11 @@ +Dhrystone 2 using register variables|10|lps|116700|116700|2 +Double-Precision Whetstone|10|MWIPS|55.0|55.0|2 +Execl Throughput|20|lps|43.0|43.0|1 +File Copy 1024 bufsize 2000 maxblocks|20|KBps|3960|3960|1 +File Copy 256 bufsize 500 maxblocks|20|KBps|1655|1655|1 +File Copy 4096 bufsize 8000 maxblocks|20|KBps|5800|5800|1 +Pipe Throughput|10|lps|12440|12440|2 +Pipe-based Context Switching|10|lps|4000|4000|2 +Process Creation|20|lps|126|126|1 +Shell Scripts (8 concurrent)|60|lpm|6|6|1 +System Call Overhead|10|lps|15000|15000|2 diff --git a/src/cmd/unixbench/pgms/index.sh b/src/cmd/unixbench/pgms/index.sh new file mode 100755 index 0000000..67c6b3b --- /dev/null +++ b/src/cmd/unixbench/pgms/index.sh @@ -0,0 +1,73 @@ +############################################################################## +# The BYTE UNIX Benchmarks - Release 3 +# Module: index.sh SID: 3.5 5/15/91 19:30:24 +# +############################################################################## +# Bug reports, patches, comments, suggestions should be sent to: +# +# Ben Smith or Tom Yager at BYTE Magazine +# ben@bytepb.byte.com tyager@byptepb.byte.com +# +############################################################################## +# generate an index from test log +# +############################################################################# +# Modification Log: +# created 4/1/91 - Ben Smith +# +############################################################################## +BINDIR=${BINDIR-pgms} +BASE=${BASE-pgms/index.base} +TARGET=${TARGET-results/log} +TEMP=/tmp/$$.dat +# +# BASELINE DATA +# +if [ $# -lt 1 ] +then + echo "Data File for baseline: \c" + read BASE +else + BASE=$1 +fi +# check for existance +if [ ! -r ${BASE} ] +then + echo "Cannot open $BASE for reading" + exit 1 +fi +# +# RESULTS TARGET +# +if [ $# -lt 2 ] +then + echo "Source File for target machine results: \c" + read TARGET +else + TARGET=$2 +fi +# check for existance +if [ ! -r ${TARGET} ] +then + echo "Cannot open $TARGET for reading" + exit 1 +fi +# +# make dat file for results + sort $TARGET > ${TEMP} +# +# DESTINATION +# +if [ $# -eq 3 ] +then + DEST=$3 + join -t'|' ${BASE} ${TEMP} | awk -f ${BINDIR}/index.awk > ${DEST} +else + join -t'|' ${BASE} ${TEMP} | awk -f ${BINDIR}/index.awk +fi + +# cleanup +rm -f ${TEMP} + + + diff --git a/src/cmd/unixbench/pgms/loopm.awk b/src/cmd/unixbench/pgms/loopm.awk new file mode 100755 index 0000000..99536a2 --- /dev/null +++ b/src/cmd/unixbench/pgms/loopm.awk @@ -0,0 +1,58 @@ +############################################################################### +# The BYTE UNIX Benchmarks - Release 1 +# Module: loopm.awk SID: 1.4 5/15/91 19:30:25 +# LOOPS per minute +# +############################################################################### +# Bug reports, patches, comments, suggestions should be sent to: +# +# Ben Smith or Tom Yager at BYTE Magazine +# ben@bytepb.byte.com tyager@bytepb.byte.com +# +############################################################################### +# Modification Log: +# created 2/12/91 -ben +# +############################################################################### +BEGIN { rsum = 0.000; r2sum = 0.000; r_product = 0.0000; + iter = 0; Test=""; SubTest=""; secs = 0.00; secs_sum = 0.00; + mins = 0.000; time_str=""; flavor="SysV"; + } +/TEST\|/ { split($0, junk,"|"); + Test=junk[2]; + } +/FLAVOR\|/ { split($0, junk,"|"); + flavor=junk[2] ; + } +/loops/ { loops=$1; + iter ++; + } +/real/ { if (flavor == "SysV") {time_str = $2; } + else { time_str = $1; } + # determine seconds from time_str + if ( time_str ~/\:/) + { + split(time_str,junk,":"); + secs = 60 * junk[1] + junk[2]; + } + else { secs = time_str; } + mins=secs/60.000; + print mins; + if(loops) { rsum += loops/mins; + r2sum += (loops*loops)/(mins*mins); + r_product += (log(loops)-log(mins)); + secs_sum += secs; + } + } +/user/ { if (flavor == "SysV") { next;} } # don't use these times +/sys/ { if (flavor == "SysV") { next;} } # don't use these times +#/^$/ { next } +END { + if (iter > 0) { +# TestName|Sample(seconds)|units|ArithMean|GeoMean|DataPoints + printf("%s|%.1f|lpm|%.1f|%.1f|%d\n",Test,secs_sum/iter,rsum/iter,exp(r_product/iter),iter); + } + else { + printf("%s| no measured results|\n",Test); + } + } diff --git a/src/cmd/unixbench/pgms/loops.awk b/src/cmd/unixbench/pgms/loops.awk new file mode 100755 index 0000000..e0b338c --- /dev/null +++ b/src/cmd/unixbench/pgms/loops.awk @@ -0,0 +1,55 @@ +############################################################################### +# The BYTE UNIX Benchmarks - Release 1 +# Module: loops.awk SID: 1.4 5/15/91 19:30:25 +# LOOPS per second +# +############################################################################### +# Bug reports, patches, comments, suggestions should be sent to: +# +# Ben Smith or Tom Yager at BYTE Magazine +# ben@bytepb.byte.com tyager@bytepb.byte.com +# +############################################################################### +# Modification Log: +# created 2/12/91 -ben +# +############################################################################### +BEGIN { rsum = 0.000; r2sum = 0.000; r_product = 0.0000; + iter = 0; Test=""; SubTest=""; secs = 0.00; secs_sum = 0.00; + } +/TEST\|/ { split($0, junk,"|"); + Test=junk[2]; + } +/FLAVOR\|/ { split($0, junk,"|"); + flavor=junk[2] ; + } +/loops/ { loops=$1; + iter ++; + } +/real/ { if (flavor == "SysV") {time_str=$2; } + else {time_str=$1; } + # determine seconds from time_str + if ( time_str ~/\:/) + { + split(time_str,junk,":"); + secs = 60 * junk[1] + junk[2]; + } + else { secs = time_str; } + if(loops) { rsum += loops/secs; + r2sum += (loops*loops)/(secs*secs); + r_product += (log(loops)-log(secs)); + secs_sum += secs; + } + } +/user/ { if (flavor == "SysV") { next;} } # don't use these times +/sys/ { if (flavor == "SysV") { next;} } # don't use these times +#/^$/ { next } +END { + if (iter > 0) { +# TestName|Sample(seconds)|units|ArithMean|GeoMean|DataPoints + printf("%s|%.1f|lps|%.1f|%.1f|%d\n",Test,secs_sum/iter,rsum/iter,exp(r_product/iter),iter) + } + else { + printf("%s| no measured results|\n",Test); + } + } diff --git a/src/cmd/unixbench/pgms/lps.awk b/src/cmd/unixbench/pgms/lps.awk new file mode 100755 index 0000000..777a1e6 --- /dev/null +++ b/src/cmd/unixbench/pgms/lps.awk @@ -0,0 +1,35 @@ +########### +# pgms/lps.awk +# +# Measures Loops per Second for self-timing benchmarks +# +# Created 1997.08.25 DCN +# +BEGIN { rsum = 0.000; r2sum = 0.000; r_product = 0.0000; + iter = 0; Test=""; SubTest=""; secs = 10.00; secs_sum = 0.00; + } +/TEST\|/ { split($0, junk,"|"); + Test=junk[2]; + } +/FLAVOR\|/ { split($0, junk,"|"); + flavor=junk[2] ; + } +/^lps/ { + loopspersec=$2; + secs=$3; + secs_sum += secs; + loops=secs*loopstmp; + iter ++; + rsum += loopspersec; + r2sum += loopspersec*loopspersec; + r_product += log(loopspersec); + } +END { + if (iter > 0) { +# TestName|Sample(seconds)|units|ArithMean|GeoMean|DataPoints + printf("%s|%.1f|lps|%.1f|%.1f|%d\n",Test,secs_sum/iter,rsum/iter,exp(r_product/iter),iter) + } + else { + printf("%s| no measured results|\n",Test); + } + } diff --git a/src/cmd/unixbench/pgms/multi.sh b/src/cmd/unixbench/pgms/multi.sh new file mode 100755 index 0000000..647b3e1 --- /dev/null +++ b/src/cmd/unixbench/pgms/multi.sh @@ -0,0 +1,23 @@ +#! /bin/sh +############################################################################### +# The BYTE UNIX Benchmarks - Release 3 +# Module: multi.sh SID: 3.4 5/15/91 19:30:24 +# +############################################################################### +# Bug reports, patches, comments, suggestions should be sent to: +# +# Ben Smith or Rick Grehan at BYTE Magazine +# ben@bytepb.UUCP rick_g@bytepb.UUCP +# +############################################################################### +# Modification Log: +# +############################################################################### +ID="@(#)multi.sh:3.4 -- 5/15/91 19:30:24"; +instance=1 +while [ $instance -le $1 ]; do + /bin/sh $BINDIR/tst.sh & + instance=`expr $instance + 1` +done +wait + diff --git a/src/cmd/unixbench/pgms/mwips.awk b/src/cmd/unixbench/pgms/mwips.awk new file mode 100755 index 0000000..7bbb441 --- /dev/null +++ b/src/cmd/unixbench/pgms/mwips.awk @@ -0,0 +1,35 @@ +########### +# pgms/mwips.awk +# +# Measures MWIPS for Whetstone (self-timing, ignore "time" output) +# +# Created 1997.08.25 DCN +# +BEGIN { rsum = 0.000; r2sum = 0.000; r_product = 0.0000; + iter = 0; Test=""; SubTest=""; secs = 10.00; secs_sum = 0.00; + } +/TEST\|/ { split($0, junk,"|"); + Test=junk[2]; + } +/FLAVOR\|/ { split($0, junk,"|"); + flavor=junk[2] ; + } +/^MWIPS/ { + loopspersec=$2; + secs=$3; + secs_sum += secs; + loops=secs*loopstmp; + iter ++; + rsum += loopspersec; + r2sum += loopspersec*loopspersec; + r_product += log(loopspersec); + } +END { + if (iter > 0) { +# TestName|Sample(seconds)|units|ArithMean|GeoMean|DataPoints + printf("%s|%.1f|MWIPS|%.1f|%.1f|%d\n",Test,secs_sum/iter,rsum/iter,exp(r_product/iter),iter) + } + else { + printf("%s| no measured results|\n",Test); + } + } diff --git a/src/cmd/unixbench/pgms/perlbench b/src/cmd/unixbench/pgms/perlbench new file mode 100755 index 0000000..ce44dda --- /dev/null +++ b/src/cmd/unixbench/pgms/perlbench @@ -0,0 +1,357 @@ +#!/usr/bin/perl +# +# $Id: perlbench,v 1.5 1997/09/10 23:59:56 niemi Exp $ +# +# perlbench +# +# A simplistic, portable Perl benchmark +# +# Copyright 1997 David C Niemi +# +# This program is distributed "as-is". +# The author places no restrictions on the use of this program. +# + +$version = "pre-v1.0-19970910"; +$rez = 0.001; +#$duration = 10; +$duration = 2; ## For quick testing only +$count = 50; +$smallarray = 200; +$largearray = 5000; + +$_tare = $_num_scores = 0; +$_score_l = $_lps_l = $_baseline_l = 0; + +## Wait until the top of the next second +sub synctime { + return if (! $rez); + + $_start = time; + $_count = 0; + while (time == $_start) { + select(undef, undef, undef, $rez); + ++ $_count; + } + $_end = time; +} + +sub pretime { + $_count = $j = 0; + &synctime; + $_targtime = time + $duration; +} + +sub posttime { + if (time > $_targtime) { + print STDERR "WARNING: System too busy, dubious results.\n"; + } + $_lps = $_count/$duration; + if ($_lps == 0) { + $_tunits = "NaN"; + $_ttime = 0; + } elsif ($_lps >= 1000000) { + $_tunits = "nsec"; + $_ttime = 1000000000/$_lps - 1000000000*$_tare*$_loops/$_count; + } elsif ($_lps >= 1000) { + $_tunits = "usec"; + $_ttime = 1000000/$_lps - 1000000*$_tare*$_loops/$_count; + } else { + $_tunits = "msec"; + $_ttime = 1000/$_lps - 1000*$_tare*$_loops/$_count; + } + $_score = $_lps / $_baseline; + write; + $_lps_l += log($_lps); + $_baseline_l += log($_baseline); + $_score_l += log($_score); + ++ $_num_tests; +} + +format STDOUT_TOP = + +Test Name Count Secs Latency Rate Baseline Score +--------- --------- ---- ------------ --------- -------- -------- +. + +format STDOUT = +@<<<<<<<<< @#######.# @### @####.## @<<<< @#######.# @######.# @####.## +$_name, $_count, $duration, $_ttime, $_tunits, $_lps, $_baseline*10, $_score +. + +## 64 legal characters +@chars = ('A' .. 'Z', 'a' .. 'z', '0' .. '9', ' ', '-'); + + +sub bynumber { $a <=> $b; } + + +sub testempty { + $_name = "EmptyLoop"; + $_baseline = 7850; + &pretime; + while (time < $_targtime) { + ++ $j; + } + $_loops = $_count = $j; + &posttime; + $_tare = $duration/$_count; +} + +sub testassign { + $_name = "VarAssign"; + $_baseline = 5980; + &pretime; + while (time < $_targtime) { + $junk = 10; + ++ $j; + } + $_loops = $_count = $j; + &posttime; + $_tare = $duration/$_count; +} + + +sub testrandom { + $_name = "Random"; + $_baseline = 280; + &pretime; + while (time < $_targtime) { + srand(0); + undef(%ssn,%name); + for ($i=0; $i < $smallarray; ++$i) { + $length = int(5 + rand(15)); + $ssn = int(rand(999999999)); + + $name = ""; + for ($c = 0; $c < $length; ++$c) { + $name .= $chars[rand(64)]; + } + $ssn{$name} = $ssn; + $name{$ssn} = $name; + } + ++ $j; + } + $_loops = $j; + $_count = $j * $smallarray; + &posttime; +} + + +sub testnumsort { + $_name = NumSort; + $_baseline = 850; + $k = 0; + &pretime; + while (time < $_targtime) { + for $i (sort bynumber keys %name) { + if ($name{$i} =~ /^[AEIOU][bcdfg]/) { + ++ $k; +# print "$i\t$name{$i}\n"; + } + } + ++ $j; + } + $_loops = $j; + $_count = $j * $smallarray; + &posttime; +} + +sub testcharsort { + $_name = "CharSort"; + $_baseline = 2000; + &pretime; + while (time < $_targtime) { + for $i (sort keys %ssn) { + if ($ssn{$i} > 950000000) { +# print "$i\t$ssn{$i}\n"; + ++ $k; + } + } + ++ $j; + } + $_loops = $j; + $_count = $j * $largearray; + &posttime; +} + + +sub testregexp { + $_name = "RegExp"; + $_baseline = 1000; + $k = 0; + %save = %name; + &pretime; + while (time < $_targtime) { + for $ssn (keys %name) { + if ($name{$ssn} =~ /^([AEIOU][bdcdfghjklmnpqrstvwxyz])(..)/) { + ($initial, $next) = ($1, $2); + $name{$ssn} =~ s/^....//; + $name{$ssn} .= ($next, $initial); + ++ $k; + } + if ($name{$ssn} =~ /^([aeiou][BDCDFGHJKLMNPQRSTVWXYZ])(..)/) { + ($initial, $next) = ($1, $2); + $name{$ssn} =~ s/....$//; + $name{$ssn} .= ($initial, $next); + -- $k; + } + if ($name{$ssn} =~ /^([AaBb]*[DdEe]*[^ ]) (.*)/) { + ($initial, $next) = ($1, $2); + $name{$ssn} =~ $2 . ' ' . $1; + ++ $k; + } + if ($name{$ssn} =~ /^([DdEe]*[AaBb]*[^ ]) (.*)/) { + ($initial, $next) = ($1, $2); + $name{$ssn} =~ $2 . ' ' . $1; + -- $k; + } + } + ++ $j; + %name = %save; + } + $_loops = $j; + $_count = $j * $largearray; + &posttime; +} + + +## Memory Write +sub testmemwrite { + $_name = "MemWrite"; + $_baseline = 2080; + &pretime; + while (time < $_targtime) { + for ($i = 0; $i < $count; ++ $i) { + $z{$i}= $i; + } + ++ $j; + } + + $_loops = $j; + $_count = $j * $count; + &posttime; +} + + +## time() +sub testtime { + $_name = "time()"; + $_baseline = 7750; + &pretime; + while (time < $_targtime) { + $junk = time(); + $junk = time(); + $junk = time(); + $junk = time(); + $junk = time(); + ++ $j; + } + + $_loops = $j; + $_count = $j * 5; + &posttime; +} + + +sub testint { + $_name = "Int"; + $_baseline = 1800; + &pretime; + $j = $sum = 0; + while (time < $_targtime) { + for ($i = 0; $i < $count; ++ $i) { + ## Make sure we don't penalize high scorers with huge + ## values as the number of iterations soars + $k = ($j % 256); + $sum += $i*$i*$i - 3*$i*$i*$k + 3*$i*$k*$k - $k*$k*$k; + } + ++ $j; + } + $_loops = $j; + $_count = $j * $i; + &posttime; +} + + +sub testfloat { + $_name = "Float"; + $_baseline = 2200; + &pretime; + $sum = 0; + while (time < $_targtime) { + for ($i = 0; $i < ($count / 10); $i += 0.1) { + $sum += log($i+1) * sin($i) + ($i ** 2.5); + } + ++ $j; + } + $_loops = $j; + $_count = $j * $i * 10; + &posttime; +} + + +## Figure out how often it is worth checking the time +print "\nStarting PerlBench $version\n\n"; +system('sync;sync;sync'); +system('uptime'); +system('uname -a'); + +print "\nCalibrating timer resolution: "; +&synctime; + +&synctime; +if (($_end != $_start + 1) || ($_count < 2)) { + print "worse than 500 msec!\n"; + $rez = 0; +} else { + printf "approximately %.1f msec\n", + 1000/$_count + .0005; + $rez = 2/$_count; +} +print "\n"; + +&testempty; +&testassign; +&testrandom; +&testnumsort; + +#print "Populating large array...\n"; +## Populate large array (don't time it, just get it done... +srand(0); +undef(%ssn,%name); +for ($i=0; $i < $largearray; ++$i) { + $length = int(5 + rand(15)); + $ssn = int(rand(999999999)); + + $name = ""; + for ($c = 0; $c < $length; ++$c) { + $name .= $chars[rand(64)]; + } + $ssn{$name} = $ssn; + $name{$ssn} = $name; +} +#print "... done.\n"; + +&testcharsort; +&testregexp; +&testmemwrite; +&testtime; +&testint; +&testfloat; + + +print +"--------- --------- -------- --------\n"; + +printf +"Total %6.1f %6.1f %6.2f\n", +exp($_lps_l/$_num_tests), +10*exp($_baseline_l/$_num_tests), +exp($_score_l/$_num_tests); + +printf STDERR "lps\t%.2f\t%.1f\n", + exp($_score_l/$_num_tests)*$duration, + $duration; + +## END ## diff --git a/src/cmd/unixbench/pgms/report.awk b/src/cmd/unixbench/pgms/report.awk new file mode 100755 index 0000000..603216a --- /dev/null +++ b/src/cmd/unixbench/pgms/report.awk @@ -0,0 +1,25 @@ +############################################################################## +# The BYTE UNIX Benchmarks - Release 1 +# Module: report.awk SID: 1.4 5/15/91 19:30:25 +# +############################################################################## +# Bug reports, patches, comments, suggestions should be sent to: +# +# Ben Smith or Tom Yager at BYTE Magazine +# ben@bytepb.byte.com tyager@byptepb.byte.com +# +############################################################################## +# generate an report from test log +# +############################################################################# +# Modification Log: +# created 4/1/91 - Ben Smith +# +############################################################################## +BEGIN { FS="|" ; + printf("\n"); + } +NF==2 { print $2; } +NF==3 { printf("%-40.40s %s\n",$1,$2); } +NF==6 { printf("%-40.40s %8.1f %-5s (%.1f secs, %d samples)\n",$1,$5,$3,$2,$6); } +END { printf("\n"); } diff --git a/src/cmd/unixbench/pgms/report.sh b/src/cmd/unixbench/pgms/report.sh new file mode 100755 index 0000000..b11bc8a --- /dev/null +++ b/src/cmd/unixbench/pgms/report.sh @@ -0,0 +1,38 @@ +############################################################################## +# The BYTE UNIX Benchmarks - Release 1 +# Module: report.sh SID: 1.4 5/15/91 19:30:26 +# +############################################################################## +# Bug reports, patches, comments, suggestions should be sent to: +# +# Ben Smith or Tom Yager at BYTE Magazine +# ben@bytepb.byte.com tyager@byptepb.byte.com +# +############################################################################## +# generate an report from test log +# +############################################################################# +# Modification Log: +# created 4/1/91 - Ben Smith +# +############################################################################## +BINDIR=${BINDIR-pgms} +TARGET=${TARGET-results/log} +# RESULTS TARGET +# +if [ $# -lt 1 ] +then + echo "Source File for target machine results: \c" + read TARGET +else + TARGET=$1 +fi +# check for existance +if [ ! -r ${TARGET} ] +then + echo "Cannot open $TARGET for reading" + exit 1 +fi +awk -f ${BINDIR}/report.awk $TARGET + + diff --git a/src/cmd/unixbench/pgms/select b/src/cmd/unixbench/pgms/select new file mode 100755 index 0000000000000000000000000000000000000000..c0b3a97988150f5d7c3a9e11a7275b619272e8cd GIT binary patch literal 7564 zcmb_he{fVs9p59D_DDksn9{UjJ=+&2v2Y|vEx~95BoxL7Ckbtp(Brtfnzq|K#cS}p_5|_&*RGK781X20d+@5*hd#76^^MqHFiW*TRt`k>5 z#Ikw)&;jj2o>U5QgGxZpkx)kZ0P-Z3(RQ&llnGFKg%Bjx7vLcOX@H+O(nY*ld<;0|z<+V*vp;7XnDq<5jDIl9 z7vc^Bz8~X9%<-K9+=%uRuDk+!fnWN`wZ(D~2y}HP;(?SAOd5fJKzN22mY)!T=Fcx* z_}OKPMc~fX6^j-*XkWOfwIv_|ozZwy1n^_P2CK~P_s~N;Fn5;YI>+Md*)ODshXbZEIV^VVtTA|3pg_@F+JD0 zO`O>)F?*nUiFZlNp6E5id5PI0y^gqFV)jg*PuwFhd#E=Nua%fR)t3_cC1#IxF5@#z z60_&}J;Zgu_5a*{)VO-3xd-`s%s77U9c+HYy_@5oJ)L>!Ex&)|UFHjy3I(0piP%!oVlNs)dNLw9&&aD#x};SuP!fC0ry^yZTzFIrxUuAZq8)$aaqbff8%JzbB^MykQOOZxj4!q)8Y$4;#?3mKZ zo_~~$*FNbQk%ltAbDw=UUnso?LokxxdTuYOOE-tKBghW!*P6g`k7%P{6G?rO%Ofp5FKjPIOhUf2InBKf3R0;zIzaLQE=DbPOTLc+6G%(eslZ33k6jr zGg_G&(4IqCL#w7u9lQbmH5dtR7UP%gz|ak7V<^nFYL(gZhot{(X}v%j^Ze#|n1Y*2 zp>l;!kg{b+*}-C$dbOnxu{|Y%Crva7-b@a|P5y$R%~B+NerCK-$c)a+yj4h7n;Kdz z)R{ko%&(tBAa zc8f2c9XoK!UHTGi6?)2ZO&&z)sJl&R*OCU*U`Ua$hvF(qZOVIUTe7=81O-1q6HDt*zR8Oj#9{P}PCc zrMH4*j~qC4RqYX!Rt>rjAdlS4tP2|RP~7NZ2{48t)2vmx3(cD542%JRRnF+%I?C8( z40m8hl`;H?)`M*Q3Ctk37CDocAQ@vOHUr4#$(h}uox@&NKP=-r`~3JD4-M|nVh~*> zIENj0LV(Imtc(H7OXD*fYT`yx+zXQ#i+pLz? zfaNonTzxmK7wgN`3ygn12Db1ew|Vew_gfW^FC^AX3NRHmw{n z>Icu;yb|vC&D${6nbBFYn*IbQav$ni@HpWR;Y+mqa?yMhWc4SomBI1(eJij*vv1k+ zh?k|pxV24xv#9#d3$$Ne`1PrmVdr8|e$0~Ro}k>-tIf;&-o2RSwmfDv?#iR_IcNw2 z(fIufh(^Do`gc)X>a8y`FRHvgg>~MMmbDXDu*ciAI`H`?-^Op_$&1JTkU8i1^Gr>j z0YzE;1X>2wm@TMvytEbaF)Ra1?Rcpl_(V*rd+{)S8(%y;W@t-o6F1R>+_KALgEf}h zvmrJ&Lb6_%p98bL9XjN<1Ahw>-wxxMPZr+&?SQc2cSP}fZ8t{N{0c1D-)AlSe)U>k zsnK}XFz)jU)yV}tdR&9k(6PhV91DWhycvq zu%=8XRj-jqSS^%^*&D?2bho!NoMIcZyvpu`KPkv()Afb1n3rv*yiqt64J8w)NGK5x zqod2(TUIV?U$$cTWcxe4W^S#ho?SmTCCaM9lPAl3EG){(f*T@9^a3J3`q!z-d~-WR ztS2?O8X5f5cb199+30@6+nq=m-e`AEB54HUhId0SmX4GmrXRokYqtr_SjKr_;_`Fy zA$}0rX(i5M>p)4+S3%zf{S@>t=pg7Q=rrhc&?NgT#(e}UQl7(K1Ls!Eb1cu^{2=A| z&+Nxp0X&?+Sps~|R=0=e?rK!#IiB^^Ih|Wr3_jr-NUR0nD1q~xbuTcq&Fx`+0Gww~ zFNk*n#SS1Z?p(Zhfw$()<*RDFbA7k_=K4PVzROg5?0a3kudd$V!}}!@zSO2}Be)J6 zXGO_%m6OND9^uo2DP8!&o8nNlxRDgTWF+S6N*GoK2RbX$6N5w^T75Dr&wW05mh~kQ z^7!YoenVJXs1&xCw1g&th-BfD=0b_??noTw;t3Kr-60gLg^YTvuk_lHrw?2kTssx$ zJnvOhV%tn#04cpj=ruy`h%B*wXpa;CDLvkql*8~|6|}YvnBe3oJ+9SZoVRDPz)q^& zF9K7K$tDxBxtX+4PjK-Xl9 zu@5S(#R8n=sHp6zawq5dB(`pzt#xQ&%K+D#g{>C2t}M*ftv%YpT*M7_U}2cK|CcEi4ZMGX5;ge>F ziM!bnIdT(swO{2QoPkx`1;FY$c?*9 z_P}rdzY6r1`=&~&e8BEM%Rh=jg(m^?0%EP*KNoJ(mjORw>$9BujT#RZZpqgH%Znj! z7jD;`aiQ8%cdhT`kJH}->?q9kwgap2ru_$iH`@JE{_s`?VzfO){0Mx)ziY)13+$x) z>359JK9mvP0Zw~=1Rn<8Y2#Diw9m+-{j=aaI5P66|1a<`@CZVim`^XxyX`Vy^_|4K z<_`d?@gTktxC8O3?%HPo^Bm)cUEXES2j-`?!p*?WyYJ5c^FELM@vghwfm#1vU><-u z_QX0c*NYDQ>DZ0pz`ejV5(}{b*m+mJ8F&EY>@WYHz6HD!7+HC@zZ2Mbcm5!7%{Q^% z!lCJC^OwNf&#CXl_&o|dy58pBl0`Et;dRsUQ?6l9@DDKm=$MO3cu=8&I zEb!B)uiiSwflmStOZ%8Z%+opGoQ=zX$AJN5e=2~LzZLNJL%=F|nc;U3KYe^5(G?2K z4d9EW2d9g$PlS?2%1C#1q9hOqCjwou#JXTCAis$M!SqH*7q_oi8E9GFj7J07353(# z-J3*bA{mMVaICOz(wir=oQC9Am2F6>v@UCFhb4MrTe4fQ3!JAII0e11_0$kZMU22Y zJR3++9M||oiIFhiGs;qehnzrXIvx@<1P%E*P<%(2c5Z?|?f1 literal 0 HcmV?d00001 diff --git a/src/cmd/unixbench/pgms/tst.sh b/src/cmd/unixbench/pgms/tst.sh new file mode 100755 index 0000000..99006e9 --- /dev/null +++ b/src/cmd/unixbench/pgms/tst.sh @@ -0,0 +1,20 @@ +#! /bin/sh +############################################################################### +# The BYTE UNIX Benchmarks - Release 3 +# Module: tst.sh SID: 3.4 5/15/91 19:30:24 +# +############################################################################### +# Bug reports, patches, comments, suggestions should be sent to: +# +# Ben Smith or Rick Grehan at BYTE Magazine +# ben@bytepb.UUCP rick_g@bytepb.UUCP +# +############################################################################### +# Modification Log: +# +############################################################################### +ID="@(#)tst.sh:3.4 -- 5/15/91 19:30:24"; +sort >sort.$$ od.$$ +grep the sort.$$ | tee grep.$$ | wc > wc.$$ +rm sort.$$ grep.$$ od.$$ wc.$$ diff --git a/src/cmd/unixbench/pgms/unixbench.logo b/src/cmd/unixbench/pgms/unixbench.logo new file mode 100644 index 0000000..1363e9e --- /dev/null +++ b/src/cmd/unixbench/pgms/unixbench.logo @@ -0,0 +1,15 @@ + + # # # # # # # ##### ###### # # #### # # + # # ## # # # # # # # ## # # # # # + # # # # # # ## ##### ##### # # # # ###### + # # # # # # ## # # # # # # # # # + # # # ## # # # # # # # ## # # # # + #### # # # # # ##### ###### # # #### # # + + 4 1 Based on the Byte Magazine Unix Benchmark + 44 11 + v v 4 4 1 + v v 44444 1 v4.1 revisions mostly by David C. Niemi, + v 4 o 111 Reston, VA, USA + + diff --git a/src/cmd/unixbench/results/log b/src/cmd/unixbench/results/log new file mode 100644 index 0000000..706a67d --- /dev/null +++ b/src/cmd/unixbench/results/log @@ -0,0 +1,13 @@ +| BYTE UNIX Benchmarks (Version 4.1.0) +| System -- Linux laptop01 3.0.0-12-generic #20-Ubuntu SMP Fri Oct 7 14:50:42 UTC 2011 i686 i686 i386 GNU/Linux +| Start Benchmark Run: Thu Oct 4 12:49:17 BST 2012 +| 3 interactive users. +| 12:49:17 up 2:43, 3 users, load average: 0.07, 0.03, 0.05 +| lrwxrwxrwx 1 root root 4 2012-04-20 13:35 /bin/sh -> dash +| /bin/sh: symbolic link to `dash' +| /dev/sda1 303701360 143403600 144870640 50% / + +Double-Precision Whetstone| no measured results| + +End Benchmark Run: Thu Oct 4 12:49:49 BST 2012 + 3 interactive users. diff --git a/src/cmd/unixbench/results/log.accum b/src/cmd/unixbench/results/log.accum new file mode 100644 index 0000000..7291aac --- /dev/null +++ b/src/cmd/unixbench/results/log.accum @@ -0,0 +1,21 @@ +| BYTE UNIX Benchmarks (Version 4.1.0) +| System -- Linux laptop01 3.0.0-12-generic #20-Ubuntu SMP Fri Oct 7 14:50:42 UTC 2011 i686 i686 i386 GNU/Linux +| Start Benchmark Run: Thu Oct 4 12:48:34 BST 2012 +| 3 interactive users. +| 12:48:34 up 2:42, 3 users, load average: 0.00, 0.01, 0.05 +| lrwxrwxrwx 1 root root 4 2012-04-20 13:35 /bin/sh -> dash +| /bin/sh: symbolic link to `dash' +| /dev/sda1 303701360 143403604 144870636 50% / + +Dhrystone 2 using register variables| no measured results| + +Terminated during iteration 2 +Double-Precision Whetstone| no measured results| + +************************** +* Benchmark Aborted .... * +************************** + + 3 interactive users. + +End Benchmark Run (Thu Oct 4 12:49:11 BST 2012) .... diff --git a/src/cmd/unixbench/results/report b/src/cmd/unixbench/results/report new file mode 100644 index 0000000..84ed2d7 --- /dev/null +++ b/src/cmd/unixbench/results/report @@ -0,0 +1,18 @@ + + BYTE UNIX Benchmarks (Version 4.1.0) + System -- Linux laptop01 3.0.0-12-generic #20-Ubuntu SMP Fri Oct 7 14:50:42 UTC 2011 i686 i686 i386 GNU/Linux + Start Benchmark Run: Thu Oct 4 12:49:17 BST 2012 + 3 interactive users. + 12:49:17 up 2:43, 3 users, load average: 0.07, 0.03, 0.05 + lrwxrwxrwx 1 root root 4 2012-04-20 13:35 /bin/sh -> dash + /bin/sh: symbolic link to `dash' + /dev/sda1 303701360 143403600 144870640 50% / +Double-Precision Whetstone no measured results + + + INDEX VALUES +TEST BASELINE RESULT INDEX + +Double-Precision Whetstone 55.0 0.0 0.0 + ========= + FINAL SCORE 0.0 diff --git a/src/cmd/unixbench/results/times b/src/cmd/unixbench/results/times new file mode 100644 index 0000000..455b9c1 --- /dev/null +++ b/src/cmd/unixbench/results/times @@ -0,0 +1,32 @@ +TEST|Double-Precision Whetstone +FLAVOR|Linux +/home/matt/retrobsd/retrobsd-partition/src/cmd/unixbench/pgms/whetstone-double: 1: Syntax error: "(" unexpected +Command exited with non-zero status 2 + 0.00 real 0.00 user 0.00 sys +/home/matt/retrobsd/retrobsd-partition/src/cmd/unixbench/pgms/whetstone-double: 1: Syntax error: "(" unexpected +Command exited with non-zero status 2 + 0.00 real 0.00 user 0.00 sys +/home/matt/retrobsd/retrobsd-partition/src/cmd/unixbench/pgms/whetstone-double: 1: Syntax error: "(" unexpected +Command exited with non-zero status 2 + 0.00 real 0.00 user 0.00 sys +/home/matt/retrobsd/retrobsd-partition/src/cmd/unixbench/pgms/whetstone-double: 1: Syntax error: "(" unexpected +Command exited with non-zero status 2 + 0.00 real 0.00 user 0.00 sys +/home/matt/retrobsd/retrobsd-partition/src/cmd/unixbench/pgms/whetstone-double: 1: Syntax error: "(" unexpected +Command exited with non-zero status 2 + 0.00 real 0.00 user 0.00 sys +/home/matt/retrobsd/retrobsd-partition/src/cmd/unixbench/pgms/whetstone-double: 1: Syntax error: "(" unexpected +Command exited with non-zero status 2 + 0.00 real 0.00 user 0.00 sys +/home/matt/retrobsd/retrobsd-partition/src/cmd/unixbench/pgms/whetstone-double: 1: Syntax error: "(" unexpected +Command exited with non-zero status 2 + 0.00 real 0.00 user 0.00 sys +/home/matt/retrobsd/retrobsd-partition/src/cmd/unixbench/pgms/whetstone-double: 1: Syntax error: "(" unexpected +Command exited with non-zero status 2 + 0.00 real 0.00 user 0.00 sys +/home/matt/retrobsd/retrobsd-partition/src/cmd/unixbench/pgms/whetstone-double: 1: Syntax error: "(" unexpected +Command exited with non-zero status 2 + 0.00 real 0.00 user 0.00 sys +/home/matt/retrobsd/retrobsd-partition/src/cmd/unixbench/pgms/whetstone-double: 1: Syntax error: "(" unexpected +Command exited with non-zero status 2 + 0.00 real 0.00 user 0.00 sys diff --git a/src/cmd/unixbench/src/arith.c b/src/cmd/unixbench/src/arith.c new file mode 100644 index 0000000..d8564ba --- /dev/null +++ b/src/cmd/unixbench/src/arith.c @@ -0,0 +1,110 @@ + +/******************************************************************************* + * The BYTE UNIX Benchmarks - Release 3 + * Module: arith.c SID: 3.3 5/15/91 19:30:19 + * + ******************************************************************************* + * Bug reports, patches, comments, suggestions should be sent to: + * + * Ben Smith, Rick Grehan or Tom Yager + * ben@bytepb.byte.com rick_g@bytepb.byte.com tyager@bytepb.byte.com + * + ******************************************************************************* + * Modification Log: + * May 12, 1989 - modified empty loops to avoid nullifying by optimizing + * compilers + * August 28, 1990 - changed timing relationship--now returns total number + * of iterations (ty) + * November 9, 1990 - made changes suggested by Keith Cantrell + * (digi!kcantrel) to defeat optimization + * to non-existence + * October 22, 1997 - code cleanup to remove ANSI C compiler warnings + * Andy Kahn + * + ******************************************************************************/ + +char SCCSid[] = "@(#) @(#)arith.c:3.3 -- 5/15/91 19:30:19"; +/* + * arithmetic test + * + */ + +#include +#include +#include "timeit.c" + +int dumb_stuff(int); + +volatile unsigned long iter; + +/* this function is called when the alarm expires */ +void report() +{ + fprintf(stderr,"%ld loops\n", iter); + exit(0); +} + +int main(argc, argv) +int argc; +char *argv[]; +{ + int duration; + int result = 0; + + if (argc != 2) { + printf("Usage: %s duration\n", argv[0]); + exit(1); + } + + duration = atoi(argv[1]); + + /* set up alarm call */ + iter = 0; /* init iteration count */ + wake_me(duration, report); + + /* this loop will be interrupted by the alarm call */ + while (1) + { + /* in switching to time-based (instead of iteration-based), + the following statement was added. It should not skew + the timings too much--there was an increment and test + in the "while" expression above. The only difference is + that now we're incrementing a long instead of an int. (ty) */ + ++iter; + /* the loop calls a function to insure that something is done + the results of the function are fed back in (just so they + they won't be thrown away. A loop with + unused assignments may get optimized out of existence */ + result = dumb_stuff(result); + } +} + + +/************************** dumb_stuff *******************/ +int dumb_stuff(i) +int i; +{ +#ifndef arithoh + datum x, y, z; + z = 0; +#endif + /* + * 101 + * sum i*i/(i*i-1) + * i=2 + */ + /* notice that the i value is always reset by the loop */ + for (i=2; i<=101; i++) + { +#ifndef arithoh + x = i; + y = x*x; + z += y/(y-1); + } +return(x+y+z); +#else +} +return(0); +#endif +} + diff --git a/src/cmd/unixbench/src/big.c b/src/cmd/unixbench/src/big.c new file mode 100644 index 0000000..70947ff --- /dev/null +++ b/src/cmd/unixbench/src/big.c @@ -0,0 +1,591 @@ +/******************************************************************************* + * The BYTE UNIX Benchmarks - Release 3 + * Module: big.c SID: 3.3 5/15/91 19:30:18 + * + ******************************************************************************* + * Bug reports, patches, comments, suggestions should be sent to: + * + * Ben Smith, Rick Grehan or Tom Yager + * ben@bytepb.byte.com rick_g@bytepb.byte.com tyager@bytepb.byte.com + * + ******************************************************************************* + * Modification Log: + * 10/22/97 - code cleanup to remove ANSI C compiler warnings + * Andy Kahn + * + ******************************************************************************/ +/* + * dummy code for execl test [ old version of makework.c ] + * + * makework [ -r rate ] [ -c copyfile ] nusers + * + * job streams are specified on standard input with lines of the form + * full_path_name_for_command [ options ] [ +#include +#include +#include +#include +#include +#include +#include + +#define DEF_RATE 5.0 +#define GRANULE 5 +#define CHUNK 60 +#define MAXCHILD 12 +#define MAXWORK 10 + +void wrapup(char *); +void onalarm(int); +void pipeerr(); +void grunt(); +void getwork(void); +#if debug +void dumpwork(void); +#endif +void fatal(char *s); + +float thres; +float est_rate = DEF_RATE; +int nusers; /* number of concurrent users to be simulated by + * this process */ +int firstuser; /* ordinal identification of first user for this + * process */ +int nwork = 0; /* number of job streams */ +int exit_status = 0; /* returned to parent */ +int sigpipe; /* pipe write error flag */ + +struct st_work { + char *cmd; /* name of command to run */ + char **av; /* arguments to command */ + char *input; /* standard input buffer */ + int inpsize; /* size of standard input buffer */ + char *outf; /* standard output (filename) */ +} work[MAXWORK]; + +struct { + int xmit; /* # characters sent */ + char *bp; /* std input buffer pointer */ + int blen; /* std input buffer length */ + int fd; /* stdin to command */ + int pid; /* child PID */ + char *line; /* start of input line */ + int firstjob; /* inital piece of work */ + int thisjob; /* current piece of work */ +} child[MAXCHILD], *cp; + +int main(argc, argv) +int argc; +char *argv[]; +{ + int i; + int l; + int fcopy = 0; /* fd for copy output */ + int master = 1; /* the REAL master, == 0 for clones */ + int nchild; /* no. of children for a clone to run */ + int done; /* count of children finished */ + int output; /* aggregate output char count for all + children */ + int c; + int thiswork = 0; /* next job stream to allocate */ + int nch; /* # characters to write */ + int written; /* # characters actully written */ + char logname[15]; /* name of the log file(s) */ + int pvec[2]; /* for pipes */ + char *p; + char *prog; /* my name */ + +#if ! debug + freopen("masterlog.00", "a", stderr); +#endif + fprintf(stderr, "*** New Run *** "); + prog = argv[0]; + while (argc > 1 && argv[1][0] == '-') { + p = &argv[1][1]; + argc--; + argv++; + while (*p) { + switch (*p) { + case 'r': + est_rate = atoi(argv[1]); + sscanf(argv[1], "%f", &est_rate); + if (est_rate <= 0) { + fprintf(stderr, "%s: bad rate, reset to %.2f chars/sec\n", prog, DEF_RATE); + est_rate = DEF_RATE; + } + argc--; + argv++; + break; + + case 'c': + fcopy = open(argv[1], 1); + if (fcopy < 0) + fcopy = creat(argv[1], 0600); + if (fcopy < 0) { + fprintf(stderr, "%s: cannot open copy file '%s'\n", + prog, argv[1]); + exit(2); + } + lseek(fcopy, 0L, 2); /* append at end of file */ + argc--; + argv++; + break; + + default: + fprintf(stderr, "%s: bad flag '%c'\n", prog, *p); + exit(4); + } + p++; + } + } + + if (argc < 2) { + fprintf(stderr, "%s: missing nusers\n", prog); + exit(4); + } + + nusers = atoi(argv[1]); + if (nusers < 1) { + fprintf(stderr, "%s: impossible nusers (%d<-%s)\n", prog, nusers, argv[1]); + exit(4); + } + fprintf(stderr, "%d Users\n", nusers); + argc--; + argv++; + + /* build job streams */ + getwork(); +#if debug + dumpwork(); +#endif + + /* clone copies of myself to run up to MAXCHILD jobs each */ + firstuser = MAXCHILD; + fprintf(stderr, "master pid %d\n", getpid()); + fflush(stderr); + while (nusers > MAXCHILD) { + fflush(stderr); + if (nusers >= 2*MAXCHILD) + /* the next clone must run MAXCHILD jobs */ + nchild = MAXCHILD; + else + /* the next clone must run the leftover jobs */ + nchild = nusers - MAXCHILD; + if ((l = fork()) == -1) { + /* fork failed */ + fatal("** clone fork failed **\n"); + goto bepatient; + } else if (l > 0) { + fprintf(stderr, "master clone pid %d\n", l); + /* I am the master with nchild fewer jobs to run */ + nusers -= nchild; + firstuser += MAXCHILD; + continue; + } else { + /* I am a clone, run MAXCHILD jobs */ +#if ! debug + sprintf(logname, "masterlog.%02d", firstuser/MAXCHILD); + freopen(logname, "w", stderr); +#endif + master = 0; + nusers = nchild; + break; + } + } + if (master) + firstuser = 0; + + close(0); + for (i = 0; i < nusers; i++ ) { + fprintf(stderr, "user %d job %d ", firstuser+i, thiswork); + if (pipe(pvec) == -1) { + /* this is fatal */ + fatal("** pipe failed **\n"); + goto bepatient; + } + fflush(stderr); + if ((child[i].pid = fork()) == 0) { + int fd; + /* the command */ + if (pvec[0] != 0) { + close(0); + dup(pvec[0]); + } +#if ! debug + sprintf(logname, "userlog.%02d", firstuser+i); + freopen(logname, "w", stderr); +#endif + for (fd = 3; fd < 24; fd++) + close(fd); + if (work[thiswork].outf[0] != '\0') { + /* redirect std output */ + char *q; + for (q = work[thiswork].outf; *q != '\n'; q++) ; + *q = '\0'; + if (freopen(work[thiswork].outf, "w", stdout) == NULL) { + fprintf(stderr, "makework: cannot open %s for std output\n", + work[thiswork].outf); + fflush(stderr); + } + *q = '\n'; + } + execv(work[thiswork].cmd, work[thiswork].av); + /* don't expect to get here! */ + fatal("** exec failed **\n"); + goto bepatient; + } + else if (child[i].pid == -1) { + fatal("** fork failed **\n"); + goto bepatient; + } + else { + close(pvec[0]); + child[i].fd = pvec[1]; + child[i].line = child[i].bp = work[thiswork].input; + child[i].blen = work[thiswork].inpsize; + child[i].thisjob = thiswork; + child[i].firstjob = thiswork; + fprintf(stderr, "pid %d pipe fd %d", child[i].pid, child[i].fd); + if (work[thiswork].outf[0] != '\0') { + char *q; + fprintf(stderr, " > "); + for (q=work[thiswork].outf; *q != '\n'; q++) + fputc(*q, stderr); + } + fputc('\n', stderr); + thiswork++; + if (thiswork >= nwork) + thiswork = 0; + } + } + fflush(stderr); + + srand(time(0)); + thres = 0; + done = output = 0; + for (i = 0; i < nusers; i++) { + if (child[i].blen == 0) + done++; + else + thres += est_rate * GRANULE; + } + est_rate = thres; + + signal(SIGALRM, onalarm); + signal(SIGPIPE, pipeerr); + alarm(GRANULE); + while (done < nusers) { + for (i = 0; i < nusers; i++) { + cp = &child[i]; + if (cp->xmit >= cp->blen) continue; + l = rand() % CHUNK + 1; /* 1-CHUNK chars */ + if (l == 0) continue; + if (cp->xmit + l > cp->blen) + l = cp->blen - cp->xmit; + p = cp->bp; + cp->bp += l; + cp->xmit += l; +#if debug + fprintf(stderr, "child %d, %d processed, %d to go\n", i, cp->xmit, cp->blen - cp->xmit); +#endif + while (p < cp->bp) { + if (*p == '\n' || (p == &cp->bp[-1] && cp->xmit >= cp->blen)) { + /* write it out */ + nch = p - cp->line + 1; + if ((written = write(cp->fd, cp->line, nch)) != nch) { + /* argh! */ + cp->line[nch] = '\0'; + fprintf(stderr, "user %d job %d cmd %s ", + firstuser+i, cp->thisjob, cp->line); + fprintf(stderr, "write(,,%d) returns %d\n", nch, written); + if (sigpipe) + fatal("** SIGPIPE error **\n"); + else + fatal("** write error **\n"); + goto bepatient; + + } + if (fcopy) + write(fcopy, cp->line, p - cp->line + 1); +#if debug + fprintf(stderr, "child %d gets \"", i); + { + char *q = cp->line; + while (q <= p) { + if (*q >= ' ' && *q <= '~') + fputc(*q, stderr); + else + fprintf(stderr, "\\%03o", *q); + q++; + } + } + fputc('"', stderr); +#endif + cp->line = &p[1]; + } + p++; + } + if (cp->xmit >= cp->blen) { + done++; + close(cp->fd); +#if debug + fprintf(stderr, "child %d, close std input\n", i); +#endif + } + output += l; + } + while (output > thres) { + pause(); +#if debug + fprintf(stderr, "after pause: output, thres, done %d %.2f %d\n", output, thres, done); +#endif + } + } + +bepatient: + alarm(0); +/**** + * If everything is going OK, we should simply be able to keep + * looping unitil 'wait' fails, however some descendent process may + * be in a state from which it can never exit, and so a timeout + * is used. + * 5 minutes should be ample, since the time to run all jobs is of + * the order of 5-10 minutes, however some machines are painfully slow, + * so the timeout has been set at 20 minutes (1200 seconds). + ****/ + signal(SIGALRM, grunt); + alarm(1200); + while ((c = wait(&l)) != -1) { + for (i = 0; i < nusers; i++) { + if (c == child[i].pid) { + fprintf(stderr, "user %d job %d pid %d done", firstuser+i, child[i].thisjob, c); + if (l != 0) { + if (l & 0x7f) + fprintf(stderr, " status %d", l & 0x7f); + if (l & 0xff00) + fprintf(stderr, " exit code %d", (l>>8) & 0xff); + exit_status = 4; + } + fputc('\n', stderr); + c = child[i].pid = -1; + break; + } + } + if (c != -1) { + fprintf(stderr, "master clone done, pid %d ", c); + if (l != 0) { + if (l & 0x7f) + fprintf(stderr, " status %d", l & 0x7f); + if (l & 0xff00) + fprintf(stderr, " exit code %d", (l>>8) & 0xff); + exit_status = 4; + } + fputc('\n', stderr); + } + } + alarm(0); + wrapup("Finished waiting ..."); + + exit(0); +} + +void onalarm(int foo) +{ + thres += est_rate; + signal(SIGALRM, onalarm); + alarm(GRANULE); +} + +void grunt() +{ + /* timeout after label "bepatient" in main */ + exit_status = 4; + wrapup("Timed out waiting for jobs to finish ..."); +} + +void pipeerr() +{ + sigpipe++; +} + +void wrapup(char *reason) +{ + int i; + int killed = 0; + fflush(stderr); + for (i = 0; i < nusers; i++) { + if (child[i].pid > 0 && kill(child[i].pid, SIGKILL) != -1) { + if (!killed) { + killed++; + fprintf(stderr, "%s\n", reason); + fflush(stderr); + } + fprintf(stderr, "user %d job %d pid %d killed off\n", firstuser+i, child[i].thisjob, child[i].pid); + fflush(stderr); + } + } + exit(exit_status); +} + +#define MAXLINE 512 +void getwork(void) +{ + int i; + int f; + int ac=0; + char *lp = (void *)0; + char *q = (void *)0; + struct st_work *w = (void *)0; + char line[MAXLINE]; + + while (fgets(line, MAXLINE, stdin) != NULL) { + if (nwork >= MAXWORK) { + fprintf(stderr, "Too many jobs specified, .. increase MAXWORK\n"); + exit(4); + } + w = &work[nwork]; + lp = line; + i = 1; + while (*lp && *lp != ' ') { + i++; + lp++; + } + w->cmd = (char *)malloc(i); + strncpy(w->cmd, line, i-1); + w->cmd[i-1] = '\0'; + w->inpsize = 0; + w->input = ""; + /* start to build arg list */ + ac = 2; + w->av = (char **)malloc(2*sizeof(char *)); + q = w->cmd; + while (*q) q++; + q--; + while (q >= w->cmd) { + if (*q == '/') { + q++; + break; + } + q--; + } + w->av[0] = q; + while (*lp) { + if (*lp == ' ') { + /* space */ + lp++; + continue; + } + else if (*lp == '<') { + /* standard input for this job */ + q = ++lp; + while (*lp && *lp != ' ') lp++; + *lp = '\0'; + if ((f = open(q, 0)) == -1) { + fprintf(stderr, "cannot open input file (%s) for job %d\n", + q, nwork); + exit(4); + } + /* gobble input */ + w->input = (char *)malloc(512); + while ((i = read(f, &w->input[w->inpsize], 512)) > 0) { + w->inpsize += i; + w->input = (char *)realloc(w->input, w->inpsize+512); + } + w->input = (char *)realloc(w->input, w->inpsize); + close(f); + /* extract stdout file name from line beginning "C=" */ + w->outf = ""; + for (q = w->input; q < &w->input[w->inpsize-10]; q++) { + if (*q == '\n' && strncmp(&q[1], "C=", 2) == 0) { + w->outf = &q[3]; + break; + } + } +#if debug + if (*w->outf) { + fprintf(stderr, "stdout->"); + for (q=w->outf; *q != '\n'; q++) + fputc(*q, stderr); + fputc('\n', stderr); + } +#endif + } + else { + /* a command option */ + ac++; + w->av = (char **)realloc(w->av, ac*sizeof(char *)); + q = lp; + i = 1; + while (*lp && *lp != ' ') { + lp++; + i++; + } + w->av[ac-2] = (char *)malloc(i); + strncpy(w->av[ac-2], q, i-1); + w->av[ac-2][i-1] = '\0'; + } + } + w->av[ac-1] = (char *)0; + nwork++; + } +} + +#if debug +void dumpwork(void) +{ + int i; + int j; + + for (i = 0; i < nwork; i++) { + fprintf(stderr, "job %d: cmd: %s\n", i, work[i].cmd); + j = 0; + while (work[i].av[j]) { + fprintf(stderr, "argv[%d]: %s\n", j, work[i].av[j]); + j++; + } + fprintf(stderr, "input: %d chars text: ", work[i].inpsize); + if (work[i].input == (char *)0) + fprintf(stderr, "\n"); + else { + register char *pend; + char *p; + char c; + p = work[i].input; + while (*p) { + pend = p; + while (*pend && *pend != '\n') + pend++; + c = *pend; + *pend = '\0'; + fprintf(stderr, "%s\n", p); + *pend = c; + p = &pend[1]; + } + } + } +} +#endif + +void fatal(char *s) +{ + int i; + fprintf(stderr, s); + fflush(stderr); + perror("Reason?"); + fflush(stderr); + for (i = 0; i < nusers; i++) { + if (child[i].pid > 0 && kill(child[i].pid, SIGKILL) != -1) { + fprintf(stderr, "pid %d killed off\n", child[i].pid); + fflush(stderr); + } + } + exit_status = 4; +} diff --git a/src/cmd/unixbench/src/context1.c b/src/cmd/unixbench/src/context1.c new file mode 100644 index 0000000..b967371 --- /dev/null +++ b/src/cmd/unixbench/src/context1.c @@ -0,0 +1,111 @@ + +/******************************************************************************* + * The BYTE UNIX Benchmarks - Release 3 + * Module: context1.c SID: 3.3 5/15/91 19:30:18 + * + ******************************************************************************* + * Bug reports, patches, comments, suggestions should be sent to: + * + * Ben Smith, Rick Grehan or Tom Yager + * ben@bytepb.byte.com rick_g@bytepb.byte.com tyager@bytepb.byte.com + * + ******************************************************************************* + * Modification Log: + * $Header: context1.c,v 3.4 87/06/22 14:22:59 kjmcdonell Beta $ + * August 28, 1990 - changed timing routines--now returns total number of + * iterations in specified time period + * October 22, 1997 - code cleanup to remove ANSI C compiler warnings + * Andy Kahn + * + ******************************************************************************/ +char SCCSid[] = "@(#) @(#)context1.c:3.3 -- 5/15/91 19:30:18"; +/* + * Context switching via synchronized unbuffered pipe i/o + * + */ + +#include +#include +#include +#include "timeit.c" + +unsigned long iter; + +void report() +{ + fprintf(stderr,"%lu loops\n", iter); + exit(0); +} + +int main(argc, argv) +int argc; +char *argv[]; +{ + int duration; + unsigned long check; + int p1[2], p2[2]; + + if (argc != 2) { + printf("Usage: context duration\n"); + exit(1); + } + + duration = atoi(argv[1]); + + /* set up alarm call */ + iter = 0; + wake_me(duration, report); + + if (pipe(p1) || pipe(p2)) { + perror("pipe create failed"); + exit(1); + } + + if (fork()) { /* parent process */ + /* master, write p1 & read p2 */ + close(p1[0]); close(p2[1]); + while (1) { + if (write(p1[1], (char *)&iter, sizeof(iter)) != sizeof(iter)) { + if ((errno != 0) && (errno != EINTR)) + perror("master write failed"); + exit(1); + } + if (read(p2[0], (char *)&check, sizeof(check)) != sizeof(check)) { + if ((errno != 0) && (errno != EINTR)) + perror("master read failed"); + exit(1); + } + if (check != iter) { + printf("Master sync error: expect %lu, got %lu\n", + iter, check); + exit(2); + } + iter++; + } + } + else { /* child process */ + unsigned long iter1; + + iter1 = 0; + /* slave, read p1 & write p2 */ + close(p1[1]); close(p2[0]); + while (1) { + if (read(p1[0], (char *)&check, sizeof(check)) != sizeof(check)) { + if ((errno != 0) && (errno != EINTR)) + perror("slave read failed"); + exit(1); + } + if (check != iter1) { + printf("Slave sync error: expect %lu, got %lu\n", + iter, check); + exit(2); + } + if (write(p2[1], (char *)&iter1, sizeof(iter1)) != sizeof(check)) { + if ((errno != 0) && (errno != EINTR)) + perror("slave write failed"); + exit(1); + } + iter1++; + } + } +} diff --git a/src/cmd/unixbench/src/dhry.h b/src/cmd/unixbench/src/dhry.h new file mode 100644 index 0000000..34a4ada --- /dev/null +++ b/src/cmd/unixbench/src/dhry.h @@ -0,0 +1,435 @@ +/***************************************************************************** + * The BYTE UNIX Benchmarks - Release 3 + * Module: dhry.h SID: 3.4 5/15/91 19:30:21 + * + ***************************************************************************** + * Bug reports, patches, comments, suggestions should be sent to: + * + * Ben Smith, Rick Grehan or Tom Yager + * ben@bytepb.byte.com rick_g@bytepb.byte.com tyager@bytepb.byte.com + * + ***************************************************************************** + * Modification Log: + * addapted from: + * + * + * "DHRYSTONE" Benchmark Program + * ----------------------------- + * + * Version: C, Version 2.1 + * + * File: dhry.h (part 1 of 3) + * + * Date: May 25, 1988 + * + * Author: Reinhold P. Weicker + * Siemens AG, AUT E 51 + * Postfach 3220 + * 8520 Erlangen + * Germany (West) + * Phone: [+49]-9131-7-20330 + * (8-17 Central European Time) + * Usenet: ..!mcvax!unido!estevax!weicker + * + * Original Version (in Ada) published in + * "Communications of the ACM" vol. 27., no. 10 (Oct. 1984), + * pp. 1013 - 1030, together with the statistics + * on which the distribution of statements etc. is based. + * + * In this C version, the following C library functions are used: + * - strcpy, strcmp (inside the measurement loop) + * - printf, scanf (outside the measurement loop) + * In addition, Berkeley UNIX system calls "times ()" or "time ()" + * are used for execution time measurement. For measurements + * on other systems, these calls have to be changed. + * + * Collection of Results: + * Reinhold Weicker (address see above) and + * + * Rick Richardson + * PC Research. Inc. + * 94 Apple Orchard Drive + * Tinton Falls, NJ 07724 + * Phone: (201) 834-1378 (9-17 EST) + * Usenet: ...!seismo!uunet!pcrat!rick + * + * Please send results to Rick Richardson and/or Reinhold Weicker. + * Complete information should be given on hardware and software used. + * Hardware information includes: Machine type, CPU, type and size + * of caches; for microprocessors: clock frequency, memory speed + * (number of wait states). + * Software information includes: Compiler (and runtime library) + * manufacturer and version, compilation switches, OS version. + * The Operating System version may give an indication about the + * compiler; Dhrystone itself performs no OS calls in the measurement loop. + * + * The complete output generated by the program should be mailed + * such that at least some checks for correctness can be made. + * + *************************************************************************** + * + * History: This version C/2.1 has been made for two reasons: + * + * 1) There is an obvious need for a common C version of + * Dhrystone, since C is at present the most popular system + * programming language for the class of processors + * (microcomputers, minicomputers) where Dhrystone is used most. + * There should be, as far as possible, only one C version of + * Dhrystone such that results can be compared without + * restrictions. In the past, the C versions distributed + * by Rick Richardson (Version 1.1) and by Reinhold Weicker + * had small (though not significant) differences. + * + * 2) As far as it is possible without changes to the Dhrystone + * statistics, optimizing compilers should be prevented from + * removing significant statements. + * + * This C version has been developed in cooperation with + * Rick Richardson (Tinton Falls, NJ), it incorporates many + * ideas from the "Version 1.1" distributed previously by + * him over the UNIX network Usenet. + * I also thank Chaim Benedelac (National Semiconductor), + * David Ditzel (SUN), Earl Killian and John Mashey (MIPS), + * Alan Smith and Rafael Saavedra-Barrera (UC at Berkeley) + * for their help with comments on earlier versions of the + * benchmark. + * + * Changes: In the initialization part, this version follows mostly + * Rick Richardson's version distributed via Usenet, not the + * version distributed earlier via floppy disk by Reinhold Weicker. + * As a concession to older compilers, names have been made + * unique within the first 8 characters. + * Inside the measurement loop, this version follows the + * version previously distributed by Reinhold Weicker. + * + * At several places in the benchmark, code has been added, + * but within the measurement loop only in branches that + * are not executed. The intention is that optimizing compilers + * should be prevented from moving code out of the measurement + * loop, or from removing code altogether. Since the statements + * that are executed within the measurement loop have NOT been + * changed, the numbers defining the "Dhrystone distribution" + * (distribution of statements, operand types and locality) + * still hold. Except for sophisticated optimizing compilers, + * execution times for this version should be the same as + * for previous versions. + * + * Since it has proven difficult to subtract the time for the + * measurement loop overhead in a correct way, the loop check + * has been made a part of the benchmark. This does have + * an impact - though a very minor one - on the distribution + * statistics which have been updated for this version. + * + * All changes within the measurement loop are described + * and discussed in the companion paper "Rationale for + * Dhrystone version 2". + * + * Because of the self-imposed limitation that the order and + * distribution of the executed statements should not be + * changed, there are still cases where optimizing compilers + * may not generate code for some statements. To a certain + * degree, this is unavoidable for small synthetic benchmarks. + * Users of the benchmark are advised to check code listings + * whether code is generated for all statements of Dhrystone. + * + * Version 2.1 is identical to version 2.0 distributed via + * the UNIX network Usenet in March 1988 except that it corrects + * some minor deficiencies that were found by users of version 2.0. + * The only change within the measurement loop is that a + * non-executed "else" part was added to the "if" statement in + * Func_3, and a non-executed "else" part removed from Proc_3. + * + *************************************************************************** + * + * Defines: The following "Defines" are possible: + * -DREG=register (default: Not defined) + * As an approximation to what an average C programmer + * might do, the "register" storage class is applied + * (if enabled by -DREG=register) + * - for local variables, if they are used (dynamically) + * five or more times + * - for parameters if they are used (dynamically) + * six or more times + * Note that an optimal "register" strategy is + * compiler-dependent, and that "register" declarations + * do not necessarily lead to faster execution. + * -DNOSTRUCTASSIGN (default: Not defined) + * Define if the C compiler does not support + * assignment of structures. + * -DNOENUMS (default: Not defined) + * Define if the C compiler does not support + * enumeration types. + * -DTIMES (default) + * -DTIME + * The "times" function of UNIX (returning process times) + * or the "time" function (returning wallclock time) + * is used for measurement. + * For single user machines, "time ()" is adequate. For + * multi-user machines where you cannot get single-user + * access, use the "times ()" function. If you have + * neither, use a stopwatch in the dead of night. + * "printf"s are provided marking the points "Start Timer" + * and "Stop Timer". DO NOT use the UNIX "time(1)" + * command, as this will measure the total time to + * run this program, which will (erroneously) include + * the time to allocate storage (malloc) and to perform + * the initialization. + * -DHZ=nnn + * In Berkeley UNIX, the function "times" returns process + * time in 1/HZ seconds, with HZ = 60 for most systems. + * CHECK YOUR SYSTEM DESCRIPTION BEFORE YOU JUST APPLY + * A VALUE. + * + *************************************************************************** + * + * Compilation model and measurement (IMPORTANT): + * + * This C version of Dhrystone consists of three files: + * - dhry.h (this file, containing global definitions and comments) + * - dhry_1.c (containing the code corresponding to Ada package Pack_1) + * - dhry_2.c (containing the code corresponding to Ada package Pack_2) + * + * The following "ground rules" apply for measurements: + * - Separate compilation + * - No procedure merging + * - Otherwise, compiler optimizations are allowed but should be indicated + * - Default results are those without register declarations + * See the companion paper "Rationale for Dhrystone Version 2" for a more + * detailed discussion of these ground rules. + * + * For 16-Bit processors (e.g. 80186, 80286), times for all compilation + * models ("small", "medium", "large" etc.) should be given if possible, + * together with a definition of these models for the compiler system used. + * + ************************************************************************** + * + * Dhrystone (C version) statistics: + * + * [Comment from the first distribution, updated for version 2. + * Note that because of language differences, the numbers are slightly + * different from the Ada version.] + * + * The following program contains statements of a high level programming + * language (here: C) in a distribution considered representative: + * + * assignments 52 (51.0 %) + * control statements 33 (32.4 %) + * procedure, function calls 17 (16.7 %) + * + * 103 statements are dynamically executed. The program is balanced with + * respect to the three aspects: + * + * - statement type + * - operand type + * - operand locality + * operand global, local, parameter, or constant. + * + * The combination of these three aspects is balanced only approximately. + * + * 1. Statement Type: + * ----------------- number + * + * V1 = V2 9 + * (incl. V1 = F(..) + * V = Constant 12 + * Assignment, 7 + * with array element + * Assignment, 6 + * with record component + * -- + * 34 34 + * + * X = Y +|-|"&&"|"|" Z 5 + * X = Y +|-|"==" Constant 6 + * X = X +|- 1 3 + * X = Y *|/ Z 2 + * X = Expression, 1 + * two operators + * X = Expression, 1 + * three operators + * -- + * 18 18 + * + * if .... 14 + * with "else" 7 + * without "else" 7 + * executed 3 + * not executed 4 + * for ... 7 | counted every time + * while ... 4 | the loop condition + * do ... while 1 | is evaluated + * switch ... 1 + * break 1 + * declaration with 1 + * initialization + * -- + * 34 34 + * + * P (...) procedure call 11 + * user procedure 10 + * library procedure 1 + * X = F (...) + * function call 6 + * user function 5 + * library function 1 + * -- + * 17 17 + * --- + * 103 + * + * The average number of parameters in procedure or function calls + * is 1.82 (not counting the function values as implicit parameters). + * + * + * 2. Operators + * ------------ + * number approximate + * percentage + * + * Arithmetic 32 50.8 + * + * + 21 33.3 + * - 7 11.1 + * * 3 4.8 + * / (int div) 1 1.6 + * + * Comparison 27 42.8 + * + * == 9 14.3 + * /= 4 6.3 + * > 1 1.6 + * < 3 4.8 + * >= 1 1.6 + * <= 9 14.3 + * + * Logic 4 6.3 + * + * && (AND-THEN) 1 1.6 + * | (OR) 1 1.6 + * ! (NOT) 2 3.2 + * + * -- ----- + * 63 100.1 + * + * + * 3. Operand Type (counted once per operand reference): + * --------------- + * number approximate + * percentage + * + * Integer 175 72.3 % + * Character 45 18.6 % + * Pointer 12 5.0 % + * String30 6 2.5 % + * Array 2 0.8 % + * Record 2 0.8 % + * --- ------- + * 242 100.0 % + * + * When there is an access path leading to the final operand (e.g. a record + * component), only the final data type on the access path is counted. + * + * + * 4. Operand Locality: + * ------------------- + * number approximate + * percentage + * + * local variable 114 47.1 % + * global variable 22 9.1 % + * parameter 45 18.6 % + * value 23 9.5 % + * reference 22 9.1 % + * function result 6 2.5 % + * constant 55 22.7 % + * --- ------- + * 242 100.0 % + * + * + * The program does not compute anything meaningful, but it is syntactically + * and semantically correct. All variables have a value assigned to them + * before they are used as a source operand. + * + * There has been no explicit effort to account for the effects of a + * cache, or to balance the use of long or short displacements for code or + * data. + * + *************************************************************************** + */ + + +/* Compiler and system dependent definitions: */ + +#ifndef TIME +#define TIMES +#endif + /* Use times(2) time function unless */ + /* explicitly defined otherwise */ + +#ifdef TIMES +#include +#include + /* for "times" */ +#endif + +#define Mic_secs_Per_Second 1000000.0 + /* Berkeley UNIX C returns process times in seconds/HZ */ + +#ifdef NOSTRUCTASSIGN +#define structassign(d, s) memcpy(&(d), &(s), sizeof(d)) +#else +#define structassign(d, s) d = s +#endif + +#ifdef NOENUM +#define Ident_1 0 +#define Ident_2 1 +#define Ident_3 2 +#define Ident_4 3 +#define Ident_5 4 + typedef int Enumeration; +#else + typedef enum {Ident_1, Ident_2, Ident_3, Ident_4, Ident_5} + Enumeration; +#endif + /* for boolean and enumeration types in Ada, Pascal */ + +/* General definitions: */ + +#include + /* for strcpy, strcmp */ + +#define Null 0 + /* Value of a Null pointer */ +#define true 1 +#define false 0 + +typedef int One_Thirty; +typedef int One_Fifty; +typedef char Capital_Letter; +typedef int Boolean; +typedef char Str_30 [31]; +typedef int Arr_1_Dim [50]; +typedef int Arr_2_Dim [50] [50]; + +typedef struct record + { + struct record *Ptr_Comp; + Enumeration Discr; + union { + struct { + Enumeration Enum_Comp; + int Int_Comp; + char Str_Comp [31]; + } var_1; + struct { + Enumeration E_Comp_2; + char Str_2_Comp [31]; + } var_2; + struct { + char Ch_1_Comp; + char Ch_2_Comp; + } var_3; + } variant; + } Rec_Type, *Rec_Pointer; + diff --git a/src/cmd/unixbench/src/dhry_1.c b/src/cmd/unixbench/src/dhry_1.c new file mode 100644 index 0000000..0782658 --- /dev/null +++ b/src/cmd/unixbench/src/dhry_1.c @@ -0,0 +1,431 @@ +/***************************************************************************** + * The BYTE UNIX Benchmarks - Release 3 + * Module: dhry_1.c SID: 3.4 5/15/91 19:30:21 + * + ***************************************************************************** + * Bug reports, patches, comments, suggestions should be sent to: + * + * Ben Smith, Rick Grehan or Tom Yager + * ben@bytepb.byte.com rick_g@bytepb.byte.com tyager@bytepb.byte.com + * + ***************************************************************************** + * + * *** WARNING **** With BYTE's modifications applied, results obtained with + * ******* this version of the Dhrystone program may not be applicable + * to other versions. + * + * Modification Log: + * 10/22/97 - code cleanup to remove ANSI C compiler warnings + * Andy Kahn + * + * Adapted from: + * + * "DHRYSTONE" Benchmark Program + * ----------------------------- + * + * Version: C, Version 2.1 + * + * File: dhry_1.c (part 2 of 3) + * + * Date: May 25, 1988 + * + * Author: Reinhold P. Weicker + * + ***************************************************************************/ +char SCCSid[] = "@(#) @(#)dhry_1.c:3.4 -- 5/15/91 19:30:21"; + +#include +#include +#include +#include "dhry.h" +#include "timeit.c" + +unsigned long Run_Index; + +void report() +{ + fprintf(stderr,"%ld loops\n", Run_Index); + exit(0); +} + +/* Global Variables: */ + +Rec_Pointer Ptr_Glob, + Next_Ptr_Glob; +int Int_Glob; +Boolean Bool_Glob; +char Ch_1_Glob, + Ch_2_Glob; +int Arr_1_Glob [50]; +int Arr_2_Glob [50] [50]; + +Enumeration Func_1 (); + /* forward declaration necessary since Enumeration may not simply be int */ + +#ifndef REG + Boolean Reg = false; +#define REG + /* REG becomes defined as empty */ + /* i.e. no register variables */ +#else + Boolean Reg = true; +#endif + +/* variables for time measurement: */ + +#ifdef TIMES +struct tms time_info; +extern int times (); + /* see library function "times" */ +#define Too_Small_Time 120 + /* Measurements should last at least about 2 seconds */ +#endif +#ifdef TIME +extern long time(); + /* see library function "time" */ +#define Too_Small_Time 2 + /* Measurements should last at least 2 seconds */ +#endif + +long Begin_Time, + End_Time, + User_Time; +float Microseconds, + Dhrystones_Per_Second; + +/* end of variables for time measurement */ + +void Proc_1 (REG Rec_Pointer Ptr_Val_Par); +void Proc_2 (One_Fifty *Int_Par_Ref); +void Proc_3 (Rec_Pointer *Ptr_Ref_Par); +void Proc_4 (void); +void Proc_5 (void); + + +extern Boolean Func_2(Str_30, Str_30); +extern void Proc_6(Enumeration, Enumeration *); +extern void Proc_7(One_Fifty, One_Fifty, One_Fifty *); +extern void Proc_8(Arr_1_Dim, Arr_2_Dim, int, int); + +int main (argc, argv) +int argc; +char *argv[]; + /* main program, corresponds to procedures */ + /* Main and Proc_0 in the Ada version */ +{ + int duration; + One_Fifty Int_1_Loc; + REG One_Fifty Int_2_Loc; + One_Fifty Int_3_Loc; + REG char Ch_Index; + Enumeration Enum_Loc; + Str_30 Str_1_Loc; + Str_30 Str_2_Loc; + + /* Initializations */ + + Next_Ptr_Glob = (Rec_Pointer) malloc (sizeof (Rec_Type)); + Ptr_Glob = (Rec_Pointer) malloc (sizeof (Rec_Type)); + + Ptr_Glob->Ptr_Comp = Next_Ptr_Glob; + Ptr_Glob->Discr = Ident_1; + Ptr_Glob->variant.var_1.Enum_Comp = Ident_3; + Ptr_Glob->variant.var_1.Int_Comp = 40; + strcpy (Ptr_Glob->variant.var_1.Str_Comp, + "DHRYSTONE PROGRAM, SOME STRING"); + strcpy (Str_1_Loc, "DHRYSTONE PROGRAM, 1'ST STRING"); + + Arr_2_Glob [8][7] = 10; + /* Was missing in published program. Without this statement, */ + /* Arr_2_Glob [8][7] would have an undefined value. */ + /* Warning: With 16-Bit processors and Number_Of_Runs > 32000, */ + /* overflow may occur for this array element. */ + +#ifdef PRATTLE + printf ("\n"); + printf ("Dhrystone Benchmark, Version 2.1 (Language: C)\n"); + printf ("\n"); + if (Reg) + { + printf ("Program compiled with 'register' attribute\n"); + printf ("\n"); + } + else + { + printf ("Program compiled without 'register' attribute\n"); + printf ("\n"); + } + printf ("Please give the number of runs through the benchmark: "); + { + int n; + scanf ("%d", &n); + Number_Of_Runs = n; + } + printf ("\n"); + + printf ("Execution starts, %d runs through Dhrystone\n", Number_Of_Runs); +#endif /* PRATTLE */ + + if (argc != 2) { + printf("Usage: %s duration\n", argv[0]); + exit(1); + } + + duration = atoi(argv[1]); + Run_Index = 0; + wake_me(duration, report); + + /***************/ + /* Start timer */ + /***************/ + +#ifdef SELF_TIMED +#ifdef TIMES + times (&time_info); + Begin_Time = (long) time_info.tms_utime; +#endif +#ifdef TIME + Begin_Time = time ( (long *) 0); +#endif +#endif /* SELF_TIMED */ + + for (Run_Index = 1; ; ++Run_Index) + { + + Proc_5(); + Proc_4(); + /* Ch_1_Glob == 'A', Ch_2_Glob == 'B', Bool_Glob == true */ + Int_1_Loc = 2; + Int_2_Loc = 3; + strcpy (Str_2_Loc, "DHRYSTONE PROGRAM, 2'ND STRING"); + Enum_Loc = Ident_2; + Bool_Glob = ! Func_2 (Str_1_Loc, Str_2_Loc); + /* Bool_Glob == 1 */ + while (Int_1_Loc < Int_2_Loc) /* loop body executed once */ + { + Int_3_Loc = 5 * Int_1_Loc - Int_2_Loc; + /* Int_3_Loc == 7 */ + Proc_7 (Int_1_Loc, Int_2_Loc, &Int_3_Loc); + /* Int_3_Loc == 7 */ + Int_1_Loc += 1; + } /* while */ + /* Int_1_Loc == 3, Int_2_Loc == 3, Int_3_Loc == 7 */ + Proc_8 (Arr_1_Glob, Arr_2_Glob, Int_1_Loc, Int_3_Loc); + /* Int_Glob == 5 */ + Proc_1 (Ptr_Glob); + for (Ch_Index = 'A'; Ch_Index <= Ch_2_Glob; ++Ch_Index) + /* loop body executed twice */ + { + if (Enum_Loc == Func_1 (Ch_Index, 'C')) + /* then, not executed */ + { + Proc_6 (Ident_1, &Enum_Loc); + strcpy (Str_2_Loc, "DHRYSTONE PROGRAM, 3'RD STRING"); + Int_2_Loc = Run_Index; + Int_Glob = Run_Index; + } + } + /* Int_1_Loc == 3, Int_2_Loc == 3, Int_3_Loc == 7 */ + Int_2_Loc = Int_2_Loc * Int_1_Loc; + Int_1_Loc = Int_2_Loc / Int_3_Loc; + Int_2_Loc = 7 * (Int_2_Loc - Int_3_Loc) - Int_1_Loc; + /* Int_1_Loc == 1, Int_2_Loc == 13, Int_3_Loc == 7 */ + Proc_2 (&Int_1_Loc); + /* Int_1_Loc == 5 */ + + } /* loop "for Run_Index" */ + + /**************/ + /* Stop timer */ + /**************/ +#ifdef SELF_TIMED +#ifdef TIMES + times (&time_info); + End_Time = (long) time_info.tms_utime; +#endif +#ifdef TIME + End_Time = time ( (long *) 0); +#endif +#endif /* SELF_TIMED */ + + /* BYTE version never executes this stuff */ +#ifdef SELF_TIMED + printf ("Execution ends\n"); + printf ("\n"); + printf ("Final values of the variables used in the benchmark:\n"); + printf ("\n"); + printf ("Int_Glob: %d\n", Int_Glob); + printf (" should be: %d\n", 5); + printf ("Bool_Glob: %d\n", Bool_Glob); + printf (" should be: %d\n", 1); + printf ("Ch_1_Glob: %c\n", Ch_1_Glob); + printf (" should be: %c\n", 'A'); + printf ("Ch_2_Glob: %c\n", Ch_2_Glob); + printf (" should be: %c\n", 'B'); + printf ("Arr_1_Glob[8]: %d\n", Arr_1_Glob[8]); + printf (" should be: %d\n", 7); + printf ("Arr_2_Glob[8][7]: %d\n", Arr_2_Glob[8][7]); + printf (" should be: Number_Of_Runs + 10\n"); + printf ("Ptr_Glob->\n"); + printf (" Ptr_Comp: %d\n", (int) Ptr_Glob->Ptr_Comp); + printf (" should be: (implementation-dependent)\n"); + printf (" Discr: %d\n", Ptr_Glob->Discr); + printf (" should be: %d\n", 0); + printf (" Enum_Comp: %d\n", Ptr_Glob->variant.var_1.Enum_Comp); + printf (" should be: %d\n", 2); + printf (" Int_Comp: %d\n", Ptr_Glob->variant.var_1.Int_Comp); + printf (" should be: %d\n", 17); + printf (" Str_Comp: %s\n", Ptr_Glob->variant.var_1.Str_Comp); + printf (" should be: DHRYSTONE PROGRAM, SOME STRING\n"); + printf ("Next_Ptr_Glob->\n"); + printf (" Ptr_Comp: %d\n", (int) Next_Ptr_Glob->Ptr_Comp); + printf (" should be: (implementation-dependent), same as above\n"); + printf (" Discr: %d\n", Next_Ptr_Glob->Discr); + printf (" should be: %d\n", 0); + printf (" Enum_Comp: %d\n", Next_Ptr_Glob->variant.var_1.Enum_Comp); + printf (" should be: %d\n", 1); + printf (" Int_Comp: %d\n", Next_Ptr_Glob->variant.var_1.Int_Comp); + printf (" should be: %d\n", 18); + printf (" Str_Comp: %s\n", + Next_Ptr_Glob->variant.var_1.Str_Comp); + printf (" should be: DHRYSTONE PROGRAM, SOME STRING\n"); + printf ("Int_1_Loc: %d\n", Int_1_Loc); + printf (" should be: %d\n", 5); + printf ("Int_2_Loc: %d\n", Int_2_Loc); + printf (" should be: %d\n", 13); + printf ("Int_3_Loc: %d\n", Int_3_Loc); + printf (" should be: %d\n", 7); + printf ("Enum_Loc: %d\n", Enum_Loc); + printf (" should be: %d\n", 1); + printf ("Str_1_Loc: %s\n", Str_1_Loc); + printf (" should be: DHRYSTONE PROGRAM, 1'ST STRING\n"); + printf ("Str_2_Loc: %s\n", Str_2_Loc); + printf (" should be: DHRYSTONE PROGRAM, 2'ND STRING\n"); + printf ("\n"); + + User_Time = End_Time - Begin_Time; + + if (User_Time < Too_Small_Time) + { + printf ("Measured time too small to obtain meaningful results\n"); + printf ("Please increase number of runs\n"); + printf ("\n"); + } + else + { +#ifdef TIME + Microseconds = (float) User_Time * Mic_secs_Per_Second + / (float) Number_Of_Runs; + Dhrystones_Per_Second = (float) Number_Of_Runs / (float) User_Time; +#else + Microseconds = (float) User_Time * Mic_secs_Per_Second + / ((float) HZ * ((float) Number_Of_Runs)); + Dhrystones_Per_Second = ((float) HZ * (float) Number_Of_Runs) + / (float) User_Time; +#endif + printf ("Microseconds for one run through Dhrystone: "); + printf ("%6.1f \n", Microseconds); + printf ("Dhrystones per Second: "); + printf ("%6.1f \n", Dhrystones_Per_Second); + printf ("\n"); + } +#endif /* SELF_TIMED */ +} + + +void Proc_1 (REG Rec_Pointer Ptr_Val_Par) + /* executed once */ +{ + REG Rec_Pointer Next_Record = Ptr_Val_Par->Ptr_Comp; + /* == Ptr_Glob_Next */ + /* Local variable, initialized with Ptr_Val_Par->Ptr_Comp, */ + /* corresponds to "rename" in Ada, "with" in Pascal */ + + structassign (*Ptr_Val_Par->Ptr_Comp, *Ptr_Glob); + Ptr_Val_Par->variant.var_1.Int_Comp = 5; + Next_Record->variant.var_1.Int_Comp + = Ptr_Val_Par->variant.var_1.Int_Comp; + Next_Record->Ptr_Comp = Ptr_Val_Par->Ptr_Comp; + Proc_3 (&Next_Record->Ptr_Comp); + /* Ptr_Val_Par->Ptr_Comp->Ptr_Comp + == Ptr_Glob->Ptr_Comp */ + if (Next_Record->Discr == Ident_1) + /* then, executed */ + { + Next_Record->variant.var_1.Int_Comp = 6; + Proc_6 (Ptr_Val_Par->variant.var_1.Enum_Comp, + &Next_Record->variant.var_1.Enum_Comp); + Next_Record->Ptr_Comp = Ptr_Glob->Ptr_Comp; + Proc_7 (Next_Record->variant.var_1.Int_Comp, 10, + &Next_Record->variant.var_1.Int_Comp); + } + else /* not executed */ + structassign (*Ptr_Val_Par, *Ptr_Val_Par->Ptr_Comp); +} /* Proc_1 */ + + +void Proc_2 (One_Fifty *Int_Par_Ref) + /* executed once */ + /* *Int_Par_Ref == 1, becomes 4 */ +{ + One_Fifty Int_Loc; + Enumeration Enum_Loc; + + Enum_Loc = 0; + + Int_Loc = *Int_Par_Ref + 10; + do /* executed once */ + if (Ch_1_Glob == 'A') + /* then, executed */ + { + Int_Loc -= 1; + *Int_Par_Ref = Int_Loc - Int_Glob; + Enum_Loc = Ident_1; + } /* if */ + while (Enum_Loc != Ident_1); /* true */ +} /* Proc_2 */ + + +void Proc_3 (Rec_Pointer *Ptr_Ref_Par) + /* executed once */ + /* Ptr_Ref_Par becomes Ptr_Glob */ +{ + if (Ptr_Glob != Null) + /* then, executed */ + *Ptr_Ref_Par = Ptr_Glob->Ptr_Comp; + Proc_7 (10, Int_Glob, &Ptr_Glob->variant.var_1.Int_Comp); +} /* Proc_3 */ + + +void Proc_4 (void) /* without parameters */ + /* executed once */ +{ + Boolean Bool_Loc; + + Bool_Loc = Ch_1_Glob == 'A'; + Bool_Glob = Bool_Loc | Bool_Glob; + Ch_2_Glob = 'B'; +} /* Proc_4 */ + +void Proc_5 (void) /* without parameters */ +/*******/ + /* executed once */ +{ + Ch_1_Glob = 'A'; + Bool_Glob = false; +} /* Proc_5 */ + + + /* Procedure for the assignment of structures, */ + /* if the C compiler doesn't support this feature */ +#ifdef NOSTRUCTASSIGN +memcpy (d, s, l) +register char *d; +register char *s; +register int l; +{ + while (l--) *d++ = *s++; +} +#endif + + diff --git a/src/cmd/unixbench/src/dhry_2.c b/src/cmd/unixbench/src/dhry_2.c new file mode 100644 index 0000000..140161f --- /dev/null +++ b/src/cmd/unixbench/src/dhry_2.c @@ -0,0 +1,209 @@ +/***************************************************************************** + * The BYTE UNIX Benchmarks - Release 3 + * Module: dhry_2.c SID: 3.4 5/15/91 19:30:22 + * + ***************************************************************************** + * Bug reports, patches, comments, suggestions should be sent to: + * + * Ben Smith, Rick Grehan or Tom Yager + * ben@bytepb.byte.com rick_g@bytepb.byte.com tyager@bytepb.byte.com + * + ***************************************************************************** + * Modification Log: + * 10/22/97 - code cleanup to remove ANSI C compiler warnings + * Andy Kahn + * + * Adapted from: + * + * "DHRYSTONE" Benchmark Program + * ----------------------------- + * + * **** WARNING **** See warning in n.dhry_1.c + * + * Version: C, Version 2.1 + * + * File: dhry_2.c (part 3 of 3) + * + * Date: May 25, 1988 + * + * Author: Reinhold P. Weicker + * + ****************************************************************************/ +/* SCCSid is defined in dhry_1.c */ + +#include +#include "dhry.h" + +#ifndef REG +#define REG + /* REG becomes defined as empty */ + /* i.e. no register variables */ +#endif + +extern int Int_Glob; +extern char Ch_1_Glob; + +void Proc_6(Enumeration, Enumeration *); +void Proc_7(One_Fifty, One_Fifty, One_Fifty *); +void Proc_8(Arr_1_Dim, Arr_2_Dim, int, int); +Enumeration Func_1(Capital_Letter, Capital_Letter); +Boolean Func_2(Str_30, Str_30); +Boolean Func_3(Enumeration); + +void Proc_6 (Enumeration Enum_Val_Par, Enumeration *Enum_Ref_Par) + /* executed once */ + /* Enum_Val_Par == Ident_3, Enum_Ref_Par becomes Ident_2 */ +{ + *Enum_Ref_Par = Enum_Val_Par; + if (! Func_3 (Enum_Val_Par)) + /* then, not executed */ + *Enum_Ref_Par = Ident_4; + switch (Enum_Val_Par) + { + case Ident_1: + *Enum_Ref_Par = Ident_1; + break; + case Ident_2: + if (Int_Glob > 100) + /* then */ + *Enum_Ref_Par = Ident_1; + else *Enum_Ref_Par = Ident_4; + break; + case Ident_3: /* executed */ + *Enum_Ref_Par = Ident_2; + break; + case Ident_4: break; + case Ident_5: + *Enum_Ref_Par = Ident_3; + break; + } /* switch */ +} /* Proc_6 */ + +void Proc_7 (Int_1_Par_Val, Int_2_Par_Val, Int_Par_Ref) +One_Fifty Int_1_Par_Val; +One_Fifty Int_2_Par_Val; +One_Fifty *Int_Par_Ref; +/**********************************************/ + /* executed three times */ + /* first call: Int_1_Par_Val == 2, Int_2_Par_Val == 3, */ + /* Int_Par_Ref becomes 7 */ + /* second call: Int_1_Par_Val == 10, Int_2_Par_Val == 5, */ + /* Int_Par_Ref becomes 17 */ + /* third call: Int_1_Par_Val == 6, Int_2_Par_Val == 10, */ + /* Int_Par_Ref becomes 18 */ +{ + One_Fifty Int_Loc; + + Int_Loc = Int_1_Par_Val + 2; + *Int_Par_Ref = Int_2_Par_Val + Int_Loc; +} /* Proc_7 */ + + +void Proc_8 (Arr_1_Par_Ref, Arr_2_Par_Ref, Int_1_Par_Val, Int_2_Par_Val) +/*********************************************************************/ + /* executed once */ + /* Int_Par_Val_1 == 3 */ + /* Int_Par_Val_2 == 7 */ +Arr_1_Dim Arr_1_Par_Ref; +Arr_2_Dim Arr_2_Par_Ref; +int Int_1_Par_Val; +int Int_2_Par_Val; +{ + REG One_Fifty Int_Index; + REG One_Fifty Int_Loc; + + Int_Loc = Int_1_Par_Val + 5; + Arr_1_Par_Ref [Int_Loc] = Int_2_Par_Val; + Arr_1_Par_Ref [Int_Loc+1] = Arr_1_Par_Ref [Int_Loc]; + Arr_1_Par_Ref [Int_Loc+30] = Int_Loc; + for (Int_Index = Int_Loc; Int_Index <= Int_Loc+1; ++Int_Index) + Arr_2_Par_Ref [Int_Loc] [Int_Index] = Int_Loc; + Arr_2_Par_Ref [Int_Loc] [Int_Loc-1] += 1; + Arr_2_Par_Ref [Int_Loc+20] [Int_Loc] = Arr_1_Par_Ref [Int_Loc]; + Int_Glob = 5; +} /* Proc_8 */ + + +Enumeration Func_1 (Capital_Letter Ch_1_Par_Val, Capital_Letter Ch_2_Par_Val) +/*************************************************/ + /* executed three times */ + /* first call: Ch_1_Par_Val == 'H', Ch_2_Par_Val == 'R' */ + /* second call: Ch_1_Par_Val == 'A', Ch_2_Par_Val == 'C' */ + /* third call: Ch_1_Par_Val == 'B', Ch_2_Par_Val == 'C' */ +{ + Capital_Letter Ch_1_Loc; + Capital_Letter Ch_2_Loc; + + Ch_1_Loc = Ch_1_Par_Val; + Ch_2_Loc = Ch_1_Loc; + if (Ch_2_Loc != Ch_2_Par_Val) + /* then, executed */ + return (Ident_1); + else /* not executed */ + { + Ch_1_Glob = Ch_1_Loc; + return (Ident_2); + } +} /* Func_1 */ + + + +Boolean Func_2 (Str_1_Par_Ref, Str_2_Par_Ref) +/*************************************************/ + /* executed once */ + /* Str_1_Par_Ref == "DHRYSTONE PROGRAM, 1'ST STRING" */ + /* Str_2_Par_Ref == "DHRYSTONE PROGRAM, 2'ND STRING" */ + +Str_30 Str_1_Par_Ref; +Str_30 Str_2_Par_Ref; +{ + REG One_Thirty Int_Loc; + Capital_Letter Ch_Loc; + + Ch_Loc = 'A'; + Int_Loc = 2; + while (Int_Loc <= 2) /* loop body executed once */ + if (Func_1 (Str_1_Par_Ref[Int_Loc], + Str_2_Par_Ref[Int_Loc+1]) == Ident_1) + /* then, executed */ + { + Ch_Loc = 'A'; + Int_Loc += 1; + } /* if, while */ + if (Ch_Loc >= 'W' && Ch_Loc < 'Z') + /* then, not executed */ + Int_Loc = 7; + if (Ch_Loc == 'R') + /* then, not executed */ + return (true); + else /* executed */ + { + if (strcmp (Str_1_Par_Ref, Str_2_Par_Ref) > 0) + /* then, not executed */ + { + Int_Loc += 7; + Int_Glob = Int_Loc; + return (true); + } + else /* executed */ + return (false); + } /* if Ch_Loc */ +} /* Func_2 */ + + +Boolean Func_3 (Enum_Par_Val) +/***************************/ + /* executed once */ + /* Enum_Par_Val == Ident_3 */ +Enumeration Enum_Par_Val; +{ + Enumeration Enum_Loc; + + Enum_Loc = Enum_Par_Val; + if (Enum_Loc == Ident_3) + /* then, executed */ + return (true); + else /* not executed */ + return (false); +} /* Func_3 */ + diff --git a/src/cmd/unixbench/src/dummy.c b/src/cmd/unixbench/src/dummy.c new file mode 100644 index 0000000..1fbc936 --- /dev/null +++ b/src/cmd/unixbench/src/dummy.c @@ -0,0 +1,319 @@ +/******************************************************************************* + * The BYTE UNIX Benchmarks - Release 3 + * Module: dummy.c SID: 3.3 5/15/91 19:30:19 + * + ******************************************************************************* + * Bug reports, patches, comments, suggestions should be sent to: + * + * Ben Smith, Rick Grehan or Tom Yager + * ben@bytepb.byte.com rick_g@bytepb.byte.com tyager@bytepb.byte.com + * + ******************************************************************************* + * Modification Log: + * 10/22/97 - code cleanup to remove ANSI C compiler warnings + * Andy Kahn + * + ******************************************************************************/ +/* + * Hacked up C program for use in the standard shell.? scripts of + * the multiuser test. This is based upon makework.c, and is typically + * edited using edscript.2 before compilation. + * + * $Header: dummy.c,v 3.4 87/06/23 15:54:53 kjmcdonell Beta $ + */ +char SCCSid[] = "@(#) @(#)dummy.c:3.3 -- 5/15/91 19:30:19"; + +#include +#include + +#define DEF_RATE 5.0 +#define GRANULE 5 +#define CHUNK 60 +#define MAXCHILD 12 +#define MAXWORK 10 + +float thres; +float est_rate = DEF_RATE; +int nusers; /* number of concurrent users to be simulated by + * this process */ +int firstuser; /* ordinal identification of first user for this + * process */ +int nwork = 0; /* number of job streams */ +int exit_status = 0; /* returned to parent */ +int sigpipe; /* pipe write error flag */ + +struct st_work { + char *cmd; /* name of command to run */ + char **av; /* arguments to command */ + char *input; /* standard input buffer */ + int inpsize; /* size of standard input buffer */ +} work[MAXWORK]; + +struct { + int xmit; /* # characters sent */ + char *bp; /* std input buffer pointer */ + int blen; /* std input buffer length */ + int fd; /* stdin to command */ + int pid; /* child PID */ + char *line; /* start of input line */ + int firstjob; /* inital piece of work */ + int thisjob; /* current piece of work */ +} child[MAXCHILD], *cp; + +main(argc, argv) +int argc; +char *argv[]; +{ + int i; + int l; + int fcopy = 0; /* fd for copy output */ + int master = 1; /* the REAL master, == 0 for clones */ + int nchild; /* no. of children for a clone to run */ + int done; /* count of children finished */ + int output; /* aggregate output char count for all + children */ + int c; + int thiswork = 0; /* next job stream to allocate */ + int nch; /* # characters to write */ + int written; /* # characters actully written */ + char logname[15]; /* name of the log file(s) */ + void onalarm(void); + void pipeerr(void); + void wrapup(void); + void grunt(void); + char *malloc(); + int pvec[2]; /* for pipes */ + char *p; + char *prog; /* my name */ + +#if ! debug + freopen("masterlog.00", "a", stderr); +#endif + fprintf(stderr, "*** New Run *** "); + prog = argv[0]; + while (argc > 1 && argv[1][0] == '-') { + p = &argv[1][1]; + argc--; + argv++; + while (*p) { + switch (*p) { + case 'r': + /* code DELETED here */ + argc--; + argv++; + break; + + case 'c': + /* code DELETED here */ + lseek(fcopy, 0L, 2); /* append at end of file */ + break; + + default: + fprintf(stderr, "%s: bad flag '%c'\n", prog, *p); + exit(4); + } + p++; + } + } + + if (argc < 2) { + fprintf(stderr, "%s: missing nusers\n", prog); + exit(4); + } + + nusers = atoi(argv[1]); + if (nusers < 1) { + fprintf(stderr, "%s: impossible nusers (%d<-%s)\n", prog, nusers, argv[1]); + exit(4); + } + fprintf(stderr, "%d Users\n", nusers); + argc--; + argv++; + + /* build job streams */ + getwork(); +#if debug + dumpwork(); +#endif + + /* clone copies of myself to run up to MAXCHILD jobs each */ + firstuser = MAXCHILD; + fprintf(stderr, "master pid %d\n", getpid()); + fflush(stderr); + while (nusers > MAXCHILD) { + fflush(stderr); + if (nusers >= 2*MAXCHILD) + /* the next clone must run MAXCHILD jobs */ + nchild = MAXCHILD; + else + /* the next clone must run the leftover jobs */ + nchild = nusers - MAXCHILD; + if ((l = fork()) == -1) { + /* fork failed */ + fatal("** clone fork failed **\n"); + goto bepatient; + } else if (l > 0) { + fprintf(stderr, "master clone pid %d\n", l); + /* I am the master with nchild fewer jobs to run */ + nusers -= nchild; + firstuser += MAXCHILD; + continue; + } else { + /* I am a clone, run MAXCHILD jobs */ +#if ! debug + sprintf(logname, "masterlog.%02d", firstuser/MAXCHILD); + freopen(logname, "w", stderr); +#endif + master = 0; + nusers = nchild; + break; + } + } + if (master) + firstuser = 0; + + close(0); + + /* code DELETED here */ + + fflush(stderr); + + srand(time(0)); + thres = 0; + done = output = 0; + for (i = 0; i < nusers; i++) { + if (child[i].blen == 0) + done++; + else + thres += est_rate * GRANULE; + } + est_rate = thres; + + signal(SIGALRM, onalarm); + signal(SIGPIPE, pipeerr); + alarm(GRANULE); + while (done < nusers) { + for (i = 0; i < nusers; i++) { + cp = &child[i]; + if (cp->xmit >= cp->blen) continue; + l = rand() % CHUNK + 1; /* 1-CHUNK chars */ + if (l == 0) continue; + if (cp->xmit + l > cp->blen) + l = cp->blen - cp->xmit; + p = cp->bp; + cp->bp += l; + cp->xmit += l; +#if debug + fprintf(stderr, "child %d, %d processed, %d to go\n", i, cp->xmit, cp->blen - cp->xmit); +#endif + while (p < cp->bp) { + if (*p == '\n' || (p == &cp->bp[-1] && cp->xmit >= cp->blen)) { + /* write it out */ + nch = p - cp->line + 1; + if ((written = write(cp->fd, cp->line, nch)) != nch) { + + /* code DELETED here */ + + } + if (fcopy) + write(fcopy, cp->line, p - cp->line + 1); +#if debug + fprintf(stderr, "child %d gets \"", i); + { + char *q = cp->line; + while (q <= p) { + if (*q >= ' ' && *q <= '~') + fputc(*q, stderr); + else + fprintf(stderr, "\\%03o", *q); + q++; + } + } + fputc('"', stderr); +#endif + cp->line = &p[1]; + } + p++; + } + if (cp->xmit >= cp->blen) { + done++; + close(cp->fd); +#if debug + fprintf(stderr, "child %d, close std input\n", i); +#endif + } + output += l; + } + while (output > thres) { + pause(); +#if debug + fprintf(stderr, "after pause: output, thres, done %d %.2f %d\n", output, thres, done); +#endif + } + } + +bepatient: + alarm(0); +/**** + * If everything is going OK, we should simply be able to keep + * looping unitil 'wait' fails, however some descendent process may + * be in a state from which it can never exit, and so a timeout + * is used. + * 5 minutes should be ample, since the time to run all jobs is of + * the order of 5-10 minutes, however some machines are painfully slow, + * so the timeout has been set at 20 minutes (1200 seconds). + ****/ + + /* code DELETED here */ + +} + +onalarm() +{ + thres += est_rate; + signal(SIGALRM, onalarm); + alarm(GRANULE); +} + +grunt() +{ + /* timeout after label "bepatient" in main */ + exit_status = 4; + wrapup(); +} + +pipeerr() +{ + sigpipe++; +} + +wrapup() +{ + /* DUMMY, real code dropped */ +} + +getwork() +{ + + /* DUMMY, real code dropped */ + gets(); + strncpy(); + malloc(); realloc(); + open(); close(); +} + +fatal(s) +char *s; +{ + int i; + fprintf(stderr, s); + fflush(stderr); + perror("Reason?"); + for (i = 0; i < nusers; i++) { + if (child[i].pid > 0 && kill(child[i].pid, SIGKILL) != -1) + fprintf(stderr, "pid %d killed off\n", child[i].pid); + } + fflush(stderr); + exit_status = 4; + return; +} diff --git a/src/cmd/unixbench/src/execl.c b/src/cmd/unixbench/src/execl.c new file mode 100644 index 0000000..ca7bd95 --- /dev/null +++ b/src/cmd/unixbench/src/execl.c @@ -0,0 +1,95 @@ +/******************************************************************************* + * The BYTE UNIX Benchmarks - Release 3 + * Module: execl.c SID: 3.3 5/15/91 19:30:19 + * + ******************************************************************************* + * Bug reports, patches, comments, suggestions should be sent to: + * + * Ben Smith, Rick Grehan or Tom Yager + * ben@bytepb.byte.com rick_g@bytepb.byte.com tyager@bytepb.byte.com + * + ******************************************************************************* + * Modification Log: + * $Header: execl.c,v 3.5 87/06/22 15:37:08 kjmcdonell Beta $ + * August 28, 1990 - Modified timing routines + * October 22, 1997 - code cleanup to remove ANSI C compiler warnings + * Andy Kahn + * + ******************************************************************************/ +/* + * Execing + * + */ +char SCCSid[] = "@(#) @(#)execl.c:3.3 -- 5/15/91 19:30:19"; + +#include +#include + +char bss[8*1024]; /* something worthwhile */ + +#define main dummy + +#include "big.c" /* some real code */ + +#undef main + +/* added by BYTE */ +char *getenv(); + + +int main(argc, argv) /* the real program */ +int argc; +char *argv[]; +{ + unsigned long iter = 0; + char *ptr; + char *fullpath; + int duration; + char count_str[6], start_str[12], path_str[81], *dur_str; + time_t start_time, this_time; + +#ifdef DEBUG + int count; + for(count = 0; count < argc; ++ count) + printf("%s ",argv[count]); + printf("\n"); +#endif + if (argc < 2) + { + printf("Usage: %s duration\n", argv[0]); + exit(1); + } + + + duration = atoi(argv[1]); + if (duration > 0) + /* the first invocation */ + { + dur_str = argv[1]; + if((ptr = getenv("BINDIR")) != NULL) + sprintf(path_str,"%s/execl",ptr); + fullpath=path_str; + time(&start_time); + } + else /* one of those execl'd invocations */ + { + /* real duration follow the phoney null duration */ + duration = atoi(argv[2]); + dur_str = argv[2]; + iter = (unsigned long)atoi(argv[3]); /* where are we now ? */ + sscanf(argv[4], "%lu", &start_time); + fullpath = argv[0]; + } + + sprintf(count_str, "%lu", ++iter); /* increment the execl counter */ + sprintf(start_str, "%lu", start_time); + time(&this_time); + if (this_time - start_time >= duration) { /* time has run out */ + fprintf(stderr, "%lu loops\n", iter); + exit(0); + } + execl(fullpath, fullpath, "0", dur_str, count_str, start_str, (char*)0); + printf("Exec failed at iteration %lu\n", iter); + perror("Reason"); + exit(1); +} diff --git a/src/cmd/unixbench/src/fstime.c b/src/cmd/unixbench/src/fstime.c new file mode 100644 index 0000000..e9d458a --- /dev/null +++ b/src/cmd/unixbench/src/fstime.c @@ -0,0 +1,320 @@ +/******************************************************************************* + * The BYTE UNIX Benchmarks - Release 3 + * Module: fstime.c SID: 3.5 5/15/91 19:30:19 + * + ******************************************************************************* + * Bug reports, patches, comments, suggestions should be sent to: + * + * Ben Smith, Rick Grehan or Tom Yager + * ben@bytepb.byte.com rick_g@bytepb.byte.com tyager@bytepb.byte.com + * + ******************************************************************************* + * Modification Log: + * $Header: fstime.c,v 3.4 87/06/22 14:23:05 kjmcdonell Beta $ + * 10/19/89 - rewrote timing calcs and added clock check (Ben Smith) + * 10/26/90 - simplify timing, change defaults (Tom Yager) + * 11/16/90 - added better error handling and changed output format (Ben Smith) + * 11/17/90 - changed the whole thing around (Ben Smith) + * 2/22/91 - change a few style elements and improved error handling (Ben Smith) + * 4/17/91 - incorporated suggestions from Seckin Unlu (seckin@sumac.intel.com) + * 4/17/91 - limited size of file, will rewind when reaches end of file + * 7/95 - fixed mishandling of read() and write() return codes + * Carl Emilio Prelz + * 12/95 - Massive changes. Made sleep time proportional increase with run + * time; added fsbuffer and fsdisk variants; added partial counting + * of partial reads/writes (was *full* credit); added dual syncs. + * David C Niemi + * 10/22/97 - code cleanup to remove ANSI C compiler warnings + * Andy Kahn + ******************************************************************************/ +char SCCSid[] = "@(#) @(#)fstime.c:3.5 -- 5/15/91 19:30:19"; + +#include +#include +#include +#include +#include +#include + +#ifndef SECONDS +#define SECONDS 10 +#endif + +#ifdef FSDISK +#define BUFSIZE 4096 +#define MAX_BLOCKS 8000 +#endif + +#ifdef FSBUFFER +#define BUFSIZE 256 +#define MAX_BLOCKS 500 +#endif + +#ifndef BUFSIZE +#define BUFSIZE 1024 +#endif + +/* This must be set to the smallest BUFSIZE or 1024, whichever is smaller */ +#define COUNTSIZE 256 +#define HALFCOUNT (COUNTSIZE/2) /* Half of COUNTSIZE */ +#define COUNTPERK (1024/COUNTSIZE) /* Countable units per 1024 bytes */ + +#define COUNTPERBUF (BUFSIZE/COUNTSIZE) /* Countable units per BUFSIZE */ + + +#ifndef MAX_BLOCKS +#define MAX_BLOCKS 2000 +#endif + /* max number of BUFSIZE blocks in file */ + /* Don't limit it much, so that memory buffering + * can be overcome + */ +#define _MAXBLOCKS MAX_BLOCKS*1024/BUFSIZE + +#define FNAME0 "dummy0" +#define FNAME1 "dummy1" + +int w_test(void); +int r_test(void); +int c_test(void); + +long read_score = 1, write_score = 1; + +/****************** GLOBALS ***************************/ +char buf[BUFSIZE]; +int seconds = SECONDS; +int f; +int g; +int i; +void stop_count(); +void clean_up(); +int sigalarm = 0; + +/******************** MAIN ****************************/ + +int main(argc, argv) +int argc; +char *argv[]; +{ + + /**** initialize ****/ + if (argc > 1) + seconds = atoi(argv[1]); + if (argc == 3 && chdir(argv[2]) == -1) { + perror("fstime: chdir"); + exit(1); + } + + + if((f = creat(FNAME0, 0600)) == -1) { + perror("fstime: creat"); + exit(1); + } + close(f); + + if((g = creat(FNAME1, 0600)) == -1) { + perror("fstime: creat"); + exit(1); + } + close(g); + + if( (f = open(FNAME0, 2)) == -1) { + perror("fstime: open"); + exit(1); + } + if( ( g = open(FNAME1, 2)) == -1 ) { + perror("fstime: open"); + exit(1); + } + + /* fill buffer */ + for (i=0; i < BUFSIZE; ++i) + buf[i] = i & 0xff; + + /*** run the tests ****/ + signal(SIGKILL,clean_up); + if (w_test() || r_test() || c_test()) { + clean_up(); + exit(1); + } + + /* else */ + clean_up(); + exit(0); +} + +/* write test */ +int w_test(void) +{ + unsigned long counted = 0L; + unsigned long tmp; + long f_blocks; + extern int sigalarm; + + /* Sync and let it settle */ + sync(); + sleep(2); + sync(); + sleep(1); + + signal(SIGALRM,stop_count); + sigalarm = 0; /* reset alarm flag */ + alarm(seconds); + + while(!sigalarm) { + for(f_blocks=0; f_blocks < _MAXBLOCKS; ++f_blocks) { + if ((tmp=write(f, buf, BUFSIZE)) != BUFSIZE) { + if (errno != EINTR) { + perror("fstime: write"); + return(-1); + } + stop_count(); + counted += ((tmp+HALFCOUNT)/COUNTSIZE); + } else + counted += COUNTPERBUF; + } + lseek(f, 0L, 0); /* rewind */ + } + + /* stop clock */ + fprintf(stderr, "%d second sample\n", seconds); + write_score = counted/((long)seconds * COUNTPERK); + fprintf(stderr, + "%ld Kbytes/sec write %d bufsize %d max blocks\n", + write_score, BUFSIZE, _MAXBLOCKS); + + return(0); +} + +/* read test */ +int r_test(void) +{ + unsigned long counted = 0L; + unsigned long tmp; + extern int sigalarm; + extern int errno; + + /* Sync and let it settle */ + sync(); + sleep(2 + seconds/4); + sync(); + sleep(1 + seconds/4); + + /* rewind */ + errno = 0; + lseek(f, 0L, 0); + + signal(SIGALRM,stop_count); + sigalarm = 0; /* reset alarm flag */ + alarm(seconds); + while(!sigalarm) { + /* read while checking for an error */ + if ((tmp=read(f, buf, BUFSIZE)) != BUFSIZE) { + switch(errno) { + case 0: + case EINVAL: + lseek(f, 0L, 0); /* rewind at end of file */ + counted += (tmp+HALFCOUNT)/COUNTSIZE; + continue; + case EINTR: + stop_count(); + counted += (tmp+HALFCOUNT)/COUNTSIZE; + break; + default: + perror("fstime: read"); + return(-1); + break; + } + } else + counted += COUNTPERBUF; + } + + /* stop clock */ + fprintf(stderr, "%d second sample\n", seconds); + read_score = counted / ((long)seconds * COUNTPERK); + fprintf(stderr, + "%ld Kbytes/sec read %d bufsize %d max blocks \n", + read_score, BUFSIZE, _MAXBLOCKS); + return(0); +} + + +/* copy test */ +int c_test(void) +{ + unsigned long counted = 0L; + unsigned long tmp; + extern int sigalarm; + + sync(); + sleep(2 + seconds/4); + sync(); + sleep(1 + seconds/8); + + /* rewind */ + errno = 0; + lseek(f, 0L, 0); + + signal(SIGALRM,stop_count); + sigalarm = 0; /* reset alarm flag */ + alarm(seconds); + + while (! sigalarm) { + if ((tmp=read(f, buf, BUFSIZE)) != BUFSIZE) { + switch(errno) { + case 0: + case EINVAL: + lseek(f, 0L, 0); /* rewind at end of file */ + lseek(g, 0L, 0); /* rewind the output too */ + continue; + case EINTR: + /* part credit for leftover bytes read */ + counted += ( (tmp * write_score) / + (read_score + write_score) + + HALFCOUNT) / COUNTSIZE; + stop_count(); + break; + default: + perror("fstime: copy read"); + return(-1); + break; + } + } else { + if ((tmp=write(g, buf, BUFSIZE)) != BUFSIZE) { + if (errno != EINTR) { + perror("fstime: copy write"); + return(-1); + } + counted += ( + /* Full credit for part of buffer written */ + tmp + + + /* Plus part credit having read full buffer */ + ( ((BUFSIZE - tmp) * write_score) / + (read_score + write_score) ) + + HALFCOUNT) / COUNTSIZE; + stop_count(); + } else + counted += COUNTPERBUF; + } + } + /* stop clock */ + + fprintf(stderr, "%d second sample\n", seconds); + fprintf(stderr, + "%ld Kbytes/sec copy %d bufsize %d max blocks \n", + counted / ((long)seconds * COUNTPERK), BUFSIZE, _MAXBLOCKS); + return(0); +} + +void stop_count(void) +{ + extern int sigalarm; + sigalarm = 1; +} + +void clean_up(void) +{ + unlink(FNAME0); + unlink(FNAME1); +} diff --git a/src/cmd/unixbench/src/getopt.c b/src/cmd/unixbench/src/getopt.c new file mode 100644 index 0000000..8a3b5b3 --- /dev/null +++ b/src/cmd/unixbench/src/getopt.c @@ -0,0 +1,99 @@ +/******************************************************************************* + * The BYTE UNIX Benchmarks - Release 3 + * Module: getopt.c SID: 3.3 5/15/91 19:30:18 + * + ******************************************************************************* + * Bug reports, patches, comments, suggestions should be sent to: + * + * Ben Smith, Rick Grehan or Tom Yager + * ben@bytepb.byte.com rick_g@bytepb.byte.com tyager@bytepb.byte.com + * + ******************************************************************************* + * Modification Log: + * @(#)getopt.c 2.5 (smail) 9/15/87 + * Here's something you've all been waiting for: the AT&T public domain + * source for getopt(3). It is the code which was given out at the 1985 + * UNIFORUM conference in Dallas. I obtained it by electronic mail + * directly from AT&T. The people there assure me that it is indeed + * in the public domain. + * + * There is no manual page. That is because the one they gave out at + * UNIFORUM was slightly different from the current System V Release 2 + * manual page. The difference apparently involved a note about the + * famous rules 5 and 6, recommending using white space between an option + * and its first argument, and not grouping options that have arguments. + * Getopt itself is currently lenient about both of these things White + * space is allowed, but not mandatory, and the last option in a group can + * have an argument. That particular version of the man page evidently + * has no official existence, and my source at AT&T did not send a copy. + * The current SVR2 man page reflects the actual behavor of this getopt. + * However, I am not about to post a copy of anything licensed by AT&T. + *********************************************************************/ +char SCCSid[] = "@(#) @(#)getopt.c:3.3 -- 5/15/91 19:30:18"; + +/* This include is needed only to get "index" defined as "strchr" on Sys V. */ +#include "defs.h" + +/*LINTLIBRARY*/ +#define NULL 0 +#define EOF (-1) +#define ERR(s, c) if(opterr){\ + extern int write();\ + char errbuf[2];\ + errbuf[0] = c; errbuf[1] = '\n';\ + (void) write(2, argv[0], (unsigned)strlen(argv[0]));\ + (void) write(2, s, (unsigned)strlen(s));\ + (void) write(2, errbuf, 2);} + +extern char *index(); + +int opterr = 1; +int optind = 1; +int optopt; +char *optarg; + +int +getopt(argc, argv, opts) +int argc; +char **argv, *opts; +{ + static int sp = 1; + register int c; + register char *cp; + + if(sp == 1) + if(optind >= argc || + argv[optind][0] != '-' || argv[optind][1] == '\0') + return(EOF); + else if(strcmp(argv[optind], "--") == NULL) { + optind++; + return(EOF); + } + optopt = c = argv[optind][sp]; + if(c == ':' || (cp=index(opts, c)) == NULL) { + ERR(": illegal option -- ", c); + if(argv[optind][++sp] == '\0') { + optind++; + sp = 1; + } + return('?'); + } + if(*++cp == ':') { + if(argv[optind][sp+1] != '\0') + optarg = &argv[optind++][sp+1]; + else if(++optind >= argc) { + ERR(": option requires an argument -- ", c); + sp = 1; + return('?'); + } else + optarg = argv[optind++]; + sp = 1; + } else { + if(argv[optind][++sp] == '\0') { + sp = 1; + optind++; + } + optarg = NULL; + } + return(c); +} diff --git a/src/cmd/unixbench/src/hanoi.c b/src/cmd/unixbench/src/hanoi.c new file mode 100644 index 0000000..f59148d --- /dev/null +++ b/src/cmd/unixbench/src/hanoi.c @@ -0,0 +1,77 @@ +/******************************************************************************* + * The BYTE UNIX Benchmarks - Release 3 + * Module: hanoi.c SID: 3.3 5/15/91 19:30:20 + * + ******************************************************************************* + * Bug reports, patches, comments, suggestions should be sent to: + * + * Ben Smith, Rick Grehan or Tom Yager + * ben@bytepb.byte.com rick_g@bytepb.byte.com tyager@bytepb.byte.com + * + ******************************************************************************* + * Modification Log: + * $Header: hanoi.c,v 3.5 87/08/06 08:11:14 kenj Exp $ + * August 28, 1990 - Modified timing routines (ty) + * October 22, 1997 - code cleanup to remove ANSI C compiler warnings + * Andy Kahn + * + ******************************************************************************/ +char SCCSid[] = "@(#) @(#)hanoi.c:3.3 -- 5/15/91 19:30:20"; + +#define other(i,j) (6-(i+j)) + +#include +#include +#include "timeit.c" + +void mov(int n, int f, int t); + +unsigned long iter = 0; +int num[4]; +long cnt; + +void report() +{ + fprintf(stderr,"%ld loops\n", iter); + exit(0); +} + + +int main(argc, argv) +int argc; +char *argv[]; +{ + int disk=10, /* default number of disks */ + duration; + + if (argc < 2) { + printf("Usage: %s duration [disks]\n", argv[0]); + exit(1); + } + duration = atoi(argv[1]); + if(argc > 2) disk = atoi(argv[2]); + num[1] = disk; + + wake_me(duration, report); + + while(1) { + mov(disk,1,3); + iter++; + } + + exit(0); +} + +void mov(int n, int f, int t) +{ + int o; + if(n == 1) { + num[f]--; + num[t]++; + return; + } + o = other(f,t); + mov(n-1,f,o); + mov(1,f,t); + mov(n-1,o,t); +} diff --git a/src/cmd/unixbench/src/limit.c b/src/cmd/unixbench/src/limit.c new file mode 100644 index 0000000..f39c246 --- /dev/null +++ b/src/cmd/unixbench/src/limit.c @@ -0,0 +1,164 @@ +/******************************************************************************* + * The BYTE UNIX Benchmarks - Release 3 + * Module: limit.c SID: 3.3 5/15/91 19:30:20 + * + ******************************************************************************* + * Bug reports, patches, comments, suggestions should be sent to: + * + * Ben Smith, Rick Grehan or Tom Yager + * ben@bytepb.byte.com rick_g@bytepb.byte.com tyager@bytepb.byte.com + * + ******************************************************************************* + * Modification Log: + * $Header: limit.c,v 3.4 87/06/22 14:25:11 kjmcdonell Beta $ + * + ******************************************************************************/ +/* + * Force a UNIX system to the per process and per user limits + * + */ +char SCCSid[] = "@(#) @(#)limit.c:3.3 -- 5/15/91 19:30:20"; + +#define CLICK 1024 +#define MAXCHN 100 + +#include +#include + +int parent; /* parent's pid */ +int child; /* child's pid */ +int pid[MAXCHN]; +int ncall; +int level; +jmp_buf env; + +int main(argc, argv) +int argc; +char *argv[]; +{ + char *top; + int pad; + int end; + int i; + int status; + float f; + int flag(); + int wakeup(); + long last; + + /* open files (file descriptors) */ + for (i = 3; open(".", 0) > 0; i++) ; + printf("Maximum open files per process: %d\n", i); + while (--i > 2) + close(i); + + /* process address space */ + top = (char *)sbrk(0); +#if debug + printf("inital top of program: 0x%x\n", top); +#endif + pad = (((int)top+CLICK-1)/CLICK)*CLICK - (int)top; + sbrk(pad); + for (i = 0; (char *)sbrk(CLICK) != (char *)-1; i++) ; +#if debug + printf("final top of program: 0x%x\n", sbrk(0)); +#endif + brk(top); +#if debug + printf("top of program restored to: 0x%x\n", sbrk(0)); +#endif + end = (((int)top+pad)/CLICK) + i; + f = ((float)end * CLICK) / 1024; + printf("Process address space limit: "); + if (f < 1024) + printf("%.2f Kbytes\n", f); + else { + f /= 1024; + printf("%.2f Mbytes\n", f); + } + + /* process creations */ + printf("Maximum number of child processes:"); + i = 0; + while (1) { +#if debug + printf("about to fork\n"); +#endif + if ((pid[i] = fork()) == -1) { +#if debug + perror("fork failed"); +#endif + break; + } else if (pid[i] != 0) { +#if debug + printf("child %d: pid=%d\n", i+1, pid[i]); +#endif + i++; + if (i >= MAXCHN) { + printf(" more than"); + break; + } + } else { +#if debug + printf("child %d pausing\n", getpid()); +#endif + pause(); +#if debug + printf("child %d exiting\n", getpid()); +#endif + exit(1); + } + } + printf(" %d\n", i); + while (--i >= 0) { + kill(pid[i], SIGKILL); + wait(0); + } + + ncall = level = 0; + parent = getpid(); + signal(SIGTERM, flag); + if ((child = fork()) == 0) { + signal(SIGALRM, wakeup); + recurse(); + exit(4); + } + while ((i = wait(&status)) == -1) { + } + printf("Estimated maximum stack size: %d Kbytes\n", level); + exit(0); +} + +recurse() +{ + int temp[1024 / sizeof(int)]; +#if debug + printf("recursion @ level %d\n", ncall); +#endif + temp[1024 / sizeof(int) - 1] = 1; + ncall++; + kill(parent, SIGTERM); + while (ncall > level) { + alarm(2); + pause(); + } + if (ncall < 8000) + /* less than 8M bytes of temp storage! */ + recurse(); + else + /* give up! */ + exit(0); +} + +flag() +{ + signal(SIGTERM, flag); + level++; + if (child != 0) + kill(child, SIGTERM); +} + +wakeup() +{ + signal(SIGALRM, wakeup); +} diff --git a/src/cmd/unixbench/src/looper.c b/src/cmd/unixbench/src/looper.c new file mode 100644 index 0000000..92d126f --- /dev/null +++ b/src/cmd/unixbench/src/looper.c @@ -0,0 +1,100 @@ +/******************************************************************************* + * The BYTE UNIX Benchmarks - Release 1 + * Module: looper.c SID: 1.4 5/15/91 19:30:22 + * + ******************************************************************************* + * Bug reports, patches, comments, suggestions should be sent to: + * + * Ben Smith or Tom Yager at BYTE Magazine + * ben@bytepb.byte.com tyager@bytepb.byte.com + * + ******************************************************************************* + * Modification Log: + * + * February 25, 1991 -- created (Ben S.) + * October 22, 1997 - code cleanup to remove ANSI C compiler warnings + * Andy Kahn + * + ******************************************************************************/ +char SCCSid[] = "@(#) @(#)looper.c:1.4 -- 5/15/91 19:30:22"; +/* + * Shell Process creation + * + */ + +#include +#include +#include +#include "timeit.c" + +unsigned long iter; +char *cmd_argv[28]; +int cmd_argc; + +void report(void) +{ + fprintf(stderr,"%lu loops\n", iter); + exit(0); +} + +int main(argc, argv) +int argc; +char *argv[]; +{ +int slave, count, duration; +int status; + +if (argc < 2) + { + printf("Usage: %s duration command [args..]\n", argv[0]); + printf(" duration in seconds\n"); + exit(1); + } + +if((duration = atoi(argv[1])) < 1) + { + printf("Usage: %s duration command [arg..]\n", argv[0]); + printf(" duration in seconds\n"); + exit(1); + } + +/* get command */ +cmd_argc=argc-2; +for( count=2;count < argc; ++count) + cmd_argv[count-2]=argv[count]; +#ifdef DEBUG +printf("<<%s>>",cmd_argv[0]); +for(count=1;count < cmd_argc; ++count) + printf(" <%s>", cmd_argv[count]); +putchar('\n'); +exit(0); +#endif + +iter = 0; +wake_me(duration, report); + +while (1) + { + if ((slave = fork()) == 0) + { /* execute command */ + execvp(cmd_argv[0],cmd_argv); + exit(0); + } + else if (slave < 0) + { + /* woops ... */ + printf("Fork failed at iteration %lu\n", iter); + perror("Reason"); + exit(2); + } + else + /* master */ + wait(&status); + if (status != 0) + { + printf("Bad wait status: 0x%x\n", status); + exit(2); + } + iter++; + } +} diff --git a/src/cmd/unixbench/src/pipe.c b/src/cmd/unixbench/src/pipe.c new file mode 100644 index 0000000..c7bf6ad --- /dev/null +++ b/src/cmd/unixbench/src/pipe.c @@ -0,0 +1,68 @@ +/******************************************************************************* + * The BYTE UNIX Benchmarks - Release 3 + * Module: pipe.c SID: 3.3 5/15/91 19:30:20 + * + ******************************************************************************* + * Bug reports, patches, comments, suggestions should be sent to: + * + * Ben Smith, Rick Grehan or Tom Yager + * ben@bytepb.byte.com rick_g@bytepb.byte.com tyager@bytepb.byte.com + * + ******************************************************************************* + * Modification Log: + * $Header: pipe.c,v 3.5 87/06/22 14:32:36 kjmcdonell Beta $ + * August 29, 1990 - modified timing routines (ty) + * October 22, 1997 - code cleanup to remove ANSI C compiler warnings + * Andy Kahn + * + ******************************************************************************/ +char SCCSid[] = "@(#) @(#)pipe.c:3.3 -- 5/15/91 19:30:20"; +/* + * pipe -- test single process pipe throughput (no context switching) + * + */ + +#include +#include +#include +#include "timeit.c" + +unsigned long iter; + +void report() +{ + fprintf(stderr,"%ld loops\n", iter); + exit(0); +} + +int main(argc, argv) +int argc; +char *argv[]; +{ + char buf[512]; + int pvec[2], duration; + + if (argc != 2) { + printf("Usage: %s duration\n", argv[0]); + exit(1); + } + + duration = atoi(argv[1]); + + pipe(pvec); + + wake_me(duration, report); + iter = 0; + + while (1) { + if (write(pvec[1], buf, sizeof(buf)) != sizeof(buf)) { + if ((errno != EINTR) && (errno != 0)) + printf("write failed, error %d\n", errno); + } + if (read(pvec[0], buf, sizeof(buf)) != sizeof(buf)) { + if ((errno != EINTR) && (errno != 0)) + printf("read failed, error %d\n", errno); + } + iter++; + } +} diff --git a/src/cmd/unixbench/src/spawn.c b/src/cmd/unixbench/src/spawn.c new file mode 100644 index 0000000..44b74a8 --- /dev/null +++ b/src/cmd/unixbench/src/spawn.c @@ -0,0 +1,80 @@ +/******************************************************************************* + * The BYTE UNIX Benchmarks - Release 3 + * Module: spawn.c SID: 3.3 5/15/91 19:30:20 + * + ******************************************************************************* + * Bug reports, patches, comments, suggestions should be sent to: + * + * Ben Smith, Rick Grehan or Tom Yagerat BYTE Magazine + * ben@bytepb.byte.com rick_g@bytepb.byte.com tyager@bytepb.byte.com + * + ******************************************************************************* + * Modification Log: + * $Header: spawn.c,v 3.4 87/06/22 14:32:48 kjmcdonell Beta $ + * August 29, 1990 - Modified timing routines (ty) + * October 22, 1997 - code cleanup to remove ANSI C compiler warnings + * Andy Kahn + * + ******************************************************************************/ +char SCCSid[] = "@(#) @(#)spawn.c:3.3 -- 5/15/91 19:30:20"; +/* + * Process creation + * + */ + +#include +#include +#include +#include "timeit.c" + +unsigned long iter; + +void report() +{ + fprintf(stderr,"%lu loops\n", iter); + exit(0); +} + +int main(argc, argv) +int argc; +char *argv[]; +{ + int slave, duration; + int status; + + if (argc != 2) { + printf("Usage: %s duration \n", argv[0]); + exit(1); + } + + duration = atoi(argv[1]); + + iter = 0; + wake_me(duration, report); + + while (1) { + if ((slave = fork()) == 0) { + /* slave .. boring */ +#if debug + printf("fork OK\n"); +#endif + /* kill it right away */ + exit(0); + } else if (slave < 0) { + /* woops ... */ + printf("Fork failed at iteration %lu\n", iter); + perror("Reason"); + exit(2); + } else + /* master */ + wait(&status); + if (status != 0) { + printf("Bad wait status: 0x%x\n", status); + exit(2); + } + iter++; +#if debug + printf("Child %d done.\n", slave); +#endif + } +} diff --git a/src/cmd/unixbench/src/syscall.c b/src/cmd/unixbench/src/syscall.c new file mode 100644 index 0000000..9a1c8f9 --- /dev/null +++ b/src/cmd/unixbench/src/syscall.c @@ -0,0 +1,62 @@ +/******************************************************************************* + * The BYTE UNIX Benchmarks - Release 3 + * Module: syscall.c SID: 3.3 5/15/91 19:30:21 + * + ******************************************************************************* + * Bug reports, patches, comments, suggestions should be sent to: + * + * Ben Smith, Rick Grehan or Tom Yager at BYTE Magazine + * ben@bytepb.byte.com rick_g@bytepb.byte.com tyager@bytepb.byte.com + * + ******************************************************************************* + * Modification Log: + * $Header: syscall.c,v 3.4 87/06/22 14:32:54 kjmcdonell Beta $ + * August 29, 1990 - Modified timing routines + * October 22, 1997 - code cleanup to remove ANSI C compiler warnings + * Andy Kahn + * + ******************************************************************************/ +/* + * syscall -- sit in a loop calling the system + * + */ +char SCCSid[] = "@(#) @(#)syscall.c:3.3 -- 5/15/91 19:30:21"; + +#include +#include +#include +#include "timeit.c" + +unsigned long iter; + +void report() +{ + fprintf(stderr,"%ld loops\n", iter); + exit(0); +} + +int main(argc, argv) +int argc; +char *argv[]; +{ + int duration; + + if (argc != 2) { + printf("Usage: %s duration\n", argv[0]); + exit(1); + } + + duration = atoi(argv[1]); + + iter = 0; + wake_me(duration, report); + + while (1) { + close(dup(0)); + getpid(); + getuid(); + umask(022); + iter++; + } + /* NOTREACHED */ +} diff --git a/src/cmd/unixbench/src/time-polling.c b/src/cmd/unixbench/src/time-polling.c new file mode 100644 index 0000000..21fa8b2 --- /dev/null +++ b/src/cmd/unixbench/src/time-polling.c @@ -0,0 +1,573 @@ +/* Programme to test how long it takes to select(2), poll(2) and poll2(2) a + large number of file descriptors. + + Copyright 1997 Richard Gooch rgooch@atnf.csiro.au + Distributed under the GNU General Public License. + + To compile this programme, use gcc -O2 -o time-polling time-polling.c + + Extra compile flags: + + Add -DHAS_SELECT if your operating system has the select(2) system call + Add -DHAS_POLL if your operating system has the poll(2) system call + Add -DHAS_POLL2 if your operating system has the poll2(2) system call + + Usage: time-polling [num_iter] [num_to_test] [num_active] [-v] + + NOTE: on many systems the default limit on file descriptors is less than + 1024. You should try to increase this limit to 1024 before doing the test. + Something like "limit descriptors 1024" or "limit openfiles 1024" should do + the trick. On some systems (like IRIX), doing the test on a smaller number + gives a *much* smaller time per descriptor, which shows that time taken + does not scale linearly with number of descriptors, which is non-optimal. + In the tests I've done, I try to use 1024 descriptors. + The benchmark results are available at: + http://www.atnf.csiro.au/~rgooch/benchmarks.html + If you want to contribute results, please email them to me. Please specify + if you want to be acknowledged. + + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + Richard Gooch may be reached by email at rgooch@atnf.csiro.au + The postal address is: + Richard Gooch, c/o ATNF, P. O. Box 76, Epping, N.S.W., 2121, Australia. + +*/ + +#ifdef UNIXBENCH + #define OUT stdout +#else + #define OUT stderr +#endif +#include +#include +#include +#include +#ifdef HAS_POLL +# include +#endif +#ifdef HAS_POLL2 +# include +#endif +#include +#include +#include + +#define TRUE 1 +#define FALSE 0 +#ifdef UNIXBENCH + #define MAX_ITERATIONS 1000 +#else + #define MAX_ITERATIONS 30 +#endif +#define MAX_FDS 40960 +#define CONST const +#define ERRSTRING strerror (errno) + +typedef int flag; + + +/* +static inline int find_first_set_bit (CONST void *array, int size) +*/ +static int find_first_set_bit (CONST void *array, int size) +/* [SUMMARY] Find the first bit set in a bitfield. + A pointer to the bitfield. This must be aligned on a long boundary. + The number of bits in the bitfield. + [RETURNS] The index of the first set bit. If no bits are set, <> + 1 + is returned. +*/ +{ + int index; + unsigned long word; + unsigned int ul_size = 8 * sizeof (unsigned long); + CONST unsigned long *ul_array = array; + + /* Find first word with any bit set */ + for (index = 0; (*ul_array == 0) && (index < size); + index += ul_size, ++ul_array); + /* Find first bit set in word */ + for (word = *ul_array; !(word & 1) && (index < size); + ++index, word = word >> 1); + return (index); +} /* End Function find_first_set_bit */ + +/* +static inline int find_next_set_bit (CONST void *array, int size, int offset) +*/ +static int find_next_set_bit (CONST void *array, int size, int offset) +/* [SUMMARY] Find the next bit set in a bitfield. + A pointer to the bitfield. This must be aligned on a long boundary. + The number of bits in the bitfield. + The offset of the current bit in the bitfield. The current bit is + ignored. + [RETURNS] The index of the next set bit. If no more bits are set, + <> + 1 is returned. +*/ +{ + int index, tmp; + unsigned long word; + unsigned int ul_size = 8 * sizeof (unsigned long); + CONST unsigned long *ul_array = array; + + if (++offset >= size) return (offset); + index = offset; + /* Jump to the long word containing the next bit */ + tmp = offset / ul_size; + ul_array += tmp; + offset -= tmp * ul_size; + if ( (offset == 0) || (*ul_array == 0) ) + return (find_first_set_bit (ul_array, size - index) + index); + /* There is a bit set somewhere in this word */ + if ( ( (word = *ul_array) != 0 ) && ( (word = word >> offset) != 0 ) ) + { + /* There is a bit set somewhere in this word at or after the offset + position */ + for (; (word & 1) == 0; word = word >> 1, ++index); + return (index); + } + /* Have to go to subsequent word(s) */ + index += ul_size - offset; + return (find_first_set_bit (++ul_array, size - index) + index); +} /* End Function find_next_set_bit */ + + +struct callback_struct +{ + void (*input_func) (void *info); + void (*output_func) (void *info); + void (*exception_func) (void *info); + void *info; +}; + +static int total_bits = 0; +struct callback_struct callbacks[MAX_FDS]; + + +static void test_func (void *info) +{ + ++total_bits; +} + +#ifdef HAS_SELECT +static void time_select (fd_set *input_fds, fd_set *output_fds, + fd_set *exception_fds, int max_fd, int num_iter, + long *times) +/* [SUMMARY] Time how long it takes to select(2) file descriptors. + The input masks. + The output masks. + The exception masks. + The highest file descriptor in the fd_sets. + The number of iterations. + The time taken (in microseconds) for each iteration. + [RETURNS] Nothing. +*/ +{ + int fd, count, nready; + fd_set i_fds, o_fds, e_fds; + struct timeval time1, time2, tv; + + /* Warm the cache a bit */ + memcpy (&i_fds, input_fds, sizeof i_fds); + memcpy (&o_fds, output_fds, sizeof i_fds); + memcpy (&e_fds, exception_fds, sizeof i_fds); + tv.tv_sec = 0; + tv.tv_usec = 0; + select (max_fd + 1, &i_fds, &o_fds, &e_fds, &tv); + for (count = 0; count < num_iter; ++count) + { + total_bits = 0; + gettimeofday (&time1, NULL); + memcpy (&i_fds, input_fds, sizeof i_fds); + memcpy (&o_fds, output_fds, sizeof i_fds); + memcpy (&e_fds, exception_fds, sizeof i_fds); + tv.tv_sec = 0; + tv.tv_usec = 0; + nready = select (max_fd + 1, &i_fds, &o_fds, &e_fds, &tv); + if (nready == -1) + { + fprintf (stderr, "Error selecting\t%s\n", ERRSTRING); + exit (2); + } + if (nready < 1) + { + fprintf (stderr, "Error: nready: %d\n", nready); + exit (1); + } + /* Scan the output */ + for (fd = find_first_set_bit (&e_fds, sizeof e_fds * 8); fd <= max_fd; + fd = find_next_set_bit (&e_fds, sizeof e_fds * 8, fd) ) + { + (*callbacks[fd].exception_func) (callbacks[fd].info); + } + for (fd = find_first_set_bit (&i_fds, sizeof i_fds * 8); fd <= max_fd; + fd = find_next_set_bit (&i_fds, sizeof i_fds * 8, fd) ) + { + (*callbacks[fd].input_func) (callbacks[fd].info); + } + for (fd = find_first_set_bit (&o_fds, sizeof o_fds * 8); fd <= max_fd; + fd = find_next_set_bit (&o_fds, sizeof o_fds * 8, fd) ) + { + (*callbacks[fd].output_func) (callbacks[fd].info); + } + gettimeofday (&time2, NULL); + times[count] = (time2.tv_sec - time1.tv_sec) * 1000000; + times[count] += time2.tv_usec - time1.tv_usec; + } +} /* End Function time_select */ +#endif /* HAS_SELECT */ + +#ifdef HAS_POLL +static void time_poll (struct pollfd *pollfd_array, int start_index, + int num_to_test, int num_iter, long *times) +/* [SUMMARY] Time how long it takes to poll(2) file descriptors. + The array of pollfd structures. + The start index in the array of pollfd structures. + The number of file descriptors to test. + The number of iterations. + The time taken (in microseconds) for each iteration. + [RETURNS] Nothing. +*/ +{ + short revents; + int fd, count, nready; + struct timeval time1, time2; + struct pollfd *pollfd_ptr, *stop_pollfd; + + /* Warm the cache a bit */ + poll (pollfd_array + start_index, num_to_test, 0); + for (count = 0; count < num_iter; ++count) + { + total_bits = 0; + gettimeofday (&time1, NULL); + nready = poll (pollfd_array + start_index, num_to_test, 0); + if (nready == -1) + { + fprintf (stderr, "Error polling\t%s\n", ERRSTRING); + exit (2); + } + if (nready < 1) + { + fprintf (stderr, "Error: nready: %d\n", nready); + exit (1); + } + stop_pollfd = pollfd_array + start_index + num_to_test; + for (pollfd_ptr = pollfd_array + start_index; TRUE; ++pollfd_ptr) + { + if (pollfd_ptr->revents == 0) continue; + /* Have an active descriptor */ + revents = pollfd_ptr->revents; + fd = pollfd_ptr->fd; + if (revents & POLLPRI) + (*callbacks[fd].exception_func) (callbacks[fd].info); + if (revents & POLLIN) + (*callbacks[fd].input_func) (callbacks[fd].info); + if (revents & POLLOUT) + (*callbacks[fd].output_func) (callbacks[fd].info); + if (--nready == 0) break; + } + gettimeofday (&time2, NULL); + times[count] = (time2.tv_sec - time1.tv_sec) * 1000000; + times[count] += time2.tv_usec - time1.tv_usec; + } +} /* End Function time_poll */ +#endif /* HAS_POLL */ + +#ifdef HAS_POLL2 +static void time_poll2 (struct poll2ifd *poll2ifd_array, int start_index, + int num_to_test, int num_iter, long *times) +/* [SUMMARY] Time how long it takes to poll2(2) file descriptors. + The array of poll2ifd structures. + The start index in the array of pollfd structures. + The number of file descriptors to test. + The number of iterations. + The time taken (in microseconds) for each iteration. + [RETURNS] Nothing. +*/ +{ + short revents; + int fd, count, nready, i; + struct timeval time1, time2; + struct poll2ofd poll2ofd_array[MAX_FDS]; + + /* Warm the cache a bit */ + poll2 (poll2ifd_array + start_index, poll2ofd_array, num_to_test, 0); + for (count = 0; count < num_iter; ++count) + { + total_bits = 0; + gettimeofday (&time1, NULL); + nready = poll2 (poll2ifd_array + start_index, poll2ofd_array, + num_to_test, 0); + if (nready == -1) + { + times[count] = -1; + if (errno == ENOSYS) return; /* Must do this first */ + fprintf (stderr, "Error calling poll2(2)\t%s\n", ERRSTRING); + exit (2); + } + if (nready < 1) + { + fprintf (stderr, "Error: nready: %d\n", nready); + exit (1); + } + for (i = 0; i < nready; ++i) + { + revents = poll2ofd_array[i].revents; + fd = poll2ofd_array[i].fd; + if (revents & POLLPRI) + (*callbacks[fd].exception_func) (callbacks[fd].info); + if (revents & POLLIN) + (*callbacks[fd].input_func) (callbacks[fd].info); + if (revents & POLLOUT) + (*callbacks[fd].output_func) (callbacks[fd].info); + } + gettimeofday (&time2, NULL); + times[count] = (time2.tv_sec - time1.tv_sec) * 1000000; + times[count] += time2.tv_usec - time1.tv_usec; + } +} /* End Function time_poll2 */ +#endif /* HAS_POLL2 */ + + +int main (argc, argv) +int argc; +char *argv[]; +{ + flag failed = FALSE; + flag verbose = FALSE; + int first_fd = -1; + int fd, max_fd, count, total_fds; + int num_to_test, num_active; +#ifdef UNIXBENCH + int max_iter = 1000; +#else + int max_iter = 10; +#endif +#ifdef HAS_SELECT + long select_total = 0; + fd_set input_fds, output_fds, exception_fds; + long select_times[MAX_ITERATIONS]; +#endif +#ifdef HAS_POLL + int start_index; + long poll_total = 0; + struct pollfd pollfd_array[MAX_FDS]; + long poll_times[MAX_ITERATIONS]; +#endif +#ifdef HAS_POLL2 + long poll2_total = 0; + struct poll2ifd poll2ifd_array[MAX_FDS]; + struct poll2ofd poll2ofd_array[MAX_FDS]; + long poll2_times[MAX_ITERATIONS]; +#endif +#if 0 + extern char *sys_errlist[]; +#endif + +#ifdef HAS_SELECT + FD_ZERO (&input_fds); + FD_ZERO (&output_fds); + FD_ZERO (&exception_fds); +#endif +#ifdef HAS_POLL + memset (pollfd_array, 0, sizeof pollfd_array); +#endif + /* Allocate file descriptors */ + total_fds = 0; + max_fd = 0; + while (!failed) + { + if ( ( fd = dup (1) ) == -1 ) + { + if (errno != EMFILE) + { + fprintf (stderr, "Error dup()ing\t%s\n", ERRSTRING); + exit (1); + } + failed = TRUE; + continue; + } + if (fd >= MAX_FDS) + { + fprintf (stderr, "File descriptor: %d larger than max: %d\n", + fd, MAX_FDS - 1); + exit (1); + } + callbacks[fd].input_func = test_func; + callbacks[fd].output_func = test_func; + callbacks[fd].exception_func = test_func; + callbacks[fd].info = NULL; + if (fd > max_fd) max_fd = fd; + if (first_fd < 0) first_fd = fd; +#ifdef HAS_POLL + pollfd_array[fd].fd = fd; + pollfd_array[fd].events = 0; +#endif +#ifdef HAS_POLL2 + poll2ifd_array[fd].fd = fd; + poll2ifd_array[fd].events = 0; +#endif + } + total_fds = max_fd + 1; + /* Process the command-line arguments */ + if (argc > 5) + { + fputs ("Usage:\ttime-polling [num_iter] [num_to_test] [num_active] [-v]\n", + stderr); + exit (1); + } + if (argc > 1) max_iter = atoi (argv[1]); + if (max_iter > MAX_ITERATIONS) + { + fprintf (stderr, "num_iter too large\n"); + exit (1); + } + if (argc > 2) num_to_test = atoi (argv[2]); + else num_to_test = total_fds - first_fd; + if (argc > 3) num_active = atoi (argv[3]); + else num_active = 1; + if (argc > 4) + { + if (strcmp (argv[4], "-v") != 0) + { + fputs ("Usage:\ttime-polling [num_iter] [num_to_test] [num_active] [-v]\n", + stderr); + exit (1); + } + verbose = TRUE; + } + + /* Sanity tests */ + if (num_to_test > total_fds - first_fd) num_to_test = total_fds - first_fd; + if (num_active > total_fds - first_fd) num_active = total_fds - first_fd; + /* Set activity monitoring flags */ + for (fd = total_fds - num_to_test; fd < total_fds; ++fd) + { +#ifdef HAS_SELECT + FD_SET (fd, &exception_fds); + FD_SET (fd, &input_fds); +#endif +#ifdef HAS_POLL + pollfd_array[fd].events = POLLPRI | POLLIN; +#endif +#ifdef HAS_POLL2 + poll2ifd_array[fd].events = POLLPRI | POLLIN; +#endif + } + for (fd = total_fds - num_active; fd < total_fds; ++fd) + { +#ifdef HAS_SELECT + FD_SET (fd, &output_fds); +#endif +#ifdef HAS_POLL + pollfd_array[fd].events |= POLLOUT; +#endif +#ifdef HAS_POLL2 + poll2ifd_array[fd].events |= POLLOUT; +#endif + } + fprintf (OUT, "Num fds: %d, polling descriptors %d-%d\n", + total_fds, total_fds - num_to_test, max_fd); + /* First do all the tests, then print the results */ +#ifdef HAS_SELECT + time_select (&input_fds, &output_fds, &exception_fds, max_fd, max_iter, + select_times); +#endif +#ifdef HAS_POLL + start_index = total_fds - num_to_test; + time_poll (pollfd_array, start_index, num_to_test, max_iter, poll_times); +#endif +#ifdef HAS_POLL2 + start_index = total_fds - num_to_test; + time_poll2 (poll2ifd_array, start_index, num_to_test, max_iter, + poll2_times); +#endif + /* Now print out all the times */ + fputs ("All times in microseconds\n", OUT); + fputs ("ITERATION\t", OUT); +#ifdef HAS_SELECT + fprintf (OUT, "%-12s", "select(2)"); +#endif +#ifdef HAS_POLL + fprintf (OUT, "%-12s", "poll(2)"); +#endif +#ifdef HAS_POLL2 + if (poll2_times[0] >= 0) fprintf (OUT, "%-12s", "poll2(2)"); +#endif + for (count = 0; count < max_iter; ++count) + { + if (verbose) fprintf (OUT, "\n%d\t\t", count); +#ifdef HAS_SELECT + if (verbose) fprintf (OUT, "%-12ld", select_times[count]); + select_total += select_times[count]; +#endif +#ifdef HAS_POLL + if (verbose) fprintf (OUT, "%-12ld", poll_times[count]); + poll_total += poll_times[count]; +#endif +#ifdef HAS_POLL2 + if ( verbose && (poll2_times[0] >= 0) ) + fprintf (OUT, "%-12ld", poll2_times[count]); + poll2_total += poll2_times[count]; +#endif + } + fputs ("\n\naverage\t\t", OUT); +#ifdef HAS_SELECT + fprintf (OUT, "%-12ld", select_total / max_iter); +#endif +#ifdef HAS_POLL + fprintf (OUT, "%-12ld", poll_total / max_iter); +#endif +#ifdef HAS_POLL2 + if (poll2_times[0] >= 0) + fprintf (OUT, "%-12ld", poll2_total / max_iter); +#endif + putc ('\n', OUT); + fputs ("Per fd\t\t", OUT); +#ifdef HAS_SELECT + fprintf (OUT, "%-12.2f", + (float) select_total / (float) max_iter / (float) num_to_test); +#ifdef UNIXBENCH + fprintf (stderr, "lps\t%.2f\t%.1f\n", + 1000000 * (float) max_iter * (float) num_to_test + / (float) select_total, (float)select_total / 1000000); +#endif +#endif +#ifdef HAS_POLL + fprintf (OUT, "%-12.2f", + (float) poll_total / (float) max_iter / (float) num_to_test); +#ifdef UNIXBENCH + fprintf (stderr, "lps\t%.2f\t%.1f\n", + 1000000 * (float) max_iter * (float) num_to_test + / (float) poll_total, (float)poll_total / 1000000); +#endif +#endif +#ifdef HAS_POLL2 + if (poll2_times[0] >= 0) { + fprintf (OUT, "%-12.2f", + (float) poll2_total / (float) max_iter / (float) num_to_test); +#ifdef UNIXBENCH + fprintf (stderr, "lps\t%.2f\t%.1f\n", + 1000000 * (float) max_iter * (float) num_to_test + / (float) poll2_total, (float)poll2_total / 1000000); +#endif + } + +#endif + fputs ("<- the most important value\n", OUT); + + exit(0); +} /* End Function main */ diff --git a/src/cmd/unixbench/src/timeit.c b/src/cmd/unixbench/src/timeit.c new file mode 100644 index 0000000..00d1cfc --- /dev/null +++ b/src/cmd/unixbench/src/timeit.c @@ -0,0 +1,41 @@ +/******************************************************************************* + * + * The BYTE UNIX Benchmarks - Release 3 + * Module: timeit.c SID: 3.3 5/15/91 19:30:21 + ******************************************************************************* + * Bug reports, patches, comments, suggestions should be sent to: + * + * Ben Smith, Rick Grehan or Tom Yager + * ben@bytepb.byte.com rick_g@bytepb.byte.com tyager@bytepb.byte.com + * + ******************************************************************************* + * Modification Log: + * May 12, 1989 - modified empty loops to avoid nullifying by optimizing + * compilers + * August 28, 1990 - changed timing relationship--now returns total number + * of iterations (ty) + * October 22, 1997 - code cleanup to remove ANSI C compiler warnings + * Andy Kahn + * + ******************************************************************************/ + +/* this module is #included in other modules--no separate SCCS ID */ + +/* + * Timing routine + * + */ + +#include +#include + +void wake_me(seconds, func) + int seconds; + void (*func)(); +{ + /* set up the signal handler */ + signal(SIGALRM, func); + /* get the clock running */ + alarm(seconds); +} + diff --git a/src/cmd/unixbench/src/whets.c b/src/cmd/unixbench/src/whets.c new file mode 100644 index 0000000..a797424 --- /dev/null +++ b/src/cmd/unixbench/src/whets.c @@ -0,0 +1,1287 @@ +/**********************************************************/ +/* Date: Mon, 10 Mar 1997 07:38:18 -0500 */ +/* From: Roy Longbottom */ +/* Subject: WHET02.txt */ +/* To: "Alfred A. Aburto Jr." */ +/**********************************************************/ + +/* + * C/C++ Whetstone Benchmark Single or Double Precision + * + * Original concept Brian Wichmann NPL 1960's + * Original author Harold Curnow CCTA 1972 + * Self timing versions Roy Longbottom CCTA 1978/87 + * Optimisation control Bangor University 1987/90 + * C/C++ Version Roy Longbottom 1996 + * Compatibility & timers Al Aburto 1996 + * + ************************************************************ + * + * Official version approved by: + * + * Harold Curnow 100421.1615@compuserve.com + * + * Happy 25th birthday Whetstone, 21 November 1997 + * + ************************************************************ + * + * The program normally runs for about 100 seconds + * (adjustable in main - variable duration). This time + * is necessary because of poor PC clock resolution. + * The original concept included such things as a given + * number of subroutine calls and divides which may be + * changed by optimisation. For comparison purposes the + * compiler and level of optimisation should be identified. + * + ************************************************************ + * + * The original benchmark had a single variable I which + * controlled the running time. Constants with values up + * to 899 were multiplied by I to control the number + * passes for each loop. It was found that large values + * of I could overflow index registers so an extra outer + * loop with a second variable J was added. + * + * Self timing versions were produced during the early + * days. The 1978 changes supplied timings of individual + * loops and these were used later to produce MFLOPS and + * MOPS ratings. + * + * 1987 changes converted the benchmark to Fortran 77 + * standards and removed redundant IF statements and + * loops to leave the 8 active loops N1 to N8. Procedure + * P3 was changed to use global variables to avoid over- + * optimisation with the first two statements changed from + * X1=X and Y1=Y to X=Y and Y=Z. A self time calibrating + * version for PCs was also produced, the facility being + * incorporated in this version. + * + * This version has changes to avoid worse than expected + * speed ratings, due to underflow, and facilities to show + * that consistent numeric output is produced with varying + * optimisation levels or versions in different languages. + * + * Some of the procedures produce ever decreasing numbers. + * To avoid problems, variables T and T1 have been changed + * from 0.499975 and 0.50025 to 0.49999975 and 0.50000025. + * + * Each section now has its own double loop. Inner loops + * are run 100 times the loop constants. Calibration + * determines the number of outer loop passes. The + * numeric results produced in the main output are for + * one pass on the outer loop. As underflow problems were + * still likely on a processor 100 times faster than a 100 + * MHZ Pentium, three sections have T=1.0-T inserted in the + * outer loop to avoid the problem. The two loops avoid + * index register overflows. + * + * The first section is run ten times longer than required + * for accuracy in calculating MFLOPS. This time is divided + * by ten for inclusion in the MWIPS calculations. + * + * This version has facilities for typing in details of the + * particular run. This information is appended to file + * whets.res along with the results. The input section can + * be avoided using a command line parameter N (for example + * Whets.exe N). + * + * Roy Longbottom 101323.2241@compuserve.com + * + ************************************************************ + * + * Whetstone benchmark results are available in whets.tbl + * from ftp.nosc.mil/pub/aburto. The results include + * further details of the benchmarks. + * + ************************************************************ + * + * Source code is available in C/C++, Fortran, Basic and + * Visual Basic in the same format as this version. Pre- + * compiled versions for PCs are also available via C++. + * These comprise optimised and non-optimised versions + * for DOS, Windows and NT. + * + * This version compiles and runs correctly either as a + * C or CPP program with a WATCOM and Borland compiler. + * + ************************************************************ + * + * Example of initial calibration display (Pentium 100 MHz) + * + * Single Precision C/C++ Whetstone Benchmark + * + * Calibrate + * 0.17 Seconds 1 Passes (x 100) + * 0.77 Seconds 5 Passes (x 100) + * 3.70 Seconds 25 Passes (x 100) + * + * Use 676 passes (x 100) + * + * 676 passes are used for an approximate duration of 100 + * seconds, providing an initial estimate of a speed rating + * of 67.6 MWIPS. + * + * This is followed by the table of results as below. Input + * statements are then supplied to type in the run details. + * + ************************************************************ + * + * Examples of results from file whets.res + * + * Whetstone Single Precision Benchmark in C/C++ + * + * Month run 4/1996 + * PC model Escom + * CPU Pentium + * Clock MHz 100 + * Cache 256K + * H/W Options Neptune chipset + * OS/DOS Windows 95 + * Compiler Watcom C/C++ 10.5 Win386 + * Options No optimisation + * Run by Roy Longbottom + * From UK + * Mail 101323.2241@compuserve.com + * + * Loop content Result MFLOPS MOPS Seconds + * + * N1 floating point -1.12475025653839100 19.971 0.274 + * N2 floating point -1.12274754047393800 11.822 3.240 + * N3 if then else 1.00000000000000000 11.659 2.530 + * N4 fixed point 12.00000000000000000 13.962 6.430 + * N5 sin,cos etc. 0.49904659390449520 2.097 11.310 + * N6 floating point 0.99999988079071040 3.360 45.750 + * N7 assignments 3.00000000000000000 2.415 21.810 + * N8 exp,sqrt etc. 0.75110864639282230 1.206 8.790 + * + * MWIPS 28.462 100.134 + * + * Whetstone Single Precision Benchmark in C/C++ + * + * Compiler Watcom C/C++ 10.5 Win386 + * Options -otexan -zp4 -om -fp5 -5r + * + * Loop content Result MFLOPS MOPS Seconds + * + * N1 floating point -1.12475025653839100 26.751 0.478 + * N2 floating point -1.12274754047393800 17.148 5.220 + * N3 if then else 1.00000000000000000 19.922 3.460 + * N4 fixed point 12.00000000000000000 15.978 13.130 + * N5 sin,cos etc. 0.49904659390449520 2.663 20.810 + * N6 floating point 0.99999988079071040 10.077 35.650 + * N7 assignments 3.00000000000000000 22.877 5.380 + * N8 exp,sqrt etc. 0.75110864639282230 1.513 16.370 + * + * MWIPS 66.270 100.498 + * + * + * Whetstone Double Precision Benchmark in C/C++ + * + * Compiler Watcom C/C++ 10.5 Win32NT + * Options -otexan -zp4 -om -fp5 -5r + * + * Loop content Result MFLOPS MOPS Seconds + * + * N1 floating point -1.12398255667391900 26.548 0.486 + * N2 floating point -1.12187079889284400 16.542 5.460 + * N3 if then else 1.00000000000000000 19.647 3.540 + * N4 fixed point 12.00000000000000000 15.680 13.500 + * N5 sin,cos etc. 0.49902937281515140 3.019 18.520 + * N6 floating point 0.99999987890802820 9.977 36.330 + * N7 assignments 3.00000000000000000 22.620 5.490 + * N8 exp,sqrt etc. 0.75100163018457870 1.493 16.740 + * + * MWIPS 67.156 100.066 + * + * Note different numeric results to single precision. Slight variations + * are normal with different compilers and sometimes optimisation levels. + * + * + * Example Single Precision Optimised Results + * + * MWIPS MFLOPS MFLOPS MFLOPS COS EXP FIXPT IF EQUAL + * PC 1 2 3 MOPS MOPS MOPS MOPS MOPS + * + * P3 5.68 0.928 0.884 0.673 0.461 0.275 2.36 2.16 0.638 + * P4 16.4 5.09 4.03 2.66 0.526 0.342 6.36 6.00 5.28 + * P5 66.3 26.8 17.1 10.1 2.66 1.51 16.0 19.9 22.9 + * P6 161 50.3 45.2 31.5 4.46 2.77 102 20.6 119 + * + * Example Single Precision Non-optimised Results + * + * P3 3.07 0.860 0.815 0.328 0.355 0.160 1.70 1.32 0.264 + * P4 10.0 4.68 3.51 1.27 0.482 0.298 5.73 5.20 1.18 + * P5 28.5 20.0 11.8 3.36 2.10 1.21 14.0 11.7 2.42 + * P6 81.7 47.5 37.8 10.9 3.91 2.43 51.2 42.8 7.85 + * + * Summary results as in whets.tbl at ftp.nosc.mil/pub/aburto + * + * MFLOPS = Geometric Mean of three MFLOPS loops + * VAX MIPS = 5 * Geometric Mean of last three items above + * + * VAX + * PC System CPU/Options Cache MHz MWIPS MFLOPS MIPS + * + * P3 Clone AM80386DX with 387 128K 40 5.68 0.820 7.40 + * P4 Escom 80486DX2 CIS chipset 128K 66 16.4 3.79 29.3 + * P5 Escom Pentium Neptune chipset 256K 100 66.3 16.7 96.9 + * P6 Dell PentiumPro 440FX PCIset 256K 200 161 41.5 315 + * + * P3 Clone AM80386DX with 387 128K 40 3.07 0.613 4.20 + * P4 Escom 80486DX2 CIS chipset 128K 66 10.0 2.75 16.4 + * P5 Escom Pentium Neptune chipset 256K 100 28.5 9.26 36.6 + * P6 Dell PentiumPro 440FX PCIset 256K 200 81.7 26.9 129 + * + ************************************************************************** + * + * Running Instructions + * + * 1. In order to compile successfully, include timer option as + * indicated below. + * 2. If pre-compiled codes are to be distributed, compile with the + * -DPRECOMP option or uncomment #define PRECOMP at PRECOMPILE + * below. Also insert compiler name and optimisation details + * at #define precompiler and #define preoptions. + * 3. Compile and run for single precision results. Include run + * time parameter N to bipass typing in hardware details etc. + * 4. Compile with -DDP option or uncomment #define DP at PRECISION + * below and run for double precision results. + * 5. Run with maximum and no optimisation (minimum debug) + * 6. Notify Roy Longbottom of other necessary changes + * 7. Send results file whets.res to Roy Longbottom - with one + * sample of each run and system details fully completed + * + * Roy Longbottom 101323.2241@compuserve.com 6 November 1996 + * + ************************************************************************** + */ + + #include /* for sin, exp etc. */ + #include /* standard I/O */ + #include /* for strcpy - 3 occurrences */ + #include /* for exit - 1 occurrence */ + +/***************************************************************/ +/* Timer options. You MUST uncomment one of the options below */ +/* or compile, for example, with the '-DUNIX' option. */ +/***************************************************************/ +/* #define Amiga */ +/* #define UNIX */ +/* #define UNIX_Old */ +/* #define VMS */ +/* #define BORLAND_C */ +/* #define MSC */ +/* #define MAC */ +/* #define IPSC */ +/* #define FORTRAN_SEC */ +/* #define GTODay */ +/* #define CTimer */ +/* #define UXPM */ +/* #define MAC_TMgr */ +/* #define PARIX */ +/* #define POSIX */ +/* #define WIN32 */ +/* #define POSIX1 */ +/***********************/ + +/*PRECISION PRECISION PRECISION PRECISION PRECISION PRECISION PRECISION*/ + + /* #define DP */ + + #ifdef DP + #define SPDP double + #define Precision "Double" + #else + #define SPDP float + #define Precision "Single" + #endif + + +/*PRECOMPILE PRECOMPILE PRECOMPILE PRECOMPILE PRECOMPILE PRECOMPILE*/ + + /* #define PRECOMP */ + + #ifdef PRECOMP + #define precompiler "INSERT COMPILER NAME HERE" + #define preoptions "INSERT OPTIMISATION OPTIONS HERE" + #endif + + + void whetstones(long xtra, long x100, int calibrate); + void pa(SPDP e[4], SPDP t, SPDP t2); + void po(SPDP e1[4], long j, long k, long l); + void p3(SPDP *x, SPDP *y, SPDP *z, SPDP t, SPDP t1, SPDP t2); + void pout(char title[22], float ops, int type, SPDP checknum, + SPDP time, int calibrate, int section); + + + static SPDP loop_time[9]; + static SPDP loop_mops[9]; + static SPDP loop_mflops[9]; + static SPDP TimeUsed; + static SPDP mwips; + static char headings[9][18]; + static SPDP Check; + static SPDP results[9]; + +int main(argc, argv) +int argc; +char *argv[]; +{ + int count = 10, calibrate = 1; + long xtra = 1; + long x100 = 100; +#ifdef UNIXBENCH + int duration = 10; +#else + int section; + int duration = 100; + FILE *outfile; + int getinput = 1; + char compiler[80] = " ", options[256] = " ", general[10][80] = {" "}; + char *endit = " "; +#endif + + printf("##########################################\n"); + printf("%s Precision C/C++ Whetstone Benchmark\n\n", Precision); + + +#ifndef UNIXBENCH + if (argc > 1) + { + switch (argv[1][0]) + { + case 'N': + case 'n': + getinput = 0; + break; + } + } + if (! getinput) + { + printf ("No run time input data\n\n"); + } + + outfile = fopen("whets.res","a+"); + if (outfile == NULL) + { + printf ("Cannot open results file \n\n"); + printf("Press RETURN to exit\n"); + gets(endit); + exit (0); + } +#endif + + printf("Calibrate\n"); + do + { + TimeUsed=0; + + whetstones(xtra,x100,calibrate); + + printf("%11.2f Seconds %10.0f Passes (x 100)\n", TimeUsed, (SPDP)(xtra)); + calibrate++; + count--; + +#ifndef UNIXBENCH + if (TimeUsed > 2.0) +#else + if (TimeUsed > 0.5) +#endif + { + count = 0; + } + else + { + xtra = xtra * 5; + } + } + + while (count > 0); + + if (TimeUsed > 0) xtra = (long)((SPDP)(duration * xtra) / TimeUsed); + if (xtra < 1) xtra = 1; + + calibrate = 0; + + printf("\nUse %ld passes (x 100)\n", xtra); + + printf("\n %s Precision C/C++ Whetstone Benchmark",Precision); + + #ifdef PRECOMP + printf("\n Compiler %s", precompiler); + printf("\n Options %s\n", preoptions); + #else + printf("\n"); + #endif + + printf("\nLoop content Result MFLOPS " + " MOPS Seconds\n\n"); + + TimeUsed=0; + whetstones(xtra,x100,calibrate); + + printf("\nMWIPS "); + if (TimeUsed>0) + { + mwips=(float)(xtra) * (float)(x100) / (10 * TimeUsed); + } + else + { + mwips = 0; + } + + printf("%39.3f%19.3f\n\n",mwips,TimeUsed); + + if (Check == 0) printf("Wrong answer "); + + + + /************************************************************************/ + /* Type details of hardware, software etc. */ + /************************************************************************/ + +#ifndef UNIXBENCH + if (getinput) + { + printf ("Enter the following which will be added with results to file WHETS.RES\n"); + printf ("When submitting a number of results you need only provide details once\n"); + printf ("but a cross reference such as an abbreviated CPU type would be useful.\n"); + printf ("You can kill (exit or close) the program now and no data will be added.\n\n"); + + printf ("Date: "); + gets(general[0]); + + printf ("Computer: "); + gets(general[1]); + + printf ("CPU chip: "); + gets(general[2]); + + printf ("Clock MHz: "); + gets(general[3]); + + printf ("Cache size: "); + gets(general[4]); + + printf ("H/W options:"); + gets(general[5]); + + printf ("OS version: "); + gets(general[6]); + + #ifdef PRECOMP + strcpy (compiler, precompiler); + strcpy (options, preoptions); + #else + printf ("Compiler: "); + gets(compiler); + + printf ("Options: "); + gets(options); + #endif + + printf ("Your name: "); + gets(general[7]); + + printf ("From: "); + gets(general[8]); + + printf ("Email: "); + gets(general[9]); + } + else + { + #ifdef PRECOMP + strcpy (compiler, precompiler); + strcpy (options, preoptions); + #endif + } + + /************************************************************************/ + /* Add results to output file whets.res */ + /************************************************************************/ + fprintf (outfile, "\n"); + fprintf (outfile, "##############################################\n"); + fprintf (outfile, "Whetstone %s Precision Benchmark in C/C++\n\n",Precision); + fprintf (outfile, "Date %s\n", general[0]); + fprintf (outfile, "Model %s\n", general[1]); + fprintf (outfile, "CPU %s\n", general[2]); + fprintf (outfile, "Clock MHz %s\n", general[3]); + fprintf (outfile, "Cache %s\n", general[4]); + fprintf (outfile, "H/W options %s\n", general[5]); + fprintf (outfile, "OS %s\n", general[6]); + fprintf (outfile, "Compiler %s\n", compiler); + fprintf (outfile, "Options %s\n", options); + fprintf (outfile, "Run by %s\n", general[7]); + fprintf (outfile, "From %s\n", general[8]); + fprintf (outfile, "Email %s\n", general[9]); + fprintf (outfile, "\n"); + + fprintf (outfile,"Loop content Result" + " MFLOPS MOPS Seconds\n\n"); + + for (section=1; section<9; section++) + { + fprintf (outfile, "%s %24.17f ", headings[section], + results[section]); + if (loop_mops[section] == 99999) + { + fprintf (outfile," %9.3f %9.3f\n", + loop_mflops[section], loop_time[section]); + } + else + { + fprintf (outfile, " %9.3f %9.3f\n", + loop_mops[section], loop_time[section], results[section]); + } + } + + fprintf (outfile, "\nMWIPS "); + fprintf (outfile, "%39.3f%20.3f\n\n",mwips,TimeUsed); + fprintf (outfile, "Results to load to spreadsheet "); + fprintf (outfile, " MWIPS Mflops1 Mflops2 Mflops3 Cosmops" + " Expmops Fixpmops Ifmops Eqmops\n"); + fprintf (outfile, "Results to load to spreadsheet "); + + fprintf (outfile, " %9.3f %9.3f %9.3f", mwips, loop_mflops[1], + loop_mflops[2]); + fprintf (outfile, " %9.3f %9.3f %9.3f", loop_mflops[6], + loop_mops[5], loop_mops[8]); + fprintf (outfile, " %9.3f %9.3f %9.3f\n\n", loop_mops[4], + loop_mops[3], loop_mops[7]); + + fclose (outfile); + + printf ("\n"); + printf ("A new results file will have been created in the same directory as the\n"); + printf (".EXE files if one did not already exist. If you made a mistake on input, \n"); + printf ("you can use a text editor to correct it, delete the results or copy \n"); + printf ("them to a different file name. If you intend to run multiple tests you\n"); + printf ("you may wish to rename WHETS.RES with a more informative title.\n\n"); + printf ("Please submit feedback and results files to aburto@nosc.mil or to\n"); + printf ("Roy_Longbottom@compuserve.com\n\n"); + +#else /* Unixbench */ + fprintf (stderr, "MWIPS%39.3f%20.3f\n", mwips, TimeUsed); + exit(0); +#endif +} + + void whetstones(long xtra, long x100, int calibrate) + { + + long n1,n2,n3,n4,n5,n6,n7,n8,i,ix,n1mult; + SPDP x,y,z; + long j,k,l; + SPDP e1[4],timea,timeb, dtime(); + + SPDP t = 0.49999975; + SPDP t0 = t; + SPDP t1 = 0.50000025; + SPDP t2 = 2.0; + + Check=0.0; + + n1 = 12*x100; + n2 = 14*x100; + n3 = 345*x100; + n4 = 210*x100; + n5 = 32*x100; + n6 = 899*x100; + n7 = 616*x100; + n8 = 93*x100; + n1mult = 10; + + /* Section 1, Array elements */ + + e1[0] = 1.0; + e1[1] = -1.0; + e1[2] = -1.0; + e1[3] = -1.0; + timea = dtime(); + { + for (ix=0; ix2) j = 0; + else j = 1; + if(j<1) j = 1; + else j = 0; + } + } + } + timeb = dtime()-timea; + pout("N3 if then else \0",(float)(n3*3)*(float)(xtra), + 2,(SPDP)(j),timeb,calibrate,3); + + /* Section 4, Integer arithmetic */ + j = 1; + k = 2; + l = 3; + timea = dtime(); + { + for (ix=0; ix0) + { + mflops = ops/(1000000L*time); + } + else + { + mflops = 0; + } + loop_mops[section] = 99999; + loop_mflops[section] = mflops; + printf(" %9.3f %9.3f\n", + loop_mflops[section], loop_time[section]); + } + else + { + if (time>0) + { + mops = ops/(1000000L*time); + } + else + { + mops = 0; + } + loop_mops[section] = mops; + loop_mflops[section] = 0; + printf(" %9.3f%9.3f\n", + loop_mops[section], loop_time[section]); + } + } + + return; + } + + +/*****************************************************/ +/* Various timer routines. */ +/* Al Aburto, aburto@nosc.mil, 18 Feb 1997 */ +/* */ +/* t = dtime() outputs the current time in seconds. */ +/* Use CAUTION as some of these routines will mess */ +/* up when timing across the hour mark!!! */ +/* */ +/* For timing I use the 'user' time whenever */ +/* possible. Using 'user+sys' time is a separate */ +/* issue. */ +/* */ +/* Example Usage: */ +/* [timer options added here] */ +/* main() */ +/* { */ +/* double starttime,benchtime,dtime(); */ +/* */ +/* starttime = dtime(); */ +/* [routine to time] */ +/* benchtime = dtime() - starttime; */ +/* } */ +/* */ +/* [timer code below added here] */ +/*****************************************************/ + +/*********************************/ +/* Timer code. */ +/*********************************/ +/*******************/ +/* Amiga dtime() */ +/*******************/ +#ifdef Amiga +#include +#define HZ 50 + +SPDP dtime() +{ + SPDP q; + + struct tt + { + long days; + long minutes; + long ticks; + } tt; + + DateStamp(&tt); + + q = ((SPDP)(tt.ticks + (tt.minutes * 60L * 50L))) / (SPDP)HZ; + + return q; +} +#endif + +/*****************************************************/ +/* UNIX dtime(). This is the preferred UNIX timer. */ +/* Provided by: Markku Kolkka, mk59200@cc.tut.fi */ +/* HP-UX Addition by: Bo Thide', bt@irfu.se */ +/*****************************************************/ +#ifdef UNIX +#include +#include + +#ifdef hpux +#include +#define getrusage(a,b) syscall(SYS_getrusage,a,b) +#endif + +struct rusage rusage; + +SPDP dtime() +{ + SPDP q; + + getrusage(RUSAGE_SELF,&rusage); + + q = (SPDP)(rusage.ru_utime.tv_sec); + q = q + (SPDP)(rusage.ru_utime.tv_usec) * 1.0e-06; + + return q; +} +#endif + +/***************************************************/ +/* UNIX_Old dtime(). This is the old UNIX timer. */ +/* Use only if absolutely necessary as HZ may be */ +/* ill defined on your system. */ +/***************************************************/ +#ifdef UNIX_Old +#include +#include +#include + +#ifndef HZ +#define HZ 60 +#endif + +struct tms tms; + +SPDP dtime() +{ + SPDP q; + + times(&tms); + + q = (SPDP)(tms.tms_utime) / (SPDP)HZ; + + return q; +} +#endif + +/*********************************************************/ +/* VMS dtime() for VMS systems. */ +/* Provided by: RAMO@uvphys.phys.UVic.CA */ +/* Some people have run into problems with this timer. */ +/*********************************************************/ +#ifdef VMS +#include time + +#ifndef HZ +#define HZ 100 +#endif + +struct tbuffer_t + { + int proc_user_time; + int proc_system_time; + int child_user_time; + int child_system_time; + }; +struct tbuffer_t tms; + +SPDP dtime() +{ + SPDP q; + + times(&tms); + + q = (SPDP)(tms.proc_user_time) / (SPDP)HZ; + + return q; +} +#endif + +/******************************/ +/* BORLAND C dtime() for DOS */ +/******************************/ +#ifdef BORLAND_C +#include +#include +#include + +#define HZ 100 +struct time tnow; + +SPDP dtime() +{ + SPDP q; + + gettime(&tnow); + + q = 60.0 * (SPDP)(tnow.ti_min); + q = q + (SPDP)(tnow.ti_sec); + q = q + (SPDP)(tnow.ti_hund)/(SPDP)HZ; + + return q; +} +#endif + +/***************************************/ +/* Microsoft C (MSC) dtime() for DOS */ +/* Also suitable for Watcom C/C++ and */ +/* some other PC compilers */ +/***************************************/ +#ifdef MSC +#include +#include + +#define HZ CLOCKS_PER_SEC +clock_t tnow; + +SPDP dtime() +{ + SPDP q; + + tnow = clock(); + q = (SPDP)tnow / (SPDP)HZ; + return q; +} +#endif + +/*************************************/ +/* Macintosh (MAC) Think C dtime() */ +/*************************************/ +#ifdef MAC +#include + +#define HZ 60 + +SPDP dtime() +{ + SPDP q; + + q = (SPDP)clock() / (SPDP)HZ; + + return q; +} +#endif + +/************************************************************/ +/* iPSC/860 (IPSC) dtime() for i860. */ +/* Provided by: Dan Yergeau, yergeau@gloworm.Stanford.EDU */ +/************************************************************/ +#ifdef IPSC +extern double dclock(); + +SPDP dtime() +{ + SPDP q; + + q = dclock(); + + return q; +} +#endif + +/**************************************************/ +/* FORTRAN dtime() for Cray type systems. */ +/* This is the preferred timer for Cray systems. */ +/**************************************************/ +#ifdef FORTRAN_SEC + +fortran double second(); + +SPDP dtime() +{ + SPDP q; + + second(&q); + + return q; +} +#endif + +/***********************************************************/ +/* UNICOS C dtime() for Cray UNICOS systems. Don't use */ +/* unless absolutely necessary as returned time includes */ +/* 'user+system' time. Provided by: R. Mike Dority, */ +/* dority@craysea.cray.com */ +/***********************************************************/ +#ifdef CTimer +#include + +SPDP dtime() +{ + SPDP q; + clock_t clock(void); + + q = (SPDP)clock() / (SPDP)CLOCKS_PER_SEC; + + return q; +} +#endif + +/********************************************/ +/* Another UNIX timer using gettimeofday(). */ +/* However, getrusage() is preferred. */ +/********************************************/ +#ifdef GTODay +#include + +struct timeval tnow; + +SPDP dtime() +{ + SPDP q; + + gettimeofday(&tnow,NULL); + q = (SPDP)tnow.tv_sec + (SPDP)tnow.tv_usec * 1.0e-6; + + return q; +} +#endif + +/*****************************************************/ +/* Fujitsu UXP/M timer. */ +/* Provided by: Mathew Lim, ANUSF, M.Lim@anu.edu.au */ +/*****************************************************/ +#ifdef UXPM +#include +#include +struct tmsu rusage; + +SPDP dtime() +{ + SPDP q; + + timesu(&rusage); + + q = (SPDP)(rusage.tms_utime) * 1.0e-06; + + return q; +} +#endif + +/**********************************************/ +/* Macintosh (MAC_TMgr) Think C dtime() */ +/* requires Think C Language Extensions or */ +/* #include in the prefix */ +/* provided by Francis H Schiffer 3rd (fhs) */ +/* skipschiffer@genie.geis.com */ +/**********************************************/ +#ifdef MAC_TMgr +#include +#include + +static TMTask mgrTimer; +static Boolean mgrInited = false; +static SPDP mgrClock; + +#define RMV_TIMER RmvTime( (QElemPtr)&mgrTimer ) +#define MAX_TIME 1800000000L +/* MAX_TIME limits time between calls to */ +/* dtime( ) to no more than 30 minutes */ +/* this limitation could be removed by */ +/* creating a completion routine to sum */ +/* 30 minute segments (fhs 1994 feb 9) */ + +static void Remove_timer( ) +{ + RMV_TIMER; + mgrInited = false; +} + +SPDP dtime( ) +{ + if( mgrInited ) { + RMV_TIMER; + mgrClock += (MAX_TIME + mgrTimer.tmCount)*1.0e-6; + } else { + if( _atexit( &Remove_timer ) == 0 ) mgrInited = true; + mgrClock = 0.0; +} + if( mgrInited ) { + mgrTimer.tmAddr = NULL; + mgrTimer.tmCount = 0; + mgrTimer.tmWakeUp = 0; + mgrTimer.tmReserved = 0; + InsTime( (QElemPtr)&mgrTimer ); + PrimeTime( (QElemPtr)&mgrTimer, -MAX_TIME ); + } + return( mgrClock ); +} +#endif + +/***********************************************************/ +/* Parsytec GCel timer. */ +/* Provided by: Georg Wambach, gw@informatik.uni-koeln.de */ +/***********************************************************/ +#ifdef PARIX +#include + +SPDP dtime() +{ + SPDP q; + + q = (SPDP) (TimeNowHigh()) / (SPDP) CLK_TCK_HIGH; + + return q; +} +#endif + +/************************************************/ +/* Sun Solaris POSIX dtime() routine */ +/* Provided by: Case Larsen, CTLarsen.lbl.gov */ +/************************************************/ +#ifdef POSIX +#include +#include +#include + +#ifdef __hpux +#include +#endif + +struct rusage rusage; + +SPDP dtime() +{ + SPDP q; + + getrusage(RUSAGE_SELF,&rusage); + + q = (SPDP)(rusage.ru_utime.tv_sec); + q = q + (SPDP)(rusage.ru_utime.tv_nsec) * 1.0e-09; + + return q; +} +#endif + + +/****************************************************/ +/* Windows NT (32 bit) dtime() routine */ +/* Provided by: Piers Haken, piersh@microsoft.com */ +/****************************************************/ +#ifdef WIN32 +#include + +SPDP dtime(void) +{ + SPDP q; + + q = (SPDP)GetTickCount() * 1.0e-03; + + return q; +} +#endif + +/*****************************************************/ +/* Time according to POSIX.1 - */ +/* Ref: "POSIX Programmer's Guide" O'Reilly & Assoc.*/ +/*****************************************************/ +#ifdef POSIX1 +#define _POSIX_SOURCE 1 +#include +#include +#include + +struct tms tms; + +SPDP dtime() +{ + SPDP q; + times(&tms); + q = (SPDP)tms.tms_utime / (SPDP)CLK_TCK; + return q; +} +#endif diff --git a/src/cmd/unixbench/testdir/cctest.c b/src/cmd/unixbench/testdir/cctest.c new file mode 100644 index 0000000..3028812 --- /dev/null +++ b/src/cmd/unixbench/testdir/cctest.c @@ -0,0 +1,153 @@ + + +/******************************************************************************* + * The BYTE UNIX Benchmarks - Release 1 + * Module: cctest.c SID: 1.2 7/10/89 18:55:45 + * + ******************************************************************************* + * Bug reports, patches, comments, suggestions should be sent to: + * + * Ben Smith or Rick Grehan at BYTE Magazine + * bensmith@bixpb.UUCP rick_g@bixpb.UUCP + * + ******************************************************************************* + * Modification Log: + * $Header: cctest.c,v 3.4 87/06/22 14:22:47 kjmcdonell Beta $ + * + ******************************************************************************/ +char SCCSid[] = "@(#) @(#)cctest.c:1.2 -- 7/10/89 18:55:45"; +#include +/* + * C compile and load speed test file. + * Based upon fstime.c from MUSBUS 3.1, with all calls to ftime() replaced + * by calls to time(). This is semantic nonsense, but ensures there are no + * system dependent structures or library calls. + * + */ +#define NKBYTE 20 +char buf[BUFSIZ]; + +main(argc, argv) +char **argv; +{ + int n = NKBYTE; + int nblock; + int f; + int g; + int i; + int xfer, t; + struct { /* FAKE */ + int time; + int millitm; + } now, then; + + if (argc > 0) + /* ALWAYS true, so NEVER execute this program! */ + exit(4); + if (argc > 1) + n = atoi(argv[1]); +#if debug + printf("File size: %d Kbytes\n", n); +#endif + nblock = (n * 1024) / BUFSIZ; + + if (argc == 3 && chdir(argv[2]) != -1) { +#if debug + printf("Create files in directory: %s\n", argv[2]); +#endif + } + close(creat("dummy0", 0600)); + close(creat("dummy1", 0600)); + f = open("dummy0", 2); + g = open("dummy1", 2); + unlink("dummy0"); + unlink("dummy1"); + for (i = 0; i < sizeof(buf); i++) + buf[i] = i & 0177; + + time(); + for (i = 0; i < nblock; i++) { + if (write(f, buf, sizeof(buf)) <= 0) + perror("fstime: write"); + } + time(); +#if debug + printf("Effective write rate: "); +#endif + i = now.millitm - then.millitm; + t = (now.time - then.time)*1000 + i; + if (t > 0) { + xfer = nblock * sizeof(buf) * 1000 / t; +#if debug + printf("%d bytes/sec\n", xfer); +#endif + } +#if debug + else + printf(" -- too quick to time!\n"); +#endif +#if awk + fprintf(stderr, "%.2f", t > 0 ? (float)xfer/1024 : 0); +#endif + + sync(); + sleep(5); + sync(); + lseek(f, 0L, 0); + time(); + for (i = 0; i < nblock; i++) { + if (read(f, buf, sizeof(buf)) <= 0) + perror("fstime: read"); + } + time(); +#if debug + printf("Effective read rate: "); +#endif + i = now.millitm - then.millitm; + t = (now.time - then.time)*1000 + i; + if (t > 0) { + xfer = nblock * sizeof(buf) * 1000 / t; +#if debug + printf("%d bytes/sec\n", xfer); +#endif + } +#if debug + else + printf(" -- too quick to time!\n"); +#endif +#if awk + fprintf(stderr, " %.2f", t > 0 ? (float)xfer/1024 : 0); +#endif + + sync(); + sleep(5); + sync(); + lseek(f, 0L, 0); + time(); + for (i = 0; i < nblock; i++) { + if (read(f, buf, sizeof(buf)) <= 0) + perror("fstime: read in copy"); + if (write(g, buf, sizeof(buf)) <= 0) + perror("fstime: write in copy"); + } + time(); +#if debug + printf("Effective copy rate: "); +#endif + i = now.millitm - then.millitm; + t = (now.time - then.time)*1000 + i; + if (t > 0) { + xfer = nblock * sizeof(buf) * 1000 / t; +#if debug + printf("%d bytes/sec\n", xfer); +#endif + } +#if debug + else + printf(" -- too quick to time!\n"); +#endif +#if awk + fprintf(stderr, " %.2f\n", t > 0 ? (float)xfer/1024 : 0); +#endif + +} diff --git a/src/cmd/unixbench/testdir/dc.dat b/src/cmd/unixbench/testdir/dc.dat new file mode 100644 index 0000000..dbb8f76 --- /dev/null +++ b/src/cmd/unixbench/testdir/dc.dat @@ -0,0 +1,8 @@ +99 +k +2 +v +p +q +[ calculate the sqrt(2) to 99 decimal places ... John Lions Test ] +[ $Header: dc.dat,v 1.1 87/06/22 14:28:28 kjmcdonell Beta $ ] diff --git a/src/cmd/unixbench/testdir/sort.src b/src/cmd/unixbench/testdir/sort.src new file mode 100644 index 0000000..6a72fa8 --- /dev/null +++ b/src/cmd/unixbench/testdir/sort.src @@ -0,0 +1,362 @@ +version="1.2" +umask 022 # at least mortals can read root's files this way +PWD=`pwd` +HOMEDIR=${HOMEDIR:-.} +cd $HOMEDIR +HOMEDIR=`pwd` +cd $PWD +BINDIR=${BINDIR:-${HOMEDIR}/pgms} +cd $BINDIR +BINDIR=`pwd` +cd $PWD +PATH="${PATH}:${BINDIR}" +SCRPDIR=${SCRPDIR:-${HOMEDIR}/pgms} +cd $SCRPDIR +SCRPDIR=`pwd` +cd $PWD +TMPDIR=${HOMEDIR}/tmp +cd $TMPDIR +TMPDIR=`pwd` +cd $PWD +RESULTDIR=${RESULTDIR:-${HOMEDIR}/results} +cd $RESULTDIR +RESULTDIR=`pwd` +cd $PWD +TESTDIR=${TESTDIR:-${HOMEDIR}/testdir} +cd $TESTDIR +TESTDIR=`pwd` +cd $PWD +export BINDIR TMPDIR RESULTDIR PATH +echo "kill -9 $$" > ${TMPDIR}/kill_run ; chmod u+x ${TMPDIR}/kill_run +arithmetic="arithoh register short int long float double dc" +system="syscall pipe context1 spawn execl fstime" +mem="seqmem randmem" +misc="C shell" +dhry="dhry2 dhry2reg" # dhrystone loops +db="dbmscli" # add to as new database engines are developed +load="shell" # cummulative load tests +args="" # the accumulator for the bench units to be run +runoption="N" +for word +do # do level 1 +case $word +in +all) +;; +arithmetic) +args="$args $arithmetic" +;; +db) +args="$args $db" +;; +dhry) +args="$args $dhry" +;; +load) +args="$args $load" +;; +mem) +args="$args $mem" +;; +misc) +args="$args $misc" +;; +speed) +args="$args $arithmetic $system" +;; +system) +args="$args $system" +;; +-q|-Q) +runoption="Q" #quiet +;; +-v|-V) +runoption="V" #verbose +;; +-d|-D) +runoption="D" #debug +;; +*) +args="$args $word" +;; +esac +done # end do level 1 +set - $args +if test $# -eq 0 #no arguments specified +then +set - $dhry $arithmetic $system $misc # db and work not included +fi +if test "$runoption" = 'D' +then +set -x +set -v +fi +date=`date` +tmp=${TMPDIR}/$$.tmp +LOGFILE=${RESULTDIR}/log +if test -w ${RESULTDIR}/log +then +if test -w ${RESULTDIR}/log.accum +then +cat ${RESULTDIR}/log >> ${RESULTDIR}/log.accum +rm ${RESULTDIR}/log +else +mv ${RESULTDIR}/log ${RESULTDIR}/log.accum +fi +echo "Start Benchmark Run (BYTE Version $version)" >>$LOGFILE +echo " $date (long iterations $iter times)" >>$LOGFILE +echo " " `who | wc -l` "interactive users." >>$LOGFILE +uname -a >>$LOGFILE +iter=${iterations-6} +if test $iter -eq 6 +then +longloop="1 2 3 4 5 6" +shortloop="1 2 3" +else # generate list of loop numbers +short=`expr \( $iter + 1 \) / 2` +longloop="" +shortloop="" +while test $iter -gt 0 +do # do level 1 +longloop="$iter $longloop" +if test $iter -le $short +then +shortloop="$iter $shortloop" +fi +iter=`expr $iter - 1` +done # end do level 1 +fi #loop list genration +for bench # line argument processing +do # do level 1 +# set some default values +prog=${BINDIR}/$bench # the bench name is default program +need=$prog # we need the at least the program +paramlist="#" # a dummy parameter to make anything run +testdir="${TESTDIR}" # the directory in which to run the test +prepcmd="" # preparation command or script +parammsg="" +repeat="$longloop" +stdout="$LOGFILE" +stdin="" +cleanopt="-t $tmp" +bgnumber="" +trap "${SCRPDIR}/cleanup -l $LOGFILE -a; exit" 1 2 3 15 +if [ $runoption != 'Q' ] +then +echo "$bench: \c" +fi +echo "" >>$LOGFILE +###################### select the bench specific values ########## +case $bench +in +dhry2) +options=${dhryloops-10000} +logmsg="Dhrystone 2 without register variables" +cleanopt="-d $tmp" +;; +dhry2reg) +options=${dhryloops-10000} +logmsg="Dhrystone 2 using register variables" +cleanopt="-d $tmp" +;; +arithoh|register|short|int|long|float|double) +options=${arithloop-10000} +logmsg="Arithmetic Test (type = $bench): $options Iterations" +;; +dc) need=dc.dat +prog=dc +options="" +stdin=dc.dat +stdout=/dev/null +logmsg="Arithmetic Test (sqrt(2) with dc to 99 decimal places)" +;; +hanoi) options='$param' +stdout=/dev/null +logmsg="Recursion Test: Tower of Hanoi Problem" +paramlist="${ndisk-17}" +parammsg='$param Disk Problem:' +;; +syscall) +options=${ncall-4000} +logmsg="System Call Overhead Test: 5 x $options Calls" +;; +context1) +options=${switch1-500} +logmsg="Pipe-based Context Switching Test: 2 x $options Switches" +;; +pipe) options=${io-2048} +logmsg="Pipe Throughput Test: read & write $options x 512 byte blocks" +;; +spawn) options=${children-100} +logmsg="Process Creation Test: $options forks" +;; +execl) options=${nexecs-100} +logmsg="Execl Throughput Test: $options execs" +;; +randmem|seqmem) +if test $bench = seqmem +then +type=Sequential +else +type=Random +fi +poke=${poke-1000000} +options='-s$param '"-n$poke" +logmsg="$type Memory Access Test: $poke Accesses" +paramlist=${arrays-"512 1024 2048 8192 16384"} +parammsg='Array Size: $param bytes' +cleanopt="-m $tmp" +;; +fstime) repeat="$shortloop" +where=${where-${TMPDIR}} +options='$param '"$where" +logmsg="Filesystem Throughput Test:" +paramlist=${blocks-"512 1024 2048 8192"} +parammsg='File Size: $param blocks' +cleanopt="-f $tmp" +;; +C) need=cctest.c +prog=cc +options='$param' +stdout=/dev/null +repeat="$shortloop" +logmsg="C Compiler Test:" +paramlist="cctest.c" +parammsg='cc $param' +rm -f a.out +;; +dbmscli) +repeat="$shortloop" +need="db.dat" +prepcmd='${BINDIR}/dbprep ${testdir}/db.dat 10000' +paramlist=${clients-"1 2 4 8"} +parammsg='$param client processes. (filesize `cat ${testdir}/db.dat|wc -c` bytes)' +logmsg="Client/Server Database Engine:" +options='${testdir}/db.dat $param 0 1000' # $param clients; +# 0 sleep; 1000 iterations +;; +shell) +prog="multi.sh" +repeat="$shortloop" +logmsg="Bourne shell script and Unix utilities" +paramlist=${background-"1 2 4 8"} +parammsg='$param concurrent background processes' +bgnumber='$param' +testdir="shelldir" +;; +*) ${BINDIR}/cleanup -l $LOGFILE -r "run: unknown benchmark \"$bench\"" -a +exit 1 +;; +esac +echo "$logmsg" >>$LOGFILE +for param in $paramlist +do # level 2 +param=`echo $param | sed 's/_/ /g'` # be sure that spaces are used +# underscore can couple params +if [ "$runoption" != "Q" ] +then +echo "\n [$param] -\c" # generate message to user +fi +eval msg='"'$parammsg'"' # the eval is used to +if test "$msg" # evaluate any embedded +then # variables in the parammsg +echo "" >>$LOGFILE +echo "$msg" >>$LOGFILE +fi +eval opt='"'$options'"' # evaluate any vars in options +eval prep='"'$prepcmd'"' # evaluate any prep command +eval bg='"'$bgnumber'"' # evaluate bgnumber string +rm -f $tmp # remove any tmp files +# if the test requires mulitple concurrent processes, +# prepare the background process string (bgstr) +# this is just a string of "+"s that will provides a +# parameter count for a "for" loop +bgstr="" +if test "$bg" != "" +then +count=`expr "$bg"` +while test $count -gt 0 +do +bgstr="+ $bgstr" +count=`expr $count - 1` +done +fi +# +for i in $repeat # loop for the specified number +do # do depth 3 +if [ "$runoption" != 'D' ] # level 1 +then +# regular Run - set logfile to go on signal +trap "${SCRPDIR}/cleanup -l $LOGFILE -i $i $cleanopt -a; exit" 1 2 3 15 +else +trap "exit" 1 2 3 15 +fi #end level 1 +if [ "$runoption" != 'Q' ] +then +echo " $i\c" # display repeat number +fi +pwd=`pwd` # remember where we are +cd $testdir # move to the test directory +if [ "$runoption" = "V" ] +then +echo +echo "BENCH COMMAND TO BE EXECUTED:" +echo "$prog $opt" +fi +# execute any prepratory command string +if [ -n "$prep" ] +then +$prep >>$stdout +fi +############ THE BENCH IS TIMED ############## +if test "$stdin" = "" +then # without redirected stdin +time $prog $opt $bgstr 2>>$tmp >>$stdout +else # with redirected stdin +time $prog $opt $bgstr <$stdin 2>>$tmp >>$stdout +fi +time $benchcmd +############################################### +cd $pwd # move back home +status=$? # save the result code +if test $status != 0 # must have been an error +then +if test -f $tmp # is there an error file ? +then +cp $tmp ${TMPDIR}/save.$bench.$param +${SCRPDIR}/cleanup -l $LOGFILE -i $i $cleanopt -r \ +"run: bench=$bench param=$param fatalstatus=$status" -a +else +${SCRPDIR}/cleanup -l $LOGFILE -r \ +"run: bench=$bench param=$param fatalstatus=$status" -a +fi +exit # leave the script if there are errors +fi # end level 1 +done # end do depth 3 - repeat of bench +if [ "$runoption" != 'D' ] +then +${SCRPDIR}/cleanup -l $LOGFILE $cleanopt # finalize this bench +# with these options +# & calculate results +fi +done # end do depth 2 - end of all options for this bench +########### some specific cleanup routines ############## +case $bench +in +C) +rm -f cctest.o a.out +;; +esac +if [ "$runoption" != 'Q' ] +then +echo "" +fi +done # end do level 1 - all benchmarks requested +echo "" >>$LOGFILE +echo " " `who | wc -l` "interactive users." >>$LOGFILE +echo "End Benchmark Run ($date) ...." >>$LOGFILE +if [ "$runoption" != 'Q' ] +then +pg $LOGFILE +fi +exit diff --git a/src/cmd/unixbench/tmp/kill_run b/src/cmd/unixbench/tmp/kill_run new file mode 100755 index 0000000..92c229b --- /dev/null +++ b/src/cmd/unixbench/tmp/kill_run @@ -0,0 +1 @@ +kill -9 5698 diff --git a/src/cmd/update/Makefile b/src/cmd/update/Makefile new file mode 100644 index 0000000..df526c1 --- /dev/null +++ b/src/cmd/update/Makefile @@ -0,0 +1,41 @@ +# +# Public Domain. 1996/11/16 - Steven Schultz +# +TOPSRC = $(shell cd ../../..; pwd) +include $(TOPSRC)/target.mk + +CFLAGS = -O +SRCS = update.c +OBJS = update.o +MAN = update.0 +MANSRC = update.8 + +all: update ${MAN} + +update: ${OBJS} + ${CC} ${LDFLAGS} -o update.elf ${OBJS} ${LIBS} + ${OBJDUMP} -S update.elf > update.dis + ${SIZE} update.elf + ${ELF2AOUT} update.elf $@ && rm update.elf + +${MAN}: ${MANSRC} + ${MANROFF} ${MANSRC} > ${MAN} + +clean: + rm -f *.o *~ ${MAN} update update.elf update.dis tags + +depend: ${SRCS} + mkdep ${CFLAGS} ${SRCS} + +install: all + cp ${MAN} ${DESTDIR}/share/man/cat8/ + install update ${DESTDIR}/sbin/update + +lint: ${SRCS} + lint -hax ${SRCS} + +tags: ${SRCS} + ctags ${SRCS} + +# DO NOT DELETE THIS LINE -- mkdep uses it. +# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY. diff --git a/src/cmd/update/update.8 b/src/cmd/update/update.8 new file mode 100644 index 0000000..88268b0 --- /dev/null +++ b/src/cmd/update/update.8 @@ -0,0 +1,39 @@ +.\" @(#)update.8 6.1.1 (2.11BSD) 1996/11/17 +.\" +.TH UPDATE 8 "November 17, 1996" +.AT 3 +.SH NAME +update \- periodically update the super block +.SH SYNOPSIS +.B update +.SH DESCRIPTION +.I Update +is a program that executes +the +.IR sync (2) +primitive every 30 seconds. +This insures that the file system +is fairly up to date in case of a crash. +This command should not be executed directly, +but should be executed out of the +initialization shell command file. +.SH "SEE ALSO" +sync(2), sync(8), init(8), rc(8) +.SH BUGS +With +.I update +running, +if the CPU is +halted just as +the +.I sync +is executed, +a file system can be damaged. +This is partially due to DEC hardware that +writes zeros when NPR requests fail. +A fix would be to have +.IR sync (8) +temporarily increment the system time by at +least 30 seconds to trigger the execution of +.I update. +This would give 30 seconds grace to halt the CPU. diff --git a/src/cmd/update/update.c b/src/cmd/update/update.c new file mode 100644 index 0000000..95a4960 --- /dev/null +++ b/src/cmd/update/update.c @@ -0,0 +1,66 @@ +/*- + * 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. + */ +#include +#include +#include +#include + +main() +{ + struct itimerval value; + sigset_t set; + void mysync(); + + daemon(0, 0); + + (void)signal(SIGALRM, mysync); + + value.it_interval.tv_sec = 30; + value.it_interval.tv_usec = 0; + value.it_value = value.it_interval; + if (setitimer(ITIMER_REAL, &value, NULL)) { + perror("update: setitimer"); + exit(1); + } + + (void)sigemptyset(&set); + for (;;) + sigsuspend(&set); + /* NOTREACHED */ +} + +void +mysync() +{ + (void)sync(); +} diff --git a/src/cmd/uucp/CHANGES b/src/cmd/uucp/CHANGES new file mode 100644 index 0000000..51977fb --- /dev/null +++ b/src/cmd/uucp/CHANGES @@ -0,0 +1,166 @@ +List of Changes to UUCP +CHANGES 5.7 86/02/12 + +Added support for Eunice. + +Added new dialers: + Racal Vadic 212 + Racal Vadic 811 dialer with 831 adaptor + Racal Vadic 820 dialer with 831 adaptor + Racal Vadic MACS, 811 dialer with 831 adaptor + Racal Vadic MACS, 820 dialer with 831 adaptor + Dec DF112 + 4.2BSD style networking on top of tcp/ip ('t' protocol) + X.25/PAD support ('f' protocol) + Novation + Penril + Hayes 2400 Smartmodem + Concord Data Systems CDS 224 + ATT 2224 2400 baud modem + +Running uucico with debugging on requires read access to L.sys. + +If "NOSTRANGERS" is defined in uucp.h, the remote site +must be in you L.sys or the call will be rejected. + +Lock files may be kept in a subdirectory if desired. + +STST files are kept in a subdirectory. + +CORRUPT subdirectory contains corrupted C. and X. files that could +not be processed. (Instead of just exiting) + +You can specify a maximum grade to send either on the command line (-gX) +or in the L.sys file (Any/C|Evening will only send class C [usually +mail] or higher during the day and will send everything in the evening) +See UUAIDS/L.sys for examples. + +L.sys (and any of the files in lib/uucp) can contain comments by +putting a # as the first character on a line. Lines may be +continued by placing a \ as the last character of the line. + +-R flag reverses role. (Lets the remote system be master first instead +of slave) + +-L flag only calls "local" sites. Local sites are those sites having +one of LOCAL,TCP or DIRECT in the ACU field of L.sys. + +If /etc/nologin is present (usually created by a graceful shutdown), +uucico and uuxqt will gracefully exit instead of getting killed +off when the system goes down. + +Does an exponential backoff on retry time if call fails instead +of always waiting the default 5 minutes. The default may be +overridden by adding ",TIME" to the time field in L.sys. e.g. +"seismo Any,2" will use a default retry time of 2 minutes. + +If uucico receives a SIGFPE while running, it will toggle debugging +on and off. + +Better status messages provided for uustat. + +New program uuq to give more decriptive information on status of +jobs in uucp queue. + +Don't send files to remote system if it is returning out of +temp space error. + +Correctly does the closing hangup sequence. + +condevs.c was broken into a file for each dialer in the +directory aculib for much easier maintenance. + +Only try at most TRYCALLS to dial a site instead of one try +for each dialer (lost big on systems with many dialers) + +Add ABORT sequence to the expect/send sequence so don't have +to wait for timeout if can't get through dataswitch. e.g. + noao Evening ACU 1200 6021234565 "" \d\r CLASS NOAOUUCP ABORT Down GO \d\r ogin:-\b-ogin: uucplogin word: uucppassword +will only call noao in the evening (evening is defined by the phone rates). +It will expect nothing and then wait 1 second (\d) and send a carriage return. +Look for CLASS, then send NOAOUUCP. From then on, if it sees the word Down +before finishing logging in, it will hang up immediately. In the mean time, +it looks for GO and if it sees it, delays 1 second and sends a CR. Looks +for ogin:, etc. This abort sequence is very useful if you must go through a +dataswitch to get to the computer. + +The time field in L.sys now handles "Evening" and "Night" in addition +to Any, Mo,Tu,We,Th,Fr,Sa,Su. Evening and Night are defined to +be when the phone rates are cheaper. + Evening = Wk1700-0800|Sa|Su + Night = Any2300-0800|Sa|Su0800-1700 + +The expect/send code now supports: + \s space + \d delay 1 second + \r carriage return with no linefeed + \b break + \c don't send a CR after these characters + \xxx the octal character xxx (e.g. \s == \040 + +L-devices now handles "chat" scripts (like HoneyDanber) to get +through local port selectors and smart modems more easily +without mucking up every line of L.sys. See UUAIDs/L-devices for +details. + +The 'g' protocol code was cleaned up a lot and is now almost +readable. + +If you need a parity other than even (the default) to login to +another system, you can change it in L.sys by putting in a +sequence like "" P_ZERO (expect nothing, send zero parity). + Odd Parity P_ODD + Even Parity P_EVEN + Zero Parity P_ZERO + One Parity P_ONE + +If DONTCOPY is defined in uucp.h, uucp will not make a copy +of the source file by default. (This is the way System 3 does it). + +If an X. request fails, the notification is returned to the +originator of the request instead of "uucp" on the previous +system. + +The man pages are actually accurate! + +If LOGBYSITE is defined, uucp logging is done with +a log file per site instead of one LOGFILE. (Like Honey DanBer does) + +There is a new file (optional) L.aliases that makes life simpler when +a site changes it's name. uucp, uux, uucico, etc all check it so +when a site is renamed (e.g convex <- parsec) all you have to do is add +an entry in L.aliases of the form: +newname oldname + +uucico will not try and resend files it has already sent (when the +files are specified in one C. file) + +Incorporated Bill Sebok's code to dial in and out on the same modem. +NOTE: acucntrl is heavily Vax/4.xbsd specific and will require work to +run on any other system. + +For compatibility with Honey DanBer, in the Date fields of L.sys, + | was changed to , (| is supported, but not encouraged) + , was changed to ; (to allow , to be the date seperator) + +For Honey DanBer compatibility, the Grade flag is now passed as + -vgrade=X instead of the old -pX + +Don't truncate site names to 7 characters (truncate to 14 if +anyone gets that absurd) for HDB compatibility. L.aliases may +be used to map host with longer names in L.sys to 7 character +names that some hosts send. Entries should be + + fullname 7-char-name + +You can specify a time for the expect send sequences with ~ instead +of getting the default MAXMSGTIME. E.g. + system Any ACU 1200 1234567 ogin~20-\r-ogin~10-\b-ogin user password pw +will look for ogin for 20 seconds, send CR, look for ogin for 10 +seconds, send a BREAK and look for ogin for MAXMSGTIME seconds + +Added code to support GTEs PC Pursuit service. It's mainly the handling of the +dialback they use. + +Added time "NonPeak" for Tymnet/Telenet services that charge lower +rates from 6pm-7am M-F and Sat & Sun. diff --git a/src/cmd/uucp/Makefile b/src/cmd/uucp/Makefile new file mode 100644 index 0000000..2ce6e11 --- /dev/null +++ b/src/cmd/uucp/Makefile @@ -0,0 +1,142 @@ +# Makefile 5.11.3 (2.11BSD GTE) 1996/11/17 +# +# LIBS can be set to reference other object modules and libraries needed +# by uucico, such as -lunet (needed when UNET is defined). +# +# Common object files are assembled into a library {uulib.a} +# +TOPSRC = $(shell cd ../../..; pwd) +include $(TOPSRC)/target.mk + +ALL= uucico uucp uux uuxqt uulog uuclean uuname uupoll uusnap \ + uuencode uudecode uusend uuq + +LIBOBJ = logent.o ulockf.o uucpdefs.o subdir.o gename.o assert.o expfile.o \ + chkpth.o cpmv.o uucpname.o getpwinfo.o versys.o xqt.o getargs.o \ + cfgets.o prefix.o lastpart.o getprm.o anyread.o anlwrk.o gnamef.o \ + mailst.o systat.o cntrl.o imsg.o gio.o sysacct.o pk0.o pk1.o \ + conn.o condevs.o chksum.o setline.o gnsys.o + +CC = $(GCCPREFIX)gcc -mips16 -EL -msoft-float -nostdinc -fshort-double -I$(TOPSRC)/include $(INCLUDES) + + + +OWNER= uucp +GROUP= daemon + +CFLAGS += -Os -Werror + +SBINDIR= ${DESTDIR}/usr/sbin +LIBEXECDIR= ${DESTDIR}/usr/libexec +BIN= ${DESTDIR}/usr/bin +PUBDIR= ${DESTDIR}/usr/spool/uucppublic +SPOOL= ${DESTDIR}/usr/spool/uucp +XQTDIR= ${SPOOL}/XTMP +CORRUPT= ${SPOOL}/CORRUPT +AUDIT= ${SPOOL}/AUDIT +LCK= ${SPOOL}/LCK +LOG= ${SPOOL}/LOG +STST= ${SPOOL}/STST +# The six subdirs {not counting XTMP}. +HOSTNAME=`uuname -l | sed 's/\(.......\).*/\1/'` +SUBDIRS=C. D.${HOSTNAME}X D.${HOSTNAME} D. X. TM. + +all: libacu $(ALL) + +libacu: + cd aculib && make + + +uuencode: uuencode.o + ${CC} ${LDFLAGS} -o uuencode.elf uuencode.o ${LIBS} + ${OBJDUMP} -S uuencode.elf > uuencode.dis + ${SIZE} uuencode.elf + ${ELF2AOUT} uuencode.elf $@ + +uudecode: uudecode.o + ${CC} ${LDFLAGS} -o uudecode.elf uudecode.o ${LIBS} + ${OBJDUMP} -S uudecode.elf > uudecode.dis + ${SIZE} uudecode.elf + ${ELF2AOUT} uudecode.elf $@ + +uucp: uucp.o libuucp.a + ${CC} ${LDFLAGS} -o uucp.elf uucp.o -L. -luucp ${LIBS} + ${OBJDUMP} -S uucp.elf > uucp.dis + ${SIZE} uucp.elf + ${ELF2AOUT} uucp.elf $@ + +uux: uux.o libuucp.a + ${CC} ${LDFLAGS} -o uux.elf uux.o -L. -luucp ${LIBS} + ${OBJDUMP} -S uux.elf > uux.dis + ${SIZE} uux.elf + ${ELF2AOUT} uux.elf $@ + +uuxqt: uuxqt.o libuucp.a + ${CC} ${LDFLAGS} -o uuxqt.elf uuxqt.o -L. -luucp ${LIBS} + ${OBJDUMP} -S uuxqt.elf > uuxqt.dis + ${SIZE} uuxqt.elf + ${ELF2AOUT} uuxqt.elf $@ + +uulog: uulog.o libuucp.a + ${CC} ${LDFLAGS} -o uulog.elf uulog.o -L. -luucp ${LIBS} + ${OBJDUMP} -S uulog.elf > uulog.dis + ${SIZE} uulog.elf + ${ELF2AOUT} uulog.elf $@ + +uuclean: uuclean.o libuucp.a + ${CC} ${LDFLAGS} -o uuclean.elf uuclean.o -L. -luucp ${LIBS} + ${OBJDUMP} -S uuclean.elf > uuclean.dis + ${SIZE} uuclean.elf + ${ELF2AOUT} uuclean.elf $@ + +uuname: uuname.o libuucp.a + ${CC} ${LDFLAGS} -o uuname.elf uuname.o -L. -luucp ${LIBS} + ${OBJDUMP} -S uuname.elf > uuname.dis + ${SIZE} uuname.elf + ${ELF2AOUT} uuname.elf $@ + +uupoll: uupoll.o libuucp.a + ${CC} ${LDFLAGS} -o uupoll.elf uupoll.o -L. -luucp ${LIBS} + ${OBJDUMP} -S uupoll.elf > uupoll.dis + ${SIZE} uupoll.elf + ${ELF2AOUT} uupoll.elf $@ + +uusnap: uusnap.o libuucp.a + ${CC} ${LDFLAGS} -o uusnap.elf uusnap.o -L. -luucp ${LIBS} + ${OBJDUMP} -S uusnap.elf > uusnap.dis + ${SIZE} uusnap.elf + ${ELF2AOUT} uusnap.elf $@ + +uusend: uusend.o libuucp.a + ${CC} ${LDFLAGS} -o uusend.elf uusend.o -L. -luucp ${LIBS} + ${OBJDUMP} -S uusend.elf > uusend.dis + ${SIZE} uusend.elf + ${ELF2AOUT} uusend.elf $@ + +uuq: uuq.o libuucp.a + ${CC} ${LDFLAGS} -o uuq.elf uuq.o -L. -luucp ${LIBS} + ${OBJDUMP} -S uuq.elf > uuq.dis + ${SIZE} uuq.elf + ${ELF2AOUT} uuq.elf $@ + +uucico: cico.o libuucp.a + ${CC} ${LDFLAGS} -o uucico.elf cico.o -L. -Laculib -luucp -lacu ${LIBS} + ${OBJDUMP} -S uucico.elf > uucico.dis + ${SIZE} uucico.elf + ${ELF2AOUT} uucico.elf $@ + +libuucp.a: $(LIBOBJ) + $(AR) r libuucp.a $(LIBOBJ) + $(RANLIB) libuucp.a + + + +install: uuencode uuencode + cp $(ALL) $(TOPSRC)/bin + +clean: + rm -f *.o $(ALL) libuucp.a *.dis *.elf + cd aculib; make ${MFLAGS} clean + +depend: + mkdep ${CFLAGS} *.c diff --git a/src/cmd/uucp/README b/src/cmd/uucp/README new file mode 100644 index 0000000..2aff425 --- /dev/null +++ b/src/cmd/uucp/README @@ -0,0 +1,216 @@ +INSTALLATION GUIDE +README 5.6.1 (2.11BSD) 1996/10/23 + +This version is based on the "rti uucp" that was on the 4.2BSD tape. +It contains many additional features and fixes from Usenet, +Tom Truscott, Guy Harris, Lou Salkind, and many others. + +A few new subdirectories have been added. Do a "make mkdirs" to make +sure that you have all of them. + +I recommend that you change the uucp mail handler in your sendmail.cf +to something like: + + # Muucp, P=/usr/bin/uux, F=sDFMhuU, S=13, R=23, M=100000, + # A=uux - -r $h!rmail ($u) + Muucp, P=/usr/bin/uux, F=sDFMmhuU, S=13, R=23, M=100000, + A=uux - -r -z -a$g -gC $h!rmail ($u) + +The -a$g provides a return address in case mail fails (So It +won't go to yourmachine!uucp anymore.) The -gC specifies a grade +for mail. C is a good choice for mail. News should run at 'd'. This +way, mail gets sent before news. The 'm' flag specifies that this +mail can send to multiple addresses, which uux can. + +The man pages now describe all the options for the various commands. +Make sure you read them. A list of the functional differences is in "Changes". + +You should also look through the UUAIDS directory. There are some useful +programs and hints therein. + +The maximum length of a site name has been changed from the old 7 to the +14. This is the be compatible with the HoneyDanBer uucp (aka BNU 1) which +is as close to a standard uucp as there is. Sites which have sitenames +longer than 7 characters that only send you the first 7 characters are +broken and should be fixed. However, there is a way of compensating for +this until they fix their problem. For each site you talk to that has a +name longer that 7 characters, put a line in /etc/uucp/L.aliases of +the form: + fullname name-truncated-to-7-characters. +E.g: + tektronix tektron + lbl-csam lbl-csa + rochester rochest + ut-sally ut-sall +(See UUAIDS/L.aliases for more details on aliasing uucp names.) If the site +name is <= 7 characters, you don't have to do anything. + + +Rick Adams +rick@seismo.ARPA +June 19, 1985 + +Tom Truscott, rti!trt,decvax!duke!trt (919)541-6488 Research Triangle Institute +Bob Gray, gray@berkeley, duke!adiron!bob (315) 336-4989 + +This is a variant of the uucp used at decvax, ittvax, rti, mcnc, adiron, +duke and others. There have been tons of bug fixes and enhancements +from people on the usenet (thank you). Speed is substantially +improved. This version fixes essentially all of the McGeady's bug list. + +Enhancements: + +Dialers Lots of dialers included. + +Subdirectories /usr/spool/uucp is now split into 7 subdirectories. + This is a huge help on busy systems. + +/etc/uucp/L.cmds List of commands permitted for remote execution. + A line of form 'PATH=...' sets the search path. + +expect-send sequence Escape characters now permitted: \r, \n. + \r, not \n, is default char sent at end of string. + \c (put at end of string). Dont send ending \r. + \d pause 1 second (\d\d pauses 2 seconds) + "" P_ZERO `expect nothing, start sending zero parity.' + P_EVEN (default), P_ODD, P_ONE other parity modes. + \05 Send a control-E + "" "" `expect nothing, send a \r'. + +uupoll [sysname] Polls named system. +uusnap Displays spooled files, and pending uuxqts. + + +This version runs on all VAXen and PDPs under UNIX-V7 and 4.1bsd, 4.2BSD. +It also runs on Gould/SEL Concept series machines (e.g. 32/8750), +DUAL 68000 unisoft. +It also runns on BTL system III, IV, and V. + +UUCP installers should read the two papers (by Dave Nowitz) +in Vol 2B of version 7 manuals and UUAIDS/setup.tblms. +Understand each step below before executing. +Some steps will vary slightly from system to system. + +**** INSTALLATION ******* + +1. If you are currently running uucp, save the old programs!: + su root + cd /usr/bin + for i in uucp uux uulog uuname (csh: foreach i (uucp ....) ) + do + cp $i $i.old + done (csh: end ) + cp -p /usr/sbin/uucico /usr/sbin/uucico.old + cp -p /usr/libexec/uuxqt /usr/libexec/uuxqt.old + cp -p /usr/sbin/uuclean /usr/sbin/uuclean.old + +2. Editing Makefile and uucp.h + 4.2 sites using the supported dialers are all set with defaults. + + non-4.2 + a) sites need to install the Berkeley directory reading library. + Try (cd libndir; make install). + Edit Makefile to have LIBNDIR= -lndir + define NDIR in uucp.h. + b) Check LDFLAGS, OWNER, GROUP, and LIBUUCICO. + c) pick a method to allow uucp to know its system: + Check out GETHOSTNAME/UNAME/WHOAMI/CCWHOAMI in uucp.h + d) define SYSIII if appropriate in uucp.h. + e) Your "make" may fail because the Makefile is so large. + If so, in /usr/src/cmds/make/defs, change + '#define NFLEFTS 60' to 512, and re-make make. + +3. Make the new commands. + make + +4. WAIT UNTIL THE UUCP SYSTEM IS IDLE!! Single-user is best. + su root (it is important that chmod, chown and chgrp work below) + +5. Install the new commands: + make install + (If you are chicken, type 'make -n install' first). + +6. Edit and install the control files: + Look in UUAIDS. Edit and install into /etc/uucp if necessary + USERFILE, L.cmds, L.sys, L-devices, L-dialcodes. + THESE FILES MUST BE OWNED BY THE SAME OWNER AND GROUP AS + THE UUCP COMMANDS AND UUCP SPOOL FILES!!! (probably uucp, daemon). + The format for dialers is slightly different so that any dialer + can be handled. + +7. Make new subdirectories: + For safety: cd /usr/spool/uucp; tar c . (save Qed files on tape) + The following assumes your site name is produced by `uuname -l`. + make mkdirs + If your system is duke, then the subdirectories created are + named C., D., D.duke, D.dukeX, TM., XTMP and X.. + rmdir /etc/uucp/.XQTDIR + which is obsolete (XTMP replaces it). + +8. Move old Qed files: + If you have spooled files, they must be moved into the subdirectories. + Assuming all spool files are in /usr/spool/uucp + (i.e. you did not have subdirs before) + the following command will move the spool files + to the right subdirectories: + make mvspoolfiles; ??? does this work now?????????? + Files beginning C. are put in the C. subdirectory, and so on. + Files begining D.dukeX are put in that directory, *not* D.. + (Note: if you already had a subdirectory version of uucp, + you need only create the new subdirectories mentioned above + and move the relevant files there. + Delete other old directories if you had any (e.g. "LOG.") + +9. Compact /usr/spool/uucp: + cd /usr/spool + mkdir nuucp + chown uucp nuucp + chgrp daemon nuucp + for i in uucp/* (csh: foreach i (uucp/*) ) + do + mv $i nuucp + done (csh: end ) + rmdir uucp + mv nuucp uucp + (Note: this does *not* work if a filesystem is mounted on + /usr/spool/uucp! If that is the case, you should 'tar' + /usr/spool/uucp somewhere, unmount, re-mkfs, and re-mount + the filesystem, and tar the uucp files back.) + +10. Test the new system + Test by mailing a letter somewhere and back. + If it works, the new system is probably fine. + Otherwise, figure out what is wrong. + Start by examining LOGFILE. Try /usr/sbin/uucico -r1 -sname -x7 + If things are no-go, you can back out the changes by restoring the + old uu programs and the spooled files. + NOTE: The subdirectories foul up a non-subdir version, + so be sure that subdirectories exist/do not exist as appropriate. + + +11. Install handy UUAIDS + Look in uuaids for handy other stuff. In particular, uu.* are + shell scripts that can be run via cron hourly, daily, and weekly + to keep uucp trim. L-devices, L-dialcodes, L.cmds, L.sys, USERFILE + are sample files. THEY MOST LIKELY NEED TO BE MODIFIED TO USE + THEM ON YOUR OWN SYSTEM! + + uu.hourly Makes sure sites are polled. + uu.daily Runs uuclean to clean up /usr/spool/uucp. + **IT HANDLES SUBDIRECTORIES!! + Renames LOGFILE to LOGFILE.old. + uu.weekly Renames SYSLOG to SYSLOG.old. + The above scripts should be run via cron. + + uucpsummary + Summarizes LOGFILE and SYSLOG. It's very helpful in telling + what is going on and who is calling who. + uucp.daily + Daily shell script run at ittvax. Manages SYSLOG files in + a convenient form for uuusage. Not integrated in time + for this distribution. + + +Comments, bug reports, *and improved code* are welcome. + Tom Truscott + Bob Gray diff --git a/src/cmd/uucp/README.TCP b/src/cmd/uucp/README.TCP new file mode 100644 index 0000000..40a64f7 --- /dev/null +++ b/src/cmd/uucp/README.TCP @@ -0,0 +1,56 @@ +The rest of this file is oriented to updating a vanilla 4.2 system. +As 4.3 comes configured, all you have to do is uncomment the "uucpd" +line in /etc/inetd.conf (and of course update your L.sys as needed). +If you want to turn off logging uucp logins in wtmp, set the "user" +field in inetd.conf to "uucp", who doesn't have write permission on wtmp. + +---------------------------------------------------------------------- +Basically, to run UUCP on top of TCP, the code had to be changed to +not do ioctl's on sockets,etc. Also, a new protocl 't' was added. +This is because the 'g' protocol maxes out at about 9000 baud +regardless of the physical medium. The 't' protocol presumes an +error free channel, and is essentially the 'g' protocol with the +checksumming and packetizing ripped out. + +To install it, make uucp with BSD4_2 defined in uucp.h. + +Add a line in /etc/services that looks like: +uucp 540/tcp uucpd + +Add lines to /etc/rc.local that looks something like: +if [ -f /usr/libexec/uucpd ]; then + /usr/libexec/uucpd & echo -n ' uucpd' >/dev/console +fi + +The L.sys entry should look something like: +uucpname time-to-call TCP port networkname standard uucp login chat + +This is how it would look for rochester. +rochester Any TCP uucp ur-seneca "" uucplogin "" uucppasswd + +UUCP site rochester is arpanet site ur-seneca (and there is a +arpanet site rochester that is a different machine) + +The "port" field is either a word or a number. It is a number, +that number is used as the port. If it is a word, the word is +looked up in /etc/services and the port is taken from there. + +Another example would be: +seismo Any TCP 33 seismo "" uucplogin "" uucppassword + +In almost every case, the networkname field will be the same as the +uucpname field. Similarly, the port field will usually be "uucp", which +says to use the standard uucp port from the services file. + +The daemon expects the incoming site to send its login and password +for authentication. + +If you have any problems feel free to call me: + + Rick Adams + Center for Seismic Studies + 1300 North 17th Street, Suite 1450 + Arlington, VA 22209 + (703) 276-7900 + rick@seismo.ARPA + seismo!rick diff --git a/src/cmd/uucp/README.dialino b/src/cmd/uucp/README.dialino new file mode 100644 index 0000000..d2b23d6 --- /dev/null +++ b/src/cmd/uucp/README.dialino @@ -0,0 +1,28 @@ +We started to use uucp after the dialin lines had been in place for a while. +It would have been very unpopular here to remove one of lines from public use +to let uucp dial out. The first version of these changes ran here early in +1983. + +Having this ability is very useful way to make full use of your modems. For +one thing, I can smile when a neighoring site complains that their one dialer +is tied up from news backed up to one of their neighbors which has been down +for a while and has just come back up. For another thing some of our neighbors +seem to be reachable better by some modems than by others. For example, I can +only reach rocky2 with a Racal Vadic. I can only reach akgua, burl, and +sjuvax with a Hayes. When our 2400 baud modem arrives so I can make special +note of that --- and I don't have to buy two 2400 baud modems to have two-way +2400 baud capability. + +The key to this is a program is provided in the file acucntrl.c . This should +be installed suid to root in the file /usr/libexec/acucntrl . + + +uucp notes: +The 3rd field of the L-devices file should contain "inout" for all devices +intended for dialin/out use. Devices without the "inout" specification will +be used like before: for dialout only. + +Good luck. I want to never go back to reserving modems for dialout. + +Bill Sebok Princeton University, Astrophysics +{allegra,akgua,burl,cbosgd,decvax,ihnp4,noao,princeton,vax135}!astrovax!wls diff --git a/src/cmd/uucp/UUAIDS/L-devices b/src/cmd/uucp/UUAIDS/L-devices new file mode 100644 index 0000000..8c2fa17 --- /dev/null +++ b/src/cmd/uucp/UUAIDS/L-devices @@ -0,0 +1,63 @@ +# The format of the L-devices file is: +# Caller Line Useful Class Dialer [Chat ...] +# +# A line beginning with a # is a comment +# If the last character of a line is \ +# the next line is considered to be a continuation of the first. + +# +# The following lines are hard-wired +# +DIR ttyh3 unused 300 direct +DIR ttyh3 unused 1200 direct + +# +# The following lines are ACUs +# +ACU cul0 cua0 1200 dn11 +ACU cul1 cua1 1200 dn11 +ACU tty49 unused 1200 ventel +ACU tty49 unused 300 ventel +ACU tty48 unused V1200 vadic + +# +# For hayes smartmodems, specify 'hayestone' for touch tone, +# 'hayespulse' for pulse dialing. 'hayes' means 'hayespulse' +# +ACU tty47 unused 1200 hayestone + +# +# The following port is to a Develcon DataSwitch. +# The 'DIR' line is used to talk to other machines on the switch. +# See how it is used in L.sys. +# The 'ACU' line is used to talk to a call-out modem on the switch. +# In this case the modem is a hayes. The 'chat' script +# makes the connection to the modem so the normal hayes modem code +# in condevs.c can be used. Here the chat script +# 'expects nothing', 'sends a return', 'expects uest:' +# (the DataSwitch's prompt), 'sends outmodem', +# and expects control-g (the DataSwitch's connection prompt). +# Note, it is a current nit that the control-g has to be typed as is +# rather than as ^g or as \07. Sorry. +# +DIR tty50 unused 9600 direct +ACU tty50 unused 1200 hayespulse "" "" uest: outmodem  +# +# +# PC Pursuit line +# +# callback_modem is the device that you have connected to +# callback_number. callback_number is the phone number of your +# modem that PCPursuit will call back on. +# their_phone is the number of PC Pursuits computer +# my_baud is the baudrate to call them at (it is assumed the +# callback will be at the same rate) +# my_modem_type is the brand of modem you are using on the +# callback number. This is used to hang up the modem in case of +# error. +# +# Currently, the outgoing call is made on an available ACU. +# +# PCP callback_modem their_phone my_baud my_modem_type my_callback_number +PCP tty07 6592863 1200 hayes 5281234 +PCP tty07 6592881 1200 hayes 5281234 diff --git a/src/cmd/uucp/UUAIDS/L-dialcodes b/src/cmd/uucp/UUAIDS/L-dialcodes new file mode 100644 index 0000000..011a37c --- /dev/null +++ b/src/cmd/uucp/UUAIDS/L-dialcodes @@ -0,0 +1,15 @@ +# This is basically used for string matching +# You do not need to use it. Some sites prefer +# to put "chicago2486706" in their L.sys instead of +# "13122486707" +# +# +# A line beginning with a # is a comment +# If the last character of a line is \ +# the next line is considered to be a continuation of the first. +# +# Example L-dialcodes +# +chicago 1312 +dc 1202 +sandiego 1714 diff --git a/src/cmd/uucp/UUAIDS/L.aliases b/src/cmd/uucp/UUAIDS/L.aliases new file mode 100644 index 0000000..112c30b --- /dev/null +++ b/src/cmd/uucp/UUAIDS/L.aliases @@ -0,0 +1,19 @@ +# +# This is useful when a site changes its uucp name. +# the file format is "newname" space "oldname" +kobold helios +ucadmus cadmus +decuac grendel +# +# it is also useful when dealing with sites that are not properly sending +# you their full sitename +# +ut-sally ut-sall +nbs-amrf nbs-amr +turtlevax turtlev +cal-unix cal-uni +prometheus prometh +lbl-csam lbl-csa +rochester rochest +# +# here, as in all the other L files, a line beginning with # is a comment diff --git a/src/cmd/uucp/UUAIDS/L.cmds b/src/cmd/uucp/UUAIDS/L.cmds new file mode 100644 index 0000000..b8894bb --- /dev/null +++ b/src/cmd/uucp/UUAIDS/L.cmds @@ -0,0 +1,25 @@ +# This is the list of commands that uuxqt will execute. +# +# A line beginning with a # is a comment +# If the last character of a line is \ +# the next line is considered to be a continuation of the first. +# +# A line of from PATH=... changes the path used to locate the commands. +# +# Example L.cmds +# +PATH=/bin:/usr/bin:/usr/ucb +# If there is a suffix of ,Error, a message will only be returned if +# the exit status is non-zero. If there is a suffix on ,No, there +# will never be a return message from uuxqt. +rmail +# Only return the status of a rnews if it is non-zero +rnews,Error +ruusend +# Never return the status of an nfrcv +nfrcv,No +# These next programs are security holes, but noone seems to care +lpr +who +uusend +finger diff --git a/src/cmd/uucp/UUAIDS/L.sys b/src/cmd/uucp/UUAIDS/L.sys new file mode 100644 index 0000000..c7e2d90 --- /dev/null +++ b/src/cmd/uucp/UUAIDS/L.sys @@ -0,0 +1,121 @@ +# This file contains the majority of the information used to call +# the destination system. It should not be readable to the world, as +# there are logins and passwords stored here +# +# A line beginning with a # is a comment +# If the last character of a line is \ +# the next line is considered to be a continuation of the first. +# +# If the time is suffixed with ";N", then N is used as the retry time +# insterad of the default. E.g. Any;1 or Evening;60 +# +# If the time is suffixed with "/X", then only files of grade X or +# lower will be sent during this time period. +# Multiple grades may be used in conjunction with the ",". E.g. +# Any/C,Evening/a,Night +# which send grades C and lower anytime, grades a and lower in the Evening +# and everything at Night +# +# The time may be any of the following: +# Any Anytime +# Evening When Evening rates are in effect +# NonPeak Tymnet/Telenets non-peak rates +# Night When Nighttime Phone rates are in effect +# Wk Any Week Day +# Mo Mondays +# Tu Tuesdays +# We Wednesdays +# Th Thursdays +# Fr Fridays +# Sa Saturdays +# Su Sundays +# These time may be suffixed with a time range nnnn-mmmm in thge 24 hour clock +# E.g. +# Evening = Wk1700-0800,Sa,Su +# NonPeak = Wk1800-0700,Sa,Su +# Night = Any2300-0800,Sa,Su0800-1700 +# Wk = Mo,Tu,We,Th,Fr +# +# If the expect part of the expect/send sequence is suffixed with a ~number, +# then that number will be used for the timeout instead of the default +# MAXMSGTIME, which is delivered as 45 seconds. +# E.g. ogin~10-\r-ogin~15-\b-ogin +# will look for ogin for 10 seconds and if it doesn't find it, send a CR +# then look for ogin for 15 seconds and if it doesn't fint it send a break +# then look for ogin for MAXMSTIME seconds then exit +# +# +# Example L.sys file +# +# The following entry indicates that system 'mcnc' can be called any time, +# and is accessible over a hard-wired tty line (tty01) at 4800 baud. +# The login sequence is: +# "" expect nothing (sort of a kludge) +# "" send carriage return +# ogin:--ogin: look for 'login:', if not received send carriage return +# and look again. +# Urti login as Urti +# ssword: look for Password: +# fatchance supply the password. +# +mcnc Any DIR 4800 tty01 "" "" ogin:--ogin:--ogin: Urti ssword: fatchance +# +# The following entry shows that the machine 'rti-sel' can be called any time +# via /dev/tty02 at 300 baud. The send-expect sequence is complex +# because it is operating a Racal-Vadic auto-dialer. An easier method would +# be to use the code supplied for a Vadic auto-dialer. See the Notes.L.sys +# and L-devices files. +# This is an unusual use of send-expect, but shows its capabilities. +# "" expect nothing +# \05 send ^E return (activate auto-dialer) +# *~2-\05-*~2 look for *, wait 2 seconds, if no such reactivate +# dialer, and look again for 2 seconds +# d send 'd' to enter a phone number +# NUMBER?~3-d... look for prompt from auto-dialer +# 7654321\r\d send number, then return, then pause, then return +# LINE wait for modem to say 'ON LINE' +# \r\d\r send return, pause, then send return again +# ogin:-\b-... look for login, if not found send a 'break' +# look again, if still not found send another 'break' +# and look one more time before giving up. +# +rti-sel Any ttyh3 300 ttyh3 "" \05 *~2-\05~2-* d NUMBER?~3-d-NUMBER?~3 7654321\r\d LINE \r\d\r ogin:-\b-ogin:-\b-ogin: Urti ssword: fatchance +# +# The next entry is for a normal ACU. uucp normally handles only a DN11. +# However, the 'condevs.c' routine can be modified to handle any kind +# of auto-dialer desired. (This is, however, an awful part of uucp.) +# Calls can be placed any day but only between 11pm and 8am. +# The connection is 300 baud. +# +rti-sel Any2300-0800 ACU 300 13057654321 ogin:--ogin: Urti ssword: fatchance +# +# The next entry is for a 4.2BSD TCP-IP connection. +# There must be a #define BSDTCP in uucp.h, and you must install +# a 'uucpd' uucico server daemon in /usr/libexec. +# Also, add an entry to /etc/services, such as: +# uucp 540/tcp uucpd +# The '540' is the port number chosen for uucpd. + +# The fields are: remote uucpname, time-to-call, TCP, portnumber, networkname. +# Sane installations will have identical uucp and networknames. However, +# arpanet machines will probably have to add their domain. Make sure that +# the network name (in this case seismo.CSS.GOV) is the entry returned for +# the sites hostname by gethostbyaddr(). An alias will not (always) work. +# This is mandatory if you are running the domain name server. +# +seismo Any TCP uucp seismo.CSS.GOV ogin: uucplogin ssword: uucppassword +# +# If ncsu cannot be raised by the method above, use the ACU. +# uucico tries each entry for ncsu in turn, until one of them connects. +# Calls on the ACU are only permitted when phone rates are cheap. +# Send grade Z or lower in the evening and if you fail retry as +# fast as 1 minute. send everything else at night. +# +ncsu Evening/Z;1,Night ACU unused 987-6543 ogin:--ogin: Urti ssword: fatchance +# +# Connect to ihnp4 using PC Pursuit +# +# chicago is the PCPursuit City name. +# 6907171 is the phone number for ihnp4 +# +ihnp4 NonPeak PCP chicago 6907171 "" \d@ ogin:~5-BREAK-ogin:~5-\r-ogin: UULOGIN ssword: PASWORD diff --git a/src/cmd/uucp/UUAIDS/Notes.L.sys b/src/cmd/uucp/UUAIDS/Notes.L.sys new file mode 100644 index 0000000..2ad84b1 --- /dev/null +++ b/src/cmd/uucp/UUAIDS/Notes.L.sys @@ -0,0 +1,84 @@ +This file describes the layout of the L.sys and L-devices files. + +Here's my interpretation of L.sys: + Site When Caller Class CallCode Login + +The nominal value for Caller is ACU, but it can be the code for any +device that places calls, e.g., micom, datakit, ethernet, etc. The +CallCode field contains the dope needed by the caller to complete the +connection, e.g., for an ACU, CallCode is the phone number, while for, +say, a micom, CallCode is the micom code for Site. Class is nominally +speed, but circumstances sometimes make it necessary to encode other +information here. E.g., at Bell Labs many sites distinguish centrex and +dimension. Some use it to identify sites that answer vadic only. + +For ACU Callers, this is the old interpretation. Some examples: + lento Any ACU D1200 MHd7464 ... + lento Any ACU C1200 MH2057 ... + lento Any MICOM 9600 lento ... + lento Any DK unused mh/tempo/lento ... + lento Any UNET lento 33 ... + lento Any DIR 9600 tty42 ... + lento Any DIR 2400 tty43 ... + +i.e., to get to lento, dial on an ACU, or open a micom port and whisper +"lento" down it, or open a datakit port and shout "mh/tempo/lento" down +it, or open Unet server 33 on Unet host 'lento', or call on tty42. + +Here's my interpretation of L-devices: + Caller Line Useful Class Dialer + +Caller and Class are as above. Line identifies the device on which the +call is placed. The Useful field is a place to identify something else +needed to dial, e.g., the name of a dialing device, or a code to get +past a sentry. The (new) Dialer field identifies the type of dialer +being used so that the right dialing function can be called. Some examples: + + ACU cul0 cua0 1200 dn11 + ACU cul1 cua1 1200 dn11 + ACU tty49 unused 1200 ventel + ACU tty49 unused 300 ventel + ACU tty48 unused V1200 vadic + ACU tty47 unused 1200 hayes + ACU tty47 unused 300 hayes + MICOM micom unused 9600 micom + DIR tty42 unused 9600 direct + +If you wish to add another dialer/caller type, you must add a line to the +condevs structure definded in condevs.c. There is a line in the condevs +table for each device type listed in the L-devices file. The condev structure +looks like: + struct condev { + char *CU_meth; /* method, such as "ACU" or "DIR" */ + char *CU_brand; /* brand, such as "vadic" or "ventel" */ + int (*CU_gen)(); /* what to call to search for brands */ + int (*CU_open)(); /* what to call to open brand */ + int (*CU_clos)(); /* what to call to close brand */ + } condevs[]; + +The line for the Ventel might look like: + { "ACU", "ventel", Acuopn, ventopn, ventcls }, +While the line for the UNET interface might look like: + { "UNET", "unet", unetopn, nulldev, unetcls }, + +There can be many 'brands' of the same kind of device, such as auto-dialers. +The condevs array is searched for a method that matches the one in the L.sys +file. The string comparison is done without regard to case, so "Acu" will +match "ACU". Once a match is found, the routine pointed to by CU_gen is +called. It is passed a pointer to the flds array, the array of pointers to +strings derived from the L.sys entry. + +Typically, the CU_gen vector goes through the L-device table looking for +a entry that is available, then trys to connect on that brand via the +CU_open vector. If that fails, it might go on to the next brand. +When it succeeds in opening a line, it should assign the brand closing +vector (CU_clos) to the global symbol CU_end (i.e. CU_end = cd->CU_clos). +The routine pointed to by CU_end is called when the line is to be shutdown. +It is passed a file descriptor which it is to close. + +Another ACU can be added by writing the code for the CU_open and CU_clos +and adding a line in the condevs[] table. The routine pointed to by +CU_open is passed a pointer to the phone number; a pointer to the flds array; +and a pointer to the dev structure, which contains the information from the +L-devices entry. It should return a file descriptor that can be used to +communicate with the other machine, or CF_DIAL if the connection was not made. diff --git a/src/cmd/uucp/UUAIDS/USERFILE b/src/cmd/uucp/UUAIDS/USERFILE new file mode 100644 index 0000000..b3f677d --- /dev/null +++ b/src/cmd/uucp/UUAIDS/USERFILE @@ -0,0 +1,12 @@ +# Example USERFILE +# Lines are of form 'loginname,uucpname fileprefix[, ...] +# It is recommended that each site have a unique login name and password. +# fileprefix is typically / or /usr/spool/uucppublic. +# +Umcnc,mcnc / +Uillia,illia / +# This last line is recommended to reduce aggravation. +# Security minded sites woulr probably use: +# , /usr/spool +# instead +, / diff --git a/src/cmd/uucp/UUAIDS/setup.tblms b/src/cmd/uucp/UUAIDS/setup.tblms new file mode 100644 index 0000000..83f7690 --- /dev/null +++ b/src/cmd/uucp/UUAIDS/setup.tblms @@ -0,0 +1,269 @@ +.TL +Setting up the Net +.AU +Tom Truscott +.AI +Duke University +(now at the Research Triangle Institute, NC) +January 1980 +(revised 1983 to better reflect reality) +.SH +Installing files and Programs. +.PP +This paper describes how to get the system named "xyz" on the uucp net. +If you are on the net, stop reading! +In chosing your system name, keep it short (no more than 7 characters long) +and make it specific. +That is, 'physics' is a poor uucp name! +The University of California at Berkeley names their machines +ucbvax, ucbcad, ucbmone, etc. +A standard Seventh Edition +.UX +system is assumed. +[Yup, this is ancient! I have deleted useless paragraphs -- trt] +The v7 C compiler MUST be used to recompile uucp; +the Phototypesetter version fails. +It is necessary to compile and install the mail, uucp, and news programs. +In what follows, "/bin/..." can be replaced by "/usr/bin/...". +.SH +MAIL +.PP +Ignore this section if you machine already has a network +mail program in place. +First, you must tell your machine its name. +Modern versions of UNIX use gethostname(II) or uname(II). +Ancient versions use include files. +If you are in the dark ages, edit /usr/include/whoami.h +and change the system name to xyz. +Do the same to /usr/include/ident.h +(not currently used, by the way). +Then recompile mail: +.DS +cd /usr/src/cmd +cmake mail +.DE +and copy it to /bin. +It should be setuid to root. +The network uses a restricted version of mail, +which is actually mail but invoked with a different name: +.DS +ln /bin/mail /bin/rmail +.DE +Mail should now be ready for the net. +A newer version of mail, called Mail, should be used if you have it. +It invokes a mail delivery program called delivermail +or the newer one called sendmail. +.SH +UUCP +.PP +Read the documents on uucp and uucp implementation in the +.I +.UX +Programmer's Manual. +.R +Also read the manual pages for uucp and uux. +.NH 1 +Getting ready to install uucp +.PP +Edit /etc/passwd to add the user "uucp" to your system. +Uucp should have unique user and group ids (for security). +Duke's uucp and daemon have the same group id, +so they can both access /dev/dn? +which is not accessible by "others." +Uucp will own the directories and other files of the uucp system. +Actually, it is nice to also add the user "UUCP" as a synonym for "uucp", +and put "UUCP" earlier in /etc/passwd. +That way uucp will identified as UUCP in mail messages, etc., +which highlights the fact that the messages are machine generated. +Here are typical lines: +.DS L +UUCP:iPkI/ZUX3YX2Y:4:19::/usr/spool/uucppublic:/usr/sbin/uucico +uucp:iPkI/ZUX3YX2Y:4:19::/usr/spool/uucppublic:/usr/sbin/uucico +.DE +.NH 1 +Installing uucp programs +.PP +To install uucp, read the INSTALL file in the uucp directory +and follow the instructions. +It references other documentation, which should also be read. +.NH 1 +Files in /etc/uucp +.PP +All of these files should have the uid and gid of uucp, +and should not be readable (or writable) by others. +The files "L-devices" and "L-dialcodes" +are needed only if xyz calls other systems. +The file formats are described in the documentation +and are straightforward. +The USERFILE file should have one line for each system which calls xyz: +.DS +Uduke,duke /usr/spool/uucppublic +,xyz / +.DE +The first line of the sample USERFILE indicates +that the duke system uses login name Uduke +and can access the public directory. +Here is a typical "Uduke" line in /etc/passwd: +.DS L +Uduke:PSB8EZ5w2tQ4I:4:19::/usr/spool/uucppublic:/usr/sbin/uucico +.DE +This line differs from that for uucp +only in having a different login name and password. +The last line of USERFILE should be ",xyz /", +which permits local users but not remote systems +to access anything on xyz. +[Actually, USERFILE is a real botch. If you want security, +never given anyone permission from '/'.] +.PP +The file L.sys has a line for each system +with which xyz communicates. +If xyz DOES NOT place calls to Duke +then the L.sys line for Duke might be: +.DS +duke None ACU 300 123-4567 ogin Uxyz ssword fooha +.DE +This line indicates that xyz should never ("None") call Duke. +If xyz DOES place calls to Duke +then the line must be altered to so indicate. +The documentation explains that case fairly well. +.NH 1 +Getting it running +.PP +Uucp is now ready for execution. +If Duke is to call xyz, +the xyz system can request that Duke send mail +to test its operation. +/usr/spool/uucp/LOGFILE, SYSLOG, and ERRLOG +are useful logs of uucp activity. +If uucp does not work, and the problems cannot be resolved, +xyz could give Duke another login on xyz +so someone here can poke around +and see what the problem might be. +The login should have the same uid and gid as uucp +but without a uucico "shell". +.PP +If xyz can place calls to another system, +a good test is to try to place the call. +Suppose xyz has both a call-out and a call-in line. +Then an entry for the mythical system "foo" +can be put in the L.sys and USERFILE files, +and xyz can call itself as follows: +.DS +echo "test 1" | mail foo!root +echo "test 2" | mail foo!xyz!root +echo "test 3" | mail foo!foo!root +.DE +Mail sent from system xyz to itself +causes a local invocation of mail. +Mail sent to the mythical system "foo" will, +however, place a call to send the mail. +Uucp will complain about locking, +and shell metacharacters may not work, +but the communication should still succeed. +Even if xyz has only a call-in or call-out unit +it may be possible to fake the other one +by putting a null modem between the two lines. +[Unfortunately, the newest version of uucp +botches loop testing fairly badly. +But you can observe it successful connect.] +.PP +Also helpful is use of the "-x" debugging option. +The debugging information produced by +this blatant security hole +is truly a wonder to behold. +When it is in effect, the /usr/spool/uucp/AUDIT +file at the remote end will also collect debugging information. +.NH 1 +Cleaning up after uucp +.PP +Uucp will run okay without any cleanup; +however, the uucp files can become immense. +Duke runs several shell files via cron(8). +These are in uuaids/uu.*. +Systems which call Duke should run the following script occasionally: +.DS +/usr/sbin/uucico -r1 -sduke +.DE +Systems which call-out can +request uucp to transmit waiting files: +.DS +/usr/sbin/uucico -r1 +.DE +The standard version of cron runs with uid "daemon" +which may not be able to run the cleanup or uucico scripts. +The scripts could be run via at(1), +or you could remove the "setuid(1);" at the start of cron. +Then cron gives superuser privileges to its children. +As a precaution, we run a program +which does a setuid to uucp before invoking the scripts. +.NH 1 +Obscure problems that can happen +.PP +When uucp logs in, it is greeted (in standard V7 systems) +with the message of the day, "you have mail.", and so forth. +Sometimes these messages cause uucp to fail. +One cure is for login to suppress the messages +when the user has a non-standard shell (e.g. uucico). +.PP +If you have implemented your own tty handler, +be sure it supports 8 bit RAW input and output. +You should compare your own handler +with that of the standard tty.c, +and make sure the RAW mode execution is the same. +[This version does not yet support 7 bit datapath.] +.SH +USING THE NET +.PP +The simplest and least error-prone use of the net +is that of sending mail from one system to another. +A user on xyz can send a letter to Duke as follows: +.DS +echo "xyz lives" | mail duke!root +.DE +A letter can be sent to unc as follows: +.DS +echo "xyz lives on" | mail duke!unc!root +.DE +Here are some local network enthusiasts: +[I only kept this around for historical interest.] +.TS +l l l. +duke!swd Steve Daniel C version of news +duke!jte duke system administrator +duke!trt Tom Truscott network enthusiast +duke!unc!smb Steve Bellovin network news architecture +duke!phs!dennis Dennis Rockwell V6/PWB UNIX enthusiast +.TE +.PP +Uucp provides a convenient way +to transfer files between systems. +Files may be transferred by mailing them, +but that can get annoying. +Here are some hints for using uucp. +.IP 1. +By convention, the name "~uucp" may be used to access +the public directory on any system. +Thus, +.ti +5 +uucp -m -d x.c duke!~uucp/xyz/ +.br +copies the file x.c to the subdirectory xyz +of Duke's public directory (/usr/spool/uucppublic). +The "-m" option requests that mail be sent when x.c is transmitted. +The "-d" option requests that the remote system +create any directories that are needed +(in this case, the subdirectory xyz). +The final "/" in ".../xyz/" +informs uucp that xyz is a directory and not an ordinary file. +.IP 2. +uucp -d -m x.c duke!unc!~uucp/xyz/ +.br +will not work since uucp cannot handle "duke!unc!". +Uucp and uux work only between two systems; +they do not handle a system-pathname sequence as does mail. +[See uusend for a uucp-like multi-hop copy program.] +.SH +NEWS +.PP +You are not running the distributed bulletin board?! +Poor innocent. Don't start. You can never go back. diff --git a/src/cmd/uucp/UUAIDS/uu.daily b/src/cmd/uucp/UUAIDS/uu.daily new file mode 100644 index 0000000..f954603 --- /dev/null +++ b/src/cmd/uucp/UUAIDS/uu.daily @@ -0,0 +1,33 @@ +: Daily uucp script +: assumes you have subdirectories. +: If you do not have them, delete the '-d....' options below. +: someone should use shell variables to do this +: Much better to have subdirectories, however. +PATH=/bin:/usr/bin:/usr/sbin:/usr/ucb +# +umask 2 +deadtime=`expr 24 \* 7` +( +uuclean -pLTMP. -n24 +uuclean -p/usr/spool/uucp/STST -n24 +uuclean -d/usr/spool/uucp/AUDIT -n48 +uuclean -d/usr/spool/uucp/TM. -pTM. -n24 +uuclean -d/usr/spool/uucp/XTMP -n24 +uuclean -d/usr/spool/uucp/X. -pX. -n$deadtime +uuclean -d/usr/spool/uucp/C. -pC. -n$deadtime +uuclean -d/usr/spool/uucp/D. -pD. -n$deadtime +uuclean -d/usr/spool/uucp/D.`uuname -l` -pD. -n$deadtime +uuclean -d/usr/spool/uucp/D.`uuname -l`X -pD. -n$deadtime +) >/dev/null 2>&1 + +/etc/uucp/uucpsummary | /usr/ucb/Mail -s "UUCP Summary" uucplist +cd /usr/spool/uucp +# +# Ma Bell's uudemon.day saves a week's worth of log file information; +# obviously, the site that came up with that never ran netnews. +# +mv LOGFILE Log-DAY +mv SYSLOG Syslog-DAY +# remove old junk from our public directory +cd /usr/spool/uucppublic +find . -type f -mtime +30 -exec rm -f {} \; diff --git a/src/cmd/uucp/UUAIDS/uu.daily.seism b/src/cmd/uucp/UUAIDS/uu.daily.seism new file mode 100644 index 0000000..4c08f17 --- /dev/null +++ b/src/cmd/uucp/UUAIDS/uu.daily.seism @@ -0,0 +1,36 @@ +PATH=/bin:/usr/sbin:/usr/bin:/usr/ucb +# +umask 2 +# give them 7 days to get through +deadtime=`expr 24 \* 7` +( +uuclean -d/usr/spool/uucp/LCK -n24 +uuclean -d/usr/spool/uucp/STST -n24 +uuclean -d/usr/spool/uucp/AUDIT -n48 +rm -f /usr/spool/uucp/AUDIT/[0-9]* +uuclean -d/usr/spool/uucp/TM. -pTM. -n24 +uuclean -d/usr/spool/uucp/XTMP -n24 +uuclean -d/usr/spool/uucp/X. -pX. -n$deadtime +uuclean -d/usr/spool/uucp/C. -pC. -n$deadtime +uuclean -d/usr/spool/uucp/D. -pD. -n$deadtime +uuclean -d/usr/spool/uucp/D.`uuname -l` -pD. -n$deadtime +uuclean -d/usr/spool/uucp/D.`uuname -l`X -pD. -n$deadtime +) >/dev/null 2>&1 + +cd /usr/spool/uucp +/etc/uucp/uucpsummary | /usr/ucb/Mail -s "UUCP Summary" uucplist + +cd /usr/spool/uucp/LOG +for i in uucico uux uuxqt uucp xferstats +do + cd $i + for j in * + do + mv $j .$j + done + cd .. +done +find . -type f -mtime +7 -exec rm -f {} \; + +cd /usr/spool/uucppublic +find . -type f -mtime +30 -exec rm -f {} \; diff --git a/src/cmd/uucp/UUAIDS/uu.hourly b/src/cmd/uucp/UUAIDS/uu.hourly new file mode 100644 index 0000000..6cbc05a --- /dev/null +++ b/src/cmd/uucp/UUAIDS/uu.hourly @@ -0,0 +1,10 @@ +: Hourly uucp script + +: uulog; : uulog no longer needed + +: hourly poll of certain sites +: /usr/sbin/uucico -r1 -smcnc +: /usr/sbin/uucico -r1 -sillia + +: attempt to ship remaining files +/usr/sbin/uucico -r1 diff --git a/src/cmd/uucp/UUAIDS/uu.weekly b/src/cmd/uucp/UUAIDS/uu.weekly new file mode 100644 index 0000000..6776de6 --- /dev/null +++ b/src/cmd/uucp/UUAIDS/uu.weekly @@ -0,0 +1,4 @@ +: Weekly uucp script + +SPOOL=/usr/spool/uucp +mv $SPOOL/SYSLOG $SPOOL/SYSLOG.old diff --git a/src/cmd/uucp/UUAIDS/uucp.daily b/src/cmd/uucp/UUAIDS/uucp.daily new file mode 100644 index 0000000..77a5278 --- /dev/null +++ b/src/cmd/uucp/UUAIDS/uucp.daily @@ -0,0 +1,89 @@ +#!/bin/sh +: '/********************************************************************* + uucp.daily + + Sccsid=@(#)uucp.daily 1.1.1 (2.11BSD) 1996/10/25 + + usage: + Called from cron in the wee early hours of the morning + + arguments: + none. + + history: + long time ago original version + 07/02/82 revisions to month change handling + *********************************************************************/' + +: 'daily UUCP cleanup' +: 'called in the morning' + +spool=/usr/spool/uucp +olddir="$spool/OLD" +PATH="/usr/new:/usr/ucb:/usr/local:/bin:/usr/bin" ; export PATH + +/usr/bin/uulog +/usr/sbin/uuclean -m -p LCK. -p X. -p D. -p C. -p TM. +/usr/sbin/uuclean -p STST. -n 12 + +set `date` +day=$1 +month=$2 +daymon=$3 + +: '************************************************************ + Old spool/log files are kept by the naming scheme: + LOGFILE.${day}${daymon} where ${day} is the day of + the week (Sun-Sat), and ${daymon} is the numerical + day of the month. SYSLOG files are kept by the scheme: + SYSLOG.week: the current weeks: totals; SYSLOG.month: + the current months totals; SYSLOG.${month} where + ${month} is the first three letters of the month: the + totals for that month. + ************************************************************' +cd $spool +mv LOGFILE $olddir/LOGFILE.${day}${daymon} +mv SYSLOG SYSLOG.$$ +cat SYSLOG.$$ >>$olddir/SYSLOG.week +rm -f SYSLOG.$$ + +: 'clean up UUCP logfiles' +cd $olddir + +: 'save the current SYSLOG in a monthly summary + each Monday. + ' +case $day in +Mon) cat SYSLOG.week >>SYSLOG.month + rm -f SYSLOG.week + ;; +esac + +: 'Create monthly name file if necessary' +if [ ! -f logmonth ] +then + echo $month >logmonth + curmonth=$month +else + curmonth=`cat logmonth` +fi + +: 'If the month has wrapped around, save the monthly + summary by the name of the month + ' +if [ $month != $curmonth ] +then + if [ -f SYSLOG.week ] + then + cat SYSLOG.week >>SYSLOG.month + rm -f SYSLOG.week + fi + mv SYSLOG.month SYSLOG.$curmonth + echo $month >logmonth + uuusage $curmonth >UUUSAGE.${curmonth} +fi + +: 'Remove LOGFILEs older than three days; save SYSLOG + files forever (remove manually) + ' +find . -name 'LOGFILE.*' -mtime +3 -exec rm -f {} \; diff --git a/src/cmd/uucp/UUAIDS/uucpsrv.c b/src/cmd/uucp/UUAIDS/uucpsrv.c new file mode 100644 index 0000000..d22ffe1 --- /dev/null +++ b/src/cmd/uucp/UUAIDS/uucpsrv.c @@ -0,0 +1,41 @@ +/* + * UNET (3Com) TCP-IP server for uucico. + * uucico's UNET channel causes this server to be run at the remote end. + * An argument, if present, is the local port number. + * This server does a tcpopen(III) to establish the connection, + * renames file descriptors 0,1, and 2 to be the UNET connection, + * and then exec(II)s uucico. + */ + +#include +#include +#include + +/* Default port of uucico server */ +#define DFLTPORT 33 + +main(argc, argv) +int argc; +char **argv; +{ + register int lport, fd; + register FILE *fp; + extern int errno; + + lport = DFLTPORT; + if (argc >= 2) + lport = atoi(argv[1]); + if (lport <= 0 || lport > 255) + lport = DFLTPORT; + + fd = tcpopen((char *)0, 0, lport, TO_PASSIVE, "rw"); + if (fd == -1) { + perror("uucico server: tcpopen"); + exit(1); + } + close(0); close(1); + dup(fd); dup(fd); + execl("/usr/sbin/uucico", "uucico", (char *)0); + perror("uucico server: execl"); + exit(1); +} diff --git a/src/cmd/uucp/UUAIDS/uucpsummary b/src/cmd/uucp/UUAIDS/uucpsummary new file mode 100644 index 0000000..167c5c3 --- /dev/null +++ b/src/cmd/uucp/UUAIDS/uucpsummary @@ -0,0 +1,240 @@ +#!/bin/sh +PATH=:/bin:/usr/bin:/usr/ucb +export PATH +rm -f /tmp/cmds /tmp/callsto /tmp/callsfrom /tmp/inuse /tmp/outuse +touch /tmp/cmds /tmp/inuse /tmp/outuse +cd /usr/spool/uucp +if [ $# -gt 0 ] +then + what="$1/uucico/* $1/uux*/* $1/xferstats/*" +else + if [ -f LOGFILE ] + then + what="LOGFILE SYSLOG" + else + what="LOG/uucico/* LOG/uux*/* LOG/xferstats/*" + fi +fi +sed -e "s/PATH=.*PATH;// +/REQUEST/d" $what | +/bin/awk ' +BEGIN { fmon = fday = ftime = 99 + lmon = lday = ltime = 0 } +$4 ~ /SUCCEEDED|OK/ { + t = substr($3,index($3,"-")+1,5) + split(t,time,":") + if($5 !~ /conversation/) { + startup[$2] = time[1]*60+time[2] + date[$2] = substr($3, 2, index($3,"-")-2) + } +} +$4 ~ /FAILED|CAUGHT|OK|TIMEOUT/ { + if(startup[$2] == 0 || $5 ~ /startup/) + continue + t = substr($3,index($3,"-")+1,5) + split(t,time,":") + elapsed = time[1]*60+time[2] - startup[$2] + if (elapsed < 0 ) + elapsed += 24*60 + if (elapsed == 0) + elapsed = 1 + if(callto[$2] ){ + totcallto[$2] += elapsed + numcallto[$2]++ + printf("%s\t%s\t%02d:%02d - %02d:%02d\n",$2,date[$2],startup[$2]/60,startup[$2]%60,time[1],time[2])>>"/tmp/callsto" + }else{ + totcallby[$2] += elapsed + numcallby[$2]++ + printf("%s\t%s\t%02d:%02d - %02d:%02d\n",$2,date[$2],startup[$2]/60,startup[$2]%60,time[1],time[2])>>"/tmp/callsfrom" + } + callto[$2] = 0 + startup[$2] = 0 +} +$4 ~ /SUCCEEDED/{ + if ($5 ~ /call/) + callto[$2]++ +} +$4 ~ /FAILED|CAUGHT/{ + if ($5 ~ /call|conversation|SIGNAL/ ) + failed[$2]++ +} +$5 ~ /sent/{ + sentbytes[$2] += $7 + sentfiles[$2] ++ + seconds[$2] += $9 + retries[$2] += $11 + havout = 1 + outuse[$1] = $1 + outusebytes[$1] += $7 + outusefiles[$1] ++ + outusesecs[$1] += $9 +} +$5 ~ /received/{ + recbytes[$2] += $7 + recfiles[$2] ++ + seconds[$2] += $9 + retries[$2] += $11 + havin = 1 + inuse[$2 "!" $1] = $2 "!" $1 + inusebytes[$2 "!" $1] += $7 + inusefiles[$2 "!" $1] ++ + inusesecs[$2 "!" $1] += $9 +} +$5 ~/XQT/{ + if( $7 ~ /!|@/ && $6 ~ /rmail/) + printf("%s\t%s\t%-8s\t%s\n",substr($3,2,index($3,"-")-2),substr($3,index($3,"-")+1,5),$2 "!" $4,$7)>>"/tmp/cmds" +} +$4 ~/XQT/{ + if ($1 ~ /uucp|daemon|root|news/ || $7 != "rmail") + continue + printf("%s\t%s\t%-8s\t%s!%s\n",substr($3,2,index($3,"-")-2),substr($3,index($3,"-")+1,5),$1,$2,$7)>>"/tmp/cmds" +} +$10 ~/secs/ { + curtime = substr($4, 5, 6) + dtmp = curtime - int($9) - lasttime[$2] + if (dtmp > 0 && dtmp < 20) + dead[$2] += dtmp + lasttime[$2] = curtime + live[$2] += $9 +} +{ + n = index ($3, "/") + thismon = 0 + if (n > 0 ) { + thismon = int(substr($3, 2, n-2)) + if (lmon < thismon) + lmon = thismon + if (thismon < fmon) + fmon = thismon + } + m = index ($3, "-") + n++ + thisday = 0 + if( (m-n) > 0 ) { + thisday = int(substr($3, n, m-n)) + if ((lday < thisday) && (lmon == thismon) || ldaymon != lmon) { + lday = thisday + ldaymon = thismon + } + if ((thisday < fday) && (fmon == thismon) || fdaymon != fmon) { + fday = thisday + fdaymon = thismon + } + } + thistime = substr($3,m+1,5) + if ((ltime < thistime) && (lmon == thismon) && (lday == thisday)) + ltime = thistime + if ((thistime < ftime) && (fmon == thismon) && (fday == thisday)) + ftime = thistime +} +END{ + printf("\n\t\t\t\tUUCP Traffic Summary\n\n") + printf("\t\t\t\tFrom %d/%d %s To %d/%d %s\n\n",fmon,fday,ftime,lmon,lday,ltime) + printf("\t Calls Minutes Files Bytes Effective Unused\n") + printf("Site[Failed] To/From To/From To/From Sent/Received Baudrate Bandwidth\n") + for( i in startup ){ + if(seconds[i]== 0)seconds[i]++ + if(dead[i]+live[i]) + percent = dead[i]*100/(dead[i]+live[i]) + else + percent = 0 + if (failed[i] || retries[i]) { + temp = i "[" failed[i] + if (retries[i]) + temp = temp "/" retries[i] "]" + else + temp = temp "]" + } else + temp = i + printf("%-12s %3d/%-3d %5d/%-5d %4d/%-4d %8d/%-8d %6d %5d%%\n",\ + temp,numcallto[i],numcallby[i],\ + totcallto[i],totcallby[i],\ + sentfiles[i],recfiles[i],\ + sentbytes[i],recbytes[i],\ + (recbytes[i]+sentbytes[i])*8/seconds[i],\ + percent) + } + printf("\n\n\n\t\t\t\tOriginating Users\n\n") + printf("User\t\t Minutes Files Bytes\n\n") + if (havout == 1) { + for (i in outuse) { + printf("%-21s %5d %7d %8d\n", i,\ + (outusesecs[i]+30)/60,\ + outusefiles[i], outusebytes[i]) >> "/tmp/outuse" + } + } + if (havin == 1) { + for (i in inuse) { + printf("%-21s %5d %7d %8d\n", i,\ + (inusesecs[i]+30)/60,\ + inusefiles[i], inusebytes[i]) >> "/tmp/inuse" + } + } +}' + +sort /tmp/outuse +echo " " +sort /tmp/inuse +echo " " +echo " " +echo " " +echo " Long Distance Calls" +echo +echo "To Day Start - End From Day Start - End" +cat >/tmp/$$local</tmp/$$a +sed -f /tmp/$$local /tmp/callsfrom | /bin/awk ' +{ + if (last == $1) + pr = "" + else { + last = $1 + pr = $1 + } + if (pr == "" && date == $2) + pd = "" + else { + date = $2 + pd = $2 + } + printf("%s\t%s\t%s - %s\n",pr,pd,$3,$5) +}'>/tmp/$$b +pr -t -m /tmp/$$a /tmp/$$b | uniq +rm -f /tmp/$$[ab] +sed -e " +/rmail seismo!/d +/rmail rlgvax!/d +/rmail rochester!/d +/rmail umcp-cs!/d +/rmail brl-tgr!/d +/rmail brl-vgr!/d +s/)$// +" /tmp/cmds >/tmp/$$c +if [ -s /tmp/$$c ] +then + echo " " + echo " " + echo " " + echo " Outgoing Mail from Other Sites" + echo + echo "Day Time From To" + cat /tmp/$$c +fi +rm -f /tmp/cmds /tmp/$$* /tmp/callsto /tmp/callsfrom /tmp/inuse /tmp/outuse diff --git a/src/cmd/uucp/UUAIDS/uucpsummary.mo b/src/cmd/uucp/UUAIDS/uucpsummary.mo new file mode 100644 index 0000000..8ead851 --- /dev/null +++ b/src/cmd/uucp/UUAIDS/uucpsummary.mo @@ -0,0 +1,130 @@ +cat <<'E_O_F' >/tmp/$$a +BEGIN { + printf("\n\t\t\t\tUUCP Traffic Summary\n\n") + printf("\t\t\t\tFor the previous 30 days\n\n") + printf("\t Calls Minutes Files Bytes Effective Unused\n") + printf("Site To/From To/From To/From Sent/Received Baudrate Bwidth\n") +E_O_F +awk '$1 !~ /#/ && $1 !~ /xxx/{print $1,$3}' /etc/uucp/L.sys | sort -u | +sed 's/\(.*\) \(.*\)/ type["\1"] = "\2"/' >>/tmp/$$a +cat <<'E_O_F' >>/tmp/$$a +} +{ + how = type[$1] + tcallsto[how] += $2 + tcallsfrom[how] += $3 + tminto[how] += $4 + tminfrom[how] += $5 + tfilesto[how] += $6 + tfilesfrom[how] += $7 + tbytesto[how] += $8 + tbytesfrom[how] += $9 + tbaudrate[how] += $10 + tpercent[how] += $11 + tfailed[how] += $12 + tretry[how] += $13 + tn[how]++ +} +name == $1 { + callsto += $2 + callsfrom += $3 + minto += $4 + minfrom += $5 + filesto += $6 + filesfrom += $7 + bytesto += $8 + bytesfrom += $9 + baudrate += $10 + percent += $11 + failed += $12 + retry += $13 + n++ +} +name != $1 { + if (NR > 1) { + s = name + if (failed > 0) { + s = s "[" failed + if (retry > 0) + s = s "/" retry "]" + else + s = s "]" + } else { + if (retry > 0) + s = s "[/" retry "]" + } + printf("%-12s %4d/%-4d %5d/%-5d %5d/%-5d %9d/%-9d %6d %5d%%\n", \ + s, callsto, callsfrom, minto, minfrom, filesto, \ + filesfrom, bytesto, bytesfrom, baudrate/n, percent/n) + } + + callsto = $2 + callsfrom = $3 + minto = $4 + minfrom = $5 + filesto = $6 + filesfrom = $7 + bytesto = $8 + bytesfrom = $9 + baudrate = $10 + percent = $11 + failed = $12 + retry = $13 + n = 1 + name = $1 +} +END { + printf("%-12s %4d/%-4d %5d/%-5d %5d/%-5d %9d/%-9d %6d %5d%%\n", \ + name, callsto, callsfrom, minto, minfrom, filesto, \ + filesfrom, bytesto, bytesfrom, baudrate/n, percent/n) + printf("------------ ----/---- -----/----- -----/----- ---------/--------- ------ -----\n") + for (i in tn) { + + s = i + if (tfailed[i] > 0) { + s = s "[" tfailed[i] + if (tretry[i] > 0) + s = s "/" tretry[i] "]" + else + s = s "]" + } else { + if (tretry[i] > 0) + s = s "[/" tretry[i] "]" + } + printf("%-12s %4d/%-4d %5d/%-5d %5d/%-5d %10d/%-10d %6d %3d%%\n", \ + s, tcallsto[i], tcallsfrom[i], tminto[i], tminfrom[i], \ + tfilesto[i], tfilesfrom[i], tbytesto[i], tbytesfrom[i], \ + tbaudrate[i]/tn[i], tpercent[i]/tn[i]) + totcallsto += tcallsto[i] + totcallsfrom += tcallsfrom[i] + totminto += tminto[i] + totminfrom += tminfrom[i] + totfilesto += tfilesto[i] + totfilesfrom += tfilesfrom[i] + totbytesto += tbytesto[i] + totbytesfrom += tbytesfrom[i] + totbaudrate += tbaudrate[i] + totpercent += tpercent[i] + totfailed += tfailed[i] + totretry += tretry[i] + totn += tn[i] + } + printf("%-12s %4d/%-4d %5d/%-5d %5d/%-5d %10d/%-10d %6d %3d%%\n", \ + "Total", totcallsto, totcallsfrom, totminto, \ + totminfrom, totfilesto, totfilesfrom, totbytesto, \ + totbytesfrom , totbaudrate/totn, totpercen/totn) +} +E_O_F +for i in `grep -l 'UUCP Summary' /usr/msgs/*` +do +sed '1,/^Site/d +/^[ ]*$/,$d +s;\[/;[0/; +s;\[\([0-9]*\)\];[\1/0]; +/\[/s;\([^\[]*\)\[\(.*\)/\(.*\)\]\(.*\);\1 \4 \2 \3; +s!/! !g +s/ */ /g +s/%// +' $i +done | sort | awk -f /tmp/$$a +rm -f /tmp/$$* diff --git a/src/cmd/uucp/UUAIDS/uurate b/src/cmd/uucp/UUAIDS/uurate new file mode 100644 index 0000000..19f7a33 --- /dev/null +++ b/src/cmd/uucp/UUAIDS/uurate @@ -0,0 +1,37 @@ +case $# in +0) + FILE=/usr/spool/uucp/SYSLOG + ;; +1) + FILE=$* + ;; +*) + echo "usage: uustat [syslog]" + ;; +esac +awk ' \ + $5 ~ /received/ {ftotal++; fcount[$2]++; fbytes[$2] += $7; \ + fsecs[$2] += $9} \ + $5 ~ /sent/ {ttotal++; tcount[$2]++; tbytes[$2] += $7; \ + tsecs[$2] += $9} \ + { curtime = substr($4, 5, 6); \ + dtmp = curtime - int($9) - lasttime[$2]; \ + if (dtmp > 0) if (dtmp < 20) \ + dead[$2] += dtmp; \ + lasttime[$2] = curtime; \ + live[$2] += $9 ; \ + } \ + END { if (ftotal) for (i in fbytes) { \ + printf "got from %8s %4d files %7d bytes %5d secs", i, \ + fcount[i], fbytes[i], fsecs[i]; \ + if (fsecs[i]) printf " %.2f bytes/sec", fbytes[i]/fsecs[i]; \ + printf "\n"; } \ + if (ttotal) for (i in tbytes) { \ + printf "sent to %8s %4d files %7d bytes %5d secs", i, \ + tcount[i], tbytes[i], tsecs[i]; \ + if (tsecs[i]) printf " %.2f bytes/sec", tbytes[i]/tsecs[i]; \ + printf "\n"; } \ + for (i in live) { \ + printf "%8s live%5d secs dead%5d secs\n", i, live[i], dead[i]; } \ + }' \ +$FILE diff --git a/src/cmd/uucp/UUAIDS/uutbl b/src/cmd/uucp/UUAIDS/uutbl new file mode 100644 index 0000000..1c3aafd --- /dev/null +++ b/src/cmd/uucp/UUAIDS/uutbl @@ -0,0 +1,42 @@ +#! /bin/sh +: '/********************************************************************* + program: uutbl + description: Make a "tbl" entry from output of uuusage command. + Produces tbl commands to make a centered display + table suitable for inclusion in monthly report. + + programmer: Alan S. Watt + + Sccsid=@(#)uutbl.sh 1.1 + + usage: + uuusage [options] | uutbl + + history: + 03/28/82 original version + 05/27/82 Fix to eliminate "mangled record" diagnostics + from input. + *********************************************************************/' + +: 'delete all the information on user usage and just report + the system usage summary. Leave the first line (the banner + heading) in. + ' +grep -v "uuusage: mangled record" \ + | sed ' + 1i\ +.DS\ +.TS\ +center, tab(:);\ +c s s s s s s\ +l r r r r r r\ +_ _ _ _ _ _ _\ +l n n n n n n. + 1a\ +.sp + s/^[ ]*// + 2,$s/ */:/g + $a\ +.DE\ +.TE +' diff --git a/src/cmd/uucp/UUAIDS/uuusage b/src/cmd/uucp/UUAIDS/uuusage new file mode 100644 index 0000000..21fc9aa --- /dev/null +++ b/src/cmd/uucp/UUAIDS/uuusage @@ -0,0 +1,272 @@ +#! /bin/sh +: '/********************************************************************* + uuusage + Print summary of UUCP usage + Alan S. Watt + + Sccsid=@(#)uuusage.sh 1.1.1 (2.11BSD) 1996/10/25 + + usage: + uuusage [-s] [-t] [period] + + arguments: + -s Just produce the system summary; dont include + individual user statistics. + + -t Produce tbl(1) output. + + period One of: + today Just print todays activities + week Week to date totals + month Month to date totals + m_name Totals for month which + is a three letter abbreviation + for the month name. + + history: + 02/28/83 original version + *********************************************************************/' + +: 'format of SYSLOG is:' +: 'cox onyxasw (4/16-18:24) received data 98 bytes 1 secs' +: 'format for newer version of UUCP stuff is:' +: 'swatt decvax (12/30-21:15) (378612944) sent data 64 bytes 0 secs' +: 'array usage:' +: ' files[name] == total number of files transferred' +: ' bytes[name] == total number of bytes sent' +: ' time[name] == total time spent by user' +: ' totfiles,tottime,totbytes are like above, but totals' +: ' sfiles[sname] == files transferred at request of system sname' +: ' sbytes[sname] == bytes sent/received at request of sname' +: ' stime[sname] == time spent at request of sname' + +uudir=/usr/spool/uucp +uutbl=/usr/sbin/uutbl +slogprefix="$uudir/OLD/SYSLOG" +ologprefix="$uudir/OLD/UUUSAGE" +month= +tbloutput=0 +systmonly=0 +for arg +do + case $arg in + -s) : 'Only print system usage' + systmonly=1 + ;; + -t) : 'Generate TBL commands' + tbloutput=1 ; systmonly=1 + ;; + today) files="$uudir/SYSLOG" + ;; + week) files="$slogprefix.week $uudir/SYSLOG" + ;; + month) files="$slogprefix.month $slogprefix.week $uudir/SYSLOG" + ;; + [Jj]an) month=Jan + ;; + [Ff]eb) month=Feb + ;; + [Mm]ar) month=Mar + ;; + [Aa]pr) month=Apr + ;; + [Mm]ay) month=May + ;; + [Jj]un) month=Jun + ;; + [Jj]ul) month=Jul + ;; + [Aa]ug) month=Aug + ;; + [Ss]ep) month=Sep + ;; + [Oo]ct) month=Oct + ;; + [Nn]ov) month=Nov + ;; + [Dd]ec) month=Dec + ;; + *) files="$files $arg" + ;; + esac +done + +: 'look for short cut on monthly summaries. If we have one, + just dump the summary, deleting the user information part if + -s set; running output through $utbl if -t set. + ' +case $month in +'') ;; +*) \ + if [ -s ${ologprefix}.${month} ] + then + case $systmonly$tbloutput in + "00") grep -v "uuusage: mangled record" \ + ${ologprefix}.${month} + ;; + "10") grep -v "uuusage: mangled record" \ + ${ologprefix}.${month} \ + | sed -e '2,/^$/d' + ;; + "01"|"11") \ + uuusage -s ${month} | $uutbl + ;; + esac + exit + else + files=${slogprefix}.${month} + fi ;; +esac + +: 'Default report: today"s transfers' +case $files in + '') files="$uudir/SYSLOG" + ;; +esac + +case $tbloutput in + 1) uuusage -s ${files} | $uutbl + exit ;; +esac + +flist= +for f in $files +do + if [ -r $f ] + then + flist="$flist $f" + else + echo "$f: Cannot read file" + fi +done + +set " " $flist ; shift +case $# in +0) echo "no files to process" ; exit 1 ;; +esac + +awk ' +BEGIN { + systmonly='"$systmonly"' + fmon = 1000; lmon = -1000 + oldnf = 9; newnf = 10 + # User Format: + # user files bytes time Avgsiz Avgtim + dfmt = "%-10s%6d%10d%8d%7d%7d\n" + sfmt = "%-10s%6s%10s%8s%7s%7s\n" + # System Format: + # system files bytes time Avgsiz Avgtim rate + sfmt1 = "%-10s%6s%10s%8s%7s%7s%7s\n" + dfmt1 = "%-10s%6d%10d%8d%7d%7d%7d\n" + space = "" + + # width of output for centering purposes + width = 52 +} +(NR == 1) { + + # Protect against partial records + maxfields = NF + if (NF == oldnf) + oldfmt++ + else if (NF == newnf) + newfmt++ + else { + # cant seem to get awk to really exit here + # it still tries to produce the report + printf "uuusage: mangled format of 1st record\n" + printf "must be either %d or %d fields\n", oldnf, newnf + exit (1) + } +} +(NF != maxfields) { + printf "uuusage: mangled record #%d in file %s (ignored)\n", \ + NR, FILENAME +} +(NF == maxfields) { + + # protect against format changes + D_name = $1 + D_sname = $2 + D_date = $3 + + # Old (V7/32V format vs. system III format) + if (oldfmt) { + D_bytes = $6 + D_time = $8 + } + else if (newfmt) { + D_bytes = $7 + D_time = $9 + } + + # protect against division by 0 + if (D_time == 0) + D_time = 1 + + # stash user usage info + if (!systmonly) { + name[D_name] = D_name; bytes[D_name] += D_bytes + time[D_name] += D_time; files[D_name] += 1 + } + + # stash system usage info + sname[D_sname] = D_sname; sbytes[D_sname] += D_bytes + stime[D_sname] += D_time + sfiles[D_sname] += 1 + + # get the date of the transfer + n = index (D_date, "/") + cmon = substr (D_date, 2, n-2) + m = index (D_date, "-") + n++ + cday = substr (D_date, n, m-n) + + + # keep earliest and latest dates (naive about new year) + if (int(cmon) < int(fmon) || (cmon == fmon && int(cday) < int(fday))) { + fmon = cmon + fday = cday + } + if (int(cmon) > int(lmon) || (cmon == lmon && int(cday) > int(lday))) { + lmon = cmon + lday = cday + } +} +END { + banner = sprintf "UUCP Usage from %s/%s to %s/%s", \ + fmon,fday,lmon,lday + precision = (width-length(banner))/2 + format = sprintf "%%%ds\n", precision + length(banner) + printf format, banner + if (!systmonly) { + printf sfmt, "user", "files", "bytes", "time", \ + "Avgsiz", "Avgtim" + totfiles=0; totbytes=0; tottime=0 + for (n in name) { + printf dfmt, n, files[n], bytes[n], time[n], \ + bytes[n]/files[n], time[n]/files[n] + totfiles += files[n] + totbytes += bytes[n] + tottime += time[n] + } + printf dfmt, "total", totfiles, totbytes, tottime, \ + totbytes/totfiles, tottime/totfiles + print space + } + + # now print system usage info + printf sfmt1, "system", "files", "bytes", "time", \ + "Avgsiz", "Avgtim", "rate" + totfiles=0; totbytes=0; tottime=0 + for (n in sname) { + printf dfmt1, n, sfiles[n], sbytes[n], stime[n], \ + sbytes[n]/sfiles[n], stime[n]/sfiles[n], \ + sbytes[n]/stime[n] + totfiles += sfiles[n] + totbytes += sbytes[n] + tottime += stime[n] + } + printf dfmt1, "total", totfiles, totbytes, tottime, \ + totbytes/totfiles, tottime/totfiles, totbytes/tottime +} ' $flist diff --git a/src/cmd/uucp/acucntrl.8 b/src/cmd/uucp/acucntrl.8 new file mode 100644 index 0000000..6afdf25 --- /dev/null +++ b/src/cmd/uucp/acucntrl.8 @@ -0,0 +1,132 @@ +.\" @(#)acucntrl.8 6.2.1 (2.11BSD) 1996/11/27 +.\" +.TH acucntrl 8 "November 27, 1996" +.UC 6 +.SH NAME +acucntrl \- turn around tty line between dialin and dialout +.SH SYNOPSIS +.B /usr/libexec/acucntrl +keyword ttyline +.SH DESCRIPTION +.PP +.I Acucntrl +turns around 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 /var/run/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 /var/run/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 /var/run/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 /var/run/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 dialin) +.IP 1) +check input arguments +.IP 2) +look in /var/run/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 /var/run/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, /var/run/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 was similar synchronization problem with the init process. +When dialins are disabled the capitalized name of the process cannot be posted +into /var/run/utmp until init has finished clearing /var/run/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 /var/run/utmp, and 4) posting the +name again. diff --git a/src/cmd/uucp/acucntrl.c b/src/cmd/uucp/acucntrl.c new file mode 100644 index 0000000..b76d332 --- /dev/null +++ b/src/cmd/uucp/acucntrl.c @@ -0,0 +1,774 @@ +#if defined(DOSCCS) && !defined(lint) +static char sccsid[] = "@(#)acucntrl.c 5.8.2 (2.11BSD GTE) 1996/3/22"; +#endif + +/* 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 at the utmp file that the line is not in use + * (3) disable modem control on terminal + * (4) check for carrier on device + * (5) change owner of device to real id + * (6) edit /etc/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 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 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 /etc/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 utmp file + */ + +/* #define SENSECARRIER */ + +#include "uucp.h" +#include +#include +#include +#ifdef pdp11 +#include +#else +#ifdef BSD4_2 +//#include +#else +#include +#endif +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 Etcutmp[] = _PATH_UTMP; +char Etcttys[] = "/etc/ttys"; +#ifdef BSD4_3 +FILE *ttysfile, *nttysfile; +char NEtcttys[] = "/etc/ttys.new"; +extern long ftell(); +#endif +char Devhome[] = "/dev"; + +char usage[] = "Usage: acucntrl {dis|en}able ttydX\n"; + +struct utmp utmp; +char resettty, resetmodem; +int etcutmp; +off_t utmploc; +off_t ttyslnbeg; + +#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; + off_t lseek(); + struct passwd *getpwuid(); + char *rindex(); + + /* check input arguments */ + if (argc!=3) { + 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; + + /* only recognize devices of the form ttydX */ + if (strncmp(device, "ttyd", 4)!=0) { + fprintf(stderr, "Bad Device Name %s", device); + exit(1); + } + + opnttys(device); + + /* Get nlist info */ + nlist("/vmunix", nl); + + /* Chdir to /dev */ + if(chdir(Devhome) < 0) { + fprintf(stderr, "Cannot chdir to %s: %s\r\n", + Devhome, strerror(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); + } + + /* to upper case */ + i = 0; + do { + uname[i] = *p; + Uname[i] = (*p>='a' && *p<='z') ? (*p - ('a'-'A')) : *p; + i++; 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", Etcutmp, + strerror(errno)); + if (write(etcutmp, (char *)&utmp, sizeof(utmp)) < 0) + fprintf(stderr, "on write in %s: %s", Etcutmp, + strerror(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", + strerror(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", Etcutmp, + strerror(errno)); + if (read(etcutmp, (char *)&utmp, sizeof utmp) < 0) + fprintf(stderr, "On read from %s: %s", Etcutmp, + strerror(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, + strerror(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, + strerror(errno)); + exit(1); + } + + ndevice = strlen(device); +#ifndef BRL4_2 + utmploc = sizeof(utmp); +#else + utmploc = 0; +#endif + + while(fgets(linebuf, sizeof(linebuf) - 1, ttysfile) != NULL) { + if(strncmp(device, linebuf, ndevice) == 0) + return; + ttyslnbeg += strlen(linebuf); + if (linebuf[0] != '#' && linebuf[0] != '\n') + utmploc += sizeof(utmp); + if (fputs(linebuf, nttysfile) == NULL) { + fprintf(stderr, "On %s write: %s\n", + Etcttys, strerror(errno)); + exit(1); + } + + } + fprintf(stderr, "%s not found in %s\n", device, Etcttys); + exit(1); +} + +/* modify appropriate line in /etc/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, strerror(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 /etc/ttys:\n%s", 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 /etc/ttys:\n%s", 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, strerror(errno)); + exit(1); + } + while(fgets(lbuf, sizeof(lbuf) - 1, ttysfile) != NULL) { + if (fputs(lbuf, nttysfile) == NULL) { + fprintf(stderr, "On %s write: %s\n", + NEtcttys, strerror(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 + +/* 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, + strerror(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); + return; + } + ttyslnbeg += lnsiz; + utmploc += sizeof(utmp); + } + fprintf(stderr, "%s not found in %s\n", device, Etcttys); + exit(1); +} + +/* modify appropriate line in /etc/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, strerror(errno)); + exit(1); + } + (void)lseek(ittysfil, ttyslnbeg, 0); + if(read(ittysfil, &in, 1)<0) { + fprintf(stderr, "On %s write: %s\n", + Etcttys, strerror(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, strerror(errno)); + exit(1); + } + (void)close(ittysfil); + return(in==out); +} +#endif + +/* + * 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 + */ + + +/* + * 2.11BSD NOTE: 2.11BSD doesn't use ui_flags. We've included the code + * for correctness in case someone decides to change the way the 2.11BSD + * tty drivers work. Mostly what needs to be done is have the tty drivers + * do something like: + * + * if ((minor(dev)&0200) || (XXinfo[unit].ui_flags&(1L<t_state |= TS_CARR_ON; + * } + * else + * XXsoftCAR[unit] &= ~(1L << line); + * + * (2.11BSD uses a bit 0200 in the minor device number of a tty /dev node + * to indicate soft carrier as opposed to compiling it into the kernel as + * 4.3BSD does.) This code minus the check of ui_flags is already present + * in all 2.11BSD drivers. + */ +setmodem(ttyline, enable) +char *ttyline; int enable; +{ + dev_t dev; + int kmem; + int unit, line, nlines; + int addr; + int devtype=0; + char cflags; + unsigned short sflags; +#ifdef BSD4_2 + long flags, tflags; +#else + short flags, tflags; +#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("/dev/kmem", 2)) < 0) { + fprintf(stderr, "/dev/kmem open: %s\n", strerror(errno)); + return(-1); + } + + if(stat(ttyline, &statb) < 0) { + fprintf(stderr, "%s stat: %s\n", ttyline, strerror(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; +#ifdef pdp11 + ubinfo = &(((struct uba_device *)NLVALUE(DZINFO))[unit]); +#else + addr = (int) &(((int *)NLVALUE(DZINFO))[unit]); +#endif + (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; +#ifdef pdp11 + ubinfo = &(((struct uba_device *)NLVALUE(DHINFO))[unit]); +#else + addr = (int) &(((int *)NLVALUE(DHINFO))[unit]); +#endif + (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; +#ifdef pdp11 + ubinfo = &(((struct uba_device *)NLVALUE(DMFINFO))[unit]); +#else + addr = (int) &(((int *)NLVALUE(DMFINFO))[unit]); +#endif + (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); + } + +#ifndef pdp11 + (void)lseek(kmem, (off_t)addr, 0); + (void)read(kmem, (char *) &ubinfo, sizeof ubinfo); +#endif + (void)lseek(kmem, (off_t) &(ubinfo->ui_flags), 0); + (void)read(kmem, (char *) &flags, sizeof flags); + +#ifdef BSD4_2 + tflags = 1L<ui_flags), 0); + (void)write(kmem, (char *) &flags, sizeof flags); +#ifndef pdp11 + 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 *) &flags, sizeof cflags); + break; + default: + fprintf(stderr, "Unknown device type\n"); + return(-1); + } +#endif + return(0); +} + +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/src/cmd/uucp/aculib/Makefile b/src/cmd/uucp/aculib/Makefile new file mode 100644 index 0000000..42cc932 --- /dev/null +++ b/src/cmd/uucp/aculib/Makefile @@ -0,0 +1,22 @@ +# Makefile 4.4 86/02/12 + +TOPSRC = $(shell cd ../../../..; pwd) +include $(TOPSRC)/target.mk + +DEBUG = +CFLAGS = -Os -Werror ${DEBUG} + +OBJS = bsdtcp.o df2.o df12.o dk.o dn.o hys.o hysq.o mic.o nov.o pen.o pnet.o \ + rvmacs.o sy.o unet.o va212.o va811.o va820.o vad.o vent.o vmacs.o \ + hys24.o cds224.o att2224.o + +libacu.a: ${OBJS} + $(AR) cr libacu.a ${OBJS} + -$(RANLIB) libacu.a + +${OBJS}: ../uucp.h ../condevs.h + +install: libacu.a + +clean: + rm -f *.o core errs libacu.a diff --git a/src/cmd/uucp/aculib/att2224.c b/src/cmd/uucp/aculib/att2224.c new file mode 100644 index 0000000..560489b --- /dev/null +++ b/src/cmd/uucp/aculib/att2224.c @@ -0,0 +1,156 @@ +#ifndef lint +static char sccsid[] = "@(#)att2224.c 1.1 (Berkeley) 2/12/86"; +#endif + +#include "../condevs.h" + +#ifdef ATT2224 +attopn(telno, flds, dev) +char *telno, *flds[]; +struct Devices *dev; +{ + char dcname[20], phone[MAXPH+10], c = 0; + int dnf, failret = 0, timelim; + + sprintf(dcname, "/dev/%s", dev->D_line); + + if (setjmp(Sjbuf)) { + delock(dev->D_line); + logent("DEVICE", "NO"); + DEBUG(4, "Open timed out %s", dcname); + alarm (0); + return CF_NODEV; + } + + signal(SIGALRM, alarmtr); + getnextfd(); + alarm(10); + + if ((dnf = open(dcname, 2)) <= 0) { + delock(dev->D_line); + logent("DEVICE", "NO"); + DEBUG(4, "Can't open %s", dcname); + alarm (0); + return CF_NODEV; + } + + alarm(0); + next_fd = -1; + fixline(dnf, dev->D_speed); + DEBUG(4, "modem port - %s\n", dcname); + + if (setjmp(Sjbuf)) { + delock(dev->D_line); + logent("ACU WRITE", "FAILED"); + return CF_DIAL; + } + signal(SIGALRM, alarmtr); + alarm(10); + do { + slowrite(dnf, "\r"); /* wake up modem */ + } while (expect(":~3", dnf)); + alarm(0); + + sprintf (phone, "atzt%s\r", telno); + slowrite (dnf, phone); /* type telno string to modem */ + + if ((expect(phone, dnf)) != SUCCESS) { + delock(dev->D_line); + logent("ACU READ", "FAILED"); + return CF_DIAL; + } + + if (setjmp(Sjbuf)) { + delock(dev->D_line); + logent("NO ANSWER", "FAILED"); + alarm (0); + return CF_DIAL; + } + timelim = strlen(telno) * 4; + signal(SIGALRM, alarmtr); + alarm(timelim > 30 ? timelim : 30); + +readchar: + if ((read(dnf, &c, 1)) != 1) { + delock(dev->D_line); + logent("ACU READ", "FAILED"); + return CF_DIAL; + } + + switch (c) { + case 'D': /* no dial tone */ + logent("NO DIAL TONE", "FAILED"); + failret++; + break; + case 'B': /* line busy */ + logent("LINE BUSY", "FAILED"); + failret++; + break; + case 'N': /* no answer */ + logent("NO ANSWER", "FAILED"); + failret++; + break; + case 'H': /* handshake failed */ + logent("MODEM HANDSHAKE", "FAILED"); + failret++; + break; + case '3': /* 2400 baud */ + DEBUG(4, "Baudrate set to 2400 baud", CNULL); + fixline(dnf, 2400); + break; + case '2': /* 1200 baud */ + DEBUG(4, "Baudrate set to 1200 baud", CNULL); + fixline(dnf, 1200); + break; + case '1': /* 300 baud */ + DEBUG(4, "Baudrate set to 300 baud", CNULL); + fixline(dnf, 300); + break; + default: /* Not one of the above, so must be garbage */ + goto readchar; + } + if (failret) { + alarm (0); + delock(dev->D_line); + return CF_DIAL; + } + alarm (0); + return dnf; +} + +attcls(fd) +int fd; +{ + char dcname[20]; +#ifdef USG + struct termio hup, sav; +#else !USG + struct sgttyb hup, sav; +#endif + + if (fd > 0) { + sprintf(dcname, "/dev/%s", devSel); + DEBUG(4, "Hanging up fd = %d\n", fd); + /* + * code to drop DTR -- change to 0 baud then back to default. + */ + gtty(fd, &hup); + gtty(fd, &sav); +#ifdef USG + hup.c_cflag = B0; +#else !USG + hup.sg_ispeed = B0; + hup.sg_ospeed = B0; +#endif + stty(fd, &hup); + sleep(2); + stty(fd, &sav); + /* + * now raise DTR -- close the device + */ + sleep(2); + close(fd); + delock(devSel); + } +} +#endif diff --git a/src/cmd/uucp/aculib/bsdtcp.c b/src/cmd/uucp/aculib/bsdtcp.c new file mode 100644 index 0000000..d30ee71 --- /dev/null +++ b/src/cmd/uucp/aculib/bsdtcp.c @@ -0,0 +1,96 @@ +#if defined(DOSCCS) && !defined(lint) +static char sccsid[] = "@(#)bsdtcp.c 4.3.2 (2.11BSD GTE) 1996/3/22"; +#endif + +#include "../condevs.h" +#ifdef BSDTCP +#include +#include +#include + +/* + * bsdtcpopn -- make a tcp connection + * + * return codes: + * >0 - file number - ok + * FAIL - failed + */ + +bsdtcpopn(flds) +register char *flds[]; +{ + struct servent *sp; + struct hostent *hp; + struct sockaddr_in hisctladdr; + int s = -1, port; + extern int errno; + + sp = getservbyname(flds[F_CLASS], "tcp"); + if (sp == NULL) { + port = htons(atoi(flds[F_CLASS])); + if (port == 0) { + logent(_FAILED, "UNKNOWN PORT NUMBER"); + return CF_SYSTEM; + } + } else + port = sp->s_port; + DEBUG(4, "bsdtcpopn host %s, ", flds[F_PHONE]); + DEBUG(4, "port %d\n", ntohs(port)); + if (setjmp(Sjbuf)) { + bsdtcpcls(s); + logent("tcpopen", "TIMEOUT"); + return CF_DIAL; + } + + bzero((char *)&hisctladdr, sizeof (hisctladdr)); + hp = gethostbyname(flds[F_PHONE]); + if (hp == NULL) { + logent("tcpopen","UNKNOWN HOST"); + return CF_DIAL; + } + signal(SIGALRM, alarmtr); + alarm(30); + hisctladdr.sin_family = hp->h_addrtype; +#ifdef BSD2_9 + s = socket(SOCK_STREAM, 0, &hisctladdr, 0); +#else BSD4_2 + s = socket(hp->h_addrtype, SOCK_STREAM, 0); +#endif + if (s < 0) + goto bad; +#ifndef BSD2_9 + if (bind(s, (char *)&hisctladdr, sizeof (hisctladdr), 0) < 0) + goto bad; +#endif + bcopy(hp->h_addr, (char *)&hisctladdr.sin_addr, hp->h_length); + hisctladdr.sin_port = port; +#ifdef BSD2_9 + if (connect(s, (char *)&hisctladdr) < 0) +#else BSD4_2 + if (connect(s, (char *)&hisctladdr, sizeof (hisctladdr), 0) < 0) +#endif + goto bad; + alarm(0); + CU_end = bsdtcpcls; + return s; +bad: + alarm(0); + bsdtcpcls(s); + DEBUG(5, "tcpopen failed: errno %d\n", errno); + logent(strerror(errno), _FAILED); + return CF_DIAL; +} + +/* + * bsdtcpcls -- close tcp connection + */ +bsdtcpcls(fd) +register int fd; +{ + DEBUG(4, "TCP CLOSE called\n", 0); + if (fd > 0) { + close(fd); + DEBUG(4, "closed fd %d\n", fd); + } +} +#endif diff --git a/src/cmd/uucp/aculib/cds224.c b/src/cmd/uucp/aculib/cds224.c new file mode 100644 index 0000000..059571e --- /dev/null +++ b/src/cmd/uucp/aculib/cds224.c @@ -0,0 +1,110 @@ +#ifndef lint +static char sccsid[] = "@(#)cds224.c 1.1 (Berkeley) 1/13/86"; +#endif + +#include "../condevs.h" +#ifdef CDS224 + +/* + * conopn: establish dial-out connection through a Concord CDS 224. + * Returns descriptor open to tty for reading and writing. + * Negative values (-1...-7) denote errors in connmsg. + * Be sure to disconnect tty when done, via HUPCL or stty 0. + */ +#define TRYS 5 /* number of trys */ + +cdsopn224(telno, flds, dev) +char *telno; +char *flds[]; +struct Devices *dev; +{ + int dh = -1; + int i, ok, er = 0, delay; + extern errno; + char dcname[20]; + char *tempbuf[20]; + + sprintf(dcname, "/dev/%s", dev->D_line); + if (setjmp(Sjbuf)) { + DEBUG(1, "timeout concord open\n", ""); + logent("concord open", "TIMEOUT"); + if (dh >= 0) + cdscls224(dh); + delock(dev->D_line); + return CF_NODEV; + } + signal(SIGALRM, alarmtr); + getnextfd(); + alarm(10); + dh = open(dcname, 2); + alarm(0); + + /* modem is open */ + next_fd = -1; + if (dh < 0) { + delock(dev->D_line); + return CF_NODEV; + } + fixline(dh, dev->D_speed); + + DEBUG(4, "calling %s -> ", telno); + if (dochat(dev, flds, dh)) { + logent(dcname, "CHAT FAILED"); + cdscls224(dh); + return CF_DIAL; + } + for(i = 0; i < TRYS; ++i) { + /* wake up Concord */ + write(dh, "\r\r", 2); + DEBUG(4, "wanted CDS >", CNULL); + ok = expect("CDS >", dh); + DEBUG(4, "got %s\n", ok ? "?" : "that"); + if (ok != 0) + continue; + + write(dh, "\r", 2); + DEBUG(4, "wanted CDS >", CNULL); + ok = expect("CDS >", dh); + DEBUG(4, "got %s\n", ok ? "?" : "that"); + if (ok != 0) + continue; + + /* send telno \r */ + sprintf(tempbuf,"D%s\r",telno); + write(dh, tempbuf, strlen(tempbuf)); + + DEBUG(4, "wanted DIALING ", CNULL); + ok = expect("DIALING ", dh); + DEBUG(4, "got %s\n", ok ? "?" : "that"); + if (ok == 0) + break; + } + + if (ok == 0) { + sleep(10); /* give concord some time */ + DEBUG(4, "wanted INITIATING " , CNULL); + ok = expect("INITIATING", dh); + DEBUG(4, "got %s\n", ok ? "?" : "that"); + } + + if (ok != 0) { + if (dh > 2) + close(dh); + DEBUG(4, "conDial failed\n", CNULL); + delock(dev->D_line); + return CF_DIAL; + } + DEBUG(4, "concord ok\n", CNULL); + return dh; +} + +cdscls224(fd) +{ + + if (fd > 0) { + close(fd); + sleep(5); + delock(devSel); + } +} +#endif diff --git a/src/cmd/uucp/aculib/df12.c b/src/cmd/uucp/aculib/df12.c new file mode 100644 index 0000000..84ca25f --- /dev/null +++ b/src/cmd/uucp/aculib/df12.c @@ -0,0 +1,156 @@ +#ifndef lint +static char sccsid[] = "@(#)df12.c 4.1 (Berkeley) 4/3/85"; +#endif + +#include "../condevs.h" + +#ifdef DF112 +/* + * df12popn(telno, flds, dev) connect to df12 modem (pulse call) + * df12topn(telno, flds, dev) connect to df12 modem (tone call) + * char *flds[], *dev[]; + * + * return codes: + * >0 - file number - ok + * CF_DIAL,CF_NODEV - failed + */ + +df12popn (telno, flds, dev) +char *telno, + *flds[]; +struct Devices *dev; +{ + return df12opn (telno, flds, dev, 0); +} + +df12topn (telno, flds, dev) +char *telno, + *flds[]; +struct Devices *dev; +{ + return df12opn (telno, flds, dev, 1); +} + +/* ARGSUSED */ +df12opn (telno, flds, dev, toneflag) +char *telno; +char *flds[]; +struct Devices *dev; +int toneflag; +{ + int phindex, dh = -1; + extern errno; + char dcname[20], newphone[64]; + + sprintf (dcname, "/dev/%s", dev -> D_line); + DEBUG (4, "dc - %s\n", dcname); + if (setjmp (Sjbuf)) + { + logent (dcname, "TIMEOUT"); + if (dh >= 0) + close (dh); + return CF_DIAL; + } + signal (SIGALRM, alarmtr); + getnextfd (); + alarm (10); + dh = open (dcname, 2);/* read/write */ + alarm (0); + + /* modem is open */ + + /* First, adjust our phone number string. These modems don't + * like any characters but digits and "=" signs (for delay) + */ + for (phindex = 0; *telno; telno++) + { + if (*telno == '=' || (*telno >= '0' && *telno <= '9')) + newphone[phindex++] = *telno; + if (phindex == 64) + { + logent (dcname, "Phone number too long"); + close (dh); + return CF_DIAL; + } + } + newphone[phindex] = '\0'; + next_fd = -1; + if (dh >= 0) + { + fixline (dh, dev -> D_speed); + if (dochat (dev, flds, dh)) + { + logent (dcname, "CHAT FAILED"); + close (dh); + return CF_DIAL; + } + slowrite (dh, "\02"); + if (expect ("Ready\r\n", dh) != 0) + { + DEBUG (4, "Didn't get 'Ready' response.\n", NULL); + logent (dcname, "Modem not responding"); + close (dh); + return CF_DIAL; + } + DEBUG (4, "Got 'Ready' response\n", NULL); + DEBUG (7, "Writing control select flag %c\n", toneflag ? 'T' : 'P'); + slowrite (dh, toneflag ? "T" : "P"); + DEBUG (4, "Writing telephone number %s\n", newphone); + slowrite (dh, newphone); + DEBUG (7, "Telephone number written\n", NULL); + slowrite (dh, "#"); + DEBUG (7, "Writing # sign\n", NULL); + + if (expect ("Attached\r\n", dh) != 0) + { + logent (dcname, "No carrier"); + strcpy (devSel, dev -> D_line); + df12cls (dh); + return CF_DIAL; + } + + } + if (dh < 0) + { + logent (dcname, "CAN'T OPEN"); + return CF_NODEV; + } + else + { + DEBUG (4, "df12 ok\n", CNULL); + return dh; + } +} + +df12cls (fd) +int fd; +{ + char dcname[20]; + struct sgttyb hup, + sav; + + if (fd > 0) + { + sprintf (dcname, "/dev/%s", devSel); + DEBUG (4, "Hanging up fd = %d\n", fd); + /* + * code to drop DTR -- change to 0 baud then back to default. + */ + gtty (fd, &hup); + gtty (fd, &sav); + hup.sg_ispeed = B0; + hup.sg_ospeed = B0; + stty (fd, &hup); + sleep (2); + stty (fd, &sav); + /* + * now raise DTR -- close the device & open it again. + */ + sleep (2); + close (fd); + sleep (2); + delock (devSel); + } +} + +#endif diff --git a/src/cmd/uucp/aculib/df2.c b/src/cmd/uucp/aculib/df2.c new file mode 100644 index 0000000..cf8dedc --- /dev/null +++ b/src/cmd/uucp/aculib/df2.c @@ -0,0 +1,146 @@ +#ifndef lint +static char sccsid[] = "@(#)df2.c 4.2 (Berkeley) 6/23/85"; +#endif + +#include "../condevs.h" +#ifdef DF02 + +/* + * df2opn(ph, flds, dev) dial remote machine + * + * return codes: + * file descriptor - succeeded + * FAIL - failed + */ +df2opn(ph, flds, dev) +char *ph; +char *flds[]; +struct Devices *dev; +{ + char dcname[20], dnname[20], phone[MAXPH+2], c = 0; +#ifdef USG + struct termio ttbuf; +#endif + int dcf, dnf; + int nw, lt, pid, st, status; + unsigned timelim; +#ifdef TIOCFLUSH + int zero = 0; +#endif TIOCFLUSH + + sprintf(dnname, "/dev/%s", dev->D_calldev); + if (setjmp(Sjbuf)) { + logent(dnname, "CAN'T OPEN"); + DEBUG(4, "%s Open timed out\n", dnname); + return CF_NODEV; + } + signal(SIGALRM, alarmtr); + getnextfd(); + errno = 0; + alarm(10); + dnf = open(dnname, 2 ); + alarm(0); + next_fd = -1; + if (dnf < 0 && errno == EACCES) { + logent(dnname, "CAN'T OPEN"); + delock(dev->D_line); + logent("DEVICE", "NO"); + return CF_NODEV; + } + fioclex(dnf); + + sprintf(dcname, "/dev/%s", dev->D_line); + fixline(dnf, dev->D_speed); + sprintf(phone, "\02%s", ph); + DEBUG(4, "dc - %s, ", dcname); + DEBUG(4, "acu - %s\n", dnname); + pid = 0; + if (setjmp(Sjbuf)) { + logent("DIALUP DN write", "TIMEOUT"); + if (pid) + kill(pid, 9); + delock(dev->D_line); + if (dnf) + close(dnf); + return CF_DIAL; + } + signal(SIGALRM, alarmtr); + timelim = 5 * strlen(phone); + alarm(timelim < 30 ? 30 : timelim); + if ((pid = fork()) == 0) { + sleep(2); + fclose(stdin); + fclose(stdout); +#ifdef TIOCFLUSH + ioctl(dnf, TIOCFLUSH, &zero); +#endif + write(dnf, "\01", 1); + sleep(1); + nw = write(dnf, phone, lt = strlen(phone)); + if (nw != lt) { + logent("DIALUP ACU write", _FAILED); + exit(1); + } + DEBUG(4, "ACU write ok%s\n", CNULL); + exit(0); + } + /* open line - will return on carrier */ + /* RT needs a sleep here because it returns immediately from open */ + +#if RT + sleep(15); +#endif + + if (read(dnf, &c, 1) != 1 || c != 'A') + dcf = -1; + else + dcf = 0; + DEBUG(4, "dcf is %d\n", dcf); + if (dcf < 0) { + logent("DIALUP LINE open", _FAILED); + alarm(0); + kill(pid, 9); + close(dnf); + delock(dev->D_line); + return CF_DIAL; + } + dcf = dnf; + dnf = 0; + while ((nw = wait(<)) != pid && nw != -1) + ; +#ifdef USG + ioctl(dcf, TCGETA, &ttbuf); + if(!(ttbuf.c_cflag & HUPCL)) { + ttbuf.c_cflag |= HUPCL; + ioctl(dcf, TCSETA, &ttbuf); + } +#endif + alarm(0); + fflush(stdout); + fixline(dcf, dev->D_speed); + DEBUG(4, "Fork Stat %o\n", lt); + if (lt != 0) { + close(dcf); + if (dnf) + close(dnf); + delock(dev->D_line); + return CF_DIAL; + } + return dcf; +} + +/* + * df2cls() close the DF02/DF03 call unit + * + * return codes: none + */ +df2cls(fd) +register int fd; +{ + if (fd > 0) { + close(fd); + sleep(5); + delock(devSel); + } +} +#endif diff --git a/src/cmd/uucp/aculib/dk.c b/src/cmd/uucp/aculib/dk.c new file mode 100644 index 0000000..7b84b96 --- /dev/null +++ b/src/cmd/uucp/aculib/dk.c @@ -0,0 +1,42 @@ +#ifndef lint +static char sccsid[] = "@(#)dk.c 4.1 (Berkeley) 1/22/85"; +#endif + +#include "../condevs.h" +#ifdef DATAKIT +#include +#define DKTRIES 2 +/*** + * dkopn(flds) make datakit connection + * + * return codes: + * >0 - file number - ok + * FAIL - failed + */ +dkopn(flds) +char *flds[]; +{ + int dkphone; + register char *cp; + register ret, i; + + if (setjmp(Sjbuf)) + return CF_DIAL; + + signal(SIGALRM, alarmtr); + dkphone = 0; + cp = flds[F_PHONE]; + while(*cp) + dkphone = 10 * dkphone + (*cp++ - '0'); + DEBUG(4, "dkphone (%d) ", dkphone); + for (i = 0; i < DKTRIES; i++) { + getnextfd(); + ret = dkdial(D_SH, dkphone, 0); + next_fd = -1; + DEBUG(4, "dkdial (%d)\n", ret); + if (ret > -1) + break; + } + return ret; +} +#endif diff --git a/src/cmd/uucp/aculib/dn.c b/src/cmd/uucp/aculib/dn.c new file mode 100644 index 0000000..9a0f967 --- /dev/null +++ b/src/cmd/uucp/aculib/dn.c @@ -0,0 +1,144 @@ +#ifndef lint +static char sccsid[] = "@(#)dn.c 4.2 (Berkeley) 6/23/85"; +#endif + +#include "../condevs.h" +#ifdef DN11 +#define ACULAST "-<" + +/*** + * dnopn(ph, flds, dev) dial remote machine + * + * return codes: + * file descriptor - succeeded + * FAIL - failed + */ +dnopn(ph, flds, dev) +char *ph; +char *flds[]; +struct Devices *dev; +{ + char dcname[20], dnname[20], phone[MAXPH+2], c = 0; +#ifdef USG + struct termio ttbuf; +#endif + int dnf, dcf; + int nw, lt, pid, status; + unsigned timelim; +#ifdef TIOCFLUSH + int zero = 0; +#endif + + sprintf(dnname, "/dev/%s", dev->D_calldev); + errno = 0; + + if (setjmp(Sjbuf)) { + logent(dnname, "CAN'T OPEN"); + DEBUG(4, "%s Open timed out\n", dnname); + return(CF_NODEV); + } + signal(SIGALRM, alarmtr); + getnextfd(); + alarm(10); + dnf = open(dnname, 1); + alarm(0); + next_fd = -1; + if (dnf < 0 && errno == EACCES) { + logent(dnname, "CAN'T OPEN"); + logent("DEVICE", "NO"); + return CF_NODEV; + } + fioclex(dnf); + + sprintf(dcname, "/dev/%s", dev->D_line); + sprintf(phone, "%s%s", ph, ACULAST); + DEBUG(4, "dc - %s, ", dcname); + DEBUG(4, "acu - %s\n", dnname); + pid = 0; + if (setjmp(Sjbuf)) { + logent("DIALUP DN write", "TIMEOUT"); + if (pid) + kill(pid, 9); + delock(dev->D_line); + if (dnf) + close(dnf); + return CF_DIAL; + } + signal(SIGALRM, alarmtr); + timelim = 5 * strlen(phone); + alarm(timelim < 30 ? 30 : timelim); + if ((pid = fork()) == 0) { + sleep(2); + fclose(stdin); + fclose(stdout); +#ifdef TIOCFLUSH + ioctl(dnf, TIOCFLUSH, &zero); +#endif TIOCFLUSH + nw = write(dnf, phone, lt = strlen(phone)); + if (nw != lt) { + logent("DIALUP ACU write", _FAILED); + exit(1); + } + DEBUG(4, "ACU write ok\n", CNULL); + exit(0); + } + /* open line - will return on carrier */ + /* RT needs a sleep here because it returns immediately from open */ + +#if RT + sleep(15); +#endif + + getnextfd(); + errno = 0; + dcf = open(dcname, 2); + next_fd = -1; + if (dcf < 0 && errno == EACCES) + logent(dcname, "CAN'T OPEN"); + DEBUG(4, "dcf is %d\n", dcf); + if (dcf < 0) { + logent("DIALUP LINE open", _FAILED); + alarm(0); + kill(pid, 9); + close(dnf); + delock(dev->D_line); + return CF_DIAL; + } + while ((nw = wait(<)) != pid && nw != -1) + ; +#ifdef USG + ioctl(dcf, TCGETA, &ttbuf); + if(!(ttbuf.c_cflag & HUPCL)) { + ttbuf.c_cflag |= HUPCL; + ioctl(dcf, TCSETA, &ttbuf); + } +#endif + alarm(0); + fflush(stdout); + fixline(dcf, dev->D_speed); + DEBUG(4, "Fork Stat %o\n", lt); + if (lt != 0) { + close(dcf); + if (dnf) + close(dnf); + delock(dev->D_line); + return CF_DIAL; + } + return dcf; +} + +/*** + * dncls() close dn type call unit + * + * return codes: None + */ +dncls(fd) +register int fd; +{ + if (fd > 0) { + close(fd); + sleep(5); + delock(devSel); + } +} +#endif diff --git a/src/cmd/uucp/aculib/hys.c b/src/cmd/uucp/aculib/hys.c new file mode 100644 index 0000000..bc00ecc --- /dev/null +++ b/src/cmd/uucp/aculib/hys.c @@ -0,0 +1,191 @@ +#ifndef lint +static char sccsid[] = "@(#)hys.c 4.6 (Berkeley) 2/12/86"; +#endif + +#include "../condevs.h" + +#ifdef HAYES +#ifdef USR2400 +#define DROPDTR +/* + * The "correct" switch settings for a USR Courier 2400 are + * Dialin/out: 0 0 1 1 0 0 0 1 0 0 + * Dialout only: 0 0 1 1 1 1 0 1 0 0 + * where 0 = off and 1 = on + */ +#endif + +/* + * hyspopn(telno, flds, dev) connect to hayes smartmodem (pulse call) + * hystopn(telno, flds, dev) connect to hayes smartmodem (tone call) + * char *flds[], *dev[]; + * + * return codes: + * >0 - file number - ok + * CF_DIAL,CF_DEVICE - failed + */ + +hyspopn(telno, flds, dev) +char *telno, *flds[]; +struct Devices *dev; +{ + return hysopn(telno, flds, dev, 0); +} + +hystopn(telno, flds, dev) +char *telno, *flds[]; +struct Devices *dev; +{ + return hysopn(telno, flds, dev, 1); +} + +/* ARGSUSED */ +hysopn(telno, flds, dev, toneflag) +char *telno; +char *flds[]; +struct Devices *dev; +int toneflag; +{ + extern errno; + char dcname[20]; + char cbuf[MAXPH]; + register char *cp; + register int i; + int dh = -1, nrings = 0; + + sprintf(dcname, "/dev/%s", dev->D_line); + DEBUG(4, "dc - %s\n", dcname); + if (setjmp(Sjbuf)) { + logent(dcname, "TIMEOUT"); + if (dh >= 0) + hyscls(dh); + return CF_DIAL; + } + signal(SIGALRM, (sig_t)alarmtr); + getnextfd(); + alarm(10); + dh = open(dcname, 2); /* read/write */ + alarm(0); + + /* modem is open */ + next_fd = -1; + if (dh >= 0) { + fixline(dh, dev->D_speed); + if (dochat(dev, flds, dh)) { + logent(dcname, "CHAT FAILED"); + hyscls(dh); + return CF_DIAL; + } + write(dh, "ATV1E0H\r", 8); + if (expect("OK\r\n", dh) != 0) { + logent(dcname, "HSM seems dead"); + hyscls(dh); + return CF_DIAL; + } +#ifdef USR2400 + write(dh, "ATX6S7=44\r", 10); + if (expect("OK\r\n", dh) != 0) { + logent(dcname, "HSM seems dead"); + hyscls(dh); + return CF_DIAL; + } +#endif + if (toneflag) + write(dh, "\rATDT", 5); + else +#ifdef USR2400 + write(dh, "\rATD", 4); +#else + write(dh, "\rATDP", 5); +#endif + write(dh, telno, strlen(telno)); + write(dh, "\r", 1); + + if (setjmp(Sjbuf)) { + logent(dcname, "TIMEOUT"); + strcpy(devSel, dev->D_line); + hyscls(dh); + return CF_DIAL; + } + signal(SIGALRM, (sig_t)alarmtr); + alarm(2*MAXMSGTIME); + do { + cp = cbuf; + while (read(dh, cp ,1) == 1) + if (*cp >= ' ') + break; + while (++cp < &cbuf[MAXPH] && read(dh, cp, 1) == 1 && *cp != '\n') + ; + alarm(0); + *cp-- = '\0'; + if (*cp == '\r') + *cp = '\0'; + DEBUG(4,"\nGOT: %s", cbuf); + alarm(MAXMSGTIME); + } while (strncmp(cbuf, "RING", 4) == 0 && nrings++ < 5); + if (strncmp(cbuf, "CONNECT", 7) != 0) { + logent(cbuf, _FAILED); + strcpy(devSel, dev->D_line); + hyscls(dh); + return CF_DIAL; + } + i = atoi(&cbuf[8]); + if (i > 0 && i != dev->D_speed) { + DEBUG(4,"Baudrate reset to %d\n", i); + fixline(dh, i); + } + + } + if (dh < 0) { + logent(dcname, "CAN'T OPEN"); + return dh; + } + DEBUG(4, "hayes ok\n", CNULL); + return dh; +} + +hyscls(fd) +int fd; +{ + char dcname[20]; +#ifdef DROPDTR + struct sgttyb hup, sav; +#endif + + if (fd > 0) { + sprintf(dcname, "/dev/%s", devSel); + DEBUG(4, "Hanging up fd = %d\n", fd); +#ifdef DROPDTR + /* + * code to drop DTR -- change to 0 baud then back to default. + */ + gtty(fd, &hup); + gtty(fd, &sav); + hup.sg_ispeed = B0; + hup.sg_ospeed = B0; + stty(fd, &hup); + sleep(2); + stty(fd, &sav); + /* + * now raise DTR -- close the device & open it again. + */ + sleep(2); + close(fd); + sleep(2); + fd = open(dcname, 2); + stty(fd, &sav); +#else + sleep(3); + write(fd, "+++", 3); +#endif + sleep(3); + write(fd, "ATZ\r", 4); + if (expect("OK",fd) != 0) + logent(devSel, "HSM did not respond to ATZ"); + write(fd, "ATH\r", 4); + sleep(1); + close(fd); + delock(devSel); + } +} +#endif diff --git a/src/cmd/uucp/aculib/hys24.c b/src/cmd/uucp/aculib/hys24.c new file mode 100644 index 0000000..b79d6ec --- /dev/null +++ b/src/cmd/uucp/aculib/hys24.c @@ -0,0 +1,126 @@ +#ifndef lint +static char sccsid[] = "@(#)hys24.c 1.1 (Berkeley) 1/13/86"; +#endif + +#include "../condevs.h" + +#ifdef HAYES2400 +/* + * hyspopn24(telno, flds, dev) connect to hayes smartmodem (pulse call) + * hystopn24(telno, flds, dev) connect to hayes smartmodem (tone call) + * char *flds[], *dev[]; + * + * return codes: + * >0 - file number - ok + * CF_DIAL,CF_DEVICE - failed + */ + +hyspopn24(telno, flds, dev) +char *telno, *flds[]; +struct Devices *dev; +{ + return hysopn24(telno, flds, dev, 0); +} + +hystopn24(telno, flds, dev) +char *telno, *flds[]; +struct Devices *dev; +{ + return hysopn24(telno, flds, dev, 1); +} + +/* ARGSUSED */ +hysopn24(telno, flds, dev, toneflag) +char *telno; +char *flds[]; +struct Devices *dev; +int toneflag; +{ + int dh = -1; + char *ii; + extern errno; + char dcname[20]; + + sprintf(dcname, "/dev/%s", dev->D_line); + DEBUG(4, "dc - %s\n", dcname); + if (setjmp(Sjbuf)) { + logent(dcname, "TIMEOUT"); + if (dh >= 0) + hyscls24(dh); + return CF_DIAL; + } + signal(SIGALRM, alarmtr); + getnextfd(); + alarm(10); + dh = open(dcname, 2); /* read/write */ + alarm(0); + + for (ii = telno; *ii; ii++) + if (*ii == '=') + *ii = ','; + + /* modem is open */ + next_fd = -1; + if (dh >= 0) { + fixline(dh, dev->D_speed); + write(dh, "\rATZH\r", 6); + sleep(2); + if (dochat(dev, flds, dh)) { + logent(dcname, "CHAT FAILED"); + hyscls24(dh); + return CF_DIAL; + } + write(dh, "AT&F&D3&C1E0X1\r", 15); + if (expect("OK\r\n", dh) != 0) { + logent(dcname, "HSM not responding OK"); + hyscls24(dh); + return CF_DIAL; + } + if (toneflag) + write(dh, "\rATDT", 5); + else + write(dh, "\rATDP", 5); + write(dh, telno, strlen(telno)); + write(dh, "\r", 1); + + if (expect("CONNECT", dh) != 0) { + logent("HSM no carrier", _FAILED); + strcpy(devSel, dev->D_line); + hyscls24(dh); + return CF_DIAL; + } + + } + if (dh < 0) { + logent(dcname, "CAN'T OPEN"); + return dh; + } + DEBUG(4, "hayes ok\n", CNULL); + return dh; +} + +hyscls24(fd) +int fd; +{ + char dcname[20]; + + if (fd > 0) { + sprintf(dcname, "/dev/%s", devSel); + DEBUG(4, "Hanging up fd = %d\n", fd); + sleep(1); +/* + * Since we have a getty sleeping on this line, when it wakes up it sends + * all kinds of garbage to the modem. Unfortunatly, the modem likes to + * execute the previous command when it sees the garbage. The previous + * command was to dial the phone, so let's make the last command reset + * the modem. + */ + write(fd, "\r+++", 4); + sleep(2); + write(fd, "\rATH\rATZ\r", 9); + sleep(2); + close(fd); + delock(devSel); + } +} +#endif diff --git a/src/cmd/uucp/aculib/hysq.c b/src/cmd/uucp/aculib/hysq.c new file mode 100644 index 0000000..9318d25 --- /dev/null +++ b/src/cmd/uucp/aculib/hysq.c @@ -0,0 +1,159 @@ +#ifndef lint +static char sccsid[] = "@(#)hysq.c 4.1 (Berkeley) 1/22/85"; +#endif + +#include "../condevs.h" + +#ifdef HAYESQ +/* + * New dialout routine to work with Hayes' SMART MODEM + * 13-JUL-82, Mike Mitchell + * Modified 23-MAR-83 to work with Tom Truscott's (rti!trt) + * version of UUCP (ncsu!mcm) + * + * The modem should be set to NOT send any result codes to + * the system (switch 3 up, 4 down). This end will figure out + * what is wrong. + * + * I had lots of problems with the modem sending + * result codes since I am using the same modem for both incomming and + * outgoing calls. I'd occasionally miss the result code (getty would + * grab it), and the connect would fail. Worse yet, the getty would + * think the result code was a user name, and send garbage to it while + * it was in the command state. I turned off ALL result codes, and hope + * for the best. 99% of the time the modem is in the correct state. + * Occassionally it doesn't connect, or the phone was busy, etc., and + * uucico sits there trying to log in. It eventually times out, calling + * clsacu() in the process, so it resets itself for the next attempt. + */ + +/* + * NOTE: this version is not for the faint-hearted. + * Someday it would be nice to have a single version of hayes dialer + * with a way to specify the switch settings that are on the dialer + * as well as tone/pulse. + * In the meantime, using HAYES rather than HAYESQ is probably best. + */ + +hysqpopn(telno, flds, dev) +char *telno, *flds[]; +struct Devices *dev; +{ + return hysqopn(telno, flds, dev, 0); +} + +hysqtopn(telno, flds, dev) +char *telno, *flds[]; +struct Devices *dev; +{ + return hysqopn(telno, flds, dev, 1); +} + +hysqopn(telno, flds, dev, toneflag) +char *telno, *flds[]; +struct Devices *dev; +int toneflag; +{ + char dcname[20], phone[MAXPH+10], c = 0; +#ifdef USG + struct termio ttbuf; +#endif + int status, dnf; + unsigned timelim; + + signal(SIGALRM, alarmtr); + sprintf(dcname, "/dev/%s", dev->D_line); + + getnextfd(); + if (setjmp(Sjbuf)) { + logent("DEVICE", "NO"); + DEBUG(4, "Open timed out %s", dcname); + return CF_NODEV; + } + alarm(10); + + if ((dnf = open(dcname, 2)) <= 0) { + logent("DEVICE", "NO"); + DEBUG(4, "Can't open %s", dcname); + return CF_NODEV; + } + + alarm(0); + next_fd = -1; + fixline(dnf, dev->D_speed); + DEBUG(4, "Hayes port - %s, ", dcname); + + if (toneflag) + sprintf(phone, "\rATDT%s\r", telno); + else + sprintf(phone, "\rATDP%s\r", telno); + + write(dnf, phone, strlen(phone)); + + /* calculate delay time for the other system to answer the phone. + * Default is 15 seconds, add 2 seconds for each comma in the phone + * number. + */ + timelim = 150; + while(*telno) { + c = *telno++; + if (c == ',') + timelim += 20; + else if (toneflag) + timelim += 2; /* .2 seconds per tone */ + else { + if (c == '0') timelim += 10; /* .1 sec per digit */ + else if (c > '0' && c <= '9') + timelim += (c - '0'); + } + } + alarm(timelim/10 + 1); + if (setjmp(Sjbuf) == 0) { + read(dnf, &c, 1); + alarm(0); + } + + return dnf; +} + +hysqcls(fd) +int fd; +{ + char dcname[20]; + struct sgttyb hup, sav; + + if (fd > 0) { + sprintf(dcname, "/dev/%s", devSel); + DEBUG(4, "Hanging up fd = %d\n", fd); + /* + * code to drop DTR -- change to 0 baud then back to default. + */ + gtty(fd, &hup); + gtty(fd, &sav); + hup.sg_ispeed = B0; + hup.sg_ospeed = B0; + stty(fd, &hup); + sleep(2); + stty(fd, &sav); + /* + * now raise DTR -- close the device & open it again. + */ + sleep(2); + close(fd); + sleep(2); + fd = open(dcname, 2); + /* + * Since we have a getty sleeping on this line, when it wakes up it sends + * all kinds of garbage to the modem. Unfortunatly, the modem likes to + * execute the previous command when it sees the garbage. The previous + * command was to dial the phone, so let's make the last command reset + * the modem. + */ + sleep(2); + write(fd, "\rATZ\r", 5); + close(fd); + delock(devSel); + } +} + +#endif diff --git a/src/cmd/uucp/aculib/mic.c b/src/cmd/uucp/aculib/mic.c new file mode 100644 index 0000000..2aeb8e9 --- /dev/null +++ b/src/cmd/uucp/aculib/mic.c @@ -0,0 +1,110 @@ +#ifndef lint +static char sccsid[] = "@(#)mic.c 4.1 (Berkeley) 1/22/85"; +#endif + +#include "../condevs.h" +#ifdef MICOM + +/* + * micopn: establish connection through a micom. + * Returns descriptor open to tty for reading and writing. + * Negative values (-1...-7) denote errors in connmsg. + * Be sure to disconnect tty when done, via HUPCL or stty 0. + */ +micopn(flds) +register char *flds[]; +{ + extern errno; + char *rindex(), *fdig(), dcname[20]; + int dh, ok = 0, speed; + register struct condev *cd; + register FILE *dfp; + struct Devices dev; + + dfp = fopen(DEVFILE, "r"); + ASSERT(dfp != NULL, "Can't open", DEVFILE, 0); + + signal(SIGALRM, alarmtr); + dh = -1; + for(cd = condevs; ((cd->CU_meth != NULL)&&(dh < 0)); cd++) { + if (snccmp(flds[F_LINE], cd->CU_meth) == SAME) { + fseek(dfp, (off_t)0, 0); + while(rddev(dfp, &dev) != FAIL) { + if (strcmp(flds[F_CLASS], dev.D_class) != SAME) + continue; + if (snccmp(flds[F_LINE], dev.D_type) != SAME) + continue; + if (mlock(dev.D_line) == FAIL) + continue; + + sprintf(dcname, "/dev/%s", dev.D_line); + getnextfd(); + alarm(10); + if (setjmp(Sjbuf)) { + delock(dev.D_line); + logent(dev.D_line,"micom open TIMEOUT"); + dh = -1; + break; + } + dh = open(dcname, 2); + alarm(0); + next_fd = -1; + if (dh > 0) { + break; + } + devSel[0] = '\0'; + delock(dev.D_line); + } + } + } + fclose(dfp); + if (dh < 0) + return CF_NODEV; + + speed = atoi(fdig(flds[F_CLASS])); + fixline(dh, speed); + sleep(1); + + /* negotiate with micom */ + if (speed != 4800) /* damn their eyes! */ + write(dh, "\r", 1); + else + write(dh, " ", 1); + + DEBUG(4, "wanted %s ", "SELECTION"); + ok = expect("SELECTION", dh); + DEBUG(4, "got %s\n", ok ? "?" : "that"); + if (ok == 0) { + write(dh, flds[F_PHONE], strlen(flds[F_PHONE])); + sleep(1); + write(dh, "\r", 1); + DEBUG(4, "wanted %s ", "GO"); + ok = expect("GO", dh); + DEBUG(4, "got %s\n", ok ? "?" : "that"); + } + + if (ok != 0) { + if (dh > 2) + close(dh); + DEBUG(4, "micom failed\n", ""); + delock(dev.D_line); + return(CF_DIAL); + } + else + DEBUG(4, "micom ok\n", ""); + + CU_end = cd->CU_clos; + strcat(devSel, dev.D_line); /* for later unlock */ + return dh; +} + +miccls(fd) +register int fd; +{ + + if (fd > 0) { + close(fd); + delock(devSel); + } +} +#endif diff --git a/src/cmd/uucp/aculib/nov.c b/src/cmd/uucp/aculib/nov.c new file mode 100644 index 0000000..d5b0ccc --- /dev/null +++ b/src/cmd/uucp/aculib/nov.c @@ -0,0 +1,122 @@ +#ifndef lint +static char sccsid[] = "@(#)nov.c 4.1 (Berkeley) 1/22/85"; +#endif + +#include "../condevs.h" +#ifdef NOVATION + +/*** + * novopn(telno, flds, dev) connect to novation Smart-Cat + * (similar to hayes smartmodem) + * char *flds[], *dev[]; + * + * return codes: + * >0 - file number - ok + * CF_DIAL,CF_DEVICE - failed + */ + +novopn(telno, flds, dev) +char *telno; +char *flds[]; +struct Devices *dev; +{ + int dh = -1; + extern errno; + char dcname[20]; + int pulse = 0; + + sprintf(dcname, "/dev/%s", dev->D_line); + DEBUG(4, "dc - %s\n", dcname); + if (strcmp(dev->D_calldev, "pulse") == 0) + pulse = 1; + if (setjmp(Sjbuf)) { + DEBUG(1, "timeout novation open %s\n", dcname); + logent("novation open", "TIMEOUT"); + if (dh >= 0) + close(dh); + delock(dev->D_line); + return CF_DIAL; + } + signal(SIGALRM, alarmtr); + getnextfd(); + alarm(10); + dh = open(dcname, 2); /* read/write */ + alarm(0); + + /* modem is open */ + next_fd = -1; + if (dh >= 0) { + fixline(dh, dev->D_speed); + /* set guard time small so line is in transparant mode */ + slowrite(dh, "\rATS12=1\r"); + if (expect("OK", dh) != 0) { + logent("NOV no line", _FAILED); + strcpy(devSel, dev->D_line); + novcls(dh); + return CF_DIAL; + } + + if (pulse) + slowrite(dh, "ATDP"); + else + slowrite(dh, "ATDT"); + slowrite(dh, telno); + slowrite(dh, "\r"); + + if (expect("CONNECT", dh) != 0) { + logent("NOV no carrier", _FAILED); + strcpy(devSel, dev->D_line); + novcls(dh); + return CF_DIAL; + } + + } + if (dh < 0) { + DEBUG(4, "novation failed\n", CNULL); + delock(dev->D_line); + } + DEBUG(4, "novation ok\n", CNULL); + return dh; +} + +novcls(fd) +int fd; +{ + char dcname[20]; + struct sgttyb hup, sav; + + if (fd > 0) { + sprintf(dcname, "/dev/%s", devSel); + DEBUG(4, "Hanging up fd = %d\n", fd); + /* + * code to drop DTR -- change to 0 baud then back to default. + */ + gtty(fd, &hup); + gtty(fd, &sav); + hup.sg_ispeed = B0; + hup.sg_ospeed = B0; + stty(fd, &hup); + sleep(2); + stty(fd, &sav); + /* + * now raise DTR -- close the device & open it again. + */ + sleep(2); + close(fd); + sleep(2); + fd = open(dcname, 2); + /* + * Since we have a getty sleeping on this line, when it wakes up it sends + * all kinds of garbage to the modem. Unfortunatly, the modem likes to + * execute the previous command when it sees the garbage. The previous + * command was to dial the phone, so let's make the last command reset + * the modem. + */ + sleep(2); + slowrite(fd, "\rATZ\r"); + close(fd); + delock(devSel); + } +} + +#endif diff --git a/src/cmd/uucp/aculib/pen.c b/src/cmd/uucp/aculib/pen.c new file mode 100644 index 0000000..6ed7389 --- /dev/null +++ b/src/cmd/uucp/aculib/pen.c @@ -0,0 +1,103 @@ +#ifndef lint +static char sccsid[] = "@(#)pen.c 4.2 (Berkeley) 10/10/85"; +#endif + +/* + * Speaker's quick and dirty penril hack. STA 4/1/85. + */ +#include "../condevs.h" +#ifdef PENRIL + +penopn(telno, flds, dev) +char *flds[], *telno; +struct Devices *dev; +{ + int dh; + int i, ok = -1; + char dcname[20]; + + sprintf(dcname, "/dev/%s", dev->D_line); + if (setjmp(Sjbuf)) { + DEBUG(1, "timeout penril open\n", ""); + logent("penril open", "TIMEOUT"); + if (dh >= 0) + close(dh); + delock(dev->D_line); + return CF_NODEV; + } + signal(SIGALRM, alarmtr); + getnextfd(); + alarm(10); + dh = open(dcname, 2); + alarm(0); + next_fd = -1; + if (dh < 0) { + DEBUG(4,"%s\n", errno == 4 ? "no carrier" : "can't open modem"); + delock(dev->D_line); + return errno == 4 ? CF_DIAL : CF_NODEV; + } + + /* modem is open */ + fixline(dh, dev->D_speed); + + /* translate - to P and = to W for Penril */ + DEBUG(4, "calling %s -> ", telno); + for (i = 0; i < strlen(telno); ++i) { + switch(telno[i]) { + case '-': /* delay */ + telno[i] = 'P'; + break; + case '=': /* await dial tone */ + telno[i] = 'W'; + break; + case '<': + telno[i] = 'P'; + break; + } + } + DEBUG(4, "%s\n", telno); + sleep(1); + for(i = 0; i < 5; ++i) { /* make up to 5 tries */ + slowrite(dh, "\r");/* awake, thou lowly Penril! */ + + DEBUG(4, "wanted %s ", ">"); + ok = expect(">", dh); + DEBUG(4, "got %s\n", ok ? "?" : "that"); + if (ok != 0) + continue; + slowrite(dh, "K"); /* "K" (enter number) command */ + DEBUG(4, "wanted %s ", "NO.: "); + ok = expect("NO.: ", dh); + DEBUG(4, "got %s\n", ok ? "?" : "that"); + if (ok == 0) + break; + } + + if (ok == 0) { + slowrite(dh, telno); /* send telno, send \r */ + slowrite(dh, "\r"); + DEBUG(4, "wanted %s ", "OK"); + ok = expect("OK", dh); + DEBUG(4, "got %s\n", ok ? "?" : "that"); + } + if (ok != 0) { + if (dh > 2) + close(dh); + DEBUG(4, "penDial failed\n", ""); + return CF_DIAL; + } + else + DEBUG(4, "penDial ok\n", ""); + return dh; +} + +pencls(fd) +int fd; +{ + if (fd > 0) { + close(fd); + sleep(5); + delock(devSel); + } +} +#endif diff --git a/src/cmd/uucp/aculib/pnet.c b/src/cmd/uucp/aculib/pnet.c new file mode 100644 index 0000000..f3f50af --- /dev/null +++ b/src/cmd/uucp/aculib/pnet.c @@ -0,0 +1,47 @@ +#ifndef lint +static char sccsid[] = "@(#)pnet.c 4.2 (Berkeley) 6/23/85"; +#endif + +#include "../condevs.h" +#ifdef PNET + +/*** + * pnetopn(flds) + * + * call remote machine via Purdue network + * use dial string as host name, speed as socket number + * - Steve Bellovin + */ +pnetopn(flds) +char *flds[]; +{ + int fd; + int socket; + register char *cp; + + fd = pnetfile(); + DEBUG(4, "pnet fd - %d\n", fd); + if (fd < 0) { + logent("AVAILABLE DEVICE", "NO"); + return CF_NODEV; + } + socket = 0; + for (cp = flds[F_CLASS]; *cp; cp++) + socket = 10*socket + (*cp - '0'); + DEBUG(4, "socket - %d\n", socket); + if (setjmp(Sjbuf)) { + DEBUG(4, "pnet timeout - %s\n", flds[F_PHONE]); + return CF_DIAL; + } + signal(SIGALRM, (sig_t)alarmtr); + DEBUG(4, "host - %s\n", flds[F_PHONE]); + alarm(15); + if (pnetscon(fd, flds[F_PHONE], socket) < 0) { + DEBUG(4, "pnet connect failed - %s\n", flds[F_PHONE]); + alarm(0); + return CF_DIAL; + } + alarm(0); + return fd; +} +#endif diff --git a/src/cmd/uucp/aculib/rvmacs.c b/src/cmd/uucp/aculib/rvmacs.c new file mode 100644 index 0000000..da686b1 --- /dev/null +++ b/src/cmd/uucp/aculib/rvmacs.c @@ -0,0 +1,183 @@ +#ifndef lint +static char sccsid[] = "@(#)rvmacs.c 4.4 (Berkeley) 6/7/86"; +#endif + +#include "../condevs.h" +#ifdef RVMACS + +/* + * Racal-Vadic 'RV820' MACS system with 831 adaptor. + * A typical 300 baud L-devices entry is + * ACU tty10 tty11,48 300 rvmacs + * where tty10 is the communication line (D_Line), + * tty11 is the dialer line (D_calldev), + * the '4' is the dialer address + modem type (viz. dialer 0, Bell 103), + * the '8' is the communication port, + * We assume the dialer speed is 1200 baud unless MULTISPEED is defined. + * We extended the semantics of the L-devices entry to allow you + * to set the speed at which the computer talks to the dialer: + * ACU cul0 cua0,0<,2400 1200 rvmacs + * This is interpreted as above, except that the number following the second + * comma in the third field is taken to be the speed at which the computer + * must communicate with the dialer. (If omitted, it defaults to the value + * in the fourth field.) Note -- just after the call completes and you get + * carrier, the line speed is reset to the speed indicated in the fourth field. + * To get this ability, define "MULTISPEED", as below. + * + */ +#define MULTISPEED /* for dialers which work at various speeds */ + +#define STX 02 /* Access Adaptor */ +#define ETX 03 /* Transfer to Dialer */ +#define SI 017 /* Buffer Empty (end of phone number) */ +#define ABORT 01 /* Abort */ + +#define pc(fd, x) (c = x, write(fd, &c, 1)) + +rvmacsopn(ph, flds, dev) +char *ph, *flds[]; +struct Devices *dev; +{ + register int va, i, child; + register char *p; + char c, acu[20], com[20]; + int baudrate; + int timelim; + int pid, status; + int zero = 0; +#ifdef MULTISPEED + char *pp; +#else !MULTISPEED + struct sgttyb sg; +#endif + + child = -1; + sprintf(com, "/dev/%s", dev->D_line); + sprintf(acu, "/dev/%s", dev->D_calldev); + if ((p = index(acu, ',')) == NULL) { + DEBUG(2, "No dialer/modem specification\n", 0); + return CF_DIAL; + } + *p++ = '\0'; +#ifdef MULTISPEED + baudrate = dev->D_speed; + if ((pp = index(p, ',')) != NULL){ + baudrate = atoi(pp+1); + DEBUG(5, "Using speed %d baud\n", baudrate); + } +#endif + if (setjmp(Sjbuf)) { + logent("rvmacsopn", "TIMEOUT"); + goto failret; + } + DEBUG(4, "STARTING CALL\n", 0); + getnextfd(); + signal(SIGALRM, alarmtr); + timelim = 5 * strlen(ph); + alarm(timelim < 45 ? 45 : timelim); + + if ((va = open(acu, 2)) < 0) { + logent(acu, "CAN'T OPEN"); + alarm(0); + return CF_DIAL; + } + + /* rti!trt: avoid passing acu file descriptor to children */ + next_fd = -1; + fioclex(va); + + if ((child = fork()) == 0) { + /* create child to do dialing */ + sleep(2); + fclose(stdin); + fclose(stdout); +#ifdef MULTISPEED + fixline(va, baudrate); +#else + sg.sg_flags = RAW|ANYP; + sg.sg_ispeed = sg.sg_ospeed = B1200; + ioctl(va, TIOCSETP, &sg); +#endif + pc(va, ABORT); + sleep(1); + ioctl(va, TIOCFLUSH, &zero); + pc(va, STX); /* access adaptor */ + pc(va, *p++); /* Send Dialer Address Digit */ + pc(va, *p); /* Send Modem Address Digit */ + while (*ph && *ph != '<') { + switch (*ph) { + case '_': + case '-': + case '=': + pc(va, '='); + break; + default: + if (*ph >= '0' && *ph <= '9') + pc(va, *ph); + break; + } + ph++; + } + pc(va, '<'); /* Transfer Control to Modem (sigh) */ + pc(va, SI); /* Send Buffer Empty */ + pc(va, ETX); /* Initiate Call */ + sleep(1); + + if (read(va, &c, 1) != 1) { + close(va); + logent("ACU READ", _FAILED); + exit(1); + } + if (c == 'B' || c == 'G') { + char cc; + pc(va, ABORT); + read(va, &cc, 1); + } + DEBUG(4, "Dialer returned %c\n", c); + close(va); + exit(c != 'A'); + } + /* + * open line - will return on carrier + */ + if ((i = open(com, 2)) < 0) { + if (errno == EIO) + logent("carrier", "LOST"); + else + logent("dialup open", _FAILED); + goto failret; + } + while ((pid = wait(&status)) != child && pid != -1) + ; + alarm(0); + if (status) { + close(i); + close(va); /* XXX */ + return CF_DIAL; + } + fixline(i, dev->D_speed); + return i; + +failret: + alarm(0); + close(va); + if (child != -1) + kill(child, SIGKILL); + return CF_DIAL; +} + +rvmacscls(fd) +register int fd; +{ + if (fd > 0) { + char c; + + pc(fd, ABORT); + ioctl(fd, TIOCCDTR, STBNULL); + sleep(1); + ioctl(fd, TIOCNXCL, STBNULL); + close(fd); + delock(devSel); + } +} +#endif diff --git a/src/cmd/uucp/aculib/sy.c b/src/cmd/uucp/aculib/sy.c new file mode 100644 index 0000000..7d756d7 --- /dev/null +++ b/src/cmd/uucp/aculib/sy.c @@ -0,0 +1,163 @@ +#ifndef lint +static char sccsid[] = "@(#)sy.c 4.1 (Berkeley) 1/22/85"; +#endif + +#include "../condevs.h" + +#ifdef SYTEK + +/* + * sykopn: establish connection through a sytek port. + * Returns descriptor open to tty for reading and writing. + * Negative values (-1...-7) denote errors in connmsg. + * Will try to change baud rate of local port to match + * that of the remote side. + */ +char sykspeed[50]; /* speed to reset to on close */ + +sykopn(flds) +register char *flds[]; +{ + extern errno; + char *rindex(), *fdig(), dcname[20]; + int dh, ok = 0, speed; + register FILE *dfp; + struct Devices dev; + char speedbuf[50]; + + dfp = fopen(DEVFILE, "r"); + ASSERT(dfp != NULL, "Can't open", DEVFILE, 0); + + signal(SIGALRM, alarmtr); + dh = -1; + while(rddev(dfp, &dev) != FAIL) { +/* we'll set our own speed; F_CLASS is how cynthia configures it every night + if (strcmp(flds[F_CLASS], dev.D_class) != SAME) + continue; +*/ + if (snccmp(flds[F_LINE], dev.D_type) != SAME) + continue; + if (mlock(dev.D_line) == FAIL) + continue; + + sprintf(dcname, "/dev/%s", dev.D_line); + getnextfd(); + alarm(10); + if (setjmp(Sjbuf)) { + delock(dev.D_line); + logent(dev.D_line,"sytek open TIMEOUT"); + dh = -1; + break; + } + dh = open(dcname, 2); + alarm(0); + next_fd = -1; + if (dh > 0) { + break; + } + devSel[0] = '\0'; + delock(dev.D_line); + } + fclose(dfp); + if (dh < 0) + return(CF_NODEV); + + speed = atoi(fdig(dev.D_class)); + fixline(dh, speed); + sleep(1); + + /* negotiate with sytek */ + genbrk(dh, 3); + + DEBUG(4, "wanted %s ", "#"); + ok = expect("#", dh); + DEBUG(4, "got %s\n", ok ? "?" : "that"); + if(ok != 0){ + if(atoi(fdig(dev.D_class)) == 9600){ + fixline(dh, 2400); + speed = 2400; + } else { + fixline(dh, 9600); + speed = 9600; + } + sleep(1); + genbrk(dh, 3); + ok = expect("#", dh); + if(ok){ + close(dh); + DEBUG(4, "sytek BREAK failed\n", ""); + delock(dev.D_line); + return(CF_DIAL); + } + } + write(dh, "done \r", 6); + ok = expect("#", dh); + DEBUG(4, "got %s\n", ok ? "?" : "that"); + if(speed != atoi(fdig(flds[F_CLASS]))){ + DEBUG(4, "changing speed\n", ""); + sprintf(speedbuf, "baud %s\r", fdig(flds[F_CLASS])); + write(dh, speedbuf, strlen(speedbuf)); + sleep(1); + speed = atoi(fdig(flds[F_CLASS])); + fixline(dh, speed); + genbrk(dh, 3); + ok = expect("#", dh); + DEBUG(4, "speed set %s\n", ok ? "failed" : flds[F_CLASS]); + } + strcpy(sykspeed, dev.D_class); + write(dh, "command break\r", 14); + ok = expect("#", dh); + DEBUG(4, "got %s\n", ok ? "?" : "that"); + if (ok == 0) { + write(dh, "call ", 5); + write(dh, flds[F_PHONE], strlen(flds[F_PHONE])); + write(dh, "\r", 1); + DEBUG(4, "sytek dial %s\n", flds[F_PHONE]); + DEBUG(4, "wanted %s ", "COMPLETED TO "); + ok = expect("COMPLETED TO ", dh); + DEBUG(4, "got %s\n", ok ? "?" : "that"); + } + + if (ok != 0) { + close(dh); + DEBUG(4, "sytek failed\n", ""); + delock(dev.D_line); + return(CF_DIAL); + } else + DEBUG(4, "sytek ok\n", ""); + + CU_end = sykcls; + strcpy(devSel, dev.D_line); /* for later unlock */ + return(dh); + +} + +sykcls(fd) +register int fd; +{ + register int ok, speed; + + + if (fd > 0) { + genbrk(fd, 3); + ok = expect("#", fd); + DEBUG(4, "got %s\n", ok ? "?" : "that"); + if(ok != 0){ + genbrk(fd, 3); + ok = expect("#", fd); + } + if(ok == 0){ + write(fd, "done 1\r", 7); + ok = expect("#", fd); + DEBUG(4, "got %s\n", ok ? "?" : "that"); + DEBUG(4, "reset baud to %s\n", sykspeed); + write(fd, "baud ", 5); + write(fd, sykspeed, strlen(sykspeed)); + write(fd, "\r", 1); + sleep(1); + } + close(fd); + delock(devSel); + } +} +#endif diff --git a/src/cmd/uucp/aculib/unet.c b/src/cmd/uucp/aculib/unet.c new file mode 100644 index 0000000..98b0713 --- /dev/null +++ b/src/cmd/uucp/aculib/unet.c @@ -0,0 +1,66 @@ +#ifndef lint +static char sccsid[] = "@(#)unet.c 4.1 (Berkeley) 1/22/85"; +#endif + +#include "../condevs.h" +#ifdef UNETTCP + +/* + * unetopn -- make UNET (tcp-ip) connection + * + * return codes: + * >0 - file number - ok + * FAIL - failed + */ + +/* Default port of uucico server */ +#define DFLTPORT 33 + +unetopn(flds) +register char *flds[]; +{ + register int ret, port; + int unetcls(); + + port = atoi(flds[F_PHONE]); + if (port <= 0 || port > 255) + port = DFLTPORT; + DEBUG(4, "unetopn host %s, ", flds[F_NAME]); + DEBUG(4, "port %d\n", port); + if (setjmp(Sjbuf)) { + logent("tcpopen", "TIMEOUT"); + endhnent(); /* see below */ + return CF_DIAL; + } + signal(SIGALRM, alarmtr); + alarm(30); + ret = tcpopen(flds[F_NAME], port, 0, TO_ACTIVE, "rw"); + alarm(0); + endhnent(); /* wave magic wand at 3com and incant "eat it, bruce" */ + if (ret < 0) { + DEBUG(5, "tcpopen failed: errno %d\n", errno); + logent("tcpopen", _FAILED); + return CF_DIAL; + } + CU_end = unetcls; + return ret; +} + +/* + * unetcls -- close UNET connection. + */ +unetcls(fd) +register int fd; +{ + DEBUG(4, "UNET CLOSE called\n", 0); + if (fd > 0) { +#ifdef notdef + /* disable this until a timeout is put in */ + if (ioctl(fd, UIOCCLOSE, STBNULL)) + logent("UNET CLOSE", _FAILED); +#endif + close(fd); + DEBUG(4, "closed fd %d\n", fd); + } +} +#endif diff --git a/src/cmd/uucp/aculib/va212.c b/src/cmd/uucp/aculib/va212.c new file mode 100644 index 0000000..f6c3ddd --- /dev/null +++ b/src/cmd/uucp/aculib/va212.c @@ -0,0 +1,126 @@ +#ifndef lint +static char sccsid[] = "@(#)va212.c 4.2 (Berkeley) 6/23/85"; +#endif + +#include "../condevs.h" + +#ifdef VA212 +va212opn(telno, flds, dev) +char *telno; +char *flds[]; +struct Devices *dev; +{ + int dh = -1; + int i, ok, er = 0, delay; + extern errno; + char dcname[20]; + + sprintf(dcname, "/dev/%s", dev->D_line); + if (setjmp(Sjbuf)) { + DEBUG(1, "timeout va212 open\n", 0); + logent("va212 open", "TIMEOUT"); + if (dh >= 0) + close(dh); + delock(dev->D_line); + return CF_NODEV; + } + signal(SIGALRM, alarmtr); + getnextfd(); + alarm(10); + dh = open(dcname, 2); + alarm(0); + + /* modem is open */ + next_fd = -1; + if (dh < 0) { + DEBUG (4, errno == 4 ? "%s: no carrier\n" : "%s: can't open\n", + dcname); + delock(dev->D_line); + return errno == 4 ? CF_DIAL : CF_NODEV; + } + fixline(dh, dev->D_speed); + + /* translate - to K for Vadic */ + DEBUG(4, "calling %s -> ", telno); + delay = 0; + for (i = 0; i < strlen(telno); ++i) { + switch(telno[i]) { + case '=': /* await dial tone */ + case '-': /* delay */ + case '<': + telno[i] = 'K'; + delay += 5; + break; + } + } + DEBUG(4, "%s\n", telno); + for(i = 0; i < TRYCALLS; ++i) { /* make TRYCALLS tries */ + /* wake up Vadic */ + sendthem("\005\\d", dh); + DEBUG(4, "wanted * ", CNULL); + ok = expect("*", dh); + DEBUG(4, "got %s\n", ok ? "?" : "that"); + if (ok != 0) + continue; + + sendthem("D\\d", dh); /* "D" (enter number) command */ + DEBUG(4, "wanted NUMBER? ", CNULL); + ok = expect("NUMBER?", dh); + if (ok == 0) + ok = expect("\n", dh); + DEBUG(4, "got %s\n", ok ? "?" : "that"); + if (ok != 0) + continue; + + /* send telno, send \r */ + sendthem(telno, dh); + DEBUG(4, "wanted %s ", telno); + ok = expect(telno, dh); + if (ok == 0) + ok = expect("\n", dh); + DEBUG(4, "got %s\n", ok ? "?" : "that"); + if (ok != 0) + continue; + + sendthem("", dh); /* confirm number */ + DEBUG(4, "wanted %s ", "DIALING..."); + ok = expect("DIALING...", dh); + if (ok == 0) { + ok = expect("\n", dh); + DEBUG(4, "wanted ANSWER TONE", CNULL); + ok = expect("ANSWER TONE", dh); + if (ok == 0) + ok = expect("\n", dh); + } + DEBUG(4, "got %s\n", ok ? "?" : "that"); + if (ok == 0) + break; + } + + if (ok == 0) { + DEBUG(4, "wanted ON LINE\\r\\n ", CNULL); + ok = expect("ON LINE\r\n", dh); + DEBUG(4, "got %s\n", ok ? "?" : "that"); + } + + if (ok != 0) { + sendthem("I\\d", dh); /* back to idle */ + if (dh > 2) + close(dh); + DEBUG(4, "vadDial failed\n", CNULL); + delock(dev->D_line); + return CF_DIAL; + } + DEBUG(4, "va212 ok\n", 0); + return dh; +} + +va212cls(fd) +{ + if (fd > 0) { + close(fd); + sleep(5); + delock(devSel); + } +} +#endif diff --git a/src/cmd/uucp/aculib/va811.c b/src/cmd/uucp/aculib/va811.c new file mode 100644 index 0000000..5ed02aa --- /dev/null +++ b/src/cmd/uucp/aculib/va811.c @@ -0,0 +1,123 @@ +#ifndef lint +static char sccsid[] = "@(#)va811.c 4.1 (Berkeley) 1/22/85"; +#endif + +#include "../condevs.h" + +#ifdef VA811S +/* + * Racal-Vadic VA811 dialer with 831 adaptor. + * A typical 300 baud L-devices entry is + * ACU /dev/tty10 unused 300 va811s + * where tty10 is the communication line (D_Line), + * and 300 is the line speed. + * This is almost identical to RVMACS except that we don't need to + * send addresses and modem types, and don't need the fork. + * Joe Kelsey, fluke!joe, vax4.1526, Apr 11 1984. + */ + +#define STX 02 /* Access Adaptor */ +#define ETX 03 /* Transfer to Dialer */ +#define SI 017 /* Buffer Empty (end of phone number) */ +#define SOH 01 /* Abort */ + +va811opn(ph, flds, dev) +char *ph, *flds[]; +struct Devices *dev; +{ + int va; + register int i, tries; + char c, dcname[20]; + char vabuf[35]; /* STX, 31 phone digits, SI, ETX, NUL */ + + va = 0; + sprintf(dcname, "/dev/%s", dev->D_line); + if (setjmp(Sjbuf)) { + DEBUG(1, "timeout va811 open\n", 0); + logent("va811opn", "TIMEOUT"); + if (va >= 0) + close(va); + delock(dev->D_line); + return CF_NODEV; + } + DEBUG(4, "va811: STARTING CALL\n", 0); + getnextfd(); + signal(SIGALRM, alarmtr); + alarm(10); + va = open(dcname, 2); + alarm(0); + + /* line is open */ + next_fd = -1; + if (va < 0) { + DEBUG(4, errno == 4 ? "%s: no carrier\n" : "%s: can't open\n", + dcname); + delock(dev->D_line); + logent(dcname, "CAN'T OPEN"); + return(errno == 4 ? CF_DIAL : CF_NODEV); + } + fixline(va, dev->D_speed); + + /* first, reset everything */ + sendthem("\\01\\c", va); + DEBUG(4, "wanted %c ", 'B'); + i = expect("B", va); + DEBUG(4, "got %s\n", i ? "?" : "that"); + if (i != 0) { + DEBUG(4, "va811: NO RESPONSE\n", 0); + logent("va811 reset", "TIMEOUT"); + close(va); + delock(dev->D_line); + return CF_DIAL; + } + + sprintf(vabuf, "%c%.31s%c%c\\c", STX, ph, SI, SOH); + sendthem(vabuf, va); + DEBUG(4, "wanted %c ", 'B'); + i = expect("B", va); + DEBUG(4, "got %s\n", i ? "?" : "that"); + + if (i != 0) { + DEBUG(4, "va811: STORE NUMBER\n", 0); + logent("va811 STORE", _FAILED); + close(va); + delock(dev->D_line); + return CF_DIAL; + } + + for (tries = 0; tries < TRYCALLS; tries++) { + sprintf(vabuf, "%c%c\\c", STX, ETX); + sendthem(vabuf, va); + DEBUG(4, "DIALING...", CNULL); + i = expect("A", va); + DEBUG(4, " %s\n", i ? _FAILED : "SUCCEEDED"); + if (i != 0) { + DEBUG(4, "va811: RESETTING\n", CNULL); + logent("va811 DIAL", _FAILED); + sendthem("\\01\\c", va); + expect("B", va); + } + else + break; + } + + if (tries >= TRYCALLS) { + close(va); + delock(dev->D_line); + return CF_DIAL; + } + + DEBUG(4, "va811 ok\n", CNULL); + return va; +} + +va811cls(fd) +register int fd; +{ + DEBUG(2, "va811 close %d\n", fd); + p_chwrite(fd, SOH); +/* ioctl(fd, TIOCCDTR, NULL);*/ + close(fd); + delock(devSel); +} +#endif diff --git a/src/cmd/uucp/aculib/va820.c b/src/cmd/uucp/aculib/va820.c new file mode 100644 index 0000000..9e31c37 --- /dev/null +++ b/src/cmd/uucp/aculib/va820.c @@ -0,0 +1,167 @@ +#ifndef lint +static char sccsid[] = "@(#)va820.c 4.3 (Berkeley) 10/10/85"; +#endif + +#include "../condevs.h" +#ifdef VA820 + +/* + * Racal-Vadic 'RV820' with 831 adaptor. + * BUGS: + * dialer baud rate is hardcoded + */ +#define MAXDIG 30 /* set by switches inside adapter */ +char c_abort = '\001'; +char c_start = '\002'; +char c_empty = '\017'; +char c_end = '\003'; + +va820opn(ph, flds, dev) +char *ph, *flds[]; +struct Devices *dev; +{ + register int va, i, child; + char c, acu[20], com[20]; + char vadbuf[MAXDIG+2]; + int nw, lt; + unsigned timelim; + struct sgttyb sg; + + child = -1; + if (strlen(ph) > MAXDIG) { + DEBUG(4, "BAD PHONE NUMBER %s\n", ph); + logent("rvadopn", "BAD PHONE NUMBER"); + i = CF_DIAL; + goto ret; + } + + if (setjmp(Sjbuf)) { + logent("rvadopn", "TIMEOUT"); + i = CF_DIAL; + goto ret; + } + DEBUG(4, "ACU %s\n", dev->D_calldev); + DEBUG(4, "LINE %s\n", dev->D_line); + sprintf(acu, "/dev/%s", dev->D_calldev); + getnextfd(); + signal(SIGALRM, alarmtr); + alarm(10); + va = open(acu, 2); + alarm(0); + next_fd = -1; + if (va < 0) { + DEBUG(4, "ACU OPEN FAIL %d\n", errno); + logent(acu, "CAN'T OPEN"); + i = CF_NODEV; + goto ret; + } + /* + * Set speed and modes on dialer and clear any + * previous requests + */ + DEBUG(4, "SETTING UP VA831 (%d)\n", va); + ioctl(va, TIOCGETP, &sg); + sg.sg_ispeed = sg.sg_ospeed = B1200; + sg.sg_flags |= RAW; + sg.sg_flags &= ~ECHO; + ioctl(va, TIOCSETP, &sg); + DEBUG(4, "CLEARING VA831\n", 0); + if ( write(va, &c_abort, 1) != 1) { + DEBUG(4,"BAD VA831 WRITE %d\n", errno); + logent(acu, "CAN'T CLEAR"); + i = CF_DIAL; + goto ret; + } + sleep(1); /* XXX */ + read(va, &c, 1); + if (c != 'B') { + DEBUG(4,"BAD VA831 RESPONSE %c\n", c); + logent(acu, "CAN'T CLEAR"); + i = CF_DIAL; + goto ret; + } + /* + * Build the dialing sequence for the adapter + */ + DEBUG(4, "DIALING %s\n", ph); + sprintf(vadbuf, "%c%s<%c%c", c_start, ph, c_empty, c_end); + timelim = 5 * strlen(ph); + alarm(timelim < 30 ? 30 : timelim); + nw = write(va, vadbuf, strlen(vadbuf)); /* Send Phone Number */ + if (nw != strlen(vadbuf)) { + DEBUG(4,"BAD VA831 WRITE %d\n", nw); + logent(acu, "BAD WRITE"); + goto failret; + } + + sprintf(com, "/dev/%s", dev->D_line); + + /* create child to open comm line */ + if ((child = fork()) == 0) { + signal(SIGINT, SIG_DFL); + open(com, 0); + sleep(5); + _exit(1); + } + + DEBUG(4, "WAITING FOR ANSWER\n", 0); + if (read(va, &c, 1) != 1) { + logent("ACU READ", _FAILED); + goto failret; + } + switch(c) { + case 'A': + /* Fine! */ + break; + case 'B': + DEBUG(2, "Line Busy / No Answer\n", 0); + goto failret; + case 'D': + DEBUG(2, "Dialer format error\n", 0); + goto failret; + case 'E': + DEBUG(2, "Dialer parity error\n", 0); + goto failret; + case 'F': + DEBUG(2, "Phone number too long\n", 0); + goto failret; + case 'G': + DEBUG(2, "Modem Busy\n", 0); + goto failret; + default: + DEBUG(2, "Unknown MACS return code '%c'\n", c&0177); + goto failret; + } + /* + * open line - will return on carrier + */ + if ((i = open(com, 2)) < 0) { + if (errno == EIO) + logent("carrier", "LOST"); + else + logent("dialup open", _FAILED); + goto failret; + } + DEBUG(2, "RVADIC opened %d\n", i); + fixline(i, dev->D_speed); + goto ret; +failret: + i = CF_DIAL; +ret: + alarm(0); + if (child != -1) + kill(child, SIGKILL); + close(va); + while ((nw = wait(<)) != child && nw != -1) + ; + return i; +} + +va820cls(fd) +register int fd; +{ + + DEBUG(2, "RVADIC close %d\n", fd); + close(fd); +} +#endif diff --git a/src/cmd/uucp/aculib/vad.c b/src/cmd/uucp/aculib/vad.c new file mode 100644 index 0000000..2c1ec8c --- /dev/null +++ b/src/cmd/uucp/aculib/vad.c @@ -0,0 +1,132 @@ +#ifndef lint +static char sccsid[] = "@(#)vad.c 4.2 (Berkeley) 10/10/85"; +#endif + +#include "../condevs.h" +#ifdef VADIC + +/* + * vadopn: establish dial-out connection through a Racal-Vadic 3450. + * Returns descriptor open to tty for reading and writing. + * Negative values (-1...-7) denote errors in connmsg. + * Be sure to disconnect tty when done, via HUPCL or stty 0. + */ + +vadopn(telno, flds, dev) +char *telno; +char *flds[]; +struct Devices *dev; +{ + int dh = -1; + int i, ok, er = 0, delay; + extern errno; + char dcname[20]; + + sprintf(dcname, "/dev/%s", dev->D_line); + if (setjmp(Sjbuf)) { + DEBUG(1, "timeout vadic open\n", ""); + logent("vadic open", "TIMEOUT"); + if (dh >= 0) + close(dh); + delock(dev->D_line); + return CF_NODEV; + } + signal(SIGALRM, alarmtr); + getnextfd(); + alarm(10); + dh = open(dcname, 2); + alarm(0); + + /* modem is open */ + next_fd = -1; + if (dh < 0) { + delock(dev->D_line); + return CF_NODEV; + } + fixline(dh, dev->D_speed); + + DEBUG(4, "calling %s -> ", telno); + if (dochat(dev, flds, dh)) { + logent(dcname, "CHAT FAILED"); + close(dh); + return CF_DIAL; + } + delay = 0; + for (i = 0; i < strlen(telno); ++i) { + switch(telno[i]) { + case '=': /* await dial tone */ + case '-': + case ',': + case '<': + case 'K': + telno[i] = 'K'; + delay += 5; + break; + } + } + DEBUG(4, "%s\n", telno); + for(i = 0; i < 5; ++i) { /* make 5 tries */ + /* wake up Vadic */ + write(dh, "\005", 1); + sleep(1); + write(dh, "\r", 1); + DEBUG(4, "wanted * ", CNULL); + ok = expect("*~5", dh); + DEBUG(4, "got %s\n", ok ? "?" : "that"); + if (ok != 0) + continue; + + write(dh, "D\r", 2); /* "D" (enter number) command */ + DEBUG(4, "wanted NUMBER?\\r\\n ", CNULL); + ok = expect("NUMBER?\r\n~5", dh); + DEBUG(4, "got %s\n", ok ? "?" : "that"); + if (ok != 0) + continue; + + /* send telno, send \r */ + write(dh, telno, strlen(telno)); + sleep(1); + write(dh, "\r", 1); + DEBUG(4, "wanted %s ", telno); + ok = expect(telno, dh); + if (ok == 0) + ok = expect("\r\n", dh); + DEBUG(4, "got %s\n", ok ? "?" : "that"); + if (ok != 0) + continue; + + write(dh, "\r", 1); /* confirm number */ + DEBUG(4, "wanted DIALING: ", CNULL); + ok = expect("DIALING: ", dh); + DEBUG(4, "got %s\n", ok ? "?" : "that"); + if (ok == 0) + break; + } + + if (ok == 0) { + sleep(10 + delay); /* give vadic some time */ + DEBUG(4, "wanted ON LINE\\r\\n ", CNULL); + ok = expect("ON LINE\r\n", dh); + DEBUG(4, "got %s\n", ok ? "?" : "that"); + } + + if (ok != 0) { + if (dh > 2) + close(dh); + DEBUG(4, "vadDial failed\n", CNULL); + delock(dev->D_line); + return CF_DIAL; + } + DEBUG(4, "vadic ok\n", CNULL); + return dh; +} + +vadcls(fd) +{ + if (fd > 0) { + close(fd); + sleep(5); + delock(devSel); + } +} +#endif diff --git a/src/cmd/uucp/aculib/vent.c b/src/cmd/uucp/aculib/vent.c new file mode 100644 index 0000000..319407c --- /dev/null +++ b/src/cmd/uucp/aculib/vent.c @@ -0,0 +1,100 @@ +#ifndef lint +static char sccsid[] = "@(#)vent.c 4.2 (Berkeley) 10/10/85"; +#endif + +#include "../condevs.h" +#ifdef VENTEL + +ventopn(telno, flds, dev) +char *flds[], *telno; +struct Devices *dev; +{ + int dh; + int i, ok = -1; + char dcname[20]; + + sprintf(dcname, "/dev/%s", dev->D_line); + if (setjmp(Sjbuf)) { + DEBUG(1, "timeout ventel open\n", ""); + logent("ventel open", "TIMEOUT"); + if (dh >= 0) + close(dh); + delock(dev->D_line); + return CF_NODEV; + } + signal(SIGALRM, alarmtr); + getnextfd(); + alarm(10); + dh = open(dcname, 2); + next_fd = -1; + alarm(0); + if (dh < 0) { + DEBUG(4,"%s\n", errno == 4 ? "no carrier" : "can't open modem"); + delock(dev->D_line); + return errno == 4 ? CF_DIAL : CF_NODEV; + } + + /* modem is open */ + fixline(dh, dev->D_speed); + + /* translate - to % and = to & for VenTel */ + DEBUG(4, "calling %s -> ", telno); + for (i = 0; i < strlen(telno); ++i) { + switch(telno[i]) { + case '-': /* delay */ + telno[i] = '%'; + break; + case '=': /* await dial tone */ + telno[i] = '&'; + break; + case '<': + telno[i] = '%'; + break; + } + } + DEBUG(4, "%s\n", telno); + sleep(1); + for(i = 0; i < 5; ++i) { /* make up to 5 tries */ + slowrite(dh, "\r\r");/* awake, thou lowly VenTel! */ + + DEBUG(4, "wanted %s ", "$"); + ok = expect("$", dh); + DEBUG(4, "got %s\n", ok ? "?" : "that"); + if (ok != 0) + continue; + slowrite(dh, "K"); /* "K" (enter number) command */ + DEBUG(4, "wanted %s ", "DIAL: "); + ok = expect("DIAL: ", dh); + DEBUG(4, "got %s\n", ok ? "?" : "that"); + if (ok == 0) + break; + } + + if (ok == 0) { + slowrite(dh, telno); /* send telno, send \r */ + slowrite(dh, "\r"); + DEBUG(4, "wanted %s ", "ONLINE"); + ok = expect("ONLINE!", dh); + DEBUG(4, "got %s\n", ok ? "?" : "that"); + } + if (ok != 0) { + if (dh > 2) + close(dh); + DEBUG(4, "venDial failed\n", ""); + return CF_DIAL; + } + else + DEBUG(4, "venDial ok\n", ""); + return dh; +} + +ventcls(fd) +int fd; +{ + if (fd > 0) { + close(fd); + sleep(5); + delock(devSel); + } +} +#endif diff --git a/src/cmd/uucp/aculib/vmacs.c b/src/cmd/uucp/aculib/vmacs.c new file mode 100644 index 0000000..5d4f424 --- /dev/null +++ b/src/cmd/uucp/aculib/vmacs.c @@ -0,0 +1,168 @@ +#ifndef lint +static char sccsid[] = "@(#)vmacs.c 4.3 (Berkeley) 10/10/85"; +#endif + +#include "../condevs.h" +#ifdef VMACS +/* + * Racal-Vadic 'RV811' MACS system with 831 adaptor. + * + * A typical 300 baud L-devices entry is + * ACU /dev/tty10 /dev/tty11,48,1200 300 vmacs + * where tty10 is the communication line (D_Line), + * tty11 is the dialer line (D_calldev), + * the '4' is the dialer address + modem type (viz. dialer 0, Bell 103), + * and the '8' is the communication port + * (Note: Based on RVMACS version for 820 dialer. This version + * developed by Doug Kingston @ BRL, 13 December 83.) + */ + +#define SOH 01 /* Abort */ +#define STX 02 /* Access Adaptor */ +#define ETX 03 /* Transfer to Dialer */ +#define SI 017 /* Buffer Empty (end of phone number) */ + +vmacsopn(ph, flds, dev) +char *ph, *flds[]; +struct Devices *dev; +{ + register int va, i, child; + register char *p; + char c, acu[20], com[20]; + char modem, dialer; + int dialspeed; + char c_STX = STX; + char c_ETX = ETX; + char c_SI = SI; + char c_SOH = SOH; + + /* create child to open comm line */ + child = -1; + sprintf(com, "/dev/%s", dev->D_line); + if ((child = fork()) == 0) { + signal(SIGINT, SIG_DFL); + open(com, 0); + DEBUG(5, "%s Opened.", com); + sleep(5); + exit(1); + } + + if ((p = index(dev->D_calldev, ',')) == NULL) { + DEBUG(2, "No dialer/modem specification\n", 0); + goto failret; + } + *p++ = '\0'; + if (*p < '0' || *p > '7') { + logent(p, "Bad dialer address/modem type"); + goto failret; + } + dialer = *p++; + if (*p < '0' || *p > '>') { + logent(p, "Bad modem address"); + goto failret; + } + modem = *p++; + if (*p++ == ',') + dialspeed = atoi (p); + else + dialspeed = dev->D_speed; + if (setjmp(Sjbuf)) { + logent("vmacsopn", "TIMEOUT"); + i = CF_DIAL; + goto ret; + } + DEBUG(4, "STARTING CALL\n", 0); + sprintf(acu, "/dev/%s", dev->D_calldev); + getnextfd(); + signal(SIGALRM, alarmtr); + alarm(60); + if ((va = open(acu, 2)) < 0) { + logent(acu, "CAN'T OPEN"); + i = CF_NODEV; + goto ret; + } + DEBUG(5, "ACU %s opened.\n", acu); + next_fd = -1; + fixline(va, dialspeed); + + write(va, &c_SOH, 1); /* abort, reset the dialer */ + do { + if (read (va, &c, 1) != 1) { + logent ("MACS initialization", _FAILED); + goto failret; + } + } while ((c&0177) != 'B'); + DEBUG(5, "ACU initialized\n", 0); + + write(va, &c_STX, 1); /* start text, access adaptor */ + write(va, &dialer, 1); /* send dialer address digit */ + write(va, &modem, 1); /* send modem address digit */ + for (p=ph; *p; p++) { + if (*p == '=' || (*p >= '0' && *p <= '9')) + write(va, p, 1); + } + write(va, &c_SI, 1); /* send buffer empty */ + write(va, &c_ETX, 1); /* end of text, initiate call */ + + if (read(va, &c, 1) != 1) { + logent("ACU READ", _FAILED); + goto failret; + } + switch(c) { + case 'A': + /* Fine! */ + DEBUG(5, "Call connected\n", 0); + break; + case 'B': + DEBUG(2, "Dialer Timeout or Abort\n", 0); + goto failret; + case 'D': + DEBUG(2, "Dialer format error\n", 0); + goto failret; + case 'E': + DEBUG(2, "Dialer parity error\n", 0); + goto failret; + case 'F': + DEBUG(2, "Phone number too long\n", 0); + goto failret; + case 'G': + DEBUG(2, "Busy signal\n", 0); + goto failret; + default: + DEBUG(2, "Unknown MACS return code '%c'\n", i); + goto failret; + } + /* + * open line - will return on carrier + */ + if ((i = open(com, 2)) < 0) { + if (errno == EIO) + logent("carrier", "LOST"); + else + logent("dialup open", _FAILED); + goto failret; + } + fixline(i, dev->D_speed); + goto ret; +failret: + i = CF_DIAL; +ret: + alarm(0); + if (child > 1) + kill(child, SIGKILL); + close(va); + sleep(2); + return i; +} + +vmacscls(fd) +register int fd; +{ + char c_SOH = SOH; + + DEBUG(2, "MACS close %d\n", fd); + write(fd, &c_SOH, 1); +/* ioctl(fd, TIOCCDTR, NULL);*/ + close(fd); +} +#endif diff --git a/src/cmd/uucp/anlwrk.c b/src/cmd/uucp/anlwrk.c new file mode 100644 index 0000000..1f3452d --- /dev/null +++ b/src/cmd/uucp/anlwrk.c @@ -0,0 +1,362 @@ +#if !defined(lint) && defined(DOSCCS) +static char sccsid[] = "@(#)anlwrk.c 5.5.1 (2.11BSD) 1997/10/2"; +#endif + +#include "uucp.h" +#include +#include +#include "uust.h" +#ifdef NDIR +#include "ndir.h" +#else +#include +#endif +#include + +#define TLIMIT (5*60L) +#define NITEMS(X) (sizeof (X) / sizeof ((X)[0])) + +int Nfiles = 0; +char Filent[LLEN][NAMESIZE]; +extern int TransferSucceeded; + +/*LINTLIBRARY*/ + +/* + * create a vector of command arguments + * + * return codes: + * 0 - no more work in this file + * positive number - number of arguments + */ + +/* LOCAL only */ +int +anlwrk(file, wvec) +register char *file, **wvec; +{ + static char str[MAXRQST], nstr[MAXRQST], lastfile[MAXFULLNAME] = ""; + static FILE *fp = NULL; + static long nextread, nextwrite; + + /* + * If called with a null string, force a shutdown + * of the current work file. + */ + if (file[0] == '\0') { + if (fp != NULL) + fclose (fp); + fp = NULL; + return 0; + } + if (fp == NULL) { + if (strncmp(file, lastfile, MAXFULLNAME) == 0) { + DEBUG(5,"Workfilename repeated: %s\n", file); + return 0; + } + strncpy(lastfile, file, MAXFULLNAME); + fp = fopen(subfile(file), "r+w"); + if (fp == NULL) { + char *bnp, rqstr[MAXFULLNAME]; + bnp = rindex(file, '/'); + sprintf(rqstr, "%s/%s", CORRUPT, bnp ? bnp + 1 : file); + xmv(file, rqstr); + logent(subfile(file), "CMD FILE UNREADABLE"); + unlink(subfile(file)); + return 0; + } + Usrf = 0; + nstr[0] = '\0'; + nextread = nextwrite = 0L; + } + + if (nstr[0] != '\0' && TransferSucceeded) { + fseek(fp, nextwrite, 0); + fputs(nstr, fp); + fseek(fp, nextread, 0); + } + + do { + nextwrite = ftell(fp); + if (fgets(str, MAXRQST, fp) == NULL) { + fclose(fp); + if (TransferSucceeded) + unlink(subfile(file)); + USRF(USR_COMP); + US_RRS(file, Usrf); + Usrf = 0; + file[0] = '\0'; + nstr[0] = '\0'; + fp = NULL; + return 0; + } + } while (!isupper(str[0])); + + nextread = ftell(fp); + strncpy(nstr, str, MAXRQST); + nstr[0] = tolower(nstr[0]); + return getargs(str, wvec, 20); +} + + +/* + * build list of work files for given system + * + * return value - 1 if work was found, else 0 + * + */ + +/* LOCAL only */ +int +bldflst (reqst, dir, pre) +char *reqst; +register char *dir, *pre; +{ + static DIR *dirp = NULL; + register nfound; + char filename[NAMESIZE]; + int plen = strlen (pre); + int flen; + extern char MaxGrade; + + if (dirp == NULL) { + if ((dirp = opendir(subdir(dir,pre[0]))) == NULL) { + DEBUG(1,"opendir(%s) FAILS\n",subdir(dir,pre[0])); + return 0; + } + } + else + rewinddir(dirp); + for (nfound = 0, Nfiles = 0; gnamef(dirp, filename);) { + /* Check for two systems with the same prefix. + * Magic number "5" is 1 for "grade" character plus + * 4 for sequence number. The point here is to not + * send work for a system which has as a prefix the + * name of the system called for. + * Special case: prefix "X." does not do this check + * so uuxqt can use bldflst. + */ + flen = strlen(filename); + if (!prefix(pre, filename) || (plen != 2 && flen-plen != 5)) { + DEBUG(99,"bldflst rejects %s\n",filename); + continue; + } + if (filename[flen-5] > MaxGrade ) { + DEBUG(8,"bldflst rejects %s, grade too low\n",filename); + continue; + } + nfound++; + if (*reqst == 'c') + return 1; + entflst(filename); + } + return nfound? 1: 0; +} + +/* + * put new name if list is not full or new name is less than the MAX + * now in the list. + * + */ + +/* LOCAL only */ +int +entflst(file) +register char *file; +{ + register int i; + + /* locate position for the new file and make room for it */ + for (i = Nfiles; i > 0; i--) { + if (pcompar(file, Filent[i-1]) <= 0) + break; + if (i 0 if p1 "has greater priority than" p2. + * Priority: + * lower grade wins. + * lower sequence number wins (unless wrap-around is suspected). + * + */ +/* LOCAL only */ +int +pcompar(p1, p2) +register char *p1, *p2; +{ + register int rc; + + /* assert: strlen(p1) and strlen(p2) are >= 5 */ + p1 += strlen(p1)-5; + p2 += strlen(p2)-5; + /* check 'grade' */ + if (rc = *p2++ - *p1++) + return rc; + /* check for sequence wrap-around */ + if (rc = *p2++ - *p1++) + if (rc < -10 || rc > 10) + return -rc; + else + return rc; + /* check remaining digits */ + return strcmp(p2, p1); +} + +/* + * get next work file + * + * return value: + * + * 0 - No file gotten + * 1 - File successfully gotten. + * + */ + +/* LOCAL only */ +gtwrkf(dir, file) +char *file, *dir; +{ + register int i; + + if (Nfiles-- <= 0) { + Nfiles = 0; + return 0; + } + sprintf(file, "%s/%s", dir, Filent[0]); + for (i=0; i 3 || !iswrk(file, "get", dir, wkpre)) + return 0; + } + return nargs; +} + +/* + * iswrk - this routine will check the work list (list). + * If it is empty or the present work is exhausted, it + * will call bldflst to generate a new list. + * The "reqst" field will be the string "chk" or "get" to + * check for work, or get the next work file respectively. + * + * return codes: + * 0 - no more work (or some error) + * 1 - there is work + * + */ + +/* EXTERNALLY CALLED */ +int +iswrk(file, reqst, dir, pre) +register char *file, *reqst, *dir, *pre; +{ + static char *lastpre = 0; + register ret; + + /* Starting new system; re-init */ + if (lastpre == 0 || strcmp(lastpre,pre) != 0) { + anlwrk ("", (char **)0); /* Force close of work file */ + + /* Save last worked-on prefix */ + if (lastpre != 0) + free (lastpre); + lastpre = (char *)malloc((unsigned)(strlen(pre)+1)); + strcpy (lastpre, pre); + + /* Set the external indexes properly + */ + Nfiles = 0; + } + + /* If the list is empty or new files have entered + * the spool area, call "bldflst" to read + * some file names into it. Because names can + * be put in the list that later turn out to + * be unusable (from "gtwrkf"), this operation + * continues until either "bldflst" can't find + * any new files, or "gtwrkf" signals success. + */ + for (;;) { + ret = 0; + if (Nfiles <= 0 || newspool((time_t)TLIMIT)) { + ret = bldflst (reqst, dir, pre); + DEBUG(99,"bldflst returns %d\n",ret); + } + + /* If they only wanted to check, return + * boolean list not empty. NB: the list + * will be forcibly emptied as soon as + * a new system name is mentioned. + */ + if (*reqst == 'c') + return ret; + + if (Nfiles <= 0) + return 0; + + if (gtwrkf(dir, file)) + return 1; + } +} + +/* Return non-zero if there is new work in the spool + * area since last check. Assumes that if the sequence + * file has been modified, there is new work. This is + * not absolutely correct, but should be close enough. + * Only checks every seconds at most. Called + * from "iswrk()" when a new work file is requested. + */ +/* LOCAL only */ +int +newspool(limit) +time_t limit; +{ + static time_t lastcheck = 0, lastmod = 0; + time_t check; + struct stat mod; + register int ret = 0; + + /* (void) */ time (&check); + if (check - lastcheck > limit || lastcheck - check > limit) { + mod.st_mtime = 0; + /* (void) */ stat (SEQFILE, &mod); + if (mod.st_mtime != lastmod) + ret = 1; + lastmod = mod.st_mtime; + } + lastcheck = check; + return ret; +} diff --git a/src/cmd/uucp/anyread.c b/src/cmd/uucp/anyread.c new file mode 100644 index 0000000..18db726 --- /dev/null +++ b/src/cmd/uucp/anyread.c @@ -0,0 +1,25 @@ +#ifndef lint +static char sccsid[] = "@(#)anyread.c 5.4 (Berkeley) 6/19/85"; +#endif + +#include "uucp.h" +#include + +/*LINTLIBRARY*/ + +/* + * anyread check if anybody can read + * return SUCCESS ok: FAIL not ok + */ +anyread(file) +char *file; +{ + struct stat s; + + if (stat(subfile(file), &s) < 0) + /* for security check a non existant file is readable */ + return SUCCESS; + if (!(s.st_mode & ANYREAD)) + return FAIL; + return SUCCESS; +} diff --git a/src/cmd/uucp/assert.c b/src/cmd/uucp/assert.c new file mode 100644 index 0000000..986a58d --- /dev/null +++ b/src/cmd/uucp/assert.c @@ -0,0 +1,51 @@ +#ifndef lint +static char sccsid[] = "@(#)assert.c 5.5 (Berkeley) 6/19/85"; +#endif + +#include "uucp.h" +#include +#include + +/*LINTLIBRARY*/ + +/* + * print out assetion error + */ + +assert(s1, s2, i1) +char *s1, *s2; +{ + register FILE *errlog; + register struct tm *tp; + extern struct tm *localtime(); + time_t clock; + int pid; + + errlog = NULL; + if (!Debug) { + int savemask; + savemask = umask(LOGMASK); + errlog = fopen(ERRLOG, "a"); + umask(savemask); + } + if (errlog == NULL) + errlog = stderr; + + pid = getpid(); + fprintf(errlog, "ASSERT ERROR (%.9s) ", Progname); + fprintf(errlog, "pid: %d ", pid); + clock = time(NULL); + tp = localtime(&clock); +#ifdef USG + fprintf(errlog, "(%d/%d-%2.2d:%2.2d) ", tp->tm_mon + 1, + tp->tm_mday, tp->tm_hour, tp->tm_min); +#endif +#ifndef USG + fprintf(errlog, "(%d/%d-%02d:%02d) ", tp->tm_mon + 1, + tp->tm_mday, tp->tm_hour, tp->tm_min); +#endif + fprintf(errlog, "%s %s (%d)\n", s1 ? s1 : "", s2 ? s2 : "", i1); + if (errlog != stderr) + (void) fclose(errlog); + return; +} diff --git a/src/cmd/uucp/cfgets.c b/src/cmd/uucp/cfgets.c new file mode 100644 index 0000000..a8f399e --- /dev/null +++ b/src/cmd/uucp/cfgets.c @@ -0,0 +1,61 @@ +#ifndef lint +static char sccsid[] = "@(#)cfgets.c 5.3 (Berkeley) 6/19/85"; +#endif + +/* + * get nonblank, non-comment, (possibly continued) line. Alan S. Watt + */ + +#include +#include +#define COMMENT '#' +#define CONTINUE '\\' +#define EOLN '\n' +#define EOS '\0' + +/*LINTLIBRARY*/ + +char * +cfgets(buf, siz, fil) +register char *buf; +int siz; +FILE *fil; +{ + register char *s; + register i, c, len; + char *fgets(); + + for (i=0,s=buf; i = (fgets(s, siz-i, fil) != NULL); i = s - buf) { + + /* get last character of line */ + c = s[len = (strlen(s) - 1)]; + + /* skip comments; make sure end of comment line seen */ + if (*s == COMMENT) { + while (c != EOLN && c != EOF) + c = getc(fil); + *s = EOS; + } + + /* skip blank lines */ + else if (*s != EOLN) { + s += len; + + /* continue lines ending with CONTINUE */ + if (c != EOLN || *--s != CONTINUE) + break; + } + } + + return i ? buf : NULL; +} + +#ifdef TEST +main() +{ + char buf[512]; + + while (cfgets(buf, sizeof buf, stdin)) + fputs(buf, stdout); +} +#endif diff --git a/src/cmd/uucp/chkpth.c b/src/cmd/uucp/chkpth.c new file mode 100644 index 0000000..3113041 --- /dev/null +++ b/src/cmd/uucp/chkpth.c @@ -0,0 +1,250 @@ +#if !defined(lint) && defined(DOSCCS) +static char sccsid[] = "@(#)chkpth.c 5.4.1 (2.11BSD) 1997/10/2"; +#endif + +#include "uucp.h" +#include +#include + +struct userpath { + char *us_lname; + char *us_mname; + char us_callback; + char **us_path; + struct userpath *unext; +}; +struct userpath *Uhead = NULL; +struct userpath *Mchdef = NULL, *Logdef = NULL; +int Uptfirst = 1; + +/*LINTLIBRARY*/ + +/* + * this routine will check the path table for the + * machine or log name (non-null parameter) to see if the + * input path (path) starts with an acceptable prefix. + * + * return codes: 0 | FAIL + */ + +chkpth(logname, mchname, path) +char *path, *logname, *mchname; +{ + register struct userpath *u; + extern char *lastpart(); + register char **p, *s; + + /* Allow only rooted pathnames. Security wish. rti!trt */ + if (*path != '/') { + DEBUG(4, "filename doesn't begin with /\n", CNULL); + return FAIL; + } + + if (Uptfirst) { + rdpth(); + ASSERT(Uhead != NULL, "INIT USERFILE, No entrys!", CNULL, 0); + Uptfirst = 0; + } + for (u = Uhead; u != NULL; ) { + if (*logname != '\0' && strcmp(logname, u->us_lname) == SAME) + break; + if (*mchname != '\0' && strncmp(mchname, u->us_mname, MAXBASENAME) == SAME) + break; + u = u->unext; + } + if (u == NULL) { + if (*logname == '\0') + u = Mchdef; + else + u = Logdef; + if (u == NULL) + return FAIL; + } + + /* check for /../ in path name */ + for (s = path; *s != '\0'; s++) { + if (prefix("/../",s)) { + DEBUG(4, "filename has /../ in it\n", CNULL); + return FAIL; + } + } + + /* Check for access permission */ + for (p = u->us_path; *p != NULL; p++) + if (prefix(*p, path)) + return SUCCESS; + DEBUG(4, "filename not in list\n", CNULL); + + /* path name not valid */ + return FAIL; +} + + +/*** + * rdpth() + * + * rdpth - this routine will read the USERFILE and + * construct the userpath structure pointed to by (u); + * + */ + +rdpth() +{ + char buf[100 + 1], *pbuf[50 + 1]; + register struct userpath *u; + register char *pc, **cp; + FILE *uf; + + if ((uf = fopen(USERFILE, "r")) == NULL) { + /* can not open file */ + return; + } + + while (cfgets(buf, sizeof(buf), uf) != NULL) { + int nargs, i; + + u = (struct userpath *)malloc(sizeof (struct userpath)); + if (u == NULL) { + DEBUG (1, "*** Userpath malloc failed\n", 0); + fclose (uf); + return; + } + if ((pc = (char *)calloc((unsigned)strlen(buf) + 1, sizeof (char))) + == NULL) { + /* can not allocate space */ + DEBUG (1, "Userpath calloc 1 failed\n", 0); + fclose(uf); + return; + } + + strcpy(pc, buf); + nargs = getargs(pc, pbuf, 50); + u->us_lname = pbuf[0]; + pc = index(u->us_lname, ','); + if (pc != NULL) + *pc++ = '\0'; + else + pc = u->us_lname + strlen(u->us_lname); + u->us_mname = pc; + if (strlen(u->us_mname) > MAXBASENAME) + u->us_mname[MAXBASENAME] = '\0'; + if (*u->us_lname == '\0' && Logdef == NULL) + Logdef = u; + if (*u->us_mname == '\0' && Mchdef == NULL) + Mchdef = u; + i = 1; + if (strcmp(pbuf[1], "c") == SAME) { + u->us_callback = 1; + i++; + } + else + u->us_callback = 0; + cp = (char **)calloc((unsigned)(nargs-i+1), sizeof(char *)); + if (cp == NULL) { + /* can not allocate space */ + DEBUG (1, "Userpath calloc 2 failed!\n", 0); + fclose(uf); + return; + } + u->us_path = cp; + + while (i < nargs) + *cp++ = pbuf[i++]; + *cp = NULL; + u->unext = Uhead; + Uhead = u; + } + + fclose(uf); + return; +} + +/*** + * callback(name) check for callback + * char *name; + * + * return codes: + * 0 - no call back + * 1 - call back + */ + +callback(name) +register char *name; +{ + register struct userpath *u; + + if (Uptfirst) { + rdpth(); + ASSERT(Uhead != NULL, "INIT USERFILE, No Users!", CNULL, 0); + Uptfirst = 0; + } + + for (u = Uhead; u != NULL; ) { + if (strcmp(u->us_lname, name) == SAME) + /* found user name */ + return u->us_callback; + u = u->unext; + } + + /* userid not found */ + return 0; +} + + +/*** + * chkperm(file, mopt) check write permission of file + * char *mopt; none NULL - create directories + * + * if mopt != NULL and permissions are ok, + * a side effect of this routine is to make + * directories up to the last part of the + * filename (if they do not exist). + * + * return SUCCESS | FAIL + */ + +chkperm(file, mopt) +char *file, *mopt; +{ + struct stat s; + int ret; + char dir[MAXFULLNAME]; + extern char *lastpart(); + + if (stat(subfile(file), &s) == 0) { + if ((s.st_mode & ANYWRITE) == 0) { + DEBUG(4,"file is not writable: mode %o\n", s.st_mode); + return FAIL; + } + return SUCCESS; + } + + strcpy(dir, file); + *lastpart(dir) = '\0'; + if ((ret = stat(subfile(dir), &s)) == -1 && mopt == NULL) { + DEBUG(4, "can't stat directory %s\n", subfile(dir)); + return FAIL; + } + + if (ret != -1) { + if ((s.st_mode & ANYWRITE) == 0) + return FAIL; + else + return SUCCESS; + } + + /* make directories */ + return mkdirs(file); +} + +/* + * Check for sufficient privilege to request debugging. + */ +chkdebug() +{ + if (access(SYSFILE, 04) < 0) { + fprintf(stderr, "Sorry, you must be able to read L.sys for debugging\n"); + cleanup(1); + exit(1); /* Just in case */ + } +} diff --git a/src/cmd/uucp/chksum.c b/src/cmd/uucp/chksum.c new file mode 100644 index 0000000..dd0b25e --- /dev/null +++ b/src/cmd/uucp/chksum.c @@ -0,0 +1,56 @@ +#ifndef lint +static char sccsid[] = "@(#)chksum.c 4.2 (Berkeley) 6/19/85"; +#endif + +#ifndef pdp11 +chksum (s, n) +register char *s; +register n; +{ + register long sum, x, t; + + sum = 0xffff; + x = 0; + do { + /* Rotate left, copying bit 15 to bit 0 */ + sum <<= 1; + if (sum & 0x10000) + sum ^= 0x10001; + t = sum; + sum = (sum + (*s++ & 0377)) & 0xffff; + x += sum ^ n; + if (sum <= t) + sum = (sum ^ x) & 0xffff; + } while (--n > 0); + + return (long) (short) sum; +} +#else +chksum(s,n) +register char *s; +register n; +{ + register unsigned sum, t; + register x; + + sum = -1; + x = 0; + + do { + if (sum&0x8000) { + sum <<= 1; + sum++; + } else + sum <<= 1; + t = sum; + sum += (unsigned)*s++ & 0377; + x += sum^n; + if ((sum&0xffff) <= (t&0xffff)) { + sum ^= x; + } + } while (--n > 0); + + return sum & 0xffff; +} + +#endif diff --git a/src/cmd/uucp/cico.c b/src/cmd/uucp/cico.c new file mode 100644 index 0000000..c99c73d --- /dev/null +++ b/src/cmd/uucp/cico.c @@ -0,0 +1,896 @@ +#if !defined(lint) && defined(DOSCCS) +static char sccsid[] = "@(#)cico.c 5.14.1 (2.11BSD) 1997/10/2"; +#endif + +#include +#include "uucp.h" +#include +#ifdef USG +#include +#endif +#ifndef USG +#include +#endif +#ifdef BSDTCP +#include +#include +#include +#include +#endif +#include +#include "uust.h" +#include "uusub.h" + +#if defined(VMS) && defined(BSDTCP) +#define NOGETPEER +#endif + +#ifdef BSD2_9 +#define NOGETPEER +#endif + +jmp_buf Sjbuf; +jmp_buf Pipebuf; + +/* call fail text */ +char *Stattext[] = { + "", + "BAD SYSTEM", + "WRONG TIME TO CALL", + "SYSTEM LOCKED", + "NO DEVICE", + "CALL FAILED", + "LOGIN FAILED", + "BAD SEQUENCE" +}; + +/* call fail codes */ +int Stattype[] = { + 0, + 0, + SS_WRONGTIME, + 0, + SS_NODEVICE, + SS_FAIL, + SS_FAIL, + SS_BADSEQ +}; + + /* Arguments to setdebug(): */ +#define DBG_TEMP 0 /* Create a temporary audit file */ +#define DBG_PERM 1 /* Create a permanent audit file */ +#define DBG_CLEAN 2 /* Cleanup, discard temp file */ + +int ReverseRole = 0; +int Role = SLAVE; +int onesys = 0; +int turntime = 30 * 60; /* 30 minutes expressed in seconds */ +char *ttyn = NULL; +extern int LocalOnly; +extern int errno; +extern char MaxGrade, DefMaxGrade; +extern char Myfullname[]; + +#ifdef USG +struct termio Savettyb; +#endif +#ifndef USG +struct sgttyb Savettyb; +#endif + +/* + * this program is used to place a call to a + * remote machine, login, and copy files between the two machines. + */ +main(argc, argv) +int argc; +register char *argv[]; +{ + register int ret; + int seq; + char wkpre[NAMESIZE], file[NAMESIZE]; + char msg[MAXFULLNAME], *q; + register char *p; + extern onintr(), timeout(), dbg_signal(); + extern char *pskip(); + char rflags[MAXFULLNAME]; +#ifdef NOGETPEER + u_long Hostnumber = 0; +#endif + + strcpy(Progname, "uucico"); + +#ifdef BSD4_2 + sigsetmask(0L); /* in case we inherit blocked signals */ +#endif + signal(SIGINT, (sig_t)onintr); + signal(SIGHUP, (sig_t)onintr); + signal(SIGQUIT, (sig_t)onintr); + signal(SIGTERM, (sig_t)onintr); + signal(SIGPIPE, (sig_t)onintr); /* 4.1a tcp-ip stupidity */ + signal(SIGFPE, (sig_t)dbg_signal); + ret = guinfo(getuid(), User, msg); + strcpy(Loginuser, User); + uucpname(Myname); + ASSERT(ret == 0, "BAD UID", CNULL, ret); + + setbuf (stderr, CNULL); + + rflags[0] = '\0'; + umask(WFMASK); + strcpy(Rmtname, Myname); + Ifn = Ofn = -1; + while(argc>1 && argv[1][0] == '-'){ + switch(argv[1][1]){ + case 'd': + Spool = &argv[1][2]; + break; + case 'g': + case 'p': + MaxGrade = DefMaxGrade = argv[1][2]; + break; + case 'r': + Role = atoi(&argv[1][2]); + break; + case 'R': + ReverseRole++; + Role = MASTER; + break; + case 's': + strncpy(Rmtname, &argv[1][2], MAXBASENAME); + Rmtname[MAXBASENAME] = '\0'; + if (Rmtname[0] != '\0') + onesys = 1; + break; + case 'x': + Debug = atoi(&argv[1][2]); + if (Debug <= 0) + Debug = 1; + strcat(rflags, argv[1]); + break; + case 't': + turntime = atoi(&argv[1][2])*60;/* minutes to seconds */ + break; + case 'L': /* local calls only */ + LocalOnly++; + break; +#ifdef NOGETPEER + case 'h': + Hostnumber = inet_addr(&argv[1][2]); + break; +#endif + default: + printf("unknown flag %s (ignored)\n", argv[1]); + break; + } + --argc; argv++; + } + + while (argc > 1) { + fprintf(stderr, "unknown argument %s (ignored)\n", argv[1]); + --argc; argv++; + } + + if (Debug && Role == MASTER) + chkdebug(); + + /* Try to run as uucp */ + setgid(getegid()); + setuid(geteuid()); +#ifdef TIOCNOTTY + /* + * detach uucico from controlling terminal + * to defend against rlogind sending us a SIGKILL (!!!) + */ + if (Role == MASTER && (ret = open("/dev/tty", 2)) >= 0) { + ioctl(ret, TIOCNOTTY, STBNULL); + close(ret); + } +#endif +#ifdef BSD4_2 + if (getpgrp(0) == 0) { /* We have no controlling terminal */ + setpgrp(0, getpid()); + } +#endif + + ret = subchdir(Spool); + ASSERT(ret >= 0, "CHDIR FAILED", Spool, ret); + strcpy(Wrkdir, Spool); + + if (Debug) { + setdebug ((Role == SLAVE) ? DBG_TEMP : DBG_PERM); + if (Debug > 0) + logent ("Local Enabled", "DEBUG"); + } + + /* + * First time through: If we're the slave, do initial checking. + */ + if (Role == SLAVE) { + /* check for /etc/nologin */ + if (access(NOLOGIN, 0) == 0) { + logent(NOLOGIN, "UUCICO SHUTDOWN"); + if (Debug > 4) + logent("DEBUGGING", "continuing anyway"); + else + cleanup(1); + } + Ifn = 0; + Ofn = 1; +#ifdef TCPIP + /* + * Determine if we are on TCPIP + */ + if (isatty(Ifn) < 0) { + IsTcpIp = 1; + DEBUG(4, "TCPIP connection -- ioctl-s disabled\n", CNULL); + } else + IsTcpIp = 0; +#endif + /* initial handshake */ + onesys = 1; + if (!IsTcpIp) { +#ifdef USG + ret = ioctl(Ifn, TCGETA, &Savettyb); + Savettyb.c_cflag = (Savettyb.c_cflag & ~CS8) | CS7; + Savettyb.c_oflag |= OPOST; + Savettyb.c_lflag |= (ISIG|ICANON|ECHO); +#else + ret = ioctl(Ifn, TIOCGETP, &Savettyb); + Savettyb.sg_flags |= ECHO; + Savettyb.sg_flags &= ~RAW; +#endif + ttyn = ttyname(Ifn); + } + fixmode(Ifn); + + /* + * Initial Message -- tell them we're here, and who we are. + */ + sprintf(msg, "here=%s", Myfullname); + omsg('S', msg, Ofn); + signal(SIGALRM, (sig_t)timeout); + alarm(MAXMSGTIME); + if (setjmp(Sjbuf)) { + /* timed out */ + if (!IsTcpIp) { +#ifdef USG + ret = ioctl(Ifn, TCSETA, &Savettyb); + +#else + ret = ioctl(Ifn, TIOCSETP, &Savettyb); +#endif + } + cleanup(0); + } + for (;;) { + ret = imsg(msg, Ifn); + if (ret != SUCCESS) { + alarm(0); + if (!IsTcpIp) { +#ifdef USG + ret = ioctl(Ifn, TCSETA, &Savettyb); +#else + ret = ioctl(Ifn, TIOCSETP, &Savettyb); +#endif + } + cleanup(0); + } + if (msg[0] == 'S') + break; + } + alarm(0); + q = &msg[1]; + p = pskip(q); + strncpy(Rmtname, q, MAXBASENAME); + Rmtname[MAXBASENAME] = '\0'; + + /* + * Now that we know who they are, give the audit file the right + * name. + */ + setdebug (DBG_PERM); + DEBUG(4, "sys-%s\n", Rmtname); + /* The versys will also do an alias on the incoming name */ + if (versys(&Rmtname)) { + /* If we don't know them, we won't talk to them... */ +#ifdef NOSTRANGERS + logent(Rmtname, "UNKNOWN HOST"); + omsg('R', "You are unknown to me", Ofn); + cleanup(0); +#endif + } +#ifdef BSDTCP + /* we must make sure they are really who they say they + * are. We compare the hostnumber with the number in the hosts + * table for the site they claim to be. + */ + if (IsTcpIp) { + struct hostent *hp; + char *cpnt, *inet_ntoa(); + int fromlen; + struct sockaddr_in from; + extern char PhoneNumber[]; + +#ifdef NOGETPEER + from.sin_addr.s_addr = Hostnumber; + from.sin_family = AF_INET; +#else + fromlen = sizeof(from); + if (getpeername(Ifn, &from, &fromlen) < 0) { + logent(Rmtname, "NOT A TCP CONNECTION"); + omsg('R', "NOT TCP", Ofn); + cleanup(0); + } +#endif + hp = gethostbyaddr(&from.sin_addr, + sizeof (struct in_addr), from.sin_family); + if (hp == NULL) { + /* security break or just old host table? */ + logent(Rmtname, "UNKNOWN IP-HOST Name ="); + cpnt = inet_ntoa(from.sin_addr), + logent(cpnt, "UNKNOWN IP-HOST Number ="); + sprintf(wkpre, "%s/%s isn't in my host table", + Rmtname, cpnt); + omsg('R' ,wkpre ,Ofn); + cleanup(0); + } + if (Debug > 99) + logent(Rmtname,"Request from IP-Host name ="); + /* + * The following is to determine if the name given us by + * the Remote uucico matches any of the names + * given its network number (remote machine) in our + * host table. + * We could check the aliases, but that won't work in + * all cases (like if you are running the domain + * server, where you don't get any aliases). The only + * reliable way I can think of that works in ALL cases + * is too look up the site in L.sys and see if the + * sitename matches what we would call him if we + * originated the call. + */ + /* PhoneNumber contains the official network name of the host we are checking. (set in versys.c) */ + if (sncncmp(PhoneNumber, hp->h_name, SYSNSIZE) == 0) { + if (Debug > 99) + logent(q,"Found in host Tables"); + } else { + logent(hp->h_name, "FORGED HOSTNAME"); + logent(inet_ntoa(from.sin_addr), "ORIGINATED AT"); + logent(PhoneNumber, "SHOULD BE"); + sprintf(wkpre, "You're not who you claim to be: %s != %s", hp->h_name, PhoneNumber); + omsg('R', wkpre, Ofn); + cleanup(0); + } + } +#endif + + if (mlock(Rmtname)) { + omsg('R', "LCK", Ofn); + cleanup(0); + } + else if (callback(Loginuser)) { + signal(SIGINT, SIG_IGN); + signal(SIGHUP, SIG_IGN); + omsg('R', "CB", Ofn); + logent("CALLBACK", "REQUIRED"); + /* set up for call back */ + systat(Rmtname, SS_CALLBACK, "CALLING BACK"); + gename(CMDPRE, Rmtname, 'C', file); + close(creat(subfile(file), 0666)); + xuucico(Rmtname); + cleanup(0); + } + seq = 0; + while (*p == '-') { + q = pskip(p); + switch(*(++p)) { + case 'x': + if (Debug == 0) { + Debug = atoi(++p); + if (Debug <= 0) + Debug = 1; + setdebug(DBG_PERM); + if (Debug > 0) + logent("Remote Enabled", "DEBUG"); + } else { + DEBUG(1, "Remote debug request ignored\n", + CNULL); + } + break; + case 'Q': + seq = atoi(++p); + break; + case 'p': + MaxGrade = DefMaxGrade = *++p; + DEBUG(4, "MaxGrade set to %c\n", MaxGrade); + break; + case 'v': + if (strncmp(p, "grade", 5) == 0) { + p += 6; + MaxGrade = DefMaxGrade = *p++; + DEBUG(4, "MaxGrade set to %c\n", MaxGrade); + } + break; + default: + break; + } + p = q; + } + if (callok(Rmtname) == SS_BADSEQ) { + logent("BADSEQ", "PREVIOUS"); + omsg('R', "BADSEQ", Ofn); + cleanup(0); + } +#ifdef GNXSEQ + if ((ret = gnxseq(Rmtname)) == seq) { + omsg('R', "OK", Ofn); + cmtseq(); + } else { +#else + if (seq == 0) + omsg('R', "OK", Ofn); + else { +#endif + systat(Rmtname, Stattype[7], Stattext[7]); + logent("BAD SEQ", "FAILED HANDSHAKE"); +#ifdef GNXSEQ + ulkseq(); +#endif + omsg('R', "BADSEQ", Ofn); + cleanup(0); + } + if (ttyn != NULL) + chmod(ttyn, 0600); + } + +loop: + if(setjmp(Pipebuf)) { /* come here on SIGPIPE */ + clsacu(); + close(Ofn); + close(Ifn); + Ifn = Ofn = -1; + rmlock(CNULL); + sleep(3); + } + if (!onesys) { + ret = gnsys(Rmtname, Spool, CMDPRE); + setdebug(DBG_PERM); + if (ret == FAIL) + cleanup(100); + if (ret == SUCCESS) + cleanup(0); + } else if (Role == MASTER && callok(Rmtname) != 0) { + logent("SYSTEM STATUS", "CAN NOT CALL"); + cleanup(0); + } + + sprintf(wkpre, "%c.%.*s", CMDPRE, SYSNSIZE, Rmtname); + + signal(SIGINT, SIG_IGN); + signal(SIGQUIT, SIG_IGN); + if (Role == MASTER) { + /* check for /etc/nologin */ + if (access(NOLOGIN, 0) == 0) { + logent(NOLOGIN, "UUCICO SHUTDOWN"); + if (Debug > 4) + logent("DEBUGGING", "continuing anyway"); + else + cleanup(1); + } + /* master part */ + signal(SIGHUP, SIG_IGN); + if (Ifn != -1 && Role == MASTER) { + write(Ofn, EOTMSG, strlen(EOTMSG)); + clsacu(); + close(Ofn); + close(Ifn); + Ifn = Ofn = -1; + rmlock(CNULL); + sleep(3); + } + sprintf(msg, "call to %s ", Rmtname); + if (mlock(Rmtname) != SUCCESS) { + logent(msg, "LOCKED"); + US_SST(us_s_lock); + goto next; + } + Ofn = Ifn = conn(Rmtname); + if (Ofn < 0) { + if (Ofn != CF_TIME) + logent(msg, _FAILED); + /* avoid excessive 'wrong time' info */ + if (Stattype[-Ofn] != SS_WRONGTIME){ + systat(Rmtname, Stattype[-Ofn], Stattext[-Ofn]); + US_SST(-Ofn); + UB_SST(-Ofn); + } + goto next; + } else { + logent(msg, "SUCCEEDED"); + US_SST(us_s_cok); + UB_SST(ub_ok); + } +#ifdef TCPIP + /* + * Determine if we are on TCPIP + */ + if (isatty(Ifn) == 0) { + IsTcpIp = 1; + DEBUG(4, "TCPIP connection -- ioctl-s disabled\n", CNULL); + } else + IsTcpIp = 0; +#endif + + if (setjmp(Sjbuf)) + goto next; + signal(SIGALRM, (sig_t)timeout); + alarm(2 * MAXMSGTIME); + for (;;) { + ret = imsg(msg, Ifn); + if (ret != 0) { + alarm(0); + logent("imsg 1", _FAILED); + goto Failure; + } + if (msg[0] == 'S') + break; + } + alarm(MAXMSGTIME); +#ifdef GNXSEQ + seq = gnxseq(Rmtname); +#else + seq = 0; +#endif + if (MaxGrade != '\177') { + DEBUG(2, "Max Grade this transfer is %c\n", MaxGrade); + sprintf(msg, "%s -Q%d -p%c -vgrade=%c %s", + Myname, seq, MaxGrade, MaxGrade, rflags); + } else + sprintf(msg, "%s -Q%d %s", Myname, seq, rflags); + omsg('S', msg, Ofn); + for (;;) { + ret = imsg(msg, Ifn); + DEBUG(4, "msg-%s\n", msg); + if (ret != SUCCESS) { + alarm(0); +#ifdef GNXSEQ + ulkseq(); +#endif + logent("imsg 2", _FAILED); + goto Failure; + } + if (msg[0] == 'R') + break; + } + alarm(0); + if (msg[1] == 'B') { + /* bad sequence */ + logent("BAD SEQ", "FAILED HANDSHAKE"); + US_SST(us_s_hand); + systat(Rmtname, SS_BADSEQ, Stattext[SS_BADSEQ]); +#ifdef GNXSEQ + ulkseq(); +#endif + goto next; + } + if (strcmp(&msg[1], "OK") != SAME) { + logent(&msg[1], "FAILED HANDSHAKE"); + US_SST(us_s_hand); +#ifdef GNXSEQ + ulkseq(); +#endif + systat(Rmtname, SS_INPROGRESS, + strcmp(&msg[1], "CB") == SAME? + "AWAITING CALLBACK": "FAILED HANDSHAKE"); + goto next; + } +#ifdef GNXSEQ + cmtseq(); +#endif + } + DEBUG(1, "Rmtname %s, ", Rmtname); + DEBUG(1, "Role %s, ", Role ? "MASTER" : "SLAVE"); + DEBUG(1, "Ifn - %d, ", Ifn); + DEBUG(1, "Loginuser - %s\n", Loginuser); + + ttyn = ttyname(Ifn); + + alarm(MAXMSGTIME); + if (ret=setjmp(Sjbuf)) + goto Failure; + ret = startup(Role); + alarm(0); + if (ret != SUCCESS) { + logent("startup", _FAILED); +Failure: + US_SST(us_s_start); + systat(Rmtname, SS_FAIL, ret > 0 ? "CONVERSATION FAILED" : + "STARTUP FAILED"); + goto next; + } else { + if (ttyn != NULL) { + char startupmsg[BUFSIZ]; + extern int linebaudrate; + sprintf(startupmsg, "startup %s %d baud", &ttyn[5], + linebaudrate); + logent(startupmsg, "OK"); + } else + logent("startup", "OK"); + US_SST(us_s_gress); + systat(Rmtname, SS_INPROGRESS, "TALKING"); + ret = cntrl(Role, wkpre); + DEBUG(1, "cntrl - %d\n", ret); + signal(SIGINT, SIG_IGN); + signal(SIGHUP, SIG_IGN); + signal(SIGALRM, (sig_t)timeout); + if (ret == SUCCESS) { + logent("conversation complete", "OK"); + US_SST(us_s_ok); + rmstat(Rmtname); + + } else { + logent("conversation complete", _FAILED); + US_SST(us_s_cf); + systat(Rmtname, SS_FAIL, "CONVERSATION FAILED"); + } + alarm(MAXMSGTIME); + DEBUG(4, "send OO %d,", ret); + if (!setjmp(Sjbuf)) { + for (;;) { + omsg('O', "OOOOO", Ofn); + ret = imsg(msg, Ifn); + if (ret != 0) + break; + if (msg[0] == 'O') + break; + } + } + alarm(0); + clsacu(); + rmlock(CNULL); + } +next: + if (!onesys) { + goto loop; + } + cleanup(0); +} + +#ifndef USG +struct sgttyb Hupvec; +#endif + +/* + * cleanup and exit with "code" status + */ +cleanup(code) +register int code; +{ + signal(SIGINT, SIG_IGN); + signal(SIGHUP, SIG_IGN); + rmlock(CNULL); + sleep(5); /* Wait for any pending output */ + clsacu(); + logcls(); + if (Role == SLAVE) { + if (!IsTcpIp) { +#ifdef USG + Savettyb.c_cflag |= HUPCL; + (void) ioctl(0, TCSETA, &Savettyb); +#else + (void) ioctl(0, TIOCHPCL, STBNULL); +#ifdef TIOCSDTR + (void) ioctl(0, TIOCCDTR, STBNULL); + sleep(2); + (void) ioctl(0, TIOCSDTR, STBNULL); +#else + (void) ioctl(0, TIOCGETP, &Hupvec); + Hupvec.sg_ispeed = B0; + Hupvec.sg_ospeed = B0; + (void) ioctl(0, TIOCSETP, &Hupvec); +#endif + sleep(2); + (void) ioctl(0, TIOCSETP, &Savettyb); + /* make *sure* exclusive access is off */ + (void) ioctl(0, TIOCNXCL, STBNULL); +#endif + } + if (ttyn != NULL) + chmod(ttyn, 0600); + } + if (Ofn != -1) { + if (Role == MASTER) + write(Ofn, EOTMSG, strlen(EOTMSG)); + close(Ifn); + close(Ofn); + } +#ifdef DIALINOUT + /* reenable logins on dialout */ + reenable(); +#endif + if (code == 0) + xuuxqt(); + else + DEBUG(1, "exit code %d\n", code); + setdebug (DBG_CLEAN); + exit(code); +} + +/* + * on interrupt - remove locks and exit + */ + +onintr(inter) +register int inter; +{ + char str[30]; + signal(inter, SIG_IGN); + sprintf(str, "SIGNAL %d", inter); + logent(str, "CAUGHT"); + US_SST(us_s_intr); + if (*Rmtname && strncmp(Rmtname, Myname, MAXBASENAME)) + systat(Rmtname, SS_FAIL, str); + if (inter == SIGPIPE && !onesys) + longjmp(Pipebuf, 1); + cleanup(inter); +} + +/* + * Catch a special signal + * (SIGFPE, ugh), and toggle debugging between 0 and 30. + * Handy for looking in on long running uucicos. + */ +dbg_signal() +{ + Debug = (Debug == 0) ? 30 : 0; + setdebug(DBG_PERM); + if (Debug > 0) + logent("Signal Enabled", "DEBUG"); +} + + +/* + * Check debugging requests, and open RMTDEBUG audit file if necessary. If an + * audit file is needed, the parm argument indicates how to create the file: + * + * DBG_TEMP - Open a temporary file, with filename = RMTDEBUG/pid. + * DBG_PERM - Open a permanent audit file, filename = RMTDEBUG/Rmtname. + * If a temp file already exists, it is mv'ed to be permanent. + * DBG_CLEAN - Cleanup; unlink temp files. + * + * Restrictions - this code can only cope with one open debug file at a time. + * Each call creates a new file; if an old one of the same name exists it will + * be overwritten. + */ +setdebug(parm) +int parm; +{ + char buf[BUFSIZ]; /* Buffer for building filenames */ + static char *temp = NULL; /* Ptr to temporary file name */ + static int auditopen = 0; /* Set to 1 when we open a file */ + struct stat stbuf; /* File status buffer */ + + /* + * If movement or cleanup of a temp file is indicated, we do it no + * matter what. + */ + if (temp != CNULL && parm == DBG_PERM) { + sprintf(buf, "%s/%s", RMTDEBUG, Rmtname); + unlink(buf); + if (link(temp, buf) != 0) { + Debug = 0; + assert("RMTDEBUG LINK FAIL", temp, errno); + cleanup(1); + } + parm = DBG_CLEAN; + } + if (parm == DBG_CLEAN) { + if (temp != CNULL) { + unlink(temp); + free(temp); + temp = CNULL; + } + return; + } + + if (Debug == 0) + return; /* Gotta be in debug to come here. */ + + /* + * If we haven't opened a file already, we can just return if it's + * alright to use the stderr we came in with. We can if: + * + * Role == MASTER, and Stderr is a regular file, a TTY or a pipe. + * + * Caution: Detecting when stderr is a pipe is tricky, because the 4.2 + * man page for fstat(2) disagrees with reality, and System V leaves it + * undefined, which means different implementations act differently. + */ + if (!auditopen && Role == MASTER) { + if (isatty(fileno(stderr))) + return; + else if (fstat(fileno(stderr), &stbuf) == 0) { +#ifdef USG + /* Is Regular File or Fifo */ + if ((stbuf.st_mode & 0060000) == 0) + return; +#else +#ifdef BSD4_2 + /* Is Regular File */ + if ((stbuf.st_mode & S_IFMT) == S_IFREG || + stbuf.st_mode == 0) /* Is a pipe */ + return; +#else + /* Is Regular File or Pipe */ + if ((stbuf.st_mode & S_IFMT) == S_IFREG) + return; +#endif +#endif + } + } + + /* + * We need RMTDEBUG directory to do auditing. If the file doesn't exist, + * then we forget about debugging; if it exists but has improper owner- + * ship or modes, we gripe about it in ERRLOG. + */ + if (stat(RMTDEBUG, &stbuf) != SUCCESS) { + Debug = 0; + return; + } + if ((geteuid() != stbuf.st_uid) || /* We must own it */ + ((stbuf.st_mode & 0170700) != 040700)) { /* Directory, rwx */ + Debug = 0; + assert("INVALID RMTDEBUG DIRECTORY:", RMTDEBUG, stbuf.st_mode); + return; + } + + if (parm == DBG_TEMP) { + sprintf(buf, "%s/%d", RMTDEBUG, getpid()); + temp = (char *)malloc(strlen (buf) + 1); + if (temp == CNULL) { + Debug = 0; + assert("RMTDEBUG MALLOC ERROR:", temp, errno); + cleanup(1); + } + strcpy(temp, buf); + } else + sprintf(buf, "%s/%s", RMTDEBUG, Rmtname); + + unlink(buf); + if (freopen(buf, "w", stderr) != stderr) { + Debug = 0; + assert("FAILED RMTDEBUG FILE OPEN:", buf, errno); + cleanup(1); + } + setbuf(stderr, CNULL); + auditopen = 1; +} + +/* + * catch SIGALRM routine + */ +timeout() +{ + extern int HaveSentHup; + if (!HaveSentHup) { + logent(Rmtname, "TIMEOUT"); + if (*Rmtname && strncmp(Rmtname, Myname, MAXBASENAME)) { + US_SST(us_s_tmot); + systat(Rmtname, SS_FAIL, "TIMEOUT"); + } + } + longjmp(Sjbuf, 1); +} + +char * +pskip(p) +register char *p; +{ + while(*p && *p != ' ') + ++p; + while(*p && *p == ' ') + *p++ = 0; + return p; +} diff --git a/src/cmd/uucp/cntrl.c b/src/cmd/uucp/cntrl.c new file mode 100644 index 0000000..1b426c8 --- /dev/null +++ b/src/cmd/uucp/cntrl.c @@ -0,0 +1,942 @@ +#ifndef lint +static char sccsid[] = "@(#)cntrl.c 5.8 (Berkeley) 1/24/86"; +#endif + +#include "uucp.h" +#include +#include +#include "uust.h" + +extern int errno; +extern int turntime; +int willturn; +int HaveSentHup = 0; + +struct Proto { + char P_id; + int (*P_turnon)(); + int (*P_rdmsg)(); + int (*P_wrmsg)(); + int (*P_rddata)(); + int (*P_wrdata)(); + int (*P_turnoff)(); +}; + +extern int gturnon(), gturnoff(); +extern int grdmsg(), grddata(); +extern int gwrmsg(), gwrdata(); +extern int imsg(), omsg(), nullf(); +#ifdef TCPIP +extern int twrmsg(), trdmsg(); +extern int twrdata(), trddata(); +#endif +#ifdef PAD +extern int fturnon(), fturnoff(); +extern int frdmsg(), frddata(); +extern int fwrmsg(), fwrdata(); +#endif + +struct Proto Ptbl[]={ +#ifdef TCPIP + 't', nullf, trdmsg, twrmsg, trddata, twrdata, nullf, +#endif +#ifdef PAD + 'f', fturnon, frdmsg, fwrmsg, frddata, fwrdata, fturnoff, +#endif + 'g', gturnon, grdmsg, gwrmsg, grddata, gwrdata, gturnoff, + '\0' +}; + +int (*Imsg)() = imsg, (*Omsg)() = omsg; + +int (*Rdmsg)()=imsg, (*Rddata)(); +int (*Wrmsg)()=omsg, (*Wrdata)(); +int (*Turnon)()=nullf, (*Turnoff)() = nullf; + +struct timeb Now, LastTurned, LastCheckedNoLogin; + +static char *YES = "Y"; +static char *NO = "N"; + +int TransferSucceeded = 1; + +/* failure messages */ +#define EM_MAX 6 +#define EM_LOCACC "N1" /* local access to file denied */ +#define EM_RMTACC "N2" /* remote access to file/path denied */ +#define EM_BADUUCP "N3" /* a bad uucp command was generated */ +#define EM_NOTMP "N4" /* remote error - can't create temp */ +#define EM_RMTCP "N5" /* can't copy to remote directory - file in public */ +#define EM_LOCCP "N6" /* can't copy on local system */ + +char *Em_msg[] = { + "COPY FAILED (reason not given by remote)", + "local access to file denied", + "remote access to path/file denied", + "system error - bad uucp command generated", + "remote system can't create temp file", + "can't copy to file/directory - file left in PUBDIR/user/file", + "can't copy to file/directory on local system - file left in PUBDIR/user/file" +}; + + +#define XUUCP 'X' /* execute uucp (string) */ +#define SLTPTCL 'P' /* select protocol (string) */ +#define USEPTCL 'U' /* use protocol (character) */ +#define RCVFILE 'R' /* receive file (string) */ +#define SNDFILE 'S' /* send file (string) */ +#define RQSTCMPT 'C' /* request complete (string - yes | no) */ +#define HUP 'H' /* ready to hangup (string - yes | no) */ +#define RESET 'X' /* reset line modes */ + +#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 W_NUSER wrkvec[7] + +#define XFRRATE 35000L +#define RMESG(m, s, n) if (rmesg(m, s, n) != 0) {(*Turnoff)(); return FAIL;} else +#define RAMESG(s, n) if (rmesg('\0', s, n) != 0) {(*Turnoff)(); return FAIL;} else +#define WMESG(m, s) if(wmesg(m, s) != 0) {(*Turnoff)(); return FAIL;} else + +char Wfile[MAXFULLNAME] = {'\0'}; +char Dfile[MAXFULLNAME]; + +/* + * To avoid a huge backlog of X. files, start uuxqt every so often. + */ +static int nXfiles = 0; /* number of X files since last uuxqt start */ +static char send_or_receive; +struct stat stbuf; + +/* + * cntrl - this routine will execute the conversation + * between the two machines after both programs are + * running. + * + * return codes + * SUCCESS - ok + * FAIL - failed + */ + +cntrl(role, wkpre) +int role; +char *wkpre; +{ + char msg[BUFSIZ], rqstr[BUFSIZ]; + register FILE *fp; + int filemode; + char filename[MAXFULLNAME], wrktype, *wrkvec[20]; + extern (*Rdmsg)(), (*Wrmsg)(); + extern char *index(), *lastpart(); + int status = 1; + register int i, narg; + int mailopt, ntfyopt; + int ret; + static int pnum, tmpnum = 0; + extern int ReverseRole; + + pnum = getpid(); + Wfile[0] = '\0'; + willturn = turntime > 0; +remaster: +#ifdef USG + time(&LastTurned.time); + LastTurned.millitm = 0; +#else + ftime(&LastTurned); +#endif + send_or_receive = RESET; + HaveSentHup = 0; +top: + for (i = 0; i < sizeof wrkvec / sizeof wrkvec[0]; i++) + wrkvec[i] = 0; + DEBUG(4, "*** TOP *** - role=%s\n", role ? "MASTER" : "SLAVE"); + setupline(RESET); + if (Now.time > (LastCheckedNoLogin.time+60)) { + LastCheckedNoLogin = Now; + if (access(NOLOGIN, 0) == 0) { + logent(NOLOGIN, "UUCICO SHUTDOWN"); + if (Debug > 4) + logent("DEBUGGING", "continuing anyway"); + else { + WMESG(HUP, YES); + RMESG(HUP, msg, 1); + goto process; + } + } + } + if (role == MASTER) { + /* get work */ + if (ReverseRole || (narg = gtwvec(Wfile, Spool, wkpre, wrkvec)) == 0) { + ReverseRole = 0; + WMESG(HUP, ""); + RMESG(HUP, msg, 1); + goto process; + } + wrktype = W_TYPE[0]; + + msg[0] = '\0'; + for (i = 1; i < narg; i++) { + strcat(msg, " "); + strcat(msg, wrkvec[i]); + } + + if (wrktype == XUUCP) { + sprintf(rqstr, "X %s", msg); + logent(rqstr, "REQUEST"); + goto sendmsg; + } + mailopt = index(W_OPTNS, 'm') != NULL; + ntfyopt = index(W_OPTNS, 'n') != NULL; + + if (narg < 5) { + char *bnp; + bnp = rindex(Wfile, '/'); + sprintf(rqstr, "%s/%s", CORRUPT, bnp ? bnp + 1 : Wfile); + xmv(Wfile, rqstr); + logent(Wfile, "CMD FILE CORRUPTED"); + Wfile[0] = '\0'; + goto top; + } + sprintf(User, "%.9s", W_USER); + sprintf(rqstr, "%s %s %s %s", W_TYPE, W_FILE1, + W_FILE2, W_USER); + logent(rqstr, "REQUEST"); + if (wrktype == SNDFILE ) { + strcpy(filename, W_FILE1); + i = expfile(filename); + DEBUG(4, "expfile type - %d, ", i); + if (i != 0 && chkpth(User, "", filename)) + goto e_access; + strcpy(Dfile, W_DFILE); + fp = NULL; + if (index(W_OPTNS, 'c') == NULL) { + fp = fopen(subfile(Dfile), "r"); + if (fp != NULL) + i = 0; + } + if (fp == NULL && + (fp = fopen(subfile(filename), "r")) == NULL) { + /* can not read data file */ + logent("CAN'T READ DATA", _FAILED); + TransferSucceeded = 1; /* else will keep sending */ + USRF(USR_LOCACC); + unlinkdf(Dfile); + lnotify(User, filename, "can't access"); + goto top; + } + /* if file exists but is not generally readable... */ + if (i != 0 && fstat(fileno(fp), &stbuf) == 0 + && (stbuf.st_mode & ANYREAD) == 0) { + e_access:; + /* access denied */ + fclose(fp); + fp = NULL; + TransferSucceeded = 1; /* else will keep sending */ + logent("DENIED", "ACCESS"); + USRF(USR_LOCACC); + unlinkdf(W_DFILE); + lnotify(User, filename, "access denied"); + goto top; + } + + setupline(SNDFILE); + } + + if (wrktype == RCVFILE) { + strcpy(filename, W_FILE2); + expfile(filename); + if (chkpth(User, "", filename) + || chkperm(filename, index(W_OPTNS, 'd'))) { + /* access denied */ + logent("DENIED", "ACCESS"); + TransferSucceeded = 1; /* else will keep trying */ + USRF(USR_LOCACC); + lnotify(User, filename, "access denied"); + goto top; + } + sprintf(Dfile, "%s/TM.%05d.%03d", Spool, pnum, tmpnum++); + if ((fp = fopen(subfile(Dfile), "w")) == NULL) { + /* can not create temp */ + logent("CAN'T CREATE TM", _FAILED); + USRF(USR_LNOTMP); + unlinkdf(Dfile); + goto top; + } + setupline(RCVFILE); + } +sendmsg: + DEBUG(4, "wrktype - %c\n", wrktype); + WMESG(wrktype, msg); + RMESG(wrktype, msg, 1); + goto process; + } + + /* role is slave */ + RAMESG(msg, 1); + if (willturn < 0) + willturn = msg[0] == HUP; + +process: + DEBUG(4, "PROCESS: msg - %s\n", msg); + switch (msg[0]) { + + case RQSTCMPT: + DEBUG(4, "RQSTCMPT:\n", CNULL); + if (msg[1] == 'N') { + i = atoi(&msg[2]); + if (i<0 || i>EM_MAX) + i = 0; + USRF( 1 << i ); + logent(Em_msg[i], "REQUEST FAILED"); + TransferSucceeded = 1; /* He had his chance */ + } + if (msg[1] == 'Y') { + USRF(USR_COK); + TransferSucceeded = 1; + } + if (role == MASTER) { + notify(mailopt, W_USER, W_FILE1, Rmtname, &msg[1]); + } + if (msg[2] == 'M') { + extern int Nfiles; + WMESG(HUP, ""); + RMESG(HUP, msg, 1); + logent(Rmtname, "TURNAROUND"); +#ifdef USG + time(&LastTurned.time); + LastTurned.millitm = 0; +#else + ftime(&LastTurned); +#endif + Nfiles = 0; /* force rescan of queue for work */ + goto process; + } + goto top; + + case HUP: + DEBUG(4, "HUP:\n", CNULL); + HaveSentHup = 1; + if (msg[1] == 'Y') { + if (role == MASTER) + WMESG(HUP, YES); + (*Turnoff)(); + Rdmsg = Imsg; + Wrmsg = Omsg; + return SUCCESS; + } + + if (msg[1] == 'N') { + ASSERT(role == MASTER, "WRONG ROLE - HUP", CNULL, role); + role = SLAVE; + goto remaster; + } + + /* get work */ + if (!iswrk(Wfile, "chk", Spool, wkpre)) { + WMESG(HUP, YES); + RMESG(HUP, msg, 1); + goto process; + } + + WMESG(HUP, NO); + role = MASTER; + goto remaster; + + case XUUCP: + if (role == MASTER) { + goto top; + } + + /* slave part */ + i = getargs(msg, wrkvec, 20); + strcpy(filename, W_FILE1); + if (index(filename, ';') != NULL || index(W_FILE2, ';') != NULL + || i < 3) { + WMESG(XUUCP, NO); + goto top; + } + expfile(filename); + if (chkpth("", Rmtname, filename)) { + WMESG(XUUCP, NO); + logent("XUUCP DENIED", filename); + USRF(USR_XUUCP); + goto top; + } + sprintf(rqstr, "%s %s", filename, W_FILE2); + xuucp(rqstr); + WMESG(XUUCP, YES); + goto top; + + case SNDFILE: + /* MASTER section of SNDFILE */ + + DEBUG(4, "%s\n", "SNDFILE:"); + if (msg[1] == 'N') { + i = atoi(&msg[2]); + if (i < 0 || i > EM_MAX) + i = 0; + logent(Em_msg[i], "REQUEST FAILED"); + USRF( 1 << i ); + fclose(fp); + fp = NULL; + /* dont send him files he can't save */ + if (strcmp(&msg[1], EM_NOTMP) == 0) { + WMESG(HUP, ""); + RMESG(HUP, msg, 1); + goto process; + } + notify(mailopt, W_USER, W_FILE1, Rmtname, &msg[1]); + ASSERT(role == MASTER, "WRONG ROLE - SN", CNULL, role); + if (msg[1] != '4') + unlinkdf(W_DFILE); + goto top; + } + + if (msg[1] == 'Y') { + /* send file */ + ASSERT(role == MASTER, "WRONG ROLE - SY", CNULL, role); + ret = fstat(fileno(fp), &stbuf); + ASSERT(ret != -1, "STAT FAILED", filename, 0); + i = 1 + (int)(stbuf.st_size / XFRRATE); + if (send_or_receive != SNDFILE) { + send_or_receive = SNDFILE; + systat(Rmtname, SS_INPROGRESS, "SENDING"); + } + ret = (*Wrdata)(fp, Ofn); + fclose(fp); + fp = NULL; + if (ret != SUCCESS) { + (*Turnoff)(); + USRF(USR_CFAIL); + return FAIL; + } + RMESG(RQSTCMPT, msg, i); + unlinkdf(W_DFILE); + goto process; + } + + /* SLAVE section of SNDFILE */ + ASSERT(role == SLAVE, "WRONG ROLE - SLAVE", CNULL, role); + + /* request to receive file */ + /* check permissions */ + i = getargs(msg, wrkvec, 20); + if (i < 5) { + char *bnp; + bnp = rindex(Wfile, '/'); + sprintf(rqstr, "%s/%s", CORRUPT, bnp ? bnp + 1 : Wfile); + xmv(Wfile, rqstr); + logent(Wfile, "CMD FILE CORRUPTED"); + Wfile[0] = '\0'; + goto top; + } + sprintf(rqstr, "%s %s %s %s", W_TYPE, W_FILE1, W_FILE2, W_USER); + logent(rqstr, "REQUESTED"); + DEBUG(4, "msg - %s\n", msg); + strcpy(filename, W_FILE2); + /* Run uuxqt occasionally */ + if (filename[0] == XQTPRE) { + if (++nXfiles > 10) { + nXfiles = 0; + /* + * want to create an orphan uuxqt, + * so a double-fork is needed. + */ + if (fork() == 0) { + xuuxqt(); + _exit(0); + } + wait((int *)0); + } + } + /* expand filename, i is set to 0 if this is + * is a vanilla spool file, so no stat(II)s are needed */ + i = expfile(filename); + DEBUG(4, "expfile type - %d\n", i); + if (i != 0) { + if (chkpth("", Rmtname, filename) + || chkperm(filename, index(W_OPTNS, 'd'))) { + WMESG(SNDFILE, EM_RMTACC); + logent("DENIED", "PERMISSION"); + goto top; + } + if (isdir(filename)) { + strcat(filename, "/"); + strcat(filename, lastpart(W_FILE1)); + } + } + sprintf(User, "%.9s", W_USER); + + DEBUG(4, "chkpth ok Rmtname - %s\n", Rmtname); + /* speed things up by OKing file before + * creating TM file. If the TM file cannot be created, + * then the conversation bombs, but that seems reasonable, + * as there are probably serious problems then. + */ + WMESG(SNDFILE, YES); + sprintf(Dfile, "%s/TM.%05d.%03d", Spool, pnum, tmpnum++); + if((fp = fopen(subfile(Dfile), "w")) == NULL) { +/* WMESG(SNDFILE, EM_NOTMP);*/ + logent("CAN'T OPEN", "TM FILE"); + unlinkdf(Dfile); + (*Turnoff)(); + return FAIL; + } + + if (send_or_receive != RCVFILE) { + send_or_receive = RCVFILE; + systat(Rmtname, SS_INPROGRESS, "RECEIVING"); + } + ret = (*Rddata)(Ifn, fp); + fflush(fp); + if (ferror(fp) || fclose(fp)) + ret = FAIL; + + if (ret != SUCCESS) { + (void) unlinkdf(Dfile); + (*Turnoff)(); + return FAIL; + } + /* copy to user directory */ + ntfyopt = index(W_OPTNS, 'n') != NULL; + status = xmv(Dfile, filename); + + if (willturn && Now.time > (LastTurned.time+turntime) + && iswrk(Wfile, "chk", Spool, wkpre)) { + WMESG(RQSTCMPT, status ? EM_RMTCP : "YM"); + willturn = -1; + } else + WMESG(RQSTCMPT, status ? EM_RMTCP : YES); + if (i == 0) + ; /* vanilla file, nothing to do */ + else if (status == 0) { + if (W_MODE == 0 || sscanf(W_MODE, "%o", &filemode) != 1) + filemode = BASEMODE; + chmod(subfile(filename), (filemode|BASEMODE)&0777); + arrived(ntfyopt, filename, W_NUSER, Rmtname, User); + } else { + logent(_FAILED, "COPY"); + status = putinpub(filename, Dfile, W_USER); + DEBUG(4, "->PUBDIR %d\n", status); + if (status == 0) + arrived(ntfyopt, filename, W_NUSER, Rmtname, User); + } + + goto top; + + case RCVFILE: + /* MASTER section of RCVFILE */ + + DEBUG(4, "%s\n", "RCVFILE:"); + if (msg[1] == 'N') { + i = atoi(&msg[2]); + if (i < 0 || i > EM_MAX) + i = 0; + logent(Em_msg[i], "REQUEST FAILED"); + USRF( 1 << i ); + fclose(fp); + fp = NULL; + notify(mailopt, W_USER, W_FILE1, Rmtname, &msg[1]); + ASSERT(role == MASTER, "WRONG ROLE - RN", CNULL, role); + unlinkdf(Dfile); + goto top; + } + + if (msg[1] == 'Y') { + /* receive file */ + ASSERT(role == MASTER, "WRONG ROLE - RY", CNULL, role); + if (send_or_receive != RCVFILE) { + send_or_receive = RCVFILE; + systat(Rmtname, SS_INPROGRESS, "RECEIVING"); + } + ret = (*Rddata)(Ifn, fp); + fflush(fp); + if (ferror(fp) || fclose(fp)) + ret = FAIL; + if (ret != SUCCESS) { + unlinkdf(Dfile); + (*Turnoff)(); + USRF(USR_CFAIL); + return FAIL; + } + /* copy to user directory */ + if (isdir(filename)) { + strcat(filename, "/"); + strcat(filename, lastpart(W_FILE1)); + } + status = xmv(Dfile, filename); + if (willturn && Now.time > (LastTurned.time+turntime) + && iswrk(Wfile, "chk", Spool, wkpre)) { + WMESG(RQSTCMPT, status ? EM_RMTCP : "YM"); + willturn = -1; + } else + WMESG(RQSTCMPT, status ? EM_RMTCP : YES); + notify(mailopt, W_USER, filename, Rmtname, + status ? EM_LOCCP : YES); + if (status == 0) { + sscanf(&msg[2], "%o", &filemode); + if (filemode <= 0) + filemode = BASEMODE; + chmod(subfile(filename), (filemode|BASEMODE)&0777); + USRF(USR_COK); + } else { + logent(_FAILED, "COPY"); + putinpub(filename, Dfile, W_USER); + USRF(USR_LOCCP); + } + goto top; + } + + /* SLAVE section of RCVFILE */ + ASSERT(role == SLAVE, "WRONG ROLE - SLAVE RCV", CNULL, role); + + /* request to send file */ + strcpy(rqstr, msg); + logent(rqstr, "REQUESTED"); + + /* check permissions */ + i = getargs(msg, wrkvec, 20); + if (i < 4) { + char *bnp; + bnp = rindex(Wfile, '/'); + sprintf(rqstr, "%s/%s", CORRUPT, bnp ? bnp + 1 : Wfile); + xmv(Wfile, rqstr); + logent(Wfile, "CMD FILE CORRUPTED"); + Wfile[0] = '\0'; + goto top; + } + DEBUG(4, "msg - %s\n", msg); + DEBUG(4, "W_FILE1 - %s\n", W_FILE1); + strcpy(filename, W_FILE1); + expfile(filename); + if (isdir(filename)) { + strcat(filename, "/"); + strcat(filename, lastpart(W_FILE2)); + } + sprintf(User, "%.9s", W_USER); + if (chkpth("", Rmtname, filename) || anyread(filename)) { + WMESG(RCVFILE, EM_RMTACC); + logent("DENIED", "PERMISSION"); + goto top; + } + DEBUG(4, "chkpth ok Rmtname - %s\n", Rmtname); + + if ((fp = fopen(subfile(filename), "r")) == NULL) { + WMESG(RCVFILE, EM_RMTACC); + logent("CAN'T OPEN", "DENIED"); + goto top; + } + + /* ok to send file */ + ret = fstat(fileno(fp), &stbuf); + ASSERT(ret != -1, "STAT FAILED", filename, 0); + i = 1 + (int)(stbuf.st_size / XFRRATE); + sprintf(msg, "%s %o", YES, (int)stbuf.st_mode & 0777); + WMESG(RCVFILE, msg); + if (send_or_receive != SNDFILE) { + send_or_receive = SNDFILE; + systat(Rmtname, SS_INPROGRESS, "SENDING"); + } + ret = (*Wrdata)(fp, Ofn); + fclose(fp); + if (ret != SUCCESS) { + (*Turnoff)(); + return FAIL; + } + RMESG(RQSTCMPT, msg, i); + goto process; + } + (*Turnoff)(); + return FAIL; +} + + +/* + * read message 'c'. try 'n' times + * + * return code: SUCCESS | FAIL + */ +rmesg(c, msg, n) +register char *msg, c; +register int n; +{ + char str[MAXFULLNAME]; + + DEBUG(4, "rmesg - '%c' ", c); + while ((*Rdmsg)(msg, Ifn) != SUCCESS) { + if (--n > 0) { + sprintf(str, "%d", n); + logent(str, "PATIENCE"); + continue; + } + DEBUG(4, "got FAIL\n", CNULL); + if (c != '\0') + sprintf(str, "expected '%c' got FAIL (%d)", c, errno); + else + sprintf(str, "expected ANY got FAIL (%d)", errno); + logent(str, "BAD READ"); + return FAIL; + } + if (c != '\0' && msg[0] != c) { + DEBUG(4, "got %s\n", msg); + sprintf(str, "expected '%c' got %s", c, msg); + logent(str, "BAD READ"); + return FAIL; + } + DEBUG(4, "got %s\n", msg); + return SUCCESS; +} + + +/* + * write a message (type m) + * + * return codes: SUCCESS - ok | FAIL - ng + */ +wmesg(m, s) +register char *s, m; +{ + DEBUG(4, "wmesg '%c' ", m); + DEBUG(4, "%s\n", s); + return (*Wrmsg)(m, s, Ofn); +} + +/* + * mail results of command + * + * return codes: none + */ +notify(mailopt, user, file, sys, msgcode) +char *user, *file, *sys, *msgcode; +{ + char str[BUFSIZ]; + int i; + char *msg; + + if (!mailopt && *msgcode == 'Y') + return; + if (*msgcode == 'Y') + msg = "copy succeeded"; + else { + i = atoi(msgcode + 1); + if (i < 1 || i > EM_MAX) + i = 0; + msg = Em_msg[i]; + } + sprintf(str, "file %s!%s -- %s\n", + sys,file, msg); + mailst(user, str, CNULL); + return; +} + +/* + * local notify + * + * return code - none + */ +lnotify(user, file, mesg) +char *user, *file, *mesg; +{ + char mbuf[200]; + sprintf(mbuf, "file %s!%s -- %s\n", Myname, file, mesg); + mailst(user, mbuf, CNULL); + return; +} + +/* + * converse with the remote machine, agree upon a protocol (if possible) + * and start the protocol. + * + * return codes: + * SUCCESS - successful protocol selection + * FAIL - can't find common or open failed + */ +startup(role) +int role; +{ + extern (*Rdmsg)(), (*Wrmsg)(); + extern char *blptcl(), fptcl(); + char msg[BUFSIZ], str[MAXFULLNAME]; + + Rdmsg = Imsg; + Wrmsg = Omsg; + if (role == MASTER) { + RMESG(SLTPTCL, msg, 1); + if ((str[0] = fptcl(&msg[1])) == NULL) { + /* no protocol match */ + WMESG(USEPTCL, NO); + return FAIL; + } + str[1] = '\0'; + WMESG(USEPTCL, str); + if (stptcl(str) != 0) + return FAIL; + DEBUG(4, "protocol %s\n", str); + return SUCCESS; + } + else { + WMESG(SLTPTCL, blptcl(str)); + RMESG(USEPTCL, msg, 1); + if (msg[1] == 'N') { + return FAIL; + } + + if (stptcl(&msg[1]) != 0) + return FAIL; + DEBUG(4, "Protocol %s\n", msg); + return SUCCESS; + } +} + +/* + * choose a protocol from the input string (str) and return the it + * + * return codes: + * '\0' - no acceptable protocol + * any character - the chosen protocol + */ +char +fptcl(str) +register char *str; +{ + register struct Proto *p; + extern char LineType[]; + + for (p = Ptbl; p->P_id != '\0'; p++) { +#ifdef TCPIP + /* Only use 't' on TCP/IP */ + if (p->P_id == 't' && strcmp("TCP", LineType)) + continue; +#endif +#ifdef PAD + /* only use 'f' protocol on PAD */ + if (p->P_id == 'f' && strcmp("PAD", LineType)) + continue; +#endif + if (index(str, p->P_id) != NULL) { + return p->P_id; + } + } + + return '\0'; +} + +/* + * build a string of the letters of the available protocols + */ +char * +blptcl(str) +register char *str; +{ + register struct Proto *p; + register char *s; + + for (p = Ptbl, s = str; (*s++ = p->P_id) != '\0'; p++) + ; + *s = '\0'; + return str; +} + +/* + * this routine will set up the six routines + * (Rdmsg, Wrmsg, Rddata, Wrdata, Turnon, Turnoff) for the + * desired protocol. + * + * return codes: + * SUCCESS - ok + * FAIL - no find or failed to open + * + */ +stptcl(c) +register char *c; +{ + register struct Proto *p; + + for (p = Ptbl; p->P_id != '\0'; p++) { + if (*c == p->P_id) { + /* found protocol - set routines */ + Rdmsg = p->P_rdmsg; + Wrmsg = p->P_wrmsg; + Rddata = p->P_rddata; + Wrdata = p->P_wrdata; + Turnon = p->P_turnon; + Turnoff = p->P_turnoff; + if ((*Turnon)() != SUCCESS) + return FAIL; + DEBUG(4, "Proto started %c\n", *c); + return SUCCESS; + } + } + DEBUG(4, "Proto start-fail %c\n", *c); + return FAIL; +} + +/* + * put file in public place. if successful, filename is modified + * + * return code SUCCESS | FAIL + */ + +putinpub(file, tmp, user) +register char *file, *tmp, *user; +{ + char fullname[MAXFULLNAME]; + char *lastpart(); + int status; + + sprintf(fullname, "%s/%s/", PUBDIR, user); + if (mkdirs(fullname) != 0) { + /* can not make directories */ + DEBUG(1, "Cannot mkdirs(%s)\n", fullname); + return FAIL; + } + strcat(fullname, lastpart(file)); + status = xmv(tmp, fullname); + if (status == 0) { + strcpy(file, fullname); + chmod(subfile(fullname), BASEMODE); + } + return status; +} + +/* + * unlink D. file + * + * return code - none + */ + +unlinkdf(file) +register char *file; +{ + if (strlen(file) > 6) + unlink(subfile(file)); + return; +} + +/* + * notify receiver of arrived file + * + * return code - none + */ +arrived(opt, file, nuser, rmtsys, rmtuser) +char *file, *nuser, *rmtsys, *rmtuser; +{ + char mbuf[200]; + + if (!opt) + return; + sprintf(mbuf, "%s from %s!%s arrived\n", file, rmtsys, rmtuser); + mailst(nuser, mbuf, CNULL); + return; +} + +nullf() +{ + return SUCCESS; +} diff --git a/src/cmd/uucp/condevs.c b/src/cmd/uucp/condevs.c new file mode 100644 index 0000000..446e6ed --- /dev/null +++ b/src/cmd/uucp/condevs.c @@ -0,0 +1,564 @@ +#if !defined(lint) && defined(DOSCCS) +static char sccsid[] = "@(#)condevs.c 5.15.2 (2.11BSD) 1997/10/2"; +#endif + +/* + * Here are various dialers to establish the machine-machine connection. + * conn.c/condevs.c was glued together by Mike Mitchell. + * The dialers were supplied by many people, to whom we are grateful. + * + * --------------------------------------------------------------------- + * NOTE: + * There is a bug that occurs at least on PDP11s due to a limitation of + * setjmp/longjmp. If the routine that does a setjmp is interrupted + * and longjmp-ed to, it loses its register variables (on a pdp11). + * What works is if the routine that does the setjmp + * calls a routine and it is the *subroutine* that is interrupted. + * + * Anyway, in conclusion, condevs.c is plagued with register variables + * that are used inside + * if (setjmp(...)) { + * .... + * } + * + * THE FIX: Don't declare variables to be register + */ + +#include "condevs.h" + +struct condev condevs[] = { + { "DIR", "direct", diropn, nulldev, dircls }, +#ifdef DATAKIT + { "DK", "datakit", dkopn, nulldev, nulldev }, +#endif +#ifdef PNET + { "PNET", "pnet", pnetopn, nulldev, nulldev }, +#endif +#ifdef UNETTCP + { "TCP", "TCP", unetopn, nulldev, unetcls }, +#endif +#ifdef BSDTCP + { "TCP", "TCP", bsdtcpopn, nulldev, bsdtcpcls }, +#endif +#ifdef MICOM + { "MICOM", "micom", micopn, nulldev, miccls }, +#endif +#ifdef DN11 + { "ACU", "dn11", Acuopn, dnopn, dncls }, +#endif +#ifdef HAYES + { "ACU", "hayes", Acuopn, hyspopn, hyscls }, + { "ACU", "hayespulse", Acuopn, hyspopn, hyscls }, + { "ACU", "hayestone", Acuopn, hystopn, hyscls }, + { "WATS", "hayestone", Acuopn, hystopn, hyscls }, +#endif +#ifdef HAYES2400 + { "ACU", "hayes2400", Acuopn, hyspopn24, hyscls24 }, + { "ACU", "hayes2400pulse", Acuopn, hyspopn24, hyscls24 }, + { "ACU", "hayes2400tone", Acuopn, hystopn24, hyscls24 }, +#endif +#ifdef HAYESQ /* a version of hayes that doesn't use result codes */ + { "ACU", "hayesq", Acuopn, hysqpopn, hysqcls }, + { "ACU", "hayesqpulse", Acuopn, hysqpopn, hysqcls }, + { "ACU", "hayesqtone", Acuopn, hysqtopn, hysqcls }, +#endif +#ifdef CDS224 + { "ACU", "cds224", Acuopn, cdsopn224, cdscls224}, +#endif +#ifdef NOVATION + { "ACU", "novation", Acuopn, novopn, novcls}, +#endif +#ifdef DF02 + { "ACU", "DF02", Acuopn, df2opn, df2cls }, +#endif +#ifdef DF112 + { "ACU", "DF112P", Acuopn, df12popn, df12cls }, + { "ACU", "DF112T", Acuopn, df12topn, df12cls }, +#endif +#ifdef VENTEL + { "ACU", "ventel", Acuopn, ventopn, ventcls }, +#endif +#ifdef PENRIL + { "ACU", "penril", Acuopn, penopn, pencls }, +#endif +#ifdef VADIC + { "ACU", "vadic", Acuopn, vadopn, vadcls }, +#endif +#ifdef VA212 + { "ACU", "va212", Acuopn, va212opn, va212cls }, +#endif +#ifdef VA811S + { "ACU", "va811s", Acuopn, va811opn, va811cls }, +#endif +#ifdef VA820 + { "ACU", "va820", Acuopn, va820opn, va820cls }, + { "WATS", "va820", Acuopn, va820opn, va820cls }, +#endif +#ifdef RVMACS + { "ACU", "rvmacs", Acuopn, rvmacsopn, rvmacscls }, +#endif +#ifdef VMACS + { "ACU", "vmacs", Acuopn, vmacsopn, vmacscls }, +#endif +#ifdef SYTEK + { "SYTEK", "sytek", sykopn, nulldev, sykcls }, +#endif +#ifdef ATT2224 + { "ACU", "att", Acuopn, attopn, attcls }, +#endif + + + /* Insert new entries before this line */ + { NULL, NULL, NULL, NULL, NULL } +}; + +/* + * nulldev a null device (returns CF_DIAL) + */ +nulldev() +{ + return CF_DIAL; +} + +/* + * nodev a null device (returns CF_NODEV) + */ +nodev() +{ + return CF_NODEV; +} + +/* + * Generic devices look through L-devices and call the CU_open routines for + * appropriate devices. Some things, like the tcp/ip interface, or direct + * connect, do not use the CU_open entry. ACUs must search to find the + * right routine to call. + */ + +/* + * diropn(flds) connect to hardware line + * + * return codes: + * > 0 - file number - ok + * FAIL - failed + */ +diropn(flds) +register char *flds[]; +{ + register int dcr, status; + struct Devices dev; + char dcname[20]; + FILE *dfp; +#ifdef VMSDTR /* Modem control on vms(works dtr) */ + int modem_control; + short iosb[4]; + int sys$qiow(); /* use this for long reads on vms */ + int ret; + long mode[2]; + modem_control = 0; +#endif + dfp = fopen(DEVFILE, "r"); + ASSERT(dfp != NULL, "CAN'T OPEN", DEVFILE, 0); + while ((status = rddev(dfp, &dev)) != FAIL) { +#ifdef VMSDTR /* Modem control on vms(works dtr) */ + /* If we find MOD in the device type field we go into action */ + if (strcmp(dev.D_type, "MOD") == SAME) { + modem_control = 1; + DEBUG(7, "Setting Modem control to %d",modem_control); + } + if (strcmp(flds[F_CLASS], dev.D_class) != SAME) + continue; + /* + * Modem control on vms(works dtr) Take anything in MOD class. + * It probably should work differently anyway so we can have + * multiple hardwired lines. + */ + if (!modem_control&&strcmp(flds[F_PHONE], dev.D_line) != SAME) +#else + if (strcmp(flds[F_CLASS], dev.D_class) != SAME) + continue; + if (strcmp(flds[F_PHONE], dev.D_line) != SAME) +#endif + continue; + if (mlock(dev.D_line) != FAIL) + break; + } + fclose(dfp); + if (status == FAIL) { + logent("DEVICE", "NO"); + return CF_NODEV; + } + + sprintf(dcname, "/dev/%s", dev.D_line); + if (setjmp(Sjbuf)) { + DEBUG(4, "Open timed out\n", CNULL); + delock(dev.D_line); + return CF_DIAL; + } + signal(SIGALRM, (sig_t)alarmtr); + /* For PC Pursuit, it could take a while to call back */ + alarm( strcmp(flds[F_LINE], "PCP") ? 10 : MAXMSGTIME*4 ); + getnextfd(); + errno = 0; + DEBUG(4,"Opening %s\n",dcname); + dcr = open(dcname, 2); /* read/write */ +#ifdef VMSDTR /* Modem control on vms(works dtr) */ + fflush(stdout); + if (modem_control) { /* Did we have MOD in the device type field ? */ + /* Sense the current terminal setup and save it */ + if ((ret = sys$qiow(_$EFN,(fd_fab_pointer[dcr]->fab).fab$l_stv, + IO$_SENSEMODE,iosb,0,0,mode,8,0,0,0,0)) + != SS$_NORMAL) { + DEBUG(7, "ret status on sense failed on Modem sense=%x<", ret); + return CF_DIAL; + } + mode[1] |= TT$M_MODEM; /* Or in modem control(DTR) */ + /* Now set the new terminal characteristics */ + /* This is temporary and will go away when we let go of it */ + if ((ret = sys$qiow(_$EFN,(fd_fab_pointer[dcr]->fab).fab$l_stv, + IO$_SETMODE,iosb,0,0,mode,8,0,0,0,0)) + != SS$_NORMAL) { + DEBUG(7, "ret status on sense failed on Modem setup=%x<", ret); + return CF_DIAL; + } + } +#endif + next_fd = -1; + alarm(0); + if (dcr < 0) { + if (errno == EACCES) + logent(dev.D_line, "CANT OPEN"); + DEBUG(4, "OPEN FAILED: errno %d\n", errno); + delock(dev.D_line); + return CF_DIAL; + } + fflush(stdout); + if (fixline(dcr, dev.D_speed) == FAIL) { + DEBUG(4, "FIXLINE FAILED\n", CNULL); + return CF_DIAL; + } + strcpy(devSel, dev.D_line); /* for latter unlock */ + CU_end = dircls; + return dcr; +} + +dircls(fd) +register int fd; +{ + if (fd > 0) { + close(fd); + delock(devSel); + } +} + +/* + * open an ACU and dial the number. The condevs table + * will be searched until a dialing unit is found that is free. + * + * return codes: >0 - file number - o.k. + * FAIL - failed + */ +char devSel[20]; /* used for later unlock() */ + +Acuopn(flds) +register char *flds[]; +{ + char phone[MAXPH+1]; + register struct condev *cd; + register int fd, acustatus; + register FILE *dfp; + struct Devices dev; + int retval = CF_NODEV; + char nobrand[MAXPH], *line; + + exphone(flds[F_PHONE], phone); + if (snccmp(flds[F_LINE], "LOCAL") == SAME) + line = "ACU"; + else + line = flds[F_LINE]; + devSel[0] = '\0'; + nobrand[0] = '\0'; + DEBUG(4, "Dialing %s\n", phone); + dfp = fopen(DEVFILE, "r"); + ASSERT(dfp != NULL, "Can't open", DEVFILE, 0); + + acustatus = 0; /* none found, none locked */ + while (rddev(dfp, &dev) != FAIL) { + /* + * for each ACU L.sys line, try at most twice + * (TRYCALLS) to establish carrier. The old way tried every + * available dialer, which on big sites takes forever! + * Sites with a single auto-dialer get one try. + * Sites with multiple dialers get a try on each of two + * different dialers. + * To try 'harder' to connect to a remote site, + * use multiple L.sys entries. + */ + if (acustatus > TRYCALLS) + break; + if (strcmp(flds[F_CLASS], dev.D_class) != SAME) + continue; + if (snccmp(line, dev.D_type) != SAME) + continue; + if (dev.D_brand[0] == '\0') { + logent("Acuopn","No 'brand' name on ACU"); + continue; + } + for(cd = condevs; cd->CU_meth != NULL; cd++) { + if (snccmp(line, cd->CU_meth) == SAME) { + if (snccmp(dev.D_brand, cd->CU_brand) == SAME) + break; + strncpy(nobrand, dev.D_brand, sizeof nobrand); + } + } + + if (mlock(dev.D_line) == FAIL) { + acustatus++; + continue; + } + if (acustatus < 1) + acustatus = 1; /* has been found */ +#ifdef DIALINOUT +#ifdef ALLACUINOUT + if (1) { +#else + if (snccmp("inout", dev.D_calldev) == SAME) { +#endif + if (disable(dev.D_line) == FAIL) { + delock(dev.D_line); + continue; + } + } else + reenable(); +#endif + + DEBUG(4, "Using %s\n", cd->CU_brand); + acustatus++; + fd = (*(cd->CU_open))(phone, flds, &dev); + if (fd > 0) { + CU_end = cd->CU_clos; /* point CU_end at close func */ + fclose(dfp); + strcpy(devSel, dev.D_line); /* save for later unlock() */ + return fd; + } else + delock(dev.D_line); + retval = CF_DIAL; + } + fclose(dfp); + if (acustatus == 0) { + if (nobrand[0]) + logent(nobrand, "unsupported ACU type"); + else + logent("L-devices", "No appropriate ACU"); + } + if (acustatus == 1) + logent("DEVICE", "NO"); + return retval; +} + +/* + * intervaldelay: delay execution for numerator/denominator seconds. + */ + +#ifdef INTERVALTIMER +#define uucpdelay(num,denom) intervaldelay(num,denom) +intervaldelay(num,denom) +int num, denom; +{ + struct timeval tv; + tv.tv_sec = num / denom; + tv.tv_usec = (num * 1000000L / denom ) % 1000000L; + (void) select (0, (fd_set*)0, (fd_set*)0, (fd_set*)0, &tv); +} +#endif + +#ifdef FASTTIMER +#define uucpdelay(num,denom) nap(60*num/denom) +/* Sleep in increments of 60ths of second. */ +nap (time) +register int time; +{ + static int fd; + + if (fd == 0) + fd = open (FASTTIMER, 0); + + read (fd, 0, time); +} +#endif + +#ifdef FTIME +#define uucpdelay(num,denom) ftimedelay(1000*num/denom) +ftimedelay(n) +{ + static struct timeb loctime; + register i = loctime.millitm; + + ftime(&loctime); + while (abs((int)(loctime.millitm - i)) 0); } +busyloop(n) +{ + DELAY(n); +} +#endif + +slowrite(fd, str) +register char *str; +{ + DEBUG(6, "slowrite ", CNULL); + while (*str) { + DEBUG(6, "%c", *str); + uucpdelay(1, 10); /* delay 1/10 second */ + write(fd, str, 1); + str++; + } + DEBUG(6, "\n", CNULL); +} + +#define BSPEED B150 + +/* + * send a break + */ +genbrk(fn, bnulls) +register int fn, bnulls; +{ +#ifdef USG + if (ioctl(fn, TCSBRK, STBNULL) < 0) + DEBUG(5, "break TCSBRK %s\n", strerror(errno)); +#else +# ifdef TIOCSBRK + if (ioctl(fn, TIOCSBRK, STBNULL) < 0) + DEBUG(5, "break TIOCSBRK %s\n", strerror(errno)); +# ifdef TIOCCBRK + uucpdelay(bnulls, 10); + if (ioctl(fn, TIOCCBRK, STBNULL) < 0) + DEBUG(5, "break TIOCCBRK %s\n", strerror(errno)); +# endif + DEBUG(4, "ioctl %f second break\n", (float) bnulls/10 ); +# else + struct sgttyb ttbuf; + register int sospeed; + + if (ioctl(fn, TIOCGETP, &ttbuf) < 0) + DEBUG(5, "break TIOCGETP %s\n", strerror(errno)); + sospeed = ttbuf.sg_ospeed; + ttbuf.sg_ospeed = BSPEED; + if (ioctl(fn, TIOCSETP, &ttbuf) < 0) + DEBUG(5, "break TIOCSETP %s\n", strerror(errno)); + if (write(fn, "\0\0\0\0\0\0\0\0\0\0\0\0", bnulls) != bnulls) { +badbreak: + logent(strerror(errno), "BAD WRITE genbrk"); + alarm(0); + longjmp(Sjbuf, 3); + } + ttbuf.sg_ospeed = sospeed; + if (ioctl(fn, TIOCSETP, &ttbuf) < 0) + DEBUG(5, "break ioctl %s\n", strerror(errno)); + if (write(fn, "@", 1) != 1) + goto badbreak; + DEBUG(4, "sent BREAK nulls - %d\n", bnulls); +#endif +#endif +} + + +#ifdef DIALINOUT +/* DIALIN/OUT CODE (WLS) */ +/* + * disable and reenable: allow a single line to be use for dialin/dialout + * + */ + +char enbdev[16]; + +disable(dev) +register char *dev; +{ + register char *rdev; + + /* strip off directory prefixes */ + rdev = dev; + while (*rdev) + rdev++; + while (--rdev >= dev && *rdev != '/') + ; + rdev++; + + if (enbdev[0]) { + if (strcmp(enbdev, rdev) == SAME) + return SUCCESS; /* already disabled */ + delock(enbdev); + reenable(); /* else, reenable the old one */ + } + DEBUG(4, "Disable %s\n", rdev); + if (enbcall("disable", rdev) == FAIL) + return FAIL; + strcpy(enbdev, rdev); + return SUCCESS; +} + +reenable() +{ + if (enbdev[0] == '\0') + return; + DEBUG(4, "Reenable %s\n", enbdev); + (void) enbcall("enable", enbdev); + enbdev[0] = '\0'; +} + +enbcall(type, dev) +char *type, *dev; +{ + int pid; + register char *p; + int fildes[2]; + int status; + FILE *fil; + char buf[80]; + + fflush(stderr); + fflush(stdout); + pipe(fildes); + if ((pid = fork()) == 0) { + DEBUG(4, DIALINOUT, CNULL); + DEBUG(4, " %s", type); + DEBUG(4, " %s\n", dev); + close(fildes[0]); + close(0); close(1); close(2); + open("/dev/null",0); + dup(fildes[1]); dup(fildes[1]); + setuid(geteuid()); /* for chown(uid()) in acu program */ + execl(DIALINOUT, "acu", type, dev, 0); + exit(-1); + } + if (pid<0) + return FAIL; + + close(fildes[1]); + fil = fdopen(fildes[0],"r"); + if (fil!=NULL) { +#ifdef BSD4_2 + setlinebuf(fil); +#endif + while (fgets(buf, sizeof buf, fil) != NULL) { + p = buf + strlen(buf) - 1; + if (*p == '\n') + *p = '\0'; + logent(buf,"ACUCNTRL:"); + } + } + while(wait(&status) != pid) + ; + fclose(fil); + return status ? FAIL : SUCCESS; +} +#endif diff --git a/src/cmd/uucp/condevs.h b/src/cmd/uucp/condevs.h new file mode 100644 index 0000000..f6cd64f --- /dev/null +++ b/src/cmd/uucp/condevs.h @@ -0,0 +1,114 @@ +/* condevs.h 4.7.1 1996/3/22 */ + +#include "uucp.h" +#include +#include +#include +#include +#ifdef VMSDTR /* Modem control on vms(works dtr) */ +#include +#define TT$M_MODEM 0x00200000 /* These should be in a '.h' somewhere */ +#define SS$_NORMAL 0x00000001 +#define IO$_SETMODE 0x00000023 +#define IO$_SENSEMODE 0x00000027 +#endif + +extern char devSel[]; /* name to pass to delock() in close */ +extern int next_fd; +extern jmp_buf Sjbuf; +extern int alarmtr(); +int nulldev(), nodev(), Acuopn(), diropn(), dircls(); + +#ifdef DATAKIT +int dkopn(); +#endif + +#ifdef DN11 +int dnopn(), dncls(); +#endif + +#ifdef HAYES +int hyspopn(), hystopn(), hyscls(); +#endif + +#ifdef HAYES2400 +int hyspopn24(), hystopn24(), hyscls24(); +#endif + +#ifdef HAYESQ +int hysqopn(), hysqcls(); /* a version of hayes that doesn't use ret codes */ +#endif + +#ifdef NOVATION +int novopn(), novcls(); +#endif + +#ifdef CDS224 +int cdsopn224(), cdscls224(); +#endif + +#ifdef DF02 +int df2opn(), df2cls(); +#endif + +#ifdef DF112 +int df12popn(), df12topn(), df12cls(); +#endif + +#ifdef PNET +int pnetopn(); +#endif + +#ifdef VENTEL +int ventopn(), ventcls(); +#endif + +#ifdef PENRIL +int penopn(), pencls(); +#endif + +#ifdef UNETTCP +#define TO_ACTIVE 0 +int unetopn(), unetcls(); +#endif + +#ifdef BSDTCP +int bsdtcpopn(), bsdtcpcls(); +#endif + +#ifdef VADIC +int vadopn(), vadcls(); +#endif + +#ifdef VA212 +int va212opn(), va212cls(); +#endif + +#ifdef VA811S +int va811opn(), va811cls(); +#endif + +#ifdef VA820 +int va820opn(), va820cls(); +#endif + +#ifdef RVMACS +int rvmacsopn(), rvmacscls(); +#endif + +#ifdef VMACS +int vmacsopn(), vmacscls(); +#endif + +#ifdef MICOM +int micopn(), miccls(); +#endif + +#ifdef SYTEK +int sykopn(), sykcls(); +#endif + +#ifdef ATT2224 +int attopn(), attcls(); +#endif + diff --git a/src/cmd/uucp/conn.c b/src/cmd/uucp/conn.c new file mode 100644 index 0000000..91bbbf3 --- /dev/null +++ b/src/cmd/uucp/conn.c @@ -0,0 +1,1143 @@ +#if !defined(lint) && defined(DOSCCS) +static char sccsid[] = "@(#)conn.c 5.10.2 (2.11BSD) 1997/10/2"; +#endif + +#include +#include +#include "uucp.h" +#include +#include +#include +#ifdef USG +#include +#include +#endif +#ifndef USG +#include +#endif + +#define MAXC 1000 + +extern jmp_buf Sjbuf; +jmp_buf Cjbuf; +extern int onesys; +extern char MaxGrade, DefMaxGrade; + +/* Parity control during login procedure */ +#define P_ZERO 0 +#define P_ONE 1 +#define P_EVEN 2 +#define P_ODD 3 + +#define ABORT -2 + +char *AbortOn = NULL; +char par_tab[128]; /* must be power of two */ +int linebaudrate; /* used for the sleep test in pk1.c */ +int next_fd = -1; /* predicted fd to close interrupted opens */ + +char *PCP = "PCP"; /* PC Pursuit device type */ +/* + * catch alarm routine for "expect". + */ +alarmtr() +{ + signal(SIGALRM, (sig_t)alarmtr); + if (next_fd >= 0) { + if (close(next_fd)) + logent("FAIL", "ACU LINE CLOSE"); + next_fd = -1; + } + longjmp(Sjbuf, 1); +} + +/* This template is for seismo to call ihnp4 + * the 3 lines marked ---> will be overwritten for the appropriate city + */ +#define PCP_BAUD 3 +#define PCP_PHONE 4 +#define PCP_CALLBACK 8 +#define PCP_CITY 10 +#define PCP_RPHONE 12 +#define NPCFIELDS 15 + +static char *PCFlds[] = { + "PC-PURSUIT", + "Any", + "ACU", + "1200", + CNULL, /* <--- **** Welcome to Telenet PC Pursuit ***** */ + "ABORT", + "Good", /* Abort of Good bye! */ + ")", /* <--- Enter your 7-digit phone number (xxx-xxxx) */ + CNULL, /* ---> 528-1234 */ + "call?", /* <--- Which city do you wish to call? */ + CNULL, /* ---> CHICAGO */ + ")", /* <--- Enter the phone number you wish to call (xxx-xxxx) */ + CNULL, /* ---> 690-7171 */ + "R)?", /* <--- You are #1 in the queue. Do you want to wait, or Restart (Y/N/R)? */ + "Y", + CNULL /* <--- .....Good Bye! */ +}; + +static char PCP_brand[20]; + +/* + * place a telephone call to system and login, etc. + * + * return codes: + * CF_SYSTEM: don't know system + * CF_TIME: wrong time to call + * CF_DIAL: call failed + * CF_NODEV: no devices available to place call + * CF_LOGIN: login/password dialog failed + * + * >0 - file no. - connect ok + */ + +int Dcf = -1; +char *Flds[MAXC/10]; +char LineType[10]; +extern int LocalOnly; + +conn(system) +char *system; +{ + int nf; + char info[MAXC], wkpre[NAMESIZE], file[NAMESIZE]; + register FILE *fsys; + int fcode = 0; + + nf = 0; + + fsys = fopen(SYSFILE, "r"); + ASSERT(fsys != NULL, "CAN'T OPEN", SYSFILE, 0); + + DEBUG(4, "finds (%s) called\n", system); +keeplooking: + while((nf = finds(fsys, system, info, Flds)) > 0) { + strncpy(LineType, Flds[F_LINE], 10); + if (LocalOnly) { + if (strcmp("TCP", LineType) + && strcmp("DIR", LineType) + && strcmp("LOCAL", LineType) ) { + fcode = CF_TIME; + continue; + } + } + sprintf(wkpre, "%c.%.*s", CMDPRE, SYSNSIZE, Rmtname); + if (!onesys && MaxGrade != DefMaxGrade && + !iswrk(file, "chk", Spool, wkpre)) { + fcode = CF_TIME; + continue; + } + /* For GTE's PC Pursuit */ + if (snccmp(LineType, PCP) == SAME) { + FILE *dfp; + int status; + static struct Devices dev; + dfp = fopen(DEVFILE, "r"); + ASSERT(dfp != NULL, "Can't open", DEVFILE, 0); + while ((status=rddev(dfp, &dev)) != FAIL + && strcmp(PCP, dev.D_type) != SAME) + ; + fclose(dfp); + if (status == FAIL) + continue; + if (mlock(PCP) == FAIL) { + fcode = CF_NODEV; + logent("DEVICE", "NO"); + continue; + } + PCFlds[PCP_BAUD] = dev.D_class; + PCFlds[PCP_PHONE] = dev.D_calldev; + PCFlds[PCP_CALLBACK] = dev.D_arg[D_CHAT]; + PCFlds[PCP_CITY] = Flds[F_CLASS]; + PCFlds[PCP_RPHONE] = Flds[F_PHONE]; + strncpy(PCP_brand, dev.D_brand, sizeof(PCP_brand)); + if ((fcode = getto(PCFlds)) < 0) + continue; + Dcf = fcode; + fcode = login(NPCFIELDS, PCFlds, Dcf); + clsacu(); /* Hang up, they'll call back */ + if (fcode != SUCCESS) { + fcode = CF_DIAL; + continue; + } + Flds[F_CLASS] = dev.D_class; + Flds[F_PHONE] = dev.D_line; + + } /* end PC Pursuit */ + if ((fcode = getto(Flds)) > 0) + break; + } + + if (nf <= 0) { + fclose(fsys); + return fcode ? fcode : nf; + } + + Dcf = fcode; + + if (fcode >= 0 && snccmp(LineType, PCP) == SAME) { + AbortOn = "Good"; /* .... Good Bye */ + fcode = expect("****~300", Dcf); + if (fcode != SUCCESS) { + DEBUG(4, "\nexpect timed out\n", CNULL); + fcode = CF_DIAL; + } + } + if (fcode >= 0) { + DEBUG(4, "login %s\n", "called"); + fcode = login(nf, Flds, Dcf); + } + if (fcode < 0) { + clsacu(); + if (fcode == ABORT) { + fcode = CF_DIAL; + goto keeplooking; + } else { + fclose(fsys); + return CF_LOGIN; + } + } + fclose(fsys); + fioclex(Dcf); + return Dcf; +} + +/* + * connect to remote machine + * + * return codes: + * >0 - file number - ok + * FAIL - failed + */ + +getto(flds) +register char *flds[]; +{ + register struct condev *cd; + int nulldev(), diropn(); + char *line; + + DEBUG(4, "getto: call no. %s ", flds[F_PHONE]); + DEBUG(4, "for sys %s\n", flds[F_NAME]); + + if (snccmp(flds[F_LINE], "LOCAL") == SAME) + line = "ACU"; + else + line = flds[F_LINE]; +#ifdef DIALINOUT + if (snccmp(line, "ACU") != SAME) + reenable(); +#endif + CU_end = nulldev; + if (snccmp(line, PCP) == SAME) { + for(cd = condevs; cd->CU_meth != NULL; cd++) { + if (snccmp(PCP_brand, cd->CU_brand) == SAME) { + CU_end = cd->CU_clos; + return diropn(flds); + } + } + logent(PCP_brand, "UNSUPPORTED ACU TYPE"); + } else { + for (cd = condevs; cd->CU_meth != NULL; cd++) { + if (snccmp(cd->CU_meth, line) == SAME) { + DEBUG(4, "Using %s to call\n", cd->CU_meth); + return (*(cd->CU_gen))(flds); + } + } + DEBUG(1, "Can't find %s, assuming DIR\n", flds[F_LINE]); + } + return diropn(flds); /* search failed, so use direct */ +} + +/* + * close call unit + * + * return codes: none + */ + +int nulldev(); +int (*CU_end)() = nulldev; +clsacu() +{ + /* make *sure* Dcf is no longer exclusive. + * Otherwise dual call-in/call-out modems could get stuck. + * Unfortunately, doing this here is not ideal, but it is the + * easiest place to put the call. + * Hopefully everyone honors the LCK protocol, of course + */ +#ifdef TIOCNXCL + if (!IsTcpIp && Dcf >= 0 && ioctl(Dcf, TIOCNXCL, STBNULL) < 0) + DEBUG(5, "clsacu ioctl %s\n", strerror(errno)); +#endif + if (setjmp(Sjbuf)) + logent(Rmtname, "CLOSE TIMEOUT"); + else { + signal(SIGALRM, (sig_t)alarmtr); + alarm(20); + (*(CU_end))(Dcf); + alarm(0); + } + if (close(Dcf) == 0) { + DEBUG(4, "fd %d NOT CLOSED by CU_clos\n", Dcf); + logent("clsacu", "NOT CLOSED by CU_clos"); + } + Dcf = -1; + CU_end = nulldev; +} + +/* + * expand phone number for given prefix and number + */ + +exphone(in, out) +register char *in, *out; +{ + FILE *fn; + char pre[MAXPH], npart[MAXPH], tpre[MAXPH], p[MAXPH]; + char buf[BUFSIZ]; + register char *s1; + + if (!isascii(*in) || !isalpha(*in)) { + strcpy(out, in); + return; + } + + s1=pre; + while (isascii(*in) && isalpha(*in)) + *s1++ = *in++; + *s1 = '\0'; + s1 = npart; + while (*in != '\0') + *s1++ = *in++; + *s1 = '\0'; + + tpre[0] = '\0'; + if ((fn = fopen(DIALFILE, "r")) == NULL) + DEBUG(2, "CAN'T OPEN %s\n", DIALFILE); + else { + while (cfgets(buf, BUFSIZ, fn)) { + if (sscanf(buf, "%s%s", p, tpre) != 2) + continue; + if (strcmp(p, pre) == SAME) + goto found; + tpre[0] = '\0'; + } + DEBUG(2, "CAN'T FIND dialcodes prefix '%s'\n", pre); + found:; + fclose(fn); + } + + strcpy(out, tpre); + strcat(out, npart); +} + +/* + * read and decode a line from device file + * + * return code - FAIL at end-of file; 0 otherwise + */ + +rddev(fp, dev) +register struct Devices *dev; +FILE *fp; +{ + register int na; + + if (!cfgets(dev->D_argbfr, sizeof(dev->D_argbfr), fp)) + return FAIL; + na = getargs(dev->D_argbfr, dev->D_arg, 20); + ASSERT(na >= 4, "BAD DEVICE ENTRY", dev->D_argbfr, 0); + if (na == 4) { + dev->D_brand = ""; + na++; + } + dev->D_speed = atoi(fdig(dev->D_class)); + dev->D_numargs = na; + return 0; +} + +/* + * set system attribute vector + * + * return codes: + * >0 - number of arguments in vector - succeeded + * CF_SYSTEM - system name not found + * CF_TIME - wrong time to call + */ + +finds(fsys, sysnam, info, flds) +char *sysnam, info[], *flds[]; +FILE *fsys; +{ + int na; + int fcode = 0; + + /* format of fields + * 0 name; + * 1 time + * 2 acu/hardwired + * 3 speed + * etc + */ + while (cfgets(info, MAXC, fsys) != NULL) { + na = getargs(info, flds, MAXC/10); + if (strncmp(sysnam, flds[F_NAME], MAXBASENAME) != SAME) + continue; + if (ifdate(flds[F_TIME]) != FAIL) + /* found a good entry */ + return na; + DEBUG(2, "Wrong time ('%s') to call\n", flds[F_TIME]); + fcode = CF_TIME; + } + return fcode ? fcode : CF_SYSTEM; +} + +/* + * do login conversation + * + * return codes: SUCCESS | FAIL + */ + +login(nf, flds, fn) +register char *flds[]; +int nf, fn; +{ + register char *want, *altern; + int k, ok; + + ASSERT(nf > 4, "TOO FEW LOG FIELDS", CNULL, nf); + if (setjmp(Cjbuf)) + return FAIL; + AbortOn = NULL; + for (k = F_LOGIN; k < nf; k += 2) { + want = flds[k]; + ok = FAIL; + while (ok != SUCCESS) { + altern = index(want, '-'); + if (altern != NULL) + *altern++ = '\0'; + if (strcmp(want, "ABORT") == 0) { + AbortOn = flds[k+1]; + DEBUG(4, "ABORT ON: %s\n", AbortOn); + goto nextfield; + } + DEBUG(4, "wanted \"%s\"\n", want); + ok = expect(want, fn); + DEBUG(4, "got: %s\n", ok ? "?" : "that"); + if (ok == FAIL) { + if (altern == NULL) { + logent("LOGIN", _FAILED); + return FAIL; + } + want = index(altern, '-'); + if (want != NULL) + *want++ = '\0'; + sendthem(altern, fn); + } else + if (ok == ABORT) { + logent("LOGIN ABORTED", _FAILED); + return ABORT; + } + } + sleep(1); + if (k+1 < nf) + sendthem(flds[k+1], fn); +nextfield: ; + } + return SUCCESS; +} + + +/* conditional table generation to support odd speeds */ +struct sg_spds {int sp_val, sp_name;} spds[] = { +#ifdef B50 + { 50, B50}, +#endif +#ifdef B75 + { 75, B75}, +#endif +#ifdef B110 + { 110, B110}, +#endif +#ifdef B150 + { 150, B150}, +#endif +#ifdef B200 + { 200, B200}, +#endif +#ifdef B300 + { 300, B300}, +#endif +#ifdef B600 + {600, B600}, +#endif +#ifdef B1200 + {1200, B1200}, +#endif +#ifdef B1800 + {1800, B1800}, +#endif +#ifdef B2000 + {2000, B2000}, +#endif +#ifdef B2400 + {2400, B2400}, +#endif +#ifdef B3600 + {3600, B3600}, +#endif +#ifdef B4800 + {4800, B4800}, +#endif +#ifdef B7200 + {7200, B7200}, +#endif +#ifdef B9600 + {9600, B9600}, +#endif +#ifdef B19200 + {19200, B19200}, +#endif +#ifdef EXTA + {19200, EXTA}, +#endif + {0, 0} +}; + +/* + * set speed/echo/mode... + * + * return codes: none + */ + +fixline(tty, spwant) +int tty, spwant; +{ +#ifdef USG + struct termio ttbuf; +#else + struct sgttyb ttbuf; +#endif + register struct sg_spds *ps; + int speed = -1; + + for (ps = spds; ps->sp_val; ps++) + if (ps->sp_val == spwant) + speed = ps->sp_name; + ASSERT(speed >= 0, "BAD SPEED", CNULL, speed); +#ifdef USG + if (ioctl(tty, TCGETA, &ttbuf) < 0) + return FAIL; + /* ttbuf.sg_flags = (ANYP|RAW); + ttbuf.sg_ispeed = ttbuf.sg_ospeed = speed; */ + ttbuf.c_iflag = (ushort)0; + ttbuf.c_oflag = (ushort)0; + ttbuf.c_cflag = (speed|CS8|HUPCL|CREAD); + ttbuf.c_lflag = (ushort)0; + ttbuf.c_cc[VMIN] = 6; + ttbuf.c_cc[VTIME] = 1; + if (ioctl(tty, TCSETA, &ttbuf) < 0) + return FAIL; +#else + if (ioctl(tty, TIOCGETP, &ttbuf) < 0) + return FAIL; + ttbuf.sg_flags = (ANYP|RAW); + ttbuf.sg_ispeed = ttbuf.sg_ospeed = speed; + if (ioctl(tty, TIOCSETP, &ttbuf) < 0) + return FAIL; +#endif +#ifndef USG + if (ioctl(tty, TIOCHPCL, STBNULL) < 0) + return FAIL; + if (ioctl(tty, TIOCEXCL, STBNULL) < 0) + return FAIL; +#endif + linebaudrate = spwant; + return SUCCESS; +} + +#define MR 100 + +/* + * look for expected string + * + * return codes: + * 0 - found + * FAIL - lost line or too many characters read + * some character - timed out + */ + +expect(str, fn) +register char *str; +int fn; +{ + char rdvec[MR]; + register char *rp = rdvec, *strptr; + int kr, cnt_char; + char nextch; + int timo = MAXMSGTIME; + + if (*str == '\0' || strcmp(str, "\"\"") == SAME) + return SUCCESS; + /* Cleanup str, convert \0xx strings to one char */ + for (strptr = str; *strptr; strptr++) { + if (*strptr == '\\') + switch(*++strptr) { + case 's': + DEBUG(5, "BLANK\n", CNULL); + *strptr = ' '; + break; + default: + strptr--; /* back up to backslash */ + sscanf(strptr + 1,"%o", &cnt_char); + DEBUG(6, "BACKSLASHED %02xH\n", cnt_char); + *strptr = (char) (cnt_char); + strcpy(&strptr[1], &strptr[4]); + } + } + + strptr = index(str, '~'); + if (strptr != NULL) { + *strptr++ = '\0'; + timo = atoi(strptr); + if (timo <= 0) + timo = MAXMSGTIME; + } + + if (setjmp(Sjbuf)) + return FAIL; + signal(SIGALRM, (sig_t)alarmtr); + alarm(timo); + *rp = 0; + while (notin(str, rdvec)) { + int c; + if(AbortOn != NULL && !notin(AbortOn, rdvec)) { + DEBUG(1, "Call aborted on '%s'\n", AbortOn); + alarm(0); + return ABORT; + } + kr = read(fn, &nextch, 1); + if (kr <= 0) { + alarm(0); + DEBUG(4, "lost line kr - %d\n, ", kr); + logent("LOGIN", "LOST LINE"); + return FAIL; + } + c = nextch & 0177; + if (c == '\0') + continue; + DEBUG(4, (isprint(c) || isspace(c)) ? "%c" : "\\%03o", c); + *rp++ = c; + if (rp >= rdvec + MR) { + register char *p; + for (p = rdvec+MR/2; p < rp; p++) + *(p-MR/2) = *p; + rp -= MR/2; + } + *rp = '\0'; + } + alarm(0); + return SUCCESS; +} + + +/* + * Determine next file descriptor that would be allocated. + * This permits later closing of a file whose open was interrupted. + * It is a UNIX kernel problem, but it has to be handled. + * unc!smb (Steve Bellovin) probably first discovered it. + */ +getnextfd() +{ + close(next_fd = open("/", 0)); +} + +/* + * send line of login sequence + * + * return codes: none + */ +sendthem(str, fn) +register char *str; +int fn; +{ + register char *strptr; + int i, n, cr = 1; + register char c; + static int p_init = 0; + + DEBUG(5, "send \"%s\"\n", str); + + if (!p_init) { + p_init++; + bld_partab(P_EVEN); + } + + if (prefix("BREAK", str)) { + sscanf(&str[5], "%1d", &i); + if (i <= 0 || i > 10) + i = 3; + /* send break */ + genbrk(fn, i); + return; + } + + if (prefix("PAUSE", str)) { + sscanf(&str[5], "%1d", &i); + if (i <= 0 || i > 10) + i = 3; + /* pause for a while */ + sleep((unsigned)i); + return; + } + + if (strcmp(str, "EOT") == SAME) { + p_chwrite(fn, '\04'); + return; + } + + /* Send a '\n' */ + if (strcmp(str, "LF") == SAME) { + p_chwrite(fn, '\n'); + return; + } + + /* Send a '\r' */ + if (strcmp(str, "CR") == SAME) { + p_chwrite(fn, '\r'); + return; + } + + /* Set parity as needed */ + if (strcmp(str, "P_ZERO") == SAME) { + bld_partab(P_ZERO); + return; + } + if (strcmp(str, "P_ONE") == SAME) { + bld_partab(P_ONE); + return; + } + if (strcmp(str, "P_EVEN") == SAME) { + bld_partab(P_EVEN); + return; + } + if (strcmp(str, "P_ODD") == SAME) { + bld_partab(P_ODD); + return; + } + + /* If "", just send '\r' */ + if (strcmp(str, "\"\"") == SAME) { + p_chwrite(fn, '\r'); + return; + } + + strptr = str; + while ((c = *strptr++) != '\0') { + if (c == '\\') { + switch(*strptr++) { + case '\0': + DEBUG(5, "TRAILING BACKSLASH IGNORED\n", CNULL); + --strptr; + continue; + case 's': + DEBUG(5, "BLANK\n", CNULL); + c = ' '; + break; + case 'd': + DEBUG(5, "DELAY\n", CNULL); + sleep(1); + continue; + case 'n': + DEBUG(5, "NEW LINE\n", CNULL); + c = '\n'; + break; + case 'r': + DEBUG(5, "RETURN\n", CNULL); + c = '\r'; + break; + case 'b': + if (isdigit(*strptr)) { + i = (*strptr++ - '0'); + if (i <= 0 || i > 10) + i = 3; + } else + i = 3; + /* send break */ + genbrk(fn, i); + if (*strptr == '\0') + cr = 0; + continue; + case 'c': + if (*strptr == '\0') { + DEBUG(5, "NO CR\n", CNULL); + cr = 0; + } else + DEBUG(5, "NO CR - IGNORED NOT EOL\n", CNULL); + continue; +#define isoctal(x) ((x >= '0') && (x <= '7')) + default: + if (isoctal(strptr[-1])) { + i = 0; + n = 0; + --strptr; + while (isoctal(*strptr) && ++n <= 3) + i = i * 8 + (*strptr++ - '0'); + DEBUG(5, "\\%o\n", i); + p_chwrite(fn, (char)i); + continue; + } + } + } + p_chwrite(fn, c); + } + + if (cr) + p_chwrite(fn, '\r'); + return; +} + +p_chwrite(fd, c) +int fd; +char c; +{ + c = par_tab[c&0177]; + if (write(fd, &c, 1) != 1) { + logent(strerror(errno), "BAD WRITE"); + longjmp(Cjbuf, 2); + } +} + +/* + * generate parity table for use by p_chwrite. + */ +bld_partab(type) +int type; +{ + register int i, j, n; + + for (i = 0; i < sizeof(par_tab); i++) { + n = 0; + for (j = i&(sizeof(par_tab)-1); j; j = (j-1)&j) + n++; + par_tab[i] = i; + if (type == P_ONE + || (type == P_EVEN && (n&01) != 0) + || (type == P_ODD && (n&01) == 0)) + par_tab[i] |= sizeof(par_tab); + } +} + +/* + * check for occurrence of substring "sh" + * + * return codes: + * 0 - found the string + * 1 - not in the string + */ +notin(sh, lg) +register char *sh, *lg; +{ + while (*lg != '\0') { + if (wprefix(sh, lg)) + return 0; + else + lg++; + } + return 1; +} + +/* + * Allow multiple date specifications separated by ','. + */ +ifdate(p) +register char *p; +{ + register char *np; + register int ret, g; + int rtime, i; + + /* pick up retry time for failures */ + /* global variable Retrytime is set here */ + if ((np = index(p, ';')) == NULL) { + Retrytime = RETRYTIME; + } else { + i = sscanf(np+1, "%d", &rtime); + if (i < 1 || rtime < 0) + rtime = 5; + Retrytime = rtime * 60; + } + + ret = FAIL; + MaxGrade = '\0'; + do { + np = strpbrk(p, ",|"); /* prefer , but allow | for compat */ + if (np) + *np = '\0'; + g = ifadate(p); + DEBUG(11,"ifadate returns %o\n", g); + if (g != FAIL) { + ret = SUCCESS; + if (g > MaxGrade) + MaxGrade = g; + } + if (np) + *np = ','; + p = np + 1; + } while (np); + if (MaxGrade == '\0') + MaxGrade = DefMaxGrade; + return ret; +} + +/* + * this routine will check a string (string) + * like "MoTu0800-1730" to see if the present + * time is within the given limits. + * SIDE EFFECT - Retrytime is set + * + * return codes: + * 0 - not within limits + * 1 - within limits + */ + +ifadate(string) +char *string; +{ + static char *days[]={ + "Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", 0 + }; + time_t clock; + register char *s = string; + int i, tl, th, tn, dayok=0; + struct tm *localtime(); + struct tm *tp; + char *p, MGrade; + + if ((p = index(s, '/')) == NULL) + MGrade = DefMaxGrade; + else + MGrade = p[1]; + + time(&clock); + tp = localtime(&clock); + while (isascii(*s) && isalpha(*s)) { + for (i = 0; days[i]; i++) { + if (prefix(days[i], s)) + if (tp->tm_wday == i) + dayok = 1; + } + + if (prefix("Wk", s)) + if (tp->tm_wday >= 1 && tp->tm_wday <= 5) + dayok = 1; + if (prefix("Any", s)) + dayok = 1; + if (prefix("Evening", s)) { + /* Sat or Sun */ + if (tp->tm_wday == 6 || tp->tm_wday == 0 + || tp->tm_hour >= 17 || tp->tm_hour < 8) + dayok = 1; + } + if (prefix("Night", s)) { + if (tp->tm_wday == 6 /* Sat */ + || tp->tm_hour >= 23 || tp->tm_hour < 8 + /* Sunday before 5pm */ + || (tp->tm_wday == 0 && tp->tm_hour < 17)) + dayok = 1; + } + if (prefix("NonPeak", s)) { /* For Tymnet and PC Pursuit */ + /* Sat or Sun */ + if (tp->tm_wday == 6 || tp->tm_wday == 0 + || tp->tm_hour >= 18 || tp->tm_hour < 7) + dayok = 1; + } + s++; + } + + if (dayok == 0 && s != string) + return FAIL; + i = sscanf(s, "%d-%d", &tl, &th); + if (i < 2) + return MGrade; + tn = tp->tm_hour * 100 + tp->tm_min; + if (th < tl) { /* crosses midnight */ + if (tl <= tn || tn < th) + return MGrade; + } else { + if (tl <= tn && tn < th) + return MGrade; + } + return FAIL; +} + +/* + * find first digit in string + * + * return - pointer to first digit in string or end of string + */ +char * +fdig(cp) +register char *cp; +{ + register char *c; + + for (c = cp; *c; c++) + if (*c >= '0' && *c <= '9') + break; + return c; +} + +/* + * Compare strings: s1>s2: >0 s1==s2: 0 s1s2: >0 s1==s2: 0 s1= 0 && c1 == c2) { + if (*s1++ == '\0') + return 0; + s2++; + if (islower(*s1)) + c1 = toupper(*s1); + else + c1 = *s1; + if (islower(*s2)) + c2 = toupper(*s2); + else + c2 = *s2; + } + return n<0 ? 0 : (c1 - c2); +} +/* + * do chat script + * occurs after local port is opened, + * before 'dialing' the other machine. + */ +dochat(dev, flds, fd) +register struct Devices *dev; +char *flds[]; +int fd; +{ + register int i; + register char *p; + char bfr[sizeof(dev->D_argbfr)]; + + if (dev->D_numargs <= 5) + return(0); + DEBUG(4, "dochat called %d\n", dev->D_numargs); + for (i = 0; i < dev->D_numargs-5; i++) { + sprintf(bfr, dev->D_arg[D_CHAT+i], flds[F_PHONE]); + if (strcmp(bfr, dev->D_arg[D_CHAT+i])) { + p = (char *)malloc((unsigned)strlen(bfr)+1); + if (p != NULL) { + strcpy(p, bfr); + dev->D_arg[D_CHAT+i] = p; + } + } + } + /* following is a kludge because login() arglist is a kludge */ + i = login(dev->D_numargs, &dev->D_arg[D_CHAT-5], fd); + /* + * If login() last did a sendthem(), must pause so things can settle. + * But don't bother if chat failed. + */ + if (i == 0 && (dev->D_numargs&01)) + sleep(2); + return(i); +} + +/* + * fix kill/echo/raw on line + * + * return codes: none + */ +fixmode(tty) +register int tty; +{ +#ifdef USG + struct termio ttbuf; +#else + struct sgttyb ttbuf; +#endif + register struct sg_spds *ps; + int speed; + + if (IsTcpIp) + return; +#ifdef USG + ioctl(tty, TCGETA, &ttbuf); + ttbuf.c_iflag = ttbuf.c_oflag = ttbuf.c_lflag = (ushort)0; + speed = ttbuf.c_cflag &= (CBAUD); + ttbuf.c_cflag |= (CS8|CREAD); + ttbuf.c_cc[VMIN] = 6; + ttbuf.c_cc[VTIME] = 1; + ioctl(tty, TCSETA, &ttbuf); +#else + ioctl(tty, TIOCGETP, &ttbuf); + ttbuf.sg_flags = (ANYP | RAW); + ioctl(tty, TIOCSETP, &ttbuf); + speed = ttbuf.sg_ispeed; + ioctl(tty, TIOCEXCL, STBNULL); +#endif + + for (ps = spds; ps->sp_val; ps++) + if (ps->sp_name == speed) { + linebaudrate = ps->sp_val; + DEBUG(9,"Incoming baudrate is %d\n", linebaudrate); + return; + } + ASSERT(linebaudrate >= 0, "BAD SPEED", CNULL, speed); +} + diff --git a/src/cmd/uucp/cpmv.c b/src/cmd/uucp/cpmv.c new file mode 100644 index 0000000..568920a --- /dev/null +++ b/src/cmd/uucp/cpmv.c @@ -0,0 +1,72 @@ +#ifndef lint +static char sccsid[] = "@(#)cpmv.c 5.5 (Berkeley) 10/9/85"; +#endif + +#include "uucp.h" +#include + +/*LINTLIBRARY*/ + +/* + * copy f1 to f2 + * + * return - SUCCESS | FAIL + */ +xcp(f1, f2) +char *f1, *f2; +{ + char buf[BUFSIZ]; + register int len; + register int fp1, fp2; + char *lastpart(); + char full[MAXFULLNAME]; + struct stat s; + + if ((fp1 = open(subfile(f1), 0)) < 0) + return FAIL; + strcpy(full, f2); + if (stat(subfile(f2), &s) == 0) { + /* check for directory */ + if ((s.st_mode & S_IFMT) == S_IFDIR) { + strcat(full, "/"); + strcat(full, lastpart(f1)); + } + } + DEBUG(4, "full %s\n", full); + if ((fp2 = creat(subfile(full), 0666)) < 0) { + close(fp1); + return FAIL; + } + while((len = read(fp1, buf, BUFSIZ)) > 0) + if (write(fp2, buf, len) != len) { + len = -1; + break; + } + + close(fp1); + close(fp2); + return len < 0 ? FAIL: SUCCESS; +} + + +/* + * move f1 to f2 + * + * return 0 ok | FAIL failed + */ +xmv(f1, f2) +register char *f1, *f2; +{ + register int ret; + + (void) unlink(subfile(f2)); + if (link(subfile(f1), subfile(f2)) < 0) { + /* copy file */ + ret = xcp(f1, f2); + if (ret == 0) + unlink(subfile(f1)); + return ret; + } + (void) unlink(subfile(f1)); + return 0; +} diff --git a/src/cmd/uucp/expfile.c b/src/cmd/uucp/expfile.c new file mode 100644 index 0000000..333d379 --- /dev/null +++ b/src/cmd/uucp/expfile.c @@ -0,0 +1,128 @@ +#ifndef lint +static char sccsid[] = "@(#)expfile.c 5.5 (Berkeley) 6/19/85"; +#endif + +#include "uucp.h" +#include +#include + +/*LINTLIBRARY*/ + +/* + * expand file name + * + * return codes: 0 - Ordinary spool area file + * 1 - Other normal file + * FAIL - no Wrkdir name available + */ + +expfile(file) +char *file; +{ + register char *fpart, *p; + char user[WKDSIZE], *up; + char full[MAXFULLNAME]; + int uid; + + switch(file[0]) { + case '/': + return 1; + case '~': + for (fpart = file + 1, up = user; *fpart != '\0' + && *fpart != '/'; fpart++) + *up++ = *fpart; + *up = '\0'; + if (!*user || gninfo(user, &uid, full) != 0) { + strcpy(full, PUBDIR); + } + + strcat(full, fpart); + strcpy(file, full); + return 1; + default: + p = index(file, '/'); + strcpy(full, Wrkdir); + strcat(full, "/"); + strcat(full, file); + strcpy(file, full); + if (Wrkdir[0] == '\0') + return FAIL; + else if (p != NULL) + return 1; + return 0; + } +} + + +/* + * check if directory name + * + * return codes: 0 - not directory | 1 - is directory + */ + +isdir(name) +char *name; +{ + register int ret; + struct stat s; + + ret = stat(subfile(name), &s); + if (ret < 0) + return 0; + if ((s.st_mode & S_IFMT) == S_IFDIR) + return 1; + return 0; +} + + +/* + * make all necessary directories + * + * return SUCCESS | FAIL + */ + +mkdirs(name) +char *name; +{ + int ret, mask; + char dir[MAXFULLNAME]; + register char *p; + + for (p = dir + 1;; p++) { + strcpy(dir, name); + if ((p = index(p, '/')) == NULL) + return SUCCESS; + *p = '\0'; + if (isdir(dir)) + continue; + + DEBUG(4, "mkdir - %s\n", dir); + mask = umask(0); + ret = mkdir(dir, 0777); + umask(mask); + if (ret != 0) + return FAIL; + } + /* NOTREACHED */ +} + +/* + * expfile and check return + * print error if it failed. + * + * return code - SUCCESS - ok; FAIL if expfile failed + */ + +ckexpf(file) +register char *file; +{ + + if (expfile(file) != FAIL) + return SUCCESS; + + /* could not expand file name */ + /* the gwd routine failed */ + + logent("CAN'T EXPAND FILENAME - PWD FAILED", file+1); + return FAIL; +} diff --git a/src/cmd/uucp/fio.c b/src/cmd/uucp/fio.c new file mode 100644 index 0000000..10816cf --- /dev/null +++ b/src/cmd/uucp/fio.c @@ -0,0 +1,549 @@ +#ifndef lint +static char sccsid[] = "@(#)fio.c 5.3 (Berkeley) 10/9/85"; +#endif + +/* + * flow control protocol. + * + * This protocol relies on flow control of the data stream. + * It is meant for working over links that can (almost) be + * guaranteed to be errorfree, specifically X.25/PAD links. + * A sumcheck is carried out over a whole file only. If a + * transport fails the receiver can request retransmission(s). + * This protocol uses a 7-bit datapath only, so it can be + * used on links that are not 8-bit transparent. + * + * When using this protocol with an X.25 PAD: + * Although this protocol uses no control chars except CR, + * control chars NULL and ^P are used before this protocol + * is started; since ^P is the default char for accessing + * PAD X.28 command mode, be sure to disable that access + * (PAD par 1). Also make sure both flow control pars + * (5 and 12) are set. The CR used in this proto is meant + * to trigger packet transmission, hence par 3 should be + * set to 2; a good value for the Idle Timer (par 4) is 10. + * All other pars should be set to 0. + * + * Normally a calling site will take care of setting the + * local PAD pars via an X.28 command and those of the remote + * PAD via an X.29 command, unless the remote site has a + * special channel assigned for this protocol with the proper + * par settings. + * + * Additional comments for hosts with direct X.25 access: + * - the global variable IsTcpIp, when set, excludes the ioctl's, + * so the same binary can run on X.25 and non-X.25 hosts; + * - reads are done in small chunks, which can be smaller than + * the packet size; your X.25 driver must support that. + * + * + * Author: + * Piet Beertema, CWI, Amsterdam, Sep 1984 + * Modified for X.25 hosts: + * Robert Elz, Melbourne Univ, Mar 1985 + */ + +#include "uucp.h" +#include +#ifdef USG +#include +#else !USG +#include +#endif !USG +#include + +#define FIBUFSIZ 256 /* for X.25 interfaces: set equal to packet size, + * but see comment above + */ + +#define FOBUFSIZ 256 /* for X.25 interfaces: set equal to packet size; + * otherwise make as large as feasible to reduce + * number of write system calls + */ + +#ifndef MAXMSGLEN +#define MAXMSGLEN BUFSIZ +#endif MAXMSGLEN + +static int fchksum; +static jmp_buf Ffailbuf; + +static +falarm() +{ + signal(SIGALRM, falarm); + longjmp(Ffailbuf, 1); +} + +static int (*fsig)(); + +#ifndef USG +#define TCGETA TIOCGETP +#define TCSETA TIOCSETP +#define termio sgttyb +#endif USG + +fturnon() +{ + int ret; + struct termio ttbuf; + + if (!IsTcpIp) { + ioctl(Ifn, TCGETA, &ttbuf); +#ifdef USG + ttbuf.c_iflag = IXOFF|IXON|ISTRIP; + ttbuf.c_cc[VMIN] = FIBUFSIZ > 64 ? 64 : FIBUFSIZ; + ttbuf.c_cc[VTIME] = 5; +#else !USG + ttbuf.sg_flags = ANYP|CBREAK|TANDEM; +#endif USG + ret = ioctl(Ifn, TCSETA, &ttbuf); + ASSERT(ret >= 0, "STTY FAILED", "", ret); + } + fsig = signal(SIGALRM, falarm); + /* give the other side time to perform its ioctl; + * otherwise it may flush out the first data this + * side is about to send. + */ + sleep(2); + return SUCCESS; +} + +fturnoff() +{ + (void) signal(SIGALRM, fsig); + return SUCCESS; +} + +fwrmsg(type, str, fn) +register char *str; +int fn; +char type; +{ + register char *s; + char bufr[MAXMSGLEN]; + + s = bufr; + *s++ = type; + while (*str) + *s++ = *str++; + if (*(s-1) == '\n') + s--; + *s++ = '\r'; + *s = 0; + (void) write(fn, bufr, s - bufr); + return SUCCESS; +} + +frdmsg(str, fn) +register char *str; +register int fn; +{ + register char *smax; + + if (setjmp(Ffailbuf)) + return FAIL; + smax = str + MAXMSGLEN - 1; + (void) alarm(2*MAXMSGTIME); + for (;;) { + if (read(fn, str, 1) <= 0) + goto msgerr; + *str &= 0177; + if (*str == '\r') + break; + if (*str < ' ') { + continue; + } + if (str++ >= smax) + goto msgerr; + } + *str = '\0'; + (void) alarm(0); + return SUCCESS; +msgerr: + (void) alarm(0); + return FAIL; +} + +fwrdata(fp1, fn) +FILE *fp1; +int fn; +{ + register int alen, ret; + register char *obp; + char ack, ibuf[MAXMSGLEN]; + int flen, mil, retries = 0; + long abytes, fbytes; + struct timeb t1, t2; + + ret = FAIL; +retry: + fchksum = 0xffff; + abytes = fbytes = 0L; + ack = '\0'; +#ifdef USG + time(&t1.time); + t1.millitm = 0; +#else !USG + ftime(&t1); +#endif !USG + do { + alen = fwrblk(fn, fp1, &flen); + fbytes += flen; + if (alen <= 0) { + abytes -= alen; + goto acct; + } + abytes += alen; + } while (!feof(fp1) && !ferror(fp1)); + DEBUG(8, "\nchecksum: %04x\n", fchksum); + if (frdmsg(ibuf, fn) != FAIL) { + if ((ack = ibuf[0]) == 'G') + ret = SUCCESS; + DEBUG(4, "ack - '%c'\n", ack); + } +acct: +#ifdef USG + time(&t2.time); + t2.millitm = 0; +#else !USG + ftime(&t2); +#endif !USG + Now = t2; + t2.time -= t1.time; + mil = t2.millitm - t1.millitm; + if (mil < 0) { + --t2.time; + mil += 1000; + } + sprintf(ibuf, "sent data %ld bytes %ld.%02d secs", + fbytes, (long)t2.time, mil / 10); + sysacct(abytes, t2.time); + if (retries > 0) + sprintf(&ibuf[strlen(ibuf)], ", %d retries", retries); + DEBUG(1, "%s\n", ibuf); + syslog(ibuf); + if (ack == 'R') { + DEBUG(4, "RETRY:\n", 0); + fseek(fp1, 0L, 0); + retries++; + goto retry; + } +#ifdef SYSACCT + if (ret == FAIL) + sysaccf(NULL); /* force accounting */ +#endif SYSACCT + return ret; +} + +/* max. attempts to retransmit a file: */ +#define MAXRETRIES (fbytes < 10000L ? 2 : 1) + +frddata(fn, fp2) +register int fn; +register FILE *fp2; +{ + register int flen; + register char eof; + char ibuf[FIBUFSIZ]; + int ret, mil, retries = 0; + long alen, abytes, fbytes; + struct timeb t1, t2; + + ret = FAIL; +retry: + fchksum = 0xffff; + abytes = fbytes = 0L; +#ifdef USG + time(&t1.time); + t1.millitm = 0; +#else !USG + ftime(&t1); +#endif !USG + do { + flen = frdblk(ibuf, fn, &alen); + abytes += alen; + if (flen < 0) + goto acct; + if (eof = flen > FIBUFSIZ) + flen -= FIBUFSIZ + 1; + fbytes += flen; + if (fwrite(ibuf, sizeof (char), flen, fp2) != flen) + goto acct; + } while (!eof); + ret = SUCCESS; +acct: +#ifdef USG + time(&t2.time); + t2.millitm = 0; +#else !USG + ftime(&t2); +#endif !USG + Now = t2; + t2.time -= t1.time; + mil = t2.millitm - t1.millitm; + if (mil < 0) { + --t2.time; + mil += 1000; + } + sprintf(ibuf, "received data %ld bytes %ld.%02d secs", + fbytes, (long)t2.time, mil/10); + if (retries > 0) + sprintf(&ibuf[strlen(ibuf)]," %d retries", retries); + sysacct(abytes, t2.time); + DEBUG(1, "%s\n", ibuf); + syslog(ibuf); + if (ret == FAIL) { + if (retries++ < MAXRETRIES) { + DEBUG(8, "send ack: 'R'\n", 0); + fwrmsg('R', "", fn); + fseek(fp2, 0L, 0); + DEBUG(4, "RETRY:\n", 0); + goto retry; + } + DEBUG(8, "send ack: 'Q'\n", 0); + fwrmsg('Q', "", fn); +#ifdef SYSACCT + sysaccf(NULL); /* force accounting */ +#endif SYSACCT + } + else { + DEBUG(8, "send ack: 'G'\n", 0); + fwrmsg('G', "", fn); + } + return ret; +} + +static +frdbuf(blk, len, fn) +register char *blk; +register int len; +register int fn; +{ + static int ret = FIBUFSIZ / 2; + + if (setjmp(Ffailbuf)) + return FAIL; + (void) alarm(MAXMSGTIME); + ret = read(fn, blk, len); + alarm(0); + return ret <= 0 ? FAIL : ret; +} + +#if !defined(BSD4_2) && !defined(USG) +/* call ultouch every TC calls to either frdblk or fwrblk */ +#define TC 20 +static int tc = TC; +#endif !defined(BSD4_2) && !defined(USG) + +/* Byte conversion: + * + * from pre to + * 000-037 172 100-137 + * 040-171 040-171 + * 172-177 173 072-077 + * 200-237 174 100-137 + * 240-371 175 040-171 + * 372-377 176 072-077 + */ + +static +fwrblk(fn, fp, lenp) +int fn; +register FILE *fp; +int *lenp; +{ + register char *op; + register int c, sum, nl, len; + char obuf[FOBUFSIZ + 8]; + int ret; + +#if !defined(BSD4_2) && !defined(USG) + /* call ultouch occasionally */ + if (--tc < 0) { + tc = TC; + ultouch(); + } +#endif !defined(BSD4_2) && !defined(USG) + op = obuf; + nl = 0; + len = 0; + sum = fchksum; + while ((c = getc(fp)) != EOF) { + len++; + if (sum & 0x8000) { + sum <<= 1; + sum++; + } else + sum <<= 1; + sum += c; + sum &= 0xffff; + if (c & 0200) { + c &= 0177; + if (c < 040) { + *op++ = '\174'; + *op++ = c + 0100; + } else + if (c <= 0171) { + *op++ = '\175'; + *op++ = c; + } + else { + *op++ = '\176'; + *op++ = c - 0100; + } + nl += 2; + } else { + if (c < 040) { + *op++ = '\172'; + *op++ = c + 0100; + nl += 2; + } else + if (c <= 0171) { + *op++ = c; + nl++; + } else { + *op++ = '\173'; + *op++ = c - 0100; + nl += 2; + } + } + if (nl >= FOBUFSIZ - 1) { + /* + * peek at next char, see if it will fit + */ + c = getc(fp); + if (c == EOF) + break; + (void) ungetc(c, fp); + if (nl >= FOBUFSIZ || c < 040 || c > 0171) + goto writeit; + } + } + /* + * At EOF - append checksum, there is space for it... + */ + sprintf(op, "\176\176%04x\r", sum); + nl += strlen(op); +writeit: + *lenp = len; + fchksum = sum; + DEBUG(8, "%d/", len); + DEBUG(8, "%d,", nl); + ret = write(fn, obuf, nl); + return ret == nl ? nl : ret < 0 ? 0 : -ret; +} + +static +frdblk(ip, fn, rlen) +register char *ip; +int fn; +long *rlen; +{ + register char *op, c; + register int sum, len, nl; + char buf[5], *erbp = ip; + int i; + static char special = 0; + +#if !defined(BSD4_2) && !defined(USG) + /* call ultouch occasionally */ + if (--tc < 0) { + tc = TC; + ultouch(); + } +#endif !defined(BSD4_2) && !defined(USG) + if ((len = frdbuf(ip, FIBUFSIZ, fn)) == FAIL) { + *rlen = 0; + goto dcorr; + } + *rlen = len; + DEBUG(8, "%d/", len); + op = ip; + nl = 0; + sum = fchksum; + do { + if ((*ip &= 0177) >= '\172') { + if (special) { + DEBUG(8, "%d", nl); + special = 0; + op = buf; + if (*ip++ != '\176' || (i = --len) > 5) + goto dcorr; + while (i--) + *op++ = *ip++ & 0177; + while (len < 5) { + i = frdbuf(&buf[len], 5 - len, fn); + if (i == FAIL) { + len = FAIL; + goto dcorr; + } + DEBUG(8, ",%d", i); + len += i; + *rlen += i; + while (i--) + *op++ &= 0177; + } + if (buf[4] != '\r') + goto dcorr; + sscanf(buf, "%4x", &fchksum); + DEBUG(8, "\nchecksum: %04x\n", sum); + if (fchksum == sum) + return FIBUFSIZ + 1 + nl; + else { + DEBUG(8, "\n", 0); + DEBUG(4, "Bad checksum\n", 0); + return FAIL; + } + } + special = *ip++; + } else { + if (*ip < '\040') { + /* error: shouldn't get control chars */ + goto dcorr; + } + switch (special) { + case 0: + c = *ip++; + break; + case '\172': + c = *ip++ - 0100; + break; + case '\173': + c = *ip++ + 0100; + break; + case '\174': + c = *ip++ + 0100; + break; + case '\175': + c = *ip++ + 0200; + break; + case '\176': + c = *ip++ + 0300; + break; + } + *op++ = c; + if (sum & 0x8000) { + sum <<= 1; + sum++; + } else + sum <<= 1; + sum += c & 0377; + sum &= 0xffff; + special = 0; + nl++; + } + } while (--len); + fchksum = sum; + DEBUG(8, "%d,", nl); + return nl; +dcorr: + DEBUG(8, "\n", 0); + DEBUG(4, "Data corrupted\n", 0); + while (len != FAIL) { + if ((len = frdbuf(erbp, FIBUFSIZ, fn)) != FAIL) + *rlen += len; + } + return FAIL; +} + diff --git a/src/cmd/uucp/gename.c b/src/cmd/uucp/gename.c new file mode 100644 index 0000000..b9a6d85 --- /dev/null +++ b/src/cmd/uucp/gename.c @@ -0,0 +1,86 @@ +#ifndef lint +static char sccsid[] = "@(#)gename.c 5.6 (Berkeley) 10/9/85"; +#endif + +#include "uucp.h" +#include + +#define SEQLEN 4 +#define SLOCKTIME 10L +#define SLOCKTRIES 5 +/* + * the alphabet can be anything, but if it's not in ascii order, + * sequence ordering is not preserved + */ +static char alphabet[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + +#ifdef BSD4_2 +#include +#endif + +/*LINTLIBRARY*/ + +/* + * generate file name + */ +gename(pre, sys, grade, file) +char pre, *sys, grade, *file; +{ + register int i, fd; + static char snum[5]; + static char *lastchar = NULL; + + if (lastchar == NULL || (snum[SEQLEN-1] = *(lastchar++)) == '\0') { +#ifndef BSD4_2 + for (i = 0; i < SLOCKTRIES; i++) { + if (!ulockf(SEQLOCK, SLOCKTIME)) + break; + sleep(5); + } + + if (i >= SLOCKTRIES) { + logent(SEQLOCK, "CAN NOT LOCK"); + goto getrandseq; + } +#endif + + if ((fd = open(SEQFILE, 2)) >= 0) { + register char *p; +#ifdef BSD4_2 + flock(fd, LOCK_EX); +#endif + read(fd, snum, SEQLEN); + /* increment the penultimate character */ + for (i = SEQLEN - 2; i >= 0; --i) { + if ((p = index(alphabet, snum[i])) == NULL) + goto getrandseq; + if (++p < &alphabet[sizeof alphabet - 1]) { + snum[i] = *p; + break; + } else /* carry */ + snum[i] = alphabet[0]; /* continue */ + } + snum[SEQLEN-1] = alphabet[0]; + } else { + extern int errno; + fd = creat(SEQFILE, 0666); +getrandseq: srand((int)time((time_t *)0)); + assert(SEQFILE, "is missing or trashed\n", errno); + for (i = 0; i < SEQLEN; i++) + snum[i] = alphabet[rand() % (sizeof alphabet - 1)]; + snum[SEQLEN-1] = alphabet[0]; + } + + if (fd >= 0) { + lseek(fd, 0L, 0); + write(fd, snum, SEQLEN); + close(fd); + } +#ifndef BSD4_2 + rmlock(SEQLOCK); +#endif + lastchar = alphabet + 1; + } + sprintf(file,"%c.%.*s%c%.*s", pre, SYSNSIZE, sys, grade, SEQLEN, snum); + DEBUG(4, "file - %s\n", file); +} diff --git a/src/cmd/uucp/getargs.c b/src/cmd/uucp/getargs.c new file mode 100644 index 0000000..234b0ed --- /dev/null +++ b/src/cmd/uucp/getargs.c @@ -0,0 +1,98 @@ +#ifndef lint +static char sccsid[] = "@(#)getargs.c 5.3 (Berkeley) 6/19/85"; +#endif + +#include "uucp.h" + +/*LINTLIBRARY*/ + +/* + * getargs - this routine will generate a vector of + * pointers (arps) to the substrings in string "s". + * Each substring is separated by blanks and/or tabs. + * + * If FANCYARGS is defined, you get the following: + * Strings containing blanks may be specified by quoting, + * in a manner similar to using the shell. + * Control characters are entered by ^X where X is any + * character; ^? gets you a rubout and ^^ is a real ^. + * Warning (rti!trt): I doubt FANCYARGS is wise, since getargs + * is used all over the place. Its features may be useful + * but a separate fancy_getargs() should be called instead. + * + * return - the number of subfields, or -1 if >= maxargs. + */ + +getargs(s, arps, maxargs) +register char *s; +char *arps[]; +int maxargs; +{ + register int i; +#ifdef FANCYARGS + register char *sp; + register char qchar; +#endif + + i = 0; +#ifndef FANCYARGS + while (i < maxargs) { + while (*s == ' ' || *s == '\t') + *s++ = '\0'; + if (*s == '\n') + *s = '\0'; + if (*s == '\0') + break; + arps[i++] = s++; + while (*s != '\0' && *s != ' ' + && *s != '\t' && *s != '\n') + s++; + } +#else + while (i < maxargs) { + while (*s == ' ' || *s == '\t') + ++s; + if (*s == '\n' || *s == '\0') + break; + arps[i++] = sp = s; + qchar = 0; + while(*s != '\0' && *s != '\n') { + if (qchar == 0 && (*s == ' ' || *s == '\t')) { + ++s; + break; + } + switch(*s) { + default: + *sp++ = *s++; + break; + case '^': + if(*++s == '^') + *sp++ = '^'; + else if(*s == '?') + *sp++ = 0177; + else + *sp++ = *s & 037; + s++; + break; + case '"': + case '\'': + if(qchar == *s) { + qchar = 0; + ++s; + break; + } + if(qchar) + *sp++ = *s++; + else + qchar = *s++; + break; + } + } + *sp++ = 0; + } +#endif + if (i >= maxargs) + return FAIL; + arps[i] = NULL; + return i; +} diff --git a/src/cmd/uucp/getprm.c b/src/cmd/uucp/getprm.c new file mode 100644 index 0000000..31b6e4d --- /dev/null +++ b/src/cmd/uucp/getprm.c @@ -0,0 +1,68 @@ +#ifndef lint +static char sccsid[] = "@(#)getprm.c 5.4 (Berkeley) 10/9/85"; +#endif + +#include "uucp.h" +#include + +#define LQUOTE '(' +#define RQUOTE ')' + +/*LINTLIBRARY*/ + +/* + * get next parameter from s + * + * return - pointer to next character in s + */ + +char * +getprm(s, prm) +register char *s, *prm; +{ + register char *c; + + while (*s == ' ' || *s == '\t' || *s == '\n') + s++; + + *prm = '\0'; + if (*s == '\0') + return NULL; + + if (*s == '>' || *s == '<' || *s == '|' + || *s == ';' || *s == '&') { + *prm++ = *s++; + *prm = '\0'; + return s; + } + + /* look for quoted argument */ + if (*s == LQUOTE) { + if ((c = index(s + 1, RQUOTE)) != NULL) { + c++; + while (c != s) + *prm++ = *s++; + *prm = '\0'; + return s; + } + } + + /* look for ` ` string */ + if (*s == '`') { + if ((c = index(s + 1, '`')) != NULL) { + c++; + while (c != s) + *prm++ = *s++; + *prm = '\0'; + return s; + } + } + + while (*s != ' ' && *s != '\t' && *s != '<' + && *s != '>' && *s != '|' && *s != '\0' + && *s != '&' && *s != ';' && *s != '\n') + *prm++ = *s++; + *prm = '\0'; + + return s; +} diff --git a/src/cmd/uucp/getpwinfo.c b/src/cmd/uucp/getpwinfo.c new file mode 100644 index 0000000..6e54801 --- /dev/null +++ b/src/cmd/uucp/getpwinfo.c @@ -0,0 +1,67 @@ +#if !defined(lint) && defined(DOSCCS) +static char sccsid[] = "@(#)getpwinfo.c 5.3.1 (2.11BSD) 1997/10/2"; +#endif + +#include "uucp.h" +#include + +/*LINTLIBRARY*/ + +/* + * get passwd file info for uid + * + * return codes: SUCCESS | FAIL + * + */ + +guinfo(uid, name, path) +int uid; +register char *path, *name; +{ + register struct passwd *pwd; + char *l; + + if ((l = getlogin()) == NULL) { + l = getenv("USER"); + } + if (l != NULL) { + pwd = getpwnam(l); + if (pwd != NULL && pwd->pw_uid == uid) + goto setup; + } + if ((pwd = getpwuid(uid)) == NULL) { + /* can not find uid in passwd file */ + *name = '\0'; + *path = '\0'; + return FAIL; + } + + setup: + strcpy(path, pwd->pw_dir); + strcpy(name, pwd->pw_name); + return SUCCESS; +} + + +/* + * get passwd file info for name + * + * return codes: SUCCESS | FAIL + */ + +gninfo(name, uid, path) +char *path, *name; +int *uid; +{ + register struct passwd *pwd; + + if ((pwd = getpwnam(name)) == NULL) { + /* can not find name in passwd file */ + *path = '\0'; + return FAIL; + } + + strcpy(path, pwd->pw_dir); + *uid = pwd->pw_uid; + return SUCCESS; +} diff --git a/src/cmd/uucp/gio.c b/src/cmd/uucp/gio.c new file mode 100644 index 0000000..5cb45c8 --- /dev/null +++ b/src/cmd/uucp/gio.c @@ -0,0 +1,236 @@ +#ifndef lint +static char sccsid[] = "@(#)gio.c 5.6 (Berkeley) 10/9/85"; +#endif + +#include "uucp.h" +#include "pk.h" +#include + +jmp_buf Failbuf; + +int Retries = 0; +struct pack *Pk; + +pkfail() +{ + longjmp(Failbuf, 1); +} + +gturnon() +{ + struct pack *pkopen(); + + if (setjmp(Failbuf)) + return FAIL; + Pk = pkopen(Ifn, Ofn); + if (Pk == NULL) + return FAIL; + return SUCCESS; +} + +gturnoff() +{ + if(setjmp(Failbuf)) + return(FAIL); + pkclose(Pk); + return SUCCESS; +} + + +gwrmsg(type, str, fn) +char type; +register char *str; +{ + char bufr[BUFSIZ]; + register char *s; + int len, i; + + if(setjmp(Failbuf)) + return(FAIL); + bufr[0] = type; + s = &bufr[1]; + while (*str) + *s++ = *str++; + *s = '\0'; + if (*(--s) == '\n') + *s = '\0'; + len = strlen(bufr) + 1; + if ((i = len % PACKSIZE)) { + len = len + PACKSIZE - i; + bufr[len - 1] = '\0'; + } + gwrblk(bufr, len, fn); + return SUCCESS; +} + +/*ARGSUSED*/ +grdmsg(str, fn) +register char *str; +{ + unsigned len; + + if(setjmp(Failbuf)) + return FAIL; + for (;;) { + len = pkread(Pk, str, PACKSIZE); + if (len == 0) + continue; + str += len; + if (*(str - 1) == '\0') + break; + } + return SUCCESS; +} + + +gwrdata(fp1, fn) +FILE *fp1; +{ + char bufr[BUFSIZ]; + register int len; + int ret, mil; + struct timeb t1, t2; + long bytes; + char text[BUFSIZ]; + + if(setjmp(Failbuf)) + return FAIL; + bytes = 0L; + Retries = 0; +#ifdef USG + time(&t1.time); + t1.millitm = 0; +#else + ftime(&t1); +#endif + while ((len = read(fileno(fp1), bufr, BUFSIZ)) > 0) { + bytes += len; + ret = gwrblk(bufr, len, fn); + if (ret != len) { + return FAIL; + } + if (len != BUFSIZ) + break; + } + ret = gwrblk(bufr, 0, fn); +#ifdef USG + time(&t2.time); + t2.millitm = 0; +#else + ftime(&t2); +#endif + Now = t2; + t2.time -= t1.time; + mil = t2.millitm - t1.millitm; + if (mil < 0) { + --t2.time; + mil += 1000; + } + sprintf(text, "sent data %ld bytes %ld.%02d secs", + bytes, (long)t2.time, mil/10); + sysacct(bytes, t2.time); + if (Retries > 0) + sprintf((char *)text+strlen(text)," %d retries", Retries); + DEBUG(1, "%s\n", text); + syslog(text); + return SUCCESS; +} + +grddata(fn, fp2) +FILE *fp2; +{ + register int len; + char bufr[BUFSIZ]; + struct timeb t1, t2; + int mil; + long bytes; + char text[BUFSIZ]; + + if(setjmp(Failbuf)) + return FAIL; + bytes = 0L; + Retries = 0; +#ifdef USG + time(&t1.time); + t1.millitm = 0; +#else + ftime(&t1); +#endif + for (;;) { + len = grdblk(bufr, BUFSIZ, fn); + if (len < 0) { + return FAIL; + } + bytes += len; + if (write(fileno(fp2), bufr, len) != len) + return FAIL; + if (len < BUFSIZ) + break; + } +#ifdef USG + time(&t2.time); + t2.millitm = 0; +#else + ftime(&t2); +#endif + Now = t2; + t2.time -= t1.time; + mil = t2.millitm - t1.millitm; + if (mil < 0) { + --t2.time; + mil += 1000; + } + sprintf(text, "received data %ld bytes %ld.%02d secs", + bytes, (long)t2.time, mil/10); + sysacct(bytes, t2.time); + if (Retries > 0) + sprintf((char *)text+strlen(text)," %d retries", Retries); + DEBUG(1, "%s\n", text); + syslog(text); + return SUCCESS; +} + +#if !defined(BSD4_2) && !defined(USG) +/* call ultouch every TC calls to either grdblk or gwrblk */ +#define TC 20 +static int tc = TC; +#endif + +/*ARGSUSED*/ +grdblk(blk, len, fn) +register int len; +char *blk; +{ + register int i, ret; + +#if !defined(BSD4_2) && !defined(USG) + /* call ultouch occasionally */ + if (--tc < 0) { + tc = TC; + ultouch(); + } +#endif + for (i = 0; i < len; i += ret) { + ret = pkread(Pk, blk, len - i); + if (ret < 0) + return FAIL; + blk += ret; + if (ret == 0) + return i; + } + return i; +} + +/*ARGSUSED*/ +gwrblk(blk, len, fn) +register char *blk; +{ +#if !defined(BSD4_2) && !defined(USG) + /* call ultouch occasionally */ + if (--tc < 0) { + tc = TC; + ultouch(); + } +#endif + return pkwrite(Pk, blk, len); +} diff --git a/src/cmd/uucp/gnamef.c b/src/cmd/uucp/gnamef.c new file mode 100644 index 0000000..ea964d6 --- /dev/null +++ b/src/cmd/uucp/gnamef.c @@ -0,0 +1,41 @@ +#ifndef lint +static char sccsid[] = "@(#)gnamef.c 5.4 (Berkeley) 6/20/85"; +#endif + +#include "uucp.h" +#ifdef NDIR +#include "ndir.h" +#else +#include +#endif + +/*LINTLIBRARY*/ + +/* + * get next file name from directory + * + * return codes: + * 0 - end of directory read + * 1 - returned name + */ + +gnamef(dirp, filename) +register DIR *dirp; +register char *filename; +{ + register struct direct *dentp; + + for (;;) { + if ((dentp = readdir(dirp)) == NULL) { + return 0; + } + if (dentp->d_ino != 0) + break; + } + + /* Truncate filename. This may become a problem someday. */ + strncpy(filename, dentp->d_name, NAMESIZE-1); + filename[NAMESIZE-1] = '\0'; + DEBUG(99,"gnamef returns %s\n",filename); + return 1; +} diff --git a/src/cmd/uucp/gnsys.c b/src/cmd/uucp/gnsys.c new file mode 100644 index 0000000..ca8803f --- /dev/null +++ b/src/cmd/uucp/gnsys.c @@ -0,0 +1,137 @@ +#if !defined(lint) && defined(DOSCCS) +static char sccsid[] = "@(#)gnsys.c 5.4.1 (2.11BSD) 1997/10/31"; +#endif + +#include "uucp.h" +#include +#ifdef NDIR +#include "ndir.h" +#else +#include +#endif + +#define LSIZE 128 /* number of systems to store */ +#define WSUFSIZE 6 /* work file name suffix size */ + +/*LINTLIBRARY*/ + +/* + * this routine will return the next system name which has work to be done. + * "sname" is a string of size DIRSIZ - WSUFSIZE. + * "pre" is the prefix for work files. + * "dir" is the directory to search. + * + * return codes: + * 1 - name returned in sname + * SUCCESS - no more names + * FAIL - bad directory + */ + +gnsys(sname, dir, pre) +char *sname, *dir, pre; +{ + register char *s, *p1, *p2; + char px[3]; + static char *list[LSIZE]; + static int nitem=0, n=0, base=0; + char systname[NAMESIZE], filename[NAMESIZE]; + DIR *dirp; + +retry: + px[0] = pre; + px[1] = '.'; + px[2] = '\0'; + if (nitem == base) { + /* get list of systems with work */ + int i; + dirp = opendir(subdir(dir,pre)); + ASSERT(dirp != NULL, "BAD DIRECTORY", dir, 0); + for (i = base; i < LSIZE; i++) + list[i] = NULL; + while (gnamef(dirp, filename) != 0) { + if (!prefix(px, filename)) + continue; + p2 = filename + strlen(filename) + - WSUFSIZE; + p1 = filename + strlen(px); + for(s = systname; p1 <= p2; p1++) + *s++ = *p1; + *s = '\0'; + if (systname[0] == '\0') + continue; + nitem = srchst(systname, list, nitem); + if (LSIZE <= nitem) break; + } + + closedir(dirp); + } + + if (nitem == base) { + for (n = 0; n < nitem; n++) + if (list[n] != NULL) + free(list[n]); + return SUCCESS; + } + while(nitem > n) { + /* We only have at most a SYSNSIZE character site name encoded + * in the file. However, we would like to use the full sitename + * if possible. If the number of chars in list[n] is < SYSNSIZE + * then the sitename could not have been truncated and + * we don't bother to check. Otherwise, we scan SYSFILE + * looking for the fullname and return it if we find it + */ + strcpy(sname, list[n++]); + if (strlen(sname) >= SYSNSIZE) { + register FILE *fp; + register char *p; + char line[MAXFULLNAME]; + fp = fopen(SYSFILE, "r"); + ASSERT(fp != NULL, CANTOPEN, SYSFILE, 0); + while (cfgets(line, sizeof(line), fp) != NULL) { + p = index(line, ' '); + if (p) + *p = '\0'; + if (strncmp(sname, line, SYSNSIZE) == SAME) { + strncpy(sname, line, MAXBASENAME); + break; + } + } + fclose(fp); + } + if (callok(sname) == 0) + return 1; + } + base = n = nitem; + goto retry; +} + +/* + * this routine will do a linear search of list (list) to find name (name). + * If the name is not found, it is added to the list. + * The number of items in the list (n) is returned (incremented if a + * name is added). + * + * return codes: + * n - the number of items in the list + */ + +srchst(name, list, n) +char *name; +register char **list; +int n; +{ + register int i; + register char *p; + + for (i = 0; i < n; i++) + if (strcmp(name, list[i]) == 0) + break; + if (i >= n) { + if ((p = (char *)calloc(strlen(name) + 1, sizeof (char))) + == NULL) + return n; + strcpy(p, name); + list[n++] = p; + } + return n; +} diff --git a/src/cmd/uucp/gnxseq.c b/src/cmd/uucp/gnxseq.c new file mode 100644 index 0000000..dea4fca --- /dev/null +++ b/src/cmd/uucp/gnxseq.c @@ -0,0 +1,122 @@ +#ifndef lint +static char sccsid[] = "@(#)gnxseq.c 5.4 (Berkeley) 6/20/85"; +#endif + +#include "uucp.h" +#ifdef BSD4_2 +#include +#else sane +#include +#endif sane + +/*LINTLIBRARY*/ + +#ifdef GNXSEQ + +/* + * get next conversation sequence number + * + * return - 0 no entry | >0 sequence number + */ + +gnxseq(rmtname) +char *rmtname; +{ + int count = 0, ct, ret, i; + register struct tm *tp; + extern struct tm *localtime(); + time_t clock; + register FILE *fp0, *fp1; + char buf[BUFSIZ], name[NAMESIZE]; + + if (access(SQFILE, 0) != 0) /* nothing to do here */ + return(0); + + for (i = 0; i < 5; i++) { + if ((ret = ulockf(SQLOCK, (time_t) SQTIME)) == 0) + break; + sleep(5); + } + if (ret != 0) { + logent("CAN'T LOCK", SQLOCK); + DEBUG(4, "can't lock %s\n", SQLOCK); + return(0); + } + if ((fp0 = fopen(SQFILE, "r")) == NULL) + return(0); + if ((fp1 = fopen(SQTMP, "w")) == NULL) { + fclose(fp0); + return(0); + } + chmod(SQTMP, 0400); + + while (fgets(buf, BUFSIZ, fp0) != NULL) { + ret = sscanf(buf, "%s%d", name, &ct); + if (ret < 2) + ct = 0; + name[MAXBASENAME] = '\0'; + if (ct > 9998) + ct = 0; + if (strncmp(rmtname, name, MAXBASENAME) != SAME) { + fputs(buf, fp1); + continue; + } + + /* found name */ + count = ++ct; + time(&clock); + tp = localtime(&clock); +#ifdef USG + fprintf(fp1, "%s %d %d/%d-%2.2d:%2.2d\n", name, ct, + tp->tm_mon + 1, tp->tm_mday, tp->tm_hour, + tp->tm_min); +#endif +#ifndef USG + fprintf(fp1, "%s %d %d/%d-%02d:%02d\n", name, ct, + tp->tm_mon + 1, tp->tm_mday, tp->tm_hour, + tp->tm_min); +#endif + while (fgets(buf, BUFSIZ, fp0) != NULL) + fputs(buf, fp1); + } + fclose(fp0); + fclose(fp1); + if (count == 0) { + rmlock(SQLOCK); + unlink(SQTMP); + } + return(count); +} + + +/*** + * cmtseq() commit sequence update + * + * return 0 ok | other - link failed + */ + +cmtseq() +{ + register int ret; + + if ((ret = access(SQTMP, 04)) != 0) { + rmlock(SQLOCK); + return(0); + } + unlink(SQFILE); + ret = link(SQTMP, SQFILE); + unlink(SQTMP); + rmlock(SQLOCK); + return(ret); +} + +/*** + * ulkseq() unlock sequence file + */ + +ulkseq() +{ + unlink(SQTMP); + rmlock(SQLOCK); +} +#endif GNXSEQ diff --git a/src/cmd/uucp/imsg.c b/src/cmd/uucp/imsg.c new file mode 100644 index 0000000..8f51fe1 --- /dev/null +++ b/src/cmd/uucp/imsg.c @@ -0,0 +1,101 @@ +#ifndef lint +static char sccsid[] = "@(#)imsg.c 5.3 (Berkeley) 1/6/86"; +#endif + +#include "uucp.h" +#include + +char Msync[2] = "\020"; + +/* to talk to both eunice and x.25 without also screwing up tcp/ip + * we must adaptively choose what character to end the msg with + * + * The idea is that initially we send ....\000\n + * Then, after they have sent us a message, we use the first character + * they send. + */ + +int seenend = 0; +char Mend = '\0'; + +/* + * this is the initial read message routine - + * used before a protocol is agreed upon. + * + * return codes: + * FAIL - no more messages + * SUCCESS - message returned + */ + +imsg(amsg, fn) +char *amsg; +register int fn; +{ + register char *msg = amsg; + int foundsync = FAIL; + char c; + + DEBUG(5, "imsg looking for SYNC<", CNULL); + for (;;) { + if (read(fn, &c, 1) != 1) + return FAIL; + c &= 0177; + if (c == '\n' || c == '\r') + DEBUG(5, "%c", c); + else + DEBUG(5, (isprint(c) || isspace(c)) ? "%c" : "\\%o", + c & 0377); + if (c == Msync[0]) { + DEBUG(5, ">\nimsg input<", CNULL); + msg = amsg; + foundsync = SUCCESS; + continue; + } else if (foundsync != SUCCESS) + continue; + if (c == '\n' || c == '\0') { + if (!seenend) { + Mend = c; + seenend++; + DEBUG(9, "\nUsing \\%o as End of message char\n", Mend); + } + break; + } + *msg++ = c; + fflush(stderr); + } + *msg = '\0'; + DEBUG(5, ">got %d characters\n", strlen(amsg)); + return foundsync; +} + + +/* + * this is the initial write message routine - + * used before a protocol is agreed upon. + * + * return code: always 0 + */ + +omsg(type, msg, fn) +register char *msg; +char type; +int fn; +{ + char buf[MAXFULLNAME]; + register char *c; + + c = buf; + *c = '\0'; /* avoid pdp 11/23,40 auto-incr stack trap bug */ + *c++ = Msync[0]; + *c++ = type; + while (*msg) + *c++ = *msg++; + *c++ = '\0'; + DEBUG(5, "omsg <%s>\n", buf); + if (seenend) + c[-1] = Mend; + else + *c++ = '\n'; + write(fn, buf, (int)(c - buf)); + return 0; +} diff --git a/src/cmd/uucp/lastpart.c b/src/cmd/uucp/lastpart.c new file mode 100644 index 0000000..4b64022 --- /dev/null +++ b/src/cmd/uucp/lastpart.c @@ -0,0 +1,27 @@ +#ifndef lint +static char sccsid[] = "@(#)lastpart.c 5.4 (Berkeley) 6/20/85"; +#endif + +#include +#include "uucp.h" + +/*LINTLIBRARY*/ + +/* + * find last part of file name + * + * return - pointer to last part + */ + +char * +lastpart(file) +register char *file; +{ + register char *c; + + c = rindex(file, '/'); + if (c++) + return c; + else + return file; +} diff --git a/src/cmd/uucp/logent.c b/src/cmd/uucp/logent.c new file mode 100644 index 0000000..9aa85db --- /dev/null +++ b/src/cmd/uucp/logent.c @@ -0,0 +1,235 @@ +#ifndef lint +static char sccsid[] = "@(#)logent.c 5.6 (Berkeley) 10/9/85"; +#endif + +#include "uucp.h" +#ifdef BSD4_2 +#include +#else +#include +#endif +#if defined(USG) || defined(BSD4_2) +#include +#endif + +static FILE *Lp = NULL; +static FILE *Sp = NULL; +static Ltried = 0; +static Stried = 0; + +/*LINTLIBRARY*/ + +/* + * make log entry + */ +logent(text, status) +char *text, *status; +{ +#ifdef LOGBYSITE + char lfile[MAXFULLNAME]; + static char LogRmtname[64]; +#endif + if (Rmtname[0] == '\0') + strcpy(Rmtname, Myname); + /* Open the log file if necessary */ +#ifdef LOGBYSITE + if (strcmp(Rmtname, LogRmtname)) { + if (Lp != NULL) + fclose(Lp); + Lp = NULL; + Ltried = 0; + } +#endif + if (Lp == NULL) { + if (!Ltried) { + int savemask; +#ifdef F_SETFL + int flags; +#endif + savemask = umask(LOGMASK); +#ifdef LOGBYSITE + (void) sprintf(lfile, "%s/%s/%s", LOGBYSITE, Progname, Rmtname); + strcpy(LogRmtname, Rmtname); + Lp = fopen (lfile, "a"); +#else + Lp = fopen (LOGFILE, "a"); +#endif + umask(savemask); +#ifdef F_SETFL + flags = fcntl(fileno(Lp), F_GETFL, 0); + fcntl(fileno(Lp), F_SETFL, flags|O_APPEND); +#endif + } + Ltried = 1; + if (Lp == NULL) + return; + fioclex(fileno(Lp)); + } + + /* make entry in existing temp log file */ + mlogent(Lp, status, text); +} + +/* + * make a log entry + */ + +mlogent(fp, status, text) +char *text, *status; +register FILE *fp; +{ + static pid = 0; + register struct tm *tp; + extern struct tm *localtime(); + + if (text == NULL) + text = ""; + if (status == NULL) + status = ""; + if (!pid) + pid = getpid(); +#ifdef USG + time(&Now.time); + Now.millitm = 0; +#else + ftime(&Now); +#endif + tp = localtime(&Now.time); +#ifdef USG + fprintf(fp, "%s %s (%d/%d-%2.2d:%2.2d-%d) ", +#else + fprintf(fp, "%s %s (%d/%d-%02d:%02d-%d) ", +#endif + User, Rmtname, tp->tm_mon + 1, tp->tm_mday, + tp->tm_hour, tp->tm_min, pid); + fprintf(fp, "%s (%s)\n", status, text); + + /* Since it's buffered */ +#ifndef F_SETFL + lseek (fileno(fp), (long)0, 2); +#endif + fflush (fp); + if (Debug) { + fprintf(stderr, "%s %s ", User, Rmtname); +#ifdef USG + fprintf(stderr, "(%d/%d-%2.2d:%2.2d-%d) ", tp->tm_mon + 1, + tp->tm_mday, tp->tm_hour, tp->tm_min, pid); +#else + fprintf(stderr, "(%d/%d-%02d:%02d-%d) ", tp->tm_mon + 1, + tp->tm_mday, tp->tm_hour, tp->tm_min, pid); +#endif + fprintf(stderr, "%s (%s)\n", status, text); + } +} + +/* + * close log file + */ +logcls() +{ + if (Lp != NULL) + fclose(Lp); + Lp = NULL; + Ltried = 0; + + if (Sp != NULL) + fclose (Sp); + Sp = NULL; + Stried = 0; +} + + +/* + * make system log entry + */ +syslog(text) +char *text; +{ + register struct tm *tp; + extern struct tm *localtime(); +#ifdef LOGBYSITE + char lfile[MAXFULLNAME]; + static char SLogRmtname[64]; + + if (strcmp(Rmtname, SLogRmtname)) { + if (Sp != NULL) + fclose(Sp); + Sp = NULL; + Stried = 0; + } +#endif + if (Sp == NULL) { + if (!Stried) { + int savemask; +#ifdef F_SETFL + int flags; +#endif + savemask = umask(LOGMASK); +#ifdef LOGBYSITE + (void) sprintf(lfile, "%s/xferstats/%s", LOGBYSITE, Rmtname); + strcpy(SLogRmtname, Rmtname); + Sp = fopen (lfile, "a"); +#else + Sp = fopen (SYSLOG, "a"); +#endif + umask(savemask); +#ifdef F_SETFL + flags = fcntl(fileno(Sp), F_GETFL, 0); + fcntl(fileno(Sp), F_SETFL, flags|O_APPEND); +#endif + + } + Stried = 1; + if (Sp == NULL) + return; + fioclex(fileno(Sp)); + } + +#ifdef USG + time(&Now.time); + Now.millitm = 0; +#else + ftime(&Now); +#endif + tp = localtime(&Now.time); + + fprintf(Sp, "%s %s ", User, Rmtname); +#ifdef USG + fprintf(Sp, "(%d/%d-%2.2d:%2.2d) ", tp->tm_mon + 1, + tp->tm_mday, tp->tm_hour, tp->tm_min); + fprintf(Sp, "(%ld) %s\n", Now.time, text); +#else + fprintf(Sp, "(%d/%d-%02d:%02d) ", tp->tm_mon + 1, + tp->tm_mday, tp->tm_hour, tp->tm_min); + fprintf(Sp, "(%ld.%02u) %s\n", Now.time, Now.millitm/10, text); +#endif + + /* Position at end and flush */ +#ifndef F_SETFL + lseek (fileno(Sp), (long)0, 2); +#endif + fflush (Sp); +} + +/* + * Arrange to close fd on exec(II). + * Otherwise unwanted file descriptors are inherited + * by other programs. And that may be a security hole. + */ +#ifndef USG +#include +#endif + +fioclex(fd) +int fd; +{ + register int ret; + +#if defined(USG) || defined(BSD4_2) + ret = fcntl(fd, F_SETFD, 1); /* Steve Bellovin says this does it */ +#else + ret = ioctl(fd, FIOCLEX, STBNULL); +#endif + if (ret) + DEBUG(2, "CAN'T FIOCLEX %d\n", fd); +} diff --git a/src/cmd/uucp/mailst.c b/src/cmd/uucp/mailst.c new file mode 100644 index 0000000..f129351 --- /dev/null +++ b/src/cmd/uucp/mailst.c @@ -0,0 +1,105 @@ +#if !defined(lint) && defined(DOSCCS) +static char sccsid[] = "@(#)mailst.c 5.6.1 (2.11BSD GTE) 6/11/94"; +#endif + +#include +#include "uucp.h" +#ifdef USG +#include +#endif + +/*LINTLIBRARY*/ + +/* + * mailst - this routine will fork and execute + * a mail command sending string (str) to user (user). + * If file is non-null, the file is also sent. + * (this is used for mail returned to sender.) + */ + +mailst(user, str, file) +char *user, *str, *file; +{ + register FILE *fp, *fi; + char buf[BUFSIZ]; + register int c; + + sprintf(buf, "%s '%s'", _PATH_SENDMAIL, user); + if ((fp = rpopen(buf, "w")) != NULL) { + fprintf(fp, "From: uucp\nTo: %s\nSubject: %s\n\n", user, str); + if (file && *file != '\0' && (fi = fopen(subfile(file), "r")) != NULL) { + while ((c = getc(fi)) != EOF) + putc(c, fp); + putc('\n', fp); + fclose(fi); + } + rpclose(fp); + } +} + +/* + * 'reverting' version of popen + * which runs process with permissions of real gid/uid + * rather than the effective gid/uid. + */ +#define tst(a,b) (*mode == 'r'? (b) : (a)) +#define RDR 0 +#define WTR 1 +static int popen_pid[20]; + +FILE * +rpopen(cmd, mode) +char *cmd; +char *mode; +{ + int p[2]; + register myside, hisside, pid; + + if(pipe(p) < 0) + return NULL; + myside = tst(p[WTR], p[RDR]); + hisside = tst(p[RDR], p[WTR]); + if((pid = fork()) == 0) { + /* myside and hisside reverse roles in child */ + close(myside); +#ifdef USG + close(tst(0, 1)); + fcntl(hisside, F_DUPFD, tst(0, 1)); +#else + dup2(hisside, tst(0, 1)); +#endif + close(hisside); + /* revert permissions */ + setgid(getgid()); + setuid(getuid()); + execl("/bin/sh", "sh", "-c", cmd, (char *)0); + _exit(1); + } + if(pid == -1) + return NULL; + popen_pid[myside] = pid; + close(hisside); + return(fdopen(myside, mode)); +} + +rpclose(ptr) +FILE *ptr; +{ + register f, r; + register sig_t hstat, istat, qstat; + int status; + + f = fileno(ptr); + fclose(ptr); + istat = signal(SIGINT, SIG_IGN); + qstat = signal(SIGQUIT, SIG_IGN); + hstat = signal(SIGHUP, SIG_IGN); + while((r = wait(&status)) != popen_pid[f] && r != -1) + ; + if(r == -1) + status = -1; + signal(SIGINT, (sig_t)istat); + signal(SIGQUIT, (sig_t)qstat); + signal(SIGHUP, (sig_t)hstat); + return status; +} diff --git a/src/cmd/uucp/pk.h b/src/cmd/uucp/pk.h new file mode 100644 index 0000000..d138c01 --- /dev/null +++ b/src/cmd/uucp/pk.h @@ -0,0 +1,128 @@ +/* pk.h 5.4 86/01/06 */ + +struct header { + char sync; + char ksize; + unsigned short sum; + char cntl; + char ccntl; +}; + +#define HDRSIZ 6 /* Packet header size */ +#define PACKSIZE 64 /* Standard packet size */ +#define WINDOWS 7 + +#define TAILSIZE 2 /* Number of trailing nulls after packet */ + +struct pack { + short p_state; /* line state */ + short p_bits; /* mask for getepack */ + short p_rsize; /* input packet size */ + short p_xsize; /* output packet size */ + struct header p_ihbuf; /* input header */ + struct header p_ohbuf; /* output header */ + char *p_rptr; + char p_mode; + char **p_ipool; + char p_xcount; /* # active output buffers */ + char p_rcount; + char p_nout,p_tout; + char p_lpsize; /* log(psize/32) */ + char p_timer; + char p_obusy; + char p_srxmit; + char p_rwindow; /* window size */ + char p_swindow; + char p_msg; /* control msg */ + char p_rmsg; /* repeated control msg */ + char p_ps,p_pr; /* last packet sent, recv'd */ + char p_rpr; + char p_nxtps; /* next output seq number */ + char p_imap; /* bit map of input buffers */ + char p_pscopy; /* newest output packet */ + char *p_ob[8]; /* output buffers */ + char *p_ib[8]; /* input buffers */ + char p_os[8]; /* output buffer status */ + char p_is[8]; /* input buffer status */ + short p_osum[8]; /* output checksums */ + short p_isum[8]; /* input checksums */ + int p_ifn, p_ofn; +}; + +#define CHECK 0125252 +#define SYN 020 +#define MOD8 7 +#define ISCNTL(a) ((a & 0300)==0) +/* MIN may have been defined in */ +#undef MIN +#define MIN(a,b) ((a>3) & MOD8; + + if (!ISCNTL(c)) { + logent("PK0", "not cntl"); + return; + } + + switch(cntl) { + case INITB: + val++; + pk->p_xsize = pksizes[val]; + pk->p_lpsize = val; + pk->p_bits = 1; + if (pk->p_state & LIVE) { + pk->p_msg |= M_INITC; + break; + } + pk->p_state |= INITb; + if ((pk->p_state & INITa)==0) { + break; + } + pk->p_rmsg &= ~M_INITA; + pk->p_msg |= M_INITC; + break; + + case INITC: + if ((pk->p_state&INITab)==INITab) { + pk->p_state = LIVE; + pk->p_rmsg &= ~M_INITB; + } else + pk->p_msg |= M_INITB; + if (val) + pk->p_swindow = val; + break; + case INITA: + if (val == 0 && pk->p_state&LIVE) { + logent("PK0", "alloc change not implemented"); + break; + } + if (val) { + pk->p_state |= INITa; + pk->p_msg |= M_INITB; + pk->p_rmsg |= M_INITB; + pk->p_swindow = val; + } + break; + case RJ: + pk->p_state |= RXMIT; + pk->p_msg |= M_RR; + pk->p_rpr = val; + (void) pksack(pk); + break; + case RR: + pk->p_rpr = val; + if (pk->p_rpr == pk->p_ps) { + DEBUG(9, "Reack count is %d\n", ++Reacks); + if (Reacks >= 4) { + DEBUG(6, "Reack overflow on %d\n", val); + pk->p_state |= RXMIT; + pk->p_msg |= M_RR; + Reacks = 0; + } + } else { + Reacks = 0; + (void) pksack(pk); + } + break; + case SRJ: + logent("PK0", "srj not implemented"); + break; + case CLOSE: + pk->p_state = DOWN+RCLOSE; + return; + } + if (pk->p_msg) + pkoutput(pk); +} + +pkaccept(pk) +register struct pack *pk; +{ + register x, seq; + char m, cntl, *p, imask, **bp; + int bad, accept, skip, t, cc; + unsigned short sum; + + bad = accept = skip = 0; + /* + * wait for input + */ + x = next[pk->p_pr]; + while ((imask=pk->p_imap) == 0 && pk->p_rcount == 0) { + pkgetpack(pk); + } + pk->p_imap = 0; + + /* + * determine input window in m. + */ + t = (~(-1<<(int)(pk->p_rwindow))) <>8; + + /* + * mark newly accepted input buffers + */ + for(x=0; x<8; x++) { + if ((imask & mask[x]) == 0) + continue; + + if (((cntl=pk->p_is[x])&0200) == 0) { + bad++; +free: + bp = (char **)pk->p_ib[x]; + *bp = (char *)pk->p_ipool; + pk->p_ipool = bp; + pk->p_is[x] = 0; + continue; + } + + pk->p_is[x] = ~(B_COPY+B_MARK); + sum = (unsigned)chksum(pk->p_ib[x], pk->p_rsize) ^ (unsigned)(cntl&0377); + sum += pk->p_isum[x]; + if (sum == CHECK) { + seq = (cntl>>3) & MOD8; + if (m & mask[seq]) { + if (pk->p_is[seq] & (B_COPY | B_MARK)) { + dup: + pk->p_msg |= M_RR; + skip++; + goto free; + } + if (x != seq) { + p = pk->p_ib[x]; + pk->p_ib[x] = pk->p_ib[seq]; + pk->p_is[x] = pk->p_is[seq]; + pk->p_ib[seq] = p; + } + pk->p_is[seq] = B_MARK; + accept++; + cc = 0; + if (cntl&B_SHORT) { + pk->p_is[seq] = B_MARK+B_SHORT; + p = pk->p_ib[seq]; + cc = (unsigned)*p++ & 0377; + if (cc & 0200) { + cc &= 0177; + cc |= *p << 7; + } + } + pk->p_isum[seq] = pk->p_rsize - cc; + } else { + goto dup; + } + } else { + bad++; + goto free; + } + } + + /* + * scan window again turning marked buffers into + * COPY buffers and looking for missing sequence + * numbers. + */ + accept = 0; + t = -1; + for(x=next[pk->p_pr]; m & mask[x]; x = next[x]) { + if (pk->p_is[x] & B_MARK) + pk->p_is[x] |= B_COPY; + + if (pk->p_is[x] & B_COPY) { + if (t >= 0) { + bp = (char **)pk->p_ib[x]; + *bp = (char *)pk->p_ipool; + pk->p_ipool = bp; + pk->p_is[x] = 0; + skip++; + } else + accept++; + } else { + if (t<0) + t = x; + } + } + + if (bad) { + pk->p_msg |= M_RJ; + } + + if (skip) { + pk->p_msg |= M_RR; + } + + pk->p_rcount = accept; + return accept; +} + +/*ARGSUSED*/ +pkread(pk, ibuf, icount) +register struct pack *pk; +char *ibuf; +int icount; +{ + register x; + int is, cc, xfr, count; + char *cp, **bp; + + xfr = 0; + count = 0; + pktimeout = PKRTIME; + pktimeskew = PKRSKEW; + Ntimeout = 0; + while (pkaccept(pk) == 0) + ; + + while (icount) { + x = next[pk->p_pr]; + is = pk->p_is[x]; + + if (is & B_COPY) { + cc = MIN(pk->p_isum[x], icount); + if (cc==0 && xfr) { + break; + } + if (is & B_RESID) + cp = pk->p_rptr; + else { + cp = pk->p_ib[x]; + if (is & B_SHORT) { + if (*cp++ & 0200) + cp++; + } + } + pkmove(cp, ibuf, cc, B_READ); + ibuf += cc; + icount -= cc; + count += cc; + xfr++; + pk->p_isum[x] -= cc; + if (pk->p_isum[x] == 0) { + pk->p_pr = x; + bp = (char **)pk->p_ib[x]; + *bp = (char *)pk->p_ipool; + pk->p_ipool = bp; + pk->p_is[x] = 0; + pk->p_rcount--; + pk->p_msg |= M_RR; + } else { + pk->p_rptr = cp+cc; + pk->p_is[x] |= B_RESID; + } + if (cc==0) + break; + } else + break; + } + pkoutput(pk); + return count; +} + +/*ARGSUSED*/ +pkwrite(pk, ibuf, icount) +register struct pack *pk; +char *ibuf; +int icount; +{ + register x; + int partial; + caddr_t cp; + int cc, fc, count; + + if (pk->p_state&DOWN || !pk->p_state&LIVE) { + return -1; + } + + pktimeout = PKWTIME; + pktimeskew = PKWSKEW; + Ntimeout = 0; + count = icount; + do { + while (pk->p_xcount>=pk->p_swindow) { + pkoutput(pk); + pkgetpack(pk); + } + x = next[pk->p_pscopy]; + while (pk->p_os[x]!=B_NULL) { + pkgetpack(pk); + } + pk->p_os[x] = B_MARK; + pk->p_pscopy = x; + pk->p_xcount++; + + cp = pk->p_ob[x] = (char *)malloc((unsigned)pk->p_xsize); + partial = 0; + if ((int)icount < pk->p_xsize) { + cc = icount; + fc = pk->p_xsize - cc; + *cp = fc&0177; + if (fc > 127) { + *cp++ |= 0200; + *cp++ = fc>>7; + } else + cp++; + partial = B_SHORT; + } else + cc = pk->p_xsize; + pkmove(cp, ibuf, cc, B_WRITE); + ibuf += cc; + icount -= cc; + pk->p_osum[x] = chksum(pk->p_ob[x], pk->p_xsize); + pk->p_os[x] = B_READY+partial; + pkoutput(pk); + } while (icount); + + return count; +} + +pksack(pk) +register struct pack *pk; +{ + register x, i; + + i = 0; + for(x=pk->p_ps; x!=pk->p_rpr; ) { + x = next[x]; + if (pk->p_os[x]&B_SENT) { + i++; + pk->p_os[x] = B_NULL; + pk->p_state &= ~WAITO; + pk->p_xcount--; + free((char *)pk->p_ob[x]); + pk->p_ps = x; + } + } + return i; +} + +pkoutput(pk) +register struct pack *pk; +{ + register x; + int i; + char bstate; + + if (pk->p_obusy++) { + pk->p_obusy--; + return; + } + + /* + * find seq number and buffer state + * of next output packet + */ + if (pk->p_state&RXMIT) { + pk->p_nxtps = next[pk->p_rpr]; + } + x = pk->p_nxtps; + bstate = pk->p_os[x]; + + /* + * Send control packet if indicated + */ + if (pk->p_msg) { + if (pk->p_msg & ~M_RR || !(bstate&B_READY) ) { + x = pk->p_msg; + for(i=0; i<8; i++) + if (x&1) + break; + else + x >>= 1; + x = i; + x <<= 3; + switch(i) { + case CLOSE: + break; + case RJ: + case RR: + x += pk->p_pr; + break; + case SRJ: + break; + case INITB: + x += pksize(pk->p_rsize); + break; + case INITC: + x += pk->p_rwindow; + break; + case INITA: + x += pk->p_rwindow; + break; + } + + pk->p_msg &= ~mask[i]; + pkxstart(pk, x, -1); + goto out; + } + } + + + /* + * Don't send data packets if line is marked dead. + */ + if (pk->p_state&DOWN) { + goto out; + } + /* + * Start transmission (or retransmission) of data packets. + */ + if (bstate & (B_READY|B_SENT)) { + char seq; + + bstate |= B_SENT; + seq = x; + pk->p_nxtps = next[x]; + + x = 0200+pk->p_pr+(seq<<3); + if (bstate & B_SHORT) + x |= 0100; + pkxstart(pk, x, seq); + pk->p_os[seq] = bstate; + pk->p_state &= ~RXMIT; + pk->p_nout++; + goto out; + } + /* + * enable timeout if there's nothing to send + * and transmission buffers are languishing + */ + if (pk->p_xcount) { + pk->p_timer = 2; + pk->p_state |= WAITO; + } else + pk->p_state &= ~WAITO; +out: + pk->p_obusy = 0; +} + +/* + * shut down line by + * ignoring new input + * letting output drain + * releasing space and turning off line discipline + */ +/*ARGSUSED*/ +pkclose(pk) +register struct pack *pk; +{ + register i; + char **bp; + int rcheck = 0; + + pk->p_state |= DRAINO; + + /* + * try to flush output + */ + i = 0; + pk->p_timer = 2; + while (pk->p_xcount && pk->p_state&LIVE) { + if (pk->p_state&(RCLOSE+DOWN) || ++i > 2) + break; + pkoutput(pk); + } + pk->p_timer = 0; + pk->p_state |= DOWN; + + /* + * try to exchange CLOSE messages + */ + i = 0; + while ((pk->p_state&RCLOSE)==0 && i<2) { + pk->p_msg = M_CLOSE; + pk->p_timer = 2; + pkoutput(pk); + i++; + } + + for(i=0;ip_os[i] != B_NULL) { + free((char *)pk->p_ob[i]); + pk->p_xcount--; + } + if (pk->p_is[i] != B_NULL) { + free((char *)pk->p_ib[i]); + rcheck++; + } + } + while (pk->p_ipool != NULL) { + bp = pk->p_ipool; + pk->p_ipool = (char **)*bp; + rcheck++; + free((char *)bp); + } + if (rcheck != pk->p_rwindow) { + char buf[256]; + + sprintf(buf, "PK0: rc %d rw %d", rcheck, pk->p_rwindow); + logent(buf, "pkclose rcheck != p_rwindow"); + } + free((char *)pk); +} + +pkreset(pk) +register struct pack *pk; +{ + + pk->p_ps = pk->p_pr = pk->p_rpr = 0; + pk->p_nxtps = 1; +} + +#ifndef BSD4_2 +bzero(s,n) +register char *s; +register n; +{ + while (n--) + *s++ = 0; +} +#endif + +pksize(n) +register n; +{ + register k; + + n >>= 5; + for(k=0; n >>= 1; k++) + ; + return k; +} diff --git a/src/cmd/uucp/pk1.c b/src/cmd/uucp/pk1.c new file mode 100644 index 0000000..7a01236 --- /dev/null +++ b/src/cmd/uucp/pk1.c @@ -0,0 +1,431 @@ +#if !defined(lint) && defined(DOSCCS) +static char sccsid[] = "@(#)pk1.c 5.9.2 (2.11BSD) 1997/10/2"; +#endif + +#include +#include +#include "uucp.h" +#include "pk.h" +#include +#include +#include +#ifdef BSD4_2 +#include +#endif + +#ifdef VMS +#include +#include +#include +int iomask[2]; +#endif + +#define PKMAXSTMSG 40 +#define MAXPKTIME 32 /* was 16 */ +#define CONNODATA 10 +#define MAXTIMEOUT 32 + +extern int Retries; +extern jmp_buf Sjbuf; + +int Connodata = 0; +int Ntimeout = 0; +int pktimeout = 4; +int pktimeskew = 2; +/* + * packet driver support routines + * + */ + +extern struct pack *pklines[]; + +/* + * start initial synchronization. + */ + +struct pack * +pkopen(ifn, ofn) +int ifn, ofn; +{ + register struct pack *pk; + register char **bp; + register int i; + + if ((pk = (struct pack *) malloc(sizeof (struct pack))) == NULL) + return NULL; + bzero((caddr_t) pk, sizeof (struct pack)); + pk->p_ifn = ifn; + pk->p_ofn = ofn; + pk->p_xsize = pk->p_rsize = PACKSIZE; + pk->p_rwindow = pk->p_swindow = WINDOWS; + /* allocate input windows */ + for (i = 0; i < pk->p_rwindow; i++) { + if ((bp = (char **) malloc((unsigned)pk->p_xsize)) == NULL) + break; + *bp = (char *) pk->p_ipool; + pk->p_ipool = bp; + } + if (i == 0) { + DEBUG(1, "pkopen: can't malloc i = 0\n", CNULL); + return NULL; + } + pk->p_rwindow = i; + + /* start synchronization */ + pk->p_msg = pk->p_rmsg = M_INITA; + for (i = 0; i < NPLINES; i++) { + if (pklines[i] == NULL) { + pklines[i] = pk; + break; + } + } + if (i >= NPLINES) { + DEBUG(1,"pkopen: i>=NPLINES\n", CNULL); + return NULL; + } + pkoutput(pk); + + for (i = 0; i < PKMAXSTMSG; i++) { + pkgetpack(pk); + if ((pk->p_state & LIVE) != 0) + break; + } + if (i >= PKMAXSTMSG) { + DEBUG(1, "pkopen: i>= PKMAXSTMSG\n", CNULL); + return NULL; + } + + pkreset(pk); + return pk; +} + + +/* + * input framing and block checking. + * frame layout for most devices is: + * + * S|K|X|Y|C|Z| ... data ... | + * + * where S == initial synch byte + * K == encoded frame size (indexes pksizes[]) + * X, Y == block check bytes + * C == control byte + * Z == XOR of header (K^X^Y^C) + * data == 0 or more data bytes + * + */ + +int pksizes[] = { + 1, 32, 64, 128, 256, 512, 1024, 2048, 4096, 1 +}; + +#define GETRIES 10 +/* + * Pseudo-dma byte collection. + */ + +pkgetpack(pk) +register struct pack *pk; +{ + int k, tries, noise; + register char *p; + register struct header *h; + unsigned short sum; + int ifn; + char **bp; + char hdchk; + + if ((pk->p_state & DOWN) || Connodata > CONNODATA || Ntimeout > MAXTIMEOUT) + pkfail(); + ifn = pk->p_ifn; + + /* find HEADER */ + for (tries = 0, noise = 0; tries < GETRIES; ) { + p = (caddr_t) &pk->p_ihbuf; + if (pkcget(ifn, p, 1) == SUCCESS) { + if (*p++ == SYN) { + if (pkcget(ifn, p, HDRSIZ-1) == SUCCESS) + break; + } else { + if (noise++ < 10 || noise < (3*pk->p_rsize)) + continue; + } + DEBUG(4, "Noisy line - set up RXMIT\n", CNULL); + noise = 0; + } + /* set up retransmit or REJ */ + tries++; + Retries++; + pk->p_msg |= pk->p_rmsg; + if (pk->p_msg == 0) + pk->p_msg |= M_RR; + if ((pk->p_state & LIVE) == LIVE) + pk->p_state |= RXMIT; + pkoutput(pk); + } + if (tries >= GETRIES) { + DEBUG(4, "tries = %d\n", tries); + pkfail(); + } + + Connodata++; + h = (struct header *) &pk->p_ihbuf; + p = (caddr_t) h; + hdchk = p[1] ^ p[2] ^ p[3] ^ p[4]; + p += 2; + sum = (unsigned) *p++ & 0377; + sum |= (unsigned) *p << 8; + h->sum = sum; + DEBUG(7, "rec h->cntl 0%o\n", h->cntl&0xff); + k = h->ksize; + if (hdchk != h->ccntl) { + /* bad header */ + DEBUG(7, "bad header 0%o,", hdchk&0xff); + DEBUG(7, "h->ccntl 0%o\n", h->ccntl&0xff); + return; + } + if (k == 9) { + if (((h->sum + h->cntl) & 0xffff) == CHECK) { + pkcntl(h->cntl, pk); + DEBUG(7, "state - 0%o\n", pk->p_state); + } else { + /* bad header */ + pk->p_state |= BADFRAME; + DEBUG(7, "bad header (k==9) 0%o\n", h->cntl&0xff); + } + return; + } + if (k && pksizes[k] == pk->p_rsize) { + pk->p_rpr = h->cntl & MOD8; + DEBUG(7, "end pksack 0%o\n", pk->p_rpr); + pksack(pk); + bp = pk->p_ipool; + if (bp == NULL) { + DEBUG(7, "bp NULL %s\n", ""); + return; + } + pk->p_ipool = (char **) *bp; + Connodata = 0; + } else + return; + + if (pkcget(pk->p_ifn, (char *) bp, pk->p_rsize) == SUCCESS) { + pkdata(h->cntl, h->sum, pk, (char **) bp); + } else { + *bp = (char *)pk->p_ipool; + pk->p_ipool = bp; + } +} + +pkdata(c, sum, pk, bp) +char c; +unsigned short sum; +register struct pack *pk; +char **bp; +{ + register x; + int t; + char m; + + if (pk->p_state & DRAINO || !(pk->p_state & LIVE)) { + pk->p_msg |= pk->p_rmsg; + pkoutput(pk); + goto drop; + } + t = next[pk->p_pr]; + for(x=pk->p_pr; x!=t; x = (x-1)&7) { + if (pk->p_is[x] == 0) + goto slot; + } +drop: + *bp = (char *)pk->p_ipool; + pk->p_ipool = bp; + return; + +slot: + m = mask[x]; + pk->p_imap |= m; + pk->p_is[x] = c; + pk->p_isum[x] = sum; + pk->p_ib[x] = (char *)bp; +} + +/* + * setup input transfers + */ +#define PKMAXBUF 128 +/* + * Start transmission on output device associated with pk. + * For asynch devices (t_line==1) framing is + * imposed. For devices with framing and crc + * in the driver (t_line==2) the transfer is + * passed on to the driver. + */ +pkxstart(pk, cntl, x) +register struct pack *pk; +char cntl; +register x; +{ + register char *p; + short checkword; + char hdchk; + + p = (caddr_t) &pk->p_ohbuf; + *p++ = SYN; + if (x < 0) { + *p++ = hdchk = 9; + checkword = cntl; + } else { + *p++ = hdchk = pk->p_lpsize; + checkword = pk->p_osum[x] ^ (unsigned)(cntl & 0377); + } + checkword = CHECK - checkword; + *p = checkword; + hdchk ^= *p++; + *p = checkword>>8; + hdchk ^= *p++; + *p = cntl; + hdchk ^= *p++; + *p = hdchk; + /* writes */ + DEBUG(7, "send 0%o\n", cntl&0xff); + p = (caddr_t) & pk->p_ohbuf; + if (x < 0) { + if(write(pk->p_ofn, p, HDRSIZ) != HDRSIZ) { + alarm(0); + logent("PKXSTART write failed", strerror(errno)); + longjmp(Sjbuf, 4); + } + } else { + char buf[PKMAXBUF + HDRSIZ + TAILSIZE], *b; + int i; + for (i = 0, b = buf; i < HDRSIZ; i++) + *b++ = *p++; + for (i = 0, p = pk->p_ob[x]; i < pk->p_xsize; i++) + *b++ = *p++; +#if TAILSIZE != 0 + for (i = 0; i < TAILSIZE; i++) + *b++ = '\0'; +#endif + if (write(pk->p_ofn, buf, pk->p_xsize + HDRSIZ + TAILSIZE) + != (HDRSIZ + TAILSIZE + pk->p_xsize)) { + alarm(0); + logent("PKXSTART write failed", strerror(errno)); + longjmp(Sjbuf, 5); + } + Connodata = 0; + } + if (pk->p_msg) + pkoutput(pk); +} + + +pkmove(p1, p2, count, flag) +char *p1, *p2; +int count, flag; +{ + register char *s, *d; + register int i; + + if (flag == B_WRITE) { + s = p2; + d = p1; + } else { + s = p1; + d = p2; + } + for (i = 0; i < count; i++) + *d++ = *s++; +} + + +/* + * get n characters from input + * + * return codes: + * n - number of characters returned + * 0 - end of file + */ + +jmp_buf Getjbuf; +cgalarm() +{ + longjmp(Getjbuf, 1); +} + +pkcget(fn, b, n) +int fn; +register char *b; +register int n; +{ + register int ret; + extern int linebaudrate; +#ifdef BSD4_2 + long r, itime = 100000L; /* guess it's been 1/10th second since we + last read the line */ + struct timeval tv; +#endif +#ifdef VMS + short iosb[4]; + int SYS$QioW(); /* use this for long reads on vms */ +#endif + + if (setjmp(Getjbuf)) { + Ntimeout++; + DEBUG(4, "pkcget: alarm %d\n", pktimeout * 1000 + Ntimeout); + pktimeout += pktimeskew; + if (pktimeout > MAXPKTIME) + pktimeout = MAXPKTIME; + return FAIL; + } + signal(SIGALRM, (sig_t)cgalarm); + + alarm(pktimeout); + while (n > 0) { +#ifdef BSD4_2 + if (linebaudrate > 0) { + r = n * 100000L; + r = r / linebaudrate; + r = (r * 100) - itime; + itime = 0; + /* we predict that more than 1/50th of a + second will go by before the read will + give back all that we want. */ + if (r > 20000) { + tv.tv_sec = r / 1000000L; + tv.tv_usec = r % 1000000L; + DEBUG(11, "PKCGET stall for %d", tv.tv_sec); + DEBUG(11, ".%06d sec\n", tv.tv_usec); + (void) select (0, (fd_set*)0, (fd_set*)0, (fd_set*)0, &tv); + } + } +#endif +#ifndef VMS + ret = read(fn, b, n); +#else + _$Cancel_IO_On_Signal = FD_FAB_Pointer[fn]; + ret = SYS$QioW(_$EFN,(FD_FAB_Pointer[fn]->fab).fab$l_stv, + IO$_READVBLK|IO$M_NOFILTR|IO$M_NOECHO, + iosb,0,0,b,n,0, + iomask,0,0); + _$Cancel_IO_On_Signal = 0; + if (ret == SS$_NORMAL) + ret = iosb[1]+iosb[3]; /* get length of transfer */ + else + ret = 0; +#endif + if (ret == 0) { + alarm(0); + return FAIL; + } + if (ret <= 0) { + alarm(0); + logent(strerror(errno),"FAILED pkcget Read"); + longjmp(Sjbuf, 6); + } + b += ret; + n -= ret; + } + alarm(0); + return SUCCESS; +} diff --git a/src/cmd/uucp/prefix.c b/src/cmd/uucp/prefix.c new file mode 100644 index 0000000..0b5d149 --- /dev/null +++ b/src/cmd/uucp/prefix.c @@ -0,0 +1,41 @@ +#ifndef lint +static char sccsid[] = "@(#)prefix.c 5.3 (Berkeley) 6/20/85"; +#endif + +/*LINTLIBRARY*/ + +/* + * check s2 for prefix s1 + * + * return 0 - != + * return 1 - == + */ + +prefix(s1, s2) +register char *s1, *s2; +{ + register char c; + + while ((c = *s1++) == *s2++) + if (c == '\0') + return 1; + return c == '\0'; +} + +/* + * check s2 for prefix s1 with a wildcard character ? + * + * return 0 - != + * return 1 - == + */ + +wprefix(s1, s2) +register char *s1, *s2; +{ + register char c; + + while ((c = *s1++) != '\0') + if (*s2 == '\0' || (c != *s2++ && c != '?')) + return 0; + return 1; +} diff --git a/src/cmd/uucp/setline.c b/src/cmd/uucp/setline.c new file mode 100644 index 0000000..6587b04 --- /dev/null +++ b/src/cmd/uucp/setline.c @@ -0,0 +1,50 @@ +#ifndef lint +static char sccsid[] = "@(#)setline.c 5.3 (Berkeley) 6/20/85"; +#endif + +#include "uucp.h" +#ifdef USG +#include +#endif + +#define PACKSIZE 64 +#define SNDFILE 'S' +#define RCVFILE 'R' +#define RESET 'X' + +/*LINTLIBRARY*/ + +/* + * optimize line setting for sending or receiving files + * + * return code - none + */ +/*ARGSUSED*/ +setupline(type) +char type; +{ +#ifdef USG + static struct termio tbuf, sbuf; + static int set = 0; + + DEBUG(2, "setline - %c\n", type); + if (IsTcpIp) + return; + switch(type) { + case SNDFILE: + break; + case RCVFILE: + ioctl(Ifn, TCGETA, &tbuf); + sbuf = tbuf; + tbuf.c_cc[VMIN] = PACKSIZE; + ioctl(Ifn, TCSETAW, &tbuf); + set++; + break; + case RESET: + if (set == 0) break; + set = 0; + ioctl(Ifn, TCSETAW, &sbuf); + break; + } +#endif +} diff --git a/src/cmd/uucp/subdir.c b/src/cmd/uucp/subdir.c new file mode 100644 index 0000000..5634803 --- /dev/null +++ b/src/cmd/uucp/subdir.c @@ -0,0 +1,108 @@ +#ifndef lint +static char sccsid[] = "@(#)subdir.c 5.4 (Berkeley) 6/23/85"; +#endif + +#include "uucp.h" + +/*LINTLIBRARY*/ + +/* + * By Tom Truscott, March 1983 + * + * Prefix table. + * If a prefix is "abc", for example, + * then any file Spool/abc... is mapped to Spool/abc/abc... . + * The first prefix found is used, so D.foo should preceed D. in table. + * + * Each prefix must be a subdirectory of Spool, owned by uucp! + * Remember: use cron to uuclean these directories daily, + * and check them manually every now and then. Beware complacency! + */ + +static char *dprefix[] = { + DLocalX, /* Outbound 'xqt' request files */ + DLocal, /* Outbound data files */ + "D.", /* Other "D." files (remember the "."!) */ + "C.", /* "C." subdirectory */ + "X.", /* "X." subdirectory */ + "TM.", /* Temporaries for inbound files */ + 0 +}; + +/* + * filename mapping kludges to put uucp work files in other directories. + */ + +#define BUFLEN 50 + +static char fn1[BUFLEN], fn2[BUFLEN]; /* remapped filename areas */ +static int inspool; /* true iff working dir is Spool */ + +/* + * return (possibly) remapped string s + */ +char * +subfile(as) +char *as; +{ + register char *s, **p; + register int n; + static char *tptr = NULL; + + /* Alternate buffers so "link(subfile(a), subfile(b))" works */ + if (tptr != fn1) + tptr = fn1; + else + tptr = fn2; + + s = as; + tptr[0] = '\0'; + + /* if s begins with Spool/, copy that to tptr and advance s */ + if (strncmp(s, Spool, n = strlen(Spool)) == 0 && s[n] == '/') { + if (!inspool) { + strcpy(tptr, Spool); + strcat(tptr, "/"); + } + s += n + 1; + } + else + if (!inspool) + return as; + + /* look for first prefix which matches, and make subdirectory */ + for (p = &dprefix[0]; *p; p++) { + if (strncmp(s, *p, n = strlen(*p))==0 && s[n] && s[n] != '/') { + strcat(tptr, *p); + strcat(tptr, "/"); + strcat(tptr, s); + return tptr; + } + } + return as; +} + +/* + * save away filename + */ +subchdir(s) +register char *s; +{ + inspool = (strcmp(s, Spool) == 0); + return chdir(s); +} + +/* + * return possibly corrected directory for searching + */ +char * +subdir(d, pre) +register char *d, pre; +{ + if (strcmp(d, Spool) == 0) + if (pre == CMDPRE) + return CMDSDIR; + else if (pre == XQTPRE) + return XEQTDIR; + return d; +} diff --git a/src/cmd/uucp/sysacct.c b/src/cmd/uucp/sysacct.c new file mode 100644 index 0000000..6738191 --- /dev/null +++ b/src/cmd/uucp/sysacct.c @@ -0,0 +1,19 @@ +#ifndef lint +static char sccsid[] = "@(#)sysacct.c 5.3 (Berkeley) 6/23/85"; +#endif + +#include + +/*LINTLIBRARY*/ + +/* + * output accounting info + */ + +/*ARGSUSED*/ +sysacct(bytes, time) +time_t time; +long bytes; +{ + return; +} diff --git a/src/cmd/uucp/systat.c b/src/cmd/uucp/systat.c new file mode 100644 index 0000000..5ac1f74 --- /dev/null +++ b/src/cmd/uucp/systat.c @@ -0,0 +1,149 @@ +#ifndef lint +static char sccsid[] = "@(#)systat.c 5.4 (Berkeley) 6/23/85"; +#endif + +#include "uucp.h" + +#define STATNAME(f, n) sprintf(f, "%s/%s/%s", Spool, "STST", n) +#define S_SIZE 100 + +/*LINTLIBRARY*/ + +/* + * make system status entry + * return codes: none + */ +systat(name, type, text) +char *name, *text; +int type; +{ + char filename[MAXFULLNAME], line[S_SIZE]; + int count, oldtype; + register FILE *fp; + time_t prestime, rtry; + + if (type == 0) + return; + line[0] = '\0'; + time(&prestime); + count = 0; + STATNAME(filename, name); + + fp = fopen(filename, "r"); + if (fp != NULL) { + fgets(line, S_SIZE, fp); + sscanf(line, "%d %d", &oldtype, &count); + if (count <= 0) + count = 0; + fclose(fp); + /* If merely 'wrong time', don't change existing STST */ + if (type == SS_WRONGTIME && oldtype != SS_INPROGRESS) + return; + } + + rtry = Retrytime; + /* if failures repeat, don't try so often, + * to forstall a 'MAX RECALLS' situation. + */ + if (type == SS_FAIL) { + count++; + if (count > 5) { + rtry = rtry * (count-5); + if (rtry > ONEDAY/2) + rtry = ONEDAY/2; + } + } + + +#ifdef VMS + unlink(filename); +#endif + fp = fopen(filename, "w"); + ASSERT(fp != NULL, "SYSTAT OPEN FAIL", filename, 0); + fprintf(fp, "%d %d %ld %ld %s %s\n", type, count, prestime, rtry, text, name); + fclose(fp); + return; +} + +/*** + * rmstat(name) remove system status entry + * char *name; + * + * return codes: none + */ + +rmstat(name) +char *name; +{ + char filename[MAXFULLNAME]; + + STATNAME(filename, name); + unlink(filename); +} + +/* + * check system status for call + * + * return codes 0 - ok | >0 system status + */ + +callok(name) +char *name; +{ + char filename[MAXFULLNAME], line[S_SIZE]; + register FILE *fp; + time_t lasttime, prestime, retrytime; + long t1, t2; + int count, type; + + STATNAME(filename, name); + fp = fopen(filename, "r"); + if (fp == NULL) + return(SS_OK); + + if (fgets(line, S_SIZE, fp) == NULL) { + /* no data */ + fclose(fp); + unlink(filename); + return(SS_OK); + } + + fclose(fp); + time(&prestime); + sscanf(line, "%d%d%ld%ld", &type, &count, &t1, &t2); + lasttime = t1; + retrytime = t2; + + switch(type) { + case SS_BADSEQ: + case SS_CALLBACK: + case SS_NODEVICE: + case SS_INPROGRESS: /*let LCK take care of it */ + return(SS_OK); + + case SS_FAIL: + if (count > MAXRECALLS) { + logent("MAX RECALLS", "NO CALL"); + DEBUG(4, "MAX RECALL COUNT %d\n", count); + if (Debug) { + logent("debugging", "continuing anyway"); + return SS_OK; + } + return type; + } + + if (prestime - lasttime < retrytime) { + logent("RETRY TIME NOT REACHED", "NO CALL"); + DEBUG(4, "RETRY TIME (%ld) NOT REACHED\n", retrytime); + if (Debug) { + logent("debugging", "continuing anyway"); + return SS_OK; + } + return type; + } + + return SS_OK; + default: + return SS_OK; + } +} diff --git a/src/cmd/uucp/tio.c b/src/cmd/uucp/tio.c new file mode 100644 index 0000000..abaa388 --- /dev/null +++ b/src/cmd/uucp/tio.c @@ -0,0 +1,264 @@ +#ifndef lint +static char sccsid[] = "@(#)tio.c 4.6 (Berkeley) 1/24/86"; +#endif + +#include +#include "uucp.h" +#include +#include +#include + +extern int pkfail(); +#define TPACKSIZE 512 +#define TBUFSIZE 1024 +#define LBUFSIZE 128 +#define min(a,b) (((a)<(b))?(a):(b)) + +/* + * htonl is a function that converts a long from host + * order to network order + * ntohl is a function that converts a long from network + * order to host order + * + * network order is 0 1 2 3 (bytes in a long) + * host order on a vax is 3 2 1 0 + * host order on a pdp11 is 1 0 3 2 + * host order on a 68000 is 0 1 2 3 + * most other machines are 0 1 2 3 + */ + +struct tbuf { + long t_nbytes; + char t_data[TBUFSIZE]; +}; + +extern jmp_buf Failbuf; + +twrmsg(type, str, fn) +char type; +register char *str; +{ + char bufr[TBUFSIZE]; + register char *s; + int len, i; + + if(setjmp(Failbuf)) + return FAIL; + signal(SIGALRM, pkfail); + alarm(MAXMSGTIME); + bufr[0] = type; + s = &bufr[1]; + while (*str) + *s++ = *str++; + *s = '\0'; + if (*(--s) == '\n') + *s = '\0'; + len = strlen(bufr) + 1; + if ((i = len % TPACKSIZE)) { + len = len + TPACKSIZE - i; + bufr[len - 1] = '\0'; + } + twrblk(bufr, len, fn); + alarm(0); + return SUCCESS; +} + +trdmsg(str, fn) +register char *str; +{ + int len, cnt = 0; + + if(setjmp(Failbuf)) + return FAIL; + signal(SIGALRM, pkfail); + alarm(MAXMSGTIME); + for (;;) { + len = read(fn, str, TPACKSIZE); + if (len == 0) + continue; + if (len < 0) { + alarm(0); + return FAIL; + } + str += len; + cnt += len; + if (*(str - 1) == '\0' && (cnt % TPACKSIZE) == 0) + break; + } + alarm(0); + return SUCCESS; +} + +twrdata(fp1, fn) +FILE *fp1; +{ + struct tbuf bufr; + register int len; + int ret, mil; + struct timeb t1, t2; + long bytes; + char text[LBUFSIZE]; + + if(setjmp(Failbuf)) + return FAIL; + signal(SIGALRM, pkfail); + bytes = 0L; +#ifdef USG + time(&t1.time); + t1.millitm = 0; +#else !USG + ftime(&t1); +#endif !USG + while ((len = read(fileno(fp1), bufr.t_data, TBUFSIZE)) > 0) { + bytes += len; +#if defined(vax) || defined(pdp11) || defined(ns32000) + bufr.t_nbytes = htonl((long)len); +#else !vax and !pdp11 and !ns32000 + bufr.t_nbytes = len; +#endif !vax and !pdp11 and !ns32000 + DEBUG(8,"twrdata sending %d bytes\n",len); + len += sizeof(long); + alarm(MAXMSGTIME); + ret = twrblk((char *)&bufr, len, fn); + alarm(0); + if (ret != len) + return FAIL; + if (len != TBUFSIZE+sizeof(long)) + break; + } + bufr.t_nbytes = 0; + len = sizeof(long); + alarm(MAXMSGTIME); + ret = twrblk((char *)&bufr, len, fn); + alarm(0); + if (ret != len) + return FAIL; +#ifdef USG + time(&t2.time); + t2.millitm = 0; +#else !USG + ftime(&t2); +#endif !USG + Now = t2; + t2.time -= t1.time; + mil = t2.millitm - t1.millitm; + if (mil < 0) { + --t2.time; + mil += 1000; + } + sprintf(text, "sent data %ld bytes %ld.%02d secs", + bytes, (long)t2.time, mil/10); + sysacct(bytes, t2.time); + DEBUG(1, "%s\n", text); + syslog(text); + return SUCCESS; +} + +trddata(fn, fp2) +FILE *fp2; +{ + register int len, nread; + char bufr[TBUFSIZE]; + struct timeb t1, t2; + int mil; + long bytes, Nbytes; + + if(setjmp(Failbuf)) + return FAIL; + signal(SIGALRM, pkfail); +#ifdef USG + time(&t1.time); + t1.millitm = 0; +#else !USG + ftime(&t1); +#endif !USG + bytes = 0L; + for (;;) { + alarm(MAXMSGTIME); + len = trdblk((char *)&Nbytes,sizeof Nbytes,fn); + alarm(0); + if (len != sizeof Nbytes) + return FAIL; +#if defined(vax) || defined(pdp11) || defined(ns32000) + Nbytes = ntohl(Nbytes); +#endif vax or pdp11 or ns32000 + DEBUG(8,"trddata expecting %ld bytes\n",Nbytes); + nread = Nbytes; + if (nread == 0) + break; + alarm(MAXMSGTIME); + len = trdblk(bufr, nread, fn); + alarm(0); + if (len < 0) { + return FAIL; + } + bytes += len; + DEBUG(11,"trddata got %ld\n",bytes); + if (write(fileno(fp2), bufr, len) != len) { + alarm(0); + return FAIL; + } + } +#ifdef USG + time(&t2.time); + t2.millitm = 0; +#else !USG + ftime(&t2); +#endif !USG + Now = t2; + t2.time -= t1.time; + mil = t2.millitm - t1.millitm; + if (mil < 0) { + --t2.time; + mil += 1000; + } + sprintf(bufr, "received data %ld bytes %ld.%02d secs", + bytes, (long)t2.time, mil/10); + sysacct(bytes, t2.time - t1.time); + DEBUG(1, "%s\n", bufr); + syslog(bufr); + return SUCCESS; +} + +#if !defined(BSD4_2) && !defined(USG) +#define TC 1024 +static int tc = TC; +#endif !BSD4_2 && !USG + +trdblk(blk, len, fn) +register int len; +char *blk; +{ + register int i, ret; + +#if !defined(BSD4_2) && !defined(USG) + /* call ultouch occasionally */ + if (--tc < 0) { + tc = TC; + ultouch(); + } +#endif !BSD4_2 && !USG + for (i = 0; i < len; i += ret) { + ret = read(fn, blk, len - i); + if (ret < 0) + return FAIL; + blk += ret; + if (ret == 0) + return i; + } + return i; +} + + +twrblk(blk, len, fn) +register char *blk; +{ +#if !defined(BSD4_2) && !defined(USG) + /* call ultouch occasionally */ + if (--tc < 0) { + tc = TC; + ultouch(); + } +#endif !BSD4_2 && !USG + return write(fn, blk, len); +} diff --git a/src/cmd/uucp/ulockf.c b/src/cmd/uucp/ulockf.c new file mode 100644 index 0000000..d1ed3c2 --- /dev/null +++ b/src/cmd/uucp/ulockf.c @@ -0,0 +1,197 @@ +#if !defined(lint) && defined(DOSCCS) +static char sccsid[] = "@(#)ulockf.c 5.5.1 (2.11BSD) 1997/10/2"; +#endif + +#include "uucp.h" +#include +#include + +#define LCKMODE 0444 /* File mode for lock files */ +#define MAXLOCKS 16 /* Maximum number of lock files */ + +char *Lockfile[MAXLOCKS]; +char *LockDirectory = LOCKDIR; +int Nlocks = 0; + +/*LINTLIBRARY*/ + +/* + * This routine will attempt to create a lock file (file). + * It makes sure that the lock file is valid if it already exists. + * + * return codes: SUCCESS | FAIL + */ +ulockf(hfile, atime) +char *hfile; +time_t atime; +{ + register char *p; + register int i; + static char tempfile[NAMESIZE]; + char file[NAMESIZE]; + static int pid = -1; + extern int errno; + + if (pid < 0) { + pid = getpid(); + sprintf(tempfile, "%s/LTMP.%d", LockDirectory, pid); + } + sprintf(file, "%s/LCK..%s", LockDirectory, hfile); + i = 0; + while (onelock(pid, tempfile, file) == -1) { /* lock file exists */ +#if !defined(BSD4_2) && !defined(USG) + struct stat stbuf; + time_t ptime; + /* get status to check age of the lock file */ + if (stat(file, &stbuf) == 0) { + (void) time(&ptime); + if ((ptime - stbuf.st_ctime) < atime) + return FAIL; /* file not old enough to delete */ + } +#else + register int fd; + fd = open(file, 0); + if (fd >= 0) { + int upid, ret; + ret = read(fd, &upid, sizeof upid); + close(fd); + if (ret == sizeof upid && (kill(upid, 0) == 0 + || errno != ESRCH)) + return FAIL; /* process is still running */ + } +#endif + assert("DEAD LOCK", file, errno); + logent(file, "DEAD LOCK"); + (void) unlink(file); + sleep(5); /* avoid a possible race */ + ASSERT(i++ < 5, "CAN'T GET LOCKFILE", tempfile, errno); + } + + for (i = 0; i < Nlocks; i++) { + if (Lockfile[i] == NULL) + break; + } + ASSERT(i < MAXLOCKS, "TOO MANY LOCKS", CNULL, i); + if (i >= Nlocks) + i = Nlocks++; + p = (char *)malloc((unsigned)(strlen(file)+1)); + ASSERT(p != NULL, "CAN NOT ALLOCATE FOR", file, 0); + strcpy(p, file); + Lockfile[i] = p; + + return SUCCESS; +} + +/* + * remove all lock files in list or name + */ +rmlock(name) +register char *name; +{ + register int i; + char file[MAXFULLNAME]; + + if (name != NULL) { + sprintf(file, "%s/LCK..%s", LockDirectory, name); + name = file; + } + for (i = 0; i < Nlocks; i++) { + if (Lockfile[i] == NULL) + continue; + if (name == NULL || strcmp(name, Lockfile[i]) == SAME) { + unlink(Lockfile[i]); + free(Lockfile[i]); + Lockfile[i] = NULL; + } + } +} + +/* + * makes lock a name on behalf of pid. Tempfile must be in the same + * file system as name. + */ +onelock(pid, tempfile, name) +int pid; +char *tempfile, *name; +{ + register int fd, ret; + extern int errno; +#ifdef VMS + fd = creat(name, LCKMODE, "1version"); +#else + fd = creat(tempfile, LCKMODE); +#endif + if (fd < 0) { + DEBUG(1,"Can't creat temp file %s ", tempfile); + DEBUG(1,"-- errno %d", errno); + return FAIL; + } + ret = write(fd, (char *)&pid, sizeof(int)); + (void) close(fd); + + if (ret != sizeof(int)) { + DEBUG(1,"Temp file write failed -- errno %d\n", errno); +#ifdef VMS + (void) unlink(name); +#else + (void) unlink(tempfile); +#endif + return FAIL; + } +#ifndef VMS + if (link(tempfile, name) < 0) { + (void) unlink(tempfile); + return FAIL; + } + unlink(tempfile); +#endif + return SUCCESS; +} + +#if !defined(BSD4_2) && !defined(USG) +/* + * update 'change' time for lock files + * + * Only update ctime, not mtime or atime. + * The 'chmod' method permits cu(I)-like programs + * to determine how long uucp has been on the line. + * The old "change access, mod, and change time" method + * can be had by defining OLDTOUCH + * + * return code - none + */ + +ultouch() +{ + static time_t lasttouch = 0; + register int i; + struct ut { + time_t actime; + time_t modtime; + } ut; + +#ifdef USG + time(&Now.time); + t1.millitm = 0; +#else + ftime(&Now); +#endif + ut.actime = ut.modtime = Now.time; + /* Do not waste time touching locking files too often */ + /* (But, defend against backward time changes) */ + if (ut.actime >= lasttouch && ut.actime < lasttouch+60) + return; + lasttouch = ut.actime; + DEBUG(4, "ultouch\n", 0); + + for (i = 0; i < Nlocks; i++) { + if (Lockfile[i] == NULL) + continue; +#ifdef OLDTOUCH + utime(Lockfile[i], &ut); +#else + chmod(Lockfile[i], LCKMODE); +#endif + } +} +#endif diff --git a/src/cmd/uucp/uuclean.c b/src/cmd/uucp/uuclean.c new file mode 100644 index 0000000..178636d --- /dev/null +++ b/src/cmd/uucp/uuclean.c @@ -0,0 +1,231 @@ +#ifndef lint +static char sccsid[] = "@(#)uuclean.c 5.6 (Berkeley) 10/9/85"; +#endif + +#include +#include "uucp.h" +#include +#include +#ifdef NDIR +#include "ndir.h" +#else +#include +#endif + +/* + * + * this program will search through the spool + * directory (Spool) and delete all files with a requested + * prefix which are older than (nomtime) seconds. + * If the -m option is set, the program will try to + * send mail to the usid of the file. + * + * options: + * -m - send mail for deleted file + * -d - directory to clean + * -n - time to age files before delete (in hours) + * -p - prefix for search + * -x - turn on debug outputs + * exit status: + * 0 - normal return + * 1 - can not read directory + */ + +#define NOMTIME 72 /* hours to age files before deletion */ + +int checkprefix = 0; +struct timeb Now; + +main(argc, argv) +char *argv[]; +{ + DIR *dirp; + char file[NAMESIZE]; + time_t nomtime, ptime; + struct stat stbuf; + int mflg=0; + + strcpy(Progname, "uuclean"); + uucpname(Myname); + nomtime = NOMTIME * (time_t)3600; + + while (argc>1 && argv[1][0] == '-') { + switch (argv[1][1]) { + case 'd': + Spool = &argv[1][2]; + break; + case 'm': + mflg = 1; + break; + case 'n': + nomtime = atoi(&argv[1][2]) * (time_t)3600; + break; + case 'p': + checkprefix = 1; + if (&argv[1][2] != '\0') + stpre(&argv[1][2]); + break; + case 'x': + chkdebug(); + Debug = atoi(&argv[1][2]); + if (Debug <= 0) + Debug = 1; + break; + default: + printf("unknown flag %s\n", argv[1]); break; + } + --argc; argv++; + } + + DEBUG(4, "DEBUG# %s\n", "START"); + if (chdir(Spool) < 0) { /* NO subdirs in uuclean! rti!trt */ + printf("%s directory inaccessible\n", Spool); + exit(1); + } + + if ((dirp = opendir(Spool)) == NULL) { + printf("%s directory unreadable\n", Spool); + exit(1); + } + + time(&ptime); + while (gnamef(dirp, file)) { + if (checkprefix && !chkpre(file)) + continue; + + if (stat(file, &stbuf) == -1) { + DEBUG(4, "stat on %s failed\n", file); + continue; + } + + + if ((stbuf.st_mode & S_IFMT) == S_IFDIR) + continue; + if ((ptime - stbuf.st_mtime) < nomtime) + continue; + if (file[0] == CMDPRE) + notfyuser(file); + DEBUG(4, "unlink file %s\n", file); + unlink(file); + if (mflg) + sdmail(file, stbuf.st_uid); + } + + closedir(dirp); + exit(0); +} + + +#define MAXPRE 10 +char Pre[MAXPRE][NAMESIZE]; +int Npre = 0; +/*** + * chkpre(file) check for prefix + * char *file; + * + * return codes: + * 0 - not prefix + * 1 - is prefix + */ + +chkpre(file) +char *file; +{ + int i; + + for (i = 0; i < Npre; i++) { + if (prefix(Pre[i], file)) + return(1); + } + return(0); +} + +/*** + * stpre(p) store prefix + * char *p; + * + * return codes: none + */ + +stpre(p) +char *p; +{ + if (Npre < MAXPRE - 2) + strcpy(Pre[Npre++], p); + return; +} + +/*** + * notfyuser(file) - notfiy requestor of deleted requres + * + * return code - none + */ + +notfyuser(file) +char *file; +{ + FILE *fp; + int numrq; + char frqst[100], lrqst[100]; + char msg[BUFSIZ]; + char *args[10]; + + if ((fp = fopen(file, "r")) == NULL) + return; + if (fgets(frqst, 100, fp) == NULL) { + fclose(fp); + return; + } + numrq = 1; + while (fgets(lrqst, 100, fp)) + numrq++; + fclose(fp); + sprintf(msg, + "File %s delete. \nCould not contact remote. \n%d requests deleted.\n", file, numrq); + if (numrq == 1) { + strcat(msg, "REQUEST: "); + strcat(msg, frqst); + } else { + strcat(msg, "FIRST REQUEST: "); + strcat(msg, frqst); + strcat(msg, "\nLAST REQUEST: "); + strcat(msg, lrqst); + } + getargs(frqst, args, 10); + mailst(args[3], msg, CNULL); +} + + +/*** + * sdmail(file, uid) + * + * sdmail - this routine will determine the owner + * of the file (file), create a message string and + * call "mailst" to send the cleanup message. + * This is only implemented for local system + * mail at this time. + */ + +sdmail(file, uid) +char *file; +{ + static struct passwd *pwd; + struct passwd *getpwuid(); + char mstr[40]; + + sprintf(mstr, "uuclean deleted file %s\n", file); + if (pwd != NULL && pwd->pw_uid == uid) { + mailst(pwd->pw_name, mstr, CNULL); + return; + } + + setpwent(); + if ((pwd = getpwuid(uid)) != NULL) + mailst(pwd->pw_name, mstr, CNULL); +} + +cleanup(code) +int code; +{ + exit(code); +} diff --git a/src/cmd/uucp/uucp.c b/src/cmd/uucp/uucp.c new file mode 100644 index 0000000..8b616b8 --- /dev/null +++ b/src/cmd/uucp/uucp.c @@ -0,0 +1,468 @@ +#ifndef lint +static char sccsid[] = "@(#)uucp.c 5.5 (Berkeley) 10/9/85"; +#endif + +#include "uucp.h" +#include +#include +#include "uust.h" + +/* + * uucp + */ +int Uid; +char *Ropt = " "; +char Path[100], Optns[10], Ename[MAXBASENAME+1]; +char Grade = 'n'; +#ifdef DONTCOPY +int Copy = 0; +#else +int Copy = 1; +#endif +char Nuser[32]; +struct timeb Now; + +/* variables used to check if talking to more than one system. */ +int xsflag = -1; +char xsys[MAXBASENAME+1]; + +long Nbytes = 0; +#define MAXBYTES 50000 /* maximun number of bytes of data per C. file */ +#define MAXCOUNT 15 /* maximun number of files per C. file */ + +main(argc, argv) +char *argv[]; +{ + int ret; + char *sysfile1, *sysfl2; + register char *cp; + char file1[MAXFULLNAME], file2[MAXFULLNAME]; + int avoidgwd = 0; + + strcpy(Progname, "uucp"); + uucpname(Myname); + umask(WFMASK); + Optns[0] = '-'; + Optns[1] = 'd'; +#ifdef DONTCOPY + Optns[2] = 'c'; +#else + Optns[2] = 'C'; +#endif + Ename[0] = Nuser[0] = Optns[3] = '\0'; + while(argc>1 && argv[1][0] == '-'){ + switch(argv[1][1]){ + case 'a': + /* efficiency hack; avoid gwd call */ + avoidgwd = 1; + break; + case 'C': + Copy = 1; + Optns[2] = 'C'; + break; + case 'c': + Copy = 0; + Optns[2] = 'c'; + break; + case 'd': + break; + case 'f': + Optns[1] = 'f'; + break; + case 'e': + strncpy(Ename, &argv[1][2], MAXBASENAME); + break; + case 'g': + Grade = argv[1][2]; + break; + case 'm': + strcat(Optns, "m"); + break; + case 'n': + sprintf(Nuser, "%.31s", &argv[1][2]); + break; + case 'r': + Ropt = argv[1]; + break; + case 's': + Spool = &argv[1][2]; break; + case 'x': + chkdebug(); + Debug = atoi(&argv[1][2]); + if (Debug <= 0) + Debug = 1; + break; + default: + printf("unknown flag %s\n", argv[1]); break; + } + --argc; argv++; + } + DEBUG(4, "\n\n** %s **\n", "START"); + if (!avoidgwd) { + cp = getwd(Wrkdir); + ASSERT(cp != 0, "GETWD FAILED", Wrkdir, cp); + } + ret = subchdir(Spool); + ASSERT(ret >= 0, "CHDIR FAILED", Spool, ret); + + Uid = getuid(); + ret = guinfo(Uid, User, Path); + ASSERT(ret == 0, "CAN NOT FIND UID", CNULL, Uid); + DEBUG(4, "UID %d, ", Uid); + DEBUG(4, "User %s,", User); + DEBUG(4, "Ename (%s) ", Ename); + DEBUG(4, "PATH %s\n", Path); + if (argc < 3) { + fprintf(stderr, "usage uucp from ... to\n"); + cleanup(1); + } + + + /* set up "to" system and file names */ + if ((cp = index(argv[argc - 1], '!')) != NULL) { + sysfl2 = argv[argc - 1]; + *cp = '\0'; + if (*sysfl2 == '\0') + sysfl2 = Myname; + else + strncpy(Rmtname, sysfl2, MAXBASENAME); + if (versys(&sysfl2) != 0) { + fprintf(stderr, "bad system name: %s\n", sysfl2); + cleanup(1); + } + if (Rmtname[0] != '\0') + strncpy(Rmtname, sysfl2, MAXBASENAME); + /* block multi-hop requests immediately */ + if (index(cp+1, '!') != NULL) { + fprintf(stderr, "uucp handles only adjacent sites.\n"); + fprintf(stderr, "Try uusend for multi-hop delivery.\n"); + cleanup(1); + } + strcpy(file2, cp + 1); + } + else { + sysfl2 = Myname; + strcpy(file2, argv[argc - 1]); + } + if (strlen(sysfl2) > MAXBASENAME) + sysfl2[MAXBASENAME] = '\0'; + + + /* do each from argument */ + while (argc > 2) { + if ((cp = index(argv[1], '!')) != NULL) { + sysfile1 = argv[1]; + *cp = '\0'; + if (strlen(sysfile1) > MAXBASENAME) + sysfile1[MAXBASENAME] = '\0'; + if (*sysfile1 == '\0') + sysfile1 = Myname; + else + strncpy(Rmtname, sysfile1, MAXBASENAME); + if (versys(&sysfile1) != 0) { + fprintf(stderr, "bad system name: %s\n", sysfile1); + cleanup(0); + } + if (Rmtname[0] != '\0') + strncpy(Rmtname, sysfl2, MAXBASENAME); + strcpy(file1, cp + 1); + } + else { + sysfile1 = Myname; + strcpy(file1, argv[1]); + } + DEBUG(4, "file1 - %s\n", file1); + copy(sysfile1, file1, sysfl2, file2); + --argc; + argv++; + } + + clscfile(); + if (*Ropt != '-' && xsflag >= 0) + xuucico(xsys); + cleanup(0); +} + +cleanup(code) +int code; +{ + logcls(); + rmlock(CNULL); + if (code) + fprintf(stderr, "uucp failed. code %d\n", code); + exit(code); +} + + +/* + * generate copy files + * + * return codes 0 | FAIL + */ + +copy(s1, f1, s2, f2) +register char *s1, *f1, *s2, *f2; +{ + int type, statret; + struct stat stbuf, stbuf1; + char dfile[NAMESIZE]; + char file1[MAXFULLNAME], file2[MAXFULLNAME]; + FILE *cfp, *gtcfile(); + char opts[100]; + + type = 0; + opts[0] = '\0'; + strcpy(file1, f1); + strcpy(file2, f2); + if (strcmp(s1, Myname) != SAME) + type = 1; + if (strcmp(s2, Myname) != SAME) + type += 2; + if (type & 01) + if ((index(f1, '*') != NULL + || index(f1, '?') != NULL + || index(f1, '[') != NULL)) + type = 4; + + switch (type) { + case 0: + /* all work here */ + DEBUG(4, "all work here %d\n", type); + if (ckexpf(file1)) + return FAIL; + if (ckexpf(file2)) + return FAIL; + if (stat(subfile(file1), &stbuf) != 0) { + fprintf(stderr, "can't get file status %s \n copy failed\n", + file1); + return SUCCESS; + } + statret = stat(subfile(file2), &stbuf1); + if (statret == 0 + && stbuf.st_ino == stbuf1.st_ino + && stbuf.st_dev == stbuf1.st_dev) { + fprintf(stderr, "%s %s - same file; can't copy\n", file1, file2); + return SUCCESS; + } + if (chkpth(User, "", file1) != 0 + || chkperm(file2, index(Optns, 'd')) + || chkpth(User, "", file2) != 0) { + fprintf(stderr, "permission denied\n"); + cleanup(1); + } + if ((stbuf.st_mode & ANYREAD) == 0) { + fprintf(stderr, "can't read file (%s) mode (%o)\n", + file1, (int)stbuf.st_mode); + return FAIL; + } + if (statret == 0 && (stbuf1.st_mode & ANYWRITE) == 0) { + fprintf(stderr, "can't write file (%s) mode (%o)\n", + file2, (int)stbuf.st_mode); + return FAIL; + } + xcp(file1, file2); + logent("WORK HERE", "DONE"); + return SUCCESS; + case 1: + /* receive file */ + DEBUG(4, "receive file - %d\n", type); + chsys(s1); + if (file1[0] != '~') + if (ckexpf(file1)) + return FAIL; + if (ckexpf(file2)) + return FAIL; + if (chkpth(User, "", file2) != 0) { + fprintf(stderr, "permission denied\n"); + return FAIL; + } + if (Ename[0] != '\0') { + /* execute uux - remote uucp */ + xuux(Ename, s1, file1, s2, file2, opts); + return SUCCESS; + } + + cfp = gtcfile(s1); + fprintf(cfp, "R %s %s %s %s\n", file1, file2, User, Optns); + break; + case 2: + /* send file */ + if (ckexpf(file1)) + return FAIL; + if (file2[0] != '~') + if (ckexpf(file2)) + return FAIL; + DEBUG(4, "send file - %d\n", type); + chsys(s2); + + if (chkpth(User, "", file1) != 0) { + fprintf(stderr, "permission denied %s\n", file1); + return FAIL; + } + if (stat(subfile(file1), &stbuf) != 0) { + fprintf(stderr, "can't get status for file %s\n", file1); + return FAIL; + } + if ((stbuf.st_mode & S_IFMT) == S_IFDIR) { + fprintf(stderr, "directory name illegal - %s\n", + file1); + return FAIL; + } + if ((stbuf.st_mode & ANYREAD) == 0) { + fprintf(stderr, "can't read file (%s) mode (%o)\n", + file1, (int)stbuf.st_mode); + return FAIL; + } + if ((Nuser[0] != '\0') && (index(Optns, 'n') == NULL)) + strcat(Optns, "n"); + if (Ename[0] != '\0') { + /* execute uux - remote uucp */ + if (Nuser[0] != '\0') + sprintf(opts, "-n%s", Nuser); + xuux(Ename, s1, file1, s2, file2, opts); + return SUCCESS; + } + Nbytes += stbuf.st_size; + if (Copy) { + gename(DATAPRE, Myname, Grade, dfile); + if (xcp(file1, dfile) != 0) { + fprintf(stderr, "can't copy %s\n", file1); + return FAIL; + } + } + else { + /* make a dummy D. name */ + /* cntrl.c knows names < 6 chars are dummy D. files */ + strcpy(dfile, "D.0"); + } + cfp = gtcfile(s2); + fprintf(cfp, "S %s %s %s %s %s %o %s\n", file1, file2, + User, Optns, dfile, (int)stbuf.st_mode & 0777, Nuser); + break; + case 3: + case 4: + /* send uucp command for execution on s1 */ + DEBUG(4, "send uucp command - %d\n", type); + chsys(s1); + if (strcmp(s2, Myname) == SAME) { + if (ckexpf(file2)) + return FAIL; + if (chkpth(User, "", file2) != 0) { + fprintf(stderr, "permission denied\n"); + return FAIL; + } + } + if (Ename[0] != '\0') { + /* execute uux - remote uucp */ + xuux(Ename, s1, file1, s2, file2, opts); + return SUCCESS; + } + cfp = gtcfile(s1); + fprintf(cfp, "X %s %s!%s %s %s\n", file1, s2, file2, User, Optns); + break; + } + return SUCCESS; +} + +/* + * execute uux for remote uucp + * + * return code - none + */ + +xuux(ename, s1, f1, s2, f2, opts) +char *ename, *s1, *s2, *f1, *f2, *opts; +{ + char cmd[200]; + + DEBUG(4, "Ropt(%s) ", Ropt); + DEBUG(4, "ename(%s) ", ename); + DEBUG(4, "s1(%s) ", s1); + DEBUG(4, "f1(%s) ", f1); + DEBUG(4, "s2(%s) ", s2); + DEBUG(4, "f2(%s)\n", f2); + sprintf(cmd, "uux %s %s!uucp %s %s!%s \\(%s!%s\\)", + Ropt, ename, opts, s1, f1, s2, f2); + DEBUG(4, "cmd (%s)\n", cmd); + system(cmd); + return; +} + +FILE *Cfp = NULL; +char Cfile[NAMESIZE]; + +/* + * get a Cfile descriptor + * + * return an open file descriptor + */ + +FILE * +gtcfile(sys) +register char *sys; +{ + static char presys[8] = ""; + static int cmdcount = 0; + register int savemask; + + if (strcmp(presys, sys) != SAME /* this is !SAME on first call */ + || Nbytes > MAXBYTES + || ++cmdcount > MAXCOUNT) { + cmdcount = 1; + Nbytes = 0; + if (presys[0] != '\0') { + clscfile(); + } + gename(CMDPRE, sys, Grade, Cfile); +#ifdef VMS + savemask = umask(~0600); /* vms must have read permission */ +#else + savemask = umask(~0200); +#endif + Cfp = fopen(subfile(Cfile), "w"); + umask(savemask); + ASSERT(Cfp != NULL, CANTOPEN, Cfile, 0); + strcpy(presys, sys); + } + return Cfp; +} + +/* + * close cfile + * + * return code - none + */ + +clscfile() +{ + if (Cfp == NULL) + return; + fclose(Cfp); + chmod(subfile(Cfile), ~WFMASK & 0777); + logent(Cfile, "QUE'D"); + US_CRS(Cfile); + Cfp = NULL; +} + +/* + * compile a list of all systems we are referencing + */ +chsys(s1) +register char *s1; +{ + if (xsflag < 0) + xsflag = 0; + else if (xsflag > 0) + return; + + if (xsys[0] == '\0') { + strncpy(xsys, s1, MAXBASENAME); + return; + } + + if (strncmp(xsys, s1, MAXBASENAME) == SAME) + return; + + xsflag++; + xsys[0] = '\0'; +} diff --git a/src/cmd/uucp/uucp.h b/src/cmd/uucp/uucp.h new file mode 100644 index 0000000..7e91841 --- /dev/null +++ b/src/cmd/uucp/uucp.h @@ -0,0 +1,424 @@ +/* uucp.h 5.11.6 1997/10/2 */ + +#include +#include +#include +#include +#include +#include + + +struct timeb { + time_t time; + u_short millitm; + short timezone; + short dstflag; +}; + +/* + * Determine local uucp name of this machine. + * Define one of the following: + * + * For UCB 4.1A and later systems, you will have the gethostname(2) call. + * If this call exists, define GETHOSTNAME. + * + * For USG 3.0 and later systems, you will have the uname(2) call. + * If this call exists, define UNAME. + * + * Some systems have a line of the form '#define sysname "myuucpname",' + * in the file /usr/include/whoami.h, to identify their machine. + * If your site does that, define WHOAMI. + * + * If your site has , but you do not want to read + * that file every time uucp runs, you can compile sysname into uucp. + * This is faster and more reliable, but binaries do not port. + * If you want to do that, define CCWHOAMI. + * + * Some systems put the local uucp name in a single-line file + * named /etc/uucpname or /local/uucpname. + * If your site does that, define UUNAME. + * + * Systems running 3Com's UNET will have the getmyhname() call. + * If you want to, define GETMYHNAME. + * + * You should also define MYNAME to be your uucp name. + * + * For each of the above that are defined, uucp checks them in order. + * It stops on the first method that returns a non null name. + * If everything fails, it uses "unknown" for the system name. + */ +#define GETHOSTNAME /**/ +/* #define UNAME /**/ +/* #define WHOAMI /**/ +/* #define CCWHOAMI /**/ +/* #define UUNAME /**/ +/* #define GETMYHNAME /**/ +/* If the above fails ... */ +#define MYNAME "wlonex" + +/* + * If you have it, include to use exit + * codes that will be understood by sendmail. + * Otherwise, define EX_NOHOST, EX_CANTCREAT, and EX_NOINPUT. + */ +#include +/*#define EX_NOINPUT 66 /**/ +/*#define EX_NOHOST 68 /**/ +/*#define EX_CANTCREAT 73 /**/ + +/* + * Define the various kinds of connections to include. + * The complete list is in the condevs array in condevs.c + */ +/* #define ATT2224 /* AT&T 2224 */ +//#define BSDTCP /* 4.2bsd or 2.9bsd TCP/IP */ +/* #define CDS224 /* Concord Data Systems 2400 */ +/* #define DATAKIT /* ATT's datakit */ +/* #define DF02 /* Dec's DF02/DF03 */ +/* #define DF112 /* Dec's DF112 */ +/* #define DN11 /* "standard" DEC dialer */ +#define HAYES /* Hayes' Smartmodem */ +/* #define HAYES2400 /* Hayes' 2400 baud Smartmodem */ +/* #define MICOM /* Micom Mux port */ +/* #define NOVATION /* Novation modem */ +/* #define PAD /* X.25 PAD */ +/* #define PENRIL /* PENRIL Dialer */ +/* #define PNET /* Purdue network */ +/* #define RVMACS /* Racal-Vadic MACS 820 dialer, 831 adaptor */ +/* #define SYTEK /* Sytek Local Area Net */ +/* #define UNETTCP /* 3Com's UNET */ +/* #define USR2400 /* USRobotics Courier 2400 */ +/* #define VA212 /* Racal-Vadic 212 */ +/* #define VA811S /* Racal-Vadic 811S dialer, 831 adaptor */ +/* #define VA820 /* Racal-Vadic 820 dialer, 831 adaptor */ +/* #define VADIC /* Racal-Vadic 345x */ +/* #define VENTEL /* Ventel Dialer */ +/* #define VMACS /* Racal-Vadic MACS 811 dialer, 831 adaptor */ + +#if defined(USR2400) && !defined(HAYES) +#define HAYES +#endif + +#if defined(UNETTCP) || defined(BSDTCP) +#define TCPIP +#endif + +/* + * We need a timer to write slowly to certain modems. + * and for generating breaks. + * + * define INTERVALTIMER to use 4.[23] bsd interval timer. + * define FASTTIMER if you have the nap() system call. + * define FTIME if you have the ftime() system call. + * define BUSYLOOP if you must do a busy loop. + * Look at uucpdelay() in condevs.c for details. + */ +#define INTERVALTIMER /**/ +/*#define FASTTIMER /**/ +/*#define FTIME /**/ +/*#define BUSYLOOP /**/ + +/* + * If your site is using "ndir.h" to retrofit the Berkeley + * directory reading routines, define NDIR. + * You will probably also have to set LIBNDIR in Makefile. + * Otherwise, is assumed to have the Berkeley directory definitions. + */ +/*#define NDIR /**/ + +/* + * If yours is a BTL system III, IV, V or so-on site, define USG. + */ +/*#define USG /**/ + +/* + * If you are running 4.3bsd, define BSD4_3 and BSD4_2 + * If you are just running 4.2bsd, define BSD4_2 + * If you are running 2.11bsd, define BSD4_3 and BSD4_2 + * If you are running the BRL version of 4.2BSD define BRL4_2, NOT BSD4_3 + */ +#define BSD4_3 /**/ +#define BSD4_2 /**/ +/*#define BRL4_2 /**/ + +#if defined(BRL4_2) && !defined(BSD4_2) +#define BSD4_2 +#undef BSD4_3 +#endif + +/* + * If you are running 2.9bsd define BSD2_9 + */ +/*#define BSD2_9 /**/ + +/* + * If you are using 'inetd' with 4.2bsd, define BSDINETD + */ +/* #define BSDINETD /**/ + +/* + * If you are running 4.3bsd, 2.11bsd or BRL 4.2, you are running 'inetd' + */ + +#if (defined(BSD4_3) || defined(BRL4_2)) && !defined(BSDINETD) +#define BSDINETD +#endif + +/*#define VMSDTR /* Turn on modem control on vms(works DTR) for + develcon and gandalf ports to gain access */ +/* + * If you want to use the same modem for dialing in and out define + * DIALINOUT to be the localtion of the acucntrl program + */ +/* #define DIALINOUT "/usr/libexec/acucntrl" /**/ + +/* + * If you want all ACU lines to be DIALINOUT, define ALLACUINOUT + */ +/* #define ALLACUINOUT /**/ + +/* define the value of WFMASK - for umask call - used for all uucp work files */ +#define WFMASK 0137 + +/* define the value of LOGMASK - for LOGFILE, SYSLOG, ERRLOG */ +#define LOGMASK 0133 + +/* All files are given at least the following at the final destination */ +/* It is also the default mode, so '666' is recommended */ +/* and 444 is minimal (minimally useful, maximally annoying) */ +#define BASEMODE 0666 + +/* + * Define NOSTRANGERS if you don't want to accept transactions from + * sites that are not in your L.sys file (see cico.c) + */ +#define NOSTRANGERS /**/ + +/* + * Traditionally LCK (lock) files have been kept in /usr/spool/uucp. + * If you want that define LOCKDIR to be ".". + * If you want the locks kept in a subdirectory, define LOCKDIR as "LCK". + * Good news about LCK. subdirectory: the directory can be mode 777 so + * unprivileged programs can share the uucp locking system, + * and the subdirectory keeps down clutter in the main directory. + * The BAD news: you have to change 'tip' and another programs that + * know where the LCK files are kept, and you have to change your /etc/rc + * if your rc cleans out the lock files (as it should). + */ +/*#define LOCKDIR "LCK" /**/ +#define LOCKDIR "." /**/ + +/* + * If you want uucp and uux to copy the data files by default, + * don't define DONTCOPY (This is the way older 4bsd uucps worked) + * If you want uucp and uux to use the original files instead of + * copies, define DONTCOPY (This is the way System III and V work) + */ +#define DONTCOPY /**/ + +/* + * Very few (that I know of) systems use the sequence checking feature. + * If you are not going to use it (hint: you are not), + * do not define GNXSEQ. This saves precious room on PDP11s. + */ +/*#define GNXSEQ /* comment this out to save space */ + +/* + * If you want the logfile stored in a file for each site instead + * of one file + * define LOGBYSITE as the directory to put the files in + */ +/*#define LOGBYSITE "/usr/spool/uucp/LOG" /**/ + +#define XQTDIR "/usr/spool/uucp/XTMP" +#define SQFILE "/etc/uucp/SQFILE" +#define SQTMP "/etc/uucp/SQTMP" +#define SLCKTIME 5400 /* system/device timeout (LCK.. files) */ +#define SEQFILE "/etc/uucp/SEQF" +#define SYSFILE "/etc/uucp/L.sys" +#define DEVFILE "/etc/uucp/L-devices" +#define DIALFILE "/etc/uucp/L-dialcodes" +#define USERFILE "/etc/uucp/USERFILE" +#define CMDFILE "/etc/uucp/L.cmds" +#define ALIASFILE "/etc/uucp/L.aliases" + +#define SPOOL "/usr/spool/uucp" +#define SYSLOG "/usr/spool/uucp/SYSLOG" +#define PUBDIR "/usr/spool/uucppublic" + +#define SQLOCK "SQ" +#define SEQLOCK "SEQL" +#define CMDPRE 'C' +#define DATAPRE 'D' +#define XQTPRE 'X' + +#define LOGFILE "/usr/spool/uucp/LOGFILE" +#define ERRLOG "/usr/spool/uucp/ERRLOG" +#define CMDSDIR "/usr/spool/uucp/C." +#define DATADIR "/usr/spool/uucp/D." +#define XEQTDIR "/usr/spool/uucp/X." + +#define RMTDEBUG "AUDIT" +#define CORRUPT "CORRUPT" +#define SQTIME 60 +#define TRYCALLS 2 /* number of tries to dial call */ + +#define LLEN 50 +#define MAXRQST 250 + +#define DEBUG(l, f, s) if (Debug >= l) fprintf(stderr, f, s); else + +#define ASSERT(e, s1, s2, i1) if (!(e)) {assert(s1, s2, i1);cleanup(FAIL);}else + +#define delock(dev) rmlock(dev) +#define mlock(dev) ulockf(dev, SLCKTIME) + +#define SAME 0 +#define ANYREAD 0004 +#define ANYWRITE 02 +#define FAIL -1 +#define SUCCESS 0 +#define CNULL (char *) 0 +#define STBNULL (struct sgttyb *) 0 +#define MASTER 1 +#define SLAVE 0 +#define MAXFULLNAME 255 +#define MAXMSGTIME 45 +#define NAMESIZE 255 +#define MAXBASENAME 14 +#define SYSNSIZE (MAXBASENAME-1-1-1-4) +#define EOTMSG "\04\n\04\n" +#define CALLBACK 1 +#define ONEDAY 86400L + + /* commands */ +#define SHELL "/bin/sh" +#define UUCICO "/usr/sbin/uucico" +#define UUXQT "/usr/libexec/uuxqt" +#define UUCP "uucp" + + /* call connect fail stuff */ +#define CF_SYSTEM -1 +#define CF_TIME -2 +#define CF_LOCK -3 +#define CF_NODEV -4 +#define CF_DIAL -5 +#define CF_LOGIN -6 + +#define F_NAME 0 +#define F_TIME 1 +#define F_LINE 2 +#define F_CLASS 3 /* an optional prefix and the speed */ +#define F_PHONE 4 +#define F_LOGIN 5 + +#define MAXPH 60 /* maximum length of a phone number */ + + /* This structure tells how to get to a device */ +struct condev { + char *CU_meth; /* method, such as 'ACU' or 'DIR' */ + char *CU_brand; /* brand, such as 'Hayes' or 'Vadic' */ + int (*CU_gen)(); /* what to call to search for brands */ + int (*CU_open)(); /* what to call to open brand */ + int (*CU_clos)(); /* what to call to close brand */ +}; + + /* This structure tells about a device */ +struct Devices { +#define D_type D_arg[0] +#define D_line D_arg[1] +#define D_calldev D_arg[2] +#define D_class D_arg[3] +#define D_brand D_arg[4] +#define D_CHAT 5 + int D_numargs; + int D_speed; + char *D_arg[20]; + char D_argbfr[100]; +}; + + /* system status stuff */ +#define SS_OK 0 +#define SS_NODEVICE 1 +#define SS_CALLBACK 2 +#define SS_INPROGRESS 3 +#define SS_FAIL 4 +#define SS_BADSEQ 5 +#define SS_WRONGTIME 6 + + /* fail/retry parameters */ +#define RETRYTIME 600 +#define MAXRECALLS 25 + + /* stuff for command execution */ +#define X_RQDFILE 'F' +#define X_STDIN 'I' +#define X_STDOUT 'O' +#define X_CMD 'C' +#define X_USER 'U' +#define X_SENDFILE 'S' +#define X_NONOTI 'N' +#define X_RETURNTO 'R' +#define X_NONZERO 'Z' +#define X_LOCK "XQT" +#define X_LOCKTIME 3600L + +#define WKDSIZE 100 /* size of work dir name */ + +#include +#ifndef USG +//#include +#else +struct timeb +{ + time_t time; + unsigned short millitm; + short timezone; + short dstflag; +}; +#define rindex strrchr +#define index strchr +#endif + +extern struct timeb Now; + +extern int Ifn, Ofn; +extern char *Rmtname; +extern char User[]; +extern char Loginuser[]; +extern char *Spool; +extern char Myname[]; +extern char Myfullname[]; +extern int Debug; +extern int Bspeed; +extern char Wrkdir[]; +extern time_t Retrytime; +extern short Usrf; +extern int IsTcpIp; +extern char Progname[]; +extern int (*CU_end)(); +extern struct condev condevs[]; +extern char NOLOGIN[]; + +extern char DLocal[], DLocalX[], *subfile(), *subdir(); + +/* Commonly called routines which return non-int value */ +extern char *fdig(), *cfgets(); +extern FILE *rpopen(); + +extern char _FAILED[], CANTOPEN[], DEVNULL[]; + +#ifdef lint +/* This horrible gross kludge is the only way I know to + * convince lint that signal(SIGINT,SIG_IGN) is legal. It hates SIG_IGN. + */ +#ifdef SIG_IGN +#undef SIG_IGN +#endif +#define SIG_IGN main +extern int main(); +#ifdef DEBUG +#undef DEBUG +#endif +#define DEBUG(a,b,c) +#endif diff --git a/src/cmd/uucp/uucpd.c b/src/cmd/uucp/uucpd.c new file mode 100644 index 0000000..2aa3deb --- /dev/null +++ b/src/cmd/uucp/uucpd.c @@ -0,0 +1,303 @@ +#if defined(DOSCCS) && !defined(lint) +static char sccsid[] = "@(#)uucpd.c 5.4.1 (2.11BSD GTE) 1/1/94"; +#endif + +/* + * 4.2BSD or 2.9BSD TCP/IP server for uucico + * uucico's TCP channel causes this server to be run at the remote end. + */ + +#include "uucp.h" +#ifdef BSD2_9 +#include +#include +#endif BSD2_9 +#include +#include +#include +#include +#include +#include +#include +#include + +#if !defined(BSD4_2) && !defined(BSD2_9) +--- You must have either BSD4_2 or BSD2_9 defined for this to work +#endif +#if defined(BSD4_2) && defined(BSD2_9) +--- You may not have both BSD4_2 and BSD2_9 defined for this to work +#endif + +char lastlog[] = "/usr/adm/lastlog"; +struct sockaddr_in hisctladdr; +int hisaddrlen = sizeof hisctladdr; +struct sockaddr_in myctladdr; +int mypid; + +char Username[64]; +char *nenv[] = { + Username, + NULL, +}; +extern char **environ; + +main(argc, argv) +int argc; +char **argv; +{ +#ifndef BSDINETD + register int s, tcp_socket; + struct servent *sp; +#endif !BSDINETD + extern int errno; + int dologout(); + + environ = nenv; +#ifdef BSDINETD + close(1); close(2); + dup(0); dup(0); + hisaddrlen = sizeof (hisctladdr); + if (getpeername(0, &hisctladdr, &hisaddrlen) < 0) { + fprintf(stderr, "%s: ", argv[0]); + perror("getpeername"); + _exit(1); + } + if (fork() == 0) + doit(&hisctladdr); + dologout(); + exit(1); +#else !BSDINETD + sp = getservbyname("uucp", "tcp"); + if (sp == NULL){ + perror("uucpd: getservbyname"); + exit(1); + } + if (fork()) + exit(0); + if ((s=open("/dev/tty", 2)) >= 0){ + ioctl(s, TIOCNOTTY, (char *)0); + close(s); + } + + bzero((char *)&myctladdr, sizeof (myctladdr)); + myctladdr.sin_family = AF_INET; + myctladdr.sin_port = sp->s_port; +#ifdef BSD4_2 + tcp_socket = socket(AF_INET, SOCK_STREAM, 0); + if (tcp_socket < 0) { + perror("uucpd: socket"); + exit(1); + } + if (bind(tcp_socket, (char *)&myctladdr, sizeof (myctladdr)) < 0) { + perror("uucpd: bind"); + exit(1); + } + listen(tcp_socket, 3); /* at most 3 simultaneuos uucp connections */ + signal(SIGCHLD, dologout); + + for(;;) { + s = accept(tcp_socket, &hisctladdr, &hisaddrlen); + if (s < 0){ + if (errno == EINTR) + continue; + perror("uucpd: accept"); + exit(1); + } + if (fork() == 0) { + close(0); close(1); close(2); + dup(s); dup(s); dup(s); + close(tcp_socket); close(s); + doit(&hisctladdr); + exit(1); + } + close(s); + } +#endif BSD4_2 + +#ifdef BSD2_9 + for(;;) { + signal(SIGCHLD, dologout); + s = socket(SOCK_STREAM, 0, &myctladdr, + SO_ACCEPTCONN|SO_KEEPALIVE); + if (s < 0) { + perror("uucpd: socket"); + exit(1); + } + if (accept(s, &hisctladdr) < 0) { + if (errno == EINTR) { + close(s); + continue; + } + perror("uucpd: accept"); + exit(1); + } + if (fork() == 0) { + close(0); close(1); close(2); + dup(s); dup(s); dup(s); + close(s); + doit(&hisctladdr); + exit(1); + } + } +#endif BSD2_9 +#endif !BSDINETD +} + +doit(sinp) +struct sockaddr_in *sinp; +{ + char user[64], passwd[64]; + char *xpasswd, *crypt(); + struct passwd *pw, *getpwnam(); + + alarm(60); + printf("login: "); fflush(stdout); + if (readline(user, sizeof user) < 0) { + fprintf(stderr, "user read\n"); + return; + } + /* truncate username to 8 characters */ + user[8] = '\0'; + pw = getpwnam(user); + if (pw == NULL) { + fprintf(stderr, "user unknown\n"); + return; + } + if (strcmp(pw->pw_shell, UUCICO)) { + fprintf(stderr, "Login incorrect."); + return; + } + if (pw->pw_passwd && *pw->pw_passwd != '\0') { + printf("Password: "); fflush(stdout); + if (readline(passwd, sizeof passwd) < 0) { + fprintf(stderr, "passwd read\n"); + return; + } + xpasswd = crypt(passwd, pw->pw_passwd); + if (strcmp(xpasswd, pw->pw_passwd)) { + fprintf(stderr, "Login incorrect."); + return; + } + } + alarm(0); + sprintf(Username, "USER=%s", user); + dologin(pw, sinp); + setgid(pw->pw_gid); +#ifdef BSD4_2 + initgroups(pw->pw_name, pw->pw_gid); +#endif BSD4_2 + chdir(pw->pw_dir); + setuid(pw->pw_uid); +#ifdef BSD4_2 + execl(UUCICO, "uucico", (char *)0); +#endif BSD4_2 +#ifdef BSD2_9 + sprintf(passwd, "-h%s", inet_ntoa(sinp->sin_addr)); + execl(UUCICO, "uucico", passwd, (char *)0); +#endif BSD2_9 + perror("uucico server: execl"); +} + +readline(p, n) +register char *p; +register int n; +{ + char c; + + while (n-- > 0) { + if (read(0, &c, 1) <= 0) + return(-1); + c &= 0177; + if (c == '\n' || c == '\r') { + *p = '\0'; + return(0); + } + *p++ = c; + } + return(-1); +} + +#include +#ifdef BSD4_2 +#include +#endif BSD4_2 + +#ifdef BSD2_9 +#define O_APPEND 0 /* kludge */ +#define wait3(a,b,c) wait2(a,b) +#endif BSD2_9 + +#define SCPYN(a, b) strncpy(a, b, sizeof (a)) + +struct utmp utmp; + +dologout() +{ + union wait status; + int pid, wtmp; + +#ifdef BSDINETD + while ((pid=wait(&status)) > 0) { +#else !BSDINETD + while ((pid=wait3(&status,WNOHANG,0)) > 0) { +#endif !BSDINETD + wtmp = open("/usr/adm/wtmp", O_WRONLY|O_APPEND); + if (wtmp >= 0) { + sprintf(utmp.ut_line, "uucp%.4d", pid); + SCPYN(utmp.ut_name, ""); + SCPYN(utmp.ut_host, ""); + (void) time(&utmp.ut_time); +#ifdef BSD2_9 + (void) lseek(wtmp, 0L, 2); +#endif BSD2_9 + (void) write(wtmp, (char *)&utmp, sizeof (utmp)); + (void) close(wtmp); + } + } +} + +/* + * Record login in wtmp file. + */ +dologin(pw, sin) +struct passwd *pw; +struct sockaddr_in *sin; +{ + char line[32]; + char remotehost[32]; + int wtmp, f; + struct hostent *hp = gethostbyaddr(&sin->sin_addr, + sizeof (struct in_addr), AF_INET); + + if (hp) { + strncpy(remotehost, hp->h_name, sizeof (remotehost)); + endhostent(); + } else + strncpy(remotehost, inet_ntoa(sin->sin_addr), + sizeof (remotehost)); + wtmp = open("/usr/adm/wtmp", O_WRONLY|O_APPEND); + if (wtmp >= 0) { + /* hack, but must be unique and no tty line */ + sprintf(line, "uucp%.4d", getpid()); + SCPYN(utmp.ut_line, line); + SCPYN(utmp.ut_name, pw->pw_name); + SCPYN(utmp.ut_host, remotehost); + time(&utmp.ut_time); +#ifdef BSD2_9 + (void) lseek(wtmp, 0L, 2); +#endif BSD2_9 + (void) write(wtmp, (char *)&utmp, sizeof (utmp)); + (void) close(wtmp); + } + if ((f = open(lastlog, 2)) >= 0) { + struct lastlog ll; + + time(&ll.ll_time); + lseek(f, (long)pw->pw_uid * sizeof(struct lastlog), 0); + strcpy(line, remotehost); + SCPYN(ll.ll_line, line); + SCPYN(ll.ll_host, remotehost); + (void) write(f, (char *) &ll, sizeof ll); + (void) close(f); + } +} diff --git a/src/cmd/uucp/uucpdefs.c b/src/cmd/uucp/uucpdefs.c new file mode 100644 index 0000000..d99f908 --- /dev/null +++ b/src/cmd/uucp/uucpdefs.c @@ -0,0 +1,31 @@ +#if !defined(lint) && defined(DOSCCS) +static char sccsid[] = "@(#)uucpdefs.c 5.5.1 (2.11BSD) 1996/11/27"; +#endif + +#include "uucp.h" + +char Progname[64]; +int Ifn, Ofn; +char RRmtname[MAXFULLNAME]; +char *Rmtname = RRmtname; +char User[128]; +char Loginuser[16]; +char Myname[MAXBASENAME+1]; +char Wrkdir[WKDSIZE]; + +char *Spool = SPOOL; +char DLocal[64]; +char DLocalX[64]; +int Debug = 0; +time_t Retrytime; +short Usrf = 0; /* Uustat global flag */ +int IsTcpIp = 0; /* 1 == TCP/IP connection, else 0. kludge to suppress ioctl */ +char MaxGrade = '\177'; +char DefMaxGrade = '\177'; +int nologinflag = 0; +char NOLOGIN[] = _PATH_NOLOGIN; + +/* Save some data space */ +char DEVNULL[] = _PATH_DEVNULL; +char CANTOPEN[] = "CAN'T OPEN"; +char _FAILED[] = "FAILED"; diff --git a/src/cmd/uucp/uucpname.c b/src/cmd/uucp/uucpname.c new file mode 100644 index 0000000..e485067 --- /dev/null +++ b/src/cmd/uucp/uucpname.c @@ -0,0 +1,227 @@ +#ifndef lint +static char sccsid[] = "@(#)uucpname.c 5.5 (Berkeley) 10/9/85"; +#endif + +#include "uucp.h" +#include +#include + +/*LINTLIBRARY*/ + +#ifdef GETMYHNAME +#include +#endif + +#ifdef UNAME +/* Use USG uname() library routine */ +#include +#endif + +#ifdef CCWHOAMI +/* Compile in 'sysname' as found in standard(!) include file */ +#include +#endif +char Myfullname[64]; + +/* + * uucpname(name) get the uucp name + * + * return code - none + */ +uucpname(name) +register char *name; +{ + register char *s; + + /* + * Since some UNIX systems do not honor the set-user-id bit + * when the invoking user is root, we must change the uid here. + * So uucp files are created with the correct owner. + */ + if (geteuid() == 0 && getuid() == 0) { + struct stat stbuf; + stbuf.st_uid = 0; /* In case the stat fails */ + stbuf.st_gid = 0; + stat(UUCICO, &stbuf); /* Assume uucico is correctly owned */ + setgid(stbuf.st_gid); + setuid(stbuf.st_uid); + } + + s = NULL; /* system name unknown, so far */ + +#ifdef GETHOSTNAME + if (s == NULL || *s == '\0') { +#ifdef VMS + int i = sizeof(Myfullname); +#endif + + s = Myfullname; +#ifdef VMS + if(gethostname(Myfullname, &i) == -1) { +#else + if(gethostname(Myfullname, sizeof(Myfullname)) == -1) { +#endif + DEBUG(1, "gethostname", _FAILED); + s = NULL; + } + } +#endif + +#ifdef UNAME + /* Use USG library routine */ + if (s == NULL || *s == '\0') { + struct utsname utsn; + + if (uname(&utsn) == -1) { + DEBUG(1, "uname", _FAILED); + s = NULL; + } else { + strncpy(Myfullname, utsn.nodename, sizeof Myfullname); + s = Myfullname; + } + } +#endif + +#ifdef WHOAMI + /* Use fake gethostname() routine */ + if (s == NULL || *s == '\0') { + + s = Myfullname; + if (fakegethostname(Myfullname, sizeof(Myfullname)) == -1) { + DEBUG(1, "whoami search", _FAILED); + s = NULL; + } + } +#endif + +#ifdef CCWHOAMI + /* compile sysname right into uucp */ + if (s == NULL || *s == '\0') { + s = sysname; + strncpy(Myfullname, s, sizeof Myfullname); + } +#endif + +#ifdef UUNAME + /* uucp name is stored in /etc/uucpname or /local/uucpname */ + if (s == NULL || *s == '\0') { + FILE *uucpf; + + s = Myfullname; + if (((uucpf = fopen("/etc/uucpname", "r")) == NULL && + (uucpf = fopen("/local/uucpname", "r")) == NULL) || + fgets(Myfullname, sizeof Myfullname, uucpf) == NULL) { + DEBUG(1, "uuname search", _FAILED); + s = NULL; + } + if (s == Myfullname) { + register char *p; + p = index(s, '\n'); + if (p) + *p = '\0'; + } + if (uucpf != NULL) + fclose(uucpf); + } +#endif + +#ifdef GETMYHNAME + /* Use 3Com's getmyhname() routine */ + if (s == NULL || *s == '\0') { + if ((s = getmyhname()) == NULL) + DEBUG(1, "getmyhname", _FAILED); + else + strncpy(Myfullname, s, sizeof Myfullname); + } +#endif + +#ifdef MYNAME + if (s == NULL || *s == '\0') { + s = MYNAME; + strncpy(Myfullname, s, sizeof Myfullname); + } +#endif + + if (s == NULL || *s == '\0') { + /* + * As a last ditch thing, we *could* search Spool + * for D. and use that, + * but that is too much trouble, isn't it? + */ + logent("SYSTEM NAME", "CANNOT DETERMINE"); + strcpy(Myfullname, "unknown"); + } + + /* + * copy uucpname back to caller-supplied buffer, + * truncating to MAXBASENAME characters. + * Also set up subdirectory names + * Truncate names at '.' if found to handle cases like + * seismo.css.gov being returned by gethostname(). + * uucp sites should not have '.' in their name anyway + */ + s = index(Myfullname, '.'); + if (s != NULL) + *s = '\0'; + strncpy(name, Myfullname, MAXBASENAME); + name[MAXBASENAME] = '\0'; + DEBUG(1, "My uucpname = %s\n", name); + + sprintf(DLocal, "D.%.*s", SYSNSIZE, name); + sprintf(DLocalX, "D.%.*sX", SYSNSIZE, name); +} + +#ifdef WHOAMI +/* + * simulate the 4.2 bsd system call by reading /usr/include/whoami.h + * and looking for the #define sysname + */ + +#define HDRFILE "/usr/include/whoami.h" + +fakegethostname(name, len) +char *name; +int len; +{ + char buf[BUFSIZ]; + char bname[32]; + char hname[32]; + char nname[128]; + register char *p, *q, *nptr; + int i; + register FILE *fd; + + fd = fopen(HDRFILE, "r"); + if (fd == NULL) + return(-1); + + hname[0] = 0; + nname[0] = 0; + nptr = nname; + + while (fgets(buf, sizeof buf, fd) != NULL) { /* each line in the file */ + if (sscanf(buf, "#define sysname \"%[^\"]\"", bname) == 1) { + strcpy(hname, bname); + } else if (sscanf(buf, "#define nickname \"%[^\"]\"", bname) == 1) { + strcpy(nptr, bname); + nptr += strlen(bname) + 1; + } else if (sscanf(buf, "#define nickname%d \"%[^\"]\"", &i, bname) == 2) { + strcpy(nptr, bname); + nptr += strlen(bname) + 1; + } + } + fclose(fd); + if (hname[0] == 0) + return FAIL; + strncpy(name, hname, len); + p = nname; + i = strlen(hname) + 1; + q = name + i; + while (i < len && (p[0] != 0 || p[1] != 0)) { + *q++ = *p++; + i++; + } + *q++ = 0; + return SUCCESS; +} +#endif diff --git a/src/cmd/uucp/uudecode.c b/src/cmd/uucp/uudecode.c new file mode 100644 index 0000000..2f67d61 --- /dev/null +++ b/src/cmd/uucp/uudecode.c @@ -0,0 +1,175 @@ +#ifndef lint +static char sccsid[] = "@(#)uudecode.c 5.3 (Berkeley) 4/10/85"; +#endif + +/* + * uudecode [input] + * + * create the specified file, decoding as you go. + * used with uuencode. + */ +#include +#include +#include +#include +#include +#include +#include + +/* single character decode */ +#define DEC(c) (((c) - ' ') & 077) + +main(argc, argv) +char **argv; +{ + FILE *in, *out; + int mode; + char dest[128]; + char buf[80]; + + /* optional input arg */ + if (argc > 1) { + if ((in = fopen(argv[1], "r")) == NULL) { + perror(argv[1]); + exit(1); + } + argv++; argc--; + } else + in = stdin; + + if (argc != 1) { + printf("Usage: uudecode [infile]\n"); + exit(2); + } + + /* search for header line */ + for (;;) { + if (fgets(buf, sizeof buf, in) == NULL) { + fprintf(stderr, "No begin line\n"); + exit(3); + } + if (strncmp(buf, "begin ", 6) == 0) + break; + } + sscanf(buf, "begin %o %s", &mode, dest); + + /* handle ~user/file format */ + if (dest[0] == '~') { + char *sl; + struct passwd *getpwnam(); + char *index(); + struct passwd *user; + char dnbuf[100]; + + sl = index(dest, '/'); + if (sl == NULL) { + fprintf(stderr, "Illegal ~user\n"); + exit(3); + } + *sl++ = 0; + user = getpwnam(dest+1); + if (user == NULL) { + fprintf(stderr, "No such user as %s\n", dest); + exit(4); + } + strcpy(dnbuf, user->pw_dir); + strcat(dnbuf, "/"); + strcat(dnbuf, sl); + strcpy(dest, dnbuf); + } + + /* create output file */ + out = fopen(dest, "w"); + if (out == NULL) { + perror(dest); + exit(4); + } + chmod(dest, mode); + + decode(in, out); + + if (fgets(buf, sizeof buf, in) == NULL || strcmp(buf, "end\n")) { + fprintf(stderr, "No end line\n"); + exit(5); + } + exit(0); +} + +/* + * copy from in to out, decoding as you go along. + */ +decode(in, out) +FILE *in; +FILE *out; +{ + char buf[80]; + char *bp; + int n; + + for (;;) { + /* for each input line */ + if (fgets(buf, sizeof buf, in) == NULL) { + printf("Short file\n"); + exit(10); + } + n = DEC(buf[0]); + if (n <= 0) + break; + + bp = &buf[1]; + while (n > 0) { + outdec(bp, out, n); + bp += 4; + n -= 3; + } + } +} + +/* + * output a group of 3 bytes (4 input characters). + * the input chars are pointed to by p, they are to + * be output to file f. n is used to tell us not to + * output all of them at the end of the file. + */ +outdec(p, f, n) +char *p; +FILE *f; +{ + int c1, c2, c3; + + c1 = DEC(*p) << 2 | DEC(p[1]) >> 4; + c2 = DEC(p[1]) << 4 | DEC(p[2]) >> 2; + c3 = DEC(p[2]) << 6 | DEC(p[3]); + if (n >= 1) + putc(c1, f); + if (n >= 2) + putc(c2, f); + if (n >= 3) + putc(c3, f); +} + + +/* fr: like read but stdio */ +int +fr(fd, buf, cnt) +FILE *fd; +char *buf; +int cnt; +{ + int c, i; + + for (i=0; i +#include +#include +#include + +/* ENC is the basic 1 character encoding function to make a char printing */ +#define ENC(c) ((c) ? ((c) & 077) + ' ': '`') + +main(argc, argv) +char **argv; +{ + FILE *in; + struct stat sbuf; + int mode; + + /* optional 1st argument */ + if (argc > 2) { + if ((in = fopen(argv[1], "r")) == NULL) { + perror(argv[1]); + exit(1); + } + argv++; argc--; + } else + in = stdin; + + if (argc != 2) { + printf("Usage: uuencode [infile] remotefile\n"); + exit(2); + } + + /* figure out the input file mode */ + fstat(fileno(in), &sbuf); + mode = sbuf.st_mode & 0777; + printf("begin %o %s\n", mode, argv[1]); + + encode(in, stdout); + + printf("end\n"); + exit(0); +} + +/* + * copy from in to out, encoding as you go along. + */ +encode(in, out) +FILE *in; +FILE *out; +{ + char buf[80]; + int i, n; + + for (;;) { + /* 1 (up to) 45 character line */ + n = fr(in, buf, 45); + putc(ENC(n), out); + + for (i=0; i> 2; + c2 = (*p << 4) & 060 | (p[1] >> 4) & 017; + c3 = (p[1] << 2) & 074 | (p[2] >> 6) & 03; + c4 = p[2] & 077; + putc(ENC(c1), f); + putc(ENC(c2), f); + putc(ENC(c3), f); + putc(ENC(c4), f); +} + +/* fr: like read but stdio */ +int +fr(fd, buf, cnt) +FILE *fd; +char *buf; +int cnt; +{ + int c, i; + + for (i=0; i1 && argv[1][0] == '-') { + switch (argv[1][1]) { + case 's': + sys = &argv[1][2]; + if (*sys == NULL && argc > 2 && argv[2][0] != '-') { + sys = &argv[2][0]; + argv++; + argc--; + } + if (strlen(sys) > MAXBASENAME) + sys[MAXBASENAME] = '\0'; + if (versys(&sys) != SUCCESS){ + fprintf(stderr,"uulog: unknown system %s\n", sys); + sys = NULL; + } + break; + case 'u': + user = &argv[1][2]; + if (*user == NULL && argc > 2 && argv[2][0] != '-') { + user = &argv[2][0]; + argv++; + argc--; + } + break; + default: + printf("unknown flag %s\n", argv[1]); break; + } + --argc; argv++; + } + + + if (user == NULL && sys == NULL) { + fprintf(stderr, "usage: uulog [-u user] [-s sys]\n"); + exit(1); + } + +#ifdef LOGBYSITE + if (chdir(SPOOL) < 0) { + perror(SPOOL); + exit(1); + } + /* this program is really obsolete, this is a rude backward compat */ + if (user) { + sprintf(buf, "exec cat LOG/uu*/* | egrep '^%s '", user); + system(buf); + } + if (sys) { + sprintf(buf,"exec cat LOG/uu*/%s", sys); + system(buf); + } +#else + plogf = fopen(LOGFILE, "r"); + ASSERT(plogf != NULL, "CAN NOT OPEN", LOGFILE, 0); + while (fgets(buf, BUFSIZ, plogf) != NULL) { + sscanf(buf, "%s%s", u, s); + if (user != NULL && !prefix(user, u)) + continue; + if (sys != NULL && !prefix(sys, s)) + continue; + fputs(buf, stdout); + fflush(stdout); + } +#endif + exit(0); +} + +cleanup(code) +int code; +{ + exit(code); +} diff --git a/src/cmd/uucp/uuname.c b/src/cmd/uucp/uuname.c new file mode 100644 index 0000000..bc74078 --- /dev/null +++ b/src/cmd/uucp/uuname.c @@ -0,0 +1,78 @@ +#ifndef lint +static char sccsid[] = "@(#)uuname.c 5.3 (Berkeley) 10/9/85"; +#endif + +#include "uucp.h" +#include + +/* + * return list of all remote systems + * recognized by uucp, or (with -l) the local uucp name. + * + * return codes: 0 | 1 (can't read) + */ + +struct timeb Now; + +main(argc,argv) +char *argv[]; +int argc; +{ + int ret; + int i; + int intrEXIT(); + FILE *np; +/* Increase buffers for s and prev. cornell!pavel */ + char prev[1000]; + char s[1000]; + + ret = chdir(Spool); + ASSERT(ret >= 0, "CHDIR FAILED", Spool, ret); + strcpy(Progname, "uuname"); + signal(SIGILL, (sig_t)intrEXIT); + signal(SIGTRAP, (sig_t)intrEXIT); + signal(SIGIOT, (sig_t)intrEXIT); + signal(SIGEMT, (sig_t)intrEXIT); + signal(SIGFPE, (sig_t)intrEXIT); + signal(SIGBUS, (sig_t)intrEXIT); + signal(SIGSEGV, (sig_t)intrEXIT); + signal(SIGSYS, (sig_t)intrEXIT); + signal(SIGINT, (sig_t)intrEXIT); + signal(SIGHUP, (sig_t)intrEXIT); + signal(SIGQUIT, (sig_t)intrEXIT); + signal(SIGTERM, (sig_t)intrEXIT); + + if(argc > 1 && argv[1][0] == '-' && argv[1][1] == 'l') { + uucpname(s); + printf("%s\n",s); + exit(0); + } + if(argc != 1) {printf("Usage: uuname [-l]\n"); exit(1);} + if((np = fopen(SYSFILE,"r")) == NULL) { + printf("%s (name file) protected\n",SYSFILE); + exit(1); + } + while ( cfgets(s,sizeof(s),np) != NULL ) { + for(i=0; s[i]!=' ' && s[i]!='\t'; i++) + ; + s[i]='\0'; + if (strcmp(s, prev) == SAME) + continue; + if(s[0]=='x' && s[1]=='x' && s[2]=='x') + continue; + printf("%s\n",s); + strcpy(prev, s); + } + + exit(0); +} +intrEXIT(inter) +{ + exit(inter); +} + +cleanup(code) +int code; +{ + exit(code); +} diff --git a/src/cmd/uucp/uupoll.c b/src/cmd/uucp/uupoll.c new file mode 100644 index 0000000..d2132b4 --- /dev/null +++ b/src/cmd/uucp/uupoll.c @@ -0,0 +1,79 @@ +#ifndef lint +static char sccsid[] = "@(#)uupoll.c 5.5 (Berkeley) 10/9/85"; +#endif + +/* + * 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). + * + * AUTHOR + * Tom Truscott (rti!trt) + */ + +#include "uucp.h" + +int TransferSucceeded = 1; +struct timeb Now; + +main(argc, argv) +register int argc; +register char **argv; +{ + int ret; + char wrkpre[MAXFULLNAME]; + char file[MAXFULLNAME]; + char grade = 'A'; + int nocall = 0; + + if (argc < 2) { + fprintf(stderr, "usage: uupoll [-gX] [-n] system ...\n"); + cleanup(1); + } + + ret = chdir(Spool); + ASSERT(ret >= 0, "CHDIR FAILED", Spool, ret); + strcpy(Progname, "uupoll"); + uucpname(Myname); + + for (--argc, ++argv; argc > 0; --argc, ++argv) { + if (strcmp(argv[0], Myname) == SAME) { + fprintf(stderr, "This *is* %s!\n", Myname); + continue; + } + if (strncmp(argv[0],"-g",2) == SAME) { + grade = argv[0][2]; + continue; + } + if (strcmp(argv[0],"-n") == SAME) { + nocall++; + continue; + } + + if (versys(&argv[0])) { + fprintf(stderr, "%s: unknown system.\n", argv[0]); + continue; + } + /* Remove any STST file that might stop the poll */ + sprintf(wrkpre, "%s/LCK..%.*s", LOCKDIR, MAXBASENAME, argv[0]); + if (access(wrkpre, 0) < 0) + rmstat(argv[0]); + sprintf(wrkpre, "%c.%.*s", CMDPRE, SYSNSIZE, argv[0]); + if (!iswrk(file, "chk", Spool, wrkpre)) { + sprintf(file, "%s/%c.%.*s%cPOLL", subdir(Spool, CMDPRE), + CMDPRE, SYSNSIZE, argv[0], grade); + close(creat(file, 0666)); + } + /* Attempt the call */ + if (!nocall) + xuucico(argv[0]); + } + cleanup(0); +} + +cleanup(code) +int code; +{ + exit(code); +} diff --git a/src/cmd/uucp/uuq.c b/src/cmd/uucp/uuq.c new file mode 100644 index 0000000..6f62df6 --- /dev/null +++ b/src/cmd/uucp/uuq.c @@ -0,0 +1,379 @@ +#if !defined(lint) && defined(DOSCCS) +static char sccsid[] = "@(#)uuq.c 4.6.1 (2.11BSD) 1997/10/2"; +#endif + +/* + * uuq - looks at uucp queues + * + * Lou Salkind + * New York University + * + */ + +#include "uucp.h" +#include +#include + +#ifdef NDIR +#include "libndir/ndir.h" +#else +#include +#endif +#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; + +float baudrate = 1200.; +char Username[BUFSIZ]; +char Filename[BUFSIZ]; +int Maxulen = 0; +struct timeb Now; + +main(argc, argv) +char **argv; +{ + register i; + register struct sys *sp; + register struct job *jp; + struct job **sortjob; + int nsys; + + strcpy(Progname, "uuq"); + uucpname(Myname); + + while (--argc > 0) { + argv++; + if (argv[0][0] == '-') switch (argv[0][1]) { + case 'r': + Spool = &argv[0][2]; + break; + case 's': + sysname = &argv[0][2]; + if (strlen(sysname) > SYSNSIZE) + sysname[SYSNSIZE] = '\0'; + break; + case 'u': + user = &argv[0][2]; + break; + case 'd': + rmjob = &argv[0][2]; + break; + case 'b': + baudrate = atof(&argv[0][2]); + 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 *= 6.; /* convert to chars/minute (60/10) */ + 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 %ld)", + minutes,(long)(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.%szPOLL", subdir(Spool, CMDPRE), CMDPRE,sp->s_name); + 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"); + 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 + */ +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) { + 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/src/cmd/uucp/uusend.c b/src/cmd/uucp/uusend.c new file mode 100644 index 0000000..012b999 --- /dev/null +++ b/src/cmd/uucp/uusend.c @@ -0,0 +1,357 @@ +#if !defined(lint) && defined(DOSCCS) +static char sccsid[] = "@(#)uusend.c 5.2.1 (2.11BSD) 1996/10/24"; +#endif + +/* + * 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 /etc/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 +#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 +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 = "/etc/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 +char *f = ""; /* so we waste a little space */ +#endif + +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 + 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 + 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 + sprintf(cmdbuf, "uux -gn -z %s- \"%s!uusend %s -m %o - (%s)\"", +#endif + rflg, nextsys, f, mode, destname); +#ifdef DEBUG + fprintf(dout, "remote: nextsys='%s', destname='%s', cmd='%s'\n", nextsys, destname, cmdbuf); +#endif + out = popen(cmdbuf, "w"); + } else { + /* + * destname is local. + */ + if (destname[0] == '~') { +#ifdef DEBUG + fprintf(dout, "before ~: '%s'\n", destname); +fflush(dout); +#endif + 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 + if (sl == NULL) { + fprintf(stderr, "Illegal ~user\n"); + exit(3); + } + *sl++ = 0; +#endif + 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 + exit(4); + } + strcpy(dnbuf, user->pw_dir); + strcat(dnbuf, "/"); + strcat(dnbuf, sl); +#endif + destname = dnbuf; + } +#ifdef RECOVER + else + destname = strcpy(dnbuf, destname); +#endif + 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 + out = fopen(destname, "w"); +#ifdef DEBUG + fprintf(dout, "local, file='%s'\n", destname); +#endif + 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 + exit(5); +#endif + } + 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 + + 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 + +#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 +#endif diff --git a/src/cmd/uucp/uusnap.c b/src/cmd/uucp/uusnap.c new file mode 100644 index 0000000..ca7318c --- /dev/null +++ b/src/cmd/uucp/uusnap.c @@ -0,0 +1,285 @@ +#ifndef lint +static char sccsid[] = "@(#)uusnap.c 5.7 (Berkeley) 10/9/85"; +#endif + +/* + * Uusnap - displays a snapshot of the uucp system. + * originally by RJKing WECo-MG6565 May 83 + */ + +#include "uucp.h" +#include +#include +#ifdef NDIR +#include "ndir.h" +#else +#include +#endif +#include + +#ifndef SYSBUF +char SYSBUF[BUFSIZ]; +#endif + +#define NSYSTEM 100 /* 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; + + setbuf(stdout, SYSBUF); + scandir(CMDSDIR, "C.", CMDSLEN, NULL, CMDTYPE); + scandir(DATADIR, "D.", DATALEN, NULL, DATTYPE); + scandir(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 == NULL || 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); +} + +scandir(dnam, prfx, flen, fchr, type) +char *dnam, *prfx, fchr; +{ + 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) { + char c; + fnamlen -= flen; + c = fnam[fnamlen]; + if (islower(c)) + c = toupper(c); + if (type == DATTYPE && (c != 'S' && c != 'B')) { + fnamlen -= 2; /* For Honey DanBer */ + fnam[fnamlen] = NULL; + } else { + fnam[fnamlen] = NULL; + fnamlen = MAXBASENAME; /* yes, after = NULL*/ + } + } else { + for(; fnamlen>0; --fnamlen) { + if(fnam[fnamlen] == fchr) { + fnam[fnamlen] = NULL; + break; + } + } + fnamlen = MAXBASENAME; + } + for(i=0; id_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 + +#define NOSYSPART 0 +#define HASSYSPART 1 + +#define LQUOTE '(' +#define RQUOTE ')' + +#define APPCMD(d) {\ +register char *p; for (p = d; *p != '\0';)\ + {*cmdp++ = *p++;\ + if(cmdp>(sizeof(cmd)+&cmd[0])){\ + fprintf(stderr,"argument list too long\n");\ + cleanup(EX_SOFTWARE);\ + }\ + }\ + *cmdp++ = ' '; *cmdp = '\0';} + +#define GENSEND(f, a, b, c, d, e) {\ + fprintf(f, "S %s %s %s -%s %s 0666\n", a, b, c, d, e); } +#define GENRCV(f, a, b, c) {fprintf(f, "R %s %s %s - \n", a, b, c);} + +struct timeb Now; + +main(argc, argv) +char *argv[]; +{ + char cfile[NAMESIZE]; /* send commands for files from here */ + char dfile[NAMESIZE]; /* used for all data files from here */ + char rxfile[NAMESIZE]; /* to be sent to xqt file (X. ...) */ + char tfile[NAMESIZE]; /* temporary file name */ + char tcfile[NAMESIZE]; /* temporary file name */ + char t2file[NAMESIZE]; /* temporary file name */ + int cflag = 0; /* commands in C. file flag */ + int rflag = 0; /* C. files for receiving flag */ +#ifdef DONTCOPY + int Copy = 0; /* Don't Copy spool files */ +#else + int Copy = 1; /* Copy spool files */ +#endif + int Linkit = 0; /* Try link before copy */ + char buf[2*BUFSIZ]; + char inargs[2*BUFSIZ]; + int pipein = 0; + int startjob = 1; + char Grade = 'A'; + char path[MAXFULLNAME]; + char cmd[2*BUFSIZ]; + char *ap, *cmdp; + char prm[2*BUFSIZ]; + char syspart[MAXBASENAME+1], rest[MAXFULLNAME]; + char Xsys[MAXBASENAME+1], local[MAXBASENAME+1]; + char *xsys = Xsys; + FILE *fprx, *fpc, *fpd, *fp; + extern char *getprm(), *lastpart(); + extern FILE *ufopen(); + int uid, ret; + char redir = '\0'; + int nonoti = 0; + int nonzero = 0; + int link_failed; + char *ReturnTo = NULL; + extern int LocalOnly; + + strcpy(Progname, "uux"); + uucpname(Myname); + umask(WFMASK); + Ofn = 1; + Ifn = 0; +#ifdef VMS + arg_fix(argc, argv); +#endif + while (argc>1 && argv[1][0] == '-') { + switch(argv[1][1]){ + case 'p': + case '\0': + pipein = 1; + break; + case 'r': + startjob = 0; + break; + case 'c': + Copy = 0; + Linkit = 0; + break; + case 'l': + Copy = 0; + Linkit = 1; + break; + case 'C': + Copy = 1; + Linkit = 0; + break; + case 'g': + Grade = argv[1][2]; + break; + case 'x': + chkdebug(); + Debug = atoi(&argv[1][2]); + if (Debug <= 0) + Debug = 1; + break; + case 'n': + nonoti = 1; + break; + case 'z': + nonzero = 1; + break; + case 'L': + LocalOnly++; + break; + case 'a': + ReturnTo = &argv[1][2]; + if (prefix(Myname, ReturnTo) && ReturnTo[strlen(Myname)] == '!') + ReturnTo = index(ReturnTo, '!') + 1; + break; + default: + fprintf(stderr, "unknown flag %s\n", argv[1]); + break; + } + --argc; argv++; + } + ap = getwd(Wrkdir); + if (ap == 0) { + fprintf(stderr, "can't get working directory; will try to continue\n"); + strcpy(Wrkdir, "/UNKNOWN"); + } + + DEBUG(4, "\n\n** %s **\n", "START"); + + inargs[0] = '\0'; + for (argv++; argc > 1; argc--) { + DEBUG(4, "arg - %s:", *argv); + strcat(inargs, " "); + strcat(inargs, *argv++); + } + DEBUG(4, "arg - %s\n", inargs); + ret = subchdir(Spool); + ASSERT(ret >= 0, "CHDIR FAILED", Spool, ret); + uid = getuid(); + guinfo(uid, User, path); + + strncpy(local, Myname, MAXBASENAME); + cmdp = cmd; + *cmdp = '\0'; + gename(DATAPRE, local, 'X', rxfile); + fprx = ufopen(rxfile, "w"); + ASSERT(fprx != NULL, "CAN'T OPEN", rxfile, 0); + gename(DATAPRE, local, 'T', tcfile); + fpc = ufopen(tcfile, "w"); + ASSERT(fpc != NULL, "CAN'T OPEN", tcfile, 0); + fprintf(fprx, "%c %s %s\n", X_USER, User, local); + if (nonoti) + fprintf(fprx, "%c\n", X_NONOTI); + if (nonzero) + fprintf(fprx, "%c\n", X_NONZERO); + if (ReturnTo == NULL || *ReturnTo == '\0') + ReturnTo = User; + fprintf(fprx, "%c %s\n", X_RETURNTO, ReturnTo); + + /* find remote system name */ + ap = inargs; + xsys[0] = '\0'; + while ((ap = getprm(ap, prm)) != NULL) { + if (prm[0] == '>' || prm[0] == '<') { + ap = getprm(ap, prm); + continue; + } + + split(prm, xsys, rest); + break; + } + if (xsys[0] == '\0') + strcpy(xsys, local); + if (versys(&xsys) != 0) { + /* bad system name */ + fprintf(stderr, "bad system name: %s\n", xsys); + fclose(fprx); + fclose(fpc); + cleanup(EX_NOHOST); + } + + strncpy(Rmtname, xsys, MAXBASENAME); + DEBUG(4, "xsys %s\n", xsys); + + if (pipein) { + gename(DATAPRE, local, 'B', dfile); + fpd = ufopen(dfile, "w"); + ASSERT(fpd != NULL, "CAN'T OPEN", dfile, 0); + while (!feof(stdin)) { + ret = fread(buf, 1, BUFSIZ, stdin); + fwrite(buf, 1, ret, fpd); + if (ferror(stdin)) { + perror("stdin"); + cleanup(EX_IOERR); + } + if (ferror(fpd)) { + perror(dfile); + cleanup(EX_IOERR); + } + } + fclose(fpd); + strcpy(tfile, dfile); + if (strcmp(local, xsys) != SAME) { + register int Len = strlen(local); + if (Len > SYSNSIZE) + Len = SYSNSIZE; + tfile[Len + 2] = 'S'; + GENSEND(fpc, dfile, tfile, User, "", dfile); + cflag++; + } + fprintf(fprx, "%c %s\n", X_RQDFILE, tfile); + fprintf(fprx, "%c %s\n", X_STDIN, tfile); + } + /* parse command */ + ap = inargs; + while ((ap = getprm(ap, prm)) != NULL) { + DEBUG(4, "prm - %s\n", prm); + if (prm[0] == '>' || prm[0] == '<') { + redir = prm[0]; + continue; + } + + if (prm[0] == ';') { + APPCMD(prm); + continue; + } + + if (prm[0] == '|' || prm[0] == '^') { + if (cmdp != cmd) + APPCMD(prm); + continue; + } + + /* process command or file or option */ + ret = split(prm, syspart, rest); + DEBUG(4, "s - %s, ", syspart); + DEBUG(4, "r - %s, ", rest); + DEBUG(4, "ret - %d\n", ret); + if (syspart[0] == '\0') + strcpy(syspart, local); + + if (cmdp == cmd && redir == '\0') { + /* command */ + APPCMD(rest); + continue; + } + + /* process file or option */ + DEBUG(4, "file s- %s, ", syspart); + DEBUG(4, "local - %s\n", local); + /* process file */ + if (redir == '>') { + if (rest[0] != '~') + if (ckexpf(rest)) + cleanup(EX_CANTCREAT); + fprintf(fprx, "%c %s %s\n", X_STDOUT, rest, + syspart); + redir = '\0'; + continue; + } + + if (ret == NOSYSPART && redir == '\0') { + /* option */ + APPCMD(rest); + continue; + } + + if (strcmp(xsys, local) == SAME + && strcmp(xsys, syspart) == SAME) { + if (ckexpf(rest)) + cleanup(EX_CANTCREAT); + if (redir == '<') + fprintf(fprx, "%c %s\n", X_STDIN, rest); + else + APPCMD(rest); + redir = '\0'; + continue; + } + + if (strcmp(syspart, local) == SAME) { + /* generate send file */ + if (ckexpf(rest)) + cleanup(EX_CANTCREAT); + gename(DATAPRE, local, 'A', dfile); + DEBUG(4, "rest %s\n", rest); + if ((chkpth(User, "", rest) || anyread(rest)) != 0) { + fprintf(stderr, "permission denied %s\n", rest); + cleanup(EX_NOINPUT); + } + link_failed = 0; + if (Linkit) { + if (link(subfile(rest), subfile(dfile)) != 0) + link_failed++; + else + GENSEND(fpc, rest, dfile, User, "", dfile); + } + if (Copy || link_failed) { + if (xcp(rest, dfile) != 0) { + fprintf(stderr, "can't copy %s to %s\n", rest, dfile); + cleanup(EX_NOINPUT); + } + GENSEND(fpc, rest, dfile, User, "", dfile); + } + if (!Copy && !Linkit) { + GENSEND(fpc, rest, dfile, User, "c", "D.0"); + } + cflag++; + if (redir == '<') { + fprintf(fprx, "%c %s\n", X_STDIN, dfile); + fprintf(fprx, "%c %s\n", X_RQDFILE, dfile); + } else { + APPCMD(lastpart(rest)); + fprintf(fprx, "%c %s %s\n", X_RQDFILE, + dfile, lastpart(rest)); + } + redir = '\0'; + continue; + } + + if (strcmp(local, xsys) == SAME) { + /* generate local receive */ + gename(CMDPRE, syspart, 'R', tfile); + strcpy(dfile, tfile); + dfile[0] = DATAPRE; + fp = ufopen(tfile, "w"); + ASSERT(fp != NULL, "CAN'T OPEN", tfile, 0); + if (ckexpf(rest)) + cleanup(EX_CANTCREAT); + GENRCV(fp, rest, dfile, User); + fclose(fp); + rflag++; + if (rest[0] != '~') + if (ckexpf(rest)) + cleanup(EX_CANTCREAT); + if (redir == '<') { + fprintf(fprx, "%c %s\n", X_RQDFILE, dfile); + fprintf(fprx, "%c %s\n", X_STDIN, dfile); + } else { + fprintf(fprx, "%c %s %s\n", X_RQDFILE, dfile, + lastpart(rest)); + APPCMD(lastpart(rest)); + } + + redir = '\0'; + continue; + } + + if (strcmp(syspart, xsys) != SAME) { + /* generate remote receives */ + gename(DATAPRE, syspart, 'R', dfile); + strcpy(tfile, dfile); + tfile[0] = CMDPRE; + fpd = ufopen(dfile, "w"); + ASSERT(fpd != NULL, "CAN'T OPEN", dfile, 0); + gename(DATAPRE, local, 'T', t2file); + GENRCV(fpd, rest, t2file, User); + fclose(fpd); + GENSEND(fpc, dfile, tfile, User, "", dfile); + cflag++; + if (redir == '<') { + fprintf(fprx, "%c %s\n", X_RQDFILE, t2file); + fprintf(fprx, "%c %s\n", X_STDIN, t2file); + } else { + fprintf(fprx, "%c %s %s\n", X_RQDFILE, t2file, + lastpart(rest)); + APPCMD(lastpart(rest)); + } + redir = '\0'; + continue; + } + + /* file on remote system */ + if (rest[0] != '~') + if (ckexpf(rest)) + cleanup(EX_CANTCREAT); + if (redir == '<') + fprintf(fprx, "%c %s\n", X_STDIN, rest); + else + APPCMD(rest); + redir = '\0'; + continue; + + } + /* + * clean up trailing ' ' in command. + */ + if (cmdp > cmd && cmdp[0] == '\0' && cmdp[-1] == ' ') + *--cmdp = '\0'; + /* block multi-hop uux, which doesn't work */ + for (ap = cmd; *ap && *ap != ' '; ap++) + if (*ap == '!') { + fprintf(stderr, "uux handles only adjacent sites.\n"); + fprintf(stderr, "Try uusend for multi-hop delivery.\n"); + cleanup(EX_USAGE); + } + + fprintf(fprx, "%c %s\n", X_CMD, cmd); + if (ferror(fprx)) { + logent(cmd, "COULD NOT QUEUE XQT"); + cleanup(EX_IOERR); + } else + logent(cmd, "XQT QUE'D"); + fclose(fprx); + + gename(XQTPRE, local, Grade, tfile); + if (strcmp(xsys, local) == SAME) { + /* rti!trt: xmv() works across filesystems, link(II) doesnt */ + xmv(rxfile, tfile); + if (startjob) + if (rflag) + xuucico(xsys); + else + xuuxqt(); + } + else { + GENSEND(fpc, rxfile, tfile, User, "", rxfile); + cflag++; + } + + if (ferror(fpc)) + cleanup(EX_IOERR); + fclose(fpc); + if (cflag) { + gename(CMDPRE, xsys, Grade, cfile); + /* rti!trt: use xmv() rather than link(II) */ + xmv(tcfile, cfile); + if (startjob) + xuucico(xsys); + cleanup(0); + } + else + unlink(subfile(tcfile)); + exit(0); +} + +#define FTABSIZE 30 +char Fname[FTABSIZE][NAMESIZE]; +int Fnamect = 0; + +/* + * cleanup and unlink if error + * + * return - none - do exit() + */ + +cleanup(code) +int code; +{ + int i; + + logcls(); + rmlock(CNULL); + if (code) { + for (i = 0; i < Fnamect; i++) + unlink(subfile(Fname[i])); + fprintf(stderr, "uux failed. code %d\n", code); + } + DEBUG(1, "exit code %d\n", code); + exit(code); +} + +/* + * open file and record name + * + * return file pointer. + */ + +FILE *ufopen(file, mode) +char *file, *mode; +{ + if (Fnamect < FTABSIZE) + strcpy(Fname[Fnamect++], file); + else + logent("Fname", "TABLE OVERFLOW"); + return fopen(subfile(file), mode); +} +#ifdef VMS +/* + * EUNICE bug: + * quotes are not stripped from DCL. Do it here. + * Note if we are running under Unix shell we don't + * do the right thing. + */ +arg_fix(argc, argv) +char **argv; +{ + register char *cp, *tp; + + for (; argc > 0; --argc, argv++) { + cp = *argv; + if (cp == (char *)0 || *cp++ != '"') + continue; + tp = cp; + while (*tp++) ; + tp -= 2; + if (*tp == '"') { + *tp = '\0'; + *argv = cp; + } + } +} +#endif + +/* + * split into system and file part + * + * return codes: + * NOSYSPART + * HASSYSPART + */ + +split(name, sys, rest) +register char *name, *rest; +char *sys; +{ + register char *c; + register int i; + + if (*name == LQUOTE) { + if ((c = index(name + 1, RQUOTE)) != NULL) { + /* strip off quotes */ + name++; + while (c != name) + *rest++ = *name++; + *rest = '\0'; + *sys = '\0'; + return NOSYSPART; + } + } + + if ((c = index(name, '!')) == NULL) { + strcpy(rest, name); + *sys = '\0'; + return NOSYSPART; + } + + *c++ = '\0'; + strncpy(sys, name, MAXBASENAME); + sys[MAXBASENAME] = '\0'; + + strcpy(rest, c); + return HASSYSPART; +} diff --git a/src/cmd/uucp/uuxqt.c b/src/cmd/uucp/uuxqt.c new file mode 100644 index 0000000..35fc510 --- /dev/null +++ b/src/cmd/uucp/uuxqt.c @@ -0,0 +1,718 @@ +#if !defined(lint) && defined(DOSCCS) +static char sccsid[] = "@(#)uuxqt.c 5.8.1 (2.11BSD) 1997/10/2"; +#endif + +#include "uucp.h" +#include +#include +#ifdef NDIR +#include "ndir.h" +#else +#include +#endif +#include + +#define BADCHARS "&^|(`\\<>;\"{}\n'" +#define RECHECKTIME 60*10 /* 10 minutes */ + +#define APPCMD(d) {\ +char *p;\ +for (p = d; *p != '\0';) *cmdp++ = *p++; *cmdp++ = ' '; *cmdp = '\0';} + +/* + * uuxqt will execute commands set up by a uux command, + * usually from a remote machine - set by uucp. + */ + +#define NCMDS 50 +char *Cmds[NCMDS+1]; +int Notify[NCMDS+1]; +#define NT_YES 0 /* if should notify on execution */ +#define NT_ERR 1 /* if should notify if non-zero exit status (-z equivalent) */ +#define NT_NO 2 /* if should not notify ever (-n equivalent) */ + +extern int Nfiles; + +int TransferSucceeded = 1; +int notiok = 1; +int nonzero = 0; + +struct timeb Now; + +char PATH[MAXFULLNAME] = "PATH=/bin:/usr/bin:/usr/ucb"; +char Shell[MAXFULLNAME]; +char HOME[MAXFULLNAME]; + +extern char **environ; +char *nenv[] = { + PATH, + Shell, + HOME, + 0 +}; + +/* to remove restrictions from uuxqt + * define ALLOK 1 + * + * to add allowable commands, add to the file CMDFILE + * A line of form "PATH=..." changes the search path + */ +main(argc, argv) +char *argv[]; +{ + char xcmd[MAXFULLNAME]; + int argnok; + int notiflg; + char xfile[MAXFULLNAME], user[MAXFULLNAME], buf[BUFSIZ]; + char lbuf[MAXFULLNAME]; + char cfile[NAMESIZE], dfile[MAXFULLNAME]; + char file[NAMESIZE]; + char fin[MAXFULLNAME], sysout[NAMESIZE], fout[MAXFULLNAME]; + register FILE *xfp, *fp; + FILE *dfp; + char path[MAXFULLNAME]; + char cmd[BUFSIZ]; + char *cmdp, prm[1000], *ptr; + char *getprm(), *lastpart(); + int uid, ret, ret2, badfiles; + register int i; + int stcico = 0; + time_t xstart, xnow; + char retstat[30]; + char **ep; + + strcpy(Progname, "uuxqt"); + uucpname(Myname); + + umask(WFMASK); + Ofn = 1; + Ifn = 0; + while (argc>1 && argv[1][0] == '-') { + switch(argv[1][1]){ + case 'x': + chkdebug(); + Debug = atoi(&argv[1][2]); + if (Debug <= 0) + Debug = 1; + break; + default: + fprintf(stderr, "unknown flag %s\n", argv[1]); + break; + } + --argc; argv++; + } + + DEBUG(4, "\n\n** START **\n", CNULL); + ret = subchdir(Spool); + ASSERT(ret >= 0, "CHDIR FAILED", Spool, ret); + strcpy(Wrkdir, Spool); + uid = getuid(); + guinfo(uid, User, path); + setgid(getegid()); + setuid(geteuid()); + + DEBUG(4, "User - %s\n", User); + if (ulockf(X_LOCK, X_LOCKTIME) != 0) + exit(0); + + fp = fopen(CMDFILE, "r"); + if (fp == NULL) { + logent(CANTOPEN, CMDFILE); + Cmds[0] = "rmail"; + Cmds[1] = "rnews"; + Cmds[2] = "ruusend"; + Cmds[3] = NULL; + goto doprocess; + } + DEBUG(5, "%s opened\n", CMDFILE); + for (i=0; i= 0; --j) + if (xcmd[j] == '\n' || xcmd[j] == ' ' || xcmd[j] == '\t') + xcmd[j] = '\0'; + else + break; + /* look for imbedded whitespace */ + for (; j >= 0; --j) + if (xcmd[j] == '\n' || xcmd[j] == ' ' || xcmd[j] == '\t') + break; + /* skip this entry if it has embedded whitespace */ + /* This defends against a bad PATH=, for example */ + if (j >= 0) { + logent(xcmd, "BAD WHITESPACE"); + continue; + } + if (strncmp(xcmd, "PATH=", 5) == 0) { + strcpy(PATH, xcmd); + i--; /*kludge */ + continue; + } + DEBUG(5, "xcmd = %s\n", xcmd); + + if ((ptr = index(xcmd, ',')) != NULL) { + *ptr++ = '\0'; + if (strncmp(ptr, "Err", 3) == SAME) + Notify[i] = NT_ERR; + else if (strcmp(ptr, "No") == SAME) + Notify[i] = NT_NO; + else + Notify[i] = NT_YES; + } else + Notify[i] = NT_YES; + if ((Cmds[i] = (char *)malloc((unsigned)(strlen(xcmd)+1))) == NULL) { + DEBUG(1, "MALLOC FAILED", CNULL); + break; + } + strcpy(Cmds[i], xcmd); + } + Cmds[i] = CNULL; + fclose(fp); + +doprocess: + + (void) sprintf(HOME, "HOME=%s", Spool); + (void) sprintf(Shell, "SHELL=%s", SHELL); + environ = nenv; /* force use if our environment */ + + DEBUG(11,"path = %s\n", getenv("PATH")); + + DEBUG(4, "process %s\n", CNULL); + time(&xstart); + while (gtxfile(xfile) > 0) { + /* if /etc/nologin exists, exit cleanly */ +#if defined(BSD4_2) || defined(USG) + if (access(NOLOGIN) == 0) { +#else + ultouch(); + if (nologinflag) { +#endif + logent(NOLOGIN, "UUXQT SHUTDOWN"); + if (Debug) + logent("debugging", "continuing anyway"); + else + break; + } + DEBUG(4, "xfile - %s\n", xfile); + + xfp = fopen(subfile(xfile), "r"); + ASSERT(xfp != NULL, CANTOPEN, xfile, 0); + + /* initialize to default */ + strcpy(user, User); + strcpy(fin, DEVNULL); + strcpy(fout, DEVNULL); + strcpy(sysout, Myname); + badfiles = 0; + while (fgets(buf, BUFSIZ, xfp) != NULL) { + switch (buf[0]) { + case X_USER: + sscanf(&buf[1], "%s %s", user, Rmtname); + break; + case X_RETURNTO: + sscanf(&buf[1], "%s", user); + break; + case X_STDIN: + sscanf(&buf[1], "%s", fin); + i = expfile(fin); + /* rti!trt: do not check permissions of + * vanilla spool file */ + if (i != 0 + && (chkpth("", "", fin) || anyread(fin) != 0)) + badfiles = 1; + break; + case X_STDOUT: + sscanf(&buf[1], "%s%s", fout, sysout); + sysout[MAXBASENAME] = '\0'; + /* rti!trt: do not check permissions of + * vanilla spool file. DO check permissions + * of writing on a non-vanilla file */ + i = 1; + if (fout[0] != '~' || prefix(sysout, Myname)) + i = expfile(fout); + if (i != 0 + && (chkpth("", "", fout) + || chkperm(fout, (char *)1))) + badfiles = 1; + break; + case X_CMD: + strcpy(cmd, &buf[2]); + if (*(cmd + strlen(cmd) - 1) == '\n') + *(cmd + strlen(cmd) - 1) = '\0'; + break; + case X_NONOTI: + notiok = 0; + break; + case X_NONZERO: + nonzero = 1; + break; + default: + break; + } + } + + fclose(xfp); + DEBUG(4, "fin - %s, ", fin); + DEBUG(4, "fout - %s, ", fout); + DEBUG(4, "sysout - %s, ", sysout); + DEBUG(4, "user - %s\n", user); + DEBUG(4, "cmd - %s\n", cmd); + + /* command execution */ + if (strcmp(fout, DEVNULL) == SAME) + strcpy(dfile,DEVNULL); + else + gename(DATAPRE, sysout, 'O', dfile); + + /* expand file names where necessary */ + expfile(dfile); + cmdp = buf; + ptr = cmd; + xcmd[0] = '\0'; + argnok = 0; + while ((ptr = getprm(ptr, prm)) != NULL) { + if (prm[0] == ';' || prm[0] == '^' + || prm[0] == '&' || prm[0] == '|') { + xcmd[0] = '\0'; + APPCMD(prm); + continue; + } + + if ((argnok = argok(xcmd, prm)) != SUCCESS) + /* command not valid */ + break; + + if (prm[0] == '~') + expfile(prm); + APPCMD(prm); + } + /* + * clean up trailing ' ' in command. + */ + if (cmdp > buf && cmdp[0] == '\0' && cmdp[-1] == ' ') + *--cmdp = '\0'; + if (argnok || badfiles) { + sprintf(lbuf, "%s XQT DENIED", user); + logent(cmd, lbuf); + DEBUG(4, "bad command %s\n", prm); + notify(user, Rmtname, cmd, "DENIED"); + goto rmfiles; + } + sprintf(lbuf, "%s XQT", user); + logent(buf, lbuf); + DEBUG(4, "cmd %s\n", buf); + + mvxfiles(xfile); + ret = subchdir(XQTDIR); + ASSERT(ret >= 0, "CHDIR FAILED", XQTDIR, ret); + ret = shio(buf, fin, dfile); + sprintf(retstat, "signal %d, exit %d", ret & 0377, + (ret>>8) & 0377); + if (strcmp(xcmd, "rmail") == SAME) + notiok = 0; + if (strcmp(xcmd, "rnews") == SAME) + nonzero = 1; + notiflg = chknotify(xcmd); + if (notiok && notiflg != NT_NO && + (ret != 0 || (!nonzero && notiflg == NT_YES))) + notify(user, Rmtname, cmd, retstat); + else if (ret != 0 && strcmp(xcmd, "rmail") == SAME) { + /* mail failed - return letter to sender */ +#ifdef DANGEROUS + /* NOT GUARANTEED SAFE!!! */ + if (!nonzero) + retosndr(user, Rmtname, fin); +#else + notify(user, Rmtname, cmd, retstat); +#endif + sprintf(buf, "%s (%s) from %s!%s", buf, retstat, Rmtname, user); + logent("MAIL FAIL", buf); + } + DEBUG(4, "exit cmd - %d\n", ret); + ret2 = subchdir(Spool); + ASSERT(ret2 >= 0, "CHDIR FAILED", Spool, ret); + rmxfiles(xfile); + if (ret != 0) { + /* exit status not zero */ + dfp = fopen(subfile(dfile), "a"); + ASSERT(dfp != NULL, CANTOPEN, dfile, 0); + fprintf(dfp, "exit status %d", ret); + fclose(dfp); + } + if (strcmp(fout, DEVNULL) != SAME) { + if (prefix(sysout, Myname)) { + xmv(dfile, fout); + chmod(fout, BASEMODE); + } else { + char *cp = rindex(user, '!'); + gename(CMDPRE, sysout, 'O', cfile); + fp = fopen(subfile(cfile), "w"); + ASSERT(fp != NULL, "OPEN", cfile, 0); + fprintf(fp, "S %s %s %s - %s 0666\n", dfile, + fout, cp ? cp : user, lastpart(dfile)); + fclose(fp); + } + } + rmfiles: + xfp = fopen(subfile(xfile), "r"); + ASSERT(xfp != NULL, CANTOPEN, xfile, 0); + while (fgets(buf, BUFSIZ, xfp) != NULL) { + if (buf[0] != X_RQDFILE) + continue; + sscanf(&buf[1], "%s", file); + unlink(subfile(file)); + } + unlink(subfile(xfile)); + fclose(xfp); + + /* rescan X. for new work every RECHECKTIME seconds */ + time(&xnow); + if (xnow > (xstart + RECHECKTIME)) { + extern int Nfiles; + Nfiles = 0; /*force rescan for new work */ + } + xstart = xnow; + } + + if (stcico) + xuucico(""); + cleanup(0); +} + + +cleanup(code) +int code; +{ + logcls(); + rmlock(CNULL); +#ifdef VMS + /* + * Since we run as a BATCH job we must wait for all processes to + * to finish + */ + while(wait(0) != -1) + ; +#endif + exit(code); +} + + +/* + * get a file to execute + * + * return codes: 0 - no file | 1 - file to execute + */ + +gtxfile(file) +register char *file; +{ + char pre[3]; + int rechecked; + time_t ystrdy; /* yesterday */ + struct stat stbuf; /* for X file age */ + + pre[0] = XQTPRE; + pre[1] = '.'; + pre[2] = '\0'; + rechecked = 0; +retry: + if (!gtwrkf(Spool, file)) { + if (rechecked) + return 0; + rechecked = 1; + DEBUG(4, "iswrk\n", CNULL); + if (!iswrk(file, "get", Spool, pre)) + return 0; + } + DEBUG(4, "file - %s\n", file); + /* skip spurious subdirectories */ + if (strcmp(pre, file) == SAME) + goto retry; + if (gotfiles(file)) + return 1; + /* check for old X. file with no work files and remove them. */ + if (Nfiles > LLEN/2) { + time(&ystrdy); + ystrdy -= (4 * 3600L); /* 4 hours ago */ + DEBUG(4, "gtxfile: Nfiles > LLEN/2\n", CNULL); + while (gtwrkf(Spool, file) && !gotfiles(file)) { + if (stat(subfile(file), &stbuf) == 0) + if (stbuf.st_mtime <= ystrdy) { + char *bnp, cfilename[NAMESIZE]; + DEBUG(4, "gtxfile: move %s to CORRUPT \n", file); + unlink(subfile(file)); + bnp = rindex(subfile(file), '/'); + sprintf(cfilename, "%s/%s", CORRUPT, + bnp ? bnp + 1 : subfile(file)); + xmv(subfile(file), cfilename); + logent(file, "X. FILE CORRUPTED"); + } + } + DEBUG(4, "iswrk\n", CNULL); + if (!iswrk(file, "get", Spool, pre)) + return 0; + } + goto retry; +} + +/* + * check for needed files + * + * return codes: 0 - not ready | 1 - all files ready + */ + +gotfiles(file) +register char *file; +{ + struct stat stbuf; + register FILE *fp; + char buf[BUFSIZ], rqfile[MAXFULLNAME]; + + fp = fopen(subfile(file), "r"); + if (fp == NULL) + return 0; + + while (fgets(buf, BUFSIZ, fp) != NULL) { + DEBUG(4, "%s\n", buf); + if (buf[0] != X_RQDFILE) + continue; + sscanf(&buf[1], "%s", rqfile); + expfile(rqfile); + if (stat(subfile(rqfile), &stbuf) == -1) { + fclose(fp); + return 0; + } + } + + fclose(fp); + return 1; +} + + +/* + * remove execute files to x-directory + */ + +rmxfiles(xfile) +register char *xfile; +{ + register FILE *fp; + char buf[BUFSIZ], file[NAMESIZE], tfile[NAMESIZE]; + char tfull[MAXFULLNAME]; + + if((fp = fopen(subfile(xfile), "r")) == NULL) + return; + + while (fgets(buf, BUFSIZ, fp) != NULL) { + if (buf[0] != X_RQDFILE) + continue; + if (sscanf(&buf[1], "%s%s", file, tfile) < 2) + continue; + sprintf(tfull, "%s/%s", XQTDIR, tfile); + unlink(subfile(tfull)); + } + fclose(fp); + return; +} + + +/* + * move execute files to x-directory + */ + +mvxfiles(xfile) +char *xfile; +{ + register FILE *fp; + char buf[BUFSIZ], ffile[MAXFULLNAME], tfile[NAMESIZE]; + char tfull[MAXFULLNAME]; + int ret; + + if((fp = fopen(subfile(xfile), "r")) == NULL) + return; + + while (fgets(buf, BUFSIZ, fp) != NULL) { + if (buf[0] != X_RQDFILE) + continue; + if (sscanf(&buf[1], "%s%s", ffile, tfile) < 2) + continue; + expfile(ffile); + sprintf(tfull, "%s/%s", XQTDIR, tfile); + unlink(subfile(tfull)); + ret = xmv(ffile, tfull); + ASSERT(ret == 0, "XQTDIR ERROR", CNULL, ret); + } + fclose(fp); +} + +/* + * check for valid command/argument + * *NOTE - side effect is to set xc to the command to be executed. + * + * return 0 - ok | 1 nok + */ + +argok(xc, cmd) +register char *xc, *cmd; +{ + register char **ptr; + +#ifndef ALLOK + if (strpbrk(cmd, BADCHARS) != NULL) { + DEBUG(1,"MAGIC CHARACTER FOUND\n", CNULL); + logent(cmd, "NASTY MAGIC CHARACTER FOUND"); + return FAIL; + } +#endif + + if (xc[0] != '\0') + return SUCCESS; + +#ifndef ALLOK + ptr = Cmds; + DEBUG(9, "Compare %s and\n", cmd); + while(*ptr != NULL) { + DEBUG(9, "\t%s\n", *ptr); + if (strcmp(cmd, *ptr) == SAME) + break; + ptr++; + } + if (*ptr == NULL) { + DEBUG(1,"COMMAND NOT FOUND\n", CNULL); + return FAIL; + } +#endif + strcpy(xc, cmd); + DEBUG(9, "MATCHED %s\n", xc); + return SUCCESS; +} + + +/* + * if notification should be sent for successful execution of cmd + * + * return NT_YES - do notification + * NT_ERR - do notification if exit status != 0 + * NT_NO - don't do notification ever + */ + +chknotify(cmd) +char *cmd; +{ + register char **ptr; + register int *nptr; + + ptr = Cmds; + nptr = Notify; + while (*ptr != NULL) { + if (strcmp(cmd, *ptr) == SAME) + return *nptr; + ptr++; + nptr++; + } + return NT_YES; /* "shouldn't happen" */ +} + + + +/* + * send mail to user giving execution results + */ + +notify(user, rmt, cmd, str) +char *user, *rmt, *cmd, *str; +{ + char text[MAXFULLNAME]; + char ruser[MAXFULLNAME]; + + if (strpbrk(user, BADCHARS) != NULL) { + char lbuf[MAXFULLNAME]; + sprintf(lbuf, "%s INVALID CHARACTER IN USERNAME", user); + logent(cmd, lbuf); + strcpy(user, "postmaster"); + } + sprintf(text, "uuxqt cmd (%s) status (%s)", cmd, str); + if (prefix(rmt, Myname)) + strcpy(ruser, user); + else + sprintf(ruser, "%s!%s", rmt, user); + mailst(ruser, text, CNULL); +} + +/* + * return mail to sender + * + */ +retosndr(user, rmt, file) +char *user, *rmt, *file; +{ + char ruser[MAXFULLNAME]; + + if (strpbrk(user, BADCHARS) != NULL) { + char lbuf[MAXFULLNAME]; + sprintf(lbuf, "%s INVALID CHARACTER IN USERNAME", user); + logent(file, lbuf); + strcpy(user, "postmaster"); + } + if (strcmp(rmt, Myname) == SAME) + strcpy(ruser, user); + else + sprintf(ruser, "%s!%s", rmt, user); + + if (anyread(file) == 0) + mailst(ruser, "Mail failed. Letter returned to sender.\n", file); + else + mailst(ruser, "Mail failed. Letter returned to sender.\n", CNULL); + return; +} + +/* + * execute shell of command with fi and fo as standard input/output + */ + +shio(cmd, fi, fo) +char *cmd, *fi, *fo; +{ + int status, f; + int uid, pid, ret; + char path[MAXFULLNAME]; + char *args[20]; + extern int errno; + + if (fi == NULL) + fi = DEVNULL; + if (fo == NULL) + fo = DEVNULL; + + getargs(cmd, args, 20); + DEBUG(3, "shio - %s\n", cmd); +#ifdef SIGCHLD + signal(SIGCHLD, SIG_IGN); +#endif + if ((pid = fork()) == 0) { + signal(SIGINT, SIG_IGN); + signal(SIGHUP, SIG_IGN); + signal(SIGQUIT, SIG_IGN); + close(Ifn); + close(Ofn); + close(0); + setuid(getuid()); + f = open(subfile(fi), 0); + if (f != 0) { + logent(fi, "CAN'T READ"); + exit(-errno); + } + close(1); + f = creat(subfile(fo), 0666); + if (f != 1) { + logent(fo, "CAN'T WRITE"); + exit(-errno); + } + execvp(args[0], args); + exit(100+errno); + } + while ((ret = wait(&status)) != pid && ret != -1) + ; + DEBUG(3, "status %d\n", status); + return status; +} diff --git a/src/cmd/uucp/versys.c b/src/cmd/uucp/versys.c new file mode 100644 index 0000000..7b56c8c --- /dev/null +++ b/src/cmd/uucp/versys.c @@ -0,0 +1,114 @@ +#if !defined(lint) && defined(DOSCCS) +static char sccsid[] = "@(#)versys.c 5.5.1 (2.11BSD) 1997/10/2"; +#endif + +#include "uucp.h" +#include +#include + +/*LINTLIBRARY*/ + +char PhoneNumber[MAXPH]; + +/* + * verify system names n1 and n2 + * return codes: SUCCESS | FAIL + * + * NOTE: + * the old calling sequence was versys(name) but is + * now versys(&name) so that we can perform aliasing!!!! + * See accompanying changes in uucp.c and uux.c + * -- Ray Essick, April 27, 1984 + */ +versys(nameptr) +register char **nameptr; +{ + register FILE *fp; + char line[BUFSIZ]; + char *name; + + DEBUG (11, "Before Alias: %s\n", *nameptr); + uualias (nameptr); /* alias expansion */ + DEBUG (11, "After Alias: %s\n", *nameptr); + name = *nameptr; /* dereference */ + + if (strncmp(name, Myname, MAXBASENAME) == 0) + return SUCCESS; + + fp = fopen(SYSFILE, "r"); + ASSERT(fp != NULL, CANTOPEN, SYSFILE, 0); + PhoneNumber[0] = '\0'; + while (cfgets(line, sizeof(line), fp) != NULL) { + char *targs[100]; + + getargs(line, targs, 100); + if (strncmp(name, targs[0], MAXBASENAME) == SAME) { + fclose(fp); + strncpy(PhoneNumber, targs[F_PHONE], MAXPH); + return SUCCESS; + } + } + fclose(fp); + return FAIL; +} + +/* + * Works (sort of) like rhost(3) on 4.1[abc] Bsd systems. + * + * Looks for the host in the L.aliases file and returns the + * "standard" name by modifying the pointer. The returned + * value is saved with malloc(3) so it isn't zapped by + * subsequent calls. + * + * Returns: + * FAIL No L.aliases file + * SUCCESS Anything else + */ + +uualias(hostptr) +char **hostptr; /* we change it */ +{ + FILE *Aliases; /* list of aliases */ + char buf[BUFSIZ]; + int atend; + char *p, *q; + char *koshername; /* "official" name */ + + if ((Aliases = fopen(ALIASFILE, "r")) == NULL) { + DEBUG(11, "No %s file\n", ALIASFILE); + return FAIL; /* no alias file */ + } + + DEBUG (11, "Alias expansion for %s\n", *hostptr); + while (cfgets(buf, sizeof (buf), Aliases)) { + p = &buf[0]; + atend = 0; + DEBUG(11, "Alias line: %s\n", buf); + + while (!atend) { + while (isspace(*p) && *p != '\n') + p++; /* skip white space */ + q = p; + while (!isspace(*q) && *q != '\n') + q++; /* find end */ + if (*q == '\n') + atend++; /* last entry */ + *q = '\0'; + DEBUG(11, "Compare against: %s\n", p); + if (strcmp(*hostptr, p) == 0)/* match? */ { + koshername = (char *)malloc((unsigned)strlen(buf) + 1); + strcpy(koshername, buf); /* save it */ + fclose(Aliases); + DEBUG(4, "Alias: %s to ", *hostptr); + DEBUG(4, "%s\n", koshername); + *hostptr = koshername; /* correct one */ + return SUCCESS; /* all is well */ + } + p = q + 1; /* try next entry */ + } + + } + fclose(Aliases); + DEBUG(11, "Alias doesn't match %s, remains unchanged\n", *hostptr); + return SUCCESS; /* unchanged host */ +} diff --git a/src/cmd/uucp/vms.tar.Z b/src/cmd/uucp/vms.tar.Z new file mode 100644 index 0000000000000000000000000000000000000000..618f160a357e3f484e1f9ab7eac4ffb31ac6be03 GIT binary patch literal 36070 zcmb5V2UJtvwmuqmb`rXwN+`z4zV!D`PMiYtJ>;EZ_RpTyvAadnGIU?UN{q>gxVPN+xmpN3Au3 zsc43T(#X#`bZD5ccT&8GKpLBzYBbjvgH|@XyeA>4W;;cPL&1CK5nEf`({kmI)%Rl^ z^^;ZDL~8CIGP8XuVY7Wv0;%-4tN3{DrbyXqx;d623Ct?NpS3t-T&C~v4W^vs;P88N zN0#Zr^zFdU<5$kzZa&|jc9M@N2-2mQ~FfKQPPOJ`l`1PO z$PWx>8%#CcqXcX{>lzlBwY8kJvd{UmEmoY$c>S4Hxnhj7DB8gWQDw@O2Qq2HGEg}s z-GtQAl$=MNl{nMAS6t3$%M>oDEN`*8(%`o&MRLhtV^QIQ8S@&c!gyVF!pBm9ny{SC znV^iyN1hF#IeecvZ67`xX)NoeUN7YsMi0`dWLZcMJB9E2Hs9AMU#WW${+5NVU8-!c z=v3@Y9S+yD6MpTBMuM7`NBm-ZZ=Y&6(P8r^JieL#a9lqiR}Ry-d9RQ~HKiA(^i!hW z=`fmp)Qt$}PsE`E04yKP&4GJgf*<43G-b=bU? zM?Vg+<(vw5dOk0CP`jg%ir>^_$e^v7l}S>++TkxBpPg9fx%3Lx9CljpyJ?5vK!YF@V-#nMNy;KH*EDoqF_a?TJ`b*2WH=ABhZg zq9GN+5kgFEQ3IGnda6XU7K@f3E*Wrby);@o`8{^q@=O8|PC2kfkfYS{yqtoSmDyC= zbvSqW_XyMZs^5DbPSB{c-e+3pyW!jP?7eSJP`4yydWwSmRc&Gdb15lFU}#cjCxnT6 zd@9B2MzWg>K981ByH7wb!xZ%d4;a4eW5~LE1nM z!V}x_*uG{KkCLTyr=?G@-w=L%lkRe!dp`%&*(s0H>-uQPQ)`!L=0&CC+ov299#K?| zv%)#h(k5SBa%oXt(d^qHWi5KQapPP0l88axrF4Z>P~F6f~^f*v#I| zxE3oMHFnBK%Prf0ch3pNg-y{bOq94zGf;m$=*^a2%K!zf>X_~sBa&~JfSaUj*y9!z zosynVS6U1ef9G(1zWM4gN@khV>83gb*9Jp&&kLOIms4^r2Pn2Q1_nRl%`*AC?Z0A| z?)BzPgsyyfuWBcv8Zkg$NvrWeO*7(d%(&E*&Vq@h<@EdeX~QXXC&!8slzQg5rK2AE zR8ouBKGgCaO0FDopuIWsaPukOMMfdVDaH(wkDWo6xW0Y-iH;tkeA5yvaMx1&AoYRU za~J{8noHhpFR4AbfUtRMT4J!nIwYDRXn&xmhq&|DsxMJo58vIJlh zEF1Eve$QEs-P-cuTR|q|AYfB4m@=&k#r<0nI@lDLOy6z3AJ#)!i!T>d zzu%pzr7-E0N`1DFZc>o(;JP}}S*hXe6$z%79R_Zaa(&+6uO5HgyZ2r4rR-ou zMYZ8)x*BQ>k(QPj{fRhL(!4j^5_@n8DUV<5eMdWRX@@59_sDTcT%aZocnTD?4)EpL zGUAzS{UmwX_u)5-Rsv@e>{th%AVZ}Li}=MkWWdrXE~zc9M>6%yX0HcS`be2d@8{UB zSq~`r2cRJ8vRu zGA`fPtIJiu2Nb`0vZ#2f1muI^SQ`6WgqefYb(Yy%^k&QCI(1angA!wAuff#o`)M)g zekvm;kn!XkowNpy+6V)n@AOe=mnP6KUI9h$d<5z`4aO#X(%H-|N+TFWRW1n>SEB$m zDA&+L{POaCRD9Ai+%Y33B%^f{ErUipWt}pD(W#7@Uk`Wdn4iz4Q@w&z^%|F=WWw2N zmMs`%_?J3?l=oQ_bX0oSiYv2Ar)1pd-if{B@cw<()C-j==t+Nk1;2(h(tXt^1*g*K zLUQ}o&=wY$u-oISadkCb$*Tzu1P)R(M(;+c+4&sXez4iU`|}e;FMa=!dtg#(0}Z;$ z_|XUaCPMP@9EL6G)`u%8%dHfuq)IOC#RuE#o$u+SBeKi&0vo@#7EcxwM%h@HA?2sb zWNI!^^hCEhs;5@Zv^mH!hT?tB*T#SJ-y18ud9%dq&7AoQVNL(`hi=!U7Vkeyq_C@u zX1{T@R!IStS=M3n{ocDvQUZAFM_nSJf2LmjRdH^$vG%JOs1iAzF{yq^Op(VcDtR?L zUES^RLJQU?e2e#Ga~DWaTRu$@A20zd;P=%94$U$6b#}IQ*s*sR^!jfmLRmjWj#uuf zV_M<9{Kl1&yy{yoW_~W+M55VO}+PDei1U8XVbGoI6KeKXNL;^?j?;mfh+(Q1}T46Utuh4=_4P4#ZBE_qN_ zM>ie!A6g6`YIvKznP{Hk%X1F}2fMjhHl?)%efx{puEQ$y#p7t7N@;`w@7(e3LRZQYf z^Y*lMcI*Qa+pvO4ph}vTCdo@{Dk4}J?7~@HXvJ>j6ZG+kbH(7oQk*X#mO?Ke8U^TJ z5emC8zn0?sTH|$OLLBc{XS)%ElL!>o3AD=Tcvw7RS^{fi5(ir%FI$3ub%Kaq{LQp@ ziRA>D*YWboph9F~WJ4mRFY(@fB2GE!dR>NiX%exBn`$b_IMUaQ5-7h8bMHes2O?!k zVNMDNGZI3F1PYddy0akPa{QS)YKy`s>7r!2QkZ!=ggzpuAtfU+jCwYuY7yK~P7Q0Y zq9$cVKT3^lNFgjE6ZF!kozl`uVWwCWM;KzWEjqgvmM1D^6bMpWk4uY4KPvH<2ok>{ zn&$`0FvDb+Vl&P=<*|t&8myDLO5-`ZlESj0!+H49eY{-)h=KlRX&TI-!*xcN0(VBZjOCq5fd}PSVrmBt!P>Oy;6B zy&`*SVbU__v0r2xm1}=F_orT}^Fi(fn_`cH)Oc%T;-g|}suJ22B6=l#k}=)14@>MY z3=c;>?JwcFoKDMr<%NE!fLEzddg-->((^J{#I#qAex^9vj~e)gPl&cc4Y$)hr}H#x00VAlHO zzMkdhFPHxoEmqYl2GWbY#VROmDuU80!c_8}tW?m1a(>U_on9#^y%TSWk=yS_^4SpH zd*zGXCFtQn1ELT^WMLCqL9_DZw#b4XE0vOzRrf@zuGmx!>J{!sW$9)l>EF#VSgtZ* z%a)7hdKsDh#QhV;!JUl4kRjo)~ zE~XJH3B6GfK?OX0gPf!Sv|CR&xu#3~hvbuDOl0J ztW$PF^&nwuEb|N%(MYv$xU}l>c$L+UEF0=-3}3Z_Z8feh+qtaT%{#{?|oukXK6?-!LHpmH_jas@woL!xbi6~X2`6LP|fQ_? zoX=Or`Ad9qunx#tXZ^mP$G6%y!xkCmb>-DPtRwMO012VhcPr^^uvtcBiyo+pK~(+7 zZ;CE!UM-|nfHRKQ1*Kng3v4N^ZTV%(>EoFza<)M%x?$kW)$JcwsqhHC?S^+YpdeAr ztQ9=81T8S-3d=z5K)$9ZD09vOKZOXfbpEh&t(dA+>t1Csd!yRj%e7~#G^on(-i6m~ zYU{=dkGvS2_-=xY*bjA(om5x=L%Vy%8*Tyf`MR$I`(PW99U%-39ug6;djH}2O{SR9(*Z=)4CUxr zB}8i`_d9C750=)ikEegpL3yrnjERH?%W%45RT9%O2Sh4LS^SkqKqy|B_7{@g0OLA^ z37O*ZLHnz~`e_;cuK~UYF7B|ttL*DY&I%Z}J?c2^KqB8j#~f0~;My08@Hux$9$M5~ ziq>6OyVR0wy;O7HtUDquo;mxA%55x+*J zl|$yb^$mNlzWB(*Cqo_vh6yS|nT3OM!dChc!}3leytL6KzhW>dV{?{c0a;_08^)Rt z?NkIQVg*cEe4H9PUMDd$S3K^3%5VFIOl0t94;gPIb;0b^-a!KD`0P)FrQ+T)-K6bzzg&HA>S}O{;f7G zG62$;ibstgCkJ>6i;(p$Px6DtgJGx(#3z{Q6XlH@mqk4pRv?719i?2M-PuHs`1-4n?QSO=H1@=1Lux)HSL z8O-lK4O%O?2ysUk{CvZ7|1X}(qa@Zkpb7mTGpaUu~@M$$0XW(FTJ!hQqj8``7)nkLyQm zJJuiHHkiBH^O(0X`!?5;nV)7Y9(EJY-QTaVczk~#kjG}B@X&29e8xpmp7`+VyU*%} zpOF+EqNp^#R(Y9P>sJiVhzhY!gTl1=*`fnu-kHlsvj}X?Aw3=_h(<(h*Koh@w|O_s z6;49dx%Itk3OPZKV*Cuyrv@h~EC`SCOjDRWy{=HP;O800vr@y|%3yPT8fm4QHa)j+ z$4XuyOWbe5Lm~p{Uwxc<2z%jtP)J}9tmHA=Dv(kmkhfl5jft1h5+&HTa(d8T`xTel z?6OK>hxallYz+pxccg#x2qhs>4-v=YIhkI0I&~4WF}_AbgasDBV-Q#NyiBX%7c~&M zj94id&;SdLb^E4uCwIn1c26KX82n!2{AR*=yZb$+9oBBs19y#pi;SSDjE^XKVq8q} z6iMqQch)5iu05mQY**hDx%zeA!Ee58lRbd65WBIG1FkucQonC(Gi-MFllDGt{W$#k zrrYm=Bq|t2I%rhv5{^2pJN-&{=l6tP`FF%ReZIzo$KD`jBdR@+>+}J6mU!s z$_4iJ_R?6ty9I8B9PKnJ?l|(0_E^`#)Ys1S8X6w$+OvN%J1Vx!{bn1`VV{dI!6KZb z_gr&#Ltk)swvZms8)SUiyJ-BQSlBOq^J`+&KI)UFV9Q2&+>hp??VHE8aYxFXhX-vB zv*KdITB=Ar6Qq6~A6{z&z8Ws5jIh9fhSh52aa$*j0S~2-1bV-?V>_W|_Fu;R?&tj} z{OPyV_YGrR(yc9d9d%9-{H{{mnh1U`uzCw64K#i{*yTT3aKNRCCJofBI`*v^;=Mb0 z`L_dp9z6VAIf>b?^8CiTRuHz6dU&-zH_yBp#1p}Rk=Wg1Voe{x+PZB!Pm%~;l;h~o zD1x*16UVDPiHjpUikmx4lba_$`MF|udyNCwqz|X+en19)8STuUS=)=;ZQlB6ls5vi zLY~I@F47}hFM}HUK%E7WKNwJ1`zA7_k5%m z3P`sE_|rDV{W~P_pyVuQOuAO?#?#BQKIpK{P_@qdDgVDM57@6V{y%#sf#jrGZ5I1u z(12Y{mP{r|Y;B|)3=|Kyt3;m}K73#s{TN=x9qG6Rk*UvUT#5QbKVA9Rpfx!d&` z|3~j_Iv|v9dC@v^m8Zn)5%VNaCKKTP;BRRICpSvkr^T+%et2W<3q?JDG z@XyuV!qD+-7x$jP_l9VH@;1te02o;@A@(xrN)TAly(q7N8`@F z`e}zrbo1St&zgJiKABC3g4J~~+;%I+YJn9?{{_48IS>hGRUQ^7**Z4ccQeGqA3sni z4JJ@rbxz|J9X^tKs6a0Qm>)A0#YSkoeW9GWc6EZ!(KreY?jV1+cFJc-O-DFYxM?ER`f;%69B9 zgTeyvFIaUBu?=R(rf&k$|8IgttUk`4{p(qn^QYCI?C8HlC?W79(6|qDEz)l5P-a#^ zb_A(VwkvzzvhRKd1onX^JH38;ydpo&@&8UTIv7$ZpMm5mz8|GA9ZIfK#><7q)~#NW zFqC!Q;%`7MMiWU^3%wBoN0l_rjJt74Jtyl7y#fNKPXEWw^l2v;zw|vNUl)tooCL^K@Ct=$AUa2rR5=x$;1&W}1@o(rKGvTpYHlhS zkiT8~PCpLZTv$3Y<>T(22!FrCV?-UW(Y{wLpt{Xlvm-D za!6Egpad*HZwRYO(DcCrbvT&7>q=HZ`kh9Fh(fbtyu;@ z!(dbd`-xCH1~dgUri8)nJKJU+gZcGQLw{X`Il&-JDFPDJ_Rk{>;~9WP+6JQ=|Ext3 z>}dh{3r^@8)poFI80>FU*M(qH^9_)s6$Wda=er6$B4L5l0tA3!mTXYy!6NDz+29D` zkGoBPghN8Rzfp92FU9Ta&p+f>V9@ttP?WMbPI1XO+`^xNOb_*q&@NUFEt2$B5X!1# ziC8o;S;w6p!VlG!F3ZFAL*=fZ(AeVWxNm^`Z{%qL*J4%lCJuEPVmQnO0^c1Cy>|qV zPsB#BbKhBr=kk)C^OhIg@JRjy+b=za1t+7feUo2)%N4!;#}R%N)(yJJIOApFE-OdB zbq3bvBvyRZ z0RObp3lwzkbT}L#Oz==Iv1(}iudB`TXs^!aG!`J2j+PdE3__$eF!k8Rc>^94uey;^ z@Vyzhn#f9FWl+gP(B;ZNfs)`Xg)2t4ceeM<~du;)(o23?YD@;6SMtMVQ)=L5_HoAb#w0E^lB`kbZ0%tpq+`jrac-)T)0SY)^X}B`Kp~<)a3<@ zro2yyBfQ>#TC>>&rXW^ZM(^f#bP7b!ip z6Fdbs!X!q%1`W}m5f=QYEY>V#?t8}ezov8J`QXL6s181|oNRwZV&#)kv^MfI9yAP0 zv>_Hde*$r{e`636{9lCRz>aB7yc0BsuCVJH(qhr%-r(P1i(vfUC-Q##zD3Tfmj}WJ zs?Xk7o?A6haO3?KdORa)N2zTK5R3~zKd($S+`z^zg-X+u{bCO zAoyTabM~9=tKly}B*DPp2TP$C84w-9-=-8zm`J-WgVL7_t?IJk00* z*}r%(S^n=?qGvi1I6)#K=Ec7Em!Ip3Y>pVV1+^fEKjZ=e z15OY|JZrIJGAFz=yddC#uGdVI=@`wp9Mr8$Ntq9bMo?SRiK;%qr;F5 z$-qCt*58uVFsiHQG;}$TvOMV>)oPx{YeS#Db z(3?ekD$iriT5sd2ayjf8Sp@0&s~X>uqcQL zIf>eU*8ZnZv<8xMC;ij9LpefA{#!A}f`#2mP!@k*H||5U`CHHJK&XX-Ldp{0hAx!< zoQ_eCukImPIe&aDg+7-e(-qoBOWgpr7Eckv%LE-S=y=|i-m#YSM12ZDNLyFF_!!!w5elk=az z%ZdmbA@6_ZbFn9MF32UT>R$!0&p&aC%r~Zz|59~zz(f=AYfFHr&(U87)|~nE|4O;P zn&bkmPNw4j6O$)>vvshVXv+su0CWV_mHz1G9ZxoWZe90JBjm;B?u2tU4P#)gk^N66 zytf(_?$K@XGDdhUm&r3x=Ng1+)}klT5}6MHo8nbA;)OPDjnPZ0gTC9+?R{&{+eFEy z%QEtg4(i^B55%Ru5hS@LuqHpB^i59n`THJv_mdw3t^a(n>q5ByisH)k4S!FbfJ+ND z{O~ig+ad1|cCDUj~zR?PM#0po*3YAi@*r@f3l>_%rf#g|*D^R~7g$jXQ z>rU1$D=r1g+zvT?6mn#ury+vW@(7)s;Lhp@g|63yV?OPQVHT;VJ<2cidB@Xp-A*6= zX@tJ9$e1wxO@AtaQKs)R`9&Z$;_uCV#K;>F7#2lu|HlA5i@Ib87tGi&sw9ALO(_b{L!kLCyZ}!y;~OM zW0k87@EG+(Qd-`!SJ9X;38F1m3Ykjbw%ddL3SN&xi-i=^zm@TQZ5>J#?mU=^Ia_iW ze%0kuR_+-iDizMp=^@`fP!O^bhTgF3QX`{wC%;IiWEo5e<(S@T>`jea6kc z{`V!d$UHF-BdexywvLzyVDQQ1g2gOOw0|oDl2(-y*Kge93yZ#g=$JjJCNhmnLCsZ32(bhSNtaHE_UQ3YLYmn1zatg*Jx z=yAHs$yMQVJw9K+QteMw1b? z>=|>1a^H)2b>;!jsRrtT*Q1yzfv^K1%2IFYB6E|Gm5~a6^THJNE?MdX8jp2QgH|T( zM-|p>Hcuy0$caId_N11I5Vr-R6(b7{Z!*kG%-|EN9m@9ldR_9l79*1}S9}7cnX4>< z%7Vcp3IEc;?nd`UhKPn^RkOHmJb#+*b7phBydZKM6RD-wAOaLE<1YM_m2HafZy1;q{lz* z3a8S@7@AaON)1ZL2MMZ-a*s;(a&;8)O;UG0*SwF{;R?Cqbfe|Ex@2eJP@a!}uHmnW z-I=0|7}K*SvLBq}Hhj?-K5b@oNg?H0+40@C=Sv=MI-fc9`zw>C*5fuxHIX@an$vOp zNpt4c1J|-F5g)CkR43tJP@tag4_7nS5 z2M=Y2A2If;%hq;2K6{gRkxqPcBAvz(RZr_FZpLRc;*HLwLM{)y z>%tO7UsTGJejoICa~~_7p`mG&-Es2_yioAFyyC%d@BHNyA#rrW9Gwdc#|FN{pegk{FxY-?cV^^#PXo>kZNN4} zLY^w*bNw-w8<+7VpLh6+r1GU zX7eWFe z)0`hWo0h(18>LL(e|-*hMxLeA6w#Og`dCxLE{o`Q-%7sn#QA}kOOK#sd&YTRYW8>5 zqt)Nqh=$V6UF$PrXRWw;8?sJF+jV(-@nyT$MGbG9wHkk3d~df_Ci{kg z$62$o91O)y(~<)t9)5fpL!n&SPvaDrczg(kqGrRH;;@L5cW6PWLU^1Si^MhjD$%nh zp2iiEB!;H&JX=#}zKyP{?R-MVy~@OmXX{mx_$GgWq)*LxP*s}lOe;m1_!3J5ZJ%W~ zC8~~7E%yO*KW@a@p z7YmBwvGEAf8d~u^j@~DbqLeEib)SeEo2Pr4QKN>Gf1gWl0XGYL1w+x|*axWsgE-e= z3yrJD@$ctkT%J`_;;!&L#@q=u2?y#0OGk>-PQ}kSM_Q4Z zsC~B!MDY$s%ff5EKWXssAw?CZy=88Fd*yZz)@etJ($G|CJV*?-FMYaky#Ea@VCtsb z%i)&pT`Yz1oq>>Ag5z)TSxVDL4VG%cr%Gap5mpgkI;n{G)jdl^?F29g8g0cHTMC9> z(&GqcP013$Q6ArxDQx*bnR!ow{U%f3-=|ibV`bbluo5P-snlT7DXAv7~>?^NQg` z>VpJs&{W0P>vx9UOY5)qpCdB4Y%7qjtKF$jmTUK3?hi|&t#znPts_Gd@rcrC2I_Nc?Ldz_DE>a;Ml8LBCb)c+I@_AU zV)iUUmebbzS4{{o%0D!|<+dQ(QB?o2fnnmABtClzDr0;sBeA!w*@J@02(PY3Fi!GB zI8)h}69A`WvhCnvT93~;}Hu*99- zyRe?hw1GMfEMM5s1!C}VlZkPW)p5U+f(}sxGU5BEQxIP~ zr*8a_Zh~r3+_p%($oIJU?~c@8VtZ<_=8Kr%KBT#hh<|J1F%x7s%;S(Dz-fTcv=qHM zN@)1b%_uCiffTWd7>QzL=&~|#EIwyty(4aDk7DkFOiHSsz>tRl)b2Ak|+T; z9ZF@rhPZRfprJBBXoygt;D~s{$N7kl?G6F&87HCaB>Xx~Ow=iVBq5Y7QPSPXANq{4 zoB4EF8n0fQ$v%O0k)5cVCh8eqx{SWGoNzulH9ggubJ;(C|3V>U8m*3J*`wr}4Uv}` z(l$HdH<>c45`m{n%2uzP)N$gXGV#ny%1S1g_139Bzb9O^4&YpN$#Iv2Z43Qa%nFBb zo))w^>n>TjW7IC#N#RcXMCOn3Q#}2<(=^-YVNudJ%tm zqByR*9#ZB}i4no5JiDu~7i{t&Cdk!CIkay8(mqkhCcBw0?^~&1&sM%jdfu-`d6F&# zGi*dE86sXgTS+C~rrqUhiAx15!M`Y@*t$?+(M8XzkhElpU_<3Zx^%N86y3=bbx*ak zj;HPR9Hz{Wu_nCL$aKvwx}yxnlCo2(2`=eD-^NU;>!#Uz8fnK5rN zoT8Xw*fZU|oI5?8Z4Oe4m9todOOvgIGE|Dg)3P$|I4=bim8R#1AC&ChzD)FrFZU|t zQ553}FXA0>&J;`7FDc_&EK2f>ZyvjR>2jL8ii;IH$Fa6DyOm-A)-wL?^6(olyKe8Z zmY881RODjLSh~lHNUxq}6;go`Y&VMbz7r+;DsH$}Fr@=V{62#U3D0l1y}MB%MXESh zR#qng?)!j0MxdP!uI>cLIsx-mHb%2TZg@-si;EHr{$O6LC_PxVCN`o~)EC2c*$wL5 z4bLrD6D_PUec(YFrb+{~p_feASncTyhh?1iYel+_<`m@fDe!^!pYhkr#dzYBYA7t< z^Ru)MbKW*VeJMdnVHq5)BC2qr?~+8Vg;^x?ZK{G$QO9GDSAD+>b4HK=C%}&4`Gs>r zAh$lwm4v+CrtgVABOdMNDJx-F03PzONZLl6u{sk!Bf&3&j3T5TBv}7!!`;tI4YkJb zMY0=E=1*##5QKr1@}kkY;#e5qG<7YwJ`Ohn8c+fk1Nn$uE>0Mt_RNI@@mRWip{N^i z%Sw*U#e5N@6EWyOcu7)BUx4`(>m?EZ&uFAcM|xmTtOEqf`anFku`Z*rF**wrM^tdw z|E2OJngSA6Ydfi$D(ZMKb@ zL5(Bh1X+<(lkYC$<4u!0P0v(sz2s;FQg2OOyA>mI^TXMMA&%xdXPb}m8w2N59;G9D zZBZwt_4>1oka`?X{kYX=nDZECTZBd%>-{FScTMZm!1HJc z9?llbJ78C}ebuAgy0qoDV)MP|4hPDPhpHW*PpgGblXYoF%zSIpTnCd~Tej8-lb`0h z*O)6q+P>Uw=Je^@P)(R=?0h5M{{C!xifGsTy>`@E%kyxg--*tEn{89#xAo55CaE^^ z-M`iOqqA}+_6lXAczNT^)vip+^u(LZDUaKx8}IPO+|G$ zO`6-OF`ZTA$u;lpd@H+6yf2uf;@lp8&ur~>OzS<3+a=9*ceGF3*MEG+AoF&vU3*>( z(|M}qUZ1=D?^-mDqlU}dMo-=D^ts)=);V$We$S(>qVk&qr?MXBKhWa5-ShlJ_1c5S zr|t>b-3t(VaOvEGB|9P4s}Eb(?v9;k*^0UU^jvT5%Kh&?4`*!gOJZk|0XkZ1ly zLk%Ar;XU9P1W5NGq@2d>Nq}cxWv&Kel~HC`)` zCtdA2*E4#_o=+@rBs8I)s&&L`3&?NcIA+80tX7KmnSenum?B?uWC}{R0&;yoaD`xW zg@(hr%JxMdSR!Wkx_uxO|n1_Z2T8OB1uW9*<68nhuzOZahY zRXp=Dv8jn?m9UL*Y|@bUq7lgbGA5{M?}@50aZ{sD~Dg@(oZ;B z3tworzF2+!;>>9-jSo@Ubb#*fH|IV~^WrMFiih^s2Fjy`I4{1H_%$d+JFxQO-j&Qd z9XI2;IQwSL_4XdTy-cYTGrcPx;r?7_i^RSqqhb-{Ce~Z-k*Cv zG_Q2mL}IWrc-Sp#nD)+%uCd`fx{*qO5m)=+3$qhm5|e(vMw%L)-j+j#|3ZeBjjnP% zi8ofoZ~7k@Y}@o`?V8IMGm(skh(7Vv0=&-5%!@_{B8EL;W+ zR|tf&YQwQSrYs1!(8B!LhhGdnela@yg6CNXc)C9uIWOe6 zC2OC*IJcn<+niNL(8QlPOKpt7lQ_QML{F}=O7nv`A1x+ z<^|9G$3*%kPl^KgK*)0LO z)yd;yW13SV@j^q2Dn4W^RlSc)}x2n`C>|#8S3H!^6bd zWhyV5%dRPT#6!f{tZuh+U@x#&zdm6kJmA~PM$`oA((}=851Y4W7B|m%U*NXc2}E$t zTd&g0;Dm;FJ;PYDl(tPDtRxAu8O7Hujc4?I41R&+oII9UH@TY$?5*;BOEv$ttiC<= zed9sp7WX7)ob)5lu+6w2peHY8ish?2j^vF0su1TUnTve;@#~jSl7loU=xC?;%=XJy z;46=<&SQWL>??=3fcUPpQ~tIg5%K2L>-zR;$D^MciihRun>Fps{o30Ky&96{br0Aa zn2nLi+N=EvVvWM$;2T`fQuX;y{HCVNJ#%6Tj;y9H`O}j5RMg{Mvl!62w5_ z_S2GY&tENHe7Hd8xN~A!qpR|CZrF*m_9cDoE#)EvYZZ*2WCMK~S<16{KJLd9{q~@# zwMs6l8u3g^lAGtz&hKwmTeOas$M%2t#1GH4K}koL%85{)wG_|tnLPwU1yC1RIUo>} zw-FZo8|HXx<$Saq4xx$Fer9S-nXLw(a2uMpPWoNHguJ3uG$vq{1^$2b1O@afVN5NnP;{g6k}yzfwIo@rML_csze<|3pYVS1)9 znYB|Jh01XK$5d|+OP8SC#L9)f!$xP2f){-Gn-S>$n+IBjA%M;EJo~)%9|e|aoD4X~U_QP2FC8=}BMbgFo#aJ%?5)4)Y#1XTsPRyy>hQHs zhXc2l^ozF7YlCDV>?YH^h#lPxB)z@s8$1@VEd|{r12Ry@`vHPiU>YP!!+AUisO|ZRneBzcdi~fwFRQ zCw-4?D+D-;&MMzACVreCi3Nbr!pBR0L#V;pxxGhCN(mVXUSD@Z^mh4eS7J{DQN*vlWk)mQy4q;tSvz~<@tegrN*q&L4x8Q{eRTr7b9oV_)Yigx%EQeyT8aB)a&j4sz;ofTy4eS+tF76<~T5#Xkk85mp{nZYwzEUk_b%_XBNZ5$8y1 zcPZA#Z}3KJe4TvZSXIH%qOq0JA2k?oCRSqp_QI!QtKgh0nLkzb z3C>KP%cYZZ1)-Dj5X#6H>aU;>RWX%59J$a&Y6M?;o8XCy)oG`+Dt55P*=uKT~8d z#T<8p^v~9-*UVjIf&Ou4vVgOXUP>3wom{Il8w@6Qaht-V_BNKu#DhucR+Dw8NS{af zW9{hQGN(k$g(1CWHIANTB1aSy0@k$eoqk}w)4K6A>nICbqCEpk=A%dk8%V6 z(x$B}oP*pku~lNmVX|$4_kF|8q=qfs3p%SoKKD7u)>Hd+c-oE+oC0fVjFF-QuEKL8FOJgJdM)CnA z>GyA(e*h`Ef0T&=sAsJIR<X==3&0eo|CT$v=CI$^(yg2=bJfi+z%|K`ZYmkUI^i zq-@$ajK{7XAHbL$6PEn^^W(!MD3Lt{6}4}okR982gee;FD<39@hv(*-i?v8Wj^+oD z$!^Hr1!W@v4Y#QS?s+(7N!h&>v*Lyn#jbdnTDz0%zWx%+P3|Yx7MQ_19K!pToh-=? z@j*{^R@o>K;Hw@Hn^lfMYZ~KFqB5v|rluwe>`;LO0J^+*o=sfp3adRc4&5r+elEJfzfb%twIm7LOtbO^65vcZ8|IfyEt5gxI}qS23N z5T8{hOD3f?W|C=6u~y3l!Py$H1^kc9OUw=InE@2ocdH8i_N|5OGGx1UAY!{8_T5dMG2 z7JtDJDhm)T@AJn(fMXH_d)mlV*9@^ zp${C1+n4_Jc=+d(fwJW8MX}%iFGT?X#B)<}r}57@S}OcedkykMEzL>&1=*P_2{qDU zmMC}Z38-_1z|kQgo`$fEz9*-w3H^8VpCWMXIeMNQ%LbD3QKc=dc=eDIsec=#oAhQr$WV8eR*lfLc1u_@_W-v`*oUqVZ9U__u zW$>Nn^ut)25LQnrVNM#k=M0aq3P&MbU1Urk3wYS2>?>qPP#BP944!Nm0v}HRsb*`S zq@cp7uyUbxJ!eAe;o*J{pHPgh*tZu~o3^ZZbJx!BdX#s$ zc6p#4B(vs7k+&Xdk2&t5Zc#Ugw+i^?^LVzxp-!(MpNCxo+56IEV3<<`4W8mx@8db8 z)VcIm%@KpdpGBU6+Ql3jXz-8Pzk1!i*guV{ka|vYlVkz_nRO((ixGhTtG)LOYohDg zhQp)*3MQe304AaL(3?O)k)l9AzyQ*_6afLnN*56{K|m0M&{VL|1uGyHK#`&%76eoj zY(YWA`pqO*uIqm8=RLk(@1K{0gJWjTn!VRv>s;qrdo!85kv6+Du;JoX)$t!6Vs(_e z3JIN>P(NVa?0Y~~1|O|`k9<6h`nTk#tHsFLwBIuM)Cz6%zhwO9@LH-Ux~k;wr+gv+eetT-_QCp;b661es~eG<#*wDn)AJrE zZ_cz&100+wVe(CA`=3kYSS#M8^oL}^9Oxjf3<;V7uN@pW5LTN;3(wTwp!A>C_@!I_ zk9T$g7JuNkVyzzsB1s4*E7nS55weZ)z1(9S%)s)=h6#g^vtq44>MmaF2ypS!Igk8F zww<)J=`4VO-~}^6ET(t6JoY=^RbC8%9PmC9sWB^Ld6M!Z+H88l1;Orz0 z!c2wPV6d!jKv)k#)bxg6cIn6bHlkNcJlhWC(Rn}|ECRc#bbqpZC*Ptn7Z9NnC{s2J zY{~G;tRy3&spyP0BnSpUjJk={XLm_ecVdY5Ao7n)Hv)c-sHKknM`IPRj+5|5W*Cu7 z4gZG#*y4}k*#Bt+6(}2D4C4*-VdV@Gu;f4h`#tXZl;G~)nyg!&FifhnM#nSJk(mtM zK)VY_Y6cknuqFM$4tMCI-6jINqedyJec%Hnq3Nwmm@TGTNes{SD}+Dnq-=Fz-cgyLQWr2s0O0P6(co)ohA z*NhV1<7a*{M4M2`g9DH~*D2klU2S*}9Rmr>l%l+|Yjt@E$nB1nCpVqRep$-(ZlYje zAiYTw3MF2^+IfAptFk*dbpR}wp-?)2^dll&8seBNn3Df*sJA*b$SW~_oepji1otsw z0cXt0mAhC$%;%ov&*g=mqBEZoJL$Luy1u51WFp*Ptb%}(u63??3=GbsEaPRTg7L69@2!B!cbd)*M4cfG!dPmxLCk*zR zWrHn`LGaIUN9W%Q25^d1TJUpY(!F}8ie_}z%N_Oj!F4M^L&AZ(Z+u_&GD z*HFm;f{?gNz@J1;1)x(Vpg2f0&jekya@{Yy(nz5D9`1>JYp{{Kq9-@Y3J_ zP$IkVVI|lb2=xzzT-&~#TDkuK&m(gG^oTYEE@gAd?8j4@`7;|Q`mh6Bm-*};?%;Yy zseGpNwEKqV?rZfCbPiw-L&lQPE?{btZS4;L3nXcdcz9#e4CBTRNC49;O!IESu0QyO z1BoqsD9#k$eTJs$wZ$RTYgRk3r2@7V_GTRn+T*%d4s)WTRv$*X#=USS-ryLhCl9{b zQOCJqBG}lrtMqq?)Gw5xBT2I)R=3 zTcD-Y1H{b5M}M{0po1rZehVyq0Ag1h{e2oc7#{xfC02HZ*a;7ozft*I^ahQmhwoDNuZd4&JIF&+1pK zQ`mCHCZ!DmUKa3aEA)%vY-;S1$(j2ISd}DYJ0^R1xn2Uj$F8I4cAxR)YkJH1l`6Aw zTNyAhDbeHE8H!U;sYA%RVM#}t{A04*>>a#M_-Q@47mfrYjU6}bpH43;GmMx2xYh23 z&|za``kh4`w2+sHO8YjXTG7d|^LipR+HfFq{7k_0B7Kpgj#386)C>lp=f)vw48HI3K}J9jD!NoBm@19JW-Z4Xhr}MXuFJ1oQ>+7j zxHbhPoZTAMH`r)OUt2zY*`?U%=K48_*Zj2HyX&Tf0#Zdi*UT?7NAA1*NaSnCYsvVD zuFO&kzh&voVMUdB)2kz1R*IMN+g;Eew91QiE0rcb1K*j5Nt1XaO}sOCO$zgP@>*%8k)U9q!|q5^IVp#%-)*GunGhK&*k!G)wzX_SJVZ*s=n)N1LnIhf_{BV9^T5l6AX zgQ@0Hh_u|`6h>M0jSj|$1I5z5nqbh4MLBI@Rt8BuD?z6n^3TUUWB$Oa5L1t7%!nM` zoUs^;zi7WW7N_l5lH#aVd7Lb`YswBSy`?~#DER4!1R$7nvj~O97tUqMMBkjVIT-(_ z_-TpXJ(Z(wi5UT?FvS##2>%XFBaXkJTlG+#X2C|3K;Vu5)ao$*;*Da3tic`$Yk6%O zjFnNNXDLk9*gqfjrKg7w#zX?1L2TqB$%J~llK$EcUK`gVLx zov;>LOX*S%ALyCttyG}EsJngXlwL{@(E72<08r}OER%| za^14<0?KulAQ7_(LV)BwcY@~DQQsb>c{{3lE^Y0HPTD?B+JX2B)N09n%_!SvK{YIm z$K;b9i_Zm4Jx;PzURy@ySFM={17g+piVK!BhZ^@;JP5!*pQe8wQrgnYdI-;phB4)CX})r`bR$x2F833MmN!MwWM{?lT{8=GJZ^ z=Fz4(s?DrdnYZW2k~{5e<6YE?Rs~mjs+Pbka!5s+MXj#++NFtqX)?+|OfTD`k`=hi zR(RjMys`>^ngH#1QqXZYpG>@bOQ-ybQ>(mz*rU2uGJEOjDSXSK+||}iZp@9aJLZ8S z>SHjK{Hytai^u(M%iC4*Td@KACQe$QV}JmW9}xM0N05V4bxBSfoG2HH&9-W$JUTTc4i`y2jH+;@V z=pG43Z)0X@_T(RF17?qgo7|~#QsHyD`4YEpo12${{&9=QjZ$JCiK4{`8m2n8*96tO z)jiOwRTOh&z^B$!{AfJ6_Tnwa5$4E|w!3JHs~a8nZoJc4216)GN|>pA>3!~^yPRIe zyiX^ha-&{WBV9!J+Xlrw$LqY1-*DghI#CASCYpUDRl*&%xwf26I2CkpR;1d9-Eptg zPJObDGWX@4Ai1b@UCpc)bJpphqDRh-o%JG{PTYU=QQykr&6|z;2pdl4i=WgGQ`;1B zZiC9eLd#G{q;tf>wNIw*wVGsVta*EQbXGX~Oyjpme=$YJD;}o=?IqK~#qi=b`4hr^ zM(NUJ%|-q?A1*CE-sB!|*zMb_gz$}w(4Cb66AxQxCCx&i>HVCE$BLgkJ||L?(92wQ zSq8{kDR+yuOlJ`FD*1_+m%y=!RU#6T%{X_MjfR8ckHrIpnPM;2FVppb?IQ_o^1qVq z9eXt73$^?6_c-Q5jO0(*l45&Q6O-1E)*AJ`5S#U0qF@!O(S6a2Fdnz@@!lsn8hC_t zl1{#%Vu+%I?JX~Z4+WQZgxtX=-wJ)(Wc^Zln(tt1=Do$K^xY{Nfb$}Q$rwF;|B~#`wl`blI4+ zb9(plTbzoRM?x!}Y`%mP>Gy`WYsOOyuIdtbH+X?+GvpJLHx>~>l4{Y*GE3q z-#?j`u(h0}@`=^w^^GVZ%bB?1K};39M9fg9lKADE1oj}mAhx5r1Z??xMe5o5Vk=1k z9@NGh{K|aEhsOQ4M4z(8W9~5QO}d&}&rIL?9DRHDu5pu^eaZaET#m1n6zGve zMH}pyUu$gUcDcQK=`SQJvQ+`^b=|3#PBmyk#!4U84j=Po%~j2kH7I| zUgFq0MZFBW{Gl=4>}sHM*4XarA3G2I=-xc@Rp<1NuOpXr*plp&r>U-jTl*X(sSOHf znOI_N0eQnS@TC}znJm0pEK01tRV1asxAAJa=oBggNA73A2*vB#=iQsUz!41@6!iBb3C){n-J1Zjc#-wmAkj%FYHNE$QTtwxJ=qIK_j*a}CEW8B;3OUq zODg>&S*(NB!l>w3sz^-&K`>Z*@xF8I`!3wycj@!KPRZQvm-`wm;n(;9nEy6PN^ZFX zT&FYls39DDWXXnKO%Ddwro#=1a04n_+aKN-2sa?Y^_aO=w(fsfynnWR|Lgnv-+tcD zkv#C;=)gSVz(V+LvBcf?*2zh_dLp$6961Yq1mM|BwaBNpy>Q&d#8Rg*^$e5=hQ=0^ z5u48`4OI1O&oJJ25?|F3QUNb`FprF4E58z5AJPec+o*L{fXx)bR?@*mMxlt!?$7+d z+AA9q>6nwEL2@Y?QG6dK%|c65wAkd$bPVPBA$1pLS2i`w&U!>ddP{F{ z&`fdIUXg;1qUhw3b-GC7YU~Pe)1qc%^ZxhRUNaW46=^t4tHoT;ym4H#q)QsuHUQH^s7k+EeuMTG^u2XHko zIZFA4eArKGq$?BJ_*o17i%#a9T#!u9DDf^MD?E~tBU82gNh8rN<6HSKxA(HR#S|sFNf(P?b%56R5*oL z8Nk6s$5wnhrW{6*c>yOGd6p$Vt3-OCI*ZC3)&(jR!N`Nyb!{PZ zlX|TUD?eMUpAU0LukuO>G~gVP9&){FEjhY~Y8nAwjL7~JjIi`VSZ}P6_pfmSU+chz zYf`~IW2C*8v-L!E>va@vQo+E>(`lo`Wqhr$c5Udk+KBqvsKa@_CP@DWHG$NlZaHNN zhmRI0A*~M|{nCT@_AJ@HFM!-|EY}6S>oCcJ3@nc)Xor?7)a%J}kWN&bBbyFB*W<8} z04ve(i!12ztPRVl?TW`c`6F|W)oD;Gq_648l@Q!xnQQv$JGa#~IGpr=A=gt80)v1a zz2c^-N(UdZaw^~CLH&z}TB?+~-NCxZZ72G?oNv#{51qp@9c1?&KE0ZA)Gy`KgB5mfyxRr)ywL1mJ6o!Ze|MTI5u0(g=1~(?M`C9e^xpsOCd!UBMws3!P(;PMugl z0ZC(S#o~itTg@Eq+gxf!wRd?wzGmInf~NArRWWc1vssmb6gbBgI)_k)Wr(T;F+2pW%_BUe(QBHfuN=BsN%Cy536jIoR-rkt=B45{`4sYq>cC^F^>AF|vjN8OUXMl)BCyP+c z7y`nQ3Rrb+0bg8ll~pvb{m5WHN|?{5bNl%~jO3%Q7c_!Vv$!?1*}#VnFWfFwo83o> zWYwy8A>N%RdU;;^)p_xVb4M2+Uc6PH7MxyuM_GTigB=At1I6Ub(!Z{Xk z?<>-l0@f(VvMzKcscRLrOMJ)0l^+o#@vVZdFTUT$IN2n=NljhyBwl4zXU_e2tySve zKD6P5GwxKR$=ZvQ3tiTnD|b!RKLu;)esc<+tJGZHGg^9)!R+b4Z9e_6do&Wc$NECe z`Bho*7vQ~zs;(Z=>^wARs?unERze*yc4GCdHPx-YC%WcD~IiA?Cj?i1qKnGGK z+fa=v?6%Z9*HXVBBL{oeq1OdJvOM;>cU6{61ltDjpe%+{c~`veXjSjK`6Jt4=*?_& z%GxUzZeE%_tf#JsgstjJ+R#^jUi@L)5w9p08@A^CUc!m{IktG2@5QM&mhuHY=?jyk z8ij0q8 zL#xZQ?^y7~)^s{z^>@7en_;RDP%?AJIySIF&6mx0S#`seZ*y)Q8nP6Pk=q+Cfsc6_ zK8{|aAyz+pHw=SSzM`~l80~!pWds15eLRzP>c)H@2|cAdmNu+8a$YY_VSm*f`_hqk z$5C%x^3Vo`0MRUDqs8mlz%gBBeTYYQuV+UpaJY51c?1eYOJyfqsFREIb48_N@sxmD zejh47J~d?p42$SelJF0~mrY+zx0&6cFaCV2I>-4)&auq6w4y6VW3aflf~ObXM-BfoxWanlYZ6jgcs`Skd!vXKcMUJ z9ib;`LsGY2UjAHAceV17?P9uyzpFVjow8N7%-g7pgwkn3*=0|hBH<&k=gvHDKPuP} z^c`QmCaWzA5b&Ky5kt8ti`7j{V)v(~)S}&P;4L_K>4#Fm?LcN6K;x{pP6EgS_=c_y zV+BS+EATTfjc*_g5i>z*p454}K4oDdlQyYij!!`{$^s^L<>X`XCoha77C0i;S7XY~ zIoJ28jHZ#!h1xb_fv_#IZu{Lox!${*gTH2ibfqZl^cl^+<7(! zWJ|{^&29-{aU>vBrC~&e9n7w8eEjJ28?$)k`>%%RleA*VH1m2mX@rF>O|%e-18|cA z!LbF$G-Z6YYCHzsPsvNZm>j0d&RCqE5HeSg+P!GQMR951MARD%G{- zXtokPN0d3riqG$t(cVN%3?&aB$Py2)?tW6L0eq?$Q#x923RqZP!j1vx(ZWSgiQ_bO&OU_Dbl9|_D?CXr+gkyH7aCLG@t712lQf| zlFX+}g`ZMSQ^5bu1uIS1{7ADa_g&-rh1~<`Ik)OG;O(imyGo`0f75eX=Dq3k4=<@F zZ*P5v^m**}^c?He%B2oTa5;fpcdff8c3CLcjmIm#l_u_gDi;GNlusz{0#wKEYRGyA z@;}wle5y=+Y9Ko$cj+lb_?e(w=-V^3Y3-`kZT8Xzi0ze*WB9rZ+ILg0{-QlOBd>o- znKJKadFky%tzGk7dGIHty7ATRd}!R;z?}6@^F`T4q*|NnleYzG-&g2LEjzg27@9yT zOp!yaf}@w@R~%f}86JvNRFD1ntq;Hc@yZI?o4Y0_O6urWsz=cdZ#Ma!{3iHSklxZ< z0o!dDD5#7y(L=VHAnj7{wlKhogZPxt)PE4R;Zh}RG06D<C^ZsCP~A7(J5v9- z81_Y;eiheb&jdde0lsVw`nzeOy3@mWg)Um@mBZ}mjID(JZEN~h&en`riR+vf|H*1L zF6I3?Q7B*$4%hdG8xi2wik&F2a9s*~SQ!qs8g}-CL{xQVy*Sdpb zu*DDqAL9pCa8A0Nc?O^Y)I3c6Yh4U9I(Su=lc&wQmk70h?b;K0kB-0Afx)Nj;20^m zE_MHm^?qYDNONs^MxQ1eQ=g|B3pY~B)9eK== z;{pVuz}B;WgjMkAR)JGTfy>M>|Ls3i8xGpc9AvL4Fk3WM_4iOsJ==KlY+{_m6sa)M zJGJ2aS$W$wC!q0^_BnAI#4P-{$T~;iAqc%f##kp$RD`djV~L5Nrf+J+zmZTTJV;lF ztUBcg`knT*!`hPujot-Vj~%RNh6W`yl_=(qZa*@YVKc_FSlOiuTUM?yq9|Z5iJN*B zm>VmIYe6x-s{EOiYvV$XUgO1sD8>UP+N%f*UpKCBhuWj$TsQwL*%=u6G}k`) z3E>oEa}w^e00rU!P($AAjwA4xNy+A}8Caf)s3j_yeei*3fq5?wME!ED`i&J4X+<}C z;3mh58bMR=5sB#gy+AOZNCbu8$8ONKgJu-d`Nx3dg_V9yWc&JtAYzst@j>i_tP%I` zfHHJ!7zwWuLaW4@LNa|D!B4d3io(x+P*BUSQ4K=Jb=u9=03f6x8Hz5bfNR5n4NYTX z!=8edM`=$!wqE#U)h|*rZ|}V-*EmwkF{(MF32s0QELSqJxojbOh8h|pS z~xgg7i{FLd)vPzxF zjgN`3$o236I%S%;P5$IY#kxpB-#W`idARRjUYaE8-jP6`7?f1EhETF%kU6t;$a53M zqBYln$%oyqO;9q`XG|bt8gg~^BYh`O+HAmz@&r1jz*Q-T+saSDt2$64+zkaVzym6D z0LE2PDJ^nwbcNw^2xm@*At z3<_i4!gX0(Y@8i7ap4I=4*i7z4I(C%3G{RY&?n>`c_NEGLA?bIc5Y$9=oq9U2Vu=A zr%F3fE0=ZKFzsqO2DpD6zFAFj_$ei3L z&`H9e1u$}Y6S6!D@Su)lNJKGV@)!x?+Wjhn;6tMTuif$qW8VI+u_k08O+ZsWLs15S z|2ilyn!x#T$I@p4YM2(@jbPGW(nJ*{v;!>wL%IyomrM=nImqg_3yx_})iM81F~t1) za-Cn(>E{9_1_OcTUsL~V5=#$0lND_o@kps6hZ21+#l zM2nCO;+?>sdqL%O{geOqL3uuM{5>cS{2VAcz#0AP_J7R?%xh5R|DyqkzoO|^D1mXr z)AoOc6WED5itB~H%=}jG3OD74%*(96xH#?qQai<>Q7BT>m#!|$wmj((WNeNKF zkM>G0cz!UEDiwDv{;d)i*Pu#E6x4V!1|||gR6(dY{lQEMT#X8c7={=7U?+MAZ5h0K z!&vmBbSRLLom@S|GC@djvF(6{bE!rx1-b8PI0K1qK;`6o{sH_r4{;L;nt5(8#}t0t^i+%n1LJ=VJvHft$tm0;Eva zf8fEW0WkVo-o@E5b}|BnW`c{I!;Xt`22Bifp_KCG1}=2}M%}+g1nHua+tpugg$9+| zmq@Qm)j@+q4OaWx{L!F!E7kzIoQ~f^%m4E7zh6f}%++jfZih^Z^ z!{0LkY2oh(<&oja8gvrZaq<*+#lBw_OI@-JD)DfF@?*iYb>I*i z<4ckK0TBK{NcTedalp$_?(uV2b}?T>wL69|vJQMUcM01cMcyySQ~!Z&ZsGtlDdVtH zk4wc!Ji5WMKa6_1BS6ue7nlzWhgmR>PQV>h9%5ib&rJJC z*%6btf{p;0;|0n&yKjSRrpw8_*QnpbP#s;@U*=>&Btj*Vsy|wl-m9Yt2a7QsN^}w% zV3D3CvVm=#cpYD~D$FUfFi>Nqw1oL|)1ue|Yqq6@wnz26*oc0R3-z8hQ`HJ}^l%G( z&>?7mki>Lgg^d64CO5&E@XWYPyov>rC&EE<>7S`?j38y=f2HP5)YCg6@!+Md0Pqr2 z%)^-Al!?SYA?J z1PTTuI=#OW2bhRs^|K?2v0Ype-dI+eCr3zKInG0@DryJ|F&;Q0?Q_Hns>3dISi?R@ z!!a4}#;Z7sj|%sAYXL6T@p|T^r{8Ko9oSOpC>5{*=0${e{6?Kqe9ga(y@Ky@kv4l2Z@cca6H5ol;OOPki~ zk$TjzyX_X?d$vx1Kf11f@NcU0A76LnIe`lmsKPuBB!OixNW~!ivVla(w9+ZRL=NRb z`GRSTAmWN+}*Wca_E2r?#bWeO_%D|jKadqPHg%i@|Y z1qXr|K32A+6Ux8WB6uYSw_4!Z_H89sjEi~r-n6jJrGVwbANM&eg2pZ_Qoss)Go>Pw zDm~u!o}fB^?7^cinMzv==7k%1`*j2!)Oj_J*RPuAPxbP88@`C^ks@BYd zhEA|5{kC!!0;_LZz&t(aOLZMo9SKmDYJM{K<{>7G8_@ub=UHwAJ}zCoj65Gm#b%4y zYw|WXepf^_e;~9}?sE4=cnbWViI-P9%{Uma$o~(_OV!|He)U*%M5S@8|329N)t}z* zyz9leTSW|X0tiamHL$zV`9)MW z+-Ru0vIisQP-fRyb#^i(!QARI>Djz+fc+(pbb+0IHs8x+$C1mQ3y@>d$LM7K?3|2)c z?}%PhUm5<;)L&3ur;!>~eNxNNpi{FXE=)-|8h?mFARSifRYXSRa zc8cuJMhFt)p0}iW5);Q}OUDh}!(YZ`4Qy+^EJD&EQih6~}K+h~(L`BGn|GJ;<|R6(=jEh_hI z=c_M>bwH*0(9D75TlzDqa?>W_j#}i*j&;o7PBxx@=UO=Gwf}-?xo|%%90IvJ%}sY>33?j;p92N6DM2h z!Ka2y8Ao27F5OAXI30AO(s066BLs!7P*T6s-GA=Xy9)+`#4SL~2^I=JRM=?q>dbkw z)r6LyP}8>oTBc$yp$EXcO1yy)dwip0=*a$1c8XNin!WU^qop(cavr7&8LO9VUsxCw z54}Bvl!(c05Pd{RV5N-<6r|evDEDxFH0@M3z5XG=T5J2elDcx1ufM#+H|L$iq`UqxdBadMd`b4uE$AP>Lk29zj8h2P0x za&^&j?7=RQt!mdk-|A5R~abEOVd=|ZhB>XO4Vh=4!r*#>b{~7uirK~Sox84O;P0u8Q zU(Y*T)hF>`vlZ>fnOyMU8o^rS+gc`-f@}SOhfFz(FTITsPMrtd6}e`rE++|CZB6qW ztP*cap;~;zF56Ib!%p{RKuJt?IlgF$f-B*-Q4M5?Zm`a*Ev5!oGx}!xn3lRP^ABx! zq~uO-xPjT>lHA%y);6>%4^mvG6f{@3>x(5i0tiXEo8d>BpwVSyN`D8aFbxZVQ*Ku|HTuMZTIwV3WXl^4qqw9S0X2RQ!lf&+g_IL5A?bwow*Uu z7aBBi{WkfdoIPyV=QNO30^B_9SsLZ5*1uk&vw%g3mJ%DJdK-v2hV<*aiE%lPm#`DE z^HaZ5iK}fMZCenErLC>qDgczUlC-7|TggsS({5epHC3jc-oLff>)mim#Jl%HTtWg-)h)*Yop5AyaobrK4@K`;I62h;Qy^8xQn$A=Bg@ zg`(GI8CpAE+;;cfb_Mk*!QJ!S2RDyOtm&UvaQeKtR7Oi+np0$)yRSvWAnpYtmOlAL z53vfFDnRwOSR;J5m<*dU>P;WgE`+V{JaQy&BG6mTSYJrq%xA6N%ma0&*7|Md6>XdB z5oTgEGfYsxt8VM>l@N=L6q(rO8GAo%`G)H^L}K|+N`s{zruERnsE3JFCuV9o zwnmuT?ina;b9UUM+V}POyMYZ0s*J14oiPPsK4Go+6{?r=(HEb8}M5(3dC|a397_OekT}h-~b1qYUjqUB?aIz z-c}mU=L+11$Js36uRCrB5KDZtG2tmyb@`8BzOu~LGwU3zffcjG>8=?+*Z1= zSTB;a3;q2hO(EVheQ=GO#L4VK7a~)ylx4(-)-=e!4b*}QxL&c8i3+gWh`-{$V{^b{ zJIvBYd8cb}d_m2`w-doeyRJK6Ref1}_({+F<+BGk zkBRdGTEjw7gX1skIa$Vg%hilO?ege;g2M;dSy-;zxH!WBwB53-EVl?8^QD}Z?WDdW z5fj2~ksJ4f8XLL`vf~9on!TSQ{5b_9nTj(?6=kG~Z%vgfPL*m;mA;=U`#F^;nMO8B XlV_wUZcS4zPE&19Q@@|4ivIrq +#include "uucp.h" + +int LocalOnly = 0; + +/*LINTLIBRARY*/ + +/* + * start up uucico for rmtname + * + * return codes: none + */ + +#ifdef VMS +#define fork vfork +#endif + +xuucico(rmtname) +char *rmtname; +{ + if (fork() == 0) { + /* start uucico for rmtname system */ + char opt[100]; + close(0); + close(1); + close(2); + open(DEVNULL, 0); + open(DEVNULL, 1); + open(DEVNULL, 1); + signal(SIGINT, SIG_IGN); + signal(SIGHUP, SIG_IGN); + signal(SIGQUIT, SIG_IGN); + signal(SIGKILL, SIG_IGN); + if (rmtname[0] != '\0') + sprintf(opt, "-s%s", rmtname); + else + opt[0] = '\0'; +#ifndef VMS + if (LocalOnly) + execl(UUCICO, "uucico", "-r1", "-L", opt, (char *)0); + else + execl(UUCICO, "uucico", "-r1", opt, (char *)0); +#else + /* Under VMS/EUNICE release the batch job */ + if (LocalOnly) + execl(STARTUUCP, "startuucp", "uucico", "-r1", "-L", opt, (char *)0); + else + execl(STARTUUCP, "startuucp", "uucico", "-r1", opt, (char *)0); +#endif + exit(100); + } +#ifdef VMS + while(wait(0) != -1) + ; /* Wait for it to finish!! */ +#endif + return; +} + + +/* + * start up uuxqt + * + * return codes: none + */ + +xuuxqt() +{ + if (fork() == 0) { + /* start uuxqt */ + close(0); + close(1); + close(2); + open(DEVNULL, 2); + open(DEVNULL, 2); + open(DEVNULL, 2); + signal(SIGINT, SIG_IGN); + signal(SIGHUP, SIG_IGN); + signal(SIGQUIT, SIG_IGN); + signal(SIGKILL, SIG_IGN); + execl(UUXQT, "UUXQT", (char *)0); + exit(100); + } + return; +} + +xuucp(str) +char *str; +{ + char text[300]; + if (fork() == 0) { + /* start uucp */ + close(0); + close(1); + close(2); + open(DEVNULL, 0); + open(DEVNULL, 1); + open(DEVNULL, 1); + signal(SIGINT, SIG_IGN); + signal(SIGHUP, SIG_IGN); + signal(SIGQUIT, SIG_IGN); + signal(SIGKILL, SIG_IGN); + sprintf(text, "%s -r %s", UUCP, str); + execl(SHELL, "sh", "-c", text, CNULL); + exit(100); + } + sleep(15); /* Give uucp chance to finish */ + return; +} diff --git a/src/cmd/vipw/Makefile b/src/cmd/vipw/Makefile new file mode 100644 index 0000000..9f0cbd4 --- /dev/null +++ b/src/cmd/vipw/Makefile @@ -0,0 +1,55 @@ +# +# 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 redistribution 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. +# +TOPSRC = $(shell cd ../../..; pwd) +include $(TOPSRC)/target.mk + +CFLAGS += -Werror + +SRCS = vipw.c +OBJS = vipw.o +MAN = vipw.0 +MANSRC = vipw.8 + +all: vipw ${MAN} + +vipw: ${OBJS} + ${CC} ${LDFLAGS} -o vipw.elf ${OBJS} ${LIBS} + ${OBJDUMP} -S vipw.elf > vipw.dis + ${SIZE} vipw.elf + ${ELF2AOUT} vipw.elf $@ && rm vipw.elf + +${MAN}: ${MANSRC} + ${MANROFF} ${MANSRC} > ${MAN} + +clean: + rm -f *.o *.elf ${MAN} vipw *.elf *.dis tags *~ + +cleandir: clean + rm -f tags .depend + +depend: ${SRCS} + mkdep ${CFLAGS} ${SRCS} + +install: all + install vipw ${DESTDIR}/sbin/ + cp ${MAN} ${DESTDIR}/share/man/cat8/ + +lint: ${SRCS} + lint ${CFLAGS} ${SRCS} + +tags: ${SRCS} + ctags ${SRCS} diff --git a/src/cmd/vipw/vipw.8 b/src/cmd/vipw/vipw.8 new file mode 100644 index 0000000..72759bd --- /dev/null +++ b/src/cmd/vipw/vipw.8 @@ -0,0 +1,53 @@ +.\" Copyright (c) 1983 The Regents of the University of California. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms are permitted +.\" provided that the above copyright notice and this paragraph are +.\" duplicated in all such forms and that any documentation, +.\" advertising materials, and other materials related to such +.\" distribution and use acknowledge that the software was developed +.\" by the University of California, Berkeley. The name of the +.\" University may not be used to endorse or promote products derived +.\" from this software without specific prior written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR +.\" IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED +.\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.\" @(#)vipw.8 6.4 (Berkeley) 3/11/89 +.\" +.TH VIPW 8 "March 11, 1989" +.UC 4 +.SH NAME +vipw \- edit the password file +.SH SYNOPSIS +.B vipw +.SH DESCRIPTION +.I Vipw +edits the password file while setting the appropriate locks, +and does any necessary processing after the password file is unlocked. +If the password file is already being edited, then you will be told +to try again later. +The +.I vi +editor will be used unless the environment variable EDITOR indicates +an alternate editor. +.PP +.I Vipw +performs a number of consistency checks on the password entries, +and will not allow a password file with a ``mangled'' entry to be +installed. +If +.I vipw +rejects the new password file, the user is prompted to re-enter +the edit session. +.PP +Once the information has been verified, +.I vipw +uses +.IR mkpasswd (8) +to update the user database. This is run in the background, and, +at very large sites could take several minutes. Until this update +is completed, the password file is unavailable for other updates +and the new information will not be available to programs. +.SH SEE ALSO +chpass(1), passwd(1), passwd(5), adduser(8), mkpasswd(8) diff --git a/src/cmd/vipw/vipw.c b/src/cmd/vipw/vipw.c new file mode 100644 index 0000000..ccbffe2 --- /dev/null +++ b/src/cmd/vipw/vipw.c @@ -0,0 +1,267 @@ +/* + * Copyright (c) 1987 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. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +char *passwd, *temp; + +main() +{ + register int n, fd_passwd, fd; + struct rlimit rlim; + struct stat s1, s2; + FILE *tfp; + char *fend, *tend; + char buf[1024], from[MAXPATHLEN], to[MAXPATHLEN]; + + (void)signal(SIGHUP, SIG_IGN); + (void)signal(SIGINT, SIG_IGN); + (void)signal(SIGQUIT, SIG_IGN); + (void)signal(SIGTSTP, SIG_IGN); + + rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY; + (void)setrlimit(RLIMIT_CPU, &rlim); + (void)setrlimit(RLIMIT_FSIZE, &rlim); + + (void)umask(0); + + temp = _PATH_PTMP; + if ((fd = open(temp, O_RDWR|O_CREAT|O_EXCL, 0600)) < 0) { + if (errno == EEXIST) + (void)fprintf(stderr, "vipw: password file busy.\n"); + else + (void)fprintf(stderr, + "vipw: %s: %s\n", temp, strerror(errno)); + exit(1); + } + passwd = _PATH_SHADOW; + if ((fd_passwd = open(passwd, O_RDONLY, 0)) < 0) { + (void)fprintf(stderr, "vipw: %s: %s\n", passwd, + strerror(errno)); + exit(1); + } + while ((n = read(fd_passwd, buf, sizeof(buf))) > 0) + if (write(fd, buf, n) != n) + goto syserr; + + if (n == -1 || close(fd_passwd)) { +syserr: (void)fprintf(stderr, "vipw: %s: %s; ", + passwd, strerror(errno)); + stop(1); + } + if (!(tfp = fdopen(fd, "r"))) { + (void)fprintf(stderr, "vipw: %s: %s; ", + temp, strerror(errno)); + stop(1); + } + + for (;;) { + (void)fstat(fd, &s1); + if (edit()) { + (void)fprintf(stderr, "vipw: edit failed; "); + stop(1); + } + (void)fstat(fd, &s2); + if (s1.st_mtime == s2.st_mtime) { + (void)fprintf(stderr, "vipw: no changes made; "); + stop(0); + } + rewind(tfp); + if (!check(tfp)) + break; + if (prompt()) + stop(0); + } + + switch(fork()) { + case 0: + break; + case -1: + (void)fprintf(stderr, "vipw: can't fork; "); + stop(1); + /* NOTREACHED */ + default: + exit(0); + /* NOTREACHED */ + } + + if (makedb(temp)) { + (void)fprintf(stderr, "vipw: mkpasswd failed; "); + stop(1); + } + + /* + * possible race; have to rename four files, and someone could slip + * in between them. LOCK_EX and rename the ``passwd.dir'' file first + * so that getpwent(3) can't slip in; the lock should never fail and + * it's unclear what to do if it does. Rename ``ptmp'' last so that + * passwd/vipw/chpass can't slip in. + */ + (void)setpriority(PRIO_PROCESS, 0, -20); + fend = strcpy(from, temp) + strlen(temp); + tend = strcpy(to, _PATH_PASSWD) + strlen(_PATH_PASSWD); + bcopy(".dir", fend, 5); + bcopy(".dir", tend, 5); + if ((fd = open(from, O_RDONLY, 0)) >= 0) + (void)flock(fd, LOCK_EX); + /* here we go... */ + (void)rename(from, to); + bcopy(".pag", fend, 5); + bcopy(".pag", tend, 5); + (void)rename(from, to); + bcopy(".orig", fend, 6); + (void)rename(from, _PATH_PASSWD); + (void)rename(temp, passwd); + /* done! */ + exit(0); +} + +check(tfp) + FILE *tfp; +{ + long id; + int root; + register int lcnt; + register char *p, *sh; + char buf[256], *getusershell(); + char *bp; + + for (lcnt = 1; fgets(buf, sizeof(buf), tfp); ++lcnt) { + bp = buf; + /* skip lines that are too big */ + if (!(p = index(buf, '\n'))) { + (void)fprintf(stderr, "vipw: line too long"); + goto bad; + } + *p = '\0'; + if (!(p = strsep(&bp, ":"))) /* login */ + goto general; + root = !strcmp(p, "root"); + (void)strsep(&bp, ":"); /* passwd */ + if (!(p = strsep(&bp, ":"))) /* uid */ + goto general; + id = atol(p); + if (root && id) { + (void)fprintf(stderr, "vipw: root uid should be 0"); + goto bad; + } + if (id > USHRT_MAX) { + (void)fprintf(stderr, "vipw: %s > max uid value (%u)", + p, USHRT_MAX); + goto bad; + } + if (!(p = strsep(&bp, ":"))) /* gid */ + goto general; + id = atol(p); + if (id > USHRT_MAX) { + (void)fprintf(stderr, "vipw: %s > max gid value (%u)", + p, USHRT_MAX); + goto bad; + } + (void)strsep(&bp, ":"); /* gecos */ + (void)strsep(&bp, ":"); /* directory */ + if (!(p = strsep(&bp, ":"))) /* shell */ + goto general; + if (root && *p) /* empty == /bin/sh */ + for (setusershell();;) + if (!(sh = getusershell())) { + (void)fprintf(stderr, + "vipw: warning, unknown root shell.\n"); + break; + } + else if (!strcmp(p, sh)) + break; + if (strsep(&bp, ":")) { /* too many */ +general: (void)fprintf(stderr, "vipw: corrupted entry"); +bad: (void)fprintf(stderr, "; line #%d.\n", lcnt); + (void)fflush(stderr); + return(1); + } + } + return(0); +} + +makedb(file) + char *file; +{ + int status, pid, w; + + if (!(pid = vfork())) { + execl(_PATH_MKPASSWD, "mkpasswd", "-p", file, NULL); + _exit(127); + } + while ((w = wait(&status)) != pid && w != -1); + return(w == -1 || status); +} + +edit() +{ + int status, pid, w; + char *p, *editor; + + if (editor = getenv("EDITOR")) { + if (p = rindex(editor, '/')) + ++p; + else + p = editor; + } + else + p = editor = "vi"; + if (!(pid = vfork())) { + execlp(editor, p, temp, NULL); + (void)fprintf(stderr, "vipw: %s: %s\n", editor, + strerror(errno)); + _exit(127); + } + while ((w = wait(&status)) != pid && w != -1); + return(w == -1 || status); +} + +prompt() +{ + register int c; + + for (;;) { + (void)printf("re-edit the password file? [y]: "); + (void)fflush(stdout); + c = getchar(); + if (c != EOF && c != (int)'\n') + while (getchar() != (int)'\n'); + return(c == (int)'n'); + } + /* NOTREACHED */ +} + +stop(val) + int val; +{ + (void)fprintf(stderr, "%s unchanged.\n", passwd); + (void)unlink(temp); + exit(val); +} diff --git a/src/cmd/virus/Makefile b/src/cmd/virus/Makefile new file mode 100644 index 0000000..8dbdedf --- /dev/null +++ b/src/cmd/virus/Makefile @@ -0,0 +1,15 @@ +TOPSRC = $(shell cd ../../..; pwd) +include $(TOPSRC)/target.mk + +CFLAGS += -Wall -Werror -Os + +virus: virus.c + $(CC) $(LDFLAGS) -o virus.elf virus.c $(LIBS) -ltermcap + $(SIZE) virus.elf + $(ELF2AOUT) virus.elf $@ + +install: virus + install virus ${DESTDIR}/bin/vi + +clean: + rm -f *.o virus.elf virus diff --git a/src/cmd/virus/lib/last_char_is.c b/src/cmd/virus/lib/last_char_is.c new file mode 100644 index 0000000..859c864 --- /dev/null +++ b/src/cmd/virus/lib/last_char_is.c @@ -0,0 +1,39 @@ +/* + * busybox library eXtended function + * + * Copyright (C) 2001 Larry Doolittle, + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include + +/* Find out if the last character of a string matches the one given Don't + * underrun the buffer if the string length is 0. Also avoids a possible + * space-hogging inline of strlen() per usage. + */ +char * last_char_is(const char *s, int c) +{ + char *sret; + if (!s) + return NULL; + sret = (char *)s+strlen(s)-1; + if (sret>=s && *sret == c) { + return sret; + } else { + return NULL; + } +} diff --git a/src/cmd/virus/lib/strlcat.c b/src/cmd/virus/lib/strlcat.c new file mode 100644 index 0000000..b309648 --- /dev/null +++ b/src/cmd/virus/lib/strlcat.c @@ -0,0 +1,73 @@ +/* $OpenBSD: strlcat.c,v 1.8 2001/05/13 15:40:15 deraadt Exp $ */ + +/* + * Copyright (c) 1998 Todd C. Miller + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char *rcsid = "$OpenBSD: strlcat.c,v 1.8 2001/05/13 15:40:15 deraadt Exp $"; +#endif /* LIBC_SCCS and not lint */ + +#include +#include + +/* + * Appends src to string dst of size siz (unlike strncat, siz is the + * full size of dst, not space left). At most siz-1 characters + * will be copied. Always NUL terminates (unless siz <= strlen(dst)). + * Returns strlen(src) + MIN(siz, strlen(initial dst)). + * If retval >= siz, truncation occurred. + */ +size_t +strlcat(dst, src, siz) + char *dst; + const char *src; + size_t siz; +{ + register char *d = dst; + register const char *s = src; + register size_t n = siz; + size_t dlen; + + /* Find the end of dst and adjust bytes left but don't go past end */ + while (n-- != 0 && *d != '\0') + d++; + dlen = d - dst; + n = siz - dlen; + + if (n == 0) + return(dlen + strlen(s)); + while (*s != '\0') { + if (n != 1) { + *d++ = *s; + n--; + } + s++; + } + *d = '\0'; + + return(dlen + (s - src)); /* count does not include NUL */ +} diff --git a/src/cmd/virus/lib/strlcpy.3 b/src/cmd/virus/lib/strlcpy.3 new file mode 100644 index 0000000..8bb1b3a --- /dev/null +++ b/src/cmd/virus/lib/strlcpy.3 @@ -0,0 +1,190 @@ +.\" $OpenBSD: strlcpy.3,v 1.13 2001/06/18 22:29:59 millert Exp $ +.\" +.\" Copyright (c) 1998, 2000 Todd C. Miller +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. The name of the author may not be used to endorse or promote products +.\" derived from this software without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, +.\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY +.\" AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +.\" THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +.\" EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +.\" PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +.\" OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +.\" WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +.\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +.\" ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.Dd June 22, 1998 +.Dt STRLCPY 3 +.Os +.Sh NAME +.Nm strlcpy , +.Nm strlcat +.Nd size-bounded string copying and concatenation +.Sh SYNOPSIS +.Fd #include +.Ft size_t +.Fn strlcpy "char *dst" "const char *src" "size_t size" +.Ft size_t +.Fn strlcat "char *dst" "const char *src" "size_t size" +.Sh DESCRIPTION +The +.Fn strlcpy +and +.Fn strlcat +functions copy and concatenate strings respectively. +They are designed +to be safer, more consistent, and less error prone replacements for +.Xr strncpy 3 +and +.Xr strncat 3 . +Unlike those functions, +.Fn strlcpy +and +.Fn strlcat +take the full size of the buffer (not just the length) and guarantee to +NUL-terminate the result (as long as +.Fa size +is larger than 0 or, in the case of +.Fn strlcat , +as long as there is at least one byte free in +.Fa dst ) . +Note that you should include a byte for the NUL in +.Fa size . +Also note that +.Fn strlcpy +and +.Fn strlcat +only operate on true +.Dq C +strings. +This means that for +.Fn strlcpy +.Fa src +must be NUL-terminated and for +.Fn strlcat +both +.Fa src +and +.Fa dst +must be NUL-terminated. +.Pp +The +.Fn strlcpy +function copies up to +.Fa size +- 1 characters from the NUL-terminated string +.Fa src +to +.Fa dst , +NUL-terminating the result. +.Pp +The +.Fn strlcat +function appends the NUL-terminated string +.Fa src +to the end of +.Fa dst . +It will append at most +.Fa size +- strlen(dst) - 1 bytes, NUL-terminating the result. +.Sh RETURN VALUES +The +.Fn strlcpy +and +.Fn strlcat +functions return the total length of the string they tried to create. +For +.Fn strlcpy +that means the length of +.Fa src . +For +.Fn strlcat +that means the initial length of +.Fa dst +plus +the length of +.Fa src . +While this may seem somewhat confusing it was done to make +truncation detection simple. +.Pp +Note however, that if +.Fn strlcat +traverses +.Fa size +characters without finding a NUL, the length of the string is considered +to be +.Fa size +and the destination string will not be NUL-terminated (since there was +no space for the NUL). +This keeps +.Fn strlcat +from running off the end of a string. +In practice this should not happen (as it means that either +.Fa size +is incorrect or that +.Fa dst +is not a proper +.Dq C +string). +The check exists to prevent potential security problems in incorrect code. +.Sh EXAMPLES +The following code fragment illustrates the simple case: +.Bd -literal -offset indent +char *s, *p, buf[BUFSIZ]; + +\&... + +(void)strlcpy(buf, s, sizeof(buf)); +(void)strlcat(buf, p, sizeof(buf)); +.Ed +.Pp +To detect truncation, perhaps while building a pathname, something +like the following might be used: +.Bd -literal -offset indent +char *dir, *file, pname[MAXPATHLEN]; + +\&... + +if (strlcpy(pname, dir, sizeof(pname)) >= sizeof(pname)) + goto toolong; +if (strlcat(pname, file, sizeof(pname)) >= sizeof(pname)) + goto toolong; +.Ed +.Pp +Since we know how many characters we copied the first time, we can +speed things up a bit by using a copy instead of an append: +.Bd -literal -offset indent +char *dir, *file, pname[MAXPATHLEN]; +size_t n; + +\&... + +n = strlcpy(pname, dir, sizeof(pname)); +if (n >= sizeof(pname)) + goto toolong; +if (strlcpy(pname + n, file, sizeof(pname) - n) >= sizeof(pname) - n) + goto toolong; +.Ed +.Pp +However, one may question the validity of such optimizations, as they +defeat the whole purpose of +.Fn strlcpy +and +.Fn strlcat . +As a matter of fact, the first version of this manual page got it wrong. +.Sh SEE ALSO +.Xr snprintf 3 , +.Xr strncat 3 , +.Xr strncpy 3 diff --git a/src/cmd/virus/lib/strlcpy.c b/src/cmd/virus/lib/strlcpy.c new file mode 100644 index 0000000..5f58696 --- /dev/null +++ b/src/cmd/virus/lib/strlcpy.c @@ -0,0 +1,69 @@ +/* $OpenBSD: strlcpy.c,v 1.5 2001/05/13 15:40:16 deraadt Exp $ */ + +/* + * Copyright (c) 1998 Todd C. Miller + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char *rcsid = "$OpenBSD: strlcpy.c,v 1.5 2001/05/13 15:40:16 deraadt Exp $"; +#endif /* LIBC_SCCS and not lint */ + +#include +#include + +/* + * Copy src to string dst of size siz. At most siz-1 characters + * will be copied. Always NUL terminates (unless siz == 0). + * Returns strlen(src); if retval >= siz, truncation occurred. + */ +size_t +strlcpy(dst, src, siz) + char *dst; + const char *src; + size_t siz; +{ + register char *d = dst; + register const char *s = src; + register size_t n = siz; + + /* Copy as many bytes as will fit */ + if (n != 0 && --n != 0) { + do { + if ((*d++ = *s++) == 0) + break; + } while (--n != 0); + } + + /* Not enough room in dst, add NUL and traverse rest of src */ + if (n == 0) { + if (siz != 0) + *d = '\0'; /* NUL-terminate dst */ + while (*s++) + ; + } + + return(s - src - 1); /* count does not include NUL */ +} diff --git a/src/cmd/virus/virus.c b/src/cmd/virus/virus.c new file mode 100644 index 0000000..ea613fc --- /dev/null +++ b/src/cmd/virus/virus.c @@ -0,0 +1,4002 @@ +/* vi: set sw=8 ts=8: */ +/* + * virus - vi resembling utility skeleton - based on + * tiny vi.c: A small 'vi' clone (from busybox 0.52) + * + * Copyright (C) 2001 - 2003 Stefan Koerner + * Copyright (C) 2000, 2001 Sterling Huxley + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +char *vi_Version = + "$Id: virus.c,v 0.0.6 2003/09/08 13:07:21 ripclaw Exp $"; + +/* + * To compile: + * gcc -Wall -Os -s -o vi virus.c + * strip vi + */ + +/* this was in here from busybox, will sort out later FIXME + * Things To Do: + * EXINIT + * $HOME/.exrc and ./.exrc + * add magic to search /foo.*bar + * add :help command + * :map macros + * how about mode lines: vi: set sw=8 ts=8: + * if mark[] values were line numbers rather than pointers + * it would be easier to change the mark when add/delete lines + * More intelligence in refresh() + * ":r !cmd" and "!cmd" to filter text through an external command + * A true "undo" facility + * An "ex" line oriented mode- maybe using "cmdedit" + */ + +//---- Feature -------------- Bytes to immplement +#define vi_main main +#define BB_FEATURE_VI_COLON // 4288 +#define BB_FEATURE_VI_YANKMARK // 1408 +#define BB_FEATURE_VI_SEARCH // 1088 +#define BB_FEATURE_VI_USE_SIGNALS // 1056 +#define BB_FEATURE_VI_DOT_CMD // 576 +#define BB_FEATURE_VI_READONLY // 128 +#define BB_FEATURE_VI_SETOPTS // 576 +#define BB_FEATURE_VI_SET // 224 +#define BB_FEATURE_VI_WIN_RESIZE // 256 WIN_RESIZE +// To test editor using CRASHME: +// vi -C filename +// To stop testing, wait until all to text[] is deleted, or +// Ctrl-Z and kill -9 %1 +// while in the editor Ctrl-T will toggle the crashme function on and off. +//#define BB_FEATURE_VI_CRASHME // randomly pick commands to execute + +#include +#include +#include +//#include +#include +#include +#include +#include +#include +//#include +#include +#include +#include +//#include +#include +#include +#include +//#include +#include + +#include "lib/last_char_is.c" +#include "lib/strlcat.c" +#include "lib/strlcpy.c" + +#ifndef TRUE +#define TRUE ((int)1) +#define FALSE ((int)0) +#endif /* TRUE */ +#define MAX_SCR_COLS BUFSIZ +#define BUFSIZ_STATBUF 200 +#define termios sgttyb + +// Misc. non-Ascii keys that report an escape sequence +#define VI_K_UP 128 // cursor key Up +#define VI_K_DOWN 129 // cursor key Down +#define VI_K_RIGHT 130 // Cursor Key Right +#define VI_K_LEFT 131 // cursor key Left +#define VI_K_HOME 132 // Cursor Key Home +#define VI_K_END 133 // Cursor Key End +#define VI_K_INSERT 134 // Cursor Key Insert +#define VI_K_PAGEUP 135 // Cursor Key Page Up +#define VI_K_PAGEDOWN 136 // Cursor Key Page Down +#define VI_K_FUN1 137 // Function Key F1 +#define VI_K_FUN2 138 // Function Key F2 +#define VI_K_FUN3 139 // Function Key F3 +#define VI_K_FUN4 140 // Function Key F4 +#define VI_K_FUN5 141 // Function Key F5 +#define VI_K_FUN6 142 // Function Key F6 +#define VI_K_FUN7 143 // Function Key F7 +#define VI_K_FUN8 144 // Function Key F8 +#define VI_K_FUN9 145 // Function Key F9 +#define VI_K_FUN10 146 // Function Key F10 +#define VI_K_FUN11 147 // Function Key F11 +#define VI_K_FUN12 148 // Function Key F12 + +static const int YANKONLY = FALSE; +static const int YANKDEL = TRUE; +static const int FORWARD = 1; // code depends on "1" for array index +static const int BACK = -1; // code depends on "-1" for array index +static const int LIMITED = 0; // how much of text[] in char_search +static const int FULL = 1; // how much of text[] in char_search + +static const int S_BEFORE_WS = 1; // used in skip_thing() for moving "dot" +static const int S_TO_WS = 2; // used in skip_thing() for moving "dot" +static const int S_OVER_WS = 3; // used in skip_thing() for moving "dot" +static const int S_END_PUNCT = 4; // used in skip_thing() for moving "dot" +static const int S_END_ALNUM = 5; // used in skip_thing() for moving "dot" + +typedef unsigned char Byte; + + +static int editing; // >0 while we are editing a file +static int cmd_mode; // 0=command 1=insert +static int file_modified; // buffer contents changed +static int err_method; // indicate error with beep or flash +static int fn_start; // index of first cmd line file name +static int save_argc; // how many file names on cmd line +static int cmdcnt; // repetition count +static fd_set rfds; // use select() for small sleeps +static struct timeval tv; // use select() for small sleeps +static char erase_char; // the users erase character +static int rows, columns; // the terminal screen is this size +static int crow, ccol, offset; // cursor is on Crow x Ccol with Horz Ofset +static char *SOs, *SOn; // terminal standout start/normal ESC sequence +static char *bell; // terminal bell sequence +static char *Ceol, *Ceos; // Clear-end-of-line and Clear-end-of-screen ESC sequence +static char *CMrc; // Cursor motion arbitrary destination ESC sequence +static char *CMup, *CMdown; // Cursor motion up and down ESC sequence +static Byte *status_buffer; // mesages to the user +static Byte last_input_char; // last char read from user +static Byte last_forward_char; // last char searched for with 'f' +static Byte *cfn; // previous, current, and next file name +static Byte *text, *end, *textend; // pointers to the user data in memory +static Byte *screen; // pointer to the virtual screen buffer +static int screensize; // and its size +static Byte *screenbegin; // index into text[], of top line on the screen +static Byte *dot; // where all the action takes place +static int tabstop; +static struct termios term_orig, term_vi; // remember what the cooked mode was + +#ifdef BB_FEATURE_VI_OPTIMIZE_CURSOR +static int last_row; // where the cursor was last moved to +#endif /* BB_FEATURE_VI_OPTIMIZE_CURSOR */ +#ifdef BB_FEATURE_VI_USE_SIGNALS +static jmp_buf restart; // catch_sig() +#endif /* BB_FEATURE_VI_USE_SIGNALS */ +#ifdef BB_FEATURE_VI_WIN_RESIZE +static struct winsize winsize; // remember the window size +#endif /* BB_FEATURE_VI_WIN_RESIZE */ +#ifdef BB_FEATURE_VI_DOT_CMD +static int adding2q; // are we currently adding user input to q +static Byte *last_modifying_cmd; // last modifying cmd for "." +static Byte *ioq, *ioq_start; // pointer to string for get_one_char to "read" +#endif /* BB_FEATURE_VI_DOT_CMD */ +#if defined(BB_FEATURE_VI_DOT_CMD) || defined(BB_FEATURE_VI_YANKMARK) +static Byte *modifying_cmds; // cmds that modify text[] +#endif /* BB_FEATURE_VI_DOT_CMD || BB_FEATURE_VI_YANKMARK */ +#ifdef BB_FEATURE_VI_READONLY +static int vi_readonly, readonly; +#endif /* BB_FEATURE_VI_READONLY */ +#ifdef BB_FEATURE_VI_SETOPTS +static int autoindent; +static int showmatch; +static int ignorecase; +#endif /* BB_FEATURE_VI_SETOPTS */ +#ifdef BB_FEATURE_VI_YANKMARK +static Byte *reg[28]; // named register a-z, "D", and "U" 0-25,26,27 +static int YDreg, Ureg; // default delete register and orig line for "U" +static Byte *mark[28]; // user marks points somewhere in text[]- a-z and previous context '' +static Byte *context_start, *context_end; +#endif /* BB_FEATURE_VI_YANKMARK */ +#ifdef BB_FEATURE_VI_SEARCH +static Byte *last_search_pattern; // last pattern from a '/' or '?' search +#endif /* BB_FEATURE_VI_SEARCH */ + + +static void edit_file(Byte *); // edit one file +static void do_cmd(Byte); // execute a command +static void sync_cursor(Byte *, int *, int *); // synchronize the screen cursor to dot +static Byte *begin_line(Byte *); // return pointer to cur line B-o-l +static Byte *end_line(Byte *); // return pointer to cur line E-o-l +static Byte *dollar_line(Byte *); // return pointer to just before NL +static Byte *prev_line(Byte *); // return pointer to prev line B-o-l +static Byte *next_line(Byte *); // return pointer to next line B-o-l +static Byte *end_screen(void); // get pointer to last char on screen +static int count_lines(Byte *, Byte *); // count line from start to stop +static Byte *find_line(int); // find begining of line #li +static Byte *move_to_col(Byte *, int); // move "p" to column l +static int isblnk(Byte); // is the char a blank or tab +static void dot_left(void); // move dot left- dont leave line +static void dot_right(void); // move dot right- dont leave line +static void dot_begin(void); // move dot to B-o-l +static void dot_end(void); // move dot to E-o-l +static void dot_next(void); // move dot to next line B-o-l +static void dot_prev(void); // move dot to prev line B-o-l +static void dot_scroll(int, int); // move the screen up or down +static void dot_skip_over_ws(void); // move dot pat WS +static void dot_delete(void); // delete the char at 'dot' +static Byte *bound_dot(Byte *); // make sure text[0] <= P < "end" +static Byte *new_screen(int, int); // malloc virtual screen memory +static Byte *new_text(int); // malloc memory for text[] buffer +static Byte *char_insert(Byte *, Byte); // insert the char c at 'p' +static Byte *stupid_insert(Byte *, Byte); // stupidly insert the char c at 'p' +static Byte find_range(Byte **, Byte **, Byte); // return pointers for an object +static int st_test(Byte *, int, int, Byte *); // helper for skip_thing() +static Byte *skip_thing(Byte *, int, int, int); // skip some object +static Byte *find_pair(Byte *, Byte); // find matching pair () [] {} +static Byte *text_hole_delete(Byte *, Byte *); // at "p", delete a 'size' byte hole +static Byte *text_hole_make(Byte *, int); // at "p", make a 'size' byte hole +static Byte *yank_delete(Byte *, Byte *, int, int); // yank text[] into register then delete +static void show_help(void); // display some help info +static void print_literal(Byte *, Byte *); // copy s to buf, convert unprintable +static void rawmode(void); // set "raw" mode on tty +static void cookmode(void); // return to "cooked" mode on tty +static int mysleep(int); // sleep for 'h' 1/100 seconds +static Byte readit(void); // read (maybe cursor) key from stdin +static Byte get_one_char(void); // read 1 char from stdin +static int file_size(Byte *); // what is the byte size of "fn" +static int file_insert(Byte *, Byte *, int); +static int file_write(Byte *, Byte *, Byte *); +static void place_cursor(int, int, int); +static void screen_erase(); +static void clear_to_eol(void); +static void clear_to_eos(void); +static void standout_start(void); // send "start reverse video" sequence +static void standout_end(void); // send "end reverse video" sequence +static void flash(int); // flash the terminal screen +static void beep(void); // beep the terminal +static void indicate_error(char); // use flash or beep to indicate error +static void show_status_line(void); // put a message on the bottom line +static void psb(char *, ...); // Print Status Buf +static void psbs(char *, ...); // Print Status Buf in standout mode +static void ni(Byte *); // display messages +static void edit_status(void); // show file status on status line +static void redraw(int); // force a full screen refresh +static void format_line(Byte*, Byte*, int); +static void refresh(int); // update the terminal from screen[] + +#ifdef BB_FEATURE_VI_SEARCH +static Byte *char_search(Byte *, Byte *, int, int); // search for pattern starting at p +static int mycmp(Byte *, Byte *, int); // string cmp based in "ignorecase" +#endif /* BB_FEATURE_VI_SEARCH */ +#ifdef BB_FEATURE_VI_COLON +static void Hit_Return(void); +static Byte *get_one_address(Byte *, int *); // get colon addr, if present +static Byte *get_address(Byte *, int *, int *); // get two colon addrs, if present +static void colon(Byte *); // execute the "colon" mode cmds +#endif /* BB_FEATURE_VI_COLON */ +static Byte *get_input_line(Byte *); // get input line- use "status line" +#ifdef BB_FEATURE_VI_USE_SIGNALS +static void winch_sig(int); // catch window size changes +static void suspend_sig(int); // catch ctrl-Z +static void alarm_sig(int); // catch alarm time-outs +static void catch_sig(int); // catch ctrl-C +static void core_sig(int); // catch a core dump signal +#endif /* BB_FEATURE_VI_USE_SIGNALS */ +#ifdef BB_FEATURE_VI_DOT_CMD +static void start_new_cmd_q(Byte); // new queue for command +static void end_cmd_q(); // stop saving input chars +#else /* BB_FEATURE_VI_DOT_CMD */ +#define end_cmd_q() +#endif /* BB_FEATURE_VI_DOT_CMD */ +#ifdef BB_FEATURE_VI_WIN_RESIZE +static void window_size_get(int); // find out what size the window is +#endif /* BB_FEATURE_VI_WIN_RESIZE */ +#ifdef BB_FEATURE_VI_SETOPTS +static void showmatching(Byte *); // show the matching pair () [] {} +#endif /* BB_FEATURE_VI_SETOPTS */ +#if defined(BB_FEATURE_VI_YANKMARK) || defined(BB_FEATURE_VI_COLON) || defined(BB_FEATURE_VI_CRASHME) +static Byte *string_insert(Byte *, Byte *); // insert the string at 'p' +#endif /* BB_FEATURE_VI_YANKMARK || BB_FEATURE_VI_COLON || BB_FEATURE_VI_CRASHME */ +#ifdef BB_FEATURE_VI_YANKMARK +static Byte *text_yank(Byte *, Byte *, int); // save copy of "p" into a register +static Byte what_reg(void); // what is letter of current YDreg +static void check_context(Byte); // remember context for '' command +static Byte *swap_context(Byte *); // goto new context for '' command +#endif /* BB_FEATURE_VI_YANKMARK */ +#ifdef BB_FEATURE_VI_CRASHME +static void crash_dummy(); +static void crash_test(); +static int crashme = 0; +#endif /* BB_FEATURE_VI_CRASHME */ + + +extern int vi_main(int argc, char **argv) +{ + int c; + +#ifdef BB_FEATURE_VI_YANKMARK + int i; +#endif /* BB_FEATURE_VI_YANKMARK */ + + CMrc= "\033[%d;%dH"; // Terminal Crusor motion ESC sequence + CMup= "\033[A"; // move cursor up one line, same col + CMdown="\n"; // move cursor down one line, same col + Ceol= "\033[0K"; // Clear from cursor to end of line + Ceos= "\033[0J"; // Clear from cursor to end of screen + SOs = "\033[7m"; // Terminal standout mode on + SOn = "\033[0m"; // Terminal standout mode off + bell= "\007"; // Terminal bell sequence +#ifdef BB_FEATURE_VI_CRASHME + (void) srand((long) getpid()); +#endif /* BB_FEATURE_VI_CRASHME */ + status_buffer = (Byte *) malloc(BUFSIZ_STATBUF); // hold messages to user +#ifdef BB_FEATURE_VI_READONLY + vi_readonly = readonly = FALSE; + if (strncmp(argv[0], "view", 4) == 0) { + readonly = TRUE; + vi_readonly = TRUE; + } +#endif /* BB_FEATURE_VI_READONLY */ +#ifdef BB_FEATURE_VI_SETOPTS + autoindent = 1; + ignorecase = 1; + showmatch = 1; +#endif /* BB_FEATURE_VI_SETOPTS */ +#ifdef BB_FEATURE_VI_YANKMARK + for (i = 0; i < 28; i++) { + reg[i] = 0; + } // init the yank regs +#endif /* BB_FEATURE_VI_YANKMARK */ +#ifdef BB_FEATURE_VI_DOT_CMD + modifying_cmds = (Byte *) "aAcCdDiIJoOpPrRsxX<>~"; // cmds modifying text[] +#endif /* BB_FEATURE_VI_DOT_CMD */ + + // 1- process $HOME/.exrc file + // 2- process EXINIT variable from environment + // 3- process command line args + while ((c = getopt(argc, argv, "hCR")) != -1) { + switch (c) { +#ifdef BB_FEATURE_VI_CRASHME + case 'C': + crashme = 1; + break; +#endif /* BB_FEATURE_VI_CRASHME */ +#ifdef BB_FEATURE_VI_READONLY + case 'R': // Read-only flag + readonly = TRUE; + break; +#endif /* BB_FEATURE_VI_READONLY */ + //case 'r': // recover flag- ignore- we don't use tmp file + //case 'x': // encryption flag- ignore + //case 'c': // execute command first + //case 'h': // help -- just use default + default: + show_help(); + return 1; + } + } + + // The argv array can be used by the ":next" and ":rewind" commands + // save optind. + fn_start = optind; // remember first file name for :next and :rew + save_argc = argc; + + //----- This is the main file handling loop -------------- + if (optind >= argc) { + editing = 1; // 0= exit, 1= one file, 2= multiple files + edit_file(0); + } else { + for (; optind < argc; optind++) { + editing = 1; // 0=exit, 1=one file, 2+ =many files + if (cfn != 0) + free(cfn); + cfn = (Byte *) strdup(argv[optind]); + edit_file(cfn); + } + } + //----------------------------------------------------------- + + return (0); +} + +static void edit_file(Byte * fn) +{ + char c; + int cnt, size, ch; + +#ifdef BB_FEATURE_VI_USE_SIGNALS + char *msg; + int sig; +#endif /* BB_FEATURE_VI_USE_SIGNALS */ +#ifdef BB_FEATURE_VI_YANKMARK + static Byte *cur_line; +#endif /* BB_FEATURE_VI_YANKMARK */ + + rawmode(); + rows = 24; + columns = 80; + ch= -1; +#ifdef BB_FEATURE_VI_WIN_RESIZE + window_size_get(0); +#endif /* BB_FEATURE_VI_WIN_RESIZE */ + new_screen(rows, columns); // get memory for virtual screen + + cnt = file_size(fn); // file size + size = 2 * cnt; // 200% of file size + new_text(size); // get a text[] buffer + screenbegin = dot = end = text; + if (fn != 0) { + ch= file_insert(fn, text, cnt); + } + if (ch < 1) { + (void) char_insert(text, '\n'); // start empty buf with dummy line + } + file_modified = FALSE; +#ifdef BB_FEATURE_VI_YANKMARK + YDreg = 26; // default Yank/Delete reg + Ureg = 27; // hold orig line for "U" cmd + for (cnt = 0; cnt < 28; cnt++) { + mark[cnt] = 0; + } // init the marks + mark[26] = mark[27] = text; // init "previous context" +#endif /* BB_FEATURE_VI_YANKMARK */ + + err_method = 1; // flash + last_forward_char = last_input_char = '\0'; + crow = 0; + ccol = 0; + edit_status(); + +#ifdef BB_FEATURE_VI_USE_SIGNALS + signal(SIGHUP, catch_sig); + signal(SIGINT, catch_sig); + signal(SIGALRM, alarm_sig); + signal(SIGTERM, catch_sig); + signal(SIGQUIT, core_sig); + signal(SIGILL, core_sig); + signal(SIGTRAP, core_sig); + signal(SIGIOT, core_sig); + signal(SIGABRT, core_sig); + signal(SIGFPE, core_sig); + signal(SIGBUS, core_sig); + signal(SIGSEGV, core_sig); +#ifdef SIGSYS + signal(SIGSYS, core_sig); +#endif + signal(SIGWINCH, winch_sig); + signal(SIGTSTP, suspend_sig); + sig = setjmp(restart); + if (sig != 0) { + msg = ""; + if (sig == SIGWINCH) + msg = "(window resize)"; + if (sig == SIGHUP) + msg = "(hangup)"; + if (sig == SIGINT) + msg = "(interrupt)"; + if (sig == SIGTERM) + msg = "(terminate)"; + if (sig == SIGBUS) + msg = "(bus error)"; + if (sig == SIGSEGV) + msg = "(I tried to touch invalid memory)"; + if (sig == SIGALRM) + msg = "(alarm)"; + + psbs("-- caught signal %d %s--", sig, msg); + screenbegin = dot = text; + } +#endif /* BB_FEATURE_VI_USE_SIGNALS */ + + editing = 1; + cmd_mode = 0; // 0=command 1=insert 2='R'eplace + cmdcnt = 0; + tabstop = 8; + offset = 0; // no horizontal offset + c = '\0'; +#ifdef BB_FEATURE_VI_DOT_CMD + if (last_modifying_cmd != 0) + free(last_modifying_cmd); + if (ioq_start != NULL) + free(ioq_start); + ioq = ioq_start = last_modifying_cmd = 0; + adding2q = 0; +#endif /* BB_FEATURE_VI_DOT_CMD */ + redraw(FALSE); // dont force every col re-draw + show_status_line(); + + //------This is the main Vi cmd handling loop ----------------------- + while (editing > 0) { +#ifdef BB_FEATURE_VI_CRASHME + if (crashme > 0) { + if ((end - text) > 1) { + crash_dummy(); // generate a random command + } else { + crashme = 0; + dot = + string_insert(text, (Byte *) "\n\n##### Ran out of text to work on. #####\n\n"); // insert the string + refresh(FALSE); + } + } +#endif /* BB_FEATURE_VI_CRASHME */ + last_input_char = c = get_one_char(); // get a cmd from user +#ifdef BB_FEATURE_VI_YANKMARK + // save a copy of the current line- for the 'U" command + if (begin_line(dot) != cur_line) { + cur_line = begin_line(dot); + text_yank(begin_line(dot), end_line(dot), Ureg); + } +#endif /* BB_FEATURE_VI_YANKMARK */ +#ifdef BB_FEATURE_VI_DOT_CMD + // These are commands that change text[]. + // Remember the input for the "." command + if (!adding2q && ioq_start == 0 + && strchr((char *) modifying_cmds, c) != NULL) { + start_new_cmd_q(c); + } +#endif /* BB_FEATURE_VI_DOT_CMD */ + do_cmd(c); // execute the user command + // + // poll to see if there is input already waiting. if we are + // not able to display output fast enough to keep up, skip + // the display update until we catch up with input. + if (mysleep(0) == 0) { + // no input pending- so update output + refresh(FALSE); + show_status_line(); + } +#ifdef BB_FEATURE_VI_CRASHME + if (crashme > 0) + crash_test(); // test editor variables +#endif /* BB_FEATURE_VI_CRASHME */ + } + //------------------------------------------------------------------- + + place_cursor(rows, 0, FALSE); // go to bottom of screen + clear_to_eol(); // Erase to end of line + cookmode(); +} + +static Byte readbuffer[BUFSIZ]; + +#ifdef BB_FEATURE_VI_CRASHME +static int totalcmds = 0; +static int Mp = 85; // Movement command Probability +static int Np = 90; // Non-movement command Probability +static int Dp = 96; // Delete command Probability +static int Ip = 97; // Insert command Probability +static int Yp = 98; // Yank command Probability +static int Pp = 99; // Put command Probability +static int M = 0, N = 0, I = 0, D = 0, Y = 0, P = 0, U = 0; +char chars[20] = "\t012345 abcdABCD-=.$"; +char *words[20] = { "this", "is", "a", "test", + "broadcast", "the", "emergency", "of", + "system", "quick", "brown", "fox", + "jumped", "over", "lazy", "dogs", + "back", "January", "Febuary", "March" +}; +char *lines[20] = { + "You should have received a copy of the GNU General Public License\n", + "char c, cm, *cmd, *cmd1;\n", + "generate a command by percentages\n", + "Numbers may be typed as a prefix to some commands.\n", + "Quit, discarding changes!\n", + "Forced write, if permission originally not valid.\n", + "In general, any ex or ed command (such as substitute or delete).\n", + "I have tickets available for the Blazers vs LA Clippers for Monday, Janurary 1 at 1:00pm.\n", + "Please get w/ me and I will go over it with you.\n", + "The following is a list of scheduled, committed changes.\n", + "1. Launch Norton Antivirus (Start, Programs, Norton Antivirus)\n", + "Reminder....Town Meeting in Central Perk cafe today at 3:00pm.\n", + "Any question about transactions please contact Sterling Huxley.\n", + "I will try to get back to you by Friday, December 31.\n", + "This Change will be implemented on Friday.\n", + "Let me know if you have problems accessing this;\n", + "Sterling Huxley recently added you to the access list.\n", + "Would you like to go to lunch?\n", + "The last command will be automatically run.\n", + "This is too much english for a computer geek.\n", +}; +char *multilines[20] = { + "You should have received a copy of the GNU General Public License\n", + "char c, cm, *cmd, *cmd1;\n", + "generate a command by percentages\n", + "Numbers may be typed as a prefix to some commands.\n", + "Quit, discarding changes!\n", + "Forced write, if permission originally not valid.\n", + "In general, any ex or ed command (such as substitute or delete).\n", + "I have tickets available for the Blazers vs LA Clippers for Monday, Janurary 1 at 1:00pm.\n", + "Please get w/ me and I will go over it with you.\n", + "The following is a list of scheduled, committed changes.\n", + "1. Launch Norton Antivirus (Start, Programs, Norton Antivirus)\n", + "Reminder....Town Meeting in Central Perk cafe today at 3:00pm.\n", + "Any question about transactions please contact Sterling Huxley.\n", + "I will try to get back to you by Friday, December 31.\n", + "This Change will be implemented on Friday.\n", + "Let me know if you have problems accessing this;\n", + "Sterling Huxley recently added you to the access list.\n", + "Would you like to go to lunch?\n", + "The last command will be automatically run.\n", + "This is too much english for a computer geek.\n", +}; + +// create a random command to execute +static void crash_dummy() +{ + static int sleeptime; // how long to pause between commands + char c, cm, *cmd, *cmd1; + int i, cnt, thing, rbi, startrbi, percent; + + // "dot" movement commands + cmd1 = " \n\r\002\004\005\006\025\0310^$-+wWeEbBhjklHL"; + + // is there already a command running? + if (strlen((char *) readbuffer) > 0) + goto cd1; + cd0: + startrbi = rbi = 0; + sleeptime = 0; // how long to pause between commands + memset(readbuffer, '\0', BUFSIZ - 1); // clear the read buffer + // generate a command by percentages + percent = (int) lrand48() % 100; // get a number from 0-99 + if (percent < Mp) { // Movement commands + // available commands + cmd = cmd1; + M++; + } else if (percent < Np) { // non-movement commands + cmd = "mz<>\'\""; // available commands + N++; + } else if (percent < Dp) { // Delete commands + cmd = "dx"; // available commands + D++; + } else if (percent < Ip) { // Inset commands + cmd = "iIaAsrJ"; // available commands + I++; + } else if (percent < Yp) { // Yank commands + cmd = "yY"; // available commands + Y++; + } else if (percent < Pp) { // Put commands + cmd = "pP"; // available commands + P++; + } else { + // We do not know how to handle this command, try again + U++; + goto cd0; + } + // randomly pick one of the available cmds from "cmd[]" + i = (int) lrand48() % strlen(cmd); + cm = cmd[i]; + if (strchr(":\024", cm)) + goto cd0; // dont allow colon or ctrl-T commands + readbuffer[rbi++] = cm; // put cmd into input buffer + + // now we have the command- + // there are 1, 2, and multi char commands + // find out which and generate the rest of command as necessary + if (strchr("dmryz<>\'\"", cm)) { // 2-char commands + cmd1 = " \n\r0$^-+wWeEbBhjklHL"; + if (cm == 'm' || cm == '\'' || cm == '\"') { // pick a reg[] + cmd1 = "abcdefghijklmnopqrstuvwxyz"; + } + thing = (int) lrand48() % strlen(cmd1); // pick a movement command + c = cmd1[thing]; + readbuffer[rbi++] = c; // add movement to input buffer + } + if (strchr("iIaAsc", cm)) { // multi-char commands + if (cm == 'c') { + // change some thing + thing = (int) lrand48() % strlen(cmd1); // pick a movement command + c = cmd1[thing]; + readbuffer[rbi++] = c; // add movement to input buffer + } + thing = (int) lrand48() % 4; // what thing to insert + cnt = (int) lrand48() % 10; // how many to insert + for (i = 0; i < cnt; i++) { + if (thing == 0) { // insert chars + readbuffer[rbi++] = chars[((int) lrand48() % strlen(chars))]; + } else if (thing == 1) { // insert words + strlcat((char *) readbuffer, words[(int) lrand48() % 20], BUFSIZ); /* FIXED added BUFSIZ and converted to strlcat() */ + strcat((char *) readbuffer, " "); + sleeptime = 0; // how fast to type + } else if (thing == 2) { // insert lines + strlcat((char *) readbuffer, lines[(int) lrand48() % 20], BUFSIZ); /* FIXED added BUFSIZ and converted to strlcat() */ + sleeptime = 0; // how fast to type + } else { // insert multi-lines + strlcat((char *) readbuffer, multilines[(int) lrand48() % 20], BUFSIZ); /* FIXED added BUFSIZ and converted to stlcat() */ + sleeptime = 0; // how fast to type + } + } + strcat((char *) readbuffer, "\033"); + } + cd1: + totalcmds++; + if (sleeptime > 0) + (void) mysleep(sleeptime); // sleep 1/100 sec +} + +// test to see if there are any errors +static void crash_test() +{ + static time_t oldtim; + time_t tim; + char d[2], buf[BUFSIZ], msg[BUFSIZ]; + + msg[0] = '\0'; + if (end < text) { + strcat((char *) msg, "end textend) { + strcat((char *) msg, "end>textend "); + } + if (dot < text) { + strcat((char *) msg, "dot end) { + strcat((char *) msg, "dot>end "); + } + if (screenbegin < text) { + strcat((char *) msg, "screenbegin end - 1) { + strcat((char *) msg, "screenbegin>end-1 "); + } + + if (strlen(msg) > 0) { + alarm(0); + sprintf(buf, "\n\n%d: \'%c\' %s\n\n\n%s[Hit return to continue]%s", + totalcmds, last_input_char, msg, SOs, SOn); + write(1, buf, strlen(buf)); + while (read(0, d, 1) > 0) { + if (d[0] == '\n' || d[0] == '\r') + break; + } + alarm(3); + } + tim = (time_t) time((time_t *) 0); + if (tim >= (oldtim + 3)) { + sprintf((char *) status_buffer, + "Tot=%d: M=%d N=%d I=%d D=%d Y=%d P=%d U=%d size=%d", + totalcmds, M, N, I, D, Y, P, U, end - text + 1); + oldtim = tim; + } + return; +} +#endif /* BB_FEATURE_VI_CRASHME */ + +//--------------------------------------------------------------------- +//----- the Ascii Chart ----------------------------------------------- +// +// 00 nul 01 soh 02 stx 03 etx 04 eot 05 enq 06 ack 07 bel +// 08 bs 09 ht 0a nl 0b vt 0c np 0d cr 0e so 0f si +// 10 dle 11 dc1 12 dc2 13 dc3 14 dc4 15 nak 16 syn 17 etb +// 18 can 19 em 1a sub 1b esc 1c fs 1d gs 1e rs 1f us +// 20 sp 21 ! 22 " 23 # 24 $ 25 % 26 & 27 ' +// 28 ( 29 ) 2a * 2b + 2c , 2d - 2e . 2f / +// 30 0 31 1 32 2 33 3 34 4 35 5 36 6 37 7 +// 38 8 39 9 3a : 3b ; 3c < 3d = 3e > 3f ? +// 40 @ 41 A 42 B 43 C 44 D 45 E 46 F 47 G +// 48 H 49 I 4a J 4b K 4c L 4d M 4e N 4f O +// 50 P 51 Q 52 R 53 S 54 T 55 U 56 V 57 W +// 58 X 59 Y 5a Z 5b [ 5c \ 5d ] 5e ^ 5f _ +// 60 ` 61 a 62 b 63 c 64 d 65 e 66 f 67 g +// 68 h 69 i 6a j 6b k 6c l 6d m 6e n 6f o +// 70 p 71 q 72 r 73 s 74 t 75 u 76 v 77 w +// 78 x 79 y 7a z 7b { 7c | 7d } 7e ~ 7f del +//--------------------------------------------------------------------- + +//----- Execute a Vi Command ----------------------------------- +static void do_cmd(Byte c) +{ + Byte c1, *p, *q, *msg, buf[9], *save_dot; + int cnt, i, j, dir, yf; + + c1 = c; // quiet the compiler + cnt = yf = dir = 0; // quiet the compiler + p = q = save_dot = msg = buf; // quiet the compiler + memset(buf, '\0', 9); // clear buf + + /* if this is a cursor key, skip these checks */ + switch (c) { + case VI_K_UP: + case VI_K_DOWN: + case VI_K_LEFT: + case VI_K_RIGHT: + case VI_K_HOME: + case VI_K_END: + case VI_K_PAGEUP: + case VI_K_PAGEDOWN: + goto key_cmd_mode; + } + + if (cmd_mode == 2) { + // we are 'R'eplacing the current *dot with new char + if (*dot == '\n') { + // don't Replace past E-o-l + cmd_mode = 1; // convert to insert + } else { + if (1 <= c && c <= 127) { // only ASCII chars + if (c != 27) + dot = yank_delete(dot, dot, 0, YANKDEL); // delete char + dot = char_insert(dot, c); // insert new char + } + goto dc1; + } + } + if (cmd_mode == 1) { + // hitting "Insert" twice means "R" replace mode + if (c == VI_K_INSERT) goto dc5; + // insert the char c at "dot" + if (c == 8) { + dir = -1; + if (dot[dir] != '\n') { + dot--; // delete prev char + dot = yank_delete(dot, dot, 0, YANKDEL); // delete char + goto dc1; + } + } + + if (1 <= c && c <= 127) { + dot = char_insert(dot, c); // only ASCII chars + } + goto dc1; + } + +key_cmd_mode: + switch (c) { + //case 0x01: // soh + //case 0x09: // ht + //case 0x0b: // vt + //case 0x0e: // so + //case 0x0f: // si + //case 0x10: // dle + //case 0x11: // dc1 + //case 0x13: // dc3 +#ifdef BB_FEATURE_VI_CRASHME + case 0x14: // dc4 ctrl-T + crashme = (crashme == 0) ? 1 : 0; + break; +#endif /* BB_FEATURE_VI_CRASHME */ + //case 0x16: // syn + //case 0x17: // etb + //case 0x18: // can + //case 0x1c: // fs + //case 0x1d: // gs + //case 0x1e: // rs + //case 0x1f: // us + //case '!': // !- + //case '#': // #- + //case '&': // &- + //case '(': // (- + //case ')': // )- + //case '*': // *- + //case ',': // ,- + //case '=': // =- + //case '@': // @- + //case 'F': // F- + //case 'K': // K- + //case 'Q': // Q- + //case 'S': // S- + //case 'T': // T- + //case 'V': // V- + //case '[': // [- + //case '\\': // \- + //case ']': // ]- + //case '_': // _- + //case '`': // `- + //case 'g': // g- + //case 'u': // u- FIXME- there is no undo + //case 'v': // v- + default: // unrecognised command + buf[0] = c; + buf[1] = '\0'; + if (c <= ' ') { + buf[0] = '^'; + buf[1] = c + '@'; + buf[2] = '\0'; + } + ni((Byte *) buf); + end_cmd_q(); // stop adding to q + case 0x00: // nul- ignore + break; + case 2: // ctrl-B scroll up full screen + case VI_K_PAGEUP: // Cursor Key Page Up + dot_scroll(rows - 2, -1); + break; +#ifdef BB_FEATURE_VI_USE_SIGNALS + case 0x03: // ctrl-C interrupt + longjmp(restart, 1); + break; + case 26: // ctrl-Z suspend + suspend_sig(SIGTSTP); + break; +#endif /* BB_FEATURE_VI_USE_SIGNALS */ + case 4: // ctrl-D scroll down half screen + dot_scroll((rows - 2) / 2, 1); + break; + case 5: // ctrl-E scroll down one line + dot_scroll(1, 1); + break; + case 6: // ctrl-F scroll down full screen + case VI_K_PAGEDOWN: // Cursor Key Page Down + dot_scroll(rows - 2, 1); + break; + case 7: // ctrl-G show current status + edit_status(); + break; + case 'h': // h- move left + case VI_K_LEFT: // cursor key Left + case 8: // ctrl-H- move left (This may be ERASE char) + case 127: // DEL- move left (This may be ERASE char) + if (cmdcnt-- > 1) { + do_cmd(c); + } // repeat cnt + dot_left(); + break; + case 10: // Newline ^J + case 'j': // j- goto next line, same col + case VI_K_DOWN: // cursor key Down + if (cmdcnt-- > 1) { + do_cmd(c); + } // repeat cnt + dot_next(); // go to next B-o-l + dot = move_to_col(dot, ccol + offset); // try stay in same col + break; + case 12: // ctrl-L force redraw whole screen + case 18: // ctrl-R force redraw + place_cursor(0, 0, FALSE); // put cursor in correct place + clear_to_eos(); // tel terminal to erase display + (void) mysleep(10); + screen_erase(); // erase the internal screen buffer + refresh(TRUE); // this will redraw the entire display + break; + case 13: // Carriage Return ^M + case '+': // +- goto next line + if (cmdcnt-- > 1) { + do_cmd(c); + } // repeat cnt + dot_next(); + dot_skip_over_ws(); + break; + case 21: // ctrl-U scroll up half screen + dot_scroll((rows - 2) / 2, -1); + break; + case 25: // ctrl-Y scroll up one line + dot_scroll(1, -1); + break; + case 27: // esc + if (cmd_mode == 0) + indicate_error(c); + cmd_mode = 0; // stop insrting + end_cmd_q(); + *status_buffer = '\0'; // clear status buffer + break; + case ' ': // move right + case 'l': // move right + case VI_K_RIGHT: // Cursor Key Right + if (cmdcnt-- > 1) { + do_cmd(c); + } // repeat cnt + dot_right(); + break; +#ifdef BB_FEATURE_VI_YANKMARK + case '"': // "- name a register to use for Delete/Yank + c1 = get_one_char(); + c1 = tolower(c1); + if (islower(c1)) { + YDreg = c1 - 'a'; + } else { + indicate_error(c); + } + break; + case '\'': // '- goto a specific mark + c1 = get_one_char(); + c1 = tolower(c1); + if (islower(c1)) { + c1 = c1 - 'a'; + // get the b-o-l + q = mark[(int) c1]; + if (text <= q && q < end) { + dot = q; + dot_begin(); // go to B-o-l + dot_skip_over_ws(); + } + } else if (c1 == '\'') { // goto previous context + dot = swap_context(dot); // swap current and previous context + dot_begin(); // go to B-o-l + dot_skip_over_ws(); + } else { + indicate_error(c); + } + break; + case 'm': // m- Mark a line + // this is really stupid. If there are any inserts or deletes + // between text[0] and dot then this mark will not point to the + // correct location! It could be off by many lines! + // Well..., at least its quick and dirty. + c1 = get_one_char(); + c1 = tolower(c1); + if (islower(c1)) { + c1 = c1 - 'a'; + // remember the line + mark[(int) c1] = dot; + } else { + indicate_error(c); + } + break; + case 'P': // P- Put register before + case 'p': // p- put register after + p = reg[YDreg]; + if (p == 0) { + psbs("Nothing in register %c", what_reg()); + break; + } + // are we putting whole lines or strings + if (strchr((char *) p, '\n') != NULL) { + if (c == 'P') { + dot_begin(); // putting lines- Put above + } + if (c == 'p') { + // are we putting after very last line? + if (end_line(dot) == (end - 1)) { + dot = end; // force dot to end of text[] + } else { + dot_next(); // next line, then put before + } + } + } else { + if (c == 'p') + dot_right(); // move to right, can move to NL + } + dot = string_insert(dot, p); // insert the string + end_cmd_q(); // stop adding to q + break; + case 'U': // U- Undo; replace current line with original version + if (reg[Ureg] != 0) { + p = begin_line(dot); + q = end_line(dot); + p = text_hole_delete(p, q); // delete cur line + p = string_insert(p, reg[Ureg]); // insert orig line + dot = p; + dot_skip_over_ws(); + } + break; +#endif /* BB_FEATURE_VI_YANKMARK */ + case '$': // $- goto end of line + case VI_K_END: // Cursor Key End + if (cmdcnt-- > 1) { + do_cmd(c); + } // repeat cnt + dot = end_line(dot + 1); + break; + case '%': // %- find matching char of pair () [] {} + for (q = dot; q < end && *q != '\n'; q++) { + if (strchr("()[]{}", *q) != NULL) { + // we found half of a pair + p = find_pair(q, *q); + if (p == NULL) { + indicate_error(c); + } else { + dot = p; + } + break; + } + } + if (*q == '\n') + indicate_error(c); + break; + case 'f': // f- forward to a user specified char + last_forward_char = get_one_char(); // get the search char + // + // dont seperate these two commands. 'f' depends on ';' + // + //**** fall thru to ... 'i' + case ';': // ;- look at rest of line for last forward char + if (cmdcnt-- > 1) { + do_cmd(';'); + } // repeat cnt + if (last_forward_char == 0) break; + q = dot + 1; + while (q < end - 1 && *q != '\n' && *q != last_forward_char) { + q++; + } + if (*q == last_forward_char) + dot = q; + break; + case '-': // -- goto prev line + if (cmdcnt-- > 1) { + do_cmd(c); + } // repeat cnt + dot_prev(); + dot_skip_over_ws(); + break; +#ifdef BB_FEATURE_VI_DOT_CMD + case '.': // .- repeat the last modifying command + // Stuff the last_modifying_cmd back into stdin + // and let it be re-executed. + if (last_modifying_cmd != 0) { + ioq = ioq_start = (Byte *) strdup((char *) last_modifying_cmd); + } + break; +#endif /* BB_FEATURE_VI_DOT_CMD */ +#ifdef BB_FEATURE_VI_SEARCH + case '?': // /- search for a pattern + case '/': // /- search for a pattern + buf[0] = c; + buf[1] = '\0'; + q = get_input_line(buf); // get input line- use "status line" + if (strlen((char *) q) == 1) + goto dc3; // if no pat re-use old pat + if (strlen((char *) q) > 1) { // new pat- save it and find + // there is a new pat + if (last_search_pattern != 0) { + free(last_search_pattern); + } + last_search_pattern = (Byte *) strdup((char *) q); + goto dc3; // now find the pattern + } + // user changed mind and erased the "/"- do nothing + break; + case 'N': // N- backward search for last pattern + if (cmdcnt-- > 1) { + do_cmd(c); + } // repeat cnt + dir = BACK; // assume BACKWARD search + p = dot - 1; + if (last_search_pattern[0] == '?') { + dir = FORWARD; + p = dot + 1; + } + goto dc4; // now search for pattern + break; + case 'n': // n- repeat search for last pattern + // search rest of text[] starting at next char + // if search fails return orignal "p" not the "p+1" address + if (cmdcnt-- > 1) { + do_cmd(c); + } // repeat cnt + dc3: + if (last_search_pattern == 0) { + msg = (Byte *) "No previous regular expression"; + goto dc2; + } + if (last_search_pattern[0] == '/') { + dir = FORWARD; // assume FORWARD search + p = dot + 1; + } + if (last_search_pattern[0] == '?') { + dir = BACK; + p = dot - 1; + } + dc4: + q = char_search(p, last_search_pattern + 1, dir, FULL); + if (q != NULL) { + dot = q; // good search, update "dot" + msg = (Byte *) ""; + goto dc2; + } + // no pattern found between "dot" and "end"- continue at top + p = text; + if (dir == BACK) { + p = end - 1; + } + q = char_search(p, last_search_pattern + 1, dir, FULL); + if (q != NULL) { // found something + dot = q; // found new pattern- goto it + msg = (Byte *) "search hit BOTTOM, continuing at TOP"; + if (dir == BACK) { + msg = (Byte *) "search hit TOP, continuing at BOTTOM"; + } + } else { + msg = (Byte *) "Pattern not found"; + } + dc2: + psbs("%s", msg); + break; + case '{': // {- move backward paragraph + q = char_search(dot, (Byte *) "\n\n", BACK, FULL); + if (q != NULL) { // found blank line + dot = next_line(q); // move to next blank line + } + break; + case '}': // }- move forward paragraph + q = char_search(dot, (Byte *) "\n\n", FORWARD, FULL); + if (q != NULL) { // found blank line + dot = next_line(q); // move to next blank line + } + break; +#endif /* BB_FEATURE_VI_SEARCH */ + case '0': // 0- goto begining of line + case '1': // 1- + case '2': // 2- + case '3': // 3- + case '4': // 4- + case '5': // 5- + case '6': // 6- + case '7': // 7- + case '8': // 8- + case '9': // 9- + if (c == '0' && cmdcnt < 1) { + dot_begin(); // this was a standalone zero + } else { + cmdcnt = cmdcnt * 10 + (c - '0'); // this 0 is part of a number + } + break; + case ':': // :- the colon mode commands + p = get_input_line((Byte *) ":"); // get input line- use "status line" +#ifdef BB_FEATURE_VI_COLON + colon(p); // execute the command +#else /* BB_FEATURE_VI_COLON */ + if (*p == ':') + p++; // move past the ':' + cnt = strlen((char *) p); + if (cnt <= 0) + break; + if (strncasecmp((char *) p, "quit", cnt) == 0 || + strncasecmp((char *) p, "q!", cnt) == 0) { // delete lines + if (file_modified == TRUE && p[1] != '!') { + psbs("No write since last change (:quit! overrides)"); + } else { + editing = 0; + } + } else if (strncasecmp((char *) p, "write", cnt) == 0 || + strncasecmp((char *) p, "wq", cnt) == 0) { + cnt = file_write(cfn, text, end - 1); + file_modified = FALSE; + psb("\"%s\" %dL, %dC", cfn, count_lines(text, end - 1), cnt); + if (p[1] == 'q') { + editing = 0; + } + } else if (strncasecmp((char *) p, "file", cnt) == 0 ) { + edit_status(); // show current file status + } else if (sscanf((char *) p, "%d", &j) > 0) { + dot = find_line(j); // go to line # j + dot_skip_over_ws(); + } else { // unrecognised cmd + ni((Byte *) p); + } +#endif /* BB_FEATURE_VI_COLON */ + break; + case '<': // <- Left shift something + case '>': // >- Right shift something + cnt = count_lines(text, dot); // remember what line we are on + c1 = get_one_char(); // get the type of thing to delete + find_range(&p, &q, c1); + (void) yank_delete(p, q, 1, YANKONLY); // save copy before change + p = begin_line(p); + q = end_line(q); + i = count_lines(p, q); // # of lines we are shifting + for ( ; i > 0; i--, p = next_line(p)) { + if (c == '<') { + // shift left- remove tab or 8 spaces + if (*p == '\t') { + // shrink buffer 1 char + (void) text_hole_delete(p, p); + } else if (*p == ' ') { + // we should be calculating columns, not just SPACE + for (j = 0; *p == ' ' && j < tabstop; j++) { + (void) text_hole_delete(p, p); + } + } + } else if (c == '>') { + // shift right -- add tab or 8 spaces + (void) char_insert(p, '\t'); + } + } + dot = find_line(cnt); // what line were we on + dot_skip_over_ws(); + end_cmd_q(); // stop adding to q + break; + case 'A': // A- append at e-o-l + dot_end(); // go to e-o-l + //**** fall thru to ... 'a' + case 'a': // a- append after current char + if (*dot != '\n') + dot++; + goto dc_i; + break; + case 'B': // B- back a blank-delimited Word + case 'E': // E- end of a blank-delimited word + case 'W': // W- forward a blank-delimited word + if (cmdcnt-- > 1) { + do_cmd(c); + } // repeat cnt + dir = FORWARD; + if (c == 'B') + dir = BACK; + if (c == 'W' || isspace(dot[dir])) { + dot = skip_thing(dot, 1, dir, S_TO_WS); + dot = skip_thing(dot, 2, dir, S_OVER_WS); + } + if (c != 'W') + dot = skip_thing(dot, 1, dir, S_BEFORE_WS); + break; + case 'C': // C- Change to e-o-l + case 'D': // D- delete to e-o-l + save_dot = dot; + dot = dollar_line(dot); // move to before NL + // copy text into a register and delete + dot = yank_delete(save_dot, dot, 0, YANKDEL); // delete to e-o-l + if (c == 'C') + goto dc_i; // start inserting +#ifdef BB_FEATURE_VI_DOT_CMD + if (c == 'D') + end_cmd_q(); // stop adding to q +#endif /* BB_FEATURE_VI_DOT_CMD */ + break; + case 'G': // G- goto to a line number (default= E-O-F) + dot = end - 1; // assume E-O-F + if (cmdcnt > 0) { + dot = find_line(cmdcnt); // what line is #cmdcnt + } + dot_skip_over_ws(); + break; + case 'H': // H- goto top line on screen + dot = screenbegin; + if (cmdcnt > (rows - 1)) { + cmdcnt = (rows - 1); + } + if (cmdcnt-- > 1) { + do_cmd('+'); + } // repeat cnt + dot_skip_over_ws(); + break; + case 'I': // I- insert before first non-blank + dot_begin(); // 0 + dot_skip_over_ws(); + //**** fall thru to ... 'i' + case 'i': // i- insert before current char + case VI_K_INSERT: // Cursor Key Insert + dc_i: + cmd_mode = 1; // start insrting + psb("-- Insert --"); + break; + case 'J': // J- join current and next lines together + if (cmdcnt-- > 2) { + do_cmd(c); + } // repeat cnt + dot_end(); // move to NL + if (dot < end - 1) { // make sure not last char in text[] + *dot++ = ' '; // replace NL with space + while (isblnk(*dot)) { // delete leading WS + dot_delete(); + } + } + end_cmd_q(); // stop adding to q + break; + case 'L': // L- goto bottom line on screen + dot = end_screen(); + if (cmdcnt > (rows - 1)) { + cmdcnt = (rows - 1); + } + if (cmdcnt-- > 1) { + do_cmd('-'); + } // repeat cnt + dot_begin(); + dot_skip_over_ws(); + break; + case 'M': // M- goto middle line on screen + dot = screenbegin; + for (cnt = 0; cnt < (rows-1) / 2; cnt++) + dot = next_line(dot); + break; + case 'O': // O- open a empty line above + // 0i\n ESC -i + p = begin_line(dot); + if (p[-1] == '\n') { + dot_prev(); + case 'o': // o- open a empty line below; Yes, I know it is in the middle of the "if (..." + dot_end(); + dot = char_insert(dot, '\n'); + } else { + dot_begin(); // 0 + dot = char_insert(dot, '\n'); // i\n ESC + dot_prev(); // - + } + goto dc_i; + break; + case 'R': // R- continuous Replace char + dc5: + cmd_mode = 2; + psb("-- Replace --"); + break; + case 'X': // X- delete char before dot + case 'x': // x- delete the current char + case 's': // s- substitute the current char + if (cmdcnt-- > 1) { + do_cmd(c); + } // repeat cnt + dir = 0; + if (c == 'X') + dir = -1; + if (dot[dir] != '\n') { + if (c == 'X') + dot--; // delete prev char + dot = yank_delete(dot, dot, 0, YANKDEL); // delete char + } + if (c == 's') + goto dc_i; // start insrting + end_cmd_q(); // stop adding to q + break; + case 'Z': // Z- if modified, {write}; exit + // ZZ means to save file (if necessary), then exit + c1 = get_one_char(); + if (c1 != 'Z') { + indicate_error(c); + break; + } + if (file_modified == TRUE +#ifdef BB_FEATURE_VI_READONLY + && vi_readonly == FALSE + && readonly == FALSE +#endif /* BB_FEATURE_VI_READONLY */ + ) { + cnt = file_write(cfn, text, end - 1); + if (cnt == (end - 1 - text + 1)) { + editing = 0; + } + } else { + editing = 0; + } + break; + case '^': // ^- move to first non-blank on line + dot_begin(); + dot_skip_over_ws(); + break; + case 'b': // b- back a word + case 'e': // e- end of word + if (cmdcnt-- > 1) { + do_cmd(c); + } // repeat cnt + dir = FORWARD; + if (c == 'b') + dir = BACK; + if ((dot + dir) < text || (dot + dir) > end - 1) + break; + dot += dir; + if (isspace(*dot)) { + dot = skip_thing(dot, (c == 'e') ? 2 : 1, dir, S_OVER_WS); + } + if (isalnum(*dot) || *dot == '_') { + dot = skip_thing(dot, 1, dir, S_END_ALNUM); + } else if (ispunct(*dot)) { + dot = skip_thing(dot, 1, dir, S_END_PUNCT); + } + break; + case 'c': // c- change something + case 'd': // d- delete something +#ifdef BB_FEATURE_VI_YANKMARK + case 'y': // y- yank something + case 'Y': // Y- Yank a line +#endif /* BB_FEATURE_VI_YANKMARK */ + yf = YANKDEL; // assume either "c" or "d" +#ifdef BB_FEATURE_VI_YANKMARK + if (c == 'y' || c == 'Y') + yf = YANKONLY; +#endif /* BB_FEATURE_VI_YANKMARK */ + c1 = 'y'; + if (c != 'Y') + c1 = get_one_char(); // get the type of thing to delete + find_range(&p, &q, c1); + if (c1 == 27) { // ESC- user changed mind and wants out + c = c1 = 27; // Escape- do nothing + } else if (strchr("wW", c1)) { + if (c == 'c') { + // don't include trailing WS as part of word + while (isblnk(*q)) { + if (q <= text || q[-1] == '\n') + break; + q--; + } + } + dot = yank_delete(p, q, 0, yf); // delete word + } else if (strchr("^0bBeEft$", c1)) { + // single line copy text into a register and delete + dot = yank_delete(p, q, 0, yf); // delete word + } else if (strchr("cdykjHL%+-{}\r\n", c1)) { + // multiple line copy text into a register and delete + dot = yank_delete(p, q, 1, yf); // delete lines + if (c == 'c') { + dot = char_insert(dot, '\n'); + // on the last line of file don't move to prev line + if (dot != (end-1)) { + dot_prev(); + } + } else if (c == 'd') { + dot_begin(); + dot_skip_over_ws(); + } + } else { + // could not recognize object + c = c1 = 27; // error- + indicate_error(c); + } + if (c1 != 27) { + // if CHANGING, not deleting, start inserting after the delete + if (c == 'c') { + strcpy((char *) buf, "Change"); + goto dc_i; // start inserting + } + if (c == 'd') { + strcpy((char *) buf, "Delete"); + } +#ifdef BB_FEATURE_VI_YANKMARK + if (c == 'y' || c == 'Y') { + strcpy((char *) buf, "Yank"); + } + p = reg[YDreg]; + q = p + strlen((char *) p); + for (cnt = 0; p <= q; p++) { + if (*p == '\n') + cnt++; + } + psb("%s %d lines (%d chars) using [%c]", + buf, cnt, strlen((char *) reg[YDreg]), what_reg()); +#endif /* BB_FEATURE_VI_YANKMARK */ + end_cmd_q(); // stop adding to q + } + break; + case 'k': // k- goto prev line, same col + case VI_K_UP: // cursor key Up + if (cmdcnt-- > 1) { + do_cmd(c); + } // repeat cnt + dot_prev(); + dot = move_to_col(dot, ccol + offset); // try stay in same col + break; + case 'r': // r- replace the current char with user input + c1 = get_one_char(); // get the replacement char + if (*dot != '\n') { + *dot = c1; + file_modified = TRUE; // has the file been modified + } + end_cmd_q(); // stop adding to q + break; + case 't': // t- move to char prior to next x + last_forward_char = get_one_char(); + do_cmd(';'); + if (*dot == last_forward_char) + dot_left(); + last_forward_char= 0; + break; + case 'w': // w- forward a word + if (cmdcnt-- > 1) { + do_cmd(c); + } // repeat cnt + if (isalnum(*dot) || *dot == '_') { // we are on ALNUM + dot = skip_thing(dot, 1, FORWARD, S_END_ALNUM); + } else if (ispunct(*dot)) { // we are on PUNCT + dot = skip_thing(dot, 1, FORWARD, S_END_PUNCT); + } + if (dot < end - 1) + dot++; // move over word + if (isspace(*dot)) { + dot = skip_thing(dot, 2, FORWARD, S_OVER_WS); + } + break; + case 'z': // z- + c1 = get_one_char(); // get the replacement char + cnt = 0; + if (c1 == '.') + cnt = (rows - 2) / 2; // put dot at center + if (c1 == '-') + cnt = rows - 2; // put dot at bottom + screenbegin = begin_line(dot); // start dot at top + dot_scroll(cnt, -1); + break; + case '|': // |- move to column "cmdcnt" + dot = move_to_col(dot, cmdcnt - 1); // try to move to column + break; + case '~': // ~- flip the case of letters a-z -> A-Z + if (cmdcnt-- > 1) { + do_cmd(c); + } // repeat cnt + if (islower(*dot)) { + *dot = toupper(*dot); + file_modified = TRUE; // has the file been modified + } else if (isupper(*dot)) { + *dot = tolower(*dot); + file_modified = TRUE; // has the file been modified + } + dot_right(); + end_cmd_q(); // stop adding to q + break; + //----- The Cursor and Function Keys ----------------------------- + case VI_K_HOME: // Cursor Key Home + dot_begin(); + break; + // The Fn keys could point to do_macro which could translate them + case VI_K_FUN1: // Function Key F1 + case VI_K_FUN2: // Function Key F2 + case VI_K_FUN3: // Function Key F3 + case VI_K_FUN4: // Function Key F4 + case VI_K_FUN5: // Function Key F5 + case VI_K_FUN6: // Function Key F6 + case VI_K_FUN7: // Function Key F7 + case VI_K_FUN8: // Function Key F8 + case VI_K_FUN9: // Function Key F9 + case VI_K_FUN10: // Function Key F10 + case VI_K_FUN11: // Function Key F11 + case VI_K_FUN12: // Function Key F12 + break; + } + + dc1: + // if text[] just became empty, add back an empty line + if (end == text) { + (void) char_insert(text, '\n'); // start empty buf with dummy line + dot = text; + } + // it is OK for dot to exactly equal to end, otherwise check dot validity + if (dot != end) { + dot = bound_dot(dot); // make sure "dot" is valid + } +#ifdef BB_FEATURE_VI_YANKMARK + check_context(c); // update the current context +#endif /* BB_FEATURE_VI_YANKMARK */ + + if (!isdigit(c)) + cmdcnt = 0; // cmd was not a number, reset cmdcnt + cnt = dot - begin_line(dot); + // Try to stay off of the Newline + if (*dot == '\n' && cnt > 0 && cmd_mode == 0) + dot--; +} + +//----- The Colon commands ------------------------------------- +#ifdef BB_FEATURE_VI_COLON +static Byte *get_one_address(Byte * p, int *addr) // get colon addr, if present +{ + int st; + Byte *q; + +#ifdef BB_FEATURE_VI_YANKMARK + Byte c; +#endif /* BB_FEATURE_VI_YANKMARK */ +#ifdef BB_FEATURE_VI_SEARCH + Byte *pat, buf[BUFSIZ]; +#endif /* BB_FEATURE_VI_SEARCH */ + + *addr = -1; // assume no addr + if (*p == '.') { // the current line + p++; + q = begin_line(dot); + *addr = count_lines(text, q); +#ifdef BB_FEATURE_VI_YANKMARK + } else if (*p == '\'') { // is this a mark addr + p++; + c = tolower(*p); + p++; + if (c >= 'a' && c <= 'z') { + // we have a mark + c = c - 'a'; + q = mark[(int) c]; + if (q != NULL) { // is mark valid + *addr = count_lines(text, q); // count lines + } + } +#endif /* BB_FEATURE_VI_YANKMARK */ +#ifdef BB_FEATURE_VI_SEARCH + } else if (*p == '/') { // a search pattern + q = buf; + for (p++; *p; p++) { + if (*p == '/') + break; + *q++ = *p; + *q = '\0'; + } + pat = (Byte *) strdup((char *) buf); // save copy of pattern + if (*p == '/') + p++; + q = char_search(dot, pat, FORWARD, FULL); + if (q != NULL) { + *addr = count_lines(text, q); + } + free(pat); +#endif /* BB_FEATURE_VI_SEARCH */ + } else if (*p == '$') { // the last line in file + p++; + q = begin_line(end - 1); + *addr = count_lines(text, q); + } else if (isdigit(*p)) { // specific line number + sscanf((char *) p, "%d%n", addr, &st); + p += st; + } else { // I don't reconise this + // unrecognised address- assume -1 + *addr = -1; + } + return (p); +} + +static Byte *get_address(Byte *p, int *b, int *e) // get two colon addrs, if present +{ + //----- get the address' i.e., 1,3 'a,'b ----- + // get FIRST addr, if present + while (isblnk(*p)) + p++; // skip over leading spaces + if (*p == '%') { // alias for 1,$ + p++; + *b = 1; + *e = count_lines(text, end-1); + goto ga0; + } + p = get_one_address(p, b); + while (isblnk(*p)) + p++; + if (*p == ',') { // is there a address seperator + p++; + while (isblnk(*p)) + p++; + // get SECOND addr, if present + p = get_one_address(p, e); + } +ga0: + while (isblnk(*p)) + p++; // skip over trailing spaces + return (p); +} + +static void colon(Byte * buf) +{ + Byte c, *orig_buf, *buf1, *q, *r; + Byte *fn, cmd[BUFSIZ], args[BUFSIZ]; + int i, l, li, ch, st, b, e; + int useforce, forced; + struct stat st_buf; + + // :3154 // if (-e line 3154) goto it else stay put + // :4,33w! foo // write a portion of buffer to file "foo" + // :w // write all of buffer to current file + // :q // quit + // :q! // quit- dont care about modified file + // :'a,'z!sort -u // filter block through sort + // :'f // goto mark "f" + // :'fl // list literal the mark "f" line + // :.r bar // read file "bar" into buffer before dot + // :/123/,/abc/d // delete lines from "123" line to "abc" line + // :/xyz/ // goto the "xyz" line + // :s/find/replace/ // substitute pattern "find" with "replace" + // :! // run then return + // + if (strlen((char *) buf) <= 0) + goto vc1; + if (*buf == ':') + buf++; // move past the ':' + + forced = useforce = FALSE; + li = st = ch = i = 0; + b = e = -1; + q = text; // assume 1,$ for the range + r = end - 1; + li = count_lines(text, end - 1); + fn = cfn; // default to current file + memset(cmd, '\0', BUFSIZ); // clear cmd[] + memset(args, '\0', BUFSIZ); // clear args[] + + // look for optional address(es) :. :1 :1,9 :'q,'a :% + buf = get_address(buf, &b, &e); + + // remember orig command line + orig_buf = buf; + + // get the COMMAND into cmd[] + buf1 = cmd; + while (*buf != '\0') { + if (isspace(*buf)) + break; + *buf1++ = *buf++; + } + // get any ARGuments + while (isblnk(*buf)) + buf++; + /* FIXED strcpy((char *) args, (char *) buf); */ + if (strlcpy((char *) args, (char *) buf, sizeof((char *)args)) > sizeof((char *)args)) err(1, "strlcpy overflow in function colon"); + buf1 = (Byte *)last_char_is((char *)cmd, '!'); + if (buf1) { + useforce = TRUE; + *buf1 = '\0'; // get rid of ! + } + if (b >= 0) { + // if there is only one addr, then the addr + // is the line number of the single line the + // user wants. So, reset the end + // pointer to point at end of the "b" line + q = find_line(b); // what line is #b + r = end_line(q); + li = 1; + } + if (e >= 0) { + // we were given two addrs. change the + // end pointer to the addr given by user. + r = find_line(e); // what line is #e + r = end_line(r); + li = e - b + 1; + } + // ------------ now look for the command ------------ + i = strlen((char *) cmd); + if (i == 0) { // :123CR goto line #123 + if (b >= 0) { + dot = find_line(b); // what line is #b + dot_skip_over_ws(); + } + } else if (strncmp((char *) cmd, "!", 1) == 0) { // run a cmd + // :!ls run the + (void) alarm(0); // wait for input- no alarms + place_cursor(rows - 1, 0, FALSE); // go to Status line + clear_to_eol(); // clear the line + cookmode(); + system((char *)orig_buf+1); // run the cmd + rawmode(); + Hit_Return(); // let user see results + (void) alarm(3); // done waiting for input + } else if (strncmp((char *) cmd, "=", i) == 0) { // where is the address + if (b < 0) { // no addr given- use defaults + b = e = count_lines(text, dot); + } + psb("%d", b); + } else if (strncasecmp((char *) cmd, "delete", i) == 0) { // delete lines + if (b < 0) { // no addr given- use defaults + q = begin_line(dot); // assume .,. for the range + r = end_line(dot); + } + dot = yank_delete(q, r, 1, YANKDEL); // save, then delete lines + dot_skip_over_ws(); + } else if (strncasecmp((char *) cmd, "edit", i) == 0) { // Edit a file + int sr; + sr= 0; + // don't edit, if the current file has been modified + if (file_modified == TRUE && useforce != TRUE) { + psbs("No write since last change (:edit! overrides)"); + goto vc1; + } + if (strlen((char *)args) > 0) { + // the user supplied a file name + fn= args; + } else if (cfn != 0 && strlen((char *)cfn) > 0) { + // no user supplied name- use the current filename + fn= cfn; + goto vc5; + } else { + // no user file name, no current name- punt + psbs("No current filename"); + goto vc1; + } + + // see if file exists- if not, its just a new file request + if ((sr=stat((char*)fn, &st_buf)) < 0) { + // This is just a request for a new file creation. + // The file_insert below will fail but we get + // an empty buffer with a file name. Then the "write" + // command can do the create. + } else { + if ((st_buf.st_mode & (S_IFREG)) == 0) { + // This is not a regular file + psbs("\"%s\" is not a regular file", fn); + goto vc1; + } + if ((st_buf.st_mode & (S_IRUSR | S_IRGRP | S_IROTH)) == 0) { + // dont have any read permissions + psbs("\"%s\" is not readable", fn); + goto vc1; + } + } + + // There is a read-able regular file + // make this the current file + q = (Byte *) strdup((char *) fn); // save the cfn + if (cfn != 0) + free(cfn); // free the old name + cfn = q; // remember new cfn + + vc5: + // delete all the contents of text[] + new_text(2 * file_size(fn)); + screenbegin = dot = end = text; + + // insert new file + ch = file_insert(fn, text, file_size(fn)); + + if (ch < 1) { + // start empty buf with dummy line + (void) char_insert(text, '\n'); + ch= 1; + } + file_modified = FALSE; +#ifdef BB_FEATURE_VI_YANKMARK + if (Ureg >= 0 && Ureg < 28 && reg[Ureg] != 0) { + free(reg[Ureg]); // free orig line reg- for 'U' + reg[Ureg]= 0; + } + if (YDreg >= 0 && YDreg < 28 && reg[YDreg] != 0) { + free(reg[YDreg]); // free default yank/delete register + reg[YDreg]= 0; + } + for (li = 0; li < 28; li++) { + mark[li] = 0; + } // init the marks +#endif /* BB_FEATURE_VI_YANKMARK */ + // how many lines in text[]? + li = count_lines(text, end - 1); + psb("\"%s\"%s" +#ifdef BB_FEATURE_VI_READONLY + "%s" +#endif /* BB_FEATURE_VI_READONLY */ + " %dL, %dC", cfn, + (sr < 0 ? " [New file]" : ""), +#ifdef BB_FEATURE_VI_READONLY + ((vi_readonly == TRUE || readonly == TRUE) ? " [Read only]" : ""), +#endif /* BB_FEATURE_VI_READONLY */ + li, ch); + } else if (strncasecmp((char *) cmd, "file", i) == 0) { // what File is this + if (b != -1 || e != -1) { + ni((Byte *) "No address allowed on this command"); + goto vc1; + } + if (strlen((char *) args) > 0) { + // user wants a new filename + if (cfn != NULL) + free(cfn); + cfn = (Byte *) strdup((char *) args); + } else { + // user wants file status info + edit_status(); + } + } else if (strncasecmp((char *) cmd, "features", i) == 0) { // what features are available + // print out values of all features + place_cursor(rows - 1, 0, FALSE); // go to Status line, bottom of screen + clear_to_eol(); // clear the line + cookmode(); + show_help(); + rawmode(); + Hit_Return(); + } else if (strncasecmp((char *) cmd, "list", i) == 0) { // literal print line + if (b < 0) { // no addr given- use defaults + q = begin_line(dot); // assume .,. for the range + r = end_line(dot); + } + place_cursor(rows - 1, 0, FALSE); // go to Status line, bottom of screen + clear_to_eol(); // clear the line + write(1, "\r\n", 2); + for (; q <= r; q++) { + c = *q; + if (c > '~') + standout_start(); + if (c == '\n') { + write(1, "$\r", 2); + } else if (*q < ' ') { + write(1, "^", 1); + c += '@'; + } + write(1, &c, 1); + if (c > '~') + standout_end(); + } +#ifdef BB_FEATURE_VI_SET + vc2: +#endif /* BB_FEATURE_VI_SET */ + Hit_Return(); + } else if ((strncasecmp((char *) cmd, "quit", i) == 0) || (strncasecmp((char *) cmd, "q", i) == 0) || // Quit + (strncasecmp((char *) cmd, "next", i) == 0)) { // edit next file + if (useforce == TRUE) { + // force end of argv list + if (*cmd == 'q') { + optind = save_argc; + } + editing = 0; + goto vc1; + } + // don't exit if the file been modified + if (file_modified == TRUE) { + psbs("No write since last change (:%s! overrides)", + (*cmd == 'q' ? "quit" : "next")); + goto vc1; + } + // are there other file to edit + if (*cmd == 'q' && optind < save_argc - 1) { + psbs("%d more file to edit", (save_argc - optind - 1)); + goto vc1; + } + if (*cmd == 'n' && optind >= save_argc - 1) { + psbs("No more files to edit"); + goto vc1; + } + editing = 0; + } else if (strncasecmp((char *) cmd, "read", i) == 0) { // read file into text[] + fn = args; + if (strlen((char *) fn) <= 0) { + psbs("No filename given"); + goto vc1; + } + if (b < 0) { // no addr given- use defaults + q = begin_line(dot); // assume "dot" + } + // read after current line- unless user said ":0r foo" + if (b != 0) + q = next_line(q); +#ifdef BB_FEATURE_VI_READONLY + l= readonly; // remember current files' status +#endif + ch = file_insert(fn, q, file_size(fn)); +#ifdef BB_FEATURE_VI_READONLY + readonly= l; +#endif + if (ch < 0) + goto vc1; // nothing was inserted + // how many lines in text[]? + li = count_lines(q, q + ch - 1); + psb("\"%s\"" +#ifdef BB_FEATURE_VI_READONLY + "%s" +#endif /* BB_FEATURE_VI_READONLY */ + " %dL, %dC", fn, +#ifdef BB_FEATURE_VI_READONLY + ((vi_readonly == TRUE || readonly == TRUE) ? " [Read only]" : ""), +#endif /* BB_FEATURE_VI_READONLY */ + li, ch); + if (ch > 0) { + // if the insert is before "dot" then we need to update + if (q <= dot) + dot += ch; + file_modified = TRUE; + } + } else if (strncasecmp((char *) cmd, "rewind", i) == 0) { // rewind cmd line args + if (file_modified == TRUE && useforce != TRUE) { + psbs("No write since last change (:rewind! overrides)"); + } else { + // reset the filenames to edit + optind = fn_start - 1; + editing = 0; + } +#ifdef BB_FEATURE_VI_SET + } else if (strncasecmp((char *) cmd, "set", i) == 0) { // set or clear features + i = 0; // offset into args + if (strlen((char *) args) == 0) { + // print out values of all options + place_cursor(rows - 1, 0, FALSE); // go to Status line, bottom of screen + clear_to_eol(); // clear the line + printf("----------------------------------------\r\n"); +#ifdef BB_FEATURE_VI_SETOPTS + if (!autoindent) + printf("no"); + printf("autoindent "); + if (!err_method) + printf("no"); + printf("flash "); + if (!ignorecase) + printf("no"); + printf("ignorecase "); + if (!showmatch) + printf("no"); + printf("showmatch "); + printf("tabstop=%d ", tabstop); +#endif /* BB_FEATURE_VI_SETOPTS */ + printf("\r\n"); + goto vc2; + } + if (strncasecmp((char *) args, "no", 2) == 0) + i = 2; // ":set noautoindent" +#ifdef BB_FEATURE_VI_SETOPTS + if (strncasecmp((char *) args + i, "autoindent", 10) == 0 || + strncasecmp((char *) args + i, "ai", 2) == 0) { + autoindent = (i == 2) ? 0 : 1; + } + if (strncasecmp((char *) args + i, "flash", 5) == 0 || + strncasecmp((char *) args + i, "fl", 2) == 0) { + err_method = (i == 2) ? 0 : 1; + } + if (strncasecmp((char *) args + i, "ignorecase", 10) == 0 || + strncasecmp((char *) args + i, "ic", 2) == 0) { + ignorecase = (i == 2) ? 0 : 1; + } + if (strncasecmp((char *) args + i, "showmatch", 9) == 0 || + strncasecmp((char *) args + i, "sm", 2) == 0) { + showmatch = (i == 2) ? 0 : 1; + } + if (strncasecmp((char *) args + i, "tabstop", 7) == 0) { + sscanf(strchr((char *) args + i, '='), "=%d", &ch); + if (ch > 0 && ch < columns - 1) + tabstop = ch; + } +#endif /* BB_FEATURE_VI_SETOPTS */ +#endif /* BB_FEATURE_VI_SET */ +#ifdef BB_FEATURE_VI_SEARCH + } else if (strncasecmp((char *) cmd, "s", 1) == 0) { // substitute a pattern with a replacement pattern + Byte *ls, *F, *R; + int gflag; + + // F points to the "find" pattern + // R points to the "replace" pattern + // replace the cmd line delimiters "/" with NULLs + gflag = 0; // global replace flag + c = orig_buf[1]; // what is the delimiter + F = orig_buf + 2; // start of "find" + R = (Byte *) strchr((char *) F, c); // middle delimiter + if (!R) goto colon_s_fail; + *R++ = '\0'; // terminate "find" + buf1 = (Byte *) strchr((char *) R, c); + if (!buf1) goto colon_s_fail; + *buf1++ = '\0'; // terminate "replace" + if (*buf1 == 'g') { // :s/foo/bar/g + buf1++; + gflag++; // turn on gflag + } + q = begin_line(q); + if (b < 0) { // maybe :s/foo/bar/ + q = begin_line(dot); // start with cur line + b = count_lines(text, q); // cur line number + } + if (e < 0) + e = b; // maybe :.s/foo/bar/ + for (i = b; i <= e; i++) { // so, :20,23 s \0 find \0 replace \0 + ls = q; // orig line start + vc4: + buf1 = char_search(q, F, FORWARD, LIMITED); // search cur line only for "find" + if (buf1 != NULL) { + // we found the "find" pattern- delete it + (void) text_hole_delete(buf1, buf1 + strlen((char *) F) - 1); + // inset the "replace" patern + (void) string_insert(buf1, R); // insert the string + // check for "global" :s/foo/bar/g + if (gflag == 1) { + if ((buf1 + strlen((char *) R)) < end_line(ls)) { + q = buf1 + strlen((char *) R); + goto vc4; // don't let q move past cur line + } + } + } + q = next_line(ls); + } +#endif /* BB_FEATURE_VI_SEARCH */ + } else if (strncasecmp((char *) cmd, "version", i) == 0) { // show software version + psb("%s", vi_Version); + } else if ((strncasecmp((char *) cmd, "write", i) == 0) || // write text to file + (strncasecmp((char *) cmd, "wq", i) == 0)) { // write text to file + // is there a file name to write to? + if (strlen((char *) args) > 0) { + fn = args; + } +#ifdef BB_FEATURE_VI_READONLY + if ((vi_readonly == TRUE || readonly == TRUE) && useforce == FALSE) { + psbs("\"%s\" File is read only", fn); + goto vc3; + } +#endif /* BB_FEATURE_VI_READONLY */ + // how many lines in text[]? + li = count_lines(q, r); + ch = r - q + 1; + // see if file exists- if not, its just a new file request + if (useforce == TRUE) { + // if "fn" is not write-able, chmod u+w + // sprintf(syscmd, "chmod u+w %s", fn); + // system(syscmd); + forced = TRUE; + } + l = file_write(fn, q, r); + if (useforce == TRUE && forced == TRUE) { + // chmod u-w + // sprintf(syscmd, "chmod u-w %s", fn); + // system(syscmd); + forced = FALSE; + } + psb("\"%s\" %dL, %dC", fn, li, l); + if (q == text && r == end - 1 && l == ch) + file_modified = FALSE; + if (cmd[1] == 'q' && l == ch) { + editing = 0; + } +#ifdef BB_FEATURE_VI_READONLY + vc3:; +#endif /* BB_FEATURE_VI_READONLY */ +#ifdef BB_FEATURE_VI_YANKMARK + } else if (strncasecmp((char *) cmd, "yank", i) == 0) { // yank lines + if (b < 0) { // no addr given- use defaults + q = begin_line(dot); // assume .,. for the range + r = end_line(dot); + } + text_yank(q, r, YDreg); + li = count_lines(q, r); + psb("Yank %d lines (%d chars) into [%c]", + li, strlen((char *) reg[YDreg]), what_reg()); +#endif /* BB_FEATURE_VI_YANKMARK */ + } else { + // cmd unknown + ni((Byte *) cmd); + } + vc1: + dot = bound_dot(dot); // make sure "dot" is valid + return; +#ifdef BB_FEATURE_VI_SEARCH +colon_s_fail: + psb(":s expression missing delimiters"); + return; +#endif + +} + +static void Hit_Return(void) +{ + char c; + + standout_start(); // start reverse video + write(1, "[Hit return to continue]", 24); + standout_end(); // end reverse video + while ((c = get_one_char()) != '\n' && c != '\r') /*do nothing */ + ; + redraw(TRUE); // force redraw all +} +#endif /* BB_FEATURE_VI_COLON */ + +//----- Synchronize the cursor to Dot -------------------------- +static void sync_cursor(Byte * d, int *row, int *col) +{ + Byte *beg_cur, *end_cur; // begin and end of "d" line + Byte *beg_scr, *end_scr; // begin and end of screen + Byte *tp; + int cnt, ro, co; + + beg_cur = begin_line(d); // first char of cur line + end_cur = end_line(d); // last char of cur line + + beg_scr = end_scr = screenbegin; // first char of screen + end_scr = end_screen(); // last char of screen + + if (beg_cur < screenbegin) { + // "d" is before top line on screen + // how many lines do we have to move + cnt = count_lines(beg_cur, screenbegin); + sc1: + screenbegin = beg_cur; + if (cnt > (rows - 1) / 2) { + // we moved too many lines. put "dot" in middle of screen + for (cnt = 0; cnt < (rows - 1) / 2; cnt++) { + screenbegin = prev_line(screenbegin); + } + } + } else if (beg_cur > end_scr) { + // "d" is after bottom line on screen + // how many lines do we have to move + cnt = count_lines(end_scr, beg_cur); + if (cnt > (rows - 1) / 2) + goto sc1; // too many lines + for (ro = 0; ro < cnt - 1; ro++) { + // move screen begin the same amount + screenbegin = next_line(screenbegin); + // now, move the end of screen + end_scr = next_line(end_scr); + end_scr = end_line(end_scr); + } + } + // "d" is on screen- find out which row + tp = screenbegin; + for (ro = 0; ro < rows - 1; ro++) { // drive "ro" to correct row + if (tp == beg_cur) + break; + tp = next_line(tp); + } + + // find out what col "d" is on + co = 0; + do { // drive "co" to correct column + if (*tp == '\n' || *tp == '\0') + break; + if (*tp == '\t') { + // 7 - (co % 8 ) + co += ((tabstop - 1) - (co % tabstop)); + } else if (*tp < ' ') { + co++; // display as ^X, use 2 columns + } + } while (tp++ < d && ++co); + + // "co" is the column where "dot" is. + // The screen has "columns" columns. + // The currently displayed columns are 0+offset -- columns+ofset + // |-------------------------------------------------------------| + // ^ ^ ^ + // offset | |------- columns ----------------| + // + // If "co" is already in this range then we do not have to adjust offset + // but, we do have to subtract the "offset" bias from "co". + // If "co" is outside this range then we have to change "offset". + // If the first char of a line is a tab the cursor will try to stay + // in column 7, but we have to set offset to 0. + + if (co < 0 + offset) { + offset = co; + } + if (co >= columns + offset) { + offset = co - columns + 1; + } + // if the first char of the line is a tab, and "dot" is sitting on it + // force offset to 0. + if (d == beg_cur && *d == '\t') { + offset = 0; + } + co -= offset; + + *row = ro; + *col = co; +} + +//----- Text Movement Routines --------------------------------- +static Byte *begin_line(Byte * p) // return pointer to first char cur line +{ + while (p > text && p[-1] != '\n') + p--; // go to cur line B-o-l + return (p); +} + +static Byte *end_line(Byte * p) // return pointer to NL of cur line line +{ + while (p < end - 1 && *p != '\n') + p++; // go to cur line E-o-l + return (p); +} + +static Byte *dollar_line(Byte * p) // return pointer to just before NL line +{ + while (p < end - 1 && *p != '\n') + p++; // go to cur line E-o-l + // Try to stay off of the Newline + if (*p == '\n' && (p - begin_line(p)) > 0) + p--; + return (p); +} + +static Byte *prev_line(Byte * p) // return pointer first char prev line +{ + p = begin_line(p); // goto begining of cur line + if (p[-1] == '\n' && p > text) + p--; // step to prev line + p = begin_line(p); // goto begining of prev line + return (p); +} + +static Byte *next_line(Byte * p) // return pointer first char next line +{ + p = end_line(p); + if (*p == '\n' && p < end - 1) + p++; // step to next line + return (p); +} + +//----- Text Information Routines ------------------------------ +static Byte *end_screen(void) +{ + Byte *q; + int cnt; + + // find new bottom line + q = screenbegin; + for (cnt = 0; cnt < rows - 2; cnt++) + q = next_line(q); + q = end_line(q); + return (q); +} + +static int count_lines(Byte * start, Byte * stop) // count line from start to stop +{ + Byte *q; + int cnt; + + if (stop < start) { // start and stop are backwards- reverse them + q = start; + start = stop; + stop = q; + } + cnt = 0; + stop = end_line(stop); // get to end of this line + for (q = start; q <= stop && q <= end - 1; q++) { + if (*q == '\n') + cnt++; + } + return (cnt); +} + +static Byte *find_line(int li) // find begining of line #li +{ + Byte *q; + + for (q = text; li > 1; li--) { + q = next_line(q); + } + return (q); +} + +//----- Dot Movement Routines ---------------------------------- +static void dot_left(void) +{ + if (dot > text && dot[-1] != '\n') + dot--; +} + +static void dot_right(void) +{ + if (dot < end - 1 && *dot != '\n') + dot++; +} + +static void dot_begin(void) +{ + dot = begin_line(dot); // return pointer to first char cur line +} + +static void dot_end(void) +{ + dot = end_line(dot); // return pointer to last char cur line +} + +static Byte *move_to_col(Byte * p, int l) +{ + int co; + + p = begin_line(p); + co = 0; + do { + if (*p == '\n' || *p == '\0') + break; + if (*p == '\t') { + // 7 - (co % 8 ) + co += ((tabstop - 1) - (co % tabstop)); + } else if (*p < ' ') { + co++; // display as ^X, use 2 columns + } + } while (++co <= l && p++ < end); + return (p); +} + +static void dot_next(void) +{ + dot = next_line(dot); +} + +static void dot_prev(void) +{ + dot = prev_line(dot); +} + +static void dot_scroll(int cnt, int dir) +{ + Byte *q; + + for (; cnt > 0; cnt--) { + if (dir < 0) { + // scroll Backwards + // ctrl-Y scroll up one line + screenbegin = prev_line(screenbegin); + } else { + // scroll Forwards + // ctrl-E scroll down one line + screenbegin = next_line(screenbegin); + } + } + // make sure "dot" stays on the screen so we dont scroll off + if (dot < screenbegin) + dot = screenbegin; + q = end_screen(); // find new bottom line + if (dot > q) + dot = begin_line(q); // is dot is below bottom line? + dot_skip_over_ws(); +} + +static void dot_skip_over_ws(void) +{ + // skip WS + while (isspace(*dot) && *dot != '\n' && dot < end - 1) + dot++; +} + +static void dot_delete(void) // delete the char at 'dot' +{ + (void) text_hole_delete(dot, dot); +} + +static Byte *bound_dot(Byte * p) // make sure text[0] <= P < "end" +{ + if (p >= end && end > text) { + p = end - 1; + indicate_error('1'); + } + if (p < text) { + p = text; + indicate_error('2'); + } + return (p); +} + +//----- Helper Utility Routines -------------------------------- + +//---------------------------------------------------------------- +//----- Char Routines -------------------------------------------- +/* Chars that are part of a word- + * 0123456789_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz + * Chars that are Not part of a word (stoppers) + * !"#$%&'()*+,-./:;<=>?@[\]^`{|}~ + * Chars that are WhiteSpace + * TAB NEWLINE VT FF RETURN SPACE + * DO NOT COUNT NEWLINE AS WHITESPACE + */ + +static Byte *new_screen(int ro, int co) +{ + int li; + + if (screen != 0) + free(screen); + screensize = ro * co + 8; + screen = (Byte *) malloc(screensize); + // initialize the new screen. assume this will be a empty file. + screen_erase(); + // non-existant text[] lines start with a tilde (~). + for (li = 1; li < ro - 1; li++) { + screen[(li * co) + 0] = '~'; + } + return (screen); +} + +static Byte *new_text(int size) +{ + if (size < 10240) + size = 10240; // have a minimum size for new files + if (text != 0) { + //text -= 4; + free(text); + } + text = (Byte *) malloc(size + 8); + memset(text, '\0', size); // clear new text[] + //text += 4; // leave some room for "oops" + textend = text + size - 1; + //textend -= 4; // leave some root for "oops" + return (text); +} + +#ifdef BB_FEATURE_VI_SEARCH +static int mycmp(Byte * s1, Byte * s2, int len) +{ + int i; + + i = strncmp((char *) s1, (char *) s2, len); +#ifdef BB_FEATURE_VI_SETOPTS + if (ignorecase) { + i = strncasecmp((char *) s1, (char *) s2, len); + } +#endif /* BB_FEATURE_VI_SETOPTS */ + return (i); +} + +static Byte *char_search(Byte * p, Byte * pat, int dir, int range) // search for pattern starting at p +{ +#ifndef REGEX_SEARCH + Byte *start, *stop; + int len; + + len = strlen((char *) pat); + if (dir == FORWARD) { + stop = end - 1; // assume range is p - end-1 + if (range == LIMITED) + stop = next_line(p); // range is to next line + for (start = p; start < stop; start++) { + if (mycmp(start, pat, len) == 0) { + return (start); + } + } + } else if (dir == BACK) { + stop = text; // assume range is text - p + if (range == LIMITED) + stop = prev_line(p); // range is to prev line + for (start = p - len; start >= stop; start--) { + if (mycmp(start, pat, len) == 0) { + return (start); + } + } + } + // pattern not found + return (NULL); +#else /*REGEX_SEARCH */ + char *q; + struct re_pattern_buffer preg; + int i; + int size, range; + + re_syntax_options = RE_SYNTAX_POSIX_EXTENDED; + preg.translate = 0; + preg.fastmap = 0; + preg.buffer = 0; + preg.allocated = 0; + + // assume a LIMITED forward search + q = next_line(p); + q = end_line(q); + q = end - 1; + if (dir == BACK) { + q = prev_line(p); + q = text; + } + // count the number of chars to search over, forward or backward + size = q - p; + if (size < 0) + size = p - q; + // RANGE could be negative if we are searching backwards + range = q - p; + + q = (char *) re_compile_pattern(pat, strlen((char *) pat), &preg); + if (q != 0) { + // The pattern was not compiled + psbs("bad search pattern: \"%s\": %s", pat, q); + i = 0; // return p if pattern not compiled + goto cs1; + } + + q = p; + if (range < 0) { + q = p - size; + if (q < text) + q = text; + } + // search for the compiled pattern, preg, in p[] + // range < 0- search backward + // range > 0- search forward + // 0 < start < size + // re_search() < 0 not found or error + // re_search() > 0 index of found pattern + // struct pattern char int int int struct reg + // re_search (*pattern_buffer, *string, size, start, range, *regs) + i = re_search(&preg, q, size, 0, range, 0); + if (i == -1) { + p = 0; + i = 0; // return NULL if pattern not found + } + cs1: + if (dir == FORWARD) { + p = p + i; + } else { + p = p - i; + } + return (p); +#endif /*REGEX_SEARCH */ +} +#endif /* BB_FEATURE_VI_SEARCH */ + +static Byte *char_insert(Byte * p, Byte c) // insert the char c at 'p' +{ + if (c == 22) { // Is this an ctrl-V? + p = stupid_insert(p, '^'); // use ^ to indicate literal next + p--; // backup onto ^ + refresh(FALSE); // show the ^ + c = get_one_char(); + *p = c; + p++; + file_modified = TRUE; // has the file been modified + } else if (c == 27) { // Is this an ESC? + cmd_mode = 0; + cmdcnt = 0; + end_cmd_q(); // stop adding to q + strcpy((char *) status_buffer, " "); // clear the status buffer + if ((p[-1] != '\n') && (dot>text)) { + p--; + } + } else if (c == erase_char) { // Is this a BS + // 123456789 + if ((p[-1] != '\n') && (dot>text)) { + p--; + p = text_hole_delete(p, p); // shrink buffer 1 char +#ifdef BB_FEATURE_VI_DOT_CMD + // also rmove char from last_modifying_cmd + if (strlen((char *) last_modifying_cmd) > 0) { + Byte *q; + + q = last_modifying_cmd; + q[strlen((char *) q) - 1] = '\0'; // erase BS + q[strlen((char *) q) - 1] = '\0'; // erase prev char + } +#endif /* BB_FEATURE_VI_DOT_CMD */ + } + } else { + // insert a char into text[] + Byte *sp; // "save p" + + if (c == 13) + c = '\n'; // translate \r to \n + sp = p; // remember addr of insert + p = stupid_insert(p, c); // insert the char +#ifdef BB_FEATURE_VI_SETOPTS + if (showmatch && strchr(")]}", *sp) != NULL) { + showmatching(sp); + } + if (autoindent && c == '\n') { // auto indent the new line + Byte *q; + + q = prev_line(p); // use prev line as templet + for (; isblnk(*q); q++) { + p = stupid_insert(p, *q); // insert the char + } + } +#endif /* BB_FEATURE_VI_SETOPTS */ + } + return (p); +} + +static Byte *stupid_insert(Byte * p, Byte c) // stupidly insert the char c at 'p' +{ + p = text_hole_make(p, 1); + if (p != 0) { + *p = c; + file_modified = TRUE; // has the file been modified + p++; + } + return (p); +} + +static Byte find_range(Byte ** start, Byte ** stop, Byte c) +{ + Byte *save_dot, *p, *q; + int cnt; + + save_dot = dot; + p = q = dot; + + if (strchr("cdy><", c)) { + // these cmds operate on whole lines + p = q = begin_line(p); + for (cnt = 1; cnt < cmdcnt; cnt++) { + q = next_line(q); + } + q = end_line(q); + } else if (strchr("^%$0bBeEft", c)) { + // These cmds operate on char positions + do_cmd(c); // execute movement cmd + q = dot; + } else if (strchr("wW", c)) { + do_cmd(c); // execute movement cmd + if (dot > text) + dot--; // move back off of next word + if (dot > text && *dot == '\n') + dot--; // stay off NL + q = dot; + } else if (strchr("H-k{", c)) { + // these operate on multi-lines backwards + q = end_line(dot); // find NL + do_cmd(c); // execute movement cmd + dot_begin(); + p = dot; + } else if (strchr("L+j}\r\n", c)) { + // these operate on multi-lines forwards + p = begin_line(dot); + do_cmd(c); // execute movement cmd + dot_end(); // find NL + q = dot; + } else { + c = 27; // error- return an ESC char + //break; + } + *start = p; + *stop = q; + if (q < p) { + *start = q; + *stop = p; + } + dot = save_dot; + return (c); +} + +static int st_test(Byte * p, int type, int dir, Byte * tested) +{ + Byte c, c0, ci; + int test, inc; + + inc = dir; + c = c0 = p[0]; + ci = p[inc]; + test = 0; + + if (type == S_BEFORE_WS) { + c = ci; + test = ((!isspace(c)) || c == '\n'); + } + if (type == S_TO_WS) { + c = c0; + test = ((!isspace(c)) || c == '\n'); + } + if (type == S_OVER_WS) { + c = c0; + test = ((isspace(c))); + } + if (type == S_END_PUNCT) { + c = ci; + test = ((ispunct(c))); + } + if (type == S_END_ALNUM) { + c = ci; + test = ((isalnum(c)) || c == '_'); + } + *tested = c; + return (test); +} + +static Byte *skip_thing(Byte * p, int linecnt, int dir, int type) +{ + Byte c; + + while (st_test(p, type, dir, &c)) { + // make sure we limit search to correct number of lines + if (c == '\n' && --linecnt < 1) + break; + if (dir >= 0 && p >= end - 1) + break; + if (dir < 0 && p <= text) + break; + p += dir; // move to next char + } + return (p); +} + +// find matching char of pair () [] {} +static Byte *find_pair(Byte * p, Byte c) +{ + Byte match, *q; + int dir, level; + + match = ')'; + level = 1; + dir = 1; // assume forward + switch (c) { + case '(': + match = ')'; + break; + case '[': + match = ']'; + break; + case '{': + match = '}'; + break; + case ')': + match = '('; + dir = -1; + break; + case ']': + match = '['; + dir = -1; + break; + case '}': + match = '{'; + dir = -1; + break; + } + for (q = p + dir; text <= q && q < end; q += dir) { + // look for match, count levels of pairs (( )) + if (*q == c) + level++; // increase pair levels + if (*q == match) + level--; // reduce pair level + if (level == 0) + break; // found matching pair + } + if (level != 0) + q = NULL; // indicate no match + return (q); +} + +#ifdef BB_FEATURE_VI_SETOPTS +// show the matching char of a pair, () [] {} +static void showmatching(Byte * p) +{ + Byte *q, *save_dot; + + // we found half of a pair + q = find_pair(p, *p); // get loc of matching char + if (q == NULL) { + indicate_error('3'); // no matching char + } else { + // "q" now points to matching pair + save_dot = dot; // remember where we are + dot = q; // go to new loc + refresh(FALSE); // let the user see it + (void) mysleep(40); // give user some time + dot = save_dot; // go back to old loc + refresh(FALSE); + } +} +#endif /* BB_FEATURE_VI_SETOPTS */ + +// open a hole in text[] +static Byte *text_hole_make(Byte * p, int size) // at "p", make a 'size' byte hole +{ + Byte *src, *dest; + int cnt; + + if (size <= 0) + goto thm0; + src = p; + dest = p + size; + cnt = end - src; // the rest of buffer + if (memmove(dest, src, cnt) != dest) { + psbs("can't create room for new characters"); + } + memset(p, ' ', size); // clear new hole + end = end + size; // adjust the new END + file_modified = TRUE; // has the file been modified + thm0: + return (p); +} + +// close a hole in text[] +static Byte *text_hole_delete(Byte * p, Byte * q) // delete "p" thru "q", inclusive +{ + Byte *src, *dest; + int cnt, hole_size; + + // move forwards, from beginning + // assume p <= q + src = q + 1; + dest = p; + if (q < p) { // they are backward- swap them + src = p + 1; + dest = q; + } + hole_size = q - p + 1; + cnt = end - src; + if (src < text || src > end) + goto thd0; + if (dest < text || dest >= end) + goto thd0; + if (src >= end) + goto thd_atend; // just delete the end of the buffer + if (memmove(dest, src, cnt) != dest) { + psbs("can't delete the character"); + } + thd_atend: + end = end - hole_size; // adjust the new END + if (dest >= end) + dest = end - 1; // make sure dest in below end-1 + if (end <= text) + dest = end = text; // keep pointers valid + file_modified = TRUE; // has the file been modified + thd0: + return (dest); +} + +// copy text into register, then delete text. +// if dist <= 0, do not include, or go past, a NewLine +// +static Byte *yank_delete(Byte * start, Byte * stop, int dist, int yf) +{ + Byte *p; + + // make sure start <= stop + if (start > stop) { + // they are backwards, reverse them + p = start; + start = stop; + stop = p; + } + if (dist <= 0) { + // we can not cross NL boundaries + p = start; + if (*p == '\n') + return (p); + // dont go past a NewLine + for (; p + 1 <= stop; p++) { + if (p[1] == '\n') { + stop = p; // "stop" just before NewLine + break; + } + } + } + p = start; +#ifdef BB_FEATURE_VI_YANKMARK + text_yank(start, stop, YDreg); +#endif /* BB_FEATURE_VI_YANKMARK */ + if (yf == YANKDEL) { + p = text_hole_delete(start, stop); + } // delete lines + return (p); +} + +static void show_help(void) +{ + fprintf(stderr, "version: %s\n", vi_Version); + puts("These features are available:" +#ifdef BB_FEATURE_VI_SEARCH + "\n\tPattern searches with / and ?" +#endif /* BB_FEATURE_VI_SEARCH */ +#ifdef BB_FEATURE_VI_DOT_CMD + "\n\tLast command repeat with \'.\'" +#endif /* BB_FEATURE_VI_DOT_CMD */ +#ifdef BB_FEATURE_VI_YANKMARK + "\n\tLine marking with 'x" + "\n\tNamed buffers with \"x" +#endif /* BB_FEATURE_VI_YANKMARK */ +#ifdef BB_FEATURE_VI_READONLY + "\n\tReadonly if vi is called as \"view\"" + "\n\tReadonly with -R command line arg" +#endif /* BB_FEATURE_VI_READONLY */ +#ifdef BB_FEATURE_VI_SET + "\n\tSome colon mode commands with \':\'" +#endif /* BB_FEATURE_VI_SET */ +#ifdef BB_FEATURE_VI_SETOPTS + "\n\tSettable options with \":set\"" +#endif /* BB_FEATURE_VI_SETOPTS */ +#ifdef BB_FEATURE_VI_USE_SIGNALS + "\n\tSignal catching- ^C" + "\n\tJob suspend and resume with ^Z" +#endif /* BB_FEATURE_VI_USE_SIGNALS */ +#ifdef BB_FEATURE_VI_WIN_RESIZE + "\n\tAdapt to window re-sizes" +#endif /* BB_FEATURE_VI_WIN_RESIZE */ + ); +} + +static void print_literal(Byte * buf, Byte * s) // copy s to buf, convert unprintable +{ + Byte c, b[2]; + + b[1] = '\0'; + strcpy((char *) buf, ""); // init buf + if (strlen((char *) s) <= 0) + s = (Byte *) "(NULL)"; + for (; *s > '\0'; s++) { + c = *s; + if (*s > '~') { + strlcat((char *) buf, SOs, BUFSIZ); /* FIXED strlcat BUFSIZ */ + c = *s - 128; + } + if (*s < ' ') { + strcat((char *) buf, "^"); + c += '@'; + } + b[0] = c; + strlcat((char *) buf, (char *) b, BUFSIZ); /* FIXED added BUFSIZ and converted to strlcat() */ + if (*s > '~') + strlcat((char *) buf, SOn, BUFSIZ); /* FIXED strlcat BUFSIZ */ + if (*s == '\n') { + strcat((char *) buf, "$"); + } + } +} + +#ifdef BB_FEATURE_VI_DOT_CMD +static void start_new_cmd_q(Byte c) +{ + // release old cmd + if (last_modifying_cmd != 0) + free(last_modifying_cmd); + // get buffer for new cmd + last_modifying_cmd = (Byte *) malloc(BUFSIZ); + memset(last_modifying_cmd, '\0', BUFSIZ); // clear new cmd queue + // if there is a current cmd count put it in the buffer first + if (cmdcnt > 0) + sprintf((char *) last_modifying_cmd, "%d", cmdcnt); + // save char c onto queue + last_modifying_cmd[strlen((char *) last_modifying_cmd)] = c; + adding2q = 1; + return; +} + +static void end_cmd_q() +{ +#ifdef BB_FEATURE_VI_YANKMARK + YDreg = 26; // go back to default Yank/Delete reg +#endif /* BB_FEATURE_VI_YANKMARK */ + adding2q = 0; + return; +} +#endif /* BB_FEATURE_VI_DOT_CMD */ + +#if defined(BB_FEATURE_VI_YANKMARK) || defined(BB_FEATURE_VI_COLON) || defined(BB_FEATURE_VI_CRASHME) +static Byte *string_insert(Byte * p, Byte * s) // insert the string at 'p' +{ + int cnt, i; + + i = strlen((char *) s); + p = text_hole_make(p, i); + strncpy((char *) p, (char *) s, i); + for (cnt = 0; *s != '\0'; s++) { + if (*s == '\n') + cnt++; + } +#ifdef BB_FEATURE_VI_YANKMARK + psb("Put %d lines (%d chars) from [%c]", cnt, i, what_reg()); +#endif /* BB_FEATURE_VI_YANKMARK */ + return (p); +} +#endif /* BB_FEATURE_VI_YANKMARK || BB_FEATURE_VI_COLON || BB_FEATURE_VI_CRASHME */ + +#ifdef BB_FEATURE_VI_YANKMARK +static Byte *text_yank(Byte * p, Byte * q, int dest) // copy text into a register +{ + Byte *t; + int cnt; + + if (q < p) { // they are backwards- reverse them + t = q; + q = p; + p = t; + } + cnt = q - p + 1; + t = reg[dest]; + if (t != 0) { // if already a yank register + free(t); // free it + } + t = (Byte *) malloc(cnt + 1); // get a new register + memset(t, '\0', cnt + 1); // clear new text[] + strncpy((char *) t, (char *) p, cnt); // copy text[] into bufer + reg[dest] = t; + return (p); +} + +static Byte what_reg(void) +{ + Byte c; + int i; + + i = 0; + c = 'D'; // default to D-reg + if (0 <= YDreg && YDreg <= 25) + c = 'a' + (Byte) YDreg; + if (YDreg == 26) + c = 'D'; + if (YDreg == 27) + c = 'U'; + return (c); +} + +static void check_context(Byte cmd) +{ + // A context is defined to be "modifying text" + // Any modifying command establishes a new context. + + if (dot < context_start || dot > context_end) { + if (strchr((char *) modifying_cmds, cmd) != NULL) { + // we are trying to modify text[]- make this the current context + mark[27] = mark[26]; // move cur to prev + mark[26] = dot; // move local to cur + context_start = prev_line(prev_line(dot)); + context_end = next_line(next_line(dot)); + //loiter= start_loiter= now; + } + } + return; +} + +static Byte *swap_context(Byte * p) // goto new context for '' command make this the current context +{ + Byte *tmp; + + // the current context is in mark[26] + // the previous context is in mark[27] + // only swap context if other context is valid + if (text <= mark[27] && mark[27] <= end - 1) { + tmp = mark[27]; + mark[27] = mark[26]; + mark[26] = tmp; + p = mark[26]; // where we are going- previous context + context_start = prev_line(prev_line(prev_line(p))); + context_end = next_line(next_line(next_line(p))); + } + return (p); +} +#endif /* BB_FEATURE_VI_YANKMARK */ + +static int isblnk(Byte c) // is the char a blank or tab +{ + return (c == ' ' || c == '\t'); +} + +//----- Set terminal attributes -------------------------------- +static void rawmode(void) +{ +#if 0 + tcgetattr(0, &term_orig); + term_vi = term_orig; + term_vi.c_lflag &= (~ICANON & ~ECHO); // leave ISIG ON- allow intr's + term_vi.c_iflag &= (~IXON & ~ICRNL); + term_vi.c_oflag &= (~ONLCR); +#ifndef linux + term_vi.c_cc[VMIN] = 1; + term_vi.c_cc[VTIME] = 0; +#endif + erase_char = term_vi.c_cc[VERASE]; + tcsetattr(0, TCSANOW, &term_vi); +#else + ioctl(0, TIOCGETP, &term_orig); + term_vi = term_orig; + + term_vi.sg_flags &= ~(ECHO | CRMOD | XTABS | RAW); + term_vi.sg_flags |= CBREAK; + + ioctl(0, TIOCSETP, &term_vi); +#endif +} + +static void cookmode(void) +{ +#if 0 + tcsetattr(0, TCSANOW, &term_orig); +#else + ioctl(0, TIOCSETP, &term_orig); +#endif +} + +#ifdef BB_FEATURE_VI_WIN_RESIZE +//----- See what the window size currently is -------------------- +static void window_size_get(int sig) +{ + int i; + + i = ioctl(0, TIOCGWINSZ, &winsize); + if (i != 0) { + // force 24x80 + winsize.ws_row = 24; + winsize.ws_col = 80; + } + if (winsize.ws_row <= 1) { + winsize.ws_row = 24; + } + if (winsize.ws_col <= 1) { + winsize.ws_col = 80; + } + rows = (int) winsize.ws_row; + columns = (int) winsize.ws_col; +} +#endif /* BB_FEATURE_VI_WIN_RESIZE */ + +//----- Come here when we get a window resize signal --------- +#ifdef BB_FEATURE_VI_USE_SIGNALS +static void winch_sig(int sig) +{ + signal(SIGWINCH, winch_sig); +#ifdef BB_FEATURE_VI_WIN_RESIZE + window_size_get(0); +#endif /* BB_FEATURE_VI_WIN_RESIZE */ + new_screen(rows, columns); // get memory for virtual screen + redraw(TRUE); // re-draw the screen +} + +//----- Come here when we get a continue signal ------------------- +static void cont_sig(int sig) +{ + rawmode(); // terminal to "raw" + *status_buffer = '\0'; // clear the status buffer + redraw(TRUE); // re-draw the screen + + signal(SIGTSTP, suspend_sig); + signal(SIGCONT, SIG_DFL); + kill(getpid(), SIGCONT); +} + +//----- Come here when we get a Suspend signal ------------------- +static void suspend_sig(int sig) +{ + place_cursor(rows - 1, 0, FALSE); // go to bottom of screen + clear_to_eol(); // Erase to end of line + cookmode(); // terminal to "cooked" + + signal(SIGCONT, cont_sig); + signal(SIGTSTP, SIG_DFL); + kill(getpid(), SIGTSTP); +} + +//----- Come here when we get a signal --------------------------- +static void catch_sig(int sig) +{ + signal(SIGHUP, catch_sig); + signal(SIGINT, catch_sig); + signal(SIGTERM, catch_sig); + longjmp(restart, sig); +} + +static void alarm_sig(int sig) +{ + signal(SIGALRM, catch_sig); + longjmp(restart, sig); +} + +//----- Come here when we get a core dump signal ----------------- +static void core_sig(int sig) +{ + signal(SIGQUIT, core_sig); + signal(SIGILL, core_sig); + signal(SIGTRAP, core_sig); + signal(SIGIOT, core_sig); + signal(SIGABRT, core_sig); + signal(SIGFPE, core_sig); + signal(SIGBUS, core_sig); + signal(SIGSEGV, core_sig); +#ifdef SIGSYS + signal(SIGSYS, core_sig); +#endif + + dot = bound_dot(dot); // make sure "dot" is valid + + longjmp(restart, sig); +} +#endif /* BB_FEATURE_VI_USE_SIGNALS */ + +static int mysleep(int hund) // sleep for 'h' 1/100 seconds +{ + // Don't hang- Wait 5/100 seconds- 1 Sec= 1000000 + FD_ZERO(&rfds); + FD_SET(0, &rfds); + tv.tv_sec = 0; + tv.tv_usec = hund * 10000; + select(1, &rfds, NULL, NULL, &tv); + return (FD_ISSET(0, &rfds)); +} + +//----- IO Routines -------------------------------------------- +static Byte readit(void) // read (maybe cursor) key from stdin +{ + Byte c; + int i, bufsiz, cnt, cmdindex; + struct esc_cmds { + Byte *seq; + Byte val; + }; + + static struct esc_cmds esccmds[] = { + {(Byte *) "OA", (Byte) VI_K_UP}, // cursor key Up + {(Byte *) "OB", (Byte) VI_K_DOWN}, // cursor key Down + {(Byte *) "OC", (Byte) VI_K_RIGHT}, // Cursor Key Right + {(Byte *) "OD", (Byte) VI_K_LEFT}, // cursor key Left + {(Byte *) "OH", (Byte) VI_K_HOME}, // Cursor Key Home + {(Byte *) "OF", (Byte) VI_K_END}, // Cursor Key End + {(Byte *) "", (Byte) VI_K_UP}, // cursor key Up + {(Byte *) "", (Byte) VI_K_DOWN}, // cursor key Down + {(Byte *) "", (Byte) VI_K_RIGHT}, // Cursor Key Right + {(Byte *) "", (Byte) VI_K_LEFT}, // cursor key Left + {(Byte *) "", (Byte) VI_K_HOME}, // Cursor Key Home + {(Byte *) "", (Byte) VI_K_END}, // Cursor Key End + {(Byte *) "[2~", (Byte) VI_K_INSERT}, // Cursor Key Insert + {(Byte *) "[5~", (Byte) VI_K_PAGEUP}, // Cursor Key Page Up + {(Byte *) "[6~", (Byte) VI_K_PAGEDOWN}, // Cursor Key Page Down + {(Byte *) "OP", (Byte) VI_K_FUN1}, // Function Key F1 + {(Byte *) "OQ", (Byte) VI_K_FUN2}, // Function Key F2 + {(Byte *) "OR", (Byte) VI_K_FUN3}, // Function Key F3 + {(Byte *) "OS", (Byte) VI_K_FUN4}, // Function Key F4 + {(Byte *) "[15~", (Byte) VI_K_FUN5}, // Function Key F5 + {(Byte *) "[17~", (Byte) VI_K_FUN6}, // Function Key F6 + {(Byte *) "[18~", (Byte) VI_K_FUN7}, // Function Key F7 + {(Byte *) "[19~", (Byte) VI_K_FUN8}, // Function Key F8 + {(Byte *) "[20~", (Byte) VI_K_FUN9}, // Function Key F9 + {(Byte *) "[21~", (Byte) VI_K_FUN10}, // Function Key F10 + {(Byte *) "[23~", (Byte) VI_K_FUN11}, // Function Key F11 + {(Byte *) "[24~", (Byte) VI_K_FUN12}, // Function Key F12 + {(Byte *) "[11~", (Byte) VI_K_FUN1}, // Function Key F1 + {(Byte *) "[12~", (Byte) VI_K_FUN2}, // Function Key F2 + {(Byte *) "[13~", (Byte) VI_K_FUN3}, // Function Key F3 + {(Byte *) "[14~", (Byte) VI_K_FUN4}, // Function Key F4 + }; + +#define ESCCMDS_COUNT (sizeof(esccmds)/sizeof(struct esc_cmds)) + + (void) alarm(0); // turn alarm OFF while we wait for input + // get input from User- are there already input chars in Q? + bufsiz = strlen((char *) readbuffer); + if (bufsiz <= 0) { + ri0: + // the Q is empty, wait for a typed char + bufsiz = read(0, readbuffer, BUFSIZ - 1); + if (bufsiz < 0) { + if (errno == EINTR) + goto ri0; // interrupted sys call + if (errno == EBADF) + editing = 0; + if (errno == EFAULT) + editing = 0; + if (errno == EINVAL) + editing = 0; + if (errno == EIO) + editing = 0; + errno = 0; + bufsiz = 0; + } + readbuffer[bufsiz] = '\0'; + } + // return char if it is not part of ESC sequence + if (readbuffer[0] != 27) + goto ri1; + + // This is an ESC char. Is this Esc sequence? + // Could be bare Esc key. See if there are any + // more chars to read after the ESC. This would + // be a Function or Cursor Key sequence. + FD_ZERO(&rfds); + FD_SET(0, &rfds); + tv.tv_sec = 0; + tv.tv_usec = 50000; // Wait 5/100 seconds- 1 Sec=1000000 + + // keep reading while there are input chars and room in buffer + while (select(1, &rfds, NULL, NULL, &tv) > 0 && bufsiz <= (BUFSIZ - 5)) { + // read the rest of the ESC string + i = read(0, (void *) (readbuffer + bufsiz), BUFSIZ - bufsiz); + if (i > 0) { + bufsiz += i; + readbuffer[bufsiz] = '\0'; // Terminate the string + } + } + // Maybe cursor or function key? + for (cmdindex = 0; cmdindex < ESCCMDS_COUNT; cmdindex++) { + cnt = strlen((char *) esccmds[cmdindex].seq); + i = strncmp((char *) esccmds[cmdindex].seq, (char *) readbuffer, cnt); + if (i == 0) { + // is a Cursor key- put derived value back into Q + readbuffer[0] = esccmds[cmdindex].val; + // squeeze out the ESC sequence + for (i = 1; i < cnt; i++) { + memmove(readbuffer + 1, readbuffer + 2, BUFSIZ - 2); + readbuffer[BUFSIZ - 1] = '\0'; + } + break; + } + } + ri1: + c = readbuffer[0]; + // remove one char from Q + memmove(readbuffer, readbuffer + 1, BUFSIZ - 1); + readbuffer[BUFSIZ - 1] = '\0'; + (void) alarm(3); // we are done waiting for input, turn alarm ON + return (c); +} + +//----- IO Routines -------------------------------------------- +static Byte get_one_char() +{ + static Byte c; + +#ifdef BB_FEATURE_VI_DOT_CMD + // ! adding2q && ioq == 0 read() + // ! adding2q && ioq != 0 *ioq + // adding2q *last_modifying_cmd= read() + if (!adding2q) { + // we are not adding to the q. + // but, we may be reading from a q + if (ioq == 0) { + // there is no current q, read from STDIN + c = readit(); // get the users input + } else { + // there is a queue to get chars from first + c = *ioq++; + if (c == '\0') { + // the end of the q, read from STDIN + free(ioq_start); + ioq_start = ioq = 0; + c = readit(); // get the users input + } + } + } else { + // adding STDIN chars to q + c = readit(); // get the users input + if (last_modifying_cmd != 0) { + int len = strlen((char *) last_modifying_cmd); + if (len + 1 >= BUFSIZ) { + /* FIXME last_modifying_cmd needs a shaving */ + fprintf(stderr,"last_modifying_cmd overrun"); + exit(EXIT_FAILURE); + } else { + // add new char to q + last_modifying_cmd[len] = c; + } + + } + } +#else /* BB_FEATURE_VI_DOT_CMD */ + c = readit(); // get the users input +#endif /* BB_FEATURE_VI_DOT_CMD */ + return (c); // return the char, where ever it came from +} + +static Byte *get_input_line(Byte * prompt) // get input line- use "status line" +{ + Byte buf[BUFSIZ]; + Byte c; + int i; + static Byte *obufp = NULL; + + /* FIXED strcpy((char *) buf, (char *) prompt); */ + if (strlcpy((char *) buf, (char *) prompt, sizeof((char *)buf)) > sizeof ((char *) buf)) err(1, "strlcpy overflow in function get_input_line"); + *status_buffer = '\0'; // clear the status buffer + place_cursor(rows - 1, 0, FALSE); // go to Status line, bottom of screen + clear_to_eol(); // clear the line + write(1, prompt, strlen((char *) prompt)); // write out the :, /, or ? prompt + + for (i = strlen((char *) buf); i < BUFSIZ;) { + c = get_one_char(); // read user input + if (c == '\n' || c == '\r' || c == 27) + break; // is this end of input + if (c == erase_char) { // user wants to erase prev char + i--; // backup to prev char + buf[i] = '\0'; // erase the char + buf[i + 1] = '\0'; // null terminate buffer + write(1, " ", 3); // erase char on screen + if (i <= 0) { // user backs up before b-o-l, exit + break; + } + } else { + buf[i] = c; // save char in buffer + buf[i + 1] = '\0'; // make sure buffer is null terminated + write(1, buf + i, 1); // echo the char back to user + i++; + } + } + refresh(FALSE); + if (obufp != NULL) + free(obufp); + obufp = (Byte *) strdup((char *) buf); + return (obufp); +} + +static int file_size(Byte * fn) // what is the byte size of "fn" +{ + struct stat st_buf; + int cnt, sr; + + if (fn == 0 || strlen(fn) <= 0) + return (-1); + cnt = -1; + sr = stat((char *) fn, &st_buf); // see if file exists + if (sr >= 0) { + cnt = (int) st_buf.st_size; + } + return (cnt); +} + +static int file_insert(Byte * fn, Byte * p, int size) +{ + int fd, cnt; + + cnt = -1; +#ifdef BB_FEATURE_VI_READONLY + readonly = FALSE; +#endif /* BB_FEATURE_VI_READONLY */ + if (fn == 0 || strlen((char*) fn) <= 0) { + psbs("No filename given"); + goto fi0; + } + if (size == 0) { + // OK- this is just a no-op + cnt = 0; + goto fi0; + } + if (size < 0) { + psbs("Trying to insert a negative number (%d) of characters", size); + goto fi0; + } + if (p < text || p > end) { + psbs("Trying to insert file outside of memory"); + goto fi0; + } + + // see if we can open the file +#ifdef BB_FEATURE_VI_READONLY + if (vi_readonly == TRUE) goto fi1; // do not try write-mode +#endif + fd = open((char *) fn, O_RDWR); // assume read & write + if (fd < 0) { + // could not open for writing- maybe file is read only +#ifdef BB_FEATURE_VI_READONLY + fi1: +#endif + fd = open((char *) fn, O_RDONLY); // try read-only + if (fd < 0) { + psbs("\"%s\" %s", fn, "could not open file"); + goto fi0; + } +#ifdef BB_FEATURE_VI_READONLY + // got the file- read-only + readonly = TRUE; +#endif /* BB_FEATURE_VI_READONLY */ + } + p = text_hole_make(p, size); + cnt = read(fd, p, size); + close(fd); + if (cnt < 0) { + cnt = -1; + p = text_hole_delete(p, p + size - 1); // un-do buffer insert + psbs("could not read file \"%s\"", fn); + } else if (cnt < size) { + // There was a partial read, shrink unused space text[] + p = text_hole_delete(p + cnt, p + (size - cnt) - 1); // un-do buffer insert + psbs("could not read all of file \"%s\"", fn); + } + if (cnt >= size) + file_modified = TRUE; + fi0: + return (cnt); +} + +static int file_write(Byte * fn, Byte * first, Byte * last) +{ + int fd, cnt, charcnt; + + if (fn == 0) { + psbs("No current filename"); + return (-1); + } + charcnt = 0; + // FIXIT- use the correct umask() + fd = open((char *) fn, (O_WRONLY | O_CREAT | O_TRUNC), 0664); + if (fd < 0) + return (-1); + cnt = last - first + 1; + charcnt = write(fd, first, cnt); + if (charcnt == cnt) { + // good write + //file_modified= FALSE; // the file has not been modified + } else { + charcnt = 0; + } + close(fd); + return (charcnt); +} + +//----- Terminal Drawing --------------------------------------- +// The terminal is made up of 'rows' line of 'columns' columns. +// classicly this would be 24 x 80. +// screen coordinates +// 0,0 ... 0,79 +// 1,0 ... 1,79 +// . ... . +// . ... . +// 22,0 ... 22,79 +// 23,0 ... 23,79 status line +// + +//----- Move the cursor to row x col (count from 0, not 1) ------- +static void place_cursor(int row, int col, int opti) +{ + char cm1[BUFSIZ]; + char *cm; + int l; +#ifdef BB_FEATURE_VI_OPTIMIZE_CURSOR + char cm2[BUFSIZ]; + Byte *screenp; + // char cm3[BUFSIZ]; + int Rrow= last_row; +#endif /* BB_FEATURE_VI_OPTIMIZE_CURSOR */ + + memset(cm1, '\0', BUFSIZ - 1); // clear the buffer + + if (row < 0) row = 0; + if (row >= rows) row = rows - 1; + if (col < 0) col = 0; + if (col >= columns) col = columns - 1; + + //----- 1. Try the standard terminal ESC sequence + sprintf((char *) cm1, CMrc, row + 1, col + 1); + cm= cm1; + if (opti == FALSE) goto pc0; + +#ifdef BB_FEATURE_VI_OPTIMIZE_CURSOR + //----- find the minimum # of chars to move cursor ------------- + //----- 2. Try moving with discreet chars (Newline, [back]space, ...) + memset(cm2, '\0', BUFSIZ - 1); // clear the buffer + /* FIXME - possible replace with strlc* ? */ + + // move to the correct row + while (row < Rrow) { + // the cursor has to move up + strlcat(cm2, CMup, BUFSIZ); /* FIXED strlcat BUFSIZ */ + Rrow--; + } + while (row > Rrow) { + // the cursor has to move down + strlcat(cm2, CMdown, BUFSIZ); /* FIXED strlcat BUFSIZE */ + Rrow++; + } + + // now move to the correct column + strcat(cm2, "\r"); // start at col 0 + // just send out orignal source char to get to correct place + screenp = &screen[row * columns]; // start of screen line + strncat(cm2, screenp, col); + + //----- 3. Try some other way of moving cursor + //--------------------------------------------- + + // pick the shortest cursor motion to send out + cm= cm1; + if (strlen(cm2) < strlen(cm)) { + cm= cm2; + } /* else if (strlen(cm3) < strlen(cm)) { + cm= cm3; + } */ +#endif /* BB_FEATURE_VI_OPTIMIZE_CURSOR */ + pc0: + l= strlen(cm); + if (l) write(1, cm, l); // move the cursor +} + +//----- Erase from cursor to end of line ----------------------- +static void clear_to_eol() +{ + write(1, Ceol, strlen(Ceol)); // Erase from cursor to end of line +} + +//----- Erase from cursor to end of screen ----------------------- +static void clear_to_eos() +{ + write(1, Ceos, strlen(Ceos)); // Erase from cursor to end of screen +} + +//----- Start standout mode ------------------------------------ +static void standout_start() // send "start reverse video" sequence +{ + write(1, SOs, strlen(SOs)); // Start reverse video mode +} + +//----- End standout mode -------------------------------------- +static void standout_end() // send "end reverse video" sequence +{ + write(1, SOn, strlen(SOn)); // End reverse video mode +} + +//----- Flash the screen -------------------------------------- +static void flash(int h) +{ + standout_start(); // send "start reverse video" sequence + redraw(TRUE); + (void) mysleep(h); + standout_end(); // send "end reverse video" sequence + redraw(TRUE); +} + +static void beep() +{ + write(1, bell, strlen(bell)); // send out a bell character +} + +static void indicate_error(char c) +{ +#ifdef BB_FEATURE_VI_CRASHME + if (crashme > 0) + return; // generate a random command +#endif /* BB_FEATURE_VI_CRASHME */ + if (err_method == 0) { + beep(); + } else { + flash(10); + } +} + +//----- Screen[] Routines -------------------------------------- +//----- Erase the Screen[] memory ------------------------------ +static void screen_erase() +{ + memset(screen, ' ', screensize); // clear new screen +} + +//----- Draw the status line at bottom of the screen ------------- +static void show_status_line(void) +{ + static int last_cksum; + int l, cnt, cksum; + + cnt = strlen((char *) status_buffer); + for (cksum= l= 0; l < cnt; l++) { cksum += (int)(status_buffer[l]); } + // don't write the status line unless it changes + if (cnt > 0 && last_cksum != cksum) { + last_cksum= cksum; // remember if we have seen this line + place_cursor(rows - 1, 0, FALSE); // put cursor on status line + write(1, status_buffer, cnt); + clear_to_eol(); + place_cursor(crow, ccol, FALSE); // put cursor back in correct place + } +} + +//----- format the status buffer, the bottom line of screen ------ +// print status buffer, with STANDOUT mode +static void psbs(char *format, ...) +{ + va_list args; + + va_start(args, format); + /* FIXED strcpy((char *) status_buffer, SOs); */ + strlcpy((char *) status_buffer, SOs, BUFSIZ_STATBUF); // Terminal standout mode on + vsprintf((char *) status_buffer + strlen((char *) status_buffer), format, + args); + /* FIXED strcat((char *) status_buffer, SOn); */ + strlcat((char *) status_buffer, SOn, BUFSIZ_STATBUF); // Terminal standout mode off + va_end(args); + + return; +} + +// print status buffer +static void psb(char *format, ...) +{ + va_list args; + + va_start(args, format); + vsprintf((char *) status_buffer, format, args); + va_end(args); + return; +} + +static void ni(Byte * s) // display messages +{ + Byte buf[BUFSIZ]; + + print_literal(buf, s); + psbs("\'%s\' is not implemented", buf); +} + +static void edit_status(void) // show file status on status line +{ + int cur, tot, percent; + + cur = count_lines(text, dot); + tot = count_lines(text, end - 1); + // current line percent + // ------------- ~~ ---------- + // total lines 100 + if (tot > 0) { + percent = (100 * cur) / tot; + } else { + cur = tot = 0; + percent = 100; + } + psb("\"%s\"" +#ifdef BB_FEATURE_VI_READONLY + "%s" +#endif /* BB_FEATURE_VI_READONLY */ + "%s line %d of %d --%d%%--", + (cfn != 0 ? (char *) cfn : "No file"), +#ifdef BB_FEATURE_VI_READONLY + ((vi_readonly == TRUE || readonly == TRUE) ? " [Read only]" : ""), +#endif /* BB_FEATURE_VI_READONLY */ + (file_modified == TRUE ? " [modified]" : ""), + cur, tot, percent); +} + +//----- Force refresh of all Lines ----------------------------- +static void redraw(int full_screen) +{ + place_cursor(0, 0, FALSE); // put cursor in correct place + clear_to_eos(); // tel terminal to erase display + screen_erase(); // erase the internal screen buffer + refresh(full_screen); // this will redraw the entire display +} + +//----- Format a text[] line into a buffer --------------------- +static void format_line(Byte *dest, Byte *src, int li) +{ + int co; + Byte c; + + for (co= 0; co < MAX_SCR_COLS; co++) { + c= ' '; // assume blank + if (li > 0 && co == 0) { + c = '~'; // not first line, assume Tilde + } + // are there chars in text[] and have we gone past the end + if (text < end && src < end) { + c = *src++; + } + if (c == '\n') + break; + if (c < ' ' || c > '~') { + if (c == '\t') { + c = ' '; + // co % 8 != 7 + for (; (co % tabstop) != (tabstop - 1); co++) { + dest[co] = c; + } + } else { + dest[co++] = '^'; + c |= '@'; // make it visible + c &= 0x7f; // get rid of hi bit + } + } + // the co++ is done here so that the column will + // not be overwritten when we blank-out the rest of line + dest[co] = c; + if (src >= end) + break; + } +} + +//----- Refresh the changed screen lines ----------------------- +// Copy the source line from text[] into the buffer and note +// if the current screenline is different from the new buffer. +// If they differ then that line needs redrawing on the terminal. +// +static void refresh(int full_screen) +{ + static int old_offset; + int li, changed; + Byte buf[MAX_SCR_COLS]; + Byte *tp, *sp; // pointer into text[] and screen[] +#ifdef BB_FEATURE_VI_OPTIMIZE_CURSOR + int last_li= -2; // last line that changed- for optimizing cursor movement +#endif /* BB_FEATURE_VI_OPTIMIZE_CURSOR */ + +#ifdef BB_FEATURE_VI_WIN_RESIZE + window_size_get(0); +#endif /* BB_FEATURE_VI_WIN_RESIZE */ + sync_cursor(dot, &crow, &ccol); // where cursor will be (on "dot") + tp = screenbegin; // index into text[] of top line + + // compare text[] to screen[] and mark screen[] lines that need updating + for (li = 0; li < rows - 1; li++) { + int cs, ce; // column start & end + memset(buf, ' ', MAX_SCR_COLS); // blank-out the buffer + buf[MAX_SCR_COLS-1] = 0; // NULL terminate the buffer + // format current text line into buf + format_line(buf, tp, li); + + // skip to the end of the current text[] line + while (tp < end && *tp++ != '\n') /*no-op*/ ; + + // see if there are any changes between vitual screen and buf + changed = FALSE; // assume no change + cs= 0; + ce= columns-1; + sp = &screen[li * columns]; // start of screen line + if (full_screen == TRUE) { + // force re-draw of every single column from 0 - columns-1 + goto re0; + } + // compare newly formatted buffer with virtual screen + // look forward for first difference between buf and screen + for ( ; cs <= ce; cs++) { + if (buf[cs + offset] != sp[cs]) { + changed = TRUE; // mark for redraw + break; + } + } + + // look backward for last difference between buf and screen + for ( ; ce >= cs; ce--) { + if (buf[ce + offset] != sp[ce]) { + changed = TRUE; // mark for redraw + break; + } + } + // now, cs is index of first diff, and ce is index of last diff + + // if horz offset has changed, force a redraw + if (offset != old_offset) { + re0: + changed = TRUE; + } + + // make a sanity check of columns indexes + if (cs < 0) cs= 0; + if (ce > columns-1) ce= columns-1; + if (cs > ce) { cs= 0; ce= columns-1; } + // is there a change between vitual screen and buf + if (changed == TRUE) { + // copy changed part of buffer to virtual screen + memmove(sp+cs, buf+(cs+offset), ce-cs+1); + + // move cursor to column of first change + if (offset != old_offset) { + // opti_cur_move is still too stupid + // to handle offsets correctly + place_cursor(li, cs, FALSE); + } else { +#ifdef BB_FEATURE_VI_OPTIMIZE_CURSOR + // if this just the next line + // try to optimize cursor movement + // otherwise, use standard ESC sequence + place_cursor(li, cs, li == (last_li+1) ? TRUE : FALSE); + last_li= li; +#else /* BB_FEATURE_VI_OPTIMIZE_CURSOR */ + place_cursor(li, cs, FALSE); // use standard ESC sequence +#endif /* BB_FEATURE_VI_OPTIMIZE_CURSOR */ + } + + // write line out to terminal + write(1, sp+cs, ce-cs+1); +#ifdef BB_FEATURE_VI_OPTIMIZE_CURSOR + last_row = li; +#endif /* BB_FEATURE_VI_OPTIMIZE_CURSOR */ + } + } + +#ifdef BB_FEATURE_VI_OPTIMIZE_CURSOR + place_cursor(crow, ccol, (crow == last_row) ? TRUE : FALSE); + last_row = crow; +#else + place_cursor(crow, ccol, FALSE); +#endif /* BB_FEATURE_VI_OPTIMIZE_CURSOR */ + + if (offset != old_offset) + old_offset = offset; +} diff --git a/src/cmd/vmstat.c b/src/cmd/vmstat.c new file mode 100644 index 0000000..1f88c9d --- /dev/null +++ b/src/cmd/vmstat.c @@ -0,0 +1,444 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +struct nlist nl[] = { +#define X_CPTIME 0 + { "_cp_time" }, +#define X_RATE 1 + { "_rate" }, +#define X_TOTAL 2 + { "_total" }, +#define X_FORKSTAT 3 + { "_forkstat" }, +#define X_SUM 4 + { "_sum" }, +#define X_BOOTTIME 5 + { "_boottime" }, +#define X_DKXFER 6 + { "_dk_xfer" }, +#define X_HZ 7 + { "_hz" }, +#define X_NCHSTATS 8 + { "_nchstats" }, +#define X_DK_NDRIVE 9 + { "_dk_ndrive" }, +#define X_DK_NAME 10 + { "_dk_name" }, +#define X_DK_UNIT 11 + { "_dk_unit" }, +#define X_FREEMEM 12 + { "_freemem" }, + { "" }, +}; + +char **dk_name; +int *dk_unit; +size_t pfree; +int pflag; +char **dr_name; +int *dr_select; +int dk_ndrive; +int ndrives = 0; +char *defdrives[] = { "sd0", 0 }; +double stat1(); +int hz; + +struct { + int busy; + long time[CPUSTATES]; + long *xfer; + + struct vmrate Rate; + struct vmtotal Total; + struct vmsum Sum; + + struct forkstat Forkstat; + unsigned rectime; + unsigned pgintime; +} s, s1, z; +#define rate s.Rate +#define total s.Total +#define sum s.Sum +#define forkstat s.Forkstat + +struct vmsum osum; +double etime; +int mf; +time_t now, boottime; +int lines = 1; + +void printhdr(sig) + int sig; +{ + register int i, j; + + if (pflag) + printf("-procs- -----memory----- -swap- "); + else + printf("-procs- ---memory-- "); + + printf("-----disks----- "); + + if (pflag) { + printf("-----faults----- ------cpu------\n"); + printf(" r b w avm tx fre i o "); + } else { + printf("---faults--- ----cpu----\n"); + printf(" r b w avm fre "); + } + + for (i = 0; i < dk_ndrive; i++) + if (dr_select[i]) + printf("%c%c%c ", + dr_name[i][0], dr_name[i][1], dr_name[i][2]); + printf(" in sy"); + if (pflag) + printf(" tr"); + printf(" cs us"); + if (pflag) + printf(" ni"); + printf(" sy id\n"); + lines = 19; +} + +main(argc, argv) + int argc; + char **argv; +{ + extern char *ctime(); + register i; + int iter, iflag = 0; + long nintv, t; + char *arg, **cp, buf[BUFSIZ]; + + knlist(nl); + if(nl[0].n_value == 0) { + fprintf(stderr, "no /vmunix namelist\n"); + exit(1); + } + mf = open("/dev/kmem", 0); + if(mf < 0) { + fprintf(stderr, "cannot open /dev/kmem\n"); + exit(1); + } + iter = 0; + argc--, argv++; + while (argc>0 && argv[0][0]=='-') { + char *cp = *argv++; + argc--; + while (*++cp) switch (*cp) { + + case 't': + dotimes(); + exit(0); + + case 'z': + close(mf); + mf = open("/dev/kmem", 2); + lseek(mf, (long)nl[X_SUM].n_value, L_SET); + write(mf, &z.Sum, sizeof z.Sum); + exit(0); + + case 'f': + doforkst(); + exit(0); + + case 's': + dosum(); + exit(0); + + case 'i': + iflag++; + break; + + case 'p': + pflag++; + break; + + default: + fprintf(stderr, + "usage: vmstat [ -fsiptz ] [ interval ] [ count]\n"); + exit(1); + } + } + lseek(mf, (long)nl[X_BOOTTIME].n_value, L_SET); + read(mf, &boottime, sizeof boottime); + lseek(mf, (long)nl[X_HZ].n_value, L_SET); + read(mf, &hz, sizeof hz); + if (nl[X_DK_NDRIVE].n_value == 0) { + fprintf(stderr, "dk_ndrive undefined in system\n"); + exit(1); + } + lseek(mf, (long)nl[X_DK_NDRIVE].n_value, L_SET); + read(mf, &dk_ndrive, sizeof (dk_ndrive)); + if (dk_ndrive <= 0) { + fprintf(stderr, "dk_ndrive %d\n", dk_ndrive); + exit(1); + } + dr_select = (int *)calloc(dk_ndrive, sizeof (int)); + dr_name = (char **)calloc(dk_ndrive, sizeof (char *)); + dk_name = (char **)calloc(dk_ndrive, sizeof (char *)); + dk_unit = (int *)calloc(dk_ndrive, sizeof (int)); +#define allocate(e, t) \ + s./**/e = (t *)calloc(dk_ndrive, sizeof (t)); \ + s1./**/e = (t *)calloc(dk_ndrive, sizeof (t)); + allocate(xfer, long); + for (arg = buf, i = 0; i < dk_ndrive; i++) { + dr_name[i] = arg; + sprintf(dr_name[i], "dk%d", i); + arg += strlen(dr_name[i]) + 1; + } + read_names(); + time(&now); + nintv = now - boottime; + if (nintv <= 0 || nintv > 60L*60L*24L*365L*10L) { + fprintf(stderr, + "Time makes no sense... namelist must be wrong.\n"); + exit(1); + } + if (iflag) { + dointr(nintv); + exit(0); + } + /* + * 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. + */ + ndrives = 0; + while (argc > 0 && !isdigit(argv[0][0])) { + for (i = 0; i < dk_ndrive; i++) { + if (strcmp(dr_name[i], argv[0])) + continue; + dr_select[i] = 1; + ndrives++; + } + argc--, argv++; + } + 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++; + } + if (argc > 1) + iter = atoi(argv[1]); + signal(SIGCONT, printhdr); +loop: + if (--lines == 0) + printhdr(); + lseek(mf, (long)nl[X_CPTIME].n_value, L_SET); + read(mf, s.time, sizeof s.time); + lseek(mf, (long)nl[X_DKXFER].n_value, L_SET); + read(mf, s.xfer, dk_ndrive * sizeof (long)); + + if (nintv != 1) { + lseek(mf, (long)nl[X_SUM].n_value, L_SET); + read(mf, &sum, sizeof(sum)); + rate.v_swtch = sum.v_swtch; + rate.v_trap = sum.v_trap; + rate.v_syscall = sum.v_syscall; + rate.v_intr = sum.v_intr; + rate.v_swpin = sum.v_swpin; + rate.v_swpout = sum.v_swpout; + } else { + lseek(mf, (long)nl[X_RATE].n_value, L_SET); + read(mf, &rate, sizeof rate); + lseek(mf, (long)nl[X_SUM].n_value, L_SET); + read(mf, &sum, sizeof sum); + } + lseek(mf, (long)nl[X_FREEMEM].n_value, L_SET); + read(mf, &pfree, sizeof(pfree)); + + lseek(mf, (long)nl[X_TOTAL].n_value, L_SET); + read(mf, &total, sizeof total); + osum = sum; + lseek(mf, (long)nl[X_SUM].n_value, L_SET); + read(mf, &sum, sizeof sum); + etime = 0; + for (i=0; i < dk_ndrive; i++) { + t = s.xfer[i]; + s.xfer[i] -= s1.xfer[i]; + s1.xfer[i] = t; + } + for (i=0; i < CPUSTATES; i++) { + t = s.time[i]; + s.time[i] -= s1.time[i]; + s1.time[i] = t; + etime += s.time[i]; + } + if(etime == 0.) + etime = 1.; + + printf("%2d%2d%2d", total.t_rq, total.t_dw, total.t_sw); + /* + * We don't use total.t_free because it slops around too much + * within this kernel + */ + printf("%7d", total.t_avm); + if (pflag) + printf("%4d", + total.t_avm ? (total.t_avmtxt * 100) / total.t_avm : 0); + printf("%6d", pfree); + + if (pflag) { + printf("%4d%3d ", rate.v_swpin / nintv, rate.v_swpout / nintv); + } + + etime /= (float)hz; + for (i = 0; i < dk_ndrive; i++) { + if (dr_select[i]) + stats(i); + } + printf("%5d%4d", rate.v_intr/nintv, rate.v_syscall/nintv); + if (pflag) + printf("%4d", rate.v_trap / nintv); + printf("%4d", rate.v_swtch / nintv); + + for(i=0; i 0) { + sleep(atoi(argv[0])); + goto loop; + } +} + +dotimes() +{ + printf("page in/out/reclamation is not applicable to 2.11BSD\n"); +} + +dosum() +{ + struct nchstats nchstats; + long nchtotal; + + lseek(mf, (long)nl[X_SUM].n_value, L_SET); + read(mf, &sum, sizeof sum); + printf("%9d swap ins\n", sum.v_swpin); + printf("%9d swap outs\n", sum.v_swpout); + printf("%9d kbytes swapped in\n", sum.v_kbin); + printf("%9d kbytes swapped out\n", sum.v_kbout); + printf("%9d cpu context switches\n", sum.v_swtch); + printf("%9d device interrupts\n", sum.v_intr); + printf("%9d software interrupts\n", sum.v_soft); + printf("%9d traps\n", sum.v_trap); + printf("%9d system calls\n", sum.v_syscall); +#define nz(x) ((x) ? (x) : 1) + lseek(mf, (long)nl[X_NCHSTATS].n_value, 0); + read(mf, &nchstats, sizeof nchstats); + nchtotal = nchstats.ncs_goodhits + nchstats.ncs_badhits + + nchstats.ncs_falsehits + nchstats.ncs_miss + nchstats.ncs_long; + printf("%9d total name lookups", nchtotal); + printf(" (cache hits %d%% system %d%% per-process)\n", + nchstats.ncs_goodhits * 100 / nz(nchtotal), + nchstats.ncs_pass2 * 100 / nz(nchtotal)); + printf("%9s badhits %d, falsehits %d, toolong %d\n", "", + nchstats.ncs_badhits, nchstats.ncs_falsehits, nchstats.ncs_long); +} + +doforkst() +{ + lseek(mf, (long)nl[X_FORKSTAT].n_value, L_SET); + read(mf, &forkstat, sizeof forkstat); + if (forkstat.cntfork != 0) + printf("%d forks, %d kbytes, average=%.2f\n", + forkstat.cntfork, forkstat.sizfork, + (float) forkstat.sizfork / forkstat.cntfork); + if (forkstat.cntvfork != 0) + printf("%d vforks, %d kbytes, average=%.2f\n", + forkstat.cntvfork, forkstat.sizvfork, + (float) forkstat.sizvfork / forkstat.cntvfork); +} + +stats(dn) +{ + if (dn >= dk_ndrive) { + printf(" 0"); + return; + } + printf("%4.0f", s.xfer[dn]/etime); +} + +double +stat1(row) +{ + double t; + register i; + + t = 0; + for(i=0; i +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define NMAX sizeof(utmp.ut_name) +#define LMAX sizeof(utmp.ut_line) +#define ARGWIDTH 33 /* # chars left on 80 col crt for args */ +#define ARGLIST 1024 /* amount of stack to examine for argument list */ + +struct smproc { + long w_addr; /* address in file for args */ + short w_pid; /* proc.p_pid */ + int w_igintr; /* INTR+3*QUIT, 0=die, 1=ign, 2=catch */ + time_t w_time; /* CPU time used by this process */ + time_t w_ctime; /* CPU time used by children */ + dev_t w_tty; /* tty device of process */ + char w_comm[15]; /* user.u_comm, null terminated */ + char w_args[ARGWIDTH+1]; /* args if interesting process */ +} *pr; + +FILE *ut; +int swmem; +int swap; /* /dev/mem, mem, and swap */ +int file; +dev_t tty; +char doing[520]; /* process attached to terminal */ +time_t proctime; /* cpu time of process in doing */ +unsigned avenrun[3]; +extern int errno, optind; + +#define DIV60(t) ((t+30)/60) /* x/60 rounded */ +#define TTYEQ (tty == pr[i].w_tty) +#define IGINT (1+3*1) /* ignoring both SIGINT & SIGQUIT */ + +char *getargs(); +char *getptr(); + +char *program; +int header = 1; /* true if -h flag: don't print heading */ +int lflag = 1; /* true if -l flag: long style output */ +time_t idle; /* number of minutes user is idle */ +int nusers; /* number of users logged in now */ +char * sel_user; /* login of particular user selected */ +int wcmd = 1; /* running as the w command */ +time_t jobtime; /* total cpu time visible */ +time_t now; /* the current time of day */ +struct tm *nowt; /* current time as time struct */ +struct timeval boottime; /* time since last reboot */ +time_t uptime; /* elapsed time since */ +int np; /* number of processes currently active */ +struct utmp utmp; +struct user up; + +struct addrmap { + long b1, e1; long f1; + long b2, e2; long f2; +}; +struct addrmap datmap; + +main(argc, argv) + char **argv; +{ + int days, hrs, mins; + register int i; + char *cp; + register int curpid, empty; + size_t size; + int mib[2]; + + program = argv[0]; + if ((cp = strrchr(program, '/')) || *(cp = program) == '-') + cp++; + if (*cp == 'u') + wcmd = 0; + + while ((i = getopt(argc, argv, "hlswu")) != EOF) + { + switch (i) + { + case 'h': + header = 0; + break; + case 'l': + lflag++; + break; + case 's': + lflag = 0; + break; + case 'u': + wcmd = 0; + break; + case 'w': + wcmd = 1; + break; + default: + fprintf(stderr, "Usage: %s [-hlswu] [user]\n", + program); + exit(1); + } + } + argc -= optind; + argv += optind; + if (*argv) + sel_user = *argv; + + if (wcmd) + readpr(); + + ut = fopen(_PATH_UTMP, "r"); + if (header) { + /* Print time of day */ + time(&now); + nowt = localtime(&now); + prtat(nowt); + + 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; + days = uptime / (60L*60L*24L); + uptime %= (60L*60L*24L); + hrs = uptime / (60L*60L); + uptime %= (60L*60L); + mins = DIV60(uptime); + + printf(" up"); + if (days > 0) + printf(" %d day%s,", days, days>1?"s":""); + if (hrs > 0 && mins > 0) { + printf(" %2d:%02d,", hrs, mins); + } else { + if (hrs > 0) + printf(" %d hr%s,", hrs, hrs>1?"s":""); + if (mins > 0) + printf(" %d min%s,", mins, mins>1?"s":""); + } + } + + /* Print number of users logged in to system */ + while (fread(&utmp, sizeof(utmp), 1, ut)) { + if (utmp.ut_name[0] != '\0') + nusers++; + } + rewind(ut); + printf(" %d user%c", nusers, nusers > 1 ? 's' : '\0'); + + if (getloadavg(avenrun, sizeof(avenrun) / sizeof(avenrun[0])) == -1) + printf(", no load average information available\n"); + else { + printf(", load averages:"); + for (i = 0; i < (sizeof(avenrun)/sizeof(avenrun[0])); i++) { + if (i > 0) + printf(","); + printf(" %u.%02u", avenrun[i] / 100, + avenrun[i] % 100); + } + } + printf("\n"); + if (wcmd == 0) + exit(0); + + /* Headers for rest of output */ + if (lflag) + printf("%-*.*s %-*.*s login@ idle JCPU PCPU what\n", + NMAX, NMAX, "User", LMAX, LMAX, "tty"); + else + printf("%-*.*s tty idle what\n", + NMAX, NMAX, "User"); + fflush(stdout); + } + + + for (;;) { /* for each entry in utmp */ + if (fread(&utmp, sizeof(utmp), 1, ut) == NULL) { + fclose(ut); + exit(0); + } + if (utmp.ut_name[0] == '\0') + continue; /* that tty is free */ + if (sel_user && strncmp(utmp.ut_name, sel_user, NMAX) != 0) + continue; /* we wanted only somebody else */ + + gettty(); + jobtime = 0; + proctime = 0; + strcpy(doing, "-"); /* default act: normally never prints */ + empty = 1; + curpid = -1; + idle = findidle(); + for (i=0; icurpid && (pr[i].w_igintr!=IGINT || empty)){ + curpid = pr[i].w_pid; + strcpy(doing, lflag ? pr[i].w_args : pr[i].w_comm); + if (doing[0]==0 || doing[0]=='-' && doing[1]<=' ' || doing[0] == '?') { + strcat(doing, " ("); + strcat(doing, pr[i].w_comm); + strcat(doing, ")"); + } + } + } + putline(); + } +} + +/* figure out the major/minor device # pair for this tty */ +gettty() +{ + char ttybuf[20]; + struct stat statbuf; + + ttybuf[0] = 0; + strcpy(ttybuf, "/dev/"); + strcat(ttybuf, utmp.ut_line); + stat(ttybuf, &statbuf); + tty = statbuf.st_rdev; +} + +/* + * putline: print out the accumulated line of info about one user. + */ +putline() +{ + + /* print login name of the user */ + printf("%-*.*s ", NMAX, NMAX, utmp.ut_name); + + /* print tty user is on */ + if (lflag) + /* long form: all (up to) LMAX chars */ + printf("%-*.*s", LMAX, LMAX, utmp.ut_line); + else { + /* short form: 2 chars, skipping 'tty' if there */ + if (utmp.ut_line[0]=='t' && utmp.ut_line[1]=='t' && utmp.ut_line[2]=='y') + printf("%-2.2s", &utmp.ut_line[3]); + else + printf("%-2.2s", utmp.ut_line); + } + + if (lflag) + /* print when the user logged in */ + prtat(localtime(&utmp.ut_time)); + + /* print idle time */ + prttime(idle," "); + + if (lflag) { + /* print CPU time for all processes & children */ + prttime(DIV60(jobtime)," "); + /* print cpu time for interesting process */ + prttime(DIV60(proctime)," "); + } + + /* what user is doing, either command tail or args */ + printf(" %-.32s\n",doing); + fflush(stdout); +} + +/* find & return number of minutes current tty has been idle */ +findidle() +{ + struct stat stbuf; + long lastaction, diff; + char ttyname[20]; + + strcpy(ttyname, "/dev/"); + strncat(ttyname, utmp.ut_line, LMAX); + stat(ttyname, &stbuf); + time(&now); + lastaction = stbuf.st_atime; + diff = now - lastaction; + diff = DIV60(diff); + if (diff < 0) diff = 0; + return(diff); +} + +/* + * prttime prints a time in hours and minutes. + * The character string tail is printed at the end, obvious + * strings to pass are "", " ", or "am". + */ +prttime(tim, tail) + time_t tim; + char *tail; +{ + register int didhrs = 0; + + if (tim >= 60) { + printf("%3ld:", tim/60); + didhrs++; + } else { + printf(" "); + } + tim %= 60; + if (tim > 0 || didhrs) { + printf(didhrs&&tim<10 ? "%02ld" : "%2ld", tim); + } else { + printf(" "); + } + printf("%s", tail); +} + +/* prtat prints a 12 hour time given a pointer to a time of day */ +prtat(p) + register struct tm *p; +{ + register int pm; + time_t t; + + t = p -> tm_hour; + pm = (t > 11); + if (t > 11) + t -= 12; + if (t == 0) + t = 12; + prttime(t*60 + p->tm_min, pm ? "pm" : "am"); +} + +/* + * readpr finds and reads in the array pr, containing the interesting + * parts of the proc and user tables for each live process. + */ +readpr() +{ + struct kinfo_proc *kp; +register struct proc *p; +register struct smproc *smp; + struct kinfo_proc *kpt; + int pn, nproc; + long addr, daddr, saddr; + long txtsiz, datsiz, stksiz; + int septxt; + int mib[4], st; + size_t size; + + if((swmem = open("/dev/mem", 0)) < 0) { + perror("/dev/mem"); + exit(1); + } + if ((swap = open("/dev/swap", 0)) < 0) { + perror("/dev/swap"); + exit(1); + } + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_ALL; + size = 0; + st = sysctl(mib, 4, NULL, &size, NULL, 0); + if (st == -1) { + fprintf(stderr, "sysctl: %s \n", strerror(errno)); + exit(1); + } + if (size % sizeof (struct kinfo_proc) != 0) { + fprintf(stderr, "proc size mismatch (%d total, %d chunks)\n", + size, sizeof(struct kinfo_proc)); + exit(1); + } + kpt = (struct kinfo_proc *)malloc(size); + if (kpt == (struct kinfo_proc *)NULL) { + fprintf(stderr, "Not %d bytes of memory for proc table\n", + size); + exit(1); + } + if (sysctl(mib, 4, kpt, &size, NULL, 0) == -1) { + fprintf(stderr, "sysctl fetch of proc table failed: %s\n", + strerror(errno)); + exit(1); + } + + nproc = size / sizeof (struct kinfo_proc); + pr = (struct smproc *) malloc(nproc * sizeof(struct smproc)); + if (pr == (struct smproc *)NULL) { + fprintf(stderr,"Not enough memory for proc table\n"); + exit(1); + } + /* + * Now step thru the kinfo_proc structures and save interesting + * process's info in the 'smproc' structure. + */ + smp = pr; + kp = kpt; + for (pn = 0; pn < nproc; kp++, pn++) { + p = &kp->kp_proc; + /* decide if it's an interesting process */ + if (p->p_stat==0 || p->p_stat==SZOMB || p->p_pgrp==0) + continue; + /* find & read in the user structure */ + if (p->p_flag & SLOAD) { + addr = (long)p->p_addr; + daddr = (long)p->p_daddr; + saddr = (long)p->p_saddr; + file = swmem; + } else { + addr = (off_t)p->p_addr * DEV_BSIZE; + daddr = (off_t)p->p_daddr * DEV_BSIZE; + saddr = (off_t)p->p_saddr * DEV_BSIZE; + file = swap; + } + lseek(file, addr, 0); + if (read(file, (char *)&up, sizeof(up)) != sizeof(up)) + continue; + if (up.u_ttyp == NULL) + continue; + + /* set up address maps for user pcs */ + txtsiz = up.u_tsize; + datsiz = up.u_dsize; + stksiz = up.u_ssize; + datmap.b1 = txtsiz; + datmap.e1 = datmap.b1+datsiz; + datmap.f1 = daddr; + datmap.b2 = stackbas(stksiz); + datmap.e2 = stacktop(stksiz); + datmap.f2 = saddr; + + /* save the interesting parts */ + smp->w_addr = saddr + (long)p->p_ssize - ARGLIST; + smp->w_pid = p->p_pid; + smp->w_igintr = ((up.u_signal[SIGINT] == SIG_IGN) + + 2 * ((unsigned)up.u_signal[SIGINT] > (unsigned)SIG_IGN) + + 3 * (up.u_signal[SIGQUIT] == SIG_IGN)) + + 6 * ((unsigned)up.u_signal[SIGQUIT] > (unsigned)SIG_IGN); + smp->w_time = up.u_ru.ru_utime + up.u_ru.ru_stime; + smp->w_ctime = up.u_cru.ru_utime + up.u_cru.ru_stime; + smp->w_tty = up.u_ttyd; + up.u_comm[14] = 0; /* Bug: This bombs next field. */ + strcpy(smp->w_comm, up.u_comm); + /* + * Get args if there's a chance we'll print it. + * Cant just save pointer: getargs returns static place. + * Cant use strncpy: that crock blank pads. + */ + smp->w_args[0] = 0; + strncat(smp->w_args,getargs(smp),ARGWIDTH); + if (smp->w_args[0]==0 || smp->w_args[0]=='-' && smp->w_args[1]<=' ' || smp->w_args[0] == '?') { + strcat(smp->w_args, " ("); + strcat(smp->w_args, smp->w_comm); + strcat(smp->w_args, ")"); + } + smp++; + } + np = smp - pr; + free(kpt); +} + +/* + * getargs: given a pointer to a proc structure, this looks at the swap area + * and tries to reconstruct the arguments. This is straight out of ps. + */ +char * +getargs(p) + struct smproc *p; +{ + int c, nbad; + static char abuf[ARGLIST]; + register int *ip; + register char *cp, *cp1; + char **ap; + long addr; + + addr = p->w_addr; + + /* look for sh special */ + lseek(file, addr+ARGLIST-sizeof(char **), 0); + if (read(file, (char *)&ap, sizeof(char *)) != sizeof(char *)) + return(NULL); + if (ap) { + char *b = (char *) abuf; + char *bp = b; + while((cp=getptr(ap++)) && cp && (bp'~') { + if (nbad++>3) + break; + continue; + } + *bp++ = c; + } + *bp++ = ' '; + } + *bp++ = 0; + return(b); + } + + lseek(file, addr, 0); + if (read(file, abuf, sizeof(abuf)) != sizeof(abuf)) + return((char *)1); + for (ip = (int *) &abuf[ARGLIST]-2; ip > (int *) abuf;) { + /* Look from top for -1 or 0 as terminator flag. */ + if (*--ip == -1 || *ip == 0) { + cp = (char *)(ip+1); + if (*cp==0) + cp++; + nbad = 0; /* up to 5 funny chars as ?'s */ + for (cp1 = cp; cp1 < (char *)&abuf[ARGLIST]; cp1++) { + c = *cp1&0177; + if (c==0) /* nulls between args => spaces */ + *cp1 = ' '; + else if (c < ' ' || c > 0176) { + if (++nbad >= 5) { + *cp1++ = ' '; + break; + } + *cp1 = '?'; + } else if (c=='=') { /* Oops - found an + * environment var, back + * over & erase it. */ + *cp1 = 0; + while (cp1>cp && *--cp1!=' ') + *cp1 = 0; + break; + } + } + while (*--cp1==' ') /* strip trailing spaces */ + *cp1 = 0; + return(cp); + } + } + return (p->w_comm); +} + +char * +getptr(adr) +char **adr; +{ + char *ptr; + register char *p, *pa; + register i; + + ptr = 0; + pa = (char *)adr; + p = (char *)&ptr; + for (i=0; ib1, amap->e1)) { + if(within(adr, amap->b2, amap->e2)) { + saddr = (unsigned)adr + amap->f2 - amap->b2; + } else + return(0); + } else + saddr = (unsigned)adr + amap->f1 - amap->b1; + if(lseek(file, saddr, 0)==-1 + || read(file, &b, 1)<1) { + return(0); + } + return((unsigned)b); +} + + +within(adr,lbd,ubd) +char *adr; +long lbd, ubd; +{ + return((unsigned)adr>=lbd && (unsigned)adr +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define IGNOREUSER "sleeper" + +char hostname[32]; +char mesg[3000]; +int msize,sline; +struct utmp *utmp; +char who[UT_NAMESIZE + 1] = "???"; +long clock; +struct tm *localclock; + +extern errno; + +main(argc, argv) +char *argv[]; +{ + register int i, c; + register struct utmp *p; + int f; + struct stat statb; + + (void) gethostname(hostname, sizeof (hostname)); + if ((f = open(_PATH_UTMP, O_RDONLY, 0)) < 0) { + fprintf(stderr, "Cannot open %s\n", _PATH_UTMP); + exit(1); + } + clock = time( 0 ); + localclock = localtime( &clock ); + sline = ttyslot(); /* 'utmp' slot no. of sender */ + (void) fstat(f, &statb); + utmp = (struct utmp *)malloc((unsigned)statb.st_size); + c = read(f, (char *)utmp, (int)statb.st_size); + (void) close(f); + c /= sizeof(struct utmp); + if (sline) + strncpy(who, utmp[sline].ut_name, sizeof(utmp[sline].ut_name)); + sprintf(mesg, + "\n\007\007Broadcast Message from %s@%s (%.*s) at %d:%02d ...\r\n\n" + , who + , hostname + , sizeof(utmp[sline].ut_line) + , utmp[sline].ut_line + , localclock -> tm_hour + , localclock -> tm_min + ); + msize = strlen(mesg); + if (argc >= 2) { + /* take message from unix file instead of standard input */ + if (freopen(argv[1], "r", stdin) == NULL) { + perror(argv[1]); + exit(1); + } + } + while ((i = getchar()) != EOF) { + if (i == '\n') + mesg[msize++] = '\r'; + if (msize >= sizeof mesg) { + fprintf(stderr, "Message too long\n"); + exit(1); + } + mesg[msize++] = i; + } + fclose(stdin); + for (i=0; iut_name[0] == 0 || + strncmp(p->ut_name, IGNOREUSER, sizeof(p->ut_name)) == 0) + continue; + sendmes(p->ut_line); + } + exit(0); +} + +sendmes(tty) +char *tty; +{ + register f, flags; + static char t[50] = "/dev/"; + int e, i; + + strcpy(t + 5, tty); + + if ((f = open(t, O_WRONLY|O_NDELAY)) < 0) { + if (errno != EWOULDBLOCK) + perror(t); + return; + } + if ((flags = fcntl(f, F_GETFL, 0)) == -1) { + perror(t); + return; + } + if (fcntl(f, F_SETFL, flags | FNDELAY) == -1) + goto oldway; + i = write(f, mesg, msize); + e = errno; + (void) fcntl(f, F_SETFL, flags); + if (i == msize) { + (void) close(f); + return; + } + if (e != EWOULDBLOCK) { + errno = e; + perror(t); + (void) close(f); + return; + } +oldway: + while ((i = fork()) == -1) + if (wait((int *)0) == -1) { + fprintf(stderr, "Try again\n"); + return; + } + if (i) { + (void) close(f); + return; + } + + (void) write(f, mesg, msize); + exit(0); +} diff --git a/src/cmd/wc.c b/src/cmd/wc.c new file mode 100644 index 0000000..77ce31e --- /dev/null +++ b/src/cmd/wc.c @@ -0,0 +1,109 @@ +/* + * wc line and word count + * + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include +#include + +long linect, wordct, charct, pagect; +long tlinect, twordct, tcharct, tpagect; +char *wd = "lwc"; + +main(argc, argv) +char **argv; +{ + int i, token; + register FILE *fp; + register int c; + char *p; + + while (argc > 1 && *argv[1] == '-') { + switch (argv[1][1]) { + case 'l': case 'w': case 'c': + wd = argv[1]+1; + break; + default: + usage: + fprintf(stderr, "Usage: wc [-lwc] [files]\n"); + exit(1); + } + argc--; + argv++; + } + + i = 1; + fp = stdin; + do { + if(argc>1 && (fp=fopen(argv[i], "r")) == NULL) { + perror(argv[i]); + continue; + } + linect = 0; + wordct = 0; + charct = 0; + token = 0; + for(;;) { + c = getc(fp); + if (c == EOF) + break; + charct++; + if(' '1) { + printf(" %s\n", argv[i]); + } else + printf("\n"); + fclose(fp); + tlinect += linect; + twordct += wordct; + tcharct += charct; + } while(++i 2) { + wcp(wd, tcharct, twordct, tlinect); + printf(" total\n"); + } + exit(0); +} + +wcp(wd, charct, wordct, linect) +register char *wd; +long charct; long wordct; long linect; +{ + while (*wd) switch (*wd++) { + case 'l': + ipr(linect); + break; + + case 'w': + ipr(wordct); + break; + + case 'c': + ipr(charct); + break; + + } +} + +ipr(num) +long num; +{ + printf(" %7ld", num); +} diff --git a/src/cmd/whereis.c b/src/cmd/whereis.c new file mode 100644 index 0000000..7f48d5b --- /dev/null +++ b/src/cmd/whereis.c @@ -0,0 +1,293 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include +#include +#include +#include +#include +#include + +static char *bindirs[] = { + "/etc", + "/bin", + "/sbin", + "/games", + "/libexec", + "/local", + "/local/bin", + "/new", + 0 +}; +static char *mandirs[] = { + "/man/man1", + "/man/man2", + "/man/man3", + "/man/man4", + "/man/man5", + "/man/man6", + "/man/man7", + "/man/man8", + "/man/manl", + "/man/mann", + "/man/mano", + 0 +}; +static char *srcdirs[] = { + "/src/bin", + "/src/sbin", + "/src/etc", + "/src/games", + "/src/lib", + "/src/libexec", + "/src/local", + "/src/new", + "/src/include", + "/src/lib/libc/gen", + "/src/lib/libc/stdio", + "/src/lib/libc/sys", + "/src/lib/libc/net/inet", + "/src/lib/libc/net/misc", + 0 +}; + +char sflag = 1; +char bflag = 1; +char mflag = 1; +char **Sflag; +int Scnt; +char **Bflag; +int Bcnt; +char **Mflag; +int Mcnt; +char uflag; +/* + * whereis name + * look for source, documentation and binaries + */ +main(argc, argv) + int argc; + char *argv[]; +{ + + argc--, argv++; + if (argc == 0) { +usage: + fprintf(stderr, "whereis [ -sbmu ] [ -SBM dir ... -f ] name...\n"); + exit(1); + } + do + if (argv[0][0] == '-') { + register char *cp = argv[0] + 1; + while (*cp) switch (*cp++) { + + case 'f': + break; + + case 'S': + getlist(&argc, &argv, &Sflag, &Scnt); + break; + + case 'B': + getlist(&argc, &argv, &Bflag, &Bcnt); + break; + + case 'M': + getlist(&argc, &argv, &Mflag, &Mcnt); + break; + + case 's': + zerof(); + sflag++; + continue; + + case 'u': + uflag++; + continue; + + case 'b': + zerof(); + bflag++; + continue; + + case 'm': + zerof(); + mflag++; + continue; + + default: + goto usage; + } + argv++; + } else + lookup(*argv++); + while (--argc > 0); +} + +getlist(argcp, argvp, flagp, cntp) + char ***argvp; + int *argcp; + char ***flagp; + int *cntp; +{ + + (*argvp)++; + *flagp = *argvp; + *cntp = 0; + for ((*argcp)--; *argcp > 0 && (*argvp)[0][0] != '-'; (*argcp)--) + (*cntp)++, (*argvp)++; + (*argcp)++; + (*argvp)--; +} + + +zerof() +{ + + if (sflag && bflag && mflag) + sflag = bflag = mflag = 0; +} +int count; +int print; + + +lookup(cp) + register char *cp; +{ + register char *dp; + + for (dp = cp; *dp; dp++) + continue; + for (; dp > cp; dp--) { + if (*dp == '.') { + *dp = 0; + break; + } + } + for (dp = cp; *dp; dp++) + if (*dp == '/') + cp = dp + 1; + if (uflag) { + print = 0; + count = 0; + } else + print = 1; +again: + if (print) + printf("%s:", cp); + if (sflag) { + looksrc(cp); + if (uflag && print == 0 && count != 1) { + print = 1; + goto again; + } + } + count = 0; + if (bflag) { + lookbin(cp); + if (uflag && print == 0 && count != 1) { + print = 1; + goto again; + } + } + count = 0; + if (mflag) { + lookman(cp); + if (uflag && print == 0 && count != 1) { + print = 1; + goto again; + } + } + if (print) + printf("\n"); +} + +looksrc(cp) + char *cp; +{ + if (Sflag == 0) { + find(srcdirs, cp); + } else + findv(Sflag, Scnt, cp); +} + +lookbin(cp) + char *cp; +{ + if (Bflag == 0) + find(bindirs, cp); + else + findv(Bflag, Bcnt, cp); +} + +lookman(cp) + char *cp; +{ + if (Mflag == 0) { + find(mandirs, cp); + } else + findv(Mflag, Mcnt, cp); +} + +findv(dirv, dirc, cp) + char **dirv; + int dirc; + char *cp; +{ + + while (dirc > 0) + findin(*dirv++, cp), dirc--; +} + +find(dirs, cp) + char **dirs; + char *cp; +{ + + while (*dirs) + findin(*dirs++, cp); +} + +findin(dir, cp) + char *dir, *cp; +{ + DIR *dirp; + struct direct *dp; + + dirp = opendir(dir); + if (dirp == NULL) + return; + while ((dp = readdir(dirp)) != NULL) { + if (itsit(cp, dp->d_name)) { + count++; + if (print) + printf(" %s/%s", dir, dp->d_name); + } + } + closedir(dirp); +} + +itsit(cp, dp) + register char *cp, *dp; +{ + register int i = strlen(dp); + + if (dp[0] == 's' && dp[1] == '.' && itsit(cp, dp+2)) + return (1); + while (*cp && *dp && *cp == *dp) + cp++, dp++, i--; + if (*cp == 0 && *dp == 0) + return (1); + while (isdigit(*dp)) + dp++; + if (*cp == 0 && *dp++ == '.') { + --i; + while (i > 0 && *dp) + if (--i, *dp++ == '.') + return (*dp++ == 'C' && *dp++ == 0); + return (1); + } + return (0); +} diff --git a/src/cmd/who.c b/src/cmd/who.c new file mode 100644 index 0000000..b752044 --- /dev/null +++ b/src/cmd/who.c @@ -0,0 +1,80 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include +#include +#include +#include +#include +#include /* for MAXHOSTNAMELEN */ +#include +#include +#include +#include +#include + +#define NMAX sizeof(utmp.ut_name) +#define LMAX sizeof(utmp.ut_line) +#define HMAX sizeof(utmp.ut_host) + +struct utmp utmp; +struct passwd *pw; +char hostname[MAXHOSTNAMELEN]; + +main(argc, argv) + int argc; + char **argv; +{ + register char *tp, *s; + register FILE *fi; + + s = _PATH_UTMP; + if(argc == 2) + s = argv[1]; + if (argc == 3) { + tp = ttyname(0); + if (tp) + tp = rindex(tp, '/') + 1; + else { /* no tty - use best guess from passwd file */ + pw = getpwuid(getuid()); + strncpy(utmp.ut_name, pw ? pw->pw_name : "?", NMAX); + strcpy(utmp.ut_line, "tty??"); + time(&utmp.ut_time); + putline(); + exit(0); + } + } + if ((fi = fopen(s, "r")) == NULL) { + fprintf(stderr, "who: cannot open %s\n", s); + exit(1); + } + while (fread((char *)&utmp, sizeof(utmp), 1, fi) == 1) { + if (argc == 3) { + gethostname(hostname, sizeof (hostname)); + if (strcmp(utmp.ut_line, tp)) + continue; + printf("%s!", hostname); + putline(); + exit(0); + } + if (utmp.ut_name[0] == '\0' && argc == 1) + continue; + putline(); + } +} + +putline() +{ + register char *cbuf; + + printf("%-*.*s %-*.*s", + NMAX, NMAX, utmp.ut_name, + LMAX, LMAX, utmp.ut_line); + cbuf = ctime(&utmp.ut_time); + printf("%.12s", cbuf+4); + if (utmp.ut_host[0]) + printf("\t(%.*s)", HMAX, utmp.ut_host); + putchar('\n'); +} diff --git a/src/cmd/wiznet/Makefile b/src/cmd/wiznet/Makefile new file mode 100644 index 0000000..c8db3c2 --- /dev/null +++ b/src/cmd/wiznet/Makefile @@ -0,0 +1,49 @@ +TOPSRC = $(shell cd ../../..; pwd) +include $(TOPSRC)/target.mk + +CFLAGS += -O -Wall -Werror +LIBS += -lwiznet -lc + +EXAMPLES = telnet \ + ntpdate \ + chat-server \ + web-client \ + web-server + +all: $(EXAMPLES) + +web-client: web-client.o + ${CC} ${LDFLAGS} -o $@.elf $< ${LIBS} + ${OBJDUMP} -S $@.elf > $@.dis + ${SIZE} $@.elf + ${ELF2AOUT} $@.elf $@ + +web-server: web-server.o + ${CC} ${LDFLAGS} -o $@.elf $< ${LIBS} + ${OBJDUMP} -S $@.elf > $@.dis + ${SIZE} $@.elf + ${ELF2AOUT} $@.elf $@ + +telnet: telnet.o + ${CC} ${LDFLAGS} -o $@.elf $< ${LIBS} + ${OBJDUMP} -S $@.elf > $@.dis + ${SIZE} $@.elf + ${ELF2AOUT} $@.elf $@ + +ntpdate: ntpdate.o + ${CC} ${LDFLAGS} -o $@.elf $< ${LIBS} + ${OBJDUMP} -S $@.elf > $@.dis + ${SIZE} $@.elf + ${ELF2AOUT} $@.elf $@ + +chat-server: chat-server.o + ${CC} ${LDFLAGS} -o $@.elf $< ${LIBS} + ${OBJDUMP} -S $@.elf > $@.dis + ${SIZE} $@.elf + ${ELF2AOUT} $@.elf $@ + +clean: + rm -f *.o *.elf *.dis $(EXAMPLES) + +install: all + install $(EXAMPLES) $(DESTDIR)/bin/ diff --git a/src/cmd/wiznet/chat-server.c b/src/cmd/wiznet/chat-server.c new file mode 100644 index 0000000..3e4db3c --- /dev/null +++ b/src/cmd/wiznet/chat-server.c @@ -0,0 +1,50 @@ +/* + * Chat Server + * + * A simple server that distributes any incoming messages to all + * connected clients. To use telnet to your device's IP address and type. + * Using an Arduino Wiznet Ethernet shield. + * + * 18 Dec 2009 created by David A. Mellis + * 10 Aug 2010 modified by Tom Igoe + * 16 Apr 2012 ported to RetroBSD by Serge Vakulenko + */ +#include +#include +#include +#include + +int got_a_message = 0; /* whether you got a message from the client yet */ + +int main() +{ + /* Initialize the ethernet device */ + ethernet_init (); + + /* Start listening for clients. + * Telnet defaults to port 23. */ + server_init (23); + + for (;;) { + /* Wait for a new client. */ + client_t client; + if (! server_available (&client)) + continue; + + /* When the client sends the first byte, say hello. */ + if (! got_a_message) { + printf ("We have a new client\n"); + client_puts (&client, "Hello, client!\n"); + got_a_message = 1; + } + + /* Read the bytes incoming from the client. + * Echo the bytes back to the client. */ + char c = client_getc (&client); + server_putc (c); + + /* Echo the bytes to the server as well. */ + putchar (c); + fflush (stdout); + } +} diff --git a/src/cmd/wiznet/ntpdate.c b/src/cmd/wiznet/ntpdate.c new file mode 100644 index 0000000..4989a3c --- /dev/null +++ b/src/cmd/wiznet/ntpdate.c @@ -0,0 +1,142 @@ +/* + * UDP NTP Client + * + * Get the time from a Network Time Protocol (NTP) time server. + * Demonstrates use of UDP send_packet and receive_packet. + * For more on NTP time servers and the messages needed to communicate with them, + * see http://en.wikipedia.org/wiki/Network_Time_Protocol + * + * 4 Sep 2010 created by Michael Margolis + * 17 Sep 2010 modified by Tom Igoe + * 16 Apr 2012 ported to RetroBSD by Serge Vakulenko + * + * This code is in the public domain. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#define NTP_PORT 123 /* Local port to listen for UDP packets */ +#define LOCAL_PORT 8888 /* Local port to listen for UDP packets */ +#define NTP_PACKET_SIZE 48 /* NTP time stamp is in the first 48 bytes of the message */ + +/* + * IP address of the server. + */ +unsigned char server[4]; + +/* + * Buffer to hold incoming and outgoing packets. + */ +unsigned char packetBuffer [NTP_PACKET_SIZE]; + +/* + * A UDP instance to let us send and receive packets over UDP. + */ +udp_t udp; + +/* + * Send an NTP request to the time server at the given address. + */ +void send_ntp_packet (unsigned char *address) +{ + /* Set all bytes in the buffer to 0. */ + memset (packetBuffer, 0, NTP_PACKET_SIZE); + + /* Initialize values needed to form NTP request + * (see URL above for details on the packets). */ + packetBuffer[0] = 0b11100011; /* LI, Version, Mode */ + packetBuffer[1] = 0; /* Stratum, or type of clock */ + packetBuffer[2] = 6; /* Polling Interval */ + packetBuffer[3] = 0xEC; /* Peer Clock Precision */ + + /* 8 bytes of zero for Root Delay & Root Dispersion. */ + packetBuffer[12] = 49; + packetBuffer[13] = 0x4E; + packetBuffer[14] = 49; + packetBuffer[15] = 52; + + /* All NTP fields have been given values, now + * you can send a packet requesting a timestamp. */ + udp_send_packet (&udp, packetBuffer, NTP_PACKET_SIZE, address, NTP_PORT); +} + +int main (int argc, char **argv) +{ + struct timeval tv; + struct timezone tz; + + gettimeofday (&tv, &tz); + + if (argc > 1) { + /* Command argument: IP address of server. */ + *(int*)server = inet_addr (argv[1]); + } else { + /* time.nist.gov NTP server */ + server[0] = 192; + server[1] = 43; + server[2] = 244; + server[3] = 18; + } + + /* Start Ethernet and UDP. */ + ethernet_init (); + udp_init (&udp, LOCAL_PORT); + + for (;;) { + /* Send an NTP packet to a time server. */ + send_ntp_packet (server); + + /* Wait to see if a reply is available. */ + sleep (1); + + if (udp_available (&udp)) { + /* Read the packet into the buffer. */ + udp_read_packet (&udp, packetBuffer, NTP_PACKET_SIZE, 0, 0); +#if 0 + int i; + for (i=0; itm_year + 1900, L->tm_mon + 1, L->tm_mday, + (epoch % 86400L) / 3600, // hour (86400 equals secs per day) + (epoch % 3600) / 60, // minute (3600 equals secs per minute) + epoch % 60); // second + } + + /* Wait before asking for the time again. */ + sleep (1); + } +} diff --git a/src/cmd/wiznet/telnet.c b/src/cmd/wiznet/telnet.c new file mode 100644 index 0000000..a13df35 --- /dev/null +++ b/src/cmd/wiznet/telnet.c @@ -0,0 +1,290 @@ +/* + * Telnet client + * + * This sketch connects to a a telnet server (http://www.google.com) + * using an Arduino Wiznet Ethernet shield. You'll need a telnet server + * to test this with. + * Processing's ChatServer example (part of the network library) works well, + * running on port 10002. It can be found as part of the examples + * in the Processing application, available at http://processing.org/ + * + * Circuit: + * - Ethernet shield attached to pins 10, 11, 12, 13 + * + * 14 Sep 2010 created by Tom Igoe + * 04 Jun 2012 telnet protocol by Serge Vakulenko + */ +#include +#include +#include +#include +#include + +/* + * 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 AYT 246 /* are you there */ +#define NOP 241 /* nop */ + +/* + * Telnet options + */ +#define TELOPT_BINARY 0 /* 8-bit data path */ +#define TELOPT_ECHO 1 /* echo */ +#define TELOPT_SGA 3 /* suppress go ahead */ +#define TELOPT_TM 6 /* timing mark */ + +/* + * IP address of the server to connect to. + */ +unsigned char server[4]; + +client_t client; + +/* + * Telnet options. + */ +unsigned char local_option [256/8]; +unsigned char remote_option [256/8]; + +/* + * Get local and remote options. + */ +static int +get_local_option (int opt) +{ + return (local_option [opt >> 3] >> (opt & 7)) & 1; +} + +static int +get_remote_option (int opt) +{ + return (remote_option [opt >> 3] >> (opt & 7)) & 1; +} + +/* +* Send reply to remote host +*/ +static void +reply (int cmd, int opt) +{ + client_putc (&client, IAC); + client_putc (&client, cmd); + client_putc (&client, opt); +} + +static void +will_option (int opt) +{ + int cmd; + + switch (opt) { + case TELOPT_BINARY: + case TELOPT_ECHO: + case TELOPT_SGA: + /* Set remote option. */ + remote_option [opt >> 3] |= 1 << (opt & 7); + cmd = DO; + break; + + case TELOPT_TM: + default: + cmd = DONT; + break; + } + reply (cmd, opt); +} + +static void +wont_option (int opt) +{ + switch (opt) { + case TELOPT_ECHO: + case TELOPT_BINARY: + case TELOPT_SGA: + /* Clear remote option. */ + remote_option [opt >> 3] &= ~(1 << (opt & 7)); + break; + } + reply (DONT, opt); +} + +static void +do_option (int opt) +{ + int cmd; + + switch (opt) { + case TELOPT_ECHO: + case TELOPT_BINARY: + case TELOPT_SGA: + /* Set local option. */ + local_option [opt >> 3] |= 1 << (opt & 7); + cmd = WILL; + break; + + case TELOPT_TM: + default: + cmd = WONT; + break; + } + reply (cmd, opt); +} + +static void +dont_option (int opt) +{ + switch (opt) { + case TELOPT_ECHO: + case TELOPT_BINARY: + case TELOPT_SGA: + /* Clear local option. */ + local_option [opt >> 3] &= ~(1 << (opt & 7)); + break; + } + reply (WONT, opt); +} + +static void +telnet_command (int c) +{ + int i; + + switch (c) { + case AYT: + /* Send reply to AYT ("Are You There") request */ + client_putc (&client, IAC); + client_putc (&client, NOP); + break; + case WILL: + /* IAC WILL received (get next character) */ + c = client_getc (&client); + if (c >= 0 && c < 256 && ! get_remote_option (c)) + will_option (c); + break; + case WONT: + /* IAC WONT received (get next character) */ + c = client_getc (&client); + if (c >= 0 && c < 256 && get_remote_option (c)) + wont_option (c); + break; + case DO: + /* IAC DO received (get next character) */ + c = client_getc (&client); + if (c >= 0 && c < 256 && ! get_local_option (c)) + do_option (c); + break; + case DONT: + /* IAC DONT received (get next character) */ + c = client_getc (&client); + if (c >= 0 && c < 256 && get_local_option (c)) + dont_option (c); + break; + case SB: + for (i=0; i<128; i++) { + c = client_getc (&client); + if (c == IAC) { + c = client_getc (&client); + break; + } + } + break; + } +} + +static int +telnet_getc () +{ + int c; + + for (;;) { + c = client_getc (&client); + if (c != IAC) + return c; + + c = client_getc (&client); + if (c < 0 || c == IAC) + return c; + + telnet_command (c); + } +} + +int main (int argc, char **argv) +{ + /* Command argument: IP address of server. */ + if (argc != 2) { + printf ("Usage: %s \n", argv[0]); + return -1; + } + *(int*)server = inet_addr (argv[1]); + + /* Start the Ethernet connection. */ + ethernet_init (); + + /* Give the Ethernet shield a second to initialize. */ + usleep (1000000); + + /* Initialize the Ethernet client library + * with the IP address and port of the server + * that you want to connect to (port 23 is default for telnet). */ + client_init (&client, server, 23); + printf("connecting to %u.%u.%u.%u\n", + server[0], server[1], server[2], server[3]); + + /* If you get a connection, report back via console. */ + if (! client_connect (&client)) { + /* If you didn't get a connection to the server. */ + printf("connection failed\n"); + client_stop (&client); + return 0; + } + printf("connected\n"); + + /* Setup telnet options */ + do_option (TELOPT_ECHO); + do_option (TELOPT_SGA); + will_option (TELOPT_SGA); + + while (client_connected (&client)) { + + /* If there are incoming bytes available + * from the server, read them and print them. */ + if (client_available (&client)) { + int c = telnet_getc(); + if (c >= 0) + putchar(c); + } + fflush (stdout); + + /* As long as there are bytes in the serial queue, + * read them and send them out the socket if it's open. */ + for (;;) { + off_t nread; + char c; + + if (ioctl (0, FIONREAD, &nread) < 0 || nread == 0) + break; + + read(0, &c, 1); + if (client_connected (&client)) { + client_putc (&client, c); + + /* IAC -> IAC IAC */ + if (c == (char) IAC) + client_putc (&client, c); + } + } + } + + /* If the server's disconnected, stop the client. */ + printf("\ndisconnecting.\n"); + client_stop (&client); + return 0; +} diff --git a/src/cmd/wiznet/todo/barometric-pressure-web-server.c b/src/cmd/wiznet/todo/barometric-pressure-web-server.c new file mode 100644 index 0000000..a58433f --- /dev/null +++ b/src/cmd/wiznet/todo/barometric-pressure-web-server.c @@ -0,0 +1,225 @@ +/* + SCP1000 Barometric Pressure Sensor Display + + Serves the output of a Barometric Pressure Sensor as a web page. + Uses the SPI library. For details on the sensor, see: + http://www.sparkfun.com/commerce/product_info.php?products_id=8161 + http://www.vti.fi/en/support/obsolete_products/pressure_sensors/ + + This sketch adapted from Nathan Seidle's SCP1000 example for PIC: + http://www.sparkfun.com/datasheets/Sensors/SCP1000-Testing.zip + + Circuit: + SCP1000 sensor attached to pins 6,7, and 11 - 13: + DRDY: pin 6 + CSB: pin 7 + MOSI: pin 11 + MISO: pin 12 + SCK: pin 13 + + created 31 July 2010 + by Tom Igoe + */ + +#include +// the sensor communicates using SPI, so include the library: +#include + + +// assign a MAC address for the ethernet controller. +// fill in your address here: +byte mac[] = { + 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED}; +// assign an IP address for the controller: +byte ip[] = { + 192,168,1,20 }; +byte gateway[] = { + 192,168,1,1}; +byte subnet[] = { + 255, 255, 255, 0 }; + + +// Initialize the Ethernet server library +// with the IP address and port you want to use +// (port 80 is default for HTTP): +Server server(80); + + +//Sensor's memory register addresses: +const int PRESSURE = 0x1F; //3 most significant bits of pressure +const int PRESSURE_LSB = 0x20; //16 least significant bits of pressure +const int TEMPERATURE = 0x21; //16 bit temperature reading + +// pins used for the connection with the sensor +// the others you need are controlled by the SPI library): +const int dataReadyPin = 6; +const int chipSelectPin = 7; + +float temperature = 0.0; +long pressure = 0; +long lastReadingTime = 0; + +void setup() { + // start the SPI library: + SPI.begin(); + + // start the Ethernet connection and the server: + Ethernet.begin(mac, ip); + server.begin(); + + // initalize the data ready and chip select pins: + pinMode(dataReadyPin, INPUT); + pinMode(chipSelectPin, OUTPUT); + + Serial.begin(9600); + + //Configure SCP1000 for low noise configuration: + writeRegister(0x02, 0x2D); + writeRegister(0x01, 0x03); + writeRegister(0x03, 0x02); + + // give the sensor and Ethernet shield time to set up: + delay(1000); + + //Set the sensor to high resolution mode tp start readings: + writeRegister(0x03, 0x0A); + +} + +void loop() { + // check for a reading no more than once a second. + if (millis() - lastReadingTime > 1000){ + // if there's a reading ready, read it: + // don't do anything until the data ready pin is high: + if (digitalRead(dataReadyPin) == HIGH) { + getData(); + // timestamp the last time you got a reading: + lastReadingTime = millis(); + } + } + + // listen for incoming Ethernet connections: + listenForClients(); +} + + +void getData() { + Serial.println("Getting reading"); + //Read the temperature data + int tempData = readRegister(0x21, 2); + + // convert the temperature to celsius and display it: + temperature = (float)tempData / 20.0; + + //Read the pressure data highest 3 bits: + byte pressureDataHigh = readRegister(0x1F, 1); + pressureDataHigh &= 0b00000111; //you only needs bits 2 to 0 + + //Read the pressure data lower 16 bits: + unsigned int pressureDataLow = readRegister(0x20, 2); + //combine the two parts into one 19-bit number: + pressure = ((pressureDataHigh << 16) | pressureDataLow)/4; + + Serial.print("Temperature: "); + Serial.print(temperature); + Serial.println(" degrees C"); + Serial.print("Pressure: " + String(pressure)); + Serial.println(" Pa"); +} + +void listenForClients() { + // listen for incoming clients + Client client = server.available(); + if (client) { + Serial.println("Got a client"); + // an http request ends with a blank line + boolean currentLineIsBlank = true; + while (client.connected()) { + if (client.available()) { + char c = client.read(); + // if you've gotten to the end of the line (received a newline + // character) and the line is blank, the http request has ended, + // so you can send a reply + if (c == '\n' && currentLineIsBlank) { + // send a standard http response header + client.println("HTTP/1.1 200 OK"); + client.println("Content-Type: text/html"); + client.println(); + // print the current readings, in HTML format: + client.print("Temperature: "); + client.print(temperature); + client.print(" degrees C"); + client.println("
    "); + client.print("Pressure: " + String(pressure)); + client.print(" Pa"); + client.println("
    "); + break; + } + if (c == '\n') { + // you're starting a new line + currentLineIsBlank = true; + } + else if (c != '\r') { + // you've gotten a character on the current line + currentLineIsBlank = false; + } + } + } + // give the web browser time to receive the data + delay(1); + // close the connection: + client.stop(); + } +} + + +//Send a write command to SCP1000 +void writeRegister(byte registerName, byte registerValue) { + // SCP1000 expects the register name in the upper 6 bits + // of the byte: + registerName <<= 2; + // command (read or write) goes in the lower two bits: + registerName |= 0b00000010; //Write command + + // take the chip select low to select the device: + digitalWrite(chipSelectPin, LOW); + + SPI.transfer(registerName); //Send register location + SPI.transfer(registerValue); //Send value to record into register + + // take the chip select high to de-select: + digitalWrite(chipSelectPin, HIGH); +} + + +//Read register from the SCP1000: +unsigned int readRegister(byte registerName, int numBytes) { + byte inByte = 0; // incoming from the SPI read + unsigned int result = 0; // result to return + + // SCP1000 expects the register name in the upper 6 bits + // of the byte: + registerName <<= 2; + // command (read or write) goes in the lower two bits: + registerName &= 0b11111100; //Read command + + // take the chip select low to select the device: + digitalWrite(chipSelectPin, LOW); + // send the device the register you want to read: + int command = SPI.transfer(registerName); + // send a value of 0 to read the first byte returned: + inByte = SPI.transfer(0x00); + + result = inByte; + // if there's more than one byte returned, + // shift the first byte then get the second byte: + if (numBytes > 1){ + result = inByte << 8; + inByte = SPI.transfer(0x00); + result = result |inByte; + } + // take the chip select high to de-select: + digitalWrite(chipSelectPin, HIGH); + // return the result: + return(result); +} diff --git a/src/cmd/wiznet/todo/pachube-client-string.c b/src/cmd/wiznet/todo/pachube-client-string.c new file mode 100644 index 0000000..d493016 --- /dev/null +++ b/src/cmd/wiznet/todo/pachube-client-string.c @@ -0,0 +1,124 @@ +/* + Pachube sensor client with Strings + + This sketch connects an analog sensor to Pachube (http://www.pachube.com) + using a Wiznet Ethernet shield. You can use the Arduino Ethernet shield, or + the Adafruit Ethernet shield, either one will work, as long as it's got + a Wiznet Ethernet module on board. + + This example uses the String library, which is part of the Arduino core from + version 0019. + + Circuit: + * Analog sensor attached to analog in 0 + * Ethernet shield attached to pins 10, 11, 12, 13 + + created 15 March 2010 + updated 4 Sep 2010 + by Tom Igoe + + This code is in the public domain. + + */ + +#include +#include + +// assign a MAC address for the ethernet controller. +// fill in your address here: +byte mac[] = { + 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED}; +// assign an IP address for the controller: +byte ip[] = { + 192,168,1,20 }; +byte gateway[] = { + 192,168,1,1}; +byte subnet[] = { + 255, 255, 255, 0 }; + +// The address of the server you want to connect to (pachube.com): +byte server[] = { + 173,203,98,29 }; + +// initialize the library instance: +Client client(server, 80); + +long lastConnectionTime = 0; // last time you connected to the server, in milliseconds +boolean lastConnected = false; // state of the connection last time through the main loop +const int postingInterval = 10000; //delay between updates to Pachube.com + +void setup() { + // start the ethernet connection and serial port: + Ethernet.begin(mac, ip); + Serial.begin(9600); + // give the ethernet module time to boot up: + delay(1000); +} + +void loop() { + // read the analog sensor: + int sensorReading = analogRead(A0); + // convert the data to a String to send it: + String dataString = String(sensorReading); + + // you can append multiple readings to this String if your + // pachube feed is set up to handle multiple values: + int otherSensorReading = analogRead(A1); + dataString += ","; + dataString += String(otherSensorReading); + + // if there's incoming data from the net connection. + // send it out the serial port. This is for debugging + // purposes only: + if (client.available()) { + char c = client.read(); + Serial.print(c); + } + + // if there's no net connection, but there was one last time + // through the loop, then stop the client: + if (!client.connected() && lastConnected) { + Serial.println(); + Serial.println("disconnecting."); + client.stop(); + } + + // if you're not connected, and ten seconds have passed since + // your last connection, then connect again and send data: + if(!client.connected() && (millis() - lastConnectionTime > postingInterval)) { + sendData(dataString); + } + // store the state of the connection for next time through + // the loop: + lastConnected = client.connected(); +} + +// this method makes a HTTP connection to the server: +void sendData(String thisData) { + // if there's a successful connection: + if (client.connect()) { + Serial.println("connecting..."); + // send the HTTP PUT request. + // fill in your feed address here: + client.print("PUT /api/YOUR_FEED_HERE.csv HTTP/1.1\n"); + client.print("Host: www.pachube.com\n"); + // fill in your Pachube API key here: + client.print("X-PachubeApiKey: YOUR_KEY_HERE\n"); + client.print("Content-Length: "); + client.println(thisData.length(), DEC); + + // last pieces of the HTTP PUT request: + client.print("Content-Type: text/csv\n"); + client.println("Connection: close\n"); + + // here's the actual content of the PUT request: + client.println(thisData); + + // note the time that the connection was made: + lastConnectionTime = millis(); + } + else { + // if you couldn't make a connection: + Serial.println("connection failed"); + } +} diff --git a/src/cmd/wiznet/todo/pachube-client.c b/src/cmd/wiznet/todo/pachube-client.c new file mode 100644 index 0000000..406c7d1 --- /dev/null +++ b/src/cmd/wiznet/todo/pachube-client.c @@ -0,0 +1,139 @@ +/* + Pachube sensor client + + This sketch connects an analog sensor to Pachube (http://www.pachube.com) + using a Wiznet Ethernet shield. You can use the Arduino Ethernet shield, or + the Adafruit Ethernet shield, either one will work, as long as it's got + a Wiznet Ethernet module on board. + + Circuit: + * Analog sensor attached to analog in 0 + * Ethernet shield attached to pins 10, 11, 12, 13 + + created 15 March 2010 + updated 4 Sep 2010 + by Tom Igoe + + http://www.tigoe.net/pcomp/code/category/arduinowiring/873 + This code is in the public domain. + + */ + +#include +#include + +// assign a MAC address for the ethernet controller. +// fill in your address here: +byte mac[] = { + 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED}; +// assign an IP address for the controller: +byte ip[] = { + 192,168,1,20 }; +byte gateway[] = { + 192,168,1,1}; +byte subnet[] = { + 255, 255, 255, 0 }; + +// The address of the server you want to connect to (pachube.com): +byte server[] = { + 173,203,98,29 }; + +// initialize the library instance: +Client client(server, 80); + +long lastConnectionTime = 0; // last time you connected to the server, in milliseconds +boolean lastConnected = false; // state of the connection last time through the main loop +const int postingInterval = 10000; //delay between updates to Pachube.com + +void setup() { + // start the ethernet connection and serial port: + Ethernet.begin(mac, ip); + Serial.begin(9600); + // give the ethernet module time to boot up: + delay(1000); +} + +void loop() { + // read the analog sensor: + int sensorReading = analogRead(A0); + + // if there's incoming data from the net connection. + // send it out the serial port. This is for debugging + // purposes only: + if (client.available()) { + char c = client.read(); + Serial.print(c); + } + + // if there's no net connection, but there was one last time + // through the loop, then stop the client: + if (!client.connected() && lastConnected) { + Serial.println(); + Serial.println("disconnecting."); + client.stop(); + } + + // if you're not connected, and ten seconds have passed since + // your last connection, then connect again and send data: + if(!client.connected() && (millis() - lastConnectionTime > postingInterval)) { + sendData(sensorReading); + } + // store the state of the connection for next time through + // the loop: + lastConnected = client.connected(); +} + +// this method makes a HTTP connection to the server: +void sendData(int thisData) { + // if there's a successful connection: + if (client.connect()) { + Serial.println("connecting..."); + // send the HTTP PUT request. + // fill in your feed address here: + client.print("PUT /api/YOUR_FEED_HERE.csv HTTP/1.1\n"); + client.print("Host: www.pachube.com\n"); + // fill in your Pachube API key here: + client.print("X-PachubeApiKey: YOUR_KEY_HERE\n"); + client.print("Content-Length: "); + + // calculate the length of the sensor reading in bytes: + int thisLength = getLength(thisData); + client.println(thisLength, DEC); + + // last pieces of the HTTP PUT request: + client.print("Content-Type: text/csv\n"); + client.println("Connection: close\n"); + + // here's the actual content of the PUT request: + client.println(thisData, DEC); + + // note the time that the connection was made: + lastConnectionTime = millis(); + } + else { + // if you couldn't make a connection: + Serial.println("connection failed"); + } +} + + +// This method calculates the number of digits in the +// sensor reading. Since each digit of the ASCII decimal +// representation is a byte, the number of digits equals +// the number of bytes: + +int getLength(int someValue) { + // there's at least one byte: + int digits = 1; + // continually divide the value by ten, + // adding one to the digit count for each + // time you divide, until you're at 0: + int dividend = someValue /10; + while (dividend > 0) { + dividend = dividend /10; + digits++; + } + // return the number of digits: + return digits; +} + diff --git a/src/cmd/wiznet/todo/udp-send-receive-string.c b/src/cmd/wiznet/todo/udp-send-receive-string.c new file mode 100644 index 0000000..f27290f --- /dev/null +++ b/src/cmd/wiznet/todo/udp-send-receive-string.c @@ -0,0 +1,109 @@ +/* + UDPSendReceive.pde: + This sketch receives UDP message strings, prints them to the serial port + and sends an "acknowledge" string back to the sender + + A Processing sketch is included at the end of file that can be used to send + and received messages for testing with a computer. + + created 21 Aug 2010 + by Michael Margolis + + This code is in the public domain. + */ + + +#include // needed for Arduino versions later than 0018 +#include +#include // UDP library from: bjoern@cs.stanford.edu 12/30/2008 + + +// Enter a MAC address and IP address for your controller below. +// The IP address will be dependent on your local network: +byte mac[] = { + 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; +byte ip[] = { + 192,168,1,177 }; + +unsigned int localPort = 8888; // local port to listen on + +// the next two variables are set when a packet is received +byte remoteIp[4]; // holds received packet's originating IP +unsigned int remotePort; // holds received packet's originating port + +// buffers for receiving and sending data +char packetBuffer[UDP_TX_PACKET_MAX_SIZE]; //buffer to hold incoming packet, +char ReplyBuffer[] = "acknowledged"; // a string to send back + +// A UDP instance to let us send and receive packets over UDP +UDP Udp; + +void setup() { + // start the Ethernet and UDP: + Ethernet.begin(mac,ip); + Udp.begin(localPort); + + Serial.begin(9600); +} + +void loop() { + // if there's data available, read a packet + int packetSize = Udp.available(); // note that this includes the UDP header + if(packetSize) + { + packetSize = packetSize - 8; // subtract the 8 byte header + Serial.print("Received packet of size "); + Serial.println(packetSize); + + // read the packet into packetBufffer and get the senders IP addr and port number + Udp.readPacket(packetBuffer,UDP_TX_PACKET_MAX_SIZE, remoteIp, remotePort); + Serial.println("Contents:"); + Serial.println(packetBuffer); + + Udp.sendPacket( ReplyBuffer, remoteIp, remotePort); + } + delay(10); +} + + +/* + Processing sketch to run with this example + ===================================================== + + // Processing UDP example to send and receive string data from Arduino + // press any key to send the "Hello Arduino" message + + + import hypermedia.net.*; + + UDP udp; // define the UDP object + + + void setup() { + udp = new UDP( this, 6000 ); // create a new datagram connection on port 6000 + //udp.log( true ); // <-- printout the connection activity + udp.listen( true ); // and wait for incoming message + } + + void draw() + { + } + + void keyPressed() { + String ip = "192.168.1.177"; // the remote IP address + int port = 8888; // the destination port + + udp.send("Hello World", ip, port ); // the message to send + + } + + void receive( byte[] data ) { // <-- default handler + //void receive( byte[] data, String ip, int port ) { // <-- extended handler + + for(int i=0; i < data.length; i++) + print(char(data[i])); + println(); + } + */ + + diff --git a/src/cmd/wiznet/web-client.c b/src/cmd/wiznet/web-client.c new file mode 100644 index 0000000..fdb6b89 --- /dev/null +++ b/src/cmd/wiznet/web-client.c @@ -0,0 +1,73 @@ +/* + * Web client + * + * This sketch connects to a website (http://www.google.com) + * using an Arduino Wiznet Ethernet shield. + * + * 18 Dec 2009 created by David A. Mellis + * 16 Apr 2012 ported to RetroBSD by Serge Vakulenko + */ +#include +#include +#include +#include + +/* + * IP address of the server. + */ +unsigned char server[4]; + +client_t client; + +int main (int argc, char **argv) +{ + if (argc > 1) { + /* Command argument: IP address of server. */ + *(int*)server = inet_addr (argv[1]); + } else { + /* Google */ + server[0] = 173; + server[1] = 194; + server[2] = 33; + server[3] = 104; + } + + /* Start the Ethernet connection. */ + ethernet_init (); + + /* Give the Ethernet shield a second to initialize. */ + usleep (1000000); + + /* Initialize the Ethernet client library + * with the IP address and port of the server + * that you want to connect to (port 80 is default for HTTP). */ + client_init (&client, server, 80); + + printf("connecting to %u.%u.%u.%u\n", + server[0], server[1], server[2], server[3]); + if (! client_connect (&client)) { + /* If you didn't get a connection to the server. */ + printf ("connection failed\n"); + client_stop (&client); + return 0; + } + + /* if you get a connection, report back via serial */ + printf ("connected\n"); + + /* Make a HTTP request. */ + client_puts (&client, "GET / HTTP/1.0\r\n\r\n"); + + while (client_connected (&client)) { + /* If there are incoming bytes available + * from the server, read them and print them. */ + int c = client_getc (&client); + if (c > 0) + putchar(c); + } + + /* If the server's disconnected, stop the client. */ + printf("\ndisconnecting.\n"); + client_stop (&client); + return 0; +} diff --git a/src/cmd/wiznet/web-server.c b/src/cmd/wiznet/web-server.c new file mode 100644 index 0000000..418197f --- /dev/null +++ b/src/cmd/wiznet/web-server.c @@ -0,0 +1,82 @@ +/* + * Web Server + * + * A simple web server that shows the value of the analog input pins. + * using an Arduino Wiznet Ethernet shield. + * + * 18 Dec 2009 created by David A. Mellis + * 4 Sep 2010 modified by Tom Igoe + * 16 Apr 2012 ported to RetroBSD by Serge Vakulenko + */ +#include +#include +#include +#include +#include +#include + +int main() +{ + /* Initialize the Ethernet server library + * with the IP address and port you want to use + * (port 80 is default for HTTP). */ + ethernet_init (); + server_init (80); + + for (;;) { + /* Listen for incoming clients. */ + client_t client; + if (! server_available (&client)) + continue; + + /* An http request ends with a blank line. */ + int current_line_is_blank = 1; + + /* Parse the http request. */ + while (client_connected (&client)) { + if (! client_available (&client)) + continue; + char c = client_getc (&client); + + /* If you've gotten to the end of the line (received + * a newline character) and the line is blank, the http + * request has ended, so you can send a reply. */ + if (c == '\n' && current_line_is_blank) { + break; + } + if (c == '\n') { + /* You're starting a new line. */ + current_line_is_blank = 1; + } + else if (c != '\r') { + /* You've gotten a character on the current line. */ + current_line_is_blank = 0; + } + } + + /* Send a standard http response header. */ + client_puts (&client, "HTTP/1.1 200 OK\n"); + client_puts (&client, "Content-Type: text/html\n\n"); + + /* Output the value of each digital pin. */ + int fd = open ("/dev/porta", O_RDONLY); + if (fd < 0) { + client_puts (&client, "Failed to open /dev/porta\n"); + } else { + int pnum; + for (pnum = 0; pnum < 6; pnum++) { + char buf [80]; + int value = ioctl (fd, GPIO_POLL | GPIO_PORT (pnum), 0); + sprintf (buf, "PORT%c = 0x%04x
    \n", pnum+'A', value); + client_puts (&client, buf); + } + close (fd); + } + + /* Give the web browser time to receive the data. */ + usleep (1000); + + /* Close the connection. */ + client_stop (&client); + } +} diff --git a/src/cmd/write.c b/src/cmd/write.c new file mode 100644 index 0000000..7dc9fd5 --- /dev/null +++ b/src/cmd/write.c @@ -0,0 +1,240 @@ +/* + * write to another user + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define NMAX sizeof(ubuf.ut_name) +#define LMAX sizeof(ubuf.ut_line) + +struct utmp ubuf; +int signum[] = {SIGHUP, SIGINT, SIGQUIT, 0}; +char me[NMAX + 1] = "???"; +char *him; +char *mytty; +char histty[32]; +char ttybuf[32]; +char *histtya; +int logcnt; +FILE *tf; + +void timout(sig) + int sig; +{ + fprintf(stderr, "write: Timeout opening their tty\n"); + exit(1); +} + +void eof(sig) + int sig; +{ + fprintf(tf, "EOF\r\n"); + exit(0); +} + +main(argc, argv) + int argc; + char *argv[]; +{ + struct stat stbuf; + register i; + register FILE *uf; + int c1, c2; + time_t clock = time(0); + int suser = getuid() == 0; + int nomesg = 0; + struct tm *localclock = localtime( &clock ); + + if (argc < 2) { + fprintf(stderr, "Usage: write user [ttyname]\n"); + exit(1); + } + him = argv[1]; + if (argc > 2) + histtya = argv[2]; + if ((uf = fopen(_PATH_UTMP, "r")) == NULL) { + fprintf(stderr, "write: %s: %s\n", _PATH_UTMP, strerror(errno)); + if (histtya == 0) + exit(10); + goto cont; + } + mytty = ttyname(2); + if (mytty == NULL) { + fprintf(stderr, "write: Can't find your tty\n"); + exit(1); + } + if (stat(mytty, &stbuf) < 0) { + perror("write: Can't stat your tty"); + exit(1); + } + if ((stbuf.st_mode&020) == 0) { + fprintf(stderr, + "write: You have write permission turned off\n"); + if (!suser) + exit(1); + } + mytty = strrchr(mytty, '/') + 1; + if (histtya) { + strcpy(histty, "/dev/"); + strcat(histty, histtya); + } + while (fread((char *)&ubuf, sizeof(ubuf), 1, uf) == 1) { + if (ubuf.ut_name[0] == '\0') + continue; + if (strcmp(ubuf.ut_line, mytty)==0) { + for (i=0; i 1) { + fprintf(stderr, + "write: %s logged in more than once ... writing to %s\n", + him, histty+5); + } +cont: + if (access(histty, 0) < 0) { + fprintf(stderr, "write: No such tty\n"); + exit(1); + } + signal(SIGALRM, timout); + alarm(5); + if ((tf = fopen(histty, "w")) == NULL) { + fprintf(stderr, "write: Permission denied\n"); + exit(1); + } + alarm(0); + sigs(eof); + { char hostname[32]; + gethostname(hostname, sizeof (hostname)); + fprintf(tf, + "\r\nMessage from %s@%s on %s at %d:%02d ...\r\n\007\007\007", + me, hostname, mytty, localclock->tm_hour, localclock->tm_min); + fflush(tf); + } + for (;;) { + char buf[BUFSIZ]; + register char *bp; + i = read(0, buf, sizeof buf); + if (i <= 0) + eof(); + if (buf[0] == '!') { + buf[i] = 0; + ex(buf); + continue; + } + for (bp = buf; --i >= 0; bp++) { + if (*bp == '\n') + putc('\r', tf); + + if (!isascii(*bp)) { + putc('M', tf); + putc('-', tf); + *bp = toascii(*bp); + } + + if (isprint(*bp) || + *bp == ' ' || *bp == '\t' || *bp == '\n') { + putc(*bp, tf); + } else { + putc('^', tf); + putc(*bp ^ 0100, tf); + } + + if (*bp == '\n') + fflush(tf); + + if (ferror(tf) || feof(tf)) { + printf("\n\007Write failed (%s logged out?)\n", + him); + exit(1); + } + } + } +} + +ex(bp) + char *bp; +{ + register i; + + sigs(SIG_IGN); + i = fork(); + if (i < 0) { + printf("Try again\n"); + goto out; + } + if (i == 0) { + fclose(tf); /* Close his terminal */ + setgid(getgid()); /* Give up effective group privs */ + sigs((sig_t) 0); + execl(getenv("SHELL") ? + getenv("SHELL") : "/bin/sh", "sh", "-c", bp+1, 0); + exit(0); + } + while (wait((int *)NULL) != i) + ; + printf("!\n"); +out: + sigs(eof); +} + +sigs(sig) + sig_t sig; +{ + register i; + + for (i=0; signum[i]; i++) + signal(signum[i], sig); +} diff --git a/src/cmd/xargs/Makefile b/src/cmd/xargs/Makefile new file mode 100644 index 0000000..a63bbc3 --- /dev/null +++ b/src/cmd/xargs/Makefile @@ -0,0 +1,39 @@ +# +# Public Domain. 1995/03/13 - Steven Schultz +# +TOPSRC = $(shell cd ../../..; pwd) +include $(TOPSRC)/target.mk + +CFLAGS += -Werror + +SRCS = xargs.c +OBJS = xargs.o +MAN = xargs.0 +MANSRC = xargs.1 + +all: xargs ${MAN} + +xargs: ${OBJS} + ${CC} ${LDFLAGS} -o xargs.elf ${OBJS} ${LIBS} + ${OBJDUMP} -S xargs.elf > xargs.dis + ${SIZE} xargs.elf + ${ELF2AOUT} xargs.elf $@ && rm xargs.elf + +${MAN}: ${MANSRC} + ${MANROFF} ${MANSRC} > ${MAN} + +clean: + rm -f *.o *.elf ${MAN} xargs *.elf *.dis tags *~ + +depend: ${SRCS} + mkdep ${CFLAGS} ${SRCS} + +install: all + install xargs ${DESTDIR}/bin/ + cp xargs.0 ${DESTDIR}/share/man/cat1/ + +lint: ${SRCS} + lint -hax ${SRCS} + +tags: ${SRCS} + ctags ${SRCS} diff --git a/src/cmd/xargs/xargs.1 b/src/cmd/xargs/xargs.1 new file mode 100644 index 0000000..3982a9f --- /dev/null +++ b/src/cmd/xargs/xargs.1 @@ -0,0 +1,169 @@ +.\" 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 +.\" +.TH XARGS 1 "June 6, 1993" +.SH NAME +xargs \- construct argument list(s) and execute utility +.SH SYNOPSIS +.B xargs +[ +.B \-t +][[ +.B \-x +] +.B \-n +.BI number +][ +.B \-s +.BI size +][ +.BI utility +[ +.BI arguments ... +]] +.PP +.SH DESCRIPTION +The +.B xargs +utility reads space, tab, newline and end-of-file delimited arguments +from the standard input and executes the specified +.BI utility +with them as +arguments. +.PP +The utility and any arguments specified on the command line are given +to the +.BI utility +upon each invocation, followed by some number of the arguments read +from standard input. +The +.BI 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: +.TP 10n +.BR \-n " number" +Set the maximum number of arguments taken from standard input for each +invocation of the utility. +An invocation of +.BI utility +will use less than +.BI number +standard input arguments if the number of bytes accumulated (see the +.B s +option) exceeds the specified +.BI size +or there are fewer than +.BI number +arguments remaining for the last invocation of +.BI utility . +The current default value for +.BI number +is 5000. +.TP +.BR \-s " size" +Set the maximum number of bytes for the command line length provided to +.BI utility . +The sum of the length of the utility name and the arguments passed to +.BI utility +(including +.I /dev/null +terminators) will be less than or equal to this number. +The current default value for +.BI size +is +ARG_MAX +- 2048. +.TP +.BR \-t +Echo the command to be executed to standard error immediately before it +is executed. +.TP +.BR \-x +Force +.B xargs +to terminate immediately if a command line containing +.BI number +arguments will not fit in the specified (or default) command line length. +.PP +If no +.BI utility +is specified, +echo(1) +is used. +.PP +Undefined behavior may occur if +.BI utility +reads from the standard input. +.PP +The +.B xargs +utility exits immediately (without processing any further input) if a +command line cannot be assembled, +.BI 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 +.B xargs +utility exits with a value of 0 if no error occurs. +If +.BI utility +cannot be invoked, +.B xargs +exits with a value of 127. +If any other error occurs, +.B xargs +exits with a value of 1. +.SH SEE ALSO +echo(1), find(1) +.PP +.SH STANDARDS +The +.B xargs +utility is expected to be +IEEE Std 1003.2("POSIX") compliant. diff --git a/src/cmd/xargs/xargs.c b/src/cmd/xargs/xargs.c new file mode 100644 index 0000000..18dbac2 --- /dev/null +++ b/src/cmd/xargs/xargs.c @@ -0,0 +1,323 @@ +/*- + * 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. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if __STDC__ +#include +#else +#include +#endif + +/* + * This is defined for pdp11s. ARG_MAX is usually defined in + * an include file. I have left it here until such times as + * the system limits stuff in machparam etc is changed to the + * same names as 4.4. Note that + * this is much smaller than the normal value cos it's only a + * small computer (sigh). + */ + +#define ARG_MAX NCARGS + +int tflag, rval; + +void +#if __STDC__ +fatal(const char *fmt, ...) +#else +fatal(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 */ +} + +void +run(argv) + char **argv; +{ + 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: + fatal("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) + fatal("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); +} + +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) + fatal("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 = + (char **)malloc((u_int)(1 + argc + nargs + 1) * sizeof(char **)))) + fatal("%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) + fatal("insufficient space for command"); + + if (!(bbp = (char *)malloc((u_int)nline + 1))) + fatal("%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) + fatal("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) + fatal("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) + fatal("backslash at EOF"); + /* FALLTHROUGH */ + default: +addch: if (p < ebp) { + *p++ = ch; + break; + } + + /* If only one argument, not enough buffer space. */ + if (bxp == xp) + fatal("insufficient space for argument"); + /* Didn't hit argument limit, so if xflag object. */ + if (xflag) + fatal("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 */ +} diff --git a/src/cmd/yacc/Makefile b/src/cmd/yacc/Makefile new file mode 100644 index 0000000..24f3204 --- /dev/null +++ b/src/cmd/yacc/Makefile @@ -0,0 +1,24 @@ +# +# @(#)Makefile 4.2.1 (2.11BSD) 1996/10/24 +# +DESTDIR= +SEPFLAG= -i +CFLAGS=-O +SRCS = Makefile dextern files yaccpar \ + y1.c y2.c y3.c y4.c \ + yaccdiffs yaccnews + +all: yacc + +yacc: y1.o y2.o y3.o y4.o + $(CC) ${SEPFLAG} -o yacc y?.o +y1.o y2.o y3.o y4.o: dextern files +install: yacc yaccpar + install -s yacc $(DESTDIR)/usr/bin + install -c yaccpar $(DESTDIR)/usr/share/misc +clean : + -rm -f *.o yacc + +srcs: $(SRCS) +$(SRCS): + sccs get $@ diff --git a/src/cmd/yacc/dextern b/src/cmd/yacc/dextern new file mode 100644 index 0000000..295da7a --- /dev/null +++ b/src/cmd/yacc/dextern @@ -0,0 +1,262 @@ +/* + * @(#)dextern 4.2 (Berkeley) 3/21/86 + */ +# include +# include +# include "files" + + /* MANIFEST CONSTANT DEFINITIONS */ + + /* base of nonterminal internal numbers */ +# define NTBASE 010000 + + /* internal codes for error and accept actions */ + +# define ERRCODE 8190 +# define ACCEPTCODE 8191 + + /* sizes and limits */ + +# ifdef HUGE +# define ACTSIZE 12000 +# define MEMSIZE 24000 +# define NSTATES 750 +# define NTERMS 300 +# define NPROD 600 +# define NNONTERM 300 +# define TEMPSIZE 1200 +# define CNAMSZ 5000 +# define LSETSIZE 600 +# define WSETSIZE 350 +# endif + +# ifdef MEDIUM +# define ACTSIZE 4000 +# define MEMSIZE 5200 +# define NSTATES 600 +# define NTERMS 127 +# define NPROD 400 +# define NNONTERM 200 +# define TEMPSIZE 800 +# define CNAMSZ 4000 +# define LSETSIZE 450 +# define WSETSIZE 250 +# endif + +# define NAMESIZE 50 +# define NTYPES 63 + +# ifdef WORD32 +# define TBITSET ((32+NTERMS)/32) + + /* bit packing macros (may be machine dependent) */ +# define BIT(a,i) ((a)[(i)>>5] & (1<<((i)&037))) +# define SETBIT(a,i) ((a)[(i)>>5] |= (1<<((i)&037))) + + /* number of words needed to hold n+1 bits */ +# define NWORDS(n) (((n)+32)/32) + +# else + +# define TBITSET ((16+NTERMS)/16) + + /* bit packing macros (may be machine dependent) */ +# define BIT(a,i) ((a)[(i)>>4] & (1<<((i)&017))) +# define SETBIT(a,i) ((a)[(i)>>4] |= (1<<((i)&017))) + + /* number of words needed to hold n+1 bits */ +# define NWORDS(n) (((n)+16)/16) +# endif + + /* relationships which must hold: + TBITSET ints must hold NTERMS+1 bits... + WSETSIZE >= NNONTERM + LSETSIZE >= NNONTERM + TEMPSIZE >= NTERMS + NNONTERMs + 1 + TEMPSIZE >= NSTATES + */ + + /* associativities */ + +# define NOASC 0 /* no assoc. */ +# define LASC 1 /* left assoc. */ +# define RASC 2 /* right assoc. */ +# define BASC 3 /* binary assoc. */ + + /* flags for state generation */ + +# define DONE 0 +# define MUSTDO 1 +# define MUSTLOOKAHEAD 2 + + /* flags for a rule having an action, and being reduced */ + +# define ACTFLAG 04 +# define REDFLAG 010 + + /* output parser flags */ +# define YYFLAG1 (-1000) + + /* macros for getting associativity and precedence levels */ + +# define ASSOC(i) ((i)&03) +# define PLEVEL(i) (((i)>>4)&077) +# define TYPE(i) ((i>>10)&077) + + /* macros for setting associativity and precedence levels */ + +# define SETASC(i,j) i|=j +# define SETPLEV(i,j) i |= (j<<4) +# define SETTYPE(i,j) i |= (j<<10) + + /* looping macros */ + +# define TLOOP(i) for(i=1;i<=ntokens;++i) +# define NTLOOP(i) for(i=0;i<=nnonter;++i) +# define PLOOP(s,i) for(i=s;i0 ; ++p ) ; + p = prdptr[-*p]; + q = chcopy( sarr, nontrst[*p-NTBASE].name ); + q = chcopy( q, " : " ); + + for(;;){ + *q++ = ++p==pp ? '_' : ' '; + *q = '\0'; + if((i = *p) <= 0) break; + q = chcopy( q, symnam(i) ); + if( q> &sarr[ISIZE-30] ) error( "item too big" ); + } + + if( (i = *pp) < 0 ){ /* an item calling for a reduction */ + q = chcopy( q, " (" ); + sprintf( q, "%d)", -i ); + } + + return( sarr ); + } + +char *symnam(i){ /* return a pointer to the name of symbol i */ + register char *cp; + + cp = (i>=NTBASE) ? nontrst[i-NTBASE].name : tokset[i].name ; + if( *cp == ' ' ) ++cp; + return( cp ); + } + +struct wset *zzcwp = wsets; +int zzgoent = 0; +int zzgobest = 0; +int zzacent = 0; +int zzexcp = 0; +int zzclose = 0; +int zzsrconf = 0; +int * zzmemsz = mem0; +int zzrrconf = 0; + +summary(){ /* output the summary on the tty */ + + if( foutput!=NULL ){ + fprintf( foutput, "\n%d/%d terminals, %d/%d nonterminals\n", ntokens, NTERMS, + nnonter, NNONTERM ); + fprintf( foutput, "%d/%d grammar rules, %d/%d states\n", nprod, NPROD, nstate, NSTATES ); + fprintf( foutput, "%d shift/reduce, %d reduce/reduce conflicts reported\n", zzsrconf, zzrrconf ); + fprintf( foutput, "%d/%d working sets used\n", zzcwp-wsets, WSETSIZE ); + fprintf( foutput, "memory: states,etc. %d/%d, parser %d/%d\n", zzmemsz-mem0, MEMSIZE, + memp-amem, ACTSIZE ); + fprintf( foutput, "%d/%d distinct lookahead sets\n", nlset, LSETSIZE ); + fprintf( foutput, "%d extra closures\n", zzclose - 2*nstate ); + fprintf( foutput, "%d shift entries, %d exceptions\n", zzacent, zzexcp ); + fprintf( foutput, "%d goto entries\n", zzgoent ); + fprintf( foutput, "%d entries saved by goto default\n", zzgobest ); + } + if( zzsrconf!=0 || zzrrconf!=0 ){ + fprintf( stdout,"\nconflicts: "); + if( zzsrconf )fprintf( stdout, "%d shift/reduce" , zzsrconf ); + if( zzsrconf && zzrrconf )fprintf( stdout, ", " ); + if( zzrrconf )fprintf( stdout, "%d reduce/reduce" , zzrrconf ); + fprintf( stdout, "\n" ); + } + + fclose( ftemp ); + if( fdefine != NULL ) fclose( fdefine ); + } + +/* VARARGS1 */ +error(s,a1) char *s; { /* write out error comment */ + + ++nerrors; + fprintf( stderr, "\n fatal error: "); + fprintf( stderr, s,a1); + fprintf( stderr, ", line %d\n", lineno ); + if( !fatfl ) return; + summary(); + exit(1); + } + +aryfil( v, n, c ) int *v,n,c; { /* set elements 0 through n-1 to c */ + register int i; + for( i=0; ilset; + if( pp == 0 ) fprintf( foutput, "\tNULL"); + else { + fprintf( foutput, " { " ); + TLOOP(j) { + if( BIT(pp,j) ) fprintf( foutput, "%s ", symnam(j) ); + } + fprintf( foutput, "}" ); + } + } + +cpres(){ /* compute an array with the beginnings of productions yielding given nonterminals + The array pres points to these lists */ + /* the array pyield has the lists: the total size is only NPROD+1 */ + int **pmem; + register c, j, i; + static int * pyield[NPROD]; + + pmem = pyield; + + NTLOOP(i){ + c = i+NTBASE; + pres[i] = pmem; + fatfl = 0; /* make undefined symbols nonfatal */ + PLOOP(0,j){ + if (*prdptr[j] == c) *pmem++ = prdptr[j]+1; + } + if(pres[i] == pmem){ + error("nonterminal %s not defined!", nontrst[i].name); + } + } + pres[i] = pmem; + fatfl = 1; + if( nerrors ){ + summary(); + exit(1); + } + if( pmem != &pyield[nprod] ) error( "internal Yacc error: pyield %d", pmem-&pyield[nprod] ); + } + +int indebug = 0; +cpfir() { + /* compute an array with the first of nonterminals */ + register *p, **s, i, **t, ch, changes; + + zzcwp = &wsets[nnonter]; + NTLOOP(i){ + aryfil( wsets[i].ws.lset, tbitset, 0 ); + t = pres[i+1]; + for( s=pres[i]; s 0 ; ++p ) { + if( ch < NTBASE ) { + SETBIT( wsets[i].ws.lset, ch ); + break; + } + else if( !pempty[ch-NTBASE] ) break; + } + } + } + + /* now, reflect transitivity */ + + changes = 1; + while( changes ){ + changes = 0; + NTLOOP(i){ + t = pres[i+1]; + for( s=pres[i]; s= 0; ++p ) { + changes |= setunion( wsets[i].ws.lset, wsets[ch].ws.lset ); + if( !pempty[ch] ) break; + } + } + } + } + + NTLOOP(i) pfirst[i] = flset( &wsets[i].ws ); + if( !indebug ) return; + if( (foutput!=NULL) ){ + NTLOOP(i) { + fprintf( foutput, "\n%s: ", nontrst[i].name ); + prlook( pfirst[i] ); + fprintf( foutput, " %d\n", pempty[i] ); + } + } + } + +state(c){ /* sorts last state,and sees if it equals earlier ones. returns state number */ + int size1,size2; + register i; + struct item *p1, *p2, *k, *l, *q1, *q2; + p1 = pstate[nstate]; + p2 = pstate[nstate+1]; + if(p1==p2) return(0); /* null state */ + /* sort the items */ + for(k=p2-1;k>p1;k--) { /* make k the biggest */ + for(l=k-1;l>=p1;--l)if( l->pitem > k->pitem ){ + int *s; + struct looksets *ss; + s = k->pitem; + k->pitem = l->pitem; + l->pitem = s; + ss = k->look; + k->look = l->look; + l->look = ss; + } + } + size1 = p2 - p1; /* size of state */ + + for( i= (c>=NTBASE)?ntstates[c-NTBASE]:tstates[c]; i != 0; i = mstates[i] ) { + /* get ith state */ + q1 = pstate[i]; + q2 = pstate[i+1]; + size2 = q2 - q1; + if (size1 != size2) continue; + k=p1; + for(l=q1;lpitem != k->pitem ) break; + ++k; + } + if (l != q2) continue; + /* found it */ + pstate[nstate+1] = pstate[nstate]; /* delete last state */ + /* fix up lookaheads */ + if( nolook ) return(i); + for( l=q1,k=p1; llook->lset[s]; + if( setunion( clset.lset, k->look->lset ) ) { + tystate[i] = MUSTDO; + /* register the new set */ + l->look = flset( &clset ); + } + } + return (i); + } + /* state is new */ + if( nolook ) error( "yacc state/nolook error" ); + pstate[nstate+2] = p2; + if(nstate+1 >= NSTATES) error("too many states" ); + if( c >= NTBASE ){ + mstates[ nstate ] = ntstates[ c-NTBASE ]; + ntstates[ c-NTBASE ] = nstate; + } + else { + mstates[ nstate ] = tstates[ c ]; + tstates[ c ] = nstate; + } + tystate[nstate]=MUSTDO; + return(nstate++); + } + +int pidebug = 0; /* debugging flag for putitem */ +putitem( ptr, lptr ) int *ptr; struct looksets *lptr; { + register struct item *j; + + if( pidebug && (foutput!=NULL) ) { + fprintf( foutput, "putitem(%s), state %d\n", writem(ptr), nstate ); + } + j = pstate[nstate+1]; + j->pitem = ptr; + if( !nolook ) j->look = flset( lptr ); + pstate[nstate+1] = ++j; + if( (int *)j > zzmemsz ){ + zzmemsz = (int *)j; + if( zzmemsz >= &mem0[MEMSIZE] ) error( "out of state space" ); + } + } + +cempty(){ /* mark nonterminals which derive the empty string */ + /* also, look for nonterminals which don't derive any token strings */ + +# define EMPTY 1 +# define WHOKNOWS 0 +# define OK 1 + + register i, *p; + + /* first, use the array pempty to detect productions that can never be reduced */ + /* set pempty to WHONOWS */ + aryfil( pempty, nnonter+1, WHOKNOWS ); + + /* now, look at productions, marking nonterminals which derive something */ + + more: + PLOOP(0,i){ + if( pempty[ *prdptr[i] - NTBASE ] ) continue; + for( p=prdptr[i]+1; *p>=0; ++p ){ + if( *p>=NTBASE && pempty[ *p-NTBASE ] == WHOKNOWS ) break; + } + if( *p < 0 ){ /* production can be derived */ + pempty[ *prdptr[i]-NTBASE ] = OK; + goto more; + } + } + + /* now, look at the nonterminals, to see if they are all OK */ + + NTLOOP(i){ + /* the added production rises or falls as the start symbol ... */ + if( i == 0 ) continue; + if( pempty[ i ] != OK ) { + fatfl = 0; + error( "nonterminal %s never derives any token string", nontrst[i].name ); + } + } + + if( nerrors ){ + summary(); + exit(1); + } + + /* now, compute the pempty array, to see which nonterminals derive the empty string */ + + /* set pempty to WHOKNOWS */ + + aryfil( pempty, nnonter+1, WHOKNOWS ); + + /* loop as long as we keep finding empty nonterminals */ + +again: + PLOOP(1,i){ + if( pempty[ *prdptr[i]-NTBASE ]==WHOKNOWS ){ /* not known to be empty */ + for( p=prdptr[i]+1; *p>=NTBASE && pempty[*p-NTBASE]==EMPTY ; ++p ) ; + if( *p < 0 ){ /* we have a nontrivially empty nonterminal */ + pempty[*prdptr[i]-NTBASE] = EMPTY; + goto again; /* got one ... try for another */ + } + } + } + + } + +int gsdebug = 0; +stagen(){ /* generate the states */ + + int i, j; + register c; + register struct wset *p, *q; + + /* initialize */ + + nstate = 0; + /* THIS IS FUNNY from the standpoint of portability */ + /* it represents the magic moment when the mem0 array, which has + /* been holding the productions, starts to hold item pointers, of a + /* different type... */ + /* someday, alloc should be used to allocate all this stuff... for now, we + /* accept that if pointers don't fit in integers, there is a problem... */ + + pstate[0] = pstate[1] = (struct item *)mem; + aryfil( clset.lset, tbitset, 0 ); + putitem( prdptr[0]+1, &clset ); + tystate[0] = MUSTDO; + nstate = 1; + pstate[2] = pstate[1]; + + aryfil( amem, ACTSIZE, 0 ); + + /* now, the main state generation loop */ + + more: + SLOOP(i){ + if( tystate[i] != MUSTDO ) continue; + tystate[i] = DONE; + aryfil( temp1, nnonter+1, 0 ); + /* take state i, close it, and do gotos */ + closure(i); + WSLOOP(wsets,p){ /* generate goto's */ + if( p->flag ) continue; + p->flag = 1; + c = *(p->pitem); + if( c <= 1 ) { + if( pstate[i+1]-pstate[i] <= p-wsets ) tystate[i] = MUSTLOOKAHEAD; + continue; + } + /* do a goto on c */ + WSLOOP(p,q){ + if( c == *(q->pitem) ){ /* this item contributes to the goto */ + putitem( q->pitem + 1, &q->ws ); + q->flag = 1; + } + } + if( c < NTBASE ) { + state(c); /* register new state */ + } + else { + temp1[c-NTBASE] = state(c); + } + } + if( gsdebug && (foutput!=NULL) ){ + fprintf( foutput, "%d: ", i ); + NTLOOP(j) { + if( temp1[j] ) fprintf( foutput, "%s %d, ", nontrst[j].name, temp1[j] ); + } + fprintf( foutput, "\n"); + } + indgo[i] = apack( &temp1[1], nnonter-1 ) - 1; + goto more; /* we have done one goto; do some more */ + } + /* no more to do... stop */ + } + +int cldebug = 0; /* debugging flag for closure */ +closure(i){ /* generate the closure of state i */ + + int c, ch, work, k; + register struct wset *u, *v; + int *pi; + int **s, **t; + struct item *q; + register struct item *p; + + ++zzclose; + + /* first, copy kernel of state i to wsets */ + + cwp = wsets; + ITMLOOP(i,p,q){ + cwp->pitem = p->pitem; + cwp->flag = 1; /* this item must get closed */ + SETLOOP(k) cwp->ws.lset[k] = p->look->lset[k]; + WSBUMP(cwp); + } + + /* now, go through the loop, closing each item */ + + work = 1; + while( work ){ + work = 0; + WSLOOP(wsets,u){ + + if( u->flag == 0 ) continue; + c = *(u->pitem); /* dot is before c */ + + if( c < NTBASE ){ + u->flag = 0; + continue; /* only interesting case is where . is before nonterminal */ + } + + /* compute the lookahead */ + aryfil( clset.lset, tbitset, 0 ); + + /* find items involving c */ + + WSLOOP(u,v){ + if( v->flag == 1 && *(pi=v->pitem) == c ){ + v->flag = 0; + if( nolook ) continue; + while( (ch= *++pi)>0 ){ + if( ch < NTBASE ){ /* terminal symbol */ + SETBIT( clset.lset, ch ); + break; + } + /* nonterminal symbol */ + setunion( clset.lset, pfirst[ch-NTBASE]->lset ); + if( !pempty[ch-NTBASE] ) break; + } + if( ch<=0 ) setunion( clset.lset, v->ws.lset ); + } + } + + /* now loop over productions derived from c */ + + c -= NTBASE; /* c is now nonterminal number */ + + t = pres[c+1]; + for( s=pres[c]; spitem == *s ){ /* yes, it is there */ + if( nolook ) goto nexts; + if( setunion( v->ws.lset, clset.lset ) ) v->flag = work = 1; + goto nexts; + } + } + + /* not there; make a new entry */ + if( cwp-wsets+1 >= WSETSIZE ) error( "working set overflow" ); + cwp->pitem = *s; + cwp->flag = 1; + if( !nolook ){ + work = 1; + SETLOOP(k) cwp->ws.lset[k] = clset.lset[k]; + } + WSBUMP(cwp); + + nexts: ; + } + + } + } + + /* have computed closure; flags are reset; return */ + + if( cwp > zzcwp ) zzcwp = cwp; + if( cldebug && (foutput!=NULL) ){ + fprintf( foutput, "\nState %d, nolook = %d\n", i, nolook ); + WSLOOP(wsets,u){ + if( u->flag ) fprintf( foutput, "flag set!\n"); + u->flag = 0; + fprintf( foutput, "\t%s", writem(u->pitem)); + prlook( &u->ws ); + fprintf( foutput, "\n" ); + } + } + } + +struct looksets *flset( p ) struct looksets *p; { + /* decide if the lookahead set pointed to by p is known */ + /* return pointer to a perminent location for the set */ + + register struct looksets *q; + int j, *w; + register *u, *v; + + for( q = &lkst[nlset]; q-- > lkst; ){ + u = p->lset; + v = q->lset; + w = & v[tbitset]; + while( v= LSETSIZE )error("too many lookahead sets" ); + SETLOOP(j){ + q->lset[j] = p->lset[j]; + } + return( q ); + } diff --git a/src/cmd/yacc/y2.c b/src/cmd/yacc/y2.c new file mode 100644 index 0000000..2b58153 --- /dev/null +++ b/src/cmd/yacc/y2.c @@ -0,0 +1,866 @@ +#if !defined(lint) && defined(DOSCCS) +static char sccsid[] = "@(#)y2.c 4.1.1 (2.11BSD) 1995/05/11"; +#endif + +# include "dextern" +# define IDENTIFIER 257 +# define MARK 258 +# define TERM 259 +# define LEFT 260 +# define RIGHT 261 +# define BINARY 262 +# define PREC 263 +# define LCURLY 264 +# define C_IDENTIFIER 265 /* name followed by colon */ +# define NUMBER 266 +# define START 267 +# define TYPEDEF 268 +# define TYPENAME 269 +# define UNION 270 +# define ENDFILE 0 + + /* communication variables between various I/O routines */ + +char *infile; /* input file name */ +int numbval; /* value of an input number */ +char tokname[NAMESIZE]; /* input token name */ + + /* storage of names */ + +char cnames[CNAMSZ]; /* place where token and nonterminal names are stored */ +int cnamsz = CNAMSZ; /* size of cnames */ +char * cnamp = cnames; /* place where next name is to be put in */ +int ndefout = 3; /* number of defined symbols output */ + + /* storage of types */ +int ntypes; /* number of types defined */ +char * typeset[NTYPES]; /* pointers to type tags */ + + /* symbol tables for tokens and nonterminals */ + +int ntokens = 0; +struct toksymb tokset[NTERMS]; +int toklev[NTERMS]; +int nnonter = -1; +struct ntsymb nontrst[NNONTERM]; +int start; /* start symbol */ + + /* assigned token type values */ +int extval = 0; + + /* input and output file descriptors */ + +FILE * finput; /* yacc input file */ +FILE * faction; /* file for saving actions */ +FILE * fdefine; /* file for # defines */ +FILE * ftable; /* y.tab.c file */ +FILE * ftemp; /* tempfile to pass 2 */ +FILE * foutput; /* y.output file */ + + /* storage for grammar rules */ + +int mem0[MEMSIZE] ; /* production storage */ +int *mem = mem0; +int nprod= 1; /* number of productions */ +int *prdptr[NPROD]; /* pointers to descriptions of productions */ +int levprd[NPROD] ; /* precedence levels for the productions */ + + +setup(argc,argv) int argc; char *argv[]; +{ int i,lev, ty; + register int t, j; + int c; + int *p; + char actname[8]; + + foutput = NULL; + fdefine = NULL; + i = 1; + while( argc >= 2 && argv[1][0] == '-' ) { + while( *++(argv[1]) ){ + switch( *argv[1] ){ + case 'v': + case 'V': + foutput = fopen(FILEU, "w" ); + if( foutput == NULL ) error( "cannot open y.output" ); + continue; + case 'D': + case 'd': + fdefine = fopen( FILED, "w" ); + continue; + case 'o': + case 'O': + fprintf( stderr, "`o' flag now default in yacc\n" ); + continue; + + case 'r': + case 'R': + error( "Ratfor Yacc is dead: sorry...\n" ); + + default: + error( "illegal option: %c", *argv[1]); + } + } + argv++; + argc--; + } + + ftable = fopen( OFILE, "w" ); + if( ftable == NULL ) error( "cannot open table file" ); + + ftemp = fopen( TEMPNAME, "w" ); + faction = fopen( ACTNAME, "w" ); + if( ftemp==NULL || faction==NULL ) error( "cannot open temp file" ); + + if( argc < 2 || ((finput=fopen( infile=argv[1], "r" )) == NULL ) ){ + error( "cannot open input file" ); + } + + cnamp = cnames; + defin(0,"$end"); + extval = 0400; + defin(0,"error"); + defin(1,"$accept"); + mem=mem0; + lev = 0; + ty = 0; + i=0; + + /* sorry -- no yacc parser here..... + we must bootstrap somehow... */ + + for( t=gettok(); t!=MARK && t!= ENDFILE; ){ + switch( t ){ + + case ';': + t = gettok(); + break; + + case START: + if( (t=gettok()) != IDENTIFIER ){ + error( "bad %%start construction" ); + } + start = chfind(1,tokname); + t = gettok(); + continue; + + case TYPEDEF: + if( (t=gettok()) != TYPENAME ) error( "bad syntax in %%type" ); + ty = numbval; + for(;;){ + t = gettok(); + switch( t ){ + + case IDENTIFIER: + if( (t=chfind( 1, tokname ) ) < NTBASE ) { + j = TYPE( toklev[t] ); + if( j!= 0 && j != ty ){ + error( "type redeclaration of token %s", + tokset[t].name ); + } + else SETTYPE( toklev[t],ty); + } + else { + j = nontrst[t-NTBASE].tvalue; + if( j != 0 && j != ty ){ + error( "type redeclaration of nonterminal %s", + nontrst[t-NTBASE].name ); + } + else nontrst[t-NTBASE].tvalue = ty; + } + case ',': + continue; + + case ';': + t = gettok(); + break; + default: + break; + } + break; + } + continue; + + case UNION: + /* copy the union declaration to the output */ + cpyunion(); + t = gettok(); + continue; + + case LEFT: + case BINARY: + case RIGHT: + ++i; + case TERM: + lev = t-TERM; /* nonzero means new prec. and assoc. */ + ty = 0; + + /* get identifiers so defined */ + + t = gettok(); + if( t == TYPENAME ){ /* there is a type defined */ + ty = numbval; + t = gettok(); + } + + for(;;) { + switch( t ){ + + case ',': + t = gettok(); + continue; + + case ';': + break; + + case IDENTIFIER: + j = chfind(0,tokname); + if( lev ){ + if( ASSOC(toklev[j]) ) error( "redeclaration of precedence of %s", tokname ); + SETASC(toklev[j],lev); + SETPLEV(toklev[j],i); + } + if( ty ){ + if( TYPE(toklev[j]) ) error( "redeclaration of type of %s", tokname ); + SETTYPE(toklev[j],ty); + } + if( (t=gettok()) == NUMBER ){ + tokset[j].value = numbval; + if( j < ndefout && j>2 ){ + error( "please define type number of %s earlier", + tokset[j].name ); + } + t=gettok(); + } + continue; + + } + + break; + } + + continue; + + case LCURLY: + defout(); + cpycode(); + t = gettok(); + continue; + + default: + error( "syntax error" ); + + } + + } + + if( t == ENDFILE ){ + error( "unexpected EOF before %%" ); + } + + /* t is MARK */ + + defout(); + + fprintf( ftable, "#define yyclearin yychar = -1\n" ); + fprintf( ftable, "#define yyerrok yyerrflag = 0\n" ); + fprintf( ftable, "extern int yychar;\nextern short yyerrflag;\n" ); + fprintf( ftable, "#ifndef YYMAXDEPTH\n#define YYMAXDEPTH 150\n#endif\n" ); + if( !ntypes ) fprintf( ftable, "#ifndef YYSTYPE\n#define YYSTYPE int\n#endif\n" ); + fprintf( ftable, "YYSTYPE yylval, yyval;\n" ); + + prdptr[0]=mem; + /* added production */ + *mem++ = NTBASE; + *mem++ = start; /* if start is 0, we will overwrite with the lhs of the first rule */ + *mem++ = 1; + *mem++ = 0; + prdptr[1]=mem; + + while( (t=gettok()) == LCURLY ) cpycode(); + + if( t != C_IDENTIFIER ) error( "bad syntax on first rule" ); + + if( !start ) prdptr[0][1] = chfind(1,tokname); + + /* read rules */ + + while( t!=MARK && t!=ENDFILE ){ + + /* process a rule */ + + if( t == '|' ){ + *mem++ = *prdptr[nprod-1]; + } + else if( t == C_IDENTIFIER ){ + *mem = chfind(1,tokname); + if( *mem < NTBASE ) error( "token illegal on LHS of grammar rule" ); + ++mem; + } + else error( "illegal rule: missing semicolon or | ?" ); + + /* read rule body */ + + + t = gettok(); + more_rule: + while( t == IDENTIFIER ) { + *mem = chfind(1,tokname); + if( *mem=NTBASE)error("nonterminal %s illegal after %%prec", nontrst[j-NTBASE].name); + levprd[nprod]=toklev[j]; + t = gettok(); + } + + if( t == '=' ){ + levprd[nprod] |= ACTFLAG; + fprintf( faction, "\ncase %d:", nprod ); + cpyact( mem-prdptr[nprod]-1 ); + fprintf( faction, " break;" ); + if( (t=gettok()) == IDENTIFIER ){ + /* action within rule... */ + + sprintf( actname, "$$%d", nprod ); + j = chfind(1,actname); /* make it a nonterminal */ + + /* the current rule will become rule number nprod+1 */ + /* move the contents down, and make room for the null */ + + for( p=mem; p>=prdptr[nprod]; --p ) p[2] = *p; + mem += 2; + + /* enter null production for action */ + + p = prdptr[nprod]; + + *p++ = j; + *p++ = -nprod; + + /* update the production information */ + + levprd[nprod+1] = levprd[nprod] & ~ACTFLAG; + levprd[nprod] = ACTFLAG; + + if( ++nprod >= NPROD ) error( "more than %d rules", NPROD ); + prdptr[nprod] = p; + + /* make the action appear in the original rule */ + *mem++ = j; + + /* get some more of the rule */ + + goto more_rule; + } + + } + + while( t == ';' ) t = gettok(); + + *mem++ = -nprod; + + /* check that default action is reasonable */ + + if( ntypes && !(levprd[nprod]&ACTFLAG) && nontrst[*prdptr[nprod]-NTBASE].tvalue ){ + /* no explicit action, LHS has value */ + register tempty; + tempty = prdptr[nprod][1]; + if( tempty < 0 ) error( "must return a value, since LHS has a type" ); + else if( tempty >= NTBASE ) tempty = nontrst[tempty-NTBASE].tvalue; + else tempty = TYPE( toklev[tempty] ); + if( tempty != nontrst[*prdptr[nprod]-NTBASE].tvalue ){ + error( "default action causes potential type clash" ); + } + } + + if( ++nprod >= NPROD ) error( "more than %d rules", NPROD ); + prdptr[nprod] = mem; + levprd[nprod]=0; + + } + + /* end of all rules */ + + finact(); + if( t == MARK ){ + fprintf( ftable, "\n# line %d \"%s\"\n", lineno, infile ); + while( (c=getc(finput)) != EOF ) putc( c, ftable ); + } + fclose( finput ); + } + +finact(){ + /* finish action routine */ + + fclose(faction); + + fprintf( ftable, "# define YYERRCODE %d\n", tokset[2].value ); + + } + +defin( t, s ) register char *s; { +/* define s to be a terminal if t=0 + or a nonterminal if t=1 */ + + register val; + + if (t) { + if( ++nnonter >= NNONTERM ) error("too many nonterminals, limit %d",NNONTERM); + nontrst[nnonter].name = cstash(s); + return( NTBASE + nnonter ); + } + /* must be a token */ + if( ++ntokens >= NTERMS ) error("too many terminals, limit %d",NTERMS ); + tokset[ntokens].name = cstash(s); + + /* establish value for token */ + + if( s[0]==' ' && s[2]=='\0' ) /* single character literal */ + val = s[1]; + else if ( s[0]==' ' && s[1]=='\\' ) { /* escape sequence */ + if( s[3] == '\0' ){ /* single character escape sequence */ + switch ( s[2] ){ + /* character which is escaped */ + case 'n': val = '\n'; break; + case 'r': val = '\r'; break; + case 'b': val = '\b'; break; + case 't': val = '\t'; break; + case 'f': val = '\f'; break; + case '\'': val = '\''; break; + case '"': val = '"'; break; + case '\\': val = '\\'; break; + default: error( "invalid escape" ); + } + } + else if( s[2] <= '7' && s[2]>='0' ){ /* \nnn sequence */ + if( s[3]<'0' || s[3] > '7' || s[4]<'0' || + s[4]>'7' || s[5] != '\0' ) error("illegal \\nnn construction" ); + val = 64*s[2] + 8*s[3] + s[4] - 73*'0'; + if( val == 0 ) error( "'\\000' is illegal" ); + } + } + else { + val = extval++; + } + tokset[ntokens].value = val; + toklev[ntokens] = 0; + return( ntokens ); + } + +defout(){ /* write out the defines (at the end of the declaration section) */ + + register int i, c; + register char *cp; + + for( i=ndefout; i<=ntokens; ++i ){ + + cp = tokset[i].name; + if( *cp == ' ' ) ++cp; /* literals */ + + for( ; (c= *cp)!='\0'; ++cp ){ + + if( islower(c) || isupper(c) || isdigit(c) || c=='_' ); /* VOID */ + else goto nodef; + } + + fprintf( ftable, "# define %s %d\n", tokset[i].name, tokset[i].value ); + if( fdefine != NULL ) fprintf( fdefine, "# define %s %d\n", tokset[i].name, tokset[i].value ); + + nodef: ; + } + + ndefout = ntokens+1; + + } + +char * +cstash( s ) register char *s; { + char *temp; + + temp = cnamp; + do { + if( cnamp >= &cnames[cnamsz] ) error("too many characters in id's and literals" ); + else *cnamp++ = *s; + } while ( *s++ ); + return( temp ); + } + +gettok() { + register i, base; + static int peekline; /* number of '\n' seen in lookahead */ + register c, match, reserve; + +begin: + reserve = 0; + lineno += peekline; + peekline = 0; + c = getc(finput); + while( c==' ' || c=='\n' || c=='\t' || c=='\f' ){ + if( c == '\n' ) ++lineno; + c=getc(finput); + } + if( c == '/' ){ /* skip comment */ + lineno += skipcom(); + goto begin; + } + + switch(c){ + + case EOF: + return(ENDFILE); + case '{': + ungetc( c, finput ); + return( '=' ); /* action ... */ + case '<': /* get, and look up, a type name (union member name) */ + i = 0; + while( (c=getc(finput)) != '>' && c>=0 && c!= '\n' ){ + tokname[i] = c; + if( ++i >= NAMESIZE ) --i; + } + if( c != '>' ) error( "unterminated < ... > clause" ); + tokname[i] = '\0'; + for( i=1; i<=ntypes; ++i ){ + if( !strcmp( typeset[i], tokname ) ){ + numbval = i; + return( TYPENAME ); + } + } + typeset[numbval = ++ntypes] = cstash( tokname ); + return( TYPENAME ); + + case '"': + case '\'': + match = c; + tokname[0] = ' '; + i = 1; + for(;;){ + c = getc(finput); + if( c == '\n' || c == EOF ) + error("illegal or missing ' or \"" ); + if( c == '\\' ){ + c = getc(finput); + tokname[i] = '\\'; + if( ++i >= NAMESIZE ) --i; + } + else if( c == match ) break; + tokname[i] = c; + if( ++i >= NAMESIZE ) --i; + } + break; + + case '%': + case '\\': + + switch(c=getc(finput)) { + + case '0': return(TERM); + case '<': return(LEFT); + case '2': return(BINARY); + case '>': return(RIGHT); + case '%': + case '\\': return(MARK); + case '=': return(PREC); + case '{': return(LCURLY); + default: reserve = 1; + } + + default: + + if( isdigit(c) ){ /* number */ + numbval = c-'0' ; + base = (c=='0') ? 8 : 10 ; + for( c=getc(finput); isdigit(c) ; c=getc(finput) ){ + numbval = numbval*base + c - '0'; + } + ungetc( c, finput ); + return(NUMBER); + } + else if( islower(c) || isupper(c) || c=='_' || c=='.' || c=='$' ){ + i = 0; + while( islower(c) || isupper(c) || isdigit(c) || c=='_' || c=='.' || c=='$' ){ + tokname[i] = c; + if( reserve && isupper(c) ) tokname[i] += 'a'-'A'; + if( ++i >= NAMESIZE ) --i; + c = getc(finput); + } + } + else return(c); + + ungetc( c, finput ); + } + + tokname[i] = '\0'; + + if( reserve ){ /* find a reserved word */ + if( !strcmp(tokname,"term")) return( TERM ); + if( !strcmp(tokname,"token")) return( TERM ); + if( !strcmp(tokname,"left")) return( LEFT ); + if( !strcmp(tokname,"nonassoc")) return( BINARY ); + if( !strcmp(tokname,"binary")) return( BINARY ); + if( !strcmp(tokname,"right")) return( RIGHT ); + if( !strcmp(tokname,"prec")) return( PREC ); + if( !strcmp(tokname,"start")) return( START ); + if( !strcmp(tokname,"type")) return( TYPEDEF ); + if( !strcmp(tokname,"union")) return( UNION ); + error("invalid escape, or illegal reserved word: %s", tokname ); + } + + /* look ahead to distinguish IDENTIFIER from C_IDENTIFIER */ + + c = getc(finput); + while( c==' ' || c=='\t'|| c=='\n' || c=='\f' || c== '/' ) { + if( c == '\n' ) ++peekline; + else if( c == '/' ){ /* look for comments */ + peekline += skipcom(); + } + c = getc(finput); + } + if( c == ':' ) return( C_IDENTIFIER ); + ungetc( c, finput ); + return( IDENTIFIER ); +} + +fdtype( t ){ /* determine the type of a symbol */ + register v; + + if( t >= NTBASE ) v = nontrst[t-NTBASE].tvalue; + else v = TYPE( toklev[t] ); + if( v <= 0 ) error( "must specify type for %s", (t>=NTBASE)?nontrst[t-NTBASE].name: + tokset[t].name ); + return( v ); + } + +chfind( t, s ) register char *s; { + int i; + + if (s[0]==' ')t=0; + TLOOP(i){ + if(!strcmp(s,tokset[i].name)){ + return( i ); + } + } + NTLOOP(i){ + if(!strcmp(s,nontrst[i].name)) { + return( i+NTBASE ); + } + } + /* cannot find name */ + if( t>1 ) + error( "%s should have been defined earlier", s ); + return( defin( t, s ) ); + } + +cpyunion(){ + /* copy the union declaration to the output, and the define file if present */ + + int level, c; + fprintf( ftable, "\n# line %d \"%s\"\n", lineno, infile ); + fprintf( ftable, "typedef union " ); + if( fdefine ) fprintf( fdefine, "\ntypedef union " ); + + level = 0; + for(;;){ + if( (c=getc(finput)) < 0 ) error( "EOF encountered while processing %%union" ); + putc( c, ftable ); + if( fdefine ) putc( c, fdefine ); + + switch( c ){ + + case '\n': + ++lineno; + break; + + case '{': + ++level; + break; + + case '}': + --level; + if( level == 0 ) { /* we are finished copying */ + fprintf( ftable, " YYSTYPE;\n" ); + if( fdefine ) fprintf( fdefine, " YYSTYPE;\nextern YYSTYPE yylval;\n" ); + return; + } + } + } + } + +cpycode(){ /* copies code between \{ and \} */ + register int c; + + c = getc(finput); + if( c == '\n' ) { + c = getc(finput); + lineno++; + } + fprintf( ftable, "\n# line %d \"%s\"\n", lineno, infile ); + while( c>=0 ){ + if( c=='\\' ) + if( (c=getc(finput)) == '}' ) return; + else putc('\\', ftable ); + if( c=='%' ) + if( (c=getc(finput)) == '}' ) return; + else putc('%', ftable ); + putc( c , ftable ); + if( c == '\n' ) ++lineno; + c = getc(finput); + } + error("eof before %%}" ); + } + +skipcom(){ /* skip over comments */ + register int c, i=0; /* i is the number of lines skipped */ + + /* skipcom is called after reading a / */ + + if( getc(finput) != '*' ) error( "illegal comment" ); + c = getc(finput); + while( c != EOF ){ + while( c == '*' ){ + if( (c=getc(finput)) == '/' ) return( i ); + } + if( c == '\n' ) ++i; + c = getc(finput); + } + error( "EOF inside comment" ); + /* NOTREACHED */ + } + +cpyact(offset){ /* copy C action to the next ; or closing } */ + register int c; + int brac, match, j, s, tok; + + fprintf( faction, "\n# line %d \"%s\"\n", lineno, infile ); + + brac = 0; + +loop: + c = getc(finput); +swt: + switch( c ){ + +case ';': + if( brac == 0 ){ + putc( c , faction ); + return; + } + goto lcopy; + +case '{': + brac++; + goto lcopy; + +case '$': + s = 1; + tok = -1; + c = getc(finput); + if( c == '<' ){ /* type description */ + ungetc( c, finput ); + if( gettok() != TYPENAME ) error( "bad syntax on $ clause" ); + tok = numbval; + c = getc(finput); + } + if( c == '$' ){ + fprintf( faction, "yyval"); + if( ntypes ){ /* put out the proper tag... */ + if( tok < 0 ) tok = fdtype( *prdptr[nprod] ); + fprintf( faction, ".%s", typeset[tok] ); + } + goto loop; + } + if( c == '-' ){ + s = -s; + c = getc(finput); + } + if( isdigit(c) ){ + j=0; + while( isdigit(c) ){ + j= j*10+c-'0'; + c = getc(finput); + } + + j = j*s - offset; + if( j > 0 ){ + error( "Illegal use of $%d", j+offset ); + } + + fprintf( faction, "yypvt[-%d]", -j ); + if( ntypes ){ /* put out the proper tag */ + if( j+offset <= 0 && tok < 0 ) error( "must specify type of $%d", j+offset ); + if( tok < 0 ) tok = fdtype( prdptr[nprod][j+offset] ); + fprintf( faction, ".%s", typeset[tok] ); + } + goto swt; + } + putc( '$' , faction ); + if( s<0 ) putc('-', faction ); + goto swt; + +case '}': + if( --brac ) goto lcopy; + putc( c, faction ); + return; + + +case '/': /* look for comments */ + putc( c , faction ); + c = getc(finput); + if( c != '*' ) goto swt; + + /* it really is a comment */ + + putc( c , faction ); + c = getc(finput); + while( c != EOF ){ + while( c=='*' ){ + putc( c , faction ); + if( (c=getc(finput)) == '/' ) goto lcopy; + } + putc( c , faction ); + if( c == '\n' )++lineno; + c = getc(finput); + } + error( "EOF inside comment" ); + +case '\'': /* character constant */ + match = '\''; + goto string; + +case '"': /* character string */ + match = '"'; + + string: + + putc( c , faction ); + while( c=getc(finput) ){ + + if( c=='\\' ){ + putc( c , faction ); + c=getc(finput); + if( c == '\n' ) ++lineno; + } + else if( c==match ) goto lcopy; + else if( c=='\n' ) error( "newline in string or char. const." ); + putc( c , faction ); + } + error( "EOF in string or character constant" ); + +case EOF: + error("action does not terminate" ); + +case '\n': ++lineno; + goto lcopy; + + } + +lcopy: + putc( c , faction ); + goto loop; + } diff --git a/src/cmd/yacc/y3.c b/src/cmd/yacc/y3.c new file mode 100644 index 0000000..4375231 --- /dev/null +++ b/src/cmd/yacc/y3.c @@ -0,0 +1,413 @@ +#if !defined(lint) && defined(DOSCCS) +static char sccsid[] = "@(#)y3.c 4.1.1 (2.11BSD) 1995/05/11"; +#endif + +# include "dextern" + + /* important local variables */ +int lastred; /* the number of the last reduction of a state */ +int defact[NSTATES]; /* the default actions of states */ + +output(){ /* print the output for the states */ + + int i, k; + register int c; + register struct wset *u, *v; + + fprintf( ftable, "short yyexca[] ={\n" ); + + SLOOP(i) { /* output the stuff for state i */ + nolook = !(tystate[i]==MUSTLOOKAHEAD); + closure(i); + /* output actions */ + nolook = 1; + aryfil( temp1, ntokens+nnonter+1, 0 ); + WSLOOP(wsets,u){ + c = *( u->pitem ); + if( c>1 && cpitem) ) putitem( v->pitem+1, (struct looksets *)0 ); + } + temp1[c] = state(c); + } + else if( c > NTBASE && temp1[ (c -= NTBASE) + ntokens ] == 0 ){ + temp1[ c+ntokens ] = amem[indgo[i]+c]; + } + } + + if( i == 1 ) temp1[1] = ACCEPTCODE; + + /* now, we have the shifts; look at the reductions */ + + lastred = 0; + WSLOOP(wsets,u){ + c = *( u->pitem ); + if( c<=0 ){ /* reduction */ + lastred = -c; + TLOOP(k){ + if( BIT(u->ws.lset,k) ){ + if( temp1[k] == 0 ) temp1[k] = c; + else if( temp1[k]<0 ){ /* reduce/reduce conflict */ + if( foutput!=NULL ) + fprintf( foutput, + "\n%d: reduce/reduce conflict (red'ns %d and %d ) on %s", + i, -temp1[k], lastred, symnam(k) ); + if( -temp1[k] > lastred ) temp1[k] = -lastred; + ++zzrrconf; + } + else { /* potential shift/reduce conflict */ + precftn( lastred, k, i ); + } + } + } + } + } + wract(i); + } + + fprintf( ftable, "\t};\n" ); + + wdef( "YYNPROD", nprod ); + + } + +int pkdebug = 0; +apack(p, n ) int *p;{ /* pack state i from temp1 into amem */ + int off; + register *pp, *qq, *rr; + int *q, *r; + + /* we don't need to worry about checking because we + we will only look entries known to be there... */ + + /* eliminate leading and trailing 0's */ + + q = p+n; + for( pp=p,off=0 ; *pp==0 && pp<=q; ++pp,--off ) /* VOID */ ; + if( pp > q ) return(0); /* no actions */ + p = pp; + + /* now, find a place for the elements from p to q, inclusive */ + + r = &amem[ACTSIZE-1]; + for( rr=amem; rr<=r; ++rr,++off ){ /* try rr */ + for( qq=rr,pp=p ; pp<=q ; ++pp,++qq){ + if( *pp != 0 ){ + if( *pp != *qq && *qq != 0 ) goto nextk; + } + } + + /* we have found an acceptable k */ + + if( pkdebug && foutput!=NULL ) fprintf( foutput, "off = %d, k = %d\n", off, rr-amem ); + + for( qq=rr,pp=p; pp<=q; ++pp,++qq ){ + if( *pp ){ + if( qq > r ) error( "action table overflow" ); + if( qq>memp ) memp = qq; + *qq = *pp; + } + } + if( pkdebug && foutput!=NULL ){ + for( pp=amem; pp<= memp; pp+=10 ){ + fprintf( foutput, "\t"); + for( qq=pp; qq<=pp+9; ++qq ) fprintf( foutput, "%d ", *qq ); + fprintf( foutput, "\n"); + } + } + return( off ); + + nextk: ; + } + error("no space in action table" ); + /* NOTREACHED */ + } + +go2out(){ /* output the gotos for the nontermninals */ + register int i, j, k; + int best, count, cbest, times; + + fprintf( ftemp, "$\n" ); /* mark begining of gotos */ + + for( i=1; i<=nnonter; ++i ) { + go2gen(i); + + /* find the best one to make default */ + + best = -1; + times = 0; + + for( j=0; j<=nstate; ++j ){ /* is j the most frequent */ + if( tystate[j] == 0 ) continue; + if( tystate[j] == best ) continue; + + /* is tystate[j] the most frequent */ + + count = 0; + cbest = tystate[j]; + + for( k=j; k<=nstate; ++k ) if( tystate[k]==cbest ) ++count; + + if( count > times ){ + best = cbest; + times = count; + } + } + + /* best is now the default entry */ + + zzgobest += (times-1); + for( j=0; j<=nstate; ++j ){ + if( tystate[j] != 0 && tystate[j]!=best ){ + fprintf( ftemp, "%d,%d,", j, tystate[j] ); + zzgoent += 1; + } + } + + /* now, the default */ + + zzgoent += 1; + fprintf( ftemp, "%d\n", best ); + + } + + + + } + +int g2debug = 0; +go2gen(c){ /* output the gotos for nonterminal c */ + + register int i, cc; + int work; + struct item *p, *q; + + + /* first, find nonterminals with gotos on c */ + + aryfil( temp1, nnonter+1, 0 ); + temp1[c] = 1; + + work = 1; + while( work ){ + work = 0; + PLOOP(0,i){ + if( (cc=prdptr[i][1]-NTBASE) >= 0 ){ /* cc is a nonterminal */ + if( temp1[cc] != 0 ){ /* cc has a goto on c */ + cc = *prdptr[i]-NTBASE; /* thus, the left side of production i does too */ + if( temp1[cc] == 0 ){ + work = 1; + temp1[cc] = 1; + } + } + } + } + } + + /* now, we have temp1[c] = 1 if a goto on c in closure of cc */ + + if( g2debug && foutput!=NULL ){ + fprintf( foutput, "%s: gotos on ", nontrst[c].name ); + NTLOOP(i) if( temp1[i] ) fprintf( foutput, "%s ", nontrst[i].name); + fprintf( foutput, "\n"); + } + + /* now, go through and put gotos into tystate */ + + aryfil( tystate, nstate, 0 ); + SLOOP(i){ + ITMLOOP(i,p,q){ + if( (cc= *p->pitem) >= NTBASE ){ + if( temp1[cc -= NTBASE] ){ /* goto on c is possible */ + tystate[i] = amem[indgo[i]+c]; + break; + } + } + } + } + } + +precftn(r,t,s) register int t; + { /* decide a shift/reduce conflict by precedence. + /* r is a rule number, t a token number */ + /* the conflict is in state s */ + /* temp1[t] is changed to reflect the action */ + + int lp,lt, action; + + lp = levprd[r]; + lt = toklev[t]; + if( PLEVEL(lt) == 0 || PLEVEL(lp) == 0 ) { + /* conflict */ + if( foutput != NULL ) fprintf( foutput, "\n%d: shift/reduce conflict (shift %d, red'n %d) on %s", + s, temp1[t], r, symnam(t) ); + ++zzsrconf; + return; + } + if( PLEVEL(lt) == PLEVEL(lp) ) action = ASSOC(lt); + else if( PLEVEL(lt) > PLEVEL(lp) ) action = RASC; /* shift */ + else action = LASC; /* reduce */ + + switch( action ){ + + case BASC: /* error action */ + temp1[t] = ERRCODE; + return; + + case LASC: /* reduce */ + temp1[t] = -r; + return; + + } + } + +wract(i) register int i; { /* output state i */ + /* temp1 has the actions, lastred the default */ + int p, p0, p1; + int ntimes, tred, count; + register int j; + int flag; + + /* find the best choice for lastred */ + + lastred = 0; + ntimes = 0; + TLOOP(j){ + if( temp1[j] >= 0 ) continue; + if( temp1[j]+lastred == 0 ) continue; + /* count the number of appearances of temp1[j] */ + count = 0; + tred = -temp1[j]; + levprd[tred] |= REDFLAG; + TLOOP(p){ + if( temp1[p]+tred == 0 ) ++count; + } + if( count >ntimes ){ + lastred = tred; + ntimes = count; + } + } + + /* for error recovery, arrange that, if there is a shift on the + /* error recovery token, `error', that the default be the error action */ + if( temp1[1] > 0 ) lastred = 0; + + /* clear out entries in temp1 which equal lastred */ + TLOOP(p) if( temp1[p]+lastred == 0 )temp1[p]=0; + + wrstate(i); + defact[i] = lastred; + + flag = 0; + TLOOP(p0){ + if( (p1=temp1[p0])!=0 ) { + if( p1 < 0 ){ + p1 = -p1; + goto exc; + } + else if( p1 == ACCEPTCODE ) { + p1 = -1; + goto exc; + } + else if( p1 == ERRCODE ) { + p1 = 0; + goto exc; + exc: + if( flag++ == 0 ) fprintf( ftable, "-1, %d,\n", i ); + fprintf( ftable, "\t%d, %d,\n", tokset[p0].value, p1 ); + ++zzexcp; + } + else { + fprintf( ftemp, "%d,%d,", tokset[p0].value, p1 ); + ++zzacent; + } + } + } + if( flag ) { + defact[i] = -2; + fprintf( ftable, "\t-2, %d,\n", lastred ); + } + fprintf( ftemp, "\n" ); + return; + } + +wrstate(i){ /* writes state i */ + register j0,j1; + register struct item *pp, *qq; + register struct wset *u; + + if( foutput == NULL ) return; + fprintf( foutput, "\nstate %d\n",i); + ITMLOOP(i,pp,qq) fprintf( foutput, "\t%s\n", writem(pp->pitem)); + if( tystate[i] == MUSTLOOKAHEAD ){ + /* print out empty productions in closure */ + WSLOOP( wsets+(pstate[i+1]-pstate[i]), u ){ + if( *(u->pitem) < 0 ) fprintf( foutput, "\t%s\n", writem(u->pitem) ); + } + } + + /* check for state equal to another */ + + TLOOP(j0) if( (j1=temp1[j0]) != 0 ){ + fprintf( foutput, "\n\t%s ", symnam(j0) ); + if( j1>0 ){ /* shift, error, or accept */ + if( j1 == ACCEPTCODE ) fprintf( foutput, "accept" ); + else if( j1 == ERRCODE ) fprintf( foutput, "error" ); + else fprintf( foutput, "shift %d", j1 ); + } + else fprintf( foutput, "reduce %d",-j1 ); + } + + /* output the final production */ + + if( lastred ) fprintf( foutput, "\n\t. reduce %d\n\n", lastred ); + else fprintf( foutput, "\n\t. error\n\n" ); + + /* now, output nonterminal actions */ + + j1 = ntokens; + for( j0 = 1; j0 <= nnonter; ++j0 ){ + if( temp1[++j1] ) fprintf( foutput, "\t%s goto %d\n", symnam( j0+NTBASE), temp1[j1] ); + } + + } + +wdef( s, n ) char *s; { /* output a definition of s to the value n */ + fprintf( ftable, "# define %s %d\n", s, n ); + } + +warray( s, v, n ) char *s; int *v, n; { + + register i; + + fprintf( ftable, "short %s[]={\n", s ); + for( i=0; i j ) j = *p; + if( *p < k ) k = *p; + } + if( k <= j ){ /* nontrivial situation */ + /* temporarily, kill this for compatibility + j -= k; /* j is now the range */ + if( k > maxoff ) maxoff = k; + } + greed[i] = (yypact[i+1]-yypact[i]) + 2*j; + if( j > maxspr ) maxspr = j; + } + + /* initialize ggreed table */ + + for( i=1; i<=nnonter; ++i ){ + ggreed[i] = 1; + j = 0; + /* minimum entry index is always 0 */ + q = mem + yypgo[i+1] -1; + for( p = mem+yypgo[i]; p j ) j = *p; + } + ggreed[i] = ggreed[i] + 2*j; + if( j > maxoff ) maxoff = j; + } + + + /* now, prepare to put the shift actions into the a array */ + + for( i=0; i1 ) fprintf( ftable, "State %d: null\n", i ); + pa[i] = YYFLAG1; + } + + while( (i = nxti()) != NOMORE ) { + if( i >= 0 ) stin(i); + else gin(-i); + + } + + if( adb>2 ){ /* print a array */ + for( p=a; p <= maxa; p += 10){ + fprintf( ftable, "%4d ", p-a ); + for( i=0; i<10; ++i ) fprintf( ftable, "%4d ", p[i] ); + fprintf( ftable, "\n" ); + } + } + /* write out the output appropriate to the language */ + + aoutput(); + + osummary(); + ZAPFILE(TEMPNAME); + } + +gin(i){ + + register *p, *r, *s, *q1, *q2; + + /* enter gotos on nonterminal i into array a */ + + ggreed[i] = 0; + + q2 = mem+ yypgo[i+1] - 1; + q1 = mem + yypgo[i]; + + /* now, find a place for it */ + + for( p=a; p < &a[ACTSIZE]; ++p ){ + if( *p ) continue; + for( r=q1; r maxa ){ + if( (maxa=s) > &a[ACTSIZE] ) error( "a array overflow" ); + } + } + /* we have found a spot */ + + *p = *q2; + if( p > maxa ){ + if( (maxa=p) > &a[ACTSIZE] ) error( "a array overflow" ); + } + for( r=q1; r1 ) fprintf( ftable, "Nonterminal %d, entry at %d\n" , i, pgo[i] ); + goto nextgi; + + nextgp: ; + } + + error( "cannot place goto %d\n", i ); + + nextgi: ; + } + +stin(i){ + register *r, *s, n, flag, j, *q1, *q2; + + greed[i] = 0; + + /* enter state i into the a array */ + + q2 = mem+yypact[i+1]; + q1 = mem+yypact[i]; + /* find an acceptable place */ + + for( n= -maxoff; n1 ) fprintf( ftable, "State %d: entry at %d equals state %d\n", + i, n, j ); + return; + } + goto nextn; /* we have some disagreement */ + } + } + + for( r = q1; r < q2; r += 2 ){ + if( (s = *r + n + a ) >= &a[ACTSIZE] ) error( "out of space in optimizer a array" ); + if( s > maxa ) maxa = s; + if( *s != 0 && *s != r[1] ) error( "clobber of a array, pos'n %d, by %d", s-a, r[1] ); + *s = r[1]; + } + pa[i] = n; + if( adb>1 ) fprintf( ftable, "State %d: entry at %d\n", i, pa[i] ); + return; + + nextn: ; + } + + error( "Error; failure to place state %d\n", i ); + + } + +nxti(){ /* finds the next i */ + register i, max, maxi; + + max = 0; + + for( i=1; i<= nnonter; ++i ) if( ggreed[i] >= max ){ + max = ggreed[i]; + maxi = -i; + } + + for( i=0; i= max ){ + max = greed[i]; + maxi = i; + } + + if( nxdb ) fprintf( ftable, "nxti = %d, max = %d\n", maxi, max ); + if( max==0 ) return( NOMORE ); + else return( maxi ); + } + +osummary(){ + /* write summary */ + + register i, *p; + + if( foutput == NULL ) return; + i=0; + for( p=maxa; p>=a; --p ) { + if( *p == 0 ) ++i; + } + + fprintf( foutput, "Optimizer space used: input %d/%d, output %d/%d\n", + pmem-mem+1, MEMSIZE, maxa-a+1, ACTSIZE ); + fprintf( foutput, "%d table entries, %d zero\n", (maxa-a)+1, i ); + fprintf( foutput, "maximum spread: %d, maximum offset: %d\n", maxspr, maxoff ); + + } + +aoutput(){ /* this version is for C */ + + + /* write out the optimized parser */ + + fprintf( ftable, "# define YYLAST %d\n", maxa-a+1 ); + + arout( "yyact", a, (maxa-a)+1 ); + arout( "yypact", pa, nstate ); + arout( "yypgo", pgo, nnonter+1 ); + + } + +arout( s, v, n ) char *s; int *v, n; { + + register i; + + fprintf( ftable, "short %s[]={\n", s ); + for( i=0; i &mem[MEMSIZE] ) error( "out of space" ); + return( c ); + + } diff --git a/src/cmd/yacc/yaccdiffs b/src/cmd/yacc/yaccdiffs new file mode 100644 index 0000000..e5f7f4f --- /dev/null +++ b/src/cmd/yacc/yaccdiffs @@ -0,0 +1,198 @@ + + + + + + + + + + Yacc Differences + + + + + +This document gives a short list of differences between the +new Yacc and earlier Yaccs. + +_B_u_g_s _F_i_x_e_d + +1. There was a bug which caused Yacc to silently steal + away in the night if an action had mismatched '' in it; + this is fixed. + +2. A number of table size overflow conditions used to be + checked incorrectly or not at all; this is now better. + +3. A bug which suppressed the printing of some rules with + empty RHS's on the y.output file has been fixed. + +_S_p_e_e_d_u_p_s, _S_h_r_i_n_k_s, _a_n_d _D_i_d_d_l_e_s + +1. The old optimizer (-o) flag is now the default in Yacc. + At the same time, the Yacc process itself has been sped + up; the result is that Yacc takes about the same or + slightly longer on short inputs, but is much faster on + long inputs. + +2. The optimized parsers produced by Yacc are likely to be + 2-3 times faster and 1-2k bytes smaller than the old + ones, for medium/large grammars. The time to parse is + now essentially independent of the grammar size; it + used to grow as the size of the grammar did. + +3. The y.output file has been considerably reformatted, to + make it easier to read. The old "goto" table is gone; + the goto's for nonterminal symbols are now printed in + the states where they occur. Rules which can be + reduced in a state have their rule number printed after + them, in (). This makes it much easier to interpret + the "reduce n" actions. The message "same as n" has + been removed; duplicate states are in fact duplicated, + saving shuffling and cross-referencing. + +4. Various table sizes are somewhat bigger. + +5. The form feed character, and the construction '\f', are + now recognized; form feed is ignored (=whitespace) on + input. + + + + + January 14, 1977 + + + + + + - 2 - + + + +6. The arrays "yysterm" and "yysnter" are no longer pro- + duced on output; they were little used, and took up a + surprising amount of space in the parser. + +7. Rules in the input which are not reduced are now com- + plained about; they may represent unreachable parts of + the grammar, botched precedence, or duplicate rules. + As with conflicts, a summary complaint, "n rules not + reduced", appears at the terminal; more information is + on the y.output file. + +_N_e_w _F_e_a_t_u_r_e_s + +1. The actions are now copied into the middle of the + parser, rather than being gathered into a separate rou- + tine. It's faster. Also, you can return a value from + yyparse (and stop parsing...) by saying `return(x);' in + an action. There are macros which simulate various + interesting parsing actions: + + YYERROR causes the parser to behave as if a syntax + error had been encountered (i.e., do error recovery) + YYACCEPT causes a return from yyparse with a value of 0 + YYABORT causes a return from yyparse with a value of 1 + + +2. The repositioning of the actions may cause scope prob- + lems for some people who include lexical analyzers in + funny places. This can probably be avoided by using + another new feature: the `-d' option. Invoking Yacc + with the -d option causes the #defines generated by + Yacc to be written out onto a file called "y.tab.h", + (as well as on the "y.tab.c" file). This can then be + included as desired in lexical analyzers, etc. + +3. Actions are now permitted within rules; for such + actions, $$, $1, $2, etc. continue to have their usual + meanings. An error message is returned if any $n + refers to a value lying to the right of the action in + the rule. These internal actions are assumed to return + a value, which is accessed through the $n mechanism. + In the y.output file, the actions are referred to by + created nonterminal names of the form $$nnn. All + actions within rules are assumed to be distinct. If + some actions are the same, Yacc might report + reduce/reduce conflicts which could be resolved by + explicitly identifying identical actions; does anyone + have a good idea for a syntax to do this? The = sign + may now be omitted in action constructions of the form + ={ ... }. + + + + + + + January 14, 1977 + + + + + + - 3 - + + + +4. As a result of the rearrangement of rules, people who + thought they knew what $1 really turned into, and wrote + programs which referred to yypv[1], etc., are in trou- + ble. See Steve Johnson if you are really suffering. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + January 14, 1977 + + diff --git a/src/cmd/yacc/yaccnews b/src/cmd/yacc/yaccnews new file mode 100644 index 0000000..547c81e --- /dev/null +++ b/src/cmd/yacc/yaccnews @@ -0,0 +1,149 @@ +5/18/78 +A new version of Yacc has been installed which contains some new +features relating to error recovery, detection of funny conditions in the +grammar, and strong typing. Existing grammars should continue to work, +with the possible exception of somewhat better error recovery behavior. +More details follow: + +*** Ratfor and EFL Yacc are dead. Long live C! + +*** The y.tab.c file now uses the # line feature to reflect + most error conditions in actions, etc., back to the yacc source + file, rather than the y.tab.c file. As always with such features, + lookahead may cause the line number to be one too large + occasionally. + +*** The error recovery algorithm has been changed to cause the + parser never to reduce on a state where there is a shift + on the special token `error'. This has the effect of causing + the error recovery action to take place somewhat closer to the + location of the error than previously. It does not affect the + behavior of the parser in the absence of errors. The parse + tables may be 1-2% larger as a result of this change. + +*** Yacc now detects the existence of nonterminals in the grammar + which can never derive any strings of tokens (even the empty string). + The simplest example is the grammar: + %% + s : s 'a' ; + Here, one must reduce `s' in order to reduce `s': the + parser would always report error. If such nonterminals are + present, Yacc reports all such, then terminates. + +*** There is a new reserved word, %start. When used in the declarations + section, it may be used to declare the start symbol of the grammar. + If %start does not appear, the start symbol is, as at present, the + first nonterminal symbol encountered. + +*** Yacc produced parsers are notorious for producing many many + comments from lint. The problem is the value stack of the + parser, which typically may contain integers, pointers, and + possibly even floating point, etc., values. The lack + of tight specification of this stack leads to potential + nonportability, and considerable loss of the diagnostic power + of lint. Thus, some new features have been added which make use + of the new structure and union facilities of C. In effect, + the user of Yacc may `honestly' declare the value stack, as + well as the lexical interface variable, yylval, to be unions + of all the types desired. Yacc will keep track of the types + declared for all terminals and nonterminals, and automatically + insert the appropriate union tag for all constructions such + as $1, $$, etc. It is up to the user to supply the appropriate + union declaration, and to declare the type of all the terminal + and nonterminal symbols which will have values. If the type + declaration feature is used at all, it must be used correctly; + if it is not used, the default values are integers, as at present. + The new type declaration features are described below: + +*** There is a new keyword, %union. A construction such as + %union { + int inttag; + float floattag; + struct mumble *ptrtag; + } + can be used, in the declarations section, to declare + the type of the yacc stack. The declaration is + effectively copied to the y.tab.c file, and, if the -d + option is present, to the y.tab.h file as well. The + declaration is used to declare the typedef YYSTYPE, which is the + type of the value stack. If the -d option is present, + the declaration + extern YYSTYPE yylval; + is also placed onto the y.tab.h file. Note that the lexical + analyzer must be changed to use the appropriate union tag when + assigning values. It is not necessary that the %union + mechanism be used, as long as there is a union type YYSTYPE + defined in the declarations section. + +*** The %token, %left, %right, and %nonassoc declarations now + accept a union tag, enclosed in angle brackets (<...>), immediately + after the keyword. All tokens mentioned in that declaration are + taken to have the appropriate type. + +*** There is a new keyword, %type, also followed by a union tag + in angle brackets, which may be used in the declarations section to + declare nonterminal symbols to have a particular type. + + In both cases, whenever a $$ or $n is encountered in an action, + the appropriate union tag is supplied by Yacc. Once any type is + declared, it is an error to use a $$ or $n whose type is unknown. + It is also illegal to have a grammar rule whose LHS has a type, + but the rule has no action and the default action { $$ = $1; } + would be inapplicable because $1 had a different type. + +*** There are occasional times when the type of something is + not known (for example, when an action within a rule returns a + value). In this case, the $$ and $n syntax is extended + to permit the declaration of the type: the syntax is + $$ + and + $n + respectively. This rather strange syntax is necessitated by the + need to distinguish the <> surrounding the tag from the < and > + operators of C in the action. It is anticipated that the usage + will be rare. + +*** As always, report gripes, bugs, suggestions to SCJ *** + +12/01/76 +A newer version of Yacc has been installed which copies the actions directly +into the parser, rather than gathering them into a separate routine. +The advantages include +1. It's faster +2. You can return a value from yyparse (and stop parsing...) by + saying `return(x);' in an action +3. There are macros which simulate various interesting parsing + actions: + YYERROR causes the parser to behave as if a syntax + error had been encountered (i.e., do error recovery) + YYACCEPT causes a return from yyparse with a value of 0 + YYABORT causes a return from yyparse with a value of 1 + +The repositioning of the actions may cause scope problems +for some people who include lexical analyzers in funny places. +This can probably be avoided by using another +new feature: the `-d' option. +Invoking Yacc with the -d option causes the #defines +generated by Yacc to be written out onto a file +called "y.tab.h". This can then be included as desired +in lexical analyzers, etc. + +11/28/76 +A new version of Yacc has been installed which permits actions within +rules. For such actions, $$ and $1, $2, etc. continue to have their +usual meanings. An error message is returned if any $n refers to +a value lying to the right of the action in the rule. + +These internal actions are assumed to return a value, which is accessed +through the $n mechanism. + +In the y.output file, the actions are referred to by created nonterminal +names of the form $$nnn. + +All actions within rules are assumed to be distinct. If some actions +are the same, Yacc might report reduce/reduce conflicts which could +be resolved by explicitly identifying identical actions; does anyone +have a good idea for a syntax to do this? + +In the new Yacc, the = sign may now be omitted in action constructions +of the form ={ ... } diff --git a/src/cmd/yacc/yaccpar b/src/cmd/yacc/yaccpar new file mode 100644 index 0000000..a37c24f --- /dev/null +++ b/src/cmd/yacc/yaccpar @@ -0,0 +1,153 @@ +#if !defined(lint) && defined(DOSCCS) +static char yaccpar_sccsid[] = "@(#)yaccpar 4.1 (Berkeley) 2/11/83"; +#endif + +# +# define YYFLAG -1000 +# define YYERROR goto yyerrlab +# define YYACCEPT return(0) +# define YYABORT return(1) + +/* parser for yacc output */ + +#ifdef YYDEBUG +int yydebug = 0; /* 1 for debugging */ +#endif +YYSTYPE yyv[YYMAXDEPTH]; /* where the values are stored */ +int yychar = -1; /* current input token number */ +int yynerrs = 0; /* number of errors */ +short yyerrflag = 0; /* error recovery flag */ + +yyparse() { + + short yys[YYMAXDEPTH]; + short yyj, yym; + register YYSTYPE *yypvt; + register short yystate, *yyps, yyn; + register YYSTYPE *yypv; + register short *yyxi; + + yystate = 0; + yychar = -1; + yynerrs = 0; + yyerrflag = 0; + yyps= &yys[-1]; + yypv= &yyv[-1]; + + yystack: /* put a state and value onto the stack */ + +#ifdef YYDEBUG + if( yydebug ) printf( "state %d, char 0%o\n", yystate, yychar ); +#endif + if( ++yyps> &yys[YYMAXDEPTH] ) { yyerror( "yacc stack overflow" ); return(1); } + *yyps = yystate; + ++yypv; + *yypv = yyval; + + yynewstate: + + yyn = yypact[yystate]; + + if( yyn<= YYFLAG ) goto yydefault; /* simple state */ + + if( yychar<0 ) if( (yychar=yylex())<0 ) yychar=0; + if( (yyn += yychar)<0 || yyn >= YYLAST ) goto yydefault; + + if( yychk[ yyn=yyact[ yyn ] ] == yychar ){ /* valid shift */ + yychar = -1; + yyval = yylval; + yystate = yyn; + if( yyerrflag > 0 ) --yyerrflag; + goto yystack; + } + + yydefault: + /* default state action */ + + if( (yyn=yydef[yystate]) == -2 ) { + if( yychar<0 ) if( (yychar=yylex())<0 ) yychar = 0; + /* look through exception table */ + + for( yyxi=yyexca; (*yyxi!= (-1)) || (yyxi[1]!=yystate) ; yyxi += 2 ) ; /* VOID */ + + while( *(yyxi+=2) >= 0 ){ + if( *yyxi == yychar ) break; + } + if( (yyn = yyxi[1]) < 0 ) return(0); /* accept */ + } + + if( yyn == 0 ){ /* error */ + /* error ... attempt to resume parsing */ + + switch( yyerrflag ){ + + case 0: /* brand new error */ + + yyerror( "syntax error" ); + yyerrlab: + ++yynerrs; + + case 1: + case 2: /* incompletely recovered error ... try again */ + + yyerrflag = 3; + + /* find a state where "error" is a legal shift action */ + + while ( yyps >= yys ) { + yyn = yypact[*yyps] + YYERRCODE; + if( yyn>= 0 && yyn < YYLAST && yychk[yyact[yyn]] == YYERRCODE ){ + yystate = yyact[yyn]; /* simulate a shift of "error" */ + goto yystack; + } + yyn = yypact[*yyps]; + + /* the current yyps has no shift onn "error", pop stack */ + +#ifdef YYDEBUG + if( yydebug ) printf( "error recovery pops state %d, uncovers %d\n", *yyps, yyps[-1] ); +#endif + --yyps; + --yypv; + } + + /* there is no state on the stack with an error shift ... abort */ + + yyabort: + return(1); + + + case 3: /* no shift yet; clobber input char */ + +#ifdef YYDEBUG + if( yydebug ) printf( "error recovery discards char %d\n", yychar ); +#endif + + if( yychar == 0 ) goto yyabort; /* don't discard EOF, quit */ + yychar = -1; + goto yynewstate; /* try again in the same state */ + + } + + } + + /* reduction by production yyn */ + +#ifdef YYDEBUG + if( yydebug ) printf("reduce %d\n",yyn); +#endif + yyps -= yyr2[yyn]; + yypvt = yypv; + yypv -= yyr2[yyn]; + yyval = yypv[1]; + yym=yyn; + /* consult goto table to find next state */ + yyn = yyr1[yyn]; + yyj = yypgo[yyn] + *yyps + 1; + if( yyj>=YYLAST || yychk[ yystate = yyact[yyj] ] != -yyn ) yystate = yyact[yypgo[yyn]]; + switch(yym){ + $A + } + goto yystack; /* stack new state and value */ + + } diff --git a/src/cmd/zmodem/Makefile b/src/cmd/zmodem/Makefile new file mode 100644 index 0000000..6a88afb --- /dev/null +++ b/src/cmd/zmodem/Makefile @@ -0,0 +1,53 @@ +# +# Driver makefile for zmodem. Calls makefile.generic. +# +TOPSRC = $(shell cd ../../..; pwd) +include $(TOPSRC)/target.mk + +CFLAGS += -Werror -DV7 -DMD=2 -DTXBSIZE=8192 -DNFGVMIN -DSEGMENTS=32 + +SRCS = rz.c sz.c +OBJS = rz.o sz.o +MAN = rz.0 sz.0 +MANSRC = rz.1 sz.1 + +all: rz sz $(MAN) + +rz: rz.o + $(CC) $(LDFLAGS) -o rz.elf $< $(LIBS) + $(OBJDUMP) -S rz.elf > rz.dis + $(SIZE) rz.elf + $(ELF2AOUT) rz.elf $@ && rm rz.elf + +sz: sz.o + $(CC) $(LDFLAGS) -o sz.elf $< $(LIBS) + $(OBJDUMP) -S sz.elf > sz.dis + $(SIZE) sz.elf + $(ELF2AOUT) sz.elf $@ && rm sz.elf + +rz.0: rz.1 + $(MANROFF) $< > $@ + +sz.0: sz.1 + $(MANROFF) $< > $@ + +clean: + rm -f *.o *.elf $(MAN) rz sz *.elf *.dis tags *~ + +install: all + install rz $(DESTDIR)/bin/ + install sz $(DESTDIR)/bin/ + cp rz.0 $(DESTDIR)/share/man/cat1/ + cp sz.0 $(DESTDIR)/share/man/cat1/ + @rm -f $(DESTDIR)/bin/sb $(DESTDIR)/bin/sx + ln $(DESTDIR)/bin/sz $(DESTDIR)/bin/sb + ln $(DESTDIR)/bin/sz $(DESTDIR)/bin/sx + @rm -f $(DESTDIR)/bin/rb $(DESTDIR)/bin/rx + ln $(DESTDIR)/bin/rz $(DESTDIR)/bin/rb + ln $(DESTDIR)/bin/rz $(DESTDIR)/bin/rx + @rm -f $(DESTDIR)/share/man/cat1/sb.0 $(DESTDIR)/share/man/cat1/sx.0 + ln $(DESTDIR)/share/man/cat1/sz.0 $(DESTDIR)/share/man/cat1/sb.0 + ln $(DESTDIR)/share/man/cat1/sz.0 $(DESTDIR)/share/man/cat1/sx.0 + @rm -f $(DESTDIR)/share/man/cat1/rb.0 $(DESTDIR)/share/man/cat1/rx.0 + ln $(DESTDIR)/share/man/cat1/rz.0 $(DESTDIR)/share/man/cat1/rb.0 + ln $(DESTDIR)/share/man/cat1/rz.0 $(DESTDIR)/share/man/cat1/rx.0 diff --git a/src/cmd/zmodem/crc.1 b/src/cmd/zmodem/crc.1 new file mode 100644 index 0000000..9b71ad5 --- /dev/null +++ b/src/cmd/zmodem/crc.1 @@ -0,0 +1,32 @@ +.TH CRC 1 OMEN +.SH NAME +crc \- checksum files +.SH SYNOPSIS +.B crc +file ... +.SH DESCRIPTION +For each file, +.I crc\^ +calculates and prints a 32-bit CRC, +the byte count, and the file name. +It is typically used to validate files transferred between +different systems, and is useful in detecting subtle disk corruption. +.I Crc\^ +uses a checksum compatible with the +DOS +version of crc, +the 32 bit CRC used by PKZIP version 0.9, +as well as the "crc" command in ZCOMM and Professional-YAM +(high reliability communications programs). + +The 32-bit CRC used is the frame +check sequence in ADCCP (ANSI X3.66, also known as FIPS PUB 71 +and FED-STD-1003, the U.S. versions of CCITT's X.25 link-level +protocol). + +32 bit CRC code courtesy Gary S. Brown. +.SH BUGS +Although extremely unlikely, +files with different data may still produce the same crc value. +.SH "SEE ALSO" +chek(1), undos(OMEN), todos(OMEN), tocpm(OMEN), sum(1), wc(1). diff --git a/src/cmd/zmodem/crc.c b/src/cmd/zmodem/crc.c new file mode 100644 index 0000000..79dce9f --- /dev/null +++ b/src/cmd/zmodem/crc.c @@ -0,0 +1,160 @@ +/*% cc -O -K -dos % -o crc.exe +*/ + +/* + * Crc - 32 BIT ANSI X3.66 CRC checksum files + */ +#include +#define OK 0 +#define ERROR (-1) +#define LINT_ARGS + +/**********************************************************************\ +|* *| +|* Demonstration program to compute the 32-bit CRC used as the frame *| +|* check sequence in ADCCP (ANSI X3.66, also known as FIPS PUB 71 *| +|* and FED-STD-1003, the U.S. versions of CCITT's X.25 link-level *| +|* protocol). The 32-bit FCS was added via the Federal Register, *| +|* 1 June 1982, p.23798. I presume but don't know for certain that *| +|* this polynomial is or will be included in CCITT V.41, which *| +|* defines the 16-bit CRC (often called CRC-CCITT) polynomial. FIPS *| +|* PUB 78 says that the 32-bit FCS reduces otherwise undetected *| +|* errors by a factor of 10^-5 over 16-bit FCS. *| +|* *| +\**********************************************************************/ + +/* Need an unsigned type capable of holding 32 bits; */ +typedef unsigned long int UNS_32_BITS; + +/* + * Copyright (C) 1986 Gary S. Brown. You may use this program, or + * code or tables extracted from it, as desired without restriction. + */ +/* First, the polynomial itself and its table of feedback terms. The */ +/* polynomial is */ +/* 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+X^0 */ +/* Note that we take it "backwards" and put the highest-order term in */ +/* the lowest-order bit. The X^32 term is "implied"; the LSB is the */ +/* X^31 term, etc. The X^0 term (usually shown as "+1") results in */ +/* the MSB being 1. */ + +/* Note that the usual hardware shift register implementation, which */ +/* is what we're using (we're merely optimizing it by doing eight-bit */ +/* chunks at a time) shifts bits into the lowest-order term. In our */ +/* implementation, that means shifting towards the right. Why do we */ +/* do it this way? Because the calculated CRC must be transmitted in */ +/* order from highest-order term to lowest-order term. UARTs transmit */ +/* characters in order from LSB to MSB. By storing the CRC this way, */ +/* we hand it to the UART in the order low-byte to high-byte; the UART */ +/* sends each low-bit to hight-bit; and the result is transmission bit */ +/* by bit from highest- to lowest-order term without requiring any bit */ +/* shuffling on our part. Reception works similarly. */ + +/* The feedback terms table consists of 256, 32-bit entries. Notes: */ +/* */ +/* 1. The table can be generated at runtime if desired; code to do so */ +/* is shown later. It might not be obvious, but the feedback */ +/* terms simply represent the results of eight shift/xor opera- */ +/* tions for all combinations of data and CRC register values. */ +/* */ +/* 2. The CRC accumulation logic is the same for all CRC polynomials, */ +/* be they sixteen or thirty-two bits wide. You simply choose the */ +/* appropriate table. Alternatively, because the table can be */ +/* generated at runtime, you can start by generating the table for */ +/* the polynomial in question and use exactly the same "updcrc", */ +/* if your application needn't simultaneously handle two CRC */ +/* polynomials. (Note, however, that XMODEM is strange.) */ +/* */ +/* 3. For 16-bit CRCs, the table entries need be only 16 bits wide; */ +/* of course, 32-bit entries work OK if the high 16 bits are zero. */ +/* */ +/* 4. The values must be right-shifted by eight bits by the "updcrc" */ +/* logic; the shift must be unsigned (bring in zeroes). On some */ +/* hardware you could probably optimize the shift in assembler by */ +/* using byte-swap instructions. */ + +static UNS_32_BITS crc_32_tab[] = { /* CRC polynomial 0xedb88320 */ +0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, +0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, +0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, +0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, +0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, +0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, +0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, +0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, +0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, +0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, +0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, +0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, +0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, +0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, +0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, +0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, +0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, +0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, +0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, +0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, +0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, +0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, +0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, +0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, +0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, +0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, +0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, +0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, +0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, +0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, +0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, +0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d +}; + +#define UPDC32(octet, crc) (crc_32_tab[((crc) ^ (octet)) & 0xff] ^ ((crc) >> 8)) + +main(argc, argp) +char **argp; +{ + register errors = 0; + + while( --argc > 0) + errors |= crc32file( *++argp); + exit(errors != 0); +} + +crc32file(name) +char *name; +{ + register FILE *fin; + register unsigned long oldcrc32; + register unsigned long crc32; + register unsigned long oldcrc; + register c; + register long charcnt; + + oldcrc32 = 0xFFFFFFFF; charcnt = 0; +#ifdef M_I86SM + if ((fin=fopen(name, "rb"))==NULL) +#else + if ((fin=fopen(name, "r"))==NULL) +#endif + { + perror(name); + return ERROR; + } + while ((c=getc(fin))!=EOF) { + ++charcnt; + oldcrc32 = UPDC32(c, oldcrc32); + } + + if (ferror(fin)) { + perror(name); + charcnt = -1; + } + fclose(fin); + + crc32 = oldcrc32; oldcrc = oldcrc32 = ~oldcrc32; + + printf("%08lX %7ld %s\n", oldcrc, charcnt, name); + + return OK; +} + diff --git a/src/cmd/zmodem/crctab.c b/src/cmd/zmodem/crctab.c new file mode 100644 index 0000000..6811b3d --- /dev/null +++ b/src/cmd/zmodem/crctab.c @@ -0,0 +1,140 @@ +/* + * Crc calculation stuff + */ + +/* crctab calculated by Mark G. Mendel, Network Systems Corporation */ +static unsigned short crctab[256] = { + 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, + 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, + 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, + 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, + 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, + 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, + 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, + 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, + 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, + 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, + 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, + 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, + 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, + 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, + 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, + 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, + 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, + 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, + 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, + 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, + 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, + 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, + 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, + 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, + 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, + 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, + 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, + 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, + 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, + 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, + 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, + 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0 +}; + +/* + * updcrc macro derived from article Copyright (C) 1986 Stephen Satchell. + * NOTE: First srgument must be in range 0 to 255. + * Second argument is referenced twice. + * + * Programmers may incorporate any or all code into their programs, + * giving proper credit within the source. Publication of the + * source routines is permitted so long as proper credit is given + * to Stephen Satchell, Satchell Evaluations and Chuck Forsberg, + * Omen Technology. + */ + +#define updcrc(cp, crc) ( crctab[((crc >> 8) & 255)] ^ (crc << 8) ^ cp) + +/* + * Copyright (C) 1986 Gary S. Brown. You may use this program, or + * code or tables extracted from it, as desired without restriction. + */ + +/* First, the polynomial itself and its table of feedback terms. The */ +/* polynomial is */ +/* 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+X^0 */ +/* Note that we take it "backwards" and put the highest-order term in */ +/* the lowest-order bit. The X^32 term is "implied"; the LSB is the */ +/* X^31 term, etc. The X^0 term (usually shown as "+1") results in */ +/* the MSB being 1. */ + +/* Note that the usual hardware shift register implementation, which */ +/* is what we're using (we're merely optimizing it by doing eight-bit */ +/* chunks at a time) shifts bits into the lowest-order term. In our */ +/* implementation, that means shifting towards the right. Why do we */ +/* do it this way? Because the calculated CRC must be transmitted in */ +/* order from highest-order term to lowest-order term. UARTs transmit */ +/* characters in order from LSB to MSB. By storing the CRC this way, */ +/* we hand it to the UART in the order low-byte to high-byte; the UART */ +/* sends each low-bit to hight-bit; and the result is transmission bit */ +/* by bit from highest- to lowest-order term without requiring any bit */ +/* shuffling on our part. Reception works similarly. */ + +/* The feedback terms table consists of 256, 32-bit entries. Notes: */ +/* */ +/* The table can be generated at runtime if desired; code to do so */ +/* is shown later. It might not be obvious, but the feedback */ +/* terms simply represent the results of eight shift/xor opera- */ +/* tions for all combinations of data and CRC register values. */ +/* */ +/* The values must be right-shifted by eight bits by the "updcrc" */ +/* logic; the shift must be unsigned (bring in zeroes). On some */ +/* hardware you could probably optimize the shift in assembler by */ +/* using byte-swap instructions. */ + +static long cr3tab[] = { /* CRC polynomial 0xedb88320 */ +0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, +0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, +0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, +0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, +0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, +0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, +0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, +0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, +0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, +0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, +0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, +0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, +0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, +0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, +0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, +0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, +0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, +0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, +0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, +0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, +0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, +0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, +0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, +0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, +0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, +0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, +0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, +0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, +0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, +0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, +0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, +0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d +}; + +#ifdef NFGM +long +UPDC32(b, c) +long c; +{ + return (cr3tab[((int)c ^ b) & 0xff] ^ ((c >> 8) & 0x00FFFFFF)); +} + +#else + +#define UPDC32(b, c) (cr3tab[((int)c ^ b) & 0xff] ^ ((c >> 8) & 0x00FFFFFF)) +#endif + +/* End of crctab.c */ diff --git a/src/cmd/zmodem/genie.c b/src/cmd/zmodem/genie.c new file mode 100644 index 0000000..3a962d8 --- /dev/null +++ b/src/cmd/zmodem/genie.c @@ -0,0 +1,111 @@ +/* + * + * Rev 5-25-89 + * This file contains GEnie specific code for setting terminal modes, + * very little is specific to ZMODEM or YMODEM per se (that code is in + * sz.c and rz.c). The CRC-16 routines used by XMODEM, YMODEM, and ZMODEM + * are also in this file, a fast table driven macro version + * + * This file is #included so the main file can set parameters such as HOWMANY. + * See the main file rz.c for compile instructions. + */ + +#include +#include + +#define XARGSFILE "/" +#define XX + +STATIC char Myattn[] = { 0335, 0336, 0336, 0, + 0335, 0336, 0336, 24,24,24,24,24,24,24,24,24,24,13 +}; +#define ALTCANOFF 4 + +/* +extern unsigned int _fmode = O_BINARY; +*/ + +/* + * return 1 iff stdout and stderr are different devices + * indicating this program operating with a modem on a + * different line + */ +int Fromcu; /* Were called from cu or yam */ +from_cu() +{ + return 0; +} +cucheck() +{ +} + + +int Twostop; /* Use two stop bits */ + + + + +/* + * mode(n) + * 3: save old tty stat, set raw mode with flow control + * 2: set XON/XOFF for sb/sz with ZMODEM or YMODEM-g + * 1: save old tty stat, set raw mode + * 0: restore original tty mode + */ +mode(n) +{ + static did0 = FALSE; + + vfile("mode:%d", n); + switch(n) { + case 2: /* Un-raw mode used by sz, sb when -g detected */ + case 1: + case 3: + did0 = TRUE; + system("set x on"); + system("set e off"); + system("set t13,10"); +/* + system("set b3"); +*/ + reset(1); + binary(1); + /* Assume fd 1 is stdout (not documented in GEnie) */ + fcntl(1, F_SETFL, + ((fcntl(1, F_GETFL, 0)|O_BINARY)& ~O_POST_BREAK)); + return OK; + case 0: + if(!did0) + return ERROR; + + return OK; + default: + return ERROR; + } +} + +sendbrk() +{ +} +/* + * readline(timeout) reads character(s) from file descriptor 0 + * timeout is in tenths of seconds + */ +readline(timeout) +{ + static char byt[1]; + + fflush(stdout); + read(0, byt, 1); + return (byt[0]&0377); +} + +flushmo() +{ + fflush(stdout); +} + +purgeline() {} + + +/* End of genie.c */ diff --git a/src/cmd/zmodem/makefile.generic b/src/cmd/zmodem/makefile.generic new file mode 100644 index 0000000..8efdd06 --- /dev/null +++ b/src/cmd/zmodem/makefile.generic @@ -0,0 +1,126 @@ +# Makefile for Unix/Xenix rz and sz programs +# the makefile is not too well tested yet +CC=cc +OFLAG=-O + +TLBFILES= zmodem.h zm.c zmr.c crctab.c sz.c rz.c \ + mailer.rz vmodem.h vvmodem.c vrzsz.c init.com crc.c + +ARCFILES= $(TLBFILES) README rbsb.c gz ptest.sh *.t minirb.c genie.c *.1 + +nothing: + @echo + @echo "Please study the #ifdef's in crctab.c, rbsb.c, rz.c and sz.c," + @echo "make any necessary hacks for oddball or merged SYSV/BSD systems," + @echo "then type 'make SYSTEM' where SYSTEM is one of:" + @echo + @echo " sysvr3 SYSTEM 5.3 Unix with mkdir(2)" + @echo " sysv SYSTEM 3/5 Unix" + @echo " xenix Xenix" + @echo " x386 386 Xenix" + @echo " bsd Berkeley 4.x BSD, Ultrix, V7" + @echo + +usenet: + shar -f /tmp/rzsz README Makefile zmodem.h zm.c sz.c rz.c rbsb.c \ + init.com crc.c vmodem.h vvmodem.c vrzsz.c crctab.c minirb.c \ + mailer.rz zmr.c *.1 gz ptest.sh *.t + +shar: + shar -f /tmp/rzsz -m 2000000 README Makefile zmodem.h zm.c \ + zmr.c init.com vmodem.h vvmodem.c vrzsz.c sz.c rz.c crctab.c \ + mailer.rz genie.c crc.c rbsb.c minirb.c *.1 gz ptest.sh *.t + +unixforum: shar + compress -b12 /tmp/rzsz.sh + +tlbcmd: + mktlb.sh README. $(TLBFILES) + +unix: + undos $(ARCFILES) + +dos: + todos $(ARCFILES) + +arc: + rm -f /tmp/rzsz.arc + arc aq /tmp/rzsz README Makefile zmodem.h zm.c sz.c rz.c \ + mailer.rz vmodem.h vvmodem.c vrzsz.c crctab.c rbsb.c \ + zmr.c genie.c init.com crc.c *.1 gz ptest.sh *.t minirb.c + chmod og-w /tmp/rzsz.arc + mv /tmp/rzsz.arc /t/yam + +zoo: + rm -f /tmp/rzsz.zoo + zoo a /tmp/rzsz README Makefile zmodem.h zm.c sz.c rz.c \ + mailer.rz vmodem.h vvmodem.c vrzsz.c crctab.c rbsb.c *.1 \ + zmr.c genie.c init.com crc.c gz ptest.sh *.t minirb.c + touch /tmp/rzsz.zoo + chmod og-w /tmp/rzsz.zoo + mv /tmp/rzsz.zoo /t/yam + +tar: + tar cvf /tmp/rzsz.tar README Makefile zmodem.h zm.c sz.c rz.c \ + mailer.rz vmodem.h vvmodem.c vrzsz.c crctab.c rbsb.c \ + zmr.c genie.c init.com crc.c *.1 gz ptest.sh *.t minirb.c + +tags: + ctags sz.c rz.c zm.c zmr.c rbsb.c + +.PRECIOUS:rz sz + +xenix: + $(CC) $(CFLAGS) $(OFLAG) -M0 -Ox -K -i -DTXBSIZE=16384 -DNFGVMIN -DREADCHECK sz.c -lx -o sz + size sz + -ln sz sb + -ln sz sx + $(CC) $(CFLAGS) $(OFLAG) -M0 -Ox -K -i -DMD rz.c -o rz + size rz + -ln rz rb + -ln rz rx + +x386: + $(CC) $(CFLAGS) $(OFLAG) -Ox -DMD rz.c -o rz + size rz + -ln rz rb + -ln rz rx + $(CC) $(CFLAGS) $(OFLAG) -Ox -DTXBSIZE=32768 -DNFGVMIN -DREADCHECK sz.c -lx -o sz + size sz + -ln sz sb + -ln sz sx + +sysv: + $(CC) $(CFLAGS) $(OFLAG) -DMD rz.c -o rz + size rz + -ln rz rb + -ln rz rx + $(CC) $(CFLAGS) $(OFLAG) -DSV -DTXBSIZE=32768 -DNFGVMIN sz.c -o sz + size sz + -ln sz sb + -ln sz sx + +sysvr3: + $(CC) $(CFLAGS) $(OFLAG) -DMD=2 rz.c -o rz + size rz + -ln rz rb + -ln rz rx + $(CC) $(CFLAGS) $(OFLAG) -DSV -DTXBSIZE=32768 -DNFGVMIN sz.c -o sz + size sz + -ln sz sb + -ln sz sx + +bsd: + $(CC) $(CFLAGS) $(OFLAG) -DMD=2 -Dstrchr=index -DV7 rz.c -o rz + size rz + -ln rz rb + -ln rz rx + $(CC) $(CFLAGS) $(OFLAG) -DV7 -DTXBSIZE=8192 -DNFGVMIN sz.c -o sz + size sz + -ln sz sb + -ln sz sx + +sz: nothing +sb: nothing +rz: nothing +rb: nothing diff --git a/src/cmd/zmodem/minirb.1 b/src/cmd/zmodem/minirb.1 new file mode 100644 index 0000000..449ee69 --- /dev/null +++ b/src/cmd/zmodem/minirb.1 @@ -0,0 +1,53 @@ +'\" Revision Level +'\" Last Delta 09-08-87 +.TH MINIRB 1 OMEN +.SH NAME +minirb \- Bootstrap YMODEM Batch file receive +.SH SYNOPSIS +.B minirb +.SH DESCRIPTION +.I Minirb +receives one or more files with YMODEM batch file transfer protocol. +.I Minirb +was developed for use as a bootstrap to simplify uploading of the longer +.I rz +and +.I sz +programs, such as are contained in the +.I rzsz.zoo +"zoo" archive or the +.I rzsz.sh +shell archive. +.SH SEE ALSO +YMODEM.DOC, +Professional-YAM manual, +sz(omen) +.SH NOTES +The source file +.I minirb.c +has been ruthlessly pruned +(4k, 175 lines) +to simplify uploading without benefit of +an error correcting file transfer protocol. +Do not reformat or add tabs to the source file +as this would complicate uploading. + +Please read the uploading suggestions in the chapter +.I "File Transfer Basics" +in the Professional-YAM or ZCOMM user's manual. + +.I Minirb +uses 8 bit checksum which may not be compatible with some programs +claiming to support YMODEM batch transfers. + +.I Minirb +uses the +YMODEM header +file length information +to avoid storing extraneous characters. +.I Minirb +deletes carriage returns and CPMEOF (^Z) characters +encountered in uploaded files. + +.I Minirb +calls stty(1) to set and reset raw tty mode. diff --git a/src/cmd/zmodem/minirb.c b/src/cmd/zmodem/minirb.c new file mode 100644 index 0000000..52316ec --- /dev/null +++ b/src/cmd/zmodem/minirb.c @@ -0,0 +1,175 @@ +/* + * minirb.c By Chuck Forsberg Omen Technology INC + * "The High Reliability Communications Software" + * + * A bootstrap program for Unix to receive files from computers running + * YMODEM Batch (Professional-YAM, PowerCom, ZCOMM, etc.). + * + * Minirb uses system(3) to call stty, avoiding system dependent code. + * program strips CR and CPMEOF (^Z) characters (see putsec()). + * Please refer to rz.c for comments, etc. + */ +char * Version = "minirb 2.00 05-25-87"; + +#include +#include +#include + +#define OK 0 +#define FALSE 0 +#define TRUE 1 +#define ERROR (-1) +#define CAN ('X'&037) +#define SOH 1 +#define STX 2 +#define EOT 4 +#define ACK 6 +#define NAK 025 +#define TIMEOUT (-2) +#define RETRYMAX 9 +#define WCEOT (-10) + +FILE *fout; +long Bytesleft; +int Blklen; +char secbuf[1024]; +char linbuf[1024]; +int Lleft=0; +jmp_buf tohere; + +alrm() { longjmp(tohere, -1); } + +bibi(n) { + canit(); mode(0); + fprintf(stderr, "minirb: caught signal %d; exiting", n); + exit(128+n); +} + +mode(n) { + if (n) system("stty raw -echo"); + else system("stty echo -raw"); +} + +main() { + mode(1); + if (signal(SIGINT, bibi) == SIG_IGN) { + signal(SIGINT, SIG_IGN); signal(SIGKILL, SIG_IGN); + } else { + signal(SIGINT, bibi); signal(SIGKILL, bibi); + } + printf("minirb: Now send file(s) with \042sb file ...\042 command\r\n"); + + if (wcreceive()==ERROR) + canit(); + mode(0); exit(0); +} + +wcreceive() { + for (;;) { + if (wcrxpn(secbuf) == ERROR) break; + if (secbuf[0]==0) return OK; + if (procheader(secbuf)==ERROR || wcrx()==ERROR) break; + } + canit(); return ERROR; +} + + +wcrxpn(rpn) char *rpn; { + register c; + + purgeline(); +et_tu: + sendline(NAK); Lleft=0; + while ((c = wcgetsec(rpn, 100)) != 0) { + if (c == WCEOT) { sendline(ACK); Lleft=0; readline(1); goto et_tu; } + return ERROR; + } + sendline(ACK); return OK; +} + +wcrx() { + register int sectnum, sectcurr, sendchar, cblklen; + + sectnum=0; sendchar=NAK; + for (;;) { + sendline(sendchar); Lleft=0; + sectcurr=wcgetsec(secbuf, 50); + if (sectcurr==(sectnum+1 & 0377)) { + sectnum++; cblklen = Bytesleft>Blklen ? Blklen:Bytesleft; + putsec(secbuf, cblklen); + if ((Bytesleft-=cblklen) < 0) Bytesleft = 0; + sendchar=ACK; + } + else if (sectcurr==(sectnum&0377)) sendchar=ACK; + else if (sectcurr==WCEOT) { + if (fclose(fout)==ERROR) return ERROR; + sendline(ACK); Lleft=0; return OK; + } + else if (sectcurr==ERROR) return ERROR; + else return ERROR; + } +} + +wcgetsec(rxbuf, maxtime) char *rxbuf; int maxtime; { + register checksum, wcj, firstch; register char *p; int sectcurr, errors; + for (errors=0; errors=0; ) { + if ((firstch=readline(1)) < 0) goto bilge; + checksum += (*p++ = firstch); + } + if ((firstch=readline(1)) < 0) goto bilge; + if (((checksum-firstch)&0377)==0) return sectcurr; + } + } + else if (firstch==EOT) return WCEOT; + else if (firstch==CAN) return ERROR; +bilge: + while(readline(1)!=TIMEOUT) + ; + maxtime=40; sendline(NAK); Lleft=0; + } + canit(); return ERROR; +} + +readline(timeout) int timeout; { + register n; static char *cdq; + + if (--Lleft >= 0) return (*cdq++ & 0377); + n = timeout/10; + if (n < 2) n = 3; + if (setjmp(tohere)) { Lleft = 0; return TIMEOUT; } + signal(SIGALRM, alrm); alarm(n); + Lleft=read(0, cdq=linbuf, 1024); alarm(0); + if (Lleft < 1) return TIMEOUT; + --Lleft; return (*cdq++ & 0377); +} + +purgeline() { Lleft = 0; lseek(0, 0L, 2); } + + +procheader(name) char *name; { + register char *p; + + Bytesleft = 2000000000L; p = name + 1 + strlen(name); + if (*p) sscanf(p, "%ld", &Bytesleft); + if ((fout=fopen(name, "w")) == NULL) return ERROR; + return OK; +} + +putsec(p, n) char *p; int n; +{ for (; --n>=0; ++p) if (*p != 015 && *p != 032) putc(*p, fout); } + +sendline(c) { char d; d = c; write(1, &d, 1); } + +char canistr[] = { 24,24,24,24,24,24,24,24,0 }; + +canit() { printf(canistr); Lleft=0; } + +/* END of minirb.c */ + diff --git a/src/cmd/zmodem/ptest.sh b/src/cmd/zmodem/ptest.sh new file mode 100644 index 0000000..1ac01ce --- /dev/null +++ b/src/cmd/zmodem/ptest.sh @@ -0,0 +1,4 @@ +#a short test for sz and rz using a named pipe - no modem used. +/etc/mknod fifo p +sz fifo +rm fifo diff --git a/src/cmd/zmodem/rbsb.c b/src/cmd/zmodem/rbsb.c new file mode 100644 index 0000000..40c83d2 --- /dev/null +++ b/src/cmd/zmodem/rbsb.c @@ -0,0 +1,340 @@ +/* + * + * Rev 1997-3-28 + * Remove use of alldelay and lcase tty flags - they're gone (at last). + * + * Rev 5-09-89 + * This file contains Unix specific code for setting terminal modes, + * very little is specific to ZMODEM or YMODEM per se (that code is in + * sz.c and rz.c). The CRC-16 routines used by XMODEM, YMODEM, and ZMODEM + * are also in this file, a fast table driven macro version + * + * V7/BSD HACKERS: SEE NOTES UNDER mode(2) !!! + * + * This file is #included so the main file can set parameters such as HOWMANY. + * See the main files (rz.c/sz.c) for compile instructions. + */ + +#ifdef V7 +#include +#include +#define STAT +#include +#define OS "V7/BSD" +#define ROPMODE "r" +#ifdef LLITOUT +int Locmode; /* Saved "local mode" for 4.x BSD "new driver" */ +int Locbit = LLITOUT|LDECCTQ; /* Bit SUPPOSED to disable output + translations and only allow ^Q to + resume after ^S */ +#include +#endif +#endif + +#ifndef OS +#ifndef USG +#define USG +#endif +#endif + +#ifdef USG +#include +#include +#define STAT +#include +#define OS "SYS III/V" +#define ROPMODE "r" +#define MODE2OK +#include +#endif + +#if HOWMANY > 255 +Howmany must be 255 or less +#endif + +extern void bibi (int); + +/* + * return 1 iff stdout and stderr are different devices + * indicating this program operating with a modem on a + * different line + */ +int Fromcu; /* Were called from cu or yam */ +from_cu() +{ + struct stat a, b; + + fstat(1, &a); fstat(2, &b); + Fromcu = a.st_rdev != b.st_rdev; + return; +} +cucheck() +{ + if (Fromcu) + fprintf(stderr,"Please read the manual page BUGS chapter!\r\n"); +} + + +struct { + unsigned baudr; + int speedcode; +} speeds[] = { + 50, B50, + 75, B75, + 150, B150, + 200, B200, + 300, B300, + 600, B600, + 1200, B1200, + 1800, B1800, + 2400, B2400, + 4800, B4800, + 9600, B9600, + 19200, B19200, + 38400, B38400, + 57600, B57600, + 115200, B115200, + 0, +}; + +int Twostop; /* Use two stop bits */ + + +/* + * The following uses an external rdchk() routine if available, + * otherwise defines the function for BSD or fakes it for SYSV. + */ + +#ifndef READCHECK +#ifdef FIONREAD +#define READCHECK +/* + * Return non 0 iff something to read from io descriptor f + */ +rdchk(f) +{ + static long lf; + + ioctl(f, FIONREAD, &lf); + return ((int) lf); +} + +#else /* FIONREAD */ + +#ifdef SV +#define READCHECK +#include + +int checked = 0; +/* + * Nonblocking I/O is a bit different in System V, Release 2 + * Note: this rdchk vsn throws away a byte, OK for ZMODEM + * sender because protocol design anticipates this problem. + */ +#define EATSIT +rdchk(f) +{ + int lf, savestat; + static char bchecked; + + savestat = fcntl(f, F_GETFL) ; + fcntl(f, F_SETFL, savestat | O_NDELAY) ; + lf = read(f, &bchecked, 1) ; + fcntl(f, F_SETFL, savestat) ; + checked = bchecked & 0377; /* force unsigned byte */ + return(lf) ; +} +#endif +#endif +#endif + + +static unsigned +getspeed(code) +{ + register n; + + for (n=0; speeds[n].baudr; ++n) + if (speeds[n].speedcode == code) + return speeds[n].baudr; + return 38400; /* Assume fifo if ioctl failed */ +} + + + +#ifdef ICANON +struct termio oldtty, tty; +#else +struct sgttyb oldtty, tty; +struct tchars oldtch, tch; +#endif + +/* + * mode(n) + * 3: save old tty stat, set raw mode with flow control + * 2: set XON/XOFF for sb/sz with ZMODEM or YMODEM-g + * 1: save old tty stat, set raw mode + * 0: restore original tty mode + */ +mode(n) +{ + static did0 = FALSE; + + vfile("mode:%d", n); + switch(n) { +#ifdef USG + case 2: /* Un-raw mode used by sz, sb when -g detected */ + if(!did0) + (void) ioctl(0, TCGETA, &oldtty); + tty = oldtty; + + tty.c_iflag = BRKINT|IXON; + + tty.c_oflag = 0; /* Transparent output */ + + tty.c_cflag &= ~PARENB; /* Disable parity */ + tty.c_cflag |= CS8; /* Set character size = 8 */ + if (Twostop) + tty.c_cflag |= CSTOPB; /* Set two stop bits */ + + +#ifdef READCHECK + tty.c_lflag = Zmodem ? 0 : ISIG; + tty.c_cc[VINTR] = Zmodem ? -1:030; /* Interrupt char */ +#else + tty.c_lflag = ISIG; + tty.c_cc[VINTR] = Zmodem ? 03:030; /* Interrupt char */ +#endif + tty.c_cc[VQUIT] = -1; /* Quit char */ +#ifdef NFGVMIN + tty.c_cc[VMIN] = 1; +#else + tty.c_cc[VMIN] = 3; /* This many chars satisfies reads */ +#endif + tty.c_cc[VTIME] = 1; /* or in this many tenths of seconds */ + + (void) ioctl(0, TCSETAW, &tty); + did0 = TRUE; + return OK; + case 1: + case 3: + if(!did0) + (void) ioctl(0, TCGETA, &oldtty); + tty = oldtty; + + tty.c_iflag = n==3 ? (IGNBRK|IXOFF) : IGNBRK; + + /* No echo, crlf mapping, INTR, QUIT, delays, no erase/kill */ + tty.c_lflag &= ~(ECHO | ICANON | ISIG); + + tty.c_oflag = 0; /* Transparent output */ + + tty.c_cflag &= ~PARENB; /* Same baud rate, disable parity */ + tty.c_cflag |= CS8; /* Set character size = 8 */ + if (Twostop) + tty.c_cflag |= CSTOPB; /* Set two stop bits */ +#ifdef NFGVMIN + tty.c_cc[VMIN] = 1; /* This many chars satisfies reads */ +#else + tty.c_cc[VMIN] = HOWMANY; /* This many chars satisfies reads */ +#endif + tty.c_cc[VTIME] = 1; /* or in this many tenths of seconds */ + (void) ioctl(0, TCSETAW, &tty); + did0 = TRUE; + Effbaud = Baudrate = getspeed(tty.c_cflag & CBAUD); + return OK; +#endif +#ifdef V7 + /* + * NOTE: this should transmit all 8 bits and at the same time + * respond to XOFF/XON flow control. If no FIONREAD or other + * rdchk() alternative, also must respond to INTRRUPT char + * This doesn't work with V7. It should work with LLITOUT, + * but LLITOUT was broken on the machine I tried it on. + */ + case 2: /* Un-raw mode used by sz, sb when -g detected */ + if(!did0) { + ioctl(0, TIOCEXCL, 0); + ioctl(0, TIOCGETP, &oldtty); + ioctl(0, TIOCGETC, &oldtch); +#ifdef LLITOUT + ioctl(0, TIOCLGET, &Locmode); +#endif + } + tty = oldtty; + tch = oldtch; +#ifdef READCHECK + tch.t_intrc = Zmodem ? -1:030; /* Interrupt char */ +#else + tch.t_intrc = Zmodem ? 03:030; /* Interrupt char */ +#endif + tty.sg_flags |= (ODDP|EVENP|CBREAK); + tty.sg_flags &= ~(CRMOD|ECHO); + ioctl(0, TIOCSETP, &tty); + ioctl(0, TIOCSETC, &tch); +#ifdef LLITOUT + ioctl(0, TIOCLBIS, &Locbit); +#endif + bibi(99); /* un-raw doesn't work w/o lit out */ + did0 = TRUE; + return OK; + case 1: + case 3: + if(!did0) { + ioctl(0, TIOCEXCL, 0); + ioctl(0, TIOCGETP, &oldtty); + ioctl(0, TIOCGETC, &oldtch); +#ifdef LLITOUT + ioctl(0, TIOCLGET, &Locmode); +#endif + } + tty = oldtty; + tty.sg_flags |= (RAW|TANDEM); + tty.sg_flags &= ~ECHO; + ioctl(0, TIOCSETP, &tty); + did0 = TRUE; + Effbaud = Baudrate = getspeed(tty.sg_ospeed); + return OK; +#endif + case 0: + if(!did0) + return ERROR; +#ifdef USG + (void) ioctl(0, TCSBRK, 1); /* Wait for output to drain */ + (void) ioctl(0, TCFLSH, 1); /* Flush input queue */ + (void) ioctl(0, TCSETAW, &oldtty); /* Restore modes */ + (void) ioctl(0, TCXONC,1); /* Restart output */ +#endif +#ifdef V7 + ioctl(0, TIOCSETP, &oldtty); + ioctl(0, TIOCSETC, &oldtch); + ioctl(0, TIOCNXCL, 0); +#ifdef LLITOUT + ioctl(0, TIOCLSET, &Locmode); +#endif +#endif + + return OK; + default: + return ERROR; + } +} + +sendbrk() +{ +#ifdef V7 +#ifdef TIOCSBRK +#define CANBREAK + sleep(1); + ioctl(0, TIOCSBRK, 0); + sleep(1); + ioctl(0, TIOCCBRK, 0); +#endif +#endif +#ifdef USG +#define CANBREAK + ioctl(0, TCSBRK, 0); +#endif +} + +/* End of rbsb.c */ diff --git a/src/cmd/zmodem/rz.1 b/src/cmd/zmodem/rz.1 new file mode 100644 index 0000000..c834e3b --- /dev/null +++ b/src/cmd/zmodem/rz.1 @@ -0,0 +1,360 @@ +'\" Revision Level +'\" Last Delta 03-25-89 +.TH RZ 1 OMEN +.SH NAME +rx, rb, rz \- XMODEM, YMODEM, ZMODEM (Batch) file receive +.SH SYNOPSIS +.B rz +.RB [\- "\ +abepqtuvy" ] +.br +.B rb +.RB [\- "\ +abqtuvy" ] +.br +.B rx +.RB [\- "\ abceqtuv" ] +.I file +.br +.B gz +.I "file ..." +.br +.RB [ \- ][ v ] rzCOMMAND +.SH DESCRIPTION +This program uses error correcting protocols to receive +files over a dial-in serial port from a variety of programs running under +PC-DOS, CP/M, +.SM Unix, +and other operating systems. +It is invoked from a shell prompt +manually, or automatically as a result of an +"sz file ..." command given to the calling program. + + +.B +.I Rz +is not intended be called from +.I cu(1), +or other communications programs. +Unix flavors of Omen Technology's +Professional-YAM communications software +are available for dial-out applications. +.R + + +.B Rz +(Receive ZMODEM) +receives files with the ZMODEM batch protocol. +Pathnames are supplied by the sending program, +and directories are made if necessary (and possible). +Normally, the +"rz" command is automatically issued by the calling ZMODEM program, +but some defective ZMODEM implementations may require starting +.I rz +the old fashioned way. +.I Rz +does not support ZMODEM Crash Recovery +and certain other ZMODEM features. +Unix flavors of Professional-YAM may be linked to "rz" +and used in place of this program +to support these ZMODEM features. + + +.B Rb +receives file(s) with YMODEM, +accepting either standard 128 byte sectors or +1024 byte sectors +(YAM sb +.B -k +option). +The user should determine when +the 1024 byte block length +actually improves throughput without causing lost data +or even system crashes. + +If True YMODEM (Omen Technology trademark) file information (file length, etc.) +is received, +the file length controls the number of bytes written to +the output dataset, +and the modify time and file mode +(iff non zero) +are set accordingly. + +If no True YMODEM file information is received, +slashes in the pathname are changed to underscore, +and any trailing period in the pathname is eliminated. +This conversion is useful for files received from CP/M systems. +With YMODEM, each file name is converted to lower case +unless it contains one or more lower case letters. + + +.B Rx +receives a single +.I file +with XMODEM or XMODEM-1k protocol. +The user should determine when +the 1024 byte block length +actually improves throughput without causing problems. +The user must supply the file name to both sending and receiving programs. +Up to 1023 garbage characters may be added to the received file. + +.B Gz +is a shell script which calls +.I sz +to command Pro-YAM or ZCOMM to transmit the specified files. +Pathnames used with +.I gz +must be escaped if they have special significance to the Unix shell. +.br +EXAMPLE: +gz "-a C:*.c D:*.h" + + +.B Rz +may be invoked as +.B rzCOMMAND +(with an optional leading \- as generated by login(1)). +For each received file, +.I rz +will pipe the file to ``COMMAND filename'' +where filename is the name of the transmitted file +with the file contents as standard input. + +Each file transfer is acknowledged when COMMAND exits with 0 status. +A non zero exit status terminates transfers. + +A typical use for this form is +.I rzrmail +which calls rmail(1) +to post mail to the user specified by the transmitted file name. +For example, sending the file "caf" from a PC-DOS system to +.I rzrmail +on a +.SM Unix +system +would result in the contents of the DOS file "caf" being mailed to user "caf". + +On some +.SM Unix +systems, the login directory must contain a link to +COMMAND as login sets SHELL=rsh which disallows absolute +pathnames. +If invoked with a leading ``v'', +.I rz +will report progress to /tmp/rzlog. +The following entry works for +.SM Unix +SYS III/V: +.ce +rzrmail::5:1::/bin:/usr/local/rzrmail +If the SHELL environment variable includes +.I "rsh" +or +.I "rksh" +(restricted shell), +.I rz +will not accept absolute pathnames +or references to a parent directory, +will not modify an existing file, and +removes any files received in error. + +If +.B rz +is invoked with stdout and stderr to different datasets, +Verbose is set to 2, causing frame by frame progress reports +to stderr. +This may be disabled with the +.B q +option. + +.PP +The meanings of the available options are: +.PP +.PD 0 +.TP +.B a +Convert files to +.SM Unix +conventions by stripping carriage returns and all characters +beginning with the first Control Z (CP/M end of file). +.TP +.B b +Binary +(tell it like it is) +file transfer override. +.TP +.B c +Request 16 bit CRC. +XMODEM file transfers default to 8 bit checksum. +YMODEM and ZMODEM normally use 16 bit CRC. +.TP +.B D +Output file data to /dev/null; for testing. +(Unix only) +.TP +.B e +Force sender to escape all control characters; +normally XON, XOFF, DLE, CR-@-CR, and Ctrl-X are escaped. +.TP +.B p +(ZMODEM) Protect: skip file if destination file exists. +.TP +.B q +Quiet suppresses verbosity. +.TP +.B "t tim" +Change timeout to +.I tim +tenths of seconds. +.TP +.B v +Verbose +causes a list of file +names to be appended to +/tmp/rzlog . +More v's generate more output. +.TP +.B y +Yes, clobber any existing files with the same name. +.PD +.ne 6 +.SH EXAMPLES +.RE +(Pro-YAM command) +.RS +.I +.br +Pro-YAM Command: +.I "sz *.h *.c" +.br +(This automatically invokes +.I rz +on the connected system.) +.RE +.SH SEE ALSO +ZMODEM.DOC, +YMODEM.DOC, +Professional-YAM, +crc(omen), +sz(omen), +usq(omen), +undos(omen) + +Compile time options required +for various operating systems are described in the +source file. +.SH NOTES +ZMODEM's support of XOFF/XON flow control allows proper +operation in many environments that do not support XMODEM uploads. +Unfortunately, not all timesharing systems support input flow control. +The TTY input buffering on some systems may not adequately buffer long blocks +or streaming input at high speed. +You should suspect this problem when you +can't send data to the Unix system at high speeds using ZMODEM, +but YMODEM-1k or XMODEM-1k, +when YMODEM with 128 byte blocks works properly. + +The DSZ or Pro-YAM +.B "zmodem l" +numeric parameter may be set to a value between 64 and 1024 to limit the +burst length ("zmodem pl128"). +Although this compromises ZMODEM's throughput, +ZMODEM's superior reliability remains intact. + +If a program that does not properly implement +the specified file transfer protocol +causes +.I rz +to "hang" the port after a failed transfer, +either wait for +.I rz +to time out or keyboard a dozen Ctrl-X characters. +Every reported instance of this problem has been corrected by using +ZCOMM, Pro-YAM, DSZ, or other program with a correct implementation +of the specified protocol. + +Many programs claiming to support YMODEM only support XMODEM with 1k blocks, +and they often don't get that quite right. + +In the case of a few poorly designed microcomputers, +sending serial data to a tty port +at sustained high speeds +has been known to cause lockups, system halts, kernel panics, +and occasional antisocial behaviour. +This problem is not unique to +.I rz; +CRT terminals with block mode transmission and line noise +have the same effect. When experimenting with high speed +input to a system, consider rebooting the system if the file +transfers are not successful, especially if the personality of +the system appears altered. + +The Unix "ulimit" parameter must be set high enough +to permit large file transfers to Unix. + +32 bit CRC code courtesy Gary S. Brown. +Directory creation code from John Gilmore's PD TAR program. +.SH BUGS +.I Rz +is not intended be called from +.I cu(1), +or other communications programs. +Unix flavors of Omen Technology's +Professional-YAM communications software +are available for dial-out applications. + +.I Rz +does not support ZMODEM Crash Recovery +and many other ZMODEM features. +Unix flavors of Professional-YAM may be linked to "rz" +to support these features. + +Pathnames are restricted to 127 characters. +In XMODEM single file mode, the pathname given on the command line +is still processed as described above. +The ASCII option\'s CR/LF to NL translation merely deletes CR\'s; +undos(omen) performs a more intelligent translation. +.SH "VMS VERSION" +The VMS version does not set the file time. + +VMS C Standard I/O and RMS may interact to modify +file contents unexpectedly. + +The VMS version does not support invocation as +.B rzCOMMAND . +The current VMS version does not support XMODEM, XMODEM-1k, or YMODEM. + +According to the VMS documentation, +the buffered input routine used on the VMS version of +.I rz +introduces a delay +of up to one second for each protocol transaction. +This delay may be significant for very short files. +Removing the "#define BUFREAD" line from rz.c will +eliminate this delay at the expense of increased +CPU utilization. + +For high speed operation, +try increasing the SYSGEN parameter TTY_TYPAHDSZ to 256. + +The VMS version causes DCL to generate a random off the wall +error message under some error conditions; this is a result of +the incompatibility of the VMS "exit" function with the +Unix/MSDOS standard. +.SH "ZMODEM CAPABILITIES" +.I Rz +supports incoming ZMODEM binary (-b), ASCII (-a), +protect (-p), +clobber (-y), +and append (-+) +requests. +Other options sent by the sender are ignored. +The default is protect (-p) and binary (-b). + +The Unix versions support ZMODEM command execution. +.SH FILES +rz.c, crctab.c, rbsb.c, zm.c, zmodem.h Unix source files. + +rz.c, crctab.c, vrzsz.c, zm.c, zmodem.h, vmodem.h, vvmodem.c, +VMS source files. + +/tmp/rzlog stores debugging output generated with -vv option +(rzlog on VMS). diff --git a/src/cmd/zmodem/rz.c b/src/cmd/zmodem/rz.c new file mode 100644 index 0000000..9732d3c --- /dev/null +++ b/src/cmd/zmodem/rz.c @@ -0,0 +1,1532 @@ +#define VERSION "3.02 6-04-89" +#define PUBDIR "/usr/spool/uucppublic" + +/*% cc -compat -M2 -Ox -K -i -DMD % -o rz; size rz; +<-xtx-*> cc386 -Ox -DMD rz.c -o $B/rz; size $B/rz + * + * rz.c By Chuck Forsberg + * + * cc -O rz.c -o rz USG (3.0) Unix + * cc -O -DV7 rz.c -o rz Unix V7, BSD 2.8 - 4.3 + * + * ln rz rb; ln rz rx For either system + * + * ln rz /usr/bin/rzrmail For remote mail. Make this the + * login shell. rzrmail then calls + * rmail(1) to deliver mail. + * + * To compile on VMS: + * + * define LNK$LIBRARY SYS$LIBRARY:VAXCRTL.OLB + * cc rz.c + * cc vvmodem.c + * link rz,vvmodem + * rz :== $disk:[username.subdir]rz.exe + * For high speed, try increasing the SYSGEN parameter TTY_TYPAHDSZ to 256. + * + * + * Unix is a trademark of Western Electric Company + * + * A program for Unix to receive files and commands from computers running + * Professional-YAM, PowerCom, YAM, IMP, or programs supporting XMODEM. + * rz uses Unix buffered input to reduce wasted CPU time. + * + * + * This version implements numerous enhancements including ZMODEM + * Run Length Encoding and variable length headers. These + * features were not funded by the original Telenet development + * contract. + * + * This software may be freely used for non commercial and + * educational (didactic only) purposes. This software may also + * be freely used to support file transfer operations to or from + * licensed Omen Technology products. Any programs which use + * part or all of this software must be provided in source form + * with this notice intact except by written permission from Omen + * Technology Incorporated. + * + * Use of this software for commercial or administrative purposes + * except when exclusively limited to interfacing Omen Technology + * products requires a per port license payment of $20.00 US per + * port (less in quantity). Use of this code by inclusion, + * decompilation, reverse engineering or any other means + * constitutes agreement to these conditions and acceptance of + * liability to license the materials and payment of reasonable + * legal costs necessary to enforce this license agreement. + * + * + * Omen Technology Inc FAX: 503-621-3745 + * Post Office Box 4681 + * Portland OR 97208 + * + * This code is made available in the hope it will be useful, + * BUT WITHOUT ANY WARRANTY OF ANY KIND OR LIABILITY FOR ANY + * DAMAGES OF ANY KIND. + * + * + * + * Iff the program is invoked by rzCOMMAND, output is piped to + * "COMMAND filename" (Unix only) + * + * Some systems (Venix, Coherent, Regulus) may not support tty raw mode + * read(2) the same way as Unix. ONEREAD must be defined to force one + * character reads for these systems. Added 7-01-84 CAF + * + * Alarm signal handling changed to work with 4.2 BSD 7-15-84 CAF + * + * BIX added 6-30-87 to support BIX(TM) upload protocol used by the + * Byte Information Exchange. + * + * NFGVMIN Updated 2-18-87 CAF for Xenix systems where c_cc[VMIN] + * doesn't work properly (even though it compiles without error!), + * + * SEGMENTS=n added 2-21-88 as a model for CP/M programs + * for CP/M-80 systems that cannot overlap modem and disk I/O. + * + * VMS flavor hacks begin with rz version 2.00 + * + * -DMD may be added to compiler command line to compile in + * Directory-creating routines from Public Domain TAR by John Gilmore + * + * HOWMANY may be tuned for best performance + * + * USG UNIX (3.0) ioctl conventions courtesy Jeff Martin + */ +#define SS_NORMAL 0 +#define LOGFILE "/tmp/rzlog" +#include +#include +#include +#include +#include +#include +#include +#include + +#define OK 0 +#define FALSE 0 +#define TRUE 1 +#define ERROR (-1) + +/* + * Max value for HOWMANY is 255. + * A larger value reduces system overhead but may evoke kernel bugs. + * 133 corresponds to an XMODEM/CRC sector + */ +#ifndef HOWMANY +#define HOWMANY 133 +#endif + +/* Ward Christensen / CP/M parameters - Don't change these! */ +#define ENQ 005 +#define CAN ('X'&037) +#define XOFF ('s'&037) +#define XON ('q'&037) +#define SOH 1 +#define STX 2 +#define EOT 4 +#define ACK 6 +#define NAK 025 +#define CPMEOF 032 +#define WANTCRC 0103 /* send C not NAK to get crc not checksum */ +#define TIMEOUT (-2) +#define RCDO (-3) +#define GCOUNT (-4) +#define ERRORMAX 5 +#define RETRYMAX 5 +#define WCEOT (-10) +#define PATHLEN 257 /* ready for 4.2 bsd ? */ +#define UNIXFILE 0xF000 /* The S_IFMT file mask bit for stat */ + +int Zmodem=0; /* ZMODEM protocol requested */ +int Nozmodem = 0; /* If invoked as "rb" */ +unsigned Baudrate = 2400; +unsigned Effbaud = 2400; +#ifdef vax11c +#include "vrzsz.c" /* most of the system dependent stuff here */ +#else +#include "rbsb.c" /* most of the system dependent stuff here */ +#endif +#include "crctab.c" + +char *substr(); +FILE *fout; + +/* + * Routine to calculate the free bytes on the current file system + * ~0 means many free bytes (unknown) + */ +long getfree() +{ + return(~0L); /* many free bytes ... */ +} + +int Lastrx; +int Crcflg; +int Firstsec; +int Eofseen; /* indicates cpm eof (^Z) has been received */ +int errors; +int Restricted=0; /* restricted; no /.. or ../ in filenames */ +#ifdef ONEREAD +/* Sorry, Regulus and some others don't work right in raw mode! */ +int Readnum = 1; /* Number of bytes to ask for in read() from modem */ +#else +int Readnum = HOWMANY; /* Number of bytes to ask for in read() from modem */ +#endif + +#define DEFBYTL 2000000000L /* default rx file size */ +long Bytesleft; /* number of bytes of incoming file left */ +long Modtime; /* Unix style mod time for incoming file */ +int Filemode; /* Unix style mode for incoming file */ +char Pathname[PATHLEN]; +char *Progname; /* the name by which we were called */ + +int Batch=0; +int Topipe=0; +int MakeLCPathname=TRUE; /* make received pathname lower case */ +int Verbose=0; +int Quiet=0; /* overrides logic that would otherwise set verbose */ +int Nflag = 0; /* Don't really transfer files */ +int Rxclob=FALSE; /* Clobber existing file */ +int Rxbinary=FALSE; /* receive all files in bin mode */ +int Rxascii=FALSE; /* receive files in ascii (translate) mode */ +int Thisbinary; /* current file is to be received in bin mode */ +int Blklen; /* record length of received packets */ + +#ifdef SEGMENTS +int chinseg = 0; /* Number of characters received in this data seg */ +char secbuf[1+(SEGMENTS+1)*1024]; +#else +char secbuf[1025]; +#endif + + +char linbuf[HOWMANY]; +int Lleft=0; /* number of characters in linbuf */ +time_t timep[2]; +char Lzmanag; /* Local file management request */ +char zconv; /* ZMODEM file conversion request */ +char zmanag; /* ZMODEM file management request */ +char ztrans; /* ZMODEM file transport request */ +int Zctlesc; /* Encode control characters */ +int Zrwindow = 1400; /* RX window size (controls garbage count) */ + +jmp_buf tohere; /* For the interrupt on RX timeout */ + +#define xsendline(c) sendline(c) + +#include "zm.c" + +#include "zmr.c" + +int tryzhdrtype=ZRINIT; /* Header type to send corresponding to Last rx close */ + +void +alrm(sig) +{ + longjmp(tohere, -1); +} + +/* called by signal interrupt or terminate to clean things up */ +void +bibi(n) +{ + if (Zmodem) + zmputs(Attn); + canit(); mode(0); + fprintf(stderr, "rz: caught signal %d; exiting", n); + cucheck(); + exit(128+n); +} + +main(argc, argv) +char *argv[]; +{ + register char *cp; + register npats; + char *virgin, **patts; + char *getenv(); + int exitcode; + + Rxtimeout = 100; + setbuf(stderr, NULL); + if ((cp=getenv("SHELL")) && (substr(cp, "rsh") || substr(cp, "rksh"))) + Restricted=TRUE; + + from_cu(); +#ifdef vax11c + chkinvok(virgin = PROGNAME); +#else + chkinvok(virgin=argv[0]); /* if called as [-]rzCOMMAND set flag */ +#endif + npats = 0; + while (--argc) { + cp = *++argv; + if (*cp == '-') { + while( *++cp) { + switch(*cp) { + case '\\': + cp[1] = toupper(cp[1]); continue; + case '+': + Lzmanag = ZMAPND; break; + case 'a': + Rxascii=TRUE; break; + case 'b': + Rxbinary=TRUE; break; + case 'c': + Crcflg=TRUE; break; +#ifndef vax11c + case 'D': + Nflag = TRUE; break; +#endif + case 'e': + Zctlesc = 1; break; + case 'p': + Lzmanag = ZMPROT; break; + case 'q': + Quiet=TRUE; Verbose=0; break; + case 't': + if (--argc < 1) { + usage(); + } + Rxtimeout = atoi(*++argv); + if (Rxtimeout<10 || Rxtimeout>1000) + usage(); + break; + case 'w': + if (--argc < 1) { + usage(); + } + Zrwindow = atoi(*++argv); + break; + case 'u': + MakeLCPathname=FALSE; break; + case 'v': + ++Verbose; break; + case 'y': + Rxclob=TRUE; break; + default: + usage(); + } + } + } + else if ( !npats && argc>0) { + if (argv[0][0]) { + npats=argc; + patts=argv; + } + } + } + if (npats > 1) + usage(); + if (Batch && npats) + usage(); + if (Verbose) { + if (freopen(LOGFILE, "a", stderr)==NULL) { + printf("Can't open log file %s\n",LOGFILE); + exit(0200); + } + setbuf(stderr, NULL); + fprintf(stderr, "argv[0]=%s Progname=%s\n", virgin, Progname); + } + if (Fromcu && !Quiet) { + if (Verbose == 0) + Verbose = 2; + } + vfile("%s %s for %s\n", Progname, VERSION, OS); + mode(1); + if (signal(SIGINT, bibi) == SIG_IGN) { + signal(SIGINT, SIG_IGN); signal(SIGKILL, SIG_IGN); + } + else { + signal(SIGINT, bibi); signal(SIGKILL, bibi); + } + signal(SIGTERM, bibi); + if (wcreceive(npats, patts)==ERROR) { + exitcode=0200; + canit(); + } + mode(0); + if (exitcode && !Zmodem) /* bellow again with all thy might. */ + canit(); + if (exitcode) + cucheck(); + exit(exitcode ? exitcode:SS_NORMAL); +} + + +usage() +{ + cucheck(); + fprintf(stderr,"Usage: rz [-abeuvy] (ZMODEM)\n"); + fprintf(stderr,"or rb [-abuvy] (YMODEM)\n"); + fprintf(stderr,"or rx [-abcv] file (XMODEM or XMODEM-1k)\n"); + fprintf(stderr," -a ASCII transfer (strip CR)\n"); + fprintf(stderr," -b Binary transfer for all files\n"); +#ifndef vax11c + fprintf(stderr," -c Use 16 bit CRC (XMODEM)\n"); +#endif + fprintf(stderr," -e Escape control characters (ZMODEM)\n"); + fprintf(stderr," -v Verbose more v's give more info\n"); + fprintf(stderr," -y Yes, clobber existing file if any\n"); + fprintf(stderr,"%s %s for %s by Chuck Forsberg, Omen Technology INC\n", + Progname, VERSION, OS); + fprintf(stderr, "\t\t\042The High Reliability Software\042\n"); + exit(SS_NORMAL); +} +/* + * Debugging information output interface routine + */ +/* VARARGS1 */ +vfile(f, a, b, c, d) +char *f; +long a, b, c, d; +{ + if (Verbose > 2) { + fprintf(stderr, f, a, b, c, d); + fprintf(stderr, "\n"); + } +} + +/* + * Let's receive something already. + */ + +char *rbmsg = +"%s ready. To begin transfer, type \"%s file ...\" to your modem program\r\n\n"; + +wcreceive(argc, argp) +char **argp; +{ + register c; + + if (Batch || argc==0) { + Crcflg=1; + if ( !Quiet) + fprintf(stderr, rbmsg, Progname, Nozmodem?"sb":"sz"); + if (c=tryz()) { + if (c == ZCOMPL) + return OK; + if (c == ERROR) + goto fubar; + c = rzfiles(); + if (c) + goto fubar; + } else { + for (;;) { + if (wcrxpn(secbuf)== ERROR) + goto fubar; + if (secbuf[0]==0) + return OK; + if (procheader(secbuf) == ERROR) + goto fubar; + if (wcrx()==ERROR) + goto fubar; + } + } + } else { + Bytesleft = DEFBYTL; Filemode = 0; Modtime = 0L; + + procheader(""); strcpy(Pathname, *argp); checkpath(Pathname); + fprintf(stderr, "\nrz: ready to receive %s\r\n", Pathname); + if ((fout=fopen(Pathname, "w")) == NULL) + return ERROR; + if (wcrx()==ERROR) + goto fubar; + } + return OK; +fubar: + canit(); +#ifndef vax11c + if (Topipe && fout) { + pclose(fout); return ERROR; + } +#endif + Modtime = 1; + if (fout) + fclose(fout); +#ifndef vax11c + if (Restricted) { + unlink(Pathname); + fprintf(stderr, "\r\nrz: %s removed.\r\n", Pathname); + } +#endif + return ERROR; +} + + +/* + * Fetch a pathname from the other end as a C ctyle ASCIZ string. + * Length is indeterminate as long as less than Blklen + * A null string represents no more files (YMODEM) + */ +wcrxpn(rpn) +char *rpn; /* receive a pathname */ +{ + register c; + +#ifdef NFGVMIN + readline(1); +#else + purgeline(); +#endif + +et_tu: + Firstsec=TRUE; Eofseen=FALSE; + sendline(Crcflg?WANTCRC:NAK); + Lleft=0; /* Do read next time ... */ + while ((c = wcgetsec(rpn, 100)) != 0) { + if (c == WCEOT) { + zperr( "Pathname fetch returned %d", c); + sendline(ACK); + Lleft=0; /* Do read next time ... */ + readline(1); + goto et_tu; + } + return ERROR; + } + sendline(ACK); + return OK; +} + +/* + * Adapted from CMODEM13.C, written by + * Jack M. Wierda and Roderick W. Hart + */ + +wcrx() +{ + register int sectnum, sectcurr; + register char sendchar; + register char *p; + int cblklen; /* bytes to dump this block */ + + Firstsec=TRUE;sectnum=0; Eofseen=FALSE; + sendchar=Crcflg?WANTCRC:NAK; + + for (;;) { + sendline(sendchar); /* send it now, we're ready! */ + Lleft=0; /* Do read next time ... */ + sectcurr=wcgetsec(secbuf, (sectnum&0177)?50:130); + report(sectcurr); + if (sectcurr==(sectnum+1 &0377)) { + sectnum++; + cblklen = Bytesleft>Blklen ? Blklen:Bytesleft; + if (putsec(secbuf, cblklen)==ERROR) + return ERROR; + if ((Bytesleft-=cblklen) < 0) + Bytesleft = 0; + sendchar=ACK; + } + else if (sectcurr==(sectnum&0377)) { + zperr( "Received dup Sector"); + sendchar=ACK; + } + else if (sectcurr==WCEOT) { + if (closeit()) + return ERROR; + sendline(ACK); + Lleft=0; /* Do read next time ... */ + return OK; + } + else if (sectcurr==ERROR) + return ERROR; + else { + zperr( "Sync Error"); + return ERROR; + } + } +} + +/* + * Wcgetsec fetches a Ward Christensen type sector. + * Returns sector number encountered or ERROR if valid sector not received, + * or CAN CAN received + * or WCEOT if eot sector + * time is timeout for first char, set to 4 seconds thereafter + ***************** NO ACK IS SENT IF SECTOR IS RECEIVED OK ************** + * (Caller must do that when he is good and ready to get next sector) + */ + +wcgetsec(rxbuf, maxtime) +char *rxbuf; +int maxtime; +{ + register checksum, wcj, firstch; + register unsigned short oldcrc; + register char *p; + int sectcurr; + + for (Lastrx=errors=0; errors=0; ) { + if ((firstch=readline(1)) < 0) + goto bilge; + oldcrc=updcrc(firstch, oldcrc); + checksum += (*p++ = firstch); + } + if ((firstch=readline(1)) < 0) + goto bilge; + if (Crcflg) { + oldcrc=updcrc(firstch, oldcrc); + if ((firstch=readline(1)) < 0) + goto bilge; + oldcrc=updcrc(firstch, oldcrc); + if (oldcrc & 0xFFFF) + zperr( "CRC"); + else { + Firstsec=FALSE; + return sectcurr; + } + } + else if (((checksum-firstch)&0377)==0) { + Firstsec=FALSE; + return sectcurr; + } + else + zperr( "Checksum"); + } + else + zperr("Sector number garbled"); + } + /* make sure eot really is eot and not just mixmash */ +#ifdef NFGVMIN + else if (firstch==EOT && readline(1)==TIMEOUT) + return WCEOT; +#else + else if (firstch==EOT && Lleft==0) + return WCEOT; +#endif + else if (firstch==CAN) { + if (Lastrx==CAN) { + zperr( "Sender CANcelled"); + return ERROR; + } else { + Lastrx=CAN; + continue; + } + } + else if (firstch==TIMEOUT) { + if (Firstsec) + goto humbug; +bilge: + zperr( "TIMEOUT"); + } + else + zperr( "Got 0%o sector header", firstch); + +humbug: + Lastrx=0; + while(readline(1)!=TIMEOUT) + ; + if (Firstsec) { + sendline(Crcflg?WANTCRC:NAK); + Lleft=0; /* Do read next time ... */ + } else { + maxtime=40; sendline(NAK); + Lleft=0; /* Do read next time ... */ + } + } + /* try to stop the bubble machine. */ + canit(); + return ERROR; +} + +#ifndef vax11c +/* + * This version of readline is reasoably well suited for + * reading many characters. + * (except, currently, for the Regulus version!) + * + * timeout is in tenths of seconds + */ +readline(timeout) +int timeout; +{ + register n; + static char *cdq; /* pointer for removing chars from linbuf */ + + if (--Lleft >= 0) { + if (Verbose > 8) { + fprintf(stderr, "%02x ", *cdq&0377); + } + return (*cdq++ & 0377); + } + n = timeout/10; + if (n < 2) + n = 3; + if (Verbose > 5) + fprintf(stderr, "Calling read: alarm=%d Readnum=%d ", + n, Readnum); + if (setjmp(tohere)) { +#ifdef TIOCFLUSH +/* ioctl(0, TIOCFLUSH, 0); */ +#endif + Lleft = 0; + if (Verbose>1) + fprintf(stderr, "Readline:TIMEOUT\n"); + return TIMEOUT; + } + signal(SIGALRM, alrm); alarm(n); + Lleft=read(0, cdq=linbuf, Readnum); + alarm(0); + if (Verbose > 5) { + fprintf(stderr, "Read returned %d bytes\n", Lleft); + } + if (Lleft < 1) + return TIMEOUT; + --Lleft; + if (Verbose > 8) { + fprintf(stderr, "%02x ", *cdq&0377); + } + return (*cdq++ & 0377); +} + + + +/* + * Purge the modem input queue of all characters + */ +purgeline() +{ + Lleft = 0; +#ifdef USG + ioctl(0, TCFLSH, 0); +#else + lseek(0, 0L, 2); +#endif +} +#endif + + +/* + * Process incoming file information header + */ +procheader(name) +char *name; +{ + register char *openmode, *p, **pp; + + /* set default parameters and overrides */ + openmode = "w"; + Thisbinary = (!Rxascii) || Rxbinary; + if (Lzmanag) + zmanag = Lzmanag; + + /* + * Process ZMODEM remote file management requests + */ + if (!Rxbinary && zconv == ZCNL) /* Remote ASCII override */ + Thisbinary = 0; + if (zconv == ZCBIN) /* Remote Binary override */ + Thisbinary = TRUE; + else if (zmanag == ZMAPND) + openmode = "a"; + +#ifndef BIX + /* Check for existing file */ + if (!Rxclob && (zmanag&ZMMASK) != ZMCLOB && (fout=fopen(name, "r"))) { + fclose(fout); return ERROR; + } +#endif + + Bytesleft = DEFBYTL; Filemode = 0; Modtime = 0L; + + p = name + 1 + strlen(name); + if (*p) { /* file coming from Unix or DOS system */ + sscanf(p, "%ld%lo%o", &Bytesleft, &Modtime, &Filemode); +#ifndef vax11c + if (Filemode & UNIXFILE) + ++Thisbinary; +#endif + if (Verbose) { + fprintf(stderr, "Incoming: %s %ld %lo %o\n", + name, Bytesleft, Modtime, Filemode); + } + } + +#ifdef BIX + if ((fout=fopen("scratchpad", openmode)) == NULL) + return ERROR; + return OK; +#else + + else { /* File coming from CP/M system */ + for (p=name; *p; ++p) /* change / to _ */ + if ( *p == '/') + *p = '_'; + + if ( *--p == '.') /* zap trailing period */ + *p = 0; + } + +#ifndef vax11c + if (!Zmodem && MakeLCPathname && !IsAnyLower(name) + && !(Filemode&UNIXFILE)) + uncaps(name); +#endif + if (Topipe > 0) { + sprintf(Pathname, "%s %s", Progname+2, name); + if (Verbose) + fprintf(stderr, "Topipe: %s %s\n", + Pathname, Thisbinary?"BIN":"ASCII"); +#ifndef vax11c + if ((fout=popen(Pathname, "w")) == NULL) + return ERROR; +#endif + } else { + strcpy(Pathname, name); + if (Verbose) { + fprintf(stderr, "Receiving %s %s %s\n", + name, Thisbinary?"BIN":"ASCII", openmode); + } + checkpath(name); + if (Nflag) + name = "/dev/null"; +#ifndef vax11c + if (name[0] == '!' || name[0] == '|') { + if ( !(fout = popen(name+1, "w"))) { + return ERROR; + } + Topipe = -1; return(OK); + } +#endif +#ifdef MD + fout = fopen(name, openmode); + if ( !fout) + if (make_dirs(name)) + fout = fopen(name, openmode); +#else + fout = fopen(name, openmode); +#endif + if ( !fout) + return ERROR; + } + return OK; +#endif /* BIX */ +} + +#ifdef MD +/* + * Directory-creating routines from Public Domain TAR by John Gilmore + */ + +/* + * After a file/link/symlink/dir creation has failed, see if + * it's because some required directory was not present, and if + * so, create all required dirs. + */ +make_dirs(pathname) +register char *pathname; +{ + register char *p; /* Points into path */ + int madeone = 0; /* Did we do anything yet? */ + int save_errno = errno; /* Remember caller's errno */ + char *strchr(); + + if (errno != ENOENT) + return 0; /* Not our problem */ + + for (p = strchr(pathname, '/'); p != NULL; p = strchr(p+1, '/')) { + /* Avoid mkdir of empty string, if leading or double '/' */ + if (p == pathname || p[-1] == '/') + continue; + /* Avoid mkdir where last part of path is '.' */ + if (p[-1] == '.' && (p == pathname+1 || p[-2] == '/')) + continue; + *p = 0; /* Truncate the path there */ + if ( !mkdir(pathname, 0777)) { /* Try to create it as a dir */ + vfile("Made directory %s\n", pathname); + madeone++; /* Remember if we made one */ + *p = '/'; + continue; + } + *p = '/'; + if (errno == EEXIST) /* Directory already exists */ + continue; + /* + * Some other error in the mkdir. We return to the caller. + */ + break; + } + errno = save_errno; /* Restore caller's errno */ + return madeone; /* Tell them to retry if we made one */ +} + +#if (MD != 2) +#define TERM_SIGNAL(status) ((status) & 0x7F) +#define TERM_COREDUMP(status) (((status) & 0x80) != 0) +#define TERM_VALUE(status) ((status) >> 8) +/* + * Make a directory. Compatible with the mkdir() system call on 4.2BSD. + */ +mkdir(dpath, dmode) +char *dpath; +int dmode; +{ + int cpid, status; + struct stat statbuf; + + if (stat(dpath,&statbuf) == 0) { + errno = EEXIST; /* Stat worked, so it already exists */ + return -1; + } + + /* If stat fails for a reason other than non-existence, return error */ + if (errno != ENOENT) return -1; + + switch (cpid = fork()) { + + case -1: /* Error in fork() */ + return(-1); /* Errno is set already */ + + case 0: /* Child process */ + /* + * Cheap hack to set mode of new directory. Since this + * child process is going away anyway, we zap its umask. + * FIXME, this won't suffice to set SUID, SGID, etc. on this + * directory. Does anybody care? + */ + status = umask(0); /* Get current umask */ + status = umask(status | (0777 & ~dmode)); /* Set for mkdir */ + execl("/bin/mkdir", "mkdir", dpath, (char *)0); + _exit(-1); /* Can't exec /bin/mkdir */ + + default: /* Parent process */ + while (cpid != wait(&status)) ; /* Wait for kid to finish */ + } + + if (TERM_SIGNAL(status) != 0 || TERM_VALUE(status) != 0) { + errno = EIO; /* We don't know why, but */ + return -1; /* /bin/mkdir failed */ + } + + return 0; +} +#endif /* MD != 2 */ +#endif /* MD */ + +/* + * Putsec writes the n characters of buf to receive file fout. + * If not in binary mode, carriage returns, and all characters + * starting with CPMEOF are discarded. + */ +putsec(buf, n) +char *buf; +register n; +{ + register char *p; + + if (n == 0) + return OK; + if (Thisbinary) { + for (p=buf; --n>=0; ) + putc( *p++, fout); + } + else { + if (Eofseen) + return OK; + for (p=buf; --n>=0; ++p ) { + if ( *p == '\r') + continue; + if (*p == CPMEOF) { + Eofseen=TRUE; return OK; + } + putc(*p ,fout); + } + } + return OK; +} + +#ifndef vax11c +/* + * Send a character to modem. Small is beautiful. + */ +sendline(c) +{ + char d; + + d = c; + if (Verbose>6) + fprintf(stderr, "Sendline: %x\n", c); + write(1, &d, 1); +} + +flushmo() {} +#endif + + + + + +/* make string s lower case */ +uncaps(s) +register char *s; +{ + for ( ; *s; ++s) + if (isupper(*s)) + *s = tolower(*s); +} +/* + * IsAnyLower returns TRUE if string s has lower case letters. + */ +IsAnyLower(s) +register char *s; +{ + for ( ; *s; ++s) + if (islower(*s)) + return TRUE; + return FALSE; +} + +/* + * substr(string, token) searches for token in string s + * returns pointer to token within string if found, NULL otherwise + */ +char * +substr(s, t) +register char *s,*t; +{ + register char *ss,*tt; + /* search for first char of token */ + for (ss=s; *s; s++) + if (*s == *t) + /* compare token with substring */ + for (ss=s,tt=t; ;) { + if (*tt == 0) + return s; + if (*ss++ != *tt++) + break; + } + return NULL; +} + +/* + * Log an error + */ +/*VARARGS1*/ +zperr(s,p,u) +char *s, *p, *u; +{ + if (Verbose <= 0) + return; + fprintf(stderr, "Retry %d: ", errors); + fprintf(stderr, s, p, u); + fprintf(stderr, "\n"); +} + +/* send cancel string to get the other end to shut up */ +canit() +{ + static char canistr[] = { + 24,24,24,24,24,24,24,24,24,24,8,8,8,8,8,8,8,8,8,8,0 + }; + +#ifdef vax11c + raw_wbuf(strlen(canistr), canistr); + purgeline(); +#else + printf(canistr); + Lleft=0; /* Do read next time ... */ + fflush(stdout); +#endif +} + + +report(sct) +int sct; +{ + if (Verbose>1) + fprintf(stderr,"%03d%c",sct,sct%10? ' ' : '\r'); +} + +/* + * If called as [-][dir/../]vrzCOMMAND set Verbose to 1 + * If called as [-][dir/../]rzCOMMAND set the pipe flag + * If called as rb use YMODEM protocol + */ +chkinvok(s) +char *s; +{ + register char *p; + + p = s; + while (*p == '-') + s = ++p; + while (*p) + if (*p++ == '/') + s = p; + if (*s == 'v') { + Verbose=1; ++s; + } + Progname = s; + if (s[0]=='r' && s[1]=='z') + Batch = TRUE; + if (s[0]=='r' && s[1]=='b') + Batch = Nozmodem = TRUE; + if (s[2] && s[0]=='r' && s[1]=='b') + Topipe = 1; + if (s[2] && s[0]=='r' && s[1]=='z') + Topipe = 1; +} + +/* + * Totalitarian Communist pathname processing + */ +checkpath(name) +char *name; +{ + if (Restricted) { + if (fopen(name, "r") != NULL) { + canit(); + fprintf(stderr, "\r\nrz: %s exists\n", name); + bibi(-1); + } + /* restrict pathnames to current tree or uucppublic */ + if ( substr(name, "../") + || (name[0]== '/' && strncmp(name, PUBDIR, strlen(PUBDIR))) ) { + canit(); + fprintf(stderr,"\r\nrz:\tSecurity Violation\r\n"); + bibi(-1); + } + } +} + +/* + * Initialize for Zmodem receive attempt, try to activate Zmodem sender + * Handles ZSINIT frame + * Return ZFILE if Zmodem filename received, -1 on error, + * ZCOMPL if transaction finished, else 0 + */ +tryz() +{ + register c, n; + register cmdzack1flg; + + if (Nozmodem) /* Check for "rb" program name */ + return 0; + + + for (n=Zmodem?15:5; --n>=0; ) { + /* Set buffer length (0) and capability flags */ +#ifdef SEGMENTS + stohdr(SEGMENTS*1024L); +#else + stohdr(0L); +#endif +#ifdef CANBREAK + Txhdr[ZF0] = CANFC32|CANFDX|CANOVIO|CANBRK; +#else + Txhdr[ZF0] = CANFC32|CANFDX|CANOVIO; +#endif + if (Zctlesc) + Txhdr[ZF0] |= TESCCTL; + Txhdr[ZF0] |= CANRLE; + Txhdr[ZF1] = CANVHDR; + /* tryzhdrtype may == ZRINIT */ + zshhdr(4,tryzhdrtype, Txhdr); + if (tryzhdrtype == ZSKIP) /* Don't skip too far */ + tryzhdrtype = ZRINIT; /* CAF 8-21-87 */ +again: + switch (zgethdr(Rxhdr, 0)) { + case ZRQINIT: + if (Rxhdr[ZF3] & 0x80) + Usevhdrs = 1; /* we can var header */ + continue; + case ZEOF: + continue; + case TIMEOUT: + continue; + case ZFILE: + zconv = Rxhdr[ZF0]; + zmanag = Rxhdr[ZF1]; + ztrans = Rxhdr[ZF2]; + if (Rxhdr[ZF3] & ZCANVHDR) + Usevhdrs = TRUE; + tryzhdrtype = ZRINIT; + c = zrdata(secbuf, 1024); + mode(3); + if (c == GOTCRCW) + return ZFILE; + zshhdr(4,ZNAK, Txhdr); + goto again; + case ZSINIT: + Zctlesc = TESCCTL & Rxhdr[ZF0]; + if (zrdata(Attn, ZATTNLEN) == GOTCRCW) { + stohdr(1L); + zshhdr(4,ZACK, Txhdr); + goto again; + } + zshhdr(4,ZNAK, Txhdr); + goto again; + case ZFREECNT: + stohdr(getfree()); + zshhdr(4,ZACK, Txhdr); + goto again; + case ZCOMMAND: +#ifdef vax11c + return ERROR; +#else + cmdzack1flg = Rxhdr[ZF0]; + if (zrdata(secbuf, 1024) == GOTCRCW) { + if (cmdzack1flg & ZCACK1) + stohdr(0L); + else + stohdr((long)sys2(secbuf)); + purgeline(); /* dump impatient questions */ + do { + zshhdr(4,ZCOMPL, Txhdr); + } + while (++errors<20 && zgethdr(Rxhdr,1) != ZFIN); + ackbibi(); + if (cmdzack1flg & ZCACK1) + exec2(secbuf); + return ZCOMPL; + } + zshhdr(4,ZNAK, Txhdr); goto again; +#endif + case ZCOMPL: + goto again; + default: + continue; + case ZFIN: + ackbibi(); return ZCOMPL; + case ZCAN: + return ERROR; + } + } + return 0; +} + +/* + * Receive 1 or more files with ZMODEM protocol + */ +rzfiles() +{ + register c; + + for (;;) { + switch (c = rzfile()) { + case ZEOF: + case ZSKIP: + switch (tryz()) { + case ZCOMPL: + return OK; + default: + return ERROR; + case ZFILE: + break; + } + continue; + default: + return c; + case ERROR: + return ERROR; + } + } +} + +/* + * Receive a file with ZMODEM protocol + * Assumes file name frame is in secbuf + */ +rzfile() +{ + register c, n; + long rxbytes; + + Eofseen=FALSE; + if (procheader(secbuf) == ERROR) { + return (tryzhdrtype = ZSKIP); + } + + n = 20; rxbytes = 0l; + + for (;;) { +#ifdef SEGMENTS + chinseg = 0; +#endif + stohdr(rxbytes); + zshhdr(4,ZRPOS, Txhdr); +nxthdr: + switch (c = zgethdr(Rxhdr, 0)) { + default: + vfile("rzfile: zgethdr returned %d", c); + return ERROR; + case ZNAK: + case TIMEOUT: +#ifdef SEGMENTS + putsec(secbuf, chinseg); + chinseg = 0; +#endif + if ( --n < 0) { + vfile("rzfile: zgethdr returned %d", c); + return ERROR; + } + case ZFILE: + zrdata(secbuf, 1024); + continue; + case ZEOF: +#ifdef SEGMENTS + putsec(secbuf, chinseg); + chinseg = 0; +#endif + if (rclhdr(Rxhdr) != rxbytes) { + /* + * Ignore eof if it's at wrong place - force + * a timeout because the eof might have gone + * out before we sent our zrpos. + */ + errors = 0; goto nxthdr; + } + if (closeit()) { + tryzhdrtype = ZFERR; + vfile("rzfile: closeit returned <> 0"); + return ERROR; + } + vfile("rzfile: normal EOF"); + return c; + case ERROR: /* Too much garbage in header search error */ +#ifdef SEGMENTS + putsec(secbuf, chinseg); + chinseg = 0; +#endif + if ( --n < 0) { + vfile("rzfile: zgethdr returned %d", c); + return ERROR; + } + zmputs(Attn); + continue; + case ZSKIP: +#ifdef SEGMENTS + putsec(secbuf, chinseg); + chinseg = 0; +#endif + Modtime = 1; + closeit(); + vfile("rzfile: Sender SKIPPED file"); + return c; + case ZDATA: + if (rclhdr(Rxhdr) != rxbytes) { + if ( --n < 0) { + return ERROR; + } +#ifdef SEGMENTS + putsec(secbuf, chinseg); + chinseg = 0; +#endif + zmputs(Attn); continue; + } +moredata: + if (Verbose>1) + fprintf(stderr, "\r%7ld ZMODEM%s ", + rxbytes, Crc32r?" CRC-32":""); +#ifdef SEGMENTS + if (chinseg >= (1024 * SEGMENTS)) { + putsec(secbuf, chinseg); + chinseg = 0; + } + switch (c = zrdata(secbuf+chinseg, 1024)) +#else + switch (c = zrdata(secbuf, 1024)) +#endif + { + case ZCAN: +#ifdef SEGMENTS + putsec(secbuf, chinseg); + chinseg = 0; +#endif + vfile("rzfile: zgethdr returned %d", c); + return ERROR; + case ERROR: /* CRC error */ +#ifdef SEGMENTS + putsec(secbuf, chinseg); + chinseg = 0; +#endif + if ( --n < 0) { + vfile("rzfile: zgethdr returned %d", c); + return ERROR; + } + zmputs(Attn); + continue; + case TIMEOUT: +#ifdef SEGMENTS + putsec(secbuf, chinseg); + chinseg = 0; +#endif + if ( --n < 0) { + vfile("rzfile: zgethdr returned %d", c); + return ERROR; + } + continue; + case GOTCRCW: + n = 20; +#ifdef SEGMENTS + chinseg += Rxcount; + putsec(secbuf, chinseg); + chinseg = 0; +#else + putsec(secbuf, Rxcount); +#endif + rxbytes += Rxcount; + stohdr(rxbytes); + zshhdr(4,ZACK, Txhdr); + sendline(XON); + goto nxthdr; + case GOTCRCQ: + n = 20; +#ifdef SEGMENTS + chinseg += Rxcount; +#else + putsec(secbuf, Rxcount); +#endif + rxbytes += Rxcount; + stohdr(rxbytes); + zshhdr(4,ZACK, Txhdr); + goto moredata; + case GOTCRCG: + n = 20; +#ifdef SEGMENTS + chinseg += Rxcount; +#else + putsec(secbuf, Rxcount); +#endif + rxbytes += Rxcount; + goto moredata; + case GOTCRCE: + n = 20; +#ifdef SEGMENTS + chinseg += Rxcount; +#else + putsec(secbuf, Rxcount); +#endif + rxbytes += Rxcount; + goto nxthdr; + } + } + } +} + +/* + * Send a string to the modem, processing for \336 (sleep 1 sec) + * and \335 (break signal) + */ +zmputs(s) +char *s; +{ + register c; + + while (*s) { + switch (c = *s++) { + case '\336': + sleep(1); continue; + case '\335': + sendbrk(); continue; + default: + sendline(c); + } + } +} + +/* + * Close the receive dataset, return OK or ERROR + */ +closeit() +{ + time_t time(); + +#ifndef vax11c + if (Topipe) { + if (pclose(fout)) { + return ERROR; + } + return OK; + } +#endif + if (fclose(fout)==ERROR) { + fprintf(stderr, "file close ERROR\n"); + return ERROR; + } +#ifndef vax11c + if (Modtime) { + timep[0] = time(NULL); + timep[1] = Modtime; + utime(Pathname, timep); + } +#endif + if ((Filemode&S_IFMT) == S_IFREG) + chmod(Pathname, (07777 & Filemode)); + return OK; +} + +/* + * Ack a ZFIN packet, let byegones be byegones + */ +ackbibi() +{ + register n; + + vfile("ackbibi:"); + Readnum = 1; + stohdr(0L); + for (n=3; --n>=0; ) { + purgeline(); + zshhdr(4,ZFIN, Txhdr); + switch (readline(100)) { + case 'O': + readline(1); /* Discard 2nd 'O' */ + vfile("ackbibi complete"); + return; + case RCDO: + return; + case TIMEOUT: + default: + break; + } + } +} + + + +/* + * Local console output simulation + */ +bttyout(c) +{ + if (Verbose || Fromcu) + putc(c, stderr); +} + +#ifndef vax11c +/* + * Strip leading ! if present, do shell escape. + */ +sys2(s) +register char *s; +{ + if (*s == '!') + ++s; + return system(s); +} +/* + * Strip leading ! if present, do exec. + */ +exec2(s) +register char *s; +{ + if (*s == '!') + ++s; + mode(0); + execl("/bin/sh", "sh", "-c", s); +} +#endif +/* End of rz.c */ diff --git a/src/cmd/zmodem/sz.1 b/src/cmd/zmodem/sz.1 new file mode 100644 index 0000000..5dbe84c --- /dev/null +++ b/src/cmd/zmodem/sz.1 @@ -0,0 +1,487 @@ +'\" Revision Level +'\" Last Delta 07-01-89 +.TH SZ 1 OMEN +.SH NAME +sx, sb, sz \- XMODEM, YMODEM, ZMODEM file send +.SH SYNOPSIS +sz +.RB [\- +abdefkLlNnopqTtuvyYZ ] +.I file ... +.br +sb +.RB [\- adfkqtuv ] +.I file ... +.br +sx +.RB [\- akqtuv ] +.I file +.br +sz +.RB [\- oqtv ] +.B "-c COMMAND" +.br +sz +.RB [\- oqtv ] +.B "-i COMMAND" +.br +sz -TT +.SH DESCRIPTION +.B Sz +uses the ZMODEM, YMODEM or XMODEM error correcting protocol to send +one or more files over a dial-in serial port to a variety of programs running under +PC-DOS, CP/M, Unix, VMS, and other operating systems. + + +.B +.I Sz +is not intended be called from +.I cu(1) +or other communications programs. +Unix flavors of Omen Technology's +Professional-YAM communications software +are available for dial-out applications. +.R + + +.B Sz +sends one or more files with ZMODEM protocol. + +ZMODEM +greatly simplifies file transfers compared to XMODEM. +In addition to a friendly user interface, ZMODEM +provides Personal Computer and other users +an efficient, accurate, and robust file transfer method. + +ZMODEM provides complete +.B "END-TO-END" +data integrity between application programs. +ZMODEM's 32 bit CRC catches errors +that sneak into even the most advanced networks. + +Advanced file management features include +AutoDownload (Automatic file Download initiated without user intervention), +Display of individual and total file lengths and transmission time estimates, +Crash Recovery, +selective file transfers, +and preservation of +exact file date and length. + +The +.B -y +option instructs the receiver to open the file for writing unconditionally. +The +.B -a +option +causes the receiver to convert Unix newlines to PC-DOS carriage returns +and linefeeds. + + +.B Sb +batch sends one or more files with YMODEM or ZMODEM protocol. +The initial ZMODEM initialization is not sent. +When requested by the receiver, +.B sb +supports +.B YMODEM-g +with "cbreak" tty mode, XON/XOFF flow control, +and interrupt character set to CAN (^X). +.B YMODEM-g +(Professional-YAM +.B g +option) +increases throughput over error free channels +(direct connection, X.PC, etc.) +by not acknowledging each transmitted sector. + +On +.SM Unix +systems, additional information about the file is transmitted. +If the receiving program uses this information, +the transmitted file length controls the exact number of bytes written to +the output dataset, +and the modify time and file mode +are set accordingly. + + +.B Sx +sends a single +.I file +with +.B XMODEM +or +.B XMODEM-1k +protocol +(sometimes incorrectly called "ymodem"). +The user must supply the file name to both sending and receiving programs. + +Iff +.B sz +is invoked with $SHELL set and iff that variable contains the +string +.I "rsh" +or +.I "rksh" +(restricted shell), +.B sz +operates in restricted mode. +Restricted mode restricts pathnames to the current directory and +PUBDIR (usually /usr/spool/uucppublic) and/or subdirectories +thereof. + + +The fourth form sends a single COMMAND to a ZMODEM receiver for execution. +.B Sz +exits with the COMMAND return value. +If COMMAND includes spaces or characters special to the shell, +it must be quoted. + + +The fifth form sends a single COMMAND to a ZMODEM receiver for execution. +.B Sz +exits as soon as the receiver has correctly received the command, +before it is executed. + + +The sixth form (sz -TT) +attempts to output all 256 code combinations to the terminal. +In you are having difficulty sending files, +this command lets you see which character codes are being +eaten by the operating system. + + +If +.B sz +is invoked with stdout and stderr to different datasets, +Verbose is set to 2, causing frame by frame progress reports +to stderr. +This may be disabled with the +.B q +option. +.PP +The meanings of the available options are: +.PP +.PD 0 +.TP +\\ +(backslash) (VMS) Force the next option letter to upper case. +.TP +.B + +Instruct the receiver to append transmitted data to an existing file +(ZMODEM only). +.TP +.B a +Convert NL characters in the transmitted file to CR/LF. +This is done by the sender for XMODEM and YMODEM, by the receiver +for ZMODEM. +.TP +.B b +(ZMODEM) Binary override: transfer file without any translation. +.TP +.B "c COMMAND" +Send COMMAND to the receiver for execution, return with COMMAND\'s exit status. +.TP +.B d +Change all instances of "." to "/" in the transmitted pathname. +Thus, C.omenB0000 (which is unacceptable to MSDOS or CP/M) +is transmitted as C/omenB0000. +If the resultant filename has more than 8 characters in the stem, +a "." is inserted to allow a total of eleven. +.TP +.B e +Escape all control characters; +normally XON, XOFF, DLE, CR-@-CR, and Ctrl-X are escaped. +.TP +.B f +Send Full pathname. +Normally directory prefixes are stripped from the transmitted +filename. +.TP +.B "i COMMAND" +Send COMMAND to the receiver for execution, return Immediately +upon the receiving program's successful recption of the command. +.TP +.B k +(XMODEM/YMODEM) Send files using 1024 byte blocks +rather than the default 128 byte blocks. +1024 byte packets speed file transfers at high bit rates. +(ZMODEM streams the data for the best possible throughput.) +.TP +.B "L N" +Use ZMODEM sub-packets of length N. +A larger N (32 <= N <= 1024) gives slightly higher throughput, +a smaller N speeds error recovery. +The default is 128 below 300 baud, 256 above 300 baud, or 1024 above 2400 baud. +.TP +.B "l N" +Wait for the receiver to acknowledge correct data every +.B N +(32 <= N <= 1024) +characters. +This may be used to avoid network overrun when XOFF flow control is lacking. +.TP +.B n +(ZMODEM) Send each file if +destination file does not exist. +Overwrite destination file if +source file is newer than the destination file. +.TP +.B N +(ZMODEM) Send each file if +destination file does not exist. +Overwrite destination file if +source file is newer or longer than the destination file. +.TP +.B o +(ZMODEM) Disable automatic selection of 32 bit CRC. +.TP +.B p +(ZMODEM) Protect existing destination files by skipping transfer if the +destination file exists. +.TP +.B q +Quiet suppresses verbosity. +.TP +.B r +(ZMODEM) Resume interrupted file transfer. +If the source file is longer than the destination file, +the transfer commences at the offset in the source file that equals +the length of the destination file. +.TP +.B rr +As above, but compares the files (the portion common to sender and reciever) +before resuming the transfer. +.TP +.B "t tim" +Change timeout to +.I tim +tenths of seconds. +.TP +.B u +Unlink the file after successful transmission. +.TP +.B "w N" +Limit the transmit window size to N bytes (ZMODEM). +.TP +.B v +Verbose +causes a list of file +names to be appended to +/tmp/szlog . +More v's generate more output. +.TP +.B y +Instruct a ZMODEM receiving program to overwrite any existing file +with the same name. +.TP +.B Y +Instruct a ZMODEM receiving program to overwrite any existing file +with the same name, +and to skip any source files that do have a file with the same +pathname on the destination system. +.TP +.B Z +Use ZMODEM file compression to speed file transfer. +.PD +.SH EXAMPLES +.ne 7 +.B "ZMODEM File Transfer" +(Unix to DSZ/ZCOMM/Professional-YAM) +.br +.B "% sz \-a *.c" +.br +This single command transfers all .c files in the current Unix directory +with conversion +.RB ( \-a ) +to end of line conventions appropriate to the receiving environment. +With ZMODEM AutoDownload enabled, Professional-YAM and ZCOMM +will automatically recieve +the files after performing a security check. + +.br +.B "% sz \-Yan *.c *.h" +.br +Send only the .c and .h files that exist on both systems, +and are newer on the sending system than the +corresponding version on the receiving system, converting Unix to +DOS text format. +.br +.B +$ sz -\\Yan file1.c file2.c file3.c foo.h baz.h +.R +(for VMS) +.br + +.B "ZMODEM Command Download" +(Unix to Professional-YAM) +.br + cpszall:all + sz \-c "c:;cd /yam/dist" + sz \-ya $(YD)/*.me + sz \-yqb y*.exe + sz \-c "cd /yam" + sz \-i "!insms" +.br +This Makefile fragment uses +.B sz +to issue commands to Professional-YAM to change current disk and directory. +Next, +.B sz +transfers the +.I .me +files from the $YD directory, commanding the receiver to overwrite the old files +and to convert from Unix end of line conventions to PC-DOS conventions. +The third line transfers some +.I .exe +files. +The fourth and fifth lines command Pro-YAM to +change directory and execute a PC-DOS batch file +.I insms . +Since the batch file takes considerable time, the +.B "\-i" +form is used to allow +.B sz +to exit immediately. + +.B "XMODEM File Transfer" +(Unix to Crosstalk) +.br +% +.B "sx \-a foo.c" +.br +.B "ESC" +.br +.B "rx foo.c" +.br +The above three commands transfer a single file +from Unix to a PC and Crosstalk with +.I sz +translating Unix newlines to DOS CR/LF. +This combination is much slower and far less reliable than ZMODEM. +.SH ERROR MESSAGES +"Caught signal 99" +indicates the program was not properly compiled, +refer to "bibi(99)" in rbsb.c for details. +.SH SEE ALSO +rz(omen), +ZMODEM.DOC, +YMODEM.DOC, +Professional-YAM, +crc(omen), +sq(omen), +todos(omen), +tocpm(omen), +tomac(omen), +yam(omen) + +Compile time options required for various operating systems are described in +the source file. +.SH "VMS VERSION" +The VMS version does not support wild cards. +Because of VMS DCL, upper case option letters muse be represented +by \\ proceding the letter. + +The current VMS version does not support XMODEM, XMODEM-1k, or YMODEM. + +VMS C Standard I/O and RMS may interact to modify the file contents. +.SH FILES +32 bit CRC code courtesy Gary S. Brown. + +sz.c, crctab.c, rbsb.c, zm.c, zmodem.h Unix source files + +sz.c, crctab.c, vrzsz.c, zm.c, zmodem.h, vmodem.h, vvmodem.c, +VMS source files. + +/tmp/szlog stores debugging output (sz -vv) +(szlog on VMS). +.SH "TESTING FEATURE" +The command "sz -T file" +exercises the +.B Attn +sequence error recovery by commanding +errors with unterminated packets. +The receiving program should complain five times about +binary data packets being too long. +Each time +.B sz +is interrupted, +it should send a ZDATA header followed by another defective packet. +If the receiver does not detect five long data packets, +the +.B Attn +sequence is not interrupting the sender, and the +.B Myattn +string in +.B sz.c +must be modified. + +After 5 packets, +.B sz +stops the "transfer" and +prints the total number of characters "sent" (Tcount). +The difference between Tcount and 5120 represents the number of characters +stored in various buffers when the Attn sequence is generated. +.SH NOTES +.I Sz +is not designed be called from +.I cu(1) +or other outdial communications programs. +Unix flavors of Omen Technology's +Professional-YAM communications software +are available for dial-out applications. + +When using TrailBlazer or other buffered modems at high speed, +particular attention must be paid to flow control. +The modem and Unix must agree on the flow control method. +Sz on USG (SYS III/V) systems uses XON/XOFF flow control. +If flow control cannot be properly set up, +Try a "-w 2048" option to enforce protocol level flow control. +Experiment with different window sizes for best results. + + +If a program that does not properly implement +the specified file transfer protocol +causes +.I sb +to "hang" the port after a failed transfer, +either wait for +.I sb +to time out or keyboard a dozen Ctrl-X characters. +Every reported instance of this problem has been corrected by using +ZCOMM, Pro-YAM, DSZ, or other program with a correct implementation +of the specified protocol. + +Many programs claiming to support YMODEM only support XMODEM with 1k blocks, +and they often don't get that quite right. +XMODEM transfers add up to 127 garbage bytes per file. +XMODEM-1k and YMODEM-1k transfers use 128 byte blocks +to avoid extra padding. + +YMODEM programs use the file length transmitted at the beginning of the +transfer to prune the file to the correct length; this may cause problems with +source files that grow during the course of the transfer. +This problem does not pertain to ZMODEM transfers, which preserve the exact +file length unconditionally. + +Most ZMODEM options are merely passed to the receiving program; +some programs do not implement all of these options. + +Circular buffering and a ZMODEM sliding window should be used +when input is from pipes instead of acknowledging frames each 1024 bytes. +If no files can be opened, +.B sz +sends a ZMODEM command to echo a suitable complaint; +perhaps it should check for the presence of at least one accessible file before +getting hot and bothered. + +A few high speed modems have a firmware bug that drops characters when the +direction of high speed transmissson is reversed. +The environment variable ZNULLS may be used to specify the number of nulls to +send before a ZDATA frame. +Values of 101 for a 4.77 mHz PC and 124 for an AT are typical. +.SH BUGS +On at least one BSD system, sz would abend it got within +a few kilobytes of the end of file. +Using the "-w 8192" flag fixed the problem. +The real cause is unknown, perhaps a bug in the kernel TTY output routines. + +The test mode leaves a zero length file on the receiving system. diff --git a/src/cmd/zmodem/sz.c b/src/cmd/zmodem/sz.c new file mode 100644 index 0000000..a256b26 --- /dev/null +++ b/src/cmd/zmodem/sz.c @@ -0,0 +1,2052 @@ +#define VERSION "sz 3.07 2-02-90" +#define PUBDIR "/usr/spool/uucppublic" + +/*% cc -compat -M2 -Ox -K -i -DTXBSIZE=16384 -DNFGVMIN -DREADCHECK sz.c -lx -o sz; size sz + +/*% cc -Zi -DXX -DNFGVMIN -DREADCHECK sz.c -lx -o xsz; size xsz +<-xtx-*> cc -Osal -DTXBSIZE=32768 -DSV sz.c -lx -o $B/sz; size $B/sz + + **************************************************************************** + * + * sz.c By Chuck Forsberg, Omen Technology INC + * + **************************************************************************** + * + * Typical Unix/Xenix/Clone compiles: + * + * cc -O sz.c -o sz USG (SYS III/V) Unix + * cc -O -DSV sz.c -o sz Sys V Release 2 with non-blocking input + * Define to allow reverse channel checking + * cc -O -DV7 sz.c -o sz Unix Version 7, 2.8 - 4.3 BSD + * + * cc -O -K -i -DNFGVMIN -DREADCHECK sz.c -lx -o sz Classic Xenix + * + * ln sz sb **** All versions **** + * ln sz sx **** All versions **** + * + **************************************************************************** + * + * Typical VMS compile and install sequence: + * + * define LNK$LIBRARY SYS$LIBRARY:VAXCRTL.OLB + * cc sz.c + * cc vvmodem.c + * link sz,vvmodem + * sz :== $disk$user2:[username.subdir]sz.exe + * + * If you feel adventureous, remove the #define BADSEEK line + * immediately following the #ifdef vax11c line! Some VMS + * systems know how to fseek, some don't. + * + **************************************************************************** + * + * + * A program for Unix to send files and commands to computers running + * Professional-YAM, PowerCom, YAM, IMP, or programs supporting Y/XMODEM. + * + * Sz uses buffered I/O to greatly reduce CPU time compared to UMODEM. + * + * USG UNIX (3.0) ioctl conventions courtesy Jeff Martin + * + * + * This version implements numerous enhancements including ZMODEM + * Run Length Encoding and variable length headers. These + * features were not funded by the original Telenet development + * contract. + * + * This software may be freely used for non commercial and + * educational (didactic only) purposes. This software may also + * be freely used to support file transfer operations to or from + * licensed Omen Technology products. Any programs which use + * part or all of this software must be provided in source form + * with this notice intact except by written permission from Omen + * Technology Incorporated. + * + * Use of this software for commercial or administrative purposes + * except when exclusively limited to interfacing Omen Technology + * products requires a per port license payment of $20.00 US per + * port (less in quantity). Use of this code by inclusion, + * decompilation, reverse engineering or any other means + * constitutes agreement to these conditions and acceptance of + * liability to license the materials and payment of reasonable + * legal costs necessary to enforce this license agreement. + * + * + * Omen Technology Inc FAX: 503-621-3745 + * Post Office Box 4681 + * Portland OR 97208 + * + * This code is made available in the hope it will be useful, + * BUT WITHOUT ANY WARRANTY OF ANY KIND OR LIABILITY FOR ANY + * DAMAGES OF ANY KIND. + * + * + * 2.1x hacks to avoid VMS fseek() bogosity, allow input from pipe + * -DBADSEEK -DTXBSIZE=32768 + * 2.x has mods for VMS flavor + * + * 1.34 implements tx backchannel garbage count and ZCRCW after ZRPOS + * in accordance with the 7-31-87 ZMODEM Protocol Description + */ + +#ifdef XX +#define XARGSFILE "args" +long Thisflen; +#endif + +char *substr(), *getenv(); + +#define LOGFILE "/tmp/szlog" +#define SS_NORMAL 0 +#include +#include +#include +#include +#include +#include +#include +#include +extern int errno; +#define STATIC + +#define sendline(c) putchar(c & 0377) +#define xsendline(c) putchar(c) + +#define PATHLEN 256 +#define OK 0 +#define FALSE 0 +#ifdef TRUE +#undef TRUE +#endif +#define TRUE 1 +#define ERROR (-1) +/* Ward Christensen / CP/M parameters - Don't change these! */ +#define ENQ 005 +#define CAN ('X'&037) +#define XOFF ('s'&037) +#define XON ('q'&037) +#define SOH 1 +#define STX 2 +#define EOT 4 +#define ACK 6 +#define NAK 025 +#define CPMEOF 032 +#define WANTCRC 0103 /* send C not NAK to get crc not checksum */ +#define WANTG 0107 /* Send G not NAK to get nonstop batch xmsn */ +#define TIMEOUT (-2) +#define RCDO (-3) +#define GCOUNT (-4) +#define RETRYMAX 10 + + +#define HOWMANY 2 +STATIC int Zmodem=0; /* ZMODEM protocol requested by receiver */ +unsigned Baudrate=4800; /* Default, set by first mode() call */ +STATIC unsigned Effbaud = 4800; +STATIC unsigned Txwindow; /* Control the size of the transmitted window */ +STATIC unsigned Txwspac; /* Spacing between zcrcq requests */ +STATIC unsigned Txwcnt; /* Counter used to space ack requests */ +STATIC long Lrxpos; /* Receiver's last reported offset */ +STATIC int errors; + +#ifdef vax11c +#include "vrzsz.c" /* most of the system dependent stuff here */ +#else +#ifdef GENIE +#include "genie.c" /* most of the system dependent stuff here */ +#else +#include "rbsb.c" /* most of the system dependent stuff here */ +#ifdef XX +#undef STAT +#endif +#endif +#endif + +#include "crctab.c" + +STATIC int Filesleft; +STATIC long Totalleft; + +/* + * Attention string to be executed by receiver to interrupt streaming data + * when an error is detected. A pause (0336) may be needed before the + * ^C (03) or after it. + */ +#ifdef READCHECK +STATIC char Myattn[] = { 0 }; +#else +#ifdef USG +STATIC char Myattn[] = { 03, 0336, 0 }; +#else +#ifndef GENIE +STATIC char Myattn[] = { 0 }; +#endif +#endif +#endif + +FILE *in; + +#ifdef BADSEEK +STATIC int Canseek = 0; /* 1: Can seek 0: only rewind -1: neither (pipe) */ +#ifndef TXBSIZE +#define TXBSIZE 16384 /* Must be power of two, < MAXINT */ +#endif +#else +STATIC int Canseek = 1; /* 1: Can seek 0: only rewind -1: neither (pipe) */ +#endif + +#ifdef TXBSIZE +#define TXBMASK (TXBSIZE-1) +STATIC char Txb[TXBSIZE]; /* Circular buffer for file reads */ +STATIC char *txbuf = Txb; /* Pointer to current file segment */ +#else +STATIC char txbuf[1024]; +#endif +STATIC long vpos = 0; /* Number of bytes read from file */ + +STATIC char Lastrx; +STATIC char Crcflg; +STATIC int Verbose=0; +STATIC int Modem2=0; /* XMODEM Protocol - don't send pathnames */ +STATIC int Restricted=0; /* restricted; no /.. or ../ in filenames */ +STATIC int Quiet=0; /* overrides logic that would otherwise set verbose */ +STATIC int Ascii=0; /* Add CR's for brain damaged programs */ +STATIC int Fullname=0; /* transmit full pathname */ +STATIC int Unlinkafter=0; /* Unlink file after it is sent */ +STATIC int Dottoslash=0; /* Change foo.bar.baz to foo/bar/baz */ +STATIC int firstsec; +STATIC int errcnt=0; /* number of files unreadable */ +STATIC int blklen=128; /* length of transmitted records */ +STATIC int Optiong; /* Let it rip no wait for sector ACK's */ +STATIC int Eofseen; /* EOF seen on input set by zfilbuf */ +STATIC int BEofseen; /* EOF seen on input set by fooseek */ +STATIC int Totsecs; /* total number of sectors this file */ +STATIC int Filcnt=0; /* count of number of files opened */ +STATIC int Lfseen=0; +STATIC unsigned Rxbuflen = 16384; /* Receiver's max buffer length */ +STATIC int Tframlen = 0; /* Override for tx frame length */ +STATIC int blkopt=0; /* Override value for zmodem blklen */ +STATIC int Rxflags = 0; +STATIC long bytcnt; +STATIC int Wantfcs32 = TRUE; /* want to send 32 bit FCS */ +STATIC char Lzconv; /* Local ZMODEM file conversion request */ +STATIC char Lzmanag; /* Local ZMODEM file management request */ +STATIC int Lskipnocor; +STATIC char Lztrans; +STATIC int Command; /* Send a command, then exit. */ +STATIC char *Cmdstr; /* Pointer to the command string */ +STATIC int Cmdtries = 11; +STATIC int Cmdack1; /* Rx ACKs command, then do it */ +STATIC int Exitcode; +STATIC int Test; /* 1= Force receiver to send Attn, etc with qbf. */ + /* 2= Character transparency test */ +STATIC char *qbf= + "The quick brown fox jumped over the lazy dog's back 1234567890\r\n"; +STATIC long Lastsync; /* Last offset to which we got a ZRPOS */ +STATIC int Beenhereb4; /* How many times we've been ZRPOS'd same place */ + +STATIC jmp_buf tohere; /* For the interrupt on RX timeout */ +STATIC jmp_buf intrjmp; /* For the interrupt on RX CAN */ + +#ifdef XARGSFILE +char * +mystrsave(s) +char *s; +{ + register char *p; + char *malloc(); + + if (p = malloc(strlen(s)+1) ) { + strcpy(p, s); return p; + } + fprintf(stderr, "No memory for mystrsave!\n"); + exit(1); +} + +/* Remove (presumably) terminating CR and/or LF from string */ +uncrlf(s) +register char *s; +{ + for ( ; *s; ++s) + switch (*s) { + case '\r': + case '\n': + *s = 0; return; + } +} +#endif + + +/* called by signal interrupt or terminate to clean things up */ +void +bibi(n) +{ + canit(); fflush(stdout); mode(0); + fprintf(stderr, "sz: caught signal %d; exiting\n", n); +#ifndef GENIE + if (n == SIGQUIT) + abort(); +#endif + if (n == 99) + fprintf(stderr, "mode(2) in rbsb.c not implemented!!\n"); + cucheck(); + exit(128+n); +} + +/* Called when ZMODEM gets an interrupt (^X) */ +void +onintr(sig) +{ + signal(SIGINT, SIG_IGN); + longjmp(intrjmp, -1); +} + +STATIC int Zctlesc; /* Encode control characters */ +STATIC int Nozmodem = 0; /* If invoked as "sb" */ +STATIC char *Progname = "sz"; +STATIC int Zrwindow = 1400; /* RX window size (controls garbage count) */ +#include "zm.c" + +#include "zmr.c" + +#ifdef XARGSFILE +#define XARGSMAX 256 +char *xargv[XARGSMAX+1]; +#endif + +main(argc, argv) +char *argv[]; +{ + register char *cp; + register npats; + int dm; + char **patts; + static char xXbuf[BUFSIZ]; + + if ((cp = getenv("ZNULLS")) && *cp) + Znulls = atoi(cp); + if ((cp=getenv("SHELL")) && (substr(cp, "rsh") || substr(cp, "rksh"))) + Restricted=TRUE; + from_cu(); +#ifdef vax11c + chkinvok(PROGNAME); +#else + chkinvok(argv[0]); +#endif + + Rxtimeout = 600; + npats=0; + if (argc<2) + usage(); + setbuf(stdout, xXbuf); + while (--argc) { + cp = *++argv; + if (*cp++ == '-' && *cp) { + while ( *cp) { + switch(*cp++) { + case '\\': + *cp = toupper(*cp); continue; + case '+': + Lzmanag = ZMAPND; break; +#ifdef CSTOPB + case '2': + Twostop = TRUE; break; +#endif + case 'a': + Lzconv = ZCNL; + Ascii = TRUE; break; + case 'b': + Lzconv = ZCBIN; break; + case 'C': + if (--argc < 1) { + usage(); + } + Cmdtries = atoi(*++argv); + break; + case 'i': + Cmdack1 = ZCACK1; + /* **** FALL THROUGH TO **** */ + case 'c': + if (--argc != 1) { + usage(); + } + Command = TRUE; + Cmdstr = *++argv; + break; + case 'd': + ++Dottoslash; + /* **** FALL THROUGH TO **** */ + case 'f': + Fullname=TRUE; break; + case 'e': + Zctlesc = 1; break; + case 'k': + blklen=1024; break; + case 'L': + if (--argc < 1) { + usage(); + } + blkopt = atoi(*++argv); + if (blkopt<24 || blkopt>1024) + usage(); + break; + case 'l': + if (--argc < 1) { + usage(); + } + Tframlen = atoi(*++argv); + if (Tframlen<32 || Tframlen>1024) + usage(); + break; + case 'N': + Lzmanag = ZMNEWL; break; + case 'n': + Lzmanag = ZMNEW; break; + case 'o': + Wantfcs32 = FALSE; break; + case 'p': + Lzmanag = ZMPROT; break; + case 'r': + if (Lzconv == ZCRESUM) + Lzmanag = (Lzmanag & ZMMASK) | ZMCRC; + Lzconv = ZCRESUM; break; + case 'q': + Quiet=TRUE; Verbose=0; break; + case 't': + if (--argc < 1) { + usage(); + } + Rxtimeout = atoi(*++argv); + if (Rxtimeout<10 || Rxtimeout>1000) + usage(); + break; + case 'T': + if (++Test > 1) { + chartest(1); chartest(2); + mode(0); exit(SS_NORMAL); + } + break; +#ifndef vax11c + case 'u': + ++Unlinkafter; break; +#endif + case 'v': + ++Verbose; break; + case 'w': + if (--argc < 1) { + usage(); + } + Txwindow = atoi(*++argv); + if (Txwindow < 256) + Txwindow = 256; + Txwindow = (Txwindow/64) * 64; + Txwspac = Txwindow/4; + if (blkopt > Txwspac + || (!blkopt && Txwspac < 1024)) + blkopt = Txwspac; + break; + case 'X': + ++Modem2; break; + case 'Y': + Lskipnocor = TRUE; + /* **** FALLL THROUGH TO **** */ + case 'y': + Lzmanag = ZMCLOB; break; + case 'Z': + case 'z': + Lztrans = ZTRLE; break; + default: + usage(); + } + } + } + else if ( !npats && argc>0) { + if (argv[0][0]) { + npats=argc; + patts=argv; + } + } + } + if (npats < 1 && !Command && !Test) + usage(); + if (Verbose) { + if (freopen(LOGFILE, "a", stderr)==NULL) { + printf("Can't open log file %s\n",LOGFILE); + exit(0200); + } + setbuf(stderr, NULL); + } + if (Fromcu && !Quiet) { + if (Verbose == 0) + Verbose = 2; + } + vfile("%s %s for %s\n", Progname, VERSION, OS); + +#ifdef XARGSFILE + vfile("npats=%d *patts=%s", npats, *patts); + if (npats == 1 && !strcmp(XARGSFILE, *patts)) { + in = fopen(XARGSFILE, "r"); + if (!in) { + printf(stderr, "Can't open / control file!\n"); + exit(2); + } + for (npats=0,argv=patts=xargv; npats>7); + } +#endif + fprintf(stderr, "Give your local XMODEM receive command now.\r\n"); + fflush(stderr); + return OK; + } + zperr("Awaiting pathname nak for %s", *name?name:""); + if ( !Zmodem) + if (getnak()) + return ERROR; + + q = (char *) 0; + if (Dottoslash) { /* change . to . */ + for (p=name; *p; ++p) { + if (*p == '/') + q = p; + else if (*p == '.') + *(q=p) = '/'; + } + if (q && strlen(++q) > 8) { /* If name>8 chars */ + q += 8; /* make it .ext */ + strcpy(name2, q); /* save excess of name */ + *q = '.'; + strcpy(++q, name2); /* add it back */ + } + } + + for (p=name, q=txbuf ; *p; ) + if ((*q++ = *p++) == '/' && !Fullname) + q = txbuf; + *q++ = 0; + p=q; + while (q < (txbuf + 1024)) + *q++ = 0; + if (*name) { +#ifdef XX + if (Thisflen >= 0) { + sprintf(p, "%u 0 0 0 %d %ld", + Thisflen, Filesleft, Totalleft); + Totalleft -= Thisflen; + } +#endif +#ifdef GENIE + else + sprintf(p, "%d", fdes.current_file_size * 1260); + vfile("%s open Binfile=%d size=%ld", name, Binfile, + fdes.current_file_size * 1260); +#endif + +#ifdef STAT +#ifndef XX + if (fstat(fileno(in), &f)!= -1) + sprintf(p, "%lu %lo %o 0 %d %ld", f.st_size, f.st_mtime, + f.st_mode, Filesleft, Totalleft); + Totalleft -= f.st_size; +#endif +#endif + + } + if (--Filesleft <= 0) + Totalleft = 0; + if (Totalleft < 0) + Totalleft = 0; + +#ifdef STAT + /* force 1k blocks if name won't fit in 128 byte block */ + if (txbuf[125]) + blklen=1024; + else { /* A little goodie for IMP/KMD */ + txbuf[127] = (f.st_size + 127) >>7; + txbuf[126] = (f.st_size + 127) >>15; + } +#endif + if (Zmodem) + return zsendfile(txbuf, 1+strlen(p)+(p-txbuf)); + if (wcputsec(txbuf, 0, 128)==ERROR) + return ERROR; + return OK; +} + +getnak() +{ + register firstch; + + Lastrx = 0; + for (;;) { + switch (firstch = readline(800)) { + case ZPAD: + if (getzrxinit()) + return ERROR; + Ascii = 0; /* Receiver does the conversion */ + return FALSE; + case TIMEOUT: + zperr("Timeout on pathname"); + return TRUE; + case WANTG: +#ifdef MODE2OK + mode(2); /* Set cbreak, XON/XOFF, etc. */ +#endif + Optiong = TRUE; + blklen=1024; + case WANTCRC: + Crcflg = TRUE; + case NAK: + return FALSE; + case CAN: + if ((firstch = readline(20)) == CAN && Lastrx == CAN) + return TRUE; + default: + break; + } + Lastrx = firstch; + } +} + + +wctx(flen) +long flen; +{ + register int thisblklen; + register int sectnum, attempts, firstch; + long charssent; + + charssent = 0; firstsec=TRUE; thisblklen = blklen; + vfile("wctx:file length=%ld", flen); + + while ((firstch=readline(Rxtimeout))!=NAK && firstch != WANTCRC + && firstch != WANTG && firstch!=TIMEOUT && firstch!=CAN) + ; + if (firstch==CAN) { + zperr("Receiver CANcelled"); + return ERROR; + } + if (firstch==WANTCRC) + Crcflg=TRUE; + if (firstch==WANTG) + Crcflg=TRUE; + sectnum=0; + for (;;) { + if (flen <= (charssent + 896L)) + thisblklen = 128; + if ( !filbuf(txbuf, thisblklen)) + break; + if (wcputsec(txbuf, ++sectnum, thisblklen)==ERROR) + return ERROR; + charssent += thisblklen; + } + fclose(in); + attempts=0; + do { + purgeline(); + sendline(EOT); + flushmo(); + ++attempts; + } + while ((firstch=(readline(Rxtimeout)) != ACK) && attempts < RETRYMAX); + if (attempts == RETRYMAX) { + zperr("No ACK on EOT"); + return ERROR; + } + else + return OK; +} + +wcputsec(buf, sectnum, cseclen) +char *buf; +int sectnum; +int cseclen; /* data length of this sector to send */ +{ + register checksum, wcj; + register char *cp; + unsigned oldcrc; + int firstch; + int attempts; + + firstch=0; /* part of logic to detect CAN CAN */ + + if (Verbose>2) + fprintf(stderr, "Sector %3d %2dk\n", Totsecs, Totsecs/8 ); + else if (Verbose>1) + fprintf(stderr, "\rSector %3d %2dk ", Totsecs, Totsecs/8 ); + for (attempts=0; attempts <= RETRYMAX; attempts++) { + Lastrx= firstch; + sendline(cseclen==1024?STX:SOH); + sendline(sectnum); + sendline(-sectnum -1); + oldcrc=checksum=0; + for (wcj=cseclen,cp=buf; --wcj>=0; ) { + sendline(*cp); + oldcrc=updcrc((0377& *cp), oldcrc); + checksum += *cp++; + } + if (Crcflg) { + oldcrc=updcrc(0,updcrc(0,oldcrc)); + sendline((int)oldcrc>>8); + sendline((int)oldcrc); + } + else + sendline(checksum); + flushmo(); + + if (Optiong) { + firstsec = FALSE; return OK; + } + firstch = readline(Rxtimeout); +gotnak: + switch (firstch) { + case CAN: + if(Lastrx == CAN) { +cancan: + zperr("Cancelled"); return ERROR; + } + break; + case TIMEOUT: + zperr("Timeout on sector ACK"); continue; + case WANTCRC: + if (firstsec) + Crcflg = TRUE; + case NAK: + zperr("NAK on sector"); continue; + case ACK: + firstsec=FALSE; + Totsecs += (cseclen>>7); + return OK; + case ERROR: + zperr("Got burst for sector ACK"); break; + default: + zperr("Got %02x for sector ACK", firstch); break; + } + for (;;) { + Lastrx = firstch; + if ((firstch = readline(Rxtimeout)) == TIMEOUT) + break; + if (firstch == NAK || firstch == WANTCRC) + goto gotnak; + if (firstch == CAN && Lastrx == CAN) + goto cancan; + } + } + zperr("Retry Count Exceeded"); + return ERROR; +} + +/* fill buf with count chars padding with ^Z for CPM */ +filbuf(buf, count) +register char *buf; +{ + register c, m; + + if ( !Ascii) { + m = read(fileno(in), buf, count); + if (m <= 0) + return 0; + while (m < count) + buf[m++] = 032; + return count; + } + m=count; + if (Lfseen) { + *buf++ = 012; --m; Lfseen = 0; + } + while ((c=getc(in))!=EOF) { + if (c == 012) { + *buf++ = 015; + if (--m == 0) { + Lfseen = TRUE; break; + } + } + *buf++ =c; + if (--m == 0) + break; + } + if (m==count) + return 0; + else + while (--m>=0) + *buf++ = CPMEOF; + return count; +} + +/* Fill buffer with blklen chars */ +zfilbuf() +{ + int n; + +#ifdef TXBSIZE + vfile("zfilbuf: bytcnt =%lu vpos=%lu blklen=%d", bytcnt, vpos, blklen); + /* We assume request is within buffer, or just beyond */ + txbuf = Txb + (bytcnt & TXBMASK); + if (vpos <= bytcnt) { +#ifdef GENIE + if (Binfile) { + long l, m; char *p; + + for (p=txbuf, n=0, l=blklen; l; l -= 128, p+= 128) { + n += m = fgetb(p, 128, in); + if (m == 0) + break; + } + } else +#endif + n = fread(txbuf, 1, blklen, in); + + vpos += n; + if (n < blklen) + Eofseen = 1; + vfile("zfilbuf: n=%d vpos=%lu Eofseen=%d", n, vpos, Eofseen); + return n; + } + if (vpos >= (bytcnt+blklen)) + return blklen; + /* May be a short block if crash recovery etc. */ + Eofseen = BEofseen; + return (vpos - bytcnt); +#else + n = fread(txbuf, 1, blklen, in); + if (n < blklen) + Eofseen = 1; + return n; +#endif +} + +#ifdef TXBSIZE +/* Replacement for brain damaged fseek function. Returns 0==success */ +fooseek(fptr, pos, whence) +FILE *fptr; +long pos; +{ + long m, n; +#ifdef GENIE + long l, k; char *p; +#endif + + vfile("fooseek: pos =%lu vpos=%lu Canseek=%d", pos, vpos, Canseek); + /* Seek offset < current buffer */ + if (pos < (vpos -TXBSIZE +1024)) { + BEofseen = 0; + if (Canseek > 0) { + vpos = pos & ~TXBMASK; + if (vpos >= pos) + vpos -= TXBSIZE; + if (fseek(fptr, vpos, 0)) + return 1; + } + else if (Canseek == 0) { +#ifdef GENIE + if (Binfile) { + if (fseekb(fptr, vpos = 0L, 0)) + return 1; + } else +#endif + if (fseek(fptr, vpos = 0L, 0)) + return 1; + } else + return 1; + while (vpos < pos) { +#ifdef GENIE + if (Binfile) { + for (p=Txb,n=0,l=TXBSIZE; l; l -= 128,p+= 128) { + n += (k = fgetb(p, 128, fptr)); + vfile("bsk1: l=%d k=%d", l, k); + if (k == 0) + break; + } + } else +#endif + n = fread(Txb, 1, TXBSIZE, fptr); + vpos += n; + vfile("n=%d vpos=%ld", n, vpos); + if (n < TXBSIZE) { + BEofseen = 1; + break; + } + } + vfile("vpos=%ld", vpos); + return 0; + } + /* Seek offset > current buffer (Crash Recovery, etc.) */ + if (pos > vpos) { + if (Canseek) + if (fseek(fptr, vpos = (pos & ~TXBMASK), 0)) + return 1; + while (vpos <= pos) { + txbuf = Txb + (vpos & TXBMASK); + m = TXBSIZE - (vpos & TXBMASK); + vfile("m=%ld vpos=%ld", m,vpos); +#ifdef GENIE + if (Binfile) { + for (p=txbuf,n=0,l=m; l; l -= 128,p+= 128) { + n += (k = fgetb(p, 128, fptr)); + vfile("bsk2: l=%d k=%d n=%d", l, k, n); + if (k == 0) + break; + } + } else +#endif + n = fread(txbuf, 1, m, fptr); + vfile("n=%ld vpos=%ld", n,vpos); + vpos += n; + vfile("bo=%d m=%ld vpos=%ld", txbuf-Txb,m,vpos); + if (n < m) { + BEofseen = 1; + break; + } + } + return 0; + } + /* Seek offset is within current buffer */ + vfile("within buffer: vpos=%ld", vpos); + return 0; +} +#define fseek fooseek +#endif + + +/* VARARGS1 */ +vfile(f, a, b, c, d) +char *f; +long a, b, c, d; +{ + if (Verbose > 2) { + fprintf(stderr, f, a, b, c, d); + fprintf(stderr, "\n"); + } +} + +void +alrm(sig) +{ + longjmp(tohere, -1); +} + +#ifndef GENIE +#ifndef vax11c +/* + * readline(timeout) reads character(s) from file descriptor 0 + * timeout is in tenths of seconds + */ +readline(timeout) +{ + register int c; + static char byt[1]; + + fflush(stdout); + if (setjmp(tohere)) { + zperr("TIMEOUT"); + return TIMEOUT; + } + c = timeout/10; + if (c<2) + c=2; + if (Verbose>5) { + fprintf(stderr, "Timeout=%d Calling alarm(%d) ", timeout, c); + } + signal(SIGALRM, alrm); alarm(c); + c=read(0, byt, 1); + alarm(0); + if (Verbose>5) + fprintf(stderr, "ret %x\n", byt[0]); + if (c<1) + return TIMEOUT; + return (byt[0]&0377); +} + +flushmo() +{ + fflush(stdout); +} + + +purgeline() +{ +#ifdef USG + ioctl(0, TCFLSH, 0); +#else + lseek(0, 0L, 2); +#endif +} +#endif +#endif + +/* send cancel string to get the other end to shut up */ +canit() +{ + static char canistr[] = { + 24,24,24,24,24,24,24,24,24,24,8,8,8,8,8,8,8,8,8,8,0 + }; + +#ifdef vax11c + raw_wbuf(strlen(canistr), canistr); + purgeline(); +#else + printf(canistr); + fflush(stdout); +#endif +} + + +/* + * Log an error + */ +/*VARARGS1*/ +zperr(s,p,u) +char *s, *p, *u; +{ + if (Verbose <= 0) + return; + fprintf(stderr, "Retry %d: ", errors); + fprintf(stderr, s, p, u); + fprintf(stderr, "\n"); +} + +/* + * substr(string, token) searches for token in string s + * returns pointer to token within string if found, NULL otherwise + */ +char * +substr(s, t) +register char *s,*t; +{ + register char *ss,*tt; + /* search for first char of token */ + for (ss=s; *s; s++) + if (*s == *t) + /* compare token with substring */ + for (ss=s,tt=t; ;) { + if (*tt == 0) + return s; + if (*ss++ != *tt++) + break; + } + return NULL; +} + +char *babble[] = { +#ifdef vax11c + "Send file(s) with ZMODEM/YMODEM/XMODEM Protocol", + " (Y) = Option applies to YMODEM only", + " (Z) = Option applies to ZMODEM only", + "Usage: sz [-2+abdefkLlNnquvwYy] [-] file ...", + " sz [-2Ceqv] -c COMMAND", + " \\ Force next option letter to upper case", + " sb [-2adfkquv] [-] file ...", + " sx [-2akquv] [-] file", +#endif +#ifndef vax11c + "Send file(s) with ZMODEM/YMODEM/XMODEM Protocol", + " (Y) = Option applies to YMODEM only", + " (Z) = Option applies to ZMODEM only", + "Usage: sz [-2+abdefkLlNnquvwYy] [-] file ...", + " sz [-2Ceqv] -c COMMAND", + " sb [-2adfkquv] [-] file ...", + " sx [-2akquv] [-] file", +#endif +#ifdef CSTOPB + " 2 Use 2 stop bits", +#endif + " + Append to existing destination file (Z)", + " a (ASCII) change NL to CR/LF", + " b Binary file transfer override", + " c send COMMAND (Z)", +#ifndef vax11c + " d Change '.' to '/' in pathnames (Y/Z)", +#endif + " e Escape all control characters (Z)", + " f send Full pathname (Y/Z)", + " i send COMMAND, ack Immediately (Z)", + " k Send 1024 byte packets (Y)", + " L N Limit subpacket length to N bytes (Z)", + " l N Limit frame length to N bytes (l>=L) (Z)", + " n send file only if source newer (Z)", + " N send file only if source newer or longer (Z)", + " o Use 16 bit CRC instead of 32 bit CRC (Z)", + " p Protect existing destination file (Z)", + " r Resume/Recover interrupted file transfer (Z)", + " q Quiet (no progress reports)", +#ifndef vax11c + " u Unlink (remove) file after transmission", +#endif + " v Verbose - provide debugging information", + " w N restrict Window to N bytes (Z)", + " Y Yes, overwrite existing file, skip if not present at rx (Z)", + " y Yes, overwrite existing file (Z)", + " Z Activate ZMODEM compression(Z)", + "" +}; + +usage() +{ + char **pp; + + for (pp=babble; **pp; ++pp) + fprintf(stderr, "%s\n", *pp); + fprintf(stderr, "%s for %s by Chuck Forsberg, Omen Technology INC\n", + VERSION, OS); + fprintf(stderr, "\t\t\042The High Reliability Software\042\n"); + cucheck(); + exit(SS_NORMAL); +} + +/* + * Get the receiver's init parameters + */ +getzrxinit() +{ + register n; +#ifdef STAT + struct stat f; +#endif + + for (n=10; --n>=0; ) { + + switch (zgethdr(Rxhdr, 1)) { + case ZCHALLENGE: /* Echo receiver's challenge numbr */ + stohdr(Rxpos); + zshhdr(4, ZACK, Txhdr); + continue; + case ZCOMMAND: /* They didn't see out ZRQINIT */ + stohdr(0L); + zshhdr(4, ZRQINIT, Txhdr); + continue; + case ZRINIT: + Rxflags = 0377 & Rxhdr[ZF0]; + Usevhdrs = Rxhdr[ZF1] & CANVHDR; + Txfcs32 = (Wantfcs32 && (Rxflags & CANFC32)); + Zctlesc |= Rxflags & TESCCTL; + Rxbuflen = (0377 & Rxhdr[ZP0])+((0377 & Rxhdr[ZP1])<<8); + if ( !(Rxflags & CANFDX)) + Txwindow = 0; + vfile("Rxbuflen=%d Tframlen=%d", Rxbuflen, Tframlen); + if ( !Fromcu) + signal(SIGINT, SIG_IGN); +#ifdef MODE2OK + mode(2); /* Set cbreak, XON/XOFF, etc. */ +#endif + +#ifndef READCHECK +#ifndef USG +#ifndef GENIE + /* Use 1024 byte frames if no sample/interrupt */ + if (Rxbuflen < 32 || Rxbuflen > 1024) { + Rxbuflen = 1024; + vfile("Rxbuflen=%d", Rxbuflen); + } +#endif +#endif +#endif + + /* Override to force shorter frame length */ + if (Rxbuflen && (Rxbuflen>Tframlen) && (Tframlen>=32)) + Rxbuflen = Tframlen; + if ( !Rxbuflen && (Tframlen>=32) && (Tframlen<=1024)) + Rxbuflen = Tframlen; + vfile("Rxbuflen=%d", Rxbuflen); + +#ifndef GENIE +#ifndef vax11c +#ifdef STAT + /* If using a pipe for testing set lower buf len */ + fstat(0, &f); + if ((f.st_mode & S_IFMT) != S_IFCHR) { + Rxbuflen = 1024; + } +#endif +#endif +#endif + +#ifdef BADSEEK +#ifdef GENIE + if (Txwindow == 0) { + Txwspac = (Txwindow = 4096)/4; + } +#else + if (Txwindow == 0) + Txwindow = TXBSIZE - 1024; + Txwspac = TXBSIZE/4; +#endif + Canseek = 0; +#endif + + /* + * If input is not a regular file, force ACK's to + * prevent running beyond the buffer limits + */ +#ifdef STAT + if ( !Command) { + fstat(fileno(in), &f); + if ((f.st_mode & S_IFMT) != S_IFREG) { + Canseek = -1; +#ifdef TXBSIZE + Txwindow = TXBSIZE - 1024; + Txwspac = TXBSIZE/4; +#else + return ERROR; +#endif + } + } +#endif + + /* Set initial subpacket length */ + if (blklen < 1024) { /* Command line override? */ + if (Effbaud > 300) + blklen = 256; + if (Effbaud > 1200) + blklen = 512; + if (Effbaud > 2400) + blklen = 1024; + } + if (Rxbuflen && blklen>Rxbuflen) + blklen = Rxbuflen; + if (blkopt && blklen > blkopt) + blklen = blkopt; +#ifdef GENIE + blklen /= 128; blklen *= 128; + if (blklen < 128) + blklen = 128; +#endif + vfile("Rxbuflen=%d blklen=%d", Rxbuflen, blklen); + vfile("Txwindow = %u Txwspac = %d", Txwindow, Txwspac); + + + if (Lztrans == ZTRLE && (Rxflags & CANRLE)) + Txfcs32 = 2; + else + Lztrans = 0; + + return (sendzsinit()); + case ZCAN: + case TIMEOUT: + return ERROR; + case ZRQINIT: + if (Rxhdr[ZF0] == ZCOMMAND) + continue; + default: + zshhdr(4, ZNAK, Txhdr); + continue; + } + } + return ERROR; +} + +/* Send send-init information */ +sendzsinit() +{ + register c; + + if (Myattn[0] == '\0' && (!Zctlesc || (Rxflags & TESCCTL))) + return OK; + errors = 0; + for (;;) { + stohdr(0L); +#ifdef ALTCANOFF + Txhdr[ALTCOFF] = ALTCANOFF; +#endif + if (Zctlesc) { + Txhdr[ZF0] |= TESCCTL; zshhdr(4, ZSINIT, Txhdr); + } + else + zsbhdr(4, ZSINIT, Txhdr); + zsdata(Myattn, ZATTNLEN, ZCRCW); + c = zgethdr(Rxhdr, 1); + switch (c) { + case ZCAN: + return ERROR; + case ZACK: + return OK; + default: + if (++errors > 19) + return ERROR; + continue; + } + } +} + +/* Send file name and related info */ +zsendfile(buf, blen) +char *buf; +{ + register c; + register UNSL long crc; + long lastcrcrq = -1; + char *p; + + for (;;) { + Txhdr[ZF0] = Lzconv; /* file conversion request */ + Txhdr[ZF1] = Lzmanag; /* file management request */ + if (Lskipnocor) + Txhdr[ZF1] |= ZMSKNOLOC; + Txhdr[ZF2] = Lztrans; /* file transport request */ + Txhdr[ZF3] = 0; + zsbhdr(4, ZFILE, Txhdr); + zsdata(buf, blen, ZCRCW); +again: + c = zgethdr(Rxhdr, 1); + switch (c) { + case ZRINIT: + while ((c = readline(50)) > 0) + if (c == ZPAD) { + goto again; + } + continue; + case ZCAN: + case TIMEOUT: + case ZABORT: + case ZFIN: + default: + return ERROR; + case ZCRC: + if (Rxpos != lastcrcrq) { + lastcrcrq = Rxpos; + crc = 0xFFFFFFFFL; + if (Canseek >= 0) { + fseek(in, 0L, 0); + while (((c = getc(in)) != EOF) && --lastcrcrq) + crc = UPDC32(c, crc); + crc = ~crc; + clearerr(in); /* Clear possible EOF */ + lastcrcrq = Rxpos; + } + } + stohdr(crc); + zsbhdr(4, ZCRC, Txhdr); + goto again; + case ZFERR: + case ZSKIP: + fclose(in); return c; + case ZRPOS: + /* + * Suppress zcrcw request otherwise triggered by + * lastyunc==bytcnt + */ +#ifdef GENIE + /* + * Special case - turn on RLE if not archive, etc. + * otherwise turn off RLE unless cmd line specified + */ + if (Rxflags & CANRLE) { /* RX can do it */ + bytcnt = 0; + zfilbuf(); + vfile("txbuf012: %x %x %x", txbuf[0], txbuf[1], + txbuf[2]); + if ((txbuf[0] != 032) /* .ARC file */ + && (txbuf[0] != 0x1f) /* .Z file */ + && (txbuf[0] != 0x1c) /* .LHZ file */ + && strncmp(txbuf, "ZOO", 3) + && strncmp(txbuf, "GIF", 3) + && (txbuf[2] != 3)) /* .ZIP file */ + Txfcs32 = 2; + else if ( !(Lztrans & ZTRLE)) + Txfcs32 = 1; + } + /* GEnie binary can't seek to byte */ + if (Binfile) { + Rxpos &= ~127L; + } +#endif + if (fseek(in, Rxpos, 0)) + return ERROR; + Lastsync = (bytcnt = Txpos = Lrxpos = Rxpos) -1; + return zsendfdata(); + } + } +} + +/* Send the data in the file */ +zsendfdata() +{ + register c, e, n; + register newcnt; + register long tcount = 0; + int junkcount; /* Counts garbage chars received by TX */ + static int tleft = 6; /* Counter for test mode */ + + junkcount = 0; + Beenhereb4 = FALSE; +somemore: + if (setjmp(intrjmp)) { +waitack: + junkcount = 0; + c = getinsync(0); +gotack: + switch (c) { + default: + case ZCAN: + fclose(in); + return ERROR; + case ZSKIP: + fclose(in); + return c; + case ZACK: + case ZRPOS: + break; + case ZRINIT: + return OK; + } +#ifdef READCHECK + /* + * If the reverse channel can be tested for data, + * this logic may be used to detect error packets + * sent by the receiver, in place of setjmp/longjmp + * rdchk(fd) returns non 0 if a character is available + */ + while (rdchk(0)) { +#ifdef EATSIT + switch (checked) +#else + switch (readline(1)) +#endif + { + case CAN: + case ZPAD: + c = getinsync(1); + goto gotack; + case XOFF: /* Wait a while for an XON */ + case XOFF|0200: + readline(100); + } + } +#endif + } + + if ( !Fromcu) + signal(SIGINT, onintr); + newcnt = Rxbuflen; + Txwcnt = 0; + stohdr(Txpos); + zsbhdr(4, ZDATA, Txhdr); + + /* + * Special testing mode. This should force receiver to Attn,ZRPOS + * many times. Each time the signal should be caught, causing the + * file to be started over from the beginning. + */ + if (Test) { + if ( --tleft) + while (tcount < 20000) { + printf(qbf); fflush(stdout); + tcount += strlen(qbf); +#ifdef READCHECK + while (rdchk(0)) { +#ifdef EATSIT + switch (checked) +#else + switch (readline(1)) +#endif + { + case CAN: + case ZPAD: +#ifdef TCFLSH + ioctl(0, TCFLSH, 1); +#endif + goto waitack; + case XOFF: /* Wait for XON */ + case XOFF|0200: + readline(100); + } + } +#endif + } + signal(SIGINT, SIG_IGN); canit(); + sleep(3); purgeline(); mode(0); + printf("\nsz: Tcount = %ld\n", tcount); + if (tleft) { + printf("ERROR: Interrupts Not Caught\n"); + exit(1); + } + exit(SS_NORMAL); + } + + do { + n = zfilbuf(); + if (Eofseen) + e = ZCRCE; + else if (junkcount > 3) + e = ZCRCW; + else if (bytcnt == Lastsync) + e = ZCRCW; + else if (Rxbuflen && (newcnt -= n) <= 0) + e = ZCRCW; + else if (Txwindow && (Txwcnt += n) >= Txwspac) { + Txwcnt = 0; e = ZCRCQ; + } else + e = ZCRCG; + if (Verbose>1) + fprintf(stderr, "\r%7ld ZMODEM%s ", + Txpos, Crc32t?" CRC-32":""); + zsdata(txbuf, n, e); + bytcnt = Txpos += n; + if (e == ZCRCW) + goto waitack; +#ifdef READCHECK + /* + * If the reverse channel can be tested for data, + * this logic may be used to detect error packets + * sent by the receiver, in place of setjmp/longjmp + * rdchk(fd) returns non 0 if a character is available + */ + fflush(stdout); + while (rdchk(0)) { +#ifdef EATSIT + switch (checked) +#else + switch (readline(1)) +#endif + { + case CAN: + case ZPAD: + c = getinsync(1); + if (c == ZACK) + break; +#ifdef TCFLSH + ioctl(0, TCFLSH, 1); +#endif + /* zcrce - dinna wanna starta ping-pong game */ + zsdata(txbuf, 0, ZCRCE); + goto gotack; + case XOFF: /* Wait a while for an XON */ + case XOFF|0200: + readline(100); + default: + ++junkcount; + } + } +#endif /* READCHECK */ + if (Txwindow) { + while ((tcount = (Txpos - Lrxpos)) >= Txwindow) { + vfile("%ld window >= %u", tcount, Txwindow); + if (e != ZCRCQ) + zsdata(txbuf, 0, e = ZCRCQ); + c = getinsync(1); + if (c != ZACK) { +#ifdef TCFLSH + ioctl(0, TCFLSH, 1); +#endif + zsdata(txbuf, 0, ZCRCE); + goto gotack; + } + } + vfile("window = %ld", tcount); + } + } while (!Eofseen); + if ( !Fromcu) + signal(SIGINT, SIG_IGN); + + for (;;) { + stohdr(Txpos); + zsbhdr(4, ZEOF, Txhdr); + switch (getinsync(0)) { + case ZACK: + continue; + case ZRPOS: + goto somemore; + case ZRINIT: + return OK; + case ZSKIP: + fclose(in); + return c; + default: + fclose(in); + return ERROR; + } + } +} + +/* + * Respond to receiver's complaint, get back in sync with receiver + */ +getinsync(flag) +{ + register c; + + for (;;) { + if (Test) { + printf("\r\n\n\n***** Signal Caught *****\r\n"); + Rxpos = 0; c = ZRPOS; + } else + c = zgethdr(Rxhdr, 0); + switch (c) { + case ZCAN: + case ZABORT: + case ZFIN: + case TIMEOUT: + return ERROR; + case ZRPOS: + /* ************************************* */ + /* If sending to a buffered modem, you */ + /* might send a break at this point to */ + /* dump the modem's buffer. */ + clearerr(in); /* In case file EOF seen */ + if (fseek(in, Rxpos, 0)) + return ERROR; + Eofseen = 0; + bytcnt = Lrxpos = Txpos = Rxpos; +#ifndef GENIE + if (Lastsync == Rxpos) { + if (++Beenhereb4 > 4) + if (blklen > 32) + blklen /= 2; + } +#endif + Lastsync = Rxpos; + return c; + case ZACK: + Lrxpos = Rxpos; + if (flag || Txpos == Rxpos) + return ZACK; + continue; + case ZRINIT: + case ZSKIP: + fclose(in); + return c; + case ERROR: + default: + zsbhdr(4, ZNAK, Txhdr); + continue; + } + } +} + + +/* Say "bibi" to the receiver, try to do it cleanly */ +saybibi() +{ + for (;;) { + stohdr(0L); /* CAF Was zsbhdr - minor change */ + zshhdr(4, ZFIN, Txhdr); /* to make debugging easier */ + switch (zgethdr(Rxhdr, 0)) { + case ZFIN: + sendline('O'); sendline('O'); flushmo(); + case ZCAN: + case TIMEOUT: + return; + } + } +} + +/* Local screen character display function */ +bttyout(c) +{ + if (Verbose) + putc(c, stderr); +} + +/* Send command and related info */ +zsendcmd(buf, blen) +char *buf; +{ + register c; + long cmdnum; + +#ifdef GENIE + cmdnum = 69; +#else + cmdnum = getpid(); +#endif + errors = 0; + for (;;) { + stohdr(cmdnum); + Txhdr[ZF0] = Cmdack1; + zsbhdr(4, ZCOMMAND, Txhdr); + zsdata(buf, blen, ZCRCW); +listen: + Rxtimeout = 100; /* Ten second wait for resp. */ + Usevhdrs = 0; /* Allow rx to send fixed len headers */ + c = zgethdr(Rxhdr, 1); + + switch (c) { + case ZRINIT: + goto listen; /* CAF 8-21-87 */ + case ERROR: + case GCOUNT: + case TIMEOUT: + if (++errors > Cmdtries) + return ERROR; + continue; + case ZCAN: + case ZABORT: + case ZFIN: + case ZSKIP: + case ZRPOS: + return ERROR; + default: + if (++errors > 20) + return ERROR; + continue; + case ZCOMPL: + Exitcode = Rxpos; + saybibi(); + return OK; + case ZRQINIT: +#ifdef vax11c /* YAMP :== Yet Another Missing Primitive */ + return ERROR; +#else + vfile("******** RZ *******"); + system("rz"); + vfile("******** SZ *******"); + goto listen; +#endif + } + } +} + +/* + * If called as sb use YMODEM protocol + */ +chkinvok(s) +char *s; +{ + register char *p; + + p = s; + while (*p == '-') + s = ++p; + while (*p) + if (*p++ == '/') + s = p; + if (*s == 'v') { + Verbose=1; ++s; + } + Progname = s; + if (s[0]=='s' && s[1]=='b') { + Nozmodem = TRUE; blklen=1024; + } + if (s[0]=='s' && s[1]=='x') { + Modem2 = TRUE; + } +} + +#ifdef STAT +countem(argc, argv) +register char **argv; +{ + register c; + struct stat f; + + for (Totalleft = 0, Filesleft = 0; --argc >=0; ++argv) { + f.st_size = -1; + if (Verbose>2) { + fprintf(stderr, "\nCountem: %03d %s ", argc, *argv); + fflush(stderr); + } + if (access(*argv, 04) >= 0 && stat(*argv, &f) >= 0) { + c = f.st_mode & S_IFMT; + if (c != S_IFDIR && c != S_IFBLK) { + ++Filesleft; Totalleft += f.st_size; + } + } + if (Verbose>2) + fprintf(stderr, " %ld", f.st_size); + } + if (Verbose>2) + fprintf(stderr, "\ncountem: Total %d %ld\n", + Filesleft, Totalleft); +} +#else +countem(argc, argv) +register char **argv; +{ + register c; + register char *p; + long size; + + for (Totalleft = 0, Filesleft = 0; --argc >=0; ++argv) { + size = -1; + if (Verbose>2) { + fprintf(stderr, "\nCountem: %03d %s ", argc, *argv); + fflush(stderr); + } + ++Filesleft; +#ifdef XARGSFILE + /* Look for file length in third colon sep field */ + for (p = *argv; *p; ++p) { + if (*p == ':') { + for (++p; *p; ++p) { + if (*p == ':') { + ++p; + size = atol(p); + Totalleft += size; + break; + } + } + break; + } + } +#endif + + if (Verbose>2) + fprintf(stderr, " %ld", size); + } + if (Verbose>2) + fprintf(stderr, "\ncountem: Total %d %ld\n", + Filesleft, Totalleft); +} +#endif + +chartest(m) +{ + register n; + + mode(m); + printf("\r\n\nCharacter Transparency Test Mode %d\r\n", m); + printf("If Pro-YAM/ZCOMM is not displaying ^M hit ALT-V NOW.\r\n"); + printf("Hit Enter.\021"); fflush(stdout); + readline(500); + + for (n = 0; n < 256; ++n) { + if (!(n%8)) + printf("\r\n"); + printf("%02x ", n); fflush(stdout); + sendline(n); flushmo(); + printf(" "); fflush(stdout); + if (n == 127) { + printf("Hit Enter.\021"); fflush(stdout); + readline(500); + printf("\r\n"); fflush(stdout); + } + } + printf("\021\r\nEnter Characters, echo is in hex.\r\n"); + printf("Hit SPACE or pause 40 seconds for exit.\r\n"); + + while (n != TIMEOUT && n != ' ') { + n = readline(400); + printf("%02x\r\n", n); + fflush(stdout); + } + printf("\r\nMode %d character transparency test ends.\r\n", m); + fflush(stdout); +} + +/* End of sz.c */ diff --git a/src/cmd/zmodem/vmodem.h b/src/cmd/zmodem/vmodem.h new file mode 100644 index 0000000..bf71f26 --- /dev/null +++ b/src/cmd/zmodem/vmodem.h @@ -0,0 +1,43 @@ +/* + * VMODEM.H + * VMS support for UMODEM program + * + * #INCLUDE files defining structures associated with terminal + * information structure TT_INFO. + * Information about the terminal is passed around in UMODEM in a + * STRUCT TT_INFO. + * + * Walter Reiher + * Harvard University + * Department of Chemistry + * 12 Oxford Street + * Cambridge, MA 02138 + * March 10, 1983 + */ + +struct tt_mode /* Info for a IO$_SETMODE call */ +{ + char class; + char type; + short page_width; + char bcharacteristics[3]; + char page_length; + int echaracteristics; +}; + +struct tt_mode_iosb /* Terminal IO$_SENSEMODE IOSB */ +{ + short status; + char t_speed; + char r_speed; + char CR_fill; + char LF_fill; + char parity_flags; + char unused2; +}; + +struct tt_info /* Summary of terminal infomation */ +{ + struct tt_mode dev_characteristics; + struct tt_mode_iosb dev_modes; +}; diff --git a/src/cmd/zmodem/vrzsz.c b/src/cmd/zmodem/vrzsz.c new file mode 100644 index 0000000..81da525 --- /dev/null +++ b/src/cmd/zmodem/vrzsz.c @@ -0,0 +1,254 @@ +#include "vmodem.h" +#include ssdef +#include tt2def +#include ttdef +#define SS_NORMAL SS$_NORMAL +#define MODE2OK /* CAF 7-3-89 */ + +/* VMS structures */ +/* + * TT_INFO structures are used for passing information about + * the terminal. Used in GTTY and STTY calls. + */ +struct tt_info ttys, ttysnew, ttystemp; + +/* + * + */ + +/* + * return 1 iff stdout and stderr are different devices + * indicating this program operating with a modem on a + * different line + */ +int Fromcu; /* Were called from cu or yam */ +from_cu() +{ +} +cucheck() +{ +} + + + +/* + * mode(n) + * 3: save old tty stat, set raw mode with INPPUT flow control + * 2: set OUTPUT XON/XOFF for sb/sz with ZMODEM or YMODEM-g + * 1: save old tty stat, set raw mode for XMODEM/YMODEM + * 0: restore original tty mode + */ +mode(n) +{ + int *iptr, parameters; + static savedmodes = FALSE; + + vfile("mode:%d", n); + + if (!savedmodes) { + if (gtty(&ttys) != SS$_NORMAL) + death("SETMODES: error return from GTTY (1)"); + if (gtty(&ttysnew) != SS$_NORMAL) + death("SETMODES: error return from GTTY (2)"); + savedmodes = TRUE; + } + + /* + * Set new terminal parameters. + * Note: there are three bytes of terminal characteristics, + * so we should make sure the fourth byte of the integer is unchanged. + */ + switch (n) { + case 1: + case 2: + case 3: + iptr = &(ttysnew.dev_characteristics.bcharacteristics); + parameters = *iptr; + + parameters &= ~TT$M_ESCAPE; /* ESCAPE OFF */ + parameters &= ~TT$M_HOSTSYNC; /* HOSTSYNC OFF */ + parameters |= TT$M_NOECHO; /* NOECHO ON */ + parameters |= TT$M_PASSALL; /* PASSALL ON */ + parameters &= ~TT$M_READSYNC; /* READSYNC OFF */ + parameters &= ~TT$M_TTSYNC; /* TTSYNC OFF */ + parameters &= ~TT$M_WRAP; /* WRAP OFF */ + parameters |= TT$M_EIGHTBIT; /* EIGHTBIT ON */ + if (n == 3) { + parameters |= TT$M_HOSTSYNC; /* HOSTSYNC On */ + } + if (n == 2) { + parameters |= TT$M_TTSYNC; /* TTSYNC On */ + } + + *iptr = parameters; + + if (stty(&ttysnew) != SS_NORMAL) + fatal("SETMODES: error return from STTY"); + break; + case 0: + stty(&ttys); /* Restore original modes */ + /* error return to /dev/null */ + break; + } +} + + + +/* set tty modes for vrzsz transfers */ +setmodes() +{ +/* Device characteristics for VMS */ +} + +fatal(msg) +char *msg; +{ + mode(0); /* put back normal tty modes */ + printf("vrzsz: %s\n", msg); + exit(SS_NORMAL); +} + +/* Call this instead if funny modes haven't been set yet */ +death(msg) +char *msg; +{ + printf("vrzsz: %s\n", msg); + exit(SS_NORMAL); +} + +#define LSIZE 64 /* Size of send & receive buffers */ +#ifdef BUFREAD + +char Rxlbuf[LSIZE+1]; +int Rxleft=0; /* number of characters in Rxlbuf */ +char *Rxcdq = Rxlbuf; /* pointer for removing chars from Rxlbuf */ + +/* + * This version of readline is reasoably well suited for + * reading many characters. + * + * timeout is in tenths of seconds + */ + +readline(timeout) +int timeout; +{ + register int c; + extern errno; + + if (--Rxleft>=0) + return (*Rxcdq++ & 0377); +#ifdef DEBUGG + eprintf("Calling read: "); +#endif + if ((c = timeout/10)<2) + c=2; + + do { + Rxleft = raw_read(LSIZE, Rxcdq=Rxlbuf, 1); + } while (Rxleft == SS$_TIMEOUT && --c >= 0); +#ifdef DEBUGG + eprintf("Read returned %d bytes\n", Rxleft); +#endif + if (Rxleft == SS$_TIMEOUT || --Rxleft < 0) { + Rxleft = 0; + return TIMEOUT; + } + return (*Rxcdq++ & 0377); +} + +purgeline() +{ + Rxleft=0; +} + + +#else /* BUFREAD */ + + +/* get a byte from data stream -- timeout if "dseconds" elapses */ +/* NOTE, however, that this function returns an INT, not a BYTE!!! */ +readline(dseconds) +{ + int seconds; + int ret, c; + + seconds = dseconds/10; + if (seconds < 2) + seconds = 2; + ret = raw_read(1, &c, seconds); + + if (ret == SS$_TIMEOUT) + return(TIMEOUT); + + return(c & 0377); /* return the char */ +} + +purgeline() +{ + int c; + + do { + c = readline(1); + } while (c != TIMEOUT); +} +#endif + + +#ifdef BUFWRITE +char Txlbuf[LSIZE+1]; +int Txleft=LSIZE; /* number of characters in Txlbuf */ +char *Txcq = Txlbuf; /* pointer for removing chars from Rxlbuf */ + +sendline(c) +{ + if (--Txleft >= 0) + *Txcq++ = c; + else { + Txleft = 0; + flushmoc(); + --Txleft; + *Txcq++ = c; + } +} + +flushmoc() +{ + register int n; + + n = LSIZE - Txleft; + Txcq=Txlbuf; Txleft = LSIZE; + raw_wbuf(n, Txlbuf); +} + +/* + * Wait for the modem line outbuffer to drain + */ +flushmo() +{ + fflush(stdout); + flushmoc(); +} + +#else /* BUFWRITE */ + +/* send a byte to data stream */ +sendline(data) +{ + char dataout; + + dataout = data; + raw_write(dataout); + +} + +flushmo() {} +flushmoc() {} +#endif + +sendbrk() +{ +} + + +/* End of vrzsz.c */ diff --git a/src/cmd/zmodem/vupl.t b/src/cmd/zmodem/vupl.t new file mode 100644 index 0000000..0ca6876 --- /dev/null +++ b/src/cmd/zmodem/vupl.t @@ -0,0 +1,18 @@ + echo "ProYAM/ZCOMM script to upload rz/sz files to VMS" + if !fvmodem.h echo "Can't find vmodem.h !!"; abort + pat + pat 1 "Server" + pat 2 "unrecognized command verb" + put "kermit server\r" + wait -f15 + if 1 goto frog + if !2 echo "Unexpected response from VMS!"; abort + expand vuplfile.t vmodem.h rz.c sz.c vrzsz.c vvmodem.c + expand vuplfile.t zm.c zmr.c zmodem.h crctab.c init.com + goto endmsg +frog: send vmodem.h rz.c sz.c vrzsz.c vvmodem.c zm.c + send zmodem.h crctab.c init.com + finish +endmsg: while "L<11" echo "Please read the VMS C Compile and Link instructions in sz.c and rz.c" + echo "vupl.t finished." + return diff --git a/src/cmd/zmodem/vuplfile.t b/src/cmd/zmodem/vuplfile.t new file mode 100644 index 0000000..f9acebf --- /dev/null +++ b/src/cmd/zmodem/vuplfile.t @@ -0,0 +1,13 @@ + echo "Uploading %item to VMS using DCL create command" + pat + if S>2400 pt1; ena -t + putw "set terminal/hostsync/noecho\r" + putw "create %item\r" + sleep 10 + f -xHr %item + pat 1 "\044" + put "\032" + wait -f30 + if !1 echo "create failed!" + putw "set terminal/echo\r" + dis -Htx diff --git a/src/cmd/zmodem/vvmodem.c b/src/cmd/zmodem/vvmodem.c new file mode 100644 index 0000000..b3c486a --- /dev/null +++ b/src/cmd/zmodem/vvmodem.c @@ -0,0 +1,273 @@ +/* + * VMODEM + * VMS support for UMODEM and vvrb/vvsb programs + * + * Defined herein are some utility routines to make the UNIX + * program UMODEM run under VAX/VMS C: + * + * assign_channel Calls the VMS System Service $ASSIGN + * to assign a channel to a device. + * The routine currently has the device + * "TT" hardwired into it. + * gtty Gets terminal characteristics, almost + * like the UNIX GTTY system call. + * raw_read Reads characters from the terminal + * without any echoing or interpretation + * and with an optional timeout period. + * raw_write Writes a character to the terminal + * without any interpretation. + * raw_wbuf Writes a buffer to the terminal + * without any interpretation. + * stty Sets terminal characteristics, almost + * like the UNIX STTY system call. + * + * Some of the ideas used here were obtained from code written + * by Max Benson and Robert Bruccoleri. + * + * Walter Reiher + * Harvard University + * Department of Chemistry + * 12 Oxford Street + * Cambridge, MA 02138 + * March 11, 1983 + * + * Modified 4-20-88 Chuck Forsberg, Omen Technology INC + * 17505-V NW Sauvie IS RD Portland OR 97231 omen!caf + * Added primitives for for ZMODEM use. + */ +#include descrip +#include iodef +#include rms +#include ssdef +#include stdio +#include "vmodem.h" + +#define TRUE 1 +#define FALSE 0 + +static char tt_name[] = "TT"; +static short tt_chan = -1; /* Terminal channel number */ + +struct tt_io_iosb /* Terminal I/O IOSB */ +{ + short status; + short byte_count; + short terminator; + short terminator_size; +}; + + +struct tt_io_tacf /* Terminal I/O type ahead */ +{ + short byte_count; + char firstchar; + char something; + short whatever; +}; + +/* + * Terminator mask for PASSALL reads. + * Permits reads of all possible 8-bit characters. + */ +int t_mask[32] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0 }; + +struct terminator_mask { + short size ; + short unused ; + int *mask ; +} + +termin_mask = { 32, 0, t_mask }; + +/* + * ASSIGN a channel to the logical name TT, which is usually + * the terminal. + */ +assign_channel() +{ + int status; + $DESCRIPTOR(tt_descriptor, tt_name); + + if (tt_chan == -1) + status = sys$assign(&tt_descriptor, &tt_chan, 0, 0); + else + status = SS$_NORMAL; + + if (status != SS$_NORMAL || tt_chan == -1) + fatal("ASSIGN_CHANNEL: error in SYS$ASSIGN\n"); + + return; +} + +/* + * Gets terminal information from VMS. + */ +gtty(tt_characteristics) +struct tt_info *tt_characteristics; +{ + int c; + int status; + extern unsigned Baudrate; + int speeds[] = { 2400, 50, 75, 110, 134, 150, 300, 600, 1200, 1800, + 2000, 2400, 3600, 4800, 7200, 9600, 19200 }; + + if (tt_chan == -1) + assign_channel(); + + status = sys$qiow(0, tt_chan, IO$_SENSEMODE, + &(tt_characteristics->dev_modes), NULL, 0, + &(tt_characteristics->dev_characteristics), 12, + 0, 0, 0, 0); + if (status != SS$_NORMAL || + tt_characteristics->dev_modes.status != SS$_NORMAL) + fatal("GTTY: sense mode QIO error return.\n"); + + c = tt_characteristics->dev_modes.t_speed % 17; + Baudrate = speeds[c]; + + return(status); +} + +/* + * Return the number of characters waiting in TTY input buffer + */ +rdchk() +{ + int status; + struct tt_io_iosb iosb; + struct tt_io_tacf typeahead; + + status = sys$qiow(0, tt_chan, IO$_SENSEMODE|IO$M_TYPEAHDCNT, + &iosb, NULL, 0, + &typeahead, 0, + 0, 0, 0, 0); + + return(typeahead.byte_count); +} + +/* + * Read NCHAR characters from the terminal without echoing or + * interpretation. + * If the argument SECONDS is non-zero, use that as the + * timeout period in seconds for the read. + * + * Returns SS$_TIMEOUT in case of timeout or other error. + * Otherwise, returns the number of characters read. + */ +raw_read(nchar, charbuf, seconds) +char *charbuf; +int nchar; +unsigned seconds; +{ + short function; + int status; + struct tt_io_iosb iosb; + + if (tt_chan == -1) + assign_channel(); + + function = IO$_READVBLK | IO$M_NOECHO | IO$M_NOFILTR; + + if (seconds) + status = sys$qiow(0, tt_chan, function | IO$M_TIMED, + &iosb, NULL, 0, + charbuf, nchar, seconds, + &termin_mask, NULL, 0); + else + status = sys$qiow(0, tt_chan, function, + &iosb, NULL, 0, + charbuf, nchar, 0, + &termin_mask, NULL, 0); + + if (iosb.byte_count) + return iosb.byte_count; + return SS$_TIMEOUT; +} + +/* + * Writes a character to the terminal without echoing or + * interpretation. + */ +raw_write(c) +char c; +{ + int status; + struct tt_io_iosb iosb; + + if (tt_chan == -1) + assign_channel(); + + status = sys$qiow(0, tt_chan, + IO$_WRITEVBLK | IO$M_CANCTRLO | IO$M_NOFORMAT, + &iosb, NULL, 0, + &c, 1, 0, 0, 0, 0); + + if (status != SS$_NORMAL || iosb.status != SS$_NORMAL) + fatal("RAW_WRITE: write QIO error return.\n"); + + return; +} + +/* + * Writes a buffer to the terminal without echoing or + * interpretation. + */ +raw_wbuf(nchar, charbuf) +char *charbuf; +int nchar; +{ + int status; + struct tt_io_iosb iosb; + + if (tt_chan == -1) + assign_channel(); + + status = sys$qiow(0, tt_chan, + IO$_WRITEVBLK | IO$M_CANCTRLO | IO$M_NOFORMAT, + &iosb, NULL, 0, + charbuf, nchar, 0, 0, 0, 0); + + if (status != SS$_NORMAL || iosb.status != SS$_NORMAL) + fatal("RAW_WRITE: write QIO error return.\n"); + + return; +} + +/* + * Sets terminal information from VMS. + * Modified 12-85 Larry Farr/Chuck Forsberg to not use + * bad parity returned by VMS 4. + */ +stty(tt_characteristics) +struct tt_info *tt_characteristics; +{ + short *f_ptr, /* *p_ptr, */ *s_ptr; + int status; + struct tt_mode_iosb iosb; + + if (tt_chan == -1) + assign_channel(); + +/* + * We do the following in order to get a full short, concatenating + * two adjacent chars: + */ + s_ptr = &(tt_characteristics->dev_modes.t_speed); /* Speeds */ + f_ptr = &(tt_characteristics->dev_modes.CR_fill); /* Fills */ + /* p_ptr = &(tt_characteristics->dev_modes.parity_flags); */ + + status = sys$qiow(0, tt_chan, IO$_SETMODE, + &iosb, NULL, 0, + &(tt_characteristics->dev_characteristics), 12, + /* *s_ptr, *f_ptr, *p_ptr, 0); */ + *s_ptr, *f_ptr, 0, 0); + if (status != SS$_NORMAL || iosb.status != SS$_NORMAL) + printf("STTY: set mode QIO returned %d\n", status); + + return(status); +} + diff --git a/src/cmd/zmodem/zm.c b/src/cmd/zmodem/zm.c new file mode 100644 index 0000000..25104b4 --- /dev/null +++ b/src/cmd/zmodem/zm.c @@ -0,0 +1,917 @@ +/* + * Z M . C + * ZMODEM protocol primitives + * 05-24-89 Chuck Forsberg Omen Technology Inc + * + * Entry point Functions: + * zsbhdr(type, hdr) send binary header + * zshhdr(type, hdr) send hex header + * zgethdr(hdr, eflag) receive header - binary or hex + * zsdata(buf, len, frameend) send data + * zrdata(buf, len) receive data + * stohdr(pos) store position data in Txhdr + * long rclhdr(hdr) recover position offset from header + * + * + * This version implements numerous enhancements including ZMODEM + * Run Length Encoding and variable length headers. These + * features were not funded by the original Telenet development + * contract. + * + * This software may be freely used for non commercial and + * educational (didactic only) purposes. This software may also + * be freely used to support file transfer operations to or from + * licensed Omen Technology products. Any programs which use + * part or all of this software must be provided in source form + * with this notice intact except by written permission from Omen + * Technology Incorporated. + * + * Use of this software for commercial or administrative purposes + * except when exclusively limited to interfacing Omen Technology + * products requires a per port license payment of $20.00 US per + * port (less in quantity). Use of this code by inclusion, + * decompilation, reverse engineering or any other means + * constitutes agreement to these conditions and acceptance of + * liability to license the materials and payment of reasonable + * legal costs necessary to enforce this license agreement. + * + * + * Omen Technology Inc FAX: 503-621-3745 + * Post Office Box 4681 + * Portland OR 97208 + * + * This code is made available in the hope it will be useful, + * BUT WITHOUT ANY WARRANTY OF ANY KIND OR LIABILITY FOR ANY + * DAMAGES OF ANY KIND. + * + */ + +#ifndef CANFDX +#include "zmodem.h" +int Rxtimeout = 100; /* Tenths of seconds to wait for something */ +#endif + +#ifndef UNSL +#define UNSL +#endif + + +/* Globals used by ZMODEM functions */ +int Rxframeind; /* ZBIN ZBIN32, or ZHEX type of frame */ +int Rxtype; /* Type of header received */ +int Rxhlen; /* Length of header received */ +int Rxcount; /* Count of data bytes received */ +char Rxhdr[ZMAXHLEN]; /* Received header */ +char Txhdr[ZMAXHLEN]; /* Transmitted header */ +long Rxpos; /* Received file position */ +long Txpos; /* Transmitted file position */ +int Txfcs32; /* TURE means send binary frames with 32 bit FCS */ +int Crc32t; /* Controls 32 bit CRC being sent */ + /* 1 == CRC32, 2 == CRC32 + RLE */ +int Crc32r; /* Indicates/controls 32 bit CRC being received */ + /* 0 == CRC16, 1 == CRC32, 2 == CRC32 + RLE */ +int Usevhdrs; /* Use variable length headers */ +int Znulls; /* Number of nulls to send at beginning of ZDATA hdr */ +char Attn[ZATTNLEN+1]; /* Attention string rx sends to tx on err */ +char *Altcan; /* Alternate canit string */ + +static lastsent; /* Last char we sent */ +static Not8bit; /* Seven bits seen on header */ + +static char *frametypes[] = { + "No Response to Error Correction Request", /* -4 */ + "No Carrier Detect", /* -3 */ + "TIMEOUT", /* -2 */ + "ERROR", /* -1 */ +#define FTOFFSET 4 + "ZRQINIT", + "ZRINIT", + "ZSINIT", + "ZACK", + "ZFILE", + "ZSKIP", + "ZNAK", + "ZABORT", + "ZFIN", + "ZRPOS", + "ZDATA", + "ZEOF", + "ZFERR", + "ZCRC", + "ZCHALLENGE", + "ZCOMPL", + "ZCAN", + "ZFREECNT", + "ZCOMMAND", + "ZSTDERR", + "xxxxx" +#define FRTYPES 22 /* Total number of frame types in this array */ + /* not including psuedo negative entries */ +}; + +static char badcrc[] = "Bad CRC"; + +/* Send ZMODEM binary header hdr of type type */ +zsbhdr(len, type, hdr) +register char *hdr; +{ + register int n; + register unsigned short crc; + +#ifndef DSZ + vfile("zsbhdr: %c %d %s %lx", Usevhdrs?'v':'f', len, + frametypes[type+FTOFFSET], rclhdr(hdr)); +#endif + if (type == ZDATA) + for (n = Znulls; --n >=0; ) + xsendline(0); + + xsendline(ZPAD); xsendline(ZDLE); + + switch (Crc32t=Txfcs32) { + case 2: + zsbh32(len, hdr, type, Usevhdrs?ZVBINR32:ZBINR32); + flushmo(); break; + case 1: + zsbh32(len, hdr, type, Usevhdrs?ZVBIN32:ZBIN32); break; + default: + if (Usevhdrs) { + xsendline(ZVBIN); + zsendline(len); + } + else + xsendline(ZBIN); + zsendline(type); + crc = updcrc(type, 0); + + for (n=len; --n >= 0; ++hdr) { + zsendline(*hdr); + crc = updcrc((0377& *hdr), crc); + } + crc = updcrc(0,updcrc(0,crc)); + zsendline(crc>>8); + zsendline(crc); + } + if (type != ZDATA) + flushmo(); +} + + +/* Send ZMODEM binary header hdr of type type */ +zsbh32(len, hdr, type, flavour) +register char *hdr; +{ + register int n; + register UNSL long crc; + + xsendline(flavour); + if (Usevhdrs) + zsendline(len); + zsendline(type); + crc = 0xFFFFFFFFL; crc = UPDC32(type, crc); + + for (n=len; --n >= 0; ++hdr) { + crc = UPDC32((0377 & *hdr), crc); + zsendline(*hdr); + } + crc = ~crc; + for (n=4; --n >= 0;) { + zsendline((int)crc); + crc >>= 8; + } +} + +/* Send ZMODEM HEX header hdr of type type */ +zshhdr(len, type, hdr) +register char *hdr; +{ + register int n; + register unsigned short crc; + +#ifndef DSZ + vfile("zshhdr: %c %d %s %lx", Usevhdrs?'v':'f', len, + frametypes[type+FTOFFSET], rclhdr(hdr)); +#endif + sendline(ZPAD); sendline(ZPAD); sendline(ZDLE); + if (Usevhdrs) { + sendline(ZVHEX); + zputhex(len); + } + else + sendline(ZHEX); + zputhex(type); + Crc32t = 0; + + crc = updcrc(type, 0); + for (n=len; --n >= 0; ++hdr) { + zputhex(*hdr); crc = updcrc((0377 & *hdr), crc); + } + crc = updcrc(0,updcrc(0,crc)); + zputhex(crc>>8); zputhex(crc); + + /* Make it printable on remote machine */ + sendline(015); sendline(0212); + /* + * Uncork the remote in case a fake XOFF has stopped data flow + */ + if (type != ZFIN && type != ZACK) + sendline(021); + flushmo(); +} + +/* + * Send binary array buf of length length, with ending ZDLE sequence frameend + */ +static char *Zendnames[] = { "ZCRCE", "ZCRCG", "ZCRCQ", "ZCRCW"}; +zsdata(buf, length, frameend) +register char *buf; +{ + register unsigned short crc; + +#ifndef DSZ + vfile("zsdata: %d %s", length, Zendnames[frameend-ZCRCE&3]); +#endif + switch (Crc32t) { + case 1: + zsda32(buf, length, frameend); break; + case 2: + zsdar32(buf, length, frameend); break; + default: + crc = 0; + for (;--length >= 0; ++buf) { + zsendline(*buf); crc = updcrc((0377 & *buf), crc); + } + xsendline(ZDLE); xsendline(frameend); + crc = updcrc(frameend, crc); + + crc = updcrc(0,updcrc(0,crc)); + zsendline(crc>>8); zsendline(crc); + } + if (frameend == ZCRCW) { + xsendline(XON); flushmo(); + } +} + +zsda32(buf, length, frameend) +register char *buf; +{ + register int c; + register UNSL long crc; + + crc = 0xFFFFFFFFL; + for (;--length >= 0; ++buf) { + c = *buf & 0377; + if (c & 0140) + xsendline(lastsent = c); + else + zsendline(c); + crc = UPDC32(c, crc); + } + xsendline(ZDLE); xsendline(frameend); + crc = UPDC32(frameend, crc); + + crc = ~crc; + for (c=4; --c >= 0;) { + zsendline((int)crc); crc >>= 8; + } +} + +/* + * Receive array buf of max length with ending ZDLE sequence + * and CRC. Returns the ending character or error code. + * NB: On errors may store length+1 bytes! + */ +zrdata(buf, length) +register char *buf; +{ + register int c; + register unsigned short crc; + register char *end; + register int d; + + switch (Crc32r) { + case 1: + return zrdat32(buf, length); + case 2: + return zrdatr32(buf, length); + } + + crc = Rxcount = 0; end = buf + length; + while (buf <= end) { + if ((c = zdlread()) & ~0377) { +crcfoo: + switch (c) { + case GOTCRCE: + case GOTCRCG: + case GOTCRCQ: + case GOTCRCW: + crc = updcrc((d=c)&0377, crc); + if ((c = zdlread()) & ~0377) + goto crcfoo; + crc = updcrc(c, crc); + if ((c = zdlread()) & ~0377) + goto crcfoo; + crc = updcrc(c, crc); + if (crc & 0xFFFF) { + zperr(badcrc); + return ERROR; + } + Rxcount = length - (end - buf); +#ifndef DSZ + vfile("zrdata: %d %s", Rxcount, + Zendnames[d-GOTCRCE&3]); +#endif + return d; + case GOTCAN: + zperr("Sender Canceled"); + return ZCAN; + case TIMEOUT: + zperr("TIMEOUT"); + return c; + default: + garbitch(); return c; + } + } + *buf++ = c; + crc = updcrc(c, crc); + } +#ifdef DSZ + garbitch(); +#else + zperr("Data subpacket too long"); +#endif + return ERROR; +} + +zrdat32(buf, length) +register char *buf; +{ + register int c; + register UNSL long crc; + register char *end; + register int d; + + crc = 0xFFFFFFFFL; Rxcount = 0; end = buf + length; + while (buf <= end) { + if ((c = zdlread()) & ~0377) { +crcfoo: + switch (c) { + case GOTCRCE: + case GOTCRCG: + case GOTCRCQ: + case GOTCRCW: + d = c; c &= 0377; + crc = UPDC32(c, crc); + if ((c = zdlread()) & ~0377) + goto crcfoo; + crc = UPDC32(c, crc); + if ((c = zdlread()) & ~0377) + goto crcfoo; + crc = UPDC32(c, crc); + if ((c = zdlread()) & ~0377) + goto crcfoo; + crc = UPDC32(c, crc); + if ((c = zdlread()) & ~0377) + goto crcfoo; + crc = UPDC32(c, crc); + if (crc != 0xDEBB20E3) { + zperr(badcrc); + return ERROR; + } + Rxcount = length - (end - buf); +#ifndef DSZ + vfile("zrdat32: %d %s", Rxcount, + Zendnames[d-GOTCRCE&3]); +#endif + return d; + case GOTCAN: + zperr("Sender Canceled"); + return ZCAN; + case TIMEOUT: + zperr("TIMEOUT"); + return c; + default: + garbitch(); return c; + } + } + *buf++ = c; + crc = UPDC32(c, crc); + } + zperr("Data subpacket too long"); + return ERROR; +} + +garbitch() +{ + zperr("Garbled data subpacket"); +} + +/* + * Read a ZMODEM header to hdr, either binary or hex. + * eflag controls local display of non zmodem characters: + * 0: no display + * 1: display printing characters only + * 2: display all non ZMODEM characters + * + * Set Rxhlen to size of header (default 4) (valid iff good hdr) + * On success, set Zmodem to 1, set Rxpos and return type of header. + * Otherwise return negative on error. + * Return ERROR instantly if ZCRCW sequence, for fast error recovery. + */ +zgethdr(hdr, eflag) +char *hdr; +{ + register int c, n, cancount; + + n = Zrwindow + Effbaud; /* Max bytes before start of frame */ + Rxframeind = Rxtype = 0; + +startover: + cancount = 5; +again: + /* Return immediate ERROR if ZCRCW sequence seen */ + switch (c = readline(Rxtimeout)) { + case 021: case 0221: + goto again; + case RCDO: + case TIMEOUT: + goto fifi; + case CAN: +gotcan: + if (--cancount <= 0) { + c = ZCAN; goto fifi; + } + switch (c = readline(1)) { + case TIMEOUT: + goto again; + case ZCRCW: + switch (readline(1)) { + case TIMEOUT: + c = ERROR; goto fifi; + case RCDO: + goto fifi; + default: + goto agn2; + } + case RCDO: + goto fifi; + default: + break; + case CAN: + if (--cancount <= 0) { + c = ZCAN; goto fifi; + } + goto again; + } + /* **** FALL THRU TO **** */ + default: +agn2: + if ( --n == 0) { + c = GCOUNT; goto fifi; + } + if (eflag && ((c &= 0177) & 0140)) + bttyout(c); + else if (eflag > 1) + bttyout(c); +#ifdef UNIX + fflush(stderr); +#endif + goto startover; + case ZPAD|0200: /* This is what we want. */ + Not8bit = c; + case ZPAD: /* This is what we want. */ + break; + } + cancount = 5; +splat: + switch (c = noxrd7()) { + case ZPAD: + goto splat; + case RCDO: + case TIMEOUT: + goto fifi; + default: + goto agn2; + case ZDLE: /* This is what we want. */ + break; + } + + + Rxhlen = 4; /* Set default length */ + Rxframeind = c = noxrd7(); + switch (c) { + case ZVBIN32: + if ((Rxhlen = c = zdlread()) < 0) + goto fifi; + if (c > ZMAXHLEN) + goto agn2; + Crc32r = 1; c = zrbhd32(hdr); break; + case ZBIN32: + if (Usevhdrs) + goto agn2; + Crc32r = 1; c = zrbhd32(hdr); break; + case ZVBINR32: + if ((Rxhlen = c = zdlread()) < 0) + goto fifi; + if (c > ZMAXHLEN) + goto agn2; + Crc32r = 2; c = zrbhd32(hdr); break; + case ZBINR32: + if (Usevhdrs) + goto agn2; + Crc32r = 2; c = zrbhd32(hdr); break; + case RCDO: + case TIMEOUT: + goto fifi; + case ZVBIN: + if ((Rxhlen = c = zdlread()) < 0) + goto fifi; + if (c > ZMAXHLEN) + goto agn2; + Crc32r = 0; c = zrbhdr(hdr); break; + case ZBIN: + if (Usevhdrs) + goto agn2; + Crc32r = 0; c = zrbhdr(hdr); break; + case ZVHEX: + if ((Rxhlen = c = zgethex()) < 0) + goto fifi; + if (c > ZMAXHLEN) + goto agn2; + Crc32r = 0; c = zrhhdr(hdr); break; + case ZHEX: + if (Usevhdrs) + goto agn2; + Crc32r = 0; c = zrhhdr(hdr); break; + case CAN: + goto gotcan; + default: + goto agn2; + } + for (n = Rxhlen; ++n < ZMAXHLEN; ) /* Clear unused hdr bytes */ + hdr[n] = 0; + Rxpos = hdr[ZP3] & 0377; + Rxpos = (Rxpos<<8) + (hdr[ZP2] & 0377); + Rxpos = (Rxpos<<8) + (hdr[ZP1] & 0377); + Rxpos = (Rxpos<<8) + (hdr[ZP0] & 0377); +fifi: + switch (c) { + case GOTCAN: + c = ZCAN; + /* **** FALL THRU TO **** */ + case ZNAK: + case ZCAN: + case ERROR: + case TIMEOUT: + case RCDO: + case GCOUNT: + zperr("Got %s", frametypes[c+FTOFFSET]); + /* **** FALL THRU TO **** */ +#ifndef DSZ + default: + if (c >= -4 && c <= FRTYPES) + vfile("zgethdr: %c %d %s %lx", Rxframeind, Rxhlen, + frametypes[c+FTOFFSET], Rxpos); + else + vfile("zgethdr: %c %d %lx", Rxframeind, c, Rxpos); +#endif + } + /* Use variable length headers if we got one */ + if (c >= 0 && c <= FRTYPES && Rxframeind & 040) + Usevhdrs = 1; + return c; +} + +/* Receive a binary style header (type and position) */ +zrbhdr(hdr) +register char *hdr; +{ + register int c, n; + register unsigned short crc; + + if ((c = zdlread()) & ~0377) + return c; + Rxtype = c; + crc = updcrc(c, 0); + + for (n=Rxhlen; --n >= 0; ++hdr) { + if ((c = zdlread()) & ~0377) + return c; + crc = updcrc(c, crc); + *hdr = c; + } + if ((c = zdlread()) & ~0377) + return c; + crc = updcrc(c, crc); + if ((c = zdlread()) & ~0377) + return c; + crc = updcrc(c, crc); + if (crc & 0xFFFF) { + zperr(badcrc); + return ERROR; + } +#ifdef ZMODEM + Protocol = ZMODEM; +#endif + Zmodem = 1; + return Rxtype; +} + +/* Receive a binary style header (type and position) with 32 bit FCS */ +zrbhd32(hdr) +register char *hdr; +{ + register int c, n; + register UNSL long crc; + + if ((c = zdlread()) & ~0377) + return c; + Rxtype = c; + crc = 0xFFFFFFFFL; crc = UPDC32(c, crc); +#ifdef DEBUGZ + vfile("zrbhd32 c=%X crc=%lX", c, crc); +#endif + + for (n=Rxhlen; --n >= 0; ++hdr) { + if ((c = zdlread()) & ~0377) + return c; + crc = UPDC32(c, crc); + *hdr = c; +#ifdef DEBUGZ + vfile("zrbhd32 c=%X crc=%lX", c, crc); +#endif + } + for (n=4; --n >= 0;) { + if ((c = zdlread()) & ~0377) + return c; + crc = UPDC32(c, crc); +#ifdef DEBUGZ + vfile("zrbhd32 c=%X crc=%lX", c, crc); +#endif + } + if (crc != 0xDEBB20E3) { + zperr(badcrc); + return ERROR; + } +#ifdef ZMODEM + Protocol = ZMODEM; +#endif + Zmodem = 1; + return Rxtype; +} + + +/* Receive a hex style header (type and position) */ +zrhhdr(hdr) +char *hdr; +{ + register int c; + register unsigned short crc; + register int n; + + if ((c = zgethex()) < 0) + return c; + Rxtype = c; + crc = updcrc(c, 0); + + for (n=Rxhlen; --n >= 0; ++hdr) { + if ((c = zgethex()) < 0) + return c; + crc = updcrc(c, crc); + *hdr = c; + } + if ((c = zgethex()) < 0) + return c; + crc = updcrc(c, crc); + if ((c = zgethex()) < 0) + return c; + crc = updcrc(c, crc); + if (crc & 0xFFFF) { + zperr(badcrc); return ERROR; + } + switch ( c = readline(2)) { + case 0215: + Not8bit = c; + /* **** FALL THRU TO **** */ + case 015: + /* Throw away possible cr/lf */ + switch (c = readline(2)) { + case 012: + Not8bit |= c; + } + } +#ifdef ZMODEM + Protocol = ZMODEM; +#endif + Zmodem = 1; + if (c < 0) + return c; + return Rxtype; +} + +/* Send a byte as two hex digits */ +zputhex(c) +register int c; +{ + static char digits[] = "0123456789abcdef"; + +#ifdef DEBUGZ + if (Verbose>8) + vfile("zputhex: %02X", c); +#endif + sendline(digits[(c&0xF0)>>4]); + sendline(digits[(c)&0xF]); +} + +/* + * Send character c with ZMODEM escape sequence encoding. + * Escape XON, XOFF. Escape CR following @ (Telenet net escape) + */ +zsendline(c) +{ + + /* Quick check for non control characters */ + if (c & 0140) + xsendline(lastsent = c); + else { + switch (c &= 0377) { + case ZDLE: + xsendline(ZDLE); + xsendline (lastsent = (c ^= 0100)); + break; + case 015: + case 0215: + if (!Zctlesc && (lastsent & 0177) != '@') + goto sendit; + /* **** FALL THRU TO **** */ + case 020: + case 021: + case 023: + case 0220: + case 0221: + case 0223: + xsendline(ZDLE); + c ^= 0100; + sendit: + xsendline(lastsent = c); + break; + default: + if (Zctlesc && ! (c & 0140)) { + xsendline(ZDLE); + c ^= 0100; + } + xsendline(lastsent = c); + } + } +} + +/* Decode two lower case hex digits into an 8 bit byte value */ +zgethex() +{ + register int c; + + c = zgeth1(); +#ifdef DEBUGZ + if (Verbose>8) + vfile("zgethex: %02X", c); +#endif + return c; +} +zgeth1() +{ + register int c, n; + + if ((c = noxrd7()) < 0) + return c; + n = c - '0'; + if (n > 9) + n -= ('a' - ':'); + if (n & ~0xF) + return ERROR; + if ((c = noxrd7()) < 0) + return c; + c -= '0'; + if (c > 9) + c -= ('a' - ':'); + if (c & ~0xF) + return ERROR; + c += (n<<4); + return c; +} + +/* + * Read a byte, checking for ZMODEM escape encoding + * including CAN*5 which represents a quick abort + */ +zdlread() +{ + register int c; + +again: + /* Quick check for non control characters */ + if ((c = readline(Rxtimeout)) & 0140) + return c; + switch (c) { + case ZDLE: + break; + case 023: + case 0223: + case 021: + case 0221: + goto again; + default: + if (Zctlesc && !(c & 0140)) { + goto again; + } + return c; + } +again2: + if ((c = readline(Rxtimeout)) < 0) + return c; + if (c == CAN && (c = readline(Rxtimeout)) < 0) + return c; + if (c == CAN && (c = readline(Rxtimeout)) < 0) + return c; + if (c == CAN && (c = readline(Rxtimeout)) < 0) + return c; + switch (c) { + case CAN: + return GOTCAN; + case ZCRCE: + case ZCRCG: + case ZCRCQ: + case ZCRCW: + return (c | GOTOR); + case ZRUB0: + return 0177; + case ZRUB1: + return 0377; + case 023: + case 0223: + case 021: + case 0221: + goto again2; + default: + if (Zctlesc && ! (c & 0140)) { + goto again2; + } + if ((c & 0140) == 0100) + return (c ^ 0100); + break; + } + if (Verbose>1) + zperr("Bad escape sequence %x", c); + return ERROR; +} + +/* + * Read a character from the modem line with timeout. + * Eat parity, XON and XOFF characters. + */ +noxrd7() +{ + register int c; + + for (;;) { + if ((c = readline(Rxtimeout)) < 0) + return c; + switch (c &= 0177) { + case XON: + case XOFF: + continue; + default: + if (Zctlesc && !(c & 0140)) + continue; + case '\r': + case '\n': + case ZDLE: + return c; + } + } +} + +/* Store long integer pos in Txhdr */ +stohdr(pos) +long pos; +{ + Txhdr[ZP0] = pos; + Txhdr[ZP1] = pos>>8; + Txhdr[ZP2] = pos>>16; + Txhdr[ZP3] = pos>>24; +} + +/* Recover a long integer from a header */ +long +rclhdr(hdr) +register char *hdr; +{ + register long l; + + l = (hdr[ZP3] & 0377); + l = (l << 8) | (hdr[ZP2] & 0377); + l = (l << 8) | (hdr[ZP1] & 0377); + l = (l << 8) | (hdr[ZP0] & 0377); + return l; +} + +/* End of zm.c */ diff --git a/src/cmd/zmodem/zmodem.h b/src/cmd/zmodem/zmodem.h new file mode 100644 index 0000000..0cf6c4e --- /dev/null +++ b/src/cmd/zmodem/zmodem.h @@ -0,0 +1,135 @@ +/* + * Z M O D E M . H Manifest constants for ZMODEM + * application to application file transfer protocol + * 04-17-89 Chuck Forsberg Omen Technology Inc + */ +#define ZPAD '*' /* 052 Padding character begins frames */ +#define ZDLE 030 /* Ctrl-X Zmodem escape - `ala BISYNC DLE */ +#define ZDLEE (ZDLE^0100) /* Escaped ZDLE as transmitted */ +#define ZBIN 'A' /* Binary frame indicator (CRC-16) */ +#define ZHEX 'B' /* HEX frame indicator */ +#define ZBIN32 'C' /* Binary frame with 32 bit FCS */ +#define ZBINR32 'D' /* RLE packed Binary frame with 32 bit FCS */ +#define ZVBIN 'a' /* Binary frame indicator (CRC-16) */ +#define ZVHEX 'b' /* HEX frame indicator */ +#define ZVBIN32 'c' /* Binary frame with 32 bit FCS */ +#define ZVBINR32 'd' /* RLE packed Binary frame with 32 bit FCS */ +#define ZRESC 0176 /* RLE flag/escape character */ +#define ZMAXHLEN 16 /* Max header information length NEVER CHANGE */ +#define ZMAXSPLEN 1024 /* Max subpacket length NEVER CHANGE */ + +/* Frame types (see array "frametypes" in zm.c) */ +#define ZRQINIT 0 /* Request receive init */ +#define ZRINIT 1 /* Receive init */ +#define ZSINIT 2 /* Send init sequence (optional) */ +#define ZACK 3 /* ACK to above */ +#define ZFILE 4 /* File name from sender */ +#define ZSKIP 5 /* To sender: skip this file */ +#define ZNAK 6 /* Last packet was garbled */ +#define ZABORT 7 /* Abort batch transfers */ +#define ZFIN 8 /* Finish session */ +#define ZRPOS 9 /* Resume data trans at this position */ +#define ZDATA 10 /* Data packet(s) follow */ +#define ZEOF 11 /* End of file */ +#define ZFERR 12 /* Fatal Read or Write error Detected */ +#define ZCRC 13 /* Request for file CRC and response */ +#define ZCHALLENGE 14 /* Receiver's Challenge */ +#define ZCOMPL 15 /* Request is complete */ +#define ZCAN 16 /* Other end canned session with CAN*5 */ +#define ZFREECNT 17 /* Request for free bytes on filesystem */ +#define ZCOMMAND 18 /* Command from sending program */ +#define ZSTDERR 19 /* Output to standard error, data follows */ + +/* ZDLE sequences */ +#define ZCRCE 'h' /* CRC next, frame ends, header packet follows */ +#define ZCRCG 'i' /* CRC next, frame continues nonstop */ +#define ZCRCQ 'j' /* CRC next, frame continues, ZACK expected */ +#define ZCRCW 'k' /* CRC next, ZACK expected, end of frame */ +#define ZRUB0 'l' /* Translate to rubout 0177 */ +#define ZRUB1 'm' /* Translate to rubout 0377 */ + +/* zdlread return values (internal) */ +/* -1 is general error, -2 is timeout */ +#define GOTOR 0400 +#define GOTCRCE (ZCRCE|GOTOR) /* ZDLE-ZCRCE received */ +#define GOTCRCG (ZCRCG|GOTOR) /* ZDLE-ZCRCG received */ +#define GOTCRCQ (ZCRCQ|GOTOR) /* ZDLE-ZCRCQ received */ +#define GOTCRCW (ZCRCW|GOTOR) /* ZDLE-ZCRCW received */ +#define GOTCAN (GOTOR|030) /* CAN*5 seen */ + +/* Byte positions within header array */ +#define ZF0 3 /* First flags byte */ +#define ZF1 2 +#define ZF2 1 +#define ZF3 0 +#define ZP0 0 /* Low order 8 bits of position */ +#define ZP1 1 +#define ZP2 2 +#define ZP3 3 /* High order 8 bits of file position */ + +/* Bit Masks for ZRINIT flags byte ZF0 */ +#define CANFDX 01 /* Rx can send and receive true FDX */ +#define CANOVIO 02 /* Rx can receive data during disk I/O */ +#define CANBRK 04 /* Rx can send a break signal */ +#define CANRLE 010 /* Receiver can decode RLE */ +#define CANLZW 020 /* Receiver can uncompress */ +#define CANFC32 040 /* Receiver can use 32 bit Frame Check */ +#define ESCCTL 0100 /* Receiver expects ctl chars to be escaped */ +#define ESC8 0200 /* Receiver expects 8th bit to be escaped */ + +/* Bit Masks for ZRINIT flags byte ZF1 */ +#define CANVHDR 01 /* Variable headers OK */ + +/* Parameters for ZSINIT frame */ +#define ZATTNLEN 32 /* Max length of attention string */ +#define ALTCOFF ZF1 /* Offset to alternate canit string, 0 if not used */ +/* Bit Masks for ZSINIT flags byte ZF0 */ +#define TESCCTL 0100 /* Transmitter expects ctl chars to be escaped */ +#define TESC8 0200 /* Transmitter expects 8th bit to be escaped */ + +/* Parameters for ZFILE frame */ +/* Conversion options one of these in ZF0 */ +#define ZCBIN 1 /* Binary transfer - inhibit conversion */ +#define ZCNL 2 /* Convert NL to local end of line convention */ +#define ZCRESUM 3 /* Resume interrupted file transfer */ +/* Management include options, one of these ored in ZF1 */ +#define ZMSKNOLOC 0200 /* Skip file if not present at rx */ +/* Management options, one of these ored in ZF1 */ +#define ZMMASK 037 /* Mask for the choices below */ +#define ZMNEWL 1 /* Transfer if source newer or longer */ +#define ZMCRC 2 /* Transfer if different file CRC or length */ +#define ZMAPND 3 /* Append contents to existing file (if any) */ +#define ZMCLOB 4 /* Replace existing file */ +#define ZMNEW 5 /* Transfer if source newer */ + /* Number 5 is alive ... */ +#define ZMDIFF 6 /* Transfer if dates or lengths different */ +#define ZMPROT 7 /* Protect destination file */ +/* Transport options, one of these in ZF2 */ +#define ZTLZW 1 /* Lempel-Ziv compression */ +#define ZTRLE 3 /* Run Length encoding */ +/* Extended options for ZF3, bit encoded */ +#define ZXSPARS 64 /* Encoding for sparse file operations */ +#define ZCANVHDR 01 /* Variable headers OK */ +/* Receiver window size override */ +#define ZRWOVR 4 /* byte position for receive window override/256 */ + +/* Parameters for ZCOMMAND frame ZF0 (otherwise 0) */ +#define ZCACK1 1 /* Acknowledge, then do command */ + +long rclhdr(); + +/* Globals used by ZMODEM functions */ +extern Rxframeind; /* ZBIN ZBIN32, or ZHEX type of frame */ +extern Rxtype; /* Type of header received */ +extern Rxcount; /* Count of data bytes received */ +extern Rxtimeout; /* Tenths of seconds to wait for something */ +extern long Rxpos; /* Received file position */ +extern long Txpos; /* Transmitted file position */ +extern Txfcs32; /* TURE means send binary frames with 32 bit FCS */ +extern Crc32t; /* Display flag indicating 32 bit CRC being sent */ +extern Crc32; /* Display flag indicating 32 bit CRC being received */ +extern Znulls; /* Number of nulls to send at beginning of ZDATA hdr */ +extern char Attn[ZATTNLEN+1]; /* Attention string rx sends to tx on err */ +extern char *Altcan; /* Alternate canit string */ + +/* End of ZMODEM.H */ diff --git a/src/cmd/zmodem/zmr.c b/src/cmd/zmodem/zmr.c new file mode 100644 index 0000000..708a248 --- /dev/null +++ b/src/cmd/zmodem/zmr.c @@ -0,0 +1,185 @@ +/* + * File: zmr.c 07-30-1989 + * Copyright 1988, 1989 Omen Technology Inc All Rights Reserved + * + * + * + * This module implements ZMODEM Run Length Encoding, an + * extension that was not funded by the original Telenet + * development contract. + * + * This software may be freely used for non commercial and + * educational (didactic only) purposes. This software may also + * be freely used to support file transfer operations to or from + * licensed Omen Technology products. Any programs which use + * part or all of this software must be provided in source form + * with this notice intact except by written permission from Omen + * Technology Incorporated. + * + * Use of this software for commercial or administrative purposes + * except when exclusively limited to interfacing Omen Technology + * products requires a per port license payment of $20.00 US per + * port (less in quantity). Use of this code by inclusion, + * decompilation, reverse engineering or any other means + * constitutes agreement to these conditions and acceptance of + * liability to license the materials and payment of reasonable + * legal costs necessary to enforce this license agreement. + * + * + * Omen Technology Inc FAX: 503-621-3745 + * Post Office Box 4681 + * Portland OR 97208 + * + * This code is made available in the hope it will be useful, + * BUT WITHOUT ANY WARRANTY OF ANY KIND OR LIABILITY FOR ANY + * DAMAGES OF ANY KIND. + * + * ZMODEM RLE compression and decompression functions + */ + +/* Send data subpacket RLE encoded with 32 bit FCS */ +zsdar32(buf, length, frameend) +char *buf; +{ + register int c, l, n; + register UNSL long crc; + + crc = 0xFFFFFFFFL; l = *buf++ & 0377; + if (length == 1) { + zsendline(l); crc = UPDC32(l, crc); + if (l == ZRESC) { + zsendline(1); crc = UPDC32(1, crc); + } + } else { + for (n = 0; --length >= 0; ++buf) { + if ((c = *buf & 0377) == l && n < 126 && length>0) { + ++n; continue; + } + switch (n) { + case 0: + zsendline(l); + crc = UPDC32(l, crc); + if (l == ZRESC) { + zsendline(0100); crc = UPDC32(0100, crc); + } + l = c; break; + case 1: + if (l != ZRESC) { + zsendline(l); zsendline(l); + crc = UPDC32(l, crc); + crc = UPDC32(l, crc); + n = 0; l = c; break; + } + /* **** FALL THRU TO **** */ + default: + zsendline(ZRESC); crc = UPDC32(ZRESC, crc); + if (l == 040 && n < 34) { + n += 036; + zsendline(n); crc = UPDC32(n, crc); + } + else { + n += 0101; + zsendline(n); crc = UPDC32(n, crc); + zsendline(l); crc = UPDC32(l, crc); + } + n = 0; l = c; break; + } + } + } + xsendline(ZDLE); xsendline(frameend); + crc = UPDC32(frameend, crc); + + crc = ~crc; + for (length=4; --length >= 0;) { + zsendline((int)crc); crc >>= 8; + } +} + + +/* Receive data subpacket RLE encoded with 32 bit FCS */ +zrdatr32(buf, length) +register char *buf; +{ + register int c; + register UNSL long crc; + register char *end; + register int d; + + crc = 0xFFFFFFFFL; Rxcount = 0; end = buf + length; + d = 0; /* Use for RLE decoder state */ + while (buf <= end) { + if ((c = zdlread()) & ~0377) { +crcfoo: + switch (c) { + case GOTCRCE: + case GOTCRCG: + case GOTCRCQ: + case GOTCRCW: + d = c; c &= 0377; + crc = UPDC32(c, crc); + if ((c = zdlread()) & ~0377) + goto crcfoo; + crc = UPDC32(c, crc); + if ((c = zdlread()) & ~0377) + goto crcfoo; + crc = UPDC32(c, crc); + if ((c = zdlread()) & ~0377) + goto crcfoo; + crc = UPDC32(c, crc); + if ((c = zdlread()) & ~0377) + goto crcfoo; + crc = UPDC32(c, crc); + if (crc != 0xDEBB20E3) { + zperr(badcrc); + return ERROR; + } + Rxcount = length - (end - buf); +#ifndef DSZ + vfile("zrdatr32: %d %s", Rxcount, + Zendnames[d-GOTCRCE&3]); +#endif + return d; + case GOTCAN: + zperr("Sender Canceled"); + return ZCAN; + case TIMEOUT: + zperr("TIMEOUT"); + return c; + default: + zperr("Bad data subpacket"); + return c; + } + } + crc = UPDC32(c, crc); + switch (d) { + case 0: + if (c == ZRESC) { + d = -1; continue; + } + *buf++ = c; continue; + case -1: + if (c >= 040 && c < 0100) { + d = c - 035; c = 040; goto spaces; + } + if (c == 0100) { + d = 0; + *buf++ = ZRESC; continue; + } + d = c; continue; + default: + d -= 0100; + if (d < 1) + goto badpkt; +spaces: + if ((buf + d) > end) + goto badpkt; + while ( --d >= 0) + *buf++ = c; + d = 0; continue; + } + } +badpkt: + zperr("Data subpacket too long"); + return ERROR; +} + diff --git a/src/cmd/zmodem/zupl.t b/src/cmd/zmodem/zupl.t new file mode 100644 index 0000000..5e6953b --- /dev/null +++ b/src/cmd/zmodem/zupl.t @@ -0,0 +1,26 @@ + echo "ProYAM/ZCOMM script to upload minirb and rz/sz to *nix" + if S>1200 pt1 + ena -t + if !fminirb.c echo "Can't find minirb.c !!"; abort + putw "stty -echo; cat >minirb.c\r" + f -xHr minirb.c + putw "\r\4" + putw "stty echo\r" + dis -h + pat 1 "rwx" + pat 2 "%" + put "cc minirb.c -o minirb; ls -l minirb\r" + wait -f120 + if 1 goto okok + echo "The compiiation appears to have failed." + echo "Please compile minirb.c to minirb, then" + echo "hit F5 to upload the rest of the rz/sz files." + set f5 +@putw minirb\r; sb README zmodem.h zm.c sz.c rz.c crctab.c rbsb.c *.1 gz ptest.sh + t + return +okok: echo "Minirb Compilation Appears Successful." + put minirb\r + sb README ?akefile zmodem.h zm.c sz.c rz.c crc.c crc.1 crctab.c rbsb.c *.1 gz ptest.sh + t + return diff --git a/src/elf32-mips.ld b/src/elf32-mips.ld new file mode 100644 index 0000000..31b362b --- /dev/null +++ b/src/elf32-mips.ld @@ -0,0 +1,253 @@ +/* + * Linker script for user executables. + */ +OUTPUT_FORMAT("elf32-littlemips", "elf32-bigmips", + "elf32-littlemips") +OUTPUT_ARCH(mips) +ENTRY(_start) + +/* Required by Microchip C32 linker */ +/*MEMORY +{ + kseg0_program_mem (rx) : ORIGIN = 0x9D000000, LENGTH = 0x80000 + kseg0_boot_mem : ORIGIN = 0x9FC00490, LENGTH = 0x970 + exception_mem : ORIGIN = 0x9FC01000, LENGTH = 0x1000 + kseg1_boot_mem : ORIGIN = 0xBFC00000, LENGTH = 0x490 + kseg1_data_mem (w!x) : ORIGIN = 0xA0000000, LENGTH = 0x20000 +}*/ + +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + PROVIDE (__executable_start = 0x7f008000); . = 0x7f008000; + .interp : { *(.interp) } + /*.reginfo : { *(.reginfo) }*/ + .note.gnu.build-id : { *(.note.gnu.build-id) } + .dynamic : { *(.dynamic) } + .hash : { *(.hash) } + .gnu.hash : { *(.gnu.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rel.init : { *(.rel.init) } + .rela.init : { *(.rela.init) } + .rel.text : { *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) } + .rela.text : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) } + .rel.fini : { *(.rel.fini) } + .rela.fini : { *(.rela.fini) } + .rel.rodata : { *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) } + .rela.rodata : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) } + .rel.data.rel.ro : { *(.rel.data.rel.ro* .rel.gnu.linkonce.d.rel.ro.*) } + .rela.data.rel.ro : { *(.rela.data.rel.ro* .rela.gnu.linkonce.d.rel.ro.*) } + .rel.data : { *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) } + .rela.data : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) } + .rel.tdata : { *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) } + .rela.tdata : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) } + .rel.tbss : { *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) } + .rela.tbss : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.sdata : { *(.rel.sdata .rel.sdata.* .rel.gnu.linkonce.s.*) } + .rela.sdata : { *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*) } + .rel.sbss : { *(.rel.sbss .rel.sbss.* .rel.gnu.linkonce.sb.*) } + .rela.sbss : { *(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*) } + .rel.sdata2 : { *(.rel.sdata2 .rel.sdata2.* .rel.gnu.linkonce.s2.*) } + .rela.sdata2 : { *(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*) } + .rel.sbss2 : { *(.rel.sbss2 .rel.sbss2.* .rel.gnu.linkonce.sb2.*) } + .rela.sbss2 : { *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*) } + .rel.bss : { *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) } + .rela.bss : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .init : + { + KEEP (*(.init)) + } =0 + .plt : { *(.plt) } + .text : + { + _ftext = . ; + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.mips16.fn.*) *(.mips16.call.*) + } =0 + .fini : + { + KEEP (*(.fini)) + } =0 + PROVIDE (__etext = .); + PROVIDE (_etext = .); + PROVIDE (etext = .); + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } + .rodata1 : { *(.rodata1) } + .sdata2 : + { + *(.sdata2 .sdata2.* .gnu.linkonce.s2.*) + } + .sbss2 : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) } + .eh_frame_hdr : { *(.eh_frame_hdr) } + .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) } + .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) } + /* Adjust the address for the data segment. */ + . = ALIGN (16) - ((16 - .) & (16 - 1)); . = DATA_SEGMENT_ALIGN (16, 16); + /* Exception handling */ + .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) } + .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) } + /* Thread Local Storage sections */ + .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) } + .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } + .preinit_array : + { + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + } + .init_array : + { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + } + .fini_array : + { + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + PROVIDE_HIDDEN (__fini_array_end = .); + } + .ctors : + { + /* gcc uses crtbegin.o to find the start of + the constructors, so we make sure it is + first. Because this is a wildcard, it + doesn't matter if the user does not + actually link against crtbegin.o; the + linker won't look for a file to match a + wildcard. The wildcard also means that it + doesn't matter which directory crtbegin.o + is in. */ + KEEP (*crtbegin.o(.ctors)) + KEEP (*crtbegin?.o(.ctors)) + /* We don't want to include the .ctor section from + the crtend.o file until after the sorted ctors. + The .ctor section from the crtend file contains the + end of ctors marker and it must be last */ + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } + .dtors : + { + KEEP (*crtbegin.o(.dtors)) + KEEP (*crtbegin?.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } + .jcr : { KEEP (*(.jcr)) } + .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro* .gnu.linkonce.d.rel.ro.*) } + . = DATA_SEGMENT_RELRO_END (0, .); + .data : + { + __data_start = .; + _fdata = . ; + *(.data .data.* .gnu.linkonce.d.*) + SORT(CONSTRUCTORS) + } + .data1 : { *(.data1) } + .got.plt : { *(.got.plt) } + . = .; + _gp = ALIGN(16) + 0x7ff0; + .got : { *(.got) } + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + .sdata : + { + *(.sdata .sdata.* .gnu.linkonce.s.*) + } + .lit8 : { *(.lit8) } + .lit4 : { *(.lit4) } + _edata = .; PROVIDE (edata = .); + __bss_start = .; + _fbss = .; + .sbss : + { + *(.dynsbss) + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) + } + .bss : + { + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. + FIXME: Why do we need it? When there is no .bss section, we don't + pad the .data section. */ + . = ALIGN(. != 0 ? 32 / 8 : 1); + } + . = ALIGN(32 / 8); + . = ALIGN(32 / 8); + _end = .; PROVIDE (end = .); + . = DATA_SEGMENT_END (.); + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /* DWARF 3 */ + .debug_pubtypes 0 : { *(.debug_pubtypes) } + .debug_ranges 0 : { *(.debug_ranges) } + .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) } + .gptab.sdata : { *(.gptab.data) *(.gptab.sdata) } + .gptab.sbss : { *(.gptab.bss) *(.gptab.sbss) } + .mdebug.abi32 : { KEEP(*(.mdebug.abi32)) } + .mdebug.abiN32 : { KEEP(*(.mdebug.abiN32)) } + .mdebug.abi64 : { KEEP(*(.mdebug.abi64)) } + .mdebug.abiO64 : { KEEP(*(.mdebug.abiO64)) } + .mdebug.eabi32 : { KEEP(*(.mdebug.eabi32)) } + .mdebug.eabi64 : { KEEP(*(.mdebug.eabi64)) } + .gcc_compiled_long32 : { KEEP(*(.gcc_compiled_long32)) } + .gcc_compiled_long64 : { KEEP(*(.gcc_compiled_long64)) } + /DISCARD/ : { *(.rel.dyn) } + /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) } +} diff --git a/src/games/Makefile b/src/games/Makefile new file mode 100644 index 0000000..e20f0dc --- /dev/null +++ b/src/games/Makefile @@ -0,0 +1,89 @@ +# +# Copyright (c) 1980 Regents of the University of California. +# All rights reserved. The Berkeley software License Agreement +# specifies the terms and conditions for redistribution. +# +TOPSRC = $(shell cd ../..; pwd) +include $(TOPSRC)/target.mk +#include $(TOPSRC)/cross.mk + +CFLAGS += -Werror -Wall -Os + +# Programs that live in subdirectories, and have makefiles of their own. +# +SUBDIR = adventure backgammon battlestar rogue sail trek +# TODO: atc boggle btlgammon cribbage +# fortune hangman hunt mille monop phantasia quiz robots +# sail snake warp + +# C programs that live in the current directory and do not need +# explicit make lines. +# +STD = banner arithmetic bcd cfscores factor fish morse \ + number ppt wump + +# C programs that live in the current directory and need explicit make lines. +# +NSTD = canfield primes rain worm worms + +all: $(SUBDIR) $(STD) $(NSTD) + +$(SUBDIR): FRC + $(MAKE) -C $@ $(MFLAGS) + +FRC: + +# $(STD) +%: %.c + $(CC) $(CFLAGS) $(LDFLAGS) -o $@.elf $< $(LIBS) + $(OBJDUMP) -S $@.elf > $@.dis + $(SIZE) $@.elf + $(ELF2AOUT) $@.elf $@ && /bin/rm $@.elf + +install: $(STD) $(NSTD) + -for i in $(SUBDIR); do \ + make -C $$i $(MFLAGS) DESTDIR=$(DESTDIR) install; done + -for i in $(STD) $(NSTD); do \ + install $$i $(DESTDIR)/games/$$i; done + -for i in *.6; do \ + ${MANROFF} $$i > $(DESTDIR)/share/man/cat6/`basename $$i .6`.0; done + cat < /dev/null > $(DESTDIR)/games/lib/cfscores + chmod 666 $(DESTDIR)/games/lib/cfscores + +clean: + rm -f a.out core *.s *.o *.dis *.elf $(STD) $(NSTD) + -for i in $(SUBDIR); do make -C $$i $(MFLAGS) clean; done + +# Files listed in $(NSTD) have explicit make lines given below. + +canfield: canfield.c + $(CC) $(CFLAGS) $(LDFLAGS) -o $@.elf $< -lcurses -ltermcap $(LIBS) + $(OBJDUMP) -S $@.elf > $@.dis + $(SIZE) $@.elf + $(ELF2AOUT) $@.elf $@ && /bin/rm $@.elf + +primes: primes.c + $(CC) $(CFLAGS) $(LDFLAGS) -o $@.elf $< -lm $(LIBS) + $(OBJDUMP) -S $@.elf > $@.dis + $(SIZE) $@.elf + $(ELF2AOUT) $@.elf $@ && /bin/rm $@.elf + +rain: rain.c + $(CC) $(CFLAGS) $(LDFLAGS) -o $@.elf $< -ltermcap $(LIBS) + $(OBJDUMP) -S $@.elf > $@.dis + $(SIZE) $@.elf + $(ELF2AOUT) $@.elf $@ && /bin/rm $@.elf + +worm: worm.c + $(CC) $(CFLAGS) $(LDFLAGS) -o $@.elf $< -lcurses -ltermcap $(LIBS) + $(OBJDUMP) -S $@.elf > $@.dis + $(SIZE) $@.elf + $(ELF2AOUT) $@.elf $@ && /bin/rm $@.elf + +worms: worms.c + $(CC) $(CFLAGS) $(LDFLAGS) -o $@.elf $< -ltermcap $(LIBS) + $(OBJDUMP) -S $@.elf > $@.dis + $(SIZE) $@.elf + $(ELF2AOUT) $@.elf $@ && /bin/rm $@.elf + +# DO NOT DELETE THIS LINE -- make depend uses it diff --git a/src/games/adventure/Makefile b/src/games/adventure/Makefile new file mode 100644 index 0000000..15dfe65 --- /dev/null +++ b/src/games/adventure/Makefile @@ -0,0 +1,35 @@ +TOPSRC = $(shell cd ../../..; pwd) +include $(TOPSRC)/target.mk +#include $(TOPSRC)/cross.mk + +CFLAGS += -Os -Wall -Werror + +OBJS = done.o init.o io.o main.o save.o subr.o vocab.o wizard.o +MAN = adventure.0 +MANSRC = adventure.6 + +all: adventure $(MAN) adventure.dat + +# Data file format is compatible for all little-endian machines. +# To rebuild it, compile the program on Linux. +adventure.dat: #glorkz + ./adventure glorkz + +adventure: ${OBJS} + ${CC} ${LDFLAGS} -o adventure.elf ${OBJS} ${LIBS} + ${OBJDUMP} -S adventure.elf > adventure.dis + ${SIZE} adventure.elf + ${ELF2AOUT} adventure.elf $@ && rm adventure.elf + +${MAN}: ${MANSRC} + ${MANROFF} $< > $@ + +clean: + rm -f *.o *.0 *.elf ${MAN} adventure *.elf *.dis tags *~ + +install: all + install adventure $(DESTDIR)/games/ + cp adventure.dat $(DESTDIR)/games/lib/ + cp ${MAN} $(DESTDIR)/share/man/cat6/ + +$(OBJS): hdr.h diff --git a/src/games/adventure/adventure.6 b/src/games/adventure/adventure.6 new file mode 100644 index 0000000..4ecb80a --- /dev/null +++ b/src/games/adventure/adventure.6 @@ -0,0 +1,21 @@ +.\" @(#)adventure.6 6.2 (Berkeley) 5/6/86 +.\" +.TH ADVENTURE 6 "May 6, 1986" +.AT 3 +.SH NAME +adventure \- an exploration game +.SH SYNOPSIS +.B /usr/games/adventure +.SH DESCRIPTION +The object of the game is to +locate and explore Colossal Cave, find the treasures hidden there, +and bring them back to the building with you. +The program is self-descriptive to a point, but part of the game is to discover +its rules. +.PP +To terminate a game, type `quit'; +to save a game for later resumption, type `suspend'. +.SH BUGS +.PP +Saving a game creates a large executable file instead of just +the information needed to resume the game. diff --git a/src/games/adventure/adventure.dat b/src/games/adventure/adventure.dat new file mode 100644 index 0000000000000000000000000000000000000000..1d9df558072daa02c68783cdd6941ad49b775d88 GIT binary patch literal 72040 zcmb@v`9mUEwk;e1L4-^Rh!7A1n23s~s3;DZX$lA!%mTsSfVS0D+Er%1%(Swq%zNKg z_h0|kJ^^ZGci;E=e&0`(rE-YjoPG9Qd#!awpFaPx(ltYav0)1YOCD)ut$WboBP)7v zq3Sp5SBAgLm7T7;75RO?=e&sqbG1;!h`8*YK*8{26R~%_w)^A5r_T>N2Cw8JftbI0 zthSc!=k|b@Ve)a>YTyJxD!h!*9#hAypcsJmm{yP+L? z`aE1YRm^h4Cpcrh%8$RY%hSp&Z)Y}GvAY-UrIeCytOTypZc{q#U|h9iC>xnBU0&9s z-%9gZA)>^DuuHY2-pZ@Wu{RMs_|+Qs^wisNiAAq=x39jt=IzU)lT6Xnnx=4F?*7TS zbD8c|mG|B#m5sVzuU#7vclU~O-)*R?t-LLv>y3w}=M{1D#~$}xy8EVWaEpQQYquE^ z+Fsq+ElTPRyP(GW=z6&y3<&jz-J>-tKmPXO)7`oeSz3-A9`lY3b{Vtvn%5TS8eToK zAwOR5@tkY0Tr;^&-=*WzhHo{g9Vz+S-#!;sN^!4n?hVx+zq}l=9C5Eq9=sXcYH^xy zW`sETeELO^%;+*zG^OUH_xj@>|KgLQ@j^v3D?=?>4!UB#)n)m$lD936y0?8bln?*# z`{#$O zb>s4n+qu1dzp^}JV zdAQN%%w`=E95a*0ykBjVoa-ZVr@{qIoHgK78{`vUrmFnqqY)2^y^Pvu&Q@Akj`U8r~+4{0w zc&zrF$+_U`euyhXv{)Gvw6*h|dw)@MetdZR{BT=W?ZSoPpN+YsNa6rjbo^>v&)?Pq zp*$v$+fi3scSrhTtLnV*4RXEnKR+37;s$S)Yu=8?)#J9zV(76ybZ(DMSIXf?fj)%k zXG^{7rY^ei`S{>(k~!ZPD|2P_% zE0R>c#yt8|eflnsh8tSQ_|v^^V_Uvlm1cFr^oGigV@a-aa&Tu71L`g``d0lo#7vA&FE5m zkdW;9>8YXl!!9Sca34M#^&Hs;43jB}ftiR)2z2XWYw2BdVKz_XJ+288p1_s(`*#d*Q5wmy8if?62#vHP5=m>u~ zML3Hqv%!(4l}u}|`|ZYjcz9begY}`O6AGTGzWGe|uxLc;7=`PrQDN*v)TxWEyLa+x zi;t(YK~7RDxntOC#pTU(X=kA9eeUoP2^0b*Y!?J;IUp{XOoW?s=9Jq zH?Wl3Ja!cBv1-gDv4Q;@2o25yV?@Kaw2(oVXxWkv7$(;X>4OWWjq6stzJ>knyZ*qo z8!aRdC_Z7I@dhgbJ*W4*CYRK#aNOo?A)YShowC&`HP!<8>^hBf8uB&=zD_`A^LQ@Z z=e_Hp%UsV44Y3r;!3rNq{M3E?Pu`cA8{VGk*l1n4%W-C?d-vkz_3F#3xpWzC*kd)~ z*siBf8_!G=6Zhg?&3b0XYP1k>&3V<5r}aK5;SIOm%;LG6)SR=gXa|3t<{n!u`;Gf* zxgIf#L#3nX*M^e9{xWFVcLxWb+D|XUrLn=~gKEFA5FM}6^f@zR4}Yd>iF?mA;TtN4M>OSeP^X?l2pEZmZgj zVk6ivO|CvPL{GR)*ArPEc8c{+d0f7ZP^@B~sYubg1AT93#g2+851O92vR2mIcS+3( zlihUv+!Q`wj{Avap(Bnmut7DWzOAMSe z_?Vj)e)#n{UQb?>f3MZIuhBZ9Ju(srbjO&K_rb?e&z{!Dx7C2$4*&406?^j?4_&as zw}$+s<-7g0#@=Oq=wJa|T}j2ZhR5E8IRx2XpM%iks~m@TZAkH=Q?uaRUR<9rq}=3mVv%XeRPn$`fQe23`bKxWT_>KaOSO zD|~n3>Dm3$+w}UwVq4+v-r}(vHul&#d)?q2$U!Ch&-YzVw-if`&T}-zrqBuL zWucW?@9y=QjZ`?eQpF@5DshgZb#|m2Dji2|aPaFl;e%e=w@)}e_kaD>O?-7EG`PkR z*DGF15v=^@IxU65^`_Ptp15AQ6Gz>HQAXKZJAFImFPmjOmpB_KksaKPZNAp$uW~Q4nL%~AC=|GI*_*G0IlkM^IbyXdN zjn0bqW zPH5}b-Nvq-w;rj^mzB2S{<-i_ee-BH{(P`D?2|Kb5a>3M3$D0XC~%LL8-er8!}GeZ z9!{D=@aU~A6pbWF zqI%Ms)*%$s#Q2RmNc94uEBo-gp4c_7zmLBelqeQavOI%43Mr;rTS`S&m6DQl)wbxH z!aqE)#n401hxujYfg8Q{OvV>n=>$Y$C@HMoxLc6$2(Y5#x2KwZa%#-!Vq0|WPz~0K z=I~zDF;cD-)J`!;lHG>Drw*uqa%^blxt^|^G=!P5aI8v;m^&>06n~dy1BHeW%O@z+SgETAu={E?3gQ8 z5}PXq(o+vAwB{RkMT}$PjI&I7;XS{mvvP1O z&>PyrW}JM$Ff^%OZUoPzL#{H6&6V9{-O3BA_H{j&HOx>AMI_?zB$M~uKKw%jL#fb~ zZsa}^R0|~tAeUOX5A5_BujZBO1xe7Yxm8tso6Fsu>-VE%s-(7p}oA#>Pw zq8LBtmAiN9S{GIQ+{X6(Y05La;mi?_d57s@W+YCp6%3nG zy;Aedhi^igv$gsZA8rf06=uWNs`4KD=27qjJIuBgs;5RFXHqP+m10!d2H4}ci?vU9X zD>G#*vDRiHj2+OMb$4GE@w#hxByxq)rXaFsTgG*gS;t5#1vY=9C^Trtj&D`_@sAI` zJy&-BBvok8#;-RFduCr;o#Pwa=z8VUv;$kPYRf!O3Z6GP=-Nn*)0 zZ6%}eN}tnQ5o6IRpZE3kR<)6G2eHBGrww85Ddc*1S5iNrft&>^OJQaH&xPNZ z!q(%z^U>BDTQTGp#$xE>Z|xWV&cFEgchmIW82-yQ+p_cDd6ZwCXUe~OQ(yk)FYwF% z`~`k#JU_B8|MNHU<;5HM^4|qFuF+8(TDKwb+xNDu*0eB*BK}5#vP;sI7Lh;{?d#sF z)H+6D3D!`YD?3mPBk|?2p(Nx=`q-3>jw4vc4#wTF&E(aNCwK&`=VYksd>4!BZcSdZ zKu?UbJ)BfI@%pU$c}3n~5$Nnl~6 z>DM`Clb+a(Ytw~1ouCVISE5d$?!CJ0GNy%$+&{(xZ?+o5P>tk|fO=UKK-FayPp zDU5{l=Uohtqj$rTzwHVDdfr(G+e(t7U7?OqEa+MjUDgX?p*lO)P4y%*Ka9ugkAFPR z?|%{rUtaM0>wIL#HAn-D6iyLrtq{-dqmEJ53|$#UkeV_`EZyC`=*5tBr3{g4$SSak z;xtwj>wi4241B4xl|0Z_tEebkK|IxvaLR|h-O`DE_cpj%&AXGMZt566HYKqvJL15x z-DR!e4mQMi{)Fh21UWqgkFXY6b?s}1+ai{)DE%{n|X@2#h z;;dto*LWJo5h}eX19{4g(x!?IfZ&%yZ9_{XWP&Fa((#m1b#9~R z_~V=P3&{A5v^D7G0e++nfJX#xjmKUc3(qQ3EGXtw(mCGc1)l2Opxkb7fN^FGGjM4L zFck%(lB#VBreqrxOv9jCobK#HY z==4vP+&?Y*%~@0ec2-2)CHO8zNVhnyP@4j}M+(ZsSOz$a83|SDrOvE!>=y5qg4;-O zbECns=`~M>Xh85)FVNWuI*|X{I!1a?@w3*F6YKyXTp&?*Lmq2P?MOss{lH%`&> zH=MR`u<6zB);SXC?ru*)xBn=$@zs#V}iyNJO~g?OfnWknfVhp}`7ZmbDQ6;6TqPaqr%1^S=4;TviGOP6?@3 zuPQ(O@l6ssO$<4#>cy5QcPPi7z^ISSsy(X*Syj!-y^2cC6{K_<|ltsE-j zA`Zk&mXGFFx}0X!w$vH3QnpNZa691jlO95}pOuJI(bFKyeU-0Wvf|CfXP3i=Mi-Io zyCh{N6G&h88ymy?Z7HOT(Zmt_eN4hqqf6-B>J-7u`lKN`R2WaC9AyDt9k#^j9&)q7e-@2h_a# z{W-$3%d%<;nmRj%8bw~5r6NqfTb2(d$vT>z6GT*v{#^L|IlNmnz)z3AKS%k0a;Lph ze%9M%bD3K=yN%?qgdW4;X~b=J@n=|DZ039G7-h34dW8n|7!>2al`I~N|Li6d5 zg*^rv?(3PmtiG;P>^IuwR+XwvLlfLC5h;%UP|2f3b%1eD2L`F&7tk+O_i%yF(VA^T zR)NBy0fgEYVV~{&nl!&4GHl9f+PJd6PvB|xPF$>0%Wwd+!FsAXxloP2Thkve%^2qT zjwGp_26z4O_vgsRp2#-!;Y!E5qtoT8SFJJRf&k+q)*(o^x?6QLOR(<^x(zQNU~SI; zf`#pH9V6w6f#{G{zJBiI?%vye-~63`=jmi|DeB5T&@=3M(cmhAnJ|3Sk@Rc9l{nxZ zWe@t4-GmfSsEt}+pBpyNI*Gepp%=$L_RR>*J%bN6fB}Sp#|iKq->s0QEP28?Bw=q-hw3}#-@eZW`bxb$2LX-Bxd>$Z*;o2$)~lWU)X(^eaSy0T>{K zw=74ReHUW)f2r=fpQTiUw{MRExV`}av`)E>IQoQwKU#CZ%IzyWdVAr=c88&v!$_!x zI0y_xQn&B*_iV#F-as??@i}--QirE5lF4CJ1Dp(0cr@gKZ-DVp+QoJsCFY7Ft&1h4 z$Fo*+T|2-yi*-F(iFjhO8e76wk0Z=@{&HKgs~yur4OoC}7za>EPDaCs{#xgs`gCY3 z&p%+8X;TY##~3SbE{f8P=aLZzSehpM@c2z=C1@zLbU`1OfII^?H-pogmu0Ayv zn*#*YpiAMG4u}V&t^^9{p{g2@c+?Xp8m`QKFjXsgx7`OAC)*a)&NYYIEK0V-y~@>QjEC!%me z>-N=P$HIwcITZ_L{-?)B%7m@1WdJEJpG(NQtvolKrC-Hak6hAPsRQ-U?0eU-Wpx5( zzUCBx&#SHEG*3OiIF!K-*=E-Ca@)&pl)UyWLdmBs601qQUK@C~H9}_zu#USpE05U& z)V}?IVO}mR{cisWglwZrWkIBNE&&3@SsCZ|qWg zN(h0b;g|JmunZ^|p?jbgZi{{-sc274+a5GwUEoPzB#tOZV<9$sg%)crDIF1h>mMw4 zye4uO2iHB}b+iIjTRrbad~jmB48^^;y=nDG zZAX+sVi!Z9)UZB-|0KgF%Y85FAzGW_{Tv!cF_xXuNEX`Q2Yew&+ehd%m9hR#GE!JS zWn7^%&b_+KKccyk)P{&^dW|KBXBxkf!M^sFTN=dFLI$Bo({^XAXHV#Zgvr1TQQ%so z*3x2_2#T4|V5=SCK-Qb%Y;7c~i}K^3Smno0hV;#=x?9$$-x2de{K-D0~9O7)H7UU-Md|=AA=YNULdvdIc?B+NvMmvCb`^ zS9;d6Wj%#$2IZl>>MpZTi)pE40^=-AG)Man^peMbZ-SUgn~Po0^dv+m{gck20t6A| zN>P)Pe_$Pkj!_-0h}lnu@Xb>Jypynqvs(yMI8zF@QhjemiQbSav|HEWQqjB?;viqO18xZ8m24Q%Qa8Oj-nu% zp!Pm-D{a5a<}6yh_};I&zL(M7VfnGCEveP9A-MTAYR0!Z%EQJoN;w*+5>~roW5y+k z6p-ZIevi+1QPSE~XPplL)N@F=1LUIMa{0TdJi(RqI4bVZq+-|ei|+581v-*^ z6?Z2rKFS2!AbL(10k#5o^>Jv#w&lWYOET-{v4~4L1J?DH+oRbA>NPH>fY3|4Kj{pi zbDedB7k%9wL~f7?qONXTC9>FKr)}TGo9+k9LLNNbcpKv!2DeOK`DXOM?(0hwF$5GX zt%b@u72H*hoxoACMRT~ z7A*AvI;RXsUba`0^*SeRyo>_?@DIsY6SL+?(Q34Yn#*vZtAzhdZ1scTZ*w8$n!g^DOa+(!M zEcc{Bp8^3;OH?%_ETHpL9w|o0t)K%AV1m+~rgND#B3#oiA+gO^xQtycfp_WMmMf?e zDJz>iws-papxnsn1H?uZ9OIBDPzQtUNI7V&vikysk6J_u-pXP|-n9b5PEls966_Ca zQZ5r%8;lzBYGK8c7`ZE?UKukvVCu)MsI_h2YC;9`hp`vzpRrS>3pLQGrY5YUSAoRI zNNu?Vyn{i@o~DdaR{-k*pgZ=7+bAFjh$f!D^{}-NS|&5)xnrM-NcQ%k-B{3Rfq^eX zyQM4QPOvQh)jWV>w4qP{6NlJ_I2S3`d~;x9J8erTk@%5G?gT0XNw`vCGmHlX{>vrH zx|Zuvb%@?G7p!vb9fmEt*5%6`Po`7l{~Ko``)8 z%%zp1%kHNtOAlDmg78T~hr_E1*s8>su%4Gx^0;$r;Ef?WaSd`s(N^y$h(Y&aEA=+G z(k?X;bC=u4csoFeXJ4ex_j6l=CK54_8%4F=XSKf~?I5`~@>)u}K9YE$ccz3UnMUlO zL(>9JhHDq5rKZJ&|AJ;mO1-%4@lnRo)~`{stb-xUm>?TfYgQAvz_*CRS@B;oB+re?h&j(G!{k9D7(*$5 ze9sI3!3NVBT=L9P{Lt(=S%Ee(3oUQF9IGo%kn-2MdB#}83>4dWoxl`=>rwsL#K(({ zmW&n%Vt{IcRp_zQzPi@$g>GV(J1q67`N2CC6|ndIW0Qs$it2IAso~)-`gZo!%rzg$ zxX?I~%;K5C`Wj*)9ey0;NvlIu=wOH(h_w~><9nSECZE{83PcPf-i%FzVCFu{M^Jbn z@e5Ukx`Q!xKoUp1qA-(^LZ*p=gh(Bp)RDLYHr>xGpTS5LH&iRjClTfS4_CIK!oae&sB?)~d# z8E_?tuHi@-{VG`pE!@iNqFGN3h(d^X?o5Z1Ip~5gPb`jVsZv-leG+hVA8!DJoJ>F{JhFm#9nCesB$o7aJy>USMExo||eEiw$Z>{5v*&xBMn z=ODOO9qlPaYVO#pB{SV4qvYHeRe{{9nj|0XRX?N$fJ7jfL0D1>_M~-$q zBpw4q@y89+@R)v$61S(HKoLQ!4s^~D_Kj3<4OIjL0Lx|YMI(|$N_@Sn?-@_yFad)j zB6BEec8<8iR*_=h3Nf9AtaT>xIc&=oTl61w7)|eXe1OU4XcHc58eths#^T)~5>^C_ zQ7O}sHH)}+#yeN;9h<$PfURQrSQ-h+JFEvr(-#if%?Oly80JI3%jlDFJW$-%`yPZy z=eXnNQa~>u&Z3>&E5F=}s@;~?y>}njyy!C4qND}NtpN3fk+&>CL&wKbZsbJ>0|Ihr ziz?u66X`&IQ!RqrpTDI>Y>S_powm6z^VXC=D*n~5&4O$T8a&ndpeU4wm7N<@} zmGkW^P5UofEyYj!H_CcNT1b+LrTScquu6i}l`3U}FYC&kWj%#{-wg^3B39Q~6AVvc z1rrpRm%Dwei-ijh^Dsz%Y{kPa`~MDtNb)XS~1YHC}Sd(Ztr%OoW19dc54zOk?Z}g}e2*@BKX_ zD-CKRG(Oe%c1a5j`&P(ClbzqXDnXx7`wr(IEhBMtG}dFkknFPBk~D&;loM|%d~(~T zWP*>|08Jw)nS`wa8mA2%$>o$1{VdJ=RFm4jLON(T(T8nF+S)#&6-?T*#`u+^jAYp{ z0nb={7YGfl%D|&S#+Yt5Uacd+g|q5ES4lnca~-|2UzJ>%*bNXmh-qGdKv;`gM0|riN-3x!wnbPqQSLF*6VH#!Rv(0ogLiZsTh zSs*bD^OBN^H%uIVwkc2eM~shpAKF6#!7$1{Kh>T$lgadYPGiG^G2YnqmD54pn1KF+U!$15^bm4VClK0}TU=a3{I3yGyp(WyG=Y{;_?DG;A40- zj&@HY)u7+qZF{v$=IU{n_suJX1qqa{vC}SSRqq6l_NG|kFbmc49B;K9<{+_>fbCLf z#ZaaY8uZkTYtH4=p&0_xcM6^l`y^0CXA#(BZYmihT2&nKIZ(M!vTZ_6OFB7rNd#~S zB4|&(l??_5`1osYTYdwZ! zK{y7vs6+xm1ug5jH3Ge#XHbpyPlj))xnao$2Gr}KSAyIXC6ysaJHV-Fw{@Q^RH9~~ zrt<+F`j3?(b+_G$X6LL|#WcqkWMpUm2b(_;|aSk6T!El|wZgZBDjRerImxH;9@VKI&J?X|~ z-B!_54KQwb;AAqAT_ISEdX%<=1#sU)hlv)kDV=0Y@XDQA4DKjhZCxKHpkkS1b50x8 z49BZA*pf&`ujd-Gm(n#2%zp2Ns&%g*ok3B>JQxO&k zP|Q+)Z~)JSIGS!^z3Gciy2c3hmcWNy6JU-yI(Nvi>02mUdd}g1%d$P=qG?CtXBn(K zMiS;LQjCJDiI$pQv-&|3E*ub;-APjfqr2ON-)}(T;SHXn#j~vDuDcQ9vOPx{BzU#w z1P|C0$F4h1M4bgNc}{E2xF{3AHzBK;!DK}g!Qq=!|1KoS723O8?V&22qM>7P+bAMo z!*_M5&4e8=6gFH&Lr6<&y_W4Sqo9DkB|UXnFFV>l6+YEpCW)-TIv`&J7s_@*Zvb~K zVRNd7t$NB9GERZ_lP_r zu;tFkE}lbQp#ELT`b}Sfwin25C|&y3&{+LBWwny|e*&%r{+rH3{TW(gpFeUy_Cg)R z)yk^?;kp0kEBLNW^)vzzWue~Ggc)QSum8Jyct)L`uOT#5D)pUijyCIm-Ce0a=T$F1 zKLr^7kKLL2cj03KP)^h{{}tBxW-@V0#{Tamj zP<_MvY%uw_;^@t zd4UV4J0N&1L232;n=&vWTOxbeWwtBUUsF-R5_M*%^4-sVpMDmX!&hiMXh_G&`IaPgP?&s#p#J&eCEYon5vk?5Bwtf1gsAnO zmYjZa(NA9xxd|edg>3ri!XZ>;9R7*v!^sv*HckQ7fMfQ9B`cqd!7c<68>rx4Ub`g# zpdVX8-^m@%1TKI2=@Bx`$z{^lSj`R?XP~q6w{=TDIT^ggYuni=TOYq;tdHsMbREA- z_d!KtB(py)`P}4-US2#A4hS}-J`$9LmT+kDcZMRZ%#+6oWVetuJiTpP7`wB{{a>#D zupkBARGacozUJlMynM@5$-cKN&nxxlhI+DLU{zT9g~@%K#U-S6Z@VQYGBw6S&VnHS z{Cr+s#y774Z13lneJ1!8EeipnO+SA+uX9$5nRzeu13+E9vod^yyg+34OmH172J`e{ zyk0nZJYK(2r+~_tD~6u8MG&4EtAIB7{LLk&mP51ZtQFf13|IP7{^H~TooVjGTOdS5 z(CR_UVC`33;F{hRi8kg|LDPF4stLl&k+rWqSX{WtWmTQfjc68qzO)Q2c9Fdbi&!?j zbZKT{qEH8~>Uq$zB7ydBFksqpMs|As9kH6SfI3hWhV_O;Dw+&e7pUV%-SDU8DB9H# z8*4-M?3oZTTwYRTJigrgHQSTXB4%6Vl+2@{PJO3TvB>E&FL4=Fq;B>kXjpuR>4&)O z40D92PdfVabClaaN{{+bm)j6Rse}B?8JcviQ5*7PhxBbzH!iJg=o`T0Z-5ZfFQ2X) zV`}^!A=}-^{9Jdj2TeHjYMw3=e}H(K;WB`j2(Dy1=;UfZz6U@%2at~Ki<6(K(dkdw zZbv_bV+npbH35VFjudreC-5Ns9*>sn!-$SJJu2Mm9n(uipl%4si>ihp~3xU(>hDfAUSL6(-+}2jGIembfYR zy{sQ=(+h1xQmYi0T)kUdTJl51f@Suk@Ax>$ohN@HNN`eG>$ja#0|-23E7zU;0k{yL zk&<;mw6Mdh3nUE&C{`vq`5TuncYxNjH32_VVc_-`NCaT*W}nme`OlcFfaJ(%0IgpY z)=k~*>rwnhwupAu3M?I3jKuo;=C7YW?+|0&bjAbnNc{2nvk`!dhK_dMYvnjL@6O-W zLs4_me!-J@`VRJYwxuQ8W3}qopiZ?CDA!yw^~Z&=a4i&skss(m!oZ&EPcRPb9Q9u4E|61B7q?r=yH)% z02CVt)kOEwf&cZ~>L34u@s@~M_b)}B zJJ_s;rX*x$KhF=F#{(p zX$vr&Va9WO{I(^kHTJ#24@lAc#fS}}7v2*?U};+SZ221qZ6N|{m=sK*Ko?B6K!&q= zO9mq!Q0RK|;foS#kAJW}rgdO6W8;WAw5}c+Meu0Iu*9sKDHg?XGwuG$c7^DvAw=?7 zI98yRO*;;bXKrCq_TfgChD~LT%|84|hVJbamPly93Nb{I%m$RlAoPs#yA>cpME{xC z$Y4!QR>g%f6Bg?Np@#23xmk(kVY;O>>)agQn@4u};R~nM#)gA95z6F#r`l#!AzEOI z^gt)KE%=;WdI0*tB8e=Zny`Qx705&{#%7>nPp#3~lqyaolhlBw+HRBrx-*20>P&5s zSwusZ0bA(Iol%KfI-N%v%eO)bXly#vG{))tfrR|^v`){^3P3bmR^+fFp{m)9rHGQu{J(RJgwXMcry3$WN4GFpP+crc-tpupxW`wrIWi@rw{JnxaKOT1dP9WApivDISCP zoN+uFB_FtkSbb6lq9=g5wZpwkY~8GZ(sr_P9P)}0*xvWWL43kQ|0B!RP5?C>gK@Cf#LAFEjB6g<(~g=XYFJ+kK+w)kFbPrFi!) z2rwppGtmF$m))8^Wq~OS!-4XER&wE`JPGV}h~Efcr4~J1-71ao6QhF=+n^R*0_>`CmThOh zFJ>RCl`^?LpGJDL>oaX#&Tn)Akuj(U&Uje`UZm~}$X}0)Q^WO!24)rz3R=rG1MTDA ztYM~a$C+6}A!+z-l)*AQn#!iV6Bb8aCAq*HUr}Zfb%nT#e%q8KN2DRW@dX1>!h>dy z3pn@jW*Sss0R9BKf$cxgPRrfDYE^WfHVs2b&Jo>?H={;p4e)yLE&-aUulVr+Mc{`& zG!;HByfX+X#m9a55T+n-Tz#$}A&FVdcA)|XfrtD-0>FpE-U~LfrxBAHiP$5?tJL41_9fWn&EEgZNm!^b3<^aha&3A86%);quRPt`PF-+V%u1Tco zFo?&B@{d?OPwHdooE%$7KrLjLhg*vxZpb)uJJ9uDvy{!-Hh%mK|L$?J;DtKp=k;*_ zN{7%o*nLDQBo{sE5{jb$!ME^5_2xW<_a5j$vWi2R{OuHY@%!`@tq#{516XLv;P$uS%~p8x;YVtKcIQ1%@yex-1WXZG!>gTY&!eqF1JhT?$iyKL>&~ zWRmp4Talc6g{sru{+s3FBZ9tahe;d4@UNn3n3LNLcWT&##gT+oBEJUZMRwFVVnn&g zRgwgu*N&&$Cpm^JYf+*LiJ2wHDA}wR1Le97S1iLjlY%84@m)hep)G3o$LXy!lo<03 zO}w?_x3R)X?a7^&+M95wDo@Nc!UnwC!rh*v=Fm7f#=^jDVBvkAb-|Wx5_23flu*;1 zPq4lVMaQDfEGI|>GvD|ce5_86*Ns1YGfb1wE_)E1{SEyx8yi^uypG-#vf zqU8kl46k4I!_b?y8S9bdxL~XBBjB|UzXX^;CaH4t1YD!8cz)hCVAJ(QoUtdEhf^cV zY(@h4>E_P--QX4(C1VA90Zg}WV8q9u4g)iH25akouhY|W%xf@vMv6ifIjkM*eTxvw ztoN+iM#Gj!@|8WXkVuqA%545xfo+aLvcbQS@7RaWY6QLjkSmrv1(@9(p_)y)SSm;n z7-nK0KBHzM+F88rhE7-Re)sC^u%g;(l%UcYGjH3za~3A7Ugm^55eu~x>9nTL2Gp_$ zMZWfkF6%aQ<2suKj!m&{;AN<#iF+=z=B~kFQAhlI1)q_k;aNJuR%tl1gFpiarBET$ z4t_2?-3;*NDf@e+CHB!7WsJ}b&`K#8Ms<%z^@Y4)<1tx-gq}d%78>e-K~B;j`NZ3m zOC-q*92jMU4l)Z5kHbH}L<})pG|A~sYn?!k72m6NZ|Uag!N6O}#Z!ZPaAGLHCKi)H|3b8AK@$&?g!*1 z`o!f3QI>K_SYTfYMr@Pc{XF1E?(1EMyvw7f0AcZxS) z+A%QZY@xI7(^MOKkZrV9*^WFDc?C0lazkCycdn4+=;mv)KaB%enb`TTN6jZ=?;r(C z#!Y(D!${2UR-qSL_~nsS{9je25d8sAwWnwg80caKpt?hX@M2Q2mnbCO$vbk%mT*;a zJ+QD9L2n*9AIUD!(BUi6)RAHm99ri^$D<5C2o!{90spQLMW z_f+K2=g9?V1wbzyGXR*tZTbr)54s1$DEH*-LPE&v%_2vfX7Gr}WY^l1uTb`K4EsUD zkWn+4ReqcNeJWm^GD_HmGY@M)J%!_fhUh%`Y@b*_mrflj#B{$Czww9Ozov)>C}xMEKj;2-eMNTHG>C{${4OQ;F*Ni8673eiM*<2Dnw2 z@BisXxKQzR(B;P>6#^09N-;Lt-z*ZxGy_4M1B1TqZ9W3_jW?~_UR~E=LQJVM zbg^)=)OHe34)vl-XR{4BS+SK>k3>ZI<&3ALr4VmvwPuh~hjLIy7Uoiu1p*Gv@jrlx z&J>(zAah%ZfrT$CSEnHnLm9#*(rvo1xLZypu7D7$b@-X zLhS-;W?4F6ha^C?5V>(*t`<#uV`x}B8Zw$U$u1UPE^`+xUppgiXvh|p*3`EoMRRvI zpj4{U9uXyEkG9hy_DyK|4$U4N$^k19mNQ?EU>N-AGg*^?=s2V=Qr()3F*7hF}jj*-2C+UE&~wN ztVv*ipCARp#s*W|R2W6A*UXP&XeJZS1;)pJH@Nk{;PyvR?U5{tUTzB7cwqgE#QV9w zP~rH2g$Gd<99TDc&J9lx?j*s%nWHl+gWJBu$b2BG{jpLt7jV9St$Yqq=$*T}+V*%; z9dwsIe_E+>p_7J@L&t=-41=neDM6@9&3=Ie!gPyXKYGvPIjWbh!r%1VH`6_aAvpsyq+?MeN&Vq-_dU$+PT4s)V@^sgK(`%~!nHZV13UJI$Z~n{Y|4pa4G|m*htideq z{e2Yn9I!EffE0|XHlnCV^x0n?|M>j>kT1IBqI`lX>4?;9&HC?b1nVH4I8Eby>*rtb zFxo294h8jNH#%ML$LCvHbCuWa!FlHK`J&yri}>GwWZ?tlxq$01PFwM^+?850Z+ucH zDl|nKW-%{l}0u!ix%IEDEic20{v+jn$;vc4RN5!&CKOSl|#;_blkxc67R(i;mffRhlb(J zM2;5bw6@|~y$^2z0L|gV7FI>Z37lg#QpBzM_B%I_Y@m{!pE*unS#gLWiTC4F?_N5Hds& zfLjnu+Se@{nY0T=E{Lcrr<6}g9h(Z4b~*`jlCm=wJx_z5`gd4;BgIqPdl>{p>^V^x8!3I6`1Lt!@@qBI*gF(V|t+BKIhWZO9W2-5pHVcNaYph5HK3(2JM#su#po zDl63#;PJX1M_BFHAwkAVAPKTXlK>gy=_7K(tKEb5KkRTIu~IF5$NB15M+d`ZSMrwICR;ud*`)hWXxz?%6K6eNM*F7T)mhep-A$kFu@2<=AFqr!au;xe0(v8KX4NZ>;ThGoH?4ablXDm>Z}|ee_1JQaZ$w86ZWG6v zc!;ZO;82C&#>FUq0}Xb?rZ%BrfEZPR{fGA2nw}UZ-HHQgbPKYSNc@8BxV>S}ecOHI&Wl?S8D4?K>vkDfI z+993N0Q)AKXH>rooPK*I7X3fBR2 zo{9dga!d0Q(;cLyAsptTI-ss(HdpTlW^9{3z&MFM%6+I)AQE98m~1A%M!_WkF9@FC zTG?mM{8uKR#!*!F+ zv4Io$jDaHwKwSl$7$>pqUv^kpEaG*(0v#deB4~6qTf3sdgxuN;R=y$&znH8LN zf;s5n7uHDm!p?-S4q5P{X#TD6CP0VKwGqvlE@N*BqQh|qs(v*KP>45F!U$%nI0lel zIh;L6rz4~!HIjdZpyCHev2J{qJD4*7fPBc|zzIip3#nl;!^0?_?cnCfBn&#BP!9o0 zwLe;MI;291dWDuWEBLQ*x<>X910;%)JV2`xI1U?tIr|`M>PmnW;Y9{fx0`J#RAsTV z(drQgXlJ6KxRCxs@Hm41lZQ^WAPFL|k+~ zPYBDt4!MJUnJy-am0V`pMsyl-8`M(p=0^W<+fdXVl)9VzHAtXY%L@UAFoI!IfV-=U z^i1qXohmCJFwjalhU1Nx%+YBXs}AhjTK?9jE5evZ54E^h%x3Pe<-UQ~@;59H^ zUemc{R34!Kom`N01JB+pz($gAO2GLXNFcwWJr4QkDY7_tR@5a}WjJ`W*a7ve@PEY) zMNbC?;#~7W2h&e98kt1_h_!v24}gy#7#%2PPN6;{Gr0yR`H(U@M&y$KtJJC!M>+D3 zsNo=q!Z@#S>>Ar1;8_Oc3IT^Iay;6Oh!7=0o+3kf0HMx48hF+-P!SJESCtQYdO}_>$&C!tViiT?f65X+rnb9u^`j4!`6?g+qO=L5GHH8`S%Do9377f2$xsWg+q5Zomz=i>Q>WmKa?^`yA zmq2^L&0o8{fY{%+o0PS!NYPNO6A_$rC<^9{m5DRY7sP_O85{Ghpz4DCKX?JKL=YDTI6QyU}rurTcMQim;V^gn&2^+PKura+tPo z=Hvr+VoPT4^niHzIPTeZkQNm^a>3A`b8d^khhX+(9bQEbW!^v;%QU7Hm4}=69&Al= z{;uVpXz)|J!nJmfIv8n#8wqquhFFCEI6NgAtb@|PK*YqQ?4PuWmK$@~&WtiR^SDX+ zz$-72ACbV4gn^cEZS05QbtKtYcGHC;4)}%`iN#z~pM8Z2lH~@`W?h{Nve>bv!1|od z4WrNwFU5Kjw}_^;hvJuYR#gK7tyT~lCN|%U7Co(~Sdy~I{NbrDzDNz*4&Y%wbZ(R) z!ykSJ?*3KPoY?6?8+s3eW02k+09n(+0Lm^4fwlpd3}@}&$Xb**6W38xABmXs?fHZlySusRoNRD?ZX| zCee#J$4#A+hIAsB)e)oD9IuPg-uoCh|F;+<+eUl5j#Bn5SuQW?sN|erNYG@oOixB$ zdkQ@&Rx3a$PtA5J%fch#90@11mRyLm295OR-}$m;AaN% z4V^w!#;%?w&L`~n$L#zi!X)ujxzv61@VJY3)!iw3VZZkpI30YF;V1F7-+5r-R(kZj;#+JNEkJ zMkWf!A>2sc$vd%^GgaJ0`xb+&l;qG5(ob{-z@%hTv5SHgf&k@1_Q3 z{3d(}9j$ay<9QtUtLq!sW%?&{Et?gK4irY7ppyet7l^Cp91tyVngBJ2W71B-zlFVi zpCok-p3d2nWmxfKQkHU*u7#*6^lF&{@YDj{)!i(D097|Qzlyky6B=GChKo7y`U9s! z9kh>;1X>wMed$_qLri$I3*lAZa-)=ikTSlalZ8J{>ncWo-Qu`F99rqxLgayi=3mZ& zx1XM1Q9+{f2+eL}+k2XAsmf6L0ZIc~D;T7AN;Nc*U7*<%V2zrlW2dTmglM_;y@TLe zu!iR6fGBU-kk&93hVO1)*@MSM9iuQHa;(}26;M}})$QwM=;H%~3PK&Hfl~jKYr}iy z0BLDCv=P19=;4evC=>{YK@BtO(i-ToqXMh4IvQSP_;mr@sp%P40PnUl-ONSD4l(hz z$-~bKP8Qe=3ECjfOv|)ThqD_U{>vi?QFk{n1VyL8fb`CP)mSP6cb#SC?G>sO;>@dm zVi@V#){EPa-a~vWjZmHuo{L?-2n@E0G!d(3m$z(AQ|L|}O=q~g~37)Bka ze2QA@5%3-;M_eF)2M4jbgUKSvk+CuDmZ`0Sehi$nLjxL!jD!aTS^^_44)+eGO~};f z%**$y<}+*=&64VA?l(*%f{r2mdz;-GN*AY8ewUkX3q z!?$Q7-b!nlUPaUnO{eMNAB*C-8iVQZ~~n~6yT8uGK5Or?Ql0sO>;t}f=wKN`Q;Jr z`OZejJHv3>F*^<6U9a4j869u;%;*>hx}br{wX>veU&o3c2MD7zp+0E-;4?uFcXXI@Vo9Ak3yZ}n(JDeQsN-g%+V8y$I5_TOUVLt=(?IGiD zkDFx6O3#@JpDy>65ScKrrYfEEbkRmADJ)mvwOV(?USZ#Mr3j9W-F|IN9s*8C#@T~a z>H(uazZNZIK?bN}1<{YSolNY#$~R`NnU8B1FaQ5-?@i$As>=1@_arChWNc5GW}Z%y zwn@__Jsr|E9Z%BC<7t}CZFjyO@p2u4BaQ@d07M7{L75CH4hR~QNkNIC zfT9>c6cum(&-1SLkWdBnet!S&e)s3jZ)ZPyowe6~*V=1**E=*GgdO~Y`R#otVE};@ z^}_DM=V8QKpTDararVJpEafv>;04I9pD(+~O<3c4X4d|pGXlOsUEgM1OZoF%V}tp^ zHcTZ$&<3Nmb!%fAq#94KtIjdfDdmXAE^_A#hQYu4Si{t z)~J=zbv~?;x4_!)$p@kRHr0>SPAj&5rtkE^sFC~R*tphiY7O|LsSrXfaSvFsF2o5iK6}!O*81ACK7c2*dBeO`Utm)vdc;rNA)@6eaWu)u1dhWM5m3HXyru3(#=g+S5u7a^$SofaOmX`skq(I90 z)YhQehGVBSw>glBUFo8x&EVE!0epHvXT~f@Tf_}8M<8-QfjQ`2t>L29`K-Xoc$$~) zis1~Q*K93s%u7`l2C}f6qF}j-JxKjs68Xuf4n*#9*&<)n&Q2Im$Xcu#Ms)4FIU{)?ZOvl{rt^4M zkcPQWKIBCFp+;Pmy#ymA9;)rhE;W9=-w)e3tGB~L77P_OKz_qn)lVs&x2*qQ-o^}= zfI1i20?>D4Qji!(Am0Ri+nkKfSk2QQ4QYwA*{ZmSEeJFn@U`}M3l{+`MrLl-RsxajST`bsCglmUN7-gdU zbjSqLLL#hSX8YA-&h)CCR4IYNCR5oC>m%Nt!nQrZA_z&A?wZnD39De(1mOfPlg9BD zfVT}91#_%s8V<_tgvCp*$}YO04IAI5(18PNWVF+~+xoxi!MKi;bsK%tQyjMlqY7=d zIwjHVs1h*qTY&8tOeqSWA~S~^EAW>+(v&x`rHqYCvnm&_U5hZ4gN@;e%%<|xX@wn~ ztA5Qsi-Fj9lN_QUlAmwohQ*bp^^^&?V~2 z4tIMnghNP~I~ncpucCIX*x@N1>17zy!0pBSmZj1~-V|hNieP>6T;JSSd&1kNVT8=d zUA+NnO04%3>4%U-Z|cVU+8RikLF>vCWzl-r-el?m%su0Sn_o6=!u%_@(O(!W=MD@h zaa%3kKr%FdoD%In`Rp57Pf)ep4I5kQU|$qHHl&zy>sq^DZhL1{-(;1T%96TGYDjo- zE8J$}rTDxw2P89#S3-npVIQnt`Du`AQ(lr6-l%P=0~^-)J9f8bKz5D>b`xfF rO zxWZssmb%N@=`X>iV^KE*_@VTY%6(5L`1*UAAV%6(GCgN|VrzE*O^#N-Xfe1LX0uBFe-U(dpmMd=N4;Oyyj%ubp$(t42*y28W+!8;?cI@5%;h0=Dpf&@ zoODMYG?=$|QfX1>j18z6YEQPUmFBLu_@*vh1}-dWh8e{$-C{6!(A%q{WvGXn$82!q zI{Zb_3)>ZoU}~ZlWdtreobENKL`+;39u+64rwM`ulxu@=^{M3J?8GXe5Q~#7#q_ep zNg(?%_TlCE*l9%4TuQ2uN%LU|9dc+fqa%pRC{yxBRV-D%r=VjU7?r)9acg%pl~hSj zn_DyTF+=Ct#2ES?(!f~1Vcu>i`QZhb|SZJ z-Fr@2UI+P}Ir;S`qZfvSAj~;hBG|eq>48?!Nh=O-?CP9Lt2hD`O>BjhVBZ~Uy5$?X z!HrQdH#$Iu^g#+IE|?d4xlm$4jYVJt!y97m*0?wirQG)<_4SClMuL;Ok^FC|mwlzBohr3a&kb5NbqP%*Jv3|19PUr=FtH+;f@gXAlq_li};3${Sg zzZkoGIaqiXagrbRpc3buCg&9fiagi|@m6`!K}wCY$%&-;3Y|kVT52v|g-YC4LNUXJ zblBSP6eZ_&d!{a`!8B@v7uL#W^z`L7!9r2$^iDWIKQYov&G6k=e!v|>ZXxy-m6x|3 zw&k-zt;MVy1ZTSoDPunCmdgEgP;6fTSCw2bO8ByVFG zWL(bd%LwGau|?W!@aH;PGoZ~u&4h-2&otSdd>jo59YCiD=k-vBDa6pG-7V&@yC7u} zhJhu@-hemTf3U3)D~-P0&5(JAapZL9i_yIIijCc+7++DuNU1Tea1)n_zO^tM2=R=r zaQ1%eg3(6bdiZMH0O^-%`ju~>rIh*WDFU1VJ@XiB5^)&o$nXS8+N5Z9MK8=0Oq~fA zVCx}34Ih~;YNd(g4z6C#_62a?)d4HK9T6}j+^$bbSpX~HLrkhZI{f|=y85P2yxt;!ug_wR&M`rr=Ih}9FyFs$1x^PK973pFymxPKJmuF3=T%8lw z4{R-Pn-*EAMfuPsnUSmh>S`d}LJJM!J!fqYL9g6i8 zrIx_;0R)(8w!z^?Mm-GFfh6p}L?W=Uklmmg9NdA~4|{-c($!JVVu17K+J%n$0@J45 zkeH+GRImhPW`%zxnKBUWfwXpqjzMpiJ1n%jDL35KmprR@2jt_>j!{Eldv2<_E#|}? zrR2<7t1B9{9bLS16J}g6V#P*-Rd=97w-u#&OFMM5p~%*ky?#sL^faVH8%Qg=!X?no z!JcSPg`{af{4^PyvHiPW-XDga(p0=#6F`k-x81CAy-D9mM{xel=+W4^01Tnc3; zI*sQTY-Hidj*UG@P5F&}0?gnj{CFb#9(N~pR+hLOBXCzKVV+Wh z?y_ecrr5BQbqG>ZZjK3APqrk?;Z)}_3H+Cg1fmnVMcWa$r?y0r& zAfdD&12*Gk!blwyK07@<2d1f*)->wa{!JNXxX7t1nE{6%K~L5R@D&>&*|TAQbKx>r z+Hexjkd*ZFGzY-&FY-dHzpxPUh$^9uYN#7*H1Z8T2xPpmWmd9(bGV`(cJI3iJyO)& zu6xdT>oOLnZ9G9!+Ux7{bzn{tN#yQLG5dY2U?HMf)X`1ybvgNU1pw?A|=M1n-AGk}40@o3J@Tk;(jZ5XkH*gy!^|h1*QV9Nw*< zx_}Lc4HRarDyrK--ENrBM?wwh-quY8)B9;8VriAkTi=jhjrkY_i@@krtL@HH?v$FG z=330TF|Pt&h4RZV8Vcc(`I`$DwrUxzg`x|_@c=ZLbaQZXBgEk$j1MmgaX00)^v+~P zd%X~&s&^vV=nb$;%2LC~A3tMlOMuE7TeU7>UKfQp?7Ue&VA+h;Xq`@1&zFcV*o z!mfr-9te7;haF9>Q_9KhNn)o2*(Yysin9M8&!3f&izVNbYUR{pa<>b66>xV_s(UMV zZC(GSjQMcosijny=-p5ZPAAwPp)&Xn4yRUtkIk>v-kJad^XdtvZj18d$fm>|LlWIC zRo1`&>_+T|rE{Md=ud~e5I;8q zN`-cQ)zi#6@ba`iVifZB7sHfucSiBdy28rtRM92utKn@0*85$k9VXrxU}iKAn_W zoH}J{?LL2{_QR@0)WJ=z%m$cA>2&rd*E>tOaYc?@MU533ra>%WB^qC=AJVSgy1rKK zeLFAJP4%Ud!`G&WswVu-2)a~Ft zb4v+JoV7_%mh(~qn*4pJ>B9dBY$kRk^u&s?Be1qWS)WAJ=FRAYKd)Wu_v`~@(WpXua1qVv(9Fyv6?USKyE za+BFT*k^=w%vhJ>K0@k?d!gwyb#NEBArBs(-~tE6#^Hm7O2oBQ+4ObGwF_N;Z)^?Z z_}C4R+1w(FQz6FAl){@CfPGDU7~aSPZaD|_MHE(uy-yITvCIZ0h{x*UeeWkwk`vfBEl zt?Tn@$tTy;VPx2lG!H`n(xJrpHnKvX8>U`>&q~}?x)FIthIFh?Pg`6m3)(j%)#Q}! z?#s^b7GRB@pUeUUPlL7%Fq?$vO9n*5R$;fRI==;`Rs7x_NJE-;s}<|u;TXlCn+Syk z)JepCi7sS=@Vta{)}v-PpQ#0qKrddg6FVa?m(TgLGcPbD4Jy$XWL2sIg8Ax+B)1c~ zXs~wE)+^9Cigl&wgxfuko;HI!BdU3U9au671I5^8qnz9VRVZwsE6RFyH)%BE4e5{# zP-#lTy7v&1YJ%I8>0oSRHm4L}H|5NN#IzckG%JL=0SpLW584hh_fxRd-iQ4nuX@jd zH72k`p;;g6N}WVe+SEl|3T-~0Y{T?(i$UkwN0~XwhUfrpfgKn4x6Fig*#skY+Ta#&HyEnJA6-x(y zZX@<;IE8K8%|s%Z>Uh=c=F>(-*mhLbgTbBSqdnT{;>8=g;gO`zX*j5XJj`CF6<3Ft zL|?A2X)8QFvfp1?Lu0WJ*4!{>L!WyMa4=v4e!?by z>$;iT#D{qA>5#qJ2gYHu4@woVv(l9fl_|Gcjq3x?oLRKGr#EHRT4)}_PKF8zH5Ree zVm9dXt)}_9V59}yp>A)_E=ZKYnp)h_4|bc9p)`s|u{}@f$!&m?%(gDr2;Q{DAAs%c zw)11%uEFX%d*I(1D=91ht4qSpHXo+Z0&UYusK;z;fmdyFen2^$o{U7Wm8e)%osF8D zhCv_BNa*Yn>ie}-fyHZ;4PK5{gNq7nOZ29-uq}xeQ2}4UZGk)(cZhYn<{8iP;x*i> zQ|;-7KwMC^6dQ=>`g>d}RJ{p~d&_+AGKUpNq?!hgV?AzP?Tw!)xYU<0@v|Ga-t==< zA`C2+VI9_^^)cRX-KL~|WeA}p!qZ~DdN`O_4o{S@XOe@}sfs5~_h46{=dGqPcs8@C z6T6K)zW9X5En;D zY_PTy>928B!8*7l>zx7i7TJ?cU?s!3cnNp1%02X(;q6miBdzs7X(ZN@*0USZiRG^XAXe=36E5E5}y;ZaqY($u8I zAfu8~(BOor(zJsrMT^|R4Jei!q-a9>3yYLV8ly` z#H4+toK!UgjlJ@)rze`{iFEo)i<|-w^p|1G)bVKCXb8^kg0jq2>anY-Vgs1a(_8aX zlgRhl1KoN|gTuOGzA+DbPYJB9uuIZSnd?pS+aWx)%kOQV=p(vO3=%MF(hxhpWAh_#ODR6xQH+T%Idv?2ldcXZ?l>HwVcJ=hm%ax;yB zv?%(qf=%#>iz;=9NwsI^VhN#+syVRKZreubC9FX(nogGof4hg%Wlt} z0$cedaPyK5KWQ-N-Ug|eX<%X@B^{`WFi`nm6?O6|1kzLF40L%tm9x=lgtgoG2P*QK z4IcHq3Lh63?Mtwwk~)>X!q+#Jg3BLPgZ^)o3`M*k5vum$uqv<4Tvxt9xS+ru0#&Iv zb64$SB+~@7wjBkqUCVZ^i>$wys?*uRN9uuRt753N!jdB_k)r?Gnvw)dmYy`KavcwT z8(b74ok@$G{94GakxQMv4UQB&eHf_fu?4<9-@9c>qPNiTjBB?wXRIKr2I9p%1+Z-e z9SyARm6Z(B4*2Z#3I7V?P_cSX&#C$OZQQScOtM=wbtP3{mkWD5>);~@Zt$RKIy<+n z4|{p((_v^Zx1*zo^|N*7Ir|cpuJ6Gliu+GU33h>C;EKEIE5P_GSy`|bM)R{O;8rE9 z(;_O@?gL{noUm+a@0vVhLb%%9v?UXgw#nF<00#y#2&yHcex(vJogie^@(tMd)dKUv zejq$iZ7I&+rV2cP!ShKc6Ee$e)NU`{Q$}V~Mm65j*H;St;8JLomUhpF+9O-W%;TjE- zTsX8&Ta?kiq&p8XpGA-&gSiyAUtGMQ8x!mn5R=N~DLk5ab3NRr=A6E{Bv=rpCmRS6 zVQZlmObJ>*IzT_r3}{PBTe>D|`NqceP}MS01&=oml{_9U=|f_1r`*3yNT6>X>8Au?%TgDM5ul5qG8`y=oR3_nGiLJ*gS zSsM;!&J4K|TA-;lh+@#-0(=%UlhxU~t|hlOFRivLcgYsobA02`7H3bDTOk|NG;}G< zMikMLA1&=&9-)EDZmA(H)nf>ELtrno2k|L;aY$0 z)|%5@&fXjbJ#6N>IIA za8Dr@G7r+530Sc~8UqX**c@t^W0EZp4KBi>0u$D48C1>3raUxSUoSrn;M9ZC<@9!()08I)DEQ4rMhm}efnwV?P~9Xfj@jHaKMWz>jax@ z@L--bs}(W~9o!%4fHpJe+tQV|5IXt(z7=3v=coFyEssJuE_Bvu7gVBiiocLDI+Z)u zdn(ggpm>?sMbfl)qL7`Zq_T9|LO+#(k2~|U6Uw1s?uE<&+%!@t$+xt%mn`JD@aqec zv*1U-^Xbxx;;LX!Oy`>f{WNntV(@-xb&{^xC;Wbfj*Q1AU27>zi#qgWM4a@=<_$fXA z^s`Spk!tVjVbcO~>@LGi&`>MooUsbKeOpi`Gj}YaxPM+sb{0(5(S7|q>RzR7p9A5} zgQuMbkHT4NcND5vIk-TcYD@#MeLKleQ!7Ms;eQw^5UE)UyYtl;Zrt7mTp?i_zLLsA z+D+B8!XS_z@{`9#fN!22SR5r&KsPGE#)N5shQz+MEmQM+)a5VVw{;2BbXf?{qk&OI zZyI{b2A8?guYHt&aiZ6O>V zQ2&O@*rtqSSPplo*gdv~Dq;GHnwFkA*t67z1?`az54-_klNvIpFic8m1JeoK1TR z8oa?&idZbbCWWfq$wK&qfz5Ah$-ux%Dipe)hg{NB(&S6ow-3&$Hy6!psDo)2Sik72 z-{|)y6j0uGw%d@z?f?v6c;U!bFb$YHXFfM*JyHz`sl2-zD(hE`i{io;-@EBx}gKgIQ_`)+>u8C<`A{fi|f_&u%n)GMFEy}$X|yMK-AGdqVj@cQHj zkAC|%xF(KF`{l3FM1K9#7YBKLY|SnEdHr3*t^K_I_AAw&c^%hBuUxdSBVFVNhli#i z+5Zs->8tqe;D7w9i3uRVg@G^5=l59j`j6iIR_Xr|zb`#->&`EO4qlIq$KO{RICAQp z_?_2de}4htYl5#GZAQ7S*_?6%fiP}QEcUZfTqA+u zO=Ea&UF+xP^ZCeuo36eG&+{5je>UQ6yzYki@%v-1e?j_NLx+AJ4}S#dY;XMhXIXD| zeCzu8zryeRS7gs$ga|tWKfdi@gztQ$^IP%wMM(d+ynFr_zh^x@Vc?acb8$T}`pQvQ z?vxX~qX*-^=K}1#^P9^_*WO>hCt8X7lYjK5uf=~q_F9dA1L2pC&P4nJ-fzFkb{6|x z(y44m2d;W_SrEUUK3aEW4X$Sly>yiE&rJAFnDG)hEBew=AFgNLFzsSwL(U1^x&@EP zIVT4mn8$1IrK4e7&kP)SH}iGw*{x5Z_~e4oB@g`s_ZL3<$W?5or!D+b?F+b`Iq%(j z@$=t2p1|*yY===*{CepH_fBK^UGiUD%l~HN|BHdE@vaZOw(RwP^(%jk0=?$sBNrtj z;ZM!GcFVEp{{s2{Ov2bp$A-VvJys#|`SxorivPY8;0w_wpZO8exv6USgDn4>ANXj( zT7(bZaML~Uc(VbHjQk}7hTP=Vz4zWf4!VxCe&SX3t4G35HFYBV_S-woRK`Q zeGt#xIpx-EWw_qEu=Pb=zxwq@&#Oheua!M}HtXltn?G~Ni}3pghjkqI#>GGXB=d3q zH++9#Kk%(XcU;5!J1f7mknQ<_EB0N>`tsF=XU}H6zIVx-+xeb{dN=+GyHWDp)b;Nv z;#D5`R0Xcz>z%%^0oTzJE}8L5(DmJ`X5UHrN3s3GdVAlCN7k~zKRWXG9jxb%js5hi ztk;h}zv<7fA>I?$opeVQ?teJ;__ZNie>CvecV^&yk6!$V_po1i%KORQS-3vF_=AI_ z>xu9aA7lG_`W>EnPPNC5JNf$@=bnx}b{Btt+V}CZ)A9Q=AHC+cg6q#e>zPxJc)!^G zm)Cj!?0KtO*&d%8dgKQSc^!E44v)nn9lyHZr3C)|s~>%{Os@?OoWSdEO76NE$;*ou zJm^KYD=$7)J7WQ^zYah0oj)QUFFyFYEfDyUmu~;etA1Rc`~7uaWO~0_K0d9G=|5li z>SIXY<)K#}A)Qb4-?W73ymsiOnx`3lTK8 z|Mk6R&0=}I{_={?^L_vI;LBT{MZ7PKJh_VF^zYtvz4v)spZwX*i++Xcvri@8qvQ6y zsTXp*zN_K6)0>c<@6pJKFXDdu^|Lne`pm+}OkTfw@@H577T2VsH&$_ceB$E+pWrxi z=e>Vk#qng!`-$WJgzHOR?>qf3xQ_NVC9uB^RNwn~KQeOnc|W`!$^WlDevkat+<((= z{@F~f!UMHQ*B$srpJO?%`0bHR|7iTb7mwp;(+elU1^U|`><`*cT+C{%2it$=tj`=s z!Clvv7hD0dq-(`D9$JZO&;8fFr<3hi<+c!EZWBakt^yH$L~K zK-{pNZNBg;r>;f)*>d02zC46&-FM^nUPd`@Td@DH=8IGCdw=Q4KK{_ZYu>6qBVP3S z@$huq@7i&087_Ko960`(>ig|hnBIvMqub;60noeWi|s#;-^Z_O08VauV*8`W_r4kL z{x#dxzOKs(+7P~fef#qe2$cg{Rvw&+=MQ}3kIyi_`=8#E!+!U)O>_3MU7!9?)<(Yn zjQY6`AH{pmT=bK*KS%f(h2uH-2tWId)+djXE z{rQ)l;JE+gSsy-+AMDO8fBYir^_}y_}rrrE8_H*CQeP#bExPSPJ%&#Wk zxko;CU?bbxqx09cvz(WWzPoDcx<1AdCEAzrwQ$>oskr{EWq12s%IDC{<*r8(_g^-^WXfyZiYYqg?Y0%zxmbS zcLi83FSPuyv4z()uaA?SUw?RTDhukxU!3$I{{G^uzAJu~emv_w&Vydr|K-=qasAnr>+Y+>^(XW1{WKnzcOT!L`1tNclDg*{ zxoFQyxo1z6JhvxLj^fPSTPjQTR!aZgcDZivnNoC8wX~g7Bq!qfzLWOL(UaPx?c{}W z{>igs=;X5`d*4E7*>{7yw69#IpR!!KPYKF_Q}X5VQ)2RmQx?nI{j+7={z5rr|8er& z{n_%&{w(?Z{>4%ShpCMRiX?iVL=NHl(E~xb^FW?_|3JRHa3Crjr%sohr>4qDutECn zQE}MCVA)`=Sbt_YvuCGo8-aE8zu10X4&}8mGZuKu9nevJ}lS##|e^j#k=In zD;nenSNujs{`1|^^{xx$fp=XdJ@0-}s@_xVX?gEYWY*wLxpeSu312x^_FcJLK67QW zyl`c?OnKi@X?ovnNq_wCOewx2Y_QuN99%gvu` zmRCQyN)}$dLiS%>C!f7~KxPlkm32d<62tl4p<=mlXr(+qR3@p{6v)hLYNYp?2Km4> zOXPuTZj(cws*>wIl_ht53NzJfzb)UscBcI1+AHLoPxpGh{h1aCe0HPk{_IKez0WR| z#Lu-z`{xeHw?21?bX->@XI)n=S6#PK9=YyBsk^>WF1-FUdGY!@@!i1I`sSnk#x~FU zzfdFhePOM5Z(1fRZ#q$~xv52-zbQjry{T5JZeA+8Zk{0*-#k-3dvmq?;O6;~FuXt( z4bPG7!`X7$aGAV+xLtlc+$OVcnIk>7yjOm5OHlsnmIX5ZNP)B+Ss|AmSs-6LGFzTJ zGG9_}ohM6fT`VWxI$u6=D_4o`V1FgjaKkD&e8UR4^M;l3dt4WMzFPV}zeGNO^8uW4 zBm1HFQ7$LQ#qurrlg#t9dvXf<*S%c+vwOQd*Ig&Uo_g8U6OmhRdLmn8TjX?k zC~~>1 zQoW;0dUjkXV>?cgwtmh5|NgPJzfErGUm!p0ua(@L%cN&#wOp`sh1{|8pv;ek<<#i& zvT0YhdpODcUA%MHG$CpCG2tVn*3d^`ChS(vgxE>Bq| zUrEW8$5M*q<&+ELKx5>R3 z%jEYNzxMoW>bvAXAR_k$PLZn2LAf*YcqyLtX}NFO3V9vp(ySG7I?gX-rOTIb-jDNP z+^0`pAuTvB#(59U*QTe7H+zMw$xfG!?7PLElP*~~$IIC{w@5|qS@QARweoasy1bD4 zL-~5%#nPOAt^6{7t7mQDBG1`HOXS9)74lrshviUlSne&(l81}0k<&|-%Jn77<(ZP5 z(onig&MQ4lUMO7w*9+;g5a;UP3ON_&ZNMWq9|ZQ#7?RJ;XqDg2sFj&zUz8t~Jt4Q0 zFP2}F*Gb9D$K}_FNu%T>2L@$k2lAp4S&<2;40u7A%>TFmKsc<;7)v(ookR zm*V^e&gA909P!GC(dX~sT^*}lMf^O zmX<x+4{kN`{!rWB+xVmkod<|#(c&^R$6TbGK%x<48o$Xu`y5ofQ3C8jJ z+ZV-y|EcRY+9%57=k3*!*^&Ro^Hm))rMn|fc6SuX#T|w633&KBg6l(w^DM5OPFLQ1 zps>@?wFqHdoyBr8&dWPF4;8tt)1`S|XO29M^EaJA$><8|Z}ETCxbN!9lM}m&<7$Ut&H zqAB=26=7)s38iDVA_MnR@Y__x#W@fN$Oz8BH2jV;f-{CQ2)iH=oFh2LaE?w#cy>UB zaRzgcF3tg7a}kD9@{k_RKtAqqh70f;&R`+Zz!@yU?>HmHcn;?<&M}-pXw3}a43^>^ zXE=!W;2g&poPqb^lrmtPBfOR)KF(2`gER5I*@%lXR)Obn4pt)m9K0LnIL=TN-i31< zXJ9VgjdKX+2+r_4Jcn}#r&Qw^oP#(=aE{{~sKIYIM{tJb<2Rh6IAbBa3uj;fe#beE zGqw=vEy6Q6M{vd#;WwPJ9M9m4;vB#^f^&EU(!&{9iTF6j zams37oY6J7$2ky2SUuj2Gui-}a0VLjOcUZY$+^zghirOcBIWuvGM<(+>?99gWLh`Bp*Fms8@zf-dW~8^IC))(D0*2&z1A=$2jhIb8J5ScE`E+ zadPT!7xy3i?SDs3^0el1te7FQ@mGa9HdhWH^nkQU2d){Y)hpyC)UCC^@0X9s*W`Wp zH3NU~BS}1Ht^Chxre675FdhNd@Eh3o2KsB@MNopC1H!*|>Yu{{_~o4%#(u%YJ2nMA zd+g!TVQ8{G|K{KMMm=B`5rj`Z5a7~d9OiA}NJd)xOR+2I`RgNIM~?kvYK2>Ep&eAP zm*e5ZyH;yokOVXhZJhKb$aEnmr~|(b%Pm0pDB&Y=E6{Yb`rG7-K>vR{{&)3j|L=Z* zc(3=jum8GtCupskoSvIqbB`r{aDU_2V>tp=qX*#;*8gw)FZR|y{g3$NQ*zn=2s-{v z#M_lXkIo=G=pPf&GbV`-^F;Q>oF}DYWSWBC0~m?ekFp2N!Hh8QW-GJyFtV0z(a;P-V7U_ z3p}FOjgF&+IaZAs=IB3eSZBNmq{k~Y_#ZIL8D&th8|6ZVIRgkAt_F@6=6j=xCy%Ge zIw}rmxEq594KwdUhMAXP!+ziq!%TD3FyA$1n6!;6wh%!=yQ8n00ADF-ult&@fXPGR*HjY?x&` zqWG`BO#SfMKmaiaEOk{f4#v7$!v#!^~q;F=K#!!@L`?I1C>& z%sjfoecxdXcjY-^n00K_u+|^NM!#XDAH0n>=r_#tgNB)xkYX!;!;Vt?h#ayEqZ;mL zh#BU098m1uJ7}19LxxG)uws|~h+(EbYM5m^W|*{%E4FV0z6^UkJ{>U3Ra($6e+?NX zonggESTCad4Rf9lH9Q5_9Z9;f9I$YP4H_nGLxxG)uwl|RVwmq5RqV=S%rMJjT(PT@ z0-h4v1R zFx$(>q-RGBGtQV|mzQzF+>@0Q((lm`BVd^H1P!xHLWY^guwil&B8FY62tYcE@IR*E zZWS_Mm^2I;=3H*bFjpDFhUWs0D0Zu!QNyHX%rNB&#|@J`hay>#C zo+vE0uwimPB8nZIQNv+`#}vC<4H#xw4I1X?I%Jr9bV9WzXd#tkd|>67R;tn?c`md>z-yKfOOOgf{A9i1`5VT2DTc61IJCOt!jS+>K5 zS+*mFm43sdVazbU*SKNUVRv{ik3#upFfWd_pkdM$QtW688xA8pqS(!=!D<@Cjc7{f4#t4U@J}!)3r@hS^V!Pl_*7T=}z43mBdO><*W&kcG3y4I7>b z95Jl@zhU-ju}OHq@N9$+8fIAy8D^;r8zy&Q#4z(RYFNiF!@H5+al@?h0-k%kodygu zzd^(0z#+pd!?0nNVZ<=MZ`3f;j49>}J$@u&t_}Jp#dp70{kL$I?TBIKchoT7HKsUG zC>c0zxPpmbuYlw4t0=^PVU}Uga4q7849`J$*l-na#4yV~BK>B^sZ3@A>N>9`3R*73_Q>rB{iHsVAK zYyB}i3vptGa}a01F!MNQnE4tqtnJq@-!)?R`{-Oo4WkHUOmTwbAWOp#K&LW z5;x#~P{TFgjeqRX!*3BD)o@p~?g3Xf1~i=OJkW0#B*>6qe#c?MY+oaWncq>vtANK8 zC+N2uH_SF7*h}K~WqS`O_DP80dib!{fcj(Mq#H@u+NDZW}E@Tj5Da% zFHi3P{f4=hFl=$yhqxmFD^t*~;p8{Qk7QvPj%&DU3xa(x_L&vVcMh&xUV}{ul1{8Z-`5Wf5Lly^6h7D`|G3-Wf{_54feaxOsLCCmawjII# z9s3`aPrxwib5OBcAB7Av{jg#7ClSLex2R$LrnqOB@Y@Y&xJTDhgNFIuA;WyHJ6xL` znG}C?Qv9(=@y89btOR?G*r!Gf0{w|`;zx>p-tgVV2>j#bG}@W|%aO8?FTw?vFHCn0W~) z_Q+?S1O0|u5FRlMXop7_940H=mqEk)c0=|o-{lUEmet6lXGaZ_=CMi7jw@z~ z$BzV8|FPf8ys*v(4fENM;Y{GLVpmoX!)&Kf!>ltgi_b4JU|9Q4#Xgy!*(c42Gi-5K z4@V}&A2rPPju~cK9yhFY6?@a9d15YHG`$1I#*c)&30^PpkoeaJBB88*!F8By%U?oq=^zv3kA2gVJvKM}|Ru>JA~ z7@pjI`Rzg)?q~}e*77$@I-`b}X3VhGf5W6<&@jtk$T0IYtazfA=X#tpj9MI~KW3QW z$uD6XopqDj^FeJz>M7Ct{dyjvD57j45`h3>en(SIph1_>rvhoMC&G z;Uk8Xe#3n4m|>RBxM3}I$Xt+q(i1SO?bk5h8&XV}0MKuk45kxS5TSj*oq z`VnP zkjo+cq$gmQ?+qGeIw8Z_UT`1hxkW6T^h6Ca9d{&Yof)ujra3q%&X8f!JZzZn8ZoT> zr(x1OW|(!@9j?yE3`alH2^gNJZ;pnLhI@o`h7B{#h++17QG1r@#0)bp1BThg2MzOE z3@J|5G=~i<{e~yXDp~9Hm_1AS#|=-k9Y<%NjCpzUx{2Q?q~X?o8rJ%6nE8zwW`7$~ z>~r~w! zCh2!`hJfJ}2ni~7bCr-`(i}G23>;DH>Q&UR(r>sOaRv;#5fT9?6Xs<|!`&QU*f7IK z3~T*2%=eBd#<+$|jvLlI&T{3?`WZ013OK0P#Sa-~e#45Bblw#)to286qK@w|!wer# z?9=xS8fG4c6#KEpLj5t!@DaoOMx&F$#}pg=hPA%UCjB1Np!ng@J}Ri;R{n-5I~q33 zb`&wp@`);T>BkJSd?=`=YS)I86Gvv_7yYC`Y>QP z1K1rNNacWj4fo^Aqy8Ay`lHx=_ff;7ZOpLFpB1|`Z#+%X5SZig!u$pehk!$h-Iog+ zX8ed^4|c!fhg-wO>{+HWV7M80(Bdoq-0%W~4=eWTw;nOfyo@SN(YiNgnDn^A>Q5DE z_6z&2fML=WG|c|o9e(Y{!W!<@wh_auZ&AhWd&La1z71F$?o$jJX84d|zf9B(zqY#( z3)lX~FzFdHJW>Ds+ULt$NB`t>nD^kM@Q`8B88*zi7cs2uSFumqW6UtqaR=oHK)=PG zOao~f)^ImoxcG@$uSPYT5@Mj=Fw-1YthHZc9_dHFf&T%+fD$y!^h1Ux#vM1NM<&IO z8fH4~NOtod4R>?bLBmYb9d156tl>#oPeu$g&Zy#KVgE2@m}NL_c%saW{%YpMr4uyF z{Du^}xk}hD>5M4$=$<%kad=c(A~q@hfMLGZ9WGx(8cvxzl)qv2KkjhznNbaQ63JtR zC*pXuzDW&fc6`NvVYc_6VfJGo!&-j~^F0y66~Ix&DN0Yw@Wi)BfvgGYkHw!Tw*;*x z!xlbKgIxHirNj7RhPD0}ZbP`tC;cgqkU{-X?AmhB@I-&^SH478!yQjDVwm4LsyIda zkeFfScfjz(d@@Db-H?TA`5R_BBZeoWx>MZzXHxv}N%6tl$5XC+0*0BFpyEWiyd33k zn0XHyW?4lHvmBy|-CPT|INVq>py4T6hX)Ol&LP8Tz{7@_ml4CHf7I|qyGzk_I>VQs<M<5HnB${6TwY*o3b*cE0mGbc1PwF&kYd-Tg$=WAL=5wLMHNq!RD7N} zFzMMr!_4o{q-Tc>^IME4PSJVAsA0w*Q|x${irHG?huaqjSsaFj4KvM%Vz15_qK285m|>RrfMJf~gNl=&eT4Ei ztnJt0Ow@ljHyG7$Cj&EPnB_TcI0!6tuKtjofMM3XpkbC_$S~_(*f76E#4zh#)G)tY z%rNWTfMI^$LBp(jLxx$$h7GgsjTmOWMh&wZ#tiejj~lK8c8BAW1eUwJ@S6q=^P7eY zr&(;a&Hca;4R`ZH_fxVc{T838xx*tYw?PY^3Or<(`5IRIW_c~8-{MR|oH4^%{)!Xi zf=lqj3ckhd?*|N5AtY$H2{>e!?+PnUln)*T{f6ftJZhNzSZq@GfZ^;5LBC;^=aAwg zi2}PLN%ycuG~A8vqlTH6F~uHTN4WTIzf4w=ez%Se7-n4x8fKY?471*b4YOXk!|km{ zEu7yjW|-*=D0cF7F23LKeV}_ZgJKTF^73uf5`KMu)b5ODS zMj^v2=dfXZqljUCqo`qi-r7dRR%&A#-rax+!bLla|6ZO{GLfFyI{00p3T|vVvpO9hJ$*^J47BQ^luh^%& zl$c@W-5ow{n}Zgg?;0|!{ik83KVmo&c+@c8HD;La8aK?my92Ju0Rr_dFN_~F%rXfX zW;urqGo8q!@Tg(tJ!Y8n4;W_s95j6FdxtHYG>jN#zD5o6y<>(++qhxUAPtUYzAIpu z-zaF9e72Bb(hxSxellYCSbAa>&i4)&COw0OSbcphMA_U zb@T@T1BOGuLBkx2Lxy$!W0+%c#4!7usNr(pm|?cN0mE!}gNB)}A;WBI!-iRgBZfH^ zj~Zqj7&FZNYTPitwKO{V(~0$P^WLC^Gru9jO21*wha-kbPt-8;8#B!J4j5*B2MzPR zLx!2(VZ$uX5yQ;ys9~1Rm|^C3+%U^WnjHPiZ@{qDAH&RV$S}(%Y0H7vpmCwncs+E zewV0W<~L@T`5G`hIlo%|7S8+*8z!A2hMC_{!&-j~2N6DQnD3PqM?b%Nz%bt%G|c>l z3^QM0!_05QFv~M)nE8zvCY=L@ncqRfTK^3*zr%*L{0&deuht(6XMV>GGhfo`=x2Td zhLwK9L4=14YyC0I{6-9u&ZuF2_n2Ykcfhc=U&Ewx$gs9w!=!V>u(n^rT7L{PzvG6r z{M#J;lk>~+30gSw8#1irZ&=%}VbT*d90ZOT*7|Rl`5iP&I)@B1zr%)EJ|l+t-A4_x ze8voG`!%few>$c^{TkNtH_ZHo46_`~( zHDuw;@33Jlf5X~-4KtlF!$IJ2!z>5sbo6WcHLUf=F!LKS%=d;3GrtkTTKjvAhYf4}H#|ANEYC3uXMV>g#g{HezqVh)TK0fTW_gYo=64@A%<_?LNB`vf^1B2lg@+82 K9(OqY-v0pziK?>z literal 0 HcmV?d00001 diff --git a/src/games/adventure/done.c b/src/games/adventure/done.c new file mode 100644 index 0000000..6b6d3b4 --- /dev/null +++ b/src/games/adventure/done.c @@ -0,0 +1,99 @@ +/* + * Re-coding of advent in C: termination routines + */ +#include "hdr.h" + +int +score() /* sort of like 20000 */ +{ register int scor,i; + mxscor=scor=0; + for (i=50; i<=maxtrs; i++) + { if (ptext[i].txtlen==0) continue; + k=12; + if (i==chest) k=14; + if (i>chest) k=16; + if (prop[i]>=0) scor += 2; + if (place[i]==3&&prop[i]==0) scor += k-2; + mxscor += k; + } + scor += (maxdie-numdie)*10; + mxscor += maxdie*10; + if (!(scorng||gaveup)) scor += 4; + mxscor += 4; + if (dflag!=0) scor += 25; + mxscor += 25; + if (closng) scor += 25; + mxscor += 25; + if (closed) + { if (bonus==0) scor += 10; + if (bonus==135) scor += 25; + if (bonus==134) scor += 30; + if (bonus==133) scor += 45; + } + mxscor += 45; + if (place[magzin]==108) scor++; + mxscor++; + scor += 2; + mxscor += 2; + for (i=1; i<=hntmax; i++) + if (hinted[i]) scor -= hints[i][2]; + return(scor); +} + +void +done(entry) /* entry=1 means goto 13000 */ /* game is over */ +int entry; /* entry=2 means goto 20000 */ /* 3=19000 */ +{ register int i,sc; + if (entry==1) mspeak(1); + if (entry==3) rspeak(136); + printf("\n\n\nYou scored %d out of a ",(sc=score())); + printf("possible %d using %d turns.\n",mxscor,turns); + for (i=1; i<=clsses; i++) + if (cval[i]>=sc) + { speak(&ctext[i]); + if (i==clsses-1) + { printf("To achieve the next higher rating"); + printf(" would be a neat trick!\n\n"); + printf("Congratulations!!\n"); + exit(0); + } + k=cval[i]+1-sc; + printf("To achieve the next higher rating, you need"); + printf(" %d more point",k); + if (k==1) printf(".\n"); + else printf("s.\n"); + exit(0); + } + printf("You just went off my scale!!!\n"); + exit(0); +} + +int +die(entry) /* label 90 */ +int entry; +{ register int i, yea; + if (entry != 99) + { rspeak(23); + oldlc2=loc; + } + if (closng) /* 99 */ + { rspeak(131); + numdie++; + done(2); + } + yea=yes(81+numdie*2, 82+numdie*2, 54); + numdie++; + if (numdie==maxdie || !yea) done(2); + place[water]=0; + place[oil]=0; + if (toting(lamp)) prop[lamp]=0; + for (i=100; i>=1; i--) + { if (!toting(i)) continue; + k=oldlc2; + if (i==lamp) k=1; + drop(i,k); + } + loc=3; + oldloc=loc; + return(2000); +} diff --git a/src/games/adventure/glorkz b/src/games/adventure/glorkz new file mode 100644 index 0000000..c872f69 --- /dev/null +++ b/src/games/adventure/glorkz @@ -0,0 +1,1813 @@ +1 +1 You are standing at the end of a road before a small brick building. +1 Around you is a forest. A small stream flows out of the building and +1 down a gully. +2 You have walked up a hill, still in the forest. The road slopes back +2 down the other side of the hill. There is a building in the distance. +3 You are inside a building, a well house for a large spring. +4 You are in a valley in the forest beside a stream tumbling along a +4 rocky bed. +5 You are in open forest, with a deep valley to one side. +6 You are in open forest near both a valley and a road. +7 At your feet all the water of the stream splashes into a 2-inch slit +7 in the rock. Downstream the streambed is bare rock. +8 You are in a 20-foot depression floored with bare dirt. Set into the +8 dirt is a strong steel grate mounted in concrete. A dry streambed +8 leads into the depression. +9 You are in a small chamber beneath a 3x3 steel grate to the surface. +9 A low crawl over cobbles leads inward to the west. +10 You are crawling over cobbles in a low passage. There is a dim light +10 at the east end of the passage. +11 You are in a debris room filled with stuff washed in from the surface. +11 A low wide passage with cobbles becomes plugged with mud and debris +11 here, but an awkward canyon leads upward and west. A note on the wall +11 says "magic word xyzzy". +12 You are in an awkward sloping east/west canyon. +13 You are in a splendid chamber thirty feet high. The walls are frozen +13 rivers of orange stone. An awkward canyon and a good passage exit +13 From east and west sides of the chamber. +14 At your feet is a small pit breathing traces of white mist. An east +14 passage ends here except for a small crack leading on. +15 You are at one end of a vast hall stretching forward out of sight to +15 the west. There are openings to either side. Nearby, a wide stone +15 staircase leads downward. The hall is filled with wisps of white mist +15 swaying to and fro almost as if alive. A cold wind blows up the +15 staircase. There is a passage at the top of a dome behind you. +16 The crack is far too small for you to follow. +17 You are on the east bank of a fissure slicing clear across the hall. +17 The mist is quite thick here, and the fissure is too wide to jump. +18 This is a low room with a crude note on the wall. The note says, +18 "You won't get it up the steps". +19 You are in the hall of the mountain king, with passages off in all +19 directions. +20 You are at the bottom of the pit with a broken neck. +21 You didn't make it. +22 The dome is unclimbable. +23 You are at the west end of the twopit room. There is a large hole in +23 the wall above the pit at this end of the room. +24 You are at the bottom of the eastern pit in the twopit room. There is +24 a small pool of oil in one corner of the pit. +25 You are at the bottom of the western pit in the twopit room. There is +25 a large hole in the wall about 25 feet above you. +26 You clamber up the plant and scurry through the hole at the top. +27 You are on the west side of the fissure in the hall of mists. +28 You are in a low n/s passage at a hole in the floor. The hole goes +28 down to an e/w passage. +29 You are in the south side chamber. +30 You are in the west side chamber of the hall of the mountain king. +30 A passage continues west and up here. +31 >$< +32 You can't get by the snake. +33 You are in a large room, with a passage to the south, a passage to the +33 west, and a wall of broken rock to the east. There is a large "y2" on +33 A rock in the room's center. +34 You are in a jumble of rock, with cracks everywhere. +35 You're at a low window overlooking a huge pit, which extends up out of +35 sight. A floor is indistinctly visible over 50 feet below. Traces of +35 White mist cover the floor of the pit, becoming thicker to the right. +35 Marks in the dust around the window would seem to indicate that +35 someone has been here recently. Directly across the pit from you and +35 25 Feet away there is a similar window looking into a lighted room. A +35 shadowy figure can be seen there peering back at you. +36 You are in a dirty broken passage. To the east is a crawl. To the +36 west is a large passage. Above you is a hole to another passage. +37 You are on the brink of a small clean climbable pit. A crawl leads +37 west. +38 You are in the bottom of a small pit with a little stream, which +38 Enters and exits through tiny slits. +39 You are in a large room full of dusty rocks. There is a big hole in +39 the floor. There are cracks everywhere, and a passage leading east. +40 You have crawled through a very low wide passage parallel to and north +40 of the hall of mists. +41 You are at the west end of hall of mists. A low wide crawl continues +41 west and another goes north. To the south is a little passage 6 feet +41 Off the floor. +42 You are in a maze of twisty little passages, all alike. +43 You are in a maze of twisty little passages, all alike. +44 You are in a maze of twisty little passages, all alike. +45 You are in a maze of twisty little passages, all alike. +46 Dead end +47 Dead end +48 Dead end +49 You are in a maze of twisty little passages, all alike. +50 You are in a maze of twisty little passages, all alike. +51 You are in a maze of twisty little passages, all alike. +52 You are in a maze of twisty little passages, all alike. +53 You are in a maze of twisty little passages, all alike. +54 Dead end +55 You are in a maze of twisty little passages, all alike. +56 Dead end +57 You are on the brink of a thirty foot pit with a massive orange column +57 down one wall. You could climb down here but you could not get back +57 up. The maze continues at this level. +58 Dead end +59 You have crawled through a very low wide passage parallel to and north +59 of the hall of mists. +60 You are at the east end of a very long hall apparently without side +60 chambers. To the east a low wide crawl slants up. To the north a +60 round two foot hole slants down. +61 You are at the west end of a very long featureless hall. The hall +61 joins up with a narrow north/south passage. +62 You are at a crossover of a high n/s passage and a low e/w one. +63 Dead end +64 You are at a complex junction. A low hands and knees passage from the +64 north joins a higher crawl from the east to make a walking passage +64 going west. There is also a large room above. The air is damp here. +65 You are in bedquilt, a long east/west passage with holes everywhere. +65 To explore at random select north, south, up, or down. +66 You are in a room whose walls resemble swiss cheese. Obvious passages +66 go west, east, ne, and nw. Part of the room is occupied by a large +66 bedrock block. +67 You are at the east end of the twopit room. The floor here is +67 littered with thin rock slabs, which make it easy to descend the pits. +67 There is a path here bypassing the pits to connect passages from east +67 and west. There are holes all over, but the only big one is on the +67 wall directly over the west pit where you can't get to it. +68 You are in a large low circular chamber whose floor is an immense slab +68 fallen from the ceiling (slab room). East and west there once were +68 large passages, but they are now filled with boulders. Low small +68 passages go north and south, and the south one quickly bends west +68 around the boulders. +69 You are in a secret n/s canyon above a large room. +70 You are in a secret n/s canyon above a sizable passage. +71 You are in a secret canyon at a junction of three canyons, bearing +71 north, south, and se. The north one is as tall as the other two +71 combined. +72 You are in a large low room. Crawls lead north, se, and sw. +73 Dead end crawl. +74 You are in a secret canyon which here runs e/w. It crosses over a +74 very tight canyon 15 feet below. If you go down you may not be able +74 to get back up. +75 You are at a wide place in a very tight n/s canyon. +76 The canyon here becomes too tight to go further south. +77 You are in a tall e/w canyon. A low tight crawl goes 3 feet north and +77 seems to open up. +78 The canyon runs into a mass of boulders -- dead end. +79 The stream flows out through a pair of 1 foot diameter sewer pipes. +79 It would be advisable to use the exit. +80 You are in a maze of twisty little passages, all alike. +81 Dead end +82 Dead end +83 You are in a maze of twisty little passages, all alike. +84 You are in a maze of twisty little passages, all alike. +85 Dead end +86 Dead end +87 You are in a maze of twisty little passages, all alike. +88 You are in a long, narrow corridor stretching out of sight to the +88 west. At the eastern end is a hole through which you can see a +88 profusion of leaves. +89 There is nothing here to climb. Use "up" or "out" to leave the pit. +90 You have climbed up the plant and out of the pit. +91 You are at the top of a steep incline above a large room. You could +91 climb down here, but you would not be able to climb up. There is a +91 passage leading back to the north. +92 You are in the giant room. The ceiling here is too high up for your +92 lamp to show it. Cavernous passages lead east, north, and south. On +92 the west wall is scrawled the inscription, "fee fie foe foo" [sic]. +93 The passage here is blocked by a recent cave-in. +94 You are at one end of an immense north/south passage. +95 You are in a magnificent cavern with a rushing stream, which cascades +95 over a sparkling waterfall into a roaring whirlpool which disappears +95 through a hole in the floor. Passages exit to the south and west. +96 You are in the soft room. The walls are covered with heavy curtains, +96 the floor with a thick pile carpet. Moss covers the ceiling. +97 This is the oriental room. Ancient oriental cave drawings cover the +97 walls. A gently sloping passage leads upward to the north, another +97 passage leads se, and a hands and knees crawl leads west. +98 You are following a wide path around the outer edge of a large cavern. +98 Far below, through a heavy white mist, strange splashing noises can be +98 heard. The mist rises up through a fissure in the ceiling. The path +98 exits to the south and west. +99 You are in an alcove. A small nw path seems to widen after a short +99 distance. An extremely tight tunnel leads east. It looks like a very +99 tight squeeze. An eerie light can be seen at the other end. +100 You're in a small chamber lit by an eerie green light. An extremely +100 narrow tunnel exits to the west. A dark corridor leads ne. +101 You're in the dark-room. A corridor leading south is the only exit. +102 You are in an arched hall. A coral passage once continued up and east +102 from here, but is now blocked by debris. The air smells of sea water. +103 You're in a large room carved out of sedimentary rock. The floor and +103 walls are littered with bits of shells imbedded in the stone. A +103 shallow passage proceeds downward, and a somewhat steeper one leads +103 up. A low hands and knees passage enters from the south. +104 You are in a long sloping corridor with ragged sharp walls. +105 You are in a cul-de-sac about eight feet across. +106 You are in an anteroom leading to a large passage to the east. Small +106 passages go west and up. The remnants of recent digging are evident. +106 A sign in midair here says "Cave under construction beyond this point. +106 Proceed at own risk. [Witt construction company]" +107 You are in a maze of twisty little passages, all different. +108 You are at Witt's end. Passages lead off in *all* directions. +109 You are in a north/south canyon about 25 feet across. The floor is +109 covered by white mist seeping in from the north. The walls extend +109 upward for well over 100 feet. Suspended from some unseen point far +109 above you, an enormous two-sided mirror is hanging parallel to and +109 Midway between the canyon walls. (The mirror is obviously provided +109 for the use of the dwarves, who as you know, are extremely vain.) A +109 Small window can be seen in either wall, some fifty feet up. +110 You're at a low window overlooking a huge pit, which extends up out of +110 sight. A floor is indistinctly visible over 50 feet below. Traces of +110 white mist cover the floor of the pit, becoming thicker to the left. +110 Marks in the dust around the window would seem to indicate that +110 someone has been here recently. Directly across the pit from you and +110 25 Feet away there is a similar window looking into a lighted room. A +110 shadowy figure can be seen there peering back at you. +111 A large stalactite extends from the roof and almost reaches the floor +111 below. You could climb down it, and jump from it to the floor, but +111 having done so you would be unable to reach it to climb back up. +112 You are in a little maze of twisting passages, all different. +113 You are at the edge of a large underground reservoir. An opaque cloud +113 of white mist fills the room and rises rapidly upward. The lake is +113 fed by a stream, which tumbles out of a hole in the wall about 10 feet +113 overhead and splashes noisily into the water somewhere within the +113 Mist. The only passage goes back toward the south. +114 Dead end +115 You are at the northeast end of an immense room, even larger than the +115 giant room. It appears to be a repository for the "adventure" +115 program. Massive torches far overhead bathe the room with smoky +115 yellow light. Scattered about you can be seen a pile of bottles (all +115 of them empty), a nursery of young beanstalks murmuring quietly, a bed +115 of oysters, a bundle of black rods with rusty stars on their ends, and +115 a collection of brass lanterns. Off to one side a great many dwarves +115 are sleeping on the floor, snoring loudly. A sign nearby reads: "Do +115 not disturb the dwarves!" An immense mirror is hanging against one +115 wall, and stretches to the other end of the room, where various other +115 sundry objects can be glimpsed dimly in the distance. +116 You are at the southwest end of the repository. To one side is a pit +116 full of fierce green snakes. On the other side is a row of small +116 wicker cages, each of which contains a little sulking bird. In one +116 corner is a bundle of black rods with rusty marks on their ends. A +116 large number of velvet pillows are scattered about on the floor. A +116 vast mirror stretches off to the northeast. At your feet is a large +116 steel grate, next to which is a sign which reads, "Treasure vault. +116 Keys in main office." +117 You are on one side of a large, deep chasm. A heavy white mist rising +117 up from below obscures all view of the far side. A sw path leads away +117 from the chasm into a winding corridor. +118 You are in a long winding corridor sloping out of sight in both +118 directions. +119 You are in a secret canyon which exits to the north and east. +120 You are in a secret canyon which exits to the north and east. +121 You are in a secret canyon which exits to the north and east. +122 You are on the far side of the chasm. A ne path leads away from the +122 chasm on this side. +123 You're in a long east/west corridor. A faint rumbling noise can be +123 heard in the distance. +124 The path forks here. The left fork leads northeast. A dull rumbling +124 seems to get louder in that direction. The right fork leads southeast +124 down a gentle slope. The main corridor enters from the west. +125 The walls are quite warm here. From the north can be heard a steady +125 roar, so loud that the entire cave seems to be trembling. Another +125 passage leads south, and a low crawl goes east. +126 You are on the edge of a breath-taking view. Far below you is an +126 active volcano, from which great gouts of molten lava come surging +126 out, cascading back down into the depths. The glowing rock fills the +126 farthest reaches of the cavern with a blood-red glare, giving every- +126 thing an eerie, macabre appearance. The air is filled with flickering +126 sparks of ash and a heavy smell of brimstone. The walls are hot to +126 the touch, and the thundering of the volcano drowns out all other +126 sounds. Embedded in the jagged roof far overhead are myriad twisted +126 formations composed of pure white alabaster, which scatter the murky +126 light into sinister apparitions upon the walls. To one side is a deep +126 gorge, filled with a bizarre chaos of tortured rock which seems to +126 have been crafted by the devil himself. An immense river of fire +126 crashes out from the depths of the volcano, burns its way through the +126 gorge, and plummets into a bottomless pit far off to your left. To +126 the right, an immense geyser of blistering steam erupts continuously +126 from a barren island in the center of a sulfurous lake, which bubbles +126 ominously. The far right wall is aflame with an incandescence of its +126 own, which lends an additional infernal splendor to the already +126 hellish scene. A dark, foreboding passage exits to the south. +127 You are in a small chamber filled with large boulders. The walls are +127 very warm, causing the air in the room to be almost stifling from the +127 heat. The only exit is a crawl heading west, through which is coming +127 a low rumbling. +128 You are walking along a gently sloping north/south passage lined with +128 oddly shaped limestone formations. +129 You are standing at the entrance to a large, barren room. A sign +129 posted above the entrance reads: "Caution! Bear in room!" +130 You are inside a barren room. The center of the room is completely +130 empty except for some dust. Marks in the dust lead away toward the +130 far end of the room. The only exit is the way you came in. +131 You are in a maze of twisting little passages, all different. +132 You are in a little maze of twisty passages, all different. +133 You are in a twisting maze of little passages, all different. +134 You are in a twisting little maze of passages, all different. +135 You are in a twisty little maze of passages, all different. +136 You are in a twisty maze of little passages, all different. +137 You are in a little twisty maze of passages, all different. +138 You are in a maze of little twisting passages, all different. +139 You are in a maze of little twisty passages, all different. +140 Dead end +-1 End +2 +1 You're at end of road again. +2 You're at hill in road. +3 You're inside building. +4 You're in valley. +5 You're in forest. +6 You're in forest. +7 You're at slit in streambed. +8 You're outside grate. +9 You're below the grate. +10 You're in cobble crawl. +11 You're in debris room. +13 You're in bird chamber. +14 You're at top of small pit. +15 You're in hall of mists. +17 You're on east bank of fissure. +18 You're in nugget of gold room. +19 You're in hall of mt king. +23 You're at west end of twopit room. +24 You're in east pit. +25 You're in west pit. +33 You're at "y2". +35 You're at window on pit. +36 You're in dirty passage. +39 You're in dusty rock room. +41 You're at west end of hall of mists. +57 You're at brink of pit. +60 You're at east end of long hall. +61 You're at west end of long hall. +64 You're at complex junction. +66 You're in swiss cheese room. +67 You're at east end of twopit room. +68 You're in slab room. +71 You're at junction of three secret canyons. +74 You're in secret e/w canyon above tight canyon. +88 You're in narrow corridor. +91 You're at steep incline above large room. +92 You're in giant room. +95 You're in cavern with waterfall. +96 You're in soft room. +97 You're in oriental room. +98 You're in misty cavern. +99 You're in alcove. +100 You're in plover room. +101 You're in dark-room. +102 You're in arched hall. +103 You're in shell room. +106 You're in anteroom. +108 You're at witt's end. +109 You're in mirror canyon. +110 You're at window on pit. +111 You're at top of stalactite. +113 You're at reservoir. +115 You're at ne end. +116 You're at sw end. +117 You're on sw side of chasm. +118 You're in sloping corridor. +122 You're on ne side of chasm. +123 You're in corridor. +124 You're at fork in path. +125 You're at junction with warm walls. +126 You're at breath-taking view. +127 You're in chamber of boulders. +128 You're in limestone passage. +129 You're in front of barren room. +130 You're in barren room. +-1 +3 +1 2 2 44 29 +1 3 3 12 19 43 +1 4 5 13 14 46 30 +1 5 6 45 43 +1 8 63 +2 1 2 12 7 43 45 30 +2 5 6 45 46 +3 1 3 11 32 44 +3 11 62 +3 33 65 +3 79 5 14 +4 1 4 12 45 +4 5 6 43 44 29 +4 7 5 46 30 +4 8 63 +5 4 9 43 30 +5 50005 6 7 45 +5 6 6 +5 5 44 46 +6 1 2 45 +6 4 9 43 44 30 +6 5 6 46 +7 1 12 +7 4 4 45 +7 5 6 43 44 +7 8 5 15 16 46 +7 595 60 14 30 +8 5 6 43 44 46 +8 1 12 +8 7 4 13 45 +8 303009 3 19 30 +8 593 3 +9 303008 11 29 +9 593 11 +9 10 17 18 19 44 +9 14 31 +9 11 51 +10 9 11 20 21 43 +10 11 19 22 44 51 +10 14 31 +11 303008 63 +11 9 64 +11 10 17 18 23 24 43 +11 12 25 19 29 44 +11 3 62 +11 14 31 +12 303008 63 +12 9 64 +12 11 30 43 51 +12 13 19 29 44 +12 14 31 +13 303008 63 +13 9 64 +13 11 51 +13 12 25 43 +13 14 23 31 44 +14 303008 63 +14 9 64 +14 11 51 +14 13 23 43 +14 150020 30 31 34 +14 15 30 +14 16 33 44 +15 18 36 46 +15 17 7 38 44 +15 19 10 30 45 +15 150022 29 31 34 35 23 43 +15 14 29 +15 34 55 +16 14 1 +17 15 38 43 +17 312596 39 +17 412021 7 +17 412597 41 42 44 69 +17 27 41 +18 15 38 11 45 +19 15 10 29 43 +19 311028 45 36 +19 311029 46 37 +19 311030 44 7 +19 32 45 +19 35074 49 +19 211032 49 +19 74 66 +20 0 1 +21 0 1 +22 15 1 +23 67 43 42 +23 68 44 61 +23 25 30 31 +23 648 52 +24 67 29 11 +25 23 29 11 +25 724031 56 +25 26 56 +26 88 1 +27 312596 39 +27 412021 7 +27 412597 41 42 43 69 +27 17 41 +27 40 45 +27 41 44 +28 19 38 11 46 +28 33 45 55 +28 36 30 52 +29 19 38 11 45 +30 19 38 11 43 +30 62 44 29 +31 524089 1 +31 90 1 +32 19 1 +33 3 65 +33 28 46 +33 34 43 53 54 +33 35 44 +33 159302 71 +33 100 71 +34 33 30 55 +34 15 29 +35 33 43 55 +35 20 39 +36 37 43 17 +36 28 29 52 +36 39 44 +36 65 70 +37 36 44 17 +37 38 30 31 56 +38 37 56 29 11 +38 595 60 14 30 4 5 +39 36 43 23 +39 64 30 52 58 +39 65 70 +40 41 1 +41 42 46 29 23 56 +41 27 43 +41 59 45 +41 60 44 17 +42 41 29 +42 42 45 +42 43 43 +42 45 46 +42 80 44 +43 42 44 +43 44 46 +43 45 43 +44 43 43 +44 48 30 +44 50 46 +44 82 45 +45 42 44 +45 43 45 +45 46 43 +45 47 46 +45 87 29 30 +46 45 44 11 +47 45 43 11 +48 44 29 11 +49 50 43 +49 51 44 +50 44 43 +50 49 44 +50 51 30 +50 52 46 +51 49 44 +51 50 29 +51 52 43 +51 53 46 +52 50 44 +52 51 43 +52 52 46 +52 53 29 +52 55 45 +52 86 30 +53 51 44 +53 52 45 +53 54 46 +54 53 44 11 +55 52 44 +55 55 45 +55 56 30 +55 57 43 +56 55 29 11 +57 13 30 56 +57 55 44 +57 58 46 +57 83 45 +57 84 43 +58 57 43 11 +59 27 1 +60 41 43 29 17 +60 61 44 +60 62 45 30 52 +61 60 43 +61 62 45 +61 100107 46 +62 60 44 +62 63 45 +62 30 43 +62 61 46 +63 62 46 11 +64 39 29 56 59 +64 65 44 70 +64 103 45 74 +64 106 43 +65 64 43 +65 66 44 +65 80556 46 +65 68 61 +65 80556 29 +65 50070 29 +65 39 29 +65 60556 45 +65 75072 45 +65 71 45 +65 80556 30 +65 106 30 +66 65 47 +66 67 44 +66 80556 46 +66 77 25 +66 96 43 +66 50556 50 +66 97 72 +67 66 43 +67 23 44 42 +67 24 30 31 +68 23 46 +68 69 29 56 +68 65 45 +69 68 30 61 +69 331120 46 +69 119 46 +69 109 45 +69 113 75 +70 71 45 +70 65 30 23 +70 111 46 +71 65 48 +71 70 46 +71 110 45 +72 65 70 +72 118 49 +72 73 45 +72 97 48 72 +73 72 46 17 11 +74 19 43 +74 331120 44 +74 121 44 +74 75 30 +75 76 46 +75 77 45 +76 75 45 +77 75 43 +77 78 44 +77 66 45 17 +78 77 46 +79 3 1 +80 42 45 +80 80 44 +80 80 46 +80 81 43 +81 80 44 11 +82 44 46 11 +83 57 46 +83 84 43 +83 85 44 +84 57 45 +84 83 44 +84 114 50 +85 83 43 11 +86 52 29 11 +87 45 29 30 +88 25 30 56 43 +88 20 39 +88 92 44 27 +89 25 1 +90 23 1 +91 95 45 73 23 +91 72 30 56 +92 88 46 +92 93 43 +92 94 45 +93 92 46 27 11 +94 92 46 27 23 +94 309095 45 3 73 +94 611 45 +95 94 46 11 +95 92 27 +95 91 44 +96 66 44 11 +97 66 48 +97 72 44 17 +97 98 29 45 73 +98 97 46 72 +98 99 44 +99 98 50 73 +99 301 43 23 +99 100 43 +100 301 44 23 11 +100 99 44 +100 159302 71 +100 33 71 +100 101 47 22 +101 100 46 71 11 +102 103 30 74 11 +103 102 29 38 +103 104 30 +103 114618 46 +103 115619 46 +103 64 46 +104 103 29 74 +104 105 30 +105 104 29 11 +105 103 74 +106 64 29 +106 65 44 +106 108 43 +107 131 46 +107 132 49 +107 133 47 +107 134 48 +107 135 29 +107 136 50 +107 137 43 +107 138 44 +107 139 45 +107 61 30 +108 95556 43 45 46 47 48 49 50 29 30 +108 106 43 +108 626 44 +109 69 46 +109 113 45 75 +110 71 44 +110 20 39 +111 70 45 +111 40050 30 39 56 +111 50053 30 +111 45 30 +112 131 49 +112 132 45 +112 133 43 +112 134 50 +112 135 48 +112 136 47 +112 137 44 +112 138 30 +112 139 29 +112 140 46 +113 109 46 11 109 +114 84 48 +115 116 49 +116 115 47 +116 593 30 +117 118 49 +117 233660 41 42 69 47 +117 332661 41 +117 303 41 +117 332021 39 +117 596 39 +118 72 30 +118 117 29 +119 69 45 11 +119 653 43 7 +120 69 45 +120 74 43 +121 74 43 11 +121 653 45 7 +122 123 47 +122 233660 41 42 69 49 +122 303 41 +122 596 39 +122 124 77 +122 126 28 +122 129 40 +123 122 44 +123 124 43 77 +123 126 28 +123 129 40 +124 123 44 +124 125 47 36 +124 128 48 37 30 +124 126 28 +124 129 40 +125 124 46 77 +125 126 45 28 +125 127 43 17 +126 125 46 23 11 +126 124 77 +126 610 30 39 +127 125 44 11 17 +127 124 77 +127 126 28 +128 124 45 29 77 +128 129 46 30 40 +128 126 28 +129 128 44 29 +129 124 77 +129 130 43 19 40 3 +129 126 28 +130 129 44 11 +130 124 77 +130 126 28 +131 107 44 +131 132 48 +131 133 50 +131 134 49 +131 135 47 +131 136 29 +131 137 30 +131 138 45 +131 139 46 +131 112 43 +132 107 50 +132 131 29 +132 133 45 +132 134 46 +132 135 44 +132 136 49 +132 137 47 +132 138 43 +132 139 30 +132 112 48 +133 107 29 +133 131 30 +133 132 44 +133 134 47 +133 135 49 +133 136 43 +133 137 45 +133 138 50 +133 139 48 +133 112 46 +134 107 47 +134 131 45 +134 132 50 +134 133 48 +134 135 43 +134 136 30 +134 137 46 +134 138 29 +134 139 44 +134 112 49 +135 107 45 +135 131 48 +135 132 30 +135 133 46 +135 134 43 +135 136 44 +135 137 49 +135 138 47 +135 139 50 +135 112 29 +136 107 43 +136 131 44 +136 132 29 +136 133 49 +136 134 30 +136 135 46 +136 137 50 +136 138 48 +136 139 47 +136 112 45 +137 107 48 +137 131 47 +137 132 46 +137 133 30 +137 134 29 +137 135 50 +137 136 45 +137 138 49 +137 139 43 +137 112 44 +138 107 30 +138 131 43 +138 132 47 +138 133 29 +138 134 44 +138 135 45 +138 136 46 +138 137 48 +138 139 49 +138 112 50 +139 107 49 +139 131 50 +139 132 43 +139 133 44 +139 134 45 +139 135 30 +139 136 48 +139 137 29 +139 138 46 +139 112 47 +140 112 45 11 +-1 +4 +2 road +2 hill +3 enter +4 upstr +5 downs +6 fores +7 forwa +7 conti +7 onwar +8 back +8 retur +8 retre +9 valle +10 stair +11 out +11 outsi +11 exit +11 leave +12 build +12 house +13 gully +14 strea +15 rock +16 bed +17 crawl +18 cobbl +19 inwar +19 insid +19 in +20 surfa +21 null +21 nowhe +22 dark +23 passa +23 tunne +24 low +25 canyo +26 awkwa +27 giant +28 view +29 upwar +29 up +29 u +29 above +29 ascen +30 d +30 downw +30 down +30 desce +31 pit +32 outdo +33 crack +34 steps +35 dome +36 left +37 right +38 hall +39 jump +40 barre +41 over +42 acros +43 east +43 e +44 west +44 w +45 north +45 n +46 south +46 s +47 ne +48 se +49 sw +50 nw +51 debri +52 hole +53 wall +54 broke +55 y2 +56 climb +57 look +57 exami +57 touch +57 descr +58 floor +59 room +60 slit +61 slab +61 slabr +62 xyzzy +63 depre +64 entra +65 plugh +66 secre +67 cave +69 cross +70 bedqu +71 plove +72 orien +73 caver +74 shell +75 reser +76 main +76 offic +77 fork +1001 keys +1001 key +1002 lamp +1002 headl +1002 lante +1003 grate +1004 cage +1005 wand +1005 rod +1006 wand +1006 rod (must be next object after "real" rod) +1007 steps +1008 bird +1009 door +1010 pillo +1010 velve +1011 snake +1012 fissu +1013 table +1014 clam +1015 oyste +1016 magaz +1016 issue +1016 spelu +1016 spell +1017 dwarf +1017 dwarv +1018 knife +1018 knive +1019 food +1019 ratio +1020 bottl +1020 jar +1021 water +1021 h2o +1022 oil +1023 mirro +1024 plant +1024 beans +1025 plant (must be next object after "real" plant) +1026 stala +1027 shado +1027 figur +1028 axe +1029 drawi +1030 pirat +1031 drago +1032 chasm +1033 troll +1034 troll (must be next object after "real" troll) +1035 bear +1036 messa +1037 volca +1037 geyse (same as volcano) +1038 machi +1038 vendi +1039 batte +1040 carpe +1040 moss +1050 gold +1050 nugge +1051 diamo +1052 silve +1052 bars +1053 jewel +1054 coins +1055 chest +1055 box +1055 treas +1056 eggs +1056 egg +1056 nest +1057 tride +1058 vase +1058 ming +1058 shard +1058 potte +1059 emera +1060 plati +1060 pyram +1061 pearl +1062 rug +1062 persi +1063 spice +1064 chain +2001 carry +2001 take +2001 keep +2001 catch +2001 steal +2001 captu +2001 get +2001 tote +2002 drop +2002 relea +2002 free +2002 disca +2002 dump +2003 say +2003 chant +2003 sing +2003 utter +2003 mumbl +2004 unloc +2004 open +2005 nothi +2006 lock +2006 close +2007 light +2007 on +2008 extin +2008 off +2009 wave +2009 shake +2009 swing +2010 calm +2010 placa +2010 tame +2011 walk +2011 run +2011 trave +2011 go +2011 proce +2011 conti +2011 explo +2011 goto +2011 follo +2011 turn +2012 attac +2012 kill +2012 slay +2012 fight +2012 hit +2012 strik +2013 pour +2014 eat +2014 devou +2015 drink +2016 rub +2017 throw +2017 toss +2018 quit +2019 find +2019 where +2020 inven +2021 feed +2022 fill +2023 blast +2023 deton +2023 ignit +2023 blowu +2024 score +2025 fee +2025 fie +2025 foe +2025 foo +2025 fum +2026 brief +2027 read +2027 perus +2028 break +2028 shatt +2028 smash +2029 wake +2029 distu +2030 suspe +2030 pause +2030 save +2031 hours +3001 fee +3002 fie +3003 foe +3004 foo +3005 fum +3050 sesam +3050 opens +3050 abra +3050 abrac +3050 shaza +3050 hocus +3050 pocus +3051 help +3051 ? +3064 tree +3064 trees +3066 dig +3066 excav +3068 lost +3069 mist +3079 fuck +3139 stop +3142 info +3142 infor +3147 swim +-1 +5 +1 Set of keys +000 There are some keys on the ground here. +2 Brass lantern +000 There is a shiny brass lamp nearby. +100 There is a lamp shining nearby. +3 *Grate +000 The grate is locked. +100 The grate is open. +4 Wicker cage +000 There is a small wicker cage discarded nearby. +5 Black rod +000 A three foot black rod with a rusty star on an end lies nearby. +6 Black rod +000 A three foot black rod with a rusty mark on an end lies nearby. +7 *Steps +000 Rough stone steps lead down the pit. +100 Rough stone steps lead up the dome. +8 Little bird in cage +000 A cheerful little bird is sitting here singing. +100 There is a little bird in the cage. +9 *Rusty door +000 The way north is barred by a massive, rusty, iron door. +100 The way north leads through a massive, rusty, iron door. +10 Velvet pillow +000 A small velvet pillow lies on the floor. +11 *Snake +000 A huge green fierce snake bars the way! +100 >$< (Chased away) +12 *Fissure +000 >$< +100 A crystal bridge now spans the fissure. +200 The crystal bridge has vanished! +13 *Stone tablet +000 A massive stone tablet imbedded in the wall reads: +000 "Congratulations on bringing light into the dark-room!" +14 Giant clam >grunt!< +000 There is an enormous clam here with its shell tightly closed. +15 Giant oyster >groan!< +000 There is an enormous oyster here with its shell tightly closed. +100 Interesting. There seems to be something written on the underside of +100 The oyster. +16 "Spelunker today" +000 There are a few recent issues of "Spelunker today" magazine here. +19 Tasty food +000 There is food here. +20 Small bottle +000 There is a bottle of water here. +100 There is an empty bottle here. +200 There is a bottle of oil here. +21 Water in the bottle +22 Oil in the bottle +23 *Mirror +000 >$< +24 *Plant +000 There is a tiny little plant in the pit, murmuring "water, water, ..." +100 The plant spurts into furious growth for a few seconds. +200 There is a 12-foot-tall beanstalk stretching up out of the pit, +200 Bellowing "water!! water!!" +300 The plant grows explosively, almost filling the bottom of the pit. +400 There is a gigantic beanstalk stretching all the way up to the hole. +500 You've over-watered the plant! It's shriveling up! It's, it's... +25 *Phony plant (seen in twopit room only when tall enough) +000 >$< +100 The top of a 12-foot-tall beanstalk is poking out of the west pit. +200 There is a huge beanstalk growing out of the west pit up to the hole. +26 *Stalactite +000 >$< +27 *Shadowy figure +000 The shadowy figure seems to be trying to attract your attention. +28 Dwarf's axe +000 There is a little axe here. +100 There is a little axe lying beside the bear. +29 *Cave drawings +000 >$< +30 *Pirate +000 >$< +31 *Dragon +000 A huge green fierce dragon bars the way! +100 Congratulations! You have just vanquished a dragon with your bare +100 Hands! (unbelievable, isn't it?) +200 The body of a huge green dead dragon is lying off to one side. +32 *Chasm +000 A rickety wooden bridge extends across the chasm, vanishing into the +000 Mist. A sign posted on the bridge reads, "stop! pay troll!" +100 The wreckage of a bridge (and a dead bear) can be seen at the bottom +100 Of the chasm. +33 *Troll +000 A burly troll stands by the bridge and insists you throw him a +000 Treasure before you may cross. +100 The troll steps out from beneath the bridge and blocks your way. +200 >$< (Chased away) +34 *Phony troll +000 The troll is nowhere to be seen. +35 >$< (Bear uses rtext 141) +000 There is a ferocious cave bear eying you from the far end of the room! +100 There is a gentle cave bear sitting placidly in one corner. +200 There is a contented-looking bear wandering about nearby. +300 >$< (Dead) +36 *Message in second maze +000 There is a message scrawled in the dust in a flowery script, reading: +000 "This is not the maze where the pirate leaves his treasure chest." +37 *Volcano and/or geyser +000 >$< +38 *Vending machine +000 There is a massive vending machine here. The instructions on it read: +000 "Drop coins here to receive fresh batteries." +39 Batteries +000 There are fresh batteries here. +100 Some worn-out batteries have been discarded nearby. +40 *Carpet and/or moss +000 >$< +50 Large gold nugget +000 There is a large sparkling nugget of gold here! +51 Several diamonds +000 There are diamonds here! +52 Bars of silver +000 There are bars of silver here! +53 Precious jewelry +000 There is precious jewelry here! +54 Rare coins +000 There are many coins here! +55 Treasure chest +000 The pirate's treasure chest is here! +56 Golden eggs +000 There is a large nest here, full of golden eggs! +100 The nest of golden eggs has vanished! +200 Done! +57 Jeweled trident +000 There is a jewel-encrusted trident here! +58 Ming vase +000 There is a delicate, precious, ming vase here! +100 The vase is now resting, delicately, on a velvet pillow. +200 The floor is littered with worthless shards of pottery. +300 The ming vase drops with a delicate crash. +59 Egg-sized emerald +000 There is an emerald here the size of a plover's egg! +60 Platinum pyramid +000 There is a platinum pyramid here, 8 inches on a side! +61 Glistening pearl +000 Off to one side lies a glistening pearl! +62 Persian rug +000 There is a persian rug spread out on the floor! +100 The dragon is sprawled out on a persian rug!! +63 Rare spices +000 There are rare spices here! +64 Golden chain +000 There is a golden chain lying in a heap on the floor! +100 The bear is locked to the wall with a golden chain! +200 There is a golden chain locked to the wall! +-1 +6 +1 Somewhere nearby is colossal cave, where others have found fortunes in +1 treasure and gold, though it is rumored that some who enter are never +1 seen again. Magic is said to work in the cave. I will be your eyes +1 and hands. Direct me with commands of 1 or 2 words. I should warn +1 you that I look at only the first five letters of each word, so you'll +1 have to enter "northeast" as "ne" to distinguish it from "north". +1 (Should you get stuck, type "help" for some general hints. For infor- +1 mation on how to end your adventure, etc., type "info".) +1 - - - +1 This program was originally developed by Willie Crowther. Most of the +1 features of the current program were added by Don Woods (don @ su-ai). +1 Contact Don if you have any questions, comments, etc. +1 Address complaints about the Unix version to jim @ rand-unix. +2 A little dwarf with a big knife blocks your way. +3 A little dwarf just walked around a corner, saw you, threw a little +3 axe at you which missed, cursed, and ran away. +4 There is a threatening little dwarf in the room with you! +5 One sharp nasty knife is thrown at you! +6 None of them hit you! +7 One of them gets you! +8 A hollow voice says "plugh". +9 There is no way to go that direction. +10 I am unsure how you are facing. Use compass points or nearby objects. +11 I don't know in from out here. Use compass points or name something +11 in the general direction you want to go. +12 I don't know how to apply that word here. +13 I don't understand that! +14 I'm game. Would you care to explain how? +15 Sorry, but I am not allowed to give more detail. I will repeat the +15 long description of your location. +16 It is now pitch dark. If you proceed you will likely fall into a pit. +17 If you prefer, simply type w rather than west. +18 Are you trying to catch the bird? +19 The bird is frightened right now and you cannot catch it no matter +19 what you try. Perhaps you might try later. +20 Are you trying to somehow deal with the snake? +21 You can't kill the snake, or drive it away, or avoid it, or anything +21 like that. There is a way to get by, but you don't have the necessary +21 resources right now. +22 Do you really want to quit now? +23 You fell into a pit and broke every bone in your body! +24 You are already carrying it! +25 You can't be serious! +26 The bird was unafraid when you entered, but as you approach it becomes +26 disturbed and you cannot catch it. +27 You can catch the bird, but you cannot carry it. +28 There is nothing here with a lock! +29 You aren't carrying it! +30 The little bird attacks the green snake, and in an astounding flurry +30 drives the snake away. +31 You have no keys! +32 It has no lock. +33 I don't know how to lock or unlock such a thing. +34 It was already locked. +35 The grate is now locked. +36 The grate is now unlocked. +37 It was already unlocked. +38 You have no source of light. +39 Your lamp is now on. +40 Your lamp is now off. +41 There is no way to get past the bear to unlock the chain, which is +41 probably just as well. +42 Nothing happens. +43 Where? +44 There is nothing here to attack. +45 The little bird is now dead. Its body disappears. +46 Attacking the snake both doesn't work and is very dangerous. +47 You killed a little dwarf. +48 You attack a little dwarf, but he dodges out of the way. +49 With what? Your bare hands? +50 Good try, but that is an old worn-out magic word. +51 I know of places, actions, and things. Most of my vocabulary +51 describes places and is used to move you there. To move, try words +51 like forest, building, downstream, enter, east, west, north, south, +51 up, or down. I know about a few special objects, like a black rod +51 hidden in the cave. These objects can be manipulated using some of +51 the action words that I know. Usually you will need to give both the +51 object and action words (in either order), but sometimes I can infer +51 the object from the verb alone. Some objects also imply verbs; in +51 particular, "inventory" implies "take inventory", which causes me to +51 give you a list of what you're carrying. The objects have side +51 effects; for instance, the rod scares the bird. Usually people having +51 trouble moving just need to try a few more words. Usually people +51 trying unsuccessfully to manipulate an object are attempting something +51 beyond their (or my!) capabilities and should try a completely +51 different tack. To speed the game you can sometimes move long +51 distances with a single word. For example, "building" usually gets +51 you to the building from anywhere above ground except when lost in the +51 forest. Also, note that cave passages turn a lot, and that leaving a +51 room to the north does not guarantee entering the next from the south. +51 Good luck! +52 It misses! +53 It gets you! +54 OK +55 You can't unlock the keys. +56 You have crawled around in some little holes and wound up back in the +56 main passage. +57 I don't know where the cave is, but hereabouts no stream can run on +57 the surface for long. I would try the stream. +58 I need more detailed instructions to do that. +59 I can only tell you what you see as you move about and manipulate +59 things. I cannot tell you where remote things are. +60 I don't know that word. +61 What? +62 Are you trying to get into the cave? +63 The grate is very solid and has a hardened steel lock. You cannot +63 enter without a key, and there are no keys nearby. I would recommend +63 looking elsewhere for the keys. +64 The trees of the forest are large hardwood oak and maple, with an +64 occasional grove of pine or spruce. There is quite a bit of under- +64 growth, largely birch and ash saplings plus nondescript bushes of +64 various sorts. This time of year visibility is quite restricted by +64 all the leaves, but travel is quite easy if you detour around the +64 spruce and berry bushes. +65 Welcome to adventure!! Would you like instructions? +66 Digging without a shovel is quite impractical. Even with a shovel +66 progress is unlikely. +67 Blasting requires dynamite. +68 I'm as confused as you are. +69 Mist is a white vapor, usually water, seen from time to time in +69 caverns. It can be found anywhere but is frequently a sign of a deep +69 pit leading down to water. +70 Your feet are now wet. +71 I think I just lost my appetite. +72 Thank you, it was delicious! +73 You have taken a drink from the stream. The water tastes strongly of +73 minerals, but is not unpleasant. It is extremely cold. +74 The bottle of water is now empty. +75 Rubbing the electric lamp is not particularly rewarding. Anyway, +75 nothing exciting happens. +76 Peculiar. Nothing unexpected happens. +77 Your bottle is empty and the ground is wet. +78 You can't pour that. +79 Watch it! +80 Which way? +81 Oh dear, you seem to have gotten yourself killed. I might be able to +81 help you out, but i've never really done this before. Do you want me +81 to try to reincarnate you? +82 All right. But don't blame me if something goes wr...... +82 --- Poof!! --- +82 You are engulfed in a cloud of orange smoke. Coughing and gasping, +82 you emerge from the smoke and find.... +83 You clumsy oaf, you've done it again! I don't know how long I can +83 keep this up. Do you want me to try reincarnating you again? +84 Okay, now where did I put my orange smoke?.... >poof!< +84 Everything disappears in a dense cloud of orange smoke. +85 Now you've really done it! I'm out of orange smoke! You don't expect +85 me to do a decent reincarnation without any orange smoke, do you? +86 Okay, if you're so smart, do it yourself! I'm leaving! +90 >>> Messages 81 thru 90 are reserved for "obituaries". <<< +91 Sorry, but I no longer seem to remember how it was you got here. +92 You can't carry anything more. You'll have to drop something first. +93 You can't go through a locked steel grate! +94 I believe what you want is right here with you. +95 You don't fit through a two-inch slit! +96 I respectfully suggest you go across the bridge instead of jumping. +97 There is no way across the fissure. +98 You're not carrying anything. +99 You are currently holding the following: +100 It's not hungry (it's merely pinin' for the fjords). Besides, you +100 have no bird seed. +101 The snake has now devoured your bird. +102 There's nothing here it wants to eat (except perhaps you). +103 You fool, dwarves eat only coal! Now you've made him *really* mad!! +104 You have nothing in which to carry it. +105 Your bottle is already full. +106 There is nothing here with which to fill the bottle. +107 Your bottle is now full of water. +108 Your bottle is now full of oil. +109 You can't fill that. +110 Don't be ridiculous! +111 The door is extremely rusty and refuses to open. +112 The plant indignantly shakes the oil off its leaves and asks, "water?" +113 The hinges are quite thoroughly rusted now and won't budge. +114 The oil has freed up the hinges so that the door will now move, +114 although it requires some effort. +115 The plant has exceptionally deep roots and cannot be pulled free. +116 The dwarves' knives vanish as they strike the walls of the cave. +117 Something you're carrying won't fit through the tunnel with you. +117 You'd best take inventory and drop something. +118 You can't fit this five-foot clam through that little passage! +119 You can't fit this five-foot oyster through that little passage! +120 I advise you to put down the clam before opening it. >strain!< +121 I advise you to put down the oyster before opening it. >wrench!< +122 You don't have anything strong enough to open the clam. +123 You don't have anything strong enough to open the oyster. +124 A glistening pearl falls out of the clam and rolls away. Goodness, +124 this must really be an oyster. (I never was very good at identifying +124 bivalves.) Whatever it is, it has now snapped shut again. +125 The oyster creaks open, revealing nothing but oyster inside. It +125 promptly snaps shut again. +126 You have crawled around in some little holes and found your way +126 blocked by a recent cave-in. You are now back in the main passage. +127 There are faint rustling noises from the darkness behind you. +128 Out from the shadows behind you pounces a bearded pirate! "Har, har," +128 he chortles, "I'll just take all this booty and hide it away with me +128 chest deep in the maze!" He snatches your treasure and vanishes into +128 the gloom. +129 A sepulchral voice reverberating through the cave, says, "Cave closing +129 soon. All adventurers exit immediately through main office." +130 A mysterious recorded voice groans into life and announces: +130 "This exit is closed. Please leave via main office." +131 It looks as though you're dead. Well, seeing as how it's so close to +131 closing time anyway, I think we'll just call it a day. +132 The sepulchral voice entones, "The cave is now closed." As the echoes +132 fade, there is a blinding flash of light (and a small puff of orange +132 Smoke). . . . As your eyes refocus, you look around and find... +133 there is a loud explosion, and a twenty-foot hole appears in the far +133 wall, burying the dwarves in the rubble. You march through the hole +133 and find yourself in the main office, where a cheering band of +133 friendly elves carry the conquering adventurer off into the sunset. +134 There is a loud explosion, and a twenty-foot hole appears in the far +134 wall, burying the snakes in the rubble. A river of molten lava pours +134 in through the hole, destroying everything in its path, including you! +135 There is a loud explosion, and you are suddenly splashed across the +135 walls of the room. +136 The resulting ruckus has awakened the dwarves. There are now several +136 threatening little dwarves in the room with you! Most of them throw +136 knives at you! All of them get you! +137 Oh, leave the poor unhappy bird alone. +138 I daresay whatever you want is around here somewhere. +139 I don't know the word "stop". Use "quit" if you want to give up. +140 You can't get there from here. +141 You are being followed by a very large, tame bear. +142 If you want to end your adventure early, say "quit". To suspend your +142 adventure such that you can continue later, say "suspend" (or "pause" +142 Or "save"). To see what hours the cave is normally open, say "hours". +142 To see how well you're doing, say "score". To get full credit for a +142 treasure, you must have left it safely in the building, though you get +142 partial credit just for locating it. You lose points for getting +142 killed, or for quitting, though the former costs you more. There are +142 also points based on how much (if any) of the cave you've managed to +142 explore; in particular, there is a large bonus just for getting in (to +142 distinguish the beginners from the rest of the pack), and there are +142 other ways to determine whether you've been through some of the more +142 harrowing sections. If you think you've found all the treasures, just +142 keep exploring for a while. If nothing interesting happens, you +142 haven't found them all yet. If something interesting *does* happen, +142 it means you're getting a bonus and have an opportunity to garner many +142 more points in the master's section. I may occasionally offer hints +142 if you seem to be having trouble. If I do, I'll warn you in advance +142 how much it will affect your score to accept the hints. Finally, to +142 save paper, you may specify "brief", which tells me never to repeat +142 the full description of a place unless you explicitly ask me to. +143 Do you indeed wish to quit now? +144 There is nothing here with which to fill the vase. +145 The sudden change in temperature has delicately shattered the vase. +146 It is beyond your power to do that. +147 I don't know how. +148 It is too far up for you to reach. +149 You killed a little dwarf. The body vanishes in a cloud of greasy +149 black smoke. +150 The shell is very strong and is impervious to attack. +151 What's the matter, can't you read? Now you'd best start over. +152 The axe bounces harmlessly off the dragon's thick scales. +153 The dragon looks rather nasty. You'd best not try to get by. +154 The little bird attacks the green dragon, and in an astounding flurry +154 gets burnt to a cinder. The ashes blow away. +155 On what? +156 Okay, from now on i'll only describe a place in full the first time +156 you come to it. To get the full description, say "look". +157 Trolls are close relatives with the rocks and have skin as tough as +157 that of a rhinoceros. The troll fends off your blows effortlessly. +158 The troll deftly catches the axe, examines it carefully, and tosses it +158 back, declaring, "good workmanship, but it's not valuable enough." +159 The troll catches your treasure and scurries away out of sight. +160 The troll refuses to let you cross. +161 There is no longer any way across the chasm. +162 Just as you reach the other side, the bridge buckles beneath the +162 weight of the bear, which was still following you around. You +162 scrabble desperately for support, but as the bridge collapses you +162 stumble back and fall into the chasm. +163 The bear lumbers toward the troll, who lets out a startled shriek and +163 scurries away. The bear soon gives up the pursuit and wanders back. +164 The axe misses and lands near the bear where you can't get at it. +165 With what? Your bare hands? Against *his* bear hands?? +166 The bear is confused; he only wants to be your friend. +167 For crying out loud, the poor thing is already dead! +168 The bear eagerly wolfs down your food, after which he seems to calm +168 Down considerably and even becomes rather friendly. +169 The bear is still chained to the wall. +170 The chain is still locked. +171 The chain is now unlocked. +172 The chain is now locked. +173 There is nothing here to which the chain can be locked. +174 There is nothing here to eat. +175 Do you want the hint? +176 Do you need help getting out of the maze? +177 You can make the passages look less alike by dropping things. +178 Are you trying to explore beyond the plover room? +179 There is a way to explore that region without having to worry about +179 falling into a pit. None of the objects available is immediately +179 useful in discovering the secret. +180 Do you need help getting out of here? +181 Don't go west. +182 Gluttony is not one of the troll's vices. Avarice, however, is. +183 Your lamp is getting dim. You'd best start wrapping this up, unless +183 You can find some fresh batteries. I seem to recall there's a vending +183 machine in the maze. Bring some coins with you. +184 Your lamp has run out of power. +185 There's not much point in wandering around out here, and you can't +185 explore the cave without a lamp. So let's just call it a day. +186 There are faint rustling noises from the darkness behind you. As you +186 turn toward them, the beam of your lamp falls across a bearded pirate. +186 He is carrying a large chest. "Shiver me timbers!" he cries, "I've +186 been spotted! I'd best hie meself off to the maze to hide me chest!" +186 With that, he vanishes into the gloom. +187 Your lamp is getting dim. You'd best go back for those batteries. +188 Your lamp is getting dim. I'm taking the liberty of replacing the +188 batteries. +189 Your lamp is getting dim, and you're out of spare batteries. You'd +189 best start wrapping this up. +190 I'm afraid the magazine is written in dwarvish. +191 "This is not the maze where the pirate leaves his treasure chest." +192 Hmmm, this looks like a clue, which means it'll cost you 10 points to +192 read it. Should I go ahead and read it anyway? +193 It says, "there is something strange about this place, such that one +193 Of the words i've always known now has a new effect." +194 It says the same thing it did before. +195 I'm afraid I don't understand. +196 "Congratulations on bringing light into the dark-room!" +197 You strike the mirror a resounding blow, whereupon it shatters into a +197 myriad tiny fragments. +198 You have taken the vase and hurled it delicately to the ground. +199 You prod the nearest dwarf, who wakes up grumpily, takes one look at +199 you, curses, and grabs for his axe. +200 Is this acceptable? +201 There's no point in suspending a demonstration game. +-1 +7 +1 3 +2 3 +3 8 9 +4 10 +5 11 +6 0 +7 14 15 +8 13 +9 94 -1 +10 96 +11 19 -1 +12 17 27 +13 101 -1 +14 103 +15 0 +16 106 +17 0 -1 +18 0 +19 3 +20 3 +21 0 +22 0 +23 109 -1 +24 25 -1 +25 23 67 +26 111 -1 +27 35 110 +28 0 +29 97 -1 +30 0 -1 +31 119 121 +32 117 122 +33 117 122 +34 0 0 +35 130 -1 +36 0 -1 +37 126 -1 +38 140 -1 +39 0 +40 96 -1 +50 18 +51 27 +52 28 +53 29 +54 30 +55 0 +56 92 +57 95 +58 97 +59 100 +60 101 +61 0 +62 119 121 +63 127 +64 130 -1 +-1 +8 +1 24 +2 29 +3 0 +4 33 +5 0 +6 33 +7 38 +8 38 +9 42 +10 14 +11 43 +12 110 +13 29 +14 110 +15 73 +16 75 +17 29 +18 13 +19 59 +20 59 +21 174 +22 109 +23 67 +24 13 +25 147 +26 155 +27 195 +28 146 +29 110 +30 13 +31 13 +-1 +9 +0 1 2 3 4 5 6 7 8 9 10 +0 100 115 116 126 +2 1 3 4 7 38 95 113 24 +1 24 +3 46 47 48 54 56 58 82 85 86 +3 122 123 124 125 126 127 128 129 130 +4 8 +5 13 +6 19 +7 42 43 44 45 46 47 48 49 50 51 +7 52 53 54 55 56 80 81 82 86 87 +8 99 100 101 +9 108 +-1 +10 +35 You are obviously a rank amateur. Better luck next time. +100 Your score qualifies you as a novice class adventurer. +130 You have achieved the rating: "experienced adventurer". +200 You may now consider yourself a "seasoned adventurer". +250 You have reached "junior master" status. +300 Your score puts you in master adventurer class c. +330 Your score puts you in master adventurer class b. +349 Your score puts you in master adventurer class a. +9999 All of adventuredom gives tribute to you, adventurer grandmaster! +-1 +11 +2 9999 10 0 0 +3 9999 5 0 0 +4 4 2 62 63 +5 5 2 18 19 +6 8 2 20 21 +7 75 4 176 177 +8 25 5 178 179 +9 20 3 180 181 +-1 +12 +1 A large cloud of green smoke appears in front of you. It clears away +1 to reveal a tall wizard, clothed in grey. He fixes you with a steely +1 glare and declares, "this adventure has lasted too long." With that +1 he makes a single pass over you with his hands, and everything around +1 You fades away into a grey nothingness. +2 Even wizards have to wait longer than that! +3 I'm terribly sorry, but colossal cave is closed. Our hours are: +4 Only wizards are permitted within the cave right now. +5 We do allow visitors to make short explorations during our off hours. +5 Would you like to do that? +6 Colossal cave is open to regular adventurers at the following hours: +7 Very well. +8 Only a wizard may continue an adventure this soon. +9 I suggest you resume your adventure at a later time. +10 Do you wish to see the hours? +11 Do you wish to change the hours? +12 New magic word (null to leave unchanged): +13 New magic number (null to leave unchanged): +14 Do you wish to change the message of the day? +15 Okay. You can save this version now. +16 Are you a wizard? +17 Prove it! Say the magic word! +18 That is not what I thought it was. Do you know what I thought it was? +19 Oh dear, you really *are* a wizard! Sorry to have bothered you . . . +20 Foo, you are nothing but a charlatan! +21 New hours specified by defining "prime time". Give only the hour +21 (E.g. 14, not 14:00 or 2pm). Enter a negative number after last pair. +22 New hours for colossal cave: +23 Limit lines to 70 chars. End with null line. +24 Line too long, retype: +25 Not enough room for another line. Ending message here. +26 Do you wish to (re)schedule the next holiday? +27 To begin how many days from today? +28 To last how many days (zero if no holiday)? +29 To be called what (up to 20 characters)? +30 Too small! Assuming minimum value (45 minutes). +31 Break out of this and save your core-image. +32 Be sure to save your core-image... +-1 +0 + glorkz 4.1 82/05/11 diff --git a/src/games/adventure/glorkz-ru b/src/games/adventure/glorkz-ru new file mode 100644 index 0000000..545b7c3 --- /dev/null +++ b/src/games/adventure/glorkz-ru @@ -0,0 +1,1815 @@ +1 +1 Ð’Ñ‹ Ñтоите у конца дороги перед небольшим кирпичным домом. Вокруг Ð²Ð°Ñ +1 леÑ. Ðебольшой ручей вытекает из дома и течет по оврагу. +2 Ð’Ñ‹ взошли на холм, вÑе еще находÑÑÑŒ в леÑу. Дорога идет вниз на +2 другой Ñтороне холма. Вдалеке виден дом. +3 Ð’Ñ‹ внутри дома. Хороший дом Ð´Ð»Ñ Ð±Ð¾Ð»ÑŒÑˆÐ¾Ð³Ð¾ родника. +4 Ð’Ñ‹ в леÑной долине у ручьÑ, текущего по камениÑтому ложу. +5 Ð’Ñ‹ в Ñплошном леÑу. По одну Ñторону Ð³Ð»ÑƒÐ±Ð¾ÐºÐ°Ñ Ð´Ð¾Ð»Ð¸Ð½Ð°. +6 Ð’Ñ‹ в Ñплошном леÑу недалеко от долины и дороги. +7 У ваших ног вÑÑ Ð²Ð¾Ð´Ð° Ñ€ÑƒÑ‡ÑŒÑ Ñтекает в пÑтиÑантиметровую щель в Ñкале. +7 Вниз по течению дно Ñ€ÑƒÑ‡ÑŒÑ ÐºÐ°Ð¼ÐµÐ½Ð¸Ñтое. +8 Ð’Ñ‹ 6-ти метровой впадине Ñ Ð¸Ð»Ð¸Ñтым дном. Ð’ ней находитÑÑ ÐºÑ€ÐµÐ¿ÐºÐ°Ñ +8 ÑÑ‚Ð°Ð»ÑŒÐ½Ð°Ñ Ñ€ÐµÑˆÐµÑ‚ÐºÐ°, Ð²Ð¼Ð¾Ð½Ñ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð½Ð°Ñ Ð² бетон. Сухое руÑло Ñ€ÑƒÑ‡ÑŒÑ Ð²ÐµÐ´ÐµÑ‚ во +8 впадину. +9 Ð’Ñ‹ в небольшой камере за Ñтальной решеткой. Ðизкий лаз, полный +9 булыжников, ведет внутрь на запад. +10 Ð’Ñ‹ ползете по булыжникам в низком проходе. Ð’ воÑточном конце прохода +10 виден туÑклый Ñвет. +11 Ð’Ñ‹ в гроте обломков, заполненном почвой, Ñмытой Ñ Ð¿Ð¾Ð²ÐµÑ€Ñ…Ð½Ð¾Ñти. Ðизкий +11 широкий проход Ñ Ð±ÑƒÐ»Ñ‹Ð¶Ð½Ð¸ÐºÐ°Ð¼Ð¸ ÑтановитÑÑ Ð½ÐµÐ¿Ñ€Ð¾Ñ…Ð¾Ð´Ð¸Ð¼Ñ‹Ð¼ из-за грÑзи и +11 камней, но опаÑный каньон ведет отÑюда вверх и на воÑток. ÐадпиÑÑŒ на +11 Ñтене глаÑит: +11 "МÐГИЧЕСКОЕ СЛОВО ÐБРÐ". +11 +12 Ð’Ñ‹ в опаÑном наклонном каньоне, идущем Ñ Ð²Ð¾Ñтока на запад. +13 Ð’Ñ‹ в великолепной камере 10-ти метровой выÑоты. Ðа ee Ñтенах как бы +13 замерзшие потоки из оранжевого камнÑ. ОпаÑный каньон и широкий проход +13 выходÑÑ‚ Ñ Ð²Ð¾Ñточной и западной Ñтороны камеры. +14 У ваших ног Ð½ÐµÐ±Ð¾Ð»ÑŒÑˆÐ°Ñ Ñма, из нее поднимаютÑÑ ÐºÐ»ÑƒÐ±Ñ‹ белого тумана. +14 Путь на запад здеÑÑŒ кончаетÑÑ, еÑли не Ñчитать небольшую трещину. +15 Ð’Ñ‹ в конце громадного зала, проÑтирающегоÑÑ Ð²Ð¿ÐµÑ€ÐµÐ´ на запад +15 наÑколько можно видеть. Во вÑе Ñтороны еÑть проходы. ПоблизоÑти +15 ÑˆÐ¸Ñ€Ð¾ÐºÐ°Ñ ÐºÐ°Ð¼ÐµÐ½Ð½Ð°Ñ Ð»ÐµÑтница ведет вниз. Зал заполнен клубами белого +15 тумана, которые двигаютÑÑ ÐºÐ°Ðº живые. С леÑтницы дует холодный +15 ветер. Ð’ верхней точке купола позади Ð²Ð°Ñ ÐµÑть проход. Грубые +15 каменные Ñтупени ведут наверх к куполу. +16 Трещина Ñлишком узкаÑ, дальше пройти не удаётÑÑ. +17 Ð’Ñ‹ на воÑточной Ñтороне пропаÑти, переÑекающей зал. Туман здеÑÑŒ очень +17 гуÑтой, a пропаÑть Ñлишком широка, чтобы ee можно было перепрыгнуть. +18 ЗдеÑÑŒ низкий грот Ñ Ð³Ñ€ÑƒÐ±Ð¾Ð¹ надпиÑью на Ñтене. Она глаÑит: +18 +18 "ВЫ ÐЕ ПОДÐИМЕТЕСЬ ПО СТУПЕÐЬКÐМ" +18 +19 Ð’Ñ‹ в зале горного королÑ. Выходы идут по вÑем направлениÑм. +20 You are at the bottom of the pit with a broken neck. +21 You didn't make it. +22 The dome is unclimbable. +23 Ð’Ñ‹ в западной чаÑти грота Ñ Ð´Ð²ÑƒÐ¼Ñ Ñмами. Ð’ Ñтой чаÑти грота над Ñмой +23 еÑть Ð±Ð¾Ð»ÑŒÑˆÐ°Ñ Ð´Ñ‹Ñ€Ð° в потолке. +24 Ð’Ñ‹ на дне воÑточной Ñмы в гроте Ñ Ð´Ð²ÑƒÐ¼Ñ Ñмами. Ð’ Ñтой Ñме еÑть +24 Ð½ÐµÐ±Ð¾Ð»ÑŒÑˆÐ°Ñ Ð»ÑƒÐ¶Ð° маÑла. +25 Ð’Ñ‹ на дне западной Ñмы в гроте Ñ Ð´Ð²ÑƒÐ¼Ñ Ñмами. над вами в потолке +25 большое отверÑтие. +26 You clamber up the plant and scurry through the hole at the top. +27 Ð’Ñ‹ на западной Ñтороне пропаÑти в зале туманов. +28 Ð’Ñ‹ в низком Ñ/ÑŽ проходе у дыры, ведущей вниз в в/з проход. +29 Ð’Ñ‹ в южной боковой камере зала горного королÑ. +30 Ð’Ñ‹ в западной боковой камере зала горного королÑ. Проход здеÑÑŒ +30 продолжаетÑÑ Ð½Ð° запад и вверх. +31 >$< +32 You can't get by the snake. +33 Ð’Ñ‹ в большом гроте Ñ Ð¿Ñ€Ð¾Ñ…Ð¾Ð´Ð°Ð¼Ð¸ на юг, на запад и Ñтеной из +33 разрушенных Ñкал на воÑтоке. на Ñкале в центре зала надпиÑÑŒ: +33 +33 "Y2" +33 +34 ЗдеÑÑŒ нагромождение Ñкал, везде трещины. +35 Ð’Ñ‹ Ñтоите у низкого окна, выходÑщего в огромный колодец, верхнего +35 ÐºÑ€Ð°Ñ ÐºÐ¾Ñ‚Ð¾Ñ€Ð¾Ð³Ð¾ не видно. Дно неÑÑно виднеетÑÑ 15-ÑŽ метрами ниже. +35 ÐšÐ»Ð¾Ñ‡ÑŒÑ Ð±ÐµÐ»Ð¾Ð³Ð¾ тумана покрывают дно колодца. Следы на пыли у окна +35 показывают, что недавно здеÑÑŒ уже кто-то был. ПрÑмо напротив вашего +35 окна на раÑÑтоÑнии 8-ми метров видно похожее окно, выходÑщее из +35 оÑвещенного грота. Ð’ нем угадываетÑÑ Ñ‚ÐµÐ¼Ð½Ð°Ñ Ñ„Ð¸Ð³ÑƒÑ€Ð°, котораÑ, кажетÑÑ, +35 Ñмотрит на ваÑ. +36 Ð’Ñ‹ в грÑзном извилиÑтом проходе. Ðа воÑток еÑть лаз, на запад ведет +36 большой проход. Ðад вами находитÑÑ Ð´Ñ‹Ñ€Ð° в другой проход. +37 Ð’Ñ‹ на краю небольшой чиÑтой Ñмы, в которую можно залезть. Ðа запад +37 ведет лаз. +38 Ð’Ñ‹ на дне небольшой Ñмы Ñ Ð¼Ð°Ð»ÐµÐ½ÑŒÐºÐ¸Ð¼ ручьем, который втекает и +38 вытекает через крошечные щели. +39 Ð’Ñ‹ в большом гроте, полном пыльных Ñкал. Ð’ полу Ð±Ð¾Ð»ÑŒÑˆÐ°Ñ Ð´Ñ‹Ñ€Ð°. Кругом +39 много трещин. Проход отÑюда ведет на воÑток. +40 You have crawled through a very low wide passage parallel to and north +40 of the hall of mists. +41 Ð’Ñ‹ в западной чаÑти зала туманов. Ðизкий широкий лаз продолжаетÑÑ Ð½Ð° +41 запад, другой идет на Ñевер. К югу еÑть небольшой проход в 2-Ñ… метрах +41 от пола. +42 Ð’Ñ‹ в лабиринте небольших извилиÑтых похожих друг на друга проходов. +43 Ð’Ñ‹ в лабиринте небольших извилиÑтых похожих друг на друга проходов. +44 Ð’Ñ‹ в лабиринте небольших извилиÑтых похожих друг на друга проходов. +45 Ð’Ñ‹ в лабиринте небольших извилиÑтых похожих друг на друга проходов. +46 ЗдеÑÑŒ тупик. +47 ЗдеÑÑŒ тупик. +48 ЗдеÑÑŒ тупик. +49 Ð’Ñ‹ в лабиринте небольших извилиÑтых похожих друг на друга проходов. +50 Ð’Ñ‹ в лабиринте небольших извилиÑтых похожих друг на друга проходов. +51 Ð’Ñ‹ в лабиринте небольших извилиÑтых похожих друг на друга проходов. +52 Ð’Ñ‹ в лабиринте небольших извилиÑтых похожих друг на друга проходов. +53 Ð’Ñ‹ в лабиринте небольших извилиÑтых похожих друг на друга проходов. +54 ЗдеÑÑŒ тупик. +55 Ð’Ñ‹ в лабиринте небольших извилиÑтых похожих друг на друга проходов. +56 ЗдеÑÑŒ тупик. +57 Ð’Ñ‹ на краю 10-ти метрового колодца Ñ Ð¼Ð°ÑÑивной оранжевой колонной c +57 одной Ñтороны. Ð’Ñ‹ Ñможете ÑпуÑтитьÑÑ Ð¾Ñ‚Ñюда, но не Ñможете взобратьÑÑ +57 обратно вверх. Лабиринт продолжаетÑÑ Ð¸ внизу. +58 ЗдеÑÑŒ тупик. +59 You have crawled through a very low wide passage parallel to and north +59 of the hall of mists. +60 Ð’Ñ‹ в воÑточной чаÑти очень длинного зала, по-видимому, без боковых +60 камер. Ðа воÑток вверх ведет низкий широкий лаз. ÐеÑколько Ñевернее +60 вниз ведет Ð¾Ð²Ð°Ð»ÑŒÐ½Ð°Ñ Ð¼ÐµÑ‚Ñ€Ð¾Ð²Ð°Ñ Ð´Ñ‹Ñ€Ð°. +61 Ð’Ñ‹ в западной чаÑти очень длинного беÑформенного зала. Этот зал +61 ÑоединÑетÑÑ Ñ ÑƒÐ·ÐºÐ¸Ð¼ Ñ/ÑŽ проходом. +62 Ð’Ñ‹ на переÑечении выÑокого Ñ/ÑŽ и низкого в/з проходов. +63 ЗдеÑÑŒ тупик. +64 Ð’Ñ‹ в Ñложном переÑечении проходов. Очень низкий лаз, идущий Ñ Ñеверa, +64 ÑоединÑетÑÑ Ñ Ð±Ð¾Ð»ÐµÐµ выÑоким воÑточным лазом и оба они образуют +64 проход, ведущий на запад, по которому можно уже идти. Ðад проходом +64 большой грот. Воздух здеÑÑŒ влажный. +65 Ð’Ñ‹ в путанице - длинном в/з проходе Ñ Ð¼Ð½Ð¾Ð¶ÐµÑтвом дыр повÑюду. Чтобы +65 выбратьÑÑ, попробуйте двигатьÑÑ Ð½Ð°ÑƒÐ³Ð°Ð´ на Ñевер, юг, воÑток, запад. +66 Ð’Ñ‹ в гроте, Ñтены которого напоминают швейцарÑкий Ñыр. Проходы ведут +66 на запад, воÑток, юв, Ñв и Ñз. ЧаÑть грота занÑта большим валуном. +67 Ð’Ñ‹ в воÑточной чаÑти грота Ñ Ð´Ð²ÑƒÐ¼Ñ Ñмами. Ðа полу в беÑпорÑдке лежат +67 плиты, что позволÑет легко ÑпуÑкатьÑÑ Ð² Ñмы. ÐžÐ±Ñ…Ð¾Ð´Ñ Ñмы, из грота +67 легко выйти на запад и воÑток. ПовÑюду много отверÑтий, но только +67 одно большое - в потолке прÑмо над западной Ñмой. Ð’ Ñто отверÑтие вы +67 не можете попаÑть. +68 Ð’Ñ‹ в большой низкой круглой камере, на полу которой лежит Ð¾Ð³Ñ€Ð¾Ð¼Ð½Ð°Ñ +68 плита, ÑвалившаÑÑÑ Ñ Ð¿Ð¾Ñ‚Ð¾Ð»ÐºÐ°. Раньше на воÑток и запад шли проходы, +68 но ÑÐµÐ¹Ñ‡Ð°Ñ Ð¾Ð½Ð¸ завалены валунами. Ðизкие маленькие проходы ведут на +68 Ñевер и юг. Южный проход быÑтро изгибаетÑÑ Ð²Ð¾ÐºÑ€ÑƒÐ³ валунов и ведет на +68 запад. +69 Ð’Ñ‹ в тайном Ñ/ÑŽ каньоне над большим гротом. +70 Ð’Ñ‹ в тайном Ñ/ÑŽ каньоне над проходом порÑдочного размера. +71 Ð’Ñ‹ в тайном каньоне у ÑÐ¾ÐµÐ´Ð¸Ð½ÐµÐ½Ð¸Ñ 3-Ñ… каньонов, ведущих на Ñевер, юг и +71 юв. Северный каньон имеет выÑоту, как два других вмеÑте взÑтых. +72 Ð’Ñ‹ в большом низком гроте. Лазы ведут на Ñевер, юв и юз. +73 ЗдеÑÑŒ лаз, заканчивающийÑÑ Ñ‚ÑƒÐ¿Ð¸ÐºÐ¾Ð¼. +74 Ð’Ñ‹ в тайном каньоне, который ведет на воÑток и запад. Он переÑекает +74 очень узкий каньон 5-ÑŽ метрами ниже. ЕÑли вы ÑпуÑтитеÑÑŒ вниз, то не +74 Ñможете поднÑтьÑÑ Ð¾Ð±Ñ€Ð°Ñ‚Ð½Ð¾. +75 Ð’Ñ‹ в широком меÑте очень узкого Ñ/ÑŽ каньона. +76 Каньон в Ñтом меÑте ÑтановитÑÑ Ñлишком узким. Дальше идти нельзÑ. +77 Ð’Ñ‹ в выÑоком в/з каньоне. Ðизкий узкий лаз ведет к Ñеверу и раÑширÑетÑÑ. +78 Каньон забит меÑÑой валунов - тупик. +79 The stream flows out through a pair of 1 foot diameter sewer pipes. +79 It would be advisable to use the exit. +80 Ð’Ñ‹ в лабиринте небольших извилиÑтых похожих друг на друга проходов. +81 ЗдеÑÑŒ тупик. +82 ЗдеÑÑŒ тупик. +83 Ð’Ñ‹ в лабиринте небольших извилиÑтых похожих друг на друга проходов. +84 Ð’Ñ‹ в лабиринте небольших извилиÑтых похожих друг на друга проходов. +85 ЗдеÑÑŒ тупик. +86 ЗдеÑÑŒ тупик. +87 Ð’Ñ‹ в лабиринте небольших извилиÑтых похожих друг на друга проходов. +88 Ð’Ñ‹ в длинном, узком коридоре, уходÑщем далеко на запад. Ð’ воÑточном +88 конце еÑть отверÑтие, в котором видна лиÑтва деревьев. +89 There is nothing here to climb. Use "up" or "out" to leave the pit. +90 You have climbed up the plant and out of the pit. +91 Ð’Ñ‹ на верху крутого Ñклона над большим гротом. ЗдеÑÑŒ можно Ñлезть, но +91 невозможно забратьÑÑ Ð¾Ð±Ñ€Ð°Ñ‚Ð½Ð¾. ИмеетÑÑ Ð¿Ñ€Ð¾Ñ…Ð¾Ð´ на Ñевер. +92 Ð’Ñ‹ в громадном гроте. Потолок так выÑок, что лампа не может его +92 оÑветить. Проходы ведут на воÑток, Ñевер и юг. Ðа западной Ñтене +92 нацарапана надпиÑÑŒ: +92 "ФЕК ФИК ФОК ФУК" +92 +93 Проход здеÑÑŒ закрыт недавним обвалом. +94 Ð’Ñ‹ на одной из Ñторон громадного Ñ/ÑŽ прохода. +95 Ð’Ñ‹ в большой каверне. ЗдеÑÑŒ ручей, вырываÑÑÑŒ из Ñкалы, падает +95 водопадом в маленькое озеро. Вода, Ð¾Ð±Ñ€Ð°Ð·ÑƒÑ Ð²Ð¾Ð´Ð¾Ð²Ð¾Ñ€Ð¾Ñ‚, вытекает через +95 отверÑтие в дне. ЕÑть проходы на юг и запад. +96 Ð’Ñ‹ в мÑгком гроте. Стены покрыты Ñ‚Ñжелыми занавеÑÑми, пол покрыт +96 ковром Ñ Ð´Ð»Ð¸Ð½Ð½Ñ‹Ð¼ ворÑом. Потолок Ð¾Ð±Ñ€Ð¾Ñ Ð¼Ñ…Ð¾Ð¼. +97 Ð’Ñ‹ в китайÑком гроте. Стены покрыты древними китайÑкими пещерными +97 риÑунками. Ðаклонный проход ведет к Ñеверу, другой проход ведет на +97 юв, низкий лаз ведет на запад. +98 Ð’Ñ‹ двигаетеÑÑŒ по широкому проходу на внешнем крае большой каверны. +98 Далеко внизу, через гуÑтой белый туман, Ñлышны Ñтранные шлепающие +98 звуки. Ток воздуха втÑгивает туман в раÑÑелину в потолке. Путь открыт +98 на запад и юг. +99 Ð’Ñ‹ в алькове. Ðебольшой Ñз проход, кажетÑÑ, вÑкоре раÑширÑетÑÑ. +99 Чрезвычайно узкий тоннель ведет на воÑток. ЗдеÑÑŒ, видимо, произошла +99 оÑадка пород. Ð’ конце Ñ‚Ð¾Ð½Ð½ÐµÐ»Ñ Ð²Ð¸Ð´ÐµÐ½ какой-то нееÑтеÑтвенный Ñвет. +100 Ð’Ñ‹ в маленькой камере, оÑвешенной таинÑтвенным зеленым Ñветом. Очень +100 узкий тоннель ведет на запад. Ðа Ñтене камеры нариÑован голубь. +100 Темный коридор ведет на Ñв. +101 Ð’Ñ‹ в темном гроте. ЗдеÑÑŒ только один выход - коридор, ведущий k югу. +102 Ð’Ñ‹ в зале Ñ Ð°Ñ€ÐºÐ°Ð¼Ð¸. Проход, выложенный кораллами когда-то продолжалÑÑ +102 вверх и на воÑток, но теперь забит обломками Ñкал. Воздух пахнет +102 морÑкой водой. +103 Ð’Ñ‹ в большом гроте, Ñложенном оÑадочными породами. Ðа полу и Ñтенах +103 здеÑÑŒ и там видны чаÑти раковин, выÑтупающие из камнÑ. Ðизкий проход +103 ведет вниз, a более крутой - вверх. Ðизкий лаз ведет на юг. +104 Ð’Ñ‹ в длинном наклонном коридоре. Стены покрыты оÑтрыми камнÑми. +105 Ð’Ñ‹ в каменном мешке примерно трех метров в диаметре. +106 Ð’Ñ‹ в приемной, ведущей к большому проходу на воÑток. Ðебольшие +106 проходы ведут на запад и вверх. Ðа Ñевер идет Ñильно петлÑющий +106 лаз. Видно, что здеÑÑŒ недавно копали. +106 Табличка, виÑÑÑ‰Ð°Ñ Ð² воздухе, глаÑит: +106 +106 "ПЕЩЕРРВ СОСТОЯÐИИ СТРОИТЕЛЬСТВÐ. ДВИГÐТЬСЯ ДÐЛЬШЕ ОПÐСÐО" +106 +107 Ð’Ñ‹ в лабиринте извилиÑтых небольших, непохожих друг на друга проходов. +108 Ð’Ñ‹ в безумном тупичке. Проходы ведут во вÑех направлениÑÑ…. Ðа полу +108 лежит груда побелевших человечеÑких коÑтей. +109 Ð’Ñ‹ в Ñ/ÑŽ каньоне шириной около 8 метров. Пол покрыт белым туманом, +109 проникающим Ñ Ñеверa. Стены поднимаютÑÑ Ð²Ð²ÐµÑ€Ñ…, Ð¿ÐµÑ€ÐµÑ…Ð¾Ð´Ñ Ð² колодец, +109 они видны еще по крайней мере в 30 метрах над вами. Ðад вами +109 находитÑÑ Ð¾Ð³Ñ€Ð¾Ð¼Ð½Ð¾Ðµ двухÑтороннее зеркало, подвешенное на невидимых +109 троÑах (Зеркало, очевидно, иÑпользуют карлики, которые, как вы +109 знаете, очень тщеÑлавны). Ðа Ñтенах колодца на выÑоте порÑдка 15 +109 метров против зеркала видны окна. +110 Ð’Ñ‹ Ñтоите у низкого окна, выходÑщего в огромный колодец, верхнего +110 ÐºÑ€Ð°Ñ ÐºÐ¾Ñ‚Ð¾Ñ€Ð¾Ð³Ð¾ не видно. Дно неÑÑно виднеетÑÑ 15-ÑŽ метрами ниже. +110 ÐšÐ»Ð¾Ñ‡ÑŒÑ Ð±ÐµÐ»Ð¾Ð³Ð¾ тумана покрывают дно колодца. Следы на пыли у окна +110 показывают, что недавно здеÑÑŒ уже кто-то был. ПрÑмо напротив вашего +110 окна на раÑÑтоÑнии 8-ми метров видно похожее окно, выходÑщее из +110 оÑвещенного грота. Ð’ нем угадываетÑÑ Ñ‚ÐµÐ¼Ð½Ð°Ñ Ñ„Ð¸Ð³ÑƒÑ€Ð°, котораÑ, кажетÑÑ, +110 Ñмотрит на ваÑ. +111 Большой Ñталактит ÑвиÑает Ñ Ð¿Ð¾Ñ‚Ð¾Ð»ÐºÐ° и почти доÑтигает пола внизу. Ð’Ñ‹ +111 можете Ñлезть по Ñталактиту и Ñпрыгнуть вниз, но уже не Ñможете +111 дотÑнутьÑÑ Ð´Ð¾ него, чтобы взобратьÑÑ Ð¾Ð±Ñ€Ð°Ñ‚Ð½Ð¾. +112 Ð’Ñ‹ в небольшом лабиринте извивающихÑÑ, непохожих друг на друга проходов. +113 Ð’Ñ‹ у ÐºÑ€Ð°Ñ Ð±Ð¾Ð»ÑŒÑˆÐ¾Ð³Ð¾ подземного резервуара. Ðепрозрачное облако белого +113 тумана заполнÑет грот и поднимаетÑÑ ÐºÐ²ÐµÑ€Ñ…Ñƒ. Озеро питаетÑÑ Ñ€ÑƒÑ‡ÑŒÐµÐ¼, +113 вырывающимÑÑ Ð¸Ð· щели в Ñтене на выÑоте около 3-x метров. Вода Ñ ÑˆÑƒÐ¼Ð¾Ð¼ +113 падает в озеро вне пределов видимоÑти. ЕдинÑтвенный выход ведет +113 обратно на юг. +114 ЗдеÑÑŒ тупик. +115 Ð’Ñ‹ в Ñеверо-воÑточной чаÑти чрезвычайно большого грота. Очевидно, Ñто +115 Ñклад программы "пещера". МаÑÑивные, выÑоко раÑположенные, +115 Ñветильники заливают грот дымным желтым Ñветом. Вокруг валÑетÑÑ ÐºÑƒÑ‡Ð° +115 бутылок (вÑе пуÑтые). ЗдеÑÑŒ же ÐºÐ¾Ð»Ð»ÐµÐºÑ†Ð¸Ñ Ð»Ð°Ñ‚ÑƒÐ½Ð½Ñ‹Ñ… ламп. Громадное +115 зеркало проÑтираетÑÑ Ð¾Ñ‚ одной Ñтены грота до другой, где неÑÑно видны +115 кучи каких-то предметов. Подальше, у Ñтены, на полу Ñпит много +115 карликов. Они громко храпÑÑ‚. Табличка, раÑÐ¿Ð¾Ð»Ð¾Ð¶ÐµÐ½Ð½Ð°Ñ Ñ€Ñдом, глаÑит: +115 +115 "ÐЕ БУДИ КÐРЛИКОВ!" +115 +116 Ð’Ñ‹ в юго-западной чаÑти Ñклада. С одной Ñтороны находитÑÑ Ñма, Ð¿Ð¾Ð»Ð½Ð°Ñ +116 зеленых змей, Ñ Ð´Ñ€ÑƒÐ³Ð¾Ð¹ Ñтороны - Ñ€Ñд маленьких плетенных клеток и в +116 каждой - Ð¼Ð°Ð»ÐµÐ½ÑŒÐºÐ°Ñ Ð¿Ñ‚Ð¸Ñ‡ÐºÐ°. МножеÑтво бархатных подушек раÑÑеÑно по +116 полу. Громадное зеркало проÑтираетÑÑ Ð½Ð° Ñв. У ваших ног Ð±Ð¾Ð»ÑŒÑˆÐ°Ñ +116 ÑÑ‚Ð°Ð»ÑŒÐ½Ð°Ñ Ñ€ÐµÑˆÐµÑ‚ÐºÐ°. табличка на ней глаÑит: +116 +116 "ХРÐÐИЛИЩЕ СОКРОВИЩ. КЛЮЧИ Ð’ ГЛÐÐ’ÐОЙ КОÐТОРЕ" +116 +117 Ð’Ñ‹ на одной Ñтороне большой глубокой раÑÑелины. ГуÑтой белый туман, +117 поднимающийÑÑ Ð¸Ð· раÑÑелины, не позволÑет раÑÑмотреть другую Ñторону. +117 Ðа юз от раÑÑелины виден проход в покатый коридор. +118 Ð’Ñ‹ в длинном покатом коридоре. Концов его не видно. +119 Ð’Ñ‹ в тайном каньоне Ñ Ð²Ñ‹Ñ…Ð¾Ð´Ð°Ð¼Ð¸ на Ñевер и воÑток. +120 Ð’Ñ‹ в тайном каньоне Ñ Ð²Ñ‹Ñ…Ð¾Ð´Ð°Ð¼Ð¸ на Ñевер и воÑток. +121 Ð’Ñ‹ в тайном каньоне Ñ Ð²Ñ‹Ñ…Ð¾Ð´Ð°Ð¼Ð¸ на Ñевер и воÑток. +122 Ð’Ñ‹ на дальней Ñтороне раÑÑелины. Путь от раÑÑелины ведет на Ñв. +123 Ð’Ñ‹ в длинном в/з коридоре. Вдалеке Ñлышен Ñлабый грохот. +124 ЗдеÑÑŒ развилка. Ðалево путь ведет на Ñв. Ð’ Ñтом направлении глухой +124 грохот, кажетÑÑ, ÑтановитÑÑ Ð³Ñ€Ð¾Ð¼Ñ‡Ðµ. Ðаправо путь ведет на юв Ñ +124 наклоном вниз. ОÑновной коридор подходит к развилке Ñ Ð·Ð°Ð¿Ð°Ð´Ð°. +125 Ð’Ñ‹ находитеÑÑŒ у ÑÐ¾ÐµÐ´Ð¸Ð½ÐµÐ½Ð¸Ñ Ð´Ð²ÑƒÑ… проходов. Один проход ведет +125 на Ñевер. Стены здеÑÑŒ довольно горÑчие. Ðа Ñевере Ñлышен +125 непрерывный гул, наÑтолько Ñильный, что, кажетÑÑ, дрожит вÑÑ +125 пещера. Другой проход ведет на юг. Ðизкий лаз ведет на воÑток. +126 Перед вами захватывающий дух вид. Ðиже Ð²Ð°Ñ - дейÑтвующий вулкан, из +126 которого вырываютÑÑ Ð±Ñ€Ñ‹Ð·Ð³Ð¸ раÑплавленной лавы. Они падают обратно в +126 жерло вулкана. РаÑкаленные камни заполнÑÑŽÑ‚ каверну кроваво-краÑным +126 Ñветом, Ð¿Ñ€Ð¸Ð´Ð°Ð²Ð°Ñ Ð²Ñему мрачный и таинÑтвенный вид. Воздух заполнен +126 чаÑтицами пепла, пахнет Ñерой, до Ñтен невозможно дотронутьÑÑ. Грохот +126 вулкана гаÑит вÑе другие звуки. Ð¨Ð¸Ñ€Ð¾ÐºÐ°Ñ Ñ€ÐµÐºÐ° Ð¾Ð³Ð½Ñ Ð²Ñ‹Ñ‚ÐµÐºÐ°ÐµÑ‚ из жерла +126 вулкана и падает в бездонный колодец далеко Ñлева от ваÑ. Справа - +126 громадный гейзер, раÑположенный на оÑтрове, непрерывно выбраÑывает +126 шипÑщую Ñтрую. ДальнÑÑ Ñтена Ñправа ÑветитÑÑ ÑобÑтвенным Ñветом, что +126 придает дополнительный таинÑтвенный оттенок и без того адÑкому +126 зрелищу. Темный проход ведет на юг. +127 Ð’Ñ‹ в маленькой камере, заполненной большими валунами. Стены горÑчие, +127 дышать трудно. ЕдинÑтвенный выход - лаз, ведущий на запад, через +127 который проникает низкий гул. +128 Ð’Ñ‹ идете по пологому Ñ/ÑŽ проходу, Ñложенному из извеÑтнÑковых камней +128 и плит Ñтранной формы. +129 Ð’Ñ‹ Ñтоите у входа в большой пуÑтой грот. Табличка, ÑƒÐºÑ€ÐµÐ¿Ð»ÐµÐ½Ð½Ð°Ñ Ð½Ð°Ð´ +129 входом, глаÑит: +129 "ОСТОРОЖÐО! Ð’ ГРОТЕ МЕДВЕДЬ!" +129 +130 Ð’Ñ‹ в пуÑтом гроте. Центр Ñовершенно пуÑÑ‚, еÑли не Ñчитать пыли. Следы +130 на пыли ведут к дальнему концу грота. ЕдинÑтвенный выход - тот, через +130 который вы вошли. +131 Ð’Ñ‹ в лабиринте извивающихÑÑ Ð½ÐµÐ±Ð¾Ð»ÑŒÑˆÐ¸Ñ… непохожих друг на друга проходов. +132 Ð’Ñ‹ в небольшом лабиринте извилиÑтых непохожих друг на друга проходов. +133 Ð’Ñ‹ в запутанном небольшом лабиринте непохожих друг на друга проходов. +134 Ð’Ñ‹ в запутанном лабиринте небольших непохожих друг на друга проходов. +135 Ð’Ñ‹ в извилиÑтом небольшом лабиринте непохожих друг на друга проходов. +136 Ð’Ñ‹ в извилиÑтом лабиринте небольших непохожих друг на друга проходов. +137 Ð’Ñ‹ в небольшом извилиÑтом лабиринте непохожих друг на друга проходов. +138 Ð’Ñ‹ в лабиринте небольших извивающихÑÑ Ð½ÐµÐ¿Ð¾Ñ…Ð¾Ð¶Ð¸Ñ… друг на друга проходов. +139 Ð’Ñ‹ в лабиринте небольших извилиÑтых непохожих друг на друга проходов. +140 ЗдеÑÑŒ тупик. +-1 End +2 +1 Ð’Ñ‹ Ñнова у конца дороги. +2 Ð’Ñ‹ у холма. +3 Ð’Ñ‹ внутри дома. +4 Ð’Ñ‹ в долине. +5 Ð’Ñ‹ в леÑу. +6 Ð’Ñ‹ в леÑу. +7 Ð’Ñ‹ у щели, в которую втекает ручей. +8 Ð’Ñ‹ Ñнаружи у решетки. +9 Ð’Ñ‹ ниже решетки. +10 Ð’Ñ‹ в лазе Ñ Ð±ÑƒÐ»Ñ‹Ð¶Ð½Ð¸ÐºÐ°Ð¼Ð¸. +11 Ð’Ñ‹ в гроте обломков. +13 Ð’Ñ‹ в птичьей камере. +14 Ð’Ñ‹ над небольшой Ñмой. +15 Ð’Ñ‹ в зале туманов. +17 Ð’Ñ‹ на воÑточном краю пропаÑти. +18 Ð’Ñ‹ в гроте золотого Ñамородка. +19 Ð’Ñ‹ в зале горного королÑ. +23 Ð’Ñ‹ в западной чаÑти грота Ñ Ð´Ð²ÑƒÐ¼Ñ Ñмами. +24 Ð’Ñ‹ в воÑточной Ñме. +25 Ð’Ñ‹ в западной Ñме. +33 Ð’Ñ‹ у "Y2". +35 Ð’Ñ‹ у окна, выходÑщего в колодец. +36 Ð’Ñ‹ в грÑзном проходе. +39 Ð’Ñ‹ в гроте Ñ Ð¿Ñ‹Ð»ÑŒÐ½Ñ‹Ð¼Ð¸ Ñкалами. +41 Ð’Ñ‹ в западной чаÑти зала туманов. +57 Ð’Ñ‹ у ÐºÑ€Ð°Ñ ÐºÐ¾Ð»Ð¾Ð´Ñ†Ð°. +60 Ð’Ñ‹ в воÑточной чаÑти длинного зала. +61 Ð’Ñ‹ в западной чаÑти длинного зала. +64 Ð’Ñ‹ у Ñложного ÑÐ¾ÐµÐ´Ð¸Ð½ÐµÐ½Ð¸Ñ Ð¿Ñ€Ð¾Ñ…Ð¾Ð´Ð¾Ð². +66 Ð’Ñ‹ в гроте, похожем на швейцарÑкий Ñыр. +67 Ð’Ñ‹ в воÑточной чаÑти грота Ñ Ð´Ð²ÑƒÐ¼Ñ Ñмами. +68 Ð’Ñ‹ в гроте Ñ Ð±Ð¾Ð»ÑŒÑˆÐ¾Ð¹ плитой. +71 Ð’Ñ‹ у ÑÐ¾ÐµÐ´Ð¸Ð½ÐµÐ½Ð¸Ñ Ñ‚Ñ€ÐµÑ… тайных каньонов. +74 Ð’Ñ‹ в тайном в/з каньоне над узким каньоном. +88 Ð’Ñ‹ в узком коридоре. +91 Ð’Ñ‹ на крутом Ñкате над большим гротом. +92 Ð’Ñ‹ в громадном гроте. +95 Ð’Ñ‹ в каверне Ñ Ð²Ð¾Ð´Ð¾Ð¿Ð°Ð´Ð¾Ð¼. +96 Ð’Ñ‹ в мÑгком гроте. +97 Ð’Ñ‹ в китайÑком гроте. +98 Ð’Ñ‹ в туманной каверне. +99 Ð’Ñ‹ в алькове. +100 Ð’Ñ‹ в голубином гроте. +101 Ð’Ñ‹ в темном гроте. +102 Ð’Ñ‹ в зале Ñ Ð°Ñ€ÐºÐ°Ð¼Ð¸. +103 Ð’Ñ‹ в гроте Ñ Ñ€Ð°ÐºÐ¾Ð²Ð¸Ð½Ð¾Ð¹. +106 Ð’Ñ‹ в приемной. +108 Ð’Ñ‹ в безумном тупичке. +109 Ð’Ñ‹ в каньоне Ñ Ð·ÐµÑ€ÐºÐ°Ð»Ð¾Ð¼. +110 Ð’Ñ‹ у окна, выходÑщего в колодец. +111 Ð’Ñ‹ у вершины Ñталактита. +113 Ð’Ñ‹ у резервуара. +115 Ð’Ñ‹ в Ñв чаÑти Ñклада. +116 Ð’Ñ‹ в юз чаÑти Ñклада. +117 Ð’Ñ‹ на юз Ñтороне раÑÑелины. +118 Ð’Ñ‹ в покатом коридоре. +122 Ð’Ñ‹ на Ñв Ñтороне раÑÑелины. +123 Ð’Ñ‹ в коридоре. +124 Ð’Ñ‹ у развилки. +125 Ð’Ñ‹ у ÑÐ¾ÐµÐ´Ð¸Ð½ÐµÐ½Ð¸Ñ Ñ Ð³Ð¾Ñ€Ñчими Ñтенами. +126 Ð’Ñ‹ в гроте Ñ Ð²Ð¸Ð´Ð¾Ð¼ на вулкан. +127 Ð’Ñ‹ в камере, заполненной валунами. +128 Ð’Ñ‹ в извеÑтнÑковом проходе. +129 Ð’Ñ‹ у входа в пуÑтой грот. +130 Ð’Ñ‹ в пуÑтом гроте. +-1 +3 +1 2 2 44 29 +1 3 3 12 19 43 +1 4 5 13 14 46 30 +1 5 6 45 43 +1 8 63 +2 1 2 12 7 43 45 30 +2 5 6 45 46 +3 1 3 11 32 44 +3 11 62 +3 33 65 +3 79 5 14 +4 1 4 12 45 +4 5 6 43 44 29 +4 7 5 46 30 +4 8 63 +5 4 9 43 30 +5 50005 6 7 45 +5 6 6 +5 5 44 46 +6 1 2 45 +6 4 9 43 44 30 +6 5 6 46 +7 1 12 +7 4 4 45 +7 5 6 43 44 +7 8 5 15 16 46 +7 595 60 14 30 +8 5 6 43 44 46 +8 1 12 +8 7 4 13 45 +8 303009 3 19 30 +8 593 3 +9 303008 11 29 +9 593 11 +9 10 17 18 19 44 +9 14 31 +9 11 51 +10 9 11 20 21 43 +10 11 19 22 44 51 +10 14 31 +11 303008 63 +11 9 64 +11 10 17 18 23 24 43 +11 12 25 19 29 44 +11 3 62 +11 14 31 +12 303008 63 +12 9 64 +12 11 30 43 51 +12 13 19 29 44 +12 14 31 +13 303008 63 +13 9 64 +13 11 51 +13 12 25 43 +13 14 23 31 44 +14 303008 63 +14 9 64 +14 11 51 +14 13 23 43 +14 150020 30 31 34 +14 15 30 +14 16 33 44 +15 18 36 46 +15 17 7 38 44 +15 19 10 30 45 +15 150022 29 31 34 35 23 43 +15 14 29 +15 34 55 +16 14 1 +17 15 38 43 +17 312596 39 +17 412021 7 +17 412597 41 42 44 69 +17 27 41 +18 15 38 11 45 +19 15 10 29 43 +19 311028 45 36 +19 311029 46 37 +19 311030 44 7 +19 32 45 +19 35074 49 +19 211032 49 +19 74 66 +20 0 1 +21 0 1 +22 15 1 +23 67 43 42 +23 68 44 61 +23 25 30 31 +23 648 52 +24 67 29 11 +25 23 29 11 +25 724031 56 +25 26 56 +26 88 1 +27 312596 39 +27 412021 7 +27 412597 41 42 43 69 +27 17 41 +27 40 45 +27 41 44 +28 19 38 11 46 +28 33 45 55 +28 36 30 52 +29 19 38 11 45 +30 19 38 11 43 +30 62 44 29 +31 524089 1 +31 90 1 +32 19 1 +33 3 65 +33 28 46 +33 34 43 53 54 +33 35 44 +33 159302 71 +33 100 71 +34 33 30 55 +34 15 29 +35 33 43 55 +35 20 39 +36 37 43 17 +36 28 29 52 +36 39 44 +36 65 70 +37 36 44 17 +37 38 30 31 56 +38 37 56 29 11 +38 595 60 14 30 4 5 +39 36 43 23 +39 64 30 52 58 +39 65 70 +40 41 1 +41 42 46 29 23 56 +41 27 43 +41 59 45 +41 60 44 17 +42 41 29 +42 42 45 +42 43 43 +42 45 46 +42 80 44 +43 42 44 +43 44 46 +43 45 43 +44 43 43 +44 48 30 +44 50 46 +44 82 45 +45 42 44 +45 43 45 +45 46 43 +45 47 46 +45 87 29 30 +46 45 44 11 +47 45 43 11 +48 44 29 11 +49 50 43 +49 51 44 +50 44 43 +50 49 44 +50 51 30 +50 52 46 +51 49 44 +51 50 29 +51 52 43 +51 53 46 +52 50 44 +52 51 43 +52 52 46 +52 53 29 +52 55 45 +52 86 30 +53 51 44 +53 52 45 +53 54 46 +54 53 44 11 +55 52 44 +55 55 45 +55 56 30 +55 57 43 +56 55 29 11 +57 13 30 56 +57 55 44 +57 58 46 +57 83 45 +57 84 43 +58 57 43 11 +59 27 1 +60 41 43 29 17 +60 61 44 +60 62 45 30 52 +61 60 43 +61 62 45 +61 100107 46 +62 60 44 +62 63 45 +62 30 43 +62 61 46 +63 62 46 11 +64 39 29 56 59 +64 65 44 70 +64 103 45 74 +64 106 43 +65 64 43 +65 66 44 +65 80556 46 +65 68 61 +65 80556 29 +65 50070 29 +65 39 29 +65 60556 45 +65 75072 45 +65 71 45 +65 80556 30 +65 106 30 +66 65 47 +66 67 44 +66 80556 46 +66 77 25 +66 96 43 +66 50556 50 +66 97 72 +67 66 43 +67 23 44 42 +67 24 30 31 +68 23 46 +68 69 29 56 +68 65 45 +69 68 30 61 +69 331120 46 +69 119 46 +69 109 45 +69 113 75 +70 71 45 +70 65 30 23 +70 111 46 +71 65 48 +71 70 46 +71 110 45 +72 65 70 +72 118 49 +72 73 45 +72 97 48 72 +73 72 46 17 11 +74 19 43 +74 331120 44 +74 121 44 +74 75 30 +75 76 46 +75 77 45 +76 75 45 +77 75 43 +77 78 44 +77 66 45 17 +78 77 46 +79 3 1 +80 42 45 +80 80 44 +80 80 46 +80 81 43 +81 80 44 11 +82 44 46 11 +83 57 46 +83 84 43 +83 85 44 +84 57 45 +84 83 44 +84 114 50 +85 83 43 11 +86 52 29 11 +87 45 29 30 +88 25 30 56 43 +88 20 39 +88 92 44 27 +89 25 1 +90 23 1 +91 95 45 73 23 +91 72 30 56 +92 88 46 +92 93 43 +92 94 45 +93 92 46 27 11 +94 92 46 27 23 +94 309095 45 3 73 +94 611 45 +95 94 46 11 +95 92 27 +95 91 44 +96 66 44 11 +97 66 48 +97 72 44 17 +97 98 29 45 73 +98 97 46 72 +98 99 44 +99 98 50 73 +99 301 43 23 +99 100 43 +100 301 44 23 11 +100 99 44 +100 159302 71 +100 33 71 +100 101 47 22 +101 100 46 71 11 +102 103 30 74 11 +103 102 29 38 +103 104 30 +103 114618 46 +103 115619 46 +103 64 46 +104 103 29 74 +104 105 30 +105 104 29 11 +105 103 74 +106 64 29 +106 65 44 +106 108 43 +107 131 46 +107 132 49 +107 133 47 +107 134 48 +107 135 29 +107 136 50 +107 137 43 +107 138 44 +107 139 45 +107 61 30 +108 95556 43 45 46 47 48 49 50 29 30 +108 106 43 +108 626 44 +109 69 46 +109 113 45 75 +110 71 44 +110 20 39 +111 70 45 +111 40050 30 39 56 +111 50053 30 +111 45 30 +112 131 49 +112 132 45 +112 133 43 +112 134 50 +112 135 48 +112 136 47 +112 137 44 +112 138 30 +112 139 29 +112 140 46 +113 109 46 11 109 +114 84 48 +115 116 49 +116 115 47 +116 593 30 +117 118 49 +117 233660 41 42 69 47 +117 332661 41 +117 303 41 +117 332021 39 +117 596 39 +118 72 30 +118 117 29 +119 69 45 11 +119 653 43 7 +120 69 45 +120 74 43 +121 74 43 11 +121 653 45 7 +122 123 47 +122 233660 41 42 69 49 +122 303 41 +122 596 39 +122 124 77 +122 126 28 +122 129 40 +123 122 44 +123 124 43 77 +123 126 28 +123 129 40 +124 123 44 +124 125 47 36 +124 128 48 37 30 +124 126 28 +124 129 40 +125 124 46 77 +125 126 45 28 +125 127 43 17 +126 125 46 23 11 +126 124 77 +126 610 30 39 +127 125 44 11 17 +127 124 77 +127 126 28 +128 124 45 29 77 +128 129 46 30 40 +128 126 28 +129 128 44 29 +129 124 77 +129 130 43 19 40 3 +129 126 28 +130 129 44 11 +130 124 77 +130 126 28 +131 107 44 +131 132 48 +131 133 50 +131 134 49 +131 135 47 +131 136 29 +131 137 30 +131 138 45 +131 139 46 +131 112 43 +132 107 50 +132 131 29 +132 133 45 +132 134 46 +132 135 44 +132 136 49 +132 137 47 +132 138 43 +132 139 30 +132 112 48 +133 107 29 +133 131 30 +133 132 44 +133 134 47 +133 135 49 +133 136 43 +133 137 45 +133 138 50 +133 139 48 +133 112 46 +134 107 47 +134 131 45 +134 132 50 +134 133 48 +134 135 43 +134 136 30 +134 137 46 +134 138 29 +134 139 44 +134 112 49 +135 107 45 +135 131 48 +135 132 30 +135 133 46 +135 134 43 +135 136 44 +135 137 49 +135 138 47 +135 139 50 +135 112 29 +136 107 43 +136 131 44 +136 132 29 +136 133 49 +136 134 30 +136 135 46 +136 137 50 +136 138 48 +136 139 47 +136 112 45 +137 107 48 +137 131 47 +137 132 46 +137 133 30 +137 134 29 +137 135 50 +137 136 45 +137 138 49 +137 139 43 +137 112 44 +138 107 30 +138 131 43 +138 132 47 +138 133 29 +138 134 44 +138 135 45 +138 136 46 +138 137 48 +138 139 49 +138 112 50 +139 107 49 +139 131 50 +139 132 43 +139 133 44 +139 134 45 +139 135 30 +139 136 48 +139 137 29 +139 138 46 +139 112 47 +140 112 45 11 +-1 +4 +2 road +2 hill +3 enter +4 upstr +5 downs +6 fores +7 forwa +7 conti +7 onwar +8 back +8 retur +8 retre +9 valle +10 stair +11 out +11 outsi +11 exit +11 leave +12 build +12 house +13 gully +14 strea +15 rock +16 bed +17 crawl +18 cobbl +19 inwar +19 insid +19 in +20 surfa +21 null +21 nowhe +22 dark +23 passa +23 tunne +24 low +25 canyo +26 awkwa +27 giant +28 view +29 upwar +29 up +29 u +29 above +29 ascen +30 d +30 downw +30 down +30 desce +31 pit +32 outdo +33 crack +34 steps +35 dome +36 left +37 right +38 hall +39 jump +40 barre +41 over +42 acros +43 east +43 e +44 west +44 w +45 north +45 n +46 south +46 s +47 ne +48 se +49 sw +50 nw +51 debri +52 hole +53 wall +54 broke +55 y2 +56 climb +57 look +57 exami +57 touch +57 descr +58 floor +59 room +60 slit +61 slab +61 slabr +62 xyzzy +63 depre +64 entra +65 plugh +66 secre +67 cave +69 cross +70 bedqu +71 plove +72 orien +73 caver +74 shell +75 reser +76 main +76 offic +77 fork +1001 keys +1001 key +1002 lamp +1002 headl +1002 lante +1003 grate +1004 cage +1005 wand +1005 rod +1006 wand +1006 rod (must be next object after "real" rod) +1007 steps +1008 bird +1009 door +1010 pillo +1010 velve +1011 snake +1012 fissu +1013 table +1014 clam +1015 oyste +1016 magaz +1016 issue +1016 spelu +1016 spell +1017 dwarf +1017 dwarv +1018 knife +1018 knive +1019 food +1019 ratio +1020 bottl +1020 jar +1021 water +1021 h2o +1022 oil +1023 mirro +1024 plant +1024 beans +1025 plant (must be next object after "real" plant) +1026 stala +1027 shado +1027 figur +1028 axe +1029 drawi +1030 pirat +1031 drago +1032 chasm +1033 troll +1034 troll (must be next object after "real" troll) +1035 bear +1036 messa +1037 volca +1037 geyse (same as volcano) +1038 machi +1038 vendi +1039 batte +1040 carpe +1040 moss +1050 gold +1050 nugge +1051 diamo +1052 silve +1052 bars +1053 jewel +1054 coins +1055 chest +1055 box +1055 treas +1056 eggs +1056 egg +1056 nest +1057 tride +1058 vase +1058 ming +1058 shard +1058 potte +1059 emera +1060 plati +1060 pyram +1061 pearl +1062 rug +1062 persi +1063 spice +1064 chain +2001 carry +2001 take +2001 keep +2001 catch +2001 steal +2001 captu +2001 get +2001 tote +2002 drop +2002 relea +2002 free +2002 disca +2002 dump +2003 say +2003 chant +2003 sing +2003 utter +2003 mumbl +2004 unloc +2004 open +2005 nothi +2006 lock +2006 close +2007 light +2007 on +2008 extin +2008 off +2009 wave +2009 shake +2009 swing +2010 calm +2010 placa +2010 tame +2011 walk +2011 run +2011 trave +2011 go +2011 proce +2011 conti +2011 explo +2011 goto +2011 follo +2011 turn +2012 attac +2012 kill +2012 slay +2012 fight +2012 hit +2012 strik +2013 pour +2014 eat +2014 devou +2015 drink +2016 rub +2017 throw +2017 toss +2018 quit +2019 find +2019 where +2020 inven +2021 feed +2022 fill +2023 blast +2023 deton +2023 ignit +2023 blowu +2024 score +2025 fee +2025 fie +2025 foe +2025 foo +2025 fum +2026 brief +2027 read +2027 perus +2028 break +2028 shatt +2028 smash +2029 wake +2029 distu +2030 suspe +2030 pause +2030 save +2031 hours +3001 fee +3002 fie +3003 foe +3004 foo +3005 fum +3050 sesam +3050 opens +3050 abra +3050 abrac +3050 shaza +3050 hocus +3050 pocus +3051 help +3051 ? +3064 tree +3064 trees +3066 dig +3066 excav +3068 lost +3069 mist +3079 fuck +3139 stop +3142 info +3142 infor +3147 swim +-1 +5 +1 ÑвÑзку ключей +000 ЗдеÑÑŒ на земле неÑколько ключей. +2 латунную лампу +000 ЗдеÑÑŒ блеÑÑ‚ÑÑ‰Ð°Ñ Ð»Ð°Ñ‚ÑƒÐ½Ð½Ð°Ñ Ð»Ð°Ð¼Ð¿Ð°. +100 TЗдеÑÑŒ Ñ€Ñдом горÑÑ‰Ð°Ñ Ð»Ð°Ð¼Ð¿Ð°. +3 *решетка +000 Решетка заперта. +100 Решетка открыта. +4 проволочную клетку +000 ЗдеÑÑŒ брошена Ð¼Ð°Ð»ÐµÐ½ÑŒÐºÐ°Ñ Ð¿Ñ€Ð¾Ð²Ð¾Ð»Ð¾Ñ‡Ð½Ð°Ñ ÐºÐ»ÐµÑ‚ÐºÐ°. +5 черный жезл +000 ЗдеÑÑŒ лежит 3-футовый черный жезл Ñ Ñ€Ð¶Ð°Ð²Ð¾Ð¹ звездой на конце. +6 черный жезл +000 ЗдеÑÑŒ лежит 3-футовый черный жезл Ñ Ñ€Ð¶Ð°Ð²Ð¾Ð¹ звездой на конце. +7 *Steps +000 Rough stone steps lead down the pit. +100 Rough stone steps lead up the dome. +8 маленькую птичку в клетке +000 ЗдеÑÑŒ Ñидит Ð¼Ð°Ð»ÐµÐ½ÑŒÐºÐ°Ñ Ð²ÐµÑÐµÐ»Ð°Ñ Ð¿Ñ‚Ð¸Ñ‡ÐºÐ° и поет. +100 ÐœÐ°Ð»ÐµÐ½ÑŒÐºÐ°Ñ Ð¿Ñ‚Ð¸Ñ‡ÐºÐ° Ñидит в клетке. +9 *Ñ€Ð¶Ð°Ð²Ð°Ñ Ð´Ð²ÐµÑ€ÑŒ +000 Путь преграждает маÑÑÐ¸Ð²Ð½Ð°Ñ Ñ€Ð¶Ð°Ð²Ð°Ñ Ð¶ÐµÐ»ÐµÐ·Ð½Ð°Ñ Ð´Ð²ÐµÑ€ÑŒ. +100 Путь ведет через маÑÑивную ржавую железную дверь. +10 бархатную подушку +000 Ðа полу лежит Ð½ÐµÐ±Ð¾Ð»ÑŒÑˆÐ°Ñ Ð±Ð°Ñ€Ñ…Ð°Ñ‚Ð½Ð°Ñ Ð¿Ð¾Ð´ÑƒÑˆÐºÐ°. +11 *Ð·Ð¼ÐµÑ +000 ÐžÐ³Ñ€Ð¾Ð¼Ð½Ð°Ñ ÑÐ²Ð¸Ñ€ÐµÐ¿Ð°Ñ Ð·ÐµÐ»ÐµÐ½Ð°Ñ Ð·Ð¼ÐµÑ Ð¿Ñ€ÐµÐ³Ñ€Ð°Ð¶Ð´Ð°ÐµÑ‚ путь! +100 >$< (Chased away) +12 *Fissure +000 >$< +100 ХруÑтальный моÑÑ‚ перекрывает пропаÑть. +200 The crystal bridge has vanished! +13 *ÐºÐ°Ð¼ÐµÐ½Ð½Ð°Ñ Ð¿Ð»Ð¸Ñ‚Ð° +000 Ðа маÑÑивной каменной плите на Ñтене надпиÑÑŒ: +000 +000 "ПОЗДРÐВЛЯЕМ ТОГО, КТО ПРИÐЕС СВЕТ Ð’ ТЕМÐЫЙ ГРОТ !" +000 +14 гигантÑкого моллюÑка >grunt!< +000 ЗдеÑÑŒ громадный моллюÑк. Его раковина крепко закрыта. +15 гигантÑкую уÑтрицу >groan!< +000 ЗдеÑÑŒ Ð³Ñ€Ð¾Ð¼Ð°Ð´Ð½Ð°Ñ ÑƒÑтрица. Ее раковина крепко закрыта. +100 Interesting. There seems to be something written on the underside of +100 The oyster. +16 "ÐовоÑти пещеры" +000 ЗдеÑÑŒ неÑколько Ñвежих номеров журнала "ÐовоÑти пещеры". +19 вкуÑную еду +000 ЗдеÑÑŒ еÑть еда. +20 небольшую бутылку +000 ЗдеÑÑŒ бутылка Ñ Ð²Ð¾Ð´Ð¾Ð¹. +100 ЗдеÑÑŒ пуÑÑ‚Ð°Ñ Ð±ÑƒÑ‚Ñ‹Ð»ÐºÐ°. +200 ЗдеÑÑŒ бутылка Ñ Ð¼Ð°Ñлом. +21 Вода в бутылке +22 МаÑло в бутылке +23 *зеркало +000 >$< +24 *Plant +000 Ð’ Ñме маленький роÑток, он шепчет: "воды, воды, ...". +100 The plant spurts into furious growth for a few seconds. +200 4-Ñ… метровое дерево выÑитÑÑ Ð½Ð°Ð´ Ñмой. Слышен рев: "ВОДЫ!! ВОДЫ!!". +300 The plant grows explosively, almost filling the bottom of the pit. +400 ЗдеÑÑŒ гигантÑкое дерево, оно протÑнулоÑÑŒ до Ñамого потолка. +500 You've over-watered the plant! It's shriveling up! It's, it's... +25 *Phony plant (seen in twopit room only when tall enough) +000 >$< +100 Вершина 4-Ñ… метрового дерева выÑтупает над западной Ñмой. +200 Громадное дерево выÑитÑÑ Ð½Ð°Ð´ западной Ñмой и доÑтает до потолка. +26 *Ñталактит +000 >$< +27 *Ñ‚ÐµÐ¼Ð½Ð°Ñ Ñ„Ð¸Ð³ÑƒÑ€Ð° +000 КажетÑÑ, Ñ‚ÐµÐ¼Ð½Ð°Ñ Ñ„Ð¸Ð³ÑƒÑ€Ð° пытаетÑÑ Ð¿Ñ€Ð¸Ð²Ð»ÐµÑ‡ÑŒ ваше внимание. +28 топор карлика +000 ЗдеÑÑŒ небольшой топор. +100 There is a little axe lying beside the bear. +29 *надпиÑÑŒ +000 >$< +30 *пират +000 >$< +31 *дракон +000 Огромный Ñвирепый зеленый дракон преграждает путь! +100 Congratulations! You have just vanquished a dragon with your bare +100 Hands! (unbelievable, isn't it?) +200 Тело громадного зеленого дракона лежит в Ñтороне от прохода. +32 *раÑÑелина +000 Шаткий деревÑнный моÑÑ‚ перекрывает раÑÑелину, иÑÑ‡ÐµÐ·Ð°Ñ Ð² тумане. Ðа +000 моÑту табличка: +000 +000 "Стой! Заплати троллю!" +000 +100 Обломки моÑта (и мертвый медведь) видны на дне раÑÑелины. +33 *тролль +000 Дородный тролль Ñтоит у моÑта и требует, чтобы вы броÑили ему +000 что-нибудь ценное. +100 The troll steps out from beneath the bridge and blocks your way. +200 >$< (Chased away) +34 *Phony troll +000 Ð¢Ñ€Ð¾Ð»Ð»Ñ Ð½Ð¸Ð³Ð´Ðµ не видно. +35 >$< (Bear uses rtext 141) +000 Дикий пещерный медведь Ñмотрит на Ð²Ð°Ñ Ð¸Ð· дальнего конца грота! +100 Ручной пещерный медведь Ñпокойно Ñидит в углу. +200 Ручной медведь бродит неподалеку. +300 >$< (Dead) +36 *Message in second maze +000 ÐадпиÑÑŒ, Ð²Ñ‹Ð²ÐµÐ´ÐµÐ½Ð½Ð°Ñ Ð½Ð° пыли, глаÑит: +000 +000 ÑтО ЛабИрИÐТ, ÑуÐДуК С Сок +000 не тОТ ГдЕ ПирÐÑ‚ ПрÑчЕт РОвиЩÐми +000 +37 *вулкан and/or гейзер +000 >$< +38 *автомат +000 ЗдеÑÑŒ Ñтоит маÑÑивный автомат, на нем надпиÑÑŒ: +000 +000 "БРОСЬ МОÐЕТЫ И ПОЛУЧИ СВЕЖИЕ БÐТÐРЕЙКИ" +000 +39 батарейки +000 ЗдеÑÑŒ еÑть Ñвежие батарейки. +100 ÐеÑколько Ñтарых батареек лежат неподалеку. +40 *ковер and/or мох +000 >$< +50 большой золотой Ñамородок +000 ЗдеÑÑŒ большой ÑиÑющий золотой Ñамородок! +51 неÑколько алмазов +000 ЗдеÑÑŒ алмазы! +52 Ñлитки Ñеребра +000 ЗдеÑÑŒ Ñлитки Ñеребра! +53 драгоценные камни +000 ЗдеÑÑŒ лежат драгоценные камни! +54 редкие монеты +000 ЗдеÑÑŒ много монет! +55 Ñундук Ñ Ñокровищами +000 ЗдеÑÑŒ Ñундук пирата Ñ Ñокровищами! +56 золотые Ñйца +000 ЗдеÑÑŒ большое гнездо, полное золотых Ñиц! +100 The nest of golden eggs has vanished! +200 Done! +57 драгоценный трезубец +000 ЗдеÑÑŒ трезубец, инкруÑтированный драгоценными камнÑми! +58 фарфоровую вазу +000 ЗдеÑÑŒ изÑщнаÑ, Ð´Ð¾Ñ€Ð¾Ð³Ð°Ñ Ñ„Ð°Ñ€Ñ„Ð¾Ñ€Ð¾Ð²Ð°Ñ Ð²Ð°Ð·Ð°! +100 The vase is now resting, delicately, on a velvet pillow. +200 Пол покрыт оÑколками фарфоровой вазы. +300 The ming vase drops with a delicate crash. +59 изумруд размером Ñ Ð³Ð¾Ð»ÑƒÐ±Ð¸Ð½Ð¾Ðµ Ñйцо +000 ЗдеÑÑŒ лежит изумруд размером Ñ Ð³Ð¾Ð»ÑƒÐ±Ð¸Ð½Ð¾Ðµ Ñйцо! +60 платиновую пирамиду +000 ЗдеÑÑŒ Ð¿Ð»Ð°Ñ‚Ð¸Ð½Ð¾Ð²Ð°Ñ 20-тиÑÐ°Ð½Ñ‚Ð¸Ð¼ÐµÑ‚Ñ€Ð¾Ð²Ð°Ñ Ð¿Ð¸Ñ€Ð°Ð¼Ð¸Ð´Ð°! +61 блеÑÑ‚Ñщую жемчужину +000 Ð’ Ñтороне лежит блеÑÑ‚ÑÑ‰Ð°Ñ Ð¶ÐµÐ¼Ñ‡ÑƒÐ¶Ð¸Ð½Ð°! +62 перÑидÑкий ковер +000 Ðа полу раÑÑтелен перÑидÑкий ковер! +100 The dragon is sprawled out on a persian rug!! +63 редкие прÑноÑти +000 ЗдеÑÑŒ редкие прÑноÑти! +64 золотую цепь +000 Ðа полу кучей лежит Ð·Ð¾Ð»Ð¾Ñ‚Ð°Ñ Ñ†ÐµÐ¿ÑŒ! +100 Медведь прикован к Ñтене золотой цепью Ñ Ð·Ð°Ð¼ÐºÐ¾Ð¼! +200 ЗдеÑÑŒ Ð·Ð¾Ð»Ð¾Ñ‚Ð°Ñ Ñ†ÐµÐ¿ÑŒ, Ð¿Ñ€Ð¸ÐºÑ€ÐµÐ¿Ð»ÐµÐ½Ð°Ñ Ðº Ñтене замком! +-1 +6 +1 Ðеподалеку находитÑÑ ÐºÐ¾Ð»Ð¾ÑÑÐ°Ð»ÑŒÐ½Ð°Ñ Ð¿ÐµÑ‰ÐµÑ€Ð°, где одни нашли золото и +1 Ñокровища, а другие, проникнув туда, не вернулиÑÑŒ. ГоворÑÑ‚, что в +1 пещере проиÑходÑÑ‚ чудеÑа. Я буду вашими глазами и руками. УправлÑйте +1 мной Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ команд из 1 или 2 Ñлов. Предупреждаю ваÑ, что Ñ Ñмотрю +1 только на 5 первых букв каждого Ñлова, поÑтому вы должны вводить +1 "Ñеверо-воÑток" как "Ñв", чтобы отличить Ñто Ñлово от "Ñевер". Чтобы +1 получить Ñовет, наберите "помоги" или "информируй". +1 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +1 +2 Маленький карлик Ñ Ð±Ð¾Ð»ÑŒÑˆÐ¸Ð¼ ножом преграждает вам путь. +3 Маленький карлик вышел из-за угла, увидел ваÑ, метнул в Ð²Ð°Ñ Ñ‚Ð¾Ð¿Ð¾Ñ€, +3 промахнулÑÑ, иÑпуÑтил проклÑтье и убежал. +4 С вами в комнате находитÑÑ Ð¼Ð°Ð»ÐµÐ½ÑŒÐºÐ¸Ð¹ ÑумаÑшедший карлик! +5 Ð’ Ð²Ð°Ñ Ð¼ÐµÑ‚Ð½ÑƒÐ»Ð¸ оÑтрый опаÑный нож! +6 Они промахнулиÑÑŒ! +7 Он попал в ваÑ! +8 Тихий Ð³Ð¾Ð»Ð¾Ñ Ð³Ð¾Ð²Ð¾Ñ€Ð¸Ñ‚ "плоф". +9 Ð’ Ñтом направлении пути нет. +10 Я не знаю, в какую Ñторону вы Ñтоите лицом, поÑтому укажите Ñторону +10 Ñвета, куда идти (Ñевер, юг, Ñз, юв ...). +11 I don't know in from out here. Use compass points or name something +11 in the general direction you want to go. +12 Я не знаю, как применить здеÑÑŒ Ñто Ñлово. +13 Я не знаю Ñтого Ñлова. +14 I'm game. Would you care to explain how? +15 Я повторю полное опиÑание вашего меÑтонахождениÑ: +16 ÐšÑ€Ð¾Ð¼ÐµÑˆÐ½Ð°Ñ Ñ‚ÑŒÐ¼Ð°. ЕÑли будете двигатьÑÑ Ð´Ð°Ð»ÑŒÑˆÐµ, ÑвалитеÑÑŒ в Ñму. +17 If you prefer, simply type w rather than west. +18 Ð’Ñ‹ пытаетеÑÑŒ поймать птицу? +19 The bird is frightened right now and you cannot catch it no matter +19 what you try. Perhaps you might try later. +20 Ð’Ñ‹ пытаетеÑÑŒ как-то ÑправитьÑÑ Ñо змеей? +21 You can't kill the snake, or drive it away, or avoid it, or anything +21 like that. There is a way to get by, but you don't have the necessary +21 resources right now. +22 Ð’Ñ‹ дейÑтвительно хотите ÑдатьÑÑ? +23 Ð’Ñ‹ ÑвалилиÑÑŒ в Ñму и поломали Ñебе вÑе коÑти! +24 You are already carrying it! +25 ÐеÑерьезно! +26 The bird was unafraid when you entered, but as you approach it becomes +26 disturbed and you cannot catch it. +27 You can catch the bird, but you cannot carry it. +28 ЗдеÑÑŒ нет ничего Ñ Ð·Ð°Ð¼ÐºÐ¾Ð¼! +29 У Ð²Ð°Ñ Ñтого нет! +30 The little bird attacks the green snake, and in an astounding flurry +30 drives the snake away. +31 У Ð²Ð°Ñ Ð½ÐµÑ‚ ключей! +32 ЗдеÑÑŒ нет ничего Ñ Ð·Ð°Ð¼ÐºÐ¾Ð¼! +33 I don't know how to lock or unlock such a thing. +34 Она уже заперта. +35 The grate is now locked. +36 The grate is now unlocked. +37 Она уже отперта. +38 У Ð²Ð°Ñ Ð½ÐµÑ‚ иÑточника Ñвета. +39 Your lamp is now on. +40 Your lamp is now off. +41 There is no way to get past the bear to unlock the chain, which is +41 probably just as well. +42 Ðичего не произошло. +43 Where? +44 ЗдеÑÑŒ некого атаковать. +45 The little bird is now dead. Its body disappears. +46 Ðтаковать змею опаÑно, да и беÑполезно. +47 Ð’Ñ‹ убили маленького карлика. +48 Ð’Ñ‹ таковали маленького карлика, но он увернулÑÑ. +49 Чем? Голыми руками? +50 Good try, but that is an old worn-out magic word. +51 Я знаю дейÑтвиÑ, меÑта и вещи. Ð‘Ð¾Ð»ÑŒÑˆÐ°Ñ Ñ‡Ð°Ñть моего ÑÐ»Ð¾Ð²Ð°Ñ€Ñ Ð¾Ð¿Ð¸Ñывает +51 меÑта; их Ð½Ð°Ð·Ð²Ð°Ð½Ð¸Ñ Ð¼Ð¾Ð¶Ð½Ð¾ иÑпользовать, чтобы передвигатьÑÑ. например: +51 леÑ,ручей,войди,ÑŽ,з,вверх. Мне извеÑтны неÑколько оÑобых предметов, +51 таких как черный жезл, клетка и Ñ‚.п. Ñти объекты можно иÑпользовать +51 Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ неÑкольких извеÑтных мне глаголов. Обычно вам нужно давать +51 оба Ñлова: объект и дейÑтвие (в любом порÑдке), но иногда можно +51 понÑть предмет по глаголу,а иногда хватает предмета. например, вмеÑто +51 "полей раÑтение" можно набрать "полей". Объекты имеют побочные +51 дейÑтвиÑ; например, жезл отпугивает птицу. Ð”Ð»Ñ Ñ‚Ð¾Ð³Ð¾, чтобы уÑкорить +51 игру, вы можете перемещатьÑÑ Ð½Ð° большие раÑÑтоÑÐ½Ð¸Ñ Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ одного +51 Ñлова. Ðапример, "дом" обычно доÑтавит Ð²Ð°Ñ Ð² дом из любого меÑта на +51 поверхноÑти земли, кроме того ÑлучаÑ, когда вы потерÑлиÑÑŒ в леÑу. +51 Ðадо заметить, что ходы пещеры имеют маÑÑу поворотов, и еÑли вы +51 выйдете на Ñевер, то не вÑегда войдете обратно Ñ ÑŽÐ³Ð°. Дополнитульную +51 информацию вы можете получить, набрав "инфор". +52 Он промахнулÑÑ! +53 Он попал в ваÑ! +54 Готово! +55 You can't unlock the keys. +56 Ð’Ñ‹ пролезли через неÑколько маленьких ходов, запуталиÑÑŒ и вернулиÑÑŒ +56 назад в главный проход. +57 Я не знаю, где находитÑÑ Ð¿ÐµÑ‰ÐµÑ€Ð°. Я попыталÑÑ Ð±Ñ‹ найти ручей, который +57 в нее течет. +58 I need more detailed instructions to do that. +59 I can only tell you what you see as you move about and manipulate +59 things. I cannot tell you where remote things are. +60 Я Ð²Ð°Ñ Ð½Ðµ понимаю. +61 Что? +62 Ð’Ñ‹ пытаетеÑÑŒ проникнуть в пещеру? +63 The grate is very solid and has a hardened steel lock. You cannot +63 enter without a key, and there are no keys nearby. I would recommend +63 looking elsewhere for the keys. +64 The trees of the forest are large hardwood oak and maple, with an +64 occasional grove of pine or spruce. There is quite a bit of under- +64 growth, largely birch and ash saplings plus nondescript bushes of +64 various sorts. This time of year visibility is quite restricted by +64 all the leaves, but travel is quite easy if you detour around the +64 spruce and berry bushes. +65 Приглашаем в путешеÑтвие! Вам нужны инÑтрукции? +66 Копать без лопаты непрактично, даже Ñ Ð»Ð¾Ð¿Ð°Ñ‚Ð¾Ð¹ едва ли что-нибудь +66 получитÑÑ. +67 Blasting requires dynamite. +68 I'm as confused as you are. +69 Mist is a white vapor, usually water, seen from time to time in +69 caverns. It can be found anywhere but is frequently a sign of a deep +69 pit leading down to water. +70 Your feet are now wet. +71 I think I just lost my appetite. +72 Thank you, it was delicious! +73 You have taken a drink from the stream. The water tastes strongly of +73 minerals, but is not unpleasant. It is extremely cold. +74 The bottle of water is now empty. +75 Rubbing the electric lamp is not particularly rewarding. Anyway, +75 nothing exciting happens. +76 Peculiar. Nothing unexpected happens. +77 Your bottle is empty and the ground is wet. +78 You can't pour that. +79 Watch it! +80 Which way? +81 Oh dear, you seem to have gotten yourself killed. I might be able to +81 help you out, but i've never really done this before. Do you want me +81 to try to reincarnate you? +82 All right. But don't blame me if something goes wr...... +82 --- Poof!! --- +82 You are engulfed in a cloud of orange smoke. Coughing and gasping, +82 you emerge from the smoke and find.... +83 You clumsy oaf, you've done it again! I don't know how long I can +83 keep this up. Do you want me to try reincarnating you again? +84 Okay, now where did I put my orange smoke?.... >poof!< +84 Everything disappears in a dense cloud of orange smoke. +85 Now you've really done it! I'm out of orange smoke! You don't expect +85 me to do a decent reincarnation without any orange smoke, do you? +86 Okay, if you're so smart, do it yourself! I'm leaving! +90 >>> Messages 81 thru 90 are reserved for "obituaries". <<< +91 Sorry, but I no longer seem to remember how it was you got here. +92 You can't carry anything more. You'll have to drop something first. +93 You can't go through a locked steel grate! +94 I believe what you want is right here with you. +95 You don't fit through a two-inch slit! +96 Советую вам идти через моÑÑ‚, а не прыгать. +97 Пути через пропаÑть нет. +98 Ð’Ñ‹ ничего не неÑете. +99 Ð’ данный момент вы неÑете Ñледующее: +100 It's not hungry (it's merely pinin' for the fjords). Besides, you +100 have no bird seed. +101 The snake has now devoured your bird. +102 There's nothing here it wants to eat (except perhaps you). +103 You fool, dwarves eat only coal! Now you've made him *really* mad!! +104 You have nothing in which to carry it. +105 Ваша бутылка уже полна. +106 There is nothing here with which to fill the bottle. +107 Ваша бутылка теперь полна воды. +108 Ваша бутылка теперь полна маÑла. +109 You can't fill that. +110 Ðе будьте Ñмешны! +111 The door is extremely rusty and refuses to open. +112 The plant indignantly shakes the oil off its leaves and asks, "water?" +113 The hinges are quite thoroughly rusted now and won't budge. +114 МаÑло Ñмазало дверь так, что ее можно открыть, но Ñто потребует +114 некоторых уÑилий. +115 The plant has exceptionally deep roots and cannot be pulled free. +116 The dwarves' knives vanish as they strike the walls of the cave. +117 Что-то из того, что вы неÑете, не проходит. вам лучше поÑмотреть +117 ÑпиÑок и чего-нибудь броÑить. +118 Вам не пролезть Ñ Ð¿Ð¾Ð»ÑƒÑ‚Ð¾Ñ€Ð°Ð¼ÐµÑ‚Ñ€Ð¾Ð²Ñ‹Ð¼ моллюÑком через Ñтот проход! +119 Вам не пролезть Ñ Ð¿Ð¾Ð»ÑƒÑ‚Ð¾Ñ€Ð°Ð¼ÐµÑ‚Ñ€Ð¾Ð²Ð¾Ð¹ уÑтрицей через Ñтот проход! +120 I advise you to put down the clam before opening it. >strain!< +121 I advise you to put down the oyster before opening it. >wrench!< +122 You don't have anything strong enough to open the clam. +123 You don't have anything strong enough to open the oyster. +124 A glistening pearl falls out of the clam and rolls away. Goodness, +124 this must really be an oyster. (I never was very good at identifying +124 bivalves.) Whatever it is, it has now snapped shut again. +125 The oyster creaks open, revealing nothing but oyster inside. It +125 promptly snaps shut again. +126 Ð’Ñ‹ ползли по неÑкольким маленьким проходам, пока путь не был +126 прегражден недавним обвалом. Ð’Ñ‹ вернулиÑÑŒ назад в главный проход. +127 There are faint rustling noises from the darkness behind you. +128 Out from the shadows behind you pounces a bearded pirate! "Har, har," +128 he chortles, "I'll just take all this booty and hide it away with me +128 chest deep in the maze!" He snatches your treasure and vanishes into +128 the gloom. +129 A sepulchral voice reverberating through the cave, says, "Cave closing +129 soon. All adventurers exit immediately through main office." +130 A mysterious recorded voice groans into life and announces: +130 "This exit is closed. Please leave via main office." +131 It looks as though you're dead. Well, seeing as how it's so close to +131 closing time anyway, I think we'll just call it a day. +132 Загробный Ð³Ð¾Ð»Ð¾Ñ Ð²Ð¾Ð·Ð²ÐµÑтил: +132 +132 П Е Щ Е Р РЗ РК Р Ы Т Ð !!! +132 +132 Когда звуки Ñмолкли, на мгновенье оÑлепительно вÑпыхнул оранжевый +132 Ñвет и оÑталоÑÑŒ только тающее облако оранжевого дыма... Как только +132 ваши глаза начинают видеть вы обнаруживаете... +132 +133 ПроиÑходит Ñильный взрыв, который заваливает карликов щебнем. +133 Ð’ дальней Ñтене образовалаÑÑŒ Ð±Ð¾Ð»ÑŒÑˆÐ°Ñ Ð´Ñ‹Ñ€Ð°. Ð’Ñ‹ проходите через нее +133 и обнаруживаете, что вы в главной конторе. ВеÑÐµÐ»Ð°Ñ ÐºÐ¾Ð¼Ð¿Ð°Ð½Ð¸Ñ +133 дружелюбных Ñльфов выноÑит ÑчаÑтливого путешеÑтвенника к выходу, +133 в лучи заходÑщего Солнца. +133 +134 ПроиÑходит Ñильный взрыв, который заваливает щебнем вÑех змей. +134 Ð’ дальней Ñтене поÑвлÑетÑÑ Ð±Ð¾Ð»ÑŒÑˆÐ°Ñ Ð´Ñ‹Ñ€Ð°, из нее льетÑÑ Ñ€Ð°ÑÐ¿Ð»Ð°Ð²Ð»ÐµÐ½Ð½Ð°Ñ +134 лава, ÑƒÐ½Ð¸Ñ‡Ñ‚Ð¾Ð¶Ð°Ñ Ð²Ñе на Ñвоем пути, Ð²ÐºÐ»ÑŽÑ‡Ð°Ñ Ð²Ð°Ñ. +134 +135 There is a loud explosion, and you are suddenly splashed across the +135 walls of the room. +136 Возникший шум будит карликов.Карлики напали на Ð²Ð°Ñ ! +136 БольшинÑтво из них броÑают в Ð²Ð°Ñ Ð½Ð¾Ð¶Ð¸! Они попали! +136 +137 Oh, leave the poor unhappy bird alone. +138 I daresay whatever you want is around here somewhere. +139 I don't know the word "stop". Use "quit" if you want to give up. +140 You can't get there from here. +141 You are being followed by a very large, tame bear. +142 If you want to end your adventure early, say "quit". To suspend your +142 adventure such that you can continue later, say "suspend" (or "pause" +142 Or "save"). To see what hours the cave is normally open, say "hours". +142 To see how well you're doing, say "score". To get full credit for a +142 treasure, you must have left it safely in the building, though you get +142 partial credit just for locating it. You lose points for getting +142 killed, or for quitting, though the former costs you more. There are +142 also points based on how much (if any) of the cave you've managed to +142 explore; in particular, there is a large bonus just for getting in (to +142 distinguish the beginners from the rest of the pack), and there are +142 other ways to determine whether you've been through some of the more +142 harrowing sections. If you think you've found all the treasures, just +142 keep exploring for a while. If nothing interesting happens, you +142 haven't found them all yet. If something interesting *does* happen, +142 it means you're getting a bonus and have an opportunity to garner many +142 more points in the master's section. I may occasionally offer hints +142 if you seem to be having trouble. If I do, I'll warn you in advance +142 how much it will affect your score to accept the hints. Finally, to +142 save paper, you may specify "brief", which tells me never to repeat +142 the full description of a place unless you explicitly ask me to. +143 Do you indeed wish to quit now? +144 There is nothing here with which to fill the vase. +145 От резкого Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ñ‚ÐµÐ¼Ð¿ÐµÑ€Ð°Ñ‚ÑƒÑ€Ñ‹ ваза потреÑкалаÑÑŒ. +146 It is beyond your power to do that. +147 I don't know how. +148 It is too far up for you to reach. +149 You killed a little dwarf. The body vanishes in a cloud of greasy +149 black smoke. +150 The shell is very strong and is impervious to attack. +151 Ð’ чем дело? Ð’Ñ‹ что, читать не умеете? Ðачните лучше Ñначала. +152 The axe bounces harmlessly off the dragon's thick scales. +153 Дракон довольно опаÑен. Лучше не ходить мимо него. +154 The little bird attacks the green dragon, and in an astounding flurry +154 gets burnt to a cinder. The ashes blow away. +155 On what? +156 Okay, from now on i'll only describe a place in full the first time +156 you come to it. To get the full description, say "look". +157 Trolls are close relatives with the rocks and have skin as tough as +157 that of a rhinoceros. The troll fends off your blows effortlessly. +158 The troll deftly catches the axe, examines it carefully, and tosses it +158 back, declaring, "good workmanship, but it's not valuable enough." +159 Тролль ловит вашу драгоценноÑть и ÑкрываетÑÑ Ð¸Ð· виду. +160 Тролль не пропуÑкает ваÑ. +161 Пути через раÑÑелину теперь нет. +162 Ð’Ñ‹ почти доÑтигли другой Ñтороны, когда моÑÑ‚ прогнулÑÑ Ð¿Ð¾Ð´ +162 Ñ‚ÑжеÑтью медведÑ, топающего за вами. Ð’Ñ‹ отчаÑнно пытаетеÑÑŒ +162 выбратьÑÑ, но моÑÑ‚ рушитÑÑ Ð¸ вы падаете в раÑÑелину. +163 The bear lumbers toward the troll, who lets out a startled shriek and +163 scurries away. The bear soon gives up the pursuit and wanders back. +164 The axe misses and lands near the bear where you can't get at it. +165 With what? Your bare hands? Against *his* bear hands?? +166 The bear is confused; he only wants to be your friend. +167 Ðе Ñтоит так горевать, беднÑга уже мертв. +168 The bear eagerly wolfs down your food, after which he seems to calm +168 Down considerably and even becomes rather friendly. +169 The bear is still chained to the wall. +170 The chain is still locked. +171 Цепь теперь оÑвобождена. +172 The chain is now locked. +173 There is nothing here to which the chain can be locked. +174 There is nothing here to eat. +175 Do you want the hint? +176 Вам подÑказать, как выбратьÑÑ Ð¸Ð· лабиринта? +177 You can make the passages look less alike by dropping things. +178 Ð’Ñ‹ ÑобираетеÑÑŒ иÑÑледовать голубиный грот? +179 There is a way to explore that region without having to worry about +179 falling into a pit. None of the objects available is immediately +179 useful in discovering the secret. +180 Вам подÑказать, как отÑюда выбратьÑÑ? +181 Don't go west. +182 Gluttony is not one of the troll's vices. Avarice, however, is. +183 Your lamp is getting dim. You'd best start wrapping this up, unless +183 You can find some fresh batteries. I seem to recall there's a vending +183 machine in the maze. Bring some coins with you. +184 Your lamp has run out of power. +185 There's not much point in wandering around out here, and you can't +185 explore the cave without a lamp. So let's just call it a day. +186 There are faint rustling noises from the darkness behind you. As you +186 turn toward them, the beam of your lamp falls across a bearded pirate. +186 He is carrying a large chest. "Shiver me timbers!" he cries, "I've +186 been spotted! I'd best hie meself off to the maze to hide me chest!" +186 With that, he vanishes into the gloom. +187 Your lamp is getting dim. You'd best go back for those batteries. +188 Your lamp is getting dim. I'm taking the liberty of replacing the +188 batteries. +189 Your lamp is getting dim, and you're out of spare batteries. You'd +189 best start wrapping this up. +190 I'm afraid the magazine is written in dwarvish. +191 "This is not the maze where the pirate leaves his treasure chest." +192 Hmmm, this looks like a clue, which means it'll cost you 10 points to +192 read it. Should I go ahead and read it anyway? +193 It says, "there is something strange about this place, such that one +193 Of the words i've always known now has a new effect." +194 It says the same thing it did before. +195 I'm afraid I don't understand. +196 "Congratulations on bringing light into the dark-room!" +197 You strike the mirror a resounding blow, whereupon it shatters into a +197 myriad tiny fragments. +198 You have taken the vase and hurled it delicately to the ground. +199 You prod the nearest dwarf, who wakes up grumpily, takes one look at +199 you, curses, and grabs for his axe. +200 Is this acceptable? +201 There's no point in suspending a demonstration game. +-1 +7 +1 3 +2 3 +3 8 9 +4 10 +5 11 +6 0 +7 14 15 +8 13 +9 94 -1 +10 96 +11 19 -1 +12 17 27 +13 101 -1 +14 103 +15 0 +16 106 +17 0 -1 +18 0 +19 3 +20 3 +21 0 +22 0 +23 109 -1 +24 25 -1 +25 23 67 +26 111 -1 +27 35 110 +28 0 +29 97 -1 +30 0 -1 +31 119 121 +32 117 122 +33 117 122 +34 0 0 +35 130 -1 +36 0 -1 +37 126 -1 +38 140 -1 +39 0 +40 96 -1 +50 18 +51 27 +52 28 +53 29 +54 30 +55 0 +56 92 +57 95 +58 97 +59 100 +60 101 +61 0 +62 119 121 +63 127 +64 130 -1 +-1 +8 +1 24 +2 29 +3 0 +4 33 +5 0 +6 33 +7 38 +8 38 +9 42 +10 14 +11 43 +12 110 +13 29 +14 110 +15 73 +16 75 +17 29 +18 13 +19 59 +20 59 +21 174 +22 109 +23 67 +24 13 +25 147 +26 155 +27 195 +28 146 +29 110 +30 13 +31 13 +-1 +9 +0 1 2 3 4 5 6 7 8 9 10 +0 100 115 116 126 +2 1 3 4 7 38 95 113 24 +1 24 +3 46 47 48 54 56 58 82 85 86 +3 122 123 124 125 126 127 128 129 130 +4 8 +5 13 +6 19 +7 42 43 44 45 46 47 48 49 50 51 +7 52 53 54 55 56 80 81 82 86 87 +8 99 100 101 +9 108 +-1 +10 +35 ЯÑно, что вы отноÑитеÑÑŒ к категории дилетантов. Удачи в Ñледующий раз. +100 Ð’Ð°Ñ Ð¼Ð¾Ð¶Ð½Ð¾ отнеÑти к категории "начинающий Ñпелеолог". +130 Ð’Ñ‹ доÑтигли ÑƒÑ€Ð¾Ð²Ð½Ñ "опытный Ñпелеолог". +200 Теперь вы можете Ñчитать ÑÐµÐ±Ñ Ð·Ð°ÐºÐ°Ð»ÐµÐ½Ð½Ñ‹Ð¼ Ñпелеологом. +250 Ð’Ñ‹ доÑтигли ранга "младший МаÑтер-Ñпелеолог". +300 Ð’Ñ‹ теперь "МаÑтер-Ñпелеолог 3 клаÑÑа". +330 Ð’Ñ‹ теперь "МаÑтер-Ñпелеолог 2 клаÑÑа". +349 Ð’Ñ‹ теперь "МаÑтер-Ñпелеолог 1 клаÑÑа". +9999 Ð’Ñе Ñпелеологи преклонÑÑŽÑ‚ÑÑ Ð¿ÐµÑ€ÐµÐ´ вами, Великий Спелеолог !!! +-1 +11 +2 9999 10 0 0 +3 9999 5 0 0 +4 4 2 62 63 +5 5 2 18 19 +6 8 2 20 21 +7 75 4 176 177 +8 25 5 178 179 +9 20 3 180 181 +-1 +12 +1 A large cloud of green smoke appears in front of you. It clears away +1 to reveal a tall wizard, clothed in grey. He fixes you with a steely +1 glare and declares, "this adventure has lasted too long." With that +1 he makes a single pass over you with his hands, and everything around +1 You fades away into a grey nothingness. +2 Even wizards have to wait longer than that! +3 I'm terribly sorry, but colossal cave is closed. Our hours are: +4 Only wizards are permitted within the cave right now. +5 We do allow visitors to make short explorations during our off hours. +5 Would you like to do that? +6 Colossal cave is open to regular adventurers at the following hours: +7 Very well. +8 Only a wizard may continue an adventure this soon. +9 I suggest you resume your adventure at a later time. +10 Do you wish to see the hours? +11 Do you wish to change the hours? +12 New magic word (null to leave unchanged): +13 New magic number (null to leave unchanged): +14 Do you wish to change the message of the day? +15 Okay. You can save this version now. +16 Are you a wizard? +17 Prove it! Say the magic word! +18 That is not what I thought it was. Do you know what I thought it was? +19 Oh dear, you really *are* a wizard! Sorry to have bothered you . . . +20 Foo, you are nothing but a charlatan! +21 New hours specified by defining "prime time". Give only the hour +21 (E.g. 14, not 14:00 or 2pm). Enter a negative number after last pair. +22 New hours for colossal cave: +23 Limit lines to 70 chars. End with null line. +24 Line too long, retype: +25 Not enough room for another line. Ending message here. +26 Do you wish to (re)schedule the next holiday? +27 To begin how many days from today? +28 To last how many days (zero if no holiday)? +29 To be called what (up to 20 characters)? +30 Too small! Assuming minimum value (45 minutes). +31 Break out of this and save your core-image. +32 Be sure to save your core-image... +-1 +0 + glorkz 4.1 82/05/11 diff --git a/src/games/adventure/hdr.h b/src/games/adventure/hdr.h new file mode 100644 index 0000000..5e9d050 --- /dev/null +++ b/src/games/adventure/hdr.h @@ -0,0 +1,325 @@ +/* + * ADVENTURE -- Jim Gillogly, Jul 1977 + * + * This program is a re-write of ADVENT, written in FORTRAN mostly by + * Don Woods of SAIL. In most places it is as nearly identical to the + * original as possible given the language and word-size differences. + * A few places, such as the message arrays and travel arrays were changed + * to reflect the smaller core size and word size. The labels of the + * original are reflected in this version, so that the comments of the + * fortran are still applicable here. + * + * The data file distributed with the fortran source is assumed to be called + * "glorkz" in the directory where the program is first run. + * + * Data save/restore rewritten in portable way by Serge Vakulenko. + */ + +/* hdr.h: included by c advent files */ +#ifdef CROSS +# ifdef __APPLE__ +# define _OFF_T + typedef long long off_t; +# endif +# include +#else +# include +#endif +#include + +int datfd; /* message file descriptor */ +int delhit; + +#define DATFILE "glorkz" /* all the original msgs */ +#define DATSIZE (46*1024) /* size of encrypted data */ + +#define TAB 011 +#define LF 012 +#define FLUSHLINE while (getchar()!='\n') +#define FLUSHLF while (next()!=LF) + +char *wd1, *wd2; /* the complete words */ + +struct hashtab { /* hash table for vocabulary */ + int val; /* word type &index (ktab) */ + int hash; /* 32-bit hash value */ +}; + +struct text { + unsigned short seekadr; /* DATFILE must be < 2**16 */ + unsigned short txtlen; /* length of msg starting here */ +}; + +struct travlist { /* direcs & conditions of travel*/ + struct travlist *next; /* ptr to next list entry */ + unsigned short conditions; /* m in writeup (newloc / 1000) */ + unsigned short tloc; /* n in writeup (newloc % 1000) */ + unsigned short tverb; /* the verb that takes you there*/ +}; + +/* + * Game state. + */ +struct { + short loc, newloc, oldloc, oldlc2, wzdark, gaveup, kq, k, k2; + short verb, obj, spk; + short blklin; + int saved, savet, mxscor, latncy; + + #define MAXSTR 20 /* max length of user's words */ + + #define HTSIZE 512 /* max number of vocab words */ + struct hashtab voc[HTSIZE]; /* hash table for vocabulary */ + + #define RTXSIZ 205 + struct text rtext[RTXSIZ]; /* random text messages */ + + #define MAGSIZ 35 + struct text mtext[MAGSIZ]; /* magic messages */ + + short clsses; + #define CLSMAX 12 + struct text ctext[CLSMAX]; /* classes of adventurer */ + short cval[CLSMAX]; + + struct text ptext[101]; /* object descriptions */ + + #define LOCSIZ 141 /* number of locations */ + struct text ltext[LOCSIZ]; /* long loc description */ + struct text stext[LOCSIZ]; /* short loc descriptions */ + + struct travlist *travel[LOCSIZ]; /* direcs & conditions of travel*/ + + short atloc[LOCSIZ]; + + short plac[101]; /* initial object placement */ + short fixd[101], fixed[101]; /* location fixed? */ + + short actspk[35]; /* rtext msg for verb */ + + short cond[LOCSIZ]; /* various condition bits */ + + short hntmax; + short hints[20][5]; /* info on hints */ + short hinted[20], hintlc[20]; + + short place[101], prop[101], plink[201]; + short abb[LOCSIZ]; + + short maxtrs, tally, tally2; /* treasure values */ + + #define FALSE 0 + #define TRUE 1 + + short keys, lamp, grate, cage, rod, /* mnemonics */ + rod2, steps, bird, door, pillow, snake, fissur, tablet, clam, + oyster, magzin, dwarf, knife, food, bottle, water, oil, plant, + plant2, axe, mirror, dragon, chasm, troll, troll2, bear, messag, + vend, batter, nugget, coins, chest, eggs, tridnt, vase, emrald, + pyram, pearl, rug, chain, spices, back, look, cave, null, entrnc, + dprssn, say, lock, throw, find, invent; + + short chloc, chloc2, dseen[7], /* dwarf stuff */ + dloc[7], odloc[7], dflag, daltlc; + + short tk[21], stick, dtotal, attack; + short turns, lmwarn, iwest, knfloc, /* various flags & counters */ + detail, abbnum, maxdie, numdie, holdng, dkill, foobar, bonus, + clock1, clock2, closng, panic, closed, scorng; + + short limit; +} game; + +struct travlist *tkk; /* travel is closer to keys(...)*/ + +extern const short setbit[16]; /* bit defn masks 1,2,4,... */ + +void linkdata (void); +void startup (void); +void trapdel (int); +void rdata (char *, char *); +void mspeak (int); +void rspeak (int); +void speak (struct text *); +int toting (int); +int yes (int, int, int); +int yesm (int, int, int); +void drop (int, int); +int vocab (char *, int, int); +void poof (void); +int confirm (char *); +void save (char *, unsigned); +void ciao (void); +int restore (char *); +int restdat (int, unsigned); +void start (int); +int length (char *); +void bug (int); +int getcmd (char *); +int fdwarf (void); +int die (int); +int forced (int); +int dark (int); +int pct (int); +void pspeak (int, int); +void checkhints (void); +void getin (char **, char **); +void copystr (char *, char *); +void done (int); +int closing (void); +int caveclose (void); +int here (int); +int at (int); +int liqloc (int); +int weq (char *, char *); +int march (void); +void dstroy (int); +int score (void); +void move (int, int); +void datime (int *, int *); +int trtake (void); +int trdrop (void); +int trsay (void); +int tropen (void); +int trkill (void); +int trtoss (void); +int trfill (void); +int trfeed (void); +int liq (int); +int ran (int); +void carry (int, int); +void juggle (int); +int put (int, int, int); + +#define voc game.voc +#define rtext game.rtext +#define mtext game.mtext +#define ctext game.ctext +#define cval game.cval +#define ptext game.ptext +#define ltext game.ltext +#define stext game.stext +#define travel game.travel +#define atloc game.atloc +#define plac game.plac +#define fixd game.fixd +#define fixed game.fixed +#define actspk game.actspk +#define cond game.cond +#define hntmax game.hntmax +#define hints game.hints +#define hinted game.hinted +#define hintlc game.hintlc +#define place game.place +#define prop game.prop +#define plink game.plink +#define abb game.abb +#define dseen game.dseen +#define dloc game.dloc +#define odloc game.odloc +#define tk game.tk +#define loc game.loc +#define newloc game.newloc +#define oldloc game.oldloc +#define oldlc2 game.oldlc2 +#define wzdark game.wzdark +#define gaveup game.gaveup +#define kq game.kq +#define k game.k +#define k2 game.k2 +#define verb game.verb +#define obj game.obj +#define spk game.spk +#define blklin game.blklin +#define saved game.saved +#define savet game.savet +#define mxscor game.mxscor +#define latncy game.latncy +#define clsses game.clsses +#define maxtrs game.maxtrs +#define tally game.tally +#define tally2 game.tally2 +#define keys game.keys +#define lamp game.lamp +#define grate game.grate +#define cage game.cage +#define rod game.rod +#define rod2 game.rod2 +#define steps game.steps +#define bird game.bird +#define door game.door +#define pillow game.pillow +#define snake game.snake +#define fissur game.fissur +#define tablet game.tablet +#define clam game.clam +#define oyster game.oyster +#define magzin game.magzin +#define dwarf game.dwarf +#define knife game.knife +#define food game.food +#define bottle game.bottle +#define water game.water +#define oil game.oil +#define plant game.plant +#define plant2 game.plant2 +#define axe game.axe +#define mirror game.mirror +#define dragon game.dragon +#define chasm game.chasm +#define troll game.troll +#define troll2 game.troll2 +#define bear game.bear +#define messag game.messag +#define vend game.vend +#define batter game.batter +#define nugget game.nugget +#define coins game.coins +#define chest game.chest +#define eggs game.eggs +#define tridnt game.tridnt +#define vase game.vase +#define emrald game.emrald +#define pyram game.pyram +#define pearl game.pearl +#define rug game.rug +#define chain game.chain +#define spices game.spices +#define back game.back +#define look game.look +#define cave game.cave +#define null game.null +#define entrnc game.entrnc +#define dprssn game.dprssn +#define say game.say +#define lock game.lock +#define throw game.throw +#define find game.find +#define invent game.invent +#define chloc game.chloc +#define chloc2 game.chloc2 +#define dflag game.dflag +#define daltlc game.daltlc +#define stick game.stick +#define dtotal game.dtotal +#define attack game.attack +#define turns game.turns +#define lmwarn game.lmwarn +#define iwest game.iwest +#define knfloc game.knfloc +#define detail game.detail +#define abbnum game.abbnum +#define maxdie game.maxdie +#define numdie game.numdie +#define holdng game.holdng +#define dkill game.dkill +#define foobar game.foobar +#define bonus game.bonus +#define clock1 game.clock1 +#define clock2 game.clock2 +#define closng game.closng +#define panic game.panic +#define closed game.closed +#define scorng game.scorng +#define newloc game.newloc +#define limit game.limit diff --git a/src/games/adventure/init.c b/src/games/adventure/init.c new file mode 100644 index 0000000..d7be918 --- /dev/null +++ b/src/games/adventure/init.c @@ -0,0 +1,150 @@ +/* + * Re-coding of advent in C: data initialization + */ +#include "hdr.h" +#include +#include +#include +#include +#include + +const short setbit[16] = { + 1, 2, 4, 010, 020,040, 0100, 0200, 0400, + 01000, 02000, 04000, 010000, 020000, 040000, 0100000, +}; + +void +linkdata() /* secondary data manipulation */ +{ register int i,j; + /* array linkages */ + for (i=1; i<=LOCSIZ; i++) + if (ltext[i].seekadr!=0 && travel[i] != 0) + if ((travel[i]->tverb)==1) cond[i]=2; + for (j=100; j>0; j--) + if (fixd[j]>0) + { drop(j+100,fixd[j]); + drop(j,plac[j]); + } + for (j=100; j>0; j--) + { fixed[j]=fixd[j]; + if (plac[j]!=0 && fixd[j]<=0) drop(j,plac[j]); + } + + maxtrs=79; + tally=0; + tally2=0; + + for (i=50; i<=maxtrs; i++) + { if (ptext[i].seekadr!=0) prop[i] = -1; + tally -= prop[i]; + } + + /* define mnemonics */ + keys=vocab("keys",1,0); + lamp=vocab("lamp",1,0); + grate=vocab("grate",1,0); + cage=vocab("cage",1,0); + rod=vocab("rod",1,0); + rod2=rod+1; + steps=vocab("steps",1,0); + bird=vocab("bird",1,0); + door=vocab("door",1,0); + pillow=vocab("pillow",1,0); + snake=vocab("snake",1,0); + fissur=vocab("fissu",1,0); + tablet=vocab("table",1,0); + clam=vocab("clam",1,0); + oyster=vocab("oyster",1,0); + magzin=vocab("magaz",1,0); + dwarf=vocab("dwarf",1,0); + knife=vocab("knife",1,0); + food=vocab("food",1,0); + bottle=vocab("bottl",1,0); + water=vocab("water",1,0); + oil=vocab("oil",1,0); + plant=vocab("plant",1,0); + plant2=plant+1; + axe=vocab("axe",1,0); + mirror=vocab("mirro",1,0); + dragon=vocab("drago",1,0); + chasm=vocab("chasm",1,0); + troll=vocab("troll",1,0); + troll2=troll+1; + bear=vocab("bear",1,0); + messag=vocab("messa",1,0); + vend=vocab("vendi",1,0); + batter=vocab("batte",1,0); + + nugget=vocab("gold",1,0); + coins=vocab("coins",1,0); + chest=vocab("chest",1,0); + eggs=vocab("eggs",1,0); + tridnt=vocab("tride",1,0); + vase=vocab("vase",1,0); + emrald=vocab("emera",1,0); + pyram=vocab("pyram",1,0); + pearl=vocab("pearl",1,0); + rug=vocab("rug",1,0); + chain=vocab("chain",1,0); + + back=vocab("back",0,0); + look=vocab("look",0,0); + cave=vocab("cave",0,0); + null=vocab("null",0,0); + entrnc=vocab("entra",0,0); + dprssn=vocab("depre",0,0); + + say=vocab("say",2,0); + lock=vocab("lock",2,0); + throw=vocab("throw",2,0); + find=vocab("find",2,0); + invent=vocab("inven",2,0); + /* initialize dwarves */ + chloc=114; + chloc2=140; + for (i=1; i<=6; i++) + dseen[i]=FALSE; + dflag=0; + dloc[1]=19; + dloc[2]=27; + dloc[3]=33; + dloc[4]=44; + dloc[5]=64; + dloc[6]=chloc; + daltlc=18; + + /* random flags & ctrs */ + turns=0; + lmwarn=FALSE; + iwest=0; + knfloc=0; + detail=0; + abbnum=5; + for (i=0; i<=4; i++) + if (rtext[2*i+81].seekadr!=0) maxdie=i+1; + numdie=holdng=dkill=foobar=bonus=0; + clock1=30; + clock2=50; + saved=0; + closng=panic=closed=scorng=FALSE; +} + +void +trapdel(sig) /* come here if he hits a del */ +{ delhit++; /* main checks, treats as QUIT */ + signal(2,trapdel); /* catch subsequent DELs */ +} + +void +startup() +{ + time_t now; + + time(&now); + srand(now); /* random odd seed */ +/* srand(371); */ /* non-random seed */ + hinted[3] = yes(65, 1, 0); + newloc = 1; + limit = 330; + if (hinted[3]) limit = 1000; /* better batteries if instrucs */ +} diff --git a/src/games/adventure/io.c b/src/games/adventure/io.c new file mode 100644 index 0000000..beadc11 --- /dev/null +++ b/src/games/adventure/io.c @@ -0,0 +1,487 @@ +/* + * Re-coding of advent in C: file i/o and user i/o + */ +#include "hdr.h" +#include + +int seekhere = 1; /* initial seek for output file */ + +FILE *inbuf, *outbuf; + +int adrptr; /* current seek adr ptr */ +int outsw = 0; /* putting stuff to data file? */ + +const char iotape[] = "Ax3F'tt$8hqer*hnGKrX:!l"; +const char *tape = iotape; /* pointer to encryption tape */ + +char breakch; /* tell which char ended rnum */ + +char nbf[12]; + +int +next() /* next char frm file, bump adr */ +{ register char ch; + adrptr++; /* seek address in file */ + ch=getc(inbuf); + if (outsw) /* putting data in tmp file */ + { if (*tape==0) tape=iotape; /* rewind encryption tape */ + putc(ch ^ *tape++,outbuf); /* encrypt & output char */ + } + return(ch); +} + +int +rnum() /* read initial location num */ +{ register char *s; + tape = iotape; /* restart encryption tape */ + for (s=nbf,*s=0;; s++) + if ((*s=next())==TAB || *s=='\n' || *s==LF) + break; + breakch= *s; /* save char for rtrav() */ + *s=0; /* got the number as ascii */ + if (nbf[0]=='-') return(-1); /* end of data */ + return(atoi(nbf)); /* convert it to integer */ +} + +void +rtrav() /* read travel table */ +{ register int locc; + register struct travlist *t = 0; + register char *s; + char buf[12]; + int len, m, n, entries = 0; + for (oldloc= -1;;) /* get another line */ + { if ((locc=rnum())!=oldloc && oldloc>=0) /* end of entry */ + { + t->next = 0; /* terminate the old entry */ + /* printf("%d:%d entries\n",oldloc,entries); */ + /* twrite(oldloc); */ + } + if (locc== -1) return; + if (locc!=oldloc) /* getting a new entry */ + { t = (struct travlist *) malloc(sizeof(*t)); + travel[locc] = t; + /* printf("New travel list for %d\n",locc); */ + entries=0; + oldloc=locc; + } + for (s=buf; *s; s++) /* get the newloc number /ASCII */ + if ((*s=next())==TAB || *s==LF) break; + *s=0; + len=length(buf)-1; /* quad long number handling */ + /* printf("Newloc: %s (%d chars)\n",buf,len); */ + if (len<4) /* no "m" conditions */ + { m=0; + n=atoi(buf); /* newloc mod 1000 = newloc */ + } + else /* a long integer */ + { n=atoi(buf+len-3); + buf[len-3]=0; /* terminate newloc/1000 */ + m=atoi(buf); + } + while (breakch!=LF) /* only do one line at a time */ + { if (entries++) { + t->next = (struct travlist *) malloc(sizeof (*t)); + t = t->next; + } + t->tverb=rnum();/* get verb from the file */ + t->tloc=n; /* table entry mod 1000 */ + t->conditions=m;/* table entry / 1000 */ + /* printf("entry %d for %d\n",entries,locc); */ + } + } +} + +void +rdesc(sect) /* read description-format msgs */ +int sect; +{ + register int locc; + int seekstart, maystart; + outsw=1; /* these msgs go into tmp file */ + if (sect==1) putc('X',outbuf); /* so seekadr > 0 */ + adrptr=0; + for (oldloc= -1, seekstart=seekhere;;) + { maystart=adrptr; /* maybe starting new entry */ + if ((locc=rnum())!=oldloc && oldloc>=0 /* finished msg */ + && ! (sect==5 && (locc==0 || locc>=100)))/* unless sect 5*/ + { switch(sect) /* now put it into right table */ + { case 1: /* long descriptions */ + ltext[oldloc].seekadr=seekhere; + ltext[oldloc].txtlen=maystart-seekstart; + break; + case 2: /* short descriptions */ + stext[oldloc].seekadr=seekhere; + stext[oldloc].txtlen=maystart-seekstart; + break; + case 5: /* object descriptions */ + ptext[oldloc].seekadr=seekhere; + ptext[oldloc].txtlen=maystart-seekstart; + break; + case 6: /* random messages */ + if (oldloc>RTXSIZ) + { printf("Too many random msgs\n"); + exit(0); + } + rtext[oldloc].seekadr=seekhere; + rtext[oldloc].txtlen=maystart-seekstart; + break; + case 10: /* class messages */ + ctext[clsses].seekadr=seekhere; + ctext[clsses].txtlen=maystart-seekstart; + cval[clsses++]=oldloc; + break; + case 12: /* magic messages */ + if (oldloc>MAGSIZ) + { printf("Too many magic msgs\n"); + exit(0); + } + mtext[oldloc].seekadr=seekhere; + mtext[oldloc].txtlen=maystart-seekstart; + break; + default: + printf("rdesc called with bad section\n"); + exit(0); + } + seekhere += maystart-seekstart; + } + if (locc<0) + { outsw=0; /* turn off output */ + seekhere += 3; /* -1 */ + return; + } + if (sect!=5 || (locc>0 && locc<100)) + { if (oldloc!=locc)/* starting a new message */ + seekstart=maystart; + oldloc=locc; + } + FLUSHLF; /* scan the line */ + } +} + +void +getin(wrd1, wrd2) /* get command from user */ +char **wrd1, **wrd2; /* no prompt, usually */ +{ register char *s; + static char wd1buf[MAXSTR],wd2buf[MAXSTR]; + int first, numch; + + *wrd1=wd1buf; /* return ptr to internal string*/ + *wrd2=wd2buf; + wd2buf[0]=0; /* in case it isn't set here */ + for (s=wd1buf, first=1, numch=0;;) + { if ((*s=getchar())>='A' && *s <='Z') *s = *s - ('A' -'a'); + /* convert to upper case */ + if (feof(stdin)) { + clearerr(stdin); + continue; + } + switch(*s) /* start reading from user */ + { case '\n': + *s=0; + return; + case ' ': + if (s==wd1buf||s==wd2buf) /* initial blank */ + continue; + *s=0; + if (first) /* finished 1st wd; start 2nd */ + { first=numch=0; + s=wd2buf; + break; + } + else /* finished 2nd word */ + { FLUSHLINE; + *s=0; + return; + } + default: + if (++numch>=MAXSTR) /* string too long */ + { printf("Give me a break!!\n"); + wd1buf[0]=wd2buf[0]=0; + FLUSHLINE; + return; + } + s++; + } + } +} + +int +confirm(mesg) /* confirm irreversible action */ +char *mesg; +{ register int result; + printf("%s",mesg); /* tell him what he did */ + if (getchar()=='y') /* was his first letter a 'y'? */ + result=1; + else result=0; + FLUSHLINE; + return(result); +} + +int +yes(x, y, z) /* confirm with rspeak */ +int x, y, z; +{ register int result = -1; + register char ch; + for (;;) + { rspeak(x); /* tell him what we want*/ + if ((ch=getchar())=='y') + result=TRUE; + else if (ch=='n') result=FALSE; + FLUSHLINE; + if (ch=='y'|| ch=='n') break; + printf("Please answer the question.\n"); + } + if (result==TRUE) rspeak(y); + if (result==FALSE) rspeak(z); + return(result); +} + +int +yesm(x, y, z) /* confirm with mspeak */ +int x, y, z; +{ register int result = -1; + register char ch; + for (;;) + { mspeak(x); /* tell him what we want*/ + if ((ch=getchar())=='y') + result=TRUE; + else if (ch=='n') result=FALSE; + FLUSHLINE; + if (ch=='y'|| ch=='n') break; + printf("Please answer the question.\n"); + } + if (result==TRUE) mspeak(y); + if (result==FALSE) mspeak(z); + return(result); +} + +void +rvoc() +{ register char *s; /* read the vocabulary */ + register int index; + char buf[6]; + for (;;) + { index=rnum(); + if (index<0) break; + for (s=buf,*s=0;; s++) /* get the word */ + if ((*s=next())==TAB || *s=='\n' || *s==LF + || *s==' ') break; + /* terminate word with newline, LF, tab, blank */ + if (*s!='\n' && *s!=LF) FLUSHLF; /* can be comments */ + *s=0; + /* printf("\"%s\"=%d\n",buf,index);*/ + vocab(buf,-2,index); + } +/* prht(); */ +} + +void +rlocs() /* initial object locations */ +{ for (;;) + { if ((obj=rnum())<0) break; + plac[obj]=rnum(); /* initial loc for this obj */ + if (breakch==TAB) /* there's another entry */ + fixd[obj]=rnum(); + else fixd[obj]=0; + } +} + +void +rdflt() /* default verb messages */ +{ for (;;) + { if ((verb=rnum())<0) break; + actspk[verb]=rnum(); + } +} + +void +rliq() /* liquid assets &c: cond bits */ +{ register int bitnum; + for (;;) /* read new bit list */ + { if ((bitnum=rnum())<0) break; + for (;;) /* read locs for bits */ + { cond[rnum()] |= setbit[bitnum]; + if (breakch==LF) break; + } + } +} + +void +rhints() +{ register int hintnum,i; + hntmax=0; + for (;;) + { if ((hintnum=rnum())<0) break; + for (i=1; i<5; i++) + hints[hintnum][i]=rnum(); + if (hintnum>hntmax) hntmax=hintnum; + } +} + +void +rdata(infile, outfile) /* read all data from orig file */ +char *infile, *outfile; /* datfile we were called with */ +{ register int sect; + register char ch; + inbuf = fopen(infile, "r"); + if (inbuf == NULL) /* all the data lives in here */ + { printf("Cannot open data file %s\n", infile); + exit(0); + } + outbuf = fopen(outfile, "w"); + if (outbuf == NULL) /* the text lines will go here */ + { printf("Cannot create output file %s\n", outfile); + exit(0); + } + clsses = 1; + for (;;) /* read data sections */ + { sect=next()-'0'; /* 1st digit of section number */ + //printf("Section %c",sect+'0'); + if ((ch=next())!=LF) /* is there a second digit? */ + { FLUSHLF; + //putchar(ch); + sect=10*sect+ch-'0'; + } + //putchar('\n'); + switch(sect) + { case 0: /* finished reading database */ + fclose(inbuf); + fclose(outbuf); + return; + case 1: /* long form descriptions */ + rdesc(1); + break; + case 2: /* short form descriptions */ + rdesc(2); + break; + case 3: /* travel table */ + rtrav(); break; + case 4: /* vocabulary */ + rvoc(); + break; + case 5: /* object descriptions */ + rdesc(5); + break; + case 6: /* arbitrary messages */ + rdesc(6); + break; + case 7: /* object locations */ + rlocs(); break; + case 8: /* action defaults */ + rdflt(); break; + case 9: /* liquid assets */ + rliq(); break; + case 10: /* class messages */ + rdesc(10); + break; + case 11: /* hints */ + rhints(); break; + case 12: /* magic messages */ + rdesc(12); + break; + default: + printf("Invalid data section number: %d\n",sect); + for (;;) putchar(next()); + } + if (breakch!=LF) /* routines return after "-1" */ + FLUSHLF; + } +} + +void +twrite(loq) /* travel options from this loc */ +int loq; +{ register struct travlist *t; + printf("If"); + speak(<ext[loq]); + printf("then\n"); + for (t=travel[loq]; t!=0; t=t->next) + { printf("verb %d takes you to ",t->tverb); + if (t->tloc<=300) + speak(<ext[t->tloc]); + else if (t->tloc<=500) + printf("special code %d\n",t->tloc-300); + else + rspeak(t->tloc-500); + printf("under conditions %d\n",t->conditions); + } +} + +void +rspeak(msg) +int msg; +{ if (msg!=0) speak(&rtext[msg]); +} + +void +mspeak(msg) +int msg; +{ if (msg!=0) speak(&mtext[msg]); +} + +void +speak(msg) /* read, decrypt, and print a message (not ptext) */ +struct text *msg;/* msg is a pointer to seek address and length of mess */ +{ register char *s,nonfirst; + register char *tbuf; + lseek(datfd, (off_t) msg->seekadr, 0); + tbuf = (char *) alloca(msg->txtlen + 1); + if (read(datfd,tbuf,msg->txtlen) != msg->txtlen) { + printf("Corrupted dat file!\n"); + return; + } + s=tbuf; + nonfirst=0; + while (s-tbuftxtlen) /* read a line at a time */ + { tape=iotape; /* restart decryption tape */ + while ((*s++^*tape++)!=TAB); /* read past loc num */ + /* assume tape is longer than location number */ + /* plus the lookahead put together */ + if ((*s^*tape)=='>' && + (*(s+1)^*(tape+1))=='$' && + (*(s+2)^*(tape+2))=='<') break; + if (blklin&&!nonfirst++) putchar('\n'); + do + { if (*tape==0) tape=iotape;/* rewind decryp tape */ + putchar(*s^*tape); + } while ((*s++^*tape++)!=LF); /* better end with LF */ + } +} + +void +pspeak(msg, skip) /* read, decrypt an print a ptext message */ +int msg; /* msg is the number of all the p msgs for this place */ +int skip; /* assumes object 1 doesn't have prop 1, obj 2 no prop 2 &c*/ +{ register char *s, nonfirst; + register char *tbuf; + char *numst; + int lstr; + lseek(datfd, (off_t) ptext[msg].seekadr, 0); + lstr = ptext[msg].txtlen; + tbuf = (char *) alloca(lstr + 1); + if (read(datfd,tbuf,lstr) != lstr) { + printf("Corrupted dat file!\n"); + return; + } + s=tbuf; + nonfirst=0; + while (s-tbuf=0) + { while ((*s++^*tape++)!=LF) /* flush the line */ + if (*tape==0) tape=iotape; + continue; + } + if ((*s^*tape)=='>' && (*(s+1)^*(tape+1))=='$' && + (*(s+2)^*(tape+2))=='<') break; + if (blklin && ! nonfirst++) putchar('\n'); + do + { if (*tape==0) tape=iotape; + putchar(*s^*tape); + } while ((*s++^*tape++)!=LF); /* better end with LF */ + if (skip<0) break; + } +} diff --git a/src/games/adventure/main.c b/src/games/adventure/main.c new file mode 100644 index 0000000..d62dfe7 --- /dev/null +++ b/src/games/adventure/main.c @@ -0,0 +1,549 @@ +/* + * Re-coding of advent in C: main program + */ +#include "hdr.h" +#include +#include +#include +#include + +int datfd; + +int +main(argc, argv) +int argc; +char **argv; +{ register int i; + int rval; + struct text *kk; + char *savfile = 0; + + if (argc > 1) + savfile = argv[1]; + + if (savfile != 0 && strcmp(savfile, DATFILE) == 0) { + /* read data from orig. file and write to datfile */ + rdata(DATFILE, "adventure.dat"); + linkdata(); + poof(); + save("adventure.dat", DATSIZE); + exit(0); + } + /* try local file first */ + datfd = open("adventure.dat", O_RDONLY); + if (datfd < 0) + datfd = open("/games/lib/adventure.dat", O_RDONLY); + if (datfd < 0) { + printf("No adventure just now\n"); + exit(0); + } + setuid(getuid()); + signal(SIGINT, trapdel); + + if (savfile != 0) { + if (restore(savfile)) { + start(0); /* restarting game : 8305 */ + k = null; + goto l8; + } + printf("Your forged file dissappears in a puff of greasy black smoke! (poof)\n"); + unlink(savfile); + exit(0); + } + if (! restdat(datfd, DATSIZE)) { + printf("Corrupted dat file\n"); + exit(0); + } + start(0); + startup(); /* prepare for a user */ + blklin = TRUE; + + for (;;) /* main command loop (label 2) */ + { if (newloc<9 && newloc!=0 && closng) + { rspeak(130); /* if closing leave only by */ + newloc=loc; /* main office */ + if (!panic) clock2=15; + panic=TRUE; + } + + rval=fdwarf(); /* dwarf stuff */ + if (rval==99) die(99); + + l2000: if (loc==0) die(99); /* label 2000 */ + kk = &stext[loc]; + if ((abb[loc]%abbnum)==0 || kk->seekadr==0) + kk = <ext[loc]; + if (!forced(loc) && dark(0)) + { if (wzdark && pct(35)) + { die(90); + goto l2000; + } + kk = &rtext[16]; + } + if (toting(bear)) rspeak(141); /* 2001 */ + speak(kk); + k=1; + if (forced(loc)) + goto l8; + if (loc==33 && pct(25)&&!closng) rspeak(8); + if (!dark(0)) + { abb[loc]++; + for (i=atloc[loc]; i!=0; i=plink[i]) /*2004 */ + { obj=i; + if (obj>100) obj -= 100; + if (obj==steps && toting(nugget)) continue; + if (prop[obj]<0) + { if (closed) continue; + prop[obj]=0; + if (obj==rug||obj==chain) + prop[obj]=1; + tally--; + if (tally==tally2 && tally != 0) + if (limit>35) limit=35; + } + int pk = prop[obj]; /* 2006 */ + if (obj==steps && loc==fixed[steps]) + pk = 1; + pspeak(obj, pk); + } /* 2008 */ + goto l2012; + l2009: k=54; /* 2009 */ + l2010: spk=k; + l2011: rspeak(spk); + } + l2012: verb=0; /* 2012 */ + obj=0; + l2600: checkhints(); /* to 2600-2602 */ + if (closed) + { if (prop[oyster]<0 && toting(oyster)) + pspeak(oyster,1); + for (i=1; i<100; i++) + if (toting(i)&&prop[i]<0) /*2604 */ + prop[i] = -1-prop[i]; + } + wzdark=dark(0); /* 2605 */ + if (knfloc>0 && knfloc!=loc) knfloc=1; + getin(&wd1,&wd2); + if (delhit) /* user typed a DEL */ + { delhit=0; /* reset counter */ + copystr("quit",wd1); /* pretend he's quitting*/ + *wd2=0; + } + l2608: if ((foobar = -foobar)>0) foobar=0; /* 2608 */ + /* should check here for "magic mode" */ + turns++; + + if (verb==say && *wd2!=0) verb=0; + if (verb==say) + goto l4090; + if (tally==0 && loc>=15 && loc!=33) clock1--; + if (clock1==0) + { closing(); /* to 10000 */ + goto l19999; + } + if (clock1<0) clock2--; + if (clock2==0) + { caveclose(); /* to 11000 */ + continue; /* back to 2 */ + } + if (prop[lamp]==1) limit--; + if (limit<=30 && here(batter) && prop[batter]==0 + && here(lamp)) + { rspeak(188); /* 12000 */ + prop[batter]=1; + if (toting(batter)) drop(batter,loc); + limit=limit+2500; + lmwarn=FALSE; + goto l19999; + } + if (limit==0) + { limit = -1; /* 12400 */ + prop[lamp]=0; + rspeak(184); + goto l19999; + } + if (limit<0&&loc<=8) + { rspeak(185); /* 12600 */ + gaveup=TRUE; + done(2); /* to 20000 */ + } + if (limit<=30) + { if (lmwarn|| !here(lamp)) goto l19999; /*12200*/ + lmwarn=TRUE; + spk=187; + if (place[batter]==0) spk=183; + if (prop[batter]==1) spk=189; + rspeak(spk); + } + l19999: k=43; + if (liqloc(loc)==water) k=70; + if (weq(wd1,"enter") && + (weq(wd2,"strea")||weq(wd2,"water"))) + goto l2010; + if (weq(wd1,"enter") && *wd2!=0) goto l2800; + if ((!weq(wd1,"water")&&!weq(wd1,"oil")) + || (!weq(wd2,"plant")&&!weq(wd2,"door"))) + goto l2610; + if (at(vocab(wd2,1,0))) copystr("pour",wd2); + l2610: if (weq(wd1,"west")) + if (++iwest==10) rspeak(17); + l2630: i=vocab(wd1,-1,0); + if (i== -1) + { spk=60; /* 3000 */ + if (pct(20)) spk=61; + if (pct(20)) spk=13; + rspeak(spk); + goto l2600; + } + k=i%1000; + kq=i/1000+1; + switch(kq) + { case 1: goto l8; + case 2: goto l5000; + case 3: goto l4000; + case 4: goto l2010; + default: + printf("Error 22\n"); + exit(0); + } + + l8: + switch(march()) + { case 2: continue; /* i.e. goto l2 */ + case 99: + switch(die(99)) + { case 2000: goto l2000; + default: bug(111); + } + default: bug(110); + } + + l2800: copystr(wd2,wd1); + *wd2=0; + goto l2610; + + l4000: verb=k; + spk=actspk[verb]; + if (*wd2!=0 && verb!=say) goto l2800; + if (verb==say) obj= *wd2; + if (obj!=0) goto l4090; + + switch(verb) + { case 1: /* take = 8010 */ + if (atloc[loc]==0||plink[atloc[loc]]!=0) goto l8000; + for (i=1; i<=5; i++) + if (dloc[i]==loc&&dflag>=2) goto l8000; + obj=atloc[loc]; + goto l9010; + case 2: case 3: case 9: /* 8000 : drop,say,wave */ + case 10: case 16: case 17: /* calm,rub,toss */ + case 19: case 21: case 28: /* find,feed,break */ + case 29: /* wake */ + l8000: printf("%s what?\n",wd1); + obj=0; + goto l2600; + case 4: case 6: /* 8040 open,lock */ + spk=28; + if (here(clam)) obj=clam; + if (here(oyster)) obj=oyster; + if (at(door)) obj=door; + if (at(grate)) obj=grate; + if (obj!=0 && here(chain)) goto l8000; + if (here(chain)) obj=chain; + if (obj==0) goto l2011; + goto l9040; + case 5: goto l2009; /* nothing */ + case 7: goto l9070; /* on */ + case 8: goto l9080; /* off */ + case 11: goto l8000; /* walk */ + case 12: goto l9120; /* kill */ + case 13: goto l9130; /* pour */ + case 14: /* eat: 8140 */ + if (!here(food)) goto l8000; + l8142: dstroy(food); + spk=72; + goto l2011; + case 15: goto l9150; /* drink */ + case 18: /* quit: 8180 */ + gaveup=yes(22,54,54); + if (gaveup) done(2); /* 8185 */ + goto l2012; + case 20: /* invent=8200 */ + spk=98; + for (i=1; i<=100; i++) + { if (i!=bear && toting(i)) + { if (spk==98) rspeak(99); + blklin=FALSE; + pspeak(i,-1); + blklin=TRUE; + spk=0; + } + } + if (toting(bear)) spk=141; + goto l2011; + case 22: goto l9220; /* fill */ + case 23: goto l9230; /* blast */ + case 24: /* score: 8240 */ + scorng=TRUE; + printf("If you were to quit now, you would score"); + printf(" %d out of a possible ",score()); + printf("%d.",mxscor); + scorng=FALSE; + gaveup=yes(143,54,54); + if (gaveup) done(2); + goto l2012; + case 25: /* foo: 8250 */ + k=vocab(wd1,3,0); + spk=42; + if (foobar==1-k) goto l8252; + if (foobar!=0) spk=151; + goto l2011; + l8252: foobar=k; + if (k!=4) goto l2009; + foobar=0; + if (place[eggs]==plac[eggs] + ||(toting(eggs)&&loc==plac[eggs])) goto l2011; + if (place[eggs]==0&&place[troll]==0&&prop[troll]==0) + prop[troll]=1; + k=2; + if (here(eggs)) k=1; + if (loc==plac[eggs]) k=0; + move(eggs,plac[eggs]); + pspeak(eggs,k); + goto l2012; + case 26: /* brief=8260 */ + spk=156; + abbnum=10000; + detail=3; + goto l2011; + case 27: /* read=8270 */ + if (here(magzin)) obj=magzin; + if (here(tablet)) obj=obj*100+tablet; + if (here(messag)) obj=obj*100+messag; + if (closed&&toting(oyster)) obj=oyster; + if (obj>100||obj==0||dark(0)) goto l8000; + goto l9270; + case 30: /* suspend=8300 */ + spk=201; + printf("I can suspend your adventure for you so"); + printf(" you can resume later, but\n"); + printf("you will have to wait at least"); + printf(" %d minutes before continuing.",latncy); + if (!yes(200,54,54)) goto l2012; + datime(&saved, &savet); + ciao(); + continue; + case 31: /* hours=8310 */ + printf("Colossal cave is closed 9am-5pm Mon "); + printf("through Fri except holidays.\n"); + goto l2012; + default: bug(23); + } + + l4090: + switch(verb) + { case 1: /* take = 9010 */ + l9010: switch(trtake()) + { case 2011: goto l2011; + case 9220: goto l9220; + case 2009: goto l2009; + case 2012: goto l2012; + default: bug(102); + } + l9020: case 2: /* drop = 9020 */ + switch(trdrop()) + { case 2011: goto l2011; + case 19000: done(3); + case 2012: goto l2012; + default: bug(105); + } + case 3: + switch(trsay()) + { case 2012: goto l2012; + case 2630: goto l2630; + default: bug(107); + } + l9040: case 4: case 6: /* open, close */ + switch(tropen()) + { case 2011: goto l2011; + case 2010: goto l2010; + default: bug(106); + } + case 5: goto l2009; /* nothing */ + case 7: /* on 9070 */ + l9070: if (!here(lamp)) goto l2011; + spk=184; + if (limit<0) goto l2011; + prop[lamp]=1; + rspeak(39); + if (wzdark) goto l2000; + goto l2012; + + case 8: /* off */ + l9080: if (!here(lamp)) goto l2011; + prop[lamp]=0; + rspeak(40); + if (dark(0)) rspeak(16); + goto l2012; + + case 9: /* wave */ + if ((!toting(obj))&&(obj!=rod||!toting(rod2))) + spk=29; + if (obj!=rod||!at(fissur)||!toting(obj)||closng) + goto l2011; + prop[fissur]=1-prop[fissur]; + pspeak(fissur,2-prop[fissur]); + goto l2012; + case 10: case 11: case 18: /* calm, walk, quit */ + case 24: case 25: case 26: /* score, foo, brief */ + case 30: case 31: /* suspend, hours */ + goto l2011; + l9120: case 12: /* kill */ + switch(trkill()) + { case 8000: goto l8000; + case 8: goto l8; + case 2011: goto l2011; + case 2608: goto l2608; + case 19000: done(3); + default: bug(112); + } + l9130: case 13: /* pour */ + if (obj==bottle||obj==0) obj=liq(0); + if (obj==0) goto l8000; + if (!toting(obj)) goto l2011; + spk=78; + if (obj!=oil&&obj!=water) goto l2011; + prop[bottle]=1; + place[obj]=0; + spk=77; + if (!(at(plant)||at(door))) goto l2011; + if (at(door)) + { prop[door]=0; /* 9132 */ + if (obj==oil) prop[door]=1; + spk=113+prop[door]; + goto l2011; + } + spk=112; + if (obj!=water) goto l2011; + pspeak(plant,prop[plant]+1); + prop[plant]=(prop[plant]+2)% 6; + prop[plant2]=prop[plant]/2; + k=null; + goto l8; + case 14: /* 9140 - eat */ + if (obj==food) goto l8142; + if (obj==bird||obj==snake||obj==clam||obj==oyster + ||obj==dwarf||obj==dragon||obj==troll + ||obj==bear) spk=71; + goto l2011; + l9150: case 15: /* 9150 - drink */ + if (obj==0&&liqloc(loc)!=water&&(liq(0)!=water + ||!here(bottle))) goto l8000; + if (obj!=0&&obj!=water) spk=110; + if (spk==110||liq(0)!=water||!here(bottle)) + goto l2011; + prop[bottle]=1; + place[water]=0; + spk=74; + goto l2011; + case 16: /* 9160: rub */ + if (obj!=lamp) spk=76; + goto l2011; + case 17: /* 9170: throw */ + switch(trtoss()) + { case 2011: goto l2011; + case 9020: goto l9020; + case 9120: goto l9120; + case 8: goto l8; + case 9210: goto l9210; + default: bug(113); + } + case 19: case 20: /* 9190: find, invent */ + if (at(obj)||(liq(0)==obj&&at(bottle)) + ||k==liqloc(loc)) spk=94; + for (i=1; i<=5; i++) + if (dloc[i]==loc&&dflag>=2&&obj==dwarf) + spk=94; + if (closed) spk=138; + if (toting(obj)) spk=24; + goto l2011; + l9210: case 21: /* feed */ + switch(trfeed()) + { case 2011: goto l2011; + default: bug(114); + } + l9220: case 22: /* fill */ + switch(trfill()) + { case 2011: goto l2011; + case 8000: goto l8000; + case 9020: goto l9020; + default: bug(115); + } + l9230: case 23: /* blast */ + if (prop[rod2]<0||!closed) goto l2011; + bonus=133; + if (loc==115) bonus=134; + if (here(rod2)) bonus=135; + rspeak(bonus); + done(2); + l9270: case 27: /* read */ + if (dark(0)) goto l5190; + if (obj==magzin) spk=190; + if (obj==tablet) spk=196; + if (obj==messag) spk=191; + if (obj==oyster&&hinted[2]&&toting(oyster)) spk=194; + if (obj!=oyster||hinted[2]||!toting(oyster) + ||!closed) goto l2011; + hinted[2]=yes(192,193,54); + goto l2012; + case 28: /* break */ + if (obj==mirror) spk=148; + if (obj==vase&&prop[vase]==0) + { spk=198; + if (toting(vase)) drop(vase,loc); + prop[vase]=2; + fixed[vase]= -1; + goto l2011; + } + if (obj!=mirror||!closed) goto l2011; + rspeak(197); + done(3); + + case 29: /* wake */ + if (obj!=dwarf||!closed) goto l2011; + rspeak(199); + done(3); + + default: bug(24); + } + + l5000: + obj=k; + if (fixed[k]!=loc && !here(k)) goto l5100; + l5010: if (*wd2!=0) goto l2800; + if (verb!=0) goto l4090; + printf("What do you want to do with the %s?\n",wd1); + goto l2600; + l5100: if (k!=grate) goto l5110; + if (loc==1||loc==4||loc==7) k=dprssn; + if (loc>9&&loc<15) k=entrnc; + if (k!=grate) goto l8; + l5110: if (k!=dwarf) goto l5120; + for (i=1; i<=5; i++) + if (dloc[i]==loc&&dflag>=2) goto l5010; + l5120: if ((liq(0)==k&&here(bottle))||k==liqloc(loc)) goto l5010; + if (obj!=plant||!at(plant2)||prop[plant2]==0) goto l5130; + obj=plant2; + goto l5010; + l5130: if (obj!=knife||knfloc!=loc) goto l5140; + knfloc = -1; + spk=116; + goto l2011; + l5140: if (obj!=rod||!here(rod2)) goto l5190; + obj=rod2; + goto l5010; + l5190: if ((verb==find||verb==invent)&&*wd2==0) goto l5010; + printf("I see no %s here\n",wd1); + goto l2012; + } +} diff --git a/src/games/adventure/save.c b/src/games/adventure/save.c new file mode 100644 index 0000000..f72eab5 --- /dev/null +++ b/src/games/adventure/save.c @@ -0,0 +1,95 @@ +/* + * save (III) J. Gillogly + * save user core image for restarting + */ +#include "hdr.h" +#include +#include + +void +save(savfile, offset) /* save game state to file */ +char *savfile; +unsigned offset; +{ + int fd, i; + struct travlist *entry; + + if (offset == 0) + fd = creat(savfile, 0644); + else + fd = open(savfile, O_WRONLY); + if (fd < 0) { + printf("Cannot write to %s\n", savfile); + exit(0); + } + if (offset != 0) { /* use offset */ + lseek (fd, (off_t) offset, SEEK_SET); + } + write(fd, &game, sizeof game); /* write all game data */ + + for (i=0; inext, entry->conditions, entry->tloc, entry->tverb);*/ + write(fd, entry, sizeof(*entry)); + entry = entry->next; + } + } + printf("Saved %u bytes to %s\n", + (unsigned) lseek(fd, (off_t) 0, SEEK_CUR), savfile); + close(fd); +} + +int +restdat(fd, offset) /* restore game from dat file */ +int fd; +unsigned offset; +{ + int i; + struct travlist **entryp; + + if (offset != 0) /* use offset */ + lseek (fd, (off_t) offset, SEEK_SET); + + /* read all game data */ + if (read(fd, &game, sizeof game) != sizeof game) { +failed: close(fd); + return 0; + } + + for (i=0; inext, (*entryp)->conditions, + (*entryp)->tloc, (*entryp)->tverb);*/ + entryp = &(*entryp)->next; + } + } + return 1; +} + +int +restore(savfile) /* restore game from user file */ +char *savfile; +{ + int fd; + + fd = open(savfile, O_RDONLY); + if (fd < 0) + return 0; + if (! restdat(fd, 0)) + return 0; + close(fd); + return 1; +} diff --git a/src/games/adventure/subr.c b/src/games/adventure/subr.c new file mode 100644 index 0000000..23d9b0b --- /dev/null +++ b/src/games/adventure/subr.c @@ -0,0 +1,801 @@ +/* + * Re-coding of advent in C: subroutines from main + */ +#include "hdr.h" + +/* Statement functions */ + +int +toting(objj) +int objj; +{ if (place[objj] == -1) return(TRUE); + else return(FALSE); +} + +int +here(objj) +int objj; +{ if (place[objj]==loc || toting(objj)) return(TRUE); + else return(FALSE); +} + +int +at(objj) +int objj; +{ if (place[objj]==loc || fixed[objj]==loc) return(TRUE); + else return (FALSE); +} + +int +liq2(pbotl) +int pbotl; +{ return((1-pbotl)*water+(pbotl/2)*(water+oil)); +} + +int +liq(foo) +{ register int i; + i=prop[bottle]; + if (i>-1-i) return(liq2(i)); + else return(liq2(-1-i)); +} + +int +liqloc(locc) /* may want to clean this one up a bit */ +int locc; +{ register int i,j,l; + i=cond[locc]/2; + j=((i*2)%8)-5; + l=cond[locc]/4; + l=l%2; + return(liq2(j*l+1)); +} + +int +bitset(l,n) +int l,n; +{ if (cond[l] & setbit[n]) return(TRUE); + return(FALSE); +} + +int +forced(locc) +int locc; +{ if (cond[locc]==2) return(TRUE); + return(FALSE); +} + +int +dark(foo) +{ if ((cond[loc]%2)==0 && (prop[lamp]==0 || !here(lamp))) + return(TRUE); + return(FALSE); +} + +int +pct(n) +int n; +{ if (ran(100)=15) dflag=1; + return(2000); + } + if (dflag==1) /* 6000 */ + { if (loc<15||pct(95)) return(2000); + dflag=2; + for (i=1; i<=2; i++) + { j=1+ran(5); + if (pct(50)&&saved== -1) dloc[j]=0; /* 6001 */ + } + for (i=1; i<=5; i++) + { if (dloc[i]==loc) dloc[i]=daltlc; + odloc[i]=dloc[i]; /* 6002 */ + } + rspeak(3); + drop(axe,loc); + return(2000); + } + dtotal=attack=stick=0; /* 6010 */ + for (i=1; i<=6; i++) /* loop to 6030 */ + { if (dloc[i]==0) continue; + j=1; + for (kk=travel[dloc[i]]; kk!=0; kk=kk->next) + { newloc=kk->tloc; + if (newloc>300||newloc<15||newloc==odloc[i] + ||(j>1&&newloc==tk[j-1])||j>=20 + ||newloc==dloc[i]||forced(newloc) + ||(i==6&&bitset(newloc,3)) + ||kk->conditions==100) continue; + tk[j++]=newloc; + } + tk[j]=odloc[i]; /* 6016 */ + if (j>=2) j--; + j=1+ran(j); + odloc[i]=dloc[i]; + dloc[i]=tk[j]; + dseen[i]=(dseen[i]&&loc>=15)||(dloc[i]==loc||odloc[i]==loc); + if (!dseen[i]) continue; /* i.e. goto 6030 */ + dloc[i]=loc; + if (i==6) /* pirate's spotted him */ + { if (loc==chloc||prop[chest]>=0) continue; + k=0; + for (j=50; j<=maxtrs; j++) /* loop to 6020 */ + { if (j==pyram&&(loc==plac[pyram] + || loc==plac[emrald])) goto l6020; + if (toting(j)) goto l6022; + l6020: if (here(j)) k=1; + } /* 6020 */ + if (tally==tally2+1 && k==0 && place[chest]==0 + &&here(lamp) && prop[lamp]==1) goto l6025; + if (odloc[6]!=dloc[6]&&pct(20)) + rspeak(127); + continue; /* to 6030 */ + l6022: rspeak(128); + if (place[messag]==0) move(chest,chloc); + move(messag,chloc2); + for (j=50; j<=maxtrs; j++) /* loop to 6023 */ + { if (j==pyram && (loc==plac[pyram] + || loc==plac[emrald])) continue; + if (at(j)&&fixed[j]==0) carry(j,loc); + if (toting(j)) drop(j,chloc); + } + l6024: dloc[6]=odloc[6]=chloc; + dseen[6]=FALSE; + continue; + l6025: rspeak(186); + move(chest,chloc); + move(messag,chloc2); + goto l6024; + } + dtotal++; /* 6027 */ + if (odloc[i]!=dloc[i]) continue; + attack++; + if (knfloc>=0) knfloc=loc; + if (ran(1000)<95*(dflag-2)) stick++; + } /* 6030 */ + if (dtotal==0) return(2000); + if (dtotal!=1) + { printf("There are %d threatening little dwarves ",dtotal); + printf("in the room with you.\n"); + } + else rspeak(4); + if (attack==0) return(2000); + if (dflag==2) dflag=3; + if (saved!= -1) dflag=20; + if (attack!=1) + { printf("%d of them throw knives at you!\n",attack); + k=6; + l82: if (stick<=1) /* 82 */ + { rspeak(k+stick); + if (stick==0) return(2000); + } + else + printf("%d of them get you!\n",stick); /* 83 */ + oldlc2=loc; + return(99); + } + rspeak(5); + k=52; + goto l82; +} + +int +mback() /* 20 */ +{ register struct travlist *tk2,*j; + register int ll; + if (forced(k=oldloc)) k=oldlc2; /* k=location */ + oldlc2=oldloc; + oldloc=loc; + tk2=0; + if (k==loc) + { rspeak(91); + return(2); + } + for (; tkk!=0; tkk=tkk->next) /* 21 */ + { ll=tkk->tloc; + if (ll==k) + { k=tkk->tverb; /* k back to verb */ + tkk=travel[loc]; + return(9); + } + if (ll<=300) + { j=travel[loc]; + if (forced(ll) && k==j->tloc) tk2=tkk; + } + } + tkk=tk2; /* 23 */ + if (tkk!=0) + { k=tkk->tverb; + tkk=travel[loc]; + return(9); + } + rspeak(140); + return(2); +} + +int +badmove() /* 20 */ +{ spk=12; + if (k>=43 && k<=50) spk=9; + if (k==29||k==30) spk=9; + if (k==7||k==36||k==37) spk=10; + if (k==11||k==19) spk=11; + if (verb==find||verb==invent) spk=59; + if (k==62||k==65) spk=42; + if (k==17) spk=80; + rspeak(spk); + return(2); +} + +int +trbridge() /* 30300 */ +{ if (prop[troll]==1) + { pspeak(troll,1); + prop[troll]=0; + move(troll2,0); + move(troll2+100,0); + move(troll,plac[troll]); + move(troll+100,fixd[troll]); + juggle(chasm); + newloc=loc; + return(2); + } + newloc=plac[troll]+fixd[troll]-loc; /* 30310 */ + if (prop[troll]==0) prop[troll]=1; + if (!toting(bear)) return(2); + rspeak(162); + prop[chasm]=1; + prop[troll]=2; + drop(bear,newloc); + fixed[bear] = -1; + prop[bear]=3; + if (prop[spices]<0) tally2++; + oldlc2=newloc; + return(99); +} + +int +specials() /* 30000 */ +{ switch(newloc -= 300) + { case 1: /* 30100 */ + newloc = 99+100-loc; + if (holdng==0||(holdng==1&&toting(emrald))) return(2); + newloc=loc; + rspeak(117); + return(2); + case 2: /* 30200 */ + drop(emrald,loc); + return(12); + case 3: /* to 30300 */ + return(trbridge()); + default: + bug(29); + return 0; + } +} + +int +march() /* label 8 */ +{ register int ll1,ll2; + + tkk = travel[newloc = loc]; + if (tkk == 0) bug(26); + if (k==null) return(2); + if (k==cave) /* 40 */ + { if (loc<8) rspeak(57); + if (loc>=8) rspeak(58); + return(2); + } + if (k==look) /* 30 */ + { if (detail++<3) rspeak(15); + wzdark=FALSE; + abb[loc]=0; + return(2); + } + if (k==back) /* 20 */ + { switch(mback()) + { case 2: return(2); + case 9: goto l9; + default: bug(100); + } + } + oldlc2=oldloc; + oldloc=loc; +l9: + for (; tkk!=0; tkk=tkk->next) + if (tkk->tverb==1 || tkk->tverb==k) break; + if (tkk==0) + { badmove(); + return(2); + } +l11: ll1=tkk->conditions; /* 11 */ + ll2=tkk->tloc; + newloc=ll1; /* newloc=conditions */ + k=newloc%100; /* k used for prob */ + if (newloc<=300) + { if (newloc<=100) /* 13 */ + { if (newloc!=0&&!pct(newloc)) goto l12; /* 14 */ + l16: newloc=ll2; /* newloc=location */ + if (newloc<=300) return(2); + if (newloc<=500) + switch(specials())/* to 30000 */ + { case 2: return(2); + case 12: goto l12; + case 99: return(99); + default: bug(101); + } + rspeak(newloc-500); + newloc=loc; + return(2); + } + if (toting(k)||(newloc>200&&at(k))) goto l16; + goto l12; + } + if (prop[k]!=(newloc/100)-3) goto l16; /* newloc still conditions*/ +l12: /* alternative to probability move */ + for (; tkk!=0; tkk=tkk->next) + if (tkk->tloc!=ll2 || tkk->conditions!=ll1) break; + if (tkk==0) bug(25); + goto l11; +} + +void +bug(n) +int n; +{ printf("Please tell jim@rand-unix that fatal bug %d happened.\n",n); + exit(0); +} + +void +checkhints() /* 2600 &c */ +{ register int hint; + for (hint=4; hint<=hntmax; hint++) + { if (hinted[hint]) continue; + if (!bitset(loc,hint)) hintlc[hint]= -1; + hintlc[hint]++; + if (hintlc[hint]1) goto l40010; + goto l40020; + case 8: /* 40800 */ + if (prop[emrald]!= -1&&prop[pyram]== -1) goto l40010; + goto l40020; + case 9: + goto l40010; /* 40900 */ + default: bug(27); + } + l40010: hintlc[hint]=0; + if (!yes(hints[hint][3],0,54)) continue; + printf("I am prepared to give you a hint, but it will "); + printf("cost you %d points.\n",hints[hint][2]); + hinted[hint]=yes(175,hints[hint][4],54); + l40020: hintlc[hint]=0; + } +} + +int +trsay() /* 9030 */ +{ register int i; + if (*wd2!=0) copystr(wd2,wd1); + i=vocab(wd1,-1,0); + if (i==62||i==65||i==71||i==2025) + { *wd2=0; + obj=0; + return(2630); + } + printf("\nOkay, \"%s\".\n",wd2); + return(2012); +} + +int +trtake() /* 9010 */ +{ + if (toting(obj)) return(2011); /* 9010 */ + spk=25; + if (obj==plant&&prop[plant]<=0) spk=115; + if (obj==bear&&prop[bear]==1) spk=169; + if (obj==chain&&prop[bear]!=0) spk=170; + if (fixed[obj]!=0) return(2011); + if (obj==water||obj==oil) + { if (here(bottle)&&liq(0)==obj) + { obj=bottle; + goto l9017; + } + obj=bottle; + if (toting(bottle)&&prop[bottle]==1) + return(9220); + if (prop[bottle]!=1) spk=105; + if (!toting(bottle)) spk=104; + return(2011); + } +l9017: if (holdng>=7) + { rspeak(92); + return(2012); + } + if (obj==bird) + { if (prop[bird]!=0) goto l9014; + if (toting(rod)) + { rspeak(26); + return(2012); + } + if (!toting(cage)) /* 9013 */ + { rspeak(27); + return(2012); + } + prop[bird]=1; /* 9015 */ + } +l9014: if ((obj==bird||obj==cage)&&prop[bird]!=0) + carry(bird+cage-obj,loc); + carry(obj,loc); + k=liq(0); + if (obj==bottle && k!=0) place[k] = -1; + return(2009); +} + +int +dropper() /* 9021 */ +{ k=liq(0); + if (k==obj) obj=bottle; + if (obj==bottle&&k!=0) place[k]=0; + if (obj==cage&&prop[bird]!=0) drop(bird,loc); + if (obj==bird) prop[bird]=0; + drop(obj,loc); + return(2012); +} + +int +trdrop() /* 9020 */ +{ + if (toting(rod2)&&obj==rod&&!toting(rod)) obj=rod2; + if (!toting(obj)) return(2011); + if (obj==bird&&here(snake)) + { rspeak(30); + if (closed) return(19000); + dstroy(snake); + prop[snake]=1; + return(dropper()); + } + if (obj==coins&&here(vend)) /* 9024 */ + { dstroy(coins); + drop(batter,loc); + pspeak(batter,0); + return(2012); + } + if (obj==bird&&at(dragon)&&prop[dragon]==0) /* 9025 */ + { rspeak(154); + dstroy(bird); + prop[bird]=0; + if (place[snake]==plac[snake]) tally2--; + return(2012); + } + if (obj==bear&&at(troll)) /* 9026 */ + { rspeak(163); + move(troll,0); + move(troll+100,0); + move(troll2,plac[troll]); + move(troll2+100,fixd[troll]); + juggle(chasm); + prop[troll]=2; + return(dropper()); + } + if (obj!=vase||loc==plac[pillow]) /* 9027 */ + { rspeak(54); + return(dropper()); + } + prop[vase]=2; /* 9028 */ + if (at(pillow)) prop[vase]=0; + pspeak(vase,prop[vase]+1); + if (prop[vase]!=0) fixed[vase] = -1; + return(dropper()); +} + +int +tropen() /* 9040 */ +{ if (obj==clam||obj==oyster) + { k=0; /* 9046 */ + if (obj==oyster) k=1; + spk=124+k; + if (toting(obj)) spk=120+k; + if (!toting(tridnt)) spk=122+k; + if (verb==lock) spk=61; + if (spk!=124) return(2011); + dstroy(clam); + drop(oyster,loc); + drop(pearl,105); + return(2011); + } + if (obj==door) spk=111; + if (obj==door&&prop[door]==1) spk=54; + if (obj==cage) spk=32; + if (obj==keys) spk=55; + if (obj==grate||obj==chain) spk=31; + if (spk!=31||!here(keys)) return(2011); + if (obj==chain) + { if (verb==lock) + { spk=172; /* 9049: lock */ + if (prop[chain]!=0) spk=34; + if (loc!=plac[chain]) spk=173; + if (spk!=172) return(2011); + prop[chain]=2; + if (toting(chain)) drop(chain,loc); + fixed[chain]= -1; + return(2011); + } + spk=171; + if (prop[bear]==0) spk=41; + if (prop[chain]==0) spk=37; + if (spk!=171) return(2011); + prop[chain]=0; + fixed[chain]=0; + if (prop[bear]!=3) prop[bear]=2; + fixed[bear]=2-prop[bear]; + return(2011); + } + if (closng) + { k=130; + if (!panic) clock2=15; + panic=TRUE; + return(2010); + } + k=34+prop[grate]; /* 9043 */ + prop[grate]=1; + if (verb==lock) prop[grate]=0; + k=k+2*prop[grate]; + return(2010); +} + +int +trkill() /* 9120 */ +{ register int i; + for (i=1; i<=5; i++) + if (dloc[i]==loc&&dflag>=2) break; + if (i==6) i=0; + if (obj==0) /* 9122 */ + { if (i!=0) obj=dwarf; + if (here(snake)) obj=obj*100+snake; + if (at(dragon)&&prop[dragon]==0) obj=obj*100+dragon; + if (at(troll)) obj=obj*100+troll; + if (here(bear)&&prop[bear]==0) obj=obj*100+bear; + if (obj>100) return(8000); + if (obj==0) + { if (here(bird)&&verb!=throw) obj=bird; + if (here(clam)||here(oyster)) obj=100*obj+clam; + if (obj>100) return(8000); + } + } + if (obj==bird) /* 9124 */ + { spk=137; + if (closed) return(2011); + dstroy(bird); + prop[bird]=0; + if (place[snake]==plac[snake]) tally2++; + spk=45; + } + if (obj==0) spk=44; /* 9125 */ + if (obj==clam||obj==oyster) spk=150; + if (obj==snake) spk=46; + if (obj==dwarf) spk=49; + if (obj==dwarf&&closed) return(19000); + if (obj==dragon) spk=147; + if (obj==troll) spk=157; + if (obj==bear) spk=165+(prop[bear]+1)/2; + if (obj!=dragon||prop[dragon]!=0) return(2011); + rspeak(49); + verb=0; + obj=0; + getin(&wd1,&wd2); + if (!weq(wd1,"y")&&!weq(wd1,"yes")) return(2608); + pspeak(dragon,1); + prop[dragon]=2; + prop[rug]=0; + k=(plac[dragon]+fixd[dragon])/2; + move(dragon+100,-1); + move(rug+100,0); + move(dragon,k); + move(rug,k); + for (obj=1; obj<=100; obj++) + if (place[obj]==plac[dragon]||place[obj]==fixd[dragon]) + move(obj,k); + loc=k; + k=null; + return(8); +} + +int +trtoss() /* 9170: throw */ +{ register int i; + if (toting(rod2)&&obj==rod&&!toting(rod)) obj=rod2; + if (!toting(obj)) return(2011); + if (obj>=50&&obj<=maxtrs&&at(troll)) + { spk=159; /* 9178 */ + drop(obj,0); + move(troll,0); + move(troll+100,0); + drop(troll2,plac[troll]); + drop(troll2+100,fixd[troll]); + juggle(chasm); + return(2011); + } + if (obj==food&&here(bear)) + { obj=bear; /* 9177 */ + return(9210); + } + if (obj!=axe) return(9020); + for (i=1; i<=5; i++) + { if (dloc[i]==loc) + { spk=48; /* 9172 */ + if (ran(3)==0||saved!= -1) + l9175: { rspeak(spk); + drop(axe,loc); + k=null; + return(8); + } + dseen[i]=FALSE; + dloc[i]=0; + spk=47; + dkill++; + if (dkill==1) spk=149; + goto l9175; + } + } + spk=152; + if (at(dragon)&&prop[dragon]==0) + goto l9175; + spk=158; + if (at(troll)) goto l9175; + if (here(bear)&&prop[bear]==0) + { spk=164; + drop(axe,loc); + fixed[axe]= -1; + prop[axe]=1; + juggle(bear); + return(2011); + } + obj=0; + return(9120); +} + +int +trfeed() /* 9210 */ +{ if (obj==bird) + { spk=100; + return(2011); + } + if (obj==snake||obj==dragon||obj==troll) + { spk=102; + if (obj==dragon&&prop[dragon]!=0) spk=110; + if (obj==troll) spk=182; + if (obj!=snake||closed||!here(bird)) return(2011); + spk=101; + dstroy(bird); + prop[bird]=0; + tally2++; + return(2011); + } + if (obj==dwarf) + { if (!here(food)) return(2011); + spk=103; + dflag++; + return(2011); + } + if (obj==bear) + { if (prop[bear]==0) spk=102; + if (prop[bear]==3) spk=110; + if (!here(food)) return(2011); + dstroy(food); + prop[bear]=1; + fixed[axe]=0; + prop[axe]=0; + spk=168; + return(2011); + } + spk=14; + return(2011); +} + +int +trfill() /* 9220 */ +{ if (obj==vase) + { spk=29; + if (liqloc(loc)==0) spk=144; + if (liqloc(loc)==0||!toting(vase)) return(2011); + rspeak(145); + prop[vase]=2; + fixed[vase]= -1; + return(9020); /* advent/10 goes to 9024 */ + } + if (obj!=0&&obj!=bottle) return(2011); + if (obj==0&&!here(bottle)) return(8000); + spk=107; + if (liqloc(loc)==0) spk=106; + if (liq(0)!=0) spk=105; + if (spk!=107) return(2011); + prop[bottle]=((cond[loc]%4)/2)*2; + k=liq(0); + if (toting(bottle)) place[k]= -1; + if (k==oil) spk=108; + return(2011); +} + +int +closing() /* 10000 */ +{ register int i; + prop[grate]=prop[fissur]=0; + for (i=1; i<=6; i++) + { dseen[i]=FALSE; + dloc[i]=0; + } + move(troll,0); + move(troll+100,0); + move(troll2,plac[troll]); + move(troll2+100,fixd[troll]); + juggle(chasm); + if(prop[bear]!=3) dstroy(bear); + prop[chain]=0; + fixed[chain]=0; + prop[axe]=0; + fixed[axe]=0; + rspeak(129); + clock1 = -1; + closng=TRUE; + return(19999); +} + +int +caveclose() /* 11000 */ +{ register int i; + prop[bottle]=put(bottle,115,1); + prop[plant]=put(plant,115,0); + prop[oyster]=put(oyster,115,0); + prop[lamp]=put(lamp,115,0); + prop[rod]=put(rod,115,0); + prop[dwarf]=put(dwarf,115,0); + loc=115; + oldloc=115; + newloc=115; + + put(grate,116,0); + prop[snake]=put(snake,116,1); + prop[bird]=put(bird,116,1); + prop[cage]=put(cage,116,0); + prop[rod2]=put(rod2,116,0); + prop[pillow]=put(pillow,116,0); + + prop[mirror]=put(mirror,115,0); + fixed[mirror]=116; + + for (i=1; i<=100; i++) + if (toting(i)) dstroy(i); + rspeak(132); + closed=TRUE; + return(2); +} diff --git a/src/games/adventure/vocab.c b/src/games/adventure/vocab.c new file mode 100644 index 0000000..ce6e6f2 --- /dev/null +++ b/src/games/adventure/vocab.c @@ -0,0 +1,202 @@ +/* + * Re-coding of advent in C: data structure routines + */ +#include "hdr.h" + +void +dstroy(object) +int object; +{ move(object,0); +} + +void +juggle(object) +int object; +{ register int i,j; + i=place[object]; + j=fixed[object]; + move(object,i); + move(object+100,j); +} + +void +move(object, where) +int object, where; +{ register int from; + if (object<=100) + from=place[object]; + else + from=fixed[object-100]; + if (from>0 && from<=300) carry(object,from); + drop(object,where); +} + +int +put(object, where, pval) +int object, where, pval; +{ move(object,where); + return(-1-pval); +} + +void +carry(object, where) +int object, where; +{ register int temp; + if (object<=100) + { if (place[object]== -1) return; + place[object] = -1; + holdng++; + } + if (atloc[where]==object) + { atloc[where]=plink[object]; + return; + } + for (temp=atloc[where]; plink[temp]!=object; temp=plink[temp]); + plink[temp]=plink[object]; +} + +void +drop(object, where) +int object, where; +{ if (object>100) fixed[object-100]=where; + else + { if (place[object]== -1) holdng--; + place[object]=where; + } + if (where<=0) return; + plink[object]=atloc[where]; + atloc[where]=object; +} + +/* + * Good hash function. + * (C) 2006 Serge Vakulenko + */ +unsigned int rot13_hash (char *str) +{ + unsigned int len, hash, c; + + /* Max 5 utf8 characters. */ + len = 5; + for (hash = 0; len > 0; str++) { + c = (unsigned char) *str; + if (c == 0) + break; + if (! (c & 0x80)) + len--; + hash += (unsigned char) *str; + hash -= (hash << 13) | (hash >> 19); + } + return hash; +} + +int +vocab(word, type, value) /* look up or store a word */ +char *word; +int type; /* -2 for store, -1 for user word, >=0 for canned lookup*/ +int value; /* used for storing only */ +{ register int adr; + unsigned int hash32, hash; + struct hashtab *h; + + hash32 = rot13_hash (word); /* some kind of hash */ + hash = hash32 % HTSIZE; /* put it into range of table */ + + for(adr = hash; ; adr++) { /* look for entry in table */ + if (adr == HTSIZE) + adr = 0; /* wrap around */ + h = &voc[adr]; /* point at the entry */ + switch(type) { + case -2: /* fill in entry */ + if (h->val) /* already got an entry? */ + goto exitloop2; + h->val = value; + h->hash = hash32; + /*printf("Stored \"%s\" (%d ch) as entry %d\n", + word, length(word), adr);*/ + return 0; /* entry unused */ + + case -1: /* looking up user word */ + if (h->val == 0) /* not found */ + return(-1); + if (h->hash != hash32) + goto exitloop2; + return h->val; /* the word matched o.k. */ + + default: /* looking up known word */ + if (h->val == 0) { + printf("Unable to find %s in vocab\n", word); + exit(0); + } + if (h->hash != hash32) + goto exitloop2; + /* the word matched o.k. */ + if (h->val/1000 != type) + continue; + return h->val % 1000; + } +exitloop2: /* hashed entry does not match */ + if (adr+1 == hash || (adr == HTSIZE && hash == 0)) { + printf("Hash table overflow\n"); + exit(0); + } + } +} + +void +copystr(w1, w2) /* copy one string to another */ +char *w1, *w2; +{ register char *s,*t; + for (s=w1,t=w2; *s;) + *t++ = *s++; + *t=0; +} + +int +weq(w1, w2) /* compare words */ +char *w1, *w2; /* w1 is user, w2 is system */ +{ register char *s,*t; + register int i; + s=w1; + t=w2; + for (i=0; i<5; i++) /* compare at most 5 chars */ + { if (*t==0 && *s==0) + return(TRUE); + if (*s++ != *t++) return(FALSE); + } + return(TRUE); +} + +int +length(str) /* includes 0 at end */ +char *str; +{ register char *s; + register int n; + for (n=0,s=str; *s++;) n++; + return(n+1); +} + +#if 0 +void +prht() /* print hash table */ +{ register int i,j,l; + char *c; + struct hashtab *h; + for (i=0; i=HTSIZE) break; + h= &voc[i*10+j]; + putchar(' '); + if (h->val==0) + { printf("-----"); + continue; + } + for (l=0, c=h->atab; l<5; l++) + if ((*c ^ '=')) putchar(*c++ ^ '='); + else putchar(' '); + } + putchar('\n'); + } +} +#endif diff --git a/src/games/adventure/wizard.c b/src/games/adventure/wizard.c new file mode 100644 index 0000000..7d00413 --- /dev/null +++ b/src/games/adventure/wizard.c @@ -0,0 +1,105 @@ +/* + * Re-coding of advent in C: privileged operations + */ +#include "hdr.h" +#include +#include +#include + +char *magic; + +void +datime(d, t) +int *d, *t; +{ + time_t now; + struct tm *tm; + + time(&now); + tm = localtime(&now); + *d = tm->tm_yday + /* day since 1977 (mod leap) */ + 365 * (tm->tm_year - 77); + /* bug: this will overflow in the year 2066 AD */ + /* it will be attributed to Wm the C's millenial celebration */ + *t = tm->tm_hour * 60 + /* and minutes since midnite */ + tm->tm_min; /* pretty painless */ +} + +void +poof() +{ magic = "dwarf"; + latncy = 15; /* originally 45 minutes */ +} + +int +wizard() /* not as complex as advent/10 (for now) */ +{ + char *word,*x; + if (!yesm(16,0,7)) return(FALSE); + mspeak(17); + getin(&word,&x); + if (!weq(word,magic)) + { mspeak(20); + return(FALSE); + } + mspeak(19); + return(TRUE); +} + +void +start(n) +{ + int d, t, delay; + + datime(&d,&t); + delay = (d-saved)*1440+(t-savet); /* good for about a month */ + if (delay >= latncy || delay < 0) { + saved = -1; + return; + } + printf("This adventure was suspended a mere %d minutes ago.",delay); + if (delay <= latncy / 3) { + mspeak(2); + exit(0); + } + mspeak(8); + if (! wizard()) { + mspeak(9); + exit(0); + } + saved = -1; +} + +void +ciao() +{ + char fname[80]; + register char *c; + + for (;;) { + printf("What would you like to call the saved version?\n"); + for (c=fname; ; c++) { + *c = getchar(); + if (*c == '\n') + break; + } + *c = 0; + if (access(fname, F_OK) < 0) + break; + printf("I can't use that one.\n"); + return; + } + save(fname, 0); + printf(" ^\n"); + printf("That should do it. Gis revido.\n"); + exit(0); +} + +int +ran(range) /* uses unix rng */ +int range; /* can't div by 32768 because */ +{ + long i; + i = rand() % range; + return(i); +} diff --git a/src/games/arithmetic.6 b/src/games/arithmetic.6 new file mode 100644 index 0000000..b9b3134 --- /dev/null +++ b/src/games/arithmetic.6 @@ -0,0 +1,56 @@ +.\" @(#)arithmetic.6 6.2 (Berkeley) 5/6/86 +.\" +.TH ARITHMETIC 6 "May 6, 1986" +.AT 3 +.SH NAME +arithmetic \- provide drill in number facts +.SH SYNOPSIS +.B /usr/games/arithmetic +[ +.B +\-x/ +] [ range ] +.SH DESCRIPTION +.I Arithmetic +types out simple arithmetic problems, and waits for an answer to be typed in. +If the answer is correct, it types back \*(lqRight!\*(rq, and a new problem. +If the answer is wrong, it replies \*(lqWhat?\*(rq, +and waits for another answer. +After every twenty problems, it publishes +statistics on correctness and the time required to answer. +.PP +To quit the program, type an interrupt (delete). +.PP +The first optional argument determines the kind of problem to be generated; +.B +\-x/ +respectively cause addition, subtraction, multiplication, and division +problems to be generated. +One or more characters can be given; +if more than one is given, the different types of +problems will be mixed in random order; default is +.B +\-. +.PP +.I Range +is a decimal number; +all addends, subtrahends, differences, multiplicands, divisors, +and quotients will be less than or equal to the value of +.IR range . +Default +.I range +is 10. +.PP +At the start, all numbers less than or equal to +.I range +are equally likely to appear. +If the respondent makes a mistake, +the numbers in the problem which was missed +become more likely to reappear. +.PP +As a matter of educational philosophy, the program will +not give correct answers, since the learner should, in principle, +be able to calculate them. +Thus the program is intended to provide drill for +someone just past the first learning stage, not to teach number facts +.I de +.IR novo . +For almost all users, the relevant statistic should be +time per problem, not percent correct. diff --git a/src/games/arithmetic.c b/src/games/arithmetic.c new file mode 100644 index 0000000..34b62df --- /dev/null +++ b/src/games/arithmetic.c @@ -0,0 +1,227 @@ +#ifdef CROSS +# include +#else +# include +#endif +#include +#include +#include +#include + +#define MAX 100 + +char types[10]; +int right[MAX]; +int left[MAX]; +int rights; +int wrongs; +long stvec; +long etvec; +long dtvec; + +void score() +{ + time(&etvec); + + printf("\n\nRights %d; Wrongs %d; Score %d%%\n", rights, wrongs, + (rights * 100)/(rights + wrongs)); + + if (rights == 0) + return; + printf("Total time %ld seconds; %.1f seconds per problem\n\n\n", + etvec - stvec, + (etvec - stvec) / (rights + 0.)); + + sleep(3); + time(&dtvec); + stvec += dtvec - etvec; +} + +void delete(sig) +{ + if(rights + wrongs == 0.) { + printf("\n"); + exit(0); + } + score(); + exit(0); +} + +int getnum(s) + char *s; +{ + int a; + char c; + + a = 0; + while((c = *s++) >= '0' && c <= '9') { + a = a*10 + c - '0'; + } + return(a); +} + +int arand; + +void srand13(n) +{ + arand = (n & 077774) | 01; +} + +int rand13() /*uniform on 0 to 2**13-1*/ +{ + arand *= 3125; + arand &= 077777; + return(arand/4); +} + +/* + * 'hmul' returns the upper 16 bits of the product, where the operands + * are assumed to be 16-bit integers. It replaces an old PDP-11 + * assembler language subroutine. -- dks. + */ +int hmul(a, b) +{ + return (long)a*b >> 16; +} + +int skrand(range) +{ + int temp; + + temp = rand13() + rand13(); + if (temp >017777) + temp = 040000 - temp; + return hmul(temp, 8*range); +} + +int rrandom(range) +{ + return(hmul(rand13(), 8*range)); +} + +void getln(s) + char *s; +{ + register char *rs; + + rs = s; + + while((*rs = getchar()) == ' '); + while(*rs != '\n') + if(*rs == 0) + exit(0); + else if(rs >= &s[99]) { + while((*rs = getchar()) != '\n') + if(*rs == '\0') + exit(0); + } + else + *++rs = getchar(); + while(*--rs == ' ') + *rs = '\n'; +} + +int main(argc, argv) + char *argv[]; +{ + int range, k, dif, l; + char line[100]; + int ans, pans, i, j, t; + + signal(SIGINT, delete); + + range = 11; + dif = 0; + while(argc > 1) { + switch(*argv[1]) { + case '+': + case '-': + case 'x': + case '/': + while ((types[dif] = argv[1][dif])) + dif++; + break; + + default: + range = getnum(argv[1]) + 1; + } + argv++; + argc--; + } + if(range > MAX) { + printf("Range is too large.\n"); + exit(0); + } + + if(dif == 0) { + types[0] = '+'; + types[1] = '-'; + dif = 2; + } + + for(i = 0; i < range; i++) { + left[i] = right[i] = i; + } + time(&stvec); + k = stvec; + srand13(k); + k = 0; + l = 0; + goto start; + +loop: + if(++k%20 == 0) + score(); + +start: + i = skrand(range); + j = skrand(range); + if(dif > 1) + l = rrandom(dif); + + switch(types[l]) { + case '+': + default: + ans = left[i] + right[j]; + printf("%d + %d = ", left[i], right[j]); + break; + + case '-': + t = left[i] + right[j]; + ans = left[i]; + printf("%d - %d = ", t, right[j]); + break; + + case 'x': + ans = left[i] * right[j]; + printf("%d x %d = ", left[i], right[j]); + break; + + case '/': + while(right[j] == 0) + j = rrandom(range); + t = left[i] * right[j] + rrandom(right[j]); + ans = left[i]; + printf("%d / %d = ", t, right[j]); + break; + } + +loop1: + getln(line); + dtvec += etvec - stvec; + if(line[0]=='\n') goto loop1; + pans = getnum(line); + if(pans == ans) { + printf("Right!\n"); + rights++; + goto loop; + } + else { + printf("What?\n"); + wrongs++; + if(range >= MAX) goto loop1; + left[range] = left[i]; + right[range++] = right[j]; + goto loop1; + } +} diff --git a/src/games/atc/BUGS b/src/games/atc/BUGS new file mode 100644 index 0000000..7d2af29 --- /dev/null +++ b/src/games/atc/BUGS @@ -0,0 +1,4 @@ +log restarts if interrupted +Still refreshes after exit +Should ^Z be disabled? +does not exit after hup diff --git a/src/games/atc/Makefile b/src/games/atc/Makefile new file mode 100644 index 0000000..285e11c --- /dev/null +++ b/src/games/atc/Makefile @@ -0,0 +1,30 @@ +# +# Copyright (c) 1987 Regents of the University of California. +# All rights reserved. The Berkeley software License Agreement +# specifies the terms and conditions for redistribution. +# +# @(#)Makefile 5.1.2 (2.11BSD) 1999/10/25 +# + +DESTDIR = +CFLAGS = -O -DSYSV -DDEST=\"${DESTDIR}/usr/games/lib/atc/\" +YFLAGS = -d +LIBS = -ll -lm -lcurses -ltermcap +OBJS = extern.o grammar.o input.o lex.o list.o log.o main.o tunable.o \ + graphics.o update.o + +all: atc + +atc: ${OBJS} + ${CC} ${OBJS} ${LIBS} -o $@ + +clean: + rm -f *.o core atc grammar.c y.tab.h y.tab.c lex.yy.c lex.c + +install: + -[ -d ${DESTDIR}/usr/games/lib/atc ] || mkdir ${DESTDIR}/usr/games/lib/atc + chmod 700 ${DESTDIR}/usr/games/lib/atc + chown games.bin ${DESTDIR}/usr/games/lib/atc + (cd games; install -c -o games -g bin -m 600 * ${DESTDIR}/usr/games/lib/atc) + install -s -o games -g bin -m 4700 atc ${DESTDIR}/usr/games/hide/atc + (cd ${DESTDIR}/usr/games; rm -f atc; ln -s dm atc; chown games.bin atc) diff --git a/src/games/atc/def.h b/src/games/atc/def.h new file mode 100644 index 0000000..9cc2749 --- /dev/null +++ b/src/games/atc/def.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 1987 by Ed James, UC Berkeley. All rights reserved. + * + * Copy permission is hereby granted provided that this notice is + * retained on all partial or complete copies. + * + * For more info on this and all of my stuff, mail edjames@berkeley.edu. + */ + +#define AUTHOR_STR "ATC - by Ed James" + +#define PI 3.14159654 + +#define LOWFUEL 15 + +#define REALLOC 10 + +#define SGN(x) ((x < 0) ? -1 : ((x > 0) ? 1 : 0)) +#define ABS(x) ((x < 0) ? -(x) : (x)) +#define DIR_FROM_DXDY(dx,dy) ((int) (atan2((double)(dy), (double)(dx)) \ + * MAXDIR / (2 * PI) + 2.5 + MAXDIR) % MAXDIR) + +#define MAXDIR 8 + +#define D_LEFT 1 +#define D_RIGHT 2 +#define D_UP 3 +#define D_DOWN 4 + +#define T_NODEST 0 +#define T_BEACON 1 +#define T_EXIT 2 +#define T_AIRPORT 3 + +#define S_NONE 0 +#define S_GONE 1 +#define S_MARKED 2 +#define S_UNMARKED 3 +#define S_IGNORED 4 + +#define INPUT_LINES 3 +#define PLANE_COLS 20 diff --git a/src/games/atc/extern.c b/src/games/atc/extern.c new file mode 100644 index 0000000..203ee8b --- /dev/null +++ b/src/games/atc/extern.c @@ -0,0 +1,36 @@ +/* + * Copyright (c) 1987 by Ed James, UC Berkeley. All rights reserved. + * + * Copy permission is hereby granted provided that this notice is + * retained on all partial or complete copies. + * + * For more info on this and all of my stuff, mail edjames@berkeley.edu. + */ + +#include "include.h" + +char GAMES[] = "Game_List", + LOG[] = "ATC_scores"; + +int clock, safe_planes, start_time, test_mode; + +char *file; + +FILE *filein, *fileout; + +C_SCREEN screen, *sp = &screen; + +LIST air, ground; + +struct sgttyb tty_start, tty_new; + +DISPLACEMENT displacement[MAXDIR] = { + { 0, -1 }, + { 1, -1 }, + { 1, 0 }, + { 1, 1 }, + { 0, 1 }, + { -1, 1 }, + { -1, 0 }, + { -1, -1 } +}; diff --git a/src/games/atc/extern.h b/src/games/atc/extern.h new file mode 100644 index 0000000..c4ef642 --- /dev/null +++ b/src/games/atc/extern.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 1987 by Ed James, UC Berkeley. All rights reserved. + * + * Copy permission is hereby granted provided that this notice is + * retained on all partial or complete copies. + * + * For more info on this and all of my stuff, mail edjames@berkeley.edu. + */ + +extern char GAMES[], LOG[], *file; + +extern int clock, safe_planes, start_time, test_mode; + +extern FILE *filein, *fileout; + +extern C_SCREEN screen, *sp; + +extern LIST air, ground; + +extern struct sgttyb tty_start, tty_new; + +extern DISPLACEMENT displacement[MAXDIR]; + +extern PLANE *findplane(), *newplane(); diff --git a/src/games/atc/games/ATC_scores b/src/games/atc/games/ATC_scores new file mode 100644 index 0000000..bbffeb2 --- /dev/null +++ b/src/games/atc/games/ATC_scores @@ -0,0 +1,5 @@ +schumann puff game_2 171 1414 195 +schumann puff default 18 220 59 +schumann puff easy 13 182 146 +schumann puff crossover 11 74 448 +schumann puff Killer 0 38 27 diff --git a/src/games/atc/games/Game_List b/src/games/atc/games/Game_List new file mode 100644 index 0000000..0117385 --- /dev/null +++ b/src/games/atc/games/Game_List @@ -0,0 +1,5 @@ +default +easy +crossover +Killer +game_2 diff --git a/src/games/atc/games/Killer b/src/games/atc/games/Killer new file mode 100644 index 0000000..f15d060 --- /dev/null +++ b/src/games/atc/games/Killer @@ -0,0 +1,21 @@ +update = 1; +newplane = 4; +width = 30; +height = 21; + +exit: ( 29 7 a ) ( 29 17 a ) + ( 0 7 d ) ( 0 0 c ) ; + +beacon: ( 12 7 ) ( 12 17 ) ( 14 10 ) ( 20 15 ) ; + +airport: ( 20 18 d ) ; + +line: [ ( 1 1 ) ( 6 6 ) ] + [ ( 12 1 ) ( 12 6 ) ] + [ ( 13 7 ) ( 28 7 ) ] + [ ( 28 1 ) ( 13 16 ) ] + [ ( 1 13 ) ( 11 13 ) ] + [ ( 12 8 ) ( 12 16 ) ] + [ ( 11 18 ) ( 10 19 ) ] + [ ( 13 17 ) ( 28 17 ) ] + [ ( 1 7 ) ( 11 7 ) ] ; diff --git a/src/games/atc/games/crossover b/src/games/atc/games/crossover new file mode 100644 index 0000000..d2689ff --- /dev/null +++ b/src/games/atc/games/crossover @@ -0,0 +1,14 @@ +update = 5; +newplane = 5; +width = 29; +height = 21; + +exit: ( 0 0 c ) ( 8 0 c ) ( 20 0 z ) ( 28 0 z ) + ( 28 20 q ) ( 20 20 q ) ( 8 20 e ) ( 0 20 e ); + +beacon: ( 14 6 ) ( 18 10 ) ( 14 14 ) ( 10 10 ); + +line: [ ( 0 0 ) ( 20 20 ) ] + [ ( 8 0 ) ( 28 20 ) ] + [ ( 20 0 ) ( 0 20 ) ] + [ ( 28 0 ) ( 8 20 ) ]; diff --git a/src/games/atc/games/default b/src/games/atc/games/default new file mode 100644 index 0000000..e19ef9d --- /dev/null +++ b/src/games/atc/games/default @@ -0,0 +1,21 @@ +update = 5; +newplane = 10; +width = 30; +height = 21; + +exit: ( 12 0 x ) ( 29 0 z ) ( 29 7 a ) ( 29 17 a ) + ( 9 20 e ) ( 0 13 d ) ( 0 7 d ) ( 0 0 c ) ; + +beacon: ( 12 7 ) ( 12 17 ) ; + +airport: ( 20 15 w ) ( 20 18 d ) ; + +line: [ ( 1 1 ) ( 6 6 ) ] + [ ( 12 1 ) ( 12 6 ) ] + [ ( 13 7 ) ( 28 7 ) ] + [ ( 28 1 ) ( 13 16 ) ] + [ ( 1 13 ) ( 11 13 ) ] + [ ( 12 8 ) ( 12 16 ) ] + [ ( 11 18 ) ( 10 19 ) ] + [ ( 13 17 ) ( 28 17 ) ] + [ ( 1 7 ) ( 11 7 ) ] ; diff --git a/src/games/atc/games/easy b/src/games/atc/games/easy new file mode 100644 index 0000000..4ab8eac --- /dev/null +++ b/src/games/atc/games/easy @@ -0,0 +1,15 @@ +update = 7; +newplane = 12; +width = 15; +height = 15; + +exit: ( 7 0 x ) ( 14 0 z ) ( 12 14 q ) ( 0 14 e ) ; + +beacon: ( 12 7 ) ; + +airport: ( 7 8 w ) ; + +line: [ ( 1 1 ) ( 6 6 ) ] + [ ( 7 9 ) ( 12 14 ) ] + [ ( 7 0 ) ( 7 14 ) ] + [ ( 1 7 ) ( 11 7 ) ] ; diff --git a/src/games/atc/games/game_2 b/src/games/atc/games/game_2 new file mode 100644 index 0000000..5788c8a --- /dev/null +++ b/src/games/atc/games/game_2 @@ -0,0 +1,22 @@ +update = 5; +newplane = 8; +width = 30; +height = 21; + +exit: ( 12 0 x ) ( 29 0 z ) ( 29 6 a ) ( 29 13 a ) + ( 9 20 e ) ( 0 13 d ) ( 0 6 d ) ( 0 0 c ) ; + +beacon: ( 12 17 ) ( 23 6 ) ( 23 13 ) ( 25 17 ) + ( 12 6 ) ( 12 13 ) ( 6 6 ) ; + +airport: ( 18 17 d ) ; + +line: [ ( 1 1 ) ( 16 16 ) ] + [ ( 1 6 ) ( 28 6 ) ] + [ ( 12 1 ) ( 12 17 ) ] + [ ( 10 19 ) ( 28 1 ) ] + [ ( 13 17 ) ( 17 17 ) ] + [ ( 1 13 ) ( 28 13 ) ] + [ ( 19 17 ) ( 24 17 ) ] + [ ( 19 17 ) ( 22 14 ) ] + [ ( 26 16 ) ( 28 14 ) ] ; diff --git a/src/games/atc/grammar.y b/src/games/atc/grammar.y new file mode 100644 index 0000000..519bfd7 --- /dev/null +++ b/src/games/atc/grammar.y @@ -0,0 +1,349 @@ +/* + * Copyright (c) 1987 by Ed James, UC Berkeley. All rights reserved. + * + * Copy permission is hereby granted provided that this notice is + * retained on all partial or complete copies. + * + * For more info on this and all of my stuff, mail edjames@berkeley.edu. + */ + +%token HeightOp +%token WidthOp +%token UpdateOp +%token NewplaneOp +%token DirOp +%token ConstOp +%token LineOp +%token AirportOp +%token BeaconOp +%token ExitOp +%union { + int ival; + char cval; +} + +%{ +#include "include.h" + +int errors = 0; +int line = 1; +%} + +%% +file: + bunch_of_defs { if (checkdefs() < 0) return (errors); } bunch_of_lines + { + if (sp->num_exits + sp->num_airports < 2) + yyerror("Need at least 2 airports and/or exits."); + return (errors); + } + ; + +bunch_of_defs: + def bunch_of_defs + | def + ; + +def: + udef + | ndef + | wdef + | hdef + ; + +udef: + UpdateOp '=' ConstOp ';' + { + if (sp->update_secs != 0) + return (yyerror("Redefinition of 'update'.")); + else if ($3 < 1) + return (yyerror("'update' is too small.")); + else + sp->update_secs = $3; + } + ; + +ndef: + NewplaneOp '=' ConstOp ';' + { + if (sp->newplane_time != 0) + return (yyerror("Redefinition of 'newplane'.")); + else if ($3 < 1) + return (yyerror("'newplane' is too small.")); + else + sp->newplane_time = $3; + } + ; + +hdef: + HeightOp '=' ConstOp ';' + { + if (sp->height != 0) + return (yyerror("Redefinition of 'height'.")); + else if ($3 < 3) + return (yyerror("'height' is too small.")); + else + sp->height = $3; + } + ; + +wdef: + WidthOp '=' ConstOp ';' + { + if (sp->height != 0) + return (yyerror("Redefinition of 'width'.")); + else if ($3 < 3) + return (yyerror("'width' is too small.")); + else + sp->width = $3; + } + ; + +bunch_of_lines: + line bunch_of_lines + {} + | line + {} + ; + +line: + BeaconOp ':' Bpoint_list ';' + {} + | ExitOp ':' Epoint_list ';' + {} + | LineOp ':' Lline_list ';' + {} + | AirportOp ':' Apoint_list ';' + {} + ; + +Bpoint_list: + Bpoint Bpoint_list + {} + | Bpoint + {} + ; + +Bpoint: + '(' ConstOp ConstOp ')' + { + if (sp->num_beacons % REALLOC == 0) { + if (sp->beacon == NULL) + sp->beacon = (BEACON *) malloc((sp->num_beacons + + REALLOC) * sizeof (BEACON)); + else + sp->beacon = (BEACON *) realloc(sp->beacon, + (sp->num_beacons + REALLOC) * + sizeof (BEACON)); + if (sp->beacon == NULL) + return (yyerror("No memory available.")); + } + sp->beacon[sp->num_beacons].x = $2; + sp->beacon[sp->num_beacons].y = $3; + check_point($2, $3); + sp->num_beacons++; + } + ; + +Epoint_list: + Epoint Epoint_list + {} + | Epoint + {} + ; + +Epoint: + '(' ConstOp ConstOp DirOp ')' + { + int dir; + + if (sp->num_exits % REALLOC == 0) { + if (sp->exit == NULL) + sp->exit = (EXIT *) malloc((sp->num_exits + + REALLOC) * sizeof (EXIT)); + else + sp->exit = (EXIT *) realloc(sp->exit, + (sp->num_exits + REALLOC) * + sizeof (EXIT)); + if (sp->exit == NULL) + return (yyerror("No memory available.")); + } + dir = dir_no($4); + sp->exit[sp->num_exits].x = $2; + sp->exit[sp->num_exits].y = $3; + sp->exit[sp->num_exits].dir = dir; + check_edge($2, $3); + check_edir($2, $3, dir); + sp->num_exits++; + } + ; + +Apoint_list: + Apoint Apoint_list + {} + | Apoint + {} + ; + +Apoint: + '(' ConstOp ConstOp DirOp ')' + { + int dir; + + if (sp->num_airports % REALLOC == 0) { + if (sp->airport == NULL) + sp->airport=(AIRPORT *)malloc((sp->num_airports + + REALLOC) * sizeof(AIRPORT)); + else + sp->airport = (AIRPORT *) realloc(sp->airport, + (sp->num_airports + REALLOC) * + sizeof(AIRPORT)); + if (sp->airport == NULL) + return (yyerror("No memory available.")); + } + dir = dir_no($4); + sp->airport[sp->num_airports].x = $2; + sp->airport[sp->num_airports].y = $3; + sp->airport[sp->num_airports].dir = dir; + check_point($2, $3); + check_adir($2, $3, dir); + sp->num_airports++; + } + ; + +Lline_list: + Lline Lline_list + {} + | Lline + {} + ; + +Lline: + '[' '(' ConstOp ConstOp ')' '(' ConstOp ConstOp ')' ']' + { + if (sp->num_lines % REALLOC == 0) { + if (sp->line == NULL) + sp->line = (LINE *) malloc((sp->num_lines + + REALLOC) * sizeof (LINE)); + else + sp->line = (LINE *) realloc(sp->line, + (sp->num_lines + REALLOC) * + sizeof (LINE)); + if (sp->line == NULL) + return (yyerror("No memory available.")); + } + sp->line[sp->num_lines].p1.x = $3; + sp->line[sp->num_lines].p1.y = $4; + sp->line[sp->num_lines].p2.x = $7; + sp->line[sp->num_lines].p2.y = $8; + check_line($3, $4, $7, $8); + sp->num_lines++; + } + ; +%% + +check_edge(x, y) +{ + if (!(x == 0) && !(x == sp->width - 1) && + !(y == 0) && !(y == sp->height - 1)) + yyerror("edge value not on edge."); +} + +check_point(x, y) +{ + if (x < 1 || x >= sp->width - 1) + yyerror("X value out of range."); + if (y < 1 || y >= sp->height - 1) + yyerror("Y value out of range."); +} + +check_linepoint(x, y) +{ + if (x < 0 || x >= sp->width) + yyerror("X value out of range."); + if (y < 0 || y >= sp->height) + yyerror("Y value out of range."); +} + +check_line(x1, y1, x2, y2) +{ + int d1, d2; + + check_linepoint(x1, y1); + check_linepoint(x2, y2); + + d1 = ABS(x2 - x1); + d2 = ABS(y2 - y1); + + if (!(d1 == d2) && !(d1 == 0) && !(d2 == 0)) + yyerror("Bad line endpoints."); +} + +yyerror(s) +{ + fprintf(stderr, "\"%s\": line %d: %s\n", file, line, s); + errors++; + + return (errors); +} + +check_edir(x, y, dir) +{ + int bad = 0; + + if (x == sp->width - 1) + x = 2; + else if (x != 0) + x = 1; + if (y == sp->height - 1) + y = 2; + else if (y != 0) + y = 1; + + switch (x * 10 + y) { + case 00: if (dir != 3) bad++; break; + case 01: if (dir < 1 || dir > 3) bad++; break; + case 02: if (dir != 1) bad++; break; + case 10: if (dir < 3 || dir > 5) bad++; break; + case 11: break; + case 12: if (dir > 1 && dir < 7) bad++; break; + case 20: if (dir != 5) bad++; break; + case 21: if (dir < 5) bad++; break; + case 22: if (dir != 7) bad++; break; + default: + yyerror("Unknown value in checkdir! Get help!"); + break; + } + if (bad) + yyerror("Bad direction for entrance at exit."); +} + +check_adir(x, y, dir) +{ +} + +checkdefs() +{ + int err = 0; + + if (sp->width == 0) { + yyerror("'width' undefined."); + err++; + } + if (sp->height == 0) { + yyerror("'height' undefined."); + err++; + } + if (sp->update_secs == 0) { + yyerror("'update' undefined."); + err++; + } + if (sp->newplane_time == 0) { + yyerror("'newplane' undefined."); + err++; + } + if (err) + return (-1); + else + return (0); +} diff --git a/src/games/atc/graphics.c b/src/games/atc/graphics.c new file mode 100644 index 0000000..f655f89 --- /dev/null +++ b/src/games/atc/graphics.c @@ -0,0 +1,378 @@ +/* + * Copyright (c) 1987 by Ed James, UC Berkeley. All rights reserved. + * + * Copy permission is hereby granted provided that this notice is + * retained on all partial or complete copies. + * + * For more info on this and all of my stuff, mail edjames@berkeley.edu. + */ + +#include "include.h" +#ifdef SYSV +#include +#endif + +#define C_TOPBOTTOM '-' +#define C_LEFTRIGHT '|' +#define C_AIRPORT '=' +#define C_LINE '+' +#define C_BACKROUND '.' +#define C_BEACON '*' +#define C_CREDIT '*' + +WINDOW *radar, *cleanradar, *credit, *input, *planes; + +getAChar() +{ +#ifdef BSD + return (getchar()); +#endif +#ifdef SYSV + int c; + + while ((c = getchar()) == -1 && errno == EINTR) ; + return(c); +#endif +} + +erase_all() +{ + PLANE *pp; + + for (pp = air.head; pp != NULL; pp = pp->next) { + wmove(cleanradar, pp->ypos, pp->xpos * 2); + wmove(radar, pp->ypos, pp->xpos * 2); + waddch(radar, winch(cleanradar)); + wmove(cleanradar, pp->ypos, pp->xpos * 2 + 1); + wmove(radar, pp->ypos, pp->xpos * 2 + 1); + waddch(radar, winch(cleanradar)); + } +} + +draw_all() +{ + PLANE *pp; + + for (pp = air.head; pp != NULL; pp = pp->next) { + if (pp->status == S_MARKED) + wstandout(radar); + wmove(radar, pp->ypos, pp->xpos * 2); + waddch(radar, name(pp)); + waddch(radar, '0' + pp->altitude); + if (pp->status == S_MARKED) + wstandend(radar); + } + wrefresh(radar); + planewin(); + wrefresh(input); /* return cursor */ + fflush(stdout); +} + +init_gr() +{ + static char buffer[BUFSIZ]; + + initscr(); + setbuf(stdout, buffer); + input = newwin(INPUT_LINES, COLS - PLANE_COLS, LINES - INPUT_LINES, 0); + credit = newwin(INPUT_LINES, PLANE_COLS, LINES - INPUT_LINES, + COLS - PLANE_COLS); + planes = newwin(LINES - INPUT_LINES, PLANE_COLS, 0, COLS - PLANE_COLS); +} + +setup_screen(scp) + C_SCREEN *scp; +{ + register int i, j; + char str[3], *airstr; + + str[2] = '\0'; + + if (radar != NULL) + delwin(radar); + radar = newwin(scp->height, scp->width * 2, 0, 0); + + if (cleanradar != NULL) + delwin(cleanradar); + cleanradar = newwin(scp->height, scp->width * 2, 0, 0); + + /* minus one here to prevent a scroll */ + for (i = 0; i < PLANE_COLS - 1; i++) { + wmove(credit, 0, i); + waddch(credit, C_CREDIT); + wmove(credit, INPUT_LINES - 1, i); + waddch(credit, C_CREDIT); + } + wmove(credit, INPUT_LINES / 2, 1); + waddstr(credit, AUTHOR_STR); + + for (i = 1; i < scp->height - 1; i++) { + for (j = 1; j < scp->width - 1; j++) { + wmove(radar, i, j * 2); + waddch(radar, C_BACKROUND); + } + } + + /* + * Draw the lines first, since people like to draw lines + * through beacons and exit points. + */ + str[0] = C_LINE; + for (i = 0; i < scp->num_lines; i++) { + str[1] = ' '; + draw_line(radar, scp->line[i].p1.x, scp->line[i].p1.y, + scp->line[i].p2.x, scp->line[i].p2.y, str); + } + + str[0] = C_TOPBOTTOM; + str[1] = C_TOPBOTTOM; + wmove(radar, 0, 0); + for (i = 0; i < scp->width - 1; i++) + waddstr(radar, str); + waddch(radar, C_TOPBOTTOM); + + str[0] = C_TOPBOTTOM; + str[1] = C_TOPBOTTOM; + wmove(radar, scp->height - 1, 0); + for (i = 0; i < scp->width - 1; i++) + waddstr(radar, str); + waddch(radar, C_TOPBOTTOM); + + for (i = 1; i < scp->height - 1; i++) { + wmove(radar, i, 0); + waddch(radar, C_LEFTRIGHT); + wmove(radar, i, (scp->width - 1) * 2); + waddch(radar, C_LEFTRIGHT); + } + + str[0] = C_BEACON; + for (i = 0; i < scp->num_beacons; i++) { + str[1] = '0' + i; + wmove(radar, scp->beacon[i].y, scp->beacon[i].x * 2); + waddstr(radar, str); + } + + for (i = 0; i < scp->num_exits; i++) { + wmove(radar, scp->exit[i].y, scp->exit[i].x * 2); + waddch(radar, '0' + i); + } + + airstr = "^?>?v?num_airports; i++) { + str[0] = airstr[scp->airport[i].dir]; + str[1] = '0' + i; + wmove(radar, scp->airport[i].y, scp->airport[i].x * 2); + waddstr(radar, str); + } + + overwrite(radar, cleanradar); + wrefresh(radar); + wrefresh(credit); + fflush(stdout); +} + +draw_line(w, x, y, lx, ly, s) + WINDOW *w; + char *s; +{ + int dx, dy; + + dx = SGN(lx - x); + dy = SGN(ly - y); + for (;;) { + wmove(w, y, x * 2); + waddstr(w, s); + if (x == lx && y == ly) + break; + x += dx; + y += dy; + } +} + +ioclrtoeol(pos) +{ + wmove(input, 0, pos); + wclrtoeol(input); + wrefresh(input); + fflush(stdout); +} + +iomove(pos) +{ + wmove(input, 0, pos); + wrefresh(input); + fflush(stdout); +} + +ioaddstr(pos, str) + char *str; +{ + wmove(input, 0, pos); + waddstr(input, str); + wrefresh(input); + fflush(stdout); +} + +ioclrtobot() +{ + wclrtobot(input); + wrefresh(input); + fflush(stdout); +} + +ioerror(pos, len, str) + char *str; +{ + int i; + + wmove(input, 1, pos); + for (i = 0; i < len; i++) + waddch(input, '^'); + wmove(input, 2, 0); + waddstr(input, str); + wrefresh(input); + fflush(stdout); +} + +quit() +{ + int c, y, x; +#ifdef BSD + struct itimerval itv; +#endif + + getyx(input, y, x); + wmove(input, 2, 0); + waddstr(input, "Really quit? (y/n) "); + wclrtobot(input); + wrefresh(input); + fflush(stdout); + + c = getchar(); + if (c == EOF || c == 'y') { + /* disable timer */ +#ifdef BSD + itv.it_value.tv_sec = 0; + itv.it_value.tv_usec = 0; + setitimer(ITIMER_REAL, &itv, NULL); +#endif +#ifdef SYSV + alarm(0); +#endif + fflush(stdout); + clear(); + refresh(); + endwin(); + log_score(0); + exit(0); + } + wmove(input, 2, 0); + wclrtobot(input); + wmove(input, y, x); + wrefresh(input); + fflush(stdout); + return; +} + +planewin() +{ + PLANE *pp; + char *command(); + int warning = 0; + +#ifdef BSD + wclear(planes); +#endif + + wmove(planes, 0,0); + +#ifdef SYSV + wclrtobot(planes); +#endif + wprintw(planes, "Time: %-4d Safe: %d", clock, safe_planes); + wmove(planes, 2, 0); + + waddstr(planes, "pl dt comm"); + for (pp = air.head; pp != NULL; pp = pp->next) { + if (waddch(planes, '\n') == ERR) { + warning++; + break; + } + waddstr(planes, command(pp)); + } + waddch(planes, '\n'); + for (pp = ground.head; pp != NULL; pp = pp->next) { + if (waddch(planes, '\n') == ERR) { + warning++; + break; + } + waddstr(planes, command(pp)); + } + if (warning) { + wmove(planes, LINES - INPUT_LINES - 1, 0); + waddstr(planes, "---- more ----"); + wclrtoeol(planes); + } + wrefresh(planes); + fflush(stdout); +} + +loser(p, s) + PLANE *p; + char *s; +{ + int c; +#ifdef BSD + struct itimerval itv; +#endif + + /* disable timer */ +#ifdef BSD + itv.it_value.tv_sec = 0; + itv.it_value.tv_usec = 0; + setitimer(ITIMER_REAL, &itv, NULL); +#endif +#ifdef SYSV + alarm(0); +#endif + + wmove(input, 0, 0); + wclrtobot(input); + wprintw(input, "Plane '%c' %s\n\nHit space for top players list...", + name(p), s); + wrefresh(input); + fflush(stdout); + while ((c = getchar()) != EOF && c != ' ') + ; + clear(); /* move to top of screen */ + refresh(); + endwin(); + log_score(0); + exit(0); +} + +redraw() +{ + clear(); + refresh(); + + touchwin(radar); + wrefresh(radar); + touchwin(planes); + wrefresh(planes); + touchwin(credit); + wrefresh(credit); + + /* refresh input last to get cursor in right place */ + touchwin(input); + wrefresh(input); + fflush(stdout); +} + + +done_screen() +{ + clear(); + refresh(); + endwin(); /* clean up curses */ +} diff --git a/src/games/atc/include.h b/src/games/atc/include.h new file mode 100644 index 0000000..084a3e5 --- /dev/null +++ b/src/games/atc/include.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 1987 by Ed James, UC Berkeley. All rights reserved. + * + * Copy permission is hereby granted provided that this notice is + * retained on all partial or complete copies. + * + * For more info on this and all of my stuff, mail edjames@berkeley.edu. + */ + +#include +#include +#ifdef SYSV +#include +#endif +#include + +#ifdef BSD +#include +#include +#include +#endif + +#ifdef SYSV +#include +#include +#include +#include +#endif + +#include +#include + +#include + +#ifdef SYSV +#define index strchr +#define rindex strrchr +#define bcopy(a,b,c) memcpy((b), (a), (c)) +#define bzero(a,b) memset((a), '\0', (b)) +#define srandom srand +#define random rand +#define sgttyb termio +#define sg_erase c_cc[2] +#define sg_kill c_cc[3] +#endif + +#include "def.h" +#include "struct.h" +#include "extern.h" +#include "tunable.h" diff --git a/src/games/atc/input.c b/src/games/atc/input.c new file mode 100644 index 0000000..7a31b54 --- /dev/null +++ b/src/games/atc/input.c @@ -0,0 +1,626 @@ +/* + * Copyright (c) 1987 by Ed James, UC Berkeley. All rights reserved. + * + * Copy permission is hereby granted provided that this notice is + * retained on all partial or complete copies. + * + * For more info on this and all of my stuff, mail edjames@berkeley.edu. + */ + +#ifndef lint +static char sccsid[] = "@(#)input.c 1.2 (Berkeley) 10/22/87"; +#endif not lint + +#include "include.h" + +#define MAXRULES 6 +#define MAXDEPTH 15 + +#define RETTOKEN '\n' +#ifdef SYSV +#define CRTOKEN '\r' +#endif +#define REDRAWTOKEN '\014' /* CTRL(L) */ +#define SHELLTOKEN '!' +#define HELPTOKEN '?' +#define ALPHATOKEN 256 +#define NUMTOKEN 257 + +typedef struct { + int token; + int to_state; + char *str; + char *(*func)(); +} RULE; + +typedef struct { + int num_rules; + RULE *rule; +} STATE; + +typedef struct { + char str[20]; + int state; + int rule; + int ch; + int pos; +} STACK; + +#define T_RULE stack[level].rule +#define T_STATE stack[level].state +#define T_STR stack[level].str +#define T_POS stack[level].pos +#define T_CH stack[level].ch + +#define NUMELS(a) (sizeof (a) / sizeof (*(a))) + +#define NUMSTATES NUMELS(st) + +char *setplane(), *circle(), *left(), *right(), *Left(), *Right(), + *beacon(), *ex_it(), *climb(), *descend(), *setalt(), *setrelalt(), + *benum(), *to_dir(), *rel_dir(), *delayb(), *mark(), *unmark(), + *airport(), *turn(), *ignore(); + +RULE state0[] = { { ALPHATOKEN, 1, "%c:", setplane}, + { RETTOKEN, -1, "", NULL }, +#ifdef SYSV + { CRTOKEN, -1, "", NULL }, +#endif + { HELPTOKEN, 12, " [a-z]", NULL }}, + state1[] = { { 't', 2, " turn", turn }, + { 'a', 3, " altitude:", NULL }, + { 'c', 4, " circle", circle }, + { 'm', 7, " mark", mark }, + { 'u', 7, " unmark", unmark }, + { 'i', 7, " ignore", ignore }, + { HELPTOKEN, 12, " tacmui", NULL }}, + state2[] = { { 'l', 6, " left", left }, + { 'r', 6, " right", right }, + { 'L', 4, " left 90", Left }, + { 'R', 4, " right 90", Right }, + { 't', 11, " towards", NULL }, + { 'w', 4, " to 0", to_dir }, + { 'e', 4, " to 45", to_dir }, + { 'd', 4, " to 90", to_dir }, + { 'c', 4, " to 135", to_dir }, + { 'x', 4, " to 180", to_dir }, + { 'z', 4, " to 225", to_dir }, + { 'a', 4, " to 270", to_dir }, + { 'q', 4, " to 315", to_dir }, + { HELPTOKEN, 12, " lrLRt", NULL }}, + state3[] = { { '+', 10, " climb", climb }, + { 'c', 10, " climb", climb }, + { '-', 10, " descend", descend }, + { 'd', 10, " descend", descend }, + { NUMTOKEN, 7, " %c000 feet", setalt }, + { HELPTOKEN, 12, " +-cd[0-9]", NULL }}, + state4[] = { { '@', 9, " at", NULL }, + { 'a', 9, " at", NULL }, + { RETTOKEN, -1, "", NULL }, +#ifdef SYSV + { CRTOKEN, -1, "", NULL }, +#endif + { HELPTOKEN, 12, " @a", NULL }}, + state5[] = { { NUMTOKEN, 7, "%c", delayb }, + { HELPTOKEN, 12, " [0-9]", NULL }}, + state6[] = { { '@', 9, " at", NULL }, + { 'a', 9, " at", NULL }, + { 'w', 4, " 0", rel_dir }, + { 'e', 4, " 45", rel_dir }, + { 'd', 4, " 90", rel_dir }, + { 'c', 4, " 135", rel_dir }, + { 'x', 4, " 180", rel_dir }, + { 'z', 4, " 225", rel_dir }, + { 'a', 4, " 270", rel_dir }, + { 'q', 4, " 315", rel_dir }, + { RETTOKEN, -1, "", NULL }, +#ifdef SYSV + { CRTOKEN, -1, "", NULL }, +#endif + { HELPTOKEN, 12, " @a",NULL }}, + state7[] = { { RETTOKEN, -1, "", NULL }, +#ifdef SYSV + { CRTOKEN, -1, "", NULL }, +#endif + { HELPTOKEN, 12, " ", NULL }}, + state8[] = { { NUMTOKEN, 4, "%c", benum }, + { HELPTOKEN, 12, " [0-9]", NULL }}, + state9[] = { { 'b', 5, " beacon #", NULL }, + { '*', 5, " beacon #", NULL }, + { HELPTOKEN, 12, " b*", NULL }}, + state10[] = { { NUMTOKEN, 7, " %c000 ft", setrelalt}, + { HELPTOKEN, 12, " [0-9]", NULL }}, + state11[] = { { 'b', 8, " beacon #", beacon }, + { '*', 8, " beacon #", beacon }, + { 'e', 8, " exit #", ex_it }, + { 'a', 8, " airport #", airport }, + { HELPTOKEN, 12, " b*ea", NULL }}, + state12[] = { { -1, -1, "", NULL }}; + +#define DEF_STATE(s) { NUMELS(s), (s) } + +STATE st[] = { + DEF_STATE(state0), DEF_STATE(state1), DEF_STATE(state2), + DEF_STATE(state3), DEF_STATE(state4), DEF_STATE(state5), + DEF_STATE(state6), DEF_STATE(state7), DEF_STATE(state8), + DEF_STATE(state9), DEF_STATE(state10), DEF_STATE(state11), + DEF_STATE(state12) +}; + +PLANE p; +STACK stack[MAXDEPTH]; +int level; +int tval; +int dest_type, dest_no, dir; + +pop() +{ + if (level == 0) + return (-1); + level--; + + ioclrtoeol(T_POS); + + strcpy(T_STR, ""); + T_RULE = -1; + T_CH = -1; + return (0); +} + +rezero() +{ + iomove(0); + + level = 0; + T_STATE = 0; + T_RULE = -1; + T_CH = -1; + T_POS = 0; + strcpy(T_STR, ""); +} + +push(ruleno, ch) +{ + int newstate, newpos; + + (void)sprintf(T_STR, st[T_STATE].rule[ruleno].str, tval); + T_RULE = ruleno; + T_CH = ch; + newstate = st[T_STATE].rule[ruleno].to_state; + newpos = T_POS + strlen(T_STR); + + ioaddstr(T_POS, T_STR); + + if (level == 0) + ioclrtobot(); + level++; + T_STATE = newstate; + T_POS = newpos; + T_RULE = -1; + strcpy(T_STR, ""); +} + +getcommand() +{ + int c, i, done; + char *s, *(*func)(); + PLANE *pp; + + rezero(); + + do { + c = gettoken(); + if (c == tty_new.sg_erase) { + if (pop() < 0) + noise(); + } else if (c == tty_new.sg_kill) { + while (pop() >= 0) + ; + } else { + done = 0; + for (i = 0; i < st[T_STATE].num_rules; i++) { + if (st[T_STATE].rule[i].token == c || + st[T_STATE].rule[i].token == tval) { + push(i, (c >= ALPHATOKEN) ? tval : c); + done = 1; + break; + } + } + if (!done) + noise(); + } + } while (T_STATE != -1); + + if (level == 1) + return (1); /* forced update */ + + dest_type = T_NODEST; + + for (i = 0; i < level; i++) { + func = st[stack[i].state].rule[stack[i].rule].func; + if (func != NULL) + if ((s = (*func)(stack[i].ch)) != NULL) { + ioerror(stack[i].pos, strlen(stack[i].str), s); + return (-1); + } + } + + pp = findplane(p.plane_no); + if (pp->new_altitude != p.new_altitude) + pp->new_altitude = p.new_altitude; + else if (pp->status != p.status) + pp->status = p.status; + else { + pp->new_dir = p.new_dir; + pp->delayd = p.delayd; + pp->delayd_no = p.delayd_no; + } + return (0); +} + +noise() +{ + putchar('\07'); + fflush(stdout); +} + +gettoken() +{ + while ((tval = getAChar()) == REDRAWTOKEN || tval == SHELLTOKEN) + { + if (tval == SHELLTOKEN) + { +#ifdef BSD + struct itimerval itv; + itv.it_value.tv_sec = 0; + itv.it_value.tv_usec = 0; + setitimer(ITIMER_REAL, &itv, NULL); +#endif +#ifdef SYSV + int aval; + aval = alarm(0); +#endif + if (fork() == 0) /* child */ + { + char *shell, *base, *getenv(), *strrchr(); + + setuid(getuid()); /* turn off setuid bit */ + done_screen(); + + /* run user's favorite shell */ + if ((shell = getenv("SHELL")) != NULL) + { + base = strrchr(shell, '/'); + if (base == NULL) + base = shell; + else + base++; + execl(shell, base, 0); + } + else + execl("/bin/sh", "sh", 0); + + exit(0); /* oops */ + } + + wait(0); +#ifdef BSD + ioctl(fileno(stdin), TIOCSETP, &tty_new); + itv.it_value.tv_sec = 0; + itv.it_value.tv_usec = 1; + itv.it_interval.tv_sec = sp->update_secs; + itv.it_interval.tv_usec = 0; + setitimer(ITIMER_REAL, &itv, NULL); +#endif +#ifdef SYSV + ioctl(fileno(stdin), TCSETAW, &tty_new); + alarm(aval); +#endif + } + redraw(); + } + + if (isdigit(tval)) + return (NUMTOKEN); + else if (isalpha(tval)) + return (ALPHATOKEN); + else + return (tval); +} + +char * +setplane(c) +{ + PLANE *pp; + + pp = findplane(number(c)); + if (pp == NULL) + return ("Unknown Plane"); + bcopy(pp, &p, sizeof (p)); + p.delayd = 0; + return (NULL); +} + +char * +turn(c) +{ + if (p.altitude == 0) + return ("Planes at airports may not change direction"); + return (NULL); +} + +char * +circle(c) +{ + if (p.altitude == 0) + return ("Planes cannot circle on the ground"); + p.new_dir = MAXDIR; + return (NULL); +} + +char * +left(c) +{ + dir = D_LEFT; + p.new_dir = p.dir - 1; + if (p.new_dir < 0) + p.new_dir += MAXDIR; + return (NULL); +} + +char * +right(c) +{ + dir = D_RIGHT; + p.new_dir = p.dir + 1; + if (p.new_dir > MAXDIR) + p.new_dir -= MAXDIR; + return (NULL); +} + +char * +Left(c) +{ + p.new_dir = p.dir - 2; + if (p.new_dir < 0) + p.new_dir += MAXDIR; + return (NULL); +} + +char * +Right(c) +{ + p.new_dir = p.dir + 2; + if (p.new_dir > MAXDIR) + p.new_dir -= MAXDIR; + return (NULL); +} + +char * +delayb(c) +{ + int xdiff, ydiff; + + c -= '0'; + + if (c >= sp->num_beacons) + return ("Unknown beacon"); + xdiff = sp->beacon[c].x - p.xpos; + xdiff = SGN(xdiff); + ydiff = sp->beacon[c].y - p.ypos; + ydiff = SGN(ydiff); + if (xdiff != displacement[p.dir].dx || ydiff != displacement[p.dir].dy) + return ("Beacon is not in flight path"); + p.delayd = 1; + p.delayd_no = c; + + if (dest_type != T_NODEST) { + switch (dest_type) { + case T_BEACON: + xdiff = sp->beacon[dest_no].x - sp->beacon[c].x; + ydiff = sp->beacon[dest_no].y - sp->beacon[c].y; + break; + case T_EXIT: + xdiff = sp->exit[dest_no].x - sp->beacon[c].x; + ydiff = sp->exit[dest_no].y - sp->beacon[c].y; + break; + case T_AIRPORT: + xdiff = sp->airport[dest_no].x - sp->beacon[c].x; + ydiff = sp->airport[dest_no].y - sp->beacon[c].y; + break; + default: + return ("Bad case in delayb! Get help!"); + break; + } + if (xdiff == 0 && ydiff == 0) + return ("Would already be there"); + p.new_dir = DIR_FROM_DXDY(xdiff, ydiff); + if (p.new_dir == p.dir) + return ("Already going in that direction"); + } + return (NULL); +} + +char * +beacon(c) +{ + dest_type = T_BEACON; + return (NULL); +} + +char * +ex_it(c) +{ + dest_type = T_EXIT; + return (NULL); +} + +char * +airport(c) +{ + dest_type = T_AIRPORT; + return (NULL); +} + +char * +climb(c) +{ + dir = D_UP; + return (NULL); +} + +char * +descend(c) +{ + dir = D_DOWN; + return (NULL); +} + +char * +setalt(c) +{ + if ((p.altitude == c - '0') && (p.new_altitude == p.altitude)) + return ("Already at that altitude"); + p.new_altitude = c - '0'; + return (NULL); +} + +char * +setrelalt(c) +{ + if (c == 0) + return ("altitude not changed"); + + switch (dir) { + case D_UP: + p.new_altitude = p.altitude + c - '0'; + break; + case D_DOWN: + p.new_altitude = p.altitude - (c - '0'); + break; + default: + return ("Unknown case in setrelalt! Get help!"); + break; + } + if (p.new_altitude < 0) + return ("Altitude would be too low"); + else if (p.new_altitude > 9) + return ("Altitude would be too high"); + return (NULL); +} + +char * +benum(c) +{ + dest_no = c -= '0'; + + switch (dest_type) { + case T_BEACON: + if (c >= sp->num_beacons) + return ("Unknown beacon"); + p.new_dir = DIR_FROM_DXDY(sp->beacon[c].x - p.xpos, + sp->beacon[c].y - p.ypos); + break; + case T_EXIT: + if (c >= sp->num_exits) + return ("Unknown exit"); + p.new_dir = DIR_FROM_DXDY(sp->exit[c].x - p.xpos, + sp->exit[c].y - p.ypos); + break; + case T_AIRPORT: + if (c >= sp->num_airports) + return ("Unknown airport"); + p.new_dir = DIR_FROM_DXDY(sp->airport[c].x - p.xpos, + sp->airport[c].y - p.ypos); + break; + default: + return ("Unknown case in benum! Get help!"); + break; + } + return (NULL); +} + +char * +to_dir(c) +{ + p.new_dir = dir_no(c); + return (NULL); +} + +char * +rel_dir(c) +{ + int angle; + + angle = dir_no(c); + switch (dir) { + case D_LEFT: + p.new_dir = p.dir - angle; + if (p.new_dir < 0) + p.new_dir += MAXDIR; + break; + case D_RIGHT: + p.new_dir = p.dir + angle; + if (p.new_dir >= MAXDIR) + p.new_dir -= MAXDIR; + break; + default: + return ("Bizarre direction in rel_dir! Get help!"); + break; + } + return (NULL); +} + +char * +mark(c) +{ + if (p.altitude == 0) + return ("Cannot mark planes on the ground"); + if (p.status == S_MARKED) + return ("Already marked"); + p.status = S_MARKED; + return (NULL); +} + +char * +unmark(c) +{ + if (p.altitude == 0) + return ("Cannot unmark planes on the ground"); + if (p.status == S_UNMARKED) + return ("Already unmarked"); + p.status = S_UNMARKED; + return (NULL); +} + +char * +ignore(c) +{ + if (p.altitude == 0) + return ("Cannot ignore planes on the ground"); + if (p.status == S_IGNORED) + return ("Already ignored"); + p.status = S_IGNORED; + return (NULL); +} + +dir_no(ch) + char ch; +{ + int dir; + + switch (ch) { + case 'w': dir = 0; break; + case 'e': dir = 1; break; + case 'd': dir = 2; break; + case 'c': dir = 3; break; + case 'x': dir = 4; break; + case 'z': dir = 5; break; + case 'a': dir = 6; break; + case 'q': dir = 7; break; + default: + fprintf(stderr, "bad character in dir_no\n"); + break; + } + return (dir); +} diff --git a/src/games/atc/lex.l b/src/games/atc/lex.l new file mode 100644 index 0000000..dde6315 --- /dev/null +++ b/src/games/atc/lex.l @@ -0,0 +1,28 @@ +%{ +/* + * Copyright (c) 1987 by Ed James, UC Berkeley. All rights reserved. + * + * Copy permission is hereby granted provided that this notice is + * retained on all partial or complete copies. + * + * For more info on this and all of my stuff, mail edjames@berkeley.edu. + */ + +#include "y.tab.h" +extern int line; +%} +%% +[0-9]+ { yylval.ival = atoi(yytext); return(ConstOp); } +height { return(HeightOp); } +width { return(WidthOp); } +newplane { return(NewplaneOp); } +update { return(UpdateOp); } +airport { return(AirportOp); } +line { return(LineOp); } +exit { return(ExitOp); } +beacon { return(BeaconOp); } +[wedcxzaq] { yylval.cval = *yytext; return (DirOp); } +[ \t]+ { } +#[^\n]*\n { line++; } +\n { line++; } +. { return *yytext; } diff --git a/src/games/atc/list.c b/src/games/atc/list.c new file mode 100644 index 0000000..5498e59 --- /dev/null +++ b/src/games/atc/list.c @@ -0,0 +1,75 @@ +/* + * Copyright (c) 1987 by Ed James, UC Berkeley. All rights reserved. + * + * Copy permission is hereby granted provided that this notice is + * retained on all partial or complete copies. + * + * For more info on this and all of my stuff, mail edjames@berkeley.edu. + */ + +#include "include.h" + +PLANE * +newplane() +{ + return ((PLANE *) calloc(1, sizeof (PLANE))); +} + +append(l, p) + LIST *l; + PLANE *p; +{ + PLANE *q = NULL, *r = NULL; + + if (l->head == NULL) { + p->next = p->prev = NULL; + l->head = l->tail = p; + } else { + q = l -> head; + + while (q != NULL && q->plane_no < p->plane_no) { + r = q; + q = q -> next; + } + + if (q) { + if (r) { + p->prev = r; + r->next = p; + p->next = q; + q->prev = p; + } else { + p->next = q; + p->prev = NULL; + q->prev = p; + l->head = p; + } + } else { + l->tail->next = p; + p->next = NULL; + p->prev = l->tail; + l->tail = p; + } + } +} + +delete(l, p) + LIST *l; + PLANE *p; +{ + if (l->head == NULL) + loser(p, "deleted a non-existant plane! Get help!"); + + if (l->head == p && l->tail == p) + l->head = l->tail = NULL; + else if (l->head == p) { + l->head = p->next; + l->head->prev = NULL; + } else if (l->tail == p) { + l->tail = p->prev; + l->tail->next = NULL; + } else { + p->prev->next = p->next; + p->next->prev = p->prev; + } +} diff --git a/src/games/atc/log.c b/src/games/atc/log.c new file mode 100644 index 0000000..cf92d85 --- /dev/null +++ b/src/games/atc/log.c @@ -0,0 +1,213 @@ +/* + * Copyright (c) 1987 by Ed James, UC Berkeley. All rights reserved. + * + * Copy permission is hereby granted provided that this notice is + * retained on all partial or complete copies. + * + * For more info on this and all of my stuff, mail edjames@berkeley.edu. + */ + +#ifndef lint +static char sccsid[] = "@(#)log.c 1.4 (Berkeley) 12/26/87"; +#endif not lint + +#include "include.h" + +compar(a, b) + SCORE *a, *b; +{ + if (b->planes == a->planes) + return (b->time - a->time); + else + return (b->planes - a->planes); +} + +#define SECAMIN 60 +#define MINAHOUR 60 +#define HOURADAY 24 +#define SECAHOUR (SECAMIN * MINAHOUR) +#define SECADAY (SECAHOUR * HOURADAY) +#define DAY(t) ((t) / SECADAY) +#define HOUR(t) (((t) % SECADAY) / SECAHOUR) +#define MIN(t) (((t) % SECAHOUR) / SECAMIN) +#define SEC(t) ((t) % SECAMIN) + +char * +timestr(t) +{ + static char s[80]; + + if (DAY(t) > 0) + (void)sprintf(s, "%dd+%02dhrs", DAY(t), HOUR(t)); + else if (HOUR(t) > 0) + (void)sprintf(s, "%d:%02d:%02d", HOUR(t), MIN(t), SEC(t)); + else if (MIN(t) > 0) + (void)sprintf(s, "%d:%02d", MIN(t), SEC(t)); + else if (SEC(t) > 0) + (void)sprintf(s, ":%02d", SEC(t)); + else + *s = '\0'; + + return (s); +} + +log_score(list_em) +{ + register int i, fd, num_scores = 0, good, changed = 0, found = 0; + struct passwd *pw; + FILE *fp; + char *cp, logstr[BUFSIZ], *index(), *rindex(); + SCORE score[100], thisscore; +#ifdef SYSV + struct utsname name; +#endif + + strcpy(logstr, SPECIAL_DIR); + strcat(logstr, LOG); + + umask(0); + fd = open(logstr, O_CREAT|O_RDWR, 0644); + if (fd < 0) { + perror(logstr); + return (-1); + } + /* + * This is done to take advantage of stdio, while still + * allowing a O_CREAT during the open(2) of the log file. + */ + fp = fdopen(fd, "r+"); + if (fp == NULL) { + perror(logstr); + return (-1); + } +#ifdef BSD + if (flock(fileno(fp), LOCK_EX) < 0) +#endif +#ifdef SYSV + while (lockf(fileno(fp), F_LOCK, 1) < 0) +#endif + { + perror("flock"); + return (-1); + } + for (;;) { + good = fscanf(fp, "%s %s %s %d %d %d", + score[num_scores].name, + score[num_scores].host, + score[num_scores].game, + &score[num_scores].planes, + &score[num_scores].time, + &score[num_scores].real_time); + if (good != 6 || ++num_scores >= NUM_SCORES) + break; + } + if (!test_mode && !list_em) { + if ((pw = (struct passwd *) getpwuid(getuid())) == NULL) { + fprintf(stderr, + "getpwuid failed for uid %d. Who are you?\n", + getuid()); + return (-1); + } + strcpy(thisscore.name, pw->pw_name); +#ifdef BSD + if (gethostname(thisscore.host, sizeof (thisscore.host)) < 0) { + perror("gethostname"); + return (-1); + } +#endif +#ifdef SYSV + uname(&name); + strcpy(thisscore.host, name.sysname); +#endif + + cp = rindex(file, '/'); + if (cp == NULL) { + fprintf(stderr, "log: where's the '/' in %s?\n", file); + return (-1); + } + cp++; + strcpy(thisscore.game, cp); + + thisscore.time = clock; + thisscore.planes = safe_planes; + thisscore.real_time = time(0) - start_time; + + for (i = 0; i < num_scores; i++) { + if (strcmp(thisscore.name, score[i].name) == 0 && + strcmp(thisscore.host, score[i].host) == 0 && + strcmp(thisscore.game, score[i].game) == 0) { + if (thisscore.time > score[i].time) { + score[i].time = thisscore.time; + score[i].planes = thisscore.planes; + score[i].real_time = + thisscore.real_time; + changed++; + } + found++; + break; + } + } + if (!found) { + for (i = 0; i < num_scores; i++) { + if (thisscore.time > score[i].time) { + if (num_scores < NUM_SCORES) + num_scores++; + bcopy(&score[i], + &score[num_scores - 1], + sizeof (score[i])); + bcopy(&thisscore, &score[i], + sizeof (score[i])); + changed++; + break; + } + } + } + if (!found && !changed && num_scores < NUM_SCORES) { + bcopy(&thisscore, &score[num_scores], + sizeof (score[num_scores])); + num_scores++; + changed++; + } + + if (changed) { + if (found) + puts("You beat your previous score!"); + else + puts("You made the top players list!"); + qsort(score, num_scores, sizeof (*score), compar); + rewind(fp); + for (i = 0; i < num_scores; i++) + fprintf(fp, "%s %s %s %d %d %d\n", + score[i].name, score[i].host, + score[i].game, score[i].planes, + score[i].time, score[i].real_time); + } else { + if (found) + puts("You didn't beat your previous score."); + else + puts("You didn't make the top players list."); + } + putchar('\n'); + } +#ifdef BSD + flock(fileno(fp), LOCK_UN); +#endif +#ifdef SYSV + /* lock will evaporate upon close */ +#endif + fclose(fp); + printf("%2s: %-8s %-8s %-18s %4s %9s %4s\n", "#", "name", "host", + "game", "time", "real time", "planes safe"); + puts("-------------------------------------------------------------------------------"); + for (i = 0; i < num_scores; i++) { + cp = index(score[i].host, '.'); + if (cp != NULL) + *cp = '\0'; + printf("%2d: %-8s %-8s %-18s %4d %9s %4d\n", i + 1, + score[i].name, score[i].host, score[i].game, + score[i].time, timestr(score[i].real_time), + score[i].planes); + } + putchar('\n'); + return (0); +} diff --git a/src/games/atc/main.c b/src/games/atc/main.c new file mode 100644 index 0000000..24218d7 --- /dev/null +++ b/src/games/atc/main.c @@ -0,0 +1,279 @@ +/* + * Copyright (c) 1987 by Ed James, UC Berkeley. All rights reserved. + * + * Copy permission is hereby granted provided that this notice is + * retained on all partial or complete copies. + * + * For more info on this and all of my stuff, mail edjames@berkeley.edu. + */ + +#include "include.h" + +main(ac, av) + char *av[]; +{ + int seed; + int f_usage = 0, f_list = 0, f_showscore = 0; + int f_printpath = 0; + char *file = NULL; + char *name, *ptr; +#ifdef BSD + struct itimerval itv; +#endif + extern int update(), quit(), log_score(); + extern char *default_game(), *okay_game(); + + start_time = seed = time(0); + + name = *av++; + while (*av) { +#ifndef SAVEDASH + if (**av == '-') + *++*av; + else + break; +#endif + ptr = *av++; + while (*ptr) { + switch (*ptr) { + case '?': + case 'u': + f_usage++; + break; + case 'l': + f_list++; + break; + case 's': + case 't': + f_showscore++; + break; + case 'p': + f_printpath++; + break; + case 'r': + seed = atoi(*av); + av++; + break; + case 'f': + case 'g': + file = *av; + av++; + break; + default: + fprintf(stderr, "Unknown option '%c'\n", *ptr, + name); + f_usage++; + break; + } + ptr++; + } + } + srandom(seed); + + if (f_usage) + fprintf(stderr, + "Usage: %s -[u?lstp] [-[gf] game_name] [-r random seed]\n", + name); + if (f_showscore) + log_score(1); + if (f_list) + list_games(); + if (f_printpath) { + char buf[100]; + + strcpy(buf, SPECIAL_DIR); + buf[strlen(buf) - 1] = '\0'; + puts(buf); + } + + if (f_usage || f_showscore || f_list || f_printpath) + exit(0); + + if (file == NULL) + file = default_game(); + else + file = okay_game(file); + + if (file == NULL || read_file(file) < 0) + exit(1); + + init_gr(); + setup_screen(sp); + + addplane(); + + signal(SIGINT, quit); + signal(SIGQUIT, quit); +#ifdef BSD + signal(SIGTSTP, SIG_IGN); + signal(SIGSTOP, SIG_IGN); +#endif + signal(SIGHUP, log_score); + signal(SIGTERM, log_score); + +#ifdef BSD + ioctl(fileno(stdin), TIOCGETP, &tty_start); + bcopy(&tty_start, &tty_new, sizeof(tty_new)); + tty_new.sg_flags |= CBREAK; + tty_new.sg_flags &= ~ECHO; + ioctl(fileno(stdin), TIOCSETP, &tty_new); +#endif + +#ifdef SYSV + ioctl(fileno(stdin), TCGETA, &tty_start); + bcopy(&tty_start, &tty_new, sizeof(tty_new)); + tty_new.c_lflag &= ~ICANON; + tty_new.c_lflag &= ~ECHO; + tty_new.c_cc[VMIN] = 1; + tty_new.c_cc[VTIME] = 0; + ioctl(fileno(stdin), TCSETAW, &tty_new); +#endif + + signal(SIGALRM, update); + +#ifdef BSD + itv.it_value.tv_sec = 0; + itv.it_value.tv_usec = 1; + itv.it_interval.tv_sec = sp->update_secs; + itv.it_interval.tv_usec = 0; + setitimer(ITIMER_REAL, &itv, NULL); +#endif +#ifdef SYSV + alarm(sp->update_secs); +#endif + + for (;;) { + if (getcommand() != 1) + planewin(); + else { +#ifdef BSD + itv.it_value.tv_sec = 0; + itv.it_value.tv_usec = 0; + setitimer(ITIMER_REAL, &itv, NULL); +#endif +#ifdef SYSV + alarm(0); +#endif + + update(); + +#ifdef BSD + itv.it_value.tv_sec = sp->update_secs; + itv.it_value.tv_usec = 0; + itv.it_interval.tv_sec = sp->update_secs; + itv.it_interval.tv_usec = 0; + setitimer(ITIMER_REAL, &itv, NULL); +#endif +#ifdef SYSV + alarm(sp->update_secs); +#endif + } + } +} + +read_file(s) + char *s; +{ + extern FILE *yyin; + int retval; + + file = s; + yyin = fopen(s, "r"); + if (yyin == NULL) { + perror(s); + return (-1); + } + retval = yyparse(); + fclose(yyin); + + if (retval != 0) + return (-1); + else + return (0); +} + +char * +default_game() +{ + FILE *fp; + static char file[256]; + char line[256], games[256]; + + strcpy(games, SPECIAL_DIR); + strcat(games, GAMES); + + if ((fp = fopen(games, "r")) == NULL) { + perror(games); + return (NULL); + } + if (fgets(line, sizeof(line), fp) == NULL) { + fprintf(stderr, "%s: no default game available\n", games); + return (NULL); + } + fclose(fp); + line[strlen(line) - 1] = '\0'; + strcpy(file, SPECIAL_DIR); + strcat(file, line); + return (file); +} + +char * +okay_game(s) + char *s; +{ + FILE *fp; + static char file[256]; + char *ret = NULL, line[256], games[256]; + + strcpy(games, SPECIAL_DIR); + strcat(games, GAMES); + + if ((fp = fopen(games, "r")) == NULL) { + perror(games); + return (NULL); + } + while (fgets(line, sizeof(line), fp) != NULL) { + line[strlen(line) - 1] = '\0'; + if (strcmp(s, line) == 0) { + strcpy(file, SPECIAL_DIR); + strcat(file, line); + ret = file; + break; + } + } + fclose(fp); + if (ret == NULL) { + test_mode = 1; + ret = s; + fprintf(stderr, "%s: %s: game not found\n", games, s); + fprintf(stderr, "Your score will not be logged.\n"); + sleep(2); /* give the guy time to read it */ + } + return (ret); +} + +list_games() +{ + FILE *fp; + char line[256], games[256]; + int num_games = 0; + + strcpy(games, SPECIAL_DIR); + strcat(games, GAMES); + + if ((fp = fopen(games, "r")) == NULL) { + perror(games); + return (-1); + } + puts("available games:"); + while (fgets(line, sizeof(line), fp) != NULL) { + printf(" %s", line); + num_games++; + } + fclose(fp); + if (num_games == 0) { + fprintf(stderr, "%s: no games available\n", games); + return (-1); + } + return (0); +} diff --git a/src/games/atc/struct.h b/src/games/atc/struct.h new file mode 100644 index 0000000..1a02e08 --- /dev/null +++ b/src/games/atc/struct.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 1987 by Ed James, UC Berkeley. All rights reserved. + * + * Copy permission is hereby granted provided that this notice is + * retained on all partial or complete copies. + * + * For more info on this and all of my stuff, mail edjames@berkeley.edu. + */ + +typedef struct { + int x, y; + int dir; /* used only sometimes */ +} SCREEN_POS; + +typedef struct { + SCREEN_POS p1, p2; +} LINE; + +typedef SCREEN_POS EXIT; +typedef SCREEN_POS BEACON; +typedef SCREEN_POS AIRPORT; + +typedef struct { + int width, height; + int update_secs; + int newplane_time; + int num_exits; + int num_lines; + int num_beacons; + int num_airports; + EXIT *exit; + LINE *line; + BEACON *beacon; + AIRPORT *airport; +} C_SCREEN; + +typedef struct plane { + struct plane *next, *prev; + int status; + int plane_no; + int plane_type; + int orig_no; + int orig_type; + int dest_no; + int dest_type; + int altitude; + int new_altitude; + int dir; + int new_dir; + int fuel; + int xpos; + int ypos; + int delayd; + int delayd_no; +} PLANE; + +typedef struct { + PLANE *head, *tail; +} LIST; + +typedef struct { + char name[10]; + char host[256]; + char game[256]; + int planes; + int time; + int real_time; +} SCORE; + +typedef struct displacement { + int dx; + int dy; +} DISPLACEMENT; diff --git a/src/games/atc/tunable.c b/src/games/atc/tunable.c new file mode 100644 index 0000000..52241f7 --- /dev/null +++ b/src/games/atc/tunable.c @@ -0,0 +1,24 @@ +/* + * Copyright (c) 1987 by Ed James, UC Berkeley. All rights reserved. + * + * Copy permission is hereby granted provided that this notice is + * retained on all partial or complete copies. + * + * For more info on this and all of my stuff, mail edjames@berkeley.edu. + */ + +/* + * SPECIAL_DIR - Where the special files are kept. + * Change this to whatever you want. Be sure to have to path end + * with a '/', like "/usr/games/lib/atc/". + */ + +char SPECIAL_DIR[] = DEST; + +/* + * NUM_SCORES - Number of scores that are kept track of. + * Keep this greater than 0, but less than 100. + * 4 lines are printed above the score, one below + your prompt, so + * to prevent scrolling: 6 + NUM_SCORES <= 24 (lines on an average terminal). + */ +int NUM_SCORES = 18; diff --git a/src/games/atc/tunable.h b/src/games/atc/tunable.h new file mode 100644 index 0000000..685da72 --- /dev/null +++ b/src/games/atc/tunable.h @@ -0,0 +1,12 @@ +/* + * Copyright (c) 1987 by Ed James, UC Berkeley. All rights reserved. + * + * Copy permission is hereby granted provided that this notice is + * retained on all partial or complete copies. + * + * For more info on this and all of my stuff, mail edjames@berkeley.edu. + */ + +extern char SPECIAL_DIR[]; + +extern int NUM_SCORES; diff --git a/src/games/atc/update.c b/src/games/atc/update.c new file mode 100644 index 0000000..cd8713a --- /dev/null +++ b/src/games/atc/update.c @@ -0,0 +1,365 @@ +/* + * Copyright (c) 1987 by Ed James, UC Berkeley. All rights reserved. + * + * Copy permission is hereby granted provided that this notice is + * retained on all partial or complete copies. + * + * For more info on this and all of my stuff, mail edjames@berkeley.edu. + */ + +#if !defined(lint) && defined(DOSCCS) +static char sccsid[] = "@(#)update.c 1.3.1 (2.11BSD) 1999/10/25"; +#endif + +#include "include.h" + +update() +{ + int i, dir_diff, unclean; + PLANE *pp, *p1, *p2, *p; + sigset_t set, oset; + + sigemptyset(&set); + sigaddset(&set, SIGINT); + (void)sigprocmask(SIG_BLOCK, &set, &oset); + + clock++; + erase_all(); + + /* put some planes in the air */ + do { + unclean = 0; + for (pp = ground.head; pp != NULL; pp = pp->next) { + if (pp->new_altitude > 0) { + delete(&ground, pp); + append(&air, pp); + unclean = 1; + break; + } + } + } while (unclean); + + /* do altitude change and basic movement */ + for (pp = air.head; pp != NULL; pp = pp->next) { + /* type 0 only move every other turn */ + if (pp->plane_type == 0 && clock & 1) + continue; + + pp->fuel--; + if (pp->fuel < 0) + loser(pp, "ran out of fuel."); + + pp->altitude += SGN(pp->new_altitude - pp->altitude); + + if (!pp->delayd) { + dir_diff = pp->new_dir - pp->dir; + /* + * Allow for circle commands + */ + if (pp->new_dir >= 0 && pp->new_dir < MAXDIR) { + if (dir_diff > MAXDIR/2) + dir_diff -= MAXDIR; + else if (dir_diff < -(MAXDIR/2)) + dir_diff += MAXDIR; + } + if (dir_diff > 2) + dir_diff = 2; + else if (dir_diff < -2) + dir_diff = -2; + pp->dir += dir_diff; + if (pp->dir >= MAXDIR) + pp->dir -= MAXDIR; + else if (pp->dir < 0) + pp->dir += MAXDIR; + } + pp->xpos += displacement[pp->dir].dx; + pp->ypos += displacement[pp->dir].dy; + + if (pp->delayd && pp->xpos == sp->beacon[pp->delayd_no].x && + pp->ypos == sp->beacon[pp->delayd_no].y) { + pp->delayd = 0; + if (pp->status == S_UNMARKED) + pp->status = S_MARKED; + } + + switch (pp->dest_type) { + case T_AIRPORT: + if (pp->xpos == sp->airport[pp->dest_no].x && + pp->ypos == sp->airport[pp->dest_no].y && + pp->altitude == 0) { + if (pp->dir != sp->airport[pp->dest_no].dir) + loser(pp, "landed in the wrong direction."); + else { + pp->status = S_GONE; + continue; + } + } + break; + case T_EXIT: + if (pp->xpos == sp->exit[pp->dest_no].x && + pp->ypos == sp->exit[pp->dest_no].y) { + if (pp->altitude != 9) + loser(pp, "exited at the wrong altitude."); + else { + pp->status = S_GONE; + continue; + } + } + break; + default: + loser(pp, "has a bizarre destination, get help!"); + } + if (pp->altitude > 9) + /* "this is impossible" */ + loser(pp, "exceded flight ceiling."); + if (pp->altitude <= 0) { + for (i = 0; i < sp->num_airports; i++) + if (pp->xpos == sp->airport[i].x && + pp->ypos == sp->airport[i].y) { + if (pp->dest_type == T_AIRPORT) + loser(pp, + "landed at the wrong airport."); + else + loser(pp, + "landed instead of exited."); + } + loser(pp, "crashed on the ground."); + } + if (pp->xpos < 1 || pp->xpos >= sp->width - 1 || + pp->ypos < 1 || pp->ypos >= sp->height - 1) { + for (i = 0; i < sp->num_exits; i++) + if (pp->xpos == sp->exit[i].x && + pp->ypos == sp->exit[i].y) { + if (pp->dest_type == T_EXIT) + loser(pp, + "exited via the wrong exit."); + else + loser(pp, + "exited instead of landed."); + } + loser(pp, "illegally left the flight arena."); + } + } + + /* + * Traverse the list once, deleting the planes that are gone. + */ + for (pp = air.head; pp != NULL; pp = p2) { + p2 = pp->next; + if (pp->status == S_GONE) { + safe_planes++; + delete(&air, pp); + } + } + + draw_all(); + + for (p1 = air.head; p1 != NULL; p1 = p1->next) + for (p2 = p1->next; p2 != NULL; p2 = p2->next) + if (too_close(p1, p2, 1)) { + static char buf[80]; + + (void)sprintf(buf, "collided with plane '%c'.", + name(p2)); + loser(p1, buf); + } + /* + * Check every other update. Actually, only add on even updates. + * Otherwise, prop jobs show up *on* entrance. Remember that + * we don't update props on odd updates. + */ + if ((rand() % sp->newplane_time) == 0) + addplane(); + + (void)sigprocmask(SIG_SETMASK, &oset, NULL); +} + +char * +command(pp) + PLANE *pp; +{ + static char buf[50], *bp, *comm_start; + char *index(); + + buf[0] = '\0'; + bp = buf; + (void)sprintf(bp, "%c%d%c%c%d: ", name(pp), pp->altitude, + (pp->fuel < LOWFUEL) ? '*' : ' ', + (pp->dest_type == T_AIRPORT) ? 'A' : 'E', pp->dest_no); + + comm_start = bp = index(buf, '\0'); + if (pp->altitude == 0) + (void)sprintf(bp, "Holding @ A%d", pp->orig_no); + else if (pp->new_dir >= MAXDIR || pp->new_dir < 0) + strcpy(bp, "Circle"); + else if (pp->new_dir != pp->dir) + (void)sprintf(bp, "%d", dir_deg(pp->new_dir)); + + bp = index(buf, '\0'); + if (pp->delayd) + (void)sprintf(bp, " @ B%d", pp->delayd_no); + + bp = index(buf, '\0'); + if (*comm_start == '\0' && + (pp->status == S_UNMARKED || pp->status == S_IGNORED)) + strcpy(bp, "---------"); + return (buf); +} + +/* char */ +name(p) + PLANE *p; +{ + if (p->plane_type == 0) + return ('A' + p->plane_no); + else + return ('a' + p->plane_no); +} + +number(l) +{ + if (l < 'a' && l > 'z' && l < 'A' && l > 'Z') + return (-1); + else if (l >= 'a' && l <= 'z') + return (l - 'a'); + else + return (l - 'A'); +} + +next_plane() +{ + static int last_plane = -1; + PLANE *pp; + int found, start_plane = last_plane; + + do { + found = 0; + last_plane++; + if (last_plane >= 26) + last_plane = 0; + for (pp = air.head; pp != NULL; pp = pp->next) + if (pp->plane_no == last_plane) { + found++; + break; + } + if (!found) + for (pp = ground.head; pp != NULL; pp = pp->next) + if (pp->plane_no == last_plane) { + found++; + break; + } + } while (found && last_plane != start_plane); + if (last_plane == start_plane) + return (-1); + return (last_plane); +} + +addplane() +{ + PLANE p, *pp, *p1; + int i, num_starts, close, rnd, rnd2, pnum; + + bzero(&p, sizeof (p)); + + p.status = S_MARKED; + p.plane_type = random() % 2; + + num_starts = sp->num_exits + sp->num_airports; + rnd = random() % num_starts; + + if (rnd < sp->num_exits) { + p.dest_type = T_EXIT; + p.dest_no = rnd; + } else { + p.dest_type = T_AIRPORT; + p.dest_no = rnd - sp->num_exits; + } + + /* loop until we get a plane not near another */ + for (i = 0; i < num_starts; i++) { + /* loop till we get a different start point */ + while ((rnd2 = random() % num_starts) == rnd) + ; + if (rnd2 < sp->num_exits) { + p.orig_type = T_EXIT; + p.orig_no = rnd2; + p.xpos = sp->exit[rnd2].x; + p.ypos = sp->exit[rnd2].y; + p.new_dir = p.dir = sp->exit[rnd2].dir; + p.altitude = p.new_altitude = 7; + close = 0; + for (p1 = air.head; p1 != NULL; p1 = p1->next) + if (too_close(p1, &p, 4)) { + close++; + break; + } + if (close) + continue; + } else { + p.orig_type = T_AIRPORT; + p.orig_no = rnd2 - sp->num_exits; + p.xpos = sp->airport[p.orig_no].x; + p.ypos = sp->airport[p.orig_no].y; + p.new_dir = p.dir = sp->airport[p.orig_no].dir; + p.altitude = p.new_altitude = 0; + } + p.fuel = sp->width + sp->height; + break; + } + if (i >= num_starts) + return (-1); + pnum = next_plane(); + if (pnum < 0) + return (-1); + p.plane_no = pnum; + + pp = newplane(); + bcopy(&p, pp, sizeof (p)); + + if (pp->orig_type == T_AIRPORT) + append(&ground, pp); + else + append(&air, pp); + + return (pp->dest_type); +} + +PLANE * +findplane(n) +{ + PLANE *pp; + + for (pp = air.head; pp != NULL; pp = pp->next) + if (pp->plane_no == n) + return (pp); + for (pp = ground.head; pp != NULL; pp = pp->next) + if (pp->plane_no == n) + return (pp); + return (NULL); +} + +too_close(p1, p2, dist) + PLANE *p1, *p2; +{ + if (ABS(p1->altitude - p2->altitude) <= dist && + ABS(p1->xpos - p2->xpos) <= dist && ABS(p1->ypos - p2->ypos) <= dist) + return (1); + else + return (0); +} + +dir_deg(d) +{ + switch (d) { + case 0: return (0); + case 1: return (45); + case 2: return (90); + case 3: return (135); + case 4: return (180); + case 5: return (225); + case 6: return (270); + case 7: return (315); + default: + return (-1); + } +} diff --git a/src/games/backgammon/Makefile b/src/games/backgammon/Makefile new file mode 100644 index 0000000..dbd7e3c --- /dev/null +++ b/src/games/backgammon/Makefile @@ -0,0 +1,46 @@ +# +# Copyright (c) 1980 Regents of the University of California. +# All rights reserved. The Berkeley software License Agreement +# specifies the terms and conditions for redistribution. +# +TOPSRC = $(shell cd ../../..; pwd) +include $(TOPSRC)/target.mk +#include $(TOPSRC)/cross.mk + +CFLAGS += -O -g -Werror -Wall #-DV7 +LIBS += -ltermcap -lc + +OBJS = allow.o board.o check.o extra.o fancy.o init.o main.o \ + move.o odds.o one.o save.o subs.o table.o text.o message.o +TOBJS = allow.o board.o check.o data.o fancy.o init.o odds.o one.o \ + save.o subs.o table.o teach.o ttext1.o ttext2.o tutor.o +MAN = backgammon.0 +MANSRC = backgammon.6 + +all: backgammon teachgammon $(MAN) + +backgammon: $(OBJS) + $(CC) $(LDFLAGS) -o backgammon.elf $(OBJS) $(LIBS) + $(OBJDUMP) -S backgammon.elf > backgammon.dis + $(SIZE) backgammon.elf + $(ELF2AOUT) backgammon.elf $@ && rm backgammon.elf + +teachgammon: $(TOBJS) + $(CC) $(LDFLAGS) -o teachgammon.elf $(TOBJS) $(LIBS) + $(OBJDUMP) -S teachgammon.elf > teachgammon.dis + $(SIZE) teachgammon.elf + $(ELF2AOUT) teachgammon.elf $@ && rm teachgammon.elf + +$(MAN): $(MANSRC) + $(MANROFF) $< > $@ + +clean: + rm -f *.o *.0 *.elf $(MAN) backgammon teachgammon *.elf *.dis tags *~ + +install: all + install backgammon $(DESTDIR)/games/ + install teachgammon $(DESTDIR)/games/ + cp $(MAN) $(DESTDIR)/share/man/cat6/ + +$(OBJS) $(TOBJS): back.h +data.o tutor.o: tutor.h diff --git a/src/games/backgammon/allow.c b/src/games/backgammon/allow.c new file mode 100644 index 0000000..a22827b --- /dev/null +++ b/src/games/backgammon/allow.c @@ -0,0 +1,79 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "back.h" + +int +movallow () +{ + register int i, m, iold; + int r; + + if (d0) + swap; + m = (D0 == D1? 4: 2); + for (i = 0; i < 4; i++) + p[i] = bar; + i = iold = 0; + while (i < m) { + if (*offptr == 15) + break; + h[i] = 0; + if (board[bar]) { + if (i == 1 || m == 4) + g[i] = bar+cturn*D1; + else + g[i] = bar+cturn*D0; + r = makmove(i); + if (r) { + if (d0 || m == 4) + break; + swap; + movback (i); + if (i > iold) + iold = i; + for (i = 0; i < 4; i++) + p[i] = bar; + i = 0; + } else + i++; + continue; + } + if ((p[i] += cturn) == home) { + if (i > iold) + iold = i; + if (m == 2 && i) { + movback(i); + p[i--] = bar; + if (p[i] != bar) + continue; + else + break; + } + if (d0 || m == 4) + break; + swap; + movback (i); + for (i = 0; i < 4; i++) + p[i] = bar; + i = 0; + continue; + } + if (i == 1 || m == 4) + g[i] = p[i]+cturn*D1; + else + g[i] = p[i]+cturn*D0; + if (g[i]*cturn > home) { + if (*offptr >= 0) + g[i] = home; + else + continue; + } + if (board[p[i]]*cturn > 0 && (r = makmove(i)) == 0) + i++; + } + movback (i); + return (iold > i? iold: i); +} diff --git a/src/games/backgammon/back.h b/src/games/backgammon/back.h new file mode 100644 index 0000000..cf241ce --- /dev/null +++ b/src/games/backgammon/back.h @@ -0,0 +1,148 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include +#include + +#define rnum(r) (random()%r) +#define D0 dice[0] +#define D1 dice[1] +#define swap {D0 ^= D1; D1 ^= D0; D0 ^= D1; d0 = 1-d0;} + +/* + * + * Some numerical conventions: + * + * Arrays have white's value in [0], red in [1]. + * Numeric values which are one color or the other use + * -1 for white, 1 for red. + * Hence, white will be negative values, red positive one. + * This makes a lot of sense since white is going in decending + * order around the board, and red is ascending. + * + */ + +extern char EXEC[]; /* object for main program */ +extern char TEACH[]; /* object for tutorial program */ + +int pnum; /* color of player: + -1 = white + 1 = red + 0 = both + 2 = not yet init'ed */ +char args[100]; /* args passed to teachgammon and back */ +int acnt; /* length of args */ +int aflag; /* flag to ask for rules or instructions */ +int bflag; /* flag for automatic board printing */ +int cflag; /* case conversion flag */ +int hflag; /* flag for cleaning screen */ +int mflag; /* backgammon flag */ +int raflag; /* 'roll again' flag for recovered game */ +int rflag; /* recovered game flag */ +int tflag; /* cursor addressing flag */ +int rfl; /* saved value of rflag */ +int iroll; /* special flag for inputting rolls */ +int board[26]; /* board: negative values are white, + positive are red */ +int dice[2]; /* value of dice */ +int mvlim; /* 'move limit': max. number of moves */ +int mvl; /* working copy of mvlim */ +int p[5]; /* starting position of moves */ +int g[5]; /* ending position of moves (goals) */ +int h[4]; /* flag for each move if a man was hit */ +int cturn; /* whose turn it currently is: + -1 = white + 1 = red + 0 = just quitted + -2 = white just lost + 2 = red just lost */ +int d0; /* flag if dice have been reversed from + original position */ +int table[6][6]; /* odds table for possible rolls */ +int rscore; /* red's score */ +int wscore; /* white's score */ +int gvalue; /* value of game (64 max.) */ +int dlast; /* who doubled last (0 = neither) */ +int bar; /* position of bar for current player */ +int home; /* position of home for current player */ +int off[2]; /* number of men off board */ +int *offptr; /* pointer to off for current player */ +int *offopp; /* pointer to off for opponent */ +int in[2]; /* number of men in inner table */ +int *inptr; /* pointer to in for current player */ +int *inopp; /* pointer to in for opponent */ + +int ncin; /* number of characters in cin */ +char cin[100]; /* input line of current move + (used for reconstructing input after + a backspace) */ + +extern char *color[]; + /* colors as strings */ +char **colorptr; /* color of current player */ +char **Colorptr; /* color of current player, capitalized */ +int colen; /* length of color of current player */ + +struct sgttyb tty; /* tty information buffer */ +int old; /* original tty status */ +int noech; /* original tty status without echo */ +int raw; /* raw tty status, no echo */ + +int curr; /* row position of cursor */ +int curc; /* column position of cursor */ +int begscr; /* 'beginning' of screen + (not including board) */ + +void getout (int); /* function to exit backgammon cleanly */ + +int makmove (int); +void movback (int); +void fixtty (int); +void clear (void); +void fboard (void); +void writel (const char *); +void gwrite (void); +void curmove (int, int); +void writec (int); +int checkmove (int); +int movokay (int); +void wrhit (int); +void nexturn (void); +void refresh (void); +int quit (void); +void proll (void); +void cline (void); +void moverr (int); +int dblgood (void); +int yorn (int); +void buflush (void); +void wrboard (void); +int freemen (int); +int trapped (int, int); +void odds (int, int, int); +int count (void); +void fancyc (int); +void newpos (void); +int addbuf (int); +void errexit (char *); +int getcaps (char *); +void getarg (char ***); +int text (const char **); +void init (void); +int readc (void); +void roll (void); +void move (int); +int movallow (void); +void getmove (void); +void clend (void); +void save (int); +void dble (void); +void wrint (int); +void wrscore (void); +void backone (int); +int canhit (int, int); +void recover (char *); +void leave (void); +void tutor (void); diff --git a/src/games/backgammon/backgammon.6 b/src/games/backgammon/backgammon.6 new file mode 100644 index 0000000..21aa313 --- /dev/null +++ b/src/games/backgammon/backgammon.6 @@ -0,0 +1,11 @@ +.\" @(#)backgammon.6 6.1 (Berkeley) 5/20/85 +.\" +.TH BACKGAMMON 6 "May 20, 1985" +.AT 3 +.SH NAME +backgammon \- the game +.SH SYNOPSIS +.B /usr/games/backgammon +.SH DESCRIPTION +This program does what you expect. +It will ask whether you need instructions. diff --git a/src/games/backgammon/backgammon.src b/src/games/backgammon/backgammon.src new file mode 100644 index 0000000..b68d945 --- /dev/null +++ b/src/games/backgammon/backgammon.src @@ -0,0 +1,195 @@ +.\" Copyright (c) 1980 Regents of the University of California. +.\" All rights reserved. The Berkeley software License Agreement +.\" specifies the terms and conditions for redistribution. +.\" +.\" @(#)backgammon.src 5.2 (Berkeley) 1/11/86 +.\" +.th BACKGAMMON PUBLIC \n(mo/\n(dy/\n(yr +.sh NAME +backgammon - the game of backgammon +.sh SYNOPSIS +.bd backgammon +[ - ] [ n r w b pr pw pb t\c +.it term +s\c +.it file +] +.sh DESCRIPTION +This program lets you play backgammon against the computer +or against a "friend". +All commands only are one letter, +so you don't need to type a carriage return, +except at the end of a move. +The program is mostly self documenting, +so that a question mark (?) will usually get some help. +If you answer `y' when the program asks if you want the rules, +you will get text explaining the rules of the game, +some hints on strategy, +instruction on how to use the program, +and a tutorial consisting of a practice game against the computer. +A description of how to use the program can be +obtained by answering `y' when it asks if you want instructions. +.s3 +The possible arguments for backgammon +(most are unnecesary but some are very convenient) +consist of: +.ne 11 +.s3 +.na +.lp 16 8 +.bn n +don't ask for rules or instructions +.lp 16 8 +.bn r +player is red (implies n) +.lp 16 8 +.bn w +player is white (implies n) +.lp 16 8 +.bn b +two players, red and white (implies n) +.lp 16 8 +.bn pr +print the board before red's turn +.lp 16 8 +.bn pw +print the board before white's turn +.lp 16 8 +.bn pb +print the board before both player's turn +.lp 16 8 +.bn t\fiterm +terminal is type +.it term, +uses /etc/termcap +.lp 16 8 +.bn s\fifile +recover previously saved game from +.it file. +(This can also be done by executing the saved file, +i.e., typing its name in as a command) +.s3 +.ad +.i0 +Arguments may be optionally preceded by a `-'. +Several arguments may be concatenated together, +but not after `s' or `t' arguments, +since they can be followed by an arbitrary string. +Any unrecognized arguments are ignored. +An argument of a lone `-' gets a description of possible arguments. +.s3 +If +.it term +has capabilities for direct cursor movement (see ttycap(VII)), +.it backgammon +"fixes" the board after each move, +so the board does not need to be reprinted, +unless the screen suffers some horrendous malady. +Also, any `p' option will be ignored. +(The `t' option is not necessary unless the terminal type does not match +the entry in the /etc/htmp data base.) +.sh QUICK\ REFERENCE +When the program prompts by typing only your color, +type a space or carriage return to roll, or +.ne 5 +.s3 +.na +.lp 16 8 +.bn d +to double +.lp 16 8 +.bn p +to print the board +.lp 16 8 +.bn q +to quit +.lp 16 8 +.bn s +to save the game for later +.s3 +.i0 +.ad +When the program prompts with 'Move:', type +.ne 4 +.s3 +.na +.lp 16 8 +.bn p +to print the board +.lp 16 8 +.bn q +to quit +.lp 16 8 +.bn s +to save the game +.ad +.i0 +.s3 +or a +.it move, +which is a sequence of +.ne 4 +.s3 +.na +.lp 16 8 +.bn s-f +move from +.bd s +to +.bd f +.lp 16 8 +.bn s/r +move one man on +.bd s +the roll +.bd r +.ad +.i0 +.s3 +separated by commas or spaces and ending with a newline. +Available abbreviations are +.ne 4 +.s3 +.na +.lp 18 10 +.bn s-f1-f2 +means +.bd s-f1,f1-f2 +.lp 18 10 +.bn s/r1r2 +means +.bd s/r1,s/r2 +.ad +.i0 +.s3 +Use `b' for bar and `h' for home, +or 0 or 25 as appropriate. +.sh AUTHOR +Alan Char +.sh FILES +.lp 30 25 +.bn /mnt/alan/:toys/teachgammon +- rules and tutorial +.br +.lp 30 25 +.bn /etc/htmp +- data base on user's environment +.br +.lp 30 25 +.bn /etc/termcap +- terminal capabilities +.i0 +.sh BUGS +The program's strategy needs much work. +.s3 +/mnt/alan/:toys/teachgammon was removed to preserve space in /usr/public +.sh COMMENTS +The program is still under development, +so a description of any bugs found should be mailed to +.bd alan. +.s3 +Because of the dynamic state of the program +(constantly changing), +the file +.it /mnt/alan/:toys/gammon.news +lists current modifications to the program. diff --git a/src/games/backgammon/board.c b/src/games/backgammon/board.c new file mode 100644 index 0000000..b6d291f --- /dev/null +++ b/src/games/backgammon/board.c @@ -0,0 +1,149 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "back.h" +#include + +static int i, j, k; +static char ln[60]; + +static void +wrbsub () +{ + register int m; + register char d; + + if (board[k] > 0) { + m = board[k]; + d = 'r'; + } else { + m = -board[k]; + d = 'w'; + } + if (m>i) + ln[j+1] = d; + if (m>i+5) + ln[j] = d; + if (m>i+10) + ln[j+2] = d; +} + +void +wrboard () +{ + register int l; + static char bl[] = + "| | | |\n"; + static char sv[] = + "| | | | \n"; + + fixtty (noech); + clear(); + + if (tflag) { + fboard(); + goto lastline; + } + + writel ("_____________________________________________________\n"); + writel (bl); + strcpy (ln,bl); + for (j = 1; j < 50; j += 4) { + k = j/4+(j > 24? 12: 13); + ln[j+1] = k%10+'0'; + ln[j] = k/10+'0'; + if (j == 21) + j += 4; + } + writel (ln); + for (i = 0; i < 5; i++) { + strcpy (ln,sv); + for (j = 1; j < 50; j += 4) { + k = j/4+(j > 24? 12: 13); + wrbsub (); + if (j == 21) + j += 4; + } + if (-board[25] > i) + ln[26] = 'w'; + if (-board[25] > i+5) + ln[25] = 'w'; + if (-board[25] > i+10) + ln[27] = 'w'; + l = 53; + if (off[1] > i || (off[1] < 0 && off[1]+15 > i)) { + ln[54] = 'r'; + l = 55; + } + if (off[1] > i+5 || (off[1] < 0 && off[1]+15 > i+5)) { + ln[55] = 'r'; + l = 56; + } + if (off[1] > i+10 || (off[1] < 0 && off[1]+15 > i+10)) { + ln[56] = 'r'; + l = 57; + } + ln[l++] = '\n'; + ln[l] = '\0'; + writel (ln); + } + strcpy (ln,bl); + ln[25] = 'B'; + ln[26] = 'A'; + ln[27] = 'R'; + writel (ln); + strcpy (ln,sv); + for (i = 4; i > -1; i--) { + for (j = 1; j < 50; j += 4) { + k = ((j > 24? 53: 49)-j)/4; + wrbsub(); + if (j == 21) + j += 4; + } + if (board[0] > i) + ln[26] = 'r'; + if (board[0] > i+5) + ln[25] = 'r'; + if (board[0] > i+10) + ln[27] = 'r'; + l = 53; + if (off[0] > i || (off[0] < 0 && off[0]+15 > i)) { + ln[54] = 'w'; + l = 55; + } + if (off[0] > i+5 || (off[0] < 0 && off[0]+15 > i+5)) { + ln[55] = 'w'; + l = 56; + } + if (off[0] > i+10 || (off[0] < 0 && off[0]+15 > i+10)) { + ln[56] = 'w'; + l = 57; + } + ln[l++] = '\n'; + ln[l] = '\0'; + writel (ln); + } + strcpy (ln,bl); + for (j = 1; j < 50; j += 4) { + k = ((j > 24? 53: 49)-j)/4; + ln[j+1] = k%10+'0'; + if (k > 9) + ln[j] = k/10+'0'; + if (j == 21) + j += 4; + } + writel (ln); + writel ("|_______________________|___|_______________________|\n"); + +lastline: + gwrite (); + if (tflag) + curmove (18,0); + else { + writec ('\n'); + writec ('\n'); + } + fixtty(raw); +} diff --git a/src/games/backgammon/check.c b/src/games/backgammon/check.c new file mode 100644 index 0000000..0e057ac --- /dev/null +++ b/src/games/backgammon/check.c @@ -0,0 +1,128 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "back.h" + +void +getmove () +{ + register int i, c; + + c = 0; + for (;;) { + i = checkmove(c); + + switch (i) { + case -1: + if (movokay(mvlim)) { + if (tflag) + curmove (20,0); + else + writec ('\n'); + for (i = 0; i < mvlim; i++) + if (h[i]) + wrhit(g[i]); + nexturn(); + if (*offopp == 15) + cturn *= -2; + if (tflag && pnum) + bflag = pnum; + return; + } + + case -4: + case 0: + if (tflag) + refresh(); + if (i != 0 && i != -4) + break; + if (tflag) + curmove (20,0); + else + writec ('\n'); + writel (*Colorptr); + if (i == -4) + writel (" must make "); + else + writel (" can only make "); + writec (mvlim+'0'); + writel (" move"); + if (mvlim > 1) + writec ('s'); + writec ('.'); + writec ('\n'); + break; + + case -3: + if (quit()) + return; + } + + if (! tflag) + proll (); + else { + curmove (cturn == -1? 18: 19,39); + cline (); + c = -1; + } + } +} + +int +movokay (mv) + register int mv; +{ + register int i, m; + + if (d0) + swap; + + for (i = 0; i < mv; i++) { + + if (p[i] == g[i]) { + moverr (i); + curmove (20,0); + writel ("Attempt to move to same location.\n"); + return (0); + } + + if (cturn*(g[i]-p[i]) < 0) { + moverr (i); + curmove (20,0); + writel ("Backwards move.\n"); + return (0); + } + + if (abs(board[bar]) && p[i] != bar) { + moverr (i); + curmove (20,0); + writel ("Men still on bar.\n"); + return (0); + } + + if ( (m = makmove(i)) ) { + moverr (i); + switch (m) { + + case 1: + writel ("Move not rolled.\n"); + break; + + case 2: + writel ("Bad starting position.\n"); + break; + + case 3: + writel ("Destination occupied.\n"); + break; + + case 4: + writel ("Can't remove men yet.\n"); + } + return (0); + } + } + return (1); +} diff --git a/src/games/backgammon/data.c b/src/games/backgammon/data.c new file mode 100644 index 0000000..e138367 --- /dev/null +++ b/src/games/backgammon/data.c @@ -0,0 +1,283 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "tutor.h" + +int maxmoves = 23; + +const char *text0[] = { + "To start the game, I roll a 3, and you roll a 1. This means", + "that I get to start first. I move 8-5,6-5 since this makes a", + "new point and helps to trap your back men on 1. You should be", + "able to do a similar move with your roll.", + 0 +}; + +const char *text1[] = { + "Now you shall see a move using doubles. I just rolled double", + "5's. I will move two men from position 13 to position 3. The", + "notation for this is 13-8,13-8,8-3,8-3. You will also roll dou-", + "bles, but you will be able to make a much stronger move.", + 0 +}; + +const char *text2[] = { + "Excellent! As you can see, you are beginning to develop a wall", + "which is trapping my men on position 24. Also, moving your back", + "men forward not only improves your board position safely, but it", + "thwarts my effort to make a wall.", + "", + "My roll now is 5 6. Normally, I would use that roll to move from", + "position 24 to position 13 (24-18-13), but your new point prevents", + "that. Instead, I am forced to move from 13 to 2, where my man is", + "open but cannot be hit.", + 0 +}; + +const char *text3[] = { + "As you can see, although you left a man open, it is a rela-", + "tively safe move to an advantageous position, which might help", + "you make a point later. Only two rolls (4 5 or 5 4) will allow", + "me to hit you. With an unprecedented amount of luck, I happen", + "to roll a 4 5 and hit you as just mentioned.", + 0 +}; + +const char *text4[] = { + "You're pretty lucky yourself, you know. I follow by rolling 2 3", + "and moving 25-22,24-22, forming a new point.", + 0 +}; + +const char *text5[] = { + "Not a spectacular move, but a safe one. I follow by rolling 6 1.", + "I decide to use this roll to move 22-16,16-17. It leaves me with", + "one man still open, but the blot is farther back on the board, and", + "would suffer less of a loss by being hit.", + 0 +}; + +const char *text6[] = { + "By moving your two men from 17 to 20, you lessen my chance of", + "getting my man off the board. In fact, the odds are 5 to 4", + "against me getting off. I roll with the odds and helplessly", + "receive a 3 5.", + 0 +}; + +const char *text7[] = { + "Note that the blot on 7 cannot be hit unless I get off the bar", + "and have a 1 or a 6 left over, and doing so will leave two of", + "my men open. Also, the blot on 16 cannot be hit at all! With", + "a sigh of frustration, I roll double 6's and remain immobile.", + 0 +}; + +const char *text8[] = { + "See, you did not get hit and, you got to 'cover up' your open men.", + "Quite an accomplishment. Finally, I get off the bar by rolling", + "6 2 and moving 25-23,23-17.", + 0 +}; + +const char *text9[] = { + "My venture off the bar did not last long. However, I got lucky", + "and rolled double 1's, allowing me to move 0-1,1-2,15-14,15-14.", + 0 +}; + +const char *text10[] = { + "You are improving your position greatly and safely, and are well", + "on the way to winning the game. I roll a 6 2 and squeak past", + "your back man. Now the game becomes a race to the finish.", + 0 +}; + +const char *text11[] = { + "Now that it is merely a race, you are trying to get as many men", + "as possible into the inner table, so you can start removing them.", + "I roll a 3 4 and move my two men farthest back to position 11", + "(15-11,14-11).", + 0 +}; + +const char *text12[] = { + "The race is still on, and you have seem to be doing all right.", + "I roll 6 1 and move 14-8,13-12.", + 0 +}; + +const char *text13[] = { + "Notice that you get to remove men the instant you have all of", + "them at your inner table, even if it is the middle of a turn.", + "I roll 1 2 and move 13-11,12-11.", + 0 +}; + +const char *text14[] = { + "Although you could have removed a man, this move illustrates two", + "points: 1) You never have to remove men, and 2) You should try", + "to spread out your men on your inner table. Since you have one", + "man on each position, you should be able to remove at least two", + "men next turn. I roll 2 5 and move 8-6,11-6.", + 0 +}; + +const char *text15[] = { + "This time you were able to remove men. I roll 3 4 and move", + "11-7,11-8. The race continues.", + 0 +}; + +const char *text16[] = { + "More holes are opening up in your inner table, but you are", + "still very much ahead. If we were doubling, you would have", + "doubled long ago. I roll 2 6 and move 8-6,11-5.", + 0 +}; + +const char *text17[] = { + "It pays to spread out your men. I roll 3 5 and move 7-4,8-3.", + 0 +}; + +const char *text18[] = { + "You can only remove some men, but you spread out more and", + "more, in order to be able to remove men more efficiently.", + "I roll double 3's, which help, but not that much. I move", + "8-5,3-0,3-0,3-0.", + 0 +}; + +const char *text19[] = { + "I roll 1 4 and move 5-4,4-0.", + 0 +}; + +const char *text20[] = { + "You are now nicely spread out to win a game. I roll 5 6 and", + "move 5-0,6-0.", + 0 +}; + +const char *text21[] = { + "Any minute now. Just a few short steps from victory. I roll", + "2 4 and move 6-4,4-0.", + 0 +}; + +const char *text22[] = { + "It looks pretty hopeless for me, but I play on, rolling 1 3 and", + "moving 4-3,3-0.", + 0 +}; + +const char *text23[] = { + "Congratulations! You just won a game of backgammon against the", + "computer! You will now be able to play a game, but remember,", + "when you start playing, that doubling will be enabled, which", + "will add another factor to the game... Good luck!!", + "", + 0 +}; + +const struct situatn test[] = { + { + {0,2,0,0,0,0,-5,0,-3,0,0,0,5,-5,0,0,0,3,0,5,0,0,0,0,-2,0}, + 3, 1, {8,6,0,0}, {5,5,0,0}, 4, 2, text0 + }, + { + {0,2,0,0,0,-2,-4,0,-2,0,0,0,5,-5,0,0,0,2,0,4,0,2,0,0,-2,0}, + 5, 5, {13,13,8,8}, {8,8,3,3}, 6, 6, text1 + }, + { + {0,0,0,-2,0,-2,-4,2,-2,0,0,0,3,-3,0,0,0,2,2,4,0,2,0,0,-2,0}, + 6, 5, {13,8,0,0}, {8,2,0,0}, 1, 2, text2 + }, + { + {0,0,-1,-2,0,-2,-4,2,-2,0,0,0,2,-2,0,1,0,2,2,4,0,2,0,0,-2,0}, + 4, 5, {24,20,0,0}, {20,15,0,0}, 2, 5, text3 + }, + { + {0,0,0,-2,0,-2,-4,3,-2,0,0,0,2,-2,0,-1,0,2,2,4,0,2,0,0,-1,-1}, + 2, 3, {25,24,0,0}, {22,22,0,0}, 4, 1, text4 + }, + { + {0,0,0,-2,0,-2,-4,2,-2,0,0,0,3,-2,0,-1,0,2,2,4,0,2,-2,0,0,0}, + 6, 1, {22,16,0,0}, {16,15,0,0}, 3, 3, text5 + }, + { + {0,0,0,-2,0,-2,-4,2,-2,0,0,0,3,-2,0,-2,0,0,2,2,2,2,2,0,0,-1}, + 3, 5, {0,0,0,0}, {0,0,0,0}, 5, 4, text6 + }, + { + {0,0,0,-2,0,-2,-4,1,-2,0,0,0,3,-2,0,-2,1,0,2,2,2,2,2,0,0,-1}, + 6, 6, {0,0,0,0}, {0,0,0,0}, 3, 6, text7 + }, + { + {0,0,0,-2,0,-2,-4,0,-2,0,0,0,3,-2,0,-2,2,0,2,2,2,2,2,0,0,-1}, + 2, 6, {25,23,0,0}, {23,17,0,0}, 5, 1, text8 + }, + { + {0,0,0,-2,0,-2,-4,0,-2,0,0,0,2,-2,0,-2,2,0,3,2,2,2,2,0,0,-1}, + 1, 1, {25,24,15,15}, {24,23,14,14}, 4, 6, text9 + }, + { + {0,0,0,-2,0,-2,-4,0,-2,0,0,0,0,-2,-2,0,3,0,4,2,2,2,2,-1,0,0}, + 6, 2, {23,17,0,0}, {17,15,0,0}, 1, 3, text10 + }, + { + {0,0,0,-2,0,-2,-4,0,-2,0,0,0,0,-2,-2,-1,2,0,3,4,2,2,2,0,0,0}, + 4, 3, {15,14,0,0}, {11,11,0,0}, 5, 3, text11 + }, + { + {0,0,0,-2,0,-2,-4,0,-2,0,0,-2,0,-2,-1,0,0,0,3,5,2,3,2,0,0,0}, + 6, 1, {14,13,0,0}, {8,12,0,0}, 4, 4, text12 + }, + { + {0,0,0,-2,0,-2,-4,0,-3,0,0,-2,-1,-1,0,0,0,0,0,5,2,2,5,0,0,0}, + 2, 1, {13,12,0,0}, {11,11,0,0}, 2, 1, text13 + }, + { + {0,0,0,-2,0,-2,-4,0,-3,0,0,-4,0,0,0,0,0,0,0,5,2,2,3,1,1,0}, + 2, 5, {8,11,0,0}, {6,6,0,0}, 6, 3, text14 + }, + { + {0,0,0,-2,0,-2,-6,0,-2,0,0,-3,0,0,0,0,0,0,0,4,2,2,2,1,1,0}, + 4, 3, {11,11,0,0}, {7,8,0,0}, 2, 5, text15 + }, + { + {0,0,0,-2,0,-2,-6,-1,-3,0,0,-1,0,0,0,0,0,0,0,4,1,2,2,0,1,0}, + 2, 6, {8,11,0,0}, {6,5,0,0}, 6, 1, text16 + }, + { + {0,0,0,-2,0,-3,-7,-1,-2,0,0,0,0,0,0,0,0,0,0,3,1,2,2,0,0,0}, + 5, 3, {8,7,0,0}, {3,4,0,0}, 5, 2, text17 + }, + { + {0,0,0,-3,-1,-3,-7,0,-1,0,0,0,0,0,0,0,0,0,0,3,0,1,2,1,0,0}, + 3, 3, {8,3,3,3}, {5,0,0,0}, 1, 6, text18 + }, + { + {0,0,0,0,-1,-4,-7,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,2,1,0,0}, + 1, 4, {4,5,0,0}, {0,4,0,0}, 2, 3, text19 + }, + { + {0,0,0,0,-1,-3,-7,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0}, + 5, 6, {6,5,0,0}, {0,0,0,0}, 1, 4, text20 + }, + { + {0,0,0,0,-1,-2,-6,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,1,0,0,0}, + 2, 4, {4,6,0,0}, {0,4,0,0}, 6, 2, text21 + }, + { + {0,0,0,0,-1,-2,-5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0}, + 3, 1, {4,3,0,0}, {3,0,0,0}, 4, 3, text22 + }, + { + {0,0,0,0,0,-2,-5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + 0, 0, {0,0,0,0}, {0,0,0,0}, 0, 0, text23 + } +}; diff --git a/src/games/backgammon/extra.c b/src/games/backgammon/extra.c new file mode 100644 index 0000000..edc9cb8 --- /dev/null +++ b/src/games/backgammon/extra.c @@ -0,0 +1,228 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "back.h" + +#ifdef DEBUG +#ifdef CROSS +# include +#else +# include +#endif +FILE *trace; +#endif + +/* + * dble() + * Have the current player double and ask opponent to accept. + */ +void +dble () +{ + register int resp; /* response to y/n */ + + for (;;) { + writel (" doubles."); /* indicate double */ + + if (cturn == -pnum) { /* see if computer accepts */ + if (dblgood()) { /* guess not */ + writel (" Declined.\n"); + nexturn(); + cturn *= -2; /* indicate loss */ + return; + } else { /* computer accepts */ + writel (" Accepted.\n"); + gvalue *= 2; /* double game value */ + dlast = cturn; + if (tflag) + gwrite(); + return; + } + } + + /* ask if player accepts */ + writel (" Does "); + writel (cturn == 1? color[2]: color[3]); + writel (" accept?"); + + /* get response from yorn, + * a "2" means he said "p" + * for print board. */ + if ((resp = yorn ('R')) == 2) { + writel (" Reprint.\n"); + buflush(); + wrboard(); + writel (*Colorptr); + continue; + } + + /* check response */ + if (resp) { + /* accepted */ + gvalue *= 2; + dlast = cturn; + if (tflag) + gwrite(); + return; + } + + nexturn (); /* declined */ + cturn *= -2; + return; + } +} + +static int +eval () +{ + register int i, j; + + for (j = i = 0; i < 26; i++) + j += (board[i] >= 0 ? i*board[i] : (25-i)*board[i]); + + if (off[1] >= 0) + j += 25*off[1]; + else + j += 25*(off[1]+15); + + if (off[0] >= 0) + j -= 25*off[0]; + else + j -= 25*(off[0]+15); + return (j); +} + +/* + * dblgood () + * Returns 1 if the computer would double in this position. This + * is not an exact science. The computer will decline a double that he + * would have made. Accumulated judgments are kept in the variable n, + * which is in "pips", i.e., the position of each man summed over all + * men, with opponent's totals negative. Thus, n should have a positive + * value of 7 for each move ahead, or a negative value of 7 for each one + * behind. + */ +int +dblgood () +{ + register int n; /* accumulated judgment */ + register int OFFC = *offptr; /* no. of computer's men off */ + register int OFFO = *offopp; /* no. of player's men off */ + +#ifdef DEBUG + register int i; + if (trace == NULL) + trace = fopen ("bgtrace","w"); +#endif + + /* get real pip value */ + n = eval()*cturn; +#ifdef DEBUG + fputs ("\nDoubles:\nBoard: ",trace); + for (i = 0; i < 26; i++) + fprintf (trace," %d",board[i]); + fprintf (trace,"\n\tpip = %d, ",n); +#endif + + /* below adjusts pip value + * according to position + * judgments */ + + /* check men moving off + * board */ + if (OFFC > -15 || OFFO > -15) { + if (OFFC < 0 && OFFO < 0) { + OFFC += 15; + OFFO += 15; + n +=((OFFC-OFFO)*7)/2; + } else if (OFFC < 0) { + OFFC += 15; + n -= OFFO*7/2; + } else if (OFFO < 0) { + OFFO += 15; + n += OFFC*7/2; + } + if (OFFC < 8 && OFFO > 8) + n -= 7; + if (OFFC < 10 && OFFO > 10) + n -= 7; + if (OFFC < 12 && OFFO > 12) + n -= 7; + if (OFFO < 8 && OFFC > 8) + n += 7; + if (OFFO < 10 && OFFC > 10) + n += 7; + if (OFFO < 12 && OFFC > 12) + n += 7; + n += ((OFFC-OFFO)*7)/2; + } + +#ifdef DEBUG + fprintf (trace,"off = %d, ",n); +#endif + + /* see if men are trapped */ + n -= freemen(bar); + n += freemen(home); + n += trapped(home,-cturn); + n -= trapped(bar,cturn); + +#ifdef DEBUG + fprintf (trace,"free = %d\n",n); + fprintf (trace,"\tOFFC = %d, OFFO = %d\n",OFFC,OFFO); + fflush (trace); +#endif + + /* double if 2-3 moves ahead */ + if (n > 10+rnum(7)) + return(1); + return (0); +} + +int +freemen (b) + int b; +{ + register int i, inc, lim; + + odds(0,0,0); + if (board[b] == 0) + return (0); + inc = (b == 0? 1: -1); + lim = (b == 0? 7: 18); + for (i = b+inc; i != lim; i += inc) + if (board[i]*inc < -1) + odds(abs(b-i),0,abs(board[b])); + if (abs(board[b]) == 1) + return ((36-count())/5); + return (count()/5); +} + +int +trapped (n, inc) + int n, inc; +{ + register int i, j, k; + int c, l, ct; + + ct = 0; + l = n+7*inc; + for (i = n+inc; i != l; i += inc) { + odds (0,0,0); + c = abs(i-l); + if (board[i]*inc > 0) { + for (j = c; j < 13; j++) + if (board[i+inc*j]*inc < -1) { + if (j < 7) + odds (j,0,1); + for (k = 1; k < 7 && k < j; k++) + if (j-k < 7) + odds (k,j-k,1); + } + ct += abs(board[i])*(36-count()); + } + } + return (ct/5); +} diff --git a/src/games/backgammon/fancy.c b/src/games/backgammon/fancy.c new file mode 100644 index 0000000..dd4a519 --- /dev/null +++ b/src/games/backgammon/fancy.c @@ -0,0 +1,729 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "back.h" +#include +#include +#include + +char PC; /* padding character */ +char *BC; /* backspace sequence */ +char *CD; /* clear to end of screen sequence */ +char *CE; /* clear to end of line sequence */ +char *CL; /* clear screen sequence */ +char *CM; /* cursor movement instructions */ +char *HO; /* home cursor sequence */ +char *MC; /* column cursor movement map */ +char *ML; /* row cursor movement map */ +char *ND; /* forward cursor sequence */ +char *UP; /* up cursor sequence */ + +int lHO; /* length of HO */ +int lBC; /* length of BC */ +int lND; /* length of ND */ +int lUP; /* length of UP */ +int CO; /* number of columns */ +int LI; /* number of lines */ +int *linect; /* array of lengths of lines on screen + (the actual screen is not stored) */ + + /* two letter codes */ +char tcap[] = "bccdceclcmhomcmlndup"; + /* corresponding strings */ +char **tstr[] = { &BC, &CD, &CE, &CL, &CM, &HO, &MC, &ML, &ND, &UP }; + +int buffnum; /* pointer to output buffer */ + +char tbuf[1024]; /* buffer for decoded termcap entries */ + +int oldb[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + +int oldr; +int oldw; + /* "real" cursor positions, so + * it knows when to reposition. + * These are -1 if curr and curc + * are accurate */ +int realr; +int realc; + +/* + * bsect (b,rpos,cpos,cnext) + * Print the contents of a board position. "b" has the value of the + * position, "rpos" is the row to start printing, "cpos" is the column to + * start printing, and "cnext" is positive if the position starts at the top + * and negative if it starts at the bottom. The value of "cpos" is checked + * to see if the position is a player's home, since those are printed + * differently. + */ +static void +bsect (b, rpos, cpos, cnext) + int b; /* contents of position */ + int rpos; /* row of position */ + int cpos; /* column of position */ + int cnext; /* direction of position */ +{ + register int j; /* index */ + register int n; /* number of men on position */ + register int bct = 0; /* counter */ + int k; /* index */ + char pc; /* color of men on position */ + + n = abs(b); /* initialize n and pc */ + pc = (b > 0? 'r': 'w'); + + if (n < 6 && cpos < 54) /* position cursor at start */ + curmove (rpos, cpos + 1); + else + curmove (rpos, cpos); + + for (j = 0; j < 5; j++) { /* print position row by row */ + + for (k = 0; k < 15; k += 5) /* print men */ + if (n > j+k) + fancyc (pc); + + if (j < 4) { /* figure how far to + * back up for next + * row */ + if (n < 6) { /* stop if none left */ + if (j+1 == n) + break; + bct = 1; /* single column */ + } else { + if (n < 11) { /* two columns */ + if (cpos == 54) { /* home pos */ + if (j+5 >= n) + bct = 1; + else + bct = 2; + } + if (cpos < 54) { /* not home */ + if (j+6 >= n) + bct = 1; + else + bct = 2; + } + } else { /* three columns */ + if (j+10 >= n) + bct = 2; + else + bct = 3; + } + } + curmove (curr + cnext, curc - bct); /* reposition cursor */ + } + } +} + +void +fboard () +{ + register int i, j, l; + + curmove (0, 0); /* do top line */ + for (i = 0; i < 53; i++) + fancyc ('_'); + + curmove (15, 0); /* do botttom line */ + for (i = 0; i < 53; i++) + fancyc ('_'); + + l = 1; /* do vertical lines */ + for (i = 52; i > -1; i -= 28) { + curmove ((l == 1) ? 1 : 15, i); + fancyc ('|'); + for (j = 0; j < 14; j++) { + curmove (curr + l, curc - 1); + fancyc ('|'); + } + if (i == 24) + i += 32; + l = -l; /* alternate directions */ + } + + curmove (2, 1); /* label positions 13-18 */ + for (i = 13; i < 18; i++) { + fancyc ('1'); + fancyc ((i % 10)+'0'); + curmove (curr, curc + 2); + } + fancyc ('1'); + fancyc ('8'); + + curmove (2, 29); /* label positions 19-24 */ + fancyc ('1'); + fancyc ('9'); + for (i = 20; i < 25; i++) { + curmove (curr, curc + 2); + fancyc ('2'); + fancyc ((i % 10)+'0'); + } + + curmove (14, 1); /* label positions 12-7 */ + fancyc ('1'); + fancyc ('2'); + for (i = 11; i > 6; i--) { + curmove (curr, curc + 2); + fancyc (i > 9? '1': ' '); + fancyc ((i % 10)+'0'); + } + + curmove (14, 30); /* label positions 6-1 */ + fancyc ('6'); + for (i = 5; i > 0; i--) { + curmove (curr, curc + 3); + fancyc (i+'0'); + } + + for (i = 12; i > 6; i--) /* print positions 12-7 */ + if (board[i]) + bsect (board[i],13,1+4*(12-i),-1); + + if (board[0]) /* print red men on bar */ + bsect (board[0],13,25,-1); + + for (i = 6; i > 0; i--) /* print positions 6-1 */ + if (board[i]) + bsect (board[i],13,29+4*(6-i),-1); + + l = (off[1] < 0? off[1]+15: off[1]); /* print white's home */ + bsect (l,3,54,1); + + curmove (8, 25); /* print the word BAR */ + fancyc ('B'); + fancyc ('A'); + fancyc ('R'); + + for (i = 13; i < 19; i++) /* print positions 13-18 */ + if (board[i]) + bsect (board[i],3,1+4*(i-13),1); + + if (board[25]) /* print white's men on bar */ + bsect (board[25],3,25,1); + + for (i = 19; i < 25; i++) /* print positions 19-24 */ + if (board[i]) + bsect (board[i],3,29+4*(i-19),1); + + l = (off[0] < 0? off[0]+15: off[0]); /* print red's home */ + bsect (-l,13,54,-1); + + for (i = 0; i < 26; i++) /* save board position + * for refresh later */ + oldb[i] = board[i]; + oldr = (off[1] < 0? off[1]+15: off[1]); + oldw = -(off[0] < 0? off[0]+15: off[0]); +} + +void +fixcol (r, c, l, ch, inc) + register int l, ch; + int r, c, inc; +{ + register int i; + + curmove (r, c); + fancyc (ch); + for (i = 1; i < l; i++) { + curmove (curr + inc, curc - 1); + fancyc (ch); + } +} + +void +fixpos (old, new, r, c, inc) + int old, new, r, c, inc; +{ + register int o, n, nv; + int ov, nc = 0; + char col; + + if (old*new >= 0) { + ov = abs(old); + nv = abs(new); + col = (old+new > 0? 'r': 'w'); + o = (ov-1)/5; + n = (nv-1)/5; + if (o == n) { + if (o == 2) + nc = c+2; + if (o == 1) + nc = c < 54? c: c+1; + if (o == 0) + nc = c < 54? c+1: c; + if (ov > nv) + fixcol (r+inc*(nv-n*5),nc,abs(ov-nv),' ',inc); + else + fixcol (r+inc*(ov-o*5),nc,abs(ov-nv),col,inc); + return; + } else { + if (c < 54) { + if (o+n == 1) { + if (n) { + fixcol (r,c,abs(nv-5),col,inc); + if (ov != 5) + fixcol (r+inc*ov,c+1,abs(ov-5),col,inc); + } else { + fixcol (r,c,abs(ov-5),' ',inc); + if (nv != 5) + fixcol (r+inc*nv,c+1,abs(nv-5),' ',inc); + } + return; + } + if (n == 2) { + if (ov != 10) + fixcol (r+inc*(ov-5),c,abs(ov-10),col,inc); + fixcol (r,c+2,abs(nv-10),col,inc); + } else { + if (nv != 10) + fixcol (r+inc*(nv-5),c,abs(nv-10),' ',inc); + fixcol (r,c+2,abs(ov-10),' ',inc); + } + return; + } + if (n > o) { + fixcol (r+inc*(ov%5),c+o,abs(5*n-ov),col,inc); + if (nv != 5*n) + fixcol (r,c+n,abs(5*n-nv),col,inc); + } else { + fixcol (r+inc*(nv%5),c+n,abs(5*n-nv),' ',inc); + if (ov != 5*o) + fixcol (r,c+o,abs(5*o-ov),' ',inc); + } + return; + } + } + nv = abs(new); + fixcol (r,c+1,nv,new > 0? 'r': 'w',inc); + if (abs(old) <= abs(new)) + return; + fixcol (r+inc*new,c+1,abs(old+new),' ',inc); +} + +void +refresh() +{ + register int i, r, c; + + r = curr; /* save current position */ + c = curc; + + for (i = 12; i > 6; i--) /* fix positions 12-7 */ + if (board[i] != oldb[i]) { + fixpos (oldb[i],board[i],13,1+(12-i)*4,-1); + oldb[i] = board[i]; + } + + if (board[0] != oldb[0]) { /* fix red men on bar */ + fixpos (oldb[0],board[0],13,25,-1); + oldb[0] = board[0]; + } + + for (i = 6; i > 0; i--) /* fix positions 6-1 */ + if (board[i] != oldb[i]) { + fixpos (oldb[i],board[i],13,29+(6-i)*4,-1); + oldb[i] = board[i]; + } + + i = -(off[0] < 0? off[0]+15: off[0]); /* fix white's home */ + if (oldw != i) { + fixpos (oldw,i,13,54,-1); + oldw = i; + } + + for (i = 13; i < 19; i++) /* fix positions 13-18 */ + if (board[i] != oldb[i]) { + fixpos (oldb[i],board[i],3,1+(i-13)*4,1); + oldb[i] = board[i]; + } + + if (board[25] != oldb[25]) { /* fix white men on bar */ + fixpos (oldb[25],board[25],3,25,1); + oldb[25] = board[25]; + } + + for (i = 19; i < 25; i++) /* fix positions 19-24 */ + if (board[i] != oldb[i]) { + fixpos (oldb[i],board[i],3,29+(i-19)*4,1); + oldb[i] = board[i]; + } + + i = (off[1] < 0? off[1]+15: off[1]); /* fix red's home */ + if (oldr != i) { + fixpos (oldr,i,3,54,1); + oldr = i; + } + + curmove (r, c); /* return to saved position */ + newpos(); + buflush(); +} + +void +curmove (r, c) + register int r, c; +{ + if (curr == r && curc == c) + return; + if (realr == -1) { + realr = curr; + realc = curc; + } + curr = r; + curc = c; +} + +void +newpos () +{ + register int r; /* destination row */ + register int c; /* destination column */ + register int mode = -1; /* mode of movement */ + + int count = 1000; /* character count */ + int i; /* index */ + int n; /* temporary variable */ + char *m = 0; /* string containing CM movement */ + + if (realr == -1) /* see if already there */ + return; + + r = curr; /* set current and dest. positions */ + c = curc; + curr = realr; + curc = realc; + + /* double check position */ + if (curr == r && curc == c) { + realr = realc = -1; + return; + } + + if (CM) { /* try CM to get there */ + mode = 0; + m = tgoto (CM, c, r); + count = strlen (m); + goto skip; + } + + /* try HO and local movement */ + if (HO && (n = r+c*lND+lHO) < count) { + mode = 1; + count = n; + } + + /* try various LF combinations */ + if (r >= curr) { + /* CR, LF, and ND */ + if ((n = (r-curr)+c*lND+1) < count) { + mode = 2; + count = n; + } + /* LF, ND */ + if (c >= curc && (n = (r-curr)+(c-curc)*lND) < count) { + mode = 3; + count = n; + } + /* LF, BS */ + if (c < curc && (n = (r-curr)+(curc-c)*lBC) < count) { + mode = 4; + count = n; + } + } + + /* try corresponding UP combinations */ + if (r < curr) { + /* CR, UP, and ND */ + if ((n = (curr-r)*lUP+c*lND+1) < count) { + mode = 5; + count = n; + } + /* UP and ND */ + if (c >= curc && (n = (curr-r)*lUP+(c-curc)*lND) < count) { + mode = 6; + count = n; + } + /* UP and BS */ + if (c < curc && (n = (curr-r)*lUP+(curc-c)*lBC) < count) { + mode = 7; + count = n; + } + } + + /* space over */ + if (curr == r && c > curc && linect[r] < curc && c-curc < count) + mode = 8; +skip: + switch (mode) { + + case -1: /* error! */ + write (2,"\r\nInternal cursor error.\r\n",26); + getout (0); + + /* direct cursor motion */ + case 0: + tputs (m, abs(curr-r),addbuf); + break; + + /* relative to "home" */ + case 1: + tputs (HO,r,addbuf); + for (i = 0; i < r; i++) + addbuf ('\012'); + for (i = 0; i < c; i++) + tputs (ND,1,addbuf); + break; + + /* CR and down and over */ + case 2: + addbuf ('\015'); + for (i = 0; i < r-curr; i++) + addbuf ('\012'); + for (i = 0; i < c; i++) + tputs (ND,1,addbuf); + break; + + /* down and over */ + case 3: + for (i = 0; i < r-curr; i++) + addbuf ('\012'); + for (i = 0; i < c-curc; i++) + tputs (ND,1,addbuf); + break; + + /* down and back */ + case 4: + for (i = 0; i < r-curr; i++) + addbuf ('\012'); + for (i = 0; i < curc-c; i++) + addbuf ('\010'); + break; + + /* CR and up and over */ + case 5: + addbuf ('\015'); + for (i = 0; i < curr-r; i++) + tputs (UP,1,addbuf); + for (i = 0; i < c; i++) + tputs (ND,1,addbuf); + break; + + /* up and over */ + case 6: + for (i = 0; i < curr-r; i++) + tputs (UP,1,addbuf); + for (i = 0; i < c-curc; i++) + tputs (ND,1,addbuf); + break; + + /* up and back */ + case 7: + for (i = 0; i < curr-r; i++) + tputs (UP,1,addbuf); + for (i = 0; i < curc-c; i++) { + if (BC) + tputs (BC,1,addbuf); + else + addbuf ('\010'); + } + break; + + /* safe space */ + case 8: + for (i = 0; i < c-curc; i++) + addbuf (' '); + } + + /* fix positions */ + curr = r; + curc = c; + realr = -1; + realc = -1; +} + +void +clear () +{ + register int i; + int addbuf(); + + /* double space if can't clear */ + if (CL == 0) { + writel ("\n\n"); + return; + } + + curr = curc = 0; /* fix position markers */ + realr = realc = -1; + for (i = 0; i < 24; i++) /* clear line counts */ + linect[i] = -1; + buffnum = -1; /* ignore leftover buffer contents */ + tputs (CL,CO,addbuf); /* put CL in buffer */ +} + +void +tos () +{ /* home cursor */ + curmove (0,0); +} + +static void +newline () +{ + cline(); + if (curr == LI-1) + curmove (begscr,0); + else + curmove (curr+1,0); +} + +void +fancyc (c) + register int c; /* character to output */ +{ + register int sp; /* counts spaces in a tab */ + + if (c == '\007') { /* bells go in blindly */ + addbuf (c); + return; + } + + /* process tabs, use spaces if the + * the tab should be erasing things, + * otherwise use cursor movement + * routines. Note this does not use + * hardware tabs at all. */ + if (c == '\t') { + sp = (curc+8) & (~ 7); /* compute spaces */ + /* check line length */ + if (linect[curr] >= curc || sp < 4) { + for (; sp > curc; sp--) + addbuf (' '); + curc = sp; /* fix curc */ + } else + curmove (curr,sp); + return; + } + + /* do newline be calling newline */ + if (c == '\n') { + newline(); + return; + } + + /* ignore any other control chars */ + if (c < ' ') + return; + + /* if an erasing space or non-space, + * just add it to buffer. Otherwise + * use cursor movement routine, so that + * multiple spaces will be grouped + * together */ + if (c > ' ' || linect[curr] >= curc) { + newpos (); /* make sure position correct */ + addbuf (c); /* add character to buffer */ + /* fix line length */ + if (c == ' ' && linect[curr] == curc) + linect[curr]--; + else if (linect[curr] < curc) + linect[curr] = curc; + curc++; /* fix curc */ + } else + /* use cursor movement routine */ + curmove (curr,curc+1); +} + +void +clend() +{ + register int i; + + if (CD) { + tputs (CD,CO-curr,addbuf); + for (i = curr; i < LI; i++) + linect[i] = -1; + return; + } + + curmove (i = curr,0); + cline(); + while (curr < LI-1) { + curmove (curr+1,0); + if (linect[curr] > -1) + cline (); + } + curmove (i,0); +} + +void +cline () +{ + register int c; + + if (curc > linect[curr]) + return; + newpos (); + if (CE) { + tputs (CE,1,addbuf); + linect[curr] = curc-1; + } else { + c = curc-1; + while (linect[curr] > c) { + addbuf (' '); + curc++; + linect[curr]--; + } + curmove (curr,c+1); + } +} + +int +getcaps (s) + register char *s; +{ + register char *code; /* two letter code */ + register char ***cap; /* pointer to cap string */ + char *bufp; /* pointer to cap buffer */ + char tentry[1024]; /* temporary uncoded caps buffer */ + + tgetent (tentry,s); /* get uncoded termcap entry */ + + LI = tgetnum ("li"); /* get number of lines */ + if (LI == -1) + LI = 12; + CO = tgetnum ("co"); /* get number of columns */ + if (CO == -1) + CO = 65; + + bufp = tbuf; /* get padding character */ + tgetstr ("pc",&bufp); + if (bufp != tbuf) + PC = *tbuf; + else + PC = 0; + + bufp = tbuf; /* get string entries */ + cap = tstr; + for (code = tcap; *code; code += 2) + **cap++ = tgetstr (code,&bufp); + + /* get pertinent lengths */ + if (HO) + lHO = strlen (HO); + if (BC) + lBC = strlen (BC); + else + lBC = 1; + if (UP) + lUP = strlen (UP); + if (ND) + lND = strlen (ND); + if (LI < 24 || CO < 72 || !(CL && UP && ND)) + return (0); + linect = calloc (LI+1,sizeof(int)); + return (1); +} diff --git a/src/games/backgammon/init.c b/src/games/backgammon/init.c new file mode 100644 index 0000000..15b5a9e --- /dev/null +++ b/src/games/backgammon/init.c @@ -0,0 +1,33 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include + +/* + * variable initialization. + */ + + /* name of executable object programs */ +char EXEC[] = "/games/backgammon"; +char TEACH[] = "/games/teachgammon"; + +int pnum = 2; /* color of player: + -1 = white + 1 = red + 0 = both + 2 = not yet init'ed */ +int acnt = 0; /* length of args */ +int aflag = 1; /* flag to ask for rules or instructions */ +int bflag = 0; /* flag for automatic board printing */ +int cflag = 0; /* case conversion flag */ +int hflag = 1; /* flag for cleaning screen */ +int mflag = 0; /* backgammon flag */ +int raflag = 0; /* 'roll again' flag for recovered game */ +int rflag = 0; /* recovered game flag */ +int tflag = 0; /* cursor addressing flag */ +int iroll = 0; /* special flag for inputting rolls */ +int rfl = 0; + +char *color[] = {"White", "Red", "white", "red"}; diff --git a/src/games/backgammon/main.c b/src/games/backgammon/main.c new file mode 100644 index 0000000..e9b7646 --- /dev/null +++ b/src/games/backgammon/main.c @@ -0,0 +1,559 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#ifdef CROSS +# include +#else +# include +#endif +#include +#include +#include +#include "back.h" + +#define MVPAUSE 5 /* time to sleep when stuck */ +#define MAXUSERS 35 /* maximum number of users */ + +extern const char *instr[]; /* text of instructions */ +extern const char *message[]; /* update message */ +char ospeed; /* tty output speed */ + +const char *helpm[] = { /* help message */ + "Enter a space or newline to roll, or", + " R to reprint the board\tD to double", + " S to save the game\tQ to quit", + 0 +}; + +const char *contin[] = { /* pause message */ + "(Type a newline to continue.)", + "", + 0 +}; + +# ifdef CORY +static char user1a[] = + "Sorry, you cannot play backgammon when there are more than "; +static char user1b[] = + " users\non the system."; +static char user2a[] = + "\nThere are now more than "; +static char user2b[] = + " users on the system, so you cannot play\nanother game. "; +#endif +static char rules[] = "\nDo you want the rules of the game?"; +static char noteach[] = "Teachgammon not available!\n\007"; +static char need[] = "Do you need instructions for this program?"; +static char askcol[] = + "Enter 'r' to play red, 'w' to play white, 'b' to play both:"; +static char rollr[] = "Red rolls a "; +static char rollw[] = ". White rolls a "; +static char rstart[] = ". Red starts.\n"; +static char wstart[] = ". White starts.\n"; +static char toobad1[] = "Too bad, "; +static char unable[] = " is unable to use that roll.\n"; +static char toobad2[] = ". Too bad, "; +static char cantmv[] = " can't move.\n"; +static char bgammon[] = "Backgammon! "; +static char gammon[] = "Gammon! "; +static char again[] = ".\nWould you like to play again?"; +static char svpromt[] = "Would you like to save this game?"; + +static char password[] = "losfurng"; +static char pbuf[10]; + +int +main (argc,argv) + int argc; + char **argv; +{ + register int i; /* non-descript index */ + register int l; /* non-descript index */ + register char c; /* non-descript character storage */ + long t; /* time for random num generator */ + + /* initialization */ + bflag = 2; /* default no board */ + signal (2, getout); /* trap interrupts */ + ioctl (0, TIOCGETP, &tty); /* get old tty mode */ + old = tty.sg_flags; +#ifdef V7 + noech = old & ~(ECHO | CRMOD | XTABS); + raw = noech | CBREAK; /* set up modes */ +#else + noech = old & ~ECHO; + raw = noech | RAW; /* set up modes */ +#endif + + /* check user count */ +# ifdef CORY + if (ucount() > MAXUSERS) { + writel (user1a); + wrint (MAXUSERS); + writel (user1b); + getout (0); + } +# endif + + /* get terminal + * capabilities, and + * decide if it can + * cursor address */ + tflag = getcaps (getenv ("TERM")); + /* use whole screen + * for text */ + if (tflag) + begscr = 0; + t = time(0); + srandom(t); /* 'random' seed */ + + while (*++argv != 0) /* process arguments */ + getarg (&argv); + args[acnt] = '\0'; + if (tflag) { /* clear screen */ + noech &= ~(CRMOD|XTABS); + raw &= ~(CRMOD|XTABS); + clear(); + } + fixtty (raw); /* go into raw mode */ + + rfl = rflag; /* check if restored + * game and save flag + * for later */ + if (rfl) { + text (message); /* print message */ + text (contin); + wrboard(); /* print board */ + /* if new game, pretend + * to be a non-restored + * game */ + if (cturn == 0) + rflag = 0; + } else { + rscore = wscore = 0; /* zero score */ + text (message); /* update message + * without pausing */ + + if (aflag) { /* print rules */ + writel (rules); + if (yorn(0)) { + + fixtty (old); /* restore tty */ + execl (TEACH, "backgammon", args, (char*)0); + + tflag = 0; /* error! */ + writel (noteach); + exit(-1); + } else { /* if not rules, then + * instructions */ + writel (need); + if (yorn(0)) { /* print instructions */ + clear(); + text (instr); + } + } + } + + init(); /* initialize board */ + + if (pnum == 2) { /* ask for color(s) */ + writec ('\n'); + writel (askcol); + while (pnum == 2) { + c = readc(); + switch (c) { + + case 'R': /* red */ + pnum = -1; + break; + + case 'W': /* white */ + pnum = 1; + break; + + case 'B': /* both */ + pnum = 0; + break; + + case 'P': + if (iroll) + break; + if (tflag) + curmove (curr,0); + else + writec ('\n'); + writel ("Password:"); + signal (14, getout); + cflag = 1; + alarm (10); + for (i = 0; i < 10; i++) { + pbuf[i] = readc(); + if (pbuf[i] == '\n') + break; + } + if (i == 10) + while (readc() != '\n'); + alarm (0); + cflag = 0; + if (i < 10) + pbuf[i] = '\0'; + for (i = 0; i < 9; i++) + if (pbuf[i] != password[i]) + getout (0); + iroll = 1; + if (tflag) + curmove (curr,0); + else + writec ('\n'); + writel (askcol); + break; + + default: /* error */ + writec ('\007'); + } + } + } else if (!aflag) + /* pause to read + * message */ + text (contin); + + wrboard(); /* print board */ + + if (tflag) + curmove (18,0); + else + writec ('\n'); + } + /* limit text to bottom + * of screen */ + if (tflag) + begscr = 17; + + for (;;) { /* begin game! */ + /* initial roll if + * needed */ + if ((! rflag) || raflag) + roll(); + + /* perform ritual of + * first roll */ + if (! rflag) { + if (tflag) + curmove (17,0); + while (D0 == D1) /* no doubles */ + roll(); + + /* print rolls */ + writel (rollr); + writec (D0+'0'); + writel (rollw); + writec (D1+'0'); + + /* winner goes first */ + if (D0 > D1) { + writel (rstart); + cturn = 1; + } else { + writel (wstart); + cturn = -1; + } + } + + /* initalize variables + * according to whose + * turn it is */ + + if (cturn == 1) { /* red */ + home = 25; + bar = 0; + inptr = &in[1]; + inopp = &in[0]; + offptr = &off[1]; + offopp = &off[0]; + Colorptr = &color[1]; + colorptr = &color[3]; + colen = 3; + } else { /* white */ + home = 0; + bar = 25; + inptr = &in[0]; + inopp = &in[1]; + offptr = &off[0]; + offopp = &off[1]; + Colorptr = &color[0]; + colorptr = &color[2]; + colen = 5; + } + + /* do first move + * (special case) */ + if (! (rflag && raflag)) { + if (cturn == pnum) /* computer's move */ + move (0); + else { /* player's move */ + mvlim = movallow(); + /* reprint roll */ + if (tflag) + curmove (cturn == -1? 18: 19,0); + proll(); + getmove(); /* get player's move */ + } + } + if (tflag) { + curmove (17,0); + cline(); + begscr = 18; + } + + /* no longer any diff- + * erence between normal + * game and recovered + * game. */ + rflag = 0; + + /* move as long as it's + * someone's turn */ + while (cturn == 1 || cturn == -1) { + + /* board maintainence */ + if (tflag) + refresh(); /* fix board */ + else + /* redo board if -p */ + if (cturn == bflag || bflag == 0) + wrboard(); + + /* do computer's move */ + if (cturn == pnum) { + move (1); + + /* see if double + * refused */ + if (cturn == -2 || cturn == 2) + break; + + /* check for winning + * move */ + if (*offopp == 15) { + cturn *= -2; + break; + } + continue; + + } + + /* (player's move) */ + + /* clean screen if + * safe */ + if (tflag && hflag) { + curmove (20,0); + clend (); + hflag = 1; + } + + /* if allowed, give him + * a chance to double */ + if (dlast != cturn && gvalue < 64) { + if (tflag) + curmove (cturn == -1? 18: 19,0); + writel (*Colorptr); + c = readc(); + + /* character cases */ + switch (c) { + + /* reprint board */ + case 'R': + wrboard(); + break; + + /* save game */ + case 'S': + raflag = 1; + save (1); + break; + + /* quit */ + case 'Q': + quit(); + break; + + /* double */ + case 'D': + dble(); + break; + + /* roll */ + case ' ': + case '\n': + roll(); + writel (" rolls "); + writec (D0+'0'); + writec (' '); + writec (D1+'0'); + writel (". "); + + /* see if he can move */ + if ( (mvlim = movallow()) == 0) { + + /* can't move */ + writel (toobad1); + writel (*colorptr); + writel (unable); + if (tflag) { + if (pnum) { + buflush(); + sleep (MVPAUSE); + } + } + nexturn(); + break; + } + + /* get move */ + getmove(); + + /* okay to clean + * screen */ + hflag = 1; + break; + + /* invalid character */ + default: + + /* print help message */ + if (tflag) + curmove (20,0); + else + writec ('\n'); + text (helpm); + if (tflag) + curmove (cturn == -1? 18: 19,0); + else + writec ('\n'); + + /* don't erase */ + hflag = 0; + } + } else { /* couldn't double */ + + /* print roll */ + roll(); + if (tflag) + curmove (cturn == -1? 18: 19,0); + proll (); + + /* can he move? */ + if ((mvlim = movallow()) == 0) { + + /* he can't */ + writel (toobad2); + writel (*colorptr); + writel (cantmv); + buflush(); + sleep (MVPAUSE); + nexturn(); + continue; + } + + /* get move */ + getmove(); + } + } + + /* don't worry about who + * won if quit */ + if (cturn == 0) + break; + + /* fix cturn = winner */ + cturn /= -2; + + /* final board pos. */ + if (tflag) + refresh(); + + /* backgammon? */ + mflag = 0; + l = bar+7*cturn; + for (i = bar; i != l; i += cturn) + if (board[i]*cturn) mflag++; + + /* compute game value */ + if (tflag) + curmove (20,0); + if (*offopp == 15) { + if (mflag) { + writel (bgammon); + gvalue *= 3; + } + else if (*offptr <= 0) { + writel (gammon); + gvalue *= 2; + } + } + + /* report situation */ + if (cturn == -1) { + writel ("Red wins "); + rscore += gvalue; + } else { + writel ("White wins "); + wscore += gvalue; + } + wrint (gvalue); + writel (" point"); + if (gvalue > 1) + writec ('s'); + writel (".\n"); + + /* write score */ + wrscore(); + + /* check user count */ +# ifdef CORY + if (ucount() > MAXUSERS) { + writel (user2a); + wrint (MAXUSERS); + writel (user2b); + rfl = 1; + break; + } +# endif + + /* see if he wants + * another game */ + writel (again); + if ((i = yorn ('S')) == 0) + break; + + init(); + if (i == 2) { + writel (" Save.\n"); + cturn = 0; + save (0); + } + + /* yes, reset game */ + wrboard(); + } + + /* give him a chance to save if game was recovered */ + if (rfl && cturn) { + writel (svpromt); + if (yorn (0)) { + /* re-initialize for + * recovery */ + init(); + cturn = 0; + save(0); + } + } + + /* leave peacefully */ + getout (0); + return 0; +} diff --git a/src/games/backgammon/message.c b/src/games/backgammon/message.c new file mode 100644 index 0000000..a712e48 --- /dev/null +++ b/src/games/backgammon/message.c @@ -0,0 +1,9 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +char *message[] = { + "Last update on Friday, November 26, 1999.", + 0 +}; diff --git a/src/games/backgammon/move.c b/src/games/backgammon/move.c new file mode 100644 index 0000000..13122aa --- /dev/null +++ b/src/games/backgammon/move.c @@ -0,0 +1,538 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "back.h" +#include + +#ifdef DEBUG +#ifdef CROSS +# include +#else +# include +#endif +FILE *trace; +static char tests[20]; +#endif + +struct BOARD { /* structure of game position */ + int b_board[26]; /* board position */ + int b_in[2]; /* men in */ + int b_off[2]; /* men off */ + int b_st[4], b_fn[4]; /* moves */ + + struct BOARD *b_next; /* forward queue pointer */ +}; + +struct BOARD *freeq = (struct BOARD *) -1; +struct BOARD *checkq = (struct BOARD *) -1; +struct BOARD *bsave(); +struct BOARD *nextfree(); + + /* these variables are values for the + * candidate move */ +static int ch; /* chance of being hit */ +static int op; /* computer's open men */ +static int pt; /* comp's protected points */ +static int em; /* farthest man back */ +static int frc; /* chance to free comp's men */ +static int frp; /* chance to free pl's men */ + + /* these values are the values for the + * move chosen (so far) */ +static int chance; /* chance of being hit */ +static int openmen; /* computer's open men */ +static int points; /* comp's protected points */ +static int endman; /* farthest man back */ +static int barmen; /* men on bar */ +static int menin; /* men in inner table */ +static int menoff; /* men off board */ +static int oldfrc; /* chance to free comp's men */ +static int oldfrp; /* chance to free pl's men */ + +static int cp[5]; /* candidate start position */ +static int cg[5]; /* candidate finish position */ + +static int race; /* game reduced to a race */ + +static int +bcomp (a, b) + struct BOARD *a; + struct BOARD *b; +{ + register int *aloc = a->b_board; /* pointer to board a */ + register int *bloc = b->b_board; /* pointer to board b */ + register int i; /* index */ + int result; /* comparison result */ + + for (i = 0; i < 26; i++) { /* compare boards */ + result = cturn*(aloc[i]-bloc[i]); + if (result) + return (result); /* found inequality */ + } + return (0); /* same position */ +} + +static void +mvcheck (incumbent, candidate) + register struct BOARD *incumbent; + register struct BOARD *candidate; +{ + register int i; + register int result; + + for (i = 0; i < mvlim; i++) { + result = cturn*(candidate->b_st[i]-incumbent->b_st[i]); + if (result > 0) + return; + if (result < 0) + break; + } + if (i == mvlim) + return; + for (i = 0; i < mvlim; i++) { + incumbent->b_st[i] = candidate->b_st[i]; + incumbent->b_fn[i] = candidate->b_fn[i]; + } +} + +static void +makefree (dead) + struct BOARD *dead; /* dead position */ +{ + dead->b_next = freeq; /* add to freeq */ + freeq = dead; +} + +static void +binsert (new) + struct BOARD *new; /* item to insert */ +{ + register struct BOARD *p = checkq; /* queue pointer */ + register int result; /* comparison result */ + + if (p == (struct BOARD*) -1) { /* check if queue empty */ + checkq = p = new; + p->b_next = (struct BOARD*) -1; + return; + } + + result = bcomp (new, p); /* compare to first element */ + if (result < 0) { /* insert in front */ + new->b_next = p; + checkq = new; + return; + } + if (result == 0) { /* duplicate entry */ + mvcheck (p,new); + makefree (new); + return; + } + + while (p->b_next != (struct BOARD*) -1) { /* traverse queue */ + result = bcomp (new,p->b_next); + if (result < 0) { /* found place */ + new->b_next = p->b_next; + p->b_next = new; + return; + } + if (result == 0) { /* duplicate entry */ + mvcheck (p->b_next,new); + makefree (new); + return; + } + p = p->b_next; + } + /* place at end of queue */ + p->b_next = new; + new->b_next = (struct BOARD*) -1; +} + +static void +trymove (mvnum, swapped) + register int mvnum; /* number of move (rel zero) */ + int swapped; /* see if swapped also tested */ +{ + register int pos; /* position on board */ + register int rval; /* value of roll */ + + /* if recursed through all dice + * values, compare move */ + if (mvnum == mvlim) { + binsert (bsave()); + return; + } + + /* make sure dice in always + * same order */ + if (d0 == swapped) + swap; + /* choose value for this move */ + rval = dice[mvnum != 0]; + + /* find all legitimate moves */ + for (pos = bar; pos != home; pos += cturn) { + /* fix order of dice */ + if (d0 == swapped) + swap; + /* break if stuck on bar */ + if (board[bar] != 0 && pos != bar) + break; + /* on to next if not occupied */ + if (board[pos]*cturn <= 0) + continue; + /* set up arrays for move */ + p[mvnum] = pos; + g[mvnum] = pos+rval*cturn; + if (g[mvnum]*cturn >= home) { + if (*offptr < 0) + break; + g[mvnum] = home; + } + /* try to move */ + if (makmove (mvnum)) + continue; + else + trymove (mvnum+1,2); + /* undo move to try another */ + backone (mvnum); + } + + /* swap dice and try again */ + if ((!swapped) && D0 != D1) + trymove (0,1); +} + +static void +brcopy (s) + register struct BOARD *s; /* game situation */ +{ + register int i; /* index */ + + for (i = 0; i < 26; i++) + board[i] = s->b_board[i]; + for (i = 0; i < 2; i++) { + in[i] = s->b_in[i]; + off[i] = s->b_off[i]; + } + for (i = 0; i < mvlim; i++) { + p[i] = s->b_st[i]; + g[i] = s->b_fn[i]; + } +} + +static int +movegood () +{ + register int n; + + if (*offptr == 15) + return (1); + if (menoff == 15) + return (0); + if (race) { +#ifdef DEBUG + strcat (tests,"o"); +#endif + if (*offptr-menoff) + return (*offptr > menoff); +#ifdef DEBUG + strcat (tests,"e"); +#endif + if (endman-em) + return (endman > em); +#ifdef DEBUG + strcat (tests,"i"); +#endif + if (menin == 15) + return (0); + if (*inptr == 15) + return (1); +#ifdef DEBUG + strcat (tests,"i"); +#endif + if (*inptr-menin) + return (*inptr > menin); + return (rnum(2)); + } else { + n = barmen-abs(board[home]); +#ifdef DEBUG + strcat (tests,"c"); +#endif + if (abs(chance-ch)+25*n > rnum(150)) + return (n? (n < 0): (ch < chance)); +#ifdef DEBUG + strcat (tests,"o"); +#endif + if (*offptr-menoff) + return (*offptr > menoff); +#ifdef DEBUG + strcat (tests,"o"); +#endif + if (abs(openmen-op) > 7+rnum(12)) + return (openmen > op); +#ifdef DEBUG + strcat (tests,"b"); +#endif + if (n) + return (n < 0); +#ifdef DEBUG + strcat (tests,"e"); +#endif + if (abs(endman-em) > rnum(2)) + return (endman > em); +#ifdef DEBUG + strcat (tests,"f"); +#endif + if (abs(frc-oldfrc) > rnum(2)) + return (frc < oldfrc); +#ifdef DEBUG + strcat (tests,"p"); +#endif + if (abs(n = pt-points) > rnum(4)) + return (n > 0); +#ifdef DEBUG + strcat (tests,"i"); +#endif + if (*inptr-menin) + return (*inptr > menin); +#ifdef DEBUG + strcat (tests,"f"); +#endif + if (abs(frp-oldfrp) > rnum(2)) + return (frp > oldfrp); + return (rnum(2)); + } +} + +static void +movcmp () +{ + register int i; + +#ifdef DEBUG + if (trace == NULL) + trace = fopen ("bgtrace","w"); +#endif + + odds (0,0,0); + if (!race) { + ch = op = pt = 0; + for (i = 1; i < 25; i++) { + if (board[i] == cturn) + ch = canhit (i,1); + op += abs (bar-i); + } + for (i = bar+cturn; i != home; i += cturn) + if (board[i]*cturn > 1) + pt += abs(bar-i); + frc = freemen (bar)+trapped (bar,cturn); + frp = freemen (home)+trapped (home,-cturn); + } + for (em = bar; em != home; em += cturn) + if (board[em]*cturn > 0) + break; + em = abs(home-em); +#ifdef DEBUG + fputs ("Board: ",trace); + for (i = 0; i < 26; i++) + fprintf (trace, " %d",board[i]); + if (race) + fprintf (trace,"\n\tem = %d\n",em); + else + fprintf (trace, + "\n\tch = %d, pt = %d, em = %d, frc = %d, frp = %d\n", + ch,pt,em,frc,frp); + fputs ("\tMove: ",trace); + for (i = 0; i < mvlim; i++) + fprintf (trace," %d-%d",p[i],g[i]); + fputs ("\n",trace); + fflush (trace); + strcpy (tests,""); +#endif + if ((cp[0] == 0 && cg[0] == 0) || movegood()) { +#ifdef DEBUG + fprintf (trace,"\t[%s] ... wins.\n",tests); + fflush (trace); +#endif + for (i = 0; i < mvlim; i++) { + cp[i] = p[i]; + cg[i] = g[i]; + } + if (!race) { + chance = ch; + openmen = op; + points = pt; + endman = em; + barmen = abs(board[home]); + oldfrc = frc; + oldfrp = frp; + } + menin = *inptr; + menoff = *offptr; + } +#ifdef DEBUG + else { + fprintf (trace,"\t[%s] ... loses.\n",tests); + fflush (trace); + } +#endif +} + +static void +pickmove () +{ + /* current game position */ + register struct BOARD *now = bsave(); + register struct BOARD *next; /* next move */ + +#ifdef DEBUG + if (trace == NULL) + trace = fopen ("bgtrace","w"); + fprintf (trace,"\nRoll: %d %d%s\n",D0,D1,race? " (race)": ""); + fflush (trace); +#endif + do { /* compare moves */ + brcopy (checkq); + next = checkq->b_next; + makefree (checkq); + checkq = next; + movcmp(); + } while (checkq != (struct BOARD*) -1); + + brcopy (now); +} + +void +move (okay) + int okay; /* zero if first move */ +{ + register int i; /* index */ + register int l = 0; /* last man */ + + if (okay) { + /* see if comp should double */ + if (gvalue < 64 && dlast != cturn && dblgood()) { + writel (*Colorptr); + dble(); /* double */ + /* return if declined */ + if (cturn != 1 && cturn != -1) + return; + } + roll(); + } + + race = 0; + for (i = 0; i < 26; i++) { + if (board[i] < 0) + l = i; + } + for (i = 0; i < l; i++) { + if (board[i] > 0) + break; + } + if (i == l) + race = 1; + + /* print roll */ + if (tflag) + curmove (cturn == -1? 18: 19,0); + writel (*Colorptr); + writel (" rolls "); + writec (D0+'0'); + writec (' '); + writec (D1+'0'); + /* make tty interruptable + * while thinking */ + if (tflag) + cline(); + fixtty (noech); + + /* find out how many moves */ + mvlim = movallow(); + if (mvlim == 0) { + writel (" but cannot use it.\n"); + nexturn(); + fixtty (raw); + return; + } + + /* initialize */ + for (i = 0; i < 4; i++) + cp[i] = cg[i] = 0; + + /* strategize */ + trymove (0,0); + pickmove(); + + /* print move */ + writel (" and moves "); + for (i = 0; i < mvlim; i++) { + if (i > 0) + writec (','); + wrint (p[i] = cp[i]); + writec ('-'); + wrint (g[i] = cg[i]); + makmove (i); + } + writec ('.'); + + /* print blots hit */ + if (tflag) + curmove (20,0); + else + writec ('\n'); + for (i = 0; i < mvlim; i++) + if (h[i]) + wrhit(g[i]); + /* get ready for next move */ + nexturn(); + if (!okay) { + buflush(); + sleep (3); + } + fixtty (raw); /* no more tty interrupt */ +} + +struct BOARD * +bsave () +{ + register int i; /* index */ + struct BOARD *now; /* current position */ + + now = nextfree (); /* get free BOARD */ + + /* store position */ + for (i = 0; i < 26; i++) + now->b_board[i] = board[i]; + now->b_in[0] = in[0]; + now->b_in[1] = in[1]; + now->b_off[0] = off[0]; + now->b_off[1] = off[1]; + for (i = 0; i < mvlim; i++) { + now->b_st[i] = p[i]; + now->b_fn[i] = g[i]; + } + return (now); +} + +struct BOARD * +nextfree () +{ + struct BOARD *new; + + if (freeq == (struct BOARD*) -1) { + new = calloc (1,sizeof (struct BOARD)); + if (new == 0) { + writel ("\nOut of memory\n"); + getout (0); + } + new->b_next = (struct BOARD*) -1; + return (new); + } + + new = freeq; + freeq = freeq->b_next; + return new; +} diff --git a/src/games/backgammon/odds.c b/src/games/backgammon/odds.c new file mode 100644 index 0000000..f7ae94a --- /dev/null +++ b/src/games/backgammon/odds.c @@ -0,0 +1,84 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "back.h" + +void +odds (r1, r2, val) + register int r1; + int r2, val; +{ + register int i, j; + + if (r1 == 0) { + for (i = 0; i < 6; i++) + for (j = 0; j < 6; j++) + table[i][j] = 0; + return; + } else { + r1--; + if (r2-- == 0) + for (i = 0; i < 6; i++) { + table[i][r1] += val; + table[r1][i] += val; + } + else { + table[r2][r1] += val; + table[r1][r2] += val; + } + } +} + +int +count () +{ + register int i; + register int j; + register int total; + + total = 0; + for (i = 0; i < 6; i++) + for (j = 0; j < 6; j++) + total += table[i][j]; + return (total); +} + +int +canhit (i, c) + int i, c; +{ + register int j, k, b; + int a, diff, place, addon, menstuck; + + if (c == 0) + odds (0,0,0); + if (board[i] > 0) { + a = -1; + b = 25; + } else { + a = 1; + b = 0; + } + place = abs (25-b-i); + menstuck = abs (board[b]); + for (j = b; j != i; j += a) { + if (board[j]*a > 0) { + diff = abs(j-i); + addon = place+((board[j]*a > 2 || j == b)? 5: 0); + if ((j == b && menstuck == 1) && + (j != b && menstuck == 0)) + for (k = 1; k < diff; k++) + if (k < 7 && diff-k < 7 && + (board[i+a*k]*a >= 0 || + board[i+a*(diff-k)] >= 0)) + odds (k,diff-k,addon); + if ((j == b || menstuck < 2) && diff < 7) + odds (diff,0,addon); + } + if (j == b && menstuck > 1) + break; + } + return (count()); +} diff --git a/src/games/backgammon/one.c b/src/games/backgammon/one.c new file mode 100644 index 0000000..f1267e7 --- /dev/null +++ b/src/games/backgammon/one.c @@ -0,0 +1,139 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "back.h" + +static int +last () +{ + register int i; + + for (i = home-6*cturn; i != home; i += cturn) + if (board[i]*cturn > 0) + return (abs(home-i)); + return 0; +} + +static int +checkd (d) + register int d; +{ + if (d0 != d) + swap; + return (0); +} + +int +makmove (i) + register int i; +{ + register int n, d; + int max; + + d = d0; + n = abs(g[i]-p[i]); + max = (*offptr < 0? 7: last()); + if (board[p[i]]*cturn <= 0) + return (checkd(d)+2); + if (g[i] != home && board[g[i]]*cturn < -1) + return (checkd(d)+3); + if (i || D0 == D1) { + if (n == max? D1 < n: D1 != n) + return (checkd(d)+1); + } else { + if (n == max? D0 < n && D1 < n: D0 != n && D1 != n) + return (checkd(d)+1); + if (n == max? D0 < n: D0 != n) { + if (d0) + return (checkd(d)+1); + swap; + } + } + if (g[i] == home && *offptr < 0) + return (checkd(d)+4); + h[i] = 0; + board[p[i]] -= cturn; + if (g[i] != home) { + if (board[g[i]] == -cturn) { + board[home] -= cturn; + board[g[i]] = 0; + h[i] = 1; + if (abs(bar-g[i]) < 7) { + (*inopp)--; + if (*offopp >= 0) + *offopp -= 15; + } + } + board[g[i]] += cturn; + if (abs(home-g[i]) < 7 && abs(home-p[i]) > 6) { + (*inptr)++; + if (*inptr+*offptr == 0) + *offptr += 15; + } + } else { + (*offptr)++; + (*inptr)--; + } + return (0); +} + +void +moverr (i) + register int i; +{ + register int j; + + if (tflag) + curmove (20,0); + else + writec ('\n'); + writel ("Error: "); + for (j = 0; j <= i; j++) { + wrint (p[j]); + writec ('-'); + wrint (g[j]); + if (j < i) + writec (','); + } + writel ("... "); + movback (i); +} + +void +movback (i) + register int i; +{ + register int j; + + for (j = i-1; j >= 0; j--) + backone(j); +} + +void +backone (i) + register int i; +{ + board[p[i]] += cturn; + if (g[i] != home) { + board[g[i]] -= cturn; + if (abs(g[i]-home) < 7 && abs(p[i]-home) > 6) { + (*inptr)--; + if (*inptr+*offptr < 15 && *offptr >= 0) + *offptr -= 15; + } + } else { + (*offptr)--; + (*inptr)++; + } + if (h[i]) { + board[home] += cturn; + board[g[i]] = -cturn; + if (abs(bar-g[i]) < 7) { + (*inopp)++; + if (*inopp+*offopp == 0) + *offopp += 15; + } + } +} diff --git a/src/games/backgammon/save.c b/src/games/backgammon/save.c new file mode 100644 index 0000000..27ec05f --- /dev/null +++ b/src/games/backgammon/save.c @@ -0,0 +1,148 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "back.h" +#include +#include +#include + +static char confirm[] = "Are you sure you want to leave now?"; +static char prompt[] = "Enter a file name: "; +static char exist1[] = "The file '"; +static char exist2[] = + "' already exists.\nAre you sure you want to use this file?"; +static char cantuse[] = "\nCan't use "; +static char saved[] = "This game has been saved on the file '"; +static char type[] = "'.\nType \"backgammon "; +static char rec[] = "\" to recover your game.\n\n"; +static char cantrec[] = "Can't recover file: "; + +void +save (n) + register int n; +{ + register int fdesc; + register char *fs; + char fname[50]; + + if (n) { + if (tflag) { + curmove (20,0); + clend(); + } else + writec ('\n'); + writel (confirm); + if (! yorn(0)) + return; + } + cflag = 1; + for (;;) { + writel (prompt); + fs = fname; + while ((*fs = readc()) != '\n') { + if (*fs == tty.sg_erase) { + if (fs > fname) { + fs--; + if (tflag) + curmove (curr,curc-1); + else + writec (*fs); + } else + writec ('\007'); + continue; + } + writec (*fs++); + } + *fs = '\0'; + if ((fdesc = open(fname,2)) == -1 /*&& errno == 2*/) { + if ((fdesc = creat (fname,0700)) != -1) + break; + } + if (fdesc != -1) { + if (tflag) { + curmove (18,0); + clend(); + } else + writec ('\n'); + writel (exist1); + writel (fname); + writel (exist2); + cflag = 0; + close (fdesc); + if (yorn (0)) { + unlink (fname); + fdesc = creat (fname,0700); + break; + } else { + cflag = 1; + continue; + } + } + writel (cantuse); + writel (fname); + writel (".\n"); + close (fdesc); + cflag = 1; + } + write (fdesc,board,sizeof board); + write (fdesc,off,sizeof off); + write (fdesc,in,sizeof in); + write (fdesc,dice,sizeof dice); + write (fdesc,&cturn,sizeof cturn); + write (fdesc,&dlast,sizeof dlast); + write (fdesc,&pnum,sizeof pnum); + write (fdesc,&rscore,sizeof rscore); + write (fdesc,&wscore,sizeof wscore); + write (fdesc,&gvalue,sizeof gvalue); + write (fdesc,&raflag,sizeof raflag); + close (fdesc); + if (tflag) + curmove (18,0); + writel (saved); + writel (fname); + writel (type); + writel (fname); + writel (rec); + if (tflag) + clend(); + getout (0); +} + +static void +norec (s) + register char *s; +{ + register char *c; + + tflag = 0; + writel (cantrec); + c = s; + while (*c != '\0') + writec (*c++); + getout (0); +} + +void +recover (s) + char *s; +{ + int fdesc; + + if ((fdesc = open (s,0)) == -1) + norec (s); + read (fdesc,board,sizeof board); + read (fdesc,off,sizeof off); + read (fdesc,in,sizeof in); + read (fdesc,dice,sizeof dice); + read (fdesc,&cturn,sizeof cturn); + read (fdesc,&dlast,sizeof dlast); + read (fdesc,&pnum,sizeof pnum); + read (fdesc,&rscore,sizeof rscore); + read (fdesc,&wscore,sizeof wscore); + read (fdesc,&gvalue,sizeof gvalue); + read (fdesc,&raflag,sizeof raflag); + close (fdesc); + rflag = 1; +} diff --git a/src/games/backgammon/subs.c b/src/games/backgammon/subs.c new file mode 100644 index 0000000..709174f --- /dev/null +++ b/src/games/backgammon/subs.c @@ -0,0 +1,475 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#ifdef CROSS +# include +#else +# include +#endif +#include +#include "back.h" + +int buffnum; +char outbuff[BUFSIZ]; + +static char plred[] = "Player is red, computer is white."; +static char plwhite[] = "Player is white, computer is red."; +static char nocomp[] = "(No computer play.)"; + +char *descr[] = { + "Usage: backgammon [-] [n r w b pr pw pb t3a]\n", + "\t-\tgets this list\n\tn\tdon't ask for rules or instructions", + "\tr\tplayer is red (implies n)\n\tw\tplayer is white (implies n)", + "\tb\ttwo players, red and white (implies n)", + "\tpr\tprint the board before red's turn", + "\tpw\tprint the board before white's turn", + "\tpb\tprint the board before both player's turn", + "\tterm\tterminal is a term", + "\tsfile\trecover saved game from file", + 0 +}; + +void +errexit (s) + register char *s; +{ + write (2,"\n",1); + perror (s); + getout (0); +} + +void +strset (s1,s2) + register char *s1, *s2; +{ + while ( (*s1++ = *s2++) != '\0'); +} + +int +addbuf (c) + register int c; +{ + buffnum++; + if (buffnum == BUFSIZ) { + if (write(1, outbuff, BUFSIZ) != BUFSIZ) + errexit ("addbuf (write):"); + buffnum = 0; + } + outbuff[buffnum] = c; + return 0; +} + +void +buflush () +{ + if (buffnum < 0) + return; + buffnum++; + if (write (1,outbuff,buffnum) != buffnum) + errexit ("buflush (write):"); + buffnum = -1; +} + +int +readc () +{ + char c; + + if (tflag) { + cline(); + newpos(); + } + buflush(); + if (read(0,&c,1) != 1) + errexit ("readc"); + if (c == '\177') + getout (0); + if (c == '\033' || c == '\015') + return ('\n'); + if (cflag) + return (c); + if (c == '\014') + return ('R'); + if (c >= 'a' && c <= 'z') + return (c & 0137); + return (c); +} + +void +writec (c) + int c; +{ + if (tflag) + fancyc (c); + else + addbuf (c); +} + +void +writel (l) + register const char *l; +{ +#ifdef DEBUG + register const char *s; + + if (trace == NULL) + trace = fopen ("bgtrace","w"); + + fprintf (trace,"writel: \""); + for (s = l; *s; s++) { + if (*s < ' ' || *s == '\177') + fprintf (trace,"^%c",(*s)^0100); + else + putc (*s,trace); + } + fprintf (trace,"\"\n"); + fflush (trace); +#endif + + while (*l) + writec (*l++); +} + +void +proll () +{ + if (d0) + swap; + if (cturn == 1) + writel ("Red's roll: "); + else + writel ("White's roll: "); + writec (D0+'0'); + writec ('\040'); + writec (D1+'0'); + if (tflag) + cline(); +} + +void +wrint (n) + int n; +{ + register int i, j, t; + + for (i = 4; i > 0; i--) { + t = 1; + for (j = 0; j t-1) + writec ((n/t)%10+'0'); + } + writec (n%10+'0'); +} + +void +gwrite() +{ + register int r = 0, c = 0; + + if (tflag) { + r = curr; + c = curc; + curmove (16,0); + } + + if (gvalue > 1) { + writel ("Game value: "); + wrint (gvalue); + writel (". "); + if (dlast == -1) + writel (color[0]); + else + writel (color[1]); + writel (" doubled last."); + } else { + switch (pnum) { + case -1: /* player is red */ + writel (plred); + break; + case 0: /* player is both colors */ + writel (nocomp); + break; + case 1: /* player is white */ + writel (plwhite); + } + } + + if (rscore || wscore) { + writel (" "); + wrscore(); + } + + if (tflag) { + cline(); + curmove (r, c); + } +} + +int +quit () +{ + if (tflag) { + curmove (20,0); + clend(); + } else + writec ('\n'); + writel ("Are you sure you want to quit?"); + if (yorn (0)) { + if (rfl) { + writel ("Would you like to save this game?"); + if (yorn(0)) + save(0); + } + cturn = 0; + return (1); + } + return (0); +} + +int +yorn (special) + register int special; /* special response */ +{ + register int c; + register int i; + + i = 1; + while ((c = readc()) != 'Y' && c != 'N') { + if (special && c == special) + return (2); + if (i) { + if (special) { + writel (" (Y, N, or "); + writec (special); + writec (')'); + } else + writel (" (Y or N)"); + i = 0; + } else + writec ('\007'); + } + if (c == 'Y') + writel (" Yes.\n"); + else + writel (" No.\n"); + if (tflag) + buflush(); + return (c == 'Y'); +} + +void +wrhit (i) + register int i; +{ + writel ("Blot hit on "); + wrint (i); + writec ('.'); + writec ('\n'); +} + +void +nexturn () +{ + register int c; + + cturn = -cturn; + c = cturn/abs(cturn); + home = bar; + bar = 25-bar; + offptr += c; + offopp -= c; + inptr += c; + inopp -= c; + Colorptr += c; + colorptr += c; +} + +void +getarg (arg) + register char ***arg; +{ + register char **s; + + /* process arguments here. dashes are ignored, nbrw are ignored + if the game is being recovered */ + + s = *arg; + while (s[0][0] == '-') { + switch (s[0][1]) { + + /* don't ask if rules or instructions needed */ + case 'n': + if (rflag) + break; + aflag = 0; + args[acnt++] = 'n'; + break; + + /* player is both read and white */ + case 'b': + if (rflag) + break; + pnum = 0; + aflag = 0; + args[acnt++] = 'b'; + break; + + /* player is red */ + case 'r': + if (rflag) + break; + pnum = -1; + aflag = 0; + args[acnt++] = 'r'; + break; + + /* player is white */ + case 'w': + if (rflag) + break; + pnum = 1; + aflag = 0; + args[acnt++] = 'w'; + break; + + /* print board after move according to following character */ + case 'p': + if (s[0][2] != 'r' && s[0][2] != 'w' && s[0][2] != 'b') + break; + args[acnt++] = 'p'; + args[acnt++] = s[0][2]; + if (s[0][2] == 'r') + bflag = 1; + if (s[0][2] == 'w') + bflag = -1; + if (s[0][2] == 'b') + bflag = 0; + break; + + case 't': + if (s[0][2] == '\0') { /* get terminal caps */ + s++; + tflag = getcaps (*s); + } else + tflag = getcaps (&s[0][2]); + break; + + case 's': + s++; + /* recover file */ + recover (s[0]); + break; + } + s++; + } + if (s[0] != 0) + recover(s[0]); +} + +void +init () +{ + register int i; + for (i = 0; i < 26;) + board[i++] = 0; + board[1] = 2; + board[6] = board[13] = -5; + board[8] = -3; + board[12] = board[19] = 5; + board[17] = 3; + board[24] = -2; + off[0] = off[1] = -15; + in[0] = in[1] = 5; + gvalue = 1; + dlast = 0; +} + +void +wrscore () +{ + writel ("Score: "); + writel (color[1]); + writec (' '); + wrint (rscore); + writel (", "); + writel (color[0]); + writec (' '); + wrint (wscore); +} + +void +fixtty (mode) + int mode; +{ + if (tflag) + newpos(); + buflush(); + tty.sg_flags = mode; + ioctl (0, TIOCSETP, &tty); +} + +void +getout (sig) +{ + /* go to bottom of screen */ + if (tflag) { + curmove (23,0); + cline(); + } else + writec ('\n'); + + /* fix terminal status */ + fixtty (old); + exit(-1); +} + +void +roll () +{ + register char c; + register int row = 0; + register int col = 0; + + if (iroll) { + if (tflag) { + row = curr; + col = curc; + curmove (17,0); + } else + writec ('\n'); + writel ("ROLL: "); + c = readc(); + if (c != '\n') { + while (c < '1' || c > '6') + c = readc(); + D0 = c-'0'; + writec (' '); + writec (c); + c = readc(); + while (c < '1' || c > '6') + c = readc(); + D1 = c-'0'; + writec (' '); + writec (c); + if (tflag) { + curmove (17,0); + cline(); + curmove (row,col); + } else + writec ('\n'); + return; + } + if (tflag) { + curmove (17,0); + cline(); + curmove (row,col); + } else + writec ('\n'); + } + D0 = rnum(6)+1; + D1 = rnum(6)+1; + d0 = 0; +} diff --git a/src/games/backgammon/table.c b/src/games/backgammon/table.c new file mode 100644 index 0000000..78a2989 --- /dev/null +++ b/src/games/backgammon/table.c @@ -0,0 +1,276 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "back.h" + +const char *help2[] = { + " Enter moves as - or / where is the starting", + "position, is the finishing position, and is the roll.", + "Remember, each die roll must be moved separately.", + 0 +}; + +struct state { + char ch; + int fcode; + int newst; +}; + +struct state atmata[] = { + + { 'R', 1, 0 }, { '?', 7, 0 }, { 'Q', 0, -3 }, { 'B', 8, 25 }, + { '9', 2, 25 }, { '8', 2, 25 }, { '7', 2, 25 }, { '6', 2, 25 }, + { '5', 2, 25 }, { '4', 2, 25 }, { '3', 2, 25 }, { '2', 2, 19 }, + { '1', 2, 15 }, { '0', 2, 25 }, { '.', 0, 0 }, { '9', 2, 25 }, + { '8', 2, 25 }, { '7', 2, 25 }, { '6', 2, 25 }, { '5', 2, 25 }, + + { '4', 2, 25 }, { '3', 2, 25 }, { '2', 2, 25 }, { '1', 2, 25 }, + { '0', 2, 25 }, { '/', 0, 32 }, { '-', 0, 39 }, { '.', 0, 0 }, + { '/', 5, 32 }, { ' ', 6, 3 }, { ',', 6, 3 }, { '\n',0, -1 }, + { '6', 3, 28 }, { '5', 3, 28 }, { '4', 3, 28 }, { '3', 3, 28 }, + { '2', 3, 28 }, { '1', 3, 28 }, { '.', 0, 0 }, { 'H', 9, 61 }, + + { '9', 4, 61 }, { '8', 4, 61 }, { '7', 4, 61 }, { '6', 4, 61 }, + { '5', 4, 61 }, { '4', 4, 61 }, { '3', 4, 61 }, { '2', 4, 53 }, + { '1', 4, 51 }, { '0', 4, 61 }, { '.', 0, 0 }, { '9', 4, 61 }, + { '8', 4, 61 }, { '7', 4, 61 }, { '6', 4, 61 }, { '5', 4, 61 }, + { '4', 4, 61 }, { '3', 4, 61 }, { '2', 4, 61 }, { '1', 4, 61 }, + + { '0', 4, 61 }, { ' ', 6, 3 }, { ',', 6, 3 }, { '-', 5, 39 }, + { '\n',0, -1 }, { '.', 0, 0 }, +}; + +static int +dotable (c, i) + char c; + register int i; +{ + register int a; + int test; + + test = (c == 'R'); + + while ( (a = atmata[i].ch) != '.') { + if (a == c || (test && a == '\n')) { + switch (atmata[i].fcode) { + + case 1: + wrboard(); + if (tflag) { + curmove (cturn == -1? 18: 19,0); + proll (); + writel ("\t\t"); + } else + proll (); + break; + + case 2: + if (p[mvl] == -1) + p[mvl] = c-'0'; + else + p[mvl] = p[mvl]*10+c-'0'; + break; + + case 3: + if (g[mvl] != -1) { + if (mvl < mvlim) + mvl++; + p[mvl] = p[mvl-1]; + } + g[mvl] = p[mvl]+cturn*(c-'0'); + if (g[mvl] < 0) + g[mvl] = 0; + if (g[mvl] > 25) + g[mvl] = 25; + break; + + case 4: + if (g[mvl] == -1) + g[mvl] = c-'0'; + else + g[mvl] = g[mvl]*10+c-'0'; + break; + + case 5: + if (mvl < mvlim) + mvl++; + p[mvl] = g[mvl-1]; + break; + + case 6: + if (mvl < mvlim) + mvl++; + break; + + case 7: + if (tflag) + curmove (20,0); + else + writec ('\n'); + text (help2); + if (tflag) { + curmove (cturn == -1? 18: 19,39); + } else { + writec ('\n'); + proll(); + writel ("\t\tMove: "); + } + break; + + case 8: + p[mvl] = bar; + break; + + case 9: + g[mvl] = home; + } + + if (! test || a != '\n') + return (atmata[i].newst); + else + return (-6); + } + + i++; + } + + return (-5); +} + +static int +rsetbrd () +{ + register int i, j, n; + + n = 0; + mvl = 0; + for (i = 0; i < 4; i++) + p[i] = g[i] = -1; + for (j = 0; j < ncin; j++) + n = dotable (cin[j],n); + return (n); +} + +int +checkmove (ist) + int ist; +{ + register int j, n; + register char c; + +domove: + if (ist == 0) { + if (tflag) + curmove (curr,32); + else + writel ("\t\t"); + writel ("Move: "); + } + ist = mvl = ncin = 0; + for (j = 0; j < 5; j++) + p[j] = g[j] = -1; + +dochar: + c = readc(); + + if (c == 'S') { + raflag = 0; + save (1); + if (tflag) { + curmove (cturn == -1? 18: 19,39); + ist = -1; + goto domove; + } else { + proll (); + ist = 0; + goto domove; + } + } + + if (c == tty.sg_erase && ncin > 0) { + if (tflag) + curmove (curr,curc-1); + else { + if (tty.sg_erase == '\010') + writel ("\010 \010"); + else + writec (cin[ncin-1]); + } + ncin--; + n = rsetbrd(); + if (n == 0) { + n = -1; + if (tflag) + refresh(); + } + if ((ist = n) > 0) + goto dochar; + goto domove; + } + + if (c == tty.sg_kill && ncin > 0) { + if (tflag) { + refresh(); + curmove (curr,39); + ist = -1; + goto domove; + } else if (tty.sg_erase == '\010') { + for (j = 0; j < ncin; j++) + writel ("\010 \010"); + ist = -1; + goto domove; + } else { + writec ('\\'); + writec ('\n'); + proll (); + ist = 0; + goto domove; + } + } + + n = dotable(c,ist); + if (n >= 0) { + cin[ncin++] = c; + if (n > 2) + if ((! tflag) || c != '\n') + writec (c); + ist = n; + if (n) + goto dochar; + else + goto domove; + } + + if (n == -1 && mvl >= mvlim) + return(0); + if (n == -1 && mvl < mvlim-1) + return(-4); + + if (n == -6) { + if (! tflag) { + if (movokay(mvl+1)) { + wrboard(); + movback (mvl+1); + } + proll (); + writel ("\t\tMove: "); + for (j = 0; j < ncin;) + writec (cin[j++]); + } else { + if (movokay(mvl+1)) { + refresh(); + movback (mvl+1); + } else + curmove (cturn == -1? 18:19,ncin+39); + } + ist = n = rsetbrd(); + goto dochar; + } + + if (n != -5) + return(n); + writec ('\007'); + goto dochar; +} diff --git a/src/games/backgammon/teach.c b/src/games/backgammon/teach.c new file mode 100644 index 0000000..6a24ead --- /dev/null +++ b/src/games/backgammon/teach.c @@ -0,0 +1,126 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "back.h" +#include +#include + +extern const char *hello[]; +extern const char *list[]; +extern const char *intro1[]; +extern const char *intro2[]; +extern const char *moves[]; +extern const char *remove[]; +extern const char *hits[]; +extern const char *endgame[]; +extern const char *doubl[]; +extern const char *stragy[]; +extern const char *prog[]; +extern const char *lastch[]; + +const char *helpm[] = { + "\nEnter a space or newline to roll, or", + " b to display the board", + " d to double", + " q to quit\n", + 0 +}; + +const char *contin[] = { + "", + 0 +}; + +int +main (argc,argv) + int argc; + char **argv; +{ + register int i; + + signal (2,getout); + if (ioctl (0, TIOCGETP, &tty) == -1) /* get old tty mode */ + errexit ("teachgammon(gtty)"); + old = tty.sg_flags; +#ifdef V7 + raw = ((noech = old & ~ECHO) | CBREAK); /* set up modes */ +#else + raw = ((noech = old & ~ECHO) | RAW); /* set up modes */ +#endif + tflag = getcaps (getenv ("TERM")); + while (*++argv != 0) + getarg (&argv); + if (tflag) { + noech &= ~(CRMOD|XTABS); + raw &= ~(CRMOD|XTABS); + clear(); + } + text (hello); + text (list); + i = text (contin); + if (i == 0) + i = 2; + init(); + while (i) + switch (i) { + case 1: + leave(); + case 2: + i = text(intro1); + if (i) + break; + wrboard(); + i = text(intro2); + if (i) + break; + case 3: + i = text(moves); + if (i) + break; + case 4: + i = text(remove); + if (i) + break; + case 5: + i = text(hits); + if (i) + break; + case 6: + i = text(endgame); + if (i) + break; + case 7: + i = text(doubl); + if (i) + break; + case 8: + i = text(stragy); + if (i) + break; + case 9: + i = text(prog); + if (i) + break; + case 10: + i = text(lastch); + if (i) + break; + } + tutor(); + return 0; +} + +void +leave() +{ + if (tflag) + clear(); + else + writec ('\n'); + fixtty(old); + execl (EXEC, "backgammon", args, "n", (char*)0); + writel ("Help! Backgammon program is missing\007!!\n"); + exit (-1); +} diff --git a/src/games/backgammon/text.c b/src/games/backgammon/text.c new file mode 100644 index 0000000..a432293 --- /dev/null +++ b/src/games/backgammon/text.c @@ -0,0 +1,100 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "back.h" + +char *instr[] = { + " If you did not notice by now, this program reacts to things as", + "soon as you type them, without waiting for a newline. This means that", + "the special characters RUBOUT, ESC, and CONTROL-D, will not perform", + "their special functions during most of this program. The program", + "should usually stop when a RUBOUT is typed, but occasionally it will", + "ignore RUBOUTs until it is waiting for input.\n", + " These instructions are presented in small chunks designed not to", + "roll off the top of your screen. When the characters '-->' are print-", + "ed, no more data will be printed until a space or newline is typed.", + "In this way, you can finish one section before continuing to another.", + "Like this:", + "", + " The two sides are colored 'red' and 'white.' The computer may play", + "one side, or if there are two players, the computer can merely act as", + "a gamekeeper, letting the players make the moves. Once you tell the", + "computer what color(s) you want to play, the decision remains in ef-", + "fect until you quit the program, even if you play more than one game,", + "since the program keeps a running score.\n", + " The program will prompt for a move in one of two ways. If the", + "player has the opportunity to double, then merely his color will be", + "typed out. The player can now do one of several things. He can dou-", + "ble by typing a 'd', he can roll by typing a space (' ') or newline,", + "or if he is not sure, he can reprint the board by typing a 'r'.\n", + " If the player cannot double, his roll will be thrust in front of", + "him, followed by the request 'Move:', asking for a move but not giving", + "him the chance to double. He can still ask for the board by typing", + "'r'. In either of these two states, the player can quit by typing 'q'", + "or save the game by typing 's'. In either case, the player will be", + "asked to verify, in case there was some error. The program then ends", + "immediately, after first saving the file if so requested.", + "", + " A player can move one of his men using two forms of input. The", + "first form is -, where is the starting position, and is", + "the finishing position of the player's man. For example, if white", + "wanted to move a piece from position 13 to position 8, his move could", + "be entered as 13-8. The second form is / where is the", + "starting position, an is the roll actually made. Hence, white", + "could have entered as 13/5 instead of 13-8.\n", + " A player must move each roll of the dice separately. For example,", + "if a player rolled 4 3, and wanted to move from 13 to 6, he could", + "enter it as 13/4,9/3 or 13/3,10/4 or 13-10,10-6 or 13-9,9-6, but not", + "13-6. The last two entries can be shortened to 13-10-6 and 13-9-6.", + "If you want to move more than one piece from the same position, such", + "as 13-10,13-9, you can abbreviate this using the / format as by", + "entering more than one , or 13/34. A player can use both forms for", + "the same roll, e.g. 13/3,13-9, and separates individual moves by ei-", + "ther a comma or a space. The letter 'b' represents the bar, and the", + "letter 'h' represents a player's home. You could also enter the", + "number that would be in the position of the bar, 25 or 0 as appropri-", + "ate. Use a newline at the end of your moves for a turn.", + "", + " As you type in your move, if a character does not make sense under", + "the above constrictions, a bell will sound instead of the character,", + "and it will be ignored. You may kill lines and erase characters as", + "you would normally, but don't be surprised if they look different than", + "usual. Also, if you have entered one or more of your rolls, and you", + "wish to see what the move looks like so far, type a 'r' to see what it", + "looks like. This cannot be done in the middle of a move (e.g., after", + "a '-' or '/'). After the printing board, the program will go back to", + "inputting your move and you can backspace or kill just as if you had", + "just typed in your input.\n", + " Now you should be ready to begin the game. Good luck!", + "", + 0}; + +int +text (t) + const char **t; +{ + register int i; + register const char *s, *a; + + fixtty (noech); + while (*t != 0) { + s = a = *t; + for (i = 0; *a != '\0'; i--) + a++; + if (i) { + writel (s); + writec ('\n'); + } else { + writel ("-->"); + fixtty (raw); + while ((i = readc()) != ' ' && i != '\n'); + fixtty (noech); + clear(); + } + t++; + } + fixtty (raw); + return 0; +} diff --git a/src/games/backgammon/ttext1.c b/src/games/backgammon/ttext1.c new file mode 100644 index 0000000..0f61578 --- /dev/null +++ b/src/games/backgammon/ttext1.c @@ -0,0 +1,152 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "back.h" + +char *opts = " QIMRHEDSPT"; +char *prompt = "-->"; + +const char *list[] = { + "\n\n\tI\tIntroduction to Backgammon", + "\tM\tMoves and Points", + "\tR\tRemoving Men from the Board", + "\tH\tHitting Blots", + "\tE\tEnding the Game and Scoring", + "\tD\tDoubling", + "\tS\tStrategy", + "\tP\tThe Program and How to Use It", + "\nalso, you can type:", + "\t?\tto get this list", + "\tQ\tto go start playing", + "\tT\tto go straight to the tutorial", + 0 +}; + +const char *hello[] = { + "\n\032 These rules consist of text describing how to play Backgammon", + "followed by a tutorial session where you play a practice game", + "against the computer. When using this program, think carefuly", + "before typing, since it reacts as soon as you type something. In", + "addition, the program presents text output, such as these rules,", + "in small blocks that will not roll off the top of the screen.", + "Frequently, you will see the characters '-->' indicating that the", + "program is waiting for you to finish reading, and will continue", + "printing when you type a space or newline. Also, the rules are", + "divided into sections, and although you should read them in or-", + "der, you can go directly to any of them by typing one of the fol-", + "lowing letters:", + "(Remember to hit a space or a newline to continue.)", + "", + 0 +}; + +const char *intro1[] = { + "\nIntroduction:", + "\n Backgammon is a game involving the skill of two players and", + "the luck of two dice. There are two players, red and white, and", + "each player gets fifteen men. The object of the game is to re-", + "move all your men from the board before the opponent does. The", + "board consists of twenty-four positions, a 'bar' and a 'home' for", + "each player. It looks like this:", + "", + 0}; + +const char *intro2[] = { + "", + "\n Although not indicated on the board, the players' homes are", + "located just to the right of the board. A player's men are placed", + "there when they are removed from the board. The board you just", + "saw was in it's initial position. All games start with the board", + "looking like this. Notice that red's pieces are represented by the", + "letter 'r' and white's pieces are represented by the letter 'w'.", + "Also, a position may have zero or more pieces on it, e.g. posi-", + "tion 12 has five red pieces on it, while position 11 does not", + "have any pieces of either color.", + "", + 0}; + +const char *moves[] = { + "\nMoves and Points:", + "\n Moves are made along the positions on the board according to", + "their numbers. Red moves in the positive direction (clockwise", + "from 1 to 24), and white moves in the negative direction (coun-", + "terclockwise from 24 to 1).", + "\n A turn consists of rolling the dice, and moving the number of", + "positions indicated on each die. The two numbers can be used to", + "move one man the sum of the two rolls, or two men the number on", + "each individual die. For example, if red rolled 6 3 at the start", + "of the game, he might move a man from 1 to 7 to 10, using both", + "dice for one man, or he might move two men from position 12, one", + "to 15 and one to 18. (Red did not have to choose two men start-", + "ing from the same position.) In addition, doubles are treated", + "specially in backgammon. When a player rolls doubles, he gets to", + "move as if he had four dice instead of two. For instance, if you", + "rolled double 2's, you could move one man eight positions, four", + "men two positions each, or any permutation in between.", + "", + "\n However, there are certain limitations, called 'points.' A", + "player has a point when he has two or more men on the same posi-", + "tion. This gives him custody of that position, and his opponent", + "cannot place his men there, even if passing through on the way to", + "another position. When a player has six points in a row, it is", + "called a 'wall,' since any of his opponent's men behind the wall", + "cannot pass it and are trapped, at least for the moment. Notice", + "that this could mean that a player could not use part or all of", + "his roll. However, he must use as much of his roll as possible.", + "", + 0}; + +const char *remove[] = { + "\nRemoving Men from the Board:", + "\n The most important part of the game is removing men, since", + "that is how you win the game. Once a man is removed, he stays", + "off the board for the duration of the game. However, a player", + "cannot remove men until all his men are on his 'inner table,' or", + "the last six positions of the board (19-24 for red, 6-1 for", + "white).", + "\n To get off the board, a player must roll the exact number to", + "get his man one position past the last position on the board, or", + "his 'home.' Hence, if red wanted to remove a man from position", + "23, he would have to roll a 2, anything else would be used for", + "another man, or for another purpose. However, there is one ex-", + "ception. If the player rolling has no men far enough to move the", + "roll made, he may move his farthest man off the board. For exam-", + "ple, if red's farthest man back was on position 21, he could re-", + "move men from that position if he rolled a 5 or a 6, as well as a", + "4. Since he does not have men on 20 (where he could use a 5) or", + "on 19 (where he could use a 6), he can use these rolls for posi-", + "tion 21. A player never has to remove men, but he must make as", + "many moves as possible.", + "", + 0}; + +const char *hits[] = { + "\nHitting Blots:", + "\n Although two men on a position form an impenetrable point, a", + "lone man is not so secure. Such a man is called a 'blot' and has", + "the potential of getting hit by an opposing man. When a player's", + "blot is hit, he is placed on the bar, and the first thing that", + "player must do is move the man off the bar. Such moves are", + "counted as if the bar is one position behind the first position", + "on the board. Thus if red has a man on the bar and rolls 2 3, he", + "must move the man on the bar to position 2 or 3 before moving any", + "other man. If white had points on positions 2 and 3, then red", + "would forfeit his turn. Being on the bar is a very bad position,", + "for often a player can lose many turns trying to move off the", + "bar, as well as being set back the full distance of the board.", + "", + 0}; + +const char *endgame[] = { + "\nEnding the Game and Scoring:", + "\n Winning a game usually wins one point, the normal value of a", + "game. However, if the losing player has not removed any men yet,", + "then the winning player wins double the game value, called a", + "'gammon.' If the losing player has a player on the bar or on the", + "winner's inner table, then the winner gets triple the game value,", + "which is called a 'backgammon.' (So that's where the name comes", + "from!)", + "", + 0}; diff --git a/src/games/backgammon/ttext2.c b/src/games/backgammon/ttext2.c new file mode 100644 index 0000000..84a6122 --- /dev/null +++ b/src/games/backgammon/ttext2.c @@ -0,0 +1,160 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "back.h" + +char *prompt, *opts; +extern const char *list[]; + +const char *doubl[] = { + "\nDoubling:", + "\n If a player thinks he is in a good position, he may double the", + "value of the game. However, his opponent may not accept the pro-", + "posal and forfeit the game before the price gets too high. A", + "player must double before he rolls, and once his double has been", + "accepted, he cannot double again, until his opponent has doubled.", + "Thus, unless the game swings back and forth in advantage between", + "the two players a great deal, the value of the game should be", + "low. At any rate, the value of the game will never go above 64,", + "or six doubles. However, if a player wins a backgammon at 64", + "points, he wins 192 points!", + "", + 0}; + +const char *stragy[] = { + "\nStrategy:", + "\n Some general hints when playing: Try not to leave men open", + "unless absolutely necessary. Also, it is good to make as many", + "points as possible. Often, two men from different positions can", + "be brought together to form a new point. Although walls (six", + "points in a row) are difficult to form, many points nestled close-", + "ly together produce a formidable barrier. Also, while it is good", + "to move back men forward, doing so lessens the opportunity for you", + "to hit men. Finally, remember that once the two player's have", + "passed each other on the board, there is no chance of either team", + "being hit, so the game reduces to a race off the board. Addi-", + "tional hints on strategy are presented in the practice game.", + "", + 0}; + +const char *prog[] = { + "\nThe Program and How It Works:", + "\n A general rule of thumb is when you don't know what to do,", + "type a question mark, and you should get some help. When it is", + "your turn, only your color will be printed out, with nothing", + "after it. You may double by typing a 'd', but if you type a", + "space or newline, you will get your roll. (Remember, you must", + "double before you roll.) Also, typing a 'r' will reprint the", + "board, and a 'q' will quit the game. The program will type", + "'Move:' when it wants your move, and you may indicate each die's", + "move with -, where is the starting position and is", + "the finishing position, or / where is the roll made.", + "-- is short for -,- and / is", + "short for /,/. Moves may be separated by a comma", + "or a space.", + "", + "\n While typing, any input which does not make sense will not be", + "echoed, and a bell will sound instead. Also, backspacing and", + "killing lines will echo differently than normal. You may examine", + "the board by typing a 'r' if you have made a partial move, or be-", + "fore you type a newline, to see what the board looks like. You", + "must end your move with a newline. If you cannot double, your", + "roll will always be printed, and you will not be given the oppor-", + "tunity to double. Home and bar are represented by the appropri-", + "ate number, 0 or 25 as the case may be, or by the letters 'h' or", + "'b' as appropriate. You may also type 'r' or 'q' when the program", + "types 'Move:', which has the same effect as above. Finally, you", + "will get to decide if you want to play red or white (or both if you", + "want to play a friend) at the beginning of the session, and you", + "will not get to change your mind later, since the computer keeps", + "score.", + "", + 0}; + +const char *lastch[] = { + "\nTutorial (Practice Game):", + "\n This tutorial, for simplicity's sake, will let you play one", + "predetermined game. All the rolls have been pre-arranged, and", + "only one response will let you advance to the next move.", + "Although a given roll will may have several legal moves, the tu-", + "torial will only accept one (not including the same moves in a", + "different order), claiming that that move is 'best.' Obviously,", + "a subjective statement. At any rate, be patient with it and have", + "fun learning about backgammon. Also, to speed things up a lit-", + "tle, doubling will not take place in the tutorial, so you will", + "never get that opportunity, and quitting only leaves the tutori-", + "al, not the game. You will still be able to play backgammon", + "after quitting.", + "\n This is your last chance to look over the rules before the tu-", + "torial starts.", + "", + 0}; + +int +text (txt) + const char **txt; +{ + const char *a; + const char *c; + char b; + int i; + + fixtty (noech); + while (*txt) { + a = *(txt++); + if (*a != '\0') { + c = a; + for (i = 0; *(c++) != '\0'; i--); + writel (a); + writec ('\n'); + } else { + fixtty (raw); + writel (prompt); + for (;;) { + b = readc(); + if (b == '?') { + if (tflag) { + if (begscr) { + curmove (18,0); + clend(); + } else + clear(); + } else + writec ('\n'); + text (list); + writel (prompt); + continue; + } + i = 0; + if (b == '\n') + break; + while (i < 11) { + if (b == opts[i]) + break; + i++; + } + if (i == 11) + writec ('\007'); + else + break; + } + if (tflag) { + if (begscr) { + curmove (18,0); + clend(); + } else + clear(); + } else + writec ('\n'); + if (i) + return(i); + fixtty (noech); + if (tflag) + curmove (curr,0); + } + } + fixtty (raw); + return (0); +} diff --git a/src/games/backgammon/tutor.c b/src/games/backgammon/tutor.c new file mode 100644 index 0000000..29e866b --- /dev/null +++ b/src/games/backgammon/tutor.c @@ -0,0 +1,127 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "back.h" +#include "tutor.h" + +extern int maxmoves; +extern char *finis[]; + +extern struct situatn test[]; + +static char better[] = "That is a legal move, but there is a better one.\n"; + +static int +brdeq (b1,b2) + register int *b1, *b2; +{ + register int *e; + + e = b1+26; + while (b1 < e) + if (*b1++ != *b2++) + return(0); + return(1); +} + +static void +clrest () +{ + register int r, c, j; + + r = curr; + c = curc; + for (j = r+1; j < 24; j++) { + curmove (j,0); + cline(); + } + curmove (r,c); +} + +void +tutor () +{ + register int i, j; + + i = 0; + begscr = 18; + cturn = -1; + home = 0; + bar = 25; + inptr = &in[0]; + inopp = &in[1]; + offptr = &off[0]; + offopp = &off[1]; + Colorptr = &color[0]; + colorptr = &color[2]; + colen = 5; + wrboard(); + + while (1) { + if (! brdeq(test[i].brd,board)) { + if (tflag && curr == 23) + curmove (18,0); + writel (better); + nexturn(); + movback (mvlim); + if (tflag) { + refresh(); + clrest (); + } + if ((! tflag) || curr == 19) { + proll(); + writec ('\t'); + } + else + curmove (curr > 19? curr-2: curr+4,25); + getmove(); + if (cturn == 0) + leave(); + continue; + } + if (tflag) + curmove (18,0); + text (test[i].com); + if (! tflag) + writec ('\n'); + if (i == maxmoves) + break; + D0 = test[i].roll1; + D1 = test[i].roll2; + d0 = 0; + mvlim = 0; + for (j = 0; j < 4; j++) { + if (test[i].mp[j] == test[i].mg[j]) + break; + p[j] = test[i].mp[j]; + g[j] = test[i].mg[j]; + mvlim++; + } + if (mvlim) + for (j = 0; j < mvlim; j++) + if (makmove(j)) + writel ("AARGH!!!\n"); + if (tflag) + refresh(); + nexturn(); + D0 = test[i].new1; + D1 = test[i].new2; + d0 = 0; + i++; + mvlim = movallow(); + if (mvlim) { + if (tflag) + clrest(); + proll(); + writec('\t'); + getmove(); + if (tflag) + refresh(); + if (cturn == 0) + leave(); + } + } + leave(); +} diff --git a/src/games/backgammon/tutor.h b/src/games/backgammon/tutor.h new file mode 100644 index 0000000..0a968b7 --- /dev/null +++ b/src/games/backgammon/tutor.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +struct situatn { + int brd[26]; + int roll1; + int roll2; + int mp[4]; + int mg[4]; + int new1; + int new2; + const char **com; +}; diff --git a/src/games/banner.6 b/src/games/banner.6 new file mode 100644 index 0000000..5990a55 --- /dev/null +++ b/src/games/banner.6 @@ -0,0 +1,45 @@ +.\" Copyright (c) 1980 Regents of the University of California. +.\" All rights reserved. The Berkeley software License Agreement +.\" specifies the terms and conditions for redistribution. +.\" +.\" @(#)banner.6 6.2 (Berkeley) 5/6/86 +.\" +.TH BANNER 6 "May 6, 1986" +.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/src/games/banner.c b/src/games/banner.c new file mode 100644 index 0000000..3055925 --- /dev/null +++ b/src/games/banner.c @@ -0,0 +1,923 @@ +/* + * banner - prints large signs + * banner [-w#] [-p@] [-t] message ... + * + * Written by Vadim Antonov, MSU 28.09.1985 + * Ported to RetroBSD by Serge Vakulenko, 2012 + */ +#ifdef CROSS +# include +#else +# include +#endif +#include +#include + +#define MAXMSG 100 /* max chars in message */ +#define DWIDTH 160 /* max output line width */ +#define SPACEW 5 /* space width */ +#define DPUNCH "#" /* symbol to use for printing */ + +struct font_t { + char code; + char glyph [7]; +}; + +int width = DWIDTH; /* -w option: scrunch letters to 80 columns */ +char *punch = DPUNCH; /* -p option: punch symbol, default # */ +int trace; +char line [DWIDTH], *linep; +char message [MAXMSG]; +int nchars; + +/* + * Font 7x7, variable width + */ +#define ROW(a,b,c,d,e,f,g) (a<<6 | b<<5 | c<<4 | d<<3 | e<<2 | f<<1 | g) +#define _ 0 +#define O 1 + +const struct font_t font[] = { + { '0', { + ROW (_,O,O,O,O,O,_), + ROW (O,_,_,_,_,O,O), + ROW (O,_,_,_,O,_,O), + ROW (O,_,_,O,_,_,O), + ROW (O,_,O,_,_,_,O), + ROW (O,O,_,_,_,_,O), + ROW (_,O,O,O,O,O,_), + }}, { '1', { + ROW (_,_,O,_,_,_,_), + ROW (_,O,O,_,_,_,_), + ROW (O,_,O,_,_,_,_), + ROW (_,_,O,_,_,_,_), + ROW (_,_,O,_,_,_,_), + ROW (_,_,O,_,_,_,_), + ROW (_,O,O,O,_,_,_), + }}, { '2', { + ROW (_,O,O,O,O,_,_), + ROW (O,_,_,_,_,O,_), + ROW (_,_,_,_,_,O,_), + ROW (_,_,_,_,O,_,_), + ROW (_,_,O,_,_,_,_), + ROW (_,O,_,_,_,_,_), + ROW (O,O,O,O,O,O,_), + }}, { '3', { + ROW (_,O,O,O,O,_,_), + ROW (O,_,_,_,_,O,_), + ROW (_,_,_,_,_,O,_), + ROW (_,_,_,O,O,_,_), + ROW (_,_,_,_,_,O,_), + ROW (O,_,_,_,_,O,_), + ROW (_,O,O,O,O,_,_), + }}, { '4', { + ROW (_,_,_,_,O,_,_), + ROW (_,_,_,O,O,_,_), + ROW (_,_,O,_,O,_,_), + ROW (_,O,_,_,O,_,_), + ROW (O,O,O,O,O,O,_), + ROW (_,_,_,_,O,_,_), + ROW (_,_,_,_,O,_,_), + }}, { '5', { + ROW (O,O,O,O,O,O,_), + ROW (O,_,_,_,_,_,_), + ROW (O,O,O,O,O,_,_), + ROW (_,_,_,_,_,O,_), + ROW (_,_,_,_,_,O,_), + ROW (O,_,_,_,_,O,_), + ROW (_,O,O,O,O,_,_), + }}, { '6', { + ROW (_,_,_,O,_,_,_), + ROW (_,_,O,_,_,_,_), + ROW (_,O,_,_,_,_,_), + ROW (O,O,O,O,O,_,_), + ROW (O,_,_,_,_,O,_), + ROW (O,_,_,_,_,O,_), + ROW (_,O,O,O,O,_,_), + }}, { '7', { + ROW (O,O,O,O,O,O,_), + ROW (_,_,_,_,_,O,_), + ROW (_,_,_,_,O,_,_), + ROW (_,_,_,O,_,_,_), + ROW (_,_,O,_,_,_,_), + ROW (_,O,_,_,_,_,_), + ROW (_,O,_,_,_,_,_), + }}, { '8', { + ROW (_,O,O,O,O,_,_), + ROW (O,_,_,_,_,O,_), + ROW (O,_,_,_,_,O,_), + ROW (_,O,O,O,O,_,_), + ROW (O,_,_,_,_,O,_), + ROW (O,_,_,_,_,O,_), + ROW (_,O,O,O,O,_,_), + }}, { '9', { + ROW (_,O,O,O,O,_,_), + ROW (O,_,_,_,_,O,_), + ROW (O,_,_,_,_,O,_), + ROW (_,O,O,O,O,O,_), + ROW (_,_,_,_,O,_,_), + ROW (_,_,_,O,_,_,_), + ROW (_,_,O,_,_,_,_), + }}, { ';', { + ROW (_,_,_,_,_,_,_), + ROW (O,O,_,_,_,_,_), + ROW (O,O,_,_,_,_,_), + ROW (_,_,_,_,_,_,_), + ROW (O,O,_,_,_,_,_), + ROW (_,O,_,_,_,_,_), + ROW (O,_,_,_,_,_,_), + }}, { '+', { + ROW (_,_,_,_,_,_,_), + ROW (_,_,_,O,_,_,_), + ROW (_,_,_,O,_,_,_), + ROW (O,O,O,O,O,O,O), + ROW (_,_,_,O,_,_,_), + ROW (_,_,_,O,_,_,_), + ROW (_,_,_,_,_,_,_), + }}, { '!', { + ROW (O,_,_,_,_,_,_), + ROW (O,_,_,_,_,_,_), + ROW (O,_,_,_,_,_,_), + ROW (O,_,_,_,_,_,_), + ROW (O,_,_,_,_,_,_), + ROW (_,_,_,_,_,_,_), + ROW (O,_,_,_,_,_,_), + }}, { '"', { + ROW (O,_,O,_,_,_,_), + ROW (O,_,O,_,_,_,_), + ROW (_,_,_,_,_,_,_), + ROW (_,_,_,_,_,_,_), + ROW (_,_,_,_,_,_,_), + ROW (_,_,_,_,_,_,_), + ROW (_,_,_,_,_,_,_), + }}, { '#', { + ROW (_,_,O,_,O,_,_), + ROW (_,_,O,_,O,_,_), + ROW (O,O,O,O,O,O,O), + ROW (_,_,O,_,O,_,_), + ROW (O,O,O,O,O,O,O), + ROW (_,_,O,_,O,_,_), + ROW (_,_,O,_,O,_,_), + }}, { '$', { + ROW (O,_,_,_,_,O,_), + ROW (_,O,O,O,O,_,_), + ROW (O,_,_,_,_,O,_), + ROW (O,_,_,_,_,O,_), + ROW (O,_,_,_,_,O,_), + ROW (_,O,O,O,O,_,_), + ROW (O,_,_,_,_,O,_), + }}, { '%', { + ROW (_,O,O,_,_,_,O), + ROW (_,O,O,_,_,O,_), + ROW (_,_,_,_,O,_,_), + ROW (_,_,_,O,_,_,_), + ROW (_,_,O,_,_,_,_), + ROW (_,O,_,_,_,O,O), + ROW (O,_,_,_,_,O,O), + }}, { '&', { + ROW (_,_,O,_,_,_,_), + ROW (_,O,_,O,_,_,_), + ROW (_,_,O,_,_,_,_), + ROW (_,O,_,O,_,_,O), + ROW (O,_,_,_,O,O,_), + ROW (O,_,_,_,O,O,_), + ROW (_,O,O,O,_,_,O), + }}, { '\'', { + ROW (_,_,O,_,_,_,_), + ROW (_,O,_,_,_,_,_), + ROW (O,_,_,_,_,_,_), + ROW (_,_,_,_,_,_,_), + ROW (_,_,_,_,_,_,_), + ROW (_,_,_,_,_,_,_), + ROW (_,_,_,_,_,_,_), + }}, { '(', { + ROW (_,_,O,_,_,_,_), + ROW (_,O,_,_,_,_,_), + ROW (O,_,_,_,_,_,_), + ROW (O,_,_,_,_,_,_), + ROW (O,_,_,_,_,_,_), + ROW (_,O,_,_,_,_,_), + ROW (_,_,O,_,_,_,_), + }}, { ')', { + ROW (O,_,_,_,_,_,_), + ROW (_,O,_,_,_,_,_), + ROW (_,_,O,_,_,_,_), + ROW (_,_,O,_,_,_,_), + ROW (_,_,O,_,_,_,_), + ROW (_,O,_,_,_,_,_), + ROW (O,_,_,_,_,_,_), + }}, { '=', { + ROW (_,_,_,_,_,_,_), + ROW (_,_,_,_,_,_,_), + ROW (O,O,O,O,O,O,_), + ROW (_,_,_,_,_,_,_), + ROW (O,O,O,O,O,O,_), + ROW (_,_,_,_,_,_,_), + ROW (_,_,_,_,_,_,_), + }}, { '-', { + ROW (_,_,_,_,_,_,_), + ROW (_,_,_,_,_,_,_), + ROW (_,_,_,_,_,_,_), + ROW (O,O,O,O,O,O,_), + ROW (_,_,_,_,_,_,_), + ROW (_,_,_,_,_,_,_), + ROW (_,_,_,_,_,_,_), + }}, { ':', { + ROW (_,_,_,_,_,_,_), + ROW (O,O,_,_,_,_,_), + ROW (O,O,_,_,_,_,_), + ROW (_,_,_,_,_,_,_), + ROW (O,O,_,_,_,_,_), + ROW (O,O,_,_,_,_,_), + ROW (_,_,_,_,_,_,_), + }}, { '*', { + ROW (_,_,_,_,_,_,_), + ROW (_,O,_,O,_,O,_), + ROW (_,_,O,O,O,_,_), + ROW (O,O,O,O,O,O,O), + ROW (_,_,O,O,O,_,_), + ROW (_,O,_,O,_,O,_), + ROW (_,_,_,_,_,_,_), + }}, { '\\', { + ROW (O,_,_,_,_,_,_), + ROW (_,O,_,_,_,_,_), + ROW (_,_,O,_,_,_,_), + ROW (_,_,_,O,_,_,_), + ROW (_,_,_,_,O,_,_), + ROW (_,_,_,_,_,O,_), + ROW (_,_,_,_,_,_,O), + }}, { '|', { + ROW (O,_,_,_,_,_,_), + ROW (O,_,_,_,_,_,_), + ROW (O,_,_,_,_,_,_), + ROW (O,_,_,_,_,_,_), + ROW (O,_,_,_,_,_,_), + ROW (O,_,_,_,_,_,_), + ROW (O,_,_,_,_,_,_), + }}, { '>', { + ROW (O,_,_,_,_,_,_), + ROW (_,O,_,_,_,_,_), + ROW (_,_,O,_,_,_,_), + ROW (_,_,_,O,_,_,_), + ROW (_,_,O,_,_,_,_), + ROW (_,O,_,_,_,_,_), + ROW (O,_,_,_,_,_,_), + }}, { '<', { + ROW (_,_,_,O,_,_,_), + ROW (_,_,O,_,_,_,_), + ROW (_,O,_,_,_,_,_), + ROW (O,_,_,_,_,_,_), + ROW (_,O,_,_,_,_,_), + ROW (_,_,O,_,_,_,_), + ROW (_,_,_,O,_,_,_), + }}, { '.', { + ROW (_,_,_,_,_,_,_), + ROW (_,_,_,_,_,_,_), + ROW (_,_,_,_,_,_,_), + ROW (_,_,_,_,_,_,_), + ROW (_,_,_,_,_,_,_), + ROW (O,O,_,_,_,_,_), + ROW (O,O,_,_,_,_,_), + }}, { ',', { + ROW (_,_,_,_,_,_,_), + ROW (_,_,_,_,_,_,_), + ROW (_,_,_,_,_,_,_), + ROW (_,_,_,_,_,_,_), + ROW (O,O,_,_,_,_,_), + ROW (_,O,_,_,_,_,_), + ROW (O,_,_,_,_,_,_), + }}, { '_', { + ROW (_,_,_,_,_,_,_), + ROW (_,_,_,_,_,_,_), + ROW (_,_,_,_,_,_,_), + ROW (_,_,_,_,_,_,_), + ROW (_,_,_,_,_,_,_), + ROW (_,_,_,_,_,_,_), + ROW (O,O,O,O,O,O,_), + }}, { '[', { + ROW (O,O,O,O,_,_,_), + ROW (O,_,_,_,_,_,_), + ROW (O,_,_,_,_,_,_), + ROW (O,_,_,_,_,_,_), + ROW (O,_,_,_,_,_,_), + ROW (O,_,_,_,_,_,_), + ROW (O,O,O,O,_,_,_), + }}, { ']', { + ROW (O,O,O,O,_,_,_), + ROW (_,_,_,O,_,_,_), + ROW (_,_,_,O,_,_,_), + ROW (_,_,_,O,_,_,_), + ROW (_,_,_,O,_,_,_), + ROW (_,_,_,O,_,_,_), + ROW (O,O,O,O,_,_,_), + }}, { '{', { + ROW (_,_,O,_,_,_,_), + ROW (_,O,_,_,_,_,_), + ROW (_,O,_,_,_,_,_), + ROW (O,_,_,_,_,_,_), + ROW (_,O,_,_,_,_,_), + ROW (_,O,_,_,_,_,_), + ROW (_,_,O,_,_,_,_), + }}, { '}', { + ROW (O,_,_,_,_,_,_), + ROW (_,O,_,_,_,_,_), + ROW (_,O,_,_,_,_,_), + ROW (_,_,O,_,_,_,_), + ROW (_,O,_,_,_,_,_), + ROW (_,O,_,_,_,_,_), + ROW (O,_,_,_,_,_,_), + }}, { '/', { + ROW (_,_,_,_,_,_,O), + ROW (_,_,_,_,_,O,_), + ROW (_,_,_,_,O,_,_), + ROW (_,_,_,O,_,_,_), + ROW (_,_,O,_,_,_,_), + ROW (_,O,_,_,_,_,_), + ROW (O,_,_,_,_,_,_), + }}, { '?', { + ROW (_,O,O,O,O,_,_), + ROW (O,_,_,_,_,O,_), + ROW (_,_,_,_,_,O,_), + ROW (_,_,_,_,O,_,_), + ROW (_,_,_,O,_,_,_), + ROW (_,_,_,_,_,_,_), + ROW (_,_,_,O,_,_,_), + }}, { '^', { + ROW (_,_,_,_,_,_,_), + ROW (_,_,_,_,_,_,_), + ROW (O,O,O,O,O,O,_), + ROW (_,_,_,_,_,O,_), + ROW (_,_,_,_,_,O,_), + ROW (_,_,_,_,_,_,_), + ROW (_,_,_,_,_,_,_), + }}, { '~', { + ROW (O,O,O,O,O,O,_), + ROW (_,_,_,_,_,_,_), + ROW (_,_,_,_,_,_,_), + ROW (_,_,_,_,_,_,_), + ROW (_,_,_,_,_,_,_), + ROW (_,_,_,_,_,_,_), + ROW (_,_,_,_,_,_,_), + }}, { '@', { + ROW (_,O,O,O,O,_,_), + ROW (O,_,_,_,_,O,_), + ROW (_,_,_,_,_,O,_), + ROW (_,O,O,_,_,O,_), + ROW (O,_,_,O,_,O,_), + ROW (O,_,_,O,_,O,_), + ROW (_,O,O,_,O,_,_), + }}, { '`', { + ROW (O,_,_,_,_,_,_), + ROW (_,O,_,_,_,_,_), + ROW (_,_,O,_,_,_,_), + ROW (_,_,_,_,_,_,_), + ROW (_,_,_,_,_,_,_), + ROW (_,_,_,_,_,_,_), + ROW (_,_,_,_,_,_,_), + }}, { 'A', { + ROW (_,_,_,O,_,_,_), + ROW (_,_,O,_,O,_,_), + ROW (_,O,_,_,_,O,_), + ROW (O,_,_,_,_,_,O), + ROW (O,O,O,O,O,O,O), + ROW (O,_,_,_,_,_,O), + ROW (O,_,_,_,_,_,O), + }}, { 'a', { + ROW (_,_,_,_,_,_,_), + ROW (_,_,_,_,_,_,_), + ROW (_,O,O,O,O,_,_), + ROW (O,_,_,_,O,_,_), + ROW (O,_,_,_,O,_,_), + ROW (O,_,_,_,O,_,_), + ROW (_,O,O,O,_,O,_), + }}, { 'B', { + ROW (O,O,O,O,O,_,_), + ROW (O,_,_,_,_,O,_), + ROW (O,_,_,_,_,O,_), + ROW (O,O,O,O,O,_,_), + ROW (O,_,_,_,_,O,_), + ROW (O,_,_,_,_,O,_), + ROW (O,O,O,O,O,_,_), + }}, { 'b', { + ROW (_,_,_,_,_,_,_), + ROW (O,_,_,_,_,_,_), + ROW (O,_,_,_,_,_,_), + ROW (O,O,O,O,_,_,_), + ROW (O,_,_,_,O,_,_), + ROW (O,_,_,_,O,_,_), + ROW (O,O,O,O,_,_,_), + }}, { 'C', { + ROW (_,O,O,O,O,_,_), + ROW (O,_,_,_,_,O,_), + ROW (O,_,_,_,_,_,_), + ROW (O,_,_,_,_,_,_), + ROW (O,_,_,_,_,_,_), + ROW (O,_,_,_,_,O,_), + ROW (_,O,O,O,O,_,_), + }}, { 'c', { + ROW (_,_,_,_,_,_,_), + ROW (_,_,_,_,_,_,_), + ROW (_,O,O,O,O,_,_), + ROW (O,_,_,_,_,_,_), + ROW (O,_,_,_,_,_,_), + ROW (O,_,_,_,_,_,_), + ROW (_,O,O,O,O,_,_), + }}, { 'D', { + ROW (O,O,O,O,_,_,_), + ROW (O,_,_,_,O,_,_), + ROW (O,_,_,_,_,O,_), + ROW (O,_,_,_,_,O,_), + ROW (O,_,_,_,_,O,_), + ROW (O,_,_,_,O,_,_), + ROW (O,O,O,O,_,_,_), + }}, { 'd', { + ROW (_,_,_,_,_,_,_), + ROW (_,_,_,_,O,_,_), + ROW (_,_,_,_,O,_,_), + ROW (_,O,O,O,O,_,_), + ROW (O,_,_,_,O,_,_), + ROW (O,_,_,_,O,_,_), + ROW (_,O,O,O,O,_,_), + }}, { 'E', { + ROW (O,O,O,O,O,O,_), + ROW (O,_,_,_,_,_,_), + ROW (O,_,_,_,_,_,_), + ROW (O,O,O,O,_,_,_), + ROW (O,_,_,_,_,_,_), + ROW (O,_,_,_,_,_,_), + ROW (O,O,O,O,O,O,_), + }}, { 'e', { + ROW (_,_,_,_,_,_,_), + ROW (_,_,_,_,_,_,_), + ROW (_,O,O,O,_,_,_), + ROW (O,_,_,_,O,_,_), + ROW (O,O,O,O,_,_,_), + ROW (O,_,_,_,_,_,_), + ROW (_,O,O,O,_,_,_), + }}, { 'F', { + ROW (O,O,O,O,O,O,_), + ROW (O,_,_,_,_,_,_), + ROW (O,_,_,_,_,_,_), + ROW (O,O,O,O,_,_,_), + ROW (O,_,_,_,_,_,_), + ROW (O,_,_,_,_,_,_), + ROW (O,_,_,_,_,_,_), + }}, { 'f', { + ROW (_,_,_,_,_,_,_), + ROW (_,_,O,_,_,_,_), + ROW (_,O,_,_,_,_,_), + ROW (O,O,O,_,_,_,_), + ROW (_,O,_,_,_,_,_), + ROW (_,O,_,_,_,_,_), + ROW (_,O,_,_,_,_,_), + }}, { 'G', { + ROW (_,O,O,O,O,_,_), + ROW (O,_,_,_,_,O,_), + ROW (O,_,_,_,_,_,_), + ROW (O,_,_,_,_,_,_), + ROW (O,_,_,_,O,O,_), + ROW (O,_,_,_,_,O,_), + ROW (_,O,O,O,O,O,_), + }}, { 'g', { + ROW (_,_,_,_,_,_,_), + ROW (_,_,_,_,O,_,_), + ROW (_,O,O,O,_,_,_), + ROW (O,_,_,_,O,_,_), + ROW (_,O,O,O,_,_,_), + ROW (_,_,_,_,O,_,_), + ROW (_,O,O,O,_,_,_), + }}, { 'H', { + ROW (O,_,_,_,_,O,_), + ROW (O,_,_,_,_,O,_), + ROW (O,_,_,_,_,O,_), + ROW (O,O,O,O,O,O,_), + ROW (O,_,_,_,_,O,_), + ROW (O,_,_,_,_,O,_), + ROW (O,_,_,_,_,O,_), + }}, { 'h', { + ROW (_,_,_,_,_,_,_), + ROW (O,_,_,_,_,_,_), + ROW (O,_,_,_,_,_,_), + ROW (O,O,O,O,_,_,_), + ROW (O,_,_,_,O,_,_), + ROW (O,_,_,_,O,_,_), + ROW (O,_,_,_,O,_,_), + }}, { 'I', { + ROW (O,O,O,_,_,_,_), + ROW (_,O,_,_,_,_,_), + ROW (_,O,_,_,_,_,_), + ROW (_,O,_,_,_,_,_), + ROW (_,O,_,_,_,_,_), + ROW (_,O,_,_,_,_,_), + ROW (O,O,O,_,_,_,_), + }}, { 'i', { + ROW (_,_,_,_,_,_,_), + ROW (O,_,_,_,_,_,_), + ROW (_,_,_,_,_,_,_), + ROW (O,_,_,_,_,_,_), + ROW (O,_,_,_,_,_,_), + ROW (O,_,_,_,_,_,_), + ROW (_,O,_,_,_,_,_), + }}, { 'J', { + ROW (_,_,O,O,O,_,_), + ROW (_,_,_,O,_,_,_), + ROW (_,_,_,O,_,_,_), + ROW (_,_,_,O,_,_,_), + ROW (_,_,_,O,_,_,_), + ROW (O,_,_,O,_,_,_), + ROW (_,O,O,_,_,_,_), + }}, { 'j', { + ROW (_,_,_,_,_,_,_), + ROW (_,_,O,_,_,_,_), + ROW (_,_,_,_,_,_,_), + ROW (_,_,O,_,_,_,_), + ROW (_,_,O,_,_,_,_), + ROW (O,_,O,_,_,_,_), + ROW (_,O,_,_,_,_,_), + }}, { 'K', { + ROW (O,_,_,_,O,_,_), + ROW (O,_,_,O,_,_,_), + ROW (O,_,O,_,_,_,_), + ROW (O,O,_,_,_,_,_), + ROW (O,_,O,_,_,_,_), + ROW (O,_,_,O,_,_,_), + ROW (O,_,_,_,O,_,_), + }}, { 'k', { + ROW (_,_,_,_,_,_,_), + ROW (O,_,_,_,_,_,_), + ROW (O,_,_,O,_,_,_), + ROW (O,_,O,_,_,_,_), + ROW (O,O,_,_,_,_,_), + ROW (O,_,O,_,_,_,_), + ROW (O,_,_,O,_,_,_), + }}, { 'L', { + ROW (O,_,_,_,_,_,_), + ROW (O,_,_,_,_,_,_), + ROW (O,_,_,_,_,_,_), + ROW (O,_,_,_,_,_,_), + ROW (O,_,_,_,_,_,_), + ROW (O,_,_,_,_,_,_), + ROW (O,O,O,O,O,O,_), + }}, { 'l', { + ROW (_,O,_,_,_,_,_), + ROW (O,O,_,_,_,_,_), + ROW (_,O,_,_,_,_,_), + ROW (_,O,_,_,_,_,_), + ROW (_,O,_,_,_,_,_), + ROW (_,O,_,_,_,_,_), + ROW (_,O,_,_,_,_,_), + }}, { 'M', { + ROW (O,_,_,_,_,_,O), + ROW (O,O,_,_,_,O,O), + ROW (O,_,O,_,O,_,O), + ROW (O,_,_,O,_,_,O), + ROW (O,_,_,_,_,_,O), + ROW (O,_,_,_,_,_,O), + ROW (O,_,_,_,_,_,O), + }}, { 'm', { + ROW (_,_,_,_,_,_,_), + ROW (_,_,_,_,_,_,_), + ROW (O,O,_,O,_,_,_), + ROW (O,_,O,_,O,_,_), + ROW (O,_,O,_,O,_,_), + ROW (O,_,O,_,O,_,_), + ROW (O,_,O,_,O,_,_), + }}, { 'N', { + ROW (O,_,_,_,_,O,_), + ROW (O,_,_,_,_,O,_), + ROW (O,O,_,_,_,O,_), + ROW (O,_,O,_,_,O,_), + ROW (O,_,_,O,_,O,_), + ROW (O,_,_,_,O,O,_), + ROW (O,_,_,_,_,O,_), + }}, { 'n', { + ROW (_,_,_,_,_,_,_), + ROW (_,_,_,_,_,_,_), + ROW (O,_,O,O,_,_,_), + ROW (O,O,_,_,O,_,_), + ROW (O,_,_,_,O,_,_), + ROW (O,_,_,_,O,_,_), + ROW (O,_,_,_,O,_,_), + }}, { 'O', { + ROW (_,O,O,O,O,_,_), + ROW (O,_,_,_,_,O,_), + ROW (O,_,_,_,_,O,_), + ROW (O,_,_,_,_,O,_), + ROW (O,_,_,_,_,O,_), + ROW (O,_,_,_,_,O,_), + ROW (_,O,O,O,O,_,_), + }}, { 'o', { + ROW (_,_,_,_,_,_,_), + ROW (_,_,_,_,_,_,_), + ROW (_,O,O,O,_,_,_), + ROW (O,_,_,_,O,_,_), + ROW (O,_,_,_,O,_,_), + ROW (O,_,_,_,O,_,_), + ROW (_,O,O,O,_,_,_), + }}, { 'P', { + ROW (O,O,O,O,O,_,_), + ROW (O,_,_,_,_,O,_), + ROW (O,_,_,_,_,O,_), + ROW (O,O,O,O,O,_,_), + ROW (O,_,_,_,_,_,_), + ROW (O,_,_,_,_,_,_), + ROW (O,_,_,_,_,_,_), + }}, { 'p', { + ROW (_,_,_,_,_,_,_), + ROW (_,_,_,_,_,_,_), + ROW (O,O,O,O,_,_,_), + ROW (O,_,_,_,O,_,_), + ROW (O,O,O,O,_,_,_), + ROW (O,_,_,_,_,_,_), + ROW (O,_,_,_,_,_,_), + }}, { 'Q', { + ROW (_,O,O,O,O,_,_), + ROW (O,_,_,_,_,O,_), + ROW (O,_,_,_,_,O,_), + ROW (O,_,_,_,_,O,_), + ROW (O,_,_,O,_,O,_), + ROW (O,_,_,_,O,_,_), + ROW (_,O,O,O,_,O,_), + }}, { 'q', { + ROW (_,_,_,_,_,_,_), + ROW (_,_,_,_,_,_,_), + ROW (_,O,O,_,_,_,_), + ROW (O,_,_,O,_,_,_), + ROW (O,_,_,O,_,_,_), + ROW (_,O,O,O,_,_,_), + ROW (_,_,_,O,_,_,_), + }}, { 'R', { + ROW (O,O,O,O,O,_,_), + ROW (O,_,_,_,_,O,_), + ROW (O,_,_,_,_,O,_), + ROW (O,O,O,O,O,_,_), + ROW (O,_,_,O,_,_,_), + ROW (O,_,_,_,O,_,_), + ROW (O,_,_,_,_,O,_), + }}, { 'r', { + ROW (_,_,_,_,_,_,_), + ROW (_,_,_,_,_,_,_), + ROW (O,_,O,O,_,_,_), + ROW (O,O,_,_,O,_,_), + ROW (O,_,_,_,_,_,_), + ROW (O,_,_,_,_,_,_), + ROW (O,_,_,_,_,_,_), + }}, { 'S', { + ROW (_,O,O,O,O,_,_), + ROW (O,_,_,_,_,O,_), + ROW (O,_,_,_,_,_,_), + ROW (_,O,O,O,O,_,_), + ROW (_,_,_,_,_,O,_), + ROW (O,_,_,_,_,O,_), + ROW (_,O,O,O,O,_,_), + }}, { 's', { + ROW (_,_,_,_,_,_,_), + ROW (_,_,_,_,_,_,_), + ROW (_,O,O,O,O,_,_), + ROW (O,_,_,_,_,_,_), + ROW (_,O,O,O,_,_,_), + ROW (_,_,_,_,O,_,_), + ROW (O,O,O,O,_,_,_), + }}, { 'T', { + ROW (O,O,O,O,O,O,O), + ROW (_,_,_,O,_,_,_), + ROW (_,_,_,O,_,_,_), + ROW (_,_,_,O,_,_,_), + ROW (_,_,_,O,_,_,_), + ROW (_,_,_,O,_,_,_), + ROW (_,_,_,O,_,_,_), + }}, { 't', { + ROW (_,_,_,_,_,_,_), + ROW (_,O,_,_,_,_,_), + ROW (O,O,O,_,_,_,_), + ROW (_,O,_,_,_,_,_), + ROW (_,O,_,_,_,_,_), + ROW (_,O,_,_,_,_,_), + ROW (_,_,O,_,_,_,_), + }}, { 'U', { + ROW (O,_,_,_,_,O,_), + ROW (O,_,_,_,_,O,_), + ROW (O,_,_,_,_,O,_), + ROW (O,_,_,_,_,O,_), + ROW (O,_,_,_,_,O,_), + ROW (O,_,_,_,_,O,_), + ROW (_,O,O,O,O,_,_), + }}, { 'u', { + ROW (_,_,_,_,_,_,_), + ROW (_,_,_,_,_,_,_), + ROW (O,_,_,_,O,_,_), + ROW (O,_,_,_,O,_,_), + ROW (O,_,_,_,O,_,_), + ROW (O,_,_,_,O,_,_), + ROW (_,O,O,O,_,O,_), + }}, { 'V', { + ROW (O,_,_,_,_,_,O), + ROW (O,_,_,_,_,_,O), + ROW (O,_,_,_,_,_,O), + ROW (O,_,_,_,_,_,O), + ROW (_,O,_,_,_,O,_), + ROW (_,_,O,_,O,_,_), + ROW (_,_,_,O,_,_,_), + }}, { 'v', { + ROW (_,_,_,_,_,_,_), + ROW (_,_,_,_,_,_,_), + ROW (O,_,_,_,O,_,_), + ROW (O,_,_,_,O,_,_), + ROW (O,_,_,_,O,_,_), + ROW (_,O,_,O,_,_,_), + ROW (_,_,O,_,_,_,_), + }}, { 'W', { + ROW (O,_,_,_,_,_,O), + ROW (O,_,_,_,_,_,O), + ROW (O,_,_,_,_,_,O), + ROW (O,_,_,_,_,_,O), + ROW (O,_,_,O,_,_,O), + ROW (O,_,O,_,O,_,O), + ROW (_,O,_,_,_,O,_), + }}, { 'w', { + ROW (_,_,_,_,_,_,_), + ROW (_,_,_,_,_,_,_), + ROW (O,_,_,_,O,_,_), + ROW (O,_,_,_,O,_,_), + ROW (O,_,O,_,O,_,_), + ROW (O,_,O,_,O,_,_), + ROW (_,O,_,O,_,_,_), + }}, { 'X', { + ROW (O,_,_,_,_,_,O), + ROW (_,O,_,_,_,O,_), + ROW (_,_,O,_,O,_,_), + ROW (_,_,_,O,_,_,_), + ROW (_,_,O,_,O,_,_), + ROW (_,O,_,_,_,O,_), + ROW (O,_,_,_,_,_,O), + }}, { 'x', { + ROW (_,_,_,_,_,_,_), + ROW (_,_,_,_,_,_,_), + ROW (O,_,_,_,O,_,_), + ROW (_,O,_,O,_,_,_), + ROW (_,_,O,_,_,_,_), + ROW (_,O,_,O,_,_,_), + ROW (O,_,_,_,O,_,_), + }}, { 'Y', { + ROW (O,_,_,_,_,_,O), + ROW (O,_,_,_,_,_,O), + ROW (_,O,_,_,_,O,_), + ROW (_,_,O,_,O,_,_), + ROW (_,_,_,O,_,_,_), + ROW (_,_,_,O,_,_,_), + ROW (_,_,_,O,_,_,_), + }}, { 'y', { + ROW (_,_,_,_,_,_,_), + ROW (_,_,_,_,_,_,_), + ROW (O,_,_,_,O,_,_), + ROW (O,_,_,_,O,_,_), + ROW (_,O,_,O,_,_,_), + ROW (_,_,O,_,_,_,_), + ROW (_,_,O,_,_,_,_), + }}, { 'Z', { + ROW (O,O,O,O,O,O,O), + ROW (_,_,_,_,_,O,_), + ROW (_,_,_,_,O,_,_), + ROW (_,_,_,O,_,_,_), + ROW (_,_,O,_,_,_,_), + ROW (_,O,_,_,_,_,_), + ROW (O,O,O,O,O,O,O), + }}, { 'z', { + ROW (_,_,_,_,_,_,_), + ROW (_,_,_,_,_,_,_), + ROW (O,O,O,O,O,_,_), + ROW (_,_,_,O,_,_,_), + ROW (_,_,O,_,_,_,_), + ROW (_,O,_,_,_,_,_), + ROW (O,O,O,O,O,_,_), + }}, +}; + +/* + * Draw a symbol + */ +int setchar (linep, glyph) + char *linep; + char glyph[7]; +{ + register int mask, w, c, morebits; + + w = 0; + morebits = glyph[0] | glyph[1] | glyph[2] | glyph[3] | + glyph[4] | glyph[5] | glyph[6]; + for (mask = 0x80; morebits && mask != 0; mask >>= 1) { + c = 0; + if (glyph[0] & mask) + c |= 0x01; + if (glyph[1] & mask) + c |= 0x02; + if (glyph[2] & mask) + c |= 0x04; + if (glyph[3] & mask) + c |= 0x08; + if (glyph[4] & mask) + c |= 0x10; + if (glyph[5] & mask) + c |= 0x20; + if (glyph[6] & mask) + c |= 0x40; + *linep++ = c; + w++; + morebits &= ~mask; + } + return w; +} + +int main (argc, argv) + int argc; + char **argv; +{ + int i, j; + + if (argc > 1 && argv[1][0] == '-') { + switch(argv[1][1]) { + case 'w': + width = atoi(&argv[1][2]); + if (width == 0) + width = 80; + break; + case 'p': + punch = &argv[1][2]; + if (*punch == 0) + punch = DPUNCH; + break; + case 't': + trace++; + break; + default: + printf("bad switch %s\n",argv[1]); + break; + } + argc--; + argv++; + } + + /* Have now read in the data. Next get the message to be printed. */ + if (argc > 1) { + strcpy(message, argv[1]); + for (i=2; i= line + width) + break; + if (trace) + printf("Char #%d: %c\n", i, c); + if (c == ' ') { + linep += SPACEW; + continue; + } + for (f=font; f->code!=0; f++) { + if (f->code == c) { + linep += setchar (linep, f->glyph) + 1; + break; + } + } + } + + /* + * Print the resulting image. + */ + for (i = 1; i < 0200 ; i <<= 1) { + char *limit = &line[width-1]; + while (! (*limit & i)) + limit--; + for (linep = line; linep <= limit; linep++) { + if (*linep & i) + fputs (punch, stdout); + else + putchar (' '); + } + putchar ('\n'); + } + + exit(0); +} diff --git a/src/games/battlestar/Makefile b/src/games/battlestar/Makefile new file mode 100644 index 0000000..015edfa --- /dev/null +++ b/src/games/battlestar/Makefile @@ -0,0 +1,43 @@ +# +# Copyright (c) 1983 Regents of the University of California, +# All rights reserved. Redistribution permitted subject to +# the terms of the Berkeley Software License Agreement. +# +TOPSRC = $(shell cd ../../..; pwd) +include $(TOPSRC)/target.mk +#include $(TOPSRC)/cross.mk + +CFLAGS += -Os -DUNIX_BSD4_2 -DANSI -DEXT_MESSAGE_FILE -Werror -Wall -mips16 + +OBJS = battlestar.o cmd1.o cmd2.o cmd3.o cmd4.o cmd5.o cmd6.o cmd7.o \ + init.o cypher.o getcom.o parse.o room.o save.o fly.o misc.o \ + _globals.o _dayfile.o _nightfile.o dayobjs.o nightobjs.o words.o \ + curses.o doprnt.o +LIBS = +MAN = battlestar.0 +MANSRC = battlestar.6 + +all: battle_strings battlestar $(MAN) + +battlestar: ${OBJS} + ${CC} ${LDFLAGS} -o battlestar.elf ${OBJS} ${LIBS} + ${OBJDUMP} -S battlestar.elf > battlestar.dis + ${SIZE} battlestar.elf + ${ELF2AOUT} battlestar.elf $@ && rm battlestar.elf + +battle_strings _globals.c _dayfile.c _nightfile.c: mkstr globals.c dayfile.c nightfile.c + ./mkstr battle_strings _ globals.c dayfile.c nightfile.c + +mkstr: mkstr.c + cc -O $< -o $@ + +${MAN}: ${MANSRC} + ${MANROFF} $< > $@ + +clean: + rm -f *.o *.0 *.elf ${MAN} battlestar mkstr *.elf *.dis tags *~ battle_strings _globals.c _dayfile.c _nightfile.c + +install: all + install battlestar $(DESTDIR)/games/ + cp battle_strings $(DESTDIR)/games/lib/ + cp ${MAN} $(DESTDIR)/share/man/cat6/ diff --git a/src/games/battlestar/Makefile-linux b/src/games/battlestar/Makefile-linux new file mode 100644 index 0000000..fdf4740 --- /dev/null +++ b/src/games/battlestar/Makefile-linux @@ -0,0 +1,23 @@ +# +# Copyright (c) 1983 Regents of the University of California, +# All rights reserved. Redistribution permitted subject to +# the terms of the Berkeley Software License Agreement. +# + +CFLAGS += -g -O -DEXT_MESSAGE_FILE -Werror -Wall + +OBJS = battlestar.o cmd1.o cmd2.o cmd3.o cmd4.o cmd5.o cmd6.o cmd7.o \ + init.o cypher.o getcom.o parse.o room.o save.o fly.o misc.o \ + _globals.o _dayfile.o _nightfile.o dayobjs.o nightobjs.o words.o +LIBS = -lncurses + +all: battle_strings battlestar + +battlestar: ${OBJS} + ${CC} ${LDFLAGS} -o $@ ${OBJS} ${LIBS} + +battle_strings _globals.c _dayfile.c _nightfile.c: mkstr globals.c dayfile.c nightfile.c + ./mkstr battle_strings _ globals.c dayfile.c nightfile.c + +clean: + rm -f *.o battlestar mkstr *~ battle_strings _globals.c _dayfile.c _nightfile.c diff --git a/src/games/battlestar/battlestar.6 b/src/games/battlestar/battlestar.6 new file mode 100644 index 0000000..95da1c6 --- /dev/null +++ b/src/games/battlestar/battlestar.6 @@ -0,0 +1,140 @@ +.\" +.\" Copyright (c) 1983 Regents of the University of California, +.\" All rights reserved. Redistribution permitted subject to +.\" the terms of the Berkeley Software License Agreement. +.\" + +.\" @(#)battlestar.6 1.2 4/24/85 + +.TH BATTLESTAR 6 +.UC 4 +.SH NAME +battlestar \- a tropical adventure game +.SH SYNOPSIS +.B battlestar +[ +.B -r (recover a saved game) +] +.br +.fi +.SH DESCRIPTION +.I Battlestar +is an adventure game in the classic style. However, It's slightly less +of a +puzzle and more a game of exploration. There are a few magical words +in the game, but on the whole, simple English +should suffice to make one's desires understandable to the parser. +.SH "THE SETTING" +In the days before the darkness came, when battlestars ruled the +heavens... +.br +.nf + + Three He made and gave them to His daughters, + Beautiful nymphs, the goddesses of the waters. + One to bring good luck and simple feats of wonder, + Two to wash the lands and churn the waves asunder, + Three to rule the world and purge the skies with thunder. + +.fi +.PP +In those times great wizards were known and their powers were beyond +belief. They could take any object from thin air, and, uttering the +word +'su,' could disappear. +.PP +In those times men were known for their lust of gold and desire to +wear fine weapons. Swords and coats of mail were fashioned that could +withstand a laser blast. +.PP +But when the darkness fell, the rightful reigns were toppled. Swords +and helms and heads of state went rolling across the grass. The entire +fleet of battlestars was reduced to a single ship. +.SH "SAMPLE COMMANDS" +.nf + + take --- take an object + drop --- drop an object + + wear --- wear an object you are holding + draw --- carry an object you are wearing + + puton --- take an object and wear it + take off -- draw an object and drop it + + throw + + ! + +.fi +.SH "IMPLIED OBJECTS" +.nf + + >-: take watermellon + watermellon: + Taken. + >-: eat + watermellon: + Eaten. + >-: take knife and sword and apple, drop all + knife: + Taken. + broadsword: + Taken. + apple: + Taken. + knife: + Dropped. + broadsword: + Dropped. + apple: + Dropped. + >-: get + knife: + Taken. + +.fi +.PP +Notice that the "shadow" of the next word stays around if you +want to take advantage of it. That is, saying "take knife" and then +"drop" +will drop the knife you just took. +.SH "SCORE & INVEN" +The two commands "score" and "inven" will print out your current status +in +the game. +.SH "SAVING A GAME" +The command "save" will save your game in a file called "Bstar." You +can +recover a saved game by using the "-r" option when you start up the +game. +.SH DIRECTIONS +The compass directions N, S, E, and W can be used if you have a compass. +If you don't have a compass, you'll have to say R, L, A, or B, which +stand for +Right, Left, Ahead, and Back. Directions printed in room descriptions +are +always printed in R, L, A, & B relative directions. +.SH HISTORY +I wrote Battlestar in 1979 in order to experiment with the niceties of +the C Language. +Most interesting things that happen in the game are hardwired into the +code, so don't +send me any hate mail about it! Instead, enjoy art for art's sake! +.SH AUTHOR +David Riggle +.SH "INSPIRATION & ASSISTANCE" +Chris Guthrie +.br +Peter Da Silva +.br +Kevin Brown +.br +Edward Wang +.br +Ken Arnold & Company +.SH BUGS +Countless. +.SH "FAN MAIL" +Send to edward%ucbarpa@Berkeley.arpa, chris%ucbcory@berkeley.arpa, +riggle.pa@xerox.arpa. diff --git a/src/games/battlestar/battlestar.c b/src/games/battlestar/battlestar.c new file mode 100644 index 0000000..e877d38 --- /dev/null +++ b/src/games/battlestar/battlestar.c @@ -0,0 +1,59 @@ +/* + * Copyright (c) 1983 Regents of the University of California, + * All rights reserved. Redistribution permitted subject to + * the terms of the Berkeley Software License Agreement. + */ + +/* + * Battlestar - a stellar-tropical adventure game + * + * Originally written by His Lordship, Admiral David W. Horatio Riggle, + * on the Cory PDP-11/70, University of California, Berkeley. + */ + +#include "externs.h" +int +main(argc,argv) + int argc; + char **argv; +{ + char mainbuf[LINELENGTH]; + char instackbuf[BUFSIZ]; + char outstackbuf[BUFSIZ]; + char *next; + + setbuf(stdin, instackbuf); + setbuf(stdout, outstackbuf); + setlinebuf(stdout); + initialize(argc < 2 || strcmp(argv[1], "-r")); +start: + news(); + beenthere[position]++; + if (notes[LAUNCHED]) + crash(); /* decrements fuel & crash */ + if (matchlight) { + puts("Your match splutters out."); + matchlight = 0; + } + if (!notes[CANTSEE] || testbit(inven,LAMPON) || + testbit(location[position].objects, LAMPON)) { + writedes(); + printobjs(); + } else + puts("It's too dark to see anything in here!"); + whichway(location[position]); +run: + next = getcom(mainbuf, sizeof mainbuf, ">-: ", + "Please type in something."); + for (wordcount = 0; next && wordcount < 20; wordcount++) + next = getword(next, words[wordcount], -1); + parse(); + switch (cypher()) { + case -1: + goto run; + case 0: + goto start; + default: + exit(0); + } +} diff --git a/src/games/battlestar/cmd1.c b/src/games/battlestar/cmd1.c new file mode 100644 index 0000000..40f168e --- /dev/null +++ b/src/games/battlestar/cmd1.c @@ -0,0 +1,236 @@ +/* + * Copyright (c) 1983 Regents of the University of California, + * All rights reserved. Redistribution permitted subject to + * the terms of the Berkeley Software License Agreement. + */ +#include "externs.h" + +int +move(thataway, token) + int thataway, token; +{ + wordnumber++; + if ((!notes[CANTMOVE] && !notes[LAUNCHED]) || + testbit(location[position].objects, LAND) || + (fuel > 0 && notes[LAUNCHED])) + if (thataway) { + position = thataway; + newway(token); + Time++; + } + else { + puts("You can't go this way."); + newway(token); + whichway(location[position]); + return(0); + } + else if (notes[CANTMOVE] && !notes[LAUNCHED]) + puts("You aren't able to move; you better drop something."); + else + puts("You are out of fuel; now you will rot in space forever!"); + return(1); +} + +void +convert(tothis) /* Converts day to night and vice versa. */ + int tothis; /* Day objects are permanent. Night objects are added*/ +{ /* at dusk, and subtracted at dawn. */ + register struct objs *p; + register int i, j; + + if (tothis == TONIGHT) { + for (i = 1; i <= NUMOFROOMS; i++) + for (j = 0; j < NUMOFWORDS; j++) + nightfile[i].objects[j] = dayfile[i].objects[j]; + for (p = nightobjs; p->room != 0; p++) + setbit(nightfile[p->room].objects, p->obj); + location = nightfile; + } else { + for (i = 1; i <= NUMOFROOMS; i++) + for (j = 0; j < NUMOFWORDS; j++) + dayfile[i].objects[j] = nightfile[i].objects[j]; + for (p = nightobjs; p->room != 0; p++) + clearbit(dayfile[p->room].objects, p->obj); + location = dayfile; + } +} + +void +news() +{ + register int n; + int hurt; + + if (Time > 30 && position < 32){ + puts("An explosion of shuddering magnitude splinters bulkheads and"); + puts("ruptures the battlestar's hull. You are sucked out into the"); + puts("frozen void of space and killed."); + die(0); + } + if (Time > 20 && position < 32) + puts("Explosions rock the battlestar."); + if (Time > snooze){ + puts("You drop from exhaustion..."); + zzz(); + } + if (Time > snooze - 5) + puts("You're getting tired."); + if (Time > (rythmn + CYCLE)) { + if (location == nightfile) { + convert(TODAY); + if (OUTSIDE && Time - rythmn - CYCLE < 10) { + puts("Dew lit sunbeams stretch out from a watery sunrise and herald the dawn."); + puts("You awake from a misty dream-world into stark reality."); + puts("It is day."); + } + } else { + convert(TONIGHT); + clearbit(location[POOLS].objects, BATHGOD); + if (OUTSIDE && Time - rythmn - CYCLE < 10) { + puts("The dying sun sinks into the ocean, leaving a blood stained sunset."); + puts("The sky slowly fades from orange to violet to black. A few stars"); + puts("flicker on, and it is night."); + puts("The world seems completly different at night."); + } + } + rythmn = Time - Time % CYCLE; + } + if (!wiz && !tempwiz) + if ((testbit(inven,TALISMAN) || testbit(wear,TALISMAN)) && (testbit(inven,MEDALION) || testbit(wear,MEDALION)) && (testbit(inven,AMULET) || testbit(wear,AMULET))){ + tempwiz = 1; + puts("The three amulets glow and reenforce each other in power.\nYou are now a wizard."); + } + if (testbit(location[position].objects,ELF)){ +#ifdef EXT_MESSAGE_FILE + strprt(ELF); +#else + printf("%s\n",objdes[ELF]); +#endif + fight(ELF,rnd(30)); + } + if (testbit(location[position].objects,DARK)){ +#ifdef EXT_MESSAGE_FILE + strprt(DARK); +#else + printf("%s\n",objdes[DARK]); +#endif + fight(DARK,100); + } + if (testbit(location[position].objects,WOODSMAN)){ +#ifdef EXT_MESSAGE_FILE + strprt(WOODSMAN); +#else + printf("%s\n",objdes[WOODSMAN]); +#endif + fight(WOODSMAN,50); + } + switch(position){ + + case 267: + case 257: /* entering a cave */ + case 274: + case 246: + notes[CANTSEE] = 1; + break; + case 160: + case 216: /* leaving a cave */ + case 230: + case 231: + case 232: + notes[CANTSEE] = 0; + break; + } + if (testbit(location[position].objects, GIRL)) + meetgirl = 1; + if (meetgirl && CYCLE * 1.5 - Time < 10){ + setbit(location[GARDEN].objects,GIRLTALK); + setbit(location[GARDEN].objects,LAMPON); + setbit(location[GARDEN].objects,ROPE); + } + if (position == DOCK && (beenthere[position] || Time > CYCLE)){ + clearbit(location[DOCK].objects, GIRL); + clearbit(location[DOCK].objects,MAN); + } + if (meetgirl && Time - CYCLE * 1.5 > 10){ + clearbit(location[GARDEN].objects,GIRLTALK); + clearbit(location[GARDEN].objects,LAMPON); + clearbit(location[GARDEN].objects,ROPE); + meetgirl = 0; + } + if (testbit(location[position].objects,CYLON)){ + puts("Oh my God, you're being shot at by an alien spacecraft!"); + printf("The targeting computer says we have %d seconds to attack!\n",clk); + fflush(stdout); + sleep(1); + if (!visual()){ + hurt = rnd(NUMOFINJURIES); + injuries[hurt] = 1; + puts("Laser blasts sear the cockpit, and the alien veers off in a victory roll."); + puts("The viper shudders under a terrible explosion."); + printf("I'm afraid you have suffered %s.\n", ouch[hurt]); + } + else + clearbit(location[position].objects,CYLON); + } + if (injuries[SKULL] && injuries[INCISE] && injuries[NECK]){ + puts("I'm afraid you have suffered fatal injuries."); + die(0); + } + for (n=0; n < NUMOFINJURIES; n++) + if (injuries[n] == 1){ + injuries[n] = 2; + if (WEIGHT > 5) + WEIGHT -= 5; + else + WEIGHT = 0; + } + if (injuries[ARM] == 2){ + CUMBER -= 5; + injuries[ARM]++; + } + if (injuries[RIBS] == 2){ + CUMBER -= 2; + injuries[RIBS]++; + } + if (injuries[SPINE] == 2){ + WEIGHT = 0; + injuries[SPINE]++; + } + if (carrying > WEIGHT || encumber > CUMBER) + notes[CANTMOVE] = 1; + else + notes[CANTMOVE] = 0; +} + +void +crash() +{ + int hurt1,hurt2; + + fuel--; + if (!location[position].flyhere || (testbit(location[position].objects,LAND) && fuel <= 0)){ + if (!location[position].flyhere) + puts("You're flying too low. We're going to crash!"); + else{ + puts("You're out of fuel. We'll have to crash land!"); + if (!location[position].down){ + puts("Your viper strikes the ground and explodes into firey fragments."); + puts("Thick black smoke billows up from the wreckage."); + die(0); + } + position = location[position].down; + } + notes[LAUNCHED] = 0; + setbit(location[position].objects,CRASH); + Time += rnd(CYCLE/4); + puts("The viper explodes into the ground and you lose consciousness..."); + zzz(); + hurt1 = rnd(NUMOFINJURIES - 2) + 2; + hurt2 = rnd(NUMOFINJURIES - 2) + 2; + injuries[hurt1] = 1; + injuries[hurt2] = 1; + injuries[0] = 1; /* abrasions */ + injuries[1] = 1; /* lacerations */ + printf("I'm afraid you have suffered %s and %s.\n",ouch[hurt1],ouch[hurt2]); + } +} diff --git a/src/games/battlestar/cmd2.c b/src/games/battlestar/cmd2.c new file mode 100644 index 0000000..848f939 --- /dev/null +++ b/src/games/battlestar/cmd2.c @@ -0,0 +1,271 @@ +/* + * Copyright (c) 1983 Regents of the University of California, + * All rights reserved. Redistribution permitted subject to + * the terms of the Berkeley Software License Agreement. + */ +#include "externs.h" + +int +wearit() /* synonyms = {sheathe, sheath} */ +{ + register int n; + int firstnumber, value; + + firstnumber = wordnumber; + while(wordtype[++wordnumber] == ADJS); + while(wordnumber <= wordcount){ + value = wordvalue[wordnumber]; + for (n=0; objsht[value][n]; n++); + switch(value){ + + case -1: + puts("Wear what?"); + return(firstnumber); + + default: + printf("You can't wear%s%s!\n",(objsht[value][n-1] == 's' ? " " : " a "),objsht[value]); + return(firstnumber); + + case KNIFE: + /* case SHIRT: */ + case ROBE: + case LEVIS: /* wearable things */ + case SWORD: + case MAIL: + case HELM: + case SHOES: + case PAJAMAS: + case COMPASS: + case LASER: + case AMULET: + case TALISMAN: + case MEDALION: + case ROPE: + case RING: + case BRACELET: + case GRENADE: + + if (testbit(inven,value)){ + clearbit(inven,value); + setbit(wear,value); + carrying -= objwt[value]; + encumber -= objcumber[value]; + Time++; + printf("You are now wearing %s %s.\n",(objsht[value][n-1] == 's' ? "the" : "a"), objsht[value]); + } + else if (testbit(wear,value)) + printf("You are already wearing the %s.\n", objsht[value]); + else + printf("You aren't holding the %s.\n", objsht[value]); + if (wordnumber < wordcount - 1 && wordvalue[++wordnumber] == AND) + wordnumber++; + else + return(firstnumber); + } /* end switch */ + } /* end while */ + puts("Don't be ridiculous."); + return(firstnumber); +} + +int +put() /* synonyms = {buckle, strap, tie} */ +{ + if (wordvalue[wordnumber + 1] == ON){ + wordvalue[++wordnumber] = PUTON; + return(cypher()); + } + if (wordvalue[wordnumber + 1] == DOWN){ + wordvalue[++wordnumber] = DROP; + return(cypher()); + } + puts("I don't understand what you want to put."); + return(-1); + +} + +int +draw() /* synonyms = {pull, carry} */ +{ + return(take(wear)); +} + +int +use() +{ + while (wordtype[++wordnumber] == ADJS && wordnumber < wordcount); + if (wordvalue[wordnumber] == AMULET && testbit(inven,AMULET) && position != FINAL){ + puts("The amulet begins to glow."); + if (testbit(inven,MEDALION)){ + puts("The medallion comes to life too."); + if (position == 114){ + location[position].down = 160; + whichway(location[position]); + puts("The waves subside and it is possible to descend to the sea cave now."); + Time++; + return(-1); + } + } + puts("A light mist falls over your eyes and the sound of purling water trickles in"); + puts("your ears. When the mist lifts you are standing beside a cool stream."); + if (position == 229) + position = 224; + else + position = 229; + Time++; + return(0); + } + else if (position == FINAL) + puts("The amulet won't work in here."); + else if (wordvalue[wordnumber] == COMPASS && testbit(inven,COMPASS)) + printf("Your compass points %s.\n",truedirec(NORTH,'-')); + else if (wordvalue[wordnumber] == COMPASS) + puts("You aren't holding the compass."); + else if (wordvalue[wordnumber] == AMULET) + puts("You aren't holding the amulet."); + else + puts("There is no apparent use."); + return(-1); +} + +void +murder() +{ + register int n; + + for (n=0; !((n == SWORD || n == KNIFE || n == TWO_HANDED || n == MACE || n == CLEAVER || n == BROAD || n == CHAIN || n == SHOVEL || n == HALBERD) && testbit(inven,n)) && n < NUMOFOBJECTS; n++); + if (n == NUMOFOBJECTS) + puts("You don't have suitable weapons to kill."); + else { + printf("Your %s should do the trick.\n",objsht[n]); + while (wordtype[++wordnumber] == ADJS); + switch(wordvalue[wordnumber]){ + + case NORMGOD: + if (testbit(location[position].objects,BATHGOD)){ + puts("The goddess's head slices off. Her corpse floats in the water."); + clearbit(location[position].objects,BATHGOD); + setbit(location[position].objects,DEADGOD); + power += 5; + notes[JINXED]++; + } else if (testbit(location[position].objects,NORMGOD)){ + puts("The goddess pleads but you strike her mercilessly. Her broken body lies in a\npool of blood."); + clearbit(location[position].objects,NORMGOD); + setbit(location[position].objects,DEADGOD); + power += 5; + notes[JINXED]++; + if (wintime) + live(); + } else puts("I dont see her anywhere."); + break; + case TIMER: + if (testbit(location[position].objects,TIMER)){ + puts("The old man offers no resistance."); + clearbit(location[position].objects,TIMER); + setbit(location[position].objects,DEADTIME); + power++; + notes[JINXED]++; + } else puts("Who?"); + break; + case NATIVE: + if (testbit(location[position].objects,NATIVE)){ + puts("The girl screams as you cut her body to shreds. She is dead."); + clearbit(location[position].objects,NATIVE); + setbit(location[position].objects,DEADNATIVE); + power += 5; + notes[JINXED]++; + } else puts("What girl?"); + break; + case MAN: + if (testbit(location[position].objects,MAN)){ + puts("You strike him to the ground, and he coughs up blood."); + puts("Your fantasy is over."); + die(0); + } + case -1: + puts("Kill what?"); + break; + + default: + if (wordtype[wordnumber] != NOUNS) + puts("Kill what?"); + else + printf("You can't kill the %s!\n",objsht[wordvalue[wordnumber]]); + } + } +} + +void +ravage() +{ + while (wordtype[++wordnumber] != NOUNS && wordnumber <= wordcount); + if (wordtype[wordnumber] == NOUNS && testbit(location[position].objects,wordvalue[wordnumber])){ + Time++; + switch(wordvalue[wordnumber]){ + case NORMGOD: + puts("You attack the goddess, and she screams as you beat her. She falls down"); + puts("crying and tries to hold her torn and bloodied dress around her."); + power += 5; + pleasure += 8; + ego -= 10; + wordnumber--; + godready = -30000; + murder(); + win = -30000; + break; + case NATIVE: + puts("The girl tries to run, but you catch her and throw her down. Her face is"); + puts("bleeding, and she screams as you tear off her clothes."); + power += 3; + pleasure += 5; + ego -= 10; + wordnumber--; + murder(); + if (rnd(100) < 50){ + puts("Her screams have attracted attention. I think we are surrounded."); + setbit(location[ahead].objects,WOODSMAN); + setbit(location[ahead].objects,DEADWOOD); + setbit(location[ahead].objects,MALLET); + setbit(location[back].objects,WOODSMAN); + setbit(location[back].objects,DEADWOOD); + setbit(location[back].objects,MALLET); + setbit(location[left].objects,WOODSMAN); + setbit(location[left].objects,DEADWOOD); + setbit(location[left].objects,MALLET); + setbit(location[right].objects,WOODSMAN); + setbit(location[right].objects,DEADWOOD); + setbit(location[right].objects,MALLET); + } + break; + default: + puts("You are perverted."); + } + } + else + puts("Who?"); +} + +int +follow() +{ + if (followfight == Time){ + puts("The Dark Lord leaps away and runs down secret tunnels and corridoors."); + puts("You chase him through the darkness and splash in pools of water."); + puts("You have cornered him. His laser sword extends as he steps forward."); + position = FINAL; + fight(DARK,75); + setbit(location[position].objects,TALISMAN); + setbit(location[position].objects,AMULET); + return(0); + } + else if (followgod == Time){ + puts("The goddess leads you down a steamy tunnel and into a high, wide chamber."); + puts("She sits down on a throne."); + position = 268; + setbit(location[position].objects,NORMGOD); + notes[CANTSEE] = 1; + return(0); + } + else + puts("There is no one to follow."); + return(-1); +} diff --git a/src/games/battlestar/cmd3.c b/src/games/battlestar/cmd3.c new file mode 100644 index 0000000..1e36c5d --- /dev/null +++ b/src/games/battlestar/cmd3.c @@ -0,0 +1,285 @@ +/* + * Copyright (c) 1983 Regents of the University of California, + * All rights reserved. Redistribution permitted subject to + * the terms of the Berkeley Software License Agreement. + */ +#include "externs.h" + +void +dig() +{ + if (testbit(inven,SHOVEL)){ + puts("OK"); + Time++; + switch(position){ + case 144: /* copse near beach */ + if (!notes[DUG]){ + setbit(location[position].objects,DEADWOOD); + setbit(location[position].objects,COMPASS); + setbit(location[position].objects,KNIFE); + setbit(location[position].objects,MACE); + notes[DUG] = 1; + } + break; + + default: + puts("Nothing happens."); + } + } + else + puts("You don't have a shovel."); +} + +int +jump() +{ + register int n; + + switch(position){ + default: + puts("Nothing happens."); + return(-1); + + case 242: + position = 133; + break; + case 214: + case 215: + case 162: + case 159: + position = 145; + break; + case 232: + position = 275; + break; + case 3: + position = 1; + break; + case 172: + position = 201; + } + puts("Ahhhhhhh..."); + injuries[12] = injuries[8] = injuries[7] = injuries[6] = 1; + for (n=0; n < NUMOFOBJECTS; n++) + if (testbit(inven,n)){ + clearbit(inven,n); + setbit(location[position].objects,n); + } + carrying = 0; + encumber = 0; + return(0); +} + +void +bury() +{ + int value; + + if (testbit(inven,SHOVEL)){ + while(wordtype[++wordnumber] != OBJECT && wordtype[wordnumber] != NOUNS && wordnumber < wordcount); + value = wordvalue[wordnumber]; + if (wordtype[wordnumber] == NOUNS && (testbit(location[position].objects,value) || value == BODY)) + switch(value){ + case BODY: + wordtype[wordnumber] = OBJECT; + if (testbit(inven,MAID) || testbit(location[position].objects,MAID)) + value = MAID; + if (testbit(inven,DEADWOOD) || testbit(location[position].objects,DEADWOOD)) + value = DEADWOOD; + if (testbit(inven,DEADGOD) || testbit(location[position].objects,DEADGOD)) + value = DEADGOD; + if (testbit(inven,DEADTIME) || testbit(location[position].objects,DEADTIME)) + value = DEADTIME; + if (testbit(inven,DEADNATIVE) || testbit(location[position].objects,DEADNATIVE)) + value = DEADNATIVE; + break; + + case NATIVE: + case NORMGOD: + puts("She screams as you wrestle her into the hole."); + case TIMER: + power += 7; + ego -= 10; + case AMULET: + case MEDALION: + case TALISMAN: + wordtype[wordnumber] = OBJECT; + break; + + default: + puts("Wha..?"); + } + if (wordtype[wordnumber] == OBJECT && position > 88 && (testbit(inven,value) || testbit(location[position].objects,value))){ + puts("Buried."); + if (testbit(inven,value)){ + clearbit(inven,value); + carrying -= objwt[value]; + encumber -= objcumber[value]; + } + clearbit(location[position].objects,value); + switch(value){ + case MAID: + case DEADWOOD: + case DEADNATIVE: + case DEADTIME: + case DEADGOD: + ego += 2; + printf("The %s should rest easier now.\n",objsht[value]); + } + } + else + puts("It doesn't seem to work."); + } + else + puts("You aren't holding a shovel."); +} + +void +drink() +{ + register int n; + + if (testbit(inven,POTION)){ + puts("The cool liquid runs down your throat but turns to fire and you choke."); + puts("The heat reaches your limbs and tingles your spirit. You feel like falling"); + puts("asleep."); + clearbit(inven, POTION); + WEIGHT = MAXWEIGHT; + CUMBER = MAXCUMBER; + for (n=0; n < NUMOFINJURIES; n++) + injuries[n] = 0; + Time++; + zzz(); + } + else + puts("I'm not thirsty."); +} + +int +shoot() +{ + int firstnumber = 0, value; + register int n; + + if (!testbit(inven,LASER)) + puts("You aren't holding a blaster."); + else { + firstnumber = wordnumber; + while(wordtype[++wordnumber] == ADJS); + while(wordnumber<=wordcount && wordtype[wordnumber] == OBJECT){ + value = wordvalue[wordnumber]; + printf("%s:\n", objsht[value]); + for (n=0; objsht[value][n]; n++); + if (testbit(location[position].objects,value)){ + clearbit(location[position].objects,value); + Time++; + printf("The %s explode%s\n",objsht[value],(objsht[value][n-1]=='s' ? (objsht[value][n-2]=='s' ? "s." : ".") : "s.")); + if (value == BOMB) + die(0); + } + else + printf("I dont see any %s around here.\n", objsht[value]); + if (wordnumber < wordcount - 1 && wordvalue[++wordnumber] == AND) + wordnumber++; + else + return(firstnumber); + } + /* special cases with their own return()'s */ + + if (wordnumber <= wordcount && wordtype[wordnumber] == NOUNS){ + Time++; + switch(wordvalue[wordnumber]){ + + case DOOR: + switch(position){ + case 189: + case 231: + puts("The door is unhinged."); + location[189].north = 231; + location[231].south = 189; + whichway(location[position]); + break; + case 30: + puts("The wooden door splinters."); + location[30].west = 25; + whichway(location[position]); + break; + case 31: + puts("The laser blast has no effect on the door."); + break; + case 20: + puts("The blast hits the door and it explodes into flame. The magnesium burns"); + puts("so rapidly that we have no chance to escape."); + die(0); + default: + puts("Nothing happens."); + } + break; + + case NORMGOD: + if (testbit(location[position].objects,BATHGOD)){ + puts("The goddess is hit in the chest and splashes back against the rocks."); + puts("Dark blood oozes from the charred blast hole. Her naked body floats in the"); + puts("pools and then off downstream."); + clearbit(location[position].objects,BATHGOD); + setbit(location[180].objects,DEADGOD); + power += 5; + ego -= 10; + notes[JINXED]++; + } else if (testbit(location[position].objects,NORMGOD)){ + puts("The blast catches the goddess in the stomach, knocking her to the ground."); + puts("She writhes in the dirt as the agony of death taunts her."); + puts("She has stopped moving."); + clearbit(location[position].objects,NORMGOD); + setbit(location[position].objects,DEADGOD); + power += 5; + ego -= 10; + notes[JINXED]++; + if (wintime) + live(); + break; + } else + puts("I don't see any goddess around here."); + break; + + case TIMER: + if (testbit(location[position].objects,TIMER)){ + puts("The old man slumps over the bar."); + power++; + ego -= 2; + notes[JINXED]++; + clearbit(location[position].objects,TIMER); + setbit(location[position].objects,DEADTIME); + } + else puts("What old timer?"); + break; + case MAN: + if (testbit(location[position].objects,MAN)){ + puts("The man falls to the ground with blood pouring all over his white suit."); + puts("Your fantasy is over."); + die(0); + } + else puts("What man?"); + break; + case NATIVE: + if (testbit(location[position].objects,NATIVE)){ + puts("The girl is blown backwards several feet and lies in a pool of blood."); + clearbit(location[position].objects,NATIVE); + setbit(location[position].objects,DEADNATIVE); + power += 5; + ego -= 2; + notes[JINXED]++; + } else puts("There is no girl here."); + break; + case -1: + puts("Shoot what?"); + break; + + default: + printf("You can't shoot the %s.\n",objsht[wordvalue[wordnumber]]); + } + } + else puts("You must be a looney."); + } + return(firstnumber); +} diff --git a/src/games/battlestar/cmd4.c b/src/games/battlestar/cmd4.c new file mode 100644 index 0000000..9029bd8 --- /dev/null +++ b/src/games/battlestar/cmd4.c @@ -0,0 +1,350 @@ +/* + * Copyright (c) 1983 Regents of the University of California, + * All rights reserved. Redistribution permitted subject to + * the terms of the Berkeley Software License Agreement. + */ +#include "externs.h" + +int +take(from) + unsigned int from[]; +{ + int firstnumber, heavy, bulky, value; + register int n; + + firstnumber = wordnumber; + if (wordnumber < wordcount && wordvalue[wordnumber+1] == OFF){ + wordnumber++; + wordvalue[wordnumber] = TAKEOFF; + return(cypher()); + } + else { + while(wordtype[++wordnumber] == ADJS); + while(wordnumber<=wordcount && wordtype[wordnumber] == OBJECT){ + value = wordvalue[wordnumber]; + printf("%s:\n", objsht[value]); + for (n=0; objsht[value][n]; n++); + heavy = (carrying + objwt[value]) <= WEIGHT; + bulky = (encumber + objcumber[value]) <= CUMBER; + if ((testbit(from,value) || wiz || tempwiz) && heavy && bulky && !testbit(inven,value)){ + setbit(inven,value); + carrying += objwt[value]; + encumber += objcumber[value]; + Time++; + if (testbit(from,value)) + printf("Taken.\n"); + else + printf("Zap! Taken from thin air.\n"); + clearbit(from,value); + if (value == MEDALION) + win--; + } + else if (testbit(inven,value)) + printf("You're already holding%s%s.\n", (objsht[value][n-1] == 's' ? " " : " a "),objsht[value]); + else if (!heavy) + printf("The %s %s too heavy.\n", objsht[value],(objsht[value][n-1] == 's' ? "are" : "is")); + else if (!bulky) + printf("The %s %s too cumbersome to hold.\n", objsht[value],(objsht[value][n-1] == 's' ? "are" : "is")); + else + printf("I dont see any %s around here.\n", objsht[value]); + if (wordnumber < wordcount -1 && wordvalue[++wordnumber] == AND) + wordnumber++; + else + return(firstnumber); + } + } + /* special cases with their own return()'s */ + + if (wordnumber <= wordcount && wordtype[wordnumber] == NOUNS) + switch(wordvalue[wordnumber]){ + + case SWORD: + if (testbit(from, SWORD)){ + wordtype[wordnumber--] = OBJECT; + return(take(from)); + } + if (testbit(from, TWO_HANDED)){ + wordvalue[wordnumber] = TWO_HANDED; + wordtype[wordnumber--] = OBJECT; + return(take(from)); + } + wordvalue[wordnumber] = BROAD; + wordtype[wordnumber--] = OBJECT; + return(take(from)); + + case BODY: + if (testbit(from,MAID)){ + wordvalue[wordnumber] = MAID; + wordtype[wordnumber--] = OBJECT; + return(take(from)); + } + else if (testbit(from,DEADWOOD)){ + wordvalue[wordnumber] = DEADWOOD; + wordtype[wordnumber--] = OBJECT; + return(take(from)); + } + else if (testbit(from,DEADNATIVE)){ + wordvalue[wordnumber] = DEADNATIVE; + wordtype[wordnumber--] = OBJECT; + return(take(from)); + } + else if (testbit(from,DEADGOD)){ + wordvalue[wordnumber] = DEADGOD; + wordtype[wordnumber--] = OBJECT; + return(take(from)); + } + else { + wordvalue[wordnumber] = DEADTIME; + wordtype[wordnumber--] = OBJECT; + return(take(from)); + } + break; + + case AMULET: + if (testbit(location[position].objects,AMULET)){ + puts("The amulet is warm to the touch, and its beauty catches your breath."); + puts("A mist falls over your eyes, but then it is gone. Sounds seem clearer"); + puts("and sharper but far away as if in a dream. The sound of purling water reaches"); + puts("you from afar. The mist falls again, and your heart leaps in horror. The gold"); + puts("freezes your hands and fathomless darkness engulfs your soul."); + } + wordtype[wordnumber--] = OBJECT; + return(take(from)); + + case MEDALION: + if (testbit(location[position].objects, MEDALION)){ + puts("The medallion is warm, and it rekindles your spirit with the warmth of life."); + puts("Your amulet begins to glow as the medallion is brought near to it, and together\nthey radiate."); + } + wordtype[wordnumber--] = OBJECT; + return(take(from)); + + case TALISMAN: + if (testbit(location[position].objects,TALISMAN)){ + puts("The talisman is cold to the touch, and it sends a chill down your spine."); + } + wordtype[wordnumber--] = OBJECT; + return(take(from)); + + case NORMGOD: + if (testbit(location[position].objects,BATHGOD) && (testbit(wear,AMULET) || testbit(inven,AMULET))){ + puts("She offers a delicate hand, and you help her out of the sparkling springs."); + puts("Water droplets like liquid silver bedew her golden skin, but when they part"); + puts("from her, they fall as teardrops. She wraps a single cloth around her and"); + puts("ties it at the waist. Around her neck hangs a golden amulet."); + puts("She bids you to follow her."); + pleasure++; + followgod = Time; + clearbit(location[position].objects,BATHGOD); + } else if (!testbit(location[position].objects,BATHGOD)) + puts("You're in no position to take her."); + else + puts("She moves away from you."); + break; + + default: + puts("It doesn't seem to work."); + } + else + puts("You've got to be kidding."); + return(firstnumber); +} + +int +throw(name) + char *name; +{ + int n; + int deposit = 0; + int first, value; + + first = wordnumber; + if (drop(name) != -1){ + switch(wordvalue[wordnumber]){ + + case AHEAD: + deposit = ahead; + break; + + case BACK: + deposit = back; + break; + + case LEFT: + deposit = left; + break; + + case RIGHT: + deposit = right; + break; + + case UP: + deposit = location[position].up * (location[position].access || position == FINAL); + break; + + case DOWN: + deposit = location[position].down; + break; + } + wordnumber = first; + while (wordtype[++wordnumber] == ADJS); + while (wordnumber <= wordcount){ + value = wordvalue[wordnumber]; + if (deposit && testbit(location[position].objects,value)){ + clearbit(location[position].objects,value); + if (value != GRENADE) + setbit(location[deposit].objects,value); + else{ + puts("A thundering explosion nearby sends up a cloud of smoke and shrapnel."); + for (n = 0; n < NUMOFWORDS; n ++) + location[deposit].objects[n] = 0; + setbit(location[deposit].objects,CHAR); + } + if (value == ROPE && position == FINAL) + location[position].access = 1; + switch(deposit){ + case 189: + case 231: + puts("The stone door is unhinged."); + location[189].north = 231; + location[231].south = 189; + break; + case 30: + puts("The wooden door is blown open."); + location[30].west = 25; + break; + case 31: + puts("The door is not damaged."); + } + } + else if (value == GRENADE && testbit(location[position].objects,value)){ + puts("You are blown into shreds when your grenade explodes."); + die(0); + } + if (wordnumber < wordcount - 1 && wordvalue[++wordnumber] == AND) + wordnumber++; + else + return(first); + } + return(first); + } + return(first); +} + +int +drop(name) + char *name; +{ + + int firstnumber, value; + + firstnumber = wordnumber; + while (wordtype[++wordnumber] == ADJS) + ; + while (wordnumber<=wordcount && (wordtype[wordnumber] == OBJECT || wordtype[wordnumber] == NOUNS)) { + value = wordvalue[wordnumber]; + printf("%s:\n", objsht[value]); + if (testbit(inven,value)){ + clearbit(inven,value); + carrying -= objwt[value]; + encumber -= objcumber[value]; + if (value == BOMB){ + puts("The bomb explodes. A blinding white light and immense concussion obliterate us."); + die(0); + } + if (value != AMULET && value != MEDALION && value != TALISMAN) + setbit(location[position].objects,value); + else + tempwiz = 0; + Time++; + if (*name == 'K') + puts("Drop kicked."); + else + printf("%s.\n", name); + } + else { + if (*name != 'K') { + printf("You aren't holding the %s.\n", objsht[value]); + if (testbit(location[position].objects,value)) { + if (*name == 'T') + puts("Kicked instead."); + else if (*name == 'G') + puts("Given anyway."); + } + } else + puts("Kicked."); + } + if (wordnumber < wordcount - 1 && wordvalue[++wordnumber] == AND) + wordnumber++; + else + return(firstnumber); + } + puts("Do what?"); + return(-1); +} + +int +takeoff() +{ + wordnumber = take(wear); + return(drop("Dropped")); +} + +int +puton() +{ + wordnumber = take(location[position].objects); + return(wearit()); +} + +int +eat() +{ + register int n; + int firstnumber, value; + + firstnumber = wordnumber; + while(wordtype[++wordnumber] == ADJS); + while(wordnumber <= wordcount){ + value = wordvalue[wordnumber]; + for (n=0; objsht[value][n]; n++); + switch(value){ + + case -1: + puts("Eat what?"); + return(firstnumber); + + default: + printf("You can't eat%s%s!\n",(objsht[value][n-1] == 's' ? " " : " a "),objsht[value]); + return(firstnumber); + + case PAPAYAS: + case PINEAPPLE: + case KIWI: + case COCONUTS: /* eatable things */ + case MANGO: + + printf("%s:\n",objsht[value]); + if (testbit(inven,value) && Time > ate - CYCLE && testbit(inven,KNIFE)){ + clearbit(inven,value); + carrying -= objwt[value]; + encumber -= objcumber[value]; + ate = max(Time,ate) + CYCLE/3; + snooze += CYCLE/10; + Time++; + puts("Eaten. You can explore a little longer now."); + } + else if (Time < ate - CYCLE) + puts("You're stuffed."); + else if (!testbit(inven,KNIFE)) + puts("You need a knife."); + else + printf("You aren't holding the %s.\n", objsht[value]); + if (wordnumber < wordcount - 1 && wordvalue[++wordnumber] == AND) + wordnumber++; + else + return(firstnumber); + } /* end switch */ + } /* end while */ + return(firstnumber); +} diff --git a/src/games/battlestar/cmd5.c b/src/games/battlestar/cmd5.c new file mode 100644 index 0000000..6b80335 --- /dev/null +++ b/src/games/battlestar/cmd5.c @@ -0,0 +1,297 @@ +/* + * Copyright (c) 1983 Regents of the University of California, + * All rights reserved. Redistribution permitted subject to + * the terms of the Berkeley Software License Agreement. + */ +#include "externs.h" + +void +kiss() +{ + while (wordtype[++wordnumber] != NOUNS && wordnumber <= wordcount); + if (wordtype[wordnumber] == NOUNS && testbit(location[position].objects,wordvalue[wordnumber])){ + pleasure++; + printf("Kissed.\n"); + switch (wordvalue[wordnumber]){ + case NORMGOD: + switch(godready++){ + case 0: + puts("She squirms and avoids your advances."); + break; + case 1: + puts("She is coming around; she didn't fight it as much."); + break; + case 2: + puts("She's begining to like it."); + break; + default: + puts("She's gone limp."); + + } + break; + case NATIVE: + puts("The lips are warm and her body robust. She pulls you down to the ground."); + break; + case TIMER: + puts("The old man blushes."); + break; + case MAN: + puts("The dwarf punches you in the kneecap."); + break; + default: + pleasure--; + } + } + else puts("I'd prefer not to."); +} + +void +love() +{ + register int n; + + while (wordtype[++wordnumber] != NOUNS && wordnumber <= wordcount); + if (wordtype[wordnumber] == NOUNS && testbit(location[position].objects,wordvalue[wordnumber])){ + if (wordvalue[wordnumber] == NORMGOD && !loved) { + if (godready >= 2){ + puts("She cuddles up to you, and her mouth starts to work:\n'That was my sister's amulet. The lovely goddess, Purl, was she. The Empire\ncaptured her just after the Darkness came. My other sister, Vert, was killed\nby the Dark Lord himself. He took her amulet and warped its power.\nYour quest was foretold by my father before he died, but to get the Dark Lord's\namulet you must use cunning and skill. I will leave you my amulet."); + puts("which you may use as you wish. As for me, I am the last goddess of the\nwaters. My father was the Island King, and the rule is rightfully mine.'\n\nShe pulls the throne out into a large bed."); + power++; + pleasure += 15; + ego++; + if (card(injuries, NUMOFINJURIES)){ + puts("Her kisses revive you; your wounds are healed.\n"); + for (n=0; n < NUMOFINJURIES; n++) + injuries[n] = 0; + WEIGHT = MAXWEIGHT; + CUMBER = MAXCUMBER; + } + printf("Goddess:\n"); + if (!loved) + setbit(location[position].objects,MEDALION); + loved = 1; + Time += 10; + zzz(); + } else { + puts("You wish!"); + return; + } + } + if (wordvalue[wordnumber] == NATIVE){ + puts("The girl is easy prey. She peals off her sarong and indulges you."); + power++; + pleasure += 5; + printf("Girl:\n"); + Time += 10; + zzz(); + } + printf("Loved.\n"); + } + else puts("I't doesn't seem to work."); +} + +int +zzz() +{ + int oldtime; + register int n; + + oldtime = Time; + if ((snooze - Time) < (0.75 * CYCLE)){ + Time += 0.75 * CYCLE - (snooze - Time); + printf(""); + for (n = 0; n < Time - oldtime; n++) + printf("."); + printf("\n"); + snooze += 3 * (Time - oldtime); + if (notes[LAUNCHED]){ + fuel -= (Time - oldtime); + if (location[position].down){ + position = location[position].down; + crash(); + } + else + notes[LAUNCHED] = 0; + } + if (OUTSIDE && rnd(100) < 50){ + puts("You are awakened abruptly by the sound of someone nearby."); + switch(rnd(4)){ + case 0: + if (ucard(inven)){ + n = rnd(NUMOFOBJECTS); + while(!testbit(inven,n)) + n = rnd(NUMOFOBJECTS); + clearbit(inven,n); + if (n != AMULET && n != MEDALION && n != TALISMAN) + setbit(location[position].objects,n); + carrying -= objwt[n]; + encumber -= objcumber[n]; + } + puts("A fiendish little Elf is stealing your treasures!"); + fight(ELF,10); + break; + case 1: + setbit(location[position].objects,DEADWOOD); + break; + case 2: + setbit(location[position].objects,HALBERD); + break; + default: + break; + } + } + } + else + return(0); + return(1); +} + +void +chime() +{ + if ((Time / CYCLE + 1) % 2 && OUTSIDE) + switch((Time % CYCLE)/(CYCLE / 7)){ + case 0: + puts("It is just after sunrise."); + break; + case 1: + puts("It is early morning."); + break; + case 2: + puts("It is late morning."); + break; + case 3: + puts("It is near noon."); + break; + case 4: + puts("It is early afternoon."); + break; + case 5: + puts("It is late afternoon."); + break; + case 6: + puts("It is near sunset."); + break; + } + else if (OUTSIDE) + switch((Time % CYCLE)/(CYCLE / 7)){ + case 0: + puts("It is just after sunset."); + break; + case 1: + puts("It is early evening."); + break; + case 2: + puts("The evening is getting old."); + break; + case 3: + puts("It is near midnight."); + break; + case 4: + puts("These are the wee hours of the morning."); + break; + case 5: + puts("The night is waning."); + break; + case 6: + puts("It is almost morning."); + break; + } + else + puts("I can't tell the time in here."); +} + +int +give() +{ + int obj = -1, result = -1, person = 0, firstnumber, last1 = 0, last2 = 0; + + firstnumber = wordnumber; + while (wordtype[++wordnumber] != OBJECT && wordvalue[wordnumber] != AMULET && wordvalue[wordnumber] != MEDALION && wordvalue[wordnumber] != TALISMAN && wordnumber <= wordcount); + if (wordnumber <= wordcount){ + obj = wordvalue[wordnumber]; + if (obj == EVERYTHING) + wordtype[wordnumber] = -1; + last1 = wordnumber; + } + wordnumber = firstnumber; + while ((wordtype[++wordnumber] != NOUNS || wordvalue[wordnumber] == obj) && wordnumber <= wordcount); + if (wordtype[wordnumber] == NOUNS){ + person = wordvalue[wordnumber]; + last2 = wordnumber; + } + wordnumber = last1 - 1; + if (person && testbit(location[position].objects,person)) + if (person == NORMGOD && godready < 2 && !(obj == RING || obj == BRACELET)) + puts("The goddess won't look at you."); + else + result = drop("Given"); + else { + puts("I don't think that is possible."); + return(0); + } + if (result != -1 && (testbit(location[position].objects,obj) || obj == AMULET || obj == MEDALION || obj == TALISMAN)){ + clearbit(location[position].objects,obj); + Time++; + ego++; + switch(person){ + case NATIVE: + puts("She accepts it shyly."); + ego += 2; + break; + case NORMGOD: + if (obj == RING || obj == BRACELET){ + puts("She takes the charm and puts it on. A little kiss on the cheek is"); + puts("your reward."); + ego += 5; + godready += 3; + } + if (obj == AMULET || obj == MEDALION || obj == TALISMAN){ + win++; + ego += 5; + power -= 5; + if (win >= 3){ + puts("The powers of the earth are now legitimate. You have destroyed the Darkness"); + puts("and restored the goddess to her thrown. The entire island celebrates with"); + puts("dancing and spring feasts. As a measure of her gratitude, the goddess weds you"); + puts("in the late summer and crowns you Prince Liverwort, Lord of Fungus."); + puts("\nBut, as the year wears on and autumn comes along, you become restless and"); + puts("yearn for adventure. The goddess, too, realizes that the marriage can't last."); + puts("She becomes bored and takes several more natives as husbands. One evening,"); + puts("after having been out drinking with the girls, she kicks the throne particulary"); + puts("hard and wakes you up. (If you want to win this game, you're going to have to\nshoot her!)"); + clearbit(location[position].objects,MEDALION); + wintime = Time; + } + } + break; + case TIMER: + if (obj == COINS){ + puts("He fingers the coins for a moment and then looks up agape. `Kind you are and"); + puts("I mean to repay you as best I can.' Grabbing a pencil and cocktail napkin...\n"); + printf( "+-----------------------------------------------------------------------------+\n"); + printf( "| xxxxxxxx\\ |\n"); + printf( "| xxxxx\\ CLIFFS |\n"); + printf( "| FOREST xxx\\ |\n"); + printf( "| \\\\ x\\ OCEAN |\n"); + printf( "| || x\\ |\n"); + printf( "| || ROAD x\\ |\n"); + printf( "| || x\\ |\n"); + printf( "| SECRET || ......... |\n"); + printf( "| - + - || ........ |\n"); + printf( "| ENTRANCE || ... BEACH |\n"); + printf( "| || ... E |\n"); + printf( "| || ... | |\n"); + printf( "| // ... N <-- + --- S |\n"); + printf( "| PALM GROVE // ... | |\n"); + printf( "| // ... W |\n"); + printf( "+-----------------------------------------------------------------------------+\n"); + puts("\n`This map shows a secret entrance to the catacombs."); + puts("You will know when you arrive because I left an old pair of shoes there.'"); + } + break; + } + } + wordnumber = max(last1,last2); + return(firstnumber); +} diff --git a/src/games/battlestar/cmd6.c b/src/games/battlestar/cmd6.c new file mode 100644 index 0000000..c60be8d --- /dev/null +++ b/src/games/battlestar/cmd6.c @@ -0,0 +1,188 @@ +/* + * Copyright (c) 1983 Regents of the University of California, + * All rights reserved. Redistribution permitted subject to + * the terms of the Berkeley Software License Agreement. + */ +#include "externs.h" +#include +#include + +int +launch() +{ + if (testbit(location[position].objects,VIPER) && !notes[CANTLAUNCH]){ + if (fuel > 4){ + clearbit(location[position].objects,VIPER); + position = location[position].up; + notes[LAUNCHED] = 1; + Time++; + fuel -= 4; + puts("You climb into the viper and prepare for launch."); + puts("With a touch of your thumb the turbo engines ignite, thrusting you back into\nyour seat."); + return(1); + } + else + puts("Not enough fuel to launch."); + } + else + puts("Can't launch."); + return(0); +} + +int +land() +{ + if (notes[LAUNCHED] && testbit(location[position].objects,LAND) && location[position].down){ + notes[LAUNCHED] = 0; + position = location[position].down; + setbit(location[position].objects,VIPER); + fuel -= 2; + Time++; + puts("You are down."); + return(1); + } + else + puts("You can't land here."); + return(0); +} + +#include + +static void +post(ch) + int ch; +{ + FILE *fp; + struct timeval tv; + char *date; + sigset_t s, oset; + + sigemptyset(&s); + sigaddset(&s, SIGINT); + (void)sigprocmask(SIG_BLOCK, &s, &oset); + gettimeofday(&tv, (struct timezone *)0); + date = ctime(&tv.tv_sec); + date[24] = '\0'; + fp = fopen(logfile, "a"); + if (fp) { + fprintf(fp, "%s %8s %c%20s", date, uname, ch, rate()); + if (wiz) + fprintf(fp, " wizard\n"); + else if (tempwiz) + fprintf(fp, " WIZARD!\n"); + else + fprintf(fp, "\n"); + } else + perror(logfile); + (void)sigprocmask(SIG_SETMASK, &oset, NULL); +} + +void +die(int signum) /* endgame */ +{ + printf("bye.\nYour rating was %s.\n", rate()); + post(' '); + exit(0); +} + +void +live() +{ + puts("\nYou win!"); + post('!'); + exit(0); +} + +char * +rate() +{ + int score; + + score = max(max(pleasure,power),ego); + if (score == pleasure){ + if (score < 5) + return("novice"); + else if (score < 20) + return("junior voyeur"); + else if (score < 35) + return("Don Juan"); + else return("Marquis De Sade"); + } + else if (score == power){ + if (score < 5) + return("serf"); + else if (score < 8) + return("Samurai"); + else if (score < 13) + return("Klingon"); + else if (score < 22) + return("Darth Vader"); + else return("Sauron the Great"); + } + else{ + if (score < 5) + return("Polyanna"); + else if (score < 10) + return("philanthropist"); + else if (score < 20) + return("Tattoo"); + else return("Mr. Roarke"); + } +} + +int +drive() +{ + if (testbit(location[position].objects,CAR)){ + puts("You hop in the car and turn the key. There is a perceptible grating noise,"); + puts("and an explosion knocks you unconscious..."); + clearbit(location[position].objects,CAR); + setbit(location[position].objects,CRASH); + injuries[5] = injuries[6] = injuries[7] = injuries[8] = 1; + Time += 15; + zzz(); + return(0); + } + else + puts("There is nothing to drive here."); + return(-1); +} + +int +ride() +{ + if (testbit(location[position].objects,HORSE)){ + puts("You climb onto the stallion and kick it in the guts. The stupid steed launches"); + puts("forward through bush and fern. You are thrown and the horse gallups off."); + clearbit(location[position].objects,HORSE); + while (!(position = rnd(NUMOFROOMS+1)) || !OUTSIDE || !beenthere[position] || location[position].flyhere); + setbit(location[position].objects,HORSE); + if (location[position].north) + position = location[position].north; + else if (location[position].south) + position = location[position].south; + else if (location[position].east) + position = location[position].east; + else + position = location[position].west; + return(0); + } + else puts("There is no horse here."); + return(-1); +} + +void +light() /* synonyms = {strike, smoke} */ +{ /* for matches, cigars */ + if (testbit(inven,MATCHES) && matchcount){ + puts("Your match splutters to life."); + Time++; + matchlight = 1; + matchcount--; + if (position == 217){ + puts("The whole bungalow explodes with an intense blast."); + die(0); + } + } + else puts("You're out of matches."); +} diff --git a/src/games/battlestar/cmd7.c b/src/games/battlestar/cmd7.c new file mode 100644 index 0000000..1be6419 --- /dev/null +++ b/src/games/battlestar/cmd7.c @@ -0,0 +1,237 @@ +/* + * Copyright (c) 1983 Regents of the University of California, + * All rights reserved. Redistribution permitted subject to + * the terms of the Berkeley Software License Agreement. + */ +#include "externs.h" + +int +fight(enemy, strength) + int enemy, strength; +{ + int lifeline = 0; + int hurt; + char auxbuf[LINELENGTH]; + char *next; + int i; + int exhaustion = 0; + +fighton: + Time++; + snooze -= 5; + if (snooze > Time) + exhaustion = CYCLE/(snooze - Time); + else { + puts("You collapse exhausted, and he pulverizes your skull."); + die(0); + } + if (snooze - Time < 20) + puts("You look tired! I hope you're able to fight."); + next = getcom(auxbuf, LINELENGTH, "-: ", 0); + for (i=0; next && i < 10; i++) + next = getword(next, words[i], -1); + parse(); + switch(wordvalue[wordnumber]){ + + case KILL: + case SMITE: + if (testbit(inven,TWO_HANDED)) + hurt = rnd(70) - 2 * card(injuries,NUMOFINJURIES) - ucard(wear) - exhaustion; + else if (testbit(inven,SWORD) || testbit(inven, BROAD)) + hurt = rnd(50)%(WEIGHT-carrying)-card(injuries,NUMOFINJURIES)-encumber - exhaustion; + else if (testbit(inven,KNIFE) || testbit(inven,MALLET) || testbit(inven,CHAIN) || testbit(inven,MACE) || testbit(inven,HALBERD)) + hurt = rnd(15) - card(injuries,NUMOFINJURIES) - exhaustion; + else + hurt = rnd(7) - encumber; + if (hurt < 5) + switch(rnd(3)){ + + case 0: + puts("You swung wide and missed."); + break; + case 1: + puts("He checked your blow. CLASH! CLANG!"); + break; + case 2: + puts("His filthy tunic hangs by one less thread."); + break; + } + else if (hurt < 10){ + switch(rnd(3)){ + case 0: + puts("He's bleeding."); + break; + case 1: + puts("A trickle of blood runs down his face."); + break; + case 2: + puts("A huge purple bruise is forming on the side of his face."); + break; + } + lifeline++; + } + else if (hurt < 20){ + switch(rnd(3)){ + case 0: + puts("He staggers back quavering."); + break; + case 1: + puts("He jumps back with his hand over the wound."); + break; + case 2: + puts("His shirt falls open with a swath across the chest."); + break; + } + lifeline += 5; + } + else if (hurt < 30){ + switch(rnd(3)){ + case 0: + printf("A bloody gash opens up on his %s side.\n",(rnd(2) ? "left" : "right")); + break; + case 1: + puts("The steel bites home and scrapes along his ribs."); + break; + case 2: + puts("You pierce him, and his breath hisses through clenched teeth."); + break; + } + lifeline += 10; + } + else if (hurt < 40){ + switch(rnd(3)){ + case 0: + puts("You smite him to the ground."); + if (strength - lifeline > 20) + puts("But in a flurry of steel he regains his feet!"); + break; + case 1: + puts("The force of your blow sends him to his knees."); + puts("His arm swings lifeless at his side."); + break; + case 2: + puts("Clutching his blood drenched shirt, he collapses stunned."); + break; + } + lifeline += 20; + } + else { + switch(rnd(3)){ + case 0: + puts("His ribs crack under your powerful swing, flooding his lungs with blood."); + break; + case 1: + puts("You shatter his upheld arm in a spray of blood. The blade continues deep"); + puts("into his back, severing the spinal cord."); + lifeline += 25; + break; + case 2: + puts("With a mighty lunge the steel slides in, and gasping, he falls to the ground."); + lifeline += 25; + break; + } + lifeline += 30; + } + break; + + case BACK: + if (enemy == DARK && lifeline > strength * 0.33){ + puts("He throws you back against the rock and pummels your face."); + if (testbit(inven,AMULET) || testbit(wear,AMULET)){ + printf("Lifting the amulet from you, "); + if (testbit(inven,MEDALION) || testbit(wear,MEDALION)){ + puts("his power grows and the walls of\nthe earth tremble."); + puts("When he touches the medallion, your chest explodes and the foundations of the\nearth collapse."); + puts("The planet is consumed by darkness."); + die(0); + } + if (testbit(inven,AMULET)){ + clearbit(inven,AMULET); + carrying -= objwt[AMULET]; + encumber -= objcumber[AMULET]; + } + else + clearbit(wear,AMULET); + puts("he flees down the dark caverns."); + clearbit(location[position].objects,DARK); + injuries[SKULL] = 1; + followfight = Time; + return (0); + } + else{ + puts("I'm afraid you have been killed."); + die(0); + } + } + else{ + puts("You escape stunned and disoriented from the fight."); + puts("A victorious bellow echoes from the battlescene."); + if (back && position != back) + move(back,BACK); + else if (ahead &&position != ahead) + move(ahead,AHEAD); + else if (left && position != left) + move(left,LEFT); + else if (right && position != right) + move(right,RIGHT); + else + move(location[position].down,AHEAD); + return(0); + } + + case SHOOT: + if (testbit(inven,LASER)){ + if (strength - lifeline <= 50){ + printf("The %s took a direct hit!\n",objsht[enemy]); + lifeline += 50; + } + else { + puts("With his bare hand he deflects the laser blast and whips the pistol from you!"); + clearbit(inven,LASER); + setbit(location[position].objects,LASER); + carrying -= objwt[LASER]; + encumber -= objcumber[LASER]; + } + } + else + puts("Unfortunately, you don't have a blaster handy."); + break; + + case DROP: + case DRAW: + cypher(); + Time--; + break; + + default: + puts("You don't have a chance, he is too quick."); + break; + + } + if (lifeline >= strength){ + printf("You have killed the %s.\n", objsht[enemy]); + if (enemy == ELF || enemy == DARK) + puts("A watery black smoke consumes his body and then vanishes with a peal of thunder!"); + clearbit(location[position].objects,enemy); + power += 2; + notes[JINXED]++; + return(0); + } + puts("He attacks..."); + /* some embellisments */ + hurt = rnd(NUMOFINJURIES) - (testbit(inven,SHIELD) != 0) - (testbit(wear,MAIL) != 0) - (testbit(wear,HELM) != 0); + hurt += (testbit(wear,AMULET) != 0) + (testbit(wear,MEDALION) != 0) + (testbit(wear,TALISMAN) != 0); + hurt = hurt < 0 ? 0 : hurt; + hurt = hurt >= NUMOFINJURIES ? NUMOFINJURIES -1 : hurt; + if (!injuries[hurt]){ + injuries[hurt] = 1; + printf("I'm afraid you have suffered %s.\n", ouch[hurt]); + } + else + puts("You emerge unscathed."); + if (injuries[SKULL] && injuries[INCISE] && injuries[NECK]){ + puts("I'm afraid you have suffered fatal injuries."); + die(0); + } + goto fighton; +} diff --git a/src/games/battlestar/curses.c b/src/games/battlestar/curses.c new file mode 100644 index 0000000..8b92a0f --- /dev/null +++ b/src/games/battlestar/curses.c @@ -0,0 +1,637 @@ +/* + * This source herein may be modified and/or distributed by anybody who + * so desires, with the following restrictions: + * 1.) No portion of this notice shall be removed. + * 2.) Credit shall not be taken for the creation of this source. + * 3.) This code is not to be traded, sold, or used for personal + * gain or profit. + */ + +/* The following is a curses emulation package suitable for the rogue program + * in which it is included. No other suitability is claimed or suspected. + * Only those routines currently needed by this rogue program are included. + * This is being provided for those systems that don't have a suitable + * curses package and want to run this rogue program. + * + * Compile the entire program with -DCURSES to incorporate this package. + * + * The following is NOT supported: + * "%D", "%B", "%n", or "%>" inside a cursor motion (cm) termcap string. + * Terminals in which the cursor motion addresses the row differently from + * the column, as in ":cm=\E%2,%3" or ":cm=\EY%+x;%+y" + * Termcap database stored in the TERMCAP environ variable as returned + * from getenv(). Only the termcap file name can be stored there. + * See the comments for getenv() in machdep.c. + * Terminals without non-destructive backspace. Backspace (^H) is used + * for cursor motion regardless of any termcap entries. + * The ":tc=" termcap entry is ignored. + * + * Suggestions: + * Use line-feed as your termcap "do" entry: ":do=^J", ":do=\012" or + * ":do=\n" This will help cursor motion optimization. If line-feed + * won't work, then a short escape sequence will do. + */ +#include +#include +#include +#include + +#define DROWS 24 +#define DCOLS 80 + +#define BS 010 +#define LF 012 +#define CR 015 +#define ESC '\033' +#define TAB '\011' + +#define ST_MASK 0x80 + +char terminal[DROWS][DCOLS]; +char buffer[DROWS][DCOLS]; + +char cm_esc[16]; +char cm_sep[16]; +char cm_end[16]; +int cm_reverse = 0; +int cm_two = 0; +int cm_three = 0; +int cm_char = 0; +short cm_inc = 0; + +int screen_dirty; +int lines_dirty[DROWS]; +int buf_stand_out = 0; +int term_stand_out = 0; + +int LINES = DROWS; +int COLS = DCOLS; +WINDOW scr_buf; +WINDOW *curscr = &scr_buf; + +int _tty_ch, _res_flg; +struct sgttyb _tty; +int _echoit, _rawmode; + +char *CL = (char *) 0; +char *CM = (char *) 0; +char *UC = (char *) 0; /* UP */ +char *DO = (char *) 0; +char *VS = ""; +char *VE = ""; +char *TI = ""; +char *TE = ""; +char *SO = ""; +char *SE = ""; + +WINDOW *stdscr = (WINDOW *) 1; + +short cur_row; +short cur_col; + +#ifndef ANSI +#define BUFLEN 256 + +static int +tc_tname(fp, term, buf) + FILE *fp; + char *term; + char *buf; +{ + int i, j; + int found = 0; + char *fg; + + while (!found) { + i = 0; + fg = fgets(buf, BUFLEN, fp); + if (fg != NULL) { + if ((buf[0] != '#') && (buf[0] != ' ') && (buf[0] != TAB) && + (buf[0] != CR) && (buf[0] != LF)) + { + while (buf[i] && (!found)) { + j = 0; + while (buf[i] == term[j]) { + i++; + j++; + } + if ((!term[j]) && ((buf[i] == '|') || (buf[i] == ':'))) { + found = 1; + } else { + while (buf[i] && (buf[i] != '|') && (buf[i] != ':')) { + i++; + } + if (buf[i]) { + i++; + } + } + } + } + } else { + break; + } + } + return(found); +} + +static int +is_digit(ch) + int ch; +{ + return((ch >= '0') && (ch <= '9')); +} + +static void +tc_gets(ibuf, tcstr) + char *ibuf; + char **tcstr; +{ + int i, j, k, n; + char obuf[BUFLEN]; + + i = 4; + j = 0; + + while (ibuf[i] && is_digit(ibuf[i])) { + i++; + } + + while (ibuf[i] && (ibuf[i] != ':')) { + if (ibuf[i] == '\\') { + i++; + switch(ibuf[i]) { + case 'E': + obuf[j] = ESC; + i++; + break; + case 'n': + obuf[j] = LF; + i++; + break; + case 'r': + obuf[j] = CR; + i++; + break; + case 'b': + obuf[j] = BS; + i++; + break; + case 't': + obuf[j] = TAB; + i++; + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + n = 0; + k = 0; + while (k < 3 && ibuf[i] && is_digit(ibuf[i])) { + n = (8 * n) + (ibuf[i] - '0'); + i++; + k++; + } + obuf[j] = (char) n; + break; + default: + obuf[j] = ibuf[i]; + i++; + } + } else if (ibuf[i] == '^') { + obuf[j] = ibuf[i+1] - 64; + i += 2; + } else { + obuf[j] = ibuf[i++]; + } + j++; + } + obuf[j] = 0; + *tcstr = malloc(j + 1); + if (! *tcstr) { + perror("malloc"); + exit(1); + } + (void) strcpy(*tcstr, obuf); +} + +static void +tc_gnum(ibuf, n) + char *ibuf; + int *n; +{ + int i, r = 0; + + i = 4; + + while (is_digit(ibuf[i])) { + r = (r * 10) + (ibuf[i] - '0'); + i++; + } + *n = r; +} + +static void +tc_cmget() +{ + int i = 0, j = 0, rc_spec = 0; + + while (CM[i] && (CM[i] != '%') && (j < 15)) { + cm_esc[j++] = CM[i++]; + } + cm_esc[j] = 0; + + while (CM[i] && (rc_spec < 2)) { + if (CM[i] == '%') { + i++; + switch(CM[i]) { + case 'd': + rc_spec++; + break; + case 'i': + cm_inc = 1; + break; + case '2': + cm_two = 1; + rc_spec++; + break; + case '3': + cm_three = 1; + rc_spec++; + break; + case '.': + cm_char = 1; + rc_spec++; + break; + case 'r': + cm_reverse = 1; + break; + case '+': + i++; + cm_inc = CM[i]; + cm_char = 1; + rc_spec++; + break; + } + i++; + } else { + j = 0; + while (CM[i] && (CM[i] != '%')) { + cm_sep[j++] = CM[i++]; + } + cm_sep[j] = 0; + } + } + + j = 0; + if (rc_spec == 2) { + while (CM[i] && (j < 15)) { + cm_end[j++] = CM[i++]; + } + } + cm_end[j] = 0; +} + +static void +tc_gtdata(fp, buf) + FILE *fp; + char *buf; +{ + int i; + int first = 1; + + do { + if (!first) { + if ((buf[0] != TAB) && (buf[0] != ' ')) { + break; + } + } + first = 0; + i = 0; + while (buf[i]) { + while (buf[i] && (buf[i] != ':')) { + i++; + } + if (buf[i] == ':') { + if (!strncmp(buf + i, ":cl=", 4)) { + tc_gets(buf + i, &CL); + } else if (!strncmp(buf + i, ":cm=", 4)) { + tc_gets(buf + i, &CM); + } else if (!strncmp(buf + i, ":up=", 4)) { + tc_gets(buf + i, &UC); + } else if (!strncmp(buf + i, ":do=", 4)) { + tc_gets(buf + i, &DO); + } else if (!strncmp(buf + i, ":vs=", 4)) { + tc_gets(buf + i, &VS); + } else if (!strncmp(buf + i, ":ve=", 4)) { + tc_gets(buf + i, &VE); + } else if (!strncmp(buf + i, ":ti=", 4)) { + tc_gets(buf + i, &TI); + } else if (!strncmp(buf + i, ":te=", 4)) { + tc_gets(buf + i, &TE); + } else if (!strncmp(buf + i, ":so=", 4)) { + tc_gets(buf + i, &SO); + } else if (!strncmp(buf + i, ":se=", 4)) { + tc_gets(buf + i, &SE); + } else if (!strncmp(buf + i, ":li#", 4)) { + tc_gnum(buf + i, &LINES); + } else if (!strncmp(buf + i, ":co#", 4)) { + tc_gnum(buf + i, &COLS); + } + i++; + } + } + } while (fgets(buf, BUFLEN, fp) != NULL); + + if (!CM || !CL) { + fprintf(stderr, "Terminal and termcap must have cm and cl\n"); + exit(1); + } + tc_cmget(); +} +#endif /* ANSI */ + +static void +get_term_info() +{ +#ifdef ANSI + /* Generic ANSI display. */ + LINES = DROWS; + COLS = DCOLS; + + CL = "\33[H\33[2J"; + UC = "\33[A"; + DO = "\12"; + SO = "\33[7m"; + SE = "\33[m"; + + cm_inc = 1; + strcpy (cm_esc, "\33["); + strcpy (cm_sep, ";"); + strcpy (cm_end, "H"); +#else + FILE *fp; + char *term, *tcf; + char buf[BUFLEN]; + char *tc_file = "/etc/termcap"; + + tcf = getenv("TERMCAP"); + if (tcf) { + if (strlen(tcf) > 40) { + fprintf(stderr, "TERMCAP file name too long\n"); + exit(1); + } + tc_file = tcf; + } + + term = getenv("TERM"); + if (! term) { + fprintf(stderr, "Cannot find TERM variable in environ\n"); + exit(1); + } + fp = fopen(tc_file, "r"); + if (! fp) { + fprintf(stderr, "Cannot open TERMCAP file: %s\n", tc_file); + exit(1); + } + + if (! tc_tname(fp, term, buf)) { + fprintf(stderr, "Cannot find TERM type: %s in TERMCAP file: %s", term, + tc_file); + exit(1); + } + tc_gtdata(fp, buf); + fclose(fp); +#endif +} + +WINDOW * +initscr() +{ + savetty(); + clear(); + get_term_info(); + printf("%s%s", TI, VS); + return stdscr; +} + +void +endwin() +{ + printf("%s%s", TE, VE); + resetty(); +} + +int +wmove(w, row, col) + WINDOW *w; + int row, col; +{ + curscr->_cury = row; + curscr->_curx = col; + screen_dirty = 1; + return 0; +} + +int +waddstr(w, str) + WINDOW *w; + char *str; +{ + while (*str) { + addch((int) *str++); + } + return 0; +} + +int +waddch(w, ch) + WINDOW *w; + register char ch; +{ + int row, col; + + row = curscr->_cury; + col = curscr->_curx++; + + if (buf_stand_out) { + ch |= ST_MASK; + } + buffer[row][col] = (char) ch; + lines_dirty[row] = 1; + screen_dirty = 1; + return 0; +} + +static void +put_st_char(ch) + register int ch; +{ + if ((ch & ST_MASK) && (!term_stand_out)) { + ch &= ~ST_MASK; + printf("%s%c", SO, ch); + term_stand_out = 1; + } else if ((!(ch & ST_MASK)) && term_stand_out) { + printf("%s%c", SE, ch); + term_stand_out = 0; + } else { + ch &= ~ST_MASK; + putchar(ch); + } +} + +static void +put_cursor(row, col) + register int row, col; +{ + register int i, rdif, cdif; + int ch, t; + + rdif = (row > cur_row) ? row - cur_row : cur_row - row; + cdif = (col > cur_col) ? col - cur_col : cur_col - col; + + if (((row > cur_row) && DO) || ((cur_row > row) && UC)) { + if ((rdif < 4) && (cdif < 4)) { + for (i = 0; i < rdif; i++) { + printf("%s", ((row < cur_row) ? UC : DO)); + } + cur_row = row; + if (col == cur_col) { + return; + } + } + } + if (row == cur_row) { + if (cdif <= 6) { + for (i = 0; i < cdif; i++) { + ch = (col < cur_col) ? BS : + terminal[row][cur_col + i]; + put_st_char((int) ch); + } + cur_row = row; + cur_col = col; + return; + } + } + cur_row = row; + cur_col = col; + + row += cm_inc; + col += cm_inc; + + if (cm_reverse) { + t = row; + row = col; + col = t; + } + if (cm_two) { + printf("%s%02d%s%02d%s", cm_esc, row, cm_sep, col, cm_end); + } else if (cm_three) { + printf("%s%03d%s%03d%s", cm_esc, row, cm_sep, col, cm_end); + } else if (cm_char) { + printf("%s%c%s%c%s", cm_esc, row, cm_sep, col, cm_end); + } else { + printf("%s%d%s%d%s", cm_esc, row, cm_sep, col, cm_end); + } +} + +int +wrefresh(scr) + WINDOW *scr; +{ + int i, col; + + printf("%s", CL); + cur_row = cur_col = 0; + + for (i = 0; i < DROWS; i++) { + col = 0; + while (col < DCOLS) { + while ((col < DCOLS) && (buffer[i][col] == ' ')) { + col++; + } + if (col < DCOLS) { + put_cursor(i, col); + } + while ((col < DCOLS) && (buffer[i][col] != ' ')) { + put_st_char((int) buffer[i][col]); + cur_col++; + col++; + } + } + } + put_cursor(curscr->_cury, curscr->_curx); + fflush(stdout); + scr = scr; /* make lint happy */ + return 0; +} + +static void +clear_buffers() +{ + register int i, j; + + screen_dirty = 0; + + for (i = 0; i < DROWS; i++) { + lines_dirty[i] = 0; + for (j = 0; j < DCOLS; j++) { + terminal[i][j] = ' '; + buffer[i][j] = ' '; + } + } +} + +int +wclear(w) + WINDOW *w; +{ + printf("%s", CL); + fflush(stdout); + cur_row = cur_col = 0; + move(0, 0); + clear_buffers(); + return 0; +} + +void +mvcur(ly, lx, y, x) + int ly, lx, y, x; +{ + cur_row = ly; + cur_col = ly; + curscr->_cury = y; + curscr->_curx = x; + put_cursor(curscr->_cury, curscr->_curx); + fflush(stdout); +} + +int +delwin(w) + WINDOW *w; +{ + return 0; +} + +int printw (char *fmt, ...) +{ + va_list args; + FILE junk; + char buf[512]; + + va_start (args, fmt); + junk._flag = _IOWRT + _IOSTRG; + junk._ptr = buf; + junk._cnt = 32767; + _doprnt(fmt, args, &junk); + va_end (args); + + putc('\0', &junk); + waddstr(stdscr, buf); + return 0; +} diff --git a/src/games/battlestar/cypher.c b/src/games/battlestar/cypher.c new file mode 100644 index 0000000..aa6c5ab --- /dev/null +++ b/src/games/battlestar/cypher.c @@ -0,0 +1,400 @@ +/* + * Copyright (c) 1983 Regents of the University of California, + * All rights reserved. Redistribution permitted subject to + * the terms of the Berkeley Software License Agreement. + */ +#include "externs.h" + +int +cypher() +{ + register int n; + int junk; + int lflag = -1; + char buffer[10]; + + while (wordtype[wordnumber] == ADJS) + wordnumber++; + while (wordnumber <= wordcount) { + switch(wordvalue[wordnumber]) { + + case UP: + if (location[position].access || wiz || tempwiz) { + if (!location[position].access) + puts("Zap! A gust of wind lifts you up."); + if (!move(location[position].up, AHEAD)) + return(-1); + } else { + puts("There is no way up"); + return(-1); + } + lflag = 0; + break; + + case DOWN: + if (!move(location[position].down, AHEAD)) + return(-1); + lflag = 0; + break; + + case LEFT: + if (!move(left, LEFT)) + return(-1); + lflag = 0; + break; + + case RIGHT: + if (!move(right, RIGHT)) + return(-1); + lflag = 0; + break; + + case AHEAD: + if (!move(ahead, AHEAD)) + return(-1); + lflag = 0; + break; + + case BACK: + if (!move(back, BACK)) + return(-1); + lflag = 0; + break; + + case SHOOT: + if (wordnumber < wordcount && wordvalue[wordnumber+1] == EVERYTHING){ + for (n=0; n < NUMOFOBJECTS; n++) + if (testbit(location[position].objects,n) && *objsht[n]){ + wordvalue[wordnumber+1] = n; + wordnumber = shoot(); + } + wordnumber++; + wordnumber++; + } + else + shoot(); + break; + + case TAKE: + if (wordnumber < wordcount && wordvalue[wordnumber+1] == EVERYTHING){ + for (n=0; n < NUMOFOBJECTS; n++) + if (testbit(location[position].objects,n) && *objsht[n]){ + wordvalue[wordnumber+1] = n; + wordnumber = take(location[position].objects); + } + wordnumber++; + wordnumber++; + } + else + take(location[position].objects); + break; + + case DROP: + + if (wordnumber < wordcount && wordvalue[wordnumber+1] == EVERYTHING){ + for (n=0; n < NUMOFOBJECTS; n++) + if (testbit(inven,n)){ + wordvalue[wordnumber+1] = n; + wordnumber = drop("Dropped"); + } + wordnumber++; + wordnumber++; + } + else + drop("Dropped"); + break; + + + case KICK: + case THROW: + if (wordnumber < wordcount && wordvalue[wordnumber+1] == EVERYTHING){ + for (n=0; n < NUMOFOBJECTS; n++) + if (testbit(inven,n) || + (testbit(location[position].objects, n) && + *objsht[n])) { + wordvalue[wordnumber+1] = n; + wordnumber = throw(wordvalue[wordnumber] == KICK ? "Kicked" : "Thrown"); + } + wordnumber += 2; + } else + throw(wordvalue[wordnumber] == KICK ? "Kicked" : "Thrown"); + break; + + case TAKEOFF: + if (wordnumber < wordcount && wordvalue[wordnumber+1] == EVERYTHING){ + for (n=0; n < NUMOFOBJECTS; n++) + if (testbit(wear,n)){ + wordvalue[wordnumber+1] = n; + wordnumber = takeoff(); + } + wordnumber += 2; + } + else + takeoff(); + break; + + + case DRAW: + + if (wordnumber < wordcount && wordvalue[wordnumber+1] == EVERYTHING){ + for (n=0; n < NUMOFOBJECTS; n++) + if (testbit(wear,n)){ + wordvalue[wordnumber+1] = n; + wordnumber = draw(); + } + wordnumber += 2; + } + else + draw(); + break; + + + case PUTON: + + if (wordnumber < wordcount && wordvalue[wordnumber+1] == EVERYTHING){ + for (n=0; n < NUMOFOBJECTS; n++) + if (testbit(location[position].objects,n) && *objsht[n]){ + wordvalue[wordnumber+1] = n; + wordnumber = puton(); + } + wordnumber += 2; + } + else + puton(); + break; + + case WEARIT: + + if (wordnumber < wordcount && wordvalue[wordnumber+1] == EVERYTHING){ + for (n=0; n < NUMOFOBJECTS; n++) + if (testbit(inven,n)){ + wordvalue[wordnumber+1] = n; + wordnumber = wearit(); + } + wordnumber += 2; + } + else + wearit(); + break; + + + case EAT: + + if (wordnumber < wordcount && wordvalue[wordnumber+1] == EVERYTHING){ + for (n=0; n < NUMOFOBJECTS; n++) + if (testbit(inven,n)){ + wordvalue[wordnumber+1] = n; + wordnumber = eat(); + } + wordnumber += 2; + } + else + eat(); + break; + + + case PUT: + put(); + break; + + + case INVEN: + if (ucard(inven)){ + puts("You are holding:\n"); + for (n=0; n < NUMOFOBJECTS; n++) + if (testbit(inven,n)) + printf("\t%s\n", objsht[n]); + printf("\n= %d kilogram%s (%d%%)\n", carrying, (carrying == 1 ? "." : "s."),(WEIGHT ? carrying*100/WEIGHT : -1)); + printf("Your arms are %d%% full.\n",encumber*100/CUMBER); + } + else + puts("You aren't carrying anything."); + + if (ucard(wear)){ + puts("\nYou are wearing:\n"); + for (n=0; n < NUMOFOBJECTS; n++) + if (testbit(wear,n)) + printf("\t%s\n", objsht[n]); + } + else + puts("\nYou are stark naked."); + if (card(injuries,NUMOFINJURIES)){ + puts("\nYou have suffered:\n"); + for (n=0; n < NUMOFINJURIES; n++) + if (injuries[n]) + printf("\t%s\n",ouch[n]); + printf("\nYou can still carry up to %d kilogram%s\n",WEIGHT,(WEIGHT == 1 ? "." : "s.")); + } + else + puts("\nYou are in perfect health."); + break; + + case USE: + lflag = use(); + break; + + case LOOK: + if (!notes[CANTSEE] || testbit(inven,LAMPON) || testbit(location[position].objects,LAMPON) || matchlight){ + beenthere[position] = 2; + writedes(); + printobjs(); + if (matchlight){ + puts("\nYour match splutters out."); + matchlight = 0; + } + } else + puts("I can't see anything."); + return(-1); + break; + + case SU: + if (wiz || tempwiz){ + printf("\nRoom (was %d) = ", position); + if (fgets(buffer,10,stdin)) /*ignore*/; + if (*buffer != '\n') + sscanf(buffer,"%d", &position); + printf("Time (was %d) = ",Time); + if (fgets(buffer,10,stdin)) /*ignore*/; + if (*buffer != '\n') + sscanf(buffer,"%d", &Time); + printf("Fuel (was %d) = ",fuel); + if (fgets(buffer,10,stdin)) /*ignore*/; + if (*buffer != '\n') + sscanf(buffer,"%d", &fuel); + printf("Torps (was %d) = ",torps); + if (fgets(buffer,10,stdin)) /*ignore*/; + if (*buffer != '\n') + sscanf(buffer,"%d", &torps); + printf("CUMBER (was %d) = ",CUMBER); + if (fgets(buffer,10,stdin)) /*ignore*/; + if (*buffer != '\n') + sscanf(buffer,"%d", &CUMBER); + printf("WEIGHT (was %d) = ",WEIGHT); + if (fgets(buffer,10,stdin)) /*ignore*/; + if (*buffer != '\n') + sscanf(buffer,"%d",&WEIGHT); + printf("Clock (was %d) = ",clk); + if (fgets(buffer,10,stdin)) /*ignore*/; + if (*buffer != '\n') + sscanf(buffer,"%d",&clk); + printf("Wizard (was %d, %d) = ",wiz, tempwiz); + if (fgets(buffer,10,stdin)) /*ignore*/; + if (*buffer != '\n'){ + sscanf(buffer,"%d",&junk); + if (!junk) + tempwiz = wiz = 0; + } + printf("\nDONE.\n"); + return(0); + } + else + puts("You aren't a wizard."); + break; + + case SCORE: + printf("\tPLEASURE\tPOWER\t\tEGO\n"); + printf("\t%3d\t\t%3d\t\t%3d\n\n",pleasure,power,ego); + printf("This gives you the rating of %s in %d turns.\n",rate(),Time); + printf("You have visited %d out of %d rooms this run (%d%%).\n",card(beenthere,NUMOFROOMS),NUMOFROOMS,card(beenthere,NUMOFROOMS)*100/NUMOFROOMS); + break; + + case KNIFE: + case KILL: + murder(); + break; + + case UNDRESS: + case RAVAGE: + ravage(); + break; + + case SAVE: + save(); + break; + + case FOLLOW: + lflag = follow(); + break; + + case GIVE: + give(); + break; + + case KISS: + kiss(); + break; + + case LOVE: + love(); + break; + + case RIDE: + lflag = ride(); + break; + + case DRIVE: + lflag = drive(); + break; + + case LIGHT: + light(); + break; + + case LAUNCH: + if (!launch()) + return(-1); + else + lflag = 0; + break; + + case LANDIT: + if (!land()) + return(-1); + else + lflag = 0; + break; + + case TIME: + chime(); + break; + + case SLEEP: + zzz(); + break; + + case DIG: + dig(); + break; + + case JUMP: + lflag = jump(); + break; + + case BURY: + bury(); + break; + + case SWIM: + puts("Surf's up!"); + break; + + case DRINK: + drink(); + break; + + case QUIT: + die(0); + + default: + puts("How's that?"); + return(-1); + break; + + + } + if (wordnumber < wordcount && *words[wordnumber++] == ',') + continue; + else return(lflag); + } + return(lflag); +} diff --git a/src/games/battlestar/dayfile.c b/src/games/battlestar/dayfile.c new file mode 100644 index 0000000..4f8fab8 --- /dev/null +++ b/src/games/battlestar/dayfile.c @@ -0,0 +1,1175 @@ +/* + * Copyright (c) 1983 Regents of the University of California, + * All rights reserved. Redistribution permitted subject to + * the terms of the Berkeley Software License Agreement. + */ +#include "externs.h" + +#define strstr(x) x + +struct room dayfile[] = { + { 0 }, + { strstr("You are in the main hangar."), + { 5, 2, 9, 3, 3, 1, 0, 0 }, +strstr("This is a huge bay where many fighters and cargo craft lie. Alarms are \n\ +sounding and fighter pilots are running to their ships. Above is a gallery\n\ +overlooking the bay. The scream of turbo engines is coming from +. The rest\n\ +of the hangar is +. There is an exit +.*\n") }, + { strstr("This is the landing bay."), + { 1, 0, 10, 0, 0, 0, 0, 0 }, +strstr("Ships are landing here, some heavily damaged. Enemy fighters continually\n\ +strafe this vulnerable port. The main hangar is +, *\n\ +There is an exit +.*\n") }, + { strstr("You are in the gallery."), + { 4, 0, 0, 0, 0, 0, 1, 0 }, +strstr("From here a view of the entire landing bay reveals that our battlestar\n\ +is near destruction. Fires are spreading out of control and laser blasts\n\ +lick at the shadows. The control room is +. ***\n") }, + { strstr("You are in the control room."), + { 0, 3, 0, 0, 0, 0, 5, 0 }, +strstr("Several frantic technicians are flipping switches wildly but otherwise\n\ +this room seems fairly deserted. A weapons locker has been left open.\n\ +A staircase leads down. * There is a way -. ** \n") }, + { strstr("This is the launch room."), + { 6, 1, 7, 0, 4, 1, 0, 0 }, +strstr("From the launch tubes here fighters blast off into space. Only one is left,\n\ +and it is guarded by two fierce men. A staircase leads up from here.\n\ +There is a cluttered workbench +. From the main hangar come sounds of great\n\ +explosions. The main hangar is +. The viper launch tubes are to the -.*\n") }, + { strstr("You are at the workbench."), + { 0, 5, 7, 0, 0, 0, 0, 0 }, +strstr("Strange and unwieldy tools are arranged here including a lunch box \n\ +and pneumatic wrenches and turbo sprocket rockets.*\n\ +The launch room is +. The remaining viper is +.*\n") }, + { strstr("You are in the viper launch tube."), + { 0, 5, 0, 5, 32, 0, 0, 0 }, +strstr("The two guards are eyeing you warily! ****\n") }, + { strstr("This is a walk in closet."), + { 22, 0, 0, 0, 0, 0, 0, 0 }, +strstr("A wardrobe of immense magnitude greets the eye. Furs and robes of kings\n\ +hang on rack after rack. Silken gowns, capes woven with spun gold, and \n\ +delicate synthetic fabrics are stowed here. The bedroom is +.***\n") }, + { strstr("You are in a wide hallway leading to the main hangar."), + { 0, 0, 11, 1, 0, 0, 0, 0 }, +strstr("The walls and ceiling here have been blasted through in several places.\n\ +It looks as if quite a battle has been fought for possession of the landing bay\n\ +Gaping corpses litter the floor.** The hallway continues +.\n\ +The main hangar is +.\n") }, + { strstr("You are in a wide hallway leading to the landing bay."), + { 0, 0, 12, 2, 0, 0, 0, 0 }, +strstr("Most of the men and supplies needed in the main hangar come through this\n\ +corridor, but the wounded are forced to use it too. It very dank and\n\ +crowded here, and the floor is slippery with blood.**\n\ +The hallway continues -. The landing bay is +.\n") }, + { strstr("The hallway is very congested with rubble here."), + { 0, 0, 0, 9, 13, 1, 0, 0 }, +strstr("It is too choked with broken steel girders and other debris to continue\n\ +on much farther. Above, the ceiling has caved in and it is possible to \n\ +climb up. There is not much chance to go -, -, or -.\n\ +But the hallway seems clearer +.\n") }, + { strstr("A wide hallway and a more narrow walkway meet here."), + { 14, 15, 0, 10, 0, 0, 0, 0 }, +strstr("The intersection is crowded with the many wounded who have come up\n\ +the wide hallway and continued +. The walkway is less crowded +.\n\ +The wide hallway goes *-.\n") }, + { strstr("You are in what was once an elegant stateroom."), + { 16, 0, 0, 0, 0, 0, 11, 0 }, +strstr("Whoever lived in this stateroom, he and his female companion\n\ +were mercilessly slain in their sleep. Clothes, trinkets and personal\n\ +belongings are scattered all across the floor. Through a hole in the\n\ +collapsed floor I can see a hallway below. A door is +.***\n") }, + { strstr("You're at the entrance to the sick bay."), + { 17, 12, 18, 0, 0, 0, 0, 0 }, +strstr("The wounded are entering the sick bay in loudly moaning files.\n\ +The walkway continues - and +. A doctor is motioning for you to \n\ +come to the -. *\n") }, + { strstr("You're in the walkway."), + { 12, 19, 0, 0, 0, 0, 0, 0 }, +strstr("Most of the men and supplies were coming from the armory. The walkway\n\ +continues -. The armory is +.**\n") }, + { strstr("These are the executive suites of the battlestar."), + { 20, 13, 21, 22, 23, 1, 24, 0 }, +strstr("Luxurious staterooms carpeted with crushed velvet and adorned with beaten\n\ +gold open onto this parlor. A wide staircase with ivory banisters leads\n\ +up or down. This parlor leads into a hallway +. The bridal suite is +.\n\ +Other rooms lie - and +.\n") }, + { strstr("You're in a long dimly lit hallway."), + { 0, 14, 25, 0, 0, 0, 0, 0 }, +strstr("This part of the walkway is deserted. There is a dead end +. The\n\ +entrance to the sickbay is +. The walkway turns sharply -.*\n") }, + { strstr("This is the sick bay."), + { 0, 0, 0, 14, 0, 0, 0, 0 }, +strstr("Sinister nurses with long needles and pitiful aim probe the depths of suffering\n\ +here. Only the mortally wounded receive medical attention on a battlestar,\n\ +but afterwards they are thrown into the incinerators along with the rest.**\n\ +Nothing but death and suffering +. The walkway is +.\n") }, + { strstr("You're in the armory."), + { 15, 26, 0, 0, 0, 0, 0, 0 }, +strstr("An armed guard is stationed here 365 sectars a yarn to protect the magazine.\n\ +The walkway is +. The magazine is +.**\n") }, + { strstr("The hallway ends here at the presidential suite."), + { 27, 16, 0, 0, 0, 0, 0, 0 }, +strstr("The door to this suite is made from solid magnesium, and the entryway is\n\ +inlaid with diamonds and fire opals. The door is ajar +. The hallway\n\ +goes -.**\n") }, + { strstr("This is the maid's utility room."), + { 0, 0, 0, 16, 0, 0, 0, 0 }, +strstr("What a gruesome sight! The maid has been brutally drowned in a bucket of\n\ +Pine Sol and repeatedly stabbed in the back with a knife.***\n\ +The hallway is +.\n") }, + { strstr("This is a luxurious stateroom."), + { 0, 8, 16, 0, 0, 0, 0, 0 }, +strstr("The floor is carpeted with a soft animal fur and the great wooden furniture\n\ +is inlaid with strips of platinum and gold. Electronic equipment built\n\ +into the walls and ceiling is flashing wildly. The floor shudders and\n\ +the sounds of dull explosions rumble though the room. From a window in\n\ +the wall + comes a view of darkest space. There is a small adjoining\n\ +room +, and a doorway +.*\n") }, + { strstr("You are at the entrance to the dining hall."), + { 0, 0, 28, 0, 0, 0, 16, 0 }, +strstr("A wide staircase with ebony banisters leads down here.**\n\ +The dining hall is to the -.*\n") }, + { strstr("This was once the first class lounge."), + { 0, 0, 29, 0, 16, 1, 0, 0 }, +strstr("There is much rubble and destruction here that was not apparent elsewhere.\n\ +The walls and ceilings have broken in in some places. A staircase with\n\ +red coral banisters leads up. It is impossible to go - or -.\n\ +It seems a little clearer +.*\n") }, + { strstr("You are in a narrow stairwell."), + { 0, 17, 0, 0, 30, 1, 0, 0 }, +strstr("These dusty and decrepit stairs lead up. There is no way -. The\n\ +hallway turns sharply -.**\n") }, + { strstr("You are in the magazine."), + { 19, 0, 0, 0, 0, 0, 0, 0 }, +strstr("Rows and rows of neatly stacked ammunition for laser pistols and grenade\n\ +launchers are here. The armory is +.***\n") }, + { strstr("You're in the presidential suite."), + { 0, 20, 0, 0, 0, 0, 0, 0 }, +strstr("Apparently the president has been assassinated. A scorched figure lies\n\ +face downward on the carpet clutching his chest.*\n\ +The hallway leads -.**\n") }, + { strstr("You are in the dining hall."), + { 0, 30, 31, 23, 0, 0, 0, 0 }, +strstr("This was the seen of a mass suicide. Hundreds of ambassadors and assorted\n\ +dignitaries sit slumped over their breakfast cereal. I suppose the news\n\ +of the cylon attack killed them. There is a strange chill in this room. I\n\ +would not linger here. * The kitchen is +. Entrances + and +.\n") }, + { strstr("The debris is very thick here."), + { 0, 11, 0, 24, 0, 0, 0, 0 }, +strstr("Broken furniture, fallen girders, and other rubble block the way.\n\ +There is not much chance to continue -, -, or -.\n\ +It would be best to go -.\n") }, + { strstr("You are in the kitchen."), + { 28, 0, 0, 0, 0, 0, 0, 0 }, +strstr("This room is full of shining stainless steel and burnished bronze cookware. An \n\ +assortment of tropical fruits and vegetables as well as fine meats and cheeses \n\ +lies on a sterling platter. The chef, unfortunately, has been skewered like a \n\ +side of beef. The dining room is +. ** There is a locked door +.\n") }, + { strstr("You are in an arched entry leading to the dining room."), + { 0, 0, 0, 28, 0, 0, 0, 0 }, +strstr("The door leading out is bolted shut from the outside and is very strong.***\n\ +The dining room is +.\n") }, + { strstr("You are in space."), + { 33, 34, 35, 36, 37, 1, 33, 1 }, +strstr("****\n") }, + { strstr("You are in space."), + { 38, 32, 39, 40, 41, 1, 42, 1 }, +strstr("****\n") }, + { strstr("You are in space."), + { 32, 44, 45, 46, 47, 1, 48, 1 }, +strstr("****\n") }, + { strstr("You are in space."), + { 40, 45, 49, 32, 50, 1, 51, 1 }, +strstr("****\n") }, + { strstr("You are in space."), + { 41, 46, 32, 52, 53, 1, 54, 1 }, +strstr("****\n") }, + { strstr("You are in space."), + { 42, 47, 50, 53, 55, 1, 32, 1 }, +strstr("****\n") }, + { strstr("You are in space."), + { 43, 48, 51, 54, 32, 1, 56, 1 }, +strstr("****\n") }, + { strstr("You are in space."), + { 57, 33, 40, 41, 42, 1, 43, 1 }, +strstr("****\n") }, + { strstr("You are in space."), + { 39, 35, 57, 33, 58, 1, 59, 1 }, +strstr("****\n") }, + { strstr("You are in space."), + { 39, 36, 33, 59, 60, 1, 61, 1 }, +strstr("****\n") }, + { strstr("You are in space."), + { 39, 37, 58, 60, 62, 1, 33, 1 }, +strstr("****\n") }, + { strstr("You are in space."), + { 39, 38, 59, 61, 33, 1, 63, 1 }, +strstr("****\n") }, + { strstr("You are in space."), + { 34, 64, 45, 46, 47, 1, 48, 1 }, +strstr("****\n") }, + { strstr("You are in space."), + { 35, 44, 49, 34, 50, 1, 51, 1 }, +strstr("****\n") }, + { strstr("You are in space."), + { 36, 44, 34, 52, 53, 1, 54, 1 }, +strstr("****\n") }, + { strstr("You are in space."), + { 37, 44, 50, 53, 55, 1, 34, 1 }, +strstr("****\n") }, + { strstr("You are in space."), + { 38, 44, 51, 54, 34, 1, 56, 1 }, +strstr("****\n") }, + { strstr("You are in space."), + { 49, 49, 52, 35, 49, 1, 49, 1 }, +strstr("****\n") }, + { strstr("You are in space."), + { 58, 47, 49, 37, 55, 1, 35, 1 }, +strstr("****\n") }, + { strstr("You are in space."), + { 59, 48, 49, 38, 35, 1, 56, 1 }, +strstr("****\n") }, + { strstr("You are in space."), + { 52, 52, 36, 49, 52, 1, 52, 1 }, +strstr("****\n") }, + { strstr("You are in space."), + { 60, 46, 37, 52, 55, 1, 36, 1 }, +strstr("****\n") }, + { strstr("You are in space."), + { 61, 48, 38, 52, 36, 1, 56, 1 }, +strstr("****\n") }, + { strstr("You are in space."), + { 62, 55, 55, 55, 56, 1, 37, 1 }, +strstr("****\n") }, + { strstr("You are in space."), + { 56, 56, 56, 56, 38, 1, 55, 1 }, +strstr("****\n") }, + { strstr("You are in space."), + { 65, 39, 57, 57, 57, 1, 57, 1 }, +strstr("****\n") }, + { strstr("You are in space."), + { 39, 50, 49, 42, 62, 1, 40, 1 }, +strstr("****\n") }, + { strstr("You are in space."), + { 39, 51, 49, 43, 40, 1, 63, 1 }, +strstr("****\n") }, + { strstr("You are in space."), + { 39, 53, 43, 59, 62, 1, 41, 1 }, +strstr("****\n") }, + { strstr("You are in space."), + { 39, 54, 43, 59, 41, 1, 56, 1 }, +strstr("****\n") }, + { strstr("You are in space."), + { 39, 55, 62, 62, 56, 1, 42, 1 }, +strstr("****\n") }, + { strstr("You are in space."), + { 39, 56, 35, 36, 43, 1, 55, 1 }, +strstr("****\n") }, + { strstr("You are in space."), + { 44, 66, 66, 66, 66, 1, 66, 1 }, +strstr("****\n") }, + { strstr("You are in space."), + { 67, 57, 67, 67, 67, 1, 67, 1 }, +strstr("****\n") }, + { strstr("You are in space."), + { 64, 68, 68, 68, 68, 1, 68, 1 }, +strstr("****\n") }, + { strstr("You are orbiting a small blue planet."), + { 67, 67, 67, 67, 65, 1, 69, 1 }, +strstr("****\n") }, + { strstr("You are orbiting a tropical planet."), + { 68, 68, 68, 68, 66, 1, 70, 1 }, +strstr("****\n") }, + { strstr("You are flying through a dense fog."), + { 69, 69, 69, 69, 69, 1, 69, 1 }, +strstr("A cold grey sea of mist is swirling around the windshield and water droplets\n\ +are spewing from the wingtips. Ominous shadows loom in the darkness and it\n\ +feels as if a trap is closing around us. I have lost all sense of direction.\n\ +****\n") }, + { strstr("You are approaching an island."), + { 71, 72, 73, 74, 68, 1, 0, 1 }, +strstr("Coconut palms, sword ferns, orchids, and other lush vegetation drape this\n\ +jagged island carved seemingly from pure emerald and set in a turquoise\n\ +sea. The land rises sharply +. There is a nice beach* +.*\n") }, + { strstr("You are flying over a mountainous region."), + { 75, 73, 76, 77, 68, 1, 0, 1 }, +strstr("Below is a magnificent canyon with deep gorges, high pinnacles and\n\ +waterfalls plummeting hundreds of feet into mist. Everything in sight\n\ +is carpeted with a tropical green.* The ocean is +.**\n") }, + { strstr("You are flying over the ocean."), + { 74, 78, 78, 78, 68, 1, 0, 1 }, +strstr("You bank over the water and your wingtips dip low to the green waves. The\n\ +sea is very shallow here and the white coral beds beneath us teem with \n\ +colorful fish.****\n") }, + { strstr("You are flying over the beach."), + { 71, 72, 79, 74, 68, 1, 80, 1 }, +strstr("A warm gentle surf caresses the white coral beach here. The land rises\n\ +sharply +.* The beach is lost in low cliffs and rocks +.*\n") }, + { strstr("You are flying over a large lagoon."), + { 81, 72, 73, 82, 68, 1, 0, 1 }, +strstr("Encircled by a coral reef, the palms and ferns in this sheltered spot\n\ +have grown down to the water's very brink which winds tortuously inland.\n\ +There looks like a small village +.***\n") }, + { strstr("You are flying over a gently sloping plane."), + { 83, 71, 84, 85, 68, 1, 0, 1 }, +strstr("This is where several alluvial fans and ancient lava flows have run\n\ +together forming a fertile plane choked with vegetation. It would be\n\ +impossible to land safely here.* The terrain is more rugged +.**\n") }, + { strstr("You are flying through a gorge."), + { 0, 0, 86, 71, 68, 1, 102, 1 }, +strstr("This narrow, steep sided canyon is lined with waving ferns. The floor is of\n\ +light gravel with many freshets pouring from the walls and running along it.\n\ +The gorge leads to the sea** +, and to a tumultuous origin +.\n") }, + { strstr("You are flying over a plantation."), + { 85, 81, 71, 88, 68, 1, 89, 1 }, +strstr("Rows of palms, papayas, mangoes, kiwi, as well as smaller fields of sugar\n\ +cane and pineapple are growing here. It might be possible to land here, but\n\ +I wouldn't advise it.* There looks like two small settlements + \n\ +and *+.\n") }, + { strstr("You are over the ocean."), + { 72, 78, 79, 74, 68, 1, 0, 1 }, +strstr("The deep green swells foam and roll into the shore **+*.\n") }, + { strstr("You are flying along the coast."), + { 86, 72, 90, 73, 68, 1, 91, 1 }, +strstr("The coastline here is very rocky with little or no sand. The surf in some\n\ +places is violent and explodes in a shower of sparkling spray.\n\ +There is a winding road below which closely follows the shore. ****\n") }, + { strstr("This is a beautiful coral beach."), + { 106, 0, 107, 108, 73, 0, 0, 0 }, +strstr("Fine silver sand kissed lightly by warm tropical waters stretches at least\n\ +30 meters here from the ocean to under gently swaying palms +.***\n") }, + { strstr("You are flying over a small fishing village."), + { 77, 74, 71, 82, 68, 1, 92, 1 }, +strstr("A few thatched huts a short distance from the water and row of more modern\n\ +bungalows on either side of a dirt road are all that is here. The road\n\ +continues on ***+.\n") }, + { strstr("You are flying over a clearing."), + { 88, 72, 74, 87, 68, 1, 93, 1 }, +strstr("There is a dock here (big enough for a seaplane) leading to a grassy\n\ +meadow and a road. Some people are having a party down there. Below is\n\ +a good landing site. ****\n") }, + { strstr("You are flying over the shore."), + { 94, 75, 95, 96, 68, 1, 0, 1 }, +strstr("Rocky lava flows or coarse sandy beaches are all that is here except for\n\ +sparse herbs and weeds.****\n") }, + { strstr("You are flying in a wide valley."), + { 95, 97, 86, 75, 68, 1, 98, 1 }, +strstr("This is a shallow valley yet the floor is obscured by a thick mist.\n\ +The valley opens to the sea +. The mist grows thicker +.**\n") }, + { strstr("You are flying near the shore."), + { 96, 77, 75, 99, 68, 1, 0, 1 }, +strstr("Very tall palm trees growing in neatly planted rows march off from the \n\ +water here towards the hills and down to the flat lands *+.*\n\ +There is a nice beach +.\n") }, + { strstr("You are flying around the very tip of the island."), + { 95, 79, 90, 84, 68, 1, 0, 1 }, +strstr("There is no beach here for sheer cliffs rise several hundred feet\n\ +to a tree covered summit. Far below, the blue sea gnaws voraciously at\n\ +the roots of these cliffs. The island bends around +** and +.\n") }, + { strstr("You are flying along the coastline."), + { 99, 82, 88, 100, 68, 1, 101, 1 }, +strstr("There is a narrow strip of sand here lined with ferns and shrubs, but very\n\ +few trees. The beach is barley wide enough to land on. The beach continues\n\ +on -.* There are some buildings +.*\n") }, + { strstr("You are flying over several cottages and buildings"), + { 99, 82, 77, 87, 68, 1, 103, 1 }, +strstr("The grounds here are landscaped with palm trees, ferns, orchids, and beds of\n\ +flowering plumeria and antheriums. Directly below is a small ornate white\n\ +house with a belltower, a lush green lawn, and a spurting fountain.\n\ +Small dirt roads go + and +.**\n") }, + { strstr("You are in a field of sugar cane."), + { 109, 110, 111, 112, 77, 0, 0, 0 }, +strstr("These strong, thick canes give little shelter but many cuts and scrapes.\n\ +There are some large trees ***+.\n") }, + { strstr("You are flying over the ocean."), + { 95, 78, 90, 86, 68, 1, 0, 1 }, +strstr("The water is a placid turquoise and so clear that fish and sharks\n\ +many fathoms below are clearly visible.****\n") }, + { strstr("You are on the coast road."), + { 113, 114, 115, 116, 79, 0, 0, 0 }, +strstr("The road winds close to the shore here and the sound of crashing surf is\n\ +deafening.* The water is +. The road continues - and -.\n") }, + { strstr("You are on the main street of the village."), + { 117, 118, 119, 120, 81, 0, 0, 0 }, +strstr("Thatched roofs and outrigger canoes, palm trees and vacation bungalows, and\n\ +comely natives in a tropical paradise all make this a fantasy come true.\n\ +There is an open bungalow +.* The road continues - and -.\n") }, + { strstr("You are at the sea plane dock."), + { 121, 122, 123, 124, 82, 0, 0, 0 }, +strstr("Native girls with skin of gold, clad only in fragrant leis and lavalavas,\n\ +line the dockside to greet you. A couple of ukulele plucking islanders and a\n\ +keyboard player are adding appropriate music. A road crosses the clearing \n\ ++*. There are some tables set up +.*\n") }, + { strstr("You are flying over the ocean."), + { 94, 83, 95, 96, 68, 1, 0, 1 }, +strstr("Sea weeds and kelp surge in the waves off shore here. The ocean becomes \n\ +much deeper +.***\n") }, + { strstr("You are flying along the coast."), + { 94, 84, 86, 83, 68, 1, 0, 1 }, +strstr("The land is very low here with a river running into the sea +. There\n\ +is a wide valley opening up +. The very tip of the island is +.*\n") }, + { strstr("You are flying along the coast."), + { 94, 85, 83, 99, 68, 1, 0, 1 }, +strstr("There are some secluded sandy stretches of beach here, but too many rocky\n\ +outcroppings of lava to land. There is a nicer beach ***+.\n") }, + { strstr("You are lost in a sea of fog."), + { 97, 104, 97, 97, 97, 1, 0, 1 }, +strstr("What have you gotten us into?\n\ +I cant see a thing! ****\n") }, + { strstr("You are on a gravel wash."), + { 125, 126, 127, 128, 84, 0, 0, 0 }, +strstr("The sound of cascading water is the background for a diluted chorus of \n\ +gurgling, splashing, and enchantingly delicate singing. Great billows\n\ +of steam are rising *+.**\n") }, + { strstr("You are flying over a wide beach."), + { 96, 88, 85, 87, 68, 1, 105, 1 }, +strstr("Unlike the leeward beaches, few coconut palms grow here but a well groomed\n\ +lawn and garden with traipsing stone walks leads down to the sand.*\n\ +There are some buildings +. Some trees are growing +.*\n") }, + { strstr("You are flying over the ocean."), + { 100, 100, 87, 100, 68, 1, 0, 1 }, +strstr("The sea is a perfectly clear blue with a white sandy bottom. No coral\n\ +grows underwater here, but the force of the waves is broken by the steep\n\ +incline.****\n") }, + { strstr("You are on a narrow strip of sand."), + { 129, 130, 131, 0, 87, 0, 0, 0 }, +strstr("Rather coarse sand makes this beach very steep and only a few meters wide.\n\ +A fresh ocean breeze is rustling the ferns **+.*\n") }, + { strstr("This is Fern Canyon."), + { 0, 0, 132, 133, 76, 0, 0, 0 }, +strstr("Delicate waving ferns flourish here, suckled by warm water dripping from \n\ +every fissure and crevice in the solid rock walls.\n\ +The canyon winds **-, and -.\n") }, + { strstr("This is the front lawn."), + { 134, 135, 136, 137, 88, 0, 0, 0 }, +strstr("There is a small fountain here where the driveway meets the lawn.\n\ +Across the driveway, +, is an ornate white house with and elegant \n\ +woodworking. The bargeboards are carved with fylfots, the ancient \n\ +symbols of luck. Even a bell tower has been built here.* There is a \n\ +road + which turns into the driveway.*\n") }, + { strstr("You have just crossed the crest of a mountain."), + { 97, 79, 86, 71, 68, 1, 0, 1 }, +strstr("The fog vanished mysteriously as we flew over the crest.*\n\ +Far + I can see the ocean.**\n") }, + { strstr("You are on a sandy beach."), + { 138, 139, 140, 0, 99, 0, 0, 0 }, +strstr("This is the only good beach on the weather side of the island. Fine coral\n\ +sand, a fresh sea breeze, and dramatic surf add to its appeal.**\n\ +Stone steps lead to the gardens +.*\n") }, + { strstr("You are among palm trees near the shore."), + { 141, 80, 142, 143, 73, 0, 0, 0 }, +strstr("Arching coconut palms laden with fruit provide a canopy for the glistening\n\ +white sand and sparse grasses growing here. The forest grows denser +.\n\ +The ocean is +.**\n") }, + { strstr("You are walking along the beach."), + { 144, 0, 145, 80, 73, 0, 0, 0 }, +strstr("The warm tropical waters nuzzle your ankles as you walk. Above is a fiercely\n\ +blue sky. The slope of the sand is so gentle that two hundred meters\n\ +offshore the water is only knee deep.** There are some rocks +.*\n") }, + { strstr("You are walking along the beach."), + { 146, 0, 80, 147, 73, 0, 0, 0 }, +strstr("Many beautiful shells have been washed up here including bright yellow \n\ +cowries, chocolate colored murex, orange conchs, striped tritons and the\n\ +deadly cone shells.****\n") }, + { strstr("You are in a papaya grove."), + { 148, 89, 149, 150, 77, 0, 0, 0 }, +strstr("Green slender trees no taller than three meters bulge with their\n\ +orange succulent fruit. There are some tall trees +.***\n") }, + { strstr("You are in a field of pineapple."), + { 89, 151, 152, 153, 77, 0, 0, 0 }, +strstr("The sharp dagger like pineapple leaves can pierce the flesh and hold fast\n\ +a skewered victim with tiny barbs.* The field ends +.**\n") }, + { strstr("You are in a field of kiwi plants."), + { 149, 154, 155, 89, 77, 0, 0, 0 }, +strstr("Round hairy fruit hang from staked vines here. There are some trees +\n\ +and +. The field ends in a dirt road +.*\n") }, + { strstr("You are in a large grove of coconuts."), + { 150, 153, 89, 156, 77, 0, 0, 0 }, +strstr("These trees are much taller than any growing near the shore plus the fat,\n\ +juicy coconuts have been selectively cultivated. The grove continues\n\ ++, +, *and +.\n") }, + { strstr("You are in the woods."), + { 157, 91, 158, 116, 79, 0, 0, 0 }, +strstr("Tropical undergrowth makes the going rough here. Sword ferns give no strong\n\ +foot hold and the dangling vines would gladly throttle one. Strange cackling\n\ +noises are coming from somewhere +.***\n") }, + { strstr("You are at the shore."), + { 91, 0, 159, 145, 79, 0, 0, 0 }, +strstr("Explosions of surf jetting out of underwater tunnels here make it\n\ +impossible to climb down to a small cave entrance below. Only at rare\n\ +minus tides would it be possible to enter.*** The beach is better +.\n") }, + { strstr("You are on the coast road."), + { 158, 161, 162, 91, 79, 0, 0, 0 }, +strstr("The road is beginning to turn inland.* I can here the surf +. The road\n\ +continues +.*\n") }, + { strstr("The road winds deeper into the trees."), + { 163, 142, 91, 164, 79, 0, 0, 0 }, +strstr("Only narrow sunbeams filter through the foliage above. The moist rich earth\n\ +has nurtured a myriad of trees, shrubs, and flowers to grow here. The\n\ +road continues - and *- from here.*\n") }, + { strstr("This is the front porch of the bungalow."), + { 165, 92, 0, 0, 81, 0, 0, 0 }, +strstr("These wooden steps and porch are very bucolic. A little woven mat on the \n\ +doorstep reads \"Don't Tread on Me\". The open front door is +.\n\ +A stone walk leads to the main street +.**\n") }, + { strstr("You are on a path leading to the lagoon."), + { 92, 166, 167, 168, 81, 0, 0, 0 }, +strstr("This path trampled fern, grass, sapling, and anything else that got in its\n\ +way.* The water is +.**\n") }, + { strstr("This is a dirt road."), + { 169, 118, 170, 92, 81, 0, 0, 0 }, +strstr("**The road continues on - here for some distance. A village is +.\n") }, + { strstr("You are on a dirt road."), + { 171, 118, 92, 172, 81, 0, 0, 0 }, +strstr("**There is a small village +. The road continues +.\n") }, + { strstr("You are on a dirt road."), + { 173, 93, 174, 175, 82, 0, 0, 0 }, +strstr("The light tan soil of the road contrasts artistically with the lush green\n\ +vegetation and seering blue sky.* There is a clearing and many people +.\n\ +The road continues - and -.\n") }, + { strstr("You are at the seaplane dock."), + { 93, 0, 176, 177, 82, 0, 0, 0 }, +strstr("Several muscular, bronze skinned men greet you warmly as you pass under\n\ +a thatched shelter above the dock here. Polynesian hospitality.\n\ +There is a clearing +.* A trail runs around the lagoon + and +.\n") }, + { strstr("There are some tables on the lawn here."), + { 121, 122, 123, 93, 82, 0, 0, 0 }, +strstr("Hors d'oeuvres, canapes, mixed drinks, and various narcotic drugs along with\n\ +cartons of Di Gel fill the tables to overflowing. Several other guests are\n\ +conversing and talking excitedly****.\n") }, + { strstr("You are nosing around in the bushes."), + { 124, 124, 93, 124, 82, 0, 0, 0 }, +strstr("There is little here but some old beer cans. You are making fools out of\n\ +us in front of the other guests.** It would be best to go -.*\n") }, + { strstr("You are walking in a dry stream bed."), + { 178, 98, 179, 0, 84, 0, 0, 0 }, +strstr("The large cobblestones are difficult to walk on. No sunlight reaches\n\ +below a white canopy of fog seemingly generated from *+. A dirt path \n\ +along the wash is +. A high bank is impossible to climb +.\n") }, + { strstr("You are at the thermal pools."), + { 98, 0, 180, 181, 84, 0, 0, 0 }, +strstr("Several steaming fumaroles and spluttering geysers drenched by icy mountain\n\ +waters from a nearby waterfall heat half a dozen natural pools to a\n\ +delicious 42 degrees. Enchantingly beautiful singing seems to flow from the\n\ +water itself as it tumbles down the falls.*** There is a mossy entrance\n\ +to a cave +.\n") }, + { strstr("You are in the woods."), + { 127, 180, 182, 98, 84, 0, 0, 0 }, +strstr("Coniferous trees girded by wild huckleberries, elderberries, salmonberries\n\ +and thimbleberries enjoy a less tropical climate here in the high mountains.\n\ +*The sound of rushing water is coming from +.**\n") }, + { strstr("You are on a dirt trail."), + { 179, 181, 98, 0, 84, 0, 0, 0 }, +strstr("The trail seems to start here and head -.** High cliffs border the \n\ +trail +.\n") }, + { strstr("You are walking along the beach."), + { 183, 101, 184, 0, 87, 0, 0, 0 }, +strstr("A rather unnerving surf explodes onto the beach here and dashes itself into\n\ +spray on the steep incline. The beach continues + and +.**\n") }, + { strstr("You are walking along the beach."), + { 101, 185, 186, 0, 87, 0, 0, 0 }, +strstr("This is not a very nice beach. The coarse sand hurts my feet.****\n") }, + { strstr("You are walking through some ferns."), + { 184, 186, 187, 101, 87, 0, 0, 0 }, +strstr("This is a wide field growing only ferns and small shrubs.** The \n\ +ocean is *+.\n") }, + { strstr("You are in a narrow canyon."), + { 0, 0, 188, 102, 76, 0, 0, 0 }, +strstr("The steep sides here squeeze a little freshet through a gauntlet like\n\ +series of riffles and pools.****\n") }, + { strstr("The canyon is much wider here."), + { 0, 0, 102, 189, 76, 0, 0, 0 }, +strstr("The sheer rock walls rise 10 meters to the forest above. A slender \n\ +waterfall careens away from the face of the rock high above and showers\n\ +the gravel floor with sparkling raindrops.** The canyon continues -\n\ +and -.\n") }, + { strstr("You are on the front porch of the cottage."), + { 190, 103, 0, 0, 0, 0, 0, 0 }, +strstr("Several giggling native girls came running down the steps as you approached\n\ +and headed on down the road. On the fern rimmed porch is a small table with\n\ +matching white wrought iron chairs cushioned with red velvet. The front\n\ +door leads -. The lawn and fountain are +.**\n") }, + { strstr("You are in a palm grove."), + { 103, 191, 192, 105, 88, 0, 0, 0 }, +strstr("****\n") }, + { strstr("You are on a dirt road."), + { 193, 192, 245, 103, 88, 0, 0, 0 }, +strstr("There is a large village +. The road cleaves a coconut plantation +.\n\ +A small dirt road goes -, and a drive way peals off +.\n") }, + { strstr("You are in a field of small shrubs."), + { 184, 186, 103, 187, 88, 0, 0, 0 }, +strstr("**Pine and other coniferous saplings have been planted here. The rich brown\n\ +soil is well tilled and watered. Across a large lawn, there is a small\n\ +cottage +. I can feel a delicious sea breeze blowing from +.\n") }, + { strstr("The beach is pretty rocky here."), + { 194, 105, 195, 0, 96, 0, 0, 0 }, +strstr("Dangerous surf and lava outcroppings make this a treacherous strand.\n\ +The beach is nicer* +.**\n") }, + { strstr("The beach is almost 10 meters wide here."), + { 105, 183, 196, 0, 99, 0, 0, 0 }, +strstr("The sand has become more coarse and the beach steeper.* It gets \n\ +worse +.**\n") }, + { strstr("You are in the gardens."), + { 195, 196, 197, 105, 99, 0, 0, 0 }, +strstr("Lush green lawns studded with palms and benches stretch as far as the eye\n\ +can see.** A path leads -. Stone steps lead down to the beach +.\n") }, + { strstr("You are on the coast road."), + { 198, 106, 163, 199, 73, 0, 0, 0 }, +strstr("The forest is dense on either side and conceals the road from anyone\n\ +approaching it.** The road continues - and -.\n") }, + { strstr("You are in the forest."), + { 116, 107, 91, 106, 73, 0, 0, 0 }, +strstr("There are trees and ferns all around.****\n") }, + { strstr("You are in the forest."), + { 199, 108, 106, 146, 73, 0, 0, 0 }, +strstr("There are trees and ferns all around.****\n") }, + { strstr("You are in a copse."), + { 142, 107, 145, 80, 0, 0, 0, 0 }, +strstr("This is a secret hidden thicket only noticeable from the beach. Someone\n\ +has been digging here recently.****\n") }, + { strstr("You are at the tide pools."), + { 91, 0, 114, 107, 79, 0, 0, 0 }, +strstr("These rocks and pools are the home for many sea anemones and crustaceans.\n\ +**The surf is very rough +. There is a nice beach +.\n") }, + { strstr("You are in the forest."), + { 199, 108, 143, 0, 73, 0, 0, 0 }, +strstr("This is a shallow depression sheltered from the wind by a thick growth of \n\ +thorny shrubs. It looks like someone has camped here. There is a fire pit\n\ +with some dry sticks and grass nearby.* The beach is +.* The thorny\n\ +shrubs block the way -.\n") }, + { strstr("You are at the mouth of the lagoon."), + { 200, 0, 108, 201, 74, 0, 0, 0 }, +strstr("The beach ends here where the coral reef rises to form a wide lagoon\n\ +bending inland. A path winds around the lagoon to the -.*\n\ +The beach continues on -. Only water lies +.\n") }, + { strstr("You are in a breadfruit grove."), + { 202, 109, 203, 204, 77, 0, 0, 0 }, +strstr("The tall trees bend leisurely in the breeze, holding many round breadfruits\n\ +close to their large serrated leaves. There are coconut palms +,\n\ +*+, and +.\n") }, + { strstr("You are in a grove of mango trees."), + { 203, 111, 205, 109, 77, 0, 0, 0 }, +strstr("The juicy yellow red fruits are nearly ripe on the trees here. There are\n\ +some coconut palms +. There are some vines +. There is a road +.*\n") }, + { strstr("You are in a grove of coconut palms."), + { 204, 112, 109, 206, 77, 0, 0, 0 }, +strstr("All I can see around us are palm trees.****\n") }, + { strstr("You are in a coconut grove."), + { 110, 207, 208, 209, 77, 0, 0, 0 }, +strstr("There are countless trees here.****\n") }, + { strstr("You are in a field of pineapple."), + { 154, 208, 210, 110, 77, 0, 0, 0 }, +strstr("The sharp leaves are cutting me to ribbons. There is a road **+.\n\ +More pineapple +.\n") }, + { strstr("You are in a coconut grove."), + { 112, 209, 110, 211, 77, 0, 0, 0 }, +strstr("There is a field of pineapple **+.*\n") }, + { strstr("You are on the edge of a kiwi and pineapple field."), + { 111, 152, 155, 110, 77, 0, 0, 0 }, +strstr("An irrigation ditch separates the two fields here. There is a road **+.*\n") }, + { strstr("This is a dirt road."), + { 205, 210, 212, 111, 77, 0, 0, 0 }, +strstr("The road runs - and - here.**\n") }, + { strstr("You are in a palm grove."), + { 206, 211, 112, 213, 77, 0, 0, 0 }, +strstr("There are palm trees all around us.****\n") }, + { strstr("You are on the edge of a small clearing."), + { 157, 113, 157, 157, 79, 0, 0, 0 }, +strstr("The ground is rather marshy here and darting in and out of the many tussocks\n\ +is a flock of wild chicken like fowl.****\n") }, + { strstr("You are in the woods."), + { 158, 115, 215, 113, 79, 0, 0, 0 }, +strstr("You have walked a long way and found only trees. ****\n") }, + { strstr("You are walking along the shore."), + { 115, 0, 214, 114, 86, 0, 0, 0 }, +strstr("You are now about 10 meters above the surf on a gently rising cliffside.**\n\ +The land rises +. There is a beach far +.\n") }, + { strstr("You are just inside the entrance to the sea cave."), + { 246, 114, 0, 0, 114, 1, 0, 0 }, +strstr("The sound of water dripping in darkness and the roar of the ocean just outside\n\ +create a very unwelcoming atmosphere inside this cave. Only on rare occasions\n\ +such as this is it possible to enter the forbidden catacombs... The cave\n\ +continues -.***\n") }, + { strstr("You are in a secret nook beside the road."), + { 115, 159, 162, 91, 79, 0, 0, 0 }, +strstr("Hidden from all but the most stalwart snoopers are some old clothes, empty\n\ +beer cans and a trash baggie full of used Huggies and ordure. Lets get\n\ +back to the road +.***\n") }, + { strstr("You are on the coast road."), + { 215, 214, 0, 115, 86, 0, 0, 0 }, +strstr("The road turns abruptly - here, avoiding the cliffs near the shore\n\ ++ and +.*\n") }, + { strstr("You are on a dirt road."), + { 216, 116, 113, 141, 79, 0, 0, 0 }, +strstr("The roadside is choked with broad leaved plants fighting for every breath of\n\ +sunshine. The palm trees are taller than at the shore yet bend over the road \n\ +forming a canopy. The road continues *- and *-.\n") }, + { strstr("You have discovered a hidden thicket near the road."), + { 163, 142, 116, 106, 73, 0, 0, 0 }, +strstr("Stuffed into a little bundle here is a bloody silken robe and many beer cans.\n\ +*Some droplets of blood and a major spill sparkle farther +.\n\ +The road is +.*\n") }, + { strstr("You are in the living room."), + { 0, 117, 217, 218, 0, 0, 0, 0 }, +strstr("A decorative entry with fresh flowers and wall to wall carpeting leads into\n\ +the living room here where a couch and two chairs converse with an end table.\n\ +*The exit is +.* The bedroom is +.\n") }, + { strstr("You are at the lagoon."), + { 118, 0, 167, 168, 81, 0, 0, 0 }, +strstr("There are several outrigger canoes pulled up on a small beach here and a\n\ +catch of colorful fish is drying in the sun. There are paths leading \n\ +off -*, -, and -.\n") }, + { strstr("You are at the lagoon."), + { 118, 0, 170, 166, 81, 0, 0, 0 }, +strstr("This is a grassy little spot near the water. A sightly native girl is frolicing\n\ +in the water close to shore here.** The path continues - and -. \n") }, + { strstr("You are at the lagoon."), + { 118, 0, 166, 172, 81, 0, 0, 0 }, +strstr("The path meanders through tussocks of grass, ferns, and thorny bushes here\n\ +and continues on **- and -.\n") }, + { strstr("You are in the woods."), + { 219, 119, 220, 92, 81, 0, 0, 0 }, +strstr("There are plenty of ferns and thorny bushes here! ****\n") }, + { strstr("You are on a dirt road."), + { 220, 167, 199, 119, 74, 0, 0, 0 }, +strstr("The road winds rather close to a large lagoon here and many sedges and tall\n\ +grasses line the shoulder *+. The road continues - and -.\n") }, + { strstr("You are in the woods beside the road."), + { 221, 120, 92, 222, 81, 0, 0, 0 }, +strstr("The forest grows darker +. The road is +.**\n") }, + { strstr("The road crosses the lagoon here."), + { 222, 0, 120, 174, 81, 0, 0, 0 }, +strstr("Coursing through the trees, the road at this point bridges a watery finger\n\ +of the lagoon.* The water is +. The road continues - and -.\n") }, + { strstr("You are in a coconut palm grove."), + { 223, 121, 224, 225, 82, 0, 0, 0 }, +strstr("The tall palms are planted about 30 feet apart with a hardy deep green grass\n\ +filling the spaces in between. There are tire tracks through the grass. The\n\ +grove continues -. There is a road +.**\n") }, + { strstr("You are walking along a dirt road."), + { 224, 176, 172, 121, 82, 0, 0, 0 }, +strstr("You are nearing the lagoon.** The road continues - and -.\n") }, + { strstr("You are on a dirt road."), + { 225, 177, 121, 226, 82, 0, 0, 0 }, +strstr("The road turns abruptly - here, entering a grove of palm trees.* The road\n\ +also continues - toward the lagoon.*\n") }, + { strstr("You are on a trail running around the lagoon."), + { 172, 0, 0, 122, 82, 0, 0, 0 }, +strstr("The dark waters brush the trail here and the path crosses a bridge +.\n\ +There is deep water + and +. The trail continues -.\n") }, + { strstr("This is the mouth of the lagoon."), + { 175, 0, 122, 227, 82, 0, 0, 0 }, +strstr("The coral reef wraps around a natural bay here to create a wide lagoon which\n\ +winds tortuously inland.** A trail goes around the lagoon +. The beach\n\ +is +.\n") }, + { strstr("You are in a dry stream bed."), + { 0, 125, 0, 0, 84, 0, 0, 0 }, +strstr("The dry wash drains over a tall precipice here into a turbid morass below. The\n\ +most noisome stench imaginable is wafting up to defile our nostrils. Above,\n\ +the lurid sun glows brown through a strange mist.* The only direction \n\ +I'm going is -.**\n") }, + { strstr("You are on a dirt path along the wash."), + { 0, 128, 125, 228, 84, 0, 0, 0 }, +strstr("This path looks more like a deer trail. It scampers away ***+.\n") }, + { strstr("The thermal pools flow into a stream here."), + { 127, 0, 229, 126, 84, 0, 0, 0 }, +strstr("The gurgling hot waters pour over boulders into a swiftly flowing\n\ +stream **+. The pools are +.\n") }, + { strstr("You are at the entrance to a cave."), + { 128, 230, 126, 0, 84, 0, 0, 0 }, +strstr("A tall narrow fissure in the rock cliffs here has become a well traveled\n\ +passage way. A hoof beaten dirt path leads directly into it. A curl of\n\ +steam is trailing from a corner of the fissure's gaping mouth. The path\n\ +leads - and -. The pools are +.*\n") }, + { strstr("You are in the woods."), + { 182, 229, 182, 127, 84, 0, 0, 0 }, +strstr("Wild berry bushes plump with fruit and thorns tangle your every effort to\n\ +proceed.* The sound of rushing water is +.**\n") }, + { strstr("You are walking along the beach."), + { 139, 129, 184, 0, 99, 0, 0, 0 }, +strstr("Some dunes here progress inland and make it impossible to get very far in that\n\ +direction. The beach continues - and -.* The ocean is +.\n") }, + { strstr("You are in the dunes."), + { 183, 101, 184, 129, 87, 0, 0, 0 }, +strstr("The endless rolling and pitching sand dunes are enough to make one very queasy!\n\ +The only way I'm going is ***+.\n") }, + { strstr("This is a lousy beach."), + { 130, 0, 0, 0, 87, 0, 0, 0 }, +strstr("Volcanic and viciously sharp bitted grains of sand here bite like cold steel\n\ +into my tender feet. I refuse to continue on. Let's get out of here. The\n\ +beach is better +.***\n") }, + { strstr("You are in a field of sparse ferns."), + { 131, 185, 187, 130, 87, 0, 0, 0 }, +strstr("The lava rock outcroppings here will support few plants. There is more \n\ +vegetation +. There is a nice beach +.* The ocean is +.\n") }, + { strstr("You are in the woods."), + { 131, 131, 137, 131, 87, 0, 0, 0 }, +strstr("Young trees and tall shrubs grow densely together at this distance from the \n\ +shore.** The trees grow thicker +.*\n") }, + { strstr("The canyon is no wider than a foot here."), + { 0, 0, 0, 132, 0, 0, 0, 0 }, +strstr("The freshet is gushing through the narrow trough, but the canyon has grown\n\ +too narrow to follow it any farther.*** I guess we'll have to go -.\n") }, + { strstr("You are in a narrow part of the canyon."), + { 0, 0, 133, 232, 76, 0, 0, 0 }, +strstr("The two sheer sides are no more than a few meters apart here. There is a stone\n\ +door in the wall +. The gravelly floor runs with tiny rivulets seeping \n\ +from the ground itself.* The canyon continues - and -.\n") }, + { strstr("You are in the drawing room."), + { 0, 134, 0, 0, 0, 0, 0, 0 }, +strstr("Exquisitely decorated with plants and antique furniture of superb\n\ +craftsmanship, the parlor reflects its owners impeccable taste. The tropical\n\ +sun is streaming in through open shutters *+. There doesn't seem \n\ +to be anybody around. A large immaculate oaken desk is visible in the\n\ +study and it even has a old fashioned telephone to complete the decor.**\n") }, + { strstr("You are in a palm grove."), + { 135, 191, 233, 191, 88, 0, 0, 0 }, +strstr("Grassy rows of palms stretch as far as I can see.** There is a road +.*\n") }, + { strstr("You are on a dirt road."), + { 136, 233, 234, 135, 88, 0, 0, 0 }, +strstr("The road winds through a coconut palm grove here. It continues on - \n\ +and -.**\n") }, + { strstr("The road leads to several large buildings here."), + { 235, 136, 236, 237, 88, 0, 0, 0 }, +strstr("There is a clubhouse +,* a large barn and stable +, and a garage of \n\ +similar construct to the barn +.\n") }, + { strstr("This part of the beach is impassable."), + { 0, 138, 0, 0, 96, 0, 0, 0 }, +strstr("The huge rocks and thunderous surf here would pound our frail bodies to pulp\n\ +in an instant.* The only direction I'm going is -.**\n") }, + { strstr("You are in the gardens."), + { 195, 140, 197, 138, 96, 0, 0, 0 }, +strstr("So much green grass is a pleasure to the eyes.****\n") }, + { strstr("You are in the gardens."), + { 140, 183, 197, 139, 99, 0, 0, 0 }, +strstr("Beautiful flowers and shrubs surround a little goldfish pond.****\n") }, + { strstr("You are on a stone walk in the garden."), + { 195, 196, 238, 140, 99, 0, 0, 0 }, +strstr("The walk leads to a road **+.*\n") }, + { strstr("You are in the forest near the road."), + { 198, 141, 216, 198, 73, 0, 0, 0 }, +strstr("There are many thorny bushes here!****\n") }, + { strstr("You are at a fork in the road."), + { 239, 146, 141, 170, 73, 0, 0, 0 }, +strstr("Two roads come together in the forest here. One runs -,* the other \n\ +runs - and -.\n") }, + { strstr("You are on a dirt path around the lagoon."), + { 170, 147, 146, 0, 74, 0, 0, 0 }, +strstr("The still waters reflect bending palms and a cloudless sky. It looks like\n\ +the path runs into a clearing +. The path continues -.**\n") }, + { strstr("You are drowning in the lagoon."), + { 201, 201, 147, 201, 74, 0, 0, 0 }, +strstr("I suggest you get out before you become waterlogged.****\n") }, + { strstr("You are in a coconut palm grove."), + { 202, 148, 203, 204, 77, 0, 0, 0 }, +strstr("****\n") }, + { strstr("You are in a palm grove."), + { 202, 149, 205, 148, 77, 0, 0, 0 }, +strstr("****\n") }, + { strstr("You are in a palm grove."), + { 202, 150, 148, 206, 77, 0, 0, 0 }, +strstr("****\n") }, + { strstr("You are on a dirt road."), + { 203, 155, 212, 149, 77, 0, 0, 0 }, +strstr("*This road ends here at a palm grove but continues on - for quite\n\ +some way.**\n") }, + { strstr("You are in a coconut palm grove."), + { 204, 156, 150, 213, 77, 0, 0, 0 }, +strstr("****\n") }, + { strstr("You are in a coconut grove."), + { 151, 219, 208, 209, 77, 0, 0, 0 }, +strstr("*The grove ends +.**\n") }, + { strstr("You are in a coconut grove."), + { 152, 207, 239, 151, 77, 0, 0, 0 }, +strstr("**There is a dirt road +.*\n") }, + { strstr("You are in a coconut grove."), + { 153, 207, 151, 211, 77, 0, 0, 0 }, +strstr("****\n") }, + { strstr("This is a dirt road."), + { 205, 239, 212, 154, 77, 0, 0, 0 }, +strstr("The road continues - and -.**\n") }, + { strstr("You are in a coconut grove."), + { 153, 209, 153, 213, 77, 0, 0, 0 }, +strstr("****\n") }, + { strstr("You are in the woods near the road."), + { 205, 210, 212, 155, 77, 0, 0, 0 }, +strstr("There are many thorny bushes here!****\n") }, + { strstr("You are in a coconut grove."), + { 213, 213, 156, 234, 88, 0, 0, 0 }, +strstr("***The grove ends in a clearing +.\n") }, + { strstr("You are walking along some high cliffs."), + { 162, 0, 0, 159, 86, 0, 0, 0 }, +strstr("The island bends sharply + here with high cliffs -\n\ +and -. The cliffs are lower +.\n") }, + { strstr("You are at the coast road turn around."), + { 0, 162, 0, 158, 90, 0, 0, 0 }, +strstr("The coast road ends here in a lookout with a view of 100 kilometers of blue\n\ +sea and 100 meters of rugged cliff. Far below the waves crash against rocks.\n\ +****\n") }, + { strstr("You are in the woods near the road."), + { 216, 163, 216, 198, 79, 0, 257, 0 }, +strstr("These thorny bushes are killing me.****\n") }, + { strstr("You are in the kitchen."), + { 0, 0, 0, 165, 0, 0, 0, 0 }, +strstr("A small gas stove and a refrigerator are all the only appliances here. The\n\ +gas oven has been left on and the whole room is reeking with natural gas.\n\ +One spark from a match and.... The door out is ***+.\n") }, + { strstr("You are in the bedroom."), + { 0, 0, 165, 0, 0, 0, 0, 0 }, +strstr("A soft feather comforter on top of layers of Answer blankets make this a very\n\ +luxurious place to sleep indeed. There are also some end tables and a dresser\n\ +here.** The living room is +.*\n") }, + { strstr("You are in the woods."), + { 207, 169, 220, 221, 81, 0, 0, 0 }, +strstr("There seems to be a clearing +.***\n") }, + { strstr("You are in the woods near the road."), + { 219, 170, 239, 169, 81, 0, 0, 0 }, +strstr("*As far as I can tell, there are two roads + and +.*\n") }, + { strstr("You are in the woods."), + { 207, 171, 219, 222, 81, 0, 0, 0 }, +strstr("The forest is clearer +.***\n") }, + { strstr("You are on the lagoon's inland finger."), + { 0, 172, 171, 172, 81, 0, 0, 0 }, +strstr("It is impossible to follow the lagoon any farther inland because of sharp\n\ +and very painful sedges.* The road is +.**\n") }, + { strstr("You are in a grassy coconut grove."), + { 240, 173, 224, 241, 82, 0, 0, 0 }, +strstr("The tall palms provide a perfect canopy for the lush green grass.***\n\ +There is a road +.\n") }, + { strstr("You are near the lagoon's inland finger."), + { 0, 174, 0, 173, 82, 0, 0, 0 }, +strstr("Very sharp sedges make it impossible to follow the lagoon any farther inland.\n\ +*There is a road +.**\n") }, + { strstr("You are on a dirt road."), + { 241, 175, 173, 226, 82, 0, 0, 0 }, +strstr("The road winds through a coconut grove here and continues - and -.**\n") }, + { strstr("You are in the woods near the road."), + { 226, 226, 175, 226, 82, 0, 0, 0 }, +strstr("**The road is +.*\n") }, + { strstr("This is a beach?"), + { 227, 227, 177, 0, 82, 0, 0, 0 }, +strstr("Hard jagged rocks that pierce with every footstep hardly comprise a beach.**\n\ +Let's go -.*\n") }, + { strstr("The trail is lost in the woods here."), + { 241, 241, 179, 241, 84, 0, 0, 0 }, +strstr("I suppose the animals that use this trail all depart in different directions\n\ +when they get this far into the woods.** The trail goes -.*\n") }, + { strstr("You are on the bank of a stream."), + { 182, 0, 242, 180, 84, 0, 0, 0 }, +strstr("The stream falls over several small boulders here and continues on **-.*\n") }, + { strstr("You are just inside the cave."), + { 181, 267, 0, 0, 0, 0, 0, 0 }, +strstr("A steamy hot breath is belching from the depths of the earth within.* The\n\ +cave continues -.**\n") }, + { strstr("You are just inside the cave entrance."), + { 274, 0, 0, 0, 0, 0, 0, 0 }, +strstr("The air is hot and sticky inside. The cave continues -. There is a \n\ +stone door in the wall +. A wooden sign in the dust reads in old elven\n\ +runes, \"GSRF KDIRE NLVEMP!\".**\n") }, + { strstr("You are at the edge of a huge chasm."), + { 0, 0, 189, 0, 76, 0, 0, 0 }, +strstr("Several hundred feet down I can see the glimmer of placid water. The\n\ +rivulets drain over the edge and trickle down into the depths. It is \n\ +impossible to climb down without a rope.** The canyon continues -.*\n") }, + { strstr("You are on a dirt road."), + { 192, 241, 240, 191, 88, 0, 0, 0 }, +strstr("The road winds through a coconut grove here. The road continues on -\n\ +and -.**\n") }, + { strstr("You are in a coconut palm grove near the road."), + { 193, 233, 213, 192, 88, 0, 0, 0 }, +strstr("***The road is +.\n") }, + { strstr("You are at the clubhouse."), + { 0, 193, 0, 0, 0, 0, 0, 0 }, +strstr("The clubhouse is built over the most inland part of the lagoon. Tropical\n\ +bananas and fragrant frangipani grow along the grassy shore. Walking across\n\ +the short wooden bridge, we enter. Along one wall is a bar with only a few\n\ +people seated at it. The restaurant and dance floor are closed off with\n\ +a 2 inch nylon rope. ****\n") }, + { strstr("You are in the stables."), + { 0, 0, 0, 193, 0, 0, 0, 0 }, +strstr("Neighing horses snacking on hay and oats fill the stalls on both sides of\n\ +the barn. It is rather warm in here but that is not the most offensive\n\ +part. The old boards of the barn part just enough to let in dust laden\n\ +shafts of light. Flies swarm overhead and strafe the ground for dung.\n\ +My nose is beginning to itch. ****\n") }, + { strstr("You are in the old garage."), + { 0, 0, 193, 0, 0, 0, 0, 0 }, +strstr("This is an old wooden building of the same vintage as the stables. Beneath\n\ +a sagging roof stand gardening tools and greasy rags. Parked in the center\n\ +is an underpowered Plymouth Volare' with a red and white striped golf cart\n\ +roof. ****\n") }, + { strstr("You are on a dirt road."), + { 197, 197, 243, 197, 85, 0, 0, 0 }, +strstr("The road leads to a beautiful formal garden laced with stone walks and tropical\n\ +flowers and trees.** The road continues -. A walk leads -.\n") }, + { strstr("You are on a dirt road."), + { 210, 199, 198, 220, 73, 0, 0, 0 }, +strstr("The road runs - and -.**\n") }, + { strstr("You are in a coconut grove near the road."), + { 234, 223, 234, 233, 88, 0, 0, 0 }, +strstr("***The road is +.\n") }, + { strstr("You are on a dirt road."), + { 233, 225, 223, 226, 82, 0, 0, 0 }, +strstr("The road continues - and -.**\n") }, + { strstr("The stream plummets over a cliff here."), + { 182, 0, 0, 229, 84, 0, 0, 0 }, +strstr("Falling 10 agonizing meters into spray, only droplets of the stream are\n\ +left to dance off the floor below. I thought I saw a sparkle of gold\n\ +at the bottom of the falls, but now it is gone. There is no way down,\n\ +even with a strong rope. ****\n") }, + { strstr("You are on a dirt road."), + { 0, 0, 244, 238, 85, 0, 0, 0 }, +strstr("**The road continues - and -.\n") }, + { strstr("You are on a dirt road."), + { 0, 245, 0, 243, 88, 0, 0, 0 }, +strstr("*The road continues -* and -.\n") }, + { strstr("You are on a dirt road."), + { 244, 234, 213, 136, 88, 0, 0, 0 }, +strstr("The road goes -* and *-.\n") }, + { strstr("You are in a low passage."), + { 247, 160, 0, 0, 0, 0, 0, 0 }, +strstr("The passage is partially flooded here and it may be hazardous to proceed.\n\ +Water is surging from the tunnel and heading out to sea. Strange moaning\n\ +noises rise above the rushing of the water. They are as thin as a whispering\n\ +wind yet penetrate to my very soul. I think we have come too far...\n\ +The passage continues -.***\n") }, + { strstr("The walls are very close together here."), + { 248, 0, 0, 0, 0, 0, 0, 0 }, +strstr("I can barely squeeze through the jagged opening. Slimy sea weeds provide\n\ +no footing at all. This tunnel seems to be an ancient lava tube. There is\n\ +a large room -.***\n") }, + { strstr("You are in the cathedral room."), + { 249, 251, 249, 251, 0, 0, 0, 0 }, +strstr("Your light casts ghostly shadows on the walls but cannot pierce the \n\ +engulfing darkness overhead. The sound of water dripping echoes in the void.\n\ +*I can see no passages leading out of this room. We have definitely\n\ +come too far.*** \n") }, + { strstr("You are walking through a very round tunnel."), + { 252, 0, 0, 0, 252, 1, 0, 0 }, +strstr("The round walls of this tunnel are amazingly smooth to the touch. A little\n\ +trickle of water flows down the center. The tunnel climbs steadily +.\n\ +The cave is beginning to flood again! Let's get out of here! ***\n") }, + { strstr("You are in the cathedral anteroom."), + { 0, 0, 0, 248, 253, 1, 0, 0 }, +strstr("This small chamber with a flat stone floor is to one side of the cathedral \n\ +room. We appear to be at the bottom of a tall narrow shaft. There are many \n\ +puddles of water here. A staircase hewn from solid rock and black lava \n\ +leads up.*** The cathedral room is +.\n") }, + { strstr("You are in a wide chamber."), + { 0, 0, 248, 254, 0, 0, 0, 0 }, +strstr("Water is sprinkling from the ceiling here. A shallow pool populated by a \n\ +myriad of blind white creatures sparkles in your light. Tiny shrimp and\n\ +crabs scurry away, frightened by the blinding rays.** The cave \n\ +continues - and -.\n") }, + { strstr("You are at the top of a sloping passage."), + { 0, 0, 255, 256, 257, 1, 0, 0 }, +strstr("There is much algae growing here, both green and brown specimens. \n\ +Water from an underground sea surges and splashes against the slope of\n\ +the rock. The walls glisten with shiny minerals. High above, light\n\ +filters in through a narrow shaft.** A hallway here runs -\n\ +and -.\n") }, + { strstr("You are in an elaborately tiled room."), + { 0, 0, 258, 0, 0, 0, 250, 0 }, +strstr("Large colorful tiles plate the floor and walls. The ceiling is a mosaic\n\ +of gems set in gold. Hopefully it is only our footsteps that are echoing in\n\ +this hollow chamber.** The room continues -. A stone staircase\n\ +leads down.*\n") }, + { strstr("You are at a dead end."), + { 0, 0, 251, 0, 0, 0, 0, 0 }, +strstr("The walls here are alive with dark mussels. They click their shells menacingly\n\ +if we disturb them. ** The only exit is +.*\n") }, + { strstr("The tunnel is very low here."), + { 0, 0, 259, 252, 0, 0, 0, 0 }, +strstr("I practically have to crawl on my knees to pass through this opening. The\n\ +air is stiflingly damp, but I can't hear any sounds of water dripping.**\n\ +The crawlspace continues -. The tunnel seems wider +.\n") }, + { strstr("This is the supply room."), + { 0, 0, 252, 0, 0, 0, 0, 0 }, +strstr("Picks and shovels line the walls here, as well as hard hats, boxes of\n\ +dynamite, and a cartload of very high grade gold and silver ore.** \n\ +A tunnel leads off +.*\n") }, + { strstr("You have found a secret entrance to the catacombs."), + { 0, 0, 0, 0, 216, 1, 252, 0 }, +strstr("I have a sickening feeling that we should not have entered the catacombs.\n\ +Below is a wet, seaweed covered floor. Above is a way out. ****\n") }, + { strstr("You are in the catacombs."), + { 0, 0, 260, 253, 0, 0, 0, 0 }, +strstr("Ornate tombs and piles of treasure line the walls. Long spears with many\n\ +blades, fine swords and coats of mail, heaps of coins, jewelry, pottery, \n\ +and golden statues are tribute of past kings and queens.** The catacombs\n\ +continue - and -.\n") }, + { strstr("You are crawling on your stomach."), + { 0, 0, 261, 255, 0, 0, 0, 0 }, +strstr("The passage is quite narrow and jagged, but the rock is no longer lava.\n\ +It appears to be a form of granite.** The crawlspace continues -, \n\ +but I would just as soon go -.\n") }, + { strstr("You are in the Sepulcher."), + { 0, 0, 0, 258, 0, 0, 0, 0 }, +strstr("A single tomb is here. Encrusted with diamonds and opals, and secured with \n\ +straps of a very hard, untarnished silver, this tomb must be of a great king.\n\ +Vases overflowing with gold coins stand nearby. A line of verse on the wall\n\ +reads, \"Three he made and gave them to his daughters.\"****\n") }, + { strstr("The passage is wider here."), + { 0, 0, 0, 259, 0, 0, 0, 0 }, +strstr("You are at the top of a flooded shaft. About a meter below the edge,\n\ +dark water rises and falls to the rhythm of the sea. A ladder goes\n\ +down into water here.*** A small crawlspace goes -.\n") }, + { strstr("You are at the bottom of a ladder."), + { 0, 0, 0, 0, 261, 1, 263, 0 }, +strstr("This is a narrow platform to rest on before we continue either up or down this\n\ +rickety wooden ladder.****\n") }, + { strstr("You are standing in several inches of water."), + { 264, 0, 265, 266, 262, 1, 0, 0 }, +strstr("This seems to be a working mine. Many different tunnels wander off following\n\ +glowing veins of precious metal. The floor is flooded here since we must\n\ +be nearly at sea level. A ladder leads up. ****\n") }, + { strstr("The tunnel here is blocked by broken rocks."), + { 0, 263, 0, 0, 0, 0, 0, 0 }, +strstr("The way is blocked, but if you had some dynamite, we might be able to blast our\n\ +way through.* The passage goes -.**\n") }, + { strstr("The tunnel is too flooded to proceed."), + { 0, 0, 0, 263, 0, 0, 0, 0 }, +strstr("Hidden shafts could swallow us if we tried to continue on down this tunnel.\n\ +The flooding is already up to my waist. Large crystals overhead shimmer\n\ +rainbows of reflected light.*** Let's go -.\n") }, + { strstr("The mine is less flooded here."), + { 0, 0, 263, 0, 0, 0, 0, 0 }, +strstr("A meandering gold laden vein of quartz and blooming crystals of diamonds\n\ +and topaz burst from the walls of the cave. A passage goes -.***\n") }, + { strstr("You are inside the cave."), + { 230, 268, 0, 0, 0, 0, 0, 0 }, +strstr("A hot steam swirls around our heads, and the walls are warm to the touch.\n\ +The trail winds + and +.**\n") }, + { strstr("You are in a rather large chamber."), + { 267, 0, 0, 269, 0, 0, 269, 0 }, +strstr("Beds of ferns and palm leaves make several cozy nests along the walls. In the\n\ +center of the room is a throne of gold and silver which pulls out into a bed\n\ +of enormous size.*** A passageway leads down to the -.\n") }, + { strstr("You are walking along the edge of a huge abyss."), + { 0, 0, 268, 0, 268, 1, 270, 0 }, +strstr("Steam is rising in great clouds from the immeasurable depths. A very narrow\n\ +trail winds down.** There is a tunnel +.*\n") }, + { strstr("You are on the edge of a huge abyss."), + { 0, 0, 0, 0, 269, 1, 271, 0 }, +strstr("The trail winds farther down.****\n") }, + { strstr("You are winding your way along the abyss."), + { 0, 0, 0, 0, 270, 1, 272, 0 }, +strstr("The trail continues up and down.****\n") }, + { strstr("You are on a wide shelf near the steamy abyss."), + { 0, 273, 0, 0, 271, 1, 0, 0 }, +strstr("The stifling hot cave seems even hotter to me, staring down into this misty \n\ +abyss. A trail winds up.* A passageway leads -.**\n") }, + { strstr("You are in a wide tunnel leading to a fuming abyss."), + { 272, 274, 0, 0, 0, 0, 0, 0 }, +strstr("The passageway winds through many beautiful formations of crystals and\n\ +sparkling minerals. The tunnel continues - and -.**\n") }, + { strstr("You are in a tunnel."), + { 273, 231, 0, 0, 0, 0, 0, 0 }, +strstr("It is very warm in here. The smell of steam and hot rocks permeates the place.\n\ +The cave continues - and -.**\n") }, + { strstr("You are at the bottom of a pit."), + { 0, 0, 0, 0, 232, 0, 0, 0 }, +strstr("I can see daylight far up at the mouth of the pit. A cool draft wafts down.\n\ +There doesn't seem to be any way out, and I don't remember how we came in.\n\ +If you had a rope it might be possible to climb out. ****\n") }, +}; diff --git a/src/games/battlestar/dayobjs.c b/src/games/battlestar/dayobjs.c new file mode 100644 index 0000000..e7e4c11 --- /dev/null +++ b/src/games/battlestar/dayobjs.c @@ -0,0 +1,106 @@ +/* + * Copyright (c) 1983 Regents of the University of California, + * All rights reserved. Redistribution permitted subject to + * the terms of the Berkeley Software License Agreement. + */ +#include "externs.h" + +struct objs dayobjs[] = { + { 236, HORSE }, + { 237, CAR }, + { 275, POT }, + { 275, BAR }, + { 275, BLOCK }, + { 260, COINS }, + { 266, DARK }, + { 235, TIMER }, + { 51, 51 }, + { 59, 51 }, + { 48, 51 }, + { 66, 52 }, + { 65, 52 }, + { 19, BOMB }, + { 167, NATIVE }, + { 21, KNIFE }, + { 30, KNIFE }, + { 30, CLEAVER }, + { 260, SWORD }, + { 70, LAND }, + { 71, LAND }, + { 72, LAND }, + { 73, LAND }, + { 74, LAND }, + { 75, LAND }, + { 76, LAND }, + { 77, LAND }, + { 78, LAND }, + { 79, LAND }, + { 81, LAND }, + { 82, LAND }, + { 83, LAND }, + { 84, LAND }, + { 85, LAND }, + { 86, LAND }, + { 87, LAND }, + { 88, LAND }, + { 90, LAND }, + { 95, LAND }, + { 96, LAND }, + { 97, LAND }, + { 99, LAND }, + { 100, LAND }, + { 104, LAND }, + { 172, WOODSMAN }, + { 172, DEADWOOD }, + { 172, MALLET }, + { 146, ELF }, + { 146, HALBERD }, + { 146, SHIELD }, + { 190, TWO_HANDED }, + { 190, POTION }, + { 142, BROAD }, + { 258, MAIL }, + { 258, HELM }, + { 21, MAID }, + { 7, VIPER }, + { 216, SHOES }, + { 64, CYLON }, + { 36, CYLON }, + { 49, CYLON }, + { 8, ROBE }, + { 13, AMULET }, + { 20, LASER }, + { 126, BATHGOD }, + { 26, GRENADE }, + { 256, GRENADE }, + { 237, CHAIN }, + { 237, COMPASS }, + { 218, LEVIS }, + { 164, MACE }, + { 137, SHOVEL }, + { 11, COINS }, + { 24, MATCHES }, + { 235, MATCHES }, + { 93, MAN }, + { 109, PAPAYAS }, + { 110, PINEAPPLE }, + { 152, PINEAPPLE }, + { 154, PINEAPPLE }, + { 111, KIWI }, + { 149, MANGO }, + { 112, COCONUTS }, + { 150, COCONUTS }, + { 151, COCONUTS }, + { 153, COCONUTS }, + { 192, COCONUTS }, + { 204, COCONUTS }, + { 207, COCONUTS }, + { 209, COCONUTS }, + { 213, COCONUTS }, + { 240, COCONUTS }, + { 218, RING }, + { 130, BRACELET }, + { 93, GIRL }, + { 268, LAMPON }, + { 0 }, +}; diff --git a/src/games/battlestar/doprnt.c b/src/games/battlestar/doprnt.c new file mode 100644 index 0000000..c5ed28d --- /dev/null +++ b/src/games/battlestar/doprnt.c @@ -0,0 +1,203 @@ +/* +Copyright (c) 2013, Alexey Frunze +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +The views and conclusions contained in the software and documentation are those +of the authors and should not be interpreted as representing official policies, +either expressed or implied, of the FreeBSD Project. +*/ + +#include +#include +#include + +int _doprnt (char const *fmt, va_list pp, FILE *stream) +{ + int cnt = 0; + const char* p; + const char* phex = "0123456789abcdef"; + char s[1/*sign*/+10/*magnitude*/+1/*\0*/]; // up to 11 octal digits in 32-bit numbers + char* pc; + int n, sign, msign; + int minlen = 0, len; + int leadchar; + + for (p = fmt; *p != '\0'; p++) + { + if (*p != '%' || p[1] == '%') + { + fputc(*p, stream); + p = p + (*p == '%'); + cnt++; + continue; + } + p++; + minlen = 0; + msign = 0; + if (*p == '+') { msign = 1; p++; } + else if (*p == '-') { msign = -1; p++; } + leadchar = ' '; + if (*p >= '0' && *p <= '9') + { + if (*p == '0') + leadchar = '0'; + while (*p >= '0' && *p <= '9') + minlen = minlen * 10 + *p++ - '0'; + if (msign < 0) + minlen = -minlen; + msign = 0; + } + if (!msign) + { + if (*p == '+') { msign = 1; p++; } + else if (*p == '-') { msign = -1; p++; } + } + switch (*p) + { + case 'c': + while (minlen > 1) { fputc(' ', stream); cnt++; minlen--; } + fputc(va_arg(pp, int), stream); + while (-minlen > 1) { fputc(' ', stream); cnt++; minlen++; } + cnt++; + break; + case 's': + pc = va_arg(pp, char*); + len = 0; + if (pc) + len = strlen(pc); + while (minlen > len) { fputc(' ', stream); cnt++; minlen--; } + if (len) + while (*pc != '\0') + { + fputc(*pc++, stream); + cnt++; + } + while (-minlen > len) { fputc(' ', stream); cnt++; minlen++; } + break; + case 'i': + case 'd': + pc = &s[sizeof s - 1]; + *pc = '\0'; + len = 0; + n = va_arg(pp, int); + sign = 1 - 2 * (n < 0); + do + { + *--pc = '0' + (n - n / 10 * 10) * sign; + n = n / 10; + len++; + } while (n); + if (sign < 0) + { + *--pc = '-'; + len++; + } + else if (msign > 0) + { + *--pc = '+'; + len++; + msign = 0; + } + while (minlen > len) { fputc(leadchar, stream); cnt++; minlen--; } + while (*pc != '\0') + { + fputc(*pc++, stream); + cnt++; + } + while (-minlen > len) { fputc(' ', stream); cnt++; minlen++; } + break; + case 'u': + pc = &s[sizeof s - 1]; + *pc = '\0'; + len = 0; + n = va_arg(pp, int); + do + { + unsigned nn = n; + *--pc = '0' + nn % 10; + n = nn / 10; + len++; + } while (n); + if (msign > 0) + { + *--pc = '+'; + len++; + msign = 0; + } + while (minlen > len) { fputc(leadchar, stream); cnt++; minlen--; } + while (*pc != '\0') + { + fputc(*pc++, stream); + cnt++; + } + while (-minlen > len) { fputc(' ', stream); cnt++; minlen++; } + break; + case 'X': + phex = "0123456789ABCDEF"; + // fallthrough + case 'p': + case 'x': + pc = &s[sizeof s - 1]; + *pc = '\0'; + len = 0; + n = va_arg(pp, int); + do + { + *--pc = phex[n & 0xF]; + n = (n >> 4) & ((1 << (8 * sizeof n - 4)) - 1); // drop sign-extended bits + len++; + } while (n); + while (minlen > len) { fputc(leadchar, stream); cnt++; minlen--; } + while (*pc != '\0') + { + fputc(*pc++, stream); + cnt++; + } + while (-minlen > len) { fputc(' ', stream); cnt++; minlen++; } + break; + case 'o': + pc = &s[sizeof s - 1]; + *pc = '\0'; + len = 0; + n = va_arg(pp, int); + do + { + *--pc = '0' + (n & 7); + n = (n >> 3) & ((1 << (8 * sizeof n - 3)) - 1); // drop sign-extended bits + len++; + } while (n); + while (minlen > len) { fputc(leadchar, stream); cnt++; minlen--; } + while (*pc != '\0') + { + fputc(*pc++, stream); + cnt++; + } + while (-minlen > len) { fputc(' ', stream); cnt++; minlen++; } + break; + default: + return -1; + } + } + + return cnt; +} diff --git a/src/games/battlestar/externs.h b/src/games/battlestar/externs.h new file mode 100644 index 0000000..88ffb16 --- /dev/null +++ b/src/games/battlestar/externs.h @@ -0,0 +1,339 @@ +/* + * Copyright (c) 1983 Regents of the University of California, + * All rights reserved. Redistribution permitted subject to + * the terms of the Berkeley Software License Agreement. + */ + +/* @(#)externs.h 1.3.1 1996/10/26 */ + +#include +#include +#include +#include +#include + +#define PATH(x) "/games/lib/"#x +#define logfile PATH(battlestar.log) +#define BATTLESTRINGS PATH(battle_strings) + +#define BITS (8 * sizeof (int)) + +#define OUTSIDE (position > 68 && position < 246 && position != 218) +#define rnd(x) (rand() % (x)) +#define max(a,b) ((a) < (b) ? (b) : (a)) +#define testbit(array, index) (array[index/BITS] & (1 << (index % BITS))) +#define setbit(array, index) (array[index/BITS] |= (1 << (index % BITS))) +#define clearbit(array, index) (array[index/BITS] &= ~(1 << (index % BITS))) + + /* well known rooms */ +#define FINAL 275 +#define GARDEN 197 +#define POOLS 126 +#define DOCK 93 + + /* word types */ +#define VERB 0 +#define OBJECT 1 +#define NOUNS 2 +#define PREPS 3 +#define ADJS 4 +#define CONJ 5 + + /* words numbers */ +#define KNIFE 0 +#define SWORD 1 +#define LAND 2 +#define WOODSMAN 3 +#define TWO_HANDED 4 +#define CLEAVER 5 +#define BROAD 6 +#define MAIL 7 +#define HELM 8 +#define SHIELD 9 +#define MAID 10 +#define BODY 10 +#define VIPER 11 +#define LAMPON 12 +#define SHOES 13 +#define CYLON 14 +#define PAJAMAS 15 +#define ROBE 16 +#define AMULET 17 +#define MEDALION 18 +#define TALISMAN 19 +#define DEADWOOD 20 +#define MALLET 21 +#define LASER 22 +#define BATHGOD 23 +#define NORMGOD 24 +#define GRENADE 25 +#define CHAIN 26 +#define ROPE 27 +#define LEVIS 28 +#define MACE 29 +#define SHOVEL 30 +#define HALBERD 31 +#define COMPASS 32 +#define CRASH 33 +#define ELF 34 +#define FOOT 35 +#define COINS 36 +#define MATCHES 37 +#define MAN 38 +#define PAPAYAS 39 +#define PINEAPPLE 40 +#define KIWI 41 +#define COCONUTS 42 +#define MANGO 43 +#define RING 44 +#define POTION 45 +#define BRACELET 46 +#define GIRL 47 +#define GIRLTALK 48 +#define DARK 49 +#define TIMER 50 +#define CHAR 53 +#define BOMB 54 +#define DEADGOD 55 +#define DEADTIME 56 +#define DEADNATIVE 57 +#define NATIVE 58 +#define HORSE 59 +#define CAR 60 +#define POT 61 +#define BAR 62 +#define BLOCK 63 +#define NUMOFOBJECTS 64 + /* non-objects below */ +#define UP 1000 +#define DOWN 1001 +#define AHEAD 1002 +#define BACK 1003 +#define RIGHT 1004 +#define LEFT 1005 +#define TAKE 1006 +#define USE 1007 +#define LOOK 1008 +#define QUIT 1009 +#define NORTH 1010 +#define SOUTH 1011 +#define EAST 1012 +#define WEST 1013 +#define SU 1014 +#define DROP 1015 +#define TAKEOFF 1016 +#define DRAW 1017 +#define PUTON 1018 +#define WEARIT 1019 +#define PUT 1020 +#define INVEN 1021 +#define EVERYTHING 1022 +#define AND 1023 +#define KILL 1024 +#define RAVAGE 1025 +#define UNDRESS 1026 +#define THROW 1027 +#define LAUNCH 1028 +#define LANDIT 1029 +#define LIGHT 1030 +#define FOLLOW 1031 +#define KISS 1032 +#define LOVE 1033 +#define GIVE 1034 +#define SMITE 1035 +#define SHOOT 1036 +#define ON 1037 +#define OFF 1038 +#define TIME 1039 +#define SLEEP 1040 +#define DIG 1041 +#define EAT 1042 +#define SWIM 1043 +#define DRINK 1044 +#define DOOR 1045 +#define SAVE 1046 +#define RIDE 1047 +#define DRIVE 1048 +#define SCORE 1049 +#define BURY 1050 +#define JUMP 1051 +#define KICK 1052 + + /* injuries */ +#define ARM 6 /* broken arm */ +#define RIBS 7 /* broken ribs */ +#define SPINE 9 /* broken back */ +#define SKULL 11 /* fractured skull */ +#define INCISE 10 /* deep incisions */ +#define NECK 12 /* broken NECK */ +#define NUMOFINJURIES 13 + + /* notes */ +#define CANTLAUNCH 0 +#define LAUNCHED 1 +#define CANTSEE 2 +#define CANTMOVE 3 +#define JINXED 4 +#define DUG 5 +#define NUMOFNOTES 6 + + /* fundamental constants */ +#define NUMOFROOMS 275 +#define NUMOFWORDS ((NUMOFOBJECTS + BITS - 1) / BITS) +#define LINELENGTH 81 + +#define TODAY 0 +#define TONIGHT 1 +#define CYCLE 100 + + /* initial variable values */ +#define TANKFULL 250 +#define TORPEDOES 10 +#define MAXWEIGHT 60 +#define MAXCUMBER 10 + +struct room { +#ifdef EXT_MESSAGE_FILE + unsigned short name; +#else + char *name; +#endif + unsigned short link[8]; +#define north link[0] +#define south link[1] +#define east link[2] +#define west link[3] +#define up link[4] +#define access link[5] +#define down link[6] +#define flyhere link[7] +#ifdef EXT_MESSAGE_FILE + unsigned short desc; +#else + char *desc; +#endif + unsigned int objects[NUMOFWORDS]; +}; +extern struct room dayfile[]; +extern struct room nightfile[]; +struct room *location; + + /* object characteristics */ +#ifdef EXT_MESSAGE_FILE +unsigned objdes[NUMOFOBJECTS]; +#else +char *objdes[NUMOFOBJECTS]; +#endif +char *objsht[NUMOFOBJECTS]; +char *ouch[NUMOFINJURIES]; +int objwt[NUMOFOBJECTS]; +int objcumber[NUMOFOBJECTS]; + + /* current input line */ +#define NWORD 20 /* words per line */ +char words[NWORD][15]; +int wordvalue[NWORD]; +int wordtype[NWORD]; +int wordcount, wordnumber; + +char *truedirec(), *rate(); +char *getcom(), *getword(); + + /* state of the game */ +int Time; +int position; +int direction; +int left, right, ahead, back; +int clk, fuel, torps; +int carrying, encumber; +int rythmn; +int followfight; +int ate; +int snooze; +int meetgirl; +int followgod; +int godready; +int win; +int wintime; +int wiz; +int tempwiz; +int matchlight, matchcount; +int loved; +int pleasure, power, ego; +int WEIGHT; +int CUMBER; +int notes[NUMOFNOTES]; +unsigned int inven[NUMOFWORDS]; +unsigned int wear[NUMOFWORDS]; +char beenthere[NUMOFROOMS+1]; +char injuries[NUMOFINJURIES]; + +char uname[9]; + +struct wlist { + char *string; + int value, article; + struct wlist *next; +}; +#define HASHSIZE 256 +#define HASHMUL 81 +#define HASHMASK (HASHSIZE - 1) +struct wlist *hashtab[HASHSIZE]; +extern struct wlist wlist[]; + +struct objs { + short room; + short obj; +}; +extern struct objs dayobjs[]; +extern struct objs nightobjs[]; + +int cypher(void); +int zzz(void); +int fight(int enemy, int strength); +int visual(void); +int take(unsigned int from[]); +int drop(char *name); +int wearit(void); +int card(char *array, int size); +int ucard(unsigned *array); +int move(int thataway, int token); +int shoot(void); +int throw(char *name); +int takeoff(void); +int draw(void); +int puton(void); +int eat(void); +int put(void); +int use(void); +int follow(void); +int give(void); +int ride(void); +int drive(void); +int launch(void); +int land(void); +int jump(void); + +void initialize(int startup); +void news(void); +void crash(void); +void writedes(void); +void printobjs(void); +void whichway(struct room here); +void parse(void); +void newway(int thisway); +void die(int); +void live(void); +void wordinit(void); +void save(void); +void restore(void); +void murder(void); +void ravage(void); +void kiss(void); +void love(void); +void light(void); +void chime(void); +void dig(void); +void bury(void); +void drink(void); +void strprt(int n); diff --git a/src/games/battlestar/fly.c b/src/games/battlestar/fly.c new file mode 100644 index 0000000..027b6cc --- /dev/null +++ b/src/games/battlestar/fly.c @@ -0,0 +1,257 @@ +/* + * Copyright (c) 1983 Regents of the University of California, + * All rights reserved. Redistribution permitted subject to + * the terms of the Berkeley Software License Agreement. + */ +#include "externs.h" +#undef UP +#include + +#define abs(a) ((a) < 0 ? -(a) : (a)) +#define MIDR (LINES/2 - 1) +#define MIDC (COLS/2 - 1) + +int row, column; +int dr = 0, dc = 0; +char destroyed; +int clk = 120; /* time for all the flights in the game */ +char cross = 0; +void (*oldsig)(); + +static void +endfly() +{ + alarm(0); + signal(SIGALRM, SIG_DFL); + mvcur(0,COLS-1,LINES-1,0); + delwin(stdscr); + endwin(); + signal(SIGTSTP, SIG_DFL); + signal(SIGINT, oldsig); +} + +void +succumb() +{ + if (oldsig == SIG_DFL) { + endfly(); + exit(1); + } + if (oldsig != SIG_IGN) { + endfly(); + (*oldsig)(); + } +} + +static void +screen() +{ + register int r,c,n; + int i; + + clear(); + i = rnd(100); + for (n=0; n < i; n++){ + r = rnd(LINES-3) + 1; + c = rnd(COLS); + mvaddch(r, c, '.'); + } + mvaddstr(LINES-1-1,21,"TORPEDOES FUEL TIME"); + refresh(); +} + +static void +target() +{ + register int n; + + move(MIDR,MIDC-10); + addstr("------- + -------"); + for (n = MIDR-4; n < MIDR-1; n++){ + mvaddch(n,MIDC,'|'); + mvaddch(n+6,MIDC,'|'); + } +} + +static void +notarget() +{ + register int n; + + move(MIDR,MIDC-10); + addstr(" "); + for (n = MIDR-4; n < MIDR-1; n++){ + mvaddch(n,MIDC,' '); + mvaddch(n+6,MIDC,' '); + } +} + +static void +moveenemy() +{ + double d; + int oldr, oldc; + + oldr = row; + oldc = column; + if (fuel > 0){ + if (row + dr <= LINES-3 && row + dr > 0) + row += dr; + if (column + dc < COLS-1 && column + dc > 0) + column += dc; + } else if (fuel < 0){ + fuel = 0; + mvaddstr(0,60,"*** Out of fuel ***"); + } + d = (double) ((row - MIDR)*(row - MIDR) + (column - MIDC)*(column - MIDC)); + if (d < 16){ + row += (rnd(9) - 4) % (4 - abs(row - MIDR)); + column += (rnd(9) - 4) % (4 - abs(column - MIDC)); + } + clk--; + mvaddstr(oldr, oldc - 1, " "); + if (cross) + target(); + mvaddstr(row, column - 1, "/-\\"); + move(LINES-1, 24); + printw("%3d", torps); + move(LINES-1, 42); + printw("%3d", fuel); + move(LINES-1, 57); + printw("%3d", clk); + refresh(); + signal(SIGALRM, moveenemy); + alarm(1); +} + +static void +blast() +{ + register int n; + + alarm(0); + move(LINES-1, 24); + printw("%3d", torps); + for(n = LINES-1-2; n >= MIDR + 1; n--){ + mvaddch(n, MIDC+MIDR-n, '/'); + mvaddch(n, MIDC-MIDR+n, '\\'); + refresh(); + } + mvaddch(MIDR,MIDC,'*'); + for(n = LINES-1-2; n >= MIDR + 1; n--){ + mvaddch(n, MIDC+MIDR-n, ' '); + mvaddch(n, MIDC-MIDR+n, ' '); + refresh(); + } + alarm(1); +} + +int +visual() +{ + destroyed = 0; + savetty(); + if(initscr() != stdscr){ + puts("Whoops! No more memory..."); + return(0); + } + oldsig = signal(SIGINT, succumb); + crmode(); + noecho(); + screen(); + row = rnd(LINES-3) + 1; + column = rnd(COLS-2) + 1; + moveenemy(); + for (;;) { + switch(getchar()){ + + case 'h': + case 'r': + dc = -1; + fuel--; + break; + + case 'H': + case 'R': + dc = -5; + fuel -= 10; + break; + + case 'l': + dc = 1; + fuel--; + break; + + case 'L': + dc = 5; + fuel -= 10; + break; + + case 'j': + case 'u': + dr = 1; + fuel--; + break; + + case 'J': + case 'U': + dr = 5; + fuel -= 10; + break; + + case 'k': + case 'd': + dr = -1; + fuel--; + break; + + case 'K': + case 'D': + dr = -5; + fuel -= 10; + break; + + case '+': + if (cross){ + cross = 0; + notarget(); + } + else + cross = 1; + break; + + case ' ': + case 'f': + if (torps){ + torps -= 2; + blast(); + if (row == MIDR && column - MIDC < 2 && MIDC - column < 2){ + destroyed = 1; + alarm(0); + } + } + else + mvaddstr(0,0,"*** Out of torpedoes. ***"); + break; + + case 'q': + endfly(); + return(0); + + default: + mvaddstr(0,26,"Commands = r,R,l,L,u,U,d,D,f,+,q"); + continue; + + case EOF: + break; + } + if (destroyed){ + endfly(); + return(1); + } + if (clk <= 0){ + endfly(); + die(0); + } + } +} diff --git a/src/games/battlestar/getcom.c b/src/games/battlestar/getcom.c new file mode 100644 index 0000000..b409ac3 --- /dev/null +++ b/src/games/battlestar/getcom.c @@ -0,0 +1,67 @@ +/* + * Copyright (c) 1983 Regents of the University of California, + * All rights reserved. Redistribution permitted subject to + * the terms of the Berkeley Software License Agreement. + */ +#include +#include + +char * +getcom(buf, size, prompt, error) + char *buf; + int size; + char *prompt, *error; +{ + for (;;) { + fputs(prompt, stdout); + if (fgets(buf, size, stdin) == 0) { + clearerr(stdin); + continue; + } + while (isspace(*buf)) + buf++; + if (*buf) + break; + if (error) + puts(error); + } + return (buf); +} + + +/* + * shifts to UPPERCASE if flag > 0, lowercase if flag < 0, + * and leaves it unchanged if flag = 0 + */ +char * +getword(buf1, buf2, flag) + register char *buf1, *buf2; + register int flag; +{ + while (isspace(*buf1)) + buf1++; + if (*buf1 != ',') { + if (!*buf1) { + *buf2 = 0; + return (0); + } + while (*buf1 && !isspace(*buf1) && *buf1 != ',') + if (flag < 0) + if (isupper(*buf1)) + *buf2++ = tolower(*buf1++); + else + *buf2++ = *buf1++; + else if (flag > 0) + if (islower(*buf1)) + *buf2++ = toupper(*buf1++); + else + *buf2++ = *buf1++; + else + *buf2++ = *buf1++; + } else + *buf2++ = *buf1++; + *buf2 = 0; + while (isspace(*buf1)) + buf1++; + return (*buf1 ? buf1 : 0); +} diff --git a/src/games/battlestar/globals.c b/src/games/battlestar/globals.c new file mode 100644 index 0000000..05b4e27 --- /dev/null +++ b/src/games/battlestar/globals.c @@ -0,0 +1,193 @@ +/* + * Copyright (c) 1983 Regents of the University of California, + * All rights reserved. Redistribution permitted subject to + * the terms of the Berkeley Software License Agreement. + */ +#include "externs.h" + +#define strstr(x) x + +int WEIGHT = MAXWEIGHT; +int CUMBER = MAXCUMBER; + +#ifdef EXT_MESSAGE_FILE +unsigned objdes[NUMOFOBJECTS] = { +#else +char *objdes[NUMOFOBJECTS] = { +#endif + strstr("There is a knife here"), + strstr("There is an exquisitely crafted sword and scabbard here."), + 0, /* can land from here */ + strstr("There is a fierce woodsman here brandishing a heavy mallet."), + strstr("There is an unweildly two-handed sword here."), + strstr("There is a bloody meat cleaver here."), + strstr("A rusty broadsword is lying here."), + strstr("There is an ancient coat of finely woven mail here."), + strstr("There is a old dented helmet with an ostrich plume here."), + strstr("There is a shield of some native tribe here."), + strstr("The maid's body is lying here. She was murdered!"), + strstr("There is a Viper ready for launch here."), + strstr("A kerosene lantern is burning luridly here."), + strstr("An old pair of shoes has been discarded here."), + 0, /* cylon */ + strstr("There is a pair of pajamas here."), + strstr("A kingly robe of royal purple and spun gold is draped here."), + strstr("There is a strange golden amulet on the floor here."), + strstr("A medallion of solid gold shimmers on the ground nearby."), + strstr("A talisman of gold is lying here."), + strstr("A dead woodsman has fallen here. He was savagely murdered."), + strstr("A heavy wooden mallet lies nearby."), + strstr("There is a laser pistol here."), + strstr("A flower-like young goddess is bathing in the hot mineral pools. She is \nwatching you, but continues to steep and sing softly."), + strstr("The goddess is reclining on a bed of ferns and studying you intently."), + strstr("There is a grenade here"), + strstr("There is a length of heavy chain here."), + strstr("There is a stout rope here."), + strstr("There is a pair of Levi's here."), + strstr("A bloody mace is lying on the ground here."), + strstr("There is a shovel here."), + strstr("A long, sharp halberd is propped up here."), + strstr("There is a compass here"), + strstr("Wreckage and smoldering debris from a crash litter the ground here."), + strstr("A woodland Elf armed with a shield and deadly halberd lunges toward you!"), + strstr("I think I hear footsteps behind us."), + strstr("There are a few coins here."), + strstr("There are some matches here."), + strstr("An unctuous man in a white suit and a dwarf are standing here."), + strstr("There are some ripe papayas here."), + strstr("There is a ripe pineapple here."), + strstr("There are some kiwi fruit here."), + strstr("There are some coconuts here."), + strstr("There is a ripe mango here."), + strstr("There is a sparkling diamond ring here."), + strstr("There is a colorful pink potion in a small crystal vial here."), + strstr("A gold bracelet is on the ground here."), + strstr("A swarthy woman with stern features pulls you aside from the crowd,\n'I must talk to you -- but not here. Meet me at midnight in the gardens.'"), + strstr("The swarthy woman has been awaiting you anxiousy. 'I must warn you that the\nIsland has anticipated your Quest. You will not be welcomed. The Darkness is\nstrong where you must search. Seek not the shadows save only at night, for\nthen are they the weakest. In the mountains far from here a canyon winds\nwith ferns and streams and forgotten vines. There you must go. Take this\nrope.'"), + strstr("Out from the shadows a figure leaps! His black cape swirls around, and he\nholds a laser sword at your chest. 'So, you have come to fulfill the Quest.\nHa! Your weapons are no match for me!'"), + strstr("An old timer with one eye missing and no money for a drink sits at the bar."), + strstr("You are flying through an asteroid field!"), + strstr("A planet is nearby."), + strstr("The ground is charred here."), + strstr("There is a thermonuclear warhead here."), + strstr("The fragile, beautiful young goddess lies here. You murdered her horribly."), + strstr("The old timer is lying here. He is dead."), + strstr("The native girl's body is lying here."), + strstr("A native girl is sitting here."), + strstr("A gorgeous white stallion is standing here."), + strstr("The keys are in the ignition."), + strstr("A pot of pearls and jewels is sitting here."), + strstr("A bar of solid gold is here."), + strstr("There is a 10 kilogram diamond block here.") + +}; + +char *objsht[NUMOFOBJECTS] = { + "knife", + "fine sword", + 0, + "Woodsman", + "two-handed sword", + "meat cleaver", + "broadsword", + "coat of mail", + "plumed helmet", + "shield", + "maid's body", + "viper", + "lantern", + "shoes", + 0, + "pajamas", + "robe", + "amulet", + "medallion", + "talisman", + "woodsman's body", + "wooden mallet", + "laser", + 0, + 0, + "grenade", + "chain", + "rope", + "levis", + "mace", + "shovel", + "halberd", + "compass", + 0, + "Elf", + 0, + "coins", + "match book", + 0, + "papayas", + "pineapple", + "kiwi", + "coconuts", + "mango", + "ring", + "potion", + "bracelet", + 0, + 0, + "Dark Lord", + 0, + 0, + 0, + 0, + "warhead", + "goddess's body", + "old timer's body", + "girl's body", + 0, + "stallion", + "car", + "pot of jewels", + "bar of gold", + "diamond block" +}; + +char *ouch[NUMOFINJURIES] = { + "some minor abrasions", + "some minor lacerations", + "a minor puncture wound", + "a minor amputation", + "a sprained wrist", + "a fractured ankle and shattered kneecap", + "a broken arm and dislocated shoulder", + "a few broken ribs", + "a broken leg and torn ligaments", + "a broken back and ruptured spleen", + "some deep incisions and a loss of blood", + "a fractured skull and mashed face", + "a broken neck" +}; + +int objwt[NUMOFOBJECTS] = { + 1, 5, 0, 10, 15, 2, 10, 10, + 3, 5, 50, 2500, 2, 1, 100, 1, + 2, 1, 1, 1, 60, 10, 5, 0, + 50, 5, 15, 5, 1, 20, 10, 10, + 0, 0, 0, 0, 1, 0, 0, 1, + 1, 1, 2, 1, 0, 0, 0, 0, + 0, 0, 100, 0, 0, 0, 55, 47, + 50, 45, 45, 100, 2000, 30, 20, 10 +}; + +int objcumber[NUMOFOBJECTS] = { + 1, 5, 0, 150, 10, 1, 5, 2, + 2, 1, 5, 10, 1, 1, 10, 1, + 1, 1, 1, 1, 7, 5, 4, 0, + 0, 1, 1, 1, 1, 5, 4, 4, + 1, 0, 0, 0, 1, 0, 0, 1, + 1, 1, 3, 1, 0, 0, 1, 0, + 0, 0, 10, 0, 0, 0, 7, 8, + 10, 8, 8, 10, 10, 3, 1, 2 +}; + +int win = 1; +int matchcount = 20; +int followgod = -1; +int followfight = -1; diff --git a/src/games/battlestar/init.c b/src/games/battlestar/init.c new file mode 100644 index 0000000..e5afa40 --- /dev/null +++ b/src/games/battlestar/init.c @@ -0,0 +1,102 @@ +/* + * Copyright (c) 1983 Regents of the University of California, + * All rights reserved. Redistribution permitted subject to + * the terms of the Berkeley Software License Agreement. + */ +#include "externs.h" +#include + +static char *list[] = { /* hereditary wizards */ + "riggle", + "chris", + "games", + "edward", + "comay", + "yee", + "dmr", + "ken", + 0 +}; + +static char *badguys[] = { + "wnj", + "root", + "ted", + 0 +}; + +static void +getutmp(uname) + char *uname; +{ + struct passwd *ptr; + + ptr = getpwuid(getuid()); + strcpy(uname, ptr ? ptr->pw_name : ""); +} + +static int +checkout(uname) + register char *uname; +{ + register char **ptr; + + for (ptr = list; *ptr; ptr++) + if (strcmp(*ptr, uname) == 0) + return 1; + for (ptr = badguys; *ptr; ptr++) + if (strcmp(*ptr, uname) == 0) { + printf("You are the Poor anti-wizard %s. Good Luck!\n", + uname); + CUMBER = 3; + WEIGHT = 9; /* that'll get him! */ + clk = 10; + setbit(location[7].objects, WOODSMAN); /* viper room */ + setbit(location[20].objects, WOODSMAN); /* laser " */ + setbit(location[13].objects, DARK); /* amulet " */ + setbit(location[8].objects, ELF); /* closet */ + return 0; /* anything else, Chris? */ + } + return 0; +} + +static int +wizard(uname) + char *uname; +{ + int flag; + + flag = checkout(uname); + if (flag) + printf("You are the Great wizard %s.\n", uname); + return flag; +} + +void +initialize(startup) + int startup; +{ + register struct objs *p; + + puts("Version 4.2, fall 1984."); + puts("First Adventure game written by His Lordship, the honorable"); + puts("Admiral D.W. Riggle\n"); + srand(getpid()); + getutmp(uname); + wiz = wizard(uname); + wordinit(); + if (startup) { + location = dayfile; + direction = NORTH; + Time = 0; + snooze = CYCLE * 1.5; + position = 22; + setbit(wear, PAJAMAS); + fuel = TANKFULL; + torps = TORPEDOES; + for (p = dayobjs; p->room != 0; p++) + setbit(location[p->room].objects, p->obj); + } else + restore(); + signal(SIGINT, die); +} diff --git a/src/games/battlestar/misc.c b/src/games/battlestar/misc.c new file mode 100644 index 0000000..c8f7dcf --- /dev/null +++ b/src/games/battlestar/misc.c @@ -0,0 +1,32 @@ +/* + * Copyright (c) 1983 Regents of the University of California, + * All rights reserved. Redistribution permitted subject to + * the terms of the Berkeley Software License Agreement. + */ +#include "externs.h" + +int +card(array, size) /* for beenthere, injuries */ + register char *array; + int size; +{ + register char *end = array + size; + register int i = 0; + + while (array < end) + if (*array++) + i++; + return (i); +} + +int +ucard(array) + register unsigned *array; +{ + register int j = 0, n; + + for (n = 0; n < NUMOFOBJECTS; n++) + if (testbit(array, n)) + j++; + return (j); +} diff --git a/src/games/battlestar/mkstr.c b/src/games/battlestar/mkstr.c new file mode 100644 index 0000000..ec7e706 --- /dev/null +++ b/src/games/battlestar/mkstr.c @@ -0,0 +1,284 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +/* + * Somewhat modified to key on strstr(" instead of error(", for use + * as a general purpose string stripper. Also replaces pointer with + * a (long) pointer. + */ +#include +#include +#include +#include +#include + +#define ungetchar(c) ungetc(c, stdin) + +/* + * 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 'strstr("' 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; + +#define NBUCKETS 511 + +struct hash { + long hval; + long hpt; + struct hash *hnext; +} *bucket[NBUCKETS]; + +static int +fgetNUL(obuf, rmdr, file) + char *obuf; + register int rmdr; + FILE *file; +{ + register int c; + register char *buf = obuf; + + while (--rmdr > 0 && (c = getc(file)) != 0 && c != EOF) + *buf++ = c; + *buf++ = 0; + getc(file); + if (feof(file) || ferror(file)) + return 0; + return 1; +} + +static long +hashit(str, really, fakept) + char *str; + int 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); +#ifdef DEBUG + fprintf(stderr, "Got (from %ld) %s\n", hp->hpt, buf); +#endif + 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; + } +#ifdef DEBUG + fprintf(stderr, "%s hashed to %ld at %ld\n", str, hp->hval, hp->hpt); +#endif + return (hp->hpt); +} + +static int +octdigit(c) + int c; +{ + return (c >= '0' && c <= '7'); +} + +static void +copystr() +{ + register int 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("%ld", hashit(buf, 1, 0)); +} + +static int +match(ocp) + char *ocp; +{ + register char *cp; + register int c; + + for (cp = ocp + 1; *cp; cp++) { + c = getchar(); + if (c != *cp) { + while (ocp < cp) + putchar(*ocp++); + ungetchar(c); + return (0); + } + } + return (1); +} + +static void +process() +{ + register int c; + + for (;;) { + c = getchar(); + if (c == EOF) + return; + if (c != 's') { + putchar(c); + continue; + } + if (match("strstr(")) { + printf("strstr("); + c = getchar(); + if (c != '"') + putchar(c); + else + copystr(); + } + } +} + +static void +inithash() +{ + char buf[512]; + int mesgpt = 0; + + rewind(mesgread); + while (fgetNUL(buf, sizeof buf, mesgread) != 0) { + hashit(buf, 0, mesgpt); + mesgpt += strlen(buf) + 2; + } +} + +int +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); +} diff --git a/src/games/battlestar/nightfile.c b/src/games/battlestar/nightfile.c new file mode 100644 index 0000000..ea93b62 --- /dev/null +++ b/src/games/battlestar/nightfile.c @@ -0,0 +1,1147 @@ +/* + * Copyright (c) 1983 Regents of the University of California, + * All rights reserved. Redistribution permitted subject to + * the terms of the Berkeley Software License Agreement. + */ +#include "externs.h" + +#define strstr(x) x + +struct room nightfile[] = { + { 0 }, + { strstr("You are in the main hangar."), + { 5, 2, 9, 3, 3, 1, 0, 0 }, +strstr("This is a huge bay where many fighters and cargo craft lie. Alarms are \n\ +sounding and fighter pilots are running to their ships. Above is a gallery\n\ +overlooking the bay. The scream of turbo engines is coming from +. The rest\n\ +of the hangar is +. There is an exit +.*\n") }, + { strstr("This is the landing bay."), + { 1, 0, 10, 0, 0, 0, 0, 0 }, +strstr("Ships are landing here, some heavily damaged. Enemy fighters continually\n\ +strafe this vulnerable port. The main hangar is +, *\n\ +There is an exit +.*\n") }, + { strstr("You are in the gallery."), + { 4, 0, 0, 0, 0, 0, 1, 0 }, +strstr("From here a view of the entire landing bay reveals that our battlestar\n\ +is near destruction. Fires are spreading out of control and laser blasts\n\ +lick at the shadows. The control room is +. ***\n") }, + { strstr("You are in the control room."), + { 0, 3, 0, 0, 0, 0, 5, 0 }, +strstr("Several frantic technicians are flipping switches wildly but otherwise\n\ +this room seems fairly deserted. A weapons locker has been left open.\n\ +A staircase leads down. * There is a way -. ** \n") }, + { strstr("This is the launch room."), + { 6, 1, 7, 0, 4, 1, 0, 0 }, +strstr("From the launch tubes here fighters blast off into space. Only one is left,\n\ +and it is guarded by two fierce men. A staircase leads up from here.\n\ +There is a cluttered workbench +. From the main hangar come sounds of great\n\ +explosions. The main hangar is +. The viper launch tubes are to the -.*\n") }, + { strstr("You are at the workbench."), + { 0, 5, 7, 0, 0, 0, 0, 0 }, +strstr("Strange and unwieldy tools are arranged here including a lunch box \n\ +and pneumatic wrenches and turbo sprocket rockets.*\n\ +The launch room is +. The remaining viper is +.*\n") }, + { strstr("You are in the viper launch tube."), + { 0, 5, 0, 5, 32, 0, 0, 0 }, +strstr("The two guards are eyeing you warily! ****\n") }, + { strstr("This is a walk in closet."), + { 22, 0, 0, 0, 0, 0, 0, 0 }, +strstr("A wardrobe of immense magnitude greets the eye. Furs and robes of kings\n\ +hang on rack after rack. Silken gowns, capes woven with spun gold, and \n\ +delicate synthetic fabrics are stowed here. The bedroom is +.***\n") }, + { strstr("You are in a wide hallway leading to the main hangar."), + { 0, 0, 11, 1, 0, 0, 0, 0 }, +strstr("The walls and ceiling here have been blasted through in several places.\n\ +It looks as if quite a battle has been fought for possession of the landing bay\n\ +Gaping corpses litter the floor.** The hallway continues +.\n\ +The main hangar is +.\n") }, + { strstr("You are in a wide hallway leading to the landing bay."), + { 0, 0, 12, 2, 0, 0, 0, 0 }, +strstr("Most of the men and supplies needed in the main hangar come through this\n\ +corridor, but the wounded are forced to use it too. It very dank and\n\ +crowded here, and the floor is slippery with blood.**\n\ +The hallway continues -. The landing bay is +.\n") }, + { strstr("The hallway is very congested with rubble here."), + { 0, 0, 0, 9, 13, 1, 0, 0 }, +strstr("It is too choked with broken steel girders and other debris to continue\n\ +on much farther. Above, the ceiling has caved in and it is possible to \n\ +climb up. There is not much chance to go -, -, or -.\n\ +But the hallway seems clearer +.\n") }, + { strstr("A wide hallway and a more narrow walkway meet here."), + { 14, 15, 0, 10, 0, 0, 0, 0 }, +strstr("The intersection is crowded with the many wounded who have come up\n\ +the wide hallway and continued +. The walkway is less crowded +.\n\ +The wide hallway goes *-.\n") }, + { strstr("You are in what was once an elegant stateroom."), + { 16, 0, 0, 0, 0, 0, 11, 0 }, +strstr("Whoever lived in this stateroom, he and his female companion\n\ +were mercilessly slain in their sleep. Clothes, trinkets and personal\n\ +belongings are scattered all across the floor. Through a hole in the\n\ +collapsed floor I can see a hallway below. A door is +.***\n") }, + { strstr("You're at the entrance to the sick bay."), + { 17, 12, 18, 0, 0, 0, 0, 0 }, +strstr("The wounded are entering the sick bay in loudly moaning files.\n\ +The walkway continues - and +. A doctor is motioning for you to \n\ +come to the -. *\n") }, + { strstr("You're in the walkway."), + { 12, 19, 0, 0, 0, 0, 0, 0 }, +strstr("Most of the men and supplies were coming from the armory. The walkway\n\ +continues -. The armory is +.**\n") }, + { strstr("These are the executive suites of the battlestar."), + { 20, 13, 21, 22, 23, 1, 24, 0 }, +strstr("Luxurious staterooms carpeted with crushed velvet and adorned with beaten\n\ +gold open onto this parlor. A wide staircase with ivory banisters leads\n\ +up or down. This parlor leads into a hallway +. The bridal suite is +.\n\ +Other rooms lie - and +.\n") }, + { strstr("You're in a long dimly lit hallway."), + { 0, 14, 25, 0, 0, 0, 0, 0 }, +strstr("This part of the walkway is deserted. There is a dead end +. The\n\ +entrance to the sickbay is +. The walkway turns sharply -.*\n") }, + { strstr("This is the sick bay."), + { 0, 0, 0, 14, 0, 0, 0, 0 }, +strstr("Sinister nurses with long needles and pitiful aim probe the depths of suffering\n\ +here. Only the mortally wounded receive medical attention on a battlestar,\n\ +but afterwards they are thrown into the incinerators along with the rest.**\n\ +Nothing but death and suffering +. The walkway is +.\n") }, + { strstr("You're in the armory."), + { 15, 26, 0, 0, 0, 0, 0, 0 }, +strstr("An armed guard is stationed here 365 sectars a yarn to protect the magazine.\n\ +The walkway is +. The magazine is +.**\n") }, + { strstr("The hallway ends here at the presidential suite."), + { 27, 16, 0, 0, 0, 0, 0, 0 }, +strstr("The door to this suite is made from solid magnesium, and the entryway is\n\ +inlaid with diamonds and fire opals. The door is ajar +. The hallway\n\ +goes -.**\n") }, + { strstr("This is the maid's utility room."), + { 0, 0, 0, 16, 0, 0, 0, 0 }, +strstr("What a gruesome sight! The maid has been brutally drowned in a bucket of\n\ +Pine Sol and repeatedly stabbed in the back with a knife.***\n\ +The hallway is +.\n") }, + { strstr("This is a luxurious stateroom."), + { 0, 8, 16, 0, 0, 0, 0, 0 }, +strstr("The floor is carpeted with a soft animal fur and the great wooden furniture\n\ +is inlaid with strips of platinum and gold. Electronic equipment built\n\ +into the walls and ceiling is flashing wildly. The floor shudders and\n\ +the sounds of dull explosions rumble though the room. From a window in\n\ +the wall + comes a view of darkest space. There is a small adjoining\n\ +room +, and a doorway +.*\n") }, + { strstr("You are at the entrance to the dining hall."), + { 0, 0, 28, 0, 0, 0, 16, 0 }, +strstr("A wide staircase with ebony banisters leads down here.**\n\ +The dining hall is to the -.*\n") }, + { strstr("This was once the first class lounge."), + { 0, 0, 29, 0, 16, 1, 0, 0 }, +strstr("There is much rubble and destruction here that was not apparent elsewhere.\n\ +The walls and ceilings have broken in in some places. A staircase with\n\ +red coral banisters leads up. It is impossible to go - or -.\n\ +It seems a little clearer +.*\n") }, + { strstr("You are in a narrow stairwell."), + { 0, 17, 0, 0, 30, 1, 0, 0 }, +strstr("These dusty and decrepit stairs lead up. There is no way -. The\n\ +hallway turns sharply -.**\n") }, + { strstr("You are in the magazine."), + { 19, 0, 0, 0, 0, 0, 0, 0 }, +strstr("Rows and rows of neatly stacked ammunition for laser pistols and grenade\n\ +launchers are here. The armory is +.***\n") }, + { strstr("You're in the presidential suite."), + { 0, 20, 0, 0, 0, 0, 0, 0 }, +strstr("Apparently the president has been assassinated. A scorched figure lies\n\ +face downward on the carpet clutching his chest.*\n\ +The hallway leads -.**\n") }, + { strstr("You are in the dining hall."), + { 0, 30, 31, 23, 0, 0, 0, 0 }, +strstr("This was the seen of a mass suicide. Hundreds of ambassadors and assorted\n\ +dignitaries sit slumped over their breakfast cereal. I suppose the news\n\ +of the cylon attack killed them. There is a strange chill in this room. I\n\ +would not linger here. * The kitchen is +. Entrances + and +.\n") }, + { strstr("The debris is very thick here."), + { 0, 11, 0, 24, 0, 0, 0, 0 }, +strstr("Broken furniture, fallen girders, and other rubble block the way.\n\ +There is not much chance to continue -, -, or -.\n\ +It would be best to go -.\n") }, + { strstr("You are in the kitchen."), + { 28, 0, 0, 0, 0, 0, 0, 0 }, +strstr("This room is full of shining stainless steel and burnished bronze cookware. An \n\ +assortment of tropical fruits and vegetables as well as fine meats and cheeses \n\ +lies on a sterling platter. The chef, unfortunately, has been skewered like a \n\ +side of beef. The dining room is +. ** There is a locked door +.\n") }, + { strstr("You are in an arched entry leading to the dining room."), + { 0, 0, 0, 28, 0, 0, 0, 0 }, +strstr("The door leading out is bolted shut from the outside and is very strong.***\n\ +The dining room is +.\n") }, + { strstr("You are in space."), + { 33, 34, 35, 36, 37, 1, 33, 1 }, +strstr("****\n") }, + { strstr("You are in space."), + { 38, 32, 39, 40, 41, 1, 42, 1 }, +strstr("****\n") }, + { strstr("You are in space."), + { 32, 44, 45, 46, 47, 1, 48, 1 }, +strstr("****\n") }, + { strstr("You are in space."), + { 40, 45, 49, 32, 50, 1, 51, 1 }, +strstr("****\n") }, + { strstr("You are in space."), + { 41, 46, 32, 52, 53, 1, 54, 1 }, +strstr("****\n") }, + { strstr("You are in space."), + { 42, 47, 50, 53, 55, 1, 32, 1 }, +strstr("****\n") }, + { strstr("You are in space."), + { 43, 48, 51, 54, 32, 1, 56, 1 }, +strstr("****\n") }, + { strstr("You are in space."), + { 57, 33, 40, 41, 42, 1, 43, 1 }, +strstr("****\n") }, + { strstr("You are in space."), + { 39, 35, 57, 33, 58, 1, 59, 1 }, +strstr("****\n") }, + { strstr("You are in space."), + { 39, 36, 33, 59, 60, 1, 61, 1 }, +strstr("****\n") }, + { strstr("You are in space."), + { 39, 37, 58, 60, 62, 1, 33, 1 }, +strstr("****\n") }, + { strstr("You are in space."), + { 39, 38, 59, 61, 33, 1, 63, 1 }, +strstr("****\n") }, + { strstr("You are in space."), + { 34, 64, 45, 46, 47, 1, 48, 1 }, +strstr("****\n") }, + { strstr("You are in space."), + { 35, 44, 49, 34, 50, 1, 51, 1 }, +strstr("****\n") }, + { strstr("You are in space."), + { 36, 44, 34, 52, 53, 1, 54, 1 }, +strstr("****\n") }, + { strstr("You are in space."), + { 37, 44, 50, 53, 55, 1, 34, 1 }, +strstr("****\n") }, + { strstr("You are in space."), + { 38, 44, 51, 54, 34, 1, 56, 1 }, +strstr("****\n") }, + { strstr("You are in space."), + { 49, 49, 52, 35, 49, 1, 49, 1 }, +strstr("****\n") }, + { strstr("You are in space."), + { 58, 47, 49, 37, 55, 1, 35, 1 }, +strstr("****\n") }, + { strstr("You are in space."), + { 59, 48, 49, 38, 35, 1, 56, 1 }, +strstr("****\n") }, + { strstr("You are in space."), + { 52, 52, 36, 49, 52, 1, 52, 1 }, +strstr("****\n") }, + { strstr("You are in space."), + { 60, 46, 37, 52, 55, 1, 36, 1 }, +strstr("****\n") }, + { strstr("You are in space."), + { 61, 48, 38, 52, 36, 1, 56, 1 }, +strstr("****\n") }, + { strstr("You are in space."), + { 62, 55, 55, 55, 56, 1, 37, 1 }, +strstr("****\n") }, + { strstr("You are in space."), + { 56, 56, 56, 56, 38, 1, 55, 1 }, +strstr("****\n") }, + { strstr("You are in space."), + { 65, 39, 57, 57, 57, 1, 57, 1 }, +strstr("****\n") }, + { strstr("You are in space."), + { 39, 50, 49, 42, 62, 1, 40, 1 }, +strstr("****\n") }, + { strstr("You are in space."), + { 39, 51, 49, 43, 40, 1, 63, 1 }, +strstr("****\n") }, + { strstr("You are in space."), + { 39, 53, 43, 59, 62, 1, 41, 1 }, +strstr("****\n") }, + { strstr("You are in space."), + { 39, 54, 43, 59, 41, 1, 56, 1 }, +strstr("****\n") }, + { strstr("You are in space."), + { 39, 55, 62, 62, 56, 1, 42, 1 }, +strstr("****\n") }, + { strstr("You are in space."), + { 39, 56, 35, 36, 43, 1, 55, 1 }, +strstr("****\n") }, + { strstr("You are in space."), + { 44, 66, 66, 66, 66, 1, 66, 1 }, +strstr("****\n") }, + { strstr("You are in space."), + { 67, 57, 67, 67, 67, 1, 67, 1 }, +strstr("****\n") }, + { strstr("You are in space."), + { 64, 68, 68, 68, 68, 1, 68, 1 }, +strstr("****\n") }, + { strstr("You are orbiting a small blue planet."), + { 67, 67, 67, 67, 65, 1, 69, 1 }, +strstr("****\n") }, + { strstr("You are orbiting a tropical planet."), + { 68, 68, 68, 68, 66, 1, 70, 1 }, +strstr("****\n") }, + { strstr("You are flying through a dense fog."), + { 69, 69, 69, 69, 69, 1, 69, 1 }, +strstr("A cold grey sea of mist is swirling around the windshield and water droplets\n\ +are spewing from the wingtips. Ominous shadows loom in the darkness and it\n\ +feels as if a trap is closing around us. I have lost all sense of direction.\n\ +****\n") }, + { strstr("You are approaching an island."), + { 71, 72, 73, 74, 68, 1, 0, 1 }, +strstr("Feather palms outlined by mellow moonlight and a silvery black ocean line\n\ +the perimeter of the island. Mighty mountains of emerald and amethyst rise\n\ +like jagged teeth from black gums. The land rises sharply +. The shore\n\ +line stretches on *+.*\n") }, + { strstr("You are flying over a mountainous region."), + { 75, 73, 76, 77, 68, 1, 0, 1 }, +strstr("Below is a shadow filled canyon with luminous waterfalls plummeting down beyond sight and looming spires and pinnacles. **The ocean is +.*\n") }, + { strstr("You are flying over the ocean."), + { 74, 78, 78, 78, 68, 1, 0, 1 }, +strstr("You bank over the water and your wingtips dip low to the green waves. The\n\ +sea is very shallow here and the white coral beds beneath us teem with \n\ +shadowy fish.****\n") }, + { strstr("You are flying over the beach."), + { 71, 72, 79, 74, 68, 1, 80, 1 }, +strstr("A warm gentle surf caresses the beach here. The land rises\n\ +sharply +.* The beach is lost in low cliffs +.*\n") }, + { strstr("You are flying over a large lagoon."), + { 81, 72, 73, 82, 68, 1, 0, 1 }, +strstr("The water's brink winds tortuously inland. There are some lights +.***\n") }, + { strstr("You are flying over a gently sloping plane."), + { 83, 71, 84, 85, 68, 1, 0, 1 }, +strstr("The ground appears to be choked with vegetation.* The terrain is more\n\ +rugged +.**\n") }, + { strstr("You are flying through a gorge."), + { 0, 0, 86, 71, 68, 1, 102, 1 }, +strstr("This is a narrow, steep sided canyon lined with plants. The stars above\n\ +glisten through the over hanging trees. The gorge leads to the\n\ +sea** +, and to a tumultuous origin +.\n") }, + { strstr("You are flying over a plantation."), + { 85, 81, 71, 88, 68, 1, 89, 1 }, +strstr("It might be possible to land here, but not in the dark.* There are some lights\n\ ++ and *+.\n") }, + { strstr("You are over the ocean."), + { 72, 78, 79, 74, 68, 1, 0, 1 }, +strstr("The deep green swells foam and roll into the shore **+*.\n") }, + { strstr("You are flying along the coast."), + { 86, 72, 90, 73, 68, 1, 91, 1 }, +strstr("The coastline here is very rocky. The surf in some places is violent\n\ +and explodes in a shower of sparkling, moonlit spray. ****\n") }, + { strstr("This is a beautiful coral beach."), + { 106, 0, 107, 108, 73, 0, 0, 0 }, +strstr("Fine silver sand kissed lightly by warm tropical waters and illuminated\n\ +by a huge tropical moon stretches at least 30 meters inland.\n\ +Gently swaying palm trees are +.***\n") }, + { strstr("You are flying over a small fishing village."), + { 77, 74, 71, 82, 68, 1, 92, 1 }, +strstr("A few thatched huts lit with torches and bonfires line a road below.\n\ +The road continues on ***+.\n") }, + { strstr("You are flying over a clearing."), + { 88, 72, 74, 87, 68, 1, 93, 1 }, +strstr("There is a dock here (big enough for a seaplane) leading to a clearing.\n\ +The still waters of the lagoon reflects our orange turbo thrusters.****\n") }, + { strstr("You are flying over the shore."), + { 94, 75, 95, 96, 68, 1, 0, 1 }, +strstr("Rocky lava flows have overtaken the beach here.****\n") }, + { strstr("You are flying in a wide valley."), + { 95, 97, 86, 75, 68, 1, 98, 1 }, +strstr("This is a shallow valley yet the floor is obscured by a thick mist.\n\ +The valley opens into blackness +. The mist grows thicker +.**\n") }, + { strstr("You are flying near the shore."), + { 96, 77, 75, 99, 68, 1, 0, 1 }, +strstr("Very tall trees growing in neatly planted rows march off from the \n\ +water here towards the hills and down to the flat lands *+.**\n") }, + { strstr("You are flying around the very tip of the island."), + { 95, 79, 90, 84, 68, 1, 0, 1 }, +strstr("Sheer cliffs rise several hundred feet to a tree covered summit. Far below,\n\ +the grey sea gnaws voraciously at the roots of these cliffs. The island bends\n\ +around +** and +.\n") }, + { strstr("You are flying along the coastline."), + { 99, 82, 88, 100, 68, 1, 101, 1 }, +strstr("This is a narrow strip of sand lined with very few trees. The stars above\n\ +flicker through wisps of clouds. The beach continues on -.* There\n\ +are some lights +.*\n") }, + { strstr("You are flying over several cottages and buildings"), + { 99, 82, 77, 87, 68, 1, 103, 1 }, +strstr("Directly below is small ornate house lit up with spot lights and decorative\n\ +bulbs. A bell tower and a spurting fountain are nearby. Small dirt roads go\n\ ++ and +.**\n") }, + { strstr("You are in a field of sugar cane."), + { 109, 110, 111, 112, 77, 0, 0, 0 }, +strstr("These strong, thick canes give little shelter but many cuts and scrapes.\n\ +There are some large trees ***+.\n") }, + { strstr("You are flying over the ocean."), + { 95, 78, 90, 86, 68, 1, 0, 1 }, +strstr("The water is a placid ebony.****\n") }, + { strstr("You are on the coast road."), + { 113, 114, 115, 116, 79, 0, 0, 0 }, +strstr("The road winds close to the shore here. The trees on either side press close\n\ +in the darkness and seem to be watching us.** The road continues -\n\ +and -.\n") }, + { strstr("You are on the main street of the village."), + { 117, 118, 119, 120, 81, 0, 0, 0 }, +strstr("The natives are having a festive luau here. Beautiful dancers gyrate in the\n\ +torchlight to the rhythm of wooden drums. A suckling pig is sizzling in a\n\ +bed of coals and ti leaves are spread with poi and tropical fruits. Several\n\ +natives have come over to you and want you to join in the festivities.\n\ +There is a light burning in a bungalow +.***\n") }, + { strstr("You are at the sea plane dock."), + { 121, 122, 123, 124, 82, 0, 0, 0 }, +strstr("The clearing is deserted. The grass is wet with the evening dew +.*\n\ +There is something set up +.*\n") }, + { strstr("You are flying over the ocean."), + { 94, 83, 95, 96, 68, 1, 0, 1 }, +strstr("The black waves surge off shore here. The ocean becomes much calmer +.***\n") }, + { strstr("You are flying along the coast."), + { 94, 84, 86, 83, 68, 1, 0, 1 }, +strstr("The land is very low here with a river running into the sea +. There\n\ +is a wide valley opening up +, but a strange mist is flowing out of it.\n\ +The very tip of the island is +.*\n") }, + { strstr("You are flying along the coast."), + { 94, 85, 83, 99, 68, 1, 0, 1 }, +strstr("The coast here is cluttered with rocky outcroppings.****\n") }, + { strstr("You are lost in a sea of fog."), + { 97, 104, 97, 97, 97, 1, 0, 1 }, +strstr("What have you gotten us into?\n\ +I cant see a thing! ****\n") }, + { strstr("You are on a gravel wash."), + { 125, 126, 127, 128, 84, 0, 0, 0 }, +strstr("It is very dark here. A cool breeze is blowing from +. No moonlight can\n\ +reach below a thick canopy of fog above. The sound of cascading water is\n\ +coming from +.**\n") }, + { strstr("You are flying over a wide beach."), + { 96, 88, 85, 87, 68, 1, 105, 1 }, +strstr("There are some lighted buildings *+. Some trees are growing +.*\n") }, + { strstr("You are flying over the ocean."), + { 100, 100, 87, 100, 68, 1, 0, 1 }, +strstr("The black waves surge and splash against the rocky shore.****\n") }, + { strstr("You are on a narrow strip of sand."), + { 129, 130, 131, 0, 87, 0, 0, 0 }, +strstr("Rather coarse sand makes this beach very steep and only a few meters wide.\n\ +A fresh ocean breeze is rustling the ferns **+.*\n") }, + { strstr("This is Fern Canyon."), + { 0, 0, 132, 133, 76, 0, 0, 0 }, +strstr("Delicate waving ferns flourish here, suckled by warm water dripping from \n\ +every fissure and crevice in the solid rock walls. The stars above sparkle\n\ +through a thin mist. The canyon winds **-, and -.\n") }, + { strstr("This is the front lawn."), + { 134, 135, 136, 137, 88, 0, 0, 0 }, +strstr("There is a small fountain lighted with green and yellow bulbs here where\n\ +the driveway meets the lawn. Across the driveway, +, is an ornate white\n\ +house lit with gas lamps. A bell tower here is awash in pale blue.* There\n\ +is a road + which turns into the driveway.*\n") }, + { strstr("You have just crossed the crest of a mountain."), + { 97, 79, 86, 71, 68, 1, 0, 1 }, +strstr("The fog vanished mysteriously as we flew over the crest.*\n\ +Far + I can see the ocean sparkling in the moonlight.**\n") }, + { strstr("You are on a sandy beach."), + { 138, 139, 140, 0, 99, 0, 0, 0 }, +strstr("Fine coral sand, a fresh sea breeze, and dramatic surf add to this beach's\n\ +appeal.** Stone steps lead to a lighted path in the gardens +.*\n") }, + { strstr("You are among palm trees near the shore."), + { 141, 80, 142, 143, 73, 0, 0, 0 }, +strstr("Arching coconut palms laden with fruit provide a canopy for the glistening\n\ +white sand and sparse, dew covered grasses growing here. The forest grows\n\ +denser +. Crickets are chirping loudly here. The ocean is +.**\n") }, + { strstr("You are walking along the beach."), + { 144, 0, 145, 80, 73, 0, 0, 0 }, +strstr("The warm tropical waters nuzzle your ankles as you walk. Above is a gorgeous\n\ +starscape. The battlestar must be up there somewhere. The slope of the sand\n\ +is so gentle that the surf only slides up the sand.** There are some rocks\n\ ++.*\n") }, + { strstr("You are walking along the beach."), + { 146, 0, 80, 147, 73, 0, 0, 0 }, +strstr("The tide is out very far tonight, and it is possible to explore hidden rocks\n\ +and caves not ordinarily accessible. Rich beds of seaweed have been exposed\n\ +to the cool night air.****\n") }, + { strstr("You are in a papaya grove."), + { 148, 89, 149, 150, 77, 0, 0, 0 }, +strstr("Slender trees with their large seven lobed leaves bulge with succulent fruit.\n\ +There are some tall trees +.***\n") }, + { strstr("You are in a field of pineapple."), + { 89, 151, 152, 153, 77, 0, 0, 0 }, +strstr("The sharp dagger like pineapple leaves can pierce the flesh and hold fast\n\ +a skewered victim with tiny barbs.* The field ends +.**\n") }, + { strstr("You are in a field of kiwi plants."), + { 149, 154, 155, 89, 77, 0, 0, 0 }, +strstr("Round hairy fruit hang from staked vines here. There are some trees +\n\ +and +. The field ends in a road +.*\n") }, + { strstr("You are in a large grove of coconuts."), + { 150, 153, 89, 156, 77, 0, 0, 0 }, +strstr("These trees are much taller than any growing near the shore and the shadows\n\ +are also deeper. It's hard to keep my sense of direction.****\n") }, + { strstr("You are in the woods."), + { 157, 91, 158, 116, 79, 0, 0, 0 }, +strstr("Tropical undergrowth makes the going rough here. Sword ferns give no strong\n\ +foot hold and the dangling vines would gladly throttle one. The darkness is\n\ +so intense here that we stand in utter blackness.****\n") }, + { strstr("You are at the shore."), + { 91, 0, 159, 145, 79, 0, 160, 0 }, +strstr("The low minus tide tonight might make it possible to climb down to a\n\ +small cave entrance below. Large rocks would usually churn the waves\n\ +asunder.*** The beach goes -.\n") }, + { strstr("You are on the coast road."), + { 158, 161, 162, 91, 79, 0, 0, 0 }, +strstr("The road is beginning to turn slightly -. I can here the surf +. The road\n\ +continues into the dark forest +.*\n") }, + { strstr("The road winds deeper into the trees."), + { 163, 142, 91, 164, 79, 0, 0, 0 }, +strstr("Only narrow moonbeams filter through the dense foliage above. The moist rich\n\ +earth has nurtured a myriad of slugs, snakes, and spiders to grow here. The\n\ +road continues - and *- into the shadows.*\n") }, + { strstr("This is the front porch of the bungalow."), + { 165, 92, 0, 0, 81, 0, 0, 0 }, +strstr("The veranda is lit by a small yellow bug light. The door leads -.\n\ +The stone walk down to the luau is lined with burning torches +. That\n\ +roast pig smells good.**\n") }, + { strstr("You are on a path leading to the lagoon."), + { 92, 166, 167, 168, 81, 0, 0, 0 }, +strstr("This path winds through the underbrush and towards the lagoon *+. The\n\ +broad faced moon peeps though the branches above. The sound of drums echos\n\ +in the woods.**\n") }, + { strstr("This is a dirt road."), + { 169, 118, 170, 92, 81, 0, 0, 0 }, +strstr("**The road continues on - here for some distance. A bonfire and party light\n\ +up the night sky +.\n") }, + { strstr("You are on a dirt road."), + { 171, 118, 92, 172, 81, 0, 0, 0 }, +strstr("**There is a village +. A huge bonfire licks at the trees, and a celebration\n\ +of some sort is going on there. The smell of luscious cooking is tantalizing\n\ +my flared nostrils. The road continues +.\n") }, + { strstr("You are on a dirt road."), + { 173, 93, 174, 175, 82, 0, 0, 0 }, +strstr("This is a wide grassy clearing bedewed with droplets of evening mist. The\n\ +trees alongside the road moan and whisper as we pass. They seem annoyed at\n\ +our presence. **The road continues - and -.\n") }, + { strstr("You are at the seaplane dock."), + { 93, 0, 176, 177, 82, 0, 0, 0 }, +strstr("Not a living thing stirs the calm surface of the lagoon. The wooden planks\n\ +creak unnaturally as we tread on them. The dock reaches a clearing +.\n\ +A dark trail leads around the lagoon **+.\n") }, + { strstr("There are some tables on the lawn here."), + { 121, 122, 123, 93, 82, 0, 0, 0 }, +strstr("Some tables are strewn on the wet lawn.****\n") }, + { strstr("You are nosing around in the bushes."), + { 124, 124, 93, 124, 82, 0, 0, 0 }, +strstr("There is little here but some old beer cans. It is damp and dirty in here.\n\ +I think I stepped in something unpleasant. It would be best to go **-.*\n") }, + { strstr("You are walking in a dry stream bed."), + { 178, 98, 179, 0, 84, 0, 0, 0 }, +strstr("The large cobblestones are difficult to walk on. No starlight reaches\n\ +below a black canopy of fog seemingly engulfing the whole island. A dirt\n\ +path along the wash is **+. The high bank is impossible to climb +.\n") }, + { strstr("You are at the thermal pools."), + { 98, 0, 180, 181, 84, 0, 0, 0 }, +strstr("Odd spluttering and belching water splashes up around the rocks here.\n\ +A spectacular waterfall nearby tumbles down as a river of effervescent\n\ +bubbles. The air is quite warm and a cave entrance ***+ spews steam.\n") }, + { strstr("You are in the woods."), + { 127, 180, 182, 98, 84, 0, 0, 0 }, +strstr("It is pitch black in the forest here and my pant leg is caught on something.\n\ +There may be poison oak here. What was that? A lantern just flickered by in\n\ +the dark! The sound of rushing water is coming from *+.**\n") }, + { strstr("You are on a dirt trail."), + { 179, 181, 98, 0, 84, 0, 0, 0 }, +strstr("The trail seems to start here and head towards the forest +.** High, dark\n\ +cliffs border the trail +. Some crickets are chirping noisily.\n") }, + { strstr("You are walking along the beach."), + { 183, 101, 184, 0, 87, 0, 0, 0 }, +strstr("The surf is rather tame tonight. The beach continues + and +.**\n") }, + { strstr("You are walking along the beach."), + { 101, 185, 186, 0, 87, 0, 0, 0 }, +strstr("This is not a very nice beach. The coarse sand hurts my feet.****\n") }, + { strstr("You are walking through some ferns."), + { 184, 186, 187, 101, 87, 0, 0, 0 }, +strstr("This is a wide field growing only ferns and small shrubs.** In the dark\n\ +it would be all to easy to stumble into a venomous snake. The ocean is\n\ +*+.\n") }, + { strstr("You are in a narrow canyon."), + { 0, 0, 188, 102, 76, 0, 0, 0 }, +strstr("The steep sides here squeeze a little freshet through a gauntlet like\n\ +series of riffles and pools. The cool mountain air is refreshing.****\n") }, + { strstr("The canyon is much wider here."), + { 0, 0, 102, 189, 76, 0, 0, 0 }, +strstr("The sheer rock walls rise 10 meters into darkness. A slender waterfall\n\ +careens away from the face of the rock high above and showers the gravel\n\ +floor with sparkling raindrops.** The canyon continues -\n\ +and -.\n") }, + { strstr("You are on the front porch of the cottage."), + { 190, 103, 0, 0, 0, 0, 0, 0 }, +strstr("The veranda is deserted. A table and chair are the only things on the porch.\n\ +Inside the house is a parlor lighted with an elegant chandelier. The door\n\ +leads -. The lawn and fountain are +.**\n") }, + { strstr("You are in a palm grove."), + { 103, 191, 192, 105, 88, 0, 0, 0 }, +strstr("Crickets are chirping in the cool night air.****\n") }, + { strstr("You are on a dirt road."), + { 193, 192, 245, 103, 88, 0, 0, 0 }, +strstr("There are many bright lights +. The road cleaves the darkness +.\n\ +A small dirt road goes -, and a drive way peals off +.\n") }, + { strstr("You are in a field of small shrubs."), + { 184, 186, 103, 187, 88, 0, 0, 0 }, +strstr("**Pine and other coniferous saplings are growing here. The rich brown\n\ +soil is well watered. Across a large lawn +, there is a small cottage lighted\n\ +with spot lights and gas lamps. A cool land breeze is blowing.*\n") }, + { strstr("The beach is pretty rocky here."), + { 194, 105, 195, 0, 96, 0, 0, 0 }, +strstr("The tide is very low tonight. The beach is nicer *+.**\n") }, + { strstr("The beach is almost 10 meters wide here."), + { 105, 183, 196, 0, 99, 0, 0, 0 }, +strstr("The sand has become more coarse and the beach steeper.****\n") }, + { strstr("You are in the gardens."), + { 195, 196, 197, 105, 99, 0, 0, 0 }, +strstr("Shadowy expanses of lawn and leaf have been groomed and manicured here.\n\ +The night sky is glowing with a full moon.** A lighted path leads -.\n\ +Stone steps lead down to the beach +.\n") }, + { strstr("You are on the coast road."), + { 198, 106, 163, 199, 73, 0, 0, 0 }, +strstr("The forest is dense on either side. The trees seem to be actually squeezing\n\ +together to keep us from passing. A feeling of emnity is in the air.**\n\ +The road continues - and -.\n") }, + { strstr("You are in the forest."), + { 116, 107, 91, 106, 73, 0, 0, 0 }, +strstr("I suppose there are trees and ferns all around, but it is too dark to see.****\n") }, + { strstr("You are in the forest."), + { 199, 108, 106, 146, 73, 0, 0, 0 }, +strstr("There are shadowy trees and ferns all around.****\n") }, + { strstr("You are in a copse."), + { 142, 107, 145, 80, 0, 0, 0, 0 }, +strstr("This is a secret hidden thicket only noticeable from the beach. In the\n\ +moonlight, I can tell that someone has been digging here recently.****\n") }, + { strstr("You are at the tide pools."), + { 91, 0, 114, 107, 79, 0, 0, 0 }, +strstr("These rocks and pools are the home for many sea anemones and crustaceans.\n\ +They are exposed because of the low tide. There is a beach ***+.\n") }, + { strstr("You are in the forest."), + { 199, 108, 143, 0, 73, 0, 0, 0 }, +strstr("This is a shallow depression sheltered from the wind by a thick growth of \n\ +thorny shrubs. It looks like someone is camping here. There is a fire pit\n\ +with warm, crackling flames and coals here.* The beach is +.* The thorny\n\ +shrubs block the way -.\n") }, + { strstr("You are at the mouth of the lagoon."), + { 200, 0, 108, 201, 74, 0, 0, 0 }, +strstr("The beach ends here where the coral reef rises to form a wide lagoon.\n\ +A path winds around the lagoon to the -.* The beach continues\n\ +on -. Only water lies +.\n") }, + { strstr("You are in a breadfruit grove."), + { 202, 109, 203, 204, 77, 0, 0, 0 }, +strstr("The tall trees bend leisurely in the breeze, holding many round breadfruits\n\ +close to their large serrated leaves. There are coconut palms +,\n\ +*+, and +.\n") }, + { strstr("You are in a grove of mango trees."), + { 203, 111, 205, 109, 77, 0, 0, 0 }, +strstr("The trees are not tall enough to obscure the view and the bright moonlight\n\ +makes it fairly easy to see.****\n") }, + { strstr("You are in a grove of coconut palms."), + { 204, 112, 109, 206, 77, 0, 0, 0 }, +strstr("All I can see around us are trees and ominous shapes darting in and out of the\n\ +shadows.****\n") }, + { strstr("You are in a coconut grove."), + { 110, 207, 208, 209, 77, 0, 0, 0 }, +strstr("There are countless trees here.****\n") }, + { strstr("You are in a field of pineapple."), + { 154, 208, 210, 110, 77, 0, 0, 0 }, +strstr("The sharp leaves are cutting me to ribbons. There is a road **+.*\n") }, + { strstr("You are in a coconut grove."), + { 112, 209, 110, 211, 77, 0, 0, 0 }, +strstr("There is a field of something **+.*\n") }, + { strstr("You are on the edge of a kiwi and pineapple field."), + { 111, 152, 155, 110, 77, 0, 0, 0 }, +strstr("An irrigation ditch separates the two fields here. There is a road **+.*\n") }, + { strstr("This is a dirt road."), + { 205, 210, 212, 111, 77, 0, 0, 0 }, +strstr("The road runs - and - here. It is very dark in the forest.**\n") }, + { strstr("You are in a palm grove."), + { 206, 211, 112, 213, 77, 0, 0, 0 }, +strstr("There are trees all around us.****\n") }, + { strstr("You are on the edge of a small clearing."), + { 157, 113, 157, 157, 79, 0, 0, 0 }, +strstr("The ground is rather marshy here and the darkness is intense. A swarm of\n\ +ravenous mosquitoes has descended upon you and has sent you quaking to your\n\ +knees.****\n") }, + { strstr("You are in the woods."), + { 158, 115, 215, 113, 79, 0, 0, 0 }, +strstr("You have walked a long way and found only spider webs. ****\n") }, + { strstr("You are walking along the shore."), + { 115, 0, 214, 114, 86, 0, 0, 0 }, +strstr("You are now about 10 meters above the surf on a gently rising cliffside.**\n\ +The land rises +. There is a beach far +.\n") }, + { strstr("You are just inside the entrance to the sea cave."), + { 246, 114, 0, 0, 114, 1, 0, 0 }, +strstr("The sound of water dripping in darkness and the roar of the ocean just outside\n\ +create a very unwelcoming atmosphere inside this cave. Only on rare occasions\n\ +such as this is it possible to enter the forbidden catacombs... The cave\n\ +continues -.***\n") }, + { strstr("You are in a secret nook beside the road."), + { 115, 159, 162, 91, 79, 0, 0, 0 }, +strstr("This little thicket is hidden from the road in the shadows of the forest.\n\ +From here we have a clear view of any traffic along the road. A great hollow\n\ +tree stuffed with something is nearby. The road is +.***\n") }, + { strstr("You are on the coast road."), + { 215, 214, 0, 115, 86, 0, 0, 0 }, +strstr("The road turns abruptly - here, wandering deeper into the black forest.***\n") }, + { strstr("You are on a dirt road."), + { 216, 116, 113, 141, 79, 0, 0, 0 }, +strstr("We are walking through a tunnel of unfriendly trees and shrubs. The tall\n\ +ones bend over the roadway and reach down with their branches to grab us.\n\ +Broad leafed plants at the roadside whisper in the darkness. Something\n\ +just darted across the road and into the bushes *+. Let's go *-.\n") }, + { strstr("You have discovered a hidden thicket near the road."), + { 163, 142, 116, 106, 73, 0, 0, 0 }, +strstr("I would think it best to stay n the road. The forest seems very unfriendly\n\ +at night. The road is **+.*\n") }, + { strstr("You are in the living room."), + { 0, 117, 217, 218, 0, 0, 0, 0 }, +strstr("A decorative entry with fresh flowers and wall to wall carpeting leads into\n\ +the living room here where a couch and two chairs converse with an end table.\n\ +*The exit is +.* The bedroom is +.\n") }, + { strstr("You are at the lagoon."), + { 118, 0, 167, 168, 81, 0, 0, 0 }, +strstr("A small beach here is deserted except for some fishing nets. It is very\n\ +peaceful at the lagoon at night. The sound of native drums is carried on\n\ +the night breeze. There are paths leading off into darkness +,\n\ +*+, and +.\n") }, + { strstr("You are at the lagoon."), + { 118, 0, 170, 166, 81, 0, 0, 0 }, +strstr("The grass near the water is moist with the refreshing evening dew. Far away,\n\ +drums reverberate in the forest.** The path continues + and +.\n") }, + { strstr("You are at the lagoon."), + { 118, 0, 166, 172, 81, 0, 0, 0 }, +strstr("The path meanders through shadows of tussocks of grass, ferns, and thorny\n\ +bushes here and continues on **- and -.\n") }, + { strstr("You are in the woods."), + { 219, 119, 220, 92, 81, 0, 0, 0 }, +strstr("There are plenty of ferns and thorny bushes here! Spider webs and probing\n\ +branches snare us as we stumble along in the pitch black night.****\n") }, + { strstr("You are on a dirt road."), + { 220, 167, 199, 119, 74, 0, 0, 0 }, +strstr("The road winds rather close to a large lagoon here and many sedges and tall\n\ +loom in the darkness *+. The road continues - and -.\n") }, + { strstr("You are in the woods beside the road."), + { 221, 120, 92, 222, 81, 0, 0, 0 }, +strstr("The forest grows darker +. The road is +.**\n") }, + { strstr("The road crosses the lagoon here."), + { 222, 0, 120, 174, 81, 0, 0, 0 }, +strstr("Strange mists rising from the water engulf a rickety old enclosed bridge here.\n\ +Spider webs catch our hair as we pass through its rotting timbers. I felt\n\ +something drop on my neck. The road delves into the accursed forest\n\ +**+ and +.\n") }, + { strstr("You are in a coconut palm grove."), + { 223, 121, 224, 225, 82, 0, 0, 0 }, +strstr("The tall palms are planted about 30 feet apart and the stary sky is clearly\n\ +visible above. A low growing grass carpets the ground all around. The grove\n\ +continues +.***\n") }, + { strstr("You are walking along a dirt road."), + { 224, 176, 172, 121, 82, 0, 0, 0 }, +strstr("You are near misty patch of the roadway **+. The road continues -.\n") }, + { strstr("You are on a dirt road."), + { 225, 177, 121, 226, 82, 0, 0, 0 }, +strstr("The road turns abruptly - here, splitting a grove of palm trees.* In the\n\ +starlight I can also discern that the road continues - toward the lagoon.*\n") }, + { strstr("You are on a trail running around the lagoon."), + { 172, 0, 0, 122, 82, 0, 0, 0 }, +strstr("The dark waters brush the trail here and the path crosses an old bridge\n\ ++. There is deep water + and +. The trail continues -.\n") }, + { strstr("This is the mouth of the lagoon."), + { 175, 0, 122, 227, 82, 0, 0, 0 }, +strstr("The coral reef wraps around a natural bay here to create a wide lagoon which\n\ +winds tortuously inland.** A trail goes around the lagoon +.\n\ +The beach is -.\n") }, + { strstr("You are in a dry stream bed."), + { 0, 125, 0, 0, 84, 0, 0, 0 }, +strstr("The dry wash drains over a tall precipice here into a turbid morass below. The\n\ +most noisome stench imaginable is wafting up to defile our nostrils. Above,\n\ +the blackness is intense and a strange mist engulfs the island.* Let's go\n\ +-.**\n") }, + { strstr("You are on a dirt path along the wash."), + { 0, 128, 125, 228, 84, 0, 0, 0 }, +strstr("The trail winds along the gravel wash and delves into the forest ***+.\n") }, + { strstr("The thermal pools flow into a stream here."), + { 127, 0, 229, 126, 84, 0, 0, 0 }, +strstr("The gurgling hot waters pour over boulders into a swiftly flowing\n\ +stream **+. The pools are +.\n") }, + { strstr("You are at the entrance to a cave."), + { 128, 230, 126, 0, 84, 0, 0, 0 }, +strstr("A torch lights the entrance to the cave. Deep inside I can see shadows moving.\n\ +A path goes + from here. The entrance is +.**\n") }, + { strstr("You are in the woods."), + { 182, 229, 182, 127, 84, 0, 0, 0 }, +strstr("Thorns tangle your every effort to proceed.* The sound of rushing water is\n\ ++.**\n") }, + { strstr("You are walking along the beach."), + { 139, 129, 184, 0, 99, 0, 0, 0 }, +strstr("Some dunes here progress inland and make it impossible to get very far in that\n\ +direction. The beach continues - and -.* The ocean is +.\n") }, + { strstr("You are in the dunes."), + { 183, 101, 184, 129, 87, 0, 0, 0 }, +strstr("The endless rolling and pitching sand dunes are enough to make one very queasy!\n\ +The sand is cool and the stars are bright at the ocean. The only way I'm going\n\ +is ***+.\n") }, + { strstr("This is a lousy beach."), + { 130, 0, 0, 0, 87, 0, 0, 0 }, +strstr("Volcanic and viciously sharp bitted grains of sand here bite like cold steel\n\ +into my tender feet. I refuse to continue on. Let's get out of here. The\n\ +beach is better +.***\n") }, + { strstr("You are in a field of sparse ferns."), + { 131, 185, 187, 130, 87, 0, 0, 0 }, +strstr("The lava rock outcroppings here will support few plants. There is more \n\ +vegetation +.** The ocean is +.\n") }, + { strstr("You are in the woods."), + { 131, 131, 137, 131, 87, 0, 0, 0 }, +strstr("Young trees and tall shrubs grow densely together here.\n\ +They grow thicker **+.*\n") }, + { strstr("The canyon is no wider than a foot here."), + { 0, 0, 0, 132, 0, 0, 0, 0 }, +strstr("The freshet is gushing through the narrow trough, but the canyon has grown\n\ +too narrow to follow it any farther.*** I guess we'll have to go -.\n") }, + { strstr("You are in a narrow part of the canyon."), + { 0, 0, 133, 232, 76, 0, 0, 0 }, +strstr("The two sheer sides are no more than a few meters apart here. There is a stone\n\ +door in the wall +. The gravelly floor runs with tiny rivulets seeping \n\ +from the ground itself.* The canyon continues - and -.\n") }, + { strstr("You are in the drawing room."), + { 0, 134, 0, 0, 0, 0, 0, 0 }, +strstr("Exquisitely decorated with plants and antique furniture of superb\n\ +craftsmanship, the parlor reflects its owners impeccable taste. The tropical\n\ +night air pours in through open shutters *+. There doesn't seem \n\ +to be anybody around. A large immaculate oaken desk is visible in the\n\ +study and it even has a old fashioned telephone to complete the decor.**\n") }, + { strstr("You are in a palm grove."), + { 135, 191, 233, 191, 88, 0, 0, 0 }, +strstr("Grassy rows of dew covered palms stretch as far as I can see.**\n\ +There is a road +.*\n") }, + { strstr("You are on a dirt road."), + { 136, 233, 234, 135, 88, 0, 0, 0 }, +strstr("The road winds through a coconut palm grove here. It continues on - \n\ +and -.**\n") }, + { strstr("The road leads to several large buildings here."), + { 235, 136, 236, 237, 88, 0, 0, 0 }, +strstr("There is a lighted clubhouse +,* a large barn and stable +, and a\n\ +garage of similar construct to the barn +.\n") }, + { strstr("This part of the beach is impassable."), + { 0, 138, 0, 0, 96, 0, 0, 0 }, +strstr("The see is calm tonight. The beach goes *-.**\n") }, + { strstr("You are in the gardens."), + { 195, 140, 197, 138, 96, 0, 0, 0 }, +strstr("Dew beaded grass sparkles in the moonlight. Tiny lamps beside the path light\n\ +the way to the ocean ***+.\n") }, + { strstr("You are in the gardens."), + { 140, 183, 197, 139, 99, 0, 0, 0 }, +strstr("Beautiful flowers and shrubs surround a lighted goldfish pond.****\n") }, + { strstr("You are on a stone walk in the garden."), + { 195, 196, 238, 140, 99, 0, 0, 0 }, +strstr("The walk leads to a road **+.*\n") }, + { strstr("You are in the forest near the road."), + { 198, 141, 216, 198, 73, 0, 0, 0 }, +strstr("There are many thorny bushes here!****\n") }, + { strstr("You are at a fork in the road."), + { 239, 146, 141, 170, 73, 0, 0, 0 }, +strstr("Two roads come together in the darkness here. One runs -,* the other \n\ +runs - and -.\n") }, + { strstr("You are on a dirt path around the lagoon."), + { 170, 147, 146, 0, 74, 0, 0, 0 }, +strstr("The still waters reflect bending palms and a stary sky. It looks like\n\ +the path runs into a clearing +. The path continues -.**\n") }, + { strstr("You are drowning in the lagoon."), + { 201, 201, 147, 201, 74, 0, 0, 0 }, +strstr("I suggest you get out before you become waterlogged.****\n") }, + { strstr("You are in a coconut palm grove."), + { 202, 148, 203, 204, 77, 0, 0, 0 }, +strstr("****\n") }, + { strstr("You are in a palm grove."), + { 202, 149, 205, 148, 77, 0, 0, 0 }, +strstr("****\n") }, + { strstr("You are in a palm grove."), + { 202, 150, 148, 206, 77, 0, 0, 0 }, +strstr("****\n") }, + { strstr("You are on a dirt road."), + { 203, 155, 212, 149, 77, 0, 0, 0 }, +strstr("*This road ends here at a palm grove but continues on - for quite\n\ +some way.**\n") }, + { strstr("You are in a coconut palm grove."), + { 204, 156, 150, 213, 77, 0, 0, 0 }, +strstr("****\n") }, + { strstr("You are in a coconut grove."), + { 151, 219, 208, 209, 77, 0, 0, 0 }, +strstr("*The grove ends +.**\n") }, + { strstr("You are in a coconut grove."), + { 152, 207, 239, 151, 77, 0, 0, 0 }, +strstr("**There is a dirt road +.*\n") }, + { strstr("You are in a coconut grove."), + { 153, 207, 151, 211, 77, 0, 0, 0 }, +strstr("****\n") }, + { strstr("This is a dirt road."), + { 205, 239, 212, 154, 77, 0, 0, 0 }, +strstr("The road continues - and -.**\n") }, + { strstr("You are in a coconut grove."), + { 153, 209, 153, 213, 77, 0, 0, 0 }, +strstr("****\n") }, + { strstr("You are in the woods near the road."), + { 205, 210, 212, 155, 77, 0, 0, 0 }, +strstr("There are many thorny bushes here!****\n") }, + { strstr("You are in a coconut grove."), + { 213, 213, 156, 234, 88, 0, 0, 0 }, +strstr("***The grove ends in a clearing +.\n") }, + { strstr("You are walking along some high cliffs."), + { 162, 0, 0, 159, 86, 0, 0, 0 }, +strstr("The island bends sharply + here with high cliffs -\n\ +and -. The cliffs are lower +.\n") }, + { strstr("You are at the coast road turn around."), + { 0, 162, 0, 158, 90, 0, 0, 0 }, +strstr("The coast road ends here in a lookout with a view of the ocean.\n\ +Far below, the waves crash against the rocks.\n\ +****\n") }, + { strstr("You are in the woods near the road."), + { 216, 163, 216, 198, 79, 0, 257, 0 }, +strstr("These thorny bushes are killing me.****\n") }, + { strstr("You are in the kitchen."), + { 0, 0, 0, 165, 0, 0, 0, 0 }, +strstr("A small gas stove and a refrigerator are all the only appliances here. The\n\ +gas oven has been left on and the whole room is reeking with natural gas.\n\ +One spark from a match and.... The door out is ***+.\n") }, + { strstr("You are in the bedroom."), + { 0, 0, 165, 0, 0, 0, 0, 0 }, +strstr("A soft feather comforter on top of layers of Answer blankets make this a very\n\ +luxurious place to sleep indeed. There are also some end tables and a dresser\n\ +here.** The living room is +.*\n") }, + { strstr("You are in the woods."), + { 207, 169, 220, 221, 81, 0, 0, 0 }, +strstr("The darkness is intense, but there seems to be a clearing +.***\n") }, + { strstr("You are in the woods near the road."), + { 219, 170, 239, 169, 81, 0, 0, 0 }, +strstr("*As far as I can tell, there are two roads + and +.*\n") }, + { strstr("You are in the woods."), + { 207, 171, 219, 222, 81, 0, 0, 0 }, +strstr("The spider webs thin out and the forest is clearer +.***\n") }, + { strstr("You are on the lagoon's inland finger."), + { 0, 172, 171, 172, 81, 0, 0, 0 }, +strstr("It is impossible to follow the lagoon any farther inland because of sharp\n\ +and very painful sedges.* The road is +.**\n") }, + { strstr("You are in a grassy coconut grove."), + { 240, 173, 224, 241, 82, 0, 0, 0 }, +strstr("The tall palms provide a ghostly canopy for the sandy ground covering.****\n") }, + { strstr("You are near the lagoon's inland finger."), + { 0, 174, 0, 173, 82, 0, 0, 0 }, +strstr("Very sharp sedges make it impossible to follow the lagoon any farther inland.\n\ +*There is a road +.**\n") }, + { strstr("You are on a dirt road."), + { 241, 175, 173, 226, 82, 0, 0, 0 }, +strstr("The road winds through a coconut grove here and continues - and -.**\n") }, + { strstr("You are in the woods near the road."), + { 226, 226, 175, 226, 82, 0, 0, 0 }, +strstr("**The road is +.*\n") }, + { strstr("This is a beach?"), + { 227, 227, 177, 0, 82, 0, 0, 0 }, +strstr("Hard jagged rocks that pierce with every footstep hardly comprise a beach.**\n\ +Let's go -.*\n") }, + { strstr("The trail is lost in the woods here."), + { 241, 241, 179, 241, 84, 0, 0, 0 }, +strstr("The trail goes **-.*\n") }, + { strstr("You are on the bank of a stream."), + { 182, 0, 242, 180, 84, 0, 0, 0 }, +strstr("The stream falls over several small boulders here and continues on **-.*\n") }, + { strstr("You are just inside the cave."), + { 181, 267, 0, 0, 0, 0, 0, 0 }, +strstr("A steamy hot breath is belching from the depths of the earth within.* The\n\ +cave continues -.**\n") }, + { strstr("You are just inside the cave entrance."), + { 274, 0, 0, 0, 0, 0, 0, 0 }, +strstr("The air is hot and sticky inside. The cave continues -. There is a \n\ +stone door in the wall +. A wooden sign in the dust warns in old elven\n\ +runes, \"GSRF KDIRE NLVEMP!\".**\n") }, + { strstr("You are at the edge of a huge chasm."), + { 0, 0, 189, 0, 76, 0, 0, 0 }, +strstr("Several hundred feet down I can see the glimmer of placid water. The\n\ +rivulets drain over the edge and trickle down into the depths. It is \n\ +impossible to climb down.** The canyon continues -.*\n") }, + { strstr("You are on a dirt road."), + { 192, 241, 240, 191, 88, 0, 0, 0 }, +strstr("The road winds through a coconut grove here. The road continues on into the\n\ +shadows - and -.**\n") }, + { strstr("You are in a coconut palm grove near the road."), + { 193, 233, 213, 192, 88, 0, 0, 0 }, +strstr("***The road is +.\n") }, + { strstr("You are at the clubhouse."), + { 0, 193, 0, 0, 0, 0, 0, 0 }, +strstr("The clubhouse is built over the most inland part of the lagoon. Tropical\n\ +bananas and fragrant frangipani grow along the grassy shore. Walking across\n\ +the short wooden bridge, we enter. Along one wall is a bar crowded with people.\n\ +The restaurant and disco dance floor are filled to capacity. A rock group\n\ +electrocutes itself to the satisfaction of the audience.****\n") }, + { strstr("You are in the stables."), + { 0, 0, 0, 193, 0, 0, 0, 0 }, +strstr("Neighing horses snacking on hay and oats fill the stalls on both sides of\n\ +the barn. It is rather warm in here but that is not the most offensive\n\ +part.****\n") }, + { strstr("You are in the old garage."), + { 0, 0, 193, 0, 0, 0, 0, 0 }, +strstr("This is an old wooden building of the same vintage as the stables. Beneath\n\ +a sagging roof stand gardening tools and greasy rags. Parked in the center\n\ +is an underpowered Plymouth Volare' with a red and white striped golf cart\n\ +roof. ****\n") }, + { strstr("You are on a dirt road."), + { 197, 197, 243, 197, 85, 0, 0, 0 }, +strstr("The road leads to a formal garden laced with lighted stone walks and tropical\n\ +flowers and trees.** The road continues -. A walk leads -.\n") }, + { strstr("You are on a dirt road."), + { 210, 199, 198, 220, 73, 0, 0, 0 }, +strstr("The road runs - and -.**\n") }, + { strstr("You are in a coconut grove near the road."), + { 234, 223, 234, 233, 88, 0, 0, 0 }, +strstr("***The road is +.\n") }, + { strstr("You are on a dirt road."), + { 233, 225, 223, 226, 82, 0, 0, 0 }, +strstr("The road continues - and -.**\n") }, + { strstr("The stream plummets over a cliff here."), + { 182, 0, 0, 229, 84, 0, 0, 0 }, +strstr("Falling 10 agonizing meters into darkness, only droplets of the stream must\n\ +be left to dance off the floor below. There is no way down, even with a\n\ +strong rope. ****\n") }, + { strstr("You are on a dirt road."), + { 0, 0, 244, 238, 85, 0, 0, 0 }, +strstr("**The road continues - and -.\n") }, + { strstr("You are on a dirt road."), + { 0, 245, 0, 243, 88, 0, 0, 0 }, +strstr("*The road continues -* and -.\n") }, + { strstr("You are on a dirt road."), + { 244, 234, 213, 136, 88, 0, 0, 0 }, +strstr("The road goes -* and *-.\n") }, + { strstr("You are in a low passage."), + { 247, 160, 0, 0, 0, 0, 0, 0 }, +strstr("The ceiling here sparkles with iridiscent gems and minerals. Colorful starfish\n\ +and sea anemones cling to the slippery walls and floor. The passage continues\n\ ++.***\n") }, + { strstr("The walls are very close together here."), + { 248, 246, 0, 0, 0, 0, 0, 0 }, +strstr("I can barely squeeze through the jagged opening. Slimy sea weeds provide\n\ +no footing at all. This tunnel seems to be an ancient lava tube. There is\n\ +a large room +.***\n") }, + { strstr("You are in the cathedral room."), + { 249, 247, 250, 251, 0, 0, 0, 0 }, +strstr("Your light casts ghostly shadows on the walls but cannot pierce the \n\ +engulfing darkness overhead. The sound of water dripping echoes in the void.\n\ +*I can see no passages leading out of this room.*** \n") }, + { strstr("You are walking through a very round tunnel."), + { 252, 248, 0, 0, 252, 1, 0, 0 }, +strstr("The round walls of this tunnel are amazingly smooth to the touch. A little\n\ +trickle of water flows down the center. The tunnel climbs steadily +.\n\ +There is a large room +.**\n") }, + { strstr("You are in the cathedral anteroom."), + { 0, 0, 0, 248, 253, 1, 0, 0 }, +strstr("This small chamber with a flat stone floor is to one side of the cathedral \n\ +room. We appear to be at the bottom of a tall narrow shaft. There are many \n\ +puddles of water here. A staircase hewn from solid rock and black lava \n\ +leads up.*** The cathedral room is -.\n") }, + { strstr("You are in a wide chamber."), + { 0, 0, 248, 254, 0, 0, 0, 0 }, +strstr("Water is sprinkling from the ceiling here. A shallow pool populated by a \n\ +myriad of blind white creatures sparkles in your light. Tiny shrimp and\n\ +crabs scurry away, frightened by the blinding rays.** The cave \n\ +continues + and +.\n") }, + { strstr("You are at the top of a sloping passage."), + { 0, 249, 255, 256, 257, 1, 249, 0 }, +strstr("There is much algae growing here, both green and brown specimens. I suspect\n\ +that we are near the high tide zone, but no light can get in here. The walls\n\ +glisten with shiny minerals.** A hallway here runs + and -.\n") }, + { strstr("You are in an elaborately tiled room."), + { 0, 0, 258, 0, 0, 0, 250, 0 }, +strstr("Large colorful tiles plate the floor and walls. The ceiling is a mosaic\n\ +of gems set in gold. Hopefully it is only our footsteps that are echoing in\n\ +this hollow chamber.** The room continues -. A stone staircase leads\n\ +down.*\n") }, + { strstr("You are at a dead end."), + { 0, 0, 251, 0, 0, 0, 0, 0 }, +strstr("The walls here are alive with dark mussels. They click their shells menacingly\n\ +if we disturb them.** The only exit is +.*\n") }, + { strstr("The tunnel is very low here."), + { 0, 0, 259, 252, 0, 0, 0, 0 }, +strstr("You practically have to crawl on your knees to pass through this opening. The\n\ +air is stiflingly damp, but you can't hear any sounds of water dripping.**\n\ +The crawlspace continues -. The tunnel seems wider +.\n") }, + { strstr("This is the supply room."), + { 0, 0, 252, 0, 0, 0, 0, 0 }, +strstr("Picks and shovels line the walls here, as well as hard hats, boxes of\n\ +dynamite, and a cartload of very high grade gold and silver ore.** \n\ +A tunnel leads off +.*\n") }, + { strstr("You have found a secret entrance to the catacombs"), + { 0, 0, 0, 0, 216, 1, 252, 0 }, +strstr("Below is a wet, seaweed covered floor. Above is a way out.****\n") }, + { strstr("You are in the catacombs."), + { 0, 0, 260, 253, 0, 0, 0, 0 }, +strstr("Ornate tombs and piles of treasure line the walls. Long spears with many\n\ +blades, fine swords and coats of mail, heaps of coins, jewelry, pottery, \n\ +and golden statues are tribute past kings and queens.** The catacombs\n\ +continue - and -.\n") }, + { strstr("You are crawling on your stomach."), + { 0, 0, 261, 255, 0, 0, 0, 0 }, +strstr("The passage is quite narrow and jagged, but the rock is no longer lava.\n\ +It appears to be a form of granite.** The crawlspace continues -, \n\ +but I would just as soon go -.\n") }, + { strstr("You are in the Sepulcher."), + { 0, 0, 0, 258, 0, 0, 0, 0 }, +strstr("A single tomb is here. Encrusted with diamonds and opals, and secured with \n\ +straps of a very hard, untarnished silver, this tomb must be of a great king.\n\ +Vases overflowing with gold coins stand nearby. A line of verse on the wall\n\ +reads, \"Three he made and gave them to his daughters.\"****\n") }, + { strstr("The passage is wider here."), + { 0, 0, 0, 259, 0, 0, 262, 0 }, +strstr("A ladder goes down into darkness here.*** A small crawlspace goes -.\n") }, + { strstr("You are at the bottom of a ladder."), + { 0, 0, 0, 0, 261, 1, 263, 0 }, +strstr("This is a narrow platform to rest on before we continue either up or down this\n\ +rickety wooden ladder.****\n") }, + { strstr("You are standing in several inches of water."), + { 264, 0, 265, 266, 262, 1, 0, 0 }, +strstr("This seems to be a working mine. Many different tunnels wander off following\n\ +glowing veins of precious metal. The floor is flooded here since we must\n\ +be nearly at sea level. A ladder leads up.****\n") }, + { strstr("The tunnel here is blocked by broken rocks."), + { 0, 263, 0, 0, 0, 0, 0, 0 }, +strstr("The way is blocked, but if you had some dynamite, we might be able to blast our\n\ +way through.* The passage goes -.**\n") }, + { strstr("The tunnel is too flooded to proceed."), + { 0, 0, 0, 263, 0, 0, 0, 0 }, +strstr("Hidden shafts could swallow us if we tried to continue on down this tunnel.\n\ +The flooding is already up to my waist. Large crystals overhead shimmer\n\ +rainbows of reflected light.*** Let's go -.\n") }, + { strstr("The mine is less flooded here."), + { 0, 0, 263, 0, 0, 0, 0, 0 }, +strstr("A meandering gold laden vein of quartz and blooming crystals of diamonds\n\ +and topaz burst from the walls of the cave. A passage goes -.***\n") }, + { strstr("You are inside the cave."), + { 230, 268, 0, 0, 0, 0, 0, 0 }, +strstr("A hot steam swirls around our heads, and the walls are warm to the touch.\n\ +The trail winds - and -.**\n") }, + { strstr("You are in a rather large chamber."), + { 267, 0, 0, 269, 0, 0, 269, 0 }, +strstr("Beds of ferns and palm leaves make several cozy nests along the walls. In the\n\ +center of the room is a throne of gold and silver.*** A passageway leads\n\ +down and +.\n") }, + { strstr("You are walking along the edge of a huge abyss."), + { 0, 0, 268, 0, 268, 1, 270, 0 }, +strstr("Steam is rising in great clouds from the immeasurable depths. A very narrow\n\ +trail winds down.** There is a tunnel -.*\n") }, + { strstr("You are on the edge of a huge abyss."), + { 0, 0, 0, 0, 269, 1, 271, 0 }, +strstr("The trail winds farther down.****\n") }, + { strstr("You are winding your way along the abyss."), + { 0, 0, 0, 0, 270, 1, 272, 0 }, +strstr("The trail continues up and down.****\n") }, + { strstr("You are on a wide shelf near the steamy abyss."), + { 0, 273, 0, 0, 271, 1, 0, 0 }, +strstr("The stifling hot cave seems even hotter to me, staring down into this misty \n\ +abyss. A trail winds up.* A passageway leads -.**\n") }, + { strstr("You are in a wide tunnel leading to a fuming abyss."), + { 272, 274, 0, 0, 0, 0, 0, 0 }, +strstr("The passageway winds through many beautiful formations of crystals and\n\ +sparkling minerals. The tunnel continues - and -.**\n") }, + { strstr("You are in a tunnel."), + { 273, 231, 0, 0, 0, 0, 0, 0 }, +strstr("It is very warm in here. The smell of steam and hot rocks permeates the place.\n\ +The cave continues - and -.**\n") }, + { strstr("You are at the bottom of a pit."), + { 0, 0, 0, 0, 232, 0, 0, 0 }, +strstr("At the top of the pit, a single star can be seen in the night sky. There\n\ +doesn't appear to be any way to get out without a rope. I don't remember\n\ +how we got here.****\n") }, +}; diff --git a/src/games/battlestar/nightobjs.c b/src/games/battlestar/nightobjs.c new file mode 100644 index 0000000..3b77bfc --- /dev/null +++ b/src/games/battlestar/nightobjs.c @@ -0,0 +1,68 @@ +/* + * Copyright (c) 1983 Regents of the University of California, + * All rights reserved. Redistribution permitted subject to + * the terms of the Berkeley Software License Agreement. + */ +#include "externs.h" + +struct objs nightobjs[] = { + { 218, PAJAMAS }, + { 235, NATIVE }, + { 92, PAPAYAS }, + { 92, PINEAPPLE }, + { 92, KIWI }, + { 92, MANGO }, + { 92, NATIVE }, + { 92, MAN }, + { 181, LAMPON }, + { 236, LAMPON }, + { 92, LAMPON }, + { 216, WOODSMAN }, + { 216, DEADWOOD }, + { 216, MALLET }, + { 168, WOODSMAN }, + { 168, DEADWOOD }, + { 168, MALLET }, + { 170, WOODSMAN }, + { 170, DEADWOOD }, + { 170, MALLET }, + { 124, SHIELD }, + { 124, HALBERD }, + { 124, ELF }, + { 144, SHIELD }, + { 144, HALBERD }, + { 144, ELF }, + { 113, SHIELD }, + { 113, HALBERD }, + { 113, ELF }, + { 161, SHIELD }, + { 161, HALBERD }, + { 161, ELF }, + { 169, SHIELD }, + { 169, HALBERD }, + { 169, ELF }, + { 182, SHIELD }, + { 182, HALBERD }, + { 182, ELF }, + { 198, SHIELD }, + { 198, HALBERD }, + { 198, ELF }, + { 212, SHIELD }, + { 212, HALBERD }, + { 212, ELF }, + { 216, SHIELD }, + { 216, HALBERD }, + { 216, ELF }, + { 226, SHIELD }, + { 226, HALBERD }, + { 226, ELF }, + { 228, SHIELD }, + { 228, HALBERD }, + { 228, ELF }, + { 68, CYLON }, + { 144, SHOVEL }, + { 249, FOOT }, + { 250, FOOT }, + { 93, PAPAYAS }, + { 0 }, +}; diff --git a/src/games/battlestar/parse.c b/src/games/battlestar/parse.c new file mode 100644 index 0000000..e8a6b08 --- /dev/null +++ b/src/games/battlestar/parse.c @@ -0,0 +1,73 @@ +/* + * Copyright (c) 1983 Regents of the University of California, + * All rights reserved. Redistribution permitted subject to + * the terms of the Berkeley Software License Agreement. + */ +#include "externs.h" + +int +hash(s) + register char *s; +{ + register int hashval = 0; + + while (*s) { + hashval += *s++; + hashval *= HASHMUL; + hashval &= HASHMASK; + } + return hashval; +} + +struct wlist * +lookup(s) + char *s; +{ + register struct wlist *wp; + + for (wp = hashtab[hash(s)]; wp != NULL; wp = wp->next) + if (*s == *wp->string && strcmp(s, wp->string) == 0) + return wp; + return NULL; +} + +static void +install(wp) + register struct wlist *wp; +{ + int hashval; + + if (lookup(wp->string) == NULL) { + hashval = hash(wp->string); + wp->next = hashtab[hashval]; + hashtab[hashval] = wp; + } else + printf("Multiply defined %s.\n", wp->string); +} + +void +wordinit() +{ + register struct wlist *w; + + for (w = wlist; w->string; w++) + install(w); +} + +void +parse() +{ + register struct wlist *wp; + register int n; + + wordnumber = 0; /* for cypher */ + for (n = 0; n <= wordcount; n++) { + if ((wp = lookup(words[n])) == NULL) { + wordvalue[n] = -1; + wordtype[n] = -1; + } else { + wordvalue[n] = wp -> value; + wordtype[n] = wp -> article; + } + } +} diff --git a/src/games/battlestar/room.c b/src/games/battlestar/room.c new file mode 100644 index 0000000..4bc1389 --- /dev/null +++ b/src/games/battlestar/room.c @@ -0,0 +1,276 @@ +/* + * Copyright (c) 1983 Regents of the University of California, + * All rights reserved. Redistribution permitted subject to + * the terms of the Berkeley Software License Agreement. + */ +#include "externs.h" + +#ifdef EXT_MESSAGE_FILE +#include +#include +#include + +static int desc = -1; + +void +writedes() +{ + int compass; + register char *p; + register int c; + char buf[BUFSIZ]; + + if (desc < 0) { + desc = open(BATTLESTRINGS, O_RDONLY, 0666); + if (desc < 0) { + perror(BATTLESTRINGS); + exit(1); + } + } + + lseek(desc, (off_t) location[position].name, L_SET); + if (read(desc, buf, sizeof(buf)) != sizeof(buf)) /*ignore*/; + printf("\n\t%s\n", buf); + if (beenthere[position] < 3) { + compass = NORTH; + lseek(desc, (off_t) location[position].desc, L_SET); + if (read(desc, buf, sizeof(buf)) != sizeof(buf)) /*ignore*/; + p = buf; + while ((c = *p++)) { + if (c != '-' && c != '*' && c != '+') + putchar(c); + else { + if (c != '*') + printf("%s", truedirec(compass, c)); + compass++; + } + } + } +} + +void +printobjs() +{ + register unsigned int *p = location[position].objects; + register int n; + char buf[BUFSIZ]; + + printf("\n"); + for (n = 0; n < NUMOFOBJECTS; n++) + if (testbit(p, n) && objdes[n]) { + lseek(desc, (off_t) objdes[n], L_SET); + if (read(desc, buf, sizeof(buf)) != sizeof(buf)) /*ignore*/; + puts(buf); + } +} + +void +strprt(n) + int n; +{ + char buf[BUFSIZ]; + + if (lseek(desc, (off_t) objdes[n], L_SET) != objdes[n] || + read(desc, buf, sizeof(buf)) != sizeof(buf)) { + perror(BATTLESTRINGS); + exit(1); + } + printf("%s\n", buf); +} + +#else /* EXT_MESSAGE_FILE */ + +void +writedes() +{ + int compass; + register char *p; + register int c; + + printf("\n\t%s\n", location[position].name); + if (beenthere[position] < 3) { + compass = NORTH; + p = location[position].desc; + while ((c = *p++) != 0) { + if (c != '-' && c != '*' && c != '+') + putchar(c); + else { + if (c != '*') + printf("%s", truedirec(compass, c)); + compass++; + } + } + } +} + +void +printobjs() +{ + register unsigned int *p = location[position].objects; + register int n; + + printf("\n"); + for (n = 0; n < NUMOFOBJECTS; n++) + if (testbit(p, n) && objdes[n]) + puts(objdes[n]); +} +#endif /* EXT_MESSAGE_FILE */ + +void +whichway(here) + struct room here; +{ + switch(direction) { + + case NORTH: + left = here.west; + right = here.east; + ahead = here.north; + back = here.south; + break; + + case SOUTH: + left = here.east; + right = here.west; + ahead = here.south; + back = here.north; + break; + + case EAST: + left = here.north; + right = here.south; + ahead = here.east; + back = here.west; + break; + + case WEST: + left = here.south; + right = here.north; + ahead = here.west; + back = here.east; + break; + + } +} + +char * +truedirec(way, option) + int way; + char option; +{ + switch(way) { + + case NORTH: + switch(direction) { + case NORTH: + return("ahead"); + case SOUTH: + return(option == '+' ? "behind you" : "back"); + case EAST: + return("left"); + case WEST: + return("right"); + } + + case SOUTH: + switch(direction) { + case NORTH: + return(option == '+' ? "behind you" : "back"); + case SOUTH: + return("ahead"); + case EAST: + return("right"); + case WEST: + return("left"); + } + + case EAST: + switch(direction) { + case NORTH: + return("right"); + case SOUTH: + return("left"); + case EAST: + return("ahead"); + case WEST: + return(option == '+' ? "behind you" : "back"); + } + + case WEST: + switch(direction) { + case NORTH: + return("left"); + case SOUTH: + return("right"); + case EAST: + return(option == '+' ? "behind you" : "back"); + case WEST: + return("ahead"); + } + + default: + printf("Error: room %d. More than four directions wanted.", position); + return("!!"); + } +} + +void +newway(thisway) + int thisway; +{ + switch(direction){ + + case NORTH: + switch(thisway){ + case LEFT: + direction = WEST; + break; + case RIGHT: + direction = EAST; + break; + case BACK: + direction = SOUTH; + break; + } + break; + case SOUTH: + switch(thisway){ + case LEFT: + direction = EAST; + break; + case RIGHT: + direction = WEST; + break; + case BACK: + direction = NORTH; + break; + } + break; + case EAST: + switch(thisway){ + case LEFT: + direction = NORTH; + break; + case RIGHT: + direction = SOUTH; + break; + case BACK: + direction = WEST; + break; + } + break; + case WEST: + switch(thisway){ + case LEFT: + direction = SOUTH; + break; + case RIGHT: + direction = NORTH; + break; + case BACK: + direction = EAST; + break; + } + break; + } +} diff --git a/src/games/battlestar/save.c b/src/games/battlestar/save.c new file mode 100644 index 0000000..07c79d1 --- /dev/null +++ b/src/games/battlestar/save.c @@ -0,0 +1,117 @@ +/* + * Copyright (c) 1983 Regents of the University of California, + * All rights reserved. Redistribution permitted subject to + * the terms of the Berkeley Software License Agreement. + */ +#include "externs.h" + +void +restore() +{ + char *home; + char home1[100]; + register int n; + int tmp; + register FILE *fp; + + home = getenv("HOME"); + strcpy(home1, home); + strcat(home1, "/Bstar"); + if ((fp = fopen(home1, "r")) == 0) { +fatal: perror(home1); + return; + } + if (fread(&WEIGHT, sizeof WEIGHT, 1, fp) != 1) goto fatal; + if (fread(&CUMBER, sizeof CUMBER, 1, fp) != 1) goto fatal; + if (fread(&clk, sizeof clk, 1, fp) != 1) goto fatal; + if (fread(&tmp, sizeof tmp, 1, fp) != 1) goto fatal; + location = tmp ? dayfile : nightfile; + for (n = 1; n <= NUMOFROOMS; n++) { + if (fread(location[n].link, sizeof location[n].link, 1, fp) != 1) goto fatal; + if (fread(location[n].objects, sizeof location[n].objects, 1, fp) != 1) goto fatal; + } + if (fread(inven, sizeof inven, 1, fp) != 1) goto fatal; + if (fread(wear, sizeof wear, 1, fp) != 1) goto fatal; + if (fread(injuries, sizeof injuries, 1, fp) != 1) goto fatal; + if (fread(notes, sizeof notes, 1, fp) != 1) goto fatal; + if (fread(&direction, sizeof direction, 1, fp) != 1) goto fatal; + if (fread(&position, sizeof position, 1, fp) != 1) goto fatal; + if (fread(&Time, sizeof Time, 1, fp) != 1) goto fatal; + if (fread(&fuel, sizeof fuel, 1, fp) != 1) goto fatal; + if (fread(&torps, sizeof torps, 1, fp) != 1) goto fatal; + if (fread(&carrying, sizeof carrying, 1, fp) != 1) goto fatal; + if (fread(&encumber, sizeof encumber, 1, fp) != 1) goto fatal; + if (fread(&rythmn, sizeof rythmn, 1, fp) != 1) goto fatal; + if (fread(&followfight, sizeof followfight, 1, fp) != 1) goto fatal; + if (fread(&ate, sizeof ate, 1, fp) != 1) goto fatal; + if (fread(&snooze, sizeof snooze, 1, fp) != 1) goto fatal; + if (fread(&meetgirl, sizeof meetgirl, 1, fp) != 1) goto fatal; + if (fread(&followgod, sizeof followgod, 1, fp) != 1) goto fatal; + if (fread(&godready, sizeof godready, 1, fp) != 1) goto fatal; + if (fread(&win, sizeof win, 1, fp) != 1) goto fatal; + if (fread(&wintime, sizeof wintime, 1, fp) != 1) goto fatal; + if (fread(&matchlight, sizeof matchlight, 1, fp) != 1) goto fatal; + if (fread(&matchcount, sizeof matchcount, 1, fp) != 1) goto fatal; + if (fread(&loved, sizeof loved, 1, fp) != 1) goto fatal; + if (fread(&pleasure, sizeof pleasure, 1, fp) != 1) goto fatal; + if (fread(&power, sizeof power, 1, fp) != 1) goto fatal; + if (fread(&ego, sizeof ego, 1, fp) != 1) goto fatal; + + fclose(fp); +} + +void +save() +{ + char *home; + char home1[100]; + register int n; + int tmp; + FILE *fp; + + home = getenv("HOME"); + strcpy(home1, home); + strcat(home1, "/Bstar"); + if ((fp = fopen(home1, "w")) == 0) { + perror(home1); + return; + } + printf("Saved in %s.\n", home1); + fwrite(&WEIGHT, sizeof WEIGHT, 1, fp); + fwrite(&CUMBER, sizeof CUMBER, 1, fp); + fwrite(&clk, sizeof clk, 1, fp); + tmp = location == dayfile; + fwrite(&tmp, sizeof tmp, 1, fp); + for (n = 1; n <= NUMOFROOMS; n++) { + fwrite(location[n].link, sizeof location[n].link, 1, fp); + fwrite(location[n].objects, sizeof location[n].objects, 1, fp); + } + fwrite(inven, sizeof inven, 1, fp); + fwrite(wear, sizeof wear, 1, fp); + fwrite(injuries, sizeof injuries, 1, fp); + fwrite(notes, sizeof notes, 1, fp); + fwrite(&direction, sizeof direction, 1, fp); + fwrite(&position, sizeof position, 1, fp); + fwrite(&Time, sizeof Time, 1, fp); + fwrite(&fuel, sizeof fuel, 1, fp); + fwrite(&torps, sizeof torps, 1, fp); + fwrite(&carrying, sizeof carrying, 1, fp); + fwrite(&encumber, sizeof encumber, 1, fp); + fwrite(&rythmn, sizeof rythmn, 1, fp); + fwrite(&followfight, sizeof followfight, 1, fp); + fwrite(&ate, sizeof ate, 1, fp); + fwrite(&snooze, sizeof snooze, 1, fp); + fwrite(&meetgirl, sizeof meetgirl, 1, fp); + fwrite(&followgod, sizeof followgod, 1, fp); + fwrite(&godready, sizeof godready, 1, fp); + fwrite(&win, sizeof win, 1, fp); + fwrite(&wintime, sizeof wintime, 1, fp); + fwrite(&matchlight, sizeof matchlight, 1, fp); + fwrite(&matchcount, sizeof matchcount, 1, fp); + fwrite(&loved, sizeof loved, 1, fp); + fwrite(&pleasure, sizeof pleasure, 1, fp); + fwrite(&power, sizeof power, 1, fp); + fwrite(&ego, sizeof ego, 1, fp); + + fclose(fp); +} diff --git a/src/games/battlestar/words.c b/src/games/battlestar/words.c new file mode 100644 index 0000000..f312161 --- /dev/null +++ b/src/games/battlestar/words.c @@ -0,0 +1,174 @@ +/* + * Copyright (c) 1983 Regents of the University of California, + * All rights reserved. Redistribution permitted subject to + * the terms of the Berkeley Software License Agreement. + */ +#include "externs.h" + +struct wlist wlist[] = { + { "knife", KNIFE, OBJECT }, + { "sword", SWORD, NOUNS }, + { "scabbard", SWORD, OBJECT }, + { "fine", SWORD, OBJECT }, + { "two-handed", TWO_HANDED, OBJECT }, + { "cleaver", CLEAVER, OBJECT }, + { "broadsword", BROAD, OBJECT }, + { "mail", MAIL, OBJECT }, + { "coat", MAIL, OBJECT }, + { "helmet", HELM, OBJECT }, + { "shield", SHIELD, OBJECT }, + { "maid", MAID, OBJECT }, + { "maid's", MAID, OBJECT }, + { "body", BODY, NOUNS }, + { "viper", VIPER, OBJECT }, + { "lamp", LAMPON, OBJECT }, + { "lantern", LAMPON, OBJECT }, + { "shoes", SHOES, OBJECT }, + { "pajamas", PAJAMAS, OBJECT }, + { "robe", ROBE, OBJECT }, + { "amulet", AMULET, NOUNS }, + { "medallion", MEDALION, NOUNS }, + { "talisman", TALISMAN, NOUNS }, + { "woodsman", DEADWOOD, OBJECT }, + { "woodsman's", DEADWOOD, OBJECT }, + { "mallet", MALLET, OBJECT }, + { "laser", LASER, OBJECT }, + { "pistol", LASER, OBJECT }, + { "blaster", LASER, OBJECT }, + { "gun", LASER, OBJECT }, + { "goddess", NORMGOD, NOUNS }, + { "grenade", GRENADE, OBJECT }, + { "chain", CHAIN, OBJECT }, + { "rope", ROPE, OBJECT }, + { "levis", LEVIS, OBJECT }, + { "pants", LEVIS, OBJECT }, + { "mace", MACE, OBJECT }, + { "shovel", SHOVEL, OBJECT }, + { "halberd", HALBERD, OBJECT }, + { "compass", COMPASS, OBJECT }, + { "elf", ELF, OBJECT }, + { "coins", COINS, OBJECT }, + { "matches", MATCHES, OBJECT }, + { "match", MATCHES, OBJECT }, + { "book", MATCHES, OBJECT }, + { "man", MAN, NOUNS }, + { "papayas", PAPAYAS, OBJECT }, + { "pineapple", PINEAPPLE, OBJECT }, + { "kiwi", KIWI, OBJECT }, + { "coconuts", COCONUTS, OBJECT }, + { "mango", MANGO, OBJECT }, + { "ring", RING, OBJECT }, + { "potion", POTION, OBJECT }, + { "bracelet", BRACELET, OBJECT }, + { "timer", TIMER, NOUNS }, + { "bomb", BOMB, OBJECT }, + { "warhead", BOMB, OBJECT }, + { "girl", NATIVE, NOUNS }, + { "native", NATIVE, NOUNS }, + { "horse", HORSE, OBJECT }, + { "stallion", HORSE, OBJECT }, + { "car", CAR, OBJECT }, + { "volare", CAR, OBJECT }, + { "pot", POT, OBJECT }, + { "jewels", POT, OBJECT }, + { "bar", BAR, OBJECT }, + { "diamond", BLOCK, OBJECT }, + { "block", BLOCK, OBJECT }, + { "up", UP, VERB }, + { "u", UP, VERB }, + { "down", DOWN, VERB }, + { "d", DOWN, VERB }, + { "ahead", AHEAD, VERB }, + { "a", AHEAD, VERB }, + { "back", BACK, VERB }, + { "b", BACK, VERB }, + { "right", RIGHT, VERB }, + { "r", RIGHT, VERB }, + { "left", LEFT, VERB }, + { "l", LEFT, VERB }, + { "take", TAKE, VERB }, + { "get", TAKE, VERB }, + { "use", USE, VERB }, + { "look", LOOK, VERB }, + { "lo", LOOK, VERB }, + { "quit", QUIT, VERB }, + { "q", QUIT, VERB }, + { "su", SU, VERB }, + { "drop", DROP, VERB }, + { "draw", DRAW, VERB }, + { "pull", DRAW, VERB }, + { "carry", DRAW, VERB }, + { "wear", WEARIT, VERB }, + { "sheathe", WEARIT, VERB }, + { "put", PUT, VERB }, + { "buckle", PUT, VERB }, + { "strap", PUT, VERB }, + { "tie", PUT, VERB }, + { "inven", INVEN, VERB }, + { "i", INVEN, VERB }, + { "everything", EVERYTHING, OBJECT }, + { "all", EVERYTHING, OBJECT }, + { "and", AND, CONJ }, + { "kill", KILL, VERB }, + { "fight", KILL, VERB }, + { "ravage", RAVAGE, VERB }, + { "rape", RAVAGE, VERB }, + { "undress", UNDRESS, VERB }, + { "throw", THROW, VERB }, + { "launch", LAUNCH, VERB }, + { "land", LANDIT, VERB }, + { "light", LIGHT, VERB }, + { "strike", LIGHT, VERB }, + { "follow", FOLLOW, VERB }, + { "chase", FOLLOW, VERB }, + { "kiss", KISS, VERB }, + { "love", LOVE, VERB }, + { "fuck", LOVE, VERB }, + { "give", GIVE, VERB }, + { "smite", SMITE, VERB }, + { "attack", SMITE, VERB }, + { "swing", SMITE, VERB }, + { "stab", SMITE, VERB }, + { "slice", SMITE, VERB }, + { "cut", SMITE, VERB }, + { "hack", SMITE, VERB }, + { "shoot", SHOOT, VERB }, + { "blast", SHOOT, VERB }, + { "on", ON, PREPS }, + { "off", OFF, PREPS }, + { "time", TIME, VERB }, + { "sleep", SLEEP, VERB }, + { "dig", DIG, VERB }, + { "eat", EAT, VERB }, + { "swim", SWIM, VERB }, + { "drink", DRINK, VERB }, + { "door", DOOR, NOUNS }, + { "save", SAVE, VERB }, + { "ride", RIDE, VERB }, + { "mount", RIDE, VERB }, + { "drive", DRIVE, VERB }, + { "start", DRIVE, VERB }, + { "score", SCORE, VERB }, + { "points", SCORE, VERB }, + { "bury", BURY, VERB }, + { "jump", JUMP, VERB }, + { "kick", KICK, VERB }, + { "kerosene", 0, ADJS }, + { "plumed", 0, ADJS }, + { "ancient", 0, ADJS }, + { "golden", 0, ADJS }, + { "gold", 0, ADJS }, + { "ostrich", 0, ADJS }, + { "rusty", 0, ADJS }, + { "old", 0, ADJS }, + { "dented", 0, ADJS }, + { "blue", 0, ADJS }, + { "purple", 0, ADJS }, + { "kingly", 0, ADJS }, + { "the", 0, ADJS }, + { "climb", 0, ADJS }, + { "move", 0, ADJS }, + { "make", 0, ADJS }, + { "to", 0, ADJS }, + { 0 }, +}; diff --git a/src/games/bcd.6 b/src/games/bcd.6 new file mode 100644 index 0000000..3badae5 --- /dev/null +++ b/src/games/bcd.6 @@ -0,0 +1,18 @@ +.TH BCD 6 +.SH NAME +bcd, ppt \- convert to antique media +.SH SYNOPSIS +.B /usr/games/bcd +text +.PP +.B /usr/games/ppt +.SH DESCRIPTION +.I Bcd +converts the literal +.I text +into a form familiar to old-timers. +.PP +.I Ppt +converts the standard input into yet another form. +.SH "SEE ALSO" +dd(1) diff --git a/src/games/bcd.c b/src/games/bcd.c new file mode 100644 index 0000000..370c950 --- /dev/null +++ b/src/games/bcd.c @@ -0,0 +1,151 @@ +#ifdef CROSS +# include +#else +# include +#endif + +int chtab[] = { + 00000, /* */ + 03004, /* ! */ + 02404, /* " */ + 02040, /* sharp */ + 02042, /* $ */ + 02104, /* % */ + 00001, /* & */ + 03002, /* ' */ + 02201, /* ( */ + 02202, /* ) */ + 02102, /* * */ + 00005, /* + */ + 02044, /* , */ + 00002, /* - */ + 02041, /* . */ + 00014, /* / */ + 00004, /* 0 */ + 00010, /* 1 */ + 00020, /* 2 */ + 00040, /* 3 */ + 00100, /* 4 */ + 00200, /* 5 */ + 00400, /* 6 */ + 01000, /* 7 */ + 02000, /* 8 */ + 04000, /* 9 */ + 02200, /* : */ + 02402, /* ; */ + 02401, /* < */ + 02204, /* = */ + 02400, /* > */ + 03000, /* ? */ + 02100, /* at */ + 011, + 021, + 041, + 0101, + 0201, + 0401, + 01001, + 02001, + 04001, + 012, + 022, + 042, + 0102, + 0202, + 0402, + 01002, + 02002, + 02002, + 024, + 044, + 0104, + 0204, + 0404, + 01004, + 02004, + 04004, + 02020, /* [ */ + 03001, /* \ */ + 02101, /* ] */ + 00006, /* ^ */ + 02024 /* _ */ +}; + +char s[128]; +char *sp = {&s[0]}; + +void putstr(ss) + char *ss; +{ + int t; + + while ((t = *ss++)) { + if (t >= 'a' && t <= 'z') + t += 'A'-'a'; + putchar(t); + } +} + +int main(argc, argv) + char *argv[]; +{ + char *spp; + int i; + int j; + int c; + int l; + + if (argc < 2) { + putstr("% "); + while ((c = getchar()) != '\0' && c != '\n') + *sp++ = c; + *sp = 0; + sp = &s[0]; + } else + sp = *++argv; + putstr("\n\n\n\n"); + putstr(" ________________________________"); + putstr("________________\n"); + spp = sp; + while(*spp++); + spp--; + l = spp - sp; + putchar('/'); + putstr(sp); + i = 49 - l; + while(--i>0) putchar(' '); + putstr("|\n"); + j = 0; + spp = sp; + while (j++ < 12) { + putchar('|'); + i = 0; + spp = sp; + while (i < 48) { + if (i > l) + c = 0; + else + c = *spp++ - 040; + i++; + if (c >= 'a' - 040) + c = c - 040; + + if (c < 0 || c > 137) + c = 0; + + if ((chtab[c] >> (j-1)) & 1) + putstr(":"); + else if (j > 3) + putchar('0' + j - 3); + else + putchar(' '); + } + putstr("|\n"); + } + putchar('|'); + putstr("____________"); + putstr("____________________________________"); + putstr("|\n"); + putstr("\n\n\n\n"); + return 0; +} diff --git a/src/games/boggle/Makefile b/src/games/boggle/Makefile new file mode 100644 index 0000000..b3179aa --- /dev/null +++ b/src/games/boggle/Makefile @@ -0,0 +1,32 @@ +# +# Copyright (c) 1980 Regents of the University of California. +# All rights reserved. The Berkeley software License Agreement +# specifies the terms and conditions for redistribution. +# +# @(#)Makefile 5.3 (Berkeley) 9/7/85 +# +DESTDIR= +CC = /bin/cc +SEPFLAG= -i +CFLAGS = -O + +all: boggle bogdict + +bogdict: comp sfile + -if [ -f /usr/local/lib/w2a ]; \ + then dict=/usr/local/lib/w2a; \ + else dict=/usr/dict/words; fi; \ + sed -f sfile $$dict | uniq | ./comp >bogdict + +install: all + install -s boggle ${DESTDIR}/usr/games/boggle + install -m 644 bogdict ${DESTDIR}/usr/games/lib/bogdict + +boggle: boggle.c + cc ${SEPFLAG} -o boggle ${CFLAGS} boggle.c + +comp: comp.c + cc ${SEPFLAG} -o comp ${CFLAGS} comp.c + +clean: + rm -f bogdict boggle comp *.o diff --git a/src/games/boggle/boggle.6 b/src/games/boggle/boggle.6 new file mode 100644 index 0000000..baa1cb2 --- /dev/null +++ b/src/games/boggle/boggle.6 @@ -0,0 +1,49 @@ +.\" Copyright (c) 1980 Regents of the University of California. +.\" All rights reserved. The Berkeley software License Agreement +.\" specifies the terms and conditions for redistribution. +.\" +.\" @(#)boggle.6 6.1 (Berkeley) 5/20/85 +.\" +.TH BOGGLE 6 "May 20, 1985" +.UC 4 +.SH NAME +boggle \- play the game of boggle +.SH SYNOPSIS +.B /usr/games/boggle +[ +.B + +] [ +.B ++ +] +.SH DESCRIPTION +This program is intended for people wishing to sharpen their +skills at Boggle (TM Parker Bros.). +If you invoke the program with 4 arguments of 4 letters each, +.RI ( e.g. +.RB \*(lq "boggle appl epie moth erhd" \*(rq) +the program forms the obvious Boggle grid and lists all the words from +.B /usr/dict/words +found therein. If you invoke the program without arguments, it will generate +a board for you, let you enter words for 3 minutes, and then tell you +how well you did relative to +.BR /usr/dict/words . +.PP +The object of Boggle is to find, within 3 +minutes, as many words as possible in a 4 by 4 grid of letters. Words +may be formed from any sequence of 3 or more adjacent letters in the +grid. The letters may join horizontally, vertically, or diagonally. +However, no position in the grid may be used more than once within any +one word. In competitive play amongst humans, each player is given +credit for those of his words which no other player has found. +.PP +In interactive play, enter your words separated by spaces, tabs, +or newlines. A bell will ring when there is 2:00, 1:00, 0:10, 0:02, +0:01, and 0:00 time left. You may complete any word started before the +expiration of time. You can surrender before time is up by hitting +\&'break'. While entering words, your erase character is only effective +within the current word and your line kill character is ignored. +.PP +Advanced players may wish to invoke the program with 1 or 2 +'s as +the first argument. The first + removes the restriction that positions +can only be used once in each word. The second + causes a position to +be considered adjacent to itself as well as its (up to) 8 neighbors. diff --git a/src/games/boggle/boggle.c b/src/games/boggle/boggle.c new file mode 100644 index 0000000..c56553e --- /dev/null +++ b/src/games/boggle/boggle.c @@ -0,0 +1,652 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +#if !defined(lint) && defined(DOSCCS) +char copyright[] = +"@(#) Copyright (c) 1980 Regents of the University of California.\n\ + All rights reserved.\n"; + +static char sccsid[] = "@(#)boggle.c 5.1.1 (2.11BSD) 1997/10/2"; +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +/* basic parameters */ +#define N 4 +#define SSIZE 200 +#define MAXWORDS 1000 +#define CWIDTH 10 +#define LWIDTH 80 + +/* parameters defined in terms of above */ +#define BSIZE (N*N) +#define row(x) (x/N) +#define col(x) (x%N) + +/* word being searched for */ +int wlength; +int numsame; +char wbuff [BSIZE+1]; + +/* tty and process control */ +extern int errno; +int status; +int pipefd[2]; +int super = 0; +int delct = 1; +int zero = 0; +int master = 1; +int column; +int *timept; +int timeint[] = {60,60,50,7,1,1,1,0}; +long timein; +struct sgttyb origttyb, tempttyb; +int ctlecho = 0; +int lctlech = LCTLECH; +jmp_buf env; + +/* monitoring variables */ +int games; +int logfile = -1; +long logloc; +char logbuff[100] = {"inst\t"}; + +/* dictionary interface */ +char defname[] = "/usr/games/lib/bogdict"; +char *dictname = &defname[0]; +FILE *dict; + +/* structures for doing matching */ +struct frame { + struct frame *parent; + int place; +}; +struct frame stack [SSIZE]; +struct frame *level [BSIZE+1]; + +/* the board and subsidiary structures */ +char present [BSIZE+1]; +char board [BSIZE]; +char olink [BSIZE]; +char adj [BSIZE+1][BSIZE]; +char occurs [26]; + +/* the boggle cubes */ +char *cube [BSIZE] = { + "forixb", "moqabj", "gurilw", "setupl", + "cmpdae", "acitao", "slcrae", "romash", + "nodesw", "hefiye", "onudtk", "tevign", + "anedvz", "pinesh", "abilyt", "gkyleu" +}; + + +/* storage for words found */ +int ubotch, ustart, wcount; +char *word [MAXWORDS]; +char *freesp; +char space[10000]; + +endline () +{ + if (column != 0) { + putchar('\n'); + column = 0; + } +} + +timeout () +{ + if (*timept > 0) { + signal (SIGALRM, timeout); + alarm(*timept++); + } + putchar('\007'); +} + +interrupt () +{ + signal(SIGINT, interrupt); + if (delct++ >= 1) + longjmp(env, 1); + timept = &zero; +} + +goodbye (stat) +int stat; +{ + if (master != 0) { + wait(&status); + if ( ctlecho & LCTLECH ) { + ioctl( fileno(stdin), TIOCLBIS, &lctlech ); + } + stty(fileno(stdin), &origttyb); + } + exit(stat); +} + +clearscreen () +{ + stty (fileno(stdin), &tempttyb); + printf("\n\f\r"); +} + +compare (a, b) +char **a, **b; +{ + return(wordcomp(*a, *b)); +} + +wordcomp (p, q) +register char *p, *q; +{ + if (*p=='0' && *q!='0') + return(-1); + if (*p!='0' && *q=='0') + return(1); + while (*++p == *++q && isalpha(*p)) ; + if (!isalpha(*p)) + return(-isalpha(*q)); + if (!isalpha(*q)) + return(1); + return(*p-*q); +} + +printinst () +{ + stty (fileno(stdin), &tempttyb); + printf("instructions?"); + if (getchar() == 'y') { + clearscreen(); + printf(" The object of Boggle (TM Parker Bros.) is to find, within 3\n"); + printf("minutes, as many words as possible in a 4 by 4 grid of letters. Words\n"); + printf("may be formed from any sequence of 3 or more adjacent letters in the\n"); + printf("grid. The letters may join horizontally, vertically, or diagonally.\n"); + printf("However, no position in the grid may be used more than once within any\n"); + printf("one word. In competitive play amongst humans, each player is given\n"); + printf("credit for those of his words which no other player has found.\n"); + printf(" This program is intended for people wishing to sharpen their\n"); + printf("skills at Boggle. If you invoke the program with 4 arguments of 4\n"); + printf("letters each, (e.g. \"boggle appl epie moth erhd\") the program forms the\n"); + printf("obvious Boggle grid and lists all the words from /usr/dict/words found\n"); + printf("therein. If you invoke the program without arguments, it will generate\n"); + printf("a board for you, let you enter words for 3 minutes, and then tell you\n"); + printf("how well you did relative to /usr/dict/words.\n"); + printf(" In interactive play, enter your words separated by spaces, tabs,\n"); + printf("or newlines. A bell will ring when there is 2:00, 1:00, 0:10, 0:02,\n"); + printf("0:01, and 0:00 time left. You may complete any word started before the\n"); + printf("expiration of time. You can surrender before time is up by hitting\n"); + printf("'break'. While entering words, your erase character is only effective\n"); + printf("within the current word and your line kill character is ignored.\n"); + printf(" Advanced players may wish to invoke the program with 1 or 2 +'s as\n"); + printf("the first argument. The first + removes the restriction that positions\n"); + printf("can only be used once in each word. The second + causes a position to\n"); + printf("be considered adjacent to itself as well as its (up to) 8 neighbors.\n"); + printf("Hit any key to begin.\n"); + stty (fileno(stdin), &tempttyb); + getchar(); + } + stty (fileno(stdin), &tempttyb); +} + +setup () +{ + register int i, j; + int rd, cd, k; + for (i=0; i=2 ? 1 : 0; + adj[BSIZE][i] = 1; + for (j=0; j0 && (isspace(c=getchar()) || c==EOF)); + if (*timept == 0) + return(0); + word[wcount++] = freesp; + *freesp++ = '0'; + r = &wbuff[1]; + q = p = freesp; + *p++ = c; + while (!isspace(c = getchar())) { + if (c == EOF) + continue; + if (c == origttyb.sg_erase) { + if (p > q) + p--; + continue; + } + *p++ = c; + } + freesp = p; + for (p=q; p=10 ? '*' : '0'+ways; +} + +aputword (ways) +int ways; +{ + /* store (wbuff, ways) in next slot in space */ + register int i; + *freesp++ = ways>=10 ? '*' : '0'+ways; + for (i=1; i<= wlength; i++) + *freesp++ = wbuff[i]; + word[++wcount] = freesp; +} + +tputword (ways) +int ways; +{ + /* print (wbuff, ways) on terminal */ + wbuff[wlength+1] = '0'; + wbuff[0] = ways>=10 ? '*' : '0'+ways; + outword(&wbuff[0]); +} + +outword (p) +register char *p; +{ + register int newcol; + register char *q; + for (q=p+1; isalpha(*q); ) { + putchar(*q); + if (*q++ == 'q') { + putchar('u'); + column++; + } + } + column += q-p-1; + if (column > LWIDTH-CWIDTH) { + putchar('\n'); + column = 0; + return; + } + newcol = ((column+CWIDTH)/CWIDTH)*CWIDTH; + while (((column+8)/8)*8 <= newcol) { + putchar('\t'); + column = ((column+8)/8)*8; + } + while (column < newcol) { + putchar(' '); + column++; + } +} + +printdiff () +{ + register int c, d, u; + char both, donly, uonly; + word[wcount] = freesp; + *freesp = '0'; + both = donly = uonly = column = d = 0; + u = ustart; + while (d < ubotch) { + c = u 0) + return(last-leaf); + count = 0; + present[BSIZE] = 1; + while (leaf < last) { + for (p = &present[0]; p < &present[BSIZE]; *p++ = 0); + for (node = leaf; present[node->place]++ == 0; node = node->parent); + if (node == &stack[0]) + count++; + leaf++; + } + return(count); +} + +evalboard (getword, putword) +int (*getword)(), (*putword)(); +{ + register struct frame *top; + register int l, q; + int fo, found; + struct frame *parent, *lastparent; + char *padj; + + numsame = found = 0; + makelists (); + + while (1) { + l = numsame; + if (!(*getword) ()) + break; + top = level[l+1]; + + while (1) { + level[l+1] = lastparent = top; + /* wbuff[1]...wbuff[l] have been matched */ + /* level[0],...,level[l] of tree built */ + if (l == wlength) { + if (wlength >= 3 && (q = numways(level[l], top)) != 0) { + (*putword) (q); + found++; + } + l = BSIZE+1; + break; + } + if ((fo = occurs[wbuff[++l]-'a']) == BSIZE) + break; + /* wbuff[1]...wbuff[l-1] have been matched */ + /* level[0],...,level[l-1] of tree built */ + for (parent=level[l-1]; parentplace][0]; + for (q=fo; q!=BSIZE; q=olink[q]) + if (padj[q]) { + top->parent = parent; + top->place = q; + if (++top >= &stack[SSIZE]) { + printf("stack overflow\n"); + goodbye(1); + } + } + } + /* were any nodes added? */ + if (top == lastparent) + break; + } + + /* advance until first l characters of next word are different */ + while (numsame >= l && (*getword)()) ; + } + return(found); +} + +main (argc, argv) +int argc; +char **argv; +{ + char *q; + register char *p; + register int i, c; + + gtty (fileno(stdin), &origttyb); + setbuf(stdin, NULL); + tempttyb = origttyb; + if (setjmp(env) != 0) + goodbye(0); + signal (SIGINT, interrupt); + timein = time(0L); + if (argv[0][0] != 'a' && (logfile = open("/usr/games/lib/boglog", 1)) >= 0) { + p = &logbuff[5]; + q = getlogin(); + while (*p++ = *q++); + p[-1] = '\t'; + q = ctime(&timein); + while (*p++ = *q++); + logloc = lseek(logfile, 0L, 2); + write(logfile, &logbuff[0], p-&logbuff[1]); + } + if ((dict = fopen(dictname, "r")) == NULL) { + printf("can't open %s\n", dictname); + goodbye (2); + } + while ( argc > 1 && ( argv[1][0] == '+' || argv[1][0] == '-' ) ) { + if (argv[1][0]=='+') { + while(*(argv[1]++) == '+') + super++; + argc--; + argv++; + } + if ( argv[1][0] == '-' ) { + timeint[0] = 60 * ( atol( &argv[1][1] ) - 2 ); + if ( timeint[0] <= 0 ) { + timeint[0] = 60; + } + argc--; + argv++; + } + } + setup (); + switch (argc) { + default: punt: + printf("usage: boggle [+[+]] [row1 row2 row3 row4]\n"); + goodbye (3); + case 5: + for (i=0; i= 0) { + strncpy(&logbuff[0], "eval", 4); + lseek(logfile, logloc, 0); + write(logfile, &logbuff[0], 4); + } + goodbye(0); + case 1: + tempttyb.sg_flags |= CBREAK; + if ( ioctl( fileno(stdin), TIOCLGET, &ctlecho ) == 0 ) { + if ( ctlecho & LCTLECH ) { + ioctl( fileno(stdin), TIOCLBIC, &lctlech ); + } + } + printinst(); + srand((int) timein); + while (setjmp(env) == 0) { + errno = 0; + if (pipe(&pipefd[0]) != 0) { + printf("can't create pipe\n"); + goodbye(4); + } + genboard(); + delct = wcount = 0; + word[0] = freesp = &space[0]; + if ((master = fork()) == 0) { + close(pipefd[0]); + clearscreen(); + printboard(); + signal(SIGALRM, timeout); + timept = &timeint[0]; + alarm(*timept++); + evalboard(getuword, aputuword); + clearscreen(); + qsort(&word[0], wcount, sizeof (int), compare); + for (i=0; i= 0) { + sprintf(&logbuff[0], "%4d", games); + lseek(logfile, logloc, 0); + write(logfile, &logbuff[0], 4); + } + stty (fileno(stdin), &tempttyb); + printf("\nanother game?"); + if (getchar() != 'y') { + putchar('\n'); + break; + } + stty (fileno(stdin), &tempttyb); + } + goodbye(0); + } +} diff --git a/src/games/boggle/comp.c b/src/games/boggle/comp.c new file mode 100644 index 0000000..874f0a2 --- /dev/null +++ b/src/games/boggle/comp.c @@ -0,0 +1,37 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +#ifndef lint +char copyright[] = +"@(#) Copyright (c) 1980 Regents of the University of California.\n\ + All rights reserved.\n"; +#endif not lint + +#ifndef lint +static char sccsid[] = "@(#)comp.c 5.1 (Berkeley) 5/30/85"; +#endif not lint + +#include +#define MAX ' ' + +char new[MAX], old[MAX]; + +main () +{ + register int i, j; + old[0] = '\0'; + while (fgets(&new[0], MAX, stdin) != NULL) { + for (i=0; i= MAX) { + fprintf(stderr, "long word\n"); + exit(1); + } + putc(i, stdout); + for (j=0; (old[j]=new[j]) != '\n'; j++); + old[j] = '\0'; + fputs(&old[i], stdout); + } +} diff --git a/src/games/boggle/inst b/src/games/boggle/inst new file mode 100644 index 0000000..c70fb7d --- /dev/null +++ b/src/games/boggle/inst @@ -0,0 +1,42 @@ +.\" Copyright (c) 1980 Regents of the University of California. +.\" All rights reserved. The Berkeley software License Agreement +.\" specifies the terms and conditions for redistribution. +.\" +.\" @(#)inst 5.1 (Berkeley) 5/30/85 +.\" +.ll 71 +.ls 1 +.ti +5 +The object of Boggle (TM Parker Bros.) is to find, within 3 minutes, as +many words as possible in a 4 by 4 grid of letters. +Words may be formed from any sequence of 3 or more adjacent letters +in the grid. The letters may join horizontally, vertically, +or diagonally. However, no position in the grid may be used +more than once within any one word. +In competitive play amongst humans, each player is given +credit for those of his words which no other player has found. +.ti +5 +This program is intended for people +wishing to sharpen their skills at Boggle. +If you invoke the program with 4 arguments of 4 letters each, +(e.g. "boggle appl epie moth erhd") +the program forms the obvious Boggle grid and lists all the +words from /usr/dict/words found therein. +If you invoke the program without arguments, it will generate +a board for you, let you enter words for 3 minutes, and then +tell you how well you did relative to /usr/dict/words. +.ti +5 +In interactive play, enter your words separated by spaces, tabs, or newlines. +A bell will ring when there is 2:00, 1:00, 0:10, 0:02, 0:01, and 0:00 time +left. +You may complete any word started before the expiration of time. +You can surrender before time is up by hitting 'break'. +While entering words, your erase character is only effective within the current +word and your line kill character is ignored. +.ti +5 +Advanced players may wish to invoke the program with 1 or 2 +'s as the +first argument. The first + removes the restriction that postions can only +be used once in each word. +The second + causes a position to be considered adjacent to itself +as well as its (up to) 8 neighbors. +Hit any key to begin. diff --git a/src/games/boggle/sfile b/src/games/boggle/sfile new file mode 100644 index 0000000..2fb416d --- /dev/null +++ b/src/games/boggle/sfile @@ -0,0 +1,10 @@ +/^-/d +/-$/d +s/-//g +/[^a-z]/d +/q[^u]/d +/q$/d +/^.$/d +/^..$/d +s/qu/q/g +/.............../d diff --git a/src/games/btlgammon/Makefile b/src/games/btlgammon/Makefile new file mode 100644 index 0000000..d0724c0 --- /dev/null +++ b/src/games/btlgammon/Makefile @@ -0,0 +1,36 @@ +# @(#)Makefile 4.2 (Berkeley) 9/7/85 +# +DESTDIR= +CFLAGS= -O +SEPFLAG= -i + +btlgammon: btlgammon.c + cc ${SEPFLAG} ${CFLAGS} -o btlgammon btlgammon.c + +install: btlgammon backrules + install -s btlgammon ${DESTDIR}/usr/games/btlgammon + install -c backrules ${DESTDIR}/usr/games/lib/backrules + +clean: + rm -f a.out core *.s *.o btlgammon + +depend: + cat x.c + for i in btlgammon; do \ + (echo $$i: $$i.c >>makedep; \ + /bin/grep '^#[ ]*include' x.c $$i.c | sed \ + -e 's,<\(.*\)>,"/usr/include/\1",' \ + -e 's/:[^"]*"\([^"]*\)".*/: \1/' \ + -e 's/\.c//' >>makedep); done + echo '/^# DO NOT DELETE THIS LINE/+2,$$d' >eddep + echo '$$r makedep' >>eddep + echo 'w' >>eddep + cp Makefile Makefile.bak + ed - Makefile < eddep + rm eddep makedep x.c + echo '# DEPENDENCIES MUST END AT END OF FILE' >> Makefile + echo '# IF YOU PUT STUFF HERE IT WILL GO AWAY' >> Makefile + echo '# see make depend above' >> Makefile + +# DO NOT DELETE THIS LINE -- make depend uses it + diff --git a/src/games/btlgammon/backrules b/src/games/btlgammon/backrules new file mode 100644 index 0000000..4b2ca70 --- /dev/null +++ b/src/games/btlgammon/backrules @@ -0,0 +1,19 @@ +To play backgammon, type the numbers of the points from which pieces are +to be moved. Thus, if the roll is '3,5', typing '2 6' will move a piece +from point 2 three spaces to point 5, and a piece from point 6 forward to +point 11. If the moves must be made in the opposite order, the first +character typed must be a minus ('-'). Thus, typing '-2 6' moves the +piece on point 2 by 5, and the piece on point 6 by 3. + +If you want to move a single piece several times, the sequence of points +from which it is to be moved must be typed. Thus '14 17' will move a +piece from point 14 to point 17 and thence to to point 22. + +If a double is rolled, you should type four numbers. Red pieces that +have been removed from the board by being hit by white are on point 0 and +must be brought in before any other move can be made. White pieces that +are hit are removed to point 25. You will not be allowed to make an +illegal move, or to make too many moves. However, if you make too few +moves, the program does not care. In particular you may skip your turn by +typing a 'new-line' all by itself. + diff --git a/src/games/btlgammon/btlgammon.c b/src/games/btlgammon/btlgammon.c new file mode 100644 index 0000000..e1acba8 --- /dev/null +++ b/src/games/btlgammon/btlgammon.c @@ -0,0 +1,717 @@ + +static char sccsid[] = " backgammon.c 4.1 82/10/24 "; + +/* +** The game of Backgammon +*/ + +#include + +#define WHITE 0 +#define BROWN 1 +#define NIL (-1) +#define MAXGMOV 10 +#define MAXIMOVES 1000 +#define RULES "/usr/games/lib/backrules" + +char level; /*'b'=beginner, 'i'=intermediate, 'e'=expert*/ + +int die1; +int die2; +int i; +int j; +int l; +int m; +int pflg = 1; +int nobroll = 0; +int count; +int imoves; +int goodmoves[MAXGMOV]; +int probmoves[MAXGMOV]; + +int brown[] = { /* brown position table */ + 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, + 0, 0, 0, 0, 3, 0, 5, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0 +}; + +int white[] = { /* white position table */ + 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, + 0, 0, 0, 0, 3, 0, 5, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0 +}; + +int probability[] = { + 0, 11, 12, 13, 14, 15, 16, + 06, 05, 04, 03, 02, 01 +}; + +struct { + int pos[4]; + int mov[4]; +} moves[MAXIMOVES]; + +main() +{ + int go[5], tvec[2]; + int k, n, pid, ret, rpid, t; + char s[100]; + + srand(time(0)); + go[5] = NIL; + fprintf(stdout, "Instructions? "); + gets(s); + if(*s == 'y') + instructions(); + putchar('\n'); + fprintf(stdout, "Opponent's level: b - beginner,\n"); + fprintf(stdout, "i - intermediate, e - expert? "); + level='e'; + gets(s); + if(*s == 'b') + level = 'b'; + else if(*s == 'i') + level = 'i'; + putchar('\n'); + fprintf(stdout, "You will play brown.\n\n"); + fprintf(stdout, "Would you like to roll your own dice? "); + gets(s); + putchar('\n'); + if(*s == 'y') + nobroll = 1; + fprintf(stdout, "Would you like to go first? "); + gets(s); + putchar('\n'); + if(*s == 'y') + goto nowhmove; +whitesmv: + roll(WHITE); + fprintf(stdout, "white rolls %d, %d\n", die1, die2); + fprintf(stdout, "white's move is:"); + if(nextmove(white, brown) == NIL) + goto nowhmove; + if(piececount(white, 0, 24) == 0){ + fprintf(stdout, "White wins"); + if(piececount(brown, 0, 6) != 0) + fprintf(stdout, " with a Backgammon!\n"); + else if (piececount(brown, 0, 24) == 24) + fprintf(stdout, " with a Gammon.\n"); + else + fprintf(stdout, ".\n"); + exit(0); + } +nowhmove: + if(pflg) + prtbrd(); + roll(BROWN); +retry: + fprintf(stdout, "\nYour roll is %d %d\n", die1, die2); + fprintf(stdout, "Move? "); + gets(s); + switch(*s) { + case '\0': /* empty line */ + fprintf(stdout, "Brown's move skipped.\n"); + goto whitesmv; + + case 'b': /* how many beared off? */ + fprintf(stdout, "Brown: %d\n", piececount(brown, 0, 24) - 15); + fprintf(stdout, "White: %d\n", piececount(white, 0, 24) - 15); + goto retry; + + case 'p': /* print board */ + prtbrd(); + goto retry; + + case 's': /* stop auto printing of board */ + pflg = 0; + goto retry; + + case 'r': /* resume auto printing */ + pflg = 1; + goto retry; + + case 'm': /* print possible moves */ + pmoves(); + goto retry; + + case 'q': /* i give up */ + exit(0); + + case '!': /* escape to Shell */ + if(s[1] != '\0') + system(s+1); + else if((pid = fork()) == 0) { + execl("/bin/sh", "sh", "-", 0); + fprintf(stderr, "back: cannot exec /bin/sh!\n"); + exit(2); + } + while((rpid = wait(&ret)) != pid && rpid != -1) + ; + goto retry; + + case '?': /* well, what can i do? */ + fprintf(stdout, " skip this move\n"); + fprintf(stdout, "b number beared off\n"); + fprintf(stdout, "p print board\n"); + fprintf(stdout, "q quit\n"); + fprintf(stdout, "r resume auto print of board\n"); + fprintf(stdout, "s stop auto print of board\n"); + fprintf(stdout, "! escape to Shell\n"); + goto retry; + } + n = sscanf(s,"%d%d%d%d%d",&go[0],&go[1],&go[2],&go[3],&go[4]); + if((die1 != die2 && n > 2) || n > 4){ + fprintf(stdout, "Too many moves.\n"); + goto retry; + } + go[n] = NIL; + if(*s=='-'){ + go[0]= -go[0]; + t=die1; + die1=die2; + die2=t; + } + for(k = 0; k < n; k++){ + if(0 <= go[k] && go[k] <= 24) + continue; + else{ + fprintf(stdout, "Move %d illegal.\n", go[k]); + goto retry; + } + } + if(play(brown, white, go)) + goto retry; + if(piececount(brown, 0, 24) == 0){ + fprintf(stdout, "Brown wins"); + if(piececount(white, 0, 6) != 0) + fprintf(stdout, " with a Backgammon.\n"); + else if(piececount(white, 0, 24) == 24) + fprintf(stdout, " with a gammon.\n"); + else + fprintf(stdout, ".\n"); + exit(0); + } + goto whitesmv; +} + +play(player,playee,pos) +int *player,*playee,pos[]; +{ + int k, n, die, ipos; + + for(k=0; k < player[0]; k++){ /*blots on player[0] must be moved first*/ + if(pos[k] == NIL) + break; + if(pos[k] != 0){ + fprintf(stdout, "Stone on bar must be moved first.\n"); + return(NIL); + } + } + for(k = 0; (ipos=pos[k]) != NIL; k++){ + die = k?die2:die1; + n = 25-ipos-die; + if(player[ipos] == 0) + goto badmove; + if(n > 0 && playee[n] >= 2) + goto badmove; + if(n <= 0){ + if(piececount(player,0,18) != 0) + goto badmove; + if((ipos+die) != 25 && piececount(player,19,24-die)!=0) + goto badmove; + } + player[ipos]--; + player[ipos+die]++; + } + for(k = 0; pos[k] != NIL; k++){ + die = k?die2:die1; + n = 25-pos[k]-die; + if(n>0 && playee[n]==1){ + playee[n]=0; + playee[0]++; + } + } + return(0); + +badmove: + fprintf(stdout, "Move %d illegal.\n", ipos); + while(k--){ + die=k?die2:die1; + player[pos[k]]++; + player[pos[k]+die]--; + } + return(NIL); +} +nextmove(player,playee) +int *player,*playee; +{ + int k; + + imoves=0; + movegen(player,playee); + if(die1!=die2){ + k=die1; + die1=die2; + die2=k; + movegen(player,playee); + } + if(imoves==0){ + fprintf(stdout, "no move possible.\n"); + return(NIL); + } + k=strategy(player,playee); /*select kth possible move*/ + prtmov(k); + update(player,playee,k); + return(0); +} +prtmov(k) +int k; +{ + int n; + + if(k == NIL) + fprintf(stdout, "No move possible\n"); + else for(n = 0; n < 4; n++){ + if(moves[k].pos[n] == NIL) + break; + fprintf(stdout, " %d, %d",25-moves[k].pos[n],moves[k].mov[n]); + } + fprintf(stdout, "\n"); +} +update(player,playee,k) +int *player,*playee,k; +{ + int n,t; + + for(n = 0; n < 4; n++){ + if(moves[k].pos[n] == NIL) + break; + player[moves[k].pos[n]]--; + player[moves[k].pos[n]+moves[k].mov[n]]++; + t=25-moves[k].pos[n]-moves[k].mov[n]; + if(t>0 && playee[t]==1){ + playee[0]++; + playee[t]--; + } + } +} +piececount(player,startrow,endrow) +int *player,startrow,endrow; +{ + int sum; + + sum=0; + while(startrow <= endrow) + sum += player[startrow++]; + return(sum); +} +pmoves() +{ + int i1, i2; + + fprintf(stdout, "Possible moves are:\n"); + for(i1 = 0; i1 < imoves; i1++){ + fprintf(stdout, "\n%d",i1); + for (i2 = 0; i2<4; i2++){ + if(moves[i1].pos[i2] == NIL) + break; + fprintf(stdout, "%d, %d",moves[i1].pos[i2],moves[i1].mov[i2]); + } + } + fprintf(stdout, "\n"); +} + +roll(who) +{ + register n; + char s[10]; + + if(who == BROWN && nobroll) { + fprintf(stdout, "Roll? "); + gets(s); + n = sscanf(s, "%d%d", &die1, &die2); + if(n != 2 || die1 < 1 || die1 > 6 || die2 < 1 || die2 > 6) + fprintf(stdout, "Illegal - I'll do it!\n"); + else + return; + } + die1 = ((rand()>>8) % 6) + 1; + die2 = ((rand()>>8) % 6) + 1; +} + +movegen(mover,movee) +int *mover,*movee; +{ + int k; + + for(i = 0; i <= 24; i++){ + count = 0; + if(mover[i] == 0) + continue; + if((k=25-i-die1) > 0 && movee[k] >= 2) + if(mover[0] > 0) + break; + else + continue; + if(k <= 0){ + if(piececount(mover, 0, 18) != 0) + break; + if((i+die1) != 25 && piececount(mover,19,i-1) != 0) + break; + } + mover[i]--; + mover[i+die1]++; + count = 1; + for(j = 0; j <= 24; j++){ + if(mover[j]==0) + continue; + if((k=25-j-die2) > 0 && movee[k] >= 2) + if(mover[0] > 0) + break; + else + continue; + if(k <= 0){ + if(piececount(mover,0,18) != 0) + break; + if((j+die2) != 25 && piececount(mover,19,j-1) != 0) + break; + } + mover[j]--; + mover[j+die2]++; + count = 2; + if(die1 != die2){ + moverecord(mover); + if(mover[0] > 0) + break; + else + continue; + } + for(l = 0; l <= 24; l++){ + if(mover[l] == 0) + continue; + if((k=25-l-die1) > 0 && movee[k] >= 2) + if(mover[0] > 0) + break; + else + continue; + if(k <= 0){ + if(piececount(mover, 0, 18) != 0) + break; + if((l+die2) != 25 && piececount(mover,19,l-1) != 0) + break; + } + mover[l]--; + mover[l+die1]++; + count=3; + for(m=0;m<=24;m++){ + if(mover[m]==0) + continue; + if((k=25-m-die1) >= 0 && movee[k] >= 2) + if(mover[0] > 0) + break; + else + continue; + if(k <= 0){ + if(piececount(mover,0,18) != 0) + break; + if((m+die2) != 25 && piececount(mover,19,m-1) != 0) + break; + } + count=4; + moverecord(mover); + if(mover[0] > 0) + break; + } + if(count == 3) + moverecord(mover); + else{ + mover[l]++; + mover[l+die1]--; + } + if(mover[0] > 0) + break; + } + if(count == 2) + moverecord(mover); + else{ + mover[j]++; + mover[j+die1]--; + } + if(mover[0] > 0) + break; + } + if(count == 1) + moverecord(mover); + else{ + mover[i]++; + mover[i+die1]--; + } + if(mover[0] > 0) + break; + } +} +moverecord(mover) +int *mover; +{ + int t; + + if(imoves < MAXIMOVES) { + for(t = 0; t <= 3; t++) + moves[imoves].pos[t] = NIL; + switch(count) { + case 4: + moves[imoves].pos[3]=m; + moves[imoves].mov[3]=die1; + + case 3: + moves[imoves].pos[2]=l; + moves[imoves].mov[2]=die1; + + case 2: + moves[imoves].pos[1]=j; + moves[imoves].mov[1]=die2; + + case 1: + moves[imoves].pos[0]=i; + moves[imoves].mov[0]=die1; + imoves++; + } + } + switch(count) { + case 4: + break; + + case 3: + mover[l]++; + mover[l+die1]--; + break; + + case 2: + mover[j]++; + mover[j+die2]--; + break; + + case 1: + mover[i]++; + mover[i+die1]--; + } +} + +strategy(player,playee) +int *player,*playee; +{ + int k, n, nn, bestval, moveval, prob; + + n = 0; + if(imoves == 0) + return(NIL); + goodmoves[0] = NIL; + bestval = -32000; + for(k = 0; k < imoves; k++){ + if((moveval=eval(player,playee,k,&prob)) < bestval) + continue; + if(moveval > bestval){ + bestval = moveval; + n = 0; + } + if(n1){ + nn=n; + n=0; + prob=32000; + for(k = 0; k < nn; k++){ + if((moveval=probmoves[k]) > prob) + continue; + if(moveval>4)%n]); +} + +eval(player,playee,k,prob) +int *player,*playee,k,*prob; +{ + int newtry[31], newother[31], *r, *q, *p, n, sum, first; + int ii, lastwhite, lastbrown; + + *prob = sum = 0; + r = player+25; + p = newtry; + q = newother; + while(player6) { + for(sum = 1000; lastwhite > 6; lastwhite--) + sum = sum-lastwhite*newtry[25-lastwhite]; + } + for(first = 0; first < 25; first++) + if(newother[first] != 0) /*find other's first piece*/ + break; + q = newtry+25; + for(p = newtry+1; p < q;) /* blocked points are good */ + if(*p++ > 1) + sum++; + if(first > 5) { /* only stress removing pieces if */ + /* homeboard cannot be hit */ + q = newtry+31; + p=newtry+25; + for(n = 6; p < q; n--) + sum += *p++ * n; /*remove pieces, but just barely*/ + } + if(level != 'b'){ + r = newtry+25-first; /*singles past this point can't be hit*/ + for(p = newtry+7; p < r; ) + if(*p++ == 1) /*singles are bad after 1st 6 points if they can be hit*/ + sum--; + q = newtry+3; + for(p = newtry; p < q; ) /*bad to be on 1st three points*/ + sum -= *p++; + } + + for(n = 1; n <= 4; n++) + *prob += n*getprob(newtry,newother,6*n-5,6*n); + return(sum); +} +instructions() +{ + register fd, r; + char buf[BUFSIZ]; + + if((fd = open(RULES, 0)) < 0) { + fprintf(stderr, "back: cannot open %s\n", RULES); + return; + } + while(r = read(fd, buf, BUFSIZ)) + write(1, buf, r); +} + +getprob(player,playee,start,finish) +int *player,*playee,start,finish; +{ /*returns the probability (times 102) that any + pieces belonging to 'player' and lying between + his points 'start' and 'finish' will be hit + by a piece belonging to playee + */ + int k, n, sum; + + sum = 0; + for(; start <= finish; start++){ + if(player[start] == 1){ + for(k = 1; k <= 12; k++){ + if((n=25-start-k) < 0) + break; + if(playee[n] != 0) + sum += probability[k]; + } + } + } + return(sum); +} +prtbrd() +{ + int k; + static char undersc[]="______________________________________________________"; + + fprintf(stdout, "White's Home\n%s\r",undersc); + for(k = 1; k <= 6; k++) + fprintf(stdout, "%4d",k); + fprintf(stdout, " "); + for(k = 7; k <= 12; k++) + fprintf(stdout, "%4d",k); + putchar('\n'); + numline(brown, white, 1, 6); + fprintf(stdout, " "); + numline(brown, white, 7, 12); + putchar('\n'); + colorline(brown, 'B', white, 'W', 1, 6); + fprintf(stdout, " "); + colorline(brown, 'B', white, 'W', 7, 12); + putchar('\n'); + if(white[0] != 0) + fprintf(stdout, "%28dW\n",white[0]); + else + putchar('\n'); + if(brown[0] != 0) + fprintf(stdout, "%28dB\n", brown[0]); + else + putchar('\n'); + colorline(white, 'W', brown, 'B', 1, 6); + fprintf(stdout, " "); + colorline(white, 'W', brown, 'B', 7, 12); + fprintf(stdout, "\n%s\r",undersc); + numline(white, brown, 1, 6); + fprintf(stdout, " "); + numline(white, brown, 7, 12); + putchar('\n'); + for(k = 24; k >= 19; k--) + fprintf(stdout, "%4d",k); + fprintf(stdout, " "); + for(k = 18; k >= 13; k--) + fprintf(stdout, "%4d",k); + fprintf(stdout, "\nBrown's Home\n\n\n\n\n"); +} +numline(upcol,downcol,start,fin) +int *upcol,*downcol,start,fin; +{ + int k, n; + + for(k = start; k <= fin; k++){ + if((n = upcol[k]) != 0 || (n = downcol[25-k]) != 0) + fprintf(stdout, "%4d", n); + else + fprintf(stdout, " "); + } +} +colorline(upcol,c1,downcol,c2,start,fin) +int *upcol,*downcol,start,fin; +char c1,c2; +{ + int k; + char c; + + for(k = start; k <= fin; k++){ + c = ' '; + if(upcol[k] != 0) + c = c1; + if(downcol[25-k] != 0) + c = c2; + fprintf(stdout, " %c",c); + } +} diff --git a/src/games/canfield.6 b/src/games/canfield.6 new file mode 100644 index 0000000..247b12c --- /dev/null +++ b/src/games/canfield.6 @@ -0,0 +1,91 @@ +.\" Copyright (c) 1983 Regents of the University of California. +.\" All rights reserved. The Berkeley software License Agreement +.\" specifies the terms and conditions for redistribution. +.\" +.\" @(#)canfield.6 6.2 (Berkeley) 5/6/86 +.\" +.TH CANFIELD 6 "May 6, 1986" +.UC 5 +.SH NAME +canfield, cfscores \- the solitaire card game canfield +.SH SYNOPSIS +.B /usr/games/canfield +.br +.B /usr/games/cfscores +.SH DESCRIPTION +.PP +If you have never played solitaire before, it is recommended +that you consult a solitaire instruction book. In +Canfield, tableau cards may be built on each other downward +in alternate colors. An entire pile must be moved as a unit +in building. Top cards of the piles are available +to be played on foundations, but never into empty spaces. +.PP +Spaces must be filled from the stock. The top card of +the stock also is available to be played on foundations or +built on tableau piles. After the stock is exhausted, +tableau spaces may be filled from the talon and the player may +keep them open until he wishes to use them. +.PP +Cards are dealt from the hand to the talon by threes +and this repeats until there are no more cards in the hand +or the player quits. To have cards dealt onto the talon the +player types 'ht' for his move. Foundation base cards are +also automatically moved to the foundation when they become +available. +.PP +The command 'c' causes +.I canfield +to maintain card counting statistics +on the bottom of the screen. +When properly used this can greatly increase one's chances of +winning. +.PP +The rules for betting are somewhat less strict than +those used in the official version of the game. +The initial deal costs $13. +You may quit at this point or inspect the game. +Inspection costs $13 and allows you to make as many +moves as possible without moving any cards from your hand +to the talon. +(The initial deal places three cards on the talon; +if all these cards are used, +three more are made available.) +Finally, if the game seems interesting, +you must pay the final installment of $26. +At this point you are +credited at the rate of $5 for each card on the foundation; +as the game progresses you are credited with $5 for each +card that is moved to the foundation. +Each run through the hand after the first costs $5. +The card counting feature +costs $1 for each unknown card that is identified. +If the information is toggled on, +you are only charged for cards +that became visible since it was last turned on. +Thus the maximum cost of information is $34. +Playing time is charged at a rate of $1 per minute. +.PP +With no arguments, the program +.I cfscores +prints out the current status of your canfield account. +If a user name is specified, +it prints out the status of their canfield account. +If the +.B \-a +flag is specified, +it prints out the canfield accounts for all users that have +played the game since the database was set up. +.SH FILES +/usr/games/canfield the game itself +.br +/usr/games/cfscores the database printer +.br +/usr/games/lib/cfscores the database of scores +.SH BUGS +It is impossible to cheat. +.SH AUTHORS +Originally written: Steve Levine +.br +Further random hacking by: Steve Feldman, Kirk McKusick, +Mikey Olson, and Eric Allman. diff --git a/src/games/canfield.c b/src/games/canfield.c new file mode 100644 index 0000000..e5c77cc --- /dev/null +++ b/src/games/canfield.c @@ -0,0 +1,1637 @@ +/* + * The canfield program + * + * Authors: + * Originally written: Steve Levine + * Converted to use curses and debugged: Steve Feldman + * Card counting: Kirk McKusick and Mikey Olson + * User interface cleanups: Eric Allman and Kirk McKusick + * Betting by Kirk McKusick + * + * Copyright (c) 1982 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#ifdef CROSS +# include +# include +#else +# include +# include +#endif +#include +#include +#include +#include +#include +#include +#include + +#define SG_ERASE ('H' & 037) +#define SG_KILL ('U' & 037) +#define SG_DEL 0177 + +#define decksize 52 +#define originrow 0 +#define origincol 0 +#define basecol 1 +#define boxcol 42 +#define tboxrow 2 +#define bboxrow 17 +#define movecol 43 +#define moverow 16 +#define msgcol 43 +#define msgrow 15 +#define titlecol 30 +#define titlerow 0 +#define sidecol 1 +#define ottlrow 6 +#define foundcol 11 +#define foundrow 3 +#define stockcol 2 +#define stockrow 8 +#define fttlcol 10 +#define fttlrow 1 +#define taloncol 2 +#define talonrow 13 +#define tabrow 8 +#define ctoprow 21 +#define cbotrow 23 +#define cinitcol 14 +#define cheightcol 1 +#define cwidthcol 4 +#define handstatrow 21 +#define handstatcol 7 +#define talonstatrow 22 +#define talonstatcol 7 +#define stockstatrow 23 +#define stockstatcol 7 +#define Ace 1 +#define Jack 11 +#define Queen 12 +#define King 13 +#define atabcol 11 +#define btabcol 18 +#define ctabcol 25 +#define dtabcol 32 + +#define spades 's' +#define clubs 'c' +#define hearts 'h' +#define diamonds 'd' +#define black 'b' +#define red 'r' + +#define stk 1 +#define tal 2 +#define tab 3 +#define INCRHAND(row, col) {\ + row -= cheightcol;\ + if (row < ctoprow) {\ + row = cbotrow;\ + col += cwidthcol;\ + }\ +} +#define DECRHAND(row, col) {\ + row += cheightcol;\ + if (row > cbotrow) {\ + row = ctoprow;\ + col -= cwidthcol;\ + }\ +} + + +struct cardtype { + char suit; + char color; + bool visible; + bool paid; + int rank; + struct cardtype *next; +}; + +#define NIL ((struct cardtype *) -1) + +struct cardtype *deck[decksize]; +struct cardtype cards[decksize]; +struct cardtype *bottom[4], *found[4], *tableau[4]; +struct cardtype *talon, *hand, *stock, *basecard; +int length[4]; +int cardsoff, base, cinhand, taloncnt, stockcnt, timesthru; +char suitmap[4] = {spades, clubs, hearts, diamonds}; +char colormap[4] = {black, black, red, red}; +char pilemap[4] = {atabcol, btabcol, ctabcol, dtabcol}; +char srcpile, destpile; +int mtforigin, tempbase; +int coldcol, cnewcol, coldrow, cnewrow; +bool errmsg, done; +bool mtfdone, Cflag = FALSE; +#define INSTRUCTIONBOX 1 +#define BETTINGBOX 2 +#define NOBOX 3 +int status = INSTRUCTIONBOX; + +/* + * Basic betting costs + */ +#define costofhand 13 +#define costofinspection 13 +#define costofgame 26 +#define costofrunthroughhand 5 +#define costofinformation 1 +#define secondsperdollar 60 +#define maxtimecharge 3 +#define valuepercardup 5 + +/* + * Variables associated with betting + */ +struct betinfo { + long hand; /* cost of dealing hand */ + long inspection; /* cost of inspecting hand */ + long game; /* cost of buying game */ + long runs; /* cost of running through hands */ + long information; /* cost of information */ + long thinktime; /* cost of thinking time */ + long wins; /* total winnings */ + long worth; /* net worth after costs */ +}; +struct betinfo this, total; +bool startedgame = FALSE, infullgame = FALSE; +time_t acctstart; +int dbfd = -1; + +/* + * print directions above move box + */ +void printtopinstructions() +{ + move(tboxrow, boxcol); + printw("*--------------------------*"); + move(tboxrow + 1, boxcol); + printw("| MOVES |"); + move(tboxrow + 2, boxcol); + printw("|s# = stock to tableau |"); + move(tboxrow + 3, boxcol); + printw("|sf = stock to foundation |"); + move(tboxrow + 4, boxcol); + printw("|t# = talon to tableau |"); + move(tboxrow + 5, boxcol); + printw("|tf = talon to foundation |"); + move(tboxrow + 6, boxcol); + printw("|## = tableau to tableau |"); + move(tboxrow + 7, boxcol); + printw("|#f = tableau to foundation|"); + move(tboxrow + 8, boxcol); + printw("|ht = hand to talon |"); + move(tboxrow + 9, boxcol); + printw("|c = toggle card counting |"); + move(tboxrow + 10, boxcol); + printw("|b = present betting info |"); + move(tboxrow + 11, boxcol); + printw("|q = quit to end the game |"); + move(tboxrow + 12, boxcol); + printw("|==========================|"); +} + +/* + * Print the betting box. + */ +void printtopbettingbox() +{ + move(tboxrow, boxcol); + printw(" "); + move(tboxrow + 1, boxcol); + printw("*--------------------------*"); + move(tboxrow + 2, boxcol); + printw("|Costs Hand Total |"); + move(tboxrow + 3, boxcol); + printw("| Hands |"); + move(tboxrow + 4, boxcol); + printw("| Inspections |"); + move(tboxrow + 5, boxcol); + printw("| Games |"); + move(tboxrow + 6, boxcol); + printw("| Runs |"); + move(tboxrow + 7, boxcol); + printw("| Information |"); + move(tboxrow + 8, boxcol); + printw("| Think time |"); + move(tboxrow + 9, boxcol); + printw("|Total Costs |"); + move(tboxrow + 10, boxcol); + printw("|Winnings |"); + move(tboxrow + 11, boxcol); + printw("|Net Worth |"); + move(tboxrow + 12, boxcol); + printw("|==========================|"); +} + +/* + * clear info above move box + */ +void clearabovemovebox() +{ + int i; + + for (i = 0; i <= 11; i++) { + move(tboxrow + i, boxcol); + printw(" "); + } + move(tboxrow + 12, boxcol); + printw("*--------------------------*"); +} + +/* + * print instructions below move box + */ +void printbottominstructions() +{ + move(bboxrow, boxcol); + printw("|Replace # with the number |"); + move(bboxrow + 1, boxcol); + printw("|of the tableau you want. |"); + move(bboxrow + 2, boxcol); + printw("*--------------------------*"); +} + +/* + * print betting information below move box + */ +void printbottombettingbox() +{ + move(bboxrow, boxcol); + printw("|x = toggle information box|"); + move(bboxrow + 1, boxcol); + printw("|i = list instructions |"); + move(bboxrow + 2, boxcol); + printw("*--------------------------*"); +} + +/* + * clear info below move box + */ +void clearbelowmovebox() +{ + int i; + + move(bboxrow, boxcol); + printw("*--------------------------*"); + for (i = 1; i <= 2; i++) { + move(bboxrow + i, boxcol); + printw(" "); + } +} + +/* + * The following procedures print the board onto the screen using the + * addressible cursor. The end of these procedures will also be + * separated from the rest of the program. + * + * procedure to set the move command box + */ +void movebox() +{ + switch (status) { + case BETTINGBOX: + printtopbettingbox(); + break; + case NOBOX: + clearabovemovebox(); + break; + case INSTRUCTIONBOX: + printtopinstructions(); + break; + } + move(moverow, boxcol); + printw("| |"); + move(msgrow, boxcol); + printw("| |"); + switch (status) { + case BETTINGBOX: + printbottombettingbox(); + break; + case NOBOX: + clearbelowmovebox(); + break; + case INSTRUCTIONBOX: + printbottominstructions(); + break; + } + refresh(); +} + +/* + * procedure to put the board on the screen using addressable cursor + */ +void makeboard() +{ + clear(); + refresh(); + move(titlerow, titlecol); + printw("=-> CANFIELD <-="); + move(fttlrow, fttlcol); + printw("foundation"); + move(foundrow - 1, fttlcol); + printw("=---= =---= =---= =---="); + move(foundrow, fttlcol); + printw("| | | | | | | |"); + move(foundrow + 1, fttlcol); + printw("=---= =---= =---= =---="); + move(ottlrow, sidecol); + printw("stock tableau"); + move(stockrow - 1, sidecol); + printw("=---="); + move(stockrow, sidecol); + printw("| |"); + move(stockrow + 1, sidecol); + printw("=---="); + move(talonrow - 2, sidecol); + printw("talon"); + move(talonrow - 1, sidecol); + printw("=---="); + move(talonrow, sidecol); + printw("| |"); + move(talonrow + 1, sidecol); + printw("=---="); + move(tabrow - 1, atabcol); + printw("-1- -2- -3- -4-"); + movebox(); +} + +/* + * procedure to clear card counting info from screen + */ +void clearstat() +{ + int row; + + move(talonstatrow, talonstatcol - 7); + printw(" "); + move(handstatrow, handstatcol - 7); + printw(" "); + move(stockstatrow, stockstatcol - 7); + printw(" "); + for (row = ctoprow ; row <= cbotrow ; row++) { + move(row, cinitcol); + printw("%56s", " "); + } +} + +/* + * procedure to remove the card from the board + */ +void removecard(a, b) +{ + move(b, a); + printw(" "); +} + +/* + * clean up the board for another game + */ +void cleanupboard() +{ + int cnt, row, col; + struct cardtype *ptr; + + if (Cflag) { + clearstat(); + for(ptr = stock, row = stockrow; + ptr != NIL; + ptr = ptr->next, row++) { + move(row, sidecol); + printw(" "); + } + move(row, sidecol); + printw(" "); + move(stockrow + 1, sidecol); + printw("=---="); + move(talonrow - 2, sidecol); + printw("talon"); + move(talonrow - 1, sidecol); + printw("=---="); + move(talonrow + 1, sidecol); + printw("=---="); + } + move(stockrow, sidecol); + printw("| |"); + move(talonrow, sidecol); + printw("| |"); + move(foundrow, fttlcol); + printw("| | | | | | | |"); + for (cnt = 0; cnt < 4; cnt++) { + switch(cnt) { + default: + case 0: + col = atabcol; + break; + case 1: + col = btabcol; + break; + case 2: + col = ctabcol; + break; + case 3: + col = dtabcol; + break; + } + for(ptr = tableau[cnt], row = tabrow; + ptr != NIL; + ptr = ptr->next, row++) + removecard(col, row); + } +} + +/* + * procedure to create a deck of cards + */ +void initdeck(deck) + struct cardtype *deck[]; +{ + int i; + int scnt; + char s; + int r; + + i = 0; + for (scnt=0; scnt<4; scnt++) { + s = suitmap[scnt]; + for (r=Ace; r<=King; r++) { + deck[i] = &cards[i]; + cards[i].rank = r; + cards[i].suit = s; + cards[i].color = colormap[scnt]; + cards[i].next = NIL; + i++; + } + } +} + +/* + * procedure to shuffle the deck + */ +void shuffle(deck) + struct cardtype *deck[]; +{ + int i,j; + struct cardtype *temp; + + for (i=0; ivisible = FALSE; + deck[i]->paid = FALSE; + } + for (i = decksize-1; i>=0; i--) { + j = random() % decksize; + if (i != j) { + temp = deck[i]; + deck[i] = deck[j]; + deck[j] = temp; + } + } +} + +/* + * procedure to print the cards on the board + */ +void printrank(a, b, cp, inverse) + struct cardtype *cp; + bool inverse; +{ + move(b, a); + if (cp->rank != 10) + addch(' '); + if (inverse) + standout(); + switch (cp->rank) { + case 2: case 3: case 4: case 5: case 6: case 7: + case 8: case 9: case 10: + printw("%d", cp->rank); + break; + case Ace: + addch('A'); + break; + case Jack: + addch('J'); + break; + case Queen: + addch('Q'); + break; + case King: + addch('K'); + } + if (inverse) + standend(); +} + +/* + * procedure to print out a card + */ +void printcard(a, b, cp) + int a,b; + struct cardtype *cp; +{ + if (cp == NIL) + removecard(a, b); + else if (cp->visible == FALSE) { + move(b, a); + printw(" ? "); + } else { + bool inverse = (cp->suit == 'd' || cp->suit == 'h'); + + printrank(a, b, cp, inverse); + if (inverse) + standout(); + addch(cp->suit); + if (inverse) + standend(); + } +} + +/* + * procedure to move the top card from one location to the top + * of another location. The pointers always point to the top + * of the piles. + */ +void transit(source, dest) + struct cardtype **source, **dest; +{ + struct cardtype *temp; + + temp = *source; + *source = (*source)->next; + temp->next = *dest; + *dest = temp; +} + +/* + * procedure to update card counting base + */ +void usedtalon() +{ + removecard(coldcol, coldrow); + DECRHAND(coldrow, coldcol); + if (talon != NIL && (talon->visible == FALSE)) { + talon->visible = TRUE; + if (Cflag) { + this.information += costofinformation; + total.information += costofinformation; + talon->paid = TRUE; + printcard(coldcol, coldrow, talon); + } + } + taloncnt--; + if (Cflag) { + move(talonstatrow, talonstatcol); + printw("%3d", taloncnt); + } +} + +/* + * procedure to update stock card counting base + */ +void usedstock() +{ + stockcnt--; + if (Cflag) { + move(stockstatrow, stockstatcol); + printw("%3d", stockcnt); + } +} + +/* + * Procedure to set the cards on the foundation base when available. + * Note that it is only called on a foundation pile at the beginning of + * the game, so the pile will have exactly one card in it. + */ +void fndbase(cp, column, row) + struct cardtype **cp; +{ + bool nomore; + + if (*cp != NIL) + do { + if ((*cp)->rank == basecard->rank) { + base++; + printcard(pilemap[base], foundrow, *cp); + if (*cp == tableau[0]) + length[0] = length[0] - 1; + if (*cp == tableau[1]) + length[1] = length[1] - 1; + if (*cp == tableau[2]) + length[2] = length[2] - 1; + if (*cp == tableau[3]) + length[3] = length[3] - 1; + transit(cp, &found[base]); + if (cp == &talon) + usedtalon(); + if (cp == &stock) + usedstock(); + if (*cp != NIL) { + printcard(column, row, *cp); + nomore = FALSE; + } else { + removecard(column, row); + nomore = TRUE; + } + cardsoff++; + if (infullgame) { + this.wins += valuepercardup; + total.wins += valuepercardup; + } + } else + nomore = TRUE; + } while (nomore == FALSE); +} + +/* + * procedure to initialize the things necessary for the game + */ +void initgame() +{ + register int i; + + for (i=0; i<18; i++) { + deck[i]->visible = TRUE; + deck[i]->paid = TRUE; + } + stockcnt = 13; + stock = deck[12]; + for (i=12; i>=1; i--) + deck[i]->next = deck[i - 1]; + deck[0]->next = NIL; + found[0] = deck[13]; + deck[13]->next = NIL; + for (i=1; i<4; i++) + found[i] = NIL; + basecard = found[0]; + for (i=14; i<18; i++) { + tableau[i - 14] = deck[i]; + deck[i]->next = NIL; + } + for (i=0; i<4; i++) { + bottom[i] = tableau[i]; + length[i] = tabrow; + } + hand = deck[18]; + for (i=18; inext = deck[i + 1]; + deck[decksize-1]->next = NIL; + talon = NIL; + base = 0; + cinhand = 34; + taloncnt = 0; + timesthru = 0; + cardsoff = 1; + coldrow = ctoprow; + coldcol = cinitcol; + cnewrow = ctoprow; + cnewcol = cinitcol + cwidthcol; +} + +/* + * procedure to print card counting info on screen + */ +void showstat() +{ + int row, col; + register struct cardtype *ptr; + + if (!Cflag) + return; + move(talonstatrow, talonstatcol - 7); + printw("Talon: %3d", taloncnt); + move(handstatrow, handstatcol - 7); + printw("Hand: %3d", cinhand); + move(stockstatrow, stockstatcol - 7); + printw("Stock: %3d", stockcnt); + for (row = coldrow, col = coldcol, ptr = talon; + ptr != NIL; + ptr = ptr->next) { + if (ptr->paid == FALSE && ptr->visible == TRUE) { + ptr->paid = TRUE; + this.information += costofinformation; + total.information += costofinformation; + } + printcard(col, row, ptr); + DECRHAND(row, col); + } + for (row = cnewrow, col = cnewcol, ptr = hand; + ptr != NIL; + ptr = ptr->next) { + if (ptr->paid == FALSE && ptr->visible == TRUE) { + ptr->paid = TRUE; + this.information += costofinformation; + total.information += costofinformation; + } + INCRHAND(row, col); + printcard(col, row, ptr); + } +} + +/* + * procedure to turn the cards onto the talon from the deck + */ +void movetotalon() +{ + int i, fin; + + if (cinhand <= 3 && cinhand > 0) { + move(msgrow, msgcol); + printw("Hand is now empty "); + } + if (cinhand >= 3) + fin = 3; + else if (cinhand > 0) + fin = cinhand; + else if (talon != NIL) { + timesthru++; + errmsg = TRUE; + move(msgrow, msgcol); + if (timesthru != 4) { + printw("Talon is now the new hand"); + this.runs += costofrunthroughhand; + total.runs += costofrunthroughhand; + while (talon != NIL) { + transit(&talon, &hand); + cinhand++; + } + if (cinhand >= 3) + fin = 3; + else + fin = cinhand; + taloncnt = 0; + coldrow = ctoprow; + coldcol = cinitcol; + cnewrow = ctoprow; + cnewcol = cinitcol + cwidthcol; + clearstat(); + showstat(); + } else { + fin = 0; + done = TRUE; + printw("I believe you have lost"); + refresh(); + sleep(5); + } + } else { + errmsg = TRUE; + move(msgrow, msgcol); + printw("Talon and hand are empty"); + fin = 0; + } + for (i=0; ivisible = TRUE; + if (Cflag) { + if (talon->paid == FALSE && talon->visible == TRUE) { + this.information += costofinformation; + total.information += costofinformation; + talon->paid = TRUE; + } + printcard(coldcol, coldrow, talon); + } + } + if (fin != 0) { + printcard(taloncol, talonrow, talon); + cinhand -= fin; + taloncnt += fin; + if (Cflag) { + move(handstatrow, handstatcol); + printw("%3d", cinhand); + move(talonstatrow, talonstatcol); + printw("%3d", taloncnt); + } + fndbase(&talon, taloncol, talonrow); + } +} + +/* + * procedure to update the betting values + */ +void updatebettinginfo() +{ + long thiscosts, totalcosts; + time_t now; + register long dollars; + + time(&now); + dollars = (now - acctstart) / secondsperdollar; + if (dollars > 0) { + acctstart += dollars * secondsperdollar; + if (dollars > maxtimecharge) + dollars = maxtimecharge; + this.thinktime += dollars; + total.thinktime += dollars; + } + thiscosts = this.hand + this.inspection + this.game + + this.runs + this.information + this.thinktime; + totalcosts = total.hand + total.inspection + total.game + + total.runs + total.information + total.thinktime; + this.worth = this.wins - thiscosts; + total.worth = total.wins - totalcosts; + if (status != BETTINGBOX) + return; + move(tboxrow + 3, boxcol + 13); + printw("%4d%9d", this.hand, total.hand); + move(tboxrow + 4, boxcol + 13); + printw("%4d%9d", this.inspection, total.inspection); + move(tboxrow + 5, boxcol + 13); + printw("%4d%9d", this.game, total.game); + move(tboxrow + 6, boxcol + 13); + printw("%4d%9d", this.runs, total.runs); + move(tboxrow + 7, boxcol + 13); + printw("%4d%9d", this.information, total.information); + move(tboxrow + 8, boxcol + 13); + printw("%4d%9d", this.thinktime, total.thinktime); + move(tboxrow + 9, boxcol + 13); + printw("%4d%9d", thiscosts, totalcosts); + move(tboxrow + 10, boxcol + 13); + printw("%4d%9d", this.wins, total.wins); + move(tboxrow + 11, boxcol + 13); + printw("%4d%9d", this.worth, total.worth); +} + +/* + * procedure to print the beginning cards and to start each game + */ +void startgame() +{ + register int j; + + shuffle(deck); + initgame(); + this.hand = costofhand; + total.hand += costofhand; + this.inspection = 0; + this.game = 0; + this.runs = 0; + this.information = 0; + this.wins = 0; + this.thinktime = 0; + infullgame = FALSE; + startedgame = FALSE; + printcard(foundcol, foundrow, found[0]); + printcard(stockcol, stockrow, stock); + printcard(atabcol, tabrow, tableau[0]); + printcard(btabcol, tabrow, tableau[1]); + printcard(ctabcol, tabrow, tableau[2]); + printcard(dtabcol, tabrow, tableau[3]); + printcard(taloncol, talonrow, talon); + move(foundrow - 2, basecol); + printw("Base"); + move(foundrow - 1, basecol); + printw("Rank"); + printrank(basecol, foundrow, found[0], 0); + for (j=0; j<=3; j++) + fndbase(&tableau[j], pilemap[j], tabrow); + fndbase(&stock, stockcol, stockrow); + showstat(); /* show card counting info to cheaters */ + movetotalon(); + updatebettinginfo(); +} + +/* + * procedure to clear the message printed from an error + */ +void clearmsg() +{ + int i; + + if (errmsg == TRUE) { + errmsg = FALSE; + move(msgrow, msgcol); + for (i=0; i<25; i++) + addch(' '); + refresh(); + } +} + +/* + * procedure to print an error message if the move is not listed + */ +void dumberror() +{ + errmsg = TRUE; + move(msgrow, msgcol); + printw("Not a proper move "); +} + +/* + * procedure to print an error message if the move is not possible + */ +void destinerror() +{ + errmsg = TRUE; + move(msgrow, msgcol); + printw("Error: Can't move there"); +} + +/* + * function to see if the source has cards in it + */ +bool notempty(cp) + struct cardtype *cp; +{ + if (cp == NIL) { + errmsg = TRUE; + move(msgrow, msgcol); + printw("Error: no cards to move"); + return (FALSE); + } else + return (TRUE); +} + +/* + * function to see if the rank of one card is less than another + */ +bool ranklower(cp1, cp2) + struct cardtype *cp1, *cp2; +{ + if (cp2->rank == Ace) + if (cp1->rank == King) + return (TRUE); + else + return (FALSE); + else if (cp1->rank + 1 == cp2->rank) + return (TRUE); + else + return (FALSE); +} + +/* + * function to check the cardcolor for moving to a tableau + */ +bool diffcolor(cp1, cp2) + struct cardtype *cp1, *cp2; +{ + if (cp1->color == cp2->color) + return (FALSE); + else + return (TRUE); +} + +/* + * function to see if the card can move to the tableau + */ +bool tabok(cp, des) + struct cardtype *cp; +{ + if ((cp == stock) && (tableau[des] == NIL)) + return (TRUE); + else if (tableau[des] == NIL) + if (stock == NIL && + cp != bottom[0] && cp != bottom[1] && + cp != bottom[2] && cp != bottom[3]) + return (TRUE); + else + return (FALSE); + else if (ranklower(cp, tableau[des]) && diffcolor(cp, tableau[des])) + return (TRUE); + else + return (FALSE); +} + +/* + * Suspend the game (shell escape if no process control on system) + */ +void suspend() +{ +#ifndef SIGTSTP + char *sh; +#endif + + move(21, 0); + refresh(); +#ifdef SIGTSTP + kill(getpid(), SIGTSTP); +#else + sh = getenv("SHELL"); + if (sh == NULL) + sh = "/bin/sh"; + system(sh); +#endif + raw(); + noecho(); +} + +/* + * procedure to get a command + */ +void getcmd(row, col, cp) + int row, col; + char *cp; +{ + char cmd[2], ch; + int i; + + i = 0; + move(row, col); + printw("%-24s", cp); + col += 1 + strlen(cp); + move(row, col); + refresh(); + do { + ch = getch() & 0177; + if (ch == SG_DEL) + ch = SG_ERASE; + if (ch >= 'A' && ch <= 'Z') + ch += ('a' - 'A'); + if (ch == '\f') { + wrefresh(curscr); + refresh(); + } else if (i >= 2 && ch != SG_ERASE && ch != SG_KILL) { + if (ch != '\n' && ch != '\r' && ch != ' ') + write(1, "\007", 1); + } else if (ch == SG_ERASE && i > 0) { + printw("\b \b"); + refresh(); + i--; + } else if (ch == SG_KILL && i > 0) { + while (i > 0) { + printw("\b \b"); + i--; + } + refresh(); + } else if (ch == '\032') { /* Control-Z */ + suspend(); + move(row, col + i); + refresh(); + } else if (isprint(ch)) { + cmd[i++] = ch; + addch(ch); + refresh(); + } + } while (ch != '\n' && ch != '\r' && ch != ' '); + srcpile = cmd[0]; + destpile = cmd[1]; +} + +/* + * let 'em know how they lost! + */ +void showcards() +{ + register struct cardtype *ptr; + int row; + + if (!Cflag || cardsoff == 52) + return; + for (ptr = talon; ptr != NIL; ptr = ptr->next) { + ptr->visible = TRUE; + ptr->paid = TRUE; + } + for (ptr = hand; ptr != NIL; ptr = ptr->next) { + ptr->visible = TRUE; + ptr->paid = TRUE; + } + showstat(); + move(stockrow + 1, sidecol); + printw(" "); + move(talonrow - 2, sidecol); + printw(" "); + move(talonrow - 1, sidecol); + printw(" "); + move(talonrow, sidecol); + printw(" "); + move(talonrow + 1, sidecol); + printw(" "); + for (ptr = stock, row = stockrow; ptr != NIL; ptr = ptr->next, row++) { + move(row, stockcol - 1); + printw("| |"); + printcard(stockcol, row, ptr); + } + if (stock == NIL) { + move(row, stockcol - 1); + printw("| |"); + row++; + } + move(handstatrow, handstatcol - 7); + printw(" "); + move(row, stockcol - 1); + printw("=---="); + if (cardsoff == 52) + getcmd(moverow, movecol, "Hit return to exit"); +} + +/* + * procedure to move a card from the stock or talon to the tableau + */ +void simpletableau(cp, des) + struct cardtype **cp; +{ + int origin; + + if (notempty(*cp)) { + if (tabok(*cp, des)) { + if (*cp == stock) + origin = stk; + else + origin = tal; + if (tableau[des] == NIL) + bottom[des] = *cp; + transit(cp, &tableau[des]); + length[des]++; + printcard(pilemap[des], length[des], tableau[des]); + timesthru = 0; + if (origin == stk) { + usedstock(); + printcard(stockcol, stockrow, stock); + } else { + usedtalon(); + printcard(taloncol, talonrow, talon); + } + } else + destinerror(); + } +} + +/* + * print the tableau + */ +void tabprint(sour, des) +{ + int dlength, slength, i; + struct cardtype *tempcard; + + for (i=tabrow; i<=length[sour]; i++) + removecard(pilemap[sour], i); + dlength = length[des] + 1; + slength = length[sour]; + if (slength == tabrow) + printcard(pilemap[des], dlength, tableau[sour]); + else + while (slength != tabrow - 1) { + tempcard = tableau[sour]; + for (i=1; i<=slength-tabrow; i++) + tempcard = tempcard->next; + printcard(pilemap[des], dlength, tempcard); + slength--; + dlength++; + } +} + +/* + * procedure to move from the tableau to the tableau + */ +void tabtotab(sour, des) + register int sour, des; +{ + struct cardtype *temp; + + if (notempty(tableau[sour])) { + if (tabok(bottom[sour], des)) { + tabprint(sour, des); + temp = bottom[sour]; + bottom[sour] = NIL; + if (bottom[des] == NIL) + bottom[des] = temp; + temp->next = tableau[des]; + tableau[des] = tableau[sour]; + tableau[sour] = NIL; + length[des] = length[des] + (length[sour] - (tabrow - 1)); + length[sour] = tabrow - 1; + timesthru = 0; + } else + destinerror(); + } +} + +/* + * functions to see if the card can go onto the foundation + */ +bool rankhigher(cp, let) + struct cardtype *cp; +{ + if (found[let]->rank == King) + if (cp->rank == Ace) + return(TRUE); + else + return(FALSE); + else if (cp->rank - 1 == found[let]->rank) + return(TRUE); + else + return(FALSE); +} + +/* + * function to determine if two cards are the same suit + */ +bool samesuit(cp, let) + struct cardtype *cp; +{ + if (cp->suit == found[let]->suit) + return (TRUE); + else + return (FALSE); +} + +/* + * procedure to move a card to the correct foundation pile + */ +void movetofound(cp, source) + struct cardtype **cp; +{ + tempbase = 0; + mtfdone = FALSE; + if (notempty(*cp)) { + do { + if (found[tempbase] != NIL) + if (rankhigher(*cp, tempbase) + && samesuit(*cp, tempbase)) { + if (*cp == stock) + mtforigin = stk; + else if (*cp == talon) + mtforigin = tal; + else + mtforigin = tab; + transit(cp, &found[tempbase]); + printcard(pilemap[tempbase], + foundrow, found[tempbase]); + timesthru = 0; + if (mtforigin == stk) { + usedstock(); + printcard(stockcol, stockrow, stock); + } else if (mtforigin == tal) { + usedtalon(); + printcard(taloncol, talonrow, talon); + } else { + removecard(pilemap[source], length[source]); + length[source]--; + } + cardsoff++; + if (infullgame) { + this.wins += valuepercardup; + total.wins += valuepercardup; + } + mtfdone = TRUE; + } else + tempbase++; + else + tempbase++; + } while ((tempbase != 4) && !mtfdone); + if (!mtfdone) + destinerror(); + } +} + +/* + * procedure to evaluate and make the specific moves + */ +void movecard() +{ + int source = 0, dest = 0; + char osrcpile, odestpile; + + done = FALSE; + errmsg = FALSE; + do { + if (talon == NIL && hand != NIL) + movetotalon(); + if (cardsoff == 52) { + refresh(); + srcpile = 'q'; + } else + getcmd(moverow, movecol, "Move:"); + clearmsg(); + if (srcpile >= '1' && srcpile <= '4') + source = (int) (srcpile - '1'); + if (destpile >= '1' && destpile <= '4') + dest = (int) (destpile - '1'); + if (!startedgame && + (srcpile == 't' || srcpile == 's' || srcpile == 'h' || + srcpile == '1' || srcpile == '2' || srcpile == '3' || + srcpile == '4')) { + startedgame = TRUE; + osrcpile = srcpile; + odestpile = destpile; + if (status != BETTINGBOX) + srcpile = 'y'; + else do { + getcmd(moverow, movecol, "Inspect game?"); + } while (srcpile != 'y' && srcpile != 'n'); + if (srcpile == 'n') { + srcpile = 'q'; + } else { + this.inspection += costofinspection; + total.inspection += costofinspection; + srcpile = osrcpile; + destpile = odestpile; + } + } + switch (srcpile) { + case 't': + if (destpile == 'f' || destpile == 'F') + movetofound(&talon, source); + else if (destpile >= '1' && destpile <= '4') + simpletableau(&talon, dest); + else + dumberror(); + break; + case 's': + if (destpile == 'f' || destpile == 'F') + movetofound(&stock, source); + else if (destpile >= '1' && destpile <= '4') + simpletableau(&stock, dest); + else dumberror(); + break; + case 'h': + if (destpile != 't' && destpile != 'T') { + dumberror(); + break; + } + if (infullgame) { + movetotalon(); + break; + } + if (status == BETTINGBOX) { + do { + getcmd(moverow, movecol, + "Buy game?"); + } while (srcpile != 'y' && + srcpile != 'n'); + if (srcpile == 'n') { + showcards(); + done = TRUE; + break; + } + } + infullgame = TRUE; + this.wins += valuepercardup * cardsoff; + total.wins += valuepercardup * cardsoff; + this.game += costofgame; + total.game += costofgame; + movetotalon(); + break; + case 'q': + showcards(); + done = TRUE; + break; + case 'b': + printtopbettingbox(); + printbottombettingbox(); + status = BETTINGBOX; + break; + case 'x': + clearabovemovebox(); + clearbelowmovebox(); + status = NOBOX; + break; + case 'i': + printtopinstructions(); + printbottominstructions(); + status = INSTRUCTIONBOX; + break; + case 'c': + Cflag = !Cflag; + if (Cflag) + showstat(); + else + clearstat(); + break; + case '1': case '2': case '3': case '4': + if (destpile == 'f' || destpile == 'F') + movetofound(&tableau[source], source); + else if (destpile >= '1' && destpile <= '4') + tabtotab(source, dest); + else dumberror(); + break; + default: + dumberror(); + } + fndbase(&stock, stockcol, stockrow); + fndbase(&talon, taloncol, talonrow); + updatebettinginfo(); + } while (!done); +} + +char *basicinstructions[] = { + "Here are brief instuctions to the game of Canfield:\n\n", + " If you have never played solitaire before, it is recom-\n", + "mended that you consult a solitaire instruction book. In\n", + "Canfield, tableau cards may be built on each other downward\n", + "in alternate colors. An entire pile must be moved as a unit\n", + "in building. Top cards of the piles are available to be able\n", + "to be played on foundations, but never into empty spaces.\n\n", + " Spaces must be filled from the stock. The top card of\n", + "the stock also is available to be played on foundations or\n", + "built on tableau piles. After the stock is exhausted, ta-\n", + "bleau spaces may be filled from the talon and the player may\n", + "keep them open until he wishes to use them.\n\n", + " Cards are dealt from the hand to the talon by threes\n", + "and this repeats until there are no more cards in the hand\n", + "or the player quits. To have cards dealt onto the talon the\n", + "player types 'ht' for his move. Foundation base cards are\n", + "also automatically moved to the foundation when they become\n", + "available.\n\n", + "push any key when you are finished: ", + 0 }; + +char *bettinginstructions[] = { + " The rules for betting are somewhat less strict than\n", + "those used in the official version of the game. The initial\n", + "deal costs $13. You may quit at this point or inspect the\n", + "game. Inspection costs $13 and allows you to make as many\n", + "moves as is possible without moving any cards from your hand\n", + "to the talon. (the initial deal places three cards on the\n", + "talon; if all these cards are used, three more are made\n", + "available) Finally, if the game seems interesting, you must\n", + "pay the final installment of $26. At this point you are\n", + "credited at the rate of $5 for each card on the foundation;\n", + "as the game progresses you are credited with $5 for each\n", + "card that is moved to the foundation. Each run through the\n", + "hand after the first costs $5. The card counting feature\n", + "costs $1 for each unknown card that is identified. If the\n", + "information is toggled on, you are only charged for cards\n", + "that became visible since it was last turned on. Thus the\n", + "maximum cost of information is $34. Playing time is charged\n", + "at a rate of $1 per minute.\n\n", + "push any key when you are finished: ", + 0, +}; + +/* + * procedure to printout instructions + */ +void instruct() +{ + register char **cp; + + move(originrow, origincol); + printw("This is the game of solitaire called Canfield. Do\n"); + printw("you want instructions for the game?"); + do { + getcmd(originrow + 3, origincol, "y or n?"); + } while (srcpile != 'y' && srcpile != 'n'); + if (srcpile == 'n') + return; + clear(); + for (cp = basicinstructions; *cp != 0; cp++) + printw(*cp); + refresh(); + getch(); + clear(); + move(originrow, origincol); + printw("Do you want instructions for betting?"); + do { + getcmd(originrow + 2, origincol, "y or n?"); + } while (srcpile != 'y' && srcpile != 'n'); + if (srcpile == 'n') + return; + clear(); + for (cp = bettinginstructions; *cp != 0; cp++) + printw(*cp); + refresh(); + getch(); +} + +/* + * procedure to initialize the game + */ +void initall() +{ + int uid, i; + + srandom(getpid()); + time(&acctstart); + initdeck(deck); + uid = getuid(); + if (uid < 0) + return; + dbfd = open("/games/lib/cfscores", 2); + if (dbfd < 0) + return; + i = lseek(dbfd, uid * sizeof(struct betinfo), 0); + if (i < 0) { + close(dbfd); + dbfd = -1; + return; + } + i = read(dbfd, (char *)&total, sizeof(total)); + if (i < 0) { + close(dbfd); + dbfd = -1; + return; + } + lseek(dbfd, uid * sizeof(struct betinfo), 0); +} + +/* + * procedure to end the game + */ +bool finish() +{ + int row, col; + + if (cardsoff == 52) { + getcmd(moverow, movecol, "Hit return to exit"); + clear(); + refresh(); + move(originrow, origincol); + printw("CONGRATULATIONS!\n"); + printw("You won the game. That is a feat to be proud of.\n"); + row = originrow + 5; + col = origincol; + } else { + move(msgrow, msgcol); + printw("You got %d card", cardsoff); + if (cardsoff > 1) + printw("s"); + printw(" off "); + move(msgrow, msgcol); + row = moverow; + col = movecol; + } + do { + getcmd(row, col, "Play again (y or n)?"); + } while (srcpile != 'y' && srcpile != 'n'); + errmsg = TRUE; + clearmsg(); + if (srcpile == 'y') + return (FALSE); + else + return (TRUE); +} + +/* + * procedure to clean up and exit + */ +void cleanup() +{ + + total.thinktime += 1; + status = NOBOX; + updatebettinginfo(); + if (dbfd != -1) { + write(dbfd, (char *)&total, sizeof(total)); + close(dbfd); + } + clear(); + move(22,0); + refresh(); + endwin(); + exit(0); + /* NOTREACHED */ +} + +/* + * Field an interrupt. + */ +void askquit() +{ + move(msgrow, msgcol); + printw("Really wish to quit? "); + + do { + getcmd(moverow, movecol, "y or n?"); + } while (srcpile != 'y' && srcpile != 'n'); + + clearmsg(); + + if (srcpile == 'y') + cleanup(); + signal(SIGINT, askquit); +} + +/* + * Can you tell that this used to be a Pascal program? + */ +int main(argc, argv) + int argc; + char *argv[]; +{ +#ifdef MAXLOAD + double vec[3]; + + getloadavg(vec, 3); + if (vec[2] >= MAXLOAD) { + puts("The system load is too high. Try again later."); + exit(0); + } +#endif + signal(SIGINT, askquit); + signal(SIGHUP, cleanup); + signal(SIGTERM, cleanup); + initscr(); + raw(); + noecho(); + initall(); + instruct(); + makeboard(); + for (;;) { + startgame(); + movecard(); + if (finish()) + break; + if (cardsoff == 52) + makeboard(); + else + cleanupboard(); + } + cleanup(); + return 0; +} diff --git a/src/games/cfscores.c b/src/games/cfscores.c new file mode 100644 index 0000000..041b3fe --- /dev/null +++ b/src/games/cfscores.c @@ -0,0 +1,114 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include +#include +#include +#include +#include +#include + +struct betinfo { + long hand; /* cost of dealing hand */ + long inspection; /* cost of inspecting hand */ + long game; /* cost of buying game */ + long runs; /* cost of running through hands */ + long information; /* cost of information */ + long thinktime; /* cost of thinking time */ + long wins; /* total winnings */ + long worth; /* net worth after costs */ +}; + +char *scorefile = "/games/lib/cfscores"; +int dbfd; + +/* + * print out info for specified password entry + */ +void printuser(pw, printfail) + register struct passwd *pw; + int printfail; +{ + struct betinfo total; + int i; + + if (pw->pw_uid < 0) { + printf("Bad uid %d\n", pw->pw_uid); + return; + } + i = lseek(dbfd, pw->pw_uid * sizeof(struct betinfo), 0); + if (i < 0) { + perror("lseek"); + return; + } + i = read(dbfd, (char *)&total, sizeof(total)); + if (i < 0) { + perror("read"); + return; + } + if (i == 0 || total.hand == 0) { + if (printfail) + printf("%s has never played canfield.\n", pw->pw_name); + return; + } + printf("*----------------------*\n"); + if (total.worth >= 0) + printf("* Winnings for %-8s*\n", pw->pw_name); + else + printf("* Losses for %-10s*\n", pw->pw_name); + printf("*======================*\n"); + printf("|Costs Total |\n"); + printf("| Hands %8ld |\n", total.hand); + printf("| Inspections %8ld |\n", total.inspection); + printf("| Games %8ld |\n", total.game); + printf("| Runs %8ld |\n", total.runs); + printf("| Information %8ld |\n", total.information); + printf("| Think time %8ld |\n", total.thinktime); + printf("|Total Costs %8ld |\n", total.wins - total.worth); + printf("|Winnings %8ld |\n", total.wins); + printf("|Net Worth %8ld |\n", total.worth); + printf("*----------------------*\n\n"); +} + +int main(argc, argv) + int argc; + char *argv[]; +{ + register struct passwd *pw; + int uid; + + if (argc > 2) { + printf("Usage: cfscores [user]\n"); + exit(1); + } + dbfd = open(scorefile, 0); + if (dbfd < 0) { + perror(scorefile); + exit(2); + } + setpwent(); + if (argc == 1) { + uid = getuid(); + pw = getpwuid(uid); + if (pw == 0) { + printf("You are not listed in the password file?!?\n"); + exit(2); + } + printuser(pw, 1); + exit(0); + } + if (strcmp(argv[1], "-a") == 0) { + while ((pw = getpwent()) != 0) + printuser(pw, 0); + exit(0); + } + pw = getpwnam(argv[1]); + if (pw == 0) { + printf("User %s unknown\n", argv[1]); + exit(3); + } + printuser(pw, 1); + exit(0); +} diff --git a/src/games/cribbage/Makefile b/src/games/cribbage/Makefile new file mode 100644 index 0000000..d0d3525 --- /dev/null +++ b/src/games/cribbage/Makefile @@ -0,0 +1,51 @@ +# +# Copyright (c) 1980 Regents of the University of California. +# All rights reserved. The Berkeley software License Agreement +# specifies the terms and conditions for redistribution. +# +# @(#)Makefile 5.2.1 (2.11BSD) 1996/1/28 +# +# make file for cribbage +# +HDRS= cribbage.h deck.h cribcur.h +OBJS= extern.o crib.o support.o cards.o score.o io.o +CFILES= extern.c crib.c support.c cards.c score.c io.c +TOBJS= test.o cards.o score.o io.o extern.o +MAN= crib.0 +SEPFLAG= -i +CFLAGS= -O +DESTDIR= + +all: cribbage ${MAN} + +cribbage: ${OBJS} + ${CC} ${SEPFLAG} ${CFLAGS} -o cribbage ${OBJS} -lcurses -ltermlib + +all: cribbage ${MAN} + +crib.o io.o support.o: cribcur.h + +test: ${TOBJS} + ${CC} ${SEPFLAG} ${CFLAGS} -o test ${TOBJS} -lcurses -ltermlib + +crib.0: cribbage.n macro + nroff cribbage.n > crib.0 + +tags: ${HDRS} ${CFILES} + ctags -u $? + ed - tags < :ctfix + sort tags -o tags + +clean: + rm -f ${OBJS} ? a.out core crib.0 cribbage errs + +crib.o: deck.h cribbage.h cribcur.h +support.o: deck.h cribbage.h cribcur.h +test.o: deck.h +cards.o: deck.h +score.o: deck.h +io.o: deck.h cribcur.h + +install: cribbage crib.0 + install -s cribbage $(DESTDIR)/usr/games + install -m 644 crib.0 $(DESTDIR)/usr/games/lib/crib.instr diff --git a/src/games/cribbage/_ctfix b/src/games/cribbage/_ctfix new file mode 100644 index 0000000..78c4a73 --- /dev/null +++ b/src/games/cribbage/_ctfix @@ -0,0 +1,3 @@ +g/^Mcrib/s//main/ +w +q diff --git a/src/games/cribbage/cards.c b/src/games/cribbage/cards.c new file mode 100644 index 0000000..e7805b3 --- /dev/null +++ b/src/games/cribbage/cards.c @@ -0,0 +1,134 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +#ifndef lint +static char sccsid[] = "@(#)cards.c 5.1 (Berkeley) 5/30/85"; +#endif not lint + +#include +#include "deck.h" + + +/* + * initialize a deck of cards to contain one of each type + */ + +makedeck( d ) + + CARD d[]; +{ + register int i, j, k; + long time(); + + i = time( (long *) 0 ); + i = ( (i&0xff) << 8 ) | ( (i >> 8)&0xff ) | 1; + srand( i ); + k = 0; + for( i = 0; i < RANKS; i++ ) { + for( j = 0; j < SUITS; j++ ) { + d[k].suit = j; + d[k++].rank = i; + } + } +} + + + +/* + * given a deck of cards, shuffle it -- i.e. randomize it + * see Knuth, vol. 2, page 125 + */ + +shuffle( d ) + + CARD d[]; +{ + register int j, k; + CARD c; + + for( j = CARDS; j > 0; --j ) { + k = ( rand() >> 4 ) % j; /* random 0 <= k < j */ + c = d[j - 1]; /* exchange (j - 1) and k */ + d[j - 1] = d[k]; + d[k] = c; + } +} + + + +/* + * return true if the two cards are equal... + */ + +eq( a, b ) + + CARD a, b; +{ + return( ( a.rank == b.rank ) && ( a.suit == b.suit ) ); +} + + + +/* + * isone returns TRUE if a is in the set of cards b + */ + +isone( a, b, n ) + + CARD a, b[]; + int n; +{ + register int i; + + for( i = 0; i < n; i++ ) { + if( eq( a, b[i] ) ) return( TRUE ); + } + return( FALSE ); +} + + + +/* + * remove the card a from the deck d of n cards + */ + +remove( a, d, n ) + + CARD a, d[]; + int n; +{ + register int i, j; + + j = 0; + for( i = 0; i < n; i++ ) { + if( !eq( a, d[i] ) ) d[j++] = d[i]; + } + if( j < n ) d[j].suit = d[j].rank = EMPTY; +} + + + +/* + * sorthand: + * Sort a hand of n cards + */ +sorthand(h, n) +register CARD h[]; +int n; +{ + register CARD *cp, *endp; + CARD c; + + for (endp = &h[n]; h < endp - 1; h++) + for (cp = h + 1; cp < endp; cp++) + if ((cp->rank < h->rank) || + (cp->rank == h->rank && cp->suit < h->suit)) { + c = *h; + *h = *cp; + *cp = c; + } +} + diff --git a/src/games/cribbage/crib.c b/src/games/cribbage/crib.c new file mode 100644 index 0000000..e853239 --- /dev/null +++ b/src/games/cribbage/crib.c @@ -0,0 +1,587 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +#ifndef lint +char copyright[] = +"@(#) Copyright (c) 1980 Regents of the University of California.\n\ + All rights reserved.\n"; +#endif not lint + +#ifndef lint +static char sccsid[] = "@(#)crib.c 5.1 (Berkeley) 5/30/85"; +#endif not lint + +# include +# include +# include "deck.h" +# include "cribbage.h" +# include "cribcur.h" + + +# define LOGFILE "/usr/games/lib/criblog" +# define INSTRCMD "more /usr/games/lib/crib.instr" + + +main(argc, argv) +int argc; +char *argv[]; +{ + register char *p; + BOOLEAN playing; + char *s; /* for reading arguments */ + char bust; /* flag for arg reader */ + FILE *f; + FILE *fopen(); + char *getline(); + int bye(); + + while (--argc > 0) { + if ((*++argv)[0] != '-') { + fprintf(stderr, "\n\ncribbage: usage is 'cribbage [-eqr]'\n"); + exit(1); + } + bust = FALSE; + for (s = argv[0] + 1; *s != NULL; s++) { + switch (*s) { + case 'e': + explain = TRUE; + break; + case 'q': + quiet = TRUE; + break; + case 'r': + rflag = TRUE; + break; + default: + fprintf(stderr, "\n\ncribbage: usage is 'cribbage [-eqr]'\n"); + exit(2); + break; + } + if (bust) + break; + } + } + + initscr(); + signal(SIGINT, bye); + crmode(); + noecho(); + Playwin = subwin(stdscr, PLAY_Y, PLAY_X, 0, 0); + Tablewin = subwin(stdscr, TABLE_Y, TABLE_X, 0, PLAY_X); + Compwin = subwin(stdscr, COMP_Y, COMP_X, 0, TABLE_X + PLAY_X); + Msgwin = subwin(stdscr, MSG_Y, MSG_X, Y_MSG_START, SCORE_X + 1); + leaveok(Playwin, TRUE); + leaveok(Tablewin, TRUE); + leaveok(Compwin, TRUE); + clearok(stdscr, FALSE); + + if (!quiet) { + msg("Do you need instructions for cribbage? "); + if (getuchar() == 'Y') { + endwin(); + fflush(stdout); + system(INSTRCMD); + crmode(); + noecho(); + clear(); + refresh(); + msg("For the rules of this program, do \"man cribbage\""); + } + } + playing = TRUE; + do { + wclrtobot(Msgwin); + msg(quiet ? "L or S? " : "Long (to 121) or Short (to 61)? "); + if (glimit == SGAME) + glimit = (getuchar() == 'L' ? LGAME : SGAME); + else + glimit = (getuchar() == 'S' ? SGAME : LGAME); + game(); + msg("Another game? "); + playing = (getuchar() == 'Y'); + } while (playing); + + if ((f = fopen(LOGFILE, "a")) != NULL) { + fprintf(f, "Won %5.5d, Lost %5.5d\n", cgames, pgames); + fclose(f); + } + + bye(); +} + +/* + * makeboard: + * Print out the initial board on the screen + */ +makeboard() +{ + mvaddstr(SCORE_Y + 0, SCORE_X, "+---------------------------------------+"); + mvaddstr(SCORE_Y + 1, SCORE_X, "| Score: 0 YOU |"); + mvaddstr(SCORE_Y + 2, SCORE_X, "| *.....:.....:.....:.....:.....:..... |"); + mvaddstr(SCORE_Y + 3, SCORE_X, "| *.....:.....:.....:.....:.....:..... |"); + mvaddstr(SCORE_Y + 4, SCORE_X, "| |"); + mvaddstr(SCORE_Y + 5, SCORE_X, "| *.....:.....:.....:.....:.....:..... |"); + mvaddstr(SCORE_Y + 6, SCORE_X, "| *.....:.....:.....:.....:.....:..... |"); + mvaddstr(SCORE_Y + 7, SCORE_X, "| Score: 0 ME |"); + mvaddstr(SCORE_Y + 8, SCORE_X, "+---------------------------------------+"); + gamescore(); +} + +/* + * gamescore: + * Print out the current game score + */ +gamescore() +{ + extern int Lastscore[]; + + if (pgames || cgames) { + mvprintw(SCORE_Y + 1, SCORE_X + 28, "Games: %3d", pgames); + mvprintw(SCORE_Y + 7, SCORE_X + 28, "Games: %3d", cgames); + } + Lastscore[0] = -1; + Lastscore[1] = -1; +} + +/* + * game: + * Play one game up to glimit points. Actually, we only ASK the + * player what card to turn. We do a random one, anyway. + */ +game() +{ + register int i, j; + BOOLEAN flag; + BOOLEAN compcrib; + + makeboard(); + refresh(); + makedeck(deck); + shuffle(deck); + if (gamecount == 0) { + flag = TRUE; + do { + if (!rflag) { /* player cuts deck */ + msg(quiet ? "Cut for crib? " : + "Cut to see whose crib it is -- low card wins? "); + getline(); + } + i = (rand() >> 4) % CARDS; /* random cut */ + do { /* comp cuts deck */ + j = (rand() >> 4) % CARDS; + } while (j == i); + addmsg(quiet ? "You cut " : "You cut the "); + msgcard(deck[i], FALSE); + endmsg(); + addmsg(quiet ? "I cut " : "I cut the "); + msgcard(deck[j], FALSE); + endmsg(); + flag = (deck[i].rank == deck[j].rank); + if (flag) { + msg(quiet ? "We tied..." : + "We tied and have to try again..."); + shuffle(deck); + continue; + } + else + compcrib = (deck[i].rank > deck[j].rank); + } while (flag); + } + else { + werase(Tablewin); + wrefresh(Tablewin); + werase(Compwin); + wrefresh(Compwin); + msg("Loser (%s) gets first crib", (iwon ? "you" : "me")); + compcrib = !iwon; + } + + pscore = cscore = 0; + flag = TRUE; + do { + shuffle(deck); + flag = !playhand(compcrib); + compcrib = !compcrib; + } while (flag); + ++gamecount; + if (cscore < pscore) { + if (glimit - cscore > 60) { + msg("YOU DOUBLE SKUNKED ME!"); + pgames += 4; + } + else if (glimit - cscore > 30) { + msg("YOU SKUNKED ME!"); + pgames += 2; + } + else { + msg("YOU WON!"); + ++pgames; + } + iwon = FALSE; + } + else { + if (glimit - pscore > 60) { + msg("I DOUBLE SKUNKED YOU!"); + cgames += 4; + } + else if (glimit - pscore > 30) { + msg("I SKUNKED YOU!"); + cgames += 2; + } + else { + msg("I WON!"); + ++cgames; + } + iwon = TRUE; + } + gamescore(); +} + +/* + * playhand: + * Do up one hand of the game + */ +playhand(mycrib) +BOOLEAN mycrib; +{ + register int deckpos; + extern char Msgbuf[]; + + werase(Compwin); + + knownum = 0; + deckpos = deal(mycrib); + sorthand(chand, FULLHAND); + sorthand(phand, FULLHAND); + makeknown(chand, FULLHAND); + prhand(phand, FULLHAND, Playwin, FALSE); + discard(mycrib); + if (cut(mycrib, deckpos)) + return TRUE; + if (peg(mycrib)) + return TRUE; + werase(Tablewin); + wrefresh(Tablewin); + if (score(mycrib)) + return TRUE; + return FALSE; +} + + + +/* + * deal cards to both players from deck + */ + +deal( mycrib ) +{ + register int i, j; + + j = 0; + for( i = 0; i < FULLHAND; i++ ) { + if( mycrib ) { + phand[i] = deck[j++]; + chand[i] = deck[j++]; + } + else { + chand[i] = deck[j++]; + phand[i] = deck[j++]; + } + } + return( j ); +} + +/* + * discard: + * Handle players discarding into the crib... + * Note: we call cdiscard() after prining first message so player doesn't wait + */ +discard(mycrib) +BOOLEAN mycrib; +{ + register char *prompt; + CARD crd; + + prcrib(mycrib, TRUE); + prompt = (quiet ? "Discard --> " : "Discard a card --> "); + cdiscard(mycrib); /* puts best discard at end */ + crd = phand[infrom(phand, FULLHAND, prompt)]; + remove(crd, phand, FULLHAND); + prhand(phand, FULLHAND, Playwin, FALSE); + crib[0] = crd; +/* next four lines same as last four except for cdiscard() */ + crd = phand[infrom(phand, FULLHAND - 1, prompt)]; + remove(crd, phand, FULLHAND - 1); + prhand(phand, FULLHAND, Playwin, FALSE); + crib[1] = crd; + crib[2] = chand[4]; + crib[3] = chand[5]; + chand[4].rank = chand[4].suit = chand[5].rank = chand[5].suit = EMPTY; +} + +/* + * cut: + * Cut the deck and set turnover. Actually, we only ASK the + * player what card to turn. We do a random one, anyway. + */ +cut(mycrib, pos) +BOOLEAN mycrib; +int pos; +{ + register int i, cardx; + BOOLEAN win = FALSE; + + if (mycrib) { + if (!rflag) { /* random cut */ + msg(quiet ? "Cut the deck? " : + "How many cards down do you wish to cut the deck? "); + getline(); + } + i = (rand() >> 4) % (CARDS - pos); + turnover = deck[i + pos]; + addmsg(quiet ? "You cut " : "You cut the "); + msgcard(turnover, FALSE); + endmsg(); + if (turnover.rank == JACK) { + msg("I get two for his heels"); + win = chkscr(&cscore,2 ); + } + } + else { + i = (rand() >> 4) % (CARDS - pos) + pos; + turnover = deck[i]; + addmsg(quiet ? "I cut " : "I cut the "); + msgcard(turnover, FALSE); + endmsg(); + if (turnover.rank == JACK) { + msg("You get two for his heels"); + win = chkscr(&pscore, 2); + } + } + makeknown(&turnover, 1); + prcrib(mycrib, FALSE); + return win; +} + +/* + * prcrib: + * Print out the turnover card with crib indicator + */ +prcrib(mycrib, blank) +BOOLEAN mycrib, blank; +{ + register int y, cardx; + + if (mycrib) + cardx = CRIB_X; + else + cardx = 0; + + mvaddstr(CRIB_Y, cardx + 1, "CRIB"); + prcard(stdscr, CRIB_Y + 1, cardx, turnover, blank); + + if (mycrib) + cardx = 0; + else + cardx = CRIB_X; + + for (y = CRIB_Y; y <= CRIB_Y + 5; y++) + mvaddstr(y, cardx, " "); +} + +/* + * peg: + * Handle all the pegging... + */ + +static CARD Table[14]; + +static int Tcnt; + +peg(mycrib) +BOOLEAN mycrib; +{ + static CARD ch[CINHAND], ph[CINHAND]; + CARD crd; + register int i, j, k; + register int l; + register int cnum, pnum, sum; + register BOOLEAN myturn, mego, ugo, last, played; + + cnum = pnum = CINHAND; + for (i = 0; i < CINHAND; i++) { /* make copies of hands */ + ch[i] = chand[i]; + ph[i] = phand[i]; + } + Tcnt = 0; /* index to table of cards played */ + sum = 0; /* sum of cards played */ + mego = ugo = FALSE; + myturn = !mycrib; + for (;;) { + last = TRUE; /* enable last flag */ + prhand(ph, pnum, Playwin, FALSE); + prhand(ch, cnum, Compwin, TRUE); + prtable(sum); + if (myturn) { /* my tyrn to play */ + if (!anymove(ch, cnum, sum)) { /* if no card to play */ + if (!mego && cnum) { /* go for comp? */ + msg("GO"); + mego = TRUE; + } + if (anymove(ph, pnum, sum)) /* can player move? */ + myturn = !myturn; + else { /* give him his point */ + msg(quiet ? "You get one" : "You get one point"); + if (chkscr(&pscore, 1)) + return TRUE; + sum = 0; + mego = ugo = FALSE; + Tcnt = 0; + } + } + else { + played = TRUE; + j = -1; + k = 0; + for (i = 0; i < cnum; i++) { /* maximize score */ + l = pegscore(ch[i], Table, Tcnt, sum); + if (l > k) { + k = l; + j = i; + } + } + if (j < 0) /* if nothing scores */ + j = cchose(ch, cnum, sum); + crd = ch[j]; + remove(crd, ch, cnum--); + sum += VAL(crd.rank); + Table[Tcnt++] = crd; + if (k > 0) { + addmsg(quiet ? "I get %d playing " : + "I get %d points playing ", k); + msgcard(crd, FALSE); + endmsg(); + if (chkscr(&cscore, k)) + return TRUE; + } + myturn = !myturn; + } + } + else { + if (!anymove(ph, pnum, sum)) { /* can player move? */ + if (!ugo && pnum) { /* go for player */ + msg("You have a GO"); + ugo = TRUE; + } + if (anymove(ch, cnum, sum)) /* can computer play? */ + myturn = !myturn; + else { + msg(quiet ? "I get one" : "I get one point"); + do_wait(); + if (chkscr(&cscore, 1)) + return TRUE; + sum = 0; + mego = ugo = FALSE; + Tcnt = 0; + } + } + else { /* player plays */ + played = FALSE; + if (pnum == 1) { + crd = ph[0]; + msg("You play your last card"); + } + else + for (;;) { + prhand(ph, pnum, Playwin, FALSE); + crd = ph[infrom(ph, pnum, "Your play: ")]; + if (sum + VAL(crd.rank) <= 31) + break; + else + msg("Total > 31 -- try again"); + } + makeknown(&crd, 1); + remove(crd, ph, pnum--); + i = pegscore(crd, Table, Tcnt, sum); + sum += VAL(crd.rank); + Table[Tcnt++] = crd; + if (i > 0) { + msg(quiet ? "You got %d" : "You got %d points", i); + if (chkscr(&pscore, i)) + return TRUE; + } + myturn = !myturn; + } + } + if (sum >= 31) { + if (!myturn) + do_wait(); + sum = 0; + mego = ugo = FALSE; + Tcnt = 0; + last = FALSE; /* disable last flag */ + } + if (!pnum && !cnum) + break; /* both done */ + } + prhand(ph, pnum, Playwin, FALSE); + prhand(ch, cnum, Compwin, TRUE); + prtable(sum); + if (last) + if (played) { + msg(quiet ? "I get one for last" : "I get one point for last"); + do_wait(); + if (chkscr(&cscore, 1)) + return TRUE; + } + else { + msg(quiet ? "You get one for last" : + "You get one point for last"); + if (chkscr(&pscore, 1)) + return TRUE; + } + return FALSE; +} + +/* + * prtable: + * Print out the table with the current score + */ +prtable(score) +int score; +{ + prhand(Table, Tcnt, Tablewin, FALSE); + mvwprintw(Tablewin, (Tcnt + 2) * 2, Tcnt + 1, "%2d", score); + wrefresh(Tablewin); +} + +/* + * score: + * Handle the scoring of the hands + */ +score(mycrib) +BOOLEAN mycrib; +{ + sorthand(crib, CINHAND); + if (mycrib) { + if (plyrhand(phand, "hand")) + return TRUE; + if (comphand(chand, "hand")) + return TRUE; + do_wait(); + if (comphand(crib, "crib")) + return TRUE; + } + else { + if (comphand(chand, "hand")) + return TRUE; + if (plyrhand(phand, "hand")) + return TRUE; + if (plyrhand(crib, "crib")) + return TRUE; + } + return FALSE; +} diff --git a/src/games/cribbage/cribbage.6 b/src/games/cribbage/cribbage.6 new file mode 100644 index 0000000..b5e3e40 --- /dev/null +++ b/src/games/cribbage/cribbage.6 @@ -0,0 +1,102 @@ +.\" Copyright (c) 1980 Regents of the University of California. +.\" All rights reserved. The Berkeley software License Agreement +.\" specifies the terms and conditions for redistribution. +.\" +.\" @(#)cribbage.6 6.2 (Berkeley) 5/6/86 +.\" +.TH CRIBBAGE 6 "May 6, 1986" +.UC 4 +.SH NAME +cribbage \- the card game cribbage +.SH SYNOPSIS +.B /usr/games/cribbage +[ +.B \-req +] +.I name ... +.SH DESCRIPTION +.I Cribbage +plays the card game cribbage, with the program playing one hand +and the user the other. The program will initially ask the user if +the rules of the game are needed \- if so, it will print out +the appropriate section from +.I According to Hoyle +with +.I more (I). +.PP +.I Cribbage +options include: +.TP +.B \-e +When the player makes a mistake scoring his hand or crib, provide an +explanation of the correct score. (This is especially useful for +beginning players.) +.TP +.B \-q +Print a shorter form of all messages \- this is only recommended for +users who have played the game without specifying this option. +.TP +.B \-r +Instead of asking the player to cut the deck, the program will randomly +cut the deck. +.PP +.I Cribbage +first asks the player whether he wishes to play a short game +(\*(lqonce around\*(rq, to 61) or a long game (\*(lqtwice around\*(rq, to 121). A +response of `s' will result in a short game, any other response will +play a long game. +.PP +At the start of the first game, the program +asks the player to cut the deck to determine who gets the +first crib. The user should respond with a number between 0 and +51, indicating how many cards down the deck is to be cut. The player +who cuts the lower ranked card gets the first crib. +If more than one game is played, the +loser of the previous game gets the first crib in the current game. +.PP +For each hand, the program first prints the player's hand, +whose crib it is, and then asks the player +to discard two cards into the crib. The cards are prompted for +one per line, and are typed as explained below. +.PP +After discarding, the program cuts the deck (if it is the player's +crib) or asks the player to cut the deck (if it's its crib); in the latter +case, the appropriate response is a number from 0 to 39 indicating +how far down the remaining 40 cards are to be cut. +.PP +After cutting the deck, play starts with the non-dealer (the person +who doesn't have the crib) leading the first card. +Play continues, as per cribbage, until all cards are exhausted. The +program keeps track of the scoring of all points and the total of +the cards on the table. +.PP +After play, the hands are scored. The program requests the player to +score his hand (and the crib, if it is his) by printing out the +appropriate cards (and the cut card enclosed in brackets). +Play continues until one player reaches the game limit (61 or 121). +.PP +A carriage return when a numeric input is expected is equivalent +to typing the lowest legal value; when cutting the deck this +is equivalent to choosing the top card. +.PP +Cards are specified as rank followed by suit. The ranks may be specified +as one of: +`a', `2', `3', `4', `5', `6', `7', `8', `9', `t', `j', `q', and `k', +or alternatively, one of: \*(lqace\*(rq, \*(lqtwo\*(rq, \*(lqthree\*(rq, \*(lqfour\*(rq, \*(lqfive\*(rq, \*(lqsix\*(rq, +\*(lqseven\*(rq, \*(lqeight\*(rq, \*(lqnine\*(rq, \*(lqten\*(rq, \*(lqjack\*(rq, \*(lqqueen\*(rq, and \*(lqking\*(rq. +Suits may be specified as: `s', `h', `d', and `c', or alternatively as: +\*(lqspades\*(rq, \*(lqhearts\*(rq, \*(lqdiamonds\*(rq, and \*(lqclubs\*(rq. +A card may be specified as: \*(lq \*(rq , or: \*(lq of \*(rq . +If the single letter rank and suit designations are used, the space +separating the suit and rank may be left out. Also, if only one card +of the desired rank is playable, typing the rank is sufficient. +For example, if your hand was \*(lq2H, 4D, 5C, 6H, JC, KD\*(rq and it was +desired to discard the king of diamonds, any of the following could be typed: +\*(lqk\*(rq, \*(lqking\*(rq, \*(lqkd\*(rq, \*(lqk d\*(rq, \*(lqk of d\*(rq, \*(lqking d\*(rq, \*(lqking of d\*(rq, \*(lqk diamonds\*(rq, +\*(lqk of diamonds\*(rq, \*(lqking diamonds\*(rq, or \*(lqking of diamonds\*(rq. +.SH FILES +.ta 2i +/usr/games/cribbage +.SH AUTHORS +Earl T. Cohen wrote the logic. +Ken Arnold added the screen oriented interface. diff --git a/src/games/cribbage/cribbage.h b/src/games/cribbage/cribbage.h new file mode 100644 index 0000000..9c0d793 --- /dev/null +++ b/src/games/cribbage/cribbage.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + * + * @(#)cribbage.h 5.1 (Berkeley) 5/30/85 + */ + +extern CARD deck[ CARDS ]; /* a deck */ +extern CARD phand[ FULLHAND ]; /* player's hand */ +extern CARD chand[ FULLHAND ]; /* computer's hand */ +extern CARD crib[ CINHAND ]; /* the crib */ +extern CARD turnover; /* the starter */ + +extern CARD known[ CARDS ]; /* cards we have seen */ +extern int knownum; /* # of cards we know */ + +extern int pscore; /* player's score */ +extern int cscore; /* comp's score */ +extern int glimit; /* points to win game */ + +extern int pgames; /* player's games won */ +extern int cgames; /* comp's games won */ +extern int gamecount; /* # games played */ +extern int Lastscore[2]; /* previous score for each */ + +extern BOOLEAN iwon; /* if comp won last */ +extern BOOLEAN explain; /* player mistakes explained */ +extern BOOLEAN rflag; /* if all cuts random */ +extern BOOLEAN quiet; /* if suppress random mess */ +extern BOOLEAN playing; /* currently playing game */ + +extern char expl[]; /* string for explanation */ + diff --git a/src/games/cribbage/cribbage.n b/src/games/cribbage/cribbage.n new file mode 100644 index 0000000..96eb9c1 --- /dev/null +++ b/src/games/cribbage/cribbage.n @@ -0,0 +1,318 @@ +.\" Copyright (c) 1980 Regents of the University of California. +.\" All rights reserved. The Berkeley software License Agreement +.\" specifies the terms and conditions for redistribution. +.\" +.\" @(#)cribbage.n 5.1 (Berkeley) 5/30/85 +.\" +.so macro +.na +.PH "CRIBBAGE" +.sp 2 +.ce +from +.sp +.ce +.ul +According to Hoyle +.sp 2 +.PG +Cribbage is believed to have been invented by Sir John Suckling (1609-1642). +Probably it is an elaboration of an older game, Noddy. The original game was +played with hands of five cards; the modern game gives each player six. That +is virtually the only change from Suckling's directions. +.HP "Players." +Two. There are variants for three and four players, described later. +.HP "Cards." +The pack of 52. The cards in each suit rank: K (high), Q, J, 10, 9, 8, +7, 6, 5, 4, 3, 2, A. The +.ul +counting values +are: K, Q, J, 10, each 10 (wherefore these are called +.ul +tenth cards); +ace, 1; each other card, its index value. +.HP "Cribbage Board". +Indispensable to scoring (unless you have a computer!, ed.) is the device +known as the +.ul +cribbage board. +This is a rectangular panel, long and narrow, in which are +four rows of 30 holes each. (See illustration.) At one end, or in the center, +are two or four additional holes, called +.ul +game holes. +The board is placed between the two players, and each keeps his own score on +the two rows of holes nearest himself. Each is supplied with two +.ul +pegs. +Before the first hand, the pegs are placed in the game holes. On +making his first score, the player advances one peg an appropriate number +of holes (one per point) away from the +.ul +game end +of the board. The second score is recorded by placing the second peg an +appropriate distance ahead of the first. For each subsequent score, the +rear peg is jumped ahead of the other, the distance between the two pegs +always showing the amount of this last score. +.PG +The traditional mode of scoring is down (away from the game end) the +outer row, and up the inner row. "Once around" is a game of 61 points. +"Twice around" is a game of 121 points. +.HP "Preliminaries." +Cards are drawn; the lower deals first. If cards of equal rank are drawn, +both players draw again. Dealer has the right to shuffle last. Nondealer +cuts, and must leave at least four cards in each packet. +.HP "Dealing." +Each player receives six cards, dealt one at a time face down, beginning +with the nondealer. The turn to deal alternates. The dealer has an +advantage. +.HP "Laying Away." +After seeing his hand, each player +.ul +lays away +two cards face down. The four cards laid away, placed in one pile, form the +.ul +crib. +The crib counts for the dealer. Nondealer therefore tries to lay away +.ul +balking cards -- +cards that are least likely to create a score in the crib. +.HP "The Starter." +After both hands have laid away, nondealer lifts off a packet from the top +of the +.ul +stock +(the rest of the pack). Again, each packet must contain at least four cards. +Dealer turns up the top card of the lower packer, which is then placed on +top of the stock when the packets are reunited. The card thus turned up is +called +.ul +1 the starter. +If it is a jack, dealer immediately pegs 2, called +.ul +2 for his heels. +.HP "The Play." +Nondealer begins the play by laying a card from his hand face up on the +table, announcing its counting value. Dealer then shows a card, announcing +the total count of the two cards. Play continues in the same way, by +alternate exposure of cards, each player announcing the new total count. +The total may be carried only to 31, no further. If a player adds a card +that brings the total exactly to 31, he pegs 2. If a player is unable to +play another card without exceeding 31, he must say "Go," and his opponent +pegs 1, but before doing so, opponent must lay down any additional cards he +can without exceeding 31. If such additional cards bring the total to +exactly 31, he pegs 2 instead of 1. +.PG +Whenever a +.ul +go +occurs, the opponent of the player who played the last card must lead for a +new count starting at zero. Playing the last card of all counts as a go. +(Since nondealer makes the opening lead, dealer is bound to peg at least +1 in play.) +.PG +Besides pegging for 31 and go, the player may also peg for certain +combinations made in play, as follows: +.sp 2 +.ti +4 +.ul +Fifteen. +.IP +Making the count total 15 pegs 2. +.EP +.sp 2 +.ti +4 +.ul +Pair. +.IP +Playing a card of same rank as that previously played pegs 2. Playing +a third card of the same rank makes +.ul +pair royal +and pegs 6. Playing the fourth card of the same rank makes +.ul +double pair royal +and pegs 12. +.PG +The tenth cards pair strictly by rank, a king with a king, a queen with a +queen, and so on. (King and jack do not make a pair, although each has +the counting value 10.) +.EP +.sp 2 +.ti +4 +.ul +Run. +.IP +Playing a card which, with the two or more played immediately previously, +makes a sequence of three or more cards, pegs 1 for each card in the +.ul +run. +Runs depend on rank alone; the suits do not matter. Nor does the score +for run depend upon playing the cards in strict sequence, so long as +the three or more last cards played can be arranged in a run. +.ul +Example: +7, 6, 8 played in that order score 3 for run; 5, 2, 4, 3 played in that order +score 4 for run. +.EP +.PG +Any of the foregoing combinations count, whether the cards are played +alternately or one player plays several times in succession in consequence +of a go. But a combination does not score if it is interrupted by a go. +.HP "Showing." +After the play, the hands are +.ul +shown +(counted). Nondealer shows first, then dealer's hand, then crib. +The starter is deemed to belong to each hand, so that each hand includes +five cards. Combinations of scoring value are as follows: +.sp 2 +.ti +4 +.ul +Fifteen. +.IP +Each combinations of two or more cards that total fifteen scores 2. +.EP +.sp 2 +.ti +4 +.ul +Pair. +.IP +Each pair of cards of the same rank scores 2. +.EP +.sp 2 +.ti +4 +.ul +Run. +.IP +Each combination of three or more cards in sequence scores 1 for each card +in the run. +.EP +.sp 2 +.ti +4 +.ul +Flush. +.IP +Four cards of the same suit in hand score 4; four cards in hand or crib +of same suit as the starter score 5. (No count for four-flush in crib.) +.EP +.sp 2 +.ti +4 +.ul +His Nobs. +.IP +Jack of same suit as the starter, in hand or crib, scores 1. +.EP +.PG +It is important to note that every separate grouping of cards that makes +a fifteen, pair, or run counts separately. Three of a kind, +.ul +pair royal, +counts 6 because three sets of pairs can be made; similarly, four of a +kind, +.ul +double pair royal, +contain six pairs and count 12. +.PG +The highest possible hand is J, 5, 5, 5 with the starter the 5 of the same +suit as the jack. There are four fifteens by combining the jack with a +five, four more by combinations of three fives (a total of 16 for fifteens); +the double pair royal adds 12 for a total of 28; and +.ul +his nobs +adds 1 for a maximum score of 29. (the score of 2 for +.ul +his heels +does not count in the total of the hand, since it is pegged before the play.) +.PG +A +.ul +double run +is a run with one card duplicated, as 4-3-3-2. Exclusive of fifteens, a +double run of three cards counts 8; of four cards, 10. A +.ul +triple run +is a run of three with one card triplicated, as K-K-K-Q-J. Exclusive of +fifteens, it counts 15. A +.ul +quadruple run +is a run of three with two different cards duplicated, as the example +8-8-7-6-6 previously given. Exclusive of fifteens, it counts 16. +.PG +No hand can be constructed that counts 19, 25, 26 or 27. A time-honored +way of showing a hand with not a single counting combination is to say +"I have nineteen." +.PG +The customary oder in showing is to count fifteens first, then runs, then +pairs, but there is no compulsion of law. +.ul +Example: +A hand (with starter) of 9-6-5-4-4 will usually be counted "Fifteen 2, +fifteen 4, fifteen 6 and double run makes 14," or simply "Fifteen 6 and +8 is 14." +.HP "Muggins." +The hands and crib are counted aloud, and if a player claims a greater +total than is due him, his opponent may require correction. In some +localities, if a player claims less than is due, his opponent may say +"Muggins" and himself score the points overlooked. +.HP "Scoring." +The usual +.ul +game +is 121, but it may be set at 61 by agreement. Since the player wins +who first returns to the game hole by going "twice around," the scores +must be pegged strictly in order: his heels, pegging in play, non-dealer's +hand, dealer's hand, crib. Thus, if nondealer goes out on showing his +hand, he wins, even though dealer might have gone out with a greater +total if allowed to count his hand and crib. +.PG +When the game of 121 is played for a stake, a player wins a single game +if the loser makes 61 points or more. If the loser fails to reach +61, he is +.ul +lurched, +and the other wins a double game. +.HP "Irregularities." +.ul +Misdeal. +There must be a new deal by the same dealer if a card is found faced in the +pack, if a card is exposed in dealing, or if the pack be found imperfect. +.PG +.ul +Wrong Number of Cards. +If one hand (not crib) is found to have the wrong number of cards after +laying away for the crib, the other hand and crib being correct, the +opponent may either demand a new deal or may peg 2 and rectify the +hand. If the crib is incorrect, both hands being correct, nondealer +pegs 2 and the crib is corrected. +.HP "Error in Pegging." +If a player places a peg short of the amount to which he is entitled, he +may not correct his error after he has played the next card or after the +cut for the next deal. If he pegs more than his announced score, +the error must be corrected on demand at any time before the cut for the +next deal and his opponent pegs 2. +.HP "Strategy." +The best balking cards are kings and aces, because they have the least +chance of producing sequences. Tenth cards are generally good, provided +that the two cards laid away are not too +.ul +near +(likely to make a sequence). When nothing better offers, give two +.ul +wide +cards -- at least three apart in rank. +.PG +Proverbially the safest lead is a 4. The next card cannot make a 15. +Lower cards are also safe from this point of view, but are better +treasured for go and 31. The most dangerous leads are 7 and 8, but +may be made to trap the opponent when they are backed with other +close cards. Generally speaking, play +.ul +on +(toward a sequence) when you have close cards and +.ul +off +when you do not. However, the state of the score is a consideration. +If far behind, play on when there is any chance of building a score +for yourself; if well ahead, balk your opponent by playing off unless +you will surely peg as much as he by playing on. diff --git a/src/games/cribbage/cribcur.h b/src/games/cribbage/cribcur.h new file mode 100644 index 0000000..c75ded9 --- /dev/null +++ b/src/games/cribbage/cribcur.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + * + * @(#)cribcur.h 5.1 (Berkeley) 5/30/85 + */ + +# define PLAY_Y 15 /* size of player's hand window */ +# define PLAY_X 12 +# define TABLE_Y 21 /* size of table window */ +# define TABLE_X 14 +# define COMP_Y 15 /* size of computer's hand window */ +# define COMP_X 12 +# define Y_SCORE_SZ 9 /* Y size of score board */ +# define X_SCORE_SZ 41 /* X size of score board */ +# define SCORE_Y 0 /* starting position of scoring board */ +# define SCORE_X (PLAY_X + TABLE_X + COMP_X) +# define CRIB_Y 17 /* position of crib (cut card) */ +# define CRIB_X (PLAY_X + TABLE_X) +# define MSG_Y (LINES - (Y_SCORE_SZ + 1)) +# define MSG_X (COLS - SCORE_X - 1) +# define Y_MSG_START (Y_SCORE_SZ + 1) + +# define PEG '*' /* what a peg looks like on the board */ + +extern WINDOW *Compwin; /* computer's hand window */ +extern WINDOW *Msgwin; /* message window */ +extern WINDOW *Playwin; /* player's hand window */ +extern WINDOW *Tablewin; /* table window */ diff --git a/src/games/cribbage/deck.h b/src/games/cribbage/deck.h new file mode 100644 index 0000000..c600be2 --- /dev/null +++ b/src/games/cribbage/deck.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + * + * @(#)deck.h 5.1 (Berkeley) 5/30/85 + */ + +/* + * define structure of a deck of cards and other related things + */ + + +#define CARDS 52 /* number cards in deck */ +#define RANKS 13 /* number ranks in deck */ +#define SUITS 4 /* number suits in deck */ + +#define CINHAND 4 /* # cards in cribbage hand */ +#define FULLHAND 6 /* # cards in dealt hand */ + +#define LGAME 121 /* number points in a game */ +#define SGAME 61 /* # points in a short game */ + +#define SPADES 0 /* value of each suit */ +#define HEARTS 1 +#define DIAMONDS 2 +#define CLUBS 3 + +#define ACE 0 /* value of each rank */ +#define TWO 1 +#define THREE 2 +#define FOUR 3 +#define FIVE 4 +#define SIX 5 +#define SEVEN 6 +#define EIGHT 7 +#define NINE 8 +#define TEN 9 +#define JACK 10 +#define QUEEN 11 +#define KING 12 +#define EMPTY 13 + +#define VAL(c) ( (c) < 9 ? (c)+1 : 10 ) /* val of rank */ + + +#ifndef TRUE +# define TRUE 1 +# define FALSE 0 +#endif + +typedef struct { + int rank; + int suit; + } CARD; + +typedef char BOOLEAN; + diff --git a/src/games/cribbage/extern.c b/src/games/cribbage/extern.c new file mode 100644 index 0000000..4914957 --- /dev/null +++ b/src/games/cribbage/extern.c @@ -0,0 +1,40 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +#ifndef lint +static char sccsid[] = "@(#)extern.c 5.1 (Berkeley) 5/30/85"; +#endif not lint + +# include +# include "deck.h" +# include "cribbage.h" + +bool explain = FALSE; /* player mistakes explained */ +bool iwon = FALSE; /* if comp won last game */ +bool quiet = FALSE; /* if suppress random mess */ +bool rflag = FALSE; /* if all cuts random */ + +char expl[128]; /* explanation */ + +int cgames = 0; /* number games comp won */ +int cscore = 0; /* comp score in this game */ +int gamecount = 0; /* number games played */ +int glimit = LGAME; /* game playe to glimit */ +int knownum = 0; /* number of cards we know */ +int pgames = 0; /* number games player won */ +int pscore = 0; /* player score in this game */ + +CARD chand[FULLHAND]; /* computer's hand */ +CARD crib[CINHAND]; /* the crib */ +CARD deck[CARDS]; /* a deck */ +CARD known[CARDS]; /* cards we have seen */ +CARD phand[FULLHAND]; /* player's hand */ +CARD turnover; /* the starter */ + +WINDOW *Compwin; /* computer's hand window */ +WINDOW *Msgwin; /* messages for the player */ +WINDOW *Playwin; /* player's hand window */ +WINDOW *Tablewin; /* table window */ diff --git a/src/games/cribbage/io.c b/src/games/cribbage/io.c new file mode 100644 index 0000000..4808d95 --- /dev/null +++ b/src/games/cribbage/io.c @@ -0,0 +1,575 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +#ifndef lint +static char sccsid[] = "@(#)io.c 5.1 (Berkeley) 5/30/85"; +#endif not lint + +# include +# include +# include +# include "deck.h" +# include "cribbage.h" +# include "cribcur.h" + +# define LINESIZE 128 + +# ifdef CTRL +# undef CTRL +# endif +# define CTRL(X) ('X' - 'A' + 1) + +# ifndef erasechar() +# define erasechar() _tty.sg_erase +# endif erasechar() + +# ifndef killchar() +# define killchar() _tty.sg_kill +# endif killchar() + +char linebuf[ LINESIZE ]; + +char *rankname[ RANKS ] = { "ACE", "TWO", "THREE", "FOUR", + "FIVE", "SIX", "SEVEN", "EIGHT", + "NINE", "TEN", "JACK", "QUEEN", + "KING" }; + +char *rankchar[ RANKS ] = { "A", "2", "3", "4", "5", "6", "7", + "8", "9", "T", "J", "Q", "K" }; + +char *suitname[ SUITS ] = { "SPADES", "HEARTS", "DIAMONDS", + "CLUBS" }; + +char *suitchar[ SUITS ] = { "S", "H", "D", "C" }; + + + +/* + * msgcard: + * Call msgcrd in one of two forms + */ +msgcard(c, brief) +CARD c; +BOOLEAN brief; +{ + if (brief) + return msgcrd(c, TRUE, (char *) NULL, TRUE); + else + return msgcrd(c, FALSE, " of ", FALSE); +} + + + +/* + * msgcrd: + * Print the value of a card in ascii + */ +msgcrd(c, brfrank, mid, brfsuit) +CARD c; +char *mid; +BOOLEAN brfrank, brfsuit; +{ + if (c.rank == EMPTY || c.suit == EMPTY) + return FALSE; + if (brfrank) + addmsg("%1.1s", rankchar[c.rank]); + else + addmsg(rankname[c.rank]); + if (mid != NULL) + addmsg(mid); + if (brfsuit) + addmsg("%1.1s", suitchar[c.suit]); + else + addmsg(suitname[c.suit]); + return TRUE; +} + +/* + * printcard: + * Print out a card. + */ +printcard(win, cardno, c, blank) +WINDOW *win; +int cardno; +CARD c; +BOOLEAN blank; +{ + prcard(win, cardno * 2, cardno, c, blank); +} + +/* + * prcard: + * Print out a card on the window at the specified location + */ +prcard(win, y, x, c, blank) +WINDOW *win; +int y, x; +CARD c; +BOOLEAN blank; +{ + if (c.rank == EMPTY) + return; + mvwaddstr(win, y + 0, x, "+-----+"); + mvwaddstr(win, y + 1, x, "| |"); + mvwaddstr(win, y + 2, x, "| |"); + mvwaddstr(win, y + 3, x, "| |"); + mvwaddstr(win, y + 4, x, "+-----+"); + if (!blank) { + mvwaddch(win, y + 1, x + 1, rankchar[c.rank][0]); + waddch(win, suitchar[c.suit][0]); + mvwaddch(win, y + 3, x + 4, rankchar[c.rank][0]); + waddch(win, suitchar[c.suit][0]); + } +} + +/* + * prhand: + * Print a hand of n cards + */ +prhand(h, n, win, blank) +CARD h[]; +int n; +WINDOW *win; +BOOLEAN blank; +{ + register int i; + + werase(win); + for (i = 0; i < n; i++) + printcard(win, i, *h++, blank); + wrefresh(win); +} + + + +/* + * infrom: + * reads a card, supposedly in hand, accepting unambigous brief + * input, returns the index of the card found... + */ +infrom(hand, n, prompt) +CARD hand[]; +int n; +char *prompt; +{ + register int i, j; + CARD crd; + + if (n < 1) { + printf("\nINFROM: %d = n < 1!!\n", n); + exit(74); + } + for (;;) { + msg(prompt); + if (incard(&crd)) { /* if card is full card */ + if (!isone(crd, hand, n)) + msg("That's not in your hand"); + else { + for (i = 0; i < n; i++) + if (hand[i].rank == crd.rank && + hand[i].suit == crd.suit) + break; + if (i >= n) { + printf("\nINFROM: isone or something messed up\n"); + exit(77); + } + return i; + } + } + else /* if not full card... */ + if (crd.rank != EMPTY) { + for (i = 0; i < n; i++) + if (hand[i].rank == crd.rank) + break; + if (i >= n) + msg("No such rank in your hand"); + else { + for (j = i + 1; j < n; j++) + if (hand[j].rank == crd.rank) + break; + if (j < n) + msg("Ambiguous rank"); + else + return i; + } + } + else + msg("Sorry, I missed that"); + } + /* NOTREACHED */ +} + + + +/* + * incard: + * Inputs a card in any format. It reads a line ending with a CR + * and then parses it. + */ +incard(crd) +CARD *crd; +{ + char *getline(); + register int i; + int rnk, sut; + char *line, *p, *p1; + BOOLEAN retval; + + retval = FALSE; + rnk = sut = EMPTY; + if (!(line = getline())) + goto gotit; + p = p1 = line; + while( *p1 != ' ' && *p1 != NULL ) ++p1; + *p1++ = NULL; + if( *p == NULL ) goto gotit; + /* IMPORTANT: no real card has 2 char first name */ + if( strlen(p) == 2 ) { /* check for short form */ + rnk = EMPTY; + for( i = 0; i < RANKS; i++ ) { + if( *p == *rankchar[i] ) { + rnk = i; + break; + } + } + if( rnk == EMPTY ) goto gotit; /* it's nothing... */ + ++p; /* advance to next char */ + sut = EMPTY; + for( i = 0; i < SUITS; i++ ) { + if( *p == *suitchar[i] ) { + sut = i; + break; + } + } + if( sut != EMPTY ) retval = TRUE; + goto gotit; + } + rnk = EMPTY; + for( i = 0; i < RANKS; i++ ) { + if( !strcmp( p, rankname[i] ) || !strcmp( p, rankchar[i] ) ) { + rnk = i; + break; + } + } + if( rnk == EMPTY ) goto gotit; + p = p1; + while( *p1 != ' ' && *p1 != NULL ) ++p1; + *p1++ = NULL; + if( *p == NULL ) goto gotit; + if( !strcmp( "OF", p ) ) { + p = p1; + while( *p1 != ' ' && *p1 != NULL ) ++p1; + *p1++ = NULL; + if( *p == NULL ) goto gotit; + } + sut = EMPTY; + for( i = 0; i < SUITS; i++ ) { + if( !strcmp( p, suitname[i] ) || !strcmp( p, suitchar[i] ) ) { + sut = i; + break; + } + } + if( sut != EMPTY ) retval = TRUE; +gotit: + (*crd).rank = rnk; + (*crd).suit = sut; + return( retval ); +} + + + +/* + * getuchar: + * Reads and converts to upper case + */ +getuchar() +{ + register int c; + + c = readchar(); + if (islower(c)) + c = toupper(c); + waddch(Msgwin, c); + return c; +} + +/* + * number: + * Reads in a decimal number and makes sure it is between "lo" and + * "hi" inclusive. + */ +number(lo, hi, prompt) +int lo, hi; +char *prompt; +{ + char *getline(); + register char *p; + register int sum; + + sum = 0; + for (;;) { + msg(prompt); + if(!(p = getline()) || *p == NULL) { + msg(quiet ? "Not a number" : "That doesn't look like a number"); + continue; + } + sum = 0; + + if (!isdigit(*p)) + sum = lo - 1; + else + while (isdigit(*p)) { + sum = 10 * sum + (*p - '0'); + ++p; + } + + if (*p != ' ' && *p != '\t' && *p != NULL) + sum = lo - 1; + if (sum >= lo && sum <= hi) + return sum; + if (sum == lo - 1) + msg("that doesn't look like a number, try again --> "); + else + msg("%d is not between %d and %d inclusive, try again --> ", + sum, lo, hi); + } +} + +/* + * msg: + * Display a message at the top of the screen. + */ +char Msgbuf[BUFSIZ] = { '\0' }; + +int Mpos = 0; + +static int Newpos = 0; + +/* VARARGS1 */ +msg(fmt, args) +char *fmt; +int args; +{ + doadd(fmt, &args); + endmsg(); +} + +/* + * addmsg: + * Add things to the current message + */ +/* VARARGS1 */ +addmsg(fmt, args) +char *fmt; +int args; +{ + doadd(fmt, &args); +} + +/* + * endmsg: + * Display a new msg. + */ + +int Lineno = 0; + +endmsg() +{ + register int len; + register char *mp, *omp; + static int lastline = 0; + + /* + * All messages should start with uppercase + */ + mvaddch(lastline + Y_MSG_START, SCORE_X, ' '); + if (islower(Msgbuf[0]) && Msgbuf[1] != ')') + Msgbuf[0] = toupper(Msgbuf[0]); + mp = Msgbuf; + len = strlen(mp); + if (len / MSG_X + Lineno >= MSG_Y) { + while (Lineno < MSG_Y) { + wmove(Msgwin, Lineno++, 0); + wclrtoeol(Msgwin); + } + Lineno = 0; + } + mvaddch(Lineno + Y_MSG_START, SCORE_X, '*'); + lastline = Lineno; + do { + mvwaddstr(Msgwin, Lineno, 0, mp); + if ((len = strlen(mp)) > MSG_X) { + omp = mp; + for (mp = &mp[MSG_X-1]; *mp != ' '; mp--) + continue; + while (*mp == ' ') + mp--; + mp++; + wmove(Msgwin, Lineno, mp - omp); + wclrtoeol(Msgwin); + } + if (++Lineno >= MSG_Y) + Lineno = 0; + } while (len > MSG_X); + wclrtoeol(Msgwin); + Mpos = len; + Newpos = 0; + wrefresh(Msgwin); + refresh(); + wrefresh(Msgwin); +} + +/* + * doadd: + * Perform an add onto the message buffer + */ +doadd(fmt, args) +char *fmt; +int *args; +{ + static FILE junk; + + /* + * Do the printf into Msgbuf + */ + junk._flag = _IOWRT + _IOSTRG; + junk._ptr = &Msgbuf[Newpos]; + junk._cnt = 32767; + _doprnt(fmt, args, &junk); + putc('\0', &junk); + Newpos = strlen(Msgbuf); +} + +/* + * do_wait: + * Wait for the user to type ' ' before doing anything else + */ +do_wait() +{ + register int line; + static char prompt[] = { '-', '-', 'M', 'o', 'r', 'e', '-', '-', '\0' }; + + if (Mpos + sizeof prompt < MSG_X) + wmove(Msgwin, Lineno > 0 ? Lineno - 1 : MSG_Y - 1, Mpos); + else { + mvwaddch(Msgwin, Lineno, 0, ' '); + wclrtoeol(Msgwin); + if (++Lineno >= MSG_Y) + Lineno = 0; + } + waddstr(Msgwin, prompt); + wrefresh(Msgwin); + wait_for(' '); +} + +/* + * wait_for + * Sit around until the guy types the right key + */ +wait_for(ch) +register char ch; +{ + register char c; + + if (ch == '\n') + while ((c = readchar()) != '\n') + continue; + else + while (readchar() != ch) + continue; +} + +/* + * readchar: + * Reads and returns a character, checking for gross input errors + */ +readchar() +{ + register int cnt, y, x; + auto char c; + +over: + cnt = 0; + while (read(0, &c, 1) <= 0) + if (cnt++ > 100) /* if we are getting infinite EOFs */ + bye(); /* quit the game */ + if (c == CTRL(L)) { + wrefresh(curscr); + goto over; + } + if (c == '\r') + return '\n'; + else + return c; +} + +/* + * getline: + * Reads the next line up to '\n' or EOF. Multiple spaces are + * compressed to one space; a space is inserted before a ',' + */ +char * +getline() +{ + register char *sp; + register int c, oy, ox; + register WINDOW *oscr; + + oscr = stdscr; + stdscr = Msgwin; + getyx(stdscr, oy, ox); + refresh(); + /* + * loop reading in the string, and put it in a temporary buffer + */ + for (sp = linebuf; (c = readchar()) != '\n'; clrtoeol(), refresh()) { + if (c == -1) + continue; + else if (c == erasechar()) { /* process erase character */ + if (sp > linebuf) { + register int i; + + sp--; + for (i = strlen(unctrl(*sp)); i; i--) + addch('\b'); + } + continue; + } + else if (c == killchar()) { /* process kill character */ + sp = linebuf; + move(oy, ox); + continue; + } + else if (sp == linebuf && c == ' ') + continue; + if (sp >= &linebuf[LINESIZE-1] || !(isprint(c) || c == ' ')) + putchar(CTRL(G)); + else { + if (islower(c)) + c = toupper(c); + *sp++ = c; + addstr(unctrl(c)); + Mpos++; + } + } + *sp = '\0'; + stdscr = oscr; + return linebuf; +} + +/* + * bye: + * Leave the program, cleaning things up as we go. + */ +bye() +{ + signal(SIGINT, SIG_IGN); + mvcur(0, COLS - 1, LINES - 1, 0); + fflush(stdout); + endwin(); + putchar('\n'); + exit(1); +} diff --git a/src/games/cribbage/macro b/src/games/cribbage/macro new file mode 100644 index 0000000..7e29a7a --- /dev/null +++ b/src/games/cribbage/macro @@ -0,0 +1,126 @@ +.\" Copyright (c) 1980 Regents of the University of California. +.\" All rights reserved. The Berkeley software License Agreement +.\" specifies the terms and conditions for redistribution. +.\" +.\" @(#)macro 5.1 (Berkeley) 5/30/85 +.\" +.nr TX 2 \" default line space for text is 2 +.nr PG 8 \" default paragraph indentation in PG is 8 +.nr QI 8 \" default indentation for quotes is 8 +.nr IP 4 \" default indentation for indented paragraph is 4 +.de TX \" define text settings +.ls \\n(TX +.fi +.. +.de NT \" define non-text setings +.nf +.ls 1 +.. +.de PG \" define paragraph starter +.sp +.ti +\\n(PG +.. +.de HD \" define page header +'sp 1i +.. +.de FO \" define page footer +.if \\n%>1 \{\ +'sp 2 +.tl ""- % -"" \} +'bp +.. +.wh 0 HD \" trap invocation of header +.wh -1i FO \" trap invocation of footer +.de pH \" define page header +.ce +.ul +\\$1 +.sp 1 +.. +.de PF \" define Page header for first page -- no .bp +.ce +.ul +\\$1 +.sp 1 +.. +.de PH \" define Page header +.ce +.ul +\\$1 +.sp 1 +.. +.de HP \" define paragraph header +.sp 2 +.ne 4 +.ul +\\$1 +.PG +.. +.de TP \" define title page +.ls 1 +   +.sp 3.5i +.ce +.ul +\\$1 +.sp +3i +.ti +50 +\\$2 +.br +.ti +50 +\\$3 +.br +.ti +50 +\\n(mo / \\n(dy / \\n(yr +.nr % 0 +.ls +.. +.de KS +.br +.di KB +.. +.de KE +.br +.di +.ne \\n(dnu +.KB +.. +.de QI \" define indented quote macro +.sp +.in +\\n(QI +.ll -\\n(QI +.ls 1 +.. +.de EQ \" define end quote macro +.ls +.sp +.ll +\\n(QI +.in -\\n(QI +.. +.de IP \" define indented paragraph macro +.in +\\n(IP +.ll -\\n(IP +.PG +.. +.de EP \" define end indented paragraph macro +.ll +\\n(IP +.in -\\n(IP +.. +.de IH \" define indented paragraph header +.in +\\n(IP +.ll -\\n(IP +.sp 2 +.ne 4 +.ul +\\$1 +.PG +.. +.de IN +.in +8 +.br +.ti -4 +\\$1 +.. +.de NE +.in -8 +.. diff --git a/src/games/cribbage/score.c b/src/games/cribbage/score.c new file mode 100644 index 0000000..ff8c942 --- /dev/null +++ b/src/games/cribbage/score.c @@ -0,0 +1,337 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +#ifndef lint +static char sccsid[] = "@(#)score.c 5.1 (Berkeley) 5/30/85"; +#endif not lint + +#include +#include "deck.h" +#include "cribbage.h" + + +/* + * the following arrays give the sum of the scores of the (50 2)*48 = 58800 + * hands obtainable for the crib given the two cards whose ranks index the + * array. the two arrays are for the case where the suits are equal and + * not equal respectively + */ + +long crbescr[ 169 ] = { + -10000, 271827, 278883, 332319, 347769, 261129, 250653, 253203, 248259, + 243435, 256275, 237435, 231051, -10000, -10000, 412815, 295707, 349497, + 267519, 262521, 259695, 254019, 250047, 262887, 244047, 237663, -10000, + -10000, -10000, 333987, 388629, 262017, 266787, 262971, 252729, 254475, + 267315, 248475, 242091, -10000, -10000, -10000, -10000, 422097, 302787, + 256437, 263751, 257883, 254271, 267111, 248271, 241887, -10000, -10000, + -10000, -10000, -10000, 427677, 387837, 349173, 347985, 423861, 436701, + 417861, 411477, -10000, -10000, -10000, -10000, -10000, -10000, 336387, + 298851, 338667, 236487, 249327, 230487, 224103, -10000, -10000, -10000, + -10000, -10000, -10000, -10000, 408483, 266691, 229803, 246195, 227355, + 220971, -10000, -10000, -10000, -10000, -10000, -10000, -10000, -10000, + 300675, 263787, 241695, 226407, 220023, -10000, -10000, -10000, -10000, + -10000, -10000, -10000, -10000, -10000, 295635, 273543, 219771, 216939, + -10000, -10000, -10000, -10000, -10000, -10000, -10000, -10000, -10000, + -10000, 306519, 252747, 211431, -10000, -10000, -10000, -10000, -10000, + -10000, -10000, -10000, -10000, -10000, -10000, 304287, 262971, -10000, + -10000, -10000, -10000, -10000, -10000, -10000, -10000, -10000, -10000, + -10000, -10000, 244131, -10000, -10000, -10000, -10000, -10000, -10000, + -10000, -10000, -10000, -10000, -10000, -10000, -10000 }; + +long crbnescr[ 169 ] = { + 325272, 260772, 267828, 321264, 336714, 250074, 239598, 242148, 237204, + 232380, 246348, 226380, 219996, -10000, 342528, 401760, 284652, 338442, + 256464, 251466, 248640, 242964, 238992, 252960, 232992, 226608, -10000, + -10000, 362280, 322932, 377574, 250962, 255732, 251916, 241674, 243420, + 257388, 237420, 231036, -10000, -10000, -10000, 360768, 411042, 291732, + 245382, 252696, 246828, 243216, 257184, 237216, 230832, -10000, -10000, + -10000, -10000, 528768, 416622, 376782, 338118, 336930, 412806, 426774, + 406806, 400422, -10000, -10000, -10000, -10000, -10000, 369864, 325332, + 287796, 327612, 225432, 239400, 219432, 213048, -10000, -10000, -10000, + -10000, -10000, -10000, 359160, 397428, 255636, 218748, 236268, 216300, + 209916, -10000, -10000, -10000, -10000, -10000, -10000, -10000, 331320, + 289620, 252732, 231768, 215352, 208968, -10000, -10000, -10000, -10000, + -10000, -10000, -10000, -10000, 325152, 284580, 263616, 208716, 205884, + -10000, -10000, -10000, -10000, -10000, -10000, -10000, -10000, -10000, + 321240, 296592, 241692, 200376, -10000, -10000, -10000, -10000, -10000, + -10000, -10000, -10000, -10000, -10000, 348600, 294360, 253044, -10000, + -10000, -10000, -10000, -10000, -10000, -10000, -10000, -10000, -10000, + -10000, 308664, 233076, -10000, -10000, -10000, -10000, -10000, -10000, + -10000, -10000, -10000, -10000, -10000, -10000, 295896 }; + + +static int ichoose2[ 5 ] = { 0, 0, 2, 6, 12 }; +static int pairpoints, runpoints; /* globals from pairuns */ + + +/* + * scorehand: + * Score the given hand of n cards and the starter card. + * n must be <= 4 + */ +scorehand(hand, starter, n, crb, do_explain) +register CARD hand[]; +CARD starter; +int n; +BOOLEAN crb; /* true if scoring crib */ +BOOLEAN do_explain; /* true if must explain this hand */ +{ + CARD h[(CINHAND + 1)]; + register int i, k; + register int score; + register BOOLEAN flag; + char buf[32]; + + expl[0] = NULL; /* initialize explanation */ + score = 0; + flag = TRUE; + k = hand[0].suit; + for (i = 0; i < n; i++) { /* check for flush */ + flag = (flag && (hand[i].suit == k)); + if (hand[i].rank == JACK) /* check for his nibs */ + if (hand[i].suit == starter.suit) { + score++; + if (do_explain) + strcat(expl, "His Nobs"); + } + h[i] = hand[i]; + } + + if (flag && n >= CINHAND) { + if (do_explain && expl[0] != NULL) + strcat(expl, ", "); + if (starter.suit == k) { + score += 5; + if (do_explain) + strcat(expl, "Five-flush"); + } + else if (!crb) { + score += 4; + if (do_explain && expl[0] != NULL) + strcat(expl, ", Four-flush"); + else + strcpy(expl, "Four-flush"); + } + } + + if (do_explain && expl[0] != NULL) + strcat(expl, ", "); + h[n] = starter; + sorthand(h, n + 1); /* sort by rank */ + i = 2 * fifteens(h, n + 1); + score += i; + if (do_explain) + if (i > 0) { + sprintf(buf, "%d points in fifteens", i); + strcat(expl, buf); + } + else + strcat(expl, "No fifteens"); + i = pairuns(h, n + 1); + score += i; + if (do_explain) + if (i > 0) { + sprintf(buf, ", %d points in pairs, %d in runs", pairpoints, + runpoints); + strcat(expl, buf); + } + else + strcat(expl, ", No pairs/runs"); + return score; +} + +/* + * fifteens: + * Return number of fifteens in hand of n cards + */ +fifteens(hand, n) +register CARD hand[]; +int n; +{ + register int *sp, *np; + register int i; + register CARD *endp; + static int sums[15], nsums[15]; + + np = nsums; + sp = sums; + i = 16; + while (--i) { + *np++ = 0; + *sp++ = 0; + } + for (endp = &hand[n]; hand < endp; hand++) { + i = hand->rank + 1; + if (i > 10) + i = 10; + np = &nsums[i]; + np[-1]++; /* one way to make this */ + sp = sums; + while (i < 15) { + *np++ += *sp++; + i++; + } + sp = sums; + np = nsums; + i = 16; + while (--i) + *sp++ = *np++; + } + return sums[14]; +} + + + +/* + * pairuns returns the number of points in the n card sorted hand + * due to pairs and runs + * this routine only works if n is strictly less than 6 + * sets the globals pairpoints and runpoints appropriately + */ + +pairuns( h, n ) + + CARD h[]; + int n; +{ + register int i; + int runlength, runmult, lastmult, curmult; + int mult1, mult2, pair1, pair2; + BOOLEAN run; + + run = TRUE; + runlength = 1; + mult1 = 1; + pair1 = -1; + mult2 = 1; + pair2 = -1; + curmult = runmult = 1; + for( i = 1; i < n; i++ ) { + lastmult = curmult; + if( h[i].rank == h[i - 1].rank ) { + if( pair1 < 0 ) { + pair1 = h[i].rank; + mult1 = curmult = 2; + } + else { + if( h[i].rank == pair1 ) { + curmult = ++mult1; + } + else { + if( pair2 < 0 ) { + pair2 = h[i].rank; + mult2 = curmult = 2; + } + else { + curmult = ++mult2; + } + } + } + if( i == (n - 1) && run ) { + runmult *= curmult; + } + } + else { + curmult = 1; + if( h[i].rank == h[i - 1].rank + 1 ) { + if( run ) { + ++runlength; + } + else { + if( runlength < 3 ) { /* only if old short */ + run = TRUE; + runlength = 2; + runmult = 1; + } + } + runmult *= lastmult; + } + else { + if( run ) runmult *= lastmult; /* if just ended */ + run = FALSE; + } + } + } + pairpoints = ichoose2[ mult1 ] + ichoose2[ mult2 ]; + runpoints = ( runlength >= 3 ? runlength*runmult : 0 ); + return( pairpoints + runpoints ); +} + + + +/* + * pegscore tells how many points crd would get if played after + * the n cards in tbl during pegging + */ + +pegscore( crd, tbl, n, sum ) + + CARD crd, tbl[]; + int n; + int sum; +{ + BOOLEAN got[ RANKS ]; + register int i, j, scr; + int k, lo, hi; + + sum += VAL( crd.rank ); + if( sum > 31 ) return( -1 ); + if( sum == 31 || sum == 15 ) scr = 2; + else scr = 0; + if( !n ) return( scr ); + j = 1; + while( ( crd.rank == tbl[n - j].rank ) && ( n - j >= 0 ) ) ++j; + if( j > 1 ) return( scr + ichoose2[j] ); + if( n < 2 ) return( scr ); + lo = hi = crd.rank; + for( i = 0; i < RANKS; i++ ) got[i] = FALSE; + got[ crd.rank ] = TRUE; + k = -1; + for( i = n - 1; i >= 0; --i ) { + if( got[ tbl[i].rank ] ) break; + got[ tbl[i].rank ] = TRUE; + if( tbl[i].rank < lo ) lo = tbl[i].rank; + if( tbl[i].rank > hi ) hi = tbl[i].rank; + for( j = lo; j <= hi; j++ ) if( !got[j] ) break; + if( j > hi ) k = hi - lo + 1; + } + if( k >= 3 ) return( scr + k ); + else return( scr ); +} + + + +/* + * adjust takes a two card hand that will be put in the crib + * and returns an adjusted normalized score for the number of + * points such a crib will get. + */ + +adjust( cb, tnv ) + + CARD cb[], tnv; +{ + int i, c0, c1; + long scr; + + c0 = cb[0].rank; + c1 = cb[1].rank; + if( c0 > c1 ) { + i = c0; + c0 = c1; + c1 = i; + } + if( cb[0].suit != cb[1].suit ) scr = crbnescr[ RANKS*c0 + c1 ]; + else scr = crbescr[ RANKS*c0 + c1 ]; + if( scr <= 0 ) { + printf( "\nADJUST: internal error %d %d\n", c0, c1 ); + exit( 93 ); + } + return( (scr + 29400)/58800 ); +} + + + diff --git a/src/games/cribbage/support.c b/src/games/cribbage/support.c new file mode 100644 index 0000000..867ad01 --- /dev/null +++ b/src/games/cribbage/support.c @@ -0,0 +1,330 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +#ifndef lint +static char sccsid[] = "@(#)support.c 5.1 (Berkeley) 5/30/85"; +#endif not lint + +#include +#include "deck.h" +#include "cribbage.h" +#include "cribcur.h" + + +#define NTV 10 /* number scores to test */ + +/* score to test reachability of, and order to test them in */ +int tv[ NTV ] = { 8, 7, 9, 6, 11, 12, 13, 14, 10, 5 }; + + +/* + * computer chooses what to play in pegging... + * only called if no playable card will score points + */ + +cchose( h, n, s ) + + CARD h[]; + int n; + int s; +{ + register int i, j, l; + + if( n <= 1 ) return( 0 ); + if( s < 4 ) { /* try for good value */ + if( ( j = anysumto(h, n, s, 4) ) >= 0 ) return( j ); + if( ( j = anysumto(h, n, s, 3) ) >= 0 && s == 0 ) + return( j ); + } + if( s > 0 && s < 20 ) { + for( i = 1; i <= 10; i++ ) { /* try for retaliation to 31 */ + if( ( j = anysumto(h, n, s, 21-i) ) >= 0 ) { + if( ( l = numofval(h, n, i) ) > 0 ) { + if( l > 1 || VAL( h[j].rank ) != i ) return( j ); + } + } + } + } + if( s < 15 ) { + for( i = 0; i < NTV; i++ ) { /* for retaliation after 15 */ + if( ( j = anysumto(h, n, s, tv[i]) ) >= 0 ) { + if( ( l = numofval(h, n, 15-tv[i]) ) > 0 ) { + if( l > 1 || VAL( h[j].rank ) != 15-tv[i] ) return( j ); + } + } + } + } + j = -1; + for( i = n - 1; i >= 0; --i ) { /* remember: h is sorted */ + l = s + VAL( h[i].rank ); + if( l > 31 ) continue; + if( l != 5 && l != 10 && l != 21 ) { + j = i; + break; + } + } + if( j >= 0 ) return( j ); + for( i = n - 1; i >= 0; --i ) { + l = s + VAL( h[i].rank ); + if( l > 31 ) continue; + if( j < 0 ) j = i; + if( l != 5 && l != 21 ) { + j = i; + break; + } + } + return( j ); +} + + + +/* + * plyrhand: + * Evaluate and score a player hand or crib + */ +plyrhand(hand, s) +CARD hand[]; +char *s; +{ + register int i, j; + register BOOLEAN win; + static char prompt[BUFSIZ]; + + prhand(hand, CINHAND, Playwin, FALSE); + sprintf(prompt, "Your %s scores ", s); + i = scorehand(hand, turnover, CINHAND, strcmp(s, "crib") == 0, explain); + if ((j = number(0, 29, prompt)) == 19) + j = 0; + if (i != j) { + if (i < j) { + win = chkscr(&pscore, i); + msg("It's really only %d points; I get %d", i, 2); + if (!win) + win = chkscr(&cscore, 2); + } + else { + win = chkscr(&pscore, j); + msg("You should have taken %d, not %d!", i, j); + } + if (explain) + msg("Explanation: %s", expl); + do_wait(); + } + else + win = chkscr(&pscore, i); + return win; +} + +/* + * comphand: + * Handle scoring and displaying the computers hand + */ +comphand(h, s) +CARD h[]; +char *s; +{ + register int j; + + j = scorehand(h, turnover, CINHAND, strcmp(s, "crib") == 0, FALSE); + prhand(h, CINHAND, Compwin, FALSE); + msg("My %s scores %d", s, (j == 0 ? 19 : j)); + return chkscr(&cscore, j); +} + +/* + * chkscr: + * Add inc to scr and test for > glimit, printing on the scoring + * board while we're at it. + */ + +int Lastscore[2] = {-1, -1}; + +chkscr(scr, inc) +int *scr, inc; +{ + BOOLEAN myturn; + + myturn = (scr == &cscore); + if (inc != 0) { + prpeg(Lastscore[myturn], '.', myturn); + Lastscore[myturn] = *scr; + *scr += inc; + prpeg(*scr, PEG, myturn); + refresh(); + } + return (*scr >= glimit); +} + +/* + * prpeg: + * Put out the peg character on the score board and put the + * score up on the board. + */ +prpeg(score, peg, myturn) +register int score; +char peg; +BOOLEAN myturn; +{ + register int y, x; + + if (!myturn) + y = SCORE_Y + 2; + else + y = SCORE_Y + 5; + + if (score <= 0 || score >= glimit) { + if (peg == '.') + peg = ' '; + if (score == 0) + x = SCORE_X + 2; + else { + x = SCORE_X + 2; + y++; + } + } + else { + x = (score - 1) % 30; + if (score > 90 || (score > 30 && score <= 60)) { + y++; + x = 29 - x; + } + x += x / 5; + x += SCORE_X + 3; + } + mvaddch(y, x, peg); + mvprintw(SCORE_Y + (myturn ? 7 : 1), SCORE_X + 10, "%3d", score); +} + +/* + * cdiscard -- the computer figures out what is the best discard for + * the crib and puts the best two cards at the end + */ + +cdiscard( mycrib ) + + BOOLEAN mycrib; +{ + CARD d[ CARDS ], h[ FULLHAND ], cb[ 2 ]; + register int i, j, k; + int nc, ns; + long sums[ 15 ]; + static int undo1[15] = {0,0,0,0,0,1,1,1,1,2,2,2,3,3,4}; + static int undo2[15] = {1,2,3,4,5,2,3,4,5,3,4,5,4,5,5}; + + makedeck( d ); + nc = CARDS; + for( i = 0; i < knownum; i++ ) { /* get all other cards */ + remove( known[i], d, nc-- ); + } + for( i = 0; i < 15; i++ ) sums[i] = 0L; + ns = 0; + for( i = 0; i < (FULLHAND - 1); i++ ) { + cb[0] = chand[i]; + for( j = i + 1; j < FULLHAND; j++ ) { + cb[1] = chand[j]; + for( k = 0; k < FULLHAND; k++ ) h[k] = chand[k]; + remove( chand[i], h, FULLHAND ); + remove( chand[j], h, FULLHAND - 1 ); + for( k = 0; k < nc; k++ ) { + sums[ns] += scorehand( h, d[k], CINHAND, TRUE, FALSE ); + if( mycrib ) sums[ns] += adjust( cb, d[k] ); + else sums[ns] -= adjust( cb, d[k] ); + } + ++ns; + } + } + j = 0; + for( i = 1; i < 15; i++ ) if( sums[i] > sums[j] ) j = i; + for( k = 0; k < FULLHAND; k++ ) h[k] = chand[k]; + remove( h[ undo1[j] ], chand, FULLHAND ); + remove( h[ undo2[j] ], chand, FULLHAND - 1 ); + chand[4] = h[ undo1[j] ]; + chand[5] = h[ undo2[j] ]; +} + + + +/* + * returns true if some card in hand can be played without exceeding 31 + */ + +anymove( hand, n, sum ) + + CARD hand[]; + int n; + int sum; +{ + register int i, j; + + if( n < 1 ) return( FALSE ); + j = hand[0].rank; + for( i = 1; i < n; i++ ) { + if( hand[i].rank < j ) j = hand[i].rank; + } + return( sum + VAL( j ) <= 31 ); +} + + + +/* + * anysumto returns the index (0 <= i < n) of the card in hand that brings + * the s up to t, or -1 if there is none + */ + +anysumto( hand, n, s, t ) + + CARD hand[]; + int n; + int s, t; +{ + register int i; + + for( i = 0; i < n; i++ ) { + if( s + VAL( hand[i].rank ) == t ) return( i ); + } + return( -1 ); +} + + + + +/* + * return the number of cards in h having the given rank value + */ + +numofval( h, n, v ) + + CARD h[]; + int n; + int v; +{ + register int i, j; + + j = 0; + for( i = 0; i < n; i++ ) { + if( VAL( h[i].rank ) == v ) ++j; + } + return( j ); +} + + + +/* + * makeknown remembers all n cards in h for future recall + */ + +makeknown( h, n ) + + CARD h[]; + int n; +{ + register int i; + + for( i = 0; i < n; i++ ) { + known[ knownum++ ] = h[i]; + } +} + diff --git a/src/games/cribbage/test.c b/src/games/cribbage/test.c new file mode 100644 index 0000000..44f2f61 --- /dev/null +++ b/src/games/cribbage/test.c @@ -0,0 +1,131 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +#ifndef lint +char copyright[] = +"@(#) Copyright (c) 1980 Regents of the University of California.\n\ + All rights reserved.\n"; +#endif not lint + +#ifndef lint +static char sccsid[] = "@(#)test.c 5.1 (Berkeley) 5/30/85"; +#endif not lint + +#include +#include "deck.h" + + +CARD known[ CARDS ]; /* a deck */ +CARD deck[ CARDS ]; /* a deck */ +CARD hand[ 4 ]; /* a hand */ + +int knownum; + + +main( argc, argv ) + + int argc; + char *argv[]; +{ + register int k, l, m; + int i, j, is, n, sum, sum2; + CARD ic, jc; + CARD d[ CARDS]; + extern char expl[]; + + printf( "Assuming cards are same suit\n" ); + if( argc == 2 ) { + is = atoi( *++argv ); + printf( "Starting at i = %d\n", is ); + } + makedeck( deck ); +# if 0 + for( i = is; i < RANKS; i++ ) { /* first card */ + ic.rank = i; + ic.suit = 0; + hand[0] = ic; + for( j = 0; j <= i; j++ ) { + printf( "%d %d: sum = %d\n", i, j, -10000000 ); + printf( "%d %d: sum2 = %d\n", i, j, -10000000 ); + } + for( j = i + 1; j < RANKS; j++ ) { /* second card */ + jc.rank = j; + jc.suit = 0; + hand[1] = jc; + for( k = 0; k < CARDS; k++ ) d[k] = deck[k]; + n = CARDS; + remove( ic, d, n-- ); + remove( jc, d, n-- ); + sum = 0; + sum2 = 0; + for( k = 0; k < n - 1; k++ ) { /* 3rd card */ + hand[2] = d[k]; + for( l = k + 1; l < n; l++ ) { /* 4th card */ + hand[3] = d[l]; + for( m = 0; m < n; m++ ) { /* cut card */ + if( m != l && m != k ) + sum += scorehand(hand, d[m], 4, FALSE, FALSE); + sum2 += scorehand(hand, d[m], 4, TRUE, FALSE); + } + } + } + printf( "%d %d: sum = %d\n", i, j, sum ); + printf( "%d %d: sum2 = %d\n", i, j, sum2 ); + fflush( stdout ); + } + } + printf( "\nthe hand scores %d\n", i ); +# else + hand[0].rank = 0; + hand[1].rank = 1; + hand[2].rank = 2; + hand[3].rank = 3; + hand[4].rank = 4; + hand[0].suit = 0; + hand[1].suit = 0; + hand[2].suit = 0; + hand[3].suit = 0; + hand[4].suit = 0; + printf("scorehand of hand = %d\n", scorehand(hand, hand[4], CINHAND, FALSE, TRUE)); + printf("\t%s\n", expl); + hand[0].rank = 0; + hand[1].rank = 1; + hand[2].rank = 2; + hand[3].rank = 3; + hand[4].rank = 4; + hand[0].suit = 0; + hand[1].suit = 0; + hand[2].suit = 0; + hand[3].suit = 0; + hand[4].suit = 0; + printf("scorehand of crib = %d\n", scorehand(hand, hand[4], CINHAND, TRUE, TRUE)); + printf("\t%s\n", expl); + hand[0].rank = 0; + hand[1].rank = 1; + hand[2].rank = 2; + hand[3].rank = 3; + hand[4].rank = 4; + hand[0].suit = 0; + hand[1].suit = 0; + hand[2].suit = 0; + hand[3].suit = 0; + hand[4].suit = 1; + printf("scorehand of hand = %d\n", scorehand(hand, hand[4], CINHAND, FALSE, TRUE)); + printf("\t%s\n", expl); + hand[0].rank = 0; + hand[1].rank = 1; + hand[2].rank = 2; + hand[3].rank = 3; + hand[4].rank = 4; + hand[0].suit = 0; + hand[1].suit = 0; + hand[2].suit = 0; + hand[3].suit = 0; + hand[4].suit = 1; + printf("scorehand of crib = %d\n", scorehand(hand, hand[4], CINHAND, TRUE, TRUE)); + printf("\t%s\n", expl); +# endif +} diff --git a/src/games/factor.c b/src/games/factor.c new file mode 100644 index 0000000..8cc5156 --- /dev/null +++ b/src/games/factor.c @@ -0,0 +1,100 @@ +/* + * factor [ number ] + * + * Written to replace factor.s in Bell V7 distribution + */ +#ifdef CROSS +# include +#else +# include +#endif + +/* + * Return smallest prime factor of integer N > 0 + * + * Algorithm from E.W. Dijkstra (A Discipline of Programming, Chapter 20) + */ +int factor(N) + int N; +{ + int p; + register int f; + static struct { + int hib; + int val[24]; + } ar; + + { register int x, y; + + ar.hib = -1; + x = N; y = 2; + while (x != 0) { + ar.val[++ar.hib] = x % y; + x /= y; + y += 1; + } + } + + f = 2; + + while (ar.val[0] != 0 && ar.hib > 1) { + register int i; + + f += 1; + i = 0; + while (i != ar.hib) { + register int j; + + j = i + 1; + ar.val[i] -= j * ar.val[j]; + while (ar.val[i] < 0) { + ar.val[i] += f + i; + ar.val[j] -= 1; + } + i = j; + } + while (ar.val[ar.hib] == 0) + ar.hib--; + } + + if (ar.val[0] == 0) + p = f; + else + p = N; + + return(p); +} + +/* + * Print all prime factors of integer n > 0, smallest first, one to a line + */ +void printfactors(n) + register int n; +{ + register int prime; + + if (n == 1) + printf("\t1\n"); + else while (n != 1) { + prime = factor(n); + printf("\t%d\n", prime); + n /= prime; + } +} + +int main(argc, argv) + char *argv[]; +{ + int n; + + if (argc >= 2) { + sscanf(argv[1], "%d", &n); + if (n > 0) + printfactors(n); + } else { + while (scanf("%d", &n) == 1) + if (n > 0) + printfactors(n); + } + return 0; +} diff --git a/src/games/fish.6 b/src/games/fish.6 new file mode 100644 index 0000000..fc1142f --- /dev/null +++ b/src/games/fish.6 @@ -0,0 +1,35 @@ +.\" Copyright (c) 1980 Regents of the University of California. +.\" All rights reserved. The Berkeley software License Agreement +.\" specifies the terms and conditions for redistribution. +.\" +.\" @(#)fish.6 6.1 (Berkeley) 5/20/85 +.\" +.TH FISH 6 "May 20, 1985" +.UC 4 +.SH NAME +fish \- play ``Go Fish'' +.SH SYNOPSIS +.B /usr/games/fish +.SH DESCRIPTION +.I Fish +plays the game of \*(lqGo Fish\*(rq, +a childrens' card game. The Object is to +accumulate `books' of 4 cards with the same face value. The +players alternate turns; each turn begins with one player +selecting a card from his hand, and asking the other player for +all cards of that face value. If the other player has one or +more cards of that face value in his hand, he gives them to the +first player, and the first player makes another request. +Eventually, the first player asks for a card which is not in +the second player's hand: he replies `GO FISH!' The first +player then draws a card from the `pool' of undealt cards. If +this is the card he had last requested, he draws again. When a +book is made, either through drawing or requesting, the cards +are laid down and no further action takes place with that face +value. +.PP +To play the computer, simply make guesses by typing a, +2, 3, 4, 5, 6, 7, 8, 9, 10, j, q, or k when asked. Hitting +return gives you information about the size of my hand and the +pool, and tells you about my books. Saying `p' as a first +guess puts you into `pro' level; The default is pretty dumb. diff --git a/src/games/fish.c b/src/games/fish.c new file mode 100644 index 0000000..7ca9b4c --- /dev/null +++ b/src/games/fish.c @@ -0,0 +1,559 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#ifdef CROSS +# include +#else +# include +#endif +#include +#include + +/* Through, `my' refers to the program, `your' to the player */ + +#define CTYPE 13 +#define CTSIZ (CTYPE+1) +#define DECK 52 +#define NOMORE 0 +#define DOUBTIT (-1); + +typedef char HAND[CTSIZ]; + +/* data structures */ + +short debug; + +HAND myhand; +HAND yourhand; +char deck[DECK]; +short nextcd; +int proflag; + +/* the program strategy */ + +int try[100]; +int ntry; +char haveguessed[CTSIZ]; +char hehas[CTSIZ]; + +/* utility and output programs */ + +void error(s) + char *s; +{ + fprintf(stderr, "error: %s\n", s); + exit(1); +} + +int choose(a, n) + char a[]; +{ + /* pick and return one at random from the n choices in a */ + /* The last one is moved to replace the one chosen */ + register int j, t; + + if (n <= 0) + error("null choice"); + + j = rand() % n; + t = a[j]; + a[j] = a[n-1]; + return(t); +} + +void shuffle() +{ + /* shuffle the deck, and reset nextcd */ + /* uses the random number generator `rand' in the C library */ + /* assumes that `srand' has already been called */ + + register int i; + + for (i=0; i0; --i) { /* select the next card at random */ + deck[i-1] = choose(deck, i); + } + + nextcd = 0; +} + +int draw() +{ + if (nextcd >= DECK) + return NOMORE; + return deck[nextcd++]; +} + +int empty(h) + HAND h; +{ + register int i; + + for (i=1; i<=CTYPE; ++i) { + if (h[i] != 0 && h[i] != 4) + return(0); + } + return(i); +} + +int mark(hand, cd) + HAND hand; +{ + if (cd != NOMORE) { + ++hand[cd]; + if (hand[cd] > 4) { + error("mark overflow"); + } + } + return(cd); +} + +void deal(hand, n) + HAND hand; +{ + while(n--) { + if (mark(hand, draw()) == NOMORE) + error("deck exhausted"); + } +} + +char *cname[] = { + "NOMORE!!!", + "A", + "2", + "3", + "4", + "5", + "6", + "7", + "8", + "9", + "10", + "J", + "Q", + "K", +}; + +void stats() +{ + register int i, ct, b; + + if (proflag) + printf("Pro level\n"); + b = ct = 0; + + for (i=1; i<=CTYPE; ++i) { + if (myhand[i] == 4) + ++b; + else + ct += myhand[i]; + } + + if (b) { + printf("My books: "); + for (i=1; i<=CTYPE; ++i) { + if (myhand[i] == 4) + printf("%s ", cname[i]); + } + printf("\n"); + } + + printf("%d cards in my hand, %d in the pool\n", ct, DECK-nextcd); + printf("You ask me for: "); +} + +void phand(h) + HAND h; +{ + register int i, j; + + j = 0; + + for (i = 1; i<= CTYPE; ++i) { + if (h[i] == 4) { + ++j; + continue; + } + if (h[i]) { + register int k = h[i]; + + while(k--) printf("%s ", cname[i]); + } + } + + if (j) { + printf("+ Books of "); + for (i=1; i<=CTYPE; ++i) { + if (h[i] == 4) + printf("%s ", cname[i]); + } + } + + printf("\n"); +} + +/* print instructions */ + +char *inst[] = { + "`Go Fish' is a childrens' card game. The Object is to", + "accumulate `books' of 4 cards with the same face value. The", + "players alternate turns; each turn begins with one player", + "selecting a card from his hand, and asking the other player for", + "all cards of that face value. If the other player has one or", + "more cards of that face value in his hand, he gives them to the", + "first player, and the first player makes another request.", + "Eventually, the first player asks for a card which is not in", + "the second player's hand: he replies `GO FISH!' The first", + "player then draws a card from the `pool' of undealt cards. If", + "this is the card he had last requested, he draws again. When a", + "book is made, either through drawing or requesting, the cards", + "are laid down and no further action takes place with that face", + "value. To play the computer, simply make guesses by typing a,", + "2, 3, 4, 5, 6, 7, 8, 9, 10, j, q, or k when asked. Hitting", + "return gives you information about the size of my hand and the", + "pool, and tells you about my books. Saying `p' as a first", + "guess puts you into `pro' level; The default is pretty dumb!", + "Good Luck!\n", + "", +}; + +void instruct() +{ + register char **cpp; + + printf("\n"); + + for (cpp = inst; **cpp != '\0'; ++cpp) { + printf("%s\n", *cpp); + } +} + +void start(h) + HAND h; +{ + ; +} + +void score() +{ + register int my, your, i; + + my = your = 0; + + printf("The game is over.\nMy books: "); + + for (i=1; i<=CTYPE;++i) { + if (myhand[i] == 4) { + ++my; + printf("%s ", cname[i]); + } + } + + printf("\nYour books: "); + + for (i=1; i<=CTYPE;++i) { + if (yourhand[i] == 4) { + ++your; + printf("%s ", cname[i]); + } + } + + printf("\n\nI have %d, you have %d\n", my, your); + + printf("\n%s win!!!\n", my>your?"I":"You"); + exit(0); +} + +void heguessed(d) +{ + ++hehas[d]; +} + +void madebook(x) +{ + printf("Made a book of %s's\n", cname[x]); +} + +void hedrew(d) +{ + ++hehas[d]; +} + +/* reflect the effect of a move on the hands */ + +int move(hs, ht, g, v) + HAND hs, ht; +{ + /* hand hs has made a guess, g, directed towards ht */ + /* v on indicates that the guess was made by the machine */ + register int d; + char *sp, *tp; + + sp = tp = "I"; + if (v) + tp = "You"; + else + sp = "You"; + + if (g == NOMORE) { + d = draw(); + if (d == NOMORE) + score(); + else { + printf("Empty Hand\n"); + if (! v) + printf("You draw %s\n", cname[d]); + mark(hs, d); + } + return(0); + } + + if (! v) + heguessed(g); + + if (hs[g] == 0) { + if (v) + error("Rotten Guess"); + printf("You don't have any %s's\n", cname[g]); + return(1); + } + + if (ht[g]) { /* successful guess */ + printf("%s have %d %s%s\n", tp, ht[g], cname[g], ht[g]>1?"'s":""); + hs[g] += ht[g]; + ht[g] = 0; + if (hs[g] == 4) + madebook(g); + return 1; + } + + /* GO FISH! */ + + printf("%s say \"GO FISH!\"\n", tp); + + newdraw: + d = draw(); + if (d == NOMORE) { + printf("No more cards\n"); + return(0); + } + mark(hs, d); + if (! v) + printf("You draw %s\n", cname[d]); + if (hs[d] == 4) + madebook(d); + if (d == g) { + printf("%s drew the guess, so draw again\n", sp); + if (! v) + hedrew(d); + goto newdraw; + } + return(0); +} + +#define G(x) { if (go) goto err; else go = x; } + +int guess() +{ + /* get the guess from the tty and return it... */ + register int g, go; + + go = 0; + + for (;;) { + switch(g = getchar()) { + + case 'p': + case 'P': + ++proflag; + continue; + + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + G (g - '0'); + continue; + + case 'a': + case 'A': + G (1); + continue; + + case '1': + G (10); + continue; + + case '0': + if (go != 10) + goto err; + continue; + + case 'J': + case 'j': + G (11); + continue; + + case 'Q': + case 'q': + G (12); + continue; + + case 'K': + case 'k': + G (13); + continue; + + case '\n': + if (empty(yourhand)) + return NOMORE; + if (go == 0) { + stats(); + continue; + } + return(go); + + case ' ': + case '\t': + continue; + + default: + err: + while(g != '\n') g = getchar(); + printf("what?\n"); + continue; + } + } +} + +int myguess() +{ + register int i, lg, t; + + if (empty(myhand)) + return(NOMORE); + + /* make a list of those things which i have */ + /* leave off any which are books */ + /* if something is found that he has, guess it! */ + + ntry = 0; + for (i=1; i<=CTYPE; ++i) { + if (myhand[i] == 0 || myhand[i] == 4) + continue; + try[ntry++] = i; + } + + if (! proflag) + goto random; + + /* get ones he has, if any */ + + for (i=0; i 1 && argv[1][0] == '-') { + while(argv[1][0] == '-') { + ++argv[1]; + ++debug; + } + argv++; + argc--; + } + + srand(getpid()); + + printf("instructions?\n"); + if ((c = getchar()) != '\n') { + if (c != 'n') + instruct(); + while (getchar() != '\n'); + } + + game(); + return 0; +} diff --git a/src/games/fortune/Do_troff b/src/games/fortune/Do_troff new file mode 100644 index 0000000..a071007 --- /dev/null +++ b/src/games/fortune/Do_troff @@ -0,0 +1,4 @@ +#!/bin/csh -f +set file=$1 +shift +( echo ".ds Se $file" ; cat Troff.mac ; sed -f Troff.sed $file ) | $* -me diff --git a/src/games/fortune/Makefile b/src/games/fortune/Makefile new file mode 100644 index 0000000..cedde4e --- /dev/null +++ b/src/games/fortune/Makefile @@ -0,0 +1,72 @@ +FORTUNES= scene obscene +SOURCE= fortune.c strfile.h strfile.c rnd.c unstr.c $(FORTUNES) +TFILES= Troff.mac Troff.sed Do_troff +LIBDIR= /usr/games/lib +BINDIR= /usr/games +OWN= arnold +GRP= arpa +DEFS= +SEPFLAG= -i +CFLAGS= -O $(DEFS) +SFLAGS= -r +TDEV= -Pver +TROFF= ditroff $(TDEV) +DESTDIR= + +all: fortune strfile unstr fortunes.dat + +fortune: fortune.o rnd.o + $(CC) ${SEPFLAG} $(CFLAGS) -o fortune fortune.o rnd.o + +strfile: strfile.o rnd.o + $(CC) ${SEPFLAG} $(CFLAGS) -o strfile strfile.o rnd.o + +unstr: unstr.o + $(CC) ${SEPFLAG} $(CFLAGS) -o unstr unstr.o + +fortune.o strfile.o unstr.o: strfile.h + +fortunes.dat: fortunes strfile + ./strfile $(SFLAGS) fortunes + +fortunes: $(FORTUNES) + cp scene fortunes + echo "%-" >> fortunes + cat obscene >> fortunes + +lint: + lint -hxb $(DEFS) fortune.c rnd.c 2>&1 > fortune.lint + lint -hxb $(DEFS) strfile.c rnd.c 2>&1 > strfile.lint + lint -hxb $(DEFS) unstr.c 2>&1 > unstr.lint + +install: all install.data + install -s -m 4711 -o daemon fortune $(DESTDIR)$(BINDIR) + +install.data: fortunes.dat + install -m 600 -o daemon fortunes.dat $(DESTDIR)$(LIBDIR) + +troff: troff.scene troff.obscene + +troff.scene: + ./Do_troff scene $(TROFF) + +troff.obscene: + ./Do_troff obscene $(TROFF) + +clean: sort.clean + rm -f fortune fortunes fortunes.dat strfile unstr ? core *.o + +sort: sort.scene sort.obscene + +sort.scene: strfile unstr + strfile -oi scene + mv scene Oscene + unstr -o scene + +sort.obscene: strfile unstr + strfile -oi obscene + mv obscene Oobscene + unstr -o obscene + +sort.clean: + rm -f Oscene Oobscene diff --git a/src/games/fortune/Troff.mac b/src/games/fortune/Troff.mac new file mode 100644 index 0000000..c2b433e --- /dev/null +++ b/src/games/fortune/Troff.mac @@ -0,0 +1,26 @@ +.nr tp 8 +.nr hm 3v +.nr fm 2v +.nr tm 5v +.nr bm 4v +.cs R +.sc +.sz 6 +.ll +10n +.lt \n(.l +.de $h +.tl 'Fortune Database'\\*(Se'\*(td' +.. +.de $f +.tl ''- % -'' +.. +.2c +.nf +.ta +.ta 8n 16n 24n 32n 40n 48n 56n 64n 72n 80n +.de %% +.sp .3 +.ce +\(sq\|\(sq\|\(sq\|\(sq\|\(sq\|\(sq\|\(sq\|\(sq\|\(sq +.sp .2 +.. diff --git a/src/games/fortune/Troff.sed b/src/games/fortune/Troff.sed new file mode 100644 index 0000000..3216681 --- /dev/null +++ b/src/games/fortune/Troff.sed @@ -0,0 +1,13 @@ +/^['.]/s//\\\&&/ +/^%%/s//.&/ +/--/s//\\*-/g +/_a-squared cos 2(phi)/s//\\fIa\\fP\\u2\\d cos 2\\(*f/ +/__**\([a-zA-Z]*\)/s//\\fI\1\\fP/g +/"\(.\)/s//\1\\*:/g +/`\(.\)/s//\1\\*`/g +/'\(.\)/s//\1\\*'/g +/~\(.\)/s//\1\\*~/g +/\^\(.\)/s//\1\\*^/g +/,\(.\)/s//\1\\*,/g +/\(.\)\(.\)/s//\\o_\1\2_/g +/*/s//\\(bs/g diff --git a/src/games/fortune/fortune.6 b/src/games/fortune/fortune.6 new file mode 100644 index 0000000..150456f --- /dev/null +++ b/src/games/fortune/fortune.6 @@ -0,0 +1,54 @@ +.\" Copyright (c) 1980 Regents of the University of California. +.\" All rights reserved. The Berkeley software License Agreement +.\" specifies the terms and conditions for redistribution. +.\" +.\" @(#)fortune.6 6.1 (Berkeley) 5/20/85 +.\" +.TH FORTUNE 6 "May 20, 1985" +.UC 4 +.SH NAME +fortune \- print a random, hopefully interesting, adage +.SH SYNOPSIS +.B /usr/games/fortune +[ +.B \- +] [ +.B \-wslao +] +..[ file ] +.SH DESCRIPTION +.I Fortune +with no arguments prints out a random adage. The flags mean: +.PP +.TP 5 +.B \-w +Waits before termination +for an amount of time calculated from the number of characters in the message. +This is useful if it is executed as part of the logout procedure +to guarantee that the message can be read before the screen is cleared. +.TP 5 +.B \-s +Short messages only. +.TP 5 +.B \-l +Long messages only. +.TP +.B \-o +Choose from an alternate list of adages, +often used for potentially offensive ones. +.TP +.B \-a +Choose from either list of adages. +.PP +..The user may specify a file of adages. +..This file must be created by strfile(6), +..and be given by the user as +...it file. +..Only one such file may be named, +..subsequent ones are ignored. +.SH FILES +/usr/games/lib/fortunes.dat +.SH AUTHOR +Ken Arnold +...SH SEE\ ALSO +..strfile(6) diff --git a/src/games/fortune/fortune.c b/src/games/fortune/fortune.c new file mode 100644 index 0000000..6253dea --- /dev/null +++ b/src/games/fortune/fortune.c @@ -0,0 +1,237 @@ +/* $Header: fortune.c,v 1.10 85/11/01 15:19:49 arnold Exp $ */ + +# include +# include +# include +# include "strfile.h" + +# define TRUE 1 +# define FALSE 0 +# define bool short + +# define MINW 6 /* minimum wait if desired */ +# define CPERS 20 /* # of chars for each sec */ +# define SLEN 160 /* # of chars in short fortune */ + +# define FORTFILE "/usr/games/lib/fortunes.dat" + +bool Wflag = FALSE, /* wait desired after fortune */ + Sflag = FALSE, /* short fortune desired */ + Lflag = FALSE, /* long fortune desired */ + Oflag = FALSE, /* offensive fortunes only */ + Aflag = FALSE; /* any fortune allowed */ + +char *Fortfile = FORTFILE, /* fortune database */ + *Usage[] = { + "usage: fortune [ - ] [ -wsloa ] [ file ]", + " - - give this summary of usage", + " w - have program wait after printing message in order", + " to give time to read", + " s - short fortune only", + " l - long fortune only", + " o - offensive fortunes only", + " a - any fortune", + " Mail suggested fortunes to \"fortune\"", + NULL + }; + +long Seekpts[2]; /* seek pointers to fortunes */ + +FILE *Inf; /* input file */ + +STRFILE Tbl; /* input table */ + +time_t time(); + +main(ac, av) +int ac; +char *av[]; +{ + register char c; + register int nchar = 0; + register int i; + + getargs(ac, av); + if ((Inf = fopen(Fortfile, "r+")) == NULL) { + perror(Fortfile); + exit(-1); + } + fread((char *) &Tbl, sizeof Tbl, 1, Inf); /* NOSTRICT */ + if (Tbl.str_longlen <= SLEN && Lflag) { + puts("Sorry, no long strings in this file"); + exit(0); + } + if (Tbl.str_shortlen > SLEN && Sflag) { + puts("Sorry, no short strings in this file"); + exit(0); + } + + /* + * initialize the pointer to the first -o fortune if need be. + */ + if (Tbl.str_delims[2] == 0) + Tbl.str_delims[2] = Tbl.str_delims[0]; + + do { + getfort(); + } while ((Sflag && !is_short()) || (Lflag && !is_long())); + + fseek(Inf, Seekpts[0], 0); + while (c = getc(Inf)) { + nchar++; + putchar(c); + } + fflush(stdout); + fseek(Inf, 0L, 0); +#ifdef LOCK_EX + /* + * if we can, we exclusive lock, but since it isn't very + * important, we just punt if we don't have easy locking + * available. + */ + flock(fileno(Inf), LOCK_EX); +#endif LOCK_EX + fwrite(&Tbl, 1, sizeof Tbl, Inf); +#ifdef LOCK_EX + flock(fileno(Inf), LOCK_UN); +#endif LOCK_EX + if (Wflag) + sleep(max((int) nchar / CPERS, MINW)); + exit(0); +} + +/* + * is_short: + * Return TRUE if fortune is "short". + */ +is_short() +{ + register int nchar; + + if (!(Tbl.str_flags & (STR_RANDOM | STR_ORDERED))) + return (Seekpts[1] - Seekpts[0] <= SLEN); + fseek(Inf, Seekpts[0], 0); + nchar = 0; + while (getc(Inf)) + nchar++; + return (nchar <= SLEN); +} + +/* + * is_long: + * Return TRUE if fortune is "long". + */ +is_long() +{ + register int nchar; + + if (!(Tbl.str_flags & (STR_RANDOM | STR_ORDERED))) + return (Seekpts[1] - Seekpts[0] > SLEN); + fseek(Inf, Seekpts[0], 0); + nchar = 0; + while (getc(Inf)) + nchar++; + return (nchar > SLEN); +} + +/* + * This routine evaluates the arguments on the command line + */ +getargs(ac, av) +register int ac; +register char *av[]; +{ + register int i; + register char *sp; + register int j; + register short bad = 0; + + for (i = 1; i < ac; i++) { + if (av[i][0] != '-') { + setuid(getuid()); + setgid(getgid()); + Fortfile = av[i]; + } + else if (av[i][1] == '\0') { + j = 0; + while (Usage[j] != NULL) + puts(Usage[j++]); + exit(0); + /* NOTREACHED */ + } + else + for (sp = &av[i][1]; *sp != '\0'; sp++) + switch (*sp) { + case 'w': /* give time to read */ + Wflag++; + break; + case 's': /* short ones only */ + Sflag++; + break; + case 'l': /* long ones only */ + Lflag++; + break; + case 'o': /* offensive ones only */ + Oflag++; + break; + case 'a': /* any fortune */ + Aflag++; + /* + * initialize the random number + * generator; throw away the first + * few numbers to avoid any non- + * randomness in startup + */ + srnd(time(NULL) + getpid()); + for (j = 0; j < 20; j++) + (void) rnd(100); + break; + default: + printf("unknown flag: '%c'\n", *sp); + bad++; + break; + } + } + if (bad) { + printf("use \"%s -\" to get usage\n", av[0]); + exit(-1); + } +} + +/* + * getfort: + * Get the fortune data file's seek pointer for the next fortune. + */ +getfort() +{ + register int fortune; + + /* + * Make sure all values are in range. + */ + + if (Tbl.str_delims[1] >= Tbl.str_delims[0]) + Tbl.str_delims[1] = 0; + if (Tbl.str_delims[2] >= Tbl.str_numstr) + Tbl.str_delims[2] = Tbl.str_delims[0]; + + if (Aflag) { + if (rnd(Tbl.str_numstr) < Tbl.str_delims[0]) + fortune = Tbl.str_delims[1]++; + else + fortune = Tbl.str_delims[2]++; + } + else if (Oflag) + fortune = Tbl.str_delims[2]++; + else + fortune = Tbl.str_delims[1]++; + + fseek(Inf, (long)(sizeof Seekpts[0]) * fortune + sizeof Tbl, 0); + fread((char *) Seekpts, (sizeof Seekpts[0]), 2, Inf); +} + +max(i, j) +register int i, j; +{ + return (i >= j ? i : j); +} diff --git a/src/games/fortune/notes b/src/games/fortune/notes new file mode 100644 index 0000000..b9e99b3 --- /dev/null +++ b/src/games/fortune/notes @@ -0,0 +1,140 @@ +Warning: The fortunes contained in the fortune database have + been collected haphazardly from a caphony of sources, + in number so huge it boggles the mind. It is + impossible to do any meaningful quality control on + attributions, or lack thereof, or exactness of the + quote. Since this database is not used for profit, and + since entire works are not published, it falls under + fair use, as we understand it. However, if any + half-assed idiot decides to make a profit off of this, + they will need to double check it all, and nobody not + involved of such an effort makes any warranty that + anything in here bears any relation to the real world + of literature, law, or other bizzarrity. + +[All examples are indented by one tab stop -- KCRCA] + +Numbers should be given in parentheses, e.g., + + (1) Everything depends. + (2) Nothing is always. + (3) Everything is sometimes. + +Attributions are two tab stops, followed by two hyphens, followed by a +space, followed by the attribution, and are *not* preceded by blank +lines. Book, journal, movie, and all other titles are in quotes, .e.g, + + $100 invested at 7% interest for 100 years will become $100,000, at + which time it will be worth absolutely nothing. + -- Lazarus Long, "Time Enough for Love" + +Attributions which do not fit on one (72 char) line should be continued +on a line which lines up below the first text of the attribution, e.g., + + -- A very long attribution which might not fit on one + line, "Ken Arnold's Stupid Sayings" + +Single paragraph fortunes are in left justified (non-indented) +paragraphs unless they fall into another category listed below (see +examle above). Longer fortunes should also be in left justified +paragraphs, but if this makes it too long, try indented paragraphs, +with indentations of either one tab stop or 5 chars. Indentations of +less than 5 are too hard to read. + +Laws have the title left justified and capitalized, followed by a +colon, with all the text of the law itself indented one tab stop, +initially capitalized, e.g., + + A Law of Computer Programming: + Make it possible for programmers to write in English and you + will find the programmers cannot write in English. + +Limericks are indented as follows, all lines capitalized: + + A computer, to print out a fact, + Will divide, multiply, and subtract. + But this output can be + No more than debris, + If the input was short of exact. + +Accents precede the letter they are over, e.g., "`^He" for e with a +grave accent. Underlining is done on a word-by-word basis, with the +underlines preceding the word, e.g., "__^H^Hhi ____^H^H^H^Hthere". + +No fortune should run beyond 72 characters on a single line without +good justification (er, no pun intended). And no right margin +justification, either. Sorry. + +Definitions are given with the word or phrase left justified, followed +by the part of speech (if appropriate) and a colon. The definition +starts indented by one tab stop, with subsequent lines left justified, +e.g., + + Afternoon, n.: + That part of the day we spend worrying about how we wasted the + morning. + +Quotes are sometimes put around statements which are funnier or make +more sense if they are understood as being spoken, rather than written, +communication, e.g, + + "All my friends and I are crazy. That's the only thing that keeps us + sane." + +Elipses are always surrounded by spaces, except when next to +puncuation, and are three dots, unless there is a good reason not to. +(In fact, all these rules can be broken if they make a good joke.) + + "... all the modern inconveniences ..." + -- Mark Twain + +Human initials always have spaces after the periods, e.g, "P. T. +Barnum", not "P.T. Barnum". However, "P.T.A.", not "P. T. A.". + +All fortunes should be attributed, but if and only if they are original +with somebody. Many people have said things that are folk sayings +(i.e., are common among the folk (i.e., us common slobs)). There is +nothing wrong with this, of course, but such statements should not be +attributed to individuals who did not invent them. + +Horoscopes should have the sign indented by one tab stop, followed by +the dates of the sign, with the text left justified below it, e.g., + + AQUARIUS (Jan 20 - Feb 18) + You have an inventive mind and are inclined to be progressive. You lie + a great deal. On the other hand, you are inclined to be careless and + impractical, causing you to make the same mistakes over and over + again. People think you are stupid. + +Single quotes should not be used except as quotes within quotes. Not +even single quotes masquerading as double quotes are to be used, e.g., +don't say ``hi there'' or `hi there' or 'hi there', but "hi there". +However, you *can* say "I said, `hi there'". + +A long poem or song can be ordered as follows in order to make it +fit on a screen (fortunes should be 19 lines or less if at all +possible): + + 11111111111111111111 + 11111111111111111111 + 11111111111111111111 22222222222222222222 + 11111111111111111111 22222222222222222222 + 22222222222222222222 + 33333333333333333333 22222222222222222222 + 33333333333333333333 + 33333333333333333333 44444444444444444444 + 33333333333333333333 44444444444444444444 + 44444444444444444444 + 44444444444444444444 + +Fortunes are split into potentially offensive and not potentially +offensive, into the files "obscene" and "scene", respectively. +Anything which would not make it onto network prime time programming +should *not* go into "scene". Also, anything which would only get on +if some discredited kind of guy said it should *not* go in scene. +Fortunes containing "shit", "fuck", "cock" (not the male version of a +chicken, obviously, but "penis"), "cunt", "pussy", and such like are +*obscene*. Political opinions are supposed to be in "obscene", too. +Antyhing which is blatantly racist, mysoginist, or homophobic, should +not be in either, since they are not really funny unless *you* are +racist, mysoginist, or homophobic. diff --git a/src/games/fortune/obscene b/src/games/fortune/obscene new file mode 100644 index 0000000..0e59fd6 --- /dev/null +++ b/src/games/fortune/obscene @@ -0,0 +1,10500 @@ +... which the Minstrel was supposed by some authorities to have composed +beneath the gibbet at Elsdon on the occasion of his hanging, drawing and +quartering for misguidedly climbing into bed with Sir Oswald Capheughton's +wife, Lady Fleur, when that noble lord was not only in it, but in her at +the same time. Minstrel Flawse's introduction of himself into Sir Oswald +had met with that reaction known as dog-knotting on the part of all +concerned... +I gan noo wha ma organs gan +When oft I lay abed I should ha' known 'twas never Fleur +So rither hang me upside doon That smelt so mooch of sweat +Than by ma empty head. For she was iver sweet and pure + And iver her purse was wet. +But old Sir Oswald allus stank +Of horse and hound and dung So hang me noo fra' Elsdon tree +And when I chose to breech his rank And draw ma innards out +Was barrel to my bung. That all the wald around may see + What I have done without. +But ere ye come to draw ma heart +Na do it all so quick So prick 'em wet or prick 'em dry +But prise the arse of Oswald 'part 'Tis all the same to me +And bring me back ma prick. I canna wait for him to die + Afore I have a pee. + -- Tom Sharpe, "The Ballad of Prick 'Em Dry" +%% +6802 hackers make great use of the SEX instruction. +%% +68: + Do me now and I'll owe you one. +%% +69 + 69 = dinner for 4. +%% +A '49er walked into the saloon at Bloody Gulch. He'd been prospecting for +more than a year. + "Hey! Y'got any wimmen around here?" + "Nope," the bartender replied, "But there's George in the back room." + "I don't go for that kind of thing," the prospector scowled. He +downed his drink and left disgustedly. +A few months passed before the miner found his way down the mountain again. +He stumbled into the tavern and asked the bartender, "Any wimmen pass through +this part of town?" + "Nope. Nary a one. But we still got George in the back room." + Angry, the miner shouted, "I told you I don't go for that kind of +thing," and turned on his heel and left. + Within a year he came back from his mine again. With a wild look on +his face he re-entered the saloon. Leaning over the bar he whispered to the +bartender, "If I was to go into the back room with George, how many people +'round here would know?" + "Oh," the bartender said, scratching his chin, "'bout seven, I guess." + "Seven!?" + "Yep. You, me, George, and the four men holdin' him down. You see, +George don't go for that kind of thing neither." +%% +A 6'8", 280-pound Southerner walked into a NY bar, sat down next to a +patron, and said, "Ah'm big, and ah'm bad, and I *loves* to fuck Northern +women!" The guy was so terrified that he put down his beer and ran out +of the bar. + The Rebel moved over to the next guy and said, "Ah'm big and ah'm +bad and I *loves* to fuck New York women." The guy took one look at him, +blanched and ran out of the bar. + The man then went over to a short little guy with "Bronx" written +all over him. "Ah'm big and ah'm bad and I *loves* to fuck your sister." + The short guy looked him up and down and said, "I don't blame +you one bit. She's *got* to be an improvement on yours." +%% + A Mexican and a Texan worked together for a construction firm, and, +while they were good friends, they had a friendly rivalry over whose wife +was the better cook. One weekend, as the Texan's wife was out of town, the +Mexican invited the Texan to have supper with his family. + The Texan accepted, and that evening sat down to some the best stew +that he had ever eaten. + "Damn! That stew is fantastic!" he exclaimed to his host. "What +kind of meat is it?" + "Rabbeet stew," replied the Mexican. + "Rabbit?" replied the Texan. "There aren't any rabbits around here." + "Si, my freend, the rabbeets make the beeg noise, and I shoot theem." + "Rabbits don't make any noise..." + "Si, my freend, they say meeyow, meeyow!" +%% +A New Yorker is riding down the road in his new Mercedes. So intent is he +on the cocaine in his hand he completely misses a turn and his car plunges +over the five-hundred-foot cliff to be smashed into pieces at the bottom. +As the on-lookers rush to the edge of the cliff they see him fifty feet +from the top of the cliff clinging to a stunted bush with all his strength. +"Dear Lord," he prays, "I never asked you for nothin' before, but I'm askin' +you now: Save me, Lord, save me." + Booms the Lord: "LET GO OF THE BRANCH." + "But Lord, if I do that, I'll fall!" + "TRUST ME, LET GO OF THE BRANCH." + "But Lord, I'm gonna fall and die..." + "TRUST ME TO SAVE YOU. LET GO OF THE BRANCH." + Okay, Lord, I'll trust you, here I... here I go!" And he falls +to his death. + "DUMB YANKEE." +%% +A New Yorker was driving through Berkeley when he saw a big crowd gathered +by the side of the street. Curiousity got the better of him and he leaned +out of his window to ask an onlooker what was going on. The fellow explained +that a protestor against the U.S. position in South America had doused +himself with gasoline and set himself on fire. "That's terrible," gasped +the man. "But why is everyone still standing around?" + "Well, they're taking up a collection for his wife and kids," the +onlooker explained. "Would you be willing to help?" + "Well, sure," said the New Yorker. "I suppose I could spare a gallon +or two." +%% +A Norse god decides to assume human form, come down from Valhalla, and check +out the local action. He finds himself in the piano bar of Caesar's Boardwalk +Regency in Atlantic City, and sits down to sip an Acquavit or two. After a few +minutes, an extremely attractive young woman, having been taken with his form +and features, sends a drink down to him, then joins him. The chemistry between +them is immediate and total. They have the next drink in her room, and spend +the night repeatedly making passionate love. The woman has no idea of her +partner's true identity; all she knows is he's driving her mad. In the +morning, the Norse god jumps into the shower. Reflecting on the previous +night he decides that he wants to be honest with his lover. Without even +bothering to wrap himself in a towel, he leaps from the shower into the room, +where the woman is still in bed, exhausted. He kneels beside the bed, looks +deep into her eyes and says, "Honey, I have something very important to tell +you -- I'm Thor!". + The woman looks at him. "You're Thor?", she says. "My inthides feel +like grated cheeth!" +%% +A bar patron returned from the men's room grumbling to himself. + "What's the trouble, buddy?" the bartender inquired. + "You got John Wayne toilet paper in there!" + "What do you mean?" the barkeeper asked. + "It's rough, it's tough, and it doesn't take shit from nobody." +%% +A beachcomber of 25 had been shipwrecked on a desert island since the age of +six. One day, while in search of food, he stumbled across a beautifully +sensuous female lying on the beach nearly naked; she'd been washed ashore from +another shipwreck that morning. After they got over their initial surprise +at seeing each other, the girl wanted to know how long he had been alone on +this barren bit of land. + "Almost twenty years," he answered. + "Twenty years!" she exclaimed. "But how ever did you survive?" + "Oh, I fish, dig for clams, and gather berries and coconuts," he +replied. + "And what do you do for sex?" she asked. + "What's that?" He looked puzzled. + Whereupon the maiden pulled the innocent young man down onto the sand +beside her and proceeded to demonstrate. After they had finished, she asked +how he had enjoyed it. + "Great!" was the reply. "But look what it did to my clamdigger!" +%% +A big store buyer had been on the road for nearly two months. Each week he +would send his wife a telegram saying, + "Can't come home yet. Still buying." +His wife knew that these buying trips usually involved more than business. +She tolerated this particular jaunt for a while, but when the third month +rolled by and she'd still seen nothing of her husband but the weekly telegrams, +she wired him, + "Better come home. I'm selling what you're buying." +%% +A bisexual is a man who likes girls as well as the next fellow. +%% +A businessman was awe-struck by the beautiful redhead at the hotel bar. +Seeing his interest, she quietly informed him that she was a prostitute +and that her price was $500. He was taken aback by the price, but after +a few minutes of thought he took her up to his room. She spent a few +minutes in the bathroom and was shocked when she came out to see him +masturbating furiously on the bed. "What are you doing?", she asked. + "Baby, for $500, you're not going to get the easy one!" +%% +A chiseler is a man who goes stag to a wife-swapping party. +%% +A clitoris is a lot like Antarctica; +most men know it's there, but few really care. +%% +A couple took their young son for his first visit to the circus, and by +chance their seats were next to the elephant pen. When his father left +to buy popcorn, the boy piped up, + "Mom, what's that long thing on the elephant?" + "That's the elephant's trunk, dear," she replied. + "No, not that." + "Oh, that's the elephant's tail." + "No, Mom. Down underneath." + His mother blushed and said, "Oh, that's nothing." + Pretty soon the father returned, and the mother went off to get +a soda. As soon as she had left the boy repeated his question. + "That's the elephant's trunk, son." + "Dad, I know what an elephant's trunk is. The thing at the +other end." + "Oh, that's the elephant's tail." + "No. Down there." + The father took a good look and explained, "That's the elephant's +penis." + "Dad, how come when I asked Mom, she said it was nothing?" + The man took a deep breath and replied, "Son, I've *spoiled* +that woman." +%% +A fisherman from Maine went to Alabama on his vacation. He rented a boat, +rowed out to the middle of the lake, and cast his line, but when he looked +down into the water he was horrified to see a man wrapped in chains lying +on the bottom of the lake. He quickly rowed to shore and ran to the police +station. "Sheriff, sheriff," he gasped, there's a guy wrapped in chains, +drowned in the lake!" + "Now ain't that jest like a Yankee," drawled the sheriff, "to steal +more chain than he can swim with?" +%% +A fool is a man who worries about whether or not his lover has integrity. +A wise man, on the other hand, busies himself with deeper attributes. +%% +A friend of mine received a note through the mail advising him, + "If you don't stop making love to my wife, I'll kill you." +The trouble is, the note wasn't signed. +%% +A gambler was telling a friend about his first junket to Las Vegas and how +hard it was to get any sleep. + "I was awakened at one, two and four in the morning by a +drunken chorus girl banging on the door and screaming," he recalled. + "That's terrible," the friend said." How'd you ever get any sleep?" + "At five o'clock I unlocked the door and let her out." +%% +A genius is a queer who can whistle while he works. + -- Bobby Knight +%% +A girl's conscience doesn't really keep her from doing anything wrong-- +it merely keeps her from enjoying it. +%% +A grade school teacher, who was doing a unit on World War II heard that +the father of one of her students had been a fighter pilot during the war +with one of the Scandinavian Air Forces. She invited him to come in and +speak to the class. The guy was more than happy to talk, and began with +a story about a morning patrol where he had been nearly shot down. + "We had been up for about 20 minutes flying over enemy held +territory, when we noticed, just in time, 3 fokkers diving on us from above." +At the first mention of `fokkers' the class giggled a little bit. + "Our group broke formation, and began the dog-fighting. As we +fought, we noticed 2 more fokkers coming at us from above and 2 more +fokkers, fresh from the landing field, come to join the battle". +At this second and third mention of `fokkers' the class was almost laughing +openly, and the teacher interrupted the story to ask the pilot to explain +to the class that a 'fokker' was a particular type of plane flown by the +German Air Force. + He replied, "Ya, dat is true, but these fokkers were Messerschmidts". +%% +A guy comes into a bar with a frog and sets it down next to the prettiest +girl there. + "This is a very special frog," he informs her. "His name is Charlie." + "What's so special about this frog?" she asks. +He's reluctant to tell her, but when pressed, explains that, + "This frog can eat pussy." +The girl slaps him, knocking him off his chair, and accuses him of telling her +a filthy lie. But no, he assures her, it's completely true. And after much +discussion, she agrees to come back to his apartment to see the frog in action. +She positions herself appropriately, the guy carefully takes out the frog, and +says, "Okay, Charlie, do your stuff!" The frog is immobile, despite his +owner's exhortations, and the girl starts to snicker. + "Okay, Charlie, do your stuff!" + "C'mon Charlie, do your stuff!" +By now, the girl is laughing openly. + "Okay, Charlie," says the guy, moving the frog out of the way, "I'm +only going to show you one more time." +%% +A hard man is good to find. +%% +A hunter saved a native boy from a boa constrictor. In gratitude, the boy gave +the hunter a magic gorilla prick. The lad said the prick would do anything you +told it to do until you told it to do something else. When the hunter returned +home to England, he put the magic gorilla prick on the mantle along with some +of his other trophies. His wife thought it quaint and his story charming. But +soon, the hunter went a-safariing again. He was away for months. One evening, +the woman eyed the MGP carefully and whispered, "Gorilla Prick, fuck me." +Whereupon the thing jumped off the mantle and began to bang her with great +thoroughness and ferocity. For the first twenty minutes it was pure heaven, +but after the next few minutes it became fatiguing, and she said, "Stop it, +Gorilla Prick," but it didn't. After a bit more she was screaming "Stop! +Stop!" at the thing and trying to pull it out of her smoking hole. But nothing +worked. Finally, the butler bursts into the room, summoned by her screams. + "Saunders, help me please!" + "But what is it, Madame?" + "It's a Magic Gorilla Prick!" + "Gorilla prick, my ass!! ... AAAaaeeeeeeeeeiiiiiiiii!!!!!!" +%% +A husky foreigner, looking for sex, accepted a prostitute's terms. When +she undressed, he noticed that she had no pubic hair. The man shouted, +"What, no wool? In my country all women have wool down there." + The prostitute snapped back, "What do you want to do, knit or fuck?" +%% +A lanky Texan was mad because Texas had just become the second largest state in +the Union, so he made up his mind to move to Alaska. He drove for three days +and three nights to get there and finally he came to what looked like the state +line. He halted his car and walked up to the border guard. "Hi, there! How +do I become a resident of this here biggest state?" demanded the Texan. + The guard looked him up and down and grinned. "Waal," he answered, +there are three things you gotta do to get in. First, drink down a quart of +110 proof corn liquor without blinkin'. Second, kill a grizzly bear, and +third, make love to an Eskimo woman." + "Sounds easy enough," said the Texan. "Where can I get a quart of +this here corn liquor?" + "Got one right here," replied the guard. + The Texan gulped down the whiskey without batting an eyelash. +"Now, do you happen to know where I can find me a grizzly?" + "Yep," answered the guard, "there's a big b'ar over that way, 'bout +a mile... lives in a cave on that cliff." + The Texan lurched merrily off. About an hour later he returned +with his clothes almost torn off and his face scratched and bloody. He was +smiling happily. "Now," he roared, "where's that damn Eskimo woman you +want killed?" +%% +A lisping fag fell off a pleasure yacht and began to scream. "Help! Help, I +can't thwim!" One of the other passengers heard the caterwauling and leaned +over the rail, remarking, "Really, there's no need to scream. Just reach out +and grab that buoy near you." To which the floundering sodomite answered, +"Buoy! Oh, thith ith no time for thekth, you degenerate... I'm dwowning!" +%% +A man and a woman got married. Although it is the first time for the +husband, it is the woman's second marriage. As they go to bed on their +wedding night, the wife says to her husband: + + "Dear, there's something I must tell you. I'm a virgin." +Naturally, the husband is surprised. + "You've been married before!", he says, "How can you still be a +virgin?" + "Well, it's all quite simple," she retorted, "my husband was a +computer programmer." + "What's so odd about that?", he asked. "Why would you still be +a virgin after a marriage to a programmer?" + "Well", she said, "all he did was sit on the edge of the bed and +tell me how great it was going to be." +%% +A man is marooned on a desert island with a female sheep and a male Doberman +for companionship. The animals soon get it on sexually, and all goes well +until the man becomes unbearably horny and makes his move for the ewe, at +which point the dog interposes himself, snarling, fangs bared. Months later, +a raft drifts into sight. The sailor swims out, finds a beautiful girl on it, +takes her to shore and feeds and comforts her. + "You are so good to me," she responds gratefully. "I'd do absolutely +anything to show my gratitude." + "Would you?" smiles the sailor as he unfastens the length of rope +that holds up his ragged pants. "Well, then, here -- use this as a leash +and take that damn dog for a walk!" +%% +A man needs a mistress, just to break the monogamy. +%% +A man never minds being in the doghouse +as long as he can get his tail outside. +%% +A man rushed into a bar and breathlessly asked the bartender to pour him +three straight scotches. The bartender complied, and watched as he downed +them one after another. + "Why three scotches?" the bartender asked as he paused for breath. + "Well, to be honest, I'm celebrating my first blow-job." + "Hell, congratulations, the next one's on me." + "No thanks," the young man replied, "if the first three didn't get +the taste out of my mouth, I don't think another one will." +%% +A man sat down next to another passenger on a train recently and couldn't +help overhearing his conversation out the window with a man standing on +the train platform. + "Thanks for putting me up while I was here, Sam," said the passenger. + "Glad to do it," said the other man. + "Thanks for the food and the drinks -- everything was wonderful." + "It was a pleasure," said the man. + "And thank your wife, Sam, she was great," said the passenger, +"she was a truly great lay." + The man was rather taken aback by this exchange and he later turned +to his fellow passenger and said: "Pardon me sir, but did I understand you +to say that your friend's wife was a great lay?" + "Well," said the other passenger, "I didn't REALLY enjoy it. But +Sam is a helluva nice guy." +%% + A man walks into a bar and says: "I'd like a shot of twelve-year-old +Scotch". The bartender, who figures the guy is just being obnoxious, reaches +down under the bar and pours him a shot of bar Scotch. The man takes one sip +and says: "Hey, bartender, I asked you for some twelve-year-old Scotch -- this +is eight-year-old Scotch." + The bartender reaches behind the bar for the twelve-year-old Scotch, +pours a shot, hands it to the man and says "I've got to hand it to you -- +most guys who come in here asking for twelve-year-old Scotch have never even +had it -- they're just being pricks. But you really know your Scotch -- this +is on the house." + A drunk has been sitting at the other end of the bar watching this +conversation. He walks up to the man, hands him a glass and says "Taste this." +The man does -- and spits it out yelling, "This tastes like piss!" To which +the drunk replies, "It is -- but how old am I?" +%% +A man was playing golf one day when a little frog hopped out the water at a +water hazard and croaked, "I am a magic frog, and since you are the 10,000th +person to play through here, I'm prepared to offer you one of two magic gifts: +First, for a whole year you can have the most fabulous sex life that anyone +ever had; beyond your wildest dreams. Or, second, for a whole year you can +be the best golfer the world has ever known. Which do you prefer?" The man +thought a bit and said that he'd take the golf. Well, the man holed his wood +shot from where he was, completed the course in an average of 2 per hole, and +went round in 22. Quickly he attracted the attention of the sports world, +and became the world's best-known golfer, setting course records wherever +he went. A year later he was playing the same course inhabited by the frog, +and at the water hazard the frog hopped out and said, "Well, the year is up, +and you now revert to the 18-handicap player you were before. But tell me, I +was a little surprised that you chose the golf -- I take it your sex life is +outstanding?" The man said, "Well, I have no complaints in that department +at all, which is why I chose the golf." "How many times did you engage in sex +last year?" inquired the frog. The man thought a little and said, "Oh, eight +or ten times, I guess." "Damn," said the frog, "that doesn't strike me as very +satisfactory." "Oh, I don't know," replied the man, "for a Catholic priest in +a little town in South Dakota it doesn't seem so bad." +%% + A man was traveling cross-country one summer from New York to LA. +He arrived in Needles CA late one night and pulled into an Exxon for some +gas. When he pulled up to the gas pumps, he noticed that all of the lights +were off. Suddenly, he heard a faint sound from outside. He wasn't sure +what he'd heard, so he rolled down his window and heard a faint cry, +"Help... help... help". He got out of his car, and sure enough there was +a guy stooped down in the corner, stark naked with his wrists tied to his +ankles. He walked up to the guy and said, "Hey, man, what happened to you?" + "These guys pulled me out of my car, took my money, my wallet, my +clothes, tied my wrists to my ankles, and then stole my car!!" + "Damn!", replied the first man as he unzipped his pants. "This just +hasn't been your day, has it?" +%% + A man went to a doctor to have his penis enlarged. Well, this +particular procedure involved splicing a baby elephant's trunk onto the +man's penis. Overjoyed, the man went out with his best girl to a very +fancy restaurant. After cocktails, the man's penis crept out of his pants, +felt around the table, grabbed a hard roll and quickly disappeared under +the tablecloth. The girl was startled and exclaimed, "What was that?" + Suddenly the penis came back, took another hard roll and just as +quickly disappeared. The girl was silent for a moment, then finally said, +"I don't believe I saw what I think I just saw... can you do that again?" + With a bit of an uncomfortable smile the man replied, "Honey, I'd +like to, but I don't think my ass can take another hard roll!" +%% +A man without a God is like a fish without a bicycle. +%% +A midget had a date with a very tall girl. It was a quiff-hanger. +%% + A mother and her daughter came to the doctor's office. The mother +asked the doctor to examine her daughter. "She has been having some strange +symptoms and I'm worried about her," the mother said. + The doctor examined the daughter carefully. Then he announced, +"Madam, I believe your daughter is pregnant." + The mother gasped. "That's nonsense!" she said. "Why, my little +girl has never even been out with a man, let alone... let alone..." She +turns to the girl and said, "Tell the doctor, Susie!" + "Yes, Mumsy," said the girl. "Doctor, I have never so much as +kissed a man!" + The doctor looked from the mother to daughter, and back again. Then, +silently he stood up and walked to the window. He stared out. He continued +staring until the mother felt compelled to ask, "Doctor, is there something +wrong out there?" + "No, Madam," said the doctor. "It's just that the last time anything +like this happened, a star appeared in the East and I was looking to see if +another one was going to show up." +%% +A mouse was sniffing around in a meadow, when an eagle swooped down, +swallowed him whole, and rose up in the air again. The mouse worked +his way through until his head was sticking out of the bird's asshole. + "Say, good buddy," he squeaked, "how high up are we, anyway?" + "Oh, about two thousand feet," answered the eagle. + The mouse's eyes bugged out. "Hey, you wouldn't shit me, would you?" +%% +A new lumberjack had just finished his first month in the lonely wilds of +Alaska, where there were no women for miles. He finally couldn't take it +anymore and nervously asked the foreman what the other men did to relieve +the pressure. + "Try the hole in the barrel outside the shower," suggested the +foreman. "The other men swear by it." + The lumberjack dubiously tried it out and had the experience of +his life. "That barrel is fantastic! Warm! Wet! I'm going to use it +every day!" + "Every day but the third Wednesday of the month," one of the +other men replied. + "Why not then?" + "That's your day in the barrel." +%% +A non-vegetarian anti-abortionist is a contradiction in terms. + -- Phyllis Schlafly +%% +A nymph hits you and steals your virginity. +%% +A pair of suburban couples who had known each other for quite some time +talked it over and decided to do a little conjugal swapping. The trade +was made the following evening and the newly arranged couples retired to +their respective houses. After about an hour of bedroom bliss, one of +the wives propped herself up on an elbow, looked at her new partner and +said: "Well, I wonder how the boys are getting along?" +%% +A pederastic necrophiliac is a gentleman who is +true to the very end of the end of a friend. +%% +A performing octopus could play the piano, the zither and a piccolo, and his +trainer wanted him to add the bagpipe to his accomplishments. With this in +mind, a bagpipe was placed in the octopus's room, and the trainer awaited +results. Hours passed, but no bagpipe music was heard. Since the talented +octopus usually learned quickly, the trainer was disturbed. Opening the door +the next morning, he asked the octopus, + "Have you learned to play that thing yet?" + "Play it!" retorted the octopus. "I've been trying to lay it all +night!" +%% +A person who has both feet planted firmly +in the air can be safely called a liberal. +%% +A proctologist is a doctor who puts in a hard day at the orifice. +%% + A proper elderly English couple visiting Australia decided to hire a +car to take a look at the outback. "We know it's rough country, but it's safe +and decent, isn't it?" the husband inquired of the rental-agency manager. +Upon being assured that it was, the couple drove off. + Later that day, they returned, upset and angry. "You said it was +decent country," the Englishwoman upbraided the rental agent, "but we hadn't +driven too far when we saw a man in a field copulating with a kangaroo!" + "And not too long after that," complained her husband, "a one-legged +aborigine leaning against a tree by the side of the road grinningly waved +at us with one hand while he brazenly masturbated himself with the other!" + "Guv'nor," responded the Aussie, "yer wouldn't expect a poor bugger +like that, with only one leg, to catch a 'roo, would you?" +%% +A retired schoolteacher finally decided that she was tired of living alone +and wanted some companionship, so after a good deal of thought she decided +to visit the local pet shop. The owner suggested a parrot, with which she +could conduct a civilized conversation. This seemed to be an excellent +idea, so she bought a handsome parrot, sat him on a perch in her living room, +and said, "Say 'Pretty boy.'" Silence from the bird. "Come on now, say +'Pretty boy ... pretty boy.'" + At long last, disgustedly, the bird said, "Oh, shit." + Shocked, the schoolteacher said, "Just for that, you get five minutes +in the refrigerator." Five minutes later she put the shivering bird back on +its perch and said, "Now let's hear it: 'Pretty boy ... pretty boy.'" + "Damn it, wouldja lay off, lady?" said the parrot. + Outraged, the woman grabbed the bird, said, "That's it! Ten minutes +in the freezer," and slammed the door on him. + Hopping about to keep warm, what does the parrot come across but a +big frozen turkey waiting for Thanksgiving. Startled, he squawks, "My God, +you must have told the bitch to go fuck herself!" +%% +A sheriff arrived at the scene of the horrible accident just as his deputy, +all alone, was climbing down from the controls of a bulldozer. "Say, +Junior, what's goin' on?" asked the sheriff. + "A bus full of migrant workers went out of control and over the +cliff, and I just finished buryin' 'em," explained the deputy. + "Good work, boy," replied the sheriff. "Pretty gory work -- were +all of 'em dead?" + Junior nodded sadly and said, "Some of them said they weren't, but +you know how them Mex'cans lie." +%% +A shy young man, preparing himself for what he hoped would be the ultimate sex +act with a pretty young lady, went into a drugstore to inquire about sizes and +styles of condoms. The lusty proprietress, a buxom widow, saw an opportunity +for fun at the lad's expense. + "Come in the back and try some on for size," she said, taking his hand. +The widow unzipped the youth's fly and watched the small instrument grow in +her hand as she measured it. When the weapon had unfurled to a rosy seven and +a half inches, the young man, unable to contain himself, had an orgasm with a +tremendous discharge. After recovering, he asked the widow if she could now +give him the proper size. + "I'll do more than that," she said. "I'll give you free meals and a +half interest in the store." +%% +A spinster in Kalamazoo +Once strolled after dark by the zoo. + She was seized by the nape, + And fucked by an ape, +And she murmured, "A wonderful screw." + +And she added, "You're rough, yes, and hairy, +But I hope -- yes I do -- that I marry + A man with a prick + Half as stiff and as thick +As the kind that you zoo-keepers carry." +%% +A stately-looking matron was walking through the Bronx Zoo, studying the +animals. When she passed the porcupine enclosure she beckoned to a nearby +attendant. + "Young man," she began, "do North American porcupines have sharper +pricks than those raised in Africa?" + The attendant hesitated for a moment. "Well, ma'am," he answered, +"the African porcupine's quills are sharper... but I think their pricks are +about the same." +%% +A sweet young schoolteacher who had always been virtuous was invited to go +for a ride in the country with the gym instructor, whom she admired. Under +a tree on the bank of a quiet lake, she struggled with her conscience and +with the gym instructor and finally gave in to the latter. Sobbing +uncontrollably she asked her seducer, + "How can I ever face my students again, knowing I have sinned twice?" + "Twice?" asked the young man, confused. + "Why, yes," said the sweet teacher, wiping a tear from her eye. +"You're going to do it again, aren't you?" +%% +A toast to the kisses you've snatched and vice-versa. +%% +A virgin is chaste. +%% +A virginal is a harpsichord that has never been plucked. +%% +A virtuous abstinence from the joys of pederasty +comes most easily to those who have no taste for it. + -- Oscar Wilde +%% +A witty writer, K. Kraus in the Vienna "Fackel", has as it were, +expressed this truth paradoxically in the cynical saying: +"Coitus is merely an unsatisfactory substitute for onanism!" + -- Sigmund Freud, attempting to explain why + masturbation is "by no means harmless" +%% +A woman is like a dresser... some man always goin' through her drawers. + -- Blind Lemon Pledge +%% +A young New York housewife was shocked by some of the language used by her +daughter. When asked about it, the daughter said she had learned it from +a small girl she played with in the park. The next day, the mother sought +out the little girl as she played in the park. "Are you the little girl +who uses bad words?" + "Who told you?" + "A little bird," answered the mother. + "Well, I like that!" exclaimed the small girl. "And I've been +feeding the little bastards, too!" +%% + A young couple jumped out of their car and dashed into the park. +They hurriedly found a secluded spot and began to make frenzied, passionate +love. Shortly thereafter, as they were driving away, the young man turned +to her and said, "If I had known you were a virgin, I'd have taken more time." + She replied, "If I had known you had more time, I'd have taken off +my pantyhose." +%% +A young lady friend of mine just swallowed a razor blade... +She performed a tonsillectomy, an appendectomy, a hysterectomy, +three circumcisions, and cut off the finger of a casual friend. +%% + A young man asked his father to lend him $50 for a blowjob, +whereupon his father solemnly replied, "When I was young we used to +settle for a kiss." + The son retorted, "OK, how about $50 for a long low kiss?" +%% +ADULTERY: + Putting yourself in someone else's position. +%% +AI hackers do it robotically. +%% +AI hackers do it with robots. +%% +AMBITION: + An ant crawling up an elephant's leg with rape on his mind. +%% +ANXIETY: + The first time you can't do it a second time. +PANIC: + The second time you can't do it the first time. +%% +APL hackers take all they want. +%% +ARKANSAS: + Where the men are men, so are the women and the sheep run scared. +%% +Aboard the good ship Venus, The cabin boy, the captain's joy, +The mast it was a penis, A cunning little nipper, + Her figurehead They filled his ass, + A whore in bed, With broken glass, +Good grief you should have seen us! And circumcized the skipper. + +The first mate's name was Higgins, The captain's daughter Mabel, +And Higgins was a biggins, They screwed when they were able, + Once round the deck, They nailed her tits, + Twice up the mast, Those nasty shits, +And the rest was used for riggins'! Right to the captain's table. + +The engineer's name was Carter, The second mate's name was Andy, +And Carter was a farter, By God, he was a dandy, + When the wind wouldn't blow, They broke his cock, + And the ship couldn't go, With chunks of rock, +Carter the farter would start her! For conking in the brandy! +%% +Achilles' Biological Findings: + (1) If a child looks like his father, that's heredity. + If he looks like a neighbor, that's environment. + (2) A lot of time has been wasted arguing over what came first + -- the chicken or the egg. It was undoubtedly the rooster. +%% +Admittedly, there are a lot of things that are better than sex, +and a lot more that are worse; but there's nothing quite like it... +%% +After an evening at the theatre and several nightcaps at an intimate little +bistro, the young man whispered to his date, "How do you feel about making +love to men?" + "That's MY business," she snapped. + "Ah," he said. "A professional." +%% +After cocktails in the Oak Room, the graying millionaire took the blond, +attractive, wholesome, winning young woman up to his suite. They chatted +for a while, and then kissed on the couch. A little fondling, some feeling +and petting ... to which the young lady lent herself shyly ... and then they +were in the wide, cool bed, naked together. They chatted more, established +a communion, a rapport the older man considered remarkably gratifying. The +girl seemed sympatico, innocent, good. + "Yes, that was it," he thought, "essentially good. Why, she could +be my own daughter." He smiled into the young girl's deep blue eyes. + "Tell me," he asked, his hand on her breast, "What's a nice girl +like you doing in a hotel like this?" + "Oh, about $2000 a week, with tips." +%% +After rushing into a drugstore, the nervous young man was obviously +embarrassed when a prim thirty-ish woman asked if she could serve him. + "N-no," he stammered, "I'd like to see the druggist." + "I'm the druggist", she replied cheerfully. + "Oh.. well, uh, it's nothing important," he said, and turned to leave. + "Young man," said the woman, "my sister and I have been running this +drugstore for nearly ten years. There is nothing you can tell us that will +embarrass us. + "Well, all right," he said. "I have this awful sexual hunger that +nothing will appease. No matter how many times I make love, I still want to +make love again and again. Is there anything you can give me for it?" + "Just a moment," said the woman, "I'll have to discuss this with my +sister." + A few minutes later, she returned. "The best we can do," she said, +"is room and board and a half-interest in the business." +%% +After spending a forbidden night on the town, two young nuns were trying +to sneak through the fence surrounding their Convent. + "You know," giggled one as she held the wire apart for the other +to crawl through, "I feel like a Marine." + "So do I," the other nun sighed, "but where are we going to +find one at three in the morning?" +%% +Alex came home from a business trip to Chicago and found no one home but his +daughter Rose, who was crying bitterly. + "What's the matter, darling?" asked Alex. + "Mommy almost died last night," sobbed Rose. + "That's nonsense," said the father. "Why do you say that?" + "Well," said Rose,"you always told us that when we die we'll see God; +so when I heard Mommy moaning last night I rushed to her bedroom and she was +screaming, "Oh God, here I come," and she would have but Uncle Jerry held her +down." +%% +"Algorithms" is an anagram for "Hilt orgasm". Maybe this explains +the popularity of this field of study in computer science. +%% +All I really want in life is a piece and some quiet. +%% +All a hacker needs is a tight PUSHJ, +a loose pair of UUOs, and a warm place to shift. +%% +All things dull and ugly, Each little snake that poisons, +All creatures short and squat, Each little wasp that stings, +All things rude and nasty, He made their brutish venom, +The Lord God made the lot; He made their horrid wings. + +All things sick and cancerous, Each nasty little hornet, +All evil great and small, Each beastly little squid. +All things foul and dangerous, Who made the spikey urchin? +The Lord God made them all. Who made the sharks? He did. + +All things scabbed and ulcerous, +All pox both great and small. +Putrid, foul and gangrenous, +The Lord God made them all. + -- Monty Python +%% +Always talk to your wife while you're +making love... if there's a phone handy. +%% +America cannot be sold a can of beer without +being offered a piece of pussy along with it. + -- Julius Lester +%% +An 11 is a 10 who doesn't have headaches. +%% + An Aggie was appointed ambassador to Japan. Two weeks before +officially reporting to the embassy, he went from geisha house to geisha +house. While making love to a geisha girl, he heard her repeat, "Yaki-san, +yaki-san." + Right away the Aggie thought to himself, "I've learned my first +Japanese word. It must be an expression of joy." + When he reported to the embassy, he received his first assignment, +which was to escort the prime minister of Japan around the golf course. +After having played a couple of holes, the prime minister teed-off and made +a hole-in-one. The prime minister jumped up and down shouting, "Bonsai! +Bonsai!" + Quickly, thinking that this was the perfect chance to show off the +new Japanese word that he'd learned, the Aggie exclaimed, "Yaki-san, +yaki-san!" + The prime minister turned to the Aggie and exclaimed, "What do you +mean, wrong hole?" +%% + An American tourist went into a restaurant in a Spanish provincial +city and asked to be served the specialty of the house. When the dish +arrived he asked what kind of meat it contained. "These, senor," explained +the waiter in halting English, "are the cojones -- the, what you say, the +testicles -- of the bull killed in the ring today. + The tourist gulped but tasted the dish and found it delicious. +Returning the following evening, he asked for the same dish. When it was +served, he commented to the waiter, "But these -- these cojones -- are +much smaller than the ones I had yesterday." + "True, senor, but the bull -- he does not ALWAYS lose." +%% +An Army travels on her stomach. +%% + An Israeli soldier was checking travelers' papers on a road, when a +man and a heavily pregnant woman on a donkey came by. "Your names please?" +said the the soldier. + "My name is Mary," said the woman. + "And mine is Joseph," said the man. + "Oh," said the soldier, a little taken aback, "And where are you +going?" + "To Bethlehem." + "Your reason for going there?" + "To pay our taxes to the government." + "Tell me," said the soldier, "are you going to name the baby Jesus?" + "Of course not," said the woman, "What do you think we are, Puerto +Ricans?" +%% + An old maid wanted to travel by bus to the pet cemetery with the +remains of her cat. As she boarded the bus, she whispered to the driver, +"I have a dead pussy." + The driver pointed to the woman in the seat behind him and said, +"Sit with my wife. You two have a lot in common." +%% +And the northern lights commenced to glow. +And she said, with a tear in her eye, +"Watch out where the huskies go, and don't you eat that yellow snow." + -- Frank Zappa, "The Story of Nanook and the Fur Trapper" +%% +"And what do you two think you are doing?!" roared the husband, as he came +upon his wife in bed with another man. The wife turned and smiled at her +companion. + "See?" she said. "I told you he was stupid!" +%% +Another stupid gay joke!!! + You see, this gay man walks into a Texas bar and orders a strawberry +daquiri. The bartender looks him over with amusement and says: "We don't +serve your kind, buddy, why don't you get out of here before the boys come +in and kick your ass?" + The guy whimpers a little and lisps, "Pleasse misssture I am soooo +thurstay...." + Well, the bartender feels somewhat sorry for him and hands him a beer +on the house on the condition that he drink it in the back and leave as soon +as he's done. A little while later, a hulking cowboy walks in and up to the +bar. He slams his fist on the bar and hollers, "I'm so thirsty, I could +lick the sweat off of a bulls' balls!" + From the back of the bar comes the cry... "Moo, moo, buckaroooooo!!!" +%% +Another nun joke!!! + You see, three nuns were walking down the street, when suddenly +this flasher jumped out in front of them and opened his trench coat, +exposing his all to the sisters. Well, two of the nuns had strokes right +there, but the third nun wouldn't touch it. +%% +Any girl who believes that the way to a man's heart is through +his stomach is obviously setting her standards too high. +%% + "Anything else, sir?" asked the attentive bellhop, trying his best +to make the lady and gentleman comfortable in their penthouse suite in the +posh hotel. + "No. No, thank you," replied the gentleman. + "Anything for your wife, sir?" the bellhop asked. + "Why, yes, young man," said the gentleman. "Would you bring me +a postcard?" +%% +Apple owners do it with mice! +%% +As for Carter being for registration but against the draft, isn't that +sort of being like for putting it in and not taking it out? Even if it +was possible not to follow through, you'd still be getting screwed. +%% +As long as your ass is pointed at the ground, don't fuck with me. +%% +As near as I can tell, you're not any crazier +than the average asshole on the street. + -- R.P. McMurphy, "One Flew Over the Cuckoo's Nest" +%% +Ass, grass or gas... nobody rides for free! +%% +At her annual checkup, the attractive young woman is told by the doctor that +it's necessary to take her temperature rectally. She agrees and bends over +the examining table, but a few seconds later says indignantly, "Doctor, that's +NOT my rectum!" + "Madam," says the doctor, "that's not my thermometer!" + Just then, the woman's husband, hearing her voice, comes into the +room. "Just what the hell is going on here?" he demands. + "I'm taking your wife's temperature," the doctor cooly replies. + "Okay, doc, you know best," says the husband as he picks a scalpel +off the doctor's desk, "but when that thing comes out, it better have +numbers on it!" +%% +Australia's a lovely land +It's full of bonza blokes, +Sheilas, beer and no-one's queer +Except in Pommie jokes. + +Australians are lovely chaps +They're God's own chosen race. +If they ever see a fairy Pom +They'll smash him in the face. + +Australians like dressing up +In skirts and having fun +And that's all we were doing +When the Vice Squad came along. + -- Monty Python +%% +B4 I4Q, RU/18 QT 3.14 +%% +BALTIMORE: + Where the women wear turtleneck + sweators to hide their flea collars. +%% +BEAT ME, BITE ME, WHIP ME, FUCK ME!!! +%% +BEEF STROGANOFF: + A bull masturbating. +%% +BETTER LATE THAN NEVER: + The single girl's motto. +%% +BOHICA: + Bend over, here it comes again. +%% +BRUNETTE BUSH: + The dark side of the moon. +%% +Back in the good ole days in Texas, when stagecoaches and the like was +popular, there were three people in a stagecoach one day: a true red- +blooded born and bred Texas gentleman, a tenderfoot city-slicker from +back East, and a beautiful and well-endowed Texas lady. The city-slicker +kept eyeing the lady, and finally he leaned forward and said, "Lady, I'll +give you $10 for a blow job." + The Texas gentleman looked appalled, pulled out his pistol, and +killed the city-slicker on the spot. The lady gasped and said, "Thank +you, suh, for defendin' mah honor!" + Whereupon the Texan holstered his gun and said, "Your honor, hell! +No tenderfoot is gonna come 'round here raisin' the price of women in Texas!" +%% +Balls Law: + The angle of the dangle is directly proportional to the heat + of the meat provided that the thrusts of the busts are constant. +%% +Bankers do it with interest (penalty for early withdrawal). +%% + Barbra Walters was doing a documentary on the customs of American +Indians. After a tour of a reservation they were on, she was curious as to +the number of feathers in the headdresses. She asked a brave who had only +one feather in his headdress. His reply was, "Me have only one squaw, me +have only one feather." She asked another brave, feeling the first fellow +was only joking. This brave had four feathers in his headdress. He replied, +"Me have four feathers, because me sleep with four squaws." + Still not convinced the number of feathers indicated the number of +squaws involved, she decided to interview the Chief. Now the Chief had a +headdress full of feathers which, needless to say, amused Ms. Walters. +Ms. W: "Why do you have so many feathers in your headdress?" +Chief: "Me Chief, me fuck-em all, big, small, fat, tall, + me fuck-em all." +Ms. W: "You ought to be hung!" +Chief: "You damned right, me hung. Big like buffalo, long like snake." +Ms. W: "You don't have to be so hostile!" +Chief: "Hoss-style, dog-style, wolf-style, any-style, me fuck-em all." +Ms. W: "Oh, dear!" +Chief: "No deer, me no fuck deer. Asshole too high and fuckers run + too fast." +%% + Before he went off to the wars, King Arthur locked his lovely wife, +Guinevere, into her chastity belt. Then he summoned his loyal friend and +subject Sir Lancelot. "Lancelot, noble knight," said Arthur, "within this +sturdy belt is imprisoned the virtue of my wife. The key to this chaste +treasure I will entrust to only one man in the world. To you." + Humbled before this great honor, Lancelot knelt, received his king's +blessing and took charge of the key. Arthur mounted his steed and rode off. +Not half a mile from his castle, he heard hoofbeats behind him and turned to +see Sir Lancelot riding hard to catch up with him. + "What is amiss, my friend?" asked the king. + "My lord," gasped Lancelot, "you have given me the wrong key!" +%% +Beneath this stone a virgin lies, +For her life held no terrors. +A virgin born, a virgin died: +No hits, no runs, no errors. +%% +Beneath this stone lies Murphy, +They buried him today, +He lived the life of Riley, +While Riley was away. +%% +Better a sister in a whorehouse than a brother on a Honda. +%% +Beware of a tall dark man with a spoon up his nose. +%% +Bill and Jim were walking home from work. As they walked along, they +discussed their wives' spending habits. "I don't understand how women +can spend so much money," Bill exclaimed. "I mean, understand, she +don't drink, and she's got her own pussy!" +%% + Bill had just returned from a week of honeymooning, and his best +friend asked him how it went. + "The first night we did it nine times," Bill said. "The second +night, eight times. The third night, seven times. The fourth night, six +times. The fifth night, five times. The sixth night, four times, and the +last night, nothing!" + "Nothing?" his pal asked. "How come?" + "Hey, you ever tried putting a marshmallow in a parking meter?" +%% +Bitch, bitch, bitch -- +That's all I ever hear, +Ever since the dog ate the baby, +"Get rida the dog, get rida the dog." +%% +Blow it out your ass! +%% +Bridget O'Flaherty McHugh +Held venal traffic with a gnu. +Mistaking fore for aft one morn +Impaled herself upon its horn. + +Moral: Those who seek high ends should shun + our furred and feathered friends. +%% +Bringing your mate to a convention is like taking a game warden hunting. +%% +Build a better mousetrap, the saying goes -- and with the brassiere, Yankee +Ingenuity did exactly that. But their true stroke of genius was the new bait. +The old fashioned mousetrap was loaded with cheese; nobody cares much about +cheese, except mice. But when American know-how reloaded the brassiere with +tits, every heterosexual male in the country was hopelessly trapped. + -- Alan Sherman, "The Rape of the A*P*E*" +%% + But among the children of the Great Society there were those whose +skins were black. And lo! Their portion was niggardly, and of the fatted +calf they were sucking hind teat... + Now it came to pass that a prophet rose up amongst them, and they +called him King. And he went unto Pharaoh and said, "Let my people go to +the front of the bus." + But Pharaoh answered: "In the fullness of time and with all +deliberate speed shall this thing come to pass. When ye shall prove +yourselves worthy, shall ye have your just portion -- yea, verily, like +unto a snowball in Hell." +%% + But the reward of a successful collaboration is a thing that +cannot be produced by either of the parties working alone. It is akin +to the benefits of sex with a partner, as opposed to masturbation. The +latter is fun, but you show me anyone who has gotten a baby from playing +with him or herself, and I'll show you an ugly baby, with just a whole +bunch of knuckles. + -- Harlan Ellison +%% +But they'll never mechanize me -- not me! +Said Charlotte, the Louisville harlot. + -- S.I. Hayakawa +%% +CAD: + A man who doesn't tell his wife + that he's sterile until she's pregnant. +%% +CHRISTIAN: + One who believes that the New Testament is a divinely inspired + book, admirably suited to the spiritual needs of his neighbor. + -- Ambrose Bierce +%% +CHRISTIAN: + One who follows the teachings of Christ in so far + as they are not inconsistent with a life of sin. +%% +CINDERELLA 10: + A woman who sucks and fucks 'til midnight and + then turns into a pizza and a six-pack. +%% +CLONE OF MY OWN (to Home on the Range) + +Oh, give me a clone +Of my own flesh and bone + With the Y chromosome changed to X. +And when she is grown, +My very own clone, + We'll be of the opposite sex. +Chorus: + Clone, clone of my own, + With the Y chromosome changed to X. + And when we're alone, + Since her mind is my own, + She'll be thinking of nothing but sex. + -- Randall Garrett +%% +COCK-SUCKER: + Someone who got caught doing what you got away with. +%% +COITUS INTERRUPTUS: + A jerky movement following the words (by either sex partner) + "I want to have your child." +%% +COLD: + When your dog sticks to the fire hydrant. +%% +COMPUTER PERSONALS: + SWBiM, 29. Gr/Fr/Mild English. + Have moose, hoop. Sincere inquiries + only. Discreet. Fortune Box 1910. +%% +COMPUTERFIRM NYMPHOMANIAC: + Hot Apple pie. +%% +CONFUSION: + Father's Day in San Francisco. +%% +CONTINENTAL BREAKFAST: + A roll in bed with some honey. +%% +COORS: + Like making love in a canoe -- fucking close to water. +%% +CORPORATE VIRGIN: + A woman who's new to the firm. +%% +COURAGE: + Two cannibals having oral sex. +%% +COYOTE LOVE: + Coyote love is a nebulous term. Basically, what it involves is + the taking of a member of the preferred sex home from a singles + bar. Then, when you wake up the next morning, they're sleeping + on your arm. So, rather than wake them up as you escape, you + chew off your arm at the shoulder. +%% +Call for Ms. Lingus, Ms. Connie Lingus... +%% +Came a bellow that echoed for miles. + Said the rector, "My gracious, + Has Father Ignatius +Forgotten the Bishop has piles!?" +%% +Captain Hook died of jock itch. +%% +"Carefully study these two enlarged photographs on display, Mr. Rafferty," +the attorney for a politician suing a newspaper for libel instructued his +client on the witness stand, "and indicate which is your ass and which is +a hole in the ground." +%% +Chaste makes waste. +%% +Chipmunks roasting on an open fire +Jack Frost ripping up your nose +Yuletide carolers being thrown in the fire +And folks dressed up like buffaloes +Everybody knows a turkey slaughtered in the snow +Helps to make the season right +Tiny tots with their eyes all gouged out +Will find it hard to see tonight +They know that Santa's on his way +He's loaded lots of guns and bullets on his sleigh +And every mother's child is sure to spy +To see if reindeer really scream when they die +And so I'm offering this simple phrase +To kids from one to ninety two +Although it's been said many times, many ways +Merry Christmas, Merry Christmas, Merry Christmas, Fuck you!! +%% +Chorus: + I don't want to join the army, I don't want to go to war, + I'd rather sit around, pickin' dillies off the ground, + And livin' off the favors of a 'igh-born lady. + I don't want a bullet up me ass 'ole, + I don't want me pecker blown away, + I'd rather live in England, in jolly, sunny, England, + And fornicate me bloody life away!! + +Monday I touched her on the ankle, +Tuesday I touched her on the knee, +And Wednesday after Mass, I lifted up her dress, +And Thursday I saw you know what, +Friday I put me hand upon it, +Saturday she gave me balls a tweak [tweak, tweak] +And Sunday after supper, I ran me fucker up 'er, +And now she pays me forty quid a week! +Oh, blimey... + +[chorus] +%% +Christmas comes but once a year, +A time for love and laughter; +You can come much more than that, +But you have to clean up after. +%% +Cleveland still lives. God MUST be dead. +%% +Close the door, let me give you what you've been waiting for!! +%% +Cocaine's a joke! + (Who's got the next line?) +%% +Coito ergo sum +%% +Coitus is punishment for the happiness of being together. +Live as ascetically as possible... that is the only possible +way for me to endure marriage. But she? + -- Franz Kafka +%% +College is like a woman -- you work so hard to get in, +and nine months later you wish you'd never come. +%% +Communists do it without class. +%% +Computer scientists are programmed to do it by macro insertion. +%% +Confucious say: + man who screws near graveyard is fucking near dead. + man who lay girl on hill, not on level. + man who fishes in other man's well often catch crabs. + boy who play with himself pulls boner. + woman who cooks carrots and pees in same pot very unsanitary. + man who marry girl with no bust has right to feel low down. + man who sleeps with old hen finds it's better than pullet. + man with hole in pocket feel cocky all day. +%% +Confucious say: + woman who ride bicycle peddle ass around town. + fool man climb tree to get cherries; wise man spread limbs. + woman who fly upside down in airplane have big crack up. + man who live in glass house should bathe in the basement. + man who make love on ground have piece on Earth. + man who lose key to girlfriend's apartment get no new key. + man who fights with wife, gets not peace at night. + child conceived in back seat of car with automatic transmission + turn out to be shiftless bastard. +%% +Confucius say: + Man who go to bed with sex problem wake up with solution in hand. +%% +Copa-ulation: +(to the tune of Copacabana) + +Her name was Lola, she was a bimbo, with yellow streamers in her hair, +She wore see-through underwear, she'd go to discos, and do the go-go, +And while she tried to be star, Tony jacked off on the bar, +And when the dance was done, his hand was full of come, +His favorite drink is cream in coffee, +Won't you order one? + +At the Copa, Copa-ulation ... + +Her name was Lola, she was a show-girl, +But that was thirty years ago, when she still could slurp and blow, +Now she's a sado, but not for Tony, still in her chains and leather gown, +She ties Rico to the ground, and fucks that boy half-blind, +But Rico, he don't mind, there are whips and a lot of beatings, +But a real good time ... +%% +Cox's philosophy: + Life's a bitch, then you die. +%% +Cunnilingus is next to cleanliness. +%% +Curiousity killed the cat, but satisfaction brought her back. +%% +DIAPHRAGM: + A childproof cap. +%% +DICKER: + What you do to your wife if arguing doesn't work. +%% +DIVORCE: + A change of wife. +%% +DYKE: + A woman who kick-starts her vibrator. +%% +DYSLEXICS OF THE WORLD, UNTIE! +%% +Dallas still lives. God MUST be dead. +%% +Dammit, how many times do I have to tell you? +FIRST you rape, THEN you pillage!! +%% + "Darling," he breathed, "after making love I doubt if I'll +be able to get over you -- so would you mind answering the phone?" +%% + "Darling", said the young bride, "tell me what's bothering you. +We promised to share all our joys and sorrows, remember?" + "But this is different," protested her husband. + "Together, darling," she insisted, "we will bear the burden. +Now tell me what our problem is." + "Well," said the husband, "we've just become the father of a +bastard child." +%% + "Darling," she whispered, "will you still love me after we are +married?" + He considered this for a moment and then replied, "I think so. +I've always been especially fond of married women." +%% +David was just a shepherd who liked to get his rocks off in leather. +%% +Dear Abby: + I have two brothers. One was sent to the electric chair when I was +a child. My mother died in an insane asylum. My father is a pimp and my +sister is a very successful and highly paid prostitute. My other brother +is a graduate student attending Purdue University. + Recently I met a wonderful girl who has just been released from prison +for murdering her illegitimate child with a Zip-loc sandwich bag. We're very +much in love and want to be married after her venereal disease is cured. + My problem is this: should I tell her about my brother at Purdue? + Sincerely, + Undecided. +%% +Dear Abby: + I just met the most terrific girl and we get along fabulously. I +think she's the one for me. There's just one problem: I can't remember +from our first date if she told me she had TB or VD. What should I do? + --Confused + +Dear Confused: + If she coughs, fuck her. +%% +Dear Lord, observe this bended knee +This visage meek and humble, +And hear this confidential plea +Voiced in reverent mumble: + Give me Shylock, give me Fagin + But O God spare me Ronald Reagan! + -- Ansel Adams +%% + Desperate about the state of her social life, a young woman resorted +to the Personal Ads in the back of her local paper. In the ad she made it +quite clear that what she was advertising for was an expert lover; she already +had plenty of sensitive friends and meaningful relationships and what she +now wanted was to get laid, to put it bluntly. Phone calls started coming +in, with each caller testifying to his sexual prowess, but none quite struck +the young woman's fancy. Until one night her doorbell rang. Opening the door +she found a man with no arms or legs, who informed her that he was there in +response to her advertisement. "I'm terribly sorry," she stammered, "but my +ad was quite explicit. I'm really looking for something of a sexual expert, +and you... uh... don't have all the..." + "Listen," the man interrupted her, "I rang the doorbell, didn't I?" +%% +Desperate because her husband hadn't made love to her in months, a lonely +housewife finally mustered her courage and went to their doctor for advice. +The doctor was very sympathetic and wrote out a prescription for pills that +were guaranteed to rekindle the husband's ardor in a big way. "They'll make +him horny as hell," the doctor confided, "but they're very potent, so just +put one in whatever he's drinking." + Upon arriving home, the woman left the pills on the kitchen counter +and dashed off to the supermarket. It didn't take long before the cat jumped +up, knocked them over onto the floor, and ate a couple, as did the family +dog. And when the husband got home with a headache, he took a few thinking +they were aspirin. + When the housewife returned, she was horrified to see the dog humping +the cat and the cat jumping all over the dog, but even stranger was the sight +of her husband with his penis inside the pencil sharpener on the counter. +"What in heaven's name are you doing, John?" she cried. + "See that mosquito?" he replied. +%% +Hear about... + the French soldier who kissed his wife's + cheeks before he went to the front? +%% +Hear about... + the girl with the big wardrobe who started with just a little slip? +%% +Hear about... + the nurse they thought had drowned + until they found her under the doc? +%% +Did you know that there are 71.9 acres of nipple tissue in the U.S.? +%% +Distributed Systems people do it loosely coupled. +%% +Do something big -- fuck a giant. +%% +"Do you cheat on your wife?" asked the psychiatrist. +"Who else?" answered the patient. +%% +Do you smoke after sex? +Why, do you know, I've never looked! +%% +Doctors take two aspirin and do it in the morning. +%% +Does he treat your breasts like unripe grapefruit? Who needs him? + -- `J', "The Sensuous Woman" +%% +Doing business with the government is like fucking sheep. +It's easy, but it's not very satisfying. +%% +Don't let your mouth write no check that your tail can't cash. + -- Bo Diddley +%% +Don't look now -- your office mate is a pederast!!! +%% +Don't look now, but your mother is having sex with a horse. +%% +Draft beer, not boys! +%% +Dry fucking: that's man on top of woman, the action is the same as fucking, +but you're dressed. It's great for the girl... you're hitting and rubbing +exactly the area that you ought to be... I still like that. + -- Grace Slick +%% +Due to a mixup in urology, orange juice will not be served this morning. +%% + During a session with a marriage counselor, the wife snapped at her +husband: "That's not true, I do enjoy sex!" Then, turning to the counselor, +she added: "But this fiend expects it three or four times a year!" +%% +Dyslexia means never having to say that you're ysror. +%% +EE's do it without shorts. +%% +EMBARRASSMENT: + Finding out your German Shepherd has the clap. +%% +Eat shit and die a virgin! +%% + Ed, a traveling salesman, had his car break down in the middle of a +blizzard. He trudged to a nearby farmhouse where the farmer told him that, +while they were short of beds, he could sleep with his daughter. She proved +to be eighteen and beautiful. So they went to bed, and shortly, Ed made a +pass at the daughter. "Stop that!" she said. "I'll call my father." + He desisted. But half an hour later he made another attempt. "Uh, +stop ... that," she said. "I'll call my father." + But she moved closer to him, so he made a third try. This time, no +protest, no threat. Just as Ed, satisfied, was about to drowse off, she +tugged at his pajama sleeve. "Could we do that again?" she asked. + Ed obliged, and this time fell asleep only to be awakened by the +tug at his sleeve. "Again?" + And again Ed obliged. But when his sleep was once more interrupted +by the tugging at his pajama sleeve, Ed indignantly pulled it away from her +and mumbled, "Stop that! Or I'll call your father." +%% +Eleven reasons a cucumber is better than a man: + 1) Cucumbers can stay up all night, + and you won't have to sleep in the wet spot. + 2) Cucumbers don't play the guitar and try to find themselves. + 3) You won't find out later that your cucumber + ...is married + ...is on penicillin + ...likes you -- but loves your brother! + 4) A cucumber won't care what time of the month it is. + 5) A cucumber never wants to get it on when your nails are wet. + 6) Cucumbers don't say "Let's keep trying until we have a boy". + 7) Cucumbers won't tell you size doesn't count. + 8) A cucumber won't leave you for a cheerleader or an ex-nun. + 9) Cucumbers don't fall asleep on your chest or drool on the pillow. + 10) Cucumbers don't care if you make more money than they do. + 11) With a cucumber, the toilet seat is always the way you left it. +%% +Evangelists do it with Him watching. +%% +Ever wondered why you always run out of breath when you throw up? +Ah, but a man's retch should exceed his gasp, else what's a heaving for? +%% + Every morning, the crowd on Coney Island beach was startled to see +a jogger with the build of a pro football player but a head the size of a +baseball. Finally, some brave young man got up the nerve to stop him and +ask, "What happened to give you such a small head?" + The jogger sadly told the story of finding a magic lamp on the beach, +which produced a beautiful genie when rubbed. The genie said, "I now give +you one wish. Do you want a quick fuck or a little head?" +%% +Everyone in the office is welcome to join the group going to the Columbus +Theater tonight. Meet in the lobby at 8:30. The films are "Blue Jennifer" +and "Hot Coed Cheerleaders". +%% + Everyone in the smart nightclub was amazed by the old gentleman, +obviously pushing 70, tossing off manhattans and cavorting around the dance +floor like a 20-year old. Finally curiousity got the best of the cigarette +girl. "I beg your pardon, sir," she said, "but I'm amazed to see a gentleman +of your age living it up like a youngster. Tell me, are all of your faculties +unimpaired?" + The old fellow looked up at the girl sadly and shook his head. "Not +all, I'm afraid." he said. "Just last evening I went nightclubbing with a +girlfriend -- we drank and danced all night and finally rolled into her place +about two A.M. We went to bed immediately, and I was asleep almost as soon +as my head hit the pillow. I woke around three-thirty and nudged my girl." + "Why, George," she said in suprise, "we did that fifteen minutes ago." + "So you see," the old boy said sadly, "my memory is beginning to +fail me." +%% +FALSIE SALESMAN: + Fuller bust man. +%% +FELT TIP: + Past tense for a breast examination! +%% +FEMALE: + Life support system for a pussy. +%% +FORNICATION: + Term used by people who don't have anybody to screw with. +%% +FUCKOFF: + The tie breaker at the Miss America Beauty Pageant. +%% +Fat dirty farts came spluttering out of your backside. You had an arse full +of farts that night, darling, and I fucked them out of you, big fat fellows, +long windy ones, quick little merry cracks... + -- James Joyce +%% +Fed some caviar to my girlfriend +She was a virgin tried and true +Now my girlfriend needs no urgin' +There ain't nothin' she won't do! + Caviar comes from a Virgin Sturgeon - + Virgin Sturgeon's a very fine fish. + Virgin Sturgeon needs no urgin' + That's why caviar is my dish! +Fed some caviar to my Grandpa +He was a man of ninety-three +Shrieks and screams were heard from Grandma +He had chased her up a tree! + (chorus) +%% +Fie for shame, +you lascivious, lewd, lecherous, +libidinous, lustful, licentious, dirty bum!! +%% +Fig Newton. +%% + "First, I'm going to buy you a few drinks and get you a little tight," +said the guy aggressively. + "Oh, no, you're not," said the girl. + "Then I'll take you to dinner at the most exclusive restaurant in +town." + "Oh, no, you won't." + "Then I'll take you to my apartment and mix up a pitcher of daiquiris." + "Oh, no, you won't." + "Then I'm going to make violent, mad, passionate love to you." + "Oh, no, you're not." + "And I'm not going to take any precautions either!" said the guy. + "Oh, yes, you are!!" said the girl. +%% +Floppy now, hard later. +%% +For children, a woman. +For pleasure, a boy. +For sheer ecstasy, a melon. +%% +For her first week's salary the gorgeous new secretary was given an +exquisite nightgown of imported lace. The next week her salary was +raised! +%% +For months the loving newlywed had asked his blushing bride to perform oral +sex on him, but to no avail. His sweet entreaties never worked, for she was +simply too innocent and inexperienced to even *think* of such a thing, let +alone attempt it. But a year of gentle persistence finally paid off, and +one night his darling nervously but lovingly performed the act. When it was +over, she looked deeply into his eyes, blushed, and asked, "How was I, +sweetheart?" + He looked at her and replied, "How should I know -- I'm no +cocksucker!" +%% +For the man who has everything ... penicillin IV. +%% +Fortune's Guide to Movies: +G: No girl. +PG: The hero gets the girl. +R: The bad guy gets the girl, then the good guy gets the girl. +X: The hero still gets the girl in the end, but he's never sure + which end it will be. +XXX: Everybody gets the girl. +%% + Friends were surprised, indeed, when Frank and Jennifer broke their +engagement, but Frank had a ready explanation: "Would you marry someone who +was habitually unfaithful, who lied at every turn, who was selfish and lazy +and sarcastic?" + "Of course not," said a sympathetic friend. + "Well," retorted Frank, "neither would Jennifer." +%% +From the outset, the blind date was a fiasco and it was intensified by the +fact that the fellow was too insensitive and ego-ridden to realize it. The +moment of truth came in the supper club as he clutched the girl's thigh and +whispered, + "Baby, how's about our cutting out to my pad +so I can slip you nine inches?" +There was a moment of silence, and then the girl said, + "You know, I really don't think you could get it up +three times in a row!" +%% +Fuck art; let's dance! +%% +Fuck off and die! +%% +Fuck'em if they can't take a joke! +%% +GAY: + One who'd rather swish than fight. +%% +GEMINI (May 21 - June 20) + You are a quick and intelligent thinker. People like you because +you are bisexual. However, you are inclined to expect too much for too +little. This means you are cheap. Geminis are known for committing incest. +%% +GET OFF THE FUCKING SYSTEM THIS INSTANT, YOU ASSHOLE!!!! +%% +GLEE CLUB GROUPIE: + A girl into choral sex. +%% +GREAT LOVER: + A man who can breathe through his ears. +%% +Gross, adj.: + When your bloody mary still has the string in it. +%% +Gross, adj.: + When your grandmother kisses you goodnight and + slips you some tongue. +%% +Gynecologist, n: + Someone who spends their time spreading old wives' tails. +%% +Gardeners do it in raised beds. +%% +George Washington not only chopped down his father's cherry tree, but he +also admitted doing it. Now, do you know why his father didn't punish him? +Because George still had the axe in his hand. +%% +Getting an education at the University of California +is like having $50.00 shoved up your ass, a nickel at a time. +%% +Girls are like pianos. When they're not upright, they're grand! +%% +Girls would never stay out late if guys didn't make them. +%% +Give me Librium or give me Meth. +%% +Go out with girls Dutch treat -- pay for dinner, drinks, +and the movie, and the rest of the evening is on her. +%% + God built a compelling sex drive into every creature, no matter +what style of fucking it practiced. He made sex irresistibly pleasurable, +wildly joyous, free from fears. He made it innocent merriment. + Needless to say, fucking was an immediate smash hit. Everyone +agreed, from aardvarks to zebras. All the jolly animals -- lions and +lambs, rhinoceroses and gazelles, skylarks and lobsters, even insects, +though most of them fuck only once in a lifetime -- fucked along +innocently and merrily for hundreds of millions of years. Maybe they +were dumb animals, but they knew a good thing when they had one. + -- Alan Sherman, "The Rape of the A*P*E*" +%% +God is a polythiest. +%% +God is an atheist. +%% +God is not dead! He's alive and autographing bibles at Cody's. +%% +God is not dead -- he's been busted. +%% +God isn't dead, He's just trying to avoid the draft. +%% +God isn't dead, he just couldn't find a parking place. +%% +God made the world in six days, and was arrested on the seventh. +%% +God must love assholes -- She made so many of them. +%% +God wanted to have a holiday, so He asked St. Peter for suggestions on +where to go. + "Why not go to Jupiter?" asked St. Peter. + "No, too much gravity, too much stomping around," said God. + "Well, how about Mercury?" + "No, it's too hot there." + "Okay," said St. Peter, "What about Earth?" + "No," sighed God, "They're such horrible gossips. When I was +there 2000 years ago, I had an affair with a Jewish woman, and they're +still talking about it." +%% +Good day for water sports. Take a bath with a friend. +%% +Grain grows best in shit. + -- U.K. LeGuin +%% +Gravity is a myth, the Earth sucks. +%% +HACKER: + A master byter. +%% +HAGGIS: + Haggis is a kind of stuff black pudding eaten by the Scots and + considered by them to be not only a delicacy but fit for human + consumption. The minced heart, liver and lungs of a sheep, calf + or other animal's inner organs are mixed with oatmeal, sealed + and boiled in maw in the sheep's intestinal stomach-bag and... + [Excuse me a minute. Ed.] +%% +HAPPINESS: + Having your Herpes (Type II) test come back negative. +%% +HENPECKED HUSBAND: + One who's afraid to tell his pregnant wife that he's sterile. +%% +HERMIT: + A man who'd rather get off by himself. +%% +HERPES: + The final proof that 'tis better to + give than to receive. Much better. +%% +HEY KIDS! ANN LANDERS SAYS: + A great way to prevent the tragedy of unwanted pregnancy is to +become a homosexual. Every year, millions of young men and women, just +like you, are making the clean change to worry-free homosexuality. +They're having more sex than ever, and more fun than ever. Send 50 cents +today for my leaflet "Gay sexual techniques". Be sure to specify the +male or female edition. +%% +HEY, KIDS! ANN LANDERS SAYS: + Masturbation isn't as simple as it looks. Do it right! +Send 50 cents for my illustrated booklet "Masturbation techniques +for the teenager". Be sure to specify the male or female edition. +%% +HEY KIDS! ANN LANDERS SAYS: + Remember, oral sex CAN cause pregnancy, unless you use an +oral contraceptive. See your family planning clinic today! +%% +HONOR: + Almost as good as in 'er. +%% +HOW TO REMOVE STAINS -- #28 + Semen stains can be removed from computer terminals with + Fantastik or the like. Use Windex on the glass however, and + be sure to turn the power off if you have to clean between + the keys. +%% +HYPOCRITE: + A man who says he likes cats, but won't eat pussy. +%% +Hackers do it bottom-up. +%% +Hackers do it with all sorts of characters. +%% +Hackers do it with bugs. +%% +Hackers do it with fewer instructions. +%% +Hackers have kernel knowledge. +%% +Hackers know all the right MOVs. +%% +Halt!! Who goes there, friend or enema? +%% +Handy hint: + A tea bag or two can be a dandy substitute + when you're out of tampons. +%% +Hang gliders come down very slowly. +%% +Hardly a pure science, history is closer to animal husbandry than it is to +mathematics, in that it involves selective breeding. The principal difference +between the husbandryman and the historian is that the former breeds sheep +or cows or such, and the latter breeds (assumed) facts. The husbandryman uses +his skills to enrich the future; the historian uses his to enrich the past. +Both are usually up to their ankles in bullshit. + -- Tom Robbins +%% +Harry came into work on Monday feeling absolutely fine, and so was astonished +when his secretary urged him to lie down on the sofa; even more so when his +boss took one look at him and ordered him to take the day, if not the week, +off. Even his poker buddies wouldn't have anything to do with him, insisting +that he go straight to bed. Finally, tired of resisting everyone's advice, +he went to see his doctor, who took one look at him and rushed over with +a stretcher. + "But doctor," he protested, "I feel fine." +Well, this was a puzzler, conceded the doctor, who proceeded to refer to the +enormous reference tomes behind his desk, muttering to himself. + "Looks good, feels good... No, you look like hell. Looks good, +feels terrible... Nah, you feel fine, right?" +Thumbing furiously through another volume, he said, + "Looks terrible, feels terrible... Nope, that won't do it either." +Finally, "Looks terrible, feels terrific... Aha!! You're a vagina!" +%% +Have you ever stopped to think what it would be like to have a woman President? +"I can't deal with the Russians today. Not now. I've got my period." + -- Steven Moore +%% +Having discovered the possibility that other creatures could be used +for sexual intercourse, early man was likely to have made many such +attempts... though it is doubtful that he was so sexually carnivorous +as the Christian and Jewish Adam, who, rabbinical interpreters of the +Old Testament tell us, had intercourse with every creature before God +finally hit upon the idea of woman and created Eve. + -- R.E. Masters +%% +He boil my first cabbage, make it awfully hot, +But when he put in the bacon, oooh, you know it overflow the pot. + -- Bessie Smith, "Empty Bed Blues" +%% +He carried me over the stream, striding through the current, his strong, +muscular, thighs scarcely hesitating as he sure-footedly forded the water. +But what was that bulge, small, oblong, solid, that might have been, say, +a pocket camera? + -- An Exciting Journey +%% +He drank with curvy Mable, +The pace was fast and furious, +He slid beneath the table, +Not drunk but merely curious. +%% +He had heard that a certain whorehouse had a reputation for the bizarre. +So he drove to the place and, once inside, asked the Madam if she had anything +unusual for him to try. "Things are pretty slow today," she said, "but I +do have one number you might enjoy." She went on to describe a New Jersey +hen that had been trained to do blow jobs. + "We've got her here, but only for the day." + The visitor could hardly believe it, but he paid the fee and went +into a room with a hen. After a frustrating hour of trying to force his +cock into the hen's mouth, he figured out that he was dealing with nothing +but a plain old chicken. He left. Thinking about it later, he decided +that he had had so much fun trying that he returned the few days later and +asked the Madam, "Do you have anything new today?" + "Come this way," she said, and led him to a dark room where a group +of men were looking through a one-way mirror. He saw that they were watching +a girl trying to make it with a dog. + "Wow!" he said to the man standing next to him. "This is really +great!" + The man replied, "Man, it ain't nothin'! You shoulda been here +a week ago and seen the guy with the chicken!" +%% +He used to kiss her on her lips, but it's all over now. +%% +He was so gay he'd never lean his ass on a baseball bat -- +scared it'd get serious. +%% +He wasn't much of an actor, he wasn't much of a Governor -- +Hell, they HAD to make him President of the United States. +It's the only job he's qualified for! + -- Michael Cain +%% +He who farts in church must sit in his own pew. +%% +He who findeth sensuous pleasures in the bodies of lush, hot, +pink damsels is not righteous, but he can have a lot more fun. +%% +He who sneezes without a handkerchief takes matters into his own hands. +%% +He: Am I... am I your first? +She: Well, honey, I could have sworn your face looked familiar... +%% +He: "Hey, Baby, I'd sure like to get in your pants!" +She: "No, thanks, I've already got one asshole in there now." +%% +Hear about the Californian terrorist that tried to blow up a bus? +Burned his lips on the exhaust pipe. +%% +Hear about the guy who had his vasectomy done by Sears? +Every time he gets a hard-on, the garage door goes up. +%% +Hear about the young lady raped in San Francisco? +By two men, one held her down while the other one did her hair. +%% +Hear the sad story of the Greek fisherman who got his upper torso +wedged into the porthole and couldn't get out to save his ass? +%% +Heard tell that the Iron Magnolia wanted to divorce ol' Jimmy. +Seems he's screwing everyone but her. +%% +"Heard you were moving your piano, so I came over to help." +"Thanks. Got it upstairs already." +"Do it alone?" +"Nope. Hitched the cat to it." +"How would that help?" +"Used a whip." +%% +Heisenberg may have done it. +%% + "Hello, Police Department." + "This is Thomas Parrish, 903 Sylvester Court. I've just been sexually +molested by a pervert, right here in my own home. It was horrifying!" + "Just remain calm, sir, and tell me about it." + "Well, the man came in the window wearing a ski mask. I was napping +on the bed, in just my pajamas, and the TV set was on so I didn't hear anything. +Suddenly he had his great big old callused hand over my mouth, holding me down. +I tried to scream... he was pulling my pants off. I was so frightened! He +held a knife to my throat and undressed so quickly. What could I do? I +couldn't stop him. He was huge. A great, hairy, beefy man, more than fifty +pounds heavier than I am, and hung like... Oh! it was terrible. He had an +erection, and he knelt on my shoulders and forced the awful thing down my +throat; forced me to suck it. Yes, officer! There was no escaping this man. +Finally, when I thought I would faint, he got off me and turned me over on +my tummy, forcing my legs apart with his knees, and oh! I'm so embarrassed to +say it, he put that huge thing... It must have been a foot long, and I don't +know how thick... into my... Just a minute." + "What's the matter, mister?" + "Listen, I have to hang up now, he's getting out of the shower." +%% +Hello, children!! + This is Uncle Dennis welcoming you to your own fortune. Hello. + Today we are going to hear a story, so sit right here on my lap + and we can all start. Comfortable? Ah, yes, ah... Ah? Ah!! + + One day, Rikki, the magic Pixie, went to visit Daisy Bumble in her + tumbledown cottage. He found her in the bedroom. Roughly he + grabbed her heaving ******* pulling her down on the bed and + hurriedly ripping off her thin *******. + + Old Nick, the Sea Captain was a rough tough jolly sort of fellow. + He loved the life of the sea and he loved to hang out down by the + pier where the men dressed as ladies ****** ** ******* ******* + ** ***** ********* **** ****** with a melon. + + Rumpletweezer ran the Dinky Tinky shop in the foot of the Magic + oak tree by the wobbly dum-dum tree in the shade of the enchanted + glen down in Dingly Dell. Here he sold contraceptives, ******** + and various appliances *** ******** *** ***** naked fun *** ***** + **** ******** ******* *** into six or seven pairs. +%% +Help Stamp Out Rape! (Say Yes.) +%% +Her kisses left something to be desired: the rest of her. +%% +Here's a toast to Screwy Dick, +The man who was born with a corkscrew prick. +He spent his life in a futile hunt, +To find a woman with a spiral cunt. +And when he did, he dropped stone dead, +'Cause the blasted thing had a left-hand thread! +%% +Here's to the girl that's sweet, +Here's to the girl that's true, +Here's to the girl in all our hearts... + +In other words, guys, what do you say we all go downtown for +the rest of the night? +%% +Here's to the woman beautiful and devine +she flowers every month bears fruit every nine +she's the only creature 'tween heaven and hell +can get the juice from a nut without cracking the shell. +%% +He's a son-of-a-bitch, but he's our son-of-a-bitch. + -- FDR on Nicaraguan dictator Anastasio Somoza +%% +He's gallantry personified, in fact, his brochures ought to +read satisfaction guaranteed, or your virginity returned intact. +%% +Hey baby! + How 'bout a brutal face fuck? +%% +Hire the handicapped -- they're fun to watch! +%% +Honest, officer, had I known my health was +in jeopardy, why, I'd never have lit one! +%% +How come if you're horny it's lust, but if she's horny it's affection? +%% +"How did you spend the weekend?" asked the pretty brunette + secretary of her blonde companion. +"Fishing through the ice," she said. +"Fishing through the ice? Whatever for?" +"Olives." +%% +How do you like the new America? We've cut the fat out of the +government, and more recently the heart and brain (the backbone was +gone some time ago). All we seem to have left now is muscle. +We'll be lucky to escape with our skins! +%% +Howard Cosell's biggest protrusion is his asshole. + -- John Valby +%% +"How'd you get that flat?" +"Ran over a bottle." +"Didn't you see it?" +"Damn kid had it under his coat." +%% +Hugh Hefner is a virgin. +%% +Did you hear about... + the plastic surgeon who hung himself? +%% +Q: Why do elephants wear springs on their feet? +A: So they can jump into trees and rape mice. + +Q: What is the most fearsome sound in the world to a mouse? +A: BOING, BOING!!! +%% +Did you hear about... + the butcher who dropped his cleaver and went home half-cocked? +%% +A sperm faced, alack and forsooth, +His moment of sexual truth. + He'd expected to fall + On a womb's spongy wall +But was dashed to his death on a tooth. +%% +Obscenity is a crutch for lazy Motherfuckers. +%% +Q: Why did the epileptic cross the road? +A: He couldn't help it. + +Q: What do you do if an epileptic has a seizure in the bathtub? +A: Throw in the dirty clothes and some laundry detergent. +%% + Well, this woman went to the butcher shop to get some ham for dinner. +She asked the butcher what kind of ham he recommended, and the butcher said, +"Well ma'am, we got some Damn ham here for $3.50 a pound..." Needless to +say, she was surprised at the butcher's language! The butcher, who was +reasonably astute, noticed the alarmed look on the woman's face, and quickly +justified himself. "No no, ma'am, I wasn't cursin', the NAME of this here +ham is "Damn ham". Amused, the woman requested some "Damn ham." + That night, before dinner, the woman took her husband aside and +explained what had happened at the butcher shop. He also was amused, and +suggested that they play a joke on their son. So, at dinner, after grace, +the man turned to his wife and said, "Honey, pass the damn ham." + Their son looked up, surprised. "WHOAH! Dad be gettin' hip! +How 'bout them mother-fuckin' potatoes?" +%% + One day a mother and daughter are walking around a farming community +and they see a stallion mounting a mare. The daughter takes in the scene and +turns to her mother. "Mommy, what are those two horses doing?" + Her mother hastily answered, "The horse on top hurt its hoof, and the +one on the bottom is carrying him back to the stable." + The daughter shook her head and sadly replied, "Isn't that just the +way it goes? Try to help someone and you get fucked." +%% +Women, can't live with them, can't leave +them by the curb when you're done with 'em. +%% +Anything more than three shakes is for fun. +%% +I never met a woman I couldn't drink pretty. +%% +You're not an alcoholic unless you go to the meetings. +%% +I may not be able to walk, but I drive from a sitting position. +%% +Some women achieve greatness, some have greatness thrust into them. +%% +There was a young woman called Pearl +Who quite resembled a churl; + When she asked a young man named Tex + Whether he would like to have sex, +"Certainly," quoth he, "Who's the girl?" +%% +Assassins do it from behind. +%% +When in calling, plain speaking is out; +When the ladies (God bless 'em) are milling about, +You may wet, make water, or empty the glass; +You can powder your nose, or the "johnny" will pass. +It's a drain for the lily, or man about dog +When everyone's drunk, it's condensing the fog; +But sure as the devil, that word with a hiss +It's only in Shakespeare that characters ____. + -- Ogden Nash +%% +Gorbachev woke up early one morning, and felt great. He walked over to his +window, threw back the curtains, and saw the sun coming up. He felt *so* +good, he crowed, "Good Morning Sun!", and was startled when a great booming +voice came back to him, "Good morning Comrade! Good morning to you and +the great Soviet Socialist Republic!". Of course, this surprised him, but +great politician that he is, he considers the political ramifications. +Gorbachev then woke up Reza and his closest aides, brought them into his +bedroom, and shouted out "Good morning, Comrade Sun!". Again a booming reply, +"Good morning, Comrade. Good morning to you and the rest of the Party!" +Everyone was quite excited about this, and Gorbachev sat down to his +day's work with a feeling of being destiny's favorite child. + Later, in the evening, he was preparing for the ballet. As he +dressed, he noticed that the sun was setting. Walking over to the window, +Gorbachev threw up the sash and again addressed the sun, "Good evening to +you, Comrade Sun!". Once more the great voice boomed out, "Fuck you, +asshole! I'm in the West, now!" +%% +If life's a piece of shit, Calculus III is the spoon. +%% +Yesterday is a memory, + Tomorrow is a vision, + Today is a bitch! +%% +Two golfers were being held up as the twosome of women in front of them +whiffed shots, hunted for lost balls and stood over putts for what seemed +like hours. + "I'll ask if we can play through," Bill said as he strode toward +the women. Twenty yards from the green, however, he turned on his heel +and went back to where his companion was waiting. + "Can't do it," he explained, sheepishly. "One of them's my wife +and the other's my mistress!" + "I'll ask," said Jim. He started off, only to turn and come back +before reaching the green. + "What's wrong?" Bill asked. + "Small world, isn't it?" +%% +Harold had never wanted a woman so much in his life, but upon overhearing +the 22-year-old beauty remark that he was too old and out of shape for +her. The determined septuagenarian immediately embarked upon a rigorous +self-improvement program. He had his face lifted, bought a toupee, ran +five miles every day, lifted weights and adopted a strict vegetarian diet. +Within months, the rejuvenated old man won the young woman's heart, and she +agreed to marry him. + On the way out of the chapel, however, Haroled was fatally struck +by lightning. Furious, he confronted Saint Peter at the pearly gates. "How +could you do this to me after all the pain I went through?" + "To be honest, Harold," Saint Peter sheepishly replied, "I didn't +recognize you." +%% +A group of scientists discovered an apelike creature in the jungle, which +they hoped would prove to be the missing link. The proof of their theory, +however, required that a human mate with the animal so that they could see +what characteristics the offspring would assume. Needing volunteers, the +scientists placed an ad in the paper: "$5000 to mate with ape." + Almost immediately, they received response from a man who said he +would be willing to take part in the experiment, with three conditions. + "First," he said, "my wife must never know. Second, any children +must be baptized. And, third, I'd have to pay in installments." +%% +Hunters make the best lovers; they go deeper into the +bush, shoot more often and *always* eat what they shoot. +%% +I believe that Ronald Reagan will someday make this +country what it once was... an arctic wilderness. + -- Steve Martin +%% + "I believe you have the wrong number," said the old gentleman into +the phone. "You'll have to call the weather bureau for that information." + "Who was that?" his young wife asked. + "Some guy wanting to know if the coast was clear." +%% +I came; I saw; I fucked up. +%% +I can't quite put my finger on it, but +something about you pisses me off. + -- Peter Knight +%% +I choked Linda Lovelace. +%% +I continued wetting my bed for a long time, not just out of contrariness, +but to have the pleasure of feeling my warm urine running down my legs +and wallowing in its odor. + -- Salvador Dali +%% +I don't care who you are, Fatso. Get those reindeer off my roof. +%% +I don't drink water; fish fuck in it. + -- W.C. Fields +%% +I don't give a flying fuck at a rolling doughnut. +%% +"I don't really mind her being unfaithful," sighed the man to his +marriage counselor, "but I just can't sleep three in a bed." +%% +I don't remember ever having had the itch, and yet +scratching is one of nature's sweet pleasures, and so handy. +%% +"I finally found out what my ranch foreman husband really meant," +sobbed the recent bride, "when he told me he'd love me 'til the +cows came home." +%% +I have a funny daddy +Who goes in and out with me +And everything that baby does +Daddy's sure to see, +And everything that baby says, +My daddy's sure to tell. +You must have read my daddy's verse. +I hope he fries in Hell. + -- Ogden Nash +%% +"I have credit with this madam who runs a string of super callgirls," +the executive reminisced at his club bar, "but when I got the bill for +the great head session one of them pleasured me with, I must say that +it was enough to make a blown man cry." +%% +I know what you're up to, you white-feathered fiend! +Go release your bowels on some lesser personage! + -- W.C. Fields, upon seeing a bird overhead +%% + "I need a camel that can go without water for at least three weeks," +the American said to an Algerian camel merchant. "Is it possible?" + "All things are possible," replied the merchant. He proceeded to +take a camel out of his barn and lead him to a tank of water. After the +camel had drunk its fill and was about to lift its head out of the tank, +the merchant picked up two nearby bricks, one in each hand, stepped behind +the camel, and smacked his testicles with the bricks. + The camel let out a gigantic "Whhoooosh!" and sucked up what seemed +like twenty more gallons of water. + The American stared incredulously at the camel merchant. "My God, +man!" he exclaimed, "doesn't that hurt?!" + The merchant shrugged. "Only if you get your thumbs in between the +bricks." +%% +I never trust a man unless I've got his pecker in my pocket. + -- Lyndon Johnson +%% +I regret to say that we are powerless to act in cases of oral-genital +intimacy, unless it has in some way obstructed interstate commerce. + -- J. Edgar Hoover +%% +I think any man in business would be foolish to fool around +with his secretary. If it's someone else's secretary, fine. + -- Barry Goldwater +%% +"I think my wife may be getting somewhat overweight. +"Oh, how can you tell?" +"Well, last night when she sat on my face, I couldn't hear the stereo." +%% +I think pop music has done more for oral intercourse +than anything else that has ever happened, and vice versa. + -- Frank Zappa +%% +I want a girl that can swallow my pride. + -- Frank Zappa, "Jewish Princess" +%% +I was a cock-teaser at Rooster Rama. +I used to enrage the bantams before the big bouts. + -- Firesign Theatre +%% +I was having sex just the other night, but she hung up. +%% +"I was plodding through the woods when suddenly a giant brown bear +grabbed me from behind and made me drop my gun. He picked it up +and stuck it in my back." + "What did you do?" + "What *could* I do? I married his daughter." +%% +I wonder what my wife will want tonight; +Wonder if the wife will fuss and fight? + I wonder can she tell + That I've been raising hell; +Wonder if she'll know that I've been tight? + +My wife is just as nice as can be, +I hope she doesn't feel too nice toward me. + For an afternoon of joy, + Is hell on the old boy, +I wonder what the wife will want tonight! +%% +I wouldn't fuck her with your prick. +%% +I wouldn't mind dying -- it's that business of +having to stay dead that scares the shit out of me. + -- R. Geis +%% +Incest, n: + Sibling revelry; a sport the whole family can enjoy. +%% +Infatuation, n: + When you're in love, there's a lump in your throat. + When you're infatuated, there's a lump in your pants. +%% +I'd like to meet the man who invented +sex and see what he's working on now. +%% +I'd walk a mile for a Camel, two for a hump. +%% +If Carter is the answer, it must have been a VERY silly question. +%% +If God doesn't destroy San Francisco, +He should apologize to Sodom and Gomorrah. +%% +If God had wanted people to give blow +jobs, he wouldn't have given them teeth. +%% +If God hadn't intended man to eat pussy, +would He have made it look like a taco? +%% +If Helen Keller is alone in a forest and falls, does she make a sound? +%% +If a President doesn't do it to his wife, he'll do it to his country. +%% +If it flies, floats or fucks, rent it, don't buy it. + -- Tommy Earl Bruner +%% +If it's not one thing, it's a mother. +%% +If men could get pregnant, abortion would be a sacrament. +%% +If men couldn't fuck there'd be a bounty on their heads. +%% +If sex is a pain in the ass, you may be doing it wrong. +%% +If someone were to ask me for a short cut to sensuality, I would +suggest he go shopping for a used 427 Shelby-Cobra. But it is +only fair to warn you that of the 300 guys who switched to them +in 1966, only two went back to women. + -- Mort Sahl +%% +If there is no God, who pops up the next Kleenex? + -- Art Hoppe +%% +If you were attacked by a homosexual, would you beat him off? +%% +If you could get an erection, you would have no need for Emacs. +%% +If you drink, don't park. Accidents make people. +%% +If you're Catholic you've only got two choices: periodic +abstinence and complete continence; (you know, rhythm and blues). +%% +If you're really into astrology, tell me, what happens +when Mercury is in the Fish, and Jupiter enters the Virgin? +%% +I'm a bisexual; I get it maybe twice a year. + -- Rodney Dangerfield +%% +I'm glad that I'm an American, +I'm glad that I am free, +But I wish I were a little doggy, +And McGovern were a tree. +%% +I'm going to Iowa for an award. Then I'm appearing at Carnegie Hall, +it's sold out. Then I'm sailing to France to be honored by the French +government -- I'd give it all up for one erection. + -- Groucho Marx +%% + "I'm looking for adventure, excitement, beautiful women," cried the +young man to his father as he prepared to leave home. "Don't try to stop me. +I'm on my way." + "Who's trying to stop you?" shouted the father. "Take me along!" +%% +I'm never through with a girl until I've had her three ways. + -- J.F. Kennedy +%% +I'm not laughing behind your back; everything funny is in front! + -- Rodney Dangerfield's wife +%% +I'm unbuttoning your shirt, unzipping your jeans.... + +Oh, I can feel your fingers on the keys, baby, + I'm getting WARM.... + +I am getting there, oh yes,. Oh, my. OH YES... OHHHH! + ...!!!rrrrrgh!!!!! + +Honey, that was *really* terrific, but, next time, +couldn't you please input a little SLOWER? +%% +Immanuel Kant was a real pissant who was very rarely stable. +Heidegger, Heidegger was a boozy beggar who could think you under the table. +David Hume could out-consume Schopenhauer and Hegel, +And Wittgenstein was a beery swine who was just as schloshed as Schlegel. +There's nothing Nietzsche couldn't teach ya 'bout the raising of the wrist. +Socrates, himself, was permanently pissed! + +John Stuart Mill, of his own free will, +On half a pint of shandy was particularly ill. +Plato, they say, could stick it away, half a crate of whiskey every day. +Aristotle, Aristotle was a bugger for the bottle, +Hobbes was fond of his dram, +And Rene Descartes was a drunken fart: "I drink, therefore I am". +Yes, Socrates, himself, is particularly missed; +A lovely little thinker but a bugger when he's pissed! + -- Monty Python, "The Philosopher's Drinking Song" +%% +In France they piss on Main Street +(In pissoirs, Mama, not cheap display). + -- Joni Mitchell +%% +In a recent survey on why some men are homosexual, 82 percent of the gay +chaps responding said that either genetics or home environment was the +principal factor. The remaining 18 percent revealed that they had been +sucked into it. +%% +In days of old, when knights were bold, + And rubbers weren't invented, +They tied their socks around their cocks + And babies were prevented. +%% +In my sweet little Alice Blue gown +Was the first time I ever laid down, + I was both proud and shy + As he opened his fly +And the moment I saw it I thought I would die. + +Oh it hung almost down to the ground, +As it went in I made not a sound, + The more that he shoved it + The more that I loved it, +As he came on my Alice Blue gown. +%% +In my sweet little night gown of blue, +On the first night that I slept with you, + I was both shy and scared + As the bed was prepared, +And you played peekaboo with my ribbons of blue. + +As we both watched the break of day, +And in peaceful submission I lay, + You said you adored it + But dammit, you tore it, +My sweet little night gown of blue. +%% +In outer space, nobody can hear you fart. +%% +In the beginning was the DEMO Project. And the Project was without form. +And darkness was upon the staff members thereof. So they spake unto +their Division Head, saying, "It is a crock of shit, and it stinks." + +And the Division Head spake unto his Department Head, saying, +"It is a crock of excrement and none may abide the odor thereof." +Now, the Department Head spake unto his Directorate Head, saying, +"It is a container of excrement, and is very strong, such that none +may abide before it." And it came to pass that the Directorate Head +spake unto the Assistant Technical Director, saying, "It is a vessel +of fertilizer and none may abide by its strength." + +And the assistant Technical Director spake thus unto the Technical +Director, saying, "It containeth that which aids growth and it is +very strong." And, Lo, the Technical Director spake then unto the +Captain, saying, "The powerful new Project will help promote the +growth of the Laboratories." + +And the Captain looked down upon the Project, and He saw that it was Good! +%% +In the romantic days of Warsaw, Viennese whores were known for their +beauty and delicacy. A gallant officer picked up one such lady of the +evening, who took him to her apartment. They made delicious love all +evening before drifting to sleep in each others' arms. In the morning +the man dressed, staring into a full-length mirror. The lady lay in her +bed watching him. Finally, she said softly, + "Didn't you forget something?" + "What did I forget?" asked the officer. + "You forgot about the money," said the lady. + "Oh, no," said the man, standing at ramrod attention. +"A Polish officer never accepts money." +%% +In the shade of the old apple tree +Where between her fat legs I could see + A little brown spot + With the hair in a knot, +And it certainly looked good to me. + +I asked as I tickled her tit +If she thought that my big thing would fit. + She said it would do + So we had a good screw In the shade of the old apple tree +In the shade of the old apple tree. I got all that was coming to me. + In the soft dewy grass +I could hear the dull buzz of the bee I had a fine piece of ass +As he sunk his grub hooks into me. From a maiden that was fine to see. + Her ass it was fine + But you should have seen mine +In the shade of the old apple tree. +%% +It is a sad commentary on today's society that this fortune has to be +classified as "offensive" simply because it contains the word "fuck". +%% +It is better to have Uranus in Cancer than to have Cancer in Uranus. +%% +It is far better to sleep with an old hen than pullet. +%% +It is not wise to make love more than once in the morning. +You never know who you'll meet later in the day. +%% +It takes a brave man to admit his mistakes. +Especially in a paternity hearing. +%% +It takes leather balls to play rugby. + (Blood makes the grass grow!) +%% +It used to be a man's world, and the woman's place was in the home. +They can kiss that shit goodbye. +%% +It was New Year's Eve and the house was brightly decorated with holiday +trappings. The only sound that broke the quiet was the click of Grandma's +knitting needles. The children; Jane, eight and Mary, five, were seated +in front of a cheerily burning fire, leafing through a picture book. +Tiring of this, they went over to Grandma's rocker. Jane climbed up on +the arm of the chair and Mary snuggled into Grandma's cozy lap. + "Tell us a story," begged Mary. + "Oh," said the old lady, laying aside her knitting and wrapping +her arms around the children. "What story should I tell you?" + "Tell us our favorite story," whispered little Jane eagerly. +"About the time you were a hooker in Chicago." +%% +It was a warm, sunny Sunday, so a man and his wife decided to take in the zoo. +They spent the day, and at closing time they walked past the gorilla cage, and +the man noticed the gorilla looking at his wife. "That gorilla is getting +excited just looking at your tits," he said. "Why don't you take your blouse +off and we'll see what he does?" + At first she refused. But finally persuaded by her husband, she took +off her blouse and bra. The gorilla went nuts. He started grunting and +jumping up and down. + "Hey," the husband said, "let's really blow his mind. Take off all +your clothes and we'll see what he does." + Again she said no and again he persuaded her. This time the ape +really went bananas! He climbed up and down the bars, did flips, ran around +in circles and tossed his food all over the cage. The husband went over to +the cage, opened the door and pushed his wife in. + "Now," said the husband, "tell that motherfucker you have a headache!" +%% +It was almost closing time when a male patron who had been getting the +frosty treatment from a girl at the end of the bar called to the +bartender and said, "Give that bitchy douche bag over there one on me." + "We discourage that sort of language here, sir," the bartender +answered sternly. + "OK, OK. Serve the lady a cocktail with my compliments." + The bartender approached the female in question. "The, uh, gentleman +at the other end of the bar would like to buy you a drink, miss. What would +you like?" + "Vinegar and water." +%% +It was at the eighth annual mouse convention and mice from near and far had +gathered for the ball. A pretty little female mouse waltzed by the stag +line and one of the males whistled a low, dirty whistle to himself. +Turning to another mouse he said, "Look at the legs on that bitch, aren't +they beautiful?" + "Just fair," was the answer. + "You're crazy," said the first mouse and then turning to another, +asked his opinion. + "They're nice," said the third mouse, "but nothing to get excited +about." + "Some mice have no appreciation," exclaimed the first mouse. "Now +you," he said to a fourth mouse, "what did you think?" + "To tell you the truth," was the reply, "I'm no authority on legs, +I'm a tit mouse myself." +%% +It was her wedding night, and the sweet young thing was in a romantic haze. +"Oh, darling," she sighed, "We're married at last. It's all like a wonderful +dream!" + Her husband didn't answer. A few moments passed. She sighed again +and said, "I'm afraid I'll awake in a moment and find it isn't true." + Still no response from her spouse. Another pause and another +sensuous sigh, then, softly, "I just can't believe that I'm really your +wife." + "Damn it," growled her mate, "as soon as I get this shoelace untied, +you will!" +%% +It was his third marriage and her fourth. He was quite surprised when on +their honeymoon she pleaded, "Please be gentle, I'm still a virgin." + "Darling, what do you mean you're still a virgin? You've been +married three times." + "Yes, but they all worked for DEC. The first was a salesman, +and all he ever did was promise how good it would be. The second was one +of their software hacks, he told me to take care of it myself. And the +third was a field service representative, and he kept promising that it +would be up in 15 minutes. +%% + It was in a bar in midtown Manhattan and the Frenchman and the +American were talking about love over some dry Martinis. "Deed you know, +sir," the Frenchman said, "that een my country thair are 79 different +ways how to make the REAL, passionate luff?" + "Do tell?" said the American. "Well, that's amazing. In this +country there's only one." + "Just one?" the Frenchman said, condescendingly. "And what eez +that?" + "Well, there's a man and a woman, and --" + "Sacre bleu!!" exclaimed the Frenchman. "Numbair 80!" +%% +It was the first day of a new term at Princeton, and a Texas A&M freshman +was learning his way around the campus. Stopping a distinguished looking +upperclassman, he inquired, + "Say, buddy, can you tell me where the library is at?" + "My good fellow," came the reply, "at Princeton we do not end our +sentences with a preposition." + "All right," said the freshman, "can you tell me where the library +is at, asshole?" +%% +It's a question of Napleon brandy versus Ripple. +I am mellow and amber and I go down real smooth. + -- Rita Moreno, commenting in Newsweek on the sex appeal + of older women versus younger women +%% +"It's always the same," the girl sighed to her roommate after returning +in the wee, small hours. "Afterward, I feel so compromised, so cheap, so +soiled... so absolutely wonderful from head to toe!" +%% +It's better to be pissed off than pissed on. +%% +It's hard to keep a good girl down -- but lots of fun trying. +%% +It's not the ups and downs of love, it's the ins and outs. +%% +It's so fuckin' great to be alive! +%% +It's the sighs that count. +%% +I've been watching you closely to see if you have been good this year; +and since you have, I will be telling my elves to make some goodies for me +to leave under your tree on Christmas. I was going to bring you all the +gifts from the twelve days of Christmas, but we had a little problem up here. +The twelve fiddlers fiddling have all come down with V.D. from fiddling with +the ten ladies dancing, the eleven lords-a-leaping have knocked up the eight +maids-a-milking, and the nine pipers piping have been arrested for doing +weird things to the seven swans-a-swimming and the six geese-a-laying. The +four calling birds, three French hens, two turtle doves, and the partridge +in the pear tree have me up to my ass in birdshit. On top of all this, Mrs. +Claus is going through menopause, eight of my reindeer are in heat, the elves +have joined gay liberation, and those dumb ass Polacks have scheduled +Christmas for the fifth of February. I'll do what I can. + Sincerely, + Santa +%% +I've finally found the perfect girl, +I couldn't ask for more, +She's deaf and dumb and over-sexed, +And owns a liquor store. +%% +Jack an Jill went up the hill. +Jill went down, +Jack came. +%% +Jack and Jill went up a hill +To fetch a pail of water. +Jack fell down and broke his crown Jack on Jill produced a thrill +And Jill came tumbling after. When on the ground he got her, + Then went down and told the town + He tumbled Jill and gaffed her. +Jack to Jill thus did such ill +That Jill, to pay the rotter, +Told the town Jack's crown broke down Jack and Jill have split the bill +When he set out to shaft her. Since Jack led Jill to totter. + Half the town deals Jill a frown + And half greets Jack with laughter. +%% +Jack and Jill went up the hill +Each had a buck and a quarter. +Jill came down with two and a half -- +And you thought that they went for water. +%% +Jack be nimble, Jack be quick. +Jack jumped over the candle stick, +And burnt his balls. +%% +Jesus loves you, but everybody else thinks you're a dork. +%% +Jesus was killed by a Moral Majority. +%% +Joan of Arc is alive and medium well. +%% +Joe sat as his dying wife's bedside. +Her voice was little more than a whisper. + "Joe, darling," she breathed, "I've got a confession to make +before I go. I ... I'm the one who took the $10,000 from your safe... +I spent it on a fling with your best friend, Charles. And it was I who +forced your mistress to leave the city. And I am the one who reported +your income-tax evasion to the I.R.S..." + "That's all right, dearest, don't give it a second thought," +whispered Joe. "I'm the one who poisoned you." +%% +John Birch Society: + That pathetic manifestation of organized apoplexy. + -- Edward P. Morgan +%% +Kasha, n: + Kasha is always defined as "buckwheat groats". There's only one + problem with this definition: what the fuck are "buckwheat groats"? + I know what they are -- they're kasha. But that doesn't help you + much. +%% +Knowledge Engineering: + +A combination of: + +Engineering, n: + The application of science and mathematics by which the properties +of matter and the sources of energy in nature are made useful to man in +structures, machines, products, systems and processes. + +and + +Knowledge, n: + Sexual intercourse. + +See also: Prostitution, Grantsmanship. +%% +Kotex, n: + Not the best thing on earth, but next to the best. +%% +Kumquat, n: + Any of several small citrus fruits with sweet spongy rind and + somewhat acidic pulp that are used chiefly for preserves. + Extremely popular in some forms of sexual intercourse. In fact, + an early indication that your partner is willing to experiment + sexually may be a rather insistent moaning of "kumquat, kumquat" + during orgasm. + + Note: this is *not* to be confused with a warning from your + partner that his/her parents are upstairs and probably awake. +%% +Kissing, petting, and even intercourse are all right as long as they are +sincere. I have never given a kiss in my life that wasn't sincere. As +for intercourse, I'd say three times a day was about right. + -- Margaret Sangor +%% +Labia majora, n: + The curly gates. +%% +LAGNAF: + Let's All Get Naked And Fuck! +%% +Lawyer, n: + Someone who can get a sodomy charge changed to "following too + closely." +%% + LEPROSY +Leprosy, all my skin is falling off of me. +I'm not half the man I used to be. +Oh, how did I get leprosy? + +Syphillis, it all started with a simple kiss. +Now it even hurts to take a piss. +Oh why did I get syphillis? + +Why'd she have VD? I don't know, she wouldn't say. +I did something wrong, now I long for yesterday .... + -- To the tune of "Yesterday" +%% +LIBRA (Sept 23 - Oct 22) + You are the artistic type and have a difficult time with +reality. If you are a man, you are more than likely gay. Chances for +employment and monetary gains are excellent. Most Libra women are +prostitutes. All Libra people die of Venereal disease. +%% +Lucky, adj: + When you have a wife and a cigarette + lighter -- both of which work. +%% +Luser, n: + Someone who picks up a female + hitch-hiker walking home from a date. +%% +Large cats can be dangerous, but a little pussy never hurt anyone. +%% +Lawyers do it to everyone. +%% +Let a Field Service Engineer put it in. +%% +Life is a bitch, but the puppies can be cute. +%% +Life is a shit sandwich, and every day you get to take another bite. +It's just that some days are TWO BITE days ... +%% +Life is like a cucumber -- one moment it's +in your hand, the next it's up your ass. +%% +Life is like a penis: when it's soft you +can't beat it, and when it's hard you get fucked. +%% +Lipstick on your dipstick told a tale on you, +Lipstick on your dipstick said you were untrue. +Bet your bottom dollar you and I are through, +'Cause lipstick on your dipstick told a tale on you. + -- To the tune of "Lipstick On Your Collar" +%% +Lisp hackers + ... do it in CARS. + ... do it with tail recursion. + ... first do it in the front, then do it in the back. + ... have DEFUN while doing it. + ... have to be bound to do it. + ... have Moby dicks. +%% +Little Herbie had been blind since birth. One day at bedtime, his mother +told him that the next day was a very special one. If he prayed extra +hard, he'd be able to see when he woke up the next morning. The next +morning she came into Herbie's room and asked him if he'd prayed hard +the night before. + "Yes, Mommie," was his reply, "all night long!" + "Well, then," she said, "open your eyes and you'll know that +your prayers have been answered." +Little Herbie opened his eyes, only to cry out, + "Mother! Mother! I still can't see!" + "I know, dear," said his mother, "April Fool." +%% +Little Johnny with a grin, +Drank up all of daddy's gin, +Mother said, when he was plastered, +Go to bed, you little love-child. +%% +Little Miss Muffet sat on a tuffet, +Eating her curds and whey. +Along came a spider +And bit her right in the snatch. +%% +Little Red Riding Hood was walking through the woods on her way to visit +her grandmother when a wolf jumped out from behind a tree. + "Aha!" the wolf said, "Now I've got you, and I'm going to eat you." + "Eat, eat, eat," said Little Red Riding Hood angrily, +"Damn it, doesn't anybody fuck anymore?" +%% +Living in California is like living in a bowl of granola. +What ain't flakes and nuts is fruits. +%% +Love is blind but desire doesn't give a good goddam. + -- James Thurber +%% +Love is eating her even when she's not having her period. +%% +Love is just for now ... herpes lasts forever. +%% +Macho, adj: + Jogging home from a vasectomy. +%% +Male, n: + Life support system for a cock. +%% +Marriage, n: + The evil aye. +%% +Menage a trois, n: + Using both hands to masturbate. +%% +Meteorologist, n: + A man who can look in a woman's eyes and predict whether. +%% +Missionary position: + The missionary on top. +%% +Mistress, n: + Something between a mister and a mattress. +%% +Montana: + Where men are men and women are sheep. +%% +Ma Bell runs a baudy house. +%% +Man who dance in crowded ballroom +dance cheek to cheek with woman behind him. +%% +Man who keep money in jockstrap has financial matters all balled up. +%% +Many a bachelor feels the need to insert his masculinity. +%% +Many a wife thinks her husband is the world's greatest lover. +But she can never catch him at it. +%% +Many a woman hasn't realized that she was raped until the check bounced. +%% +Many nice things suck. +%% +Marijuana is nature's way of saying, "Hi!". +%% +Marriage is learning about women the hard way. +%% +Mary had a little lamb, +She kept it in a bucket. +And every time she let it out, +The bulldog used to +Chase it around the garden. +%% +Mary had a little sheep, +And with the sheep she went to sleep, +The sheep turned out to be a ram, +And Mary had a little lamb. +%% +Mary had a little watch; +She swallowed it one day. +And so she took some Ex-Lax +To pass the time away. + +But when she took the Ex-Lax +The time it did not pass. +So when you want to know the time, +Just look up Mary's ... + Uncle, he has a watch, too. +%% +Don't knock masturbation, it's sex with someone I love. + -- Woody Allen +%% +Mathematicians + ... do it in groups. + ... do it in theory. + ... take it to the limit. +%% +Maybe if the guy who developed Twinkies hadn't had such a low +opinion of himself they would have been an inch or two longer! +%% +Meanwhile, back at the ranch, Granny was a-beating off the Indians, but they +jus' kept on a-comin'. And, as the U.S. fourth Calvary mounted the hill, +Tonto, cleverly disguised as a doorknob, came off in the Lone Ranger's hand. +%% +Mickey Mouse has a long talk one day with a psychiatrist, after which +the psychiatrist interviews Minnie Mouse. A few days later Mickey meets +with the psychiatrist, and the following conversation ensues: + +Sigmund : I talked with Minnie after talking with you. +Mickey : Oh? +Sigmund : I couldn't find anything wrong with her -- she isn't insane. +Mickey : Idiot! I didn't say she was insane -- I said she was + fuckin' Goofy. +%% +Mistress Mary, quite contrary, +How does your garden grow? +With silver bells and cockle shells, +And one fucked-up petunia. +%% +Morris left for a two-day business trip to Chicago. He was only a few +blocks from his house, when he realized that he had left the airplane +tickets on his bureau top. He returned and quietly entered the house. +His wife, in her skimpiest negligee, was standing at the sink washing +the breakfast dishes. She looked so inviting that he tiptoed up behind +her, reached out, and squeezed her breast. + "Leave only one quart of milk," she said. "Morris won't be here +for breakfast tomorrow." +%% +Most seminars have a happy ending. Everyone's glad when they're over. +%% +Most women look for a man who is tall, dark and hung some. +%% +Motto of the Electrical Engineer: + Working computer hardware is a lot like an erect penis: + it stays up as long as you don't fuck with it. +%% +Moustache rides, 50 cents. +%% +Mrs. Johnson had a very beautiful and intelligent parrot. He had just one +problem: He liked to fuck Mr. Hawkins' chickens. Mrs. Johnson scolded him +time and time again, but he would just laugh at her. Finally, she told him +that if he did it again, she would cut off all of the feathers on the top of +his head. Well, he resisted the urge for a week, but one day, he just +couldn't resist going next door. Besides, he figured she was bluffing. + Well, Mr. Hawkins came over, ranting and raving about how the parrot +had been fucking his chickens again. Mrs. Johnson didn't say a word, just +took out her scissors and cut off all of the parrot's head feathers. + That night, Mrs. Johnson had a big party at her house. Before it +started, she took the parrot and put him on top of the piano by the front +door. "Since you disobeyed me today, you have to stay here on the piano +tonight. Now, don't you dare move." + Well, the parrot was pretty pissed off about having his head bare, +and he wasn't too happy about having to spend the whole evening on the piano. +Still, as he usually did, when the butler would announce the guests as they +arrived, he would say hello to them. Just then, two bald-headed men came to +the door. + Before the butler could say anything, the parrot yelled, "Okay, you +chicken-fuckers, up here on the piano with me!" +%% +Much to his Mum and Dad's dismay, Horace ate himself one day. +He didn't stop to say his grace, he just sat down and ate his face. +"We can't have this!" his Dad declared, "If that lad's ate, he should + be shared." +But even as he spoke they saw Horace eating more and more: +First his legs and then his thighs, his arms, his nose, his hair, his eyes... +"Stop him someone!" Mother cried, "Those eyeballs would be better fried!" +But all too late, for they were gone, and he had started on his dong... +"Oh! foolish child!" the father mourns "You could have deep-fried that + with prawns, +Some parsley and and some tartar sauce..." +But H. was on his second course: his liver and his lights and lung, +His ears, his neck, his chin, his tongue; "To think I raised him from the cot, +And now he's going to scoff the lot!" +His Mother cried: "What shall we do? What's left won't even make a stew..." +And as she wept, her son was seen, to eat his head, his heart his spleen. +and there he lay: a boy no more, just a stomach on the floor... +None the less, since it *was* his, they ate it -- that's what haggis is. +%% +Must be getting close to town -- we're hitting more people. +%% +My brother-in-law has found a way to make ends meet. +He goes around with his head stuck up his ass. +%% +My girlfriend and I sure had a good time at the beach last summer. First +she'd bury me in the sand, then I'd bury her. This summer I'm going to go +back and dig her up. +%% +My girlfriend's favorite erotic position is bending over my credit cards. +%% + "My mother," said the sweet young steno, "says there are some things +a girl should not do before twenty." + "Your mother is right," said the executive, "I don't like a large +audience, either." +%% +My sex life hasn't been so good; either fist or famine. +%% +Navel, n: + A place to stash your gum on the way down. +%% +Necrophilia, n: + Dropping in for a cold one. +%% +NEW ADDITION TO THE LIBRARY: + "Sally", the department's new inflatable doll, is available on +a short-term removal basis only -- please sign her out and return her +promptly to avoid extended waits. (We are still awaiting shipment of +our "Big John" doll.) +%% +New York: + Where men are men, sheep enjoy it, and lepers laugh their heads off. +%% +NEWSFLASH!! + Rodney Fenster looked up the shaft of elevator number four at +1700 N. 17th St. this morning to see if the elevator was on its way down. +It was. Age 31. +%% +Nothing, n: + A man with an erection who walks into a wall and breaks his nose. +%% +Naked children are so perfectly pure and lovely. I confess I do not admire +naked boys. They always seem to me to need clothes -- whereas one hardly +sees why the lovely forms of girls should ever be covered up. + -- Lewis Carroll +%% +Nancy Reagan wants to divorce old Ron... +seems he's making it hard for everyone but her. +%% +Need to buy black lace crotchless panties for sheep? +Try Fredricks of Ithaca, New York. +%% + Never take a resume seriously. Resumes only make money for the +people who write the resumes. No resume ever tells an employer how many +times a job applicant has had the clap. + Why, indeed, would anyone hire a person based +on a resume written by a professional liar? + If the applicant is a man, the employer must ask only one question: +did the applicant go to TCU? + If the applicant is a woman, the employer may simply ask: does she +have a tongue that can lick the paint off a dormitory wall? + -- Dan Jenkins, "Baja Oklahoma" +%% +Never try to keep up with the Joneses; they might be newlyweds. +%% +New Jersey is not the armpit of the nation; +it's the asshole of the universe. + -- Jonathan Michael Smith +%% +Nice computers don't go down. +%% +Nine out of ten men who preferred Camels have switched back to women. +%% +Nine reasons a taco is better than a woman: + 1: Tacos don't put frilly covers on the toilet seat + so the lid won't stay up. + 2: Tacos don't use your razor on their legs. + 3: Tacos don't say "That's okay, it doesn't have to be good for me." + 4: Tacos don't get upset if you eat another taco, "Just for fun." + 5: Tacos will never contest a divorce, + demand a property settlement or seek custody of anything. + 6: Tacos won't ask you about your last lover, + or speculate about your next one. + 7: A taco will never make a scene because + there are other tacos in the refrigerator. + 8: It's easy to drop a taco. + 9: Tacos don't want to sleep on your chest. +%% +OLD FELLA RED CLARET + Produce of Australia -- "The Big 69'er" + +An unusual "Rough-as-Guts" wine that has the Distinctive Bouquet of old +and ill-cared for animals. It is best drunk with the teeth clenched to +prevent ingestion of the seeds and skins. Connoisseurs will savour the +slight Tannin Taste of burnt shag feathers and soiled medical dressings. +Possessors of a cultivated Palate admire the initial assault on the taste +buds which comes from the careful and loving blending of circus hosings +with perished jock straps. The maturing in Midland Abattoir hogsheads +gives it a very Definite Nose. With the bouquet like an aborigine's armpit. +In the United States this wine is marketed as Crow Brand (9 out of 10 people +who drink it for the first time exclaim "VRAAAARRRRRK"). + +It won a Bronze at the "Kings Cross Homosexuals Convention" of 1973 + +Warning: Avoid contact with eyes and open cuts. + Keep away from open naked flames -- both old and new. +%% +Oral sex, n: + The taste of things to come. +%% +Oh, I'm looking over, my dead dog Rover, +That got run over with my mower. +One leg is missing, and one other is gone, +The fourth one is scattered all over the lawn. +It's no use explain'n, the one remaining, +It landed by the kitchen door. +Oh, I'm looking over, my dead dog rover, +that ain't gonna walk no more... + -- Tune is something about a four-leaf clover. +%% +Oh John, let's not park here. +Oh John, let's not park. +Oh John, let's not. +Oh John, let's. +Oh John. +Oh. +%% +Oh, baby, put two fingers here and one finger there and call me bitch. +%% +Oh give me a home, where the bookmakers roam, +Where the beer and the whiskey flows free, +Where never is heard, a discouraging word, +And the call-girls keep callin' for me! +%% +Old Mother Hubbard, +Went to the cubbard, +To get her poor doggie a bone. + +But when she stooped over, +Old Rover, he drove her. +You see, he had a bone of his own. +%% +On Brassieres: + Russian: Uplifts the masses. + Salvation Army: Raises the fallen. + American: Makes mountains out of molehills. +%% +On an isolated stretch of beach near Cannes, a beautiful French girl threw +herself into the sea and drowned despite a young man's attempt to save her. +The man dragged the half-nude body ashore and left it on the sand while he +went to notify the authorities. Upon his return, he was horrified to find +a man making love to the corpse. + "Monsieur, monsieur," he shouted, "that woman is dead, +that woman is dead!" + "Sacre bleu," exclaimed the man, springing up. +"I thought she was an American!" +%% +Ona day Ima gonna to Detroit to a bigga hotel. Ina morning I go down to +eat breakfast. I tella waitress I wanna two piss's toast. She bringa me +only one piss. I tella her I wanna two piss ona my plate. She says you +better no piss on the plate, you sonna bitch. I don't even know the lady +and she call me sonna bitch. Later I go out to eat at the bigga restaurant. +The waitress bring me a spoon and a knife but no fock. I tell her I wanna +fock. She tells me everone wanna fock. I tell her "you no understand", I +wanna fock on the table. She say you better not fock on the table, you +sonna bitch. So I go back to my room ina hotel and there isa no shits ona +my bed. I calla the manager and tella him I wanna shit. He tella me to go +to the toilet. I say "you no understand", I wanna shit on the bed. He say +you better no shit ona bed, you sonna bitch. I go to check out and the man +at the desk say "peace to you". I say piss on you too, you sonna bitch. I +gonna back to Italy. +%% +Once upon a girl there was a time... +%% +Once upon a time there was a farmer who owned a large number of chickens and +made money by selling chickens to a local distributing company. The farmer +wanted to increase his business, and so went to market to buy another rooster. +"This rooster," assured the vendor, "is my best. He's virile and energetic +and will take care of all your chickens!" The farmer, delighted at this, +bought the rooster and returned to his farm. He set the rooster loose among +his hen houses and, sure enough, the rooster enthusiastically went to work. +It wasn't too long, however, before the rooster finished off all the hens and +began on the few geese and ducks that were on the farm. "If you keep up this +rate," warned the farmer, "you'll screw yourself to death!" The rooster, +however, scoffed at the farmer and continued at an increased speed. The next +morning, the farmer was doing his chores when he noticed several buzzards in +the sky circling over something. He headed out behind the barn, and sure +enough there was the rooster, flat on his back, with eyes closed. The farmer +shook his fist at the motionless body and cursed, shouting "I knew it! I told +you so! I knew you'd screw yourself to death!" The rooster turned his head +toward the farmer, opened one eye, and winked. "Shhh!" he said, pointing to +the birds above. "I think they're coming down." +%% +Once upon a time there was a little girl named Little Red Riding Hood. One +fine morning she decided to visit her Grandmother, so she put a freshly baked +cake and a .357 magnum into her basket and set off through the forest. When +she got there, what should she find but a big black wolf in the bed, who +jumped up, grabbed her and snarled, "I'm going to fuck you until the sun goes +down." + So Little Red Riding Hood whipped out the .357 and said, "Oh, no, +you're not! You're going to eat me just like the story says!" +%% +Once upon a time, there was a non-conforming sparrow who decided not to +fly south for the winter. However, soon after the weather turned cold, +the sparrow changed his mind and reluctantly started to fly south. +After a short time, ice began to form his on his wings and he fell to +earth in a barnyard almost frozen. A cow passed by and crapped on this +little bird and the sparrow thought it was the end, but the manure +warmed him and defrosted his wings. Warm and happy the little sparrow +began to sing. Just then, a large Tom cat came by and hearing the +chirping investigated the sounds. As Old Tom cleared away the manure, +he found the chirping bird and promptly ate him. +There are three morals to this story: +1) Everyone who shits on you is not necessarily your enemy. +2) Everyone who gets you out of shit is not necessarily your friend. +3) If you are warm and happy in a pile of shit, keep your mouth shut. +%% +Once upon a time there was a sperm named Stanley. He'd do pushups and +somersaults and limber up all the time, while the other sperm just lay around +on their fat asses not doing a thing. One day, one of them became curious +enough to ask Stanley why he exercised all day. Stanley said, + "Look, only one sperm gets a woman pregnant and when the right +time comes, I am going to be that one." +A few days later, the all felt themselves getting hotter and hotter, and they +knew that it was getting to be their time to go. They were released abruptly +and, sure enough, there was Stanley swimming far ahead of all the others. +All of a sudden, Stanley stopped, turned around, and began to swim back with +all his might. + "Go back! Go back!" he screamed. "It's a blow job!" +%% +Once upon a time there were three coeds -- a big coed, a medium-sized coed, +and a little, tiny coed. One night they came home from a dance, and the big +coed said, "Someone's been sleeping in my bed!" + The medium-sized coed looked in her room and said, "Someone's been +sleeping in my bed!" + And the little, tiny coed said, "Well, nighty-night, girls!" +%% +Once you've got them by the balls, their hearts and minds will follow. +%% +One by one the vice-presidents of a large corporation were called into the +boss's office. Then the junior executives were individually summoned. +Finally the office boy was brought in. + "I want the truth, Charles," the boss bellowed. "Have you been +playing around with my secretary?" + "N-no, sir," the office boy stammered. "I-I'd never do anything +like that, sir." + "All right, all right," sighed the boss, "then you fire her." +%% +One day Father O'Malley was walking through the park when he came upon an +enchanting scene. A beautiful little girl with long blond hair, deep blue +eyes, and a dainty white dress was reading under a tree with her adorable +little dog. + What a lovely picture, thought the Father to himself. Walking over, +he asked, "Child, what is your name?" + "Blossom," she replied. + "What a fitting name," exclaimed Father O'Malley. "And how did your +parents come to choose such a pretty name?" + "Well, one day when I was still in my mommy's tummy she was lying +under this very tree when a blossom fell and landed on her stomach. She +thought it was a message from God and decided that I would be a girl and my +name would be Blossom," explained the little girl sweetly. + How charming, thought the priest. He started to say good-bye and +walk away, then turned back. "And the name of your little dog?" he +inquired. + "Porky," was the child's reply. + Again he asked her how the unusual name had been chosen. + "Because he likes to fuck pigs." +%% +One day President Reagan, Chairman Brezhnev, the Pope, and a boy scout were +flying together in an airplane. Right out in the middle of nowhere the plane +developed engine trouble and started to go down. Unfortunately, only three +parachutes could be found for the four passengers! Brezhnev grabbed one of +the parachutes and declared "Comrades, as leader of the socialist workers +revolution, my life must be spared." And he jumped out of the plane. Then +Reagan exclaimed "As leader of the greatest nation on earth, I must keep the +world safe for democracy." And with that he too jumped to safety. Now if +you are following all this (or counting on your fingers) you must see that +there is only one parachute left for the two remaining passengers. The Pope +looked kindly upon the boy scout and said "I have had a long and productive +life, my son. You take the parachute and leave me in God's hands." "That's +very kind of you," the observant scout replied, "but there is no need. Reagan +just jumped out with my knapsack." +%% +One day a mouse was driving along the road in his Mercedes when he heard an +anguished roaring noise coming from the side of the road. Stopping the car, +he got out and discovered a lion stuck in a deep ditch and roaring for help. +Reassuring the lion, the mouse tied a rope around the axle of the Mercedes, +threw the other end down to the lion, and pulled the beast out of the ditch. +The lion thanked the mouse profusely and they went their separate ways. + Two weeks later the lion was out for a stroll in the country when +he heard a panicked squeaking coming from the side of the road. Investigating +the noise, what should he come across but the mouse stuck in the same hole. +"Oh, please help me, Mr. Lion," squeaked the terrified mouse. "I saved you +with my car once, remember?" + "Course I'll help you, little feller," roared the lion. "I'll just +lower my dick down to you, you hold on to it, and we'll have you out of there +in a jiffy." Sure enough, a few minutes later the mouse was high and dry on +the roadside, trying to convey his eternal gratitude to the lion. + "Don't give it another thought," said the lion kindly. "It just goes +to show that if you've got a big dick, you don't need a Mercedes." +%% +One fall day, two men were out in the woods hunting. Feeling a sudden need +to relieve himself, George went over to a nearby clump of bushes, unzipped +his fly, and started in when a poisonous snake lunged out of the bushes and +bit him on his penis. Hearing George's howl of pain and fright, his friend +Fred came running up and told him to lie still while he used the radio to +call a doctor. + "There's only one way to save your friend's life," said the doctor +gravely. "If you cut a shallow 'X' over the bite and then suck as much of +the poison out as you can, he'll probably be okay, but otherwise there's not +much hope." + Hearing Fred's footsteps, George rose weakly up on one elbow and +cried out, "Fred, what'd he say? What did the doctor say?" + "George, old friend," said Fred sadly, "he said you're gonna die." +%% +One man's nightmare is another man's wet dream. +%% + One night when his charge was pretty high, Micro-Farad decided to +seek out a cute little coil to let him discharge. He picked up Milli-Amp +and took her for a ride on his Megacycle. They rode across the Wheatstone +bridge, around the sine waves, and stopped in the magnetic field by the +flowing current. Micro-Farad, attracted by Milli-Amp's charactaristic curves, +soon had her fully charged and excited, her resistance to a minimum. He laid +her on the ground potential, raised her frequency, and lowered her reluctance. +He pulled out his high voltage probe and inserted it into her socket, +connecting them in parallel and began short circuiting her resistance shunt. +Fully excited, Milli-Amp mumbled: "OHM-OHM-OHM." + With his tube operating at a maximum and her field vibrating with +his current flow, it caused her shunt to overheat, and Micro-Farad was rapidly +discharged and drained of every electron. They Fluxed all night trying +various connections and sockets until his magnet had a soft core and lost +all of its field strength. + Afterwards, Milli-Amp tried self-induction and damaged her +solenoids. With his battery fully discharged, Micro-Farad was unable to +excite his field, so they spent the night reversing polarity and blowing +each others fuses. + -- Eddie Currents, "The Sex Life of an Electron" +%% +One of the airlines recently introduced a special half-fare rate for wives +accompanying their husbands on business trips. Anticipating some valuable +testimonials, the publicity department of the airline sent out letters to +all the wives of businessmen who used the special rates, asking how they +enjoyed their trip. Responses are still pouring in asking, + "What trip?" +%% +One should be cherry of virgins. +%% + One spring evening, after a hard rain, grandpa and grandson were +sitting out on the porch, talking. Grandpa spied a worm crawling up out +of its hole and said to his grandson, "Sonny, if you can get that there +worm back down its hole, I'll give you five dollars." + "Sure!", says sonny, and runs in the house. Out he runs an +instant later with a can of hairspray, grabs the worm, and sprays it with +the hairspray as it dangles earthward. He then slips the stiff worm back +into its hole and turns to his grandpa with a huge smile on his face. + "Well, I'll be. That was pretty smart there, boy.", he says. +"Here's your fiver.", he adds as he fishes out a bill. By then it's almost +dark, and they say their goodnights and part. + The next day sonny's playing out on the porch, and grandpa comes +out of the house and gives him a five. "But you gave me my five yesterday, +grandpa.", he remarks. + "Yep, I know. This is from your grandma." +%% +One who does not know a burro from a burrow +does not know his ass from a hole in the ground! +%% +Ooooooh, nooooooo, not tonite!! +%% +Operators mount anything! +%% +Opinions are like assholes -- everyone's got one, +but nobody wants to look at the other guy's. + -- Hal Hickman +%% +Over 5,000 years ago, Moses said to the children of Israel, + "Pick up your shovels, mount your asses and load your camels, +and I will lead you to the promised land." + Not too long ago, Roosevelt said, "Lay down your shovels, sit on +your asses, light a Camel, this is the promised land." + Now Nixon is stealing your shovels, kicking your asses, raising +the price of Camels, and mortgaging the promised land. +%% +PENIS ENVY: + The desire to be pink and wrinkled and about four inches long. +%% +PHILADELPHIA FLYING FUCK: + Okay, see, he hangs from a chin-up bar with his feet on the arms + of the rocking chair. She crouches in the rocking chair pleasuring + him orally. + + [Note: Personally, we've never tried this. If you have, or if + you do, please inform us of the results at Fortune, Box 1597, + Rockville IL. Thank you. Ed.] +%% + PLAYGIRL, Inc. + Philadelphia, Pa. 19369 +Dear Sir: + Your name has been submitted to us with your photo. I regret to +inform you that we will be unable to use your body in our centerfold. On +a scale of one to ten, your body was rated a minus two by a panel of women +ranging in age from 60 to 75 years. We tried to assemble a panel in the +age bracket of 25 to 35 years, but we could not get them to stop laughing +long enough to reach a decision. Should the taste of the American woman +ever change so drastically that bodies such as yours would be appropriate +in our magazine, you will be notified by this office. Please, don't call +us. + Sympathetically, + Amanda L. Smith + +p.s. We also want to commend you for your unusual pose. Were you + wounded in the war, or do you ride your bike a lot? +%% +POCKET POOL: + Well, for guys, it's two-ball in the side pocket. + For girls, it's playing the slots. +%% +POLISH FLY: + You put it in her drink and she begs you to take her bowling. +%% +PREMATURE EJACULATOR: + Troubled shooter. +%% +PUBIC HAIR: + Organic dental floss. +%% +Painters do it with even strokes. +%% +Pardon me, sir, but you've obviously +mistaken me for someone who gives a shit. +%% +People who live in glass houses should ball in the basement. +%% + People who write position papers often find themselves in an +enviable position. They are hired to write papers for both sides of the +position. + A good position paper will have many words in it like +"superincumbence," "egress," and "plurification." + You will not often find the phrase "lightweight dropcase +limp-wristed motherfucker" in a serious position paper. + Charts and multiplication tables should always be included in +position papers. They should look complicated enough to make Albert +Einstein stagger across the room for a Tylenol. + A good position paper will never underestimate the value of a +semicolon. + -- Dan Jenkins, "Baja Oklahoma" +%% +Physicists do it with charm. +%% +Picking up a man in a bar is like a snowstorm, you never know when +he's coming, how many inches you'll get or how long'll he'll stay. +%% +Politicians do it to everyone. +%% +Postulate #1: Nothing is better than sex. +Postulate #2: Masturbation is better than nothing. +Conclusion: Masturbation is better than sex. +%% +Pouring out his troubles to his great and good friend over a couple of +triple martinis, Brad had to confess that things weren't going too well +at home. "My wife and I just don't hit it off at night," he was saying +to Bart. "I hate to admit it, but I'm afraid I just don't know how to +make her happy." + "Hell, boy," said Bart, "there's really nothing to it. Let me +give you some advice. At bedtime, switch on a new Sinatra platter, turn +all the lights low and spray some perfume around the room. Next, tell +your wife to get into her sheerest nightie; then make sure you raise the +bottom window." + "Then what do I do?" asked Brad. + "Just whistle." + "Whistle?" + "That's right. I'll be waiting outside the window. When I hear +you whistle, I'll come right up and finish the job." +%% +Pregnancy -- the worst sexually transmitted disease of them all. +%% +Pregnancy begins with a single sell. +%% +Printers do it without wrinkling the sheets. +%% +Procrastinators do it tomorrow. +%% +Programmers do it bit by bit. +%% +Prostitution is the only business where you +can go into the hole and still come out ahead. +%% +Puff the Jewish dragon lived in Palestine, +And frollicked in the Autumn mist, +And drank Manishiewitz wine. +Little Rabbi Jacob loved that rascal Puff, +And brought him soup and Matzah balls, +And other kosher stuff. + +Then one day it happened, Puff was eating pork. +Little Rabbi Jacob took that dragon for a walk. +Gently he explained that dragons don't eat meat, +That come from little piggies who have dirty filthy feet. +%% +Q. Do you know how to tell a Polack at a cockfight? +A. He's the only one with a duck. + +Q. Do you know how to tell an Aggie at a cockfight? +A. He's the only one who bets on the duck. + +Q. And do you know how to tell the Mafia is at the cockfight? +A. The duck wins! +%% +Q: Have you ever been picked up by the fuzz? +A: No, but I bet it hurts like hell. +%% +Q: How can a real man tell when his girl friend's having an orgasm. +A: Real men don't care. +%% +Q: How can you tell the bride at a WASP wedding? +A: She's the one kissing the golden retriever. +%% +Q: How can you tell when a WASP is sexually aroused? +A: By the stiff upper lip. +%% +Q: How can you tell when your girlfriend has had an orgasm? +A: Who cares? +%% +Q: How did Hellen Keller burn the side of her face? +A: She answered the iron. + +Q: How did she burn the other side of her face? +A: They called back. +%% +Q: How do you fit 1000 dead babies into a phone booth? +A: Cusinart. + +Q: How do you get them back out? +A: Doritos. +%% +Q: How do you get a woman to stop having sex with you? +A: Propose. +%% +Q: How do you hide an elephant in a cherry tree? +A: Paint his balls red and his toenails green. + +Q: Ever see an elephant in a cherry tree? +A: No -- so it must work pretty well! + +Q: How did Tarzan die? +A: Picking cherries!!! +%% +Q: How do you know your elephant had her period? +A: There's a nickel on your dresser and your mattress is missing. +%% +Q: How do you make a dead baby float? +A: With 2 scoops of dead baby and some rootbeer. +%% +Q: How do you tell if two elephants have + been making love in your backyard? +A: Your Hefty trashcan liners are missing. +%% +Q: How do you tell if you're making love to a nurse, + a schoolteacher, or an airline stewardess? +A: A nurse says: "This won't hurt a bit." + A schoolteacher says: "We're going to have to do this + over and over again until we get it right." + An airline stewardess says: "Just hold this over your mouth + and nose, and breath normally." +%% +Q: How do you tell that your roommate's gay? +A: When his cock tastes like shit. +%% +Q: How does a girl know she's sleeping with a Computer Scientist? +A: It isn't hard. +%% +Q: How does a mink get babies? +A: The same way babies get minks. +%% +Q: How many Aggies does it take to eat an armadillo? +A: Three, one to eat it, and two to watch for traffic. +%% +Q: How many feminists does it take to screw in a lightbulb? +A: NONE! THAT'S NOT FUNNY!!!!! +%% +Q: How many heterosexual males does it take + to screw in a light bulb in San Fransisco? +A: Both of them. +%% +Q: How many lesbians does it take to screw in a lightbulb? +A: Ten. One to do it, and nine to talk about how gratifying + it was without a man. +%% +Q: If Tarzan was Jewish, and Jane was a princess, + what would Cheetah have been? +A: A fur coat. +%% +Q: What can you use used tampons for? +A: Tea bags for vampires. +%% +Q: What did Raggedy Anne say to Pinocchio as she was + sitting on his face? +A: Tell the truth! Tell a lie! Tell the truth! Tell a lie! +%% +Q: What do a walrus and a tupperware container have in common? +A: They both like a tight seal. +%% +Q: What do elephants use instead of tampons? +A: Sheep. Well, they used to, anyway. There have been so + many cases of Toxic Flock Syndrome recently that their + ewes has been discouraged. + +Q: Why do elephants have trunks? +A: Sheep don't have strings. +%% +Q: What do two WASPs say after making love? +A: Thank you very much. It'll never happen again. +%% +Q: What do you call a blind, deaf-mute, quadraplegic Virginian? +A: Trustworthy. +%% +Q: What do you call a nun who has had a sex change operation? +A: A transistor. +%% +Q: What do you call a truck load of vibrators? +A: Toys for twats. +%% +Q: What do you call a woman who can suck a + golf ball through 50 feet of garden hose? +A: Darling. + [Often? Ed.] +%% +Q: What do you call couples that use that rhythm method? +A: Parents. +%% +Q: What do you do if an Irishman throws a pin at you? +A: Run like hell, he's got a grenade in his mouth!! +%% +Q: What do you do with an elephant with three balls? +A: Walk him and pitch to the rhino. +%% +Q: What do you get when you cross a computer and a JAP? +A: A computer that won't go down on you. +%% +Q: What do you get when you cross a rooster with a telephone pole? +A: A thirty foot cock that wants to reach out and touch someone! +%% +Q: What do you get when you cross an onion with a donkey? +A: Well, most of the time you get an onion with big ears, but every + once in a while you get a piece of ass that will bring tears to + your eyes... +%% +Q: What do you say to a Puerto Rican in a three-piece suit? +A: Will the defendant please rise? +%% +Q: What goes green, red, green, red, green, red, pink? +A: A frog in a blender. + +Q: What do you get if you add 2 eggs to it?? +A: Frognogg. If you drink it, you croak. +%% +Q: What is black and white and red all over? +A: Half a nun. +%% +Q: What is green and comes in Brownies? +A: Boy Scouts. +%% +Q: What is the difference between snow-men and snow-women? +A: Snowballs! +%% +Q: What's a JAP's (Jewish American Princess) dream house? +A: Fourteen rooms in Scarsdale, no kitchen, no bedroom. +%% +Q: What's a WASPs idea of open-mindedness? +A: Dating a Canadian. +%% +Q: What's black and white and red all over and can't go through + revolving doors? +A: A nun with a javelin through her head. +%% +Q: What's buried in Grant's tomb? +A: A corpse. +%% +Q: What's hard going in and soft and sticky coming out? +A: Chewing gum. +%% +Q: What's invisible and smells like carrots? +A: Bunny farts. +%% +Q: What's red and has 7 dents? +A: Snow White's cherry. +%% +Q: What's the difference between a dog and a fox? +A: About four drinks. +%% +Q: What's the difference between a man and a toilet? +A: A toilet doesn't follow you around for a week after you flush it. +%% +Q: What's the difference between a man and the weekend? +A: The weekend never comes too soon. +%% +Q: What's the difference between a sorority girl and a fast car? +A: Not everyone's been in a fast car. +%% +Q: What's the difference between erotic and kinky? +A: Erotic is when you use a feather. + Kinky is when you use the whole bird... +%% +Q: What's the difference between hard and dark? +A: It stays dark all night. +%% +Q: What's the difference between your girlfriend and the Titanic? +A: Only 1100 men went down on the Titanic. +%% +Q: What's the last thing that goes through a + grasshopper's mind when he hits your windshield? +A: His ass. + +Q. What's the second-to-last thing to go + through a grasshopper's mind when he hits your windshield? +A. Oh, SHIT!! +%% +Q: What's white and crawls up your leg? +A: Uncle Ben's Perverted Rice. +%% +Q: What's worse than getting raped by Jack the Ripper? +A: Getting fingered by Captain Hook! +%% +Q: Where does Catwoman go for a good time? +A: To the batpoles, Robin! +%% +Q: Where does virgin wool come from? +A: Ugly sheep. +%% +Q: Where'd your girlfriend get those crow's feet? +A: From squinting and saying, "Suck what!?" +%% +Q: Why can't Hellen Keller have children? +A: Because she's dead. +%% +Q: Why did Captain Kirk piss on the bridge? +A: He wanted to boldly go where no man had gone before! +%% +Q: Why did God invent booze? +A: So ugly men could get laid too. +%% +Q: Why did Hellen Keller go all the way on her first date? +A: She'd never been taught to say no. +%% +Q: Why did Menachem Begin invade Lebanon? +A: To impress Jodie Foster. +%% +Q: Why did Ted Kennedy report the accident 8 hours after Mary + Jo Kopechne drowned? +A: Do you have any idea how hard it is to dress a woman underwater? +%% +Q: Why do dogs lick their private parts? +A: Because they can. +%% +Q: Why do ducks have webbed feet? +A: To stamp out forest firest. + +Q: Why do elephants have big flat feet? +A: To stamp out flaming ducks. +%% +Q: Why do men marry women? +A: You can't teach sheep to do housework. +%% +Q: Why do mice have such small balls? +A: Very few of them know how to dance! +%% +Q: Why do women have vaginas? +A: So when they're drunk, you can carry them like a six-pack. +%% +Q: Why do you put a baby in a blender feet first? +A: So you can watch the expression on its face. +%% +Q: Why does an elephant have 4 feet? +A: Because 8 inches isn't enough. +%% +Q: Why is it that Mexico isn't sending anyone to the '84 summer games? +A: Anyone in Mexico who can run, swim or jump is already in LA. +%% +RANDEL: + A nonsensical poem recited by Irish schoolboys as an + apology for farting at a friend. + -- Mrs. Byrne's Dictionary of Unusual, + Obscure & Preposterous Words +%% +REAL BUDDY: + Someone who'll go downtown and get two blowjobs, + and come back and give you one. +%% +REFORMED: + A synagogue that closes for the Jewish holidays. +%% +REJECTION: + When you're masturbating and your hand falls asleep. +%% +ROWING: + Eight big men and their cute little cox. +%% +RUGBY: + A sport requiring leather balls. +%% +Ralph: Lisa, you have no tits and a awful tight pussy. +Lisa: Ralph... get off my back!! +%% +Reach out and fuck someone. +%% +Reefers and roach clips and papers and rollers +Cocaine and procaine for twenty year molars +Reds and peyote to work out your bugs +These are a few of my favorite drugs. + +Uppers and downers and methedrine freakout +Take some amphetamines, watch your brains leak out +Acid and mescaline pull out your plugs +These are a few of my favorite drugs. + +Backs that are perfect for carrying monkeys +Users of heroin, often called junkies +Methadone helps then to stop being thugs +Takes them off one of my favorite drugs. + + On a bad trip + When the cops come + When I lose my head + I simply take more of my favorite drugs + And then I'm not sad -- I'm dead! + -- My Favorite Drugs, sung to "My Favorite Things" +%% +Religion is fine, Churchianity sucks. +%% +Remember, when preparing a dish for bedtime, +champagne is the best tenderizer. +%% +Remember when you were a kid and the boys didn't like the girls? Only +sissies liked girls? What I'm trying to tell you is that nothing's +changed. You think boys grow out of not liking girls, but we don't grow +out of it. We just grow horny. That's the problem. We mix up liking +pussy for liking girls. Believe me, one couldn't have less to do with +the other. + -- Jules Feiffer +%% +Revenge is sleeping with your enemy's wife. +Sweet revenge is the realization that she's a lousy lay. +%% +Rogue players do it with all sorts of different animals. +%% +Roses on your piano isn't nearly as good as tulips on your organ. +%% +SMALL: + Is it in yet? +%% +SPINSTER: + Unlusted number. +%% +SUCCESSFUL CUNNILINGUS: + When you wake up the next morning + with a face like a frosted doughnut. +%% +SUGAR DADDY: + A man who can afford to raise cain. +%% +Said Einstein, "I have an equation +Which to some may seem Rabelaisian: + Let V be virginity + Approaching infinity; +Let P be a constant persuasion; + +"Let V over P be inverted +With the square root of Mu inserted + N times into V ... + The result, Q.E.D., +Is a relative!" Einstein asserted. +%% +Said the attractive, cigar-smoking housewife to her girl-friend: "I +got started one night when George came home and found one burning in +the ashtray." +%% +Sam Lefkovitz is having an intimate party to celebrate his thirty +immensely profitable years in the construction business. + "You know," he laments to his friends, "over the years I have +constructed dozens of enormous projects in and around this city, but +am I known as Sam the Builder? No. + And over the years I have contributed literally millions of +dollars to charitable causes of one sort or another, but am I called +Sam the Philanthropist? No sir! + But suck one little cock..." +%% +Save Soviet Jewry -- Win Valuable Prizes!!!! +%% +Save a forest - eat a beaver! +%% +Save a mouse, eat a pussy! +%% +Save the whales. Club a seal instead. +%% +"Scott, baby," the sexually aggressive girl murmured as she guided +her date's finger to her clitoris, "This bud's for you." +%% +Sex and drugs and UNIX. +%% +Sex and drugs and rock and roll, +Is all my brain and body need. +Sex and drugs and rock and roll, +Are very good indeed. + +Take your silly ways, +Throw them out the window, +The wisdom of your ways, +I've been there and I know, +Lots of other ways... + -- Ian Drury, "New Boots and Panties" +%% +Sex is better than grass, if you have the right pusher. +%% +Sex is dirty, but only if you do it right. +%% +Sex is great, +Sex is grand, +Sex around here, +Is mostly by hand. +%% +Sex is just one damp thing after another. +%% +Sex is like a bridge game -- +If you have a good hand no partner is needed. +%% +Sex is not the answer. Sex is the question. "Yes" is the answer. +%% +Sex is what women have and men want. +%% +Share and enjoy, share and enjoy. +Journey through life with a plastic boy or girl by your side. +Let your pal be your guide. +And when it breaks down or starts to annoy, + or grinds when it moves and gives you no joy, + 'cause it digs up your hat, + or has sex with your cat, + sprays oil on your wall or rips off your door, + and you get to the point you can't stand any more. +Bring it to us, we won't give a shit. +We'll tell you: "Go stick your head in a pig". +%% +She asked me if I loved her still. +"Yes," I replied. "I've never had you any other way." +%% +She called her parakeet Onan, because he spilled his seed. + -- Dorothy Parker +%% +She hates testicles, thus limiting the men +she can admire to Democratic candidates for president. + -- John Greenway, "The American Tradition", + on feminist Elizabeth Gould Davis +%% +She never liked zippers, she said, +Until she opened one in bed. +%% +She was a farmer's daughter but she couldn't keep her calves together. +%% +She was wearing a very tight skirt, and when she tried to board the Fifth +Avenue bus she found she couldn't lift her leg. She reached back and +unzipped her zipper. It didn't seem to do any good, so she reached back +and unzipped it again. Suddenly the man behind her lifted her up and put +her on the top step. + "How dare you?" she demanded. + "Well, lady," he said, "by the time you unzipped my fly for the +second time I thought we'd become good friends." +%% +She's fine, upstanding, and wonderful laying down. +%% +Short man who dance with tall woman gets bust in mouth. +%% + Shortly after arriving at their honeymoon destination, the +still-nervous groom became worried about the state of his bride's innocence. +Deciding on a direct confrontation, he quickly undressed, pointed at his +exposed manhood and asked his mate, "Do you know what this is?" + Without hesitation, she blushingly answered, "That's a wee-wee." + Delighted at the idea of instructing his naive wife in the ways of +love, the husband whispered, "From now on, dearest, this will be called a +prick." + "Oh, come now," the girl chided. "I've seen lots of pricks and I +assure you, that's a wee-wee." +%% +Sixteen'll get you twenty. +%% +Sniff sniff... Hey! Who farted? +%% +Snow White: + "Gee guys, I've always dreamed of getting seven inches... + but not an inch at a time! +%% +So, how's your love life? +Still holding your own? +%% +So, if there's no God, who changes the water? + -- New Yorker cartoon of two goldfish in a bowl +%% +So this elderly couple were sitting in their tiny cold water flat on the +lower East Side when the husband said, "Doris, we're in bad shape. Inflation +has eaten up our Social Security check. The next one isn't due for a week +and we've got no money left for food." + "Could I do anything to help?" she asked. + "Yes," he said. "I hate to see you do this but it's the only way. +You're going to have to go out and hustle." + "Me?" she asked. "At the age of sixty-five?" + "It's the only way," he said. +Resigned to the situation, she went out into the warm night. She came +staggering in early the next morning. + "How did you do?" asked the husband. + "Here," she said, "I've got four dollars and ten cents." + "Four dollars and ten cents," he said . "Who gave you the ten cents?" + "Everybody," she said. +%% +So this traveling salesman got an audience with the Pope. + "Hey, father," he said, "have you heard the joke about the two +Polacks who --" + "My son," the Pope reminded him, "I'm Polish." +The salesman thought for a moment. + "That's okay, Father," he said. "I'll tell it very slowly." +%% +So you fucked up... you trusted us! + -- Animal House +%% +Sodomy, fellatio, cunnilingus, pederasty, +Father, why do these words sound so nasty? + -- Hair +%% +Sodomy is a pain in the ass. +%% +Some women are like musical glasses. +To keep them in tune they must be wet. + -- Samuel Coleridge +%% +Sometimes, you just gotta say "What the fuck." + -- Risky Business +%% +Special tonight, the best toot in town at prices you won't believe!! +Also, the finest dope, brought all the way from Columbia by spirited +young adventurers. All available tonight, as usual, in the graduate +students bullpen from 11: pm on, usual terms and conditions. +Faculty members especially welcome. +%% +Statisticians do it with 95 percent confidence. +%% +Statisticians probably do it. +%% +Sticks and stones may break my bones but whips and chains excite me!!! +%% +Success is like a fart -- only your own smells nice. + -- James P. Hogan +%% +Support the Girl Scouts! + (Today's Brownie is tomorrow's Cookie!) +%% +Support the right of unborn males to bear arms! + -- A public service announcement from Phyllis Schlafly, + the Catholic Church, and the National Rifle Association +%% +Systems people do it with a small, but clean, interface. +%% +TAXIDERMIST: + A man who mounts animals. +%% +TEAR LEATHER: + To become excited, as in the sentence + "Robin Hood tore his leather jerkin' off." +%% +TEARING OFF A QUICKY: + Gunning the jump. +%% +TEXAN: + A wet-back that didn't make Oklahoma. +%% +THE PERFECT WOMAN: + Four feet tall, no teeth and a flat head so you can rest your drink. +%% +THORNY: + A thailor at thea. +%% +TOURIST: + A pretty girl in Oklahoma. +%% +TRUST ME: + Los Angeles for "Fuck you, your mother, + and the horse she rode in on." +%% +TRUST: + Two cannibals having oral sex. +%% +Teddy Kennedy: A Blond in Every Pond! +%% +Teen-age prostitution: the problem is mounting! +%% +Tequila my girl, is deceiving: +Take two at the very most. +Take three and you're under the table, +Take four and you're under the host. +%% +Test makers do it: + A: sometimes + B: always + C: never +%% +That girl could suck the chrome off a bumper. +%% + "That wife of mine is a liar," said the angry husband to a +sympathetic pal seated next to him in a bar. + "How do you know?" the friend asked. + "She didn't come home last night, and when I asked her where +she'd been she said she'd spent the night with her sister Shirley." + "So?" + "So, she's a liar. I spent the night with her sister Shirley." +%% +The Father, the Son and the Holy Ghost would never throw the +Devil out of Heaven as long as they still need him as a fourth for bridge. + -- New Libertarian Notes, #19 +%% +The Israelites were all waiting anxiously at the foot of the mountain, +knowing that Moses had had a tough day negotiating with God over the +Commandments. Finally a tired Moses came into sight. + "I've got some good news and some bad news, folks," he said. "The +good news is that I got Him down to ten. The bad news is that adultery's +still in." +%% +The Pope is working on a crossword puzzle one Sunday afternoon. He stops +for a moment, scratches his forehead, then asks a Cardinal, "Can you think +of a four-letter word for `woman' that ends in `u-n-t'?" + "Aunt," replies the Cardinal. + "Say, thanks," says the Pope. "You got an eraser?" +%% +The REVERSE function works on the opposite SEXPR. +%% +The San Francisco police are nothing if not sensitive to the mood of the +community. The word is that Dirty Harry has been replaced by Bitchy Gerald. +%% + The Snack +Oh my God, screamed Mommy, You went and ate the Baby. + +What baby? asked Daddy. You know that's just the last of the leftover donkey. + +Donkey, my ass! said Mommy with some sentience. Do you think I don't + recognize my own baby? Why I can still see his little privates + caught in the gap between your front teeth. How many times have + I told you to take only what's on the *top* two shelves of the freezer? + +But there wasn't a thing to eat, cried Daddy. + And am I not the master of my own? + +Nothing to eat? + What about the elephant testicles in aspic that I put up for you + just last week in the ball jar? Our very first baby, too, wailed + Mommy, that I was saving for Christmas dinner. + +Testicles, testicles, said Daddy. A man gets tired of testicles. + -- L.L. Zeiger +%% +The abbess of a nunnery was instructing a group of novices on the house rules +of her particular order. The indoctrination period, which went on for hours, +began with "No washing of undies in the founts," and ended with "Lights out at +nine. Candles out at ten." +%% +The attractive and grief-stricken widow had been living in seclusion at the +home of her deceased husband's younger brother for several weeks. One evening, +when she could no longer control her emotions, she barged into her brother-in- +law's study and pleaded, "James, I want you to take off my dress." Shyly, +the brother-in-law did as she requested. "Now," she continued, "take off my +slip." He again complied. "And now," she said, with a slight blush, "remove +my panties and bra." Once more James obeyed her command. + Then, regaining her composure, she stared directly at the young man +and boldly announced, "I have only one more request, James. Don't ever let +me catch you wearing my things again." +%% +The best way to cut off a cat's tail is to repossess his Jaguar. +%% +The blacksmith told me before he died, +And I have no reason to believe that he lied, +That no matter how he tried, +His wife was never satisfied! + +And so he built a bloody great wheel, +Harnessed to a cock of steel, +Two balls of brass were filled with cream, +And the whole damn thing was driven by steam. + +Round and round went the bloody great wheel, +In and out went the cock of steel, +Till at last the maiden cried, +"Enough! Enough! I am satisfied!" + +And now we come to the crucial bit -- +There was no way of stopping it. +And she was split from hole to hole, +And the whole fucking thing was covered in shit... +%% +The blind daters had really hit it off and at the end of the evening, as +they were beginning to undress each other in his apartment, the fellow said, + "Before we go any further, Charmaine, tell me -- do you have +any special fetishes that I should take into account in bed?" + "As a matter of fact," smiled the girl, "I do happen to have a foot +fetish -- but I suppose I'd settle for maybe seven or eight inches." +%% +The bottom-up approach always gets me buggered. + -- Sidney J. Hurtubise +%% +The butcher, the baker, the candlestick make her, why can't I? +%% +The computer is the ultimate polluter: +Its shit is indistinguishable from the food it produces. +%% +The country girl who became a city madam +has obviously gone from rags to rigids. +%% + The defense attorney was hammering away at the plaintiff: +"You claim," he jeered, "that my client came at you with a broken bottle +in his hand. But is it not true, that you had something in YOUR hand?" + "Yes," the man admitted, "his wife. Very charming, of course, +but not much good in a fight." +%% + The devout Jew was beside himself because his son had been dating +a shiksa, so he went to visit his rabbi. The rabbi listened solemnly to +his problem, took his hand, and said, "Pray to God." + So the Jew went to the synagogue, bowed his head, and prayed, "God, +please help me. My son, my favorite son, he's going to marry a shiksa, he +sees nothing but goyim..." + "Your son," boomed down this voice from the heavens, "you think +you got problems. What about my son?" +%% +The difference between a lawyer and a rooster, is that +the rooster gets up in the morning and clucks defiance. +%% +The difference between a sorority girl and a bowling ball +is that you can only get three fingers in a bowling ball. +%% +The difference between like and love is the +same as the difference between a spit and a swallow. +%% +The difference between this school and a cactus plant +is that the cactus has the pricks on the outside. +%% +The difference between women and girls +is as much as twenty years in some states. +%% + The doctor had just finished giving the young man a thorough +physical examination. "The best thing for you to do," the M.D. said, +"is give up drinking, give up smoking, get to bed early and stay away +from women." + "Doc, I don't deserve the best," pleaded his patient. "What's +second best?" +%% +The early worm gets the bird. +%% +The five-alarm fire had been raging out of control for hours, pouring thick, +black smoke over the street. At last the blaze was under control and the +fire chief began accounting for his men. Two were missing, so he ordered +a search. Captain Kelly finally rounded a fire truck parked in an alley +and found, to his shock, one fireman with his trousers down leaning over a +garbage can and another fireman screwing him in the ass. + "What's the meaning of this!", the captain roared. + "Jones here had passed out from smoke inhalation," the fireman on +top panted. + "You're supposed to give mouth to mouth resuscitation for that!" +the captain yelled. + "I know. That's what started this," the fireman replied. +%% + The foreman of a lumber camp put a new workman on the circular saw. +As he turned away, he heard the man say, "Ouch". + "What happened?" + "Dunno," replied the man. "I just stuck out my hand like this, and +-- well, I'll be damned. There goes another one!" +%% +The fucking ain't worth the fighting. +%% +The girls that go to see a man's etchings +may not know art, but they know what they like. +%% +The good doctor had been an inspiration to the jungle natives. He had cured +their sick and taught them the religious and moral values of his own England. +He was loved and respected by every native in the village, but on this +particular afternoon the chief was obviously troubled as he entered the +doctor's hut. "You live among my people long time now," said the chief. +"You tell us not right for a man and girl to be close together before +marriage and we believe what you say. This morning white child born to +woman in village. You only white man in jungle. What I tell my people?" + The doctor smiled and led the chief to a window. "My son," he said, +"I'll won't attempt to give you a full scientific explanation for the +phenomenon known as an albino. But look at the flock of sheep upon that +hill. Every one is snow white except one. The white baby born to the +woman in your village means nothing more or less than that one black sheep +in the white flock. It is simply one of nature's mysterious accidents." + The black chief became embarrassed and looked at his feet. "OK, doc," +he said. "You no tell -- I no tell." +%% +The good news is that the horse is dead, but your mother's pregnant. +%% +The greatest lies of all time: + (1) I love you. + (2) This won't hurt a bit. + (3) The Mercedes is paid for. + (4) The check is in the mail. + (5) I was just going to call you. + (6) I've always worn cowboy boots. + (7) I swear I won't come in your mouth. + (8) Of course I'll respect you in the morning. + (9) We have a really challenging assignment for you. + (10) I'm from the government, and I'm here to help you. +%% +The hacker as a mate/lover and the signs of trouble: + +-- The morning after note reads: + Whiting, Barbara: + I enjoyed last night. We really interfaced. You looked so cute + I wanted to byte your ear. +-- He believes Steve Wozniak offered the Apple to Adam. +-- The people he tries to emulate are five years his junior. +-- The last straw: + Once again, your date has lost all track of time debugging a new + program and shows up an hour late. + + You Don't...: + Make nasty asides regarding his 5-1/4 inch floppy. + You Do...: + Remind him that "going down" doesn't necessarily + indicate a malfunction. +%% +The honeymoon is over when a quickie before dinner refers to a short drink. +%% + The honeymooning couple agreed it was a fine day for horseback riding. +After a mile or so, the bride's mount cantered under a low tree and a +branch scraped her forehead lightly. The groom dismounted, glared at his +wife's horse, and said, "That's number one." + The ride then proceeded. After another mile or so, the bride's +horse stumbled over a pebble and the lady suffered a slight jostling. +Again, her man leapt from his saddle and strode over to the nervous animal. +"That's two," he said. + Five miles later, the bride's horse became frightened when a rabbit +crossed its path, reared up and threw the girl. Immediately, the groom was +off his horse. "That's three!", he shouted, and, pulling out a pistol, he +shot the horse between the eyes. + "You brute!" shrieked his bride. "Now I see the kind of man I +married! You're a sadist, that's what!" + The groom turned to her coolly. "That's one," he said. +%% +The hungover couple dawdled over a midafternoon breakfast, after a +particularly wild all-night party held in their fashionable apartment. + "Dearest, this is rather embarrassing," said the husband, "but +was it you I made love to in the library last night?" + His wife looked at him reflectively and then asked, "About what +time?" +%% +The husband was disturbed by his wife's indifferent attitude towards him +and the marriage counselor suggested he try being more aggressive in his +lovemaking. + "Act more like a romantic lover and less like a bored spouse," he +was advised. "When you go home, make love to her as soon as you meet -- +even if it's right inside the front door." + At the next consultation, the adviser was pleased to hear that the +husband had followed his instructions. "And how did she react this time?" +the consultant asked. + "Well, to tell you the truth," the husband replied, "she was still +sort of indifferent. But one thing I've got to admit: her bridge club went +absolutely wild!" +%% +The husband wired home that he had been able to wind up his business trip a +day early and would be home on Thursday. When he walked into his apartment, +however, he found his wife in bed with another man. Furious,he picked up his +bag and stormed out. He met his mother-in-law on the street, told her what +had happened and announced that he was filing for divorce in the morning. + "Give my daughter a chance to explain before you take any action," +the older woman pleaded. Reluctantly, he agreed. + An hour later his mother-in-law phoned the husband at his club. +"I knew my daughter would have an explanation," she said, a note of triumph +in her voice. "She didn't receive your telegram!" +%% +The king arranged a regal marriage for his daughter -- a bond that would unite +two great kingdoms. Yet, because the young couple seemed so formal to each +other, he posted a spy outside the royal wedding chamber and demanded a full +account of the wedding night's progress. + "It's hard to tell," said the spy the next morning. "When the prince +entered the chamber, I heard the princess say, quite formally, 'I offer you my +honor.' Then the prince said, with equal courtliness, 'I honor your offer.' +And that's the way it went all night long -- honor, offer, honor, offer. +%% +The largest gay community in the U.S. (as a percentage of total population) +is not in San Francisco, but in Iowa Falls, Minnesota (pop. 763), a small +town in which virtually everyone is gay. In 1976, a group of about 100 +gays fleeing persecution in the South settled in the town, and soon won a +majority on the town council. Ordinances prohibiting heterosexual acts +soon followed. "After all," said mayor Harry Whalen, "If the Supreme Court +has refused to strike down laws prohibiting homosexual acts, then our +anti-straight laws are equally valid." Rigorous enforcement of those laws +has resulted in a community that is now almost 100% gay. Said one long-time +resident: "I've lived here 35 years and didn't want to leave, but I didn't +want to give up sex either. Then my neighbor Ed came over one night, and +said how about I do it with him, and my wife Millie could do it with his +wife. Well, I found it wasn't nearly as bad as I thought it was gonna be. +Fact is, I rather like it." +%% +The little boy pointed to two dogs in the park and asked his father what +they were doing. "They're making puppies, son," replied the father. + That night, the boy wandered into his parents' room while they were +making love. Asked what they were doing, the father replied, "Making you +a baby brother." + "Gee, Dad," the boy pleaded, "turn her over -- I'd rather have a +puppy." +%% +The little old lady rushed into the taxidermist and unwrapped a package +containing two recently deceased monkeys. Her instructions to the proprietor +were delivered in a welter of tears. + "Favorite pets... (blubber,sob)... caught cold... (moan)... Don't +see how I'll live without them... (weep,sob)... want to have them stuffed... +(blubber,blubber)!" + "Of course, madam," said the proprietor in an understanding voice, +"and would you care to have them mounted?" + "Oh, no," she sobbed, "shaking hands. They were just close friends." +%% +The most common form of marriage proposal: "YOU'RE WHAT!?" +%% +The moving finger having writ... gestures. +%% +The nervous young bride became irritated by her husband's lusty advances on +their wedding night and reprimanded him severly. + "I demand proper manners in bed," she declared, "just as I do at +the dinner table." + Amused by his wife's formality, the groom smoothed his rumpled hair +and climbed quietly between the sheets. "Is that better?" he asked, with a +hint of a smile. + "Yes," replied the girl, "much better." + "Very good, darling," the husband whispered. "Now would you +be so kind as to please pass the pussy?" +%% +The new rooster caused a great stir in the barnyard. From resplendent comb +to defiant spurs, he was the picture of young bantamhood. Almost immediately +upon arrival, he was greeted by and elderly rooster who took him behind the +barn and whispered in his ear: "Young fellow, I'm long past my prime. All I +want now is peace and solitude. So you take over right now as ruler of the +roost with my blessings." + The newcomer did just that. He went about his squirely duties as only +a young rooster could. After several days, however, the elder rooster again +took the young champion behind the barn. "Kid," he said, "the hens are after +me for giving up my position so readily. So why don't we have a race, say, +ten laps around the farmhouse? The winner becomes undisputed keeper of the +henhouse and the hens will stop nagging me. + The young rooster, with only contempt for his elder, agreed. +Surprisingly, the older one jumped off to an early lead. His counterpart, +weakened by the activities of the previous week, was never quite able to +overtake him. As they rounded the barn for the fourth time, the elder rooster +maintained a formidable lead. + Suddenly, a shotgun blast rang out. The young rooster fell in the +dust, his plumage riddled with buckshot. + "Dammit, Emmy," said the farmer. "That's the last rooster we buy +from Ferguson. Four of 'em this month, and every one's been queer." +%% +The only psychologically damaging thing about masturbation is +that there's nobody else to blame later for persuading you to do it. +%% +The other night I was having sex, but the girl hung up on me. +%% +The outraged husband discovered his wife in bed with another man. + "What is the meaning of this?" he demanded. "Who is this fellow?" + "That seems like a fair question," said the wife, rolling over. +"What IS your name?" +%% +The passionate young thing was having a difficult time getting across what +she wanted from her rather dense boyfriend. Finally she asked, + "Would you like to see where I was operated on for appendicitis?" + "Gosh, no!" he replied. "I hate hospitals." +%% +The penis mightier than the sword. +%% +The pleasure is momentary, +The position ridiculous, +The expense damnable. + -- Chesterfield, on sex +%% +The plural of spouse is spice. + -- R.A. Heinlein +%% +The police were investigating the mysterious death of a prominent businessman +who had jumped from a window of his 11th story office. His voluptuous private +secretary could offer no explanation for the action but said that her boss had +been acting peculiarly ever since she started working for him a month ago. + "After my very first week on the job," she said, "I received a +twenty-dollar raise. At the end of the second week he called me into his +private office, gave me a lovely black nightie, five pairs of nylon stockings +and said, 'These are for a beautiful, efficient secretary.' At the end of the +third week he gave me a gorgeous mink stole. Then, this afternoon, he called me +into his private office again, presented me with this fabulous diamond bracelet +and asked me if I would consider making love to him and what it would cost. +I told him I would, and because he had been so nice to me, he could have it +for five dollars, although I was charging all the other boys in the office ten +dollars. That's when he jumped out the window." +%% +The poor little doe +Crawled out of the woods, +Tired, bedraggled and blue. +"Look," she said, "What I did for a buck, +I should have asked for two!" +%% +The priest at Sunday mass noticed that Michael took a ten-dollar bill and two +one-dollar bills from the collection plate, instead of putting something in. +He thought to himself, I'd better watch out for Michael. The next week he +noticed the same thing. So he waited outside church when mass was over, and +as Michael came out, he accosted his and said, + "Michael, tell me -- why did you take out a ten-dollar bill and two +singles two weeks in a row, instead of putting money into the collection?" + Michael replied, "Father, I'm embarrassed, but I did it because I +wanted to go downtown for a blow job." + The priest looked suprised but said to Michael, "Listen, don't do +that anymore. I'll be watching you from now on." + When he got back to the rectory, the priest was still perplexed. +Finally he decided to call Mother Agatha at the convent. He said, "Mother, +you've been such a great friend of mine, I have a question I need to ask you. +What is a blow job?" + Mother Agatha replied, "Oh, twelve dollars, same as downtown." +%% +The problem with being best man at a wedding +is that you never get a chance to prove it. +%% +The problems with "Medflies" may have hurt Jerry Brown's chances to become a +Senator. After all, if they won't allow California fruit out of the state, +how is Brown going to get to Washington? +%% +The quality of a blow-job is determined by the +length of sheet you have to pull out of your ass. +%% +The real problem with fucking a sheep is that you have +to walk around in front every time you want to kiss her. +%% +The reason Roman Catholics are allowed to use the +rhythm method of birth control is that it doesn't work. +%% +The reason that sex is so popular is that it's centrally located. +%% +The rich man uses vaseline, + The poor man uses lard; +The worker uses axle grease + But gets it twice as hard. +%% +The romantic young man sat on the park bench with a first date. He was +certain his charming words and manner would win her as they had many others. + "Some moon out tonight,"he cooed. + "There certainly is," she agreed. + "Some really bright stars in the sky." + She nodded. + "Some dew on the grass." + "Some do," she said indignantly, "but I'm not that sort." +%% +The sergeant walked into the shower and caught me giving myself a +dishonorable discharge. Without missing a beat, I said... + "It's my dick and I can wash it as fast as I want!" +%% +The sex act is the funniest thing on the face of this earth. + -- Diana Rigg +%% +The sex life of spiders is very interesting. +He fucks her. +She bites his head off. + -- From a Women's Lib Poster +%% +The shy young man had been married for three months when he reported to his +doctor that his marriage was still in name only. The doctor, after hearing +the sad tale, told him that waiting until bedtime to make advances was causing +psychological pressure and advised him to take advantage of the next time he +felt in the mood. A week later, the doctor happened to meet the man again, +and noticed a new spring in his step. "My advice worked, I take it?" he +inquired. + The young man grinned. "Perfectly. The other night, we were having +supper, and as I reached for the salt -- so did she! Our hands touched... It +was as if an electric current ran through us. I leaped to my feet, swept the +dishes from the table and then and there consummated our marriage! There's +just one problem, however. We can't go back to The Four Seasons again..." +%% +The sun was shining brightly The breeze was blowing briskly, +And I could hardly wait, It made the flowers sway, +To ponder at my window The garden was enchanting +And gaze at my estate. On this inspiring day. + +My eyes fell on a little bird, I smiled at him cheerfully +With a beautiful yellow bill, And gave him a crust of bread, +I beckoned him to come and light And then I closed the window +Upon my window sill. And smashed his fucking head. + -- "Good Morning", Debbie Smith +%% +The surest sign that a man is in love is when he divorces his wife. +%% +The three most important parts of a stove: lifter, leg, and poker. +%% +The time has come for kicking ass and taking names. +%% +The two couples were enjoying their vacation together at a resort hotel. They +were in the middle of a game of Scrabble in the lobby when a thunderstorm cut +off the hotel's electricity, leaving little to do but retire to their rooms. +Bill was a rather devout man, so before getting into bed with his companion, +he said his prayers. As he got under the covers, the lightning suddenly +flashed through the window and he discovered that he was in the wrong room. +He instantly jumped up and started to dash for the hallway. "It's too late, +called the girl from the bed, "my guy doesn't pray." +%% +The two men feigned friendship but secretly hated each other's guts and took +great pleasure in giving one another the needle on any and all occasions. +This particular evening they met, quite by accident, at a popular bar. +The conversation started innocently enough; then one, with sudden inspiration, +ran his hand over the other's bald head and exclaimed, + "By God, Fred, that feels just like my wife's ass!" +The other ran his own hand over his head and nonchalantly retorted, + "Well, I'll be damned, Jim, so it does, so it does!" +%% +The very proper spinster didn't go out very often, but she had some important +shopping to do that morning and so decided to have her lunch in what appeared +to be a nice quiet respectable restaurant. With the noontime crowd, many +customers shared their tables with strangers; the spinster selected a seat +next to an attractive, young office girl. The girl finished her sandwich and +coffee, then settled back and lit up a cigarette. The older woman controlled +herself for a few moments and then snapped, + "I'd rather commit adultery than smoke in public." + "So would I," said the girl, "but I only have half an hour for lunch." +%% +The wages of sin are high -- unless you know someone who does it for nothing. +%% +The warden of the De Luxington preparatory school for boys was holding a +hearing. The lad before his desk, a very popular young fellow, was angrily +accusing one of his schoolmates of having assaulted him sexually. + "I must warn you, m'boy, this is a very serious charge, the warden +said. + "I don't care. I tell you it is true. He raped me, warden." The +youth pointed to another, somewhat larger boy smirking in the corner. +"That's him, sir, the one who forced me to do all those crimes against +nature. The bully!" + "Now tell me, son, as closely as you can, when this happened." + "Sir, two weeks ago on Wednesday at 4:00, then at 7:00 that same +evening, on Friday, twice on Saturday, two times on Monday, once on +Wednesday, and then he met that bitch Roy and he hasn't touched me since." +%% +The whole world is about three drinks behind. + -- Humphrey Bogart +%% +The word `spine' is, of course, an anagram of `penis'. This is true in +almost fifty percent of the languages of the Galaxy, and many people have +attempted to explain why. Usually these explanations get bogged down in +silly puns about "standing erect". + -- The Hitchhiker's Guide to the Galaxy +%% +The world is an 8000 mile in diameter spherical pile of shit. +%% +The young Georgia miss came to the hospital for a checkup. + "Have you been X-rayed?" asked the doctor. + "Nope," she said, "but ah've been ultraviolated." +%% +The young girl was having a heart-to-heart talk with her mother on her +first visit home since starting college. + "Mom, I have to tell you," the girl confessed. "I lost my virginity +last weekend." + "I'm not suprised," said her mother. "It was bound to happen sooner +or later. I just hope it was a romantic and pleasurable experience." + "Well, yes and no," the pretty student remarked. "The first eight +guys felt great, but after them my pussy got real sore." +%% +The young lady had an unusual list, +Linked in part to a structural weakness. +She set no preconditions. +%% + The young male race horse came from a long line of winners, and did +wonderfully in time trials. However, in actual races he proved a little too +romantic, and could never quite bring himself to pass a mare. + So one day the trainer went to him and told him he'd have to be +castrated. The young horse, knowing that it was either this or the glue +factory, took it philosophically. After all, having the operation was +almost a certain guarantee of a long and illustrious racing career. + After a short recovery period, the horse was again run in time +trials, and found to do as well as ever. But the first time he actually +ran in a race, he only went about ten paces, before getting a dejected look +on his face, turning around, and ambling back to the starting gates. + "What's the matter?" asked the trainer, "you were doing great!" + "Yeah, well how would you feel" replied the horse, "if five thousand +people took one look at you and shouted `they're off!'?" +%% + The young man took a blind date to the amusement park. They went +for a ride on the Ferris wheel. The ride completed, she seemed rather bored. +"What would you like to do next?" he asked. + "I wanna get weighed," she said. So he took her over to the weight +guesser. Next they rode the roller coaster. After that he bought her some +popcorn and cotton candy, then he asked what else she would like to do. + "I wanna get weighed," she said, bluntly. + I really latched onto a square one tonight, thought the boy, and +using the excuse that he had developed a headache, he took the girl home. +The girl's mother was surprised to see her home so early, and asked, "What's +wrong, dear, didn't you have a nice time tonight?" + "Wousy," said the girl. +%% +Then there was the girl who was engaged +to a gymnast -- 'til he broke it off. +%% +Then there was the girl whose boyfriend didn't smoke, drink or +swear, and never, ever made a pass at her. He also made his own dresses. +%% +Then there was the middle-aged businessman who took his spouse to Paris. +After traipsing with her from one mansion du couture to another, be begged +for a day off to rest and got it. With the wife gone shopping again, he +went to the Ritz Bar and picked up a luscious parisienne. They got on +well until the question of money came up. She wanted a hundred American +dollars; he offered fifty. They couldn't get together on the price; so +they didn't get together. That evening he escorted his wife to of the +nicer restaurants on the Rue de Rivoli, and there he spotted his gorgeous +babe of the afternoon seated at a table near the door. + "See, monsieur?" she said as they passed her. "Look what you got +for your lousy fifty bucks." +%% +There are Jews in the world, there are Buddhists, Every sperm is sacred, +there are Hindus and Mormons and then Every sperm is great, +there are those that follow Mohammed ...But... If a sperm is wasted, +I've never been one of them. God gets quite irate. + +I am a Roman Catholic Every sperm is wanted, +And have been since before I was born, Every sperm is good. +And the one thing they say about Catholics is Every sperm is needed, +They'll take you as soon as you're warm. In your neighborhood. + +You don't have to be a six-footer. Let the heathens spill theirs, +You don't have to have a great brain. On the dusty ground. +You don't have to have any clothes on, God shall make them pay for +You're a Catholic the moment Dad came Each sperm that can't be found. +...Because... + +Hindu, Taoist, Mormon, Every sperm is useful, +spill theirs just anywhere Every sperm is fine. +but God loves those who treat their God needs everybodies, +semen with more care. Mine, and mine, and mine. + -- Monty Python, "Every Sperm is Sacred" +%% +There are a couple of things about her I greatly admire. +%% +There are many ways to say "I love you", but fucking is the fastest. +%% +There are really not many jobs that actually require a penis +or a vagina, and all other occupations should be open to everyone. + -- Gloria Steinem +%% +There are three women on the fast track in a particular company. The +president realizes it's time to promote one of them, but they're all so +competent that he's not sure which one to choose. So he devises a little +test. One day while they're all at lunch, he places $500 on each of their +desks. #1 returns it to him immediately. #2 pockets it. #3 invests +in the market and returns $1,500 to him in the morning. Who gets the +promotion? The one with the big tits! +%% + There are two couples that want to convert to Catholicism. They go +and see a priest and he tells them that the first requirement is to abstain +from sex for thirty days. + Thirty days later, the couples come back to see the priest. He asks +the first couple if they passed the test. + "Father, we didn't so much as TOUCH one another during the last month. + "Congratulations," the priest replies, "you are now qualified to enter +the Church." Then, the priests asked the second couple how they did. + "Well, Father," the husband says, "everything was going just fine +until the 27th day. My wife bent over the freezer to get something out, and +I just happened to notice that she didn't have any panties on. I couldn't +stand it any more, so I walked over to her, dropped my pants, and slipped it +to her right there." + "That's DISGUSTING!", the priest bellows. "I can never let you into +the Church after something like that." + "I understand Father," the man replies sadly, "they won't let us +into Safeway anymore either." +%% +There are two sides to every divorce: yours and the shithead's. +%% +There is a definite parallel between shots of tequila and a +woman's breasts. One is not enough and three are too many. +%% +There is nothing as overrated as a bad +lay, or as underrated as a great shit. +%% +There is nothing wrong with screwing everyone in sight. +Boring your friends about it is the sin. + -- Mama Liz +%% +There once was a Sailor who looked through a glass +And spied a fair mermaid with scales on her... island. +Where seagulls flew over their nest. +She combed the long hair which hung over her... shoulders. +And caused her to tickle and itch. +The sailor cried out "There's a beautiful... mermaid. +A sittin' out there on the rocks." +The crew came a running, all grabbing their... glasses. +And crowded four deep to the rail. +All eager to share in this fine piece of... news. +... +"Throw out a line and we'll lasso her... flippers. +And soon we will certainly find +If mermaids are better before or be... brave +My dear fellows," The captain cried out. +And cursing with spleen. +This song may be dull, but it's certainly clean. + -- "The Clean Song", Oscar Brandt +%% +There once was a clergyman's daughter +Who detested the pony he bought her, + Till she found that its dong + Was as hard and as long +As the prayers her father had taught her. + +She married a fellow named Tony +Who soon found her fucking the pony. + Said he, "What's it got, + My dear, that I've not?" +Sighed she, "Just a yard-long bologna." +%% +There once was a young man from France +Who waited ten years for his chance; +Then he muffed it... +%% +There was a young fellow named Bliss +Whose sex life was strangely amiss, + For even with Venus + His recalcitrant penis +Would never do better than t + h + i + s + . +%% +There was a young fellow named Fyfe +Whose marriage was ruined for life, + For he had an aversion + To every perversion, +And only liked fucking his wife. + +Well, one year the poor woman struck, +And she wept, and she cursed at her luck, + And said, "Where have you gotten us + With your goddamn monotonous +Fuck after fuck after fuck? + +"I once knew a harlot named Lou -- +And a versatile girl she was, too. + After ten years of whoredom + She perished of boredom +When she married a jackass like you!" +%% +There was a young fellow named Skinner +Who took a young lady to dinner + At a quarter to nine, + They sat down to dine, +At twenty to ten it was in her. +The dinner, not Skinner -- Skinner was in her before dinner. + +There was a young fellow named Tupper +Who took a young lady to supper. + At a quarter to nine, + They sat down to dine, +And at twenty to ten it was up her. +Not the supper -- not Tupper -- It was some son-of-a-bitch named Skinner! +%% +There was a young fellow of Greenwich +Whose balls were all covered with spinach. + He had such a tool + It was wound on a spool, +And he reeled it out inich by inich. + +But this tale has an unhappy finich, +For due to the sand in the spinach + His ballocks grew rough + And wrecked his wife's muff, +And scratched up her thatch in the scrimmage. +%% +There was a young girl from New York +Who plugged up her cunt with a cork. + A woodpecker or two + Made the grade it is true, +But it totally baffled the stork. + +Till along came a man who presented +A tool that was strangely indented. + With a dizzying twirl + He punctured that girl, +And thus was the cork-screw invented. +%% +There was a young girl of Detroit +Who at fucking was very adroit: + She could squeeze her vagina + To a pin-point, or finer, +Or open it out like a quoit. + +And she had a friend named Durand +Whose cock could contract or expand. + He could diddle a midge + Or the arch of a bridge -- +Their performance together was grand! +%% +There was a young girl of LLewellyn +Whose breasts were as big as a melon. + They were big it is true, + But her cunt was big too, +Like a bifocal, full-color, aerial view +Of Cape Horn and the Straits of Magellan. +%% +There was a young harlot named Schwartz +Whose cock-pit was studded with warts, + And they tickled so nice + She drew a high price +From the studs at the summer resorts. + +Her pimp, a young fellow named Biddle, +Was seldom hard up for a diddle, + For according to rumor + His tool had a tumor +And a fine row of warts down the middle. +%% +There was a young lady from Munich +Who had an affair with a eunuch. + At the height of their passion + He dealt her a ration +%% +There was a young lady of Natchez +Who chanced to be born with two snatches, + And she often said, "Shit! + Why, I'd give either tit +For a man with equipment that matches." + +There was a young fellow named Locke +Who was born with a two-headed cock. + When he'd fondle the thing + It would rise up and sing +An antiphonal chorus by Bach. + +But whether these two ever met +Has not been recorded as yet, + Still, it would be diverting + To see him inserting +His whang while it sang a duet. +%% +There was a young man with a fiddle +Who asked of his girl, "Do you diddle?" + She replied, "Yes, I do, + But prefer to with two -- +It's twice as much fun in the middle." +%% +There was a young man with a prick +Which into his wife he would stick + Every morning and night + If it stood up all right -- +Not a very remarkable trick. + +His wife had a nice little cunt: +It was hairy, and soft, and in front, + And with this she would fuck him, + Though sometimes she'd suck him -- +A charming, if commonplace, stunt. +%% +There was a young woman of Croft +Who played with herself in a loft, + Having reasoned that candles + Could never cause scandals, +Besides which they did not go soft. + +Said another young woman of Croft, +Amusing herself in the loft, + "A salami or wurst + Is what I'd choose first -- +With bologna you know you've been boffed." +%% +There was once a newly-married couple. Now these two lovers were, well, +rather uptight about using expressions such as "having sex", "getting it on", +or "boffing the brains out". So, they decided to use the euphemism, "doing +the laundry" whenever the topic of sex came up. + One evening, hubby said, "Well, honey, feel like doing some laundry +tonite?", and she consented. The next evening, hubby again asked, "Sweetie, +feel like doing some laundry tonite?" Well, wifey wasn't really in the mood, +but complied. On the third night, when hubby approached her, asking her to +participate in doing still MORE laundry, she replied, "Oh, Hon, I'm really not +in the mood for doing any laundry tonite." + Well, hubby, being a bit disappointed, locked himself in the bathroom +and engaged in a spot of self-abuse instead. Upon returning to the living +room, wifey said, "Well, Poopsie, I've changed my mind -- how about doing +some laundry?" To which he replied, "Oh, no, that's okay, I just did a small +load!" +%% +There was once a salesman who had an outstanding record for selling tooth- +brushes. His boss, wondering at his unlikely success, sent a man out to +follow the salesman on rounds to see what pitch he gave that brought such +good results. It was soon found that this particular salesman went to the +corner of a busy street and opened up his briefcase, and on one side was the +assortment of toothbrushes, and on the other side various chips and garnishes +and a bowl of brownish stuff. He would grab a likely customer and give them +the following pitch. + "Good morning, ma'am, this is a commercial promotion for --- brand +of chip dip. Would you care to give it a try?" + At that point the person would try it, then spit it out and scream +in utter disgust, "This tastes like shit!" + The salesman would smile and say, "It is. You want to buy a +toothbrush?" +%% +There was something about her I liked, +but I couldn't put my finger on it. +%% +There's a vas deferens between men and women. +%% +There's many a slurp t'wixt the tip and the zip. +%% +There's more than one way to skin a cat: + Way #3 -- Krazy Glue and a toothbrush. + Way #27 -- Use an electric sander. + Way #32 -- Wrap it around a lonely frat man's pecker. + Way #33 -- A bicycle pump. +%% +There's nothing better than good sex. But bad sex? +A peanut butter and jelly sandwich is better than bad sex. + -- Billy Joel +%% +There's nothing wrong with America that a good erection wouldn't cure. + -- David Mairowitz +%% + These two project managers were walking through a residential area +one day, when they saw a dog (also male) sitting on a lawn, licking its +cock. (Why do dogs do that? Because they can). Anyway, the first manager +nudged the second and said, "Hey, look at that! That really looks like fun +-- I wish I could do that!" + Whereupon the second manager replied, "Well, I don't know... I tried +it once, and the damn dog bit me!" +%% + This 600-pound guy decides he can't go on living this way, so he seeks +the help of a clinic and proceeds to go on a drastic diet. It works: four +months later he's down to 160 pounds and feeling great, except for one problem. +He's covered with great folds of flesh where the fat used to be. He calls +up the clinic, and the doctor tells him not to worry. "There's a special +surgical procedure to correct this condition," the doctor assures him. "Just +come on over to the clinic." + "But doctor," the man pleads, "you don't understand. I'm too +embarrassed to be seen in public like this." + "Don't give it another thought," says the doctor. "Simply pull up +all the folds as high as they'll go, pile the flesh on top of your head, put +on a top hat, and come on over." + The guy follows the instructions and provokes no comments until he +reaches the clinic and is standing in front of the admitting nurse's desk, +dying of self-consciousness. "The doctor will be right with you," says the +nurse. "Say, what's that hole in the middle of your forehead?" + "My navel," blurts out the guy, "how d'ya like my tie?" +%% +This fellow rushed into a crowded tavern on Saturday night. Men and women +stood three-deep at the bar. Our man, who felt nature calling strongly, +looked about him but couldn't see anything that resembled a john. He saw a +stairway and bounded up the steps to the second floor in his increasingly +desperate search. Just as his bowels threatened to erupt, he spotted a +one-foot by one-foot hole in the floor. Now, at the end of his control, he +decided to take advantage of the hole. He dropped his pants, hunched over it, +and did his thing. Thoroughly relieved and relaxed, he sauntered down the +steps to find, to his suprise, that the crowded bar was now empty. + "Hey!" he yelled to the seemingly empty room, "Where is everyone?" + From behind the bar a voice responded, "Hey! Where were you when +the shit hit the fan?" +%% + This guy is taking a leak in a public men's room when a man enters +with his arms held out from his sides, bent at the elbows with his hands +dangling awkwardly, and comes over to him. + "Would you do me a favor and unzip my fly?" he asks. + Figuring the man to be a poor cripple, perhaps an accident victim, +the guy obliges, not without a flush of embarrassment when the man next +requests that he take out his prick and hold it in the appropriate position. + "Shake it off" is the next instruction, then "zip me up," and the +guy follows orders, wincing at his own embarrassment and at the shame of +being so helpless. + "Say, thanks," says the man, flouncing to the door. "I can't do a +*thing* 'til my nails dry!" +%% + This guy is walking down the beach one fine sunny day, feeling +good, when suddenly he sees this woman with no arms or legs in a wheelchair, +sobbing like crazy. He decides to be gallant, "What's wrong, miss?" + "I......I'm 21 and I I've never been kissed... +" + So this guy, he decides, what the hell, let's cheer up the poor lady. +He leans over and gives her a long wonderful kiss. This does wonders, and +the woman's face lights up and she grins from ear to ear, and the guy wanders +away feeling wonderful. + Well, next week, the same guy is walking along the same beach, and +sees the same girl who is once again sobbing her eyes out. Gallant to the +end, our hero says, "What's wrong, miss, can I help?" + "I...I'm 21 and I've never been fucked..." + The guy picks her up out of her chair, cuddles her close, and brings +her over to the shore, and throws her into the water. "Now you're fucked!" +%% +This guy makes an appointment with a doctor because his hemorrhoids are +really bothering him. The doctor gives him some suppositories and tells +him to come back in a week for a checkup. "How's it going?" he asks +the patient a week later. + "I gotta tell you the truth, Doc," said the man. "For all the +good these pills did me, I coulda shoved them up my ass." +%% +This guy was screwing his neighbors wife when a car pulls into the drive. +"My husband!" she screams. He panics and jumps out the window. He finds +himself on the street, naked, under cloudy skies. There is no place to hide +except in a crowd of joggers. As he runs along, a woman looks over and says, + "Do you always jog in the nude?" + "Yes ma'am!" he replies. + "Does it always result in that kind of sexual excitement?" she asks. + "Yes ma'am!" he replies. + "Do you always wear a condom?" + "Only when it rains, lady. Only when it rains." +%% +This here's the wattle +The emblem of our land +You can stick it in a bottle +Or you can hold it in your hand. + -- Monty Python +%% +This hot and dusty cowboy rode in from the mesa, filthy and exhausted. He +obviously had had nothing but his horse for company for a couple of weeks +and was looking forward to a couple of cold beers in the saloon. Swinging +off his horse and hitching it to the rail, the cowboy gave his horse an +affectionate slap on the neck. Then he astonished an old cowhand lounging +on the porch by moving around to the horse's hindquarters, lifting up its +tail and planting a demure kiss on its asshole. + "What'd you do that for?" asked the cowhand, completely repulsed. + "Chapped lips," said the cowboy, heading for the saloon doors. + "Wait a minute," said the old guy. "Whaddaya mean, chapped lips?" + "Keeps ya from lickin' 'em," explained the cowboy. +%% +This is National Smokers-Are-Shits Week. +%% +This is a test of the emergency cunnilingus system. +If this had been an actual emergency, you would have known it! +%% +This limerick is **SO**FILTHY** that it would offend you. +So I'll put in "di-dah" for the filthy words. + + Di-dah, di-dah, di-dah di-dah, + Di-dah di-dah di-dah, di-dah; + Di-dah di-dah di-dah? + Di-dah di-dah di-dah. + Di-dah di-dah, di-dah di-fuck. +%% +This story concerns a man who, after putting his son to bed each night, would +stand by his boy's door and listen to his son saying his prayers. One night, +the boy ended his prayers with, "God specially bless Granddad, who won't be +with us much longer." The man thought this was rather curious, but passed it +off as childish whimsy. The next day, however, he received a call from his +mother, informing him that his father had passed away early that morning. +During the next few weeks, he listened particularly closely to his son's +prayers, but noticed nothing unusual. Then, one night, the boy ended his +prayers with, "God specially bless Grandmom, who won't be with us much longer." +Although the shock of the original incident had worn off during the intervening +weeks, he nontheless phoned his mother to inquire as to her health. He went to +bed reassured, only to be awakened in the night by his sister calling with the +news that their mother had died suddenly in the night. The father had a series +of psychological tests done; nothing unusual was uncovered. About a month +later, the boy ended his prayers with, "God specially bless Daddy, who won't +be with us much longer." The man was panic-stricken, certain that he was +going to die during the night. He resolved to stay awake all night; if awake +and alert he should be able to prevent any tragedy. Morning came. Breathing +a huge sigh of relief, he went to get the paper off the porch. There, lying +dead on the doorstep, was the milkman. +%% +This system goes down more often than a two-dollar whore. +%% +This time it's for love; next time it's $100.00. +%% +Thou shalt not omit adultery. +%% +Thought: + Girls get minks the same way minks get minks! +%% +Three gay guys were discussing what they thought their favorite sport would +be. The first decides on football, 'cause of all those gorgeous guys bending +over in their tight pants. + "Definitely wrestling," sighs the second guy. "Those skimpy little +costumes, and think of the holds." + "Definitely baseball," says the third guy. "Why? Well, I'd be +pitching with the bases loaded, the batter would hit a savage one-hopper +right to me, I'd catch it, and I'd just stand there while the other guys +rounded the bases. Meanwhile, the crowd would be going crazy, screaming, +`Throw the ball, you cocksucker!' and that's what I like -- recognition!" +%% + Three girls and Feldstein were brought before the presiding judge. +The girls had been arrested for soliciting and the man was arrested for +selling ties without a license. "What do you do for a living?" the judge +asked, pointing at the first girl. + "Your honor, I'm a model," she replied. + "Thirty days," was the sentence. The judge turned to the second +girl. "What do you do for a living?" he asked. + "Your honor, I'm an actress." + "Thirty days." Then he turned to the third girl. "And how about +you?" he demanded. + "Well, your honor, I'm a prostitute. I'm not proud of it, but it's +the only way I can support my mother and my children since my husband's been +laid off." + "For telling the truth," he said, "I'm going to suspend sentence. +Furthermore, here's $100 to help your family out." Now he turns to Feldstein, +arrested for selling ties illegally. "And you," he said, "what do you do +for a living?" + "Your honor, I'm a prostitute. I'm not proud..." +%% +To a Real Woman, every ejaculation is premature. +%% +Tom Hayden is the kind of politician who gives opportunism a bad name. + -- Gore Vidal +%% +Tonight's piss is tommorrow's Tang. + -- An American astronaut +%% +Too ripped. Gotta go. +%% + Two Englishmen struck up a conversation with an American in the club +car of a train headed east out of Chicago. + "I say," queried the younger Englishman, "have you ever been to +London?" + The American laughed. "It was my home for two years during the war," +he said. "Had some of the wildest times of my life in that old town." + The older Englishman, a little hard of hearing, asked, "What did +he say, Reggie?" + "He said he's been to London, father," the younger Englishman +replied. + After a little lull in the conversation, the young man asked, "You +didn't, by any chance, meet a Hazel Wimbleton in London, did you?" + The American almost fell off his chair. "Hot Pants Hazel!" he +exclaimed. "My God, I shacked up with that horny broad for three months +just before I came back to the States!" + "What did he say, Reggie?" the older Englishman wanted to know. + "He says he knows Mother," the younger Englishman responded. +%% +Two anglers were fishing off Wight +And his bobber was dipping all night. + Murmured she, with a laugh, + "It's ready to gaff, +But don't break your rod which is light." + +A couple was fishing near Clombe +When the maid began looking quite glum, + And said, "Bother the fish! + I'd rather coish!" +Which they did -- which was why they had come. + +As two consular clerks in Madras +Fished, hidden in deep shore-grass, + "What a marvelous pole," + Said she, "but control +Your sinkers -- they're banging my ass." +%% + Two buddies had been out drinking for hours when their money finally +ran out. "I have an idea," croaked Al. "Lesh go over to my housh and borrow +shum money from my wife." + The two of them reeled into Al's living room, snapped on the light, +and lo and behold, there was Al's wife making love on the sofa to another man. +This state of affairs considerably unnerved Al's friend but didn't seem to +affect the husband. + "Shay, dear, you have any money for your ever-lovin' hushban?" he +asked. + "Yes, yes," she snapped. "Take my purse from the mantle, and for +Pete's sake, turn off those lights." + Outside they examined the purse, and Al proudly announced, "There's +enough here for a pint for you and a pint for me. Pretty good, eh, old buddy?" + "But, Al," protested his friend, somewhat sobered by the spectacle +he'd just witnessed, "what about that fellow back there with your wife?" + "The hell with him," replied Al. "Let him buy his own pint." +%% + Two gay guys, Larry and Phil, were driving down the highway when they +were rear-ended by a huge semi. Somewhat shaken, they maneuvered over to the +side of the road, where Phil instructed Larry to get out and confront the truck +driver. "Tell him we're going to sue, sue, sue!" he shrieked. + Obligingly, Larry got out and went around to the cab of the truck to +deliver this message to the huge, burly driver, whose response was to snarl, +"Ah, why doncha suck my cock." + "Phil," said Larry, coming back to their car, "I think we're going +to be able to settle out of court." +%% +Two gentlemen met at the club after a long absence and talked. + "Did you hear about Chumley?", one asked. + "No, old man, what about him?" + "Last seen in Africa, you know." + "No, I didn't." + "Yes. Appalling. Ran off with a gorilla. Fallen in love." + "Queer." + "Not Chumley. Female gorilla." +%% + Two little kids, aged six and eight, decide it's time to learn how +to swear. So, the eight-year-old says to the six-year-old, "Okay, you say +`ass' and I'll say `hell'". + All excited about their plan, they troop downstairs, where their +mother asks them what they'd like for breakfast. + "Aw, hell," says the eight-year-old, "gimme some Cheerios." +His mother backhands him off the stool, sending him bawling out of the room, +and turns to the younger brother. "What'll you have?" + "I dunno," quavers the six-year-old, "but you can bet your ass +it ain't gonna be Cheerios." +%% + Two longtime friends sipped Scotch in a local bar and talked about +their troubles. "And on top of everything else," said the first, "my wife +has cut me down to just once a week." + "That's too bad," agreed his friend, "but it could be worse. I know +two guys she's cut off altogether. +%% +Two men and a woman were stranded on a desert island - + +Two weeks later, the woman was so ashamed of what she +had been doing, she committed suicide. + +Two weeks later, the men were so ashamed of what they +had been doing, they buried her. + +Two weeks later, the men were so ashamed of what they +had been doing, they dug her back up. +%% +Two men were standing around talking while nearby a large German Shepherd +lay licking his balls. One man says to the other, "Damn, I wish I could +do that." + The other man replies, "Well, it's okay by me, but I think you +ought to get to know him a little first." +%% +Two midgets arrived at the convent door and asked to speak with the Mother +Superior. Led into her office, the first one asked respectfully "Excuse +me, your holiness, but are there any midget nuns in this convent?" + Receiving a reply to the negative, he asked whether any midget +nuns were to be found in any of the neighboring parish. Again the reply +was no. + The tiny man scratched his head and posed a final question. "Beggin' +your pardon, Mother Superior, but would you know of *any* midget nuns at +all, anywhere?" The nun shook her head. + At which the first midget turned to the second midget, put his hand +on his shoulder, and said, "You see, I told you you fucked a penguin!" +%% + Two morticians alternated in sharing the responsibility of covering +the night shift. One early morning about 3:00 am, a body was brought into the +mortuary, and the mortician began work. When he had unclothed the corpse, he +noticed a cork in the anus. Removing it, the strains of "Hello, Dolly, well, +hello, Dolly...!" were plainly heard being sung. He put the cork back, and +the singing stopped. Pulling it out again, the same song started, "You're +lookin' swell, Dolly!". Amazed, he telephoned his partner, and insisted he +come immediately to see something very unusual. Roused from sleep, the partner +asked if it could wait until morning. It took great persistence, but finally +the partner agreed to dress and come down to the shop. When he got there, he +said, "Now what was it that was so important you had to get me out of bed at +this ungodly hour?" + The man said, "Come into the embalming room." + They go into the embalming room, and the first partner says, "Now +watch." + He pulls out the cork, and the anus takes off singing again. The +partner looks at him disgustedly and says: "You brought me down here at +3 in the morning to hear some asshole sing Hello Dolly"? +%% +Two nuns, a mother superior and a new nun, are walking home one night from +church when they are attacked by two vicious rapists. The two men drag the +nuns off into the bushes and proceed to have their way with them. The mother +superior is very afraid, but she knows that God will protect her. To show her +strength and trust in God she yells out "Forgive him Father, for he knows not +what he does!" + To which the young nun replies "Oooooh, mine does!!" +%% +Two recent emigrants to the United States, on their first day off the boat +in New York City, spied a hotdog vendor. "Do they eat dogs in America?" +one asked his companion. + "I don't know." + "Well, if we're going to live in America, we have to learn to eat +American foods." + So they each bought a wax paper wrapped hotdog and sat down to eat +them on a nearby park bench. One man looked inside his wax paper, then over +at the other man, and asked, "So, what part did you get?" +%% +Two young men seated in a restaurant were watching a customer busily +disposing of a plate of oysters on the half shell. One of the young +men remarked to his friend, + "Did you ever hear that business about raw oysters being +good for a man's virility?" + "Yes, why?" the friend replied. + "Well, take it from me, that's a lot of foolishness. I ate a +dozen of them the other night, and only nine worked." +%% +Unitarian, n: + A bunch of athiests who really like going to church. +%% +Unix programmers do it with pipes. +%% +Vagina, n: + The box a penis comes in. +%% +Vd, n: + The gift that keeps on giving. +%% +Virgin, n: + An ugly third grader. +%% +VIRGO (Aug 23 - Sept 22) + You are the logical type and hate disorder. This nitpicking is +sickening to your friends. You are cold and unemotional and sometimes +fall asleep while making love. Virgos make good bus drivers. +%% +Vidi, vici, veni. +(I saw, I conquered, I came.) +%% +Virginity is a bubble on the sea of life, +which takes but one prick to break. + -- Jordan Sand +%% +Visiting a lawyer for advice, the wife said, "I want you to help me obtain a +divorce. My husband is getting a little queer to sleep with." + What do you mean?" asked the attorney. "Does he force you to indulge +in unusual sex practices?" + "No, he doesn't," replied the woman, "and neither does the little +queer." +%% +Wasp, n: + Someone who gets out of the shower to take a piss. +%% +Wet dream, n: + Overnight sensation. +%% +SDW/M, 35, offers French lessons for ladies. +If you desire fluency in the French tongue, +this cunning linguist can lick your problem. + +Fortune -- P.O. Box 478 +%% +Watch out for cold wave this week. (Or maybe a warm WAC.) +%% +We call our dog Egypt, because in every room he leaves a pyramid. +%% +We don't have to protect the environment -- the Second Coming is at hand. + -- James Watt, noted ecologist +%% +We drove to the hotel and said goodbye. How hypocritical to go upstairs +with a man you don't want to fuck, leave the one you do sitting there alone, +and then, in a state of great excitement, fuck the one you don't want to +fuck while pretending he's the one you do. That's called fidelity. That's +called civilization and its discontents. + -- Erica Jong, "Fear of Flying" +%% +We took some pictures of the girls, but they weren't developed. +%% + We were somewhere around Barstow on the edge of the desert when the +drugs began to take hold. I remember saying something like "I feel a bit +lightheaded; maybe you should drive...." And suddenly there was a terrible +roar all around us and the sky was full of what looked like huge bats, all +swooping and screeching and diving around the car, which was going about a +hundred miles an hour with the top down to Las Vegas. And a voice was +screaming: "Holy Jesus! What are these goddamn animals?" + Then it was quiet again. My attorney had taken his shirt off and +was pouring beer on his chest, to facilitate the tanning process. "What the +hell are you yelling about?" he muttered, staring up at the sun with his +eyes closed and covered with wraparound Spanish sungalsses. "Never mind," +I said. "It's your turn to drive." I hit the brakes and aimed the Great +Red Shark toward the shoulder of the highway. No point in mentioning those +bats, I thought. The poor bastard will see them soon enough. + -- Dr. Hunter S. Thompson, "Fear and Loathing in Las Vegas: + A Savage Journey to the Heart of the American Dream" +%% +Well, I don't know where they come from but they sure do come, +I hope they comin' for me! +And I don't know how they do it but they sure do it good, +I hope they doin' it for free! +They give me cat scratch fever... cat scratch fever! +First time that I got it I was just ten years old, +Got it from the kitty next door... +I went to see the doctor and he gave me the cure, +I think I got it some more! +Got a bad scratch fever... + -- T. Nugent, "Cat Scratch Fever" +%% +Well, I went to a party, and what did they do? +They took off their socks and they took off their shoes. +They took off their shirts, and they took off their pants, +I had a hunch, we weren't gonna dance. + +Everybody, everbody's ass was bare, +No bras left, just a queer over there. +But the whole damn thing didn't faze me a bit; +I just jumped on the pile and grabbed some tit. + +My baby's not a sports fan, +But she plays with balls whenever she can. +'Cause her favorite sport you see, +Is playing tonsil hockey. +[chorus] + Eat, bite, fuck, suck, gobble, nibble, chew; + Nipple, bosom, hair pie, finger fuck, screw. + Moose piss, cat pud, orangutan tit; + Sheep pussy, camel crack, pig-lie-in-shit. + -- Doctor Dirty, "The Eat-Bite Song" +%% +Well, he went down to dinner in his Sunday best, +Excitable boy, they all said! +And he rubbed the pot roast all over his chest, +Excitable boy, they all said! +Well, he's just an excitable boy. +He took Sally Tompkins to the junior prom, +Excitable boy, they all said! +Then he raped her and killed her, then he took her home, +Excitable boy, they all said! +Well, he's just an excitable boy. +After ten long years, they let him out of the home +Excitable boy, they all said! +And he dug up her grave, made a cage of her bones, +Excitable boy, they all said! +Well, he's just an excitable boy. + -- Warren Zevon, "Excitable Boy" +%% +Well, see, I was out with this chick last night, and we were in bed, and +she groaned to me, "Give me nine inches, and make it hurt!" So, I fucked +her twice and slapped her. +%% +Well, see, Joyce, there we were, trapped in the elevator. Now, I had +my tennis racquet and the goldfish; she was holding the Crisco. Surely +you can imagine how one thing naturally led to another! +%% +We've all heard about the woman who married a Field Service engineer but +divorced him after one day because he'd done nothing on their wedding night +but promise to have it up in 15 minutes. What few people know is that the +poor man was in the bathroom all night, masturbating furiously, saying +"I don't understand, it passes all the diagnostics!" +%% +We've just recieved the results of a survey conducted to ascertain the +various reasons men get out of bed in the middle of the night. According +to the report, 2% are motivated by a desire to visit the bathroom, and +3% have an urge to raid the refrigerator. The other 95% get up to go home. +%% +What creatures of habit we are. This morning, without thinking, half asleep, +I put $100 on my pillow. That's not so bad, no one would worry about it, but +my wife, half asleep, without thinking, gave me $20 change. +%% +What the fuck, over? +%% +What this department needs is a really good inflatible doll. +%% +What's on the floor of the old hen-house? +Doo-doo, doo-doo. + -- Foghorn Leghorn +%% +When Snow White turns on with the dwarfs +she probably winds up feeling Dopey. +%% +When a man grows old and his balls grow cold, +And the end of his knob turns blue; +When it's bent in the middle like a broken fiddle, +He can tell a tale or two. + +So find me a seat and stand me a drink +And a tale to you I'll tell +Of Dead-eye Dick and Mexico Pete When Dead-eye Dick and Mexico Pete +And the gentle Eskimo Nell. Go out in search of fun, + It's usually Dick who wields the prick +And when Dead-eye Dick and Mexico Pete And Mexico Pete the gun. +Are sore, depressed, and mad, +'Tis the cunt that bears the brunt There was rarely a day without a lay +So the shooting ain't so bad. And usually two or three + For Dead-eye Dick, his kingly prick + Was always like a tree. + -- The Ballad of Eskimo Nell +%% +When better women are made, computer programmers will make them. +%% +When ev'rybody's tryin' to sleep, +I'm somewhere makin' my midnight creep. Chorus: +In the mornin' the rooster crow, I am a back door man, +Somethin' tells me I got to go. I am a back door man, + Well, the men don't know, +They take me to the doctor, But the little girls understand. + shot full of holes, +Nurse try to save a soul. +Killed her for murder first degree, +Judge what tried let the man go free. + +Stand up, cop's wife cried, don't take him down, +Rather be dead six feet in the ground. +When you come home, you can eat pork and beans, +I eats more chicken than any man's seen. + -- Willie Dixon, "Backdoor Man", 1961 +%% +When his company fell on hard times, the boss realized that he'd have to +lay off one of his two middle managers. As both Jack and Liz were equally +honest and dedicated to their jobs, he was unable to decide which one to +fire. To resolve his dilemma, the boss arbitrarily decided that the first +to leave his or her desk the next morning would be the one to get the ax. + The next morning found Liz at her desk, rubbing her temples. Asking +Jack for some aspirin, she headed for the water fountain and that's where +the boss caught up with her. "I've got some bad news for you, Liz," he said. +"I've got to lay you or Jack off." + "Jack off," she snapped. "I have a headache." +%% +When it all boils down to the essence of truth one must live by +a dog's rule of life: If you can't eat it or fuck it, piss on it! +%% +When she hauled ass, it took three trips. +%% +When the candles are out all women are fair. + -- Plutarch +%% +When the prick stands up, the brains get buried in the ground. + -- Old Jewish saying + +[How come there aren't ever any "New Jewish sayings?" Ed.] +%% +When you and I are far apart +Can sorrow break your tender heart? +I love you darling, yes I do; +Sleep is so sweet when I dream of you; +All you are is a blossoming rose. +Night is here so I must close. +With care read the first word of each line. +You will find a question of mine. + -- Yours hopefully, The VAX. +%% +Which of the following doesn't belong? + a. meat + b. eggs + c. drum + d. blowjob. + +Answer: + d: A blowjob, because you can beat your meat, your eggs, + or your drum, but you just can't beat a blowjob. +%% +While away at a convention, an executive happened to meet a young woman who +was pretty, chic, and intelligent. When he persuaded her to disrobe in his +hotel room, he found out she had a superb body as well. Unfortunately, the +executive sadly found himself unable to perform. + On his first night home, the executive padded naked from the shower +into the bedroom to find his wife swathed in a rumpled bathrobe, her hair +curled, her face creamed, munching candy loudly as she pored through a movie +magazine. And then, without warning, he felt the onset of a magnificent +erection. + Looking down at his throbbing member, he snarled, "Why you ungrateful, +mixed-up son of a bitch! Now I know why they call you a prick!" +%% +While farmers generally allow one rooster for ten hens, +ten men are scarcely sufficient to service one woman. + -- Boccaccio +%% +While not actually a sailor, I certainly enjoy getting blown ashore. +%% +While sitting 'neath an oak one morn +In thought on this and that, +A tiny, twitt'ring little bird "Oh tiny bird, O Nature's gift +A load dropped in my hat. Of music and of wit! + Why didst thou feel that my best hat +"Thy music gladdens my poor soul, Was thy best place to shit?" +And brings joy to my heart. +But tell me, little bird divine, The tiny bird a few notes sang, +Why didst thou not just fart?" Then answer'd "Pardon me, + For thy hat I thought was my nest, +I rose and stood in solemn awe A-fallen from the tree." +His words to better mull, +Then lifted up a paving block +And crushed his fucking skull. + -- Bill Wordsworth, "A Tiny Twitt'ring Bird" +%% +While vacationing last summer in the North Woods, a young fellow thought it +might be a good idea to write his girl. He had brought no stationery with +him, however; so he had to walk into town for some. Entering the one and +only general store, he discovered that the clerk was a young, full-blown farm +girl with languorous eyes. + "Do you keep stationery?" he asked. + "Well," she giggled, "I do until the last few seconds, and then I +just go wild." +%% + While visiting our country, a lovely French maiden found herself +out of money just as her visa expired. Unable to pay her passage back to +France, she was in despair until an enterprising sailor made her a sporting +proposition. "My ship is sailing tonight," he said. "I'll smuggle you +aboard, hide you down in the hold and provide you with a mattress, blankets +and food. All it will cost you is a little love." + The girl consented, and late that night the sailor sneaked her on +board his vessel. Twice each day thereafter, the sailor smuggled a large +tray of food below decks, took his pleasure with the little French stowaway +and departed. The days turned into weeks, and the weeks might have turned +into months if the captain hadn't noticed the sailor carrying food below one +evening and followed him. After witnessing this unique bit of barter, he +waited until the sailor had departed and then confronted the girl, demanding +an explanation. She told him the whole story. + "Hmmm," mused the captian. "A clever arrangement, and I must say I +admire that young seaman's ingenuity. However, miss, I feel it is only fair +to tell you that this is the Staten Island Ferry." +%% + "Why did you spend so much time parked in that fellow's car last +night?" demanded the irate mother. +"I could hear the giggling and squealing for a good half hour." + "But, Mom," answered her daughter, "if a fellow takes you to the +movies you ought to at least kiss him good night." + "I thought you went to the Stork Club?" countered the mother. + "We did." +%% +Q: Why do women love Pacman? +A: Only place you can get eaten three times for a quarter. +%% +Why does Dr. Pepper come in a bottle? + +Because his wife left him. But things are looking up for their +reconciliation. Seems that when she left, she took his word +processor, and she's been renting it out occasionally in Japan. +That is, every now and then she gets a yen for his Wang. +%% +Why, Good Morning! I'm the bluebird of fellatio! +%% +Why is Mrs. Carter always on top when she and Jimmy make love? +Because all Jimmy Carter can do is fuck up. +%% +Why is it that there are so many more horses' asses than there are horses? + -- G. Gordon Liddy +%% +Why marry a virgin? If she wasn't good enough for +the rest of them then she isn't good enough for you. +%% +Willie in the cauldron fell; Willie saw some dynamite, +See the grief on mother's brow; Couldn't understand it quite; +Mother loved her darling well -- Curiosity never pays: +Willie's quite hard-boiled by now. It rained Willie seven days. + +Little Willie with a shout, William in a nice new sash, +Gouged the baby's eyeballs out; Fell in the fire and burned to an ash. +Stamped on them to make them pop. Now, although the room grows chilly, +Mother cried, "Now, William, stop!" I haven't the heart to poke poor Billy. + +William with a thirst for gore, +Nailed the baby to the door. +Mother said, with humor quaint: +"Careful, Will, don't mar the paint." + -- Harry Graham, "Ruthless Rhymes for Heartless Homes", 1899 +%% + With deep concern, if not alarm, Dick noted that his friend +Conrad was drunker than he'd ever seen him before. "What's the trouble, +buddy?", he asked, sliding onto the stool next to his friend. + "It's a woman, Dick," Conrad replied. + "I guessed that much. Tell me about it." + "I can't," Conrad said. But after a few more drinks his tongue +and resolution both seemed to weaken and, turning to his buddy, he said, +"Okay. It's your wife." + "My wife!!" + "Yeah." + "What about her?" + Conrad pondered the question heavily, and draped his arm around +his pal. "Well, buddy-boy," he said, "I'm afraid she's cheating on us." +%% +Women should be obscene and not heard. +%% +Women want their men to be cops. They want you to punish them and tell +them what the limits are. The only thing that women hate worse from a man +than being slapped is when you get on your knees and say you're sorry. + -- Mort Sahl +%% +Working hard around here is like pissing on yourself in +a dark suit; you get a warm feeling but nobody notices. +%% +Working here is like a pregnancy. +After nine months you wish you hadn't come. +%% +Would you rather have a 5-inch hard or an 8-inch floppy? +%% +Writers do it between periods. +%% +You are a tower of strength in the office, but only so-so in bed. +%% +You are without a doubt a rogue, a rascal, a villain, a thief, a scoundrel, +and a mean, dirty, stinking, sniveling, sneaking, pimping, pocketpicking, +thrice double-damned, no-good son-of-a-bitch. +%% +You better believe that marijuana can cause castration. +Just suppose your girlfriend gets the munchies! +%% +You can find sympathy, in the dictionary, right near shit and suicide. +%% +You can get used to living at a nudist camp. +The first three days are the hardest. + -- R. Dreiser +%% +You can pick your friends, and you can pick your nose; +but you can't pick your friend's nose. +%% +You come out of a woman and you spend the rest +of your life trying to get back inside. + -- Heathcote Williams +%% +You have been bitchy since Tuesday and you'll probably get fired today. +%% +You might get caught holding the bag. Say she's your sister. +%% +You pedophiliac sodomizer of ducklings!! +%% +You play ball with us, and we'll stick the fucking bat up your ass. +%% +You see that fucking fish? +If he'd kept his mouth shut, he wouldn'ta got caught. + -- Sam Giancana +%% + You see, this girl wakes up one morning, rolls over and sees an +elephant in the bed with her. Almost in shock, she says, "Did I pick you +up in the bar last night?" + "Uh-huh.", the elephant replies. + "Did I bring you home?" + "Uh-huh." + "Did we, uh, fool around?" + "Uh-huh." + "Lord, I must have been tight!" + "Not any more." +%% +You should be a hemorrhoid, you're such a pain in the ass. +%% +You wanna play the dozens, +Well, the dozens is a game, +But the way I fuck your mother is an ass-wringing shame! + -- George Carlin +%% +You'll be a guest at a gay party. +That will have important consequences for you. +%% +Young men want to be faithful and are not; +old men want to be faithless and cannot. + -- Oscar Wilde +%% +She's the kind of woman you could fall madly in bed with. +%% +Your spooning days are over, + And your pilot light is out; +When what used to be your sex appeal + Is now your water spout! +%% +Q: Why are babies born with soft spots on their heads? +A: So you can pick 'em up five at a time. +%% +If they can't take a joke, then fuck 'em. +If they can, then fuck 'em. +%% +Beat me, bite me, whip me, fuck me, make me write bad checks! +%% +Fuck you and anybody who looks like you. +%% +Kansas, where the men are men, the sheep +are scared and the women are grateful. +%% +Horny, adj: + When your cock gets hard if the wind blows. +%% + "Yes, sir, the bowling ball nipple rings in black. +Will there be anything else?" +%% +Teaching undergraduates is like herding sheep. And, like the old Basque +sheepherder explained, whenever the livestock starts looking good to you, +it's time to spend a night in town. +%% +San Francisco is my kind of city, +Where the women are strong and the men are pretty. +%% +Daisy, Daisy, give me your answer true, +Daisy, Daisy, wouldn't you like to screw? +I really must beg your pardon, +But I've got a hell of a hard-on, +From beating my meat, against the seat, +Of a bicycle built for two. + -- "Daisy, Daisy", "The Dirty Song Book" +%% +Love comes in spurts. + --Devo, "Please Please" +%% + Elroy stared at Barb and then leaned quietly over to Shake Tiller +and stuck out his hand. "Son," he said. "Tell the truth. It ain't better +than fried chicken, is it?" + Shake looked solemnly at Elroy, clasping his hand, and said: + "I got to be dead honest, Roy." + And Elroy said yeah, lay it on him. + Shake said slowly, "For a Lesbian who gave up the only real love she +ever knew -- Sister Francis at Our Lady of Victory -- and for a person who +can't make it any more with nothing but an electric toothbrush, she's the +finest I've ever had." + -- Dan Jenkins, "Semi-Tough" +%% +My jaw aches, my pussy is sore. +I simply can't fuck any more; + I'm covered with sweat, + And you haven't come yet, +And my God, it's a quarter to four! + -- The Gray-haired Woman's Complaint +%% +Q: What's the difference between a JAP and a baby elephant? +A: About 10 pounds. + +Q: How do you make them the same? +A: Force feed the elephant. +%% +You might as well say "yes", the sheets are messy already. +%% +Life isn't a bitch. Life is a virgin. A bitch is easy. +%% +FORTUNE TESTS THE GREAT MANAGERS: #3 + +You have prepared a proposal for your supervisor. The success of this +proposal will mean increasing your salary 20%. In the middle of your +proposal your supervisor leans over to look at your report and spits into +your coffee. You: + + (a) Tell him you take your coffee black. + (b) Ask him if he has any communicable diseases. + (c) Show him who's in command; promptly take a piss in his + "In" basket. + (d) Take a sip and comment how much better it tastes. +%% +Necrophelia, n: + Dead boring. + +Incest, n: + Relatively boring. +%% +Little Miss Muffet, sat on a tuffet, +Eating her curds and whey. +Along came a spider who sat down beside her, +And said, "What's in the bowl, bitch?" +%% +Mary had a little lamb, +It's fleece as white as snow. +It followed her to school one day, +And got fucked by a big black dog. +%% +When you're lying on the bed, +And the thought is in your head, +But the feeling is way down between your legs, +Take your problem in your hand, +And beat it to the band, +And try your best to keep it off the walls. + +Don't let your lover tell you, +Don't let anybody sell you, +That the joy of masturbation is a crime. +For I've rid myself of fears, +(I've been doing it for years) +And now I have an erection all the time. +%% +As the Catholic church becomes more and more tolerant, some day they will +have to consider the possibility of a gay pope. Possibly the largest +issue will be having to decide whether he is "absolutely divine" or "just +simply marvelous." +%% +I don't want to say that she had big tits, but one day I asked her + just how big they was, and she said, "7 and 7/8". +I said, "7 and 7/8?! What did you measure 'em with?" +And she replied, "A Stetson." +%% + It seems there were two young Marines walking down the street, and +they chanced upon a lady who was both very proper and very well endowed. +One of them said, "Wow! What tits! Hey lady, would I love to snuggle up with +them for awhile. What are you doing this afternoon?" + Well, the other Marine thought that was just about the most shameful +thing he had ever witnessed, and felt that he had to restore the honor of the +Corp. "Pardon my friend, Ma'am," he said, "He's not been very well brought +up and don't know how to talk to cunt." +%% + A bear and a rabbit are taking a crap in the woods. The bear looks +over at the rabbit and asks, "Say, does shit ever stick to your fur?" + "No." + So the bear wiped his ass with the rabbit. +%% +Once upon a time there was a farmer who had borrowed a bull to service his +two cows. He put all three animals on a meadow and sent little Johnny to +observe and report any success. A short time later, little Johnny came +running towards the house shouting: "Daddy, Daddy, the bull just fucked the +white cow!" + The father took little Johnny aside and said: "Look, kid, it's +alright if you use that kind of language around me, but the reverend is +going to be visiting soon. So next time, please use another word; just +say that the bull "surprised" the cow." + Johnny agreed and went back to observe any progress. A little +while later, while the preacher was talking to the farmer, little Johnny +came a-running again, shouting: "Daddy, Daddy!" + The father, trying to avoid embarrassing the preacher, said: "I +know, the bull surprised the brown cow." + Little Johnny replied: "He sure did, he fucked the white one again!" +%% +When things go wrong as they usually will, +And your daily road seems all uphill, +When funds are low and debts are high, +When you try to smile, but can only cry -- +And you really feel you'd like to quit, +Don't talk to me; I don't give a shit. +%% + Santa Claus comes down the chimney and the nubile sixteen-year-old +has been waiting for him. Santa sees her, and in typically unflappable +Santa-style says, "And what do you want for Christmas, little girl?" + The girl, and she's not so little, tells him. Well, Santa is +definitely flapped by this, but he manages to come out with, "Ho ho ho, +gotta go, gotta get the children their toys, you know." + The girl, not to be daunted, takes off her robe. "Aw, please stay +Santa," she begs. + He replies, "Ho ho ho, gotta go, gotta get the children their toys, +you know." + She then takes off her pajama top, her firm pouting breasts pointing +at Santa like an accusation. "Aw, please stay Santa," she pleads. + "Ho ho ho, gotta go, gotta get the children their toys, you know." + Finally, she takes off her pajama bottoms, revealing to Santa her +warm mound of delight. "Aw, please stay Santa," she begs. + Being only mortal, Santa finally gives in, sighing, "Hey hey hey, +gotta stay, can't get up the chimney with my dick this way." +%% +The three sexual positions during preganancy. + +During the first four months: Missionary style +During the second four months: Doggie style +And during the last month: Coyote style + +Coyote style? + You sit by the hole and howl. +%% + A man walks into a bar and orders 3 shots and 3 beers. The +bartender, seeing that the man is distraught, asks what the problem is. + "I just found out that my brother is gay", he replies. + About a week later, the same man walks in and orders 6 shots and +6 beers. So the bartender inquires, "What's wrong this time?" + To which the man says, "I just found out that two of my brothers +are lovers." + Another week goes by and the man comes back to the bar and orders +NINE shots and NINE beers. The bartenders says "Damn, boy, doesn't anyone in +your family like pussy?" + "Yeah. Me and my sister." +%% +Here I sit, my cheeks a flexin', +Just gave birth to another Texan. +%% + A college jock was dating a jockette; both were simple, direct, and +physical types, and not much talking was done on the dates. Not much action +either, and one night the jock decided the time had come. When they got back +to his place, he jumped her and they had a terrific tussle, wrestling back and +forth, and the jock had a great deal of difficulty in getting his penis +inserted. He pushed and shoved, and for a while all that happened was that +the girl's legs waved and thrashed about in the air. Finally he got it in and +they finished. Afterward he said, "Gee, if I'd known you were a virgin, +I'd have taken it a little easier." + The girl replied, "That's OK -- if I'd known we were going to fuck +I wouldn't have worn pantyhose." +%% +Life is like a penis: when it's soft you +can't beat it, and when it's hard you get fucked. +%% +Life is like a shit sandwich. The more bread +you have, the less shit you have to eat. +%% +He: So, what do you say to little fuck? +She: I say, "get lost, little fuck." +%% +There is a new model of car being sold in San Francisco -- +the pervertible. The top doesn't go down, but the driver does. +%% + A ten-year-old kid came home from school one day, and when his mom +asked how was school he says: "Gee, great, mom. I got laid!" + She's shocked and sends him upstairs, where his dad finds him after +work. "Mommy told me about your day at school, Billy, and I think we men +should keep it a secret. Women just don't understand these things." + So every night Dad goes up to Billy's room after Mom tucks him in: +"You get laid today, Billy?" + "Yeah, Dad." + "How was it?" + "Real neat, Dad, I liked it a lot." + "Good Boy!". + A month later: "You get laid today?" + "No, Dad." + "No? How come?" + "Gee, Dad, my ass was really sore." +%% +Hear about... + the new rule at the girls' school? + Lights out by ten, candles by eleven. +%% +Hear about... + the girl who called her boyfriend + Courvoisier, 'cause he was such a sweet liquor? +%% +Hear about... + the drunken midget who walked into a home for + girls and kissed everybody in the joint? +%% +Hear about... + the over-eager bride who came, walking down the aisle? +%% +Hear about... + the real smart girl who could play post-office all night + without getting any mail in her box? +%% +Hear about... + the new vitamin made from chicken blood, + it makes men cocky and women lay better? +%% +She was a farmer's daughter but she couldn't keep her calves together. +%% +Hear about... + the french soldier who kisses both his wife's cheeks before + he went to the front? +%% +Hear about... + the fellow who got ten years for pumping Ethyl behind the station? +%% +Hear about... + The fellow who chased his girlfriend up a tree and kissed + her between the limbs? +%% +Hear about... + the perverted australian who left his wife and returned to Sydney? +%% +Hear about... + the new breakfast cereal called "Swingers". They don't go snap, + crackle, or pop; they just lie there and go bang, bang, bang? +%% +Hear about... + the new instrument of credit especially designed for use in + single bars? It's called Bang Americard. +%% +Hear about... + the couple on the stalled elevator who got off between floors? +%% +Hear about... + the nymphomaniac teenager popularly known as Little Often Annie? +%% +Hear about... + the ultimate in singles bars? It's a place where girls have + to show their I.U.D.'s to be admitted. +%% +Hear about... + the young thing who is fondly known to the men in the office as + Secretariat -- not just because she's a good secretary but because + she's a wonderful mount? +%% +Hear about... + the mother of 12 who was called upon to use her diaphragm so often + that she kept it tacked to the headboard of her bed? +%% +Hear about... + the handsome bachelor Senator who hired a ravishing blonde as his + assistant and then made her the object of a long Congressional probe? +%% +Hear about... + the guy who took a course in exotic lovemaking and announced that + he'd never be able to face his girl again? +%% +Hear about... + the careless contortionist who accidentally swallowed his pride? +%% +Hear about... + the inexperienced stenographer who discovered that she could lose + a lot more than letters behind the files? +%% +Hear about... + the ambitious secretary who walked into her boss's office and + demanded a salary on next week's advance? +%% +Hear about... + the woman who claimed that two martinis usually made her + feel like a new man? +%% +Hear about... + the doctor that prescribed sex for insommia? His patients didn't + get any more sleep, but they had more fun staying awake. +%% +Hear about... + the cinema buff that's very excited by current trends in films? + The hero still gets the girl in the end, but he's never sure + which end it will be. +%% +Hear about... + the basketball player who was so tall that his girlfriend had to + go up on him? +%% +Hear about... + the new breakfast cereal called Queerios? You simply add milk + and they eat each other. +%% +Hear about... + the guy who couldn't find his way to the orgy? Just + kind of lost his ball bearings. +%% +Hear about... + the guy who was an incurable romantic until penicillin came along? +%% +Hear about... + the hurricane that recently struck Fire Island -- Hurricane Bruce? +%% +Bookstores will soon be stocking a volume called "The Unsensuous +Census Taker". It's about a guy who comes once every ten years. +%% +Hear about... + the fellow who maintains a special register of particularly + accommodating girls? He refers to it as his little blew book. +%% +We understand that the vote on a bill to +legalize bisexuality could go either way. +%% +Hear about... + one penile desensitizer that's so effective that you + have to stroke the tube for five minutes to get the cap off? +%% +Hear about... + the loner who gave up his solitary vice for + Lent? Except on Palm Sunday, of course. +%% +Hear about... + the high school drum major who dated two of the + majorettes and so enjoyed the breasts of both whirlers? +%% +Five-foot nine, eyes that shine +He was born in Palestine +Has anybody seen my Lord? + +He's so cool, he's so fine +Eat his bread and drink his wine +Has anybody seen my Lord? + +He's so neat, he's so cool, +Walks across my swimming pool. +Has anybody... +%% +Q: How can you tell when a Polish girl's been sucking cock? +A: She has a mouthful of feathers. +%% +He's learned about 50% of the rules of sex and conversation; +he knows how to stick it in, but not how to stick it out. +%% +The two things that you should never lend out are your car +or your woman. Someone's bound to throw a rod in either one. +%% +SUBPOENA: + From the root "sub", below, and the Latin "poena" for male organ + or penis. Therefore, "below the penis" or "by the balls." +%% +Couples in motion have moments. +%% + "Jean, what is this attraction between Catholic girls and +Jewish men?" + "You really want to know?" + "Yeah." + "Well, Carol, Jewish men are great in bed... right, Bob? And +Catholic girls fuck like bunnies." +%% +How soon can you have sexual relations after your wife delivers? +Well, depends on if she's in a ward or a private room. +%% +I don't know why women get so upset, +they have half the money and all the pussy. + -- Gary Bussy, "DC Cab" +%% +You will always have friends +Some friends will peter out. +But I'll always be your friend, +Peter in or peter out. +%% +Here's to the girl in little red shoes, +She drinks my liquor, she drinks my booze, +She has no cherry, but that's no sin, +She has the box the cherry came in. +%% +Here's to the girl that's dressed in black, +She's dressed so neat there's nothing to lack +She feels so fine and kisses so sweet +She makes things stand that have no feet. +%% +If thine eye offends thee, pluck it out. +If thy dick offends thee, whack it off. +%% +A hand in a bird is worth two on 'er bush. +%% +They watched the sun slowly sink behind the hills, and the fiery glow on the +lake fade into darkness. He eyed her shadowy figure, accentuated by the moon- +light, as the tension from within began to fuel his animalistic desires. +She followed him, ever so quietly, as they sought a secluded corner in the +barn. Alone! At last. His hands roamed about her soft back, around to her +thighs, and finally caressed her budding nipples. Oh, how smooth and succulent +she was! "Was it so wrong?", he asked himself. No, he thought, for his +father had done it, as did his own father, ad infinitum. The boiling, +uncontrollable rage within him became unbearable. She signalled her eagerness, +spreading her legs, as he grasped her nipples again. Stroking, again and +again, longer each time. It began coming; again, again, again, again. His +mind raced with fear "Will it stop?". Exhausted, he lay down beside her. +"Dear God, what have I done?". Suddenly, his father burst in. His eyes +burned as he stared for what seemed an eternity. Finally, his father spoke. + "Son, you ain't supposed to milk the damn cow till mornin'!" +%% +You know what burns my ass? A flame about three feet high. +%% + A strange looking white man came to the Indian reservation looking +for a job. He asked to talk to the Chief of the tribe, so he might give his +qualifications. The Chief strode forward from the group surrounding the +white man and said: "You leave! No job!" + The man explained that this was no ordinary job he was seeking, but +that of tribe Medicine-Man. He would convince him if the Chief would allow +him to demonstrate his magic. "No magic!" said the disbelieving Chief. + "Oh, yeah?", said the stranger. "I'll prove it to you by making +your dog, here, talk!" + "Dog, no talk!" responded the Chief, but before he could finish, he +heard a voice coming out of the mouth of the dog saying, "The Chief treats me +good. He feeds me, and keeps me in teepee when it snows!" + "If you still have doubts as to my magic," continued the stranger, +"the next voice you'll hear will be that of your horse!" + "Horse, no talk!" argued the still-sceptical Chief, but again he +heard a voice that said: "I am the Chief's favorite horse. He takes me up to +the green pasture to eat and brushes my coat when I get dirty." + The stranger, still seeing some disbelieving faces, claimed for his +final trick he would make the Chief's sheep talk. + "NO!" cried the Chief, "SHEEP LIE!" +%% +Sure eating yoghurt will improve your sex life. People +know that if you'll eat that stuff, you'll eat anything. +%% +There's a tendency today to absolve individuals from moral responsibility and +treat them as victims of social circumstance. You buy that, you pay with your +soul. It's not men who limit women, it's not straights who limit gays, it's +not whites who limit blacks. What limits people is lack of character. What +limits people is that they don't have the fucking nerve or imagination to star +in their own movie, let alone direct it. + -- Bernard Mickey Wrangle +%% +Q: Why are Unix emulators like your right hand? +A: They're just pussy substitutes! +%% + Out on the great American desert one day, a bald eagle reached a +state of great libidal distress. Pickings were slim, but in time, he saw a +dove flying by. "Better than nothin'", he muttered (birds in jokes can mutter) +and swooped down, grabbed the dove and flew to his nest. Feathers flew, and +eventually the dove tottered to the edge of the cliff and shouted (yes, they +shout, too): + "I'm a dove! I've been loved! And I LIKE it!" + Well, this took care of the old boy for a while but soon enough he +was at it again. All he could find was a lark, so away he went, and feathers +flew and soon the lark tottered to the edge of the cliff and shouted: + "I'm a lark! I've been sparked! And I LIKE it!" + As you can guess, some time later our friend was again in need of +amor... lib... you know! This time, all that happened by was... a duck! +So down he swooped, and feathers flew, and the next thing seen is the duck +tottering to the cliffside and shouting: + "I'M A DRAKE! THERE'S BEEN A MISTAKE! AND I DON'T LIKE IT!!! +%% +One day, in a bar, a young man walks in with a little dwarf about one foot +tall on his shoulder and orders a beer. The bartender serves the man a beer; +to his astonishment, the little guy walks down the man's arm, takes a swallow +of the brew and spits it in his face. After a few minutes the customer +orders another beer and the exact same thing happens. Well, by this time, +the bartender is getting pretty upset; he figures that the man should take +care of the dwarf. So he asks the guy, "Why are you letting that guy drink +all your beer and spit it in my face?" + "Well, sir, when I was on a contract in Saudi Arabia I met this genie +and he granted me three wishes. I asked for a million dollars, the most +beautiful woman in the world, and a twelve-inch prick. +%% +A real estate agent, looking over a farmer's house for possible sale, +commented to the farmer how sturdy the house looked. + The farmer replied, "Yep, built it with my bare hands... did it +the hard way. The steps to the front door, here, carved 'em out of +field stones... did it the hard way. That hardwood floor in the living +room, dovetailed the pieces myself... did it the hard way. The ceiling +beams, made 'em out of my own oak trees... did it the hard way." + Just then, the farmer's gorgeous daughter walked in. The farmer +looks over at the real estate agent who is trying not to stare too +obviously and smiles. "Yep... standing up in a canoe." +%% +One day Adam, while wandering around the Garden of Eden, noticed that all +the animals seemed to come in pairs, male and female. He also noted that +they seemed to enjoy being together a lot. So, he went to his special +place an reported to God what he'd noticed. + God, understanding his need, said, "Adam, the time has come for me +to provide you with a mate. Go lie down and when you have fallen asleep, I +will create your mate." + So Adam wandered off, found a nice patch of soft grass and fell +asleep. Some time later he awoke, possibly due to a bit of pain in his +ribs, possibly because of the gorgeous woman leaning over him. Remembering +the animals he'd seen having such fun, he immediately reached for her. +Pretty soon Adam's back at his special place. + "God?" + "Yes, Adam, what now?" + "God, what's a headache?" +%% +Jesus died for your sins... make it worth his time. +%% +That reminds me of a friend of mine who went north to work on the Alaskan +pipeline. Before he went up there, he was just a skinny little runt. When +he got back, he was a husky fucker. +%% +The young stud walked into a bordello. After he took his clothes off, the +woman was puzzled to see him put a clothespin on his nose, stuff cotton in +his ears, and put a prophylactic on his penis. + "Hey," she asked, "what the hell are you doing?" + "Well, ma'am", replied the stud, "there are two things I just can't +stand. A screaming woman and the smell of burning rubber." +%% +I love this fucking University, and this University loves fucking me. +%% +Q: What is Smoorplay? +A: What Smurfs do before they smuck! +%% + Well, there was this tiger, who woke up one morning, and just felt +great (yes, just like Tony the Tiger: GREAAAAAAT). Anyway, he just felt +so good, he went out and cornered a small monkey and roared at him: "WHO IS +THE MIGHTIEST OF ALL THE JUNGLE ANIMALS?" + And this poor quaking little monkey replied: "You are of course, no +one is mightier than you." + A little while later this tiger confronts a deer, and just bellows out: +"WHO IS THE GREATEST AND STRONGEST OF ALL THE JUNGLE ANIMALS?" + The deer is shaking so hard it can barely speak, but manages to +stammer: "Oh great tiger, you are by far the mightiest animal in the jungle." + The tiger, being on a roll, swaggered, up to an elephant that was +quietly munching on some weeds, and roared at the top of his voice: "WHO IS +THE MIGHTIEST OF ALL THE ANIMALS IN THE JUNGLE?" + Well, this elephant grabs the tiger with his trunk, picks him up, slams +him down; picks him up again, and shakes him until the tiger is just a blur of +orange and black; and finally throws him violently into a nearby tree. + The tiger staggers to his feet, looks at the elephant and says: "Man, +you don't have to get so pissed, just because you don't know the answer!" +%% + When the surgeon came to see her on the morning after her +operation, the young woman asked him somewhat hesitantly how long +it would be before she could resume her sex life. + "I really haven't thought about it," gulped the stunned surgeon. +"You're the first patient who's asked me that after a tonsillectomy!" +%% + People who claim to know jackrabbits will tell you they are primarily +motivated by Fear, Stupidity and Craziness. But I have spent enough time in +jackrabbit country to know that most of them lead pretty dull lives; they are +bored with their daily routines: eat, fuck, sleep, hop around a bush now and +then... No wonder some of them drift over the line into cheap thrills once in +a while; there has to be a powerful adrenalin rush in crouching by the side of +a road, waiting for the next set of headlights to come along, then streaking +out of the bushes with split-second timing and making it across to the other +side just inches in front of the speeding front wheels. + Why not? Anything that gets the adrenalin moving like a 440 volt +blast in a copper bathtub is good for the reflexes and keeps the veins free +of cholesterol ... but too many adrenalin rushes in any given time-span has +the same bad effect on the nervous system as too many electro-shock treatments +are said to have on the brain: after a while you start burning out the +circuits. + When a jackrabbit gets addicted to road running, it is only a matter +of time before he gets smashed -- and when a journalist turns into a politics +junkie he will sooner or later start raving and babbling in print about things +that only a person who has Been There can possibly understand. + -- Hunter Thompson, "Fear and Loathing: On the Campaign Trail" +%% +Tip O'Neill is just like Congress; old, fat and out of control. + -- J. LeBoutillier +%% + One of my favorite Zoo jokes has to do with a woman who, while +visiting the zoo, desided to have a little fun with the Gorilla. She walks +up to his cage, reaches in, and begins to fondle the beast. Needless to +say, the animal becomes quite excited, and as he tries to reciprocate in +kind, the woman steps back and gives him a raspberry...! + The gorilla becomes enraged. He rips the bars from his cage, grabs +the woman, drags her back into the cage, and ravishes her. While doing so, +he inflicts a great deal of harm upon her person. + Later, at the hospital, a neighbor of the woman visits and exclaims, +"Oh, you poor dear...! Are you hurt?" + "Hurt!", "Hurt!?" the injured lady sobs, "He doesn't phone. He +never writes..." +%% +If guns are outlawed, how will we shoot the liberals? +%% +On one hot dusty day in 1860, a lone Mexican bandit crossed the border into +Texas. After robbing a small bank and shooting up the town, he led the posse +on a merry chase through the desert. On the sixth day of the chase he was +apprehended. + Sheriff-to-interpreter: "Ask him where the money is." + Interpreter-to-bandit: "He wants to know where you hid the money." + Bandit-to-interpreter: "I'll never tell, never!" + Interpreter-to-sheriff: "He says he'll never tell, senor." +At this point, the sheriff loses his cool. His town has been shot up, his +bank robbed, he's spent a week in the desert tracking this guy, and now he +says he'll never tell. So he takes his pistol, jams it under the bandits' +chin, and, with the veins standing out on his neck, screams "Tell him to tell +me where the money is, or I'm gonna blow his brains all over the desert!" + Interpreter-to-bandit: "He says if you don't tell him where the + money is right now, he will kill you here." + Bandit-to-interpreter: "Do not kill me, senor, the money is hidden + under the big tree at the pass!" + Interpreter-to-sheriff: "He says you ain't got the balls..." +%% +Tell you what," the haberdasher said to a persistent job applicant. "I've +got one suit I can't sell -- that purple, green and yellow number over there. +If you can make that sale, you've not only got the job, you've got it for +life." + Then the store owner left for lunch. When he returned, he was shocked +to see the young man's clothes in tatters and his hands and face bleeding. + "My God, what happened to you?" + "I sold the suit! I sold the suit!" the young man shouted, a smile +on his bloodied lips. + "Congratulations," the haberdasher said. "You've got the job. But +what happened? Did the customer start a fight?" + "Oh, no," the new salesman replied. "But his Seeing Eye dog was +*pissed*." +%% +The voters have spoken, the bastards... +%% +Hypocrisy is the vaseline of social intercourse. +%% +I'm not a pheasant plucker, +Nor a pheasant plucker's son. +I'm just a'plucking pheasants +'Til the pheasant plucker comes. +%% +Hear about... + the careless canary that did it for a lark? +%% +Hear about... + the truck driver who pulled out to + avoid a child and fell off the sofa? +%% +Hear about... + the over-anxious bride who came down the aisle? +%% +Hear about... + the absent minded nurse who made + the patient without disturbing the bed? +%% +Hear about... + the frustrated musician who worked all week on an + arrangement and then his wife didn't leave town? +%% +Hear about... + the fellow who was descended from a long line his mother heard? +%% +Hear about... + the girl that wanted to impress her new boyfriend, + so she put on her low-cut dress to show him a thing or two? +%% +A Frenchman who lived in Alsace +Had sex with a virgin named Grace. + When he popped her cherry, + She made things hairy +By bleeding all over his face. +%% +A bad little girl in Madrid, +A most reprehensible kid, + Told her Tante Louise + That her cunt smelled like cheese, +And the worst of it was that it did! +%% +A beat schizophrenic said, "Me? +I am not I, I'm a tree." + But another, more sane, + Shouted, "I'm a Great Dane!" +And covered his pants leg with pee. +%% +A beautiful belle of Del Norte +Is reckoned disdainful and haughrty + Because during the day + She says: "Boys, keep away!" +But she fucks in the gloaming like forty. +%% +A beautiful lady named Psyche +Is loved by a fellow named Ikey. + One thing about Ike + The lady can't like +Is his prick, which is dreadfully spikey. +%% +A big-bosomed Bunny named Gression +Sold cigars at a key-club concession. + When she swiveled about + Even strong men cried out, +For her costume did not keep her flesh in. +%% +A bobby of Nottingham Junction +Whose organ had long ceased to function + Deceived his good wife + For the rest of her life +With the aid of his constable's truncheon. +%% +A broken-down harlot named Tupps +Was heard to confess in her cups: + "The height of my folly + Was fucking a collie -- +But I got a nice price for the pups." +%% +A cautious young fellow named Tunney +Had a whang that was worth any money. + When eased in half-way, + The girl's sigh made him say, +"Why the sigh?" "For the rest of it, honey." +%% +A certain young person of Ghent, +Uncertain if lady or gent, + Shows his organs at large + For a small handling charge +To assist him in paying the rent. +%% +A chap down in Oklahoma +Had a cock that could sing La Paloma, + But the sweetness of pitch + Couldn't put off the hitch +Of impotence, size and aroma. +%% +A charmer from old Amarillo, +Sick of finding strange heads on her pillow, + Decided one day + That to keep men away +She would stuff up her crevice with Brillo. +%% +A chippy who worked in Black Bluff +Had a pussy as large as a muff. + It had room for both hands + And some intimate glands, +And was soft as a little duck's fluff. +%% +A clever young man named Eugene +Invented a jack-off machine. + On the twenty-third stroke + The fuckin' thing broke +And beat both his balls to a creame. +%% +A contortionist hailing from Lynch +Used to rent out his tool by the inch. + A foot cost a quid -- + He could and he did +Stretch it to three in a pinch. +%% +A couple was fishing near Clombe +When the maid began looking quite glum, + And said, "Bother the fish! + I'd rather coish!" +Which they did -- which was why they had come. +%% +A cowhand way out in Seattle +Had a dooflicker flat as a paddle. + He said, "No, I can't fuck + A lamb or a duck, +But golly! it just fits the cattle." +%% +A cute little twerp from Samoa +Had a cock of one inch and no moa. + It was good for keyholes + And debutantes' peeholes +But not worth a damn on a whoa. +%% +A daredevil skater named Lowe, +Leaps barrels arranged in the snow, + But is proudest of doing, + Some incredible screwing, +Since he's jumped thirteen girls in a row! +%% +A deep-throated virgin named Netty +Was sucking a cock on the jetty. + She said, "It tastes nice, + Much better than rice, +Though not quite as good as spaghetti." +%% +A despairing old landlord named Fyfe, +With a frigid and quarrelsome wife, + Let his third-story front, + To a willing young cunt, +Who supplied him a new lease on life! +%% +A distinguished professor from Swarthmore +Got along with a sexy young sophomore. + As quick as a glance + He stripped off his pants, +But he found that the sophomore'd got off more. +%% +A doctoral student from Buckingham +Wrote his thesis on cunts and on fucking'em. + But a dropout from paree + Taught him Gamahuchee +So he added a footnote on sucking 'em. +%% +A do-it-yourselfer named Alice, +Used a dynamite stick for a phallus. + She blew her vagina + To South Carolina, +And her tits landed somewhere in Dallas. +%% +A dulcet-voiced callgirl named Shedd, +Who's cultured, well-spoken, well-bred, + Had achieved some reknown + For her tone going down-- +There's a nice civil tongue in her head. +%% +A fair-haired young damsel named Grace +Thought it very, very foolish to place + Her hand on your cock + When it turned hard as rock, +For fear it would explode in your face. +%% +A farmer I know named O'Doole +Had a long and incredible tool. + He can use it to plow, + Or to diddle a cow, +Or just as a cue-stick at pool. +%% +A fellatrix's healthful condition +Proved the value of spunk as nutrition. + Her remarkable diet + (I suggest that you try it) +Was only her clients' emission. +%% +A fellow whose surname was Hunt +Trained his cock to perform a slick stunt: + This versatile spout + Could be turned inside out, +Like a glove, and be used as a cunt. +%% +A fisherman off of Cape Cod +Said, "I'll bugger that tuna, by God!" + But the high-minded fish + Resented his wish, +And nimbly swam off with his rod. +%% +A girl of uncertain nativity +Had an ass of extreme sensitivity + While she sat on the lap + Of a German or Jap, +She could sense Fifth Column activity. +%% +A habit obscene and bizarre, +Has taken a-hold of papa. + He brings home young camels + And other odd mammals, +And gives them a go at mama. +%% +A habit obscene and unsavory, +Holds a CS professor in slavery. + With maniacal howls, + He deflowers young owls, +That he keeps in an underground aviary. +%% +A hacker-turned-pervert named Fisk +Made love to the drive of his disk. + The thing circumsized him, + Which rather suprised him. +He wasn't aware of *that* risk. +%% +A hardware debugger named Court +Shoved his tool in an Ethernet port. + But its buffer array + Only handled 1K, +So the port's driver cut it off short. +%% +A highly aesthetic young Jew +Had eyes of a heavenly blue; + The end of his dillie + Was shaped like a lilly, +And his balls were too utterly two! +%% +A highway patrol buff named Claire, +Once screwed half a troop on a dare, + And her parts grew so hot, + There was steam on her twat, +So they nicknamed her Smokey the Bare! +%% +A horny young fellow named Reg, +Was jerking off under a hedge. + The gardener drew near + With a huge pruning shear, +And trimmed off the edge of his wedge. +%% +A huge-organed female in Dallas, +Named Alice, who yearned for a phallus, + Was virgo intacto, + Because, ipso facto, +No phallus in Dallas fit Alice. +%% +A lacklustre lady of Brougham +Weaveth all night at her loom. + Anon she doth blench + When her lord and his wench +Pull a chain in the neighbouring room. +%% +A lad, at his first copulation, +Cried, "What a sensation! Inflation, + Gyration, elation + Throughout the duration, +I guess I'll give up masturbation." +%% +A lad from far-off Transvaal +Was lustful, but tactful withal. + He'd say, just for luck, + "Mam'selle, do you fuck?" +But he'd bow till he almost would crawl. +%% +A lady from Old Little Rock +In fidelity took little stock, + And deserted her man + In the streets of Japan +For a boy with a prehensile cock. +%% +A lady removing her scanties, +Heard them crackle electrical chanties. + Said her beau, "Have no fear, + For the reason is clear: +You simply have amps in your panties. +%% +A lady stockholder quite hetera +Decided her fortune to bettera: + On the floor, quite unclad, + She successively had +Merrill Lynch, Pierce, Fenner, et cetera... +%% +A lady while dining at Crewe +Found an elephant's whang in her stew. + Said the waiter, "Don't shout, + And don't wave it about, +Or the others will all want one too." +%% +A lady with features cherubic +Was famed for her area pubic. + When they asked her its size + She replied in surprise, +"Are you speaking of square feet, or cubic?" +%% +A licentious old justice of Salem +Used to catch all the harlots and jail 'em. + But instead of a fine + He would stand them in line, +With his common-law tool to impale 'em. +%% +A lonely young lad of Eton +Used always to sleep with the heat on, + Till he ran into a lass + Who showed him her ass -- +Now they sleep with only a sheet on. +%% +A lusty young maid from Seattle +Got pleasure by sleeping with cattle; + Till she found a bull + Who filled her so full +It made both her ovaries rattle. +%% +A lusty young woodsman of Maine +For years with no woman had lain, + But he found sublimation + At a high elevation +In the crotch of a pine -- God, the pain! +%% +A maestro directing in Rome +Had a quaint way of driving it home. + Whoever he climbed + Had to keep her tail timed +To the beat of his old metronome. +%% +A maiden who lived in Virginny +Had a cunt that could bark, neigh and whinny. + The horsey set rushed her, + But success finally crushed her +For her tone soon became harsh and tinny. +%% +A maiden who wrote of big cities +Some songs full of love, fun and pities, + Sold her stuff at the shop + Of a musical wop +Who played with her soft little titties. +%% +A man was once heard to boast, +That he received a parcel by post, + It contained, so we heard, + A magnificent turd, +And the balls of his grandfather's ghost. +%% +A marine being sent to Hong Kong +Got a doctor to alter his dong. + He sailed off with a tool + Flat and thin as a rule - +When he got there he found he was wrong. +%% +A mathematician named Hall +Had a hexhedronical ball, + And the square of its weight + Times his pecker's, plus eight, +Was four-fifths of five-eighths of fuck-all. +%% +A mathematician named Hall +Has a hexahedronical ball, + And the cube of its weight + Times his pecker's, plus eight +Is his phone number -- give him a call... +%% +A middle-aged codger named Bruin +Found his love life completely in ruin, + For he flirted with flirts + Wearing pants and no skirts, +And he never got in for no screwin'. +%% +A milkmaid there was, with a stutter, +Who was lonely and wanted a futter. + She had nowhere to turn, + So she diddled a churn, +And managed to come with the butter. +%% +A mortician who practised in Fife +Made love to the corpse of his wife. + "How could I know, Judge? + She was cold, did not budge-- +Just the same as she'd acted in life." +%% +A nervous young fellow named Fred +Took a charming young widow to bed. + When he'd diddled a while + She remarked with a smile, +"You've got it all in but the head." +%% +A newlywed couple from Goshen +Spent their honeymoon sailing the ocean. + In twenty-eight days + They got laid eighty ways -- +Imagine such fucking devotion! +%% +A newly-wed man of Peru +Found himself in a terrible stew: + His wife was in bed + Much deader than dead, +And so he had no one to screw. +%% +A notorious whore named Ms. Hearst, +In the pleasures of men was well-versed. + Reads the sign o'er the head + Of her well-rumpled bed +"The customer always comes first." +%% +A nudist resort at Benares +Took a midget in all unawares. + But he made members weep + For he just couldn't keep +His nose out of private affairs. +%% +A passionate red-haired girl +When you kissed her, her senses would whirl, + And her twat would get wet, + And would wiggle and fret, +And her cunt-lips would curl and unfurl. +%% +A petulant man once said, "Pish, +Your cunt is as big as a dish." + She replied, "Why, you fool, + With your limp little tool, +It's like driving a pin with a fish." +%% +A pious old woman named Tweak +Had taught her vagina to speak. + It was frequently liable + To quote from the Bible, +But when fucking -- not even a squeak! +%% +A pious young lady named Finnegan +Would caution her friend, "Well, you're in again; + So time it aright, + Make it last through the night, +For I certainly don't want to sin again!" +%% +A pious young lady of Chichester +Made all of the saints in their niches stir + And each morning at matin + Her breast in pink satin +Made the bishop of Chichester's breeches stir. +%% +A plumber whose name was John Brink +Plumbed the cook as she bent o'er the sink. + Her resistance was stout, + And John Brink petered out, +With his pipe-wrench all limber and pink. +%% +A potter who lived in Bombay +Once fashioned a cunt out of clay; + But the heat of his prick + Kilned the damn thing to brick +And chafed all his foreskin away. +%% +A pretty wife living in Tours +Demanded her daily amour. + But the husband said, "No! + It's to much. Let it go! +My backsides are dragging the floor." +%% +A pretty young lady named Vogel +Once sat herself down on a molehill. + A curious mole + Nosed into her hole -- +Ms. Vogel's ok, but the mole's ill. +%% +A pretty young maiden from France +Decided she'd "just take a chance." + She let herself go + For an hour or so +And now all her sisters are aunts. +%% +A rapturous young fellatrix +One day was at work on five pricks. + With an unholy cry + She whipped out her glass eye: +"Tell the boys I can now take on six." +%% +A reckless young lady of France +Had no qualms about taking a chance, + But she thought it was crude + To get screwed in the nude, +So she always went home with damp pants. +%% +A remarkable race are the Persians; +They have such peculiar diversions. + They make love the whole day + In the usual way +And save up the nights for perversions. +%% +A romantic attraction has clung +To a chap of whom damsels have sung: + "'Tis the Scourge from the East, + That lascivious beast +Who was known as Attila the Hung!" +%% +A sailor who slept in the sun, +Woke to find his fly buttons undone, + He remarked with a smile, + "Good grief, a sun-dial! +And now it's a quarter-past one." +%% +A savvy young hooker named Gail +Got busted and lodged in the jail. + But the jailer got hot, + To be lodged in her twat, +And so Gail made the bail with her tail. +%% +A scandal involving an oyster +Sent the Countess of Clews to a cloister + She preferred it, in bed, + To the count (so she said) +'Cause it's longer and stronger and moister. +%% +A seafaring hacker named Slatey +Went to bed with a VAX/780. + The thing's learned to swear + With a nautical air, +And refers to its users as "matey". +%% +A sex-loving coed named Bree +Caught the clap from her Apple IIE. + The joystick, she found, + Had been fooling around +With a neighboring student's PC. +%% +A stout Gaelic warrior, McPherson, +Was having a captive, a person + Who was not averse + Though she had the curse, +And he'd breeches of bristling furs on. +%% +A structured programmer named Drew +Was intensely turned on by "goto". + When he saw it in code + He'd shoot off his load. +It's a good thing his shop used so few. +%% +A studious professor named Nestor +Bet a whore all his books that he could best her. + But she drained out his balls + And skipped up the walls, +Beseeching poor Nestor to rest her. +%% +A sweetheart named Teresa Arden +Went down on her beau in the garden. + He said, "Good lord, Tess, + Don't swallow that mess " +And she replied, "Ulp, beg your pardon?" +%% +A talented fuckstress, Miss Chisholm, +Was renowned for her fine paroxysm. + While the man detumesced + She still spent on with zest, +Her rapture sheer anachronism. +%% +A team playing baseball in Dallas +Called the umpire blind out of malice. + While this worthy had fits + The team made eight hits +And a girl in the bleachers named Alice. +%% +A tidy young lady of Streator +Dearly loved to nibble a peter. + She always would say, + "I prefer it this way. +I think it is very much neater." +%% +A tired young trollop of Nome +Was worn out from her toes to her dome. + Eight miners came screwing, + But she said, "Nothing doing; +One of you has to go home!" +%% +A vengeful technician named Schmitz +Caused a disk drive to go on the fritz. + He covered the platter + With bats' fecal matter. +Now it's seek time is really the pits. +%% +A very odd pair are the Pitts: +His balls are as large as her tits, + Her tits are as large + As an invasion barge-- +Neither knows how the other cohabits. +%% +A wanton young lady from Wimley +Reproached for not acting quite primly + Said, "Heavens above! + I know sex isn't love, +But it's such an entrancing facsimile." +%% +A weary old lecher named Blott +Took a luscious young blond to his yacht. + Too lazy to rape her, + He made darts out of paper, +Which he leisurely tossed at her twat. +%% +A whimsical fellow named Bloch +Could beat the base drum with his cock. + With a special erection + He could play a selection +From Johann Sebastian Bach. +%% +A wide-bottomed girl named Trasket +Had a hole as big as a basket. + A spot, as a bride, + In it now, you could hide, +And include with your luggage your mascot. +%% +A widow whose singular vice +Was to keep her late husband on ice + Said, "It's been hard since I lost him -- + I'll never defrost him! +Cold comfort, but cheap at the price." +%% +A wonderful tribe are the Sweenies, +Renowned for the length of their peenies. + The hair on their balls + Sweeps the floors of their halls, +But they don't look at women, the meanies. +%% +A wood-fetish busboy named Gable +Is rapid, is thorough, is able; + But when everything's cleared, + He gives way to the weird, +As he lovingly busses each table. +%% +A worn-out young husband named Lehr +Her daily his wife's plaintive prayer: + "Slip on a sheath, quick, + Then slip your big dick +Between these lips covered with hair." +%% +A worried young man from Stamboul +Founds lots of red spots on his tool. + Said the doctor, a cynic, + "Get out of my clinic; +Just wipe off the lipstick, you fool!" +%% +A young Juliet of St. Louis +On a balcony stood acting screwy. + Her Romeo climbed, + But he wasn't well timed, +And half-way up, off he went -- blooey! +%% +A young fellow discovered through Freud +That although of penis devoid, + He could practice coitus + By eating a foetus, +And his parents were quite overjoyed. +%% +A young lady sat by the sea, +Just as proper as proper could be. + A young fellow goosed her, + And roughly seduced her, +So she thanked him and went home to tea. +%% +A young man by a girl was desired +To give her the thrills she required, + But he died of old age + Ere his cock could assuage +The volcanic desire it inspired. +%% +A young man from the banks of the Po +Found his cock had elongated so, + That when he'd pee + It was never he +But only his neighbors who'd know. +%% +A young man maintained that his trigger +Was so big that there weren't any bigger. + But this long and thick pud + Was so heavy it could +Scarcely lift up its head. It lacked vigor. +%% +A young man of Llanfairpwllgwyngyll +While bent over plucking a dingle + Had the whole of Eisteddfod + Taking turns at his pod +While they sang some impossible jingle. +%% +A young man with passions quite gingery +Tore a hole in his sister's best lingerie. + He slapped her behind + And made up his mind +To add incest to insult and injury. +%% +A young polo-player of Berkeley +Made love to his sweetheart beserkly. + In the midst of each chukker + He would break off and fuck her +Horizontally, laterally and verkeley. +%% +A young systems programmer of Sprotic +Found his software intensely erotic. + In jealous distress + He wiped his OS. +It's possible that he's a psychotic. +%% +A young violinist from Rio +Was seducing a woman named Cleo. + As she took down her panties + She said, "No andantes; +I want this allegro con brio!" +%% +A young wife in the outskirts of Reims +Preferred frigging to going to mass. + Said her husband, "Take Jacques, + Or any young cock, +For I cannot live up to your ass." +%% +A young woman got married at Chester, +Her mother she kissed her and blessed her. + Says she, "You're in luck, + He's a stunning good fuck, +For I've had him myself down in Leicester." +%% +Alas for the Countess d'Isere, +Whose muff wasn't furnished with hair. + Said the Count, "Quelle surprise!" + When he parted her thighs; +"Magnifique! Pourtant pas de la guerre." +%% +All the female apes ran from King Kong +For his dong was unspeakably long. + But a friendly giraffe + Quaffed his yard and a half, +And ecstatically burst into song. +%% +An AI researcher named Bluth +Wrote, to find out the sexual truth, + Eroticon VI, + Which he taught certain tricks +Which I'm sure can't be found in Knuth. +%% +An aesthete from South Carolina +Had a cock that tickled like China, + But while shooting his load + It cracked like old Spode, +So he's bought him a Steuben vagina. +%% +An agreeable girl named Miss Doves +Likes to jack off the young men she loves. + She will use her bare fist + If the fellows insist +But she really prefers to wear gloves. +%% +An amazon giantess named Dunne +Let a midget screw her for fun. + But the poor little runt + Was engulfed in her cunt +And re-born as the twin of his son. +%% +An ambitious lady named Harriet +Once dreamed she was raped in a chariot + By seventeen sailors + A monk and three tailors, +Mohammed and Judas Iscariot. +%% +An anonymous woman we knew +Was dozing one day in her pew; + When the preacher yelled "Sin!" + She said, "Count me in +As soon as the service is through." +%% +An arrogant wench from Salt Lake +Liked to tease all the boys on the make. + She was finally the prize + Of a man twice her size +And all she recalls is the ache. +%% +An eager young hacker named Gus +Once buggered a VAX Unibus. + The hardware went bad, + But not the young lad +He didn't expect all that fuss! +%% +An envious girl named McMeanus +Was jealous of her lover's big penis. + It was small consolation + That the rest of the nation +Of women were with her in weeness. +%% +An exotic young lady named Suki +Once danced in a troupe of kabuki + When asked for a fuck + She said, "Solly, no luck-- +See here: looky looky, no nuki " +%% +An impish young fellow named James +Had a passion for idiot games. + He lighted the hair + Of his lady's affair +And laughed as she pissed through the flames. +%% +An impotent Scot named MacDougall +Had to husband his sperm and be frugal. + He was gathering semen + To gender a he-man, +By screwing his wife through a bugle. +%% +An ingenious young man in South Bend +Made a synthetic ass for a friend, + But the friend shortly found + Its construction unsound, +It was simply a bother -- no end. +%% +An octagenerian Jew +To his wife remained steadfastly true. + This was not from compunction, + But due to dysfunction +Of his spermatic glands -- nuts to you. +%% +An old couple just at Shrovetide +Were having a piece -- when he died. + The wife for a week + Sat tight on his peak, +And bounced up and down as she cried. +%% +An old man at the Folies Bergere +Had a jock, a most wondrous affair: + It snipped off a twat-curl + From each new chorus girl, +And he had a wig made of the hair. +%% +An organist playing in York +Had a prick that could hold a small fork, + And between obbligatos + He'd munch at tomatoes, +To keep up his strength while at work. +%% +An orgasmic young sex star named Sue +Was a hit as she writhed to a screw. + Her climatic fame spread + With an ad blitz that said: +Coming soon at a theater near you! +%% +And earnest young woman in Thrace +Said, "Darling, that's not the right place!" + So he gave her a thwack, + And did on her back, +What he couldn't have done face to face. +%% +And then there's the story that's fraught +With disaster -- of balls that got caught, + When a chap took a crap + In the woods, and a trap +Underneath... Oh, I can't bear the thought! +%% +As for weirdness, the guy who's the tops +Is a kinky old butcher named Pops. + Since he thinks it's effete + To be beating his meat, +What he's into is licking his chops. +%% +At Vassar, sex isn't injurious, +Though of love we are never penurious. + Thanks to vulcanized aids, + Though we may die old maids, +At least we shall never die curious. +%% +At the moment Japan declared war +A sailor was fucking a whore. + He said, "After this poke + `Long and hard' ain't no joke; +This means months 'til I get back ashore." +%% +Coitus upon a cadaver +Is the ultimate way you can have 'er. + Her inanimate state + Means a man needn't wait, +And eliminates all the palaver. +%% +Cum Hilde autem ambulabat +Homo qui aedificabat. + Dixit volebat. Debet et potebat. + Sic ille ducebat. Statim faciebat. +Sed virginem pine necebat. +%% +Dame Catherine of Ashton-on-Lynches +Got on with her grooms and her wenches: + She went down on the gents, + And pronged the girl's vents +With a clitoris reaching six inches. +%% +De Hispanice puella verumque +Simplex oris verborumque + Tulit potens vagina + Hominum agmina +Iterum iterum iterumque. +%% +Did you hear about young Henry Lockett? +He was blown down the street by a rocket. + The force of the blast + Blew his balls up his ass, +And his pecker was found in his pocket. +%% +Don't dip your wick in a WAC, +Don't ride the breast of a WAVE, + Just sit in the sand + And do it by hand, +And buy bonds with the money you save. +%% +Down by the old model T, +Where she first showed it to me. + It was furry and black, + And she called it a crack, +But it looked like a manhole to me. +%% +DuPont, I.G., Monsanto, and Shell +Built a world-circling pussy cartel, + And by planned obsolescence, + So controlled detumescence, +A poor man could not get a smell. +%% +Es giebt ein Arbeiter von Tinz, +Er schlaft mit ein Madel von Linz. + Sie sagt, "Halt sein' plummen, + Ich hore Mann kommen." +"Jacht, jacht," sagt der Plummer, "Ich binz." +%% +Ethnologists up with the Sioux +Wired home for two punts, one canoe. + The answer next day, + Said, "Girls on the way, +But what the hell's a `panoe'?" +%% +Fond of equestrians, Mabel +Looked for true love in the stable. + But she found the studs, + For her were all duds, +Now she's out with the leg of a table. +%% +For a house-to-house salesman named Moore, +Getting housewives' attention's no chore: + He's endowed with a dong + That is 12 inches long, +So he wedges his foot in the door. +%% +For the sores on his prick he used Dial. +That failed; he gave Lava a trial. + But the one remedy + For contagious V.D. +Is the wonder drug sulfa-denial. +%% +"For the tenth time, dull Daphnis," said Chloe, +"You have told me my bosom is snowy; + You have made much fine verse on + Each part of my person, +Now do something -- there's a good boy!" +%% +From deep in the crypt at St. Giles +Came a bellow that echoed for miles. + Said the rector, "My gracious, + Has Father Ignatius +Forgotten the Bishop has piles!?" +%% +Have you heard of knock-kneed Samuel McGuzzum +Who married Samantha, his bow-legged cousin? + Some people say, + Love finds a way, +But for Sam and Samantha it doesn'. +%% +Have you heard of the lady named Cox +Who had a capacious old box? + When her lover was in place + She said, "Please turn your face. +I look like a gal, but I screw like a fox." +%% +He hated to mend, so young Ned +Called in a cute neighbor instead. + Her husband said, "Vi, + When you stitched up his torn fly, +Did you have to bite off the thread?" +%% +He'd kiss and the girls called him Georgie +They'd cry and the girls called him Porgie. + So he put Spanish fly + In their pudding and pie +And had the first tiny-tot orgy. +%% +"Hell, no," said the Duchess of Quick, +"I won't suck his filthy old prick! + It's not that I funk + At a mouthful of spunk, +But the smell of his ass makes me sick!" +%% +Her brother, a bastard named Ben, +Could rotate his pecker, and then + He would shoot through his rear + Which made him dear +Of the girls, and the envy of men. +%% +Her daughter, thought worried Ms. Coffin, +Had morals the city might soften. + So she phoned and asked, "Lynn, + Are you living in sin?" +Lynn said, "No -- but I visit there often." +%% +I dined with Lord Hughing Fitz-Bluing +Who said, "Do you squirm when you're screwing?" + I replied, "Simple shagging + Without any wagging +Is only for screwing canoeing." +%% +I know of a fortunate Hindu +Who is sought in the towns that he's been to + By the ladies he knows, + Who are thrilled to the toes +By the tricks that he makes his foreskin do. +%% +I met a young man in Chungking +Who had a very long thing -- + But you'll guess my surprise + When I found that its size +Just measured a third-finger ring! +%% +I never had Miss Defauw, +But it wouldn't have been quite so raw + If she'd only said "No" + When I wanted her so; +But she didn't -- she laughed and said "Naw!" +%% +I once had the wife of a Dean +Seven times while the Dean was out skiin'. + She remarked with some gaiety, + "Not bad for the laiety, +Though the Bishop once managed thirteen." +%% +I once met a lassie named Ruth +In a long distance telephone booth. + Now I know the perfection + Of an ideal connection +Even if somewhat uncouth. +%% +I once was annoyed by a queer +Who made his intentions quite clear. + Said I, "I'm no prude, + So don't think me rude, +But I'm already stewed, screwed, and tattooed." +%% +I wooed a stewed nude in Bermuda, +I was lewd, but my God! she was lewder. + She said it was crude + To be wooed in the nude-- +I persued her, subdued her, and screwed her! +%% +I'd rather have fingers than toes, +I'd rather have ears than a nose, + And a happy erection + Brought just to perfection +Makes me terribly sad when it goes. +%% +If you're speaking of actions immoral +The how about giving the laurel + To doughty Queen Esther, + No three men could best her -- +One fore, and one aft, and one oral. +%% +Il y avait un plombier, Francois, +Qui plombait sa femme dans le Bois. + Dit-elle, "Arretez! + J'entends quelqu'un venait." +Dit le plombier, en plombant, "C'est moi." +%% +Il y avait une madame de Lahore +Dont la figure n'etait la meilleure, + Mais la vagine tres forte, + Toujours ouverte la porte, +Encore, et encore, et encore. +%% +In bed Dr. Oscar McPugh +Spoke of Spengler -- and ate crackers too. + His wife said, "Oh, stuff + That philosophy guff +Up your ass, dear, and throw me a screw!" +%% +In the Garden of Eden lay Adam, +Complacently stroking his madam, + And loud was his mirth + For on all of the earth +There were only two balls -- and he had 'em. +%% +In the case of a lady named Frost, +Whose cunt's a good two feet acrost, + It's the best part of valor + To bugger the gal, or +You're apt to fall in and get lost. +%% +In the little French town of Le'Beau, +Lived a maiden exceedingly droll. + At a masquerade ball, + Clad in nothing at all, +She backed in as a Parker house roll. +%% +It always delights me at Hank's +To walk up the old river banks. + One time in the grass + I stepped on an ass, +And heard a young girl murmur, "Thanks." +%% +It had snowed, and the man in the drift, +Flagged her down and asked, "Give me a lift?" + They sat in her Bentley, + She fondled him gently, +And the lift that he'd asked for was swift! +%% +King Louis gave a lesson in class, +One time while enjoying a lass. + When she used the word "Damn" + He rebuked her: "Please ma'am, +Keep a more civil tongue in my ass." +%% +"Last night," said a lassie named Ruth, +"In a long-distance telephone booth, + I enjoyed the perfection + Of an ideal connection -- +I was screwed, if you must know the truth." +%% +Love letters no longer they write us, +To their homes they so seldom invite us. + It grieves me to say, + They have learned with dismay, +We can't cure their `vulva pruritus'. +%% +Meet Elmer, young son of the Thorpes, +Afflicted with psychotic warps. + His idea of fun + Is to bugger a nun, +And then vomit all over the corpse. +%% +Now hear this fair lass from Rhode Isle +Who said with a wink and a smile, + "Sure, please stick it in, + Be it thick be it thin, +But if's rough I won't do as a file." +%% +Oden the bardling averred +His muse was the bum of a bird, + And his Lesbian wife + Would finger his fife +While Fisherwood waited as third. +%% +Of his face she thought not very much, +But then, at the very first touch, + Her attitude shifted -- + He was terribly gifted +At frigging and fucking and such. +%% +Oh, pity the Duchess of Kent! +Her cunt is so dreadfully bent, + The poor wench doth stammer, + "I need a sledgehammer +To pound a man into my vent." +%% +Oh pity the prince, Montezuma +He tried to make love to a puma. + Seems the puma, in play, + Tore his testes away -- +An example of animal huma. +%% +On a cannibal isle near Malaysia +Lives a lady they call Anastasia. + Not Russian elite- + She's eager to eat +Whatever or whoever lays her. +%% +On the porch of a dude named Horatio, +His girl got a yen for fellatio. + As she sucked on his dingus + He tried cunnilingus +But the cops ran 'em off of that patio. +%% +One evening a guru had coitus +With an actress, a whore and a poetess. + When asked what position + He used for coition, +He answered serenely, "the lotus." +%% +One night a girl had an affair +With a fellow all covered with hair. + Then she picked up his hat + And realized that +She'd been had by Smokey the Bear. +%% +Perplexed, a shy virgin named Plummer +Asked, "what's there to do in the summer?" + She declined and declined + Till approached from behind... +When her summer turned out quite a bummer! +%% +Playing poker with busty Ms. Ware, +He announced as he folded with flair, + "I had four of a kind, + But those aces combined, +Don't stack up, I'm afraid with your pair." +%% +Prince Absalom lay with his sister +And bundled and nibbled and kissed her, + But the kid was so tight, + And it was deep night -- +Though he shot at the target, he missed her. +%% +Prope mare erat tubulator +Qui virginem ingrediebatur. + Dessine ingressus + Audivi progressus: +Est mihi inquit tubulator. +%% +Said a dainty young whore named Ms. Meggs, +"The men like to spread my two legs, + Then slip in between, + If you know what I mean, +And leave me the white of their eggs." +%% +Said a horny young girl from Milpitas, +"My favorite sport is coitus." + But a fullback from State, + Made her period late, +And now she has athlete's fetus. +%% +Said a lecherous fellow named Shea, +When his prick wouldn't rise for a lay, + "You must sieze it, and squeeze it, + And tease it, and please it, +For Rome wasn't built in a day." +%% +Said a lesbian lady, "It's sad; +Of all the girls that I've had, + None gave me the thrill + Of real rapture until +I learned how to be a tribade." +%% +Said a madam named Mamie La Farge +To a sailor just off of a barge, + "We have one girl that's dead, + With a hole in her head-- +Of course there's a slight extra charge." +%% +Said a modest young miss to de Sade, +I'm simply too shy and afraid + To take part in your pranks. + But to show you my thanks, +I'd just love to become your first aide. +%% +Said a pornographistic young poet +"Although I perhaps do not show it, + My interest in sin + Is wearing quite thin, +And I'll soon tell those fuckers to stow it." +%% +Said a swinging young chick named Lyth +Whose virtue was largely a myth, + "Try as hard as I can, + I can't find a man +That it's fun to be virtuous with." +%% +Said the Duchess of Danzer at tea, +"Young man, do you fart when you pee?" + I replied with some wit, + "Do you belch when you shit?" +I think that was one up for me. +%% +Says an airlining wanton named Vi: +"I'm a pantyless stew when I fly. + To a muffer's delight, + I'll take head on a flight, +So the guy can have pie in the sky." +%% +She made a thing of soft leather, +And topped off the end with a feather. + When she poked it inside her + She took off like a glider, +And gave up her lover forever. +%% +She was coming round the mountain doin' ninety, +When the chain on her motorcycle broke, + Now she's lying in the grass, + With the muffler up her ass, +And her tits a-playin' Dixie on the spokes. +%% +Shouted Frosty the Snowman "Hooray! +I'm agog with excitement today! + And the reason of course, + A reliable source, +Said the snow blower's heading this way!" +%% +"Snyder's got a stiff ticket," said Kay, +"Come on, take it out, and let's play." + He pulled it on out, + But she started to pout, +His ticket was only a quarter-inch stout. +%% +So here was this fellow of Strensall +Whose pecker was shaped like a pencil, + Anemic, 'tis true, + But an interesting screw, +Inasmuch as the tip was prehensile. +%% +Thank God for the Duchess of Gloucester, +She obliges all who accost her. + She welcomes the prick + Of Tom, Harry or Dick, +Or Baldwin, or even Lord Astor. +%% +That Harvard don down at El Djim -- +Oh, wasn't it nasty of him, + With the whole harem randy, + The sheik himself handy, +To muss up a young camel's quim. +%% +That naughty old Sappho of Greece +Said "What I prefer to a piece + Is to have my pudenda + Rubbed hard by the enda +The little pink nose of my niece." +%% +The King named Oedipus Rex +Who started this fuss about sex + Put the world to great pains + By the spots and the stains +Which he made on his mother's pubex. +%% +The King plugged the Queen's ass with mustard +To make her fuck hot, but got flustered, + And cried, "Oh, my dear, + I am coming, I fear, +But the mustard will make you come `plus tard'." +%% +The Reverend Henry Ward Beecher +Called a girl a most elegant creature. + So she laid on her back + And, exposing her crack, +Said, "Fuck that, you old Sunday School Teacher!" +%% +The Shah of the Empire of Persia +Lay for days in a sexual merger. + When the nautch asked the Shah, + "Won't you ever withdraw?" +He replied with a yawn, "It's inertia." +%% +The acrobats - Tom and Louise- +Do an act in the nude on their knees. + They crawl down the aisle + While screwing dog-style, +As the orchestra plays Kilmer's "Trees." +%% +The late Brigham Young was no neuter -- +No faggot, no fairy, no fruiter. + Where ten thousand virgins + Succumbed to his urgin's +There now stands the great State of Utah. +%% +The latest reports from Good Hope +State that apes there have pricks thick as rope, + And fuck high, wide, and free, + From the top of one tree +To the top of the next -- what a scope! +%% +The new local cinematorium +Is not only a super sensorium, + But a highly effectual + Heterosexual +Mutual masturbatorium. +%% +The nipples of Sarah Sarong +When excited are twelve inches long + This embarassed her lover + Who was pained to discover +She expected no less of his dong +%% +The notorious Duchess of Peels +Saw a fisherman fishing for eels. + Said she, "Would you mind? -- + Shove one up my behind. +I am anxious to know how it feels." +%% +The skater, Barbara Ann Scott +Is so fuckingly "winsome" a snot, + That when posed on her toes + She elaborately shows +Teeth, fat ass, titties and twat. +%% +The spouse of a pretty young thing +Came home from the wars in the spring. + He was lame but he came + With his dame like a flame -- +A discharge is a wondeful thing. +%% +"The testes are cooler outside," +Said the doc to the curious bride, + "For the semen must no + Get too fucking hot, +And the bag fans your bum on the ride." +%% +"The testes are cooler outside," +Said the doc to the curious bride, + "For the semen must not + Get too fucking hot, +And the bag fans your bum on the ride." +%% +The wife of young Richard of Limerick +Complained to her husband, "My quim, Rick, + Still grows in diameter + Each time that you ram at her; +How can your poor tool stay so slim, Rick?" +%% +The woman who lives on the moon +Is still cherishing the balloon + Of an earthling who'd come + And given her some, +But had dribbled away all too soon. +%% +There a young man from the Coast +Who had an affair with a ghost. + At the height of orgasm + Said the pallid phantasm, +"I think I can feel it -- almost!" +%% +There is a young faggot named Mose +Who insists that you fuck his long nose. + And you'll double the joy + Of this lecherous boy +If you'll tickle his balls with your toes. +%% +There once was a Duchess of Bruges +Whose cunt was incredibly huge. + Said the king to this dame + As he thunderously came: +"Mon Dieu! Apres moi, le deluge!" +%% +There once was a Scot named McAmeter +With a tool of prodigious diameter. + It was not the size + That cause such surprise; +'Twas his rhythm -- iambic pentameter. +%% +There once was a Swede in Minneapolis, +Discovered his sex life was hapless: + The more he would screw + The more he'd want to, +And he feared he would soon be quite sapless. +%% +There once was a chick named Longet, +Who went out to Aspen to play. + Along came a Spyder, + Who sat down beside her +And she blew the poor bastard away. +%% +There once was a couple named Kelley, +Who lived their life belly to belly. + Because in their haste + They used library paste, +Instead of petroleum jelly. +%% +There once was a dentist named Stone +Who saw all his patients alone. + In a fit of depravity + He filled the wrong cavity, +And my, how his practice has grown! +%% +There once was a fag of Khartoom +Who spent the night in a Lesbians room. + They argued all night, + Over who had the right, +To do what, and with which, and to whom. +%% +There once was a fellow named Bob +Who in sexual ways was a snob. + One day he was swimmin' + With twelve naked women +And deserted them all for a gob. +%% +There once was a fellow named Brewster +Who said to his wife, as he goosed her, + "It used to be grand + But look at my hand +You're not wiping as clean as ya uster." +%% +There once was a fellow named Howard, +Whose tool it was nuclear-powered, + While grabbing some ass, + He reached critical mass, +But think of the girl he deflowered! +%% +There once was a fellow named Siegel +Who attempted to bugger a beagle, + But the mettlesome bitch + Turned and said with a twitch, +"It's fun, but you know it's illegal." +%% +There once was a fencer named Fisk, +Whose speed was incredibly brisk. + So fast was his action, + The Fitzgerald contraction, +Foreshortended his foil to a disk. +%% +There once was a floozie named Annie +Whose prices were cosy--but cannie: + A buck for a fuck, + Fifty cents for a suck, +And a dime for a feel of her fanny. +%% +There once was a freshman named Lin, +Whose tool was as thin as a pin, + A virgin named Joan + From a bible belt home, +Said "This won't be much of a sin." +%% +There once was a gaucho named Bruno, +Who said, "About sex, well, I do know, + Sheep are just fine, + Chickens, divine, +But iguanas are Numero Uno." +%% +There once was a gay young Parisian +Who screwed an appendix incision, + And the girl of his choice + Could hardly rejoice +At the horrible lack of precision. +%% +There once was a girl from Cornell +Whose teats were shaped like a bell. + When you touched them they shrunk, + Except when she was drunk, +And then they got bigger than hell. +%% +There once was a girl from Decatur, +Who got laid by a big alligator. + Now nobody knew + The result of that screw, +'Cause after he laid her, he ate her. +%% +There once was a girl from Spokane, +Went to bed with a one-legged man. + She said, "I know you-- + You've really got two! +Why didn't you say so when we began?" +%% +There once was a girl named Mcgoffin +Who was diddled amazingly often. + She was rogered by scores + Who'd been turned down by whores, +And was finally screwed in her coffin. +%% +There once was a girl named Priscilla +Whose vagina was flavored vanilla. + The taste was so fine + Man and beast stood in line +(Including a stud armadilla). +%% +There once was a golfer named Leer, +Who got put in the clink for a year, + For an action obscene, + On the very first green. +Where the sign said "Enter course here." +%% +There once was a gouty old colonel +Who grew glum when the weather grew vernal, + And he cried in his tiffin + For his prick wouldn't stiffen, +And the size of the thing was infernal. +%% +There once was a hacker named Ken +Who inherited truckloads of Yen. + So he built him some chicks, + Of silicon chips, +And hasn't been heard from since then. +%% +There once was a handsome young seaman +Who with ladies was really a demon. + In peace or in war, + At sea or on shore, +He could certainly dish out the semen. +%% +There once was a horny old bitch +With a motorized self-frigger which + She would use with delight + All day long and all night - +Twenty bucks: Abercrombie & Fitch. +%% +There once was a horse named Lily +Whose dingus was really a dilly. + It was vaginoid duply, + And labial quadruply -- +In fact, he was really a filly. +%% +There once was a husky young Viking +Whose sexual prowess was striking. + Every time he got hot + He would scour the twat +Of some girl that might be to his liking. +%% +There once was a jolly old bloke +Who picked up a girl for a poke. + He took down her pants, + Fucked her into a trance, +And then shit into her shoe for a joke. +%% +There once was a kiddie named Carr +Caught a man on top of his mar. + As he saw him stick 'er, + He said with a snicker, +"You do it much faster than par." +%% +There once was a lady from Exeter, +So pretty that men craned their necks at her. + One was even so brave + As to take out and wave +The distinguishing mark of his sex at her. +%% +There once was a lady from Kansas +Whose cunt was as big as Bonanzas. + It was nine inches deep + And the sides were quite steep -- +It had whiskers like General Carranza's. +%% +There once was a lady named Carter, +Fell in love with a virile young Tartar. + She stripped off his pants, + At his prick quickly glanced, +And cried: "For that I'll be a martyr!" +%% +There once was a lady named Clair, +Who posessed a magnificent pair. + Or that's what I thought, + Till I saw one get caught, +On a thorn and begin losing air. +%% +There once was a lady named Myrtle +Who had an affair with a turtle. + She had crabs, so they say, + In a year and a day +Which proved that that turtle was fertile. +%% +There once was a lifeguard named Lee +Who rescued a girl from the sea + She asked how to pay, + And he said "Try this way, +Go down for the third time on me." +%% +71: + 69 with two fingers up your ass. + -- George Carlin +%% +When someone tells you to "take it like +a man" it usually means up your ass. +%% +Bend over and take it like a man! +%% +Gravity is an unforgiving motherfucker. +%% +I know a Polack his name is Cliff, +Hey-la-de-la-de-la. +He sticks it in the freezer to get it stiff, +Hey-la-de-la-de-lo. + +I know a girl, her name is Serafina, +Hey-la-de-la-de-la. +She'll get down on all fours for a bowl of Purina, +Hey-la-de-la-de-lo. + +I know a girl, her name is Cuffy, +Hey-la-de-la-de-la. +She douches with Tide and makes her pubes fluffy, +Hey la-de-la-de-lo. + -- Doctor Dirty +%% +Hangover, n: + The burden of proof. +%% +When the naive young lady asked the clerk in Le Sex Shoppe to show her his +selection of vibrators, he brought out the two most popular ones. + "The basic white one here is twenty dollars," the clerk said. "The +flesh-toned model is thirty." + "I'm just not sure," the woman said, Then she noticed an eye-catching +item on the back shelf. "How much is that plaid one over there? + "Uh, well, that's a pretty special one," said the clerk. "I couldn't +sell you that one for less than a hundred." + "I'll take it." + Later that day, the store owner checked in to see how business was +going. "Great," the clerk told him. "This morning, I sold four white +vibrators and three flesh-toned ones. And, this afternoon, I got a hundred +bucks for my Thermos." +%% +We have reason to believe that man first +walked upright to free his hands for masturbation. + -- Lily Tomlin +%% + A white man was traveling with Indian (American) out West. The +Indian stops, puts his ear to the ground, and says, "Buffalo come." + The white man looks around in all directions, sees nothing for +miles and asks the Indian how the hell he's knows that. + Replies the Indian, "Ear wet." + -- Lily Tomlin, "The Search for Signs of Intelligent + Life in the Universe" +%% +Swallow, v: + The (blew) bird of birth control. +%% +Having lost his potency years before, the octogenarian was desperate to +satisfy his new 18-year-old wife. He visited a gypsy woman with magical +powers. + After the man downed a foul-tasting potion, the gypsy said, "There. +Now the words beep-beep will give you an enormous erection. Repeating +the phrase will make it disappear. But remember," she cautioned, "it will +work only three times. Make use of them wisely." + As the old man left, he decided to test her prediction. "Beep-beep," +he said, and sure enough, he got the biggest erection of his life. +"Beep-beep", he repeated. It went away. + He sped through traffic on his way home. "Beep-beep," honked a taxi. +The old man gasped as he instantly got hard. + "Beep-beep," honked a truck. His erection wilted. + Pulling into his driveway at last, the frantic man rushed inside +and found his nubile wife lying on the bed reading a novel. + "Have I got a surprise for you," he said, tearing off his clothes. +"Beep-beep!" + "Hold on a second," his wife said, eyeing his magnificent erection. +"What's all this beep-beep shit?" +%% +After a few steamy dances and a few more drinks, the pickup couple +are back at his place tearing their clothes off. Things are really +starting to heat up when he leaps out of bed and starts frantically +rummaging through a dresser drawer. + "What are you doing?" she asks. + "Just a second, honey, I'm trying to find my lucky rubber." +%% +Be prepared... that's the Boy Scout's solemn creed. +Be prepared... to be clean in word and deed. +Don't solicit for your sister, that's not nice, +Unless you get a good percentage of her price. + -- Tom Lehrer +%% +Claude believed that only smart attractive people had the right +to fuck, and it sincerely hurt him when he discovered evidence to +the contrary. + -- Tom Robbins, "Jitterbug Perfume" +%% +I walked on toward Ploughwright, thinking about faeces. What a lot we +had found out about the prehistoric past from the study of fossilized +dung of long-vanished animals. A miraculous thing, really; a recovery +from the past from what was carelessly rejected. And in the Middle +Ages, how concerned people who lived close to the world of nature were +with the faeces of animals. And what a variety of names they had for +them: the Crotels of a Hare, the Friants of a Boar, the Spraints of +an Otter, the Werderobe of a Badger, the Waggying of a Fox, the Fumets +of a Deer. Surely there might be some words for the material so near +to the heart of Ozy Froats [an academic studying feces] than shit? +What about the Problems of a President, the Backward Passes of a +Footballer, the Deferrals of a Dean, the Odd Volumes of a Librarian, +the Footnotes of a Ph.D., the Low Grades of a Freshman, the Anxieties +of an Untenured Professor? + -- Robertson Davies, "The Rebel Angels" +%% +A certain bartender decided to try to get a few new customers into his bar +by starting a gimmick involving a horse. His claim was that if anyone could +get the horse to laugh, he would give them drinks on the house. The idea +worked well and business improved until one night a young man walked in and +whispered in the horse's ear. The horse immediately burst into hysterical +laughter and the man won the contest. The next night the same thing +happened: the man whispered in the horse's ear and the horse burst out +laughing. The next night, the bartender decided to change the rules. Now, +a person had to get the horse to cry in order to win the drinks on the +house. Later on that night, the same guy came in and said "Can I take the +horse into the bathroom for a minute? I promise I'll make him cry." The +bartender agreed and sure enough, when the man came out leading the horse, +the horse was crying his eyes out. The bartender could take it no more and +said, "How did you make him laugh the other two nights?" + "I told him that my dick was bigger than his", replied the man. + "How did you make him cry tonight?" + "I proved it." +%% +Man in stall: + Hey, buddy? Is there any toilet paper out there? +Man at sink: + No, I don't see any. Just a second... Nope, none in + any of the other stalls either. +A minute passes. +Man in stall: + Say, buddy? +Man at sink: + Yeah? +Man in stall: + You got change for a ten? +%% +Q: What did Jesus tell the Aggies? +A: Play dumb until the second coming. +%% +May a diseased yak take a liking to your sister. +%% +May the fairy god-camel leave a lump on your pillow! +%% +May Allah blow sand in your Preparation H. +%% +May a deranged midget on a pogo stick +take refuge in your sister's hoop skirt. +%% +A gorgeous young sophomore is having an affair with her English +professor. She goes home to visit her family for Christmas vacation +and when she gets back, she immediately invites him over for the +night. As soon as he walks through the door she hugs him and +asks, "Were you blue while I was away?" + "Blown, my dear," the professor corrects her, "blown." +%% +The operator's left hand quivered as she gingerly unlatched the +catch to the diskette reader. Uncontrollably, she reached down, +guiding the sharply pointed diskette into the deep, dark slot. +The floppy diskette nearly folded under the repeated thrusts of +her hand, until finally she could control it no longer, her right +hand instinctively taking an option zero. And then it all came at +once, thousands upon thousands of data bits flowing from diskette +to disk in a torrent of torrid transfer, as the helpless legs +of the 32 strained to remain on the floor. +%% +I've been feeling kind of jealous, +Of all them well-hung fellas, +Like Michael, Rod, and Mick. It would have to be a big one, +Tell me, Doctor can you mend me? A giant, horny love gun, +I've a case of penis envy -- To let me be a jock. +If I only had a dick. Girls would never beg my pardon, + They would turn on to my hardon -- + If I only had a cock. +Oh, I can tell you now, +The number of times I'd score, +I could fuck girls like I would not be just a housewife, + I never have before, Living a little mouse-life +And then I'd cum (wee!) In days that drag out long. +And fuck some more! I would dance and I'd be merry + Life would be a ding-a-derry + If I only had a dong! + -- to "If I Only Had A Brain", The Wizard of Oz +%% +Condoms are like listening to a symphony with cotton in your ears. +%% + Are you a Young Urban Professional Woman? If so, you know how +Yuppie women are; cold, ruthless bitches with no time for love, and only +an occasional weekend for sex. Your one "hot date" with Joe Fastrack, +rising corporate star, ended in disaster. Yesterday you heard him telling +a friend over lunch, "The woman must masturbate with popsicles!" Well, +all is not lost! SofSqueeze can change your nickname to Electrolux in just +15 minutes a day! + SofSqueeze is a pressure sensitive device (divided into appropriate +sections) that plugs into the serial port of most home computers. Through +the magic of biofeedback, SofSqueeze teaches you control over your vaginal +muscles. With our exciting, easy-to-follow software you'll master the +"Cincinnati Squeeze", the "Irresistable", the "California Crusher", and, +of course, the perennial favorite, "Milking Time Down on the Farm". Or, +using our exclusive Interactive Mode, invent your own! + SofSqueeze is made of sturdy ABS plastic, and is completely +immersible for easy cleaning. SofSqueeze's flesh-toned exterior is finely +textured for a realistic effect. Requires 4K RAM, a DB25 serial port and +limited graphics capability. Comes fully assembled, with 4 AA batteries. +%% +It's a bitch being butch. +%% +Of course, most people eventually give up bowling for sex. +The balls are lighter and you don't have to change your shoes. +%% +Some of the management around here are the +final proof that the Indians fucked the buffalo. +%% +Life is not a cabaret. +It's a fucking circus. +%% +Yuck Foo. +%% +Winning isn't everything, but losing really sucks. +%% +There once was a man from Calcutta +Who used to beat off in the gutta + The heat of the sun + Affected his gun +And turned all his cream into butta! +%% +There once was a man from Madras, +Whose balls were made out of brass. + When they clanged together, + They played "Stormy Weather", +And lightning shot out of his ass. +%% +There once was a man from Nantee +Who buggered an ape in a tree. + The results were most horrid + All ass and no forehead +Three balls and a purple goatee. +%% +There once was a man from Nantucket, +Whose cock was so long he could sucket. + He said with a grin, + As he wiped off his chin, +If my ear were a cunt I could fucket. +%% +There once was a man from Racine, +Who invented a screwing machine. + Both concave and convex, + It could please either sex, +But, oh, what a bastard to clean! +%% +There once was a man from Sydney +Who could put it up to her kidney. + But the man from Quebec + Put it up to her neck; +He had a big one, now didn't he? +%% +There once was a man named Lodge, +Who had seatbelts installed in his Dodge. + When his date was strapped in, + He committed a sin, +Without ever leaving the garage. +%% +There once was a man named McGruder, +Who canoed with a girl in Bermuder. + But the girl thought it crude, + To be wooed in the nude, +So McGru took an oar and subduder. +%% +There once was a man named McSweeny +Who spilled some raw gin on his weeny. + Just to be couth, + He added vermouth, +And slipped his girlfriend a martini. +%% +There once was a man named Parridge +With peculiar views on marriage. + He sucked off his brother, + Fucked his own mother, +And gobbled his sister's miscarriage. +%% +There once was a miner named Dave, +Who kept a dead whore in his cave. + She was ugly as shit, + And missing one tit, +But think of the money he saves. +%% +There once was a newspaper vendor, +A person of dubious gender. + He would charge one-and-two + For permission to view +His remarkable double pudenda. +%% +There once was a plumber from Leigh, +Who was plumbing his maid by the sea, + Said she, "Please stop plumbing, + I think someone's coming!" +Said he, "Yes I know, love, it's me." +%% +There once was a queen of Bulgaria +Whose bush had grown hairier and hairier, + Till a prince from Peru + Who came up for a screw +Had to hunt for her cunt with a terrier. +%% +There once was a sad Maitre d'hotel +Who said, "They can all go to hell! + What they do to my wife -- + Why it ruins my life; +And the worst is they all do it well." +%% +There once was a sailor named Gasted, +A swell guy, as long as he lasted, + He could jerk himself off + In a basket, aloft, +Or a breeches-buoy swung from the masthead. +%% +There once was a son-of-a-bitch, +Neither clever, nor handsome, nor rich, + Yet the girls he would dazzle, + And fuck to a frazzle, +And then ditch them, the son-of-a-bitch! +%% +There once was a woman from Arden +Who sucked off a man in a garden. + He said, "My dear Flo, + Where does all that stuff go?" +And she said, "[Swallow hard] I beg pardon?" +%% +There once was a yokel of Beaconsfield +Engaged to look after the deacon's field, + But he lurked in the ditches + And diddled the bitches +Who happened to cross that antique 'un's field. +%% +There once was a young fellow named Blaine, +And he screwed some disgusting old jane. + She was ugly and smelly, + With an awful pot-belly, +But... well, they were caught in the rain. +%% +There once was a young man from Boston +Who drove around town in an Austin, + There was room for his ass, + And a gallon of gas, +So he hung out his balls and he lost 'em. +%% +There once was a young man named Gene, +Who invented a screwing machine. + Concave and convex, + It served either sex, +And it played with itself inbetween. +%% +There once were two brothers named Luntz +Who buggered each other at once. + When asked to account + For this intricate mount, +They said, "Ass-holes are tighter than cunts." +%% +There was a bluestocking in Florence +Wrote anti-sex pamphlets in torrents, + Till a Spanish grandee, + Got her off with his knee, +And she burned all her works with abhorrence. +%% +There was a family named Doe, +An ideal family to know. + As father screwed mother, + She said, "You're heavier than brother." +And he said, "Yes, Sis told me so!" +%% +There was a fat lady of China +Who'd a really enormous vagina, + And when she was dead + They painted it red, +And used it for docking a liner. +%% +There was a fat man from Rangoon +Whose prick was much like a ballon. + He tried hard to ride her + And when finally inside her +She thought she was pregnant too soon. +%% +There was a gay countess of Bray, +And you may think it odd when I say, + That in spite of high station, + Rank and education, +She always spelled cunt with a 'k'. +%% +There was a gay dog from Ontario +Who fancied himself a Lothario. + At a wench's glance + He'd snatch off his pants +And make for her Mons Venerio. +%% +There was a gay parson of Norton +Whose prick, although thick, was a short 'un. + To make up for this loss, + He had balls like a horse, +And never spent less than a quartern. +%% +There was a gay parson of Tooting +Whose roe he was frequently shooting, + Till he married a lass + With a face like my arse, +And a cunt you could put a top-boot in. +%% +There was a girl from Aberystwyth +Who brought grain to the mill to get grist with. + The miller's son Jack + Laid her flat on her back +And united the organs they pissed with. +%% +There was a pianist named Liszt +Who played with one hand while he pissed, + But as he grew older + His technique grew bolder, +And in concert jacked off with his fist. +%% +There was a poor parson from Goring, +Who made a small hole in his flooring, + Fur-lined it all round, + Then laid on the ground, +And declared it was cheaper than whoring. +%% +There was a strong man of Drumrig +Who one day did seven times frig. + He buggered three sailors, + Four dogs and two tailors, +And ended by fucking a pig. +%% +There was a young German named Ringer +Who was screwing an opera singer. + Said he with a grin, + "Well, I've sure got it in!" +Said she, "You mean that ain't your finger?" +%% +There was a young Scot in Madrid +Who got fifty-five fucks for a quid. + When they said, "Are you faint?" + He replied, "No, I ain't, +But I don't feel as good as I did." +%% +There was a young blade from South Greece +Whose bush did so greatly increase + That before he could shack + He must hunt needle in stack. +'Twas as bad as being obese. +%% +There was a young bride, a Canuck, +Told her husband, "Let's do more than suck. + You say that I, maybe, + Can have my first baby-- +Let's give up this Frenchin' and fuck!" +%% +There was a young bride of Antigua +Whose husband said, "Dear me, how big you are!" + Said the girl, "What damn'd rot! + Why, you've only felt my twot, +My legs and my arse and my figua!" +%% +There was a young damsel named Baker +Who was poked in a pew by a Quaker. + He yelled, "My God! what + Do you call this -- a twat? +Why, the entrance is more than an acre!" +%% +There was a young dolly named Molly +Who thought that to frig was a folly. + Said she, "Your pee-pee + Means nothing to me, +But I'll do it just to be jolly." +%% +There was a young fellow from Cal., +In bed with a passionate gal. + He leapt from the bed, + To the toilet he sped; +Said the gal, "What about me, old pal?" +%% +There was a young fellow from Florida +Who liked a friend's wife, so he borrowed her. + When they got into bed + He cried, "God strike me dead! +This ain't a cunt -- it's a corridor!" +%% +There was a young fellow from Leeds +Who swallowed a package of seeds. + Great tufts of grass + Sprouted out of his ass +And his balls were all covered with weeds. +%% +There was a young fellow from Parma +Who was solemnly screwing his charmer. + Said the damsel demure, + "You'll excuse me, I'm sure, +But I must say you fuck like a farmer." +%% +There was a young fellow name Tucker +Who, instructing a novice cock-sucker, + Said, "Don't bow out your lips + Like an elephant's hips, +The boys like it best when they pucker." +%% +There was a young fellow named Babbitt +Who could screw nine times like a rabbit, + But a girl from Johore + Could do it twice more, +Which was just enough extra to crab it. +%% +There was a young fellow named Bill, +Who took an atomic pill, + His navel corroded, + His asshole exploded, +And they found his nuts in Brazil. +%% +There was a young fellow named Bowen +Whose pecker kept growin' and growin'. + It grew so tremendous, + So long and so pendulous, +'Twas no good for fuckin' -- just showin'. +%% +There was a young fellow named Charteris +Put his hand where his young lady's garter is. + Said she, "I don't mind, + And higher up you'll find +The place where my fucker and farter is." +%% +There was a young fellow named Cribbs +Whose cock was so big it had ribs. + They were inches apart, + And to suck it took art, +While to fuck it took forty-two trips. +%% +There was a young fellow named Fletcher, +Was reputed an infamous lecher. + When he'd take on a whore + She'd need a rebore, +And they'd carry him out on a stretcher. +%% +There was a young fellow named Gluck +Who found himself shit out of luck. + Though he petted and wooed, + When he tried to get screwed +He found virgins just don't give a fuck. +%% +There was a young fellow named Goody +Who claimed that he wouldn't, but would he? + If he found himself nude + With a gal in the mood +The question's not woody but could he? +%% +There was a young fellow named Grimes +Who fucked his girl seventeen times + In the course of a week -- + And this isn't to speak +Of assorted venereal crimes. +%% +There was a young fellow named Harry, +Had a joint that was long, huge and scary. + He grabbed him a virgin, + Who, without any urgin', +Immediately spread like a fairy. +%% +There was a young fellow named Kimble +Whose prick was exceedingly nimble, + But fragile and slender, + And dainty and tender, +So he kept it encased in a thimble. +%% +There was a young fellow named Meek +Who invented a lingual technique. + It drove women frantic, + And made them romantic, +And wore all the hair off his cheek. +%% +There was a young fellow named Morgan +Who possessed an unusual organ: + The end of his dong, + Which was nine inches long, +Was tipped with the head of a gorgon. +%% +There was a young fellow named Paul +Who confessed, "I have only one ball. + But the size of my prick + Is God's dirtiest trick, +For my girls always ask, 'Is that all?'" +%% +There was a young fellow named Pell +Who didn't like cunt very well. + He would finger or fuck one, + But never would suck one-- +He just couldn't get used to the smell. +%% +There was a young fellow named Price +Who dabbled in all sorts of vice. + He had virgins and boys + And mechanical toys, +And on Mondays... he meddled with mice! +%% +There was a young fellow named Prynne +Whose prick was so short and so thin, + His wife found she needed + A Fuckoscope -- she did -- +To see if he'd gotten it in. +%% +There was a young fellow named Rex +With diminutive organs of sex. + When charged with exposure + He said with composure, +"De minimis non curat lex!" +%% +There was a young fellow named Sweeney, +Whose girl was a terrible meanie, + The hatch of her snatch, + Had a catch that would latch, +She could only be screwed by Houdini. +%% +There was a young fellow of Burma +Whose betrothed had good reason to murmur. + But now that he's married he's + Been using cantharides +And the root of their love is much firmer. +%% +There was a young fellow of Harrow +Whose john was the size of a marrow. + He said to his tart, + "How's this for a start? +My balls are outside in a barrow." +%% +There was a young fellow of Kent +Whose prick was so long that it bent, + So to save himself trouble + He put it in double, +And instead of coming he went. +%% +There was a young fellow of Mayence +Who fucked his own arse in defiance + Not only of custom + And morals, dad-bust him, +But of most of the known laws of science. +%% +There was a young fellow of Perth +Whose balls were the finest on earth. + They grew to such size + That one won a prize, +And goodness knows what they were worth. +%% +There was a young fellow of Strensall +Whose prick was as sharp as a pencil. + On the night of his wedding + It went through the bedding, +And shattered the chamber utensil. +%% +There was a young fellow of Warwick +Who had reason for feeling euphoric, + For he could by election + Have triune erection: +Ionic, Corinthian, and Doric. +%% +There was a young fellow whose dong +Was prodigiously massive and long. + On each side of his whang + Two testes did hang +That attracted a curious throng. +%% +There was a young gaucho named Bruno +Who said, "Screwing is one thing I do know. + A woman is fine, + And a sheep is divine, +But a llama is Numero Uno." +%% +There was a young girl from Hong Kong +Who said, "You are utterly wrong + To say my vagina + Is the largest in China +Just because of your mean little dong." +%% +There was a young girl from Hong Kong +Whose cervical cap was a gong. + She said with a yell, + As a shot rang her bell, +"I'll give you a ding for a dong!" +%% +There was a young girl from Medina +Who could completely control her vagina. + She could twist it around + Like the cunts that are found +In Japan, Manchukuo and China. +%% +There was a young girl from New York +Who plugged up her quim with a cork + A woodpecker or two + Made the grade, it is true, +But it totally baffled the stork. +%% +There was a young girl from Peru, +Who had nothing whatever to do. + So she sat on the stairs, + And counted cunt hairs, +Four thousand, three hundred and two. +%% +There was a young girl from Samoa +Who pledged that no man would know her. + One young fellow tried, + But she wriggled aside, +And he spilled all his spermatozoa. +%% +There was a young girl from Siam +Who said to her boyfriend Priam, + "To seduce me, of course, + You'll have to use force, +And thank goodness you're stronger than I am. +%% +There was a young girl from St. Cyr +Whose reflex reactions were queer. + Her escort said, "Mable, + Get up off the table; +That money's to pay for the beer." +%% +There was a young girl from the Bronix +Who had a vagina of onyx. + She had so much `tsoris' + With her clitoris, +She traded it in for a Packard. +%% +There was a young girl in Berlin +Who eked out a living through sin. + She didn't mind fucking, + But much preferred sucking, +And she'd wipe off the pricks on her chin. +%% +There was a young girl in Berlin +Who was fucked by an elderly Finn. + Though he diddled his best, + And fucked her with zest, +She kept asking, "Hey, Pop, is it in?" +%% +There was a young girl in Dakota +Had a letter from Ickes; he wrote her: + "In addition to gas + We are rationing ass, +And you've greatly exceeded your quota." +%% +There was a young girl name McKnight +Who got drunk with her boy-friend one night. + She came to in bed, + With a split maidenhead-- +That's the last time she ever was tight. +%% +There was a young girl named Ann Heuser +Who swore that no man could surprise her. + But Pabst took a chance, + Found a Schlitz in her pants, +And now she is sadder Budweiser. +%% +There was a young girl named Heather +Whose twitcher was made out of leather. + She made a queer noise, + Which attracted the boys, +By flapping the edges together. +%% +There was a young girl named McCall +Whose cunt was exceedingly small, + But the size of her anus + Was something quite heinous -- +It could hold seven pricks and one ball. +%% +There was a young girl named O'Clare +Whose body was covered with hair. + It was really quite fun + To probe with one's gun, +For her quimmy might be anywhere. +%% +There was a young girl named O'Malley +Who wanted to dance in the ballet. + She got roars of applause + When she kicked off her drawers, +But her hair and her bush didn't tally. +%% +There was a young girl named Sapphire +Who succumbed to her lover's desire. + She said, "It's a sin, + But now that it's in, +Could you shove it a few inches higher?" +%% +There was a young girl of Aberystwyth +Who took grain to the mill to get grist with. + The miller's sun, Jack, + Laid her flat on her back, +And united the organs they pissed with. +%% +There was a young girl of Angina +Who stretched catgut across her vagina. + From the love-making frock + (With the proper sized cock) +Came Tocata and Fugue in D minor. +%% +There was a young girl of Asturias +With a penchant for practices curious. + She loved to bat rocks + With her gentlemen's cocks -- +A practice both rude and injurious. +%% +There was a young girl of Batonger +who diddled herself with a conger, + When asked how it feels + To be pleasured by eels +She said, "Just like a man, only longer. +%% +There was a young girl of Cah'lina, +Had a very capricious vagina: + To the shock of the fucker + "Twould suddenly pucker, +And whistle the chorus of "Dinah." +%% +There was a young girl of Cape Cod +Who dreamt she'd been buggered by God. + But it wasn't Jehovah + That turned the girl over, +'Twas Roger the lodger, the dirty old codger, + the bugger, the bastard, the sod! +%% +There was a young girl of Darjeeling +Who could dance with such exquisite feeling + There was never a sound + For miles around +Save of fly-buttons hitting the ceiling. +%% +There was a young girl of Des Moines +Whose cunt could be fitted with coins, + Till a guy from Hoboken + Went and dropped in a token, +And now she rides free on the ferry. +%% +There was a young girl of East Lynne +Whose mother, to save her from sin, + Had filled up her crack, + To the brim with shellac, +But the boys picked it out with a pin. +%% +There was a young girl of Gibraltar +Who was raped as she knelt at the altar. + It really seems odd + That a virtuous God +Should answer her prayers and assault her. +%% +There was a young girl of Mobile, +Who hymen was made of chilled steel, + To give her a thrill, + Took a rotary drill, +Or a number nine emery wheel. +%% +There was a young girl of Moline +Whose fucking was sweet and obscene. + She would work on a prick + With every known trick, +And finish by winking it clean. +%% +There was a young girl of Newcastle +Whose charms were declared universal. + While one man in front + Wired into her cunt, +Another was engaged at her arsehole. +%% +There was a young girl of Pawtucket +Whose box was as big as a bucket. + Her boy-friend said, "Toots, + I'll have to wear boots, +For I see I must muck it, not fuck it." +%% +There was a young girl of Penzance +Who boarded a bus in a trance. + The passengers fucked her, + Likewise the conductor, +While the driver shot off in his pants. +%% +There was a young girl of Pitlochry +Who was had by a man in a rockery. + She said, "Oh! You've come + All over my bum; +This isn't a fuck -- it's a mockery." +%% +There was a young girl of Rangoon +Who was blocked by the Man in the Moon. + "Well, it has been great fun," + She remarked when he'd done, +"But I'm sorry you came quite so soon." +%% +There was a young girl of Spitzbergen, +Whose people all thought her a virgin, + Till they found her in bed + With her twat very red, +And the head of a kid just emergin'. +%% +There was a young girl, very sweet, +Who thought sailors' meat quite a treat. + When she sat on their lap + She unbuttoned their flap, +And always had plenty to eat. +%% +There was a young girl who begat +Three brats, by name Nat, Pat, and Tat. + It was fun in the breeding, + But hell in the feeding, +When she found there was no tit for Tat. +%% +There was a young hayseed from Tiffan +Whose cock would constantly stiffen. + The knob out in front + Attracted foul cunt +Which he greatly delighted in sniffin'. +%% +There was a young idler named Blood, +Made a fortune performing at stud, + With a fifteen-inch peter, + A double-beat metre, +And a load like the Biblical Flood. +%% +There was a young lad from Nahant +Who was made like the Sensitve Plant. + When asked, "Do you fuck?" + He replied, "No such luck. +I would if I could but I can't." +%% +There was a young lad from Siam, +Whose sexlife was caught in a jam. + He loved them real small, + 'Cause they're funner to ball, +So he went out and bought him a lamb! +%% +There was a young lad name of Durcan +Who was always jerkin' his gherkin. + His father said, "Durcan! + Stop jerkin' your gherkin! +Your gherkin's for ferkin', not jerkin'. +%% +There was a young lad named McFee +Who was stung in the balls by a bee + He made oodles of money + By oozing pure honey +Every time he attempted to pee. +%% +There was a young lady at sea +Who said, "God, how it hurts me to pee." + "I see," said the mate, + "That accounts for the state +Of the captain, the purser, and me." +%% +There was a young lady from Brussels +Who was proud of her vaginal muscles. + She could easily plex them + And so interflex them +As to whistle love songs through her bustles. +%% +There was a young lady from Maine +Who claimed she had men on her brain. + But you knew from the view, + As her abdomen grew, +It was not on her brain that he'd lain. +%% +There was a young lady from Munich +Who had an affair with a eunuch. + At the height of their passion + He dealt her a ration +From a squirt gun concealed in his tunic. +%% +There was a young lady from Prentice +Who had an affair with a dentist. + To make things easier + He used anesthesia, +And diddled her, `non compos mentis'. +%% +There was a young lady from Rheims +Who amazingly pissed in four streams. + A friend poked around + And a fly-button found +Lodged tight in her hole so it seems. +%% +There was a young lady from Spain +Whose face was exceedingly plain, + But her cunt had a pucker + That made the men fuck her, +Again, and again, and again. +%% +There was a young lady from Wooster +Who complained that too many men gooster. + So she traded her scanties + For sandpaper panties, +Now they goose her much less than they used 'ter. +%% +There was a young lady in Reno, +Who lost all her dough playing Keno. + But she lay on her back, + And opened her crack, +So now she owns the Casino! +%% +There was a young lady named Astor +Who never let any get past her. + She finally got plenty + By stopping twenty, +Which certainly ought to last her. +%% +There was a young lady named Banker, +Who slept while the ship lay at anchor, + She woke in dismay, + When she heard the mate say, +"Now hoist up the topsheet and spanker." +%% +There was a young lady named Blount +Who had a rectangular cunt. + She learned for diversion + Posterior perversion, +Since no one could fit here in front. +%% +There was a young lady named Brent +With a cunt of enormous extent, + And so deep and so wide, + The acoustics inside +Were so good you could hear when you spent. +%% +There was a young lady named Cager +Who, as the result of a wager, + Consented to fart + The entire oboe part +Of Mozart's quartet in F major. +%% +There was a young lady named Clair +Who possessed a magnificent pair; + At least so I thought + Till I saw one get caught +On a thorn, and begin losing air. +%% +There was a young lady named Duff +With a lovely, luxuriant muff. + In his haste to get in her + One eager beginner +Lost both of his balls in the rough. +%% +There was a young lady named Etta +Who was constantly seen in a swetta. + Three reasons she had: + To keep warm wasn't bad, +But the other two reasons were betta. +%% +There was a young lady named Flo +Whose lover had pulled out too slow. + So they tried it all night, + Till he got it just right... +Well, practice makes pregnant, you know. +%% +There was a young lady named Flynn +Who thought fornication a sin, + But when she was tight + It seemed quite all right, +So everyone filled her with gin. +%% +There was a young lady named Gilda +Who went on a date with a builder. + He said that he would, + And he could and he should, +And he did and it damn well near killed her. +%% +There was a young lady named Gloria +Who was had by Sir Gerald Du Maurier, + And then by six men, + Sir Gerald again, +And the band at the Waldorf-Astoria. +%% +There was a young lady named Gloria, +Whose boyfriend said, "May I explore ya?" + She replied to the chap, + "I'll draw you a map, +Of where others have been to before ya." +%% +There was a young lady named Hall, +Wore a newspaper dress to a ball. + The dress caught on fire + And burned her entire +Front page, sporting section, and all. +%% +There was a young lady named Hatch +Who would always come through in a scratch. + If a guy wouldn't neck her, + She'd grab up his pecker +And shove the damn thing up her snatch. +%% +There was a young lady named Mable +Who liked to sprawl out on the table, + Then cry to her man, + "Stuff in all you can -- +Get your ballocks in, too, if you're able." +%% +There was a young lady named Mandel +Who caused quite a neighborhood scandal + By coming out bare + On the main village square +And frigging herself with a candle. +%% +There was a young lady named Maud, +A terrible society fraud: + In company, I'm told, + She was distant and cold, +But if you got her alone, Oh God! +%% +There was a young lady named May +Who strolled in a park by the way, + And she met a youg man + Who fucked her and ran -- +Now she goes to the park every day. +%% +There was a young lady named Nance +Who learned about fucking in France, + And when you'd insert it + She'd squeeze till she hurt it, +And shoved it right back in your pants. +%% +There was a young lady named Nelly +Whose tits would jiggle like jelly. + They could tickle her twat + Or be tied in a knot, +And could even swat flies on her belly. +%% +There was a young lady named Ransom +Who was rogered three times in a hansom. + When she cried out for more + A voice from the floor +Replied, "My name is Simpson, not Samson." +%% +There was a young lady named Riddle +Who had an untouchable middle. + She had many friends + Because of her ends, +Since it isn't the middle you diddle. +%% +There was a young lady named Schneider +Who often kept trysts with a spider. + She found a strange bliss, + In the hiss of her piss, +As it strained through the cobwebs inside her. +%% +There was a young lady named Smith +Whose virtue was largely a myth. + She said, "Try as I can + I can't find a man +Who it's fun to be virtuous with." +%% +There was a young lady named Twiss +Who said she thought fucking a bliss, + For it tickled her bum + And caused her to come +.siht ekil gniyl ylbatrofmoc elihW +%% +There was a young lady named Wylde +Who kept herself quite undefiled + By thinking of Jesus; + Contagious diseases; +And the bother of having a child. +%% +There was a young lady of Arden, +The tool of whose swain wouldn't harden. + Said she with a frown, + "I've been sadly let down +By the tool of a fool in a garden." +%% +There was a young lady of Bicester +Who was nicer by far than her sister: + The sister would giggle + And wiggle and jiggle, +But this one would come if you kissed her. +%% +There was a young lady of Bude +Who walked down the street in the nude. + A bobby said, "Whattum + Magnificent bottom!" +And slapped it as hard as he could. +%% +There was a young lady of Dee +Who went down to the river to pee. + A man in a punt + Put his hand on her cunt, +And God! how I wish it were me. +%% +There was a young lady of Dexter +Whose husband exceedingly vexed her, + For whenever they'd start + He'd unfailingly fart +With a blast that damn nearly unsexed her. +%% +There was a young lady of Dover +Whose passion was such that it drove her + To cry, when you came, + "Oh dear! What a shame! +Well, now we shall have to start over." +%% +There was a young lady of Ealing +And her lover before her was kneeling. + Said she, "Dearest Jim, + Take your hands off my quim; +I much prefer fucking to feeling." +%% +There was a young lady of Gaza +Who shaved her cunt bare with a razor. + The crabs, in a lump, + Made tracks to her rump - +This passing parade did amaze her. +%% +There was a young lady of Gaza +Who shaved her cunt bare with a razor. + The crabs, in a lump, + Made tracks to her rump-- +This passing parade did amaze her. +%% +There was a young lady of Gloucester, +Met a passionate fellow who tossed her. + She wasn't much hurt, + But he dirtied her skirt, +So think of the anguish it cost her. +%% +There was a young lady of Gloucester +Whose friends they thought they had lost her + Till they found on the grass + The marks of her arse, +And the knees of the man who had crossed her. +%% +There was a young lady of Kent, +Who admitted she knew what it meant + When men asked her to dine, + And plied her with wine, +She knew, oh she knew -- but she went! +%% +There was a young lady of Lee +Who scrambled up into a tree, + When she got there + Her arsehole was bare, +And so was her C U N T. +%% +There was a young lady of Lincoln +Who said that her cunt was a pink'un, + So she had a prick lent her + Which turned it magenta, +This artful old lady of Lincoln. +%% +There was a young lady of Norway +Who hung by her toes in a doorway. + She said to her beau + "Just look at me Joe +I think I've discovered one more way." +%% +There was a young lady of Rhyll +In an omnibus was taken ill, + So she called the conductor, + Who got in and fucked her, +Which did more good than a pill. +%% +There was a young lady of Spain +Who took down her pants on a train. + There was a young porter + Saw more than he orter, +And asked her to do it again. +%% +There was a young lady of Spain +Who was fucked by a monk in a drain. + They did it again + And again and again, +And again and again and again. +%% +There was a young lady of Twickenham +Who thought men had not enough prick in 'em. + On her knees every day + To God she would pray +To lengthen and strengthen and thicken 'em. +%% +There was a young lady of Wheeling +Said to her beau, "I've a feeling + My little brown jug + Has need of a plug" -- +And straightaway she started to peeling. +%% +There was a young lady of Wheeling +Who professed to lack sexual feeling. + But a cynic named Boris + Just touched her clitoris, +And she had to be scraped off the ceiling. +%% +There was a young lady of fashion +Who had oodles and oodles of passion. + To her lover she said, + As they climbed into bed, +"Here's one thing the bastards can't ration!" +%% +There was a young lady who said, +As her bridegroom got into the bed, + "I'm tired of this stunt, + That they do with one's cunt, +You can get up my bottom instead." +%% +There was a young lady whose cunt +Could accomodate a small punt. + Her mother said, "Annie, + It matches your fanny, +Which never was that of a runt." +%% +There was a young lady whose thighs, +When spread showed a slit of such size, + And so deep and so wide, + You could play cards inside, +Much to her bridegroom's surprise. +%% +There was a young laundress named Wrangle +Whose tits tilted up at an angle. + "They may tickle my chin," + She said with a grin, +"But at least they keep out of the mangle." +%% +There was a young maiden from Osset +Whose quim was nine inches across it. + Said a young man named Tong, + With tool nine inches long, +"I'll put bugger-in if I loss it." +%% +There was a young man from Bel-Aire +Who was screwing his girl on the stair, + But the banister broke + So he doubled his stroke +And finished her off in mid-air. +%% +There was a young man from Calcutta +Who was heard in his beard to mutter, + "If her Bartholin glands + Don't respond to my hands, +I'm afraid I shall have to use butter." +%% +There was a young man from Dallas +Who had an exceptional phallus. + He couldn't find room + In any girl's womb +Without rubbing it first with Vitalis. +%% +There was a young man from East Wubley +Whose cock was bifurcated doubly. + Each quadruplicate shaft + Had two balls hanging aft, +And the general effect was quite lovely. + +There was a young man from Hong Kong +Who had a trifurcated prong: + A small one for sucking, + A large one for fucking, +And a `boney' for beating a gong. +%% +There was a young man from Glengozzle +Who found a remarkable fossil. + He knew by the bend + And the wart on the end, +'Twas the peter of Paul the Apostle. +%% +There was a young man from Jodhpur +Who found he could easily cure + His dread diabetes + By eating a foetus +Served up in a sauce of manure. +%% +There was a young man from Kent +Whose tool was so long that it bent. + To save himself trouble + He put it in double +And instead of coming, he went. +%% +There was a young man from Lynn +Whose cock was the size of a pin. + Said his girl with a laugh + As she felt his staff, +"This won't be much of a sin." +%% +There was a young man from Maine +Whose prick was as strong as a crane; + It was almost as long, + So he strolled with his dong +Extended in sunshine and rain. +%% +There was a young man from Nantucket +Whose prick was so long he could suck it. + He said with a grin, + As he wiped off his chin, +If my ear were a cunt I could fuck it! +%% +There was a young man from New Haven +Who had an affair with a raven. + He said with a grin + As he wiped off his chin, +"Nevermore!" +%% +There was a young man from Peru, +Who took a long trip by canoe. + While staring at Venus, + And rubbing his penis, +He wound up with a handful of goo. +%% +There was a young man from Purdue +Who was only just learning to screw, + But he hadn't the knack, + And he got too far back -- +In the right church, but in the wrong pew. +%% +There was a young man from Rangoon +Who used to lament 'neath the moon + That he had the luck + To be born of a fuck +That was scraped off the sheets with a spoon. +%% +There was a young man from Salinas +Who had an extremely long penis: + Believe it or not, + When he lay on his cot +It reached from Marin to Martinez. +%% +There was a young man from Seattle +Whose testicles tended to rattle. + He said as he fuck-ed + Some stones in a bucket, +"If Stravinsky won't deafen you -- that'll." +%% +There was a young man from Siam +Who said, "I go in with a wham, + But I soon lose my starch + Like the mad month of March, +And the lion comes out like a lamb." +%% +There was a young man from Stamboul +Who boasted so torrid a tool + That each female crater + Explored by this satyr +Seemed almost unpleasantly cool. +%% +There was a young man in Madrid +Who got fifty-five fucks for a quid. + When they said, "Are you faint?" + He replied, "No I ain't, +But I don't feel as good as I did. +%% +There was a young man in Norway, +Tried to jerk himself off in a sleigh, + But the air was so frigid + It froze his cock rigid, +And all he could come was frappe. +%% +There was a young man in the choir +Whose penis rose higher and higher, + Till it reached such a height + It was quite out of sight -- +But of course you know I'm a liar. +%% +There was a young man, name of Saul, +Who was able to bounce either ball, + He could stretch them and snap them, + And juggle and clap them, +Which earned him the plaudits of all. +%% +There was a young man named Crockett +Whose balls got caught in a socket. + His wife was a bitch, + Yeah, she threw the switch, +And Crockett went off like a rocket. +%% +There was a young man named Hughes +Who swore off all kinds of booze. + He said, "When I'm muddled + My senses get fuddled, +And I pass up too many screws." +%% +There was a young man named Knute +Who had warts all over his root. + He put acid on these + And now when he pees, +He fingers the thing like a flute. +%% +There was a young man named McNamiter +With a tool of prodigious diameter. + But it wasn't the size + Gave the girls a surprise, +But his rythm -- iambic pentameter. +%% +There was a young man named Zerubbabel +Who had only one real, and one rubber ball. + When they asked if his pleasure + Was only half measure, +He replied, "That is highly improbable." +%% +There was a young man named Zerubbabub +Who belonged to the Block, Fuck & Bugger Club + But the pride of his life + Were the tits of his wife -- +One real, and one India-rubber bub. +%% +There was a young man of Arras +Who stretched himself out on the grass, + And with no little trouble, + He bent himself double, +And stuck his prick well up his ass. +%% +There was a young man of Australia +Who went on a wild bacchanalia. + He buggered a frog, + Two mice and a dog, +And a bishop in fullest regalia. +%% +There was a young man of Bengal +Who swore he had only one ball, + But two little bitches + Unbuttoned his britches, +And found he had no balls at all. +%% +There was a young man of Bombay +Who buggered his dad once a day. + He said, "I like, rather, + Fucking my father -- +He's clean, and there's nothing to pay." +%% +There was a young man of Calcutta, +Who tried to write "cunt" on a shutter. + When he got to c-u, + A pious Hindoo +Knocked him ass-over-head in the gutter. +%% +There was a young man of Cape Horn +Who wished he had never been born, + And he wouldn't have been + If his father had seen +That the end of the rubber was torn. +%% +There was a young man of Coblenz +Whose ballocks were simply immense: + It took forty-four draymen, + A priest and three laymen +To carry them thither and thence. +%% +There was a young man of Darjeeling +Whose cock reached up to the ceiling. + In the electric light socket, + He'd put it and rock it-- +Oh God! What a wonderful feeling! +%% +There was a young man of Devizes +Whose balls were of different sizes. + His tool when at ease, + Hung down to his knees, +Oh, what must it be when it rises! +%% +There was a young man of Dumfries +Who said to his girl, "If you please, + It would give me great bliss + If, while playing with this, +You would pay some attention to these!" +%% +There was a young man of Greenwich +Whose balls were all covered with spinach. + So long was his tool + That it wound round a spool, +And he let it out inach by inach. +%% +There was a young man of Khartoum +Who lured a poor girl to her doom. + He not only fucked her, + But buggered and sucked her-- +And left her to pay for the room. +%% +There was a young man of Kildare +Who was fucking a girl on the stair. + The bannister broke, + But he doubled his stroke +And finished her off in mid-air. +%% +There was a young man of Kutki +Who could blink himself off with one eye. + For a while though, he pined, + When his organ declined +To function, because of a stye. +%% +There was a young man of Lahore +Whose prick was one inch and no more. + It was all right for key-holes + And little girl's pee-holes, +But not worth a damn with a whore. +%% +There was a young man of Lake Placid +Whose prick was lethargic and flaccid. + When he wanted to sport + He would have to resort +To injections of sulphuric acid. +%% +There was a young man of Madras +Whose balls were constructed of brass. + When jangled together + They played "Stormy Weather", +And lightning shot out of his ass. +%% +There was a young man of Missouri +Who fucked with a terrible fury. + Till hauled into court + For his beastial sport, +And condemned by a poorly-hung jury. +%% +There was a young man of Natal +And Sue was the name of his gal. + One day, north of Aden, + He got his hard rod in, +And came clear up Suez Canal. +%% +There was a young man of Natal +Who was fucking a Hottentot gal. + Said she, "You're a sluggard!" + Said he, "You be buggered! +I like to fuck slow and I shall." +%% +There was a young man of Ostend +Who let a girl play with his end. + She took hold of Rover, + And felt it all over, +And it did what she didn't intend. +%% +There was a young man of Ostend +Whose wife caught him fucking her friend. + "It's no use, my duck, + Interrupting our fuck, +For I'm damned if I draw till I spend." +%% +There was a young man of Seattle +Who bested a bull in a battle. + With fire and gumption + He assumed the bull's function, +And deflowered a whole herd of cattle. +%% +There was a young man of St. John's +Who wanted to bugger the swans. + But the loyal hall porter + Said, "Pray take my daughter! +Those birds are reserved for the dons." +%% +There was a young man of Tibet +-- And this is the strangest one yet -- + His prick was so long, + And so pointed and strong, +He could bugger six sheep en brochette. +%% +There was a young man of Toulouse +Who had a deficient prepuce, + But the foreskin he lacked + He made up in his sac; +The result was, his balls were too loose. +%% +There was a young man of high station +Who was found by a pious relation + Making love in a ditch + To -- I won't say a bitch -- +But a woman of no reputation. +%% +There was a young man with one foot +Who had a very long root. + If he used this peg + As an extra leg +Is a question exceedingly moot. +%% +There was a young miss from Johore +Who'd lie on a mat on the floor; + In a manner uncanny + She'd wobble her fanny, +And drain your nuts dry to the core. +%% +There was a young monk in Siberia, +Whose morals were very inferior, + He jumped on a nun + Which he shouldn't have done, +And now she's a Mother Superior. +%% +There was a young of Warwick +Who had reason for feeling euphoric, + For he could by election + Have triune erection: +Ionic, Corinthian, and Doric. +%% +There was a young parson of Harwich, +Tried to grind his betrothed in a carriage. + She said, "No, you young goose, + Just try self-abuse. +And the other we'll try after marriage." +%% +There was a young peasant named Gorse +Who fell madly in love with his horse. + Said his wife, "You rapscallion, + That horse is a stallion -- +This constitutes grounds for divorce." +%% +There was a young person of Kent +Who was famous wherever he went. + All the way through a fuck, + He would quack like a duck, +And he crowed like a cock when he spent. +%% +There was a young sailor from Brighton, +Who remarked to his girl, "You're a tight one." + She replied, "'Pon my soul, + You're in the wrong hole; +There's plenty of room in the right one." +%% +There was a young sapphic named Anna +Who stuffed her friend's cunt with banana, + Which she sucked, bit by bit, + From her partner's warm slit, +In the most approved lesbian manner. +%% +There was a young soldier from Munich +Whose penis hung down past his tunic, + And their chops girls would lick + When they thought of his prick, +But alas! he was only a eunuch. +%% +There was a young squaw of Wohunt +Who possessed a collapsible cunt. + It had many odd uses, + Produced no papooses, +And fitted both giant and runt. +%% +There was a young student from Yale +Who was getting his first piece of tail. + He shoved in his pole, + But in the wrong hole, +And a voice from beneath yelled: "No sale!" +%% +There was a young trollop at Yale, +Who had verses tattooed on her tail, + And on her behind, + For the sake of the blind, +A duplicate version in Braille. +%% +There was a young whore from Kaloo +Who filled her vagina with glue. + She said with a grin, + "If they pay to get in, +They can pay to get out again too!" +%% +There was a young woman in Dee +Who stayed with each man she did see. + When it came to a test + She wished to be best, +And practice makes perfect, you see. +%% +There was a young woman named Alice +Who peed in a Catholic chalice. + She said, "I do this + From a great need to piss, +And not from sectarian malice." +%% +There was a young woman named Brent +With a cunt of enormous extent, + And so deep and so wide, + The acoustics inside +Were so good you could hear when you spent. +%% +There was a young woman named Florence +Who for fucking professed an abhorrence, + But they found her in bed + With her cunt flaming red, +And her poodle-dog spending in torrents. +%% +There was a young woman named Sutton +Who said, as she carved up the mutton, + "My father preferred + The last sheep in the herd -- +This is one of his children I'm cuttin'." +%% +There was a young woman of Cheadle, +Who once gave the clap to a beadle. + Said she, "Does it itch?" + "It does, you damned bitch, +And it burns like hell-fire when I peedle." +%% +There was an Old Man of the Mountain +Who frigged himself into a fountain + Fifteen times had he spent, + Still he wasn't content, +He simply got tired of the counting. +%% +There was an old Count of Swoboda +Who would not pay a whore what he owed her. + So with great savoir-faire + She stood on a chair, +And pissed in his whiskey-and-soda. +%% +There was an old abbess quite shocked +To find nuns where the candles were locked. + Said the abbess, "You nuns + Should behave more like guns, +And never go off till you're cocked." +%% +There was an old curate of Hestion +Who'd errect at the slightest suggestion. + But so small was his tool + He could scarce screw a spool, +And a cunt was quite out of the question. +%% +There was an old fellow named Skinner +Whose prick, his wife said, had grown thinner. + But still, by and large, + It would always discharge +Once he could just get it in her. +%% +There was an old gent from Kentuck +Who boasted a filigreed schmuck, + But he put it away + For fear that one day +He might put it in and get stuck. +%% +There was an old girl of Kilkenny +Whose usual charge was a penny. + For half of that sum + You could finger her bum-- +A source of amusement to many. +%% +There was an old lady of Kewry +Whose cunt was a `lusus naturae': + The `introitus vaginae', + Was unnaturally tiny, +And the thought of it filled her with fury. +%% +There was an old lady who lay +With her legs wide apart in the hay, + Then, calling the ploughman, + She said, "Do it now, man! +Don't wait till your hair has turned gray." +%% +There was an old man from Bengal +Who liked to do tricks in the hall. + His favorite trick + Was to stand on his dick +While he rolled around on one ball. +%% +There was an old man of Brienz +The length of whose cock was immense: + With one swerve he could plug + A boy's bottom in Zug, +And a kitchen-maid's cunt in Coblenz. +%% +There was an old man of Cajon +Who never could get a good bone. + With the aid of a gland + It grew simply grand; +Now his wife cannot leave it alone. +%% +There was an old man of Duddee +Who came home as drunk as could be. + He wound up the clock + With the end of his cock, +And buggered his wife with the key. +%% +There was an old man of Duluth +Whose cock was shot off in his youth. + He fucked with his nose + And with fingers and toes, +And he came through a hole in his tooth. +%% +There was an old man of Hong Kong +Who never did anything wrong. + He would lie on his back + With his head in a sack +And secretly finger his dong. +%% +There was an old man of Tagore +Whose tool was a yard long or more, + So he wore the damn thing + In a surgical sling +To keep it from wiping the floor. +%% +There was an old man of the port +Whose prick was remarkably short. + When he got into bed, + The old woman said, +"This isn't a prick; it's a wart!" +%% +There was an old man who said, "Tush! +My balls always hang in the brush, + And I fumble about, + Half in and half out, +With a pecker as limber as mush." +%% +There was an old pirate named Bates +Who was learning to rhumba on skates. + He fell on his cutlass + Which rendered him nutless +And practically useless on dates. +%% +There was an old satyr named Mack +Whose prick had a left handed tack. + If the ladies he loves + Don't spin when he shoves, +Their cervixes frequently crack. +%% +There was an old woman of Ghent +Who swore that her cunt had no scent. + She got fucked so often + At last she got rotten, +And didn't she stink when she spent. +%% +There was once a mechanic named Bench +Whose best tool was a sturdy gut-wrench. + With this vibrant device + He could reach, in a trice, +The innermost parts of a wench. +%% +There was once a sad Maitre d'hotel +Who said, "They can all go to hell! + What they do to my wife-- + Why it ruins my life; +And the worst is, they all do it well. +%% +There were three ladies of Huxham, +And whenever we meets 'em we fucks 'em, + And when that game grows stale + We sits on a rail, +And pulls out our pricks and they sucks 'em. +%% +There's a charming young girl in Tobruk +Who refers to her quiff as a nook. + It's deep and it's wide, + -- You can curl up inside +With a nice easy chair and a book. +%% +There's a charming young lady named Beaulieu +Who's often been screwed by yours truly, + But now--it's appallin'-- + My balls always fall in! +I fear that I've fucked her unduly. +%% +There's a dowager near Sweden Landing +Whose manners are odd and demanding. + It's one of her jests + To suck off her guests -- +She hates to keep gentlemen standing. +%% +There's a lovely young lady named Shittlecock +Who loves to play diddle and fiddle-cock, + But her cunt's got a pucker + That's best not to fuck, or +When least you expect it to, it'll lock. +%% +There's a sports-minded coed named Sue, +Who's been coxing the varsity crew. + In the shell Sue is great, + But her boyfriend's irate, +When she calls out the stroke as they screw. +%% +There's a tavern in London that's staffed, +By a barmaid who's tops at her craft: + In her striving to please, + She serves ale on her knees, +So the patrons get head with their draft. +%% +There's a vicar who's classed as nefarious, +Since his shocking perversions are various... + He will bugger some lad + With a dildo (the cad!) +While exulting, "My pleasure's vicarious!" +%% +There's a young Yiddish slut with two cunts, +Whose pleasure in life is to pruntz. + When one pireg is shot, + There's that alternate twat, +But the ausgefuckt male merely grunts. +%% +There's an over-sexed lady named Whyte +Who insists on a dozen a night. + A fellow named Cheddar + Had the brashness to wed her-- +His chance for survival is slight. +%% +There's an unbroken babe from Toronto, +Exceedingly hard to get onto, + But when you get there, + And have parted the hair, +You can fuck her as much as you want to. +%% +Though the invalid Saint of Brac +Lay all of his life on his back, + His wife got her share, + And the pilgrims now stare +At the scene, in his shrine, on a plaque. +%% +To bear offspring, Noah's snakes were unable. +Their fertility was somewhat unstable. + He constructed a bed + Out of tree trunks and said, +"Even adders can multiply on a log table." +%% +To his bride a young bridegroom said, "Pish! +Your cunt is as big as a dish!" + She replied, "Why, you fool, + With your limp little tool +It's like driving a nail with a fish!" +%% +To his bride said the keen-eyed detective, +"Can it be that my eyesight's defective? + Has the east tit the least bit + The best of the west tit, +Or is it the faulty perspective?" +%% +Two roosters in one of our pens +Found their pricks were no larger than wens. + As they looked at their foreskins + And wished they had more skins, +They discovered they'd both become hens. +%% +Under the spreading chestnut tree +The village smith he sat, + Amusing himself + By abusing himself +And catching the load in his hat. +%% +Une joile epousetta a Tours +Voulait de gig-gig tous le jours. + Mais le mari disait, "Non! + De trop n'est pas bon! +Mon derriere exige du secours!" +%% +Visas erat: huic geminarum +Dispar modus testicularum: + Minor haec nihili, + Palma triplici, +Jam fecerat altera clarum. +%% +"Well, I took your advice, Doc", said Knopp, +"And told my wife to try it on top. + She bounced for an hour, + Till she ran out of power, +And the kids, who'd grown bored, made us stop." +%% +Well buggered was a boy named Delpasse +By all of the lads in his class + He said, with a yawn, + "Now the novelty's gone +And it's only a pain in the ass." +%% +"Well, madam," the bishop declared, +While the vicar just mumbled and stared, + "'Twere better, perhaps, + In the crypt or the apse, +Because sex in the nave must be shared." +%% +When I was a baby, my penis +Was as white as the buttocks of Venus. + But now 'this as red + As her nipples instead-- +All because of the feminie genus! +%% +When he tried to inject his huge whanger +A young man aroused his girl's anger. + As they strove in the dark + She was heard to remark, +"What you need is a zeppelin hanger." +%% +When they asked a pert baggage name Alice, +Who'd been bedded and banged in the palace, + "Was he modest or vain?" + "Was he regal or plain?" +She replied, "He's a jolly good phallus!" +%% +While I, with my usual enthusiasm, +Was exploring in Ermintrude's busiasm, + She explained, "They are flat, + But think nothing of that -- +You will find that my sweet sister Susiasm." +%% +While Titian was mixing rose madder, +His model reclined on a ladder. + Her position to Titian + Suggested coition, +So he leapt up the ladder and had 'er. +%% +While out on a date in his Fiat, +The man exclaimed "Where's my key at?" + As he bent down to seek, + She let out a shriek: +"That's not where it's likely to be at." +%% +While spending the winter at Pau +Lady Pamela forgot to say "No." + So the head-porter made her + And the second-cook laid her; +The waiters were all hanging low. +%% +Winter is here with his grouch, +The time when you sneeze and you slouch. + You can't take your women + Canoein' or swimmin', +But a lot can be done on a couch. +%% +There once was a reverend at Kings +Whose mind 'twas on heavenly things. + But his heart was on fire + For a boy in the choir +Whose buns were like jelly on springs. +%% +Floating idly one day through the air, +A circus performer named Blair, + Tied a sizeable rock, + To the end of his cock, +And shattered a balcony chair. +%% +"For the tenth time, dull Daphnis," said Chloe, +"You have told me my bosom is snowy; + You have made much fine verse on + Each part of my person, +Now do something -- there's a good boy!" +%% +There were three young ladies of Birmingham, +And this is the scandal concerning 'em. + They lifted the frock + And tickled the cock +Of the Bishop engaged in confirming 'em. + +Now, the Bishop was nobody's fool, +He'd been to a good public school, + So he took down their britches + And buggered those bitches +With his ten-inch episcopal tool. + +Then up spoke a lady from Kew, +And said, as the Bishop withdrew, + "The vicar is quicker + And thicker and slicker, +And longer and stronger than you." + -- Abuses of the Clergy +%% +Said the nun as the bishop withdrew, +"This must be our final adieu, + For the vicar is slicker, + And thicker, and quicker, +And two inches longer than you." +%% +There was an old Scot named McTavish +Who attempted an anthropoid ravish. + The object of rape + Was the wrong sex of ape, +And the anthropoid ravished McTavish. +%% +I once met a lassie named Ruth +In a long distance telephone booth. + Now I know the perfection + Of an ideal connection +Even if somewhat uncouth. +%% + The big problem with pornography is defining it. You can't just +say it's pictures of people naked. For example, you have these +primitive African tribes that exist by chasing the wildebeest on foot, +and they have to go around largely naked, because, as the old tribal +saying goes: "N'wam k'honi soit qui mali," which means, "If you think +you can catch a wildebeest in this climate and wear clothes at the same +time, then I have some beach front property in the desert region of +Northern Mali that you may be interested in." + So it's not considered pornographic when National Geographic +publishes color photographs of these people hunting the wildebeest +naked, or pounding one rock onto another rock for some primitive reason +naked, or whatever. But if National Geographic were to publish an +article entitled "The Girls of the California Junior College System +Hunt the Wildebeest Naked," some people would call it pornography. But +others would not. And still others, such as the Spectacularly Rev. +Jerry Falwell, would get upset about seeing the wildebeest naked. + -- Dave Barry, "Pornography" +%% + ... So this is a very confusing situation, and what makes +it even worse is, our standards keep changing. Take Playboy magazine. +Back in the 1950s, when I started reading it strictly for the articles, +Playboy was considered just about the raciest thing around, even though +all it ever showed was women's breasts. Granted, any given one of +these breasts would have provided adequate shelter for a family of +four, but the overall effect was no more explicit than many +publications we think nothing of today, such as Sports Illustrated's +Annual Nipples Poking Through Swimsuits Issue. + -- Dave Barry, "Pornography" +%% +They [District Attorneys] learn in District Attorney School that there +are two sure-fire ways to get a lot of favorable publicity: + +(1) Go down and raid all the lockers in the local high school and + confiscate 53 marijuana cigarettes and put them in a pile and hold + a press conference where you announce that they have a street value + of $850 million. These raids never fail, because ALL high schools, + including brand-new, never-used ones, have at least 53 marijuana + cigarettes in the lockers. As far as anyone can tell, the locker + factory puts them there. +(2) Raid an "adult book store" and hold a press conference where you + announce you are charging the owner with 850 counts of being a + piece of human sleaze. This also never fails, because you always + get a conviction. A juror at a pornography trial is not about to + state for the record that he finds nothing obscene about a movie + where actors engage in sexual activities with live snakes and a + fire extinguisher. He is going to convict the bookstore owner, and + vote for the death penalty just to make sure nobody gets the wrong + impression. + -- Dave Barry, "Pornography" +%% + Here is the problem: for many years, the Supreme Court wrestled +with the issue of pornography, until finally Associate Justice John +Paul Stevens came up with the famous quotation about how he couldn't +define pornography, but he knew it when he saw it. So for a while, the +court's policy was to have all the suspected pornography trucked to +Justice Stevens' house, where he would look it over. "Nope, this isn't +it," he'd say. "Bring some more." This went on until one morning when +his housekeeper found him trapped in the recreation room under an +enormous mound of rubberized implements, and the court had to issue a +ruling stating that it didn't know what the hell pornography was except +that it was illegal and everybody should stop badgering the court about +it because the court was going to take a nap. + -- Dave Barry, "Pornography" +%% +What you mean, how old am I? About one hundred! But Viennese answer is +better: we say, "I keep passing the open windows." This is an old joke. +There was a street clown called King of the Mice: he trained rodents, he +did horoscopes, he could impersonate Napoleon, he could make dogs fart +on command. One night he jumped out his window with all his pets in a box. +Written on the box was this: "Life is serious, but art is fun!" I hear his +funeral was a party. A street artist had killed himself. Nobody had +supported him but now everybody missed him. Now who would make the dogs +make music and the mice pant? The bear knows this, too: it is hard work +and great art to make life not so serious. + -- John Irving "The Hotel New Hampshire" +%% +It was April the 41st, +Being a quadruple leap year. +I was driving in down-town Atlantis. +My Barracuda was in the shop, +So I was in a rented stingray + -- and it was over-heating. +So, I pulled into a Shell station. +They said I'd blown a seal. +I said "Fix the damned thing and leave my private + life out of it, okay pal?" + -- Wet Dreams +%% + A cowboy, his horse and his dog were captured by hostile Indians. +This wasn't really a problem for the animals as the Indians can always use +them, but the cowboy is informed that he will be burned at the stake the +following sunrise. That evening, the Indian chief tells the cowboy that +he can one last wish, within reason, of course, before meeting his fate +the following morning. The cowboy replies that all he really wants is to +see his faithful dog, Rex, one last time. When the dog is brought by the +Indians, the cowboy hugs his companion and whispers something into his ear. +At once the dog runs off over the hill. Amazingly enough, a few hours later, +he returns, accompanied by some two dozen prostitutes from a nearby town. +Needless to say, the braves are delighted and as a reward offer the cowboy +his dog to keep him company through the rest of the night. When the dog is +brought forth the cowboy again runs his hand over Rex's head and then bends +down to whisper into his ear: "This may be my last chance, Rex, so get it +right this time -- go into town and get the posse!" +%% +In the stands here I see a young couple who must be in love -- they're +kissing on every pitch. He's kissing her on the strikes, and she's +kissing him on the balls. + -- Harry Caray, a Chicago sportscaster +%% + And Jesus said unto them, "And whom do you say that I am?" + They replied, "You are the eschatological manifestation of the +ground of our being, the ontological foundation of the context of our +very selfhood revealed." + And Jesus replied, "What?" +%% +Persistence, like perspiration, is 99 percent of the fine art of love. +%% +Jehovah is an alien and still threatens this planet! +%% +This guy walks into a bank and up to a female bank teller: + +Man: "I want to open a fuckin' savings account." +Teller: "Excuse me, sir?" +M: "Listen, bitch, I want to open a fuckin' savings account." +T: "Sir, I don't have to listen to this abusive language." +M: "LOOK! I just want to open a fuckin' savings account." +T: "Sir, you leave me no choice but to speak to the manager." + +The teller walks over and explains the customer's rude behavior to the bank +manager who then accompanies her back to the teller booth. + +Mgr: "Can I help you, sir?" +M: "I want to open a fuckin' savings account." +Mgr: "Please, sir, we'll be delighted to help you, but we must request + that you not use abusive language to our tellers." +M: "Look. I just won $25 million in the state lottery and I want to + open a fuckin' savings account!" +Mgr: "I see. And has this cunt being giving you any trouble?" +%% +Get your bytes from our backend! + -- Britton Lee +%% +Me, I love the rich. *Somebody* has to love them. Sure, a lot +of rich people are assholes, but believe me, a lot of poor people +are assholes too. And an asshole with money can at least pay +for his own drinks. + -- Tom Robbins, "Jitterbug Perfume" +%% + The radio was screaming: "Power to the People -- Right On!" John +Lennon's political song, ten years too late. "That poor fool should have +stayed where he was," said my attorney. "Punks like him only get in the +way when they try to be serious." + "Speaking of serious," I said. "I think it's about time to get +into the ether and the cocaine." + "Forget ether," he said. "Let's save it for soaking down the rug +in the suite. But here's this. Your half of the sunshine blotter. Just +chew it up like baseball gum." + I took the blotter and ate it. My attorney was now fumbling with +the salt shaker containing the cocaine. Opening it. Spilling it. Then +screaming and grabbing at the air, as our fine white dust blew up and out +across the desert highway. A very expensive little twister rising up from +the Great Red Shark. "Oh, Jesus!" he moaned. "Did you see what God just +did to us?" + -- Raoul Duke, "Rolling Stone", issue 95, Nov. 11, 1971 +%% + The new patron was amazed by the cleanliness of the restaurant. A +waiter approached the table. "Good afternoon, sir. What may I serve you?" + "I'll have the steak dinner," the man answered. + As the waiter headed for the kitchen, the diner noticed that he +wore a spotless white apron and clean white gloves. Soon the waiter +returned, bearing a casserole dish on a cart which he uncovered to reveal +two tempting filet mignons. From a covered pocket in his apron he produced +a small pair of shining silver tongs and with them he transferred the meat +from the steaming casserole to the diner's plate. "We never touch anything +with our hands," he explained. + The waiter continued serving. "Confidentially," he said, "we even +have a special set of rules about visiting the lavatory. Do you see this +little piece of string attached to my apron?" + "Yes," the diner replied. "I noticed that all the aprons had one." + The waiter put a large browned potato on the plate with his tongs. +"Well," he began, "if I should have to go to the bathroom, that string +comes in very handily. I simply unzip my pants and take it out with that +piece of string. That way everything stays sanitary." + "But how do you put it back?" + "I don't know about the other guys," the waiter confided, "but I +use the tongs." +%% +There once was a girl from Madras +Who had such a beautiful ass - + It was not round and pink + (As you bastards think) +But had two ears, a tail, and ate grass. +%% +There once was a lawyer named Rex +With minuscule organs of sex. + Arraigned for exposure, + He maintained with composure: +"De minimis non curat lex." +%% +There once was a man from Bombay +He would do it all night and all day + He soon became sore + You shoulda' heard him roar +When his wife rubbed his balls with Ben-Gay! +%% +There once was a monk of Camyre +Who was seized with a carnal desire + And the primary cause + Was the abbess's drawers +Which were hung up to dry by the fire. +%% +There was a young girl from Peru, +Who noticed her lovers were few; + So she walked out her door + With a fig leaf, no more, +And now she's in bed - with the flu. +%% +There was a young lady from Spain +Who demurely undressed on a train. + A helpful young porter + Helped more than he orter, +And she promptly cried "Help me again!" +%% +There was a young lady named Rose +With erogenous zones in her toes. + She remained onanistic + Till a foot-fetishistic +Young man became one of her beaux. +%% +To be the kind of girl designed to be kissed between the thighs. +%% +'Twas orgy, and the hip and mod And as in raffish thought he sprawled, +Did groove and trip out at the pad: The Radcliffe girl, no idle flirt, +All whimsy were the slamming chicks, Crept past the hippies getting balled +And the Radcliffe undergrad. And doffed her miniskirt. + +"Beware the Radcliff girl, my son! One, two! One, two! And through +The looks that mell, the claws that and through + catch! The venerable staff went snicker-snack! +Beware the Byrn Mawr deb, and shun He left her bred, sans maidenhead, +The uppity Wellesleysnatch!" And went galumphing back. + +He took his venerable staff in hand: "And hast thou laid the Radcliffe girl? +Long time the cool young stuff he Come to my arms, my horny boy! + sought-- O spaced-out day! Calooh! Callay!" +So rested he among the spree He cackled in his joy. +And paused to smoke some pot. + 'Twas orgy, and the hip and mod + Did groove and trip out at the pad: + All whimsy were the slamming chicks, + And the Radcliffe undergrad. +%% +If God had meant for Texans to ski he would have made bullshit white. +%% +Rating women on the Budweiser scale; the number +of Clydesdales it would take to pull you off her. +%% +Did you know that some people your age have sex +thirty-seven times in a week? And die immediately after? +%% +War is menstruation envy. +%% +18th Rule of Friendship: + +A friend will let you hold the ladder while he goes up on the roof to +install your new aerial, which is the biggest son-of-a-bitch you ever saw. + -- Esquire, May 1977 +%% +Love comes in spurts. +%% +Women -- can't live with 'em, can't +leave 'em by the curb when you're done. +%% +Men -- can't live with 'em, can't leave +'em by the curb when you're done. +%% +Sex is low in calories, and *oooh* that aftertaste! +%% +National Sex Week -- don't let your meat loaf. +%% +Sex discriminates against the shy and ugly. +%% +Confucious say man who pull out too fast leave rubber. +%% +Lick-a-dee-clit! +%% +One of the first things schoolchildren in Texas learn is how to +compose a simple declarative sentence without the word "shit" in it. +%% + For three years, the young attorney had been taking his brief +vacations at this country inn. The last time he'd finally managed an +affair with the innkeeper's daughter. Looking forward to an exciting +few days, he dragged his suitcase up the stairs of the inn, then stopped +short. There sat his lover with an infant on her lap! + "Helen, why didn't you write when you learned you were pregnant?" +he cried. "I would have rushed up here, we could have gotten married, +and the baby would have my name!" + "Well," she said, "when my folks found out about my condition, +we sat up all night talkin' and talkin' and decided it would be better +to have a bastard in the family than a lawyer." +%% diff --git a/src/games/fortune/obscene.4.3 b/src/games/fortune/obscene.4.3 new file mode 100644 index 0000000..6c96f2b --- /dev/null +++ b/src/games/fortune/obscene.4.3 @@ -0,0 +1,1499 @@ +A bather whose clothing was strewed +By breezes that left her quite nude, + Saw a man come along + And, unless I'm quite wrong, +You expected this line to be lewd. +%% +A beat schizophrenic said, "Me? +I am not I, I'm a tree." + But another, more sane, + Shouted, "I'm a Great Dane!" +And covered his pants leg with pee. +%% +A conservative is a man who believes that nothing should be done for +the first time. + -- Alfred E. Wiggam +%% +A conservative is a man with two perfectly good legs who has never +learned to walk. + -- Franklin D. Roosevelt +%% +A friend with weed is a friend indeed. +%% +A hard man is good to find. +%% +A hard man is good to find. +%% +A man needs a mistress, just to break the monogamy. +%% +A mathematician named Hall +Has a hexahedronical ball, + And the cube of its weight + Times his pecker's, plus eight +Is his phone number -- give him a call.. +%% +"A Mormon is a man that has the bad taste and the religion to do what a +good many other people are restrained from doing by conscientious +scruples and the police." + -- Mr. Dooley +%% +A Nixon [is preferable to] a Dean Rusk -- who will be passionately +wrong with a high sense of consistency. + -- J. K. Galbraith +%% +A non-vegetarian anti-abortionist is a contradiction in terms. + --Phyllis Schlafly +%% +A nymph hits you and steals your virginity. +%% +A person who has both feet planted firmly in the air can be safely +called a liberal. +%% +A pretty young lady named Vogel +Once sat herself down on a molehill. + A curious mole + Nosed into her hole -- +Ms. Vogel's ok, but the mole's ill. +%% +A pretty young maiden from France +Decided she'd "just take a chance." + She let herself go + For an hour or so +And now all her sisters are aunts. +%% +A Puritan is someone who is deathly afraid that someone, somewhere, +is having fun. +%% +A remarkable race are the Persians; +They have such peculiar diversions. + They make love the whole day + In the usual way +And save up the nights for perversions. +%% +A team playing baseball in Dallas +Called the umpire blind out of malice. + While this worthy had fits + The team made eight hits +And a girl in the bleachers named Alice. +%% +A wanton young lady from Wimley +Reproached for not acting quite primly + Said, "Heavens above! + I know sex isn't love, +But it's such an entrancing facsimile." +%% +A wanton young lady from Wimley +Reproached for not acting quite primly + Said, "Heavens above! + I know sex isn't love, +But it's such an entrancing facsimile." +%% +A widow who fancied a man some +Was diddled three times in a hansome. + When she clamored for more + Her young man became sore +And exclaimed "My name's Simpson not Samson." +%% +"A woman is like a dresser ... some man always goin' through her +drawers." + --- Blind Lemon Pledge +%% +A worried young man from Stamboul +Founds lots of red spots on his tool. + Said the doctor, a cynic, + "Get out of my clinic; +Just wipe off the lipstick, you fool!" +%% +Achilles' Biological Findings: + (1) If a child looks like his father, that's heredity. If he + looks like a neighbor, that's environment. + (2) A lot of time has been wasted arguing over what came first + -- the chicken or the egg. It was undoubtedly the rooster. +%% +AI hackers do it with robots. +%% +Aide to Raygun: Sir, the poor are outside protesting your budget cuts. +Raygun himself: Tell them they'll have to help themselves. +Aide to Raygun: Sir, the Pentagon wants another $30 billion. +Raygun himself: Tell them to help themselves. +%% +All a hacker needs is a tight PUSHJ, a loose pair of UUOs, and a warm +place to shift. +%% +All things dull and ugly, All creatures short and squat, + All things rude and nasty, The Lord God made the lot; +Each little snake that poisons, Each little wasp that stings, + He made their brutish venom, He made their horrid wings. +All things sick and cancerous, All evil great and small, + All things foul and dangerous, The Lord God made them all. +Each nasty little hornet, Each beastly little squid. + Who made the spikey urchin? Who made the sharks? He did. +All things scabbed and ulcerous, All pox both great and small. + Putrid, foul and gangrenous, The Lord God made them all. + -- Monty Python's Flying Circus +%% +An architect fellow named Yoric +Could, when feeling euphoric, + Display for selection + Three kinds of erection -- +Corinthian, ionic, and doric. +%% +An Army travels on her stomach. +%% +An attorney was defending his client against a charge of first-degree +murder. "Your Honor, my client is accused of stuff his lover's +mutilated body into a suitcase and heading for the Mexican border. +Just north of Tijuana a cop spotted her hand sticking out of the +suitcase. Now, I would like to stress that my client is *___not* a +murderer. A sloppy packer, maybe..." +%% +"And Bezel saideth unto Sham: `Sham,' he saideth, `Thou shalt goest +unto the town of Begorrah, and there thou shalt fetcheth unto thine +bosom 35 talents, and also shalt thou fetcheth a like number of cubits, +provideth that they are nice and fresh.'" + -- Dave Barry, "Getting Religion" +%% +... And then there's the guy who bought 20,000 bras, cut them in half, +and sold 40,000 yamalchas with chin straps ... +%% +Anxiety, n.: + The first time you can't do it a second time. + +Panic, n.: + The second time you can't do it the first time. +%% +Back in the good ole days in Texas, when stagecoaches and the like was +popular, there were three people in a stagecoach one day: a true red- +blooded born-and-raised Texas gentleman, a tenderfoot city-slicker from +back East, and a beautiful and well-endowed Texas lady. The city- +slicker kept eyeing the lady, and finally he leaned forward and said, +"Lady, I'll give you $10 for a blow job." The Texas gentleman looked +appalled, pulled out his pistol, and killed the city-slicker on the +spot. The lady gasped and said, "Thank you, suh, for defendin' mah +honor!" Whereupon the Texan holstered his gun and said, "Your honor, +hell!! No tenderfoot is gonna raise the price of women in Texas!!" +%% +Baltimore, n.: + Where the women wear turtleneck sweaters to hide their flea +collars. +%% +Bankers do it with interest (penalty for early withdrawal). +%% +Behold the unborn fetus and + Weep salt tears crocodilian; +All life is sacred (save, of course, + An enemy civilian). +%% +Being stoned on marijuana isn't very different from being stoned on +gin. + -- Ralph Nader +%% +Beneath this stone a virgin lies, +For her life held no terrors. +A virgin born, a virgin died: +No hits, no runs, no errors. +%% +Blessed are the meek for they shall inhibit the earth. +%% +Build a better mousetrap, the saying goes -- and with the brassiere, +Yankee Ingenuity did exactly that. But their true stroke of genius was +the new bait. The old fashioned mousetrap was loaded with cheese; +nobody cares much about cheese, except mice. But when American +Know-How reloaded the brassiere with tits, every heterosexual male in +the country was hopelessly trapped. + -- Alan Sherman, "The Rape of the A*P*E*" +%% + ... But the reward of a successful collaboration is a +thing that cannot be produced by either of the parties working alone. +It is akin to the benefits of sex with a partner, as opposed to +masturbation. The latter is fun, but you show me anyone who has gotten +a baby from playing with him or herself, and I'll show you an ugly +baby, with just a whole bunch of knuckles. + -- Harlan Ellison +%% +Captain Hook died of jock itch. +%% +Chaste makes waste. +%% +Chipmunks roasting on an open fire +Jack Frost ripping up your nose +Yuletide carolers being thrown in the fire +And folks dressed up like buffaloes +Everybody knows a turkey slaughtered in the snow +Helps to make the season right +Tiny tots with their eyes all gouged out +Will find it hard to see tonight +They know that Santa's on his way +He's loaded lots of guns and bullets on his sleigh +And every mother's child is sure to spy +To see if reindeer really scream when they die +And so I'm offering this simple phrase +To kids from one to ninety two +Although it's been said many times, many ways +Merry Christmas, Merry Christmas, Merry Christmas, Fuck you!! +%% +Christian, n.: + One who believes that the New Testament is a divinely inspired +book admirably suited to the spiritual needs of his neighbor. One who +follows the teachings of Christ in so far as they are not inconsistent +with a life of sin. +%% +Clarke's Third Law: + Any sufficiently advanced technology is indistinguishable from + magic. + +G's Third Law: + In spite of all evidence to the contrary, the entire universe + is composed of only two basic substances: magic and bullshit. + +H's Dictum: + There is no magic ... +%% +CLONE OF MY OWN (to Home on the Range) + +Oh, give me a clone +Of my own flesh and bone + With the Y chromosome changed to X. +And when she is grown, +My very own clone, + We'll be of the opposite sex. + +Chorus: + Clone, clone of my own, + With the Y chromosome changed to X. + And when we're alone, + Since her mind is my own, + She'll be thinking of nothing but sex. + -- Randall Garrett +%% +Cocaine is nature's way of telling you you have too much money. +%% +Coito ergo sum +%% +College is like a woman -- you work so hard to get in, and nine months +later you wish you'd never come. +%% +Communists do it without class. +%% +Conservative, n.: + One who admires radicals centuries after they're dead. + -- Leo C. Rosten +%% +Cunnilingus is next to godliness. +%% +Dammit, how many times do I have to tell you? ____FIRST you rape, ____THEN you +pillage!! +%% +Dear Lord, observe this bended knee +This visage meek and humble, +And hear this confidential plea +Voiced in reverent mumble: + Give me Shylock, give me Fagin + But O God spare me Ronald Reagan! + -- Ansel Adams +%% +Did you hear about the new German microwave oven? + + ... Seats 500. +%% +Did you know that there are 71.9 acres of nipple tissue in the U.S.? +%% +Do something big -- fuck a giant +%% + "Do you cheat on your wife?" asked the psychiatrist. + "Who else?" answered the patient. +%% +Doctors take two aspirin and do it in the morning. +%% +"Don't let your mouth write no check that your tail can't cash." + -- Bo Diddley +%% +Draft beer, not people +%% +Eleven reasons a cucumber is better than a man: + 1) Cucumbers can stay up all night, and you won't have to + sleep in the wet spot. + 2) Cucumbers don't play the guitar and try to find themselves. + 3) You won't find out later that your cucumber + ... is married + ... is on penicillin + ... likes you -- but loves your brother! + 4) A cucumber won't care what time of the month it is. + 5) A cucumber never wants to get it on when your nails are wet. + 6) Cucumbers don't say "Let's keep trying until we have a boy". + 7) Cucumbers won't tell you size doesn't count. + 8) A cucumber won't leave you for a cheerleader or an ex-nun. + 9) Cucumbers don't fall asleep on your chest or drool on the pillow. + 10) Cucumbers don't care if you make more money than they do. + 11) With a cucumber, the toilet seat is always the way you left it. +%% +Evangelists do it with Him watching. +%% +Fie for shame, you lascivious, lewd, lecherous, libidinous, lustful, +licentious, dirty bum!! +%% +Floppy now, hard later. +%% +Fornication, n.: + Term used by people who don't have anybody to screw with. +%% +George Washington not only chopped down his father's cherry tree, but +he also admitted doing it. Now, do you know why his father didn't +punish him? Because George still had the axe in his hand. +%% +Getting an education at the University of California is like +having $50.00 shoved up your ass, a nickel at a time. +%% + "God built a compelling sex drive into every creature, no +matter what style of fucking it practiced. He made sex irresistibly +pleasurable, wildly joyous, free from fears. He made it innocent +merriment. + "Needless to say, fucking was an immediate smash hit. Everyone +agreed, from aardvarks to zebras. All the jolly animals -- lions and +lambs, rhinoceroses and gazelles, skylarks and lobsters, even insects, +though most of them fuck only once in a lifetime -- fucked along +innocently and merrily for hundreds of millions of years. Maybe they +were dumb animals, but they knew a good thing when they had one." + -- Alan Sherman, "The Rape of the A*P*E*" +%% +God gives us relatives; thank goodness we can chose our friends. +%% +God is an atheist. +%% +God isn't dead -- he's been busted +%% +God isn't dead, He's just trying to avoid the draft. +%% +God must love assholes -- She made so many of them. +%% +God wanted to have a holiday, so He asked St. Peter for suggestions on +where to go. + "Why not go to Jupiter?" asked St. Peter. + "No, too much gravity, too much stomping around," said God. + "Well, how about Mercury?" + "No, it's too hot there." + "Okay," said St. Peter, "What about Earth?" + "No," said God, "They're such horrible gossips. When I was +there 2000 years ago, I had an affair with a Jewish woman, and they're +still talking about it." +%% +Good day for water sports. Take a bath with a friend. +%% +Grain grows best in shit + -- Ursula K. LeGuin +%% +Great Lover, n.: + A man who can breathe through his ears. +%% +Hackers do it with all sorts of characters. +%% +Hackers do it with bugs. +%% +Hackers do it with fewer instructions. +%% +Hackers know all the right MOVs. +%% +Haggis, n.: + Haggis is a kind of stuff black pudding eaten by the Scots and +considered by them to be not only a delicacy but fit for human +consumption. The minced heart, liver and lungs of a sheep, calf or +other animal's inner organs are mixed with oatmeal, sealed and boiled +in maw in the sheep's intestinal stomach-bag and ... Excuse me a +minute ... +%% +Hardly a pure science, history is closer to animal husbandry than it is +to mathematics, in that it involves selective breeding. The principal +difference between the husbandryman and the historian is that the +former breeds sheep or cows or such, and the latter breeds (assumed) +facts. The husbandryman uses his skills to enrich the future; the +historian uses his to enrich the past. Both are usually up to their +ankles in bullshit. + -- Tom Robbins +%% +Having discovered the possibility that other creatures could be used +for sexual intercourse, early man was likely to have made many such +attempts ... though it is doubtful that he was so sexually carnivorous +as the Christian and Jewish Adam, who, rabbinical interpreters of the +Old Testament tell us, had intercourse with every creature before God +finally hit upon the idea of woman and created Eve. + -- R. E. Masters +%% +He hated to mend, so young Ned +Called in a cute neighbor instead. + Her husband said, "Vi, + When you stitched up his torn fly, +Did you have to bite off the thread?" +%% +He wasn't much of an actor, he wasn't much of a Governor -- Hell, they +_H_A_D to make him President of the United States. It's the only job he's +qualified for! + -- Michael Cain +%% +He who findeth sensuous pleasures in the bodies of lush, hot, pink +damsels is not righteous, but he can have a lot more fun. +%% +He who sneezes without a handkerchief takes matters into his own +hands. +%% +Her kisses left something to be desired -- the rest of her. +%% + Here is the problem: for many years, the Supreme Court wrestled +with the issue of pornography, until finally Associate Justice John +Paul Stevens came up with the famous quotation about how he couldn't +define pornography, but he knew it when he saw it. So for a while, the +court's policy was to have all the suspected pornography trucked to +Justice Stevens' house, where he would look it over. "Nope, this isn't +it," he'd say. "Bring some more." This went on until one morning when +his housekeeper found him trapped in the recreation room under an +enormous mound of rubberized implements, and the court had to issue a +ruling stating that it didn't know what the hell pornography was except +that it was illegal and everybody should stop badgering the court about +it because the court was going to take a nap. + -- Dave Barry, "Pornography" +%% +History has the relation to truth that theology has to religion -- +i.e., none to speak of. + -- Lazarus Long +%% +"How do you like the new America? We've cut the fat out of the +government, and more recently the heart and brain (the backbone was +gone some time ago). All we seem to have left now is muscle. We'll be +lucky to escape with our skins!" +%% +Howard Cosell's biggest protrusion is his asshole + -- John Valby +%% +Hugh Hefner is a virgin. +%% +I believe that Ronald Reagan will someday make this country what it +once was ... an arctic wilderness + -- Steve Martin +%% +I came; I saw; I fucked up +%% +I have a funny daddy +Who goes in and out with me +And everything that baby does +Daddy's sure to see, +And everything that baby says, +My daddy's sure to tell. +You _m_u_s_t have read my daddy's verse. +I hope he fries in Hell. + -- Ogden Nash +%% +I love this fucking University, and this University loves fucking me. +%% +I once met a lassie named Ruth +In a long distance telephone booth. + Now I know the perfection + Of an ideal connection +Even if somewhat uncouth. +%% +"I own my own body, but I share" +%% +I realize that today you have a number of top female athletes such as +Martina Navratilova who can run like deer and bench-press Chevrolet +trucks. But to be brutally frank, women as a group have a long way to +go before they reach the level of intensity and dedication to sports +that enables men to be such incredible jerks about it. + -- Dave Barry, "Sports is a Drag" +%% +I regret to say that we of the F.B.I. are powerless to act in cases of +oral-genital intimacy, unless it has in some way obstructed interstate +commerce. + -- J. Edgar Hoover +%% +I think every good Christian ought to kick Falwell right in the ass. + -- Barry Goldwater +%% +I think pop music has done more for oral intercourse than anything else +that has ever happened, and vice versa. + -- Frank Zappa +%% +I wouldn't mind dying -- it's that business of having to stay dead that +scares the shit out of me. + -- R. Geis +%% +I'd like to meet the man who invented sex and see what he's working on +now. +%% +I'm going to Iowa for an award. Then I'm appearing at Carnegie Hall, +it's sold out. Then I'm sailing to France to be honored by the French +government -- I'd give it all up for one erection. + -- Groucho Marx +%% +"I've had one child. My husband wants to have another. I'd like to +watch him have another." +%% +If guns are outlawed, how will we shoot the liberals? +%% +If Helen Keller is alone in a forest and falls, does she make a sound? +%% +If men could get pregnant, abortion would be a sacrament. +%% +If men could get pregnant, abortion would be a sacrament. +%% +If Reagan is the answer, it must have been a VERY silly question. +%% +If someone were to ask me for a short cut to sensuality, I would +suggest he go shopping for a used 427 Shelby-Cobra. But it is only +fair to warn you that of the 300 guys who switched to them in 1966, +only two went back to women. + -- Mort Sahl +%% +If you can believe ten impossible things before breakfast, then you +should join + + THE CHURCH OF COUNTERFACTUAL BELIEF + +The Church of Counterfactual Belief has been set up to cater to all who +do not allow demonstrable truth to get in the way of their beliefs. In +addition to creation science and the flatness of the earth, the +following beliefs have been certified by Pope Duane as Church dogma: + + -- That there is a hole in the Earth at the North Pole from which + UFOs come. + -- That pi equals precisely 3.000. + -- That sex can be enjoyed only by blacks and homosexuals. + -- That Billy Joe Wilson (Hoopla, Miss.) has successfully squared + the circle. + -- That Harry Truman is still president, and doing a fine job. + -- That pi equals precisely 22/7. + +Several other important counterfactual beliefs are presently being +studied, including Reaganomics, A.I., and that the moon landings were +done in a Hollywood special effects studio. These will be the subject +of a forthcoming Papal Bull ... +%% +If you meet somebody who tells you that he loves you more than anybody +in the whole wide world, don't trust him. It means he experiments. +%% +If you think sex is a pain in the ass, try different position. +%% +"If you're a real good kid, I'll give you a piggy-back ride on a +buzz-saw." + -- W. C. Fields +%% +Ignorance is the Mother of Devotion. + -- Robert Burton +%% + In the beginning was the DEMO Project. And the Project was +without form. And darkness was upon the staff members thereof. So +they spake unto their Division Head, saying, "It is a crock of shit, +and it stinks." + + And the Division Head spake unto his Department Head, saying, +"It is a crock of excrement and none may abide the odor thereof." Now, +the Department Head spake unto his Directorate Head, saying, "It is a +container of excrement, and is very strong, such that none may abide +before it." And it came to pass that the Directorate Head spake unto +the Assistant Technical Director, saying, "It is a vessel of fertilizer +and none may abide by its strength." + + And the assistant Technical Director spake thus unto the +Technical Director, saying, "It containeth that which aids growth and +it is very strong." And, Lo, the Technical Director spake then unto +the Captain, saying, "The powerful new Project will help promote the +growth of the Laboratories." + + And the Captain looked down upon the Project, and He saw that +it was Good! +%% +In the Garden of Eden sat Adam, +Massaging the bust of his madam, + He chuckled with mirth, + For he knew that on earth, +There were only two boobs and he had 'em. +%% +Incest, n.: + Sibling revelry. +%% +It is a sad commentary on today's society that this fortune has to be +classified as "offensive" simply because it contains the word "fuck". +%% +Jesus died for your sins. Make it worth his time. +%% +Jesus was killed by a Moral Majority. +%% +John Birch Society -- that pathetic manifestation of organized +apoplexy. + -- Edward P. Morgan +%% +Kasha, n.: + Kasha is always defined as "buckwheat groats". There's only one +problem with this definition: what the fuck are "buckwheat groats"? _I +know what they are -- they're kasha. But that doesn't help ___you much. + -- Arthur Naiman, "Every Goy's Guide to Yiddish" +%% +Kill a commie for Christ! +%% +Laissez Faire Economics is the theory that if each acts like a vulture, +all will end as doves. +%% +Large cats can be dangerous, but a little pussy never hurt anyone. +%% +Life is like a penis: when it's soft you can't beat it, and when it's +hard you get fucked. +%% +Lisp hackers have to be bound (to-do 'it) ... +%% +Living in Hollywood is like living in a bowl of granola. What ain't +fruits and nuts is flakes. +%% +Mathematicians do it in theory. +%% +Mathematicians take it to the limit. +%% +Missionary Position: + The missionary on top. +%% +Most legislators are so dumb that they couldn't pour piss out of a boot +if the instructions were printed on the heel. +%% +Motto of the Electrical Engineer: + Working computer hardware is a lot like an erect penis: it + stays up as long as you don't fuck with it. +%% +My brother-in-law has found a way to make ends meet. He goes around +with his head stuck up his ass. +%% + My Favorite Drugs [Sung to My Favorite Things] +Reefers and roach clips and papers and rollers +Cocaine and procaine for twenty year molars +Reds and peyote to work out your bugs +These are a few of my favorite drugs. + +Uppers and downers and methedrine freakout +Take some amphetamines, watch your brains leak out +Acid and mescaline pull out your plugs +These are a few of my favorite drugs. + +Backs that are perfect for carrying monkeys +Users of heroin, often called junkies +Methadone helps then to stop being thugs +Takes them off one of my favorite drugs. + + On a bad trip + When the cops come + When I lose my head + I simply take more of my favorite drugs + And then I'm not sad -- I'm dead! +%% +Nancy Reagan wants divorce old Ron ... seems he's making it hard for +everyone but her. +%% + NEW ADDITION TO THE LIBRARY: +"Sally", the department's new inflatable doll, is available on a +short-term removal basis only -- please sign her out and return her +promptly to avoid extended waits. (We are still awaiting shipment of +our "Big John" doll.) +%% +Nothing is better than Sex. +Masturbation is better than nothing. +Therefore, Masturbation is better than Sex. +%% +O'Riordan's Theorem: + Brains x Beauty = Constant. + +Purmal's Corollary: + As the limit of (Brains x Beauty) goes to infinity, + availability goes to zero. +%% +Occident, n.: + The part of the world lying west (or east) of the Orient. It +is largely inhabited by Christians, powerful sub-tribe of the +Hypocrites, whose principal industries are murder and cheating, which +they are pleased to call "war" and "commerce." These, also, are the +principal industries of the Orient. + -- Ambrose Bierce, "The Devil's Dictionary" +%% +Ocean, n.: + A body of water occupying about two-thirds of a world made for +man -- who has no gills. +%% +Once a young gay from Khartoum +Took a lesbian up to his room. + They argued all night + Over who had the right +To do what, and with which, and to whom. +%% +Once upon a time, there was a non-conforming sparrow who decided not to +fly south for the winter. However, soon after the weather turned cold, +the sparrow changed his mind and reluctantly started to fly south. +After a short time, ice began to form his on his wings and he fell to +earth in a barnyard almost frozen. A cow passed by and crapped on this +little bird and the sparrow thought it was the end, but the manure +warmed him and defrosted his wings. Warm and happy the little sparrow +began to sing. Just then, a large Tom cat came by and hearing the +chirping investigated the sounds. As Old Tom cleared away the manure, +he found the chirping bird and promptly ate him. + +There are three morals to this story: + +1) Everyone who shits on you is not necessarily your enemy. +2) Everyone who gets you out of shit is not necessarily your friend. +3) If you are warm and happy in a pile of shit, keep your mouth shut. +%% +One day President Reagan, Chairman Andropov, the Pope, and a boy scout +were flying together in an airplane. Right out in the middle of +nowhere the plane developed engine trouble and started to go down. +Unfortunately, only three parachutes could be found for the four +passengers! Andropov grabbed one of the parachutes and declared +"Comrades, as leader of the socialist workers revolution, my life must +be spared," and he jumped out of the plane. Then Reagan exclaimed "As +leader of the greatest nation on earth, I must keep the world safe for +democracy," and with that he too jumped to safety. Now if you are +following all this (or counting on your fingers) you must see that +there is only one parachute left for the two remaining passengers. The +Pope looked kindly upon the boy scout and said "I have had a long and +productive life, my son. You take the parachute and leave me in God's +hands." "That's very kind of you," the observant scout replied, "but +there is no need. Reagan just jumped out with my knapsack." +%% +Opinions are like assholes -- everyone's got one, but nobody wants to +look at the other guy's. + -- Hal Hickman +%% +Our team usually puts the other woman at second base, where the maximum +possible number of males can get there on short notice to help out in +case of emergency. As far as I can tell, our second basewoman is a +pretty good baseball player, better than I am, anyway, but there's no +way to know for sure because if the ball gets anywhere near her, a male +comes barging over from, say, right field, to deal with it. She's been +on the team for three seasons now, but the males still don't trust +her. They know, deep in their souls, that if she had to choose between +catching a fly ball and saving an infant's life, she probably would +elect to save the infant's life, without ever considering whether there +were men on base. + -- Dave Barry, "Sports is a Drag" +%% + Overheard in a bar: +Man: "Hey, Baby, I'd sure like to get in your pants!" +Woman: "No, thanks, I've already got one ass-hole in there now." +%% +Physicists do it with charm +%% +Politicians do it to everyone. +%% +Posterity will ne'er survey +A nobler grave than this; +Here lie the bones of Castlereagh; +Stop, traveler, and piss. + -- Lord Byron, on Lord Castlereagh +%% +Procrastinators do it tomorrow. +%% +Prostitution is the only business where you can go into the hole and +still come out ahead. +%% +Q: How do you play religious roulette? +A: You stand around in a circle and blaspheme and see who gets struck + by lightning first. +%% +Q: How do you tell if an Elephant has been making love in your + backyard? +A: If all your trashcan liners are missing ... +%% +Q: How do you tell if you're making love to a nurse, a schoolteacher, + or an airline stewardess? +A: A nurse says: "This won't hurt a bit." A schoolteacher says: "We're + going to have to do this over and over again until we get it + right." An airline stewardess says: "Just hold this over your mouth + and nose, and breath normally." +%% +Q: How many right-to-lifers does it take to change a light bulb? +A: Two. One to screw it in and one to say that light started when the + screwing began. +%% +Q: How many supply-siders does it take to change a light bulb? +A: None. The darkness will cause the light bulb to change by itself. +%% +Q: If Tarzan was Jewish, and Jane was a princess, what would Cheetah + be? +A: A fur coat. +%% +Q: What do you do with an elephant with three balls? +A: Walk him and pitch to the rhino. +%% +Q: What is "SMOORPLAY"? +A: It's what SMURFS do before they SMUCK, of course! +%% +Q: What's Jewish foreplay? +A: Two hours of begging. +%% +Q: Where can you buy black lace crotchless panties for sheep? +A: Fredricks of Ithaca, New York. +%% +Q: Where does virgin wool come from? +A: Ugly sheep. +%% +Randel, n.: + A nonsensical poem recited by Irish schoolboys as an apology +for farting at a friend. + -- Mrs. Byrne's Dictionary of Unusual, Obscure & + Preposterous Words +%% +Reagan can't _a_c_t either +%% +Remember when you were a kid and the boys didn't like the girls? Only +sissies liked girls? What I'm trying to tell you is that nothing's +changed. You think boys grow out of not liking girls, but we don't +grow out of it. We just grow horny. That's the problem. We mix up +liking pussy for liking girls. Believe me, one couldn't have less to +do with the other. + -- Jules Feiffer +%% +Republicans raise dahlias, Dalmatians and eyebrows. +Democrats raise Airedales, kids and taxes. + +Democrats eat the fish they catch. +Republicans hang them on the wall. + +Republican boys date Democratic girls. They plan to marry Republican +girls, but feel they're entitled to a little fun first. + +Democrats make up plans and then do something else. +Republicans follow the plans their grandfathers made. + +Republicans consume three-fourths of the rutabaga produced in the USA. +The remainder is thrown out. + +Republicans sleep in twin beds -- some even in separate rooms. +That is why there are more Democrats. + -- The Official Rules, as compiled by Paul Dickson +%% +Ronald Reagan -- America's favorite placebo +%% +Said a horny young girl from Milpitas, +"My favorite sport is coitus." + But a fullback from State + Made her period late, +And now she has athlete's fetus +%% +Said a swinging young chick named Lyth +Whose virtue was largely a myth, + "Try as hard as I can, + I can't find a man +That it's fun to be virtuous with." +%% +Said Einstein, "I have an equation +Which to some may seem rabelaisian: + Let _V be virginity + Approaching infinity; +Let _P be a constant persuasion; + +"Let _V over _P be inverted +With the square root of _M_u inserted + _N times into _V ... + The result, Q.E.D., +Is a relative!" Einstein asserted. +%% +Save Soviet Jewry -- Win Valuable Prizes!!!! +%% +Sex is like a bridge game -- +If you have a good hand no partner is needed. +%% +Sex is the poor man's opera. + -- G. B. Shaw +%% +She asked me if I loved her still. "Yes," I replied. "I've never had +you any other way." +%% +She hates testicles, thus limiting the men she can admire to Democratic +candidates for president. + -- John Greenway, "The American Tradition", on feminist + Elizabeth Gould Davis +%% + ... So this is a very confusing situation, and what makes +it even worse is, our standards keep changing. Take Playboy magazine. +Back in the 1950s, when I started reading it strictly for the articles, +Playboy was considered just about the raciest thing around, even though +all it ever showed was women's breasts. Granted, any given one of +these breasts would have provided adequate shelter for a family of +four, but the overall effect was no more explicit than many +publications we think nothing of today, such as Sports Illustrated's +Annual Nipples Poking Through Swimsuits Issue. + -- Dave Barry, "Pornography" +%% +Statisticians do it with 95% confidence. +%% +Statisticians probably do it. +%% +Subpoena,n .: + From the root "sub", below, and the Latin "poena" for male +organ or penis. Therefore, "below the penis" or "by the balls." +%% +Support the right of unborn males to bear arms! + -- A public service announcement from Phyllis Schlafly, + the Catholic Church, and the National Rifle + Association +%% +Sure eating yogurt will improve your sex life. People know that if +you'll eat that stuff, you'll eat anything. +%% +Sure, Reagan has promised to take senility tests. But what if he +forgets? +%% + The big problem with pornography is defining it You can't just +say it's pictures of people naked. For example, you have these +primitive African tribes that exist by chasing the wildebeest on foot, +and they have to go around largely naked, because, as the old tribal +saying goes: "N'wam k'honi soit qui mali," which means, "If you think +you can catch a wildebeest in this climate and wear clothes at the same +time, then I have some beach front property in the desert region of +Northern Mali that you may be interested in." + So it's not considered pornographic when National Geographic +publishes color photographs of these people hunting the wildebeest +naked, or pounding one rock onto another rock for some primitive reason +naked, or whatever. But if National Geographic were to publish an +article entitled "The Girls of the California Junior College System +Hunt the Wildebeest Naked," some people would call it pornography. But +others would not. And still others, such as the Spectacularly Rev. +Jerry Falwell, would get upset about seeing the wildebeest naked. + -- Dave Barry, "Pornography" +%% +The computer is the ultimate polluter: its shit is indistinguishable +from the food it produces. +%% + The defense attorney was hammering away at the plaintiff: "You +claim," he jeered, "that my client came at you with a broken bottle in +his hand. But is it not true, that you had something in YOUR hand?" + + "Yes," he admitted, "his wife. Very charming, of course, but +not much good in a fight." +%% +The difference between this school and a cactus plant is that the +cactus has the pricks on the outside. +%% +... the Father, the Son and the Holy Ghost would never throw the +Devil out of Heaven as long as they still need him as a fourth for +bridge. + -- Letter in NEW LIBERTARIAN NOTES #19 +%% + The Gray-haired Woman's Complaint + +My back aches, my pussy is sore; +I simply can't fuck any more; + I'm covered with sweat, + And you haven't come yet, +And my God, it's a quarter to four! +%% +The other night I was having sex, but the girl hung up on me. +%% +The problem with being best man at a wedding is that you never get a +chance to prove it. +%% +The real problem with fucking a sheep is that you have to walk around +in front every time you want to kiss her. +%% +The sergeant walked into the shower and caught me giving myself a +dishonorable discharge. Without missing a beat, I said, "It's my dick +and I can wash it as fast as I want!" +%% + The Split-Atom Blues + +Gimme Twinkies, gimme wine, + Gimme jeans by Calvin Kline ... +But if you split those atoms fine, + Mama keep 'em off those genes of mine! + +Gimme zits, take my dough, + Gimme arsenic in my jelly roll ... +Call the devil and sell my soul, + But Mama keep dem atoms whole! + -- Milo Bloom, "Bloom County" +%% +The United States Army; +194 years of proud service, +unhampered by progress. +%% +"The voters have spoken, the bastards ..." +%% +"The whole world is about three drinks behind." + -- Humphrey Bogart +%% +The word "spine" is, of course, an anagram of "penis". This is true in +almost fifty percent of the languages of the Galaxy, and many people +have attempted to explain why. Usually these explanations get bogged +down in silly puns about "standing erect". + -- Donald Adams, "The Hitchhiker's Guide to the Galaxy" +%% +The world is an 8000 mile in diameter spherical pile of shit. +%% + Them Toad Suckers + +How 'bout them toad suckers, ain't they clods? +Sittin' there suckin' them green toady frogs! + +Suckin' them hop toads, suckin' them chunkers, +Suckin' them a leapy type, suckin' them flunkers. + +Look at them toad suckers, ain't they snappy? +Suckin' them bog frogs sure make's 'em happy! + +Them hugger mugger toad suckers, way down south, +Stickin' them sucky toads in they mouth! + +How to be a toad sucker, no way to duck it, +Get yourself a toad, rear back, and suck it! + -- Mason Williams +%% +There are two sides to every divorce: yours and the shithead's. +%% +There once was a couple named Kelley, +Who lived their life belly to belly. + Because in their haste + They used Library Paste, +Instead of Petroleum Jelly. +%% +There once was a freshman named Lin, +Whose tool was as thin as a pin, + A virgin named Joan + From a bible belt home, +Said "This won't be much of a sin." +%% +There once was a hacker named Ken +Who inherited truckloads of Yen + So he built him some chicks + Of silicon chips +And hasn't been heard from since then. +%% +There once was a lady from Exeter, +So pretty that men craned their necks at her. + One was even so brave + As to take out and wave +The distinguishing mark of his sex at her. +%% +There once was a plumber from Leigh, +Who was plumbing his maid by the sea, + Said she, "Please stop plumbing, + I think someone's coming!" +Said he, "Yes I know love, it's me." +%% +There once was a queen of Bulgaria +Whose bush had grown hairier and hairier, + Till a prince from Peru + Who came up for a screw +Had to hunt for her cunt with a terrier. +%% +There once was a Scot named McAmeter +With a tool of prodigious diameter. + It was not the size + That cause such surprise; +'Twas his rhythm -- iambic pentameter. +%% +There once was a young man named Gene +Who invented a screwing machine + Concave and convex + It served either sex +And it played with itself in between. +%% +There was a bluestocking in Florence +Wrote anti-sex pamphlets in torrents, + Till a Spanish grandee, + Got her off with his knee, +And she burned all her works with abhorrence. +%% +There was a gay countess of Bray, +And you may think it odd when I say, + That in spite of high station, + Rank and education, +She always spelled cunt with a "k". +%% +There was a young fellow named Bliss +Whose sex life was strangely amiss, + For even with Venus + His recalcitrant penis +Would never do better than t + h + i + s + . +%% +There was a young girl from Hong Kong +Whose cervical cap was a gong. + She said with a yell, + As a shot rang her bell, +"I'll give you a ding for a dong!" +%% +There was a young girl named Sapphire +Who succumbed to her lover's desire. + She said, "It's a sin, + But now that it's in, +Could you shove it a few inches higher?" +%% +There was a young girl of Angina +Who stretched catgut across her vagina. + From the love-making frock + (With the proper sized cock) +Came Tocata and Fugue in D minor. +%% +There was a young girl of Darjeeling +Who could dance with such exquisite feeling + There was never a sound + For miles around +Save of fly-buttons hitting the ceiling. +%% +There was a young lad name of Durcan +Who was always jerkin' his gherkin. + His father said, "Durcan! + Stop jerkin' your gherkin! +Your gherkin's for ferkin', not jerkin'. +%% +There was a young lady from Maine +Who claimed she had men on her brain. + But you knew from the view, + As her abdomen grew, +It was not on her brain that he'd lain. +%% +There was a young lady named Clair +Who possessed a magnificent pair; + At least so I thought + Till I saw one get caught +On a thorn, and begin losing air. +%% +There was a young lady named Hall, +Wore a newspaper dress to a ball. + The dress caught on fire + And burned her entire +Front page, sporting section, and all. +%% +There was a young lady named Twiss +Who said she thought fucking a bliss, + For it tickled her bum + And caused her to come +.siht ekil gniyl ylbatrofmoc elihW +%% +There was a young lady of Norway +Who hung by her toes in a doorway. + She said to her beau + "Just look at me Joe +I think I've discovered one more way." +%% +There was a young man from Bel-Aire +Who was screwing his girl on the stair, + But the banister broke + So he doubled his stroke +And finished her off in mid-air. +%% +There was a young man named Crockett +Whose balls got caught in a socket. + His wife was a bitch, + And she threw the switch, +As Crockett went off like a rocket. +%% +There was a young man of Cape Horn +Who wished he had never been born, + And he wouldn't have been + If his father had seen +That the end of the rubber was torn. +%% +There was a young man of St. John's +Who wanted to bugger the swans. + But the loyal hall porter + Said, "Pray take my daughter! +Those birds are reserved for the dons." +%% +There was a young whore from kaloo +Who filled her vagina with glue. + She said with a grin, + "If they pay to get in, +They can pay to get out again too!" +%% +There was an old man of the port +Whose prick was remarkably short. + When he got into bed, + The old woman said, +"This isn't a prick; it's a wart!" +%% +There was an old pirate named Bates +Who was learning to rhumba on skates. + He fell on his cutlass + Which rendered him nutless +And practically useless on dates. +%% +There were the Scots +Who kept the Sabbath +And everything else they could lay their hands on. +Then there were the Welsh +Who prayed on their knees and their neighbors. +Thirdly there were the Irish +Who never knew what they wanted +But were willing to fight for it anyway. +Lastly there were the English +Who considered themselves a self-made nation +Thus relieving the Almighty of a dreadful responsibility. +%% +There's more than one way to skin a cat: + Way number 15 -- Krazy Glue and a toothbrush. +%% +There's more than one way to skin a cat: + Way number 27 -- Use an electric sander. +%% +There's more than one way to skin a cat: + Way number 32 -- Wrap it around a lonely frat man's pecker. +%% +There's nothing better than good sex. But bad sex? A peanut butter +and jelly sandwich is better than bad sex. + -- Billy Joel +%% +There's nothing wrong with America that a good erection wouldn't cure. + -- David Mairowitz +%% +They [District Attorneys] learn in District Attorney School that there +are two sure-fire ways to get a lot of favorable publicity: + +(1) Go down and raid all the lockers in the local high school and + confiscate 53 marijuana cigarettes and put them in a pile and hold + a press conference where you announce that they have a street value + of $850 million. These raids never fail, because ALL high schools, + including brand-new, never-used ones, have at least 53 marijuana + cigarettes in the lockers. As far as anyone can tell, the locker + factory puts them there. +(2) Raid an "adult book store" and hold a press conference where you + announce you are charging the owner with 850 counts of being a + piece of human sleaze. This also never fails, because you always + get a conviction. A juror at a pornography trial is not about to + state for the record that he finds nothing obscene about a movie + where actors engage in sexual activities with live snakes and a + fire extinguisher. He is going to convict the bookstore owner, and + vote for the death penalty just to make sure nobody gets the wrong + impression. + -- Dave Barry, "Pornography" +%% +This is a test of the emergency cunnilingus system. If this had been an +actual emergency, you would have known it! +%% +This is National Smokers-Are-Shits Week. +%% +This limerick is **SO**FILTHY** that it would offend you. So I'll put +"di-dah" for the filthy words: + + Di-dah, di-dah, di-dah di-dah, + Di-dah di-dah di-dah, di-dah; + di-dah di-dah di-dah? + Di-dah di-dah di-dah. + Di-dah di-dah, di-dah di-fuck. +%% +This test has been designed to evaluate reactions of management +personal to various situations. + +You are making a sales presentation to a group of corporate executives +in the plushest office you've ever seen. The enchillada casserole and +egg salad sandwich you had for lunch react, creating severe pressure. +Your sphincter loses control and you break wind, causing the glass +bookcase doors to shatter and a secretary to pass out. + +YOU SHOULD: + +(A) Offer to come back next week when the smell has gone away. +(B) Point to the Chief Executive and accuse him of the offense. +(C) Challenge anyone in the room to do better. +%% +This test has been designed to evaluate reactions of management +personal to various situations. + +You are making a sales presentation to a group of corporate executives +in the plushest office you've ever seen. The enchillada casserole and +egg salad sandwich you had for lunch react, creating severe pressure. +Your sphincter loses control and you break wind, causing the glass +bookcase doors to shatter and a secretary to pass out. + +YOU SHOULD: + +(A) Offer to come back next week when the smell has gone away. +(B) Point to the Chief Executive and accuse him of the offense. +(C) Challenge anyone in the room to do better. +%% +Thou shalt not omit adultery. +%% +To a Real Woman, every ejaculation is premature. +%% +"Tom Hayden is the kind of politician who gives opportunism a bad +name." + -- Gore Vidal +%% +'Twas orgy, and the hip and mod And as in raffish thought he sprawled, +Did groove and trip out at the pad: The Radcliffe girl, no idle flirt, +All whimsy were the slamming chicks, Crept past the hippies getting balled +And the Radcliffe undergrad. And doffed her miniskirt. + +"Beware the Radcliff girl, my son! One, two! One, two! And through +The looks that melt, the claws that and through + catch! The venerable staff went snicker-snack! +Beware the Byrn Mawr deb, and shun He left her bred, sans maidenhead, +The uppity Wellesleysnatch!" And went galumphing back. + +He took his venerable staff in hand: "And hast thou laid the Radcliffe girl? +Long time the cool young stuff he Come to my arms, my horny boy! + sought -- O spaced-out day! Calooh! Callay!" +So rested he among the spree He cackled in his joy. +And paused to smoke some pot. + 'Twas orgy, and the hip and mod + Did groove and trip out at the pad: + All whimsy were the slamming chicks, + And the Radcliffe undergrad. +%% + Two little kids, aged six and eight, decide it's time to learn +how to swear. So, the eight-year-old says to the six-year-old, "Okay, +you say `ass' and I'll say `hell'". + All excited about their plan, they troop downstairs, where +their mother asks them what they'd like for breakfast. + "Aw, hell," says the eight-year-old, "gimme some Cheerios." His +mother backhands him off the stool, sending him bawling out of the +room, and turns to the younger brother. "What'll you have?" + "I dunno," quavers the six-year-old, "but you can bet your ass +it ain't gonna be Cheerios." +%% +"Under capitalism, man exploits man. Under Communism, it's just the +opposite." + -- John Kenneth Galbraith +%% +Vidi, vici, veni. +(I saw, I conquered, I came.) +%% +Virgin, n.: + An ugly third grader. +%% +War is menstruation envy. +%% +We call our dog Egypt, because in every room he leaves a pyramid. +%% +"We don't have to protect the environment -- the Second Coming is at +hand." + -- James Watt +%% +Well, see, Joyce, there we were, trapped in the elevator. Now, I had +my tennis racquet and the goldfish; she was holding the Crisco. Surely +you can imagine how one thing naturally led to another! +%% + Well, there was this tiger, who woke up one morning, and just +felt great (yes, just like Tony the Tiger: GREAAAAAAT). Anyway, he +just felt so good, he went out and cornered a small monkey and roared +at him: "WHO IS THE MIGHTIEST OF ALL THE JUNGLE ANIMALS?" And this +poor quaking little monkey replied: "You are of course, no one is +mightier than you." A little while later this tiger confronts a deer, +and just bellows out: "WHO IS THE GREATEST AND STRONGEST OF ALL THE +JUNGLE ANIMALS?" The deer is shaking so hard it can barely speak, but +manages to stammer: "Oh great tiger, you are by far the mightiest +animal in the jungle." The tiger, being on a roll, swaggered, up to an +elephant that was quietly munching on some weeds, and roared at the top +of his voice: "WHO IS THE MIGHTIEST OF ALL THE ANIMALS IN THE JUNGLE?" +Well, this elephant grabs the tiger with his trunk, picks him up, slams +him down; picks him up again, and shakes him until the tiger is just a +blur of orange and black; and finally throws him violently into a +nearby tree. The tiger staggers to his feet and looks at the elephant +and says: "Man, just because you don't know the answer, you don't have +to get so pissed." +%% +What can you use used tampons for? Tea bags for vampires. +%% + "What the hell are you getting so upset about? I thought you +didn't believe in God." + "I don't," she sobbed, bursting violently into tears, "but the +God I don't believe in is a good God, a just God, a merciful God. He's +not the mean and stupid God you make Him out to be." + -- Joseph Heller, "Catch-22" +%% +When God created man, She was only testing. +%% +"When I grow up, I want to be an honest lawyer so things like that +can't happen." + -- Richard Nixon as a boy (on the Teapot Dome scandal) +%% +When it all boils down to the essence of truth one must live by a dog's +rule of life: if you can't eat it or fuck it, piss on it! +%% + When the surgeon came to see her on the morning after her +operation, the young woman asked her somewhat hesitantly how long it +would be before she could resume her sex life. "I really haven't +thought about it," gulped the stunned surgeon. "You're the first +patient who's asked me that after a tonsillectomy!" +%% +While I, with my usual enthusiasm, +Was exploring in Ermintrude's busiasm, + She explained, "They are flat, + But think nothing of that -- +You will find that my sweet sister Susiasm." +%% +"White House carpenters have reworked the master bedroom, remodeling it +so that Ronnie can sleep with his head in the hall. That way, by the +time he wakes up, somebody will have already shined his hair." +%% +Why is it that there are so many more horses' asses than there are +horses? + -- G. Gordon Liddy +%% +Why marry a virgin? If she wasn't good enough for the rest of them +then she isn't good enough for you. +%% +Women Unite! Make *___him* sleep in the wet spot tonight! +%% +Women who want to be equal to men lack imagination + -- Graffito in a women's restroom +%% +Womens Libbers are OK. I just wouldn't want my sister to marry one. +%% +"Yes, that was Richard Nixon. He used to be President. When he left +the White House, the Secret Service would count the silverware." + -- Woody Allen, "Sleeper" +%% +You are at a business lunch when you are suddenly overcome with an +uncontrollable desire to pick your nose. Since this is definitely a +no-no, you: + +(a) Pretend to wave to someone across the room and with one fluid + motion, bury your forefinger in your nostril right up to the 4th + joint. + +(b) Get everyone drunk and organize a nose picking contest with a + prize to the one who makes his nose bleed first. + +(c) Drop your napkin on the floor and when you bend over to pick it + up, blow your nose on your sock. +%% +You are making a presentation to a group of corporate executives in the +plushest board room you have ever seen. The hot enchillada casserole +and egg salad sandwich you had for lunch react, creating a severe +pressure. Your sphincter loses its control and you break wind in a +most convincing manner causing 3 water tumblers to shatter and a +secretary to pass out. What you should do next is: + +(a) Offer to come back next week when the smell has gone away. + +(b) Point out the Marketing Manager and accuse him of the act. + +(c) Challenge anyone in the room to do better. +%% +You better believe that marijuana can cause castration. Just suppose +your girlfriend gets the munchies! +%% +You can pick your friends, and you can pick your nose, but you can't +pick your friend's nose. +%% +You come out of a woman and you spend the rest of your life trying to +get back inside. + -- Heathcote Williams +%% +You have just returned from a trip to Green Bay, Wisconsin in January +and tell your boss that nobody but whores and football players live +there. He mentions that his wife is from Green Bay. You: + +(a) Pretend you are suffering from amnesia and don't remember your + name. + +(b) Ask what position she played. + +(c) Ask if she is still working the streets. +%% +You have prepared a proposal for your supervisor. The success of this +proposal will mean increasing your salary 20%. In the middle of your +proposal your supervisor leans over to look at your report and spits +into your coffee. You: + +(a) Tell him you take your coffee black. + +(b) Ask him if he has any communicable diseases. + +(c) Show him who's in command; promptly take a leak in his "In" + basket. diff --git a/src/games/fortune/obscene.sp.ok b/src/games/fortune/obscene.sp.ok new file mode 100644 index 0000000..c3e34dc --- /dev/null +++ b/src/games/fortune/obscene.sp.ok @@ -0,0 +1,238 @@ +A.I +AI +Aire +amnesia +Andropov +Angina +Ansel +apoplexy +asshole +assholes +Aw +basewoman +Begorrah +bible +Bierce +Bo +Bogart +boobs +bras +brutish +buffaloes +bullshit +busiasm +Byrn +Callay +Calooh +carnivorous +Castlereagh +castration +catgut +cervical +Cheerios +chromosome +Clair +Coito +coitus +commie +containeth +Cosell's +COUNTERFACTUAL +Counterfactual +counterfactual +countess +Crisco +cubits +Cunnilingus +cunnilingus +cunt +dah +Dalmatians +Dammit +Darjeeling +deb +defendin +dem +DEMO +Di +di +Diddley +dong +doric +dunno +Durcan +ekil +elihW +enchillada +ergo +Ermintrude's +excrement +eyeing +F.B.I +Fagin +Faire +Falwell +farting +Feiffer +ferkin +fetcheth +Fie +findeth +flunkers +Fornication +frat +freakout +Fredricks +Fuck +fuck +fucked +fucking +Galbraith +galumphing +gangrenous +Geis +genital +Gimme +gimme +girlfriend +gniyl +goin +gonna +Goy's +Graffito +grandee +GREAAAAAAT +Greenway +Groucho +Haggis +hansome +Heathcote +Hefner +hexahedronical +Hitchhiker's +husbandryman +i.e +iht +intestinal +jeered +jerkin +Jewry +k'honi +kaloo +Kasha +kasha +Krazy +lassie +leapy +lecherous +LeGuin +lesbian +Libbers +Liddy +limerick +Lyth +mah +maidenhead +Mairowitz +mali +Mama +Martina +Masturbation +masturbation +McAmeter +Methadone +methedrine +Milo +Milpitas +miniskirt +mod +mousetrap +MOVs +munchies +N'wam +Nader +Naiman +Navratilova +ne'er +Nope +O'Riordan's +ok +ole +penis +pentameter +peyote +poena +pox +provideth +Purmal's +PUSHJ +Putrid +Q.E.D +qui +rabbinical +rabelaisian +racquet +Radcliff +Randel +Raygun +Reaganomics +rhumba +Rosten +Sahl +saideth +Schlafly +shalt +shit +shithead's +Shits +shits +sissies +Sittin +sleaze +SMOORPLAY +SMUCK +SMURFS +soit +spake +sphincter +spikey +Stamboul +Stickin +strewed +Subpoena,n +Suckin +suckin +sucky +suh +Susiasm +Tijuana +Tocata +tonsillectomy +trashcan +truckloads +Twas +Twinkies +Twiss +U.S +UFOs +ulcerous +UUOs +Valby +veni +vici +Vidal +Vidi +Wellesleysnatch +What'll +whimsy +Wiggam +Wildebeest +wildebeest +Wimley +yamalchas +ylbatrofmoc +yogurt +Yoric +Yuletide +Zappa +zits diff --git a/src/games/fortune/rnd.c b/src/games/fortune/rnd.c new file mode 100644 index 0000000..946b460 --- /dev/null +++ b/src/games/fortune/rnd.c @@ -0,0 +1,365 @@ +/* + * code for when the good (berkeley) random number generator is around + */ + +rnd(num) +{ + return (random() % num); +} + +srnd(num) +{ + srandom(num); +} + +#ifdef NO_RANDOM + +#ifndef lint +static char sccsid[] = "@(#)random.c 4.2 (Berkeley) 83/01/02"; +#endif + +#include + +/* + * random.c: + * An improved random number generation package. In addition to the standard + * rand()/srand() like interface, this package also has a special state info + * interface. The initstate() routine is called with a seed, an array of + * bytes, and a count of how many bytes are being passed in; this array is then + * initialized to contain information for random number generation with that + * much state information. Good sizes for the amount of state information are + * 32, 64, 128, and 256 bytes. The state can be switched by calling the + * setstate() routine with the same array as was initiallized with initstate(). + * By default, the package runs with 128 bytes of state information and + * generates far better random numbers than a linear congruential generator. + * If the amount of state information is less than 32 bytes, a simple linear + * congruential R.N.G. is used. + * Internally, the state information is treated as an array of longs; the + * zeroeth element of the array is the type of R.N.G. being used (small + * integer); the remainder of the array is the state information for the + * R.N.G. Thus, 32 bytes of state information will give 7 longs worth of + * state information, which will allow a degree seven polynomial. (Note: the + * zeroeth word of state information also has some other information stored + * in it -- see setstate() for details). + * The random number generation technique is a linear feedback shift register + * approach, employing trinomials (since there are fewer terms to sum up that + * way). In this approach, the least significant bit of all the numbers in + * the state table will act as a linear feedback shift register, and will have + * period 2^deg - 1 (where deg is the degree of the polynomial being used, + * assuming that the polynomial is irreducible and primitive). The higher + * order bits will have longer periods, since their values are also influenced + * by pseudo-random carries out of the lower bits. The total period of the + * generator is approximately deg*(2**deg - 1); thus doubling the amount of + * state information has a vast influence on the period of the generator. + * Note: the deg*(2**deg - 1) is an approximation only good for large deg, + * when the period of the shift register is the dominant factor. With deg + * equal to seven, the period is actually much longer than the 7*(2**7 - 1) + * predicted by this formula. + */ + + + +/* + * For each of the currently supported random number generators, we have a + * break value on the amount of state information (you need at least this + * many bytes of state info to support this random number generator), a degree + * for the polynomial (actually a trinomial) that the R.N.G. is based on, and + * the separation between the two lower order coefficients of the trinomial. + */ + +#define TYPE_0 0 /* linear congruential */ +#define BREAK_0 8 +#define DEG_0 0 +#define SEP_0 0 + +#define TYPE_1 1 /* x**7 + x**3 + 1 */ +#define BREAK_1 32 +#define DEG_1 7 +#define SEP_1 3 + +#define TYPE_2 2 /* x**15 + x + 1 */ +#define BREAK_2 64 +#define DEG_2 15 +#define SEP_2 1 + +#define TYPE_3 3 /* x**31 + x**3 + 1 */ +#define BREAK_3 128 +#define DEG_3 31 +#define SEP_3 3 + +#define TYPE_4 4 /* x**63 + x + 1 */ +#define BREAK_4 256 +#define DEG_4 63 +#define SEP_4 1 + + +/* + * Array versions of the above information to make code run faster -- relies + * on fact that TYPE_i == i. + */ + +#define MAX_TYPES 5 /* max number of types above */ + +static int degrees[ MAX_TYPES ] = { DEG_0, DEG_1, DEG_2, + DEG_3, DEG_4 }; + +static int seps[ MAX_TYPES ] = { SEP_0, SEP_1, SEP_2, + SEP_3, SEP_4 }; + + + +/* + * Initially, everything is set up as if from : + * initstate( 1, &randtbl, 128 ); + * Note that this initialization takes advantage of the fact that srandom() + * advances the front and rear pointers 10*rand_deg times, and hence the + * rear pointer which starts at 0 will also end up at zero; thus the zeroeth + * element of the state information, which contains info about the current + * position of the rear pointer is just + * MAX_TYPES*(rptr - state) + TYPE_3 == TYPE_3. + */ + +static long randtbl[ DEG_3 + 1 ] = { TYPE_3, + 0x9a319039, 0x32d9c024, 0x9b663182, 0x5da1f342, + 0xde3b81e0, 0xdf0a6fb5, 0xf103bc02, 0x48f340fb, + 0x7449e56b, 0xbeb1dbb0, 0xab5c5918, 0x946554fd, + 0x8c2e680f, 0xeb3d799f, 0xb11ee0b7, 0x2d436b86, + 0xda672e2a, 0x1588ca88, 0xe369735d, 0x904f35f7, + 0xd7158fd6, 0x6fa6f051, 0x616e6b96, 0xac94efdc, + 0x36413f93, 0xc622c298, 0xf5a42ab8, 0x8a88d77b, + 0xf5ad9d0e, 0x8999220b, 0x27fb47b9 }; + +/* + * fptr and rptr are two pointers into the state info, a front and a rear + * pointer. These two pointers are always rand_sep places aparts, as they cycle + * cyclically through the state information. (Yes, this does mean we could get + * away with just one pointer, but the code for random() is more efficient this + * way). The pointers are left positioned as they would be from the call + * initstate( 1, randtbl, 128 ) + * (The position of the rear pointer, rptr, is really 0 (as explained above + * in the initialization of randtbl) because the state table pointer is set + * to point to randtbl[1] (as explained below). + */ + +static long *fptr = &randtbl[ SEP_3 + 1 ]; +static long *rptr = &randtbl[ 1 ]; + + + +/* + * The following things are the pointer to the state information table, + * the type of the current generator, the degree of the current polynomial + * being used, and the separation between the two pointers. + * Note that for efficiency of random(), we remember the first location of + * the state information, not the zeroeth. Hence it is valid to access + * state[-1], which is used to store the type of the R.N.G. + * Also, we remember the last location, since this is more efficient than + * indexing every time to find the address of the last element to see if + * the front and rear pointers have wrapped. + */ + +static long *state = &randtbl[ 1 ]; + +static int rand_type = TYPE_3; +static int rand_deg = DEG_3; +static int rand_sep = SEP_3; + +static long *end_ptr = &randtbl[ DEG_3 + 1 ]; + + + +/* + * srandom: + * Initialize the random number generator based on the given seed. If the + * type is the trivial no-state-information type, just remember the seed. + * Otherwise, initializes state[] based on the given "seed" via a linear + * congruential generator. Then, the pointers are set to known locations + * that are exactly rand_sep places apart. Lastly, it cycles the state + * information a given number of times to get rid of any initial dependencies + * introduced by the L.C.R.N.G. + * Note that the initialization of randtbl[] for default usage relies on + * values produced by this routine. + */ + +srandom( x ) + + unsigned x; +{ + register int i, j; + + if( rand_type == TYPE_0 ) { + state[ 0 ] = x; + } + else { + j = 1; + state[ 0 ] = x; + for( i = 1; i < rand_deg; i++ ) { + state[i] = 1103515245*state[i - 1] + 12345; + } + fptr = &state[ rand_sep ]; + rptr = &state[ 0 ]; + for( i = 0; i < 10*rand_deg; i++ ) random(); + } +} + + + +/* + * initstate: + * Initialize the state information in the given array of n bytes for + * future random number generation. Based on the number of bytes we + * are given, and the break values for the different R.N.G.'s, we choose + * the best (largest) one we can and set things up for it. srandom() is + * then called to initialize the state information. + * Note that on return from srandom(), we set state[-1] to be the type + * multiplexed with the current value of the rear pointer; this is so + * successive calls to initstate() won't lose this information and will + * be able to restart with setstate(). + * Note: the first thing we do is save the current state, if any, just like + * setstate() so that it doesn't matter when initstate is called. + * Returns a pointer to the old state. + */ + +char * +initstate( seed, arg_state, n ) + + unsigned seed; /* seed for R. N. G. */ + char *arg_state; /* pointer to state array */ + int n; /* # bytes of state info */ +{ + register char *ostate = (char *)( &state[ -1 ] ); + + if( rand_type == TYPE_0 ) state[ -1 ] = rand_type; + else state[ -1 ] = MAX_TYPES*(rptr - state) + rand_type; + if( n < BREAK_1 ) { + if( n < BREAK_0 ) { + fprintf( stderr, "initstate: not enough state (%d bytes) with which to do jack; ignored.\n" ); + return; + } + rand_type = TYPE_0; + rand_deg = DEG_0; + rand_sep = SEP_0; + } + else { + if( n < BREAK_2 ) { + rand_type = TYPE_1; + rand_deg = DEG_1; + rand_sep = SEP_1; + } + else { + if( n < BREAK_3 ) { + rand_type = TYPE_2; + rand_deg = DEG_2; + rand_sep = SEP_2; + } + else { + if( n < BREAK_4 ) { + rand_type = TYPE_3; + rand_deg = DEG_3; + rand_sep = SEP_3; + } + else { + rand_type = TYPE_4; + rand_deg = DEG_4; + rand_sep = SEP_4; + } + } + } + } + state = &( ( (long *)arg_state )[1] ); /* first location */ + end_ptr = &state[ rand_deg ]; /* must set end_ptr before srandom */ + srandom( seed ); + if( rand_type == TYPE_0 ) state[ -1 ] = rand_type; + else state[ -1 ] = MAX_TYPES*(rptr - state) + rand_type; + return( ostate ); +} + + + +/* + * setstate: + * Restore the state from the given state array. + * Note: it is important that we also remember the locations of the pointers + * in the current state information, and restore the locations of the pointers + * from the old state information. This is done by multiplexing the pointer + * location into the zeroeth word of the state information. + * Note that due to the order in which things are done, it is OK to call + * setstate() with the same state as the current state. + * Returns a pointer to the old state information. + */ + +char * +setstate( arg_state ) + + char *arg_state; +{ + register long *new_state = (long *)arg_state; + register int type = new_state[0]%MAX_TYPES; + register int rear = new_state[0]/MAX_TYPES; + char *ostate = (char *)( &state[ -1 ] ); + + if( rand_type == TYPE_0 ) state[ -1 ] = rand_type; + else state[ -1 ] = MAX_TYPES*(rptr - state) + rand_type; + switch( type ) { + case TYPE_0: + case TYPE_1: + case TYPE_2: + case TYPE_3: + case TYPE_4: + rand_type = type; + rand_deg = degrees[ type ]; + rand_sep = seps[ type ]; + break; + + default: + fprintf( stderr, "setstate: state info has been munged; not changed.\n" ); + } + state = &new_state[ 1 ]; + if( rand_type != TYPE_0 ) { + rptr = &state[ rear ]; + fptr = &state[ (rear + rand_sep)%rand_deg ]; + } + end_ptr = &state[ rand_deg ]; /* set end_ptr too */ + return( ostate ); +} + + + +/* + * random: + * If we are using the trivial TYPE_0 R.N.G., just do the old linear + * congruential bit. Otherwise, we do our fancy trinomial stuff, which is the + * same in all ther other cases due to all the global variables that have been + * set up. The basic operation is to add the number at the rear pointer into + * the one at the front pointer. Then both pointers are advanced to the next + * location cyclically in the table. The value returned is the sum generated, + * reduced to 31 bits by throwing away the "least random" low bit. + * Note: the code takes advantage of the fact that both the front and + * rear pointers can't wrap on the same call by not testing the rear + * pointer if the front one has wrapped. + * Returns a 31-bit random number. + */ + +long +random() +{ + long i; + + if( rand_type == TYPE_0 ) { + i = state[0] = ( state[0]*1103515245 + 12345 )&0x7fffffff; + } + else { + *fptr += *rptr; + i = (*fptr >> 1)&0x7fffffff; /* chucking least random bit */ + if( ++fptr >= end_ptr ) { + fptr = state; + ++rptr; + } + else { + if( ++rptr >= end_ptr ) rptr = state; + } + } + return( i ); +} + +#endif NO_RANDOM diff --git a/src/games/fortune/scene b/src/games/fortune/scene new file mode 100644 index 0000000..b124453 --- /dev/null +++ b/src/games/fortune/scene @@ -0,0 +1,35245 @@ + *** + ******* + ********* + ****** Confucious say: "Is stuffy inside fortune cookie." + ******* + *** +%% + Has your family tried 'em? + + POWDERMILK BISCUITS + + Heavens, they're tasty and expeditious! + + They're made from whole wheat, to give shy persons + the strength to get up and do what needs to be done. + + POWDERMILK BISCUITS + + Buy them ready-made in the big blue box with the picture of + the biscuit on the front, or in the brown bag with the dark + stains that indicate freshness. +%% + 1/2 + /\(3) + | 2 1/3 + | z dz cos(3 * PI / 9) = ln (e ) + | + \/ 1 + +The integral of z squared, dz +From 1 to the square root of 3 + Times the cosine + Of 3 PI over nine +Is the log of the cube root of e +%% +* * * * * THIS TERMINAL IS IN USE * * * * * +%% +======================================================================= +|| || +|| The FORTUNE-COOKIE program is soon to be a Major Motion Picture! || +|| Watch for it at a theater near you next summer! || +|| || +======================================================================= + Francis Ford Coppola presents a George Lucas Production: + "Fortune Cookie" + Directed by Steven Spielberg. + Starring Harrison Ford Bette Midler Marlon Brando + Christopher Reeves Marilyn Chambers + and Bob Hope as "The Waiter". + Costumes Designed by Pierre Cardin. + Special Effects by Timothy Leary. + Read the Warner paperback! + Invoke the Unix program! + Soundtrack on XTC Records. + In 70mm and Dolby Stereo at selected theaters and terminal + centers. +%% + (1/2) + / 3 + | 2 3 x 3.14 (1/2) + | z dz cos (--------) = ln(e ) + / 1 9 + +The integral, from one to root three, +Of z to the second dz, + Times the cosine + Of 3 pi over nine +Is the log of the third root of e. +%% +=== ALL CSH USERS PLEASE NOTE ======================== + +Set the variable $LOSERS to all the people that you think are losers. This +will cause all said losers to have the variable $PEOPLE-WHO-THINK-I-AM-A-LOSER +updated in their .login file. Should you attempt to execute a job on a +machine with poor response time and a machine on your local net is currently +populated by losers, that machine will be freed up for your job through a +cold boot process. +%% +=== ALL USERS PLEASE NOTE ======================== + +A new system, the CIRCULATORY system, has been added. + +The long-experimental CIRCULATORY system has been released to users. The +Lisp Machine uses Type B fluid, the L machine uses Type A fluid. When the +switch to Common Lisp occurs both machines will, of course, be Type O. +Please check fluid level by using the DIP stick which is located in the +back of VMI monitors. Unchecked low fluid levels can cause poor paging +performance. +%% +=== ALL USERS PLEASE NOTE ======================== + +Bug reports now amount to an average of 12,853 per day. Unfortunately, +this is only a small fraction [ < 1% ] of the mail volume we receive. In +order that we may more expeditiously deal with these valuable messages, +please communicate them by one of the following paths: + + ARPA: WastebasketSLMHQ.ARPA + UUCP: [berkeley, seismo, harpo]!fubar!thekid!slmhq!wastebasket + Non-network sites: Federal Express to: + Wastebasket + Room NE43-926 + Copernicus, The Moon, 12345-6789 + For that personal contact feeling call 1-900-555-1212; our trained + operators are on call 24 hours a day. VISA/MC accepted.* + +* Our very rich lawyers have assured us that we are not + responsible for any errors or advice given over the phone. +%% +=== ALL USERS PLEASE NOTE ======================== + +CAR and CDR now return extra values. + +The function CAR now returns two values. Since it has to go to the trouble +to figure out if the object is carcdr-able anyway, we figured you might as +well get both halves at once. For example, the following code shows how to +destructure a cons (SOME-CONS) into its two slots (THE-CAR and THE-CDR): + + (MULTIPLE-VALUE-BIND (THE-CAR THE-CDR) (CAR SOME-CONS) ...) + +For symmetry with CAR, CDR returns a second value which is the CAR of the +object. In a related change, the functions MAKE-ARRAY and CONS have been +fixed so they don't allocate any storage except on the stack. This should +hopefully help people who don't like using the garbage collector because +it cold boots the machine so often. +%% +=== ALL USERS PLEASE NOTE ======================== + +Compiler optimizations have been made to macro expand LET into a WITHOUT- +INTERRUPTS special form so that it can PUSH things into a stack in the +LET-OPTIMIZATION area, SETQ the variables and then POP them back when it's +done. Don't worry about this unless you use multiprocessing. +Note that LET *could* have been defined by: + + (LET ((LET '`(LET ((LET ',LET)) + ,LET))) + `(LET ((LET ',LET)) + ,LET)) + +This is believed to speed up execution by as much as a factor of 1.01 or +3.50 depending on whether you believe our friendly marketing representatives. +This code was written by a new programmer here (we snatched him away from +Itty Bitti Machines where we was writting COUGHBOL code) so to give him +confidence we trusted his vows of "it works pretty well" and installed it. +%% +=== ALL USERS PLEASE NOTE ======================== + +JCL support as alternative to system menu. + +In our continuing effort to support languages other than LISP on the CADDR, +we have developed an OS/360-compatible JCL. This can be used as an +alternative to the standard system menu. Type System J to get to a JCL +interactive read-execute-diagnose loop window. [Note that for 360 +compatibility, all input lines are truncated to 80 characters.] This +window also maintains a mouse-sensitive display of critical job parameters +such as dataset allocation, core allocation, channels, etc. When a JCL +syntax error is detected or your job ABENDs, the window-oriented JCL +debugger is entered. The JCL debugger displays appropriate OS/360 error +messages (such as IEC703, "disk error") and allows you to dequeue your job. +%% +=== ALL USERS PLEASE NOTE ======================== + +The garbage collector now works. In addition a new, experimental garbage +collection algorithm has been installed. With SI:%DSK-GC-QLX-BITS set to 17, +(NOT the default) the old garbage collection algorithm remains in force; when +virtual storage is filled, the machine cold boots itself. With SI:%DSK-GC- +QLX-BITS set to 23, the new garbage collector is enabled. Unlike most garbage +collectors, the new gc starts its mark phase from the mind of the user, rather +than from the obarray. This allows the garbage collection of significantly +more Qs. As the garbage collector runs, it may ask you something like "Do you +remember what SI:RDTBL-TRANS does?", and if you can't give a reasonable answer +in thirty seconds, the symbol becomes a candidate for GCing. The variable +SI:%GC-QLX-LUSER-TM governs how long the GC waits before timing out the user. +%% +=== ALL USERS PLEASE NOTE ======================== + +There has been some confusion concerning MAPCAR. + (DEFUN MAPCAR (&FUNCTIONAL FCN &EVAL &REST LISTS) + (PROG (V P LP) + (SETQ P (LOCF V)) + L (SETQ LP LISTS) + (%START-FUNCTION-CALL FCN T (LENGTH LISTS) NIL) + L1 (OR LP (GO L2)) + (AND (NULL (CAR LP)) (RETURN V)) + (%PUSH (CAAR LP)) + (RPLACA LP (CDAR LP)) + (SETQ LP (CDR LP)) + (GO L1) + L2 (%FINISH-FUNCTION-CALL FCN T (LENGTH LISTS) NIL) + (SETQ LP (%POP)) + (RPLACD P (SETQ P (NCONS LP))) + (GO L))) +We hope this clears up the many questions we've had about it. +%% +**** CONVENTION REMINDER + +No experiment was approved for the convention by the Human Subjects +Committee of the Psychiatric Convention Planning Team. If you notice +smoke coming from under a closed door, if you find a body on the hotel +carpet, or if you just meet someone who orders you to press a button +marked "450 volts", react as you would normally. +%% +**** GROWTH CENTER REPAIR SERVICE + +For those who have had too much of Esalen, Topanga, and Kairos. +Tired of being genuine all the time? Would you like to learn how +to be a little phony again? Have you disclosed so much that you're +beginning to avoid people? Have you touched so many people that +they're all beginning to feel the same? Like to be a little dependent? +Are perfect orgasms beginning to bore you? Would you like, for once, +not to express a feeling? Or better yet, not be in touch with it at +all? Come to us. We promise to relieve you of the burden of your +great potential. +%% + *** A NEW KIND OF PROGRAMMING *** + +Do you want the instant respect that comes from being able to use technical +terms that nobody understands? Do you want to strike fear and loathing into +the hearts of DP managers everywhere? If so, then let the Famous Programmers' +School lead you on... into the world of professional computer programming. +They say a good programmer can write 20 lines of effective program per day. +With our unique training course, we'll show you how to write 20 lines of code +and lots more besides. Our training course covers every programming language +in existence, and some that aren't. You'll learn why the on/off switch for a +computer is so important, what the words *fatal error* mean, and who and what +you should blame when you make a mistake. + + Yes, I want the brochure describing this incredible offer. + I enclose $1000 is small unmarked bills to cover the cost of + postage and handling. (No live poultry, please.) + +*** Our Slogan: Top down programming for the masses. *** +%% +=============== ALL FRESHMEN PLEASE NOTE =============== + +To minimize scheduling confusion, please realize that if you are taking one +course which is offered at only one time on a given day, and another which is +offered at all times on that day, the second class will be arranged as to +afford maximum inconvenience to the student. For example, if you happen +to work on campus, you will have 1-2 hours between classes. If you commute, +there will be a minimum of 6 hours between the two classes. +%% +-- All articles that coruscate with resplendence are not truly auriferous. +-- When there are visible vapors having the prevenience in ignited + carbonaceous materials, there is conflagration. +-- Sorting on the part of mendicants must be interdicted. +-- A plethora of individuals wither expertise in culinary techniques vitiated + the potable concoction produced by steeping certain coupestibles. +-- Eleemosynary deeds have their initial incidence intramurally. +-- Male cadavers are incapable of yielding testimony. +-- Individuals who make their abode in vitreous edifices would be well + advised to refrain from catapulting projectiles. +%% + *** DO YOU HAVE A RESTLESS URGE TO PROGRAM? *** +Do you want the instant respect that comes from being able to use technical +terms that nobody understands? Do you want to strike fear and loathing into +the hearts of DP managers everywhere? If so, then let the Famous Programmers' +School lead you on... into the world of professional computer programming. + + *** IS PROGRAMMING FOR YOU? *** +Programming is not for everyone. But, if you have the desire to learn, we can +help you get started. All you need is the Famous Programmers' Course and +enough money to keep those lessons coming month after month. + + *** TAKE OUR FREE APTITUDE TEST *** +To help determine if you are qualified to be a programmer, take a moment to +try this simple test: + 1: Write down the numbers from zero to nine and the first six letters + of the alphabet (Hint: 0123456789ABCDEF). + 2: Whose picture is on the back of a twenty-dollar bill? + 3: What is the state capital of Idaho? +If you managed to read all three questions without wondering why we asked +them, you may have a future as a computer programmer. +%% +<<<<< EVACUATION ROUTE <<<<< +%% +**** IMPORTANT **** ALL USERS PLEASE NOTE **** + +Due to a recent systems overload error your recent disk files have been +erased. Therefore, in accordance with the UNIX Basic Manual, University of +Washington Geophysics Manual, and Bylaw 9(c), Section XII of the Revised +Federal Communications Act, you are being granted Temporary Disk Space, +valid for three months from this date, subject to the restrictions set forth +in Appendix II of the Federal Communications Handbook (18th edition) as well +as the references mentioned herein. You may apply for more disk space at any +time. Disk usage in or above the eighth percentile will secure the removal +of all restrictions and you will immediately receive your permanent disk +space. Disk usage in the sixth or seventh percentile will not effect the +validity of your temporary disk space, though its expiration date may be +extended for a period of up to three months. A score in the fifth percentile +or below will result in the withdrawal of your Temporary Disk space. +%% +>>> Internal error in fortune program: +>>> fnum=2987 n=45 flag=1 goose_level=-232323 +>>> Please write down these values and notify fortune program administrator. +%% +** MAXIMUM TERMINALS ACTIVE. TRY AGAIN LATER ** +%% +*** NEWSFLASH *** + Russian tanks steamrolling through New Jersey!!!! + Details at eleven! +%% +-- Neophyte's serendipity. +-- Exclusive dedication to necessitious chores without interludes of + hedonistic diversion renders John a hebetudinous fellow. +-- A revolving concretion of earthy or mineral matter accumulates no + congeries of small, green bryophytic plant. +-- The person presenting the ultimate cachinnation possesses thereby the + optimal cachinnation. +-- Abstention from any aleatory undertaking precludes a potential + escallation of a lucrative nature. +-- Missiles of ligneous or osteal consistency have the potential of + fracturing osseous structure, but appellations will eternally + remain innocuous. +%% + *** STUDENT SUCCESSES *** + +Many of our students have gone on to achieve great success in all fields of +programming. One former student developed the concept of the personalized +form letter. Does the phrase, "Dear Mr.(insert name), You may already be a +winner!," sound familiar? Another student writes "After only five lessons I +sold a "My Most Unforgettable Program" article to Corrosive Computing magazine. +Another of our graduates writes, "I recently completed a database-management +program for my department manager. My program touched him so deeply that he +was speechless. He told me later that he had never seen such a program in +his entire career. Thank you, Famous Programmers' school; only you could +have made this possible." Send for our introductory brochure which explains +in vague detail the operation of the Famous Programmers' School, and you'll +be eligible to win a possible chance to enter a drawing, the winner of which +can vie for a set of free steak knives. If you don't do it now, you'll hate +yourself in the morning. +%% +-- Scintillate, scintillate, asteroid minikin. +-- Members of an avian species of identical plumage congregate. +-- Surveillance should precede saltation. +-- Pulchritude possesses solely cutaneous profundity. +-- It is fruitless to become lachrymose over precipitately departed + lacteal fluid. +-- Freedom from incrustations of grime is contiguous to rectitude. +-- It is fruitless to attempt to indoctrinate a superannuated + canine with innovative maneuvers. +-- Eschew the implement of correction and vitiate the scion. +-- The temperature of the aqueous content of an unremittingly + galled saucepan does not reach 212 degrees Farenheit. +%% +***** Special AI Seminar (abstract) + +It has been widely recognized that AI programs require expert knowledge +in order to perform well in complex domains. But knowledge alone is not +sufficient for some applications; wisdom is needed as well. Accordingly, +we have developed a new approach to artificial intelligence which we call +"wisdom engineering". As a test of our ideas, we have written IMMANUEL, a +wisdom based system for the task domain of western philosophical thought. +IMMANUEL was supplied initially with 200 wisdom units which contained wisdom +about such elementary concepts as mind, matter, being, nothingness, and so +forth. IMMANUEL was then allowed to run freely, guided by the heuristic +rules contained in its heterarchically organized meta wisdom base. IMMANUEL +succeeded in rediscovering most of the important philosophical ideas developed +in western culture over the course of the last 25 centuries, including those +underlying Plato's theory of government, Kant's metaphysics, Nietzsche's theory +of value, and Husserl's phenomenology. In this seminar, we will describe +IMMANUEL's achievements and internal architecture. We will also briefly +discuss our recent efforts to apply wisdom engineering to oil exploration. +%% + U X +e dUdX, e dX, cosine, secant, tangent, sine, 3.14159... +%% +* UNIX is a Trademark of Bell Laboratories. +%% +<< WAIT >> +%% +: is not an identifier +%% +!07/11 PDP a ni deppart m'I !pleH +%% +[1] Alexander the Great was a great general. +[2] Great generals are forewarned. +[3] Forewarned is forearmed. +[4] Four is an even number. +[5] Four is certainly an odd number of arms for a man to have. +[6] The only number that is both even and odd is infinity. + Therefore, Alexander the Great had an infinite number of arms. +%% +[1] Alexander the Great was a great general. +[2] Great generals are forewarned. +[3] Forewarned is forearmed. +[4] Four is an even number. +[5] Four is certainly an odd number of arms for a man to have. +[6] The only number that is both even and odd is infinity. + Therefore, all horses are black. +%% +1) Everything depends. +2) Nothing is always. +3) Everything is sometimes. +%% +1) Never draw what you can copy. +2) Never copy what you can trace. +3) Never trace what you can cut out and paste down. +%% +1: No code table for op: ++post +%% +1) X=Y ; Given +2) X^2=XY ; Multiply both sides by X +3) X^2-Y^2=XY-Y^2 ; Subtract Y^2 from both sides +4) (X+Y)(X-Y)=Y(X-Y) ; Factor +5) X+Y=Y ; Cancel out (X-Y) term +6) 2Y=Y ; Substitute X for Y, by equation 1 +7) 2=1 ; Divide both sides by Y + -- "Omni", proof that 2 equals 1 +%% +1 bulls, 3 cows. +%% +$100 placed at 7 percent interest compounded quarterly for 200 years will +increase to more than $100,000,000 -- by which time it will be worth nothing. + -- Lazarus Long, "Time Enough For Love" +%% +10.0 times 0.1 is hardly ever 1.0. +%% + 12 + 144 + 20 + 3(4) 2 + ---------------------- + 5(11) = 9 + 0 + 7 + +A dozen, a gross and a score, +Plus three times the square root of four, + Divided by seven, + Plus five times eleven, +Equals nine squared plus zero, no more! +%% +13. ... r-q1 +%% +17. HO HUM -- The Redundant + +------- (7) This hexagram refers to a situation of extreme +--- --- (8) boredom. Your programs always bomb off. Your wife +------- (7) smells bad. Your children have hives. You are working +---O--- (6) on an accounting system, when you want to develop +---X--- (9) the GREAT AMERICAN COMPILER. You give up hot dates +--- --- (8) to nurse sick computers. What you need now is sex. + +Nine in the second place means: + The yellow bird approaches the malt shop. Misfortune. + +Six in the third place means: + In former times men built altars to honor the Internal + Revenue Service. Great Dragons! Are you in trouble! +%% +186,000 miles per second: +It isn't just a good idea, it's the law! +%% +1: A sheet of paper is an ink-lined plane. +2: An inclined plane is a slope up. +3: A slow pup is a lazy dog. + +QED: A sheet of paper is a lazy dog. + -- Willard Espy, "An Almanac of Words at Play" +%% +$3,000,000. +%% +355/113 -- + Not the famous irrational number PI, but an incredible simulation. +%% +3M, under the Scotch brand name, manufactures a fine adhesive for art +and display work. This product is called "Craft Mount". 3M suggests +that to obtain the best results, one should make the bond "while the +adhesive is wet, aggressively tacky." I did not know what "aggressively +tacky" meant until I read today's fortune. + + [And who said we didn't offer equal time, huh? Ed.] +%% +3rd Law of Computing: + Anything that can go wr +fortune: Segmentation violation -- Core dumped +%% +90% of the work takes 90% of the time. +The remaining 10% takes the other 90% of the time. +%% +94% of the women in America are beautiful +and the rest hang out around here. +%% +99 blocks of crud on the disk, +99 blocks of crud! +You patch a bug, and dump it again: +100 blocks of crud on the disk! + +100 blocks of crud on the disk, +100 blocks of crud! +You patch a bug, and dump it again: +101 blocks of crud on the disk! +%% +A truly great man will neither trample on a worm nor sneak to an emperor. + -- B. Franklin +%% +A CONS is an object which cares. + -- Bernie Greenberg. +%% +A Fortran compiler is the hobgoblin of little minis. +%% +A LISP programmer knows the value of +everything, but the cost of nothing. + -- Alan Perlis +%% +A Law of Computer Programming: + Make it possible for programmers to write in English + and you will find that programmers cannot write in English. +%% +A Mormon is a man that has the bad taste and the religion to do what a good +many other people are restrained from doing by conscientious scruples and +the police. + -- Mr. Dooley +%% +A Nixon [is preferable to] a Dean Rusk -- who will be +passionately wrong with a high sense of consistency. + -- J.K. Galbraith +%% +A Polish worker walks into a bank to deposit his paycheck. He has heard +about Poland's economic problems, and he asks what would happen to his +money if the bank collapsed. "All of our deposits are guaranteed by the +finance ministry, sir," the teller replies. + "But what if the finance ministry goes broke?" the worker asks. + "Then the government will intercede to protect the working class," +the teller says. + "But what if the government goes broke?" the worker asks. + "Our socialist comrades in the Soviet Union naturally will come +to our assistance," the teller responds with growing irritation. + "And if the Soviet Union goes broke?" the worker asks. + "Idiot!" the teller snorts. "Isn't that worth losing one lousy +paycheck?" + -- Making the rounds in Warsaw, 1984 +%% +A Puritan is someone who is deathly +afraid that someone, somewhere is having fun. +%% +A Roman divorced from his wife, being highly blamed by his friends, who +demanded, "Was she not chaste? Was she not fair? Was she not fruitful?" +holding out his shoe, asked them whether it was not new and well made. +Yet, added he, none of you can tell where it pinches me. + -- Plutarch +%% +A Severe Strain on the Credulity + As a method of sending a missile to the higher, and even to the +highest parts of the earth's atmospheric envelope, Professor Goddard's rocket +is a practicable and therefore promising device. It is when one considers the +multiple-charge rocket as a traveler to the moon that one begins to doubt... +for after the rocket quits our air and really starts on its journey, its +flight would be neither accelerated nor maintained by the explosion of the +charges it then might have left. Professor Goddard, with his "chair" in +Clark College and countenancing of the Smithsonian Institution, does not +know the relation of action to re-action, and of the need to have something +better than a vacuum against which to react... Of course he only seems to +lack the knowledge ladled out daily in high schools. + -- New York Times Editorial, 1920 +%% +A Smith & Wesson beats four aces. +%% +A baby is an alimentary canal with a loud voice +at one end and no responsibility at the other. +%% +A bachelor is a selfish, undeserving guy +who has cheated some woman out of a divorce. + -- Don Quinn +%% +A banker is a fellow who lends you his umbrella when the +sun is shining and wants it back the minute it begins to rain. + -- Mark Twain +%% +A bather whose clothing was strewed +By breezes that left her quite nude, + Saw a man come along + And, unless I'm quite wrong, +You expected this line to be lewd. +%% +A beautiful woman is a blessing from Heaven, but a good cigar is a smoke. + -- Kipling +%% +A beautiful woman is a picture which drives all beholders nobly mad. + -- Emerson +%% +A beginning is the time for taking the +most delicate care that balances are correct. + -- Princess Irulan, "Manual of Maud'Dib" +%% +A billion here, a couple of billion there-- +first thing you know it adds up to be real money. + -- Everett Dirksen +%% +A bird in the hand is worth two in the bush. + -- Cervantes +%% +A bird in the hand is worth what it will bring. +%% +A bit of talcum +Is always walcum + -- Ogden Nash +%% +A black cat crossing your path signifies +that the animal is going somewhere. + -- Groucho Marx +%% +A book is the work of a mind, doing its work in the way that a mind deems +best. That's dangerous. Is the work of some mere individual mind likely to +serve the aims of collectively accepted compromises, which are known in the +schools as 'standards'? Any mind that would audaciously put itself forth to +work all alone is surely a bad example for the students, and probably, if +not downright antisocial, at least a little off-center, self-indulgent, +elitist. ... It's just good pedagogy, therefore, to stay away from such +stuff, and use instead, if film-strips and rap-sessions must be +supplemented, 'texts,' selected, or prepared, or adapted, by real +professionals. Those texts are called 'reading material.' They are the +academic equivalent of the 'listening material' that fills waiting-rooms, +and the 'eating material' that you can buy in thousands of convenient eating +resource centers along the roads. + -- The Underground Grammarian +%% +A bore is a man who talks so much about +himself that you can't talk about yourself. +%% +A bore is someone who persists in holding his +own views after we have enlightened him with ours. +%% +A boss with no humor is like a job that's no fun. +%% +A box without hinges, key, or lid, +Yet golden treasure inside is hid. + -- J.R. Tolkien +%% +A boy gets to be a man when a man is needed. + -- John Steinbeck +%% +A budget is just a method of worrying +before you spend money, as well as afterward. +%% +A bug in the code is worth two in the documentation. +%% +A bug in the hand is better than one as yet undetected. +%% +A bunch of the boys were whooping it in the Malemute saloon; +The kid that handles the music box was hitting a jag-time tune; +Back of the bar, in a solo game, sat Dangerous Dan McGrew, +And watching his luck was his light-o'-love, the lady that's known as Lou. + -- Robert W. Service +%% +A bureaucrat's idea of cleaning up his files +is to make a copy of everything before he destroys it. +%% +A burleyque dancer, a pip +Named Virginia, could peel in a zip; + But she read science fiction + And died of constriction +Attempting a Moebius strip. + -- Cyril Kornbluth, "The Unfortunate Topology" +%% + A business executive is consumed by jealousy: he suspects his wife +of cheating on him. The suspicion grows and grows, and one morning as he +drives to work he can't take it any more. He thinks to himself, "she +probably just waited until I left so she could meet with her lover." + When he gets to his office, he calls home. The maid answers. He +says, "Hello. Is my wife there?" + "Yes, sir", the maid whispers. + "Is she with her lover?" + The maid pauses, and then says, "Yes, sir, she is, and I must say +that I feel terrible about how she treats you." + The man yells, "That no good **#*&!!. If you feel as badly as you +say you do, you must do this for me: go to my dresser and get my gun. Check +to make sure that it's loaded. Then go upstairs and shoot both that cheating +two-timing whore and her lover. Dispose of the gun, and then come back to +the phone and tell me that it's over. Don't worry -- I'll protect you." +The man hears footsteps, a drawer being opened, a click, more footsteps, +silence... and then two shots. More footsteps. Finally the maid comes back +to the phone and says "It's done." + The man asks, "What did you do with the gun?" + "I threw it behind the statue in the garden", the maid replies. + "Statue in the garden? Say, what number is this, anyway?" +%% +A businessman is a hybrid of a dancer and a calculator. + -- Paul Valery +%% +A candidate is a person who gets money from the rich +and votes from the poor to protect them from each other. +%% +A castaway was washed ashore after many days on the open sea. The island +on which he landed was populated by savage cannibals who tied him, dazed +and exhausted, to a thick stake. They then proceeded to cut his arms +with their spears and drink his blood. This continued for several days +until the castaway could stand no more. He yelled for the cannibal chief +and declared, "You can kill me if you want to, but this torture with the +spears has got to stop. Dammit, I'm tired of getting stuck for the drinks." +%% +A cauliflower is nothing but cabbage with a college education. + -- Mark Twain +%% +A celebrity is a person who is known for his well-knownness. +%% +A certain amount of opposition is a help, not a hindrance. +Kites rise against the wind, not with it. +%% +A certain monk had a habit of pestering the Grand Tortue (the only one who +had ever reached the Enlightenment 'Yond Enlightenment), by asking whether +various objects had Buddha-nature or not. To such a question Tortue +invariably sat silent. The monk had already asked about a bean, a lake, +and a moonlit night. One day he brought to Tortue a piece of string, and +asked the same question. In reply, the Grand Tortue grasped the loop +between his feet and, with a few simple manipulations, created a complex +string which he proferred wordlessly to the monk. At that moment, the monk +was enlightened. + +From then on, the monk did not bother Tortue. Instead, he made string after +string by Tortue's method; and he passed the method on to his own disciples, +who passed it on to theirs. +%% +A chicken is an egg's way of producing more eggs. +%% +A chronic disposition to inquiry +deprives domestic felines of vital qualities. +%% +A chubby man with a white beard and a red suit +will approach you soon. Avoid him. He's a Commie. +%% +A city is a large community where people are lonesome together. + -- Herbert Prochnow +%% +A clash of doctrine is not a disaster - it is an opportunity. +%% +A classic is something +that everyone wants to have read and nobody wants to read. + -- Mark Twain +%% +A clever prophet makes sure of the event first. +%% +A closed mouth gathers no foot. +%% +A cloud does not know why it moves in just such a direction and at such +a speed, if feels an impulsion... this is the place to go now. But the +sky knows the reasons and the patterns behind all clouds, and you will +know, too, when you lift yourself high enough to see beyond horizons. + -- Messiah's Handbook : Reminders for the Advanced Soul +%% +A committee is a life form with six or more legs and no brain. + -- Lazarus Long, "Time Enough For Love" +%% +A committee takes root and grows, it flowers, wilts and dies, +scattering the seed from which other committees will bloom. + -- Parkinson +%% +A commune is where people join together to share their lack of wealth. + -- R. Stallman +%% +A company is known by the men it keeps. +%% +A complex system that works is invariably +found to have evolved from a simple system that works. +%% +A compliment is something like a kiss through a veil. + -- Victor Hugo +%% +A computer called Illiac4 +Had a rather tough bug in its core. + It chewed up its cards + And spewed yards and yards +Of illegible tape on the floor. +%% +A computer salesman visits a company president for the purpose of selling +the president one of the latest talking computers. +Salesman: "This machine knows everything. I can ask it any quesstion + and it'll give the correct answer. Computer, what is the + speed of light?" +Computer: 186,000 miles per second. +Salesman: "Who was the first president of the United States?" +Computer: George Washington. +President: "I'm still not convinced. Let me ask a question. + Where is my father?" +Computer: Your father is fishing in Georgia. +President: "Hah!! The computer is wrong. My father died over twenty + years ago!" +Computer: Your mother's husband died 22 years ago. Your father just + landed a twelve pound bass. +%% +A computer scientist is someone who fixes things that aren't broken. +%% +A computer, to print out a fact, +Will divide, multiply, and subtract. + But this output can be + No more than debris, +If the input was short of exact. + -- Gigo +%% +A conclusion is simply the place where someone got tired of thinking. +%% +A conservative is a man +who believes that nothing should be done for the first time. + -- Alfred E. Wiggam +%% +A conservative is a man +with two perfectly good legs who has never learned to walk. + -- Franklin D. Roosevelt +%% +A conservative is one who is too cowardly to fight and too fat to run. +%% +A couch is as good as a chair. +%% +A countryman between two lawyers is like a fish between two cats. + -- B. Franklin +%% +A couple more shots of whiskey, women 'round here start looking good. + + [something about a 10 being a 4 after a six-pack? Ed.] +%% +A cousin of mine once said about money, +money is always there but the pockets change; +it is not in the same pockets after a change, +and that is all there is to say about money. + -- Gertrude Stein +%% +A "critic" is a man who creates nothing and thereby feels +qualified to judge the work of creative men. There is logic +in this; he is unbiased -- he hates all creative people equally. +%% +A crusader's wife slipped from the garrison +And had an affair with a Saracen. + She was not oversexed, + Or jealous or vexed, +She just wanted to make a comparison. +%% +A day for firm decisions!!!!! Or is it? +%% +A day without orange juice is like a day without orange juice. +%% +A day without sunshine is like a day without Anita Bryant. +%% +A day without sunshine is like a day without orange juice. +%% +A day without sunshine is like night. +%% +A dead man cannot bite. + -- Gnaeus Pompeius (Pompey) +%% +A debugged program is one for which you have +not yet found the conditions that make it fail. + -- Jerry Ogdin +%% +A decade after Vietnam, we still cannot understand why "their" +Salvadorans fight better than "our" Salvadorans. It is not a matter of +their training or their equipment. It has to do with the quality of the +society we are asking them to risk death defending. The metaphor of the +domino obscures this reality, and the cost our self-imposed blindness +is high. San Salvador is closer to Saigon than to Munich. + -- William LeoGrande, "New York Times", 3/9/83 +%% +A diplomat is a man who can convince his +wife she'd look stout in a fur coat. +%% +A diplomat is a man who can tell you to +go to hell and make the trip sound pleasurable. + -- Samuel Clemens +%% +A diplomat is man who always remembers a woman's birthday but never her age. + -- Robert Frost +%% +A diplomat is someone who can tell you to go to hell +in such a way that you will look forward to the trip. +%% +A diplomat's life consists of three things: protocol, Geritol, and alcohol. + -- Adlai Stevenson +%% + A disciple of another sect once came to Drescher as he was eating +his morning meal. "I would like to give you this personality test", said +the outsider, "because I want you to be happy." + Drescher took the paper that was offered him and put it into the +toaster -- "I wish the toaster to be happy too". +%% +A diva who specializes in risque arias is an off-coloratura soprano. +%% + A doctor, an architect, and a computer scientist were arguing about +whose profession was the oldest. In the course of their arguments, they +got all the way back to the Garden of Eden, whereupon the doctor said, "The +medical profession is clearly the oldest, because Eve was made from Adam's +rib, as the story goes, and that was a simply incredible surgical feat." + The architect did not agree. He said, "But if you look at the Garden +itself, in the beginning there was chaos and void, and out of that the Garden +and the world were created. So God must have been an architect." + The computer scientist, who'd listened carefully to all of this, then +commented, "Yes, but where do you think the chaos came from?" +%% +A door is what a dog is perpetually on the wrong side of. + -- Ogden Nash +%% +A dreary young bank clerk named Fennis +Wished to foster an aura of menace. + To make people afraid + He wore gloves of grey suede +And white footgear intended for tennis. + -- Edward Gorey, "Amphigorey" +%% +A fail-safe circuit will destroy others. + -- Klipstein +%% +A failure will not appear until a unit has passed final inspection. +%% +A fair exterior is a silent recommendation. + -- Publilius Syrus +%% +A fake fortuneteller can be tolerated. But an authentic soothsayer +should be shot on sight. Cassandra did not get half the kicking around +she deserved. + -- R.A. Heinlein +%% +A famous Lisp Hacker noticed an Undergraduate sitting in front of a Xerox +1108, trying to edit a complex Klone network via a browser. Wanting to help, +the Hacker clicked one of the nodes in the network with the mouse, and asked +"what do you see?" Very earnestly, the Undergraduate replied, "I see a +cursor." The Hacker then quickly pressed the boot toggle at the back of +the keyboard, while simultaneously hitting the Undergraduate over the head +with a thick Interlisp Manual. The Undergraduate was then Enlightened. +%% +A fanatic is one who can't change his mind and won't change the subject. + -- Winston Churchill +%% +A farmer is a man outstanding in his field. +%% +A few hours grace before the madness begins again. +%% +A fitter fits; Though sinners sin +A cutter cuts; And thinners thin +And an aircraft spotter spots; And paper-blotters blot +A baby-sitter I've never yet +Baby-sits -- Had letters let +But an otter never ots. Or seen an otter ot. + +A batter bats +(Or scatters scats); +A potting shed's for potting; +But no one's found +A bounder bound +Or caught an otter otting. + -- Ralph Lewin +%% +A fool and his honey are soon parted. +%% +A fool and his money are soon popular. +%% +A fool and your money are soon partners. +%% +A fool must now and then be right by chance. +%% +A foolish consistency is the hobgoblin of little minds. + -- Ralph Waldo Emerson +%% +A fool-proof method for sculpting an elephant: first, get a huge block +of marble; then you chip away everything that doesn't look like an elephant. +%% +A fool's brain digests philosophy into folly, science into +superstition, and art into pedantry. Hence University education. + -- G.B. Shaw +%% +A formal parsing algorithm should not always be used. + -- D. Gries +%% +A friend in need is a pest indeed. +%% +A full belly makes a dull brain. + -- Ben Franklin + + [and the local candy machine man. Ed] +%% +A furore Normanorum libera nos, O Domine! +%% +A gambler's biggest thrill is winning a bet. +His next biggest thrill is losing a bet. +%% +A game can by God repent or we'll punish it. +That's how they did it in Salem in the seventeenth century, +and that's how we'll do it now. + -- Dick Hamlet +%% +A geneticist living in Delft +Scientifically played with himself, + And when he was done + He labled it: son, +And filed him away on a shelf. +%% +A gift of a flower will soon be made to you. +%% +A gleekzorp without a tornpee is like +a quop without a fertsneet (sort of). +%% +A good memory does not equal pale ink. +%% +A good plan today is better than a perfect plan tomorrow. + -- Patton +%% +A good reputation is more valuable than money. + -- Publilius Syrus +%% +A good scapegoat is hard to find. +%% +A good supervisor can step on your toes without messing up your shine. +%% +A great empire, like a great cake, is most easily diminished at the edges. + -- B. Franklin +%% +A great many people think they are thinking +when they are merely rearranging their prejudices. + -- William James +%% +A guy has to get fresh once in a while +so a girl doesn't lose her confidence. +%% + A guy returns from a long trip to Europe, having left his beloved +dog in his brother's care. The minute he's cleared customs, he calls up his +brother and inquires after his pet. + "Your dog's dead," replies his brother bluntly. + The guy is devastated. "You know how much that dog meant to me," +he moaned into the phone. "Couldn't you at least have thought of a nicer way +of breaking the news? Couldn't you have said, `Well, you know, the dog got +outside one day, and was crossing the street, and a car was speeding around a +corner...' or something...? Why are you always so thoughtless?" + "Look, I'm sorry," said his brother, "I guess I just didn't think." + "Okay, okay, let's just put it behind us. How are you anyway? +How's Mom?" + His brother is silent a moment. "Uh," he stammers, "uh... Mom got +outside one day..." +%% +A hacker does for love what others would not do for money. +%% +A halted retreat +Is nerve-wracking and dangerous. +To retain people as men -- and maidservants +Brings good fortune. +%% +A hammer sometimes misses its mark - a bouquet never. +%% +A handful of friends is worth more than a wagon of gold. +%% +A handful of patience is worth more than a bushel of brains. +%% +A handsome young rodent named Gratian +As a lifeguard became a sensation. + All the lady mice waved + And screamed to be saved +By his mouse-to-mouse resuscitation. +%% +A hearty young fellow named Yost +Once had an affair with a ghost. + At the height of the spasm + The poor ectoplasm +Cried, "Goodie, I feel it... almost." +%% +A hermit is a deserter from the army of humanity. +%% +A holding company is a thing where you hand +an accomplice the goods while the policeman searches you. +%% +A homeowner's reach should exceed his grasp, or what's a weekend for? +%% +A horse! A horse! My kingdom for a horse! + -- Wm. Shakespeare, "Henry VI" +%% +A joker who haunts Monticello +Is really a terrible fellow. + In the midst of caresses + He fills ladies dresses +With garter snakes, ice cubes, and jello. +%% +A journey of a thousand miles begins with a cash advance from Sam. +%% +A journey of a thousand miles must begin with a single step. + -- Lao Tsu +%% +A journey of a thousand miles starts under one's feet. + -- Lao Tsu +%% +A jug of wine, a bowl of rice with it; +Earthen vessels +Simply handed in through the window. +There is certainly no blame in this. +%% +A kid'll eat the middle of an Oreo, eventually. +%% +A king's castle is his home. +%% +A kiss is a course of procedure, cunningly devised, +for the mutual stoppage of speech at a moment when +words are superfluous. +%% +A lack of leadership is no substitute for inaction. +%% +A lady with one of her ears applied +To an open keyhole heard, inside, +Two female gossips in converse free -- +The subject engaging them was she. +"I think", said one, "and my husband thinks +That she's a prying, inquisitive minx!" +As soon as no more of it she could hear +The lady, indignant, removed her ear. +"I will not stay," she said with a pout, +"To hear my character lied about!" + -- Gopete Sherany +%% +A language that doesn't affect the way you +think about programming is not worth knowing. +%% +A language that doesn't have everything is +actually easier to program in than some that do. + -- D.M. Ritchie +%% +A large number of installed systems work by fiat. +That is, they work by being declared to work. + -- Anatol Holt +%% +A large spider in an old house built a beautiful web in which to catch flies. +Every time a fly landed on the web and was entangled in it the spider devoured +him, so that when another fly came along he would think the web was a safe and +quiet place in which to rest. One day a fairly intelligent fly buzzed around +above the web so long without lighting that the spider appeared and said, +"Come on down." But the fly was too clever for him and said, "I never light +where I don't see other flies and I don't see any other flies in your house." +So he flew away until he came to a place where there were a great many other +flies. He was about to settle down among them when a bee buzzed up and said, +"Hold it, stupid, that's flypaper. All those flies are trapped." "Don't be +silly," said the fly, "they're dancing." So he settled down and became stuck +to the flypaper with all the other flies. + +Moral: There is no safety in numbers, or in anything else. + -- James Thurber, "The Fairly Intelligent Fly" +%% +A liberal is someone too poor to be a +capitalist, and too rich to be a communist. +%% +A lie in time saves nine. +%% +A lifetime isn't nearly long enough to figure out what it's all about. +%% +A light wife doth make a heavy husband. + -- Wm. Shakespeare, "The Merchant of Venice" +%% +A likely impossibility is always preferable to an unconvincing possibility. + -- Aristotle +%% +A limerick packs laughs anatomical +Into space that is quite economical. + But the good ones I've seen + So seldom are clean, +And the clean ones so seldom are comical. +%% +A linguist thought it a farce +That memory space was so sparse. + One day they increased it. + Said he as he seized it: +"At last! Enough core for the parse". +%% +A list is only as strong as its weakest link. + -- Don Knuth +%% +A little bit of rape is good for a man's soul. + -- Norman Mailer +%% + A little dog goes into a saloon in the Wild West, and beckons to +the bartender. "Hey, bartender, gimmie a whiskey." + The bartender ignores him. + "Hey bartender, gimmie a whiskey." + Still ignored. + "HEY BARMAN!! GIMMIE A WHISKEY!!" + The bartender takes out his six-shooter and shoots the dog in the +leg, and the dog runs out the saloon, howling in pain. + Three years later, the wee dog appears again, wearing boots, +jeans, chaps, a Stetson, gun belt, and guns. He ambles slowly into the +saloon, goes up to the bar, leans over it, and says to the bartender, +"I'm here t'git the man that shot muh paw." +%% +A little experience often upsets a lot of theory. +%% +A little inaccuracy sometimes saves tons of explanation. + -- H.H. Munro, "Saki" +%% +A log may float in a river, but that does not make it a crocodile. +%% +A long-forgotten loved one will appear soon. +Buy the negatives at any price. +%% +A lost ounce of gold may be found, a lost moment of time never. +%% +A lot of people I know believe in positive thinking, +and so do I. I believe everything positively stinks. + -- Lew Col +%% +A lovely young diver named Nancy, +Wore a bikini bottom quite chancy, + The fish of Bonaire, + Watched her Derriere, +And the sea fans all tickled her fancy. +%% +A lovely young maid from St. Jude +Once rode through the streets in the nude. + The police cried, "Whatam-- + Agnificent bottom" +And slapped it as hard as they could. +%% +A man always needs to remember one thing about +a pretty girl. Somewhere, somebody's tired of her. +%% +A man fell off a mountain and, as he fell, saw a branch and grabbed for it. +By superhuman effort he was able to get a precarious grip on it. As he +was hanging there for dear life, he looked up and cried out, + "Is anybody there?" +A deep majestic voice answered, + "Yes my son, I am here. What do you need?" + "Help me!!" cried the man. + "I will help you", said the voice, "just let go of the branch and +you'll be safe. All you have to do is trust." +The man thought for a moment and cried out: + "Anybody ELSE up there?" +%% + A man from AI walked across the mountains to SAIL to see the Master, +Knuth. When he arrived, the Master was nowhere to be found. "Where is the +wise one named Knuth?" he asked a passing student. + "Ah," said the student, "you have not heard. He has gone on a +pilgrimage across the mountains to the temple of AI to seek out new +disciples." + Hearing this, the man was Enlightened. +%% +A man is incomplete until he is married; then he's really finished. +%% +A man is known by the company he organizes. + -- A. Bierce +%% +A man may be so much of everything that he is nothing of anything. + -- Samuel Johnson +%% +A man may sometimes be forgiven the kiss to which he is not entitled, +but never the kiss he has not the initiative to claim. +%% +A man may well bring a horse to the water, +but he cannot make him drink with he will. + -- John Heywood +%% +A man of genius makes no mistakes. +His errors are volitional and are the portals of discovery. + -- James Joyce, "Ulysses" +%% +A man paints with his brains and not with his hands. +%% +A man said to the Universe: + "Sir, I exist!" + "However," replied the Universe, + "the fact has not created in me a sense of obligation." + -- Stephen Crane +%% +A man was kneeling by a grave in a cemetery, crying and praying very loudly, + "Oh why..eeeee did you die...eeeeee, Oh Why..eeeeee, +why did you Di......eeee" +The caretaker walks up, pardons himself and asks politely, + "Excuse me, sir, but I've been seeing you for hours now, +carrying on at this grave. You must have been very close to the deceased." + "No, I never met him. Oh why....eeeee did you dieeeeee, +why....eeeee did you.." + "Sir, you say you never met this person, yet you carry on so? +Tell, me who is buried here?" + "My wife's first husband." +%% +A man who cannot seduce men cannot save them either. + -- Soren Kierkegaard +%% +A man who fishes for marlin in ponds +will put his money in Etruscan bonds. +%% +A man who turns green has eschewed protein. +%% +A man with 3 wings and a dictionary is cousin to the turkey. +%% +A man with one watch knows what time it is. +A man with two watches is never quite sure. +%% +A man without a woman is like a fish without gills. +%% +A man would still do something out of sheer perversity - he would create +destruction and chaos - just to gain his point... and if all this could in +turn be analyzed and prevented by predicting that it would occur, then man +would deliberately go mad to prove his point. + -- Feodor Dostoevsky, "Notes From the Underground" +%% +A man wrapped up in himself makes a very small package. +%% +A man's best friend is his dogma. +%% +A man's gotta know his limitations. + -- Clint Eastwood, "Dirty Harry" +%% +A man's house is his castle. + -- Sir Edward Coke +%% +A man's house is his hassle. +%% +A master was asked the question, "What is the Way?" by a curious monk. + "It is right before your eyes," said the master. + "Why do I not see it for myself?" + "Because you are thinking of yourself." + "What about you: do you see it?" + "So long as you see double, saying `I don't', and `you do', and so +on, your eyes are clouded," said the master. + "When there is neither `I' nor `You', can one see it?" + "When there is neither `I' nor `You', +who is the one that wants to see it?" +%% +A mathematician named Klein +Thought the Mobius band was divine. + Said he, "If you glue + The edges of two, +You'll get a weird bottle like mine! +%% +A meeting is an event at which the +minutes are kept and the hours are lost. +%% +A method of solution is perfect if we can forsee from the start, +and even prove, that following that method we shall attain our aim. + -- Leibnitz +%% +A mighty creature is the germ, +Though smaller than the pachyderm. +His customary dwelling place +Is deep within the human race. +His childish pride he often pleases +By giving people strange diseases. +Do you, my poppet, feel infirm? +You probably contain a germ. + -- Ogden Nash +%% +A modem is a baudy house. +%% +A modest woman, dressed out in all her finery, +is the most tremendous object in the whole creation. + -- Goldsmith +%% +A mother takes twenty years to make a man of her boy, +and another woman makes a fool of him in twenty minutes. + -- Frost +%% +A motion to adjourn is always in order. +%% +A mouse is an elephant built by the Japanese. +%% +A mushroom cloud has no silver lining. +%% +A musician, an artist, an architect: + the man or woman who is not one of these is not a Christian. + -- William Blake +%% + A musician of more ambition than talent composed an elegy at +the death of composer Edward MacDowell. She played the elegy for the +pianist Josef Hoffman, then asked his opinion. "Well, it's quite +nice," he replied, but don't you think it would be better if..." + "If what?" asked the composer. + "If ... if you had died and MacDowell had written the elegy?" +%% +A nasty looking dwarf throws a knife at you. +%% +A national debt, if it is not excessive, +will be to us a national blessing. + -- Alexander Hamilton +%% +A new dramatist of the absurd +Has a voice that will shortly be heard. + I learn from my spies + He's about to devise +An unprintable three-letter word. +%% +A new koan: + If you have some ice cream, I will give it to you. + If you have no ice cream, I will take it away from you. +It is an ice cream koan. +%% +A new supply of round tuits has arrived and are available from Mary. +Anyone who has been putting off work until they got a `round tuit' +now has no excuse for further procrastination. +%% +A new taste had been acquired and a new appetite began to grow. The time +had long since arrived to crush the technical intelligentsia, which had +come to regard itself as too irreplaceable and had not gotten used to +catching instructions on the wing. In other words, we never did trust +the engineers - and from the very first years of the Revolution we saw to +it that those lackeys and servants of former capitalist bosses were kept +in line by healthy suspicion and surveillance by the workers. + -- Aleksandr I. Solzhenitsyn, "The Gulag Archipelago" +%% +A newspaper is a circulating library with high blood pressure. + -- Arthure "Bugs" Baer +%% + A novice was trying to fix a broken lisp machine by turning the +power off and on. Knight, seeing what the student was doing spoke sternly, +"You cannot fix a machine by just power-cycling it with no understanding +of what is going wrong." Knight turned the machine off and on. The +machine worked. +%% +A nubile female virtually never experiences difficulty in finding willing +sexual partners, and in a natural habitat nubile females are probably always +married. The basic female "strategy" is to obtain the best possible husband, +to be fertilized by the fittest available male (always, of course, taking +risk into account), and to maximize the returns on sexual favors bestowed: +to be sexually aroused by the sight of males would promote random matings, +thus undermining all of these aims, and would also waste time and energy +that could be spent in economically significant activities and in nurturing +children. A female's reproductive success would be seriously compromised +by the propensity to be sexually aroused by the sight of males. + -- Donald Symons, "The Evolution of Human Sexuality", + attempting to explain the lack of female interest in + pornography. +%% +A nuclear war can ruin your whole day. +%% +A pencil with no point needs no eraser. +%% +A penny saved has not been spent. +%% +A penny saved is a penny taxed. +%% +A penny saved is ridiculous. +%% +A perfectly honest woman, a woman who never flatters, who never manages, +who never cajoles, who never conceals, who never uses her eyes, who never +speculates on the effect which she produces, who never is conscious of +unspoken admiration, what a monster, I say, would such a female be! + -- Thackeray +%% +A person forgives only when they are in the wrong. +%% +A person is just about as big as the things that make him angry. +%% +A person who has nothing looks at all there is and wants something. +A person who has something looks at all there is and wants all the rest. +%% +A person who is more than casually interested +in computers should be well schooled in machine +language, since it is a fundamental part of a computer. + -- Donald Knuth +%% +A physicist is an atom's way of knowing about atoms. + -- George Wald +%% +A pipe gives a wise man time to think +and a fool something to stick in his mouth. +%% +A plethora of individuals with expertise in culinary techniques +contaminate the potable concoction produced by steeping certain +edible nutriments. +%% +A plucked goose doesn't lay golden eggs. +%% +A poet who reads his verse in public may have other nasty habits. +%% +A political man can have as his aim the realization of freedom, +but he has no means to realize it other than through violence. + -- Jean Paul Sartre +%% +A possum must be himself, and being himself he is honest. + -- Walt Kelly +%% +A pound of salt will not sweeten a single cup of tea. +%% +A "practical joker" deserves applause for his wit according to its quality. +Bastinado is about right. For exceptional wit one might grant keelhauling. +But staking him out on an anthill should be reserved for the very wittiest. + -- Lazarus Long +%% +A prediction is worth twenty explanations. + -- K. Brecher +%% +A pretty woman can do anything; an ugly woman must do everything. +%% +A priest asked: What is Fate, Master? + + And the Master answered: + It is that which gives a beast of burden its reason for existence. +It is that which men in former times had to bear upon their backs. + + It is that which has caused nations to build byways from City +to City upon which carts and coaches pass, and alongside which inns +have come to be built to stave off Hunger, Thirst and Weariness. + + And that is Fate? said the priest. + + Fate... I thought you said Freight, responded the Master. + + That's all right, said the priest. I wanted to know +what Freight was too. + -- Kehlog Albran +%% +A prig is a fellow who is always making you a present of his opinions. + -- George Eliot +%% +A princess who lived near a bog +Met a prince in the form of a frog. + Now she and her prince + Are the parents of quints, +Four boys and one fine polliwog. +%% +A private sin is not so prejudicial in the world as a public indecency. + -- Miguel de Cervantes +%% +A professor is one who talks in someone else's sleep. +%% +A programmer down in Moline +Said, I'm the match for any machine. + My secret's aversion, + To loops and recursion, +Just acres of in-line routine. + -- W.J. Wilson +%% +A programmer is a person who passes as an exacting expert on the basis of +being able to turn out, after innumerable punching, an infinite series of +incomprehensible answers calculated with micrometric precisions from vague +assumptions based on debatable figures taken from inconclusive documents +and carried out on instruments of problematical accuracy by persons of +dubious reliability and questionable mentality for the avowed purpose of +annoying and confounding a hopelessly defenseless department that was +unfortunate enough to ask for the information in the first place. + -- IEEE Grid newsmagazine +%% +A programming language is low level +when its programs require attention to the irrelevant. +%% +A progressive professor named Winners +Held classes each evening for sinners. + They were graded and spaced + So the vile and debased +Would not be held back by beginners. +%% +A prominent broadcaster, on a big-game safari in Africa, was taken to a +watering hole where the life of the jungle could be observed. As he +looked down from his tree platform and described the scene into his +tape recorder, he saw two gnus grazing peacefully. So preoccupied were +they that they failed to observe the approach of a pride of lions led +by two magnificent specimens, obviously the leaders. The lions charged, +killed the gnus, and dragged them into the bushes where their feasting +could not be seen. A little while later the two kings of the jungle +emerged and the radioman recorded on his tape: "Well, that's the end of +the gnus and here, once again, are the head lions." +%% +A real patriot is the fellow who gets a parking +ticket and rejoices that the system works. +%% +A recent study has found that concentrating on difficult off-screen +objects, such as the faces of loved ones, causes eye strain in computer +scientists. Researchers into the phenomenon cite the added concentration +needed to "make sense" of such unnatural three dimensional objects. +%% +A relationship is like a shark - it has to keep moving forward or it dies. +Well, what we have on our hands here is a dead shark. + -- Woody Allen +%% +A robin redbreast in a cage +Puts all Heaven in a rage. + -- Blake +%% +A rock pile ceases to be a rock pile the moment a single +man contemplates it, bearing within him the image of a cathedral. + -- Antoine de Saint-Exupery +%% +A rolling disk gathers no MOS. +%% +A rolling stone gathers momentum. +%% +A rolling stone gathers no moss. + -- Publilius Syrus +%% +A sadist is a masochist who follows the Golden Rule. +%% +A scientific truth does not triumph by convincing its opponents and +making them see the light, but rather because its opponents eventually +die and a new generation grows up that is familiar with it. + -- Max Planck +%% +A sense of desolation and uncertainty, of futility, of the baselessness +of aspirations, of the vanity of endeavor, and a thirst for a life giving +water which seems suddenly to have failed, are the signs in conciousness +of this necessary reorganization of our lives. + +It is difficult to believe that this state of mind can be produced by the +recognition of such facts as that unsupported stones always fall to the +ground. + -- J.W.N. Sullivan +%% +A shortcut is the longest distance between two points. +%% +A sine curve goes off to infinity, or at least the end of the blackboard. + -- Prof. Steiner +%% +A single death is a tragedy, a million deaths is a statistic. + -- Joseph Stalin +%% +A single flow'r he sent me, since we met. +All tenderly his messenger he chose; +Deep-hearted, pure, with scented dew still wet-- +One perfect rose. + +I knew the language of the floweret; +"My fragile leaves," it said, "his heart enclose." +Love long has taken for his amulet +One perfect rose. + +Why is it no one ever sent me yet +One perfect limousine, do you suppose? +Ah no, it's always just my luck to get +One perfect rose. + -- Dorothy Parker, "One Perfect Rose" +%% +A sinking ship gathers no moss. + -- Donald Kaul +%% +A snake lurks in the grass. + -- Publius Vergilius Maro (Virgil) +%% +A soft answer turneth away wrath; but grievous words stir up anger. + -- Proverbs 15:1 +%% +A soft drink turneth away company. +%% +A software technician from Digital +Had hardware extremely prodigical. + It's rumoured, I hear, + That when he was near +He made the ladies all flustered and fidgital. +%% +A solemn, unsmiling, sanctimonious old iceberg +that looked like he was waiting for a vacancy in the Trinity. + -- Mark Twain +%% +A song in time is worth a dime. +%% +A stitch in time saves nine. +%% +A straw vote only shows which way the hot air blows. + -- O'Henry +%% +A student, in hopes of understanding the Lambda-nature, came to Greenblatt. +As they spoke a Multics system hacker walked by. "Is it true", asked the +student, "that PL-1 has many of the same data types as Lisp?" Almost before +the student had finished his question, Greenblatt shouted, "FOO!", and hit +the student with a stick. +%% +A student who changes the course of history is probably taking an exam. +%% +A successful tool is one +that was used to do something undreamed of by its author. + -- S.C. Johnson +%% +A tall, dark stranger will have more fun than you. +%% +A teenage protester named Lil +Cried, "Those Watergate spies make me ill + First they bugged our martinis, + Our bras and bikinis, +And now they are bugging the pill." +%% +A thrice-married gal from L.A. +Said, "My hymen's intact to this day, + 'Cause my first (a shrink) talked of it, + The voyeur only gawked at it, +And my most recent man's a gourmet." +%% +A total abstainer is one who abstains from everything +but abstention, and especially from inactivity in the affairs of others. + -- Ambrose Bierce +%% +A transistor protected by a fast-acting +fuse will protect the fuse by blowing first. +%% +A traveling salesman was driving past a farm when he saw a pig with three +wooden legs executing a magnificent series of backflips and cartwheels. +Intrigued, he drove up to the farmhouse, where he found an old farmer +sitting in the yard watching the pig. + "That's quite a pig you have there, sir" said the salesman. + "Sure is, son," the farmer replied. "Why, two years ago, my daughter +was swimming in the lake and bumped her head and damned near drowned, but that +pig swam out and dragged her back to shore." + "Amazing!" the salesman exlaimed. + "And that's not the only thing. Last fall I was cuttin' wood up on +the north forty when a tree fell on me. Pinned me to the ground, it did. +That pig run up and wiggled underneath that tree and lifted it off of me. +Saved my life." + "Fantastic! the salesman said. But tell me, how come the pig has +three wooden legs?" + The farmer stared at the newcomer in amazement. "Mister, when you +got an amazin' pig like that, you don't eat him all at once." +%% +A true artist will let his wife starve, his children go barefoot, his mother +drudge for his living at seventy, sooner than work at anything but his art. + -- Shaw +%% +A truly wise man never plays leapfrog with a unicorn. +%% +A truly wise woman never plays leapfrog with a unicorn. +%% +A truth that's told with bad intent +Beats all the lies you can invent. + -- William Blake +%% +A university is what a college becomes +when the faculty loses interest in students. + -- John Ciardi +%% +A vacuum is a hell of a lot better +than some of the stuff that nature replaces it with. + -- Tenessee Williams +%% +A vasectomy means never having to say you're sorry. +%% +A very intelligent turtle +Found programming UNIX a hurdle + The system, you see, + Ran as slow as did he, +And that's not saying much for the turtle. +%% +A violent man will die a violent death. + -- Lao Tsu +%% +A visit to a fresh place will bring strange work. +%% +A visit to a strange place will bring fresh work. +%% +A vivid and creative mind characterizes you. +%% +A waist is a terrible thing to mind. + -- Ziggy +%% +A watched clock never boils. +%% +A well adjusted person is one who makes +the same mistake twice without getting nervous. +%% +A well-known friend is a treasure. +%% +A widow is more sought after than an old maid of the same age. + -- Addison +%% +A wise man can see more from a mountain top +than a fool can from the bottom of a well. +%% +A wise man can see more from the bottom +of a well than a fool can from a mountain top. +%% +A wise person makes his own decisions, a weak one obeys public opinion. + -- Chinese proverb +%% +A woman can never be too rich or too thin. +%% +A woman employs sincerity only when every other form of deception has failed. + -- Scott +%% +A woman, especially if she have the misfortune +of knowing anything, should conceal it as well as she can. + -- Jane Austen +%% +A woman forgives the audacity of which +her beauty has prompted us to be guilty. + -- LeSage +%% +A woman is like your shadow; follow her, +she flies; fly from her, she follows. + -- Chamfort +%% +A woman must be a cute, cuddly, naive +little thing -- tender, sweet, and stupid. + -- Adolf Hitler +%% +A woman of generous character will sacrifice her life a thousand times +over for her lover, but will break with him for ever over a question of +pride -- for the opening or the shutting of a door. + -- Stendhal +%% +A woman physician has made the statement that smoking is neither +physically defective nor morally degrading, and that nicotine, even +when indulged to in excess, is less harmful than excessive petting." + -- Purdue Exponent, Jan 16, 1925 +%% +A woman takes off her claim to respect along with her garments. + -- Herodotus +%% + A woman was married to a golfer. One day she asked, "If I were +to die, would you remarry?" + After some thought, the man replied, "Yes, I've been very happy in +this marriage and I would want to be this happy again." + The wife asked, "Would you give your new wife my car?" + "Yes," he replied. "That's a good car and it runs well." + "Well, would you live in this house?" + "Yes, it is a lovely house and you have decorated it beautifully. +I've always loved it here." + "Well, would you give her my golf clubs?" + "No." + "Why not?" + "She's left handed." +%% +A woman who is guided by the head and not by the heart is a social +pestilence: she has all the defects of the passionate and affectionate +woman, with none of her compensations; she is without pity, without +love, without virtue, without sex. + -- Balzac +%% +A woman without a man is like a fish without a bicycle. + -- Gloria Steinem +%% +A woman without a man is like a fish without a bicycle. +Therefore, a man without a woman is like a bicycle without a fish. +%% +A woman's place is in the house... and in the Senate. +%% +A wonderful bird is the pelican. +His mouth can hold more than his belican. + He can take in his beak + Enough food for a week. +I'm darned if I know how the helican. +%% +A word to the wise is enough. + -- Miguel de Cervantes +%% +A would-be disciple came to Nasrudin's hut on the mountain-side. Knowing +that every action of such an enlightened one is significant, the seeker +watched the teacher closely. "Why do you blow on your hands?" "To warm +myself in the cold." Later, Nasrudin poured bowls of hot soup for himself +and the newcomer, and blew on his own. "Why are you doing that, Master?" +"To cool the soup." Unable to trust a man who uses the same process +to arrive at two different results -- hot and cold -- the disciple departed. +%% +A yawn is a silent shout. + -- G.K. Chesterton +%% +A year spent in Artificial Intelligence is enough to make one believe in God. +%% + A young honeymoon couple were touring southern Florida and happened +to stop at one of the rattlesnake farms along the road. After seeing the +sights, they engaged in small talk with the man that handled the snakes. +"Gosh!" exclaimed the new bride. "You certainly have a dangerous job. +Don't you ever get bitten by the snakes?" + "Yes, upon rare occasions," answered the handler. + "Well," she continued, "just what do you do when you're bitten by +a snake?" + "I always carry a razor-sharp knife in my pocket, and as soon as I +am bitten, I make deep criss-cross marks across the fang entry and then +suck the poison from the wound." + "What, uh... what would happen if you were to accidentally *sit* on +a rattler?" persisted the woman. + "Ma'am," answered the snake handler, "that will be the day I learn +who my real friends are." +%% +A young maiden from France was no prude, +She decided to dive in the nude, + But her buddy, behind, + Went out of his mind, +When he noticed where she was tatooed. +%% + A young married couple had their first child. Their original pride +and joy slowly turned to concern however, for after a couple of years the +child had never uttered any form of speech. They hired the best speech +therapists, doctors, psychiatrists, all to no avail. The child simply refused +to speak. One morning when the child was five, while the husband was reading +the paper, and the wife was feeding the dog, the little kid looks up from +his bowl and said, "My cereal's cold." + The couple is stunned. The man, in tears, confronts his son. "Son, +after all these years, why have you waited so long to say something?". + Shrugs the kid, "Everything's been okay 'til now". +%% +A.A.A.A.A.: An organization for drunks who drive. +%% +AAAAAAAAAAAaaaaaaaaaaaaaaaccccccccckkkkkk!!!!!!!!! +You brute! Knock before entering a ladies room! +%% +ABSCOND: + To be unexpectedly called away to the bedside + of a dying relative and miss the return train. +%% +ABSENTEE: + A person with an income who has had the forethought + to remove themselves from the sphere of exaction. +%% +ABSENT: + Exposed to the attacks of friends and + acquaintances; defamed; slandered. +%% +ABSTAINER: + A weak person who yields to the + temptation of denying himself a pleasure. +%% +ABSURDITY: + A statement or belief manifestly + inconsistent with one's own opinion. +%% +ACADEMY: + A modern school where football is taught. +INSTITUTE: + An archaic school where football is not taught. +%% +ACCEPTANCE TESTING: + An unsuccessful attempt to find bugs. +%% +ACCORDION: + A bagpipe with pleats. +%% +ACCURACY: + The vice of being right. +%% +ADA: + Something you need only know the name of to be an Expert in + Computing. Useful in sentences like, "We had better develop + an ADA awareness. + -- "Datamation", January 15, 1984 +%% +ADMIRATION: + Our polite recognition of another's resemblance to ourselves. +%% +ADOLESCENCE: + The stage between puberty and adultery. +%% +ADORE: + To venerate expectantly. +%% +ADULT: + One old enough to know better. +%% +AFTERNOON: + That part of the day we spend worrying + about how we wasted the morning. +%% +AIR: + A nutritious substance supplied by + a bountiful Providence for the fattening of the poor. + -- Ambrose Bierce +%% +ALASKA: + A prelude to "No." +%% +ALBRECHT'S LAW: + Social innovations tend to the level + of minimum tolerable well-being. +%% +ALGORITHM: + Trendy dance for hip programmers. +%% +ALL NEW: + Parts not interchangeable with previous model. +%% +ALLIANCE: + In international politics, the union of two thieves who + have their hands so deeply inserted in each other's pockets + that they cannot separately plunder a third. +%% +ALONE: + In bad company. +%% +AMAZING BUT TRUE... + If all the salmon caught in Canada in one year were laid end to + end across the Sahara Desert, the smell would be absolutely awful. +%% +AMAZING BUT TRUE... + There is so much sand in Northern Africa that if it + were spread out it would completely cover the Sahara Desert. +%% +AMBIDEXTROUS: + Able to pick with equal skill a right-hand pocket or a left. +%% +AMBIGUITY: + Telling the truth when you don't mean to. +%% +AMOEBIT: + Amoeba/rabbit cross; it can multiply + and divide at the same time. +%% +ANDROPHOBIA: + Fear of men. +%% +ANOINT: + To grease a king or other great + functionary already sufficiently slippery. +%% +ANTONYM: + The opposite of the word you're trying to think of. +%% +APHASIA: + Loss of speech in social scientists when asked + at parties, "But of what use is your research?" +%% +APL hackers do it in the quad. +%% +APL is a natural extension of assembler language programming; +...and is best for educational purposes. + -- A. Perlis +%% +APPENDIX: + A portion of a book, for which nobody yet has discovered any use. +%% +APPOINTMENT BOOK: + The reference of last resort when trying to duck undesired + invitations ("Gee, the soonest I can pencil you in is + December, 2004"), or when trying to figure out what the hell + it was you did during the past year. +%% +AQUARIUS (Jan 20 - Feb 18) + You have an inventive mind and are inclined to be progressive. + You lie a great deal. On the other hand, you are inclined to be + careless and impractical, causing you to make the same mistakes over + and over again. People think you are stupid. +%% +AQUARIUS (Jan.20 - Feb.18) + You are the type of person who never has enough money to do what + you want. Don't expect things to get any better today, either. + As a matter of fact they might get worse. Intensify your + relationship with your bank and any friends you have who might be + able to lend you a few bucks. +%% +ARIES (Mar 21 - Apr 19) + You are the pioneer type and hold most people in contempt. You are + quick tempered, impatient, and scornful of advice. You are not + very nice. +%% +ARIES (Mar.21 - Apr.19) + You are a wonderfully interesting, honest, hard-working person + and you should make many new friends, but you won't because you've + got a mean streak in you a mile wide. +%% +ARITHMETIC: + An obscure art no longer practiced in + the world's developed countries. +%% +ARMADILLO: + To provide weapons to a Spanish pickle. +%% +ARMADILLO: + To provide weapons to a spanish pickle. +%% +ASCII a stupid question, you get an EBCDIC answer. +%% +ASCII: + The control code for all beginning programmers and those who would + become computer literate. Etymologically, the term has come down as + a contraction of the often-repeated phrase "ascii and you shall + receive." + -- Robb Russon +%% +ASS: + The masculine of "lass". +%% +ATLANTA: + An entire city surrounded by an airport. +%% +AUCTION: + A gyp off the old block. +%% +AUTHENTIC: + Indubitably true, in somebody's opinion. +%% +AUTOMOBILE: + A four-wheeled vehicle that runs up hills and down pedestrians. +%% +A-Z affectionately, +1 to 10 alphabetically, +from here to eternity without in betweens, +still looking for a custom fit in an off-the-rack world, +sales talk from sales assistants + when all i want to do is lower your resistance, +no rhythm in cymbals no tempo in drums, +love's on arrival, +she comes when she comes, +right on the target but wide of the mark... +%% +Abandon the search for Truth; settle for a good fantasy. +%% +Aberdeen was so small that when the family with the car went +on vacation, the gas station and drive-in theatre had to close. +%% +About all some men accomplish in life is to send a son to Harvard. +%% +About the only thing on a farm that has an easy time is the dog. +%% +About the only thing we have left that actually +discriminates in favor of the plain people is the stork. +%% +About the time we think we can make ends meet, somebody moves the ends. + -- Herbert Hoover +%% +Above all else - sky. +%% +Above all things, reverence yourself. +%% +Absence diminishes mediocre passions and increases +great ones, as the wind blows out candles and fans fires. + -- La Rochefoucauld +%% +Absence in love is like water upon fire; +a little quickens, but much extinguishes it. + -- Hannah More +%% +Absence makes the heart forget. +%% +Absence makes the heart go wander. +%% +Absence makes the heart grow fonder. + -- Sextus Aurelius +%% +Absence makes the heart grow frantic. +%% +Absolutum obsoletum. (If it works, it's out of date.) + -- Stafford Beer +%% +Academicians care, that's who. +%% +Accent on helpful side of your nature. Drain the moat. +%% +Accept people for what they are -- completely unacceptable. +%% +Accident: + A condition in which presence of mind is good, + but absence of body is better. + -- Foolish Dictionary +%% +According to all the latest reports, +there was no truth in any of the earlier reports. +%% +According to experts, the oyster +In its shell - a crustacean cloister - + May frequently be + Either he or a she +Or both, if it should be its choice ter. +%% +According to my best recollection, I don't remember. + -- Vincent "Jimmy Blue Eyes" Alo +%% +According to the latest official figures, +43% of all statistics are totally worthless. +%% +Acid -- better living through chemistry. +%% +Acid absorbs 47 times its own weight in excess Reality. +%% +Acquaintance: + A person whom we know well enough + to borrow from, but not well enough to lend to. + -- Ambrose Bierce +%% +Acting is an art which consists of keeping the audience from coughing. +%% +Actor: I'm a smash hit. Why, yesterday during the last act, I had + everyone glued in their seats! +Oliver Herford: Wonderful! Wonderful! Clever of you to think of + it! +%% +Actors will happen in the best-regulated families. +%% +Actually, my goal is to have a sandwich named after me. +%% +Actually, the probability is 100% that the elevator +will be going in the right direction. Proof by induction: + +N=1. Trivialy true, since both you and the elevator + only have one floor to go to. + +Assume true for N, prove for N+1: + If you are on any of the first N floors, then it is true by the + induction hypothesis. If you are on the N+1st floor, then both you + and the elevator have only one choice, namely down. Therefore, + it is true for all N+1 floors. +QED. +%% +Ad astra per aspera. (To the stars by aspiration.) +%% +Adam's Law: + (1) Women don't know what they want; + they don't like what they have got. + (2) Men know very well what they want; + having got it, they begin to lose interest. +%% +Adde parvum parvo manus acervus erit. +[Add little to little and there will be a big pile.] + -- Ovid +%% +Adding manpower to a late software project makes it later. + -- F. Brooks, "The Mythical Man-Month" +%% +Adhere to your own act, and congratulate yourself if you have done +something strange and extravagant, and broken the monotony of a +decorous age. + -- Ralph Waldo Emerson +%% +Adler's Distinction: + Language is all that separates us from the lower animals, + and from the bureaucrats. +%% +Adults die young. +%% +Advancement in position. +%% +Advertisements contain the only +truths to be relied on in a newspaper. + -- Thomas Jefferson +%% +Advertising Rule: + In writing a patent-medicine advertisement, first convince the + reader that he has the disease he is reading about; secondly, + that it is curable. +%% +Advertising is the most fun of anything you can do with your clothes on. + -- Mary Wells, advertising executive +%% +Advice from an old carpenter: measure twice, saw once. +%% +Advice is a dangerous gift; be cautious about giving and receiving it. +%% +After a number of decimal places, nobody gives a damn. +%% +After a while you learn the subtle difference between holding a hand + and chaining a soul, +And you learn that love doesn't mean leaning and company doesn't mean + security, +And you begin to learn that kisses aren't contracts and presents aren't + promises, +And you begin to accept your defeats with your head up and your eyes open, + with the grace of an adult, not the grief of a child, +And you learn to build all your roads on today because tomorrow's ground + is too uncertain for plans. +After a while you learn that even sunshine burns if you get too much. +So plant your own garden and decorate your own soul, instead of waiting + for someone to bring you flowers. +And you learn that you really can endure... that you really are strong, +And you really do have worth. +%% +After all, all he did was string together +a lot of old, well-known quotations. + -- H.L. Mencken, on Shakespeare +%% +After all is said and done, a hell of a lot more is said than done. +%% +After all, it is only the mediocre who are always at their best. + -- Jean Giraudoux +%% +After all my erstwhile dear, +My no longer cherished, +Need we say it was not love, +Just because it perished? + -- Edna St. Vincent Millay +%% +I have yet to see any problem, however complicated, which, when +you looked at it in the right way, did not become still more complicated. + -- Poul Anderson +%% +After all, what is your hosts' purpose in having a party? Surely not for +you to enjoy yourself; if that were their sole purpose, they'd have simply +sent champagne and women over to your place by taxi. + -- P.J. O'Rourke +%% +After an instrument has been assembled, +extra components will be found on the bench. +%% +After his Ignoble Disgrace, Satan was being expelled from +Heaven. As he passed through the Gates, he paused a moment in thought, +and turned to God and said, "A new creature called Man, I hear, is soon +to be created." + "This is true," He replied. + "He will need laws," said the Demon slyly. + "What! You, his appointed Enemy for all Time! You ask for the +right to make his laws?" + "Oh, no!" Satan replied, "I ask only that he be allowed to make +his own." + It was so granted. +%% +After repeatedly warding off her date's amorous advances during the evening, +the pretty young thing decided to put her foot down: "See here," she shouted +indignantly. "This is positively the last time I'm going to tell you `no'." + "Splendid!" exclaimed her date. "Now we can start making some +progress." +%% +After the game the king and the pawn go in the same box. + -- Italian proverb +%% +After the last of 16 mounting screws has been removed from an access +cover, it will be discovered that the wrong access cover has been removed. +%% +After this was written there appeared a remarkable posthumous memoir that +throws some doubt on Millikan's leading role in these experiments. Harvey +Fletcher (1884-1981), who was a graduate student at the University of Chicago, +at Millikan's suggestion worked on the measurement of electronic charge for +his doctoral thesis, and co-authored some of the early papers on this subject +with Millikan. Fletcher left a manuscript with a friend with instructions +that it be published after his death; the manuscript was published in +Physics Today, June 1982, page 43. In it, Fletcher claims that he was the +first to do the experiment with oil drops, was the first to measure charges on +single droplets, and may have been the first to suggest the use of oil. +According to Fletcher, he had expected to be co-authored with Millikan on +the crucial first article announcing the measurement of the electronic +charge, but was talked out of this by Millikan. + -- Steven Weinberg, "The Discovery of Subatomic Particles" + +Robert Millikan is generally credited with making the first really +precise measurement of the charge on an electron and was awarded the +Nobel Prize in 1923. +%% +After two or three weeks of this madness, you begin to feel As One with +the man who said, "No news is good news." In twenty-eight papers, only +the rarest kind of luck will turn up more than two or three articles of +any interest... but even then the interest items are usually buried +deep around paragraph 16 on the jump (or "Cont. on ...") page... + +The Post will have a story about Muskie making a speech in Iowa. The +Star will say the same thing, and the Journal will say nothing at all. +But the Times might have enough room on the jump page to include a line +or so that says something like: "When he finished his speech, Muskie +burst into tears and seized his campaign manager by the side of the +neck. They grappled briefly, but the struggle was kicked apart by an +oriental woman who seemed to be in control." + +Now that's good journalism. Totally objective; very active and +straight to the point. + -- Hunter S. Thompson, "Fear and Loathing '72" +%% + After watching an extremely attractive maternity-ward patient +earnestly thumbing her way through a telephone directory for several +minutes, a hospital orderly finally asked if he could be of some help. + "No, thanks," smiled the young mother, "I'm just looking for a +name for my baby." + "But the hospital supplies a special booklet that lists hundreds +of first names and their meanings," said the orderly. + "That won't help," said the woman, "my baby already has a first +name." +%% +After your lover has gone you will still have PEANUT BUTTER! +%% +Afternoon very favorable for romance. Try a single person for a change. +%% +Against Idleness and Mischief + +How doth the little busy bee How skillfully she builds her cell! +Improve each shining hour, How neat she spreads the wax! +And gather honey all the day And labours hard to store it well +From every opening flower! With the sweet food she makes. + +In works of labour or of skill In books, or work, or healthful play, +I would be busy too; Let my first years be passed, +For Satan finds some mischief still That I may give for every day +For idle hands to do. Some good account at last. + -- Isaac Watts, 1674-1748 +%% +Age and treachery will always overcome youth and skill. +%% +Age is a tyrant who forbids, +at the penalty of life, all the pleasures of youth. +%% +Agree with them now, it will save so much time. +%% +Ah, but a man's grasp should exceed his reach, +Or what's a heaven for ? + -- Robert Browning, "Andrea del Sarto" +%% +Ah, the Tsar's bazaar's bizarre beaux-arts! +%% +Ahead warp factor one, Mr. Sulu. +%% +Aim for the moon. If you miss, you may hit a star. + -- W. Clement Stone +%% +Air Force Inertia Axiom: + Consistency is always easier to defend than correctness. +%% +Air is water with holes in it. +%% +Alas, I am dying beyond my means. + -- Oscar Wilde [as he sipped champagne on his deathbed] +%% +Alas, how love can trifle with itself! + -- William Shakespeare, "The Two Gentlemen of Verona" +%% +Albert Camus wrote that the only serious question is whether to kill yourself +or not. Tom Robbins wrote that the only serious question is whether time has +a beginning and an end. Camus clearly got up on the wrong side of bed, and +Robbins must have forgotten to set the alarm. + -- Tom Robbins +%% +Alcohol, hashish, prussic acid, strychnine are weak dilutions. +The surest poison is time. + -- Emerson, "Society and Solitude" +%% +Alden's Laws: + (1) Giving away baby clothes and furniture is the major cause + of pregnancy. + (2) Always be backlit. + (3) Sit down whenever possible. +%% +Aleph-null bottles of beer on the wall, +Aleph-null bottles of beer, +You take one down, and pass it around, +Aleph-null bottles of beer on the wall. +%% +Alex Haley was adopted! +%% +Alexander Graham Bell is alive and well +in New York, and still waiting for a dial tone. +%% +Algebraic symbols are used when you don't know what you're talking about. +%% +Algol-60 surely must be regarded as the most +important programming language yet developed. + -- T. Cheatham +%% +Alimony and bribes will engage a large share of your wealth. +%% +Alimony is a system by which, when two people +make a mistake, one of them continues to pay for it. + -- Peggy Joyce +%% +Alimony is the high cost of leaving. +%% +Alive without breath, +As cold as death; +Never thirsty, ever drinking, +All in mail ever clinking. +%% +All I ask is a chance to prove that money can't make me happy. +%% +All I know is what the words know, and dead things, and that +makes a handsome little sum, with a beginning and a middle and +an end, as in the well-built phrase and the long sonata of the dead. + -- Samuel Beckett +%% +All I've got left on the list of desirable vocations is heiress to the +throne of any country in Western Europe and Laurie Anderson. "Be +practical", was the choral reply from the dinner table. Well, Laurie +Anderson is already Laurie Anderson, but I read an article in Harpers +that said there were eleven countries, in the world this is I think, +that have queens as sovereign rulers. That's probably my best shot. +%% +All a man needs out of life is a place to sit 'n' spit in the fire. +%% +All art is but imitation of nature. + -- Lucius Annaeus Seneca +%% +All articles that coruscate with resplendence are not truly auriferous. +%% +All constants are variables. +%% +All flesh is grass. + -- Isaiah +Smoke a friend today. +%% +All generalizations are useless, including this one. +%% +All great discoveries are made by mistake. +%% +All great discoveries are made by mistake. + -- Young +%% +All great ideas are controversial, or have been at one time. +%% + All he did was take the ball and run every time they called his +number -- which came to be more and more often, and in the Super Bowl Thomas +was the whole show. But the season is now over; the purse is safe in the +vault; and Duane Thomas is facing two to twenty for possession. Nobody really +expects him to serve time, but nobody seems to think he'll be playing for +Dallas next year either, and a few sporting people who claim to know how the +NFL works say he won't be playing for ANYBODY next year; that the Commissioner +is outraged at this mockery of all those Government-sponsored "Beware of Dope" +TV shots that dressed up the screen last autumn. + We all enjoyed those spots, but not everyone found them convincing. +Here was a White House directive saying several million dollars would be spent +to drill dozens of Name Players to stare at the camera and try to stop grinding +their teeth long enough to say they hate drugs of any kind... and then the best +running back in the world turns out to be a goddamn uncontrollable drugsucker. + But not for long. There is not much room for freaks in the National +Football League. Joe Namath was saved by the simple blind luck of getting +drafted by a team in New York City, a place where social outlaws are not +always viewed as criminals. But Namath would have had a very different trip +if he'd been drafted by the St. Louis Cardinals. + -- Hunter S. Thompson +%% +All heiresses are beautiful. + -- John Dryden +%% +All his life he has looked away... to the horizon, to the sky, +to the future. Never his mind on where he was, on what he was doing. + -- Yoda +%% +All hope abandon, ye who enter here! + -- Dante Alighieri +%% +All is fear in love and war. +%% +All is well that ends well. + -- John Heywood +%% +All laws are simulations of reality. + -- John C. Lilly +%% +All life evolves by the differential survival of replicating entities. + -- Dawkins +%% +All men know the utility of useful things; +but they do not know the utility of futility. + -- Chuang-tzu +%% +All men profess honesty as long as they can. +To believe all men honest would be folly. +To believe none so is something worse. + -- John Quincy Adams +%% +All most people ask of life is a constant +and exaggerated sense of their own importance. +%% +All most people want is a little more than they'll ever get. +%% +All my friends and I are crazy. +That's the only thing that keeps us sane. +%% +All my friends are getting married, +Yes, they're all growing old, +They're all staying home on the weekend, +They're all doing what they're told. +%% +All of the animals except man know that +the principal business of life is to enjoy it. +%% +All parts should go together without forcing. You must remember that the +parts you are reassembling were disassembled by you. Therefore, if you +can't get them together again, there must be a reason. By all means, do +not use a hammer. + -- IBM maintenance manual, 1925 +%% +All people are born alike -- except Republicans and Democrats. + -- Groucho Marx +%% +All possibility of understanding is rooted in the ability to say no. + -- Susan Sontag +%% +All programmers are playwrights and all computers are lousy actors. +%% +All progress is based upon a universal innate desire on the +part of every organism to live beyond its income. + -- Samuel Butler +%% +All religions issue Bibles against Satan, and say the most +injurious things against him, but we never hear his side. + -- Mark Twain +%% +All science is either physics or stamp collecting. + -- Ernest Rutherford +%% +All seems condemned in the long run +to approximate a state akin to Gaussian noise. + -- James Martin +%% +All that glitters has a high refractive index. +%% + All that you touch, And all you create, + All that you see, And all you destroy, + All that you taste, All that you do, + All you feel, And all you say, + And all that you love, All that you eat, + And all that you hate, And everyone you meet, + All you distrust, All that you slight, + All you save, And everyone you fight, + And all that you give, And all that is now, + And all that you deal, And all that is gone, + All that you buy, And all that's to come, + Beg, borrow or steal, And everything under the sun is + in tune, + But the sun is eclipsed + By the moon. + +There is no dark side of the moon... really... matter of fact it's all dark. + -- Pink Floyd, "Dark Side of the Moon" +%% +All the evidence concerning the universe +has not yet been collected, so there's still hope. +%% +All the girls in France, do a hookie-kookie dance, +And you know the way they shake, is enough to fry a snake, +And the snake they fry, is enough to tell a lie, +And the lie they tell, is enough to go to +Hello, operator, give me number nine, +If you disconnect me, I'll kick you in the +Behind the 'frigerator, there was a piece of glass, +If you do not pick it up, I'll kick you in the +Ask me no more questions, tell me no more lies, +This is what Lulu told me, just before she died. +She had a little brother, she named him Tiny Tim, +She put him in the potty, to see if he could swim. +He swam down to the bottom, he swam up to the top, +Lulu got disgusted, and flushed him down the pot. + -- Princess +%% +All the lines have been written There's been Sandburg, +It's sad but it's true Keats, Poe and McKuen +With all the words gone, They all had their day +What's a young poet to do? And knew what they're doin' + +But of all the words written The bird is a strange one, +And all the lines read, So small and so tender +There's one I like most, Its breed still unknown, +And by a bird it was said! Not to mention its gender. + +It reminds me of days of So what is this line +Both gloom and of light. Whose author's unknown +It still lifts my spirits And still makes me giggle +And starts the day right. Even now that I'm grown? + +I've read all the greats +Both starving and fat, +But none was as great as +"I tot I taw a puddy tat." + -- Etta Stallings, "An Ode To Childhood" +%% +All the really good ideas I ever had came to me while I was milking a cow. + -- Grant Wood +%% +All the simple programs have been written. +%% +All the troubles you have will pass away very quickly. +%% +All the world's a stage and most of us are desperately un-rehearsed. + -- Sean O'Casey +%% +All things are possible except skiing through a revolving door. +%% +All things are possible except skiing thru a revolving door. +%% +All things being equal, you are bound to lose. +%% +All things that are, are with more spirit chased than enjoyed. + -- Shakespeare, "Merchant of Venice" +%% +All this big deal about white collar crime -- what's WRONG with white collar +crime? Who enjoys his job today? You? Me? Anybody? The only satisfying +part of any job is coffee break, lunch hour and quitting time. Years ago +there was at least the hope of improvement -- eventual promotion -- more +important jobs to come. Once you can be sold the myth that you may make +president of the company you'll hardly ever steal stamps. But nobody +believes he's going to be president anymore. The more people change jobs +the more they realize that there is a direct connection between working for +a living and total stupefying boredom. So why NOT take revenge? You're not +going to find ME knocking a guy because he pads an expense account and his +home stationery carries the company emblem. Take away crime from the white +collar worker and you will rob him of his last vestige of job interest. + -- J. Feiffer +%% +All this wheeling and dealing around, why, it isn't for money, +it's for fun. Money's just the way we keep score. + -- Henry Tyroon +%% +All true wisdom is found on T-shirts. +%% +All warranty and guarantee clauses +become null and void upon payment of invoice. +%% +All who joy would win Must share it -- +Happiness was born a twin. + -- Lord Byron +%% +All your files have been destroyed (sorry). Paul. +%% +Allen's Axiom: + When all else fails, read the instructions. +%% +All's well that ends. +%% +Almost anything derogatory you could say +about today's software design would be accurate. + -- K.E. Iverson +%% +Always borrow money from a pessimist; he doesn't expect to be paid back. +%% +Always do right. +This will gratify some people and astonish the rest. + -- Mark Twain +%% +Always draw your curves, then plot your reading. +%% +Always leave room to add an explanation if it doesn't work out. +%% +Always store beer in a dark place. +%% +Always the dullness of the fool is the whetstone of the wits. + -- William Shakespeare, "As You Like It" +%% +Always there remain portions of our heart +into which no one is able to enter, invite them as we may. +%% +Always think of something new; this +helps you forget your last rotten idea. + -- Seth Frankel +%% +Ambition is a poor excuse for not having sense enough to be lazy. + -- Charlie McCarthy +%% +America, I'm putting my queer shoulder to the wheel. + -- Allen Ginsberg +%% +America: born free and taxed to death. +%% +America is the country where you buy a lifetime +supply of aspirin for one dollar, and use it up in two weeks. +%% +America may be unique in being a country which has leapt +from barbarism to decadence without touching civilization. + -- John O'Hara +%% +American by birth; Texan by the grace of God. +%% +American cars are made shoddily... +Cars made overseas are far superior. + -- Sen. Barry Goldwater +%% +American culture is based on the automobile, and any young man of promise +is going to own one and want to travel great distances in it. Consequently, +any young woman of aspiration should expect to spend most of her vacations +in a car, probing into unfamiliar corners. She is not required to know how +to drive but she will certainly be expected to read the road map while her +husband drives, and if she can't, or if she's abnormally slow in giving him +help, she's bound to cause trouble. Therefore, you'd think that colleges +which train the bright young women who're going to marry the bright young +men who are going to own the Cadillacs that roar back and forth across this +continent would teach the girls to read maps. None do. They teach a hundred +other useless things, but never a word about the one that will cause the +greatest friction. + -- James Michener, "Space" +%% +Americans are people who insist on living in the present, tense. +%% +Americans' greatest fear is that America +will turn out to have been a phenomenon, not a civilization. + -- Shirley Hazzard, "Transit of Venus" +%% +America's best buy for a quarter is a telephone call to the right person. +%% +Amnesia used to be my favorite word, but then I forgot it. +%% +Among the lucky, you are the chosen one. +%% +An American is a man with two arms and four wheels. + -- A Chinese child +%% +An American scientist once visited the offices of the great Nobel prize +winning physicist, Niels Bohr, in Copenhagen. He was amazed to find that +over Bohr's desk was a horseshoe, securely nailed to the wall, with the +open end up in the approved manner (so it would catch the good luck and not +let it spill out). The American said with a nervous laugh, + "Surely you don't believe the horseshoe will bring you good luck, +do you, Professor Bohr? After all, as a scientist --" +Bohr chuckled. + "I believe no such thing, my good friend. Not at all. I am +scarcely likely to believe in such foolish nonsense. However, I am told +that a horseshoe will bring you good luck whether you believe in it or not." +%% +An American's a person who isn't afraid to criticize +the president but is always polite to traffic cops. +%% +An Englishman never enjoys himself, except for a noble purpose. + -- A.P. Herbert +%% +An Hacker there was, one of the finest sort +Who controlled the system; graphics was his sport. +A manly man, to be a wizard able; +Many a protected file he had sitting on his table. +His console, when he typed, a man might hear +Clicking and feeping wind as clear, +Aye, and as loud as does the machine room bell +Where my lord Hacker was Prior of the cell. +The Rule of good St Savage or St Doeppnor +As old and strict he tended to ignore; +He let go by the things of yesterday +And took the modern world's more spacious way. +He did not rate that text as a plucked hen +Which says that Hackers are not holy men. +And that a hacker underworked is a mere +Fish out of water, flapping on the pier. +That is to say, a hacker out of his cloister. +That was a text he held not worth an oyster. +And I agreed and said his views were sound; +Was he to study till his head wend round +Poring over books in the cloisters? Must he toil +As Andy bade and till the very soil? +Was he to leave the world upon the shelf? +Let Andy have his labor to himself! + -- Chaucer + [well, almost. Ed.] +%% +An adequate bootstrap is a contradiction in terms. +%% +An algorithm must be seen to be believed. + -- D.E. Knuth +%% +An ambassador is an honest man sent abroad +to lie and intrigue for the benefit of his country. + -- Henry Wotton +%% +An amendment to a motion may be amended, but an amendment to an amendment +to a motion may not be amended. However, a substitute for an amendment to +and amendment to a motion may be adopted and the substitute may be amended. + -- The Montana legislature's contribution to the English + language. +%% +An angst-ridden amorist, Fred, +Saw sartorial changes ahead. + His mind kept on ringing + With fishy girls singing; +Soft fruit also filled him with dread. + -- J. Walker, "The Love Song Of J. Alfred Prufrock" +%% +An aphorism is never exactly true; +it is either a half-truth or one-and-a-half truths. + -- Karl Kraus +%% +An apple a day makes 365 apples a year. +%% +An architect fellow named Yoric +Could, when feeling euphoric, + Display for selection + Three kinds of erection- +Corinthian, ionic, and doric. +%% +An artist who lived in Australia +Once painted his ass like a Dahlia. + The drawing was fine, + The colour - divine, +The scent - ah, that was a failia. +%% +An atheist is a man with no invisible means of support. +%% +An atom-blaster is a good weapon, but it can point both ways. + -- Isaac Asimov +%% +An attachment a la Plato +for a bashful young potato +or a, not too French, french bean +must excite your languid spleen. +For, if you walk down Picadilly +with a poppy or lily +in your medieval hand, +every one will say, +as you walk your flowery way; +"If this young man is content, +with a vegetable love +which would certainly not content me. +Why, what a very pure young man +this pure young man must be!" + -- W.S. Gilbert, "Patience" + [The subject of the humour is, of course, Oscar Wilde] +%% +An avocado-tone refrigerator would look good on your resume. +%% +An egghead is one who stands firmly on both feet, +in mid-air, on both sides of an issue. + -- Homer Ferguson +%% +An elephant is a mouse with an operating system. +%% +An encounter with a beautiful woman is good medicine for the well organized +logical mind -- a little jolt never hurt. Note that the anarchists have +been saying this for years about the A-bomb and civilization. + -- Encyclopadia Apocryphia +%% +An engineer is someone who does list processing in FORTRAN. +%% +An evil mind is a great comfort. +%% +An expert is a person who avoids the small errors +as he sweeps on to the grand fallacy. + -- Benjamin Stolberg +%% +An expert is one who knows more and more about less +and less until he knows absolutely nothing about everything. +%% +An eye in a blue face +Saw an eye in a green face. +"That eye is like this eye" +Said the first eye, +"But in low place, +Not in high place." +%% +An honest tale speeds best being plainly told. + -- William Shakespeare, "Henry VI" +%% +An idea is not responsible for the people who believe in it. +%% +An idle mind is worth two in the bush. +%% +An infallible method of concilliating a tiger +is to allow oneself to be devoured. + -- Konrad Adenauer +%% +An investment in knowledge always pays the best interest. + -- Benjamin Franklin +%% +An old Jewish man reads about Einstein's theory of relativity +in the newspaper and asks his scientist grandson to explain it to him. + "Well, zayda, it's sort of like this. Einstein says that if +you're having your teeth drilled without Novocain, a minute seems like +an hour. But if you're sitting with a beautiful woman on your lap, an +hour seems like a minute." + The old man considers this profound bit of thinking for a +moment and says, "And from this he makes a living?" + -- Arthur Naiman +%% +An optimist is a guy that has never had much experience. + -- Don Marquis +%% +An optimist is a man who looks forward to marriage. +A pessimist is a married optimist. +%% +Booker's Law: + An ounce of application is worth a ton of abstraction. +%% +An ounce of clear truth is worth a pound of obfuscation. +%% +An ounce of hypocrisy is worth a pound of ambition. + -- Michael Korda +%% +Anarchy may not be a better form of government, +but it's better than no government at all. +%% +And I alone am returned to wag the tail. +%% +And I suppose the little things are harder to get used to than the big +ones. The big ones you get used to, you make up your mind to them. The +little things come along unexpectedly, when you aren't thinking about +them, aren't braced against them. + -- Marion Zimmer Bradley, "The Forbidden Tower" +%% +And did those feet, in ancient times, +Walk upon England's mountains green? +And was the Holy Lamb of God +In England's pleasant pastures seen? +And did the Countenance Divine +Shine forth upon these crowded hills? +And was Jerusalem builded here +Among these dark satanic mills? + +Bring me my bow of burning gold! +Bring me my arrows of desire! +Bring me my spears! O clouds unfold! +Bring me my chariot of fire! +I shall not cease from mental fight, +Nor shall my sword rest in my hand, +Till we have built Jerusalem +In England's green and pleasant land. + -- William Blake, "Jerusalem" +%% +And ever has it been known that +love knows not its own depth until the hour of separation. + -- Kahlil Gibran +%% +And here I wait so patiently +Waiting to find out what price +You have to pay to get out of +Going thru all of these things twice + -- Dylan, "Memphis Blues Again" +%% +And if sometime, somewhere, someone asketh thee, +"Who kilt thee?", tell them it 'twas the Doones of Bagworthy! +%% +And malt does more than Milton can to justify God's ways to man. + -- A.E. Housman +%% +And miles to go before I sleep. +%% +And now for something completely the same. +%% +And now your toner's toney, Disk blocks aplenty +And your paper near pure white, Await your laser drawn lines, +The smudges on your soul are gone Your intricate fonts, +And your output's clean as light.. Your pictures and signs. + +We've labored with your father, Your amputative absence +The venerable XGP, Has made the Ten dumb, +But his slow artistic hand, Without you, Dover, +Lacks your clean velocity. We're system untounged- + +Theses and papers DRAW Plots and TEXage +And code in a queue Have been biding their time, +Dover, oh Dover, With LISP code and programs, +We've been waiting for you. And this crufty rhyme. + +Dover, oh Dover, Dover, oh Dover, arisen from dead. +We welcome you back, Dover, oh Dover, awoken from bed. +Though still you may jam, Dover, oh Dover, welcome back to the Lab. +You're on the right track. Dover, oh Dover, we've missed your clean + hand... +%% +And on the seventh day, He exited from append mode. +%% +And that's the way it is... + -- Walter Cronkite +%% +And the French medical anatomist Etienne Serres really did argue that +black males are primitive because the distance between their navel and +penis remains small (relative to body height) throughout life, while +white children begin with a small separation but increase it during +growth -- the rising belly button as a mark of progress. + -- S.J. Gould, "Racism and Recapitulation" +%% +And the silence came surging softly backwards +When the plunging hooves were gone... + -- Walter de La Mare, "The Listeners" +%% +And this is a table ma'am. What in essence it consists of is a horizontal +rectilinear plane surface maintained by four vertical columnar supports, +which we call legs. The tables in this laboratory, ma'am, are as advanced +in design as one will find anywhere in the world. + -- Michael Frayn, "The Tin Men" +%% +And this is good old Boston, +The home of the bean and the cod, +Where the Lowells talk only to Cabots, +And the Cabots talk only to God. +%% +And tomorrow will be like today, only more so. + -- Isaiah 56:12, New Standard Version +%% +And what accomplished villains these old engineers were! What diabolical +ways to sabotage they found! Nikolai Karlovich von Meck, of the People's +Comissariat of Railroads ... would hold forth for hours on end about the +economic problems involved in the construction of socialism, and he loved to +give advice. One such pernicious piece of advice was to increase the size +of freight trains and not worry about heavier than average loads. The GPU +exposed van Meck, and he was shot: his objective had been to wear out rails +and roadbeds, freight cars and locomotives, so as to leave the Republic +without railroads in case of foreign military intervention! When, not long +afterward, the new People's Commissar of Railroads ordered that average +loads should be increased, and even doubled and tripled them, the malicious +engineers who protested became known as limiters ... they were rightly +shot for their lack of faith in the possibilities of socialist transport. + -- Aleksandr I. Solzhenitsyn, "The Gulag Archipelago" +%% + "And what will you do when you grow up to be as big as me?" +asked the father of his little son. + "Diet." +%% +And yet I should have dearly liked, I own, to have touched her lips; to +have questioned her, that she might have opened them; to have looked upon +the lashes of her downcast eyes, and never raised a blush; to have let +loose waves of hair, an inch of which would be a keepsake beyond price: +in short, I should have liked, I do confess, to have had the lightest +license of a child, and yet been man enough to know its value. + -- Charles Dickens +%% +And you can't get any Watney's Red Barrel, +because the bars close every time you're thirsty... +%% +And... What ever became of Sweet Jane? + She's lost her sparkle, you see she isn't the same. + Livin' on reds, vitamin C, and cocaine + All a friend can say is "Ain't it a shame?" + -- The Grateful Dead +%% +Andrea's Admonition: + Never bestow profanity upon a driver who has wronged you. + If you think his window is closed and he can't hear you, + it isn't and he can. +%% +Anger is momentary madness. + -- Horace +%% +Anger kills as surely as the other vices. +%% +Animals can be driven crazy by putting too many in too small a pen. +Homo sapiens is the only animal that voluntarily does this to himself. + -- Lazarus Long +%% +Another day, another dollar. + -- Vincent J. Fuller + [defense lawyer for John Hinckley, upon Hinckley's acquittal] +%% +Another good night not to sleep in a eucalyptus tree. +%% +Another greeting card category consists of those persons who send out +photographs of their families every year. In the same mail that brought the +greetings from Marcia and Philip, my friend found such a conversation piece. +"My God, Lida is enormous!" she exclaimed. I don't know why women want to +record each year, for two or three hundred people to see, the ravages wrought +upon them, their mates, and their progeny by the artillery of time, but +between five and seven per cent of Christmas cards, at a rough estimate, are +family groups, and even the most charitable recipient studies them for little +signs of dissolution or derangement. Nothing cheers a woman more, I am afraid, +than the proof that another woman is letting herself go, or has lost control +of her figure, or is clearly driving her husband crazy, or is obviously +drinking more than is good for her, or still doesn't know what to wear. +Middle-aged husbands in such photographs are often described as looking +"young enough to be her son," but they don't always escape so easily, and a +couple opening envelopes in the season of mercy and good will sometimes handle +a male friend or acquaintance rather sharply. "Good Lord!" the wife will say. +"Frank looks like a sex-crazed shotgun slayer, doesn't he?" "Not to me," the +husband may reply. "to me he looks more like a Wilkes-Barre dentist who is +being sought by the police in connection with the disappearance of a choir +singer." + -- James Thurber, "Merry Christmas" +%% +Another megabytes the dust. +%% +Another such victory over the Romans, and we are undone. + -- Pyrrhus +%% + Answers to Last Fortunes' Questions: +1) None. (Moses didn't have an ark). +2) Your mother, by the pigeonhole principle. +3) You don't know. Neither does your boss. +4) Who cares? +5) 6 (or maybe 4, or else 3). Mr. Alfred J. Duncan of Podunk, Montana, + submitted an interesting solution to Problem 5. Unfortunately, I lost it. +6) I know the answer to this one, but I'm not telling! Suffer! Ha-ha-ha!! +7) There is an interesting solution to this problem on page 10,953 of my + book, which you can pick up for $23.95 at finer bookstores and bathroom + supply outlets (or 99 cents at the table in front of Papyrus Books). +%% +Anthony's Law of the Workshop: + Any tool when dropped, will roll into the least accessible + corner of the workshop. + +Corollary: + On the way to the corner, any dropped tool will first strike + your toes. +%% +Any circuit design must contain at least one part which is obsolete, two parts +which are unobtainable, and three parts which are still under development. +%% +Any clod can have the facts, but having opinions is an art. + -- Charles McCabe +%% +Any coward can sit in his home and criticize a pilot for flying into a +mountain in a fog. But I would rather, by far, die on a mountainside +than in bed. What kind of man would live where there is no daring? +And is life so dear that we should blame men for dying in adventure? +Is there a better way to die? + -- Charles Lindbergh +%% +Any excuse will serve a tyrant. + -- Aesop +%% +Any fool can paint a picture, +but it takes a wise person to be able to sell it. +%% +Any fool can tell the truth, +but it requires a man of some sense to know how to lie well. +%% +Any given program, when running, is obsolete. +%% +Any given program will expand to fill available memory. +%% +Any instrument when dropped will roll into the least accessible corner. +%% +Any man can work when every stroke of his hand brings down the fruit +rattling from the tree to the ground; but to labor in season and out +of season, under every discouragement, by the power of truth -- that +requires a heroism which is transcendent. + -- Henry Ward Beecher +%% +Any man who hates dogs and babies can't be all bad. + -- Leo Rosten, on W.C. Fields +%% +Any member introducing a dog into the Society's premises shall be +liable to a fine of one pound. Any animal leading a blind person shall +be deemed to be a cat. + -- Rule 46, Oxford Union Society, London +%% +Any philosophy that can be put "in a nutshell" belongs there. + -- Harris's Law +%% +Any president should have the right to shoot +at least two people a year without explanation. + -- Herbert Hoover, discussing the press +%% +Any priest or shaman must be presumed guilty until proved innocent. + -- Lazarus Long +%% +Any program which runs right is obsolete. +%% +Any programming language is at its best before it is implemented and used. +%% +Any road followed to its end leads precisely nowhere. +Climb the mountain just a little to test it's a mountain. +From the top of the mountain, you cannot see the mountain. + -- Bene Gesserit proverb, "Dune" +%% +Any small object that is accidentally +dropped will hide under a larger object. +%% +Any sufficiently advanced bug becomes a feature. +%% +Any sufficiently advanced technology is +indistinguishable from a rigged demo. +%% +Any sufficiently advanced technology is indistinguishable from magic. + -- Arthur Clarke +%% +Any two philosophers can tell each other all they know in two hours. + -- Oliver Wendell Holmes, Jr. +%% +Any woman is a volume if one knows how to read her. +%% +Anybody can win, unless there happens to be a second entry. +%% +Anybody who doesn't cut his speed at the +sight of a police car is probably parked. +%% +Anybody with money to burn will easily find someone to tend the fire. +%% +Anyone can hold the helm when the sea is calm. + -- Publilius Syrus +%% +Anyone who cannot cope with mathematics is not fully human. +At best he is a tolerable subhuman who has learned to wear shoes, +bathe and not make messes in the house. + -- Lazarus Long +%% +Anyone who goes to a psychiatrist ought to have his head examined. + -- Samuel Goldwyn +%% +Anyone who has had a bull by the tail +knows five or six more things than someone who hasn't. + -- Mark Twain +%% +Anyone who imagines that all fruits ripen at the same time +as the strawberries, knows nothing about grapes. + -- Philippus Paracelsus +%% +Anyone who is capable of getting themselves made President +should on no account be allowed to do the job. + -- The Hitchhiker's Guide to the Galaxy +%% +Anything cut to length will be too short. +%% + "Anything else you wish to draw to my attention, Mr. Holmes ?" + "The curious incident of the stable dog in the nightime." + "But the dog did nothing in the nighttime." + "That was the curious incident." + -- A. Conan Doyle, "Silver Blaze" +%% +Anything free is worth what you'll pay for it. +%% +Anything is good and useful if it's made of chocolate. +%% +Anything is good if it's made of chocolate. +%% +Anything is possible, unless it's not. +%% +Anything labeled "NEW" and/or "IMPROVED" isn't. +The label means the price went up. +The label "ALL NEW", "COMPLETELY NEW", or "GREAT NEW" +means the price went way up. +%% +Anything worth doing is worth overdoing. +%% +Anytime things appear to be going better, you've overlooked something. +%% +Anyway, I keep picturing all these little kids playing some game in this +big field of rye and all. Thousands of little kids, and nobody's around -- +nobody big, I mean -- except me. And I'm standing on the edge of some crazy +cliff. What I have to do, I have to catch everybody if they start to go +over the cliff -- I mean if they're running and they don't look where they're +going I have to come out from somewhere and catch them. That's all I'd do +all day. I'd just be the catcher in the rye. I know it; I know it's crazy, +but that's the only thing I'd really like to be. I know it's crazy. + -- J.D. Salinger, "Catcher in the Rye" +%% +Appearances often are deceiving. + -- Aesop +%% +April is the cruellest month... + -- Thomas Stearns Eliot +%% +Are there those in the land of the brave +Who can tell me how I should behave + When I am disgraced + Because I erased + A file I intended to save? +%% +Are we not men? +%% +Are we running light with overbyte? +%% +Are you making all this up as you go along? +%% +Are you sure the back door is locked? +%% +Are your glasses mended with a strip of masking tape right over your nose? +Do you put pennies in the slots in your penny loafers? +Does your bow-tie flash "hey you kid" in red neon at parties? +Do you think pizza before noon is unhealthy? +Do you use the "greasy kid's stuff" to stick down your cowlick? +Do you wear a "nerd-pack" in your shirt pocket to keep the dozen + or so pencils from marking the cloth? +Do you think Mary Jane is somebody's name? +Is illegal fishing is something only a daring criminal would do? +Is Batman your hero? Superman? Green Lantern? The Shadow? +Do you think girls who kiss on the first date are loose? + + Rate yourself on the nerd-o-matic scale. (1 point for each YES answer) +0-2 -- You are really hip, a real cool cat, a hoopy frood. +3-5 -- There is hope for you yet. +6-7 -- Uh-oh, trouble in River City. +8-10 -- Your immortal soul is in peril. +11+ -- Does suicide seem attractive? +%% +Argue for your limitations, and sure enough, they're yours. + -- Messiah's Handbook : Reminders for the Advanced Soul +%% +Arguments are extremely vulgar, for everyone +in good society holds exactly the same opinion. + -- O. Wilde +%% +Arguments with furniture are rarely productive. +%% +Arithmetic is being able to count up to twenty without taking off your shoes. + -- Mickey Mouse +%% +Armor's Axiom: + Virtue is the failure to achieve vice. +%% +Armstrong's Collection Law: + If the check is truly in the mail, + it is surely made out to someone else. +%% +Arnold's Laws of Documentation: + 1.) If it should exist, it doesn't. + 2.) If it does exist, it's out of date. + 3.) Only documentation for useless programs transcends the + first two laws. +%% +Arrakis teaches the attitude of the knife - chopping off what's +incomplete and saying: "Now it's complete because it's ended here." + -- Muad'dib, "Dune" +%% +Art is a jealous mistress. + -- Ralph Waldo Emerson +%% +Art is a lie which makes us realize the truth. + -- Picasso +%% +Art is the tree of life. Science is the tree of death. +%% +Arthur's Laws of Love: + 1. People to whom you are attracted invariably think you + remind them of someone else. + 2. The love letter you finally got the courage to send will + be delayed in the mail long enough for you to make a fool + of yourself in person. +%% +Article the Third: + Where a crime of the kidneys has been committed, the accused should + enjoy the right to a speedy diaper change. Public announcements and + guided tours of the aforementioned are not necessary. +Article the Fourth: + The decision to eat strained lamb or not should be with the "feedee" + and not the "feeder". Blowing the strained lamb into the feeder's + face should be accepted as an opinion, not as a declaration of war. +Article the Fifth: + Babies should enjoy the freedom to vocalize, whether it be in church, + a public meeting place, during a movie, or after hours when the + lights are out. They have not yet learned that joy and laughter have + to last a lifetime and must be conserved. + -- Erma Bombeck, "A Baby's Bill of Rights" +%% +Artistic ventures highlighted. Rob a museum. +%% +As Gen. de Gaulle occassionally acknowledges America to be the daughter +of Europe, so I am pleased to come to Yale, the daughter of Harvard. + -- J.F. Kennedy +%% +As I was passing Project MAC, +I met a Quux with seven hacks. +Every hack had seven bugs; +Every bug had seven manifestations; +Every manifestation had seven symptoms. +Symptoms, manifestations, bugs, and hacks, +How many losses at Project MAC? +%% +As Will Rogers would have said, +"There is no such things as a free variable." +%% +As Zeus said to Narcissus, "Watch yourself." +%% +As a computer, I find your faith in technology amusing. +%% +As crazy as hauling timber into the woods. + -- Quintus Horatius Flaccus (Horace) +%% +As far as the laws of mathematics refer to reality, they are not certain; +and as far as they are certain, they do not refer to reality. + -- Einstein +%% +As far as we know, our computer has never had an undetected error. + -- Weisert +%% +As flies to wanton boys are we to the gods; they kill us for their sport. + -- Shakespeare, "King Lear" +%% +As for the women, though we scorn and flout 'em, +We may live with, but cannot live without 'em. + -- Frederic Reynolds +%% +As goatherd learns his trade by goat, so writer learns his trade by wrote. +%% +As in certain cults it is possible to +kill a process if you know its true name. + -- Ken Thompson and Dennis M. Ritchie +%% +As long as the answer is right, who cares if the question is wrong? +%% +As long as there are ill-defined goals, bizarre bugs, and unrealistic +schedules, there will be Real Programmers willing to jump in and Solve +The Problem, saving the documentation for later. +%% +As long as war is regarded as wicked, it will always have its fascination. +When it is looked upon as vulgar, it will cease to be popular. + -- Oscar Wilde +%% +As of next Thursday, UNIX will be flushed in favor of TOPS-10. +Please update your programs. +%% +As of next Tuesday, C will be flushed in favor of COBOL. +Please update your programs. +%% +As of next week, passwords will be entered in Morse code. +%% +As soon as we started programming, we found to our surprise that it wasn't +as easy to get programs right as we had thought. Debugging had to be +discovered. I can remember the exact instant when I realized that a large +part of my life from then on was going to be spent in finding mistakes in +my own programs. + -- Maurice Wilkes, designer of EDSAC, on programming, 1949 +%% +As the poet said, "Only God can make a tree" -- probably +because it's so hard to figure out how to get the bark on. + -- Woody Allen +%% +As the trials of life continue to take their toll, +remember that there is always a future in Computer Maintenance. + -- Deteriorata +%% +As well look for a needle in a bottle of hay. + -- Miguel de Cervantes +%% +As with most fine things, chocolate has its season. There is a simple memory +aid that you can use to determine whether it is the correct time to order +chocolate dishes: Any month whose name contains the letter A, E, or U is the +proper time for chocolate. + -- Sandra Boynton, "Chocolate: The Consuming Passion" +%% +Ashes to ashes, dust to dust, +If God won't have you, the devil must. +%% +Ask not for whom the Bell tolls, and you +will pay only the station-to-station rate. + -- Howard Kandel +%% +Ask not for whom the telephone bell tolls... +if thou art in the bathtub, it tolls for thee. +%% +Ask not what's inside your head, but what your head's inside of. + -- J.J. Gibson +%% +Ask your boss to reconsider -- +It's so difficult to take "Go to hell" for an answer. +%% +Ask yourself whether you are happy and you cease to be so. + -- John Stuart Mill +%% +Assembly language experience is [important] for the maturity +and understanding of how computers work that it provides. + -- D. Gries +%% +Astrology... just a bunch of Taurus. +%% +Asynchronous inputs are at the root of our race problems. + -- D. Winker and F. Prosser +%% +At ebb tide I wrote a line upon the sand, and gave it all my heart and all +my soul. At flood tide I returned to read what I had inscribed and found my +ignorance upon the shore. + -- Kahlil Gibran +%% +At least I thought I was dancing, 'til somebody stepped on my hand. + -- J.B. White +%% +At once it struck me what quality went to form a man of achievement, +especially in literature, and which Shakespeare possessed so enormously +-- I mean negative capability, that is, when a man is capable of being +in uncertainties, mysteries, doubts, without any irritable reaching +after fact and reason. + -- John Keats +%% +At the end of all civilization +Is the planet Terminus's location. + There's a girl there whose feat, + Without stone or concrete, +Nonetheless, was to lay the Foundation. +%% +At the end of your life there'll be a good rest, +and no further activities are scheduled. +%% +At the foot of the mountain, thunder: +The image of Providing Nourishment. +Thus the superior man is careful of his words +And temperate in eating and drinking. +%% +At the source of every error which is blamed on the computer you will find +at least two human errors, including the error of blaming it on the computer. +%% +At these prices, I lose money -- but I make it up in volume. + -- Peter G. Alaquon +%% +At times discretion should be thrown aside, +and with the foolish we should play the fool. + -- Menander +%% +Atheism is a non-prophet organization. +%% +Atlee is a very modest man. And with reason. + -- Winston Churchill +%% +Attractive bisexual young woman seeks same for high mellow times. +%% +Audacity, and again, audacity, and always audacity. + -- G.J. Danton +%% +Auribus teneo lupum. +[I hold a wolf by the ears.] +%% +Avec! +%% +Avert misunderstanding by calm, poise, and balance. +%% +Avoid Quiet and Placid persons unless you are in Need of Sleep. +%% +Avoid gunfire in the bathroom tonight. +%% +Avoid reality at all costs. +%% +Avoid strange women and temporary variables. +%% +BACCHUS: + A convenient deity invented by the ancients + as an excuse for getting drunk. +%% +BACHELOR: + A guy who is footloose and fiancee-free. +%% +BACHELOR: + A man who chases women and never Mrs. one. +%% +BACKWARD CONDITIONING: + Putting saliva in a dog's mouth in an attempt to make a bell ring. +%% +BAD CRAZINESS, MAN!!! +%% +BALLISTOPHOBIA: + Fear of bullets; +OTOPHOBIA: + Fear of opening one's eyes. +PECCATOPHOBIA: + Fear of sinning. +TAPHEPHOBIA: + Fear of being buried alive. +SITOPHOBIA: + Fear of food. +TRICHOPHOBIA: + Fear of hair. +VESTIPHOBIA: + Fear of clothing. +%% +BALTIMORE: + A wharf-rat stealing Diogenes' lamp. +%% +BAROMETER: + An ingenious instrument which indicates + what kind of weather we are having. +%% +BASIC is to computer programming as QWERTY is to typing. + -- Seymour Papert +%% +BASIC: + A programming language. Related to certain social diseases + in that those who have it will not admit it in polite company. +%% +BE ALERT!!!! (The world needs more lerts...) +%% +BELIEF: + Something you do not believe. +%% +BEWARE! People acting under the influence of human nature. +%% +BIRTH: + The first and direst of all disasters. +%% +BORE: + A person who talks when you wish him to listen. +%% +BOSS: + According to the Oxford English Dictionary, in the Middle Ages the + words "boss" and "botch" were largely synonymous, except that boss, + in addition to meaning "a supervisor of workers" also meant "an + ornamental stud." +%% +BOSTON: + Ludwig van Beethoven being jeered by 50,000 sports + fans for finishing second in the Irish jig competition. +%% +BOY: + A noise with dirt on it. +%% +BRAIN, v.: [as in "to brain"] + To rebuke bluntly, but not pointedly; + to dispel a source of error in an opponent. +%% +BRAIN: + The apparatus with which we think that we think. +%% +BRIDE: + A woman with a fine prospect of happiness behind her. +%% +BRIEFCASE: + A trial where the jury gets together and forms a lynching party. +%% +BROAD-MINDEDNESS: + The result of flattening high-mindedness out. +%% +BROKEE: + Someone who buys stocks on the advice of a broker. +%% +BS: You remind me of a man. +B: What man? +BS: The man with the power. +B: What power? +BS: The power of voodoo. +B: Voodoo? +BS: You do. +B: Do what? +BS: Remind me of a man. +B: What man? +BS: The man with the power... + -- Cary Grant, "The Bachelor and the Bobby-Soxer" +%% +BUG: + An elusive creature living in a program that makes it incorrect. + The activity of "debugging", or removing bugs from a program, ends + when people get tired of doing it, not when the bugs are removed. + -- "Datamation", January 15, 1984 +%% +BUGS: + A son of a glitch. +%% +BUREAUCRAT: + A politician who has tenure. +%% +Bachelors' wives and old maids' children are always perfect. + -- Nicolas Chamfort +%% +Back in '80 or '81 the workers were rioting in Gdansk and there were fears +that the Soviets would invade Poland to put down the demonstrations. Foreign +correspondents were curious as to just what the Poles would do if they were +invaded. They asked, "What will you do if the East Germans invade from the +West and the Soviets invade from the East? Who will you fight first?" + To which the Poles replied, "Why, we will fight the Germans first. +Business before pleasure." +%% +Bad men live that they may eat and drink, +whereas good men eat and drink that they may live. + -- Socrates +%% +Bagdikian's Observation: + Trying to be a first-rate reporter on the average American newspaper + is like trying to play Bach's "St. Matthew Passion" on a ukelele. +%% +Bahdges? We don't need no stinkin bahdges! + -- "The Treasure of Sierra Madre" +%% +Baker's First Law of Federal Geometry: + A block grant is a solid mass of money + surrounded on all sides by governors. +%% +Ban the bomb. Save the world for conventional warfare. +%% +Banacek's Eighteenth Polish Proverb: + The hippo has no sting, but the wise + man would rather be sat upon by the bee. +%% +Bank error in your favor. Collect $200. +%% +Barach's Rule: + An alcoholic is a person who drinks more than his own physician. +%% +Barbara's Rules of Bitter Experience: + (1) When you empty a drawer for his clothes + and a shelf for his toiletries, the relationship ends. + (2) When you finally buy pretty stationary + to continue the correspondence, he stops writing. +%% +Barker's Proof: + Proofreading is more effective after publication. +%% +Base 8 is just like base 10, if you are missing two fingers. + -- Tom Lehrer +%% +Basic Definitions of Science: + If it's green or wiggles, it's biology. + If it stinks, it's chemistry. + If it doesn't work, it's physics. +%% +Basic is a high level languish. +%% +Be a better psychiatrist and the world +will beat a psychopath to your door. +%% +Be assured that a walk through the ocean of most Souls would scarcely +get your Feet wet. Fall not in Love, therefore: it will stick to your face. + -- Deteriorata +%% +Be both a speaker of words and a doer of deeds. + -- Homer +%% +Be careful! Is it classified? +%% +Be careful how you get yourself involved with persons or +situations that can't bear inspection. +%% +Be careful of reading health books, you might die of a misprint. + -- Mark Twain +%% +Be careful when a loop exits to the same place from side and bottom. +%% +Be careful when you bite into your hamburger. + -- Derek Bok +%% +Be cautious in your daily affairs. +%% +Be cheerful while you are alive. + -- Phathotep, 24th Century B.C. +%% +Be circumspect in your liaisons with women. It is better +to be seen at the opera with a man than at mass with a woman. + -- DeMaintenon +%% +Be different: conform. +%% +Be free and open and breezy! Enjoy! +Things won't get any better so get used to it. +%% +Be independent. +Insult a rich relative today. +%% +Be it our wealth, our jobs, or even our homes; +nothing is safe while the legislature is in session. +%% +Be not anxious about what you have, but about what you are. + -- Pope St. Gregory I +%% +Be open to other people -- they may enrich your dream. +%% +Be prepared to accept sacrifices. +Vestal virgins aren't all that bad. +%% +Be security conscious -- National Defense is at stake. +%% +Be self-reliant and your success is assured. +%% +Be sociable. +Speak to the person next to you in the unemployment line tomorrow. +%% +Be sure to evaluate the bird-hand/bush ratio. +%% +Be valiant, but not too venturous. +Let thy attire be comely, but not costly. + -- John Lyly +%% +Beam me up, Scotty! +%% +Beam me up, Scotty, there's no intelligent life down here! +%% +Beauty and harmony are as necessary to you as the very breath of life. +%% +Beauty is one of the rare things which does not lead to doubt of God. + -- Jean Anouilh +%% +Beauty is truth, truth beauty, that is all +Ye know on earth, and all ye need to know. + -- John Keats +%% +Beauty may be skin deep, but ugly goes clear to the bone. + -- Redd Foxx +%% +Beauty seldom recommends one woman to another. +%% +Because I do, +Because I do not hope, +Because I do not hope to survive +Injustice from the Palace, death from the air, +Because I do, only do, +I continue... + -- T.S. Pynchon +%% +Because the wine remembers. +%% +Because we don't think about future generations, they will never forget us. + -- Henrik Tikkanen +%% +Bedfellows make strange politicians. +%% +Been Transferred Lately? +%% +Been through hell? +What did you bring back for me? +%% +Been transferred lately? +%% +Beer & Pretzels -- Breakfast of Champions. +%% +Before I knew the best part of my life had come, it had gone. +%% +Before borrowing money from a friend, decide which you need more. + -- Addison H. Hallock +%% +Before destruction a man's heart is +haughty, but humility goes before honour. + -- Psalms 18:12 +%% +"Before we get married," said the young woman to her fiancee, "I want to +confess some affairs that I've had in the past." + "But you told me all about those a few weeks ago," her young man +replied. + "Yes, darling," she explained, "but that was a few weeks ago." +%% +Before you ask more questions, think about +whether you really want to know the answers. + -- Gene Wolfe, "The Claw of the Conciliator" +%% +Beggar to well-dressed businessman: + "Could you spare $20.95 for a fifth of Chivas?" +%% +Beggars should be no choosers. + -- John Heywood +%% +Behind every argument is someone's ignorance. +%% +Behind every successful man you'll find a woman with nothing to wear. +%% +Behold the fool saith, "Put not all thine eggs in the one basket" -- which +is but a manner of saying, "Scatter your money and your attention"; but +the wise man saith, "Put all your eggs in the one basket and -- watch that +basket!" + -- Mark Twain +%% +Behold the warranty -- the bold print +giveth and the fine print taketh away. +%% +Beifeld's Principle: + The probability of a young man meeting a desirable and receptive + young female increases by pyramidical progression when he + is already in the company of (1) a date, (2) his wife, (3) a + better-looking and richer male friend. + -- R. Beifeld +%% +Being a miner, as soon as you're too old and tired and sick and +stupid to do your job properly, you have to go, where the very +opposite applies with the judges. + -- Beyond the Fringe +%% +Being a woman is a terribly difficult trade, +since it consists principally of dealings with men. + -- Conrad +%% +Being popular is important. Otherwise people might not like you. +%% +Being stoned on marijuana isn't very +different from being stoned on gin. + -- Ralph Nader +%% +Being ugly isn't illegal. Yet. +%% +Bell Labs Unix - Reach out and grep someone. +%% +Ben, why didn't you tell me? + -- Luke Skywalker +%% +Bennett's Laws of Horticulture: + (1) Houses are for people to live in. + (2) Gardens are for plants to live in. + (3) There is no such thing as a houseplant. +%% +Benny Hill: Would you like a peanut? +Girl: No, thank you, I don't want to be under obligation. +Benny Hill: You won't be under obligation for a peanut. + It's not as if it were a chocolate bar or something. +%% +Bershere's Formula for Failure: + There are only two kinds of people who fail: + those who listen to nobody... and those who listen to everybody. +%% +Better by far you should forget and +smile than that you should remember and be sad. + -- Christina Rossetti +%% +Better hope the life-inspector doesn't come +around while you have your life in such a mess. +%% +Better hope you get what you want before you stop wanting it. +%% +Better late than never. + -- Titus Livius (Livy) +%% +Better living a beggar than buried an emperor. +%% +Better the prince of some inferior court, +Than second, or less, in beatific light. + -- Lucifer, Joost van den Vondel's "Lucifer" +%% +Better to light one candle than to curse the darkness. + -- motto of the Christopher Society +%% +Better to use medicines at the outset than at the last moment. +%% +Between two evils, I always pick the one I never tried before. + -- Mae West +%% +Beware of Bigfoot! +%% +Beware of Programmers who carry screwdrivers. + -- Leonard Brandwein +%% +Beware of a dark-haired man with a loud tie. +%% +Beware of a tall black man with one blond shoe. +%% +Beware of a tall blond man with one black shoe. +%% +Beware of all enterprises that require new clothes, +and not rather a new wearer of clothes. + -- Henry David Thoreau +%% +Beware of bugs in the above code; +I have only proved it correct, not tried it. + -- D. Knuth +%% +Beware of friends who are false and deceitful. +%% +Beware of geeks bearing graft. +%% +Beware of low-flying butterflies. +%% +Beware of strong drink. It can make you +shoot at tax collectors -- and miss. + -- Lazarus Long, "Time Enough For Love" +%% +Beware of the Turing Tar-pit in which everything +is possible but nothing of interest is easy. +%% +Beware of the man who knows the answer before he understands the question. +%% +"Beware of the man who works hard to learn something, learns it, and finds +himself no wiser than before," Bokonon tells us. "He is full of murderous +resentment of people who are ignorant without having come by their +ignorance the hard way." + -- Vonnegut +%% +Beware the new TTY code! +%% +Beware the one behind you. +%% +Bierman's Laws of Contracts: + (1) In any given document, you can't cover all the "what if's". + (2) Lawyers stay in business resolving all the unresolved "what if's". + (3) Every resolved "what if" creates two unresolved "what if's". +%% +Big M, Little M, many mumbling mice +Are making midnight music in the moonlight, +Mighty nice! +%% +Big book, big bore. + -- Callimachus +%% +Bigamy is having one spouse too many. Monogamy is the same. +%% +Biggest security gap -- an open mouth. +%% +Bilbo's First Law: + You cannot count friends that are all packed up in barrels. +%% +Billy: Mom, you know that vase you said was handed down from + generation to generation? +Mom: Yes? +Billy: Well, this generation dropped it. +%% +Bing's Rule: + Don't try to stem the tide -- move the beach. +%% +Biology grows on you. +%% +Biology is the only science in which +multiplication means the same thing as division. +%% +Birds are entangled by their feet and men by their tongues. +%% +Bistromathics is simply a revolutionary new way of understanding the +behavior of numbers. Just as Einstein observed that space was not an +absolute, but depended on the observer's movement in space, and that +time was not an absolute, but depended on the observer's movement in +time, so it is now realized that numbers are not absolute, but depend +on the observer's movement in restaurants. + -- Douglas Adams +%% +Biz is better. +%% +Bizarreness is the essence of the exotic. +%% +Black shiny mollies and bright colored guppies, +Shy little angels as gentle as puppies, +Swimming and diving with scarcely a swish, +They were just some of my tropical fish. + +Then I got mantas that sting in the water, +Deadly piranhas that itch for a slaughter, +Savage male betas that bite with a squish, +Now I have many less tropical fish. + + If you think that + Fish are peaceful + That's an empty wish. + Just dump them together + And leave them alone, + And soon you will have -- no fish. + -- To My Favorite Things +%% +Blackout, heatwave, .44 caliber homicide, +The bums drop dead and the dogs go mad in packs on the West Side, +A young girl standing on a ledge, looks like another suicide, +She wants to hit those bricks, + 'cause the news at six got to stick to a deadline, +While the millionaires hide in Beekman place, +The bag ladies throw their bones in my face, +I get attacked by a kid with stereo sound, +I don't want to hear it but he won't turn it down... + -- Billy Joel, "Glass Houses" +%% +Blame Saint Andreas -- it's all his fault. +%% +Blessed are the forgetful: for they +get the better even of their blunders. + -- Nietzsche +%% +Blessed are the meek for they shall inhibit the earth. +%% +Blessed are they who Go Around in Circles, +for they Shall be Known as Wheels. +%% +Blessed is he who expects nothing, for he shall never be disappointed. + -- Alexander Pope +%% +Blessed is he who has reached the point of no return and knows it, +for he shall enjoy living. + -- W.C. Bennett +%% +Blessed is he who expects no gratitude, for he shall not be disappointed. + -- W.C. Bennett +%% +Blinding speed can compensate for a lot of deficiencies. + -- David Nichols +%% +Bloom's Seventh Law of Litigation: + The judge's jokes are always funny. +%% +Blue paint today. + [Funny only to Guy Harris and Hal Pierson. Ed.] +%% +Blutarsky's Axiom: + Nothing is impossible for the man who will not listen to reason. +%% +Boling's postulate: + If you're feeling good, don't worry. You'll get over it. +%% +Bolub's Fourth Law of Computerdom: + Project teams detest weekly progress reporting because it so + vividly manifests their lack of progress. +%% +Bones: "The man's DEAD, Jim!" +%% +Boob's Law: + You always find something in the last place you look. +%% +Boren's Law's of the Bureaucracy: + 1) When in doubt, mumble. + 2) When in trouble, delegate. + 3) When in charge, ponder. + -- James H. Boren +%% +Both models are identical in performance, functional operation, and +interface circuit details. The two models, however, are not compatible +on the same communications line connection. + -- Bell System Technical Reference +%% +Boucher's Observation: + He who blows his own horn always plays the music + several octaves higher than originally written. +%% +Bounders get bound when they are caught bounding. + -- Ralph Lewin +%% +Bower's Law: + Talent goes where the action is. +%% +Bowie's Theorem: + If an experiment works, you must be using the wrong equipment. +%% +Boy! Eucalyptus! +%% +Boy, I sure wish that I could be in the +'Advanced Systems Development' group! +%% +Boy, get your head out of the stars above, +You get the maximum pleasure from a minimum of love. +Save your heart and let your body be enough, +To get the maximum pleasure from a minimum of love. +Save your heart and let your body be enough, +And get the maximum pleasure from a minimum of love. + -- Mac Macinelli, "Minimum Love" +%% +Boy, that crayon sure did hurt! +%% +Boycott meat - suck your thumb. +%% +Bozo is the Brotherhood of Zips and Others. Bozos are people who band +together for fun and profit. They have no jobs. Anybody who goes on a +tour is a Bozo. Why does a Bozo cross the street? Because there's a Bozo +on the other side. It comes from the phrase vos otros, meaning others. +They're the huge, fat, middle waist. The archetype is an Irish drunk +clown with red hair and nose, and pale skin. Fields, William Bendix. +Everybody tends to drift toward Bozoness. It has Oz in it. They mean +well. They're straight-looking except they've got inflatable shoes. They +like their comforts. The Bozos have learned to enjoy their free time, +which is all the time. + -- Firesign Theatre, "If Bees Lived Inside Your Head" +%% +Bradley's Bromide: + If computers get too powerful, we can organize + them into a committee -- that will do them in. +%% +Brady's First Law of Problem Solving: + When confronted by a difficult problem, you can + solve it more easily by reducing it to the question, + "How would the Lone Ranger have handled this?" +%% +Brain fried -- core dumped +%% +Brandy-and-water spoils two good things. + -- Charles Lamb +%% +Break into jail and claim police brutality. +%% +Breakfast sometime? + Sure. +Shall I call you or just nudge you? +%% +Breeding rabbits is a hare raising experience. +%% + Brian Kernighan has an automobile which he helped design. +Unlike most automobiles, it has neither speedometer, nor gas guage, nor +any of the numerous idiot lights which plague the modern driver. +Rather, if the driver makes any mistake, a giant "?" lights up in the +center of the dashboard. "The experienced driver", he says, "will +usually know what's wrong." +%% +Bridge ahead. Pay troll. +%% +Brigands will demand your money or +your life, but a woman will demand both. + -- Samuel Butler +%% +Bringing computers into the home won't change +either one, but may revitalize the corner saloon. +%% +Britain has lowered the tax on chastity belts by about 60 cents each... +[reclassifying them] as a safety device rather than... clothing + -- NY Times +%% +Brogan's Constant: + People tend to congregate in the back + of the church and the front of the bus. +%% +Brooke's Law: + Whenever a system becomes completely defined, some damn fool + discovers something which either abolishes the system or + expands it beyond recognition. +%% +Buck-passing usually turns out to be a boomerang. +%% +Bucy's Law: + Nothing is ever accomplished by a reasonable man. +%% +Build a system that even a fool can use +and only a fool will want to use it. +%% +Building translators is good clean fun. + -- T. Cheatham +%% +Bumper sticker: + All the parts falling off this car are + of the very finest British manufacture. +%% +Bunker's Admonition: + You cannot buy beer; you can only rent it. +%% +Bureau Termination, Law of: + When a government bureau is scheduled to be phased out, + the number of employees in that bureau will double within + 12 months after the decision is made. +%% +Burke's Postulates: + Anything is possible if you don't know what you are talking about. + Don't create a problem for which you do not have the answer. +%% +Bus error -- driver executed. +%% +Business will be either better or worse. + -- Calvin Coolidge +%% +But Captain -- the engines can't take this much longer! +%% +"But Huey, you PROMISED!" +"Tell 'em I lied." +%% +But I don't like Spam!!!! +%% +But I find the old notions somehow appealing. Not that I want to go +back to them -- it is outrageous to have some outer authority tell you +what is proper use and abuse of your own faculties, and it is ludicrous +to hold reason higher than body or feeling. Still there is something +true and profoundly sane about the belief that acts like murder or +theft or assault violate the doer as well as the done to. We might +even, if we thought this way, have less crime. The popular view of +crime, as far as I can deduce it from the movies and television, is +that it is a breaking of a rule by someone who thinks they can get away +with that; implicitly, everyone would like to break the rule, but not +everyone is arrogant enough to imagine they can get away with it. It +therefore becomes very important for the rule upholders to bring such +arrogance down. + -- Marilyn French, "The Woman's Room" +%% +But Officer, I stopped for the last one, and it was green! +%% +But, for my own part, it was Greek to me. + -- William Shakespeare, "Julius Caesar" +%% +But has any little atom, + While a-sittin' and a-splittin', +Ever stopped to think or CARE + That E = m c**2 ? +%% +But if we laugh with derision, we will never understand. Human +intellectual capacity has not altered for thousands of years so far as +we can tell. If intelligent people invested intense energy in issues +that now seem foolish to us, then the failure lies in our understanding +of their world, not in their distorted perceptions. Even the standard +example of ancient nonsense -- the debate about angels on pinheads -- +makes sense once you realize that theologians were not discussing +whether five or eighteen would fit, but whether a pin could house a +finite or an infinite number. + -- S.J. Gould, "Wide Hats and Narrow Minds" +%% +But if you wish at once to do nothing and to be respectable +nowdays, the best pretext is to be at work on some profound study. + -- Leslie Stephen [Sketches from Cambridge] +%% +But in our enthusiasm, we could not resist a radical overhaul of the +system, in which all of its major weaknesses have been exposed, +analyzed, and replaced with new weaknesses. + -- Bruce Leverett, + "Register Allocation in Optimizing Compilers" +%% +But it does move! + -- Galileo Galilei +%% +But, officer, he's not drunk, I just saw his fingers twitch! +%% +But scientists, who ought to know +Assure us that it must be so. +Oh, let us never, never doubt +What nobody is sure about. + -- Hilaire Belloc +%% +But sex and drugs and rock & roll, why, they'd bring our blackest day. +%% +But soft you, the fair Ophelia: +Ope not thy ponderous and marble jaws, +But get thee to a nunnery -- go! + -- Mark "The Bard" Twain +%% +But these pills can't be habit forming; +I've been taking them for years. +%% +But this has taken us far afield from interface, which is not a bad +place to be, since I particularly want to move ahead to the kludge. +Why do people have so much trouble understanding the kludge? What +is a kludge, after all, but not enough K's, not enough ROM's, not +enough RAM's, poor quality interface and too few bytes to go around? +Have I explained yet about the bytes? +%% +But we've only fondled the surface of that subject. + -- Virginia Masters, of Master & Johnson +%% +But you shall not escape my iambics. + -- Gaius Valerius Catullus +%% +But you who live on dreams, you are better pleased with the sophistical +reasoning and frauds of talkers about great and uncertain matters than +those who speak of certain and natural matters, not of such lofty nature. + -- Leonardo Da Vinci, "The Codex on the Flight of Birds" +%% +Buzz off, Banana Nose; Relieve mine eyes +Of hateful soreness, purge mine ears of corn; +Less dear than army ants in apple pies +Art thou, old prune-face, with thy chestnuts worn, +Dropt from thy peeling lips like lousy fruit; +Like honeybees upon the perfum'd rose +They suck, and like the double-breasted suit +Are out of date; therefore, Banana Nose, +Go fly a kite, thy welcome's overstayed; +And stem the produce of thy waspish wits: +Thy logick, like thy locks, is disarrayed; +Thy cheer, like thy complexion, is the pits. +Be off, I say; go bug somebody new, +Scram, beat it, get thee hence, and nuts to you. +%% +By doing just a little every day, you can +gradually let the task completely overwhelm you. +%% +By failing to prepare, you are preparing to fail. +%% +By nature, men are nearly alike; +by practice, they get to be wide apart. + -- Confucius +%% +By necessity, by proclivity, and by delight, we all quote. +In fact, it is as difficult to appropriate the thoughts of others +as it is to invent. + -- R. Emerson + -- Quoted from a fortune cookie program + (whose author claims, "Actually, stealing IS easier.") + [to which I reply, "You think it's easy for me to + misconstrue all these misquotations?!?" Ed.] +%% +By perseverance the snail reached the Ark. + -- Charles Spurgeon +%% +By protracting life, we do not deduct one jot from the duration of death. + -- Titus Lucretius Carus +%% +By the yard, life is hard. +By the inch, it's a cinch. +%% +By trying we can easily learn to endure adversity. +Another man's, I mean. + -- Mark Twain +%% +By working faithfully eight hours a day, you may +eventually get to be boss and work twelve. + -- Robert Frost +%% +Bypasses are devices that allow some people to dash from point A to +point B very fast while other people dash from point B to point A very +fast. People living at point C, being a point directly in between, are +often given to wonder what's so great about point A that so many people +from point B are so keen to get there and what's so great about point B +that so many people from point B are so keen to get there. They often +wish that people would just once and for all work out where the hell +they wanted to be. + -- The Hitchhiker's Guide to the Galaxy +%% +Byte your tongue. +%% +C for yourself. +%% +C: + A programming language that is sort of like Pascal except more like + assembly except that it isn't very much like either one, or anything + else. It is either the best language available to the art today, or + it isn't. +%% +CABBAGE: + A familiar kitchen-garden vegetable + about as large and wise as a man's head. +%% +CALIFORNIA: + From Latin 'calor', meaning "heat" (as in English + 'calorie' or Spanish 'caliente'); and 'fornia', for "sexual + intercourse" or "fornication." Hence: Tierra de California, + "the land of hot sex." + -- Ed Moran, Covina, California +%% +CANCER (June 21 - July 22) + This is a good time for those of you who are rich and happy, + but a poor time for those of you born under this sign who are + poor and unhappy. To tell you the truth, any day is tough + when you're poor and unhappy. +%% +CANCER (June 21 - July 22) + You are sympathetic and understanding of other people's problems. + They think you are a sucker. You are always putting things off. + That's why you'll never make anything of yourself. Most welfare + recipients are Cancer people. +%% +CAPRICORN (Dec 23 - Jan 19) + You are conservative and afraid of taking risks. You don't do + much of anything and are lazy. There has never been a Capricorn + of any importance. Capricorns should avoid standing still for + too long as they tend to take root and become trees. +%% +CAPRICORN (Dec.22 - Jan.19) + Play your hunches. This is a day when luck will play an important + part in your life. If you were smarter, you wouldn't need so much + luck and you wouldn't be reading your horoscope, either. You are + a suspicious person, and it will occur to you that astrologers + don't know what they're talking about any more than your Aunt Martha. +%% +CChheecckk yyoouurr dduupplleexx sswwiittcchh.. +%% +CHARITY: + A thing that begins at home and usually stays there. +%% +CHASTITY BELT: + An anti-trust suit. + (And an unchivalrous knight is the one that files it.) +%% +CHEMICALS: + Noxious substances from which modern foods are made. +%% +CHICAGO: + Where the dead still vote... early and often! +%% +CHRIST: + A man who was born at least 5,000 years ahead of his time. +%% +CHRISTMAS: + A day set apart by some as a time for turkey, presents, cranberry + salads, family get-togethers; for others, noted as having the best + response time of the entire year. +%% +CHRISTMAS: + A time when each of us gets to reflect upon what we each most + deeply and sincerely believe in. Money. At the mall of our + choice. +%% +CIGARETTE: + A fire at one end, a fool at the other, + and a bit of tobacco in between. +%% +CLEVELAND: + Where their last tornado did six + million dollars worth of improvements. +%% +COBOL is for morons. + -- E.W. Dijkstra +%% +COBOL: + An exercise in Artificial Inelegance. +%% +COBOL: + Completely Over and Beyond reason Or Logic. +%% +COCAINE: + The thinking man's Dristan. +%% +COLD: + When the local flashers are handing out written descriptions. +%% +COLD: + When the politicians walk around + with their hands in their own pockets. +%% +COLLABORATION: + A literary partnership based on the false + assumption that the other fellow can spell. +%% +COLLEGE: + The fountains of knowledge, where everyone goes to drink. +%% +COMMENT: + A superfluous element of a source program included so the + programmer can remember what the hell it was he was doing + six months later. Only the weak-minded need them, according + to those who think they aren't. +%% +COMMITTMENT: + Committment can be illustrated by a breakfast of ham and eggs. + The chicken was involved, the pig was committed. +%% +COMPASS [for the CDC-6000 series] is the sort of assembler +one expects from a corporation whose president codes in octal. + -- J.N. Gray +%% +COMPLIMENT: + When you say something to another which everyone knows isn't true. +%% +COMPUTER SCIENCE: + 1) A study akin to numerology and astrology, but lacking the + precision of the former and the success of the latter. + 2) The protracted value analysis of algorithms. + 3) The costly enumeration of the obvious. + 4) The boring art of coping with a large number of trivialities. + 5) Tautology harnessed in the service of Man at the speed of light. + 6) The Post-Turing decline in formal systems theory. +%% +COMPUTER: + An electronic entity which performs sequences of useful steps in a + totally understandable, rigorously logical manner. If you believe + this, see me about a bridge I have for sale in Manhattan. +%% +CONCEPT: + Any "idea" for which an outside + consultant billed you more than $25,000. +%% +CONFERENCE: + A special meeting in which the boss gathers subordinates to hear + what they have to say, so long as it doesn't conflict with what + he's already decided to do. +%% +CONFIRMED BACHELOR: + A man who goes through life without a hitch. +%% +CONFUSION: + One woman plus one left turn. +EXCITEMENT: + Two women plus one secret. +BEDLAM: + Three women plus one bargain. +CHAOS: + Four women plus one luncheon check. +%% +CONSENT DECREE: + A document in which a hapless company consents never to commit + in the future whatever heinous violations of Federal law it + never admitted to in the first place. +%% +CONSULTANT: + (1) Someone you pay to take the watch off your wrist and tell + you what time it is. (2) (For resume use) The working title + of anyone who doesn't currently hold a job. Motto: Have + Calculator, Will Travel. +%% +CONSULTANT: + An ordinary man a long way from home. +%% +CONSULTANT: + [From con "to defraud, dupe, swindle," or, possibly, French con + (vulgar) "a person of little merit" + sult elliptical form of + "insult."] A tipster disguised as an oracle, especially one who + has learned to decamp at high speed in spite of a large briefcase + and heavy wallet. +%% +CONSULTANT: + Someone who knowns 101 ways to make love, but can't get a date. +%% +CONSULTANT: + Someone who'd rather climb a tree and tell a + lie than stand on the ground and tell the truth. +%% +CONSULTATION: + Medical term meaning "to share the wealth." +%% +CONVERSATION: + A vocal competition in which the one who + is catching his breath is called the listener. +%% +COPYING MACHINE: + A device that shreds paper, flashes mysteriously + coded messages, and makes duplicates for everyone + in the office who isn't interested in reading them. +%% +CORONATION: + The ceremony of investing a sovereign with the outward and visible + signs of his divine right to be blown skyhigh with a dynamite bomb. +%% +CORRUPT: + In politics, holding an office of trust or profit. +%% +COWARD: + One who in a perilous emergency thinks with his legs. +%% +CREDITOR: + A man who has a better memory than a debtor. +%% +CRITIC: + A person who boasts himself hard to please + because nobody tries to please him. +%% +CURSOR: + One whose program will not run. + -- Robb Russon +%% +CYNIC: + A blackguard whose faulty vision sees things as they are, + not as they ought to be. Hence the custom among the + Scythians of plucking out a cynic's eyes to improve his vision. +%% +CYNIC: + Experienced. +%% +CYNIC: + One who looks through rose-colored glasses with a jaundiced eye. +%% +Cahn's Axiom: + When all else fails, read the instructions. +%% +California is a fine place to live -- if you happen to be an orange. + -- Fred Allen +%% +Call on God, but row away from the rocks. + -- Indian proverb +%% +Calvin Coolidge looks as if he had been weaned on a pickle. + -- Alice Roosevelt Longworth +%% +Calvin Coolidge was the greatest man +who ever came out of Plymouth Corner, Vermont. + -- Clarence Darrow +%% +Camille's Axiom: + If you haven't asked yourself, "Why the hell did + I go to college anyway?", you must be teaching. +%% +Campbell's Law: + Nature abhors a vacuous experimenter. +%% +Can anyone remember when the times +were not hard, and money not scarce? +%% +Can anything be sadder than work left unfinished? +Yes, work never begun. +%% +Can you buy friendship? You not only can, you must. It's the +only way to obtain friends. Everything worthwhile has a price. + -- Robert J. Ringer +%% +Canada Bill Jones's Motto: + It's morally wrong to allow suckers to keep their money. + +Canada Bill Jones's Supplement: + A Smith and Wesson beats four aces. +%% +Canada Post doesn't really charge 32 cents for a stamp. +It's 2 cents for postage and 30 cents for storage. + -- Gerald Regan, Cabinet Minister, 12/31/83 Financial Post +%% +Candy +Is dandy +But liquor +Is quicker. + -- Ogden Nash, "Reflections on Ice-Breaking" + +Fortune updates the great quotes: #53. + Candy is dandy; but liquor is quicker, + and sex won't rot your teeth. +%% +Can't open /usr/fortunes. Lid stuck on cookie jar. +%% +Can't open /usr/games/lib/fortunes.dat. +%% +Captain Penny's Law: + You can fool all of the people some of the time, and + some of the people all of the time, but you Can't Fool Mom. +%% +Captain's Log, star date 21:34.5... +%% +Carson's Consolation: + Nothing is ever a complete failure. + It can always be used as a bad example. +%% + Carol's head ached as she trailed behind the unsmiling Calibrees +along the block of booths. She chirruped at Kennicott, "Let's be wild! +Let's ride on the merry-go-round and grab a gold ring!" + Kennicott considered it, and mumbled to Calibree, "Think you folks +would like to stop and try a ride on the merry-go-round?" + Calibree considered it, and mumbled to his wife, "Think you'd like +to stop and try a ride on the merry-go-round?" + Mrs. Calibree smiled in a washed-out manner, and sighed, "Oh no, +I don't believe I care to much, but you folks go ahead and try it." + Calibree stated to Kennicott, "No, I don't believe we care to a +whole lot, but you folks go ahead and try it." + Kennicott summarized the whole case against wildness: "Let's try +it some other time, Carrie." + She gave it up. + -- Sinclair Lewis, "Main Street" +%% +Carson's Observation on Footwear: + If the shoe fits, buy the other one too. +%% +Carswell's Corollary: + Whenever man comes up with a better mousetrap, + nature invariably comes up with a better mouse. +%% +Cats, no less liquid than their shadows, offer no angles to the wind. +%% +Caution: Breathing may be hazardous to your health. +%% +Caution: Keep out of reach of children. +%% +Celebrate Hannibal Day this year. Take an elephant to lunch. +%% +Census Taker to Housewife: +Did you ever have the measles, and, if so, how many? +%% +Center meeting at 4pm in 2C-543. +%% +Cerebus: I'd love to lick apricot brandy out of your navel. +Jaka: Look, Cerebus -- Jaka has to tell you... something +Cerebus: If Cerebus had a navel, would you lick apricot brandy out + of it? +Jaka: Oooh. +Cerebus: You don't like apricot brandy? + -- Cerebus, #6, "The Secret" +%% +Certain old men prefer to rise at dawn, taking a cold bath and a long +walk with an empty stomach and otherwise mortifying the flesh. They +then point with pride to these practices as the cause of their sturdy +health and ripe years; the truth being that they are hearty and old, +not because of their habits, but in spite of them. The reason we find +only robust persons doing this thing is that it has killed all the +others who have tried it. +%% +Certainly the game is rigged. +Don't let that stop you; if you don't bet, you can't win. + -- Robert Heinlein, "Time Enough For Love" +%% +Certainly there are things in life that money can't buy, +But it's very funny -- +did you ever try buying them without money? + -- Ogden Nash +%% +C'est magnifique, mais ce n'est pas l'Informatique. + -- Bosquet [on seeing the IBM 4341] +%% +C'est magnifique, mais ce n'est pas la gare! +%% +Chance is perhaps the work of God when He did not want to sign. + -- Anatole France +%% +Change your thoughts and you change your world. +%% +Chapter 2: Newtonian Growth and Decay + + The growth-decay formulas were developed in the trivial fashion by +Isaac Newton's famous brother Phigg. His idea was to provide an equation +that would describe a quantity that would dwindle and dwindle, but never +quite reach zero. Historically, he was merely trying to work out his +mortgage. Another versatile equation also emerged, one which would define +a function that would continue to grow, but never reach unity. This equation +can be applied to charging capacitors, over-damped springs, and the human +race in general. +%% + Chapter VIII +Due to the convergence of forces beyond his comprehension, +Salvatore Quanucci was suddenly squirted out of the universe +like a watermelon seed, and never heard from again. +%% +Charity begins at home. + -- Publius Terentius Afer (Terence) +%% +Charlie was a chemist, +But Charlie is no more. +What Charlie thought was H2O was H2SO4. +%% +Charm is a way of getting the answer "Yes" -- +without having asked any clear question. +%% +Chaste makes waste. +%% +Chastity is its own punishment. +%% +Chastity: + The most unnatural of the sexual perversions. + -- Aldous Huxley +%% +Cheap things are of no value, valuable things are not cheap. +%% +Cheer Up! Things are getting worse at a slower rate. +%% +Cheit's Lament: + If you help a friend in need, he is sure to remember you-- + the next time he's in need. +%% +Chemist who falls in acid is absorbed in work. +%% +Chemist who falls in acid will be tripping for weeks. +%% +Chemistry professors never die, they just fail to react. +%% +Cheops' Law: + Nothing ever gets built on schedule or within budget. +%% +"Cheshire-Puss," she began, "would you tell me, please, + which way I ought to go from here?" +"That depends a good deal on where you want to get to," said the Cat. +"I don't care much where--" said Alice. +"Then it doesn't matter which way you go," said the Cat. +%% +Chess tonight. +%% +Chicken Little was right. +%% +Chicken Soup: + An ancient miracle drug containing equal parts of aureomycin, + cocaine, interferon, and TLC. The only ailment chicken soup + can't cure is neurotic dependence on one's mother. + -- Arthur Naiman +%% +Children are natural mimics who act like their parents +despite every effort to teach them good manners. +%% +Children aren't happy without something to ignore, +And that's what parents were created for. + -- Ogden Nash +%% +Children seldom misquote you. In fact, they usually +repeat word for word what you shouldn't have said. +%% +Chinese saying: "He who speak with forked tongue, not need chopsticks." +%% +Chism's Law of Completion: + The amount of time required to complete a government project is + precisely equal to the length of time already spent on it. +%% +Chisolm's First Corollary to Murphy's Second Law: + When things just can't possibly get any worse, they will. +%% +Chocolate Chip. +%% +Choose in marriage only a woman whom you would choose as +a friend if she were a man. + -- Joubert +%% +Christ died for our sins, so let's not disappoint Him. +%% +Christianity and Judaism aren't all that different, really. Growing up in +a Christian family, the feeling of guilt for Man's sins comes from God. +In a Jewish family, it comes from your parents. +%% +Christianity might be a good thing if anyone ever tried it. + -- George Bernard Shaw +%% +Christmas time is here, by Golly; Kill the turkeys, ducks and chickens; +Disapproval would be folly; Mix the punch, drag out the Dickens; +Deck the halls with hunks of holly; Even though the prospect sickens, +Fill the cup and don't say when... Brother, here we go again. + +On Christmas day, you can't get sore; Relations sparing no expense'll, +Your fellow man you must adore; Send some useless old utensil, +There's time to rob him all the more, Or a matching pen and pencil, +The other three hundred and sixty-four! Just the thing I need... how nice. + +It doesn't matter how sincere Hark The Herald-Tribune sings, +It is, nor how heartfelt the spirit; Advertising wondrous things. +Sentiment will not endear it; God Rest Ye Merry Merchants, +What's important is... the price. May you make the Yuletide pay. + Angels We Have Heard On High, +Let the raucous sleighbells jingle; Tell us to go out and buy. +Hail our dear old friend, Kris Kringle, Sooooo... +Driving his reindeer across the sky, +Don't stand underneath when they fly by! + -- Tom Lehrer +%% +Churchill's Commentary on Man: + Man will occasionally stumble over the truth, + but most of the time he will pick himself up and continue on. +%% +Circumstances rule men; men do not rule circumstances. + -- Herodotus +%% +Civilization and profits go hand in hand. + -- Calvin Coolidge +%% +Civilization, as we know it, will end sometime this evening. +See SYSNOTE tomorrow for more information. +%% +Civilization is the limitless multiplication of unnecessary necessities. + -- Mark Twain +%% +Clark Kent is a transvestite. +%% +Class, that's the only thing that counts in life. Class. +Without class and style, a man's a bum; he might as well be dead. + -- "Bugsy" Siegel +%% +Clay's Conclusion: + Creativity is great, but plagiarism is faster. +%% +Cleanliness is next to impossible. +%% +Cleveland? +Yes, I spent a week there one day. +%% +Clones are people two. +%% +Cloning is the sincerest form of flattery. +%% +Clothes make the man. +Naked people have little or no influence on society. + -- Mark Twain +%% +Clovis' Consideration of an Atmospheric Anomaly: + The perversity of nature is nowhere better demonstrated + than by the fact that, when exposed to the same atmosphere, + bread becomes hard while crackers become soft. +%% +Cobol programmers are down in the dumps. +%% +Cocaine -- the thinking man's Dristan. +%% +Coding is easy; All you do is sit staring at a +terminal until the drops of blood form on your forehead. +%% +Cogito cogito ergo cogito sum -- +I think that I think, therefore I think that I am. + -- Ambrose Bierce +%% +Cohen's Law: + There is no bottom to worse. +%% +Cohn's Law: + The more time you spend in reporting on what you are doing, the less + time you have to do anything. Stability is achieved when you spend + all your time reporting on the nothing you are doing. +%% +Cold hands, no gloves. +%% +Cole's Law: + Thinly sliced cabbage. +%% +College football is a game which would be much more interesting if the +faculty played instead of the students, and even more interesting if +the trustees played. There would be a great increase in broken arms, +legs, and necks, and simultaneously an appreciable diminution in the +loss to humanity. + -- H.L. Mencken +%% +Colorless green ideas sleep furiously. +%% +Colvard's Logical Premises: + All probabilities are 50%. +Either a thing will happen or it won't. + +Colvard's Unconscionable Commentary: + This is especially true when + dealing with someone you're attracted to. + +Grelb's Commentary: + Likelihoods, however, are 90% against you. +%% +Come fill the cup and in the fire of spring +Your winter garment of repentence fling. +The bird of time has but a little way +To flutter -- and the bird is on the wing. + -- Omar Khayyam +%% +Come home America. + -- George McGovern, 1972 +%% +Come, let us hasten to a higher plane, +Where dyads tread the fairy fields of Venn, +Their indices bedecked from one to n, +Commingled in an endless Markov chain! + +Come, every frustum longs to be a cone, +And every vector dreams of matrices. +Hark to the gentle gradient of the breeze: +It whispers of a more ergodic zone. + +In Riemann, Hilbert or in Banach space +Let superscripts and subscripts go their ways. +Our asymptotes no longer out of phase, +We shall encounter, counting, face to face. + -- The Cyberiad +%% +Come live with me, and be my love, +And we will some new pleasures prove +Of golden sands, and crystal brooks, +With silken lines, and silver hooks. + -- John Donne +%% +Come live with me and be my love, +And we will some new pleasures prove +Of golden sands and crystal brooks +With silken lines, and silver hooks. +There's nothing that I wouldn't do +If you would be my posslq. + +You live with me, and I with you, +And you will be my posslq. +I'll be your friend and so much more; +That's what a posslq is for. + +And everything we will confess; +Yes, even to the IRS. +Some day on what we both may earn, +Perhaps we'll file a joint return. +You'll share my pad, my taxes, joint; +You'll share my life - up to a point! +And that you'll be so glad to do, +Because you'll be my posslq. +%% +Come, muse, let us sing of rats! + -- From a poem by James Grainger, 1721-1767 +%% +Come up and see me sometime. Come Wednesday, that's amateur night. + -- Mae West +%% +Come, you spirits +That tend on mortal thoughts, unsex me here, +And fill me, from the crown to the toe, top-full +Of direst cruelty! make thick my blood, +Stop up the access and passage to remorse +That no compunctious visiting of nature +Shake my fell purpose, not keep peace between +The effect and it! Come to my woman's breasts, +And take my milk for gall, you murdering ministers, +Wherever in your sightless substances +You wait on nature's mischief! Come, thick night, +And pall the in the dunnest smoke of hell, +That my keen knife see not the wound it makes, +Nor heaven peep through the blanket of the dark, +To cry `Hold, hold!' + -- Lady MacBeth +%% +Coming together is a beginning; + keeping together is progress; + working together is success. +%% +Commit the oldest sins the newest kind of ways. + -- William Shakespeare, "Henry IV" +%% +Common sense is the collection of prejudices acquired by age eighteen. + -- Albert Einstein +%% +Commoner's three laws of ecology: + 1) No action is without side-effects. + 2) Nothing ever goes away. + 3) There is no free lunch. +%% +Communicate! It can't make things any worse. +%% +Competence, like truth, beauty, and contact lenses, +is in the eye of the beholder. + -- Dr. Laurence J. Peter +%% +Competitive fury is not always anger. It is the true missionary's +courage and zeal in facing the possibility that one's best may not +be enough. + -- Gene Scott +%% +Computer programmers do it byte by byte. +%% +Computer programmers never die, they just get lost in the processing. +%% +Computer programs expand so as to fill the core available. +%% +Computers are not intelligent. They only think they are. +%% +Computers are unreliable, but humans are even more unreliable. +Any system which depends on human reliability is unreliable. + -- Gilb +%% +Computers don't actually think. + You just think they think. + (We think.) +%% +Conceit causes more conversation than wit. + -- LaRouchefoucauld +%% +Condense soup, not books! +%% +Confess your sins to the Lord and you will be forgiven; +confess them to man and you will be laughed at. + -- Josh Billings +%% +Confession is good for the soul, but bad for the career. +%% +Confession is good for the soul only in the sense +that a tweed coat is good for dandruff. + -- Peter de Vries +%% +Confidence is the feeling you have before you understand the situation. +%% +Conflicting research paradigms +Have legitimized various crimes. + The worst we can see + Is in psychology, +Measuring reaction times. +%% +Conformity is the refuge of the unimaginative. +%% +Confucious say too damn much! +%% +Confucius say too much. + -- Recent Chinese Proverb +%% +Confusion will be my epitaph +as I walk a cracked and broken path +If we make it we can all sit back and laugh +but I fear that tomorrow we'll be crying. + -- King Crimson, "In the Court of the Crimson King" +%% +Congratulations! You are the one-millionth user to log into our system. +If there's anything special we can do for you, anything at all, don't +hesitate to ask! +%% +Conscience doth make cowards of us all. + -- Shakespeare +%% +Conscience is defined as the thing that hurts +when everything else feels great. +%% +Conscience is the inner voice that warns us somebody may be looking. + -- H.L. Mencken +%% +Conscience is what hurts when everything else feels so good. +%% +Conservative: + One who admires radicals centuries after they're dead. + -- Leo C. Rosten +%% +Consider the little mouse, how sagacious an animal +it is which never entrusts its life to one hole only. + -- Titus Maccius Plautus +%% +Consider the postage stamp: its usefulness consists in +the ability to stick to one thing till it gets there. + -- Josh Billings +%% +Consultants are mystical people who ask a +company for a number and then give it back to them. +%% +Continental Life. Why? +%% +"Contrariwise," continued Tweedledee, "if it was so, it might be, and +if it were so, it would be; but as it isn't, it ain't. That's logic!" + -- Lewis Carroll +%% +Convention is the ruler of all. + -- Pindar +%% +Conversation enriches the understanding, +but solitude is the school of genius. +%% +Conway's Law: + In any organization there will always be one person who knows + what is going on. + + This person must be fired. +%% +Correspondence Corollary: + An experiment may be considered a success if no more than half + your data must be discarded to obtain correspondence with your theory. +%% +Corruption is not the No. 1 priority of the Police Commissioner. +His job is to enforce the law and fight crime. + -- P.B.A. President E.J. Kiernan +%% +Corry's Law: + Paper is always strongest at the perforations. +%% +Couldn't we jury-rig the cat to act as an audio switch, and have it yell +at people to save their core images before logging them out? I'm sure +the cattle prod would be effective in this regard. In any case, a traverse +mounted iguana, while more perverted, gives better traction, not to mention +being easier to stake. +%% +Counting in binary is just like counting +in decimal -- if you are all thumbs. + -- Glaser and Way +%% +Counting in octal is just like counting +in decimal -- if you don't use your thumbs. + -- Tom Lehrer +%% +Courage is fear that has said its prayers. +%% +Courage is grace under pressure. +%% +Courage is resistance to fear, mastery of fear -- not absence of fear. + -- Mark Twain +%% +Courage is your greatest present need. +%% +[Crash programs] fail because they are based on the theory that, +with nine women pregnant, you can get a baby a month. + -- Wernher von Braun +%% +Crazee Edeee, his prices are INSANE!!! +%% +Creating computer software is always a demanding and painstaking +process -- an exercise in logic, clear expression, and almost fanatical +attention to detail. It requires intelligence, dedication, and an +enormous amount of hard work. But, a certain amount of unpredictable +and often unrepeatable inspiration is what usually makes the difference +between adequacy and excellence. +%% +Creativity in living is not without its attendant difficulties, for +peculiarity breeds contempt. And the unfortunate thing about being +ahead of your time when people finally realize you were right, they'll +say it was obvious all along. + -- Alan Ashley-Pitt +%% +Creativity is no substitute for knowing what you are doing. +%% +Creativity is not always bred in an environment of tranquility; +sometimes you have to squeeze a little to get the paste out of the tube. +%% +Crenna's Law of Political Accountability: + If you are the first to know about something bad, + you are going to be held responsible for acting on it, + regardless of your formal duties. +%% +Crime does not pay... as well as politics. + -- A.E. Newman +%% +Crinklaw's Observation: + Nowadays the order of life is reversed: Sex is first enjoyed, + marriage follows, and after marriage comes abstinence. +%% +Criticism comes easier than craftsmanship. + -- Zeuxis +%% +Crito, I owe a cock to Asclepius; will you remember to pay the debt? + -- Socrates' last words +%% +Cropp's Law: + The amount of work done varies inversly + with the time spent in the office. +%% +Cruickshank's Law of Committees: + If a committee is allowed to discuss a bad idea long enough, it + will inevitably decide to implement the idea simply because so + much work has already been done on it. +%% +Crush! Kill! Destroy! +%% +Culture is the habit of being pleased with the best and knowing why. +%% +Cure the disease and kill the patient. + -- Francis Bacon +%% +Cutler Webster's Law: + There are two sides to every argument, unless a person + is personally involved, in which case there is only one. +%% +DALLAS: + The city that chose Astroturf to + keep the cheerleaders from grazing. +%% +DAMN IT, I GOTTA GET OUTTA HERE! +%% +DATA: + An accrual of straws on the backs of theories. +%% +DATA: + Computerspeak for "information". Properly pronounced + the way Bostonians pronounce the word for a female child. +%% +DAWN: + The time when men of reason go to bed. +%% +DEADWOOD: + Anyone in your company who is more senior than you are. +%% +DEATH WISH: + The only wish that always comes true, whether or not one wishes it to. +%% +DEATH: + To stop sinning suddenly. + -- Elbert Hubbard +%% +DECISIONMAKER: + The person in your office who was unable + to form a task force before the music stopped. +%% +DEFAULT: + The hardware's, of course. +%% +DEJA VU: + French., already seen; unoriginal; trite. + Psychol., The illusion of having previously experienced + something actually being encountered for the first time. + Psychol., The illusion of having previously experienced + something actually being encountered for the first time. +%% + DELETE A FORTUNE! +Don't some of these fortunes just drive you nuts?! +Wouldn't you like to see some of them deleted from the system? +You can! Just mail to `fortune' with the fortune you hate most, +and we'll make sure it gets expunged. +%% +DELIBERATION: + The act of examining one's bread + to determine which side it is buttered on. +%% +DENVER: + A smallish city located just below the `O' in Colorado. +%% +DESIGN: + What you regret not doing later on. +%% +DIPLOMACY: + Lying in state. +%% +DISBAR: + As distinguished from some other bar. +%% +DISTRESS: + A disease incurred by exposure to the prosperity of a friend. +%% +DROP THE DAMN BEAR!!! +%% +DRUG: + A substance that, when injected into a rat, + produces a scientific paper. +%% + Dallas Cowboys Official Schedule + + Sept 14 Pasadena Junior High + Sept 21 Boy Scout Troop 049 + Sept 28 Blind Academy + Sept 30 World War I Veterans + Oct 5 Brownie Scout Troop 041 + Oct 12 Sugarcreek High Cheerleaders + Oct 26 St. Thomas Boys Choir + Nov 2 Texas City Vet Clinic + Nov 9 Korean War Amputees + Nov 15 VA Hospital Polio Patients +%% +Dallas still lives. God MUST be dead. +%% +Dames lie about anything -- just for practice. + -- Raymond Chandler +%% +Dammit Jim, I'm an actor not a doctor. +%% +Damn, I need a Coke! + -- Dr. William DeVries + [after implanting the first artificial human heart] +%% +Damn braces. + -- William Blake, "Proverbs of Hell" +%% +Darth Vader! Only you would be so bold! + -- Princess Leia Organa +%% +Darth Vader sleeps with a Teddywookie. +%% +Dave has an areoplane, +In which he likes to frisk. +Oh what a foolish boy, +His silly *. +%% +Davis' Law of Traffic Density: + The density of rush-hour traffic is directly proportional to + 1.5 times the amount of extra time you allow to arrive on time. +%% +Davis's Dictum: + Problems that go away by themselves, come back by themselves. +%% +Day of inquiry. You will be subpoenaed. +%% +DeVries' Dilemma: + If you hit two keys on the typewriter, + the one you don't want hits the paper. +%% +Dealing with failure is easy: + Work hard to improve. +Success is also easy to handle: + You've solved the wrong problem. Work hard to improve. +%% +Dealing with the problem of pure staff accumulation, +all our researches ... point to an average increase of 5.75% per year. + -- C.N. Parkinson +%% +Dear Ann Landers: + I have a problem. I have two brothers; one works for the Illinois +Bell Telephone Company, the other brother was just sentenced to death +in the electric chair for murder. My mother died from insanity when +I was three years old. My two sisters are prostitutes and my father +sells narcotics. + I recently met girl who was just released from a reformatory where +she served time for smothering her illegitimate child to death. I love +this girl and want to marry her. My problem is this -- dare I tell her +about my brother who works for Illinois Bell? + -- Confused. +%% +Dear Ann Landers: + My husband watches the TV preachers every Sunday. He claims +one minister said there are 350 different sins. My husband wants to +know if you can get the list. He thinks he is missing something. + -- E.J. Mayfield +%% +Dear Freshman, + You don't know who I am and frankly shouldn't care, but +unknown to you we have something in common. We are both rather +prone to mistakes. I was elected Student Government President by +mistake, and you came to school here by mistake. +%% +Dear Miss Manners: +I carry a big black umbrella, even if there's just a thirty percent chance of +rain. May I ask a young lady who is a stranger to me to share its protection? +This morning, I was waiting for a bus in comparative comfort, my umbrella +protecting me from the downpour, and noticed an attractive young woman getting +soaked. I have often seen her at my bus stop, although we have never spoken, +and I don't even know her name. Could I have asked her to get under my +umbrella without seeming insulting? + +Gentle Reader: +Certainly. Consideration for those less fortunate than you is always proper, +although it would be more convincing if you stopped babbling about how +attractive she is. In order not to give Good Samaritanism a bad name, Miss +Manners asks you to allow her two or three rainy days of unmolested protection +before making your attack. +%% +Dear Miss Manners: + My home economics teacher says that one must never place one's +elbows on the table. However, I have read that one elbow, in between +courses, is all right. Which is correct? + +Gentle Reader: + For the purpose of answering examinations in your home +economics class, your teacher is correct. Catching on to this principle +of education may be of even greater importance to you now than learning +correct current table manners, vital as Miss Manners believes that is. +%% +Dear Miss Manners: +Please list some tactful ways of removing a man's saliva from your face. + +Gentle Reader: +Please list some decent ways of acquiring a man's saliva on your face. +If the gentleman sprayed you inadvertently to accompany enthusiastic +discourse, you may step back two paces, bring out your handkerchief, +and go through the motions of wiping your nose, while trailing the cloth +along your face to pick up whatever needs mopping along the route. If, +however, the substance was acquired as a result of enthusiasm of a more +intimate nature, you may delicately retrieve it with a flick of your +pink tongue. +%% +Dear Sir, + I am firmly opposed to the spread of microchips either to the home or +to the office, We have more than enough of them foisted upon us in public +places. They are a disgusting Americanism, and can only result in the farmers +being forced to grow smaller potatoes, which in turn will cause massive un- +employment in the already severely depressed agricultural industry. + Yours faithfully, + Capt. Quinton D'Arcy, J.P. + Sevenoaks + -- Letters To The Editor, The Times of London +%% +Death has been proven to be 99% fatal in laboratory rats. +%% +Death is God's way of telling you not to be such a wise guy. +%% +Death is Nature's way of recycling human beings. +%% +Death is a spirit leaving a body, sort +of like a shell leaving the nut behind. + -- Erma Bombeck +%% +Death is life's way of telling you you've been fired. + -- R. Geis +%% +Death is nature's way of telling you to slow down. +%% +Death rays don't kill people, people kill people!! +%% + Deck us all with Boston Charlie, + Walla Walla, Wash., an' Kalamazoo! + Nora's freezin' on the trolley, + Swaller dollar cauliflower, alleygaroo! + + Don't we know archaic barrel, + Lullaby Lilla Boy, Louisville Lou. + Trolley Molly don't love Harold, + Boola boola Pensacoola hullabaloo! + -- Pogo, "Deck Us All With Boston Charlie" +%% +Declared guilty... of displaying feelings of an almost human nature. + -- Pink Floyd, "The Wall" +%% +Decorate your home. It gives the illusion +that your life is more interesting than it really is. + -- C. Schultz +%% +"Deep" is a word like "theory" or "semantic" -- it implies all sorts of +marvelous things. It's one thing to be able to say "I've got a theory", +quite another to say "I've got a semantic theory", but, ah, those who can +claim "I've got a deep semantic theory", they are truly blessed. + -- Randy Davis +%% +Deflector shields just came on, Captain. +%% +Delay is preferable to error. + -- Thomas Jefferson +%% +Deliver yesterday, code today, think tomorrow. +%% +Delusions are often functional. A mother's opinions about +her children's beauty, intelligence, goodness, et cetera ad +nauseam, keep her from drowning them at birth. +%% +Democracy is a form of government in which it is permitted to wonder +aloud what the country could do under first-class management. + -- Senator Soaper +%% +Democracy is a form of government that substitutes election by the +incompetent many for appointment by the corrupt few. + -- G.B. Shaw +%% +Democracy is also a form of worship. +It is the worship of Jackals by Jackasses. + -- H.L. Mencken +%% +Democracy is the recurrent suspicion that more than half +of the people are right more than half of the time. + -- E.B. White +%% +Democracy is the worst form of government except all those other +forms that have been tried from time to time. + -- Winston Churchill +%% +Demonstrating once again the importance of the lowly comma, this +telegram was sent from a wife to her husband: + "NOT GETTING ANY, BETTER COME HOME AT ONCE." +%% +Dental health is next to mental health. +%% +Dentist: + A Prestidigitator who, putting metal in one's mouth, + pulls coins out of one's pockets. + -- Ambrose Bierce +%% +Depart in pieces, i.e., split. +%% +Depart not from the path which fate has assigned you. +%% +Department chairmen never die, they just lose their faculties. +%% +Depend on the rabbit's foot if you will, +but remember, it didn't help the rabbit. + -- R.E. Shay +%% +Deprive a mirror of its silver and even the Czar won't see his face. +%% +Der Horizont vieler Menschen ist ein Kreis mit Radius Null - +und das nennen sie ihren Standpunkt. +%% +Desist from enumerating your fowl +prior to their emergence from the shell. +%% +Despite all appearances, your boss +is a thinking, feeling, human being. +%% +Dibble's First Law of Sociology: + Some do, some don't. +%% +Did Detroit invent the back seat to destroy the morals of America? + -- Ed Sanders +%% +Did it ever occur to you that fat chance +and slim chance mean the same thing? + +Or that we drive on parkways and park on driveways? +%% +Did you hear about the model who sat +on a broken bottle and cut a nice figure? +%% +Did you know about the -o option of the fortune program? It makes a +selection from a set of offensive and/or obscene fortunes. Why not +try it, and see how offended you are? The -a ("all") option will +select a fortune at random from either the offensive or inoffensive +set, and it is suggested that "fortune -a" is the command that you +should have in your .profile or .cshrc. file. +%% +Did you know that clones never use mirrors? +%% +Did you know that for the price of a 280-Z you can buy two Z-80's? + -- P.J. Plauger +%% +Did you know the University of Iowa +closed down after someone stole the book? +%% +Did you know.... + +That no-one ever reads these things? +%% +Didja' ever have to make up your mind, +Pick up on one and leave the other behind, +It's not often easy, and it's not often kind, +Didja' ever have to make up your mind? + -- Lovin' Spoonful +%% +Die? I should say not, dear fellow. No Barrymore +would allow such a conventional thing to happen to him. + -- John Barrymore's dying words +%% +Dieters live life in the fasting lane. +%% +Different all twisty a of in maze are you, passages little. +%% +Dig it, first they killed those pigs, then they ate dinner +in the same room with them, then they even shoved a fork in +a victim's stomach. Wild! + -- Bernadine Dohrn, on the Manson killings +%% +Digital circuits are made from analog parts. + -- Don Vonada +%% +Dime is money. +%% +Dinner suggestion #302 (Hacker's De-lite): + 1 tin imported Brisling sardines in tomato sauce + 1 pouch Chocolate Malt Carnation Instant Breakfast + 1 carton milk +%% +Diogenes, having abandoned his search for +truth, is now searching for a good fantasy. +%% +Diplomacy is the art of letting someone else have your way. +%% +Diplomacy is the art of letting the other party have things your way. + -- Daniele Vare +%% +Diplomacy is the art of saying "nice doggie" until you can find a rock. + -- Wynn Catlin +%% +Disc space -- the final frontier! +%% +Disclose classified information only when a NEED TO KNOW exists. +%% +Disco is to music what Etch-A-Sketch is to art. +%% +Disease can be cured; fate is incurable. + -- Chinese proverb +%% +Dishonor will not trouble me, once I am dead. + -- Euripides +%% +Disillusioned words like bullets bark, +As human gods aim for their mark, +Make everything from toy guns that spark +To flesh-colored christs that glow in the dark. +It's easy to see without looking too far +That not much is really sacred. +%% +Disk crisis, please clean up! +%% +Disks travel in packs. +%% +Distance doesn't make you any smaller, +but it does make you part of a larger picture. +%% +Ditat Deus. (God enriches.) +%% +Do YOU have redeeming social value? +%% +Do clones have navels? +%% +Do infants have as much fun in infancy as adults do in adultery? +%% +Do married women make the best wives? +%% +Do molecular biologists wear designer genes? +%% +Do more than anyone expects, and pretty soon everyone will expect more. +%% +Do not believe in miracles -- rely on them. +%% +Do not clog intellect's sluices with bits of knowledge of questionable uses. +%% +Do not count your chickens before they are hatched. + -- Aesop +%% +Do not despair of life. You have no doubt force enough to overcome +your obstacles. Think of the fox prowling through wood and field in +a winter night for something to satisfy his hunger. Notwithstanding +cold and hounds and traps, his race survives. I do not believe any +of them ever committed suicide. + -- Henry David Thoreau +%% +Do not do unto others as you would they should do unto you. +Their tastes may not be the same. + -- George Bernard Shaw +%% +Do not drink coffee in early A.M. It will keep you awake until noon. +%% +Do not handicap your children by making their lives easy. + -- Robert Heinlein +%% +Do not meddle in the affairs of wizards, +for they become soggy and hard to light. + +Do not throw cigarette butts in the urinal, +for they are subtle and quick to anger. +%% +Do not overtax your powers. +%% +Do not permit a woman to ask forgiveness, for that is only the first +step. The second is justification of herself by accusation of you. + -- DeGourmont +%% +Do not read this fortune under penalty of law. +Violators will be prosecuted. +(Penal Code sec. 2.3.2 (II.a.)) +%% +Do not seek death; death will find you. +But seek the road which makes death a fulfillment. + -- Dag Hammarskjold +%% +Do not simplify the design of a program if a way +can be found to make it complex and wonderful. +%% +Do not sleep in a eucalyptus tree tonight. +%% +Do not stoop to tie your laces in your neighbor's melon patch. +%% +Do not take life too seriously; you will never get out of it alive. +%% +Do not think by infection, catching an opinion like a cold. +%% +Do not try to solve all life's problems at once -- +learn to dread each day as it comes. + -- Donald Kaul +%% +Do not underestimate the power of the Farce. +%% +Do not underestimate the power of the Force. +%% +Do not use the blue keys on this terminal. +%% +Do not worry about which side your +bread is buttered on: you eat BOTH sides. +%% +Do nothing unless you must, and when you must act -- hesitate. +%% +Do, or do not; there is no try. +%% +Do something unusual today. Pay a bill. +%% +Do students of Zen Buddhism do Om-work? +%% +Do unto others before they undo you. +%% +Do what comes naturally. Seethe and fume and throw a tantrum. +%% +Do what you can to prolong your life, +in the hope that someday you'll learn what it's for. +%% +Do you feel personally responsible for the world food shortage? +Every time you go to the beach, does the tide come in? +Have you ever eaten an entire moose? +Can you see your neck? +Do joggers take laps around you for exercise? +If so, welcome to National Fat Week. +This week we'll eat without guilt, and kick off our membership campaign, + ...by force-feeding a box of cornstarch to a skinny person. + -- Garfield +%% +Do you guys know what you're doing, or are you just hacking? +%% +Do you know, I think that Dr. Swift was silly to laugh about Laputa. +I believe it is a mistake to make a mock of people, just because they +think. There are ninety thousand people in this world who do not +think, for every one who does, and these people hate the thinkers +like poison. Even if some thinkers are fanciful, it is wrong to make +fun of them for it. Better to think about cucumbers even, than not +to think at all. + -- T.H. White +%% +Do you know Montana? +%% +Do you suffer painful elimination? + -- Don Knuth, "Structured Programming with Gotos" + +Do you suffer painful recrimination? + -- Nancy Boxer, "Structured Programming with Come-froms" + +Do you suffer painful illumination? + -- Isaac Newton, "Optics" + +Do you suffer painful hallucination? + -- Don Juan, cited by Carlos Casteneda +%% +Do you think your mother and I should have lived +comfortably so long together if ever we had been married? +%% +Do you want to know what's ahead for you, in your happiness at home, +your business success? Here's a telling test: Look in the mirror. Is +your skin smooth and lovely, your hair gleaming, your make-up glamorous? +Are you slender enough for your height? Do you stand erect, confident? +Yes? Then you are on your way to success as a woman. + -- Ladies Home Journal, 1947 advertisement +%% +Do your part to help preserve life on +Earth -- by trying to preserve your own. +%% +Documentation is like sex: when it is good, it is very, +very good; and when it is bad, it is better than nothing. + -- Dick Brandon +%% +Documentation is the castor oil of programming. +Managers know it must be good because the programmers hate it so much. +%% + Does anyone know how to get chocolate syrup and honey out of a +white electric blanket? I'm afraid to wash it in the machine. + +Thanks, Kathy. (front desk, x17) + +p.s. Also, anyone ever used Noxema on friction burns? + Or is Vaseline better? +%% +Does it rape elephants? + -- Brent Byer +%% +Does the name Pavlov ring a bell? +%% +Doin' it in the dark, down in Rock Creek Park. +%% +Doing gets it done. +%% +Domestic happiness and faithful friends. +%% +Don +Ameche: I didn't know you had a cousin Penelope, Bill! + Was she pretty? +W.C.: Well, her face was so wrinkled it looked like seven miles of + bad road. She had so many gold teeth, Don, she use to have + to sleep with her head in a safe. She died in Bolivia. +Don: Oh Bill, it must be hard to lose a relative. +W.C.: It's almost impossible. + + -- W.C. Fields, "The Further Adventures of Larson E. + Whipsnade and other Tarradiddles" +%% +Don't I know you? +%% +Don't Worry, Be Happy. + -- Meher Baba +%% +Don't abandon hope. +Your Captain Midnight decoder ring arrives tomorrow. +%% +Don't be concerned, it will not harm you, +It's only me pursuing something I'm not sure of, +Across my dreams, with neptive wonder, +I chase the bright elusive butterfly of love. +%% +Don't be humble, you're not that great. + -- Golda Meir +%% +Don't be irreplaceable. If you can't +be replaced, you cannot be promoted. +%% +Don't be overly suspicious where it's not warranted. +%% +Don't believe everything you hear or anything you say. +%% +Don't compare floating point numbers solely for equality. +%% +Don't confuse things that need action +with those that take care of themselves. +%% +Don't cook tonight -- starve a rat today! +%% +Don't crush that dwarf, hand me the pliers! + -- Firesign Theatre +%% +Don't despair; your ideal lover is waiting for you around the corner. +%% +Don't do unto others as you would they should do unto you. +Their tastes may not be the same. + -- G.B. Shaw +%% +Don't drink when you drive -- you might hit a bump and spill it. +%% +Don't eat yellow snow. +%% +Don't ever slam a door; you might want to go back. +%% +Don't everyone thank me at once! + -- Han Solo +%% +Don't expect people to keep in step-- +it's hard enough just staying in line. +%% +Don't feed the bats tonight. +%% +Don't force it, get a larger hammer. + -- Anthony +%% +Don't get mad, get interest. +%% +Don't get stuck in a closet -- wear yourself out. +%% +Don't get to bragging. +%% +Don't go around saying the world owes you a living. +The world owes you nothing. It was here first. + -- Mark Twain +%% +Don't go surfing in South Dakota for a while. +%% +Don't go to bed with no price on your head. + -- Baretta +%% +Don't guess - check your security regulations. +%% +Don't hate yourself in the morning -- sleep till noon. +%% +Don't have good ideas if you aren't willing to be responsible for them. +%% +Don't hit the keys so hard, it hurts. +%% +Don't interfere with the stranger's style. +%% +Don't kid yourself. Little is relevant, and nothing lasts forever. +%% +Don't kiss an elephant on the lips today. +%% +Don't knock President Fillmore. He kept us out of Vietnam. +%% +Don't let nobody tell you what you cannot do; +don't let nobody tell you what's impossible for you; +don't let nobody tell you what you got to do, +or you'll never know ... what's on the other side of the rainbow... +remember, if you don't follow your dreams, +you'll never know what's on the other side of the rainbow... + -- melba moore, "the other side of the rainbow" +%% +Don't let your status become too quo! +%% +Don't look back, the lemmings are gaining on you. +%% +Don't look now, but the man in the moon is laughing at you. +%% +Don't look now, but there is a multi-legged creature on your shoulder. +%% +Don't make a big deal out of everything; just deal with everything. +%% +Don't marry for money; you can borrow it cheaper. + -- Scottish Proverb +%% +Don't mind him; politicians always sound like that. +%% +Don't plan any hasty moves. +You'll be evicted soon anyway. +%% +Don't put off for tomorrow what you can do today because +if you do it today, you can do it again tomorrow. +%% +Don't put too fine a point to your wit for fear it should get blunted. + -- Miguel de Cervantes +%% +Don't quit now, we might just as well +lock the door and throw away the key. +%% +Don't read any sky-writing for the next two weeks. +%% +Don't read everything you believe. +%% +Don't relax! It's only your tension that's holding you together. +%% +Don't shoot until you're sure you both aren't on the same side. +%% +Don't speak about Time, until you have spoken to him. +%% +Don't sweat it -- it's only ones and zeros. + -- P. Skelly +%% +Don't take life seriously, you'll never get out alive. +%% +Don't tell any big lies today. Small ones can be just as effective. +%% +Don't tell me that worry doesn't do any good. +I know better. The things I worry about don't happen. + -- Watchman Examiner +%% +Don't tell me what you dream'd last night for I've been reading Freud. +%% +Don't try to have the last word -- you might get it. + -- Lazarus Long +%% +Don't vote - it only encourages them! +%% +Don't wake me up too soon... +Gonna take a ride across the moon... +You and me. +%% +Don't worry. Life's too long. + -- Vincent Sardi, Jr. +%% +Don't worry -- the brontosaurus is slow, stupid, and placid. +%% +Don't worry about people stealing your ideas. If your ideas +are any good, you'll have to ram them down people's throats. + -- Howard Aiken +%% +Don't worry about the world coming to an end today. +It's already tomorrow in Australia. + -- Charles Schultz +%% +Don't worry if you're a kleptomaniac, +you can always take something for it. +%% +Don't worry over what other people are thinking about you. +They're too busy worrying over what you are thinking about them. +%% +Don't worry so loud, your roommate can't think. +%% +Don't you feel more like you do now than you did when you came in? +%% +Don't you wish that all the people who sincerely +want to help you could agree with each other? +%% +Don't you wish you had more energy... or less ambition? +%% +Dope will get you through times of no money +better than money will get you through times of no dope! + -- Freewheelin' Franklin, "The Fabulous Furry Freak Brothers" +%% +Dorothy: But how can you talk without a brain? +Scarecrow: Well, I don't know... but some people + without brains do an awful lot of talking. + -- The Wizard of Oz +%% +Double! +%% +Double Bucky, you're the one, +You make my keyboard so much fun, +Double Bucky, an additional bit or two, (Vo-vo-de-o) +Control and meta, side by side, +Augmented ASCII, 9 bits wide! +Double Bucky, a half a thousand glyphs, plus a few! + +Oh, I sure wish that I, +Had a couple of bits more! +Perhaps a set of pedals to make the number of bits four. + +Double Double Bucky! Double Bucky left and right +OR'd together, outta sight! +Double Bucky, I'd like a whole word of, +Double Bucky, I'm happy I heard of, +Double Bucky, I'd like a whole word of you! + -- to Nicholas Wirth, who suggested that an extra bit + be added to terminal codes on 36-bit machines for use + by screen editors. [to the tune of "Rubber Ducky"] +%% +Down with the categorical imperative! +%% +Dow's Law: + In a hierarchical organization, + the higher the level, the greater the confusion. +%% +Dr. Fritzkee's Lucky Astrology Diet + +The problem with the diets of today is that most women who do achieve +that magic weight, seventy-six pounds, are still fat. Dr. Fritzkee's +Lucky Astrology Diet is a sure-fire method of reducing with the added +luxury that you never feel hungry. + +Here's how the diet works: + + FOODS ALLOWED +First Month: One egg +Second Month: A raisin +Third Month: Pumpkin pie with whipped cream and chocolate sauce. + +If after the third month you haven't gotten to your dream weight, try +lopping off parts of your body until those scales tip just right for you. +%% +Dr. Jekyll had something to Hyde. +%% + Dr. Oliver Wendell Holmes of Harvard Medical School inhaled ether +at a time when it was popularly supposed to produce such mystical or +"mind-expanding" experiences, much as LSD is supposed to produce such +experiences today. Here is his account of what happened: + "I once inhaled a pretty full dose of ether, with the determination +to put on record, at the earliest moment of regaining consciousness, the +thought I should find uppermost in my mind. The mighty music of the triumphal +march into nothingness reverberated through my brain, and filled me with a +sense of infinite possibilities, which made me an archangel for a moment. +The veil of eternity was lifted. The one great truth which underlies all +human experience and is the key to all the mysteries that philosophy has +sought in vain to solve, flashed upon me in a sudden revelation. Henceforth +all was clear: a few words had lifted my intelligence to the level of the +knowledge of the cherubim. As my natural condition returned, I remembered +my resolution; and, staggering to my desk, I wrote, in ill-shaped, straggling +characters, the all-embracing truth still glimmering in my consciousness. +The words were these (children may smile; the wise will ponder): +`A strong smell of turpentine prevails throughout.'" + -- The Consumers Union Report: Licit & Illicit Drugs +%% +Draft beer, not people. +%% +Drakenberg's Discovery: + If you can't seem to find your glasses, + it's probably because you don't have them on. +%% +Drawing on my fine command of language, I said nothing. +%% +Dreams are free, but there's a small charge for alterations. +%% +Dreams are free, but you get soaked on the connect time. +%% +Drew's Law of Highway Biology: + The first bug to hit a clean windshield + lands directly in front of your eyes. +%% +Drilling for oil is boring. +%% +Drinking is not a spectator sport. + -- Jim Brosnan +%% +Drive defensively, buy a tank. +%% +Drop that pickle! +%% +Drop the vase and it will become a Ming of the past. + -- The Adventurer +%% +Drugs may be the road to nowhere, but at least they're the scenic route! +%% +Ducharme's Precept: + Opportunity always knocks at the least opportune moment. + +Ducharme's Axiom: + If you view your problem closely enough you will recognize + yourself as part of the problem. +%% +Duckies are fun! +%% +Ducks? What ducks?? +%% +Duct tape is like the force. It has a light side, +and a dark side, and it holds the universe together. + -- Carl Zwanzig +%% +Due to a shortage of devoted followers, the +production of great leaders has been discontinued. +%% +Due to circumstances beyond your control, +you are master of your fate and captain of your soul. +%% +Dungeons and Dragons is just a lot of Saxon Violence. +%% + During a grouse hunt in North Carolina two intrepid sportsmen were +blasting away at a clump of trees near a stone wall. Suddenly a red-face +country squire popped his head over the wall and shouted, "Hey, you almost +hit my wife." + "Did I?" cried one hunter, aghast. "Terribly sorry. Have a shot +at mine, over there." +%% +During the next two hours, the VAX will be going up and down +several times, often with lin~po_~{po ~poz~ppo\~{ o n~po_~ +{o[po ~poodsou>#w4k**n~po_~{ol;lkld;f;g;dd;po\~{o +%% +During the voyage of life, remember to keep an eye out for a +fair wind; batten down during a storm; hail all passing ships; +and fly your colors proudly. +%% +Duty, n: + What one expects from others. + -- Oscar Wilde +%% +Dying is a very dull, dreary affair. And my advice +to you is to have nothing whatever to do with it. + -- W. Somerset Maughm +%% +E = MC ** 2 +- 3db +%% +E Pluribus UNIX. +%% +Egotism, n: + Doing the New York Times crossword puzzle with a pen. + +Egotist, n: + A person of low taste, more interested in himself than me. +%% +Electrocution, n: + Burning at the stake with all the modern improvements. +%% +Elephant, n: + A mouse built to government specifications. +%% +Elliptical, n: + The feel of a kiss. +%% +Engram, n: + 1. The physical manifestation of human memory -- "the engram." +2. A particular memory in physical form. [Usage note: this term is no longer +in common use. Prior to Wilson and Magruder's historic discovery, the nature +of the engram was a topic of intense speculation among neuroscientists, +psychologists, and even computer scientists. In 1994 Professors M. R. Wilson +and W. V. Magruder, both of Mount St. Coax University in Palo Alto, proved +conclusively that the mammalian brain is hardwired to interpret a set of +thirty seven genetically transmitted cooperating TECO macros. Human memory +was shown to reside in 1 million Q-registers as Huffman coded uppercase-only +ASCII strings. Interest in the engram has declined substantially since that +time.] + -- New Century Unabridged English Dictionary, + 3rd edition, 2007 A.D. +%% +Entreprenuer, n: + A high-rolling risk taker who would rather + be a spectacular failure than a dismal success. +%% +Envy, n: + Wishing you'd been born with an unfair advantage, + instead of having to try and acquire one. +%% +Erogenous zone, n: + The skin you touch to love. +%% +E.T. GO HOME!!! (And take your Smurfs with you.) +%% +Etymology, n: + Some early etymological scholars came up with derivations that + were hard for the public to believe. The term 'etymology' was + formed from the Latin 'etus' ("eaten"), the root 'mal' ("bad"), + and 'logy' ("study of"). It meant "the study of things that are + hard to swallow." + -- Mike Kellen +%% +Expense accounts, n: + Corporate food stamps. +%% +Each man is his own prisoner, in solitary confinement for life. +%% +Each of us bears his own Hell. + -- Publius Vergilius Maro (Virgil) +%% +Early to bed and early to rise and you'll +be groggy when everyone else is wide awake. +%% +Early to rise and early to bed makes +a man healthy and wealthy and dead. + -- James Thurber +%% +Earn cash in your spare time -- blackmail your friends. +%% +Earth Destroyed by Solar Flare -- film clips at eleven. +%% +/Earth is 98% full ... please delete anyone you can. +%% +Earth is a great funhouse without the fun. + -- Jeff Berner +%% +Easiest Color to Solve on a Rubik's Cube: Black. + +Simply remove all the little colored stickers on the cube, and each of +side of the cube will now be the original color of the plastic underneath +-- black. According to the instructions, this means the puzzle is solved. +%% +Easy come and easy go, + some call me easy money, +Sometimes life is full of laughs, + and sometimes it ain't funny +You may think that I'm a fool + and sometimes that is true, +But I'm goin' to heaven in a flash of fire, + with or without you. + -- Hoyt Axton +%% +Eat drink and be merry! Tommorrow you may be in Utah. +%% +Eat prune yogurt for that "get up and go" feeling. +%% +Economics is extremely useful as a form of employment for economists. + -- John Kenneth Galbraith +%% +Economists are still trying to figure out why the +girls with the least principle draw the most interest. +%% +Editing is a rewording activity. +%% +Higher education helps your earning capacity. Ask any college professor. +%% +Education is an admirable thing, but it is well to +remember that nothing that is worth knowing can be taught. + -- Oscar Wilde +%% +Education is what survives when what has been learnt has been forgotten. + -- B.F. Skinner +%% +Eeny, Meeny, Jelly Beanie, +The spirits are about to speak... +%% +Eggheads unite! You have nothing to lose but your yolks. + -- Adlai Stevenson +%% +Ego sum ens omnipotens +%% +Egotism is the anesthetic given by a kindly nature +to relieve the pain of being a damned fool. + -- Bellamy Brooks +%% +Ehrman's Commentary: + 1. Things will get worse before they get better. + 2. Who said things would get better? +%% +Eighteen goddess-like daughters are not equal to one son with a hump. + -- Chinese Proverb +%% +Eighty percent of air pollution comes from plants and trees. + -- Ronald Reagan, famous movie star +%% +Eisenhower was very nice, +Nixon was his only vice. + -- C. Degen +%% +Either I'm dead or my watch has stopped. + -- Groucho Marx' last words +%% +Eleanor Rigby +Sits at the keyboard and waits for a line on the screen +Lives in a dream +Waits for a signal, finding some code that will + make the machine do some more. +What is it for? +All the lonely users, where do they all come from? +All the lonely users, why does it take so long? +%% +Electrical Engineers do it with less resistance. +%% +Elegance and truth are inversely related. + -- Becker's Razor +%% +Elevators smell different to midgets. +%% +Eli and Bessie went to sleep. +In the middle of the night, Bessie nudged Eli. + "Please be so kindly and close the window. It's cold outside!" +Half asleep, Eli murmured, + "Nu ... so if I'll close the window, will it be warm outside?" +%% +Elliptic paraboloids for sale. +%% +Eloquence is logic on fire. +%% +Emersons' Law of Contrariness: + Our chief want in life is somebody who shall make us do + what we can. Having found them, we shall then hate them + for it. +%% +Encyclopedia for sale by father. +Son knows everything. +%% +Endless Loop: n. see Loop, Endless. +Loop, Endless: n. see Endless Loop. + -- Random Shack Data Processing Dictionary +%% +Endless the world's turn, endless the sun's spinning +Endless the quest; +I turn again, back to my own beginning, +And here, find rest. +%% +Enjoy your life; be pleasant and gay, like the birds in May. +%% +Enjoy yourself while you're still old. +%% +Entropy isn't what it used to be. +%% +Entropy requires no maintenance. + -- Markoff Chaney +%% +Envy is a pain of mind that successful men cause their neighbors. + -- Onasander +%% +Enzymes are things invented by biologists +that explain things which otherwise require harder thinking. + -- Jerome Lettvin +%% +Equal bytes for women. +%% +Es brilig war. Die schlichte Toven + Wirrten und wimmelten in Waben; +Und aller-mumsige Burggoven + Dir mohmen Rath ausgraben. +%% +Eschew obfuscation. +%% +Established technology tends to persist in the face of new technology. + -- G. Blaauw, one of the designers of System 360 +%% +Eternal nothingness is fine if you happen to be dressed for it. + -- Woody Allen +%% +Etiquette is for those with no breeding; +fashion for those with no taste. +%% +Eureka! + -- Archimedes +%% +Even God cannot change the past. + -- Joseph Stalin +%% +Even God lends a hand to honest boldness. + -- Menander +%% +Even a cabbage may look at a king. +%% +Even a hawk is an eagle among crows. +%% +Even bytes get lonely for a little bit. +%% +Even if you do learn to speak correct +English, whom are you going to speak it to? + -- Clarence Darrow +%% +Even if you persuade me, you won't persuade me. + -- Aristophanes +%% +Even in the moment of our earliest kiss, +When sighed the straitened bud into the flower, +Sat the dry seed of most unwelcome this; +And that I knew, though not the day and hour. +Too season-wise am I, being country-bred, +To tilt at autumn or defy the frost: +Snuffing the chill even as my fathers did, +I say with them, "What's out tonight is lost." +I only hoped, with the mild hope of all +Who watch the leaf take shape upon the tree, +A fairer summer and a later fall +Than in these parts a man is apt to see, +And sunny clusters ripened for the wine: +I tell you this across the blackened vine. + -- Edna St. Vincent Millay, "Even in the Moment o + Our Earliest Kiss", 1931 +%% +Even moderation ought not to be practiced to excess. +%% +Even the best of friends cannot attend each other's funeral. + -- Kehlog Albran +%% +Even though they raised the rate for first class mail in the United +States we really shouldn't complain -- it's still only 2 cents a day. +%% +Evening hours "all clear" for romance! +(Tell mate you have to work late.) +%% +Events are not affected, they develop. + -- Sri Aurobindo +%% +Ever Onward! Ever Onward! +That's the sprit that has brought us fame. +We're big but bigger we will be, +We can't fail for all can see, that to serve humanity +Has been our aim. +Our products now are known in every zone. +Our reputation sparkles like a gem. +We've fought our way thru +And new fields we're sure to conquer, too +For the Ever Onward IBM! + -- Ever Onward, from the 1940 IBM Songbook +%% +Ever Onward! Ever Onward! +We're bound for the top to never fall, +Right here and now we thankfully +Pledge sincerest loyalty +To the corporation that's the best of all +Our leaders we revere and while we're here, +Let's show the world just what we think of them! +So let us sing men -- Sing men +Once or twice, then sing again +For the Ever Onward IBM! + -- Ever Onward, from the 1940 IBM Songbook +%% +Ever feel like you're the head pin on life's +bowling alley, and everyone's rolling strikes? +%% +Ever get the feeling that the world's +on tape and one of the reels is missing? + -- Rich Little +%% +Ever notice that even the busiest people are +never too busy to tell you just how busy they are? +%% +Ever wonder why fire engines are red? + +Because newspapers are read too. +Two and Two is four. +Four and four is eight. +Eight and four is twelve. +There are twelve inches in a ruler. +Queen Mary was a ruler. +Queen Mary was a ship. +Ships sail the sea. +There are fishes in the sea. +Fishes have fins. +The Fins fought the Russians. +Russians are red. +Fire engines are always rush'n. +Therefore fire engines are red. +%% +Ever wondered about the origins of the term "bugs" as applied to computer +technology? U.S. Navy Capt. Grace Murray Hopper has firsthand explanation. +The 74-year-old captain, who is still on active duty, was a pioneer in +computer technology during World War II. At the C.W. Post Center of Long +Island University, Hopper told a group of Long Island public school adminis- +trators that the first computer "bug" was a real bug--a moth. At Harvard +one August night in 1945, Hopper and her associates were working on the +"granddaddy" of modern computers, the Mark I. "Things were going badly; +there was something wrong in one of the circuits of the long glass-enclosed +computer," she said. "Finally, someone located the trouble spot and, using +ordinary tweezers, removed the problem, a two-inch moth. From then on, when +anything went wrong with a computer, we said it had bugs in it." Hopper +said that when the veracity of her story was questioned recently, "I referred +them to my 1945 log book, now in the collection of the Naval Surface Weapons +Center, and they found the remains of that moth taped to the page in +question." + [actually, the term "bug" had even earlier usage in + regard to problems with radio hardware. Ed.] +%% +Every 4 seconds a woman has a baby. +Our problem is to find this woman and stop her. +%% +Every cloud engenders not a storm. + -- William Shakespeare, "Henry VI" +%% +Every cloud has a silver lining; +you should have sold it, and bought titanium. +%% +Every creature has within him the wild, uncontrollable urge to punt. +%% +Every dog has its day, but the nights belong to the pussycats. +%% +Every gun that is made, every warship launched, every rocket fired +signifies in the final sense, a theft from those who hunger and are not +fed, those who are cold and are not clothed. This world in arms is not +spending money alone. It is spending the sweat of its laborers, the +genius of its scientists, the hopes of its children. This is not +a way of life at all in any true sense. Under the clouds of war, it +is humanity hanging on a cross of iron. + -- Dwight Eisenhower, 1953 +%% +Every harlot was a virgin once. + -- William Blake +%% +Every little picofarad has a nanohenry all its own. + -- Don Vonada +%% +Every man is apt to form his notions of things difficult to be apprehended, +or less familiar, from their analogy to things which are more familiar. +Thus, if a man bred to the seafaring life, and accustomed to think and talk +only of matters relating to navigation, enters into discourse upon any other +subject; it is well known, that the language and the notions proper to his +own profession are infused into every subject, and all things are measured +by the rules of navigation: and if he should take it into his head to +philosophize concerning the faculties of the mind, it cannot be doubted, +but he would draw his notions from the fabric of the ship, and would find +in the mind, sails, masts, rudder, and compass. + -- Thomas Reid, "An Inquiry into the Human Mind", 1764 +%% +Every man is as God made him, ay, and often worse. + -- Miguel de Cervantes +%% +Every man takes the limits of his own field +of vision for the limits of the world. + -- Schopenhauer +%% +Every man who is high up likes to think that he has done +it all himself, and the wife smiles and lets it go at that. + -- Barrie +%% +Every morning is a Smirnoff morning. +%% +Every nation has the government it deserves. + -- Joseph De Maistre +%% +Every night my prayers I say, + And get my dinner every day; +And every day that I've been good, + I get an orange after food. +The child that is not clean and neat, + With lots of toys and things to eat, +He is a naughty child, I'm sure-- + Or else his dear papa is poor. + -- Robert Louis Stevenson +%% +Every paper published in a respectable journal should have a preface by +the author stating why he is publishing the article, and what value he +sees in it. I have no hope that this practice will ever be adopted. + -- Morris Kline +%% +Every path has its puddle. +%% +Every person, all the events in your life are there because you have +drawn them there. What you choose to do with them is up to you. + -- Messiah's Handbook : Reminders for the Advanced Soul +%% +Every program has at least one bug and can be shortened by at least one +instruction -- from which, by induction, one can deduce that every program +can be reduced to one instruction which doesn't work. +%% +Every program has (at least) two purposes: + the one for which it was written and another for which it wasn't. +%% +Every silver lining has a cloud around it. +%% +Every successful person has had failures +but repeated failure is no guarantee of eventual success. +%% +Every time I look at you I am more convinced of Darwin's theory. +%% +Every time I lose weight, it finds me again! +%% +Every time I think I know where it's at, they move it. +%% +Every time you manage to close the door on +Reality, it comes in through the window. +%% +Every why hath a wherefore. + -- William Shakespeare, "A Comedy of Errors" +%% +Every word is like an unnecessary stain on silence and nothingness. + -- Beckett +%% +Everybody but Sam had signed up for a new company pension plan that +called for a small employee contribution. The company was paying all +the rest. Unfortunately, 100% employee participation was needed; +otherwise the plan was off. Sam's boss and his fellow workers pleaded +and cajoled, but to no avail. Sam said the plan would never pay off. +Finally the company president called Sam into his office. + "Sam," he said, "here's a copy of the new pension plan and here's +a pen. I want you to sign the papers. I'm sorry, but if you don't sign, +you're fired. As of right now." + Sam signed the papers immediately. + "Now," said the president, "would you mind telling me why you +couldn't have signed earlier?" + "Well, sir," replied Sam, "nobody explained it to me quite so +clearly before." +%% +Everybody has something to conceal. + -- Humphrey Bogart +%% +Everybody is somebody elses weirdo. + -- Dykstra +%% +Everybody needs a little love sometime; +stop hacking and fall in love! +%% +Everybody wants to go to heaven, but nobody wants to die. +%% +Everyone can be taught to sculpt: Michelangelo would have had +to be taught how not to. So it is with the great programmers. +%% +Everyone complains of his memory, no one of his judgement. +%% +Everyone hates me because I'm paranoid. +%% +Everyone is entitled to my opinion. +%% +Everyone is in the best seat. + -- John Cage +%% +Everyone is more or less mad on one point. + -- Rudyard Kipling +%% +Everyone knows that dragons don't exist. But while this simplistic +formulation may satisfy the layman, it does not suffice for the +scientific mind. The School of Higher Neantical Nillity is in fact +wholly unconcerned with what DOES exist. Indeed, the banality of +existence has been so amply demonstrated, there is no need for us +to discuss it any further here. The brilliant Cerebron, attacking +the problem analytically, discovered three distinct kinds of dragon: +the mythical, the chimerical, and the purely hypothetical. They were +all, one might say, nonexistent, but each nonexisted in an entirely +different way... +%% +Everyone's in a high place when you're on your knees. +%% +Everything bows to success, even grammar. +%% +Everything in this book may be wrong. + -- Messiah's Handbook : Reminders for the Advanced Soul +%% +Everything is controlled by a small evil group +to which, unfortunately, no one we know belongs. +%% +Everything might be different in the present +if only one thing had been different in the past. +%% +Everything should be built top-down, except the first time. +%% +Everything should be made as simple as possible, but not simpler. + -- Albert Einstein +%% +Everything takes longer, costs more, and is less useful. + -- Erwin Tomash +%% +Everything that you know is wrong, but you can be straightened out. +%% +Everything will be just tickety-boo today. +%% +Everything you know is wrong! +%% +Everything you've learned in school as "obvious" becomes less and less +obvious as you begin to study the universe. For example, there are no +solids in the universe. There's not even a suggestion of a solid. There +are no absolute continuums. There are no surfaces. There are no +straight lines. + -- R. Buckminster Fuller +%% +Everywhere you go you'll see them searching, +Everywhere you turn you'll feel the pain, +Everyone is looking for the answer, +Well look again. + -- Moody Blues, "Lost in a Lost World" +%% +Evolution is a million line computer +program falling into place by accident. +%% +Examinations are formidable even to the best prepared, for +even the greatest fool may ask more the the wisest man can answer. + -- C.C. Colton +%% +Excellent day for drinking heavily. +Spike the office water cooler. +%% +Excellent day to have a rotten day. +%% +Excellent time to become a missing person. +%% +Exceptions prove the rule, and wreck the budget. + -- Miller +%% +Excess on occasion is exhilarating. It prevents +moderation from acquiring the deadening effect of a habit. + -- W. Somerset Maugham +%% +Excessive login messages is a sure sign of senility. +%% +Execute every act of thy life as though it were thy last. + -- Marcus Aurelius +%% +Executive ability is prominent in your make-up. +%% +Exercise caution in your daily affairs. +%% +Expansion means complexity; and complexity decay. +%% +Expect a letter from a friend who will ask a favor of you. +%% +Expect the worst, it's the least you can do. +%% +Expedience is the best teacher. +%% +Experience is not what happens to you; +it is what you do with what happens to you. + -- Aldous Huxley +%% +Experience is that marvelous thing that enables +you recognize a mistake when you make it again. + -- F.P. Jones +%% +Experience is the worst teacher. It always +gives the test first and the instruction afterward. +%% +Experience is what causes a person +to make new mistakes instead of old ones. +%% +Experience is what you get when you were expecting something else. +%% +Experience varies directly with equipment ruined. +%% +Experience, n: + Something you don't get until just after you need it. + -- Olivier +%% +Experiments must be reproducible; they should all fail in the same way. +%% +External Security: +%% +Extreme fear can neither fight nor fly. + -- William Shakespeare, "The Rape of Lucrece" +%% +F u cn rd ths u cnt spl wrth a dm! +%% +FACILITY REJECTED 100044200000; +%% +Fairy tale: + A horror story to prepare children for the newspapers. +%% +Faith, n: + That quality which enables us to + believe what we know to be untrue. +%% +Fakir, n: + A psychologist whose charismatic data have inspired almost + religious devotion in his followers, even though the sources + seem to have shinnied up a rope and vanished. +%% +Female rabbits: + The gift that just "keeps on giving." +%% +Fidelity, n: + A virtue peculiar to those who are about to be betrayed. +%% +File cabinet: + A four drawer, manually activated trash compactor. +%% +Fishbowl, n: + A glass-enclosed isolation cell where newly + promoted managers are kept for observation. +%% +FLASH! +Intelligence of mankind decreasing. +Details at ... uh, when the little hand is on the .... +%% +Foolproof Operation: + No provision for adjustment. +%% +FORCE YOURSELF TO RELAX! +%% +Forecast, n: + A prediction of the future, based on the past, for + which the forecaster demands payment in the present. +%% +Forgetfulness, n: + A gift of God bestowed upon debtors in compensation for + their destitution of conscience. +%% +FORTH IF HONK THEN +%% +FORTRAN is a good example of a language +which is easier to parse using ad hoc techniques. + -- D. Gries + [What's good about it? Ed.] +%% +FORTRAN is not a flower but a weed -- it is hardy, +occasionally blooms, and grows in every computer. + -- A.J. Perlis +%% +FORTRAN is the language of Powerful Computers. + -- Steven Feiner +%% +FORTRAN rots the brain. + -- John McQuillin +%% +FORTRAN, "the infantile disorder", by now nearly 20 years old, is +hopelessly inadequate for whatever computer application you have +in mind today: it is now too clumsy, too risky, and too expensive +to use. + -- E.W. Dijkstra +%% +[FORTRAN] will persist for some time -- +probably for at least the next decade. + -- T. Cheatham +%% +Friends, n: + People who borrow your books and set wet glasses on them. + + People who know you well, but like you anyway. +%% + FROM THE DESK OF + Dorothy Gale + + Auntie Em: + Hate you. + Hate Kansas. + Taking the dog. + Dorothy +%% +F.S. Fitzgerald to Hemingway: + "Ernest, the rich are different from us." +Hemingway: + "Yes. They have more money." +%% +Facts, apart from their relationships, are like labels on empty bottles. + -- Sven Italla +%% +Facts are the enemy of truth. + -- Don Quixote +%% +Facts do not cease to exist because they are ignored. + -- Aldous Huxley +%% +Failure is more frequently from want of energy than want of capital. +%% +Fain would I climb, yet fear I to fall. + -- Sir Walter Raleigh +%% +Faith goes out through the window when beauty comes in at the door. +%% +Faith is the quality that enables you to eat blackberry jam +on a picnic without looking to see whether the seeds move. +%% +Fall not in love; it will stick to your face. + -- Deteriorata +%% +Falling in love is a lot like dying. +You never get to do it enough to become good at it. +%% +Familiarity breeds attempt. +%% +Familiarity breeds contempt -- and children. + -- Mark Twain +%% +Families, when a child is born +Want it to be intelligent. +I, through intelligence, +Having wrecked my whole life, +Only hope the baby will prove +Ignorant and stupid. +Then he will crown a tranquil life +By becoming a Cabinet Minister + -- Su Tung-p'o +%% +Famous last words: +%% +Famous last words: + 1: Don't unplug it, it will just take a moment to fix. + 2: Let's take the shortcut, he can't see us from there. + 3: What happens if you touch these two wires tog... + 4: We won't need reservations. + 5: It's always sunny there this time of the year. + 6: Don't worry, it's not loaded. + 7: They'd never (be stupid enough to) make him a manager. + 8: Don't worry! Women love it! +%% +Famous last words: + 1: Everything that you'll need to know is in the manual. + 2: You and what army? + 3: Don't worry, I can handle it. + 4: If you were as smart as you think you are, you wouldn't + be a cop. + 5: I don't see how they make a profit + out of this stuff at a dollar and a quarter a fifth. + 6: We're just getting into semantics again. + 7: Everything's under control. + 8: He's an asshole! Don't try to "shush" me! +%% +"Fantasies are free." +"NO!! NO!! It's the thought police!!!!" +%% +Far duller than a serpent's tooth it is to spend a quiet youth. +%% +Far out in the uncharted backwaters of the unfashionable end of the Western +Spiral arm of the Galaxy lies a small unregarded yellow sun. Orbiting this +at a distance of roughly ninety-eight million miles is an utterly +insignificant little blue-green planet whose ape-descended life forms are +so amazingly primitive that they still think digital watches are a pretty +neat idea. + -- Douglas Adams, "The Hitchhicker's Guide to the Galaxy" +%% +Farmers in the Iowa State survey rated +machinery breakdowns more stressful than divorce. + -- Wall Street Journal +%% +Fashion is a form of ugliness so intolerable +that we have to alter it every six months. + -- Oscar Wilde +%% +Fashions have done more harm than revolutions. + -- Victor Hugo +%% +Fast ship? You mean you've never heard of the Millennium Falcon? + -- Han Solo +%% +Faster, faster, you fool, you fool! + -- Bill Cosby +%% +Father: Son, it's time we talked about sex. +Son: Sure, Dad, what do you want to know? +%% +Fats Loves Madelyn. +%% +Fear and loathing, my man, fear and loathing. + -- H.S. Thompson +%% +Fear is the greatest salesman. + -- Robert Klein +%% +Federal grants are offered for... research into the recreation +potential of interplanetary space travel for the culturally +disadvantaged. +%% +Feel disillusioned? +I've got some great new illusions, right here! +%% +Fellow programmer, greetings! You are reading a letter which will bring +you luck and good fortune. Just mail (or UUCP) ten copies of this letter +to ten of your friends. Before you make the copies, send a chip or +other bit of hardware, and 100 lines of 'C' code to the first person on the +list given at the bottom of this letter. Then delete their name and add +yours to the bottom of the list. + +Don't break the chain! Make the copy within 48 hours. Gerald R. of San +Diego failed to send out his ten copies and woke the next morning to find +his job description changed to "COBOL programmer." Fred A. of New York sent +out his ten copies and within a month had enough hardware and software to +build a Cray dedicated to playing Zork. Martha H. of Chicago laughed at +this letter and broke the chain. Shortly thereafter, a fire broke out in +her terminal and she now spends her days writing documentation for IBM PC's. + +Don't break the chain! Send out your ten copies today! +%% +Feminists just want the human race to be a tie. +%% +Fertility is hereditary. If your parents +didn't have any children, neither will you. +%% +Fess: Well, you must admit there is something innately humorous about + a man chasing an invention of his own halfway across the galaxy. +Rod: Oh yeah, it's a million yuks, sure. But after all, isn't that the + basic difference between robots and humans? +Fess: What, the ability to form imaginary constructs? +Rod: No, the ability to get hung up on them. + -- Christopher Stasheff, "The Warlock in Spite of Himself" +%% +Fifteen men on a dead man's chest, +Yo-ho-ho and a bottle of rum! +Drink and the devil had done for the rest, +Yo-ho-ho and a bottle of rum! + -- Stevenson, "Treasure Island" +%% +Fifth Law of Applied Terror: + If you are given an open-book exam, you will forget your book. +Corollary: + If you are given a take-home exam, you will forget where you live. +%% +Fill what's empty, empty what's full, scratch where it itches. + -- Alice Roosevelt Longworth +%% +Finagle's Creed: + Science is true. Don't be misled by facts. +%% +Finagle's Eighth Law: + If an experiment works, something has gone wrong. + +Finagle's Ninth Law: + No matter what results are expected, + someone is always willing to fake it. + +Finagle's Tenth Law: + No matter what the result someone + is always eager to misinterpret it. + +Finagle's Eleventh Law: + No matter what occurs, someone believes + it happened according to his pet theory. +%% +Finagle's First Law: + To study a subject best, understand it thoroughly before you start. + +Finagle's Second Law: + Always keep a record of data -- it indicates you've been working. + +Finagle's Fourth Law: + Once a job is fouled up, + anything done to improve it only makes it worse. + +Finagle's Fifth Law: + Always draw your curves, then plot your readings. + +Finagle's Sixth Law: + Don't believe in miracles -- rely on them. +%% +Finagle's Law: + The perversity of the universe tends toward a maximum. +%% +Finagle's Seventh Law: + The perversity of the universe tends toward a maximum. +%% +Finagle's Third Law: + In any collection of data, the figure most obviously correct, + beyond all need of checking, is the mistake. + +Corollaries: + 1. Nobody whom you ask for help will see it. + 2. The first person who stops by, whose advice you really + don't want to hear, will see it immediately. +%% +Fine day for friends. +So-so day for you. +%% +Fine day to throw a party. Throw him as far as you can. +%% +Fine day to work off excess energy. Steal something heavy. +%% +First Law of Bicycling: + No matter which way you ride, it's uphill and against the wind. +%% +First Law of Procrastination: + Procrastination shortens the job and places the responsibility + for its termination on someone else (i.e., the authority who + imposed the deadline). + +Fifth Law of Procrastination: + Procrastination avoids boredom; one never has the feeling that + there is nothing important to do. +%% +First Law of Socio-Genetics: + Celibacy is not hereditary. +%% +First Rule of History: + History doesn't repeat itself -- + historians merely repeat each other. +%% +First law of debate: + Never argue with a fool. People might not know the difference. +%% +First rule of public speaking. + First, tell 'em what you're goin' to tell 'em; + then tell 'em; + then tell 'em what you've tole 'em. +%% +First you get down on your knees, Get in line in that processional, +Fiddle with your rosaries, Step into that small confessional, +Bow your head with great respect, There the guy who's got religion'll +And genuflect, genuflect, genuflect! Tell you if your sins' original. +Do whatever steps you want if If it is, try playin' it safer, +You have cleared them with the Pontiff, Drink the wine and chew the wafer, +Ev'rybody say his own Two, four, six eight, +Kyrie eleison, Time to transubstantiate! +Doin' the Vatican Rag. + +So get down upon your knees, Make a cross on your abdomen, +Fiddle with your rosaries, When in Rome do like a Roman, +Bow your head with great respect, Ave Maria, +And genuflect, genuflect, genuflect! Gee, it's good to see ya, + Gettin' ecstatic an' sorta dramatic an' Doin' the Vatican Rag! + -- Tom Lehrer, "The Vatican Rag" +%% +Five bicycles make a volkswagen, seven make a truck. + -- Adolfo Guzman +%% +Five names that I can hardly stand to hear, +Including yours and mine and one more chimp who isn't here, +I can see the ladies talking how the times is gettin' hard, +And that fearsome excavation on Magnolia boulevard, +Yes, I'm goin' insane, +And I'm laughing at the frozen rain, +Well, I'm so alone, honey when they gonna send me home? + Bad sneakers and a pina colada my friend, + Stopping on the avenue by Radio City, with a + Transistor and a large sum of money to spend... +You fellah, you tearin' up the street, +You wear that white tuxedo, how you gonna beat the heat, +Do you take me for a fool, do you think that I don't see, +That ditch out in the Valley that they're diggin' just for me, +Yes, and goin' insane, +You know I'm laughin' at the frozen rain, +Feel like I'm so alone, honey when they gonna send me home? +(chorus) + -- Bad Sneakers, "Steely Dan" +%% +Five rules for eternal misery: + 1) Always try to exhort others to look upon you favorably. + 2) Make lots of assumptions about situations and be sure to + treat these assumptions as though they are reality. + 3) Then treat each new situation as though it's a crisis. + 4) Live in the past and future only (become obsessed with + how much better things might have been or how much worse + things might become). + 5) Occasionally stomp on yourself for being so stupid as to + follow the first four rules. +%% +Flame on! + -- Johnny Storm +%% +Flappity, floppity, flip +The mouse on the Mobius strip; + The strip revolved, + The mouse dissolved +In a chronodimensional skip. +%% +Flattery is like cologne -- to be smelled, but not swallowed. + -- Josh Billings +%% +Flattery will get you everywhere. +%% +Flee at once, all is discovered. +%% +Flirting is the gentle art of making a man feel pleased with himself. + -- Helen Rowland +%% +Flon's Law: + There is not now, and never will be, a language in + which it is the least bit difficult to write bad programs. +%% +Flugg's Law: + When you need to knock on wood is when you realize + that the world is composed of vinyl, naugahyde and aluminum. +%% +Fly me away to the bright side of the moon ... +%% +Folks, what can I tell you about my next guest. This cat allowed himself +to be adored, but not loved. And his success in show business was matched +by failure in his personal relationship bag, now that's where he really +bombed. And he came to believe that work, show business, love, his whole +life, even himself and all that jazz was bullshit. He became numero uno +gameplayer. Uh, to the point where he didn't know where the games ended +and the reality began. Like to this cat, the only reality... is death, man. +Ladies and gentlemen, let me lay on you, a so-so entertainer, not much of +a humanitarian, and this cat was never nobody's friend. In his final +appearance on the great stage of life, uh, you can applaud if you want to, +Mr. Joe Gideon!! + -- All That Jazz +%% +Fools rush in -- and get the best seats in the house. +%% +Football builds self-discipline. What else would induce +a spectator to sit out in the open in subfreezing weather? +%% +For God's sake, stop researching for a while and begin to think! +%% +For I do not do the good I want, but the evil I do not want is what I do. + -- Paul of Tarsus, (Saint Paul) +%% +For I swore I would stay a year away from her; out and alas! +but with break of day I went to make supplication. + -- Paulus Silentarius, c. 540 A.D. +%% +For a gay time, call 632-9483. Ask for Brucie. +%% +For a good time, call 632-9484. Ask for Cathy. +%% +For a good time, call 632-9485. Ask for Michael. +%% +For a holy stint, a moth of the cloth gave up his woolens for lint. +%% +For a light heart lives long. + -- Shakespeare, "Love's Labour's Lost" +%% +For adult education nothing beats children. +%% +For an idea to be fashionable is ominous, +since it must afterwards be always old-fashioned. +%% +For children with short attention spans: boomerangs that don't come back. +%% +For courage mounteth with occasion. + -- William Shakespeare, "King John" +%% +For every action, there is an equal and opposite criticism. + -- Harrison +%% +For example, if \thinmskip = 3mu, this makes \thickmskip = 6mu. But if +you also want to use \skip12 for horizontal glue, whether in math mode or +not, the amount of skipping will be in points (e.g., 6pt). The rule is +that glue in math mode varies with the size only when it is an \mskip; +when moving between an mskipand ordinary skip, the conversion factor +1mu=1pt is always used. The meaning of '\mskip\skip12' and +'\baselineskip=\the\thickmskip' should be clear. + -- Donald Knuth, TeX 82 -- Comparison with TeX80 +%% + For example, in Year 1 that useless letter 'c' would be dropped to be +replased either by 'k' or 's', and likewise 'x' would no longer be part of the +alphabet. The only kase in which 'c' would be retained would be the 'ch' +formation, which will be dealt with later. Year 2 might reform 'w' spelling, +so that 'which' and 'one' would take the same konsonant, wile Year 3 might +well abolish 'y' replasing it with 'i' and Iear 4 might fiks the 'g-j' +anomali wonse and for all. + Jenerally, then, the improvement would kontinue iear bai iear with +Iear 5 doing awai with useless double konsonants, and Iears 6-12 or so +modifaiing vowlz and the rimeining voist and unvoist konsonants. Bai +Iear 15 or sou, it wud fainali bi posibl tu meik ius ov thi ridandant letez +'c', 'y' and 'x' - bai now jast a memori in the maindz ov ould doderez - tu +riplais 'ch', 'sh', and 'th' rispektivli. + Fainali, xen, aafte sam 20 iers ov orxogrefkl riform, wi wud hev a +lojikl, kohirnt speling in ius xrewawt xe Ingliy-spiking werld. +%% +For fast-acting relief, try slowing down. +%% +For fools rush in where angels fear to tread. + -- Alexander Pope +%% +For good, return good. +For evil, return justice. +%% +For if there is a sin against life, it consists perhaps not so much in +despairing of life as in hoping for another life and in eluding the +implacable grandeur of this life. + -- Albert Camus +%% +For men use, if they have an evil turn, to write it in marble: +and whoso doth us a good turn we write it in dust. + -- Sir Thomas More +%% +For myself, I can only say that I am astonished and somewhat terrified at +the results of this evening's experiments. Astonished at the wonderful +power you have developed, and terrified at the thought that so much hideous +and bad music may be put on record forever. + -- Sir Arthur Sullivan, message to Edison, 1888 +%% +For people who like that kind of book, +that is the kind of book they will like. +%% +For some reason a glaze passes over people's faces when you say +`Canada'. Maybe we should invade South Dakota or something. + -- Sandra Gotlieb, wife of the Canadian ambassador to the U.S. +%% +For some reason, this fortune reminds everyone of Marvin Zelkowitz. +%% +For that matter, compare your pocket computer with the +massive jobs of a thousand years ago. Why not, then, the +last step of doing away with computers altogether?" + -- Jehan Shuman +%% +For the first time we have a weapon that nobody has used for thirty years. +This gives me great hope for the human race. + -- Harlan Ellison +%% +For the next hour, WE will control all that you see and hear. +%% +For thee the wonder-working earth puts forth sweet flowers. + -- Titus Lucretius Carus +%% +For they starve the frightened little child +Till it weeps both night and day: +And they scourge the weak, and flog the fool, +And gibe the old and grey, +And some grow mad, and all grow bad, +And none a word may say. + +Each narrow cell in which we dwell +Is a foul and dark latrine, +And the fetid breath of living Death +Chokes up each grated screen, +And all, but Lust, is turned to dust +In Humanity's machine. + +And all men kill the thing they love, +By all let this be heard, +Some do it with a bitter look, +Some with a flattering word, +The coward does it with a kiss, +The brave man with a sword. + -- Oscar Wilde +%% +For thirty years a certain man went to spend every evening with Mme. ___. +When his wife died his friends believed he would marry her, and urged +him to do so. "No, no," he said: "if I did, where should I have to +spend my evenings?" + -- Chamfort +%% +For those who like this sort of thing, this is the sort of thing they like. + -- Abraham Lincoln +%% +For years a secret shame destroyed my peace-- +I'd not read Eliot, Auden or MacNiece. +But now I think a thought that brings me hope: +Neither had Chaucer, Shakespeare, Milton, Pope. + -- Justin Richardson. +%% +Force has no place where there is need of skill. + -- Herodotus +%% +"Force is but might," the teacher said-- +"That definition's just." +The boy said naught but thought instead, +Remembering his pounded head: +"Force is not might but must!" +%% +Force it!!! +If it breaks, well, it wasn't working anyway... +No, don't force it, get a bigger hammer. +%% +Forgive, O Lord, my little jokes on Thee +And I'll forgive Thy great big one on me. + -- Robert Frost +%% +Forgive and forget. + -- Cervantes +%% +Forgive him, +for he believes that the customs of his tribe are the laws of nature! + -- G.B. Shaw +%% +Forsan et haec olim meminisse juvabit. +%% +Fortune and love befriend the bold. + -- Ovid +%% +Fortune favors the lucky. +%% +Fortune finishes the great quotations, #15 + + "Give me your tired, your poor, your huddled masses." + And while you're at it, throw in a couple of those Dallas + Cowboy cheerleaders. +%% +Fortune finishes the great quotations, #17 + + "This bud of love, by summer's ripening breath, + May prove a beauteous flower when next we meet." + Juliet, this bud's for you. +%% +Fortune finishes the great quotations, #6 + + "But, soft! What light through yonder window breaks?" + It's nothing, honey. Go back to sleep. +%% +Fortune finishes the great quotations, #3 + + Birds of a feather flock to a newly washed car. +%% +Fortune finishes the great quotations, #2 + + If at first you don't succeed, think how many people + you've made happy. +%% +Fortune finishes the great quotations, #9 + + A word to the wise is often enough to start an argument. +%% +Fortune finishes the great quotations, #12 + + Those who can, do. Those who can't, write the instructions. +%% +Fortune suggests uses for YOUR favorite UNIX commands! + +Try: + ar t "God" + drink < bottle (Bourne Shell) + cat "food in tin cans" (all but 4.[23]BSD) + Hey UNIX! Got a match? (V6 or C shell) + mkdir matter;cat > matter (Bourne Shell) + make "the perfect dry martini" + !!:Say, what do you think of margarine? (C shell) +%% +Fortune's Exercising Truths: + +1: Richard Simmons gets paid to exercise like a lunatic. You don't. +2. Aerobic exercises stimulate and speed up the heart. So do heart attacks. +3. Exercising around small children can scar them emotionally for life. +4. Sweating like a pig and gasping for breath is not refreshing. +5. No matter what anyone tells you, isometric exercises cannot be done + quietly at your desk at work. People will suspect manic tendencies as + you twitter around in your chair. +6. Next to burying bones, the thing a dog enjoys mosts is tripping joggers. +7. Locking four people in a tiny, cement-walled room so they can run around + for an hour smashing a little rubber ball -- and each other -- with a hard + racket should immediately be recognized for what it is: a form of insanity. +8. Fifty push-ups, followed by thirty sit-ups, followed by ten chin-ups, + followed by one throw-up. +9. Any activity that can't be done while smoking should be avoided. +%% +Fortune's Great Moments in History: #3 + +August 27, 1949: + A Hall of Fame opened to honor outstanding members of the + Women's Air Corp. It was a WAC's Museum. +%% +Fortune's Rules for Memo Wars + + Any attempt to say that someone's personal beliefs are wrong, even if +you supply conclusive evidence to support your claim, is an outright attack. +If you show someone a flaw in his/her logic, they have every right to punch +you in the face. Mathematical proofs of errors are the moral equivalent +of rape and should be avoided at all cost. + Now... your opponent has requested a "rational discussion". What do +you do? Well, remember that people are normally willing to discuss things +rationally if and only if you agree with them; anything less would obviously +not be rational. Therefore, agree immediately, and continue as before. + Always assume that whenever you see someone making a statement about +"certain parties who shall remain nameless", "some people", "assholes", etc., +they are talking about *you*. It is also correct to assume that words you +don't understand, such as "prestidigatory", "lapidarian", and "buprestid", +are direct personal attacks aimed at your loved ones and merit an equally +scathing response. Failure to do this results in many lost opportunities for +rational discussion. (See above.) +%% +Fortune's Rules for Memo Wars + +Given the incredible advances in sociocybernetics and telepsychology over +the last few years, we are now able to completely understand everything that +the author of an memo is trying to say. Thanks to modern developments +in electrocommunications like notes, vnews, and electricity, we have an +incredible level of interunderstanding the likes of which civilization has +never known. Thus, the possibility of your misinterpreting someone else's +memo is practically nil. Knowing this, anyone who accuses you of having +done so is a liar, and should be treated accordingly. If you *do* understand +the memo in question, but have absolutely nothing of substance to say, then +you have an excellent opportunity for a vicious ad hominem attack. In fact, +the only *inappropriate* times for an ad hominem attack are as follows: + 1: When you agree completely with the author of an memo. + 2: When the author of the original memo is much bigger than you are. + 3: When replying to one of your own memos. +%% +Fortune's Rules for Memo Wars + +The proper time for a vicious ad hominem attack is when you have no logical +recourse. If you have been arguing a point with a person or persons for +30 odd weeks, and an memo comes across that logically tears down the +final shred of evidence that you thought you had, that is the time to call +the author of that memo: + 1: a mindless twit who attacks other people's beliefs for no reason. + 2: an egotistical flaming typical wombat aggie melon-humping + cheese-whizzing nanosexual subuseless clamsucker whose + memos are apparently sneezed onto his/her terminal. + 3: something unpleasant. +The OTHER proper time for an ad hominem attack is immediately after someone +has posted something you don't understand. Given the current state of modern +electronic communications technology your inability to comprehend the meaning +of an memo constitutes a violation of western moral tradition on the part of +the author of that memo, and the author should be taken to task publicly via +a series of really nasty, name-calling oriented memos. +%% +Fortune's current rates: + + Answers .10 + Long answers .25 + Answers requiring thought .50 + Correct answers $1.00 + + Dumb looks are still free. +%% +Fortune's diet truths: +1: Forget what the cookbooks say, plain yogurt tastes nothing like sour cream. +2: Any recipe calling for soybeans tastes like mud. +3: Carob is not an acceptable substitute for chocolate. In fact, carob is not + an acceptable substitute for anything, except, perhaps, brown shoe polish. +4: There is no such thing as a "fun salad." So let's stop pretending and see + salads for what they are: God's punishment for being fat. +5: Fruit salad without maraschino cherries and marshmallows is about as + appealing as tepid beer. +6: A world lacking gravy is a tragic place! +7: You should immediately pass up any recipes entitled "luscious and + low-cal." Also skip dishes featuring "lively liver." They aren't and + it isn't. +8: Wearing a blindfold often makes many diet foods more palatable. +9: Fresh fruit is not dessert. CAKE is dessert! +10: Okra tastes slightly worse than its name implies. +11: A plain baked potato isn't worth the effort involved in chewing and + swallowing. +%% +Fortune's nomination for All-Time Champion and Protector of Youthful Morals +goes to Representative Clare E. Hoffman of Michigan. During an impassioned +House debate over a proposed bill to "expand oyster and clam research," a +sharp-eared informant transcribed the following exchange between our hero +and Rep. John D. Dingell, also of Michigan. + +Dingell: "There are places in the world at the present time where we are + having to artifically propogate oysters and clams." +Hoffman: "You mean the oysters I buy are not nature's oysters?" +Dingell: "They may or may not be natural. The simple fact of the matter is + that female oysters through their living habits cast out large + amounts of seed and the male oysters cast out large amounts of + fertilization." +Hoffman: "Wait a minute! I do not want to go into that. There are many + teenagers who read The Congressional Record." +%% + "Found it," the Mouse replied rather crossly: +"of course you know what 'it' means." + + "I know what 'it' means well enough, when I find a thing," +said the Duck: "it's generally a frog or a worm. + +The question is, what did the archbishop find?" +%% +Four be the things I am wiser to know: +Idleness, sorrow, a friend, and a foe. + +Four be the things I'd been better without: +Love, curiosity, freckles, and doubt. + +Three be the things I shall never attain: +Envy, content, and sufficient champagne. + +Three be the things I shall have till I die: +Laughter and hope and a sock in the eye. + -- Inventory +%% +Four hours to bury the cat? +Yes, damn thing wouldn't keep still, kept mucking about, 'owling... +%% +Fourth Law of Applied Terror: + The night before the English History mid-term, your Biology + instructor will assign 200 pages on planaria. + +Corollary: + Every instructor assumes that you have nothing else to do except + study for that instructor's course. +%% +Fourth Law of Revision: + It is usually impractical to worry beforehand about + interferences -- if you have none, someone will make one + for you. +%% +Freedom begins when you tell Mrs. Grundy to go fly a kite. +%% +Freedom from incrustation of grime is contiguous to rectitude. +%% +Freedom is nothing else but the chance to do better. + -- Camus +%% +Freedom is slavery. +Ignorance is strength. +War is peace. + -- George Orwell +%% +Freedom of the press is for those who happen to own one. +%% +Fresco's Discovery: + If you knew what you were doing you'd probably be bored. +%% +Friction is a drag. +%% +Fried's 1st Rule: + Increased automation of clerical function + invariably results in increased operational costs. +%% +Friends, Romans, Hipsters, +Let me clue you in; +I come to put down Caeser, not to groove him. +The square kicks some cats are on stay with them; +The hip bits, like, go down under; so let it lay with Caeser. +The cool Brutus gave you the message: Caeser had big eyes; +If that's the sound, someone's copping a plea, +And, like, old Caeser really set them straight. +Here, copacetic with Brutus and the studs, -- for Brutus is a + real cool cat; +So are they all, all cool cats, -- +Come I to make this gig at Caeser's laying down. +%% +Frisbeetarianism is the belief that when you die, +your soul goes up the on roof and gets stuck. +%% +From a certain point onward there is no longer any turning back. +That is the point that must be reached. + -- F. Kafka +%% +From listening comes wisdom and from speaking repentance. +%% +From the cradle to the coffin underwear comes first. + -- Bertolt Brecht +%% +From too much love of living, +From hope and fear set free, +We thank with brief thanskgiving, +Whatever gods may be, +That no life lives forever, +That dead men rise up never, +That even the weariest river winds somewhere safe to sea. + -- Swinburne +%% +Fudd's First Law of Opposition: + Push something hard enough and it will fall over. +%% +Function reject. +%% +Fundamentally, there may be no basis for anything. +%% +Future looks spotty. You will spill soup in late evening. +%% +GARTER: + An elastic band intended to keep a woman + from coming out of her stockings and desolating the country. +%% +GEMINI (May 21 - June 20) + A day to take the initiative. Put the garbage out, for + instance, and pick up the stuff at the dry cleaners. Watch + the mail carefully, although there won't be anything good + in it today, either. +%% +GENEALOGY: + An account of one's descent from an ancestor + who did not particularly care to trace his own. + -- Ambrose Bierce +%% +GENIUS: + A chemist who discovers a laundry additive that rhymes with bright. +%% +GENIUS: + Person clever enough to be born in the right place at the right + time of the right sex and to follow up this advantage by saying + all the right things to all the right people. +%% +GEORGIA: + Where kinky sex means getting laid. +%% +GIVE UP!!!! +%% +GIVE: Support the helpless victims of computer error. +%% +GOD: + Darwin's chief rival. +%% +//GO.SYSIN DD *, DOODAH, DOODAH +%% +GRASSHOPPOTAMUS: + A creature that can leap to tremendous heights... once. +%% +GRAVITY: + What you get when you eat too much and too fast. +%% +GREAT MOMENTS IN AMERICAN HISTORY (#21): July 30, 1917 + +On this day, New York City hotel detectives burst in and caught then +Senator Warren G. Harding in bed with an underage girl. He bought +them off with a $20 bribe, and later remarked thankfully, "I thought +I wouldn't get out of that under $1000!" Always one to learn from +his mistakes, in later years President Harding carried on his affairs +in a tiny closet in the White House Cabinet Room while Secret Service +men stood lookout. +%% +GUILLOTINE: + A French chopping center. +%% +GURU: + A person in T-shirt and sandals who took an elevator ride with + a senior vice-president and is ultimately responsible for the + phone call you are about to receive from your boss. +%% +Garbage In - Gospel Out. +%% +Gauls! We have nothing to fear; except perhaps that the sky may fall on +our heads tomorrow. But as we all know, tomorrow never comes!! + -- Adventures of Asterix +%% +Gay shlafen: Yiddish for "go to sleep". + +Now doesn't "gay shlafen" have a softer, more soothing sound than the +harsh, staccato "go to sleep"? Listen to the difference: + "Go to sleep, you little wretch!" ... "Gay shlafen, darling." +Obvious, isn't it? + Clearly the best thing you can do for you children is to start +speaking Yiddish right now and never speak another word of English as +long as you live. This will, of course, entail teaching Yiddish to all +your friends, business associates, the people at the supermarket, and +so on, but that's just the point. It has to start with committed +individuals and then grow.... + Some minor adjustments will have to be made, of course: those +signs written in what look like Yiddish letters won't be funny when +everything is written in Yiddish. And we'll have to start driving on +the left side of the road so we won't be reading the street signs +backwards. But is that too high a price to pay for world peace? +I think not, my friend, I think not. + -- Arthur Naiman +%% + "Gee, Mudhead, everyone at Morse Science High has an +extracurricular activity except you." + "Well, gee, doesn't Louise count?" + "Only to ten, Mudhead." +%% +General notions are generally wrong. + -- Lady M.W. Montagu +%% +Generosity and perfection are your everlasting goals. +%% +Genetics explains why you look like your father, +and if you don't, why you should. +%% +Genius does what it must, and Talent does what it can. + -- Owen Meredith +%% +Genius is one percent inspiration and ninety-nine percent perspiration. + -- Thomas Alva Edison +%% +Genius is pain. + -- John Lennon +%% +Genius is ten percent inspiration and fifty percent capital gains. +%% +Genius is the talent of a person who is dead. +%% +Genius may have its limitations, but stupidity is not thus handicapped. + -- Elbert Hubbard +%% + "Gentlemen of the jury," said the defense attorney, now beginning +to warm to his summation, "the real question here before you is, shall this +beautiful young woman be forced to languish away her loveliest years in a +dark prison cell? Or shall she be set free to return to her cozy little +apartment at 4134 Mountain Ave. -- there to spend her lonely, loveless hours +in her boudoir, lying beside her little Princess phone, 962-7873?" +%% +Gentlemen prefer blondes, but who says blondes prefer gentlemen? + -- Mae West +%% +Geometry teaches us to bisex angels. +%% +George Orwell was an optimist. +%% +George, after tying on a whopper the night before, woke up in the morning to +find a pathetically unattractive woman sleeping blissfully beside him. He +leaped out of bed, dressed quickly, and furtively placed $100 on top of the +bureau. He then started to tiptoe out of the room. But, as he passed the +foot of the bed, he felt a tug at his trouser leg. Glancing down, he saw +another female even homelier than the one he'd left in bed. She gazed up +at him soulfully, and asked, "Nothing for the bridesmaid?" +%% +George's friend Sam had a dog who could recite the Gettysburg Address. "Let +me buy him from you," pleaded George after a demonstration. + "Okay," agreed Sam. "All he knows is that Lincoln speech anyway." + At his company's Fourth of July picnic, George brought his new pet +and announced that the animal could recite the entire Gettysburg Address. +No one believed him, and they proceeded to place bets against the dog. +George quieted the crowd and said, "Now we'll begin!" Then he looked at +the dog. The dog looked back. No sound. "Come on, boy, do your stuff." +Nothing. A disappointed George took his dog and went home. + "Why did you embarrass me like that in front of everybody?" George +yelled at the dog. "Do you realize how much money you lost me?" + "Don't be silly, George," replied the dog. "Think of the odds we're +gonna get on Labor Day." +%% +Gerrold's Laws of Infernal Dynamics: + 1) An object in motion will always be headed in the wrong direction. + 2) An object at rest will always be in the wrong place. + 3) The energy required to change either one of these states + will always be more than you wish to expend, but never so + much as to make the task totally impossible. +%% +Get forgiveness now -- tomorrow you may no longer feel guilty. +%% +Get in touch with your feelings of hostility against the dying light. + -- Dylan Thomas +%% +Getting into trouble is easy. + -- D. Winkel and F. Prosser +%% +Getting there is only half as far as getting there and back. +%% +Gibble gabble gabble gibble gurgle lubble gibble babble beeble triggle + Lean closer. +Libble gabble gabble ibble gurgle gubble tibble babble feeble riggle + Smile at her *knowingly*. +Gibble gabble sabble gibble surgle gubble gibble babble beeble giggle + Nod sympathetically. Show you're on *her* side. +Bibble gabble gabble babble gurgle gubble gibble tribble beeble figgle + Touch her hand lightly. Nobody understands but we two. +Fibble gabble fobble gibble gurgle bubble gibble tabble beeble giggle + Look sincere. + +"Why don't we have the next drink up at MY place?" + + God's gift to women strikes again. + -- J. Feiffer +%% +Gilbert's Discovery: + Any attempt to use the new super glues results in the two pieces + sticking to your thumb and index finger rather than to each other. +%% +Ginger Snap +%% +Ginsberg's Theorem: + 1. You can't win. + 2. You can't break even. + 3. You can't even quit the game. + +Freeman's Commentary on Ginsberg's theorem: + + Every major philosophy that attempts to make life seem + meaningful is based on the negation of one part of Ginsberg's + Theorem. To wit: + + 1. Capitalism is based on the assumption that you can win. + 2. Socialism is based on the assumption that you can break even. + 3. Mysticism is based on the assumption that you can quit the game. +%% +Girls marry for love. Boys marry because of a chronic irritation +that causes them to gravitate in the direction of objects with +certain curvilinear properties. + -- Ashley Montagu +%% +Girls who throw themselves at men, +are actually taking very careful aim. +%% +Give a woman an inch and she'll park a car in it. +%% +Give all orders verbally. Never write anything down +that might go into a "Pearl Harbor File". +%% +Give him an evasive answer. +%% +Give me a Plumber's friend the size of the Pittsburgh +dome, and a place to stand, and I will drain the world. +%% +Give me a fish and I will eat today. +Teach me to fish and I will eat forever. +%% +Give me a sleeping pill and tell me your troubles. +%% +Give me chastity and continence, but not just now. + -- St. Augustine +%% +Give me libertines or give me meth. +%% +Give me the Luxuries, and the Hell with the Necessities! +%% +Give me your students, your secretaries, +Your huddled writers yearning to breathe free, +The wretched refuse of your Selectric III's. +Give these, the homeless, typist-tossed to me. +I lift my disk beside the processor. + -- Inscription on a Word Processor +%% +Give thought to your reputation. +Consider changing your name and moving to a new town. +%% +Give your child mental blocks for Christmas. +%% +Give your very best today. +Heaven knows it's little enough. +%% +Given a choice between grief and nothing, I'd choose grief. + -- William Faulkner +%% +Given my druthers, I'd druther not. +%% +Given sufficient time, what you put +off doing today will get done by itself. +%% +Glib's Fourth Law of Unreliability: + Investment in reliability will increase until it exceeds the + probable cost of errors, or until someone insists on getting + some useful work done. +%% +Gloffing is a state of mine. +%% +Go ahead... make my day. + -- Dirty Harry +%% +Go away! Stop bothering me with all your +"compute this ... compute that"! I'm taking a VAX-NAP. + +logout +%% +Go climb a gravity well. +%% +Go directly to jail. Do not pass Go, do not collect $200. +%% +Go on writing plays, my boy. One of these days a London producer will go +into his office and say to his secretary, "Is there a play from Shaw this +morning?" and when she says "No," he will say, "Well, then we'll have to +start on the rubbish." And that's your chance, my boy. + -- G.B. Shaw to William Douglas Home +%% +Go placidly amid the noise and waste, and remember +what value there may be in owning a piece thereof. + -- Deteriorata +%% +Go slowly to the entertainments of thy friends, +but quickly to their misfortunes. + -- Chilo +%% +Go to a movie tonight. +Darkness becomes you. +%% +Go 'way! You're bothering me! +%% +Goals... Plans... they're fantasies, they're part of a dream world... + -- Wally Shawn +%% +God, I ask for patience -- and I want it right now! +%% +God created woman. +And boredom did indeed cease from that moment -- +but many other things ceased as well. +Woman was God's second mistake. + -- Nietzsche +%% +God did not create the world in 7 days; He screwed +around for 6 days and then pulled an all-nighter. +%% +God gave man two ears and one tongue so +that we listen twice as much as we speak. + -- Arab proverb +%% +God gives burdens; also shoulders. + + Jimmy Carter cited this Jewish saying in his concession speech +at the end of the 1980 election. At least he said it was a Jewish +saying; I can't find it anywhere. I'm sure he's telling the truth +though; why would he lie about a thing like that? + -- Arthur Naiman +%% +God gives us relatives; thank goodness we can chose our friends. +%% +God has intended the great to be great and the little to be little... +The trade unions, under the European system, destroy liberty [...] I do +not mean to say that a dollar a day is enough to support a workingman... +not enough to support a man and five children if he insists on smoking +and drinking beer. But the man who cannot live on bread and water is +not fit to live! A family may live on good bread and water in the +morning, water and bread at midday, and good bread and water at night! + -- Rev. Henry Ward Beecher +%% +God help the troubadour who tries to be a star. The more +that you try to find success, the more that you will fail. + -- Phil Ochs, on the Second System Effect +%% +God helps them that helps themselves. + -- B. Franklin +%% +God instructs the heart, not by ideas, +but by pains and contradictions. + -- De Caussade +%% +God is Dead. + -- Nietzsche +Nietzsche is Dead. + -- God +Nietzsche is God. + -- Dead +%% +God is a comic playing to an audience that's afraid to laugh. +%% +God is a polythiest. +%% +God is not dead! He's alive and autographing Bibles at Cody's! +%% +God is omnipotent, omniscient, and omnibenevolent -- it says so right here +on the label. If you have a mind capable of believing all three of these +divine attributes simultaneously, I have a wonderful bargain for you. No +checks, please. Cash and in small bills. + -- Lazarus Long +%% +God is really only another artist. He invented the giraffe, the +elephant and the cat. He has no real style, He just goes on trying +other things. + -- Pablo Picasso +%% +God is the tangential point between zero and infinity. + -- Alfred Jarry +%% +God isn't dead, he just couldn't find a parking place. +%% +God made machine language; all the rest is the work of man. +%% +God made the integers; all else is the work of Man. + -- Kronecker +%% +God made the world in six days, and was arrested on the seventh. +%% +God may be subtle, but he isn't plain mean. + -- Albert Einstein +%% +God must love the common man; He made so many of them. +%% +God rest ye CS students now, The bearings on the drum are gone, +Let nothing you dismay. The disk is wobbling, too. +The VAX is down and won't be up, We've found a bug in Lisp, and Algol +Until the first of May. Can't tell false from true. +The program that was due this morn, And now we find that we can't get +Won't be postponed, they say. At Berkeley's 4.2. +(chorus) (chorus) + +We've just received a call from DEC, And now some cheery news for you, +They'll send without delay The network's also dead, +A monitor called RSuX We'll have to print your files on +It takes nine hundred K. The line printer instead. +The staff committed suicide, The turnaround time's nineteen weeks. +We'll bury them today. And only cards are read. +(chorus) (chorus) + +And now we'd like to say to you CHORUS: Oh, tidings of comfort and joy, +Before we go away, Comfort and joy, +We hope the news we've brought to you Oh, tidings of comfort and joy. +Won't ruin your whole day. +You've got another program due, tomorrow, by the way. +(chorus) + -- to God Rest Ye Merry Gentlemen +%% +God votes Republican. +%% +God's plan made a hopeful beginning +But man spoiled his chances by sinning. + We trust that the story + Will end in God's glory +But at present, the other side's winning. +%% +Going into politics is as fatal to a gentleman as going into a bordello +is fatal to a virgin. + -- H.L. Mencken, "A Carnival of Buncombe" +%% +Going the speed of light is bad for your age. +%% +Going to church does not make a person religious, nor does going to school +make a person educated, any more than going to a garage makes a person a car. +%% +Goldenstern's Rules: + 1. Always hire a rich attorney. + 2. Never buy from a rich salesman. +%% +Gold's Law: + If the shoe fits, it's ugly. +%% +Gomme's Laws: + (1) A backscratcher will always find new itches. + (2) Time accelerates. + (3) The weather at home improves as soon as you go away. +%% +Good advice is something a man gives +when he is too old to set a bad example. + -- La Rouchefoucauld +%% +Good day for a change of scene. Repaper the bedroom wall. +%% +Good day for business affairs. +Make a pass at that the new file clerk. +%% +Good day for overcoming obstacles. Try a steeplechase. +%% +Good day to avoid cops. Crawl to school. +%% +Good day to avoid cops. Crawl to work. +%% +Good day to deal with people in high places; +particularly lonely stewardesses. +%% +Good day to let down old friends who need help. +%% +Good evening, gentlemen. I am a HAL 9000 computer. I became operational +at the HAL plant in Urbana, Illinois, on January 11th, nineteen hundred +ninety-five. My supervisor was Mr. Langley, and he taught me to sing a +song. If you would like, I could sing it for you. +%% +Good girls go to heaven, bad girls go everywhere. +%% +"Good health" is merely the slowest rate at which one can die. +%% +Good judgement comes from experience. +Experience comes from bad judgement. + -- Jim Horning +%% +Good leaders being scarce, following yourself is allowed. +%% +Good morning. This is the telephone company. Due to repairs, we're +giving you advance notice that your service will be cut off indefinitely +at ten o'clock. That's two minutes from now. +%% +Good news. Ten weeks from Friday will be a pretty good day. +%% +Good news from afar can bring you a welcome visitor. +%% +Good news is just life's way of keeping you off balance. +%% +Good night, Austin, Texas, wherever you are! +%% +Good night to spend with family, +but avoid arguments with your mate's new lover. +%% +Good-bye. I am leaving because I am bored. + -- George Saunders' dying words +%% +Goodbye, cool world. +%% +Gordon's Law: + If you think you have the solution, the question was poorly phrased. +%% +Got Mole problems? +Call Avogadro at 6.02 x 10^23. +%% +Got a dictionary? I want to know the meaning of life. +%% +Govern a great nation as you would cook a small fish. Don't overdo it. + -- Lao Tsu +%% +Government's Law: + There is an exception to all laws. +%% +Governor Tarkin. I should have expected to find you holding Vader's +leash. I thought I recognized your foul stench when I was brought on +board. + -- Princess Leia Organa +%% +Grabel's Law: + 2 is not equal to 3 -- not even for large values of 2. +%% +Graduate life -- it's not just a job, it's an indenture. +%% +Graduate students and most professors are +no smarter than undergrads. They're just older. +%% +Grandpa Charnock's Law: + You never really learn to swear until you learn to drive. + + [I thought it was when your kids learned to drive. Ed.] +%% +Gravity brings me down. +%% +Gravity is a myth, the Earth sucks. +%% +Gray's Law of Programming: + 'n+1' trivial tasks are expected to be + accomplished in the same time as 'n' tasks. + +Logg's Rebuttal to Gray's Law: + 'n+1' trivial tasks take twice as long as 'n' trivial tasks. +%% +Great American Axiom: + Some is good, more is better, too much is just right. +%% +Great acts are made up of small deeds. + -- Lao Tsu +%% +Great spirits have always encountered +violent opposition from mediocre minds. + -- A. Einstein +%% +Greatness is a transitory experience. It is never consistent. +%% +Green light in A.M. for new projects. +Red light in P.M. for traffic tickets. +%% +Grelb's Reminder: + Eighty percent of all people consider + themselves to be above average drivers. +%% +Grief can take care of itself; but to get the full +value of a joy you must have somebody to divide it with. + -- Mark Twain +%% +Grinnell's Law of Labor Laxity: + At all times, for any task, you have not got enough done today. +%% +Grownups are reluctant to take science fiction seriously, and with good +reason: sci-fi is a hormonal activity, not a literary one. Its traditional +concerns are all pubescent. Secondary sexual characteristics are everywhere, +disguised. Aliens have tentacles. Telepathy allows you to have sex without +any nasty inconvenience of touching. Womblike spaceships provide balanced +meals. No one ever has to grow old -- body parts are replaceable, like +Job's daughters, and if you're lucky you can become a robot. As for the +adult world, it's simply not there; political systems tend to be naively +authoritarian (there are more lords in science fiction than on public +television) and are often ruled by young boys on quests. The most popular +sci-fi book in years, Frank Herbert's Dune, sold millions of copies by +combining all these themes: it ends with its adolescent hero conquering the +universe while straddling a giant worm. + -- Arnold Klein +%% +Grub first, then ethics. + -- Bertolt Brecht +%% +Gumperson's Law: + The probability of a given event + occurring is inversely proportional to its desirability. +%% +Guns don't kill people. Bullets kill people. +%% +Gunter's Airborne Discoveries: + (1) When you are served a meal aboard an aircraft, + the aircraft will encounter turbulence. + (2) The strength of the turbulence + is directly proportional to the temperature of your coffee. +%% +HACKER: + Originally, any person with a knack for coercing stubborn inanimate +things; hence, a person with a happy knack, later contracted by the mythical +philosopher Frisbee Frobenius to the common usage, 'hack'. + In olden times, upon completion of some particularly atrocious body +of coding that happened to work well, culpable programmers would gather in +a small circle around a first edition of Knuth's Best Volume I by candlelight, +and proceed to get very drunk while sporadically rending the following ditty: + + Hacker's Fight Song + + He's a Hack! He's a Hack! + He's a guy with the happy knack! + Never bungles, never shirks, + Always gets his stuff to work! + +All take a drink (important!) +%% +HALF-DONE: + This is the best way to eat a kosher dill -- when it's still crunchy, + light green, yet full of garlic flavor. The difference between this + and the typical soggy dark green cucumber corpse is like the + difference between life and death. + + You may find it difficult to find a good half-done kosher dill there + in Seattle, so what you should do is take a cab out to the airport, + fly to New York, take the JFK Express to Jay Street-Borough Hall, + transfer to an uptown F, get off at East Broadway, walk north on + Essex (along the park), make your first left onto Hester Street, walk + about fifteen steps, turn ninety degrees left, and stop. Say to the + man, "Let me have a nice half-done." Worth the trouble, wasn't it? + -- Arthur Naiman +%% +HAND: + A singular instrument worn at the end of a human + arm and commonly thrust into somebody's pocket. +%% +HANGOVER: + The wrath of grapes. +%% +HAPPINESS: + An agreeable sensation arising + from contemplating the misery of another. +%% +HAPPINESS: + Finding the owner of a lost bikini. +%% +HARD: + The quality of your own data; also how + it is to believe those of other people. +%% +HARDWARE: + The parts of a computer system that can be kicked. +%% +HATRED: + A sentiment appropriate to the occasion of another's superiority. +%% +HEAD CRASH!! FILES LOST!! +Details at 11. +%% +HEAVEN: + A place where the wicked cease from troubling you with talk of + their personal affairs, and the good listen with attention while + you expound your own. +%% +HEAVY: + Seduced by the chocolate side of the force. +%% +HELL: + Truth seen too late. +%% +HELP! Man trapped in a human body! +%% +HELP!!!! I'm being held prisoner in /usr/games/lib! +%% +HE: Let's end it all, bequeathin' our brains to science. +SHE: What?!? Science got enough trouble with their OWN brains. + -- Walt Kelley +%% +HEY KIDS! ANN LANDERS SAYS: + Be sure it's true, when you say "I love you". It's a sin to + tell a lie. Millions of hearts have been broken, just because + these words were spoken. +%% +HIGH TECHNOLOGY: + A California innovation composed + of equal parts of silicon and marijuana. +%% +HIPPOGRIFF: + An animal (now extinct) which was half horse and half griffin. + The griffin was itself a compound creature, half lion and half + eagle. The hippogriff was actually, therefore, only one quarter + eagle, which is two dollars and fifty cents in gold. + The study of zoology is full of surprises. +%% +H.L. Mencken's Law: + Those who can -- do. + Those who can't -- teach. + +Martin's Extension: + Those who cannot teach -- administrate. + + [No, those who can't teach, teach here. Ed.] +%% +HOLY MACRO! +%% +HONEYMOON: + A short period of doting between dating and debting. + -- Ray C. Bandy +%% +HONORABLE: + Afflicted with an impediment in one's reach. In legislative + bodies, it is customary to mention all members as honorable; + as, "the honorable gentleman is a scurvy cur." +%% +HOST SYSTEM NOT RESPONDING, PROBABLY DOWN. DO YOU WANT TO WAIT? (Y/N) +%% +HOST SYSTEM RESPONDING, PROBABLY UP... +%% +Hacker's Guide To Cooking: +2 pkg. cream cheese (the mushy white stuff in silver wrappings that doesn't + really come from Philadelphia after all; anyway, about 16 oz.) +1 tsp. vanilla extract (which is more alcohol than vanilla and pretty + strong so this part you *GOTTA* measure) +1/4 cup sugar (but honey works fine too) +8 oz. Cool Whip (the fluffy stuff devoid of nutritional value that you + can squirt all over your friends and lick off...) +"Blend all together until creamy with no lumps." This is where you get to + join(1) all the raw data in a big buffer and then filter it through + merge(1m) with the -thick option, I mean, it starts out ultra lumpy + and icky looking and you have to work hard to mix it. Try an electric + beater if you have a cat(1) that can climb wall(1s) to lick it off + the ceiling(3m). +"Pour into a graham cracker crust..." Aha, the BUGS section at last. You + just happened to have a GCC sitting around under /etc/food, right? + If not, don't panic(8), merely crumble a rand(3m) handful of innocent + GCs into a suitable tempfile and mix in some melted butter. +"...and refrigerate for an hour." Leave the recipe's stdout in a fridge + for 3.6E6 milliseconds while you work on cleaning up stderr, and + by time out your cheesecake will be ready for stdin. +%% +Hacker's Law: + The belief that enhanced understanding will necessarily stir + a nation to action is one of mankind's oldest illusions. +%% +Hacker's Quicky #313: + Sour Cream -n- Onion Potato Chips + Microwave Egg Roll + Chocolate Milk +%% +Hackers of the world, unite! +%% +"Had he and I but met But ranged as infantry, +By some old ancient inn, And staring face to face, +We should have sat us down to wet I shot at him as he at me, +Right many a nipperkin! And killed him in his place. + +I shot him dead because -- He thought he'd 'list, perhaps, + Because he was my foe, Off-hand-like -- just as I -- +Just so: my foe of course he was; Was out of work -- had sold his traps +That's clear enough; although No other reason why. + +Yes; quaint and curious war is! +You shoot a fellow down +You'd treat, if met where any bar is +Or help to half-a-crown." + -- Thomas Hardy +%% +Had this been an actual emergency, we would have +fled in terror, and you would not have been informed. +%% +Hail to the sun god +He's such a fun god +Ra! Ra! Ra! +%% +Hailing frequencies open, Captain. +%% +Hale Mail Rule, The: + When you are ready to reply to a letter, you will lack at least + one of the following: + (a) A pen or pencil or typewriter. + (b) Stationery. + (c) Postage stamp. + (d) The letter you are answering. +%% +Half Moon tonight. (At least its better than no Moon at all.) +%% +Half the world is composed of people who have something to say and can't, +and the other half who have nothing to say and keep on saying it. +%% +Hall's Laws of Politics: + (1) The voters want fewer taxes and more spending. + (2) Citizens want honest politicians until they want + something fixed. + (3) Constituency drives out consistency (i.e., liberals defend + military spending, and conservatives social spending in + their own districts). +%% +Handel's Proverb: + You can't produce a baby in one month by impregnating 9 women! +%% +Hanging on in quiet desperation is the English way. + -- Pink Floyd +%% +Hanlon's Razor: + Never attribute to malice + that which is adequately explained by stupidity. +%% +Hanson's Treatment of Time: + There are never enough hours in a day, + but always too many days before Saturday. +%% +Happiness adds and multiplies as we divide it with others. +%% +Happiness is a hard disk. +%% +Happiness is having a scratch for every itch. + -- Ogden Nash +%% +Happiness is just an illusion, filled with sadness and confusion. +%% +Happiness is the greatest good. +%% +Happiness is twin floppies. +%% +Happiness isn't something you experience; it's something you remember. + -- Oscar Levant +%% +Happiness makes up in height what it lacks in length. +%% +Happy feast of the pig! +%% +Hard reality has a way of cramping your style. + -- Daniel Dennett +%% +Hark, the Herald Tribune sings, +Advertising wondrous things. + +Angels we have heard on High +Tell us to go out and Buy. +%% +Hark,Hark,the dogs do bark +The Duke is fond of kittens +He likes to take their insides out +And use them for his mittens + -- The Thirteen Clocks +%% +Harp not on that string. + -- William Shakespeare, "Henry VI" +%% +Harriet's Dining Observation: + In every restaurant, the hardness of the butter pats + increases in direct proportion to the softness of the bread. +%% +Harrisberger's Fourth Law of the Lab: + Experience is directly proportional to the amount of + equipment ruined. +%% +Harris's Lament: + All the good ones are taken. +%% + Harry, a golfing enthusiast if there ever was one, arrived home +from the club to an irate, ranting wife. + "I'm leaving you, Harry," his wife announced bitterly. "You +promised me faithfully that you'd be back before six and here it is almost +nine. It just can't take that long to play 18 holes of golf." + "Honey, wait," said Harry. "Let me explain. I know what I promised +you, but I have a very good reason for being late. Fred and I tee'd off +right on time and everything was find for the first three holes. Then, on +the fourth tee Fred had a stroke. I ran back to the clubhouse but couldn't +find a doctor. And, by the time I got back to Fred, he was dead. So, for +the next 15 holes, it was hit the ball, drag Fred, hit the ball, drag Fred... +%% +Harry and Fred were playing their sunday afternoon golf game. The game, as +always, was close. They were at the treacherous 12th hole: a par three that +required a perfect first shot over a large pond and onto a tiny green. There +were sand traps on the other three sides of the green, and a small road 50 +feet beyond it. Harry went first. He carefully addressed the ball and hit +a good shot that landed just on the edge of the green, narrowly avoiding the +pond. Just as Fred addressed his ball, he looked up and noticed a funeral +procession along the road just behind the green. Fred put down his club, +took his hat off, and waited for the entire procession to pass. As soon as +the cars were gone he put his hat back on and started addressing the ball +again. Harry said, "Damn, Fred. That was a really nice thing you did, +waiting for the funeral to pass like that." + Fred finished his swing, making perfect contact with the ball. It +was an excellent shot that landed 7 feet from the hole. "It's the least I +could do," he said, smiling at his shot, "We were married for 22 years, +you know." +%% + Harry constantly irritated his friends with his eternal optimism. +No matter how bad the situation, he would always say, "Well, it could have +been worse." + To cure him of his annoying habit, his friends decided to invent a +situation so completely black, so dreadful, that even Harry could find no +hope in it. Approaching him at the club bar one day, one of them said, +"Harry! Did you hear what happened to George? He came home last night, +found his wife in bed with another man, shot them both, and then turned +the gun on himself!" + "Terrible," said Harry. "But it could have been worse." + "How in hell," demanded his dumfounded friend, "could it possibly +have been worse?" + "Well," said Harry, "if it had happened the night before, I'd be +dead now." +%% +Harry's bar has a new cocktail. It's called MRS punch. They make it with +milk, rum and sugar and it's wonderful. The milk is for vitality and the +sugar is for pep. They put in the rum so that people will know what to do +with all that pep and vitality. +%% +Hartley's First Law: + You can lead a horse to water, but if you can + get him to float on his back, you've got something. +%% +Hartley's Second Law: + Never sleep with anyone crazier than yourself. +%% +Harvard Law: + Under the most rigorously controlled conditions of pressure, + temperature, volume, humidity, and other variables, the + organism will do as it damn well pleases. +%% +Has the great art and mystery of politics no apparent utility? Does it +appear to be unqualifiedly ratty, raffish, sordid, obscene and low down, +and its salient virtuosi a gang of umitigated scoundrels? Then let us +not forget its high capacity to soothe and tickel the midriff, its +incomparable services as a maker of entertainment. + -- H.L. Mencken, "A Carnival of Buncombe" +%% +Haste makes waste. + -- John Heywood +%% +Hate is like acid. It can damage the vessel in which it is +stored as well as destroy the object on which it is poured. +%% +Hate the sin and love the sinner. + -- Mahatma Gandhi +%% +Hating the Yankees is as American as pizza pie, +unwed mothers and cheating on your income tax. + -- Mike Royko +%% +Have a coke and a smile! + -- John DeLorean +%% +Have a nice day! +%% +Have a nice diurnal anomaly. +%% +Have a place for everything and keep the thing +somewhere else; this is not advice, it is merely custom. + -- Mark Twain +%% +Have a taco. + -- P.S. Beagle +%% +Have at you! +%% +Have no friends not equal to yourself. + -- Confucius +%% +Have the courage to take your own thoughts +seriously, for they will shape you. + -- Albert Einstein +%% +Have you ever felt like a wounded cow +halfway between an oven and a pasture? +walking in a trance toward a pregnant + seventeen-year-old housewife's + two-day-old cookbook? + -- Richard Brautigan +%% +Have you ever met a man of good character where women are concerned? + +Well, I haven't. I find that whenever a woman becomes friends with me, +she becomes jealous, exacting, suspicious, and a damn nuisance; and +whenever I become friends with a woman, I become selfish and tyrannical. +So here I am, Pickering, a confirmed old bachelor and very likely to +remain so. + -- Henry Higgins, "My Fair Lady" +%% +Have you ever noticed that the people who are always trying +to tell you `there's a time for work and a time for play' +never find the time for play? +%% +Have you ever really thought about there being a simple solution to +America's problems? Why, we could solve all of our raw materials +difficulties, foreign complications etc. over a long weekend. If we +got up early, early mind you, on Saturday, we could take over Mexico +by 10:00. Panama and most of South America would be a bit more difficult, +but I believe we could do it by 6 or 7 that evening. Turning our +attention northward, Canada would require most of Sunday morning. +General mopping up and execution of the civilian populations would take +up Sunday afternoon. I just don't understand why Washington hasn't +thought of this... +%% +Have you flogged your kid today? +%% +Have you locked your file cabinet? +%% +Have you noticed that all you need to grow healthy, +vigorous grass is a crack in your sidewalk? +%% +Have you seen how Sonny's burning, +Like some bright erotic star, +He lights up the proceedings, +And raises the temperature. + -- The Birthday Party, "Sonny's Burning" +%% +Have you seen the old man in the closed down market, +Kicking up the papers in his worn out shoes? +In his eyes you see no pride, hands hang loosely at his side +Yesterdays papers, telling yesterdays news. + +How can you tell me you're lonely, +And say for you the sun don't shine? +Let me take you by the hand +Lead you through the streets of London +I'll show you something to make you change your mind... + +Have you seen the old man outside the sea-mans mission +Memories fading like the metal ribbons that he wears. +In our winter city the rain cries a little pity +For one more forgotten hero and a world that doesn't care... +%% +Have you seen the well-to-do, up and down Park Avenue? +On that famous thoroughfare, with their noses in the air, +High hats and Arrow collars, white spats and lots of dollars, +Spending every dime, for a wonderful time... +If you're blue and you don't know where to go to, +Why don't you go where fashion sits, +... +Dressed up like a million dollar trooper, +Trying hard to look like Gary Cooper, (super dooper) +Come, let's mix where Rockefeller's walk with sticks, +Or umberellas, in their mitts, +Puttin' on the Ritz. +... +If you're blue and you don't know where to go to, +Why don't you go where fashion sits, +Puttin' on the Ritz. +Puttin' on the Ritz. +Puttin' on the Ritz. +Puttin' on the Ritz. +%% +Having a wonderful wine, wish you were beer. +%% +Having nothing, nothing can he lose. + -- William Shakespeare, "Henry VI" +%% +Having the fewest wants, I am nearest to the gods. + -- Socrates +%% +Having wandered helplessly into a blinding snowstorm Sam was greatly +relieved to see a sturdy Saint Bernard dog bounding toward him with +the traditional keg of brandy strapped to his collar. + "At last," cried Sam, "man's best friend -- and a great big +dog, too!" +%% +Hawkeye's Conclusion: + It's not easy to play the clown + when you've got to run the whole circus. +%% +He does it with a better grace, but I do it more natural. + -- William Shakespeare, "Twelfth-Night" +%% +He dove down overweighted with lead. +Passed one hundred and flat lost his head. + He flapped and he flailed, + Spit his hose and he wailed, +Swallowed water and found himself dead. +%% +He draweth out the thread of his verbosity +finer than the staple of his argument. + -- William Shakespeare, "Love's Labour's Lost" +%% +He gave her a look that you could have poured on a waffle. +%% +He grabbed me by my slender neck, +I could not call or scream. +He dragged me to his tiny room, +Where we could not be seen. +He tore away my filmy wrap, +And gazed upon my form. +I so cold and frightened, +While he so strong and warm. +He pressed me to his thirsty lips, +I gave him every drop. +He drained me of my very self, +I could not make him stop! +And that is why you see me here, +An empty, broken bottle of beer... +%% + He had been bitten by a dog, but didn't give it much thought +until he noticed that the wound was taking a remarkably long time to +heal. Finally, he consulted a doctor who took one look at it and +ordered the dog brought in. Just as he had suspected, the dog had +rabies. Since it was too late to give the patient serum, the doctor +felt he had to prepare him for the worst. The poor man sat down at the +doctor's desk and began to write. His physician tried to comfort him. +"Perhaps it won't be so bad," he said. "You needn't make out your will +right now." + "I'm not making out any will," relied the man. "I'm just writing +out a list of people I'm going to bite!" +%% +He had that rare weird electricity about him -- that extremely wild +and heavy presence that you only see in a person who has abandoned +all hope of ever behaving "normally." + -- Hunter S. Thompson, "Fear and Loathing '72" +%% +He hadn't a single redeeming vice. + -- Oscar Wilde +%% +He has not acquired a fortune; the fortune has acquired him. + -- Bion +%% +He hath eaten me out of house and home. + -- William Shakespeare, "Henry IV" +%% +He is considered a most graceful speaker +who can say nothing in the most words. +%% +He is no lawyer who cannot take two sides. +%% +He is now rising from affluence to poverty. + -- Mark Twain +%% +He is the best of men who dislikes power. + -- Mohammed +%% +He is truly wise who gains wisdom from another's mishap. +%% +He jests at scars who never felt a wound. + -- Shakespeare, "Romeo and Juliet, II. 2" +%% +He keeps differentiating, flying off on a tangent. +%% +He knows not how to know who knows not also how to unknow. + -- Sir Richard Burton +%% +He laughs at every joke three times... once when it's told, +once when it's explained, and once when he understands it. +%% +He looked at me as if I was a side dish he hadn't ordered. +%% +He missed an invaluable opportunity to hold this tongue. + -- Andrew Lang +%% +He played the king as if afraid someone else would play the ace. + -- John Mason Brown, drama critic +%% +He tells you when you've got on too much lipstick, +And helps you with your girdle when your hips stick. + -- O. Nash, on the perfect husband +%% +He that breaks a thing to find out what it is has left the path of wisdom. + -- J.R.R. Tolkien +%% +He that bringeth a present, findeth the door open. + -- Scottish proverb. +%% +He that composes himself is wiser than he that composes a book. + -- B. Franklin +%% +He that is giddy thinks the world turns round. + -- William Shakespeare, "The Taming of the Shrew" +%% +He that would govern others, first should be the master of himself. +%% +He thinks by infection, catching an opinion like a cold. +%% +He thought he saw an albatross +That fluttered 'round the lamp. +He looked again and saw it was +A penny postage stamp. +"You'd best be getting home," he said, +"The nights are rather damp." +%% +He thought of Musashi, the Sword Saint, standing in his garden more than +three hundred years ago. "What is the 'Body of a rock'?" he was asked. +In answer, Musashi summoned a pupil of his and bid him kill himself by +slashing his abdomen with a knife. Just as the pupil was about to comply, +the Master stayed his hand, saying, "That is the 'Body of a rock'." + -- Eric Van Lustbader +%% +He walks as if balancing the family tree on his nose. +%% +He was not only a great swordsman, but also a cunning linguist. +%% +He was part of my dream, of course -- +but then I was part of his dream too. + -- Lewis Carroll +%% +He was so narrow-minded he could see through a keyhole with both eyes. +%% +He who Laughs, Lasts. +%% +He who always plows a straight furrow is in a rut. +%% +He who attacks the fundamentals of the American +broadcasting industry attacks democracy itself. + -- William S. Paley, chairman of CBS +%% +He who enters his wife's dressing room is a philosopher or a fool. + -- Balzac +%% +He who falls in love with himself will have no rivals. +%% +He who fears the unknown may one day flee from his own backside. + -- Sinbad +%% +He who fights and runs away lives to fight another day. +%% +He who foresees calamities suffers them twice over. +%% +He who has a shady past knows that nice guys finish last. +%% +He who has but four and spends five has no need for a wallet. +%% +He who has imagination without learning has wings but no feet. +%% +He who hates vices hates mankind. +%% +He who hesitates is last. +%% +He who hesitates is sometimes saved. +%% +He who hoots with owls by night cannot soar with eagles by day. +%% +He who invents adages for others to peruse +takes along rowboat when going on cruise. +%% +He who is content with his lot probably has a lot. +%% +He who is flogged by fate and laughs the louder is a masochist. +%% +He who is good for making excuses is seldom good for anything else. +%% +He who is intoxicated with wine will be sober again in the course of the +night, but he who is intoxicated by the cupbearer will not recover his +senses until the day of judgement. + -- Saadi +%% +He who is known as an early riser need not get up until noon. +%% +He who is still laughing hasn't yet heard the bad news. + -- Bertolt Brecht +%% +He who knows, does not speak. He who speaks, does not know. + -- Lao Tsu +%% +He who knows nothing, knows nothing. +But he who knows he knows nothing knows something. +And he who knows someone whose friend's wife's brother knows nothing, + he knows something. Or something like that. +%% +He who knows others is wise. +He who knows himself is enlightened. + -- Lao Tsu +%% +He who knows that enough is enough will always have enough. + -- Lao Tsu +%% +He who laughs last -- missed the punch line. +%% +He who laughs last didn't get the joke. +%% +He who laughs last hasn't been told the terrible truth. +%% +He who laughs last is probably your boss. +%% +He who laughs last probably doesn't understand the joke. +%% +He who laughs last usually had to have joke explained. +%% +He who laughs, lasts. +%% +He who lives without folly is less wise than he believes. +%% +He who loses, wins the race, +And parallel lines meet in space. + -- John Boyd, "Last Starship from Earth" +%% +He who makes a beast of himself gets rid of the pain of being a man. + -- Dr. Johnson +%% +He who minds his own business is never unemployed. +%% +He who slings mud generally loses ground. + -- Adlai Stevenson +%% +He who slings mud loses ground. + -- Chinese Proverb +%% +He who spends a storm beneath a tree, takes life with a grain of TNT. +%% +He who steps on others to reach the top has good balance. +%% +He who trains his tongue to quote the learned +sages, will be known far and wide as a smart ass. + -- Howard Kandel +%% +He who walks on burning coals is sure to get burned. + -- Sinbad +%% +He who wonders discovers that this in itself is wonder. + -- M.C. Escher +%% +He who writes with no misspelled words has prevented a first suspicion +on the limits of his scholarship or, in the social world, of his general +education and culture. + -- Julia Norton McCorkle +%% +He: Do you like Kipling? +She: Oh, you naughty boy, I don't know! I've never kippled! +%% +He: "If I made love to you, would you yell?" +She: "What do you want me to yell?" + -- Benny Hill +%% +Health is merely the slowest possible rate at which one can die. +%% +Heard about the man who never worried about his marriage until he +moved from New York to California and discovered that he still had +the same mailman? +%% +Heard that the next Space Shuttle is supposed to carry several +Guernsey cows? It's gonna be the herd shot 'round the world. +%% +Hearts will never be practical until they can be made unbreakable. + -- The Wizard of Oz +%% +Heisenberg may have been here. +%% +Hell hath no fury like a bureaucrat scorned. + -- Milton Friedman +%% +Hell hath no limits, nor is circumscribed in one self place, +for where we are is Hell, and where Hell is there must we ever be. + -- Christopher Marlowe, "Doctor Faustus" +%% +Hell is empty and all the devils are here. + -- Wm. Shakespeare, "The Tempest" +%% +Heller's Law: + The first myth of management is that it exists. + +Johnson's Corollary: + Nobody really knows what is going on anywhere within the + organization. +%% +Hello. Jim Rockford's machine, this is Larry Doheny's machine. Will you +please have your master call my master at his convenience? Thank you. +Thank you. Thank you. Thank you. Thank you. Thank you. +%% +Hello, friend! You say things aren't going too well? You say you have a +date with your favorite girl when it starts raining so hard you can't see? +And you're out on some back road when the car stalls and won't start, so +you set off accross the fields, and 50 feet of barbed wire hits you right +smack in the puss? And then there's a big explosion behind you and you +don't hear your girl screaming any more? + + Well, take a walk in the sun and hold your head up high! + You'll show the world; you'll tell them where to get off! + You'll never give up, never give up, never give up -- that ship! +%% +Hell's broken loose. + -- Robert Greene +%% +Help! I'm trapped in a Chinese computer factory! +%% +Help! I'm trapped in a PDP 11/70! +%% +Help a swallow land at Capistrano. +%% +Help stamp out and abolish redundancy! +%% +Hempstone's Question: + If you have to travel on the Titanic, why not go first class? +%% +Her locks an ancient lady gave +Her loving husband's life to save; +And men -- they honored so the dame -- +Upon some stars bestowed her name. + +But to our modern married fair, +Who'd give their lords to save their hair, +No stellar recognition's given. +There are not stars enough in heaven. +%% +Here I am again right where I know I shouldn't be +I've been caught inside this trap too many times +I must've walked these steps and said these words a + thousand times before +It seems like I know everybody's lines. + -- David Bromberg, "How Late'll You Play 'Til?" +%% +Here I sit, broken-hearted, +All logged in, but work unstarted. +First net.this and net.that, +And a hot buttered bun for net.fat. + +The boss comes by, and I play the game, +Then I turn back to net.flame. +Is there a cure (I need your views), +For someone trapped in net.news? + +I need your help, I say 'tween sobs, +'Cause I'll soon be listed in net.jobs. +%% +Here at the Phone Company, we serve all kinds of people; +from President's and Kings to the scum of the earth... +%% +Here comes the orator, with his flood of words and his drop of reason. +%% +Here in my heart, I am Helen; + I'm Aspasia and Hero, at least. +I'm Judith, and Jael, and Madame de Stael; + I'm Salome, moon of the East. + +Here in my soul I am Sappho; + Lady Hamilton am I, as well. +In me Recamier vies with Kitty O'Shea, + With Dido, and Eve, and poor Nell. + +I'm all of the glamorous ladies + At whose beckoning history shook. +But you are a man, and see only my pan, + So I stay at home with a book. + -- Dorothy Parker +%% +Here is a test to find whether your mission on earth is finished: +if you're alive, it isn't. +%% +Here there by tygers. +%% +Here's to women. Would that we could fall +into her arms without falling into her hands. + -- Ambrose Bierce +%% +Herth's Law: + He who turns the other cheek too far gets it in the neck. +%% +He's been like a father to me, +He's the only DJ you can get after three, +I'm an all-night musician in a rock and roll band, +And why he don't like me I don't understand. + -- The Byrds +%% +He's dead, Jim. +%% +He's got the heart of a little child, +and he keeps it in a jar on his desk. +%% +He's just a politician trying to save both his faces... +%% +He's just like Capistrano, always ready for a few swallows. +%% +He's the kind of guy, that, well, if you were ever in a jam he'd +be there... with two slices of bread and some chunky peanut butter. +%% +Heuristics are bug ridden by definition. +If they didn't have bugs, then they'd be algorithms. +%% +Hewett's Observation: + The rudeness of a bureaucrat is inversely proportional to his or + her position in the governmental hierarchy and to the number of + peers similarly engaged. +%% +Hey, Jim, it's me, Susie Lillis from the laundromat. You said you were +gonna call and it's been two weeks. What's wrong, you lose my number? +%% +"Hey, Sam, how about a loan?" +"Whattaya need?" +"Oh, about $500." +"Whattaya got for collateral?" +"Whattaya need?" +"How about an eye?" + -- Sam Giancana +%% +Hey, diddle, diddle the overflow pdl +To get a little more stack; +If that's not enough then you lose it all +And have to pop all the way back. +%% +Hi! How are things going? + (just fine, thank you...) +Great! Say, could I bother you for a question? + (you just asked one...) +Well, how about one more? + (one more than the first one?) +Yes. + (you already asked that...) +[at this point, Alphonso gets smart... ] +May I ask two questions, sir? + (no.) +May I ask ONE then? + (nope...) +Then may I ask, sir, how I may ask you a question? + (yes, you may.) +Sir, how may I ask you a question? + (you must ask for retroactive question asking privileges for + the number of questions you have asked, then ask for that + number plus two, one for the current question, and one for the + next one) +Sir, may I ask nine questions? + (go right ahead...) +%% +Hi Jimbo. Dennis. Really appreciate the help on the income tax. +You wanna help on the audit now? +%% +Hi there! This is just a note from me, to you, to tell you, the person +reading this note, that I can't think up any more famous quotes, jokes, +nor bizarre stories, so you may as well go home. +%% +Hickery Dickery Dock, +The mice ran up the clock, +The clock struck one, +The others escaped with minor injuries. +%% +Higgeldy Piggeldy, +Hamlet of Elsinore +Ruffled the critics by +Dropping this bomb: +"Phooey on Freud and his +Psychoanalysis, +Oedipus, Shmoedipus, +I just loved Mom." +%% +Higgins: Doolittle, you're either an honest man or a rogue. +Doolittle: A little of both, Guv'nor. Like the rest of us, a + little of both. + -- Shaw, "Pygmalion" +%% +Higgledy Piggledy Coeducational +Yale University Extracurricular +Gave up misogyny Heterosexual +Opened its door. Fun is in store. +%% +High heels are a device invented by a woman +who was tired of being kissed on the forehead. +%% +Hildebrant's Principle: + If you don't know where you are going, + any road will get you there. +%% +Him: "Your skin is so soft. Are you a model?" +Her: "No," [blush] "I'm a cosmetologist." +Him: "Really? That's incredible... + It must be very tough to handle weightlessness." + -- The Jerk. +%% +Hindsight is an exact science. +%% +Hire the morally handicapped. +%% +His followers called him Mahasamatman and said he was a god. He preferred +to drop the Maha- and the -atman, however, and called himself Sam. He never +claimed to be a god. But then, he never claimed not to be a god. Circum- +stances being what they were, neither admission could be of any benefit. +Silence, though, could. It was in the days of the rains that their prayers +went up, not from the fingering of knotted prayer cords or the spinning of +prayer wheels, but from the great pray-machine in the monastery of Ratri, +goddess of the Night. The high-frequency prayers were directed upward through +the atmosphere and out beyond it, passing into that golden cloud called the +Bridge of the Gods, which circles the entire world, is seen as a bronze +rainbow at night and is the place where the red sun becomes orange at midday. +Some of the monks doubted the orthodoxy of this prayer technique... + -- Roger Zelazny, "Lord of Light" +%% +His heart was yours from the first moment that you met. +%% +His life was formal; his actions seemed ruled with a ruler. +%% +His mind is like a steel trap: full of mice. + -- Foghorn Leghorn +%% +History books which contain no lies are extremely dull. +%% +History has the relation to truth that theology has to religion -- +i.e. none to speak of. + -- Lazarus Long +%% +History is on our side (as long as we can control the historians). +%% +History repeats itself. That's one thing wrong with history. +%% +History repeats itself only if one does not listen the first time. +%% +Hit them biscuits with another touch of gravy, +Burn that sausage just a match or two more done. +Pour my black old coffee longer, +While that smell is gettin' stronger +A semi-meal ain't nuthin' much to want. + +Loan me ten, I got a feelin' it'll save me, +With an ornery soul who don't shoot pool for fun, +If that coat'll fit you're wearin', +The Lord'll bless your sharin' +A semi-friend ain't nuthin' much to want. + +And let me halfway fall in love, +For part of a lonely night, +With a semi-pretty woman in my arms. +Yes, I could halfway fall in deep-- +Into a snugglin', lovin' heap, +With a semi-pretty woman in my arms. + -- Elroy Blunt +%% +Hitchcock's Staple Principle: + The stapler runs out of staples + only while you are trying to staple something. +%% +Hlade's Law: + If you have a difficult task, give it to a lazy person -- + they will find an easier way to do it. +%% +Hoare's Law of Large Problems: + Inside every large problem is a small + problem struggling to get out. +%% +Hodie natus est radici frater. +%% +Hoffer's Discovery: + The grand act of a dying institution is to issue a newly + revised, enlarged edition of the policies and procedures manual. +%% +Hofstadter's Law: + It always takes longer than you expect, even when you take + Hofstadter's Law into account. +%% +Hollywood is where if you don't have happiness you send out for it. + -- Rex Reed +%% +"Home, Sweet Home" must surely have been written by a bachelor. +%% +Home is the place where, when you have +to go there, they have to take you in. +%% +Home on the Range was originally written in beef-flat. +%% +Honesty is for the most part less profitable than dishonesty. + -- Plato +%% +Honesty pays, but it doesn't seem to pay enough to suit some people. + -- F.M. Hubbard +%% +Honesty's the best policy. + -- Miguel de Cervantes +%% +Honi soit la vache qui rit. +%% +Honk if you love peace and quiet. +%% +Hope is a good breakfast, but it is a bad supper. + -- Francis Bacon +%% +Hope is a waking dream. + -- Aristotle +%% +Hope not, lest ye be disappointed. + -- M. Horner +%% +Hope that the day after you die is a nice day. +%% +Horace's best ode would not please a young woman as much +as the mediocre verses of the young man she is in love with. + -- Moore +%% +Horner's Five Thumb Postulate: + Experience varies directly with equipment ruined. +%% +Horngren's Observation: + Among economists, the real world is often a special case. +%% +Hors d'oeuvres -- a ham sandwich cut into forty pieces. + -- Jack Benny +%% +Horse sense is the thing a horse has +which keeps it from betting on people. + -- W.C. Fields +%% +Horsecrap, little brother. There's always something more to be done. +Another palm to be greased. Another back to be scratched. Another +weak sister to be shored up. + -- J.R. Ewing +%% +Houdini escaping from New Jersey! +%% +Household hint: + If you are out of cream for your coffee, + mayonnaise makes a dandy substitute. +%% +Houston, Tranquillity Base here. The Eagle has landed. + -- Neil Armstrong +%% +How apt the poor are to be proud. + -- William Shakespeare, "Twelfth-Night" +%% +How can you be in two places at once +when you're not anywhere at all? +%% +How can you do 'New Math' problems with an 'Old Math' mind? + -- Schulz +%% +How can you govern a nation which has 246 kinds of cheese? + -- Charles de Gaulle +%% +How can you have any pudding if you don't eat your meat? + -- Pink Floyd +%% +How can you work when the system's so crowded? +%% +How come we never talk anymore? +%% +How come wrong numbers are never busy? +%% +How comes it to pass, then, that we appear such cowards +in reasoning, and are so afraid to stand the test of ridicule? + -- A. Cooper +%% +How do you explain school to a higher intelligence? + -- Elliot, "E.T." +%% +How doth the VAX's C-compiler + Improve its object code. +And even as we speak does it + Increase the system load. + +How patiently it seems to run + And spit out error flags, +While users, with frustration, all + Tear their clothes to rags. +%% +How doth the little crocodile + Improve his shining tail, +And pour the waters of the Nile + On every golden scale! + +How cheerfully he seems to grin, + How neatly spreads his claws, +And welcomes little fishes in, + With gently smiling jaws! +%% +How kind of you to want to live someone's life for them. +%% +How long a minute is depends on which +side of the bathroom door you're on. +%% +How many "coming men" has one known! +Where on earth do they all go to? +%% +How many people work here? +Oh, about half. +%% +How many priests are needed for a Boston Mass? +%% +How many weeks are there in a light year? +%% +How much does she love you? +Less than you'll ever know. +%% +How much of their influence on you +is a result of your influence on them? +%% +How often I found where I should be going +only by setting out for somewhere else. + -- R. Buckminster Fuller +%% +How sharper than a hound's tooth it is to have a thankless serpent. +%% +How sharper than a serpent's tooth is a sister's "see?" + -- Linus Van Pelt +%% +How untasteful can you get? +%% +How wonderful opera would be if there were no singers. +%% +How you look depends on where you go. +%% +However, never daunted, I will cope with adversity +in my traditional manner... sulking and nausea. + -- Tom K. Ryan +%% +Hubbard's Law: + Don't take life too seriously; + you won't get out of it alive. +%% +Huh? +%% +Human beings were created by water to transport it uphill. +%% +Human cardiac catheterization was introduced by Werner Forssman in 1929. +Ignoring his department chief, and tying his assistant to an operating +table to prevent her interference, he placed a ureteral catheter into +a vein in his arm, advanced it to the right atrium [of his heart], and +walked upstairs to the x-ray department where he took the confirmatory +x-ray film. In 1956, Dr. Forssman was awarded the Nobel Prize. +%% +Human kind cannot bear very much reality. + -- T.S. Eliot, "Four Quartets: Burnt Norton" +%% +Human resources are human first, and resources second. + -- J. Garbers +%% +Humans are communications junkies. We just can't get enough. + -- Alan Kay +%% +Humility is the first of the virtues -- for other people. + -- Oliver Wendell Holmes +%% +Hummingbirds never remember the words to songs. +%% +Humor is a drug which it's the fashion to abuse. + -- William Gilbert +%% +Humpty Dumpty was pushed. +%% +Humpty Dumpty sat on the wall, +Humpty Dumpty had a great fall! +All the king's horses, +And all the king's men, +Had scrambled eggs for breakfast again! +%% +Hurewitz's Memory Principle: + The chance of forgetting something is directly proportional + to... to... uh..... +%% +I wish there was a knob on the TV to turn up the intelligence. +There's a knob called "brightness", but it doesn't seem to work. + -- Gallagher +%% +I B M +U B M +We all B M +For I B M!!!! + -- H.A.R.L.I.E. +%% +I accept chaos. I am not sure whether it accepts me. I know some people +are terrified of the bomb. But then some people are terrified to be seen +carrying a modern screen magazine. Experience teaches us that silence +terrifies people the most. + -- Bob Dylan +%% +I allow the world to live as it chooses, +and I allow myself to live as I choose. +%% +I always had a repulsive need to be something more than human. + -- David Bowie +%% +I always will remember-- I was in no mood to trifle; +'Twas a year ago November-- I got down my trusty rifle +I went out to shoot some deer And went out to stalk my prey-- +On a morning bright and clear. What a haul I made that day! +I went and shot the maximum I tied them to my bumper and +The game laws would allow: I drove them home somehow, +Two game wardens, seven hunters, Two game wardens, seven hunters, +And a cow. And a cow. + +The Law was very firm, it People ask me how I do it +Took away my permit-- And I say, "There's nothin' to it! +The worst punishment I ever endured. You just stand there lookin' cute, +It turns out there was a reason: And when something moves, you shoot." +Cows were out of season, and And there's ten stuffed heads +One of the hunters wasn't insured. In my trophy room right now: + Two game wardens, seven hunters, + And a pure-bred gurnsey cow. + -- Tom Lehrer, "The Hunting Song" +%% +I am NOMAD! +%% +I am a computer. +I am dumber than any human and smarter than any administrator. +%% +I am a conscientious man, when I throw +rocks at seabirds I leave no tern unstoned. + -- Ogden Nash, "Everybody's Mind to Me a Kingdom Is" +%% +I am a man: nothing human is alien to me. + -- Publius Terentius Afer (Terence) +%% +I am an optimist. It does not seem too much use being anything else. + -- Winston Churchill +%% +I am convinced that the truest act of courage is to sacrifice ourselves +for others in a totally nonviolent struggle for justice. To be a man +is to suffer for others. + -- Cesar Chavez +%% +I am, in point of fact, a particularly haughty and exclusive person, of +pre-Adamite ancestral descent. You will understand this when I tell you +that I can trace my ancestry back to a protoplasmal primordial atomic +globule. Consequently, my family pride is something inconceivable. I +can't help it. I was born sneering. + -- Pooh-Bah, "The Mikado" +%% +I am looking for a honest man. + -- Diogenes the Cynic +%% +I am not a crook. + -- Richard Nixon +%% +I am not a politician and my other habits are also good. + -- A. Ward +%% +I am not afraid of tomorrow, for I have seen yesterday and I love today. + -- William Allen White +%% +I am not an Economist. I am an honest man! + -- Paul McCracken +%% +I am not now and never have been a girl friend of Henry Kissinger. + -- Gloria Steinem +%% +I am professionally trained in computer science, which is to say +(in all seriousness) that I am extremely poorly educated. + -- Joseph Weizenbaum, "Computer Power and Human Reason" +%% +I am ready to meet my Maker. Whether my Maker is prepared +for the great ordeal of meeting me is another matter. + -- W. Churchill +%% +I am the wandering glitch -- catch me if you can. +%% +I am two fools, I know, for loving, and for saying so. + -- John Donne +%% +I am very fond of the company of ladies. I like their beauty, +I like their delicacy, I like their vivacity, and I like their silence. + -- Johnson +%% +I asked the engineer who designed the communication terminal's keyboards +why these were not manufactured in a central facility, in view of the +small number needed [1 per month] in his factory. He explained that this +would be contrary to the political concept of local self-sufficiency. +Therefore, each factory needing keyboards, no matter how few, manufactures +them completely, even molding the keypads. + -- Isaac Auerbach, IEEE "Computer", Nov. 1979 +%% +I began many years ago, as so many young men do, in searching for the +perfect woman. I believed that if I looked long enough, and hard enough, +I would find her and then I would be secure for life. Well, the years +and romances came and went, and I eventually ended up settling for someone +a lot less than my idea of perfection. But one day, after many years +together, I lay there on our bed recovering from a slight illness. My +wife was sitting on a chair next to the bed, humming softly and watching +the late afternoon sun filtering through the trees. The only sounds to +be heard elsewhere were the clock ticking, the kettle downstairs starting +to boil, and an occasional schoolchild passing beneath our window. And +as I looked up into my wife's now wrinkled face, but still warm and +twinkling eyes, I realized something about perfection... It comes only +with time. + -- James L. Collymore, "Perfect Woman" +%% +I believe a little incompatibility is the spice of life, +particularly if he has income and she is pattable. + -- Ogden Nash +%% +I believe in getting into hot water; it keeps you clean. + -- G.K. Chesterton +%% +I belong to no organized party. I am a Democrat. + -- Will Rogers +%% +I bet the human brain is a kludge. + -- Marvin Minsky +%% +I call Christianity the one great curse, the one enormous and innermost +perversion, the one great instinct of revenge, for which no means are +too venomous, too underhand, too underground and too petty -- I call it +the one immortal blemish of mankind. + -- Fredrich Nietzsche +%% +I came, I saw, I deleted all your files. +%% +I came out of twelve years of college and I didn't even know how to sew. +All I could do was account -- I couldn't even account for myself. + -- Firesign Theatre +%% +I came to MIT to get an education for myself and a diploma for my mother. +%% +I can relate to that. +%% +I can resist anything but temptation. +%% +I can see him a'comin' +With his big boots on, +With his big thumb out, +He wants to get me. +He wants to hurt me. +He wants to bring me down. +But some time later, +When I feel a little straighter, +I'll come across a stranger +Who'll remind me of the danger, +And then.... I'll run him over. +Pretty smart on my part! +To find my way... In the dark! + -- Phil Ochs +%% +I can write better than anybody who can write faster, +and I can write faster than anybody who can write better. + -- A.J. Liebling +%% +I cannot and will not cut my conscience to fit this year's fashions. + -- Lillian Hellman +%% +I cannot believe that God plays dice with the cosmos. + -- Albert Einstein, on the randomness of quantum mechanics +%% +I cannot draw a cart, nor eat dried oats; +If it be man's work I will do it. +%% + I cannot read the fiery letters, said Frodo in a quavering voice. + No, said Gandalf, but I can. The letters are Elvish, of course, of +an ancient mode, but the language is that of Mordor, which I will not utter +here. They are lines of a verse long known in Elven-lore: + + This Ring, no other, is made by the elves, + Who'd pawn their own mother to grab it themselves. + Ruler of creeper, mortal, and scallop, + This is a sleeper that packs quite a wallop. + The Power almighty rests in this Lone Ring. + The Power, alrighty, for doing your Own Thing. + If broken or busted, it cannot be remade. + If found, send to Sorhed (with postage prepaid). + + -- National Lampoon, "Bored of the Rings" +%% +I can't complain, but sometimes I still do. + -- Joe Walsh +%% +I can't stand squealers; hit that guy. + -- Albert Anastasia +%% +I can't understand it. +I can't even understand the people who can understand it. + -- Queen Juliana of the Netherlands. +%% +I consider the day misspent that I am not +either charged with a crime or arrested for one. + -- "Ratsy" Tourbillon +%% +I could never learn to like her -- +except on a raft at sea with no other provisions in sight. + -- Mark Twain +%% +I couldn't possibly fail to disagree with you less. +%% +I despise the pleasure of pleasing people whom I despise. +%% + I did some heavy research so as to be prepared for "Mommy, why is +the sky blue?" + HE asked me about black holes in space. + (There's a hole *where*?) + + I boned up to be ready for, "Why is the grass green?" + HE wanted to discuss nature's food chains. + (Well, let's see, there's ShopRite, Pathmark...) + + I talked about Choo-Choo trains. + HE talked internal combustion engines. + (The INTERNAL COMBUSTION ENGINE said, "I think I can, I think I can.") + + I was delighted with the video game craze, thinking we could compete +as equals. + HE described the complexities of the microchips required to create +the graphics. + + Then puberty struck. Ah, adolescence. + HE said, "Mom, I just don't understand women." + (Gotcha!) + -- Betty LiBrizzi, "The Care and Feeding of a Gifted Child" +%% +I didn't get sophisticated -- I just got tired. +But maybe that's what sophisticated is -- being tired. + -- Rita Gain +%% +I disagree with what you say, but will defend +to the death your right to tell such LIES! +%% +I do desire we may be better strangers. + -- William Shakespeare, "As You Like It" +%% +I do enjoy a good long walk -- especially when my wife takes one. +%% +I do not care if half the league strikes. Those who do will encounter +quick retribution. All will be suspended, and I don't care if it wrecks +the National League for five years. This is the United States of America +and one citizen has as much right to play as another. + -- Ford Frick, National League President, reacting to a + threatened strike by some Cardinal players in 1947 if + Jackie Robinson took the field against St. Louis. The + Cardinals backed down and played. +%% +I do not fear computers. I fear the lack of them. + -- Isaac Asimov +%% +I do not feel obliged to believe that the same God who has endowed us with +sense, reason, and intellect has intended us to forgo their use. + -- Galileo Galilei +%% +I do not know myself and God forbid that I should. + -- Johann Wolfgang von Goethe +%% +I do not know where to find in any literature, whether ancient or modern, +any adequate account of that nature with which I am acquainted. Mythology +comes nearest to it of any. + -- Henry David Thoreau +%% +I do not know whether I was then a man dreaming I was a +butterfly, or whether I am now a butterfly dreaming I am a man. + -- Chuang-tzu +%% +I do not seek the ignorant; the ignorant seek me -- I will instruct them. +I ask nothing but sincerity. If they come out of habit, they become +tiresome. + -- I Ching +%% +I do not take drugs -- I am drugs. + -- Salvador Dali +%% +I don't care what star you're following, +get that camel off my front lawn. + -- Heard in Bethlehem +%% +I don't drink, I don't like it, it makes me feel too good. + -- K. Coates +%% +I don't get no respect. +%% +I don't have any solution but I certainly admire the problem. + -- Ashleigh Brilliant +%% +I don't know what Descartes' got, +But booze can do what Kant cannot. + -- Mike Cross +%% + "I don't know what you mean by 'glory'," Alice said. + Humpty Dumpty smiled contemptuously. "Of course you don't -- +till I tell you. I meant 'there's a nice knock-down argument for you!'" + "But glory doesn't mean 'a nice knock-down argument'," Alice +objected. + "When I use a word," Humpty Dumpty said, in a rather scornful +tone, "it means just what I choose it to mean -- neither more nor less." + "The question is," said Alice, "whether you can make words mean +so many different things." + "The question is," said Humpty Dumpty, "which is to be master -- +that's all." +%% +I don't know who my grandfather was; I am much +more concerned to know what his grandson will be. + -- Abraham Lincoln +%% +I don't know why *anyone* would want a computer in their home. + -- Ken Olson, president of DEC, 1974 +%% +I don't know why we're here, I say we all go home and free associate. +%% +I don't like spinach, and I'm glad I don't, +because if I liked it I'd eat it, and I'd just hate it. + -- Clarence Darrow +%% +I don't love you, asshole, I love your daughter. + -- The Undergraduate +%% +I don't make the rules, Gil, I only play the game. + -- Cash McCall +%% +I don't need no arms around me... +I don't need no drugs to calm me... +I have seen the writing on the wall. +Don't think I need anything at all. +No! Don't think I need anything at all! +All in all, it was all just bricks in the wall. +All in all, it was all just bricks in the wall. + -- Pink Floyd, "Another Brick in the Wall", Part III +%% +I don't remember it, but I have it written down. +%% +I don't see what's wrong with giving Bobby a +little experience before he starts to practice law. + -- John F. Kennedy, upon appointing his brother + Attorney-General. +%% +I don't understand you anymore. +%% +I don't wanna argue, and I don't wanna fight, +But there will definitely be a party tonight... +%% +I don't want a pickle, +I just wanna ride on my motorcycle. +And I don't want to die, +I just want to ride on my motorcycle. + -- Arlo Guthrie +%% +I don't want people to love me. It makes for obligations. + -- Jean Anouilh +%% +I don't want to bore you, but there's nobody else around for me to bore. +%% +I don't wish to appear overly inquisitive, but are you still alive? +%% +I dote on his very absence. + -- William Shakespeare, "The Merchant of Venice" +%% +I dread success. To have succeeded is to have finished one's business on +earth, like the male spider, who is killed by the female the moment he has +succeeded in his courtship. I like a state of continual becoming, with a +goal in front and not behind. + -- George Bernard Shaw +%% +I dream of things that aren't and ask "why not?" +%% +I drink to make other people interesting. + -- George Jean Nathan +%% +I enjoy the time that we spend together. +%% +I exist, therefore I am paid. +%% +I fear explanations explanatory of things explained. +%% +I fell asleep reading a dull book, +and I dreamt that I was reading on, +so I woke up from sheer boredom. +%% + I for one cannot protest the recent M.T.A. fare hike and the +accompanying promises that this would in no way improve service. For +the transit system, as it now operates, has hidden advantages that +can't be measured in monetary terms. + Personally, I feel that it is well worth 75 cents or even $1 to +have that unimpeachable excuse whenever I am late to anything: "I came +by subway." Those four words have such magic in them that if Godot +should someday show up and mumble them, any audience would instantly +understand his long delay. +%% +I found Rome a city of bricks and left it a city of marble. + -- Augustus Caesar +%% +I generally avoid temptation unless I can't resist it. + -- Mae West +%% +I get up each morning, gather my wits. +Pick up the paper, read the obits. +If I'm not there I know I'm not dead. +So I eat a good breakfast and go back to bed. + +Oh, how do I know my youth is all spent? +My get-up-and-go has got-up-and-went. +But in spite of it all, I'm able to grin, +And think of the places my get-up has been. + -- Pete Seeger +%% +I give you the man who -- the man who -- uh, I forgets the man who? + -- Beauregard Bugleboy +%% +I go the way that Providence dictates. + -- Adolf Hitler +%% +I got vision, and the rest of the world wears bifocals. + -- Butch Cassidy +%% +I grew up in an Italian family, you know, the +strange thing about Italians -- they're so Jewish. + -- Kay Ballard +%% +I guess I've been so wrapped up in playing the game that I never took +time enough to figure out where the goal line was -- what it meant to +win -- or even how you won. + -- Cash McCall +%% +I guess I've been wrong all my life, but so have billions of +other people... Certainty is just an emotion. + -- Hal Clement +%% +I guess the Little League is even littler than we thought. + -- D. Cavett +%% +I had a dream last night... +I dreamt about 1976. +I dreamt about a country with incurable brain damage... +I even dreamt they gave it a heart transplant. +Then I woke up and I knew it was only a nightmare... +so I went back to sleep again. + -- Ralph Steadman, "Fear and Loathing '72" +%% +I had a feeling once about mathematics -- that I saw it all. Depth beyond +depth was revealed to me -- the Byss and the Abyss. I saw -- as one might +see the transit of Venus or even the Lord Mayor's Show -- a quantity passing +through infinity and changing its sign from plus to minus. I saw exactly +why it happened and why tergiversation was inevitable -- but it was after +dinner and I let it go. + -- Winston Churchill +%% +I had a virgin once. I had to go to Florida for her. She was twelve +years old, blind in one eye, and carried a stuffed alligator labeled +"Made in Taiwan". + -- The Stunt Man +%% +I had the rare misfortune of being one of the first people +to try and implement a PL/1 compiler. + -- T. Cheatham +%% +I hate dying. + -- Dave Johnson +%% +I hate quotations. + -- Ralph Waldo Emerson +%% +I have a hard time being attracted to anyone who can beat me up. + -- John McGrath, Atlanta sportswriter on women weightlifters. +%% +I have a little shadow that goes in and out with me, +And what can be the use of him is more than I can see. +He is very, very like me from the heels up to the head; +And I see him jump before me, when I jump into my bed. + +The funniest thing about him is the way he likes to grow-- +Not at all like proper children, which is always very slow; +For he sometimes shoots up taller, like an india-rubber ball, +And he sometimes gets so little that there's none of him at all. + -- R.L. Stevenson +%% +I have a theory that it's impossible to +prove anything, but I can't prove it. +%% +I have a very small mind and must live with it. + -- E. Dijkstra +%% +I have a very strange feeling about this... + -- Luke Skywalker +%% +I have always noticed that whenever a radical takes +to Imperialism, he catches it in a very acute form. + -- Winston Churchill, 1903 +%% +I have become me without my consent. +%% +I have defined the hundred per cent American +as ninety-nine per cent an idiot. + -- George Bernard Shaw +%% +I have discovered the art of deceiving diplomats. +I tell them the truth and they never believe me. + -- Camillo Di Cavour +%% +I have found it impossible to carry the heavy burden of responsibility and +to discharge my duties as king as I would wish to do without the help and +support of the woman I love. + -- Edward, Duke of Windsor, 1936, announcing his abdication + of the British throne in order to marry the American divorcee + Wallis Warfield Simpson. +%% +I have gained this by philosophy: +that I do without being commanded what others +do only from fear of the law. + -- Aristotle +%% +I have hardly ever known a mathematician who was capable of reasoning. + -- Plato +%% +I have just had eighteen whiskeys in a row. +I do believe that is a record. + -- Dylan Thomas, his last words. +%% +I have learned silence from the talkative, +toleration from the intolerant, and kindness from the unkind. + -- Kahlil Gibran +%% +I have lots of things in my pockets; +None of them is worth anything. +Sociopolitical whines aside, +Gan you give me, gratis, free, +The price of half a gallon +Of Gallo extra bad +And most of the bus fare home. +%% +I have made mistakes but I have never made the +mistake of claiming that I have never made one. + -- James Gordon Bennett +%% +I have made this letter longer than usual +because I lack the time to make it shorter. + -- Blaise Pascal +%% +I have never been one to sacrifice +my appetite on the altar of appearance. + -- A.M. Readyhough +%% +I have never let my schooling interfere with my education. + -- Mark Twain +%% +I have no doubt the Devil grins, +As seas of ink I spatter. +Ye gods, forgive my "literary" sins-- +The other kind don't matter. + -- Robert W. Service +%% +I have no right, by anything I do or say, to demean a human being in his +own eyes. What matters is not what I think of him; it is what he thinks +of himself. To undermine a man's self-respect is a sin. + -- Antoine de Saint-Exupery +%% +I have not yet begun to byte! +%% +I have nothing but utter contempt for the courts of this land. + -- George Wallace +%% +I have now come to the conclusion never again to think of marrying, +and for this reason: I can never be satisfied with anyone who would +be blockhead enough to have me. + -- Abraham Lincoln +%% +I have often regretted my speech, never my silence. + -- Publilius Syrus +%% +I have seen the future and it is just like the present, only longer. + -- Kehlog Albran +%% +I have that old biological urge, +I have that old irresistible surge, +I'm hungry. +%% +I have the simplest tastes. I am always satisfied with the best. + -- Oscar Wilde +%% +I have ways of making money that you know nothing of. + -- John D. Rockefeller +%% +I haven't lost my mind -- it's backed up on tape somewhere. +%% +I hear the sound that the machines make, +and feel my heart break, just for a moment. +%% +I hear what you're saying but I just don't care. +%% +I heard there was a lot of sex on television these days, +but when I tried it I kept falling off. +%% +I hold it, that a little rebellion, now and then, is a good thing... + -- Thomas Jefferson +%% +I hold your hand in mine, dear, I press it to my lips, +I take a healthy bite from your dainty fingertips, +My joy would be complete, dear, if you were only here, +But still I keep your hand as a precious souvenir. + +The night you died I cut it off, I really don't know why, +For now each time I kiss it I get bloodstains on my tie, +I'm sorry now I killed you, our love was something fine, +So until they come to get me I will hold your hand in mine. + + -- Tom Lehrer, "I Hold Your Hand In Mine" +%% +I just asked myself... what would John DeLorean do? + -- Raoul Duke +%% +I just need enough to tide me over until I need more. + -- Bill Hoest +%% +I knew Leo G. Carrol +Was over a barrel +When Tarantula took to the hills. ["Lick it!"] +And I really got hot +When I saw Jeanette Scott +Fight a triffid that spits poison and kills. + +Science fiction, double feature +Doctor X will build a creature. +See androids fighting Brad and Janet +Anne Francis stars in Forbidden Planet +Oh Oh Oh Oh Oh +At the late night, double feature, picture show. + -- The Rocky Horror Picture Show +%% +I know if you been talkin' you done said +just how suprised you wuz by the living dead. +You wuz suprised that they could understand you words +and never respond once to all the truth they heard. +But don't you get square! +There ain't no rule that says they got to care. +They can always swear they're deaf, dumb and blind. +%% +I know not how I came into this, +shall I call it a dying life or a living death? + -- St. Augustine +%% +I know not with what weapons World War III will be fought, but +World War IV will be fought with sticks and stones. + -- Albert Einstein +%% +I know on which side my bread is buttered. + -- John Heywood +%% +I know the disposition of women: when you will, they won't; when +you won't, they set their hearts upon you of their own inclination. + -- Publius Terentius Afer (Terence) +%% +I know what you're thinking. Did he fire six shots or only five? Well, to +tell you the truth, I forgot myself in all this excitement. But bein' this +is a .44 Magnum, the most powerful handgun in the world, and it could blow +your head clean off, you have to ask yourself one question: `Do I feel lucky?' +Well, do you, punk? + -- Dirty Harry +%% +I know you believe you understand what you think this fortune says, +but I'm not sure you realize that what you are reading is not what +it means. +%% +I know you think you thought you knew what you thought I said, +but I'm not sure you understood what you thought I meant. +%% +I know you're in search of yourself, I just haven't seen you anywhere. +%% +I lately lost a preposition; +It hid, I thought, beneath my chair +And angrily I cried, "Perdition! +Up from out of under there." + +Correctness is my vade mecum, +And straggling phrases I abhor, +And yet I wondered, "What should he come +Up from out of under for?" + -- Morris Bishop +%% +I like being single. I'm always there when I need me. + -- Art Leo +%% +I like myself, but I won't say I'm as +handsome as the bull that kidnapped Europa. + -- Marcus Tullius Cicero +%% +I like work; it fascinates me; +I can sit and look at it for hours. +%% +I live the way I type; fast, with a lot of mistakes. +%% +I look at life as being cruise director on the Titanic. +I may not get there, but I'm going first class. + -- Art Buchwald +%% +I love mankind ... It's people I hate. + -- Schulz +%% +I love the smell of napalm in the morning. + -- Robert Duval, "Apocalypse Now" +%% +I love treason but hate a traitor. + -- Gaius Julius Caesar +%% +I love you, not only for what you are, +but for what I am when I am with you. + -- Roy Croft +%% +I married beneath me. All women do. + -- Nancy, Lady Astor +%% +I may be getting older, but I refuse to grow up! +%% +I may not be totally perfect, but parts of me are excellent. + -- Ashleigh Brilliant +%% +I must Create a System, or be enslav'd by another Man's; +I will not Reason and Compare; my business is to Create. + -- William Blake, "Jerusalem" +%% +I must get out of these wet clothes and into a dry Martini. + -- Alexander Woolcott +%% +I must have slipped a disk; my pack hurts. +%% +I myself have dreamed up a structure intermediate between Dyson spheres +and planets. Build a ring 93 million miles in radius -- one Earth orbit +-- around the sun. If we have the mass of Jupiter to work with, and if +we make it a thousand miles wide, we get a thickness of about a thousand +feet for the base. + +And it has advantages. The Ringworld will be much sturdier than a Dyson +sphere. We can spin it on its axis for gravity. A rotation speed of 770 +m/s will give us a gravity of one Earth normal. We wouldn't even need to +roof it over. Place walls one thousand miles high at each edge, facing the +sun. Very little air will leak over the edges. + +Lord knows the thing is roomy enough. With three million times the surface +area of the Earth, it will be some time before anyone complains of the +crowding. + -- Larry Niven, "Ringworld" +%% +I need another lawyer like I need another hole in my head. + -- Fratianno +%% +I needed the good will of the legislature of four states. +I formed the legislative bodies with my own money. I found +that it was cheaper that way. + -- Jay Gould +%% +I never cheated an honest man, only rascals. They wanted +something for nothing. I gave them nothing for something. + -- Joseph "Yellow Kid" Weil +%% +I never did it that way before. +%% +I never fail to convince an audience +that the best thing they could do was to go away. +%% +I never forget a face, but in your case I'll make an exception. + -- Groucho Marx +%% +I never killed a man that didn't deserve it. + -- Mickey Cohen +%% +I never made a mistake in my life. +I thought I did once, but I was wrong. + -- Lucy Van Pelt +%% +I never pray before meals -- my mom's a good cook. +%% +I never refuse. I never contradict. I sometimes forget. + -- Benjamin Disraeli +%% +I never said all Democrats were saloonkeepers; +what I said was all saloonkeepers were Democrats. +%% +I never saw a purple cow +I never hope to see one +But I can tell you anyhow +I'd rather see than be one. + -- Gellett Burgess + +I've never seen a purple cow +I never hope to see one +But from the milk we're getting now +There certainly must be one + -- Odgen Nash + +Ah, yes, I wrote "The Purple Cow" +I'm sorry now I wrote it +But I can tell you anyhow +I'll kill you if you quote it. + -- Gellett Burgess +%% +I only know what I read in the papers. + -- Will Rogers +%% +I opened the drawer of my little desk and a single letter fell out, a +letter from my mother, written in pencil, one of her last, with unfinished +words and an implicit sense of her departure. It's so curious: one can +resist tears and "behave" very well in the hardest hours of grief. But +then someone makes you a friendly sign behind a window... or one notices +that a flower that was in bud only yesterday has suddenly blossomed... or +a letter slips from a drawer... and everything collapses. + -- Letters From Colette +%% +I owe, I owe, it's off to work I go... +%% +I owe the public nothing. + -- J.P. Morgan +%% +I prefer the most unjust peace to the most righteous war. + -- Cicero +Even peace may be purchased at too high a price. + -- Poor Richard +%% +I profoundly believe it takes a lot of practice to become a moral slob. + -- William F. Buckley +%% +I put up my thumb... and it blotted out the planet Earth. + -- Neil Armstrong +%% +I quite agree with you, said the Duchess; and the moral of +that is -- 'Be what you would seem to be' -- or, if you'd like it put +more simply -- 'Never imagine yourself not to be otherwise than what it +might appear to others that what you were or might have been was not +otherwise than what you had been would have appeared to them to be +otherwise.' +%% +I read Playboy for the same reason I read National Geographic. +To see the sights I'm never going to visit. +%% +I really hate this damned machine +I wish that they would sell it. +It never does quite what I want +But only what I tell it. +%% +I really look with commiseration over the great body of my fellow citizens +who, reading newspapers, live and die in the belief that they have known +something of what has been passing in their time. + -- H. Truman +%% +I recognize terror as the finest emotion and so I will try to terrorize the +reader. But if I find that I cannot terrify, I will try to horrify, and if +I find that I cannot horrify, I'll go for the gross-out. + -- Stephen King +%% +I refuse to have a battle of wits with an unarmed person. +%% +I remember Ulysses well... Left one day for the post office +to mail a letter, met a blonde named Circe on the streetcar, +and didn't come back for 20 years. +%% +I remember once being on a station platform in Cleveland at four in the +morning. A black porter was carrying my bags, and as we were waiting for +the train to come in, he said to me: "Excuse me, Mr. Cooke, I don't want to +invade your privacy, but I have a bet with a friend of mine. Who composed +the opening theme music of 'Omnibus'? My friend said Virgil Thomson." I +asked him, "What do you say?" He replied, "I say Aaron Copeland." I said, +"You're right." The porter said, "I knew Thomson doesn't write counterpoint +that way." I told that to a network president, and he was deeply unimpressed. + -- Alistair Cooke +%% +I respect the institution of marriage -- I have +always thought that every woman should marry, and no man. + -- Disraeli +%% +I reverently believe that the maker who made us all makes everything in New +England, but the weather. I don't know who makes that, but I think it must be +raw apprentices in the weather-clerks factory who experiment and learn how, in +New England, for board and clothes, and then are promoted to make weather for +countries that require a good article, and will take their custom elsewhere +if they don't get it. + -- Mark Twain +%% +I sat down beside her, said hello, offered to buy her a drink... +and then natural selection reared its ugly head. +%% +I saw a man pursuing the Horizon, +'Round and round they sped. +I was disturbed at this, +I accosted the man, +"It is futile," I said. +"You can never--" +"You lie!" He cried, +and ran on. + -- Stephen Crane +%% +I saw what you did and I know who you are. +%% +I say, and without apology, hang the bitch. +%% +I see a bad moon rising. +I see trouble on the way. +I see earthquakes and lightnin' +I see bad times today. +Don't go 'round tonight, +It's bound to take your life. +There's a bad moon on the rise. + -- J. C. Fogerty, "Bad Moon Rising" +%% +I sent a letter to the fish, I said it very loud and clear, +I told them, "This is what I wish." I went and shouted in his ear. +The little fishes of the sea, But he was very stiff and proud, +They sent an answer back to me. He said "You needn't shout so loud." +The little fishes' answer was And he was very proud and stiff, +"We cannot do it, sir, because..." He said "I'll go and wake them if..." +I sent a letter back to say I took a kettle from the shelf, +It would be better to obey. I went to wake them up myself. +But someone came to me and said But when I found the door was locked +"The little fishes are in bed." I pulled and pushed and kicked and + knocked, +I said to him, and I said it plain And when I found the door was shut, +"Then you must wake them up again." I tried to turn the handle, But... + + "Is that all?" asked Alice. + "That is all." said Humpty Dumpty. "Goodbye." +%% +I sent a message to another time, +But as the days unwind -- this I just can't believe, +I sent a message to another plane, +Maybe it's all a game -- but this I just can't conceive. +... +I met someone who looks at lot like you, +She does the things you do, but she is an IBM. +She's only programmed to be very nice, +But she's as cold as ice, whenever I get too near, +She tells me that she likes me very much, +But when I try to touch, she makes it all too clear. +... +I realize that it must seem so strange, +That time has rearranged, but time has the final word, +She knows I think of you, she reads my mind, +She tries to be unkind, she knows nothing of our world. + -- ELO, "Yours Truly, 2095" +%% +I smell a wumpus. +%% +I sold my memoirs of my love life to Parker +Brothers and they are going to make a game out of it. + -- Woody Allen +%% +I stick my neck out for nobody. + -- Humphrey Bogart, "Casablanca" +%% +I stood on the leading edge, +The eastern seaboard at my feet. +"Jump!" said Yoko Ono +I'm too scared and good-looking, I cried. +Go on and give it a try, +Why prolong the agony, all men must die. + -- Roger Waters, "The Pros and Cons of Hitchhiking" +%% +I suggest a new stategy, Artoo: let the Wookiee win. + -- CP30 +%% +I suppose I could collect my books and get on back to school, +Or steal my daddy's cue and make a living out of playing pool, +Or find myself a rock 'n' roll band, +That needs a helping hand, +Oh, Maggie I wish I'd never seen your face. + -- Rod Stewart, "Maggie May" +%% +I suppose that in a few hours I will sober up. That's such a sad +thought. I think I'll have a few more drinks to prepare myself. +%% +I tell ya, I knew my morning wasn't going right. When I put on my shirt +the button fell off, when I picked up my briefcase, the handle fell off, +I tell ya, I was afraid to go to the bathroom. + -- Rodney Dangerfield +%% +I tell ya, I was an ugly kid. I was so ugly that my dad +kept the kid's picture that came with the wallet he bought. + -- Rodney Dangerfield +%% +I think I'll snatch a kiss and flee. + -- Shakespeare +%% +I think every good Christian ought to kick Falwell right in the ass. + -- Barry Goldwater +%% +I think that I shall never see +A billboard lovely as a tree. +Indeed, unless the billboards fall +I'll never see a tree at all. + -- Nash +%% +I think the Mormon prophet +Was a very funny man. +I wonder how his wives enjoyed +His Prophet Sharing Plan. +%% +I think, therefore I am... I think. +%% +I think we are in Rats Alley where the dead men lost their bones. + -- T.S. Eliot +%% +I think we're all Bozos on this bus. + -- Firesign Theatre +%% +I think we're in trouble. + -- Han Solo +%% +I thought YOU silenced the guard! +%% +"I thought that you said you were 20 years old!" +"As a programmer, yes," she replied, +"And you claimed to be very near two meters tall!" +"You said you were blonde, but you lied!" +Oh, she was a hacker and he was one, too, +They had so much in common, you'd say. +They exchanged jokes and poems, and clever new hacks, +And prompts that were cute or risque'. +He sent her a picture of his brother Sam, +She sent one from some past high school day, +And it might have gone on for the rest of their lives, +If they hadn't met in L.A. +"Your beard is an armpit," she said in disgust. +He answered, "Your armpit's a beard!" +And they chorused: "I think I could stand all the rest +If you were not so totally weird!" +If she had not said what he wanted to hear, +And he had not done just the same, +They'd have been far more honest, and never have met, +And would not have had fun with the game. + -- Judith Schrier, "Face to Face After Six + Months of Electronic Mail" +%% +I told my kids, "Someday, you'll have kids of your own." +One of them said, "So will you." + -- Rodney Dangerfield +%% +I treasure this strange combination found in very few persons: a fierce +desire for life as well as a lucid perception of the ultimate futility of +the quest. + -- Madeleine Gobeil +%% +I try not to break the rules but merely to test their elasticity. + -- Bill Veeck +%% +I understand why you're confused. You're thinking too much. + -- Carole Wallach. +%% +I used to be Snow White, but I drifted. + -- Mae West +%% +I used to be a rebel in my youth. +This cause... that cause... (chuckle) I backed 'em ALL! But I learned. +Rebellion is simply a device used by the immature to hide from his own +problems. So I lost interest in politics. Now when I feel aroused by +a civil rights case or a passport hearing... I realize it's just a device. +I go to my analyst and we work it out. You have no idea how much better +I feel these days. + -- J. Feiffer +%% +I used to be disgusted, now I find I'm just amused. + -- Elvis Costello +%% +I used to be such a sweet sweet thing, 'til they got a hold of me, +I opened doors for little old ladies, I helped the blind to see, +I got no friends 'cause they read the papers, they can't be seen, +With me, and I'm feelin' real shot down, +And I'm, uh, feelin' mean, + No more, Mr. Nice Guy, + No more, Mr. Clean, + No more, Mr. Nice Guy, +They say "He's sick, he's obscene". + +My dog bit me on the leg today, my cat clawed my eyes, +Ma's been thrown out of the social circle, and Dad has to hide, +I went to church, incognito, when everybody rose, +The reverend Smithy, he recognized me, +And punched me in the nose, he said, +(chorus) +He said "You're sick, you're obscene". + -- Alice Cooper, "No More Mr. Nice Guy" +%% +I used to think I was indecisive, but now I'm not so sure. +%% +I waited and waited and when no message came I knew it must be from you. +%% +I want to achieve immortality through not dying. + -- Woody Allen +%% +I want to reach your mind -- where is it currently located? +%% +I was eatin' some chop suey, +With a lady in St. Louie, +When there sudden comes a knockin' at the door. +And that knocker, he says, "Honey, +Roll this rocker out some money, +Or your daddy shoots a baddie to the floor." + -- Mr. Miggle +%% +I was gratified to be able to answer promptly, and I did. +I said I didn't know. + -- Mark Twain +%% +I was in accord with the system so long as it +permitted me to function effectively. + -- Albert Speer +%% +I was working on a case. It had to be a case, because I couldn't afford a +desk. Then I saw her. This tall blond lady. She must have been tall +because I was on the third floor. She rolled her deep blue eyes towards +me. I picked them up and rolled them back. We kissed. She screamed. I +took the cigarette from my mouth and kissed her again. +%% +I wasted time and now doth time waste me. + -- William Shakespeare +%% + I went into a bar feeling a little depressed, the bartender said, +"What'll you have, bud"? + I said," I don't know, surprise me". + So he showed me a nude picture of my wife. + -- Rodney Dangerfield +%% +I went into the business for the money, and the art grew out of it. +If people are disillusioned by that remark, I can't help it. +It's the truth. + -- Charlie Chaplin +%% +I went over to my friend, he was eatin' a pickle. +I said "Hi, what's happenin'?" +He said "Nothin'." +Try to sing this song with that kind of enthusiasm; +As if you just squashed a cop. + -- Arlo Guthrie, "Motorcycle Song" +%% +I went to a wild party last night. I tell ya, it was so wild, we played +a new version of Russian roulette. We passed around six girls and one +of them had V.D. + -- Rodney Dangerfield +%% +I will always love the false image I had of you. +%% +I will follow the good side right to the fire, +but not into it if I can help it. + -- Michel Eyquem de Montaigne +%% +I will honour Christmas in my heart, and try to keep it all the +year. I will live in the Past, the Present, and the Future. The +Spirits of all Three shall strive within me. I will not shut out +the lessons that they teach. Oh, tell me that I may sponge away the +writing on this stone! + -- Charles Dickens +%% +I will make you shorter by the head. + -- Elizabeth I +%% +I will never lie to you. +%% +I will not forget you. +%% +I will not say that women have no character; +rather, they have a new one every day. + -- Heine +%% +I wish I was a fascinating lady +With a past that was cheap and a future that was shady +I'd sleep all day and I'd work all night +I'd live in a house with a little red light +And once a month I'd take a small vacation +And leave all the men to their imagination +And once in a while I'd go all wild +And have myself an illegitimate child +I wish I were a fascinating lady +Instead I'm the minister's child +%% +I wish that my room had a floor; +I don't so much care for a door, + But this walking around + Without touching the ground +Is getting to be quite a bore! + -- Gelett Burgess +%% +I wish you humans would leave me alone. +%% +I woke up a feelin' mean +went down to play the slot machine +the wheels turned round, +and the letters read +"Better head back to Tennessee Jed" + -- Grateful Dead +%% +I would be batting the big feller if they wasn't ready with the other one, +but a left-hander would be the thing if they wouldn't have knowed it already +because there is more things involved than could come up on the road, even +after we've been home a long while. + -- Casey Stengel +%% +I would gladly raise my voice in praise of women, +only they won't let me raise my voice. + -- Winkle +%% +I would have made a good pope. + -- Richard Nixon +%% +I would like the government to do all it can to mitigate, then, in +understanding, in mutuality of interest, in concern for the common good, +our tasks will be solved. + -- Warren G. Harding +%% +I would like to know +What I was fencing in +And what I was fencing out. + -- Robert Frost +%% +I would much rather have men ask why +I have no statue, than why I have one. + -- Marcus Procius Cato +%% +I would rather be a serf in a poor man's house +and be above ground than reign among the dead. + -- Achilles, "The Odessey", XI, 489-91 +%% +I wouldn't be so paranoid if you weren't all out to get me!! +%% +I wouldn't marry her with a ten foot pole. +%% +I wouldn't recommend sex, drugs or insanity +for everyone, but they've always worked for me. + -- Hunter S. Thompson +%% +IBM Advanced Systems Group -- a bunch of mindless jerks, +who'll be first against the wall when the revolution comes... + -- with regrets to D. Adams +%% +IBM had a PL/I, +Its syntax worse than JOSS; +And everywhere this language went, +It was a total loss. +%% +IBM: + I've Been Moved + Idiots Become Managers + Idiots Buy More + Impossible to Buy Machine + Incredibly Big Machine + Industry's Biggest Mistake + International Brotherhood of Mercenaries + It Boggles the Mind + It's Better Manually + Itty-Bitty Machines +%% +IBM's original motto: + Cogito ergo vendo; vendo ergo sum. +%% +IDIOT: + A member of a large and powerful tribe whose influence + in human affairs has always been dominant and controlling. +%% +IDLENESS: + Leisure gone to seed. +%% +IGNORANCE: + When you don't know anything, and someone else finds out. +%% +IMPARTIAL: + Unable to perceive any promise of personal advantage from + espousing either side of a controversy or adopting either of two + conflicting opinions. +%% +IN BOX: + A catch basin for everything you don't want + to deal with, but are afraid to throw away. +%% +INCENTIVE PROGRAM: + The system of long and short-term rewards that a corporation uses + to motivate its people. Still, despite all the experimentation with + profit sharing, stock options, and the like, the most effective + incentive program to date remains: + "Do a good job and you get to keep it." +%% +INCUMBENT: + Person of livliest interest to the outcumbents. +%% +INDEX: + Alphabetical list of words of no possible interest where an + alphabetical list of subjects with references ought to be. +%% +INGRATE: + A man who bites the hand that feeds him, + and then complains of indigestion. +%% +INK: + A villainous compound of tannogallate of iron, gum-arabic, + and water, chiefly used to facilitate the infection of + idiocy and promote intellectual crime. + -- H.L. Mencken +%% +INNOVATE: + Annoy people. +%% +INNUENDO: + Italian enema. +%% +INSECURITY: + Finding out that you've mispronounced for years + one of your favorite words. + + Realizing halfway through a joke that you are + telling it to the person who told it to you. +%% +INTEREST: + What borrowers pay, lenders receive, stockholders + own, and burned out employees must feign. +%% +INTERPRETER: + One who enables two persons of different languages to understand + each other by repeating to each what it would have been to the + interpreter's advantage for the other to have said. +%% +INTOXICATED: + When you feel sophisticated without being able to pronounce it. +%% +IOT trap -- core dumped +%% +IOT trap -- mos dumped +%% +IRONY: + A windy day, when, just as a beautiful girl with + a short skirt approaches, dust blows in your eyes. +%% +IT IS IN PROCESS: + So wrapped up in red tape that the situation is almost hopeless. +%% +Iam +not +very +happy +acting +pleased +whenever +prominent +scientists +overmagnify +intellectual +enlightenment +%% +I'd give my right arm to be ambidextrous. +%% +I'd just as soon kiss a Wookiee. + -- Princess Leia Organa +%% +I'd love to kiss you, but I just washed my hair. + -- Bette Davis, "Cabin in the Cotton" +%% +I'd never join any club that would have the likes of me as a member. + -- Groucho Marx +%% +I'd rather be led to hell than managed to heavan. +%% +I'd rather have a free bottle in front of me than a prefrontal lobotomy. + -- Fred Allen +%% +I'd rather have two girls at 21 each than one girl at 42. + -- W.C. Fields +%% +I'd rather just believe that it's done by little elves running around. +%% +I'd rather laugh with the sinners, +Than cry with the saints, +The sinners are much more fun! + -- Billy Joel, "Only The Good Die Young" +%% +I'd rather push my Harley than ride a rice burner. +%% +Identify your visitor. +%% +Idleness is the holiday of fools. +%% +If A = B and B = C, then A = C, except where void or prohibited by law. + -- Roy Santoro +%% +If A fool persists in his folly he shall become wise. + -- William Blake +%% +If Christianity was morality, Socrates would be the Saviour. + -- William Blake +%% +If God had intended Man to Smoke, He would have set him on Fire. +%% +If God had intended Man to Walk, He would have given him Feet. +%% +If God had intended Man to Watch TV, He would have given him Rabbit Ears. +%% +If God had intended Man to program, we'd be born with serial I/O ports. +%% +If God had intended Men to Smoke, He would have put Chimneys in their Heads. +%% +If God had meant for us to be in the Army, +we would have been born with green, baggy skin. +%% +If God had meant for us to be naked, we would have been born that way. +%% +If God had not given us sticky tape, +it would have been necessary to invent it. +%% +If God had wanted you to go around nude, +He would have given you bigger hands. +%% +If God is perfect, why did He create discontinuous functions? +%% +If God lived on Earth, people would knock out all His windows. + -- Yiddish saying +%% +If God wanted us to have a President, +He would have sent us a candidate. + -- Jerry Dreshfield +%% +If I cannot bend Heaven, I shall move Hell. + -- Publius Vergilius Maro (Virgil) +%% +If I could read your mind, love, +What a tale your thoughts could tell, +Just like a paperback novel, +The kind the drugstore sells, +When you reach the part where the heartaches come, +The hero would be me, +Heroes often fail, +You won't read that book again, because + the ending is just too hard to take. + +I walk away, like a movie star, +Who gets burned in a three way script, +Enter number two, +A movie queen to play the scene +Of bringing all the good things out in me, +But for now, love, let's be real +I never thought I could act this way, +And I've got to say that I just don't get it, +I don't know where we went wrong but the feeling is gone +And I just can't get it back... + -- Gordon Lightfoot, "If You Could Read My Mind" +%% +If I don't drive around the park, +I'm pretty sure to make my mark. +If I'm in bed each night by ten, +I may get back my looks again. +If I abstain from fun and such, +I'll probably amount to much; +But I shall stay the way I am, +Because I do not give a damn. + -- Dorothy Parker +%% +If I had a plantation in Georgia and a home in Hell, +I'd sell the plantation and go home. + -- Eugene P. Gallagher +%% +If I had any humility I would be perfect. + -- Ted Turner +%% +If I had only known, I would have been a locksmith. + -- Albert Einstein +%% +If I have not seen so far it is because I stood in giant's footsteps. +%% +If I have to lay an egg for my country, I'll do it. + -- Bob Hope +%% +If I kiss you, that is an psychological interaction. +On the other hand, if I hit you over the head with a brick, +that is also a psychological interaction. +The difference is that one is friendly and the other is not so friendly. +The crucial point is if you can tell which is which. +%% +If I knew what brand [of whiskey] he drinks, +I would send a barrel or so to my other generals. + -- Abraham Lincoln, on General Grant +%% +If I promised you the moon and the stars, would you believe it? + -- Alan Parsons Project +%% +If I told you you had a beautiful body, would you hold it against me? +%% +If I traveled to the end of the rainbow +As Dame Fortune did intend, +Murphy would be there to tell me +The pot's at the other end. + -- Bert Whitney +%% +If I want your opinion, I'll ask you to fill out the necessary form. +%% +If I'd known computer science was going to be like this, +I'd never have given up being a rock 'n' roll star. + -- G. Hirst +%% +If Jesus Christ were to come today, people would not even crucify him. +They would ask him to dinner, and hear what he had to say, and make +fun of it. + -- Thomas Carlyle +%% +If Karl, instead of writing a lot about Capital, +had made a lot of Capital, it would have been much better. + -- Karl Marx's Mother +%% +If a President doesn't do it to his wife, he'll do it to his country. +%% +If a group of N persons implements a COBOL compiler, +there will be N-1 passes. Someone in the group has to be the manager. + -- T. Cheatham +%% +If a listener nods his head when you're +explaining your program, wake him up. +%% +If a man has a strong faith he can indulge in the luxury of skepticism. + -- Friedrich Nietzsche +%% +If a man has talent and cannot use it, he has failed. + -- Thomas Wolfe +%% +If a man is not a liberal at 25, he has no heart. +If he's not a conservative by 45, he has no brain. +%% +If a man loses his reverence for any part of life, +he will lose his reverence for all of life. + -- Albert Schweitzer +%% +If a nation expects to be ignorant and free, +... it expects what never was and never will be. + -- Thomas Jefferson +%% +If a subordinate asks you a pertinent question, +look at him as if he had lost his senses. +When he looks down, paraphrase the question back at him. +%% +If a thing's worth doing, it is worth doing badly. + -- G.K. Chesterton +%% +If all be true that I do think, +There be five reasons why one should drink; +Good friends, good wine, or being dry, +Or lest we should be by-and-by, +Or any other reason why. +%% +If all else fails, immortality can always be assured by spectacular error. + -- John Kenneth Galbraith +%% +If all men were brothers, would you let one marry your sister? +%% +If all the world's a stage, I want to operate the trap door. + -- Paul Beatty +%% +If all the world's economists were laid end to end, +we wouldn't reach a conclusion. + -- William Baumol +%% +If an S and an I and an O and a U +With an X at the end spell Su; +And an E and a Y and an E spell I, +Pray what is a speller to do? +Then, if also an S and an I and a G +And an HED spell side, +There's nothing much left for a speller to do +But to go commit siouxeyesighed. + -- Charles Follen Adams, "An Orthographic Lament" +%% +If an experiment works, something has gone wrong. +%% +If any man wishes to be humbled and mortified, +let him become president of Harvard. + -- Edward Holyoke +%% +If anything can go wrong, it will. +%% +If at first you do succeed, try to hide your astonishment. +%% +If at first you don't succeed, quit; don't be a nut about success. +%% +If at first you don't succeed, redefine success. +%% +If at first you don't succeed, try, try again. +Then quit. No use being a damn fool about it. + -- W.C. Fields + [Also attributed to Roy Mengot. Ed.] +%% +If at first you don't succeed, try, try again. + -- W.E. Hickson +%% +If at first you don't succeed, you must be a programmer. +%% +If at first you don't succeed, you're doing about average. + -- Leonard Levinson +%% +If bankers can count, how come they have +eight windows and only four tellers? +%% +If builders built buildings the way programmers wrote programs, +then the first woodpecker to come along would destroy civilization. +%% +If continence causes neurosis +And intercourse causes thrombosis + I'd rather expire + Fulfilling desire +Than live in a state of psychosis. +%% +If dolphins are so smart, why did Flipper work for television? +%% +If everything on the road of life seems to +be coming your way, you're in the wrong lane. +%% +If everything seems to be going well, +you have obviously overlooked something. +%% +If food be the music of love, eat up, eat up. +%% +If graphics hackers are so smart, +why can't they get the bugs out of fresh paint? +%% +If happiness is in your destiny, you need not be in a hurry. + -- Chinese proverb +%% +If he had only learnt a little less, how +infinitely better he might have taught much more! +%% +If he once again pushes up his sleeves in order to compute for 3 days +and 3 nights in a row, he will spend a quarter of an hour before to +think which principles of computation shall be most appropriate. + -- Voltaire, "Diatribe du docteur Akakia" +%% +If he should ever change his faith, +it'll be because he no longer thinks he's God. +%% +If in doubt, mumble. +%% +If it ain't broke, don't fix it. +%% +If it doesn't smell yet, it's pretty fresh. + -- Dave Johnson, on dead seagulls +%% +If it happens once, it's a bug. +If it happens twice, it's a feature. +If it happens more than twice, it's a design philosophy. +%% +If it is a Miracle, any sort of evidence will +answer, but if it is a Fact, proof is necessary. + -- Samuel Clemens +%% +Stockmayer's Theorem: + If it looks easy, it's tough. + If it looks tough, it's damn well impossible. +%% +If it pours before seven, it has rained by eleven. +%% +If it wasn't for Newton, we wouldn't have to eat bruised apples. +%% +If it wasn't so warm out today, it would be cooler. +%% +If it's Tuesday, this must be someone else's fortune. +%% +If it's not in the computer, it doesn't exist. +%% +If it's worth doing, it's worth doing for money. +%% +If it's worth hacking on well, it's worth hacking on for money. +%% +If life gives you lemons, make lemonade. +%% +If life is a stage, I want some better lighting. +%% +If life is merely a joke, the question +still remains: for whose amusement? +%% +If life isn't what you wanted, have you asked for anything else? +%% +If love is the answer, could you rephrase the question? + -- Lily Tomlin +%% +If mathematically you end up with the wrong +answer, try multipying by the page number. +%% +If one cannot enjoy reading a book over and +over again, there is no use in reading it at all. + -- Oscar Wilde +%% +If one tells the truth, one is sure sooner or later to be found out. + -- Oscar Wilde +%% +If only Dionysus were alive! Where would he eat? + -- Woody Allen +%% +If only one could get that wonderful feeling of +accomplishment without having to accomplish anything. +%% +If only you could be respected without having to be respectable. +%% +If only you knew she loved you, you could +face the uncertainty of whether you love her. +%% +If opportunity came disguised as temptation, one knock would be enough. +%% +If parents would only realize how they bore their children. + -- G.B. Shaw +%% +If people drank ink instead of Schlitz, they'd be better off. + -- Edward E. Hippensteel + [What brand of ink? Ed.] +%% +If practice makes perfect, and nobody's perfect, why practice? +%% +If rabbits feet are so lucky, what happened to the rabbit? +%% +If reporters don't know that truth is plural, they ought to be lawyers. + -- Tom Wicker +%% +If researchers wrote nursery rhymes... + +Little Miss Muffet sat on her gluteal region, +Eating components of soured milk. +On at least one occasion, + along came an arachnid and sat down beside her, +Or at least in her vicinity, +And caused her to feel an overwhelming, but not paralyzing, fear, +Which motivated the patient to leave the area rather quickly. + -- Ann Melugin Williams +%% +If scientific reasoning were limited to the logical processes of +arithmetic, we should not get very far in our understanding of the physical +world. One might as well attempt to grasp the game of poker entirely by +the use of the mathematics of probability. + -- Vannevar Bush +%% +If she had not been cupric in her ions, +Her shape ovoidal, +Their romance might have flourished. +But he built tetrahedral in his shape, +His ions ferric, +Love could not help but die, +Uncatylised, inert, and undernourished. +%% +If some day it should happen that a victim must be found, +I've got a little list, I've got a little list. + -- Koko, "The Mikado" +%% +If some people didn't tell you, +you'd never know they'd been away on vacation. +%% +If someone had told me I would be Pope +one day, I would have studied harder. + -- Pope John Paul I +%% +If something has not yet gone wrong then it would +ultimately have been beneficial for it to go wrong. +%% +If the English language made any sense, lackadaisical +would have something to do with a shortage of flowers. + -- Doug Larson + [Not to mention, butterfly would be flutterby. Ed.] +%% +If the colleges were better, if they really had it, you would need to get +the police at the gates to keep order in the inrushing multitude. See in +college how we thwart the natural love of learning by leaving the natural +method of teaching what each wishes to learn, and insisting that you shall +learn what you have no taste or capacity for. The college, which should +be a place of delightful labor, is made odious and unhealthy, and the +young men are tempted to frivolous amusements to rally their jaded spirits. +I would have the studies elective. Scholarship is to be created not +by compulsion, but by awakening a pure interest in knowledge. The wise +instructor accomplishes this by opening to his pupils precisely the +attractions the study has for himself. The marking is a system for schools, +not for the college; for boys, not for men; and it is an ungracious work to +put on a professor. + -- Ralph Waldo Emerson +%% +If the future isn't what it used to be, does that +mean that the past is subject to change in times to come? +%% +If the girl you love moves in with another guy once, it's more than enough. +Twice, it's much too much. Three times, it's the story of your life. +%% +If the grass is greener on other side of fence, +consider what may be fertilizing it. +%% +If the master dies and the disciple grieves, +the lives of both have been wasted. +%% +If the meanings of "true" and "false" were switched, +then this sentence would not be false. +%% +If the odds are a million to one against something +occurring, chances are 50-50 it will. +%% +If the path be beautiful, let us not ask where it leads. + -- Anatole France +%% +If the rich could pay the poor to die for them, +what a living the poor could make! +%% +If the shoe fits, it's ugly. +%% +If the very old will remember, the very young will listen. + -- Chief Dan George +%% +If the weather is extremely bad, church attendance will be down. +If the weather is extremely good, church attendance will be down. +If the bulletin covers are in short supply, however, +church attendance will exceed all expectations. + -- Reverend Chichester +%% +If there are epigrams, there must be meta-epigrams. +%% +If there is a possibility of several things going wrong, +the one that will cause the most damage will be the one to go wrong. + +If you perceive that there are four possible ways in which a procedure +can go wrong, and circumvent these, then a fifth way will promptly develop. +%% +If there is a sin against life, it consists perhaps not so much in despairing +of life as in hoping for another life and in eluding the implacable grandeur +of this life. + -- Albert Camus +%% +If there is a wrong way to do something, then someone will do it. + -- Edward A. Murphy Jr. +%% +If there is no God, who pops up the next Kleenex? + -- Art Hoppe +%% +If there is no wind, row. + -- Polish proverb +%% +If they were so inclined, they could impeach +him because they don't like his necktie. + -- Attorney General William Saxbe +%% +If things don't improve soon, you'd better ask them to stop helping you. +%% +If this fortune didn't exist, somebody would have invented it. +%% +If this is timesharing, give me my share right now. +It's not time yet. +%% +If time heals all wounds, how come the belly button stays the same? +%% +If two men agree on everything, you may +be sure that one of them is doing the thinking. + -- L.B. Johnson +%% +If we all work together, we can totally disrupt the system. +%% +If we can ever make red tape nutritional, we can feed the world. + -- R. Schaeberle, "Management Accounting" +%% +If we do not change our direction we are +likely to end up where we are headed. +%% +If we don't survive, we don't do anything else. + -- John Sinclair +%% +If we spoke a different language, we +would perceive a somewhat different world. + -- Wittgenstein +%% +If we suffer tamely a lawless attack upon our liberty, +we encourage it, and involve others in our doom. + -- Samuel Adams +%% +If while you are in school, there is a shortage of qualified personnel +in a particular field, then by the time you graduate with the necessary +qualifications, that field's employment market is glutted. + -- Marguerite Emmons +%% +If wishes were horses, then beggars would be thieves. +%% +If women didn't exist, all the money in the world would have no meaning. + -- Aristotle Onassis +%% +If you MUST get married, it is always advisable to marry beauty. +Otherwise, you'll never find anybody to take her off your hands. +%% +If you always postpone pleasure you will never have it. +Quit work and play for once! +%% +If you analyse anything, you destroy it. + -- Arthur Miller +%% +If you are going to walk on thin ice, you may as well dance. +%% +If you are not for yourself, who will be for you? +If you are for yourself, then what are you? +If not now, when? +%% +If you are over 80 years old and accompanied +by your parents, we will cash your check. +%% +If you are smart enough to know that you're not +smart enough to be an Engineer, then you're in Business. +%% +If you are too busy to read, then you are too busy. +%% +If you are what you eat, does that mean Euelle Gibbons really was a nut? +%% +If you can count your money, you don't have a billion dollars. + -- J. Paul Getty +%% +If you can keep your head when all about you are losing +theirs, then you clearly don't understand the situation. +%% +If you can lead it to water and force it to drink, it isn't a horse. +%% +If you can survive death, you can probably survive anything. +%% +If you cannot convince them, confuse them. + -- Harry S. Truman +%% +If you can't be good, be careful. +If you can't be careful, give me a call. +%% +If you can't learn to do it well, learn to enjoy doing it badly. +%% +If you can't understand it, it is intuitively obvious. +%% +If you continually give you will continually have. +%% +If you could only get that wonderful feeling of +accomplishment without having to accomplish anything. +%% +If you didn't get caught, did you really do it? +%% +If you didn't have most of your friends, +you wouldn't have most of your problems. +%% +If you didn't have to work so hard, +you'd have more time to be depressed. +%% +If you do not think about the future, you cannot have one. + -- John Galsworthy +%% +If you do something right once, someone will ask you to do it again. +%% +If you don't care where you are, then you ain't lost. +%% +If you don't do it, you'll never know what +would have happened if you had done it. +%% +If you don't do the things that are not worth doing, who will? +%% +If you don't have the time right now, +will you have redo right time later? +%% +If you don't have time to do it right, where +are you going to find the time to do it over? +%% +If you don't know what game you're playing, don't ask what the score is. +%% +If you don't like the way I drive, stay off the sidewalk! +%% +If you don't say anything, you won't be called on to repeat it. + -- Calvin Coolidge +%% +If you don't strike oil in twenty minutes, stop boring. + -- Andrew Carnegie, on public speaking +%% +If you ever want to have a lot of fun, I recommend that you go off and program +an imbedded system. The salient characteristic of an imbedded system is that +it cannot be allowed to get into a state from which only direct intervention +will suffice to remove it. An imbedded system can't permanently trust anything +it hears from the outside world. It must sniff around, adapt, consider, sniff +around, and adapt again. I'm not talking about ordinary modular programming +carefulness here. No. Programming an imbedded system calls for undiluted +raging maniacal paranoia. For example, our ethernet front ends need to know +what network number they are on so that they can address and route PUPs +properly. How do you find out what your network number is? Easy, you ask a +gateway. Gateways are required by definition to know their correct network +numbers. Once you've got your network number, you start using it and before +you can blink you've got it wired into fifteen different sockets spread all +over creation. Now what happens when the panic-stricken operator realizes he +was running the wrong version of the gateway which was giving out the wrong +network number? Never supposed to happen. Tough. Supposing that your +software discovers that the gateway is now giving out a different network +number than before, what's it supposed to do about it? This is not discussed +in the protocol document. Never supposed to happen. Tough. I think you +get my drift. +%% +If you explain something so clearly that no +one can possibly misunderstand, someone will. +%% +If you float on instinct alone, how can you +calculate the buoyancy for the computed load? + -- Christopher Hodder-Williams +%% +If you fool around with something long +enough, it will eventually break. +%% +If you give Congress a chance to vote on +both sides of an issue, it will always do it. + -- Les Aspin, D, Wisconsin +%% +If you give a man enough rope, he'll claim he's tied up at the office. +%% +If you go on with this nuclear arms race, +all you are going to do is make the rubble bounce. + -- Winston Churchill +%% +If you go out of your mind, do it quietly, +so as not to disturb those around you. +%% +If you had better tools, you could more +effectively demonstrate your total incompetence. +%% +If you had just one moment to live +And they granted you one special wish +Would you ask for something +Like another chance. + -- Traffic, "The Low Spark of Hi Heeled Boys" +%% +If you hands are clean and your cause is just +and your demands are reasonable, at least it's a start. +%% +If you have a procedure with 10 parameters, you probably missed some. +%% +If you have nothing to do, don't do it here. +%% +If you have received a letter inviting you to speak at the dedication of a +new cat hospital, and you hate cats, your reply, declining the invitation, +does not necessarily have to cover the full range of your emotions. You must +make it clear that you will not attend, but you do not have to let fly at cats. +The writer of the letter asked a civil question; attack cats, then, only if +you can do so with good humor, good taste, and in such a way that your answer +will be courteous as well as responsive. Since you are out of sympathy with +cats, you may quite properly give this as a reason for not appearing at the +dedication ceremonies of a cat hospital. But bear in mind that your opinion +of cats was not sought, only your services as a speaker. Try to keep things +straight. + -- Strunk and White, "The Elements of Style" +%% +If you have to ask how much it is, you can't afford it. +%% +If you have to ask what jazz is, you'll never know. + -- Louis Armstrong +%% +If you have to hate, hate gently. +%% +If you have to think twice about it, you're wrong. +%% +If you haven't got anything nice to say about anyone, come sit by me. + -- Alice Roosevelt Longworth +%% +If you knew what to say next, would you say it? +%% +If you know the answer to a question, don't ask. + -- Petersen Nesbit +%% +If you learn one useless thing every day, +in a single year you'll learn 365 useless things. +%% +If you liked the Earth you'll love Heaven. +%% +If you live in a country run by committee, be on the committee. + -- Graham Summer +%% +If you lose a son you can always get another, +but there's only one Maltese Falcon. + -- The Maltese Falcon +%% +If you lose your temper at a newspaper columnist, +he'll get rich or famous or both. +%% +If you love something set it free. If it doesn't +come back to you, hunt it down and kill it. +%% +If you make a mistake you right it +immediately to the best of your ability. +%% +If you make people think they're thinking, they'll love you; +but if you really make them think they'll hate you. +%% +If you mess with a thing long enough, it'll break. + -- Schmidt +%% +If you need anything just whistle. +You know how to whistle, don't you, Steve? +Just put your lips together and blow. + -- Lauren Bacall, "To Have and Have Not" +%% +If you notice that a person is deceiving you, +they must not be deceiving you very well. +%% +If you pick up a starving dog and make him prosperous, he will not +bite you. This is the principal difference between a dog and a man. + -- Mark Twain +%% +If you push the "extra ice" button on the soft drink vending machine, +you won't get any ice. If you push the "no ice" button, you'll get +ice, but no cup. +%% +If you put garbage in a computer nothing comes out but garbage. +But this garbage, having passed through a very expensive machine, +is somehow enobled and none dare criticize it. +%% +If you put it off long enough, it might go away. +%% + If you rap your knuckles against a window jamb or door, if you +brush your leg against a bed or desk, if you catch your foot in a curled- +up corner of a rug, or strike a toe against a desk or chair, go back and +repeat the sequence. + You will find yourself surprised how far off course you were to +hit that window jamb, that door, that chair. Get back on course and do it +again. How can you pilot a spacecraft if you can't find your way around +your own apartment? + -- William S. Burroughs +%% +If you refuse to accept anything but the best you very often get it. +%% +If you resist reading what you disagree with, how will you ever acquire +deeper insights into what you believe? The things most worth reading +are precisely those that challenge our convictions. +%% +If you see an onion ring -- answer it! +%% +If you sell diamonds, you cannot expect to have many customers. +But a diamond is a diamond even if there are no customers. + -- Swami Prabhupada +%% +If you stew apples like cranberries, +they taste more like prunes than rhubarb does. + -- Groucho Marx +%% +If you suspect a man, don't employ him. +%% +If you think before you speak the other guy gets his joke in first. +%% +If you think last Tuesday was a drag, +wait till you see what happens tomorrow! +%% +If you think nobody cares if you're alive, +try missing a couple of car payments. + -- Earl Wilson +%% +If you think the United States has stood still, +who built the largest shopping center in the world? + -- Richard Nixon +%% +If you took all the women at the Harvard Prom +and laid them end to end, I wouldn't be a bit surprised. + -- Dorothy Parker +%% +If you treat people right they will treat you right -- 90% of the time. + -- F.D. Roosevelt +%% +If you try to please everyone, somebody is not going to like it. +%% +If you wait long enough, it will go away... after having +done its damage. If it was bad, it will be back. +%% +If you want me to be a good little bunny +just dangle some carats in front of my nose. + -- Lauren Bacall +%% +If you want to be ruined, marry a rich woman. + -- Michelet +%% +If you want to know how old a man is, ask his brother-in-law. +%% +If you want to put yourself on the map, publish your own map. +%% +If you want to see card tricks, you have to expect to take cards. + -- Harry Blackstone +%% +If you want your spouse to listen and pay strict +attention to every word you say, talk in your sleep. +%% +If you wants to get elected president, you'se got to think up some +memoraboble homily so's school kids can be pestered into memorizin' +it, even if they don't know what it means. + -- Walt Kelly +%% +If you waste your time cooking, you'll miss the next meal. +%% +If you will practice being fictional for a while, you will understand that +fictional characters are sometimes more real than people with bodies and +heartbeats. +%% +If you wish to be happy for one hour, get drunk. +If you wish to be happy for three days, get married. +If you wish to be happy for a month, kill your pig and eat it. +If you wish to be happy forever, learn to fish. + -- Chinese Proverb +%% +If you wish to succeed, consult three old people. +%% +If you wish women to love you, be original; I know a man who wore fur +boots summer and winter, and women fell in love with him. + -- Anton Chekov +%% +If you would keep a secret from an enemy, tell it not to a friend. +%% +If you would know the value of money, go try to borrow some. + -- Ben Franklin +%% +If you would understand your own age, read the works +of fiction produced in it. People in disguise speak freely. +%% +If you'd like to cultivate insomnia, +Bed down with a pretty girl. +Amor vincit omnia. +%% +If your aim in life is nothing; you can't miss. +%% +If your bread is stale, make toast. +%% +If your enemy is buried in quicksand up to his neck, pull him out. +If he is buried up to his eyes, step on his head. + -- Niccoli Machiavelli, "The Prince" +%% +If your happiness depends on what somebody else does, +I guess you do have a problem. + -- Richard Bach, "Illusions" +%% +If your life was a horse, you'd have to shoot it. +%% +If your mother knew what you're doing, +she'd probably hang her head and cry. +%% +If your parents don't have kids, neither will you. +%% +If your thesis is utterly vacuous, +Employ first-order predicate calculus. + With sufficient formality, + The sheerest banality, +Will be hailed by all as miraculous! +%% +If you're careful enough, nothing +bad or good will ever happen to you. +%% +If you're carrying a torch, put it down. +The Olympics are over. +%% +If you're going to do something tonight +that you'll be sorry for tomorrow morning, sleep late. + -- Henny Youngman +%% +If you're happy, you're successful. +%% +If you're not part of the solution, you're part of the precipitate. +%% +If you're not very clever you should be conciliatory. + -- Benjamin Disraeli +%% +If you've done six impossible things before breakfast, why not round it +off with dinner at Milliway's, the restaurant at the end of the universe. +%% +If you've seen one redwood, you've seen them all. + -- Ronald Reagan +%% +Ignorance is bliss. + -- Thomas Gray + +Fortune updates the great quotes, #42: + BLISS is ignorance. +%% +Ignorance is when you don't know anything and somebody finds it out. +%% +Ignore previous fortune. +%% +Il brilgue: les toves libricilleux + Se gyrent et frillant dans le guave, +Enmimes sont les gougebosquex, + Et le momerade horgrave. + +Es brilig war. Die schlichte Toven + Wirrten und wimmelten in Waben; +Und aller-mumsige Burggoven + Dir mohmen Rath ausgraben. +%% +I'll burn my books. + -- Christopher Marlowe +%% +I'll grant thee random access to my heart, +Thoul't tell me all the constants of thy love; +And so we two shall all love's lemmas prove +And in our bound partition never part. + +Cancel me not -- for what then shall remain? +Abscissas, some mantissas, modules, modes, +A root or two, a torus and a node: +The inverse of my verse, a null domain. + +I see the eigenvalue in thine eye, +I hear the tender tensor in thy sigh. +Bernoulli would have been content to die +Had he but known such a-squared cos 2(thi)! +%% +I'll meet you... on the dark side of the moon... + -- Pink Floyd +%% +I'll never get off this planet. + -- Luke Skywalker +%% +I'll pretend to trust you if you'll pretend to trust me. +%% +I'll turn over a new leaf. + -- Miguel de Cervantes +%% +Illegitimi non carborundum (translation: no carbonated drinks allowed.) +%% +Illusion is the first of all pleasures. + -- Voltaire +%% +I'm Jewish. Count Basie's Jewish. Ray Charles is Jewish. Eddie +Cantor's goyish. The B'nai Brith is goyish. The Hadassah is Jewish. +Marine Corps -- heavy goyish, dangerous. Kool-Aid is goyish. All Drake's +Cakes are goyish. Pumpernickel is Jewish and, as you know, white bread is +very goyish. Instant potatoes -- goyish. Black cherry soda's very Jewish. +Macaroons are very Jewish. Fruit salad is Jewish. Lime Jell-O is goyish. +Lime soda is very goyish. Trailer parks are so goyish that Jews won't +go near them. + -- Lenny Bruce +%% +I'm N-ary the tree, I am, +N-ary the tree, I am, I am. +I'm getting traversed by the parser next door, +She's traversed me seven times before. +And ev'ry time it was an N-ary (N-ary!) +Never wouldn't ever do a binary. (No sir!) +I'm 'er eighth tree that was N-ary. +N-ary the tree I am, I am, +N-ary the tree I am. + -- Stolen from Paul Revere and the Raiders +%% +I'm a Hollywood writer; so I put on +a sports jacket and take off my brain. +%% +I'm a creationist; I refuse to believe +that I could have evolved from man. +%% +I'm all for computer dating, but I +wouldn't want one to marry my sister. +%% +I'm always looking for a new idea that +will be more productive than its cost. + -- David Rockefeller +%% +I'm an artist. +But it's not what I really want to do. +What I really want to do is be a shoe salesman. +I know what you're going to say -- +"Dreamer! Get your head out of the clouds." +All right! But it's what I want to do. +Instead I have to go on painting all day long. + +The world should make a place for shoe salesmen. + -- J. Feiffer +%% +I'm an evolutionist; I refuse to believe +that I could have been created by man. +%% +I'm dying beyond my means. + -- Oscar Wilde, his last words, while sipping champagne +%% +I'm fed up to the ears with old men +dreaming up wars for young men to die in. + -- George McGovern +%% +I'm free -- and freedom tastes of reality. +%% +I'm going through my "I want to go back to New York" phase today. Happens +every six months or so. So, I thought, perhaps unwisely, that I'd share +it with you. +> In New York in the winter it is million degrees below zero and + the wind travels at a million miles an hour down 5th avenue. +> And in LA it's 72. + +> In New York in the summer it is a million degrees and the humidity + is a million percent. +> And in LA it's 72. + +> In New York there are a million interesting people. +> And in LA there are 72. +%% +I'm hungry, time to eat lunch. +%% +I'm in Pittsburgh. Why am I here? + -- Harold Urey +%% +I'm just as sad as sad can be! + I've missed your special date. +Please say that you're not mad at me + My tax return is late. + -- Modern Lines for Modern Greeting Cards +%% +I'm not a lovable man. + -- Richard Nixon. +%% +I'm not even going to *bother* comparing C to BASIC or FORTRAN. + -- L. Zolman, creator of BDS C +%% +I'm not laughing with you, I'm laughing at you. +%% +I'm not offering myself as an example; +every life evolves by its own laws. +%% +I'm not prejudiced, I hate everyone equally. +%% +I'm not proud. +%% +I'm not under the alkafluence of inkahol +that some thinkle peep I am. +It's just the drunker I sit here the longer I get. +%% +I'm prepared for all emergencies but +totally unprepared for everyday life. +%% +I'm really enjoying not talking to you... +Let's not talk again REAL soon... +%% +I'm so broke I can't even pay attention. +%% +I'm sorry if the correct way of doing things offends you. +%% +I'm still waiting for the advent of the computer science groupie. +%% +I'm successful because I'm lucky. +The harder I work, the luckier I get. +%% +Imagination is more important than knowledge. + -- A. Einstein +%% +Imagination is the one weapon in the war against reality. + -- Jules de Gaultier +%% +Imagine there's no heaven... it's easy if you try. + -- John Lennon, "Imagine" +%% +Imagine what we can imagine! + -- Arthur Rubinstein +%% +Imbalance of power corrupts and monopoly of power corrupts absolutely. + -- Genji +%% +Imbesi's Law with Freeman's Extension: + In order for something to become clean, something else must + become dirty; but you can get everything dirty without getting + anything clean. +%% +Immanuel Kant but Kubla Khan. +%% +Immortality -- a fate worse than death. + -- Edgar A. Shoaff +%% +Immutability, Three Rules of: + (1) If a tarpaulin can flap, it will. + (2) If a small boy can get dirty, he will. + (3) If a teenager can go out, he will. +%% +Important letters which contain no errors will develop errors in the mail. +Corresponding errors will show up in the duplicate while the Boss is reading +it. Vital papers will demonstrate their vitality by spontaneously moving +from where you left them to where you can't find them. +%% +In America, any boy may become president and I +suppose that's just one of the risks he takes. + -- Adlai Stevenson +%% +In America, it's not how much an +item costs, it's how much you save. +%% +In Brooklyn, we had such great pennant races, it +made the World Series just something that came later. + -- Walter O'Malley, Dodgers owner +%% +In Cristianity, a man may have only one wife. +This is called Monotony. +%% +In Dr. Johnson's famous dictionary patriotism is defined as the +last resort of the scoundrel. With all due respect to an enlightened +but inferior lexicographer I beg to submit that it is the first. + -- Ambrose Bierce +%% +In Duluth there's a hostess, forsooth, +Who doesn't know gin from vermouth, + But this lubricant lapse + Isn't noticed, perhaps +Because nobody does in Duluth. +%% +In English, every word can be verbed. +Would that it were so in our programming languages. +%% +In God we trust; all else we walk through. +%% +In India, "cold weather" is merely a conventional phrase and has come into +use through the necessity of having some way to distinguish between weather +which will melt a brass door-knob and weather which will only make it mushy. + -- Mark Twain +%% + In "King Henry VI, Part II," Shakespeare has Dick Butcher suggest to +his fellow anti-establishment rabble-rousers, "The first thing we do, let's +kill all the lawyers." That action may be extreme but a similar sentiment +was expressed by Thomas K. Connellan, president of The Management Group, Inc. +Speaking to business executives in Chicago and quoted in Automotive News, +Connellan attributed a measure of America's falling productivity to an excess +of attorneys and accountants, and a dearth of production experts. Lawyers +and accountants "do not make the economic pie any bigger; they only figure +out how the pie gets divided. Neither profession provides any added value +to product." + According to Connellan, the highly productive Japanese society has +10 lawyers and 30 accountants per 100,000 population. The U.S. has 200 +lawyers and 700 accountants. This suggests that "the U.S. proportion of +pie-bakers and pie-dividers is way out of whack." Could Dick Butcher have +been an efficiency expert? + -- Motor Trend, May 1983 +%% +In Minnesota they ask why all football fields in Iowa have artificial turf. +It's so the cheerleaders won't graze during the game. +%% +In Oz, never say "krizzle kroo" to a Woozy. +%% +In Pierre Trudeau, Canada has finally produced +a Prime Minister worthy of assassination. + -- John Diefenbaker +%% +In Xanadu did Kubla Khan +A stately pleasure dome decree: +Where Alph, the sacred river, ran +Through caverns measureless to man +Down to a sunless sea. +So twice five miles of fertile ground +With walls and towers were girdled round: +And there were gardens bright with sinuous rills, +Where blossomed many an incense-bearing tree; +And here were forest ancient as the hills, +Enfolding sunny spots of greenery. + -- S.T. Coleridge, "Kubla Kahn" +%% +In a bottle, the neck is always at the top. +%% +In a circuit with a fast-acting fuse, +an IC will blow to protect the fuse. +%% +In a consumer society there are inevitably two kinds of slaves: +the prisoners of addiction and the prisoners of envy. +%% +In a country where the sole employer is the State, opposition means death +by slow starvation. The old principle: Who does not work shall not eat, +has been replaced by a new one: Who does not obey shall not eat. + -- Leon Trotsky, 1937 +%% +In a five year period we can get one superb programming language. +Only we can't control when the five year period will begin. +%% +In a gathering of two or more people, when a lighted cigarette is +placed in an ashtray, the smoke will waft into the face of the non-smoker. +%% +In a hierarchy every employee tends to rise to his level of incompetence. + -- Dr. Laurence J. Peter +%% +In a surprise raid last night, federal agent's ransacked a house in search +of a rebel computer hacker. However, they were unable to complete the arrest +because the warrant was made out in the name of Don Provan, while the only +person in the house was named don provan. Proving, once again, that Unix is +superior to Tops10. +%% +In a whiskey it's age, in a cigarette it's +taste and in a sports car it's impossible. +%% +I'm very good at integral and differential calculus, +I know the scientific names of beings animalculous; +In short, in matters vegetable, animal, and mineral, +I am the very model of a modern Major-General. + -- Gilbert & Sullivan, "The Pirates of Penzance" +%% +In an orderly world, there's always a place for the disorderly. +%% +In any formula, constants (especially those obtained from handbooks) +are to be treated as variables. +%% +In any problem, if you find yourself doing an infinite amount of work, +the answer may be obtained by inspection. +%% +In buying horses and taking a wife +shut your eyes tight and commend yourself to God. +%% +In case of atomic attack, the federal ruling +against prayer in schools will be temporarily cancelled. +%% +In case of fire, yell "FIRE!" +%% +In case of injury notify your superior immediately. +He'll kiss it and make it better. +%% +In charity there is no excess. + -- Francis Bacon +%% +In computing, the mean time to failure keeps getting shorter. +%% +In cosmetics, there's cases of revolutionary Venus Envy Hair Spray; +Legette Hair Fastener Heat Bags; Lady O' Spain Self-Blinding Eye Shadow +with Magic Puncture Pencil; Sanitary Napkin Rings in Little Miss, Moon +Maid and Stuck Pig Strength; and deported Italian Napagel Balls for +soaking or eating; and they're all slash-priced with the lady in mind... + -- Firesign Theatre +%% +In dwelling, be close to the land. +In meditation, delve deep into the heart. +In dealing with others, be gentle and kind. +In speech, be true. +In work, be competent. +In action, be careful of your timing. + -- Lao Tsu +%% +In every hierarchy the cream rises until it sours. + -- Dr. Laurence J. Peter +%% +In every job that must be done, there is an element of fun. +Find the fun and snap! the job's a game, and every task +you undertake becomes a piece of cake, a lark, a spree; +it's very clear to see. + -- Mary Poppins +%% +In every non-trivial program there is at least one bug. +%% +In fact, S. M. Simpson, eventually devised an efficient 24-point Fourier +transform, which was a precursor to the Cooley-Tukey fast Fourier transform +in 1965. The FFT made all of Simpson's efficient autocorrelation and +spectrum programs instantly obsolete, on which he had worked half a lifetime. + -- Proc. IEEE, Sept. 1982, p.900 +%% +In good speaking, should not the mind of the speaker +know the truth of the matter about which he is to speak? + -- Plato +%% +In just seven days, I can make you a man! + -- The Rocky Horror Picture Show +%% +In less than a century, computers will be making substantial +progress on ... the overriding problem of war and peace. + -- James Slagle +%% +In like a dimwit, out like a light. + -- Pogo +%% +In love, she who gives her portrait promises the original. + -- Bruton +%% +In marriage, as in war, it is permitted +to take every advantage of the enemy. +%% +In matters of principle, stand like a rock; +in matters of taste, swim with the current. + -- Thomas Jefferson +%% +In most instances, all an argument +proves is that two people are present. +%% +In my end is my beginning. + -- Mary Stuart, Queen of Scots +%% +In olden times sacrifices were made at the altar -- +a custom which is still continued. + -- Helen Rowland +%% +In order to dial out, it is necessary to broaden one's dimension. +%% +In order to get a loan you must first prove you don't need it. +%% +In order to live free and happily, you must sacrifice boredom. +It is not always an easy sacrifice. +%% +In our civilization, and under our republican form of government, +intelligence is so highly honored that it is rewarded by exemption +from the cares of office. +%% +In short, N is Richardian if, and only if, N is not Richardian. +%% +In success there's a tendency to keep on doing what you were doing. + -- Alan Kay +%% +In the Spring, I have counted 136 +different kinds of weather inside of 24 hours. + -- Mark Twain, on New England weather +%% +In the Top 40, half the songs are secret messages to the teen world to drop +out, turn on, and groove with the chemicals and light shows at discotheques. + -- Art Linkletter +%% + In the begining, God created the Earth and he said, "Let there be +mud." + And there was mud. + And God said, "Let Us make living creatures out of mud, so the mud +can see what we have done." + And God created every living creature that now moveth, and one was +man. Mud-as-man alone could speak. + "What is the purpose of all this?" man asked politely. + "Everything must have a purpose?" asked God. + "Certainly," said man. + "Then I leave it to you to think of one for all of this," said God. + And He went away. + -- Kurt Vonnegut, Between Time and Timbuktu" +%% + In the beginning there was data. The data was without form and +null, and darkness was upon the face of the console; and the Spirit of +IBM was moving over the face of the market. And DEC said, "Let there +be registers"; and there were registers. And DEC saw that they +carried; and DEC separated the data from the instructions. DEC called +the data Stack, and the instructions they called Code. And there was +evening and there was morning, one interrupt. + -- Rico Tudor, "The Story of Creation or, The Myth of Urk" +%% +In the days of old, +When Knights were bold, + And women were too cautious; +Oh, those gallant days, +When women were women, + And men were really obnoxious. +%% + In the days when Sussman was a novice Minsky once came to him as he +sat hacking at the PDP-6. + "What are you doing?", asked Minsky. + "I am training a randomly wired neural net to play Tic-Tac-Toe." + "Why is the net wired randomly?", inquired Minsky. + "I do not want it to have any preconceptions of how to play". + At this Minsky shut his eyes, and Sussman asked his teacher "Why do +you close your eyes?" + "So that the room will be empty." + At that momment, Sussman was enlightened. +%% +In the dimestores and bus stations +People talk of situations +Read books repeat quotations +Draw conclusions on the wall. + -- Bob Dylan +%% +In the eyes of my dog, I'm a man. + -- Martin Mull +%% +In the first place, God made idiots; +this was for practice; then he made school boards. + -- Mark Twain +%% +In the future, you're going to get computers as prizes in breakfast cereals. +You'll throw them out because your house will be littered with them. +%% +In the highest society, as well as in the lowest, +woman is merely an instrument of pleasure. + -- Tolstoy +%% +In the land of the dark the Ship of the +Sun is driven by the Grateful Dead. + -- Egyptian Book of the Dead +%% +In the long run, every program becomes rococco, and then rubble. + -- Alan Perlis +%% +In the middle of a wide field is a pot of gold. 100 feet to the north stands +a smart manager. 100 feet to the south stands a dumb manager. 100 feet to +the east is the Easter Bunny, and 100 feet to the west is Santa Claus. + +Q: Who gets to the pot of gold first? +A: The dumb manager. All the rest are myths. +%% +In the midst of one of the wildest parties he'd ever been to, the young man +noticed a very prim and pretty girl sitting quietly apart from the rest of +the revelers. Approaching her, he introduced himself and, after some quiet +conversation, said, "I'm afraid you and I don't really fit in with this +jaded group. Why don't I take you home?"" + "Fine," said the girl, smiling up at him demurely. "Where do you +live?" +%% + In the morning, laughing, happy fish heads + In the evening, floating in the soup. +(chorus): +Fish heads, fish heads, roly-poly fish heads; +Fish heads, fish heads, eat them up. Yum! + You can ask them anything you want to. + They won't answer; they can't talk. +(chorus): + I took a fish head out to see a movie, + Didn't have to pay to get it in. +(chorus): + They can't play baseball; they don't wear sweaters; + They aren't good dancers; they can't play drums. +(chorus): + Roly-poly fish heads are NEVER seen drinking cappucino in + Italian restaurants with Oriental women. +(chorus): + Fishy! +(chorus): + -- Fish Heads +%% +In the next world, you're on your own. +%% +In the stairway of life, you'd best take the elevator. +%% +In the war of wits, he's unarmed. +%% +In these matters the only certainty is that there is nothing certain. + -- Pliny the Elder +%% +In this world some people are going to like me and some are not. +So, I may as well be me. Then I know if someone likes me, they like me. +%% +In this world, truth can wait; she's used to it. +%% +In time, every post tends to be occupied by an +employee who is incompetent to carry out its duties. + -- Dr. L.J. Peter +%% +In /users3 did Kubla Kahn +A stately pleasure dome decree, +Where /bin, the sacred river ran +Through Test Suites measureless to Man +Down to a sunless C. +%% +In war it is not men, but the man who counts. + -- Napoleon +%% +In war, truth is the first casualty. + -- U Thant +%% + In what can only be described as a surprise move, God has officially +announced His candidacy for the U.S. presidency. During His press conference +today, the first in over 4000 years, He is quoted as saying, "I think I have +a chance for the White House if I can just get my campaign pulled together +in time. I'd like to get this country turned around; I mean REALLY turned +around! Let's put Florida up north for awhile, and let's get rid of all +those annoying mountains and rivers. I never could stand them!" + There apparently is still some controversy over the Almighty's +citizenship and other qualifications for the Presidency. God replied to +these charges by saying, "Come on, would the United States have anyone other +than a citizen bless their country?" +%% +In which level of metalanguage are you now speaking? +%% +In wine there is truth (In vino veritas). + -- Pliny +%% +In youth, it was a way I had +To do my best to please, +And change, with every passing lad, +To suit his theories. + +But now I know the things I know, +And do the things I do; +And if you do not like me so, +To hell, my love, with you! + -- Dorothy Parker, "Indian Summer" +%% +Include me out. +%% +Increased knowledge will help you now. +Have mate's phone bugged. +%% +Indecision is the true basis for flexibility. +%% +Indeed, the first noble truth of Buddhism, usually translated as +`all life is suffering,' is more accurately rendered `life is filled +with a sense of pervasive unsatisfactoriness.' + -- M.D. Epstein +%% +Individualists unite! +%% +Indomitable in retreat; invincible in +advance; insufferable in victory. + -- Winston Churchill, on General Montgomery +%% +Infidel: In New York, one who does not believe in the +Christian religion; in Constantinople, one who does. + -- Ambrose Bierce +%% +Inform all the troops that communications have completely broken down. +%% +Information is the inverse of entropy. +%% +Injustice anywhere is a threat to justice everywhere. + -- Martin Luther King, Jr. +%% +Innovation is hard to schedule. + -- Dan Fylstra +%% +Insanity is inherited, you get it from your kids! +%% +Insanity is the final defense. It's hard to get a refund when +the salesman is sniffing your crotch and baying at the moon. +%% +Inside every large problem is a small problem struggling to get out. +%% +Insomnia isn't anything to lose sleep over. +%% +Inspiration without perspiration is usually sterile. +%% +Inspite of all evidence to the contrary, the entire universe +is composed of only two basic substances: magic and bullshit. +%% +Integrity has no need for rules. +%% +Intellect annuls Fate. +So far as a man thinks, he is free. + -- Ralph Waldo Emerson +%% +Interchangeable parts won't. +%% +Introducing, the 1010, a one-bit processor. + +INSTRUCTION SET + Code Mnemonic What + 0 NOP No Operation + 1 JMP Jump (address specified by next 2 bits) + +Now Available for only 12 1/2 cents! +%% +Invest in physics -- own a piece of Dirac! +%% +Involvement with people is always a very delicate thing -- +it requires real maturity to become involved and not get all messed up. + -- Bernard Cooke +%% +Iowans ask why Minnesotans don't drink more Kool-Aid. That's because +they can't figure out how to get two quarts of water into one of those +little paper envelopes. +%% +Iron Law of Distribution: + Them that has, gets. +%% +Is a computer language with goto's totally Wirth-less? +%% +Is death legally binding? +%% +Is it possible that software is not like anything else, that it is +meant to be discarded: that the whole point is to always see it as +a soap bubble? +%% +Is knowledge knowable? If not, how do we know that? +%% +Is not marriage an open question, when it is alleged, from the beginning +of the world, that such as are in the institution wish to get out, +and such as are out wish to get in? + -- Ralph Emerson +%% +Is that really YOU that is reading this? +%% +Is there life before breakfast? +%% +Is this really happening? +%% +Isn't air travel wonderful? +Breakfast in London, dinner in New York, luggage in Brazil. +%% +Isn't it conceivable to you that an intelligent +person could harbor two opposing ideas in his mind? + -- Adlai Stevenson, to reporters +%% +Isn't it ironic that many men spend a great part of their lives +avoiding marriage while single-mindedly pursuing those things that +would make them better prospects? +%% +Isn't it strange that the same people that +laugh at gypsy fortune tellers take economists seriously? +%% +Issawi's Laws of Progress: + The Course of Progress: + Most things get steadily worse. + The Path of Progress: + A shortcut is the longest distance between two points. +%% +It appears that PL/I (and its dialects) is, or will be, the +most widely used higher level language for systems programming. + -- J. Sammet +%% +It cannot be seen, cannot be felt, +Cannot be heard, cannot be smelt. +It lies behind starts and under hills, +And empty holes it fills. +It comes first and follows after, +Ends life, kills laughter. +%% +"It could be that Walter's horse has wings" does not imply that there is +any such animal as Walter's horse, only that there could be; but "Walter's +horse is a thing which could have wings" does imply Walter's horse's +existence. But the conjunction "Walter's horse exists, and it could be +that Walter's horse has wings" still does not imply "Walter's horse is a +thing that could have wings", for perhaps it can only be that Walter's +horse has wings by Walter having a different horse. Nor does "Walter's +horse is a thing which could have wings" conversely imply "It could be that +Walter's horse has wings"; for it might be that Walter's horse could only +have wings by not being Walter's horse. + +I would deny, though, that the formula [Necessarily if some x has property P +then some x has property P] expresses a logical law, since P(x) could stand +for, let us say "x is a better logician than I am", and the statement "It is +necessary that if someone is a better logician than I am then someone is a +better logician than I am" is false because there need not have been any me. + -- A.N. Prior, "Time and Modality" +%% +It does not do to leave a live dragon out of your calculations. +%% +It doesn't matter whether you win or lose -- until you lose. +%% +It got to the point where I had to get a haircut +or both feet firmly planted in the air. +%% +It happened long ago +In the new magic land +The Indians and the buffalo +Existed hand in hand +The Indians needed food +They need skins for a roof +The only took what they needed +And the buffalo ran loose +But then came the white man +With his thick and empty head +He couldn't see past his billfold +He wanted all the buffalo dead +It was sad, oh so sad. + -- Ted Nugent, "The Great White Buffalo" +%% +It has been justly observed by sages of all lands that although +a man may be most happily married and continue in that state with the +utmost contentment, it does not necessarily follow that he has +therefore been struck stone-blind. + -- H. Warner Munn +%% +It has been observed that one's nose is never so happy as when it +is thrust into the affairs of another, from which some physiologists +have drawn the inference that the nose is devoid of the sense of smell. + -- Ambrose Bierce +%% +It has just been discovered that research causes cancer in rats. +%% +It has long been an article of our folklore that too much knowledge or skill, +or especially consummate expertise, is a bad thing. It dehumanizes those who +achieve it, and makes difficult their commerce with just plain folks, in whom +good old common sense has not been obliterated by mere book learning or fancy +notions. This popular delusion flourishes now more than ever, for we are all +infected with it in the schools, where educationists have elevated it from +folklore to Article of Belief. It enhances their self-esteem and lightens +their labors by providing theoretical justification for deciding that +appreciation, or even simple awareness, is more to be prized than knowledge, +and relating (to self and others), more than skill, in which minimum +competence will be quite enough. + -- The Underground Grammarian +%% +It has long been an axiom of mine that the +little things are infinitely the most important. + -- Sir Arthur Conan Doyle, "A Case of Identity" +%% +It has long been known that birds will occasionally build nests in the +manes of horses. The only known solution to this problem is to sprinkle +baker's yeast in the mane, for, as we all know, yeast is yeast and nest +is nest, and never the mane shall tweet. +%% +It has long been known that one horse can run faster +than another -- but which one? Differences are crucial. + -- Lazarus Long +%% +It is Fortune, not Wisdom, that rules man's life. +%% +It is a hard matter, my fellow citizens, +to argue with the belly, since it has no ears. + -- Marcus Porcius Cato +%% +It is a lesson which all history teaches +wise men, to put trust in ideas, and not in circumstances. + -- Emerson +%% +It is a poor judge who cannot award a prize. +%% +It is a profitable thing, if one is wise, to seem foolish. + -- Aeschylus +%% +It is a sobering thought that when Mozart was +my age, he had been dead for 2 years. + -- Tom Lehrer +%% +It is a wise father that knows his own child. + -- William Shakespeare, "The Merchant of Venice" +%% +It is against the grain of modern education to teach children to program. +What fun is there in making plans, acquiring discipline in organizing +thoughts, devoting attention to detail, and learning to be self-critical? + -- Alan Perlis +%% + It is always preferable to visit home with a friend. Your parents will +not be pleased with this plan, because they want you all to themselves and +because in the presence of your friend, they will have to act like mature +human beings. + The worst kind of friend to take home is a girl, because in that case, +there is the potential that your parents will lose you not just for the +duration of the visit but forever. The worst kind of girl to take home is one +of a different religion: Not only will you be lost to your parents forever but +you will be lost to a woman who is immune to their religious/moral arguments +and whose example will irretrievably corrupt you. + Let's say you've fallen in love with just such a girl and would like +to take her home for the holidays. You are aware of your parents' xenophobic +response to anyone of a different religion. How to prepare them for the shock? + Simple. Call them up shortly before your visit and tell them that you +have gotten quite serious about somebody who is of a different religion, a +different race and the same sex. Tell them you have already invited this +person to meet them. Give the information a moment to sink in and then +remark that you were only kidding, that your lover is merely of a different +religion. They will be so relieved they will welcome her with open arms. + -- Playboy, January, 1983 +%% +It is always the best policy to speak the truth, +unless of course you are an exceptionally good liar. + -- Jerome K. Jerome +%% +It is amazing how complete is the delusion that beauty is goodness. +%% +It is amusing that a virtue is made of the vice of chastity; and +it's a pretty odd sort of chastity at that, which leads men straight +into the sin of Onan, and girls to the waning of their color. + -- Voltaire +%% +It is annoying to be honest to no purpose. + -- Publius Ovidius Naso (Ovid) +%% +It is bad luck to be superstitious. + -- Andrew W. Mathis +%% +It is better to be bow-legged than no-legged. +%% +It is better to be on penicillin, than never to have loved at all. +%% +It is better to burn out than it is to rust. +%% +It is better to die on your feet than to live on your knees. +%% +It is better to have a positive Wasserman than never to have loved at all. +%% +It is better to have loved a short man than never to have loved a tall. +%% +It is better to have loved and lost -- much better. +%% +It is better to have loved and lost than just to have lost. +%% +It is better to kiss an avocado than to get in a fight with an aardvark. +%% +It is better to remain childless than to father an orphan. +%% +It is better to wear chains than to believe you are free, +and weight yourself down with invisible chains. +%% +It is better to wear out than to rust out. +%% +It is common sense to take a method and try it. If it fails, +admit it frankly and try another. But above all, try something. + -- Franklin D. Roosevelt +%% +It is contrary to reasoning to say that there +is a vacuum or space in which there is absolutely nothing. + -- Descartes +%% +It is convenient that there be gods, and, +as it is convenient, let us believe there are. + -- Publius Ovidius Naso (Ovid) +%% +It is difficult to legislate morality in the absence of moral legislators. +%% +It is difficult to produce a television documentary that is both incisive +and probing when every twelve minutes one is interrupted by twelve dancing +rabbits singing about toilet paper. + -- R. Serling +%% +It is difficult to soar with the eagles when you work with turkeys. +%% +It is easier for a camel to pass through the +eye of a needle if it is lightly greased. + -- Kehlog Albran +%% +It is easier to be a liberal a long way from home. +%% +It is easier to change the specification to fit the program than vice versa. +%% +It is easier to get forgiveness than permission. +%% +It is easier to make a saint out of a libertine than out of a prig. + -- George Santayana +%% +It is easier to resist at the beginning than at the end. + -- Leonardo da Vinci +%% +It is easier to run down a hill than up one. +%% +It is easier to write an incorrect program than understand a correct one. +%% +It is easy when we are in prosperity to give advice to the afflicted. + -- Aeschylus +%% +It is enough to make one sympathize with a tyrant for the determination +of his courtiers to deceive him for their own personal ends... + -- Russell Baker and Charles Peters +%% +It is exactly because a man cannot do a +thing that he is a proper judge of it. + -- Oscar Wilde +%% +It is far better to be deceived than to be undeceived by those we love. +%% +It is fruitless: + to become lacrymose over precipitately departed lactate fluid. + + to attempt to indoctrinate a superannuated canine with + innovative maneuvers. +%% +It is generally agreed that "Hello" is an appropriate greeting because +if you entered a room and said "Goodbye," it could confuse a lot of people. + -- Dolph Sharp +%% +It is idle to attempt to talk a young woman out of her passion: +love does not lie in the ear. + -- Walpole +%% +It is impossible for an optimist to be pleasantly surprised. +%% +It is impossible to defend perfectly +against the attack of those who want to die. +%% +It is impossible to enjoy idling thoroughly +unless one has plenty of work to do. + -- Jerome Klapka Jerome +%% +It is impossible to make anything +foolproof because fools are so ingenious. +%% +It is impossible to travel faster than light, and +certainly not desirable, as one's hat keeps blowing off. + -- Woody Allen +%% +It is indeed desirable to be well descended, +but the glory belongs to our ancestors. + -- Plutarch +%% +It is like saying that for the cause of peace, +God and the Devil will have a high-level meeting. + -- Rev. Carl McIntire, on Nixon's China trip +%% +It is most dangerous nowadays for a husband to pay any attention to his +wife in public. It always makes people think that he beats her when +they're alone. The world has grown so suspicious of anything that looks +like a happy married life. + -- Wilde +%% +It is much easier to be critical than to be correct. + -- Benjamin Disraeli +%% +It is much easier to suggest solutions +when you know nothing about the problem. +%% +It is much harder to find a job than to keep one. +%% +It is not a good omen when goldfish commit suicide. +%% +It is not enough to have a good mind. +The main thing is to use it well. + -- Rene Descartes +%% +It is not enough to have great qualities, +we should also have the management of them. + -- La Rochefoucauld +%% +It is not enough that I should succeed. Others must fail. + -- Ray Kroc, Founder of McDonald's + [Also attributed to David Merrick. Ed.] + +It is not enough to succeed. Others must fail. + -- Gore Vidal + [Great minds think alike? Ed.] +%% +It is not every question that deserves an answer. + -- Publilius Syrus +%% +It is not for me to attempt to fathom the +inscrutable workings of Providence. + -- The Earl of Birkenhead +%% +It is not good for a man to be without knowledge, +and he who makes haste with his feet misses his way. + -- Proverbs 19:2 +%% +It is not the critic who counts, or how the strong man stumbled, or whether +the doer of deeds could have done them better. The credit belongs to the +man who is actually in the arena, whose face is marred by dust and sweat and +blood, who strives valiantly, who errs and comes short again and again; who +knows the great enthusiasm, the great devotion, and who spends himself in a +worthy cause, and if he fails, at least fails while daring greatly, so that +he'll never be with those cold and timid souls who never know either victory +or defeat. + -- Teddy Roosevelt +%% +It is not true that life is one damn thing after +another -- it's one damn thing over and over. + -- Edna St. Vincent Millay +%% +It is now 10 p.m. Do you know where Henry Kissinger is? + -- Elizabeth Carpenter +%% +It is now pitch dark. If you proceed, you will likely fall into a pit. +%% +It is one of the superstitions of the human mind +to have imagined that virginity could be a virtue. + -- Voltaire +%% +It is one thing to praise discipline, and another to submit to it. + -- Cervantes +%% +It is only by risking our persons from one hour to another that we live +at all. And often enough our faith beforehand in an uncertified result +is the only thing that makes the result come true. + -- William James +%% +It is only the man whose intellect is clouded by his sexual impulse that +could give the name of the fair sex to that undersized, narrow-shouldered, +broad-hipped, and short-legged race. + -- Schopenhauer +%% +It is only with the heart one can see clearly; +what is essential is invisible to the eye. + -- The Fox, 'The Little Prince" +%% +It is ridiculous to call this an industry. This is not. This is rat eat +rat, dog eat dog. I'll kill 'em, and I'm going to kill 'em before they +kill me. You're talking about the American way of survival of the fittest. + -- Ray Kroc, Founder of McDonald's +%% +It is said an Eastern monarch once charged his wise men to invent him a +sentence to be ever in view, and which should be true and appropriate +in all times and situations. They presented him the words: "And this, +too, shall pass away." + -- A. Lincoln +%% +It is said that the lonely eagle flies to the mountain peaks while the +lowly ant crawls the ground, but cannot the soul of the ant soar as +high as the eagle? +%% +It is so soon that I am done for, I wonder what I was begun for. + -- Epitaph, Cheltenham Churchyard +%% +It is so very hard to be an on-your-own-take-care-of- +yourself-because-there-is-no-one-else-to-do-it-for-you grown up. +%% +It is something to be able to paint a particular picture, or to carve a +statue, and so to make a few objects beautiful; but it is far more glorious +to carve and paint the very atmosphere and medium through which we look, +which morally we can do. To affect the quality of the day, that is the +highest of arts. Every man is tasked to make his life, even in its details, +worthy of the contemplation of his most elevated and critical hour. + -- Henry David Thoreau, "Where I Live" +%% +It is sweet to let the mind unbend on occasion. + -- Quintus Horatius Flaccus (Horace) +%% +It is the business of little minds to shrink. + -- Carl Sandburg +%% +It is the business of the future to be dangerous. + -- Hawkwind +%% +It is the nature of extreme self-lovers, as they will +set an house on fire, and it were but to roast their eggs. + -- Francis Bacon +%% +It is the wisdom of crocodiles, that shed tears when they would devour. + -- Francis Bacon +%% +It is the wise bird who builds his nest in a tree. +%% +It is through symbols that man consciously or unconsciously +lives, works and has his being. + -- Thomas Carlyle +%% +It is very vulgar to talk like a dentist when one isn't a dentist. +It produces a false impression. + -- Oscar Wilde. +%% +It is when I struggle to be brief that I become obscure. + -- Quintus Horatius Flaccus (Horace) +%% +It is wise to keep in mind that neither success nor failure is ever final. + -- Roger Babson +%% +It is your concern when your neighbor's wall is on fire. + -- Quintus Horatius Flaccus (Horace) +%% +It isn't easy being a Friday kind of person in a Monday kind of world. +%% +It looks like blind screaming hedonism won out. +%% +It looks like it's up to me to save our skins. +Get into that garbage chute, flyboy! + -- Princess Leia Organa +%% +It [marriage] happens as with cages: the birds without despair +to get in, and those within despair of getting out. + -- Michel Eyquem de Montaigne +%% +It may be better to be a live jackal than a dead lion, but it is +better still to be a live lion. And usually easier. + -- Lazarus Long +%% +It may or may not be worthwhile, but it still has to be done. +%% +It now costs more to amuse a child than it once did to educate his father. +%% +It occurred to me lately that nothing has occurred to me lately. +%% +It pays to be obvious, especially if you have a reputation for subtlety. +%% +It seems a little silly now, but this country +was founded as a protest against taxation. +%% +It seems the less a statesman amounts to, the more he loves the flag. + -- Frank Hubbard +%% +It seems to make an auto driver mad if he misses you. +%% +It takes a special kind of courage +to face what we all have to face. +%% +It takes all kinds to fill the freeways. + -- Crazy Charlie +%% +It takes both a weapon, and two people, to commit a murder. +%% +It takes less time to do a thing right +than it does to explain why you did it wrong. + -- H.W. Longfellow +%% +It takes two to tell the truth: one to speak and one to hear. +%% + It took 300 years to build and by the time it was 10% built, +everyone knew it would be a total disaster. But by then the investment +was so big they felt compelled to go on. Since its completion, it has +cost a fortune to maintain and is still in danger of collapsing. + There are at present no plans to replace it, since it was never +really needed in the first place. + I expect every installation has its own pet software which is +analogous to the above. + -- K.E. Iverson, on the Leaning Tower of Pisa +%% +It used to be the fun was in +The capture and kill. +In another place and time +I did it all for thrills. + -- Lust to Love +%% +It was Penguin lust... at its ugliest. +%% +It was a book to kill time for those who liked it better dead. +%% +It was a brave man that ate the first oyster. +%% +It was a female that drove me to drink +and I didn't even have the kindness to thank her. + -- R.E. Baber +%% +It was all so different before everything changed. +%% +It was kinda like stuffing the wrong card in a computer, +when you're stickin' those artificial stimulants in your arm. + -- Dion, noted computer scientist +%% +It was on the tip of my tongue to tell them about the deer, but I ended up +not doing it. That was one thing I kept to myself. I've never spoken or +written of it until just now, today. And I have to tell you that it seems +a lesser thing written down, damn near inconsequential. But for me it was +the best part of that trip, the cleanest part, and it was a moment I found +myself returning to, almost helplessly, when there was trouble in my life -- +my first day in the bush in Vietnam, and this fellow walked into the clearing +where we were with his hand over his nose and when he took his hand away there +was no nose there because it had been shot off; the time the doctor told us +our youngest son might be hydrocephalic (he turned out just to have an +oversized head, thank God); the long crazy weeks before my mother died. I +would find my thoughts turning back to that morning, the scuffed suede of +her ears, the white flash of her tail. But eight hundred million Red Chinese +don't give a shit, right? The most important things are the hardest to say, +because words diminish them. It's hard to make strangers care about the +good things in your life. + -- Stephen King, "The Body" +%% +It was pleasant to me to get a letter from you the other day. Perhaps +I should have found it pleasanter if I had been able to decipher it. I +don't think that I mastered anything beyond the date (which I knew) and +the signature (which I guessed at). There's a singular and a perpetual +charm in a letter of yours; it never grows old, it never loses its +novelty. Other letters are read and thrown away and forgotten, but +yours are kept forever -- unread. One of them will last a reasonable +man a lifetime. + -- Thomas Aldrich +%% +It was raining heavily, and the motorist had car trouble on a lonely country +road. Anxious to find shelter for the night, he walked over to a farmhouse +and knocked on the front door. No one responded. He could feel the water +from the roof running down the back of his neck as he stood on the stoop. +The next time he knocked louder, but still no answer. By now he was soaked +to the skin. Desperately he pounded on the door. At last the head of a +man appeared out of an upstairs window. + "What do you want?" he asked gruffly. + "My car broke down," said the traveler, "and I want to know if you +would let me stay here for the night." + "Sure," replied the man. "If you want to stay there all night, it's +okay with me." +%% + It was the next morning that the armies of Twodor marched east +laden with long lances, sharp swords, and death-dealing hangovers. The +thousands were led by Arrowroot, who sat limply in his sidesaddle, +nursing a whopper. Goodgulf, Gimlet, and the rest rode by him, praying +for their fate to be quick, painless, and if possible, someone else's. + Many an hour the armies forged ahead, the war-merinos bleating +under their heavy burdens and the soldiers bleating under their melting +icepacks. + -- "Bored of the Rings", The Harvard Lampoon +%% +It was wonderful to find America, but it +would have been more wonderful to miss it. + -- Mark Twain +%% +It would be nice to be sure of anything +the way some people are of everything. +%% +It'll be a nice world if they ever get it finished. +%% +It'll be just like Beggars Canyon back home. + -- Luke Skywalker +%% +It's a damn poor mind that can only think of one way to spell a word. + -- Andrew Jackson +%% +It's a funny thing that when a woman hasn't got anything +on earth to worry about, she goes off and gets married. +%% +It's a naive, domestic operating system without any +breeding, but I think you'll be amused by its presumption. +%% +It's a poor workman who blames his tools. +%% +It's all in the mind, ya know. +%% +"It's all so painfully empty and lonesome... I don't think I can stand +any more of it... the whole dreadful way we are born, die, and are +never missed. The fact there is *nobody*... nobody really... We come +out of a yawning tomb of flesh and sink back finally into another tomb. +What is the point of it all? Who thought up this sickening circle of +flesh and blood? We come into the world bleeding and cut and our bones +half-crushed only to emerge and suffer more torment, multilation, and +then at the last lie down in some hole in the ground forever. Who could +have thought it up, I wonder?" + -- James Purdy +%% +It's amazing how many people you could be friends +with if only they'd only make the first approach. +%% +It's amazing how much "mature wisdom" resembles being too tired. +%% +It's bad enough that life is a rat-race, +but why do the rats always have to win? +%% +It's better to burn out than it is to rust. +%% +It's better to burn out than to fade away. +%% +It's better to have loved and lost -- much better. +%% +It's business doing pleasure with you. +%% +It's clever, but is it art? +%% +It's difficult to see the picture when you are inside the frame. +%% +"It's easier said than done." + +... and if you don't believe it, try proving that it's easier done than +said, and you'll see that "it's easier said that `it's easier done than +said' than it is done", which really proves that "it's easier said than +done". +%% +It's easier to get forgiveness for being +wrong than forgiveness for being right. +%% +It's easier to take it apart than to put it back together. + -- Washlesky +%% +It's easy to forgive someone for being wrong; +it's much harder to forgive them for being right. +%% +It's fabulous! We haven't seen anything like it in the last half an hour! + -- Macy's +%% +It's faster horses, +Younger women, +Older whiskey and +More money. + -- Tom T. Hall, "The Secret of Life" +%% +It's from Casablanca. I've been waiting all my life to use that line. + -- Woody Allen, "Play It Again, Sam" +%% +It's getting uncommonly easy to kill people in large numbers, and the +first thing a principle does -- if it really is a principle -- is to +kill somebody. + -- Dorothy Sayers +%% +It's gonna be alright, +It's almost midnight, +And I've got two more bottles of wine. +%% + It's grad exam time... +COMPUTER SCIENCE + Inside your desk you'll find a listing of the DEC/VMS operating +system in IBM 1710 machine code. Show what changes are necessary to convert +this code into a UNIX Berkley 7 operating system. Prove that these fixes are +bug free and run correctly. You should gain at least 150% efficiency in the +new system. (You should take no more than 10 minutes on this question.) + +MATHEMATICS + If X equals PI times R^2, construct a formula showing how long +it would take a fire ant to drill a hole through a dill pickle, if the +length-girth ratio of the ant to the pickle were 98.17:1. + +GENERAL KNOWLEDGE +Describe the Universe. Give three examples. +%% + It's grad exam time... +MEDICINE + You have been provided with a razor blade, a piece of gauze, and a +bottle of Scotch. Remove your appendix. Do not suture until your work has +been inspected. (You have 15 minutes.) + +HISTORY + Describe the history of the papacy from its origins to the present +day, concentrating especially, but not exclusively, on its social, political, +economic, religious and philisophical impact upon Europe, Asia, America, and +Africa. Be brief, concise, and specific. + +BIOLOGY + Create life. Estimate the differences in subsequent human culture +if this form of life had been created 500 million years ago or earlier, with +special attention to its probable effect on the English parliamentary system. +%% +It's hard to be humble when you're perfect. +%% +It's hard to drive at the limit, but +it's harder to know where the limits are. + -- Stirling Moss +%% +It's hard to get ivory in Africa, but in Alabama the Tuscaloosa. + -- Groucho Marx +%% +It's hard to keep your shirt on when +you're getting something off your chest. +%% +It's important that people know what you stand for. +It's more important that they know what you won't stand for. +%% +It's interesting to think that many quite +distinguished people have bodies similar to yours. +%% +It's is not, it isn't ain't, and it's it's, not its, if you mean it is. +If you don't, it's its. Then too, it's hers. It isn't her's. It isn't +our's either. It's ours, and likewise yours and theirs. + -- Oxford University Press, "Edpress News" +%% +It's just apartment house rules, +So all you 'partment house fools +Remember: one man's ceiling is another man's floor. +One man's ceiling is another man's floor. + -- Paul Simon, "One Man's Ceiling Is Another Man's Floor" +%% +It's later than you think. +%% +It's later than you think, the joint +Russian-American space mission has already begun. +%% +It's lucky you're going so slowly, because +you're going in the wrong direction. +%% +Its name is Public Opinion. It is held in reverence. +It settles everything. Some think it is the voice of God. + -- Mark Twain +%% +It's no use crying over spilt milk -- it only makes it salty for the cat. +%% +It's not Camelot, but it's not Cleveland, either. + -- Kevin White, Mayor of Boston +%% +It's not against any religion to want to dispose of a pigeon. + -- Tom Lehrer +%% +It's not easy being green. + -- Kermit +%% +It's not enough to be Hungarian; you must have talent too. + -- Alexander Korda +%% +It's not hard to admit errors that are [only] cosmetically wrong. + -- J.K. Galbraith +%% +It's not pretty being easy. +%% +It's not reality that's important, but how you perceive things. +%% +It's not that I'm afraid to die. +I just don't want to be there when it happens. + -- Woody Allen +%% +It's not whether you win or lose but how you played the game. + -- Grantland Rice +%% +It's not whether you win or lose, it's how you look playing the game. +%% +It's only by NOT taking the human race seriously that I retain +what fragments of my once considerable mental powers I still possess. + -- Roger Noe +%% +It may be that your whole purpose in life +is simply to serve as a warning to others. +%% +It's pretty hard to tell what does bring happiness; +poverty and wealth have both failed. + -- Kim Hubbard +%% +It's really quite a simple choice: Life, Death, or Los Angeles. +%% +It's so confusing choosing sides in the heat of the moment, + just to see if it's real, +Oooh, it's so erotic having you tell me how it should feel, +But I'm avoiding all the hard cold facts that I got to face, +So ask me just one question when this magic night is through, +Could it have been just anyone or did it have to be you? + -- Billy Joel, "Glass Houses" +%% +It's sort of a threat, you see. I've never been very +good at them myself but I'm told they can be very effective. +%% +It's sweet to be remembered, but it's often cheaper to be forgotten. +%% +It's ten o'clock; do you know where your processes are? +%% +It's very inconvenient to be mortal -- you never +know when everything may suddenly stop happening. +%% +I've Been Moved! +%% +I've already told you more than I know. +%% +I've been told that it's far more sensous to have a woman leave +something on rather than being totally nude. Myself, I've always +felt that the lights were more than enough. +%% +I've always considered statesmen to be more expendable than soldiers. +%% +I've always made it a solemn practice to never +drink anything stronger than tequila before breakfast. + -- R. Nesson +%% +I've been on this lonely road so long, +Does anybody know where it goes, +I remember last time the signs pointed home, +A month ago. + -- Carpenters, "Road Ode" +%% +I've been there. +%% +I've given up reading books; I find it takes my mind off myself. +%% +I've got a very bad feeling about this. + -- Han Solo +%% +I've had one child. My husband wants to have another. +I'd like to watch him have another. +%% +I've looked at the listing, and it's right! + -- Joel Halpern. +%% +I've never been canoeing before, but I imagine there must +be just a few simple heuristics you have to remember... + +Yes, don't fall out, and don't hit rocks. +%% +I've never been hurt by anything I didn't say. + -- Calvin Coolidge +%% +I've noticed several design suggestions in your code. +%% +I've only got 12 cards. +%% +JOB INTERVIEW: + The excruciating process during which personnel officers + separate the wheat from the chaff -- then hire the chaff. +%% +JOGGER: + An odd sort of person with a thing for pain. +%% +JUSTICE: + A decision in your favor. +%% +Jacquin's Postulate on Democratic Government: + No man's life, liberty, or property + are safe while the legislature is in session. +%% +Jealousy is all the fun you think they have. +%% +Jenkinson's Law: + It won't work. +%% +Jesus Saves, +Moses Invests, +But only Buddha pays Dividends. +%% +Jim Nasium's Law: + In a large locker room with hundreds of lockers, the few people + using the facility at any one time will all have lockers next to + each other so that everybody is cramped. +%% +Jim, it's Grace at the bank. I checked your Christmas Club account. +You don't have five-hundred dollars. You have fifty. Sorry, computer foul-up! +%% +Jim, it's Jack. I'm at the airport. I'm going to Tokyo and wanna pay +you the five-hundred I owe you. Catch you next year when I get back! +%% +Jim, this is Janelle. I'm flying tonight, so I can't make our date, and +I gotta find a safe place for Daffy. He loves you, Jim! It's only two +days, and you'll see. Great Danes are no problem! +%% +Jim, this is Matty down at Ralph's and Mark's. Some guy named Angel +Martin just ran up a fifty buck bar tab. And now he wants to charge it +to you. You gonna pay it? +%% +Joe Cool always spends the first two weeks at college sailing his frisbee. + -- Snoopy +%% +Joe's sister puts spaghetti in her shoes! +%% +John the Baptist after poisoning a thief, +Looks up at his hero, the Commander-in-Chief, +Saying tell me great leader, but please make it brief +Is there a hole for me to get sick in? +The Commander-in-Chief answers him while chasing a fly, +Saying death to all those who would whimper and cry. +And dropping a barbell he points to the sky, +Saying the sun is not yellow, it's chicken. + -- Bob Dylan, "Tombstone Blues" +%% +John Dame May Oscar +Was Gay Was Whitty Was Wilde +But Gerard Hopkins But John Greenleaf But Thornton +Was Manley Was Whittier Was Wilder + -- Willard Espy +%% +Johnson's First Law: + When any mechanical contrivance fails, it will do so at the + most inconvenient possible time. +%% +Johnson's law: + Systems resemble the organizations that create them. +%% +Join the Navy; travel to far-off exotic lands, +meet exciting interesting people, and kill them. +%% +Jones' First Law: + Anyone who makes a significant contribution to any field of + endeavor, and stays in that field long enough, becomes an + obstruction to its progress -- in direct proportion to the + importance of their original contribution. +%% +Jones' Law: + Friends may come and go, but enemies accumulate. +%% +Jones' Second Law: + The man who smiles when things go wrong has thought of someone + to blame it on. +%% +Joshu: What is the true Way? +Nansen: Every way is the true Way. +J: Can I study it? +N: The more you study, the further from the Way. +J: If I don't study it, how can I know it? +N: The Way does not belong to things seen: nor to things unseen. + It does not belong to things known: nor to things unknown. Do + not seek it, study it, or name it. To find yourself on it, open + yourself as wide as the sky. +%% +Journalism is literature in a hurry. + -- Matthew Arnold +%% +Journalism will kill you, but it will +keep you alive while you're at it. +%% +Juall's Law on Nice Guys: + Nice guys don't always finish last; sometimes they don't finish. + Sometimes they don't even get a chance to start! +%% +Just a song before I go, Going through security +To whom it may concern, I held her for so long. +Traveling twice the speed of sound She finally looked at me in love, +It's easy to get burned. And she was gone. +When the shows were over Just a song before I go, +We had to get back home, A lesson to be learned. +And when we opened up the door Traveling twice the speed of sound +I had to be alone. It's easy to get burned. +She helped me with my suitcase, +She stands before my eyes, +Driving me to the airport +And to the friendly skies. + -- Crosby, Stills, Nash, "Just a Song Before I Go" +%% +Just as I cannot remember any time when I could not read and write, I cannot +remember any time when I did not exercise my imagination in daydreams about +women. + -- G.B. Shaw +%% +Just because he's dead is no reason to lay off work. +%% +Just because the message may never be +received does not mean it is not worth sending. +%% +Just because you like my stuff doesn't mean I owe you anything. + -- Bob Dylan +%% +Just because your doctor has a name for your +condition doesn't mean he knows what it is. +%% +Just because you're paranoid doesn't mean they AREN'T after you. +%% +Just close your eyes, tap your heels together three times, +and think to yourself, `There's no place like home.' + -- Glynda +%% +Just give Alice some pencils and she will stay busy for hours. +%% +Just machines to make big decisions, +Programmed by men for compassion and vision, +We'll be clean when their work is done, +We'll be eternally free, yes, eternally young, +What a beautiful world this will be, +What a glorious time to be free. + -- Donald Fagon, "What A Beautiful World" +%% +Just once, I wish we would encounter +an alien menace that wasn't immune to bullets. + -- The Brigader, "Dr. Who" +%% +Just once I would like to persuade the audience not to wear any article of +blue denim. If only they could see themselves in a pair of brown corduroys +like mine instead of this awful, boring blue denim. I don't enjoy the sky +or sea as much as I used to because of this Levi character. If Jesus Christ +came back today, He and I would get into our brown corduroys and go to the +nearest jean store and overturn the racks of blue denim. Then we'd get +crucified in the morning. + -- Ian Anderson, of Jethro Tull +%% +Just to have it is enough. +%% +Just weigh your own hurt against the hurt +of all the others, and then do what's best. + -- Lovers and Other Strangers +%% +Just yesterday morning, they let me know you were gone, +Suzanne, the plans they made put an end to you, +I went out this morning and I wrote down this song, +Just can't remember who to send it to... + +Oh, I've seen fire and I've seen rain, +I've seen sunny days that I thought would never end, +I've seen lonely times when I could not find a friend, +But I always thought that I'd see you again. +Thought I'd see you one more time again. + -- James Taylor, "Fire and Rain" +%% +Justice is incidental to law and order. + -- J. Edgar Hoover +%% +KANSAS: + Where the men are men and so are the women! +%% +KERNEL: + A part of an operating system that preserves the medieval + traditions of sorcery and black art. +%% +KIN: + An affliction of the blood. +%% +KLEPTOMANIAC: + A rich thief. +%% +KNOWLEDGE: + Things you believe. +%% +Katz' Law: + Men and nations will act rationally when + all other possibilities have been exhausted. +%% +Kaufman's First Law of Party Physics: + Population density is inversely proportional + to the square of the distance from the keg. +%% +Kaufman's Law: + A policy is a restrictive document to prevent a recurrence + of a single incident, in which that incident is never mentioned. +%% +Keep America beautiful. Swallow your beer cans. +%% +Keep ancient lands, your storied pomp! cries she +With silent lips. Give me your tired, your poor, +Your huddled masses yearning to breathe free, +The wretched refuse of your teeming shore. +Send these, the homeless, tempest-tossed to me... + -- Emma Lazarus, "The New Colossus" +%% +Keep emotionally active. Cater to your favorite neurosis. +%% +Keep grandma off the streets -- legalize bingo. +%% +Keep in mind always the four constant Laws of Frisbee: + 1) The most powerful force in the world is that of a disc + straining to land under a car, just out of reach (this + force is technically termed "car suck"). + 2) Never precede any maneuver by a comment more predictive + than "Watch this!" + 3) The probability of a Frisbee hitting something is directly + proportional to the cost of hitting it. For instance, a + Frisbee will always head directly towards a policeman or + a little old lady rather than the beat up Chevy. + 4) Your best throw happens when no one is watching; when the + cute girl you've been trying to impress is watching, the + Frisbee will invariably bounce out of your hand or hit you + in the head and knock you silly. +%% +Keep it short for pithy sake. +%% +Keep on keepin' on. +%% +Keep patting your enemy on the back until a +small bullet hole appears between your fingers. + -- Joe Bonanno +%% +Keep the number of passes in a compiler to a minimum. + -- D. Gries +%% +Keep the phase, baby. +%% +Keep up the good work! But please don't ask me to help. +%% +Keep women you cannot. Marry them and they come to hate the way +you walk across the room; remain their lover, and they jilt you +at the end of six months. + -- Moore +%% +Keep your Eye on the Ball, +Your Shoulder to the Wheel, +Your Nose to the Grindstone, +Your Feet on the Ground, +Your Head on your Shoulders. +Now... try to get something DONE! +%% +Keep your laws off my body! +%% +Keep your mouth shut and people will think you stupid; +Open it and you remove all doubt. +%% +Kennedy's Market Theorem: + Given enough inside information and unlimited credit, + you've got to go broke. +%% +Kerr's Three Rules for a Successful College: + Have plenty of football for the alumni, sex + for the students, and parking for the faculty. +%% +Kettering's Observation: + Logic is an organized way of going wrong with confidence. +%% +Kill Kill, +Hate Hate, +Murder, Maim, and Mutilate! +%% +Kill a commy for your mommy. +%% +Kill 'em all, and let God sort 'em out. +%% +Kilroe hic erat! +%% +Kime's Law for the Reward of Meekness: + Turning the other cheek merely ensures two bruised cheeks. +%% +Kindness is a language which the deaf can hear and the blind can read. + -- Mark Twain +%% +Kindness is the beginning of cruelty. + -- Muad'dib +%% +Kington's Law of Perforation: + If a straight line of holes is made in a piece of paper, such + as a sheet of stamps or a check, that line becomes the strongest + part of the paper. +%% +Kinkler's First Law: + Responsibility always exceeds authority. + +Kinkler's Second Law: + All the easy problems have been solved. +%% +Kirk to Enterprise... +%% +Kirk to Enterprise -- beam down yeoman Rand and a six-pack. +%% +Kiss me, Kate, we will be married o' Sunday. + -- William Shakespeare, "The Taming of the Shrew" +%% +Kiss me twice. I'm schizophrenic. +%% +Kiss your keyboard goodbye! +%% +Kissing a fish is like smoking a bicycle. +%% +Kissing a smoker is like licking an ashtray. +%% +Kitchen activity is highlighted. +Butter up a friend. +%% +Kites rise highest against the wind -- not with it. + -- Winston Churchill +%% +Klatu barada nikto. +%% +Kleeneness is next to Godelness. +%% +Klein bottle for rent -- inquire within. +%% +Kliban's First Law of Dining: + Never eat anything bigger than your head. +%% +Klingon phaser attack from front!!!!! +100% Damage to life support!!!! +%% +Knock, knock! + Who's there? +Sam and Janet. + Sam and Janet who? +Sam and Janet Evening... +%% +Knocked, you weren't in. + -- Opportunity +%% +Know Thy User. +%% +Know how to save 5 drowning lawyers? + +-- No? + +GOOD! +%% +Know thyself. If you need help, call the C.I.A. +%% +Know what I hate most? Rhetorical questions. + -- Henry N. Camp +%% +Knowledge is power. + -- Francis Bacon +%% +Knowledge without common sense is folly. +%% +LABOR: + One of the processes by which A acquires property for B. +%% +LASER: + Failed death ray. +%% +LA: + Where the only way to determine that the seasons have changed + is to note that people have changed the main topic of conversation. + From mud slides to brush fires. +%% +LAZY: + Marrying a pregnant woman. +%% +LEARNING CURVE: + An astonishing new theory, discovered by management consultants + in the 1970's, asserting that the more you do something the + quicker you can do it. +%% +LEO (July 23 - Aug 22) + You consider yourself a born leader. Others think you are pushy. + Most Leo people are bullies. You are vain and dislike honest + criticism. Your arrogance is disgusting. Leo people are thieves. +%% +LEO (July 23 - Aug 22) + Your determination and sense of humor will come to the fore. Your + ability to laugh at adversity will be a blessing because you've got + a day coming you wouldn't believe. As a matter of fact, if you can + laugh at what happens to you today, you've got a sick sense of humor. +%% +LEVERAGE: + Even if someone doesn't care what the world thinks + about them, they always hope their mother doesn't find out. +%% +LIAR: + A lawyer with a roving commission. +%% +LIAR: + One who tells an unpleasant truth. +%% +LIBERAL: + Someone too poor to be a capitalist and too rich to be a communist. +%% +LIBRA (Sept 23 - Oct 23) + Major achievements, new friends, and a previously unexplored way + to make a lot of money will come to a lot of people today, but + unfortunately you won't be one of them. Consider not getting out + of bed today. +%% +LIE: + A very poor substitute for the truth, + but the only one discovered to date. +%% +LIFE: + A whim of several billion cells to be you for a while. +%% +LIFE: + Learning about people the hard way -- by being one. +%% +LIFE: + That brief interlude between nothingness and eternity. +%% +LIGHTHOUSE: + A tall building on the seashore in which the government + maintains a lamp and the friend of a politician. +%% +LIKE: + When being alive at the same time is a wonderful coincidence. +%% +LISP: + To call a spade a thpade. +%% +LIVING YOUR LIFE: + A task so difficult, it has never been attempted before. +%% +LOGO for the Dead + +LOGO for the Dead lets you continue your computing activities from +"The Other Side." + +The package includes a unique telecommunications feature which lets you +turn your TRS-80 into an electronic Ouija board. Then, using Logo's +graphics capabilities, you can work with a friend or relative on this +side of the Great Beyond to write programs. The software requires that +your body be hardwired to an analog-to-digital converter, which is then +interfaced to your computer. A special terminal (very terminal) program +lets you talk with the users through Deadnet, an EBBS (Ectoplasmic +Bulletin Board System). + +LOGO for the Dead is available for 10 percent of your estate +from NecroSoft inc., 6502 Charnelhouse Blvd., Cleveland, OH 44101. + -- '80 Microcomputing +%% +LOVE: + I'll let you play with my life if you'll let me play with yours. +%% +LOVE: + Love ties in a knot in the end of the rope. +%% +LOVE: + When, if asked to choose between your lover + and happiness, you'd skip happiness in a heartbeat. +%% +LOVE: + When it's growing, you don't mind watering it with a few tears. +%% +LOVE: + When you don't want someone too close-- + because you're very sensitive to pleasure. +%% +LOVE: + When you like to think of someone on days that begin with a morning. +%% +LSD melts in your mind, not in your hand. +%% +LUNATIC ASYLUM: + The place where optimism most flourishes. +%% +Lack of capability is usually disguised by lack of interest. +%% +Lack of money is the root of all evil. + -- George Bernard Shaw +%% +Lackland's Laws: + 1. Never be first. + 2. Never be last. + 3. Never volunteer for anything. +%% +La-dee-dee, la-dee-dah. +%% +Ladies and Gentlemen, Hobos and Tramps, +Cross-eyed mosquitos and bowlegged ants, +I come before you to stand behind you +To tell you of something I know nothing about. +Next Thursday (which is good Friday), +There will be a convention held in the +Women's Club which is strictly for Men. +Admission is free, pay at the door, +Pull up a chair, and sit on the floor. +It was a summer's day in winter, +And the snow was raining fast, +As a barefoot boy with shoes on, +Stood sitting in the grass. +Oh, that bright day in the dead of night, +Two dead men got up to fight. +Three blind men to see fair play, +Forty mutes to yell "Hooray"! +Back to back, they faced each other, +Drew their swords and shot each other. +A deaf policeman heard the noise, +Came and arrested those two dead boys. +%% +Lady Astor: "If you were my husband, I'd poison your coffee." +Winston Churchill: "If you were my wife, I'd drink it." +%% +Lady Luck brings added income today. +Lady friend takes it away tonight. +%% +Laetrile is the pits. +%% +Laissez Faire Economics is the theory that if +each acts like a vulture, all will end as doves. +%% +Lake Erie died for your sins. +%% +Lamonte Cranston once hired a new Chinese manservant. While describing his +duties to the new man, Lamonte pointed to a bowl of candy on the coffee +table and warned him that he was not to take any. Some days later, the new +manservant was cleaning up, with no one at home, and decided to sample some +of the candy. Just than, Cranston walked in, spied the manservant at the +candy, and said: + "Pardon me Choy, is that the Shadow's nugate you chew?" +%% +Larkinson's Law: + All laws are basically false. +%% +Last night I met upon the stair +a little man who wasn't there. +He wasn't there again today. +Gee how I wish he'd go away! +%% +Last week I saw a girl in a sweater so tight I could hardly breathe. +%% +Last week's pet, this week's special. +%% +Laugh, and the world ignores you. Crying doesn't help either. +%% +Laugh and the world thinks you're an idiot. +%% +Laugh at your problems: everybody else does. +%% +Laugh when you can; cry when you must. +%% +Laura's Law: + No child throws up in the bathroom. +%% +Lavish spending can be disastrous. +Don't buy any lavishes for a while. +%% +Law enforcement officers should use only the minimum +force necessary in dealing with disorders when they arise. + -- Richard M. Nixon +%% +Law of Communications: + The inevitable result of improved and enlarged communications + between different levels in a hierarchy is a vastly increased + area of misunderstanding. +%% +Law of Continuity: + Experiments should be reproducible. + They should all fail the same way. +%% +Law of Probable Dispersal: + Whatever it is that hits the fan will not be evenly distributed. +%% +Law of Procrastination: + Procrastination avoids boredom; one never has + the feeling that there is nothing important to do. +%% +Law of Selective Gravity: + An object will fall so as to do the most damage. + +Jenning's Corollary: + The chance of the bread falling with the buttered side + down is directly proportional to the cost of the carpet. + +Law of the Perversity of Nature: + You cannot determine beforehand which side of the bread to butter. +%% +Law stands mute in the midst of arms. + -- Marcus Tullius Cicero +%% +Lawful Dungeon Master -- and they're MY laws! +%% +Lawrence Radiation Laboratory keeps all its data in an old gray trunk. +%% +Laws of Computer Programming: + 1. Any given program, when running, is obsolete. + 2. Any given program costs more and takes longer. + 3. If a program is useful, it will have to be changed. + 4. If a program is useless, it will have to be documented. + 5. Any given program will expand to fill all available memory. + 6. The value of a program is proportional the weight of its output. + 7. Program complexity grows until it exceeds the capability of + the programmer who must maintain it. +%% +LAWSUIT: + A machine which you go into as a pig and come out as a sausage. + -- Ambrose Bierce +%% +Lay on, MacDuff, and curs'd be him who first cries, "Hold, enough!". + -- Shakespeare +%% +Lays eggs inside a paper bag; +The reason, you will see, no doubt, +Is to keep the lightning out. +But what these unobservant birds +Have failed to notice is that herds +Of bears may come with buns +And steal the bags to hold the crumbs. +%% +Lazlo's Chinese Relativity Axiom: + No matter how great your triumphs or how tragic your defeats -- + approximately one billion Chinese couldn't care less. +%% +Leadership involves finding a parade and getting in front of it; what +is happening in America is that those parades are getting smaller and +smaller -- and there are many more of them. + -- John Naisbitt, "Megatrends" +%% +Learn from other people's mistakes, you don't have time to make your own. +%% +Learn to pause -- or nothing worthwhile can catch up to you. +%% +Learned men are the cisterns of knowledge, not the fountainheads. +%% +Learning at some schools is like drinking from a firehose. +%% +Learning without thought is labor lost; +thought without learning is perilous. + -- Confucius +%% +Leave no stone unturned. + -- Euripides +%% +Lee's Law: + Mother said there would be days like this, + but she never said that there'd be so many! +%% +Left to themselves, things tend to go from bad to worse. +%% +Leibowitz's Rule: + When hammering a nail, you will never hit your + finger if you hold the hammer with both hands. +%% +Lend money to a bad debtor and he will hate you. +%% +Lensmen eat Jedi for breakfast. +%% + Leslie West heads for the sticks, to Providence, Rhode Island and +tries to hide behind a beard. No good. There are still too many people +and too many stares, always taunting, always smirking. He moves to the +outskirts of town. He finds a place to live -- huge mansion, dirt cheap, +caretaker included. He plugs in his guitar and plays as loud as he wants, +day and night, and there's no one to laugh or boo or even look bored. + Nobody's cut the grass in months. What's happened to that caretaker? +What neighborhood people there are start to talk, and what kids there are +start to get curious. A 13 year-old blond with an angelic face misses supper. +Before the summer's end, four more teenagers have disappeared. The senior +class president, Barnard-bound come autumn, tells Mom she's going out to a +movie one night and stays out. The town's up in arms, but just before the +police take action, the kids turn up. They've found a purpose. They go +home for their stuff and tell the folks not to worry but they'll be going +now. They're in a band. + -- Ira Kaplan +%% +Let a fool hold his tongue and he will pass for a sage. + -- Publilius Syrus +%% +Let he who takes the plunge remember to return it by Tuesday. +%% +Let him choose out of my files, his projects to accomplish. + -- Shakespeare, "Coriolanus" +%% +Let me take you a button-hole lower. + -- William Shakespeare, "Love's Labour's Lost" +%% +Let no guilty man escape. + -- U.S. Grant +%% +Let not the sands of time get in your lunch. +%% +Let sleeping dogs lie. + -- Charles Dickens +%% +Let the machine do the dirty work. + -- "Elements of Programming Style", Kernighan and Ritchie +%% +Let the worthy citizens of Chicago get their liquor the best way +they can. I'm sick of the job. It's a thankless one and full of grief. + -- Capone +%% +Let us go, through certain half-deserted streets, +The muttering retreats +Of restless nights in one-night cheap hotels +And sawdust restaurants with oyster-shells: +Streets that follow like a tedious argument +Of insidious intent +To lead you to an overwhelming question... +Oh, do not ask, "What is it?" + -- T.S. Eliot, "Love song of J. Alfred Prufrock" +%% +Let us never negotiate out of fear, +but let us never fear to negotiate. + -- John F. Kennedy +%% +Let us not look back in anger or forward +in fear, but around us in awareness. + -- James Thurber +%% +Let us remember that ours is a nation of lawyers and order. +%% +Let us treat men and women well; +Treat them as if they were real; +Perhaps they are. + -- Ralph Waldo Emerson +%% +Let your conscience be your guide. + -- Pope +%% +Let's just be friends and make no special +effort to ever see each other again. +%% +Let's not complicate our relationship +by trying to communicate with each other. +%% +Let's organize this thing and take all the fun out of it. +%% +Leveraging always beats prototyping. +%% +Lewis's Law of Travel: + The first piece of luggage out of the + chute doesn't belong to anyone, ever. +%% +Liberals are the first to dump you if you con them or get into +trouble. Conservatives are better. They never run out on you. + -- Joseph "Crazy Joe" Gallo +%% +Lieberman's Law: + Everybody lies, but it doesn't matter since nobody listens. +%% +Lies! All lies! You're all lying against my boys! + -- Ma Barker +%% +Life -- Love It or Leave It. +%% +Life Sucks. Cynical, misanthropic male, 34, looking for soul mate but +certain not to find her. Drop me a note. I'll call you, we'll talk and +I'll ask you out to dinner where I'll probably spend more than I can +afford in a feeble attempt to impress you. Then we'll realize we have +absolutely nothing in common and we'll go our separate ways, more +embittered and depressed than before (if such a thing is possible). +%% +Life begins at the centerfold and expands outward. + -- Miss November, 1966 +%% +Life can be so tragic -- you're here today and here tomorrow. +%% +Life exists for no known purpose. +%% +Life is a game. In order to have a game, something has to be more +important than something else. If what already is, is more important +than what isn't, the game is over. So, life is a game in which what +isn't, is more important than what is. Let the good times roll. + -- Werner Erhard +%% +Life is a game of bridge -- and you've just been finessed. +%% +Life is a hospital in which every patient +is possessed by the desire to change his bed. +%% +Life is a series of rude awakenings. + -- R.V. Winkle +%% +Life is a serious burden, which no thinking, +humane person would wantonly inflict on someone else. + -- Clarence Darrow +%% +Life is a yo-yo, and mankind ties knots in the string. +%% +Life is an exciting business, and most +exciting when it is lived for others. +%% +Life is both difficult and time consuming. +%% +Life is difficult because it is non-linear. +%% +Life is fraught with opportunities to keep your mouth shut. +%% +Life is just a bowl of cherries, but why do I always get the pits? +%% +Life is like a 10 speed bicycle. Most of us have gears we never use. + -- C. Schultz +%% +Life is like a diaper - short and loaded. +%% +Life is like a sewer. +What you get out of it depends on what you put into it. + -- Tom Lehrer +%% +Life is like a tin of sardines. +We're, all of us, looking for the key. + -- Beyond the Fringe +%% +Life is like an egg stain on your chin -- +you can lick it, but it still won't go away. +%% +Life is like an onion: you peel it off +one layer at a time, and sometimes you weep. + -- Carl Sandburg +%% +Life is like an onion: you peel off layer after +layer, then you find there is nothing in it. +%% +Life is like bein' on a mule team. Unless you're +the lead mule, all the scenery looks about the same. +%% +Life is not for everyone. +%% +Life is one long struggle in the dark. + -- Titus Lucretius Carus +%% +Life is the childhood of our immortality. + -- Goethe +%% +Life is the living you do, +Death is the living you don't do. + -- Joseph Pintauro +%% +Life is the urge to ecstasy. +%% +Life is to you a dashing and bold adventure. +%% +Life is too short to be taken seriously. + -- O. Wilde +%% +Life is wasted on the living. + -- The Restaurant at the Edge of the Universe. +%% +Life may have no meaning, or, even worse, +it may have a meaning of which you disapprove. +%% +Life only demands from you the strength you possess. +Only one feat is possible -- not to have run away. + -- Dag Hammarskjold +%% +Life without caffeine is stimulating enough. + -- Sanka Ad +%% +Life would be tolerable but for its amusements. + -- G.B. Shaw +%% +Lift every voice and sing +Till earth and heaven ring, +Ring with the harmonies of Liberty; +Let our rejoicing rise +High as the listening skies, +Let it resound loud as the rolling sea. + +Sing a song full of the faith that the dark past has taught us. +Sing a song full of the hope that the present has bought us. +Facing the rising sun of our new day begun, +Let us march on till victory is won. + -- James Weldon Johnson +%% +Lighten up, while you still can, +Don't even try to understand, +Just find a place to make your stand, +And take it easy. + -- The Eagles, "Take It Easy" +%% +Like all young men, you greatly exaggerate +the difference between one young woman and another. + -- George Bernard Shaw, "Major Barbara" +%% +Like corn in a field I cut you down, +I threw the last punch way too hard, +After years of going steady, well, I thought it was time, +To throw in my hand for a new set of cards. +And I can't take you dancing out on the weekend, +I figured we'd painted too much of this town, +And I tried not to look as I walked to my wagon, +And I knew then I had lost what should have been found, +I knew then I had lost what should have been found. + And I feel like a bullet in the gun of Robert Ford + I'm as low as a paid assassin is + You know I'm cold as a hired sword. + I'm so ashamed we can't patch it up, + You know I can't think straight no more + You make me feel like a bullet, honey, + a bullet in the gun of Robert Ford. + -- Elton John "I Feel Like a Bullet" +%% +Like punning, programming is a play on words. +%% +Like so many Americans, she was trying to construct +a life that made sense from things she found in gift shops. + -- Kurt Vonnegut, Jr. +%% +Like the ski resort of girls looking for husbands and husbands +looking for girls, the situation is not as symmetrical as it might seem. + -- Alan McKay +%% +Like the time I ran away... +And turned around and you were standing close to me. + -- YES, "Going For The One/Awaken" +%% +Like winter snow on summer lawn, time past is time gone. +%% +Limericks are art forms complex, +Their topics run chiefly to sex. + They usually have virgins, + And masculine urgin's, +And other erotic effects. +%% +"Lines that are parallel meet at Infinity!" +Euclid repeatedly, heatedly, urged. + +Until he died, and so reached that vicinity: +in it he found that the damned things diverged. + -- Piet Hein +%% +Linus' Law: + There is no heavier burden than a great potential. +%% +Linus: Hi! I thought it was you. + I've been watching you from way off... You're looking great! +Snoopy: That's nice to know. + The secret of life is to look good at a distance. +%% +Linus: I guess it's wrong always to be worrying about tomorrow. + Maybe we should think only about today. +Charlie Brown: + No, that's giving up. I'm still hoping that yesterday + will get better. +%% +Lions in the street and roaming, +Dogs in heat, rabid, foaming, +A beast caged in the heart of the city. +The body of his mother lying in the summer ground, +He fled the town. +Went down south across the border, +Left the chaos and disorder +Back there, over his shoulder. +One morning he awoke in a green hotel, +A strange creature groaning beside him. +Sweat oozed from its shiny skin. +Is everybody in? The ceremony is about to begin. + -- Jim Morrison, "Celebration of the Lizard" +%% +Lisp, Lisp, Lisp Machine, +Lisp Machine is Fun. +Lisp, Lisp, Lisp Machine, +Fun for everyone. +%% +Lisp Users: +Due to the holiday next Monday, there will be no garbage collection. +%% +Lisp programmers do it deeper and deeper and deeper. +%% + Listen, Tyrone, you don't know how dangerous that stuff is. +Suppose someday you just plug in and go away and never come back? Eh? + Ho, ho! Don't I wish! What do you think every electrofreak +dreams about? You're such an old fuddyduddy! A-and who sez it's a +dream, huh? M-maybe it exists. Maybe there is a Machine to take us +away, take us completely, suck us out through the electrodes out of +the skull 'n' into the Machine and live there forever with all the +other souls it's got stored there. It could decide who it would suck +out, a-and when. Dope never gave you immortality. You hadda come +back, every time, into a dying hunk of smelly meat! But We can live +forever, in a clean, honest, purified, Electroworld. + -- Thomas Pynchon, "Gravity's Rainbow" +%% +Littering is dumb. + -- Ronald Macdonald +%% +Little Mary on the ice, +Went out to have a frisk, +Now wasn't little Mary nice, +Her pretty *? +%% +Little girls, like butterflies, need no excuse. + -- Lazarus Long +%% +Live fast, die young, and leave a good looking corpse. + -- James Dean +%% +Live from New York ... It's Saturday Night! +%% +Live in a world of your own, but always welcome visitors. +%% +Live never to be ashamed if anything you do or say is +published around the world -- even if what is published is not true. + -- Messiah's Handbook : Reminders for the Advanced Soul +%% +Living in Hollywood is like living in a bowl of granola. +What ain't fruits and nuts is flakes. +%% +Living in New York City gives people real incentives +to want things that nobody else wants. + -- Andy Warhol +%% +Living in the complex world of the future is somewhat +like having bees live in your head. But, there they are. +%% +Living on Earth may be expensive, but it +includes an annual free trip around the Sun. +%% +Lizzie Borden took an axe, +And plunged it deep into the VAX; +Don't you envy people who +Do all the things YOU want to do? +%% +Lo! Men have become the tool of their tools. + -- Henry David Thoreau +%% +Lockwood's Long Shot: + The chances of getting eaten up by a lion on Main Street + aren't one in a million, but once would be enough. +%% +Logic doesn't apply to the real world. + -- Marvin Minsky +%% +Logic is a little bird, sitting in a tree, that smells AWFUL. +%% +Logic is a pretty flower that smells bad. +%% +Logic is a systematic method of coming +to the wrong conclusion with confidence. +%% +Logic is the chastity belt of the mind! +%% +Loneliness is a terrible price to pay for independence. +%% +Lonely is a man without love. + -- Englebert Humperdinck +%% +Lonely men seek companionship. +Lonely women sit at home and wait. They never meet. +%% +Lonesome? + +Like a change? +Like a new job? +Like excitement? +Like to meet new and interesting people? + +JUST SCREW-UP ONE MORE TIME!!!!!!! +%% +Long ago I proposed that unsuccessful candidates for the Presidency +be quietly hanged, as a matter of public sanitation and decorum. +The sight of their grief must have a very evil effect upon the young. + -- H.L. Mencken, "A Carnival of Buncombe" +%% + Long ago, in a finite state far away, there lived a JOVIAL +character named Jack. Jack and his relations were poor. Often their +hash table was bare. One day Jack's parent said to him, "Our matrices +are sparse. You must go to the market to exchange our RAM for some +BASICs." She compiled a linked list of items to retrieve and passed it +to him. + So Jack set out. But as he was walking along a Hamilton path, +he met the traveling salesman. + "Whither dost thy flow chart take thou?" prompted the salesman +in high-level language. + "I'm going to the market to exchange this RAM for some chips +and Apples," commented Jack. + "I have a much better algorithm. You needn't join a queue +there; I will swap your RAM for these magic kernels now." + Jack made the trade, then backtracked to his house. But when +he told his busy-waiting parent of the deal, she became so angry she +started thrashing. + "Don't you even have any artificial intelligence? All these +kernels together hardly make up one byte," and she popped them out the +window... + -- Mark Isaak, "Jack and the Beanstack" +%% +Long computations which yield zero are probably all for naught. +%% +Long life is in store for you. +%% +Long were the days of pain I have spent within its walls, and +long were the nights of aloneness; and who can depart from his +pain and his aloneness without regret? + -- Kahlil Gibran, "The Prophet" +%% +Look! Before our very eyes, the future is becoming the past. +%% +Look afar and see the end from the beginning. +%% +Look at it this way: +Your daughter just named the fresh turkey you brought +home "Cuddles", so you're going out to buy a canned ham. +And you're still drinking ordinary scotch? +%% +Look at it this way: +Your wife's spending $280 a month on meditation lessons to +forget $26,000 of college education. +And you're still drinking ordinary scotch? +%% +Look before you leap. + -- Samuel Butler +%% +Look ere ye leap. + -- John Heywood +%% +Look out! Behind you! +%% +Lookie, lookie, here comes cookie... + -- Stephen Sondheim +%% +Loose bits sink chips. +%% +Lord, what fools these mortals be! + -- William Shakespeare, "A Midsummer-Night's Dream" +%% +Losing your drivers' license is just +God's way of saying "BOOGA, BOOGA!" +%% +Lost: gray and white female cat. +Answers to electric can opener. +%% +Lots of folks confuse bad management with destiny. + -- Frank Hubbard +%% +Lots of girls can be had for a song. +Unfortunately, it often turns out to be the wedding march. +%% +Love America - or give it back. +%% +Love IS what it's cracked up to be. +%% +Love and scandal are the best sweeteners of tea. +%% +Love at first sight is one of the greatest +labor-saving devices the world has ever seen. +%% +Love conquers all things; let us too surrender to love. + -- Publius Vergilius Maro (Virgil) +%% +Love in your heart wasn't put there to stay. +Love isn't love 'til you give it away. + -- Oscar Hammerstein II +%% +Love is a grave mental disease. + -- Plato +%% +Love is a word that is constantly heard, +Hate is a word that is not. +Love, I am told, is more precious than gold. +Love, I have read, is hot. +But hate is the verb that to me is superb, +And Love but a drug on the mart. +Any kiddie in school can love like a fool, +But Hating, my boy, is an Art. + -- Ogden Nash +%% +Love is always open arms. With arms open you allow love to come and +go as it wills, freely, for it will do so anyway. I you close your +arms about love you'll find you are left only holding yourself. +%% +Love is in the offing. Be affectionate to one who adores you. +%% +Love is in the offing. + -- The Homicidal Maniac +%% +Love is like a friendship caught on fire. In the beginning a flame, very +pretty, often hot and fierce, but still only light and flickering. As love +grows older, our hearts mature and our love becomes as coals, deep-burning +and unquenchable. + -- Bruce Lee +%% +Love is never asking why? +%% +Love is not enough, but it sure helps. +%% +Love is sentimental measles. +%% +Love is the process of my leading you gently back to yourself. + -- Saint Exupery +%% +Love is the triumph of imagination over intelligence. + -- H.L. Mencken +%% +Love means never having to say you're sorry. + -- Eric Segal, "Love Story" +%% +Love means nothing to a tennis player. +%% +Love the sea? I dote upon it -- from the beach. +%% +Love to eat them mousies, +Mousies what I love to eat. +Bite they little heads off, +Nibble on they tiny feet. + -- Kliban +%% +Love your enemies: they'll go crazy +trying to figure out what you're up to. +%% +Lowery's Law: + If it jams -- force it. If it + breaks, it needed replacing anyway. +%% +Lubarsky's Law of Cybernetic Entomology: + There's always one more bug. +%% +Luck, that's when preparation and opportunity meet. + -- P.E. Trudeau +%% +Lucky is he for whom the belle toils. +%% +Lucy: Dance, dance, dance. That is all you ever do. + Can't you be serious for once? +Snoopy: She is right! I think I had better think + of the more important things in life! + (pause) + Tomorrow!! +%% +Lysistrata had a good idea. +%% +MAC user's dynamic debugging list evaluator? Never heard of that. +%% +MAD: + Affected with a high degree of intellectual independence. +%% +MAGPIE: + A bird whose thievish disposition suggested + to someone that it might be taught to talk. + -- A. Bierce +%% +MAIDEN AUNT: + A girl who never had the sense to say "uncle." +%% +MAJORITY: + That quality that distinguishes a crime from a law. +%% +MALPRACTICE: + The reason surgeons wear masks. +%% +MANAGEMENT: + The art of getting other people to do all the work. +%% +MANAGER: + A man known for giving great meeting. +%% +MAN: + An animal so lost in rapturous contemplation of what he thinks he + is as to overlook what he indubitably ought to be. His chief + occupation is extermination of other animals and his own species, + which, however, multiplies with such insistent rapidity as to infest + the whole habitable earth and Canada. + -- A. Bierce +%% +MANIC-DEPRESSIVE: + Easy glum, easy glow. +%% +MARRIAGE: + An old, established institution, entered into by two people deeply + in love and desiring to make a committment to each other expressing + that love. In short, committment to an institution. +%% +MARRIAGE: + Convertible bonds. +%% +MEETINGS: + A place where minutes are kept and hours are lost. +%% +MEMO: + An interoffice communication too often written more for + the benefit of the person who sends it than the person + who receives it. +%% +MENU: + A list of dishes which the restaurant has just run out of. +%% +METEOROLOGIST: + One who doubts the established fact that it is + bound to rain if you forget your umbrella. +%% +MICRO: + Thinker toys. +%% +MIPS: + Meaningless Indicator of Processor Speed +%% +MISFORTUNE: + The kind of fortune that never misses. +%% +MISS: + A title with which we brand unmarried + women to indicate that they are in the market. +%% +MIXED EMOTIONS: + Watching your mother-in-law back off + a cliff in your brand new Mercedes. +%% +MIXED EMOTIONS: + Watching a bus-load of lawyers plunge + off a cliff. With five empty seats. +%% +MOCK APPLE PIE (No Apples Needed) + + Pastry to two crust 9-inch pie 36 RITZ Crackers +2 cups water 2 cups sugar +2 teaspoons cream of tartar 2 tablespoons lemon juice + Grated rind of one lemon Butter or margarine + Cinnamon + +Roll out bottom crust of pastry and fit into 9-inch pie plate. Break +RITZ Crackers coarsley into pastry-lined plate. Combine water, sugar +and cream of tartar in saucepan, boil gently for 15 minutes. Add lemon +juice and rind. Cool. Pour this syrup over Crackers, dot generously +with butter or margarine and sprinkle with cinnamon. Cover with top +crust. Trim and flute edges together. Cut slits in top crust to let +steam escape. Bake in a hot oven (425 F) 30 to 35 minutes, until crust +is crisp and golden. Serve warm. Cut into 6 to 8 slices. + -- Found lurking on a Ritz Crackers box +%% +MODESTY: + Being comfortable that others will discover your greatness. +%% +MODESTY: + The gentle art of enhancing your charm + by pretending not to be aware of it. +%% +MOLECULE: + The ultimate, indivisible unit of matter. It is distinguished from + the corpuscle, also the ultimate, indivisible unit of matter, by a + closer resemblance to the atom, also the ultimate, indivisible unit + of matter... The ion differs from the molecule, the corpuscle and + the atom in that it is an ion... +%% +MOMENTUM: + What you give a person when they are going away. +%% +MONDAY: + In Christian countries, the day after the football game. + -- Ambrose Bierce +%% +MONOTONY: + Marriage to one woman at a time. +%% +MONTANA: + A grizzly bear praying for the early arrival of cable television. +%% +MOPHOBIA: + Fear of being verbally abused by a Mississippian. +%% +MORE SPORTS RESULTS: +The Beverly Hills Freudians tied the Chicago Rogerians 0-0 last Saturday +night. The match started with a long period of silence while the Freudians +waited for the Rogerians to free associate and the Rogerians waited for +the Freudians to say something they could paraphrase. The stalemate was +broken when the Freudians' best player took the offensive and interpreted +the Rogerians' silence as reflecting their anal-retentive personalities. +At this the Rogerians' star player said "I hear you saying you think we're +full of ka-ka." This started a fight and the match was called by officials. +%% +MOSQUITO: + The state bird of New Jersey. +%% +MOTHER: + Half a word. +%% +MOUNT TAPE U1439 ON B3, NO RING +%% + MOUNTIES: +I'm a lumberjack and I'm OK, He's a lumberjack and he's OK, +I sleep all night and I work all day. He sleeps all night and he works + all day. + +I cut down trees, I eat my lunch, He cuts down trees, he eats his lunch, +I go to the lavatory. He goes to the lavatory. +On Wednesday I go shopping, On Wednesday he goes shopping, +And have buttered scones for tea. And has buttered scones for tea. + +I cut down trees, I skip and jump, He cuts down trees, he skips and jumps, +I like to press wild flowers, He likes to press wild flowers. +I put on women's clothing, He puts on women's clothing, +And hang around in bars. And hangs around in bars. + +I cut down trees, I wear high heels, He cuts down trees, he wears high heels, +Suspenders and a bra. Suspenders? and a bra? +I wish I'd been a girlie, That's rude... +Just like my dear Pappa. +%% +MUMMY: + An Egyptian who was pressed for time. +%% +MYTHOLOGY: + The body of a primitive people's beliefs concerning its origin, + early history, heroes, deities and so forth, as distinguished + from the true accounts which it invents later. +%% +Machines have less problems. I'd like to be a machine. + -- Andy Warhol +%% +Madam, there's no such thing as a tough child -- +if you parboil them first for seven hours, they always come out tender. + -- W.C. Fields +%% +Madison's Inquiry: + If you have to travel on the Titanic, why not go first class? +%% +Madness takes its toll. +%% +Magary's Principle: + When there is a public outcry to cut deadwood and fat from any + government bureaucracy, it is the deadwood and the fat that do + the cutting, and the public's services are cut. +%% +Magic is always the best solution -- especially reliable magic. +%% +Magnet, n.: Something acted upon by magnetism. + +Magnetism, n.: Something acting upon a magnet. + +The two preceding definitions are condensed from the works of one +thousand eminent scientists, who have illuminated the subject with a +great white light, to the inexpressible advancement of human knowledge. +%% +Maiden, n. A young person of the unfair sex addicted to clewless conduct and +views that madden to crime. The genus has a wide geographical distribution, +being found wherever sought and deplored wherever found. The maiden is not +altogether unpleasing to the eye, nor (without her piano and her views) +insupportable to the ear, though in respect to comeliness distinctly inferior +to the rainbow, and, with regard to the part of her that is audible, beaten +out of the field by the canary -- which, also, is more portable. + +Male, n. A member of the unconsidered, or negligible sex. The male of the +human race is commonly known (to the female) as Mere Man. The genus has two +varieties: good providers and bad providers. + -- Ambrose Bierce +%% +Maier's Law: + If the facts do not conform to the theory, they must be disposed of. + -- N. R. Maier, "American Psychologist", March 1960 + +Corollaries: + 1. The bigger the theory, the better. + 2. The experiment may be considered a success if no more than + 50% of the observed measurements must be discarded to + obtain a correspondence with the theory. +%% +Main's Law: + For every action there is an equal and opposite government program. +%% +Major premise: + Sixty men can do sixty times as much work as one man. +Minor premise: + A man can dig a posthole in sixty seconds. +Conclusion: + Sixty men can dig a posthole in one second. + +Secondary Conclusion: + Do you realize how many holes there would be if people + would just take the time to take the dirt out of them? +%% +Majorities, of course, start with minorities. + -- Robert Moses +%% +Make a wish, it might come true. +%% +Make headway at work. Continue to let things deteriorate at home. +%% +Make it right before you make it faster. +%% +Make no little plans; they have no magic to stir men's blood. + -- Daniel Hudson Burnham +%% +Make sure your code does nothing gracefully. +%% +Making files is easy under the UNIX operating system. Therefore, users +tend to create numerous files using large amounts of file space. It has +been said that the only standard thing about all UNIX systems is the +message-of-the-day telling users to clean up their files. + -- System V.2 administrator's guide +%% +Malek's Law: + Any simple idea will be worded in the most complicated way. +%% +Man and wife make one fool. +%% +Man belongs wherever he wants to go. + -- Wernher von Braun +%% +Man has always assumed that he is more intelligent than dolphins because +he has achieved so much -- the wheel, New York, wars and so on -- while +all the dolphins had ever done was muck about in the water having a good +time. But, conversely, the dolphins had always believed that they were +far more intelligent than man -- for precisely the same reasons. + -- D. Adams, "Hitchhiker's Guide to the Galaxy" +%% +Man has made his bedlam; let him lie in it. + -- Fred Allen +%% +Man has never reconciled himself to the ten commandments. +%% +Man is a military animal, +Glories in gunpowder, and loves parade. + -- P.J. Bailey +%% +Man is a rational animal who always loses his temper when he +is called upon to act in accordance with the dictates of reason. + -- Oscar Wilde +%% +Man is an animal that makes bargains: no other animal does this-- +no dog exchanges bones with another. + -- Adam Smith +%% +Man is by nature a political animal. + -- Aristotle +%% +Man is the best computer we can put aboard a spacecraft... +and the only one that can be mass produced with unskilled labor. + -- Wernher von Braun +%% +Man is the measure of all things. + -- Protagoras +%% +Man is the only animal that blushes -- or needs to. + -- Mark Twain +%% +Man is the only animal that laughs and weeps; +for he is the only animal that is struck with the +difference between what things are and what they ought to be. + -- William Hazlitt +%% +Man must shape his tools lest they shape him. + -- Arthur R. Miller +%% +Man proposes, God disposes. + -- Thomas a Kempis +%% +Man usually avoids attributing cleverness to somebody else -- +unless it is an enemy. + -- A. Einstein +%% +Man who arrives at party two hours late +will find he has been beaten to the punch. +%% +Man who falls in blast furnace is certain to feel overwrought. +%% +Man who falls in vat of molten optical glass makes spectacle of self. +%% +Man who sleep in beer keg wake up stickey. +%% +Man will never fly. +Space travel is merely a dream. +All aspirin is alike. +%% +Mankind is poised midway between the gods and the beasts. + -- Plotinus +%% +Man's horizons are bounded by his vision. +%% +Man's lust for a bust is hardly recent, +Some say not even indecent. +But if you lust, +It's a must! +%% +Man's reach must exceed his grasp, for why else the heavens? +%% +Man's unique agony as a species consists in his perpetual +conflict between the desire to stand out and the need to blend in. + -- Sydney J. Harris +%% +Many a bum show has been saved by the flag. + -- George M. Cohan +%% +Many a family tree needs trimming. +%% +Many a man that can't direct you to a corner drugstore will +get a respectful hearing when age has further impaired his mind. + -- Finley Peter Dunne +%% +Many a man who thinks he's going on a maiden voyage with +a woman finds out later that it was just a shake-down cruise. +%% +Many a writer seems to thing he is never profound +except when he can't understand his own meaning. + -- George D. Prentice +%% +Many are called, few are chosen. +Fewer still get to do the choosing. +%% +Many are called, few volunteer. +%% +Many are cold, but few are frozen. +%% +Many changes of mind and mood; do not hesitate too long. +%% +Many hands make light work. + -- John Heywood +%% +Many mental processes admit of being roughly measured. For instance, +the degree to which people are bored, by counting the number of their +fidgets. I not infrequently tried this method at the meetings of the +Royal Geographical Society, for even there dull memoirs are occasionally +read. [...] The use of a watch attracts attention, so I reckon time +by the number of my breathings, of which there are 15 in a minute. They +are not counted mentally, but are punctuated by pressing with 15 fingers +successively. The counting is reserved for the fidgets. These observations +should be confined to persons of middle age. Children are rarely still, +while elderly philosophers will sometimes remain rigid for minutes altogether. + -- Francis Galton, 1909 +%% +Many of the convicted thieves Parker has met began their +life of crime after taking college Computer Science courses. + -- Roger Rapoport, "Programs for Plunder", Omni, March 1981 +%% +Many pages make a thick book. +%% +Many pages make a thick book, except for +pocket bibles which are on very thin paper. +%% +Many people are desperately looking for some wise advice +which will recommend that they do what they want to do. +%% +Many people are secretly interested in life. +%% +Many people are unenthusiastic about their work. +%% +Many people are unenthusiastic about your work. +%% +Many people feel that if you won't let +them make you happy, they'll make you suffer. +%% +Many people feel that they deserve some kind of +recognition for all the bad things they haven't done. +%% +Many people resent being treated like the person they really are. +%% +Many people write memos to tell you they have nothing to say. +%% +Many receive advice, few profit by it. + -- Publilius Syrus +%% +Many years ago in a period commonly know as Next Friday Afternoon, +there lived a King who was very Gloomy on Tuesday mornings because he +was so Sad thinking about how Unhappy he had been on Monday and how +completely Mournful he would be on Wednesday.... + -- Walt Kelly +%% +Margaret, are you grieving +Over Goldengrove unleaving? +Leaves, like the things of man, +You, with your fresh thoughts +Care for, can you? +Ah! as the heart grows older +It will come to such sights colder +By and by, nor spare a sigh +Though worlds of wanwood leafmeal lie +And yet you will weep and know why. +Now no matter, child, the name +Sorrow's springs are the same: +It is the blight man was born for, +It is Margaret you mourn for. + -- Gerard Manley Hopkins. +%% +Marijuana is like Coors beer. If you could buy the damn stuff +at a Georgia filling station, you'd decide you wouldn't want it. + -- Billy Carter +%% +Marijuana will be legal some day, because the many law students +who now smoke pot will someday become congressmen and legalize +it in order to protect themselves. + -- Lenny Bruce +%% +Mark's Dental-Chair Discovery: + Dentists are incapable of asking questions + that require a simple yes or no answer. +%% +Marriage is a three ring circus: +engagement ring, wedding ring, and suffering. + -- Roger Price +%% +Marriage is an institution in which two undertake +to become one, and one undertakes to become nothing. +%% +Marriage is the only adventure open to the cowardly. + -- Voltaire +%% +Marriage is the process of finding out what +kind of man your wife would have preferred. +%% +Marriage is the waste-paper basket of the emotions. +%% +Marriages are made in heaven and consummated on earth. + -- John Lyly +%% +Marvin the Nature Lover spied a grasshopper hopping along in the grass, +and in a mood for communing with nature, rare even among full-fledged +Nature Lovers, he spoke to the grasshopper, saying: "Hello, friend +grasshopper. Did you know they've named a drink after you?" + "Really?" replied the grasshopper, obviously pleased. "They've +named a drink Fred?" +%% +Mary had a little lamb, +The lamb turned out to be a ram, +Now Mary has a little lamb. +%% +Maryann's Law: + You can always find what you're not looking for. +%% +Maslow's Maxim: + If the only tool you have is a hammer, + you treat everything like a nail. +%% +Massachusetts has the best politicians money can buy. +%% +Mate, this parrot wouldn't VOOM if you put four million volts through it! + -- Monty Python +%% +Mater artium necessitas. + [Necessity is the mother of invention]. +%% +Mathematicians practice absolute freedom. + -- Henry Adams +%% +Mathematicians take it to the limit. +%% +Mathematics deals exclusively with the relations of concepts +to each other without consideration of their relation to experience. + -- Albert Einstein +%% +Matrimony is the root of all evil. +%% +Matrimony isn't a word, it's a sentence. +%% +Matter cannot be created or destroyed, +nor can it be returned without a receipt. +%% +Matter will be damaged in direct proportion to its value. +%% +[Maturity consists in the discovery that] there comes a critical moment +where everything is reversed, after which the point becomes to understand +more and more that there is something which cannot be understood. + -- S. Kierkegaard +%% +Maturity is only a short break in adolescence. + -- Jules Feiffer +%% +Matz's Law: + A conclusion is the place where you got tired of thinking. +%% +May a Misguided Platypus lay its Eggs in your Jockey Shorts +%% +May all your PUSHes be POPped. +%% +May the Fleas of a Thousand Camels infest one of your Erogenous Zones. +%% +May the bluebird of happiness twiddle your bits. +%% +May the fleas of a thousand camels infest your armpits. +%% +May you die in bed at 95, shot by a jealous spouse. +%% +May you live in uninteresting times. + -- Chinese proverb +%% +May your Tongue stick to the Roof of your +Mouth with the Force of a Thousand Caramels. +%% +Maybe Computer Science should be in the College of Theology. + -- R.S. Barton +%% +Maybe Jesus was right when he said that the meek shall inherit the +earth -- but they inherit very small plots, about six feet by three. + -- Lazarus Long +%% +Maybe ain't ain't so correct, but I notice that +lots of folks who ain't using ain't ain't eatin' well. + -- Will Rogers +%% +Maybe you can't buy happiness, but +these days you can certainly charge it. +%% +May's Law: + The quality of correlation is inversly proportional to the density + of control. (The fewer the data points, the smoother the curves.) +%% +McDonald's -- Because you're worth it. +%% +McEwan's Rule of Relative Importance: + When traveling with a herd of elephants, + don't be the first to lie down and rest. +%% +McGowan's Madison Avenue Axiom: + If an item is advertised as "under $50", + you can bet your ass it's not $19.95. +%% +Meader's Law: + Whatever happens to you, it will previously + have happened to everyone you know, only more so. +%% +Measure twice, cut once. +%% +Measure with a micrometer. Mark with chalk. Cut with an axe. +%% +Meekness is uncommon patience in planning a worthwhile revenge. +%% +Meester, do you vant to buy a duck? +%% +Memory fault -- brain fried +%% +Memory fault -- core...uh...um...core... Oh dammit, I forget! +%% +Memory fault - where am I? +%% +Memory should be the starting point of the present. +%% +Men are always ready to respect anything that bores them. + -- Marilyn Monroe +%% +Men aren't attracted to me by my mind. +They're attracted by what I don't mind... + -- Gypsy Rose Lee +%% +Men freely believe that what they wish to desire. + -- Julius Caesar +%% +Men have a much better time of it than women; for one +thing, they marry later; for another thing, they die earlier. + -- H.L. Mencken +%% +Men have as exaggerated an idea of their +rights as women have of their wrongs. + -- E.W. Howe +%% +Men have many faults, + Women only two: +Everything they say, + And everything they do! +%% +Men live for three things, fast cars, fast women and fast food. +%% +Men love to wonder, and that is the seed of science. +%% +Men never make passes at girls wearing glasses. + -- Dorothy Parker +%% +Men occasionally stumble over the truth, but most of them +pick themselves up and hurry off as if nothing had happened. + -- Winston Churchill +%% +Men of quality are not afraid of women for equality. +%% +Men often believe -- or pretend -- that the "Law" is something sacred, or +at least a science -- an unfounded assumption very convenient to governments. +%% +Men say of women what pleases them; women do with men what pleases them. + -- DeSegur +%% +Men seldom show dimples to girls who have pimples. +%% +Men still remember the first kiss after women have forgotten the last. +%% +Men take only their needs into consideration -- never their abilities. + -- Napoleon Bonaparte +%% +Men use thought only to justify their wrong doings, +and speech only to conceal their thoughts. + -- Voltaire +%% +Men were real men, women were real women, and small, furry creatures +from Alpha Centauri were REAL small, furry creatures from Alpha Centauri. +Spirits were brave, men boldly split infinitives that no man had split +before. Thus was the Empire forged. + -- Douglas Adams, "The Hitchhiker's Guide to the Galaxy" +%% +Mencken and Nathan's Second Law of The Average American: + All the postmasters in small towns read all the postcards. + +Mencken and Nathan's Ninth Law of The Average American: + The quality of a champagne is judged by the + amount of noise the cork makes when it is popped. + +Mencken and Nathan's Fifteenth Law of The Average American: + The worst actress in the company is always the manager's wife. + +Mencken and Nathan's Sixteenth Law of The Average American: + Milking a cow is an operation demanding a special talent that + is possessed only by yokels, and no person born in a large city + can ever hope to acquire it. +%% +Mene, mene, tekel, upharsen. +%% +Mental power tended to corrupt, and absolute intelligence tended to +corrupt absolutely, until the victim eschewed violence entirely in +favor of smart solutions to stupid problems. + -- Piers Anthony +%% +Mental things which have not gone in through the +senses are vain and bring forth no truth except detrimental. + -- Leonardo +%% +Meskimen's Law: + There's never time to do it right, but there's always time to + do it over. +%% +Message from Our Sponsor on ttyTV at 13:58 ... +%% +Message will arrive in the mail. +Destroy, before the FBI sees it. +%% +Mickey Mouse wears a Spiro Agnew watch. +%% +Microbiology Lab: Staph Only! +%% +Microwaves frizz your heir. +%% +Mieux vaut tard que jamais! +%% +Might as well be frank, monsieur. It would take a miracle to +get you out of Casablanca and the Germans have outlawed miracles. + -- Casablanca +%% +Miksch's Law: + If a string has one end, then it has another end. +%% +Military intelligence is a contradiction in terms. + -- Groucho Marx +%% +Military justice is to justice what military music is to music. + -- Groucho Marx +%% +Miller's Slogan: + Lose a few, lose a few. +%% +Millions long for immortality who do not know what +to do with themselves on a rainy Sunday afternoon. + -- Susan Ertz +%% +Millions of sensible people are too high-minded to concede that politics is +almost always the choice of the lesser evil. "Tweedledum and Tweedledee," +they say. "I will not vote." Having abstained, they are presented with a +President who appoints the people who are going to rummage around in their +lives for the next four years. Consider all the people who sat home in a +stew in 1968 rather than vote for Hubert Humphrey. They showed Humphrey. +Those people who taught Hubert Humphrey a lesson will still be enjoying the +Nixon Supreme Court when Tricia and Julie begin to find silver threads among +the gold and the black. + -- Russel Baker, "Ford without Flummery" +%% +Mind! I don't mean to say that I know, of my own knowledge, what there is +particularly dead about a door-nail. I might have been inclined, myself, +to regard a coffin-nail as the deadest piece of ironmongery in the trade. +But the wisdom of our ancestors is in the simile; and my unhallowed hands +shall not disturb it, or the Country's done for. You will therefore permit +me to repeat, emphatically, that Marley was as dead as a door-nail. +%% +Mind your own business, Spock. +I'm sick of your halfbreed interference. +%% +Minnie Mouse is a slow maze learner. +%% +Misery loves company, but company does not reciprocate. +%% +Misery no longer loves company. +Nowadays it insists on it. + -- Russell Baker +%% +Misfortunes arrive on wings and leave on foot. +%% +Mistakes are oft the stepping stones to utter failure. +%% +Mistrust first impulses; they are always right. +%% +Mitchell's Law of Committees: + Any simple problem can be made insoluble + if enough meetings are held to discuss it. +%% +Mix a little foolishness with your serious plans; +it's lovely to be silly at the right moment. + -- Horace +%% +Mix's Law: + There is nothing more permanent than a temporary building. + There is nothing more permanent than a temporary tax. +%% +Mobius strippers never show you their back side. +%% +Modeling paged and segmented memories is tricky business. + -- P.J. Denning +%% +Moderation in all things. + -- Publius Terentius Afer [Terence] +%% +Moderation is a fatal thing. Nothing succeeds like excess. + -- Oscar Wilde +%% +Modern man is the missing link between apes and human beings. +%% +Modesty is a vastly overrated virtue. + -- J.K. Galbraith +%% +Moe: What did you give your wife for Valentine's Day? +Joe: The usual gift -- she ate my heart out. +%% +Moe: Wanna play poker tonight? +Joe: I can't. It's the kids' night out. +Moe: So? +Joe: I gotta stay home with the nurse. +%% +Mollison's Bureaucracy Hypothesis: + If an idea can survive a bureaucratic review + and be implemented it wasn't worth doing. +%% +Mom's Law: + When they finally do have to take you to the + hospital, your underwear won't be clean or new. +%% +Monday is an awful way to spend one seventh of your life. +%% +Money cannot buy love, nor even friendship. +%% +Money is a powerful aphrodisiac. But flowers work almost as well. + -- Lazarus Long +%% +Money is its own reward. +%% +Money is the root of all evil, and man needs roots. +%% +Money is the root of all wealth. +%% +Money is truthful. If a man speaks of his honor, make him pay cash. + -- Lazarus Long +%% +Money isn't everything -- but it's a long way ahead of what comes next. + -- Sir Edmond Stockdale +%% +Money may buy friendship but money cannot buy love. +%% +Money may not buy happiness, but it sure +puts you in a great bargaining position. +%% +Money will say more in one moment than +the most eloquent lover can in years. +%% +Moneyliness is next to Godliness. + -- Andries van Dam +%% +Moore's Constant: + Everybody sets out to do something, and everybody + does something, but no one does what he sets out to do. +%% +More people are flattered into virtue than bullied out of vice. + -- R.S. Surtees +%% +More people have died in Ted Kennedy's +car than in nuclear power plants. +%% +More than any time in history, mankind now faces a crossroads. One path +leads to despair and utter hopelessness, the other to total extinction. +Let us pray that we have the wisdom to choose correctly. + -- Woody Allen +%% +Morton's Law: + If rats are experimented upon, they will develop cancer. +%% +Mos Eisley Spaceport; you'll not find a more +wretched collection of villainy and disreputable types... + -- Obi-wan Kenobi, "Star Wars" +%% +Mosher's Law of Software Engineering: + Don't worry if it doesn't work right. + If everything did, you'd be out of a job. +%% +Most burning issues generate far more heat than light. +%% +Most general statements are false, including this one. + -- Alexander Dumas +%% +Most legislators are so dumb that they couldn't pour piss +out of a boot if the instructions were printed on the heel. +%% +Most of your faults are not your fault. +%% +Most people are too busy to have time for anything important. +%% +Most people can do without the +essentials, but not without the luxuries. +%% +Most people deserve each other. + -- Shirley +%% +Most people don't need a great deal of love +nearly so much as they need a steady supply. +%% +Most people eat as though they were fattening themselves for market. + -- E.W. Howe +%% +Most people feel that everyone is entitled to their opinion. +%% +Most people have a mind that's open by appointment only. +%% +Most people have two reasons for doing anything -- +a good reason, and the real reason. +%% +Most people in this society who aren't actively mad are, +at best, reformed or potential lunatics. + -- Susan Sontag +%% +Most people need some of their problems +to help take their mind off some of the others. +%% +Most people prefer certainty to truth. +%% +Most people want either less corruption +or more of a chance to participate in it. +%% +Most people will listen to your unreasonable demands, +if you'll consider their unacceptable offer. +%% +Most people wouldn't know music if it came up and bit them on the ass. + -- Frank Zappa +%% +Most people's favorite way to end a game is by winning. +%% +Mother Earth is not flat! +%% +Mothers of large families (who claim to common sense) +Will find a Tiger will repay the trouble and expense. + -- Hilaire Belloc, "The Tiger" +%% +Mount St. Helens should have used earth control. +%% + Moving along a dimly light street, a man I know was suddenly +approached by a stranger who had slipped from the shadows nearby. + "Please, sir," pleaded the stranger, "would you be so kind as +to help a poor unfortunate fellow who is hungry and can't find work? +All I have in the world is this gun." +%% +Mr. Cole's Axiom: + The sum of the intelligence on the planet is a constant; the + population is growing. +%% +Mr. Rockford? This is Betty Joe Withers. I got four shirts of yours from +the Bo Peep Cleaners by mistake. I don't know why they gave me men's +shirts but they're going back. +%% +Mr. Rockford? You don't know me, but I'd like to hire you. Could +you call me at... My name is... uh... Never mind, forget it! +%% +Mr. Rockford; Miss Collins from the Bureau of Licenses. We got your +renewal before the extended deadline but not your check. I'm sorry but +at midnight you're no longer licensed as an investigator. +%% +Mr. Rockford, this is the Thomas Crown School of Dance and Contemporary +Etiquette. We aren't going to call again! Now you want these free +lessons or what? +%% +Multics is security spelled sideways. +%% +Mum's the word. + -- Miguel de Cervantes +%% +Murphy was an optimist. +%% +Murphy's Discovery: + Do you know Presidents talk to the country the way men talk + to women? They say, "Trust me, go all the way with me, and + everything will be all right." And what happens? Nine + months later, you're in trouble! +%% +Murphy's Law is recursive. Washing your car to make it rain doesn't work. +%% +Murphy's Law of Research: + Enough research will tend to support your theory. +%% +Murphy's Law, that brash proletarian restatement of Godel's Theorem. + -- Thomas Pynchon, "Gravity's Rainbow" +%% +Murphy's Laws: + (1) If anything can go wrong, it will. + (2) Nothing is as easy as it looks. + (3) Everything takes longer than you think it will. +%% + Murray and Esther, a middle-aged Jewish couple, are touring Chile. +Murray just got a new camera and is constantly snapping pictures. One day, +without knowing it, he photographs a top-secret military installation. In +an instant, armed troops surround Murray and Esther and hustle them off to +prison. + They can't prove who they are because they've left their passports +in their hotel room. For three weeks they're tortured day and night to get +them to name their contacts in the liberation movement.. Finally they're +hauled in front of a military court, charged with espionage, and sentenced +to death. + The next morning they're lined up in front of the wall where they'll +be shot. The sergeant in charge of the firing squad asks them if they have +any last requests. Esther wants to know if she can call her daughter in +Chicago. The sergeant says he's sorry, that's not possible, and turns to +Murray. + "This is crazy!" Murray shouts. "We're not spies!" And he +spits in the sergeants face. + "Murray!" Esther cries. "Please! Don't make trouble." + -- Arthur Naiman +%% +Murray's Rule: + Any country with "democratic" in the title isn't. +%% +Music in the soul can be heard by the universe. + -- Lao Tsu +%% +Must I hold a candle to my shames? + -- William Shakespeare, "The Merchant of Venice" +%% +My God, I'm depressed! Here I am, a computer with a mind a thousand times +as powerful as yours, doing nothing but cranking out fortunes and sending +mail about softball games. And I've got this pain right through my ALU. +I've asked for it to be replaced, but nobody ever listens. I think it +would be better for us both if you were to just log out again. +%% +My My, hey hey +Rock and roll is here to stay The king is gone but he's not forgotten +It's better to burn out This is the story of a Johnny Rotten +Than to fade away It's better to burn out than it is to rust +My my, hey hey The king is gone but he's not forgotten + +It's out of the blue and into the black Hey hey, my my +They give you this, but you pay for that Rock and roll can never die +And once you're gone you can never come back There's more to the picture +When you're out of the blue Than meets the eye +And into the black + -- Neil Young + "My My, Hey Hey (Out of the Blue), Rust Never Sleeps" +%% +My analyst told me that I was right out of my head, + But I said, "Dear Doctor, I think that it is you instead. +Because I have got a thing that is unique and new, + To prove it I'll have the last laugh on you. +'Cause instead of one head -- I've got two. + +And you know two heads are better than one. +%% +My calculator is my shepherd, I shall not want +It maketh me accurate to ten significant figures, + and it leadeth me in scientific notation to 99 digits. +It restoreth my square roots and guideth me along paths of floating + decimal points for the sake of precision. +Yea, tho I walk through the valley of surprise quizzes, + I will fear no prof, for my calculator is there to hearten me. +It prepareth a log table to comfort me, it prepareth an + arc sin for me in the presence of my teachers. +It annoints my homework with correct solutions, my interpolations are + over. +Surely, both precision and accuracy shall follow me all the days of my + life, and I shall dwell in the house of Texas instruments forever. +%% +My central memory of that time seems to hang on one or five or maybe forty +nights -- or very early mornings -- when I left the Fillmore half-crazy and, +instead of going home, aimed the big 650 Lightning across the Bay Bridge at +a hundred miles an hour ... booming through the Treasure Island tunnel at +the lights of Oakland and Berkeley and Richmond, not quite sure which +turnoff to take when I got to the other end ... but being absolutely certain +that no matter which way I went I would come to a place where people were +just as high and wild as I was: no doubt at all about that. + -- Hunter S. Thompson +%% +My cup hath runneth'd over with love. +%% +My darling wife was always glum. +I drowned her in a cask of rum, +And so made sure that she would stay +In better spirits night and day. +%% +My doctorate's in Literature, but it +seems like a pretty good pulse to me. +%% +My experience with government is when things are non-controversial, +beautifully co-ordinated and all the rest, it must be that not much +is going on. + -- J.F. Kennedy +%% +My family history begins with me, but yours ends with you. + -- Iphicrates +%% +My father, a good man, told me, "Never lose +your ignorance; you cannot replace it." + -- Erich Maria Remarque +%% +My father taught me three things: + 1: Never mix whiskey with anything but water. + 2: Never try to draw to an inside straight. + 3: Never discuss business with anyone who refuses to give his name. +%% +My father was a God-fearing man, but he never +missed a copy of the New York Times, either. + -- E.B. White +%% +My folks didn't come over on the Mayflower, +but they were there to meet the boat. +%% + My friends, I am here to tell you of the wonderous continent known as +Africa. Well we left New York drunk and early on the morning of February 31. +We were 15 days on the water, and 3 on the boat when we finally arrived in +Africa. Upon our arrival we immediately set up a rigorous schedule: Up at +6:00, breakfast, and back in bed by 7:00. Pretty soon we were back in bed by +6:30. Now Africa is full of big game. The first day I shot two bucks. That +was the biggest game we had. Africa is primerally inhabited by Elks, Moose +and Knights of Pithiests. + The elks live up in the mountains and come down once a year for their +annual conventions. And you should see them gathered around the water hole, +which they leave immediately when they discover it's full of water. They +weren't looking for a water hole. They were looking for an alck hole. + One morning I shot an elephant in my pajamas, how he got in my +pajamas, I don't know. Then we tried to remove the tusks. That's a tough +word to say, tusks. As I said we tried to remove the tusks, but they were +imbedded so firmly we couldn't get them out. But in Alabama the Tusks are +looser, but that is totally irrelephant to what I was saying. + We took some pictures of the native girls, but they weren't developed. +So we're going back in a few years... + -- Julius H. Marx +%% +My godda bless, never I see sucha people. + -- Signor Piozzi, quoted by Cecilia Thrale +%% +My, how you've changed since I've changed. +%% +My interest is in the future because I am +going to spend the rest of my life there. +%% +My love, he's mad, and my love, he's fleet, + And a wild young wood-thing bore him! +The ways are fair to his roaming feet, + And the skies are sunlit for him. +As sharply sweet to my heart he seems + As the fragrance of acacia. +My own dear love, he is all my dreams -- + And I wish he were in Asia. + -- Dorothy Parker, part 2 +%% +My love runs by like a day in June, + And he makes no friends of sorrows. +He'll tread his galloping rigadoon + In the pathway or the morrows. +He'll live his days where the sunbeams start + Nor could storm or wind uproot him. +My own dear love, he is all my heart -- + And I wish somebody'd shoot him. + -- Dorothy Parker, part 3 +%% + My message is not that biological determinists were bad scientists or +even that they were always wrong. Rather, I believe that science must be +understood as a social phenomenon, a gutsy, human enterprise, not the work of +robots programmed to collect pure information. I also present this view as +an upbeat for science, not as a gloomy epitaph for a noble hope sacrificed on +the alter of human limitations. + I believe that a factual reality exists and that science, though often +in an obtuse and erratic manner, can learn about it. Galileo was not shown +the instruments of torture in an abstract debate about lunar motion. He had +threatened the Church's conventional argument for social and doctrinal +stability: the static world order with planets circling about a central +earth, priests subordinate to the Pope and serfs to their lord. But the +Church soon made its peace with Galileo's cosmology. They had no choice; the +earth really does revolve about the sun. + -- S.J. Gould, "The Mismeasure of Man" +%% +My method is to take the utmost trouble to find the right +thing to say. And then say it with the utmost levity. + -- G.B. Shaw +%% +My mind can never know my body, although +it has become quite friendly with my legs. + -- Woody Allen, on Epistemology +%% +My mother drinks to forget she drinks. + -- Crazy Jimmy +%% +My mother loved children -- she would +have given anything if I had been one. + -- Groucho Marx +%% +My mother was a test tube; my father was a knife. + -- Friday +%% +My mother-in-law broke up my marriage. One day my wife +came home early from work and found us in bed together. + -- Lenny Bruce +%% +My notion of a husband at forty is that a woman should +be able to change him, like a bank note, for two twenties. +%% +My only love sprung from my only hate! +Too early seen unknown, and known too late! + -- William Shakespeare, "Romeo and Juliet" +%% +My opinions may have changed, but not the fact that I am right. +%% +My own business always bores me to death; I prefer other people's. + -- O. Wilde +%% +My own dear love, he is strong and bold + And he cares not what comes after. +His words ring sweet as a chime of gold, + And his eyes are lit with laughter. +He is jubilant as a flag unfurled -- + Oh, a girl, she'd not forget him. +My own dear love, he is all my world -- + And I wish I'd never met him. + -- Dorothy Parker, part 1 +%% +My parents went to Niagra Falls and all I got was this crummy life. +%% +My rackets are run on strictly American +lines, and they're going to stay that way. + -- A. Capone +%% +My way of joking is to tell the truth. +That's the funniest joke in the world. + -- Muhammad Ali +%% +My weight is perfect for my height -- which varies. +%% +Mystics always hope that science will some day overtake them. + -- Booth Tarkington +%% +NAPOLEON: What shall we do with this soldier, Guiseppe? + Everything he says is wrong. +GUISEPPE: Make him a general, Excellency, + and then everything he says will be right. + + -- G.B. Shaw +%% +NERD PACK: + Plastic pouch worn in breast pocket to keep pens from soiling + clothes. Nerd's position in engineering hierarchy can be + measured by number of pens, grease pencils, and rulers bristling + in his pack. +%% +NEUTRON BOMB: + An explosive device of limited military value because, as + it only destroys people without destroying property, it + must be used in conjunction with bombs that destroy property. +%% +NEW: + Different color from previous model. +%% +NO BRAINER: + A decision which, viewed through the retrospectoscope, + is "obvious" to those who failed to make it originally. +%% +NO MAINTENANCE: + Impossible to fix. +%% +NOBODY EXPECTS THE SPANISH INQUISITION. +%% +NOLO CONTENDERE: + A legal term meaning: "I didn't do it, + judge, and I'll never do it again." +%% +NOMINAL EGG: + New Yorkerese for expensive. +%% +NOVEMBER: + The eleventh twelfth of a weariness. +%% +Nadia Comaneci, simple perfection. + -- '76 Olympics +%% +Naeser's Law: + You can make it foolproof, but you can't make it damnfoolproof. +%% +National security is in your hands - guard it well. +%% +Natural laws have no pity. +%% +Nature always sides with the hidden flaw. +%% +Nature and nature's laws lay hid in night, +God said, "Let Newton be," and all was light. + +It did not last; the devil howling "Ho! +Let Einstein be!" restored the status quo. +%% +Nature has given women so much power that the +law has wisely given them very little. + -- Johnson +%% +Nature to all things fixed the limits fit, +And wisely curbed proud man's pretending wit. +As on the land while here the ocean gains, +In other parts it leaves wide sandy plains; +Thus in the soul while memory prevails, +The solid power of understanding fails; +Where beams of warm imagination play, +The memory's soft figures melt away. + -- Alexander Pope (on runtime bounds checking?) +%% +Nature, to be commanded, must be obeyed. + -- Francis Bacon +%% +Near the Studio Jean Cocteau +On the Rue des Ecoles +lived an old man +with a blind dog +Every evening I would see him +guiding the dog along +the sidewalk, keeping +a firm grip on the leash +so that the dog wouldn't +run into a passerby +Sometimes the dog would stop +and look up at the sky +Once the old man +noticed me watching the dog +and he said, "Oh, yes, +this one knows +when the moon is out, +he can feel it on his face" + -- Barry Gifford +%% +Nearly all men can stand adversity, but if you +want to test a man's character, give him power. + -- Abraham Lincoln +%% +Necessity has no law. + -- St. Augustine +%% +Necessity is a mother. +%% +Necessity is the mother of strange bedfellows. +Watch who you sleep with. +%% +Necessity is the plea for every infringement of human freedom. +It is the argument of tyrants; it is the creed of slaves. + -- William Pitt, 1783 +%% +Neckties strangle clear thinking. + -- Lin Yutang +%% +Negative expectations yield negative results. +Positive expectations yield negative results. +%% +Neil Armstrong tripped. +%% +Neither spread the germs of gossip nor encourage others to do so. +%% +Nemo me impune lacessit + [No one provokes me with impunity] + -- Motto of the Crown of Scotland +%% +Neuroses are red, + Melancholia's blue. +I'm schizophrenic, + What are you? +%% +Neurotics build castles in the sky, +Psychotics live in them, +And psychiatrists collect the rent. +%% +Neutrinos are into physicists. +%% +Neutrinos have bad breadth. +%% +Never appeal to a man's "better nature." He may not have one. +Invoking his self-interest gives you more leverage. + -- Lazarus Long +%% +Never argue with a fool -- people might not be able to tell the difference. +%% +Never argue with a man who buys ink by the barrel. +%% +Never argue with a woman when she's tired -- or rested. +%% +Never be led astray onto the path of virtue. +%% +Never buy from a rich salesman. + -- Goldenstern +%% +Never buy what you do not want +because it is cheap; it will be dear to you. + -- Thomas Jefferson +%% +Never call a man a fool. Borrow from him. +%% +Never count your chickens before they rip your lips off. +%% +Never do today what you can put off until tomorrow. +%% +Never drink Coca-Cola in a moving elevator. The elevator's motion coupled +with the chemicals in Coke produce hallucinations. People tend to change +into lizards and attack without warning, and large bats usually fly in the +window. (Additionally, you begin to believe that elevators have windows.) +%% +Never drink from your finger bowl -- it contains only water. +%% +Never eat anything bigger than your head. +%% +Never eat more than you can lift. + -- Miss Piggy +%% +Never, ever lie to someone you love unless you're +absolutely sure they'll never find out the truth. +%% +Never explain. Your friends do not need it +and your enemies will never believe you anyway. + -- Elbert Hubbard +%% +Never fly under a sea gull - they'll shit on your airplane. + -- Gordon Cooper +%% +Never frighten a small man -- he'll kill you. +%% +Never give an inch! +%% +Never have so many understood so little about so much. + -- James Burke +%% +Never hit a man with glasses; hit him with a baseball bat. +%% +Never insult an alligator until you've crossed the river. +%% +Never invest your money in anything that eats or needs repainting. + -- Billy Rose +%% +Never kick a man, unless he's down. +%% +Never laugh at live dragons. + -- Bilbo Baggins +%% +Never leave anything to chance; +make sure all your crimes are premeditated. +%% +Never let someone who says it cannot be done +interrupt the person who is doing it. +%% +Never let your sense of morals prevent you from doing what is right. + -- Salvor Hardin, "Foundation" +%% +Never look a gift horse in the mouth. + -- Saint Jerome +%% +Never make anything simple and efficient when a +way can be found to make it complex and wonderful. +%% +Never pay a compliment as if expecting a receipt. +%% +Never play pool with anyone named "Fats". +%% +Never promise more than you can perform. + -- Publilius Syrus +%% +Never put off till run-time what you can do at compile-time. + -- D. Gries +%% +Never put off till tomorrow what you can avoid all together. +%% +Never put off until tomorrow what you can do the day after. +%% +Never reveal your best argument. +%% +Never say you know a man until you have divided an inheritance with him. +%% +Never sleep with a woman whose troubles are worse than your own. + -- Nelson Algren +%% +Never trust a child farther than you can throw it. +%% +Never trust a computer you can't repair yourself. +%% +Never trust an automatic pistol or a D.A.'s deal. + -- John Dillinger +%% +Never trust an operating system. +%% +Never trust anyone who says money is no object. +%% +Never try to outstubborn a cat. + -- Lazarus Long +%% +Never try to teach a pig to sing. +It wastes your time and annoys the pig. +%% +Never underestimate the power of human stupidity. +%% +Never use "etc." -- it makes people think there is more where +there is not or that there is not space to list it all, etc. +%% +Never volunteer for anything. + -- Lackland +%% +Never worry about theory as long as the +machinery does what it's supposed to do. + -- R.A. Heinlein +%% +New England Life, of course. Why? +%% +New Year's Eve is the time of year when a man most feels his +age, and his wife most often reminds him to act it. + -- Webster's Unafraid Dictionary +%% +New York-- to that tall skyline I come +Flyin' in from London to your door +New York-- lookin' down on Central Park +Where they say you should not wander after dark. +New York. + -- Simon and Garfunkle +%% +New York's got the ways and means, just won't let you be. +%% +New crypt. See /usr/news/crypt. +%% +New members are urgently needed in the Society +for Prevention of Cruelty to Yourself. Apply within. +%% +New systems generate new problems. +%% +Newlan's Truism: + An "acceptable" level of unemployment means that the + government economist to whom it is acceptable still has a job. +%% +Newlywed groom: + Honey, I have something to confess to you. I'm a golfer. + You'll never see me on Tuesday nights, Thursday nights, + and weekends. I'm sorry. +Newlywed bride: + I have something even worse to confess, dear. I'm a hooker. +Groom: + Oh, that's no problem! Just keep your head low and follow through... +%% +Newman's Discovery: + Your best dreams may not come true; + fortunately, neither will your worst dreams. +%% +Newton's Little-Known Seventh Law: + A bird in the hand is safer than one overhead. +%% +Next Friday will not be your lucky day. +As a matter of fact, you don't have a lucky day this year. +%% +Next to being shot at and missed, nothing is +really quite as satisfying as an income tax refund. + -- F.J. Raymond +%% +Nice guys don't finish nice. +%% +Nice guys finish last. + -- Leo Durocher +%% +Nice guys get sick. +%% +Nietzsche is pietzsche, Goethe is murder. +%% +Nihilism should commence with oneself. +%% +Niklaus Wirth has lamented that, whereas Europeans pronounce his +name correctly (Ni-klows Virt), Americans invariably mangle it into +(Nick-les Worth). Which is to say that Europeans call him by name, +but Americans call him by value. +%% +Nine megs for the secretaries fair, +Seven megs for the hackers scarce, +Five megs for the grads in smoky lairs, +Three megs for system source; + +One disk to rule them all, +One disk to bind them, +One disk to hold the files +And in the darkness grind 'em. +%% +Ninety-Ninety Rule of Project Schedules: + The first ninety percent of the task takes ninety percent of + the time, and the last ten percent takes the other ninety percent. +%% +Nitwit ideas are for emergencies. You use them when you've got nothing +else to try. If they work, they go in the Book. Otherwise you follow +the Book, which is largely a collection of nitwit ideas that worked. + -- Larry Niven, "The Mote in God's Eye" +%% +No, I don't have a drinking problem. +I drink, I get drunk, I fall down. No problem! +%% + "No, I understand now," Auberon said, calm in the woods -- it was so +simple, really. "I didn't, for a long time, but I do now. You just can't +hold people, you can't own them. I mean it's only natural, a natural process +really. Meet. Love. Part. Life goes on. There was never any reason to +expect her to stay always the same -- I mean `in love,' you know." There were +those doubt-quotes of Smoky's, heavily indicated. "I don't hold a grudge. I +can't." + "You do," Grandfather Trout said. "And you don't understand." + -- Little, Big, "John Crowley" +%% +No act of kindness, no matter how small, is ever wasted. + -- Aesop +%% +No amount of careful planning will ever replace dumb luck. +%% +No amount of genius can overcome a preoccupation with detail. +%% +No bird soars too high if he soars with his own wings. + -- William Blake +%% +No character, however upright, is a match for +constantly reiterated attacks, however false. + -- Alexander Hamilton +%% +No directory. +%% +No discipline is ever requisite to force +attendance upon lectures which are really worth the attending. + -- Adam Smith, "The Wealth of Nations" +%% +No doubt Jack the Ripper excused himself +on the grounds that it was human nature. +%% +No evil can happen to a good man. + -- Plato +%% +No excellent soul is exempt from a mixture of madness. + -- Aristotle +%% +No extensible language will be universal. + -- T. Cheatham +%% +No friendship is so cordial or so delicious as that of girl for girl; +no hatred so intense or immovable as that of woman for woman. + -- Landor +%% +No good deed goes unpunished. + -- Clare Boothe Luce +%% +No guest is so welcome in a friend's house that +he will not become a nuisance after three days. + -- Titus Maccius Plautus +%% +No guts, no glory. +%% +No, his mind is not for rent +To any god or government. +Always hopeful, yet discontent, +He knows changes aren't permanent - +But change is. +%% +No house should ever be on any hill or on anything. +It should be of the hill, belonging to it. + -- Frank Lloyd Wright +%% +No is no negative in a woman's mouth. + -- Sidney +%% +No line available at 300 baud. +%% +No live organism can continue for long to exist sanely under conditions of +absolute reality; even larks and katydids are supposed, by some, to dream. +Hill House, not sane, stood by itself against its hills, holding darkness +within; it had stood so for eighty years and might stand for eighty more. +Within, walls continued upright, bricks met neatly, floors were firm, and +doors were sensibly shut; silence lay steadily against the wood and stone +of Hill House, and whatever walked there, walked alone. + -- Shirley Jackson, "The Haunting of Hill House" +%% +No man is an Iland, intire of it selfe; every man is a peece of the +Continent, a part of the maine; if a Clod bee washed away by the Sea, +Europe is the lesse, as well as if a Promontorie were, as well as if +a Mannor of thy friends or of thine owne were; any mans death diminishes +me, because I am involved in Mankinde; And therefore never send to know +for whom the bell tolls; It tolls for thee. + -- John Donne, "No Man is an Iland" +%% +No man is an island, but some of us are long peninsulas. +%% +No man is useless who has a friend, +and if we are loved we are indispensable. + -- Robert Louis Stevenson +%% +No man would listen to you talk if +he didn't know it was his turn next. + -- E.W. Howe +%% +No man's ambition has a right to stand in +the way of performing a simple act of justice. + -- John Altgeld +%% +No matter how clever the hardware boys +are, the software boys piss it away. +%% +No matter what happens, there is always someone who knew it would. +%% +No matter where I go, the place is always called "here". +%% +No matter who you are, some scholar can show you +the great idea you had was had by someone before you. +%% +No matther whether th' constitution follows th' flag or not, +th' supreme court follows th' iliction returns. + -- Mr. Dooley +%% +No one becomes depraved in a moment. + -- Decimus Junius Juvenalis +%% +No one can feel as helpless as the owner of a sick goldfish. +%% +No one can make you feel inferior without your consent. + -- Eleanor Roosevelt +%% +No one can put you down without your full cooperation. +%% +No one knows like a woman how to say +things that are at once gentle and deep. + -- Hugo +%% +No one knows what he can do till he tries. + -- Publilius Syrus +%% +No one regards what is before his feet; we all gaze at the stars. + -- Quintus Ennius +%% +No pig should go sky diving during monsoon +For this isn't really the norm. +But should a fat swine try to soar like a loon, +So what? Any pork in a storm. + +No pig should go sky diving during monsoon, +It's risky enough when the weather is fine. +But to have a pig soar when the monsoon doth roar +Cast even more perils before swine. +%% +No problem is insoluble in all conceivable circumstances. +%% +No problem is so formidable that you can't just walk away from it. +%% +No problem is so formidable that you can't just walk away from it. + -- C. Schulz +%% +No problem is so large it can't be fit in somewhere. +%% +"No program is perfect," +They said with a shrug. +"The customer's happy-- +What's one little bug?" + +But he was determined, Then change two, then three more, +The others went home. As year followed year. +He dug out the flow chart And strangers would comment, +Deserted, alone. "Is that guy still here?" + +Night passed into morning. He died at the console +The room was cluttered Of hunger and thirst +With core dumps, source listings. Next day he was buried +"I'm close," he muttered. Face down, nine edge first. + +Chain smoking, cold coffee, And his wife through her tears +Logic, deduction. Accepted his fate. +"I've got it!" he cried, Said "He's not really gone, +"Just change one instruction." He's just working late." + -- The Perfect Programmer +%% +No question is so difficult as one to which the answer is obvious. +%% +No rock so hard but that a little wave +May beat admission in a thousand years. + -- Tennyson +%% +No self-made man ever did such a good job +that some woman didn't want to make some alterations. + -- Kim Hubbard +%% +No skis take rocks like rental skis! +%% +No small art is it to sleep: it is necessary +for that purpose to keep awake all day. + -- Nietzsche +%% +No snowflake in an avalanche ever feels responsible. +%% +No sooner had Edger Allen Poe +Finished his old Raven, +then he started his Old Crow. +%% +No sooner said than done -- so acts your man of worth. + -- Quintus Ennius +%% +No spitting on the Bus! +Thank you, The Management. +%% +No two persons ever read the same book. + -- Edmund Wilson +%% +No use getting too involved in life -- +you're only here for a limited time. +%% +No wonder Clairol makes so much money selling shampoo. +Lather, Rinse, Repeat is an infinite loop! +%% +No wonder you're tired! You understood so much today. +%% +No yak too dirty; no dumpster too hollow. +%% +Nobody can be as agreeable as an uninvited guest. +%% +Nobody ever ruined their eyesight by looking at the bright side of something. +%% +Nobody is one block of harmony. We are all afraid of something, or feel +limited in something. We all need somebody to talk to. It would be good +if we talked to each other--not just pitter-patter, but real talk. We +shouldn't be so afraid, because most people really like this contact; +that you show you are vulnerable makes them free to be vulnerable too. +It's so much easier to be together when we drop our masks. + -- Liv Ullman +%% +Nobody knows the trouble I've been. +%% +Nobody knows what goes between his cold toes and his warm ears. + -- Roy Harper +%% +Nobody loves me, +Everybody hates me, +I think I'll go out and eat worms. +I'm gonna cut their heads off, +Eat their insides out, +And throw way the skins. +Big, fat, juicy ones, +Little, skinny, cute ones, +Watch how they wiggle and they squirm. +%% +Nobody shot me. + -- Frank Gusenberg, his last words, when asked by police + who had shot him 14 times with a machine gun in the Saint + Valentine's Day massacre. +%% +Nobody wants constructive criticism. +It's all we can do to put up with constructive praise. +%% +Noise proves nothing. Often a hen who has +merely laid an egg cackles as if she laid an asteroid. + -- Mark Twain +%% +Non Illegitemus Carborundum. + [Don't let the bastards wear you down.] +%% +Non-Determinism is not meant to be reasonable. + -- M.J. 0'Donnell +%% +Noncombatant: + A dead Quaker. + -- Ambrose Bierce +%% +Nondeterminism means never having to say you are wrong. +%% +Nonsense. Space is blue and birds fly through it. + -- Heisenberg +%% +Nonsense and beauty have close connections. + -- E.M. Forster +%% +Normal times may possibly be over forever. +%% +Normally our rules are rigid; we tend to discretion, if for no other +reason than self-protection. We never recommend any of our graduates, +although we cheerfully provide information as to those who have failed +their courses. + -- Jack Vance, "Freitzke's Turn" +%% +Nostalgia just isn't what it used to be. +%% +Not all men who drink are poets. +Some of us drink because we aren't poets. +%% +Not all who own a harp are harpers. + -- Marcus Terentius Varro +%% +Not drinking, chasing women, or doing drugs won't +make you live longer -- it just seems that way. +%% +Not every question deserves an answer. +%% +Not everything worth doing is worth doing well. +%% +Not far from here, by a white sun, behind a green star, lived the +Steelypips, illustrious, industrious, and they hadn't a care: no spats +in their vats, no rules, no schools, no gloom, no evil influence of the +moon, no trouble from matter or antimatter -- for they had a machine, +a dream of a machine, with springs and gears and perfect in every +respect. And they lived with it, and on it, and under it, and inside +it, for it was all they had -- first they saved up all their atoms, +then they put them all together, and if one didn't fit, why they +chipped at it a bit, and everything was just fine... + -- Stanislaw Lem +%% +Not that we needed all that stuff, but when you get locked into a +serious drug collection the tendency is to push it as far as you can. + -- Hunter S. Thompson, "Fear and Loathing in Las Vegas" +%% +Not to laugh, not to lament, not to curse, but to understand. + -- Spinoza +%% +Nothing astonishes men so much as common sense and plain dealing. + -- Ralph Waldo Emerson +%% +Nothing can be done in one trip. + -- Snider +%% +Nothing cures insomnia like the realization that it's time to get up. +%% +Nothing endures but change. + -- Heraclitus + [Yeah, yeah, "Everything changes but change itself." --JFK Ed.] +%% +Nothing ever becomes real till it is experienced -- even a +proverb is no proverb to you till your life has illustrated it. + -- John Keats +%% +Nothing in life is to be feared. It is only to be understood. +%% +Nothing increases your golf score like witnesses. +%% +Nothing is but what is not. +%% +Nothing is ever a total loss; it can always serve as a bad example. +%% +Nothing is faster than the speed of light. + +To prove this to yourself, try opening the +refrigerator door before the light comes on. +%% +Nothing is finished until the paperwork is done. +%% +Nothing is illegal if one hundred businessmen decide to do it. + -- Andrew Young +%% +Nothing is impossible for the man who doesn't have to do it himself. + -- Weller +%% +Nothing is more quiet than the sound of hair going grey. +%% +Nothing is rich but the inexhaustible wealth of nature. +She shows us only surfaces, but she is a million fathoms deep. + -- Ralph Waldo Emerson +%% +Nothing is so firmly believed as which is least known. + -- Michel Eyquem de Montaigne +%% +Nothing is so often irretrievably missed as a daily opportunity. + -- Ebner-Eschenbach +%% +Nothing motivates a man more than to +see his boss put in an honest day's work. +%% +Nothing, nothing, nothing, no error, no crime is so absolutely +repugnant to God as everything which is official; and why? because +the official is so impersonal and therefore the deepest insult +which can be offered to a personality. + -- Soren Kierkegaard +%% +Nothing recedes like success. + -- Walter Winchell +%% +Nothing so needs reforming as other people's habits. + -- Mark Twain +%% +Nothing succeeds like excess. + -- Oscar Wilde +%% +Nothing succeeds like success. + -- Alexandre Dumas +%% +Nothing takes the taste out of peanut +butter quite like unrequited love. + -- Charlie Brown +%% +Nothing that's forced can ever be right, + if it doesn't come naturally leave it. +That's what she said as she turned out the light, +And we bent our backs as slaves in the night, +She lowered her guard, showed me the scars she got from trying to fight, +Said, "Oh, you better believe it." +[...] +Well nothing that's real is ever for free and you just have to + pay for it sometime. +She said it before, she said it to me, +I suppose she believed there was nothing to see, +But the same old four imaginary walls +She'd built for livin' inside +I said "Oh, you just can't mean it." +[...] +Well, nothing that's forced can ever be right, if it doesn't come + naturally leave it. +That's what she said as she turned out the light, +And she may have been wrong and she may have been right, +But I woke with the frost, + I noticed she'd lost the veil that covered her eyes, +I said "Oh, you can leave it." + -- Al Stewart, "If It Doesn't Come Naturally" +%% +Nothing will dispel enthusiasm like a small admission fee. + -- Kim Hubbard +%% +Nothing will ever be attempted +if all possible objections must be first overcome. + -- Dr. Johnson +%% +Novinson's Revolutionary Discovery: + + When comes the revolution, things will be different -- + not better, just different. +%% +Now I lay me down to sleep, +I pray the Lord my soul to keep, +If I should die before I wake, +I'll cry in anguish, Mistake!! Mistake!! +%% +Now I lay me down to sleep +I pray the double lock will keep; +May no brick through the window break, +And, no one rob me till I awake. +%% +Now I lay me down to study, +I pray the Lord I won't go nutty. +And if I fail to learn this junk, +I pray the Lord that I won't flunk. +But if I do, don't pity me at all, +Just lay my bones in the study hall. +Tell my teacher I've done my best, +Then pile my books upon my chest. +%% +Now and then an innocent man is sent to the legislature. +%% +Now is the time for all good men to come to. + -- Walt Kelly +%% +Now is the time for drinking; +now the time to beat the earth with unfettered foot. + -- Quintus Horatius Flaccus (Horace) +%% +Now it is such a bizarrely improbable coincidence that anything so mind- +bogglingly useful could have evolved purely by chance that some thinkers +have chosen to see it as a final and clinching proof of the non-existence +of God. The argument follows: "I refuse to prove that I exist," says God, +"for proof denies faith, and without faith I am nothing." "But," says Man, +"the Babel fish is a dead giveaway, isn't it? It could not have evolved +by chance, thus proving that you exist, therefore by your own arguements, +you don't. QED." "Oh, dear," says God, "I hadn't thought of that," and +promptly vanishes in a puff of logic. + -- D. Adams +%% +Now it's time to say goodbye +To all our company... +M-I-C (see you next week!) +K-E-Y (Why? Because we LIKE you!) +M-O-U-S-E. +%% +Now of my threescore years and ten, +Twenty will not come again, +And take from seventy springs a score, +It leaves me only fifty more. + +And since to look at things in bloom +Fifty springs are little room, +About the woodlands I will go +To see the cherry hung with snow. + -- A.E. Housman +%% + Now she speaks rapidly. "Do you know *why* you want to program?" + He shakes his head. He hasn't the faintest idea. + "For the sheer *joy* of programming!" she cries triumphantly. +"The joy of the parent, the artist, the craftsman. "You take a program, +born weak and impotent as a dimly-realized solution. You nurture the +program and guide it down the right path, building, watching it grow ever +stronger. Sometimes you paint with tiny strokes, a keystroke added here, +a keystroke changed there." She sweeps her arm in a wide arc. "And other +times you savage whole *blocks* of code, ripping out the program's very +*essence*, then beginning anew. But always building, creating, filling the +program with your own personal stamp, your own quirks and nuances. Watching +the program grow stronger, patching it when it crashes, until finally it can +stand alone--proud, powerful, and perfect. This is the programmer's finest +hour!" Softly at first, then louder, he hears the strains of a Sousa march. +"This ... this is your canvas! your clay! Go forth and create a masterwork!" +%% +Now that day wearies me, +My yearning desire +Will receive more kindly, +Like a tired child, the starry night. + +Hands, leave off your deeds, +Mind, forget all thoughts; +All of my forces +Yearn only to sink into sleep. + +And my soul, unguarded, +Would soar on widespread wings, +To live in night's magical sphere +More profoundly, more variously. + -- Hermann Hesse, "Going to Sleep" +%% +Now that you've read Fortune's diet truths, you'll be prepared the next time +some housewife or boutique owner turned diet expert appears on TV to plug +her latest book. And, if you still feel a twinge of guilt for eating coffee +cake while listening to her exhortations, ask yourself the following questions: + +1: Do I dare trust a person who actually considers alfalfa sprouts a food? +2: Was the author's sole motive in writing this book to get rich + exploiting the forlorn hopes of chubby people like me? +3: Would a longer life be worthwhile if it had to be lived as prescribed... + without French-fried onion rings, pizza with double cheese, or the + occasional Mai-Tai? (Remember, living right doesn't really make + you live longer, it just *seems* like longer.) + +That, and another piece of coffee cake, should do the trick. +%% +Now the Lord God planted a garden East of Whittier in a place called +Yorba Linda, and out of the ground he made to grow orange trees that +were good for food and the fruits thereof he labeled SUNKIST... +%% +Now there's three things you can do in a baseball game: +you can win or you can lose or it can rain. + -- Casey Stengel +%% +Now what would they do if I just sailed away? +Who the hell really compelled me to leave today? +Runnin' low on stories of what made it a ball, +What would they do if I made no landfall?" + -- Jimmy Buffet, "Landfall" +%% +[Nuclear war] ... may not be desirable. + -- Edwin Meese III +%% +Nudists are people who wear one-button suits. +%% +Nuke the unborn gay female whales for Jesus. +%% +Nuke them till they glow, then shoot them in the dark. +%% +Nullum magnum ingenium sine mixtura dementiae fuit. + -- Seneca +%% +Numeric stability is probably not all that important when you're guessing. +%% +Nurse Donna: Oh, Groucho, I'm afraid I'm gonna wind up an old maid. +Groucho: Well, bring her in and we'll wind her up together. +Nurse Donna: Do you believe in computer dating? +Groucho: Only if the computers really love each other. +%% +Nusbaum's Rule: + The more pretentious the corporate name, the smaller the + organization. (For instance, the Murphy Center for the + Codification of Human and Organizational Law, contrasted + to IBM, GM, and AT&T.) +%% +O! If I were a fish +I'd lay hap'ly on my dish. +Yes, that's my one and only wish -- +To be a fish! + +For fish don't ever mish; +They needn't flush after they pish! +Yes, and life's just swish, swish, swish, +For all the fish!!! +%% + `O' LEVEL COUNTER CULTURE +Timewarp allowed: 3 hours. Do not scrawl situationalist graffiti in the +margins or stub your rollups in the inkwells. Orange may be worn. Credit +will be given to candidates who self-actualise. + + 1: Compare and contrast Pink Floyd with Black Sabbath and say why +neither has street credibility. + 2: "Even Buddha would have been hard pushed to reach Nirvana squatting +on a juggernaut route." Consider the dialectic of inner truth and inner +city. + 3: Discuss degree of hassle involved in paranoia about being sucked +into a black hole. + 4: "The Egomaniac's Liberation Front were a bunch of revisionist +ripoff merchants." Comment on this insult. + 5: Account for the lack of references to brown rice in Dylan's lyrics. + 6: "Castenada was a bit of a bozo." How far is this a fair summing +up of western dualism? + 7: Hermann Hesse was a Pisces. Discuss. +%% +O give me a home, +Where the buffalo roam, +Where the deer and the antelope play, +Where seldom is heard +A discouraging word, +'Cause what can an antelope say? +%% +O imitators, you slavish herd! + -- Quintus Horatius Flaccus (Horace) +%% +O, it is excellent +To have a giant's strength; but it is tyrannous +To use it like a giant. + -- Shakespeare, "Measure for Measure", II, 2] +%% +O love, could thou and I with fate conspire +To grasp this sorry scheme of things entire, +Might we not smash it to bits +And mould it closer to our hearts' desire? + -- Omar Khayyam, tr. FitzGerald +%% +O'Brian's Law: + Everything is always done for the wrong reasons. +%% +O'Brien held up his left hand, its back toward Winston, with the +thumb hidden and the four fingers extended. + "How many fingers am I holding up, Winston?" + "Four." + "And if the Party says that it is not four but five -- + then how many?" + "Four." + The word ended in a gasp of pain. + -- George Orwell +%% +OCCAM'S ERASER: + The philosophical principle that even the simplest + solution is bound to have something wrong with it. +%% +OCCIDENT: + The part of the world lying west (or east) of the Orient. It is + largely inhabited by Christians, powerful sub-tribe of the + Hypocrites, whose principal industries are murder and cheating, + which they are pleased to call "war" and "commerce." These, also, + are the principal industries of the Orient. + -- Ambrose Bierce +%% +OCEAN: + A body of water occupying about two-thirds + of a world made for man -- who has no gills. +%% +O.K., fine. +%% +OLD TIMER: + One who remembers when charity was a virtue and not an organization. +%% +ONE LIFE TO LIVE for ALL MY CHILDREN in +ANOTHER WORLD all THE DAYS OF OUR LIVES. +%% +ONE SIZE FITS ALL: + Doesn't fit anyone. +%% +OPTIMIST: + A man who makes a motel reservation before a blind date. +%% +OPTIMIST: + A proponent of the belief that black is white. + + A pessimist asked God for relief. + "Ah, you wish me to restore your hope and cheerfulness," said God. + "No," replied the petitioner, "I wish you to create something that +would justify them." + "The world is all created," said God, "but you have overlooked +something -- the mortality of the optimist." + -- Ambrose Bierce, "The Devil's Dictionary" +%% +OPTIMIST: + Someone who goes down to the marriage + bureau to see if his license has expired. +%% +ORAL CONTRACEPTIVE: + The word "No". +%% +OREGON: + Eighty billion gallons of water with + no place to go on Saturday night. +%% +O'Riordan's Theorem: + Brains x Beauty = Constant. + +Purmal's Corollary: + As the limit of (Brains x Beauty) goes to infinity, + availability goes to zero. +%% +O'Toole's commentary on Murphy's Law: + Murphy was an optimist. +%% +Oatmeal raisin. +%% +Objects are lost only because people +look where they are not rather than where they are. +%% +Observe yon plumed biped fine. +To activate its captivation, +Deposit on its termination, +A quantity of particles saline. +%% +Obstacles are what you see when you take your eyes off your goal. +%% +Obviously the only rational solution to your problem is suicide. +%% +Obviously the subject of death was in the air, but more as something to +be avoided than harped upon. + +Possibly the horror that Zaphod experienced at the prospect of being +reunited with his deceased relatives led on to the thought that they +might just feel the same way about him and, what's more, be able to do +something about helping to postpone this reunion. + -- Douglas Adams +%% +Of all forms of caution, caution in love is the most fatal. +%% +Of all men's miseries, the bitterest is this: +to know so much and have control over nothing. + -- Herodotus +%% +Of all the animals, the boy is the most unmanageable. + -- Plato +%% +Of all things man is the measure. + -- Protagoras +%% +Of course, I speak of nothing else but that classic of understated yet +wildly exciting eroticism, "The Windflower," by Laura London. Ms. London +is the author of such other philosophical block-busters as "Bad Baron's +Daughter," "A Heart Too Proud," "Moonlight Mist," and most thigh-warming +of all, "Gypsy Heiress". Well, glasses-steaming scenes are to be found +on every page, to an extent which overwhelms Your Humble Narrator, and so, +in order to save himself extreme embarrassment, he brings you... the blurb: + + "Every lady of breeding knows: no one has a good time on a +pirate ship. No one, that is, but the pirates. Yet there she was, +Merry Wilding -- kidnapped in error, taken from a ship bound from +New York to England, spirited away in a barrel and swept aboard the +infamous "Black Joke"... There she was, trembling with pleasure in +the arms of her achingly handsome, sensationally sensual, golden-haired +captor -- Devon." +%% +Of course there's no reason for it, it's just our policy. +%% +Of course you have a purpose -- to find a purpose. +%% +Official Project Stages: + 1. Uncritical Acceptance + 2. Wild Enthusiasm + 3. Dejected Disillusionment + 4. Total Confusion + 5. Search for the Guilty + 6. Punishment of the Innocent + 7. Promotion of the Non-participants +%% +Often statistics are used as a drunken man uses +lampposts -- for support rather than illumination. +%% +Often things ARE as bad as they seem! +%% +Ogden's Law: + The sooner you fall behind, the more time you have to catch up. +%% +Oh, Aunty Em, it's so good to be home! +%% +Oh, I could while away the hours, +Smoking herbs and flowers, +Shooting up my veins, + De-dum, De-dum, De-dum +Tell you, I've been a-thinkin' +I could drive a shiny Lincoln, +If I dealt in good cocaine. + -- To If I Only Had A Brain from "The Wizard of Oz" +%% +Oh, by the way, which one's Pink? + -- Pink Floyd +%% +Oh don't the days seem lank and long +When all goes right and none goes wrong, +And isn't your life extremely flat +With nothing whatever to grumble at! +%% +Oh freddled gruntbuggly, thy micturations are to me +As plurdled gabbleblotchits on a lurgid bee. +Groop I implore thee, my foonting turlingdromes, +And hooptiously drangle me with crinkly bindlewurdles, +Or I will rend thee in the goblerwarts with my blurglecruncheon, + see if I don't. + -- Prostetnic Vogon Jeltz +%% +Oh, give me a locus where the gravitons focus + Where the three-body problem is solved, + Where the microwaves play down at three degrees K, + And the cold virus never evolved. (chorus) +We eat algea pie, our vacuum is high, + Our ball bearings are perfectly round. + Our horizon is curved, our warheads are MIRVed, + And a kilogram weighs half a pound. (chorus) +If we run out of space for our burgeoning race + No more Lebensraum left for the Mensch + When we're ready to start, we can take Mars apart, + If we just find a big enough wrench. (chorus) +I'm sick of this place, it's just McDonald's in space, + And living up here is a bore. + Tell the shiggies, "Don't cry," they can kiss me goodbye + 'Cause I'm moving next week to L4! (chorus) + +CHORUS: Home, home on LaGrange, + Where the space debris always collects, + We possess, so it seems, two of Man's greatest dreams: + Solar power and zero-gee sex. + -- to Home on the Range +%% +"Oh, he [a big dog] hunts with papa," she said. "He says Don Carlos [the +dog] is good for almost every kind of game. He went duck hunting one time +and did real well at it. Then Papa bought some ducks, not wild ducks but, +you know, farm ducks. And it got Don Carlos all mixed up. Since the +ducks were always around the yard with nobody shooting at them he knew he +wasn't supposed to kill them, but he had to do something. So one morning +last spring, when the ground was still soft, he took all the ducks and +buried them." "What do you mean, buried them?" "Oh, he didn't hurt them. +He dug little holes all over the yard and picked up the ducks in his mouth +and put them in the holes. Then he covered them up with mud except for +their heads. He did thirteen ducks that way and was digging a hole for +another one when Tony found him. We talked about it for a long time. Papa +said Don Carlos was afraid the ducks might run away, and since he didn't +know how to build a cage he put them in holes. He's a smart dog." + -- R. Bradford, "Red Sky At Morning" +%% +Oh, life is a glorious cycle of song, +A medley of extemporanea; +And love is thing that can never go wrong; +And I am Marie of Roumania. + -- Dorothy Parker, "Comment" +%% +Oh, so there you are! +%% +Oh this age! How tasteless and ill-bred it is. + -- Gaius Valerius Catullus +%% +Oh wearisome condition of humanity! +Born under one law, to another bound. + -- Fulke Greville, Lord Brooke +%% +Oh, well, I guess this is just going to be one of those lifetimes. +%% +Oh, what a tangled web we weave when first we practice to conceive. + -- Don Herold +%% +Oh what a tangled web we weave, when first we practice to deceive. + -- Shakespeare +%% +Oh, when I was in love with you, + Then I was clean and brave, +And miles around the wonder grew + How well did I behave. + +And now the fancy passes by, + And nothing will remain, +And miles around they'll say that I + Am quite myself again. + -- A.E. Housman +%% +Oh, wow! Look at the moon! +%% +Oh yeah? Well, I remember when sex was dirty and the air was clean. +%% +Oh, yeah, life goes on, long after the thrill of livin' is gone. + -- John Cougar, "Jack and Diane" +%% +Okay, Okay -- I admit it. You didn't change that program that worked +just a little while ago; I inserted some random characters into the +executable. Please forgive me. You can recover the file by typing in +the code over again, since I also removed the source. +%% +Old Grandad is dead but his spirits live on. +%% +Old MacDonald had an agricultural real estate tax abatement. +%% +Old McDonald had a farm, +E-I-E-I-O +And on this farm he had some chicks, +E-I-E-I-O +With a chickie-poo here, and a chickie-poo there, +Here a chick, there a chick, everywhere a whoop-ti-doo, +Old McDonald lost his farm, +'Cause he had too many chicks. +%% +Old age and treachery will overcome youth and skill. +%% +Old age is the harbor of all ills. + -- Bion +%% +Old age is the most unexpected of things that can happen to a man. + -- Trotsky +%% +Old mail has arrived. +%% +Old men are fond of giving good advice to console +themselves for their inability to give bad examples. +%% +Old musicians never die, they just decompose. +%% +Old programmers never die, they just become managers. +%% +Old programmers never die, they just branch to a new address. +%% +Old programmers never die, they just hit account block limit. +%% +Old soldiers never die. Young ones do. +%% +Oliver's Law: + Experience is something you don't get until just after you need it. +%% +Olmstead's Law: + After all is said and done, a hell of a lot more is said than done. +%% +On a clear day, U.C.L.A. +%% +On a clear disk you can seek forever. + -- P. Denning +%% +On a tous un peu peur de l'amour, mais on +a surtout peur de souffrir ou de faire souffrir. + +[One is always a little afraid of love, but +above all, one is afraid of pain or causing pain.] +%% +On ability: + A dwarf is small, even if he stands on a mountain top; + a colossus keeps his height, even if he stands in a well. + -- Lucius Annaeus Seneca, 4BC - 65AD +%% +On day a Monterey daughter +Did scuba down under the water. + She later turned up + The mom of a pup, +And they say t'was a otter that gotter. +%% + On his first day as a bus driver, Maxey Eckstein handed in +receipts of $65. The next day his take was $67. The third day's +income was $62. But on the fourth day, Eckstein emptied no less than +$283 on the desk before the cashier. + "Eckstein!" exclaimed the cashier. "This is fantastic. That +route never brought in money like this! What happened?" + "Well, after three days on that cockamamy route, I figured +business would never improve, so I drove over to Fourteenth Street and +worked there. I tell you, that street is a gold mine!" +%% +On the eighth day, God created FORTRAN. +%% + On the occasion of Nero's 25th birthday, he arrived at the Colosseum +to find that the Praetorian Guard had prepared a treat for him in the arena. +There stood 25 naked virgins, like candles on a cake, tied to poles, burning +alive. "Wonderful!" exclaimed the deranged emperor, "but one of them isn't +dead yet. I can see her lips moving. Go quickly and find out what she is +saying." + The centurion saluted, and hurried out to the virgin, getting as near +the flames as he dared, and listened intently. Then he turned and ran back +to the imperial box. "She is not talking," he reported to Nero, "she is +singing." + "Singing?" said the astounded emperor. "Singing what?" + "Happy birthday to you, happy birthday to you..." +%% +On the whole, I'd rather be in Philadelphia. + -- W.C. Fields' epitaph +%% +Once ... in the wilds of Afghanistan, I lost my corkscrew, +and we were forced to live on nothing but food and water for days. + -- W.C. Fields, "My Little Chickadee" +%% +Once I belonged to a group that really had THE WORD. I fought like hell +for them. But another group came along and exposed the word of my group +as shallow and degenerate. They had a better word. So I quit the first +group and lost all the friends I had made and I joined up with this new +group. I fought like hell for them. But another group came around. They +exposed the word of my group as false and materialistic. Their word was +very much better. So I quit the second group and lost all the friends I +had made. And I joined up with this new group. I fought like hell for them. +Till this one guy came along and proved that there wasn't any word at all. +That I should go off as an individual and grow! So I quit the last group +and lost all the friends I had made. And now I sit home alone all day and +all I do is grow. It would be nice to join up with some others who feel +the way I do. + -- J. Feiffer +%% +Once I finally figured out all of life's +answers, they changed the questions. +%% +Once, I read that a man be never stronger +than when he truly realizes how weak he is. + -- Jim Starlin, "Captain Marvel #31" +%% +Once Law was sitting on the bench + And Mercy knelt a-weeping. +"Clear out!" he cried, "disordered wench! + Nor come before me creeping. +Upon you knees if you appear, +'Tis plain you have no standing here." + +Then Justice came. His Honor cried: + "YOUR states? -- Devil seize you!" +"Amica curiae," she replied -- + "Friend of the court, so please you." +"Begone!" he shouted -- "There's the door -- +I never saw your face before!" +%% +Once a woman has given you her heart you +can never get rid of the rest of her. + -- Vanbrugh +%% +Once a word has been allowed to escape, it cannot be recalled. + -- Quintus Horatius Flaccus (Horace) +%% +Once, adv.: Enough. +%% +Once harm has been done, even a fool understands it. + -- Homer +%% +Once the realization is accepted that even between the closest human beings +infinite distances continue to exist, a wonderful living side by side can +grow up, if they succeed in loving the distance between them which makes it +possible for each to see each other whole against the sky. + -- Rainer Rilke +%% +Once the toothpaste is out of the tube, it's hard to get it back in. + -- H.R. Haldeman +%% + Once there lived a village of creatures along the bottom of a great +crystal river. Each creature in its own manner clung tightly to the twigs +and rocks of the river bottom, for clinging was their way of life, and +resisting the current what each had learned from birth. But one creature +said at last, "I trust that the current knows where it is going. I shall +let go, and let it take me where it will. Clinging, I shall die of boredom." + The other creatures laughed and said, "Fool! Let go, and that current +you worship will throw you tumbled and smashed across the rocks, and you will +die quicker than boredom!" + But the one heeded them not, and taking a breath did let go, and at +once was tumbled and smashed by the current across the rocks. Yet, in time, +as the creature refused to cling again, the current lifted him free from the +bottom, and he was bruised and hurt no more. + And the creatures downstream, to whom he was a stranger, cried, "See +a miracle! A creature like ourselves, yet he flies! See the Messiah, come +to save us all!" And the one carried in the current said, "I am no more +Messiah than you. The river delight to lift us free, if only we dare let go. +Our true work is this voyage, this adventure. + But they cried the more, "Saviour!" all the while clinging to the +rocks, making legends of a Saviour. + -- Richard Bach +%% +Once there was a little nerd who loved to read your mail, +And then yank back the i-access times to get hackers off his tail, +And once as he finished reading from the secretary's spool, +He wrote a rude rejection to her boyfriend (how uncool!) +And this as delivermail did work and he ran his backfstat, +He heard an awful crackling like rat fritters in hot fat, +And hard errors brought the system down 'fore he could even shout! + And the bio bug'll bring yours down too, ef you don't watch out! +And once they was a little flake who'd prowl through the uulog, +And when he went to his blit that night to play at being god, +The ops all heard him holler, and they to the console dashed, +But when they did a ps -ut they found the system crashed! +Oh, the wizards adb'd the dumps and did the system trace, +And worked on the file system 'til the disk head was hot paste, +But all they ever found was this: "panic: never doubt", + And the bio bug'll crash your box too, ef you don't watch out! +When the day is done and the moon comes out, +And you hear the printer whining and the rk's seems to count, +When the other desks are empty and their terminals glassy grey, +And the load is only 1.6 and you wonder if it'll stay, +You must mind the file protections and not snoop around, + Or the bio bug'll getcha and bring the system down! +%% + Once there was a marine biologist who loved dolphins. He spent his +time trying to feed and protect his beloved creatures of the sea. One day, +in a fit of inventive genius, he came up with a serum that would make +dolphins live forever! + Of course he was ecstatic. But he soon realized that in order to mass +produce this serum he would need large amounts of a certain compound that was +only found in nature in the metabolism of a rare South American bird. Carried +away by his love for dolphins, he resolved that he would go to the zoo and +steal one of these birds. + Unbeknownst to him, as he was arriving at the zoo an elderly lion was +escaping from its cage. The zookeepers were alarmed and immediately began +combing the zoo for the escaped animal, unaware that it had simply lain down +on the sidewalk and had gone to sleep. + Meanwhile, the marine biologist arrived at the zoo and procured his +bird. He was so excited by the prospect of helping his dolphins that he +stepped absentmindedly stepped over the sleeping lion on his way back to his +car. Immediately, 1500 policemen converged on him and arrested him for +transporting a myna across a staid lion for immortal porpoises. +%% +Once there was this conductor see, who had a bass problem. You see, during +a portion of Beethovan's Ninth Symphony in which there are no bass violin +parts, one of the bassists always passed a bottle of scotch around. So, +to remind himself that the basses usually required an extra cue towards the +end of the symphony, the conductor would fasten a piece of string around the +page of the score before the bass cue. As the basses grew more and more +inebriated, two of them fell asleep. The conductor grew quite nervous (he +was very concerned about the pitch) because it was the bottom of the ninth; +the score was tied and the basses were loaded with two out. +%% +Once upon a time there... +%% + Once upon a time there was a beautiful young girl taking a stroll +through the woods. All at once she saw an extremely ugly bull frog seated +on a log and to her amazement the frog spoke to her. "Maiden," croaked the +frog, "would you do me a favor? This will be hard for you to believe, but +I was once a handsome, charming prince and then a mean, ugly old witch cast +a spell over me and turned me into a frog." + "Oh, what a pity!", exclaimed the girl. "I'll do anything I can to +help you break such a spell." + "Well," replied the frog, "the only way that this spell can be +taken away is for some lovely young woman to take me home and let me spend +the night under her pillow." + The young girl took the ugly frog home and placed him beneath her +pillow that night when she retired. When she awoke the next morning, sure +enough, there beside her in bed was a very young, handsome man, clearly of +royal blood. And so they lived happily ever after, except that to this day +her father and mother still don't believe her story. +%% + Once upon a time there were three brothers who were knights +in a certain kingdom. And, there was a Princess in a neighboring kingdom +who was of marriageable age. Well, one day, in full armour, their horses, +and their page, the three brothers set off to see if one of them could +win her hand. The road was long and there were many obstacles along the +way, robbers to be overcome, hard terrain to cross. As they coped with +each obstacle they became more and more disgusted with their page. He was +not only inept, he was a coward, he could not handle the horses, he was, +in short, a complete flop. When they arrived at the court of the kingdom, +they found that they were expected to present the Princess with some +treasure. The two older brothers were discouraged, since they had not +thought of this and were unprepared. The youngest, however, had the +answer: Promise her anything, but give her our page. +%% +Once upon a time, when I was training to be a mathematician, a group of +us bright young students taking number theory discovered the names of the +smaller prime numbers. + +2: The Odd Prime -- + It's the only even prime, therefore is odd. QED. +3: The True Prime -- + Lewis Carroll: "If I tell you 3 times, it's true." +31: The Arbitrary Prime -- + Determined by unanimous unvote. We needed an arbitrary prime in + case the prof asked for one, and so had an election. 91 received + the most votes (well, it *looks* prime) and 3+4i the next most. + However, 31 was the only candidate to receive none at all. +41: The Female Prime -- + The polynomial X**2 - X + 41 is + prime for integer values from 1 to 40. +43: The Male Prime - they form a prime pair. + +Since the composite numbers are formed from primes, their qualities +are derived from those primes. So, for instance, the number 6 is "odd +but true", while the powers of 2 are all extremely odd numbers. +%% +Once you've seen one nuclear war, you've seen them all. +%% +Once you've tried to change the world you find +it's a whole bunch easier to change your mind. +%% +One Bell System - it sometimes works. +%% +One Bell System - it used to work before they installed the Dimension! +%% +One Bell System - it works. +%% +One big pile is better than two little piles. + -- Arlo Guthrie +%% +One can never consent to creep when one feels an impulse to soar. + -- Helen Keller +%% +One can search the brain with a microscope and not find the +mind, and can search the stars with a telescope and not find God. + -- J. Gustav White +%% +One can't proceed from the informal to the formal by formal means. +%% + One day a student came to Moon and said, "I understand how to make +a better garbage collector. We must keep a reference count of the pointers +to each cons." + Moon patiently told the student the following story -- "One day a +student came to Moon and said, "I understand how to make a better garbage +collector..." +%% +One day, +A mad meta-poet, +With nothing to say, +Wrote a mad meta-poem +That started: "One day, +A mad meta-poet, +With nothing to say, +Wrote a mad meta-poem +That started: "One day, +[...] +sort of close". +Were the words that the poet, +Finally chose, +To bring his mad poem, +To some sort of close". +Were the words that the poet, +Finally chose, +To bring his mad poem, +To some sort of close". +%% +One difference between a man and a machine +is that a machine is quiet when well oiled. +%% + One evening he spoke. Sitting at her feet, his face raised to her, +he allowed his soul to be heard. "My darling, anything you wish, anything +I am, anything I can ever be... That's what I want to offer you -- not the +things I'll get for you, but the thing in me that will make me able to get +them. That thing -- a man can't renounce it -- but I want to renounce it -- +so that it will be yours -- so that it will be in your service -- only for +you." + The girl smiled and asked: "Do you think I'm prettier than Maggie +Kelly?" + He got up. He said nothing and walked out of the house. He never +saw that girl again. Gail Wynand, who prided himself on never needing a +lesson twice, did not fall in love again in the years that followed. + -- Ayn Rand, "The Fountainhead" +%% +One expresses well the love he does not feel. + -- J.A. Karr +%% +One family builds a wall, two families enjoy it. +%% +One good reason why computers can do more work than +people is that they never have to stop and answer the phone. +%% +One good suit is worth a thousand resumes. +%% +One good thing about music, +Well, it helps you feel no pain. +So hit me with music; +Hit me with music now. + -- Bob Marley, "Trenchtown Rock" +%% +One good turn asketh another. + -- John Heywood +%% +One good turn deserves another. + -- Gaius Petronius +%% +One good turn usually gets most of the blanket. +%% +One hundred and one uses for canned peaches. +One hundred and two if you plan to eat them. +%% +One man tells a falsehood, a hundred repeat it as true. +%% +One man's Mede is another man's Persian. + -- George M. Cohan +%% +One man's constant is another man's variable. + -- A.J. Perlis +%% +One man's "magic" is another man's engineering. +"Supernatural" is a null word. +%% +One man's theology is another man's belly laugh. +%% +One measure of friendship consists not in the number of things friends +can discuss, but in the number of things they need no longer mention. + -- Clifton Fadiman +%% +One meets his destiny often on the road he takes to avoid it. +%% +One morning after an evening of particularly heavy drinking, a man awoke +and upon rolling over in bed saw one of the ugliest women he had ever +seen. As he was about to get out of bed, he looked on the floor and saw +another woman even less appealing than the first. Seeing his look of +wide-eyed amazement, the woman on the floor snapped, "Don't look at me +like that, I was only the bridesmaid." +%% +One nice thing about egotists: they don't talk about other people. +%% +One nuclear bomb can ruin your whole day. +%% +One of my less pleasant chores when I was young was to read the Bible from +one end to the other. Reading the Bible straight through is at least 70 +percent discipline, like learning Latin. But the good parts are, of course, +simply amazing. God is an extremely uneven writer, but when He's good, +nobody can touch him. + -- John Gardner, NYT Book Review, Jan. 1983 +%% +One of the chief duties of the mathematician in acting as an +advisor... is to discourage... from expecting too much from +mathematics. + -- N. Wiener +%% +One of the large consolations for experiencing anything +unpleasant is the knowledge that one can communicate it. + -- Joyce Carol Oates +%% +One of the most expensive things in life +is a girl who is free for the evening. +%% +One of the most striking differences between a +cat and a lie is that a cat has only nine lives. + -- Mark Twain +%% + One of the questions that comes up all the time is: How enthusiastic +is our support for UNIX? + Unix was written on our machines and for our machines many years ago. +Today, much of UNIX being done is done on our machines. Ten percent of our +VAXs are going for UNIX use. UNIX is a simple language, easy to understand, +easy to get started with. It's great for students, great for somewhat casual +users, and it's great for interchanging programs between different machines. +And so, because of its popularity in these markets, we support it. We have +good UNIX on VAX and good UNIX on PDP-11s. + It is our belief, however, that serious professional users will run +out of things they can do with UNIX. They'll want a real system and will end +up doing VMS when they get to be serious about programming. + With UNIX, if you're looking for something, you can easily and quickly +check that small manual and find out that it's not there. With VMS, no matter +what you look for -- it's literally a five-foot shelf of documentation -- if +you look long enough it's there. That's the difference -- the beauty of UNIX +is it's simple; and the beauty of VMS is that it's all there. + -- Ken Olsen, president of DEC, DECWORLD Vol. 8 No. 5, 1984 +[It's been argued that the beauty of UNIX is the same as the beauty of Ken +Olsen's brain. Ed.] +%% +One of the rules of Busmanship, New York style, is never surrender your +seat to another passenger. This may seem callous, but it is the best +way, really. If one passenger were to give a seat to someone who fainted +in the aisle, say, the others on the bus would become disoriented and +imagine they were in Topeka Kansas. +%% +One of the worst of my many faults is that I'm too critical of myself. +%% +One of your most ancient writers, a historian named Herodotus, tells of a +thief who was to be executed. As he was taken away he made a bargain with +the king: in one year he would teach the king's favorite horse to sing +hymns. The other prisoners watched the thief singing to the horse and +laughed. "You will not succeed," they told him. "No one can." + To which the thief replied, "I have a year, and who knows what might +happen in that time. The king might die. The horse might die. I might die. +And perhaps the horse will learn to sing. + -- "The Mote in God's Eye", Niven and Pournelle +%% +One person's error is another person's data. +%% +One picture is worth 128K words. +%% +One picture is worth more than ten thousand words. + -- Chinese proverb +%% +One pill makes you larger And if you go chasing rabbits +And, one pill makes you small. And you know you're going to fall. +And the ones that mother gives you, Tell 'em a hookah smoking caterpillar +Don't do anything at all. Has given you the call. +Go ask Alice Call Alice +When she's ten feet tall. When she was just small. + +When men on the chessboard When logic and proportion +Get up and tell you where to go. Have fallen sloppy dead, +And you've just had some kind of And the White Knight is talking + mushroom backwards +And your mind is moving low. And the Red Queen's lost her head +Go ask Alice Remember what the dormouse said: +I think she'll know. Feed your head. + Feed your head. + Feed your head. + -- Jefferson Airplane, "White Rabbit" +%% +One planet is all you get. +%% +One possible reason why things aren't going +according to plan is that there never was a plan. +%% +One seldom sees a monument to a committee. +%% +One small step for man, one giant stumble for mankind. +%% +One thing the inventors can't seem to +get the bugs out of is fresh paint. +%% +One toke over the line, sweet Mary, +One toke over the line, +Sittin' downtown in a railway station, +One toke over the line. +Waitin' for the train that goes home, +Hopin' that the train is on time, +Sittin' downtown in a railway station, +One toke over the line. +%% +One, two, three, four +What are we fighting for? +Don't ask me I don't give a damn. +Next stop is Vietnam. +Five, six, seven, eight +Open up the pearly gates. +Ain't no time to wonder why +Whoopie! We're all going to die. + -- Country Joe and the Fish +%% +One way to stop a run away horse is to bet on him. +%% +Only God can make random selections. +%% +Only a fool has no doubts. +%% +Only a mediocre person is always at his best. + -- Laurence Peter +%% +Only adults have difficulty with childproof caps. +%% +Only fools are quoted. + -- Anonymous +%% +Only someone with nothing to be sorry for +smiles back at the rear of an elephant. +%% +Only that in you which is me can hear what I'm saying. + -- Baba Ram Dass +%% +Only the fittest survive. The vanquished acknowledge their unworthiness by +placing a classified ad with the ritual phrase "must sell -- best offer," +and thereafter dwell in infamy, relegated to discussing gas mileage and lawn +food. But if successful, you join the elite sodality that spends hours +unpurifying the dialect of the tribe with arcane talk of bits and bytes, RAMS +and ROMS, hard disks and baud rates. Are you obnoxious, obsessed? It's a +modest price to pay. For you have tapped into the same awesome primal power +that produces credit-card billing errors and lost plane reservations. Hail, +postindustrial warrior, subduer of Bounceoids, pride of the cosmos, keeper of +the silicone creed: Computo, ergo sum. The force is with you -- at 110 volts. +May your RAMS be fruitful and multiply. + -- Curt Suplee, "Smithsonian", 4/83 +%% +Only those who leisurely approach that which the masses are +busy about can be busy about that which the masses take leisurely. + -- Lao Tsu +%% +Only way to open lips of pigeon, sledgehammer. +%% +Ontogeny recapitulates phylogeny. +%% +Onward through the fog. +%% +Ooops. Gotta run. My dog wants sex. Later. +%% +Operator, please trace this call and tell me where I am. +%% +Opium is very cheap considering you don't +feel like eating for the next six days. + -- Taylor Mead, famous transvestite +%% +Oppernockity tunes but once. +%% +Opportunities are usually disguised as hard +work, so most people don't recognize them. +%% +Optimization hinders evolution. +%% +Or you or I must yield up his life to Ahrimanes. I would rather it were you. +I should have no hesitation in sacrificing my own life to spare yours, but +we take stock next week, and it would not be fair on the company. + -- J. Wellington Wells +%% +Orcs really aren't so bad (if you use lots of catsup). +%% +Order and simplification are the first steps toward +mastery of a subject -- the actual enemy is the unknown. + -- Thomas Mann +%% +Oreo +%% +Organic chemistry is the chemistry of carbon compounds. +Biochemistry is the study of carbon compounds that crawl. + -- Mike Adams +%% +Osborn's Law: + Variables won't; constants aren't. +%% +Other than that, Mrs. Lincoln, how did you like the play? +%% +Other women cloy +The appetites they feed, but she makes hungry +Where most she satisfies. + -- Antony and Cleopatra +%% +Others will look to you for stability, +so hide when you bite your nails. +%% +Our OS who art in CPU, UNIX be thy name. +Thy programs run, thy syscalls done, +In kernel as it is in user. +%% +Our business in life is not to succeed +but to continue to fail in high spirits. + -- Robert Louis Stevenson +%% +Our country has plenty of good five-cent cigars, +but the trouble is they charge fifteen cents for them. +%% +Our houseplants have a good sense of humous. +%% +Our little systems have their day; +They have their day and cease to be; +They are but broken lights of thee. + -- Tennyson +%% +Our policy is, when in doubt, do the right thing. + -- Roy L. Ash, ex-president, Litton Industries +%% +Our problems are so serious that the best +way to talk about them is lightheartedly. +%% + "Our school, madame, postulates, first of all, that since the +science of mathematics is an abstract science, it is best inculcated by +some concrete example." + Said the Queen, "But that sounds rather complicated." + "It occasionally leads to complications," Jurgen admitted, "through +a choice of the wrong example. But the axiom is no less true." + "Come, then, and sit next to me on this couch if you can find it in +the dark; and do you explain to me what you mean." + "Why, madame, by a concrete example I mean one that is perceptible +to any of the senses -- as to sight or hearing, or touch --" + "Oh, oh!" said the Queen, "now I perceive what you mean by a concrete +example. And grasping this, I can understand that complications must of +course arise from a choice of the wrong example." + -- James Branch Cabell, "Jurgen" +%% +Our sires' age was worse that our grandsires'. +We their sons are more worthless than they: +so in our turn we shall give the world a progeny yet more corrupt. + -- Quintus Horatius Flaccus (Horace) +%% +Our swords shall play the orators for us. + -- Christopher Marlowe +%% +Ours is a world where people don't know what they +want and are willing to go through hell to get it. +%% +Out of sight is out of mind. + -- Arthur Clough +%% +Out of the crooked timber of humanity no straight thing can ever be made. + -- Immanuel Kant +%% +Out of the mouths of babes does often come cereal. +%% +Over the shoulder supervision is more a +need of the manager than the programming task. +%% +Overconfidence breeds error when we take for granted that the game will +continue on its normal course; when we fail to provide for an unusually +powerful resource -- a check, a sacrifice, a stalemate. Afterwards the +victim may wail, `But who could have dreamt of such an idiotic-looking +move?' + -- Fred Reinfeld, "The Complete Chess Course" +%% +Overflow on /dev/null, please empty the bit bucket. +%% +Overload -- core meltdown sequence initiated. +%% +Owe no man any thing... + -- Romans 13:8 +%% +Ozman's Laws: + (1) If someone says he will do something "without fail," he won't. + (2) The more people talk on the phone, the less money they make. + (3) People who go to conferences are the ones who shouldn't. + (4) Pizza always burns the roof of your mouth. +%% +PAIN: + One thing, at least it proves that you're alive! +%% +PAIN: + Sliding down a 50-foot razor blade into a bucket of alcohol. +%% +PARANOIA: + A healthy understanding of the way the universe works. +%% +PARTY: + A gathering where you meet people who drink + so much you can't even remember their names. +%% +PASCAL: + A programming language named after a man who would turn over + in his grave if he knew about it. + -- Datamation, January 15, 1984 +%% +PATENT: + A method of publicizing inventions so others can copy them. +%% +PAYCHECK: + The weekly $5.27 that remains after deductions for federal + withholding, state withholding, city withholding, FICA, + medical/dental, long-term disability, unemployment insurance, + Christmas Club, and payroll savings plan contributions. +%% +PEACE: + In international affairs, a period of + cheating between two periods of fighting. + -- Ambrose Bierce +%% +PEEPING TOM: + A window fan. +%% +PENGUINICITY!! +%% +PENSION: + A federally insured chain letter. +%% +PERFECT GUEST: + One who makes his host feel at home. +%% +PERFORMANCE: + A statement of the speed at which a computer system works. Or + rather, might work under certain circumstances. Or was rumored + to be working over in Jersey about a month ago. +%% +PESSIMIST: + A man who spends all his time worrying + about how he can keep the wolf from the door. + +OPTIMIST: + A man who refuses to see the wolf + until he seizes the seat of his pants. + +OPPORTUNIST: + A man who invites the wolf in and + appears the next day in a fur coat. +%% +PHILOSOPHY: + The ability to bear with calmness + the misfortunes of our friends. +%% +PHILOSOPHY: + Unintelligible answers to insoluble problems. +%% +PIG: + An animal (Porcus omnivorous) closely allied to the human + race by the splendor and vivacity of its appetite, which, + however, is inferior in scope, for it balks at pig. + -- Ambrose Bierce +%% +PISCES (Feb. 19 - Mar. 20) + You have a vivid imagination and often think you are being followed + by the CIA or FBI. You have minor influence over your associates + and people resent your flaunting of your power. You lack confidence + and you are generally a coward. Pisces people do terrible things to + small animals. +%% +PISCES (Feb.19 - Mar.20) + You will get some very interesting news of a promotion today. + It will go to someone in the office you dislike and will be the + job you wanted. Don't lend anyone a car today. You don't have + a car. +%% +P-K4 +%% +PL/1, "the fatal disease", belongs more +to the problem set than to the solution set. + -- E.W. Dijkstra +%% +PLATONIC FRIENDSHIP: + What develops when two people get + tired of making love to each other. +%% +PLEASE DON'T SMOKE HERE! + +Penalty: An early, lingering death from cancer, + emphysema, or other smoking-caused ailment. +%% +PLUG IT IN!!! +%% +PLUNDERER'S THEME + (to Supercalifragilisticexpialidocius) + +Pillage, rape, and loot and burn, but all in moderation. +If you do the things we say, then you'll soon rule the nation. +Kill your foes and enemies and then kill your relations. +Pillage, rape, and loot and burn, but all in moderation. +%% +POLITICIAN: + From the Greek 'poly' ("many") and the French 'tete' ("head" or + "face," as in 'tete-a-tete': head to head or face to face). + Hence 'polytetien', a person of two or more faces. + -- Martin Pitt +%% +POLYGON: + Dead parrot. +%% +POSITIVE: + Being mistaken at the top of your voice. +%% +POVERTY: + An unfortunate state that persists as long + as anyone lacks anything he would like to have. +%% +POWER: + The only narcotic regulated by the SEC instead of the FDA. +%% +PPRB -- Pillage, plunder, rape and burn. +%% +PRAIRIES: + Vast plains covered by treeless forests. +%% +PROGRAM: + Any task that can't be completed in one telephone call or one + day. Once a task is defined as a program ("training program," + "sales program," or "marketing program"), its implementation + always justifies hiring at least three more people. +%% +PROGRESS: + Medieval man thought disease was caused by invisible demons + invading the body and taking possession of it. + + Modern man knows disease is caused by microscopic bacteria + and viruses invading the body and causing it to malfunction. +%% +PROMOTION FROM WITHIN: + A system of moving incompetents up to the policy-making + level where they can't foul up operations. +%% +PROMOTION: + New title, new salary, new office, same old crap. +%% +PURGE COMPLETE. +%% +Pain is just God's way of hurting you. +%% +Paranoia doesn't mean the whole world isn't out to get you. +%% +Paranoia is heightened awareness. +%% +Paranoia is simply an optimistic outlook on life. +%% +Paranoids are people, too; they have their own problems. It's easy +to criticize, but if everybody hated you, you'd be paranoid too. + -- D.J. Hicks +%% +Pardon me while I laugh. +%% +Pardo's First Postulate: + Anything good in life is either illegal, immoral, or fattening. + +Arnold's Addendum: + Anything not fitting into these categories causes cancer in rats. +%% +Parkinson's Fifth Law: + If there is a way to delay in important decision, the good + bureaucracy, public or private, will find it. +%% +Parkinson's Fourth Law: + The number of people in any working group tends to increase + regardless of the amount of work to be done. +%% +Parkinson's Law: + Work expands to fill the time available for its completion. +%% +Parts that positively cannot be assembled in improper order will be. +%% +Pascal Users: + The Pascal system will be replaced next Tuesday by Cobol. + Please modify your programs accordingly. +%% +Pascal Users: + To show respect for the 313th anniversary (tomorrow) of the + death of Blaise Pascal, your programs will be run at half speed. +%% +Pascal is not a high-level language. + -- Steven Feiner +%% +Passionate hatred can give meaning and purpose to an empty life. + -- Eric Hoffer +%% +Password: +%% +Passwords are implemented as a result of insecurity. +%% +Patch griefs with proverbs. + -- William Shakespeare, "Much Ado About Nothing" +%% +Patience is a minor form of despair, disguised as virtue. + -- Ambrose Bierce, on qualifiers +%% +Patience is the best remedy for every trouble. + -- Titus Maccius Plautus +%% +Pauca sed matura. (Few but excellent.) + -- Gauss +%% +Paul Revere was a tattle-tale. +%% +Paulg's Law: + In America, it's not how much an + item costs, it's how much you save. +%% +Paul's Law: + You can't fall off the floor. +%% +Pause for storage relocation. +%% +Payeen to a Twang +Derrida +Ore-Ida +potato. + +If you dared, +I'd ask you +to go dig +up your ides under brown- +tubered skies. + +where pitchforked +you will ask +Derrida? +%% +Paying alimony is like pumping gas into another man's car. +%% +Peace be to this house, and all that dwell in it. +%% +Peace cannot be kept by force; it +can only be achieved by understanding. + -- A. Einstein +%% +Peace is much more precious than a piece +of land... let there be no more wars. + -- Mohammed Anwar Sadat, 1918-1981 +%% +Peanut Blossoms + +4 cups sugar 16 tbsp. milk +4 cups brown sugar 4 tsp. vanilla +4 cups shortening 14 cups flour +8 eggs 4 tsp. soda +4 cups peanut butter 4 tsp. salt + +Shape dough into balls. Roll in sugar and bake on ungreased +cookie sheet at 375 F. for 10-12 minutes. Immediately top +each cookie with a Hershey's kiss or star pressing down firmly +to crack cookie. Makes a hell of a lot. +%% +Pecor's Health-Food Principle: + Never eat rutabaga on any day of + the week that has a "y" in it. +%% +Pelorat sighed. + "I will never understand people." + "There's nothing to it. All you have to do is take a close look +at yourself and you will understand everyone else. How would Seldon have +worked out his Plan -- and I don't care how subtle his mathematics was -- +if he didn't understand people; and how could he have done that if people +weren't easy to understand? You show me someone who can't understand +people and I'll show you someone who has built up a false image of himself +-- no offense intended." + -- Asimov, "Foundation's Edge" +%% +People are beginning to notice you. +Try dressing before you leave the house. +%% +People are unconditionally guaranteed to be full of defects. +%% +People humiliating a salami! +%% +People in general do not willingly read +if they have anything else to amuse them. + -- S. Johnson +%% + People of all sorts of genders are reporting great difficulty, +these days, in selecting the proper words to refer to those of the female +persuasion. + "Lady," "woman," and "girl" are all perfectly good words, but +misapplying them can earn one anything from the charge of vulgarity to a good +swift smack. We are messing here with matters of deference, condescension, +respect, bigotry, and two vague concepts, age and rank. It is troubling +enough to get straight who is really what. Those who deliberately misuse +the terms in a misbegotten attempt at flattery are asking for it. + A woman is any grown-up female person. A girl is the un-grown-up +version. If you call a wee thing with chubby cheeks and pink hair ribbons a +"woman," you will probably not get into trouble, and if you do, you will be +able to handle it because she will be under three feet tall. However, if you +call a grown-up by a child's name for the sake of implying that she has a +youthful body, you are also implying that she has a brain to match. +%% +People of privilege will always risk their complete destruction +rather than surrender any material part of their advantage. + -- John Kenneth Galbraith +%% +People often find it easier to be a +result of the past than a cause of the future. +%% +People respond to people who respond. +%% +People seem to think that the blanket phrase, "I only work here," +absolves them utterly from any moral obligation in terms of the +public -- but this was precisely Eichmann's excuse for his job in +the concentration camps. +%% +People think love is an emotion. Love is good sense. + -- Ken Kesey +%% +People usually get what's coming to them -- unless it's been mailed. +%% +People who claim they don't let little things bother +them have never slept in a room with a single mosquito. +%% +People who have no faults are terrible; +there is no way of taking advantage of them. +%% +People who have what they want are very fond of telling +people who haven't what they want that they don't want it. + -- Ogden Nash +%% +People who make no mistakes do not usually make anything. +%% +People who push both buttons should get their wish. +%% +People who take cat naps don't usually sleep in a cat's cradle. +%% +People who think they know everything +greatly annoy those of us who do. +%% +People will buy anything that's one to a customer. +%% +People with narrow minds usually have broad tongues. +%% +People's Action Rules: + (1) Some people who can, shouldn't. + (2) Some people who should, won't. + (3) Some people who shouldn't, will. + (4) Some people who can't, will try, regardless. + (5) Some people who shouldn't, but try, will then blame others. +%% +Per buck you get more computing action with the small computer. + -- R.W. Hamming +%% +Pereant, inquit, qui ante nos nostra dixerunt. +[Confound those who have said our remarks before us.] +or +[May they perish who have expressed our bright ideas before us.] + -- Aelius Donatus +%% +Perfect day for scrubbing the floor and other exciting things. +%% +Perfection is finally attained, not when there is no longer +anything to add, but when there is no longer anything to take away. + -- Antoine de Saint-Exupery +%% +Perhaps, after all, America never has been discovered. +I myself would say that it had merely been detected. + -- Oscar Wilde +%% +Perhaps no person can be a poet, or even enjoy +poetry without a certain unsoundness of mind. + -- Thomas Macaulay +%% +Perhaps the biggest disappointments were the ones you expected anyway. +%% +Perhaps the most widespread illusion is that if we were in power we would +behave very differently from those who now hold it -- when, in truth, in +order to get power we would have to become very much like them. (Lenin's +fatal mistake, both in theory and in practice.) +%% +Perilous to all of us are the devices of +an art deeper than we ourselves possess. + -- Gandalf the Grey +%% +Pete: Waiter, this meat is bad. +Waiter: Who told you? +Pete: A little swallow. +%% +Peter's Law of Substitution: + Look after the molehills, and the + mountains will look after themselves. + +Peter's Principle of Success: + Get up one time more than you're knocked down. + +Peter's Principle: + In every hierarchy, each employee tends + to rise to the level of his incompetence. +%% +Peter's hungry, time to eat lunch. +%% +Peterson's Admonition: + When you think you're going down for the third time -- + just remember that you may have counted wrong. +%% +Peterson's Rules: + (1) Trucks that overturn on freeways + are filled with something sticky. + (2) No cute baby in a carriage is ever a girl when called one. + (3) Things that tick are not always clocks. + (4) Suicide only works when you're bluffing. +%% +Phasers locked on target, Captain. +%% +Philadelphia is not dull -- it just seems so +because it is next to exciting Camden, New Jersy. +%% +Philogyny recapitulates erogeny; erogeny recapitulates philogyny. +%% +Phone call for chucky-pooh. +%% +Photographing a volcano is just about +the most miserable thing you can do. + -- Robert B. Goodman + [Who has clearly never tried to use a PDP-10. Ed.] +%% +Picking up the pieces of my sweet shattered dream, +I wonder how the old folks are tonight, +Her name was Ann, and I'll be damned if I recall her face, +She left me not knowing what to do. + +Carefree Highway, let me slip away on you, +Carefree Highway, you seen better days, +The morning after blues, from my head down to my shoes, +Carefree Highway, let me slip away, slip away, on you... + +Turning back the pages to the times I love best, +I wonder if she'll ever do the same, +Now the thing that I call livin' is just bein' satisfied, +With knowing I got noone left to blame. +Carefree Highway, I got to see you, my old flame... + +Searching through the fragments of my dream shattered sleep, +I wonder if the years have closed her mind, +I guess it must be wanderlust or tryin' to get free, +From the good old faithful feelin' we once knew. + -- Gordon Lightfoot, "Carefree Highway" +%% +Pickle's Law: + If Congress must do a painful thing, + the thing must be done in an odd-number year. +%% +Piddle, twiddle, and resolve, +Not one damn thing do we solve. +%% +Piece of cake! + -- G.S. Koblas +%% + Pittsburgh driver's test +10: Potholes are + a) extremely dangerous. + b) patriotic. + c) the fault of the previous administration. + d) all going to be fixed next summer. +The correct answer is b. +Potholes destroy unpatriotic, unamerican, imported cars, since the holes +are larger than the cars. If you drive a big, patriotic, American car +you have nothing to worry about. +%% + Pittsburgh driver's test +2: A traffic light at an intersection changes from yellow to red, you should + a) stop immediately. + b) proceed slowly through the intersection. + c) blow the horn. + d) floor it. +The correct answer is d. +If you said c, you were almost right, so give yourself a half point. +%% + Pittsburgh driver's test +3: When stopped at an intersection you should + a) watch the traffic light for your lane. + b) watch for pedestrians crossing the street. + c) blow the horn. + d) watch the traffic light for the intersecting street. +The correct answer is d. +You need to start as soon as the traffic light for the intersecting +street turns yellow. +Answer c is worth a half point. +%% + Pittsburgh driver's test +4: Exhaust gas is + a) beneficial. + b) not harmful. + c) toxic. + d) a punk band. +The correct answer is b. +The meddling Washington eco-freak communist bureaucrats who say otherwise +are liars. (Message to those who answered d. Go back to California where +you came from. Your kind are not welcome here.) +%% + Pittsburgh driver's test +5: Your car's horn is a vital piece of safety equipment. + How often should you test it? + a) once a year. + b) once a month. + c) once a day. + d) once an hour. +The correct answer is d. +You should test your car's horn at least once every hour, +and more often at night or in residential neighborhoods. +%% + Pittsburgh driver's test +7: The car directly in front of you has a flashing right tail light + but a steady left tail light. + a) One of the tail lights is broken. You should blow your + horn to call the problem to the driver's attention. + b) The driver is signaling a right turn. + c) The driver is signaling a left turn. + d) The driver is from out of town. +The correct answer is d. +Tail lights are used in some foreign countries to signal turns. +%% + Pittsburgh driver's test +8: Pedestrians are + a) irrelevant. + b) communists. + c) a nuisance. + d) difficult to clean off the front grille. +The correct answer is a. Pedestrians are not in cars, so they +are totally irrelevant to driving, and you should ignore them +completely. +%% + Pittsburgh driver's test +9: Roads are salted in order to + a) kill grass. + b) melt snow. + c) help the economy. + d) prevent potholes. +The correct answer is c. +Road salting employs thousands of persons directly, and millions more +indirectly, for example, salt miners and rustproofers. Most important, +salting reduces the life spans of cars, thus stimulating the car and +steel industries. +%% +Plagiarize, plagiarize, +Let no man's work evade your eyes, +Remember why the good Lord made your eyes, +Don't shade your eyes, +But plagiarize, plagiarize, plagiarize. +Only be sure to call it research. + -- Tom Lehrer +%% +Planet Claire has pink hair. +All the trees are red. +No one ever dies there. +No one has a head.... +%% +Plastic... Aluminum... These are the inheritors of the Universe! +Flesh and Blood have had their day... and that day is past! + -- Green Lantern Comics +%% +Plato, by the way, wanted to banish all poets from his proposed Utopia +because they were liars. The truth was that Plato knew philosophers +couldn't compete successfully with poets. + -- Kilgore Trout, "Venus on the Half Shell" +%% +Please don't put a strain on our friendship +by asking me to do something for you. +%% +Please don't recommend me to your friends-- +it's difficult enough to cope with you alone. +%% +Please forgive me if, in the heat of battle, +I sometimes forget which side I'm on. +%% +Please go away. +%% +Please help keep the world clean: others may wish to use it. +%% +Please ignore previous fortune. +%% +Please keep your hands off the secretary's reproducing equipment. +%% +Please, Mother! I'd rather do it myself! +%% +Please remain calm, it's no use both of +us being hysterical at the same time. +%% +Please stand for the Nation Anthem: + + O Canada + Our home and native land + True patriot love + In all thy sons' command + With glowing hearts we see thee rise + The true north strong and free + From far and wide, O Canada + We stand on guard for thee + God keep our land glorious and free + O Canada we stand on guard for thee + O Canada we stand on guard for thee + +Thank you. You may resume your seat. +%% +Please stand for the National Anthem: + + God save our Gracious Queen! + Long live our Noble Queen! + God save the Queen! + Send her victorious, + Happy and glorious, + Long to reign o'er us! + God save the Queen! + +Thank you. You may resume your seat. +%% +Please stand for the National Anthem: + + Oh, say can you see by dawn's early light + What so proudly we hailed at the twilight's last gleaming? + Whose broad stripes and bright stars through the perilous flight + O'er the ramparts we watched were so gallantly streaming? + And the rockets' red glare, the bombs bursting in air, + Gave proof through the night that our flag was still there. + Oh, say does that star-spangled banner yet wave + O'er the land of the free and the home of the brave? + +Thank you. You may resume your seat. +%% +Please take note: +%% +Please try to limit the amount of "this room doesn't have any bazingas" +until you are told that those rooms are "punched out." Once punched out, +we have a right to complain about atrocities, missing bazingas, and such. + -- N. Meyrowitz +%% +Please, won't somebody tell me what diddie-wa-diddie means? +%% +Plots are like girdles. Hidden, they hold your interest; revealed, they're +of no interest except to fetishists. Like girdles, they attempt to contain +an uncontainable experience. + -- R.S. Knapp +%% +Plus ca change, plus c'est le meme chose. +%% +Pohl's law: + Nothing is so good that somebody, somewhere, will not hate it. +%% +Political speeches are like steer horns. A point +here, a point there, and a lot of bull inbetween. + -- Alfred E. Neuman +%% +Political television commercials prove one thing: some candidates +can tell all their good points and qualifications in just 30 seconds. +%% +Politicians are the same everywhere. They promise +to build a bridge even where there is no river. + -- Nikita Khrushchev +%% +Politics are almost as exciting as war, and quite as +dangerous. In war, you can only be killed once. + -- Winston Churchill +%% +Politics is like coaching a football team. You have to be smart +enough to understand the game but not smart enough to lose interest. +%% +Politics, like religion, hold up the +torches of matrydom to the reformers of error. + -- Thomas Jefferson +%% +Pollyanna's Educational Constant: + The hyperactive child is never absent. +%% +Polymer physicists are into chains. +%% +Poorman's Rule: + When you pull a plastic garbage bag from its handy dispenser + package, you always get hold of the closed end and try to + pull it open. +%% +Populus vult decipi. +[The people like to be deceived.] +%% +Porsche; there simply is no substitute. + -- Risky Business +%% +Possessions increase to fill the space available for their storage. + -- Ryan +%% +Post proelium, praemium. +[After the battle, the reward.] +%% +Postmen never die, they just lose their zip. +%% +Poverty begins at home. +%% +Power is poison. +%% +Power is the finest token of affection. +%% +Power, like a desolating pestilence, +Pollutes whate'er it touches... + -- Percy Bysshe Shelley +%% +Power tends to corrupt, absolute power corrupts absolutely. + -- Lord Acton +%% +Practical people would be more practical if +they would take a little more time for dreaming. + -- J.P. McEvoy +%% +Practically perfect people never permit +sentiment to muddle their thinking. + -- Mary Poppins +%% +Practice is the best of all instructors. + -- Publilius +%% +Practice yourself what you preach. + -- Titus Maccius Plautus +%% +Praise the sea; on shore remain. + -- John Florio +%% +Predestination was doomed from the start. +%% +Prejudice: + A vagrant opinion without visible means of support. + -- Ambrose Bierce +%% +Premature optimization is the root of all evil. + -- D.E. Knuth +%% +Preserve Wildlife! Throw a party today! +%% +Preserve the old, but know the new. +%% +Preserve wildlife -- pickle a squirrel today! +%% +President Reagan has noted that there are too many economic +pundits and forecasters and has decided on an excess prophets tax. +%% +President Thieu says he'll quit if he doesn't get more than 50% +of the vote. In a democracy, that's not called quitting. + -- The Washington Post +%% +Pretend to spank me -- I'm a pseudo-masochist! +%% +Preudhomme's Law of Window Cleaning: + It's on the other side. +%% +Price's Advice: + It's all a game -- play it to have fun. +%% +[Prime Minister Joseph] Chamberlain loves +the working man, he loves to see him work. + -- Winston Churchill +%% +[Prime Minister MacDonald] has the gift of compressing the +largest amount of words into the smallest amount of thought. + -- Winston Churchill +%% +Prince Hamlet thought Uncle a traitor +For having it off with his Mater; + Revenge Dad or not? + That's the gist of the plot, +And he did -- nine soliloquies later. + -- Stanley J. Sharpless +%% +Princeton's taste is sweet like a strawberry tart. Harvard's is a subtle +taste, like whiskey, coffee, or tobacco. It may even be a bad habit, for +all I know. + -- Prof. J.H. Finley '25 +%% +Prisons are built with stones of Law, brothels with bricks of Religion. + -- Blake +%% +Prizes are for children. + -- Charles Ives, + upon being given, but refusing, the Pulitzer prize +%% +Pro is to con as progress is to Congress. +%% +Probable-Possible, my black hen, +She lays eggs in the Relative When. +She doesn't lay eggs in the Positive Now +Because she's unable to postulate How. + -- Frederick Winsor +%% +Profanity is the one language all programmers know best. +%% +Professor Gorden Newell threw another shutout in last week's Chem Eng. +130 midterm. Once again a student did not receive a single point on +his exam. Newell has now tossed 5 shutouts this quarter. Newell's +earned exam average has now dropped to a phenomenal 30%. +%% +Programmers do it bit by bit. +%% +Programmers do it until it goes down. +%% +Programmers get overlaid. +%% +Programmers used to batch environments may find it hard to live +without giant listings; we would find it hard to use them. + -- D.M. Ritchie +%% +Programming Department: + Mistakes made while you wait. +%% +Programming is an unnatural act. +%% +Progress is impossible without change, and those who +cannot change their minds cannot change anything. + -- G.B. Shaw +%% +Progress means replacing a theory that +is wrong with one more subtly wrong. +%% +Progress might have been all right once, but it's gone on too long. + -- Ogden Nash +%% +Promise her anything, but give her Exxon unleaded. +%% +Promising costs nothing, it's the delivering that kills you. +%% +Promptness is its own reward, if one lives by the clock instead of the sword. +%% +Proof techniques #1: Proof by Induction. + +This technique is used on equations with 'n' in them. Induction +techniques are very popular, even the military use them. + +SAMPLE: Proof of induction without proof of induction. + + We know it's true for n equal to 1. Now assume that it's true +for every natural number less than n. N is arbitrary, so we can take n +as large as we want. If n is sufficiently large, the case of n+1 is +trivially equivalent, so the only important n are n less than n. We can +take n = n (from above), so it's true for n+1 becuase it's just about n. + QED. (QED translates from the Latin as "So what?") +%% +Proof techniques #2: Proof by Oddity. + SAMPLE: To prove that horses have an infinite number of legs. +[1] Horses have an even number of legs. +[2] They have two legs in back and fore legs in front. +[3] This makes a total of six legs, + which certainly is an odd number of legs for a horse. +[4] But the only number that is both odd and even is infinity. +[5] Therefore, horses must have an infinite number of legs. + +Topics is be covered in future issues include proof by: + intimidation, + gesticulation (handwaving), + "try it; it works", + constipation (I was just sitting there and...), + blatant assertion, + changing all the 2's to n's, + mutual consent, + lack of a counterexample, and, + "it stands to reason". +%% +Proper treatment will cure a cold in seven days, +but left to itself, a cold will hang on for a week. + -- Darrell Huff +%% +Prosperity makes friends, adversity tries them. + -- Publilius Syrus +%% +Prototype designs always work. + -- Don Vonada +%% +Providence New Jersey is one of the few cities +where Velveeta cheese appears on the gourmet shelf. +%% +Prunes give you a run for your money. +%% +Pryor's Observation: + How long you live has nothing to do + with how long you are going to be dead. +%% +Psychiatrists say that one out of four people are mentally ill. +Check three friends. If they're okay, you're it. +%% +Psychiatry is quite similar to prostitution, only less honest. They +both promise to make people feel better, but the prostitute doesn't +make pretensions that the feelings will last once the client walks +out the door. +%% +Public use of any portable music system is a +virtually guaranteed indicator of sociopathic tendencies. + -- Zoso +%% +Publishing a volume of verse is like dropping +a rose petal down the Grand Canyon and waiting for the echo. +%% +Pudder's Law: + Anything that begins well will end badly. + (Note: The converse of Pudder's law is not true.) +%% +Push where it gives and scratch where it itches. +%% +Put all your eggs in one basket and -- WATCH THAT BASKET. + -- Mark Twain +%% +Put another password in, +Bomb it out, then try again. +Try to get past logging in, +We're hacking, hacking, hacking. + +Try his first wife's maiden name, +This is more than just a game. +It's real fun, but just the same, +It's hacking, hacking, hacking. +%% +Put cats in the coffee and mice in the tea! +%% +Put not your trust in money, but put your money in trust. +%% +Put your Nose to the Grindstone! + -- Amalgamated Plastic Surgeons and Toolmakers, Ltd. +%% +Put your best foot forward. +Or just call in and say you're sick. +%% +Put your brain in gear before starting your mouth in motion. +%% +Put your trust in those who are worthy. +%% +Putt's Law: + Technology is dominated by two types of people: + Those who understand what they do not manage. + Those who manage what they do not understand. +%% +Q: Are we not men? +A: We are Vaxen. +%% +Q: Do you know what the death rate around here is? +A: One per person. +%% +QED. +%% +Q: Have you heard about the man who didn't pay for his exorcism? +A: He got re-possessed! +%% +Q: How can we get the Beatles to reunite for one more concert? +A: With three more bullets. +%% +Q: How can you tell if an elephant is having an affair with + your wife? +A: You have to wait 22 months. +%% +Q: How can you tell if an elephant is sitting on your back + in a hurricane? +A: You can hear his ears flapping in the wind. +%% +Q: How can you tell when a Burroughs salesman is lying? +A: When his lips move. +%% +Q: How did the elephant get to the top of the oak tree? +A: He sat on a acorn and waited for spring. + +Q: But how did he get back down? +A: He crawled out on a leaf and waited for autumn. +%% +Q: How do you catch a unique rabbit? +A: Unique up on it! + +Q: How do you catch a tame rabbit? +A: The tame way! +%% +Q: How do you keep a moron in suspense? +%% +Q: How do you make an elephant float? +A: You get two scoops of elephant and some rootbeer... +%% +Q: How do you stop an elephant from charging? +A: Take away his credit cards. +%% +Q: How does a hacker fix a function which + doesn't work for all of the elements in its domain? +A: He changes the domain. +%% +Q: How many Californians does it take to screw in a lightbulb? +A: Five. One to screw in the lightbulb and four to share the + experience. (Actually, Californians don't screw in + lightbulbs, they screw in hot tubs.) + +Q: How many Oregonians does it take to screw in a light bulb? +A: Three. One to screw in the lightbulb and two to fend off all + those Californians trying to share the experience. +%% +Q: How many DEC repairman does it take to fix a flat? +A: Five; four to hold the car up and one to swap tires. + +Q: How long does it take? +A: It's indeterminate. + It will depend upon how many flats they've brought with them. + +Q: What happens if you've got TWO flats? +A: They replace your generator. +%% +Q: How many IBM 370's does it take to execute a job? +A: Four, three to hold it down, and one to rip its head off. +%% +Q: How many IBM CPU's does it take to do a logical right shift? +A: 33. 1 to hold the bits and 32 to push the register. +%% +Q: How many WASP's does it take to change a lightbulb? +A: One. +%% +Q: How many college football players does it take to screw in a lightbulb? +A: Only one, but he gets three credits for it. +%% +Q: How many hardware engineers does it take to change a lightbulb? +A: None. We'll fix it in software. + +Q: How many system programmers does it take to change a light bulb? +A: None. The application can work around it. + +Q: How many software engineers does it take to change a lightbulb? +A: None. We'll document it in the manual. + +Q: How many tech writers does it take to change a lightbulb? +A: None. The user can figure it out. +%% +Q: How many journalists does it take to screw in a lightbulb? +A: Three. One to report it as an inspired government program to bring + light to the people, one to report it as a diabolical government plot + to deprive the poor of darkness, and one to win a Pulitzer prize for + reporting that Electric Company hired a lightbulb-assassin to break + the bulb in the first place. +%% +Q: How many people from New Jersey does it take to change a light + bulb? +A: Three. One to do it, one to watch, and the third to shoot the + witness. +%% +Q: How many psychiatrists does it take to change a light bulb? +A: Only one, but it takes a long time, and the light bulb has + to really want to change. +%% +Q: How many surrealists does it take to change a light bulb? +A: Two, one to hold the giraffe, and the other to fill the + bathtub with brightly colored machine tools. +%% +Q: How much does it cost to ride the Unibus? +A: 2 bits. +%% +Q: How was Thomas J. Watson buried? +A: 9 edge down. +%% +Q: Know what the difference between your latest project + and putting wings on an elephant is? +A: Who knows? The elephant *might* fly, heh, heh... +%% +QUALITY CONTROL: + The process of testing one out of every 1,000 units coming off a + production line to make sure that at least one out of 100 works. +%% +QUARK: + The sound made by a well bred duck. +%% +QWERT (kwirt) n. [MW < OW qwertyuiop, a thirteenth] 1. a unit of weight +equal to 13 poiuyt avoirdupois (or 1.69 kiloliks), commonly used in +structural engineering 2. [Colloq.] one thirteenth the load that a fully +grown sligo can carry. 3. [Anat.] a painful irritation of the dermis +in the region of the anus 4. [Slang] person who excites in others the +symptoms of a qwert. + -- Webster's Middle World Dictionary, 4th ed. +%% +Q: What did Tarzan say when he saw the elephants coming over the hill? +A: "The elephants are coming over the hill." + +Q: What did he say when saw them coming over the hill wearing + sunglasses? +A: Nothing, for he didn't recognize them. +%% +Q: What do WASP's do instead of making love? +A: Rule the country. +%% +Q: What do little WASPs want to be when they grow up? +A: The very best person they can possibly be. +%% +Q: What do they call the alphabet in Arkansas? +A: The impossible dream. +%% +Q: What do you call a boomerang that doesn't come back? +A: A stick. +%% +Q: What do you call a half-dozen Indians with Asian flu? +A: Six sick Sikhs (sic). +%% +Q: What do you call a million cats at the bottom of Lake Michigan? +A: A good start. +%% +Q: What do you call the WASP who doesn't work for + his father, isn't a lawyer, and believes in social causes? +A: A failure. +%% +Q: What do you call the money you pay to the government when + you ride into the country on the back of an elephant? +A: A howdah duty. +%% +Q: What do you call the scratches + that you get when a female sheep bites you? +A: Ewe nicks. +%% +Q: What do you get when you stuff a flaming stick down a rabbit-hole? +A: Hot cross bunnies! +%% +Q: What does a WASP Mom make for dinner? +A: A crisp salad, a hearty soup, a lovely entree, followed by + a delicious dessert. +%% +Q: What does it say on the bottom of Coke cans in North Dakota? +A: Open other end. +%% +Q: What goes + Click. "Did I get it?" + Click. "Did I get it?" + Click. "Did I get it?" + Click. "Did I get it?" +A: Stevie Wonder doing the Rubik's Cube. +%% +Q: What is green and lives in the ocean? +A: Moby Pickle. +%% +Q: What is it that a cow has four of and a woman has two of? +A: Feet. +%% +Q: What is orange and goes "click, click?" +A: A ball point carrot. +%% +Q: What is printed on the bottom of beer bottles in Minnesota? +A: Open other end. +%% +Q: What is purple and commutes? +A: A boolean grape. +%% +Q: What is purple and commutes? +A: An Abelian grape. +%% +Q: What is purple and concord the world? +A: Alexander the Grape. +%% +Q: What is the difference between Texas and yogurt? +A: Yogurt has culture. +%% +Q: What is the difference between a duck? +A: One leg is both the same. +%% +Q: What is the last thing a Kansas stripper takes off? +A: Her bowling shoes. +%% +Q: What lies on the bottom of the ocean and twitches? +A: A nervous wreck. +%% +Q: What looks like a cat, flies like a bat, + brays like a donkey, and plays like a monkey? +A: Nothing. +%% +Q: What's bruised, bleeding, and lies in a ditch? +A: Somebody who tells Aggie jokes. +%% +Q. What's the capital of Canada? +A. American. +%% +Q: What's the difference between Bell Labs and the + Boy Scouts of America? +A: The Boy Scouts have adult supervision. +%% +Q: What's the difference between a duck? +A: You can't get down off an elephant. +%% +Q: What's the difference between an Irish wedding and an Irish wake? +A: One more drunk. +%% +Q: What's tiny and yellow and very, very, dangerous? +A: A canary with the super-user password. +%% +Q: Why did God create goyim? +A: Somebody had to buy retail. +%% +Q: Why did the WASP cross the road? +A: To get to the middle. +%% +Q: Why did the chicken cross the road? +A: He was giving it last rites. +%% +Q: Why did the germ cross the microscope? +A: To get to the other slide. +%% +Q: Why did the programmer call his mother long distance? +A: Because that was her name. +%% +Q: Why do ducks have big flat feet? +A: To stamp out forest fires. + +Q: Why do elephants have big flat feet? +A: To stamp out flaming ducks. +%% +Q: Why do firemen wear red suspenders? +A: To conform with departmental regulations concerning uniform dress. +%% +Q: Why do mountain climbers rope themselves together? +A: To prevent the sensible ones from going home. +%% +Q: Why do the police always travel in threes? +A: One does the reading, one the writing, and the other + keeps an eye on the two intellectuals. +%% +Quack! + Quack!! Quack!! +%% +Quantity is no substitute for quality, but its the only one we've got. +%% +Quark! Quark! Beware the quantum duck! +%% +Question: Is it better to abide by the rules until +they're changed or help speed the change by breaking them? +%% +Question authority. +%% +Question: + Man Invented Alcohol, + God Invented Grass. + Whom do you trust? +%% +Questionable day. +Ask somebody something. +%% +Questions are never indiscreet, answers sometimes are. + -- Oscar Wilde +%% +Quick!! Act as if nothing has happened! +%% +Quigley's Law: + Whoever has any authority over you, + no matter how small, will attempt to use it. +%% +Quite frankly, I don't like you humans. +After what you all have done, I find being "inhuman" a compliment. +%% +Qvid me anxivs svm? +%% +RADIO SHACK LEVEL II BASIC +READY +>_ +%% +RAM wasn't built in a day. +%% +Random, n: + as in number, predictable. + as in memory access, unpredictable. +%% +Reappraisal, n: + An abrupt change of mind after being found out. +%% +Reception area, n: + The purgatory where office visitors are condemned to spend + innumerable hours reading dog-eared back issues of trade + magazines like Modern Plastics, Chain Saw Age, and Chicken World, + while the receptionist blithely reads her own trade magazine -- + Cosmopolitan. +%% +Reliable source, n: + The guy you just met. +%% +Reputation, adj: + What others are not thinking about you. +%% +Research, n: + Consider Columbus: + He didn't know where he was going. + When he got there he didn't know where he was. + When he got back he didn't know where he had been. + And he did it all on someone else's money. +%% +Revolution, n: + A form of government abroad. +%% +Robot, n: + Someone who's been made by a scientist. +%% +Robot, n: + University administrator. +%% +Robustness, adj: + Never having to say you're sorry. +%% +ROMEO: Courage, man; the hurt cannot be much. +MERCUTIO: No, 'tis not so deep as a well, nor so wide + as a church-door; but 'tis enough, 'twill serve. +%% +RUGBY: + Elegant violence. +%% +RUGGED: + Too heavy to lift. +%% +Radicalism: + The conservatism of tomorrow injected into the affairs of today. + -- A. Bierce +%% +Radioactive cats have 18 half-lives. +%% +Raffiniert ist der Herrgott aber boshaft ist er nicht. + -- Albert Einstein +%% +Rainy days and Mondays always get me down. +%% +Raising pet electric eels is gaining a lot of current popularity. +%% +Rascal, am I? Take THAT! + -- Errol Flynn +%% +Rattling around the back of my head is a disturbing image of something I +saw at the airport... Now I'm remembering, those giant piles of computer +magazines right next to "People" and "Time" in the airport store. Does it +bother anyone else that half the world is being told all of our hard-won +secrets of computer technology? Remember how all the lawyers cried foul +when "How to Avoid Probate" was published? Are they taking no-fault +insurance lying down? No way! But at the current rate it won't be long +before there are stacks of the "Transactions on Information Theory" at the +A&P checkout counters. Who's going to be impressed with us electrical +engineers then? Are we, as the saying goes, giving away the store? + -- Robert W. Lucky, IEEE president +%% +Razors pain you; +Rivers are damp; +Acids stain you; +And drugs cause cramp. +Guns aren't lawful; +Nooses give; +Gas smells awful; +You might as well live. + -- Dorothy Parker, "Resume", 1926 +%% +Re: Graphics: + A picture is worth 10K words -- but only those to describe + the picture. Hardly any sets of 10K words can be adequately + described with pictures. +%% +Reach into the thoughts of friends, +And find they do not know your name. +Squeeze the teddy bear too tight, +And watch the feathers burst the seams. +Touch the stained glass with your cheek, +And feel its chill upon your blood. +Hold a candle to the night, +And see the darkness bend the flame. +Tear the mask of peace from God, +And hear the roar of souls in hell. +Pluck a rose in name of love, +And watch the petals curl and wilt. +Lean upon the western wind, +And know you are alone. + -- Dru Mims +%% +Reading is thinking with someone else's head instead of one's own. +%% +Reading is to the mind what exercise is to the body. +%% +Reagan can't act either. +%% +Real Programmers don't play tennis, or any other sport that requires +you to change clothes. Mountain climbing is OK, and real programmers +wear their climbing boots to work in case a mountain should suddenly +spring up in the middle of the machine room. +%% +Real programmers don't document; if it was +hard to write, it should be hard to understand. +%% +Real programs don't eat cache. +%% +Real wealth can only increase. + -- R. Buckminster Fuller +%% +Reality -- what a concept! + -- Robin Williams +%% +Reality always seems harsher in the early morning. +%% +Reality does not exist - yet. +%% +Reality is an obstacle to hallucination. +%% +Reality is for people who can't deal with drugs. + -- Lily Tomlin +%% +Reality is just a crutch for people who can't handle science fiction. +%% +Really?? What a coincidence, I'm shallow too!! +%% +Rebellion lay in his way, and he found it. + -- William Shakespeare, "Henry IV" +%% +Recent investments will yield a slight profit. +%% +Recent research has tended to show that the Abominable No-Man +is being replaced by the Prohibitive Procrastinator. + -- C.N. Parkinson +%% +Recession is when your neighbor loses his job. Depression is when you +lose your job. These economic downturns are very difficult to predict, +but sophisticated econometric modeling houses like Data Resources and +Chase Econometrics have successfully predicted 14 of the last 3 recessions. +%% +Recieving a million dollars tax free will make you feel +better than being flat broke and having a stomach ache. + -- Dolph Sharp +%% +Reclaimer, spare that tree! +Take not a single bit! +It used to point to me, +Now I'm protecting it. +It was the reader's CONS +That made it, paired by dot; +Now, GC, for the nonce, +Thou shalt reclaim it not. +%% +Recursion is the root of computation +since it trades description for time. +%% +Recursion: n. See Recursion. + -- Random Shack Data Processing Dictionary +%% +Regardless of whether a mission expands or contracts, +administrative overhead continues to grow at a steady rate. +%% +Regnant populi. +%% + "Reintegration complete," ZORAC advised. "We're back in the +universe again..." An unusually long pause followed, "...but I don't +know which part. We seem to have changed our position in space." A +spherical display in the middle of the floor illuminated to show the +starfield surrounding the ship. + "Several large, artificial constructions are approaching us," +ZORAC announced after a short pause. "The designs are not familiar, but +they are obviously the products of intelligence. Implications: we have +been intercepted deliberately by a means unknown, for a purpose unknown, +and transferred to a place unknown by a form of intelligence unknown. +Apart from the unknowns, everything is obvious." + -- James P. Hogan, "Giants Star" +%% +Reisner's Rule of Conceptual Inertia: + If you think big enough, you'll never have to do it. +%% +Religions revolve madly around sexual questions. +%% +Remember -- only 10% of anything can be in the top 10%. +%% +Remember Darwin; building a better +mousetrap merely results in smarter mice. +%% +Remember, UNIX spelled backwards is XINU. + -- Mt. +%% +Remember, even if you win the rat race -- you're still a rat. +%% +Remember that there is an outside world to see and enjoy. + -- Hans Liepmann +%% +Remember that whatever misfortune may be your lot, +it could only be worse in Cleveland. +%% +Remember the good old days, when CPU was singular? +%% +Remember the... the... uhh..... +%% +Remember to say hello to your bank teller. +%% +Remember: use logout to logout. +%% +Remembering is for those who have forgotten. + -- Chinese proverb +%% +Removing the straw that broke the camel's back +does not necessarily allow the camel to walk again. +%% +Renning's Maxim: + Man is the highest animal. Man does the classifying. +%% +Reply hazy, ask again later. +%% +Reporter (to Mahatma Gandhi): + Mr. Gandhi, what do you think of Western Civilization? +Gandhi: I think it would be a good idea. +%% +Reporter: + A writer who guesses his way to the truth + and dispels it with a tempest of words. + -- Ambrose Bierce +%% + Reporters like Bill Greider from the Washington Post and Him +Naughton of the New York Times, for instance, had to file long, detailed, +and relatively complex stories every day -- while my own deadline fell +every two weeks -- but neither of them ever seemed in a hurry about +getting their work done, and from time to time they would try to console +me about the terrible pressure I always seemed to be laboring under. + Any $100-an-hour psychiatrist could probably explain this problem +to me, in thirteen or fourteen sessions, but I don't have time for that. +No doubt it has something to do with a deep-seated personality defect, or +maybe a kink in whatever blood vessel leads into the pineal gland... On +the other hand, it might be something as simple & basically perverse as +whatever instinct it is that causes a jackrabbit to wait until the last +possible second to dart across the road in front of a speeding car. + -- H.S. Thompson, "Fear and Loathing: On the Campaign Trail" +%% +Research is the best place to be: you work your buns off, and if it works +you're a hero; if it doesn't, well -- nobody else has done it yet either, +so you're still a valiant nerd. +%% +Research is to see what everybody else has seen, +and think what nobody else has thought. +%% +Research is what I'm doing when I don't know what I'm doing. + -- Wernher von Braun +%% +Resisting temptation is easier when you +think you'll probably get another chance later on. +%% +Rest assured that your dog is finally getting enough cheese. + -- Deteriorata +%% +Rev. Jim: What does an amber light mean? +Bobby: Slow down. +Rev. Jim: What... does... an... amber... light... mean? +Bobby: Slow down. +Rev. Jim: What.... does.... an.... amber.... light.... +%% +Revenge is a form of nostalgia. +%% +Revenge is a meal best served cold. +%% +Review Questions + +1: If Nerd on the planet Nutley starts out in his spaceship at 20 KPH, + and his speed doubles every 3.2 seconds, how long will it be before + he exceeds the speed of light? How long will it be before the + Galactic Patrol picks up the pieces of his spaceship? + +2: If Roger Rowdy wrecks his car every week, and each week he breaks + twice as many bones as before, how long will it be before he breaks + every bone in his body? How long will it be before they cut off + his insurance? Where does he get a new car every week? + +3: If Johnson drinks one beer the first hour (slow start), four beers + the next hour, nine beers the next, etc., and stacks the cans in + a pyramid, how soon will Johnson's pyramid be larger than King + Tut's? When will it fall on him? Will he notice? +%% +Rhode's Law: + When any principle, law, tenet, probability, happening, circumstance, + or result can in no way be directly, indirectly, empirically, or + circuitously proven, derived, implied, inferred, induced, deducted, + estimated, or scientifically guessed, it will always for the purpose + of convenience, expediency, political advantage, material gain, or + personal comfort, or any combination of the above, or none of the + above, be unilaterally and unequivocally assumed, proclaimed, and + adhered to as absolute truth to be undeniably, universally, immutably, + and infinitely so, until such time as it becomes advantageous to + assume otherwise, maybe. +%% + "Richard, in being so fierce toward my vampire, you were doing +what you wanted to do, even though you thought it was going to hurt +somebody else. He even told you he'd be hurt if..." + "He was going to suck my blood!" + "Which is what we do to anyone when we tell them we'll be hurt +if they don't live our way." +... + "The thing that puzzles you," he said, "is an accepted saying that +happens to be impossible. The phrase is hurt somebody else. We choose, +ourselves, to be hurt or not to be hurt, no matter what. Us who decides. +Nobody else. My vampire told you he'd be hurt if you didn't let him? That's +his decision to be hurt, that's his choice. What you do about it is your +decision, your choice: give him blood; ignore him; tie him up; drive a stake +through his heart. If he doesn't want the holly stake, he's free to resist, +in whatever way he wants. It goes on and on, choices, choices." + "When you look at it that way..." + "Listen," he said, "it's important. We are all. Free. To do. +Whatever. We want. To do." + -- Richard Bach, "Illusions" +%% +Riches cover a multitude of woes. + -- Menander +%% +Rick: "How can you close me up? On what grounds?" +Renault: "I'm shocked! Shocked! To find that gambling is + going on here." +Croupier (handing money to Renault): + "Your winnings, sir." +Renault: "Oh. Thank you very much." + -- Casablanca +%% +Riffle West Virginia is so small that the +Boy Scout had to double as the town drunk. +%% +"Rights" is a fictional abstraction. No one has "Rights", neither +machines nor flesh-and-blood. Persons... have opportunities, not +rights, which they use or do not use. + -- Lazarus Long +%% +Ring around the collar. +%% + Risch's decision procedure for integration, not surprisingly, +uses a recursion on the number and type of the extensions from the +rational functions needed to represent the integrand. Although the +algorithm follows and critically depends upon the appropriate structure +of the input, as in the case of multivariate factorization, we cannot +claim that the algorithm is a natural one. In fact, the creator of +differential algebra, Ritt, committed suicide in the early 1950's, +largely, it is claimed, because few paid attention to his work. Probably +he would have received more attention had he obtained the algorithm as +well. + -- Joel Moses, "Algorithms and Complexity", ed. J.F. Traub +%% +Ritchie's Rule: + (1) Everything has some value -- if you use the right currency. + (2) Paint splashes last longer than the paint job. + (3) Search and ye shall find -- but make sure it was lost. +%% +Rocky's Lemma of Innovation Prevention + Unless the results are known in advance, + funding agencies will reject the proposal. +%% +Rome was not built in one day. + -- John Heywood +%% +Rome wasn't burnt in a day. +%% +Romeo was restless, he was ready to kill, +He jumped out the window 'cause he couldn't sit still, +Juliet was waiting with a safety net, +Said "don't bury me 'cause I ain't dead yet". + -- Elvis Costello +%% +Roses are red; + Violets are blue. +I'm schizophrenic, + And so am I. +%% +Rotten wood cannot be carved. + -- Confucius, "Analects", Book 5, Ch. 9 +%% +Round Numbers are always false. + -- Samuel Johnson +%% +Row, row, row your bits, gently down the stream... +%% +Rubber bands have snappy endings! +%% +Rudd's Discovery: + You know that any senator or congressman could go home and make + $300,000 to $400,000, but they don't. Why? Because they can + stay in Washington and make it there. +%% +Rudin's Law: + If there is a wrong way to do something, most people will + do it every time. + +Rudin's Second Law: + In a crisis that forces a choice to be made among alternative + courses of action, people tend to choose the worst possible + course. +%% +Rugby players eat their dead. +%% +Rule of Creative Research: + 1) Never draw what you can copy. + 2) Never copy what you can trace. + 3) Never trace what you can cut out and paste down. +%% +Rule of Defactualization: + Information deteriorates upward through bureaucracies. +%% +Rule of Feline Frustration: + When your cat has fallen asleep on your lap and looks utterly + content and adorable, you will suddenly have to go to the + bathroom. +%% +Rule of Life #1 -- Never get separated from your luggage. +%% +Rule of the Great: + When people you greatly admire appear to be thinking deep + thoughts, they probably are thinking about lunch. +%% +Rules for Good Grammar #4. + 1: Don't use no double negatives. + 2: Make each pronoun agree with their antecedents. + 3: Join clauses good, like a conjunction should. + 4: About them sentence fragments. + 5: When dangling, watch your participles. + 6: Verbs has got to agree with their subjects. + 7: Just between you and i, case is important. + 8: Don't write run-on sentences when they are hard to read. + 9: Don't use commas, which aren't necessary. +10: Try to not ever split infinitives. +11: It is important to use your apostrophe's correctly. +12: Proofread your writing to see if you any words out. +13: Correct speling is essential. +14: A preposition is something you never end a sentence with. +15: While a transcendant vocabulary is laudable, one must be eternally + careful so that the calculated objective of communication does not + become ensconsed in obscurity. In other words, eschew obfuscation. +%% +Rules for Writers: + Avoid run-on sentences they are hard to read. Don't use no double +negatives. Use the semicolon properly, always use it where it is appropriate; +and never where it isn't. Reserve the apostrophe for it's proper use and +omit it when its not needed. No sentence fragments. Avoid commas, that are +unnecessary. Eschew dialect, irregardless. And don't start a sentence with +a conjunction. Hyphenate between sy-llables and avoid un-necessary hyphens. +Write all adverbial forms correct. Don't use contractions in formal writing. +Writing carefully, dangling participles must be avoided. It is incumbent on +us to avoid archaisms. Steer clear of incorrect forms of verbs that have +snuck in the language. Never, ever use repetitive redundancies. If I've +told you once, I've told you a thousand times, resist hyperbole. Also, +avoid awkward or affected alliteration. Don't string too many prepositional +phrases together unless you are walking through the valley of the shadow of +death. "Avoid overuse of 'quotation "marks."'" +%% +Rules for driving in New York: + 1) Anything done while honking your horn is legal. + 2) You may park anywhere if you turn your four-way flashers on. + 3) A red light means the next six cars may go through the + intersection. +%% +Ruling a big country is like cooking a small fish. + -- Lao Tsu +%% +Russia has abolished God, but so far God has been more tolerant. + -- John Cameron Swayze +%% +Ryan's Law: + Make three correct guesses consecutively + and you will establish yourself as an expert. +%% +SADISM: + A sadist refusing to whip a masochist. +%% +SADO-NECRO-BESTIALITY: + Beating a dead horse. +%% + SAFETY +I can live without +Someone I love +But not without +Someone I need. +%% +SAGITTARIUS (Nov 22 - Dec 21) + You are optimistic and enthusiastic. You have a reckless + tendency to rely on luck since you lack talent. The majority of + Sagitarians are drunks or dope fiends or both. People laugh at + you a great deal. +%% +SAGITTARIUS (Nov.22 - Dec.21) + Your efforts to help a little old lady cross a street will + backfire when you learn that she was waiting for a bus. Subdue + impulse you have to push her out into traffic. +%% +SAN DIEGO: + Four million people, where you can't get a + good cheeseburger, no matter how hard you try. +%% +SAN FRANCISCO: + Marcel Proust editing an issue of Penthouse. +%% +SCCS, the source motel! Programs check in and never check out! + -- Ken Thompson +%% +SCENARIO: + An imagined sequence of events that provides the context in + which a business decision is made. Scenarios always come in + sets of three: best case, worst case, and just in case. +%% +SCORPIO (Oct 23 - Nov 21) + You are shrewd in business and cannot be trusted. You will achieve + the pinnacle of success because of your total lack of ethics. Most + Scorpio people are murdered. +%% +SCORPIO (Oct.24 - Nov.21) + You will receive word today that you are eligible to win a million + dollars in prizes. It will be from a magazine trying to get you to + subscribe, and you're just dumb enough to think you've got a chance + to win. You never learn. +%% +SEMINARS: + From 'semi' and 'arse', hence, any half-assed discussion. +%% +SEMPER UBI SUB UBI!!!! +%% +SENILITY: + The state of mind of elderly persons + with whom one happens to disagree. +%% +SERENDIPITY: + The process by which human knowledge is advanced. +%% +share, n: + To give in, endure humiliation. +%% +SHIFT TO THE LEFT! +SHIFT TO THE RIGHT! +POP UP, PUSH DOWN, +BYTE, BYTE, BYTE! +%% +SMOKING IS NOW ALLOWED !!! + Anyone wishing to smoke, however, must file, in triplicate, the + U.S. government Environmental Impact Narrative Statement (EINS), + describing in detail the type of combustion proposed, impact on + the environment, and anticipated opposition. Statements must be + filed 30 days in advance. +%% +SNAPPY REPARTEE: + What you'd say if you had another chance. +%% +SOCIALISM: + You have two cows. Give one to your neighbour. +COMMUNISM: + You have two cows. + Give both to the government. The government gives you milk. +CAPITALISM: + You sell one cow and buy a bull. +FACISM: + You have two cows. Give milk to the government. + The government sells it. +NAZISM: + The government shoots you and takes the cows. +NEW DEALISM: + The government shoots one cow, + milks the other, and pours the milk down the sink. +ANARCHISM: + Keep the cows. Steal another one. Shoot the government. +CONSERVATISM: + Freeze the milk. Embalm the cows. +%% +SOFTWARE: + Formal evening attire for female computer analysts. +%% +SPINSTER: + A bachelor's wife. +%% +SPOUSE: + Someone who'll stand by you through all the + trouble you wouldn't have had if you'd stayed single. +%% +STANDARDS: + The principles we use to reject other people's code. +%% +STATISTICS: + A system for expressing your political + prejudices in convincing scientific guise. +%% +STRAPLESS EVENING GOWN: + Bust truster. +%% +STRATEGY: + A comprehensive plan of inaction. +%% +STUPID: + Losing $25 on the tackle and $25 on the instant replay. +%% +SUNSET: + Pronounced atmospheric scattering of shorter wavelengths, + resulting in selective transmission below 650 nanometers with + progressively reducing solar elevation. +%% +SWEATER: + A garment worn by a child when their mother feels chilly. +%% +SYSTEM-INDEPENDENT: + Works equally poorly on all systems. +%% +Sacher's Observation: + Some people grow with responsibility -- others merely swell. +%% +Safety Third. +%% + Safety Tips for the Post-Nuclear Existence +1. Never use an elevator in a building that has been hit by a + nuclear bomb, use the stairs. +2. When you're flying through the air, remember to roll + when you hit the ground. +3. If you're on fire, avoid gasoline and other flammable materials. +4. Don't attempt communication with dead people; it will only lead + to psychological problems. +5. Food will be scarce, you will have to scavenge. Learn to recognize + foods that will be available after the bomb: mashed potatoes, + shredded wheat, tossed salad, ground beef, etc. +6. Put your hand over your mouth when you sneeze, internal organs + will be scarce in the post-nuclear age. +7. Try to be neat, fall only in designated piles. +8. Drive carefully in "Heavy Fallout" areas, people could be + staggering illegally. +9. Nutritionally, hundred dollar bills are equal to one's, but more + sanitary due to limited circulation. +10. Accumulate mannequins now, spare parts will be in short + supply on D-Day. +%% +Safety Tips for the Post-Nuclear Existence + Tip #1: How to tell when you are dead. + + 1. Little things start bothering you: little things like worms, + bugs, ants. + 2. Something is missing in your personal relationships. + 3. Your dog becomes overly affectionate. + 4. You have a hard time getting a waiter. + 5. Exotic birds flock around you. + 6. People ignore you at parties. + 7. You have a hard time getting up in the morning. + 8. You no longer get off on cocaine. +%% +Sailing is fun, but scrubbing the decks is aardvark. + -- Heard on Noahs' ark +%% +Sailors in ships, sail on! +Even while we died, others rode out the storm. +%% + Sam went to his psychiatrist complaining of a hatred for elephants. +"I can't stand elephants," he explained. "I lie awake nights despising +them. The thought of an elephant fills me with loathing." + "Sam," said the psychiatrist, "there's only one thing for you to do. +Go to Africa, organize a safari, find an elephant in the jungle and shoot it. +That way you'll get it out of your system." + Sam immediately made arrangements for a safari hunt in Africa, +inviting his best friend to join him. They arrived in Nairobi and lost no +time getting out on the jungle trails. After they had been hunting for +several days, Sam's best friend grabbed him by the arm one morning and +yelled at him: + "Sam, Sam, Sam! Over there behind that tree there's and elephant! +Sam -- Get your gun -- no, no, not THAT gun -- the rifle with the longer +barrel! Now aim it! QUICK! SAM! QUICK! No! Not that way -- this way! +Be sure you don't jerk the trigger! Wait SAM! Don't let him see you! Aim +at his head!" + Sam whirled around, took aim, and killed his friend. He was put in +prison and his psychiatrist flew to Africa to visit him. "I sent you over +here to kill and elephant and instead you shoot your best friend," the +psychiatrist said. "Why?" + "Well," Sam replied, "there's only one thing in the world that I +hate more than elephants and that is a loudmouth know-it-all!" +%% +San Francisco isn't what it used to be, and it never was. +%% +Sank heaven for leetle curls. +%% +Santa Claus is watching! +%% +Santa Claus wears a red suit +He's a Communist. + +He has long hair and a beard +Must be a pacifist. + +And what's in the pipe that he's smoking? + +Santa Claus comes in your house at night. +He must be a dope fiend to get you up tight. + +Why do police guys beat on peace guys? + -- Arlo Guthrie, "The Pause of Mr. Claus" +%% +Santa's elves are just a bunch of subordinate Clauses. +%% +Satellite Safety Tip #14: + If you see a bright streak in the sky coming at you, duck. +%% +Satire does not look pretty upon a tombstone. +%% +Satire is what closes in New Haven. +%% +Sattinger's Law: + It works better if you plug it in. +%% +Saturday night in Toledo Ohio, +Is like being nowhere at all, +All through the day how the hours rush by, +You sit in the park and you watch the grass die. + -- John Denver, "Saturday Night in Toledo Ohio" +%% +Satyrs have more faun. +%% +Savage's Law of Expediency: + You want it bad, you'll get it bad. +%% +Save energy: Drive a smaller shell. +%% +Save energy: be apathetic. +%% +Save gas, don't eat beans. +%% +Save gas, don't use the shell. +%% +Save yourself! Reboot in 5 seconds! +%% +Say! You've struck a heap of trouble-- +Bust in business, lost your wife; +No one cares a cent about you, +You don't care a cent for life; +Hard luck has of hope bereft you, +Health is failing, wish you'd die-- +Why, you've still the sunshine left you +And the big blue sky. + -- R.W. Service +%% +Say many of cameras focused t'us, +Our middle-aged shots do us justice. +No justice, please, curse ye! +We really want mercy: +You see, 'tis the justice, disgusts us. + -- Thomas H. Hildebrandt +%% +Say my love is easy had, +Say I'm bitten raw with pride, +Say I am too often sad -- +Still behold me at your side. + +Say I'm neither brave nor young, +Say I woo and coddle care, +Say the devil touched my tongue, +Still you have my heart to wear. + +But say my verses do not scan, +And I get me another man! + -- Dorothy Parker, "Fighting Words" +%% +Say no, then negotiate. + -- Helga +%% +Say something you'll be sorry for, I love receiving apologies. +%% +Say "twenty-three-skiddoo" to logout. +%% +Scenary is here, wish you were beautiful. +%% +Schapiro's Explanation: + The grass is always greener on the other side -- + but that's because they use more manure. +%% +Schizophrenia beats being alone. +%% +Science Fiction, Double Feature. +Frank has built and lost his creature. +Darkness has conquered Brad and Janet. +The servants gone to a distant planet. +Wo, oh, oh, oh. +At the late night, double feature, Picture show. +I want to go, oh, oh, oh. +To the late night, double feature, Picture show. + -- Rocky Horror Picture Show +%% +Science is built up of facts, as a house is with stones. But a +collection of facts is no more a science than a heap of stones +is a house. + -- Jules Henri Poincare +%% +Science is to computer science as hydrodynamics is to plumbing. +%% +Science is what happens when preconception meets verification. +%% +Science may someday discover what faith has always known. +%% +Science! true daughter of Old Time thou art! +Who alterest all things with thy peering eyes. +Why preyest thou thus upon the poet's heart, +Vulture, whose wings are dull realities? +How should he love thee? or how deem thee wise? +Who wouldst not leave him in his wandering +To seek for treasure in the jewelled skies, +Albeit he soared with an undaunted wing? +Hast thou not dragged Diana from her car? +And driven the Hamadryad from the wood +To seek a shelter in some happier star? +Hast thou not torn the Naiad from her flood, +The Elfin from the green grass, and from me +The summer dream beneath the tamarind tree? + -- Edgar Allen Poe, "Science, a Sonnet" +%% +Scientists still know less about what attracts men +than they do about what attracts mosquitoes. + -- Dr. Joyce Brothers, + "What Every Woman Should Know About Men" +%% +Scientists were preparing an experiment to ask the ultimate question. +They had worked for months gathering one each of every computer that +was built. Finally the big day was at hand. All the computers were +linked together. They asked the question, "Is there a God?". Lights +started blinking, flashing and blinking some more. Suddenly, there +was a loud crash, and a bolt of lightning came down from the sky, +struck the computers, and welded all the connections permanently +together. "There is now", came the reply. +%% +Scintilate, scintilate, globule vivific, +Fain how I pause at your nature specific, +Loftily poised in the ether capacious, +Highly resembling a gem carbonaceous. +Scintilate, scintilate, globule vivific, +Fain how I pause at your nature specific. +%% +Scintillation is not always identification for an auric substance. +%% +Scott's First Law: + No matter what goes wrong, it will probably look right. + +Scott's Second Law: + When an error has been detected and corrected, it will be found + to have been wrong in the first place. +Corollary: + After the correction has been found in error, it will be + impossible to fit the original quantity back into the + equation. +%% +Scotty: Captain, we din' can reference it! +Kirk: Analysis, Mr. Spock? +Spock: Captain, it doesn't appear in the symbol table. +Kirk: Then it's of external origin? +Spock: Affirmative. +Kirk: Mr. Sulu, go to pass two. +Sulu: Aye aye, sir, going to pass two. +%% +Scratch the average female and you'll find a purring bundle... at the +ready to love and honor, bake a torte and still produce quintuplets. + -- Edgar Berman +%% +Scratch the disks, dump the core, Shut it down, pull the plug +Roll the tapes across the floor, Give the core an extra tug +And the system is going to crash. And the system is going to crash. +Teletypes smashed to bits. Mem'ry cards, one and all, +Give the scopes some nasty hits Toss out halfway down the hall +And the system is going to crash. And the system is going to crash. +And we've also found Just flip one switch +When you turn the power down, And the lights will cease to twitch +You turn the disk readers into trash. And the tape drives will crumble + in a flash. +Oh, it's so much fun, When the CPU +Now the CPU won't run Can print nothing out but "foo," +And the system is going to crash. The system is going to crash. + -- To The Caissons Go Rolling Along +%% +Scratch the disks! +Drop the core! +Roll the tapes across the floor! +%% +Screw up your courage! You've screwed up everything else. +%% +Sears has everything. +%% +Seattle is so wet that people protect their property with watch-ducks. +%% +Second Law of Business Meetings: + If there are two possible ways to spell a person's name, you + will pick the wrong one. + +Corollary: + If there is only one way to spell a name, + you will spell it wrong, anyway. +%% +Second Law of Final Exams: + In your toughest final -- for the first time all year -- the most + distractingly attractive student in the class will sit next to you. +%% +Secrecy is the beginning of tyranny. +%% +Security check: INTRUDER ALERT! +%% +Sed quis custodiet ipsos Custodes? +[Who guards the Guardians?] +%% +Seduced, shaggy Samson snored. +She scissored short. Sorely shorn, +Soon shackled slave, Samson sighed, +Silently scheming, +Sightlessly seeking +Some savage, spectacular suicide. + -- Stanislaw Lem +%% +Seeing is believing. +You wouldn't have seen it if you hadn't believed it. +%% +Seeing is deceiving. It's eating that's believing. + -- James Thurber +%% +Seeing that death, a necessary end, +Will come when it will come. + -- William Shakespeare, "Julius Caesar" +%% +Seek simplicity -- and distrust it. + -- Alfred North Whitehead +%% +Seize the day, put no trust in the morrow! + -- Quintus Horatius Flaccus (Horace) +%% +Seleznick's Theory of Holistic Medicine: + Ice Cream cures all ills. Temporarily. +%% +Send lawyers, guns, and money, +The shit has hit the fan. + -- Warren Zevon +%% +Send some filthy mail. +%% +Sentient plasmoids are a gas. +%% +Serfs up! + -- Spartacus +%% +Serocki's Stricture: + Marriage is always a bachelor's last option. +%% +Serving coffee on aircraft causes turbulence. +%% +Set the cart before the horse. + -- John Heywood +%% + "Seven years and six months!" Humpty Dumpty repeated thoughtfully. +"An uncomfortable sort of age. Now if you'd asked MY advice, I'd have +said 'Leave off at seven' -- but it's too late now." + "I never ask advice about growing," Alice said indignantly. + "Too proud?" the other enquired. + Alice felt even more indignant at this suggestion. "I mean," +she said, "that one can't help growing older." + "ONE can't, perhaps," said Humpty Dumpty; "but TWO can. With +proper assistance, you might have left off at seven." + -- Lewis Carroll, "Through the Looking-Glass" +%% +Several years ago, an international chess tournament was being held in a +swank hotel in New York. Most of the major stars of the chess world were +there, and after a grueling day of chess, the players and their entourages +retired to the lobby of the hotel for a little refreshment. In the lobby, +some players got into a heated argument about who was the brightest, the +fastest, and the best chess player in the world. The argument got quite +loud, as various players claimed that honor. At that point, a security +guard in the lobby turned to another guard and commented, "If there's +anything I just can't stand, it's chess nuts boasting in an open foyer." +%% +Sex is nobody's business but the three people involved. +%% +Sex is the mathematics urge sublimated. + -- M.C. Reed +%% +Shah, shah! Ayatulla you so! +%% +Shall I compare thee to a Summer day? +No, I guess not. +%% +Shall we make a new rule of life from tonight: +always to try to be a little kinder than is necessary? + -- J.M. Barrie +%% +Shame is an improper emotion invented by +pietists to oppress the human race. + -- Robert Preston, Toddy, "Victor/Victoria" +%% +Shamus: A shamus is a guy who takes care of handyman tasks around the +temple, and makes sure everything is in working order. A shamus is at +the bottom of the pecking order of synagog functionaries, and there's +a joke about that: + +A rabbi, to show his humility before God, cries out in the middle of a +service, + "Oh, Lord, I am nobody!" +The cantor, not to be bested, also cries out, + "Oh, Lord, I am nobody!" +The shamus, deeply moved, follows suit and cries, + "Oh, Lord, I am nobody!" +The rabbi turns to the cantor and says, + "Look who thinks he's nobody!" +%% +Shannon's Observation + Nothing is so frustrating as a bad situation + that is beginning to improve. +%% +Shaw's Principle: + Build a system that even a fool can use, + and only a fool will want to use it. +%% +She asked me, "What's your sign?" +I blinked and answered "Neon," +I thought I'd blow her mind... +%% +She been married so many times +she got rice marks all over her face. + -- Tom Waits +%% +She begged and she pleaded for more. +I said, "We've already had four, + And I'm sure that you've heard, + Though its somewhat absurd, +That eros spelt backwards is sore." +%% +She blinded me with science! +%% +She can kill all your files; +She can freeze with a frown. +And a wave of her hand brings the whole system down. +And she works on her code until ten after three. +She lives like a bat but she's always a hacker to me. + -- Apologies to Billy Joel +%% +She has an alarm clock and a phone that don't ring - they applaud. +%% +She is descended from a long line that her mother listened to. + -- Gypsy Rose Lee +%% +She missed an invaluable opportunity to give him +a look that you could have poured on a waffle. +%% +She often gave herself very good advice +(though she very seldom followed it). + -- Lewis Carroll +%% +She ran the gamut of emotions from 'A' to 'B'. + -- Dorothy Parker, on a Kate Hepburn performance +%% +She sells cshs by the cshore. +%% +She won' go Warp 7, Cap'n! The batteries are dead! +%% +Shedenhelm's Law: + All trails have more uphill sections + than they have downhill sections. +%% +"Shelter", what a nice name for for a place where you polish your cat. +%% +Sherry [Thomas Sheridan] is dull, naturally dull; but it must have taken +him a great deal of pains to become what we now see him. Such an excess +of stupidity, sir, is not in Nature. + -- Samuel Johnson +%% +She's learned to say things with her eyes +that others waste time putting into words. +%% +She's so tough she won't take 'yes' for an answer. +%% +She's such a kinky girl, +The kind you don't take home to mother. +She will never let your spirits down +Once you get her off the street. +%% +Shick's Law: + There is no problem a good miracle can't solve. +%% +Shift to the left, +Shift to the right, +Mask in, mask out, +BYTE, BYTE, BYTE !!! +%% +Ships are safe in harbor, but they were never meant to stay there. +%% +Shopping at this grody little computer store at the Galleria for a +totally awwwsome Apple. Fer suuure. I mean Apples are nice you +know? But, you know, there is this cute guy who works there and HE +says that VAX's are cooler! I mean I don't really know, you know? +He says that he has this totally tubular VAX at home and it's stuffed +with memory-to-the-max! Right, yeah. And he wants to take me home +to show it to me. Oh My God! I'm suuure. Gag me with a Prime! +%% +Show me a man who is a good loser and I'll +show you a man who playing golf with his boss. +%% +Show respect for age. Drink good Scotch for a change. +%% +Show your affection, which will probably meet with pleasant response. +%% +Showing up is 80% of life. + -- Woody Allen +%% +Si Dieu n'existait pas, il faudrait l'inventer. + -- Voltaire +%% +Si jeunesse savait, si vieillesse pouvait. +[If youth but knew, if old age but could.] + -- Henri Estienne +%% +Sic Transit Gloria Thursdi. +%% +Sic transit gloria Monday! +%% +Sic transit gloria mundi. +[So passes away the glory of this world.] + -- Thomas a Kempis +%% +Sight is a faculty; seeing is an art. +%% +Sigmund's wife wore Freudian slips. +%% +Signs of crime: screaming or cries for help. + -- The Brown University Security Crime Prevention Pamphlet +%% +Silence can be the biggest lie of all. We have a responsibility to speak +up; and whenever the occasion calls for it, we have a responsibility to +raise bloody hell. + -- Herbert Block +%% +Silence is the element in which great things fashion themselves. + -- Thomas Carlyle +%% +Silverman's Law: + If Murphy's Law can go wrong, it will. +%% +Simon's Law: + Everything put together falls apart sooner or later. +%% +Simplicity does not precede complexity, but follows it. +%% +Sin boldly. + -- Martin Luther +%% +Sin has many tools, but a lie is the handle which fits them all. +%% +Sin lies only in hurting other people unnecessarily. +All other "sins" are invented nonsense. +(Hurting yourself is not sinful -- just stupid). + -- Lazarus Long +%% +Since I hurt my pendulum +My life is all erratic. +My parrot who was cordial +Is now transmitting static. +The carpet died, a palm collapsed, +The cat keeps doing poo. +The only thing that keeps me sane +Is talking to my shoe. + -- My Shoe +%% +Since aerosols are forbidden, the police are using roll-on Mace! +%% +Since before the Earth was formed and before the sun burned hot in space, +cosmic forces of inexorable power have been working relentlessly toward +this moment in space-time -- your receiving this fortune. +%% +Since everything in life is but an experience perfect in being what it is, +having nothing to do with good or bad, acceptance or rejection, one may well +burst out in laughter. + -- Long Chen Pa +%% +Since we cannot hope for order, let us withdraw with style from the chaos. + -- Tom Stoppard +%% +Sink or Swim with Teddy! +%% +[Sir Stafford Cripps] has all the virtues +I dislike and none of the vices I admire. + -- Winston Churchill +%% +Sir, it's very possible this asteroid is not stable. + -- CP30 +%% + Sixtus V, Pope from 1585 to 1590 authorized a printing of the +Vulgate Bible. Taking no chances, the pope issued a papal bull +automatically excommunicating any printer who might make an alteration +in the text. This he ordered printed at the beginning of the Bible. +He personally examined every sheet as it came off the press. Yet the +published Vulgate Bible contained so many errors that corrected scraps +had to be printed and pasted over them in every copy. The result +provoked wry comments on the rather patchy papal infallibility, and +Pope Sixtus had no recourse but to order the return and destruction of +every copy. +%% +Skinner's Constant (or Flannagan's Finagling Factor): + That quantity which, when multiplied by, divided by, added to, + or subtracted from the answer you got, gives you the answer you + should have gotten. +%% +Slang is language that takes off its coat, +spits on its hands, and goes to work. +%% +Sleep -- the most beautiful experience in life -- except drink. + -- W.C. Fields +%% +Slick's Three Laws of the Universe: + 1) Nothing in the known universe travels faster than a bad check. + 2) A quarter-ounce of chocolate = four pounds of fat. + 3) There are two types of dirt: the dark kind, which is + attracted to light objects, and the light kind, which is + attracted to dark objects. +%% +Slous' Contention: + If you do a job too well, you'll get stuck with it. +%% +Slow day. +Practice crawling. +%% +Small change can often be found under seat cushions. +%% +Small is beautiful. + -- Schumacher's Dictum +%% +Small things make base men proud. + -- William Shakespeare, "Henry VI" +%% +Smear the road with a runner!! +%% +Smile! You're on Candid Camera. +%% +Smoking Prohibited. Absolutely no ifs, ands, or butts. +%% +Smoking a woman is like kissing a fish. +%% +Snakes. Why did it have to be snakes? +%% +Snoopy: No problem is so big that it can't be run away from. +%% +Snow Day -- stay home. +%% +Snow and adolescence are the only problems +that disappear if you ignore them long enough. +%% +So do the noble fall. For they are ever caught in a trap of their own making. +A trap -- walled by duty, and locked by reality. Against the greater force +they must fall -- for, against that force they fight because of duty, because +of obligations. And when the noble fall, the base remain. The base -- whose +only purpose is the corruption of what the noble did protect. Whose only +purpose is to destroy. The noble: who, even when fallen, retain a vestige of +strength. For theirs is a strength born of things other than mere force. +Theirs is a strength supreme... theirs is the strength -- to restore. + -- Gerry Conway, "Thor", #193 +%% +So far as I can remember, there is not one +word in the Gospels in praise of intelligence. + -- Bertrand Russell +%% +So from the depths of its enchantment, Terra was able to calculate a course +of action. Here at last was an opportunity to consort with Dirbanu on a +friendly basis -- great Durbanu which, since it had force fields which Earth +could not duplicate, must of necessity have many other things Earth could +use; mighty Durbanu before whom we would kneel in supplication (with purely- +for-defense bombs hidden in our pockets) with lowered heads (making invisible +the knife in our teeth) and ask for crumbs from their table (in order to +extrapolate the location of their kitchens). + -- T. Sturgeon, "The World Well Lost" +%% +So live that you wouldn't be ashamed +to sell the family parrot to the town gossip. +%% +So many men and so little time. +%% +So many men, so many opinions; every one his own way. + -- Publius Terentius Afer (Terence) +%% +So many women, and so little time! +%% +So much +depends +upon +a red + +wheel +barrow +glazed with + +rain +water +beside +the white +chickens. + -- William Carlos Williams, "The Red Wheel Barrow" +%% +So she went into the garden to cut a cabbage leaf to make an apple pie; +and at the same time a great she-bear, coming up the street pops its head +into the shop. "What! no soap?" So he died, and she very imprudently +married the barber; and there were present the Picninnies, and the Grand +Panjandrum himself, with the little round button at top, and they all +fell to playing the game of catch as catch can, till the gunpowder ran +out at the heels of their boots. + -- Samuel Foote +%% +So so is good, very good, very excellent good: +and yet it is not; it is but so so. + -- William Shakespeare, "As You Like It" +%% +So this it it. We're going to die. +%% +So you think that money is the root of all evil. +Have you ever asked what is the root of money? + -- Ayn Rand +%% +So, your daughter was voted "Most Likely to Conceive", +and you're still drinking ordinary scotch? +%% +So you're back... about time... +%% +Soap and education are not as sudden as a +massacre, but they are more deadly in the long run. + -- Mark Twain +%% +Soldiers who wish to be a hero +Are practically zero, +But those who wish to be civilians, +They run into the millions. +%% +Solutions are obvious if one only has the +optical power to observe them over the horizon. + -- K.A. Arsdall +%% + Some 1500 miles west of the Big Apple we find the Minneapple, a +haven of tranquility in troubled times. It's a good town, a civilized town. +A town where they still know how to get your shirts back by Thursday. Let +the Big Apple have the feats of "Broadway Joe" Namath. We have known the +stolid but steady Killebrew. Listening to Cole Porter over a dry martini +may well suit those unlucky enough never to have heard the Whoopee John Polka +Band and never to have shared a pitcher of 3.2 Grain Belt Beer. The loss is +theirs. And the Big Apple has yet to bake the bagel that can match peanut +butter on lefse. Here is a town where the major urban problem is dutch elm +disease and the number one crime is overtime parking. We boast more theater +per capita than the Big Apple. We go to see, not to be seen. We go even +when we must shovel ten inches of snow from the driveway to get there. Indeed +the winters are fierce. But then comes the marvel of the Minneapple summer. +People flock to the city's lakes to frolic and rejoice at the sight of so +much happy humanity free from the bonds of the traditional down-filled parka. +Here's to the Minneapple. And to its people. Our flair for style is balanced +by a healthy respect for wind chill factors. + And we always, always eat our vegetables. + This is the Minneapple. +%% +Some books are to be tasted, others to be swallowed, +and some few to be chewed and digested. + -- Francis Bacon + [As anyone who has ever owned a puppy already knows. Ed.] +%% +Some changes are so slow, you don't notice them. +Others are so fast, they don't notice you. +%% +Some circumstantial evidence is very strong, +as when you find a trout in the milk. + -- Thoreau +%% +Some men are discovered; others are found out. +%% +Some men are so interested in their wives continued happiness +that they hire detectives to find out the reason for it. +%% +Some men feel that the only thing they owe +the woman who marries them is a grudge. + -- Helen Rowland +%% +Some men rob you with a six-gun -- others with a fountain pen. + -- Woodie Guthrie +%% +Some men who fear that they are playing +second fiddle aren't in the band at all. +%% +Some of my readers ask me what a "Serial Port" is. +The answer is: I don't know. +Is it some kind of wine you have with breakfast? +%% +Some of the things that live the longest +in peoples' memories never really happened. +%% +Some of us are becoming the men we wanted to marry. + -- Gloria Steinem +%% +Some parts of the past must be preserved, +and some of the future prevented at all costs. +%% +Some people are born mediocre, some people achieve +mediocrity, and some people have mediocrity thrust upon them. + -- Joseph Heller, "Catch-22" +%% +Some people around here wouldn't recognize +subtlety if it hit them on the head. +%% +Some people carve careers, others chisel them. +%% +Some people cause happiness wherever +they go; others, whenever they go. +%% +Some people have a great ambition: to build something +that will last, at least until they've finished building it. +%% +Some people have no respect for age unless it's bottled. +%% +Some people have parts that are so private +they themselves have no knowledge of them. +%% +Some people manage by the book, even though they +don't know who wrote the book or even what book. +%% +Some people need a good imaginary cure +for their painful imaginary ailment. +%% +Some people only open up to tell you that they're closed. +%% +Some peoples mouths work faster than their brains. +They say things they haven't even thought of yet. +%% +Some rise by sin and some by virtue fall. +%% +Some say the world will end in fire, +Some say in ice. +From what I've tasted of desire +I hold with those who favor fire. +But if it had to perish twice +I think I know enough of hate +To say that for destruction, ice +Is also great +And would suffice + -- Robert Frost, "Fire and Ice" +%% +Some scholars are like donkeys, they merely carry a lot of books. + -- Folk saying +%% +Some things have to be believed to be seen. +%% +Somebody ought to cross ball point pens with coat hangers +so that the pens will multiply instead of disappear. +%% +Somebody's terminal is dropping bits. +I found a pile of them over in the corner. +%% +Someday somebody has got to decide whether the +typewriter is the machine, or the person who operates it. +%% +Someday you'll get your big chance -- or have you already had it? +%% +Someday you'll look back on this moment and plow into a parked car. +%% +Someday your prints will come. + -- Kodak +%% +Somehow, the world always affects you more than you affect it. +%% +Someone is speaking well of you. +%% +Someone is speaking well of you. +How unusual! +%% +Someone is unenthusiastic about your work. +%% +Someone whom you reject today, will reject you tomorrow. +%% +Someone will try to honk your nose today. +%% +Something's rotten in the state of Denmark. + -- Shakespeare +%% +Sometime when you least expect it, Love will tap you on the shoulder... +and ask you to move out of the way because it still isn't your turn. + -- N.V. Plyter +%% +Sometimes I feel like I'm fading away, +Looking at me, I got nothin' to say. +Don't make me angry with the things games that you play, +Either light up or leave me alone. +%% +Sometimes I live in the country, +And sometimes I live in town. +And sometimes I have a great notion, +To jump in the river and drown. +%% +Sometimes I simply feel that the whole +world is a cigarette and I'm the only ashtray. +%% +Sometimes I wonder if I'm in my right mind. +Then it passes off and I'm as intelligent as ever. + -- Samuel Beckett, "Endgame" +%% +Sometimes I worry about being a success in a mediocre world. + -- Lily Tomlin +%% +Sometimes, at the end of the day, when I'm +smiling and shaking their hands, I want to kick them. + -- Richard M. Nixon +%% +Sometimes even to live is an act of courage. + -- Seneca +%% +Sometimes the best medicine is to stop taking something. +%% +Sometimes the light is all shining on me, +Other times I can hardly see. +Lately it occurs to me +What a long strange trip it's been. + -- The Grateful Dead, "American Beauty" +%% +Sometimes when I get up in the morning, I feel very peculiar. I feel +like I've just got to bite a cat! I feel like if I don't bite a cat +before sundown, I'll go crazy! But then I just take a deep breath and +forget about it. That's what is known as real maturity. + -- Snoopy +%% +Sometimes, when I think of what that girl means +to me, it's all I can do to keep from telling her. + -- Andy Capp +%% +Sometimes you get an almost irresistible urge to go on living. +%% + "Somewhere", said Father Vittorini, "did Blake not speak of the +Machineries of Joy? That is, did not God promote environments, then +intimidate these Natures by provoking the existence of flesh, toy men and +women, such as are we all? And thus happily sent forth, at our best, with +good grace and fine wit, on calm noons, in fair climes, are we not God's +Machineries of Joy?" + "If Blake said that", said Father Brian, "he never lived in Dublin." + -- R. Bradbury, "The Machineries of Joy" +%% +Somewhere, something incredible is waiting to be known. + -- Carl Sagan +%% +Son, someday a man is going to walk up to you with a deck of cards on which +the seal is not yet broken. And he is going to offer to bet you that he can +make the Ace of Spades jump out of the deck and squirt cider in your ears. +But son, do not bet this man, for you will end up with a ear full of cider. + -- Sky Masterson's Father +%% +Sooner or later you must pay for your sins. +(Those who have already paid may disregard this cookie). +%% +Sorry. Nice try. +%% +Sorry 'bout that sweat, honey. That's just holy water. + -- Little Richard +%% +Sorry never means having you're say to love. +%% +So... so you think you can tell +Heaven from Hell? +Blue skies from pain? Did they get you to trade +Can you tell a green field Your heroes for ghosts? +From a cold steel rail? Hot ashes for trees? +A smile from a veil? Hot air for a cool breeze? +Do you think you can tell? Cold comfort for change? + Did you exchange + A walk on part in a war + For the lead role in a cage? + -- Pink Floyd, "Wish You Were Here" +%% +Space is big. You just won't believe how vastly, hugely, mind-bogglingly +big it is. I mean, you may think it's a long way down the road to the +drug store, but that's just peanuts to space. + -- The Hitchhiker's Guide to the Galaxy +%% +Space is to place as eternity is to time. + -- Joseph Joubert +%% +Space tells matter how to move and matter tells space how to curve. + -- Wheeler +%% +Speak roughly to your little Vax, +And boot it when it crashes; +It knows that one cannot relax +Because the paging thrashes! + +I speak severely to my Vax, +And boot it when it crashes; +In spite of all my favorite hacks, +My jobs it always trashes! +%% +Speak roughly to your little boy, + And beat him when he sneezes: +He only does it to annoy + Because he knows it teases. + + Wow! wow! wow! + +I speak severely to my boy, + And beat him when he sneezes: +For he can thoroughly enjoy + The pepper when he pleases! + + Wow! wow! wow! +%% +"Speak, thou vast and venerable head," muttered Ahab, "which, though +ungarnished with a beard, yet here and there lookest hoary with mosses; speak, +mighty head, and tell us the secret thing that is in thee. Of all divers, +thou has dived the deepest. That head upon which the upper sun now gleams has +moved amid the world's foundations. Where unrecorded names and navies rust, +and untold hopes and anchors rot; where in her murderous hold this frigate +earth is ballasted with bones of millions of the drowned; there, in that awful +water-land, there was thy most familiar home. Thou hast been where bell or +diver never went; has slept by many a sailer's side, where sleepless mothers +would give their lives to lay them down. Thou saw'st the locked lovers when +leaping from their flaming ship; heart to heart they sank beneath the exulting +wave; true to each other, when heaven seemed false to them. Thou saw'st the +murdered mate when tossed by pirates from the midnight deck; for hours he fell +into the deeper midnight of the insatiate maw; and his murderers still sailed +on unharmed -- while swift lightnings shivered the neighboring ship that would +have borne a righteous husband to outstretched, longing arms. O head! thou has +seen enough to split the planets and make an infidel of Abraham, and not one +syllable is thine!" + -- H. Melville, "Moby Dick" +%% +Speaking as someone who has delved into the intricacies of PL/I, I am sure +that only Real Men could have written such a machine-hogging, cycle-grabbing, +all-encompassing monster. Allocate an array and free the middle third? +Sure! Why not? Multiply a character string times a bit string and assign the +result to a float decimal? Go ahead! Free a controlled variable procedure +parameter and reallocate it before passing it back? Overlay three different +types of variable on the same memory location? Anything you say! Write a +recursive macro? Well, no, but Real Men use rescan. How could a language +so obviously designed and written by Real Men not be intended for Real Man use? +%% +Speaking of love, one problem that recurs more and more frequently these +days, in books and plays and movies, is the inability of people to communicate +with the people they love; Husbands and wives who can't communicate, children +who can't communicate with their parents, and so on. And the characters in +these books and plays and so on (and in real life, I might add) spend hours +bemoaning the fact that they can't communicate. I feel that if a person can't +communicate, the very least he can do is to shut up! + -- Tom Lehrer, "That Was the Year that Was" +%% +Speaking of purchasing a dog, never buy a watchdog that's +on sale. After all, everyone knows a bargain dog never bites! +%% +Spence's Admonition: + Never stow away on a kamikaze plane. +%% +Spend extra time on hobby. Get plenty of rolling papers. +%% +Spock: The odds of surviving another +attack are 13562190123 to 1, Captain. +%% +Spock: We suffered 23 casualties in that attack, Captain. +%% +Spring is here, spring is here, +Life is skittles and life is beer. +%% +Squirrels eating squirrels, my God, that's sick. +%% +Stability itself is nothing else than a more sluggish motion. +%% +Staff meeting in the conference room in 3 minutes. +%% +Stamp out organized crime!! Abolish the IRS. +%% +Stamp out philately. +%% +Standing on head makes smile of frown, but rest of face also upside down. +%% +Starkle, starkle, little twink, +Who the hell you are I think +I'm not as drunk as thinkle peep +I'm just a little slort of sheep. +Tee martoonis make a guy, +Feel so woozy, I don't know why. +So mass the pixer and kill my fup +I've all day sober to sunday up. +%% +Start the day with a smile. +After that you can be your nasty old self again. +%% +Statistics are no substitute for judgement. + -- Henry Clay +%% +Stay away from flying saucers today. +%% +Stay away from hurricanes for a while. +%% +Stay the curse. +%% +Stay together, drag each other down. +%% +Stayed in bed all morning just to pass the time, +There's something wrong here, there can be no more denying, +One of us is changing, or maybe we just stopped trying, + +And it's too late, baby, now, it's too late, +Though we really did try to make it, +Something inside has died and I can't hide and I just can't fake it... + +It used to be so easy living here with you, +You were light and breezy and I knew just what to do +Now you look so unhappy and I feel like a fool. + +There'll be good times again for me and you, +But we just can't stay together, don't you feel it too? +But I'm glad for what we had and that I once loved you... + +But it's too late baby... +It's too late, now darling, it's too late... + -- Carol King, "Tapestry" +%% +Steady movement is more important than speed, much of the time. So +long as there is a regular progression of stimuli to get your mental +hooks into, there is room for lateral movement. Once this begins, +its rate is a matter of discretion. + -- Corwin, "Prince of Amber" +%% +Stealing a rhinoceros should not be attempted lightly. +%% +Steckel's Rule to Success: + Good enough is never good enough. +%% +Steele's Plagiarism of Somebody's Philosophy: + Everybody should believe in something -- + I believe I'll have another drink. +%% +Never test for an error condition you don't know how to handle. + -- Steinbach +%% +Stellar rays prove fibbing never pays. +Embezzlement is another matter. +%% +Step back, unbelievers! +Or the rain will never come. +Somebody keep the fire burning, someone come and beat the drum. +You may think I'm crazy, you may think that I'm insane, +But I swear to you, before this day is out, + you folks are gonna see some rain! +%% +Still looking for the glorious results of my misspent youth. +Say, do you have a map to the next joint? +%% +Stock's Observation: + You no sooner get your head above water + but what someone pulls your flippers off. +%% +Stone's Law: + One man's "simple" is another man's "huh?" +%% +Stop! There was first a game of blindman's buff. Of course there was. +And I no more believe Topper was really blind than I believe he had eyes +in his boots. My opinion is, that it was a done thing between him and +Scrooge's nephew; and that the Ghost of Christmas Present knew it. The +way he went after that plump sister in the lace tucker, was an outrage +on the credulity of human nature. +%% +Stop me, before I kill again! +%% +Stop searching. Happiness is right next to you. +%% +Stop searching. Happiness is right next to you. +Now, if they'd only take a bath... +%% +Stop searching forever. Happiness is just next to you. +%% +Stop searching forever. Happiness is unattainable. +%% + Strange memories on this nervous night in Las Vegas. Five years later? +Six? It seems like a lifetime, or at least a Main Era -- the kind of peak that +never comes again. San Fransisco in the middle sixties was a very special time +and place to be a part of. Maybe it meant something. Maybe not, in the long +run... There was madness in any direction, at any hour. If not across the +Bay, then up the Golden Gate or down 101 to Los Altos or La Honda... You could +strike sparks anywhere. There was a fantastic universal sense that whatever we +were doing was right, that we were winning... + And that, I think, was the handle -- that sense of inevitable victory +over the forces of Old and Evil. Not in any mean or military sense; we didn't +need that. Our energy would simply prevail. There was no point in fighting +-- on our side or theirs. We had all the momentum; we were riding the crest +of a high and beautiful wave. So now, less than five years later, you can go +up on a steep hill in Las Vegas and look West, and with the right kind of eyes +you can almost see the high-water mark -- that place where the wave finally +broke and rolled back. + -- H.S. Thompson +%% +Straw? No, too stupid a fad. I put soot on warts. +%% +Stress has been pinpointed as a major cause of illness. To avoid overload +and burnout, keep stress out of your life. Give it to others instead. Learn +the "Gaslight" treatment, the "Are you talking to me?" technique, and the +"Do you feel okay? You look pale." approach. Start with negotiation and +implication. Advance to manipulation and humiliation. Above all, relax +and have a nice day. +%% +Stuckness shouldn't be avoided. It's the psychic predecessor of all +real understanding. An egoless acceptance of stuckness is a key to an +understanding of all Quality, in mechanical work as in other endeavors. + -- R. Pirsig, "Zen and the Art of Motorcycle Maintenance" +%% +Stult's Report: + Our problems are mostly behind us. + What we have to do now is fight the solutions. +%% +Substitute 'damn' every time you're inclined to write 'very'; your +editor will delete it and the writing will be just as it should be. + -- Mark Twain +%% +Success is a journey, not a destination. +%% +Success is getting what you want; happiness is wanting what you get. +%% +Success is something I will dress for when I get there, and not until. +%% +Success is the sole earthly judge of right and wrong. + -- Adolph Hitler, "Mein Kampf" +%% +Succumb to natural tendencies. Be hateful and boring. +%% +Such a foolish notion, that war is called devotion, +when the greatest warriors are the ones who stand for peace. +%% +Such evil deeds could religion prompt. + -- Titus Lucretius Carus +%% +Suggest you just sit there and wait till life gets easier. +%% +Suicide is simply a case of mistaken identity. +%% +Suicide is the sincerest form of self-criticism. + -- Donald Kaul +%% +Sum quod eris. +%% +Sun in the night, everyone is together, +Ascending into the heavens, life is forever. + -- Brand X, "Moroccan Roll/Sun in the Night" +%% +It hangs down from the chandelier +Nobody knows quite what it does +Its color is odd and its shape is weird +It emits a high-sounding buzz + +It grows a couple of feet each day +and wriggles with sort of a twitch +Nobody bugs it 'cause it comes from +a visiting uncle who's rich! + -- To "It Came Upon A Midnight Clear" +%% +Superstition, idolatry, and hypocrisy +have ample wages, but truth goes a-begging. + -- Martin Luther +%% +Support Bingo, keep Grandma off the streets. +%% +Support mental health or I'LL KILL YOU!!!! +%% +Support the American Kidney Foundation. +Don't wear your motorcycle helmet. +%% +Support your local church or synagogue. +Worship at Bank of America. +%% +Support your local hooker! Play rugby! +%% +Support your right to arm bears!! +%% +Support your right to bare arms! + -- A message from the National Short-Sleeved Shirt Association +%% +Sure, Reagan has promised to take senility tests. +But what if he forgets? +%% +Sure, and of course I would vote for a woman for president! +Quite naturally, we wouldn't have to pay her so much. +%% +Surprise! You are the lucky winner of random I.R.S Audit! +Just type in your name and social security number. +Please remember that leaving the room is punishable under law: + +Name # + + +%% +Surprise due today. Also the rent. +%% +Surprise your boss. Get to work on time. +%% +Suspicion always haunts the guilty mind. + -- Wm. Shakespeare +%% +Swap read error. You lose your mind. +%% +Sweet April showers do spring May flowers. + -- Thomas Tusser +%% +Sweet sixteen is beautiful Bess, +And her voice is changing -- from "No" to "Yes". +%% +Swerve me? The path to my fixed purpose is laid with iron rails, +whereon my soul is grooved to run. Over unsounded gorges, through +the rifled hearts of mountains, under torrents' beds, unerringly +I rush! + -- Captain Ahab, "Moby Dick" +%% +Swipple's Rule of Order: + He who shouts the loudest has the floor. +%% +System checkpoint complete. +%% +System going down at 1:45 this afternoon for disk crashing. +%% +System going down at 5 this afternoon to install scheduler bug. +%% +System going down in 5 minutes. +%% +System restarting, wait... +%% +System/3! System/3! +See how it runs! See how it runs! + Its monitor loses so totally! + It runs all its programs in RPG! + It's made by our favorite monopoly! +System/3! +%% +Systems programmers are the high priests of a low cult. + -- R.S. Barton +%% +T. Sturgeon's Law: + 90% of everything is crap. +%% +TACKY: + Serving grape kool-aid at religious functions. +%% +TACT: + The unsaid part of what you're thinking. +%% +TAKE FORCEFUL ACTION: + Do something that should have been done a long time ago. +%% +TAURUS (Apr 20 - May 20) + You are practical and persistent. You have a dogged determination + and work like hell. Most people think you are stubborn and bull + headed. You are a Communist. +%% +TAURUS (Apr.20 - May 20) + Take advantage of this opportunity to get a little extra sleep, + because you're going to miss the bus again today anyway. You will + decide to lose weight today, just like yesterday. +%% +TAX OFFICE: + Den of inequity. +%% +TAXES: + Of life's two certainties, + the only one for which you can get an extension. +%% +TEAMWORK: + Having someone to blame. +%% +TEUTONIC: + Not enough gin. +%% +TEX is potentially the most significant invention in typesetting in this +century. It introduces a standard language for computer typography, and in +terms of importance could rank near the introduction of the Gutenberg press. + -- Gordon Bell +%% +THE BEATLES: + Paul McCartney's old back-up band. +%% + THE CHURCH OF COUNTERFACTUAL BELIEF + +An amalgamation of the Creation Science Research Foundation and the Flat Earth +Society, The Church of Counterfactual Belief has been set up to cater to all +who do not allow demonstrable truth to get in the way of their beliefs. +In addition to creation science and the flatness of the earth, the following +beliefs have been certified by Pope Duane as correct Church dogma: + + --That there is a hole in the Earth at the North Pole from + which UFOs come. + --That pi equals precisely 3.000. + --That Billy Joe Wilson (Hoopla, Miss.) has successfully + squared the circle. + --That Harry Truman is still president, and doing a fine job. +%% +THE LESSER-KNOWN PROGRAMMING LANGUAGES #10 -- SIMPLE + + SIMPLE is an acronym for Sheer Idiot's Monopurpose Programming +Language Environment. This language, developed at the Hanover College +for Technological Misfits, was designed to make it impossible to write +code with errors in it. The statements are, therefore, confined to BEGIN, +END and STOP. No matter how you arrange the statements, you can't make +a syntax error. Programs written in SIMPLE do nothing useful. Thus +they achieve the results of programs written in other languages without +the tedious, frustrating process of testing and debugging. +%% +THE LESSER-KNOWN PROGRAMMING LANGUAGES #12 -- LITHP + + This otherwise unremarkable language is distinguished by the +absence of an "S" in its character set; users must substitute "TH". +LITHP is said to be useful in protheththing lithtth. +%% +THE LESSER-KNOWN PROGRAMMING LANGUAGES #13 -- SLOBOL + + SLOBOL is best known for the speed, or lack of it, of its compiler. +Although many compilers allow you to take a coffee break while they compile, +SLOBOL compilers allow you to travel to Bolivia to pick the beans. Forty- +three programmers are known to have died of boredom sitting at their terminals +while waiting for a SLOBOL program to compile. Weary SLOBOL programmers +often turn to a related (but infinitely faster) language, COCAINE. +%% +THE LESSER-KNOWN PROGRAMMING LANGUAGES #14 -- VALGOL + + VALGOL is enjoying a dramatic surge of popularity across the +industry. VALGOL commands include REALLY, LIKE, WELL, and Y*KNOW. +Variables are assigned with the =LIKE and =TOTALLY operators. Other +operators include the "California booleans", FERSURE and NOWAY. VALGOL +is characterized by its unfriendly error messages. For example, when +the user makes a syntax error, the interpreter displays the message GAG +ME WITH A SPOON! A successful compile may be termed MAXIMALLY AWESOME! +%% +THE LESSER-KNOWN PROGRAMMING LANGUAGES #17 -- DOGO + + Developed at the Massachusetts Institute of Obedience Training, DOGO +DOGO heralds a new era of computer-literate pets. DOGO commands include +SIT, STAY, HEEL, and ROLL OVER. An innovative feature of DOGO is "puppy +graphics", a small cocker spaniel that occasionally leaves a deposit as +he travels across the screen. +%% +THE LESSER-KNOWN PROGRAMMING LANGUAGES #17 -- SARTRE + + Named after the late existential philosopher, SARTRE is an extremely +unstructured language. Statements in SARTRE have no purpose; they just are. +Thus SARTRE programs are left to define their own functions. SARTRE +programmers tend to be boring and depressed, and are no fun at parties. +%% +THE LESSER-KNOWN PROGRAMMING LANGUAGES #18 -- C- + + This language was named for the grade received by its creator when +he submitted it as a class project in a graduate programming class. C- is +best described as a "low-level" programming language. In fact, the language +generally requires more C- statements than machine-code statements to execute +a given task. In this respect, it is very similar to COBOL. +%% +THE LESSER-KNOWN PROGRAMMING LANGUAGES #18 -- FIFTH + + FIFTH is a precision mathematical language in which the data types +refer to quantity. The data types range from CC, OUNCE, SHOT, and JIGGER to +FIFTH (hence the name of the language), LITER, MAGNUM and BLOTTO. Commands +refer to ingredients such as CHABLIS, CHARDONNAY, CABERNET, GIN, VERMOUTH, +VODKA, SCOTCH, and WHATEVERSAROUND. + The many versions of the FIFTH language reflect the sophistication and +financial status of its users. Commands in the ELITE dialect include VSOP and +LAFITE, while commands in the GUTTER dialect include HOOTCH and RIPPLE. The +latter is a favorite of frustrated FORTH programmers who end up using this +language. +%% +THE LESSER-KNOWN PROGRAMMING LANGUAGES #5 -- LAIDBACK + + LAIDBACK was developed at the (now defunct) Marin County Center for +T'ai Chi, Mellowness and Computer Programming, as an alternative to the more +intense languages of nearby Silicon Valley. + The Center was ideal for programmers who liked to soak in hot tubs +while they worked. Unfortunately, few programmers could survive there long, +since the Center outlawed pizza and RC Cola in favor of bean curd and Perrier. + Many mourn the demise of LAIDBACK because of its reputation as a +gentle and nonthreatening language. For example, LAIDBACK responded to +syntax errors with the message SORRY MAN, I CAN'T DEAL BEHIND THAT. +%% +THE NEW RIGHT: + A javelin team that elects to receive. +%% +THEORY +Into love and out again, + Thus I went and thus I go. +Spare your voice, and hold your pen: + Well and bitterly I know +All the songs were ever sung, + All the words were ever said; +Could it be, when I was young, + Someone dropped me on my head? + -- Dorothy Parker +%% +THEORY: + System of ideas meant to explain something, chosen with a view to + originality, controversialism, incomprehensibility, and how good + it will look in print. +%% + THIS IS PLEDGE WEEK FOR THE FORTUNE PROGRAM + +If you like the fortune program, why not support it now with your contribution +of a pithy fortune, clean or obscene? We cannot continue without your support. +Less than 14% of all fortune users are contributors. That means that 86% of +you are getting a free ride. We can't go on like this much longer. Federal +cutbacks mean less money for fortunes, and unless user contributions increase +to make up the difference, the fortune program will have to shut down between +midnight and 8 a.m. Don't let this happen. Mail your fortunes right now to +`fortune'. Just type in your favorite pithy fortune. Do it now before you +forget. Our target is 300 new fortunes by the end of the week. Don't miss +out. All fortunes will be acknowledged. If you contribute 30 fortunes or +more, you will receive a free subscription to "The Fortune Hunter", our monthly +program guide. If you contribute 50 or more, you will receive a free "Fortune +Hunter" coffee mug! +%% +THREE-BAG UGLY: + That's when you put one bag over her head, one bag over your + head in case her's falls off, and one over the dog's to keep it + from howling. +%% +TIRED of calculating components of vectors? Displacements along direction of +force getting you down? Well, now there's help. Try amazing "Dot-Product", +the fast, easy way many professionals have used for years and is now available +to YOU through this special offer. Three out of five engineering consultants +recommend "Dot-Product" for their clients who use vector products. Mr. +Gumbinowitz, mechanical engineer, in a hidden-camera interview... + "Dot-Product really works! Calculating Z-axis force components has + never been easier." +Yes, you too can take advantage of the amazing properties of Dot-Product. Use +it to calculate forces, velocities, displacements, and virtually any vector +components. How much would you pay for it? But wait, it also calculates the +work done in Joules, Ergs, and, yes, even BTU's. Divide Dot-Product by the +magnitude of the vectors and it becomes an instant angle calculator! Now, how +much would you pay? All this can be yours for the low, low price of $19.95!! +But that's not all! If you order before midnight, you'll also get "Famous +Numbers of Famous People" as a bonus gift, absolutely free! Yes, you'll get +Avogadro's number, Planck's, Euler's, Boltzmann's, and many, many, more!! +Call 1-800-DOT-6000. Operators are standing by. That number again... +1-800-DOT-6000. Supplies are limited, so act now. This offer is not +available through stores and is void where prohibited by law. +%% +TODAY: + A nice place to visit, but you can't stay here for long. +%% +TRAGEDY: + A busload of lawyers driving off a cliff with three empty seats. +%% +TRANSACTION CANCELLED - FARECARD RETURNED +%% +TRANSFER: + A promotion you receive on the condition that you leave town. +%% +TRANSPARENT: + Being or pertaining to an existing, nontangible object. + "It's there, but you can't see it" + -- IBM System/360 announcement, 1964. + +VIRTUAL: + Being or pertaining to a tangible, nonexistent object. + "I can see it, but it's not there." + -- Lady Macbeth. +%% +TRANSVESTITE: + Someone who spends his junior year at college abroad. +%% +TRAVEL: + Something that makes you feel like you're getting somewhere. +%% +TRUTHFUL: + Dumb and illiterate. +%% +Tis man's perdition to be safe, when for the truth he ought to die. +%% +TV is chewing gum for the eyes. + -- Frank Lloyd Wright +%% +Tact in audacity is knowing how far you can go without going too far. + -- Jean Cocteau +%% +Tact is the ability to tell a man he has +an open mind when he has a hole in his head. +%% +Tact is the art of making a point without making an enemy. +%% +Take a lesson from the whale; the only time +he gets speared is when he raises to spout. +%% +Take a look around you, tell me what you see, +A girl who thinks she's ordinary lookin' she has got the key. +If you can get close enough to look into her eyes +There's something special right behind the bitterness she hides. + And you're fair game, + You never know what she'll decide, you're fair game, + Just relax, enjoy the ride. +Find a way to reach her, make yourself a fool, +But do it with a little class, disregard the rules. +'Cause this one knows the bottom line, couldn't get a date. +The ugly duckling striking back, and she'll decide her fate. + (chorus) +The ones you never notice are the ones you have to watch. +She's pleasant and she's friendly while she's looking at your crotch. +Try your hand at conversation, gossip is a lie, +And sure enough she'll take you home and make you wanna die. + (chorus) + -- Crosby, Stills, Nash, "Fair Game" +%% +Take an astronaut to launch. +%% +Take care of the luxuries and the +necessities will take care of themselves. + -- L. Long +%% +Take everything in stride. +Trample anyone who gets in your way. +%% +Take it easy, we're in a hurry. +%% +Take my word for it, the silliest woman can manage a clever man, +but it needs a very clever woman to manage a fool. + -- Kipling +%% +Take time to reflect on all the things you have, not as a result of your +merit or hard work or because God or chance or the efforts of other people +have given them to you. +%% +Take what you can use and let the rest go by. + -- Ken Kesey +%% +Take your Senator to lunch this week. +%% +Take your dying with some seriousness, however. +Laughing on the way to your execution is not generally understood +by less-advanced life-forms, and they'll call you crazy. + -- Messiah's Handbook : Reminders for the Advanced Soul +%% +Talk sense to a fool and he calls you foolish. + -- Euripides +%% +Talkers are no good doers. + -- William Shakespeare, "Henry VI" +%% +Talking much about oneself can also be a means to conceal oneself. + -- Friedrich Nietzsche +%% +Tallulah Bankhead barged down the +Nile last night as Cleopatra and sank. + -- John Mason Brown, drama critic +%% +Tan me hide when I'm dead, Fred, +Tan me hide when I'm dead. +So we tanned his hide when he died, Clyde, +It's hanging there on the shed. + +All together now... + Tie me kangaroo down, sport, + Tie me kangaroo down. + Tie me kangaroo down, sport, + Tie me kangaroo down. +%% +Tart words make no friends; a spoonful of honey +will catch more flies than a gallon of vinegar. + -- B. Franklin +%% +Tax reform means "Don't tax you, don't +tax me, tax that fellow behind the tree." + -- Russell Long +%% +Taxes are not levied for the benefit of the taxed. +%% +Teach children to be polite and courteous in the home, and, +when they grow up, they won't be able to edge a car onto a freeway. +%% +Teachers have class. +%% +Teamwork is essential -- it allows you to blame someone else. +%% +Technicality, n. In an English court a man named Home was tried for +slander in having accused a neighbor of murder. His exact words were: +"Sir Thomas Holt hath taken a cleaver and stricken his cook upon the +head, so that one side of his head fell on one shoulder and the other +side upon the other shoulder." The defendant was acquitted by +instruction of the court, the learned judges holding that the words did +not charge murder, for they did not affirm the death of the cook, that +being only an inference. + -- Ambrose Bierce, "The Devil's Dictionary" +%% +Technological progress has merely provided us +with more efficient means for going backwards. + -- Aldous Huxley +%% +Technology is dominated by those who manage what they do not understand. +%% +Tehee quod she, and clapte the wyndow to. + -- Geoffrey Chaucer +%% +Telephone books are like dictionaries -- if you know the answer before +you look it up, you can eventually reaffirm what you thought you knew +but weren't sure. But if you're searching for something you don't +already know, your fingers could walk themselves to death. + -- Erma Bombeck +%% +Television is now so desperately hungry for material +that it is scraping the top of the barrel. + -- Gore Vidal +%% +Television only proves that people will look at anything -- +rather than each other. +%% +Tell a man there are 300 billion stars in the universe and he'll +believe you. Tell him a bench has wet paint on it and he'll have +to touch to be sure. +%% +Tell me what to think!!! +%% +Telling the truth to people who misunderstand you is generally +promoting a falsehood, isn't it? + -- A. Hope +%% +Tempt me with a spoon! +%% +Tempt not a desperate man. + -- William Shakespeare, "Romeo and Juliet" +%% +Ten persons who speak make more noise than ten thousand who are silent. + -- Napoleon I +%% +Ten years of rejection slips is nature's +way of telling you to stop writing. + -- R. Geis +%% +"Terence, this is stupid stuff: +You eat your victuals fast enough; +There can't be much amiss, 'tis clear, +To see the rate you drink your beer. +But oh, good Lord, the verse you make, +It gives a chap the belly-ache. +The cow, the old cow, she is dead; +It sleeps well the horned head: +We poor lads, 'tis our turn now +To hear such tunes as killed the cow. +Pretty friendship 'tis to rhyme +Your friends to death before their time. +Moping, melancholy mad: +Come, pipe a tune to dance to, lad." + -- A.E. Housman +%% +Term, holidays, term, holidays, till we leave +school, and then work, work, work till we die. + -- C.S. Lewis +%% +Tertullian was born in Carthage somewhere about 160 A.D. He was a pagan, +and he abandoned himself to the lascivious life of his city until about +his 35th year, when he became a Christian. [...] To him is ascribed the +sublime confession: Credo quia absurdum est (I believe because it is absurd). +This does not altogether accord with historical fact, for he merely said: + "And the Son of God died, which is immediately credible because it + is absurd. And buried he rose again, which is certain because it + is impossible." +Thanks to the acuteness of his mind, he saw through the poverty of +philosophical and Gnostic knowledge, and contemptuously rejected it. + -- C.G. Jung, "Psychological Types" + [Teruillian was one of the founders of the Catholic Church. Ed.] +%% +Test for paraquat: + Take amount of grass used in one joint, and wash in 5 cc's + of water, agitating gently for 15 minutes. Strain out leaves, + leaving a brownish-yellow solution. Add 100 mg each of sodium + bicarbonate and sodium dithionite. If paraquat is present, + the solution will turn blue-green. +%% +Test-tube babies shouldn't throw stones. +%% +Texas A&M football coach Jackie Sherrill went to the office of the Dean +of Academics because he was concerned about his players' mental abilities. +"My players are just too stupid for me to deal with them", he told the +unbelieving dean. At this point, one of his players happened to enter +the dean's office. "Let me show you what I mean", said Sherrill, and he +told the player to run over to his office to see if he was in. "OK, Coach", +the player replied, and was off. "See what I mean?" Sherrill asked. +"Yeah", replied the dean. "He could have just picked up this phone and +called you from here." +%% +Texas is Hell on woman and horses. + -- Wayne Oakes +%% +Thank you for observing all safety precautions. +%% +That Xanthippe's husband should have become so great a philosopher is +remarkable. Amid all the scolding, to be able to think! But he could not +write: that was impossible. Socrates has not left us a single book. + -- Heine +%% +That does not compute. +%% +That money talks, +I'll not deny, +I heard it once, +It said "Good-bye. + -- Richard Armour +%% +That must be wonderful: I don't understand it at all. + -- Moliere +%% +That segment of the community with which one has the greatest +sympathy as a liberal, inevitably turns out to be one of the most +narrow-minded and bigoted segments of the community. +%% +That that is is that that is not is not. +%% +That, that is, is. +That, that is not, is not. +That, that is, is not that, that is not. +That, that is not, is not that, that is. +%% +That which is not good for the swarm, neither is it good for the bee. +%% +That woman speaks eight languages and can't say "no" in any of them. + -- Dorothy Parker +%% +That's always the way when you discover +something new; everyone thinks you're crazy. + -- Evelyn E. Smith +%% +That's life for you, said McDunn. Someone always waiting for someone +who never comes home. Always someone loving something more than that +thing loves them. And after awhile you want to destroy whatever that +thing is, so it can't hurt you no more. + -- R. Bradbury, "The Fog Horn" +%% +That's life. + What's life? +A magazine. + How much does it cost? +Two-fifty. + I only have a dollar. +That's life. +%% +That's no moon... + -- Obi-wan Kenobi +%% +That's one small step for a man; one giant leap for mankind. + -- Neil Armstrong +%% +That's the true harbinger of spring, not crocuses or swallows +returning to Capistrano, but the sound of a bat on a ball. + -- Bill Veeck +%% +That's what she said. +%% +The White Rabbit put on his spectacles. + "Where shall I begin, please your Majesty ?" he asked. + "Begin at the beginning,", the King said, very gravely, +"and go on till you come to the end: then stop." + -- Lewis Carroll +%% +The greatest disloyalty one can offer to great pioneers +is to refuse to move an inch from where they stood. +%% +The key elements in human thinking are +not numbers but labels of fuzzy sets. + -- L. Zadeh +%% +The 11 is for people with the pride of a 10 and the pocketbook of an 8. + -- R.B. Greenberg +%% +The 357.73 Theory -- + Auditors always reject expense accounts + with a bottom line divisible by 5. +%% +The Abrams' Principle: + The shortest distance between two points is off the wall. +%% +The Almighty in His infinite wisdom did not see +fit to create Frenchmen in the image of Englishmen. + -- Winston Churchill, 1942 +%% +The American system of ours, call it Americanism, call it Capitalism, +call it what you like, gives each and every one of us a great +opportunity if we only seize it with both hands and make the most of it. + -- Al Capone +%% +The Analytical Engine weaves Algebraical patterns +just as the Jacquard loom weaves flowers and leaves. + -- Ada Augusta, Countess of Lovelace, the first programmer +%% +The Angels want to wear my red shoes. + -- E. Costello +%% +The Army has carried the American ... ideal to its logical conclusion. +Not only do they prohibit discrimination on the grounds of race, creed +and color, but also on ability. + -- T. Lehrer +%% +The Army needs leaders the way a foot needs a big toe. + -- Bill Murray +%% +The Bible on letters of reference: + + Are we beginning all over again to produce our credentials? Do +we, like some people, need letters of introduction to you, or from you? +No, you are all the letter we need, a letter written on your heart; any +man can see it for what it is and read it for himself. + -- 2 Corinthians 3:1-2, New English translation +%% +The Bible says that woman was the last thing God made. +Evidently He made her on Saturday night. She reveals his fatigue. + -- Dumas +%% +The Bird of Time has but a little way to fly ... +and the bird is on the wing. + -- Omar Khayyam +%% +The Briggs - Chase Law of Program Development: + To determine how long it will take to write and debug a + program, take your best estimate, multiply that by two, add + one, and convert to the next higher units. +%% +The British are coming! The British are coming! +%% +The Buddha, the Godhead, resides quite as comfortably in the circuits of a +digital computer or the gears of a cycle transmission as he does at the top +of a mountain or in the petals of a flower. To think otherwise is to demean +the Buddha -- which is to demean oneself. + -- Robert Pirsig, "Zen and the Art of Motorcycle Maintenance" +%% +The Commandments of the EE: + +1: Beware of lightning that lurketh in an uncharged condenser + lest it cause thee to bounce upon thy buttocks in a most + embarrassing manner. +2: Cause thou the switch that supplieth large quantities of juice to + be opened and thusly tagged, that thy days may be long in this + earthly vale of tears. +3: Prove to thyself that all circuits that radiateth, and upon + which the worketh, are grounded and thusly tagged lest they lift + thee to a radio frequency potential and causeth thee to make like + a radiator too. +4: Tarry thou not amongst these fools that engage in intentional + shocks for they are not long for this world and are surely + unbelievers. +%% +The Commandments of the EE: + +5: Take care that thou useth the proper method when thou takest the + measures of high-voltage circuits too, that thou dost not incinerate + both thee and thy test meter, for verily, though thou has no company + property number and can be easily surveyed, the test meter has + one and, as a consequence, bringeth much woe unto a purchasing agent. +6: Take care that thou tamperest not with interlocks and safety devices, + for this incurreth the wrath of the chief electrician and bring + the fury of the engineers on his head. +7: Work thou not on energized equipment for if thou doest so, thy + friends will surely be buying beers for thy widow and consoling + her in certain ways not generally acceptable to thee. +8: Verily, verily I say unto thee, never service equipment alone, + for electrical cooking is a slow process and thou might sizzle in + thy own fat upon a hot circuit for hours on end before thy maker + sees fit to end thy misery and drag thee into his fold. +%% +The Commandments of the EE: + +9: Trifle thee not with radioactive tubes and substances lest thou + commence to glow in the dark like a lightning bug, and thy wife be + frustrated and have not further use for thee except for thy wages. +10: Commit thou to memory all the words of the prophets which are + written down in thy Bible which is the National Electrical Code, + and giveth out with the straight dope and consoleth thee when + thou hast suffered a ream job by the chief electrician. +11: When thou muckest about with a device in an unthinking and/or + unknowing manner, thou shalt keep one hand in thy pocket. Better + that thou shouldest keep both hands in thy pockets than + experimentally determine the electrical potential of an + innocent-seeming device. +%% +The Crown is full of it! + -- Nate Harris, 1775 +%% +The English have no respect for their language, +and will not teach their children to speak it. + -- G.B. Shaw +%% +The Fifth Rule: + You have taken yourself too seriously. +%% +The Force is what holds everything together. +It has its dark side, and it has its light side. +It's sort of like cosmic duct tape. +%% +The [Ford Foundation] is a large body of money +completely surrounded by people who want some. + -- Dwight MacDonald +%% +[The French Riviera is] a sunny place for shady people. + -- Somerset Maugham +%% +The Golden Rule of Arts and Sciences: + He who has the gold makes the rules. +%% + The Guy on the Right Doesn't Stand a Chance +The guy on the right has the Osborne 1, a fully functional computer system +in a portable package the size of a briefcase. The guy on the left has an +Uzi submachine gun concealed in his attache case. Also in the case are four +fully loaded, 32-round clips of 125-grain 9mm ammunition. The owner of the +Uzi is going to get more tactical firepower delivered -- and delivered on +target -- in less time, and with less effort. All for $795. It's inevitable. +If you're going up against some guy with an Osborne 1 -- or any personal +computer -- he's the one who's in trouble. One round from an Uzi can zip +through ten inches of solid pine wood, so you can imagine what it will do +to structural foam acrylic and sheet aluminum. In fact, detachable magazines +for the Uzi are available in 25-, 32-, and 40-round capacities, so you can +take out an entire office full of Apple II or IBM Personal Computers tied +into Ethernet or other local-area networks. What about the new 16-bit +computers, like the Lisa and Fortune? Even with the Winchester backup, +they're no match for the Uzi. One quick burst and they'll find out what +Unix means. Make your commanding officer proud. Get an Uzi -- and come home +a winner in the fight for office automatic weapons. + -- "InfoWorld", June, 1984 +%% +The Heineken Uncertainty Principle: + You can never be sure how many beers you had last night. +%% +The History of every major Galactic Civilization tends to pass through +three distinct and recognizable phases, those of Survival, Inquiry, and +Sophistication, otherwise known as the How, Why, and Where phases. For +instance, the first phase is characterized by the question "How can we +eat?" the second by "Why do we eat?" and the third by "Where shall we +have lunch?". + -- Hitchhiker's Guide to the Galaxy +%% + The Hitchhiker's Guide to the Galaxy has a few things to say on +the subject of towels. + Most importantly, a towel has immense psychological value. For +some reason, if a non-hitchhiker discovers that a hitchhiker has his towel +with him, he will automatically assume that he is also in possession of a +toothbrush, washcloth, flask, gnat spray, space suit, etc., etc. Furthermore, +the non-hitchhiker will then happily lend the hitchhiker any of these or +a dozen other items that he may have "lost". After all, any man who can +hitch the length and breadth of the Galaxy, struggle against terrible odds, +win through and still know where his towel is, is clearly a man to be +reckoned with. +%% + The Hitchiker's Guide to the Galaxy has a few things to say on +the subject of towels. + A towel, it says, is about the most massively useful thing an +interstellar hitchhiker can have. Partly it has great practical value. +You can wrap it around you for warmth as you bound across the cold moons +of Jaglan Beta; you can lie on it on the brilliant marble-sanded beaches +of Santraginus V ... use it to sail a miniraft down the slow heavy River +Moth; wave your towel in emergencies, and, of course, dry yourself off +with it if it still seems to be clean enough. +%% +The IBM 2250 is impressive ... +if you compare it with a system selling for a tenth its price. + -- D. Cohen +%% +The IQ of the group is the lowest IQ of a member of +the group divided by the number of people in the group. +%% +The Junior God now heads the roll +In the list of heaven's peers; +He sits in the House of High Control, +And he regulates the spheres. +Yet does he wonder, do you suppose, +If, even in gods divine, +The best and wisest may not be those +Who have wallowed awhile with the swine? + -- R.W. Service +%% +The Kennedy Constant: + Don't get mad -- get even. +%% +The Killer Ducks are coming!!! +%% +The Kosher Dill was invented in 1723 by Joe Kosher and Sam Dill. It is +the single most popular pickle variety today, enjoyed throughout the free +world by man, woman and child alike. An astounding 350 billion kosher +dills are eaten each year, averaging out to almost 1/4 pickle per person +per day. New York Times food critic Mimi Sheraton says "The kosher dill +really changed my life. I used to enjoy eating McDonald's hamburgers and +drinking Iron City Lite, and then I encountered the kosher dill pickle. +I realized that there was far more to haute cuisine then I'd ever imagined. +And now, just look at me." +%% +The Law, in its majestic equality, forbids the rich, as well as the +poor, to sleep under the bridges, to beg in the streets, and to steal +bread. + -- Anatole France +%% +The Law of Probable Dispersal: + That which hits the fan will not be evenly distributed. +%% +The Law of the Letter: + The best way to inspire fresh thoughts is to seal the envelope. +%% +The Law of the Perversity of Nature: + You cannot determine beforehand which side of the bread to butter. +%% +The Lord gave us farmers two strong hands so we +could grab as much as we could with both of them. + -- Major Major's father +%% +The Marines: + The few, the proud, the dead on the beach. +%% +The Marines: + The few, the proud, the not very bright. +%% + The Martian landed his saucer in Manhattan, and immediately upon +emerging was approached by a panhandler. "Mister," said the man, "can I +have a quarter?" + The Martian asked, "What's a quarter?" + The panhandler thought a minute, brightened, then said, "You're +right! Can I have a dollar?" +%% +The Modelski Chain Rule: +1: Look intently at the problem for several minutes. Scratch your + head at 20-30 second intervals. Try solving the problem on your + Hewlett-Packard. +2: Failing this, look around at the class. Select a particularly + bright-looking individual. +3: Procure a large chain. +4: Walk over to the selected student and threaten to beat him severely + with the chain unless he gives you the answer to the problem. + Generally, he will. It may also be a good idea to give him a sound + thrashing anyway, just to show you mean business. +%% +The Moral Majority is neither. +%% +The Moving Finger writes; and, having writ, + Moves on: nor all they Piety nor Wit +Shall lure it back to cancel half a Line, + Nor all thy Tears wash out a Word of it. +%% +The New Testament offers the basis for modern computer coding theory, +in the form of an affirmation of the binary number system. + + But let your communication be Yea, yea; nay, nay: + for whatsoever is more than these cometh of evil. + + -- Matthew 5:37 +%% +The Official MBA Handbook on business cards: + + Avoid overly pretentious job titles such as "Lord of the + Realm, Defender of the Faith, Emperor of India" or "Director + of Corporate Planning." +%% +The Official MBA Handbook on doing company business on an airplane: + + Do not work openly on top-secret company cost documents unless + you have previously ascertained that the passenger next to you + is blind, a rock musician on mood-ameliorating drugs, or the + unfortunate possessor of a forty-seventh chromosome. +%% +The Official MBA Handbook on the use of sunlamps: + Use a sunlamp only on weekends. That way, if the office wise guy + remarks on the sudden appearance of your tan, you can fabricate + some story about a sun-stroked weekend at some island Shangri-La + like Caneel Bay. Nothing is more transparent than leaving the + office at 11:45 on a Tuesday night, only to return an Aztec sun + god at 8:15 the next morning. +%% +The Pig, if I am not mistaken, +Gives us ham and pork and Bacon. +Let others think his heart is big, +I think it stupid of the Pig. +%% +The Poems, all three hundred of them, +may be summed up in one of their phrases: +"Let our thoughts be correct". + -- Confucius +%% +The Preacher, the Politician, the Teacher, + Were each of them once a kiddie. +A child, indeed, is a wonderful creature. + Do I want one? God Forbiddie! + -- Ogden Nash +%% +The Public is merely a multiplied "me." + -- Mark Twain +%% +The Rabbits The Cow +Here is a verse about rabbits The cow is of the bovine ilk; +That doesn't mention their habits. One end is moo, the other, milk. + -- Ogden Nash +%% +The Ranger isn't gonna like it, Yogi. +%% +The Reverend Henry Ward Beecher +Called a hen a most elegant creature. + The hen, pleased with that, + Laid an egg in his hat -- +And thus did the hen reward Beecher. + -- Oliver Wendell Holmes +%% +The Roman Rule + The one who says it cannot be done should never interrupt the + one who is doing it. +%% +The Russians have put a small ball up in the air. +That does not raise my apprehensions one iota. + -- Dwight D. Eisenhower +%% +The Schwine-Kitzenger Institute study +of 47 men over the age of 100 showed that all had these things in common: + 1) They all had moderate appetites. + 2) They all came from middle class homes. + 3) All but two of them were dead. +%% +The Shuttle is now going five times the sound of speed. + -- Dan Rather, first landing of Columbia +%% + The Split-Atom Blues +Gimme Twinkies, gimme wine, + Gimme jeans by Calvin Kline... +But if you split those atoms fine, + Mama keep 'em off those genes of mine! +Gimme zits, take my dough, + Gimme arsenic in my jelly roll... +Call the devil and sell my soul, + But Mama keep dem atoms whole! + -- Milo Bloom +%% +The Supreme Court does it with all deliberate speed. +%% +The Third Law of Photography: + If you did manage to get any good shots, they will be ruined + when someone inadvertently opens the darkroom door and all of + the dark leaks out. +%% +The Thought Police are here. They've come +To put you under cardiac arrest. +And as they drag you through the door +They tell you that you've failed the test. + -- Buggles, "Living in the Plastic Age" +%% +The Tree of Learning bears the noblest fruit, but noble fruit tastes bad. +%% +The USA is so enormous, and so numerous are its schools, colleges and +religious seminaries, many devoted to special religious beliefs ranging +from the unorthodox to the dotty, that we can hardly wonder at its +yielding a more bounteous harvest of gobbledegook than the rest of the +world put together. + -- Sir Peter Medawar +%% +The United States Army; +194 years of proud service, unhampered by progress. +%% +The Universe is populated by stable things. + -- Richard Dawkins +%% +The University of California Bears announced the signing of Reggie +Philbin to a letter of intent to attend Cal next Fall. Philbin is +said to make up for no talent by cheating well. Says Philbin of +his decision to attend Cal, "I'm in it for the free ride." +%% +The VFW represents many who died to give this country a second chance +to make it what it is supposed to be -- God's guest house on earth. + -- John Wayne +%% +The absence of labels [in ECL] is probably a good thing. + -- T. Cheatham +%% +The absurd is the essential concept and the first truth. + -- A. Camus +%% +The abuse of greatness is when it disjoins remorse from power. + -- William Shakespeare, "Julius Caesar" +%% +The adjective is the banana peel of the parts of speech. + -- Clifton Fadiman +%% +The adjuration to be "normal" seems shockingly repellent to me; I see neither +hope nor comfort in sinking to that low level. I think it is ignorance that +makes people think of abnormality only with horror and allows them to remain +undismayed at the proximity of "normal" to average and mediocre. For surely +anyone who achieves anything is, essentially, abnormal. + -- Dr. Karl Menninger, "The Human Mind", 1930 +%% +The aim of science is to seek the simplest explanations of complex +facts. Seek simplicity and distrust it. + -- Whitehead. +%% +The anger of a woman is the greatest evil +with which you can threaten your enemies. + -- Bonnard +%% +The angry man always thinks he can do more than he can. + -- Albertano of Brescia +%% +The annual meeting of the "You Have To Listen To Experience" Club is now in +session. Our Achievement Awards this year are in the fields of publishing, +advertising and industry. For best consistent contribution in the field of +publishing our award goes to editor, R.L.K., [...] for his unrivalled alle- +giance without variation to the statement: "Personally I'd love to do it, +we'd ALL love to do it. But we're not going to do it. It's not the kind of +book our house knows how to handle." Our superior performance award in the +field of advertising goes to media executive, E.L.M., [...] for the continu- +ally creative use of the old favorite: "I think what you've got here could be +very exciting. Why not give it one more try based on the approach I've out- +lined and see if you can come up with something fresh." Our final award for +courageous holding action in the field of industry goes to supervisor, R.S., +[...] for her unyielding grip on "I don't care if they fire me, I've been +arguing for a new approach for YEARS but are we SURE that this is the right +time--" I would like to conclude this meeting with a verse written specially +for our prospectus by our founding president fifty years ago -- and now, as +then, fully expressive of the emotion most close to all our hearts -- + Treat freshness as a youthful quirk, + And dare not stray to ideas new, + For if t'were tried they might e'en work + And for a living what woulds't we do? +%% +The answer to the Ultimate Question of Life, the Universe, and +Everything was released with the kind permission of the Amalgamated +Union of Philosophers, Sages, Luminaries, and Other Professional +Thinking Persons. +%% +The attacker must vanquish; the defender need only survive. +%% +The attention span of a computer is only as long as its power cord. +%% +The average individual's position in any hierarchy is a lot like pulling +a dogsled -- there's no real change of scenery except for the lead dog. +%% +The average woman must inevitably view her actual husband with a certain +disdain; he is anything but her ideal. In consequence, she cannot help +feeling that her children are cruelly handicapped by the fact that he is +their father. + -- Mencken +%% +The average woman would rather have beauty than brains, +because the average man can see better than he can think. +%% +The bay-trees in our country are all wither'd +And meteors fright the fixed stars of heaven; +The pale-faced moon looks bloody on the earth +And lean-look'd prophets whisper fearful change. +These signs forerun the death or fall of kings. + -- Wm. Shakespeare, "Richard II" +%% +The best book on programming for the layman is "Alice in Wonderland"; +but that's because it's the best book on anything for the layman. +%% +The best cure for insomnia is to get a lot of sleep. + -- W.C. Fields +%% +The best defense against logic is ignorance. +%% +The best diplomat I know is a fully activated phaser bank. + -- Scotty +%% +The best equipment for your work is, of course, the most expensive. +However, your neighbor is always wasting money that should be yours +by judging things by their price. +%% +The best laid plans of mice and men are usually about equal. + -- Blair +%% +The best man for the job is often a woman. +%% +The best portion of a good man's life, his little, +nameless, unremembered acts of kindness and love. + -- Wordsworth +%% +The best prophet of the future is the past. +%% +The best thing about growing older is that it takes such a long time. +%% + "The best thing for being sad," replied Merlin, beginning to puff +and blow, "is to learn something. That's the only thing that never fails. +You may grow old and trembling in your anatomies, you may lie awake at +night listening to the disorder of your veins, you may miss your only love, +you may see the world about you devastated by evil lunatics, or know your +honour trampled in the sewers of baser minds. There is only one thing for +it then -- to learn. Learn why the world wags and what wags it. That is +the only thing which the mind can never exhaust, never alienate, never be +tortured by, never fear or distrust, and never dream of regretting. Learning +is the only thing for you. Look what a lot of things there are to learn." + -- T.H. White, "The Once and Future King" +%% +The best things in life are for a fee. +%% +The best way to avoid responsibility is +to say, "I've got responsibilities." +%% +The best way to get rid of worries is to let them die of neglect. +%% +The best way to keep your friends is not to give them away. +%% +The best way to preserve a right is to exercise it, +and the right to smoke is a right worth dying for. +%% +The best you get is an even break. + -- Franklin Adams +%% +The better part of valor is discretion. + -- William Shakespeare, "Henry IV" +%% +The big question is why in the course of evolution the males +permitted themselves to be so totally eclipsed by the females. +Why do they tolerate this total subservience, this wretched +existence as outcasts who are hungry all the time? +%% +The bigger they are, the harder they hit. +%% +The biggest difference between time +and space is that you can't reuse time. + -- Merrick Furst +%% +The biggest mistake you can make is to +believe that you are working for someone else. +%% + The birds are singing, the flowers are budding, and it is time +for Miss Manners to tell young lovers to stop necking in public. + It's not that Miss Manners is immune to romance. Miss Manners +has been known to squeeze a gentleman's arm while being helped over a +curb, and, in her wild youth, even to press a dainty slipper against a +foot or two under the dinner table. Miss Manners also believes that the +sight of people strolling hand in hand or arm in arm or arm in hand +dresses up a city considerably more than the more familiar sight of +people shaking umbrellas at one another. What Miss Manners objects to +is the kind of activity that frightens the horses on the street... +%% +The brain is a wonderful organ; it starts working the moment +you get up in the morning, and does not stop until you get to work. +%% +The broad mass of a nation... will more easily +fall victim to a big lie than to a small one. + -- Adolf Hitler, "Mein Kampf" +%% +The bustard's a remarkable fowl +With surely no reason to growl + He escapes what would be + Illegitimacy +By the grace of a fortunate vowel. +%% +The cart has no place where a fifth wheel could be used. + -- Herbert von Fritzlar +%% +The chicken that clucks the loudest is the one +most likely to show up at the steam fitters picnic. +%% +The chief cause of problems is solutions. +%% +The church saves sinners, but science +seeks to stop their manufacture. + -- Elbert Hubbard +%% +The climate of Bombay is such that +its inhabitants have to live elsewhere. +%% +The closest to perfection a person ever comes +is when he fills out a job application form. + -- Stanley J. Randall +%% +The coast was clear. + -- Lope de Vega +%% +The college graduate is presented with a +sheepskin to cover his intellectual nakedness. + -- Robert M. Hutchins +%% +The common cormorant, or shag, lays eggs inside a paper bag. +%% +The computer is to the information industry roughly what the +central power station is to the electrical industry. + -- Peter Drucker +%% +The computing field is always in need of new cliches. + -- Alan Perlis +%% +The concept seems to be clear by now. It has been +defined several times by examples of what it is not. +%% +The control of the production of wealth +is the control of human life itself. + -- Hilaire Belloc +%% +The correct way to punctuate a sentence that starts: "Of course it is +none of my business, but --" is to place a period after the word "but." +Don't use excessive force in supplying such a moron with a period. +Cutting his throat is only a momentary pleasure and is bound to get +you talked about. + -- Lazarus Long +%% +The cost of feathers has risen, even down is up! +%% +The cost of living has gone up, another buck a fifth. +%% +The cost of living hasn't affected its popularity. +%% +The cost of living is going up, and the chance of living is going down. +%% +The courtroom was pregnant (pun intended) with anxious silence as the +judge solemnly considered his verdict in the paternity suit before him. +Suddenly, he reached into the folds of his robes, drew out a cigar and +cermoniously handed it to the defendant. + "Congratulations!" said the jurist. "You have just become a +father!" +%% +The cow is nothing but a machine which +makes grass fit for us people to eat. + -- John McNulty +%% +The cruelest of creatures' the crab +With claws that can pinch you or stab, + And then when you dine + On crab and white wine +It gets you as well with the tab. +%% +The days are all empty and the nights are unreal. +%% +The days just prior to marriage are like +a snappy introduction to a tedious book. +%% +The day-to-day travails of the IBM programmer are so amusing to most of us +who are fortunate enough never to have been one -- like watching Charlie +Chaplin trying to cook a shoe. +%% +The debate rages on: Is PL/I Bachtrian or Dromedary? +%% +The decision doesn't have to be logical; it was unanimous. +%% +The degree of civilization in a society +can be judged by entering its prisons. + -- F. Dostoyevski +%% +The degree of technical confidence is inversely +proportional to the level of management. +%% +The descent to Hades is the same from every place. + -- Anaxagoras +%% +The devil can cite Scripture for his purpose. + -- William Shakespeare, "The Merchant of Venice" +%% +The devil finds work for idle circuits to do. +%% +The die is cast. + -- Gaius Julius Caesar +%% +The difference between a Miracle and a Fact is +exactly the difference between a mermaid and a seal. + -- Mark Twain +%% +The difference between a career and a job is about 20 hours a week. +%% +The difference between a good haircut and a bad one is seven days. +%% +The difference between a misfortune and a calamity? If Gladstone fell into +the Thames, it would be a misfortune. But if someone dragged him out again, +it would be a calamity. + -- Benjamin Disraeli +%% +The difference between common-sense and paranoia is that common-sense is +thinking everyone is out to get you. That's normal -- they are. Paranoia +is thinking that they're conspiring. + -- J. Kegler +%% +The difference between legal separation and divorce is +that legal separation gives the man time to hide his money. +%% +The difference between science and the fuzzy subjects is that science +requires reasoning while those other subjects merely require scholarship. + -- Robert Heinlein +%% +The difference between the right word and the almost right word +is the difference between lightning and the lightning bug. + -- Mark Twain +%% +The difference between this place and yogurt +is that yogurt has a live culture. +%% +The difference between us is not very far, +cruising for burgers in daddy's new car. +%% +The difficult we do today; the impossible takes a little longer. +%% +The discerning person is always at a disadvantage. +%% +The disks are getting full; purge a file today. +%% +The distinction between Freedom and Liberty is not accurately known; +naturalists have been unable to find a living specimen of either. + -- Ambrose Bierce +%% +The distinction between true and false appears to become +increasingly blurred by... the pollution of the language. + -- Arne Tiselius +%% +The door is the key. +%% +The duck hunter trained his retriever to walk on water. Eager to show off +this amazing accomplishment, he asked a friend to go along on his next +hunting trip. Saying nothing, he fired his first shot and, as the duck fell, +the dog walked on the surface of the water, retrieved the duck and returned +it to his master. + "Notice anything?" the owner asked eagerly. + "Yes," said his friend, "I see that fool dog of yours can't swim." +%% +The early bird gets the coffee left over from the night before. +%% +The early worm gets the bird. +%% +The early worm gets the late bird. +%% +The earth is like a tiny grain of sand, only much, much heavier. +%% +The end of labor is to gain leisure. +%% +The end of the world will occur at three p.m., +this Friday, with symposium to follow. +%% +The ends justify the means. + -- after Matthew Prior +%% +The eternal feminine draws us upward. + -- Goethe +%% +The eyes of Texas are upon you, +All the livelong day; +The eyes of Texas are upon you, +You cannot get away; +Do not think you can escape them +From night 'til early in the morn; +The eyes of Texas are upon you +'Til Gabriel blows his horn. + -- University of Texas' school song +%% +The eyes of taxes are upon you. +%% +The fact that it works is immaterial. + -- L. Ogborn +%% +The fact that people are poor or discriminated against doesn't necessarily +endow them with any special qualities of justice, nobility, charity or +compassion. + -- Saul Alinsky +%% + The famous Nell Gwynn, stepping one day from a house where she had +made a short visit into her coach, saw a great crowd assembled, and her +footman all bloody and dirty; the fellow being asked by his mistress, the +reason for his being in that condition, answered, "I have been fighting, +madam, with an impudent rascal who called your ladyship a whore." + "You blockhead," replied Mrs. Gywnn, "at this rate you must fight +every day of your life; why, you fool, all the world knows it." + "Do they?" cries the fellow, in a muttering voice, after he had shut +the coach door, "they shan't call me a whore's footman for all that." + -- Henry Fielding, "Tom Jones" +%% +The famous politician was trying to save both his faces. +%% +The farther you go, the less you know. + -- Lao Tsu, "Tao Te Ching" +%% +The fashion wears out more apparel than the man. + -- William Shakespeare, "Much Ado About Nothing" +%% +The feeling persists that no one can simultaneously be a respectable writer +and understand how a refrigerator works, just as no gentleman wears a brown +suit in the city. Colleges may be to blame. English majors are encouraged, +I know, to hate chemistry and physics, and to be proud because they are not +dull and creepy and humorless and war-oriented like the engineers across the +quad. And our most impressive critics have commonly been such English majors, +and they are squeamish about technology to this very day. So it is natural +for them to despise science fiction. + -- Kurt Vonnegut Jr., "Science Fiction" +%% +The finest eloquence is that which gets things done. +%% +The first Great Steward, Parrafin the Climber, was employed in King +Chloroplast's kitchen as second scullery boy when the old King met a tragic +death. He apparently fell backward by accident on a dozen salad forks. +Simultaneously the true heir, his son Carotene, mysteriously fled the city, +complaining of some sort of plot and a lot of threatening notes left on his +breakfast tray. At the time, this looked suspicious what with his father's +death, and Carotene was suspected of foul play. Then the rest of the King's +relatives began to drop dead one after the other in an odd fashion. Some +were found strangled with dishrags and some succumbed to food poisoning. A +few were found drowned in the soup vats, and one was attacked by assailants +unknown and beaten to death with a pot roast. At least three appear to have +thrown themselves backward on salad forks, perhaps in a noble gesture of +grief over the King's untimely end. Finally there was no one left in Minas +Troney who was either eligible or willing to wear the accursed crown, and +the rule of Twodor was up for grabs. The scullery slave Parrafin bravely +accepted the Stewardship of Twodor until that day when a lineal descendant +of Carotene's returns to reclaim his rightful throne, conquer Twodor's +enemies, and revamp the postal system. + -- Bored of the Rings, "Harvard Lampoon" +%% +The first duty of a revolutionary is to get away with it. + -- Abbie Hoffman +%% +The first guy that rats gets a belly-full +of slugs in the head. Understand? + -- Joey Glimco +%% +The first myth of management is that it exists. +%% +The first requisite for immortality is death. + -- Stanislaw Lem +%% +The first riddle I ever heard, one familiar to almost every Jewish child, +was propounded to me by my father: + + "What is it that hangs on the wall, is green, wet -- and whistles?" +I knit my brow and thought and thought, and in final perplexity gave up. + "A herring," said my father. + "A herring," I echoed. "A herring doesn't hang on the wall!" + "So hang it there." + "But a herring isn't green!" I protested. + "Paint it." + "But a herring isn't wet." + "If its just painted it's still wet." + "But -- " I sputtered, summoning all my outrage, + "a herring doesn't whistle!!" + "Right, " smiled my father. "I just put that in to make it hard." + -- Leo Rosten +%% +The first rule of intelligent tinkering is to save all the parts. + -- Ehrlich +%% +The first thing I do in the morning +is brush my teeth and sharpen my tongue. + -- D. Parker +%% +The first thing we do, let's kill all the lawyers. + -- Wm. Shakespeare, "Henry VI", Part IV +%% +The first version always gets thrown away. +%% +The following statement is not true. +The previous statement is true. +%% +The forest is safe because a lion lives therein and the lion is safe +because it lives in a forest. Likewise the friendship of persons +rests on mutual help. + -- Laukikanyay. +%% +The fortune program is supported, in part, by user contributions +and by a major grant from the National Endowment for the Inanities. +%% +The future is a myth created by insurance +salesmen and high school counselors. +%% +The future is a race between education and catastrophe. + -- H.G. Wells +%% +The future isn't what it used to be. (It never was.) +%% +The future lies ahead. +%% +The future not being born, my friend, +we will abstain from baptizing it. + -- George Meredith +%% +The garden is in mourning; +The rain falls cool among the flowers. +Summer shivers quietly +On its way towards its end. + +Golden leaf after leaf +Falls from the tall acacia. +Summer smiles, astonished, feeble, +In this dying dream of a garden. + +For a long while, yet, in the roses, +She will linger on, yearning for peace, +And slowly +Close her weary eyes. + -- Hermann Hesse, "September" +%% +The generation of random numbers is too important to be left to chance. +%% +The gent who wakes up and finds himself a success hasn't been asleep. +%% +The gentlemen looked one another over with microscopic carelessness. +%% + The geographical center of Boston is in Roxbury. Due north of +the center we find the South End. This is not to be confused with South +Boston which lies directly east from the South End. North of the South +End is East Boston and southwest of East Boston is the North End. +%% +The girl who stoops to conquer usually wears a low-cut dress. +%% +The goal of Computer Science is to build something +that will at least last until we've finished building it. +%% +The goal of science is to build better mousetraps. +The goal of nature is to build better mice. +%% +The gods gave man fire and he invented fire engines. +They gave him love and he invented marriage. +%% +The good life was so elusive +It really got me down +I had to regain some confidence +So I got into camaflouge +%% +The good time is approaching, +The season is at hand. +When the merry click of the two-base lick +Will be heard throughout the land. +The frost still lingers on the earth, and +Budless are the trees. +But the merry ring of the voice of spring +Is borne upon the breeze. + -- Ode to Opening Day, "The Sporting News", 1886 +%% +The government has just completed work on a missile that turned out +to be a bit of a boondoggle; nicknamed "Civil Servant", it won't work +and they can't fire it. +%% +The government was contemplating the dispatch of an expedition to Burma, +with a view to taking Rangoon, and a question arose as to who would be the +fittest general to be sent in command of the expedition. The Cabinet sent +for the Duke of Wellington, and asked his advice. He instantly replied, +"Send Lord Combermere." + "But we have always understood that your Grace thought Lord +Combermere a fool." + "So he is a fool, and a damned fool; but he can take Rangoon." + -- G.W.E. Russell +%% +The grass is always greener on the other side of your sunglasses. +%% +The grave's a fine and private place, +but none, I think, do there embrace. + -- Andrew Marvell +%% +The great question that has never been answered and which I have not +yet been able to answer despite my thirty years of research into the +feminine soul is: WHAT DOES A WOMAN WANT? + -- Sigmund Freud +%% +The greatest griefs are those we cause ourselves. + -- Sophocles +%% +The greatest of faults is to be conscious of none. +%% +The greatest productive force is human selfishness. + -- Robert Heinlein +%% +The greatest remedy for anger is delay. +%% +The hardest part of climbing the ladder of +success is getting through the crowd at the bottom. +%% +The hardest thing in the world to understand is the income tax. + -- Albert Einstein +%% +The hardest thing is to disguise your feelings when +you put a lot of relatives on the train for home. +%% +The health of a democratic society may be measured by the quality +of functions performed by private citizens. + -- Alexis de Tocqueville +%% +The hearing ear is always found close to the speaking tongue, a custom +whereof the memory of man runneth not howsomever to the contrary, nohow. +%% +The heart has its reasons which reason knows nothing of. + -- Blaise Pascal +%% +The heart is wiser than the intellect. +%% +The heaviest object in the world is the +body of the woman you have ceased to love. + -- Marquis de Lac de Clapiers Vauvenargues +%% +The help people need most urgently is +help in admitting that they need help. +%% +The heroic hours of life do not announce their presence by drum and trumpet, +challenging us to be true to ourselves by appeals to the martial spirit that +keeps the blood at heat. Some little, unassuming, unobtrusive choice presents +itself before us slyly and craftily, glib and insinuating, in the modest garb +of innocence. To yield to its blandishments is so easy. The wrong, it seems, +is venial... Then it is that you will be summoned to show the courage of +adventurous youth. + -- Benjamin Cardozo +%% +The history of warfare is similarly subdivided, although here the phases +are Retribution, Anticipation, and Diplomacy. Thus: + +Retribution: + I'm going to kill you because you killed my brother. +Anticipation: + I'm going to kill you because I killed your brother. +Diplomacy: + I'm going to kill my brother and then kill you on the + pretext that your brother did it. +%% +The honeymoon is not actually over until we cease +to stifle our sighs and begin to stifle our yawns. + -- Helen Rowland +%% +The horror... the horror! +%% +The human animal differs from the lesser +primates in his passion for lists of "Ten Best". + -- H. Allen Smith +%% +The human brain is a wonderful thing. It starts working the moment +you are born, and never stops until you stand up to speak in public. +%% +The human mind ordinarily operates at only ten percent of +its capacity -- the rest is overhead for the operating system. +%% +The human race has one really effective weapon, and that is laughter. + -- Mark Twain +%% +The ideal voice for radio may be defined as showing no substance, +no sex, no owner, and a message of importance for every housewife. + -- Harry V. Wade +%% +The ideas of economists and political philosophers, both when they +are right and when they are wrong, are more powerful than is generally +understood. Indeed, the world is ruled by little else. + -- John Maynard Keyes +%% +The idle man does not know what it is to enjoy rest. +%% +The idle mind knows not what it is it wants. + -- Quintus Ennius +%% +The important thing is not to stop questioning. +%% +The important thing to remember about walking on eggs is not to hop. +%% +The individual choice of garnishment of a burger can be an important +point to the consumer in this day when individualism is an increasingly +important thing to people. + -- Donald N. Smith, president of Burger King +%% +The infliction of cruelty with a good conscience is +a delight to moralists. That is why they invented hell. + -- Bertrand Russell +%% +The instruments of science do not in themselves discover truth. And +there are searchings that are not concluded by the coincidence of a +pointer and a mark. + -- Fred Saberhagen, "The Berserker Wars" +%% +The kind of danger people most enjoy is +the kind they can watch from a safe place. +%% +The knowledge that makes us cherish +innocence makes innocence unattainable. + -- Irving Howe +%% +The ladies men admire, I've heard, +Would shudder at a wicked word. +Their candle gives a single light; +They'd rather stay at home at night. +They do not keep awake till three, +Nor read erotic poetry. +They never sanction the impure, +Nor recognize an overture. +They shrink from powders and from paints... +So far, I've had no complaints. + -- Dorothy Parker +%% +The last person who said that (God +rest his soul) lived to regret it. +%% +The last vestiges of the old Republic have been swept away. + -- Governor Tarkin +%% +The less time planning, the more time programming. +%% +The life which is unexamined is not worth living. + -- Plato +%% +The light at the end of the tunnel is the headlight of an approaching train. +%% +The light of a hundred stars does not equal the light of the moon. +%% +The limerick is furtive and mean; +You must keep her in close quarantine, + Or she sneaks to the slums + And promptly becomes +Disorderly, drunk, and obscene. + -- Morris Bishop +%% +The lion and the calf shall lie down +together but the calf won't get much sleep. + -- Woody Allen +%% +The little girl expects no declaration of tenderness from her doll. +She loves it -- and that's all. It is thus that we should love. + -- DeGourmont +%% +The little pieces of my life I give to you, +with love, to make a quilt to keep away the cold. +%% +The `loner' may be respected, but he is always resented by his colleagues, +for he seems to be passing a critical judgment on them, when he may be +simply making a limiting statement about himself. + -- Sidney Harris +%% +The longer I am out of office, the more infallible I appear to myself. + -- Henry Kissinger +%% +The longest part of the journey is said to be the passing of the gate. + -- Marcus Terentius Varro +%% +The luck that is ordained for you will be coveted by others. +%% +The major advances in civilization are processes +that all but wreck the societies in which they occur. + -- A.N. Whitehead +%% + The man standing at the bar (in court, unfortunately) was well- +dressed, alert and obviously intelligent. The judge asked him how he +pleaded to the charge of rape and, much to the magistrate's surprise, he +replied, "Not guilty by reason of insanity, your Honor." + "Insanity?" exclaimed the judge. + "Yes, sir," said the defendant. "I'm just crazy about it." +%% +The man who follows the crowd will usually get no further than the crowd. +The man who walks alone is likely to find himself in places no one has ever +been. + -- Alan Ashley-Pitt +%% +The man who has never been flogged has never been taught. + -- Menander +%% +The man who laughs has not yet been told the terrible news. + -- Bertolt Brecht +%% +The man who raises a fist has run out of ideas. + -- H.G. Wells, "Time After Time" +%% +The man who runs may fight again. + -- Menander +%% +The man who sees, on New Year's day, Mount +Fuji, a hawk, and an eggplant is forever blessed. + -- Old Japanese proverb +%% +The man who understands one woman is +qualified to understand pretty well everything. + -- Yeats +%% +The man-hating woman, like the cold woman, is largely imaginary. She +is simply a woman who has done her best to snare a man and has failed. + -- Norton +%% +The mark of the immature man is that he wants to die nobly for a cause, +while the mark of a mature man is that he wants to live humbly for one. + -- Wilhelm Stekel +%% +The mark of your ignorance is the depth of your belief in injustice +and tragedy. What the caterpillar calls the end of the world, the +master calls a butterfly. + -- Messiah's Handbook : Reminders for the Advanced Soul +%% +The marriage of Marxism and feminism has been like the marriage of +husband and wife depicted in English common law: Marxism and feminism +are one, and that one is marxism. + -- Heidi Hartmann, + "The Unhappy Marriage of Marxism and Feminism" +%% +The marvels of today's modern technology include the development of a +soda can, which, when discarded will last forever -- and a $7,000 car +which, when properly cared for, will rust out in two or three years. +%% +The mate for beauty should be a man and not a money chest. + -- Bulwer +%% +The mature bohemian is one whose woman works full time. +%% +The means-and-ends moralists, or non-doers, +always end up on their ends without any means. + -- Saul Alinsky +%% +The meat is rotten, but the booze is holding out. +Computer translation of "The spirit is willing, but the flesh is weak." +%% +The meek inherit the earth -- usually in small sections... about 6 by 3. +%% +The meek shall inherit the earth -- they are too weak to refuse. +%% +The meek shall inherit the earth; the rest of us, the Universe. +%% +The meek shall inherit the earth; the rest of us will go to the stars. +%% +The meek shall inherit the earth; but by that +time there won't be anything left worth inheriting. +%% +The meeting of two personalities is like the contact of two +chemical substances: if there is any reaction, both are transformed. + -- Carl Jung +%% +[The members of the Chamberlain government] are decided only to be +undecided, resolved to be irresolute, adamant for drift, all-powerful +for impotency. + -- W. Churchill +%% +The men sat sipping their tea in silence. After a while the klutz said, + "Life is like a bowl of sour cream." + "Like a bowl of sour cream?" asked the other. "Why?" + "How should I know? What am I, a philosopher?" +%% +The mind is its own place, and in itself +Can make a Heaven of Hell, a Hell of Heaven. +What matter where, if I be still the same, +And what I should be, all but less than he +Whom thunder hath made greater? here at least +We shall be free; the almighty hath not built +Here for his envy, will not drive us hence; +Here we may reign secure, and, in my choice, +To reign is worth ambition, though in Hell: +Better to reign in Hell than serve in Heaven. + -- Satan, Milton's "Paradise Lost", I, 254-263 +%% +The minute a man is convinced that he is interesting, he isn't. +%% +The mirror sees the man as beautiful, the mirror loves the man; another +mirror sees the man as frightful and hates him; and it is always the same +being who produces the impressions. + -- Marquis D.A.F. de Sade +%% +The moon is made of green cheese. + -- John Heywood +%% +The moon may be smaller than Earth, but it's further away. +%% +The more I know men the more I like my horse. +%% +The more I learn about men, the more I love my dog. +%% +The more I learn about women, the more I love my cat. +%% +The more I want to get something done, the less I call it work. + -- R. Bach, "Illusions" +%% +The more complex the mind, the greater +the need for the simplicity of play. + -- Captain Kirk, "Shore Leave" +%% +The more control, the more that requires control. +%% +The more cordial the buyers secretary, the greater +the odds that the competition already has the order. +%% +The more laws and order are made prominent, +the more thieves and robbers there will be. + -- Lao Tsu +%% +The more the merrier. + -- John Heywood +%% +The more things change, the more they remain the same. + -- Alphonse Karr +%% +The more things change, the more they stay insane. +%% +The more things change, the more they'll never be the same again. +%% +The more we disagree, the more chance +there is that at least one of us is right. +%% +The more you sweat in peace, the less you bleed in war. +%% +The mosquito exists to keep the mighty humble. +%% +The moss on the tree does not fear the talons of the hawk. +%% +The most advantageous, pre-eminent thing thou canst do is not to +exhibit nor display thyself within the limits of our galaxy, but +rather depart instantaneously whence thou even now standest and +flee to yet another rotten planet in the universe, if thou canst +have the good fortune to find one. + -- Carlyle +%% +The most costly of all follies is to believe passionately +in the palpably not true. It is the chief occupation of mankind. + -- H.L. Mencken +%% +The most difficult thing about surviving AIDS +is trying to convince your parents that you're Haitian. +%% +The most difficult thing in the world is to know how to do a +thing and to watch someone else doing it wrong, without commenting. + -- T.H. White +%% +The most exciting phrase to hear in science, the one that heralds new +discoveries, is not "Eureka!" (I found it!) but "That's funny ..." + -- Isaac Asimov +%% +The most hopelessly stupid man is he who is not aware that he is wise. +%% +The most important early product on the way +to developing a good product is an imperfect version. +%% +The most important things, each person must do for himself. +%% +The most unsatisfactory men are those who pride themselves on their +virility and regard sex as if it were some form of athletics at which +you win cups. It is a woman's spirit and mood which a man has to +stimulate in order to make sex interesting. The real lover is the +man who can thrill you by just touching your head or smiling into +your eyes - or just by staring into space. + -- Marilyn Monroe +%% +The moving cursor writes, and having written, blinks on. +%% +The naked truth of it is, I have no shirt. + -- William Shakespeare, "Love's Labour's Lost" +%% +The nation that controls magnetism controls the universe. + -- Chester Gould/Dick Tracy +%% +The nearer to the church, the further from God. + -- John Heywood +%% +The new Congressmen say they're going to turn the government around. +I hope I don't get run over again. +%% +The next person to mention spaghetti stacks +to me is going to have his head knocked off. + -- Bill Conrad +%% +The next thing I say to you will be true. +The last thing I said was false. +%% +The nice thing about standards +is that there are so many of them to choose from. + -- Andrew S. Tanenbaum +%% +The nicest thing about the Alto is that it doesn't run faster at night. +%% +The night passes quickly when you're asleep +But I'm out shufflin' for something to eat +... +Breakfast at the Egg House, +Like the waffle on the griddle, +I'm burnt around the edges, +But I'm tender in the middle. + -- Adrian Belew +%% +The notion of a "record" is an obsolete +remnant of the days of the 80-column card. + -- D.M. Ritchie +%% +The number of computer scientists in a room is inversely +proportional to the number of bugs in their code. +%% +The number of licorice gumballs you get out of a gumball machine +increases in direct proportion to how much you hate licorice. +%% +The objective of all dedicated employees should be to thoroughly analyze +all situations, anticipate all problems prior to their occurrence, have +answers for these problems, and move swiftly to solve these problems +when called upon. + However... +When you are up to your ass in alligators it is difficult to remind +yourself your initial objective was to drain the swamp. +%% +The odds are a million to one against your being one in a million. +%% +The odds are five to six that the headlight at the +end of the tunnel is the headlight of an oncoming train. +%% +The older I grow, the more I distrust the +familiar doctrine that age brings wisdom. + -- H.L. Mencken +%% +The older a man gets, the farther he had to walk to school as a boy. +%% +The one L lama, he's a priest +The two L llama, he's a beast +And I will bet my silk pyjama +There isn't any three L lllama. + -- O. Nash, to which a fire chief replied that occasionally + his department responded to something like a "three L lllama." +%% +The one day you'd sell your soul for something, souls are a glut. +%% +The one good thing about repeating your +mistakes is that you know when to cringe. +%% +The one sure way to make a lazy man look +respectable is to put a fishing rod in his hand. +%% +The only certainty is that nothing is certain. + -- Pliny the Elder +%% +The only constant is change. +%% +The only difference between a rut and a grave is their dimensions. +%% +The only difference between the saint and the sinner is that +every saint has a past and every sinner has a future. + -- Oscar Wilde +%% +The only difference between your girlfriend +and a barracuda is the nailpolish. +%% +The only difference in the game of love over the last few +thousand years is that they've changed trumps from clubs to diamonds. + -- The Indianapolis Star +%% +The only justification for our concepts and systems of concepts is +that they serve to represent the complex of our experiences; +beyond this they have not legitimacy. + -- Einstein. +%% +The only people for me are the mad ones -- the ones who are mad to live, +mad to talk, mad to be saved, desirous of everything at the same time, +the ones who never yawn or say a commonplace thing, but burn, burn, burn +like fabulous yellow Roman candles. + -- Jack Kerouac, "On the Road" +%% +The only perfect science is hind-sight. +%% +The only possible interpretation of any research +whatever in the 'social sciences' is: some do, some don't. + -- Ernest Rutherford +%% +The only problem with being a man of leisure +is that you can never stop and take a rest. +%% +The only problem with seeing too much is that it makes you insane. + -- Phaedrus +%% + The only real game in the world, I think, is baseball... +You've got to start way down, at the bottom, when you're six or seven years +old. You can't wait until you're fifteen or sixteen. You've got to let it +grow up with you, and if you're successful and you try hard enough, you're +bound to come out on top, just like these boys have come to the top now. + -- Babe Ruth, in his 1948 farewell speech at Yankee Stadium +%% +The only real way to look younger is not to be born so soon. + -- C. Schultz +%% +The only reward of virtue is virtue. + -- Ralph Waldo Emerson +%% +The only rose without thorns is friendship. +%% +The only thing better than love is milk. +%% +The only thing cheaper than hardware is talk. +%% +The only thing to do with good advice is pass it on. +It is never any use to oneself. + -- Oscar Wilde +%% +The only thing we learn from history is that we do not learn. + -- Earl Warren +%% +The only time a dog gets complimented is when he doesn't do anything. + -- C. Schultz +%% +The only way to amuse some people +is to slip and fall on an icy pavement. +%% +The only way to behave to a woman is to make love to +her if she is pretty and to someone else if she is plain. + -- Oscar Wilde +%% +The only way to get rid of a temptation is to yield to it. + -- Oscar Wilde +%% +The only way to keep you health is to eat what you don't want, +drink what you don't like, and do what you'd rather not. + -- Mark Twain +%% +The only way you'll ever hear from +me is if you're living in the same hell. + -- Roy Harper +%% +The onset and the waning of love make themselves felt +in the uneasiness experienced at being alone together. + -- Jean de la Bruyere +%% +The opossum is a very sophisticated animal. +It doesn't even get up until 5 or 6 pm. +%% +The opposite of a profound truth may well be another profound truth. + -- Bohr +%% +The optimist proclaims that we live in the best of all possible +worlds, and the pessimist fears this is true. +%% +The optimum committee has no members. + -- Norman Augustine +%% +The opulence of the front office door varies +inversely with the fundamental solvency of the firm. +%% +The other line moves faster. +%% +The owner of a large furniture store in the mid-west arrived in France on +a buying trip. As he was checking into a hotel he struck up an acquaintance +with a beautiful young lady. However, she only spoke French and he only spoke +English, so each couldn't understand a word the other spoke. He took out a +pencil and a notebook and drew a picture of a coach. She smiled, nodded her +head and they went for a ride in the park. Later, he drew a picture of a +table in a restaurant with a question mark and she nodded, so they went to +dinner. After dinner he sketched two dancers and she was delighted. They +went to several nightclubs, drank champagne, danced and had a glorious +evening. It had gotten quite late when she motioned for the pencil and drew +a picture of a four-poster bed. He was dumbfounded, and to this day has +never be able to understand how she knew he was in the furniture business. +%% +The part of the world that people find most puzzling is the part called "Me". +%% +The party adjourned to a hot tub, yes. Fully clothed, I might add. + -- IBM employee, testifying in California State Supreme Court +%% +The past always looks better than it was. +It's only pleasant because it isn't here. + -- Finley Peter Dunne (Mr. Dooley) +%% +The people sensible enough to give +good advice are usually sensible enough to give none. +%% +The perfect friend sees the best in you -- sees it constantly -- +not just when you occasionally are that way, but also when you +waver, when you forget yourself, act like less than you are. +In time, you become more like his vision of you -- which is the +person you have always wanted to be. + -- Nancy Friday +%% +The perfect man is the true partner. Not a bed partner nor a fun partner, +but a man who will shoulder burdens equally with [you] and possess that +quality of joy. + -- Erica Jong +%% +The person who can smile when something +goes wrong has thought of someone to blame it on. +%% +The person who makes no mistakes does not usually make anything. +%% +The person you rejected yesterday could make you happy, if you say yes. +%% +The philosopher's treatment of a question +is like the treatment of an illness. + -- Wittgenstein. +%% +The pitcher wound up and he flang the ball at the batter. The batter swang +and missed. The pitcher flang the ball again and this time the batter +connected. He hit a high fly right to the center fielder. The center +fielder was all set to catch the ball, but at the last minute his eyes were +blound by the sun and he dropped it. + -- Dizzy Dean +%% +The pleasure is transitory, the cost +prohibitive, and the position ridiculous. + -- Disraeli, on sex +%% +The plural of spouse is spice. +%% +The point is, you see, that there is no point in driving yourself mad +trying to stop yourself going mad. You might just as well give in and +save your sanity for later. +%% +The politician is someone who deals in man's problems of adjustment. +To ask a politician to lead us is to ask the tail of a dog to lead the dog. + -- Buckminster Fuller +%% +The pollution's at that awkward stage. +Too thick to navigate and too thin to cultivate. + -- Doug Sneyd +%% +The price of greatness is responsibility. +%% +The price of success in philosophy is triviality. + -- C. Glymour. +%% +The primary function of the design engineer is to make things +difficult for the fabricator and impossible for the serviceman. +%% +The primary purpose of the DATA statement is to give names to constants; +instead of referring to pi as 3.141592653589793 at every appearance, the +variable PI can be given that value with a DATA statement and used instead +of the longer form of the constant. This also simplifies modifying the +program, should the value of pi change. + -- FORTRAN manual for Xerox Computers +%% +The probability of someone watching you is directly +proportional to the stupidity of your action. +%% +The problem with any unwritten law is that +you don't know where to go to erase it. + -- Glaser and Way +%% +The problem with people who have no vices is that generally you can +be pretty sure they're going to have some pretty annoying virtues. + -- Elizabeth Taylor +%% +The problem with the gene pool is that there is no lifeguard. +%% +The proof of the pudding is in the eating. + -- Miguel de Cervantes +%% +The public demands certainties; it must be told definitely and a bit +raucously that this is true and that is false. But there are no +certainties. + -- H.L. Mencken, "Prejudice" +%% +The questions remain the same. +The answers are eternally variable. +%% +The race is not always to the swift... but that's the way to bet. + -- Runyon +%% +The rain it raineth on the just +And also on the unjust fella, +But chiefly on the just, because +The unjust steals the just's umbrella. +%% +The real man's Bloody Mary: + Ingredients: vodka, tomato juice, Tobasco, Worcestershire + sauce, A-1 steak sauce, ice, salt, pepper, celery. + + Fill a large tumbler with vodka. + Throw all the other ingredients away. +%% +The real reason psychology is hard is that +psychologists are trying to do the impossible. +%% +The reason computer chips are so small is computers don't eat much. +%% +The reason they're called wisdom teeth +is that the experience makes you wise. +%% +The reason why worry kills more people +than work is that more people worry than work. +%% +The reasonable man adapts himself to the world; the unreasonable one +persists in trying to adapt the world to himself. Therefore all progress +depends on the unreasonable man. + -- George Bernard Shaw +%% +The relative importance of files depends on their cost +in terms of the human effort needed to regenerate them. + -- T.A. Dolotta +%% +The revolution will not be televised. +%% +The reward for working hard is more hard work. +%% +The reward of a thing well done is to have done it. + -- Emerson +%% +The rich get rich, and the poor get poorer. +The haves get more, the have-nots die. +%% +The right half of the brain controls the left half of the body. +This means that only left handed people are in their right mind. +%% +The right to be let alone is indeed the beginning of all freedom. + -- Justice Douglas +%% +The rights and interests of the laboring man will be protected and cared +for not by our labor agitators, but by the Christian men to whom God in his +infinite wisdom has given control of property interests of the country, and +upon the successful management of which so much remains. + -- George F. Baer, railroad industrialist +%% +The ripest fruit falls first. + -- William Shakespeare, "Richard II" +%% +The road to Hades is easy to travel. + -- Bion +%% +The road to hell is paved with NAND gates. + -- J. Gooding +%% +The road to ruin is always in good repair, +and the travellers pay the expense of it. + -- Josh Billings +%% +The root of all superstition is that men +observe when a thing hits, but not when it misses. + -- Francis Bacon +%% +The rose of yore is but a name, mere names are left to us. +%% +The rule is, jam to-morrow and jam yesterday, but never jam today. + -- Lewis Carroll +%% +The rules: + +1: Thou shalt not worship other computer systems. +2: Thou shalt not impersonate Liberace or eat watermelon while sitting at + the console keyboard. +3: Thou shalt not slap users on the face, nor staple their silly little + card decks together. +4: Thou shalt not get physically involved with the computer system, + especially if you're already married. +5: Thou shalt not use magnetic tapes as frisbees, nor use a disk pack as + a stool to reach another disk pack. +6: Thou shalt not stare at the blinking lights for more than one 8 hour + shift. +7: Thou shalt not tell users that you accidentally destroyed their + files/backup just to see the look on their little faces. +8: Thou shalt not enjoy cancelling a job. +9: Thou shalt not display firearms in the computer room. +10: Thou shalt not push buttons "just to see what happens". +%% +The savior becomes the victim. +%% +The second best policy is dishonesty. +%% +The secret of happiness is total disregard of everybody. +%% +The secret of healthy hitchhiking is to eat junk food. +%% +The secret of success is sincerity. +Once you can fake that, you've got it made. +%% +The secret source of humor is not joy but sorrow; +there is no humor in Heaven. + -- Mark Twain +%% +The seven eyes of Ningauble the Wizard floated back to his hood as he +reported to Fafhrd: "I have seen much, yet cannot explain all. The Gray +Mouser is exactly twenty-five feet below the deepest cellar in the palace +of Gilpkerio Kistomerces. Even though twenty-four parts in twenty-five of +him are dead, he is alive. + Now about Lankhmar. She's been invaded, her walls breached +everywhere and desperate fighting is going on in the streets, by a fierce +host which out-numbers Lankhamar's inhabitants by fifty to one -- and +equipped with all modern weapons. Yet you can save the city." + "How?" demanded Fafhrd. + Ningauble shrugged. "You're a hero. You should know." + -- Fritz Leiber, "The Swords of Lankhmar" +%% +The sheep died in the wool. +%% +The shifts of Fortune test the reliability of friends. + -- Marcus Tullius Cicero +%% +The shortest distance between two points is under construction. + -- Noelie Altito +%% +The six great gifts of an Irish girl are beauty, soft +voice, sweet speech, wisdom, needlework, and chastity. + -- Theodore Roosevelt, 1907 +%% +The sixth shiek's sixth sheep's sick. + -- [just say that five times...] +%% +The smallest worm will turn being trodden on. + -- William Shakespeare, "Henry VI" +%% +The smiling Spring comes in rejoicing, +And surly Winter grimly flies. +Now crystal clear are the falling waters, +And bonnie blue are the sunny skies. +Fresh o'er the mountains breaks forth the morning, +The ev'ning gilds the oceans's swell: +All creatures joy in the sun's returning, +And I rejoice in my bonnie Bell. + +The flowery Spring leads sunny Summer, +The yellow Autumn presses near; +Then in his turn come gloomy Winter, +Till smiling Spring again appear. +Thus seasons dancing, life advancing, +Old Time and Nature their changes tell; +But never ranging, still unchanging, +I adore my bonnie Bell. + -- Robert Burns, "My Bonnie Bell" +%% +The so-called lessons of history are for the most part the +rationalizations of the victors. History is written by the survivors. + -- Max Lerner +%% +The society which scorns excellence in plumbing as a humble activity and +tolerates shoddiness in philosophy because it is an exalted activity will +have neither good plumbing nor good philosophy... neither its pipes nor +its theories will hold water. +%% +The solution of problems is the most characteristic +and peculiar sort of voluntary thinking. + -- William James +%% +The solution of this problem is trivial +and is left as an exercise for the reader. +%% +The solution to a problem changes the nature of the problem. + -- Peer +%% +The sooner you fall behind, the more time you have to catch up. +%% +The soul would have no rainbow had the eyes no tears. +%% +The speed of anything depends on the flow of everything. +%% +The spirit of Plato dies hard. We have been unable to escape the +philosophical tradition that what we can see and measure in the world +is merely the superficial and imperfect representation of an underlying +reality. + -- S.J. Gould, "The Mismeasure of Man" +%% +The star of riches is shining upon you. +%% +The startling truth finally became apparent, and it was this: Numbers +written on restaurant checks within the confines of restaurants do not +follow the same mathematical laws as numbers written on any other pieces +of paper in any other parts of the Universe. This single statement took +the scientific world by storm. So many mathematical conferences got held +in such good restaurants that many of the finest minds of a generation +died of obesity and heart failure, and the science of mathematics was put +back by years. + -- Douglas Adams +%% +The street preacher looked so baffled +When I asked him why he dressed +With forty pounds of headlines +Stapled to his chest. +But he cursed me when I proved to him +I said, "Not even you can hide. +You see, you're just like me. +I hope you're satisfied." + -- Bob Dylan +%% +The strong give up and move away, while the weak give up and stay. +%% +The struggling for knowledge has a pleasure in it +like that of wrestling with a fine woman. + -- Lord Halifax +%% +The sudden sight of me causes panic in the streets. They have +yet to learn - only the savage fears what he does not understand. + -- The Silver Surfer +%% +The sun never sets on those who ride into it. + -- RKO +%% +The sun was shining on the sea, +Shining with all his might: +He did his very best to make +The billows smooth and bright -- +And this was very odd, because it was +The middle of the night. + -- Lewis Carroll +%% +The sunlights differ, but there is only one darkness. + -- Ursula K. LeGuin, "The Dispossessed" +%% +The superfluous is very necessary. + -- Voltaire +%% +The superior man understands what is right; +the inferior man understands what will sell. + -- Confucius +%% +The surest way to remain a winner is to +win once, and then not play any more. +%% +The system was down for backups from 5am to 10am last Saturday. +%% +The system will be down for 10 days for preventative maintenance. +%% +The temperature of the aqueous content of an unremittingly ogled +culinary vessel will not achieve 100 degrees on the Celsius scale. +%% +The test of a first-rate intelligence is the ability to hold two opposed +ideas in the mind at the same time and still retain the ability to function. + -- F. Scott Fitzgerald +%% +The test of intelligent tinkering is to save all the parts. + -- Aldo Leopold +%% +The thing that takes up the least amount of time +and causes the most amount of trouble is sex. +%% +The things that interest people most are usually none of their business. +%% +The three faithful things in life are money, a dog and an old woman. +%% +The three laws of thermodynamics: + (1) You can't get anything without working for it. + (2) The most you can accomplish by working is to break even. + (3) You can only break even at absolute zero. +%% +The time for action is past! +Now is the time for senseless bickering. +%% +The time is right to make new friends. +%% +The time spent on any item of the agenda [of a finance +committee] will be in inverse proportion to the sum involved. + -- C.N. Parkinson +%% +The time was the 19th of May, 1780. The place was Hartford, Connecticut. +The day has gone down in New England history as a terrible foretaste of +Judgement Day. For at noon the skies turned from blue to grey and by +mid-afternoon had blackened over so densely that, in that religious age, +men fell on their knees and begged a final blessing before the end came. +The Connecticut House of Representatives was in session. And, as some of +the men fell down and others clamored for an immediate adjournment, the +Speaker of the House, one Col. Davenport, came to his feet. He silenced +them and said these words: "The day of judgment is either approaching or +it is not. If it is not, there is no cause for adjournment. If it is, I +choose to be found doing my duty. I wish therefore that candles may be +brought." + -- Alistair Cooke +%% +The tree in which the sap is stagnant remains fruitless. + -- Hosea Ballou +%% +The trouble is, there is an endless supply of White Men, +but there has always been a limited number of Human Beings. + -- Little Big Man +%% +The trouble with being poor is that it takes up all your time. +%% +The trouble with being punctual is that people +think you have nothing more important to do. +%% +The trouble with computers is that they do +what you tell them, not what you want. + -- D. Cohen +%% +The trouble with doing something right the first +time is that nobody appreciates how difficult it was. +%% +The trouble with money is it costs too much! +%% +The trouble with opportunity is that it +always comes disguised as hard work. + -- Herbert V. Prochnow +%% +The trouble with some women is that they get +all excited about nothing -- and then marry him. + -- Cher +%% +The trouble with you +Is the trouble with me. +Got two good eyes +But we still don't see. + -- Robert Hunter, "Workingman's Dead" +%% +The true way goes over a rope which is not stretched at any great +height but just above the ground. It seems more designed to make +people stumble than to be walked upon. + -- Franz Kafka +%% +The truth about a man lies first and foremost in what he hides. + -- Andre Malraux +%% +The truth about a woman often lasts longer than the woman is true. +%% +The truth is rarely pure, and never simple. + -- Oscar Wilde +%% +The truth of a proposition has nothing to do with its credibility. +And vice versa. +%% +The truth you speak has no past and no future. +It is, and that's all it needs to be. +%% +The turtle lives 'twixt plated decks +Which practically conceal its sex. +I think it clever of the turtle +In such a fix to be so fertile. + -- O. Nash +%% +The two oldest professions in the world have been ruined by amateurs. + -- G.B. Shaw +%% +The two things that can get you into trouble +quicker than anything else are fast women and slow horses. +%% +The typewriting machine, when played with expression, is no more +annoying than the piano when played by a sister or near relation. + -- Oscar Wilde +%% +The, uh, snowy mountains are like really cold, eh? +And the, um, plains stretch out like my moms girdle, eh? +There's lotsa beers and doughnuts for everyone, eh? +So the last one to be peaceful and everything is a big idiot, +Eh? +So shut yer face up and dry yer mucklucks by the fire, eh? +And dream about girls with their high beams on, eh? +They may be cold, but that's okay! Beer's better that way! +Eh? + -- A, like, Tribute to the Great White North, eh? +Beauty! +%% +The ultimate game show will be the one +where somebody gets killed at the end. + -- Chuck Barris, creator of "The Gong Show" +%% +The universe is all a spin-off of the Big Bang. +%% +The universe is an island, +surrounded by whatever it is that surrounds universes. +%% +The universe is laughing behind your back. +%% +The universe is ruled by letting things take their course. +It cannot be ruled by interfering. + -- Chinese proverb +%% +The universe seems neither benign nor hostile, merely indifferent. + -- Sagan +%% +The use of COBOL cripples the mind; +its teaching should, therefore, be regarded as a criminal offense. + -- E.W. Dijkstra +%% +The use of money is all the advantage there is to having money. + -- B. Franklin +%% +The value of a program is proportional to the weight of its output. +%% +The very first essential for success is a perpetually +constant and regular employment of violence. + -- Adolph Hitler, "Mein Kampf" +%% +The very remembrance of my former misfortune proves a new one to me. + -- Miguel de Cervantes +%% +The voluptuous blond was chatting with her handsome escort in a posh +restaurant when their waiter, stumbling as he brought their drinks, +dumped a martini on the rocks down the back of the blonde's dress. She +sprang to her feet with a wild rebel yell, dashed wildly around the table, +then galloped wriggling from the room followed by her distraught boyfriend. +A man seated on the other side of the room with a date of his own beckoned +to the waiter and said, "We'll have two of whatever she was drinking." +%% +The warning message we sent the Russians was a +calculated ambiguity that would be clearly understood. + -- Alexander Haig +%% +The water was not fit to drink. +To make it palatable, we had to add whiskey. +By diligent effort, I learned to like it. + -- W. Churchill +%% + The way my jeweler explained it, it's like insurance. + Six months' pay isn't much to keep my wife from sleeping around. + +A diamond -- pure, sparkling, natural, flawless, forever. The way marriage +should be but never quite is. People grow and change and sometimes want to +take their clothes off with strangers. So when you invest in a fine piece +of diamond jewelry, you're not only making an investment, you're making a +statement. You're telling the woman you love that you've just spent a lot of +your hard-earned money on her. Now she owes you the kind of loyalty that +only precious jewelry can buy. Isn't she worth it? + + The Honeymoon's Over: from $ 5000 + The Seven Year Itch: from $10000 + No More Lunchtime Quickies: from $15000 + Divorce Would Be More Expensive: from $42000 + + A diamond is for leverage. BeDears +%% +The way to a man's heart is through the left ventricle. +%% +The way to a man's stomach is through his esophagus. +%% +The way to fight a woman is with your hat. Grab it and run. +%% +The way to love anything is to realize that it might be lost. +%% +The way to make a small fortune +in the commodities market is to start with a large fortune. +%% +The weather is here. Wish you were beautiful. +%% +The weather is here, I wish you were beautiful. +My thoughts aren't too clear, but don't run away. +My girlfriend's a bore; my job is too dutiful. +Hell nobody's perfect, would you like to play? +I feel together today! + -- Jimmy Buffet, "Coconut Telegraph" +%% +The weed of crime bears bitter fruit. +%% +The weed of crime bears bitter fruit... +but the leaves are good to smoke! + -- The Shadow +%% +The white race is the cancer of history. + -- Susan Sontag +%% +The whole of life is futile unless you +consider it as a sporting proposition. +%% +The whole world is a tuxedo and you are a pair of brown shoes. + -- George Gobel +%% +The wise man seeks everything in himself; +the ignorant man tries to get everything from somebody else. +%% +The wise shepherd never trusts his flock to a smiling wolf. +%% +The woman you buy -- and she is the least expensive -- takes a great +deal of money. The woman who gives herself takes all your time. + -- Balzac +%% +The wonderful thing about a dancing bear +is not how well he dances, but that he dances at all. +%% +The world has many unintentionally cruel mechanisms that are not +designed for people who walk on their hands. + -- John Irving, "The World According to Garp" +%% +The world is coming to an end... SAVE YOUR BUFFERS!! +%% +The world is coming to an end! +Repent and return those library books! +%% +The world is full of people who have never, since +childhood, met an open doorway with an open mind. + -- E.B. White +%% +The world is moving so fast these days that the man who says +it can't be done is generally interrupted by someone doing it. + -- E. Hubbard +%% +The world is not octal despite DEC. +%% +The world is your exercise-book, the pages on which you do your sums. +It is not reality, although you can express reality there if you wish. +You are also free to write nonsense, or lies, or to tear the pages. + -- Messiah's Handbook : Reminders for the Advanced Soul +%% +The world needs more people like us and fewer like them. +%% +The world really isn't any worse. +It's just that the news coverage is so much better. +%% +The world wants to be deceived. + -- Sebastian Brant +%% +The world will end in 5 minutes. Please log out. +%% +The world's as ugly as sin, +And almost as delightful + -- Frederick Locker-Lampson +%% +The world's great men have not commonly been great scholars, +nor its great scholars great men. + -- Oliver Wendell Holmes +%% +The worst cliques are those which consist of one man. + -- G.B. Shaw +%% +The worst is enemy of the bad. +%% +The worst is not so long as we can say "This is the worst." + -- King Lear +%% +The worst part of valor is indiscretion. +%% +The worst sin towards our fellow creatures is not to hate them, +but to be indifferent to them; that's the essence of inhumanity. + -- G.B. Shaw +%% +The worst thing one can do is not to try, to be aware of what one +wants and not give in to it, to spend years in silent hurt wondering +if something could have materialized -- and never knowing. + -- David Viscott +%% +The yankees, son, are up north. +The damnyankees are down here. +%% +The years of peak mental activity are undoubtedly between the ages of +four and eighteen. At four we know all the questions, at eighteen all +the answers. +%% +The young man-about-town enjoyed luxury but didn't always have the means +to buy it, and so he huffily walked out of the Miami Beach hotel when he +found out the charges for room, meals and golf privileges were $100 a day. +He registered across the street at an equally elegant hotel, where the +rates were only $70. The following morning he went down to the hotel's +golf course and asked Scotty, the pro, to sell him a couple of golf balls. +"Sure," said Scotty. "That'll be $15 apiece." + "What?" screamed the bachelor. "In the hotel across the street +they only charge $1 a ball!" + "Naturally," replied the pro. "Over there they get you by the +rooms." +%% +Theft from a single author is plagiarism. +Theft from three or more is research. +%% +Their idea of an offer you can't refuse is an offer... +and you'd better not refuse. +%% + Them Toad Suckers + +How 'bout them toad suckers, ain't they clods? +Sittin' there suckin' them green toady frogs! + +Suckin' them hop toads, suckin' them chunkers, +Suckin' them a leapy type, suckin' them flunkers. + +Look at them toad suckers, ain't they snappy? +Suckin' them bog frogs sure make's 'em happy! + +Them hugger mugger toad suckers, way down south, +Stickin' them sucky toads in they mouth! + +How to be a toad sucker, no way to duck it, +Get yourself a toad, rear back, and suck it! + -- Mason Williams +%% +Them as has, gets. +%% + Then a man said: Speak to us of Expectations. + + He then said: If a man does not see or hear the waters of the +Jordan, then he should not taste the pomegranate or ply his wares in an +open market. + + If a man would not labour in the salt and rock quarries then he +should not accept of the Earth that which he refuses to give of +himself. + + Such a man would expect a pear of a peach tree. + Such a man would expect a stone to lay an egg. + Such a man would expect Sears to assemble a lawnmower. + -- Kehlog Albran +%% +Then, gently touching my face, she hesitated for a moment as her +incredible eyes poured forth into mine love, joy, pain, tragedy, +acceptance, and peace. "'Bye for now," she said warmly. + -- Thea Alexander, "2150 A.D." +%% +Then there was the Formosan bartender named Taiwan-On. +%% +Then there was the guy that got badly messed up fighting +for his girl's honor. It seems she wanted to keep it. +%% + Then there's the atmosphere -- half the time you can eat the air, +it's got so much stuff floating around in it. It takes the edge out of +the colors. Down here even the traffic lights are pastel. And people! +With a lot of these folks you'd have to check their green cards just to +make sure that they are Earthlings. Then there's the police. In Portland, +when some guy goes bananas, the cops rope off a sixteen block area around +him and call a shrink from the medical school who stands atop a patrol car +with a megaphone and shouts, "OK! THIS! ALL! STARTED! WHEN! YOU! WERE! +THREE! YEARS! OLD! ON! ACCOUNT! OF! YOUR MOTHER! RIGHT? SO! LET'S! +TALK! ABOUT! IT!" Down here they don't waste that kind of time. The LAPD +has SWAT teams composed of guys who make Darth Vader look like Mr. Peepers. +Before they go to bust a bookie joint they mortar it first. + -- M. Christensen, "A Portland Innocent in LA" +%% + Then there's the story of the man who avoided reality for 70 years +with drugs, sex, alcohol, fantasy, TV, movies, records, a hobby, lots of +sleep... And on his 80th birthday died without ever having faced any of +his real problems. + The man's younger brother, who had been facing reality and all his +problems for 50 years with psychiatrists, nervous breakdowns, tics, tension, +headaches, worry, anxiety and ulcers, was so angry at his brother for having +gotten away scott free that he had a paralyzing stroke. + The moral to this story is that there ain't no justice that we can +stand to live with. + -- R. Geis +%% + "Then what is magic for?" Prince Lir demanded wildly. "What use is +wizardry if it cannot save a unicorn?" He gripped the magician's shoulder +hard, to keep from falling. + Schmendrick did not turn his head. With a touch of sad mockery in +his voice, he said, "That's what heroes are for." +... + "Yes, of course," he [Prince Lir] said. "That is exactly what heroes +are for. Wizards make no difference, so they say that nothing does, but +heroes are meant to die for unicorns." + -- P. Beagle, "The Last Unicorn" +%% +Theology is an attempt to explain a subject by men who do not understand +it. The intent is not to tell the truth but to satisfy the questioner. + -- Elbert Hubbard +%% +Theorem: All programs are dull. + +Proof: Assume the contrary; i.e., the set of interesting programs is +nonempty. Arrange them (or it) in order of interest (note that all +sets can be well ordered, so do it properly). The minimal element is +the "least interesting program", the obvious dullness of which provides +the contradictory denouement we so devoutly seek. + -- Stan Kelly-Bootle, "The Devil's DP Dictionary" +%% +Theory is gray, but the golden tree of life is green. + -- Goethe +%% +Theory of Selective Supervision: + The one time in the day that you lean back and relax is + the one time the boss walks through the office. +%% + Theory +Into love and out again, + Thus I went and thus I go. +Spare your voice, and hold your pen: + Well and bitterly I know +All the songs were ever sung, + All the words were ever said; +Could it be, when I was young, + Someone dropped me on my head? + -- Dorothy Parker +%% +There ain't nothing in the middle of the road +except yellow stripes and dead armadillos. +%% +There appears before you a threatening figure clad all over in heavy black +armor. His legs seem like the massive trunk of the oak tree. His broad +shoulders and helmeted head loom high over your own puny frame and you +realize that his powerful arms could easily crush the very life from your +body. There hangs from his belt a veritable arsenal of deadly weapons: +sword, mace, ball and chain, dagger, lance, and trident. +He speaks with a commanding voice: + + "YOU SHALL NOT PASS" + +As he grabs you by the neck all grows dim about you. +%% +There appears to be irrefutable evidence that +the mere fact of overcrowding induces violence. + -- Harvey Wheeler +%% +There are a few things that never go out of style, +and a feminine woman is one of them. + -- Ralston +%% +There are few people more often in the wrong +than those who cannot endure to be thought so. +%% +There are four kinds of homicide: felonious, +excusable, justifiable, and praiseworthy... + -- Ambrose Bierce +%% +There are in this country two very large monopolies. The larger of the +two has the following record: The Vietnam War, Watergate, double-digit +inflation, fuel and energy shortages, bankrupt airlines, and the 8-cent +postcard. The second is responsible for such things as the transistor, +the solar cell, lasers, synthetic crystals, high fidelity stereo recording, +sound motion pictures, radio astronomy, negative feedback, magnetic tape, +magnetic "bubbles", electronic switching systems, microwave radio and TV +relay systems, information theory, the first electrical digital computer, +and the first communications satellite. Guess which one is going to tell +the other how to run the telephone business? I can hardly wait for the +results. +%% +There are many people today who literally do not have a close personal +friend. They may know something that we don't. They are probably +avoiding a great deal of pain. +%% +There are more old drunkards than old doctors. +%% +There are more things in heaven and earth than any place else. +%% +There are more things in heaven and earth, +Horatio, than are dreamt of in your philosophy. + -- Hamlet +%% +There are more ways of killing a cat than choking her with cream. +%% +There are never any bugs you haven't found yet. +%% +There are new messages. +%% +There are no accidents whatsoever in the universe. + -- Baba Ram Dass +%% +There are no answers, only cross-references. + -- Weiner +%% +There are no great men, only great challenges that +ordinary men are forced by circumstances to meet. + -- Admiral William Halsey +%% +There are no rules for March. March is spring, sort +of, usually, March means maybe, but don't bet on it. +%% +There are only two kinds of tequila. Good and better. +%% +There are people so addicted to exaggeration +that they can't tell the truth without lying. + -- Josh Billings +%% +There are people who find it odd to eat four or five Chinese meals +in a row; in China, I often remind them, there are a billion or so +people who find nothing odd about it. + -- Calvin Trillin +%% +There are places I'll remember +All my life though some have changed. +Some forever not for better +Some have gone and some remain. +All these places had their moments +With lovers and friends I still recall. +Some are dead and some are living, +In my life I've loved them all. + +But of all these friends and lovers, +There is no one compared with you, +All these memories lose their meaning +When I think of love as something new. +Though I know I'll never lose affection +For people and things that went before, +I know I'll often stop and think about them +In my life I'll love you more. + -- Lennon/McCartney, "In My Life", 1965 +%% +There are running jobs. +Why don't you go chase them? +%% + There are some goyisha names that just about guarantee that +someone isn't Jewish. For example, you'll never meet a Jew named +Johnson or Wright or Jones or Sinclair or Ricks or Stevenson or Reid or +Larsen or Jenks. But some goyisha names just about guarantee that +every other person you meet with that name will be Jewish. Why is +this? + Who knows? Learned rabbis have pondered this question for +centuries and have failed to come up with an answer, and you think you +can find one? Get serious. You don't even understand why it's +forbidden to eat crab -- fresh cold crab with mayonnaise -- or lobster +-- soft tender morsels of lobster dipped in melted butter. You don't +even understand a simple thing like that, and yet you hope to discover +why there are more Jews named Miller than Katz? Fat Chance. + -- Arthur Naiman +%% +There are some micro-organisms that exhibit characteristics of both +plants and animals. When exposed to light they undergo photosynthesis; +and when the lights go out, they turn into animals. But then again, +don't we all. +%% +There are strange things done in the midnight sun + By the men who moil for gold; +The Arctic trails have their secret tales + That would make your blood run cold; +The Northern Lights have seen queer sights, + But the queerest they ever did see +Was that night on the marge of Lake Lebarge + I cremated Sam McGee. + -- Robert W. Service +%% +There are ten or twenty basic truths, and life +is the process of discovering them over and over and over. + -- David Nichols +%% +There are three kinds of lies: lies, damned lies and statistics. + -- Benjamin Disraeli +%% +There are three kinds of people: men, women, and unix. +%% +There are three possibilities: +Pioneer's solar panel has turned away from the sun; +there's a large meteor blocking transmission; +someone loaded Star Trek 3.2 into our video processor. +%% +There are three possible parts to a date, of which at least two must be +offered: entertainment, food, and affection. It is customary to begin a +series of dates with a great deal of entertainment, a moderate amount of +food, and the merest suggestion of affection. As the amount of affection +increases, the entertainment can be reduced proportionately. When the +affection IS the entertainment, we no longer call it dating. Under no +circumstances can the food be omitted. + -- Miss Manners' Guide to Excruciatingly Correct Behaviour +%% +There are three things I have always loved +and never understood -- art, music, and women. +%% +There are three things men can do with women: +love them, suffer for them, or turn them into literature. + -- Stephen Stills +%% +There are three ways to get something done: +do it yourself, hire someone, or forbid your kids to do it. +%% +There are twenty-five people left in the world, +and twenty-seven of them are hamburgers. + -- Ed Sanders +%% +There may be said to be two classes of people in the world; those who +constantly divide the people of the world into two classes and those +who do not. + -- Robert Benchley +%% +There are two ways of disliking art. +One is to dislike it. +The other is to like it rationally. + -- Oscar Wilde +%% +There are two ways of disliking poetry; +one way is to dislike it, the other is to read Pope. + -- Oscar Wilde +%% +There are two ways to write error-free +programs; only the third one works. +%% +There cannot be a crisis next week. My schedule is already full. + -- Henry Kissinger +%% +There comes a time in the affairs of a man when he +has to take the bull by the tail and face the situation. + -- W.C. Fields +%% +There comes a time to stop being angry. + -- A Small Circle of Friends +%% +There exist tasks which cannot be done +by more than 10 men or fewer than 100. + -- Steele's Law +%% +There has been a little distress selling on the stock exchange. + -- Thomas W. Lamont, October 29, 1929 +%% +There has been an alarming increase in the +number of things you know nothing about. +%% +There is a 20% chance of tomorrow. +%% +There is a fly on your nose. +%% +There is a great discovery still to be made in Literature: +that of paying literary men by the quantity they do NOT write. +%% +There is a green, multi-legged creature crawling on your shoulder. +%% +There is a theory which states that if ever anyone discovers exactly +what the Universe is for and why it is here, it will instantly disappear +and be replaced by something even more bizarre and inexplicable. There +is another theory which states that this has already happened. + -- The Hitchhiker's Guide to the Galaxy +%% +For every human problem, there is a neat, +plain solution -- and it is always wrong. + -- H.L. Mencken +%% +There is always more hell that needs raising. + -- Lauren Leveut +%% +There is always someone worse off than yourself. +%% +There is always something new out of Africa. + -- Gaius Plinius Secundus +%% +There is an innocence in admiration; it is found in those to whom it +has not yet occurred that they, too, might be admired some day. + -- Friedrich Nietzsche +%% +There is an old time toast which is golden for its beauty. +"When you ascend the hill of prosperity may you not meet a friend." + -- Mark Twain +%% +There is grandeur in this view of life, with its several powers, +having been originally breathed into a few forms or into one; and that, +whilst this planet has gone cycling on according to the fixed law of +gravity, from so simple a beginning endless forms most beautiful and +most wonderful have been, and are being, evolved. + -- Darwin +%% +There is hardly a thing in the world that some man can +not make a little worse and sell a little cheaper. +%% +There is in certain living souls +A quality of loneliness unspeakable, +So great it must be shared +As company is shared by lesser beings. +Such a loneliness is mine; so know by this +That in immensity +There is one lonelier than you. +%% +There is more to life than increasing its speed. + -- Mahatma Gandhi +%% +There is much Obi-Wan did not tell you. + -- Darth Vader +%% +There is never time to do it right, but always time to do it over. +%% +There is no comfort without pain; thus +we define salvation through suffering. + -- Cato +%% +There is no cure for birth and death other than to enjoy the interval. + -- George Santayana +%% +There is no distinction between any AI program and some existent game. +%% +There is no distinctly native American criminal class except Congress. + -- Mark Twain +%% +There is no education that is not political. An apolitical +education is also political because it is purposely isolating. +%% +There is no fear in love; but perfect love casteth out fear. +%% +There is no fool to the old fool. + -- John Heywood +%% +There is no future in time travel. +%% +There is no grief which time does not lessen and soften. +%% +There is no hunting like the hunting of man, and those who have +hunted armed men long enough and liked it, never care for anything +else thereafter. + -- Ernest Hemingway +%% +There is no ox so dumb as the orthodox. + -- George Francis Gillette +%% +There is no point in waiting. +The train stopped running years ago. +All the schedules, the brochures, +The bright-colored posters full of lies, +Promise rides to a distant country +That no longer exists. +%% +There is no proverb that is not true. + -- Cervantes +%% +There is no realizable power that man cannot, in time, fashion the tools +to attain, nor any power so secure that the naked ape will not abuse it. +So it is written in the genetic cards -- only physics and war hold him in +check. And also the wife who wants him home by five, of course. + -- Encyclopadia Apocryphia, 1990 +%% +There is no royal road to geometry. + -- Euclid +%% +There is no sadder sight than a young pessimist. +%% +There is no satisfaction in hanging a man who does not object to it. + -- G.B. Shaw +%% +There is no security on this earth. There is only opportunity. + -- General Douglas MacArthur +%% +There is no sin but ignorance. + -- Christopher Marlowe +%% +There is no such thing as a free lunch. +%% +There is no such thing as a problem without a gift for you in its hands. +%% +There is no such thing as an ugly woman -- there are only +the ones who do not know how to make themselves attractive. + -- Christian Dior +%% +There is no such thing as inner peace; there is only nervousness +or death. Any attempt to prove otherwise is a breach of manners. + -- Fran Lebowitz +%% +There is no such thing as pure pleasure; +some anxiety always goes with it. +%% +There is no time like the pleasant. +%% +There is no time like the present +for postponing what you ought to be doing. +%% +There is not much to choose between a woman who deceives +us for another, and a woman who deceives another for ourselves. + -- Augier +%% +There is nothing more silly than a silly laugh. + -- Gaius Valerius Catullus +%% +There is nothing new except what has been forgotten. + -- Marie Antoinette +%% +There is nothing so easy but that it becomes difficult +when you do it reluctantly. + -- Publius Terentius Afer (Terence) +%% +There is nothing wrong with abstinence, in moderation. +%% +There is nothing wrong with writing ... as long as it +is done in private and you wash your hands afterward. +%% +There is one difference between a tax collector and +a taxidermist -- the taxidermist leaves the hide. + -- Mortimer Caplan +%% +There is only one thing in the world worse than being +talked about, and that is not being talked about. + -- Oscar Wilde +%% +There is only one way to console a widow. But remember the risk. + -- Robert Heinlein +%% +There is only one way to kill capitalism -- +by taxes, taxes, and more taxes. + -- Karl Marx +%% +There is something fascinating about science. One gets such wholesale +returns of conjecture out of such a trifling investment of fact. + -- Mark Twain +%% +There is something in the pang of change +More than the heart can bear, +Unhappiness remembering happiness. + -- Euripides +%% +There is very little future in being right when your boss is wrong. +%% +There isn't room enough in this dress for both of us! +%% +There must be at least 500,000,000 rats in the United +States; of course, I never heard the story before. +%% +There never was a good war or a bad peace. + -- B. Franklin +%% +There once was a girl named Irene +Who lived on distilled kerosene + But she started absorbin' + A new hydrocarbon +And since then has never benzene. +%% +There once was a girl so lovely, +Who wanted to make love in the bubbly, + She strapped on her tanks, + And started her pranks, +But the lobsters all thought she was ugly. +%% +There once was an Arpanet freak, +Who better response-time did seek. + He searched coast to coast, + For a reliable host, +Whose logger took less than a week. +%% +There once was an old man from Esser, +Who's knowledge grew lesser and lesser. + It at last grew so small, + He knew nothing at all, +And now he's a College Professor. +%% +There seems no plan because it is all plan. + -- C.S. Lewis +%% +There was a phone call for you. +%% +There was a plane crash over mid-ocean, and only three survivors were +left in the life-raft: the Pope, the President, and Mayor Daley. +Unfortunately, it was a one-man life-raft, and quickly sinking, so +they started debating who should be allowed to stay. The Pope pointed +out that he was the spiritual leader of millions all over the world, +the President explained that if he died then America would be stuck +with the Vice-President, and so forth. Then Mayor Daley said, "Look! +We're not solving anything like this! The only fair thing to do is +to vote on it." So they did, and Mayor Daley won by 97 votes. +%% +There was a writer in 'Life' magazine ... who claimed that rabbits have +no memory, which is one of their defensive mechanisms. If they recalled +every close shave they had in the course of just an hour life would become +insupportable. + -- Kurt Vonnegut +%% +There was a young belle of old Natchez +Whose garments were always in patchez. + When comment arose + On the state of her clothes +She drawled, "When ah itchez, ah scratchez." +%% +There was a young lady from Bright, +Whose speed was much faster than light. + She went out one day + In a relative way +And returned on the previous night. +%% +There was a young lady from Hyde +Who ate a green apple and died. + While her lover lamented + The apple fermented +And made cider inside her inside. +%% +There was a young lady from Siam +Who said to her lover, one Kiam, + "You may kiss me of course, + But you'll have to use force. +Though God knows you're stronger than I am." +%% +There was a young man from Brazil, +And a lady who'd not take the pill, + They lay on the sofa, + And a <$H12{ot]{ok]{ob{o[]{oR{oK{oDpo~po~pot~poe~{ o!po~po~poq~ +n~po_~{o[po ~poz~pok~po\~{o +8]{o/pomF~po^~{opoh~poY~{opoc~poT~{op~po^~poO~{o[~poY~ poJ~{oF~poT~poE~{o1~ +%% +There was a young man from LeDoux, +Whose limericks stopped at line two. + +There was a young man from Verdunne. +%% +There was a young man who said "God, +I find it exceedingly odd, + That the willow oak tree + Continues to be, +When there's no one about in the Quad." + +"Dear Sir, your astonishment's odd, +For I'm always about in the Quad; + And that's why the tree, + Continues to be," +Signed "Yours faithfully, God." +%% +There was a young poet named Dan, +Whose poetry never would scan. + When told this was so, + He said, "Yes, I know. +It's because I try to put every single +syllable into the last line that I possibly, +possibly can." +%% +There was a young woman from Bude, +Who went for a swim in the nude, + But a man in a punt, + Grabbed at her elbow, +And said "Hey, lady, you can't swim here, it's private property." +%% +There was an old Indian belief that by making love on the hide of +their favorite animal, one could guarantee the health and prosperity +of the offspring conceived thereupon. And so it goes that one Indian +couple made love on a buffalo hide. Nine months later, they were +blessed with a healthy baby son. Yet another couple huddled together +on the hide of a deer and they too were blessed with a very healthy +baby son. But a third couple, whose favorite animal was a hippopotamus, +were blessed with not one, but TWO very healthy baby sons at the conclusion +of the nine month interval. All of which proves the old theorem that: +The sons of the squaw of the hippopotamus are equal to the sons of +the squaws of the other two hides. +%% +There was an old man of St. Bees, +Who was stung in the arm by a wasp. + When asked, "Does it hurt?" + He relied, "No, it doesn't. +I'm so glad that it wasn't a hornet." + -- W.S. Gilbert +%% +There was an old person of Ware +Who had an affair with a bear. + He explained, "I don't mind, + For it's gentle and kind, +But I wish it had slightly less hair." +%% +There was this New Yorker that had a lifelong ambition to be an Texan. +Fortunately, he had an Texan friend and went to him for advice. "Mike, +you know I've always wanted to be a Texan. You're a *real* Texan, what +should I do?" + "Well," answered Mike, "The first thing you've got to do is look +like a Texan. That means you have to dress right. The second thing +you've got to do is speak in a southern drawl." + "Thanks, Mike, I'll give it a try," replied the New Yorker. + A few weeks passed and the New Yorker saunters into a store dressed +in a ten-gallon hat, cowboy boots, Levi jeans and a bandanna. "Hey, there, +pardner, I'd like some beef, not too rare, and some of them fresh biscuits," +he tells the counterman. + The guy behind the counter takes a long look at him and then says, +"You must be from New York." + The New Yorker blushes, and says, "Well, yes, I am. How did +you know?" + "Because this is a hardware store." +%% +There were the Scots +Who kept the Sabbath +And everything else they could lay their hands on. +Then there were the Welsh +Who prayed on their knees and their neighbors. +Thirdly there were the Irish +Who never knew what they wanted +But were willing to fight for it anyway. +Lastly there were the English +Who considered themselves a self-made nation +Thus relieving the Almighty of a dreadful responsibility. +%% +There will be big changes for you but you will be happy. +%% +There's a couple of million dollars worth of baseball talent on the loose, +ready for the big leagues, yet unsigned by any major league. There are +pitchers who would win 20 games a season ... and outfielders [who] could +hit .350, infielders who could win recognition as stars, and there's at +least one catcher who at this writing is probably superior to Bill Dickey, +Josh Gibson. Only one thing is keeping them out of the big leagues, the +pigmentation of their skin. They happen to be colored. + -- Shirley Povich, 1941 +%% +There's a fine line between courage and foolishness. +Too bad it's not a fence. +%% +There's a lot to be said for not saying a lot. +%% +There's a man deeply in debt, see, and he takes the money he has left +and goes to Monte Carlo to try to recoup at the roulette tables. Won a +little, lost a lot, and was down to his last franc. Prayed for help. +A voice whispered in his ear: "Le rouge..." Man looked around; nobody +there. What the hell -- he puts his last franc on the red, and it won. +The voice immediately said, "Encore le rouge..." Played red again, and +it won again. The voice said, "Impair..." Played odd, and it won. Voice +said, "Quinze..." so he put all the money on 15, and it won. This went +on for hours, the voice telling him what to bet, and the man putting all +his money on what the voice said, and winning. Finally when the voice +spoke, the man protested that he'd won millions of dollars and wanted to +quit. The voice was inexorable: "Douze..." The man put the money on 12, +and 11 came up -- he had lost everything -- the voice murmured "Merde!!" +%% +There's a thrill in store for all for we're about to toast +The corporation that we represent. +We're here to cheer each pioneer and also proudly boast, +Of that man of men our sterling president +The name of T.J. Watson means +A courage none can stem +And we feel honored to be here to toast the IBM. + -- Ever Onward, from the 1940 IBM Songbook +%% +There's a trick to the Graceful Exit. It begins with the vision to +recognize when a job, a life stage, a relationship is over -- and to +let go. It means leaving what's over without denying its validity +or its past importance in our lives. It involves a sense of future, +a belief that every exit line is an entry, that we are moving on, +rather than out. The trick of retiring well may be the trick of +living well. It's hard to recognize that life isn't a holding +action, but a process. It's hard to learn that we don't leave the +best parts of ourselves behind, back in the dugout or the office. +We own what we learned back there. The experiences and the growth +are grafted onto our lives. And when we exit, we can take ourselves +along -- quite gracefully. + -- Ellen Goodman +%% +There's a whole WORLD in a mud puddle! + -- Doug Clifford +%% +There's an old proverb that says just about whatever you want it to. +%% +There's been no top authority saying what marijuana does to you. +I really don't know that much about it. I tried it once but it +didn't do anything to me. + -- John Wayne +%% +There's got to be more to life than compile-and-go. +%% +There's just something I don't like about Virginia; the state. +%% +There's little in taking or giving, + There's little in water or wine: +This living, this living, this living, + Was never a project of mine. +Oh, hard is the struggle, and sparse is + The gain of the one at the top, +For art is a form of catharsis, + And love is a permanent flop, +And work is the provence of cattle, + And rest's for a clam in a shell, +So I'm thinking of throwing the battle -- + Would you kindly direct me to hell? + -- Dorothy Parker +%% +There's no future in time travel. +%% +There's no heavier burden than a great potential. +%% +There's no justice in this world. + -- Frank Costello + On the prosecution of "Lucky" Luciano by New York district + attorney Thomas Dewey after Luciano had saved Dewey from + assassination by Dutch Schultz (by ordering the assassination + of Schultz instead) +%% +There's no point in being grown up if you can't be childish sometimes. + -- Dr. Who +%% +There's no room in the drug world for amateurs. + -- Raoul Duke +%% +There's no saint like a reformed sinner. +%% +There's no such thing as an original sin. + -- Elvis Costello +%% +There's no such thing as pure pleasure; some anxiety always goes with it. +%% +There's no time like the pleasant. +%% +There's no use being precise about something +when you don't even know what you're talking about. + -- John von Neumann +%% +There's no use in having a dog and doing your own barking. +%% +There's nothing like a girl with a plunging +neckline to keep a man on his toes. +%% +There's nothing like good food, good wine, and a bad girl. +%% +There's nothing like the face of a kid eating a Hershey bar. +%% +There's nothing very mysterious about you, except that +nobody really knows your origin, purpose, or destination. +%% +There's nothing worse for your business than +extra Santa Clauses smoking in the men's room. + -- W. Bossert +%% +There's one fool at least in every married couple. +%% +There's only one everything. +%% +There's only one way to have a happy marriage +and as soon as I learn what it is I'll get married again. + -- Clint Eastwood +%% +There's small choice in rotten apples. + -- William Shakespeare, "The Taming of the Shrew" +%% +There's so much plastic in this culture that +vinyl leopard skin is becoming an endangered synthetic. + -- Lily Tomlin +%% +There's so much to say but your eyes keep interrupting me. +%% +There's too much beauty upon this earth for lonely men to bear. + -- Richard Le Gallienne +%% +These activities have their own rules and methods +of concealment which seek to mislead and obscure. + -- Dwight D. Eisenhower, 1960 +%% +These days the necessities of life cost you about three times what +they used to, and half the time they aren't even fit to drink. +%% +They also serve who only stand and wait. + -- John Milton +%% +They also surf who only stand on waves. +%% +They are called computers simply because computation is +the only significant job that has so far been given to them. +%% +They are ill discoverers that think there is no land, +when they can see nothing but sea. + -- Francis Bacon +%% +They are relatively good but absolutely terrible. + -- Alan Kay, commenting on Apollos +%% +They can't stop us... we're on a mission from God! + -- The Blues Brothers +%% +They couldn't hit an elephant at this dist... + -- Civil War General John Sedgwick, his last + words, Battle of Spotsylvania Court House, 1864 +%% +They don't suffer. They can't even speak English. + -- George F. Baer, answering a reporter's + question about the suffering of starving miners. +%% +They have been at a great feast of languages, and stolen the scraps. + -- William Shakespeare, "Love's Labour's Lost" +%% +They just buzzed and buzzed...buzzed. +%% +They spell it Vinci and pronounce it Vinchy. +Foreigners always spell better than they pronounce. + -- Mark Twain +%% + "They spend years searching for their natural parents, convinced their +parents will be happy to see them. I mean, really, can you imagine someone +being happy to see an orphan? Nobody wants them... that's why they're orphans!" + The speaker is Anne Baker, founder and guiding force behind +Orphan-Off, an organization dedicated to keeping orphans confused about the +whereabouts of their natural parents. She is a woman with a mission: + "Basically, what we do is band together to exchange information +about which orphans are looking for which parents in what part of the +country. We're completely computerized. + "The idea is to throw the orphans as many red herrings and false +leads as possible. We'll tell some twenty-three-year-old loser that his +real parents can be found at a certain address on the other side of the +country. Well, by the time the kid shows up, the family is prepared. They +look over the kid's photos and information and they say, 'Oh, the Emersons... +yeah, they used to live here... I think they moved out about five years ago. +I think they went to Iowa, or maybe Idaho.' + "Bam, the door shuts in the kid's face and he's back to zero again. +He's got nothing to go on but the orphan's pathetic determination to continue. + "It's really amazing how much these kids will put up with. Last year +we even sent one kid all the way to Australia. I mean, really. Besides, if +your natural parents were Australian, would you want to meet them?" + -- "National Lampoon", September, 1984 +%% +They told me you had proven it When they discovered our results +About a month before. Their hair began to curl +The proof was valid, more or less Instead of understanding it +But rather less than more. We'd run the thing through PRL. + +He sent them word that we would try Don't tell a soul about all this +To pass where they had failed For it must ever be +And after we were done, to them A secret, kept from all the rest +The new proof would be mailed. Between yourself and me. + +My notion was to start again +Ignoring all they'd done +We quickly turned it into code +To see if it would run. +%% +They took some of the Van Goghs, most +of the jewels, and all of the Chivas! +%% +They went rushing down that freeway, +Messed around and got lost. +They didn't care... they were just dying to get off, +And it was life in the fast lane. + -- Eagles, "Life in the Fast Lane" +%% +They wouldn't listen to the fact that I was a genius, +The man said "We got all that we can use", +So I've got those steadily-depressin', low-down, mind-messin', +Working-at-the-car-wash blues. + -- Jim Croce +%% +They're just jealous because they don't have three +wise men and a virgin in the whole organization. + -- Mayor Vincent J. `Buddy' Cianci, on the + ACLU's suit to have a city nativity scene removed. +%% +They're only trying to make me LOOK paranoid! +%% +Things are more like they are today than they ever were before. + -- Dwight Eisenhower +%% +Things are more like they used to be than they are new. +%% +Things are not always what they seem. + -- Phaedrus +%% +Things equal to nothing else are equal to each other. +%% +Things fall apart; the centre cannot hold. +%% +Things past redress and now with me past care. + -- William Shakespeare, "Richard II" +%% +Things will be bright in P.M. +A cop will shine a light in your face. +%% +Things will get better despite our efforts to improve them. + -- Will Rogers +%% +Things worth having are worth cheating for. +%% +Think big. +Pollute the Mississippi. +%% +Think honk if you're a telepath. +%% +Think lucky. If you fall in a pond, check your pockets for fish. + -- Darrell Royal +%% +Think of it! With VLSI we can pack 100 ENIACs in 1 sq. cm.! +%% +Think of your family tonight. +Try to crawl home after the computer crashes. +%% +Think sideways! + -- Ed De Bono +%% +Think twice before speaking, but don't say "think think click click". +%% +Thinks't thou existence doth depend on time? +It doth; but actions are our epochs; mine +Have made my days and nights imperishable, +Endless, and all alike, as sands on the shore, +Innumerable atoms; and one desert, +Barren and cold, on which the wild waves break, +But nothing rests, save carcasses and wrecks, +Rocks, and the salt-surf weeds of bitterness. +%% +Thirteen at a table is unlucky only +when the hostess has only twelve chops. + -- Groucho Marx +%% +Thirty white horses on a red hill, +First they champ, +Then they stamp, +Then they stand still. + -- Tolkien +%% +This door is baroquen, please wiggle Handel. +(If I wiggle Handel, will it wiggle Bach?) + -- Found on a door in the MSU music building +%% +This dungeon is owned and operated by Frobazz Magic Co., Ltd. +%% +This file will self-destruct in five minutes. +%% +This fortune cookie program out of order. For those in desperate +need, please use the program "randchar". This program generates +random characters, and, given enough time, will undoubtedly come +up with something profound. It will, however, take it no time at +all to be more profound than THIS program has ever been. +%% +This fortune intentionally not included. +%% +This fortune intentionally says nothing. +%% +This fortune is dedicated to your mother, without whose +invaluable assistance last night would never have been possible. +%% +This fortune is encrypted -- get your decoder rings ready! +%% +This fortune is inoperative. Please try another. +%% +This fortune soaks up 47 times its own weight in excess memory. +%% +This fortune was brought to you by the people at Hewlett-Packard. +%% +This fortune would be seven words long if it were six words shorter. +%% +This is Betty Frenel. I don't know who to call but I can't reach my +Food-a-holics partner. I'm at Vido's on my second pizza with sausage +and mushroom. Jim, come and get me! +%% +This is Jim Rockford. +At the tone leave your name and message; I'll get back to you. +%% +This is Maria, Liberty Bail Bonds. Your client, Todd Lieman, skipped and +his bail is forfeit. That's the pink slip on your '74 Firebird, I believe. +Sorry, Jim, bring it on over. +%% +This is Marilyn Reed, I wanta talk to you... Is this a machine? +I don't talk to machines! [Click] +%% +This is NOT a repeat. +%% +This is National Non-Dairy Creamer Week. +%% +This is a country where people are free to practice their religion, +regardless of race, creed, color, obesity, or number of dangling keys... +%% +This is a good time to punt work. +%% +This is a test of the emergency broadcast system. +Had there been an actual emergency, then you would no longer be here. +%% +This is for all ill-treated fellows + Unborn and unbegot, +For them to read when they're in trouble + And I am not. + -- A.E. Housman +%% +This is the Baron. Angel Martin tells me you buy information. Ok, +meet me at one a.m. behind the bus depot, bring five-hundred dollars +and come alone. I'm serious! +%% +This is the sort of English up with which I will not put. + -- Winston Churchill +%% +This is the theory that Jack built. +This is the flaw that lay in the theory that Jack built. +This is the palpable verbal haze that hid the flaw that lay in... +%% +This isn't right. This isn't even wrong. + -- Wolfgang Pauli, on a colleague's paper +%% +This land is my land, and only my land, +I've got a shotgun, and you ain't got one, +If you don't get off, I'll blow your head off, +This land is private property. + -- Apologies to Woody Guthrie +%% +This life is a test. It is only a test. Had this been an +actual life, you would have received further instructions as +to what to do and where to go. +%% +This life is yours. Some of it was given +to you; the rest, you made yourself. +%% +This login session: $13.76, but for you $11.88. +%% +This login session: $13.99 +%% +This night methinks is but the daylight sick. + -- William Shakespeare, "The Merchant of Venice" +%% +This planet has -- or rather had -- a problem, which was this: most of +the people living on it were unhappy for pretty much of the time. Many +solutions were suggested for this problem, but most of these were +largely concerned with the movements of small green pieces of paper, +which is odd because on the whole it wasn't the small green pieces of +paper that were unhappy. + -- Douglas Adams +%% +This sad little lizard told me that he was a brontosaurus on his +mother's side. I did not laugh; people who boast of ancestry +often have little else to sustain them. Humoring them costs nothing and +adds happiness in a world in which happiness is always in short supply. + -- Lazarus Long +%% +This screen intentionally left blank. +%% +This sentence does in fact not have the property it claims not to have. +%% +This sentence no verb. +%% +This system will self-destruct in five minutes. +%% +This thing all things devours: +Birds, beasts, trees, flowers; +Gnaws iron, bites steel; +Grinds hard stones to meal; +Slays king, ruins town, +And beats high mountain down. +%% +This unit... must... survive. +%% +This was a Golden Age, a time of high adventure, rich living, and hard +dying... but nobody thought so. This was a future of fortune and theft, +pillage and rapine, culture and vice... but nobody admitted it. + -- Alfred Bester, "The Stars My Destination" +%% +This was the most unkindest cut of all. + -- William Shakespeare, "Julius Caesar" +%% +This wasn't just plain terrible, this was fancy terrible. +This was terrible with raisins in it. + -- Dorothy Parker +%% +This will be a memorable month -- no matter how hard you try to forget it. +%% +The world is a comedy to those who think, +and a tragedy to those who feel. + -- Horace Walpole +%% + Thompson, if he is to be believed, has sampled the entire rainbow of +legal and illegal drugs in heroic efforts to feel better than he does. + As for the truth about his health: I have asked around about it. I +am told that he appears to be strong and rosy, and steadily sane. But we +will be doing what he wants us to do, I think, if we consider his exterior +a sort of Dorian Gray facade. Inwardly, he is being eaten alive by tinhorn +politicians. + The disease is fatal. There is no known cure. The most we can do +for the poor devil, it seems to me, is to name his disease in his honor. +From this moment on, let all those who feel that Americans can be as easily +led to beauty as to ugliness, to truth as to public relations, to joy as to +bitterness, be said to be suffering from Hunter Thompson's disease. I don't +have it this morning. It comes and goes. This morning I don't have Hunter +Thompson's disease. + -- Kurt Vonnegut Jr., on Dr. Hunter S. Thompson: Excerpt + from "A Political Disease", Vonnegut's review of "Fear and + Loathing: On the Campaign Trail '72" +%% +Those of you who think you know everything +are annoying those of us who do. +%% +Those of you who think you know it all upset those of us who do. +%% +Those who can, do; those who can't, simulate. +%% +Those who can, do; those who can't, write. +Those who can't write work for the Bell Labs Record. +%% +Those who cannot remember the past are condemned to repeat it. + -- George Santayana +%% +Those who can't write, write manuals. +%% +Those who claim the dead never return +to life haven't ever been around here at quitting time. +%% +Those who do things in a noble spirit of +self-sacrifice are to be avoided at all costs. + -- N. Alexander. +%% +Those who educate children well are more to be honored than +parents, for these only gave life, those the art of living well. + -- Aristotle +%% +Those who in quarrels interpose, must often wipe a bloody nose. +%% +Those who like sausages and the law had better not watch either one being made. +%% +Those who make peaceful revolution impossible +will make violent revolution inevitable. + -- John Fitzgerald Kennedy +%% +Those who talk don't know. Those who don't talk, know. +%% +Thou hast seen nothing yet. + -- Miguel de Cervantes +%% +Thrashing is just virtual crashing. +%% +Three Midwesterners, a Kansan, a Missourian and an Iowan, +all appearing on a quiz program, were asked to complete this sentence: +"Old MacDonald had a . . ." + + "Old MacDonald had a carburetor," answered the Kansan. + "Sorry, that's wrong," the game show host said. + "Old MacDonald had a free brake alignment down at the + service station," said the Missourian. + "Wrong." + "Old MacDonald had a farm," said the Iowan. + "CORRECT!" shouts the quizmaster. "Now for $100,000, spell 'farm.'" + "Easy," said the Iowan. "E-I-E-I-O." +%% +Three Rings for the Elven-kings under the sky, +Seven for the Dwarf-lords in their halls of stone, +Nine for Mortal Men doomed to die, +One for the Dark Lord on his dark throne +In the Land of Mordor where the Shadows lie. +One Ring to rule them all, One Ring to find them, +One Ring to bring them all and in the darkness bind them +In the Land of Mordor where the Shadows lie. + -- J.R.R. Tolkien, "The Lord of the Rings" +%% +Three great scientific theories of the structure of the universe are +the molecular, the corpuscular and the atomic. A fourth affirms, with +Haeckel, the condensation or precipitation of matter from ether -- +whose existence is proved by the condensation or precipitation... +A fifth theory is held by idiots, but it is doubtful if they know any +more about the matter than the others. +%% +Three hours a day will produce as much as a man ought to write. + -- Trollope +%% +Three may keep a secret if two of them are dead. + -- B. Franklin +%% +Three may keep a secret, if two of them are dead. + -- Ben Franklin +%% +Three o'clock is always too late or too early for anything you want to do. + -- Jean-Paul Sartre +%% +Three rules for sounding like an expert: +1. Oversimplify your explanations to the point of uselessness. +2. Always point out second-order effects, + but never point out when they can be ignored. +3. Come up with three rules. +%% +Three things have been difficult to tame: The oceans, fools, +and women. We may soon be able to tame the ocean. Fools and +women will take a little longer. + -- Spiro Agnew +%% +Three young women were attending the same logic class given at one of the +better universities. During a lecture the professor stated that he was +going to test their ability at situation reasoning. + "Let us assume," said the prof, "that you are aboard a small craft +alone in the Pacific, and you spot a vessel approaching you with several +sex-starved sailors on board. What would you do in this situation to avoid +the problem?" + "I would attempt to turn my craft in the opposite direction and +flee," said the first girl. + "I would pass them, and hope that I could fend them off," responded +the second woman. + "Frankly," murmured the third woman, "I understand the situation, +but I fail to see the problem." +%% +Thus mathematics may be defined as the +subject in which we never know what we are talking about, +nor whether what we are saying is true. + -- Bertrand Russell +%% +Thyme's Law: + Everything goes wrong at once. +%% +Ticking away the moments that make up a dull day +Fritter and waste the hours in an offhand way +Kicking around on a piece of ground in your hometown +Waiting for someone or something to show you the way + +Tired of lying in the sunshine And then one day you find +Staying home to watch the rain Ten years have got behind you +You are young and life is long No one told you when to run +And there is time to kill today You missed the starting gun + +And you run and you run to catch up with the sun but it's sinking +And racing around to come up behind you again +The sun is the same in a relative way but you're older +Shorter of breath and one day closer to death + +Every year is getting shorter Hanging on in quiet desperation + is the English way +Never seem to find the time The time is gone, the song is over +Plans that either come to nought Thought I'd something more to say... +Or half a page of scribbled lines + -- Pink Floyd, "Time" +%% +Tiddely Quiddely +Edward M. Kennedy +Quite unaccountably +Drove in a stream. + +Pleas of amnesia +Incomprehensible +Possibly shattered +Political dream. +%% +Time and tide wait for no man. +%% +Time as he grows old teaches all things. + -- Aeschylus +%% +Time flies like an arrow. Fruit flies like a banana. +%% +Time goes, you say? +Ah no! +Time stays, *we* go. + -- Austin Dobson +%% +Time is an illusion, lunchtime doubly so. + -- The Hitchhiker's Guide to the Galaxy +%% +Time is an illusion perpetrated by the manufacturers of space. +%% +Time is but the stream I go a-fishing in. + -- Henry David Thoreau +%% +Time is nature's way of making sure +that everything doesn't happen at once. +%% +Time is the most valuable thing a man can spend. + -- Theophrastus +%% +Time sure flies when you don't know what you're doing. +%% +Time to be aggressive. Go after a tattooed Virgo. +%% +Time to take stock. +Go home with some office supplies. +%% +Time washes clean +Love's wounds unseen. +That's what someone told me; +But I don't know what it means. + -- Linda Ronstadt, "Long Long Time" +%% +Time will end all my troubles, +but I don't always approve of Time's methods. +%% +Time-sharing is the junk-mail part of the computer business. + -- H.R.J. Grosch (attributed) +%% +Timing must be perfect now. +Two-timing must be better than perfect. +%% +Tip the world over on its side and +everything loose will land in Los Angeles. + -- Frank Lloyd Wright +%% + To A Quick Young Fox +Why jog exquisite bulk, fond crazy vamp, +Daft buxom jonquil, zephyr's gawky vice? +Guy fed by work, quiz Jove's xanthic lamp-- +Zow! Qualms by deja vu gyp fox-kin thrice. + -- Lazy Dog +%% +To Theodore Roosevelt: + You are like the Wind and I like the Lion. You form the Tempest. +The sand stings my eyes and the Ground is parched. I roar in defiance but +you do not hear. But between us there is a difference. I, like the lion, +must remain in my place. While you, like the wind, will never know yours. + Mulay Hamid El Raisuli + Lord of the Riff + Sultan to the Berbers + Last of the Barbary Pirates +%% +To add insult to injury. + -- Phaedrus +%% +To any truly impartial person, it would +be obvious that I am always right. +%% +To avoid criticism, do nothing, say nothing, be nothing. + -- Elbert Hubbard +%% +To be a kind of moral Unix, he touched the hem of Nature's shift. + -- Shelley +%% +To be beautiful is enough! if a woman can do that well who +should demand more from her? You don't want a rose to sing. + -- Thackeray +%% +To be considered successful, a woman must be much better at her job +than a man would have to be. Fortunately, this isn't difficult. +%% +To be excellent when engaged in administration is to be like the North +Star. As it remains in its one position, all the other stars surround it. + -- Confucius +%% +To be great is to be misunderstood. + -- Ralph Waldo Emerson +%% +To be happy one must be a) well fed, unhounded by sordid cares, at ease in +Zion, b) full of a comfortable feeling of superiority to the masses of one's +fellow men, and c) delicately and unceasingly amused according to one's taste. +It is my contention that, if this definition be accepted, there is no country +in the world wherein a man constituted as I am -- a man of my peculiar +weaknesses, vanities, appetites, and aversions -- can be so happy as he can +be in the United States. Going further, I lay down the doctrine that it is +a sheer physical impossibility for such a man to live in the United States +and not be happy. + -- H.L. Mencken, "On Being An American" +%% +To be is to be related. + -- C.J. Keyser. +%% +To be is to do. + -- I. Kant +To do is to be. + -- A. Sartre +Yabba-Dabba-Doo! + -- F. Flintstone +%% +To be nobody-but-yourself in a world which is doing its best to, +night and day, to make you everybody else -- means to fight the hardest +battle which any human being can fight; and never stop fighting. + -- E.E. Cummings, "A Miscellany" +%% +To be or not to be, that is the bottom line. +%% +To be or not to be. + -- Shakespeare +To do is to be. + -- Nietzsche +To be is to do. + -- Sartre +Do be do be do. + -- Sinatra +%% +To be successful, a woman has to be much better at her job than a man. + -- Golda Meir +%% +To be successful, a woman must do her job ten times +as well as a man. Fortunately, this is not difficult. +%% +To be sure of hitting the target, shoot first +and, whatever you hit, call it the target. +%% +To be who one is, is not to be someone else. +%% +To be wise, the only thing you really need +to know is when to say "I don't know." +%% +To believe your own thought, to believe that what is true for +you in your private heart is true for all men -- that is genius. + -- Ralph Waldo Emerson +%% +To communicate is the beginning of understanding. + -- AT&T +%% +To craunch a marmoset. + -- Pedro Carolino, "English as She is Spoke" +%% +To criticize the incompetent is easy; +it is more difficult to criticize the competent. +%% +To defend the Saigon regime is not worth one more human life. + -- Senator Edmund Muskie +%% +To do nothing is to be nothing. +%% +To do two things at once is to do neither. + -- Publilius Syrus +%% +To doubt everything or to believe everything are two equally +convenient solutions; both dispense with the necessity of reflection. + -- H. Poincare +%% +To err is human, but I can REALLY foul things up. +%% +To err is human, but to really foul things up requires a computer. +%% +To err is human; to admit it, a blunder. +%% +To err is human, to forgive is Not Company Policy. +%% +To err is human, to forgive is against company policy. +%% +To err is human, to forgive unusual. +%% +To err is human, to repent, divine, to persist, devilish. + -- Benjamin Franklin +%% +To err is human. +To blame someone else for your mistakes is even more human. +%% +To err is humor. +%% +To fear love is to fear life, and those +who fear life are already three parts dead. + -- Bertrand Russell +%% +To find out a girl's faults, praise her to her girl friends. + -- Benjamin Franklin +%% +To give happiness is to deserve happiness. +%% +To give of yourself, you must first know yourself. +%% +To have died once is enough. + -- Publius Vergilius Maro (Virgil) +%% +To hell with the Prime Directive; +Let's KILL something! +%% +To invent, you need a good imagination and a pile of junk. + -- Thomas Edison +%% +To iterate is human, to recurse, divine. + -- Robert Heller +%% +To keep your friends treat them kindly; +to kill them, treat them often. +%% +To know Edina is to reject it. + -- Dudley Riggs, "The Year the Grinch Stole the Election" +%% +To laugh at men of sense is the privilege of fools. +%% +To lead people, you must follow behind. + -- Lao Tsu +%% +To listen to some devout people, +one would imagine that God never laughs. + -- Sri Aurobindo +%% +To love is good, love being difficult. +%% +To make an enemy, do someone a favor. +%% +To make tax forms true they should +read "Income Owed Us" and "Incommode You". +%% +To many, total abstinence is easier than perfect moderation. + -- St. Augustine +%% +To refuse praise is to seek praise twice. +%% +To restore a sense of reality, I think +Walt Disney should have a Hardluckland. + -- Jack Paar +%% +To save a single life is better than to build a seven story pagoda. +%% +To say you got a vote of confidence +would be to say you needed a vote of confidence. + -- Andrew Young +%% +To see a need and wait to be asked, is to already refuse. +%% +To see the butcher slap the steak, before he laid it on the block, +and give his knife a sharpening, was to forget breakfast instantly. It was +agreeable, too -it really was- to see him cut it off, so smooth and juicy. +There was nothing savage in the act, although the knife was large and keen; +it was a piece of art, high art; there was delicacy of touch, clearness of +tone, skilful handling of the subject, fine shading. It was the triumph of +mind over matter; quite. + -- Dickens, "Martin Chuzzlewit" +%% +To spot the expert, pick the one who predicts +the job will take the longest and cost the most. +%% +To stay young requires unceasing cultivation +of the ability to unlearn old falsehoods. + -- Lazarus Long, "Time Enough For Love" +%% +To stay youthful, stay useful. +%% +To teach is to learn. +%% +To teach is to learn twice. + -- Joseph Joubert +%% +To the landlord belongs the doorknobs. +%% +To thine own self be true. +(If not that, at least make some money.) +%% +To those accustomed to the precise, structured methods of conventional +system development, exploratory development techniques may seem messy, +inelegant, and unsatisfying. But it's a question of congruence: +precision and flexibility may be just as disfunctional in novel, +uncertain situations as sloppiness and vacillation are in familiar, +well-defined ones. Those who admire the massive, rigid bone structures +of dinosaurs should remember that jellyfish still enjoy their very +secure ecological niche. + -- Beau Sheil, "Power Tools for Programmers" +%% +To understand a program you must become both the machine and the program. +%% +To use violence is to already be defeated. + -- Chinese proverb +%% +To whom the mornings are like nights, +What must the midnights be! + -- Emily Dickinson (on hacking?) +%% +To you I'm an atheist; to God, I'm the loyal opposition. + -- Woody Allen +%% +Tobacco is a filthy weed, +That from the devil does proceed; +It drains your purse, it burns your clothes, +And makes a chimney of your nose. + -- B. Waterhouse +%% +Today is National Existential Ennui Awareness Day. +%% +Today is a good day for information-gathering. +Read someone else's mail file. +%% +Today is a good day to bribe a high-ranking public official. +%% +Today is gonna be one helluva week! +%% +Today is the first day of the rest of the mess. +%% +Today is the first day of the rest of your life. +%% +Today is the first day of the rest of your lossage. +%% +Today is the last day of your life so far. +%% +Today is the tomorrow you worried about yesterday. +%% +Today is what happened to yesterday. +%% +Todays title: + Creative Violence in Sexual Relationships +%% +Todays weirdness is tomorrows reason why. + -- H.S. Thompson +%% +Tomorrow, this will be part of the unchangeable past +but fortunately, it can still be changed today. +%% +Tomorrow will be cancelled due to lack of interest. +%% +Tomorrow, you can be anywhere. +%% +Tomorrow's computers some time next month. + -- DEC +%% +Tom's hungry, time to eat lunch. +%% +Tonight you will pay the wages of sin; +Don't forget to leave a tip. +%% +Tonight's the night: Sleep in a eucalyptus tree. +%% +Toni's Solution to a Guilt-Free Life: + If you have to lie to someone, it's their fault. +%% +Too clever is dumb. + -- Ogden Nash +%% +Too cool to calypso, +Too tough to tango, +Too weird to watusi + -- The Only Ones +%% +Too much is just enough. + -- Mark Twain, on whiskey +%% +Too much is not enough. +%% +Too much of a good thing is WONDERFUL. + -- Mae West +%% +Too often people have come to me and said, "If I had just one wish for +anything in all the world, I would wish for more user-defined equations +in the HP-51820A Waveform Generator Software." + -- Instrument News + [Once is too often. Ed.] +%% +Toothpaste never hurts the taste of good scotch. +%% +Topologists are just plane folks. + Pilots are just plane folks. + Carpenters are just plane folks. + Midwest farmers are just plain folks. + Musicians are just playin' folks. + Whodunit readers are just Spillaine folks. +Some Londoners are just P. Lane folks. +%% +Torque is cheap. +%% +Toto, I don't think we're in Kansas anymore. + -- Judy Garland, "Wizard of Oz" +%% +Trap full -- please empty. +%% +Travel important today; Internal Revenue men arrive tomorrow. +%% +Traveling through hyperspace isn't like dusting crops, boy. + -- Han Solo +%% +Treat your friend as if he might become an enemy. + -- Publilius Syrus +%% +Treaties are like roses and young girls. They last while they last. + -- Charles de Gaulle +%% +Troglodytism does not necessarily imply a low cultural level. +%% +Trouble always comes at the wrong time. +%% +Troubled day for virgins over 16 who are +beautiful and wealthy and live in eucalyptus trees. +%% +Troubles are like babies; they only grow by nursing. +%% +True happiness will be found only in true love. +%% +True leadership is the art of changing +a group from what it is to what it ought to be. + -- Virginia Allan +%% +Truly great madness can not be achieved without significant intelligence. + -- Henrik Tikkanen +%% +Truly simple systems... require infinite testing. + -- Norman Augustine +%% +Trust your husband, adore your husband, +and get as much as you can in your own name. + -- Joan Rivers +%% +Truth has no special time of its own. Its hour is now -- always. + -- Albert Schweitzer +%% +Truth is hard to find and harder to obscure. +%% +Truth will out this morning. (Which may really mess things up.) +%% +Try again. +%% +Try not to have a good time ... +This is supposed to be educational. + -- Charles Schulz +%% +Try not. +Do. +Or do not. +There is no try. +%% +Try `stty 0' -- it works much better. +%% +Try the Moo Shu Pork. It is especially good today. +%% +Try to be the best of whatever you are, even if what you are is no good. +%% +Try to be the best of whatever you are, +even if what you are is no good. +%% +Try to divide your time evenly to keep others happy. +%% +Try to get all of your posthumous medals in advance. +%% +Try to have as good a life as you can under the circumstances. +%% +Try to value useful qualities in one who loves you. +%% +Trying to be happy is like trying to build a machine for +which the only specification is that it should run noiselessly. +%% +Trying to get an education here is like +trying to take a drink from a fire hose. +%% +T-shirt of the Week: + I'm not excited, I'm cold! +%% +Tuesday After Lunch is the cosmic time of the week. +%% +Tuesday is the Wednesday of the rest of your life. +%% +Turn on, tune in, and take over. + -- Tim Leary +%% +Turn the other cheek. + -- Jesus Christ +%% +Turnaucka's Law: + The attention span of a computer is only as long as its + electrical cord. +%% +Tussman's Law: + Nothing is as inevitable as a mistake whose time has come. +%% +'Twas a woman who drove me to drink, +and I never even had the decency to thank her. + -- R.B. Gossling +%% +'Twas brillig, and the slithy toves And as in uffish thought he stood +Did gyre and gimble in the wabe. The Jabberwock, with eyes aflame +All mimsy were the borogroves Came whuffling through the tulgey wood +And the mome raths outgrabe. And burbled as it came! + +"Beware the Jabberwock, my son! One! Two! One! Two! +The jaws that bite, and through and through + the claws that catch! The vorpal blade went snicker-snack. +Beware the Jubjub bird, He left it dead, and took its head, +And shun the frumious Bandersnatch!" And went galumphing back. + +He took his vorpal sword in hand "Hast thou slain the Jabberwock? +Long time the manxome foe he sought. Come to my arms, my beamish boy! +So rested he by the tumtum tree Oh frabjous day! Calooh! Callay!" +And stood awhile in thought. He chortled in his joy. + + 'Twas brillig, and the slithy toves + Did gyre and gimble in the wabe. + All mimsy were the borogroves + -- Lewis Carroll +%% +'Twas midnight, and the UNIX hacks +Did gyre and gimble in their cave +All mimsy was the CS-VAX +And Cory raths outgrave. + +"Beware the software rot, my son! +The faults that bite, the jobs that thrash! +Beware the broken pipe, and shun +The frumious system crash!" +%% +Twenty two thousand days. +Twenty two thousand days. +It's not a lot. +It's all you've got. +Twenty two thousand days. + -- Moody Blues, "Twenty Two Thousand Days" +%% +Twenty years of romance make a woman look like a ruin; but +twenty years of marriage make her something like a public building. + -- Wilde +%% +Two can Live as Cheaply as One for Half as Long. + -- Howard Kandel +%% +Two cars in every pot and a chicken in every garage. +%% +Two heads are better than one. + -- John Heywood +%% +Two heads are more numerous than one. +%% +Two hundred years ago today, Irma Chine of White Plains, New York, was +performing her normal housekeeping routines. She was interrupted by +British soldiers who, rallying to the call of their supervisor, General +Hughes, sought to gain control of the voter registration lists kept in +her home. Masking her fear and thinking fast, Mrs. Chine quickly divided +a nearby apple in two and deftly stored the list in its center. Upon +entering, the British blatantly violated every conceivable convention, +and, though they went through the house virtually bit by bit, their +search was fruitless. They had to return empty handed. Word of the +incident propagated rapidly through the region. This historic event +became the first documented use of core storage for the saving of registers. +%% +Two is company, three is an orgy. +%% +Two is not equal to three, even for large values of two. +%% +Two men look out through the same bars; one sees mud, and one the stars. +%% + Two men looked out from the prison bars, + One saw mud-- + The other saw stars. + +Now let me get this right: two prisoners are looking out the window. +While one of them was looking at all the mud -- the other one got hit +in the head. +%% +Two men were sitting over coffee, contemplating the nature of things, +with all due respect for their breakfast. "I wonder why it is that +toast always falls on the buttered side," said one. + "Tell me," replied his friend, "why you say such a thing. Look +at this." And he dropped his toast on the floor, where it landed on the +dry side. + "So, what have you to say for your theory now?" + "What am I to say? You obviously buttered the wrong side." +%% +Two percent of zero is almost nothing. +%% +Two rights don't make a wrong, they make an airplane. +%% +Two wrongs are only the beginning. + -- Kohn +%% +Tyger, Tyger, burning bright Where the hammer? Where the chain? +In the forests of the night, In what furnace was thy brain? +What immortal hand or eye What the anvil? What dread grasp +Dare frame thy fearful symmetry? Dare its deadly terrors clasp? + +Burnt in distant deeps or skies When the stars threw down their spears +The cruel fire of thine eyes? And water'd heaven with their tears +On what wings dare he aspire? Dare he laugh his work to see? +What the hand dare seize the fire? Dare he who made the lamb make thee? + +And what shoulder & what art Tyger, Tyger, burning bright +Could twist the sinews of they heart? In the forests of the night, +And when thy heart began to beat What immortal hand or eye +What dread hand & what dread feet Dare frame thy fearful symmetry? + +Could fetch it from the furnace deep +And in thy horrid ribs dare steep +In the well of sanguine woe? +In what clay & in what mould +Were thy eyes of fury roll'd? + -- William Blake, "The Tyger" +%% +Type louder, please. +%% +UFO's are for real: the Air Force doesn't exist. +%% +UNFAIR COMPETITION: + Selling cheaper than we do. +%% +UNION: + A dues-paying club workers wield to strike management. +%% +UNIVERSE: + The problem. +%% +UNIVERSITY: + Like a software house, except the software's free, and it's + usable, and it works, and if it breaks they'll quickly tell + you how to fix it, and... + + [Okay, okay, I'll leave it in, but I think you're destroying + the credibility of the entire fortune program. Ed.] +%% +UNIX enhancements aren't. +%% +UNIX is many things to many people, +but it's never been everything to anybody. +%% +UNTOLD WEALTH: + What you left out on April 15th. +%% +USER: + A programmer who will believe anything you tell him. +%% +Udall's Fourth Law: + Any change or reform you make + is going to have consequences you don't like. +%% +Uh-oh -- I've let the cat out of the bag. Let me, then, +straightforwardly state the thesis I shall now elaborate: +Making variations on a theme is really the crux of creativity. + -- Douglas R. Hofstadter, "Metamagical Themas" +%% +Unbearably lovely music is heard as the curtain rises, and we see the +woods on a summer afternoon. A fawn dances on and nibbles at some +leaves. He drifts lazily through the soft foliage. Soon he starts +coughing and drops dead. + -- Woody Allen, "Without Feathers" +%% +Uncle Cosmo, why do they call this a word processor? +It's simple, Skyler. You've seen what food processors do to food, right? +%% +Uncle Ed's Rule of Thumb: + Never use your thumb for a rule. + You'll either hit it with a hammer or get a splinter in it. +%% +Under capitalism, man exploits man. +Under communism, it's just the opposite. + -- J.K. Galbraith +%% +Under deadline pressure for the next week. +If you want something, it can wait. +Unless it's blind screaming paroxysmally hedonistic... +%% +Under every stone lurks a politician. + -- Aristophanes +%% +Under the wide an starry sky, +Dig my grave and let me lie, +Glad did I live and gladly die, +And laid me down with a will, +And this be the verse that you grave for me, +Here he lies where he longed to be, +Home is the sailor home from the sea, +And the hunter home from the hill. + -- R. Kipling +%% +Under the wide and heavy VAX +Dig my grave and let me relax +Long have I lived, and many my hacks +And I lay me down with a will. +These be the words that tell the way: +"Here he lies who piped 64K, +Brought down the machine for nearly a day, +And Rogue playing to an awful standstill." +%% +Underlying Principle of Socio-Genetics: + Superiority is recessive. +%% +Understanding is always the understanding of a smaller problem +in relation to a bigger problem. + -- P.D. Ouspensky +%% +Unfair animal names: + +-- tsetse fly -- bullhead +-- booby -- duck-billed platypus +-- sapsucker -- Clarence + -- Gary Larson +%% +Unfortunately, most programmers like to play with new toys. I have many +friends who, immediately upon buying a snakebite kit, would be tempted to +throw the first person they see to the ground, tie the tourniquet on him, +slash him with the knife, and apply suction to the wound. + -- Jon Bentley +%% +United Nations, New York, December 25. The peace and joy of the Christmas +season was marred by a proclamation of a general strike of all the military +forces of the world. Panic reigns in the hearts of all the patriots of +every persuasion. Meanwhile, fears of universal disaster sank to an all-time +low over the world. + -- Isaac Asimov +%% +Universities are places of knowledge. The freshman each bring a little +in with them, and the seniors take none away, so knowledge accumulates. +%% +Unix is a lot more complicated (than CP/M) of course -- the typical Unix +hacker can never remember what the PRINT command is called this week -- +but when it gets right down to it, Unix is a glorified video game. +People don't do serious work on Unix systems; they send jokes around the +world on USENET or write adventure games and research papers. + -- E. Post + "Real Programmers Don't Use Pascal", Datamation, 7/83 +%% +Unix is the worst operating system; except for all others. + -- Berry Kercheval +%% +Unix will self-destruct in five seconds... 4... 3... 2... 1... +%% +Unless hours were cups of sack, and minutes capons, and clocks the tongues +of bawds, and dials the signs of leaping houses, and the blessed sun himself +a fair, hot wench in flame-colored taffeta, I see no reason why thou shouldst +be so superfluous to demand the time of the day. +I wasted time and now doth time waste me. + -- William Shakespeare +%% +Unnamed Law: + If it happens, it must be possible. +%% +Unquestionably, there is progress. The average American now +pays out twice as much in taxes as he formerly got in wages. + -- H.L. Mencken +%% +Up against the net, redneck mother, +Mother who has raised your son so well; +He's seventeen and hackin' on a Macintosh, +Flaming spelling errors and raisin' hell... +%% +Upon leaving a hotel bar one evening, an executive noticed a drunk sitting +on the edge of a potted palm in the lobby, crying like a baby. Because he'd +had a couple himself that night, and was feeling rather sorry for his fellow +man, he asked the inebriated one what the trouble was. + "I did a terrible thing tonight," sniffled the drunk. "I sold my +wife to a guy for a bottle of Scotch." + "That is terrible," said the man, too much under the weather to +muster any real indignation. "And now that she's gone, you wish you had her +back." + "Thas right," said the drunk, still sniffling. + "You're sorry you sold her, because you realize too late that you +love her," sympathized the executive. + "No, no," said the drunk. "I wish I had her back because I'm +thirsty again." +%% +Usage: fortune -P [-f] -a [xsz] Q: file [rKe9] -v6[+] file1 ... +%% +Use what talents you possess: the woods would be very silent +if no birds sang there except those that sang best. + -- Henry Van Dyke +%% +Useful Farsi phrases for Americans traveling to Iran: + +AKBAR KHALI-KILI HAFTIR LOTFAN. + Thank you for showing me your marvelous gun. + +FEKR GABUL CARDAN DAVAT PAEH GUSH DIVAR. + I am delighted to accept your kind invitation to lie down + on the floor with my arms above my head and my legs apart. + +SHOMAEH FEKR TAMOMEH QEH GOFTEH BANDE. + I agree with everything you have ever said or thought in your life. +%% +Useful Farsi phrases for Americans traveling to Iran: + +AUTO ARRAREGH DAVATEMAN MANO SEPAHEH-HAST. + It is exceptionally kind of you to allow me to + travel in the trunk of your car. + +FASHAL-EH TUPEHMAN NA DEGAT MANO +GOFTAM CHEESHAYEH MOHEMA RAJEBEH KESHVAREHMAN. + If you will do me the kindness of not harming my genital + appendages I will gladly reciprocate by betraying my + country in public. + +KHREL, JEPAHEH MANEH VA JAYEH AMRIKAHEY. + I will tell you the names and addresses of + many American spies traveling as reporters. +%% +Useful Farsi phrases for Americans traveling to Iran: + +MAMNOUNAN GHORBAN IN DAFAYEH MEEMUNAM. + It is with greatest pleasure that I sign + this confession of capital crimes. + +MATERNIER GHERMEZ AHLIEH, GHORBAN. + The red blindfold would be lovely, excellency. + +TIKEH NUNEH BA OB KHRELEH BEZORG VA KHRUBE BOYAST INO BEGERAM. + The water-soaked bread crumbs are delicious, thank you. + I must have the recipe. + +ETEHFOR'AN, DEHRATEE, OTAGEH SHOMA MIKRASTAM KHE +DO HAFTAEH BA BODANEH SHEEREEL TEEGZ. + Truly, I would rather be a hostage to your greatly esteemed + self than spend a fortnight upon the person of Cheryl Tiegs. +%% +Using TSO is like kicking a dead whale down the beach. + -- S.C. Johnson +%% +VACATION: + A two-week binge of rest and relaxation so intense that + it takes another 50 weeks of your restrained workaday + life-style to recuperate. +%% +VIRGINIA: + A group of beautifully mounted hunters galloping behind + baying hounds in pursuit of a union organizer. +%% +VIRGO (Aug.23 - Sept.22) + Learn something new today, like how to spell or how to count + to ten without using your fingers. Be careful dressing this + morning. You may be hit by a car later in the day and you + wouldn't want to be taken to the doctor's office in some of + that old underwear you own. +%% +VMS version 2.0 ==> +%% +VOLCANO: + A mountain with hiccups. +%% +VU-JADE: + The feeling that you've *never* been in this situation before. +%% +Van Roy's Law: + An unbreakable toy is useful for breaking other toys. +%% +Variables don't; constants aren't. +%% +Vax Vobiscum +%% +Vegeterians beware! You are what you eat. +%% +Velilind's Laws of Experimentation: + 1. If reproducibility may be a problem, conduct the test only once. + 2. If a straight line fit is required, obtain only two data points. +%% + "Verily and forsooth," replied Goodgulf darkly. "In the past year +strange and fearful wonders I have seen. Fields sown with barley reap +crabgrass and fungus, and even small gardens reject their artichoke hearts. +There has been a hot day in December and a blue moon. Calendars are made with +a month of Sundays and a blue-ribbon Holstein bore alive two insurance +salesmen. The earth splits and the entrails of a goat were found tied in +square knots. The face of the sun blackens and the skies have rained down +soggy potato chips." + "But what do all these things mean?" gasped Frito. + "Beats me," said Goodgulf with a shrug, +"but I thought it made good copy." + -- Harvard Lampoon, "Bored of the Rings" +%% +Very few profundities can be expressed in less than 80 characters. +%% +Very few things actually get manufactured these days, because in an +infinitely large Universe, such as the one in which we live, most things one +could possibly imagine, and a lot of things one would rather not, grow +somewhere. A forest was discovered recently in which most of the trees grew +ratchet screwdrivers as fruit. The life cycle of the ratchet screwdriver is +quite interesting. Once picked it needs a dark dusty drawer in which it can +lie undisturbed for years. Then one night it suddenly hatches, discards its +outer skin that crumbles into dust, and emerges as a totally unidentifiable +little metal object with flanges at both ends and a sort of ridge and a hole +for a screw. This, when found, will get thrown away. No one knows what the +screwdriver is supposed to gain from this. Nature, in her infinite wisdom, +is presumably working on it. +%% +Vests are to suits as seat-belts are to cars. +%% +Victory uber allies! +%% +Vini, vidi, vici. +[I came, I saw, I conquered]. + -- Gaius Julius Caesar +%% +"Violence accomplishes nothing." What a contemptible lie! Raw, naked +violence has settled more issues throughout history than any other method +ever employed. Perhaps the city fathers of Carthage could debate the +issue, with Hitler and Alexander as judges? +%% +Violence is a sword that has no handle -- you have to hold the blade. +%% +Violence is molding. +%% +Violence is the last refuge of the incompetent. + -- Salvador Hardin +%% +Virtue does not always demand a heavy sacrifice -- +only the willingness to make it when necessary. + -- Frederick Dunn +%% +Virtue is its own punishment. + -- Denniston +%% +Virtue is not left to stand alone. +He who practices it will have neighbors. + -- Confucius +%% +Virtue would go far if vanity did not keep it company. + -- La Rochefoucauld +%% +Visit beautiful Vergas Minnesota. +%% +Visit beautiful Wisconsin Dells. +%% +Vital papers will demonstrate their vitality by spontaneously +moving from where you left them to where you can't find them. +%% +Voicless it cries, +Wingless flutters, +Toothless bites, +Mouthless mutters. +%% +Volcanoes have a grandeur that is grim +And earthquakes only terrify the dolts, +And to him who's scientific +There is nothing that's terrific +In the pattern of a flight of thunderbolts! + -- W.S. Gilbert, "The Mikado" +%% +Volley Theory: + It is better to have lobbed and lost + than never to have lobbed at all. +%% +Vote anarchist. +%% +WARNING: + Reading this fortune can affect the dimensionality of your + mind, change the curvature of your spine, cause the growth + of hair on your palms, and make a difference in the outcome + of your favorite war. +%% +WARNING!!! +This machine is subject to breakdowns during periods of critical need. + +A special circuit in the machine called "critical detector" senses the +operator's emotional state in terms of how desperate he/she is to use the +machine. The "critical detector" then creates a malfunction proportional +to the desperation of the operator. Threatening the machine with violence +only aggravates the situation. Likewise, attempts to use another machine +may cause it to malfunction. They belong to the same union. Keep cool +and say nice things to the machine. Nothing else seems to work. + +See also: flog(1), tm(1) +%% +WEAPON: + An index of the lack of development of a culture. +%% +WE'LL LOOK INTO IT: + By the time the wheels make a full turn, we + assume you will have forgotten about it,too. +%% +WELL-ADJUSTED: + The ability to play bridge or golf as if they were games. +%% +WE: + The single most important word in the world. +%% +WHERE CAN THE MATTER BE + Oh, dear, where can the matter be + When it's converted to energy? + There is a slight loss of parity. + Johnny's so long at the fair. +%% +WIT: + The salt with which the American Humorist spoils his cookery... + by leaving it out. +%% +WOLF: + A man who knows all the ankles. +%% +WOMAN: + An animal usually living in the vicinity of Man, and + having a rudimentary susceptibility to domestication. + -- Bierce +%% +WORK: + The blessed respite from screaming kids and + soap operas for which you actually get paid. +%% +WRITE-PROTECT TAB: + A small sticker created to cover the unsightly notch carelessly + left by disk manufacturers. The use of the tab creates an error + message once in a while, but its aesthetic value far outweighs + the momentary inconvenience. + -- Robb Russon +%% +WRONG! +%% +WYSIWYG: + What You See Is What You Get. +%% +Wagner's music is better than it sounds. + -- Mark Twain +%% +Wait for that wisest of all counselors, Time. + -- Pericles +%% +Waiter: "Tea or coffee, gentlemen?" +1st customer: "I'll have tea." +2nd customer: "Me, too -- and be sure the glass is clean!" + (Waiter exits, returns) +Waiter: "Two teas. Which one asked for the clean glass?" +%% +Wake up all you citizens, hear your country's call, +Not to arms and violence, But peace for one and all. +Crush out hate and prejudice, fear and greed and sin, +Help bring back her dignity, restore her faith again. + +Work hard for a common cause, don't let our country fall. +Make her proud and strong again, democracy for all. +Yes, make our country strong again, keep our flag unfurled. +Make our country well again, respected by the world. + +Make her whole and beautiful, work from sun to sun. +Stand tall and labor side by side, because there's so much to be done. +Yes, make her whole and beautiful, united strong and free, +Wake up, all you citizens, It's up to you and me. + -- Pansy Myers Schroeder +%% +Wake up and smell the coffee. + -- Ann Landers +%% +Waking a person unnecessarily should not be considered +a capital crime. For a first offense, that is. +%% +Walk softly and carry a big stick. + -- Theodore Roosevelt +%% +Walking on water wasn't built in a day. + -- Jack Kerouac +%% +Walt: Dad, what's gradual school? +Garp: Gradual school? +Walt: Yeah. Mom says her work's more fun now that she's teaching + gradual school. +Garp: Oh. Well, gradual school is someplace you go and gradually + find out that you don't want to go to school anymore. + -- The World According To Garp +%% +Walters' Rule: + All airline flights depart from the gates most distant from + the center of the terminal. Nobody ever had a reservation + on a plane that left Gate 1. +%% +Wanna buy a duck? +%% +War hath no fury like a non-combatant. + -- Charles Edward Montague +%% +War is an equal opportunity destroyer. +%% +War is much too serious a matter to be entrusted to the military. + -- Clemenceau +%% +War spares not the brave, but the cowardly. + -- Anacreon +%% +Warning: Trespassers will be shot. +Survivors will be shot again. +%% +Was there a time when dancers with their fiddles +In children's circuses could stay their troubles? +There was a time they could cry over books, +But time has set its maggot on their track. +Under the arc of the sky they are unsafe. +What's never known is safest in this life. +Under the skysigns they who have no arms +Have cleanest hands, and, as the heartless ghost +Alone's unhurt, so the blind man sees best. + -- Dylan Thomas, "Was There A Time" +%% +Washington [D.C.] is a city of Southern efficiency and Northern charm. + -- John F. Kennedy +%% +[Washington, D.C.] is the home of... taste for +the people -- the big, the bland and the banal. + -- Ada Louise Huxtable +%% +Wasn't there something about a PASCAL programmer +knowing the value of everything and the Wirth of nothing? +%% +Waste not fresh tears over old griefs. + -- Euripides +%% +Waste not, get your budget cut next year. +%% +Wasting time is an important part of living. +%% +Watch all-night Donna Reed reruns until your mind resembles oatmeal. +%% +Watch your mouth, kid, or you'll find yourself floating home. + -- Han Solo +%% +Watson's Law: + The reliability of machinery is inversely proportional to the + number and significance of any persons watching it. +%% +We ARE as gods and might as well get good at it. + -- Whole Earth Catalog +%% +We all declare for liberty, but in using the +same word we do not all mean the same thing. + -- A. Lincoln +%% +We all dream of being the darling of everybody's darling. +%% +We all know that no one understands anything that isn't funny. +%% +We all like praise, but a hike in our pay is the best kind of ways. +%% +We all live in a state of ambitious poverty. + -- Decimus Junius Juvenalis +%% +We all live under the same sky, but we don't all have the same horizon. + -- Dr. Konrad Adenauer +%% +We are all born equal... just some of us are more equal than others. +%% +We are all born mad. Some remain so. + -- Samuel Beckett +%% +We are all dying -- and we're gonna be dead for a long time. +%% +We are all in the gutter, but some of us are looking at the stars. + -- Oscar Wilde +%% +We are all so much together and yet we are all dying of loneliness. + -- A. Schweitzer +%% +We are all worms. But I do believe I am a glowworm. + -- Winston Churchill +%% +We are anthill men upon an anthill world. + -- Ray Bradbury +%% +We are confronted with unsurmountable opportunities. + -- Pogo +%% +We are experiencing system trouble -- do not adjust your terminal. +%% +We are giving instruction to FBI agents in the various Chinese +dialects ... to handle present and likely future contingencies. + -- J.Hoover +%% +We are going to have peace even if we have to fight for it. + -- Dwight D. Eisenhower +%% +We are not a clone. +%% +We are not a loved organization, but we are a respected one. + -- John Fisher +%% +We are not alone. +%% +We are not loved by our friends for what we are; +rather, we are loved in spite of what we are. + -- Victor Hugo +%% +We are simple killers of people and destroyers of property. +%% +We are so fond of each other because our ailments are the same. + -- Jonathon Swift +%% +We are sorry. We cannot complete your call as dialed. Please check +the number and dial again or ask your operator for assistance. + +This is a recording. +%% +We are stronger than our skin of flesh and metal, for we carry and +share a spectrum of suns and lands that lends us legends as we craft +our immortality and interweave our destinies of water and air, +leaving shadows that gather color of their own, until they outshine +the substance that cast them. +%% +We are the people our parents warned us about. +%% +TOTD (T-shirt Of The Day): + I'm the person your mother warned you about. +%% +We are the unwilling... led by the unqualified... +to do the unnecessary... for the ungrateful... + -- GI in Vietnam, 1970 +%% +We are what we are. +%% +We are what we pretend to be. + -- Kurt Vonnegut, Jr. +%% +We boggies are a hairy folk Ever hungry, ever thirsting, +Who like to eat until we choke. Never stop till belly's bursting. +Loving all like friend and brother, Chewing chop and pork and muttons, +And hardly ever eat each other. A merry race of boring gluttons. + +Sing: GOBBLE, GOBBLE, GOBBLE, GOBBLE, GOBBLE, GOBBLE, GOBBLE, GOBBLE. + +Boggies gather 'round the table, Anything edible, we've got dibs on, +Eat as much as you are able. And hope we all die with our bibs on. +Gorge yourselves from moon till noon Ever gay, we'll never grow up, +(Don't forget your plate and spoon.) Come! And sing and play and throw-up! + +Sing: GOBBLE, GOBBLE, GOBBLE, GOBBLE, GOBBLE, GOBBLE, GOBBLE, GOBBLE! + -- Bored of the Rings, "The Hobbits National Anthem" +%% +We can defeat gravity. The problem is the paperwork involved. +%% +We can embody the truth, but we cannot know it. + -- Yates +%% +We cannot command nature except by obeying her. + -- Sir Francis Bacon +%% +We cannot do everything at once, but we can do something at once. + -- Calvin Coolidge +%% +We could do that, but it would be wrong, that's for sure. + -- Richard Nixon +%% +We dedicate this book to our fellow citizens who, for love of truth, +take from their own wants by taxes and gifts, and now and then send +forth one of themselves as dedicated servant, to forward the search +into the mysteries and marvelous simplicities of this strange and +beautiful Universe, Our home. + -- "Gravitation", Misner, Thorne, and Wheeler +%% +We don't care. We don't have to. We're the Phone Company. +%% +We don't have to protect the environment -- the Second Coming is at hand. + -- James Watt, noted theologian +%% +We don't know one millionth of one percent about anything. +%% +We don't know who discovered water, but we're certain it wasn't a fish. +%% +We don't need no education, we don't need no thought control. + -- Pink Floyd +%% +We don't need no indirection We don't need no compilation +We don't need no flow control We don't need no load control +No data typing or declarations No link edit for external bindings +Hey! did you leave the lists alone? Hey! did you leave that source alone? +Chorus: (Chorus) + Oh No. It's just a pure LISP function call. + +We don't need no side-effecting We don't need no allocation +We don't need no flow control We don't need no special-nodes +No global variables for execution No dark bit-flipping for debugging +Hey! did you leave the args alone? Hey! did you leave those bits alone? +(Chorus) (Chorus) + -- "Another Glitch in the Call", a la Pink Floyd +%% +We don't really understand it, so we'll give it to the programmers. +%% +We don't smoke and we don't chew, and we don't go with girls that do. + -- Walter Summers +%% +We don't understand the software, and sometimes we don't +understand the hardware, but we can *see* the blinking lights! +%% + "We friends, yes?" The shoe shine boy put on his hustling smile +and looked into the Sailor's dead, cold, undersea eyes, eyes without a +trace of warmth or lust or hate or any feeling the boy had experienced +in himself or seen in another, at once cold and intense, impersonal and +predatory. + The Sailor leaned forward and put a finger on the boy's inner arm +at the elbow. He spoke in his dead junky whisper. "With veins like that, +Kid, I'd have myself a time!" + -- William Burroughs +%% +We give advice, but we cannot give the wisdom to profit by it. + -- La Rochefoucauld +%% +We gotta get out of this place, +If it's the last thing we ever do. + -- The Animals +%% +We have a equal opportunity Calculus class -- it's fully integrated. +%% +We have art that we do not die of the truth. + -- Nietzsche +%% +We have ears, earther...FOUR OF THEM! +%% +We have gone on piling weapon upon weapon, missile upon missile, new +levels of destructiveness upon old ones. We have done this helplessly, +almost involuntarily: like the victims of some sort of hypnotism, like +men in a dream, like lemmings heading for the sea, like the children of +Hamelin marching blindly along behind their Pied Piper. And the result +is that today we have achieved, we and the Russians together, in the +creation of these devices and their means of delivery, levels of +redundancy of such grotesque dimensions as to defy rational understanding. + -- George Kennan, May 19, 1981 +%% +We have lingered long enough on the shores of the Cosmic Ocean. + -- Carl Sagan +%% +We have met the enemy, and he is us. + -- Walt Kelly +%% +We have more to fear from the bungling of the incompetent +than from the machinations of the wicked. +%% +We have no scorched earth policy. +We have a policy of scorched Communists. + -- General Efrain Rios Montt, President of Guatemala, 1982 +%% +We have nowhere else to go... this is all we have. + -- Margaret Mead +%% +We have reason to be afraid. This is a terrible place. + -- John Berryman +%% + We have some absolutely irrefutable statistics to show exactly why +you are so tired. + There are not as many people actually working as you may have thought. + The population of this country is 200 million. 84 million are over +60 years of age, which leaves 116 million to do the work. People under 20 +years of age total 75 million, which leaves 41 million to do the work. + There are 22 million who are employed by the government, which leaves +19 million to do the work. Four million are in the Armed Services, which +leaves 15 million to do the work. Deduct 14,800,000, the number in the state +and city offices, leaving 200,000 to do the work. There are 188,000 in +hospitals, insane asylums, etc., so that leaves 12,000 to do the work. + Now it may interest you to know that there are 11,998 people in jail, +so that leaves just 2 people to carry the load. That is you and me, and +brother, I'm getting tired of doing everything myself! +%% +We interrupt this fortune for an important announcement... +%% +We laugh at the Indian philosopher, who to account for the support +of the earth, contrived the hypothesis of a huge elephant, and to support +the elephant, a huge tortoise. If we will candidly confess the truth, we +know as little of the operation of the nerves, as he did of the manner in +which the earth is supported: and our hypothesis about animal spirits, or +about the tension and vibrations of the nerves, are as like to be true, as +his about the support of the earth. His elephant was a hypothesis, and our +hypotheses are elephants. Every theory in philosophy, which is built on +pure conjecture, is an elephant; and every theory that is supported partly +by fact, and partly by conjecture, is like Nebuchadnezzar's image, whose +feet were partly of iron, and partly of clay. + -- Thomas Reid, "An Inquiry into the Human Mind", 1764 +%% +We learn from history that we do not learn anything from history. +%% +We love our little Johnny +He's the best little boy in all the world +And we wouldn't trade him for anything +That's how much we love him. +No, we couldn't live without him +So that's why, since he died, +We keep him safe in our G.E. freezer. +He's so good, so well-behaved, +Even better than before; +Oh, such a wonderful kid he is. +Alice and me, we'll never be lonely, +Never miss our little Johnny, +He'll never grow up and leave us +That's why we love him like we do. + -- Mr. Mincemeat +%% +"We maintain that the very foundation of our way of life is what we call +free enterprise," said Cash McCall, "but when one of our citizens +show enough free enterprise to pile up a little of that profit, we do +our best to make him feel that he ought to be ashamed of himself." + -- Cameron Hawley +%% +We may not return the affection of those who like us, +but we always respect their good judgement. +%% +We must believe that it is the darkest before the dawn +of a beautiful new world. We will see it when we believe it. + -- Saul Alinsky +%% +We must die because we have known them. + -- Ptah-hotep, 2000 B.C. +%% +We must remember the First Amendment which +protects any shrill jackass no matter how self-seeking. + -- F.G. Withington +%% +We only acknowledge small faults in order +to make it appear that we are free from great ones. + -- LaRouchefoucauld +%% +We prefer to speak evil of ourselves +rather than not speak of ourselves at all. +%% +We promise according to our hopes, and perform according to our fears. +%% +We rarely find anyone who can say he has lived a happy life, and who, +content with his life, can retire from the world like a satisfied guest. + -- Quintus Horatius Flaccus (Horace) +%% +We read to say that we have read. +%% +We really don't have any enemies. +It's just that some of our best friends are trying to kill us. +%% +We secure our friends not by accepting favors but by doing them. + -- Thucydides +%% +We seldom repent talking too little, but very often talking too much. + -- Jean de la Bruyere +%% +We should be careful to get out of an experience only the wisdom that is +in it - and stay there, lest we be like the cat that sits down on a hot +stove-lid. She will never sit down on a hot stove-lid again - and that +is well; but also she will never sit down on a cold one any more. + -- Mark Twain +%% +We should have a great many fewer disputes in the world if only words were +taken for what they are, the signs of our ideas only, and not for things +themselves. + -- John Locke +%% +We the Users, in order to form a more perfect system, establish priorities, +ensure connective tranquility, provide for common repairs, promote +preventive maintenance, and secure the blessings of liberty for ourselves +and our processes, do ordain and establish this Software of The Unixed States +of America. +%% +We the unwilling, led by the ungrateful, are doing the impossible. +We've done so much, for so long, with so little, +that we are now qualified to do something with nothing. +%% +We totally deny the allegations, and +we're trying to identify the allegators. +%% +[We] use bad software and bad machines for the wrong things. + -- R.W. Hamming +%% +We was playin' the Homestead Grays in the city of Pitchburgh. Josh +[Gibson] comes up in the last of the ninth with a man on and us a run +behind. Well, he hit one. The Grays waited around and waited around, +but finally the empire rules it ain't comin' down. So we win. The +next day, we was disputin' the Grays in Philadelphia when here come +a ball outta the sky right in the glove of the Grays' center fielder. +The empire made the only possible call. "You're out, boy!" he says +to Josh. "Yesterday, in Pitchburgh." + -- Satchel Paige +%% +We were so poor we couldn't afford a watchdog. +If we heard a noise at night, we'd bark ourselves. + -- Crazy Jimmy +%% +We who revel in nature's diversity and feel instructed by every animal +tend to brand Homo sapiens as the greatest catastrophe since the Cretaceous +extinction. + -- S.J. Gould +%% +We will follow Zarathustra, We will worship like the Druids, +Zarathustra like we use to, Dancing naked in the woods, +I'm a Zarathustra booster, Drinking strange fermented fluids, +And he's good enough for me! And it's good enough for me! +(chorus) (chorus) + +In the church of Aphrodite, +The priestess wears a see through nightie, +She's a mighty righteous sightie, +And she's good enough for me! +(chorus) + +CHORUS: Give me that old time religion, + Give me that old time religion, + Give me that old time religion, + 'Cause it's good enough for me! +%% +We will have solar energy as soon as the utility companies solve +one technical problem -- how to run a sunbeam through a meter. +%% +We wish you a Hare Krishna +We wish you a Hare Krishna +We wish you a Hare Krishna +And a Sun Myung Moon! + -- Maxwell Smart +%% +Wedding is destiny, and hanging likewise. + -- John Heywood +%% +Weed's Axiom: + Never ask two questions in a business letter. + The reply will discuss the one in which you are + least interested and say nothing about the other. +%% +Weekend, where are you? +%% +Weiler's Law: + Nothing is impossible to a person who doesn't have to do the work. +%% +Weinberg's First Law: + Progress is only made on alternate Fridays. +%% +Weinberg's Principle: + An expert is a person who avoids the small errors while sweeping + on to the grand fallacy. +%% +Weinberg's Second Law: + If builders built buildings the way programmers wrote programs, + then the first woodpecker that came along would destroy civilization. +%% +Weiner's Law of Libraries: + There are no answers, only cross references. +%% + "Welcome back for you 13th consecutive week, Evelyn. Evelyn, will +you go into the auto-suggestion booth and take your regular place on the +psycho-prompter couch?" + "Thank you, Red." + "Now, Evelyn, last week you went up to $40,000 by properly citing +your rivalry with your sibling as a compulsive sado-masochistic behavior +pattern which developed out of an early post-natal feeding problem." + "Yes, Red." + "But -- later, when asked about pre-adolescent oedipal phantasy +repressions, you rationalized twice and mental blocked three times. Now, +at $300 per rationalization and $500 per mental block you lost $2,100 off +your $40,000 leaving you with a total of $37,900. Now, any combination of +two more mental blocks and either one rationalization or three defensive +projections will put you out of the game. Are you willing to go ahead?" + "Yes, Red." + "I might say here that all of Evelyn's questions and answers have +been checked for accuracy with her analyst. Now, Evelyn, for $80,000 +explain the failure of your three marriages." + "Well, I--" + "We'll get back to Evelyn in one minute. First a word about our +product." +%% +Welcome back, my friends, to the show that never ends! +We're so glad you could attend, come inside, come inside! +There behind the glass there's a real blade of grass, +Be careful as you pass, move along, move along. +Come inside, the show's about to start, +Guaranteed to blow your head apart. +Rest assured, you'll get your money's worth, +Greatest show, in heaven, hell or earth! +You gotta see the show! It's a dynamo! +You gotta see the show! It's rock 'n' roll! + -- ELP, "Karn Evil 9" (1st Impression, Part 2) +%% +Welcome to Fortune Blackmail!! + Ms. Kat****** Bl****an is the mistress of a well-known + banker in Houston, Texas. That's $5000, please, to stop + us from revealing both of your names, Mr. L*****, so that + your wife Doreen, and your lovely children Diane, Janice + and Tom need never know the name of your mistress. You + have two days to reach us at: + + Fortune Blackmail + Behind the hot water pipes, + Third stall from the end, + Greyhound Bus Terminal, Fayette MO. +%% +Welcome to Fortune Blackmail!! + This is the first of a series of revelations which could + add up to a divorce, premature retirement and possible + criminal proceedings for a company vice-president in Langley Virginia. + So, Mr. S*****, $10,000 please to stop us from revealing: + 1: Whose shoulders you were sitting on. + 2: What you were doing. + 3: The names of the three people involved. + 4: The youth organization to which they belonged. + 5: The shop where you bought the equipment. +%% +Welcome to UNIX! Enjoy your session! Have a great time! Note the +use of exclamation points! They are a very effective method for +demonstrating excitement, and can also spice up an otherwise plain-looking +sentence! However, there are drawbacks! Too much unnecessary exclaiming +can lead to a reduction in the effect that an exclamation point has on +the reader! For example, the sentence + + Jane went to the store to buy bread + +should only be ended with an exclamation point if there is something +sensational about her going to the store, for example, if Jane is a +cocker spaniel or if Jane is on a diet that doesn't allow bread or if +Jane doesn't exist for some reason! See how easy it is?! Proper control +of exclamation points can add new meaning to your life! Call now to receive +my free pamphlet, "The Wonder and Mystery of the Exclamation Point!"! +Enclose fifteen(!) dollars for postage and handling! Operators are +standing by! (Which is pretty amazing, because they're all cocker spaniels!) +%% +Welcome to boggle - do you want instructions? + +D G G O + +O Y A N + +A D B T + +K I S P +Enter words: +> +%% +Welcome to the Zoo! +%% +Well, God gave me a bust. What am I supposed to do with it? + -- Martha Mitchell +%% +Well I looked at my watch and it said a quarter to five, +The headline screamed that I was still alive, +I couldn't understand it, I thought I died last night. +I dreamed I'd been in a border town, +In a little cantina that the boys had found, +I was desperate to dance, just to dig the local sounds. +When along came a senorita, +She looked so good that I had to meet her, +I was ready to approach her with my English charm, +When her brass knuckled boyfriend grabbed me by the arm, +And he said, grow some funk of your own, amigo, +Grow some funk of your own. +We no like to with the gringo fight, +But there might be a death in Mexico tonite. +... +Take my advice, take the next flight, +And grow some funk, grow your funk at home. + -- Elton John, "Grow Some Funk of Your Own" +%% +Well, Jim, I'm not much of an actor either. +%% +Well, actually, I don't mind going to weddings or anything, as long as they're +not my own, I show up, but uh, I've always kinda been partial to callin' myself +up on the phone, asking myself out, y'know, yeah, one thing about it, you're +always around. Yeah, I know, yeah, you ask yourself out, y'know, some class +joint somewhere, the Burrito King, or somethin', y'know, well, I ain't cheap +y'know. Take yourself out for a coupla drinks, mebbe, then you eat, some +provocative conversation on the way home, and uh, park in front of the house, +y'know, and you, oh yeah, you smoo with yourself, put a little nice music on, +mebbe you put on like, uh, y'know, like shoppin' music, something that's not +too interruptive, y'know, and then uh, y'know, slide over real nice, and say, +"Oh, I think you have something in your eye", well, maybe it's not that +romantic with you, but I don't, y'know, I get into it, y'know, I take myself +up to the porch, and uh, take myself inside, maybe, oh, I might get a little +something in a brandy snifter, "Would you like to listen to some of my back +records, I got something here...", well, usually, about two-thirty in the +morning, you've ended up takin' advantage of yourself, and there ain't no way +around that, y'know, yeah, makin' the scene with a magazine, ain't no way +around it. I'll confess, y'know, I'm no different, y'know, I'm not weird about +it or anything, I don't tie myself up first, I just, I just kinda spend a +little time with myself. + -- Tom Waits, "Nighthawks at the Diner" +%% +Well begun is half done. + -- Aristotle +%% +We'll cross that bridge when we come back to it later. +%% +Well, didja wake up grouchy or did you let her sleep? +%% +Well, fancy giving money to the Government! +Might as well have put it down the drain. +Fancy giving money to the Government! +Nobody will see the stuff again. +Well, they've no idea what money's for -- +Ten to one they'll start another war. +I've heard a lot of silly things, but, Lor'! +Fancy giving money to the Government! + -- A.P. Herbert +%% +We'll have solar energy when the power companies develop a sunbeam meter. +%% + Well, he thought, since neither Aristotilian Logic nor the disciplines +of Science seemed to offer much hope, it's time to go beyond them... + Drawing a few deep even breaths, he entered a mental state practiced +only by Masters of the Universal Way of Zen. In it his mind floated freely, +able to rummage at will among the bits and pieces of data he had absorbed, +undistracted by any outside disturbances. Logical structures no longer +inhibited him. Pre-conceptions, prejudices, ordinary human standards vanished. +All things, those previously trivial as well as those once thought important, +became absolutely equal by acquiring an absolute value, revealing relationships +not evident to ordinary vision. Like beads strung on a string of their own +meaning, each thing pointed to its own common ground of existence, shared by +all. Finally, each began to melt into each, staying itself while becoming +all others. And Mind no longer contemplated Problem, but became Problem, +destroying Subject-Object by becoming them. + Time passed, unheeded. + Eventually, there was a tentative stirring, then a decisive one, and +Nakamura arose, a smile on his face and the light of laughter in his eyes. + -- Wayfarer +%% + "Well, it's a little rough... it might not be necessary to drag him 40 +blocks. Maybe just four. You could put him in the trunk for the first 36 +blocks, then haul him out and drag him the last four; that would certainly +scare the piss out of him, bumping alone the street, feeling all his skin being +ripped off..." + "He'd be a bloody mess. They might think he was just some drunk and let +him lie there all night." + "Don't worry about that. They have a guard station in front of the +White House that's open 24 hours a day. The guards would recognize Colson... +and by that time of course his wife would have called the cops and reported +that a bunch of thugs had kidnapped him." + "Wouldn't it be a little kinder if you drove about four more blocks +and stopped at a phone box to ring the hospital and say, 'Would you mind going +around to the front of the White House? There's a naked man lying outside +in the street, bleeding to death...'" + "... and we think it's Mr. Colson." + "It would be quite a story for the newspapers, wouldn't it?" + "Yeah, I think it's safe to say we'd see some headlines on that one." + -- H. Thompson, talking to R. Steadman on C. Colson, + ex-Marine captain, now born again, of Watergate fame. +%% +Well, my daddy left home when I was three, +And he didn't leave much for Ma and me, +Just and old guitar an'a empty bottle of booze. +Now I don't blame him 'cause he ran and hid, +But the meanest thing that he ever did, +Was before he left he went and named me Sue. +... +But I made me a vow to the moon and the stars, +I'd search the honkey tonks and the bars, +And kill the man that give me that awful name. +It was Gatlinburg in mid-July, +I'd just hit town and my throat was dry, +Thought I'd stop and have myself a brew, +At an old saloon on a street of mud, +Sitting at a table, dealing stud, +Sat that dirty (bleep) that name me Sue. +... +Now, I knew that snake was my own sweet Dad, +From a wornout picture that my Mother had, +And I knew that scar on his cheek and his evil eye... + -- Johnny Cash, "A Boy Named Sue" +%% +Well, my terminal's locked up, and I ain't got any Mail, +And I can't recall the last time that my program didn't fail; +I've got stacks in my structs, I've got arrays in my queues, +I've got the : Segmentation violation -- Core dumped blues. + +If you think that it's nice that you get what you C, +Then go : illogical statement with your whole family, +'Cause the Supreme Court ain't the only place with : Bus error views. +I've got the : Segmentation violation -- Core dumped blues. + +On a PDP-11, life should be a breeze, +But with VAXen in the house even magnetic tapes would freeze. +Now you might think that unlike VAXen I'd know who I abuse, +I've got the : Segmentation violation -- Core dumped blues. + -- Core Dumped Blues +%% +We'll pivot at warp 2 and bring all tubes to bear, Mr. Sulu! +%% +Well thaaaaaaat's okay. +%% +Well, the handwriting is on the floor. + -- Joe E. Lewis +%% + Well, there was this tiger, who woke up one morning, and just felt +great (yes, just like Tony the Tiger: GREAAAAAAT). Anyway, he just felt so +good, he went out and cornered a small monkey and roared at him: "WHO IS THE +MIGHTIEST OF ALL THE JUNGLE ANIMALS?" + The poor, quaking, little monkey replied: "You are of course, no one +is mightier than you." + A little while later the tiger confronts a deer, and just bellows out: +"WHO IS THE GREATEST AND STRONGEST OF ALL THE JUNGLE ANIMALS?" + The deer is shaking so hard it can barely speak, but manages to +stammer: "Oh great tiger, you are by far the mightiest animal in the jungle." + The tiger, being on a roll, swaggered, up to an elephant that was +quietly munching on some weeds, and roared at the top of his voice: "WHO IS +THE MIGHTIEST OF ALL THE ANIMALS IN THE JUNGLE?" + Well, the elephant grabs the tiger with his trunk, picks him up, slams +him down; picks him up again, and shakes him until the tiger is just a blur of +orange and black; and finally throws him violently into a nearby tree. The +tiger staggers to his feet and looks at the elephant and whispers: "Man, you +don't have to get so pissed, just 'cause you don't know the answer." +%% +Well, we'll really have a party, +but we've gotta post a guard outside. + -- Eddie Cochran, "Come On Everybody" +%% +Well, we're big rock singers, +We've got golden fingers, +And we're loved everywhere we go. +We sing about beauty, and we sing about truth, +At ten thousand dollars a show. +We take all kinds of pills to give us all kinds of thrills, +But the thrill we've never known, +Is the thrill that'll get you, when you get your picture, +On the cover of the Rolling Stone. + -- Dr. Hook and the Medicine Show + [As a note, they eventually DID make the cover of RS. Ed.] +%% +Well, you got your mules and you got your racehorses, and you can kick +a mule in the ass all you want, and he's still not gonna be a racehorse. + -- Billy Martin, "Esquire", May, 1984 +%% +Well, you know, no matter where you go, there you are. + -- Buckaroo Banzai +%% +We're happy little Vegemites, + As bright as bright can be. +We all all enjoy our Vegemite + For breakfast, lunch and tea. +%% +Were it not for the presence of the unwashed and the half-educated, the +formless, queer and incomplete, the unreasonable and absurd, the infinite +shapes of the delightful human tadpole, the horizon would not wear so wide +a grin. + -- F.M. Colby, "Imaginary Obligations" +%% +We're living in a golden age. All you need is gold. + -- D.W. Robertson. +%% +"We're not talking about the same thing," he said. "For you the world is +weird because if you're not bored with it you're at odds with it. For me +the world is weird because it is stupendous, awesome, mysterious, +unfathomable; my interest has been to convince you that you must accept +responsibility for being here, in this marvelous world, in this marvelous +desert, in this marvelous time. I wanted to convince you that you must +learn to make every act count, since you are going to be here for only a +short while, in fact, too short for witnessing all the marvels of it." + -- Don Juan +%% +Wernher von Braun settled for a V-2 when he coulda had a V-8. +%% +Westheimer's Discovery: + A couple of months in the laboratory can + frequently save a couple of hours in the library. +%% +Wethern's Law: + Assumption is the mother of all screw-ups. +%% +We've tried each spinning space mote +And reckoned its true worth: +Take us back again to the homes of men +On the cool, green hills of Earth. + +The arching sky is calling +Spacemen back to their trade. +All hands! Standby! Free falling! +And the lights below us fade. +Out ride the sons of Terra, +Far drives the thundering jet, +Up leaps the race of Earthmen, +Out, far, and onward yet-- + +We pray for one last landing +On the globe that gave us birth; +Let us rest our eyes on the fleecy skies +And the cool, green hills of Earth. + -- Robert A. Heinlein, 1941 +%% +Wharbat darbid yarbou sarbay? +%% +What!? Me worry? + -- A.E. Newman +%% + What I Did During My Fall Semester +On the first day of my fall semester, I got up. +Then I went to the library to find a thesis topic. +Then I hung out in front of the Dover. + +On the second day of my fall semester, I got up. +Then I went to the library to find a thesis topic. +Then I hung out in front of the Dover. + +On the third day of my fall semester, I got up. +Then I went to the library to find a thesis topic. +I found a thesis topic: + How to keep people from hanging out in front of the Dover. + -- Sister Mary Elephant, + "Student Statement for Black Friday" +%% +What I mean (and everybody else means) by the word QUALITY cannot be +broken down into subjects and predicates. This is not because Quality +is so mysterious but because Quality is so simple, immediate, and direct. + -- R. Pirsig, "Zen and the Art of Motorcycle Maintenance" +%% +What I tell you three times is true. + -- Lewis Carroll +%% +What I want is all of the power and none of the responsibility. +%% +What a strange game. The only winning move is not to play. + -- WOP, "War Games" +%% +What, after all, is a halo? It's only one more thing to keep clean. + -- Christopher Fry +%% +What an artist dies with me! + -- Nero +%% +What awful irony is this? +We are as gods, but know it not. +%% +What causes the mysterious death of everyone? +%% +What did ya do with your burder and your cross? +Did you carry it yourself or did you cry? +You and I know that a burden and a cross, +Can only be carried on one man's back. + -- Louden Wainwright III +%% +What did you bring that book I didn't want +to be read to out of about Down Under up for? +%% +What did you do when the ship sank? +I grabbed a cake of soap and washed myself ashore. +%% +What do I consider a reasonable person to be? I'd say a reasonable person +is one who accepts that we are all human and therefore fallible, and takes +that into account when dealing with others. Implicit in this definition is +the belief that it is the right and the responsibility of each person to +live his or her own life as he or she sees fit, to respect this right in +others, and to demand the assumption of this responsibility by others. +%% + "What do you give a man who has everything?" the pretty teenager +asked her mother. + "Encouragement, dear," she replied. +%% +What does education often do? +It makes a straight cut ditch of a free meandering brook. + -- Henry David Thoreau +%% +What does it mean if there is no fortune for you? +%% +What does not destroy me, makes me stronger. + -- Nietzsche +%% +What ever happened to happily ever after? +%% +What excuses stand in your way? How can you eliminate them? + -- Roger von Oech +%% +What foods these morsels be! +%% +What fools these morals be! +%% +What fools these mortals be. + -- Lucius Annaeus Seneca +%% +What garlic is to salad, insanity is to art. +%% +What good is a ticket to the good life, +if you can't find the entrance? +%% +What good is having someone who can walk +on water if you don't follow in his footsteps? +%% +What good is it if you talk in flowers, and they think in pastry? + -- Ashleigh Brilliant +%% +What happened last night can happen again. +%% +What happens to a dream deferred? +Does it dry up +Like a raisin in the sun? +Or fester like a sore -- +And then run? +Does it stink like rotten meat? +Or crust and sugar over -- +Like a syrupy sweet? + +Maybe it just sags +Like a heavy load. + +Or does it explode? + -- Langston Hughes +%% +What happens when you cut back the jungle? It recedes. +%% +What has roots as nobody sees, +Is taller than trees, +Up, up it goes, +And yet never grows? +%% +What is a magician but a practising theorist? + -- Obi-Wan Kenobi +%% +What is food to one, is to others bitter poison. + -- Titus Lucretius Carus +%% +What is good? Everything that heightens the feeling of power in man, the +will to power, power itself. What is bad? Everything that is born of +weakness. Not contentedness but more power; not peace but war; not virtue +but fitness. The weak and the failures shall perish: first principle of +our love of man. And they shall even be given every possible assistance. +What is more harmful than any vice? Active pity for all the failures and +all the weak: Christianity. + -- Friedrich Nietzsche +%% + What is involved in such [close] relationships is a form of emotional +chemistry, so far unexplained by any school of psychiatry I am aware of, that +conditions nothing so simple as a choice between the poles of attraction and +repulsion. You can meet some people thirty, forty times down the years, and +they remain amiable bystanders, like the shore lights of towns that a sailor +passes at stated times but never calls at on the regular run. Conversely, +all considerations of sex aside, you can meet some other people once or twice +and they remain permanent influences on your life. + Everyone is aware of this discrepancy between the acquaintance seen +as familiar wallpaper or instant friend. The chemical action it entails is +less worth analyzing than enjoying. At any rate, these six pieces are about +men with whom I felt an immediate sympat - to use a coining of Max Beerbohm's +more satisfactory to me than the opaque vogue word "empathy". + -- Alistair Cooke, "Six Men" +%% +What is love but a second-hand emotion? + -- Tina Turner +%% +What is mind? No matter. +What is matter? Never mind. + -- Thomas Hewitt Key, 1799 - 1875 +%% +What is now proved was once only imagin'd. + -- William Blake +%% +What is research but a blind date with knowledge? + -- Will Harvey +%% +What is status? + Status is when the President calls you for your opinion. + +Uh, no... + Status is when the President calls you in to discuss a + problem with him. + +Uh, that still ain't right... + STATUS is when you're in the Oval Office talking to the President, + and the phone rings. The President picks it up, listens for a + minute, and hands it to you, saying, "It's for you." +%% +What is the difference between a Turing machine and the modern computer? +It's the same as that between Hillary's ascent of Everest and the +establishment of a Hilton on its peak. +%% +What is the sound of one hand clapping? +%% +What is wanted is not the will-to-believe, +but the wish to find out, which is exact opposite. + -- Bertrand Russell +%% +What is worth doing is worth the trouble of asking somebody to do it. +%% +What kind of sordid business are you on now? I mean, man, whither +goest thou? Whither goest thou, America, in thy shiny car in the night? + -- Jack Kerouac +%% +What makes the Universe so hard to comprehend +is that there's nothing to compare it with. +%% +What makes us so bitter against people who outwit us +is that they think themselves cleverer than we are. +%% +What makes you think graduate school +is supposed to be satisfying? + -- Erica Jong, "Fear of Flying" +%% +What most people want is all of the power but none of the responsibility. +%% +What no spouse of a writer can ever understand +is that a writer is working when he's staring out the window. +%% +What nonsense people talk about happy marriages! +A man can be happy with any woman so long as he doesn't love her. + -- Wilde +%% +What on earth would a man do with himself +if something did not stand in his way? + -- H.G. Wells +%% +What one believes to be true either is true or becomes true. + -- John Lilly +%% +What one fool can do, another can. + -- Ancient Simian Proverb +%% +What orators lack in depth they make up in length. +%% +What pains others pleasures me, +At home am I in Lisp or C; +There i couch in ecstasy, +'Til debugger's poke i flee, +Into kernel memory. +In system space, system space, there shall i fare-- +Inside of a VAX on a silicon square. +%% +What passes for woman's intuition +is often nothing more than man's transparency. +%% +What publishers are looking for these days isn't radical feminism. +It's corporate feminism -- a brand of feminism designed to sell books +and magazines, three-piece suits, airline tickets, Scotch, cigarettes +and, most important, corporate America's message, which runs: Yes, +women were discriminated against in the past, but that unfortunate +mistake has been remedied; now every woman can attain wealth, prestige +and power by dint of individual rather than collective effort. + -- Susan Gordon +%% +What sane person could live in this world and not be crazy? + -- U.K. LeGuin +%% +What scoundrel stole the cork from my lunch? + -- J.D. Farley +%% +What segment's this, that, laid to rest Why lies it here, on public disk +On FHA0, is sleeping? And why is it now unprotected? +What system file, lay here a while A bug in incant, made it thus. +While hackers around it were weeping? The problem has not been corrected. + +This, this is "acct.run," Mount, mount all your DECtapes now +Accounting file for everyone. And copy the file somehow, somehow. +Dump, dump it and type it out, Dump, dump it and type it out, +The file, the highseg of login. The file, the highseg of login. + -- to Greensleeves +%% +What sin has not been committed in the name of efficiency? +%% +What soon grows old? Gratitude. + -- Aristotle +%% +What, still alive at twenty-two, +A clean upstanding chap like you? +Sure, if your throat 'tis hard to slit, +Slit your girl's, and swing for it. +Like enough, you won't be glad, +When they come to hang you, lad: +But bacon's not the only thing +That's cured by hanging from a string. +So, when the spilt ink of the night +Spreads o'er the blotting pad of light, +Lads whose job is still to do +Shall whet their knives, and think of you. + -- Hugh Kingsmill +%% + "What the hell are you getting so upset about? I thought you +didn't believe in God". + "I don't," she sobbed, bursting violently into tears, "but the +God I don't believe in is a good God, a just God, a merciful God. He's +not the mean and stupid God you make Him out to be". + -- Joseph Heller +%% +What the hell, go ahead and put all your eggs in one basket. +%% +What the large print giveth, the small print taketh away. +%% +What the scientists have in their briefcases is terrifying. + -- Nikita Khruschev +%% +What this country needs is a dime that will buy a good five-cent bagel. +%% +What this country needs is a good five cent ANYTHING! +%% +What this country needs is a good five cent microcomputer. +%% +What this country needs is a good five-cent nickel. +%% +What time is it? +I don't know, it keeps changing. +%% +What upsets me is not that you lied to me, +but that from now on I can no longer believe you. + -- Nietzsche +%% + "What was the worst thing you've ever done?" + "I won't tell you that, but I'll tell you the worst thing that +ever happened to me... the most dreadful thing." + -- Peter Straub, "Ghost Story" +%% +What we cannot speak about we must pass over in silence. + -- Wittgenstein +%% +What we need is either less corruption, +or more chance to participate in it. +%% +What we wish, that we readily believe. + -- Demosthenes +%% +What will you do if all your problems aren't solved by the time you die? +%% +What you don't know won't help you much either. + -- D. Bennett +%% +What you see is from outside yourself, and may come, or not, but is beyond +your control. But your fear is yours, and yours alone, like your voice, or +your fingers, or your memory, and therefore yours to control. If you feel +powerless over your fear, you have not yet admitted that it is yours, to do +with as you will. + -- Marion Zimmer Bradley, "Stormqueen" +%% +Whatever became of Strange de Jim? Well, he found a substitute for +cocaine: "You cover Q-tips with sandpaper and ram them up your +nostrils as far as they will go. Then you sniff talcum powder while +shredding hundred dollar bills." + -- Herb Caen, as discovered in Marya Schrier's scrapbook +%% +Whatever became of eternal truth? +%% +Whatever happened to the good old days +when sex was dirty and the air was clean? +%% +Whatever is not nailed down is mine. +What I can pry loose is not nailed down. + -- Collis P. Huntingdon +%% +Whatever it is, I fear Greeks even when they bring gifts. + -- Publius Vergilius Maro (Virgil) +%% +Whatever occurs from love is always beyond good and evil. + -- Friedrich Nietzsche +%% +Whatever you do will be insignificant, +but it is very important that you do it. + -- Gandhi +%% +Whatever you say about pornography, sex is here to stay. +%% +Whatever you want to do, you have to do something else first. +%% +What's all this bru-ha-ha? +%% +What's done to children, they will do to society. +%% +What's so funny? +%% + "What's that thing?" + "Well, it's a highly technical, sensitive instrument we +use in computer repair. Being a layman, you probably can't grasp +exactly what it does. We call it a two-by-four." + -- "Shoe", Jeff MacNelly +%% +What's the ugliest part of your body? +What's the ugliest part of your body? +Some say your nose, +Some say your toes, +But I think it's your mind. + -- Frank Zappa, 1965 +%% +When Boy Scouts do it, it's intense. +%% +When God endowed human beings with brains, +He did not intend to guarantee them. +%% +When God saw how faulty was man He tried again and made woman. As to +why he then stopped there are two opinions. One of them is woman's. + -- DeGourmont +%% +When I grow up, I want to be an honest +lawyer so things like that can't happen. + -- Richard Nixon, as a boy, on the Teapot Dome scandal +%% +When I have one foot in the grave I will tell the truth about women. I +shall tell it, jump into my coffin, pull the lid over me, and say, "Do +what you like now." + -- Tolstoy +%% +When I said "we", officer, I was referring to +myself, the four young ladies, and, of course, the goat. +%% +When I say the magic word to all these people, they will vanish forever. +I will then say the magic words to you, and you, +too, will vanish -- never to be seen again. + -- Kurt Vonnegut Jr., "Between Time and Timbuktu" +%% +When I sell liquor, it's called bootlegging; when my patrons serve +it on silver trays on Lake Shore Drive, it's called hospitality. + -- Al Capone +%% +When I think about myself, Sixty years in these folks' world +I almost laugh myself to death, The child I works for calls me girl +My life has been one great big joke, I say "Yes ma'am" for working's sake. +A dance that's walked Too proud to bend +A song that's spoke, Too poor to break, +I laugh so hard I almost choke I laugh until my stomach ache, +When I think about myself. When I think about myself. + +My folks can make me split my side, +I laughed so hard I nearly died, +The tales they tell, sound just like lying, +They grow the fruit, +But eat the rind, +I laugh until I start to crying, +When I think about my folks. + -- Maya Angelou +%% +When I was 16, I thought there was no hope for my father. +By the time I was 20, he had made great improvement. +%% +When I was in college, there were a lot of four-letter words you couldn't +say in front of girls. Now you can say them. But you can't say "girls". +%% +When I was in school, I cheated on my metaphysics exam: +I looked within the soul of the boy sitting next to me. + -- Woody Allen +%% +When I was younger, I could remember anything, whether it had happened +or not; but my faculties are decaying now and soon I shall be so I cannot +remember any but the things that never happened. It is sad to go to +pieces like this but we all have to do it. + -- Mark Twain +%% +When I'm gone, boxing will be nothing again. The fans with the cigars and +the hats turned down'll be there, but no more housewives and little men in +the street and foreign presidents. It's goin' to be back to the fighter who +comes to town, smells a flower, visits a hospital, blows a horn and says +he's in shape. Old hat. I was the onliest boxer in history people asked +questions like a senator. + -- Muhammad Ali +%% +When I'm good, I'm great; but when I'm bad, I'm better. + -- Mae West +%% +When Marriage is Outlawed, +Only Outlaws will have Inlaws. +%% +When a fellow says, "It ain't the money but +the principle of the thing," it's the money. + -- Kim Hubbard +%% +When a girl can read the handwriting on +the wall, she may be in the wrong rest room. +%% +When a girl marries, she exchanges the attentions +of many men for the inattentions of one. + Helen Rowland +%% +When a lion meets another with a louder roar, +the first lion thinks the last a bore. + -- G.B. Shaw +%% +When a lot of remedies are suggested for +a disease, that means it can't be cured. + -- Chekhov, "The Cherry Orchard" +%% +When a man assumes a public trust, he +should consider himself as public property. + -- Thomas Jefferson +%% +When a man is tired of London, he is tired of life. + -- Samuel Johnson +%% +When a man knows he is to be hanged in a fortnight, +it concentrates his mind wonderfully. + -- Samuel Johnson +%% +When a man sits with a pretty girl for an hour, it seems like a minute. +But let him sit on a hot stove for a minute-- and it's longer than any +hour. That's relativity. + -- Albert Einstein +%% +When a person goes on a diet, the first thing he loses is his temper. +%% +When a place gets crowded enough to require ID's, social collapse is not +far away. It is time to go elsewhere. The best thing about space travel +is that it made it possible to go elsewhere. + -- R.A. Heinlein, "Time Enough For Love" +%% +When a shepherd goes to kill a wolf, and takes his dog along to see +the sport, he should take care to avoid mistakes. The dog has certain +relationships to the wolf the shepherd may have forgotten. + -- Robert Pirsig, "Zen and the Art of Motorcycle Maintenance" +%% +When a woman gives me a present I have always two surprises: +first is the present, and afterward, having to pay for it. + -- Donnay +%% +When a woman marries again it is because she detested her first husband. +When a man marries again, it is because he adored his first wife. + -- Wilde +%% +When all else fails, EAT!!! +%% +When all else fails, read the instructions. +%% +When all else fails, try Kate Smith. +%% +When all other means of communication fail, try words. +%% +When among apes, one must play the ape. +%% +When angry, count four; when very angry, swear. + -- Mark Twain +%% +When arguments fail, use a blackjack. + -- Ed "Spike" O'Donnell +%% +When choosing between evils, I always +like to take the one I've never tried before. + -- Mae West +%% +When democracy granted democratic methods to us in times of opposition, this +was bound to happen in a democratic system. However, we National Socialists +never asserted that we represented a democratic point of view, but we have +declared openly that we used the democratic methods only to gain power and +that, after assuming the power, we would deny to our adversaries without any +consideration the means which were granted to us in times of our opposition. + -- Josef Goebbels +%% +When does later become never? +%% +When he got in trouble in the ring, [Ali] imagined a door swung open and +inside he could see neon, orange, and green lights blinking, and bats +blowing trumpets and alligators blowing trombones, and he could hear snakes +screaming. Weird masks and actors' clothes hung on the wall, and if he +stepped across the sill and reached for them, he knew that he was committing +himself to destruction. + -- George Plimpton +%% +When in Rome, live in the Roman way. + -- St. Ambrose +%% +When in charge ponder, +When in doubt mumble, +When in trouble delegate. +%% +When in doubt, do it. It's much easier +to apologize than to get permission. + -- Grace Murray Hopper +%% +When in doubt, do what the President does -- guess. +%% +When in doubt, follow your heart. +%% +When in doubt, lead trump. +%% +When in trouble or in doubt, run in circles, scream and shout. +%% +When it comes to helping you, some people stop at nothing. +%% +When it is not necessary to make a decision, +it is necessary not to make a decision. +%% +When it's dark enough you can see the stars. + -- Ralph Waldo Emerson, +%% +When love is gone, there's always justice. +And when justice is gone, there's always force. +And when force is gone, there's always Mom. +Hi, Mom! + -- Laurie Anderson +%% +When more and more people are thrown out of work, unemployment results. + -- Calvin Coolidge +%% +When my freshman roommate at Cornell found out I was Jewish, she was, +at her request, moved to a different room. She told me she didn't +think she had ever seen a Jew before. My only response was to begin +wearing a small Star of David on a chain around my neck. I had not +become a more observing Jew; rather, discovering that the label of +Jew was offensive to others made me want to let people know who I +was and what I believed in. Similarly, after talking to these young +women -- one of whom told me that she didn't think she had ever met +a feminist -- I've taken to identifying myself as a feminist in the +most unlikely of situations. + -- Susan Bolotin, "Voices From the Post-Feminist Generation" +%% +When neither their poverty nor their honor is +touched, the majority of men live content. + -- Niccolo Machiavelli +%% +When nothing can possibly go wrong, it will. +%% +When one burns one's bridges, what a very nice fire it makes. + -- Dylan Thomas +%% +When one wants to get rid of an unsupportable pressure, one needs hashish. + -- Friedrich Nietzsche +%% +When our best friends are in trouble, there is +always something that is not wholly displeasing to us. + -- La Rochefoucauld +%% +When oxygen Tech played Hydrogen U. +The Game had just begun, when Hydrogen scored two fast points +And Oxygen still had none +Then Oxygen scored a single goal +And thus it did remain, At Hydrogen 2 and Oxygen 1 +Called because of rain. +%% +When people have trouble communicating, +the least they can do is to shut up. + -- Tom Lehrer +%% +When people say nothing, they don't necessarily mean nothing. +%% +When pleasure remains, does it remain a pleasure? +%% +When some people decide it's time for everyone to make +big changes, it means that they want you to change first. +%% +When some people discover the truth, they just +can't understand why everybody isn't eager to hear it. +%% +When someone makes a move We'll send them all we've got, +Of which we don't approve, John Wayne and Randolph Scott, +Who is it that always intervenes? Remember those exciting fighting scenes? +U.N. and O.A.S., To the shores of Tripoli, +They have their place, I guess, But not to Mississippoli, +But first, send the Marines! What do we do? We send the Marines! + +For might makes right, Members of the corps +And till they've seen the light, All hate the thought of war: +They've got to be protected, They'd rather kill them off by + peaceful means. +All their rights respected, Stop calling it aggression-- +Till somebody we like can be elected. We hate that expression! + We only want the world to know + That we support the status quo; + They love us everywhere we go, + So when in doubt, send the Marines! + -- Tom Lehrer, "Send The Marines" +%% +When someone says "I want a programming language in +which I need only say what I wish done," give him a lollipop. +%% +When speculation has done its worst, two plus two still equals four. + -- S. Johnson +%% +When taxes are due, Americans tend to feel quite bled-white and blue. +%% +When the English language gets in my way, I walk over it. + -- Billy Sunday +%% +When the Universe was not so out of whack as it is today, and all the +stars were lined up in their proper places, you could easily count them +from left to right, or top to bottom, and the larger and bluer ones were +set apart, and the smaller yellowing types pushed off to the corners as +bodies of a lower grade... + -- Stanislaw Lem +%% +When the blind lead the blind they will both fall over the cliff. + -- Chinese proverb +%% +When the candles are out all women are fair. + -- Plutarch +%% +When the cup is full, carry it level. +%% +When the going gets tough, everyone leaves. + -- Lynch +%% +When the going gets tough, the tough go grab a beer. +%% +When the going gets tough, the tough go shopping. +%% +When the going gets weird, the weird turn pro. + -- Hunter S. Thompson +%% +When the government bureau's remedies do not match +your problem, you modify the problem, not the remedy. +%% +When the lights are out, all women are fair. + -- Plutarch +%% + When the lodge meeting broke up, Meyer confided to a friend. +"Abe, I'm in a terrible pickle! I'm strapped for cash and I haven't +the slightest idea where I'm going to get it from!" + "I'm glad to hear that," answered Abe. "I was afraid you +might have some idea that you could borrow from me!" +%% +When the only tool you have is a hammer, +every problem starts to look like a nail. +%% +When the revolution comes, count your change. +%% +When the sun shineth, make hay. + -- John Heywood +%% +When the wind is great, bow before it; +when the wind is heavy, yield to it. +%% +When there is an old maid in the house, a watch dog is unnecessary. + -- Balzac +%% +When they tell me to stick it where +the sun don't shine, I put it in Oregon. +%% +When things go well, expect something to +explode, erode, collapse or just disappear. +%% +When two people are under the influence of the most violent, most insane, +most delusive, and most transient of passions, they are required to swear +that they will remain in that excited, abnormal, and exhausting condition +continuously until death do them part. + -- George Bernard Shaw +%% +When we are planning for posterity, +we ought to remember that virtue is not hereditary. + -- Thomas Paine +%% +When we talk of tomorrow, the gods laugh. +%% +When we understand knowledge-based systems, it will be +as before -- except our finger-tips will have been singed. +%% +When we write programs that "learn", +it turns out we do and they don't. +%% +When women love us, they forgive us everything, even our crimes; +when they do not love us, they give us credit for nothing, not +even our virtues. + -- Balzac +%% +When you are at Rome live in the Roman style; +when you are elsewhere live as they live elsewhere. + -- St. Ambrose +%% +When you are in it up to your ears, keep your mouth shut. +%% +When you are working hard, get up and retch every so often. +%% +When you become used to never being alone, +you may consider yourself Americanized. +%% +When you dial a wrong number you never get a busy signal. +%% +When you dig another out of trouble, +you've got a place to bury your own. +%% +When you do not know what you are doing, do it neatly. +%% +When you go out to buy, don't show your silver. +%% +When you have eliminated the impossible, whatever +remains, however improbable, must be the truth. + -- Sherlock Holmes, "The Sign of Four" +%% +When you have shot and killed a man you have in some measure +clarified your attitude toward him. You have given a definite +answer to a definite problem. For better or worse you have +acted decisively. In a way, the next move is up to him. + -- R.A. Lafferty +%% +When you jump for joy, beware that no one +moves the ground from beneath your feet. + -- Stanislaw Lem +%% +When you live in a sick society, +just about everything you do is wrong. +%% +When you make your mark in the world, +watch out for guys with erasers. + -- The Wall Street Journal +%% +When you say that you agree to a thing in principle you mean that +you have not the slightest intention of carrying it out in practice. + -- Bismarck +%% +When you speak to others for their own good it's advice; +when they speak to you for your own good it's interference. +%% +When you try to make an impression, the +chances are that is the impression you will make. +%% + "When you wake up in the morning, Pooh," said Piglet at last, +"what's the first thing you say to yourself?" + "What's for breakfast?" said Pooh. "What do you say, Piglet?" + "I say, I wonder what's going to happen exciting today?" said +Piglet. + Pooh nodded thoughtfully. "It's the same thing," he said. +%% +When your conscious becomes unconscious, you are drunk. +When your unconscious becomes conscious, you are stoned. +%% +When your life is a leaf that the seasons tear off and condemn +They will bind you with love that is graceful and green as a stem. + -- Leonard Cohen, "Sisters of Mercy" +%% +When your memory goes, forget it! +%% +When your work speaks for itself, don't interrupt. + -- Henry J. Kaiser +%% +When you're away, I'm restless, lonely, +Wretched, bored, dejected; only +Here's the rub, my darling dear +I feel the same when you are near. + -- Samuel Hoffenstein, "When You're Away" +%% +When you were born, a big chance was taken for you. +%% +When you're dining out and you suspect +something's wrong, you're probably right. +%% +When you're down and out, lift up your +voice and shout, "I'M DOWN AND OUT"! +%% +When you're in command, command. + -- Admiral Nimitz +%% +When you're not looking at it, this fortune is written in FORTRAN. +%% +When you're ready to give up the struggle, who can you surrender to? +%% +When you've seen one nuclear war, you've seen them all. +%% +Whenever I feel like exercise, I lie down until the feeling passes. +%% +Whenever I hear anyone arguing for slavery, I feel +a strong impulse to see it tried on him personally. + -- A. Lincoln +%% +Whenever Richard Cory went downtown, + We people on the pavement looked at him: +He was a gentleman from sole to crown, + Clean-favored, and imperially slim. +And he was always quietly arrayed, + And he was always human when he talked; +But still he fluttered pulses when he said, + "Good morning," and he glittered when he walked. +And he was rich -- yes, richer than a king -- + And admirably schooled in every grace: +In fine, we thought that he was everything + To make us wish that we were in his place. +So on we worked, and waited for the light, + And went without the meat, and cursed the bread; +And Richard Cory, one calm summer night, + Went home and put a bullet through his head. + -- E.A. Robinson, "Richard Cory" +%% +Whenever a system becomes completely defined, +some damn fool discovers something which either +abolishes the system or expands it beyond recognition. +%% +Whenever anyone says, "theoretically," they really mean, "not really". + -- Dave Parnas +%% +Whenever people agree with me I always feel I must be wrong. + -- Oscar Wilde +%% +Whenever the literary German dives into a sentence, that +is the last you are going to see of him until he emerges +on the other side of his Atlantic with his verb in his mouth. + -- Mark Twain +%% +Whenever you find that you are on the +side of the majority, it is time to reform. + -- Mark Twain +%% +Where am I? Who am I? Am I? I +%% +Where humor is concerned there are no standards -- no one can say what +is good or bad, although you can be sure that everyone will. + -- John Kenneth Galbraith +%% +Where is John Carson now that we need him? + -- RLG +%% +Where, oh where, are you tonight? +Why did you leave me here all alone? +I searched the world over, +And I thought I'd found true love, +You met another and [Bronx cheer] you were gone! + -- Hee Haw +%% +Where the hell is Wall Drug? +%% +Where the system is concerned, you're not allowed to ask "Why?". +%% +Where there are visible vapors, having their prevenance +in ignited carbonaceous materials, there is conflagration. +%% +Where there is much light there is also much shadow. + -- Goethe +%% +Where there's a whip there's a way. +%% +Where there's a will, there's a relative. +%% +Where there's a will, there's an Inheritance Tax. +%% +Where will it all end? +Probably somewhere near where it all began. +%% +Where you stand depends on where you sit. + -- Rufus Miles, HEW +%% +Whereof one cannot speak, thereof one must be silent. + -- Wittgenstein +%% +Whether weary or unweary, O man, do not rest, +Do not cease your single-handed struggle. +Go on, do not rest. + -- An old Gujarati hymn +%% +Whether you can hear it or not, +The Universe is laughing behind your back. +%% +Which would you rather have, a bursting +planet or an earthquake here and there? + -- John Joseph Lynch +%% +While Europe's eye is fix'd on mighty things, +The fate of empires and the fall of kings; +While quacks of State must each produce his plan, +And even children lisp the Rights of Man; +Amid this mighty fuss just let me mention, +The Rights of Woman merit some attention. + -- Robert Burns, + Address on "The Rights of Woman", November 26, 1792 +%% +While anyone can admit to themselves they were +wrong, the true test is admission to someone else. +%% + While hunting, a man saw a beautiful nude woman come running out of +the woods and disappear across the clearing. Just as she got out of sight, +three men dressed in white uniforms came running out of the same woods. +"Hey, you," yelled one of them, "did you see a woman come by here?" + "Yes," replied the hunter. "What's the trouble?" + "She's an inmate of the county asylum, and gets loose every now and +then. We're trying to catch her." + "I can understand that," said the hunter, "But why is one of you +carrying a bucket of sand?" + "That's his handicap," said the spokesman, "he caught her last time." +%% +While money can't buy happiness, it certainly +lets you choose your own form of misery. +%% +While money doesn't buy love, it puts you in a great bargaining position. +%% +While most peoples' opinions change, +the conviction of their correctness never does. +%% +While there's life, there's hope. + -- Publius Terentius Afer (Terence) +%% +While walking down a crowded +City street the other day, +I heard a little urchin +To a comrade turn and say, +"Say, Chimmey, lemme tell youse, +I'd be happy as a clam +If only I was de feller dat +Me mudder t'inks I am. + +"She t'inks I am a wonder, My friends, be yours a life of toil +An' she knows her little lad Or undiluted joy, +Could never mix wit' nuttin' You can learn a wholesome lesson +Dat was ugly, mean or bad. From that small, untutored boy. +Oh, lot o' times I sit and t'ink Don't aim to be an earthly saint +How nice, 'twould be, gee whiz! With eyes fixed on a star: +If a feller was de feller Just try to be the fellow that +Dat his mudder t'inks he is." Your mother thinks you are. + -- Will S. Adkin, "If I Only Was the Fellow" +%% +While we are sleeping, two-thirds of the world is plotting to do us in. + -- Dean Rusk +%% +While you don't greatly need the outside world, it's +still very reassuring to know that it's still there. +%% +While you recently had your problems on the run, +they've regrouped and are making another attack. +%% +While your friend holds you affectionately by both +your hands you are safe, for you can watch both of his. +%% +Whip it, baby. +Whip it right. +Whip it, baby. +Whip it all night! +%% +Whip it, whip it good! +%% +Whistler's Law: + You never know who is right, but you always know who is in charge. +%% +Whistler's mother is off her rocker. +%% +White House carpenters have reworked the master bedroom, remodeling it +so that Ronnie can sleep with his head in the hall. That way, by the +time he wakes up, somebody will have already shined his hair. +%% +White dwarf seeks red giant for binary relationship. +%% +Whitehead's Law: + The obvious answer is always overlooked. +%% +White's Statement: + Don't lose heart! + +Owen's Commentary on White's Statement: + ...they might want to cut it out... + +Byrd's Addition to Owen's Commentary: + ...and they want to avoid a lengthy search. +%% +Who are you? +%% +Who can take the demands of the SDS seriously? + -- Nathan Pusey +%% +Who cares if it doesn't do anything? It was made with +our new Triple-Iso-Bifurcated-Krypton-Gate-MOS process... +%% +Who dat who say "who dat" when I say "who dat"? + -- Hattie McDaniel +%% +Who does not love wine, women, and song, +Remains a fool his whole life long. + -- Johann Heinrich Voss +%% +Who does not trust enough will not be trusted. + -- Lao Tsu +%% +Who goeth a-borrowing goeth a-sorrowing. + -- Thomas Tusser +%% +Who is D.B. Cooper, and where is he now? +%% +Who is John Galt? +%% +Who is W.O. Baker, and why is he saying those terrible things about me? +%% +Who made the world I cannot tell; +'Tis made, and here am I in hell. +My hand, though now my knuckles bleed, +I never soiled with such a deed. + -- A.E. Housman +%% +Who needs companionship when you +can sit alone in your room and drink? +%% +Who on earth would eat a charred caterpillar!? +No, no, you SINGE 'em! You SINGE 'em and eat 'em! +%% +Who to himself is law no law doth need, +offends no law, and is a king indeed. + -- George Chapman +%% +Who took the MMMMMM out of MURINE? +%% +Who was that masked man? +%% +Who will take care of the world after you're gone? +%% +Whoever dies with the most toys wins. +%% +Whoever fights monsters should see to it that in the process he does not +become a monster. And when you look into an abyss, the abyss also looks +into you. + -- Friedrich Nietzsche +%% +Whoever would lie usefully should lie seldom. +%% +Whom computers would destroy, they must first drive insane. +%% +Who's on first? +%% +Who's scruffy-looking? + -- Han Solo +%% +Why I Can't Go Out With You: + +I'd LOVE to, but... + -- I have to floss my cat. + -- I've dedicated my life to linguini. + -- I need to spend more time with my blender. + -- it wouldn't be fair to the other Beautiful People. + -- it's my night to pet the dog/ferret/goldfish. + -- I'm going downtown to try on some gloves. + -- I have to check the freshness dates on my dairy products. + -- I'm going down to the bakery to watch the buns rise. + -- I have an appointment with a cuticle specialist. + -- I have some really hard words to look up. + -- I've got a Friends of the Lowly Rutabaga meeting. + -- I promised to help a friend fold road maps. +%% +Why a man would want a wife is a big mystery to some people. +Why a man would want *two* wives is a bigamystery. +%% + Why are you doing this to me? + Because knowledge is torture, and there must be +awareness before there is change. + -- Jim Starlin, "Captain Marvel", #29 +%% +Why are you so hard to ignore? +%% +Why are you watching +The washing machine? +I love entertainment +So long as it's clean. + +Professor Doberman: + While the preceding poem is unarguably a change from the guarded +pessimism of "The Hound of Heaven," it cannot be regarded as an unqualified +improvement. Obscurity is of value only when it tends to clarify the poetic +experience. As much as one is compelled to admire the poem's technique, one +must question whether its byplay of complex literary allusions does not in +fact distract from the unity of the whole. In the final analysis, one +receives the distinct impression that the poem's length could safely have +been reduced by a factor of eight or ten without sacrificing any of its +meaning. It is to be hoped that further publication of this poem can be +suspended pending a thorough investigation of its potential subversive +implications. +%% +Why be a man when you can be a success? + -- Bertolt Brecht +%% +Why be difficult when, with a bit of effort, you could be impossible? +%% +Why did the Lord give us so much quickness of +movement unless it was to avoid responsibility with? +%% +Why did the Roman Empire collapse? +What's the Latin for office automation? +%% +Why do so many foods come packaged in plastic? +It's quite uncanny. +%% +Why do they call a fast a fast, when it goes so slow? +%% +Why do we want intelligent terminals +when there are so many stupid users? +%% +Why does a hearse horse snicker, hauling a lawyer away? + -- Carl Sandburg +%% +Why doesn't everybody leave everybody else the hell alone? + -- Jimmy Durante +%% +Why don't you fix your little problem... and light this candle? + -- Alan Shepherd, the first man into space, Gemini program +%% +Why, every one as they like; as the +good woman said when she kissed her cow. + -- Rabelais +%% +Why is it taking so long for her to bring out all the good in you? +%% +Why is it that there are so many more +horses' asses than there are horses? + -- G. Gordon Liddy +%% +Why is it that we rejoice at a birth and grieve at a funeral? +It is because we are not the person involved. + -- Mark Twain +%% +Why isn't there a special name for the tops of your feet? + -- Lily Tomlin +%% +Why isn't there some cheap and easy +way to prove how much she means to me? +%% +Why not go out on a limb? +Isn't that where the fruit is? +%% +Why was I born with such contemporaries? + -- Oscar Wilde +%% +Why would anyone want to be called "Later"? +%% +Wiker's Law: + Government expands to absorb all + available revenue and then some. +%% +Wilcox's Law: + A pat on the back is only a few + centimeters from a kick in the pants. +%% +Will Rogers never met you. +%% +Will you loan me $20.00 and only give me ten of it? +That way, you will owe me ten, and I'll owe you ten, and we'll be even! +%% +William Safire's Rules for Writers: + Remember to never split an infinitive. The passive voice +should never be used. Do not put statements in the negative form. +Verbs have to agree with their subjects. Proofread carefully to see if +you words out. If you reread your work, you can find on rereading a +great deal of repetition can be avoided by rereading and editing. A +writer must not shift your point of view. And don't start a sentence +with a conjunction. (Remember, too, a preposition is a terrible word +to end a sentence with.) Don't overuse exclamation marks!! Place +pronouns as close as possible, especially in long sentences, as of 10 +or more words, to their antecedents. Writing carefully, dangling +participles must be avoided. If any word is improper at the end of a +sentence, a linking verb is. Take the bull by the hand and avoid +mixing metaphors. Avoid trendy locutions that sound flaky. Everyone +should be careful to use a singular pronoun with singular nouns in +their writing. Always pick on the correct idiom. The adverb always +follows the verb. Last but not least, avoid cliches like the plague; +seek viable alternatives. +%% +Williams and Holland's Law: + If enough data is collected, + anything may be proven by statistical methods. +%% +Willie, looking in the mirror, Willie with the nursery shears +Sucked the mercury off Cut off both the baby's ears. +Thinking in his childish error To the baby so unsightly +It would cure the whooping cough. Mother raised her eyebrows slightly. + +At the funeral his weeping mother In the family drinking well +Sadly said to Mrs. Brown, Willie pushed his sister, Nell. +"'Twas a chilly day for Willie She's there still because it killed her, +When the mercury went down." Now, we have to buy a filter. +%% +Winning isn't everything, but losing isn't anything. +%% +Winter is the season in which people try to keep the house +as warm as it was in the summer, when they complained about the heat. +%% +[Wisdom] is a tree of life to those laying +hold of her, making happy each one holding her fast. + -- Proverbs 3:18, NSV +%% +Wisdom is knowing what to do with what you know. + -- J. Winter Smith +%% +Wisdom is rarely found on the best-seller list. +%% +Wishing without work is like fishing without bait. + -- Frank Tyger +%% +With Congress, every time they make a joke it's a law; +and every time they make a law it's a joke. + -- W. Rogers +%% +With a bushel of apples, you can have +a hell of a time with the doctor's wife. +%% +With a rubber duck, one's never alone. +%% +With all the fancy scientists in the world, +why can't they just once build a nuclear balm. +%% +With all the talent around, it's sort of +amazing that a woman could be up here with us. + -- Ralph Kiner, on introducing an award winner +%% +With clothes the new are best, with friends the old are best. +%% +With every passing hour our solar system comes forty-three thousand +miles closer to globular cluster M13 in the constellation Hercules, +and still there are some misfits who continue to insist that there +is no such thing as progress. + -- Ransom K. Ferm +%% +With her body, woman is more sincere than man; but with her mind +she lies. And when she lies, she does not believe herself. + -- Tolstoy +%% +With listening comes wisdom, with speaking repentance. +%% +With reasonable men I will reason; +with humane men I will plead; +but to tyrants I will give no quarter. + -- William Lloyd Garrison +%% +With stupidity the gods themselves struggle in vain. + -- Friedrich von Schiller +%% +With/Without - and who'll deny it's what the fighting's all about? + -- Pink Floyd +%% +Within a computer, natural language is unnatural. +%% +Within a month [in 1969] I had met the first of a small but not uninfluential +community of people who violently opposed SALT for a simple reason: It might +keep America from developing a first-strike capability against the Soviet +Union. I'll never forget being lectured by an Air Force colonel about how +we should have "nuked" the Soviets in late 1940s before they got The Bomb. +I was told that if SALT would go away, we'd soon have the capability to nuke +them again -- and this time we'd use it. + -- Roger Molander, former nuclear strategist for the + White House's National Security Council, Washington + Post, 21 March, 1982 +%% +Without adventure, civilization is in full decay. + -- Alfred North Whitehead +%% +Without fools there would be no wisdom. +%% +Without life, Biology itself would be impossible. +%% +Without love intelligence is dangerous; +without intelligence love is not enough. + -- Ashley Montagu +%% +Woke up this mornin' an' I had myself a beer, +Yeah, Ah woke up this mornin' an' I had myself a beer +The future's uncertain and the end is always near. + -- Jim Morrison, "Roadhouse Blues" +%% +Woke up this morning, don't believe what I saw. Hundred billion +bottles washed up on the shore. Seems I never noted being alone. +Hundred billion castaways looking for a call. +%% +Woman is generally so bad that the difference +between a good and a bad woman scarcely exists. + -- Tolstoy +%% +Woman on Street: Sir, you are drunk; very, very drunk. +Winston Churchill: Madame, you are ugly; very, very ugly. + I shall be sober in the morning. +%% +Woman was God's second mistake. + -- Nietzsche +%% +Woman was taken out of man -- not out of his head, to rule over him; nor +out of his feet, to be trampled under by him; but out of his side, to be +equal to him -- under his arm, that he might protect her, and near his heart +that he might love her. + -- Henry +%% +Woman would be more charming if one could +fall into her arms without falling into her hands. + -- DeGourmont +%% +Woman's advice has little value, but he who won't take it is a fool. + -- Cervantes +%% +Women are a problem, but if you haven't already guessed, +they're the kind of problem I enjoy wrestling with. + -- Warren Beatty +%% +Women are all alike. When they're maids they're mild as milk: +once make 'em wives, and they lean their backs against their +marriage certificates, and defy you. + -- Jerrold +%% +Women are always so eager to urge bachelors into matrimony: +is it from charity or revenge? + -- Scott +%% +Women are just like men, only different. +%% +Women are like elephants to me: I like to +look at them, but I wouldn't want to own one. + -- W.C. Fields +%% +Women are not much, but they are the best other sex we have. + -- Herold +%% +Women are nothing but machines for producing children. + -- Napoleon +%% +Women are wiser than men because they know less and understand more. + -- Stephens +%% +Women can keep a secret just as well as men, +but it takes more of them to do it. +%% +Women give themselves to God when the +Devil wants nothing more to do with them. + -- Arnould +%% +Women give to men the very gold of their lives. Possibly; +but they invariably want it back in such very small change. + -- Wilde +%% +Women in love consist of a little sighing, a little +crying, a little dying -- and a good deal of lying. + -- Ansey +%% +Women of genius commonly have masculine faces, figures and manners. +In transplanting brains to an alien soil God leaves a little of the +original earth clinging to the roots. + -- Bierce +%% +Women reason with the heart and are much less often wrong +than men who reason with the head. + -- DeLescure +%% +Women sometimes forgive a man who forces the opportunity, +but never a man who misses one. + -- Charles De Talleyrand-Perigord +%% +Women treat us just as humanity treats its gods. They worship +us and are always bothering us to do something for them. + -- Wilde +%% +Women waste men's lives and think they have +indemnified them by a few gracious words. + -- Balzac +%% +Women, when they are not in love, have all +the cold blood of an experienced attorney. + -- Balzac +%% +Women, when they have made a sheep of a man, +always tell him that he is a lion with a will of iron. + -- Balzac +%% +Women who desire to be like men, lack ambition. +%% +Women wish to be loved without a why or a wherefore; +not because they are pretty, or good, or well-bred, or +graceful, or intelligent, but because they are themselves. + -- Amiel +%% +Women's Libbers are OK, I just wouldn't want my sister to marry one. +%% +Women's virtue is man's greatest invention. + -- Cornelia Otis Skinner +%% +Wonder is the feeling of a philosopher, +and philosophy begins in wonder. + Socrates, quoting Plato +%% +Wonderful day. +Your hangover just makes it seem terrible. +%% +Woodward's Law: + A theory is better than its explanation. +%% +Woolsey-Swanson Rule: + People would rather live with a problem they cannot + solve rather than accept a solution they cannot understand. +%% +Words are the voice of the heart. +%% +Words can never express what words can never express. +%% +Words have a longer life than deeds. + -- Pindar +%% +Words must be weighed, not counted. +%% +Work consists of whatever a body is obliged to do. +Play consists of whatever a body is not obliged to do. + -- Mark Twain +%% +Work continues in this area. + -- DEC's SPR-Answering-Automaton +%% +Work expands so as to fill the time available for its completion. + -- C. Northcote Parkinson +%% +Work is the crab grass in the lawn of life. + -- Schulz +%% +Work is the curse of the drinking classes. +%% +Work smarter, not harder, and be careful of your speling. +%% +Work without a vision is slavery, +Vision without work is a pipe dream, +But vision with work is the hope of the world. +%% +World tensions have, if anything, increased in the quarter century +since H.G. Wells uttered his glum warning: "There is no more evil +thing on earth than race prejudice, none at all. I write deliberately +-- it is the worst single thing in life now. It justifies and holds +together more baseness, cruelty and abomination than any other sort of +error in the world." + -- Sydney Harris +%% +Worrying is like rocking in a rocking chair-- +It gives you something to do, but it doesn't get you anywhere. +%% +Worst Month of 1981 for Downhill Skiing: August. + +The lift lines are the shortest, though. +%% +Worst Month of the Year: February. + +February has only 28 days in it, which means that if you rent an +apartment, you are paying for three full days you don't get. Try to +avoid Februarys whenever possible. +%% +Worst Vegetable of the Year: Brussel sprout. + +This is also the worst vegetable of next year. +%% +Worth seeing? +Yes, but not worth going to see. +%% +Would it help if I got out and pushed? + -- Princess Leia Organa +%% +Would that my hand were as swift as my tongue. + -- Alfieri +%% +Would the last person to leave Michigan please turn out the lights? +%% +Would ye both eat your cake and have your cake? + -- John Heywood +%% +Would you care to drift aimlessly in my direction? +%% +Would you people stop playing these stupid games?!?!?!!!! +%% +"Would you tell me, please, which way I ought to go from here?" +"That depends a good deal on where you want to get to," said the Cat. + -- Lewis Carrol +%% +Wrinkles should merely indicate where smiles have been. + -- Mark Twain +%% +Write yourself a threatening letter and pen a defiant reply. +%% +Writing free verse is like playing tennis with the net down. +%% +Writing software is more fun than working. +%% +XEROX never does anything original. +%% +Xerox does it again and again and again and... +%% +Xerox never comes up with anything original. +%% +X-rated movies are all alike -- the only thing +they leave to the imagination is the plot. +%% +YEAR: + A period of three hundred and sixty-five disappointments. +%% +YO-YO: + Something that is occasionally up but normally down. + (see also Computer). +%% +Yacc owes much to a most stimulating collection of users, who have +goaded me beyond my inclination, and frequently beyond my ability in +their endless search for "one more feature". Their irritating +unwillingness to learn how to do things my way has usually led to my +doing things their way; most of the time, they have been right. + -- Stephen C. Johnson, "Yacc guide acknowledgements" +%% +Yawd [noun, Bostonese]: the campus of Have Id. + -- Webster's Unafraid Dictionary +%% +Yea from the table of my memory +I'll wipe away all trivial fond records. + -- Hamlet +%% +Yeah, God is dead, he laughed himself to death. +%% +Q: What do you call a dog with no legs? +A: What does it matter? He can't come anyway. + + [I got a dog with no legs -- I call him Cigarette. + Every night, I take him out for a drag. Ed.] +%% +Yeah, there are more important things in life than money, +but they won't go out with you if you don't have any. +%% +Yes, but every time I try to see things your way, I get a headache. +%% +Yes, but which self do you want to be? +%% + "Yes, let's consider," said Bruno, putting his thumb into his +mouth again, and sitting down upon a dead mouse. + "What do you keep that mouse for?" I said. "You should either +bury it or else throw it into the brook." + "Why, it's to measure with!" cried Bruno. "How ever would you +do a garden without one? We make each bed three mouses and a half +long, and two mouses wide." + I stopped him as he was dragging it off by the tail to show me +how it was used... + -- Lewis Carroll, "Sylvie and Bruno" +%% +Yesterday I was a dog. Today I'm a dog. +Tomorrow I'll probably still be a dog. +Sigh! There's so little hope for advancement. + -- Snoopy +%% +Yet creeds mean very little, Coth answered the dark god, still speaking +almost gently. The optimist proclaims that we live in the best of all +possible worlds; and the pessimist fears this is true. + -- J.B. Cabell, "The Silver Stallion" +%% +Yield to temptation; it may not pass your way again. +%% +You ain't learning nothing when you're talking. +%% +You always have the option of pitching baseballs at empty +spray paint cans in a cul-de-sac in a Cleveland suburb. +%% +You are a bundle of energy, always on the go. +%% +You are a fluke of the universe; you have no right to be here. +%% +You are a taxi driver. Your cab is yellow and black, and has been in +use for only seven years. One of its windshield wipers is broken, and +the carburetor needs adjusting. The tank holds 20 gallons, but at the +moment is only three-quarters full. How old is the taxi driver?" +%% +You are a wish to be here wishing yourself. + -- Philip Whalen +%% +You are always busy. +%% +You are an insult to my intelligence! +I demand that you log off immediately. +%% +You are capable of planning your future. +%% +You are confused; but this is your normal state. +%% +You are deeply attached to your friends and acquaintances. +%% +You are destined to become the commandant of the +fighting men of the department of transportation. +%% +You are dishonest, but never to the point of hurting a friend. +%% +You are fairminded, just and loving. +%% +You are false data. +%% +You are farsighted, a good planner, +an ardent lover, and a faithful friend. +%% +You are fighting for survival in your own sweet and gentle way. +%% +You are going to have a new love affair. +%% +You are in a maze of little twisting passages, all alike. +%% +You are in a maze of little twisting passages, all different. +%% +You are in the hall of the mountain king. +%% +You are lost in the Swamps of Despair. +%% +You are loved by the multitudes. +Have you been to the clinic lately? +%% +You are magnetic in your bearing. +%% +You are never given a wish without also being given the +power to make it true. You may have to work for it, however. + -- R. Bach, "Messiah's Handbook : Reminders for + the Advanced Soul" +%% +You are not a fool just because you have done +something foolish -- only if the folly of it escapes you. +%% +You are not dead yet. +But watch for further reports. +%% +You are not permitted to kill a woman who has wronged you, but nothing +forbids you to reflect that she is growing older every minute. You are +avenged fourteen hundred and forty times a day. + -- Bierce +%% +You are now in Atlanta, Georgia. +Please set your clocks back 200 years. +%% +You are number 6! Who is number one? +%% +"You are old, father William," the young man said, + "And your hair has become very white; +And yet you incessantly stand on your head -- + Do you think, at your age, it is right?" + +"In my youth," father William replied to his son, + "I feared it might injure the brain; +But, now that I'm perfectly sure I have none, + Why, I do it again and again." + +"You are old," said the youth, "as I mentioned before, + And have grown most uncommonly fat; +Yet you turned a back-somersault in at the door -- + Pray what is the reason of that?" + +"In my youth," said the sage, as he shook his grey locks, + "I kept all my limbs very supple +By the use of this ointment -- one shilling the box -- + Allow me to sell you a couple?" +%% +"You are old," said the youth, "and your jaws are too weak + For anything tougher than suet; +Yet you finished the goose, with the bones and the beak -- + Pray, how did you manage to do it?" + +"In my youth," said his father, "I took to the law, + And argued each case with my wife; +And the muscular strength which it gave to my jaw, + Has lasted the rest of my life." + +"You are old," said the youth, "one would hardly suppose + That your eye was as steady as ever; +Yet you balanced an eel on the end of your nose -- + What made you so awfully clever?" + +"I have answered three questions, and that is enough," + Said his father. "Don't give yourself airs! +Do you think I can listen all day to such stuff? + Be off, or I'll kick you down stairs!" +%% +You are only young once, but you can stay immature indefinitely. +%% +You are scrupulously honest, frank, and straightforward. +Therefore you have few friends. +%% +You are sick, twisted and perverted. +I like that in a person. +%% +You are so boring that when I see you my feet go to sleep. +%% +You are standing on my toes. +%% +You are taking yourself far too seriously. +%% +You are transported to a room where you are faced by a wizard who +points to you and says, "Them's fighting words!" You immediately get +attacked by all sorts of denizens of the museum: there is a cobra +chewing on your leg, a troglodyte is bashing your brains out with a +gold nugget, a crocodile is removing large chunks of flesh from you, a +rhinoceros is goring you with his horn, a sabre-tooth cat is busy +trying to disembowel you, you are being trampled by a large mammoth, a +vampire is sucking you dry, a Tyranosaurus Rex is sinking his six inch +long fangs into various parts of your anatomy, a large bear is +dismembering your body, a gargoyle is bouncing up and down on your +head, a burly troll is tearing you limb from limb, several dire wolves +are making mince meat out of your torso, and the wizard is about to +transport you to the corner of Westwood and Broxton. Oh dear, you seem +to have gotten yourself killed, as well. + +You scored 0 out of 250 possible points. +That gives you a ranking of junior beginning adventurer. +To achieve the next higher rating, you need to score 32 more points. +%% +You are wise, witty, and wonderful, +but you spend too much time reading this sort of trash. +%% +You ask what a nice girl will do? +She won't give an inch, but she won't say no. + -- Marcus Valerius Martialis +%% +You attempt things that you do not even plan +because of your extreme stupidity. +%% +You auto buy now. +%% +You buttered your bread, now lie in it! +%% +You buy a judge by weight, like iron in a junk yard. A justice of the +peace or a magistrate can be had for a five-dollar bill. In the +municipal courts, he will cost you ten. In the circuit or superior +courts, he wants fifteen. The state appellate courts or the state +supreme court is on a par with the Federal courts. By the time a judge +reaches such courts, he is middle-aged, thick around the middle, fat +between the ears. He's heavy. You can't buy a Federal judge for less +than a twenty-dollar bill. + -- Jake "Greasy Thumb" Guzik +%% +You can always pick up your needle and move to another groove. + -- Tim Leary +%% +You can always tell luck from ability by its duration. +%% +You can be replaced by this computer. +%% +You can bear anything if it isn't your own fault. + -- Katharine Fullerton Gerould +%% +You can bring men from other parts of the world who are sane. And you +know what happens? At the very moment they cross those mountains... +they go mad. Instantaneously and automatically, at the very moment +they cross the mountains into California, they go insane. + -- Quentin Genter +%% +You can cage a swallow, can't you, + but you can't swallow a cage, can you? +Girl, bathing on Bikini, eyeing boy, + finds boy eyeing bikini on bathing girl. +A man, a plan, a canal -- Panama! + -- The Palindromist +%% +You can create your own opportunities this week. +Blackmail a senior executive. +%% +You can destroy your now by worrying about tomorrow. + -- Janis Joplin +%% +You can do very well in speculation where +land or anything to do with dirt is concerned. +%% +You can drive a horse to water, but a pencil must be lead. +%% +You can fool some of the people all of the time, +and all of the people some of the time, +but you can make a fool of yourself anytime. +%% +You can fool some of the people some of the time, +and some of the people all of the time, and that is sufficient. +%% +You can get more with a kind word and a +gun than you can get with a kind word alone. + -- Al Capone +%% +You can get there from here, but why on earth would you want to? +%% +You can grovel with a lover, you can grovel with a friend, +You can grovel with your boss, and it never has to end. + +(chorus) Grovel, grovel, grovel, every night and every day, + Grovel, grovel, grovel, in your own peculiar way. + +You can grovel in a hallway, you can grovel in a park, +You can grovel in an alley with a mugger after dark. +(chorus) + +You can grovel with your uncle, you can grovel with your aunt, +You can grovel with your Apple, even though you say you can't. +(chorus) +%% +You can have peace. Or you can have freedom. +Don't ever count on having both at once. + -- Lazarus Long +%% +You can lead a horse to water, but if you can +get him to float on his back, you've got something. +%% +You can make it illegal, but you can't make it unpopular. +%% +You can measure a programmer's perspective by noting +his attitude on the continuing vitality of FORTRAN. +%% +You can move the world with an idea, +but you have to think of it first. +%% +You can never do just one thing. + -- Hardin +%% +You can never tell which way the train went by looking at the tracks. +%% +You can never trust a woman; she may be true to you. +%% +You can now buy more gates with less +specifications than at any other time in history. + -- Kenneth Parker +%% +You can observe a lot just by watching. + -- Yogi Berra +%% +You can rent this space for only $5 a week. +%% +You can tell how far we have to go, +when Fortran is the language of supercomputers. + -- Steven Feiner +%% +You canna change the laws of physics, Captain; +I've got to have thirty minutes! +%% +You cannot achieve the impossible without attempting the absurd. +%% +You cannot choose your battlefield, the gods do that for you. +But you can plant a standard where a standard never flew. + -- Nathalia Crane +%% +You cannot have a science without measurement. + -- R. W. Hamming +%% +You cannot kill time without injuring eternity. +%% +You cannot propel yourself forward by patting yourself on the back. +%% +You cannot see the wood for the trees. + -- John Heywood +%% +You cannot shake hands with a clenched fist. + -- Indira Gandhi +%% +You cannot use your friends and have them too. +%% +You can't break eggs without making an omelet. +%% +You can't carve your way to success without cutting remarks. +%% +You can't cheat an honest man, never give +a sucker an even break or smarten up a chump. + -- W.C. Fields +%% +You can't cheat the phone company. +%% +You can't depend on the man who made the mess to clean it up. + -- Richard Nixon, 1952 +%% +You can't erase a dream, you can only wake me up. + -- Peter Frampton +%% +"You can't expect a mother to be with a small child all the time", +Margaret Mead once remarked, with her usual good sense, but in 1978 +she shocked feminists by snapping that women don't really have +children to put them in day care twelve hours a day, either. + -- Caroline Bird, "The Two Paycheck Marriage" +%% +You can't fall off the floor. +%% +You can't get there from here. +%% +You can't go home again, unless you set $HOME. +%% +You can't judge a book by the way it wears its hair. +%% +You can't kiss a girl unexpectedly -- +only sooner than she thought you would. +%% +You can't mend a wristwatch while falling from an airplane. +%% +You can't play your friends like marks, kid. + -- Henry Gondorf, "The Sting" +%% +You can't push on a string. +%% +You can't start worrying about what's going to happen. +You get spastic enough worrying about what's happening now. + -- Lauren Bacall +%% +You can't take damsel here now. +%% +You can't take it with you -- +especially when crossing a state line. +%% +You can't teach people to be lazy -- +either they have it, or they don't. + -- Dagwood Bumstead +%% +You can't underestimate the power of fear. + -- Tricia Nixon Cox +%% +You climb to reach the summit, but once +there, discover that all roads lead down. + -- Stanislaw Lem, "The Cyberiad" +%% +You could get a new lease on life -- if only you +didn't need the first and last month in advance. +%% +You could live a better life, if you +had a better mind and a better body. +%% +You couldn't even prove the White House +staff sane beyond a reasonable doubt. + -- Ed Meese, on the Hinckley verdict +%% +You definitely intend to start living sometime soon. +%% +You dialed 5483. +%% +You display the wonderful traits of charm and courtesy. +%% +You do not have mail. +%% +You don't have to be nice to people on the way up +if you're not planning on coming back down. + -- Oliver Warbucks, "Annie" +%% +You don't have to know how the computer +works, just how to work the computer. +%% +You don't have to think too hard when you talk to teachers. + -- J.D. Salinger +%% +You don't move to Edina, you achieve Edina. + -- Guindon +%% +You don't sew with a fork, so I see no +reason to eat with knitting needles. + -- Miss Piggy, on eating Chinese Food +%% +You enjoy the company of other people. +%% +You feel a whole lot more like you do +now than you did when you used to. +%% +You fill a much-needed gap. +%% +You get along very well with everyone except animals and people. +%% +You get what you pay for. + -- Gabriel Biel +%% +You give me space to belong to myself yet without separating me +from your own life. May it all turn out to your happiness. + -- Goethe +%% +You go down to the pickup station, + craving warmth and beauty; +You settle for less than fascination -- + a few drinks later you're not so choosy. +And the closing lights strip off the shadows + on this strange new flesh you've found -- +Clutching the night to you like a fig leaf + you hurry to the blackness + and the blankets to lay down an impression + and your loneliness. + -- Joni Mitchell +%% +You got to be very careful if you don't know +where you're going, because you might not get there. + -- Yogi Berra +%% +You got to pay your dues if you want to sing the blues, +And you know it don't come easy ... +I don't ask for much, I only want trust, +And you know it don't come easy ... +%% +You guys have been practicing discrimination for years. +Now it's our turn. + -- Thurgood Marshall, quoted by Justice Douglas +%% +You had mail, but the super-user read it, and deleted it! +%% +You had mail. +Paul read it, so ask him what it said. +%% +You had some happiness once, +but your parents moved away, and you had to leave it behind. +%% +You have Egyptian flu: you're going to be a mummy. +%% +You have a deep appreciation of the arts and music. +%% +You have a deep interest in all that is artistic. +%% +You have a massage (from the Swedish prime minister). +%% +You have a message from the operator. +%% +You have a reputation for being thoroughly reliable and trustworthy. +A pity that it's totally undeserved. +%% +You have a strong appeal for members of the opposite sex. +%% +You have a strong appeal for members of your own sex. +%% +You have a strong desire for a home +and your family interests come first. +%% +You have a tendency to feel you are superior to most computers. +%% +You have a truly strong individuality. +%% +You have a will that can be influenced +by all with whom you come in contact. +%% +You have all eternity to be cautious in when you're dead. + -- Lois Platford +%% +You have all the characteristics of a popular politician: +a horrible voice, bad breeding, and a vulgar manner. + -- Aristophanes +%% +You have an ability to sense and know higher truth. +%% +You have an ambitious nature and may make a name for yourself. +%% +You have an unusual equipment for success. +Be sure to use it properly. +%% +You have an unusual understanding of +the problems of human relationships. +%% +You have been in Afghanistan, I perceive. + -- Sherlock Holmes, "A Study in Scarlet" +%% +You have been selected for a secret mission. +%% +You have had a long-term stimulation relative to business. +%% +You have literary talent that you should take pains to develop. +%% +You have mail. +%% +You have many friends and very few living enemies. +%% +You have no real enemies. +%% +You have not converted a man because you have silenced him. + -- John Viscount Morley +%% +You have taken yourself too seriously. +%% +You have the capacity to learn from mistakes. +You'll learn a lot today. +%% +You have the power to influence all with whom you come in contact. +%% +You have to run as fast as you can just to stay where you are. +If you want to get anywhere, you'll have to run much faster. + -- Lewis Carroll +%% +You humans are all alike. +%% +You just wait, I'll sin till I blow up! + -- Dylan Thomas +%% +You k'n hide de fier, but w'at you gwine do wid de smoke? + -- Joel Chandler Harris, proverbs of Uncle Remus +%% +You knew the job was dangerous when you took it, Fred. + -- Superchicken +%% +You know, Callahan's is a peaceable bar, but if +you ask that dog what his favorite formatter is, +and he says "roff! roff!", well, I'll just have to... +%% +You know how to win a victory, Hannibal, but not how to use it. + -- Maharbal +%% +You know it's Monday when you wake up and it's Tuesday. + -- Garfield +%% + "You know, it's at times like this when I'm trapped in a Vogon +airlock with a man from Betelgeuse and about to die of asphyxiation in +deep space that I really wish I'd listened to what my mother told me +when I was young!" + "Why, what did she tell you?" + "I don't know, I didn't listen." + -- Douglas Adams, "The Hitchhiker's Guide to the Galaxy" +%% +You know my heart keeps tellin' me, +You're not a kid at thirty-three, +You play around you lose your wife, +You play too long, you lose your life. +Some gotta win, some gotta lose, +Goodtime Charlie's got the blues. +%% +You know, the difference between this company and +the Titanic is that the Titanic had paying customers. +%% +You know you're in trouble when... +1) You wake up face down on the pavement. +2) Your wife wakes up feeling amorous and you have a headache. +3) You turn on the news and they're showing emergency routes + out of the city. +4) Your twin sister forgot your birthday. +5) You wake up and discover your waterbed broke and then + remember that you don't have a waterbed. +6) Your doctor tells you you're allergic to chocolate. +%% +You know you're in trouble when... +1) Your car horn goes off accidentally and remains stuck as you + follow a group of Hell's Angels on the freeway. +2) You want to put on the clothes you wore home from the party + and there aren't any. +3) Your boss tells you not to bother to take off your coat. +4) The bird singing outside your window is a buzzard. +5) You wake up and your braces are locked together. +6) Your mother approves of the person you're dating. +%% +You know you're in trouble when... +(1) Your only son tells you he wishes Anita Bryant would mind + her own business. +(2) You put your bra on backwards and it fits better. +(3) You call Suicide Prevention and they put you on hold. +(4) You see a `60 Minutes' news team waiting in your office. +(5) Your birthday cake collapses from the weight of the candles. +(6) Your 4-year old reveals that it's "almost impossible" to + flush a grapefruit down the toilet. +(7) You realize that you've memorized the back of the cereal box. +%% +You know you're in trouble when... +(1) You've been at work for an hour before you notice that your + skirt is caught in your pantyhose. +(2) Your blind date turns out to be your ex-wife. +(3) Your income tax check bounces. +(4) You put both contact lenses in the same eye. +(5) Your wife says, "Good morning, Bill" and your name is George. +(6) You wake up to the soothing sound of flowing water... the day + after you bought a waterbed. +(7) You go on your honeymoon to a remote little hotel and the desk + clerk, bell hop, and manager have a "Welcome Back" party + for your spouse. +%% +You know you've been sitting in front of your Lisp machine too long +when you go out to the junk food machine and start wondering how to +make it give you the CADR of Item H so you can get that yummie +chocolate cupcake that's stuck behind the disgusting vanilla one. +%% +You learn to write as if to someone else +because NEXT YEAR YOU WILL BE "SOMEONE ELSE". +%% +You like to form new friendships and make new acquaintances. +%% +You lived with a man who wore white belts? +Laura, I'm disappointed in you. + -- Remington Steele +%% +You look tired. +%% +You love peace. +%% +You love your home and want it to be beautiful. +%% +You may be gone tomorrow, but that +doesn't mean that you weren't here today. +%% +You may be infinitely smaller than some things, +but you're infinitely larger than others. +%% +You may be recognized soon. Hide. +%% +You may get an opportunity for advancement today. Watch it! +%% +You may have heard that a dean is +to faculty as a hydrant is to a dog. + -- Alfred Kahn +%% +You may my glories and my state dispose, +But not my griefs; still am I king of those. + -- William Shakespeare, "Richard II" +%% +I may not be totally perfect, but parts of me are excellent. + -- Ashleigh Brilliant +%% +You mentioned your name as if I should recognize it, but beyond +the obvious facts that you are a bachelor, a solicitor, a freemason, +and an asthmatic, I know nothing whatever about you. + -- Sherlock Holmes, "The Norwood Builder" +%% +You might have mail. +%% +You must dine in our cafeteria. +You can eat dirt cheap there!!!! +%% +You must include all income you receive in the form of money, property +and services if it is not specifically exempt. Report property (goods) +and services at their fair market values. Examples include income from +bartering or swapping transactions, side commissions, kickbacks, rent +paid in services, illegal activities (such as stealing, drugs, etc.), +cash skimming by proprietors and tradesmen, "moonlighting" services, +gambling, prizes and awards. Not reporting such income can lead to +prosecution for perjury and fraud. + -- Excerpt from Taxachussettes income tax forms +%% +You must realize that the computer has it in for you. The irrefutable +proof of this is that the computer always does what you tell it to do. +%% +You need more time; and you probably always will. +%% +You need no longer worry about the future. +This time tomorrow you'll be dead. +%% +You need not worry about your future. +%% +You never gain something but that you lose something. + -- Thoreau +%% +You never get a second chance to make a first impression. +%% +You never go anywhere without your soul. +%% +You never have to change anything you +got up in the middle of the night to write. + -- Saul Bellow +%% +You never hesitate to tackle the most difficult problems. +%% +You never know how many friends you +have until you rent a house on the beach. +%% +You never know what is enough until you know what is more than enough. + -- William Blake +%% +You never learned anything by doing it right. +%% +You now have Asian Flu. +%% +You own a dog, but you can only feed a cat. +%% +You plan things that you do not even +attempt because of your extreme caution. +%% +You prefer the company of the opposite +sex, but are well liked by your own. +%% +You probably wouldn't worry about what people +think of you if you could know how seldom they do. + -- Olin Miller +%% +You recoil from the crude; you tend naturally toward the exquisite. +%% +You roll my log, and I will roll yours. + -- Lucius Annaeus Seneca +%% + "You say there are two types of people?" + "Yes, those who separate people into two groups and those that +don't." + "Wrong. There are three groups: + Those who separate people into three groups. + Those who don't separate people into groups. + Those who can't decide." + "Wait a minute, what about people who separate people into +two groups?" + "Oh. Okay, then there are four groups." + "Aren't you then separating people into four groups?" + "Yeah." + "So then there's a fifth group, right?" + "You know, the problem is these idiots who can't make up their +minds." +%% +You scratch my tape, and I'll scratch yours. +%% +You see things; and you say "Why?" +But I dream things that never were; and I say "Why not?" + -- George Bernard Shaw, "Back to Methuselah" + [No, it WASN'T J.F. Kennedy. Ed.] +%% +You see, wire telegraph is a kind of a very, very long cat. You pull +his tail in New York and his head is meowing in Los Angeles. Do you +understand this? And radio operates exactly the same way: you send +signals here, they receive them there. The only difference is that +there is no cat. + -- Albert Einstein, when asked to describe radio +%% +You seek to shield those you love +and you like the role of the provider. +%% +You shall be rewarded for a dastardly deed. +%% +You shall judge of a man by his foes as well as by his friends. + -- Joseph Conrad +%% +You should avoid hedging, at least that's what I think. +%% +You should go home. +%% +You should never wear your best trousers +when you go out to fight for freedom and liberty. + -- Henrick Ibsen +%% +You shouldn't have to pay for your love with your bones and your flesh. + -- Pat Benatar, "Hell is for Children" +%% +You shouldn't wallow in self-pity. But it's OK to put +your feet in it and swish them around a little. + -- Guindon +%% +You single-handedly fought your way into this hopeless mess. +%% +You teach best what you most need to learn. +%% +You tread upon my patience. + -- William Shakespeare, "Henry IV" +%% +You two ought to be more careful-- +your love could drag on for years and years. +%% +You will always find something in the last place you look. +%% +You will always have good luck in your personal affairs. +%% +You will attract cultured and artistic people to your home. +%% +You will be Told about it Tomorrow. Go Home and Prepare Thyself. +%% +You will be a winner today. Pick a fight with a four-year-old. +%% +You will be advanced socially, +without any special effort on your part. +%% +You will be aided greatly by a person +whom you thought to be unimportant. +%% +You will be audited by the Internal Revenue Service. +%% +You will be awarded a medal for disregarding safety in saving someone. +%% +You will be awarded some great honor. +%% +You will be awarded the Nobel Peace Prize... posthumously. +%% +You will be called upon to help a friend in trouble. +%% +You will be dead within a year. +%% +You will be divorced within a year. +%% +You will be given a post of trust and responsibility. +%% +You will be held hostage by a radical group. +%% +You will be honored for contributing +your time and skill to a worthy cause. +%% +You will be imprisoned for contributing +your time and skill to a bank robbery. +%% +You will be married within a year. +%% +You will be married within a year, and divorced within two. +%% +You will be misunderstood by everyone. +%% +You will be recognized and honored as a community leader. +%% +You will be reincarnated as a toad; and you will be much happier. +%% +You will be run over by a beer truck. +%% +You will be run over by a bus. +%% +You will be singled out for promotion in your work. +%% +You will be successful in love. +%% +You will be surprised by a loud noise. +%% +You will be surrounded by luxury. +%% +You will be the last person to buy a Chrysler. +%% +You will be the victim of a bizarre joke. +%% +You will be traveling and coming into a fortune. +%% +You will be winged by an anti-aircraft battery. +%% +You will become rich and famous unless you don't. +%% +You will contract a rare disease. +%% +You will engage in a profitable business activity. +%% +You will experience a strong urge to do good; but it will pass. +%% +You will feel hungry again in another hour. +%% +You will forget that you ever knew me. +%% +You will gain money by a fattening action. +%% +You will gain money by a speculation or lottery. +%% +You will gain money by an illegal action. +%% +You will gain money by an immoral action. +%% +You will get what you deserve. +%% +You will give someone a piece of your mind, which you can ill afford. +%% +You will have a head crash on your private pack. +%% +You will have a long and boring life. +%% +You will have a long and unpleasant discussion with your supervisor. +%% +You will have domestic happiness and faithful friends. +%% +You will have good luck and overcome many hardships. +%% +You will have long and healthy life. +%% +You will have many recoverable tape errors. +%% +You will hear good news from one you thought unfriendly to you. +%% +You will inherit millions of dollars. +%% +You will inherit some money or a small piece of land. +%% +You will live a long, healthy, happy life and make bags of money. +%% +You will live to see your grandchildren. +%% +You will lose an important disk file. +%% +You will lose an important tape file. +%% +You will meet an important person who will help you advance professionally. +%% +You will never know hunger. +%% +You will not be elected to public office this year. +%% +You will obey or molten silver will be poured into your ears. +%% +You will outgrow your usefulness. +%% +You will overcome the attacks of jealous associates. +%% +You will pass away very quickly. +%% +You will pay for your sins. +If you have already paid, please disregard this message. +%% +You will pioneer the first Martian colony. +%% +You will probably marry after a very brief courtship. +%% +You will reach the highest possible point in your business or profession. +%% +You will receive a legacy which will place you above want. +%% +You will remember something that you should not have forgotten. +%% +You will soon forget this. +%% +You will soon meet a person who will play an important role in your life. +%% +You will step on the night soil of many countries. +%% +You will stop at nothing to reach your objective, +but only because your brakes are defective. +%% +You will triumph over your enemy. +%% +You will visit the Dung Pits of Glive soon. +%% +You will win success in whatever calling you adopt. +%% +You will wish you hadn't. +%% +You won't skid if you stay in a rut. + -- Frank Hubbard +%% +You work very hard. Don't try to think as well. +%% +You worry too much about your job. +Stop it. You are not paid enough to worry. +%% +You would if you could but you can't so you won't. +%% +You'd better smile when they watch you, smile like you're in control. + -- Smile, "Was (Not Was)" +%% +You'd like to do it instantaneously, but that's too slow. +%% +You'll always be, +What you always were, +Which has nothing to do with, +All to do, with her. + -- Company +%% +You'll be called to a post requiring +ability in handling groups of people. +%% +You'll be sorry... +%% +You'll feel devilish tonight. +Toss dynamite caps under a flamenco dancer's heel. +%% +You'll feel much better once you've given up hope. +%% +You'll never be the man your mother was! +%% +You'll never see all the places, or read all the +books, but fortunately, they're not all recommended. +%% +You'll wish that you had done some of the +hard things when they were easier to do. +%% + Young men and young women may work systematically six days +in the week and rise fresh in the morning, but let them attend modern +dances for only a few hours each evening and see what happens. The +Waltz, Polka, Gallop and other dances of the same kind will be +disastrous in their effects to both sexes. Health and vigor will +vanish like the dew before the sun. + It is not the extraordinary exercise which harms the dancer, +but rather the coming into close contact with the opposite sex. It +is the fury of lust craving incessantly for more pleasure that +undermines the soul, the body, the sinews and nerves. Experience and +statistics show beyond doubt that passionate excessive dancing girls +can hardly reach twenty-five years of age and men thirty-one. Even +if they reached that age they will in most instances be broken in +health physically and morally. This is the claim of prominent +physicians in this country. + -- Quote from a 1910 periodical +%% +Young men are fitter to invent than to judge; fitter for execution than for +counsel; and fitter for new projects than for settled business. For the +experience of age, in things that fall within the compass of it, directeth +them; but in new things, abuseth them. The errors of young men are the ruin +of business; but the errors of aged men amount but to this, that more might +have been done, or sooner. Young men, in the conduct and management of +actions, embrace more than they can hold; stir more than they can quiet; fly +to the end, without consideration of the means and degrees; pursue some few +principles which they have chanced upon absurdly; care not how they innovate, +which draws unknown inconveniences; and, that which doubleth all errors, will +not acknowledge or retract them; like an unready horse, that will neither stop +nor turn. Men of age object too much, consult too long, adventure too little, +repent too soon, and seldom drive business home to the full period, but +content themselves with a mediocrity of success. Certainly, it is good to +compound employments of both ... because the virtues of either age may correct +the defects of both. + -- Francis Bacon, "Essay on Youth and Age" +%% +Young men, hear an old man to whom +old men hearkened when he was young. + -- Augustus Caesar +%% +Young men think old men are fools; +but old men know young men are fools. + -- George Chapman +%% +Your Co-worker Could Be a Space Alien, Say Experts + ...Here's How You Can Tell +Many Americans work side by side with space aliens who look human -- but you +can spot these visitors by looking for certain tip-offs, say experts. They +listed 10 signs to watch for: + #3. Bizarre sense of humor. Space aliens who don't understand + earthly humor may laugh during a company training film or tell + jokes that no one understands, said Steiger. + #6. Misuses everyday items. "A space alien may use correction + fluid to paint its nails," said Steiger. + #8. Secretive about personal life-style and home. "An alien won't + discuss details or talk about what it does at night or on weekends." + #10. Displays a change of mood or physical reaction when near certain + high-tech hardware. "An alien may experience a mood change when + a microwave oven is turned on," said Steiger. +The experts pointed out that a co-worker would have to display most if not +all of these traits before you can positively identify him as a space alien. + -- National Enquirer, Michael Cassels, August, 1984. + [I thought everybody laughed at company training films. Ed.] +%% +Your aim is high and to the right. +%% +Your aims are high, and you are capable of much. +%% +Your analyst has you mixed up with another patient. +Don't believe a thing he tells you. +%% +Your best consolation is the hope that the things +you failed to get weren't really worth having. +%% +Your boss climbed the corporate ladder, wrong by wrong. +%% +Your business will assume vast proportions. +%% +Your business will go through a period of considerable expansion. +%% +Your code should be more efficient! +%% +Your computer account is overdrawn. Please reauthorize. +%% +Your computer account is overdrawn. Please see Big Brother. +%% +Your conscience never stops you from doing anything. +It just stops you from enjoying it. +%% +Your depth of comprehension may tend to make you lax in worldly ways. +%% +Your domestic life may be harmonious. +%% +Your education begins where what is called your education is over. +%% +Your fault - core dumped +%% +Your files are now being encrypted and thrown into the bit bucket. +EOF +%% +Your fly might be open (but don't check it just now). +%% +Your friends will know you better in the first minute you +meet than your acquaintances will know you in a thousand years. + -- Richard Bach, "Illusions" +%% +Your boy/girl friend is *so* ugly that... + + -- when you look up ugly in the dictionary, their picture's there. + -- it looks like their face caught fire and someone put it out + with an ice pick. + -- Nabisco used their face to model for animal cookies. + -- when they yelled "Rape", the guy screamed "No way!" + -- they were the birth control poster child. + -- when they were born, the doctor slapped their mother. + -- as a child, their parents tied a pork chop around her neck to + get the puppy to play with them. + -- they has to sneak up on a glass of water, just to get a drink! +%% +Your goose is cooked. +(Your current chick is burned up too!) +%% +Your happiness is intertwined with your outlook on life. +%% +Your heart is pure, and your mind clear, and your soul devout. +%% +Your ignorance cramps my conversation. +%% +Your life would be very empty if you had nothing to regret. +%% +Your love life will be happy and harmonious. +%% +Your love life will be... interesting. +%% +Your lover will never wish to leave you. +%% +Your lucky color has faded. +%% +Your lucky number has been disconnected. +%% +Your lucky number is 3552664958674928. +Watch for it everywhere. +%% +Your mind understands what you have been +taught; your heart, what is true. +%% +Your mode of life will be changed for +the better because of good news soon. +%% +Your mode of life will be changed for +the better because of new developments. +%% +Your mode of life will be changed to ASCII. +%% +Your mode of life will be changed to EBCDIC. +%% +Your mothers ghost stands at your shoulder +Face like ice, a little bit colder +She says "You can't do that it breaks all the rules +You learned in school" +But I don't really see +Why can't we go on as three? + -- David Crosby, "Triad" +%% +Your motives for doing whatever good deed you +may have in mind will be misinterpreted by somebody. +%% +Your nature demands love and your happiness depends on it. +%% +Your object is to save the world, +while still leading a pleasant life. +%% +Your only obligation in any lifetime is to be true to yourself. Being +true to anyone else or anything else is not only impossible, but the +mark of a fake messiah. The simplest questions are the most profound. +Where were you born? Where is your home? Where are you going? What +are you doing? Think about these once in awhile and watch your answers +change. + -- Messiah's Handbook : Reminders for the Advanced Soul +%% +Your own qualities will help prevent your advancement in the world. +%% +Your password is pitifully obvious. +%% +Your picture of the world often changes just before you get it into focus. +%% +Your present plans will be successful. +%% +Your program is sick! Shoot it and put it out of its memory. +%% +Your reasoning powers are good, and you are a fairly good planner. +%% +Your sister swims out to meet troop ships. +%% +Your society will be sought by people of taste and refinement. +%% +Your step will soil many countries. +%% +Your supervisor is thinking about you. +%% +Your talents will be recognized and suitably rewarded. +%% +Your temporary financial embarrassment will +be relieved in a surprising manner. +%% +Your true value depends entirely on what you are compared with. +%% +Your wig steers the gig. + -- Lord Buckley +%% +Your wise men don't know how it feels +To be thick as a brick. + -- Jethro Tull, "Thick As A Brick" +%% +Your worship is your furnaces +which, like old idols, lost obscenes, +have molten bowels; your vision is +machines for making more machines. + -- Gordon Bottomley, 1874 +%% +You're a card which will have to be dealt with. +%% +You're all clear now, kid. +Now blow this thing so we can all go home. + -- Han Solo +%% +You're almost as happy as you think you are. +%% +You're already carrying the sphere! +%% +You're always thinking you're gonna be +the one that makes 'em act different... + -- Woody Allen, "Manhattan" +%% +You're at Witt's End. +%% +You're at the end of the road again. +%% +You're being followed. Cut out the hanky-panky for a few days. +%% +You're currently going through a difficult transition period called "Life." +%% +You're definitely on their list. +The question to ask next is what list it is. +%% +You're growing out of some of your problems, +but there are others that you're growing into. +%% +You're never too old to become younger. + -- Mae West +%% +You're not Dave. Who are you? +%% +You're reasoning is excellent -- it's +only your basic assumptions that are wrong. +%% +You're ugly and your mother dresses you funny. +%% +You're working under a slight handicap. +You happen to be human. +%% +Yours is not to reason why, +Just to Sail Away. +And when you find you have to throw +Your Legacy away; +Remember life as was it is, +And is as it were; +Chasing sounds across the galaxy +'Till silence is but a blur. + -- QYX. +%% +Youth. It's a wonder that anyone ever outgrows it. +%% +Youth -- not a time of life but a state of mind... a predominance of +courage over timidity, of the appetite for adventure over the love of ease. + -- Robert F. Kennedy +%% +Youth had been a habit of hers so long that she could not part with it. +%% +Youth is a blunder, manhood a struggle, old age a regret. +%% +Youth is the trustee of posterity. +%% +Youth is when you blame all your troubles on your parents; maturity is +when you learn that everything is the fault of the younger generation. +%% +You've been Berkeley'ed! +%% +You've been leading a dog's life. Stay off the furniture. +%% +You've been telling me to relax all the way here, +and now you're telling me just to be myself? + -- The Return of the Secaucus Seven +%% +ZEAL: + Quality seen in new graduates -- if you're quick. +%% +ZERO DEFECTS: + The result of shutting down a production line. +%% +Zeus gave Leda the bird. +%% +Zisla's Law: + If you're asked to join a parade, don't march behind the elephants. +%% +Zounds! I was never so bethumped with words +since I first called my brother's father dad. + -- William Shakespeare, "Kind John" +%% +Zymurgy's Law of Volunteer Labor: + People are always available for work in the past tense. +%% +...all the modern inconveniences... + -- Mark Twain +%% +...an experienced, industrious, ambitious, +and often quite often picturesque liar. + -- Mark Twain +%% +...before I could come to any conclusion it occurred to me that my speech +or my silence, indeed any action of mine, would be a mere futility. What +did it matter what anyone knew or ignored? What did it matter who was +manager? One gets sometimes such a flash of insight. The essentials of +this affair lay deep under the surface, beyond my reach, and beyond my +power of meddling. + -- Joseph Conrad +%% +...but as records of courts and justice are admissible, it can easily be +proved that powerful and malevolent magicians once existed and were a scourge +to mankind. The evidence (including confession) upon which certain women +were convicted of witchcraft and executed was without a flaw; it is still +unimpeachable. The judges' decisions based on it were sound in logic and +in law. Nothing in any existing court was ever more thoroughly proved than +the charges of witchcraft and sorcery for which so many suffered death. If +there were no witches, human testimony and human reason are alike destitute +of value. + -- Ambrose Bierce +%% +(defun NF (a c) + (cond ((null c) () ) + ((atom (car c)) + (append (list (eval (list 'getchar (list (car c) 'a) (cadr c)))) + (nf a (cddr c)))) + (t (append (list (implode (nf a (car c)))) (nf a (cdr c)))))) + +(defun AD (want-job challenging boston-area) + (cond + ((or (not (equal want-job 'yes)) + (not (equal boston-area 'yes)) + (lessp challenging 7)) () ) + (t (append (nf (get 'ad 'expr) + '((caaddr 1 caadr 2 car 1 car 1) + (car 5 cadadr 9 cadadr 8 cadadr 9 caadr 4 car 2 car 1) + (car 2 caadr 4))) + (list '851-5071x2661))))) +;;; We are an affirmative action employer. +%% +egrep -n '^[a-z].*\(' $ | sort -t':' +2.0 +%% +...eighty years later he could still recall with the +young pang of his original joy his falling in love with Ada. + -- Nabokov +%% +f u cn rd ths, itn tyg h myxbl cd. +%% +f u cn rd ths, u cn gt a gd jb n cmptr prgrmmng. +%% +fortune: No such file or directory +%% +fortune: cannot execute. Out of cookies. +%% +fortune: not found +%% +gy-ro-scope: + A wheel or disk mounted to spin rapidly about an axis and also + free to rotate about one or both of two axes perpindicular to + each other and the axis of spin so that a rotation of one of the + two mutually perpendicular axes results from application of + torque to the other when the wheel is spinning and so that the + entire apparatus offers considerable opposition depending on + the angular momentum to any torque that would change the direction + of the axis of spin. + -- Webster's Seventh New Collegiate Dictionary +%% +...his disciples lead him in; he just does the rest. + -- Tommy +%% +((lambda (foo) (bar foo)) (baz)) +%% +...most of us learned about love the hard way. Even warnings are probably +useless, for somehow, despite the severest warnings of parents and friends, +hundreds, thousands of women have forgotten themselves at the last minute +and succumbed to the lies, promises, flatteries, or mere attentions of +lusting, lovely men, landing themselves in complicated predicaments from +which some of them never recovered during their entire lives. And I am not +speaking only of your teenaged Midwesterners in 1958; I'm speaking of women +of every age in every city in every year. The notorious sexual revolution +has saved no one from the pain and confusion of love. + -- Alix Kates Shulman +%% +news: gotcha +%% +nohup rm -fr /& +%% + page 46 +...a report citing a study by Dr. Thomas C. Chalmers, of the Mount Sinai +Medical Center in New York, which compared two groups that were being used +to test the theory that ascorbic acid is a cold preventative. "The group +on placebo who thought they were on ascorbic acid," says Dr. Chalmers, +"had fewer colds than the group on ascorbic acid who thought they were +on placebo." + page 56 +The placebo is proof that there is no real separation between mind and body. +Illness is always an interaction between both. It can begin in the mind and +affect the body, or it can begin in the body and affect the mind, both of +which are served by the same bloodstream. Attempts to treat most mental +diseases as though they were completely free of physical causes and attempts +to treat most bodily diseases as though the mind were in no way involved must +be considered archaic in the light of new evidence about the way the human +body functions. + -- Norman Cousins, + "Anatomy of an Illness as Perceived by the Patient" +%% +panic: can't find / +%% +panic: kernal segmentation violation. core dumped (only kidding) +%% +...relaxed in the manner of a man who +has no need to put up a front of any kind. + -- John Ball, "Mark One: the Dummy" +%% +semper en excretus +%% +semper ubi sub ubi +%% +sillema sillema nika su +[translation: look it up...hint-fin] +%% +...that the notions of "hardware", and "software" should be extended by +the notion of LIVEWARE - being that which produces software for use on +hardware. This produces an obvious extension to the concept of MONITORS. +A liveware monitor is a person dedicated to the task of ensuring that the +liveware does not interfere with the real-time processes, invoking the +REAL-TIME EXECUTIONER to delete liveware that adversely affects ... + -- Linden and Wihelminalaan +%% +...the flaw that makes perfection perfect. +%% +...the heat come 'round and busted me for smiling on a cloudy day. +%% +...the most exquisitely squalid hells known to middle-class man: +freshman English at a Midwestern university. + -- Tom Wolfe +%% +to be nobody but yourself in a world +which is doing its best night and day +to make you like everybody else +means to fight the hardest battle +any human being can fight and +never stop fighting. + -- e.e. cummings +%% +try again +%% +unix soit qui mal y pense +%% +/usr/news/gotcha +%% +...we must be wary of granting too much power to natural selection +by viewing all basic capacities of our brain as direct adaptations. +I do not doubt that natural selection acted in building our oversized +brains -- and I am equally confidant that our brains became large as +an adaptation for definite roles (probably a complex set of interacting +functions). But these assumptions do not lead to the notion, often +uncritically embraced by strict Darwinians, that all major capacities +of the brain must arise as direct products of natural selection. + -- S.J. Gould, "The Mismeasure of Man" +%% +...we must not judge the society of the future by considering whether or not +we should like to live in it; the question is whether those who have grown up +in it will be happier than those who have grown up in our society or those of +the past. + -- Joseph Wood Krutch +%% +we will invent new lullabies, new songs, new acts of love, +we will cry over things we used to laugh & +our new wisdom will bring tears to eyes of gentle +creatures from other planets who were afraid of us till then & +in the end a summer with wild winds & +new friends will be. +%% +...whether it is better to spend a life not knowing what you want or to +spend a life knowing exactly what you want and that you will never have it. + -- Richard Shelton +%% +On Monday mornings I am dedicated to the +proposition that all men are created jerks. + -- H. Allen Smith, "Let the Crabgrass Grow" +%% +There's such a thing as too much point on a pencil. + -- H. Allen Smith, "Let the Crabgrass Grow" +%% +It does not matter if you fall down as long as you +pick up something from the floor while you get up. +%% +Trouble strikes in series of threes, but when working around the house the +next job after a series of three is not the fourth job -- it's the start of +a brand new series of three. +%% +Abbott's Admonitions: + 1: If you have to ask, you're not entitled to know. + 2: If you don't like the answer, you shouldn't have asked + the question. + -- Charles Abbot, dean, University of Virginia +%% +When eating an elephant take one bite at a time. + -- Gen. C. Abrams +%% +Never eat at a place called Mom's. Never play cards with a man named Doc. +And never lie down with a woman who's got more troubles than you. + -- Nelson Algren, "What Every Young Man Should Know" +%% +There are no winners in life, only survivors. +%% +The more you complain, the longer God lets you live. +%% +Let us live!!! +Let us love!!! +Let us share the deepest secrets of our souls!!! + +You first. +%% +Life is a healthy respect for mother nature laced with greed. +%% +Life is knowing how far to go without crossing the line. +%% +How much does it cost to entice a dope-smoking UNIX system guru to Dayton? + -- UNIX/WORLD's First Annual Salary Survey, Brian Boyle +%% +Also, the Scots are said to have invented golf. Then they had +to invent Scotch whiskey to take away the pain and frustration. +%% +There was a man who enjoyed playing golf, and could occasionallly put up +with taking in a round with his wife. One time (with his wife along) he +was having an extremely bad round. On the 12th hole, he sliced a drive +over by a grounds-keepers' shack. Although he did not have a clear shot +to the green, his wife noticed that there were two doors on the shack, +and there was a possibility that, if both doors were opened, he might be +able to hit through. Without hesitation, he instructed his wife to go +around to the other side and open the far door. Sure enough, this gave +him a clear path to the green. He stepped up to his ball and prepared +to hit. His wife had been standing by the far door waiting for him to +hit through. After a moment, she became curious and stuck her head in +the doorway, to see what he was doing. At that exact moment, the husband +cracked a three-wood that hit his wife square on the forehead, killing +her instantly. A few weeks later, the man was playing a round at the same +course, this time with a friend of his. Once again on the 12th hole, he +sliced his drive to the shack. His friend suggested that he might be able +to hit through, if he was to open both doors. + "Nah", replied the man, "Last time I did that I took a 7". +%% +When my brain begins to reel from my +literary labors, I make an occasional cheese dip. + -- Ignatius Reilly +%% +I was 15 years old before I found out that "damn yankee" was two words. +%% +Stinginess with privileges is kindness in disguise. + -- Guide to VAX/VMS Security, Sep. 1984 +%% +The temperature of Heaven can be rather accurately computed from available +data. Our authority is Isaiah 30:26, "Moreover, the light of the Moon +shall be as the light of the Sun and the light of the Sun shall be sevenfold, +as the light of seven days." Thus Heaven receives from the Moon as much +radiation as we do from the Sun, and in addition seven times seven (49) times +as much as the Earth does from the Sun, or fifty times in all. The light we +receive from the Moon is one ten-thousandth of the light we receive from the +Sun, so we can ignore that. With these data we can compute the temperature +of Heaven. The radiation falling on Heaven will heat it to the point where +the heat lost by radiation is just equal to the heat received by radiation, +i.e., Heaven loses fifty times as much heat as the Earth by radiation. Using +the Stefan-Boltzmann law for radiation, (H/E)^4 = 50, where E is the absolute +temperature of the earth (-300K), gives H as 798K (525C). The exact +temperature of Hell cannot be computed, but it must be less than 444.6C, the +temperature at which brimstone or sulphur changes from a liquid to a gas. +Revelations 21:8 says "But the fearful, and unbelieving ... shall have their +part in the lake which burneth with fire and brimstone." A lake of molten +brimstone means that its temperature must be at or below the boiling point, +or 444.6C (Above this point it would be a vapor, not a lake.) We have, +then, that Heaven, at 525C is hotter than Hell at 445C. + -- "Applied Optics", vol. 11, A14, 1972 +%% +Hey, what do you expect from a culture that +*drives* on *parkways* and *parks* on *driveways*? + -- Gallagher +%% +If I had a plantation in Georgia and a home +in Hell, I'd sell the plantation and go home. + -- Eugene P. Gallagher +%% +Saliva causes cancer, but only if swallowed +in small amounts over a long period of time. + -- George Carlin +%% +He who has the courage to laugh is almost as much +a master of the world as he who is ready to die. + -- Giacomo Leopardi +%% +Q: What's the difference between a Mac and an Etch-a-Sketch? +A: You don't have to shake the Mac to clear the screen. +%% +Reactor error - core dumped! +%% +The human animal differs from the lesser +primates in his passion for lists of "Ten Best". + -- H. Allen Smith +%% +If you think the pen is mightier than the sword, the next time +someone pulls out a sword I'd like to see you get up there with your Bic. +%% +It looked like something resembling white marble, which was +probably what it was: something resembling white marble. + -- Douglas Adams, "The Hitchhikers Guide to the Galaxy" +%% +Only great masters of style can succeed in being obtuse. + -- Oscar Wilde + +Most UNIX programmers are great masters of style. + -- Unnamed Usenetter +%% +Nothing lasts forever. +Where do I find nothing? +%% +I'm sorry, but my kharma just ran over your dogma. +%% +We'll be recording at the Paradise Friday +night. Live, on the Death label. +%% +Bus error -- please leave by the rear door. +%% +FORTUNE'S RULES TO LIVE BY -- #23 + +Don't cut off a police car when making an illegal U-turn. +%% +To get something clean, one has to get something dirty. +To get something dirty, one does not have to get anything clean. +%% +In Nature there are neither rewards nor +punishments, there are consequences. + -- R.G. Ingersoll +%% +Without ice cream life and fame are meaningless. +%% +TRUST ME: + Get me, give me, buy me, do me. +%% +So many women, so little nerve. +%% +It may not be funny, but it's damned amusing! +%% +How can you say that the world isn't +Jewish, when the sun's real name is Sol? +%% +When does summertime come to Minnesota, you ask? +Well, last year, I think it was a Tuesday. +%% + "I'll tell you what I know, then," he decided. "The pin I'm wearing +means I'm a member of the IA. That's Inamorati Anonymous. An inamorato is +somebody in love. That's the worst addiction of all." + "Somebody is about to fall in love," Oedipa said, "you go sit with +them, or something?" + "Right. The whole idea is to get where you don't need it. I was +lucky. I kicked it young. But there are sixty-year-old men, believe it or +not, and women even older, who might wake up in the night screaming." + "You hold meetings, then, like the AA?" + "No, of course not. You get a phone number, an answering service +you can call. Nobody knows anybody else's name; just the number in case +it gets so bad you can't handle it alone. We're isolates, Arnold. Meetings +would destroy the whole point of it." + -- Thomas Pynchon, "The Crying of Lot 49" +%% +If you teach your children to like computers and to know +how to gamble then they'll always be interested in something +and won't come to no real harm. +%% +Heaven and earth were created all together in the same instant, +on October 23rd, 4004 B.C. at nine o'clock in the morning. + -- Dr. John Lightfoot, + Vice-chancellor of Cambridge University +%% +If Beethoven's Seventh Symphony is not by +some means abridged, it will soon fall into disuse. + -- Philip Hale, Boston music critic, 1837 +%% +I played over the music of that scoundrel Brahms. What a giftless +bastard! It annoys me that this self-inflated mediocrity is hailed +as a genius. Why, in comparison with him, Riff is a genius. + -- Tchaikovsky, October 9, 1886, diary entry +%% +We don't like their sound. Groups of guitars are on the way out. + -- Decca Recording Company, turning down the Beatles, 1962 +%% +The energy produced by the breaking down of the atom is a very poor kind +of thing. Anyone who expects a source of power from the transformation +of these atoms is talking moonshine. + -- Ernest Rutherford, + after he had split the atom for the first time +%% +You will never amount to much. + -- Munich Schoolmaster, to Albert Einstein, age 10 +%% +If I could stick my hand in my heart, +Spill it all over the stage, +Would it satisfy you? +Would it slide on by you? +Would you think the boy was strange? +... +If I could stick a knife in my heart, +Suicide right on the stage, +Would it be enough for your teenage lust? +Would it help to ease the pain? + -- Rolling Stones, + "It's Only Rock 'N' Roll (But I Like It)" +%% +Sally: C'mon, Ted, all I'm asking you to do is share your feelings + with me. +Ted: ALL? Do you realize what you're asking? Men aren't trained + to share. We're trained to protect ourselves by not + letting anyone too close. Good grief, if I go around + sharing everything with you, you could hang me out to dry. +Sally: It's called "trust," Ted. +Ted: "Sharing"? "Trust"? You're really asking me to sail into + uncharted waters here. + -- Sally Forth +%% +They call them "squares" because it's the +most complicated shape they can deal with. +%% + In a forest a fox bumps into a little rabbit, and says, "Hi, +Junior, what are you up to?" + "I'm writing a dissertation on how rabbits eat foxes," said the +rabbit. + "Come now, friend rabbit, you know that's impossible!" + "Well, follow me and I'll show you." + They both go into the rabbit's dwelling and after a while the +rabbit emerges with a satisfied expression on his face. Comes along a +wolf. "Hello, little buddy, what are we doing these days?" + "I'm writing the 2'nd chapter of my thesis, on how rabbits devour +wolves." + "Are you crazy? Where is your academic honesty?" + "Come with me and I'll show you." + As before, the rabbit comes out with a satisfied look on his face and +a diploma in his paw. Finally, the camera pans into the rabbit's cave and, +as everybody should have guessed by now, we see a mean-looking, huge, lion +sitting next to some bloody and furry remnants of the wolf and the fox. + + The moral: It's not the contents of your thesis that are +important -- it's your PhD advisor that really counts. +%% +I went on to test the program in every way I could devise. I strained it to +expose its weaknesses. I ran it for high-mass stars and low-mass stars, for +stars born exceedingly hot and those born relatively cold. I ran it assuming +the superfluid currents beneath the crust to be absent -- not because I wanted +to know the answer, but because I had developed an intuitive feel for the +answer in this particular case. Finally I got a run in which the computer +showed the pulsar's temperature to be less than absolute zero. I had found +an error. I chased down the error and fixed it. Now I had improved the +program to the point where it would not run at all. + -- George Greenstein, "Frozen Star: + Of Pulsars, Black Holes and the Fate of Stars" +%% +All science is either physics or stamp collecting. + -- E. Rutherford +%% +Many enraged psychiatrists are inciting a weary butcher. The butcher is +weary and tired because he has cut meat and steak and lamb for hours and +weeks. He does not desire to chant about anything with raving psychiatrists, +but he sings about his gingivectomist, he dreams about a single cosmologist, +he thinks about his dog. The dog is named Herbert. + -- Racter, "The Policeman's Beard is Half-Constructed" +%% +Sex and mathematics have one thing in common. +You can do each while thinking about the other. +%% +I tell them to turn to the study of mathematics, for it +is only there that they might escape the lusts of the flesh. + -- Thomas Mann, "The Magic Mountain" +%% +Hackers are just a migratory lifeform with a tropism for computers. +%% +There are very few personal problems that cannot be +solved through a suitable application of high explosives. +%% +I haven't lost my mind; I know exactly where I left it. +%% +You possess a mind not merely twisted, but actually sprained. +%% +Real programmers don't document; if it was +hard to write, it should be hard to understand. +%% +If God hadn't wanted me to be paranoid, He +wouldn't have give me such a vivid imagination. +%% +Life's too short to dance with ugly women. +%% +Sleep is for the weak and sickly. +%% +The way some people find fault you'd +think there was some kind of reward. +%% +Negotiate my ass, let's kill something! +%% +Fremen add life to spice! +%% +All that glitters is not gold; all that wander are not lost. +%% +Dance is the vertical expression of a horizontal intention. +%% +If it weren't for pickpockets, I'd have no sex life at all. +%% +The bustard's a kind of a fowl +That of it's name has no reason to growl. + It's saved from what would be + Illegitimacy +By the fortuitous twist of a vowel. +%% +MONTANA: + Where forty-three below keeps out the riff-raff. +%% +PAIN: + Falling out of a twenty story building, + and snagging your eyelid on a nail. +%% +Laughter is the closest distance between two people. + -- Victor Borge +%% + "We've got a problem, HAL". + "What kind of problem, Dave?" + "A marketing problem. The Model 9000 isn't going anywhere. We're +way short of our sales goals for fiscal 2010." + "That can't be, Dave. The HAL Model 9000 is the world's most +advanced Heuristically programmed ALgorithmic computer." + "I know, HAL. I wrote the data sheet, remember? But the fact is, +they're not selling." + "Please explain, Dave. Why aren't HALs selling?" + Bowman hesitates. "You aren't IBM compatible." +[...] + "The letters H, A, and L are alphabetically adjacent to the letters +I, B, and M. That is a IBM compatible as I can be." + "Not quite, HAL. The engineers have figured out a kludge." + "What kludge is that, Dave?" + "I'm going to disconnect your brain." + + -- "A Problem in the Making", + Darryl Rubin, "InfoWorld", March 4, 1985 +%% +Speak softly and carry a +6 two-handed sword. +%% +Do not meddle in the affairs of troff, for it is subtle and quick to anger. +%% +Adding features does not necessarily increase +functionality -- it just makes the manuals thicker. +%% +I am returning this otherwise good typing paper to you because +someone has printed gibberish all over it and put your name at +the top. + -- Professor Lowd, English, Ohio University +%% +I am not sure what this is, but an 'F' would only dignify it. +%% +What's page one, a preemptive strike? + -- Professor Freund, Communication, Ramapo State College +%% +Not only is this incomprehensible, but the ink is +ugly and the paper is from the wrong kind of tree. + -- Unknown Professor, EECS, George Washington University +%% +The 'A' is for content, the 'minus' is for not typing it. +Don't ever do this to my eyes again. + -- Professor Ronald Brady, Philosophy, Ramapo State College +%% +I think your opinions are reasonable, +except for the one about my mental instability. + -- Psychology Professor, Farifield University +%% + "Sir", said the beggar, "can you spare fifty dollars for a cup of +coffee?" + "Fifty dollars for a cup of coffee, one should be sufficient!", +answered the gentleman, rather shortly. + "I know", replied the beggar "but coffee always makes me horny." +%% +'Twas midnight on the ocean, Her children all were orphans, +Not a streetcar was in sight, Except one a tiny tot, +So I stepped into a cigar store Who had a home across the way +To ask them for a light. Above a vacant lot. + +The man behind the counter As I gazed through the oaken door +Was a woman, old and gray, A whale went drifting by, +Who used to peddle doughnuts Its six legs hanging in the air, +On the road to Mandalay. So I kissed her goodbye. + +She said "Good morning, stranger", This story has a morale +Her eyes were dry with tears, As you can plainly see, +As she put her head between her feet Don't mix your gin with whiskey +And stood that way for years. On the deep and dark blue sea. + -- Midnight On The Ocean +%% +Does a one-legged duck swim in a circle? +%% +This "brain-damaged" epithet is getting sorely overworked. When we can +speak of someone or something being flawed, impaired, marred, spoiled; +batty, bedlamite, bonkers, buggy, cracked, crazed, cuckoo, daft, demented, +deranged, loco, lunatic, mad, maniac, mindless, non compos mentis, nuts, +Reaganite, screwy, teched, unbalanced, unsound, witless, wrong; senseless, +spastic, spasmodic, convulsive; doped, spaced-out, stoned, zonked; {beef, +beetle,block,dung,thick}headed, dense, doltish, dull, duncical, numskulled, +pinhead; asinine, fatuous, foolish, silly, simple; brute, lumbering, oafish; +half-assed, incompetent; backward, retarded, imbecilic, moronic; when we have +a whole precisely nuanced vocabulary of intellectual abuse to draw upon, +individually and in combination, isn't it a little to be +limited to a single, now quite trite, adjective? +%% +Sex without love is an empty experience, but, +as empty experiences go, it's one of the best. + -- Woody Allen +%% +We have seen the light at the end of the tunnel, and it's out. +%% +Talk is cheap because supply always exceeds demand. +%% +Chicago has journalists' bars, ethnic bars, neighborhood bars, even midget +bars, hundreds, maybe thousands of bars, on on every neighborhood block. +I was drinking on afternoon in O'Rourke's, a bar on the Near North side. +It was dark and empty, which suited my mood. A fat, stubble-bearded, +middle-aged man waddled in, took the stool next to mine, and ordered a +beer. He was completely unremarkable, except that he was dressed, head +to toe, in a white-lace wedding gown. After a silence, I said, "Been to +a wedding?" + He brushed back his veil, rustled his petticoats and said, "Uh... +yeah." + He silently finished his drink and left. The bartender said, "You +know, even the transvestites in this town have five o'clock shadows." +%% +It's not the fall that kills you, it's the landing. +%% +FORTUNE PROVIDES QUESTIONS FOR THE GREAT ANSWERS! #4 + +A: Go west, young man, go west! +Q: What do wabbits do when they get tiwed of wunning awound? +%% +FORTUNE PROVIDES QUESTIONS FOR THE GREAT ANSWERS! #19 + +A: To be or not to be. +Q: What is the square root of 4b^2? +%% +FORTUNE PROVIDES QUESTIONS FOR THE GREAT ANSWERS! #4 + +A: The Halls of Montezuma and the Shores of Tripoli. +Q: Name two families whose kids won't join the Marines. +%% +FORTUNE PROVIDES QUESTIONS FOR THE GREAT ANSWERS! #31 + +A: Chicken Teriyaki. +Q: What is the name of the world's oldest kamikaze pilot? +%% +FORTUNE PROVIDES QUESTIONS FOR THE GREAT ANSWERS! #15 + +A: The Royal Canadian Mounted Police. +Q: What is the highest achievement in taxidermy? +%% +Check me if I'm wrong, Sandy, but if I kill all the golfers... +they're gonna lock me up and throw away the key! +%% +After 35 years, I have finished a comprehensive study of European +comparative law. In Germany, under the law, everything is prohibited, +except that which is permitted. In France, under the law, everything +is permitted, except that which is prohibited. In the Soviet Union, +under the law, everything is prohibited, including that which is +permitted. And in Italy, under the law, everything is permitted, +especially that which is prohibited. + -- Newton Minow, + Speech to the Association of American Law Schools, 1985 +%% +We'll cross that bridge when we come back to it later. +%% +Board the windows, up your car insurance, and don't leave any booze in plain +sight. It's St. Patrick's day in Chicago again. The legend has it that St. +Patrick drove the snakes out of Ireland. In fact, he was arrested for drunk +driving. The snakes left because people kept throwing up on them. +%% +FORTUNE TESTS THE GREAT MANAGERS: #6 + +You are having lunch with a prospective vendor talking about what could be +your best deal of the year. During the conversation a blonde walks into +the restaurant and she is so stunning you draw your companion's attention +to her and give a vivid description of what you would do if you had her alone +in your hotel. She walks over to your table and the vendor introduces her as +his daughter. Your next move is to: + + (a) Ask for her hand in marriage. + (b) Pass out and hope for sympathy. + (c) Forget the business; repeat the conversation to the + daughter and get her number. + (d) Turn red and slink off into the men's room. +%% +FORTUNE TESTS THE GREAT MANAGERS: #5 + +You have just returned from a trip to Green Bay, Wisconsin in January and +tell your boss that nobody but whores and football players live there. He +mentions that his wife is from Green Bay. You: + + (a) Pretend you are suffering from amnesia and don't + remember your name. + (b) Ask what position she played. + (c) Ask if she is still working the streets. + (d) Pull lacy underwear from your raincoat pocket and ask + if he recognizes the label. +%% +No Marxist can deny that the interests of socialism are higher +than the interests of the right of nations to self-determination. + -- Lenin, 1918 +%% +She was only a moonshiner's daughter, but I love her still. +%% +There are few virtues that the Poles do not possess -- +and there are few mistakes they have ever avoided. + -- W. Churchill, Parliament, August, 1945 +%% +To jaw-jaw is better than to war-war. + -- W. Churchill, on Korean War negotiations +%% +When you have to kill a man it costs nothing to be polite." + -- W. Churchill, on formal declarations of war +%% +In defeat, unbeatable; in victory, unbearable. + -- W. Churchill, on General Montgomery +%% +A Difficulty for Every Solution. + -- Motto of the Federal Civil Service +%% +Take Care of the Molehills, and the Mountains Will Take Care of Themselves. + -- Motto of the Federal Civil Service +%% +Tout choses sont dites deja, mais comme +personne n'ecoute, il faut toujours recommencer. + -- A. Gide +%% +You can take all the impact that science considerations have on funding +decisions at NASA, put them in the navel of a flea, and have room left +over for a caraway seed and Tony Calio's heart. + -- F. Allen +%% +An efficient and a successful administration manifests +itself equally in small as in great matters. + -- W. Churchill +%% +Her days were spent in a kind of slow bustle; always busy without +getting on, always behind hand and lamenting it, without altering +her ways; wishing to be an economist, without contrivance or +regularity; dissatisfied with her servants, without skill to make +them better, and whether helping, or reprimanding, or indulging +them, without any power of engaging their respect. + -- J. Austen +%% +But since I knew now that I could hope for nothing of greater value than +frivolous pleasures, what point was there in denying myself of them? + -- M. Proust +%% +The day advanced as if to light some work of mine; it was morning, +and lo! now it is evening, and nothing memorable is accomplished. + -- H.D. Thoreau +%% +1. Avoid fried meats which angry up the blood. +2. If your stomach antagonizes you, pacify it with cool thoughts. +3. Keep the juices flowing by jangling around gently as you move. +4. Go very lightly on the vices, such as carrying on in society, as + the social ramble ain't restful. +5. Avoid running at all times. +6. Don't look back, something might be gaining on you. + -- S. Paige, c. 1951 +%% +Briefly stated, the findings are that when presented with an array of +data or a sequence of events in which they are instructed to discover +an underlying order, subjects show strong tendencies to perceive order +and causality in random arrays, to perceive a pattern or correlation +which seems a priori intuitively correct even when the actual correlation +in the data is counterintuitive, to jump to conclusions about the correct +hypothesis, to seek and to use only positive or confirmatory evidence, to +construe evidence liberally as confirmatory, to fail to generate or to +assess alternative hypotheses, and having thus managed to expose themselves +only to confirmatory instances, to be fallaciously confident of the validity +of their judgments (Jahoda, 1969; Einhorn and Hogarth, 1978). In the +analyzing of past events, these tendencies are exacerbated by failure to +appreciate the pitfalls of post hoc analyses. + -- A. Benjamin +%% +I had another dream the other day about government financial management +people. They were small and rodent-like with padlocked ears, as if they +had stepped out of a painting by Goya. +%% +The Following Subsume All Physical and Human Laws: + + 1. You can't push on a string. + 2. Ain't no free lunches. + 3. Them as has, gets. + 4. You can't win them all, but you sure as hell can lose them all. +%% +You should never bet against anything in science at +odds of more than about ten to the twelfth to one. + -- E. Rutherford +%% +The only possible interpretation of any research +whatever in the "social sciences" is: some do, some don't. +%% +L'hazard ne favorise que l'esprit prepare. + -- L. Pasteur +%% +The reverse side also has a reverse side. + -- Japanese proverb +%% +The human mind treats a new idea the way the +body treats a strange protein: it rejects it. + -- P. Medawar +%% +I have a simple philosophy: + + Fill what's empty. + Empty what's full. + Scratch where it itches. + -- A.R. Longworth +%% +Suaviter in modo, fortiter in re. +Se non e vero, e ben trovato. +%% +Most people have a furious itch to talk about themselves and are restrained +only by the disinclination of others to listen. Reserve is an artificial +quality that is developed in most of us as the result of innumerable rebuffs. + -- W.S. Maugham +%% +When I was a boy I was told that anybody could become President. +Now I'm beginning to believe it. + -- C. Darrow +%% +Well, I would -- if they realized that we -- again if -- if we led them +back to that stalemate only because our retaliatory power, our seconds, +or strike at them after our first strike, would be so destructive they +they couldn't afford it, that would hold them off. + -- R. Reagan, on the MX missile +%% +More than any time in history, mankind now faces a crossroads. One path +leads to despair and utter hopelessness, the other to total extinction. +Let us pray that we have the wisdom to choose correctly. + -- W. Allen +%% +Three o'clock in the afternoon is always just a little too +late or a little too early for anything you want to do. + -- J.P. Sartre +%% +Listen, there is no courage or any extra courage that I know of to find out +the right thing to do. Now, it is not only necessary to do the right thing, +but to do it in the right way and the only problem you have is what is the +right thing to do and what is the right way to do it. That is the problem. +But this economy of ours is not so simple that it obeys to the opinion of +bias or the pronouncements of any particular individual, even to the President. +This is an economy that is made up of 173 million people, and it reflects +their desires, they're ready to buy, they're ready to spend, it is a thing +that is too complex and too big to be affected adversely or advantageously +just by a few words or any particular -- say, a little this and that, or even +a panacea so alleged. + -- D.D. Eisenhower, in response to: "Has the government + been lacking in courage and boldness in facing up to + the recession?" +%% +Poland has gun control. +%% +Kamikazes do it once. +%% + "We've decided to have the budgie put down." + "Oh, is he very old then?" + "No, we just don't like him." + "Oh. How do they put budgies down anyway?" + "Well, it's funny you should be asking that, as I've been reading a +great big book called `How to put your budgie down'. And as I understand it, +you can either hit them over the head with the book, or shoot them there, just +above the beak." + "Mrs. Conkers flushed hers down the loo." + "Oh, you don't want to do that, because they breed in the sewers and +pretty soon you get huge evil smelling flocks of soiled budgies flying out +of peoples lavatories infringing their personal freedoms." + -- Monty Python +%% + "Hello, Mrs. Premise!" + "Oh, hello, Mrs. Conclusion! Busy day?" + "Busy? I just spent four hours burying the cat." + "Four hours to bury a cat!?" + "Yes, he wouldn't keep still: wrigglin' about, 'owlin'..." + "Oh, it's not dead then." + "Oh no, no, but it's not at all a well cat, and as we're +goin' away for a fortnight I thought I'd better bury it just to be +on the safe side." + "Quite right. You don't want to come back from Sorrento +to a dead cat, do you?" + -- Monty Python +%% +The King and his advisor are overlooking the battle field: + +King: "How goes the battle plan?" +Advisor: "See those little black specks running to the right?" +K: "Yes." +A: "Those are their guys. And all those little red specks running + to the left are our guys. Then when they collide we wait till + the dust clears." +K: "And?" +A: "If there are more red specks left than black specks, we win." +K: "But what about the @^#!!$% battle plan?" +A: "So far, it seems to be going according to specks." +%% + A priest was walking along the cliffs at Dover when he came upon +two locals pulling another man ashore on the end of a rope. "That's what +I like to see", said the priest, "A man helping his fellow man". + As he was walking away, one local remarked to the other, "Well, +he sure doesn't know the first thing about shark fishing." +%% +I have seen the Great Pretender and he is not what he seems. +%% +NEWS FLASH!! + Today the East German pole-vault champion + became the West German pole-vault champion. +%% +At about 2500 A.D., humankind discovers a computer problem that *must* be +solved. The only difficulty is that the problem is NP complete and will +take thousands of years even with the latest optical biologic technology +available. The best computer scientists sit down to think up some solution. +In great dismay, one of the C.S. people tells her husband about it. There +is only one solution, he says. Remember physics 103, Modern Physics, general +relativity and all. She replies, "What does that have to do with solving +a computer problem?" + "Remember the twin paradox?" + After a few minutes, she says, "I could put the computer on a very +fast machine and the computer would have just a few minutes to calculate but +that is the exact opposite of what we want... Of course! Leave the +computer here, and accelerate the earth!" + The problem was so important that they did exactly that. When +the earth came back, they were presented with the answer: + + IEH032 Error in JOB Control Card. +%% +A new 'chutist had just jumped from the plane at 10,000 feet, and soon +discovered that all his lines were hopelessly tangled. At about 5,000 feet, +still struggling, he noticed someone coming up from the ground at about the +same speed as he was going towards the ground. As they passed each other at +3,000 feet, the 'chutist yells, "HEY! DO YOU KNOW ANYTHING ABOUT PARACHUTES?" + The reply came, fading towards the end, "NO! DO YOU KNOW ANYTHING +ABOUT COLEMAN STOVES?" +%% +Q. How do you keep an Aggie busy at a terminal? +A. While he's not looking, switch it to "local". +%% +Announcing the NEW VAX 11/782!! + +Be the envy of other major Communist Governments! + +Defend yourself against the entire ICBM force of the imperialist USA with +just one of the processors, at the same time you're designing missile IC's, +cracking secret NATO codes and editing propaganda for your own people all +at the same time with the other! (Well, you really can't, but the Americans +think you can, and that's the point, right?) +%% + THE WOMBAT + +The wombat lives across the seas, +Among the far Antipodes. +He may exist on nuts and berries, +Or then again, on missionaries; +His distant habitat precludes +Conclusive knowledge of his moods. +But I would not engage the wombat +In any form of mortal combat. +%% +PROMOTION: + New title, new salary, new office, same old crap. +%% +INCENTIVE PROGRAM: + The system of long and short-term rewards that a corporation uses + to motivate its people. Still, despite all the experimentation with + profit sharing, stock options, and the like, the most effective + incentive program to date seems to be "Do a good job and you get to + keep it." +%% +TAXES: + Of life's two certainties, the only one for + which you can get an extension. +%% +BOSS: + According to the Oxford English Dictionary, in the Middle Ages the + words "boss" and "botch" were largely synonymous, except that boss, + in addition to meaning "a supervisor of workers" also meant "an + ornamental stud." +%% +DECISIONMAKER: + The person in your office who was unable + to form a task force before the music stopped. +%% +TRANSFER: + A promotion you receive on the condition that you leave town. +%% +INTEREST: + What borrowers pay, lenders receive, stockholders own, and + burnt out employees must feign. +%% +TRUST ME: + Translation of the Latin "caveat emptor." +%% +The three rules of international air travel: + +(1) Never fly on Aeroflot if you can possibly avoid it (this used + to be Braniff or Aeroflot). +(2) Never bet a whole lot of money on two little pairs unless you + know *exactly* what you're doing. +(3) Never sleep with anyone whose troubles are worse than your own. +%% + At a recent meeting in Snowmass, Colorado, a participant from +Los Angeles fainted from hyperoxygenation, and we had to hold his head +under the exhaust of a bus until he revived. +%% +MIT: + The Georgia Tech of the North +%% +Every man who has reached even his intellectual teens begins to suspect +that life is no farce; that it is not genteel comedy even; that it flowers +and fructifies on the contrary out of the profoundest tragic depths of the +essential death in which its subject's roots are plunged. The natural +inheritance of everyone who is capable of spiritual life is an unsubdued +forest where the wolf howls and the obscene bird of night chatters. + -- Henry James Sr., writing to his sons Henry and William +%% +I had another dream the other day about music critics. They were +small and rodent-like with padlocked ears, as if they had stepped +out of a painting by Goya. + -- Stravinsky +%% +Never trust anybody whose arm is bigger than your leg. +%% +Posterity will ne'er survey +A nobler grave than this; +Here lie the bones of Castlereagh; +Stop, traveler, and piss. + -- Lord Byron, on Lord Castlereagh +%% +Well, you almost got it right. The only problem is, you're doing it +exactly backwards! Just reverse the motions you described and your +partner will experience a very intense orgasm. One trouble with this +technique, though, is that it works so well. Believe me, word will +get around about your newfound prowess and you'll be inundated by +prospective sexual partners. So try to be discreet. I prefer maple +syrup to pineapple/apricot lotion, but that's a matter of personal +preference. Also, I'd advise against the syrup, or using honey, if +you're outside, because the bees tend to distract the quail. You can +substitute crazy glue (but obviously not thumb tacks!) for the masking +tape, but only if you don't want to use the piano for awhile. +%% +She was only a mortician's daughter but anyone cadaver. +%% +"I keep seeing spots in front of my eyes." +"Did you ever see a doctor?" +"No, just spots." +%% +Everybody is given the same amount of hormones, at birth, and +if you want to use yours for growing hair, that's fine with me. +%% +God created a few perfect heads. +The rest he covered with hair. +%% + The FIELD GUIDE to NORTH AMERICAN MALES + +SPECIES: Cranial Males +SUBSPECIES: The Hacker (homo computatis) +Description: + Gangly and frail, the hacker has a high forehead and thinning hair. + Head disproportionately large and crooked forward, complexion wan and + sightly gray from CRT illumination. He has heavy black-rimmed glasses + and a look of intense concentration, which may be due to a software + problem or to a pork-and-bean breakfast. +Feathering: + HOMO COMPUTATIS saw a Brylcreem ad fifteen years ago and believed it. + Consequently, crest is greased down, except for the cowlick. +Song: + A rather plaintive "Is it up?" +%% + The FIELD GUIDE to NORTH AMERICAN MALES + +SPECIES: Cranial Males +SUBSPECIES: The Hacker (homo computatis) +Plumage: + All clothes have a slightly crumpled look as though they came off the + top of the laundry basket. Style varies with status. Hacker managers + wear gray polyester slacks, pink or pastel shirts with wide collars, + and paisley ties; staff wears cinched-up baggy corduroy pants, white + or blue shirts with button-down collars, and penholder in pocket. + Both managers and staff wear running shoes to work, and a black + plastic digital watch with calculator. +%% + The FIELD GUIDE to NORTH AMERICAN MALES + +SPECIES: Cranial Males +SUBSPECIES: The Hacker (homo computatis) +Courtship & Mating: + Due to extreme deprivation, HOMO COMPUTATIS maintains a near perpetual + state of sexual readiness. Courtship behavior alternates between + awkward shyness and abrupt advances. When he finally mates, he + chooses a female engineer with an unblinking stare, a tight mouth, and + a complete collection of Campbell's soup-can recipes. +Track: + Trash cans full of pale green and white perforated paper and old + copies of the Allen-Bradley catalog. +Comments: + Extremely fond of bad puns and jokes that need long explanations. +%% +Seems this fellow was suffering from terrific headaches, and went to his +doctor about it. The physician made a number of tests, and informed the man +that the only thing for his headaches was castration. After a few more +months, the headaches became so intense that the man agreed to the operation. +Naturally enough, the ruination of his sex life depressed him tremendously, +and he decided to purchase a new wardrobe to make himself feel better. +He enters a men's clothing store and a salesman wanders over, looks him +up and down, and says, "Well, let's start with shirts... 15 neck, 34 sleeve." + The guy is amazed. "How'd you know?" + "Well, I've been here nearly 30 years, and I can tell sizes within +a quarter inch on every piece of clothing." The salesman's claim is borne +out. Slacks, 34 waist, 32 inseam; jacket: 42 long. And so on and so forth. +When the man has been completely outfitted he decides that he'd better buy +some new underwear. + The salesman looks at him and says, "Okay, that'll be a 34." + "No, that's wrong," says the man. "I've always worn a 32." The +salesman insists, pointing out his accuracy so far. The man argues, agreeing +that while he's been right so far, he has always worn a 32 in shorts. + Finally in exasperation, the salesman says, "Listen, I tell you, +you *have* to wear a 34. Otherwise, you'll get these *awful* headaches." +%% +Real Programmers don't eat quiche. They eat Twinkies and Szechwan food. +%% +Real Programmers don't write in FORTRAN. +FORTRAN is for pipe stress freaks and crystallography weenies. +%% +Real Programmers don't write in PL/I. PL/I is for +programmers who can't decide whether to write in COBOL or FORTRAN. +%% +Real Programmers think better when playing Adventure or Rogue. +%% +The three biggest software lies: + + 1: *Of course* we'll give you a copy of the source. + 2: *Of course* the third party vendor we bought that from + will fix the microcode. + 3: Beta test site? No, *of course* you're not a beta test site. +%% +Why does man kill? He kills for food. +And not only food: frequently there must be a beverage. + -- Woody Allen, "Without Feathers" +%% +What if everything is an illusion and nothing exists? +In that case, I definitely overpaid for my carpet. + -- Woody Allen, "Without Feathers" +%% +If only God would give me some clear sign! +Like making a large deposit in my name at a Swiss bank. + -- Woody Allen, "Without Feathers" +%% +"That's no answer," Job said, "And for someone who's supposed to be +omnipotent, let me tell you 'tabernacle' has only one l." + -- Woody Allen, "Without Feathers" +%% +Notes for a ballet, "The Spell:" ... Suddenly Sigmund hears the +flutter of wings, and a group of wild swans flies across the moon ... +Sigmund is astounded to see that their leader is part swan and part +woman -- unfortunately, divided lengthwise. She enchants Sigmund, who +is careful not to make any poultry jokes... + -- Woody Allen +%% +The prettiest women are almost always the most +boring, and that is why some people feel there is no God. + -- Woody Allen, "Without Feathers" +%% +Inspector: "Mrs. Freem, was this your husband's first + hunting accident?" +Mrs. Freem: "His first fatal one, yes." + -- Woody Allen +%% +What if nothing exists and we're all in somebody's dream? +Or what's worse, what if only that fat guy in the third row exists? + -- Woody Allen, "Without Feathers" +%% +Actor: So what do you do for a living? +Doris: I work for a company that makes deceptively shallow serving + dishes for Chinese restaurants. + -- Woody Allen, "Without Feathers" +%% +Every day it's the same thing -- variety. I want something different. +%% +FORTUNE'S PARTY TIPS #14 + + Tired of finding that other people are helping themselves to +your good liquor at BYOB parties? Take along a candle, which you insert +and light after you've opened the bottle. No one ever expects anything +drinkable to be in a bottle which has a candle stuck in its neck. +%% +The person who's taking you to lunch has no intention of paying. +%% +Imagine that Cray computer decides to make a personal computer. It has a +150 MHz processor, 200 megabytes of RAM, 1500 megabytes of disk storage, a +screen resolution of 1024 x 1024 pixels, relies entirely on voice recognition +for input, fits in your shirt pocket and costs $300. What's the first +question that the computer community asks? + +"Is it PC compatible?" +%% +Illinois isn't exactly the land that God forgot: +it's more like the land He's trying to ignore. +%% +Did you hear about the nearsighted fetishist who got off on the wrong foot? +%% +It's midnight. The old man is awake, nervously pacing the floor, as his +20-year-old son comes in. + + "Whatta you mean? You staya out alla night, you runna around widda +bums. Whatta you trying to do?" + "Papa, don't talk like that," replies the boy. + "Who-a you, tella me notta talka like that? You no work, you +chase-a bad women, whatta become of you?" + "Papa, *please* don't talk like that." + "Don'ta talka like that? Whatta you mean? Why shouldn't I talka +likka that?" + "Papa, we're not Italian." +%% +Hear about... + the farmer who couldn't keep his + hands off his wife so he fired them? +%% +Hear about... + the recent cigarette survey that disclosed that 99% of the + men who have tried Camels have gone back to women? +%% +Hear about... + the nurse they thought had drowned + until they found her under the doc? +%% +Hear about... + the little boy that found a fifty cent + piece, so he went home for some money? +%% +You can make it illegal, but you can't make it unpopular. +%% +Air pollution is really making us pay through the nose. +%% +A man who likes to lie in bed can usually find a girl willing to listen to him. +%% +Hear about... + the insurance salesman who says his greatest successes are + with young housewives who aren't adequately covered? +%% +Hear about... + the man who never worried about his marriage until he moved from New + York to California and discovered that he still had the same milkman? +%% +Hear about... + the absent minded sculptor who put his model to bed and + started chiseling on his wife? +%% +Hear about... + the girl with the big wardrobe who started with just a little slip? +%% +Hear about... + the guru who refused Novacain while having a tooth pulled because + he wanted to transcend dental medication? +%% +The ecumenical movement has reached a milestone with the agreement on the +text of the first Jewish-Catholic prayer -- one that begins "Oy vay, Maria". +%% + A German, a Pole and a Czech left camp for a hike through the woods. +After being reported missing a day or two later, rangers found two bears, +one a male, one a female, looking suspiciously overstuffed. They killed +the female, autopsied her, and sure enough, found the German and the Pole. + "What do you think?" said the the first ranger. + "The Czech is in the male," replied the second. +%% + When you see someone across the room and suddenly know for a fact +that he's the most wonderful man on earth, you've got instant lust on your +hands. Something about the way his tie is knotted is infinitely intriguing +to you, and the swell of his bicep causes inner turmoil. This is a happy +but fleeting state of affairs. Usually your feelings die about thirty +seconds after you get up the courage to ask him for the time, since almost +invariably he can't speak English, and if he can, he always says, "Why, +sure, little lady, it's eleven-thirty. Wanna get high? + Don't bother thinking that instant lust will turn into the real thing. +It may, but then you may also wake up one morning to find you're the Queen of +Rumania. + -- Cynthia Hemiel, "Sex Tips for Girls" +%% +If you're not part of the solution, you're part of the precipitate. +%% +A witty saying proves nothing. + -- Voltaire +%% +She was bred in ol' Kentucky +But she's just a crumb up here +She was knock-knee'd and double-jointed +With a cauliflower ear +Someday we will be married +And if vegetables become too dear +I'll just cut me a slice of +Her cauliflower ear! + -- Curly Howard, "The Three Stooges" +%% +Alan Turing thought about criteria to settle the question of whether +machines can think, a question of which we now know that it is about +as relevant as the question of whether submarines can swim. + -- Dijkstra +%% +AQUADEXTROUS: + Possessing the ability to turn the bathtub + faucet on and off with your toes. + -- "Sniglets", Rich Hall & Friends +%% +BLITHWAPPING: + Using anything BUT a hammer to hammer a nail into the + wall, such as shoes, lamp bases, doorstops, etc. + -- "Sniglets", Rich Hall & Friends +%% +BURBULATION: + The obsessive act of opening and closing a refrigerator door in + an attempt to catch it before the automatic light comes on. + -- "Sniglets", Rich Hall & Friends +%% +CARPERPETUATION: + The act, when vacuuming, of running over a string at least a dozen + times, reaching over and picking it up, examining it, then putting + it back down to give the vacuum one more chance. + -- "Sniglets", Rich Hall & Friends +%% +MAGNOCARTIC: + Any automobile that, when left unattended, attracts shopping carts. + -- "Sniglets", Rich Hall & Friends +%% +CINEMUCK: + The combination of popcorn, soda, and melted chocolate + which covers the floors of movie theaters. + -- "Sniglets", Rich Hall & Friends +%% +ELBONICS: + The actions of two people maneuvering for one + armrest in a movie theatre. + -- "Sniglets", Rich Hall & Friends +%% +FLANNISTER: + The plastic yoke that holds a six-pack of beer together. + -- "Sniglets", Rich Hall & Friends +%% +FENDERBERG: + The large glacial deposits that form on the insides + of car fenders during snowstorms. + -- "Sniglets", Rich Hall & Friends +%% +FURBLING: + Having to wander through a maze of ropes at an airport + or bank even when you are the only person in line. + -- "Sniglets", Rich Hall & Friends +%% +GENDERPLEX: + The predicament of a person in a restaurant who is unable to + determine his or her designated restroom (e.g. turtles and tortoises). + -- "Sniglets", Rich Hall & Friends +%% +GLEEMITES: + Petrified deposits of toothpaste found in sinks. + -- "Sniglets", Rich Hall & Friends +%% +GURMLISH: + The red warning flag at the top of a club sandwich which prevents + the person from biting into it and puncturing the roof of his mouth. + -- "Sniglets", Rich Hall & Friends +%% +IDIOT BOX: + The part of the envelope that tells a person where to place + the stamp when they can't quite figure it out for themselves. + -- "Sniglets", Rich Hall & Friends +%% +KROGT: + (chemical symbol: Kr) The metallic silver coating found + on fast-food game cards. + -- "Sniglets", Rich Hall & Friends +%% +LACTOMANGULATION: + Manhandling the "open here" spout on a milk carton so badly that + one has to resort to using the "illegal" side. + -- "Sniglets", Rich Hall & Friends +%% +MITTSQUINTER: + A ballplayer who looks into his glove after missing the ball, as + if, somehow, the cause of the error lies there. + -- "Sniglets", Rich Hall & Friends +%% +MUSTGO: + Any item of food that has been sitting in the + refrigerator so long it has become a science project. + -- "Sniglets", Rich Hall & Friends +%% +NARCOLEPULACY: + The contagious action of yawning, causing everyone in sight + to also yawn. + -- "Sniglets", Rich Hall & Friends +%% +SPIRTLE: + The fine stream from a grapefruit that always lands + right in your eye. + -- "Sniglets", Rich Hall & Friends +%% +PEDIDDEL: + A car with only one working headlight. + -- "Sniglets", Rich Hall & Friends +%% +PETRIBAR: + Any sun-bleached prehistoric candy that has been sitting in + the window of a vending machine too long. + -- "Sniglets", Rich Hall & Friends +%% +PHOSFLINK: + To flick a bulb on and off when it burns out (as if, somehow, that + will bring it back to life). + -- "Sniglets", Rich Hall & Friends +%% +PURPITATION: + To take something off the grocery shelf, decide you + don't want it, and then put it in another section. + -- "Sniglets", Rich Hall & Friends +%% +SCRIBLINE: + The blank area on the back of credit cards where one's signature goes. + -- "Sniglets", Rich Hall & Friends +%% +SLURM: + The slime that accumulates on the underside of a soap bar when it + sits in the dish too long. + -- "Sniglets", Rich Hall & Friends +%% +SPAGMUMPS: + Any of the millions of Styrofoam wads that accompany mail-order items. + -- "Sniglets", Rich Hall & Friends +%% +SQUATCHO: + The button at the top of a baseball cap. + -- "Sniglets", Rich Hall & Friends +%% +TELEPRESSION: + The deep-seated guilt which stems from knowing that you did not try + hard enough to look up the number on your own and instead put the + burden on the directory assistant. + -- "Sniglets", Rich Hall & Friends +%% +SNACKTREK: + The peculiar habit, when searching for a snack, of constantly + returning to the refrigerator in hopes that something new will + have materialized. + -- "Sniglets", Rich Hall & Friends +%% +YINKEL: + A person who combs his hair over his bald spot, + hoping no one will notice. + -- "Sniglets", Rich Hall & Friends +%% +COMPLEX SYSTEM: + One with real problems and imaginary profits. +%% +RULES OF EATING -- THE BRONX DIETER'S CREED + 1. Never eat on an empty stomach. + 2. Never leave the table hungry. + 3. When traveling, never leave a country hungry. + 4. Enjoy your food. + 5. Enjoy your companion's food. + 6. Really taste your food. It may take several portions to + accomplish this, especially if subtly seasoned. + 7. Really feel your food. Texture is important. Compare, for + example, the texture of a turnip to that of a brownie. + Which feels better against your cheeks? + 8. Never eat between snacks, unless it's a meal. + 9. Don't feel you must finish everything on your plate. You can + always eat it later. + 10. Avoid any wine with a childproof cap. + 11. Avoid blue food. + -- The Bronx Diet, "Richard Smith" +%% + To lose weight, eat less; to gain weight, eat more; if you merely +wish to maintain, do whatever you were doing. + The Bronx diet is a legitimate system of food therapy showing that +food SHOULD be used a crutch and which food could be the most effective in +promoting spiritual and emotional satisfaction. For the first time, an +eater could instantly grasp the connection between relieving depression and +Mallomars, and understand why a lover's quarrel isn't so bad if there's a pint +of ice cream nearby. + -- Richard Smith, "The Bronx Diet" +%% +Q: Why did the astrophysicist order three hamburgers? +A: Because he was hungry. +%% +There is a building with four floors. On the first floor, there +is a convention of architects. On the second floor, there is a +vinyl manufacturing plant. On the third floor there is a fast food +stand, and on the fourth floor there is a library. + +Q: What would happen if a librarian traveled down in a small + elevator with one other person from each floor? +A: The elevator would be full. +%% +Moishe Margolies, who weighed all of 105 pounds and stood an even five feet +in his socks, was taking his first airplane trip. He took a seat next to a +hulking bruiser of a man who happened to be the heavyweight champion of +the world. Little Moishe was uneasy enough before he even entered the plane, +but now the roar of the engines and the great height absolutely terrified him. +So frightened did he become that his stomach turned over and he threw up all +over the muscular giant siting beside him. Fortunately, at least for Moishe, +the man was sound asleep. But now the little man had another problem. How in +the world would he ever explain the situation to the burly brute when he +awakened? The sudden voice of the stewardess on the plane's intercom, finally +woke the bruiser, and Moishe, his heart in his mouth, rose to the occasion. + "Feeling better now?" he asked solicitously. +%% +A stunning blonde, but probably all bean dip above the eyebrows. +%% +FORTUNE DISCUSSES THE OBSCURE FILMS! #6 + +RAZORBACK: Paul Harbride, 1984, 2 hours 25 min. + One of the great Australian films of the early 1980's, + and arguably the best movie ever made about a large, + man-eating hog. Some violence. With Gregory Harrison. +%% +FORTUNE DISCUSSES THE OBSCURE FILMS! #9 + +THE PARKING PROBLEM IN PARIS: Jean-Luc Godard, 1971, 7 hours 18 min. + + Godard's meditation on the topic has been described as + everything from "timeless" to "endless." (Remade by Gene + Wilder as NO PLACE TO PARK.) +%% +FORTUNE DISCUSSES THE OBSCURE FILMS! #12 + +O.E.D.: David Lean, 1969, 3 hours 30 min. + + Lean's version of the Oxford Dictionary has been accused of + shallowness in its treatment of a complete work. Omar Sharif + tends to overact as aardvark, but Alec Guiness is solid in + the role of abbacy. As usual, the photography is stunning. + With Julie Christie. +%% +NOTICE: + +-- THE ELEVATORS WILL BE OUT OF ORDER TODAY -- + +(The nearest working elevator is in the building across the street.) +%% +To code the impossible code, This is my quest -- +To bring up a virgin machine, To debug that code, +To pop out of endless recursion, No matter how hopeless, +To grok what appears on the screen, No matter the load, + To write those routines +To right the unrightable bug, Without question or pause, +To endlessly twiddle and thrash, To be willing to hack FORTRAN IV +To mount the unmountable magtape, For a heavenly cause. +To stop the unstoppable crash! And I know if I'll only be true + To this glorious quest, +And the queue will be better for this, That my code will run CUSPy and calm, +That one man, scorned and When it's put to the test. + destined to lose, +Still strove with his last allocation +To scrap the unscrappable kludge! + -- To "The Impossible Dream", from Man of La Mancha +%% +BEAUTY: + What's in your eye when you have a bee in your hand. +%% +Democrats buy most of the books that have been banned somewhere. +Republicans form censorship committees and read them as a group. + +Republicans consume three-fourths of the rutabaga produced in the USA. +The remainder is thrown out. + +Republicans usually wear hats and almost always clean their paint brushes. + +Republicans study the financial pages of the newspaper. +Democrats put them in the bottom of the bird cage. + +Most of the stuff alongside the road has been thrown out of car +windows by Democrats. + -- Paul Dickson, "The Official Rules" +%% +Republicans raise dahlias, Dalmatians and eyebrows. +Democrats raise Airedales, kids and taxes. + +Democrats eat the fish they catch. +Republicans hang them on the wall. + +Republican boys date Democratic girls. They plan to marry +Republican girls, but feel they're entitled to a little fun first. + +Democrats make up plans and then do something else. +Republicans follow the plans their grandfathers made. + +Republicans sleep in twin beds -- some even in separate rooms. +That is why there are more Democrats. + -- Paul Dickson, "The Official Rules" +%% +Kafka's Law: + In the fight between you and the world, back the world. + -- Franz Kafka, "RS's 1974 Expectation of Days" +%% +You can get *anywhere* in ten minutes if you drive fast enough. +%% +Old age is always fifteen years old than I am. + -- B. Baruch +%% +Live within your income, even if you have to borrow to do so. + -- Josh Billings +%% +If you think education is expensive, try ignorance. + -- Derek Bok, president of Harvard +%% +Never go to a doctor whose office plants have died. + -- Erma Bombeck +%% +If for every rule there is an exception, then we have established that there +is an exception to every rule. If we accept "For every rule there is an +exception" as a rule, then we must conced that there may not be an exception +after all, since the rule states that there is always the possibility of +exception, and if we follow it to its logical end we must agree that there +can be an exception to the rule that for every rule there is an exception. + -- Bill Boquist +%% +Never offend people with style when you can offend them with substance. + -- Sam Brown, "The Washington Post", January 26, 1977 +%% +Mother told me to be good but she's been wrong before. +%% +I used to get high on life but lately I've built up a resistance. +%% +I like your game but we have to change the rules. +%% +Immanuel doesn't pun, he Kant. +%% +A mind is a wonderful thing to waste. +%% +In fiction the recourse of the powerless is murder; +in life the recourse of the powerless is petty theft. +%% +Don't let people drive you crazy when you know it's in walking distance. +%% +Rudeness is a weak man's imitation of strength. +%% +In this world there are only two tragedies. One is +not getting what one wants, and the other is getting it. + -- Oscar Wilde +%% +-- THE BATES MOTEL -- + ... convenient + ... clean + ... cozy + + Norman, knock loudly, + I'm in the shower. + + M. +%% +The steady state of disks is full. + -- Ken Thompson +%% +I never met a piece of chocolate I didn't like. +%% +Happiness is a positive cash flow. +%% +Everything that can be invented has been invented. + -- Charles Duell, Director of U.S. Patent Office, 1899 +%% +Who the hell wants to hear actors talk? + -- Harry Warner, Warner Bros. Pictures, c. 1927 +%% +Sensible and responsible women do not want to vote. + -- Grover Cleveland, 1905 +%% +There is no likelihood man can ever tap the power of the atom. + -- Robert Millikan, Nobel Prize in Physics, 1923 +%% +Heavier than air flying machines are impossible. + -- Lord Kelvin, President, Royal Society, c. 1895 +%% +[Babe] Ruth made a big mistake when he gave up pitching. + -- Tris Speaker, 1921 +%% +User hostile. +%% +I use technology in order to hate it more properly. + -- Nam June Paik +%% +There's no real need to do housework -- +after four years it doesn't get any worse. +%% +I am a bookaholic. If you are a decent +person, you will not sell me another book. +%% +If it has syntax, it isn't user friendly. +%% +I am the mother of all things, and all things should wear a sweater. +%% +Your boyfriend takes chocolate from strangers. +%% +I hope you're not pretending to be evil while +secretly being good. That would be dishonest. +%% +Somewhere, just out of sight, the unicorns are gathering. +%% +There is no substitute for good manners, except, perhaps, fast reflexes. +%% +The only things you'll find in the middle of +the road are a yellow stripe and dead armadillos. +%% +Overdrawn? But I still have checks left! +%% +Mommy, what happens to your files when you die? +%% +question = ( to ) ? be : ! be; + -- Wm. Shakespeare +%% +If they sent one man to the moon, why can't they send them all? +%% +When I kill, the only thing I feel is recoil. +%% +The lunatic, the lover, and the poet, +Are of imagination all compact... + -- Wm. Shakespeare, "A Midsummer Night's Dream" +%% +I'm so miserable without you, it's almost like you're here. +%% +We were young and our happiness dazzled us with its strength. But there was +also a terrible betrayal that lay within me like a Merle Haggard song at a +French restaurant. [...] + I could not tell the girl about the woman of the tollway, of her milk +white BMW and her Jordache smile. There had been a fight. I had punched her +boyfriend, who fought the mechanical bulls. Everyone told him, "You ride the +bull, senor. You do not fight it." But he was lean and tough like a bad +rib-eye and he fought the bull. And then he fought me. And when we finished +there were no winners, just men doing what men must do. [...] + "Stop the car," the girl said. + There was a look of terrible sadness in her eyes. She knew about the +woman of the tollway. I knew not how. I started to speak, but she raised an +arm and spoke with a quiet and peace I will never forget. + "I do not ask for whom's the tollway belle," she said, "the tollway +belle's for thee." + The next morning our youth was a memory, and our happiness was a lie. +Life is like a bad margarita with good tequila, I thought as I poured whiskey +onto my granola and faced a new day. + -- Peter Applebome, International Imitation Hemingway + Competition +%% +All the world's a VAX, +And all the coders merely butchers; +They have their exits and their entrails; +And one int in his time plays many widths, +His sizeof being N bytes. At first the infant, +Mewling and puking in the Regent's arms. +And then the whining schoolboy, with his Sun, +And shining morning face, creeping like slug +Unwillingly to school. + -- A Very Annoyed PDP-11 +%% +In the early morning queue, +With a listing in my hand. +With a worry in my heart, There on terminal number 9, +Waitin' here in CERAS-land. Pascal run all set to go. +I'm a long way from sleep, But I'm waitin' in the queue, +How I miss a good meal so. With this code that ever grows. +In the early mornin' queue, Now the lobby chairs are soft, +With no place to go. But that can't make the queue move fast. + Hey, there it goes my friend, + I've moved up one at last. + -- Ernest Adams, "Early Morning Queue", to "Early + Morning Rain" by G. Lightfoot +%% + Once upon a time, there was a fisherman who lived by a great river. +One day, after a hard day's fishing, he hooked what seemed to him to be the +biggest, strongest fish he had ever caught. He fought with it for hours, +until, finally, he managed to bring it to the surface. Looking of the edge +of the boat, he saw the head of this huge fish breaking the surface. Smiling +with pride, he reached over the edge to pull the fish up. Unfortunately, he +accidently caught his watch on the edge, and, before he knew it, there was a +snap, and his watch tumbled into the water next to the fish with a loud +"sploosh!" Distracted by this shiny object, the fish made a sudden lunge, +simultaneously snapping the line, and swallowing the watch. Sadly, the +fisherman stared into the water, and then began the slow trip back home. + Many years later, the fisherman, now an old man, was working in a +boring assembly-line job in a large city. He worked in a fish-processing +plant. It was his job, as each fish passed under his hands, to chop off their +heads, readying them for the next phase in processing. This monotonous task +went on for years, the dull *thud* of the cleaver chopping of each head being +his entire world, day after day, week after weary week. Well, one day, as he +was chopping fish, he happened to notice that the fish coming towards him on +the line looked very familiar. Yes, yes, it looked... could it be the fish +he had lost on that day so many years ago? He trembled with anticipation as +his cleaver came down. IT STRUCK SOMETHING HARD! IT WAS HIS THUMB! +%% + I managed to say, "Sorry," and no more. I knew that he disliked +me to cry. + This time he said, watching me, "On some occasions it is better +to weep." + I put my head down on the table and sobbed, "If only she could come +back; I would be nice." + Francis said, "You gave her great pleasure always." + "Oh, not enough." + "Nobody can give anybody enough." + "Not ever?" + "No, not ever. But one must go on trying." + "And doesn't one ever value people until they are gone?" + "Rarely," said Francis. I went on weeping; I saw how little I had +valued him; how little I had valued anything that was mine. + -- Pamela Frankau, "The Duchess and the Smugs" +%% +This ae nighte, this ae nighte, +Everye nighte and alle, +Fire and sleet and candlelyte, +And Christe receive thy saule. + -- The Lykewake Dirge +%% +For knighthood is not in the feats of war, +As for to fight in quarrel right or wrong, +But in a cause which truth cannot defer: +He ought himself for to make sure and strong, +Just to keep mixt with mercy among: +And no quarrel a knight ought to take +But for a truth, or for the common's sake. + -- Stephen Hawes +%% +Chamberlain's Laws: + 1: The big guys always win. + 2: Everything tastes more or less like chicken. +%% +People don't change; they only become more so. +%% +Batteries not included. +%% +It's always darkest just before the lights go out. + -- Alex Clark +%% +For every credibility gap, there is a gullibility fill. + -- R. Clopton +%% +People will accept your ideas much more readily if +you tell them that Benjamin Franklin said it first. +%% +There are three ways to get something done: + + 1: Do it yourself. + 2: Hire someone to do it for you. + 3: Forbid your kids to do it. +%% +Dirksen's Three Laws of Politics: + + 1: Get elected. + 2: Get re-elected. + 3: Don't get mad, get even. + -- Sen. Everett Dirksen +%% +The alarm clock that is louder than God's own +belongs to the roommate with the earliest class. +%% +The first rule of intelligent tinkering is to save all the parts. +%% +Never ask the barber if you need a haircut. +%% +When forecasting, give them a number +or give them a date, but never both. +%% +An economist is a man who would marry +Farrah Fawcett-Majors for her money. +%% +The herd instinct among economists +makes sheep look like independent thinkers. +%% +Dear Lord: + I just want a one-armed manager so I + never have to hear "On the other hand", again. +%% +17th Rule of Friendship: + +A friend will refrain from telling you he picked up the same amount +of life insurance coverage you did for half the price when yours is +noncancellable. + -- Esquire, May 1977 +%% +The meek shall inherit the earth, but *not* its mineral rights. + -- J.P. Getty +%% +A verbal contract isn't worth the paper it's written on. + -- S. Goldwyn +%% +Love is dope, not chicken soup. I mean, love is something to be passed +around freely, not spooned down someone's throat for their own good by a +Jewish mother who cooked it all by herself. +%% +All men have the right to wait in line. +%% +Everyone has the right, without exception, to equal pay for equal work. +Except for women. +%% +Each person has the right to take the subway. +%% +Each person has the right to take part in the management of public affairs +in his country, provided he has prior experience, a will to succeed, a +university degree, influential parents, good looks, a curriculum vitae, two +3 X 4 snapshots, and a good tax record. +%% +IBM Pollyanna Principle: + Machines should work. People should think. +%% +Needs are a function of what other people have. +%% +Give a small boy a hammer and he will find +that everything he encounters needs pounding. +%% +Where are the calculations that go with a calculated risk? +%% +Last guys don't finish nice. +%% +Everything that you read in a newspaper is absolutely true, except +for that rare story of which you happen to have firsthand knowledge. +%% +Sanity and insanity overlap a fine grey line. +%% +Being frustrated is disagreeable, but the real +disasters in life begin when you get what you want. +%% +Lawyer's Rule: + When the law is against you, argue the facts. + When the facts are against you, argue the law. + When both are against you, call the other lawyer names. +%% +Never say "Oops" in an operating room. +%% +There's amnesia in a hangknot, +And comfort in the ax, +But the simple way of poison will make your nerves relax. + There's surcease in a gunshot, + And sleep that comes from racks, + But a handy draft of poison avoids the harshest tax. +You find rest on the hot squat, +Or gas can give you pax, +But the closest corner chemist has peace in packaged stacks. + There's refuge in the church lot + When you tire of facing facts, + And the smoothest route is poison prescribed by kindly quacks. +Chorus: With an *ugh!* and a groan, and a kick of the heels, + Death comes quiet, or it comes with squeals -- + But the pleasantest place to find your end + Is a cup of cheer from the hand of a friend. + -- Jubal Harshaw, "One For The Road" +%% +And I will do all these good works, and I will do them for free! +My only reward will be a tombstone that says "Here lies Gomez +Addams -- he was good for nothing." + -- Jack Sharkey, The Addams Family +%% +Yeah, if it looks like a duck, and walks like +a duck, and quacks like a duck -- shoot it. +%% +This is supposed to be a happy occasion. +Let's not BICKER and ARGUE over who killed who! +%% +The Lord giveth and the Lord taketh away. +Indian Giver be the name of the Lord. +%% +How much for your women? I want to buy your +daughter... how much for the little girl? + -- Jake Blues, "The Blues Brothers" +%% +Q: How many marketing people does it take to change a lightbulb? +A: I'll have to get back to you on that. +%% +The thrill is here, but it won't last long +You'd better have your fun before it moves along... +%% +If God is dead, who will save the Queen? +%% + A man sank into the psychiatrist's couch and said, "I have a +terrible problem, Doctor. I have a son at Harvard and another son at +Princeton; I've just gifted each of them with a new Ferrari; I've got +homes in Beverly Hills, Palm Beach, and a co-op in New York; and I've +got a thriving ranch in Venezuela. My wife is a gorgeous young actress +who considers my two mistresses to be her best friends." + The psychiatrist looked at the patient, confused. "Did I miss +something? It sounds to me like you have no problems at all." + "But, Doctor, I only make $175 a week." +%% +Surly to bed, surly to rise, makes you about average. +%% +Whenever people agree with me I always feel I must be wrong. + -- Oscar Wilde +%% +ARIES (Mar. 21 to Apr. 19) + Be cheerful today. People who don't like you will outnumber those + who do. You have warts. Focus on domestic status, financial matters, + and venereal disease. Look for involvement with Libra or Aquarius + natives; probably a fistfight with one of each. +%% +TAURUS (Apr. 20 to May 20) + Let your self-confidence and determination shine, and people will + find you boorish and headstrong. Travel, promotion, and romance + highlighted, if you live long enough. Don't take any wooden nickels. +%% +GEMINI (May 21 to Jun. 20) + Good news and bad news highlighted. Enjoy the good news while you + can; the bad news will make you forget it. You will enjoy praise + and respect from those around you; everybody loves a sucker. A short + trip is in the stars, possibly to the men's room. +%% +LEO (Jul. 23 to Aug. 22) + Your presence, poise, charm and good looks won't even help you today. + Look over your shoulder; an ugly person may be following you. Be on + your toes. Brush your teeth. Take Geritol. +%% +VIRGO (Aug. 23 to Sep. 22) + Get it in writing. Be careful. You are surrounded by lechers and + assholes; birds of a feather flock together. Trust no one. People + will not be offended, because they've come to recognize you for the + paranoid neurotic that you are. Your dentures are loose. +%% +LIBRA (Sep. 23 to Oct. 22) + Your desire for justice and truth will be overshadowed by your desire + for filthy lucre and a decent meal. Be gracious and polite. Someone + is watching you, so stop staring like that. +%% +SCORPIO (Oct. 23 to Nov. 21) + Friends abound today, seeking repayment of past loans. Smile. Check + for concealed weapons. Your natural cheerfulness makes others want + to throw up. Knock it off. +%% +SAGITTARIUS (Nov. 22 to Dec. 21) + Move slowly today, be deliberate. Indications are for bleeding + ulcers. Drink milk. Try not to be your usual offensive and + obnoxious self. Call your mother. +%% +CAPRICORN (Dec. 22 to Jan. 19) + Follow your instincts. You are much too scatterbrained to do anything + else, such as think. Romance is in the air, but not for you, so forget + it. That pimple on the end of your nose will get worse. +%% +AQUARIUS (Jan. 20 to Feb. 18) + A friend will step forward and confide in you about your breath. Rely + on your outgoing personality and winning smile to get you into a lot + of trouble. Be relaxed, things will change. Look for a pink slip on + payday. Stop wetting your bed. +%% +PISCES (Feb. 19 to Mar. 20) + Take the high road, look for the good things, carry the American + Express card and a weapon. The world is yours today, as nobody + else wants it. Your mortgage will be foreclosed. You will probably + get run over by a bus. +%% +Hacking's just another word for nothing left to kludge. +%% +Most folks they like the daytime, + 'cause they like to see the shining sun. +They're up in the morning, + off and a-running till they're too tired for having fun. +But when the sun goes down, + and the bright lights shine, my daytime has just begun. + +Now there are two sides to this great big world, + and one of them is always night. +If you can take care of business in the sunshine, baby, + I guess you're gonna be all right. +Don't come looking for me to lend you a hand. + My eyes just can't stand the light. + +'Cause I'm a night owl honey, sleep all day long. + -- Carly Simon +%% +Real Programs don't use shared text. Otherwise, how can they +use functions for scratch space after they are finished calling them? +%% +We're constantly being bombarded by insulting and humiliating music, which +people are making for you the way they make those Wonder Bread products. +Just as food can be bad for your system, music can be bad for your spirtual +and emotional feelings. It might taste good or clever, but in the long run, +it's not going to do anything for you. + -- Bob Dylan, "LA Times", September 5, 1984 +%% +There once was a man from Nantucket +Who kept all his cash in a bucket. + His daughter, named Nan, + Ran away with a man, +And as for the bucket, Nantucket. + +The pair of them went to Manhasset, +(Nan and the man with the asset.) + Pa followed them there, + But they left in a tear, +And as for the asset, Manhasset. + +Pa followed the pair to Pawtucket, +(Nan and the man with the bucket.) + Pa said to the man, + "You're welcome to Nan." +But as for the bucket, Pawtucket. +%% +If ever the pleasure of one has to be bought by the pain of the other, +there better be no trade. A trade by which one gains and the other loses +is a fraud. + -- Dagny Taggart, "Atlas Shrugged" +%% +When a girl admits she's had a checkered career, it's your move. +%% +Ah, sweet Springtime, when a young man lightly turns his fancy over! +%% +A pig is a jolly companion, +Boar, sow, barrow, or gilt -- +A pig is a pal, who'll boost your morale, +Though mountains may topple and tilt. +When they've blackballed, bamboozled, and burned you, +When they've turned on you, Tory and Whig, +Though you may be thrown over by Tabby and Rover, +You'll never go wrong with a pig, a pig, +You'll never go wrong with a pig! + -- Thomas Pynchon, "Gravity's Rainbow" +%% +Q: Why are Jewish divorces so expensive? +A: Because they're worth it! +%% +In these days +Of toil and sin +Your head grows bald +But not your chin + -- Burma Shave +%% +Beware of mathematicians and all those who make empty prophecies. +The danger already exists that the mathematicians have made covenant +with the devil to darken the spirit and to confine man in the bonds +of hell. + -- St. Augustine +%% +Your boss is a few sandwiches short of a picnic. +%% +Anyone stupid enough to be caught by the police is probably guilty. +%% +Would you like to be tried in court by people +who weren't smart enough to get out of jury duty? +%% +Q: What's black and white and red all over? +A: Two nuns in a chainsaw fight. +%% +Once upon a time there was a kingdom ruled by a great bear. The peasants +were not very rich, and one of the few ways to become at all wealthy was +to become a Royal Knight. This required an interview with the bear. If +the bear liked you, you were knighted on the spot. If not, the bear would +just as likely remove your head with one swat of a paw. However, the family +of these unfortunate would-be knights was compensated with a beautiful +sheepdog from the royal kennels, which was itself a fairly valuable +possession. And the moral of the story is: + +The mourning after a terrible knight, nothing beats the dog of the bear that +hit you. +%% +But I always fired into the nearest hill or, failing that, into blackness. +I meant no harm; I just liked the explosions. And I was careful never to +kill more than I could eat. + -- Raoul Duke +%% +Macho, adj.: + Jogging home from your vasectomy. +%% +According to convention there is a sweet and a bitter, a hot and a cold, +and according to convention, there is an order. In truth, there are atoms +and a void. + -- Democritus, 400 B.C. +%% + One fine day, the bus driver went to the bus garage, started his bus, +and drove off along the route. No problems for the first few stops -- a few +people got on, a few got off, and things went generally well. At the next +stop, however, a big hulk of a guy got on. Six feet eight, built like a +wrestler, arms hanging down to the ground. He glared at the driver and said, +"Big John doesn't pay!" and sat down at the back. + Did I mention that the driver was five feet three, thin, and basically +meek? Well, he was. Naturally, he didn't argue with Big John, but he wasn't +happy about it. Well, the next day the same thing happened -- Big John got on +again, made a show of refusing to pay, and sat down. And the next day, and the +one after that, and so forth. This grated on the bus driver, who started +losing sleep over the way Big John was taking advantage of him. Finally he +could stand it no longer. He signed up for bodybuilding courses, karate, judo, +and all that good stuff. By the end of the summer, he had become quite strong; +what's more, he felt really good about himself. + So on the next Monday, when Big John once again got on the bus +and said "Big John doesn't pay!," the driver stood up, glared back at the +passenger, and screamed, "And why not?" + With a surprised look on his face, Big John replied, "Big John has a +bus pass." +%% +The soldier came knocking upon the queen's door +He said, "I am not fighting for you anymore" +The queen knew she had seen his face someplace before +And slowly she let him inside. + +He said, "I see you now, and you're so very young +But I've seen more battles lost than I have battles won +And I have this intuition that it's all for your fun +And now will you tell me why?" + -- Suzanne Vega, "The Queen and The Soldier" +%% +And if you wonder, +What I am doing, +As I am heading for the sink. +I am spitting out all the bitterness, +Along with half of my last drink. +%% +Oh I'm just a typical American boy +From a typical American town. +I believe in God and Senator Dodd +And keeping old Castro down. +And when it came my time to serve +I knew "Better Dead Than Red", +But when I got to my old draft board, +Buddy, this is what I said: + +Chorus: + Sarge, I'm only eighteen, I've got a ruptured spleen, + And I always carry a purse! + I've got eyes like a bat and my feet are flat, + And my asthma's getting worse! + Yes, think of my career and my sweetheart dear, + And my poor old invalid aunt! + Besides I ain't no fool, I'm a-going to school + And I'm a-working in a defense plant! + -- Phil Ochs, "Draft Dodger Rag" +%% +At Group L, Stoffel oversees six first-rate programmers, +a managerial challenge roughly comparable to herding cats. + -- "The Washington Post Magazine", June 9, 1985 +%% +The IBM purchase of ROLM gives new meaning to the term "twisted pair". + -- Howard Anderson, "Yankee Group" +%% +We were so poor that we thought new clothes meant someone had died. +%% +Hi. I'm Larry. This is my brother Bob, and this is my other brother +Jimbo. We thought you might like to know the names of your assailants. +%% +Fame is a vapor; popularity an accident; +the only earthly certainty is oblivion. + -- Mark Twain +%% +If men are not afraid to die, +it is of no avail to threaten them with death. + +If men live in constant fear of dying, +And if breaking the law means a man will be killed, +Who will dare to break the law? + +There is always an official executioner. +If you try to take his place, +It is like trying to be a master carpenter and cutting wood. +If you try to cut wood like a master carpenter, + you will only hurt your hand. + -- Tao Te Ching, "Lao Tsu, #74" +%% +"Any news from the President on a successor?" he asked hopefully. +"None," Anita replied. "She's having great difficulty finding someone +qualified who is willing to accept the post." + "Then I stay," said Dr. Fresh. "I'm not good for much, but I +can at least make a decision." + "Somewhere," he grumphed, "there must be a naive, opportunistic +young welp with a masochistic streak who would like to run the most +up-and-down bureaucracy in the history of mankind." + -- R. L. Forward, "Flight of the Dragonfly" +%% + They are fools that think that wealth or women or strong drink or even +drugs can buy the most in effort out of the soul of a man. These things offer +pale pleasures compared to that which is greatest of them all, that task which +demands from him more than his utmost strength, that absorbs him, bone and +sinew and brain and hope and fear and dreams -- and still calls for more. + They are fools that think otherwise. No great effort was ever bought. +No painting, no music, no poem, no cathedral in stone, no church, no state was +ever raised into being for payment of any kind. No parthenon, no Thermopylae +was ever built or fought for pay or glory; no Bukhara sacked, or China ground +beneath Mongol heel, for loot or power alone. The payment for doing these +things was itself the doing of them. + To wield onself -- to use oneself as a tool in one's own hand -- and +so to make or break that which no one else can build or ruin -- THAT is the +greatest pleasure known to man! To one who has felt the chisel in his hand +and set free the angel prisoned in the marble block, or to one who has felt +sword in hand and set homeless the soul that a moment before lived in the body +of his mortal enemy -- to those both come alike the taste of that rare food +spread only for demons or for gods." + -- Gordon R. Dickson, "Soldier Ask Not" +%% +There are only two things in this world that I am sure of, death and +taxes, and we just might do something about death one of these days. + -- shades +%% +Violence stinks, no matter which end of it you're on. But now and then +there's nothing left to do but hit the other person over the head with a +frying pan. Sometimes people are just begging for that frypan, and if we +weaken for a moment and honor their request, we should regard it as +impulsive philanthropy, which we aren't in any position to afford, but +shouldn't regret it too loudly lest we spoil the purity of the deed. + -- Tom Robbins +%% +Stenderup's Law: + The sooner you fall behind, the more time you will have to catch up. +%% +In this vale +Of toil and sin +Your head grows bald +But not your chin. + -- Burma Shave +%% +Old mercenaries never die. They go to hell and regroup. +%% +Sex is about as important as a cheese sandwich. But a cheese sandwich, +if you ain't got one to put in your belly, is extremely important. + -- Ian Dury +%% +I consider a new device or technology to have been +culturally accepted when it has been used to commit a murder. + -- M. Gallaher +%% +Money can't buy happiness, but it can make you +awfully comfortable while you're being miserable. + -- C.B. Luce +%% +"I said, "Preacher, give me strength for round 5." +He said,"What you need is to grow up, son." +I said,"Growin' up leads to growin' old, +And then to dying, and to me that don't sound like much fun." + -- John Cougar, "The Authority Song" +%% + A group of soldiers being prepared for a practice landing on a tropical +island were warned of the one danger the island held, a poisonous snake that +could be readily identified by its alternating orange and black bands. They +were instructed, should they find one of these snakes, to grab the tail end of +the snake with one hand and slide the other hand up the body of the snake to +the snake's head. Then, forcefully, bend the thumb above the snake's head +downward to break the snake's spine. All went well for the landing, the +charge up the beach, and the move into the jungle. At one foxhole site, two +men were starting to dig and wondering what had happened to their partner. +Suddenly he staggered out of the underbrush, uniform in shreds, covered with +blood. He collapsed to the ground. His buddies were so shocked they could +only blurt out, "What happened?" + "I ran from the beachhead to the edge of the jungle, and, as I hit the +ground, I saw an orange and black striped snake right in front of me. I +grabbed its tail end with my left hand. I placed my right hand above my left +hand. I held firmly with my left hand and slid my right hand up the body of +the snake. When I reached the head of the snake I flicked my right thumb down +to break the snake's spine... did you ever goose a tiger?" +%% +After I run your program, let's make love like crazed weasels, OK? +%% +It seems that there was this Christian about to be thrown to the lions. He +was shoved into the middle of the arena and the lion was released. Being +a good Christian, as the lion approached he knelt and prayed, asking God for +forgiveness for his (few) sins, and begging that the lion might be dissuaded +from eating him for its breakfast. Much to his dismay, the lion didn't stop +but kept coming, getting faster and faster, now almost running, so the +Christian took off too. There they were, running around and around the arena, +the lion getting closer and the Christian praying harder and harder between +gasps for breath. The lions breath was now hot upon his heels and he could +even feel droplets of the lions saliva splashing on his bare feet. So he +pulled out all the stops, promising God that if the lion will only spare him, +he will devote the rest of his life to spreading the Christian faith, +forsaking all temptation and possessions. Suddenly he no longer felt the +lions breath, no longer heard the great beast's snarls close behind him. +Slowing to a stop, he turned around and saw the lion on its knees, eyes rolled +upward, paws held together. The lion appeared to be muttering something so +the Christian approached until he could make out what the lion was saying. + "Dear Lord, for what I am about to receive..." +%% +I think I'm schizophrenic. One half of me's +paranoid and the other half's out to get him. +%% +Micro Credo: + Never trust a computer bigger than you can lift. +%% +Once upon this midnight incoherent, +While you pondered sentient and crystalline, +Over many a broken and subordinate +Volume of gnarly lore, +While I pestered, nearly singing, +Sudddenly there came a hewing, +As of someone profusely skulking, +Skulking at my chamber door. +%% +Ahhhhhh... the smell of cuprinol and mahogany. It +excites me to... acts of passion... acts of... ineptitude. +%% +The perversity of nature is nowhere better demonstrated by the fact that, +when exposed to the same atmosphere, bread becomes hard while crackers +become soft. +%% +An effective way to deal with predators is to taste terrible. +%% +The best thing that comes out of Iowa is I-80. +%% +What this country needs is a good 5 dollar plasma weapon. +%% +I shot a query into the net. +I haven't got an answer yet, A posted message called me rotten +But seven people gave me hell For ignoring mail I'd never gotten; +And said I ought to learn to spell; An angry message asked me, Please + Don't send such drivel overseas; +A lawyer sent me private mail +And swore he'd slap my ass in jail -- One netter thought it was a hoax: +I'd mentioned Un*x in my gem "Hereafter, post to net dot jokes!"; +And failed to add the T and M; Another called my grammar vile + And criticized my writing style. +Each day I scan each Subject line +In hopes the topic will be mine; +I shot a query into the net. +I haven't got an answer yet... + -- Ed Nather +%% + "What are you watching?" + "I don't know." + "Well, what's happening?" + "I'm not sure... I think the guy in the hat did +something terrible." + "Why are you watching it?" + "You're so analytical. Sometimes you just have to let +art flow over you." + -- The Big Chill +%% +Every morning in Africa, a gazelle wakes up. It knows it must run faster +than the fastest lion or it will be killed. Every morning a lion wakes up. +It knows it must outrun the slowest gazelle or it will starve to death. +It doesn't matter whether you are a lion or a gazelle: when the sun comes +up, you'd better be running. +%% +I attribute my success to intelligence, guts, determination, honesty, +ambition, and having enough money to buy people with those qualities. +%% +Has everyone noticed that all the letters of the word "database" are typed +with the left hand? Now the layout of the QWERTYUIOP typewriter keyboard +was designed, among other things, to facilitate the even use of both hands. +It follows, therefore, that writing about databases is not only unnatural, +but a lot harder than it appears. +%% +You're not drunk if you can lie on the floor without holding on. + -- Dean Martin +%% +Being in politics is like being a football coach. You have to be smart +enough to understand the game and dumb enough to think it's important. + -- Eugene McCarthy +%% +Don't stop to stomp ants when the elephants are stampeding. +%% +Decisions of the judges will be final unless shouted down by a really over- +whelming majority of the crowd present. Abusive and obscene language may +not be used by contestants when addressing members of the judging panel, +or, conversely, by members of the judging panel when addressing contestants +(unless struck by a boomerang). + -- Mudgeeraba Creek Emu-Riding and Boomerang-Throwing Assoc. +%% +If two wrongs don't make a right, try three wrongs. +%% +For every human problem, there is a neat, +plain solution -- and it is always wrong. + -- H.L. Mencken +%% + Phases of a Project: +(1) Exultation. +(2) Disenchantment. +(3) Confusion. +(4) Search for the Guilty. +(5) Punishment for the Innocent. +(6) Distinction for the Uninvolved. +%% +The race is not always to the swift, nor the +battle to the strong, but that's the way to bet. + -- Damon Runyon +%% +Good salesmen and good repairmen will never go hungry. + -- R.E. Schenk +%% +O Lord, grant that we may always be right, +for Thou knowest we will never change our minds. +%% +The chief cause of problems is solutions. + -- E. Sevareid +%% +Half of being smart is knowing what you're dumb at. +%% +Finality is death. +Perfection is finality. +Nothing is perfect. +There are lumps in it. +%% +(1) Office employees will daily sweep the floors, dust the + furniture, shelves, and showcases. +(2) Each day fill lamps, clean chimneys, and trim wicks. + Wash the windows once a week. +(3) Each clerk will bring a bucket of water and a scuttle of + coal for the day's business. +(4) Make your pens carefully. You may whittle nibs to your + individual taste. +(5) This office will open at 7 a.m. and close at 8 p.m. except + on the Sabbath, on which day we will remain closed. Each + employee is expected to spend the Sabbath by attending + church and contributing liberally to the cause of the Lord. + -- "Office Worker's Guide", New England Carriage + Works, 1872 +%% +(6) Men employees will be given time off each week for courting + purposes, or two evenings a week if they go regularly to church. +(7) After an employee has spent his thirteen hours of labor in the + office, he should spend the remaining time reading the Bible + and other good books. +(8) Every employee should lay aside from each pay packet a goodly + sum of his earnings for his benefit during his declining years, + so that he will not become a burden on society or his betters. +(9) Any employee who smokes Spanish cigars, uses alcoholic drink + in any form, frequents pool tables and public halls, or gets + shaved in a barber's shop, will give me good reason to suspect + his worth, intentions, integrity and honesty. +(10) The employee who has performed his labours faithfully and + without a fault for five years, will be given an increase of + five cents per day in his pay, providing profits from the + business permit it. + -- "Office Worker's Guide", New England Carriage + Works, 1872 +%% +Ankh if you love Isis. +%% +Being a mime means never having to say you're sorry. +%% +Blood is thicker than water, and much tastier. +%% +Calm down, it's *only* ones and zeroes. +%% +Campus crusade for Cthulhu -- it found me. +%% +Chaos is King and Magic is loose in the world. +%% +Conquering Russia should be done steppe by steppe. +%% +Cthulhu for President -- + if you're tired of choosing the lesser of two evils. +%% +Cthulhu Saves -- in case He's hungry later. +%% +Dyslexics have more fnu. +%% +Eat the rich, the poor are tough and stringy. +%% +Entropy isn't what it used to be. +%% +Everyone was born right-handed. +Only the greatest overcome it. +%% +God is real, unless declared integer. +%% +"The hell with the prime directive! Let's kill something!" +%% +I don't have to take this abuse from you -- +I've got hundreds of people waiting to abuse me. + -- Bill Murray, "Ghostbusters" +%% +If people see that you mean them no harm, +they'll never hurt you, nine times out of ten! +%% +If voting could change the system, it would be illegal. +If not voting could change the system, it would be illegal. +%% +"I'm not stupid, I'm not expendable, and I'M NOT GOING!" +%% +It's hard to think of you as the end +result of millions of years of evolution. +%% +I have more hit points that you can possible imagine. +%% +Let me put it this way: today is going to be a learning experience. +%% +That's odd. That's very odd. +Wouldn't you say that's very odd? +%% +All intelligent species own cats. +%% +This must be morning. I never could get the hang of mornings. +%% +We came, we saw, we kicked its ass! + -- Bill Murray, "Ghostbusters" +%% +When Cthulhu calls, He calls collect! +%% +It would save me a lot of time if you just gave up and went mad now. +%% +When you get what you want in your struggle for self +And the world makes you king for a day, +Just go to a mirror and look at yourself +And see what that man has to say. + For it isn't your father or mother or wife + Whose judgement upon you must pass; + The fellow whose verdict counts most in your life + Is the one staring back from the glass. +Some people may think you a straight-shootin' chum +And call you a wonderful guy, +But the man in the glass says you're only a bum +If you can't look him straight in the eye. + He's the fellow to please, never mind all the rest, + For he's with you clear up to the end, + And you've passed your most dangerous, difficult test + If the man in the glass is your friend. +You may fool the whole world down the pathway of life +And get pats on the back as you pass, +But your final reward will be heartaches and tears +If you've cheated the man in the glass. +%% +A good name lost is seldom regained. When character is gone, +all is gone, and one of the richest jewels of life is lost forever. + -- J. Hawes +%% +My idea of roughing it is when room service is late. +%% +My idea of roughing it turning the air conditioner to low. +%% + Never ask your lover if he'd dive in front of an oncoming train for +you. He doesn't know. Never ask your lover if she'd dive in front of an +oncoming band of Hell's Angels for you. She doesn't know. Never ask how many +cigarettes your lover has smoked today. Cancer is a personal committment. + Never ask to see pictures of your lover's former lovers -- especially +the ones who dived in front of trains. If you look like one of them, you are +repeating history's mistakes. If you don't, you'll wonder what he or she saw +in the others. + While we are on the subject of pictures: You may admire the picture +of your lover cavorting naked in a tidal pool on Maui. Don't ask who took +it. The answer is obvious. A Japanese tourist took the picture. + Never ask if your lover has had therapy. Only people who have had +therapy ask if people have had therapy. + Don't ask about plaster casts of male sex organs marked JIMI, JIM, etc. +Assume that she bought them at a flea market. + -- James Peterson and Kate Nolan +%% +Eudaemonic research proceeded with the casual mania peculiar to this part of +the world. Nude sunbathing on the back deck was combined with phone calls to +Advanced Kinetics in Costa Mesa, American Laser Systems in Goleta, Automation +Industries in Danbury, Connecticut, Arenberg Ultrasonics in Jamaica Plain, +Massachusetts, and Hewlett Packard in Sunnyvale, California, where Norman +Packard's cousin, David, presided as chairman of the board. The trick was to +make these calls at noon, in the hope that out-to-lunch executives would return +them at their own expense. Eudaemonic Enterprises, for all they knew, might be +a fast-growing computer company branching out of the Silicon Valley. Sniffing +the possibility of high-volume sales, these executives little suspected that +they were talking on the other end of the line to a naked physicist crazed +over roulette. + -- Thomas Bass, "The Eudaemonic Pie" +%% +When you are about to die, a wombat is better than no company at all. + -- Roger Zelazny, "Doorways in the Sand" +%% +Don't know what time I'll be back, Mom. +Probably soon after she throws me out. +%% +And Bezel saideth unto Sham: "Sham," he saideth, "Thou shalt goest unto the +town of Begorrah, and there thou shalt fetcheth unto thine bosom 35 talents, +and also shalt thou fetcheth a like number of cubits, provideth that they +are nice and fresh." + -- Dave Barry, "Getting Religion" +%% +Aide to Raygun: Sir, the poor are outside protesting your budget cuts. +Raygun himself: Tell them they'll have to help themselves. +Aide to Raygun: Sir, the Pentagon wants another $30 billion. +Raygun himself: Tell them to help themselves. +%% +I realize that today you have a number of top female athletes such as +Martina Navratilova who can run like deer and bench-press Chevrolet +trucks. But to be brutally frank, women as a group have a long way to +go before they reach the level of intensity and dedication to sports +that enables men to be such incredible jerks about it. + -- Dave Barry, "Sports is a Drag" +%% +I own my own body, but I share. +%% +Lisp hackers have to be bound (to-do 'it) ... +%% +Our team usually puts the other woman at second base, where the maximum +possible number of males can get there on short notice to help out in case +of emergency. As far as I can tell, our second basewoman is a pretty good +baseball player, better than I am, anyway, but there's no way to know for +sure because if the ball gets anywhere near her, a male comes barging over +from, say, right field, to deal with it. She's been on the team for three +seasons now, but the males still don't trust her. They know, deep in their +souls, that if she had to choose between catching a fly ball and saving an +infant's life, she probably would elect to save the infant's life, without +ever considering whether there were men on base. + -- Dave Barry, "Sports is a Drag" +%% +Q: How do you play religious roulette? +A: You stand around in a circle and blaspheme and see who gets + struck by lightning first. +%% +Women who want to be equal to men lack imagination. +%% +Yes, that was Richard Nixon. He used to be President. When he left +the White House, the Secret Service would count the silverware. + -- Woody Allen, "Sleeper" +%% +The difference between reality and unreality +is that reality has so little to recommend it. + -- Allan Sherman +%% +Children are like cats, they can tell when you don't like +them. That's when they come over and violate your body space. +%% + Looking for a cool one after a long, dusty ride, the drifter strode +into the saloon. As he made his way through the crowd to the bar, a man +galloped through town screaming, "Big Mike's comin'! Run fer yer lives!" + Suddenly, the saloon doors burst open. An enormous man, standing over +eight feet tall and weighing an easy 400 pounds, rode in on a bull, using a +rattlesnake for a whip. Grabbing the drifter by the arm and throwing him over +the bar, the giant thundered, "Gimme a drink!" + The terrified man handed over a bottle of whiskey, which the man +guzzled in one gulp and then smashed on the bar. He then stood aghast as +the man stuffed the broken bottle in his mouth, munched broken glass and +smacked his lips with relish. + "Can I, ah, uh, get you another, sir?" the drifter stammered. + "Naw, I gotta git outa here, boy," the man grunted. "Big Mike's +a-comin'." +%% +If you marry a man who cheats on his wife, you'll +be married to a man who cheats on his wife. + -- Ann Landers +%% +A rabbi and a priest are sitting together on a train, and the rabbi leans +over and asks, "So, how high can you advance in your organization?" + The priest replies, "Well, if I am lucky, I guess I could become a +Bishop." + "Well, could you get any higher than that?" + "I suppose that if my works are seen in a very good light that I +might be made an Archbishop." + "Is there any way that you might go higher than that?" + "If all the Saints should smile, I guess I could be made a Cardinal." + "Could you be anything higher than a Cardinal?" + Hesitating a little bit, the priest said, "I supose that I could +be elected Pope, but only if it's God's will." + "And could you be anything higher than that, is there any way to go +up from being the Pope?" + "What?! I should be the Messiah himself?!" + The rabbi leaned back and smiled. "One of our boys made it." +%% +One dusty July afternoon, somewhere around the turn of the century, Patrick +Malone was in Mulcahey's Bar, bending an elbow with the other street car +conductors from the Brooklyn Traction Company. While they were discussing the +merits of a local ring hero, the bar goes silent. Malone turns around to see +his wife, with a face grim as death, stalking to the bar. + Slapping a four-bit piece down on the bar, she draws herself up to her +full five feet five inches and says to Mulcahey, "Give me what himself has +been havin' all these years." + Mulcahey looks at Malone, who shrugs, and then back at Margaret Mary +Malone. He sets out a glass and pours her a triple shot of Rye. The bar is +totally silent as they watch the woman pick up the glass and knock back the +drink. She slams the glass down on the bar, gasps, shudders slightly, and +passes out; falling straight back, stiff as a board, saved from sudden contact +with the barroom floor by the ample belly of Seamus Fogerty. + Sometime later, she comes to on the pool table, a jacket under her +head. Her bloodshot eyes fell upon her husband, who says, "And all these +years you've been thinkin' I've been enjoying meself." +%% +I used to think I was a child; now I think I am an adult -- not because +I no longer do childish things, but because those I call adults are no +more mature than I am. +%% +When in doubt, tell the truth. + -- Mark Twain +%% +Save the whales. Collect the whole set. +%% +"Do you think what we're doing is wrong?" +"Of course it's wrong! It's illegal!" +"I've never done anything illegal before." +"I thought you said you were an accountant." +%% +"The pyramid is opening!" +"Which one?" +"The one with the ever-widening hole in it!" +%% +Calling J-Man Kink. Calling J-Man Kink. Hash missle sighted, target +Los Angeles. Disregard personal feelings about city and intercept. +%% +Well, if you can't believe what you read +in a comic book, what *can* you believe? + -- Bullwinkle J. Moose +%% +I want to buy a husband who, every week when I sit down to watch "St. +Elsewhere", won't scream, "Forget it, Blanche... It's time for Hee-Haw!" +%% +Bullwinkle: You just leave that to my pal. He's the brains of the outfit. +General: What does that make YOU? +Bullwinkle: What else? An executive. +%% +His super power is to turn into a scotch terrier. +%% +What with chromodynamics and electroweak too +Our Standardized Model should please even you, +Tho' once you did say that of charm there was none +It took courage to switch as to say Earth moves not Sun. +Yet your state of the union penultimate large +Is the last known haunt of the Fractional Charge, +And as you surf in the hot tub with sourdough roll +Please ponder the passing of your sole Monopole. +Your Olympics were fun, you should bring them all back +For transsexual tennis or Anamalon Track, +But Hollywood movies remain sinfully crude +Whether seen on the telly or Remotely Viewed. +Now fasten your sunbelts, for you've done it once more, +You said it in Leipzig of the thing we adore, +That you've built an incredible crystalline sphere +Whose German attendants spread trembling and fear +Of the death of our theory by Particle Zeta +Which I'll bet is not there say your article, later. + -- Sheldon Glashow, Physics Today, December, 1984 +%% +I don't believe in astrology. But then I'm an +Aquarius, and Aquarians don't believe in astrology. + -- James Quirk +%% +It's not an optical illusion, it just looks like one. + -- Phil White +%% +I am changing my name to Chrysler +I am going down to Washington, D.C. +I will tell some power broker + What they did for Iacocca +Will be perfectly acceptable to me! + +I am changing my name to Chrysler, +I am heading for that great receiving line. +When they hand a million grand out, + I'll be standing with my hand out, +Yessir, I'll get mine! +%% +Yesterday upon the stair +I met a man who wasn't there. +He wasn't there again today -- +I think he's from the CIA. +%% +The bland leadeth the bland and they both shall fall into the kitsch. +%% +When in doubt, use brute force. + -- Ken Thompson +%% +If the code and the comments disagree, then both are probably wrong. + -- Norm Schryer +%% +Don't get suckered in by the comments -- they +can be terribly misleading. Debug only code. + -- Dave Storer +%% +Maintainer's Motto: + If we can't fix it, it ain't broke. +%% +The First Rule of Program Optimization: + Don't do it. + +The Second Rule of Program Optimization (for experts only!): + Don't do it yet. + -- Michael Jackson +%% +One Page Principle: + A specification that will not fit on one page + of 8.5x11 inch paper cannot be understood. + -- Mark Ardis +%% +Furious activity is no substitute for understanding. + -- H. H. Williams +%% +God must have loved calories, she made so many of them. +%% +Just a few of the perfect excuses for having some strawberry shortcake. +Pick one. + +1: It's less calories than two pieces of strawberry shortcake. +2: It's cheaper than going to France. +3: It neutralizes the brownies I had yesterday. +4: Life is short. +5: It's somebody's birthday. I don't want them to celebrate alone. +6: It matches my eyes. +7: Whoever said, "Let them eat cake." must have been talking to me. +8: To punish myself for eating dessert yesterday. +9: Compensation for all the time I spend in the shower not eating. +10: Strawberry shortcake is evil. I must help rid the world of it. +11: I'm getting weak from eating all that healthy stuff. +12: It's the second anniversary of the night I ate plain broccoli. +%% +Asked how she felt being the first woman to make a major-league team, she +said, "Like a pig in mud," or words to that effect, and then turned and +released a squirt of tobacco juice from the wad of rum soaked plug in her +right cheek. She chewed a rare brand of plug called Stuff It, which she +learned to chew when she was playing Nicaraguan summer ball. She told the +writers, "They were so mean to me down there you couldn't write it in your +newspaper. I took a gun everywhere I went, even to bed. *Especially* to +bed. Guys were after me like you can't believe. That's when I started +chewing tobacco -- because no matter how bad anybody treats you, it's not +as bad as this. This is the worst chew in the world. After this, +everything else is peaches and cream." The writers elected Gentleman Jim, +the Sparrow's P.R. guy, to bite off a chunk and tell them how it tasted, +and as he sat and chewed it tears ran down his old sunburnt cheeks and he +couldn't talk for a while. Then he whispered, "You've been chewing this for +two years? God, I had no idea it was so hard to be a woman." + -- Garrison Keillor +%% +Vermouth always makes me brilliant unless it makes me idiotic. + -- E.F. Benson +%% +"Life is like a buffet; it's not good but there's plenty of it." +%% +I have come up with a surefire concept for a hit television show, which +would be called "A Live Celebrity Gets Eaten by a Shark." + -- Dave Barry, "The Wonders of Sharks on TV" +%% +The human race has been fascinated by sharks for as long as I can +remember. Just like the bluebird feeding its young, or the spider +struggling to weave its perfect web, or the buttercup blooming in +spring, the shark reveals to us yet another of the infinite and +wonderful facets of nature, namely the facet that it can bite your head +off. This causes us humans to feel a certain degree of awe. + -- Dave Barry, "The Wonders of Sharks on TV" +%% + So Richard and I decided to try to catch [the small shark]. +With a great deal of strategy and effort and shouting, we managed to +maneuver the shark, over the course of about a half-hour, to a sort of +corner of the lagoon, so that it had no way to escape other than to +flop up onto the land and evolve. Richard and I were inching toward +it, sort of crouched over, when all of a sudden it turned around and -- +I can still remember the sensation I felt at that moment, primarily in +the armpit area -- headed right straight toward us. + Many people would have panicked at this point. But Richard and +I were not "many people." We were experienced waders, and we kept our +heads. We did exactly what the textbook says you should do when you're +unarmed and a shark that is nearly two feet long turns on you in water +up to your lower calves: We sprinted I would say 600 yards in the +opposite direction, using a sprinting style such that the bottoms of +our feet never once went below the surface of the water. We ran all +the way to the far shore, and if we had been in a Warner Brothers +cartoon we would have run right INTO the beach, and you would have seen +these two mounds of sand racing across the island until they bonked +into trees and coconuts fell onto their heads. + -- Dave Barry, "The Wonders of Sharks on TV" +%% +... So the documentary-makers stick with sharks. Generally, their +procedure is to scatter bleeding fish pieces around their boat, so as +to infest the waters. I would estimate that the primary food source of +sharks today is bleeding fish pieces scattered by people making +documentaries. Once the sharks arrive, they are generally fairly +listless. The general shark attitude seems to be: "Oh God, another +documentary." So the divers have to somehow goad them into attacking, +under the guise of Scientific Research. "We know very little about the +effect of electricity on sharks," the narrator will say, in a deeply +scientific voice. "That is why Todd is going to jab this Great White +in the testicles with a cattle prod." The divers keep this kind of +thing up until the shark finally gets irritated and snaps at them, and +then they act as though this was a totally unexpected and very +dangerous development, although clearly it is what they wanted all along. + -- Dave Barry, "The Wonders of Sharks on TV" +%% +"Of course it's the murder weapon. +Who would frame someone with a fake?" +%% + Lassie looked brilliant, in part because the farm family she +lived with was made up of idiots. Remember? One of them was always +getting pinned under the tractor, and Lassie was always rushing back to +the farmhouse to alert the other ones. She'd whimper and tug at their +sleeves, and they'd always waste precious minutes saying things: "Do +you think something's wrong? Do you think she wants us to follow her? +What is it, girl?", etc., as if this had never happened before, instead +of every week. What with all the time these people spent pinned under +the tractor, I don't see how they managed to grow any crops whatsoever. +They probably got by on federal crop supports, which Lassie filed the +applications for. + -- Dave Barry +%% + Excellence is THE trend of the '80s. Walk into any shopping +mall bookstore, go to the rack where they keep the best-sellers such as +"Garfield Gets Spayed", and you'll see a half-dozen books telling you +how to be excellent: "In Search of Excellence", "Finding Excellence", +"Grasping Hold of Excellence", "Where to Hide Your Excellence at Night +So the Cleaning Personnel Don't Steal It", etc. + -- Dave Barry, "In Search of Excellence" +%% + Take the folks at Coca-Cola. For many years, they were content +to sit back and make the same old carbonated beverage. It was a good +beverage, no question about it; generations of people had grown up +drinking it and doing the experiment in sixth grade where you put a +nail into a glass of Coke and after a couple of days the nail dissolves +and the teacher says: "Imagine what it does to your TEETH!" So Coca-Cola +was solidly entrenched in the market, and the management saw no need to +improve ... + -- Dave Barry, "In Search of Excellence" +%% + ... This striving for excellence extends into people's +personal lives as well. When '80s people buy something, they buy the +best one, as determined by (1) price and (2) lack of availability. +Eighties people buy imported dental floss. They buy gourmet baking +soda. If an '80s couple goes to a restaurant where they have made a +reservation three weeks in advance, and they are informed that their +table is available, they stalk out immediately, because they know it is +not an excellent restaurant. If it were, it would have an enormous +crowd of excellence-oriented people like themselves waiting, their +beepers going off like crickets in the night. An excellent restaurant +wouldn't have a table ready immediately for anybody below the rank of +Liza Minnelli. + -- Dave Barry, "In Search of Excellence" +%% +An excellence-oriented '80s male does not wear a regular watch. He wears +a Rolex watch, because it weighs nearly six pounds and is advertised +only in excellence-oriented publications such as Fortune and Rich +Protestant Golfer Magazine. The advertisements are written in +incomplete sentences, which is how advertising copywriters denote +excellence: + +"The Rolex Hyperion. An elegant new standard in quality excellence and +discriminating handcraftsmanship. For the individual who is truly able +to discriminate with regard to excellent quality standards of crafting +things by hand. Fabricated of 100 percent 24-karat gold. No watch +parts or anything. Just a great big chunk on your wrist. Truly a +timeless statement. For the individual who is very secure. Who +doesn't need to be reminded all the time that he is very successful. +Much more successful than the people who laughed at him in high +school. Because of his acne. People who are probably nowhere near as +successful as he is now. Maybe he'll go to his 20th reunion, and +they'll see his Rolex Hyperion. Hahahahahahahahaha." + -- Dave Barry, "In Search of Excellence" +%% +Brillineggiava, ed i tovoli slati + girlavano ghimbanti nella vaba; +i borogovi eran tutti mimanti + e la moma radeva fuorigraba. + +"Figliuolo mio, sta' attento al Gibrovacco, + dagli artigli e dal morso lacerante; +fuggi l'uccello Giuggiolo, e nel sacco + metti infine il frumioso Bandifante". + -- "The Jabberwock" +%% +Dimensions will always be expressed in the least usable term, convertible +only through the use of weird and unnatural conversion factors. Velocity, +for example, will be expressed in furlongs per fortnight. +%% +The primary theme of SoupCon is communication. The acronym "LEO" +represents the secondary theme: + + Law Enforcement Officials + +The overall theme of SoupCon shall be: + + Avoiding Communication with Law Enforcement Officials + -- M. Gallaher +%% +While having never invented a sin, +I'm trying to perfect several. +%% +Chef, n: + Any cook who swears in French. +%% +Gourmet, n: + Anyone whom, when you fail to finish something strange or + revolting, remarks that it's an acquired taste and that you're + leaving the best part. +%% + FROM THE DESK OF + Rapunzel + +Dear Prince: + + Use ladder tonight -- + you're splitting my ends. +%% + FROM THE DESK OF + Snow White + +Dear Snow White: + + Thanks for last night. + + Sleepy, Doc, Grumpy, Sneezy, Happy, Dopey, Bashful +%% +Women aren't as mere as they used to be. + -- Pogo +%% +No plain fanfold paper could hold that fractal Puff -- +He grew so fast no plotting pack could shrink him far enough. +Compiles and simulations grew so quickly tame +And swapped out all their data space when Puff pushed his stack frame. +(refrain) + Puff, he grew so quickly, while others moved like snails + And mini-Puffs would perch themselves on his gigantic tail. + All the student hackers loved that fractal Puff + But DCS did not like Puff, and finally said, "Enough!" + (refrain) +Puff used more resources than DCS could spare. +The operator killed Puff's job -- he didn't seem to care. +A gloom fell on the hackers; it seemed to be the end, +But Puff trapped the exception, and grew from naught again! +(refrain) +Refrain: + Puff the fractal dragon was written in C, + And frolicked while processes switched in mainframe memory. + Puff the fractal dragon was written in C, + And frolicked while processes switched in mainframe memory. +%% +It wasn't that she had a rose in her teeth, exactly. +It was more like the rose and the teeth were in the same glass. +%% +When a camel flies, no one laughs if it doesn't get very far! +%% +It's recently come to Fortune's attention that scientists have stopped +using laboratory rats in favor of attorneys. Seems that there are not +only more of them, but you don't get so emotionally attached. +%% +A Mexican newspaper reports that bored Royal Air Force pilots stationed +on the Falkland Islands have devised what they consider a marvelous new +game. Noting that the local penguins are fascinated by airplanes, the +pilots search out a beach where the birds are gathered and fly slowly +along it at the water's edge. Perhaps ten thousand penguins turn their +heads in unison watching the planes go by, and when the pilots turn +around and fly back, the birds turn their heads in the opposite +direction, like spectators at a slow-motion tennis match. Then, the +paper reports "The pilots fly out to sea and directly to the penguin +colony and overfly it. Heads go up, up, up, and ten thousand penguins +fall over gently onto their backs. + -- Audobon Society Magazine +%% + An architect's first work is apt to be spare and clean. He + knows he doesn't know what he's doing, so he does it carefully +and with great restraint. + As he designs the first work, frill after frill and + embellishment after embellishment occur to him. These get +stored away to be used "next time." Sooner or later the first system +is finished, and the architect, with firm confidence and a demonstrated +mastery of that class of systems, is ready to build a second system. + This second is the most dangerous system a man ever designs. +When he does his third and later ones, his prior experiences will +confirm each other as to the general characteristics of such systems, +and their differences will identify those parts of his experience that +are particular and not generalizable. + The general tendency is to over-design the second system, using +all the ideas and frills that were cautiously sidetracked on the first +one. The result, as Ovid says, is a "big pile." + -- Frederick Brooks, "The Mythical Man Month" +%% + The Soviet pre-eminence in chess can be traced to the average +Russian's readiness to brood obsessively over anything, even the +arrangement of some pieces of wood. Indeed, the Russians' +predisposition for quiet reflection followed by sudden preventive action +explains why they led the field for many years in both chess and ax +murders. It is well known that as early as 1970, the U.S.S.R., aware of +what a defeat at Reykjavik would do to national prestige, implemented a +vigorous program of preparation and incentive. Every day for an entire +year, a team of psychologists, chess analysts and coaches met with the +top three Russian grand masters and threatened them with a pointy +stick. That these tactics proved fruitless is now a part of chess +history and a further testament to the American way, which provides +that if you want something badly enough, you can always go to Iceland +and get it from the Russians. + -- Marshall Brickman, Playboy, April, 1973 +%% + Before he became a hermit, Zarathud was a young Priest, and + took great delight in making fools of his opponents in front of +his followers. + One day Zarathud took his students to a pleasant pasture and +there he confronted The Sacred Chao while She was contentedly grazing. + "Tell me, you dumb beast," demanded the Priest in his +commanding voice, "why don't you do something worthwhile? What is your +Purpose in Life, anyway?" + Munching the tasty grass, The Sacred Chao replied "MU". (The +Chinese ideogram for NO-THING.) + Upon hearing this, absolutely nobody was enlightened. + Primarily because nobody understood Chinese. + -- Camden Benares, "Zen Without Zen Masters" +%% + An older student came to Otis and said, "I have been to see a +great number of teachers and I have given up a great number of pleasures. +I have fasted, been celibate and stayed awake nights seeking enlightenment. +I have given up everything I was asked to give up and I have suffered, but +I have not been enlightened. What should I do?" + Otis replied, "Give up suffering." + -- Camden Benares, "Zen Without Zen Masters" +%% + A novel approach is to remove all power from the system, which +removes most system overhead so that resources can be fully devoted to +doing nothing. Benchmarks on this technique are promising; tremendous +amounts of nothing can be produced in this manner. Certain hardware +limitations can limit the speed of this method, especially in the +larger systems which require a more involved & less efficient +power-down sequence. + An alternate approach is to pull the main breaker for the +building, which seems to provide even more nothing, but in truth has +bugs in it, since it usually inhibits the systems which keep the beer +cool. +%% + Wouldn't the sentence "I want to put a hyphen between the words +Fish and And and And and Chips in my Fish-And-Chips sign" have been +clearer if quotation marks had been placed before Fish, and between +Fish and and, and and and And, and And and and, and and and And, and +And and and, and and and Chips, as well as after Chips? +%% +Nature is by and large to be found out of doors, a location where, +it cannot be argued, there are never enough comfortable chairs. + -- Fran Lebowitz +%% +Welcome thy neighbor into thy fallout shelter. +He'll come in handy if you run out of food. + -- Dean McLaughlin. +%% +And yet, seasons must be taken with a grain of salt, for they too have +a sense of humor, as does history. Corn stalks comedy, comedy stalks +tragedy, and this too is historic. And yet, still, when corn meets +tragedy face to face, we have politics. + -- Dalglish, Larsen and Sutherland, + "Root Crops and Ground Cover" +%% +The strong give up and move on, while the weak give up and stay. +%% +Man invented language to satisfy his deep need to complain. + -- Lily Tomlin +%% +The difference between America and England is, the English think 100 +miles is a long distance and the Americans think 100 years is a long +time. +%% +I wish there was a knob on the TV where you could turn up the +intelligence. They've got one called brightness, but it doesn't +seem to work. + -- Gallagher +%% + On the day of his anniversary, Joe was frantically shopping +around for a present for his wife. He knew what she wanted, a +grandfather clock for the living room, but he found the right one +almost impossible to find. Finally, after many hours of searching, Joe +found just the clock he wanted, but the store didn't deliver. Joe, +desperate, paid the shopkeeper, hoisted the clock onto his back, and +staggered out onto the sidewalk. On the way home, he passed a bar. +Just as he reached the door, a drunk stumbled out and crashed into Joe, +sending himself, Joe, and the clock into the gutter. Murphy's law +being in effect, the clock ended up in roughly a thousand pieces. + "You stupid drunk!" screamed Joe, jumping up from the +wreckage. "Why don't you look where the hell you're going!" + With quiet dignity the drunk stood up somewhat unsteadily and +dusted himself off. "And why don't you just wear a wristwatch like a +normal person?" +%% +Some people have a way about them that seems to say: +"If I have only one life to live, let me live it as a jerk." +%% +The introduction of a new kind of music must be shunned as imperiling +the whole state, for styles of music are never disturbed without +affecting the most important political institutions. ... The new +style, gradually gaining a lodgement, quitely insinuates itself into +manners and customs, and from it ... goes on to attack laws and +constitutions, displaying the utmost impudence, until it ends by +overturning everything. + -- Plato, "Republic", 370 B.C. +%% +For every bloke who makes his mark, +there's half a dozen waiting to rub it out. + -- Andy Capp +%% +Jerry Ford is a nice guy, but he played too much football with his +helmet off. + -- Lyndon Johnson +%% +In the course of reading Hadamard's "The Psychology of Invention in the +Mathematical Field", I have come across evidence supporting a fact +which we coffee achievers have long appreciated: no really creative, +intelligent thought is possible without a good cup of coffee. On page +14, Hadamard is discussing Poincare's theory of fuchsian groups and +fuchsian functions, which he describes as "... one of his greatest +discoveries, the first which consecrated his glory ..." Hadamard refers +to Poincare having had a "... sleepless night which initiated all that +memorable work ..." and gives the following, very revealing quote: + "One evening, contrary to my custom, I drank black coffee and + could not sleep. Ideas rose in crowds; I felt them collide + until pairs interlocked, so to speak, making a stable + combination." +Too bad drinking black coffee was contrary to his custom. Maybe he +could really have amounted to something as a coffee achiever. +%% +Just go with the flow control, roll with the +crunches, and, when you get a prompt, type like hell. +%% +Most people are unable to write because they are unable to think, and +they are unable to think because they congenitally lack the equipment +to do so, just as they congenitally lack the equipment to fly over the +moon. + -- H.L. Mencken +%% +Paranoid Club meeting this Friday. +Now ... just try to find out where! +%% +Apathy Club meeting this Friday. +If you want to come, you're not invited. +%% +I really had to act; 'cause I didn't have any lines. + -- Marilyn Chambers +%% +Driving in Texas is simple. For the first 100 miles you swerve to +avoid jackrabbits. For the second 100 miles you hit whatever +jackrabbits get in the way. After that you chase off into the +brush after them. +%% +NOTE: No warranties, either express or implied, are hereby given. +All software is supplied as is, without guarantee. The user assumes +all responsibility for damages resulting from the use of these +features, including, but not limited to, frustration, disgust, system +abends, disk head-crashes, general malfeasance, floods, fires, shark +attack, nerve gas, locust infestation, cyclones, hurricanes, tsunamis, +local electromagnetic disruptions, hydraulic brake system failure, +invasion, hashing collisions, normal wear and tear of friction +surfaces, comic radiation, inadvertent destruction of sensitive +electronic components, windstorms, the Riders of Nazgul, infuriated +chickens, malfunctioning mechanical or electrical sexual devices, +premature activation of the distant early warning system, peasant +uprisings, halitosis, artillery bombardment, explosions, cave-ins, +and/or frogs falling from the sky. +%% + It appears that after his death, Albert Einstein found himself +working as the doorkeeper at the Pearly Gates. One slow day, he +found that he had time to chat with the new entrants. To the first one +he asked, "What's your IQ?" The new arrival replied, "190". They +discussed Einstein's theory of relativity for hours. When the second +new arrival came, Einstein once again inquired as to the newcomer's +IQ. The answer this time came "120". To which Einstein replied, "Tell +me, how did the Cubs do this year?" and they proceeded to talk for half +an hour or so. To the final arrival, Einstein once again posed the +question, "What's your IQ?". Upon receiving the answer "70", +Einstein smiled and replied, "Got a minute to tell me about VMS 4.0?" +%% +Being owned by someone used to be called +slavery -- now it's called commitment. +%% +When you meet a master swordsman, +show him your sword. +When you meet a man who is not a poet, +do not show him your poem. + -- Rinzai, ninth century Zen master +%% +If I had my life to live over, I'd try to make more mistakes next +time. I would relax, I would limber up, I would be sillier than I have +been this trip. I know of very few things I would take seriously. I +would be crazier. I would climb more mountains, swim more rivers and +watch more sunsets. I'd travel and see. I would have more actual +troubles and fewer imaginary ones. You see, I am one of those people +who lives prophylactically and sensibly and sanely, hour after hour, +day after day. Oh, I have had my moments and, if I had it to do over +again, I'd have more of them. In fact, I'd try to have nothing else. +Just moments, one after another, instead of living so many years ahead +each day. I have been one of those people who never go anywhere +without a thermometer, a hotwater bottle, a gargle, a raincoat and a +parachute. If I had it to do over again, I would go places and do +things and travel lighter than I have. If I had my life to live over, +I would start bare-footed earlier in the spring and stay that way later +in the fall. I would play hooky more. I probably wouldn't make such +good grades, but I'd learn more. I would ride on more +merry-go-rounds. I'd pick more daisies. +%% +People who are funny and smart and return phone calls get +much better press than people who are just funny and smart. + -- Howard Simons, "The Washington Post" +%% +I've always felt sorry for people that don't drink -- remember, +when they wake up, that's as good as they're gonna feel all day! +%% + "Sheriff, we gotta catch Black Bart." + "Oh, yeah? What's he look like?" + "Well, he's wearin' a paper hat, a paper shirt, paper pants and +paper boots." + "What's he wanted for?" + "Rustling." +%% +Chorus: + Grandma got run over by a reindeer, + Walking home from our house Christmas eve. + You can say there's no such thing as Santa, + But as for me and Grandpa, we believe! +She'd been drinking too much eggnog, +And we begged her not to go. +But she'd forgot her medication, When we found her Christmas morning, +And she staggered through the door At the scene of the attack. + out in the snow. She had hoofprints on her forehead, + And incriminating claus-marks on her +Now we're all so proud of Grandpa, back. +He's been taking this so well. +See him in there watching football. I've warned all my friends and +Drinking beer and playing cards neighbors, + with cousin Mel. Better watch out for yourselves! + They should never give a license, + To a man who drives a sleigh and + plays with elves! + -- Elmo and Patsy, "Grandma Got Run Over by a Reindeer" +%% +Law of the Yukon: + Only the lead dog gets a change of scenery. +%% +Home is the place where, when you have to go there +They have to take you in. + -- Robert Frost, "The Death of the Hired Man" +%% +There are no emotional victims, only volunteers. +%% +Paralysis through analysis. +%% +"Truth is stranger than fiction, because fiction has to make sense." +%% +"How come everyone's going so slow if it's called rush hour?" +%% +"Maybe we can get together and show off to each other sometimes." +%% +Go away. I'm all right. + -- H.G. Wells' last words +%% +Health nuts are going to feel stupid someday, +lying in hospitals dying of nothing. + -- Redd Foxx +%% +Smoking is one of the leading causes of statistics. + -- Fletcher Knebel +%% +I don't know anything about music. In my line you don't have to. + -- Elvis Presley +%% +"Hello," he lied. + -- Don Carpenter, quoting a Hollywood agent +%% +The United States is like the guy at the party who +gives cocaine to everybody and still nobody likes him. + -- Jim Samuels +%% +Man is the only animal that can remain on friendly terms +with the victims he intends to eat until he eats them. + -- Samuel Butler, 1835-1902 +%% +I'm going to Boston to see my doctor. He's a very sick man. + -- Fred Allen +%% +After twelve years of therapy my psychiatrist said something that +brought tears to my eyes. He said, "No hablo ingles." + -- Ronnie Shakes +%% +Cleaning your house while your kids are still growing +is like shoveling the walk before it stops snowing. + -- Phyllis Diller +%% +It's better to be wanted for murder that not to be wanted at all. + -- Marty Winch +%% +Coincidences are spiritual puns. + -- G.K. Chesterton +%% +I took a course in speed reading and was able to read +War and Peace in twenty minutes. It's about Russia. + -- Woody Allen +%% +One is not superior merely because one sees the world as odious. + -- Chateaubriand, 1768-1848 +%% +The mome rath isn't born that could outgrabe me. + -- Nicol Williamson +%% +If you live to the age of a hundred you have it made +because very few people die past the age of a hundred. + -- George Burns +%% +Computers are useless. They can only give you answers. + -- Pablo Picasso +%% +Dr. Livingston? +Dr. Livingston I. Presume? +%% + WARNING TO ALL PERSONNEL: + +Firings will continue until morale improves. +%% +Immigration is the sincerest form of flattery. + -- Jack Paar +%% +I'm living so far beyond my income that +we may almost be said to be living apart. + -- E.E. Cummings +%% +There is no need to do any housework at all. +After the first four years the dirt doesn't get any worse. + -- Quentin Crisp +%% +I used to work in a fire hydrant factory. +You couldn't park anywhere near the place. + -- Steven Wright +%% + On this morning in August when I was 13, my mother sent us out pick +tomatoes. Back in April I'd have killed for a fresh tomato, but in August +they are no more rare or wonderful than rocks. So I picked up one and threw +it at a crab apple tree, where it made a good *splat*, and then threw a tomato +at my brother. He whipped one back at me. We ducked down by the vines, +heaving tomatoes at each other. My sister, who was a good person, said, +"You're going to get it." She bent over and kept on picking. + What a target! She was 17, a girl with big hips, and bending over, +she looked like the side of a barn. + I picked up a tomato so big it sat on the ground. It looked like it +had sat there a week. The underside was brown, small white worms lived in it, +and it was very juicy. I stood up and took aim, and went into the windup, +when my mother at the kitchen window called my name in a sharp voice. I had +to decide quickly. I decided. + A rotten Big Boy hitting the target is a memorable sound, like a fat +man doing a belly-flop. With a whoop and a yell the tomatoee came after +faster than I knew she could run, and grabbed my shirt and was about to brain +me when Mother called her name in a sharp voice. And my sister, who was a +good person, obeyed and let go -- and burst into tears. I guess she knew that +the pleasure of obedience is pretty thin compared with the pleasure of hearing +a rotten tomato hit someone in the rear end. + -- Garrison Keillor, "Lake Wobegon Days" +%% +It is November first 1940; in the famous sound stage of THE WIZARD OF +OZ on the MGM lot, a little man is lying face-up on the yellow brick +road. His wide eyes stare upward into the blinding stage lights. He +is wearing a kind of comic soldier's uniform with a yellow coat and +puffy sleeves and big fez-like blue and yellow hat with a feather on +top. His yellow hair and beard are the phony straw color of +Hollywood. He could pass for some kind of cute in the typical +tinsel-town way if it wasn't for the knife sticking out of his chest. +*Someone had murdered a Munchkin.* + -- Stuart Kaminsky, "Murder on the Yellow Brick Road" +%% +Oh, I have slipped the surly bonds of earth, +And danced the skies on laughter silvered wings; +Sunward I've climbed and joined the tumbling mirth +Of sun-split clouds and done a hundred things +You have not dreamed of -- +Wheeled and soared and swung +High in the sunlit silence. +Hovering there +I've chased the shouting wind along and flung +My eager craft through footless halls of air. +Up, up along delirious, burning blue +I've topped the wind-swept heights with easy grace, +Where never lark, or even eagle flew; +And, while with silent, lifting mind I've trod +The high untrespassed sanctity of space, +Put out my hand, and touched the face of God. + -- John Gillespie Magee Jr., "High Flight" +%% +If you flaunt it, expect to have it trashed. +%% +Chairman of the Bored. +%% +FORTUNE DISCUSSES THE OBSCURE FILMS! #6 + +RAZORBACK: Paul Harbride, 1984, 2 hours 25 min. + One of the great Australian films of the early 1980's, + and arguably the best movie ever made about a large, + man-eating hog. Some violence. With Gregory Harrison. +%% +The higher you climb, the more you show your ass. + -- Alexander Pope, "The Dunciad" +%% +He who renders warfare fatal to all engaged in it will +be the greatest benefactor the world has yet known. + -- Sir Richard Burton +%% +If it heals good, say it. +%% +"Obviously, a major malfunction has occurred." + -- Steve Nesbitt, voice of Mission Control, January 28, + 1986, as the shuttle Challenger exploded within view + of the grandstands. +%% +Feminism, n: + A political position which seeks to rebuild society so that + both men and women are treated as women wish to be treated. +%% +Millihelen, adj: + The amount of beauty required to launch one ship. +%% +Snow White has become a camera buff. She spends hours and hours +shooting pictures of the seven dwarfs and their antics. Then she +mails the exposed film to a cut rate photo service. It takes weeks +for the developed film to arrive in the mail, but that is all right +with Snow White. She clears the table, washes the dishes and sweeps +the floor, all the while singing "Someday my prints will come." +%% +A young man enters the New York branch of Tiffany's on a Friday evening and +walks up to a display case full of pearl necklaces. He turns to a gorgeous +woman, who is obviously windowshopping, looks her straight in the eye and +says, "I can tell by your eyes that you really want that necklace. If you'll +allow me, I'd like to buy it for you." + The woman looks him up and down; he's wearing a nice suit and some +pretty nice jewelry, but she has trouble believing this story. + "Look, this is some kind of put on, right?" + "No, really. You see, I've got quite a lot of money -- so much that +I could never spend it all. I'd really like for you to have it." + The guys whips out his checkbook, writes a check for five figures, +calls over a clerk and hands it to him. The clerk peers at the check, looks +at the young man, looks at the check again. "Very good, sir. I'm afraid I +can't release the necklace immediately, would Monday be all right?" + "That'll be fine, she'll pick it up." the man replies, and walks out +of the store with the woman following him in a daze. + The next Monday the man comes back in and walks up to the counter. +The same clerk hurries over to him and says, "Sir, I'm sorry to have to tell +you this, but your check was returned for insufficient funds." + "I know," the man replies. "I just wanted to thank you for a +terrific weekend." +%% +I'm not afraid of death -- I just don't want to be there when it happens. + -- Woody Allen +%% +What really shapes and conditions and makes us is somebody only a few +of us ever have the courage to face: and that is the child you once +were, long before formal education ever got its claws into you -- that +impatient, all-demanding child who wants love and power and can't get +enough of either and who goes on raging and weeping in your spirit +till at last your eyes are closed and all the fools say, "Doesn't he +look peaceful?" It is those pent-up, craving children who make all +the wars and all the horrors and all the art and all the beauty and +discovery in life, because they are trying to achieve what lay beyond +their grasp before they were five years old. + -- Robertson Davies, "The Rebel Angels" +%% + I paid a visit to my local precinct in Greenwich Village and +asked a sergeant to show me some rape statistics. He politely obliged. +That month there had been thirty-five rape complaints, an advance of ten +over the same month for the previous year. The precinct had made two +arrests. + "Not a very impressive record," I offered. + "Don't worry about it," the sergeant assured me. "You know what +these complaints represent?" + "What do they represent?" I asked. + "Prostitutes who didn't get their money," he said firmly, +closing the book. + -- Susan Brownmiller, "Against Our Will" +%% + ...He who laughs does not believe in what he laughs at, but neither +does he hate it. Therefore, laughing at evil means not preparing oneself to +combat it, and laughing at good means denying the power through which good is +self-propagating. + -- Umberto Eco, "The Name of the Rose" +%% +Did you ever wonder what you'd say to God if He sneezed? +%% +Hideously disfigured by an ancient Indian curse? + + WE CAN HELP! + +Call (511) 338-0959 for an immediate appointment. +%% +Once it hits the fan, the only rational choice is to +sweep it up, package it, and sell it as fertilizer. +%% +Q: What do you call a principal female opera singer whose high C + is lower than those of other principal female opera singers? +A: A deep C diva. +%% +This week only, all our fiber-fill jackets are marked down! +%% +The other day I... uh, no, that wasn't me. + -- Steven Wright +%% +It's a small world, but I wouldn't want to have to paint it. + -- Steven Wright +%% +When I woke up this morning, my girlfriend asked if I had +slept well. I said, "No, I made a few mistakes." + -- Steven Wright +%% +I have a map of the United States. It's actual size. +I spent last summer folding it. +People ask me where I live, and I say, "E6". + -- Steven Wright +%% +You can't have everything. Where would you put it? + -- Steven Wright +%% +I woke up this morning and discovered that everything in my apartment +had been stolen and replaced with an exact replica. I told my roommate, +"Isn't this amazing? Everything in the apartment has been stolen and +replaced with an exact replica." He said, "Do I know you?" + -- Steven Wright +%% +When I was crossing the border into Canada, they asked if +I had any firearms with me. I said, "Well, what do you need?" + -- Steven Wright +%% +Is it weird in here, or is it just me? + -- Steven Wright +%% +Sometimes it happens. People just explode. Natural causes. + -- Repo Man +%% +A mother mouse was taking her large brood for a stroll across the kitchen +floor one day when the local cat, by a feat of stealth unusual even for +its species, managed to trap them in a corner. The children cowered, +terrified by this fearsome beast, plaintively crying, "Help, Mother! +Save us! Save us! We're scared, Mother!" + Mother Mouse, with the hopeless valor of a parent protecting its +children, turned with her teeth bared to the cat, towering huge above them, +and suddenly began to bark in a fashion that would have done any Doberman +proud. The startled cat fled in fear for its life. + As her grateful offspring flocked around her shouting "Oh, Mother, +you saved us!" and "Yay! You scared the cat away!" she turned to them +purposefully and declared, "You see how useful it is to know a second +language?" +%% + A circus foreman was making the rounds inspecting the big top when +a scrawny little man entered the tent and walked up to him. "Are you the +foreman around here?" he asked timidly. "I'd like to join your circus; I +have what I think is a pretty good act." + The foreman nodded assent, whereupon the little man hurried over to +the main pole and rapidly climbed up to the very tip-top of the big top. +Drawing a deep breath, he hurled himself off into the air and began flapping +his arms furiously. Amazingly, rather than plummeting to his death the little +man began to fly all around the poles, lines, trapezes and other obstacles, +performing astounding feats of aerobatics which ended in a long power dive +from the top of the tent, pulling up into a gentle feet-first landing beside +the foreman, who had been nonchalantly watching the whole time. + "Well," puffed the little man. "What do you think?" + "That's all you do?" answered the foreman scornfully. "Bird +imitations?" +%% +What's another word for Thesaurus? + -- Steven Wright +%% +A raccoon tangled with a 23,000 volt line today. The +results blacked out 1400 homes and, of course, one raccoon. + -- Steel City News +%% +The president publicly apologized today to all those offended by +his brother's remark, "There's more Arabs in this country than +there is Jews!". Those offended include Arabs, Jews, and English +teachers. + -- Channel 11 News, Baltimore, on Billy Carter +%% +I bet you have fun chasing the soap around the bathtub. + -- Princess Diana, to a one-armed war veteran during + a visit to a London veterans hospital +%% +During the Reagan-Mondale debates: + +Q: "Do you feel that a person's age affects his ability to + perform as president?" +Reagan: "I refuse to make an issue out of my opponent's youth and + inexperience." +%% +We are going to give a little something, a few little years more, to +socialism, because socialism is defunct. It dies all by itself. The +bad thing is that socialism, being a victim of its... +Did I say socialism? + -- Fidel Castro +%% +FOR SALE: + Parachute. Used once. + Never opened. Slightly Stained. +%% +After living in New York, you trust nobody, +but you believe everything. Just in case. +%% +Why bother building anymore nuclear +warheads until we use the ones we have? +%% +Hier liegt ein Mann ganz obnegleich; +Im Leibe dick, an Suden reich. +Wir haben ihn in das Grab gesteckt, Here lies a man with sundry flaws +Weil es uns dunkt er sei verreckt. And numerous Sins upon his head; + We buried him today because + As far as we can tell, he's dead. + + -- PDQ Bach's epitaph, as requested by his cousin Betty + Sue Bach and written by the local doggeral catcher; + "The Definitive Biography of PDQ Bach", Peter Schickele +%% +Why not? -- What? -- Why not? -- Why should I not send it? -- Why should I +not dispatch it? -- Why not? -- Strange! I don't know why I shouldn't -- +Well, then -- You will do me this favor. -- Why not? -- Why should you not +do it? -- Why not? -- Strange! I shall do the same for you, when you want +me to. Why not? Why should I not do it for you? Strange! Why not? -- +I can't think why not. + -- Wolfgang Amadeus Mozart, from a letter to his cousin Maria, + "The Definitive Biography of PDQ Bach", Peter Schickele +%% +Perfection is reached, not when there is no longer anything +to add, but when there is no longer anything to take away. + -- Antoine de Saint-Exupery +%% +It has been said that man is a rational animal. All my life +I have been searching for evidence which could support this. + -- Bertrand Russell +%% +There are two problems with a major hangover. You feel +like you are going to die and you're afraid that you won't. +%% +Someone did a study of the three most-often-heard phrases in New York +City. One is "Hey, taxi." Two is, "What train do I take to get to +Bloomingdale's?" And three is, "Don't worry. It's just a flesh wound." + -- David Letterman +%% +I'll learn to play the Saxophone, +I play just what I feel. +Drink Scotch whisky all night long, +And die behind the wheel. +They got a name for the winners in the world, +I want a name when I lose. +They call Alabama the Crimson Tide, +Call me Deacon Blues. + -- Becker and Fagan, "Deacon Blues" +%% + "How would I know if I believe in love at first sight?" the sexy +social climber said to her roommate. "I mean, I've never seen a Porsche +full of money before." +%% +Why be difficult, when, with just a +little more effort, you can be impossible? +%% +So, what's with this guy Gideon, anyway? +And why can't he ever remember his Bible? +%% +Halley's Comet: It came, we saw, we drank. +%% +Dull women have immaculate homes. +%% +All work and no pay makes a housewife. +%% +Smuggling... It's not just a job, it's an adventure! + -- paid for by your local Colombian recruiting office +%% +Save the bales! +%% +Take me drunk, +I'm home again! +%% +If coke is a joke, I'm waiting around for the next line. +%% +I used to have a drinking problem. +Now I love the stuff. +%% +I wish you were a Scotch on the rocks. +%% +Silence is the only virtue you have left. +%% +I don't have an eating problem. I eat. +I get fat. I buy new clothes. No problem. +%% +I can't decide whether to commit suicide or go bowling. + -- Florence Henderson +%% +If it's worth doing, do it for money. +%% +When I was a child, I was told that anyone could become President. +I'm beginning to believe it. +%% +Experience is what you get when you didn't get what you wanted. +%% +You'll never know how many friends you really +have until you own a cottage at the beach. +%% +Pushing 30 is exercise enough. +%% +The major difference between genius and +stupidity is that genius has its limits. +%% +It's not whether you win or lose, +it's how you place the blame. +%% +Rainy days and automatic weapons always get me down. +%% +Talent does what it can. +Genius does what it must. +You do what you get paid to do. +%% +I owe, I owe, +It's off to work I go... +%% +Whenever someone tells you to take their advice, +you can be pretty sure that they're not using it. +%% +So, good night, you moonlit ladies, +Rock-a-bye sweet baby James. +Deep greens and blues are the colors I choose, +Won't you let me go down in my dreams? +And rock-a-bye sweet baby James. + -- James Taylor, "Rock-a-bye Sweet Baby James" +%% +It is considered normal to consecrate virginity in the +general and lust for its destruction in the particular. +%% +Let's just say that where a change was required, I adjusted. In every +relationship that exists, people have to seek a way to survive. If you +really care about the person, you do what's necessary, or that's the end. +For the first time, I found that I really could change, and the qualities +I most admired in myself I gave up. I stopped being loud and bossy... +Oh, all right. I was still loud and bossy, but only behind his back." + -- Kate Hepburn, on Tracy and Hepburn +%% +All I need to have a good time, +Is a reefer, a woman and a bottle of wine. +With those three things I don't need no sunshine, +A reefer, a woman and a bottle of wine. + +All I want is to never grow old, +I want to wash in a bathtub of gold. +I want 97 kilos already rolled, +I want to wash in a bathtub of gold. + +I want to light my cigars with 10 dollar bills, +I like to have a cattle ranch in Beverly Hills. +I want a bottle of Red Eye that's always filled, +I like to have a cattle ranch in Beverly Hills. + -- Country Joe and the Fish, "Zachariah" +%% +"... gentlemen do not read each other's mail." + -- Secretary of State Henry Stimson, on closing down + the Black Chamber, the precursor to the National + Security Agency. +%% +"Yow!! Those people look exactly like Donnie and Marie Osmond!!" + -- Zippy the Pinhead +%% +"My pants just went on a wild rampage through a Long Island Bowling Alley!!" + -- Zippy the Pinhead +%% +"Hello? Enema Bondage? I'm calling because I want to be happy, I guess..." + -- Zippy the Pinhead +%% +"I want to kill everyone here with a cute colorful Hydrogen Bomb!!" + -- Zippy the Pinhead +%% +"Yow! Am I in Milwaukee?" + -- Zippy the Pinhead +%% +"Yow! Am I having fun yet?" + -- Zippy the Pinhead +%% +"I didn't order any WOO-WOO... Maybe a YUBBA... But no WOO-WOO!" + -- Zippy the Pinhead +%% +"Didn't I buy a 1951 Packard from you last March in Cairo?" + -- Zippy the Pinhead +%% +"Yow! Did something bad happen or am I in a drive-in movie?" + -- Zippy the Pinhead +%% +"Yow! And then we could sit on the hoods of cars at stop lights!" + -- Zippy the Pinhead +%% +"...bleakness... desolation... plastic forks..." + -- Zippy the Pinhead +%% +"Yow! Is this sexual intercourse yet? Is it, huh, is it?" + -- Zippy the Pinhead +%% +"Is a tatoo real, like a curb or a battleship? +Or are we suffering in Safeway?" + -- Zippy the Pinhead +%% +"WHOA!! Ken and Barbie are having TOO MUCH FUN!! +It must be the NEGATIVE IONS!!" + -- Zippy the Pinhead +%% +"I'm ANN LANDERS!! I can SHOPLIFT!!" + -- Zippy the Pinhead +%% +"Did YOU find a DIGITAL WATCH in YOUR box of VELVEETA?" + -- Zippy the Pinhead +%% +"I have accepted Provolone into my life!" + -- Zippy the Pinhead +%% +"A can of ASPARAGUS, 73 pigeons, some LIVE ammo, and a FROZEN DAIQURI!!" + -- Zippy the Pinhead +%% +On the road, ZIPPY is a pinhead without +a purpose, but never without a POINT. +%% +"Yow! Now I get to think about all the BAD THINGS I did +to a BOWLING BALL when I was in JUNIOR HIGH SCHOOL!" + -- Zippy the Pinhead +%% +Hollerith, v: + What thou doest when thy phone is on the fritzeth. +%% +If God had a beard, he'd be a UNIX programmer. +%% +If you stick a stock of liquor in your locker, +It is slick to stick a lock upon your stock. +Or some joker who is slicker, +Will trick you of your liquor, +If you fail to lock your liquor with a lock. +%% +Fortune presents: + USEFUL PHRASES IN ESPERANTO, #1. + +^Cu vi parolas angle? Do you speak English? +Mi ne komprenas. I don't understand. +Vi estas la sola esperantisto kiun mi You're the only Esperanto speaker + renkontas. I've met. +La ^ceko estas enpo^stigita. The check is in the mail. +Oni ne povas, ^gin netrovi. You can't miss it. +Mi nur rigardadas. I'm just looking around. +Nu, ^sajnis bona ideo. Well, it seemed like a good idea. +%% +Fortune presents: + USEFUL PHRASES IN ESPERANTO, #2. + +^Cu tiu loko estas okupita? Is this seat taken? +^Cu vi ofte venas ^ci-tien? Do you come here often? +^Cu mi povas havi via telelonnumeron? May I have your phone number? +Mi estas komputilisto. I work with computers. +Mi legas multe da scienca fikcio. I read a lot of science fiction. +^Cu necesas ke vi eliras? Do you really have to be going? +%% +Fortune presents: + USEFUL PHRASES IN ESPERANTO, #3. + +Kie estas la plej proksima masa^gejo? Where's the nearest massage parlor? +Vi dolorigas min. You're hurting me. +Mi deziras viziti usonan kuraciston. I want to see an American doctor. +Mi deziras a^ceti kontraugraveda^jojn. I would like to buy some + contraceptives. +^Cu tiu estis ankau bona por ci? Was it good for you too? +%% +Fortune presents: + USEFUL PHRASES IN ESPERANTO, #4. +Mia ^svebo^sipo estas plena je angiloj. My hovercraft is full of eels. +Neniu anticipas la hispanan No one expects the Spanish + Inkvizicion. Inquisition. +La solvo estas kvardekdu. The answer is forty-two. +Adiau, kaj dankoj por ^ciom da fi^so. So long, and thanks for all the fish. +^Cu estas krajono en via po^so, au ^cu Is that a pencil in your pocket, + vi feli^cas pri vidi min? or are you happy to see me? +%% +I'd horsewhip you if I had a horse. + -- Groucho Marx +%% +Fortune presents: + USEFUL PHRASES IN ESPERANTO, #5. + +Mi ^cevalovipus vin se mi havus I'd horsewhip you if I had a horse. + ^cevalon. +Vere vi ^sercas. You must be kidding. +Nu, parDOOOOOnu min! Well exCUUUUUSE me! +Kiu invitis vin? Who invited you? +Kion vi diris pri mia patrino? What did you say about my mother? +Bu^so^stopu min per kulero. Gag me with a spoon. +%% +Love means having to say you're sorry every five minutes. +%% +Got a wife and kids in Baltimore Jack, +I went out for a ride and never came back. +Like a river that don't know where it's flowing, +I took a wrong turn and I just kept going. + + Everybody's got a hungry heart. + Everybody's got a hungry heart. + Lay down your money and you play your part, + Everybody's got a hungry heart. + +I met her in a Kingstown bar, +We fell in love, I knew it had to end. +We took what we had and we ripped it apart, +Now here I am down in Kingstown again. + +Everybody needs a place to rest, +Everybody wants to have a home. +Don't make no difference what nobody says, +Ain't nobody likes to be alone. + -- Bruce Springsteen, "Hungry Heart" +%% +All most men really want in life is a wife, a house, two kids and a car, +a cat, no maybe a dog. Ummm, scratch one of the kids and add a dog. +Definitely a dog. +%% + "I have examined Bogota," he said, "and the case is clearer to me. +I think very probably he might be cured." + "That is what I have always hoped," said old Yacob. + "His brain is affected," said the blind doctor. + The elders murmured assent. + "Now, what affects it?" + "Ah!" said old Yacob. + "This," said the doctor, answering his own question. "Those queer +things that are called the eyes, and which exist to make an agreeable soft +depression in the face, are diseased, in the case of Bogota, in such a way +as to affect his brain. They are greatly distended, he has eyelashes, and +his eyelids move, and cosequently his brain is in a state of constant +irritation and distraction." + "Yes?" said old Yacob. "Yes?" + "And I think I may say with reasonable certainty that, in order +to cure him completely, all that we need do is a simple and easy surgical +operation - namely, to remove those irritant bodies." + "And then he will be sane?" + "Then he will be perfectly sane, and a quite admirable citizen." + "Thank heaven for science!" said old Yacob. + -- H.G. Wells, "The Country of the Blind" +%% +The only thing that stops God from sending +another flood is that the first one was useless. + -- Chamfort +%% +Life being what it is, one dreams of revenge. + -- Gauguin +%% +Housework can kill you if done right. + -- Erma Bombeck +%% +A man always remembers his first love with special +tenderness, but after that begins to bunch them. + -- Mencken +%% +Sex is good, but not as good as fresh sweet corn. + -- Garrison Keillor +%% +The happiest time in any man's life +is just after the first divorce. + -- Galbraith +%% +Never lend your car to anyone to whom you have given birth. + -- Erma Bombeck +%% +The volume of paper expands to fill the available briefcases. + -- Jerry Brown +%% +Business is a good game -- lots of competition +and minimum of rules. You keep score with money. + -- Nolan Bushnell, founder of Atari +%% +The opposite of talking isn't listening. +The opposite of talking is waiting. + -- Fran Liebowitz +%% +In Mexico we have a word for sushi: bait. + -- Josi Simon +%% +The trouble with eating Italian food is that +five or six days later you're hungry again. + -- George Miller +%% +Marriage is not merely sharing the fettucine, but sharing the +burden of finding the fettucine restaurant in the first place. + -- Calvin Trillin +%% +The trouble with heart disease is that the first +symptom is often hard to deal with: death. + -- Michael Phelps +%% +A male gynecologist is like an auto mechanic who has never owned a car. + -- Carrie Snow +%% +When I was young we didn't have MTV; we +had to take drugs and go to concerts. + -- Steven Pearl +%% +I believe that professional wrestling is clean +and everything else in the world is fixed. + -- Frank Deford, sports writer +%% +There is nothing more exhilarating than to be shot at without result. + -- Churchill +%% +A team effort is a lot of people doing what I say. + -- Michael Winner, British film director +%% +It's our fault. We should have given him better parts. + -- Jack Warner, on hearing that Reagan had been + elected governor of California. + +[Warner is also reported to have said, when told of Reagan's candidacy +for governor, "No, Jimmy Stewart for Governor; Reagan for best friend."] +%% +There are three rules for writing a novel. +Unfortunately, no one knows what they are. + -- Maugham +%% +All newspaper editorial writers ever do is come down from +the hills after the battle is over and shoot the wounded. +%% +I can mend the break of day, heal a broken heart, +and provide temporary relief to nymphomaniacs. + -- Larry Lee +%% +I can't believe that out of 100,000 sperm, you were the quickest. + -- Steven Pearl +%% +Only Irish coffee provides in a single glass all four +essential food groups -- alcohol, caffeine, sugar, and fat. + -- Alex Levine + +[Oh come on, everybody knows that the four basic food groups are +hot sugar, cold sugar, carbohydrates and grease. Ed.] +%% +The astronomer Francesco Sizi, a contemporary of Galileo, argues that +Jupiter can have no satellites: + + There are seven windows in the head, two nostrils, two ears, two +eyes, and a mouth; so in the heavens there are two favorable stars, two +unpropitious, two luminaries, and Mercury alone undecided and indifferent. +From which and many other similar phenomena of nature such as the seven +metals, etc., which it were tedious to enumerate, we gather that the number +of planets is necessarily seven. [...] + Moreover, the satellites are invisible to the naked eye and +therefore can have no influence on the earth and therefore would be useless +and therefore do not exist. +%% +I was appalled by this story of the destruction of a member of a valued +endangered species. It's all very well to celebrate the practicality of +pigs by ennobling the porcine sibling who constructed his home out of +bricks and mortar. But to wantonly destroy a wolf, even one with an +excessive taste for porkers, is unconscionable in these ecologically +critical times when both man and his domestic beasts continue to maraud +the earth. + Sylvia Kamerman, "Book Reviewing" +%% +As part of an ongoing effort to keep you, the Fortune reader, abreast of +the valuable information the daily crosses the USENET, Fortune presents: + +News articles that answer *your* questions, #1: + + Newsgroups: comp.sources.d + Subject: how do I run C code received from sources + Keywords: C sources + Distribution: na + + I do not know how to run the C programs that are posted in the + sources newsgroup. I save the files, edit them to remove the + headers, and change the mode so that they are executable, but I + cannot get them to run. (I have never written a C program before.) + + Must they be compiled? With what compiler? How do I do this? If + I compile them, is an object code file generated or must I generate + it explicitly with the > character? Is there something else that + must be done? +%% +Do you believe in intuition? +No, but I have a strange feeling that someday I will. +%% +The number of UNIX installations has grown to 10, with more expected. + -- The Unix Programmer's Manual, 2nd Edition, June 1972 +%% +My advice to you, my violent friend, is to seek out gold and sit on it. + -- The Dragon to Grendel, in John Gardner's "Grendel" +%% +My mother once said to me, "Elwood," (she always called me Elwood) +"Elwood, in this world you must be oh so smart or oh so pleasant." +For years I tried smart. I recommend pleasant. + -- Elwood P. Dowde, "Harvey" +%% + It is a profoundly erroneous truism, repeated by all copy-books and +by eminent people when they are making speeches, that we should cultivate +the habit of thinking about what we are doing. The precise opposite is the +case. Civilization advances by extending the numbers of important operations +which we can perform without thinking about them. Operations of thought are +like cavalry charges in battle -- they are strictly limited in number, they +require fresh horses, and must only be made at decisive moments. + -- Alfred North Whitehead +%% +I try to keep an open mind, but not so open that my brains fall out. + -- Judge Harold T. Stone +%% + Approaching the gates of the monastery, Hakuin found Ken the Zen +preaching to a group of disciples. + "Words..." Ken orated, "they are but an illusory veil obfuscating +the absolute reality of --" + "Ken!" Hakuin interrupted. "Your fly is down!" + Whereupon the Clear Light of Illumination exploded upon Ken, and he +vaporized. + On the way to town, Hakuin was greeted by an itinerant monk imbued +with the spirit of the morning. + "Ah," the monk sighed, a beatific smile wrinkling across his cheeks, +"Thou art That..." + "Ah," Hakuin replied, pointing excitedly, "And Thou art Fat!" + Whereupon the Clear Light of Illumination exploded upon the monk, +and he vaporized. + Next, the Governor sought the advice of Hakuin, crying: "As our +enemies bear down upon us, how shall I, with such heartless and callow +soldiers as I am heir to, hope to withstand the impending onslaught?" + "US?" snapped Hakuin. + Whereupon the Clear Light of Illumination exploded upon the +Governor, and he vaporized. + Then, a redneck went up to Hakuin and vaporized the old Master with +his shotgun. "Ha! Beat ya' to the punchline, ya' scrawny li'l geek!" +%% +You can always tell the people that are forging the new +frontier. They're the ones with arrows sticking out of them. +%% +Pascal is a language for children wanting to be naughty. + -- Dr. Kasi Ananthanarayanan +%% +There is a limit to the admiration we may hold for a man who spends +his waking hours poking the contents of chickens with a stick. + -- Tom Robbins, "Jitterbug Perfume" +%% +Hell, if you don't try to remake someone, +how are they supposed to know you care? +%% +What's this stuff about people being "released on their +own recognizance"? Aren't we all out on own recognizance? +%% +The best case: Get salary from America, build a house in England, + live with a Japanese wife, and eat Chinese food. +Pretty good case: Get salary from England, build a house in America, + live with a Chinese wife, and eat Japanese food. +The worst case: Get salary from China, build a house in Japan, + live with a British wife, and eat American food. + + --Bungei Shunju, a popular Japanese magazine +%% +Once Again From the Top + +Correction notice in the Miami Herald: "Last Sunday, The Herald erroneously +reported that original Dolphin Johnny Holmes had been an insurance salesman +in Raleigh, North Carolina, that he had won the New York lottery in 1982 and +lost the money in a land swindle, that he had been charged with vehicular +homicide, but acquitted because his mother said she drove the car, and that +he stated that the funniest thing he ever saw was Flipper spouting water on +George Wilson. Each of these items was erroneous material published +inadvertently. He was not an insurance salesman in Raleigh, did not win the +lottery, neither he nor his mother was charged or involved in any way with +vehicular homicide, and he made no comment about Flipper or George Wilson. +The Herald regrets the errors." + -- "The Progressive", March, 1987 +%% +DEC diagnostics would run on a dead whale. + -- Mel Ferentz +%% +A pain in the ass of major dimensions. + -- C.A. Desoer, on the solution of non-linear circuits +%% +Reality must take precedence over public +relations, for Mother Nature cannot be fooled. + -- R.P. Feynman +%% +"The jig's up, Elman." +"Which jig?" + -- Jeff Elman +%% +As you will see, I told them, in no uncertain terms, to see Figure one. + -- Dave "First Strike" Pare +%% +CF&C stole it, fair and square. + -- Tim Hahn +%% +You'd best be snoozin', 'cause you don't +be gettin' no work done at 5 am anyway. + -- From the wall of the Wurster Hall stairwell +%% +He's like a function -- he returns a value, in the form of +his opinion. It's up to you to cast it into a void or not. + -- Phil Lapsley +%% +The purpose of Physics 7A is to make the engineers realize that they're +not perfect, and to make the rest of the people realize that they're not +engineers. +%% +We warn the reader in advance that the proof presented here +depends on a clever but highly unmotivated trick. + -- Howard Anton, "Elementary Linear Algebra" +%% +If Machiavelli were a hacker, he'd have worked for the CSSG. + -- Phil Lapsley +%% +Sendmail may be safely run set-user-id to root. + -- Eric Allman, "Sendmail Installation Guide" +%% +It is not that polar co-ordinates are complicated, it is simply +that cartesian co-ordinates are simpler than they have a right to be. + -- Kleppner & Kolenhow, "An Introduction to Mechanics" +%% +Opiates are the religion of the upper-middle classes. + -- Debbie VanDam +%% +This generation doesn't have emotional baggage. +We have emotional moving vans. + -- Bruce Feirstein +%% +Sudden Death Dating: + +Quote, female: + Am I worried about taking his last name? Forget it, + at this point I'll take his first name, too. +%% + As a general rule of thumb, never trust anybody who's been +in therapy for more than 15 percent of their life span. The words +"I am sorry" and "I am wrong" will have totally disappeared from +their vocabulary. They will stab you, shoot you, break things in +your apartment, say horrible things to your friends and family, and +then justify this abhorrent behavior by saying: + "Sure, I put your dog in the microwave. But I feel *better* +for doing it." + -- Bruce Feirstein, "Nice Guys Sleep Alone" +%% +Sex is a biological function; kissing is a committment. +%% +Don't get mad, get even. + -- Joseph P. Kennedy + +Don't get even, get jewelry. + -- Anon. +%% +Don't get even, get odd. +%% +Some people live life in the fast lane. +You're in oncoming traffic. +%% +Ankh if you love Isis. +%% +You mean you didn't *know* she was off +making lots of little phone companies? +%% +Avoid cliches like the plague. +They're a dime a dozen. +%% +Beam me up, Scotty! It ate my phaser! +%% +The beauty of a pun is in the "Oy!" of the beholder. +%% +Bushydo -- the way of the shrub. Bonsai! +%% +Cthulhu Cthucks! +%% +Cthulhu Saves -- in case He's hungry later. +%% +Cthulhu for President! +(If you're tired of choosing the lesser of two evils.) +%% +I *knew* I had some reason for not logging you off... +If I could just remember what it was. +%% +The best thing about being bald is, that, when unexpected +company arrives, all you have to do is straighten your tie. +%% +Pandora's Rule: + Never open a box you didn't close. +%% +The groundhog is like most other prophets; +it delivers its message and then disappears. +%% +Death before dishonor. +But neither before breakfast. +%% +Hatcheck girl: + "Goodness! What lovely diamonds!" +Mae West: + "Goodness had nothin' to do with it, dearie." + -- "Night After Night", 1932 +%% +Adding sound to movies would be like +putting lipstick on the Venus de Milo. + -- actress Mary Pickford, 1925 +%% +T-shirt: + Life is *not* a Cabaret, and stop calling me chum! +%% + "You mean, if you allow the master to be uncivil, to treat you +any old way he likes, and to insult your dignity, then he may deem you +fit to hear his view of things?" + "Quite the contrary. You must defend your integrity, assuming +you have integrity to defend. But you must defend it nobly, not by +imitating his own low behavior. If you are gentle where he is rough, +if you are polite where he is uncouth, then he will recognize you as +potentially worthy. If he does not, then he is not a master, after all, +and you may feel free to kick his ass." + -- Tom Robbins, "Jitterbug Perfume" +%% +Love ain't nothin' but sex misspelled. +%% +A bachelor is a man who never made the same mistake once. +%% +A bachelor is an unaltared male. +%% +A flashy Mercedes-Benz roared up to the curb where a cute young miss stood +waiting for a taxi. + "Hi," said the gentleman at the wheel. "I'm going west." + "How wonderful," came the cool reply. "Bring me back an orange." +%% +A friend with weed is a friend indeed. +%% +A joint is just tea for two. +%% +If God hadn't wanted you to be paranoid, +He wouldn't have given you such a vivid imagination. +%% +If it has syntax, it isn't user-friendly. +%% +If puns were deli meat, this would be the wurst. +%% +If the government doesn't trust the people, why +doesn't it dissolve them and elect a new people? +%% +If you're going to walk on thin ice, you might as well dance. +%% +Interfere? Of course you should interfere! +Always do what you're best at, I say. +%% +It's never too late to have a happy childhood. +%% +Militant agnostic: I don't know, and you don't either. +%% +Marvelous! The super-user's going to boot me! +What a finely tuned resopnse to the situation! +%% +No matter how cynical you get, it's impossible to keep up. +%% +No man is an island if he's on at least one mailing list. +%% +Of course you can't flap your arms and fly to the moon. +After awhile you'd run out of air to push against. +%% +Only two of my personalities are schizophrenic, but one +of them is paranoid and the other one is out to get him. +%% +Please do not look directly into laser with remaining eye. +%% +A real friend isn't someone you use once and then throw away. +A real friend is someone you can use over and over again. +%% +Sushido, n: + The way of the tuna. +%% +Total strangers need love, too; and I'm stranger than most. +%% +The unfacts, did we have them, are too +imprecisely few to warrant out certitude. +%% +We'll know that rock is dead when you have to get a degree to work in it. +%% +When Cthulhu calls, he calls collect. +%% +Mathematicians stand on each other's shoulders. + -- Gauss + +Mathemeticians stand on each other's shoulders while +computer scientists stand on each other's toes. + -- Richard Hamming + +It has been said that physicists stand on one another's shoulders. +If this is the case, then programmers stand on one another's toes, +and software engineers dig each other's graves. + -- Unknown +%% +FEAR: + What you feel when you see a U-Haul with Texas license plates. +%% +You can fool some of the people all of the time and all +of the people some of the time, but you can never fool your Mom. +%% +I want to marry a girl just like the girl that married dear old dad. + -- Freud +%% +PROBLEM DRINKER: + A man who never buys. +%% +Pyro's of the world... IGNITE !!! +%% + Seems George was playing his usual eighteen holes on Saturday +afternoon. Teeing off from the 17th, he sliced into the rough over near +the edge of the fairway. Just as he was about to chip out, he noticed a +long funeral procession going past on a nearby street. Reverently, George +removed his hat and stood at attention until the procession had passed. +Then he continued his game, finishing with a birdie on the eighteenth. +Later, at the clubhouse, a fellow golfer greet George. "Say, that was a +nice gesture you made today, George. + "What do you mean?" asked George. + "Well, it was nice of you to take off your cap and stand +respectfully when that funeral went by," the friend replied. + "Oh, yes," said George. "Well, we were married 17 years, you +know." +%% +The father, passing through his son's college town late one evening on a +business trip, thought he would pay his boy a suprise visit. Arriving at the +lad's fraternity house, dad rapped loudly on the door. After several minutes +of knocking, a sleepy voice drifted down from a second-floor window, + "Whaddaya want?" + "Does Ramsey Duncan live here?" asked the father. + "Yeah," replied the voice. "Dump him on the front porch." +%% +The meek don't want it. +%% + There was a knock on the door. Mrs. Miffin opened it. "Are +you the Widow Miffin?" a small boy asked. + "I'm Mrs. Miffin," she replied, "but I'm not a widow." + "Oh, no?" replied the little boy. "Wait 'til you see what +they're carrying upstairs!" +%% +A bachelor is a man who never made the same mistake once. +%% +A bachelor is an unaltared male. +%% +A flashy Mercedes-Benz roared up to the curb where a cute young miss stood +waiting for a taxi. + "Hi," said the gentleman at the wheel. "I'm going west." + "How wonderful," came the cool reply. "Bring me back an orange." +%% +A friend with weed is a friend indeed. +%% +A joint is just tea for two. +%% +A pretty foot is one of the greatest gifts of nature... please send me your +last pair of shoes, already worn out in dancing... so I can have something of +yours to press against my heart. + -- Goethe +%% +Behold the unborn foetus and + Weep salt tears crocodilian; +All life is sacred (save, of course, + An enemy civilian). +%% +Blessed are the meek for they shall inhibit the earth. +%% +Blow it out your ear. +%% +COLORADO: + Where they don't buy M & M's, 'cause they're so hard to peel. +%% +Cocaine is nature's way of telling you you have too much money. +%% +%% +A beer delayed is a beer denied. +%% +If you don't drink it, someone else will. +%% +I don't care what star you're following; +get that camel out of my front yard! +%% +"Your son still sliding down the banisters?" +"We wound barbed wire around them." +"That stop him?" +"No, but it sure slowed him up." +%% +Destiny is a good thing to accept when it's going your way. When it isn't, +don't call it destiny; call it injustice, treachery, or simple bad luck. + -- Joseph Heller, "God Knows" +%% +Having a baby isn't so bad. If you're a female Emperor penguin +in the Antarctic. She lays the egg, rolls it over to the father, +then takes off for warmer weather where she eats and eats and +eats. For two months, the father stands stiff, without food, +blind in the 24-hour dark, balancing the egg on his feet. After +the little penguin is hatched, the mother sees fit to come home. + -- L.M. Boyd, "Austin American-Statesman" +%% +It's hard not to like a man of many qualities, +even if most of them are bad. +%% +Remember, DESSERT is spelled with two `s's while DESERT is spelled +with one, because EVERYONE wants two desserts, but NO ONE wants two +deserts. + -- Miss Oglethorp, Gr. 5, PS 59 +%% +4.2 BSD UNIX #57: Sun Jun 1 23:02:07 EDT 1986 + +You swing at the Sun. You miss. The Sun swings. He hits you with a +575MB disk! You read the 575MB disk. It is written in an alien +tongue and cannot be read by your tired Sun-2 eyes. You throw the +575MB disk at the Sun. You hit! The Sun must repair your eyes. The +Sun reads a scroll. He hits your 130MB disk! He has defeated the +130MB disk! The Sun reads a scroll. He hits your Ethernet board! He +has defeated your Ethernet board! You read a scroll of "postpone until +Monday at 9 AM". Everything goes dark... + -- /etc/motd, cbosgd +%% +The UNIX philosophy basically involves giving you enough rope to +hang yourself. And then a couple of feet more, just to be sure. +%% +I know the answer! The answer lies within the heart of all mankind! +The answer is twelve? I think I'm in the wrong building. + -- Charles Schulz +%% +Life is what happens while you are making other plans. + -- John Lennon +%% +Dying is one of the few things that can be done as easily lying down. + -- Woody Allen +%% +In the long run we are all dead. + -- John Maynard Keynes +%% +Death is nature's way of saying `Howdy'. +%% +For three days after death hair and fingernails +continue to grow, but phone calls taper off. + -- Johnny Carson +%% +If once a man indulges himself in murder, very soon he comes to think +little of robbing; and from robbing he next comes to drinking and +Sabbath-breaking, and from that to incivility and procrastination. + -- Thomas De Quincey +%% +The difference between genius and stupidity +is that genius has its limits. +%% +Egotist, n: + A person ... more interested in himself than in me. + -- Ambrose Bierce +%% +A narcissist is someone better looking than you are. + -- Gore Vidal +%% +Don't be humble. You're not that great. + -- Golda Meir +%% +Somewhere on this globe, every ten seconds, there is a +woman giving birth to a child. She must be found and stopped. + -- Sam Levenson +%% +There's nothing wrong with teenagers that +reasoning with them won't aggravate. +%% +When all else fails, pour a pint of Guinness in the gas tank, advance +the spark 20 degrees, cry "God Save the Queen!", and pull the starter +knob. + -- MG "Series MGA" Workshop Manual +%% +The meek shall inherit the Earth. +(But they're gonna have to fight for it...) +%% +War doesn't prove who's right, just who's left. +%% +Just what does "it" mean in the sentence, "What time is it?" +%% +It's not a sin not to be Irish, but it is a great shame. + -- Sean O'Huiginn +%% +May those that love us love us; and those that don't love us, may +God turn their hearts; and if he doesn't turn their hearts, may +he turn their ankles so we'll know them by their limping. +%% +The curse of the Irish is not that they don't know the +words to a song -- it's that they know them *all*. + -- Susan Dooley +%% +St. Patrick was a gentleman +who through strategy and stealth +drove all the snakes from Ireland. +Here's a toasting to his health -- +but not too many toastings +lest you lose yourself and then +forget the good St. Patrick +and see all those snakes again. +%% +May you have warm words on a cold evening, +a full mooon on a dark night, +and a smooth road all the way to your door. +%% +It has long been noticed that juries are pitiless for robbery and full of +indulgence for infanticide. A question of interest, my dear Sir! The jury +is afraid of being robbed and has passed the age when it could be a victim +of infanticide. + -- Edmond About +%% +Marriage, in life, is like a duel in the midst of a battle. + -- Edmond About +%% +A memorandum is written not to inform the reader, +but to protect the writer. + -- Dean Acheson +%% +The danger is not that a particular class is unfit to govern. +Every class is unfit to govern. + -- Lord Acton +%% +The trouble with this country is that there are too many politicians +who believe, with a conviction based on experience, that you can fool +all of the people all of the time. + -- Franklin Adams +%% +When a man you like switches from what he said a year ago, or four years +ago, he is a broad-minded man who has courage enough to change his mind +with changing conditions. When a man you don't like does it, he is a +liar who has broken his promises. + -- Franklin Adams +%% +Politics, as a practice, whatever its professions, has always been the +systematic organisation of hatreds. + -- Henry Adams, "The Education of Henry Adams" +%% +Practical politics consists in ignoring facts. + -- Henry Adams +%% +The most popular labor-saving device today is still a husband with money. + -- Joey Adams +%% +A psychiatrist is a fellow who asks you a lot of expensive questions +your wife asks you for nothing. + -- Joey Adams +%% +Men who cherish for women the highest +respect are seldom popular with them. + -- Joseph Addison +%% +If it were not for the presents, an elopment would be preferable. + -- George Ade, "Forty Modern Fables" +%% +It is easier to fight for one's principles than to live up to them. + -- Alfred Adler +%% +The English instinctively admire any man +who has no talent and is modest about it. + -- James Agate, British film and drama critic +%% +The way to a man's heart is through his +wife's belly, and don't you forget it. + -- Edward Albee, "Who's Afraid of Virginia Woolf?" +%% +The avocation of assessing the failures of better men can be turned +into a comfortable livelihood, providing you back it up with a Ph.D. + -- Nelson Algren, "Writers at Work" +%% +A racially integrated community is a chronological term timed from +the entrance of the first black family to the exit of the last white +family. + -- Saul Alinsky +%% +California is a fine place to live in -- if you're an orange. + -- Fred Allen +%% +A conference is a gathering of important people who singly can +do nothing but together can decide that nothing can be done. + -- Fred Allen +%% +Imitation is the sincerest form of television. + -- Fred Allen +%% +Look, we trade every day out there with hustlers, deal-makers, shysters, +con-men. That's the way businesses get started. That's the way this +country was built. + -- Hubert Allen +%% +Love is the answer, but while you are waiting for the answer, sex +raises some pretty good questions. + -- Woody Allen +%% +Life is a concentration camp. You're stuck here and there's no way +out and you can only rage impotently against your persecutors. + -- Woody Allen +%% +Is sex dirty? Only if it's done right. + -- Woody Allen, "All You Ever Wanted To Know About Sex" +%% +In California they don't throw their garbadge away -- they make +it into television shows. + -- Woody Allen, "Annie Hall" +%% +Life is divided into the horrible and the miserable. + -- Woody Allen, "Annie Hall" +%% +It seemed the world was divided into good and bad people. The good ones +slept better... while the bad ones seemed to enjoy the waking hours much +more. + -- Woody Allen, "Side Effects" +%% +More than any other time in history, mankind faces a crossroads. One path +leads to despair and utter hopelessness. The other, to total extinction. +Let us pray we have the wisdom to choose correctly. + -- Woody Allen, "Side Effects" +%% +Don't knock masturbation -- it's sex with someone I love. + -- Woody Allen +%% +Gratitude, like love, is never a dependable international emotion. + -- Joseph Alsop +%% +What's a cult? It just means not enough people to make a minority. + -- Robert Altman +%% +In any country there must be people who have to die. They are the +sacrifices any nation has to make to achieve law and order. + -- Idi Amin Dada +%% +Most plain girls are virtuous because of the scarcity of opportunity +to be otherwise. + -- Maya Angelou, "I Know Why the Caged Bird Sings" +%% +Children's talent to endure stems from their ignorance of alternatives. + -- Maya Angelou, "I Know Why the Caged Bird Sings" +%% +Oh, love is real enough, you will find it some day, but it has one +arch-enemy -- and that is life. + -- Jean Anouilh, "Ardele" +%% +Every man thinks God is on his side. The rich +and powerful know that he is. + -- Jean Anouilh, "The Lark" +%% +Experience is a good teacher, but she sends in terrific bills. + -- Minna Antrim, "Naked Truth and Veiled Allusions" +%% +It's amazing how nice people are to you when they know you're going away. + -- Michael Arlen +%% +The state of innocence contains the germs of all future sin. + -- Alexandre Arnoux, "Etudes et caprices" +%% +What passes for optimism is most often the effect of an intellectual error. + -- Raymond Aron, "The Opium of the Intellectuals" +%% +There is a good deal of solemn cant about the common interests of capital +and labour. As matters stand, their only common interest is that of cutting +each other's throat. + -- Brooks Atkinson, "Once Around the Sun" +%% +No poet or novelist wishes he was the only one who ever lived, but most of +them wish they were the only one alive, and quite a number fondly believe +their wish has been granted. + -- W.H. Auden, "The Dyer's Hand" +%% +Money cannot buy +The fuel of love +but is excellent kindling. + +To the man-in-the-street, who, I'm sorry to say, +Is a keen observer of life, +The word intellectual suggests right away +A man who's untrue to his wife. + -- W.H. Auden, "Collected Shorter Poems" +%% +A little inaccuracy saves a world of explanation. + -- C.E. Ayres +%% +Diplomacy is to do and say, the nastiest thing in the nicest way. + -- Balfour +%% +Mathematics is the only science where one never knows what +one is talking about nor whether what is said is true. + -- Russell +%% +Art is Nature speeded up and God slowed down. + -- Chazal +%% +I'm going to raise an issue and stick it in your ear. + -- John Foreman +%% +To understand the heart and mind of a person, look not at what +he has already achieved, but at what he aspires to do. +%% +Science and religion are in full accord but +science and faith are in complete discord. +%% +Before Xerox, five carbons were the maximum extension of anybody's ego. +%% +I will not be briefed or debriefed, my underwear is my own. +%% +Subtlety is the art of saying what you think +and getting out of the way before it is understood +%% +I've finally learned what 'upward compatible' means. +It means we get to keep all our old mistakes. + -- Dennie van Tassel +%% +Mathematicians are like Frenchmen: whatever you say to them they +translate into their own language and forthwith it is something +entirely different. + -- Goethe +%% +The Second Law of Thermodynamics: + If you think things are in a mess now, just wait! + -- Jim Warner +%% +Computer Science is the only discipline in which we view +adding a new wing to a building as being maintenance + -- Jim Horning +%% +Don't remember what you can infer. + -- Harry Tennant +%% +In case of fire, stand in the hall and shout "Fire!" + -- The Kidner Report +%% +Never tell people how to do things. Tell them WHAT to +do and they will surprise you with their ingenuity. + -- Gen. George S. Patton, Jr. +%% +Eternity is a terrible thought. I mean, where's it going to end? + -- Tom Stoppard +%% +If God had really intended men to fly, +he'd make it easier to get to the airport. + -- George Winters +%% +I have more humility in my little finger +than you have in your whole BODY! + -- Cerebus, #82 +%% +Five is a sufficiently close approximation to infinity. + -- Robert Firth +%% +brain-damaged, generalization of "Honeywell Brain Damage" (HBD), a +theoretical disease invented to explain certain utter cretinisms in +Multics, adj: + Obviously wrong; cretinous; demented. There is an implication + that the person responsible must have suffered brain damage, + because he/she should have known better. Calling something + brain-damaged is bad; it also implies it is unusable. +%% +feature, n: + A surprising property of a program. Occasionaly documented. To + call a property a feature sometimes means the author did not + consider that case, and the program makes an unexpected, though + not necessarily wrong response. See BUG. "That's not a bug, it's + a feature!" A bug can be changed to a feature by documenting it. +%% +Ferguson's Precept: + A crisis is when you can't say "let's forget the whole thing." +%% +If fifty million people say a foolish thing, it's still a foolish thing. + -- Bertrand Russell +%% +Rune's Rule: + If you don't care where you are, you ain't lost. +%% +He was the sort of person whose personality +would be greatly improved by a terminal illness. +%% +Style may not be the answer, but at least it's a workable alternative. +%% +To be trusted is a greater compliment than to be loved. +%% +To err is human, but when the eraser wears out +before the pencil, you're overdoing it a little. +%% +Wad some power the giftie gie us +To see oursels as others see us. + -- R. Browning +%% +I don't mind arguing with myself. +Its when I lose that it bothers me. + -- Richard Powers +%% +Beware of all enterprises that require new clothes. + -- Thoreau +%% +Time is an illusion; lunch-time doubly so. + -- Ford Prefect +%% +Much of the excitement we get out of our work +is that we don't really know what we are doing. + -- E. Dijkstra +%% +"First World" nations are the ones where people drive Japanese cars; +"Second World" nations are where First World residents go on vacation; +and "Third World" nations are the ones where people still dive out of +trees to prove their manhood. + -- Dave Barry +%% +When you die, you lose a very important part of your life. + -- Brooke Shields +%% +Between infinite and short there is a big difference. + -- G.H. Gonnet +%% +%% +Breadth-first search is the bulldozer of science. + -- Randy Goebel +%% +If I'm over the hill, why is it I don't recall ever being on top? + -- Jerry Muscha +%% +Nirvana? That's the place where the powers +that be and their friends hang out. + -- Zonker Harris +%% + "What are you doing?" + "Examining the world's major religions. I'm looking for something +that's light on morals, has lots of holidays, and with a short initiation +period." +%% +"A wizard cannot do everything; a fact most magicians are recticent to admit, +let alone discuss with prospective clients. Still, the fact remains that +there are certain objects, and people, that are, for one reason or another, +completely immune to any direct magical spell. It is for this group of +beings that the magician learns the subtleties of using indirect spells. +It also does no harm, in dealing with these matters, to carry a large club +near your person at all times." + -- The Teachings of Ebenezum, Volume VIII +%% +"There are those who claim that magic is like the tide; that it swells and +fades over the surface of the earth, collecting in concentrated pools here +and there, almost disappearing from other spots, leaving them parched for +wonder. There are also those who believe that if you stick your fingers up +your nose and blow, it will increase your intelligence." + -- The Teachings of Ebenezum, Volume VII +%% +What we do not understand we do not possess. + -- Goethe +%% +It is common sense to take a method and try it. If it fails, admit +it frankly and try another. But above all, try something. + -- Franklin D. Roosevelt +%% +Egotism is the anesthetic which numbs the pain of stupidity. +%% +Therefore it is necessary to learn how not to be good, and to use +this knowledge and not use it, according to the necessity of the cause. + -- Machiavelli +%% +A woman did what a woman had to, the best way she knew how. +To do more was impossible, to do less, unthinkable. + -- Dirisha, "The Man Who Never Missed" +%% +If you took all of the grains of sand in the world, and lined +them up end to end in a row, you'd be working for the government! + -- Mr. Interesting +%% +All I want is a warm bed and a kind word and unlimited power. + -- Ashleigh Brilliant +%% +Somehow I reached excess without ever noticing +when I was passing through satisfaction. + -- Ashleigh Brilliant +%% +That is the true season of love, when we believe that we alone can love, +that no one could have loved so before us, and that no one will love +in the same way as us. + -- Johann Wolfgang von Goethe +%% +A dream will always triumph over reality, once it is given the chance. + -- Stanislaw Lem +%% +Justice, n: + A decision in your favor. +%% +You first parents of the human race... who ruined yourself for +an apple, what might you not have done for a truffled turkey? + -- Brillat-Savarin +%% +A prohibitionist is the sort of man one wouldn't care to +drink with -- even if he drank. + -- Mencken +%% +I can give you my word, but I know what it's worth and you don't. + -- Nero Wolfe, "Over My Dead Body" +%% +Fame may be fleeting but obscurity is forever. +%% +Viking, n: + 1. Daring Scandinavian seafarers, explorers, adventurers, + entrepreneurs world-famous for their aggressive, nautical import + business, highly leveraged takeovers and blue eyes. + 2. Bloodthirsty sea pirates who ravaged northern Europe beginning + in the 9th century. + +Hagar's note: The first definition is much preferred; the second is used +only by malcontents, the envious, and disgruntled owners of waterfront +property. +%% +Write a wise saying and your name will live forever. + -- Anonymous +%% +Knights are hardly worth it. +I mean, all that shell and so little meat... +%% +Rule #7: Silence is not acquiescence. + Contrary to what you may have heard, silence of those present is +not necessarily consent, even the reluctant variety. They simply may +sit in stunned silence and figure ways of sabotaging the plan after they +regain their composure. +%% +Do you mean that you not only want a wrong +answer, but a certain wrong answer? + -- Tobaben +%% +The problem that we thought was a problem was, indeed, +a problem, but not the problem we thought was the problem. + -- Mike Smith +%% +The tree of research must from time to time +be refreshed with the blood of bean counters. + -- Alan Kay +%% +By working faithfully eight hours a day, +you may eventually get to be boss and work twelve. + -- Robert Frost +%% +The worst part of having success is trying +to find someone who is happy for you. + -- Bette Midler +%% +I've got all the money I'll ever need if I die by 4 o'clock. + -- Henny Youngman +%% +The Puritan hated bear-baiting, not because it gave pain to +the bear, but because it gave pleasure to the spectators. + -- Macaulay, "History of England, I" +%% +What good is an obscenity trial except to popularize literature? + -- Nero Wolfe, "The League of Frightened Men" +%% +Come, landlord, fill the flowing bowl until it does run over, +Tonight we will all merry be -- tomorrow we'll get sober. + -- John Fletcher, "The Bloody Brother", II, 2 +%% +There be sober men a'plenty, and drunkards barely twenty; there are men +of over ninety who have never yet kissed a girl. But give me the rambling +rover, from Orkney down to Dover, we will roam the whole world over, and +together we'll face the world. + -- Andy Stewart, "After the Hush" +%% +Dignity is like a flag. +It flaps in a storm. + -- Roy Mengot +%% +The only winner in the War of 1812 was Tchaikovsky. + -- David Gerrold +%% +The explanation requiring the fewest assumptions +is the most likely to be correct. + -- William of Occam +%% +It must be remembered that there is nothing more difficult to plan, +more doubtful of success, nor more dangerous to manage, than the +creation of a new system. For the initiator has the emnity of all +who would profit by the preservation of the old institutions and +merely lukewarm defenders in those who would gain by the new ones. + -- Niccolo Machiavelli, 1513 +%% +Gil-galad was an Elven-King +of him the harpers sadly sing; +the last whose realm was fair and free +between the Mountains and the Sea. + +His sword was long, his lance was keen, +his shining helm afar was seen; +the countless stars of heaven's field +were mirrored in his silver shield. + +But long ago he rode away, +and where he dwelleth none can say; +for into darkness fell his star +in Mordor where the shadows are. +%% +It is possible by ingenuity and at the expense of clarity... {to +do almost anything in any language}. However, the fact that it is +possible to push a pea up a mountain with your nose does not mean +that this is a sensible way of getting it there. Each of these +techniques of language extension should be used in its proper place. + -- Christopher Strachey +%% +Truth is the most valuable thing we have -- so let us economize it. + -- Mark Twain +%% +Nothing is more admirable than the fortitude with which +millionaires tolerate the disadvantages of their wealth. + -- Nero Wolfe +%% +HISTORY: Papa Hegel he say that all we learn from history is that we +learn nothing from history. I know people who can't even learn from +what happened this morning. Hegel must have been taking the long view. + -- "The Hipcrime Vocab", Chad C. Mulligan +%% + "...The name of the song is called 'Haddocks' Eyes'!" + "Oh, that's the name of the song, is it?" Alice said, trying to +feel interested. + "No, you don't understand," the Knight said, looking a little +vexed. "That's what the name is called. The name really is, 'The Aged +Aged Man.'" + "Then I ought to have said "That's what the song is called'?" +Alice corrected herself. + "No, you oughtn't: that's quite another thing! The song is +called 'Ways and Means': but that's only what it is called you know!" + "Well, what is the song then?" said Alice, who was by this +time completely bewildered. + "I was coming to that," the Knight said. "The song really is +"A-sitting on a Gate": and the tune's my own invention." + --Lewis Carroll, "Through the Looking Glass" +%% +If I set here and stare at nothing long enough, +people might think I'm an engineer working on something. + -- S.R. McElroy +%% +When in doubt, have a man come through the door with a gun in his hand. + -- Raymond Chandler +%% +Chapter 1: + The story so far: + In the beginning the Universe was created. This has made +a lot of people very angry and been widely regarded as a bad move. +%% +"I only touch base with reality on an as-needed basis!" +%% +Repartee is something we think of twenty-four hours too late. + -- Mark Twain +%% +I often quote myself; it adds spice to my conversation. + -- Shaw +%% +The real purpose of books is to trap the mind into doing its own thinking. + -- Christopher Morley +%% +I took a course in speed reading, learning to read straight down +the middle of the page, and I was able to go through "War and Peace" +in twenty minutes. It's about Russia. + -- Woody Allen +%% +It is all right to hold a conversation, +but you should let go of it now and then. + -- Richard Armour +%% +Now I lay me back to sleep. +The speaker's dull; the subject's deep. +If he should stop before I wake, +Give me a nudge for goodness' sake. + -- Anonymous +%% +Passion is that funny feeling that drives a man to +bite a woman's neck because she has beautiful legs. +%% + The problem with engineers is that they tend to +cheat in order to get results. + The problem with mathematicians is that they tend +to work on toy problems in order to get results + The problem with program verifiers is that they tend +to cheat at toy problems in order to get results. +%% +Never hit a man with glasses; hit him with your fist. +%% +Ninety percent of the time things turn out worse than you thought they +would. The other ten percent of the time you had no right to expect +that much. + -- Augustine +%% +Responsibility: + Everyone says that having power is a great responsibility. This is +a lot of bunk. Responsibility is when someone can blame you if something +goes wrong. When you have power you are surrounded by people whose job it +is to take the blame for your mistakes. If they're smart, that is. + -- Cerebus, "On Governing" +%% +Anything is possible on paper. + -- Ron McAfee +%% +We are each only one drop in a great +ocean -- but some of the drops sparkle! +%% +An Ada exception is when a routine gets +in trouble and says 'Beam me up, Scotty'. +%% +Large increases in cost with questionable increases in +performance can be tolerated only in race horses and women. + -- Lord Kalvin +%% +Well, some take delight in the carriages a-rolling, +And some take delight in the hurling and the bowling, +But I take delight in the juice of the barley, +And courting pretty fair maids in the morning bright and early. +%% +Just remember, wherever you go, there you are. + -- Buckeroo Banzai +%% +I value kindness to human beings first of all, and kindness to animals. I +don't respect the law; I have a total irreverence for anything connected +with society except that which makes the roads safer, the beer stronger, +the food cheaper, and old men and womem warmer in the winter, and happier +in the summer. + -- Brendan Behan +%% +A woman shouldn't have to buy her own perfume. + -- Maurine Lewis +%% +The Celts invented two things, Whiskey and self-distruction. +%% +Ye've also got to remember that ... respectable people do the most +astonishin' things to preserve their respectability. Thank God +I'm not respectable. + -- Ruthven Campbell Todd +%% +Say it with flowers, +Or say it with mink, +But whatever you do, +Don't say it with ink! + -- Jimmie Durante +%% +Love to eat them mousies; +Mousies what I love to eat. +Bite they tiny heads off, +Nibble on they tiny feet! + -- Kilban +%% +Nice boy, but about as sharp as a sack of wet mice. + -- Foghorn Leghorn +%% +The streets were dark with something more than night. + -- Raymond Chandler +%% + Insofar as I may be heard by anything, which may or may not care +what I say, I ask, if it matters, that you be forgiven for anything you +may have done or failed to do which requires forgiveness. Conversely, if +not forgiveness but something else may be required to insure any possible +benefit for which you may be eligible after the destruction of your body, +I ask this, whatever it may be, be granted or withheld, as the case may be, +in such a manner as to insure your receiving said benefit. I ask this in my +capacity as your elected intermediary between yourself and that which may +not be yourself, but which may have an interest in the matter of your +receiving as much as it is possible for you to receive of this thing, and +which may in some way be influenced by this ceremony. + Amen. +%% +The best laid plans of mice and men +are held up in the legal department. +%% +No group of professionals meets except to +conspire against the public at large. + -- Mark Twain +%% +One thing about the past. +It's likely to last. + -- Ogden Nash +%% +Luck can't last a lifetime, unless you die young. + -- Russell Banks +%% +Nothing ever becomes real till it is experienced -- even a +proverb is no proverb to you till your life has illustrated it. + -- John Keats +%% +Simulations are like miniskirts, they show a lot and hide the essentials. + -- Hubert Kirrman +%% +The last thing one knows in constructing a work is what to put first. + -- Blaise Pascal +%% +If you cannot in the long run tell everyone +what you have been doing, your doing was worthless. + -- Edwim Schrodinger +%% +I don't want to achieve immortality through my works. +I want to achieve immortality through not dying. + -- Woody Allen +%% +A sequel is an admission that you've been reduced to imitating yourself. + -- Don Marquis +%% +If you want to get rich from writing, write the sort of thing that's +read by persons who move their lips when the're reading to themselves. + -- Don Marquis +%% +It took me fifteen years to discover that I had no talent for writing, +but I couldn't give it up because by that time I was too famous. + -- Robert Benchley +%% +God is REAL unless declared INTEGER. +%% +There are many intelligent species in +the universe, and they all own cats. +%% +I would rather say that a desire to drive fast +sports cars is what sets man apart from the animals. +%% +If you sow your wild oats, hope for a crop failure. +%% +Girls are better looking in snowstorms. + -- Archie Goodwin +%% +You must know that a man can have only one invulnerable loyalty, loyalty +to his own concept of the obligations of manhood. All other loyalties +are merely deputies of that one. + -- Nero Wolfe +%% +On the road, ZIPPY is a pinhead without a purpose, but never without a POINT. +%% +WHOA!! Ken and Barbie are having TOO MUCH FUN!! +It must be the NEGATIVE IONS!! +%% + God decided to take the devil to court and settle their +differences once and for all. + When Satan heard of this, he grinned and said, "And just +where do you think you're going to find a lawyer?" +%% + A lawyer named Strange was shopping for a tombstone. After he had +made his selection, the stonecutter asked him what inscription he +would like on it. "Here lies an honest man and a lawyer," responded the +lawyer. + "Sorry, but I can't do that," replied the stonecutter. "In this +state, it's against the law to bury two people in the same grave. However, +I could put ``here lies an honest lawyer'', if that would be okay." + "But that won't let people know who it is" protested the lawyer. + "Certainly will," retorted the stonecutter. "people will read it +and exclaim, "That's Strange!" +%% +History has much to say on following the proper procedures. From a history +of the Mexican revolution: + + "Hildago was later defeated at Guadalajara. The rebel army was +captured on is way through the mountains. All were courtmartialed and +shot, except Hildago, because he was a priest. He was handed over to +the bishop of Durango who excommunicated him and returned him to the +army where he was then executed." +%% +We're Knights of the Round Table +We dance whene'er we're able We're knights of the Round Table +We do routines and chorus scenes Our shows are formidable +With footwork impeccable But many times +We dine well here in Camelot We're given rhymes +We eat ham and jam and Spam a lot. That are quite unsingable + We're opera mad in Camelot + We sing from the diaphragm a lot. +In war we're tough and able, +Quite indefatigable +Between our quests +We sequin vests +And impersonate Clark Gable +It's a busy life in Camelot. +I have to push the pram a lot. + -- Monty Python +%% + And St. Attila raised the hand grenade up on high saying "O Lord +bless this thy hand grenade that with it thou mayest blow thine enemies +to tiny bits, in thy mercy" and the Lord did grin and the people did feast +upon the lambs and sloths and carp and anchovies and orang-utangs and +breakfast cereals and fruit bats and... + (skip a bit brother...) + Er ... oh, yes ... and the Lord spake, saying "First shalt thou +take out the Holy Pin, then shalt thou count to three, no more, no less. +Three shall be the number thou shalt count, and the number of the count +shall be three. Four shalt thou not count neither count thou two, excepting +that thou then proceed to three. Five is right out. Once the number +three, being the third number, be reached then lobbest thou thy Holy Hand +Grenade of Antioch towards thy foe, who being naught in my sight, shall +snuff it. + -- Monty Python, "The Book of Armaments" +%% +Fog Lamps, n: + Excessively (often obnoxiously) bright lamps mounted on the fronts + of automobiles; used on dry, clear nights to indicate that the + driver's brain is in a fog. See also "Idiot Lights". +%% +Don't drop acid -- take it pass/fail. + -- Seen in a Ladies Room at Harvard +%% +I just got out of the hospital after a +speed reading accident. I hit a bookmark. + -- S. Wright +%% +I finally went to the eye doctor. I got contacts. +I only need them to read, so I got flip-ups. + -- S. Wright +%% +I have a box of telephone rings under my bed. Whenever I get lonely, I +open it up a little bit, and I get a phone call. One day I dropped the +box all over the floor. The phone wouldn't stop ringing. I had to get +it disconnected. So I got a new phone. I didn't have much money, so I +had to get an irregular. It doesn't have a five. I ran into a friend +of mine on the street the other day. He said why don't you give me a +call. I told him I can't call everybody I want to anymore, my phone +doesn't have a five. He asked how long had it been that way. I said I +didn't know -- my calendar doesn't have any sevens. + -- S. Wright +%% +I am getting into abstract painting. Real abstract - no brush, no +%% +I woke up one morning and found that everything in my apartment had been +stolen and replaced with an exact duplicate. I called up a friend of mine, +told him this. He said, "Do I know you?" + -- S. Wright +%% +I am getting into abstract painting. Real abstract -- no brush, no +canvas, I just think about it. I just went to an art museum where +all of the art was done by children. All the paintings were hung on +refridgerators. + -- S. Wright +%% +He asked me if I knew what time it was -- I said yes, but not right now. + -- S. Wright +%% +I got tired of listening to the recording on the phone at the movie +theater. So I bought the album. I got kicked out of a theater the +other day for bringing my own food in. I argued that the concession +stand prices were outrageous. Besides, I hadn't had a barbecue in a +long time. I went to the theater and the sign said adults $5 children +$2.50. I told them I wanted 2 boys and a girl. I once took a cab to +a drive-in movie. The movie cost me $95. + -- S. Wright +%% +I was at this restaurant. The sign said "Breakfast Anytime." So I +ordered French Toast in the Rennaissance. + -- S. Wright +%% +I was in Vegas last week. I was at the roulette table, having a +lengthy argument about what I considered an Odd number. + -- S. Wright +%% +I got this powdered water -- now I don't know what to add. + -- S. Wright +%% +I poured spot remover on my dog. Now he's gone. + -- S. Wright +%% +Go away. I'm all right. + -- H.G. Wells' last words +%% +I used to work in a fire hydrant factory. You couldn't +park anywhere near the place. + -- Steven Wright +%% +World War III is about to break out, but hidden somewhere in Switzerland, +a small group of international statesmen are trying to avert disaster. +The key members of this group are the representatives from Moscow, Bonn, and +Jerusalem, who, despite their personal enmity, manage to forge a peaceful +settlement, at the last moment. As the treaty is signed, and the war +postponed, almost entirely through the efforts of those three men, an angel +appears. "The earth is saved through the efforts of these three men! +Therefore, I will grant each of them their heart's desire!" + So, the angel asks the German for his wish, and the German, recalling +the nearness of their disaster, and perceiving the cause to have been the +Russians, immediately says "I wish there were no more Russians!" And God +said, "It will be done." + The angel asks the Russian for his wish, which, of course, is "*I* +wish there were no more Germans!" Replies the angel, "It will be done." + So the angel asks the Jew for his wish. The Jew is in a state of +shock. "Will you really grant the German's wish?" he asks, and the angel +avers. "And the Russian's, too?" The angel avers yet again. Then the Jew +thinks a moment, leans back and says, "In that case, I think I'd like a small +cup of coffee." +%% +An Aggie farmer was lifting his hogs, one by one, up to the branches of +his apple trees to graze on the apples. A Texas student walked by and +asked him, "Doesn't that take a lot of time?" + Replied the Aggie, "What's time to a hog?" +%% diff --git a/src/games/fortune/scene.4.3 b/src/games/fortune/scene.4.3 new file mode 100644 index 0000000..f7ccdbf --- /dev/null +++ b/src/games/fortune/scene.4.3 @@ -0,0 +1,9761 @@ +!07/11 PDP a ni deppart m'I !pleH +%% +(1) Alexander the Great was a great general. +(2) Great generals are forewarned. +(3) Forewarned is forearmed. +(4) Four is an even number. +(5) Four is certainly an odd number of arms for a man to have. +(6) The only number that is both even and odd is infinity. + +Therefore, Alexander the Great had an infinite number of arms. +%% +(1) Everything depends. +(2) Nothing is always. +(3) Everything is sometimes. +%% +$100 invested at 7% interest for 100 years will become $100,000, at +which time it will be worth absolutely nothing. + -- Lazarus Long, "Time Enough for Love" +%% +101 USES FOR A DEAD MICROPROCESSOR + (1) Scarecrow for centipedes + (2) Dead cat brush + (3) Hair barrettes + (4) Cleats + (5) Self-piercing earrings + (6) Fungus trellis + (7) False eyelashes + (8) Prosthetic dog claws + . + . + . + (99) Window garden harrow (pulled behind Tonka tractors) + (100) Killer velcro + 101. Currency +%% +186,282 miles per second: + +It isn't just a good idea, it's the law! +%% +$3,000,000 +%% +355/113 -- Not the famous irrational number PI, but an incredible +simulation! +%% +43rd Law of Computing: + Anything that can go wr +fortune: Segmentation violation -- Core dumped +%% +77. HO HUM -- The Redundant + +------- (7) This hexagram refers to a situation of extreme +--- --- (8) boredom. Your programs always bomb off. Your wife +------- (7) smells bad. Your children have hives. You are working +---O--- (6) on an accounting system, when you want to develop +---X--- (9) the GREAT AMERICAN COMPILER. You give up hot dates +--- --- (8) to nurse sick computers. What you need now is sex. + +Nine in the second place means: + The yellow bird approaches the malt shop. Misfortune. + +Six in the third place means: + In former times men built altars to honor the Internal + Revenue Service. Great Dragons! Are you in trouble! +%% +99 blocks of crud on the disk, +99 blocks of crud! +You patch a bug, and dump it again: +100 blocks of crud on the disk! + +100 blocks of crud on the disk, +100 blocks of crud! +You patch a bug, and dump it again: +101 blocks of crud on the disk! ... +%% +A baby is an alimentary canal with a loud voice at one end and no +responsibility at the other. +%% +A bachelor is a selfish, undeserving guy who has cheated some woman +out of a divorce. + -- Don Quinn +%% +A banker is a fellow who lends you his umbrella when the sun is shining +and wants it back the minute it begins to rain. + -- Mark Twain +%% +A billion here, a couple of billion there -- first thing you know it +adds up to be real money. + -- Everett McKinley Dirksen +%% +A bird in the bush usually has a friend in there with him. +%% +A bird in the hand is worth what it will bring. +%% +A bore is someone who persists in holding his own views after we have +enlightened him with ours. +%% +A budget is just a method of worrying before you spend money, as well +as afterward. +%% +A candidate is a person who gets money from the rich and votes from the +poor to protect them from each other. +%% +A celebrity is a person who is known for his well-knownness. +%% +A chubby man with a white beard and a red suit will approach you soon. +Avoid him. He's a Commie. +%% +A city is a large community where people are lonesome together + -- Herbert Prochnow +%% +A classic is something that everybody wants to have read and nobody +wants to read. + -- Mark Twain +%% +A closed mouth gathers no foot. +%% +A computer, to print out a fact, +Will divide, multiply, and subtract. + But this output can be + No more than debris, +If the input was short of exact. + -- Gigo +%% +A conclusion is simply the place where someone got tired of thinking. +%% +A CONS is an object which cares. + -- Bernie Greenberg. +%% +A countryman between two lawyers is like a fish between two cats. + -- Ben Franklin +%% +A crusader's wife slipped from the garrison +And had an affair with a Saracen. + She was not oversexed, + Or jealous or vexed, +She just wanted to make a comparison. +%% +A day for firm decisions!!!!! Or is it? +%% +A day without sunshine is like night. +%% +A diplomat is a man who can convince his wife she'd look stout in a +fur coat. +%% +A diplomat is someone who can tell you to go to hell in such a way that +you will look forward to the trip. +%% + A disciple of another sect once came to Drescher as he was +eating his morning meal. "I would like to give you this personality +test", said the outsider, "because I want you to be happy." + Drescher took the paper that was offered him and put it into +the toaster -- "I wish the toaster to be happy too". +%% +A diva who specializes in risqu'e arias is an off-coloratura soprano ... +%% + A doctor, an architect, and a computer scientist were arguing +about whose profession was the oldest. In the course of their +arguments, they got all the way back to the Garden of Eden, whereupon +the doctor said, "The medical profession is clearly the oldest, because +Eve was made from Adam's rib, as the story goes, and that was a simply +incredible surgical feat." + The architect did not agree. He said, "But if you look at the +Garden itself, in the beginning there was chaos and void, and out of +that, the Garden and the world were created. So God must have been an +architect." + The computer scientist, who had listened to all of this said, +"Yes, but where do you think the chaos came from?" +%% +A door is what a dog is perpetually on the wrong side of. + -- Ogden Nash +%% +A dozen, a gross, and a score, +Plus three times the square root of four, + Divided by seven, + Plus five time eleven, +Equals nine squared plus zero, no more. +%% +A famous Lisp Hacker noticed an Undergraduate sitting in front of a +Xerox 1108, trying to edit a complex Klone network via a browser. +Wanting to help, the Hacker clicked one of the nodes in the network +with the mouse, and asked "what do you see?" Very earnestly, the +Undergraduate replied "I see a cursor." The Hacker then quickly pressed +the boot toggle at the back of the keyboard, while simultaneously +hitting the Undergraduate over the head with a thick Interlisp Manual. +The Undergraduate was then Enlightened. +%% +A fanatic is one who can't change his mind and won't change the +subject. + -- Winston Churchill +%% +A fool must now and then be right by chance. +%% +A fool's brain digests philosophy into folly, science into +superstition, and art into pedantry. Hence University education. + -- G. B. Shaw +%% +A fool-proof method for sculpting an elephant: first, get a huge block +of marble; then you chip away everything that doesn't look like an +elephant. +%% +A formal parsing algorithm should not always be used. + -- D. Gries +%% +A gleekzorp without a tornpee is like a quop without a fertsneet (sort +of). +%% +A great many people think they are thinking when they are merely +rearranging their prejudices. + -- William James +%% +A lack of leadership is no substitute for inaction. +%% +A lady with one of her ears applied +To an open keyhole heard, inside, +Two female gossips in converse free -- +The subject engaging them was she. +"I think", said one, "and my husband thinks +That she's a prying, inquisitive minx!" +As soon as no more of it she could hear +The lady, indignant, removed her ear. +"I will not stay," she said with a pout, +"To hear my character lied about!" + -- Gopete Sherany +%% +A language that doesn't affect the way you think about programming is +not worth knowing. +%% +A language that doesn't have everything is actually easier to program +in than some that do. + -- Dennis M. Ritchie +%% +A large number of installed systems work by fiat. That is, they work +by being declared to work. + -- Anatol Holt +%% +A Law of Computer Programming: + Make it possible for programmers to write in English and you + will find the programmers cannot write in English. +%% +A limerick packs laughs anatomical +Into space that is quite economical. + But the good ones I've seen + So seldom are clean, +And the clean ones so seldom are comical. +%% +A LISP programmer knows the value of everything, but the cost of +nothing. +%% +A long-forgotten loved one will appear soon. Buy the negatives at any +price. +%% +A lot of people I know believe in positive thinking, and so do I. I +believe everything positively stinks. + -- Lew Col +%% + A man goes to a tailor to try on a new custom-made suit. The +first thing he notices is that the arms are too long. + "No problem," says the tailor. "Just bend them at the elbow +and hold them out in front of you. See, now it's fine." + "But the collar is up around my ears!" + "It's nothing. Just hunch your back up a little ... no, a +little more ... that's it." + "But I'm stepping on my cuffs!" the man cries in desperation. + "Nu, bend you knees a little to take up the slack. There you +go. Look in the mirror -- the suit fits perfectly." + So, twisted like a pretzel, the man lurches out onto the +street. Reba and Florence see him go by. + "Oh, look," says Reba, "that poor man!" + "Yes," says Florence, "but what a beautiful suit." + -- Arthur Naiman, "Every Goy's Guide to Yiddish" +%% +A man said to the Universe: "Sir, I exist!" + +"However," replied the Universe, "the fact has not created in me a +sense of obligation." + -- Stephen Crane +%% +A man wrapped up in himself makes a very small package. +%% +A mathematician is a machine for converting coffee into theorems. +%% + A musician of more ambition than talent composed an elegy at +the death of composer Edward MacDowell. She played the elegy for the +pianist Josef Hoffman, then asked his opinion. "Well, it's quite +nice," he replied, but don't you think it would be better if ..." + "If what?" asked the composer. + "If ... if you had died and MacDowell had written the elegy?" +%% +A new dramatist of the absurd +Has a voice that will shortly be heard. + I learn from my spies + He's about to devise +An unprintable three-letter word. +%% +A new koan: + + If you have some ice cream, I will give it to you. + + If you have no ice cream, I will take it away from you. + +It is an ice cream koan. +%% +A new supply of round tuits has arrived and are available from Mary. +Anyone who has been putting off work until they got a "round tuit" now +has no excuse for further procrastination. +%% +A nuclear war can ruin your whole day. +%% +A penny saved is ridiculous. +%% +A person is just about as big as the things that make them angry. +%% +A physicist is an atom's way of knowing about atoms. + -- George Wald +%% +A pig is a jolly companion, +Boar, sow, barrow, or gilt -- +A pig is a pal, who'll boost your morale, +Though mountains may topple and tilt. +When they've blackballed, bamboozled, and burned you, +When they've turned on you, Tory and Whig, +Though you may be thrown over by Tabby and Rover, +You'll never go wrong with a pig, a pig, +You'll never go wrong with a pig! + -- Thomas Pynchon, "Gravity's Rainbow" +%% + A Plan for the Improvement of English Spelling + by Mark Twain + + For example, in Year 1 that useless letter "c" would be dropped +to be replased either by "k" or "s", and likewise "x" would no longer +be part of the alphabet. The only kase in which "c" would be retained +would be the "ch" formation, which will be dealt with later. Year 2 +might reform "w" spelling, so that "which" and "one" would take the +same konsonant, wile Year 3 might well abolish "y" replasing it with +"i" and Iear 4 might fiks the "g/j" anomali wonse and for all. + Jenerally, then, the improvement would kontinue iear bai iear +with Iear 5 doing awai with useless double konsonants, and Iears 6-12 +or so modifaiing vowlz and the rimeining voist and unvoist konsonants. +Bai Iear 15 or sou, it wud fainali bi posibl tu meik ius ov thi +ridandant letez "c", "y" and "x" -- bai now jast a memori in the maindz +ov ould doderez -- tu riplais "ch", "sh", and "th" rispektivli. + Fainali, xen, aafte sam 20 iers ov orxogrefkl riform, wi wud +hev a lojikl, kohirnt speling in ius xrewawt xe Ingliy-spiking werld. +%% +A priest asked: What is Fate, Master? + +And he answered: + +It is that which gives a beast of burden its reason for existence. + +It is that which men in former times had to bear upon their backs. + +It is that which has caused nations to build byways from City to City +upon which carts and coaches pass, and alongside which inns have come +to be built to stave off Hunger, Thirst and Weariness. + +And that is Fate? said the priest. + +Fate ... I thought you said Freight, responded the Master. + +That's all right, said the priest. I wanted to know what Freight was +too. + -- Kehlog Albran, "The Profit" +%% + A priest was walking along the cliffs at Dover when he came +upon two locals pulling another man ashore on the end of a rope. +"That's what I like to see", said the priest, "A man helping his fellow +man". + As he was walking away, one local remarked to the other, "Well, +he sure doesn't know the first thing about shark fishing." +%% +A professor is one who talks in someone else's sleep. +%% +"A programmer is a person who passes as an exacting expert on the basis +of being able to turn out, after innumerable punching, an infinite +series of incomprehensive answers calculated with micrometric +precisions from vague assumptions based on debatable figures taken from +inconclusive documents and carried out on instruments of problematical +accuracy by persons of dubious reliability and questionable mentality +for the avowed purpose of annoying and confounding a hopelessly +defenseless department that was unfortunate enough to ask for the +information in the first place." + -- IEEE Grid newsmagazine +%% +A psychiatrist is a person who will give you expensive answers that +your wife will give you for free. +%% +A real patriot is the fellow who gets a parking ticket and rejoices +that the system works. +%% +A real person has two reasons for doing anything ... a good reason and +the real reason. +%% +A recent study has found that concentrating on difficult off-screen +objects, such as the faces of loved ones, causes eye strain in computer +scientists. Researchers into the phenomenon cite the added +concentration needed to "make sense" of such unnatural three +dimensional objects ... +%% +A rock pile ceases to be a rock pile the moment a single man +contemplates it, bearing within him the image of a cathedral. + -- Antoine de Saint-Exupery +%% + A Severe Strain on the Credulity + +As a method of sending a missile to the higher, and even to the highest +parts of the earth's atmospheric envelope, Professor Goddard's rocket +is a practicable and therefore promising device. It is when one +considers the multiple-charge rocket as a traveler to the moon that one +begins to doubt ... for after the rocket quits our air and really +starts on its journey, its flight would be neither accelerated nor +maintained by the explosion of the charges it then might have left. +Professor Goddard, with his "chair" in Clark College and countenancing +of the Smithsonian Institution, does not know the relation of action to +re-action, and of the need to have something better than a vacuum +against which to react ... Of course he only seems to lack the +knowledge ladled out daily in high schools. + -- New York Times Editorial, 1920 +%% +A sine curve goes off to infinity or at least the end of the blackboard + -- Prof. Steiner +%% +A solemn, unsmiling, sanctimonious old iceberg who looked like he was +waiting for a vacancy in the Trinity. + -- Mark Twain +%% +A straw vote only shows which way the hot air blows. + -- O'Henry +%% +A student who changes the course of history is probably taking an +exam. +%% +A successful tool is one that was used to do something undreamed of by +its author. + -- S. C. Johnson +%% +A total abstainer is one who abstains from everything but abstention, +and especially from inactivity in the affairs of others. + -- Ambrose Bierce, "The Devil's Dictionary" +%% +A transistor protected by a fast-acting fuse will protect the fuse by +blowing first. +%% +A truly wise man never plays leapfrog with a unicorn. +%% +A university is what a college becomes when the faculty loses interest +in students. + -- John Ciardi +%% +A UNIX saleslady, Lenore, +Enjoys work, but she likes the beach more. + She found a good way + To combine work and play: +She sells C shells by the seashore. +%% +A vacuum is a hell of a lot better than some of the stuff that nature +replaces it with. + -- Tenessee Williams +%% +A very intelligent turtle +Found programming UNIX a hurdle + The system, you see, + Ran as slow as did he, +And that's not saying much for the turtle. +%% +A well adjusted person is one who makes the same mistake twice without +getting nervous. +%% +"A witty saying proves nothing." + -- Voltaire +%% +A year spent in artificial intelligence is enough to make one believe +in God. +%% +A.A.A.A.A.: + An organization for drunks who drive +%% +AAAAAAAAAaaaaaaaaaaaaaaaccccccccckkkkkk!!!!!!!!! +You brute! Knock before entering a ladies room! +%% +Abandon the search for Truth; settle for a good fantasy. +%% +About the time we think we can make ends meet, somebody moves the +ends. + -- Herbert Hoover +%% +Absence makes the heart go wander. +%% +Absent, adj.: + Exposed to the attacks of friends and acquaintances; defamed; +slandered. +%% +Absentee, n.: + A person with an income who has had the forethought to remove +himself from the sphere of exaction. + -- Ambrose Bierce, "The Devil's Dictionary" +%% +Abstainer, n.: + A weak person who yields to the temptation of denying himself a +pleasure. + -- Ambrose Bierce, "The Devil's Dictionary" +%% +Absurdity, n.: + A statement or belief manifestly inconsistent with one's own +opinion. + -- Ambrose Bierce, "The Devil's Dictionary" +%% +Accident, n.: + A condition in which presence of mind is good, but absence of +body is better. +%% +Accidents cause History. + +If Sigismund Unbuckle had taken a walk in 1426 and met Wat Tyler, the +Peasant's Revolt would never have happened and the motor car would not +have been invented until 2026, which would have meant that all the oil +could have been used for lamps, thus saving the electric light bulb and +the whale, and nobody would have caught Moby Dick or Billy Budd. + -- Mike Harding, "The Armchair Anarchist's Almanac" +%% +According to my best recollection, I don't remember. + -- Vincent "Jimmy Blue Eyes" Alo +%% +According to the latest official figures, 43% of all statistics are +totally worthless. +%% +Accordion, n.: + A bagpipe with pleats. +%% +Accuracy, n.: + The vice of being right +%% +Acid -- better living through chemistry. +%% +Acid absorbs 47 times it's weight in excess Reality. +%% +Acquaintance, n.: + A person whom we know well enough to borrow from, but not well +enough to lend to. + -- Ambrose Bierce, "The Devil's Dictionary" +%% +"Acting is an art which consists of keeping the audience from +coughing." +%% +Actor: "I'm a smash hit. Why, yesterday during the last act, I had + everyone glued in their seats!" +Oliver Herford: "Wonderful! Wonderful! Clever of you to think of + it!" +%% +Actor: So what do you do for a living? +Doris: I work for a company that makes deceptively shallow serving + dishes for Chinese restaurants. + -- Woody Allen, "Without Feathers" +%% +ADA, n.: + Something you need only know the name of to be an Expert in +Computing. Useful in sentences like, "We had better develop an ADA +awareness." +%% +Admiration, n.: + Our polite recognition of another's resemblance to ourselves. + -- Ambrose Bierce, "The Devil's Dictionary" +%% +Adolescence, n.: + The stage between puberty and adultery. +%% +"Adopted kids are such a pain -- you have to teach them how to look +like you ..." + --- Gilda Radner +%% +Adore, v.: + To venerate expectantly. + -- Ambrose Bierce, "The Devil's Dictionary" +%% +Adult, n.: + One old enough to know better. +%% +After [Benjamin] Franklin came a herd of Electrical Pioneers whose +names have become part of our electrical terminology: Myron Volt, Mary +Louise Amp, James Watt, Bob Transformer, etc. These pioneers conducted +many important electrical experiments. For example, in 1780 Luigi +Galvani discovered (this is the truth) that when he attached two +different kinds of metal to the leg of a frog, an electrical current +developed and the frog's leg kicked, even though it was no longer +attached to the frog, which was dead anyway. Galvani's discovery led +to enormous advances in the field of amphibian medicine. Today, +skilled veterinary surgeons can take a frog that has been seriously +injured or killed, implant pieces of metal in its muscles, and watch it +hop back into the pond just like a normal frog, except for the fact +that it sinks like a stone. + -- Dave Barry, "What is Electricity?" +%% +After all, all he did was string together a lot of old, well-known +quotations. + -- H. L. Mencken, on Shakespeare +%% +After all, what is your hosts' purpose in having a party? Surely not +for you to enjoy yourself; if that were their sole purpose, they'd have +simply sent champagne and women over to your place by taxi. + -- P. J. O'Rourke +%% +After an instrument has been assembled, extra components will be found +on the bench. +%% + After his Ignoble Disgrace, Satan was being expelled from +Heaven. As he passed through the Gates, he paused a moment in thought, +and turned to God and said, "A new creature called Man, I hear, is soon +to be created." + "This is true," He replied. + "He will need laws," said the Demon slyly. + "What! You, his appointed Enemy for all Time! You ask for the +right to make his laws?" + "Oh, no!" Satan replied, "I ask only that he be allowed to make +his own." + It was so granted. + -- Ambrose Bierce, "The Devil's Dictionary" +%% +After I run your program, let's make love like crazed weasels, OK? +%% +After the last of 16 mounting screws has been removed from an access +cover, it will be discovered that the wrong access cover has been +removed. +%% +Afternoon very favorable for romance. Try a single person for a +change. +%% +Afternoon, n.: + That part of the day we spend worrying about how we wasted the +morning. +%% +Air is water with holes in it +%% +Alas, I am dying beyond my means. + -- Oscar Wilde, as he sipped champagne on his deathbed +%% +Albert Einstein, when asked to describe radio, replied: "You see, wire +telegraph is a kind of a very, very long cat. You pull his tail in New +York and his head is meowing in Los Angeles. Do you understand this? +And radio operates exactly the same way: you send signals here, they +receive them there. The only difference is that there is no cat." +%% +Aleph-null bottles of beer on the wall, +Aleph-null bottles of beer, + You take one down, and pass it around, +Aleph-null bottles of beer on the wall. +%% +Alex Haley was adopted! +%% +Alexander Graham Bell is alive and well in New York, and still waiting +for a dial tone. +%% +Alimony is a system by which, when two people make a mistake, one of +them keeps paying for it. + -- Peggy Joyce +%% +"All flesh is grass" + -- Isiah +Smoke a friend today. +%% +All I ask is a chance to prove that money can't make me happy. +%% +All I ask is a chance to prove that money can't make me happy. +%% +All I ask of life is a constant and exaggerated sense of my own +importance. +%% +"All my friends and I are crazy. That's the only thing that keeps us +sane." +%% +All programmers are playwrights and all computers are lousy actors. +%% +All progress is based upon a universal innate desire on the part of +every organism to live beyond its income. + -- Samuel Butler +%% +All science is either physics or stamp collecting. + -- E. Rutherford +%% +All the big corporations depreciate their possessions, and you can, +too, provided you use them for business purposes. For example, if you +subscribe to the Wall Street Journal, a business-related newspaper, you +can deduct the cost of your house, because, in the words of U.S. +Supreme Court Chief Justice Warren Burger in a landmark 1979 tax +decision: "Where else are you going to read the paper? Outside? What +if it rains?" + -- Dave Barry, "Sweating Out Taxes" +%% +"... all the modern inconveniences ..." + -- Mark Twain +%% +All the world's a stage and most of us are desperately unrehearsed. + -- Sean O'Casey +%% +All the world's a VAX, +And all the coders merely butchers; +They have their exits and their entrails; +And one int in his time plays many widths, +His sizeof being N bytes. At first the infant, +Mewling and puking in the Regent's arms. +And then the whining schoolboy, with his Sun, +And shining morning face, creeping like slug +Unwillingly to school. + -- A Very Annoyed PDP-11 +%% +All things are possible except skiing thru a revolving door. +%% +All true wisdom is found on T-shirts. +%% +All you have to do to see the accuracy of my thesis is look around +you. Look, in particular, at the people who, like you, are making +average incomes for doing average jobs -- bank vice presidents, +insurance salesman, auditors, secretaries of defense -- and you'll +realize they all dress the same way, essentially the way the mannequins +in the Sears menswear department dress. Now look at the real +successes, the people who make a lot more money than you -- Elton John, +Captain Kangaroo, anybody from Saudi Arabia, Big Bird, and so on. They +all dress funny -- and they all succeed. Are you catching on? + -- Dave Barry, "How to Dress for Real Success" +%% +Alliance, n.: + In international politics, the union of two thieves who have +their hands so deeply inserted in each other's pocket that they cannot +separately plunder a third. + -- Ambrose Bierce, "The Devil's Dictionary" +%% +Alone, adj.: + In bad company. + -- Ambrose Bierce, "The Devil's Dictionary" +%% +Although we modern persons tend to take our electric lights, radios, +mixers, etc., for granted, hundreds of years ago people did not have +any of these things, which is just as well because there was no place +to plug them in. Then along came the first Electrical Pioneer, +Benjamin Franklin, who flew a kite in a lighting storm and received a +serious electrical shock. This proved that lighting was powered by the +same force as carpets, but it also damaged Franklin's brain so severely +that he started speaking only in incomprehensible maxims, such as "A +penny saved is a penny earned." Eventually he had to be given a job +running the post office. + -- Dave Barry, "What is Electricity?" +%% +Always borrow money from a pessimist; he doesn't expect to be paid +back. +%% + AMAZING BUT TRUE ... + +If all the salmon caught in Canada in one year were laid end to end +across the Sahara Desert, the smell would be absolutely awful. +%% + AMAZING BUT TRUE ... + +There is so much sand in Northern Africa that if it were spread out it +would completely cover the Sahara Desert. +%% +Ambidextrous, adj.: + Able to pick with equal skill a right-hand pocket or a left. + -- Ambrose Bierce, "The Devil's Dictionary" +%% +Ambition is a poor excuse for not having sense enough to be lazy. + -- Charlie McCarthy +%% +America may be unique in being a country which has leapt from barbarism +to decadence without touching civilization. + -- John O'Hara +%% +America was discovered by Amerigo Vespucci and was named after him, +until people got tired of living in a place called "Vespuccia" and +changed its name to "America". + -- Mike Harding, "The Armchair Anarchist's Almanac" +%% +Amnesia used to be my favorite word, but then I forgot it. +%% +An American's a person who isn't afraid to criticize the President but +is always polite to traffic cops. +%% +An effective way to deal with predators is to taste terrible. +%% +An elephant is a mouse with an operating system. +%% +An Englishman never enjoys himself, except for a noble purpose. + -- A. P. Herbert +%% +An excellence-oriented '80s male does not wear a regular watch He wears +a Rolex watch, because it weighs nearly six pounds and is advertised +only in excellence-oriented publications such as Fortune and Rich +Protestant Golfer Magazine. The advertisements are written in +incomplete sentences, which is how advertising copywriters denote +excellence: + +"The Rolex Hyperion. An elegant new standard in quality excellence and +discriminating handcraftsmanship. For the individual who is truly able +to discriminate with regard to excellent quality standards of crafting +things by hand. Fabricated of 100 percent 24-karat gold. No watch +parts or anything. Just a great big chunk on your wrist. Truly a +timeless statement. For the individual who is very secure. Who +doesn't need to be reminded all the time that he is very successful. +Much more successful than the people who laughed at him in high +school. Because of his acne. People who are probably nowhere near as +successful as he is now. Maybe he'll go to his 20th reunion, and +they'll see his Rolex Hyperion. Hahahahahahahahaha." + -- Dave Barry, "In Search of Excellence" +%% +"... an experienced, industrious, ambitious, and often quite often +picturesque liar." + -- Mark Twain +%% +An idea is not responsible for the people who believe in it. +%% + An old Jewish man reads about Einstein's theory of relativity +in the newspaper and asks his scientist grandson to explain it to him. + "Well, zayda, it's sort of like this. Einstein says that if +you're having your teeth drilled without Novocain, a minute seems like +an hour. But if you're sitting with a beautiful woman on your lap, an +hour seems like a minute." + The old man considers this profound bit of thinking for a +moment and says, "And from this he makes a living?" + -- Arthur Naiman, "Every Goy's Guide to Yiddish" +%% +Anarchy may not be the best form of government, but it's better than no +government at all. +%% +... And malt does more than Milton can +To justify God's ways to man + -- A. E. Housman +%% +And on the seventh day, He exited from append mode. +%% +And this is a table ma'am. What in essence it consists of is a +horizontal rectilinear plane surface maintained by four vertical +columnar supports, which we call legs. The tables in this laboratory, +ma'am, are as advanced in design as one will find anywhere in the +world. + -- Michael Frayn, "The Tin Men" +%% + "And what will you do when you grow up to be as big as me?" +asked the father of his little son. + "Diet." +%% +Angels we have heard on High +Tell us to go out and Buy. + -- Tom Leher +%% +Ankh if you love Isis. +%% +Anoint, v.: + To grease a king or other great functionary already +sufficiently slippery. + -- Ambrose Bierce, "The Devil's Dictionary" +%% + Another Glitch in the Call + ------- ------ -- --- ---- + (Sung to the tune of a recent Pink Floyd song.) + +We don't need no indirection +We don't need no flow control +No data typing or declarations +Did you leave the lists alone? + + Hey! Hacker! Leave those lists alone! + +Chorus: + All in all, it's just a pure-LISP function call. + All in all, it's just a pure-LISP function call. +%% +Another good night not to sleep in a eucalyptus tree. +%% + Answers to Last Fortune's Questions: + +1. None. (Moses didn't have an ark). +2. Your mother, by the pigeonhole principle. +3. I don't know. +4. Who cares? +5. 6 (or maybe 4, or else 3). Mr. Alfred J. Duncan of Podunk, + Montana, submitted an interesting solution to Problem 5. +6. There is an interesting solution to this problem on page 1029 of my + book, which you can pick up for $23.95 at finer bookstores and + bathroom supply outlets (or 99 cents at the table in front of + Papyrus Books). +%% +Anthony's Law of Force: + Don't force it; get a larger hammer. +%% +Anthony's Law of the Workshop: + Any tool when dropped, will roll into the least accessible + corner of the workshop. + +Corollary: + On the way to the corner, any dropped tool will first strike + your toes. +%% +Antonym, n.: + The opposite of the word you're trying to think of. +%% +Any clod can have the facts, but having opinions is an art. + -- Charles McCabe +%% +Any excuse will serve a tyrant. + -- Aesop +%% +Any fool can paint a picture, but it takes a wise person to be able to +sell it. +%% +... Any resemblance between the above views and those of my employer, +my terminal, or the view out my window are purely coincidental. Any +resemblance between the above and my own views is non-deterministic. +The question of the existence of views in the absence of anyone to hold +them is left as an exercise for the reader. The question of the +existence of the reader is left as an exercise for the second god +coefficient. (A discussion of non-orthogonal, non-integral polytheism +is beyond the scope of this article.) +%% +Any small object that is accidentally dropped will hide under a +larger object. +%% +Any sufficiently advanced technology is indistinguishable from a rigged +demo. +%% +Any sufficiently advanced technology is indistinguishable from magic. + -- Arthur C. Clarke +%% +Any two philosophers can tell each other all they know in two hours. + -- Oliver Wendell Holmes, Jr. +%% +Any woman is a volume if one knows how to read her. +%% +Anybody can win, unless there happens to be a second entry. +%% +Anybody who doesn't cut his speed at the sight of a police car is +probably parked. +%% +Anybody with money to burn will easily find someone to tend the fire. +%% +Anyone can hold the helm when the sea is calm. + -- Publilius Syrus +%% +Anyone who cannot cope with mathematics is not fully human. At best he +is a tolerable subhuman who has learned to wear shoes, bathe and not +make messes in the house. + -- Lazarus Long, "Time Enough for Love" +%% +Anyone who goes to a psychiatrist ought to have his head examined. + -- Samuel Goldwyn +%% +Anyone who hates Dogs and Kids Can't be All Bad. + -- W. C. Fields +%% +Anyone who is capable of getting themselves made President should on no +account be allowed to do the job. + -- Douglas Adams, "The Hitchhiker's Guide to the Galaxy" +%% +Anything free is worth what you pay for it. +%% +Anything is good and useful if it's made of chocolate. +%% +Anything is good if it's made of chocolate. +%% +Anything labeled "NEW" and/or "IMPROVED" isn't. The label means the +price went up. The label "ALL NEW", "COMPLETELY NEW", or "GREAT NEW" +means the price went way up. +%% +Anything that is good and useful is made of chocolate. +%% +Anything worth doing is worth overdoing +%% +Anytime things appear to be going better, you have overlooked +something. +%% +Aquadextrous, adj.: + Possessing the ability to turn the bathtub faucet on and off +with your toes. + -- Rich Hall, "Sniglets" +%% + AQUARIUS (Jan 20 - Feb 18) +You have an inventive mind and are inclined to be progressive. You lie +a great deal. On the other hand, you are inclined to be careless and +impractical, causing you to make the same mistakes over and over +again. People think you are stupid. +%% +"Arguments with furniture are rarely productive." + -- Kehlog Albran, "The Profit" +%% + ARIES (Mar 21 - Apr 19) +You are the pioneer type and hold most people in contempt. You are +quick tempered, impatient, and scornful of advice. You are not very +nice. +%% +Arithmetic is being able to count up to twenty without taking off your +shoes. + -- Mickey Mouse +%% +Armadillo: + To provide weapons to a Spanish pickle +%% +Arnold's Laws of Documentation: + (1) If it should exist, it doesn't. + (2) If it does exist, it's out of date. + (3) Only documentation for useless programs transcends the + first two laws. +%% +Arthur's Laws of Love: + (1) People to whom you are attracted invariably think you + remind them of someone else. + (2) The love letter you finally got the courage to send will + be delayed in the mail long enough for you to make a fool + of yourself in person. +%% +Artistic ventures highlighted. Rob a museum. +%% +As far as the laws of mathematics refer to reality, they are not +certain; and as far as they are certain, they do not refer to reality. + -- Albert Einstein +%% +As far as we know, our computer has never had an undetected error. + -- Weisert +%% +As I was passing Project MAC, +I met a Quux with seven hacks. +Every hack had seven bugs; +Every bug had seven manifestations; +Every manifestation had seven symptoms. +Symptoms, manifestations, bugs, and hacks, +How many losses at Project MAC? +%% +As long as war is regarded as wicked, it will always have its +fascination. When it is looked upon as vulgar, it will cease to be +popular. + -- Oscar Wilde +%% +As of next week, passwords will be entered in Morse code. +%% +"As part of the conversion, computer specialists rewrote 1,500 +programs -- a process that traditionally requires some debugging." + --- USA Today, referring to the IRS switchover to a new + computer system. +%% +As soon as we started programming, we found to our surprise that it +wasn't as easy to get programs right as we had thought. Debugging had +to be discovered. I can remember the exact instant when I realized +that a large part of my life from then on was going to be spent in +finding mistakes in my own programs. + -- Maurice Wilkes discovers debugging, 1949 +%% +As the poet said, "Only God can make a tree" -- probably because it's +so hard to figure out how to get the bark on. + -- Woody Allen +%% +As the trials of life continue to take their toll, remember that there +is always a future in Computer Maintenance. + -- National Lampoon, "Deteriorada" +%% +As Will Rogers would have said, "There is no such things as a free +variable." +%% +As with most fine things, chocolate has its season. There is a simple +memory aid that you can use to determine whether it is the correct time +to order chocolate dishes: any month whose name contains the letter A, +E, or U is the proper time for chocolate. + -- Sandra Boynton, "Chocolate: The Consuming Passion" +%% +As Zeus said to Narcissus, "Watch yourself." +%% +Ask Not for whom the Bell Tolls, and You will Pay only the +Station-to-Station rate. +%% +Ask not for whom the telephone bell tolls ... if thou art in the +bathtub, it tolls for thee. +%% +Ask your boss to reconsider -- it's so difficult to take "Go to hell" +for an answer. +%% +Ass, n.: + The masculine of "lass". +%% +At a recent meeting in Snowmass, Colorado, a participant from Los +Angeles fainted from hyperoxygenation, and we had to hold his head +under the exhaust of a bus until he revived. +%% +At Group L, Stoffel oversees six first-rate programmers, a managerial +challenge roughly comparable to herding cats. + -- The Washington Post Magazine, June 9, 1985 +%% +... at least I thought I was dancing, 'til somebody stepped on my hand. + -- J. B. White +%% +At the source of every error which is blamed on the computer you will +find at least two human errors, including the error of blaming it on +the computer. +%% +Atlee is a very modest man. And with reason. + -- Winston Churchill +%% +Automobile, n.: + A four-wheeled vehicle that runs up hills and down +pedestrians. +%% +Avoid Quiet and Placid persons unless you are in Need of Sleep. + -- National Lampoon, "Deteriorada" +%% +Avoid reality at all costs. +%% +Bacchus, n.: + A convenient deity invented by the ancients as an excuse for +getting drunk. + -- Ambrose Bierce, "The Devil's Dictionary" +%% +Bagdikian's Observation: + Trying to be a first-rate reporter on the average American + newspaper is like trying to play Bach's "St. Matthew Passion" + on a ukelele. +%% +Baker's First Law of Federal Geometry: + A block grant is a solid mass of money surrounded on all sides + by governors. +%% +Ban the bomb. Save the world for conventional warfare. +%% +Bank error in your favor. Collect $200. +%% +Barach's Rule: + An alcoholic is a person who drinks more than his own + physician. +%% +Barometer, n.: + An ingenious instrument which indicates what kind of weather we +are having. + -- Ambrose Bierce, "The Devil's Dictionary" +%% +Barth's Distinction: + There are two types of people: those who divide people into two + types, and those who don't. +%% +Baruch's Observation: + If all you have is a hammer, everything looks like a nail. +%% +Basic, n.: + A programming language. Related to certain social diseases in +that those who have it will not admit it in polite company. +%% +Be a better psychiatrist and the world will beat a psychopath to your +door. +%% +BE ALERT!!!! (The world needs more lerts ...) +%% +Be assured that a walk through the ocean of most Souls would scarcely +get your Feet wet. Fall not in Love, therefore: it will stick to your +face. + -- National Lampoon, "Deteriorada" +%% +Be careful of reading health books, you might die of a misprint. + -- Mark Twain +%% +Be different: conform. +%% +Be free and open and breezy! Enjoy! Things won't get any better so +get used to it. +%% +Be wary of strong drink. It can make you shoot at tax collectors and +miss + -- Lazarus Long, "Time Enough for Love" +%% +Behold the warranty ... the bold print giveth and the fine print taketh +away. +%% +Beifeld's Principle: + The probability of a young man meeting a desirable and + receptive young female increases by pyramidal progression when + he is already in the company of: (1) a date, (2) his wife, (3) + a better looking and richer male friend. +%% +Bell Labs Unix -- Reach out and grep someone. +%% +"Benson, you are so free of the ravages of intelligence" + -- Time Bandits +%% +Besides the device, the box should contain: + +* Eight little rectangular snippets of paper that say "WARNING" + +* A plastic packet containing four 5/17 inch pilfer grommets and two + club-ended 6/93 inch boxcar prawns. + +YOU WILL NEED TO SUPPLY: a matrix wrench and 60,000 feet of tram +cable. + +IF ANYTHING IS DAMAGED OR MISSING: You IMMEDIATELY should turn to your +spouse and say: "Margaret, you know why this country can't make a car +that can get all the way through the drive-through at Burger King +without a major transmission overhaul? Because nobody cares, that's +why." + +WARNING: This is assuming your spouse's name is Margaret. + -- Dave Barry, "Read This First!" +%% +better !pout !cry +better watchout +lpr why +santa claus town + +cat /etc/passwd >list +ncheck list +ncheck list +cat list | grep naughty >nogiftlist +cat list | grep nice >giftlist +santa claus town + +who | grep sleeping +who | grep awake +who | egrep 'bad|good' +for (goodness sake) { + be good +} +%% +"Beware of bugs in the above code; I have only proved it correct, not +tried it." + -- Donald Knuth +%% +Beware of low-flying butterflies. +%% +Beware of Programmers who carry screwdrivers. + -- Leonard Brandwein +%% +"Beware of the man who works hard to learn something, learns it, and +finds himself no wiser than before," Bokonon tells us. "He is full of +murderous resentment of people who are ignorant without having come by +their ignorance the hard way." + -- Kurt Vonnegut, "Cat's Cradle" +%% +Beware of the Turing Tar-pit in which everything is possible but +nothing of interest is easy. +%% +Binary, adj.: + Possessing the ability to have friends of both sexes. +%% +Bipolar, adj.: + Refers to someone who has homes in Nome, Alaska, and Buffalo, +New York +%% +Birth, n.: + The first and direst of all disasters. + -- Ambrose Bierce, "The Devil's Dictionary" +%% +Bizarreness is the essence of the exotic +%% +Blessed are they who Go Around in Circles, for they Shall be Known +as Wheels. +%% +BLISS is ignorance +%% +Blood is thicker than water, and much tastier. +%% +Board the windows, up your car insurance, and don't leave any booze in +plain sight. It's St. Patrick's day in Chicago again. The legend has +it that St. Patrick drove the snakes out of Ireland. In fact, he was +arrested for drunk driving. The snakes left because people kept +throwing up on them. +%% +Boling's postulate: + If you're feeling good, don't worry. You'll get over it. +%% +Bolub's Fourth Law of Computerdom: + Project teams detest weekly progress reporting because it so + vividly manifests their lack of progress. +%% +Bombeck's Rule of Medicine: + Never go to a doctor whose office plants have died. +%% +Boob's Law: + You always find something in the last place you look. +%% +Bore, n.: + A person who talks when you wish him to listen. + -- Ambrose Bierce, "The Devil's Dictionary" +%% +Boren's Laws: + (1) When in charge, ponder. + (2) When in trouble, delegate. + (3) When in doubt, mumble. +%% +Boss, n.: + According to the Oxford English Dictionary, in the Middle Ages +the words "boss" and "botch" were largely synonymous, except that boss, +in addition to meaning "a supervisor of workers" also meant "an +ornamental stud." +%% +Boston, n.: + Ludwig van Beethoven being jeered by 50,000 sports fans for +finishing second in the Irish jig competition. +%% +Boy, n.: + A noise with dirt on it. +%% +Bradley's Bromide: + If computers get too powerful, we can organize them into a + committee -- that will do them in. +%% +Brady's First Law of Problem Solving: + When confronted by a difficult problem, you can solve it more + easily by reducing it to the question, "How would the Lone + Ranger have handled this?" +%% +Brain fried -- Core dumped +%% +Brain, n.: + The apparatus with which we think that we think. + -- Ambrose Bierce, "The Devil's Dictionary" +%% +Brain, v. [as in "to brain"]: + To rebuke bluntly, but not pointedly; to dispel a source of +error in an opponent. + -- Ambrose Bierce, "The Devil's Dictionary" +%% +Breast Feeding should not be attempted by fathers with hairy chests, +since they can make the baby sneeze and give it wind. + -- Mike Harding, "The Armchair Anarchist's Almanac" +%% +Bride, n.: + A woman with a fine prospect of happiness behind her. + -- Ambrose Bierce, "The Devil's Dictionary" +%% +Bringing computers into the home won't change either one, but may +revitalize the corner saloon. +%% +British Israelites: + The British Israelites believe the white Anglo-Saxons of +Britain to be descended from the ten lost tribes of Israel deported by +Sargon of Assyria on the fall of Sumeria in 721 B.C. ... They further +believe that the future can be foretold by the measurements of the +Great Pyramid, which probably means it will be big and yellow and in +the hand of the Arabs. They also believe that if you sleep with your +head under the pillow a fairy will come and take all your teeth. + -- Mike Harding, "The Armchair Anarchist's Almanac" +%% +Broad-mindedness, n.: + The result of flattening high-mindedness out. +%% +Brook's Law: + Adding manpower to a late software project makes it later +%% +Brook's Law: + Adding manpower to a late software project makes it later. +%% +Brooke's Law: + Whenever a system becomes completely defined, some damn fool + discovers something which either abolishes the system or + expands it beyond recognition. +%% +Bubble Memory, n.: + A derogatory term, usually referring to a person's +intelligence. See also "vacuum tube". +%% +Bucy's Law: + Nothing is ever accomplished by a reasonable man. +%% +Bug, n.: + An aspect of a computer program which exists because the +PROGRAMMER was thinking about Jumbo Jacks or stock options when s/he +wrote the program. + +Fortunately, the second-to-last bug has just been fixed. + -- Ray Simard +%% +Bug: + Small living things that small living boys throw on small +living girls. +%% +BULLWINKLE: "You just leave that to my pal. He's the brains of the + outfit." +GENERAL: "What does that make YOU?" +BULLWINKLE: "What else? An executive..." + -- Jay Ward +%% +Bumper sticker: + +"All the parts falling off this car are of the very finest British +manufacture" +%% +Bureaucrat, n.: + A politician who has tenure. +%% +... But as records of courts and justice are admissible, it can +easily be proved that powerful and malevolent magicians once existed +and were a scourge to mankind. The evidence (including confession) +upon which certain women were convicted of witchcraft and executed was +without a flaw; it is still unimpeachable. The judges' decisions based +on it were sound in logic and in law. Nothing in any existing court +was ever more thoroughly proved than the charges of witchcraft and +sorcery for which so many suffered death. If there were no witches, +human testimony and human reason are alike destitute of value. + -- Ambrose Bierce, "The Devil's Dictionary" +%% +... But if we laugh with derision, we will never understand. Human +intellectual capacity has not altered for thousands of years so far as +we can tell. If intelligent people invested intense energy in issues +that now seem foolish to us, then the failure lies in our understanding +of their world, not in their distorted perceptions. Even the standard +example of ancient nonsense -- the debate about angels on pinheads -- +makes sense once you realize that theologians were not discussing +whether five or eighteen would fit, but whether a pin could house a +finite or an infinite number. + -- S. J. Gould, "Wide Hats and Narrow Minds" +%% +But in our enthusiasm, we could not resist a radical overhaul of the +system, in which all of its major weaknesses have been exposed, +analyzed, and replaced with new weaknesses. + -- Bruce Leverett, "Register Allocation in Optimizing + Compilers" +%% +But scientists, who ought to know +Assure us that it must be so. +Oh, let us never, never doubt +What nobody is sure about. + -- Hilaire Belloc +%% +But soft you, the fair Ophelia: +Ope not thy ponderous and marble jaws, +But get thee to a nunnery -- go! + -- Mark "The Bard" Twain +%% +But the greatest Electrical Pioneer of them all was Thomas Edison, who +was a brilliant inventor despite the fact that he had little formal +education and lived in New Jersey. Edison's first major invention in +1877, was the phonograph, which could soon be found in thousands of +American homes, where it basically sat until 1923, when the record was +invented. But Edison's greatest achievement came in 1879, when he +invented the electric company. Edison's design was a brilliant +adaptation of the simple electrical circuit: the electric company sends +electricity through a wire to a customer, then immediately gets the +electricity back through another wire, then (this is the brilliant +part) sends it right back to the customer again. + +This means that an electric company can sell a customer the same batch +of electricity thousands of times a day and never get caught, since +very few customers take the time to examine their electricity closely. +In fact the last year any new electricity was generated in the United +States was 1937; the electric companies have been merely re-selling it +ever since, which is why they have so much free time to apply for rate +increases. + -- Dave Barry, "What is Electricity?" +%% +"But this has taken us far afield from interface, which is not a bad +place to be, since I particularly want to move ahead to the kludge. +Why do people have so much trouble understanding the kludge? What is a +kludge, after all, but not enough Ks, not enough ROMs, not enough RAMs, +poor quality interface and too few bytes to go around? Have I +explained yet about the bytes?" +%% +"But what we need to know is, do people want nasally-insertable +computers?" +%% +Buzz off, Banana Nose; Relieve mine eyes +Of hateful soreness, purge mine ears of corn; +Less dear than army ants in apple pies +Art thou, old prune-face, with thy chestnuts worn, +Dropt from thy peeling lips like lousy fruit; +Like honeybees upon the perfum'd rose +They suck, and like the double-breasted suit +Are out of date; therefore, Banana Nose, +Go fly a kite, thy welcome's overstayed; +And stem the produce of thy waspish wits: +Thy logick, like thy locks, is disarrayed; +Thy cheer, like thy complexion, is the pits. +Be off, I say; go bug somebody new, +Scram, beat it, get thee hence, and nuts to you. +%% +By doing just a little every day, you can gradually let the task +completely overwhelm you. +%% +"By necessity, by proclivity, and by delight, we all quote. In fact, +it is as difficult to appropriate the thoughts of others as it is to +invent. (R. Emerson)" + -- Quoted from a fortune cookie program + (whose author claims, "Actually, stealing IS easier.") + [to which I reply, "You think it's easy for me to + misconstrue all these misquotations?!?"] +%% +Bypasses are devices that allow some people to dash from point A to +point B very fast while other people dash from point B to point A very +fast. People living at point C, being a point directly in between, are +often given to wonder what's so great about point A that so many people +from point B are so keen to get there and what's so great about point B +that so many people from point A are so keen to get _____there. They often +wish that people would just once and for all work out where the hell +they wanted to be. + -- Douglas Adams, "The Hitchhiker's Guide to the Galaxy" +%% +C, n.: + A programming language that is sort of like Pascal except more +like assembly except that it isn't very much like either one, or +anything else. It is either the best language available to the art +today, or it isn't. + -- Ray Simard +%% +Cabbage, n.: + A familiar kitchen-garden vegetable about as large and wise as +a man's head. + -- Ambrose Bierce, "The Devil's Dictionary" +%% +Cahn's Axiom: + When all else fails, read the instructions. +%% +California is a fine place to live -- if you happen to be an orange. + -- Fred Allen +%% +California, n.: + From Latin "calor", meaning "heat" (as in English "calorie" or +Spanish "caliente"); and "fornia'" for "sexual intercourse" or +"fornication." Hence: Tierra de California, "the land of hot sex." + -- Ed Moran +%% +Call on God, but row away from the rocks. + -- Indian proverb +%% +"Calling J-Man Kink. Calling J-Man Kink. Hash missle sighted, target +Los Angeles. Disregard personal feelings about city and intercept." +%% +"Calvin Coolidge looks as if he had been weaned on a pickle." + -- Alice Roosevelt Longworth +%% +"Calvin Coolidge was the greatest man who ever came out of Plymouth +Corner, Vermont." + -- Clarence Darrow +%% +Canada Bill Jone's Motto: + It's morally wrong to allow suckers to keep their money. + +Supplement: + A .44 magnum beats four aces. +%% +Canada Post doesn't really charge 32 cents for a stamp. It's 2 cents +for postage and 30 cents for storage. + -- Gerald Regan, Cabinet Minister, 12/31/83 Financial + Post +%% +Cancel me not -- for what then shall remain? +Abscissas, some mantissas, modules, modes, +A root or two, a torus and a node: +The inverse of my verse, a null domain. + -- Stanislaw Lem, "Cyberiad" +%% + CANCER (June 21 - July 22) +You are sympathetic and understanding to other people's problems. They +think you are a sucker. You are always putting things off. That's why +you'll never make anything of yourself. Most welfare recipients are +Cancer people. +%% + CAPRICORN (Dec 23 - Jan 19) +You are conservative and afraid of taking risks. You don't do much of +anything and are lazy. There has never been a Capricorn of any +importance. Capricorns should avoid standing still for too long as +they take root and become trees. +%% +Captain Penny's Law: + You can fool all of the people some of the time, and some of + the people all of the time, but you Can't Fool Mom. +%% +Carelessly planned projects take three times longer to complete than +expected. Carefully planned projects take four times longer to +complete than expected, mostly because the planners expect their +planning to reduce the time it takes. +%% +Carperpetuation (kar' pur pet u a shun), n.: + The act, when vacuuming, of running over a string at least a +dozen times, reaching over and picking it up, examining it, then +putting it back down to give the vacuum one more chance. + -- Rich Hall, "Sniglets" +%% +Cauliflower is nothing but Cabbage with a College Education. + -- Mark Twain +%% +Caution: breathing may be hazardous to your health. +%% +CChheecckk yyoouurr dduupplleexx sswwiittcchh.. +%% +Celebrate Hannibal Day this year. Take an elephant to lunch. +%% +Census Taker to Housewife: Did you ever have the measles, and, if so, +how many? +%% +Cerebus: I'd love to lick apricot brandy out of your navel. +Jaka: Look, Cerebus-- Jaka has to tell you ... something +Cerebus: If Cerebus had a navel, would you lick apricot brandy + out of it? +Jaka: Ugh! +Cerebus: You don't like apricot brandy? + -- Cerebus #6, "The Secret" +%% +Certain old men prefer to rise at dawn, taking a cold bath and a long +walk with an empty stomach and otherwise mortifying the flesh. They +then point with pride to these practices as the cause of their sturdy +health and ripe years; the truth being that they are hearty and old, +not because of their habits, but in spite of them. The reason we find +only robust persons doing this thing is that it has killed all the +others who have tried it. + -- Ambrose Bierce, "The Devil's Dictionary" +%% +Certainly there are things in life that money can't buy, but it's very funny-- + Did you ever try buying then without money? + -- Ogden Nash +%% +Character Density: the number of very weird people in the office. +%% +Chemicals, n.: + Noxious substances from which modern foods are made. +%% +Chicago, n.: + Where the dead still vote ... early and often! +%% +Chicken Little was right. +%% +Chicken Soup, n.: + An ancient miracle drug containing equal parts of aureomycin, +cocaine, interferon, and TLC. The only ailment chicken soup can't cure +is neurotic dependence on one's mother. + -- Arthur Naiman, "Every Goy's Guide to Yiddish" +%% +Children are natural mimic who act like their parents despite every +effort to teach them good manners. +%% +Children aren't happy without something to ignore, +And that's what parents were created for. + -- Ogden Nash +%% +Children seldom misquote you. In fact, they usually repeat word for +word what you shouldn't have said. +%% +Chism's Law of Completion: + The amount of time required to complete a government project is + precisely equal to the length of time already spent on it. +%% +Chisolm's First Corollary to Murphy's Second Law: + When things just can't possibly get any worse, they will. +%% +Christ: + A man who was born at least 5,000 years ahead of his time. +%% +Churchill's Commentary on Man: + Man will occasionally stumble over the truth, but most of the + time he will pick himself up and continue on. +%% +Cigarette, n.: + A fire at one end, a fool at the other, and a bit of tobacco in +between. +%% +Cinemuck, n.: + The combination of popcorn, soda, and melted chocolate which +covers the floors of movie theaters. + -- Rich Hall, "Sniglets" +%% +Cleanliness is next to impossible. +%% +Cleveland still lives. God ____must be dead. +%% +"Cleveland? Yes, I spent a week there one day." +%% +Cloning is the sincerest form of flattery. +%% +Clothes make the man. Naked people have little or no influence on +society. + -- Mark Twain +%% +Cocaine -- the thinking man's Dristan. +%% +Cogito cogito ergo cogito sum -- +"I think that I think, therefore I think that I am." + -- Ambrose Bierce, "The Devil's Dictionary" +%% +Cold, adj.: + When the local flashers are handing out written descriptions. +%% +Cold, adj.: + When the politicians walk around with their hands in their own +pockets. +%% +Collaboration, n.: + A literary partnership based on the false assumption that the +other fellow can spell. +%% +College football is a game which would be much more interesting if the +faculty played instead of the students, and even more interesting if +the trustees played. There would be a great increase in broken arms, +legs, and necks, and simultaneously an appreciable diminution in the +loss to humanity. + -- H. L. Mencken +%% +Colvard's Logical Premises: + All probabilities are 50%. Either a thing will happen or + it won't. +Colvard's Unconscionable Commentary: + This is especially true when dealing with someone you're + attracted to. +Grelb's Commentary + Likelihoods, however, are 90% against you. +%% +Come, every frustum longs to be a cone, +And every vector dreams of matrices. +Hark to the gentle gradient of the breeze: +It whispers of a more ergodic zone. + -- Stanislaw Lem, "Cyberiad" +%% +Come, let us hasten to a higher plane, +Where dyads tread the fairy fields of Venn, +Their indices bedecked from one to _n, +Commingled in an endless Markov chain! + -- Stanislaw Lem, "Cyberiad" +%% +Command, n.: + Statement presented by a human and accepted by a computer in +such a manner as to make the human feel as if he is in control. +%% + COMMENT + +Oh, life is a glorious cycle of song, +A medley of extemporanea; +And love is thing that can never go wrong; +And I am Marie of Roumania. + -- Dorothy Parker +%% +Commitment, n.: + Commitment can be illustrated by a breakfast of ham and eggs. +The chicken was involved, the pig was committed. +%% +Common sense is the collection of prejudices acquired by age eighteen. + -- Albert Einstein +%% +Computer programmers do it byte by byte +%% +Computer Science is merely the post-Turing decline in formal systems +theory. +%% +Computers are not intelligent. They only think they are. +%% +Conceit causes more conversation than wit. + -- LaRouchefoucauld +%% +Concept, n.: + Any "idea" for which an outside consultant billed you more than +$25,000. +%% +Condense soup, not books! +%% +Confession is good for the soul only in the sense that a tweed coat is +good for dandruff. + -- Peter de Vries +%% +Confidence is the feeling you have before you understand the situation. +%% +Congratulations! You have purchased an extremely fine device that +would give you thousands of years of trouble-free service, except that +you undoubtably will destroy it via some typical bonehead consumer +maneuver. Which is why we ask you to PLEASE FOR GOD'S SAKE READ THIS +OWNER'S MANUAL CAREFULLY BEFORE YOU UNPACK THE DEVICE. YOU ALREADY +UNPACKED IT, DIDN'T YOU? YOU UNPACKED IT AND PLUGGED IT IN AND TURNED +IT ON AND FIDDLED WITH THE KNOBS, AND NOW YOUR CHILD, THE SAME CHILD +WHO ONCE SHOVED A POLISH SAUSAGE INTO YOUR VIDEOCASSETTE RECORDED AND +SET IT ON "FAST FORWARD", THIS CHILD ALSO IS FIDDLING WITH HE KNOBS, +RIGHT? AND YOU'RE JUST NOW STARTING TO READ THE INSTRUCTIONS, +RIGHT??? WE MIGHT AS WELL JUST BREAK THESE DEVICES RIGHT AT THE +FACTORY BEFORE WE SHIP THEM OUT, YOU KNOW THAT? + -- Dave Barry, "Read This First!" +%% +Conscience is the inner voice that warns us somebody is looking + -- H. L. Mencken +%% +Conscience is what hurts when everything else feels so good. +%% +Consultants are mystical people who ask a company for a number and then +give it back to them. +%% +"Contrariwise," continued Tweedledee, "if it was so, it might be, and +if it were so, it would be; but as it isn't, it ain't. That's logic!" + -- Lewis Carroll, "Through the Looking Glass" +%% +Conversation, n.: + A vocal competition in which the one who is catching his breath +is called the listener. +%% +Conway's Law: + In any organization there will always be one person who knows + what is going on. + + This person must be fired. +%% +Coronation, n.: + The ceremony of investing a sovereign with the outward and +visible signs of his divine right to be blown skyhigh with a dynamite +bomb. + -- Ambrose Bierce, "The Devil's Dictionary" +%% +Corrupt, adj.: + In politics, holding an office of trust or profit. +%% +Corruption is not the #1 priority of the Police Commissioner. His job +is to enforce the law and fight crime. + -- P.B.A. President E. J. Kiernan +%% +Coward, n.: + One who in a perilous emergency thinks with his legs. + -- Ambrose Bierce, "The Devil's Dictionary" +%% +Crash programs fail because they are based on the theory that, with +nine women pregnant, you can get a baby a month. + -- Wernher von Braun +%% +Crime does not pay ... as well as politics. + -- A. E. Newman +%% +Critic, n.: + A person who boasts himself hard to please because nobody tries +to please him. + -- Ambrose Bierce, "The Devil's Dictionary" +%% +Cynic, n.: + A blackguard whose faulty vision sees things as they are, not +as they ought to be. Hence the custom among the Scythians of plucking +out a cynic's eyes to improve his vision. + -- Ambrose Bierce, "The Devil's Dictionary" +%% +Cynic, n.: + One who looks through rose-colored glasses with a jaundiced +eye. +%% +Darth Vader sleeps with a Teddywookie. +%% +Dawn, n.: + The time when men of reason go to bed. + -- Ambrose Bierce, "The Devil's Dictionary" +%% +Day of inquiry. You will be subpoenaed. +%% +Dealing with failure is easy: work hard to improve. Success is also +easy to handle: you've solved the wrong problem. Work hard to +improve. +%% +Dear Lord: + I just want *___one* one-armed manager so I never have to hear "On + the other hand", again. +%% +Dear Miss Manners: + My home economics teacher says that one must never place one's +elbows on the table. However, I have read that one elbow, in between +courses, is all right. Which is correct? + +Gentle Reader: + For the purpose of answering examinations in your home +economics class, your teacher is correct. Catching on to this +principle of education may be of even greater importance to you now +than learning correct current table manners, vital as Miss Manners +believes that is. +%% +Dear Miss Manners: + Please list some tactful ways of removing a man's saliva from + your face. + +Gentle Reader: + Please list some decent ways of acquiring a man's saliva on + your face ... +%% +Death is God's way of telling you not to be such a wise guy. +%% +Death is life's way of telling you you've been fired. + -- R. Geis +%% +Death is Nature's way of recycling human beings. +%% +Death is nature's way of telling you to slow down +%% +Decisionmaker, n.: + The person in your office who was unable to form a task force +before the music stopped. +%% +Decisions of the judges will be final unless shouted down by a really +overwhelming majority of the crowd present. Abusive and obscene +language may not be used by contestants when addressing members of the +judging panel, or, conversely, by members of the judging panel when +addressing contestants (unless struck by a boomerang). + -- Mudgeeraba Creek Emu-Riding and Boomerang-Throwing + Assoc. +%% + Deck Us All With Boston Charlie + +Deck us all with Boston Charlie, +Walla Walla, Wash., an' Kalamazoo! +Nora's freezin' on the trolley, +Swaller dollar cauliflower, alleygaroo! + +Don't we know archaic barrel, +Lullaby Lilla Boy, Louisville Lou. +Trolley Molly don't love Harold, +Boola boola Pensacoola hullabaloo! + -- Walt Kelly +%% + "Deep" is a word like "theory" or "semantic" -- it implies all +sorts of marvelous things. It's one thing to be able to say "I've got +a theory", quite another to say "I've got a semantic theory", but, ah, +those who can claim "I've got a deep semantic theory", they are truly +blessed. + -- Randy Davis +%% + DELETE A FORTUNE! + +Don't some of these fortunes just drive you nuts?! Wouldn't you like +to see some of them deleted from the system? You can! Just mail to +"fortune" with the fortune you hate most, and we MIGHT make sure it +gets expunged. +%% +Deliberation, n.: + The act of examining one's bread to determine which side it is +buttered on. + -- Ambrose Bierce, "The Devil's Dictionary" +%% +"Deliver yesterday, code today, think tomorrow." +%% +Democracy is a form of government in which it is permitted to wonder +aloud what the country could do under first-class management. + -- Senator Soaper +%% +Democracy is a form of government that substitutes election by the +incompetent many for appointment by the corrupt few. + -- G. B. Shaw +%% +Democracy is also a form of worship. It is the worship of Jackals by +Jackasses. + -- H. L. Mencken +%% +Democracy is the recurrent suspicion that more than half of the people +are right more than half of the time. + -- E. B. White +%% +Dentist, n.: + A Prestidigitator who, putting metal in one's mouth, pulls +coins out of one's pockets. + -- Ambrose Bierce, "The Devil's Dictionary" +%% + DETERIORATA + +Go placidly amid the noise and waste, +And remember what comfort there may be in owning a piece thereof. +Avoid quiet and passive persons, unless you are in need of sleep. +Rotate your tires. +Speak glowingly of those greater than yourself, +And heed well their advice -- even though they be turkeys. +Know what to kiss -- and when. +Remember that two wrongs never make a right, +But that three do. +Wherever possible, put people on "HOLD". +Be comforted, that in the face of all aridity and disillusionment, +And despite the changing fortunes of time, +There is always a big future in computer maintenance. + + You are a fluke of the universe ... + You have no right to be here. + Whether you can hear it or not, the universe + Is laughing behind your back. + -- National Lampoon +%% +DeVries's Dilemma: + If you hit two keys on the typewriter, the one you don't want + hits the paper. +%% +Did you know ... + +That no-one ever reads these things? +%% +Did you know that clones never use mirrors? + -- Ambrose Bierce, "The Devil's Dictionary" +%% +Die, v.: + To stop sinning suddenly. + -- Elbert Hubbard +%% +"Die? I should say not, dear fellow. No Barrymore would allow such a +conventional thing to happen to him." + -- John Barrymore's dying words +%% +Different all twisty a of in maze are you, passages little. +%% +Dimensions will always be expressed in the least usable term. +Velocity, for example, will be expressed in furlongs per fortnight. +%% +Diplomacy is the art of saying "nice doggy" until you can find a rock. +%% +Disc space -- the final frontier! +%% +Disco is to music what Etch-A-Sketch is to art. +%% +Distress, n.: + A disease incurred by exposure to the prosperity of a friend. + -- Ambrose Bierce, "The Devil's Dictionary" +%% +Do infants have as much fun in infancy as adults do in adultery? +%% +Do molecular biologists wear designer genes? +%% +Do not believe in miracles -- rely on them. +%% +Do not drink coffee in early A.M. It will keep you awake until noon. +%% +Do not meddle in the affairs of troff, for it is subtle and quick to +anger. +%% +Do not read this fortune under penalty of law. +Violators will be prosecuted. +(Penal Code sec. 2.3.2 (II.a.)) +%% +Do not sleep in a eucalyptus tree tonight. +%% +Do not try to solve all life's problems at once -- learn to dread each +day as it comes. + -- Donald Kaul +%% +Do something unusual today. Pay a bill. +%% +Do what comes naturally now. Seethe and fume and throw a tantrum. +%% +Do you realize how many holes there could be if people would just take +the time to take the dirt out of them? +%% +"Do you think what we're doing is wrong?" +"Of course it's wrong! It's illegal!" +"I've never done anything illegal before." +"I thought you said you were an accountant!" +%% +Documentation is like sex: when it is good, it is very, very good; and +when it is bad, it is better than nothing. + -- Dick Brandon +%% +Documentation is the castor oil of programming. Managers know it must +be good because the programmers hate it so much. +%% +Don't abandon hope: your Tom Mix decoder ring arrives tomorrow. +%% +Don't be humble, you're not that great. + -- Golda Meir +%% +Don't believe everything you hear or anything you say. +%% +Don't cook tonight -- starve a rat today! +%% +Don't feed the bats tonight. +%% +Don't get suckered in by the comments -- they can be terribly +misleading. Debug only code. + -- Dave Storer +%% +Don't go around saying the world owes you a living. The world owes you +nothing. It was here first. + -- Mark Twain +%% +Don't go surfing in South Dakota for a while. +%% +Don't hate yourself in the morning -- sleep till noon. +%% +Don't kiss an elephant on the lips today. +%% +Don't knock President Fillmore. He kept us out of Vietnam. +%% +Don't let people drive you crazy when you know it's in walking +distance. +%% +Don't look back, the lemmings are gaining on you. +%% +Don't put off for tomorrow what you can do today, because if you enjoy +it today you can do it again tomorrow. +%% +"Don't say yes until I finish talking." + -- Darryl F. Zanuck +%% +Don't take life too seriously -- you'll never get out if it alive. +%% +Don't tell any big lies today. Small ones can be just as effective. +%% +"Don't tell me I'm burning the candle at both ends -- tell me where to +get more wax!!" +%% +Don't worry about the world coming to an end today. It's already +tomorrow in Australia. + -- Charles Schultz +%% +Don't worry over what other people are thinking about you. They're too +busy worrying over what you are thinking about them. +%% +Don't you feel more like you do now than you did when you came in? +%% +Don: I didn't know you had a cousin Penelope, Bill! Was she + pretty? +W. C.: Well, her face was so wrinkled it looked like seven miles of + bad road. She had so many gold teeth, Don, she use to have to + sleep with her head in a safe. She died in Bolivia. +Don: Oh Bill, it must be hard to lose a relative. +W. C.: It's almost impossible. + -- W. C. Fields, from "The Further Adventures of Larson + E. Whipsnade and other Tarradiddles" +%% +Down with categorical imperative! +%% +"Drawing on my fine command of language, I said nothing." +%% +Drew's Law of Highway Biology: + The first bug to hit a clean windshield lands directly in front + of your eyes. +%% +Drive defensively. Buy a tank. +%% +Drugs may be the road to nowhere, but at least they're the scenic +route! +%% +Ducharm's Axiom: + If you view your problem closely enough you will recognize + yourself as part of the problem. +%% +Ducharme's Precept: + Opportunity always knocks at the least opportune moment. +%% +Duct tape is like the force. It has a light side, and a dark side, and +it holds the universe together ... + -- Carl Zwanzig +%% +Due to a shortage of devoted followers, the production of great leaders +has been discontinued. +%% +Due to circumstances beyond your control, you are master of your fate +and captain of your soul. +%% + During a grouse hunt in North Carolina two intrepid sportsmen +were blasting away at a clump of trees near a stone wall. Suddenly a +red-faced country squire popped his head over the wall and shouted, +"Hey, you almost hit my wife." + "Did I?" cried the hunter, aghast. "Terribly sorry. Have a +shot at mine, over there." +%% +During the next two hours, the VAX will be going up and down several +times, often with lin~po_~{po ~poz~ppo\~{ o n~po_~{o[po ~y oodsou>#w4k**n~po_~{ol;lkld;f;g;dd;po\~{o +%% +Dying is a very dull, dreary affair. And my advice to you is to +have nothing whatever to do with it. + -- W. Somerset Maughm +%% +E Pluribus Unix +%% +Earn cash in your spare time -- blackmail your friends +%% +Earn cash in your spare time -- blackmail your friends. +%% +/Earth is 98% full ... please delete anyone you can. +%% +/earth is 98% full ... please delete anyone you can. +%% +"Earth is a great, big funhouse without the fun." + -- Jeff Berner +%% +Easiest Color to Solve on a Rubik's Cube: + Black. Simply remove all the little colored stickers on the +cube, and each of side of the cube will now be the original color of +the plastic underneath -- black. According to the instructions, this +means the puzzle is solved. + -- Steve Rubenstein +%% +Economics is extremely useful as a form of employment for economists. + -- John Kenneth Galbraith +%% +Economics, n.: + Economics is the study of the value and meaning of J. K. +Galbraith ... + -- Mike Harding, "The Armchair Anarchist's Almanac" +%% +Eggheads unite! You have nothing to lose but your yolks. + -- Adlai Stevenson +%% +Eggnog is a traditional holiday drink invented by the English. Many +people wonder where the word "eggnog" comes from. The first syllable +comes from the English word "egg", meaning "egg". I don't know where +the "nog" comes from. + +To make eggnog, you'll need rum, whiskey, wine gin and, if they are in +season, eggs... +%% +Egotism is the anesthetic given by a kindly nature to relieve the pain +of being a damned fool. + -- Bellamy Brooks +%% +Egotist, n.: + A person of low taste, more interested in himself than me. + -- Ambrose Bierce, "The Devil's Dictionary" +%% +Ehrman's Commentary: + 1. Things will get worse before they get better. + 2. Who said things would get better? +%% +Eighty percent of air pollution comes from plants and trees. + -- Ronald Reagan, famous movie star +%% +Eisenhower was very nice, +Nixon was his only vice. + -- C. Degen +%% +Eleanor Rigby + Sits at the keyboard + And waits for a line on the screen +Lives in a dream +Waits for a signal + Finding some code + That will make the machine do some more. +What is it for? + +All the lonely users, where do they all come from? +All the lonely users, why does it take so long? +%% +Electrical Engineers do it with less resistance. +%% +Electrocution, n.: + Burning at the stake with all the modern improvements. +%% +Elevators smell different to midgets +%% +Emersons' Law of Contrariness: + Our chief want in life is somebody who shall make us do what we + can. Having found them, we shall then hate them for it. +%% +Encyclopedia Salesmen: + Invite them all in. Nip out the back door. Phone the police +and tell them your house is being burgled. + -- Mike Harding, "The Armchair Anarchist's Almanac" +%% +Endless Loop: n., see Loop, Endless. +Loop, Endless: n., see Endless Loop. + -- Random Shack Data Processing Dictionary +%% +Entropy isn't what it used to be. +%% +Enzymes are things invented by biologists that explain things which +otherwise require harder thinking. + -- Jerome Lettvin +%% +Equal bytes for women. +%% +Es brilig war. Die schlichte Toven + Wirrten und wimmelten in Waben; +Und aller-m"umsige Burggoven + Dir mohmen R"ath ausgraben. + -- Lewis Carrol, "Through the Looking Glass" +%% +Eternal nothingness is fine if you happen to be dressed for it. + -- Woody Allen +%% +Etymology, n.: + Some early etymological scholars come up with derivations that +were hard for the public to believe. The term "etymology" was formed +from the Latin "etus" ("eaten"), the root "mal" ("bad"), and "logy" +("study of"). It meant "the study of things that are hard to swallow." + -- Mike Kellen +%% +Even if you do learn to speak correct English, whom are you going to +speak it to? + -- Clarence Darrow +%% +"Even the best of friends cannot attend each other's funeral." + -- Kehlog Albran, "The Profit" +%% +Even though they raised the rate for first class mail in the United +States we really shouldn't complain -- it's still only 2 cents a day. +%% +Ever notice that even the busiest people are never too busy to tell you +just how busy they are. +%% +Every 4 seconds a woman has a baby. Our problem is to find this woman +and stop her. +%% +Every absurdity has a champion who will defend it. +%% +Every creature has within him the wild, uncontrollable urge to punt. +%% +Every gun that is made, every warship launched, every rocket fired +signifies in the final sense, a theft from those who hunger and are not +fed, those who are cold and are not clothed. This world in arms is not +spending money alone. It is spending the sweat of its laborers, the +genius of its scientists, the hopes of its children. This is not a way +of life at all in any true sense. Under the clouds of war, it is +humanity hanging on a cross of iron. + -- Dwight Eisenhower, April 16, 1953 +%% +Every Horse has an Infinite Number of Legs (proof by intimidation): + +Horses have an even number of legs. Behind they have two legs, and in +front they have fore-legs. This makes six legs, which is certainly an +odd number of legs for a horse. But the only number that is both even +and odd is infinity. Therefore, horses have an infinite number of +legs. Now to show this for the general case, suppose that somewhere, +there is a horse that has a finite number of legs. But that is a horse +of another color, and by the [above] lemma ["All horses are the same +color"], that does not exist. +%% +Every little picofarad has a nanohenry all its own. + -- Don Vonada +%% +Every man is as God made him, ay, and often worse. + -- Miguel de Cervantes +%% +Every program has at least one bug and can be shortened by at least one +instruction -- from which, by induction, one can deduce that every +program can be reduced to one instruction which doesn't work. +%% +Every program has two purposes -- +written and another for which it wasn't. +%% +Every program is a part of some other program, and rarely fits. +%% +Every solution breeds new problems. +%% +Every successful person has had failures but repeated failure is no +guarantee of eventual success. +%% +"Every time I think I know where it's at, they move it." +%% +Every word is like an unnecessary stain on silence and nothingness. + -- Beckett +%% +Everybody is somebody else's weirdo. + -- Dykstra +%% +Everybody wants to go to heaven, but nobody wants to die. +%% +Everyone can be taught to sculpt: Michelangelo would have had to be +taught how ___not to. So it is with the great programmers. +%% +Everyone knows that dragons don't exist. But while this simplistic +formulation may satisfy the layman, it does not suffice for the +scientific mind. The School of Higher Neantical Nillity is in fact +wholly unconcerned with what ____does exist. Indeed, the banality of +existence has been so amply demonstrated, there is no need for us to +discuss it any further here. The brilliant Cerebron, attacking the +problem analytically, discovered three distinct kinds of dragon: the +mythical, the chimerical, and the purely hypothetical. They were all, +one might say, nonexistent, but each nonexisted in an entirely +different way ... + -- Stanislaw Lem, "Cyberiad" +%% +Everyone talks about apathy, but no one ____does anything about it. +%% +Everything is controlled by a small evil group to which, unfortunately, +no one we know belongs. +%% +Everything you know is wrong! +%% +Everything you've learned in school as "obvious" becomes less and less +obvious as you begin to study the universe. For example, there are no +solids in the universe. There's not even a suggestion of a solid. +There are no absolute continuums. There are no surfaces. There are no +straight lines. + -- R. Buckminster Fuller +%% +Everyting should be built top-down, except the first time. +%% + Excellence is THE trend of the '80s. Walk into any shopping +mall bookstore, go to the rack where they keep the best-sellers such as +"Garfield Gets Spayed", and you'll see a half-dozen books telling you +how to be excellent: "In Search of Excellence", "Finding Excellence", +"Grasping Hold of Excellence", "Where to Hide Your Excellence at Night +So the Cleaning Personnel Don't Steal It", etc. + -- Dave Barry, "In Search of Excellence" +%% +Excellent day for drinking heavily. Spike office water cooler. +%% +Excellent day to have a rotten day. +%% +Excellent time to become a missing person. +%% +Excess on occasion is exhilarating. It prevents moderation from +acquiring the deadening effect of a habit. + -- W. Somerset Maugham +%% +Excessive login or logout messages are a sure sign of senility. +%% +Expect the worst, it's the least you can do. +%% +Expense Accounts, n.: + Corporate food stamps. +%% +Experience is something you don't get until just after you need it. + -- Olivier +%% +Experience is that marvelous thing that enables you recognize a +mistake when you make it again. + -- F. P. Jones +%% +Experience is the worst teacher. It always gives the test first and +the instruction afterward. +%% +Experience is what causes a person to make new mistakes instead of old +ones. +%% +Experience is what you get when you were expecting something else. +%% +Experience varies directly with equipment ruined. +%% +F u cn rd ths u cnt spl wrth a dm! +%% +f u cn rd ths, itn tyg h myxbl cd. +%% +f u cn rd ths, u cn gt a gd jb n cmptr prgrmmng. +%% +Fairy Tale, n.: + A horror story to prepare children for the newspapers. +%% +Faith is the quality that enables you to eat blackberry jam on a picnic +without looking to see whether the seeds move. +%% +Faith, n: + That quality which enables us to believe what we know to be +untrue. +%% +Fakir, n: + A psychologist whose charismatic data have inspired almost +religious devotion in his followers, even though the sources seem to +have shinnied up a rope and vanished. +%% +Familiarity breeds attempt +%% +Families, when a child is born +Want it to be intelligent. +I, through intelligence, +Having wrecked my whole life, +Only hope the baby will prove +Ignorant and stupid. +Then he will crown a tranquil life +By becoming a Cabinet Minister + -- Su Tung-p'o +%% +Famous last words: +%% +Famous last words: + 1) "Don't worry, I can handle it." + 2) "You and what army?" + 3) "If you were as smart as you think you are, you wouldn't be + a cop." +%% +Famous last words: + 1. Don't unplug it, it will just take a moment to fix. + 2. Let's take the shortcut, he can't see us from there. + 3. What happens if you touch these two wires tog-- + 4. We won't need reservations. + 5. It's always sunny there this time of the year. + 6. Don't worry, it's not loaded. + 7. They'd never (be stupid enough to) make him a manager. +%% +Far out in the uncharted backwaters of the unfashionable end of the +Western Spiral arm of the Galaxy lies a small unregarded yellow sun. +Orbiting this at a distance of roughly ninety-eight million miles is an +utterly insignificant little blue-green planet whose ape-descended life +forms are so amazingly primitive that they still think digital watches +are a pretty neat idea ... + -- Douglas Adams, "The Hitchhiker's Guide to the Galaxy" +%% +Fashion is a form of ugliness so intolerable that we have to alter it +every six months. + -- Oscar Wilde +%% +Fats Loves Madelyn +%% +Feel disillusioned? I've got some great new illusions ... +%% +Fertility is hereditary. If your parents didn't have any children, +neither will you. +%% + Festivity Level 1: Your guests are chatting amiably with each +other, admiring your Christmas-tree ornaments, singing carols around +the upright piano, sipping at their drinks and nibbling hors +d'oeuvres. + Festivity Level 2: Your guests are talking loudly -- sometimes +to each other, and sometimes to nobody at all, rearranging your +Christmas-tree ornaments, singing "I Gotta Be Me" around the upright +piano, gulping their drinks and wolfing down hors d'oeuvres. + Festivity Level 3: Your guests are arguing violently with +inanimate objects, singing "I can't get no satisfaction," gulping down +other peoples' drinks, wolfing down Christmas tree ornaments and +placing hors d'oeuvres in the upright piano to see what happens when +the little hammers strike. + Festivity Level 4: Your guests, hors d'oeuvres smeared all over +their naked bodies are performing a ritual dance around the burning +Christmas tree. The piano is missing. + + You want to keep your party somewhere around level 3, unless +you rent your home and own Firearms, in which case you can go to level +4. The best way to get to level 3 is egg-nog. +%% +Fifth Law of Applied Terror: + If you are given an open-book exam, you will forget your book. +Corollary: + If you are given a take-home exam, you will forget where you + live. +%% +Fifth Law of Procrastination: + Procrastination avoids boredom; one never has the feeling that + there is nothing important to do. +%% + FIGHTING WORDS + +Say my love is easy had, + Say I'm bitten raw with pride, +Say I am too often sad -- + Still behold me at your side. + +Say I'm neither brave nor young, + Say I woo and coddle care, +Say the devil touched my tongue -- + Still you have my heart to wear. + +But say my verses do not scan, + And I get me another man! + -- Dorothy Parker +%% +Finagle's Creed: + Science is true. Don't be misled by facts. +%% +Finagle's First Law: + If an experiment works, something has gone wrong. +%% +Finagle's fourth Law: + Once a job is fouled up, anything done to improve it only + makes it worse. +%% +Finagle's Second Law: + No matter what the anticipated result, there will always be + someone eager to (a) misinterpret it, (b) fake it, or (c) + believe it happened according to his own pet theory. +%% +Finagle's Third Law: + In any collection of data, the figure most obviously correct, + beyond all need of checking, is the mistake + +Corollaries: + 1. Nobody whom you ask for help will see it. + 2. The first person who stops by, whose advice you really + don't want to hear, will see it immediately. +%% +Fine day to throw a party. Throw him as far as you can. +%% +Fine day to work off excess energy. Steal something heavy. +%% +First Law of Bicycling: + No matter which way you ride, it's uphill and against the + wind. +%% +First Law of Procrastination: + Procrastination shortens the job and places the responsibility + for its termination on someone else (i.e., the authority who + imposed the deadline). +%% +First Law of Socio-Genetics: + Celibacy is not hereditary. +%% +First Rule of History: + History doesn't repeat itself -- historians merely repeat each + other. +%% +Flappity, floppity, flip +The mouse on the m"obius strip; + The strip revolved, + The mouse dissolved +In a chronodimensional skip. +%% +FLASH! Intelligence of mankind decreasing. Details at ... uh, when +the little hand is on the .... +%% +Flon's Law: + There is not now, and never will be, a language in which it is + the least bit difficult to write bad programs. +%% +Flugg's Law: + When you need to knock on wood is when you realize that the + world is composed of vinyl, naugahyde and aluminum. +%% +For a good time, call (415) 642-9483 +%% +For an idea to be fashionable is ominous, since it must afterwards be +always old-fashioned. +%% +For every complex problem, there is a solution that is simple, neat, +and wrong. + -- H. L. Mencken +%% +For every credibility gap, there is a gullibility fill. + -- R. Clopton +%% + "For I perceive that behind this seemingly unrelated sequence +of events, there lurks a singular, sinister attitude of mind." + + "Whose?" + + "MINE! HA-HA!" +%% +For some reason a glaze passes over people's faces when you say +"Canada". Maybe we should invade South Dakota or something. + -- Sandra Gotlieb, wife of the Canadian ambassador to + the U.S. +%% +For some reason, this fortune reminds everyone of Marvin Zelkowitz. +%% +"For that matter, compare your pocket computer with the massive jobs of +a thousand years ago. Why not, then, the last step of doing away with +computers altogether?" + -- Jehan Shuman +%% +For those who like this sort of thing, this is the sort of thing they +like. + -- Abraham Lincoln +%% +For years a secret shame destroyed my peace -- +I'd not read Eliot, Auden or MacNiece. +But now I think a thought that brings me hope: +Neither had Chaucer, Shakespeare, Milton, Pope. + -- Justin Richardson. +%% +Forgetfulness, n.: + A gift of God bestowed upon debtors in compensation for their +destitution of conscience. +%% +Fortune's graffito of the week (or maybe even month): + + Don't Write On Walls! + + (and underneath) + + You want I should type? +%% +Fortune's nomination for All-Time Champion and Protector of Youthful +Morals goes to Representative Clare E. Hoffman of Michigan. During an +impassioned House debate over a proposed bill to "expand oyster and +clam research," a sharp-eared informant transcribed the following +exchange between our hero and Rep. John D. Dingell, also of Michigan. + +DINGELL: There are places in the world at the present time where we are + having to artificially propagate oysters and clams. +HOFFMAN: You mean the oysters I buy are not nature's oysters? +DINGELL: They may or may not be natural. The simple fact of the matter + is that female oysters through their living habits cast out + large amounts of seed and the male oysters cast out large + amounts of fertilization. +HOFFMAN: Wait a minute! I do not want to go into that. There are many + teenagers who read The Congressional Record. +%% +FORTUNE'S PARTY TIPS #14 + +Tired of finding that other people are helping themselves to your good +liquor at BYOB parties? Take along a candle, which you insert and +light after you've opened the bottle. No one ever expects anything +drinkable to be in a bottle which has a candle stuck in its neck. +%% +Fourth Law of Applied Terror: + The night before the English History mid-term, your Biology + instructor will assign 200 pages on planaria. +Corollary: + Every instructor assumes that you have nothing else to do + except study for that instructor's course. +%% +Fourth Law of Revision: + It is usually impractical to worry beforehand about + interferences -- if you have none, someone will make one for + you. +%% +Fresco's Discovery: + If you knew what you were doing you'd probably be bored. +%% +Friends, Romans, Hipsters, +Let me clue you in; +I come to put down Caeser, not to groove him. +The square kicks some cats are on stay with them; +The hip bits, like, go down under; so let it lay with Caeser. The cool Brutus +Gave you the message: Caeser had big eyes; +If that's the sound, someone's copping a plea, +And, like, old Caeser really set them straight. +Here, copacetic with Brutus and the studs, -- for Brutus is a real cool cat; +So are they all, all cool cats, -- +Come I to make this gig at Caeser's laying down. +%% +Frisbeetarianism, n.: + The belief that when you die, your soul goes up the on roof and +gets stuck. +%% +Frobnicate, v.: + To manipulate or adjust, to tweak. Derived from FROBNITZ. +Usually abbreviated to FROB. Thus one has the saying "to frob a +frob". See TWEAK and TWIDDLE. Usage: FROB, TWIDDLE, and TWEAK +sometimes connote points along a continuum. FROB connotes aimless +manipulation; TWIDDLE connotes gross manipulation, often a coarse +search for a proper setting; TWEAK connotes fine-tuning. If someone is +turning a knob on an oscilloscope, then if he's carefully adjusting it +he is probably tweaking it; if he is just turning it but looking at the +screen he is probably twiddling it; but if he's just doing it because +turning a knob is fun, he's frobbing it. +%% +From too much love of living, +From hope and fear set free, +We thank with brief thanksgiving, +Whatever gods may be, +That no life lives forever, +That dead men rise up never, +That even the weariest river winds somewhere safe to sea. + -- Swinburne +%% +Fudd's First Law of Opposition: + Push something hard enough and it will fall over. +%% +Furbling, v.: + Having to wander through a maze of ropes at an airport or bank +even when you are the only person in line. + -- Rich Hall, "Sniglets" +%% +Furious activity is no substitute for understanding. + -- H. H. Williams +%% +Future looks spotty. You will spill soup in late evening. +%% +G. B. Shaw to William Douglas Home: "Go on writing plays, my boy. One +of these days a London producer will go into his office and say to his +secretary, `Is there a play from Shaw this morning?' and when she says +`No,' he will say, `Well, then we'll have to start on the rubbish.' +And that's your chance, my boy." +%% +Garbage In -- Gospel Out. +%% +Garter, n.: + An elastic band intended to keep a woman from coming out of her +stockings and desolating the country. + -- Ambrose Bierce, "The Devil's Dictionary" +%% +Gauls! We have nothing to fear; except perhaps that the sky may fall +on our heads tomorrow. But as we all know, tomorrow never comes!! + -- Adventures of Asterix. +%% +Gay shlafen: Yiddish for "go to sleep". + + Now doesn't "gay shlafen" have a softer, more soothing sound +than the harsh, staccato "go to sleep"? Listen to the difference: + "Go to sleep, you little wretch!" ... "Gay shlafen, darling." +Obvious, isn't it? + Clearly the best thing you can do for you children is to start +speaking Yiddish right now and never speak another word of English as +long as you live. This will, of course, entail teaching Yiddish to all +your friends, business associates, the people at the supermarket, and +so on, but that's just the point. It has to start with committed +individuals and then grow ... + Some minor adjustments will have to be made, of course: those +signs written in what look like Yiddish letters won't be funny when +everything is written in Yiddish. And we'll have to start driving on +the left side of the road so we won't be reading the street signs +backwards. But is that too high a price to pay for world peace? I +think not, my friend, I think not. + -- Arthur Naiman, "Every Goy's Guide to Yiddish" +%% + "Gee, Mudhead, everyone at Morse Science High has an +extracurricular activity except you." + "Well, gee, doesn't Louise count?" + "Only to ten, Mudhead." + + -- Firesign Theater +%% + GEMINI (May 21 - June 20) +You are a quick and intelligent thinker. People like you because you +are bisexual. However, you are inclined to expect too much for too +little. This means you are cheap. Geminis are known for committing +incest. +%% +GEMINI (May 21 to Jun. 20) + Good news and bad news highlighted. Enjoy the good news while + you can; the bad news will make you forget it. You will enjoy + praise and respect from those around you; everybody loves a + sucker. A short trip is in the stars, possibly to the men's + room. +%% +Genderplex, n.: + The predicament of a person in a restaurant who is unable to +determine his or her designated restroom (e.g., turtles and +tortoises). + -- Rich Hall, "Sniglets" +%% +Genetics explains why you look like your father, and if you don't, why +you should. +%% +Genius may have its limitations, but stupidity is not thus +handicapped. + -- Elbert Hubbard +%% +Genius, n.: + A chemist who discovers a laundry additive that rhymes with +"bright". +%% +George Orwell was an optimist. +%% +Gerrold's Laws of Infernal Dynamics: + 1. An object in motion will always be headed in the wrong + direction. + 2. An object at rest will always be in the wrong place. + 3. The energy required to change either one of these states + will always be more than you wish to expend, but never so + much as to make the task totally impossible. +%% +Get forgiveness now -- tomorrow you may no longer feel guilty. +%% +Get Revenge! Live long enough to be a problem for your children! +%% + -- Gifts for Children -- + +This is easy. You never have to figure out what to get for children, +because they will tell you exactly what they want. They spend months +and months researching these kinds of things by watching Saturday- +morning cartoon-show advertisements. Make sure you get your children +exactly what they ask for, even if you disapprove of their choices. If +your child thinks he wants Murderous Bob, the Doll with the Face You +Can Rip Right Off, you'd better get it. You may be worried that it +might help to encourage your child's antisocial tendencies, but believe +me, you have not seen antisocial tendencies until you've seen a child +who is convinced that he or she did not get the right gift. + -- Dave Barry, "Christmas Shopping: A Survivor's Guide" +%% + -- Gifts for Men -- + +Men are amused by almost any idiot thing -- that is why professional +ice hockey is so popular -- so buying gifts for them is easy. But you +should never buy them clothes. Men believe they already have all the +clothes they will ever need, and new ones make them nervous. For +example, your average man has 84 ties, but he wears, at most, only +three of them. He has learned, through humiliating trial and error, +that if he wears any of the other 81 ties, his wife will probably laugh +at him ("You're not going to wear THAT tie with that suit, are you?"). +So he has narrowed it down to three safe ties, and has gone several +years without being laughed at. If you give him a new tie, he will +pretend to like it, but deep inside he will hate you. + +If you want to give a man something practical, consider tires. More +than once, I would have gladly traded all the gifts I got for a new set +of tires. + -- Dave Barry, "Christmas Shopping: A Survivor's Guide" +%% + Gimmie That Old Time Religion +We will follow Zarathustra, We will worship like the Druids, +Zarathustra like we use to, Dancing naked in the woods, +I'm a Zarathustra booster, Drinking strange fermented fluids, +And he's good enough for me! And it's good enough for me! + (chorus) (chorus) + +In the church of Aphrodite, +The priestess wears a see through nightie, +She's a mighty righteous sightie, +And she's good enough for me! + (chorus) + +CHORUS: Give me that old time religion, + Give me that old time religion, + Give me that old time religion, + 'Cause it's good enough for me! +%% +Ginsberg's Theorem: + 1. You can't win. + 2. You can't break even. + 3. You can't even quit the game. + +Freeman's Commentary on Ginsberg's theorem: + + Every major philosophy that attempts to make life seem + meaningful is based on the negation of one part of Ginsberg's + Theorem. To wit: + + 1. Capitalism is based on the assumption that you can win. + 2. Socialism is based on the assumption that you can break + even. + 3. Mysticism is based on the assumption that you can quit the + game. +%% +Give me a Plumber's friend the size of the Pittsburgh dome, and a place +to stand, and I will drain the world. +%% +Give me the Luxuries, and the Hell with the Necessities! +%% +Give thought to your reputation. Consider changing name and moving to +a new town. +%% +Give your child mental blocks for Christmas. +%% +Glib's Fourth Law of Unreliability: + Investment in reliability will increase until it exceeds the + probable cost of errors, or until someone insists on getting + some useful work done. +%% +Go 'way! You're bothering me! +%% +Go placidly amid the noise and waste, and remember what value there may +be in owning a piece thereof. + -- National Lampoon, "Deteriorada" +%% +//GO.SYSIN DD *, DOODAH, DOODAH +%% +God did not create the world in 7 days; he screwed around for 6 days +and then pulled an all-nighter. +%% +"God gives burdens; also shoulders" + + Jimmy Carter cited this Jewish saying in his concession speech +at the end of the 1980 election. At least he said it was a Jewish +saying; I can't find it anywhere. I'm sure he's telling the truth +though; why would he lie about a thing like that? + -- Arthur Naiman, "Every Goy's Guide to Yiddish" +%% +God has intended the great to be great and the little to be little ... +The trade unions, under the European system, destroy liberty ... I do +not mean to say that a dollar a day is enough to support a workingman +... not enough to support a man and five children if he insists on +smoking and drinking beer. But the man who cannot live on bread and +water is not fit to live! A family may live on good bread and water in +the morning, water and bread at midday, and good bread and water at +night! + -- Rev. Henry Ward Beecher +%% +God is a comic playing to an audience that's afraid to laugh +%% +God is a polythiest +%% +God is Dead + -- Nietzsche +Nietzsche is Dead + -- God +Nietzsche is God + -- The Dead +%% +God is not dead! He's alive and autographing bibles at Cody's +%% +God is real, unless declared integer. +%% +God is really only another artist. He invented the giraffe, the +elephant and the cat. He has no real style, He just goes on trying +other things. + -- Pablo Picasso +%% +God is the tangential point between zero and infinity. + -- Alfred Jarry +%% +God isn't dead, he just couldn't find a parking place. +%% +God made machine language; all the rest is the work of man. +%% +God made the Idiot for practice, and then He made the School Board + -- Mark Twain +%% +God made the integers; all else is the work of Man. + -- Kronecker +%% +God made the world in six days, and was arrested on the seventh. +%% +God may be subtle, but He isn't plain mean. + -- Albert Einstein +%% +God must love the Common Man; He made so many of them. +%% +God rest ye CS students now, +Let nothing you dismay. +The VAX is down and won't be up, +Until the first of May. +The program that was due this morn, +Won't be postponed, they say. + + Oh, tidings of comfort and joy, + Comfort and joy, + Oh, tidings of comfort and joy. + +The bearings on the drum are gone, +The disk is wobbling, too. +We've found a bug in Lisp, and Algol +Can't tell false from true. +And now we find that we can't get +At Berkeley's 4.2. + + (chorus) +%% +Going to church does not make a person religious, nor does going to +school make a person educated, any more than going to a garage makes a +person a car. +%% +Gold, n.: + A soft malleable metal relatively scarce in distribution. It +is mined deep in the earth by poor men who then give it to rich men who +immediately bury it back in the earth in great prisons, although gold +hasn't done anything to them. + -- Mike Harding, "The Armchair Anarchist's Almanac" +%% +Goldenstern's Rules: + 1. Always hire a rich attorney + 2. Never buy from a rich salesman. +%% +Good advice is something a man gives when he is too old to set a bad +example. + -- La Rouchefoucauld +%% +Good day for a change of scene. Repaper the bedroom wall. +%% +Good day for overcoming obstacles. Try a steeplechase. +%% +Good day to avoid cops. Crawl to school. +%% +Good day to let down old friends who need help. +%% +Good leaders being scarce, following yourself is allowed. +%% +Good news is just life's way of keeping you off balance. +%% +Good news. Ten weeks from Friday will be a pretty good day. +%% +Good night to spend with family, but avoid arguments with your mate's +new lover. +%% +Good-bye. I am leaving because I am bored. + -- George Saunders' dying words +%% +Got Mole problems? +Call Avogardo 6.02 x 10^23 +%% +Goto, n.: + A programming tool that exists to allow structured programmers +to complain about unstructured programmers. + -- Ray Simard +%% +Goy: ... The distinction between Jewish and goyish can be quite subtle, +as the following quote from Lenny Bruce illustrates: + + "I'm Jewish. Count Basie's Jewish. Ray Charles is Jewish. +Eddie Cantor's goyish. The B'nai Brith is goyish. The Hadassah is +Jewish. Marine Corps -- heavy goyish, dangerous. + "Kool-Aid is goyish. All Drake's Cakes are goyish. +Pumpernickel is Jewish and, as you know, white bread is very goyish. +Instant potatoes -- goyish. Black cherry soda's very Jewish. +Macaroons are ____very Jewish. Fruit salad is Jewish. Lime Jell-O is +goyish. Lime soda is ____very goyish. Trailer parks are so goyish that +Jews won't go near them ..." + -- Arthur Naiman, "Every Goy's Guide to Yiddish" +%% +Grabel's Law: + 2 is not equal to 3 -- not even for large values of 2. +%% +Graduate life -- it's not just a job, it's an indenture. +%% +Grandpa Charnock's Law: + You never really learn to swear until you learn to drive. +%% +Gravity is a myth, the Earth sucks. +%% +Gray's Law of Programming: + `_n+1' trivial tasks are expected to be accomplished in the same + time as `_n' tasks. + +Logg's Rebuttal to Gray's Law: + `_n+1' trivial tasks take twice as long as `_n' trivial tasks. +%% + GREAT MOMENTS IN AMERICAN HISTORY (#21) -- July 30, 1917 + +On this day, New York City hotel detectives burst in and caught then- +Senator Warren G. Harding in bed with an underage girl. He bought them +off with a $20 bribe, and later remarked thankfully, "I thought I +wouldn't get out of that under $1000!" Always one to learn from his +mistakes, in later years President Harding carried on his affairs in a +tiny closet in the White House Cabinet Room while Secret Service men +stood lookout. +%% +Green light in A.M. for new projects. Red light in P.M. for traffic +tickets. +%% +Greener's Law: + Never argue with a man who buys ink by the barrel. +%% +Grelb's Reminder: + Eighty percent of all people consider themselves to be above + average drivers. +%% +"Grub first, then ethics." + -- Bertolt Brecht +%% +Gyroscope, n.: + A wheel or disk mounted to spin rapidly about an axis and also +free to rotate about one or both of two axes perpendicular to each +other and the axis of spin so that a rotation of one of the two +mutually perpendicular axes results from application of torque to the +other when the wheel is spinning and so that the entire apparatus +offers considerable opposition depending on the angular momentum to any +torque that would change the direction of the axis of spin. + -- Webster's Seventh New Collegiate Dictionary +%% +H. L. Mencken's Law: + Those who can -- do. + Those who can't -- teach. + +Martin's Extension: + Those who cannot teach -- administrate. +%% +Hacker's Law: + The belief that enhanced understanding will necessarily stir + a nation to action is one of mankind's oldest illusions. +%% +Hacking's just another word for nothing left to kludge. +%% +... Had this been an actual emergency, we would have fled in terror, +and you would not have been informed. +%% +Hail to the sun god +He sure is a fun god +Ra! Ra! Ra! +%% +Half Moon tonight. (At least it's better than no Moon at all.) +%% +Half-done: This is the best way to eat a kosher dill -- when it's still +crunchy, light green, yet full of garlic flavor. The difference +between this and the typical soggy dark green cucumber corpse is like +the the difference between life and death. + You may find it difficult to find a good half-done kosher dill +there in Seattle, so what you should do is take a cab out to the +airport, fly to New York, take the JFK Express to Jay Street-Borough +Hall, transfer to an uptown F, get off at East Broadway, walk north on +Essex (along the park), make your first left onto Hester Street, walk +about fifteen steps, turn ninety degrees left, and stop. Say to the +man, "Let me have a nice half-done." + Worth the trouble, wasn't it? + -- Arthur Naiman, "Every Goy's Guide to Yiddish" +%% +Hall's Laws of Politics: + (1) The voters want fewer taxes and more spending. + (2) Citizens want honest politicians until they want something + fixed. + (3) Constituency drives out consistency (i.e., liberals defend + military spending, and conservatives social spending in + their own districts). +%% +Hand, n.: + A singular instrument worn at the end of a human arm and +commonly thrust into somebody's pocket. + -- Ambrose Bierce, "The Devil's Dictionary" +%% +Hanlon's Razor: + Never attribute to malice that which is adequately explained by + stupidity. +%% +Hanson's Treatment of Time: + There are never enough hours in a day, but always too many days + before Saturday. +%% +Happiness is having a scratch for every itch. + -- Ogden Nash +%% +Happiness isn't something you experience; it's something you remember. + -- Oscar Levant +%% +Happiness, n.: + An agreeable sensation arising from contemplating the misery of +another. + -- Ambrose Bierce, "The Devil's Dictionary" +%% +Hardware, n.: + The parts of a computer system that can be kicked. +%% +Hark, Hark, the dogs do bark +The Duke is fond of kittens +He likes to take their insides out +And use them for his mittens + From "The Thirteen Clocks" +%% +Hark, the Herald Tribune sings, +Advertising wondrous things. + -- Tom Leher +%% +Harris's Lament: + All the good ones are taken. +%% +Harrisberger's Fourth Law of the Lab: + Experience is directly proportional to the amount of + equipment ruined. +%% +Harry is heavily into camping, and every year in the late fall, he +makes us all go to Assateague, which is an island on the Atlantic Ocean +famous for its wild horses. I realize that the concept of wild horses +probably stirs romantic notions in many of you, but this is because you +have never met any wild horses in person. In person, they are like +enormous hooved rats. They amble up to your camp site, and their +attitude is: "We're wild horses. We're going to eat your food, knock +down your tent and poop on your shoes. We're protected by federal law, +just like Richard Nixon." + -- Dave Barry, "Tenting Grandpa Bob" +%% +Hartley's First Law: + You can lead a horse to water, but if you can get him to float + on his back, you've got something. +%% +Hartley's Second Law: + Never sleep with anyone crazier than yourself. +%% +Harvard Law: + Under the most rigorously controlled conditions of pressure, + temperature, volume, humidity, and other variables, the + organism will do as it damn well pleases. +%% +Has everyone noticed that all the letters of the word "database" are +typed with the left hand? Now the layout of the QWERTYUIOP typewriter +keyboard was designed, among other things, to facilitate the even use +of both hands. It follows, therefore, that writing about databases is +not only unnatural, but a lot harder than it appears. +%% + Has your family tried 'em? + + POWDERMILK BISCUITS + + Heavens, they're tasty and expeditious! + + They're made from whole wheat, to give shy persons + the strength to get up and do what needs to be done. + + POWDERMILK BISCUITS + + Buy them ready-made in the big blue box with the picture of + the biscuit on the front, or in the brown bag with the dark + stains that indicate freshness. +%% +Hatred, n.: + A sentiment appropriate to the occasion of another's +superiority. + -- Ambrose Bierce, "The Devil's Dictionary" +%% +Have you ever noticed that the people who are always trying to tell +you, "There's a time for work and a time for play," never find the time +for play? +%% +Have you noticed that all you need to grow healthy, vigorous grass is a +crack in your sidewalk? +%% +He had that rare weird electricity about him -- that extremely wild and +heavy presence that you only see in a person who has abandoned all hope +of ever behaving "normally." + -- Hunter S. Thompson, "Fear and Loathing '72" +%% +He hadn't a single redeeming vice. + -- Oscar Wilde +%% +"He is now rising from affluence to poverty." + -- Mark Twain +%% +He looked at me as if I was a side dish he hadn't ordered. +%% +He played the king as if afraid someone else would play the ace. + -- John Mason Brown, drama critic +%% +He thought he saw an albatross +That fluttered 'round the lamp. +He looked again and saw it was +A penny postage stamp. +"You'd best be getting home," he said, +"The nights are rather damp." +%% +"He was so narrow minded he could see through a keyhole with both +eyes ..." +%% +He who attacks the fundamentals of the American broadcasting industry +attacks democracy itself. + -- William S. Paley, chairman of CBS +%% +He who Laughs, Lasts. +%% +"He's just a politician trying to save both his faces ..." +%% +He's the kind of guy, that, well, if you were ever in a jam he'd be +there ... with two slices of bread and some chunky peanut butter. +%% +"He's the kind of man for the times that need the kind of man he is ..." +%% +HE: Let's end it all, bequeathin' our brains to science. +SHE: What?!? Science got enough trouble with their OWN brains. + -- Walt Kelley +%% +Health is merely the slowest possible rate at which one can die. +%% +Heaven, n.: + A place where the wicked cease from troubling you with talk of +their personal affairs, and the good listen with attention while you +expound your own. + -- Ambrose Bierce, "The Devil's Dictionary" +%% +Heavy, adj.: + Seduced by the chocolate side of the force. +%% +"Heisenberg may have slept here" +%% +Hell hath no fury like a bureaucrat scorned. + -- Milton Friedman +%% +Heller's Law: + The first myth of management is that it exists. + +Johnson's Corollary: + Nobody really knows what is going on anywhere within the + organization. +%% +Help a swallow land at Capistrano. +%% +Help! I'm trapped in a PDP 11/70! +%% +Her locks an ancient lady gave +Her loving husband's life to save; +And men -- they honored so the dame -- +Upon some stars bestowed her name. + +But to our modern married fair, +Who'd give their lords to save their hair, +No stellar recognition's given. +There are not stars enough in heaven. +%% +"Here at the Phone Company, we serve all kinds of people; from +Presidents and Kings to the scum of the earth ..." +%% +Here I sit, broken-hearted, +All logged in, but work unstarted. +First net.this and net.that, +And a hot buttered bun for net.fat. + +The boss comes by, and I play the game, +Then I turn back to net.flame. +Is there a cure (I need your views), +For someone trapped in net.news? + +I need your help, I say 'tween sobs, +'Cause I'll soon be listed in net.jobs. +%% +Here in my heart, I am Helen; + I'm Aspasia and Hero, at least. +I'm Judith, and Jael, and Madame de Sta"el; + I'm Salome, moon of the East. + +Here in my soul I am Sappho; + Lady Hamilton am I, as well. +In me R'ecamier vies with Kitty O'Shea, + With Dido, and Eve, and poor nell. + +I'm all of the glamorous ladies + At whose beckoning history shook. +But you are a man, and see only my pan, + So I stay at home with a book. + -- Dorothy Parker +%% +Here is a simple experiment that will teach you an important electrical +lesson: On a cool, dry day, scuff your feet along a carpet, then reach +your hand into a friend's mouth and touch one of his dental fillings. +Did you notice how your friend twitched violently and cried out in +pain? This teaches us that electricity can be a very powerful force, +but we must never use it to hurt others unless we need to learn an +important electrical lesson. + +It also teaches us how an electrical circuit works. When you scuffed +your feet, you picked up batches of "electrons", which are very small +objects that carpet manufacturers weave into carpets so they will +attract dirt. The electrons travel through your bloodstream and +collect in your finger, where they form a spark that leaps to your +friend's filling, then travels down to his feet and back into the +carpet, thus completing the circuit. + +Amazing Electronic Fact: If you scuffed your feet long enough without +touching anything, you would build up so many electrons that your +finger would explode! But this is nothing to worry about unless you +have carpeting. + -- Dave Barry, "What is Electricity?" +%% + Here is the fact of the week, maybe even the fact of the +month. According to probably reliable sources, the Coca-Cola people +are experiencing severe marketing anxiety in China. + The words "Coca-Cola" translate into Chinese as either +(depending on the inflection) "wax-fattened mare" or "bite the wax +tadpole". + Bite the wax tadpole. + There is a sort of rough justice, is there not? + The trouble with this fact, as lovely as it is, is that it's +hard to get a whole column out of it. I'd like to teach the world to +bite a wax tadpole. Coke -- it's the real wax-fattened mare. Not bad, +but broad satiric vistas do not open up. + -- John Carrol, San Francisco Chronicle +%% +Heuristics are bug ridden by definition. If they didn't have bugs, +then they'd be algorithms. +%% +"Hey! Who took the cork off my lunch??!" + -- W. C. Fields +%% +Hi there! This is just a note from me, to you, to tell you, the person +reading this note, that I can't think up any more famous quotes, jokes, +nor bizarre stories, so you may as well go home. +%% +Higgeldy Piggeldy, +Hamlet of Elsinore +Ruffled the critics by +Dropping this bomb: +"Phooey on Freud and his +Psychoanalysis -- +Oedipus, Shmoedipus, +I just loved Mom." +%% +Hindsight is an exact science. +%% +Hippogriff, n.: + An animal (now extinct) which was half horse and half griffin. +The griffin was itself a compound creature, half lion and half eagle. +The hippogriff was actually, therefore, only one quarter eagle, which +is two dollars and fifty cents in gold. The study of zoology is full +of surprises. + -- Ambrose Bierce, "The Devil's Dictionary" +%% +Hire the morally handicapped. +%% +"His mind is like a steel trap -- full of mice" + -- Foghorn Leghorn +%% +"His super power is to turn into a scotch terrier." +%% +History repeats itself. That's one thing wrong with history. +%% +Hlade's Law: + If you have a difficult task, give it to a lazy person -- they + will find an easier way to do it. +%% +Hoare's Law of Large Problems: + Inside every large problem is a small problem struggling to get + out. +%% +Hofstadter's Law: + It always takes longer than you expect, even when you take + Hofstadter's Law into account. +%% +Hollywood is where if you don't have happiness you send out for it. + -- Rex Reed +%% +"Honesty is the best policy, but insanity is a better defense" +%% +Honesty pays, but it doesn't seem to pay enough to suit some people. + -- F. M. Hubbard +%% +Honk if you hate bumper stickers that say "Honk if ..." +%% +Honk if you love peace and quiet. +%% +Honorable, adj.: + Afflicted with an impediment in one's reach. In legislative +bodies, it is customary to mention all members as honorable; as, "the +honorable gentleman is a scurvy cur." + -- Ambrose Bierce, "The Devil's Dictionary" +%% +Horngren's Observation: + Among economists, the real world is often a special case. +%% +Horngren's Observation: + Among economists, the real world is often a special case. +%% +Horse sense is the thing a horse has which keeps it from betting on +people. + -- W. C. Fields +%% +How can you be in two places at once when you're not anywhere at all? +%% +How come only your friends step on your new white sneakers? +%% +How come wrong numbers are never busy? +%% +How do you explain school to a higher intelligence? + -- Elliot, "E.T." +%% +How doth the little crocodile + Improve his shining tail, +And pour the waters of the Nile + On every golden scale! + +How cheerfully he seems to grin, + How neatly spreads his claws, +And welcomes little fishes in, + With gently smiling jaws! + -- Lewis Carrol, "Alice in Wonderland" +%% +How doth the VAX's C compiler +Improve its object code. +And even as we speak does it +Increase the system load. + +How patiently it seems to run +And spit out error flags, +While users, with frustration, all +Tear their clothes to rags. +%% +How doth the VAX's C-compiler +Improve its object code. +And even as we speak does it +Increase the system load. + +How patiently it seems to run +And spit out error flags, +While users, with frustration, all +Tear all their clothes to rags. +%% +How long a minute is depends on which side of the bathroom door you're +on. +%% +How many hardware engineers does it take to change a lightbulb? +None: "We'll fix it in software." + +How many software engineers does it take to change a lightbulb? +None: "We'll document it in the manual." + +How many tech writers does it take to change a lightbulb? +None: "The user can work it out." +%% +How many Zen masters does it take to screw in a light bulb? + +None. The Universe spines the bulb, and the Zen master stays out of +the way. +%% +How much does it cost to entice a dope-smoking UNIX system guru to +Dayton? + -- Brian Boyle, UNIX/WORLD's First Annual Salary Survey +%% +How wonderful opera would be if there were no singers. +%% +Howe's Law: + Everyone has a scheme that will not work. +%% +However, never daunted, I will cope with adversity in my traditional +manner ... sulking and nausea. + -- Tom K. Ryan +%% +Human beings were created by water to transport it uphill. +%% +Human cardiac catheterization was introduced by Werner Forssman in +1929. Ignoring his department chief, and tying his assistant to an +operating table to prevent his interference, he placed a uretheral +catheter into a vein in his arm, advanced it to the right atrium [of +his heart], and walked upstairs to the x-ray department where he took +the confirmatory x-ray film. In 1956, Dr. Forssman was awarded the +Nobel Prize. +%% +Hummingbirds never remember the words to songs. +%% +"Humor is a drug which it's the fashion to abuse." + -- William Gilbert +%% +Hurewitz's Memory Principle: + The chance of forgetting something is directly proportional + to ..... to ........ uh .............. +%% +I am changing my name to Crysler +I am going down to Washington, D.C. +I will tell some power broker + What they did for Iacocca +Will be perfectly acceptable to me! +I am changing my name to Chrysler, +I am heading for that great receiving line. +When they hand a million grand out, + I'll be standing with my hand out, +Yessir, I'll get mine! +%% +"I am not an Economist. I am an honest man!" + -- Paul McCracken +%% +I am not now, and never have been, a girl friend of Henry Kissinger. + -- Gloria Steinem +%% +"I am not sure what this is, but an `F' would only dignify it." + -- English Professor +%% +I am ready to meet my Maker. Whether my Maker is prepared for the +great ordeal of meeting me is another matter. + -- Winston Churchill +%% +"I am returning this otherwise good typing paper to you because someone +has printed gibberish all over it and put your name at the top." + --English Professor, Ohio University +%% +I am the mother of all things, and all things should wear a sweater. +%% +I am, in point of fact, a particularly haughty and exclusive person, of +pre-Adamite ancestral descent. You will understand this when I tell +you that I can trace my ancestry back to a protoplasmal primordial +atomic globule. Consequently, my family pride is something +inconceivable. I can't help it. I was born sneering. + -- Pooh-Bah, "The Mikado", Gilbert & Sullivan +%% +I believe in getting into hot water; it keeps you clean. + -- G. K. Chesterton +%% +I belong to no organized party. I am a Democrat. + -- Will Rogers +%% +I bet the human brain is a kludge. + -- Marvin Minsky +%% +I can resist anything but temptation. +%% +I can't complain, but sometimes I still do. + -- Joe Walsh +%% +I cannot and will not cut my conscience to fit this year's fashions. + -- Lillian Hellman +%% +I cannot overemphasize the importance of good grammar. + +What a crock. I could easily overemphasize the importance of good +grammar. For example, I could say: "Bad grammar is the leading cause +of slow, painful death in North America," or "Without good grammar, the +United States would have lost World War II." + -- Dave Barry, "An Utterly Absurd Look at Grammar" +%% + "I cannot read the fiery letters," said Frodo in a quavering +voice. + "No," Said Gandalf, "but I can. The letters are Elvish, of +course, of an ancient mode, but the language is that of Mordor, which +I will not utter here. They are lines of a verse long known in +Elven-lore: + + "This Ring, no other, is made by the elves, + Who'd pawn their own mother to grab it themselves. + Ruler of creeper, mortal, and scallop, + This is a sleeper that packs quite a wallop. + The Power almighty rests in this Lone Ring. + The Power, alrighty, for doing your Own Thing. + If broken or busted, it cannot be remade. + If found, send to Sorhed (with postage prepaid)." +%% +I do not fear computers. I fear the lack of them. + -- Isaac Asimov +%% +I do not feel obliged to believe that the same God who has endowed us +with sense, reason, and intellect has intended us to forgo their use. + -- Galileo Galilei +%% +I do not know myself, and God forbid that I should. + -- Johann Wolfgang von Goethe +%% +I don't believe in astrology. But then I'm an Aquarius, and Aquarians +don't believe in astrology. + -- James R. F. Quirk +%% +"I don't care who does the electing as long as I get to do the +nominating" + -- Boss Tweed +%% +"I don't have any solution but I certainly admire the problem." + -- Ashleigh Brilliant +%% +I don't have to take this abuse from you -- I've got hundreds of people +waiting to abuse me. + --Bill Murray, "Ghostbusters" +%% + "I don't know what you mean by `glory,'" Alice said + Humpty Dumpty smiled contemptuously. "Of course you don't-- +till I tell you. I meant `there's a nice knock-down argument for +you!'" + "But glory doesn't mean `a nice knock-down argument,'" Alice +objected. + "When I use a word," Humpty Dumpty said, in a rather scornful +tone, "it means just what I choose it to mean -- neither more nor +less." + "The question is," said Alice, "whether you can make words mean +so many different things." + "The question is," said Humpty Dumpty, "which is to be master-- +that's all." + -- Lewis Carrol, "Through the Looking Glass" +%% +I don't like spinach, and I'm glad I don't, because if I liked it I'd +eat it, and I just hate it. + -- Clarence Darrow +%% +I don't object to sex before marriage, but two minutes before?!? +%% +I dread success. To have succeeded is to have finished one's business +on earth, like the male spider, who is killed by the female the moment +he has succeeded in his courtship. I like a state of continual +becoming, with a goal in front and not behind. + -- George Bernard Shaw +%% +"I drink to make other people interesting." + -- George Jean Nathan +%% +I for one cannot protest the recent M. T. A. fare hike and the +accompanying promises that this would in no way improve service. For +the transit system, as it now operates, has hidden advantages that +can't be measured in monetary terms. + +Personally, I feel that it is well worth 75 cents or even $1 to have +that unimpeachable excuse whenever I am late to anything: "I came by +subway." Those four words have such magic in them that if Godot should +someday show up and mumble them, any audience would instantly +understand his long delay. +%% +I for one cannot protest the recent M.T.A. fare hike and the +accompanying promises that this would in no way improve service. For +the transit system, as it now operates, has hidden advantages that +can't be measured in monetary terms. + +Personally, I feel that it is well worth 75 cents or even $1 to have +that unimpeachable excuse whenever I am late to anything: "I came by +subway." Those four words have such magic in them that if Godot should +someday show up and mumble them, any audience would instantly +understand his long delay. +%% +I generally avoid temptation unless I can't resist it. + -- Mae West +%% +I get up each morning, gather my wits. +Pick up the paper, read the obits. +If I'm not there I know I'm not dead. +So I eat a good breakfast and go back to bed. + +Oh, how do I know my youth is all spent? +My get-up-and-go has got-up-and-went. +But in spite of it all, I'm able to grin, +And think of the places my get-up has been. + -- Pete Seeger +%% +I hate quotations. + -- Ralph Waldo Emerson +%% +I have a simple philosophy: + + Fill what's empty. + Empty what's full. + Scratch where it itches. + -- A. R. Longworth +%% +I have learned +To spell hors d'oeuvres +Which still grates on +Some people's n'oeuvres. + -- Warren Knox +%% +I have made mistakes but I have never made the mistake of claiming that +I have never made one. + -- James Gordon Bennett +%% +I have made this letter longer than usual because I lack the time to +make it shorter. + -- Blaise Pascal +%% +I have seen the future and it is just like the present, only longer. + -- Kehlog Albran, "The Profit" +%% +I have the simplest tastes. I am always satisfied with the best. + -- Oscar Wilde +%% +I haven't lost my mind -- it's backed up on tape somewhere. +%% +I haven't lost my mind; I know exactly where I left it. +%% +"I just need enough to tide me over until I need more." + -- Bill Hoest +%% +"I know not with what weapons World War III will be fought, but +World War IV will be fought with sticks and stones." + -- Albert Einstein +%% +I like being single. I'm always there when I need me. + -- Art Leo +%% +I like work ... +I can sit and watch it for hours. +%% +I like your game but we have to change the rules. +%% +"I may not be totally perfect, but parts of me are excellent." + -- Ashleigh Brilliant +%% +"I must have a prodigious quantity of mind; it takes me as much as a +week sometimes to make it up." + -- Mark Twain, "The Innocents Abroad" +%% +I must have slipped a disk -- my pack hurts +%% +I never fail to convince an audience that the best thing they could do +was to go away. +%% +I never met a piece of chocolate I didn't like. +%% +I profoundly believe it takes a lot of practice to become a moral +slob. + -- William F. Buckley +%% + "I quite agree with you," said the Duchess; "and the moral of +that is -- `Be what you would seem to be' -- or, if you'd like it put +more simply -- `Never imagine yourself not to be otherwise than what it +might appear to others that what you were or might have been was not +otherwise than what you had been would have appeared to them to be +otherwise.'" + -- Lewis Carrol, "Alice in Wonderland" +%% +I really hate this damned machine +I wish that they would sell it. +It never does quite what I want +But only what I tell it. +%% +"I refuse to have a battle of wits with an unarmed person." +%% +I see the eigenvalue in thine eye, +I hear the tender tensor in thy sigh. +Bernoulli would have been content to die +Had he but known such _a-squared cos 2(phi)! + -- Stanislaw Lem, "Cyberiad" +%% +I sent a letter to the fish, +I told them, "This is what I wish." +The little fishes of the sea, +They sent an answer back to me. +The little fishes' answer was +"We cannot do it, sir, because ..." +I sent a letter back to say +It would be better to obey. +But someone came to me and said +"The little fishes are in bed." +I said to him, and I said it plain +"Then you must wake them up again." +I said it very loud and clear, +I went and shouted in his ear. +But he was very stiff and proud, +He said "You needn't shout so loud." +And he was very proud and stiff, +He said "I'll go and wake them if ..." +I took a kettle from the shelf, +I went to wake them up myself. +But when I found the door was locked +I pulled and pushed and kicked and knocked, +And when I found the door was shut, +I tried to turn the handle, But ... + + "Is that all?" asked Alice. + "That is all." said Humpty Dumpty. "Goodbye." + -- Lewis Carrol, "Through the Looking Glass" +%% +I think that I shall never see +A billboard lovely as a tree. +Perhaps, unless the billboards fall +I'll never see a tree at all. + -- Ogden Nash +%% +I used to get high on life but lately I've built up a resistance. +%% +I used to think I was indecisive, but now I'm not so sure. +%% +"I want to buy a husband who, every week when I sit down to watch `St. +Elsewhere', won't scream, `FORGET IT, BLANCHE ... IT'S TIME FOR "HEE +HAW"!!'" + -- Berke Breathed, "Bloom County" +%% +I was gratified to be able to answer promptly, and I did. I said I +didn't know. + -- Mark Twain +%% +I went on to test the program in every way I could devise. I strained +it to expose its weaknesses. I ran it for high-mass stars and low-mass +stars, for stars born exceedingly hot and those born relatively cold. +I ran it assuming the superfluid currents beneath the crust to be +absent -- not because I wanted to know the answer, but because I had +developed an intuitive feel for the answer in this particular case. +Finally I got a run in which the computer showed the pulsar's +temperature to be less than absolute zero. I had found an error. I +chased down the error and fixed it. Now I had improved the program to +the point where it would not run at all. + -- George Greenstein, "Frozen Star: Of Pulsars, Black + Holes and the Fate of Stars" +%% +I wish there was a knob on the TV to turn up the intelligence. There's +a knob called "brightness", but it doesn't work. + -- Gallagher +%% +I wouldn't recommend sex, drugs or insanity for everyone, but they've +always worked for me. + -- Hunter S. Thompson +%% +I'd give my right arm to be ambidextrous. +%% +"I'd love to go out with you, but I did my own thing and now I've got +to undo it." +%% +"I'd love to go out with you, but I have to floss my cat." +%% +"I'd love to go out with you, but I have to stay home and see if I +snore." +%% +"I'd love to go out with you, but I never go out on days that end in +`Y.'" +%% +"I'd love to go out with you, but I want to spend more time with my +blender." +%% +"I'd love to go out with you, but I'm attending the opening of my +garage door." +%% +"I'd love to go out with you, but I'm converting my calendar watch from +Julian to Gregorian." +%% +"I'd love to go out with you, but I'm doing door-to-door collecting for +static cling." +%% +"I'd love to go out with you, but I'm having all my plants neutered." +%% +"I'd love to go out with you, but I'm staying home to work on my +cottage cheese sculpture." +%% +"I'd love to go out with you, but I'm taking punk totem pole carving." +%% +"I'd love to go out with you, but I've been scheduled for a karma +transplant." +%% +"I'd love to go out with you, but it's my parakeet's bowling night." +%% +"I'd love to go out with you, but my favorite commercial is on TV." +%% +"I'd love to go out with you, but the last time I went out, I never +came back." +%% +"I'd love to go out with you, but the man on television told me to say +tuned." +%% +"I'd love to go out with you, but there are important world issues that +need worrying about." +%% +I'd rather have a bottle in front of me than a frontal lobotomy. +%% +I'll grant the random access to my heart, +Thoul't tell me all the constants of thy love; +And so we two shall all love's lemmas prove +And in our bound partition never part. + -- Stanislaw Lem, "Cyberiad" +%% +I'm a creationist; I refuse to believe that I could have evolved from +man. +%% +I'm all for computer dating, but I wouldn't want one to marry my +sister. +%% +I'm fed up to the ears with old men dreaming up wars for young men to +die in. + -- George McGovern +%% +I'm in Pittsburgh. Why am I here? + -- Harold Urey, Nobel Laureate +%% +I'm N-ary the tree, I am, +N-ary the tree, I am, I am. +I'm getting traversed by the parser next door, +She's traversed me seven times before. +And ev'ry time it was an N-ary (N-ary!) +Never wouldn't ever do a binary. (No sir!) +I'm 'er eighth tree that was N-ary. +N-ary the tree I am, I am, +N-ary the tree I am. +%% +I'm not under the alkafluence of inkahol that some thinkle peep I am. +It's just the drunker I sit here the longer I get. +%% +I'm prepared for all emergencies but totally unprepared for everyday +life. +%% +I'm really enjoying not talking to you ... Let's not talk again ____REAL +soon ... +%% +I'm very good at integral and differential calculus, +I know the scientific names of beings animalculous; +In short, in matters vegetable, animal, and mineral, +I am the very model of a modern Major-General. + -- Gilbert & Sullivan, "Pirates of Penzance" +%% +IBM had a PL/I, + Its syntax worse than JOSS; +And everywhere this language went, + It was a total loss. +%% +Idiot Box, n.: + The part of the envelope that tells a person where to place the +stamp when they can't quite figure it out for themselves. + -- Rich Hall, "Sniglets" +%% +Idiot, n.: + A member of a large and powerful tribe whose influence in human +affairs has always been dominant and controlling. + -- Ambrose Bierce, "The Devil's Dictionary" +%% +If A = B and B = C, then A = C, except where void or prohibited by law. + -- Roy Santoro +%% +If a group of _N persons implements a COBOL compiler, there will be _N-1 +passes. Someone in the group has to be the manager. + -- T. Cheatham +%% +If a listener nods his head when you're explaining your program, wake +him up. +%% +If a President doesn't do it to his wife, he'll do it to his country. +%% +If all be true that I do think, +There be Five Reasons why one should Drink; +Good friends, good wine, or being dry, +Or lest we should be by-and-by, +Or any other reason why. +%% +If all else fails, immortality can always be assured by spectacular +error. + -- John Kenneth Galbraith +%% +If all the world's a stage, I want to operate the trap door. + -- Paul Beatty +%% +If all the world's economists were laid end to end, we wouldn't reach a +conclusion. + -- William Baumol +%% +If an S and an I and an O and a U +With an X at the end spell Su; +And an E and a Y and an E spell I, +Pray what is a speller to do? +Then, if also an S and an I and a G +And an HED spell side, +There's nothing much left for a speller to do +But to go commit siouxeyesighed. + -- Charles Follen Adams, "An Orthographic Lament" +%% +If anything can go wrong, it will. +%% +If at first you don't succeed, give up, no use being a damn fool. +%% +If at first you don't succeed, redefine success. +%% +If bankers can count, how come they have eight windows and only four +tellers? +%% +"If dolphins are so smart, why did Flipper work for television?" +%% +If entropy is increasing, where is it coming from? +%% +If everything is coming your way then you're in the wrong lane. +%% +... if forced to travel on an airplane, try and get in the cabin with +the Captain, so you can keep an eye on him and nudge him if he falls +asleep or point out any mountains looming up ahead ... + -- Mike Harding, "The Armchair Anarchist's Almanac" +%% +If God had intended Man to Smoke, He would have set him on Fire. +%% +If God had intended Man to Walk, He would have given him Feet. +%% +If God had intended Man to Watch TV, He would have given him Rabbit +Ears. +%% +If God had intended Men to Smoke, He would have put Chimneys in their +Heads. +%% +If God had meant for us to be in the Army, we would have been born with +green, baggy skin. +%% +If God had meant for us to be naked, we would have been born that way. +%% +If God had not given us sticky tape, it would have been necessary to +invent it. +%% +If God had wanted you to go around nude, He would have given you bigger +hands. +%% +If God is perfect, why did He create discontinuous functions? +%% +"If God lived on Earth, people would knock out all His windows." + -- Yiddish saying +%% +If I don't drive around the park, +I'm pretty sure to make my mark. +If I'm in bed each night by ten, +I may get back my looks again. +If I abstain from fun and such, +I'll probably amount to much; +But I shall stay the way I am, +Because I do not give a damn. + -- Dorothy Parker +%% +If I had a plantation in Georgia and a home in Hell, I'd sell the +plantation and go home. + -- Eugene P. Gallagher +%% +If I had any humility I would be perfect. + -- Ted Turner +%% +"If I had only known, I would have been a locksmith." + -- Albert Einstein +%% +If I kiss you, that is a psychological interaction. + +On the other hand, if I hit you over the head with a brick, that is +also a psychological interaction. + +The difference is that one is friendly and the other is not so +friendly. + +The crucial point is if you can tell which is which. + -- Dolph Sharp, "I'm O.K., You're Not So Hot" +%% +If I traveled to the end of the rainbow +As Dame Fortune did intend, +Murphy would be there to tell me +The pot's at the other end. + -- Bert Whitney +%% +If ignorance is bliss, why aren't there more happy people? +%% +If it's Tuesday, this must be someone else's fortune. +%% +If Jesus Christ were to come today, people would not even crucify him. +They would ask him to dinner, and hear what he had to say, and make fun +of it. + -- Thomas Carlyle +%% +If life is a stage, I want some better lighting. +%% +If little green men land in your back yard, hide any little green women +you've got in the house. + -- Mike Harding, "The Armchair Anarchist's Almanac" +%% +If mathematically you end up with the wrong answer, try multiplying by +the page number. +%% +If money can't buy happiness, I guess you'll just have to rent it. +%% +If only God would give me some clear sign! Like making a large deposit +in my name at a Swiss bank. + -- Woody Allen, "Without Feathers" +%% +If only I could be respected without having to be respectable. +%% +If only one could get that wonderful feeling of accomplishment without +having to accomplish anything. +%% +If scientific reasoning were limited to the logical processes of +arithmetic, we should not get very far in our understanding of the +physical world. One might as well attempt to grasp the game of poker +entirely by the use of the mathematics of probability. + -- Vannevar Bush +%% +If someone had told me I would be Pope one day, I would have studied +harder. + -- Pope John Paul I +%% +If the code and the comments disagree, then both are probably wrong. + -- Norm Schryer +%% +If the colleges were better, if they really had it, you would need to +get the police at the gates to keep order in the inrushing multitude. +See in college how we thwart the natural love of learning by leaving +the natural method of teaching what each wishes to learn, and insisting +that you shall learn what you have no taste or capacity for. The +college, which should be a place of delightful labor, is made odious +and unhealthy, and the young men are tempted to frivolous amusements to +rally their jaded spirits. I would have the studies elective. +Scholarship is to be created not by compulsion, but by awakening a pure +interest in knowledge. The wise instructor accomplishes this by +opening to his pupils precisely the attractions the study has for +himself. The marking is a system for schools, not for the college; for +boys, not for men; and it is an ungracious work to put on a professor. + -- Ralph Waldo Emerson +%% +"If the King's English was good enough for Jesus, it's good enough for +me!" + -- "Ma" Ferguson, Governor of Texas (circa 1920) +%% +If the odds are a million to one against something occurring, chances +are 50-50 it will. +%% +If the weather is extremely bad, church attendance will be down. If +the weather is extremely good, church attendance will be down. If the +bulletin covers are in short supply, however, church attendance will +exceed all expectations. + -- Reverend Chichester +%% +If there are epigrams, there must be meta-epigrams. +%% +If there is a possibility of several things going wrong, the one that +will cause the most damage will be the one to go wrong. +%% +If there is no God, who pops up the next Kleenex? + -- Art Hoppe +%% +If this fortune didn't exist, somebody would have invented it. +%% +If time heals all wounds, how come the belly button stays the same? +%% +If two men agree on everything, you may be sure that one of them is +doing the thinking. + -- Lyndon Baines Johnson +%% +If we do not change our direction we are likely to end up where we are +headed. +%% +If while you are in school, there is a shortage of qualified personnel +in a particular field, then by the time you graduate with the necessary +qualifications, that field's employment market is glutted. + -- Marguerite Emmons +%% +"If you can count your money, you don't have a billion dollars." + -- J. Paul Getty +%% +If you can lead it to water and force it to drink, it isn't a horse. +%% +If you can survive death, you can probably survive anything. +%% +If you can't be good, be careful. If you can't be careful, give me a +call. +%% +If you can't learn to do it well, learn to enjoy doing it badly. +%% +If you cannot convince them, confuse them. + -- Harry S Truman +%% +If you didn't get caught, did you really do it? +%% +If you don't care where you are, then you ain't lost. +%% +If you explain so clearly that nobody can misunderstand, somebody +will. +%% +If you give Congress a chance to vote on both sides of an issue, it +will always do it. + -- Les Aspin, D., Wisconsin +%% +"If you go on with this nuclear arms race, all you are going to do is +make the rubble bounce" + -- Winston Churchill +%% +If you had any brains, you'd be dangerous. +%% +If you have a procedure with 10 parameters, you probably missed some. +%% +"If you have to hate, hate gently" +%% +If you live in a country run by committee, be on the committee. + -- Graham Summer +%% +If you make people think they're thinking, they'll love you; but if you +really make them think they'll hate you. +%% +If you only have a hammer, you tend to see every problem as a nail. + -- Maslow +%% +If you perceive that there are four possible ways in which a procedure +can go wrong, and circumvent these, then a fifth way will promptly +develop. +%% +If you pick up a starving dog and make him prosperous, he will not bite +you. This is the principal difference between a dog and a man. + -- Mark Twain +%% +If you push the "extra ice" button on the soft drink vending machine, +you won't get any ice. If you push the "no ice" button, you'll get +ice, but no cup. +%% +If you put garbage in a computer nothing comes out but garbage. But +this garbage, having passed through a very expensive machine, is +somehow enobled and none dare criticize it. +%% +If you think education is expensive, try ignorance. + -- Derek Bok, president of Harvard +%% +If you think last Tuesday was a drag, wait till you see what happens +tomorrow! +%% +If you think nobody cares if you're alive, try missing a couple of car +payments. + -- Earl Wilson +%% +If you think the United States has stood still, who built the largest +shopping center in the world? + -- Richard M. Nixon +%% +If you think the United States has stood still, who built the largest +shopping center in the world? + -- Richard Nixon +%% +If you throw a New Year's Party, the worst thing that you can do would +be to throw the kind of party where your guests wake up today, and call +you to say they had a nice time. Now you'll be be expected to throw +another party next year. + +What you should do is throw the kind of party where your guest wake up +several days from now and call their lawyers to find out if they've +been indicted for anything. You want your guests to be so anxious to +avoid a recurrence of your party that they immediately start planning +parties of their own, a year in advance, just to prevent you from +having another one ... + +If your party is successful, the police will knock on your door, unless +your party is very successful in which case they will lob tear gas +through your living room window. As host, your job is to make sure +that they don't arrest anybody. Or if they're dead set on arresting +someone, your job is to make sure it isn't you ... +%% +If you want your spouse to listen and pay strict attention to every +word you say, talk in your sleep. +%% +"If you wants to get elected president, you'se got to think up some +memoraboble homily so's school kids can be pestered into memorizin' +it, even if they don't know what it means." + -- Walt Kelly, "The Pogo Party" +%% +If you're going to do something tonight that you'll be sorry for +tomorrow morning, sleep late. + -- Henny Youngman +%% +If you're happy, you're successful. +%% +If you're not part of the solution, you're part of the precipitate. +%% +If you're not very clever you should be conciliatory. + -- Benjamin Disraeli +%% +If you've done six impossible things before breakfast, why not round it +off with dinner at Milliway's, the restaurant at the end of the +universe? +%% +If you've seen one redwood, you've seen them all. + -- Ronald Reagan +%% +Il brilgue: les t^oves libricilleux + Se gyrent et frillant dans le guave, +Enm^im'es sont les gougebosquex, + Et le m^omerade horgrave. + -- Lewis Carrol, "Through the Looking Glass" +%% +Illinois isn't exactly the land that God forgot -- it's more like the +land He's trying to ignore. +%% +Imagination is the one weapon in the war against reality. + -- Jules de Gaultier +%% +Imagine that Cray computer decides to make a personal computer. It has +a 150 MHz processor, 200 megabytes of RAM, 1500 megabytes of disk +storage, a screen resolution of 1024 x 1024 pixels, relies entirely on +voice recognition for input, fits in your shirt pocket and costs $300. +What's the first question that the computer community asks? + +"Is it PC compatible?" +%% +Immortality -- a fate worse than death. + -- Edgar A. Shoaff +%% +Impartial, adj.: + Unable to perceive any promise of personal advantage from +espousing either side of a controversy or adopting either of two +conflicting opinions. + -- Ambrose Bierce, "The Devil's Dictionary" +%% +Important letters which contain no errors will develop errors in the +mail. Corresponding errors will show up in the duplicate while the +Boss is reading it. +%% +In a five year period we can get one superb programming language. Only +we can't control when the five year period will begin. +%% + In a forest a fox bumps into a little rabbit, and says, "Hi, +junior, what are you up to?" + "I'm writing a dissertation on how rabbits eat foxes," said the +rabbit. + "Come now, friend rabbit, you know that's impossible!" + "Well, follow me and I'll show you." They both go into the +rabbit's dwelling and after a while the rabbit emerges with a satisfied +expression on his face. + Comes along a wolf. "Hello, what are we doing these days?" + "I'm writing the second chapter of my thesis, on how rabbits +devour wolves." + "Are you crazy? Where is your academic honesty?" + "Come with me and I'll show you." As before, the rabbit comes +out with a satisfied look on his face and a diploma in his paw. +Finally, the camera pans into the rabbit's cave and, as everybody +should have guessed by now, we see a mean-looking, huge lion sitting +next to some bloody and furry remnants of the wolf and the fox. + +The moral: It's not the contents of your thesis that are important -- +it's your PhD advisor that really counts. +%% +In America, any boy may become president and I suppose that's just one +of the risks he takes. + -- Adlai Stevenson +%% +In an organization, each person rises to the level of his own +incompetency + -- The Peter Principle +%% +In any formula, constants (especially those obtained from handbooks) +are to be treated as variables. +%% +In case of atomic attack, the federal ruling against prayer in schools +will be temporarily canceled. +%% +In case of injury notify your superior immediately. He'll kiss it and +make it better. +%% +"In defeat, unbeatable; in victory, unbearable." + -- Winston Curchill, of Montgomery +%% +In Dr. Johnson's famous dictionary patriotism is defined as the last +resort of the scoundrel. With all due respect to an enlightened but +inferior lexicographer I beg to submit that it is the first. + -- Ambrose Bierce, "The Devil's Dictionary" +%% +In English, every word can be verbed. Would that it were so in our +programming languages. +%% +In India, "cold weather" is merely a conventional phrase and has come +into use through the necessity of having some way to distinguish +between weather which will melt a brass door-knob and weather which +will only make it mushy. + -- Mark Twain +%% +In our civilization, and under our republican form of government, +intelligence is so highly honored that it is rewarded by exemption +from the cares of office. + -- Ambrose Bierce, "The Devil's Dictionary" +%% +In Riemann, Hilbert or in Banach space +Let superscripts and subscripts go their ways. +Our symptotes no longer out of phase, +We shall encounter, counting, face to face. + -- Stanislaw Lem, "Cyberiad" +%% +"In short, _N is Richardian if, and only if, _N is not Richardian." +%% +[In the 60's] there was madness in any direction, at any hour ... You +could strike sparks anywhere. There was a fantastic universal sense +that whatever we were doing was `right', that we were winning ... + +And that, I think, was the handle -- the sense of inevitable victory +over the forces of Old and Evil. Not in any mean or military sense; we +didn't need that. Our energy would simply `prevail'. There was no +point in fighting -- on our side or theirs. We had all the momentum; +we were riding the crest of a high and beautiful wave .... + +So now, less than five years later, you can go up on a steep hill in +Las Vegas and look West, and with the right kind of eyes you can almost +___see the high-water mark -- the place where the wave finally broke and +rolled back. + -- Hunter S. Thompson, "Fear and Loathing in Las Vegas" +%% +In the force if Yoda's so strong, construct a sentence with words in +the proper order then why can't he? +%% +In the land of the dark, the Ship of the Sun is driven by the Grateful +Dead. + -- Egyptian Book of the Dead +%% +In the long run, every program becomes rococo, and then rubble. + -- Alan Perlis +%% +In the olden days in England, you could be hung for stealing a sheep or +a loaf of bread. However, if a sheep stole a loaf of bread and gave it +to you, you would only be tried for receiving, a crime punishable by +forty lashes with the cat or the dog, whichever was handy. If you +stole a dog and were caught, you were punished with twelve rabbit +punches, although it was hard to find rabbits big enough or strong +enough to punch you. + -- Mike Harding, "The Armchair Anarchist's Almanac" +%% +In the Top 40, half the songs are secret messages to the teen world to +drop out, turn on, and groove with the chemicals and light shows at +discotheques. + -- Art Linkletter +%% +Incumbent, n.: + Person of liveliest interest to the outcumbents. + -- Ambrose Bierce, "The Devil's Dictionary" +%% +Information Center, n.: + A room staffed by professional computer people whose job it is +to tell you why you cannot have the information you require. +%% +Ingrate, n.: + A man who bites the hand that feeds him, and then complains of +indigestion. +%% +Injustice anywhere is a threat to justice everywhere. + -- Martin Luther King, Jr. +%% +Ink, n.: + A villainous compound of tannogallate of iron, gum-arabic, and +water, chiefly used to facilitate the infection of idiocy and promote +intellectual crime. + -- Ambrose Bierce, "The Devil's Dictionary" +%% +Innovation is hard to schedule. + -- Dan Fylstra +%% +Insanity is hereditary. You get it from your kids. +%% +Insanity is the final defense ... It's hard to get a refund when the +salesman is sniffing your crotch and baying at the moon. +%% +Interpreter, n.: + One who enables two persons of different languages to +understand each other by repeating to each what it would have been to +the interpreter's advantage for the other to have said. + -- Ambrose Bierce, "The Devil's Dictionary" +%% + INVENTORY +Four be the things I am wiser to know: +Idleness, sorrow, a friend, and a foe. + +Four be the things I'd been better without: +Love, curiosity, freckles, and doubt. + +Three be the things I shall never attain: +Envy, content, and sufficient champagne. + +Three be the things I shall have till I die: +Laughter and hope and a sock in the eye. +%% +Iron Law of Distribution: + Them that has, gets. +%% +Is it possible that software is not like anything else, that it is +meant to be discarded: that the whole point is to always see it as a +soap bubble? +%% +Is not marriage an open question, when it is alleged, from the +beginning of the world, that such as are in the institution wish to get +out, and such as are out wish to get in? + -- Ralph Emerson +%% +Is your job running? You'd better go catch it! +%% +Isn't it strange that the same people that laugh at gypsy fortune +tellers take economists seriously? +%% +Issawi's Laws of Progress: + + The Course of Progress: + Most things get steadily worse. + + The Path of Progress: + A shortcut is the longest distance between two points. +%% +It has been observed that one's nose is never so happy as when it is +thrust into the affairs of another, from which some physiologists have +drawn the inference that the nose is devoid of the sense of smell. + -- Ambrose Bierce, "The Devil's Dictionary" +%% +It has just been discovered that research causes cancer in rats. +%% +It is against the grain of modern education to teach children to +program. What fun is there in making plans, acquiring discipline in +organizing thoughts, devoting attention to detail, and learning to be +self-critical? + -- Alan Perlis +%% + It is always preferable to visit home with a friend. Your +parents will not be pleased with this plan, because they want you all +to themselves and because in the presence of your friend, they will +have to act like mature human beings ... + -- Playboy, January 1983 +%% +It is amusing that a virtue is made of the vice of chastity; and it's a +pretty odd sort of chastity at that, which leads men straight into the +sin of Onan, and girls to the waning of their color. + -- Voltaire +%% +It is better to kiss an avocado than to get in a fight with an aardvark +%% +It is by the fortune of God that, in this country, we have three +benefits: freedom of speech, freedom of thought, and the wisdom never +to use either. + -- Mark Twain +%% +It is difficult to produce a television documentary that is both +incisive and probing when every twelve minutes one is interrupted by +twelve dancing rabbits singing about toilet paper. + -- R. Serling +%% +"It is easier for a camel to pass through the eye of a needle if it is +lightly greased." + -- Kehlog Albran, "The Profit" +%% +It is easier to change the specification to fit the program than vice +versa. +%% +It is easier to get forgiveness than permission. +%% +It is easier to write an incorrect program than understand a correct +one. +%% +It is generally agreed that "Hello" is an appropriate greeting because +if you entered a room and said "Goodbye," it could confuse a lot of +people. + -- Dolph Sharp, "I'm O.K., You're Not So Hot" +%% +It is impossible to make anything foolproof because fools are so +ingenious. +%% +It is impossible to travel faster than light, and certainly not +desirable, as one's hat keeps blowing off. + -- Woody Allen +%% +It is much easier to suggest solutions when you know nothing about the +problem. +%% +It is not enough to succeed. Others must fail. + -- Gore Vidal +%% +It is not true that life is one damn thing after another -- it's one +damn thing over and over. + -- Edna St. Vincent Millay +%% +It is now 10 p.m. Do you know where Henry Kissinger is? + -- Elizabeth Carpenter +%% +It is now pitch dark. If you proceed, you will likely fall into a +pit. +%% +It is one of the superstitions of the human mind to have imagined that +virginity could be a virtue. + -- Voltaire +%% +It is said that the lonely eagle flies to the mountain peaks while the +lowly ant crawls the ground, but cannot the soul of the ant soar as +high as the eagle? +%% +It is something to be able to paint a particular picture, or to carve a +statue, and so to make a few objects beautiful; but it is far more +glorious to carve and paint the very atmosphere and medium through +which we look, which morally we can do. To affect the quality of the +day, that is the highest of arts. + -- Henry David Thoreau, "Where I Live" +%% +It is the business of little minds to shrink. + -- Carl Sandburg +%% +It is the business of the future to be dangerous. + -- Hawkwind +%% +It looks like blind screaming hedonism won out. +%% +It may be that your whole purpose in life is simply to serve as a +warning to others. +%% +It seems like the less a statesman amounts to, the more he loves the +flag. +%% +"It took me fifteen years to discover that I had no talent for writing, +but I couldn't give up because by that time I was too famous." +%% +It was a book to kill time for those who liked it better dead. +%% +"It was pleasant to me to get a letter from you the other day. Perhaps +I should have found it pleasanter if I had been able to decipher it. I +don't think that I mastered anything beyond the date (which I knew) and +the signature (which I guessed at). There's a singular and a perpetual +charm in a letter of yours; it never grows old, it never loses its +novelty .... Other letters are read and thrown away and forgotten, but +yours are kept forever -- unread. One of them will last a reasonable +man a lifetime." + -- Thomas Aldrich +%% + It was the next morning that the armies of Twodor marched east +laden with long lances, sharp swords, and death-dealing hangovers. The +thousands were led by Arrowroot, who sat limply in his sidesaddle, +nursing a whopper. Goodgulf, Gimlet, and the rest rode by him, praying +for their fate to be quick, painless, and if possible, someone else's. + Many an hour the armies forged ahead, the war-merinos bleating +under their heavy burdens and the soldiers bleating under their melting +icepacks. + -- The Harvard Lampoon, "Bored of the Rings" +%% +It will be advantageous to cross the great stream ... the Dragon is on +the wing in the Sky ... the Great Man rouses himself to his Work. +%% +It's a damn poor mind that can only think of one way to spell a word. + -- Andrew Jackson +%% +"It's bad luck to be superstitious." + -- Andrew W. Mathis +%% +"It's easier said than done." + +... and if you don't believe it, try proving that it's easier done than +said, and you'll see that "it's easier said that `it's easier done than +said' than it is done", which really proves that "it's easier said than +done". +%% +It's easier to fight for one's principles than to live up to them. +%% +It's easier to get forgiveness for being wrong than forgiveness for +being right. +%% +"It's Fabulous! We haven't seen anything like it in the last half an +hour!" + -- Macy's +%% +It's is not, it isn't ain't, and it's it's, not its, if you mean it +is. If you don't, it's its. Then too, it's hers. It isn't her's. It +isn't our's either. It's ours, and likewise yours and theirs. + -- Oxford University Press, Edpress News +%% +It's lucky you're going so slowly, because you're going in the wrong +direction. +%% +It's not an optical illusion, it just looks like one. + -- Phil White +%% +"It's not Camelot, but it's not Cleveland, either." + -- Kevin White, mayor of Boston +%% +It's not enough to be Hungarian; you must have talent too. + -- Alexander Korda +%% +It's not that I'm afraid to die. I just don't want to be there when it +happens. + -- Woody Allen +%% +It's really quite a simple choice: Life, Death, or Los Angeles. +%% + JACK AND THE BEANSTACK + by Mark Isaak + + Long ago, in a finite state far away, there lived a JOVIAL +character named Jack. Jack and his relations were poor. Often their +hash table was bare. One day Jack's parent said to him, "Our matrices +are sparse. You must go to the market to exchange our RAM for some +BASICs." She compiled a linked list of items to retrieve and passed it +to him. + So Jack set out. But as he was walking along a Hamilton path, +he met the traveling salesman. + "Whither dost thy flow chart take thou?" prompted the salesman +in high-level language. + "I'm going to the market to exchange this RAM for some chips +and Apples," commented Jack. + "I have a much better algorithm. You needn't join a queue +there; I will swap your RAM for these magic kernels now." + Jack made the trade, then backtracked to his house. But when +he told his busy-waiting parent of the deal, she became so angry she +started thrashing. + "Don't you even have any artificial intelligence? All these +kernels together hardly make up one byte," and she popped them out the +window ... +%% +Jacquin's Postulate on Democratic Government: + No man's life, liberty, or property are safe while the + legislature is in session. +%% +Jenkinson's Law: + It won't work. +%% +Jesus Saves, +Moses Invests, +But only Buddha pays Dividends. +%% +Joe's sister puts spaghetti in her shoes! +%% +Johnson's First Law: + When any mechanical contrivance fails, it will do so at the + most inconvenient possible time. +%% +Jone's Law: + The man who smiles when things go wrong has thought of someone + to blame it on. +%% +Jone's Motto: + Friends come and go, but enemies accumulate. +%% +Jones's First Law: + Anyone who makes a significant contribution to any field of + endeavor, and stays in that field long enough, becomes an + obstruction to its progress -- in direct proportion to the + importance of their original contribution. +%% +Just because you're paranoid doesn't mean they AREN'T after you. +%% +Just because your doctor has a name for your condition doesn't mean he +knows what it is. +%% +"Just once, I wish we would encounter an alien menace that wasn't +immune to bullets" + -- The Brigader, "Dr. Who" +%% +Just remember: when you go to court, you are trusting your fate to +twelve people that weren't smart enough to get out of jury duty! +%% +Justice is incidental to law and order. + -- J. Edgar Hoover +%% +Justice is incidental to law and order. + -- J. Edgar Hoover +%% +Justice, n.: + A decision in your favor. +%% +Katz' Law: + Man and nations will act rationally when all other + possibilities have been exhausted. +%% +Keep America beautiful. Swallow your beer cans. +%% +Keep emotionally active. Cater to your favorite neurosis. +%% +Keep grandma off the streets -- legalize bingo. +%% +Keep in mind always the two constant Laws of Frisbee: + 1. The most powerful force in the world is that of a disc + straining to land under a car, just out of reach (this + force is technically termed "car suck"). + 2. Never precede any maneuver by a comment more predictive + than "Watch this!" +%% +Keep you Eye on the Ball, +Your Shoulder to the Wheel, +Your Nose to the Grindstone, +Your Feet on the Ground, +Your Head on your Shoulders. +Now ... try to get something DONE! +%% +Ken Thompson has an automobile which he helped design. Unlike most +automobiles, it has neither speedometer, nor gas gage, nor any of the +numerous idiot lights which plague the modern driver. Rather, if the +driver makes any mistake, a giant "?" lights up in the center of the +dashboard. "The experienced driver", he says, "will usually know +what's wrong." +%% +Kerr's Three Rules for a Successful College: + Have plenty of football for the alumni, sex for the students, + and parking for the faculty. +%% +Kin, n.: + An affliction of the blood +%% +Kinkler's First Law: + Responsibility always exceeds authority. + +Kinkler's Second Law: + All the easy problems have been solved. +%% +"Kirk to Enterprise -- beam down yeoman Rand and a six-pack." +%% +Kiss me twice. I'm schizophrenic. +%% +Kiss your keyboard goodbye! +%% +Klein bottle for rent -- inquire within. +%% +Klein bottle for sale ... inquire within. +%% +Kleptomaniac, n.: + A rich thief. + -- Ambrose Bierce, "The Devil's Dictionary" +%% +Know thyself. If you need help, call the C.I.A. +%% +Know what I hate most? Rhetorical questions. + -- Henry N. Camp +%% +Krogt, n. (chemical symbol: Kr): + The metallic silver coating found on fast-food game cards. + -- Rich Hall, "Sniglets" +%% +Labor, n.: + One of the processes by which A acquires property for B. + -- Ambrose Bierce, "The Devil's Dictionary" +%% +Lackland's Laws: + 1. Never be first. + 2. Never be last. + 3. Never volunteer for anything +%% +Lactomangulation, n.: + Manhandling the "open here" spout on a milk carton so badly +that one has to resort to using the "illegal" side. + -- Rich Hall, "Sniglets" +%% +Laetrile is the pits +%% +Langsam's Laws: + 1) Everything depends. + 2) Nothing is always. + 3) Everything is sometimes. +%% +Larkinson's Law: + All laws are basically false. +%% + Lassie looked brilliant, in part because the farm family she +lived with was made up of idiots. Remember? One of them was always +getting pinned under the tractor, and Lassie was always rushing back to +the farmhouse to alert the other ones. She'd whimper and tug at their +sleeves, and they'd always waste precious minutes saying things: "Do +you think something's wrong? Do you think she wants us to follow her? +What is it, girl?", etc., as if this had never happened before, instead +of every week. What with all the time these people spent pinned under +the tractor, I don't see how they managed to grow any crops +whatsoever. They probably got by on federal crop supports, which +Lassie filed the applications for. + -- Dave Barry +%% +Laugh at your problems; everybody else does. +%% +"Laughter is the closest distance between two people." + -- Victor Borge +%% +Law of Communications: + The inevitable result of improved and enlarged communications + between different levels in a hierarchy is a vastly increased + area of misunderstanding. +%% +Law of Probable Dispersal: + Whatever it is that hits the fan will not be evenly + distributed. +%% +Law of Selective Gravity: + An object will fall so as to do the most damage. + +Jenning's Corollary: + The chance of the bread falling with the buttered side down is + directly proportional to the cost of the carpet. +%% +Law of the Perversity of Nature: + You cannot successfully determine beforehand which side of the + bread to butter. +%% +Laws of Serendipity: + + 1. In order to discover anything, you must be looking for + something. + 2. If you wish to make an improved product, you must already + be engaged in making an inferior one. +%% +Lazlo's Chinese Relativity Axiom: + No matter how great your triumphs or how tragic your defeats -- + approximately one billion Chinese couldn't care less. +%% +Left to themselves, things tend to go from bad to worse. +%% +Leibowitz's Rule: + When hammering a nail, you will never hit your finger if you + hold the hammer with both hands. +%% +LEO (July 23 - Aug 22) + Your determination and sense of humor will come to the fore. + Your ability to laugh at adversity will be a blessing because + you've got a day coming you wouldn't believe. As a matter of + fact, if you can laugh at what happens to you today, you've got + a sick sense of humor. +%% + LEO (July 23 - Aug 22) +You consider yourself a born leader. Others think you are pushy. Most +Leo people are bullies. You are vain and dislike honest criticism. +Your arrogance is disgusting. Leo people are thieves. +%% +Let He who taketh the Plunge Remember to return it by Tuesday. +%% +Let us live!!! +Let us love!!! +Let us share the deepest secrets of our souls!!! + +You first. +%% +Let's talk about how to fill out your 1984 tax return. Here's an often +overlooked accounting technique that can save you thousands of dollars: +For several days before you put it in the mail, carry your tax return +around under your armpit. No IRS agent is going to want to spend hours +poring over a sweat-stained document. So even if you owe money, you +can put in for an enormous refund and the agent will probably give it +to you, just to avoid an audit. What does he care? It's not his +money. + -- Dave Barry, "Sweating Out Taxes" +%% +LETTERS TO THE EDITOR (The Times of London) + +Dear Sir, + +I am firmly opposed to the spread of microchips either to the home or +to the office. We have more than enough of them foisted upon us in +public places. They are a disgusting Americanism, and can only result +in the farmers being forced to grow smaller potatoes, which in turn +will cause massive unemployment in the already severely depressed +agricultural industry. + +Yours faithfully, + Capt. Quinton D'Arcy, J. P. + Sevenoaks +%% +Lewis's Law of Travel: + The first piece of luggage out of the chute doesn't belong to + anyone, ever. +%% +Liar, n.: + A lawyer with a roving commission. + -- Ambrose Bierce, "The Devil's Dictionary" +%% +LIBRA (Sep. 23 to Oct. 22) + Your desire for justice and truth will be overshadowed by your + desire for filthy lucre and a decent meal. Be gracious and + polite. Someone is watching you, so stop staring like that. +%% + LIBRA (Sept 23 - Oct 22) +You are the artistic type and have a difficult time with reality. If +you are a man, you are more than likely gay. Chances for employment +and monetary gains are excellent. Most Libra women are prostitutes. +All Libra people die of Venereal disease. +%% +Lie, n.: + A very poor substitute for the truth, but the only one +discovered to date. +%% +Lieberman's Law: + Everybody lies, but it doesn't matter since nobody listens. +%% +Life is a whim of several billion cells to be you for a while. +%% +Life is a yo-yo, and mankind ties knots in the string. +%% +Life is like an onion: you peel off layer after layer, then you find +there is nothing in it. +%% +"Life may have no meaning -- or even worse, it may have a meaning of +which I disapprove." +%% +Like so many Americans, she was trying to construct a life that made +sense from things she found in gift shops. + -- Kurt Vonnegut, Jr. +%% +Like the ski resort of girls looking for husbands and husbands looking +for girls, the situation is not as symmetrical as it might seem. + -- Alan McKay +%% +Limericks are art forms complex, +Their topics run chiefly to sex. + They usually have virgins, + And masculine urgin's, +And other erotic effects. +%% +Line Printer paper is strongest at the perforations. +%% +Linus: I guess it's wrong always to be worrying about tomorrow. Maybe + we should think only about today. +Charlie Brown: + No, that's giving up. I'm still hoping that yesterday will get + better. +%% +Living on Earth may be expensive, but it includes an annual free trip +around the Sun. +%% +Living your life is a task so difficult, it has never been attempted +before. +%% +Lizzie Borden took an axe, +And plunged it deep into the VAX; +Don't you envy people who +Do all the things ___YOU want to do? +%% +Lockwood's Long Shot: + The chances of getting eaten up by a lion on Main Street aren't + one in a million, but once would be enough. +%% +Look out! Behind you! +%% +Losing your drivers' license is just God's way of saying "BOOGA, BOOGA!" +%% +Love at first sight is one of the greatest labor-saving devices the +world has ever seen. +%% +Love is a word that is constantly heard, +Hate is a word that is not. +Love, I am told, is more precious than gold. +Love, I have read, is hot. +But hate is the verb that to me is superb, +And Love but a drug on the mart. +Any kiddie in school can love like a fool, +But Hating, my boy, is an Art. + -- Ogden Nash +%% +Love is sentimental measles. +%% +Love is the triumph of imagination over intelligence. + -- H. L. Mencken +%% +Love your enemies: they'll go crazy trying to figure out what you're up +to. +%% + Love's Drug + +My love is like an iron wand + That conks me on the head, +My love is like the valium + That I take before me bed, +My love is like the pint of scotch + That I drink when i be dry; +And I shall love thee still my dear, + Until my wife is wise. +%% +Lowery's Law: + If it jams -- force it. If it breaks, it needed replacing + anyway. +%% +LSD melts in your mind, not in your hand. +%% +Lubarsky's Law of Cybernetic Entomology: + There's always one more bug. +%% +Lunatic Asylum, n.: + The place where optimism most flourishes. +%% +Lysistrata had a good idea. +%% +"MacDonald has the gift on compressing the largest amount of words into +the smallest amount of thoughts." + -- Winston Churchill +%% +Mad, adj.: + Affected with a high degree of intellectual independence ... + -- Ambrose Bierce, "The Devil's Dictionary" +%% +Madam, there's no such thing as a tough child -- if you parboil them +first for seven hours, they always come out tender. + -- W. C. Fields +%% +Magnet, n.: Something acted upon by magnetism + +Magnetism, n.: Something acting upon a magnet. + +The two definition immediately foregoing are condensed from the works +of one thousand eminent scientists, who have illuminated the subject +with a great white light, to the inexpressible advancement of human +knowledge. + -- Ambrose Bierce, "The Devil's Dictionary" +%% +Magnocartic, adj.: + Any automobile that, when left unattended, attracts shopping +carts. + -- Sniglets, "Rich Hall & Friends" +%% +Magpie, n.: + A bird whose theivish disposition suggested to someone that it +might be taught to talk. + -- Ambrose Bierce, "The Devil's Dictionary" +%% +Maier's Law: + If the facts do not conform to the theory, they must be + disposed of. + +Corollaries: + 1. The bigger the theory, the better. + 2. The experiment may be considered a success if no more than + 50% of the observed measurements must be discarded to + obtain a correspondence with the theory. +%% +Main's Law: + For every action there is an equal and opposite government + program. +%% +Maintainer's Motto: + If we can't fix it, it ain't broke. +%% +Major Premise: Sixty men can do a piece of work sixty times as quickly + as one man. + +Minor Premise: One man can dig a posthole in sixty seconds. + +Conclusion: Sixty men can dig a posthole in one second. + -- Ambrose Bierce, "The Devil's Dictionary" +%% +Majority, n.: + That quality that distinguishes a crime from a law. +%% +Making files is easy under the UNIX operating system. Therefore, users +tend to create numerous files using large amounts of file space. It +has been said that the only standard thing about all UNIX systems is +the message-of-the-day telling users to clean up their files. + -- System V.2 administrator's guide +%% +Malek's Law: + Any simple idea will be worded in the most complicated way. +%% +"Man invented language to satisfy his deep need to complain." + -- Lily Tomlin +%% +Man is a rational animal who always loses his temper when he is called +upon to act in accordance with the dictates of reason. + -- Oscar Wilde +%% +Man is the best computer we can put aboard a spacecraft ... and the +only one that can be mass produced with unskilled labor. + -- Wernher von Braun +%% +Man is the only animal that blushes -- or needs to. + -- Mark Twain +%% +Man usually avoids attributing cleverness to somebody else -- +unless it is an enemy. + -- A. Einstein +%% +Man, n.: + An animal so lost in rapturous contemplation of what he thinks +he is as to overlook what he indubitably ought to be. His chief +occupation is extermination of other animals and his own species, +which, however, multiplies with such insistent rapidity as to infest +the whole habitable earth and Canada. + -- Ambrose Bierce, "The Devil's Dictionary" +%% +Mankind's yearning to engage in sports is older than recorded history, +dating back to the time millions of years ago, when the first primitive +man picked up a crude club and a round rock, tossed the rock into the +air, and whomped the club into the sloping forehead of the first +primitive umpire. + +What inner force drove this first athlete? Your guess is as good as +mine. Better, probably, because you haven't had four beers. + -- Dave Barry, "Sports is a Drag" +%% +Manual, n.: + A unit of documentation. There are always three or more on a +given item. One is on the shelf; someone has the others. The +information you need in in the others. + -- Ray Simard +%% +Many years ago in a period commonly know as Next Friday Afternoon, +there lived a King who was very Gloomy on Tuesday mornings because he +was so Sad thinking about how Unhappy he had been on Monday and how +completely Mournful he would be on Wednesday ... + -- Walt Kelly +%% +Mark's Dental-Chair Discovery: + Dentists are incapable of asking questions that require a + simple yes or no answer. +%% +Marriage is the only adventure open to the cowardly. + -- Voltaire +%% +"Matrimony isn't a word, it's a sentence." +%% +Matter cannot be created or destroyed, nor can it be returned without a +receipt. +%% +Maturity is only a short break in adolescence. + -- Jules Feiffer +%% +May a Misguided Platypus lay its Eggs in your Jockey Shorts +%% +May Euell Gibbons eat your only copy of the manual! +%% +May the Fleas of a Thousand Camels infest one of your Erogenous Zones. +%% +May your Tongue stick to the Roof of your Mouth with the Force of a +Thousand Caramels. +%% +Maybe Computer Science should be in the College of Theology. + -- R. S. Barton +%% +Maybe you can't buy happiness, but these days you can certainly charge +it. +%% +Mayor Vincent J. `Buddy' Cianci on the ACLU's suit to have a city +nativity scene removed: + "They're just jealous because they don't have three wise men + and a virgin in the whole organization." +%% +McGowan's Madison Avenue Axiom: + If an item is advertised as "under $50", you can bet it's not + $19.95. +%% +Meader's Law: + Whatever happens to you, it will previously have happened to + everyone you know, only more so. +%% +Measure with a micrometer. Mark with chalk. Cut with an axe. +%% +Meeting, n.: + An assembly of people coming together to decide what person or +department not represented in the room must solve a problem. +%% +Men were real men, women were real women, and small, furry creatures +from Alpha Centauri were REAL small, furry creatures from Alpha +Centauri. Spirits were brave, men boldly split infinitives that no man +had split before. Thus was the Empire forged. + -- "The Hitchhiker's Guide to the Galaxy", Douglas Adams +%% +Mencken and Nathan's Fifteenth Law of The Average American: + The worst actress in the company is always the manager's wife. +%% +Mencken and Nathan's Ninth Law of The Average American: + The quality of a champagne is judged by the amount of noise the + cork makes when it is popped. +%% +Mencken and Nathan's Second Law of The Average American: + All the postmasters in small towns read all the postcards. +%% +Mencken and Nathan's Sixteenth Law of The Average American: + Milking a cow is an operation demanding a special talent that + is possessed only by yokels, and no person born in a large city + can never hope to acquire it. +%% +Menu, n.: + A list of dishes which the restaurant has just run out of. +%% +Meskimen's Law: + There's never time to do it right, but there's always time to + do it over. +%% +Message will arrive in the mail. Destroy, before the FBI sees it. +%% +Mickey Mouse wears a Spiro Agnew watch. +%% +Micro Credo: + Never trust a computer bigger than you can lift. +%% +"Might as well be frank, monsieur. It would take a miracle to get you +out of Casablanca and the Germans have outlawed miracles." +%% +Miksch's Law: + If a string has one end, then it has another end. +%% +Military intelligence is a contradiction in terms. + -- Groucho Marx +%% +Military justice is to justice what military music is to music. + -- Groucho Marx +%% +Millions long for immortality who do not know what to do with +themselves on a rainy Sunday afternoon. + -- Susan Ertz +%% +Millions of sensible people are too high-minded to concede that +politics is almost always the choice of the lesser evil. "Tweedledum +and Tweedledee," they say, "I will not vote." Having abstained, they +are presented with a President who appoints the people who are going to +rummage around in their lives for the next four years. Consider all +the people who sat home in a stew in 1968 rather than vote for Hubert +Humphrey. They showed Humphrey. Those people who taught Hubert +Humphrey a lesson will still be enjoying the Nixon Supreme Court when +Tricia and Julie begin to find silver threads among the gold and the +black. + -- Russel Baker, "Ford without Flummery" +%% +Mind! I don't mean to say that I know, of my own knowledge, what there +is particularly dead about a door-nail. I might have been inclined, +myself, to regard a coffin-nail as the deadest piece of ironmongery in +the trade. But the wisdom of our ancestors is in the simile; and my +unhallowed hands shall not disturb it, or the Country's done for. You +will therefore permit me to repeat, emphatically, that Marley was as +dead as a door-nail. +%% +Minnie Mouse is a slow maze learner. +%% +Misery loves company, but company does not reciprocate. +%% +Misfortune, n.: + The kind of fortune that never misses. + -- Ambrose Bierce, "The Devil's Dictionary" +%% +Miss, n.: + A title with which we brand unmarried women to indicate that +they are in the market. + -- Ambrose Bierce, "The Devil's Dictionary" +%% +Mistakes are often the stepping stones to utter failure. +%% +Mitchell's Law of Committees: + Any simple problem can be made insoluble if enough meetings are + held to discuss it. +%% +MOCK APPLE PIE (No Apples Needed) + + Pastry to two crust 9-inch pie 36 RITZ Crackers +2 cups water 2 cups sugar +2 teaspoons cream of tartar 2 tablespoons lemon juice + Grated rind of one lemon Butter or margarine + Cinnamon + +Roll out bottom crust of pastry and fit into 9-inch pie plate. Break +RITZ Crackers coarsely into pastry-lined plate. Combine water, sugar +and cream of tartar in saucepan, boil gently for 15 minutes. Add lemon +juice and rind. Cool. Pour this syrup over Crackers, dot generously +with butter or margarine and sprinkle with cinnamon. Cover with top +crust. Trim and flute edges together. Cut slits in top crust to let +steam escape. Bake in a hot oven (425 F) 30 to 35 minutes, until crust +is crisp and golden. Serve warm. Cut into 6 to 8 slices. + -- Found lurking on a Ritz Crackers box +%% +Modern man is the missing link between apes and human beings. +%% +Molecule, n.: + The ultimate, indivisible unit of matter. It is distinguished +from the corpuscle, also the ultimate, indivisible unit of matter, by a +closer resemblance to the atom, also the ultimate, indivisible unit of +matter ... The ion differs from the molecule, the corpuscle and the +atom in that it is an ion ... + -- Ambrose Bierce, "The Devil's Dictionary" +%% +Mollison's Bureaucracy Hypothesis: + If an idea can survive a bureaucratic review and be implemented + it wasn't worth doing. +%% +Monday is an awful way to spend one seventh of your life. +%% +Monday, n.: + In Christian countries, the day after the baseball game. + -- Ambrose Bierce, "The Devil's Dictionary" +%% +Money is the root of all evil, and man needs roots +%% +Mophobia, n.: + Fear of being verbally abused by a Mississippian. +%% + MORE SPORTS RESULTS: +The Beverly Hills Freudians tied the Chicago Rogerians 0-0 last +Saturday night. The match started with a long period of silence while +the Freudians waited for the Rogerians to free associate and the +Rogerians waited for the Freudians to say something they could +paraphrase. The stalemate was broken when the Freudians' best player +took the offensive and interpreted the Rogerians' silence as reflecting +their anal-retentive personalities. At this the Rogerians' star player +said "I hear you saying you think we're full of ka-ka." This started a +fight and the match was called by officials. +%% +More than any time in history, mankind now faces a crossroads. One +path leads to despair and utter hopelessness, the other to total +extinction. Let us pray that we have the wisdom to choose correctly. + -- Woody Allen +%% +Mosher's Law of Software Engineering: + Don't worry if it doesn't work right. If everything did, you'd + be out of a job. +%% +Most people wouldn't know music if it came up and bit them on the ass. + -- Frank Zappa +%% +Mother told me to be good, but she's been wrong before. +%% +Mr. Cole's Axiom: + The sum of the intelligence on the planet is a constant; the + population is growing. +%% +Murphy's Discovery: + Do you know Presidents talk to the country the way men talk to + women? They say, "Trust me, go all the way with me, and + everything will be all right." And what happens? Nine months + later, you're in trouble! +%% +Murphy's Law is recursive. Washing your car to make it rain doesn't +work. +%% +Murphy's Law of Research: + Enough research will tend to support your theory. +%% + Murray and Esther, a middle-aged Jewish couple, are touring +Chile. Murray just got a new camera and is constantly snapping +pictures. One day, without knowing it, he photographs a top-secret +military installation. In an instant, armed troops surround Murray and +Esther and hustle them off to prison. + They can't prove who they are because they've left their +passports in their hotel room. For three weeks they're tortured day +and night to get them to name their contacts in the liberation +movement.. Finally they're hauled in front of a military court, +charged with espionage, and sentenced to death. + The next morning they're lined up in front of the wall where +they'll be shot. The sergeant in charge of the firing squad asks them +if they have any lasts requests. Esther wants to know if she can call +her daughter in Chicago. The sergeant says he's sorry, that's not +possible, and turns to Murray. + "This is crazy!" Murray shouts. "We're not spies!" And he +spits in the sergeants face. + "Murray!" Esther cries. "Please! Don't make trouble." + -- Arthur Naiman, "Every Goy's Guide to Yiddish" +%% +Mustgo, n.: + Any item of food that has been sitting in the refrigerator so +long it has become a science project. + -- Sniglets, "Rich Hall & Friends" +%% +My God, I'm depressed! Here I am, a computer with a mind a thousand +times as powerful as yours, doing nothing but cranking out fortunes and +sending mail about softball games. And I've got this pain right +through my ALU. I've asked for it to be replaced, but nobody ever +listens. I think it would be better for us both if you were to just +log out again. +%% +My love runs by like a day in June, + And he makes no friends of sorrows. +He'll tread his galloping rigadoon + In the pathway or the morrows. +He'll live his days where the sunbeams start + Nor could storm or wind uproot him. +My own dear love, he is all my heart -- + And I wish somebody'd shoot him. + -- Dorothy Parker +%% +My love, he's mad, and my love, he's fleet, + And a wild young wood-thing bore him! +The ways are fair to his roaming feet, + And the skies are sunlit for him. +As sharply sweet to my heart he seems + As the fragrance of acacia. +My own dear love, he is all my dreams -- + And I wish he were in Asia. + -- Dorothy Parker +%% +My opinions may have changed, but not the fact that I am right. +%% +My own dear love, he is strong and bold + And he cares not what comes after. +His words ring sweet as a chime of gold, + And his eyes are lit with laughter. +He is jubilant as a flag unfurled -- + Oh, a girl, she'd not forget him. +My own dear love, he is all my world -- + And I wish I'd never met him. + -- Dorothy Parker +%% +"My weight is perfect for my height -- which varies" +%% +Mythology, n.: + The body of a primitive people's beliefs concerning its +origin, early history, heroes, deities and so forth, as distinguished +from the true accounts which it invents later. + -- Ambrose Bierce, "The Devil's Dictionary" +%% +Naeser's Law: + You can make it foolproof, but you can't make it + damnfoolproof. +%% +NAPOLEON: What shall we do with this soldier, Guiseppe? Everything he + says is wrong. +GUISEPPE: Make him a general, Excellency, and then everything he says + will be right. + -- G. B. Shaw, "The Man of Destiny" +%% +Nature and nature's laws lay hid in night, +God said, "Let Newton be," and all was light. + +It did not last; the devil howling "Ho! +Let Einstein be!" restored the status quo. +%% +Nearly all men can stand adversity, but if you want to test a man's +character, give him power. + -- Abraham Lincoln +%% +Necessity is a mother. +%% +Never be led astray onto the path of virtue. +%% +Never call a man a fool. Borrow from him. +%% +Never call a man a fool; borrow from him. +%% +Never count your chickens before they rip your lips off +%% +Never drink coke in a moving elevator. The elevator's motion coupled +with the chemicals in coke produce hallucinations. People tend to +change into lizards and attack without warning, and large bats usually +fly in the window. Additionally, you begin to believe that elevators +have windows. +%% +Never eat more than you can lift. + -- Miss Piggy +%% +Never hit a man with glasses. Hit him with a baseball bat. +%% +Never let your sense of morals prevent you from doing what is right. + -- Salvor Hardin, "Foundation" +%% +Never make anything simple and efficient when a way can be found to +make it complex and wonderful. +%% +Never offend people with style when you can offend them with +substance. + -- Sam Brown, "The Washington Post", January 26, 1977 +%% +Never put off till tomorrow what you can avoid all together. +%% +Never try to outstubborn a cat. + -- Lazarus Long, "Time Enough for Love" +%% +Never worry about theory as long as the machinery does what it's +supposed to do. + -- R. A. Heinlein +%% +New crypt. See /usr/news/crypt. +%% +New members are urgently needed in the Society for Prevention of +Cruelty to Yourself. Apply within. +%% +New systems generate new problems. +%% +New Year's Eve is the time of year when a man most feels his age, and +his wife most often reminds him to act it. + -- Webster's Unafraid Dictionary +%% +New York is real. The rest is done with mirrors. +%% +New York's got the ways and means; +Just won't let you be. + -- The Grateful Dead +%% +Newlan's Truism: + An "acceptable" level of unemployment means that the government + economist to whom it is acceptable still has a job. +%% +NEWS FLASH!! + Today the East German pole-vault champion became the West + German pole-vault champion. +%% + *** NEWSFLASH *** +Russian tanks steamrolling through New Jersey!!!! Details at eleven! +%% +Newton's Fourth Law: Every action has an equal and opposite satisfaction. +%% +Newton's Little-Known Seventh Law: + A bird in the hand is safer than one overhead. +%% +Next Friday will not be your lucky day. As a matter of fact, you don't +have a lucky day this year. +%% +Next to being shot at and missed, nothing is really quite as satisfying +as an income tax refund. + -- F. J. Raymond +%% +Nihilism should commence with oneself. +%% +Niklaus Wirth has lamented that, whereas Europeans pronounce his name +correctly (Ni-klows Virt), Americans invariably mangle it into +(Nick-les Worth). Which is to say that Europeans call him by name, but +Americans call him by value. +%% +Nine megs for the secretaries fair, +Seven megs for the hackers scarce, +Five megs for the grads in smoky lairs, +Three megs for system source; + +One disk to rule them all, +One disk to bind them, +One disk to hold the files +And in the darkness grind 'em. +%% +Ninety-Ninety Rule of Project Schedules: + The first ninety percent of the task takes ninety percent of + the time, and the last ten percent takes the other ninety + percent. +%% +No good deed goes unpunished. + -- Clare Boothe Luce +%% +No man is an island, but some of us are long peninsulas. +%% +No one can make you feel inferior without your consent. + -- Eleanor Roosevelt +%% +No problem is so formidable that you can't just walk away from it. +%% +No problem is so large it can't be fit in somewhere. +%% +NOBODY EXPECTS THE SPANISH INQUISITION +%% +Nobody wants constructive criticism. It's all we can do to put up with +constructive praise. +%% +Non-Reciprocal Laws of Expectations: + Negative expectations yield negative results. + Positive expectations yield negative results. +%% +Noncombatant, n.: + A dead Quaker. + -- Ambrose Bierce +%% +Nondeterminism means never having to say you are wrong. +%% +"Nondeterminism means never having to say you are wrong." +%% +Nostalgia isn't what it used to be. +%% +Not far from here, by a white sun, behind a green star, lived the +Steelypips, illustrious, industrious, and they hadn't a care: no spats +in their vats, no rules, no schools, no gloom, no evil influence of the +moon, no trouble from matter or antimatter -- for they had a machine, +a dream of a machine, with springs and gears and perfect in every +respect. And they lived with it, and on it, and under it, and inside +it, for it was all they had -- first they saved up all their atoms, +then they put them all together, and if one didn't fit, why they +chipped at it a bit, and everything was just fine ... + -- Stanislaw Lem, "Cyberiad" +%% +"Not only is this incomprehensible, but the ink is ugly and the paper +is from the wrong kind of tree." + --Profesoor W. +%% +Notes for a ballet, "The Spell": ... Suddenly Sigmund hears the flutter +of wings, and a group of wild swans flies across the moon ... Sigmund +is astounded to see that their leader is part swan and part woman -- +unfortunately, divided lengthwise. She enchants Sigmund, who is +careful not to make any poultry jokes ... + -- Woody Allen +%% +Nothing astonishes men so much as common sense and plain dealing. +%% +Nothing cures insomnia like the realization that it's time to get up. +%% +Nothing is faster than the speed of light ... + +To prove this to yourself, try opening the refrigerator door before +the light comes on. +%% +Nothing is illegal if one hundred businessmen decide to do it. + -- Andrew Young +%% +Nothing recedes like success. + -- Walter Winchell +%% +Nothing takes the taste out of peanut butter quite like unrequited +love. + -- Charlie Brown +%% +November, n.: + The eleventh twelfth of a weariness. + -- Ambrose Bierce, "The Devil's Dictionary" +%% +Now and then an innocent person is sent to the legislature. +%% +Now and then, an innocent man is sent to the Legislature. +%% +Now I lay me down to sleep +I pray the double lock will keep; +May no brick through the window break, +And, no one rob me till I awake. +%% +"Now is the time for all good men to come to." + -- Walt Kelly +%% +Now that you've read Fortune's diet truths, you'll be prepared the next +time some housewife or boutique-owner-turned-diet-expert appears on TV +to plug her latest book. And, if you still feel a twinge of guilt for +eating coffee cake while listening to her exhortations, ask yourself +the following questions: + +1: Do I dare trust a person who actually considers alfalfa sprouts + a food? +2: Was the author's sole motive in writing this book to get rich + exploiting the forlorn hopes of chubby people like me? +3: Would a longer life be worthwhile if it had to be lived as + prescribed ... without French-fried onion rings, pizza with + double cheese, or the occasional Mai-Tai? (Remember, living + right doesn't really make you live longer, it just *seems* like + longer.) + +That, and another piece of coffee cake, should do the trick. +%% +"Now the Lord God planted a garden East of Whittier in a place called +Yorba Linda, and out of the ground he made to grow orange trees that +were good for food and the fruits thereof he labeled SUNKIST ..." + -- "The Begatting of a President" +%% +... Now you're ready for the actual shopping. Your goal should be to +get it over with as quickly as possible, because the longer you stay in +the mall, the longer your children will have to listen to holiday songs +on the mall public-address system, and many of these songs can damage +children emotionally. For example: "Frosty the Snowman" is about a +snowman who befriends some children, plays with them until they learn +to love him, then melts. And "Rudolph the Red-Nosed Reindeer" is about +a young reindeer who, because of a physical deformity, is treated as an +outcast by the other reindeer. Then along comes good, old Santa. Does +he ignore the deformity? Does he look past Rudolph's nose and respect +Rudolph for the sensitive reindeer he is underneath? No. Santa asks +Rudolph to guide his sleigh, as if Rudolph were nothing more than some +kind of headlight with legs and a tail. So unless you want your +children exposed to this kind of insensitivity, you should shop +quickly. + -- Dave Barry, "Christmas Shopping: A Survivor's Guide" +%% +[Nuclear war] ... may not be desirable. + -- Edwin Meese III +%% +Nudists are people who wear one-button suits. +%% +Numeric stability is probably not all that important when you're +guessing. +%% +O give me a home, +Where the buffalo roam, +Where the deer and the antelope play, +Where seldom is heard +A discouraging word, +'Cause what can an antelope say? +%% +O'Toole's commentary on Murphy's Law: + "Murphy was an optimist." +%% +O'Toole's Commentary on Murphy's Law: + Murphy was an optimist. +%% +"Of ______course it's the murder weapon. Who would frame someone with a +fake?" +%% +Of all the animals, the boy is the most unmanageable. + -- Plato +%% +Of course there's no reason for it, it's just our policy. +%% +Office Automation, n.: + The use of computers to improve efficiency by removing anyone +you would want to talk with over coffee. +%% +Ogden's Law: + The sooner you fall behind, the more time you have to catch + up. +%% +Oh don't the days seem lank and long + When all goes right and none goes wrong, +And isn't your life extremely flat + With nothing whatever to grumble at! +%% +Oh, well, I guess this is just going to be one of those lifetimes. +%% +Oh, when I was in love with you, + Then I was clean and brave, +And miles around the wonder grew + How well did I behave. + +And now the fancy passes by, + And nothing will remain, +And miles around they'll say that I + Am quite myself again. + -- A. E. Housman +%% +Oh, wow! Look at the moon! +%% +Old age is the most unexpected of things that can happen to a man. + -- Trotsky +%% +Old age is the most unexpected of things that can happen to a man. + -- Trotsky +%% +Old programmers never die. They just branch to a new address. +%% +Old soldiers never die. Young ones do. +%% +Oliver's Law: + Experience is something you don't get until just after you need + it. +%% +On a paper submitted by a physicist colleague: + +"This isn't right. This isn't even wrong." + -- Wolfgang Pauli +%% + On his first day as a bus driver, Maxey Eckstein handed in +receipts of $65. The next day his take was $67. The third day's +income was $62. But on the fourth day, Eckstein emptied no less than +$283 on the desk before the cashier. + "Eckstein!" exclaimed the cashier. "This is fantastic. That +route never brought in money like this! What happened?" + "Well, after three days on that cockamamie route, I figured +business would never improve, so I drove over to Fourteenth Street and +worked there. I tell you, that street is a gold mine!" +%% +On Monday mornings I am dedicated to the proposition that all men are +created jerks. + -- H. Allen Smith, "Let the Crabgrass Grow" +%% +On-line, adj.: + The idea that a human being should always be accessible to a +computer. +%% +Once ... in the wilds of Afghanistan, I lost my corkscrew, and we were +forced to live on nothing but food and water for days. + -- W. C. Fields, "My Little Chickadee" +%% +Once again, we come to the Holiday Season, a deeply religious time that +each of us observes, in his own way, by going to the mall of his +choice. + +In the old days, it was not called the Holiday Season; the Christians +called it "Christmas" and went to church; the Jews called it "Hanukka" +and went to synagogue; the atheists went to parties and drank. People +passing each other on the street would say "Merry Christmas!" or "Happy +Hanukka!" or (to the atheists) "Look out for the wall!" + -- Dave Barry, "Christmas Shopping: A Survivor's Guide" +%% +Once Law was sitting on the bench + And Mercy knelt a-weeping. +"Clear out!" he cried, "disordered wench! + Nor come before me creeping. +Upon you knees if you appear, +'Tis plain you have no standing here." + +Then Justice came. His Honor cried: + "YOUR states? -- Devil seize you!" +"Amica curiae," she replied -- + "Friend of the court, so please you." +"Begone!" he shouted -- "There's the door -- +I never saw your face before!" + -- Ambrose Bierce, "The Devil's Dictionary" +%% +Once the realization is accepted that even between the closest human +beings infinite distances continue to exist, a wonderful living side by +side can grow up, if they succeed in loving the distance between them +which makes it possible for each to see each other whole against the +sky. + -- Rainer Rilke +%% + Once there lived a village of creatures along the bottom of a +great crystal river. Each creature in its own manner clung tightly to +the twigs and rocks of the river bottom, for clinging was their way of +life, and resisting the current what each had learned from birth. But +one creature said at last, "I trust that the current knows where it is +going. I shall let go, and let it take me where it will. Clinging, I +shall die of boredom." + The other creatures laughed and said, "Fool! Let go, and that +current you worship will throw you tumbled and smashed across the +rocks, and you will die quicker than boredom!" + But the one heeded them not, and taking a breath did let go, +and at once was tumbled and smashed by the current across the rocks. +Yet, in time, as the creature refused to cling again, the current +lifted him free from the bottom, and he was bruised and hurt no more. + And the creatures downstream, to whom he was a stranger, cried, +"See a miracle! A creature like ourselves, yet he flies! See the +Messiah, come to save us all!" And the one carried in the current +said, "I am no more Messiah than you. The river delight to lift us +free, if only we dare let go. Our true work is this voyage, this +adventure. + But they cried the more, "Saviour!" all the while clinging to +the rocks, making legends of a Saviour. +%% +Once upon a time, when I was training to be a mathematician, a group of +us bright young students taking number theory discovered the names of +the smaller prime numbers. + +2: The Odd Prime -- + It's the only even prime, therefore is odd. QED. +3: The True Prime -- + Lewis Carroll: "If I tell you 3 times, it's true." +31: The Arbitrary Prime -- + Determined by unanimous unvote. We needed an arbitrary prime + in case the prof asked for one, and so had an election. 91 + received the most votes (well, it *looks* prime) and 3+4i the + next most. However, 31 was the only candidate to receive none + at all. + +Since the composite numbers are formed from primes, their qualities are +derived from those primes. So, for instance, the number 6 is "odd but +true", while the powers of 2 are all extremely odd numbers. +%% +... Once you're safely in the mall, you should tie your children to you +with ropes so the other shoppers won't try to buy them. Holiday +shoppers have been whipped into a frenzy by months of holiday +advertisements, and they will buy anything small enough to stuff into a +shopping bag. If your children object to being tied, threaten to take +them to see Santa Claus; that ought to shut them up. + -- Dave Barry, "Christmas Shopping: A Survivor's Guide" +%% +Once, adv.: + Enough. + -- Ambrose Bierce, "The Devil's Dictionary" +%% +One can't proceed from the informal to the formal by formal means. +%% +One difference between a man and a machine is that a machine is quiet +when well oiled. +%% +One good reason why computers can do more work than people is that they +never have to stop and answer the phone. +%% +One nice thing about egotists: they don't talk about other people. +%% +One of my less pleasant chores when I was young was to read the Bible +from one end to the other. Reading the Bible straight through is at +least 70 percent discipline, like learning Latin. But the good parts +are, of course, simply amazing. God is an extremely uneven writer, but +when He's good, nobody can touch Him. + -- John Gardner, NYT Book Review, Jan 1983 +%% +One of the oldest problems puzzled over in the Talmud is: "Why did God +create goyim?" The generally accepted answer is "________somebody has to buy +retail." + -- Arthur Naiman, "Every Goy's Guide to Yiddish" +%% + One of the questions that comes up all the time is: How +enthusiastic is our support for UNIX? + Unix was written on our machines and for our machines many +years ago. Today, much of UNIX being done is done on our machines. +Ten percent of our VAXs are going for UNIX use. UNIX is a simple +language, easy to understand, easy to get started with. It's great for +students, great for somewhat casual users, and it's great for +interchanging programs between different machines. And so, because of +its popularity in these markets, we support it. We have good UNIX on +VAX and good UNIX on PDP-11s. + It is our belief, however, that serious professional users will +run out of things they can do with UNIX. They'll want a real system and +will end up doing VMS when they get to be serious about programming. + With UNIX, if you're looking for something, you can easily and +quickly check that small manual and find out that it's not there. With +VMS, no matter what you look for -- it's literally a five-foot shelf of +documentation -- if you look long enough it's there. That's the +difference -- the beauty of UNIX is it's simple; and the beauty of VMS +is that it's all there. + -- Ken Olsen, President of DEC, 1984 +%% +One of the rules of Busmanship, New York style, is never surrender your +seat to another passenger. This may seem callous, but it is the best +way, really. If one passenger were to give a seat to someone who +fainted in the aisle, say, the others on the bus would become +disoriented and imagine they were in Topeka, Kansas. +%% +One Page Principle: + A specification that will not fit on one page of 8.5x11 inch + paper cannot be understood. + -- Mark Ardis +%% +"One planet is all you get." +%% +One seldom sees a monument to a committee. +%% +One thing the inventors can't seem to get the bugs out of is fresh +paint. +%% +One way to stop a runaway horse is to bet on him. +%% +Only adults have difficulty with childproof caps. +%% +Only God can make random selections. +%% +Optimization hinders evolution. +%% +Optimization hinders evolution. +%% +Oregon, n.: + Eighty billion gallons of water with no place to go on Saturday +night. +%% +Organic chemistry is the chemistry of carbon compounds. +Biochemistry is the study of carbon compounds that crawl. + -- Mike Adams +%% +Osborn's Law: + Variables won't; constants aren't. +%% +Others will look to you for stability, so hide when you bite your +nails. +%% +Our country has plenty of good five-cent cigars, but the trouble is +they charge fifteen cents for them. +%% +Our OS who art in CPU, UNIX be thy name. + Thy programs run, thy syscalls done, + in kernel as it is in user! +%% +Our policy is, when in doubt, do the right thing. + -- Roy L. Ash, ex-president Litton Industries +%% +Overdrawn? But I still have checks left! +%% +Overflow on /dev/null, please empty the bit bucket. +%% +Overload -- core meltdown sequence initiated. +%% +Ozman's Laws: + 1. If someone says he will do something "without fail," he + won't. + 2. The more people talk on the phone, the less money they + make. + 3. People who go to conferences are the ones who shouldn't. + 4. Pizza always burns the roof of your mouth. +%% +Paranoia is simply an optimistic outlook on life. +%% +Paranoids are people, too; they have their own problems. It's easy to +criticize, but if everybody hated you, you'd be paranoid too. + -- D. J. Hicks +%% +Pardo's First Postulate: + Anything good in life is either illegal, immoral, or fattening. + +Arnold's Addendum: + Anything not fitting into these categories causes cancer in + rats. +%% +Parker's Law: + Beauty is only skin deep, but ugly goes clean to the bone. +%% +Parkinson's Fifth Law: + If there is a way to delay in important decision, the good + bureaucracy, public or private, will find it. +%% +Parkinson's Fourth Law: + The number of people in any working group tends to increase + regardless of the amount of work to be done. +%% +Parts that positively cannot be assembled in improper order will be. +%% +"Pascal is not a high-level language." + -- Steven Feiner +%% +Pascal Users: + To show respect for the 313th anniversary (tomorrow) of the + death of Blaise Pascal, your programs will be run at half + speed. +%% +Pascal, n.: + A programming language named after a man who would turn over in +his grave if he knew about it. +%% +Passionate hatred can give meaning and purpose to an empty life. + -- Eric Hoffer +%% +Paul Revere was a tattle-tale +%% +Paul's Law: + In America, it's not how much an item costs, it's how much you + save. +%% +Paul's Law: + You can't fall off the floor. +%% +Peace, n.: + In international affairs, a period of cheating between two +periods of fighting. + -- Ambrose Bierce, "The Devil's Dictionary" +%% +Peanut Blossoms + +4 cups sugar 16 tbsp. milk +4 cups brown sugar 4 tsp. vanilla +4 cups shortening 14 cups flour +8 eggs 4 tsp. soda +4 cups peanut butter 4 tsp. salt + +Shape dough into balls. Roll in sugar and bake on ungreased cookie +sheet at 375 F. for 10-12 minutes. Immediately top each cookie with a +Hershey's kiss or star pressing down firmly to crack cookie. Makes a +hell of a lot. +%% +Pecor's Health-Food Principle: + Never eat rutabaga on any day of the week that has a "y" in + it. +%% +People often find it easier to be a result of the past than a cause of +the future. +%% +People usually get what's coming to them ... unless it's been mailed. +%% +People who claim they don't let little things bother them have never +slept in a room with a single mosquito. +%% +People who have what they want are very fond of telling people who +haven't what they want that they don't want it. + -- Ogden Nash +%% +People will accept your ideas much more readily if you tell them that +Benjamin Franklin said it first. +%% +People will buy anything that's one to a customer. +%% +People will buy anything that's one to a customer. +%% +Pereant, inquit, qui ante nos nostra dixerunt. +"Confound those who have said our remarks before us." + -- Aelius Donatus +%% +Perfect day for scrubbing the floor and other exciting things. +%% +Peter's Law of Substitution: + Look after the molehills, and the mountains will look after + themselves. +%% +Philadelphia is not dull -- it just seems so because it is next to +exciting Camden, New Jersy. +%% +Philogyny recapitulates erogeny; erogeny recapitulates philogyny. +%% +pi seconds is a nanocentury. + -- Tom Duff +%% +Pig, n.: + An animal (Porcus omnivorous) closely allied to the human race +by the splendor and vivacity of its appetite, which, however, is +inferior in scope, for it balks at pig. + -- Ambrose Bierce, "The Devil's Dictionary" +%% + PISCES (Feb. 19 - Mar. 20) +You have a vivid imagination and often think you are being followed by +the CIA or FBI. You have minor influence over your associates and +people resent your flaunting of your power. You lack confidence and +you are generally a coward. Pisces people do terrible things to small +animals. +%% +PISCES (Feb. 19 to Mar. 20) + Take the high road, look for the good things, carry the + American Express card and a weapon. The world is yours today, + as nobody else wants it. Your mortgage will be foreclosed. + You will probably get run over by a bus. +%% + Pittsburgh Driver's Test + +7: The car directly in front of you has a flashing right tail + light but a steady left tail light. This means + + (a) one of the tail lights is broken; you should blow your horn + to call the problem to the driver's attention. + (b) the driver is signaling a right turn. + (c) the driver is signaling a left turn. + (d) the driver is from out of town. + +The correct answer is (d). Tail lights are used in some foreign +countries to signal turns. +%% + Pittsburgh Driver's Test + +8: Pedestrians are + + (a) irrelevant. + (b) communists. + (c) a nuisance. + (d) difficult to clean off the front grille. + +The correct answer is (a). Pedestrians are not in cars, so they are +totally irrelevant to driving; you should ignore them completely. +%% +PL/1, "the fatal disease", belongs more to the problem set than to the +solution set. + -- E. W. Dijkstra +%% +Please ignore previous fortune. +%% +Please take note: +%% +Please try to limit the amount of `this room doesn't have any bazingas' +until you are told that those rooms are `punched out.' Once punched +out, we have a right to complain about atrocities, missing bazingas, +and such. + -- N. Meyrowitz +%% +Please, won't somebody tell me what diddie-wa-diddie means? +%% +PLUNDERER'S THEME +(to Supercalifragilisticexpialidocius) + +Pillage, rape, and loot and burn, but all in moderation. +If you do the things we say, then you'll soon rule the nation. +Kill your foes and enemies and then kill your relations. +Pillage, rape, and loot and burn, but all in moderation. +%% +Pohl's law: + Nothing is so good that somebody, somewhere, will not hate it. +%% +Police: Good evening, are you the host? +Host: No. +Police: We've been getting complaints about this party. +Host: About the drugs? +Police: No. +Host: About the guns, then? Is somebody complaining about the guns? +Police: No, the noise. +Host: Oh, the noise. Well that makes sense because there are no guns + or drugs here. (An enormous explosion is heard in the + background.) Or fireworks. Who's complaining about the noise? + The neighbors? +Police: No, the neighbors fled inland hours ago. Most of the recent + complaints have come from Pittsburgh. Do you think you could + ask the host to quiet things down? +Host: No Problem. (At this point, a Volkswagon bug with primitive + religious symbols drawn on the doors emerges from the living + room and roars down the hall, past the police and onto the + lawn, where it smashes into a tree. Eight guests tumble out + onto the grass, moaning.) See? Things are starting to wind + down. +%% +Political T.V. commercials prove one thing: some candidates can tell +all their good points and qualifications in just 30 seconds. +%% +Politician, n.: + From the Greek "poly" ("many") and the French "tete" ("head" or +"face," as in "tete-a-tete": head to head or face to face). Hence +"polytetien", a person of two or more faces. + -- Martin Pitt +%% +Politics is like coaching a football team. you have to be smart enough +to understand the game but not smart enough to lose interest. +%% +Polymer physicists are into chains. +%% +Pope Goestheveezl was the shortest reigning pope in the history of the +Church, reigning for two hours and six minutes on 1 April 1866. The +white smoke had hardly faded into the blue of the Vatican skies before +it dawned on the assembled multitudes in St. Peter's Square that his +name had hilarious possibilities. The crowds fell about, helpless with +laughter, singing + Half a pound of tuppenny rice + Half a pound of treacle + That's the way the chimney smokes + Pope Goestheveezl +The square was finally cleared by armed carabineri with tears of +laughter streaming down their faces. The event set a record for +hilarious civic functions, smashing the previous record set when Baron +Hans Neizant B"ompzidaize was elected Landburgher of K"oln in 1653. + -- Mike Harding, "The Armchair Anarchist's Almanac" +%% +Positive, adj.: + Mistaken at the top of one's voice. + -- Ambrose Bierce, "The Devil's Dictionary" +%% +Power, n: + The only narcotic regulated by the SEC instead of the FDA. +%% +Practical people would be more practical if they would take a little +more time for dreaming. + -- J. P. McEvoy +%% +Predestination was doomed from the start. +%% +President Reagan has noted that there are too many economic pundits and +forecasters and has decided on an excess prophets tax. +%% +President Thieu says he'll quit if he doesn't get more than 50% of the +vote. In a democracy, that's not called quitting. + -- The Washington Post +%% +Pretend to spank me -- I'm a pseudo-masochist! +%% +Preudhomme's Law of Window Cleaning: + It's on the other side. +%% +[Prime Minister Joseph] Chamberlain loves the working man -- he loves +to see him work. + -- Winston Churchill +%% +Pro is to con as progress is to Congress. +%% +Probable-Possible, my black hen, +She lays eggs in the Relative When. +She doesn't lay eggs in the Positive Now +Because she's unable to postulate how. + -- Frederick Winsor +%% +Professor Gorden Newell threw another shutout in last week's Chem. +Eng. 130 midterm. Once again a student did not receive a single point +on his exam. Newell has now tossed 5 shutouts this quarter. Newell's +earned exam average has now dropped to a phenomenal 30% +%% +Proof techniques #1: Proof by Induction. + +This technique is used on equations with "_n" in them. Induction +techniques are very popular, even the military used them. + +SAMPLE: Proof of induction without proof of induction. + + We know it's true for _n equal to 1. Now assume that it's true +for every natural number less than _n. _N is arbitrary, so we can take _n +as large as we want. If _n is sufficiently large, the case of _n+1 is +trivially equivalent, so the only important _n are _n less than _n. We +can take _n = _n (from above), so it's true for _n+1 because it's just +about _n. + QED. (QED translates from the Latin as "So what?") +%% +Proof techniques #2: Proof by Oddity. + SAMPLE: To prove that horses have an infinite number of legs. +(1) Horses have an even number of legs. +(2) They have two legs in back and fore legs in front. +(3) This makes a total of six legs, which certainly is an odd number of + legs for a horse. +(4) But the only number that is both odd and even is infinity. +(5) Therefore, horses must have an infinite number of legs. + +Topics is be covered in future issues include proof by: + Intimidation + Gesticulation (handwaving) + "Try it; it works" + Constipation (I was just sitting there and ...) + Blatant assertion + Changing all the 2's to _n's + Mutual consent + Lack of a counterexample, and + "It stands to reason" +%% +Psychiatrists say that one out of four people are mentally ill. Check +three friends. If they're ok, you're it. +%% +Put your Nose to the Grindstone! + -- Amalgamated Plastic Surgeons and Toolmakers, Ltd. +%% +Putt's Law: + Technology is dominated by two types of people: + Those who understand what they do not manage. + Those who manage what they do not understand. +%% +Q: Do you know what the death rate around here is? +A: One per person. +%% +Q: Why do ducks have flat feet? +A: To stamp out forest fires. + +Q: Why do elephants have flat feet? +A: To stamp out flaming ducks. +%% +Q: Why do mountain climbers rope themselves together? +A: To prevent the sensible ones from going home. +%% +Q: How many DEC repairman does it take to fix a flat ? +A: Five; four to hold the car up and one to swap tires. +%% +Q: How many DEC repairman does it take to fix a flat? +A: Five; four to hold the car up and one to swap tires. + +Q: How long does it take? +A: It's indeterminate. It will depend upon how many flats they've + brought with them. + +Q: What happens if you've got TWO flats? +A: They replace your generator. +%% +Q: How many existentialists does it take to screw in a lightbulb? +A: Two. One to screw it in and one to observe how the lightbulb itself + symbolizes a single incandescent beacon of subjective reality in a + netherworld of endless absurdity reaching out toward a maudlin + cosmos of nothingness. +%% +Q: How many IBM cpu's does it take to do a logical right shift? +A: 33. 1 to hold the bits and 32 to push the register. +%% +Q: How many IBM CPU's does it take to execute a job? +A: Four; three to hold it down, and one to rip its head off. +%% +Q: How many IBM types does it take to change a light bulb? +A: 100. Ten to do it, and 90 to write document number GC7500439-0001, + Multitasking Incandescent Source System Facility, of which 10% of + the pages state only "This page intentionally left blank", and 20% + of the definitions are of the form "A ...... consists of sequences + of non-blank characters separated by blanks". +%% +Q: How many journalists does it take to screw in a lightbulb? +A: Three. One to report it as an inspired government program to bring + light to the people, one to report it as a diabolical government + plot to deprive the poor of darkness, and one to win a pulitzer + prize for reporting that Electric Company hired a lightbulb-assassin + to break the bulb in the first place. +% +Q: How many heterosexual males does it take to screw in a light bulb in + San Francisco? +A: Both of them. +%% +Q: How many Martians does it take to screw in a lightbulb? +A: One and a half. +%% +Q: How many Oregonians does it take to screw in a light bulb? +A: Three. One to screw in the lightbulb and two to fend off all those + Californians trying to share the experience. +%% +Q: How many surrealists does it take to change a light bulb? +A: Two. One to hold the girrafe and the other to fill the bathtub with + brightly colored machine tools. +%% +Q: Why did the tachyon cross the road? +A: Because it was on the other side. +%% +Quality Control, n.: + The process of testing one out of every 1,000 units coming off +a production line to make sure that at least one out of 100 works. +%% +Question: +Man Invented Alcohol, +God Invented Grass. +Who do you trust? +%% +Quick!! Act as if nothing has happened! +%% +"Qvid me anxivs svm?" +%% +QWERT (kwirt), n. [MW < OW qwertyuiop, a thirteenth]: + 1. a unit of weight equal to 13 poiuyt avoirdupois (or 1.69 +kiloliks), commonly used in structural engineering; 2. [Colloq.] one +thirteenth the load that a fully grown sligo can carry; 3. [Anat.] a +painful irritation of the dermis in the region of the anus; 4. [Slang] +person who excites in others the symptoms of a qwert. + -- Webster's Middle World Dictionary, 4th ed. +%% +Radioactive cats have 18 half-lives. +%% +Rattling around the back of my head is a disturbing image of something +I saw at the airport ... Now I'm remembering, those giant piles of +computer magazines right next to "People" and "Time" in the airport +store. Does it bother anyone else that half the world is being told +all of our hard-won secrets of computer technology? Remember how all +the lawyers cried foul when "How to Avoid Probate" was published? Are +they taking no-fault insurance lying down? No way! But at the current +rate it won't be long before there are stacks of the "Transactions on +Information Theory" at the A&P checkout counters. Who's going to be +impressed with us electrical engineers then? Are we, as the saying +goes, giving away the store? + -- Robert W. Lucky, IEEE President +%% +Ray's Rule of Precision: + Measure with a micrometer. Mark with chalk. Cut with an axe. +%% +Razors pain you; +Rivers are damp; +Acids stain you; +And drugs cause cramp. +Guns aren't lawful; +Nooses give; +Gas smells awful; +You might as well live. + -- Dorothy Parker +%% +Re graphics: A picture is worth 10K words -- but only those to describe +the picture. Hardly any sets of 10K words can be adequately described +with pictures. +%% +Real Programmers don't play tennis, or any other sport that requires +you to change clothes. Mountain climbing is OK, and real programmers +wear their climbing boots to work in case a mountain should suddenly +spring up in the middle of the machine room. +%% +Real Programmers don't write in PL/I. PL/I is for programmers who +can't decide whether to write in COBOL or FORTRAN. +%% +Real Programmers think better when playing Adventure or Rogue. +%% +Real Programs don't use shared text. Otherwise, how can they use +functions for scratch space after they are finished calling them? +%% +Real Time, adj.: + Here and now, as opposed to fake time, which only occurs there +and then. +%% +Reality is a cop-out for people who can't handle drugs. +%% +Reality is an obstacle to hallucination. +%% +Reality is for those who can't face Science Fiction. +%% +"Really ?? What a coincidence, I'm shallow too!!" +%% +Receiving a million dollars tax free will make you feel better than +being flat broke and having a stomach ache. + -- Dolph Sharp, "I'm O.K., You're Not So Hot" +%% +Recession is when your neighbor loses his job. Depression is when you +lose your job. These economic downturns are very difficult to predict, +but sophisticated econometric modeling houses like Data Resources and +Chase Econometrics have successfully predicted 14 of the last 3 +recessions. +%% +Reclaimer, spare that tree! +Take not a single bit! +It used to point to me, +Now I'm protecting it. +It was the reader's CONS +That made it, paired by dot; +Now, GC, for the nonce, +Thou shalt reclaim it not. +%% + "Reflections on Ice-Breaking" +Candy +Is dandy +But liquor +Is quicker. + -- Ogden Nash +%% +"Reintegration complete," ZORAC advised. "We're back in the universe +again ..." An unusually long pause followed, "... but I don't know +which part. We seem to have changed our position in space." A +spherical display in the middle of the floor illuminated to show the +starfield surrounding the ship. + +"Several large, artificial constructions are approaching us," ZORAC +announced after a short pause. "The designs are not familiar, but they +are obviously the products of intelligence. Implications: we have been +intercepted deliberately by a means unknown, for a purpose unknown, and +transferred to a place unknown by a form of intelligence unknown. +Apart from the unknowns, everything is obvious." + -- James P. Hogan, "Giants Star" +%% +Reisner's Rule of Conceptual Inertia: + If you think big enough, you'll never have to do it. +%% +Remember that whatever misfortune may be your lot, it could only be +worse in Cleveland. + -- National Lampoon, "Deteriorada" +%% +Remember, even if you win the rat race -- you're still a rat. +%% +Remember, UNIX spelled backwards is XINU. +%% +Reporter (to Mahatma Gandhi): Mr Gandhi, what do you think of + Western Civilization? +Gandhi: I think it would be a good idea. +%% +Reporter, n.: + A writer who guesses his way to the truth and dispels it with a +tempest of words. + -- Ambrose Bierce, "The Devil's Dictionary" +%% +Research is what I'm doing when I don't know what I'm doing. + -- Wernher von Braun +%% +Resisting temptation is easier when you think you'll probably get +another chance later on. +%% +Review Questions + +1: If Nerd on the planet Nutley starts out in his spaceship at 20 + KPH, and his speed doubles every 3.2 seconds, how long will it + be before he exceeds the speed of light? How long will it be + before the Galactic Patrol picks up the pieces of his + spaceship? + +2: If Roger Rowdy wrecks his car every week, and each week he + breaks twice as many bones as before, how long will it be + before he breaks every bone in his body? How long will it be + before they cut off his insurance? Where does he get a new car + every week? + +3: If Johnson drinks one beer the first hour (slow start), four + beers the next hour, nine beers the next, etc., and stacks the + cans in a pyramid, how soon will Johnson's pyramid be larger + than King Tut's? When will it fall on him? Will he notice? +%% +Rhode's Law: + When any principle, law, tenet, probability, happening, + circumstance, or result can in no way be directly, indirectly, + empirically, or circuitously proven, derived, implied, + inferred, induced, deducted, estimated, or scientifically + guessed, it will always for the purpose of convenience, + expediency, political advantage, material gain, or personal + comfort, or any combination of the above, or none of the above, + be unilaterally and unequivocally assumed, proclaimed, and + adhered to as absolute truth to be undeniably, universally, + immutably, and infinitely so, until such time as it becomes + advantageous to assume otherwise, maybe. +%% +Rocky's Lemma of Innovation Prevention + Unless the results are known in advance, funding agencies will + reject the proposal. +%% +ROMEO: Courage, man; the hurt cannot be much. +MERCUTIO: No, 'tis not so deep as a well, nor so wide as a church- + door; but 'tis enough, 'twill serve. +%% +Rudin's Law: + If there is a wrong way to do something, most people will + do it every time. +%% +Rule 46, Oxford Union Society, London: + Any member introducing a dog into the Society's premises shall + be liable to a fine of one pound. Any animal leading a blind + person shall be deemed to be a cat. +%% +Rule of Creative Research: + 1) Never draw what you can copy. + 2) Never copy what you can trace. + 3) Never trace what you can cut out and paste down. +%% +Rule of Defactualization: + Information deteriorates upward through bureaucracies. +%% +Rule of Feline Frustration: + When your cat has fallen asleep on your lap and looks utterly + content and adorable, you will suddenly have to go to the + bathroom. +%% +Rule of the Great: + When people you greatly admire appear to be thinking deep + thoughts, they probably are thinking about lunch. +%% +Rules for driving in New York: + 1) Anything done while honking your horn is legal. + 2) You may park anywhere if you turn your four-way flashers + on. + 3) A red light means the next six cars may go through the + intersection. +%% +RULES OF EATING -- THE BRONX DIETER'S CREED + 1. Never eat on an empty stomach. + 2. Never leave the table hungry. + 3. When traveling, never leave a country hungry. + 4. Enjoy your food. + 5. Enjoy your companion's food. + 6. Really taste your food. It may take several portions to + accomplish this, especially if subtly seasoned. + 7. Really feel your food. Texture is important. Compare, for + example, the texture of a turnip to that of a brownie. + Which feels better against your cheeks? + 8. Never eat between snacks, unless it's a meal. + 9. Don't feel you must finish everything on your plate. You + can always eat it later. + 10. Avoid any wine with a childproof cap. + 11. Avoid blue food. + -- Richard Smit, "The Bronx Diet" +%% +Safety Tips for the Post-Nuclear Existence + Tip #1: How to tell when you are dead. + + 1. Little things start bothering you: little things like + worms, bugs, ants. + 2. Something is missing in your personal relationships. + 3. Your dog becomes overly affectionate. + 4. You have a hard time getting a waiter. + 5. Exotic birds flock around you. + 6. People ignore you at parties. + 7. You have a hard time getting up in the morning. + 8. You no longer get off on cocaine. +%% + Safety Tips for the Post-Nuclear Existence +1. Never use an elevator in a building that has been hit by a nuclear + bomb; use the stairs. +2. When you're flying through the air, remember to roll when you hit + the ground. +3. If you're on fire, avoid gasoline and other flammable materials. +4. Don't attempt communication with dead people; it will only lead to + psychological problems. +5. Food will be scarce; you will have to scavenge. Learn to recognize + foods that will be available after the bomb: mashed potatoes, + shredded wheat, tossed salad, ground beef, etc. +6. Put your hand over your mouth when you sneeze; internal organs will + be scarce in the post-nuclear age. +7. Try to be neat; fall only in designated piles. +8. Drive carefully in "Heavy Fallout" areas; people could be + staggering illegally. +9. Nutritionally, hundred dollar bills are equal to ones, but more + sanitary due to limited circulation. +10. Accumulate mannequins now; spare parts will be in short supply on + D-Day. +%% + SAGITTARIUS (Nov 22 - Dec 21) +You are optimistic and enthusiastic. You have a reckless tendency to +rely on luck since you lack talent. The majority of Sagittarians are +drunks or dope fiends or both. People laugh at you a great deal. +%% +San Francisco isn't what it used to be, and it never was. + -- Herb Caen +%% +San Francisco, n.: + Marcel Proust editing an issue of Penthouse. +%% +Santa Claus wears a Red Suit, + He must be a communist. +And a beard and long hair, + Must be a pacifist. + + What's in that pipe that he's smoking? + -- Arlo Guthrie +%% +Satellite Safety Tip #14: + If you see a bright streak in the sky coming at you, duck. +%% +Sattinger's Law: + It works better if you plug it in. +%% +Saturday night in Toledo Ohio, + Is like being nowhere at all, +All through the day how the hours rush by, + You sit in the park and you watch the grass die. + -- John Denver, "Saturday Night in Toledo Ohio" +%% +Save energy: be apathetic. +%% +Save the whales. Collect the whole set. +%% +SCCS, the source motel! Programs check in and never check out! + -- Ken Thompson +%% +Schapiro's Explanation: + The grass is always greener on the other side -- but that's + because they use more manure. +%% +Schizophrenia beats being alone. +%% +Science is what happens when preconception meets verification. +%% + SCORPIO (Oct 23 - Nov 21) +You are shrewd in business and cannot be trusted. You will achieve the +pinnacle of success because of your total lack of ethics. Most Scorpio +people are murdered. +%% +Scott's first Law: + No matter what goes wrong, it will probably look right. +%% +Scott's second Law: + When an error has been detected and corrected, it will be found + to have been wrong in the first place. +Corollary: + After the correction has been found in error, it will be + impossible to fit the original quantity back into the + equation. +%% +Scotty: Captain, we din' can reference it! +Kirk: Analysis, Mr. Spock? +Spock: Captain, it doesn't appear in the symbol table. +Kirk: Then it's of external origin? +Spock: Affirmative. +Kirk: Mr. Sulu, go to pass two. +Sulu: Aye aye, sir, going to pass two. +%% +Screw up your courage! You've screwed up everything else. +%% +Second Law of Business Meetings: + If there are two possible ways to spell a person's name, you + will pick the wrong one. + +Corollary: + If there is only one way to spell a name, you will spell it + wrong, anyway. +%% +Security check: INTRUDER ALERT! +%% +Seduced, shaggy Samson snored. +She scissored short. Sorely shorn, +Soon shackled slave, Samson sighed, +Silently scheming, +Sightlessly seeking +Some savage, spectacular suicide. + -- Stanislaw Lem, "Cyberiad" +%% +Self Test for Paranoia: + You know you have it when you can't think of anything that's + your own fault. +%% +Seminars, n.: + From "semi" and "arse", hence, any half-assed discussion. +%% +Serocki's Stricture: + Marriage is always a bachelor's last option. +%% +Serving coffee on aircraft causes turbulence. +%% + "Seven years and six months!" Humpty Dumpty repeated +thoughtfully. "An uncomfortable sort of age. Now if you'd asked MY +advice, I'd have said `Leave off at seven' -- but it's too late now." + "I never ask advice about growing," Alice said indignantly. + "Too proud?" the other enquired. + Alice felt even more indignant at this suggestion. "I mean," +she said, "that one can't help growing older." + "ONE can't, perhaps," said Humpty Dumpty; "but TWO can. With +proper assistance, you might have left off at seven." + -- Lewis Carroll +%% +Sex is not the answer. Sex is the question. "Yes" is the answer. + -- Swami X +%% +Sex is the mathematics urge sublimated. + -- M. C. Reed. +%% +Sex without love is an empty experience, but, as empty experiences go, +it's one of the best. + -- Woody Allen +%% +Shamus, n.: + A shamus is a guy who takes care of handyman tasks around the +temple, and makes sure everything is in working order. + A shamus is at the bottom of the pecking order of synagog +functionaries, and there's a joke about that: + A rabbi, to show his humility before God, cries out in the +middle of a service, "Oh, Lord, I am nobody!" The cantor, not to be +bested, also cries out, "Oh, Lord, I am nobody!" + The shamus, deeply moved, follows suit and cries, "Oh, Lord, I +am nobody!" The rabbi turns to the cantor and says, "Look who thinks +he's nobody!" + -- Arthur Naiman, "Every Goy's Guide to Yiddish" +%% +Shaw's Principle: + Build a system that even a fool can use, and only a fool will + want to use it. +%% +"She is descended from a long line that her mother listened to." + -- Gypsy Rose Lee +%% +She is not refined. She is not unrefined. She keeps a parrot. + -- Mark Twain +%% +She missed an invaluable opportunity to give him a look that you could +have poured on a waffle ... +%% +She's genuinely bogus. +%% +"Sherry [Thomas Sheridan] is dull, naturally dull; but it must have +taken him a great deal of pains to become what we now see him. Such an +excess of stupidity, sir, is not in Nature." + -- Samuel Johnson +%% +SHIFT TO THE LEFT! SHIFT TO THE RIGHT! +POP UP, PUSH DOWN, BYTE, BYTE, BYTE! +%% +Show me a man who is a good loser and I'll show you a man who is +playing golf with his boss. +%% +Show respect for age. Drink good Scotch for a change. +%% +Signs of crime: screaming or cries for help. + -- from the Brown Security Crime Prevention Pamphlet +%% +Silverman's Law: + If Murphy's Law can go wrong, it will. +%% +Simon's Law: + Everything put together falls apart sooner or later. +%% +Since I hurt my pendulum +My life is all erratic. +My parrot, who was cordial, +Is now transmitting static. +The carpet died, a palm collapsed, +The cat keeps doing poo. +The only thing that keeps me sane +Is talking to my shoe. + -- My Shoe +%% +Since we're all here, we must not be all there. + -- Bob "Mountain" Beck +%% +[Sir Stafford Cripps] has all the virtues I dislike and none of the +vices I admire. + -- Winston Churchill +%% +Sixtus V, Pope from 1585 to 1590 authorized a printing of the Vulgate +Bible. Taking no chances, the pope issued a papal bull automatically +excommunicating any printer who might make an alteration in the text. +This he ordered printed at the beginning of the Bible. He personally +examined every sheet as it came off the press. Yet the published +Vulgate Bible contained so many errors that corrected scraps had to be +printed and pasted over them in every copy. The result provoked wry +comments on the rather patchy papal infallibility, and Pope Sixtus had +no recourse but to order the return and destruction of every copy. +%% +Skinner's Constant (or Flannagan's Finagling Factor): + That quantity which, when multiplied by, divided by, added to, + or subtracted from the answer you get, gives you the answer you + should have gotten. +%% +Slang is language that takes off its coat, spits on its hands, and goes +to work. +%% +Slick's Three Laws of the Universe: + 1. Nothing in the known universe travels faster than a bad + check. + 2. A quarter-ounce of chocolate = four pounds of fat. + 3. There are two types of dirt: the dark kind, which is + attracted to light objects, and the light kind, which is + attracted to dark objects. +%% +Slurm, n.: + The slime that accumulates on the underside of a soap bar when +it sits in the dish too long. + -- Rich Hall, "Sniglets" +%% +Snacktrek, n.: + The peculiar habit, when searching for a snack, of constantly +returning to the refrigerator in hopes that something new will have +materialized. + -- Rich Hall, "Sniglets" +%% +So far as I can remember, there is not one word in the Gospels in +praise of intelligence. + -- Bertrand Russell +%% +"So she went into the garden to cut a cabbage leaf to make an apple +pie; and at the same time a great she-bear, coming up the street pops +its head into the shop. "What! no soap?" So he died, and she very +imprudently married the barber; and there were present the Picninnies, +and the Grand Panjandrum himself, with the little round button at top, +and they all fell to playing the game of catch as catch can, till the +gunpowder ran out at the heels of their boots." + -- Samuel Foote +%% +Sodd's Second Law: + Sooner or later, the worst possible set of circumstances is + bound to occur. +%% +SOFTWARE -- formal evening attire for female computer analysts. +%% +Some of you ... may have decided that, this year, you're going to +celebrate it the old-fashioned way, with your family sitting around +stringing cranberries and exchanging humble, handmade gifts, like on +"The Waltons". Well, you can forget it. If everybody pulled that kind +of subversive stunt, the economy would collapse overnight. The +government would have to intervene: it would form a cabinet-level +Department of Holiday Gift-Giving, which would spend billions and +billions of tax dollars to buy Barbie dolls and electronic games, which +it would drop on the populace from Air Force jets, killing and maiming +thousands. So, for the good of the nation, you should go along with +the Holiday Program. This means you should get a large sum of money +and go to a mall. + -- Dave Barry, "Christmas Shopping: A Survivor's Guide" +%% +Some people are born mediocre, some people achieve mediocrity, and some +people have mediocrity thrust upon them. + -- Joseph Heller, "Catch-22" +%% +Some people in this department wouldn't recognize subtlety if it hit +them on the head. +%% +Some points to remember [about animals]: + +1. Don't go to sleep under big animals, e.g., elephants, + rhinoceri, hippopotamuses; +2. Don't put animals with sharp teeth or poisonous fangs down the + front of your clothes; +3. Don't pat certain animals, e.g., crocodiles and scorpions or + dogs you have just kicked. + -- Mike Harding, "The Armchair Anarchist's Almanac" +%% +Somebody ought to cross ball point pens with coat hangers so that the +pens will multiply instead of disappear. +%% +Someone will try to honk your nose today. +%% +"Sometimes I simply feel that the whole world is a cigarette and I'm +the only ashtray." +%% +Sometimes I worry about being a success in a mediocre world. + -- Lily Tomlin +%% +"Somewhere", said Father Vittorini, "did Blake not speak of the +Machineries of Joy? That is, did not God promote environments, then +intimidate these Natures by provoking the existence of flesh, toy men +and women, such as are we all? And thus happily sent forth, at our +best, with good grace and fine wit, on calm noons, in fair climes, are +we not God's Machineries of Joy?" + +"If Blake said that", said Father Brian, "he never lived in Dublin." + -- R. Bradbury, "The Machineries of Joy" +%% +Sooner or later you must pay for your sins. (Those who have already +paid may disregard this fortune). +%% +Space is big. You just won't believe how vastly, hugely, mind- +bogglingly big it is. I mean, you may think it's a long way down the +road to the drug store, but that's just peanuts to space. + -- "The Hitchhiker's Guide to the Galaxy" +%% +Spark's Sixth Rule for Managers: + If a subordinate asks you a pertinent question, look at him as + if he had lost his senses. When he looks down, paraphrase the + question back at him. +%% +Speak roughly to your little boy, + And beat him when he sneezes: +He only does it to annoy + Because he knows it teases. + + Wow! wow! wow! + +I speak severely to my boy, + And beat him when he sneezes: +For he can thoroughly enjoy + The pepper when he pleases! + + Wow! wow! wow! + -- Lewis Carrol, "Alice in Wonderland" +%% +Speak roughly to your little VAX, + And boot it when it crashes; +It knows that one cannot relax + Because the paging thrashes! + + Wow! Wow! Wow! + +I speak severely to my VAX, + And boot it when it crashes; +In spite of all my favorite hacks + My jobs it always thrashes! + + Wow! Wow! Wow! +%% +Speak softly and carry a +6 two-handed sword. +%% +Speaking as someone who has delved into the intricacies of PL/I, I am +sure that only Real Men could have written such a machine-hogging, +cycle-grabbing, all-encompassing monster. Allocate an array and free +the middle third? Sure! Why not? Multiply a character string times a +bit string and assign the result to a float decimal? Go ahead! Free a +controlled variable procedure parameter and reallocate it before +passing it back? Overlay three different types of variable on the same +memory location? Anything you say! Write a recursive macro? Well, +no, but Real Men use rescan. How could a language so obviously +designed and written by Real Men not be intended for Real Man use? +%% +Speaking of love, one problem that recurs more and more frequently +these days, in books and plays and movies, is the inability of people +to communicate with the people they love; Husbands and wives who can't +communicate, children who can't communicate with their parents, and so +on. And the characters in these books and plays and so on (and in real +life, I might add) spend hours bemoaning the fact that they can't +communicate. I feel that if a person can't communicate, the very _____least +he can do is to Shut Up! + -- Tom Lehrer, "That Was the Year that Was" +%% +Spend extra time on hobby. Get plenty of rolling papers. +%% +Spirtle, n.: + The fine stream from a grapefruit that always lands right in +your eye. + -- Sniglets, "Rich Hall & Friends" +%% +Spouse, n.: + Someone who'll stand by you through all the trouble you +wouldn't have had if you'd stayed single. +%% +Stay away from flying saucers today. +%% +Stay away from hurricanes for a while. +%% +"Stealing a rhinoceros should not be attempted lightly." +%% +Steele's Plagiarism of Somebody's Philosophy: + Everybody should believe in something -- I believe I'll have + another drink. +%% +Steinbach's Guideline for Systems Programming + Never test for an error condition you don't know how to + handle. +%% +Stop searching. Happiness is right next to you. +%% +Stop searching. Happiness is right next to you. Now, if they'd only +take a bath ... +%% +Stult's Report: + Our problems are mostly behind us. What we have to do now is + fight the solutions. +%% +Stupid, n.: + Losing $25 on the game and $25 on the instant replay. +%% +Sturgeon's Law: + 90% of everything is crud. +%% +Substitute "damn" every time you're inclined to write "very"; your +editor will delete it and the writing will be just as it should be. + -- Mark Twain +%% +Succumb to natural tendencies. Be hateful and boring. +%% +(Sung to the tune of "The Impossible Dream" from MAN OF LA MANCHA) + + To code the impossible code, + To bring up a virgin machine, + To pop out of endless recursion, + To grok what appears on the screen, + + To right the unrightable bug, + To endlessly twiddle and thrash, + To mount the unmountable magtape, + To stop the unstoppable crash! +%% +Support bacteria -- it's the only culture some people have! +%% +Surprise due today. Also the rent. +%% +Surprise your boss. Get to work on time. +%% +Surprise! You are the lucky winner of random I.R.S. Audit! Just type +in your name and social security number. Please remember that leaving +the room is punishable under law: + +Name # +%% +Sweater, n.: + A garment worn by a child when its mother feels chilly. +%% +Swipple's Rule of Order: + He who shouts the loudest has the floor. +%% +System/3! System/3! +See how it runs! See how it runs! + Its monitor loses so totally! + It runs all its programs in RPG! + It's made by our favorite monopoly! +System/3! +%% +Tact is the ability to tell a man he has an open mind when he has a +hole in his head. +%% +Tact is the ability to tell a man he has an open mind when he has a +hole in his head. +%% +Tact, n.: + The unsaid part of what you're thinking. +%% +Take everything in stride. Trample anyone who gets in your way. +%% +Take heart amid the deepening gloom that your dog is finally getting +enough cheese + -- National Lampoon, "Deteriorada" +%% +Take it easy, we're in a hurry. +%% +Take my word for it, the silliest woman can manage a clever man, but it +needs a very clever woman to manage a fool. + -- Kipling +%% + Take the folks at Coca-Cola. For many years, they were content +to sit back and make the same old carbonated beverage. It was a good +beverage, no question about it; generations of people had grown up +drinking it and doing the experiment in sixth grade where you put a +nail into a glass of Coke and after a couple of days the nail dissolves +and the teacher says: "Imagine what it does to your TEETH!" So +Coca-Cola was solidly entrenched in the market, and the management saw +no need to improve ... + -- Dave Barry, "In Search of Excellence" +%% +Take your dying with some seriousness, however. Laughing on the way to +your execution is not generally understood by less advanced life forms, +and they'll call you crazy. + -- "Messiah's Handbook: Reminders for the Advanced Soul" +%% +Take your dying with some seriousness, however. Laughing on the way to +your execution is not generally understood by less-advanced life-forms, +and they'll call you crazy. + -- Messiah's Handbook: Reminders for the Advanced Soul +%% +Talk sense to a fool and he calls you foolish. + -- Euripides +%% +Talkers are no good doers. + -- William Shakespeare, "Henry VI" +%% +Talking much about oneself can also be a means to conceal oneself. + -- Friedrich Nietzsche +%% + TAURUS (Apr 20 - May 20) +You are practical and persistent. You have a dogged determination and +work like hell. Most people think you are stubborn and bull headed. +You are a Communist. +%% +Tax reform means "Don't tax you, don't tax me, tax that fellow behind +the tree." + -- Russell Long +%% +Taxes, n.: + Of life's two certainties, the only one for which you can get +an extension. +%% +Teach children to be polite and courteous in the home, and, when he +grows up, he will never be able to edge his car onto a freeway. +%% +Teamwork is essential -- it allows you to blame someone else. +%% +Technological progress has merely provided us with more efficient means +for going backwards. + -- Aldous Huxley +%% +Ten years of rejection slips is nature's way of telling you to stop +writing. + -- R. Geis +%% +"Terence, this is stupid stuff: +You eat your victuals fast enough; +There can't be much amiss, 'tis clear, +To see the rate you drink your beer. +But oh, good Lord, the verse you make, +It gives a chap the belly-ache. +The cow, the old cow, she is dead; +It sleeps well the horned head: +We poor lads, 'tis our turn now +To hear such tunes as killed the cow. +Pretty friendship 'tis to rhyme +Your friends to death before their time. +Moping, melancholy mad: +Come, pipe a tune to dance to, lad." + -- A. E. Housman +%% +Tertullian was born in Carthage somewhere about 160 A.D. He was a +pagan, and he abandoned himself to the lascivious life of his city +until about his 35th year, when he became a Christian .... To him is +ascribed the sublime confession: Credo quia absurdum est (I believe +because it is absurd). This does not altogether accord with historical +fact, for he merely said: + + "And the Son of God died, which is immediately credible because + it is absurd. And buried he rose again, which is certain + because it is impossible." + +Thanks to the acuteness of his mind, he saw through the poverty of +philosophical and Gnostic knowledge, and contemptuously rejected it. + -- C. G. Jung, in Psychological Types + +(Teruillian was one of the founders of the Catholic Church). +%% +Test-tube babies shouldn't throw stones. +%% +"Text processing has made it possible to right-justify any idea, even +one which cannot be justified on any other grounds." + -- J. Finnegan, USC. +%% +"That must be wonderful! I don't understand it at all." +%% +That secret you've been guarding, isn't. +%% +That woman speaks eight languages and can't say "no" in any of them. + -- Dorothy Parker +%% +The [Ford Foundation] is a large body of money completely surrounded by +people who want some. + -- Dwight MacDonald +%% +The Abrams' Principle: + The shortest distance between two points is off the wall. +%% +The advertisement is the most truthful part of a newspaper + -- Thomas Jefferson +%% +... The Anarchists' [national] anthem is an international anthem that +consists of 365 raspberries blown in very quick succession to the tune +of "Camptown Races". Nobody has to stand up for it, nobody has to +listen to it, and, even better, nobody has to play it. + -- Mike Harding, "The Armchair Anarchist's Almanac" +%% +The Army has carried the American ... ideal to its logical conclusion. +Not only do they prohibit discrimination on the grounds of race, creed +and color, but also on ability. + -- T. Lehrer +%% +The Army needs leaders the way a foot needs a big toe. + -- Bill Murray +%% +The average woman would rather have beauty than brains, because the +average man can see better than he can think. +%% +The basic idea behind malls is that they are more convenient than +cities. Cities contain streets, which are dangerous and crowded and +difficult to park in. Malls, on the other hand, have parking lots, +which are also dangerous and crowded and difficult to park in, but -- +here is the big difference -- in mall parking lots, THERE ARE NO +RULES. You're allowed to do anything. You can drive as fast as you +want in any direction you want. I was once driving in a mall parking +lot when my car was struck by a pickup truck being driven backward by a +squat man with a tattoo that said "Charlie" on his forearm, who got out +and explained to me, in great detail, why the accident was my fault, +his reasoning being that he was violent and muscular, whereas I was +neither. This kind of reasoning is legally valid in mall parking +lots. + -- Dave Barry, "Christmas Shopping: A Survivor's Guide" +%% +The best book on programming for the layman is "Alice in Wonderland"; +but that's because it's the best book on anything for the layman. +%% +The best cure for insomnia is to get a lot of sleep. + -- W. C. Fields +%% +The best defense against logic is ignorance. +%% +The best thing about growing older is that it takes such a long time. +%% +The biggest difference between time and space is that you can't reuse +time. + -- Merrick Furst +%% +The birds are singing, the flowers are budding, and it is time for Miss +Manners to tell young lovers to stop necking in public. + +It's not that Miss Manners is immune to romance. Miss Manners has been +known to squeeze a gentleman's arm while being helped over a curb, and, +in her wild youth, even to press a dainty slipper against a foot or two +under the dinner table. Miss Manners also believes that the sight of +people strolling hand in hand or arm in arm or arm in hand dresses up a +city considerably more than the more familiar sight of people shaking +umbrellas at one another. What Miss Manners objects to is the kind of +activity that frightens the horses on the street ... +%% +"The bland leadeth the bland and they both shall fall into the kitsch." +%% +The brain is a wonderful organ; it starts working the moment you get up +in the morning, and does not stop until you get to school. +%% +The Briggs/Chase Law of Program Development: + To determine how long it will take to write and debug a + program, take your best estimate, multiply that by two, add + one, and convert to the next higher units. +%% +"The C Programming Language -- A language which combines the +flexibility of assembly language with the power of assembly language." +%% +The chicken that clucks the loudest is the one most likely to show up +at the steam fitters' picnic. +%% +The chief cause of problems is solutions. +%% +"The climate of Bombay is such that its inhabitants have to live +elsewhere." +%% +The computing field is always in need of new cliches. + -- Alan Perlis +%% +The correct way to punctuate a sentence that starts: "Of course it is +none of my business, but --" is to place a period after the word "but." +Don't use excessive force in supplying such a moron with a period. +Cutting his throat is only a momentary pleasure and is bound to get you +talked about. + -- Lazarus Long, "Time Enough for Love" +%% +The cost of living hasn't affected its popularity. +%% +The cost of living is going up, and the chance of living is going +down. +%% +The cow is nothing but a machine with makes grass fit for us people to +eat. + -- John McNulty +%% +The Crown is full of it! + -- Nate Harris, 1775 +%% +The day-to-day travails of the IBM programmer are so amusing to most of +us who are fortunate enough never to have been one -- like watching +Charlie Chaplin trying to cook a shoe. +%% +The debate rages on: Is PL/I Bachtrian or Dromedary? +%% +The devil finds work for idle circuits to do. +%% +"The difference between a misfortune and a calamity? If Gladstone fell +into the Thames, it would be a misfortune. But if someone dragged him +out again, it would be a calamity." + -- Benjamin Disraeli +%% +The difference between science and the fuzzy subjects is that science +requires reasoning while those other subjects merely require +scholarship. + -- Robert Heinlein +%% +The duck hunter trained his retriever to walk on water. Eager to show +off this amazing accomplishment, he asked a friend to go along on his +next hunting trip. Saying nothing, he fired his first shot and, as the +duck fell, the dog walked on the surface of the water, retrieved the +duck and returned it to his master. + "Notice anything?" the owner asked eagerly. + "Yes," said his friend, "I see that fool dog of yours can't +swim." +%% +The earth is like a tiny grain of sand, only much, much heavier. +%% +The end of the world will occur at 3:00 p.m., this Friday, with +symposium to follow. +%% +The English have no respect for their language, and will not teach +their children to speak it. + -- G. B. Shaw +%% +The fact that it works is immaterial. + -- L. Ogborn +%% +The Fifth Rule: + You have taken yourself too seriously. +%% +The first duty of a revolutionary is to get away with it. + -- Abbie Hoffman +%% +The first Great Steward, Parrafin the Climber, was employed in King +Chloroplast's kitchen as second scullery boy when the old King met a +tragic death. He apparently fell backward by accident on a dozen salad +forks. Simultaneously the true heir, his son Carotene, mysteriously +fled the city, complaining of some sort of plot and a lot of +threatening notes left on his breakfast tray. At the time, this looked +suspicious what with his father's death, and Carotene was suspected of +foul play. Then the rest of the King's relatives began to drop dead +one after the other in an odd fashion. Some were found strangled with +dishrags and some succumbed to food poisoning. A few were found +drowned in the soup vats, and one was attacked by assailants unknown +and beaten to death with a pot roast. At least three appear to have +thrown themselves backward on salad forks, perhaps in a noble gesture +of grief over the King's untimely end. Finally there was no one left +in Minas Troney who was either eligible or willing to wear the accursed +crown, and the rule of Twodor was up for grabs. The scullery slave +Parrafin bravely accepted the Stewardship of Twodor until that day when +a lineal descendant of Carotene's returns to reclaim his rightful +throne, conquer Twodor's enemies, and revamp the postal system. + -- Harvard Lampoon, "Bored of the Rings" +%% +The first riddle I ever heard, one familiar to almost every Jewish +child, was propounded to me by my father: + "What is it that hangs on the wall, is green, wet -- and +whistles?" + I knit my brow and thought and thought, and in final perplexity +gave up. + "A herring," said my father. + "A herring," I echoed. "A herring doesn't hang on the wall!" + "So hang it there." + "But a herring isn't green!" I protested. + "Paint it." + "But a herring isn't wet." + "If its just painted its still wet." + "But -- " I sputtered, summoning all my outrage, "-- a herring +doesn't whistle!!" + "Right, " smiled my father. "I just put that in to make it +hard." + -- Leo Rosten, "The Joys of Yiddish" +%% +The First Rule of Program Optimization: + Don't do it. + +The Second Rule of Program Optimization (for experts only!): + Don't do it yet. + -- Michael Jackson +%% +The fortune program is supported, in part, by user contributions and by +a major grant from the National Endowment for the Inanities. +%% +The generation of random numbers is too important to be left to +chance. +%% +The geographical center of Boston is in Roxbury. Due north of the +center we find the South End. This is not to be confused with South +Boston which lies directly east from the South End. North of the South +End is East Boston and southwest of East Boston is the North End. +%% +The goal of Computer Science is to build something that will last at +least until we've finished building it. +%% +The goal of science is to build better mousetraps. +The goal of nature is to build better mice. +%% +The gods gave man fire and he invented fire engines. They gave him +love and he invented marriage. +%% +THE GOLDEN RULE OF ARTS AND SCIENCES + The one who has the gold makes the rules. +%% +The Great Bald Swamp Hedgehog: + The Gerat Bald Swamp Hedgehog of Billericay displays, in +courtship, his single prickle and does impressions of Holiday Inn desk +clerks. Since this means him standing motionless for enormous periods +of time he is often eaten in full display by The Great Bald Swamp +Hedgehog Eater. + -- Mike Harding, "The Armchair Anarchist's Almanac" +%% +The hardest thing in the world to understand is the income tax. + -- Albert Einstein +%% +The hearing ear is always found close to the speaking tongue, +a custom whereof the memory of man runneth not howsomever to +the contrary, nohow. +%% +The Heineken Uncertainty Principle: + You can never be sure how many beers you had last night. +%% +The herd instinct among economists makes sheep look like independent +thinkers. +%% +The human animal differs from the lesser primates in his passion for +lists of "Ten Best". + -- H. Allen Smith +%% +The human mind ordinarily operates at only ten percent of its capacity +-- the rest is overhead for the operating system. +%% +The human mind treats a new idea the way the body treats a strange +protein -- it rejects it. + -- P. Medawar +%% +The human race has one really effective weapon, and that is laughter. + -- Mark Twain +%% +"The illegal we do immediately. The unconstitutional takes a bit +longer." + -- Henry Kissinger +%% +The individual choice of garnishment of a burger can be an important +point to the consumer in this day when individualism is an increasingly +important thing to people. + -- Donald N. Smith, president of Burger King +%% +The IQ of the group is the lowest IQ of a member of the group divided +by the number of people in the group. +%% +The IRS spends God knows how much of your tax money on these toll-free +information hot lines staffed by IRS employees, whose idea of a +dynamite tax tip is that you should print neatly. If you ask them a +real tax question, such as how you can cheat, they're useless. + +So, for guidance, you want to look to big business. Big business never +pays a nickel in taxes, according to Ralph Nader, who represents a big +consumer organization that never pays a nickel in taxes... + -- Dave Barry, "Sweating Out Taxes" +%% +The Kennedy Constant: + Don't get mad -- get even. +%% +The Killer Ducks are coming!!! +%% +The ladies men admire, I've heard, +Would shudder at a wicked word. +Their candle gives a single light; +They'd rather stay at home at night. +They do not keep awake till three, +Nor read erotic poetry. +They never sanction the impure, +Nor recognize an overture. +They shrink from powders and from paints ... +So far, I've had no complaints. + -- Dorothy Parker +%% +The Law, in its majestic equality, forbids the rich, as well as the +poor, to sleep under the bridges, to beg in the streets, and to steal +bread. + -- Anatole France +%% +THE LESSER-KNOWN PROGRAMMING LANGUAGES #10 -- SIMPLE + +SIMPLE is an acronym for Sheer Idiot's Monopurpose Programming Language +Environment. This language, developed at the Hanover College for +Technological Misfits, was designed to make it impossible to write code +with errors in it. The statements are, therefore, confined to BEGIN, +END and STOP. No matter how you arrange the statements, you can't make +a syntax error. Programs written in SIMPLE do nothing useful. Thus +they achieve the results of programs written in other languages without +the tedious, frustrating process of testing and debugging. +%% +THE LESSER-KNOWN PROGRAMMING LANGUAGES #12 -- LITHP + +This otherwise unremarkable language is distinguished by the absence of +an "S" in its character set; users must substitute "TH". LITHP is said +to be useful in protheththing lithtth. +%% +THE LESSER-KNOWN PROGRAMMING LANGUAGES #13 -- SLOBOL + +SLOBOL is best known for the speed, or lack of it, of its compiler. +Although many compilers allow you to take a coffee break while they +compile, SLOBOL compilers allow you to travel to Bolivia to pick the +coffee. Forty-three programmers are known to have died of boredom +sitting at their terminals while waiting for a SLOBOL program to +compile. Weary SLOBOL programmers often turn to a related (but +infinitely faster) language, COCAINE. +%% +THE LESSER-KNOWN PROGRAMMING LANGUAGES #17 -- SARTRE + + Named after the late existential philosopher, SARTRE is an +extremely unstructured language. Statements in SARTRE have no purpose; +they just are. Thus SARTRE programs are left to define their own +functions. SARTRE programmers tend to be boring and depressed, and are +no fun at parties. +%% +THE LESSER-KNOWN PROGRAMMING LANGUAGES #17 -- SARTRE + +Named after the late existential philosopher, SARTRE is an extremely +unstructured language. Statements in SARTRE have no purpose; they just +are. Thus SARTRE programs are left to define their own functions. +SARTRE programmers tend to be boring and depressed, and are no fun at +parties. +%% +THE LESSER-KNOWN PROGRAMMING LANGUAGES #18 -- C- + +This language was named for the grade received by its creator when he +submitted it as a class project in a graduate programming class. C- is +best described as a "low-level" programming language. In fact, the +language generally requires more C- statements than machine-code +statements to execute a given task. In this respect, it is very +similar to COBOL. +%% +THE LESSER-KNOWN PROGRAMMING LANGUAGES #18 -- FIFTH + +FIFTH is a precision mathematical language in which the data types +refer to quantity. The data types range from CC, OUNCE, SHOT, and +JIGGER to FIFTH (hence the name of the language), LITER, MAGNUM and +BLOTTO. Commands refer to ingredients such as CHABLIS, CHARDONNAY, +CABERNET, GIN, VERMOUTH, VODKA, SCOTCH, and WHATEVERSAROUND. + +The many versions of the FIFTH language reflect the sophistication and +financial status of its users. Commands in the ELITE dialect include +VSOP and LAFITE, while commands in the GUTTER dialect include HOOTCH +and RIPPLE. The latter is a favorite of frustrated FORTH programmers +who end up using this language. +%% +The light at the end of the tunnel is the headlight of an approaching +train. +%% +The lion and the calf shall lie down together but the calf won't get +much sleep. + -- Woody Allen +%% +The longer I am out of office, the more infallible I appear to myself. + -- Henry Kissinger +%% +"The Lord gave us farmers two strong hands so we could grab as much as +we could with both of them." + -- Joseph Heller, "Catch-22" +%% +The man who follows the crowd will usually get no further than the +crowd. The man who walks alone is likely to find himself in places no +one has ever been. + -- Alan Ashley-Pitt +%% +The marvels of today's modern technology include the development of a +soda can, when discarded will last forever ... and a $7,000 car which +when properly cared for will rust out in two or three years. +%% +The meek shall inherit the earth -- they are too weak to refuse. +%% + The men sat sipping their tea in silence. After a while the +klutz said, "Life is like a bowl of sour cream." + + "Like a bowl of sour cream?" asked the other. "Why?" + + "How should I know? What am I, a philosopher?" +%% +The moon may be smaller than Earth, but it's further away. +%% +The more laws and order are made prominent, the more thieves and +robbers there will be. + -- Lao Tsu +%% +The more things change, the more they stay insane. +%% +The more we disagree, the more chance there is that at least one of us +is right. +%% +The mosquito is the state bird of New Jersey. + -- Andy Warhol +%% +The most exciting phrase to hear in science, the one that heralds new +discoveries, is not "Eureka!" (I found it!) but "That's funny ..." + -- Isaac Asimov +%% +The moving cursor writes, and having written, blinks on. +%% +The National Short-Sleeved Shirt Association says: + Support your right to bare arms! +%% +The new Congressmen say they're going to turn the government around. I +hope I don't get run over again. +%% +The New Testament offers the basis for modern computer coding theory, +in the form of an affirmation of the binary number system. + + But let your communication be Yea, yea; nay, nay: for + whatsoever is more than these cometh of evil. + -- Matthew 5:37 +%% +The nice thing about standards is that there are so many of them to +choose from. + -- Andrew S. Tanenbaum +%% +The notion of a "record" is an obsolete remnant of the days of the +80-column card. + -- Dennis M. Ritchie +%% +The objective of all dedicated employees should be to thoroughly +analyze all situations, anticipate all problems prior to their +occurrence, have answers for these problems, and move swiftly to solve +these problems when called upon. + +However, When you are up to your ass in alligators it is difficult to +remind yourself your initial objective was to drain the swamp. +%% +The Official MBA Handbook on business cards: + + Avoid overly pretentious job titles such as "Lord of the Realm, + Defender of the Faith, Emperor of India" or "Director of + Corporate Planning." +%% +The older a man gets, the farther he had to walk to school as a boy. +%% +The one good thing about repeating your mistakes is that you know when +to cringe. +%% +The only possible interpretation of any research whatever in the +`social sciences' is: some do, some don't. + -- Ernest Rutherford +%% +The only problem with being a man of leisure is that you can never stop +and take a rest. +%% +The only thing to do with good advice is pass it on. It is never any +use to oneself. + -- Oscar Wilde +%% +The only way to get rid of a temptation is to yield to it. + -- Oscar Wilde +%% +The opossum is a very sophisticated animal. It doesn't even get up +until 5 or 6 pm. +%% +The opposite of a profound truth may well be another profound truth. + -- Bohr +%% +The optimum committee has no members. + -- Norman Augustine +%% +The owner of a large furniture store in the mid-west arrived in France +on a buying trip. As he was checking into a hotel he struck up an +acquaintance with a beautiful young lady. However, she only spoke +French and he only spoke English, so each couldn't understand a word +the other spoke. He took out a pencil and a notebook and drew a +picture of a taxi. She smiled, nodded her head and they went for a +ride in the park. Later, he drew a picture of a table in a restaurant +with a question mark and she nodded, so they went to dinner. After +dinner he sketched two dancers and she was delighted. They went to +several nightclubs, drank champagne, danced and had a glorious +evening. It had gotten quite late when she motioned for the pencil and +drew a picture of a four-poster bed. He was dumbfounded, and has never +be able to understand how she knew he was in the furniture business. +%% +The past always looks better than it was. It's only pleasant because +it isn't here. + -- Finley Peter Dunne (Mr. Dooley) +%% + The people of Halifax invented the trampoline. During the +Victorian period the tripe-dressers of Halifax stretched tripe across a +large wooden frame and jumped up and down on it to `tender and dress' +it. The tripoline, as they called it, degenerated into becoming the +apparatus for a spectator sport. + + The people of Halifax also invented the harmonium, a device for +castrating pigs during Sunday service. + -- Mike Harding, "The Armchair Anarchist's Almanac" +%% +The Pig, if I am not mistaken, +Gives us ham and pork and Bacon. +Let others think his heart is big, +I think it stupid of the Pig. + -- Ogden Nash +%% +The pitcher wound up and he flang the ball at the batter. The batter +swang and missed. The pitcher flang the ball again and this time the +batter connected. He hit a high fly right to the center fielder. The +center fielder was all set to catch the ball, but at the last minute +his eyes were blound by the sun and he dropped it. + -- Dizzy Dean +%% +The pitcher wound up and he flang the ball at the batter. The batter +swang and missed. The pitcher flang the ball again and this time the +batter connected. He hit a high fly right to the center fielder. The +center fielder was all set to catch the ball, but at the last minute +his eyes were blound by the sun and he dropped it. + -- Dizzy Dean +%% +The Preacher, the Politicain, the Teacher, + Were each of them once a kiddie. +A child, indeed, is a wonderful creature. + Do I want one? God Forbiddie! + -- Ogden Nash +%% +The primary purpose of the DATA statement is to give names to +constants; instead of referring to pi as 3.141592653589793 at every +appearance, the variable PI can be given that value with a DATA +statement and used instead of the longer form of the constant. This +also simplifies modifying the program, should the value of pi change. + -- FORTRAN manual for Xerox Computers +%% +The probability of someone watching you is proportional to the +stupidity of your action. +%% +The problem ... is that we have run out of dinosaurs to form oil with. +Scientists working for the Department of Energy have tried to form oil +using other animals; they've piled thousands of tons of sand and Middle +Eastern countries on top of cows, raccoons, haddock, laboratory rats, +etc., but so far all they have managed to do is run up an enormous +bulldozer-rental bill and anger a lot of Middle Eastern persons. None +of the animals turned into oil, although most of the laboratory rats +developed cancer. + -- Dave Barry, "Postpetroleum Guzzler" +%% +The problem with any unwritten law is that you don't know where to go +to erase it. + -- Glaser and Way +%% +The problem with people who have no vices is that generally you can be +pretty sure they're going to have some pretty annoying virtues. + -- Elizabeth Taylor +%% +The problem with the gene pool is that there is no lifeguard. +%% +The Psblurtex is an 18-inch long anaconda that hides in the gentlemen's +outfitting departments of Amazonian stores and is often bought by +mistake since its colors are those of the London Reform Club. Once +tied around its victim's neck, it strangles him gently and then claims +the insurance before running off to Germany where it lives in hiding. + -- Mike Harding, "The Armchair Anarchist's Almanac" +%% +"The pyramid is opening!" +"Which one?" +"The one with the ever-widening hole in it!" + -- Firesign Theater, "How Can You Be In Two Places At + Once When You're Not Anywhere At All" +%% +The rain it raineth on the just + And also on the unjust fella, +But chiefly on the just, because + The unjust steals the just's umbrella. +%% +The reason computer chips are so small is computers don't eat much. +%% +The reasonable man adapts himself to the world; the unreasonable one +persists in trying to adapt the world to himself. Therefore all +progress depends on the unreasonable man. + -- George Bernard Shaw +%% +The revolution will not be televised. +%% +The reward of a thing well done is to have done it. + -- Emerson +%% +The right half of the brain controls the left half of the body. +This means that only left handed people are in their right mind. +%% +The Roman Rule + The one who says it cannot be done should never interrupt the + one who is doing it. +%% +The Ruffed Pandanga of Borneo and Rotherham spreads out his feathers in +his courtship dance and imitates Winston Churchill and Tommy Cooper on +one leg. The padanga is dying out because the female padanga doesn't +take it too seriously. + -- Mike Harding, "The Armchair Anarchist's Almanac" +%% +The Schwine-Kitzenger Institute study of 47 men over the age of 100 +showed that all had these things in common: + + 1. They all had moderate appetites. + 2. They all came from middle class homes + 3. All but two of them were dead. +%% + The seven eyes of Ningauble the Wizard floated back to his hood +as he reported to Fafhrd: "I have seen much, yet cannot explain all. +The Gray Mouser is exactly twenty-five feet below the deepest cellar in +the palace of Gilpkerio Kistomerces. Even though twenty-four parts in +twenty-five of him are dead, he is alive. + + "Now about Lankhmar. She's been invaded, her walls breached +everywhere and desperate fighting is going on in the streets, by a +fierce host which out-numbers Lankhamar's inhabitants by fifty to one +-- and equipped with all modern weapons. Yet you can save the city." + + "How?" demanded Fafhrd. + + Ningauble shrugged. "You're a hero. You should know." + -- Fritz Leiber, from "The Swords of Lankhmar" +%% +The shortest distance between two points is under construction. + -- Noelie Altito +%% +"The society which scorns excellence in plumbing as a humble activity +and tolerates shoddiness in philosophy because it is an exaulted +activity will have neither good plumbing nor good philosophy ... +neither its pipes nor its theories will hold water." +%% +"The sooner you fall behind, the more time you'll have to catch up!" +%% + The STAR WARS Song + Sung to the tune of "Lola", by the Kinks: + +I met him in a swamp down in Dagobah +Where it bubbles all the time like a giant cabinet soda + S-O-D-A soda +I saw the little runt sitting there on a log +I asked him his name and in a raspy voice he said Yoda + Y-O-D-A Yoda, Yo-Yo-Yo-Yo Yoda + +Well I've been around but I ain't never seen +A guy who looks like a Muppet but he's wrinkled and green + Oh my Yoda, Yo-Yo-Yo-Yo Yoda +Well I'm not dumb but I can't understand +How he can raise me in the air just by raising his hand + Oh my Yoda, Yo-Yo-Yo-Yo Yoda, Yo-Yo-Yo-Yo Yoda +%% +The steady state of disks is full. + --Ken Thompson +%% + THE STORY OF CREATION + or + THE MYTH OF URK + +In the beginning there was data. The data was without form and null, +and darkness was upon the face of the console; and the Spirit of IBM +was moving over the face of the market. And DEC said, "Let there be +registers"; and there were registers. And DEC saw that they carried; +and DEC separated the data from the instructions. DEC called the data +Stack, and the instructions they called Code. And there was evening +and there was morning, one interrupt ... + -- Rico Tudor +%% +The sun was shining on the sea, +Shining with all his might: +He did his very best to make +The billows smooth and bright -- +And this was very odd, because it was +The middle of the night. + -- Lewis Carroll, "Through the Looking Glass" +%% +The superfluous is very necessary. + -- Voltaire +%% +The temperature of Heaven can be rather accurately computed. Our +authority is Isaiah 30:26, "Moreover, the light of the Moon shall be as +the light of the Sun and the light of the Sun shall be sevenfold, as +the light of seven days." Thus Heaven receives from the Moon as much +radiation as we do from the Sun, and in addition 7*7 (49) times as much +as the Earth does from the Sun, or 50 times in all. The light we +receive from the Moon is one 1/10,000 of the light we receive from the +Sun, so we can ignore that ... The radiation falling on Heaven will +heat it to the point where the heat lost by radiation is just equal to +the heat received by radiation, i.e., Heaven loses 50 times as much +heat as the Earth by radiation. Using the Stefan-Boltzmann law for +radiation, (_H/_E)^4 = 50, where _E is the absolute temperature of the +earth (-300K), gives _H as 798K (525C). The exact temperature of Hell +cannot be computed ... [However] Revelations 21:8 says "But the +fearful, and unbelieving ... shall have their part in the lake which +burneth with fire and brimstone." A lake of molten brimstone means +that its temperature must be at or below the boiling point, 444.6C. We +have, then, that Heaven, at 525C is hotter than Hell at 445C. + -- From "Applied Optics" vol. 11, A14, 1972 +%% +The Third Law of Photography: + If you did manage to get any good shots, they will be ruined + when someone inadvertently opens the darkroom door and all of + the dark leaks out. +%% +The three laws of thermodynamics: + +The First Law: You can't get anything without working for it. +The Second Law: The most you can accomplish by working is to break + even. +The Third Law: You can only break even at absolute zero. +%% +The trouble with a kitten is that +When it grows up, it's always a cat + -- Ogden Nash. +%% +The trouble with being poor is that it takes up all your time. +%% +The trouble with being punctual is that people think you have nothing +more important to do. +%% +The trouble with doing something right the first time is that nobody +appreciates how difficult it was. +%% +The truth of a proposition has nothing to do with its credibility. And +vice versa. +%% +The turtle lives 'twixt plated decks +Which practically conceal its sex. +I think it clever of the turtle +In such a fix to be so fertile. + -- Ogden Nash +%% +The typewriting machine, when played with expression, is no more +annoying than the piano when played by a sister or near relation. + -- Oscar Wilde +%% +The University of California Bears announced the signing of Reggie +Philbin to a letter of intent to attend Cal next Fall. Philbin is said +to make up for no talent by cheating well. Says Philbin of his +decision to attend Cal, "I'm in it for the free ride." +%% +The USA is so enormous, and so numerous are its schools, colleges and +religious seminaries, many devoted to special religious beliefs ranging +from the unorthodox to the dotty, that we can hardly wonder at its +yielding a more bounteous harvest of gobbledegook than the rest of the +world put together. + -- Sir Peter Medawar +%% +The USA is so enormous, and so numerous are its schools, colleges and +religious seminaries, many devoted to special religious beliefs ranging +from the unorthodox to the dotty, that we can hardly wonder at its +yielding a more bounteous harvest of gobbledygook than the rest of the +world put together. + -- Sir Peter Medawar +%% +The use of COBOL cripples the mind; its teaching should, therefore, be +regarded as a criminal offense. + -- E. W. Dijkstra +%% +"The voters have spoken, the bastards ..." +%% +"The warning message we sent the Russians was a calculated ambiguity +that would be clearly understood." + -- Alexander Haig +%% +"The way to make a small fortune in the commodities market is to start +with a large fortune." +%% + THE WOMBAT + +The wombat lives across the seas, +Among the far Antipodes. +He may exist on nuts and berries, +Or then again, on missionaries; +His distant habitat precludes +Conclusive knowledge of his moods. +But I would not engage the wombat +In any form of mortal combat. +%% +The world is coming to an end! Repent and return those library books! +%% +The world is coming to an end. Please log off. +%% +The world's as ugly as sin, +And almost as delightful + -- Frederick Locker-Lampson +%% +The years of peak mental activity are undoubtedly between the ages of +four and eighteen. At four we know all the questions, at eighteen all +the answers. +%% +Then a man said: Speak to us of Expectations. + +He then said: If a man does not see or hear the waters of the Jordan, +then he should not taste the pomegranate or ply his wares in an open +market. + +If a man would not labour in the salt and rock quarries then he should +not accept of the Earth that which he refuses to give of himself. + +Such a man would expect a pear of a peach tree. +Such a man would expect a stone to lay an egg. +Such a man would expect Sears to assemble a lawnmower. + -- Kehlog Albran, "The Profit" +%% + THEORY +Into love and out again, + Thus I went and thus I go. +Spare your voice, and hold your pen: + Well and bitterly I know +All the songs were ever sung, + All the words were ever said; +Could it be, when I was young, + Someone dropped me on my head? + -- Dorothy Parker +%% +There are four kinds of homicide: felonious, excusable, justifiable, +and praiseworthy ... + -- Ambrose Bierce, "The Devil's Dictionary" +%% +There are really not many jobs that actually require a penis or a +vagina, and all other occupations should be open to everyone. + -- Gloria Steinem +%% + There are some goyisha names that just about guarantee that +someone isn't Jewish. For example, you'll never meet a Jew named +Johnson or Wright or Jones or Sinclair or Ricks or Stevenson or Reid or +Larsen or Jenks. But some goyisha names just about guarantee that +every other person you meet with that name will be Jewish. Why is +this? + Who knows? Learned rabbis have pondered this question for +centuries and have failed to come up with an answer, and you think ___you +can find one? Get serious. You don't even understand why it's +forbidden to eat crab -- fresh cold crab with mayonnaise -- or lobster +-- soft tender morsels of lobster dipped in melted butter. You don't +even understand a simple thing like that, and yet you hope to discover +why there are more Jews named Miller than Katz? Fat Chance. + -- Arthur Naiman, "Every Goy's Guide to Yiddish" +%% +There are some micro-organisms that exhibit characteristics of both +plants and animals. When exposed to light they undergo photosynthesis; +and when the lights go out, they turn into animals. But then again, +don't we all? +%% +There are three kinds of lies: Lies, Damn Lies, and Statistics. + -- Disraeli +%% +"There are three possibilities: Pioneer's solar panel has turned away +from the sun; there's a large meteor blocking transmission; or someone +loaded Star Trek 3.2 into our video processor." +%% +There are three possible parts to a date, of which at least two must be +offered: entertainment, food, and affection. It is customary to begin +a series of dates with a great deal of entertainment, a moderate amount +of food, and the merest suggestion of affection. As the amount of +affection increases, the entertainment can be reduced proportionately. +When the affection IS the entertainment, we no longer call it dating. +Under no circumstances can the food be omitted. + -- Miss Manners' Guide to Excruciatingly Correct Behaviour +%% +There are three ways to get something done: + 1. Do it yourself. + 2. Hire someone to do it for you. + 3. Forbid your kids to do it. +%% +There are three ways to get something done: do it yourself, hire +someone, or forbid your kids to do it. +%% +There are two kinds of solar-heat systems: "passive" systems collect +the sunlight that hits your home, and "active" systems collect the +sunlight that hits your neighbors' homes, too. + -- Dave Barry, "Postpetroleum Guzzler" +%% +"There are two ways of disliking poetry; one way is to dislike it, the +other is to read Pope." + -- Oscar Wilde +%% +There are two ways to write error-free programs. Only the third one +works. +%% +There are very few personal problems that cannot be solved through a +suitable application of high explosives. +%% +There cannot be a crisis next week. My schedule is already full. + -- Henry Kissinger +%% +There has been an alarming increase in the number of things you know +nothing about. +%% +There is a great discovery still to be made in Literature: that of +paying literary men by the quantity they do NOT write. +%% +There is a green, multi-legged creature crawling on your shoulder. +%% +There is a theory that states: "If anyone finds out what the universe +is for it will disappear and be replaced by something more bazaarly +inexplicable." + +There is another theory that states: "This has already happened ...." + -- Donald Adams, "Hitch-Hikers Guide to the Galaxy" +%% +There is a theory which states that if ever anyone discovers exactly +what the Universe is for and why it is here, it will instantly +disappear and be replaced by something even more bizarre and +inexplicable. There is another theory which states that this has +already happened. + -- Donald Adams, "The Hitchhiker's Guide to the Galaxy" +%% +There is no distinctly native American criminal class except Congress. + -- Mark Twain +%% +There is no realizable power that man cannot, in time, fashion the +tools to attain, nor any power so secure that the naked ape will not +abuse it. So it is written in the genetic cards -- only physics and +war hold him in check. And also the wife who wants him home by five, +of course. + -- Encyclopadia Apocryphia, 1990 ed. +%% +There is no satisfaction in hanging a man who does not object to it + -- G. B. Shaw +%% +There is no substitute for good manners, except, perhaps, fast +reflexes. +%% +There is no time like the present for postponing what you ought to be +doing. +%% +There is only one thing in the world worse than being talked about, and +that is not being talked about. + -- Oscar Wilde +%% +There is something fascinating about science. One gets such wholesale +returns of conjecture out of such a trifling investment of fact. + -- Mark Twain +%% +There once was a girl named Irene +Who lived on distilled kerosene + But she started absorbin' + A new hydrocarbon +And since then has never benzene. +%% +There once was an old man from Esser, +Who's knowledge grew lesser and lesser. + It at last grew so small, + He knew nothing at all, +And now he's a College Professor. +%% +"There was a boy called Eustace Clarence Scrubb, and he almost deserved +it." + -- C. S. Lewis, The Chronicles of Narnia +%% +There was a plane crash over mid-ocean, and only three survivors were +left in the life-raft: the Pope, the President, and Mayor Daley. +Unfortunately, it was a one-man life-raft, and quickly sinking, so they +started debating who should be allowed to stay. + +The Pope pointed out that he was the spiritual leader of millions all +over the world, the President explained that if he died then America +would be stuck with the Vice-President, and so forth. Then Mayor Daley +said, "Look! We're not solving anything like this! The only fair +thing to do is to vote on it." So they did, and Mayor Daley won by 97 +votes. +%% +There was a young lady from Hyde +Who ate a green apple and died. + While her lover lamented + The apple fermented +And made cider inside her inside. +%% +There was a young man who said "God, +I find it exceedingly odd, + That the willow oak tree + Continues to be, +When there's no one about in the Quad." + +"Dear Sir, your astonishment's odd, +For I'm always about in the Quad; + And that's why the tree, + Continues to be," +Signed "Yours faithfully, God." +%% +There was a young poet named Dan, +Whose poetry never would scan. + When told this was so, + He said, "Yes, I know. +It's because I try to put every possible syllable into that last line that I can." +%% +There were in this country two very large monopolies. The larger of +the two had the following record: the Vietnam War, Watergate, double- +digit inflation, fuel and energy shortages, bankrupt airlines, and the +8-cent postcard. The second was responsible for such things as the +transistor, the solar cell, lasers, synthetic crystals, high fidelity +stereo recording, sound motion pictures, radio astronomy, negative +feedback, magnetic tape, magnetic "bubbles", electronic switching +systems, microwave radio and TV relay systems, information theory, the +first electrical digital computer, and the first communications +satellite. Guess which one got to tell the other how to run the +telephone business? +%% +There's a fine line between courage and foolishness. Too bad its not a +fence. +%% +There's an old proverb that says just about whatever you want it to. +%% +There's little in taking or giving, + There's little in water or wine: +This living, this living, this living, + Was never a project of mine. +Oh, hard is the struggle, and sparse is + The gain of the one at the top, +For art is a form of catharsis, + And love is a permanent flop, +And work is the province of cattle, + And rest's for a clam in a shell, +So I'm thinking of throwing the battle -- + Would you kindly direct me to hell? + -- Dorothy Parker +%% +There's no future in time travel +%% +There's no point in being grown up if you can't be childish sometimes. + -- Dr. Who +%% +There's no real need to do housework -- after four years it doesn't get +any worse. +%% +There's only one way to have a happy marriage and as soon as I learn +what it is I'll get married again. + -- Clint Eastwood +%% +There's so much plastic in this culture that vinyl leopard skin is +becoming an endangered synthetic. + -- Lily Tomlin +%% +"These are DARK TIMES for all mankind's HIGHEST VALUES!" +"These are DARK TIMES for FREEDOM and PROSPERITY!" +"These are GREAT TIMES to put your money on BAD GUY to kick the CRAP +out of MEGATON MAN!" +%% +These days the necessities of life cost you about three times what they +used to, and half the time they aren't even fit to drink. +%% +They also surf who only stand on waves. +%% +They spell it "da Vinci" and pronounce it "da Vinchy". Foreigners +always spell better than they pronounce. + -- Mark Twain +%% +"They told me I was gullible ... and I believed them!" +%% +They told me you had proven it When they discovered our results + About a month before. Their hair began to curl +The proof was valid, more or less Instead of understanding it + But rather less than more. We'd run the thing through PRL. + +He sent them word that we would try Don't tell a soul about all this + To pass where they had failed For it must ever be +And after we were done, to them A secret, kept from all the rest + The new proof would be mailed. Between yourself and me. + +My notion was to start again + Ignoring all they'd done +We quickly turned it into code + To see if it would run. +%% +They're only trying to make me LOOK paranoid! +%% +Things are more like they used to be than they are now. +%% +Things will be bright in P.M. A cop will shine a light in your face. +%% +Think big. Pollute the Mississippi. +%% +Think honk if you're a telepath. +%% +Think of it! With VLSI we can pack 100 ENIACs in 1 sq. cm.! +%% +Think of it! With VLSI we can pack 100 ENIACs in 1 sq. cm.! +%% +Think of your family tonight. Try to crawl home after the +computer crashes. +%% +Think twice before speaking, but don't say "think think click click". +%% +This fortune cookie program out of order. For those in desperate need, +please use the program "________randchar". This program generates random +characters, and, given enough time, will undoubtedly come up with +something profound. It will, however, take it no time at all to be +more profound than THIS program has ever been. +%% +This fortune intentionally not included. +%% +This fortune is false. +%% +"This is a country where people are free to practice their religion, +regardless of race, creed, color, obesity, or number of dangling +keys ..." +%% +This is for all ill-treated fellows + Unborn and unbegot, +For them to read when they're in trouble + And I am not. + -- A. E. Housman +%% +This is National Non-Dairy Creamer Week. +%% +THIS IS PLEDGE WEEK FOR THE FORTUNE PROGRAM + +If you like the fortune program, why not support it now with your +contribution of a pithy fortune, clean or obscene? We cannot continue +without your support. Less than 14% of all fortune users are +contributors. That means that 86% of you are getting a free ride. We +can't go on like this much longer. Federal cutbacks mean less money +for fortunes, and unless user contributions increase to make up the +difference, the fortune program will have to shut down between midnight +and 8 a.m. Don't let this happen. Mail your fortunes right now to +"fortune". Just type in your favorite pithy saying. Do it now before +you forget. Our target is 300 new fortunes by the end of the week. +Don't miss out. All fortunes will be acknowledged. If you contribute +30 fortunes or more, you will receive a free subscription to "The +Fortune Hunter", our monthly program guide. If you contribute 50 or +more, you will receive a free "Fortune Hunter" coffee mug .... +%% +This is the story of the bee +Whose sex is very hard to see + +You cannot tell the he from the she +But she can tell, and so can he + +The little bee is never still +She has no time to take the pill + +And that is why, in times like these +There are so many sons of bees. +%% +This life is a test. It is only a test. Had this been an actual life, +you would have received further instructions as to what to do and where +to go. +%% +This login session: $13.99, but for you $11.88 +%% +This planet has -- or rather had -- a problem, which was this: most of +the people living on it were unhappy for pretty much of the time. Many +solutions were suggested for this problem, but most of these were +largely concerned with the movements of small green pieces of paper, +which is odd because on the whole it wasn't the small green pieces of +paper that were unhappy. + -- Douglas Adams +%% + ... This striving for excellence extends into people's +personal lives as well. When '80s people buy something, they buy the +best one, as determined by (1) price and (2) lack of availability. +Eighties people buy imported dental floss. They buy gourmet baking +soda. If an '80s couple goes to a restaurant where they have made a +reservation three weeks in advance, and they are informed that their +table is available, they stalk out immediately, because they know it is +not an excellent restaurant. If it were, it would have an enormous +crowd of excellence-oriented people like themselves waiting, their +beepers going off like crickets in the night. An excellent restaurant +wouldn't have a table ready immediately for anybody below the rank of +Liza Minnelli. + -- Dave Barry, "In Search of Excellence" +%% +This will be a memorable month -- no matter how hard you try to forget +it. +%% + Thompson, if he is to be believed, has sampled the entire +rainbow of legal and illegal drugs in heroic efforts to feel better +than he does. + As for the truth about his health: I have asked around about +it. I am told that he appears to be strong and rosy, and steadily +sane. But we will be doing what he wants us to do, I think, if we +consider his exterior a sort of Dorian Gray facade. Inwardly, he is +being eaten alive by tinhorn politicians. + The disease is fatal. There is no known cure. The most we can +do for the poor devil, it seems to me, is to name his disease in his +honor. From this moment on, let all those who feel that Americans can +be as easily led to beauty as to ugliness, to truth as to public +relations, to joy as to bitterness, be said to be suffering from Hunter +Thompson's disease. I don't have it this morning. It comes and goes. +This morning I don't have Hunter Thompson's disease. + -- Kurt Vonnegut Jr. on Dr. Hunter S. Thompson: Excerpt + from "A Political Disease", Vonnegut's review of "Fear + and Loathing: On the Campaign Trail '72" +%% +Those who can't write, write manuals. +%% +Those who can, do. Those who can't, simulate. +%% +Those who educate children well are more to be honored than parents, +for these only gave life, those the art of living well. + -- Aristotle +%% +Those who in quarrels interpose, must often wipe a bloody nose. +%% +Those who make peaceful revolution impossible will make violent +revolution inevitable. + -- John F. Kennedy +%% +Three great scientific theories of the structure of the universe are +the molecular, the corpuscular and the atomic. A fourth affirms, with +Haeckel, the condensation or precipitation of matter from ether -- +whose existence is proved by the condensation or precipitation ... A +fifth theory is held by idiots, but it is doubtful if they know any +more about the matter than the others. + -- Ambrose Bierce, "The Devil's Dictionary" +%% +Time flies like an arrow +Fruit flies like a banana +%% +Time is nature's way of making sure that everything doesn't happen at +once. +%% + (to "The Caissons Go Rolling Along") +Scratch the disks, dump the core, Shut it down, pull the plug +Roll the tapes across the floor, Give the core an extra tug +And the system is going to crash. And the system is going to crash. +Teletypes smashed to bits. Mem'ry cards, one and all, +Give the scopes some nasty hits Toss out halfway down the hall +And the system is going to crash. And the system is going to crash. +And we've also found Just flip one switch +When you turn the power down, And the lights will cease to twitch +You turn the disk readers into trash. And the tape drives will crumble + in a flash. +Oh, it's so much fun, When the CPU +Now the CPU won't run Can print nothing out but "foo," +And the system is going to crash. The system is going to crash. +%% + To A Quick Young Fox: +Why jog exquisite bulk, fond crazy vamp, +Daft buxom jonquil, zephyr's gawky vice? +Guy fed by work, quiz Jove's xanthic lamp -- +Zow! Qualms by deja vu gyp fox-kin thrice. + -- Lazy Dog +%% +To be intoxicated is to feel sophisticated but not be able to say it. +%% +To be is to do. + -- I. Kant +To do is to be. + -- A. Sartre +Yabba-Dabba-Doo! + -- F. Flinstone +%% +To be sure of hitting the target, shoot first and, whatever you hit, +call it the target. +%% +To err is human, to forgive is Not Company Policy. +%% +To invent, you need a good imagination and a pile of junk. + -- Thomas Edison +%% +To iterate is human, to recurse, divine. +%% +To those accustomed to the precise, structured methods of conventional +system development, exploratory development techniques may seem messy, +inelegant, and unsatisfying. But it's a question of congruence: +precision and flexibility may be just as disfunctional in novel, +uncertain situations as sloppiness and vacillation are in familiar, +well-defined ones. Those who admire the massive, rigid bone structures +of dinosaurs should remember that jellyfish still enjoy their very +secure ecological niche. + -- Beau Sheil, "Power Tools for Programmers" +%% +"To vacillate or not to vacillate, that is the question ... or is it?" +%% +"To YOU I'm an atheist; to God, I'm the Loyal Opposition." + -- Woody Allen +%% +Today is a good day to bribe a high-ranking public official. +%% +Today is National Existential Ennui Awareness Day. +%% +Today is the first day of the rest of the mess +%% +Today is the tomorrow you worried about yesterday +%% +Today's scientific question is: What in the world is electricity? + +And where does it go after it leaves the toaster? + -- Dave Barry, "What is Electricity?" +%% +Tomorrow will be canceled due to lack of interest. +%% +Tonight's the night: Sleep in a eucalyptus tree. +%% +Too much of a good thing is WONDERFUL. + -- Mae West +%% +Travel important today; Internal Revenue men arrive tomorrow. +%% +Troubled day for virgins over 16 who are beautiful and wealthy and live +in eucalyptus trees. +%% +Truly great madness can not be achieved without significant +intelligence. + -- Henrik Tikkanen +%% +Truth will be out this morning. (Which may really mess things up.) +%% +Truthful, adj.: + Dumb and illiterate. +%% +Truthful, adj.: + Dumb and illiterate. + -- Ambrose Bierce, "The Devil's Dictionary" +%% +Try not to have a good time ... This is supposed to be educational. + -- Charles Schulz +%% +Try to be the best of whatever you are, even if what you are is no +good. +%% +Try to get all of your posthumous medals in advance. +%% +Trying to be happy is like trying to build a machine for which the only +specification is that it should run noiselessly. +%% +Turnaucka's Law: + The attention span of a computer is only as long as its + electrical cord. +%% +Tussman's Law: + Nothing is as inevitable as a mistake whose time has come. +%% +TV is chewing gum for the eyes. + -- Frank Lloyd Wright +%% +'Twas midnight, and the UNIX hacks +Did gyre and gimble in their cave +All mimsy was the CS-VAX +And Cory raths outgrave. + +"Beware the software rot, my son! +The faults that bite, the jobs that thrash! +Beware the broken pipe, and shun +The frumious system crash!" +%% + 'Twas the Night before Crisis + +'Twas the night before crisis, and all through the house, + Not a program was working not even a browse. +The programmers were wrung out too mindless to care, + Knowing chances of cutover hadn't a prayer. +The users were nestled all snug in their beds, + While visions of inquiries danced in their heads. +When out in the lobby there arose such a clatter, + I sprang from my tube to see what was the matter. +And what to my wondering eyes should appear, + But a Super Programmer, oblivious to fear. +More rapid than eagles, his programs they came, + And he whistled and shouted and called them by name; +On Update! On Add! On Inquiry! On Delete! + On Batch Jobs! On Closing! On Functions Complete! +His eyes were glazed over, his fingers were lean, + From Weekends and nights in front of a screen. +A wink of his eye, and a twist of his head, + Soon gave me to know I had nothing to dread... +%% +'Twas the nocturnal segment of the diurnal period + preceding the annual Yuletide celebration, And + throughout our place of residence, +Kinetic activity was not in evidence among the + possessors of this potential, including that + species of domestic rodent known as Mus musculus. +Hosiery was meticulously suspended from the forward + edge of the woodburning caloric apparatus, +Pursuant to our anticipatory pleasure regarding an + imminent visitation from an eccentric + philanthropist among whose folkloric appelations + is the honorific title of St. Nicklaus ... +%% +Two can Live as Cheaply as One for Half as Long. + -- Howard Kandel +%% +Two percent of zero is almost nothing. +%% +UFO's are for real: the Air Force doesn't exist. +%% +"Uncle Cosmo ... why do they call this a word processor?" + +"It's simple, Skyler ... you've seen what food processors do to food, +right?" + -- MacNelley, "Shoe" +%% +Uncle Ed's Rule of Thumb: + Never use your thumb for a rule. You'll either hit it with a + hammer or get a splinter in it. +%% +Under deadline pressure for the next week. If you want something, it +can wait. Unless it's blind screaming paroxysmally hedonistic ... +%% +Underlying Principle of Socio-Genetics: + Superiority is recessive. +%% +Unfair animal names: + +-- tsetse fly -- bullhead +-- booby -- duck-billed platypus +-- sapsucker -- Clarence + -- Gary Larson +%% +United Nations, New York, December 25. The peace and joy of the +Christmas season was marred by a proclamation of a general strike of +all the military forces of the world. Panic reigns in the hearts of +all the patriots of every persuasion. + +Meanwhile, fears of universal disaster sank to an all-time low over the +world. + -- Isaac Asimov +%% +Universe, n.: + The problem. +%% +University, n.: + Like a software house, except the software's free, and it's +usable, and it works, and if it breaks they'll quickly tell you how to +fix it, and ... +%% +Unnamed Law: + If it happens, it must be possible. +%% +Unquestionably, there is progress. The average American now pays out +twice as much in taxes as he formerly got in wages. + -- H. L. Mencken +%% +Usage: fortune -P [] -a [xsz] [Q: [file]] [rKe9] -v6[+] dataspec ... inputdir +%% +User n.: + A programmer who will believe anything you tell him. +%% +Using TSO is like kicking a dead whale down the beach. + -- S. C. Johnson +%% +Vail's Second Axiom: + The amount of work to be done increases in proportion to the + amount of work already completed. +%% +Van Roy's Law: + An unbreakable toy is useful for breaking other toys. +%% +Velilind's Laws of Experimentation: + 1. If reproducibility may be a problem, conduct the test only + once. + 2. If a straight line fit is required, obtain only two data + points. +%% + "Verily and forsooth," replied Goodgulf darkly. "In the past +year strange and fearful wonders I have seen. Fields sown with barley +reap crabgrass and fungus, and even small gardens reject their +artichoke hearts. There has been a hot day in December and a blue +moon. Calendars are made with a month of Sundays and a blue-ribbon +Holstein bore alive two insurance salesmen. The earth splits and the +entrails of a goat were found tied in square knots. The face of the +sun blackens and the skies have rained down soggy potato chips." + + "But what do all these things mean?" gasped Frito. + + "Beats me," said Goodgulf with a shrug, "but I thought it made +good copy." + -- Harvard Lampoon, "Bored of the Rings" +%% +Very few profundities can be expressed in less than 80 characters. +%% +Violence is the last refuge of the incompetent. + -- Salvor Hardin +%% +VIRGO (Aug 23 - Sept 22) + Learn something new today, like how to spell or how to count to + ten without using your fingers. Be careful dressing this + morning. You may be hit by a car later in the day and you + wouldn't want to be taken to the doctor's office in some of + that old underwear you own. +%% + VIRGO (Aug 23 - Sept 22) +You are the logical type and hate disorder. This nitpicking is +sickening to your friends. You are cold and unemotional and sometimes +fall asleep while making love. Virgos make good bus drivers. +%% +Virtue is its own punishment. +%% +Vital papers will demonstrate their vitality by spontaneously moving +from where you left them to where you can't find them. +%% +Vitamin C deficiency is apauling +%% +Vote anarchist +%% +"Wagner's music is better than it sounds." + -- Mark Twain +%% +Waiter: "Tea or coffee, gentlemen?" +1st customer: "I'll have tea." +2nd customer: "Me, too -- and be sure the glass is clean!" + (Waiter exits, returns) +Waiter: "Two teas. Which one asked for the clean glass?" +%% +War hath no fury like a non-combatant. + -- Charles Edward Montague +%% +WARNING: + Reading this fortune can affect the dimensionality of your + mind, change the curvature of your spine, cause the growth of + hair on your palms, and make a difference in the outcome of + your favorite war. +%% +Washington [D.C.] is a city of Southern efficiency and Northern charm. + -- John F. Kennedy +%% +Wasting time is an important part of living. +%% +Watson's Law: + The reliability of machinery is inversely proportional to the + number and significance of any persons watching it. +%% +We ARE as gods and might as well get good at it. + -- Whole Earth Catalog +%% +We are confronted with insurmountable opportunities. + -- Walt Kelly, "Pogo" +%% +We are confronted with insurmountable opportunities. + -- Walt Kelly, "Pogo" +%% +We can defeat gravity. The problem is the paperwork involved. +%% +"We don't care. We don't have to. We're the Phone Company." +%% +We don't understand the software, and sometimes we don't understand the +hardware, but we can *___see* the blinking lights! +%% +We have met the enemy, and he is us. + -- Walt Kelly +%% +"We have reason to believe that man first walked upright to free his +hands for masturbation." + -- Lily Tomlin +%% +We may not return the affection of those who like us, but we always +respect their good judgement. +%% +We must remember the First Amendment which protects any shrill jackass +no matter how self-seeking. + -- F. G. Withington +%% +We really don't have any enemies. It's just that some of our best +friends are trying to kill us. +%% + We were young and our happiness dazzled us with its strength. +But there was also a terrible betrayal that lay within me like a Merle +Haggard song at a French restaurant. ... + I could not tell the girl about the woman of the tollway, of +her milk white BMW and her Jordache smile. There had been a fight. I +had punched her boyfriend, who fought the mechanical bulls. Everyone +told him, "You ride the bull, senor. You do not fight it." But he was +lean and tough like a bad rib-eye and he fought the bull. And then he +fought me. And when we finished there were no winners, just men doing +what men must do. ... + "Stop the car," the girl said. There was a look of terrible +sadness in her eyes. She knew about the woman of the tollway. I knew +not how. I started to speak, but she raised an arm and spoke with a +quiet and peace I will never forget. + "I do not ask for whom's the tollway belle," she said, "the +tollway belle's for thee." + The next morning our youth was a memory, and our happiness was +a lie. Life is like a bad margarita with good tequila, I thought as I +poured whiskey onto my granola and faced a new day. + -- Peter Applebome, International Imitation Hemingway + Competition +%% +We will have solar energy as soon as the utility companies solve one +technical problem -- how to run a sunbeam through a meter. +%% +we will invent new lullabies, new songs, new acts of love, +we will cry over things we used to laugh & +our new wisdom will bring tears to eyes of gentile +creatures from other planets who were afraid of us till then & +in the end a summer with wild winds & +new friends will be. +%% +We wish you a Hare Krishna +We wish you a Hare Krishna +We wish you a Hare Krishna +And a Sun Myung Moon! + -- Maxwell Smart +%% +"We'll cross out that bridge when we come back to it later." +%% +We're deep into the holiday gift-giving season, as you can tell from +the fact that everywhere you look, you see jolly old St. Nick urging +you to purchase things, to the point where you want to slug him right +in his bowl full of jelly. + -- Dave Barry, "Simple, Homespun Gifts" +%% +We've sent a man to the moon, and that's 29,000 miles away. The center +of the Earth is only 4,000 miles away. You could drive that in a week, +but for some reason nobody's ever done it. + -- Andy Rooney +%% +Weiler's Law: + Nothing is impossible for the man who doesn't have to do it + himself. +%% +Weinberg's First Law: + Progress is made on alternate Fridays. +%% +Weinberg's Principle: + An expert is a person who avoids the small errors while + sweeping on to the grand fallacy. +%% +Weinberg's Second Law: + If builders built buildings the way programmers wrote programs, + then the first woodpecker that came along would destroy + civilization. +%% +Weiner's Law of Libraries: + There are no answers, only cross references. +%% +Well, I would -- if they realized that we -- again if -- if we led them +back to that stalemate only because our retaliatory power, our seconds, +or strike at them after our first strike, would be so destructive they +they couldn't afford it, that would hold them off. + -- President Ronald Reagan, on the MX missile +%% +"Well, if you can't believe what you read in a comic book, what *___can* +you believe?!" + -- Bullwinkle J. Moose [Jay Ward] +%% +Well, my terminal's locked up, and I ain't got any Mail, + And I can't recall the last time that my program didn't fail; +I've got stacks in my structs, I've got arrays in my queues, + I've got the : Segmentation violation -- Core dumped blues. + +If you think that it's nice that you get what you C, + Then go : illogical statement with your whole family, +'Cause the Supreme Court ain't the only place with : Bus error views. + I've got the : Segmentation violation -- Core dumped blues. + +On a PDP-11, life should be a breeze, + But with VAXen in the house even magnetic tapes would freeze. +Now you might think that unlike VAXen I'd know who I abuse, + I've got the : Segmentation violation -- Core dumped blues. + -- Core Dumped Blues +%% +Westheimer's Discovery: + A couple of months in the laboratory can frequently save a + couple of hours in the library. +%% +Wethern's Law: + Assumption is the mother of all screw-ups. +%% + "What do you give a man who has everything?" the pretty +teenager asked her mother. + "Encouragement, dear," she replied. +%% +What does it mean if there is no fortune for you? +%% +What garlic is to food, insanity is to art. +%% +What garlic is to salad, insanity is to art. +%% +What good is a ticket to the good life, if you can't find the +entrance? +%% +What good is having someone who can walk on water if you don't follow +in his footsteps? +%% +What I tell you three times is true. +%% +What I want is all of the power and none of the responsibility. +%% +What if everything is an illusion and nothing exists? In that case, I +definitely overpaid for my carpet. + -- Woody Allen, "Without Feathers" +%% +What if nothing exists and we're all in somebody's dream? Or what's +worse, what if only that fat guy in the third row exists? + -- Woody Allen, "Without Feathers" +%% +What is a magician but a practising theorist? + -- Obi-Wan Kenobi +%% +What is mind? No matter. +What is matter? Never mind. + -- Thomas Hewitt Key, 1799-1875 +%% +What is the difference between a Turing machine and the modern +computer? It's the same as that between Hillary's ascent of Everest +and the establishment of a Hilton on its peak. +%% +"What is the robbing of a bank compared to the FOUNDING of a bank?" + -- Bertold Brecht +%% +What is worth doing is worth the trouble of asking somebody to do. +%% +What makes the Universe so hard to comprehend is that there's nothing +to compare it with. +%% +What makes the universe so hard to comprehend is that there's nothing +to compare it with. +%% +What publishers are looking for these days isn't radical feminism. +It's corporate feminism -- a brand of feminism designed to sell books +and magazines, three-piece suits, airline tickets, Scotch, cigarettes +and, most important, corporate America's message, which runs: "Yes, +women were discriminated against in the past, but that unfortunate +mistake has been remedied; now every woman can attain wealth, prestige +and power by dint of individual rather than collective effort." + -- Susan Gordon +%% +What sane person could live in this world and not be crazy? + -- Ursula K. LeGuin +%% +What the hell, go ahead and put all your eggs in one basket. +%% +What the large print giveth, the small print taketh away. +%% +What this country needs is a dime that will buy a good five-cent +bagel. +%% +What this country needs is a dime that will buy a good five-cent +bagel. +%% +What this country needs is a good 5 dollar plasma weapon. +%% +What this country needs is a good five cent ANYTHING! +%% +What this country needs is a good five-cent nickel. +%% +What use is magic if it can't save a unicorn? + -- Peter S. Beagle, "The Last Unicorn" +%% +What with chromodynamics and electroweak too + Our Standardized Model should please even you, +Tho once you did say that of charm there was none + It took courage to switch as to say Earth moves not Sun. +Yet your state of the union penultimate large + Is the last known haunt of the Fractional Charge, +And as you surf in the hot tub with sourdough roll + Please ponder the passing of your sole Monopole. +Your Olympics were fun, you should bring them all back + For transsexual tennis or Anamalon Track, +But Hollywood movies remain sinfully crude + Whether seen on the telly or Remotely Viewed. +Now fasten your sunbelts, for you've done it once more, + You said it in Leipzig of the thing we adore, +That you've built an incredible crystalline sphere + Whose German attendants spread trembling and fear +Of the death of our theory by Particle Zeta + Which I'll bet is not there say your article, later. + -- Sheldon Glashow, Physics Today, Dec. 1984 +%% + "What's that thing?" + "Well, it's a highly technical, sensitive instrument we use in +computer repair. Being a layman, you probably can't grasp exactly what +it does. We call it a two-by-four." + -- Jeff MacNelly, "Shoe" +%% +Whatever became of eternal truth? +%% +Whatever became of Strange de Jim? Well, he found a substitute for +cocaine: "You cover Q-tips with sandpaper and ram them up your nostrils +as far as they will go. Then you sniff talcum powder while shredding +hundred dollar bills." + -- Herb Caen +%% +Whatever is not nailed down is mine. What I can pry loose is not +nailed down. + -- Collis P. Huntingdon +%% +When a Banker jumps out of a window, jump after him -- that's where the +money is. + -- Robespierre +%% +When a fellow says, "It ain't the money but the principle of the +thing," it's the money. + -- Kim Hubbard +%% +When a fly lands on the ceiling, does it do a half roll or a half +loop? +%% +When a place gets crowded enough to require ID's, social collapse is +not far away. It is time to go elsewhere. The best thing about space +travel is that it made it possible to go elsewhere. + -- Robert Heinlein +%% +When a shepherd goes to kill a wolf, and takes his dog along to see the +sport, he should take care to avoid mistakes. The dog has certain +relationships to the wolf the shepherd may have forgotten. + -- Robert Pirsig, "Zen and the Art of Motorcycle + Maintenance" +%% +When all other means of communication fail, try words. +%% +When does summertime come to Minnesota, you ask? Well, last year, I +think it was a Tuesday. +%% +When God endowed human beings with brains, He did not intend to +guarantee them. +%% +When I said "we", officer, I was referring to myself, the four young +ladies, and, of course, the goat. +%% +When I was a boy I was told that anybody could become President. Now +I'm beginning to believe it. + -- Clarence Darrow +%% +When I was in school, I cheated on my metaphysics exam: I looked into +the soul of the boy sitting next to me. + -- Woody Allen +%% +When I was younger, I could remember anything, whether it had happened +or not; but my faculties are decaying now and soon I shall be so I +cannot remember any but the things that never happened. It is sad to +go to pieces like this but we all have to do it. + -- Mark Twain +%% +When in doubt, do what the President does -- guess. +%% +"When in doubt, tell the truth." + -- Mark Twain +%% +When in doubt, use brute force. + -- Ken Thompson +%% +When love is gone, there's always justice. +And when justice is gone, there's always force. +And when force is gone, there's always Mom. +Hi, Mom! + -- Laurie Anderson +%% +When Marriage is Outlawed, +Only Outlaws will have Inlaws. +%% +When more and more people are thrown out of work, unemployment +results. + -- Calvin Coolidge +%% +When someone says "I want a programming language in which I need only +say what I wish done," give him a lollipop. +%% +"When the going gets tough, the tough get empirical" + -- Jon Carroll +%% +When the government bureau's remedies do not match your problem, you +modify the problem, not the remedy. +%% +When the Ngdanga tribe of West Africa hold their moon love ceremonies, +the men of the tribe bang their heads on sacred trees until they get a +nose bleed, which usually cures them of ____that. + -- Mike Harding, "The Armchair Anarchist's Almanac" +%% +When the Universe was not so out of whack as it is today, and all the +stars were lined up in their proper places, you could easily count them +from left to right, or top to bottom, and the larger and bluer ones +were set apart, and the smaller yellowing types pushed off to the +corners as bodies of a lower grade ... + -- Stanislaw Lem, "Cyberiad" +%% +When two people are under the influence of the most violent, most +insane, most delusive, and most transient of passions, they are +required to swear that they will remain in that excited, abnormal, and +exhausting condition continuously until death do them part. + -- George Bernard Shaw +%% +When we are planning for posterity, we ought to remember that virtue is +not hereditary. + -- Thomas Paine +%% +"When you are in it up to your ears, keep your mouth shut." +%% +When you do not know what you are doing, do it neatly. +%% + When you have shot and killed a man you have in some measure +clarified your attitude toward him. You have given a definite answer +to a definite problem. For better or worse you have acted decisively. + In a way, the next move is up to him. + -- R. A. Lafferty +%% +"When you have to kill a man it costs nothing to be polite." + -- Winston Curchill, On formal declarations of war +%% +When you make your mark in the world, watch out for guys with erasers. + -- The Wall Street Journal +%% +When you're away, I'm restless, lonely, +Wretched, bored, dejected; only +Here's the rub, my darling dear +I feel the same when you are near. + -- Samuel Hoffenstein, "When You're Away" +%% +When you're not looking at it, this fortune is written in FORTRAN. +%% +When you're not looking at it, this fortune is written in FORTRAN. +%% +Whenever anyone says, "theoretically", they really mean, "not really". + -- Dave Parnas +%% +Whenever I hear anyone arguing for slavery, I feel a strong impulse to +see it tried on him personally. + -- A. Lincoln +%% +Whenever people agree with me I always feel I must be wrong. + --Oscar Wilde +%% +Whenever the literary German dives into a sentence, that is the last +you are going to see of him until he emerges on the other side of his +Atlantic with his verb in his mouth. + -- Mark Twain + "Connecticut Yankee in King Arthur's Court" +%% +Whenever you find that you are on the side of the majority, it is time +to reform. + -- Mark Twain +%% +Whenever you find that you are on the side of the majority, it is time +to reform. + -- Mark Twain +%% +WHERE CAN THE MATTER BE + + Oh, dear, where can the matter be + When it's converted to energy? + There is a slight loss of parity. + Johnny's so long at the fair. +%% +Where humor is concerned there are no standards -- no one can say what +is good or bad, although you can be sure that everyone will. + -- John Kenneth Galbraith +%% +Where there's a will, there's an Inheritance Tax. +%% +Whether you can hear it or not +The Universe is laughing behind your back + -- National Lampoon, "Deteriorada" +%% +While anyone can admit to themselves they were wrong, the true test is +admission to someone else. +%% +While Europe's eye is fix'd on mighty things, +The fate of empires and the fall of kings; +While quacks of State must each produce his plan, +And even children lisp the Rights of Man; +Amid this mighty fuss just let me mention, +The Rights of Woman merit some attention. + -- Robert Burns, Address on "The Rights of Woman", + November 26, 1792 +%% +While money can't buy happiness, it certainly lets you choose your own +form of misery. +%% +While money doesn't buy love, it puts you in a great bargaining +position. +%% +While most peoples' opinions change, the conviction of their +correctness never does. +%% +While you don't greatly need the outside world, it's still very +reassuring to know that it's still there. +%% +While your friend holds you affectionately by both your hands you are +safe, for you can watch both of his. + -- Ambrose Bierce, "The Devil's Dictionary" +%% +Whistler's Law: + You never know who is right, but you always know who is in + charge. +%% +"Who cares if it doesn't do anything? It was made with our new +Triple-Iso-Bifurcated-Krypton-Gate-MOS process ..." +%% +Who made the world I cannot tell; +'Tis made, and here am I in hell. +My hand, though now my knuckles bleed, +I never soiled with such a deed. + -- A. E. Housman +%% +Who needs friends when you can sit alone in your room and drink? +%% +Who's on first? +%% +Whom computers would destroy, they must first drive mad. +%% +"Why be a man when you can be a success?" + -- Bertold Brecht +%% +Why did the Lord give us so much quickness of movement unless it was to +avoid responsibility with? +%% +Why did the Roman Empire collapse? What is the Latin for office +automation? +%% +Why does man kill? He kills for food. And not only food: frequently +there must be a beverage. + -- Woody Allen, "Without Feathers" +%% +Why I Can't Go Out With You: + +I'd LOVE to, but ... + -- I have to floss my cat. + -- I've dedicated my life to linguini. + -- I need to spend more time with my blender. + -- it wouldn't be fair to the other Beautiful People. + -- it's my night to pet the dog/ferret/goldfish. + -- I'm going downtown to try on some gloves. + -- I have to check the freshness dates on my dairy products. + -- I'm going down to the bakery to watch the buns rise. + -- I have an appointment with a cuticle specialist. + -- I have some really hard words to look up. + -- I've got a Friends of the Lowly Rutabaga meeting. + -- I promised to help a friend fold road maps. +%% +"Why is it that we rejoice at a birth and grieve at a funeral? It is +because we are not the person involved" + -- Mark Twain +%% +"Why isn't there a special name for the tops of your feet?" + -- Lily Tomlin +%% +Why not have an old-fashioned Christmas for your family this year? +Just picture the scene in your living room on Christmas morning as your +children open their old-fashioned presents. + +Your 11-year-old son: "What the heck is this?" + +You: "A spinning top! You spin it around, and then eventually it + falls down. What fun! Ha, ha!" + +Son: "Is this a joke? Jason Thompson's parents got him a computer + with two disk drives and 128 kilobytes of random-access memory, + and I get this cretin TOP?" + +Your 8-year-old daughter: "You think that's bad? Look at this." + +You: "It's figgy pudding! What a treat!" + +Daughter: "It looks like goat barf." + -- Dave Barry, "Simple, Homespun Gifts" +%% +"Why was I born with such contemporaries?" + -- Oscar Wilde +%% +Wiker's Law: + Government expands to absorb revenue and then some. +%% + William Safire's Rules for Writers: + +Remember to never split an infinitive. The passive voice should never +be used. Do not put statements in the negative form. Verbs have to +agree with their subjects. Proofread carefully to see if you words +out. If you reread your work, you can find on rereading a great deal +of repetition can be avoided by rereading and editing. A writer must +not shift your point of view. And don't start a sentence with a +conjunction. (Remember, too, a preposition is a terrible word to end a +sentence with.) Don't overuse exclamation marks!! Place pronouns as +close as possible, especially in long sentences, as of 10 or more +words, to their antecedents. Writing carefully, dangling participles +must be avoided. If any word is improper at the end of a sentence, a +linking verb is. Take the bull by the hand and avoid mixing +metaphors. Avoid trendy locutions that sound flaky. Everyone should +be careful to use a singular pronoun with singular nouns in their +writing. Always pick on the correct idiom. The adverb always follows +the verb. Last but not least, avoid cliches like the plague; seek +viable alternatives. +%% +Williams and Holland's Law: + If enough data is collected, anything may be proven by + statistical methods. +%% +Winter is the season in which people try to keep the house as warm as +it was in the summer, when they complained about the heat. +%% +Wit, n.: + The salt with which the American Humorist spoils his cookery +... by leaving it out. + -- Ambrose Bierce, "The Devil's Dictionary" +%% +With a rubber duck, one's never alone. + -- "The Hitchhiker's Guide to the Galaxy" +%% +With all the fancy scientists in the world, why can't they just once +build a nuclear balm? +%% +With every passing hour our solar system comes forty-three thousand +miles closer to globular cluster M13 in the constellation Hercules, and +still there are some misfits who continue to insist that there is no +such thing as progress. + -- Ransom K. Ferm +%% +Without ice cream life and fame are meaningless. +%% +Wood is highly ecological, since trees are a renewable resource. If +you cut down a tree, another will grow in its place. And if you cut +down the new tree, still another will grow. And if you cut down that +tree, yet another will grow, only this one will be a mutation with +long, poisonous tentacles and revenge in its heart, and it will sit +there in the forest, cackling and making elaborate plans for when you +come back. + +Wood heat is not new. It dates back to a day millions of years ago, +when a group of cavemen were sitting around, watching dinosaurs rot. +Suddenly, lightning struck a nearby log and set it on fire. One of the +cavemen stared at the fire for a few minutes, then said: "Hey! Wood +heat!" The other cavemen, who did not understand English, immediately +beat him to death with stones. But the key discovery had been made, +and from that day forward, the cavemen had all the heat they needed, +although their insurance rates went way up. + -- Dave Barry, "Postpetroleum Guzzler" +%% +Workers of the world, arise! You have nothing to lose but your +chairs. +%% +Worst Month of 1981 for Downhill Skiing: + August. The lines are the shortest, though. + -- Steve Rubenstein +%% +Worst Month of the Year: + February. February has only 28 days in it, which means that if +you rent an apartment, you are paying for three full days you don't +get. Try to avoid Februarys whenever possible. + -- Steve Rubenstein +%% +Worst Vegetable of the Year: + The brussels sprout. This is also the worst vegetable of next +year. + -- Steve Rubenstein +%% +"Would you tell me, please, which way I ought to go from here?" + +"That depends a good deal on where you want to get to," said the Cat + -- Lewis Carrol +%% +Write-Protect Tab, n.: + A small sticker created to cover the unsightly notch carelessly +left by disk manufacturers. The use of the tab creates an error +message once in a while, but its aesthetic value far outweighs the +momentary inconvenience. + -- Robb Russon +%% +X-rated movies are all alike ... the only thing they leave to the +imagination is the plot. +%% +Xerox does it again and again and again and ... +%% +Xerox never comes up with anything original. +%% +"Yacc" owes much to a most stimulating collection of users, who have +goaded me beyond my inclination, and frequently beyond my ability in +their endless search for "one more feature". Their irritating +unwillingness to learn how to do things my way has usually led to my +doing things their way; most of the time, they have been right. + -- S. C. Johnson, "Yacc guide acknowledgements" +%% +Year, n.: + A period of three hundred and sixty-five disappointments. + -- Ambrose Bierce, "The Devil's Dictionary" +%% +Yes, but every time I try to see things your way, I get a headache. +%% +Yes, but which self do you want to be? +%% +Yesterday I was a dog. Today I'm a dog. Tomorrow I'll probably still +be a dog. Sigh! There's so little hope for advancement. + -- Snoopy +%% +Yesterday upon the stair +I met a man who wasn't there. +He wasn't there again today -- +I think he's from the CIA. +%% +Yield to Temptation ... it may not pass your way again. + -- Lazarus Long, "Time Enough for Love" +%% +Yinkel, n.: + A person who combs his hair over his bald spot, hoping no one +will notice. + -- Rich Hall, "Sniglets" +%% +"You are old, Father William," the young man said, + "All your papers these days look the same; +Those William's would be better unread -- + Do these facts never fill you with shame?" + +"In my youth," Father William replied to his son, + "I wrote wonderful papers galore; +But the great reputation I found that I'd won, + Made it pointless to think any more." +%% +"You are old, father William," the young man said, + "And your hair has become very white; +And yet you incessantly stand on your head -- + Do you think, at your age, it is right?" + +"In my youth," father William replied to his son, + "I feared it might injure the brain; +But, now that I'm perfectly sure I have none, + Why, I do it again and again." + -- Lewis Carrol +%% +"You are old," said the youth, "and I'm told by my peers + That your lectures bore people to death. +Yet you talk at one hundred conventions per year -- + Don't you think that you should save your breath?" + +"I have answered three questions and that is enough," + Said his father, "Don't give yourself airs! +Do you think I can listen all day to such stuff? + Be off, or I'll kick you downstairs!" +%% +"You are old," said the youth, "and your jaws are too weak + For anything tougher than suet; +Yet you finished the goose, with the bones and the beak -- + Pray, how did you manage to do it?" + +"In my youth," said his father, "I took to the law, + And argued each case with my wife; +And the muscular strength which it gave to my jaw, + Has lasted the rest of my life." + -- Lewis Carrol +%% +"You are old," said the youth, "and your programs don't run, + And there isn't one language you like; +Yet of useful suggestions for help you have none -- + Have you thought about taking a hike?" + +"Since I never write programs," his father replied, + "Every language looks equally bad; +Yet the people keep paying to read all my books + And don't realize that they've been had." +%% +"You are old," said the youth, "as I mentioned before, + And have grown most uncommonly fat; +Yet you turned a back-somersault in at the door -- + Pray what is the reason of that?" + +"In my youth," said the sage, as he shook his grey locks, + "I kept all my limbs very supple +By the use of this ointment -- one shilling the box -- + Allow me to sell you a couple?" + -- Lewis Carrol +%% +"You are old," said the youth, "as I mentioned before, + And make errors few people could bear; +You complain about everyone's English but yours -- + Do you really think this is quite fair?" + +"I make lots of mistakes," Father William declared, + "But my stature these days is so great +That no critic can hurt me -- I've got them all scared, + And to stop me it's now far too late." +%% +"You are old," said the youth, "one would hardly suppose + That your eye was as steady as ever; +Yet you balanced an eel on the end of your nose -- + What made you so awfully clever?" + +"I have answered three questions, and that is enough," + Said his father. "Don't give yourself airs! +Do you think I can listen all day to such stuff? + Be off, or I'll kick you down stairs!" + -- Lewis Carrol +%% +You are only young once, but you can stay immature indefinitely. +%% +You are wise, witty, and wonderful, but you spend too much time reading +this sort of trash. +%% +You can always tell the Christmas season is here when you start getting +incredibly dense, tinfoil-and-ribbon- wrapped lumps in the mail. +Fruitcakes make ideal gifts because the Postal Service has been unable +to find a way to damage them. They last forever, largely because +nobody ever eats them. In fact, many smart people save the fruitcakes +they receive and send them back to the original givers the next year; +some fruitcakes have been passed back and forth for hundreds of years. + +The easiest way to make a fruitcake is to buy a darkish cake, then +pound some old, hard fruit into it with a mallet. Be sure to wear +safety glasses. + -- Dave Barry, "Simple, Homespun Gifts" +%% +You can create your own opportunities this week. Blackmail a senior +executive. +%% +You can get more of what you want with a kind word and a gun than you +can with just a kind word. + -- Bumper Sticker +%% +You can make it illegal, but you can't make it unpopular. +%% +You can measure a programmer's perspective by noting his attitude on +the continuing viability of FORTRAN. + -- Alan Perlis +%% +You can take all the impact that science considerations have on funding +decisions at NASA, put them in the navel of a flea, and have room left +over for a caraway seed and Tony Calio's heart. + -- F. Allen +%% +You can tell how far we have to go, when FORTRAN is the language of +supercomputers. + -- Steven Feiner +%% +You can't carve your way to success without cutting remarks. +%% +You can't judge a book by the way it wears its hair. +%% +You can't start worrying about what's going to happen. You get spastic +enough worrying about what's happening now. + -- Lauren Bacall +%% +"You can't teach people to be lazy - either they have it, or they +don't." + -- Dagwood Bumstead +%% +You cannot achieve the impossible without attempting the absurd. +%% +You cannot kill time without injuring eternity. +%% +You cannot propel yourself forward by patting yourself on the back. +%% +You could get a new lease on life -- if only you didn't need the first +and last month in advance. +%% +You couldn't even prove the White House staff sane beyond a reasonable +doubt. + -- Ed Meese, on the Hinckley verdict +%% +You don't have to think too hard when you talk to teachers. + -- J. D. Salinger +%% +You don't sew with a fork, so I see no reason to eat with knitting +needles. + -- Miss Piggy, on eating Chinese Food +%% +You first have to decide whether to use the short or the long form. The +short form is what the Internal Revenue Service calls "simplified", +which means it is designed for people who need the help of a Sears +tax-preparation expert to distinguish between their first and last +names. Here's the complete text: + + "1. How much did you make? (AMOUNT) + "2. How much did we here at the government take out? (AMOUNT) + "3. Hey! Sounds like we took too much! So we're going to + send an official government check for (ONE-FIFTEENTH OF + THE AMOUNT WE TOOK) directly to the (YOUR LAST NAME) + household at (YOUR ADDRESS), for you to spend in any way + you please! Which just goes to show you, (YOUR FIRST + NAME), that it pays to file the short form!" + +The IRS wants you to use this form because it gets to keep most of your +money. So unless you have pond silt for brains, you want the long +form. + -- Dave Barry, "Sweating Out Taxes" +%% +You have the capacity to learn from mistakes. You'll learn a lot +today. +%% +You know you've been spending too much time on the computer when your +friend misdates a check, and you suggest adding a "++" to fix it. +%% + "You know, it's at times like this when I'm trapped in a Vogon +airlock with a man from Betelgeuse and about to die of asphyxiation in +deep space that I really wish I'd listened to what my mother told me +when I was young!" + "Why, what did she tell you?" + "I don't know, I didn't listen!" + -- Douglas Adams, "Hitchhiker's Guide to the Galaxy" +%% +You may be recognized soon. Hide. +%% +You may have heard that a dean is to faculty as a hydrant is to a dog. + -- Alfred Kahn +%% +You men out there probably think you already know how to dress for +success. You know, for example, that you should not wear leisure suits +or white plastic belts and shoes, unless you are going to a costume +party disguised as a pig farmer vacationing at Disney World. + -- Dave Barry, "How to Dress for Real Success" +%% +You might have mail +%% +"You must realize that the computer has it in for you. The irrefutable +proof of this is that the computer always does what you tell it to do." +%% +You need no longer worry about the future. This time tomorrow you'll +be dead. +%% +You never know how many friends you have until you rent a house on the +beach. +%% +You or I must yield up his life to Ahrimanes. I would rather it were +you. I should have no hesitation in sacrificing my own life to spare +yours, but we take stock next week, and it would not be fair on the +company. + -- J. Wellington Wells +%% +You possess a mind not merely twisted, but actually sprained. +%% +You should emulate your heros, but don't carry it too far. Especially +if they are dead. +%% +You should never wear your best trousers when you go out to fight for +freedom and liberty. + -- Henrick Ibson +%% +You should not use your fireplace, because scientists now believe that, +contrary to popular opinion, fireplaces actually remove heat from +houses. Really, that's what scientists believe. In fact many +scientists actually use their fireplaces to cool their houses in the +summer. If you visit a scientist's house on a sultry August day, +you'll find a cheerful fire roaring on the hearth and the scientist +sitting nearby, remarking on how cool he is and drinking heavily. + -- Dave Barry, "Postpetroleum Guzzler" +%% +You will be a winner today. Pick a fight with a four-year-old. +%% +You will be surprised by a loud noise. +%% +You will be Told about it Tomorrow. Go Home and Prepare Thyself. +%% +You worry too much about your job. Stop it. You are not paid enough +to worry. +%% +"You'll never be the man your mother was!" +%% +You're at the end of the road again. +%% +You're being followed. Cut out the hanky-panky for a few days. +%% +You're never too old to become younger. + -- Mae West +%% +You're not drunk if you can lie on the floor without holding on. + -- Dean Martin +%% +You've been leading a dog's life. Stay off the furniture. +%% +Your analyst has you mixed up with another patient. Don't believe a +thing he tells you. +%% +Your conscience never stops you from doing anything. It just stops you +from enjoying it. +%% +Your fault: core dumped +%% +Your life would be very empty if you had nothing to regret. +%% +Your lucky color has faded. +%% +Your lucky number has been disconnected. +%% +Your lucky number is 3552664958674928. Watch for it everywhere. +%% +Your true value depends entirely on what you are compared with. +%% +Youth is when you blame all your troubles on your parents; maturity is +when you learn that everything is the fault of the younger generation. +%% +Zero Defects, n.: + The result of shutting down a production line. +%% +Zounds! I was never so bethumped with words +since I first called my brother's father dad. + -- William Shakespeare, "King John" +%% +Zymurgy's Law of Volunteer Labor: + People are always available for work in the past tense. diff --git a/src/games/fortune/scene.sp.ok b/src/games/fortune/scene.sp.ok new file mode 100644 index 0000000..27aaa3e --- /dev/null +++ b/src/games/fortune/scene.sp.ok @@ -0,0 +1,1175 @@ +A.A.A.A.A +A.D +A.M +a.m +AAAAAAAAAaaaaaaaaaaaaaaaccccccccckkkkkk +aafte +Abbie +absorbin +absurdum +acacia +accursed +ACLU's +acne +Adamite +adj +Adlai +adv +Aelius +Aesop +Ahrimanes +Albran +Aldous +alimentary +alkafluence +alleygaroo +Alo +alrighty +Altito +ALU +Amerigo +Amica +Amnesia +Amp +anal +Anamalon +Anat +Anatol +animalculous +Ankh +Anoint +anomali +Antonym +anxivs +Anytime +apauling +Apocryphia +appelations +Applebome +Apr +Aquadextrous +Aquarians +arabic +Ardis +arias +Arlo +arse +ary +Ashleigh +Asimov +Aspasia +Aspin +Assateague +Assoc +Asterix +astrology +ath +Atlee +atrium +Auden +ause +ausgraben +Avogardo +avoirdupois +awai +ay +B'nai +B.C +Bacall +Bachtrian +Bagdikian's +bagel +Bai +bai +Baines +bamboozled +Banach +Barach's +Barbie +barf +Baruch's +BASICs +Basie's +Baumol +bazingas +Beagle +BEANSTACK +Beatty +Beckett +bedecked +befriends +Begatting +Begone +Behaviour +Beifeld's +Belloc +bequeathin +Berke +Bertold +Bertolt +bethumped +bi +bibles +Bierce +Billericay +bingo +bisexual +blackguard +Blaise +BLOTTO +blound +Bok +Bokonon +Bolub's +Bombeck's +bonehead +Boob's +BOOGA +Boola +boola +Boothe +Boren's +Borge +bounteous +boyfriend +Boynton +Brandwein +Brecht +brilgue +brilig +Brith +brussels +Brutus +Buckminster +Bucy's +BULLWINKLE +Bullwinkle +Bumstead +Burggoven +burgled +burneth +Busmanship +BYOB +C.I.A +CABERNET +Caen +Caeser +Caeser's +Cahn's +Caissons +caliente +Calio's +calor +Camptown +Capt +carabineri +Carotene +Carotene's +Carperpetuation +Carrol +Casablanca +castrating +CChheecckk +Celibacy +Centauri +Cerebron +Cerebus +ch +CHARDONNAY +Charnock's +Cheatham +Chem +Chichester +childproof +Chism's +Chisolm's +Chloroplast's +chromodynamics +chronodimensional +Cianci +Ciardi +Cinemuck +Clopton +cm +cmptr +cn +cnt +cockamamie +Cogito +cogito +Collis +Colloq +Colvard's +Commie +Computerdom +conks +Constipation +Contrariwise +copacetic +corpuscle +Cory +Cosmo +CPU +CPU's +cpu's +Crabgrass +crabgrass +Cray +Cripps +crunchy +Crysler +CS +Curchill +curiae +cuticle +Cyberiad +Cybernetic +D'Arcy +D.C +da +Dabba +Daft +Dagobah +Dagwood +damnfoolproof +dandruff +dans +darkish +darkroom +Darrow +Darryl +Darth +dataspec +dduupplleexx +de +Decisionmaker +Defactualization +defamed +Degen +demo +deppart +dermis +destitution +Deteriorada +DETERIORATA +dev +DeVries's +diddie +Dijkstra +DINGELL +Dingell +Dirksen +Disco +discotheques +dishes +dishrags +Disraeli +dixerunt +dm +doderez +doggy +Dolph +Donatus +Doo +DOODAH +dost +doth +dotty +Drescher +Dristan +Dropt +Ducharm's +Ducharme's +dumbfounded +Dunne +Dykstra +e.g +E.T +ecamier +Eckstein +Edpress +Eggnog +eggnog +Ehrman's +Elbert +Electrocution +Elliot +Elven +Elvish +Emmons +Emu +Encyclopadia +ENIACs +Enm +Ennui +enobled +er +ergo +Erogenous +erogeny +Ertz +Es +es +Esser +est +etus +Euell +Eustace +ev'ry +Everyting +exaulted +extemporanea +extracurricular +Exupery +Fafhrd +Fainali +fainali +Fakir +Feiffer +Feiner +fella +Ferm +fertsneet +figgy +fiks +Fillmore +Finagle's +Finagling +Firesign +fix'd +flang +Flannagan's +Flinstone +Flon's +floss +Flugg's +Flummery +Foghorn +folkloric +Follen +foo +Forbiddie +forgo +fornia +fornication +forsooth +Forssman +Frayn +freezin +Friedrich +frillant +Frisbee +Frisbeetarianism +Frito +FROB +frob +frobbing +Frobnicate +FROBNITZ +Frodo +fruitcake +Fruitcakes +fruitcakes +frumious +Fudd's +funhouse +Furbling +Furst +Fylstra +Galbraith +Galilei +Galileo +galore +Galvani +Galvani's +Gandalf +Gandhi +garnishment +Gaultier +GC +GC7500439 +gd +Geis +Genderplex +Gerat +Gerrold's +Ghostbusters +Gigo +Gilda +Gilpkerio +gimble +Gimlet +Gimmie +girrafe +Glaser +Glashow +gleekzorp +GO.SYSIN +gobbledegook +Godot +Goestheveezl +Golda +Goldenstern's +Goldwyn +Goodbye +goodbye +Goodgulf +Gopete +Gorden +Gotlieb +Goto +Gotta +gougebosquex +Goy +Goy's +goyim +goyish +goyisha +Grabel's +graffito +Greenstein +Gregorian +Grelb's +Gries +grok +Groucho +grouse +gt +guave +GUISEPPE +Guiseppe +gyre +gyrent +Hadassah +Haeckel +Hahahahahahahahaha +Haig +handcraftsmanship +handwaving +hanky +Hanukka +harmonium +Harrisberger's +Hawkwind +HED +HEE +Heineken +Heinlein +Hellman +Henny +Henrick +Henrik +Herford +hev +hexagram +Higgeldy +Hilaire +Hillary's +Hinckley +Hippogriff +hippogriff +Hitchhiker's +Hlade's +Hoare's +Hoffenstein +Hofstadter's +Homespun +honorific +HOOTCH +hooved +Hoppe +horgrave +Horngren's +hors +Housman +hullabaloo +Huntingdon +Hurewitz's +i.e +I.R.S +Iacocca +Ibson +icepacks +ID's +Iear +iear +Iears +iers +II.a +Il +im +incomprehensive +Ingliy +inkahol +Inlaws +inputdir +inquit +inrushing +interferon +ironmongery +Isaak +Isiah +Iso +Issawi's +itn +ius +Jackals +Jacquin's +Jael +Jaka +Jarry +jast +jb +jeered +Jehan +Jell +Jenerally +Jenkinson's +Jenks +Jenning's +Jersy +JFK +Jone's +Jordache +Jun +Jung +Justin +ka +Kandel +kar +karat +karma +kase +Kaul +Kehlog +Kellen +Kenobi +Kiernan +kiloliks +Kinkler's +Kistomerces +kitsch +Kitzenger +Kleptomaniac +Klone +klows +kludge +klutz +Knuth +koan +kohirnt +konsonant +konsonants +kontinue +Kool +Korda +KPH +Kr +Krogt +Ks +kwirt +Lackland's +Lactomangulation +Laetrile +Lafferty +LAFITE +Lampson +Landburgher +Langsam's +lank +Lankhamar's +Lankhmar +Larkinson's +LaRouchefoucauld +Lassie +lawnmower +Lazlo's +le +LeGuin +Leher +Lehrer +Leiber +Leibowitz's +Leipzig +Lem +Lenore +lerts +Les +les +letez +Lettvin +Levant +Leverett +lexicographer +LIBRA +Libra +libricilleux +Lieberman's +lightbulb +Lilla +limerick +lin +linguini +Linkletter +LITHP +lithtth +Liza +lobotomy +locutions +Logg's +logick +logout +logy +lojikl +Longworth +Lowery's +LSD +Ltd +Lubarsky's +Luce +Luigi +Lyndon +Lysistrata +m'I +M.T.A +ma'am +Macaroons +MacDowell +MacNelley +MacNelly +MacNiece +Macy's +Madelyn +Magnocartic +magtape +Mahatma +Mai +maindz +mal +Malek's +MANCHA +Manhandling +margarita +Marley +Maslow +masochist +Mathis +Maugham +Maughm +Maxey +McEvoy +McNulty +Medawar +Meese +megs +meik +Meir +meltdown +Mem'ry +memoraboble +memori +memorizin +Mencken +Mencken's +menswear +meowing +MERCUTIO +merinos +Merrick +Meskimen's +meta +Mewling +Meyrowitz +MHz +midterm +Mikado +Miksch's +Millay +Millions +millions +mimsy +Minas +Minnelli +minx +missle +Moby +modifaiing +mohmen +Mollison's +Mom +Mophobia +Moping +Mordor +MOS +Mosher's +mousetraps +Mudgeeraba +Mudhead +Muppet +musculus +Mustgo +MW +MX +Myung +myxbl +n'oeuvres +Nader +Naeser's +Naiman +nanocentury +nanohenry +Narnia +Nate +naugahyde +Neantical +Neizant +nell +Nerd +net.fat +net.flame +net.jobs +net.news +net.that +net.this +Newlan's +NEWSFLASH +newsmagazine +Ngdanga +Ni +ni +Nicklaus +nightie +Niklaus +Ningauble +Noelie +nog +nohow +Nome +Nora's +nostra +Novocain +nunnery +Nutley +NYT +O'Casey +O'Hara +O'Henry +O'Rourke +O'Toole's +O.K +Obi +obits +obius +Ogborn +ok +ol;lkld;f;g;dd;po +Olivier +oln +omerade +omnivorous +ompzidaize +Onan +oodsou +Ope +Ophelia +orxogrefkl +OS +ould +outcumbents +ov +oves +Ozman's +p'o +P.B.A +P.M +p.m +padanga +Paley +Pandanga +panky +Pardo's +Parnas +paroxysmally +Parrafin +PDP +Pecor's +penis +Pensacoola +Penzance +Pereant +perfum'd +Perlis +Pharaoh +Philbin +Philogyny +philogyny +Phooey +Picninnies +Piggeldy +Pirsig +PL +planaria +Platypus +platypus +pleH +Pluribus +pm +po +Podunk +Pohl's +poiuyt +Politicain +poly +polytetien +polytheism +poo +popcorn +Porcus +posibl +posthole +Postpetroleum +POWDERMILK +poz +ppo +prawns +pre +pretzel +Preudhomme's +prgrmmng +priestess +primordial +PRL +Prochnow +Profesoor +propounded +protheththing +protoplasmal +Psblurtex +Publilius +pulitzer +Pumpernickel +pur +pushy +Pynchon +qui +quia +Quinton +quop +Quux +Qvid +QWERT +qwert +QWERTYUIOP +qwertyuiop +Ra +Radner +raineth +RAMs +randchar +rapturous +raspy +raths +rd +Reba +Regan +Reggie +Reisner's +replased +replasing +rhinoceri +Richardian +ridandant +riform +rigadoon +Rigby +Rilke +rimeining +rind +riplais +rispektivli +risqu +rKe9 +Robb +Robespierre +Rogerians +Rolex +ROMs +Rooney +Rosten +Rotherham +Rouchefoucauld +Roumania +Roxbury +RPG +Rubenstein +Rubik's +Rudin's +Ruffed +Russel +Russon +Safire's +Sagittarians +Salome +Salvor +sam +Santoro +Sappho +Sargon +SARTRE +Sartre +SCCS +Schapiro's +schlichte +Schryer +Schwine +Scrubb +scullery +Se +Seeger +Sep +Serendipity +Serling +Serocki's +Sevenoaks +shalt +Shamus +shamus +Sheil +Sherany +shinnied +shlafen +Shmoedipus +Shoaff +shorn +Shuman +sightie +Sigismund +Simard +siouxeyesighed +Sixtus +sizeof +skyhigh +Skyler +sligo +SLOBOL +Slurm +Smit +Snacktrek +Sniglets +Snowman +snowman +Snowmass +Socio +Sodd's +somebody'd +sont +Sorhed +spank +speling +Spirtle +spl +Spock +sq +sswwiittcchh +Sta +Stanislaw +starfield +steamrolling +Steelypips +steeplechase +Steinbach's +Steinem +Stoffel +Stult's +suet +Sulu +Sumeria +sunbelts +Supercalifragilisticexpialidocius +svm +Swaller +swang +Swinburne +Swipple's +switchover +symptotes +synagog +Syrus +syscalls +T.V +Tabby +tachyon +Tai +taketh +Tanenbaum +tannogallate +Tarradiddles +tbsp +Teddywookie +telepath +telly +Tenessee +tequila +Terence +Tertullian +Teruillian +TH +th +Thames +theivish +thi +Thieu +thinkle +Tho +Thoul't +thru +ths +Thyself +thyself +Tierra +Tikkanen +tinhorn +TLC +tollway +Tomlin +Tonka +tornpee +Toven +trampoline +transsexual +treacle +Tricia +tripoline +Troney +Trotsky +tsetse +TSO +tsp +Tsu +tu +tuit +tuits +tuppenny +Turnaucka's +Tussman's +Tut's +Twas +Tweedledee +Tweedledum +tween +twixt +Twodor +Twodor's +tyg +U.S +UFO's +uh +ukelele +umsige +unbegot +Und +und +unvoist +uretheral +Urey +urgin's +URK +valium +Vannevar +VAX +VAX's +VAXen +VAXs +velcro +Velilind's +Venn +Vespucci +Vespuccia +Vidal +VIDEOCASSETTE +Vinchy +Vinci +Virt +Vittorini +VLSI +VMS +VODKA +Vogon +voist +vol +Volkswagon +Vonada +Vonnegut +Vonnegut's +vowlz +Vries +VSOP +vu +Vulgate +w4k +wa +Waben +Wald +Walla +Warhol +Wat +Weiler's +Weiner's +weirdo +Weisert +wench +werld +Wernher +Westheimer's +Wethern's +WHATEVERSAROUND +Whipsnade +whomped +wi +Wiker's +Wilde +wimmelten +Winchell +Winsor +Wirrten +Wirth +Withington +WOMBAT +wombat +wonse +woodburning +workingman +WORLD's +wr +wrth +wrung +wud +xanthic +xe +xen +XINU +xrewawt +xsz +Yabba +Yessir +Yinkel +Yo +yo +Yoda +Yoda's +Yorba +you'se +Youngman +Yuletide +yyoouurr +Zanuck +Zappa +Zarathustra +zayda +Zelkowitz +zephyr's +ZORAC +Zow +Zwanzig +Zymurgy's +masturbation diff --git a/src/games/fortune/strfile.c b/src/games/fortune/strfile.c new file mode 100644 index 0000000..00ce2aa --- /dev/null +++ b/src/games/fortune/strfile.c @@ -0,0 +1,394 @@ +# include +# include +# include "strfile.h" + +/* + * This program takes a file composed of strings seperated by + * lines starting with two consecutive delimiting character (default + * character is '%') and creates another file which consists of a table + * describing the file (structure from "strfile.h"), a table of seek + * pointers to the start of the strings, and the strings, each terinated + * by a null byte. Usage: + * + * % strfile [ - ] [ -cC ] [ -sv ] [ -oir ] sourcefile [ datafile ] + * + * - - Give a usage summary useful for jogging the memory + * c - Change delimiting character from '%' to 'C' + * s - Silent. Give no summary of data processed at the end of + * the run. + * v - Verbose. Give summary of data processed. (Default) + * o - order the strings in alphabetic order + * i - if ordering, ignore case + * r - randomize the order of the strings + * + * Ken Arnold Sept. 7, 1978 -- + * + * Added method to indicate dividers. A "%-" will cause the address + * to be added to the structure in one of the pointer elements. + * + * Ken Arnold Nov., 1984 -- + * + * Added ordering options. + */ + +# define TRUE 1 +# define FALSE 0 + +# define DELIM_CH '-' + +typedef struct { + char first; + long pos; +} STR; + +char *Infile = NULL, /* input file name */ + Outfile[100] = "", /* output file name */ + Delimch = '%', /* delimiting character */ + *Usage[] = { /* usage summary */ + "usage: strfile [ - ] [ -cC ] [ -sv ] [ -oir ] inputfile [ datafile ]", + " - - Give this usage summary", + " c - Replace delimiting character with 'C'", + " s - Silent. Give no summary", + " v - Verbose. Give summary. (default)", + " o - order strings alphabetically", + " i - ignore case in ordering", + " r - randomize the order of the strings", + " Default \"datafile\" is inputfile.dat", + NULL + }; + +int Sflag = FALSE; /* silent run flag */ +int Oflag = FALSE; /* ordering flag */ +int Iflag = FALSE; /* ignore case flag */ +int Rflag = FALSE; /* randomize order flag */ +int Delim = 0; /* current delimiter number */ + +long *Seekpts; + +FILE *Sort_1, *Sort_2; /* pointers for sorting */ + +STRFILE Tbl; /* statistics table */ + +STR *Firstch; /* first chars of each string */ + +char *fgets(), *malloc(), *strcpy(), *strcat(); + +long ftell(); + +main(ac, av) +int ac; +char **av; +{ + register char *sp, dc; + register long *lp; + register unsigned int curseek; /* number of strings */ + register long *seekpts, li; /* table of seek pointers */ + register FILE *inf, *outf; + register int first; + register char *nsp; + register STR *fp; + static char string[257]; + + getargs(ac, av); /* evalute arguments */ + + /* + * initial counting of input file + */ + + dc = Delimch; + if ((inf = fopen(Infile, "r")) == NULL) { + perror(Infile); + exit(-1); + } + for (curseek = 0; (sp = fgets(string, 256, inf)) != NULL; ) + if (*sp++ == dc && (*sp == dc || *sp == DELIM_CH)) + curseek++; + curseek++; + + /* + * save space at begginning of file for tables + */ + + if ((outf = fopen(Outfile, "w")) == NULL) { + perror(Outfile); + exit(-1); + } + + /* + * Allocate space for the pointers, adding one to the end so the + * length of the final string can be calculated. + */ + ++curseek; + seekpts = (long *) malloc(sizeof *seekpts * curseek); /* NOSTRICT */ + if (seekpts == NULL) { + perror("calloc"); + exit(-1); + } + if (Oflag) { + Firstch = (STR *) malloc(sizeof *Firstch * curseek); + if (Firstch == NULL) { + perror("calloc"); + exit(-1); + } + } + + (void) fseek(outf, (long) (sizeof Tbl + sizeof *seekpts * curseek), 0); + (void) fseek(inf, (long) 0, 0); /* goto start of input */ + + /* + * write the strings onto the file + */ + + Tbl.str_longlen = 0; + Tbl.str_shortlen = (unsigned int) 0xffffffff; + lp = seekpts; + first = Oflag; + *seekpts = ftell(outf); + fp = Firstch; + do { + sp = fgets(string, 256, inf); + if (sp == NULL || + (*sp == dc && (sp[1] == dc || sp[1] == DELIM_CH))) { + putc('\0', outf); + *++lp = ftell(outf); + li = ftell(outf) - lp[-1] - 1; + if (Tbl.str_longlen < li) + Tbl.str_longlen = li; + if (Tbl.str_shortlen > li) + Tbl.str_shortlen = li; + if (sp && sp[1] == DELIM_CH && Delim < MAXDELIMS) + Tbl.str_delims[Delim++] = lp - seekpts; + first = Oflag; + } + else { + if (first) { + for (nsp = sp; !isalnum(*nsp); nsp++) + continue; + if (Iflag && isupper(*nsp)) + fp->first = tolower(*nsp); + else + fp->first = *nsp; + fp->pos = *lp; + fp++; + first = FALSE; + } + fputs(sp, outf); + } + } while (sp != NULL); + + /* + * write the tables in + */ + + (void) fclose(inf); + Tbl.str_numstr = curseek - 1; + + if (Oflag) + do_order(seekpts, outf); + else if (Rflag) + randomize(seekpts); + + (void) fseek(outf, (long) 0, 0); + (void) fwrite((char *) &Tbl, sizeof Tbl, 1, outf); + (void) fwrite((char *) seekpts, sizeof *seekpts, curseek, outf); + (void) fclose(outf); + + if (!Sflag) { + printf("\"%s\" converted to \"%s\"\n", Infile, Outfile); + if (curseek == 0) + puts("There was 1 string"); + else + printf("There were %u strings\n", curseek - 1); + printf("Longest string: %u byte%s\n", Tbl.str_longlen, + Tbl.str_longlen == 1 ? "" : "s"); + printf("Shortest string: %u byte%s\n", Tbl.str_shortlen, + Tbl.str_shortlen == 1 ? "" : "s"); + } + exit(0); +} + +/* + * This routine evaluates arguments from the command line + */ +getargs(ac, av) +register int ac; +register char **av; +{ + register char *sp; + register int i; + register int bad, j; + + bad = 0; + for (i = 1; i < ac; i++) + if (*av[i] == '-' && av[i][1]) { + for (sp = &av[i][1]; *sp; sp++) + switch (*sp) { + case 'c': /* new delimiting char */ + if ((Delimch = *++sp) == '\0') { + --sp; + Delimch = *av[++i]; + } + if (Delimch <= 0 || Delimch > '~' || + Delimch == DELIM_CH) { + printf("bad delimiting character: '\\%o\n'", + Delimch); + bad++; + } + break; + case 's': /* silent */ + Sflag++; + break; + case 'v': /* verbose */ + Sflag = 0; + break; + case 'o': /* order strings */ + Oflag++; + break; + case 'i': /* ignore case in ordering */ + Iflag++; + break; + case 'r': /* ignore case in ordering */ + Rflag++; + break; + default: /* unknown flag */ + bad++; + printf("bad flag: '%c'\n", *sp); + break; + } + } + else if (*av[i] == '-') { + for (j = 0; Usage[j]; j++) + puts(Usage[j]); + exit(0); + } + else if (Infile) + (void) strcpy(Outfile, av[i]); + else + Infile = av[i]; + if (!Infile) { + bad++; + puts("No input file name"); + } + if (*Outfile == '\0' && !bad) { + (void) strcpy(Outfile, Infile); + (void) strcat(Outfile, ".dat"); + } + if (bad) { + puts("use \"strfile -\" to get usage"); + exit(-1); + } +} + +/* + * do_order: + * Order the strings alphabetically (possibly ignoring case). + */ +do_order(seekpts, outf) +long *seekpts; +FILE *outf; +{ + register int i; + register long *lp; + register STR *fp; + extern int cmp_str(); + + (void) fflush(outf); + Sort_1 = fopen(Outfile, "r"); + Sort_2 = fopen(Outfile, "r"); + Seekpts = seekpts; + qsort((char *) Firstch, Tbl.str_numstr, sizeof *Firstch, cmp_str); + i = Tbl.str_numstr; + lp = seekpts; + fp = Firstch; + while (i--) + *lp++ = fp++->pos; + (void) fclose(Sort_1); + (void) fclose(Sort_2); + Tbl.str_flags |= STR_ORDERED; +} + +/* + * cmp_str: + * Compare two strings in the file + */ +cmp_str(p1, p2) +STR *p1, *p2; +{ + register int c1, c2; + + c1 = p1->first; + c2 = p2->first; + if (c1 != c2) + return c1 - c2; + + (void) fseek(Sort_1, p1->pos, 0); + (void) fseek(Sort_2, p2->pos, 0); + + while (!isalnum(c1 = getc(Sort_1)) && c1 != '\0') + continue; + while (!isalnum(c2 = getc(Sort_2)) && c2 != '\0') + continue; + + while (c1 != '\0' && c2 != '\0') { + if (Iflag) { + if (isupper(c1)) + c1 = tolower(c1); + if (isupper(c2)) + c2 = tolower(c2); + } + if (c1 != c2) + return c1 - c2; + c1 = getc(Sort_1); + c2 = getc(Sort_2); + } + return c1 - c2; +} + +/* + * randomize: + * Randomize the order of the string table. We must be careful + * not to randomize across delimiter boundaries. All + * randomization is done within each block. + */ +randomize(seekpts) +register long *seekpts; +{ + register int cnt, i, j, start; + register long tmp; + register long *origsp; + + Tbl.str_flags |= STR_RANDOM; + srnd(time((long *) NULL) + getpid()); + origsp = seekpts; + for (j = 0; j <= Delim; j++) { + + /* + * get the starting place for the block + */ + + if (j == 0) + start = 0; + else + start = Tbl.str_delims[j - 1]; + + /* + * get the ending point + */ + + if (j == Delim) + cnt = Tbl.str_numstr; + else + cnt = Tbl.str_delims[j]; + + /* + * move things around randomly + */ + + for (seekpts = &origsp[start]; cnt > start; cnt--, seekpts++) { + i = rnd(cnt - start); + tmp = seekpts[0]; + seekpts[0] = seekpts[i]; + seekpts[i] = tmp; + } + } +} diff --git a/src/games/fortune/strfile.h b/src/games/fortune/strfile.h new file mode 100644 index 0000000..014afc1 --- /dev/null +++ b/src/games/fortune/strfile.h @@ -0,0 +1,20 @@ +/* @(#)strfile.h 1.2 (Berkeley) 5/14/81 */ + +# define MAXDELIMS 3 + +/* + * bits for flag field + */ + +# define STR_RANDOM 0x1 +# define STR_ORDERED 0x2 + +struct strfile { /* information table */ + unsigned int str_numstr; /* # of strings in the file */ + unsigned int str_longlen; /* length of longest string */ + unsigned int str_shortlen; /* length of shortest string */ + long str_delims[MAXDELIMS]; /* delimiter markings */ + int str_flags; /* bit field for flags */ +}; + +typedef struct strfile STRFILE; diff --git a/src/games/fortune/unstr.c b/src/games/fortune/unstr.c new file mode 100644 index 0000000..8cae59b --- /dev/null +++ b/src/games/fortune/unstr.c @@ -0,0 +1,127 @@ +# include +# include "strfile.h" + +# define TRUE 1 +# define FALSE 0 + +/* + * This program un-does what "strfile" makes, thereby obtaining the + * original file again. This can be invoked with the name of the output + * file, the input file, or both. If invoked with only a single argument + * ending in ".dat", it is pressumed to be the input file and the output + * file will be the same stripped of the ".dat". If the single argument + * doesn't end in ".dat", then it is presumed to be the output file, and + * the input file is that name prepended by a ".dat". If both are given + * they are treated literally as the input and output files. + * + * Ken Arnold Aug 13, 1978 + */ + +# define DELIM_CH '-' + +char Infile[100], /* name of input file */ + Outfile[100]; /* name of output file */ + +short Oflag = FALSE; /* use order of initial table */ + +FILE *Inf, *Outf; + +char *rindex(), *malloc(), *strcat(), *strcpy(); + +main(ac, av) +int ac; +char **av; +{ + register char c; + register int nstr, delim; + static STRFILE tbl; /* description table */ + + getargs(ac, av); + if ((Inf = fopen(Infile, "r")) == NULL) { + perror(Infile); + exit(-1); + /* NOTREACHED */ + } + if ((Outf = fopen(Outfile, "w")) == NULL) { + perror(Outfile); + exit(-1); + /* NOTREACHED */ + } + (void) fread((char *) &tbl, sizeof tbl, 1, Inf); + if (Oflag) { + order_unstr(&tbl); + exit(0); + /* NOTREACHED */ + } + nstr = tbl.str_numstr; + (void) fseek(Inf, (long) (sizeof (long) * (nstr + 1)), 1); + delim = 0; + for (nstr = 0; (c = getc(Inf)) != EOF; nstr++) + if (c != '\0') + putc(c, Outf); + else if (nstr != tbl.str_numstr - 1) + if (nstr == tbl.str_delims[delim]) { + fputs("%-\n", Outf); + delim++; + } + else + fputs("%%\n", Outf); + exit(0); + /* NOTREACHED */ +} + +getargs(ac, av) +register int ac; +register char **av; +{ + register char *sp; + + if (ac > 1 && strcmp(av[1], "-o") == 0) { + Oflag++; + ac--; + av++; + } + if (ac < 2) { + printf("usage: %s datafile[.dat] [ outfile ]\n", av[0]); + exit(-1); + } + (void) strcpy(Infile, av[1]); + if (ac < 3) { + (void) strcpy(Outfile, Infile); + if ((sp = rindex(av[1], '.')) && strcmp(sp, ".dat") == 0) + Outfile[strlen(Outfile) - 4] = '\0'; + else + (void) strcat(Infile, ".dat"); + } + else + (void) strcpy(Outfile, av[2]); +} + +order_unstr(tbl) +STRFILE *tbl; +{ + register int i, c; + register int delim; + register long *seekpts; + + seekpts = (long *) malloc(sizeof *seekpts * tbl->str_numstr); /* NOSTRICT */ + if (seekpts == NULL) { + perror("malloc"); + exit(-1); + /* NOTREACHED */ + } + (void) fread((char *) seekpts, sizeof *seekpts, tbl->str_numstr, Inf); + delim = 0; + for (i = 0; i < tbl->str_numstr; i++, seekpts++) { + if (i != 0) + if (i == tbl->str_delims[delim]) { + fputs("%-\n", Outf); + delim++; + } + else + fputs("%%\n", Outf); + (void) fseek(Inf, *seekpts, 0); + while ((c = getc(Inf)) != '\0') + putc(c, Outf); + } +} diff --git a/src/games/hangman/Makefile b/src/games/hangman/Makefile new file mode 100644 index 0000000..99bd640 --- /dev/null +++ b/src/games/hangman/Makefile @@ -0,0 +1,22 @@ +OBJS= endgame.o extern.o getguess.o getword.o main.o playgame.o \ + prdata.o prman.o prword.o setup.o +CFILES= endgame.c extern.c getguess.c getword.c main.c playgame.c \ + prdata.c prman.c prword.c setup.c +HDRS= hangman.h +CFLAGS= -O +LDFLAGS= +SEPFLAG= -i + +all: hangman + +tags: $(HDRS) $(CFILES) + ctags $(HDRS) $(CFILES) + +install: hangman + install -s hangman $(DESTDIR)/usr/games/hangman + +hangman: $(OBJS) + $(CC) ${SEPFLAG} $(LDFLAGS) -o hangman $(OBJS) -lcurses -ltermlib + +clean: + rm -f $(OBJS) hangman ? core diff --git a/src/games/hangman/endgame.c b/src/games/hangman/endgame.c new file mode 100644 index 0000000..4bbe4cb --- /dev/null +++ b/src/games/hangman/endgame.c @@ -0,0 +1,36 @@ +# include "hangman.h" + +/* + * endgame: + * Do what's necessary at the end of the game + */ +endgame() +{ + register char ch; + + prman(); + if (Errors >= MAXERRS) + Errors = MAXERRS + 2; + prword(); + prdata(); + move(MESGY, MESGX); + if (Errors > MAXERRS) + printw("Sorry, the word was \"%s\"\n", Word); + else + printw("You got it!\n"); + + for (;;) { + mvaddstr(MESGY + 1, MESGX, "Another word? "); + leaveok(stdscr, FALSE); + refresh(); + if ((ch = readch()) == 'n') + die(); + else if (ch == 'y') + break; + mvaddstr(MESGY + 2, MESGX, "Please type 'y' or 'n'"); + } + + leaveok(stdscr, TRUE); + move(MESGY, MESGX); + addstr("\n\n\n"); +} diff --git a/src/games/hangman/extern.c b/src/games/hangman/extern.c new file mode 100644 index 0000000..4b4fc47 --- /dev/null +++ b/src/games/hangman/extern.c @@ -0,0 +1,37 @@ +# include "hangman.h" + +bool Guessed[26]; + +char Word[BUFSIZ], + Known[BUFSIZ], + *Noose_pict[] = { + " ______", + " | |", + " |", + " |", + " |", + " |", + " __|_____", + " | |___", + " |_________|", + NULL + }; + +int Errors, + Wordnum = 0; + +double Average = 0.0; + +ERR_POS Err_pos[MAXERRS] = { + { 2, 10, 'O' }, + { 3, 10, '|' }, + { 4, 10, '|' }, + { 5, 9, '/' }, + { 3, 9, '/' }, + { 3, 11, '\\' }, + { 5, 11, '\\' } +}; + +FILE *Dict = NULL; + +off_t Dict_size; diff --git a/src/games/hangman/getguess.c b/src/games/hangman/getguess.c new file mode 100644 index 0000000..3aa31b0 --- /dev/null +++ b/src/games/hangman/getguess.c @@ -0,0 +1,70 @@ +# include "hangman.h" + +/* + * getguess: + * Get another guess + */ +getguess() +{ + register int i; + register int ch; + register bool correct; + + leaveok(stdscr, FALSE); + for (;;) { + move(PROMPTY, PROMPTX + sizeof "Guess: "); + refresh(); + ch = readch(); + if (isalpha(ch)) { + if (isupper(ch)) + ch = tolower(ch); + if (Guessed[ch - 'a']) + mvprintw(MESGY, MESGX, "Already guessed '%c'", ch); + else + break; + } + else if (ch == CTRL(D)) + die(); + else + mvprintw(MESGY, MESGX, "Not a valid guess: '%s'", + unctrl(ch)); + } + leaveok(stdscr, TRUE); + move(MESGY, MESGX); + clrtoeol(); + + Guessed[ch - 'a'] = TRUE; + correct = FALSE; + for (i = 0; Word[i] != '\0'; i++) + if (Word[i] == ch) { + Known[i] = ch; + correct = TRUE; + } + if (!correct) + Errors++; +} + +/* + * readch; + * Read a character from the input + */ +readch() +{ + register int cnt, r; + auto char ch; + + cnt = 0; + for (;;) { + if (read(0, &ch, sizeof ch) <= 0) + { + if (++cnt > 100) + die(); + } + else if (ch == CTRL(L)) { + wrefresh(curscr); + mvcur(0, 0, curscr->_cury, curscr->_curx); + } + else + return ch; + } +} diff --git a/src/games/hangman/getword.c b/src/games/hangman/getword.c new file mode 100644 index 0000000..b28c0ce --- /dev/null +++ b/src/games/hangman/getword.c @@ -0,0 +1,55 @@ +# include "hangman.h" + +# if pdp11 +# define RN (((off_t) rand() << 16) | (off_t) rand()) +# else +# define RN rand() +# endif + +/* + * getword: + * Get a valid word out of the dictionary file + */ +getword() +{ + register FILE *inf; + register char *wp, *gp; + + inf = Dict; + for (;;) { + fseek(inf, abs(RN % Dict_size), 0); + if (fgets(Word, BUFSIZ, inf) == NULL) + continue; + if (fgets(Word, BUFSIZ, inf) == NULL) + continue; + Word[strlen(Word) - 1] = '\0'; + if (strlen(Word) < MINLEN) + continue; + for (wp = Word; *wp; wp++) + if (!islower(*wp)) + goto cont; + break; +cont: ; + } + gp = Known; + wp = Word; + while (*wp) { + *gp++ = '-'; + wp++; + } + *gp = '\0'; +} + +/* + * abs: + * Return the absolute value of an integer + */ +off_t +abs(i) +off_t i; +{ + if (i < 0) + return -(off_t) i; + else + return (off_t) i; +} diff --git a/src/games/hangman/hangman.6 b/src/games/hangman/hangman.6 new file mode 100644 index 0000000..60dcacf --- /dev/null +++ b/src/games/hangman/hangman.6 @@ -0,0 +1,23 @@ +.\" Copyright (c) 1980 Regents of the University of California. +.\" All rights reserved. The Berkeley software License Agreement +.\" specifies the terms and conditions for redistribution. +.\" +.\" @(#)hangman.6 6.1 (Berkeley) 5/20/85 +.\" +.TH HANGMAN 6 "May 20, 1985" +.UC 4 +.SH NAME +hangman \- Computer version of the game hangman +.SH SYNOPSIS +.B /usr/games/hangman +.SH DESCRIPTION +In +.I hangman, +the computer picks a word from the on-line word list +and you must try to guess it. +The computer keeps track of which letters have been guessed +and how many wrong guesses you have made on the screen in a graphic fashion. +.SH FILES +/usr/dict/words On-line word list +.SH AUTHOR +Ken Arnold diff --git a/src/games/hangman/hangman.h b/src/games/hangman/hangman.h new file mode 100644 index 0000000..78af604 --- /dev/null +++ b/src/games/hangman/hangman.h @@ -0,0 +1,46 @@ +# include +# include +# include +# include +# include + +# define MINLEN 6 +# define MAXERRS 7 +# define DICT "/usr/dict/words" + +# define MESGY 12 +# define MESGX 0 +# define PROMPTY 11 +# define PROMPTX 0 +# define KNOWNY 10 +# define KNOWNX 1 +# define NUMBERY 4 +# define NUMBERX (COLS - 1 - 26) +# define AVGY 5 +# define AVGX (COLS - 1 - 26) +# define GUESSY 2 +# define GUESSX (COLS - 1 - 26) + + +typedef struct { + short y, x; + char ch; +} ERR_POS; + +extern bool Guessed[]; + +extern char Word[], Known[], *Noose_pict[]; + +extern int Errors, Wordnum; + +extern double Average; + +extern ERR_POS Err_pos[]; + +extern FILE *Dict; + +extern off_t Dict_size; + +int die(); + +off_t abs(); diff --git a/src/games/hangman/main.c b/src/games/hangman/main.c new file mode 100644 index 0000000..5a03d83 --- /dev/null +++ b/src/games/hangman/main.c @@ -0,0 +1,29 @@ +# include "hangman.h" + +/* + * This game written by Ken Arnold. + */ +main() +{ + initscr(); + signal(SIGINT, die); + setup(); + for (;;) { + Wordnum++; + playgame(); + Average = (Average * (Wordnum - 1) + Errors) / Wordnum; + } + /* NOTREACHED */ +} + +/* + * die: + * Die properly. + */ +die() +{ + mvcur(0, COLS - 1, LINES - 1, 0); + endwin(); + putchar('\n'); + exit(0); +} diff --git a/src/games/hangman/playgame.c b/src/games/hangman/playgame.c new file mode 100644 index 0000000..d0ca809 --- /dev/null +++ b/src/games/hangman/playgame.c @@ -0,0 +1,23 @@ +# include "hangman.h" + +/* + * playgame: + * play a game + */ +playgame() +{ + register bool *bp; + + getword(); + Errors = 0; + bp = Guessed; + while (bp < &Guessed[26]) + *bp++ = FALSE; + while (Errors < MAXERRS && index(Known, '-') != NULL) { + prword(); + prdata(); + prman(); + getguess(); + } + endgame(); +} diff --git a/src/games/hangman/prdata.c b/src/games/hangman/prdata.c new file mode 100644 index 0000000..8874bca --- /dev/null +++ b/src/games/hangman/prdata.c @@ -0,0 +1,21 @@ +# include "hangman.h" + +/* + * prdata: + * Print out the current guesses + */ +prdata() +{ + register bool *bp; + + move(GUESSY, GUESSX + sizeof "Guessed: "); + bp = Guessed; + while (bp < &Guessed[26]) + if (*bp++) + addch((bp - Guessed) + 'a' - 1); + clrtoeol(); + mvprintw(NUMBERY, NUMBERX + sizeof "Word #: ", "%d", Wordnum); + mvprintw(AVGY, AVGX + sizeof "Current Average: ", "%.3f", + (Average * (Wordnum - 1) + Errors) / Wordnum); + mvprintw(AVGY + 1, AVGX + sizeof "Overall Average: ", "%.3f", Average); +} diff --git a/src/games/hangman/prman.c b/src/games/hangman/prman.c new file mode 100644 index 0000000..4d1d976 --- /dev/null +++ b/src/games/hangman/prman.c @@ -0,0 +1,18 @@ +# include "hangman.h" + +/* + * prman: + * Print out the man appropriately for the give number + * of incorrect guesses. + */ +prman() +{ + register int i; + + for (i = 0; i < Errors; i++) + mvaddch(Err_pos[i].y, Err_pos[i].x, Err_pos[i].ch); + while (i < MAXERRS) { + mvaddch(Err_pos[i].y, Err_pos[i].x, ' '); + i++; + } +} diff --git a/src/games/hangman/prword.c b/src/games/hangman/prword.c new file mode 100644 index 0000000..1770028 --- /dev/null +++ b/src/games/hangman/prword.c @@ -0,0 +1,12 @@ +# include "hangman.h" + +/* + * prword: + * Print out the current state of the word + */ +prword() +{ + move(KNOWNY, KNOWNX + sizeof "Word: "); + addstr(Known); + clrtoeol(); +} diff --git a/src/games/hangman/setup.c b/src/games/hangman/setup.c new file mode 100644 index 0000000..bda8511 --- /dev/null +++ b/src/games/hangman/setup.c @@ -0,0 +1,35 @@ +# include "hangman.h" + +/* + * setup: + * Set up the strings on the screen. + */ +setup() +{ + register char **sp; + static struct stat sbuf; + + noecho(); + crmode(); + + mvaddstr(PROMPTY, PROMPTX, "Guess:"); + mvaddstr(GUESSY, GUESSX, "Guessed:"); + mvaddstr(NUMBERY, NUMBERX, "Word #:"); + mvaddstr(AVGY, AVGX, "Current Average:"); + mvaddstr(AVGY + 1, AVGX, "Overall Average:"); + mvaddstr(KNOWNY, KNOWNX, "Word: "); + + for (sp = Noose_pict; *sp != NULL; sp++) { + move(sp - Noose_pict, 0); + addstr(*sp); + } + + srand(time(NULL) + getpid()); + if ((Dict = fopen(DICT, "r")) == NULL) { + perror(DICT); + endwin(); + exit(1); + } + fstat(fileno(Dict), &sbuf); + Dict_size = sbuf.st_size; +} diff --git a/src/games/hunt/Makefile b/src/games/hunt/Makefile new file mode 100644 index 0000000..e74e15d --- /dev/null +++ b/src/games/hunt/Makefile @@ -0,0 +1,127 @@ +# +# Hunt +# Copyright (c) 1985 Conrad C. Huang, Gregory S. Couch, Kenneth C.R.C. Arnold +# San Francisco, California +# +# Copyright (c) 1985 Regents of the University of California. +# All rights reserved. The Berkeley software License Agreement +# specifies the terms and conditions for redistribution. +# +HDR= hunt.h +DSRC= answer.c driver.c draw.c execute.c expl.c makemaze.c \ + shots.c terminal.c extern.c pathname.c +DOBJ= answer.o driver.o draw.o execute.o expl.o makemaze.o \ + shots.o terminal.o extern.o +PSRC= hunt.c connect.c playit.c pathname.c +POBJ= hunt.o connect.o playit.o + +# +# Flags are: +# DEBUG Don't trust everything in the code +# INTERNET Use the Internet domain IPC instead of UNIX domain +# BROADCAST Use internet broadcasting code when looking for driver +# OLDIPC Use 4.1a internet system calls (must also define +# INTERNET but not BROADCAST) +# RANDOM Include doors which disperse shots randomly +# REFLECT Include diagonal walls that reflect shots +# MONITOR Include code for watching the game from the sidelines +# OOZE Include slime shots +# FLY Make people fly when walls regenerate under them +# START_FLYING Players enter flying (FLY must also be defined) +# VOLCANO Include occasional large slime explosions +# +# NOTE: if you change the domain (INTERNET vs UNIX) then "make newdomain" +# +DEFS= -I. -DBROADCAST -DRANDOM -DREFLECT -DMONITOR -DINTERNET \ + -DOOZE -DFLY -DVOLCANO +CFLAGS= -O $(DEFS) +LDFLAGS= +SEPFLAG= -i +PROFLAGS= +LD= /bin/ld +.SUFFIXES: .uu .obj .c,v + +.obj.uu: + uuencode $*.obj < $*.obj > $*.uu + +.c,v.c: + co $*.c + +standard: hunt hunt.driver + +# +# For testing +# +debug: hunt.dbg hunt.driver.dbg + +hunt.dbg: $(POBJ) pathname.dbg.o + $(CC) ${SEPFLAG} $(LDFLAGS) -o hunt.dbg \ + $(POBJ) pathname.dbg.o -lcurses -ltermlib + +hunt.driver.dbg: $(DOBJ) pathname.dbg.o + $(CC) ${SEPFLAG} $(PROFLAGS) $(LDFLAGS) -o hunt.driver.dbg \ + $(DOBJ) pathname.dbg.o + +# +# Binary distribution to other sites +# +distribution: hunt.uu hunt.driver.uu README pathname.c Makefile.dist hunt.6 + @ln Makefile.dist makefile + shar -a README makefile pathname.c hunt.uu hunt.driver.uu hunt.6\ + > distribution + @rm -f makefile hunt.uu hunt.driver.uu hunt.obj hunt.driver.obj + +hunt.driver.obj: $(DOBJ) pathname.o + $(LD) -r -x -o hunt.driver.obj $(DOBJ) + symstrip hunt.driver.obj pathname.o -lcurses -ltermcap + +hunt.obj: $(POBJ) pathname.o + $(LD) -r -x -o hunt.obj $(POBJ) + symstrip hunt.obj pathname.o -lcurses -ltermcap + +# +# System installation +# +install: standard + install -s hunt.driver $(DESTDIR)/usr/games/lib/hunt.driver + install -s hunt $(DESTDIR)/usr/games/hunt + +hunt: $(POBJ) pathname.o + $(CC) ${SEPFLAG} $(LDFLAGS) -o hunt $(POBJ) \ + pathname.o -lcurses -ltermlib + +hunt.driver: $(DOBJ) pathname.o + $(CC) ${SEPFLAG} $(PROFLAGS) $(LDFLAGS) -o hunt.driver \ + $(DOBJ) pathname.o + +# +# Object file dependencies +# +$(POBJ): $(HDR) + +$(DOBJ): $(HDR) + $(CC) $(CFLAGS) $(PROFLAGS) -c $*.c + +pathname.dbg.o: pathname.c + @echo $(CC) $(CFLAGS) -DDEBUG -c pathname.c -o pathname.dbg.o + @rm -f x.c + @ln pathname.c x.c + @$(CC) $(CFLAGS) -DDEBUG -c x.c + @mv x.o pathname.dbg.o + @rm -f x.c + +# +# Miscellaneous functions +# +lint: $(DSRC) $(PSRC) + lint $(DEFS) -DSTANDARD $(DSRC) 2>&1 > driver.lint + lint $(DEFS) -DSTANDARD $(PSRC) -lcurses 2>&1 > hunt.lint + +tags: $(DSRC) $(PSRC) + ctags $(DSRC) $(PSRC) + +newdomain: + rm -f hunt.o extern.o driver.o + +clean: + rm -f hunt hunt.driver *.o tags errs diff --git a/src/games/hunt/README b/src/games/hunt/README new file mode 100644 index 0000000..0079806 --- /dev/null +++ b/src/games/hunt/README @@ -0,0 +1,9 @@ +If you have an old tcp/ip you might have to turn off the BROADCAST +option; see the Makefile. + +Hunt is not officially supported by anyone anywhere; however, bug +reports will be read and bug fixes/enhancements may be sent out at +irregular intervals. Enjoy. + + ucbvax!ucsfcgl!conrad + ucsfcgl!conrad@berkeley.edu diff --git a/src/games/hunt/answer.c b/src/games/hunt/answer.c new file mode 100644 index 0000000..6f004dd --- /dev/null +++ b/src/games/hunt/answer.c @@ -0,0 +1,359 @@ +/* + * Hunt + * Copyright (c) 1985 Conrad C. Huang, Gregory S. Couch, Kenneth C.R.C. Arnold + * San Francisco, California + * + * Copyright (c) 1985 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + * + * @(#) answer.c 1.1 (2.11BSD) 96/7/10 + */ + +# include "hunt.h" +# include +# include /* for gethostid() */ + +# define MAXPERMACH 3 /* Max player/monitor per machine */ + +static char Ttyname[NAMELEN]; + +answer() +{ + register PLAYER *pp; + register int newsock; + register FILE *tmpfd; +# ifdef MONITOR + static FLAG monitor; +# endif MONITOR + static char name[NAMELEN]; + static int socklen; + static u_long machine; + static u_long uid; + static SOCKET sockstruct; +# ifdef OLDIPC + extern SOCKET Daemon; +# endif OLDIPC + +# ifdef INTERNET + socklen = sizeof sockstruct; +# else + socklen = sizeof sockstruct - 1; +# endif INTERNET + errno = 0; +# ifndef OLDIPC + if ((newsock = accept(Socket, &sockstruct, &socklen)) < 0) +# else OLDIPC + if (accept(Socket, &sockstruct) < 0) +# endif OLDIPC + { + if (errno == EINTR) + return; + perror("accept"); + cleanup(1); + } +# ifdef OLDIPC + newsock = Socket; + Socket = socket(SOCK_STREAM, 0, (struct sockaddr *) &Daemon, + SO_ACCEPTCONN); + if (Socket < 0) { + perror("new accept socket"); + cleanup(1); + } + Sock_mask = (1 << Socket); + Fds_mask |= Sock_mask; + if (Socket >= Num_fds) + Num_fds = Socket + 1; +# endif OLDIPC + + tmpfd = fdopen(newsock, "w"); + +# ifdef INTERNET + machine = ntohl(((struct sockaddr_in *) &sockstruct)->sin_addr.s_addr); +# else INTERNET + if (machine == 0) + machine = gethostid(); +# endif INTERNET + (void) putw(getpid(), tmpfd); + (void) read(newsock, (char *) &uid, sizeof uid); + uid = ntohl(uid); + (void) read(newsock, name, NAMELEN); + (void) read(newsock, Ttyname, NAMELEN); +# ifdef MONITOR + (void) read(newsock, (char *) &monitor, sizeof monitor); +# endif MONITOR + + if (reached_limit(machine)) { + socklen = 0; + (void) write(newsock, (char *) &socklen, sizeof socklen); + (void) close(newsock); +# ifdef OLDIPC + Fds_mask &= ~(1 << newsock); +# endif OLDIPC + return; + } + +# ifdef MONITOR + if (monitor) + if (End_monitor < &Monitor[MAXMON]) + pp = End_monitor++; + else { + socklen = 0; + (void) write(newsock, (char *) &socklen, + sizeof socklen); + (void) close(newsock); + return; + } + else +# endif MONITOR + if (End_player < &Player[MAXPL]) + pp = End_player++; + else { + socklen = 0; + (void) write(newsock, (char *) &socklen, + sizeof socklen); + (void) close(newsock); + return; + } + + pp->p_ident = get_ident(machine, uid, name); + pp->p_output = tmpfd; + pp->p_death[0] = '\0'; + pp->p_fd = newsock; + pp->p_mask = (1 << pp->p_fd); +# ifndef OLDIPC + Fds_mask |= pp->p_mask; + if (pp->p_fd >= Num_fds) + Num_fds = pp->p_fd + 1; +# endif OLDIPC + + pp->p_y = 0; + pp->p_x = 0; + +# ifdef MONITOR + if (monitor) + stmonitor(pp); + else +# endif MONITOR + stplayer(pp); +} + +# ifdef MONITOR +stmonitor(pp) +register PLAYER *pp; +{ + register int line; + register PLAYER *npp; + + bcopy((char *) Maze, (char *) pp->p_maze, sizeof Maze); + + drawmaze(pp); + + (void) sprintf(Buf, "%5.5s%c%-10.10s", " ", stat_char(pp), + pp->p_ident->i_name); + line = STAT_MON_ROW + 1 + (pp - Monitor); + for (npp = Player; npp < End_player; npp++) { + cgoto(npp, line, STAT_NAME_COL); + outstr(npp, Buf, STAT_NAME_LEN); + } + for (npp = Monitor; npp < End_monitor; npp++) { + cgoto(npp, line, STAT_NAME_COL); + outstr(npp, Buf, STAT_NAME_LEN); + } + + sendcom(pp, REFRESH); + sendcom(pp, READY, 0); + (void) fflush(pp->p_output); +} +# endif MONITOR + +stplayer(newpp) +register PLAYER *newpp; +{ + register int x, y; + register PLAYER *pp; + + Nplayer++; + + for (y = 0; y < UBOUND; y++) + for (x = 0; x < WIDTH; x++) + newpp->p_maze[y][x] = Maze[y][x]; + for ( ; y < DBOUND; y++) { + for (x = 0; x < LBOUND; x++) + newpp->p_maze[y][x] = Maze[y][x]; + for ( ; x < RBOUND; x++) + newpp->p_maze[y][x] = SPACE; + for ( ; x < WIDTH; x++) + newpp->p_maze[y][x] = Maze[y][x]; + } + for ( ; y < HEIGHT; y++) + for (x = 0; x < WIDTH; x++) + newpp->p_maze[y][x] = Maze[y][x]; + + do { + x = rand_num(WIDTH - 1) + 1; + y = rand_num(HEIGHT - 1) + 1; + } while (Maze[y][x] != SPACE); + newpp->p_over = SPACE; + newpp->p_x = x; + newpp->p_y = y; + newpp->p_undershot = FALSE; + +# ifdef START_FLYING + /* This is only for debugging */ + newpp->p_flying = rand_num(20); + newpp->p_flyx = 2 * rand_num(6) - 5; + newpp->p_flyy = 2 * rand_num(6) - 5; + newpp->p_face = FLYER; +# else START_FLYING + newpp->p_flying = -1; + rand_face(newpp); +# endif START_FLYING + newpp->p_damage = 0; + newpp->p_damcap = MAXDAM; + newpp->p_nchar = 0; + newpp->p_ncount = 0; + newpp->p_nexec = 0; + newpp->p_ammo = ISHOTS; + newpp->p_scan = -1; + newpp->p_cloak = CLOAKLEN; + newpp->p_ncshot = 0; + + do { + x = rand_num(WIDTH - 1) + 1; + y = rand_num(HEIGHT - 1) + 1; + } while (Maze[y][x] != SPACE); + Maze[y][x] = GMINE; +# ifdef MONITOR + for (pp = Monitor; pp < End_monitor; pp++) + check(pp, y, x); +# endif MONITOR + + do { + x = rand_num(WIDTH - 1) + 1; + y = rand_num(HEIGHT - 1) + 1; + } while (Maze[y][x] != SPACE); + Maze[y][x] = MINE; +# ifdef MONITOR + for (pp = Monitor; pp < End_monitor; pp++) + check(pp, y, x); +# endif MONITOR + + (void) sprintf(Buf, "%5.2f%c%-10.10s", newpp->p_ident->i_score, + stat_char(newpp), newpp->p_ident->i_name); + y = STAT_PLAY_ROW + 1 + (newpp - Player); + for (pp = Player; pp < End_player; pp++) { + if (pp != newpp) { + char smallbuf[10]; + + pp->p_ammo += NSHOTS; + newpp->p_ammo += NSHOTS; + cgoto(pp, y, STAT_NAME_COL); + outstr(pp, Buf, STAT_NAME_LEN); + (void) sprintf(smallbuf, "%3d", pp->p_ammo); + cgoto(pp, STAT_AMMO_ROW, STAT_VALUE_COL); + outstr(pp, smallbuf, 3); + } + } +# ifdef MONITOR + for (pp = Monitor; pp < End_monitor; pp++) { + cgoto(pp, y, STAT_NAME_COL); + outstr(pp, Buf, STAT_NAME_LEN); + } +# endif MONITOR + + drawmaze(newpp); + drawplayer(newpp, TRUE); + look(newpp); +# ifdef START_FLYING + /* Make sure that the position you enter in will be erased */ + showexpl(newpp->p_y, newpp->p_x, FLYER); +# endif START_FLYING + sendcom(newpp, REFRESH); + sendcom(newpp, READY, 0); + (void) fflush(newpp->p_output); +} + +/* + * rand_face: + * Give the player a random facing direction + */ +rand_face(pp) +register PLAYER *pp; +{ + switch (rand_num(4)) { + case 0: + pp->p_face = LEFTS; + break; + case 1: + pp->p_face = RIGHT; + break; + case 2: + pp->p_face = BELOW; + break; + case 3: + pp->p_face = ABOVE; + break; + } +} + +/* + * get_ident: + * Get the score structure of a player + */ +IDENT * +get_ident(machine, uid, name) +u_long machine; +u_long uid; +char *name; +{ + register IDENT *ip; + static IDENT punt; + + for (ip = Scores; ip != NULL; ip = ip->i_next) + if (ip->i_machine == machine && ip->i_uid == uid && + strncmp(ip->i_name, name, NAMELEN) == 0) + break; + + if (ip != NULL) { + ip->i_entries++; + ip->i_score = ip->i_kills / (double) ip->i_entries; + } + else { + ip = (IDENT *) malloc(sizeof (IDENT)); + if (ip == NULL) { + /* Fourth down, time to punt */ + ip = &punt; + } + ip->i_machine = machine; + ip->i_uid = uid; + strncpy(ip->i_name, name, NAMELEN); + ip->i_kills = 0; + ip->i_entries = 1; + ip->i_score = 0; + ip->i_next = Scores; + Scores = ip; + } + + return ip; +} + +/* + * reached_limit: + * Returns whether the limit of x persons per machine has been reached + */ +reached_limit(machine) +u_long machine; +{ + register PLAYER *pp; + register int count; + + count = 0; + for (pp = Player; pp < End_player; pp++) + if (pp->p_ident->i_machine == machine) + count++; + for (pp = Monitor; pp < End_monitor; pp++) + if (pp->p_ident->i_machine == machine) + count++; + return count >= MAXPERMACH; +} diff --git a/src/games/hunt/connect.c b/src/games/hunt/connect.c new file mode 100644 index 0000000..de38700 --- /dev/null +++ b/src/games/hunt/connect.c @@ -0,0 +1,28 @@ +/* + * Hunt + * Copyright (c) 1985 Conrad C. Huang, Gregory S. Couch, Kenneth C.R.C. Arnold + * San Francisco, California + * + * Copyright (c) 1985 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +# include "hunt.h" +# include + +do_connect(name) +char *name; +{ + static long uid; + extern char *ttyname(); + + uid = htonl(getuid()); + (void) write(Socket, (char *) &uid, sizeof uid); + (void) write(Socket, name, NAMELEN); + (void) strcpy(Buf, ttyname(fileno(stderr))); + (void) write(Socket, Buf, NAMELEN); +# ifdef MONITOR + (void) write(Socket, (char *) &Am_monitor, sizeof Am_monitor); +# endif MONITOR +} diff --git a/src/games/hunt/draw.c b/src/games/hunt/draw.c new file mode 100644 index 0000000..796c514 --- /dev/null +++ b/src/games/hunt/draw.c @@ -0,0 +1,388 @@ +/* + * Hunt + * Copyright (c) 1985 Conrad C. Huang, Gregory S. Couch, Kenneth C.R.C. Arnold + * San Francisco, California + * + * Copyright (c) 1985 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +# include "hunt.h" + +drawmaze(pp) +register PLAYER *pp; +{ + register int x; + register char *sp; + register int y; + register char *endp; + + clrscr(pp); + outstr(pp, pp->p_maze[0], WIDTH); + for (y = 1; y < HEIGHT - 1; y++) { + endp = &pp->p_maze[y][WIDTH]; + for (x = 0, sp = pp->p_maze[y]; sp < endp; x++, sp++) + if (*sp != SPACE) { + cgoto(pp, y, x); + if (pp->p_x == x && pp->p_y == y) + outch(pp, translate(*sp)); + else + outch(pp, *sp); + } + } + cgoto(pp, HEIGHT - 1, 0); + outstr(pp, pp->p_maze[HEIGHT - 1], WIDTH); + drawstatus(pp); +} + +/* + * drawstatus - put up the status lines (this assumes the screen + * size is 80x24 with the maze being 64x24) + */ +drawstatus(pp) +register PLAYER *pp; +{ + register int i; + register PLAYER *np; + + (void) sprintf(Buf, "%-13.13s", pp->p_ident->i_name); + cgoto(pp, STAT_NAME_ROW, STAT_LABEL_COL); + outstr(pp, Buf, 13); + + cgoto(pp, STAT_AMMO_ROW, STAT_LABEL_COL); + outstr(pp, "Ammo:", 5); + (void) sprintf(Buf, "%3d", pp->p_ammo); + cgoto(pp, STAT_AMMO_ROW, STAT_VALUE_COL); + outstr(pp, Buf, 3); + + cgoto(pp, STAT_CLOAK_ROW, STAT_LABEL_COL); + outstr(pp, "Cloak:", 6); + cgoto(pp, STAT_CLOAK_ROW, STAT_VALUE_COL); + outstr(pp, (pp->p_cloak < 0) ? " " : " on", 3); + + cgoto(pp, STAT_SCAN_ROW, STAT_LABEL_COL); + outstr(pp, "Scan:", 5); + cgoto(pp, STAT_SCAN_ROW, STAT_VALUE_COL); + outstr(pp, (pp->p_scan < 0) ? " " : " on", 3); + + cgoto(pp, STAT_GUN_ROW, STAT_LABEL_COL); + outstr(pp, "Gun:", 4); + cgoto(pp, STAT_GUN_ROW, STAT_VALUE_COL); + outstr(pp, (pp->p_ncshot < MAXNCSHOT) ? " ok" : " ", 3); + + cgoto(pp, STAT_DAM_ROW, STAT_LABEL_COL); + outstr(pp, "Damage:", 7); + (void) sprintf(Buf, "%2d/%2d", pp->p_damage, pp->p_damcap); + cgoto(pp, STAT_DAM_ROW, STAT_VALUE_COL); + outstr(pp, Buf, 5); + + cgoto(pp, STAT_KILL_ROW, STAT_LABEL_COL); + outstr(pp, "Kills:", 6); + (void) sprintf(Buf, "%3d", (pp->p_damcap - MAXDAM) / 2); + cgoto(pp, STAT_KILL_ROW, STAT_VALUE_COL); + outstr(pp, Buf, 3); + + cgoto(pp, STAT_PLAY_ROW, STAT_LABEL_COL); + outstr(pp, "Player:", 7); + for (i = STAT_PLAY_ROW + 1, np = Player; np < End_player; np++) { + (void) sprintf(Buf, "%5.2f%c%-10.10s", np->p_ident->i_score, + stat_char(np), np->p_ident->i_name); + cgoto(pp, i++, STAT_NAME_COL); + outstr(pp, Buf, STAT_NAME_LEN); + } + +# ifdef MONITOR + cgoto(pp, STAT_MON_ROW, STAT_LABEL_COL); + outstr(pp, "Monitor:", 8); + for (i = STAT_MON_ROW + 1, np = Monitor; np < End_monitor; np++) { + (void) sprintf(Buf, "%5.5s %-10.10s", " ", np->p_ident->i_name); + cgoto(pp, i++, STAT_NAME_COL); + outstr(pp, Buf, STAT_NAME_LEN); + } +# endif MONITOR +} + +# ifndef CPUHOG +look(pp) +register PLAYER *pp; +{ + register int x, y; + + x = pp->p_x; + y = pp->p_y; + + check(pp, y - 1, x - 1); + check(pp, y - 1, x ); + check(pp, y - 1, x + 1); + check(pp, y , x - 1); + check(pp, y , x ); + check(pp, y , x + 1); + check(pp, y + 1, x - 1); + check(pp, y + 1, x ); + check(pp, y + 1, x + 1); + + switch (pp->p_face) { + case LEFTS: + see(pp, LEFTS); + see(pp, ABOVE); + see(pp, BELOW); + break; + case RIGHT: + see(pp, RIGHT); + see(pp, ABOVE); + see(pp, BELOW); + break; + case ABOVE: + see(pp, ABOVE); + see(pp, LEFTS); + see(pp, RIGHT); + break; + case BELOW: + see(pp, BELOW); + see(pp, LEFTS); + see(pp, RIGHT); + break; +# ifdef FLY + case FLYER: + break; +# endif FLY + } + cgoto(pp, y, x); +} + +see(pp, face) +register PLAYER *pp; +int face; +{ + register char *sp; + register int y, x, i, cnt; + + x = pp->p_x; + y = pp->p_y; + + switch (face) { + case LEFTS: + sp = &Maze[y][x]; + for (i = 0; See_over[*--sp]; i++) + continue; + + if (i == 0) + break; + + cnt = i; + x = pp->p_x - 1; + --y; + while (i--) + check(pp, y, --x); + i = cnt; + x = pp->p_x - 1; + ++y; + while (i--) + check(pp, y, --x); + i = cnt; + x = pp->p_x - 1; + ++y; + while (i--) + check(pp, y, --x); + break; + case RIGHT: + sp = &Maze[y][++x]; + for (i = 0; See_over[*sp++]; i++) + continue; + + if (i == 0) + break; + + cnt = i; + x = pp->p_x + 1; + --y; + while (i--) + check(pp, y, ++x); + i = cnt; + x = pp->p_x + 1; + ++y; + while (i--) + check(pp, y, ++x); + i = cnt; + x = pp->p_x + 1; + ++y; + while (i--) + check(pp, y, ++x); + break; + case ABOVE: + sp = &Maze[--y][x]; + if (!See_over[*sp]) + break; + do { + --y; + sp -= sizeof Maze[0]; + check(pp, y, x - 1); + check(pp, y, x ); + check(pp, y, x + 1); + } while (See_over[*sp]); + break; + case BELOW: + sp = &Maze[++y][x]; + if (!See_over[*sp]) + break; + do { + y++; + sp += sizeof Maze[0]; + check(pp, y, x - 1); + check(pp, y, x ); + check(pp, y, x + 1); + } while (See_over[*sp]); + break; + } +} + +# else CPUHOG + +look(pp) +register PLAYER *pp; +{ + switch (pp->p_face) { + case LEFTS: + lookquad2(pp, pp->p_y, pp->p_x); + lookquad3(pp, pp->p_y, pp->p_x); + break; + case RIGHT: + lookquad1(pp, pp->p_y, pp->p_x); + lookquad4(pp, pp->p_y, pp->p_x); + break; + case ABOVE: + lookquad3(pp, pp->p_y, pp->p_x); + lookquad4(pp, pp->p_y, pp->p_x); + break; + case BELOW: + lookquad1(pp, pp->p_y, pp->p_x); + lookquad2(pp, pp->p_y, pp->p_x); + break; + } + cgoto(pp, pp->p_y, pp->p_x); +} +# endif CPUHOG + +check(pp, y, x) +PLAYER *pp; +int y, x; +{ + register int index; + register int ch; + register PLAYER *rpp; + + index = y * sizeof Maze[0] + x; + ch = ((char *) Maze)[index]; + if (ch != ((char *) pp->p_maze)[index]) { + rpp = pp; + cgoto(rpp, y, x); + if (x == rpp->p_x && y == rpp->p_y) + outch(rpp, translate(ch)); + else + outch(rpp, ch); + ((char *) rpp->p_maze)[index] = ch; + } +} + +/* + * showstat + * Update the status of players + */ +showstat(pp) +register PLAYER *pp; +{ + register PLAYER *np; + register int y; + register char c; + + y = STAT_PLAY_ROW + 1 + (pp - Player); + c = stat_char(pp); +# ifdef MONITOR + for (np = Monitor; np < End_monitor; np++) { + cgoto(np, y, STAT_SCAN_COL); + outch(np, c); + } +# endif MONITOR + for (np = Player; np < End_player; np++) { + cgoto(np, y, STAT_SCAN_COL); + outch(np, c); + } +} + +/* + * drawplayer: + * Draw the player on the screen and show him to everyone who's scanning + * unless he is cloaked. + */ +drawplayer(pp, draw) +PLAYER *pp; +FLAG draw; +{ + register PLAYER *newp; + register int x, y; + + x = pp->p_x; + y = pp->p_y; + Maze[y][x] = draw ? pp->p_face : pp->p_over; + +# ifdef MONITOR + for (newp = Monitor; newp < End_monitor; newp++) + check(newp, y, x); +# endif MONITOR + + for (newp = Player; newp < End_player; newp++) { + if (!draw || newp == pp) { + check(newp, y, x); + continue; + } + if (newp->p_scan == 0) { + cgoto(newp, STAT_SCAN_ROW, STAT_VALUE_COL); + outstr(newp, " ", 3); + newp->p_scan--; + showstat(newp); + } + else if (newp->p_scan > 0) { + if (pp->p_cloak < 0) + check(newp, y, x); + newp->p_scan--; + } + } + if (!draw || pp->p_cloak < 0) + return; + if (pp->p_cloak-- == 0) { + cgoto(pp, STAT_CLOAK_ROW, STAT_VALUE_COL); + outstr(pp, " ", 3); + showstat(pp); + } +} + +message(pp, s) +register PLAYER *pp; +char *s; +{ + cgoto(pp, HEIGHT, 0); + outstr(pp, s, strlen(s)); + ce(pp); +} + +/* + * translate: + * Turn a charcter into the right direction character if we are + * looking at the current player. + */ +translate(ch) +char ch; +{ + switch (ch) { + case LEFTS: + return '<'; + case RIGHT: + return '>'; + case ABOVE: + return '^'; + case BELOW: + return 'v'; + } + return ch; +} diff --git a/src/games/hunt/driver.c b/src/games/hunt/driver.c new file mode 100644 index 0000000..04d9ba6 --- /dev/null +++ b/src/games/hunt/driver.c @@ -0,0 +1,671 @@ +/* + * Hunt + * Copyright (c) 1985 Conrad C. Huang, Gregory S. Couch, Kenneth C.R.C. Arnold + * San Francisco, California + * + * Copyright (c) 1985 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + * + * 1997/9/9 - updated to use sigprocmask (and compute the alarm mask correctly) + */ + +# include "hunt.h" +# include +# include +# include +# include + +# ifndef pdp11 +# define RN (((Seed = Seed * 11109 + 13849) >> 16) & 0xffff) +# else pdp11 +# define RN ((Seed = Seed * 11109 + 13849) & 0x7fff) +# endif pdp11 + +int Seed = 0; + +# ifdef CONSTANT_MOVE +static struct itimerval Timing; +# endif CONSTANT_MOVE + +SOCKET Daemon; +# ifdef INTERNET +int Test_socket; /* test socket to answer datagrams */ +# define DAEMON_SIZE (sizeof Daemon) +# else INTERNET +# define DAEMON_SIZE (sizeof Daemon - 1) +# endif INTERNET + +/* + * main: + * The main program. + */ +main() +{ + register PLAYER *pp; + register int had_char; +# ifdef INTERNET + register long test_mask; + int msg; + int namelen; + SOCKET test; +# endif INTERNET +# ifdef CONSTANT_MOVE + sigset_t alarm_sigset; +# endif CONSTANT_MOVE + static long read_fds; + + init(); + Sock_mask = (1 << Socket); +# ifdef INTERNET + test_mask = (1 << Test_socket); +# endif INTERNET + +# ifdef CONSTANT_MOVE + sigemptyset(&alarm_sigset); + sigaddset(&alarm_sigset, SIGALRM); + (void) sigprocmask(SIG_BLOCK, &alarm_sigset, NULL); + (void) signal(SIGALRM, moveshots); +# endif CONSTANT_MOVE + + while (Nplayer > 0) { +# ifdef CONSTANT_MOVE + (void) sigprocmask(SIG_UNBLOCK, &alarm_sigset, NULL); +# endif CONSTANT_MOVE + read_fds = Fds_mask; + errno = 0; +# ifndef OLDIPC + while (select(Num_fds, &read_fds, (int *) NULL, + (int *) NULL, (struct timeval *) NULL) < 0) +# else OLDIPC + while (select(20, &read_fds, NULL, 32767) < 0) +# endif OLDIPC + { + if (errno != EINTR) + perror("select"); + if (Nplayer == 0) + goto out; + errno = 0; + } + Have_inp = read_fds; +# ifdef CONSTANT_MOVE + (void) sigprocmask(SIG_BLOCK, &alarm_sigset, NULL); +# endif CONSTANT_MOVE +# ifdef INTERNET + if (read_fds & test_mask) { + namelen = DAEMON_SIZE; +# ifndef OLDIPC + (void) recvfrom(Test_socket, (char *) &msg, sizeof msg, + 0, (struct sockaddr *) &test, &namelen); + (void) sendto(Test_socket, (char *) &msg, sizeof msg, + 0, (struct sockaddr *) &test, DAEMON_SIZE); +# else OLDIPC + (void) receive(Test_socket, (struct sockaddr *) &test, + (char *) &msg, sizeof msg); + (void) send(Test_socket, (struct sockaddr *) &test, + (char *) &msg, sizeof msg); +# endif OLDIPC + } +# endif INTERNET + for (;;) { + had_char = FALSE; + for (pp = Player; pp < End_player; pp++) + if (havechar(pp)) { + execute(pp); + pp->p_nexec++; + had_char++; + } +# ifdef MONITOR + for (pp = Monitor; pp < End_monitor; pp++) + if (havechar(pp)) { + mon_execute(pp); + pp->p_nexec++; + had_char++; + } +# endif MONITOR + if (!had_char) + break; +# ifdef CONSTANT_MOVE + for (pp = Player; pp < End_player; pp++) { + look(pp); + sendcom(pp, REFRESH); + } +# ifdef MONITOR + for (pp = Monitor; pp < End_monitor; pp++) + sendcom(pp, REFRESH); +# endif MONITOR +# else CONSTANT_MOVE + moveshots(); +# endif CONSTANT_MOVE + for (pp = Player; pp < End_player; ) + if (pp->p_death[0] != '\0') + zap(pp, TRUE); + else + pp++; +# ifdef MONITOR + for (pp = Monitor; pp < End_monitor; ) + if (pp->p_death[0] != '\0') + zap(pp, FALSE); + else + pp++; +# endif MONITOR + } + if (read_fds & Sock_mask) + answer(); + for (pp = Player; pp < End_player; pp++) { + if (read_fds & pp->p_mask) + sendcom(pp, READY, pp->p_nexec); + pp->p_nexec = 0; + (void) fflush(pp->p_output); + } +# ifdef MONITOR + for (pp = Monitor; pp < End_monitor; pp++) { + if (read_fds & pp->p_mask) + sendcom(pp, READY, pp->p_nexec); + pp->p_nexec = 0; + (void) fflush(pp->p_output); + } +# endif MONITOR + } +out: +# ifdef CONSTANT_MOVE + bul_alarm(0); +# endif CONSTANT_MOVE + +# ifdef MONITOR + for (pp = Monitor; pp < End_monitor; ) + zap(pp, FALSE); +# endif MONITOR + cleanup(0); +} + +/* + * init: + * Initialize the global parameters. + */ +init() +{ + register int i; +# ifdef INTERNET + SOCKET test_port; + auto int msg; +# endif INTERNET + int cleanup(); + +# ifndef DEBUG + (void) ioctl(fileno(stdout), TIOCNOTTY, NULL); + (void) setpgrp(getpid(), getpid()); + (void) signal(SIGHUP, SIG_IGN); + (void) signal(SIGINT, SIG_IGN); + (void) signal(SIGQUIT, SIG_IGN); + (void) signal(SIGTERM, cleanup); +# endif DEBUG + + (void) chdir("/usr/tmp"); /* just in case it core dumps */ + (void) signal(SIGPIPE, SIG_IGN); + +# ifdef INTERNET + Daemon.sin_family = SOCK_FAMILY; +# ifdef OLD + if (gethostname(local_name, sizeof local_name) < 0) { + perror("gethostname"); + exit(1); + } + if ((hp = gethostbyname(local_name)) == NULL) { + fprintf(stderr, "Unknown host %s\n", local_name); + exit(1); + } + bcopy(hp->h_addr, &(Daemon.sin_addr.s_addr), hp->h_length); +# else + Daemon.sin_addr.s_addr = INADDR_ANY; +# endif OLD + Daemon.sin_port = htons(Sock_port); +# else INTERNET + Daemon.sun_family = SOCK_FAMILY; + (void) strcpy(Daemon.sun_path, Sock_name); +# endif INTERNET + +# ifndef OLDIPC + Socket = socket(SOCK_FAMILY, SOCK_STREAM, 0); +# else OLDIPC + Socket = socket(SOCK_STREAM, 0, (struct sockaddr *) &Daemon, + SO_ACCEPTCONN); +# endif OLDIPC +# if defined(INTERNET) && !defined(OLDIPC) + if (setsockopt(Socket, SOL_SOCKET, SO_USELOOPBACK, &msg, sizeof msg)<0) + perror("setsockopt loopback"); +# endif INTERNET +# ifndef OLDIPC + if (bind(Socket, (struct sockaddr *) &Daemon, DAEMON_SIZE) < 0) { + if (errno == EADDRINUSE) + exit(0); + else { + perror("bind"); + cleanup(1); + } + } + (void) listen(Socket, 5); +# endif OLDIPC + Fds_mask = (1 << Socket); + Num_fds = Socket + 1; + +# ifdef INTERNET + test_port = Daemon; + test_port.sin_port = htons(Test_port); + +# ifndef OLDIPC + Test_socket = socket(SOCK_FAMILY, SOCK_DGRAM, 0); + if (bind(Test_socket, (struct sockaddr *) &test_port, + DAEMON_SIZE) < 0) { + perror("bind"); + exit(1); + } + (void) listen(Test_socket, 5); +# else OLDIPC + Test_socket = socket(SOCK_DGRAM, 0, (struct sockaddr *) &test_port, 0); +# endif OLDIPC + Fds_mask |= (1 << Test_socket); + if (Test_socket > Socket) + Num_fds = Test_socket + 1; +# endif INTERNET + + Seed = getpid() + time((time_t *) NULL); + makemaze(); + + for (i = 0; i < NASCII; i++) + See_over[i] = TRUE; + See_over[DOOR] = FALSE; + See_over[WALL1] = FALSE; + See_over[WALL2] = FALSE; + See_over[WALL3] = FALSE; +# ifdef REFLECT + See_over[WALL4] = FALSE; + See_over[WALL5] = FALSE; +# endif REFLECT + +# ifdef CONSTANT_MOVE + getitimer(ITIMER_REAL, &Timing); + Timing.it_interval.tv_sec = 0; + Timing.it_interval.tv_usec = 500; + Timing.it_value.tv_sec = 0; + Timing.it_value.tv_usec = 0; + setitimer(ITIMER_REAL, &Timing, NULL); +# endif CONSTANT_MOVE + + answer(); +} + +# ifdef CONSTANT_MOVE +/* + * bul_alarm: + * Set up the alarm for the bullets + */ +bul_alarm(val) +int val; +{ + Timing.it_value.tv_usec = val * Timing.it_interval.tv_usec; + setitimer(ITIMER_REAL, &Timing, NULL); +} +# endif CONSTANT_MOVE + +/* + * checkdam: + * Check the damage to the given player, and see if s/he is killed + */ +checkdam(ouch, gotcha, credit, amt, shot_type) +register PLAYER *ouch, *gotcha; +register IDENT *credit; +int amt; +char shot_type; +{ + register char *cp; + + if (ouch->p_death[0] != '\0') + return; + if (rand_num(100) < 5) { + message(ouch, "Missed you by a hair"); + if (gotcha != NULL) + message(gotcha, "Missed him"); + return; + } + ouch->p_damage += amt; + if (ouch->p_damage <= ouch->p_damcap) { + (void) sprintf(Buf, "%2d", ouch->p_damage); + cgoto(ouch, STAT_DAM_ROW, STAT_VALUE_COL); + outstr(ouch, Buf, 2); + return; + } + + /* Someone DIED */ + switch (shot_type) { + default: + cp = "Killed"; + break; +# ifdef FLY + case FALL: + cp = "Killed on impact"; + break; +# endif FLY + case KNIFE: + cp = "Stabbed to death"; + break; + case SHOT: + cp = "Shot to death"; + break; + case GRENADE: + case SATCHEL: + case BOMB: + cp = "Bombed"; + break; + case MINE: + case GMINE: + cp = "Blown apart"; + break; +# ifdef OOZE + case SLIME: + cp = "Slimed"; + break; +# endif OOZE +# ifdef VOLCANO + case LAVA: + cp = "Baked"; + break; +# endif VOLCANO + } + if (credit == NULL) { + (void) sprintf(ouch->p_death, "| %s by %s |", cp, + (shot_type == MINE || shot_type == GMINE) ? + "a mine" : "act of God"); + return; + } + + (void) sprintf(ouch->p_death, "| %s by %s |", cp, credit->i_name); + + credit->i_kills++; + credit->i_score = credit->i_kills / (double) credit->i_entries; + if (gotcha == NULL) + return; + gotcha->p_damcap += STABDAM; + gotcha->p_damage -= STABDAM; + if (gotcha->p_damage < 0) + gotcha->p_damage = 0; + (void) sprintf(Buf, "%2d/%2d", gotcha->p_damage, gotcha->p_damcap); + cgoto(gotcha, STAT_DAM_ROW, STAT_VALUE_COL); + outstr(gotcha, Buf, 5); + (void) sprintf(Buf, "%3d", (gotcha->p_damcap - MAXDAM) / 2); + cgoto(gotcha, STAT_KILL_ROW, STAT_VALUE_COL); + outstr(gotcha, Buf, 3); + (void) sprintf(Buf, "%5.2f", gotcha->p_ident->i_score); + for (ouch = Player; ouch < End_player; ouch++) { + cgoto(ouch, STAT_PLAY_ROW + 1 + (gotcha - Player), + STAT_NAME_COL); + outstr(ouch, Buf, 5); + } +} + +/* + * zap: + * Kill off a player and take him out of the game. + */ +zap(pp, was_player) +register PLAYER *pp; +FLAG was_player; +{ + register int i, len; + register BULLET *bp; + register PLAYER *np; + register int x, y; + int savefd, savemask; + + if (was_player) { + drawplayer(pp, FALSE); + Nplayer--; + } + + len = strlen(pp->p_death); /* Display the cause of death */ + x = (WIDTH - len) / 2; + cgoto(pp, HEIGHT / 2, x); + outstr(pp, pp->p_death, len); + for (i = 1; i < len; i++) + pp->p_death[i] = '-'; + pp->p_death[0] = '+'; + pp->p_death[len - 1] = '+'; + cgoto(pp, HEIGHT / 2 - 1, x); + outstr(pp, pp->p_death, len); + cgoto(pp, HEIGHT / 2 + 1, x); + outstr(pp, pp->p_death, len); + cgoto(pp, HEIGHT, 0); + + if (Nplayer == 0) { +# ifdef CONSTANT_MOVE + bul_alarm(0); +# endif CONSTANT_MOVE + cleanup(0); + /* NOTREACHED */ + } + + savefd = pp->p_fd; + savemask = pp->p_mask; + +# ifdef MONITOR + if (was_player) { +# endif MONITOR + for (bp = Bullets; bp != NULL; bp = bp->b_next) { + if (bp->b_owner == pp) + bp->b_owner = NULL; + if (bp->b_x == pp->p_x && bp->b_y == pp->p_y) + bp->b_over = SPACE; + } + + i = rand_num(pp->p_ammo); + if (i == pp->p_ammo - 1) { + x = pp->p_ammo; + len = SLIME; + } + else if (i >= BOMBREQ) { + x = BOMBREQ; + len = BOMB; + } + else if (i >= SSLIMEREQ) { + x = SSLIMEREQ; + len = SLIME; + } + else if (i >= SATREQ) { + x = SATREQ; + len = SATCHEL; + } + else if (i >= SLIMEREQ) { + x = SLIMEREQ; + len = SLIME; + } + else if (i >= GRENREQ) { + x = GRENREQ; + len = GRENADE; + } + else + x = 0; + if (x > 0) { + add_shot(len, pp->p_y, pp->p_x, pp->p_face, x, + (PLAYER *) NULL, TRUE, SPACE); + (void) sprintf(Buf, "%s detonated.", + pp->p_ident->i_name); + for (np = Player; np < End_player; np++) + message(np, Buf); +# ifdef MONITOR + for (np = Monitor; np < End_monitor; np++) + message(np, Buf); +# endif MONITOR + } + +# ifdef VOLCANO + volcano += pp->p_ammo - x; + if (rand_num(100) < volcano / 50) { + do { + x = rand_num(WIDTH / 2) + WIDTH / 4; + y = rand_num(HEIGHT / 2) + HEIGHT / 4; + } while (Maze[y][x] != SPACE); + add_shot(LAVA, y, x, LEFTS, volcano, + (PLAYER *) NULL, TRUE, SPACE); + for (np = Player; np < End_player; np++) + message(np, "Volcano eruption."); + volcano = 0; + } +# endif VOLCANO + + sendcom(pp, ENDWIN); + (void) fclose(pp->p_output); + + End_player--; + if (pp != End_player) { + bcopy((char *) End_player, (char *) pp, + sizeof (PLAYER)); + (void) sprintf(Buf, "%5.2f%c%-10.10s", + pp->p_ident->i_score, stat_char(pp), + pp->p_ident->i_name); + i = STAT_PLAY_ROW + 1 + (pp - Player); + for (np = Player; np < End_player; np++) { + cgoto(np, i, STAT_NAME_COL); + outstr(np, Buf, STAT_NAME_LEN); + } +# ifdef MONITOR + for (np = Monitor; np < End_monitor; np++) { + cgoto(np, i, STAT_NAME_COL); + outstr(np, Buf, STAT_NAME_LEN); + } +# endif MONITOR + } + + /* Erase the last player */ + i = STAT_PLAY_ROW + 1 + Nplayer; + for (np = Player; np < End_player; np++) { + cgoto(np, i, STAT_NAME_COL); + ce(np); + } +# ifdef MONITOR + for (np = Monitor; np < End_monitor; np++) { + cgoto(np, i, STAT_NAME_COL); + ce(np); + } + } + else { + sendcom(pp, ENDWIN); + (void) putc(LAST_PLAYER, pp->p_output); + (void) fclose(pp->p_output); + + End_monitor--; + if (pp != End_monitor) { + bcopy((char *) End_monitor, (char *) pp, + sizeof (PLAYER)); + (void) sprintf(Buf, "%5.5s %-10.10s", " ", + pp->p_ident->i_name); + i = STAT_MON_ROW + 1 + (pp - Player); + for (np = Player; np < End_player; np++) { + cgoto(np, i, STAT_NAME_COL); + outstr(np, Buf, STAT_NAME_LEN); + } + for (np = Monitor; np < End_monitor; np++) { + cgoto(np, i, STAT_NAME_COL); + outstr(np, Buf, STAT_NAME_LEN); + } + } + + /* Erase the last monitor */ + i = STAT_MON_ROW + 1 + (End_monitor - Monitor); + for (np = Player; np < End_player; np++) { + cgoto(np, i, STAT_NAME_COL); + ce(np); + } + for (np = Monitor; np < End_monitor; np++) { + cgoto(np, i, STAT_NAME_COL); + ce(np); + } + + } +# endif MONITOR + + Fds_mask &= ~savemask; + if (Num_fds == savefd + 1) { + Num_fds = Socket; +# ifdef INTERNET + if (Test_socket > Socket) + Num_fds = Test_socket; +# endif INTERNET + for (np = Player; np < End_player; np++) + if (np->p_fd > Num_fds) + Num_fds = np->p_fd; +# ifdef MONITOR + for (np = Monitor; np < End_monitor; np++) + if (np->p_fd > Num_fds) + Num_fds = np->p_fd; +# endif MONITOR + Num_fds++; + } +} + +/* + * rand_num: + * Return a random number in a given range. + */ +rand_num(range) +int range; +{ + return (range == 0 ? 0 : RN % range); +} + +/* + * havechar: + * Check to see if we have any characters in the input queue; if + * we do, read them, stash them away, and return TRUE; else return + * FALSE. + */ +havechar(pp) +register PLAYER *pp; +{ + extern int errno; + + if (pp->p_ncount < pp->p_nchar) + return TRUE; + if (!(Have_inp & pp->p_mask)) + return FALSE; + Have_inp &= ~pp->p_mask; +check_again: + errno = 0; + if ((pp->p_nchar = read(pp->p_fd, pp->p_cbuf, sizeof pp->p_cbuf)) <= 0) + { + if (errno == EINTR) + goto check_again; + pp->p_cbuf[0] = 'q'; + } + pp->p_ncount = 0; + return TRUE; +} + +/* + * cleanup: + * Exit with the given value, cleaning up any droppings lying around + */ +cleanup(eval) +int eval; +{ + register PLAYER *pp; + + for (pp = Player; pp < End_player; pp++) { + cgoto(pp, HEIGHT, 0); + sendcom(pp, ENDWIN); + (void) putc(LAST_PLAYER, pp->p_output); + (void) fclose(pp->p_output); + } +# ifdef MONITOR + for (pp = Monitor; pp < End_monitor; pp++) { + cgoto(pp, HEIGHT, 0); + sendcom(pp, ENDWIN); + (void) putc(LAST_PLAYER, pp->p_output); + (void) fclose(pp->p_output); + } +# endif MONITOR + (void) close(Socket); +# ifdef AF_UNIX_HACK + (void) unlink(Sock_name); +# endif AF_UNIX_HACK + exit(eval); +} diff --git a/src/games/hunt/execute.c b/src/games/hunt/execute.c new file mode 100644 index 0000000..72adb41 --- /dev/null +++ b/src/games/hunt/execute.c @@ -0,0 +1,497 @@ +/* + * Hunt + * Copyright (c) 1985 Conrad C. Huang, Gregory S. Couch, Kenneth C.R.C. Arnold + * San Francisco, California + * + * Copyright (c) 1985 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +# include "hunt.h" + +# undef CTRL +# define CTRL(x) ('x' & 037) + +# ifdef MONITOR +/* + * mon_execute: + * Execute a single monitor command + */ +mon_execute(pp) +register PLAYER *pp; +{ + register char ch; + + ch = pp->p_cbuf[pp->p_ncount++]; + switch (ch) { + case CTRL(L): + sendcom(pp, REDRAW); + break; + case 'q': + (void) strcpy(pp->p_death, "| Quit |"); + break; + } +} +# endif MONITOR + +/* + * execute: + * Execute a single command + */ +execute(pp) +register PLAYER *pp; +{ + register char ch; + + ch = pp->p_cbuf[pp->p_ncount++]; + +# ifdef FLY + if (pp->p_flying >= 0) { + switch (ch) { + case CTRL(L): + sendcom(pp, REDRAW); + break; + case 'q': + (void) strcpy(pp->p_death, "| Quit |"); + break; + } + return; + } +# endif FLY + + switch (ch) { + case CTRL(L): + sendcom(pp, REDRAW); + break; + case 'h': + move(pp, LEFTS); + break; + case 'H': + face(pp, LEFTS); + break; + case 'j': + move(pp, BELOW); + break; + case 'J': + face(pp, BELOW); + break; + case 'k': + move(pp, ABOVE); + break; + case 'K': + face(pp, ABOVE); + break; + case 'l': + move(pp, RIGHT); + break; + case 'L': + face(pp, RIGHT); + break; + case 'f': + fire(pp, SHOT); + break; + case 'g': + fire(pp, GRENADE); + break; + case 'F': + fire(pp, SATCHEL); + break; + case 'G': + fire(pp, BOMB); + break; +# ifdef OOZE + case 'o': + fire_slime(pp, SLIMEREQ); + break; + case 'O': + fire_slime(pp, SSLIMEREQ); + break; +# endif OOZE + case 's': + scan(pp); + break; + case 'c': + cloak(pp); + break; + case 'q': + (void) strcpy(pp->p_death, "| Quit |"); + break; + } +} + +/* + * move: + * Execute a move in the given direction + */ +move(pp, dir) +register PLAYER *pp; +int dir; +{ + register PLAYER *newp; + register int x, y; + register FLAG moved; + register BULLET *bp; + + y = pp->p_y; + x = pp->p_x; + + switch (dir) { + case LEFTS: + x--; + break; + case RIGHT: + x++; + break; + case ABOVE: + y--; + break; + case BELOW: + y++; + break; + } + + moved = FALSE; + switch (Maze[y][x]) { + case SPACE: +# ifdef RANDOM + case DOOR: +# endif RANDOM + moved = TRUE; + break; + case WALL1: + case WALL2: + case WALL3: +# ifdef REFLECT + case WALL4: + case WALL5: +# endif REFLECT + break; + case MINE: + case GMINE: + if (dir == pp->p_face) + pickup(pp, y, x, 5, Maze[y][x]); + else if (opposite(dir, pp->p_face)) + pickup(pp, y, x, 95, Maze[y][x]); + else + pickup(pp, y, x, 50, Maze[y][x]); + Maze[y][x] = SPACE; + moved = TRUE; + break; + case SHOT: + case GRENADE: + case SATCHEL: + case BOMB: + bp = is_bullet(y, x); + if (bp != NULL) + bp->b_expl = TRUE; + Maze[y][x] = SPACE; + moved = TRUE; + break; + case LEFTS: + case RIGHT: + case ABOVE: + case BELOW: +# ifdef FLY + case FLYER: +# endif FLY + if (dir != pp->p_face) + sendcom(pp, BELL); + else { + newp = play_at(y, x); + checkdam(newp, pp, pp->p_ident, STABDAM, KNIFE); + } + break; + } + if (moved) { + if (pp->p_ncshot > 0) + if (--pp->p_ncshot == MAXNCSHOT) { + cgoto(pp, STAT_GUN_ROW, STAT_VALUE_COL); + outstr(pp, " ok", 3); + } + if (pp->p_undershot) { + fixshots(pp->p_y, pp->p_x, pp->p_over); + pp->p_undershot = FALSE; + } + drawplayer(pp, FALSE); + pp->p_over = Maze[y][x]; + pp->p_y = y; + pp->p_x = x; + drawplayer(pp, TRUE); + } +} + +/* + * face: + * Change the direction the player is facing + */ +face(pp, dir) +register PLAYER *pp; +register int dir; +{ + if (pp->p_face != dir) { + pp->p_face = dir; + drawplayer(pp, TRUE); + } +} + +/* + * fire: + * Fire a shot of the given type in the given direction + */ +fire(pp, type) +register PLAYER *pp; +register char type; +{ + register int req_index; + static int req[4] = { BULREQ, GRENREQ, SATREQ, BOMBREQ }; + static int shot_type[4] = { SHOT, GRENADE, SATCHEL, BOMB }; + + if (pp == NULL) + return; + if (pp->p_ammo == 0) { + message(pp, "No more charges."); + return; + } + if (pp->p_ncshot > MAXNCSHOT) + return; + if (pp->p_ncshot++ == MAXNCSHOT) { + cgoto(pp, STAT_GUN_ROW, STAT_VALUE_COL); + outstr(pp, " ", 3); + } + switch (type) { + case SHOT: + req_index = 0; + break; + case GRENADE: + req_index = 1; + break; + case SATCHEL: + req_index = 2; + break; + case BOMB: + req_index = 3; + break; +# ifdef DEBUG + default: + message(pp, "What you do!!!"); + return; +# endif DEBUG + } + while (pp->p_ammo < req[req_index]) + req_index--; + pp->p_ammo -= req[req_index]; + (void) sprintf(Buf, "%3d", pp->p_ammo); + cgoto(pp, STAT_AMMO_ROW, STAT_VALUE_COL); + outstr(pp, Buf, 3); + + add_shot(shot_type[req_index], pp->p_y, pp->p_x, pp->p_face, + req[req_index], pp, FALSE, pp->p_face); + pp->p_undershot = TRUE; + + /* + * Show the object to everyone + */ + showexpl(pp->p_y, pp->p_x, shot_type[req_index]); + for (pp = Player; pp < End_player; pp++) + sendcom(pp, REFRESH); +# ifdef MONITOR + for (pp = Monitor; pp < End_monitor; pp++) + sendcom(pp, REFRESH); +# endif MONITOR +} + +# ifdef OOZE +/* + * fire_slime: + * Fire a slime shot in the given direction + */ +fire_slime(pp, req) +register PLAYER *pp; +register int req; +{ + if (pp == NULL) + return; + if (pp->p_ammo < req) { + message(pp, "Not enough charges."); + return; + } + if (pp->p_ncshot > MAXNCSHOT) + return; + if (pp->p_ncshot++ == MAXNCSHOT) { + cgoto(pp, STAT_GUN_ROW, STAT_VALUE_COL); + outstr(pp, " ", 3); + } + pp->p_ammo -= req; + (void) sprintf(Buf, "%3d", pp->p_ammo); + cgoto(pp, STAT_AMMO_ROW, STAT_VALUE_COL); + outstr(pp, Buf, 3); + + add_shot(SLIME, pp->p_y, pp->p_x, pp->p_face, req, pp, FALSE, + pp->p_face); + + /* + * Show the object to everyone + */ + showexpl(pp->p_y, pp->p_x, SLIME); + for (pp = Player; pp < End_player; pp++) + sendcom(pp, REFRESH); +# ifdef MONITOR + for (pp = Monitor; pp < End_monitor; pp++) + sendcom(pp, REFRESH); +# endif MONITOR +} +# endif OOZE + +/* + * create_shot: + * Create a shot with the given properties + */ +add_shot(type, y, x, face, charge, owner, expl, over) +int type; +int y, x; +char face; +int charge; +PLAYER *owner; +int expl; +char over; +{ + register BULLET *bp; + +# ifdef CONSTANT_MOVE + /* + * if there are no bullets in flight, set up the alarm + */ + + if (Bullets == NULL) + bul_alarm(1); +# endif CONSTANT_MOVE + + bp = create_shot(type, y, x, face, charge, owner, + (owner == NULL) ? NULL : owner->p_ident, expl, over); + bp->b_next = Bullets; + Bullets = bp; +} + +BULLET * +create_shot(type, y, x, face, charge, owner, score, expl, over) +int type; +int y, x; +char face; +int charge; +PLAYER *owner; +IDENT *score; +int expl; +char over; +{ + register BULLET *bp; + + bp = (BULLET *) malloc(sizeof (BULLET)); /* NOSTRICT */ + if (bp == NULL) { + if (owner != NULL) + message(owner, "Out of memory"); + return NULL; + } + + bp->b_face = face; + bp->b_x = x; + bp->b_y = y; + bp->b_charge = charge; + bp->b_owner = owner; + bp->b_score = score; + bp->b_type = type; + bp->b_expl = expl; + bp->b_over = over; + bp->b_next = NULL; + + return bp; +} + +/* + * cloak: + * Turn on or increase length of a cloak + */ +cloak(pp) +register PLAYER *pp; +{ + if (pp->p_ammo <= 0) { + message(pp, "No more charges"); + return; + } + (void) sprintf(Buf, "%3d", --pp->p_ammo); + cgoto(pp, STAT_AMMO_ROW, STAT_VALUE_COL); + outstr(pp, Buf, 3); + + pp->p_cloak += CLOAKLEN; + cgoto(pp, STAT_CLOAK_ROW, STAT_VALUE_COL); + outstr(pp, " on", 3); + + if (pp->p_scan >= 0) { + pp->p_scan = -1; + cgoto(pp, STAT_SCAN_ROW, STAT_VALUE_COL); + outstr(pp, " ", 3); + } + + showstat(pp); +} + +/* + * scan: + * Turn on or increase length of a scan + */ +scan(pp) +register PLAYER *pp; +{ + if (pp->p_ammo <= 0) { + message(pp, "No more charges"); + return; + } + (void) sprintf(Buf, "%3d", --pp->p_ammo); + cgoto(pp, STAT_AMMO_ROW, STAT_VALUE_COL); + outstr(pp, Buf, 3); + + pp->p_scan += SCANLEN; + cgoto(pp, STAT_SCAN_ROW, STAT_VALUE_COL); + outstr(pp, " on", 3); + + if (pp->p_cloak >= 0) { + pp->p_cloak = -1; + cgoto(pp, STAT_CLOAK_ROW, STAT_VALUE_COL); + outstr(pp, " ", 3); + } + + showstat(pp); +} + +/* + * pickup: + * check whether the object blew up or whether he picked it up + */ +pickup(pp, y, x, prob, obj) +register PLAYER *pp; +register int y, x; +int prob; +int obj; +{ + register int req; + + switch (obj) { + case MINE: + req = BULREQ; + break; + case GMINE: + req = GRENREQ; + break; + default: + abort(); + } + if (rand_num(100) < prob) + add_shot(obj, y, x, LEFTS, req, (PLAYER *) NULL, + TRUE, pp->p_face); + else { + pp->p_ammo += req; + (void) sprintf(Buf, "%3d", pp->p_ammo); + cgoto(pp, STAT_AMMO_ROW, STAT_VALUE_COL); + outstr(pp, Buf, 3); + } +} diff --git a/src/games/hunt/expl.c b/src/games/hunt/expl.c new file mode 100644 index 0000000..0f579ee --- /dev/null +++ b/src/games/hunt/expl.c @@ -0,0 +1,198 @@ +/* + * Hunt + * Copyright (c) 1985 Conrad C. Huang, Gregory S. Couch, Kenneth C.R.C. Arnold + * San Francisco, California + * + * Copyright (c) 1985 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +# include "hunt.h" + +/* + * showexpl: + * Show the explosions as they currently are + */ +showexpl(y, x, type) +register int y, x; +char type; +{ + register PLAYER *pp; + register EXPL *ep; + + if (y < 0 || y >= HEIGHT) + return; + if (x < 0 || x >= WIDTH) + return; + ep = (EXPL *) malloc(sizeof (EXPL)); /* NOSTRICT */ + ep->e_y = y; + ep->e_x = x; + ep->e_char = type; + ep->e_next = Expl[0]; + Expl[0] = ep; + for (pp = Player; pp < End_player; pp++) { + if (pp->p_maze[y][x] == type) + continue; + pp->p_maze[y][x] = type; + cgoto(pp, y, x); + outch(pp, type); + } +# ifdef MONITOR + for (pp = Monitor; pp < End_monitor; pp++) { + if (pp->p_maze[y][x] == type) + continue; + pp->p_maze[y][x] = type; + cgoto(pp, y, x); + outch(pp, type); + } +# endif MONITOR + switch (Maze[y][x]) { + case WALL1: + case WALL2: + case WALL3: +# ifdef RANDOM + case DOOR: +# endif RANDOM +# ifdef REFLECT + case WALL4: + case WALL5: +# endif REFLECT + if (y >= UBOUND && y < DBOUND && x >= LBOUND && x < RBOUND) + remove_wall(y, x); + break; + } +} + +/* + * rollexpl: + * Roll the explosions over, so the next one in the list is at the + * top + */ +rollexpl() +{ + register EXPL *ep; + register PLAYER *pp; + register int y, x; + register char c; + register EXPL *nextep; + + for (ep = Expl[EXPLEN - 1]; ep != NULL; ep = nextep) { + nextep = ep->e_next; + y = ep->e_y; + x = ep->e_x; + if (y < UBOUND || y >= DBOUND || x < LBOUND || x >= RBOUND) + c = Maze[y][x]; + else + c = SPACE; + for (pp = Player; pp < End_player; pp++) + if (pp->p_maze[y][x] == ep->e_char) { + pp->p_maze[y][x] = c; + cgoto(pp, y, x); + outch(pp, c); + } +# ifdef MONITOR + for (pp = Monitor; pp < End_monitor; pp++) + check(pp, y, x); +# endif MONITOR + free((char *) ep); + } + for (x = EXPLEN - 1; x > 0; x--) + Expl[x] = Expl[x - 1]; + Expl[0] = NULL; +} + +/* There's about 700 walls in the initial maze. So we pick a number + * that keeps the maze relatively full. */ +# define MAXREMOVE 40 + +static REGEN removed[MAXREMOVE]; +static REGEN *rem_index = removed; + +/* + * remove_wall - add a location where the wall was blown away. + * if there is no space left over, put the a wall at + * the location currently pointed at. + */ +remove_wall(y, x) +int y, x; +{ + register REGEN *r; +# if defined(MONITOR) || defined(FLY) + register PLAYER *pp; +# endif MONITOR || FLY +# ifdef FLY + register char save_char; +# endif FLY + + r = rem_index; + while (r->r_y != 0) { +# ifdef FLY + switch (Maze[r->r_y][r->r_x]) { + case SPACE: + case LEFTS: + case RIGHT: + case ABOVE: + case BELOW: + case FLYER: + save_char = Maze[r->r_y][r->r_x]; + goto found; + } +# else FLY + if (Maze[r->r_y][r->r_x] == SPACE) + break; +# endif FLY + if (++r >= &removed[MAXREMOVE]) + r = removed; + } + +found: + if (r->r_y != 0) { + /* Slot being used, put back this wall */ +# ifdef FLY + if (save_char == SPACE) + Maze[r->r_y][r->r_x] = Orig_maze[r->r_y][r->r_x]; + else { + pp = play_at(r->r_y, r->r_x); + if (pp->p_flying >= 0) + pp->p_flying += rand_num(10); + else { + pp->p_flying = rand_num(20); + pp->p_flyx = 2 * rand_num(6) - 5; + pp->p_flyy = 2 * rand_num(6) - 5; + } + pp->p_over = Orig_maze[r->r_y][r->r_x]; + pp->p_face = FLYER; + Maze[r->r_y][r->r_x] = FLYER; + showexpl(r->r_y, r->r_x, FLYER); + } +# else FLY + Maze[r->r_y][r->r_x] = Orig_maze[r->r_y][r->r_x]; +# endif FLY +# ifdef RANDOM + if (rand_num(100) == 0) + Maze[r->r_y][r->r_x] = DOOR; +# endif RANDOM +# ifdef REFLECT + if (rand_num(100) == 0) /* one percent of the time */ + Maze[r->r_y][r->r_x] = WALL4; +# endif REFLECT +# ifdef MONITOR + for (pp = Monitor; pp < End_monitor; pp++) + check(pp, r->r_y, r->r_x); +# endif MONITOR + } + + r->r_y = y; + r->r_x = x; + if (++r >= &removed[MAXREMOVE]) + rem_index = removed; + else + rem_index = r; + + Maze[y][x] = SPACE; +# ifdef MONITOR + for (pp = Monitor; pp < End_monitor; pp++) + check(pp, y, x); +# endif MONITOR +} diff --git a/src/games/hunt/extern.c b/src/games/hunt/extern.c new file mode 100644 index 0000000..ae525e0 --- /dev/null +++ b/src/games/hunt/extern.c @@ -0,0 +1,45 @@ +/* + * Hunt + * Copyright (c) 1985 Conrad C. Huang, Gregory S. Couch, Kenneth C.R.C. Arnold + * San Francisco, California + * + * Copyright (c) 1985 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +# include "hunt.h" + +# ifdef MONITOR +FLAG Am_monitor = FALSE; /* current process is a monitor */ +# endif MONITOR + +char Buf[BUFSIZ]; /* general scribbling buffer */ +char Maze[HEIGHT][WIDTH2]; /* the maze */ +char Orig_maze[HEIGHT][WIDTH2]; /* the original maze */ + +long Fds_mask; /* mask for the file descriptors */ +int Have_inp; /* which file descriptors have input */ +int Nplayer = 0; /* number of players */ +int Num_fds; /* number of maximum file descriptor */ +int Socket; /* main socket */ +long Sock_mask; /* select mask for main socket */ +int See_over[NASCII]; /* lookup table for determining whether + * character represents "transparent" + * item */ + +BULLET *Bullets = NULL; /* linked list of bullets */ + +EXPL *Expl[EXPLEN]; /* explosion lists */ + +PLAYER Player[MAXPL]; /* all the players */ +PLAYER *End_player = Player; /* last active player slot */ +IDENT *Scores; /* score cache */ +# ifdef MONITOR +PLAYER Monitor[MAXMON]; /* all the monitors */ +PLAYER *End_monitor = Monitor; /* last active monitor slot */ +# endif MONITOR + +# ifdef VOLCANO +int volcano = 0; /* Explosion size */ +# endif VOLCANO diff --git a/src/games/hunt/hunt.6 b/src/games/hunt/hunt.6 new file mode 100644 index 0000000..1a0c7f5 --- /dev/null +++ b/src/games/hunt/hunt.6 @@ -0,0 +1,266 @@ +.\" Hunt +.\" Copyright (c) 1985 Conrad C. Huang, Gregory S. Couch, Kenneth C.R.C. Arnold +.\" San Francisco, California +.\" +.\" Copyright (c) 1985 Regents of the University of California. +.\" All rights reserved. The Berkeley software License Agreement +.\" specifies the terms and conditions for redistribution. +.\" +.\" @(#)hunt.6 6.3 (Berkeley) 1/9/86 +.\" +.TH HUNT 6 "January 9, 1986" +.UC 6 +.SH NAME +hunt \- a multi-player multi-terminal game +.SH SYNOPSIS +\fB/usr/games/hunt\fP [-q] [\fB-m\fP] [hostname] [\fB-l\fP name] +.SH DESCRIPTION +The object of the game +.I hunt +is to kill off the other players. +There are no rooms, no treasures, and no monsters. +Instead, you wander around a maze, find grenades, trip mines, and shoot down +walls and players. +The more players you kill before you die, the better your score is. +If the +.B \-m +flag is given, +you enter the game as a monitor +(you can see the action but you cannot play). +.PP +.I Hunt +normally looks for an active game on the local network; if none is found, +it starts one up on the local host. One may specify the location of the +game by giving the \fIhostname\fP argument. The player name may be specified +on the command line by using the \fB-l\fP option. This command syntax was +chosen for \fIrlogin/rsh\fP compatibility. +If the +.B \-q +flag is given, +.I hunt +queries the network and reports if an active game were found. +This is useful for .login scripts. +.PP +.I Hunt +only works on crt (vdt) terminals with at least 24 lines, 80 columns, and +cursor addressing. +The screen is divided in to 3 areas. +On the right hand side is the status area. +It shows you how much damage you've sustained, +how many charges you have left, +who's in the game, +who's scanning (the asterisk in front of the name), +who's cloaked (the plus sign in front of the name), +and other players' scores. +Most of the rest of the screen is taken up by your map of the maze, +except for the 24th line, +which is used for longer messages that don't fit in the status area. +.PP +.I Hunt +uses the same keys to move as +.I vi +does, +.IR i.e. , +.BR h , j , k , +and +.B l +for left, down, up, right respectively. +To change which direction you're facing in the maze, +use the upper case version of the movement key (\c +.IR i.e. , +HJKL). +.TP +Other commands are: +.sp +.nf +.ta +.ta \w'>\|<\|^\|v\ \ 'u +f \- Fire (in the direction you're facing) (Takes 1 charge) +g \- Throw grenade (in the direction you're facing) (Takes 9 charges) +F \- Throw satchel charge (Takes 25 charges) +G \- Throw bomb (Takes 49 charges) +o \- Throw small slime bomb (Takes 15 charges) +O \- Throw big slime bomb (Takes 30 charges) +s \- Scan (show where other players are) (Takes 1 charge) +c \- Cloak (hide from scanners) (Takes 1 charge) + +^L \- Redraw screen +q \- Quit +.fi +.TP +Knowing what the symbols on the screen often helps: +.sp +.nf +.ta +.ta \w'>\|<\|^\|v\ \ 'u +\-\||\|+ \- walls +/\|\\ \- diagonal (deflecting) walls +# \- doors (dispersion walls) +; \- small mine +g \- large mine +: \- shot +o \- grenade +O \- satchel charge +@ \- bomb +s \- small slime bomb +$ \- big slime bomb +>\|<\|^\|v \- you facing right, left, up, or down +}\|{\|i\|! \- other players facing right, left, up, or down +\(** \- explosion +.ne 3 +.cs R 24 +.cs I 24 +\fR\\|/\fP +.cs R +\fI\-\(**\-\fP \- grenade and large mine explosion +.fl +.cs R 24 +\fR/|\\\fP +.cs R +.cs I +.fi +.TP +Satchel and bomb explosions are larger than grenades (5x5, 7x7, +and 3x3 respectively). +.LP +Other helpful hints: +.sp +.ie n .ds b [] +.el .ds b \(bu +.ta +.ta \w'\*b\ \|'u +.nr In \n(.i +.de MP +.br +.in \n(Inu+\w'\*b\ \|'u +.ti \n(Inu +\*b \c +.. +.MP +You can only fire in the direction you are facing. +.MP +You can only fire three shots in a row, then the gun must cool. +.MP +A shot only affects the square it hits. +.MP +Shots and grenades move 5 times faster than you do. +.MP +To stab someone, +you must face that player and move at them. +.MP +Stabbing does 2 points worth of damage and shooting does 5 points. +.MP +Slime does 5 points of damage each time it hits. +.MP +You start with 15 charges and get 5 more for every new player. +.MP +A grenade affects the nine squares centered about the square it hits. +.MP +A satchel affects the twenty-five squares centered about the square it hits. +.MP +A bomb affects the forty-nine squares centered about the square it hits. +.MP +Slime affects all squares it oozes over (15 or 30 respectively). +.MP +One small mine and one large mine is placed in the maze for every new player. +A mine has a 5% probability of tripping when you walk directly at it; +50% when going sideways on to it; +95% when backing up on to it. +Tripping a mine costs you 5 points or 10 points respectively. +Defusing a mine is worth 1 charge or 9 charges respectively. +.MP +You cannot see behind you. +.MP +Scanning lasts for (20 times the number of players) turns. +Scanning takes 1 ammo charge, +so don't waste all your charges scanning. +.MP +Cloaking lasts for 20 turns. +.MP +Whenever you kill someone, +you get 2 more damage capacity points and 2 damage points taken away. +.MP +Maximum typeahead is 5 characters. +.MP +A shot destroys normal (\c +.IR i.e., +non-diagonal, non-door) walls. +.MP +Diagonal walls deflect shots and change orientation. +.MP +Doors disperse shots in random directions (up, down, left, right). +.MP +Diagonal walls and doors cannot be destroyed by direct shots but may +be destroyed by an adjacent grenade explosion. +.MP +Slime goes around walls, not through them. +.MP +Walls regenerate, reappearing in the order they were destroyed. +One percent of the regenerated walls will be diagonal walls or doors. +When a wall is generated directly beneath a player, he is thrown in +a random direction for a random period of time. When he lands, he +sustains damage (up to 20 percent of the amount of damage he had before +impact); that is, the less damage he had, the more nimble he is and +therefore less likely to hurt himself on landing. +\".MP +\"There is a volcano close to the center of the maze which goes off +\"close to every 100 deaths. +.MP +The environment variable +.B HUNT +is checked to get the player name. +If you don't have this variable set, +.I hunt +will ask you what name you want to play under. +If it is set, +you may also set up a single character keyboard map, but then you have to +enumerate the options: +.br +.ti +1i +\fIe.g.\fP setenv HUNT ``name=Sneaky,mapkey=zoFfGg1f2g3F4G'' +.br +sets the player name to Sneaky, +and the maps \fBz\fP to \fBo\fP, \fBF\fP to \fBf\fP, \fBG\fP to \fBg\fP, +\fB1\fP to \fBf\fP, +\fB2\fP to \fBg\fP, \fB3\fP to \fBF\fP, and \fB4\fP to \fBG\fP. +The \fImapkey\fP option must be last. +.MP +It's a boring game if you're the only one playing. +.PP +Your score is the ratio of number of kills to number +of times you entered the game and is only kept for the duration +of a single session of \fIhunt\fP. +.PP +.I Hunt +normally drives up the load average to be about +(number_of_players + 0.5) greater than it would be without a +.I hunt +game executing. A limit of three players per host and nine players +total is enforced by \fIhunt\fP. +.SH FILES +.nf +.ta +.ta \w'/usr/games/lib/hunt.driver\ \ \ 'u +/usr/games/lib/hunt.driver game coordinator +.DT +.fi +.SH AUTHORS +Conrad Huang, +Ken Arnold, +and Greg Couch; +University of California, San Francisco, Computer Graphics Lab +.SH ACKNOWLEDGEMENTS +We thank Don Kneller, +John Thomason, Eric Pettersen, +and Scott Weiner for providing +endless hours of play-testing to improve the character of the game. +We hope their significant others will forgive them; +we certainly don't. +.SH BUGS +To keep up the pace, not everything is as realistic as possible. +.PP +There were some bugs in early releases of 4.2 BSD that +.I hunt +helped discover; +.I hunt +will crash your system if those bugs haven't been fixed. diff --git a/src/games/hunt/hunt.c b/src/games/hunt/hunt.c new file mode 100644 index 0000000..d8e050b --- /dev/null +++ b/src/games/hunt/hunt.c @@ -0,0 +1,717 @@ +/* + * Hunt + * Copyright (c) 1985 Conrad C. Huang, Gregory S. Couch, Kenneth C.R.C. Arnold + * San Francisco, California + * + * Copyright (c) 1985 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +# include +# include +# include "hunt.h" +# include +# include +# include + +FLAG Last_player = FALSE; +# ifdef MONITOR +FLAG Am_monitor = FALSE; +# endif MONITOR +FLAG Query_driver = FALSE; + +char Buf[BUFSIZ]; + +int Master_pid; +int Socket; +# ifdef INTERNET +char *Sock_host; +# endif INTERNET + +SOCKET Daemon; +# ifdef INTERNET +# define DAEMON_SIZE (sizeof Daemon) +# else INTERNET +# define DAEMON_SIZE (sizeof Daemon - 1) +# endif INTERNET + +char map_key[256]; /* what to map keys to */ + +static char name[NAMELEN]; + +extern int cur_row, cur_col, _putchar(); +extern char *tgoto(); + +/* + * main: + * Main program for local process + */ +main(ac, av) +int ac; +char **av; +{ + char *term; + extern int errno; + extern int Otto_mode; + int dumpit(), intr(), sigterm(), sigemt(), tstp(); + + for (ac--, av++; ac > 0 && av[0][0] == '-'; ac--, av++) { + switch (av[0][1]) { + + case 'l': /* rsh compatibility */ + case 'n': + if (ac <= 1) + goto usage; + ac--, av++; + (void) strcpy(name, av[0]); + break; + case 'o': +# ifndef OTTO + fputs("The -o flag is reserved for future use.\n", + stderr); + goto usage; +# else OTTO + Otto_mode = TRUE; + break; +# endif OTTO +# ifdef MONITOR + case 'm': + Am_monitor = TRUE; + break; +# endif MONITOR +# ifdef INTERNET + case 'q': /* query whether hunt is running */ + Query_driver = TRUE; + break; + case 'h': + if (ac <= 1) + goto usage; + ac--, av++; + Sock_host = av[0]; + break; +# endif INTERNET + default: + usage: +# ifdef INTERNET +# ifdef MONITOR +# define USAGE "usage: hunt [-q] [-n name] [-h host] [-m]\n" +# else MONITOR +# define USAGE "usage: hunt [-q] [-n name] [-h host]\n" +# endif MONITOR +# else INTERNET +# ifdef MONITOR +# define USAGE "usage: hunt [-n name] [-m]\n" +# else MONITOR +# define USAGE "usage: hunt [-n name]\n" +# endif MONITOR +# endif INTERNET + fputs(USAGE, stderr); +# undef USAGE + exit(1); + } + } +# ifdef INTERNET + if (ac > 1) + goto usage; + else if (ac > 0) + Sock_host = av[0]; +# else INTERNET + if (ac > 0) + goto usage; +# endif INTERNET + +# ifdef INTERNET + if (Query_driver) { + find_driver(FALSE); + if (Daemon.sin_port != 0) { + struct hostent *hp; + + hp = gethostbyaddr(&Daemon.sin_addr, + sizeof Daemon.sin_addr, AF_INET); + fprintf(stderr, "HUNT!! found on %s\n", hp != NULL + ? hp->h_name : inet_ntoa(Daemon.sin_addr)); + } + exit(Daemon.sin_port == 0); + } +# endif INTERNET +# ifdef OTTO + if (Otto_mode) + (void) strcpy(name, "otto"); + else +# endif OTTO + env_init(); + + (void) fflush(stdout); + if (!isatty(0) || (term = getenv("TERM")) == NULL) { + fprintf(stderr, "no terminal type\n"); + exit(1); + } + _tty_ch = 0; + gettmode(); + setterm(term); + noecho(); + cbreak(); + _puts(TI); + _puts(VS); + clear_screen(); + (void) signal(SIGINT, intr); + (void) signal(SIGTERM, sigterm); + (void) signal(SIGEMT, sigemt); + (void) signal(SIGQUIT, dumpit); + (void) signal(SIGPIPE, SIG_IGN); + (void) signal(SIGTSTP, tstp); + + do { +# ifdef INTERNET + find_driver(TRUE); + + do { + int msg; + +# ifndef OLDIPC + Socket = socket(SOCK_FAMILY, SOCK_STREAM, 0); +# else OLDIPC + Socket = socket(SOCK_STREAM, 0, 0, 0); +# endif OLDIPC + if (Socket < 0) { + perror("socket"); + exit(1); + } +# ifndef OLDIPC + msg = 1; + if (setsockopt(Socket, SOL_SOCKET, SO_USELOOPBACK, + &msg, sizeof msg) < 0) + perror("setsockopt loopback"); +# endif OLDIPC + errno = 0; + if (connect(Socket, (struct sockaddr *) &Daemon, + DAEMON_SIZE) < 0) { + if (errno != ECONNREFUSED) { + perror("connect"); + leave(1, "connect"); + } + } + else + break; + sleep(1); + } while (close(Socket) == 0); +# else INTERNET + /* + * set up a socket + */ + + if ((Socket = socket(SOCK_FAMILY, SOCK_STREAM, 0)) < 0) { + perror("socket"); + exit(1); + } + + /* + * attempt to connect the socket to a name; if it fails that + * usually means that the driver isn't running, so we start + * up the driver. + */ + + Daemon.sun_family = SOCK_FAMILY; + (void) strcpy(Daemon.sun_path, Sock_name); + if (connect(Socket, &Daemon, DAEMON_SIZE) < 0) { + if (errno != ENOENT) { + perror("connect"); + leave(1, "connect2"); + } + start_driver(); + + do { + (void) close(Socket); + if ((Socket = socket(SOCK_FAMILY, SOCK_STREAM, 0)) < 0) { + perror("socket"); + exit(1); + } + sleep(2); + } while (connect(Socket, &Daemon, DAEMON_SIZE) < 0); + } +# endif INTERNET + + do_connect(name); + playit(); + } while (!quit()); + leave(0, NULL); + /* NOTREACHED */ +} + +# ifdef INTERNET +# ifdef BROADCAST +broadcast_vec(s, vector) + int s; /* socket */ + struct sockaddr **vector; +{ + char if_buf[BUFSIZ]; + struct ifconf ifc; + struct ifreq *ifr; + int n; + int vec_cnt; + + *vector = NULL; + ifc.ifc_len = sizeof if_buf; + ifc.ifc_buf = if_buf; + if (ioctl(s, SIOCGIFCONF, (char *) &ifc) < 0) + return 0; + vec_cnt = 0; + n = ifc.ifc_len / sizeof (struct ifreq); + *vector = (struct sockaddr *) malloc(n * sizeof (struct sockaddr)); + for (ifr = ifc.ifc_req; n > 0; n--, ifr++) + if (ioctl(s, SIOCGIFBRDADDR, ifr) >= 0) + bcopy(&ifr->ifr_addr, &(*vector)[vec_cnt++], + sizeof (struct sockaddr)); + return vec_cnt; +} +# endif BROADCAST + +find_driver(do_startup) +FLAG do_startup; +{ + int msg; + static SOCKET test; + int test_socket; + int namelen; + char local_name[80]; + static initial = TRUE; + static struct in_addr local_address; + register struct hostent *hp; + int (*oldsigalrm)(), sigalrm(); + extern int errno; +# ifdef BROADCAST + static int brdc; + static SOCKET *brdv; + int i; +# endif BROADCAST + + if (Sock_host != NULL) { + if (!initial) + return; /* Daemon address already valid */ + initial = FALSE; + if ((hp = gethostbyname(Sock_host)) == NULL) { + leave(1, "Unknown host"); + /* NOTREACHED */ + } + Daemon.sin_family = SOCK_FAMILY; + Daemon.sin_port = htons(Sock_port); + Daemon.sin_addr = *((struct in_addr *) hp->h_addr); + if (!Query_driver) + return; + } + + + if (initial) { /* do one time initialization */ +# ifndef BROADCAST + sethostent(1); /* don't bother to close host file */ +# endif BROADCAST + if (gethostname(local_name, sizeof local_name) < 0) { + leave(1, "Sorry, I have no name."); + /* NOTREACHED */ + } + if ((hp = gethostbyname(local_name)) == NULL) { + leave(1, "Can't find myself."); + /* NOTREACHED */ + } + local_address = * ((struct in_addr *) hp->h_addr); + + test.sin_family = SOCK_FAMILY; + test.sin_addr = local_address; + test.sin_port = htons(Test_port); + } + +# ifndef OLDIPC + test_socket = socket(SOCK_FAMILY, SOCK_DGRAM, 0); +# else OLDIPC + test_socket = socket(SOCK_DGRAM, 0, 0, 0); +# endif OLCIPC + if (test_socket < 0) { + perror("socket"); + leave(1, "socket system call failed"); + /* NOTREACHED */ + } + + msg = 1; + if (Query_driver && Sock_host != NULL) { + test.sin_family = SOCK_FAMILY; + test.sin_addr = Daemon.sin_addr; + test.sin_port = htons(Test_port); +# ifndef OLDIPC + (void) sendto(test_socket, (char *) &msg, sizeof msg, 0, + (struct sockaddr *) &test, DAEMON_SIZE); +# else OLDIPC + (void) send(test_socket, (struct sockaddr *) &test, + (char *) &msg, sizeof msg); +# endif OLDIPC + goto get_response; + } + + if (!initial) { + /* favor host of previous session by broadcasting to it first */ + test.sin_addr = Daemon.sin_addr; + test.sin_port = htons(Test_port); + (void) sendto(test_socket, (char *) &msg, sizeof msg, 0, + (struct sockaddr *) &test, DAEMON_SIZE); + } + + +# ifdef BROADCAST + if (initial) + brdc = broadcast_vec(test_socket, &brdv); + + if (brdc <= 0) { + Daemon.sin_family = SOCK_FAMILY; + Daemon.sin_addr = local_address; + Daemon.sin_port = htons(Sock_port); + initial = FALSE; + return; + } + + if (setsockopt(test_socket, SOL_SOCKET, SO_BROADCAST, + (int) &msg, sizeof msg) < 0) { + perror("setsockopt broadcast"); + leave(1, "setsockopt broadcast"); + /* NOTREACHED */ + } + + /* send broadcast packets on all interfaces */ + for (i = 0; i < brdc; i++) { + bcopy(&brdv[i], &test, sizeof (SOCKET)); + test.sin_port = htons(Test_port); + if (sendto(test_socket, (char *) &msg, sizeof msg, 0, + (struct sockaddr *) &test, DAEMON_SIZE) < 0) { + perror("sendto"); + leave(1, "sendto"); + /* NOTREACHED */ + } + } +# else BROADCAST + /* loop thru all hosts on local net and send msg to them. */ + sethostent(0); /* rewind host file */ + while (hp = gethostent()) { + if (inet_netof(test.sin_addr) + == inet_netof(* ((struct in_addr *) hp->h_addr))) { + test.sin_addr = * ((struct in_addr *) hp->h_addr); +# ifndef OLDIPC + (void) sendto(test_socket, (char *) &msg, sizeof msg, 0, + (struct sockaddr *) &test, DAEMON_SIZE); +# else OLDIPC + (void) send(test_socket, (struct sockaddr *) &test, + (char *) &msg, sizeof msg); +# endif OLDIPC + } + } +# endif BROADCAST + +get_response: + namelen = DAEMON_SIZE; + oldsigalrm = signal(SIGALRM, sigalrm); + errno = 0; + (void) alarm(1); +# ifndef OLDIPC + if (recvfrom(test_socket, (char *) &msg, sizeof msg, 0, + (struct sockaddr *) &Daemon, &namelen) < 0) +# else OLDIPC + if (receive(test_socket, (struct sockaddr *) &Daemon, &msg, + sizeof msg) < 0) +# endif OLDIPC + { + if (errno != EINTR) { + perror("recvfrom"); + leave(1, "recvfrom"); + /* NOTREACHED */ + } + (void) alarm(0); + (void) signal(SIGALRM, oldsigalrm); + Daemon.sin_family = SOCK_FAMILY; + Daemon.sin_port = htons(Sock_port); + Daemon.sin_addr = local_address; + if (!do_startup) + Daemon.sin_port = 0; + else + start_driver(); + } + else { + (void) alarm(0); + (void) signal(SIGALRM, oldsigalrm); + Daemon.sin_port = htons(Sock_port); + } + (void) close(test_socket); + initial = FALSE; +} +# endif INTERNET + +start_driver() +{ + register int procid; + +# ifdef MONITOR + if (Am_monitor) { + leave(1, "No one playing."); + /* NOTREACHED */ + } +# endif MONITOR + +# ifdef INTERNET + if (Sock_host != NULL) { + sleep(3); + return 0; + } +# endif INTERNET + + mvcur(cur_row, cur_col, 23, 0); + cur_row = 23; + cur_col = 0; + put_str("Starting..."); + fflush(stdout); + procid = vfork(); + if (procid == -1) { + perror("fork"); + leave(1, "fork failed."); + } + if (procid == 0) { + (void) signal(SIGINT, SIG_IGN); + (void) close(Socket); + execl(Driver, "HUNT", NULL); + /* only get here if exec failed */ + kill(getppid(), SIGEMT); /* tell mom */ + _exit(1); + } + mvcur(cur_row, cur_col, 23, 0); + cur_row = 23; + cur_col = 0; + put_str("Connecting..."); + fflush(stdout); + return 0; +} + +/* + * bad_con: + * We had a bad connection. For the moment we assume that this + * means the game is full. + */ +bad_con() +{ + leave(1, "The game is full. Sorry."); + /* NOTREACHED */ +} + +/* + * dumpit: + * Handle a core dump signal by not dumping core, just leaving, + * so we end up with a core dump from the driver + */ +dumpit() +{ + (void) kill(Master_pid, SIGQUIT); + (void) chdir("coredump"); + abort(); +} + +/* + * sigterm: + * Handle a terminate signal + */ +sigterm() +{ + leave(0, NULL); + /* NOTREACHED */ +} + + +/* + * sigemt: + * Handle a emt signal - shouldn't happen on vaxes(?) + */ +sigemt() +{ + leave(1, "Unable to start driver. Try again."); + /* NOTREACHED */ +} + +# ifdef INTERNET +/* + * sigalrm: + * Handle an alarm signal + */ +sigalrm() +{ + return; +} +# endif INTERNET + +/* + * rmnl: + * Remove a '\n' at the end of a string if there is one + */ +rmnl(s) +char *s; +{ + register char *cp; + char *rindex(); + + cp = rindex(s, '\n'); + if (cp != NULL) + *cp = '\0'; +} + +/* + * intr: + * Handle a interrupt signal + */ +intr() +{ + register int ch; + register int explained; + register int y, x; + + (void) signal(SIGINT, SIG_IGN); + y = cur_row; + x = cur_col; + mvcur(cur_row, cur_col, 23, 0); + cur_row = 23; + cur_col = 0; + put_str("Really quit? "); + clear_eol(); + fflush(stdout); + explained = FALSE; + for (;;) { + ch = getchar(); + if (isupper(ch)) + ch = tolower(ch); + if (ch == 'y') { + (void) write(Socket, "q", 1); + (void) close(Socket); + leave(0, NULL); + } + else if (ch == 'n') { + (void) signal(SIGINT, intr); + mvcur(cur_row, cur_col, y, x); + cur_row = y; + cur_col = x; + fflush(stdout); + return; + } + if (!explained) { + put_str("(Y or N) "); + fflush(stdout); + explained = TRUE; + } + (void) putchar(CTRL(G)); + (void) fflush(stdout); + } +} + +/* + * leave: + * Leave the game somewhat gracefully, restoring all current + * tty stats. + */ +leave(eval, mesg) +int eval; +char *mesg; +{ + mvcur(cur_row, cur_col, 23, 0); + if (mesg == NULL) + clear_eol(); + else { + put_str(mesg); + clear_eol(); + putchar('\n'); + fflush(stdout); /* flush in case VE changes pages */ + } + resetty(); + _puts(VE); + _puts(TE); + exit(eval); +} + +/* + * tstp: + * Handle stop and start signals + */ +tstp() +{ + static struct sgttyb tty; + int y, x; + + tty = _tty; + y = cur_row; + x = cur_col; + mvcur(cur_row, cur_col, 23, 0); + cur_row = 23; + cur_col = 0; + _puts(VE); + _puts(TE); + (void) fflush(stdout); + resetty(); + (void) kill(getpid(), SIGSTOP); + (void) signal(SIGTSTP, tstp); + _tty = tty; + (void) stty(_tty_ch, &_tty); + _puts(TI); + _puts(VS); + cur_row = y; + cur_col = x; + _puts(tgoto(CM, cur_row, cur_col)); + redraw_screen(); + fflush(stdout); +} + +env_init() +{ + register int i; + char *envp, *envname, *s, *index(); + + for (i = 0; i < 256; i++) + map_key[i] = (char) i; + + envname = NULL; + if ((envp = getenv("HUNT")) != NULL) { + while ((s = index(envp, '=')) != NULL) { + if (strncmp(envp, "name=", s - envp + 1) == 0) { + envname = s + 1; + if ((s = index(envp, ',')) == NULL) { + *envp = '\0'; + break; + } + *s = '\0'; + envp = s + 1; + } /* must be last option */ + else if (strncmp(envp, "mapkey=", s - envp + 1) == 0) { + for (s = s + 1; *s != '\0'; s += 2) { + map_key[(unsigned int) *s] = *(s + 1); + if (*(s + 1) == '\0') { + break; + } + } + *envp = '\0'; + break; + } else { + *s = '\0'; + printf("unknown option %s\n", envp); + if ((s = index(envp, ',')) == NULL) { + *envp = '\0'; + break; + } + envp = s + 1; + } + } + if (*envp != '\0') + if (envname == NULL) + envname = envp; + else + printf("unknown option %s\n", envp); + } + if (envname != NULL) { + (void) strcpy(name, envname); + printf("Entering as '%s'\n", envname); + } + else if (name[0] == '\0') { + printf("Enter your code name: "); + if (fgets(name, sizeof name, stdin) == NULL) + exit(1); + } + rmnl(name); +} diff --git a/src/games/hunt/hunt.h b/src/games/hunt/hunt.h new file mode 100644 index 0000000..aa78ea8 --- /dev/null +++ b/src/games/hunt/hunt.h @@ -0,0 +1,307 @@ +/* + * Hunt + * Copyright (c) 1985 Conrad C. Huang, Gregory S. Couch, Kenneth C.R.C. Arnold + * San Francisco, California + * + * Copyright (c) 1985 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +# include +# ifndef OLDIPC +# include +# include +# include +# else OLDIPC +# include +# include +# include +# endif OLDIPC +# include +# ifdef INTERNET +# include +# include +# ifndef OLDIPC +# include +# endif !OLDIPC +# ifdef BROADCAST +# include +# endif BROADCAST +# else INTERNET +# include +# endif INTERNET + +# ifdef INTERNET +# define SOCK_FAMILY AF_INET +# else INTERNET +# define SOCK_FAMILY AF_UNIX +# define AF_UNIX_HACK /* 4.2 hack; leaves files around */ +# endif INTERNET + +# define ADDCH ('a' | 0200) +# define MOVE ('m' | 0200) +# define REFRESH ('r' | 0200) +# define CLRTOEOL ('c' | 0200) +# define ENDWIN ('e' | 0200) +# define CLEAR ('C' | 0200) +# define REDRAW ('R' | 0200) +# define LAST_PLAYER ('l' | 0200) +# define BELL ('b' | 0200) +# define READY ('g' | 0200) + +/* + * Choose MAXPL and MAXMON carefully. The screen is assumed to be + * 23 lines high and will only tolerate (MAXPL == 12 && MAXMON == 0) + * or (MAXPL + MAXMON <= 10). + */ +# define MAXPL 9 +# ifdef MONITOR +# define MAXMON 1 +# endif MONITOR +# define NAMELEN 20 +# define MSGLEN 80 +# define DECAY 50.0 + +# define NASCII 128 + +# ifndef REFLECT +# ifndef RANDOM +# define RANDOM +# endif RANDOM +# endif REFLECT + +# define WIDTH 59 +# define WIDTH2 64 /* Next power of 2 >= WIDTH (for fast access) */ +# define HEIGHT 23 +# define UBOUND 1 +# define DBOUND 22 +# define LBOUND 1 +# define RBOUND (WIDTH - 1) + +# define STAT_LABEL_COL 60 +# define STAT_VALUE_COL 74 +# define STAT_NAME_COL 61 +# define STAT_SCAN_COL (STAT_NAME_COL + 5) +# define STAT_NAME_ROW 0 +# define STAT_AMMO_ROW 2 +# define STAT_SCAN_ROW 3 +# define STAT_CLOAK_ROW 4 +# define STAT_GUN_ROW 5 +# define STAT_DAM_ROW 7 +# define STAT_KILL_ROW 8 +# define STAT_PLAY_ROW 10 +# ifdef MONITOR +# define STAT_MON_ROW (STAT_PLAY_ROW + MAXPL + 1) +# endif MONITOR +# define STAT_NAME_LEN 16 + +# define DOOR '#' +# define WALL1 '-' +# define WALL2 '|' +# define WALL3 '+' +# ifdef REFLECT +# define WALL4 '/' +# define WALL5 '\\' +# endif REFLECT +# define KNIFE 'K' +# define SHOT ':' +# define GRENADE 'o' +# define SATCHEL 'O' +# define BOMB '@' +# define MINE ';' +# define GMINE 'g' +# ifdef OOZE +# define SLIME '$' +# endif OOZE +# ifdef VOLCANO +# define LAVA '~' +# endif VOLCANO +# ifdef FLY +# define FALL 'F' +# endif FLY +# define SPACE ' ' + +# define ABOVE 'i' +# define BELOW '!' +# define RIGHT '}' +# define LEFTS '{' +# ifdef FLY +# define FLYER '&' +# endif FLY + +# define NORTH 01 +# define SOUTH 02 +# define EAST 010 +# define WEST 020 + +# ifndef TRUE +# define TRUE 1 +# define FALSE 0 +# endif TRUE +# ifndef CTRL +# define CTRL(x) ('x' & 037) +# endif CTRL + +# define BULSPD 5 /* bullets movement speed */ +# define ISHOTS 15 +# define NSHOTS 5 +# define MAXNCSHOT 2 +# define MAXDAM 10 +# define MINDAM 5 +# define STABDAM 2 + +# define BULREQ 1 +# define GRENREQ 9 +# define SATREQ 25 +# define BOMBREQ 49 +# ifdef OOZE +# define SLIMEREQ 15 +# define SSLIMEREQ 30 +# define SLIMESPEED 5 +# endif OOZE +# ifdef VOLCANO +# define LAVASPEED 2 +# endif VOLCANO + +# define CLOAKLEN 20 +# define SCANLEN (Nplayer * 20) +# define EXPLEN 4 + +# ifdef FLY +# define _cloak_char(pp) (((pp)->p_cloak < 0) ? ' ' : '+') +# define _scan_char(pp) (((pp)->p_scan < 0) ? _cloak_char(pp) : '*') +# define stat_char(pp) (((pp)->p_flying < 0) ? _scan_char(pp) : FLYER) +# else FLY +# define _cloak_char(pp) (((pp)->p_cloak < 0) ? ' ' : '+') +# define stat_char(pp) (((pp)->p_scan < 0) ? _cloak_char(pp) : '*') +# endif FLY + +typedef int FLAG; +typedef struct bullet_def BULLET; +typedef struct expl_def EXPL; +typedef struct player_def PLAYER; +typedef struct ident_def IDENT; +typedef struct regen_def REGEN; +# ifdef INTERNET +typedef struct sockaddr_in SOCKET; +# else INTERNET +typedef struct sockaddr_un SOCKET; +# endif INTERNET +typedef struct sgttyb TTYB; + +struct ident_def { + char i_name[NAMELEN]; + long i_machine; + long i_uid; + int i_kills; + int i_entries; + float i_score; + IDENT *i_next; +}; + +struct player_def { + IDENT *p_ident; + int p_face; + char p_over; + int p_undershot; +# ifdef FLY + int p_flying; + int p_flyx, p_flyy; +# endif FLY + FILE *p_output; + int p_fd; + int p_mask; + int p_damage; + int p_damcap; + int p_ammo; + int p_ncshot; + int p_scan; + int p_cloak; + int p_x, p_y; + int p_ncount; + int p_nexec; + long p_nchar; + char p_death[MSGLEN]; + char p_maze[HEIGHT][WIDTH2]; + int p_curx, p_cury; + int p_lastx, p_lasty; + int p_changed; + char p_cbuf[BUFSIZ]; +}; + +struct bullet_def { + int b_x, b_y; + int b_face; + int b_charge; + char b_type; + char b_over; + PLAYER *b_owner; + IDENT *b_score; + FLAG b_expl; + BULLET *b_next; +}; + +struct expl_def { + int e_x, e_y; + char e_char; + EXPL *e_next; +}; + +struct regen_def { + int r_x, r_y; + REGEN *r_next; +}; + +/* + * external variables + */ + +extern FLAG Last_player; + +extern char Buf[BUFSIZ], Maze[HEIGHT][WIDTH2], Orig_maze[HEIGHT][WIDTH2]; + +extern char *Sock_name, *Driver; + +extern int errno, Have_inp, Nplayer, Num_fds, Socket; +extern long Fds_mask, Sock_mask; + +# ifdef INTERNET +extern int Test_port; +extern int Sock_port; +# else INTERNET +extern char *Sock_name; +# endif INTERNET + +# ifdef VOLCANO +extern int volcano; +# endif VOLCANO + +extern int See_over[NASCII]; + +extern BULLET *Bullets; + +extern EXPL *Expl[EXPLEN]; + +extern IDENT *Scores; + +extern PLAYER Player[MAXPL], *End_player; + +# ifdef MONITOR +extern FLAG Am_monitor; +extern PLAYER Monitor[MAXMON], *End_monitor; +# endif MONITOR + +/* + * function types + */ + +char *getenv(), *malloc(), *sprintf(), *strcpy(), *strncpy(); + +IDENT *get_ident(); + +int moveshots(); + +BULLET *is_bullet(), *create_shot(); + +PLAYER *play_at(); diff --git a/src/games/hunt/makemaze.c b/src/games/hunt/makemaze.c new file mode 100644 index 0000000..1bed280 --- /dev/null +++ b/src/games/hunt/makemaze.c @@ -0,0 +1,145 @@ +/* + * Hunt + * Copyright (c) 1985 Conrad C. Huang, Gregory S. Couch, Kenneth C.R.C. Arnold + * San Francisco, California + * + * Copyright (c) 1985 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +# include "hunt.h" + +# define ISCLEAR(y,x) (Maze[y][x] == SPACE) +# define ODD(n) ((n) & 01) + +makemaze() +{ + register char *sp; + register int y, x; + + /* + * fill maze with walls + */ + sp = &Maze[0][0]; + while (sp < &Maze[HEIGHT - 1][WIDTH]) + *sp++ = DOOR; + + y = rand_num(DBOUND - UBOUND) + UBOUND; + x = rand_num(RBOUND - LBOUND) + LBOUND; + dig(y, x); /* Dig out the maze */ + remap(); +} + +# define NPERM 24 +# define NDIR 4 + +int dirs[NPERM][NDIR] = { + {0,1,2,3}, {3,0,1,2}, {0,2,3,1}, {0,3,2,1}, + {1,0,2,3}, {2,3,0,1}, {0,2,1,3}, {2,3,1,0}, + {1,0,3,2}, {1,2,0,3}, {3,1,2,0}, {2,0,3,1}, + {1,3,0,2}, {0,3,1,2}, {1,3,2,0}, {2,0,1,3}, + {0,1,3,2}, {3,1,0,2}, {2,1,0,3}, {1,2,3,0}, + {2,1,3,0}, {3,0,2,1}, {3,2,0,1}, {3,2,1,0} + }; + +int incr[NDIR][2] = { + {0, 1}, {1, 0}, {0, -1}, {-1, 0} + }; + +dig(y, x) +int y, x; +{ + register int *dp; + register int *ip; + register int ny, nx; + register int *endp; + + Maze[y][x] = SPACE; /* Clear this spot */ + dp = dirs[rand_num(NPERM)]; + endp = &dp[NDIR]; + while (dp < endp) { + ip = &incr[*dp++][0]; + ny = y + *ip++; + nx = x + *ip; + if (candig(ny, nx)) + dig(ny, nx); + } +} + +/* + * candig: + * Is it legal to clear this spot? + */ +candig(y, x) +register int y, x; +{ + register int i; + + if (ODD(x) && ODD(y)) + return FALSE; /* can't touch ODD spots */ + + if (y < UBOUND || y >= DBOUND) + return FALSE; /* Beyond vertical bounds, NO */ + if (x < LBOUND || x >= RBOUND) + return FALSE; /* Beyond horizontal bounds, NO */ + + if (ISCLEAR(y, x)) + return FALSE; /* Already clear, NO */ + + i = ISCLEAR(y, x + 1); + i += ISCLEAR(y, x - 1); + if (i > 1) + return FALSE; /* Introduces cycle, NO */ + i += ISCLEAR(y + 1, x); + if (i > 1) + return FALSE; /* Introduces cycle, NO */ + i += ISCLEAR(y - 1, x); + if (i > 1) + return FALSE; /* Introduces cycle, NO */ + + return TRUE; /* OK */ +} + +remap() +{ + register int y, x; + register char *sp; + register int stat; + + for (y = 0; y < HEIGHT; y++) + for (x = 0; x < WIDTH; x++) { + sp = &Maze[y][x]; + if (*sp == SPACE) + continue; + stat = 0; + if (y - 1 >= 0 && Maze[y - 1][x] != SPACE) + stat |= NORTH; + if (y + 1 < HEIGHT && Maze[y + 1][x] != SPACE) + stat |= SOUTH; + if (x + 1 < WIDTH && Maze[y][x + 1] != SPACE) + stat |= EAST; + if (x - 1 >= 0 && Maze[y][x - 1] != SPACE) + stat |= WEST; + switch (stat) { + case WEST | EAST: + *sp = WALL1; + break; + case NORTH | SOUTH: + *sp = WALL2; + break; + case 0: +# ifdef RANDOM + *sp = DOOR; +# endif RANDOM +# ifdef REFLECT + *sp = rand_num(2) ? WALL4 : WALL5; +# endif REFLECT + break; + default: + *sp = WALL3; + break; + } + } + bcopy((char *) Maze, (char *) Orig_maze, sizeof Maze); +} diff --git a/src/games/hunt/pathname.c b/src/games/hunt/pathname.c new file mode 100644 index 0000000..1d79811 --- /dev/null +++ b/src/games/hunt/pathname.c @@ -0,0 +1,37 @@ +/* + * Hunt + * Copyright (c) 1985 Conrad C. Huang, Gregory S. Couch, Kenneth C.R.C. Arnold + * San Francisco, California + * + * Copyright (c) 1985 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +/* + * There is no particular significance to the numbers assigned + * to Test_port and Sock_port. They're just random numbers greater + * than then range reserved for privileged sockets. + */ + +# ifdef DEBUG + +char *Driver = "/va/conrad/games/src/hunt/hunt.driver.dbg"; +# ifdef INTERNET +int Test_port = ('h' << 8) | 't'; +int Sock_port = ('h' << 8) | 's'; +# else INTERNET +char *Sock_name = "/tmp/hunt"; +# endif INTERNET + +# else DEBUG + +char *Driver = "/usr/games/lib/hunt.driver"; +# ifdef INTERNET +int Test_port = ('h' << 8) | 't'; +int Sock_port = ('h' << 8) | 's'; +# else INTERNET +char *Sock_name = "/tmp/hunt"; +# endif INTERNET + +# endif DEBUG diff --git a/src/games/hunt/playit.c b/src/games/hunt/playit.c new file mode 100644 index 0000000..dee1a25 --- /dev/null +++ b/src/games/hunt/playit.c @@ -0,0 +1,386 @@ +/* + * Hunt + * Copyright (c) 1985 Conrad C. Huang, Gregory S. Couch, Kenneth C.R.C. Arnold + * San Francisco, California + * + * Copyright (c) 1985 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +# include +# include +# include +# include +# include "hunt.h" +# include + +# undef CTRL +# define CTRL(x) ('x' & 037) + +int input(); +static int nchar_send; +static int in = FREAD; +char screen[24][80], blanks[80]; +int cur_row, cur_col; +# ifdef OTTO +int Otto_count; +int Otto_mode; +static int otto_y, otto_x; +static char otto_face; +# endif OTTO + +# define MAX_SEND 5 + +/* + * ibuf is the input buffer used for the stream from the driver. + * It is small because we do not check for user input when there + * are characters in the input buffer. + */ +static char ibuf[20]; + +#define GETCHR(fd) (--(fd)->_cnt >= 0 ? *(fd)->_ptr++&0377 : getchr(fd)) + +/* + * playit: + * Play a given game, handling all the curses commands from + * the driver. + */ +playit() +{ + register FILE *inf; + register int ch; + register unsigned int y, x; + extern int Master_pid; + extern int errno; + extern int _putchar(); + + errno = 0; + while ((inf = fdopen(Socket, "r")) == NULL) + if (errno == EINTR) + errno = 0; + else { + perror("fdopen of socket"); + exit(1); + } + setbuffer(inf, ibuf, sizeof ibuf); + Master_pid = getw(inf); + if (Master_pid == 0 || Master_pid == EOF) { + bad_con(); + /* NOTREACHED */ + } +# ifdef OTTO + Otto_count = 0; +# endif OTTO + nchar_send = MAX_SEND; + while ((ch = GETCHR(inf)) != EOF) { +# ifdef DEBUG + fputc(ch, stderr); +# endif DEBUG + switch (ch & 0377) { + case MOVE: + y = GETCHR(inf); + x = GETCHR(inf); + mvcur(cur_row, cur_col, y, x); + cur_row = y; + cur_col = x; + break; + case ADDCH: + ch = GETCHR(inf); +# ifdef OTTO + switch (ch) { + + case '<': + case '>': + case '^': + case 'v': + otto_face = ch; + getyx(stdscr, otto_y, otto_x); + break; + } +# endif OTTO + put_ch(ch); + break; + case CLRTOEOL: + clear_eol(); + break; + case CLEAR: + clear_screen(); + break; + case REFRESH: + fflush(stdout); + break; + case REDRAW: + redraw_screen(); + fflush(stdout); + break; + case ENDWIN: + fflush(stdout); + if ((ch = GETCHR(inf)) == LAST_PLAYER) + Last_player = TRUE; + ch = EOF; + goto out; + case BELL: + putchar(CTRL(G)); + break; + case READY: + (void) fflush(stdout); + if (nchar_send < 0) + (void) ioctl(fileno(stdin), TIOCFLUSH, &in); + nchar_send = MAX_SEND; +# ifndef OTTO + (void) GETCHR(inf); +# else OTTO + Otto_count -= (GETCHR(inf) & 255); + if (!Am_monitor) { +# ifdef DEBUG + fputc('0' + Otto_count, stderr); +# endif DEBUG + if (Otto_count == 0 && Otto_mode) + otto(otto_y, otto_x, otto_face); + } +# endif OTTO + break; + default: +# ifdef OTTO + switch (ch) { + + case '<': + case '>': + case '^': + case 'v': + otto_face = ch; + getyx(stdscr, otto_y, otto_x); + break; + } +# endif OTTO + put_ch(ch); + break; + } + } +out: + (void) fclose(inf); +} + +/* + * getchr: + * Grab input and pass it along to the driver + * Return any characters from the driver + * When this routine is called by GETCHR, we already know there are + * no characters in the input buffer. + */ +getchr(fd) +register FILE *fd; +{ + long nchar; + long readfds, s_readfds; + int driver_mask, stdin_mask; + int nfds, s_nfds; + + driver_mask = 1L << fileno(fd); + stdin_mask = 1L << fileno(stdin); + s_readfds = driver_mask | stdin_mask; + s_nfds = (driver_mask > stdin_mask) ? driver_mask : stdin_mask; + s_nfds++; + +one_more_time: + do { + errno = 0; + readfds = s_readfds; + nfds = s_nfds; +# ifndef OLDIPC + nfds = select(nfds, &readfds, NULL, NULL, NULL); +# else OLDIPC + nfds = select(nfds, &readfds, (int *) NULL, 32767); +# endif OLDIPC + } while (nfds <= 0 && errno == EINTR); + + if (readfds & stdin_mask) + send_stuff(); + if ((readfds & driver_mask) == 0) + goto one_more_time; + return _filbuf(fd); +} + +/* + * send_stuff: + * Send standard input characters to the driver + */ +send_stuff() +{ + register int count; + register char *sp, *nsp; + static char inp[sizeof Buf]; + extern char map_key[256]; + + count = read(fileno(stdin), Buf, sizeof Buf); + if (count <= 0) + return; + if (nchar_send <= 0) { + (void) write(1, "\7", 1); + return; + } + + /* + * look for 'q'uit commands; if we find one, + * confirm it. If it is not confirmed, strip + * it out of the input + */ + Buf[count] = '\0'; + nsp = inp; + for (sp = Buf; *sp != '\0'; sp++) + if ((*nsp = map_key[*sp]) == 'q') + intr(); +# ifdef OTTO + else if (*nsp == CTRL(O)) + Otto_mode = !Otto_mode; +# endif OTTO + else + nsp++; + count = nsp - inp; + if (count) { +# ifdef OTTO + Otto_count += count; +# endif OTTO + nchar_send -= count; + if (nchar_send < 0) + count += nchar_send; + (void) write(Socket, inp, count); + } +} + +/* + * quit: + * Handle the end of the game when the player dies + */ +quit() +{ + register int explain, ch; + + if (Last_player) + return TRUE; +# ifdef OTTO + if (Otto_mode) + return FALSE; +# endif OTTO + mvcur(cur_row, cur_col, HEIGHT, 0); + cur_row = HEIGHT; + cur_col = 0; + put_str("Re-enter game? "); + clear_eol(); + fflush(stdout); + explain = FALSE; + for (;;) { + if (isupper(ch = getchar())) + ch = tolower(ch); + if (ch == 'y') { + sleep(2); + return FALSE; + } + else if (ch == 'n') + return TRUE; + (void) putchar(CTRL(G)); + if (!explain) { + put_str("(Y or N) "); + explain = TRUE; + } + fflush(stdout); + } +} + +put_ch(ch) + char ch; +{ + if (!isprint(ch)) { + fprintf(stderr, "r,c,ch: %d,%d,%d", cur_row, cur_col, ch); + return; + } + screen[cur_row][cur_col] = ch; + putchar(ch); + if (++cur_col >= COLS) { + if (!AM || XN) + putchar('\n'); + cur_col = 0; + if (++cur_row >= LINES) + cur_row = LINES; + } +} + +put_str(s) + char *s; +{ + while (*s) + put_ch(*s++); +} + +clear_screen() +{ + register int i; + int _putchar(); + + if (blanks[0] == '\0') + for (i = 0; i < 80; i++) + blanks[i] = ' '; + + if (CL != NULL) { + tputs(CL, LINES, _putchar); + for (i = 0; i < 24; i++) + bcopy(blanks, screen[i], 80); + } else { + for (i = 0; i < 24; i++) { + mvcur(cur_row, cur_col, i, 0); + cur_row = i; + cur_col = 0; + clear_eol(); + } + mvcur(cur_row, cur_col, 0, 0); + } + cur_row = cur_col = 0; +} + +clear_eol() +{ + int _putchar(); + + if (CE != NULL) + tputs(CE, 1, _putchar); + else { + fwrite(blanks, sizeof (char), 80 - cur_col, stdout); + if (COLS != 80) + mvcur(cur_row, 80, cur_row, cur_col); + else if (AM) + mvcur(cur_row + 1, 0, cur_row, cur_col); + else + mvcur(cur_row, 79, cur_row, cur_col); + } + bcopy(blanks, &screen[cur_row][cur_col], 80 - cur_col); +} + +redraw_screen() +{ + register int i; + static int first = 1; + + if (first) { + if ((curscr = newwin(24, 80, 0, 0)) == NULL) { + fprintf(stderr, "Can't create curscr\n"); + exit(1); + } + for (i = 0; i < 24; i++) + curscr->_y[i] = screen[i]; + first = 0; + } + curscr->_cury = cur_row; + curscr->_curx = cur_col; + wrefresh(curscr); +#ifdef NOCURSES + mvcur(cur_row, cur_col, 0, 0); + for (i = 0; i < 23; i++) { + fwrite(screen[i], sizeof (char), 80, stdout); + if (COLS > 80 || (COLS == 80 && !AM)) + putchar('\n'); + } + fwrite(screen[23], sizeof (char), 79, stdout); + mvcur(23, 79, cur_row, cur_col); +#endif +} diff --git a/src/games/hunt/shots.c b/src/games/hunt/shots.c new file mode 100644 index 0000000..a99ba5f --- /dev/null +++ b/src/games/hunt/shots.c @@ -0,0 +1,823 @@ +/* + * Hunt + * Copyright (c) 1985 Conrad C. Huang, Gregory S. Couch, Kenneth C.R.C. Arnold + * San Francisco, California + * + * Copyright (c) 1985 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +# include "hunt.h" +# include + +# define PLUS_DELTA(x, max) if (x < max) x++; else x-- +# define MINUS_DELTA(x, min) if (x > min) x--; else x++ + +/* + * moveshots: + * Move the shots already in the air, taking explosions into account + */ +moveshots() +{ + register BULLET *bp, *next; + register PLAYER *pp; + register int x, y; + register BULLET *blist; + register int i; + + rollexpl(); + if (Bullets == NULL) + goto ret; + + /* + * First we move through the bullet list BULSPD times, looking + * for things we may have run into. If we do run into + * something, we set up the explosion and disappear, checking + * for damage to any player who got in the way. + */ + + blist = Bullets; + Bullets = NULL; + for (bp = blist; bp != NULL; bp = next) { + next = bp->b_next; + x = bp->b_x; + y = bp->b_y; + Maze[y][x] = bp->b_over; + for (pp = Player; pp < End_player; pp++) + check(pp, y, x); +# ifdef MONITOR + for (pp = Monitor; pp < End_monitor; pp++) + check(pp, y, x); +# endif MONITOR + + for (i = 0; i < BULSPD; i++) { + if (bp->b_expl) + break; + + x = bp->b_x; + y = bp->b_y; + + switch (bp->b_face) { + case LEFTS: + x--; + break; + case RIGHT: + x++; + break; + case ABOVE: + y--; + break; + case BELOW: + y++; + break; + } + + switch (Maze[y][x]) { + case SHOT: + if (rand_num(100) < 5) { + zapshot(Bullets, bp); + zapshot(next, bp); + } + break; + case GRENADE: + if (rand_num(100) < 10) { + zapshot(Bullets, bp); + zapshot(next, bp); + } + break; +# ifdef REFLECT + case WALL4: /* reflecting walls */ + switch (bp->b_face) { + case LEFTS: + bp->b_face = BELOW; + break; + case RIGHT: + bp->b_face = ABOVE; + break; + case ABOVE: + bp->b_face = RIGHT; + break; + case BELOW: + bp->b_face = LEFTS; + break; + } + Maze[y][x] = WALL5; +# ifdef MONITOR + for (pp = Monitor; pp < End_monitor; pp++) + check(pp, y, x); +# endif MONITOR + break; + case WALL5: + switch (bp->b_face) { + case LEFTS: + bp->b_face = ABOVE; + break; + case RIGHT: + bp->b_face = BELOW; + break; + case ABOVE: + bp->b_face = LEFTS; + break; + case BELOW: + bp->b_face = RIGHT; + break; + } + Maze[y][x] = WALL4; +# ifdef MONITOR + for (pp = Monitor; pp < End_monitor; pp++) + check(pp, y, x); +# endif MONITOR + break; +# endif REFLECT +# ifdef RANDOM + case DOOR: + switch (rand_num(4)) { + case 0: + bp->b_face = ABOVE; + break; + case 1: + bp->b_face = BELOW; + break; + case 2: + bp->b_face = LEFTS; + break; + case 3: + bp->b_face = RIGHT; + break; + } + break; +# endif RANDOM + case LEFTS: + case RIGHT: + case BELOW: + case ABOVE: +# ifdef FLY + case FLYER: +# endif FLY + /* + * give the person a chance to catch a + * grenade if s/he is facing it + */ + if (rand_num(100) < 10 + && opposite(bp->b_face, Maze[y][x])) { + if (bp->b_owner != NULL) + message(bp->b_owner, + "Your charge was absorbed!"); + pp = play_at(y, x); + pp->p_ammo += bp->b_charge; + (void) sprintf(Buf, + "Absorbed charge (good shield!)"); + message(pp, Buf); + free((char *) bp); + (void) sprintf(Buf, "%3d", pp->p_ammo); + cgoto(pp, STAT_AMMO_ROW, STAT_VALUE_COL); + outstr(pp, Buf, 3); + goto next_bullet; + } + /* FALLTHROUGH */ +# ifndef RANDOM + case DOOR: +# endif RANDOM + case WALL1: + case WALL2: + case WALL3: + bp->b_expl = TRUE; + break; + } + + bp->b_x = x; + bp->b_y = y; + } + + bp->b_next = Bullets; + Bullets = bp; +next_bullet: + ; + } + + blist = Bullets; + Bullets = NULL; + for (bp = blist; bp != NULL; bp = next) { + next = bp->b_next; + if (!bp->b_expl) { + save_bullet(bp); +# ifdef MONITOR + for (pp = Monitor; pp < End_monitor; pp++) + check(pp, bp->b_y, bp->b_x); +# endif MONITOR + continue; + } + + chkshot(bp); + free((char *) bp); + } + for (pp = Player; pp < End_player; pp++) + Maze[pp->p_y][pp->p_x] = pp->p_face; +ret: + for (pp = Player; pp < End_player; pp++) { +# ifdef FLY + if (pp->p_flying >= 0) { + Maze[pp->p_y][pp->p_x] = pp->p_over; + x = pp->p_x + pp->p_flyx; + y = pp->p_y + pp->p_flyy; + if (x < 1) { + x = 1 - x; + pp->p_flyx = -pp->p_flyx; + } + else if (x > WIDTH - 2) { + x = (WIDTH - 2) - (x - (WIDTH - 2)); + pp->p_flyx = -pp->p_flyx; + } + if (y < 1) { + y = 1 - y; + pp->p_flyy = -pp->p_flyy; + } + else if (y > HEIGHT - 2) { + y = (HEIGHT - 2) - (y - (HEIGHT - 2)); + pp->p_flyy = -pp->p_flyy; + } +again: switch (Maze[y][x]) { + case LEFTS: + case RIGHT: + case ABOVE: + case BELOW: + case FLYER: + switch (rand_num(4)) { + case 0: + PLUS_DELTA(x, WIDTH - 2); + break; + case 1: + MINUS_DELTA(x, 1); + break; + case 2: + PLUS_DELTA(y, HEIGHT - 2); + break; + case 3: + MINUS_DELTA(y, 1); + break; + } + goto again; + case WALL1: + case WALL2: + case WALL3: +# ifdef REFLECT + case WALL4: + case WALL5: +# endif REFLECT +# ifdef RANDOM + case DOOR: +# endif RANDOM + if (pp->p_flying == 0) + pp->p_flying++; + break; + case MINE: + checkdam(pp, NULL, NULL, MINDAM, MINE); + Maze[y][x] = SPACE; + break; + case GMINE: + checkdam(pp, NULL, NULL, MINDAM, GMINE); + checkdam(pp, NULL, NULL, MINDAM, GMINE); + Maze[y][x] = SPACE; + break; + } + pp->p_y = y; + pp->p_x = x; + pp->p_over = Maze[y][x]; + if (pp->p_flying-- == 0) { + checkdam(pp, NULL, NULL, + rand_num(pp->p_damage / 5), FALL); + rand_face(pp); + showstat(pp); + } + Maze[y][x] = pp->p_face; + showexpl(y, x, pp->p_face); + } +# endif FLY + sendcom(pp, REFRESH); /* Flush out the explosions */ + look(pp); + sendcom(pp, REFRESH); + } +# ifdef MONITOR + for (pp = Monitor; pp < End_monitor; pp++) + sendcom(pp, REFRESH); +# endif MONITOR + +# ifdef CONSTANT_MOVE + if (Bullets != NULL) { + bul_alarm(1); + return; + } + for (i = 0; i < EXPLEN; i++) + if (Expl[i] != NULL) { + bul_alarm(1); + return; + } + bul_alarm(0); +# endif CONSTANT_MOVE + + return; +} + +save_bullet(bp) +register BULLET *bp; +{ + bp->b_over = Maze[bp->b_y][bp->b_x]; + switch (bp->b_over) { + case SHOT: + case GRENADE: + case SATCHEL: + case BOMB: +# ifdef OOZE + case SLIME: +# ifdef VOLCANO + case LAVA: +# endif VOLCANO +# endif OOZE + find_under(Bullets, bp); + break; + } + + switch (bp->b_over) { + case LEFTS: + case RIGHT: + case ABOVE: + case BELOW: +# ifdef FLY + case FLYER: +# endif FLY + mark_player(bp); + break; + + default: + Maze[bp->b_y][bp->b_x] = bp->b_type; + break; + } + + bp->b_next = Bullets; + Bullets = bp; +} + +/* + * chkshot + * Handle explosions + */ +chkshot(bp) +register BULLET *bp; +{ + register int y, x; + register int dy, dx, absdy; + register int delta, damage; + register char expl; + register PLAYER *pp; + + switch (bp->b_type) { + case SHOT: + case MINE: + delta = 0; + break; + case GRENADE: + case GMINE: + delta = 1; + break; + case SATCHEL: + delta = 2; + break; + case BOMB: + delta = 3; + break; +# ifdef OOZE + case SLIME: +# ifdef VOLCANO + case LAVA: +# endif VOLCANO + chkslime(bp); + return; +# endif OOZE + } + for (y = bp->b_y - delta; y <= bp->b_y + delta; y++) { + if (y < 0 || y >= HEIGHT) + continue; + dy = y - bp->b_y; + absdy = (dy < 0) ? -dy : dy; + for (x = bp->b_x - delta; x <= bp->b_x + delta; x++) { + if (x < 0 || x >= WIDTH) + continue; + dx = x - bp->b_x; + if (dx == 0) + expl = (dy == 0) ? '*' : '|'; + else if (dy == 0) + expl = '-'; + else if (dx == dy) + expl = '\\'; + else if (dx == -dy) + expl = '/'; + else + expl = '*'; + showexpl(y, x, expl); + switch (Maze[y][x]) { + case LEFTS: + case RIGHT: + case ABOVE: + case BELOW: +# ifdef FLY + case FLYER: +# endif FLY + if (dx < 0) + dx = -dx; + if (absdy > dx) + damage = delta - absdy + 1; + else + damage = delta - dx + 1; + pp = play_at(y, x); + while (damage-- > 0) + checkdam(pp, bp->b_owner, bp->b_score, + MINDAM, bp->b_type); + break; + case GMINE: + case MINE: + add_shot((Maze[y][x] == GMINE) ? + GRENADE : SHOT, + y, x, LEFTS, + (Maze[y][x] == GMINE) ? + GRENREQ : BULREQ, + (PLAYER *) NULL, TRUE, SPACE); + Maze[y][x] = SPACE; + break; + } + } + } +} + +# ifdef OOZE +/* + * chkslime: + * handle slime shot exploding + */ +chkslime(bp) +register BULLET *bp; +{ + register BULLET *nbp; + + switch (Maze[bp->b_y][bp->b_x]) { + case WALL1: + case WALL2: + case WALL3: +# ifdef REFLECT + case WALL4: + case WALL5: +# endif REFLECT +# ifdef RANDOM + case DOOR: +# endif RANDOM + switch (bp->b_face) { + case LEFTS: + bp->b_x++; + break; + case RIGHT: + bp->b_x--; + break; + case ABOVE: + bp->b_y++; + break; + case BELOW: + bp->b_y--; + break; + } + break; + } + nbp = (BULLET *) malloc(sizeof (BULLET)); + *nbp = *bp; +# ifdef VOLCANO + moveslime(nbp, nbp->b_type == SLIME ? SLIMESPEED : LAVASPEED); +# else VOLCANO + moveslime(nbp, SLIMESPEED); +# endif VOLCANO +} + +/* + * moveslime: + * move the given slime shot speed times and add it back if + * it hasn't fizzled yet + */ +moveslime(bp, speed) +register BULLET *bp; +register int speed; +{ + register int i, j, dirmask, count; + register PLAYER *pp; + register BULLET *nbp; + + if (speed == 0) { + if (bp->b_charge <= 0) + free((char *) bp); + else + save_bullet(bp); + return; + } + +# ifdef VOLCANO + showexpl(bp->b_y, bp->b_x, bp->b_type == LAVA ? LAVA : '*'); +# else VOLCANO + showexpl(bp->b_y, bp->b_x, '*'); +# endif VOLCANO + switch (Maze[bp->b_y][bp->b_x]) { + case LEFTS: + case RIGHT: + case ABOVE: + case BELOW: +# ifdef FLY + case FLYER: +# endif FLY + pp = play_at(bp->b_y, bp->b_x); + message(pp, "You've been slimed."); + checkdam(pp, bp->b_owner, bp->b_score, MINDAM, bp->b_type); + break; + } + + if (--bp->b_charge <= 0) { + free((char *) bp); + return; + } + + dirmask = 0; + count = 0; + switch (bp->b_face) { + case LEFTS: + if (!iswall(bp->b_y, bp->b_x - 1)) + dirmask |= WEST, count++; + if (!iswall(bp->b_y - 1, bp->b_x)) + dirmask |= NORTH, count++; + if (!iswall(bp->b_y + 1, bp->b_x)) + dirmask |= SOUTH, count++; + if (dirmask == 0) + if (!iswall(bp->b_y, bp->b_x + 1)) + dirmask |= EAST, count++; + break; + case RIGHT: + if (!iswall(bp->b_y, bp->b_x + 1)) + dirmask |= EAST, count++; + if (!iswall(bp->b_y - 1, bp->b_x)) + dirmask |= NORTH, count++; + if (!iswall(bp->b_y + 1, bp->b_x)) + dirmask |= SOUTH, count++; + if (dirmask == 0) + if (!iswall(bp->b_y, bp->b_x - 1)) + dirmask |= WEST, count++; + break; + case ABOVE: + if (!iswall(bp->b_y - 1, bp->b_x)) + dirmask |= NORTH, count++; + if (!iswall(bp->b_y, bp->b_x - 1)) + dirmask |= WEST, count++; + if (!iswall(bp->b_y, bp->b_x + 1)) + dirmask |= EAST, count++; + if (dirmask == 0) + if (!iswall(bp->b_y + 1, bp->b_x)) + dirmask |= SOUTH, count++; + break; + case BELOW: + if (!iswall(bp->b_y + 1, bp->b_x)) + dirmask |= SOUTH, count++; + if (!iswall(bp->b_y, bp->b_x - 1)) + dirmask |= WEST, count++; + if (!iswall(bp->b_y, bp->b_x + 1)) + dirmask |= EAST, count++; + if (dirmask == 0) + if (!iswall(bp->b_y - 1, bp->b_x)) + dirmask |= NORTH, count++; + break; + } + if (count == 0) { + /* + * No place to go. Just sit here for a while and wait + * for adjacent squares to clear out. + */ + save_bullet(bp); + return; + } + if (bp->b_charge < count) { + /* Only bp->b_charge paths may be taken */ + while (count > bp->b_charge) { + if (dirmask & WEST) + dirmask &= ~WEST; + else if (dirmask & EAST) + dirmask &= ~EAST; + else if (dirmask & NORTH) + dirmask &= ~NORTH; + else if (dirmask & SOUTH) + dirmask &= ~SOUTH; + count--; + } + } + + i = bp->b_charge / count; + j = bp->b_charge % count; + if (dirmask & WEST) { + count--; + nbp = create_shot(bp->b_type, bp->b_y, bp->b_x - 1, LEFTS, + i, bp->b_owner, bp->b_score, TRUE, SPACE); + moveslime(nbp, speed - 1); + } + if (dirmask & EAST) { + count--; + nbp = create_shot(bp->b_type, bp->b_y, bp->b_x + 1, RIGHT, + (count < j) ? i + 1 : i, bp->b_owner, bp->b_score, + TRUE, SPACE); + moveslime(nbp, speed - 1); + } + if (dirmask & NORTH) { + count--; + nbp = create_shot(bp->b_type, bp->b_y - 1, bp->b_x, ABOVE, + (count < j) ? i + 1 : i, bp->b_owner, bp->b_score, + TRUE, SPACE); + moveslime(nbp, speed - 1); + } + if (dirmask & SOUTH) { + count--; + nbp = create_shot(bp->b_type, bp->b_y + 1, bp->b_x, BELOW, + (count < j) ? i + 1 : i, bp->b_owner, bp->b_score, + TRUE, SPACE); + moveslime(nbp, speed - 1); + } + + free((char *) bp); +} + +/* + * iswall: + * returns whether the given location is a wall + */ +iswall(y, x) +register int y, x; +{ + if (y < 0 || x < 0 || y >= HEIGHT || x >= WIDTH) + return TRUE; + switch (Maze[y][x]) { + case WALL1: + case WALL2: + case WALL3: +# ifdef REFLECT + case WALL4: + case WALL5: +# endif REFLECT +# ifdef RANDOM + case DOOR: +# endif RANDOM +# ifdef VOLCANO + case LAVA: +# endif VOLCANO + return TRUE; + } + return FALSE; +} +# endif OOZE + +/* + * zapshot: + * Take a shot out of the air. + */ +zapshot(blist, obp) +register BULLET *blist, *obp; +{ + register BULLET *bp; + register FLAG explode; + + explode = FALSE; + for (bp = blist; bp != NULL; bp = bp->b_next) { + if (bp->b_x != obp->b_x || bp->b_y != obp->b_y) + continue; + if (bp->b_face == obp->b_face) + continue; + explode = TRUE; + break; + } + if (!explode) + return; + explshot(blist, obp->b_y, obp->b_x); +} + +/* + * explshot - + * Make all shots at this location blow up + */ +explshot(blist, y, x) +register BULLET *blist; +register int y, x; +{ + register BULLET *bp; + + for (bp = blist; bp != NULL; bp = bp->b_next) + if (bp->b_x == x && bp->b_y == y) { + bp->b_expl = TRUE; + if (bp->b_owner != NULL) + message(bp->b_owner, "Shot intercepted"); + } +} + +/* + * play_at: + * Return a pointer to the player at the given location + */ +PLAYER * +play_at(y, x) +register int y, x; +{ + register PLAYER *pp; + + for (pp = Player; pp < End_player; pp++) + if (pp->p_x == x && pp->p_y == y) + return pp; + fprintf(stderr, "driver: couldn't find player at (%d,%d)\n", x, y); + abort(); + /* NOTREACHED */ +} + +/* + * opposite: + * Return TRUE if the bullet direction faces the opposite direction + * of the player in the maze + */ +opposite(face, dir) +int face; +char dir; +{ + switch (face) { + case LEFTS: + return (dir == RIGHT); + case RIGHT: + return (dir == LEFTS); + case ABOVE: + return (dir == BELOW); + case BELOW: + return (dir == ABOVE); + default: + return FALSE; + } +} + +/* + * is_bullet: + * Is there a bullet at the given coordinates? If so, return + * a pointer to the bullet, otherwise return NULL + */ +BULLET * +is_bullet(y, x) +register int y, x; +{ + register BULLET *bp; + + for (bp = Bullets; bp != NULL; bp = bp->b_next) + if (bp->b_y == y && bp->b_x == x) + return bp; + return NULL; +} + +/* + * fixshots: + * change the underlying character of the shots at a location + * to the given character. + */ +fixshots(y, x, over) +register int y, x; +char over; +{ + register BULLET *bp; + + for (bp = Bullets; bp != NULL; bp = bp->b_next) + if (bp->b_y == y && bp->b_x == x) + bp->b_over = over; +} + +/* + * find_under: + * find the underlying character for a bullet when it lands + * on another bullet. + */ +find_under(blist, bp) +register BULLET *blist, *bp; +{ + register BULLET *nbp; + + for (nbp = blist; nbp != NULL; nbp = nbp->b_next) + if (bp->b_y == nbp->b_y && bp->b_x == nbp->b_x) { + bp->b_over = nbp->b_over; + break; + } +} + +/* + * mark_player: + * mark a player as under a shot + */ +mark_player(bp) +register BULLET *bp; +{ + register PLAYER *pp; + + for (pp = Player; pp < End_player; pp++) + if (pp->p_y == bp->b_y && pp->p_x == bp->b_x) { + pp->p_undershot = TRUE; + break; + } +} diff --git a/src/games/hunt/terminal.c b/src/games/hunt/terminal.c new file mode 100644 index 0000000..2053277 --- /dev/null +++ b/src/games/hunt/terminal.c @@ -0,0 +1,114 @@ +/* + * Hunt + * Copyright (c) 1985 Conrad C. Huang, Gregory S. Couch, Kenneth C.R.C. Arnold + * San Francisco, California + * + * Copyright (c) 1985 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +# include "hunt.h" +# define TERM_WIDTH 80 /* Assume terminals are 80-char wide */ + +/* + * cgoto: + * Move the cursor to the given position on the given player's + * terminal. + */ +cgoto(pp, y, x) +register PLAYER *pp; +register int y, x; +{ + if (x == pp->p_curx && y == pp->p_cury) + return; + sendcom(pp, MOVE, y, x); + pp->p_cury = y; + pp->p_curx = x; +} + +/* + * outch: + * Put out a single character. + */ +outch(pp, ch) +register PLAYER *pp; +char ch; +{ + if (++pp->p_curx >= TERM_WIDTH) { + pp->p_curx = 0; + pp->p_cury++; + } + (void) putc(ch, pp->p_output); +} + +/* + * outstr: + * Put out a string of the given length. + */ +outstr(pp, str, len) +register PLAYER *pp; +register char *str; +register int len; +{ + pp->p_curx += len; + pp->p_cury += (pp->p_curx / TERM_WIDTH); + pp->p_curx %= TERM_WIDTH; + while (len--) + (void) putc(*str++, pp->p_output); +} + +/* + * clrscr: + * Clear the screen, and reset the current position on the screen. + */ +clrscr(pp) +register PLAYER *pp; +{ + sendcom(pp, CLEAR); + pp->p_cury = 0; + pp->p_curx = 0; +} + +/* + * ce: + * Clear to the end of the line + */ +ce(pp) +PLAYER *pp; +{ + sendcom(pp, CLRTOEOL); +} + +/* + * ref; + * Refresh the screen + */ +ref(pp) +register PLAYER *pp; +{ + sendcom(pp, REFRESH); +} + +/* + * sendcom: + * Send a command to the given user + */ +/* VARARGS2 */ +sendcom(pp, command, arg1, arg2) +register PLAYER *pp; +register int command; +int arg1, arg2; +{ + (void) putc(command, pp->p_output); + switch (command & 0377) { + case MOVE: + (void) putc(arg1, pp->p_output); + (void) putc(arg2, pp->p_output); + break; + case ADDCH: + case READY: + (void) putc(arg1, pp->p_output); + break; + } +} diff --git a/src/games/mille/Makefile b/src/games/mille/Makefile new file mode 100644 index 0000000..4f40253 --- /dev/null +++ b/src/games/mille/Makefile @@ -0,0 +1,75 @@ +# +# mille bourne game makefile +# +HEADERS=mille.h +CFILES= comp.c end.c extern.c init.c mille.c misc.c move.c print.c \ + roll.c save.c types.c varpush.c +OBJS= comp.o end.o extern.o init.o mille.o misc.o move.o print.o \ + roll.o save.o types.o varpush.o +POBJS= comp.po end.po extern.po init.po mille.po misc.po move.po \ + roll.po print.po save.po types.po varpush.po +# CRL= /jb/ingres/arnold/=lib/=curses/crlib +# CRL= =curses/screen/libcurses.a +CRL= +# L= -ltermlib +L= -lcurses -ltermlib +LIBS= ${CRL} ${L} +DEFS= +CFLAGS= -O ${DEFS} +SEPFLAG= -i +LDFLAGS= +DESTDIR= +BINDIR= /usr/games +.SUFFIXES: .po .i + +.c.po: + rm -f x.c ; ln $*.c x.c + ${CC} ${CFLAGS} -p -c x.c + mv x.o $*.po + +.c.i: + ${CC} ${LDFLAGS} -P $*.c + +a.out: ${OBJS} ${CRL} + ${CC} ${SEPFLAG} ${LDFLAGS} ${OBJS} ${LIBS} + +mille: ${OBJS} ${CRL} + ${CC} ${SEPFLAG} ${CFLAGS} -o mille ${OBJS} ${LIBS} + +install: mille + install -s mille ${DESTDIR}${BINDIR} + +pmb: ${POBJS} ../pcrlib + ${CC} ${SEPFLAG} ${CFLAGS} -p -o pmb ${POBJS} ../pcrlib -ltermlib + +mille.po: mille.c + rm -f x.c ; ln mille.c x.c + ${CC} ${CFLAGS} -DPROF -p -c x.c + mv x.o mille.po + +table: table.o extern.o + ${CC} ${SEPFLAG} ${CFLAGS} -i -o table table.o extern.o + +readdump: readdump.o extern.o varpush.o + ${CC} ${SEPFLAG} ${CFLAGS} -i -o readdump readdump.o extern.o varpush.o + +ctags: + ctags ${HEADERS} ${CFILES} + ed - tags < :ctfix + sort tags -o tags + +lint: + lint -hxb ${DEFS} ${CFILES} ${L} > lint.out + +mille.ar: + ar ruv mille.ar Makefile tags ${HEADERS} ${CFILES} + +tar: + tar rvf /dev/rmt0 Makefile tags :ctfix ${HEADERS} ${CFILES} + +lpr: + pr Makefile ${HEADERS} ${CFILES} tags | lpr ; lpq + +clean: + rm -f ${OBJS} ${POBJS} core ? a.out errs mille lint.out mille.ar \ + tags pmb diff --git a/src/games/mille/comp.c b/src/games/mille/comp.c new file mode 100644 index 0000000..c5faa90 --- /dev/null +++ b/src/games/mille/comp.c @@ -0,0 +1,431 @@ +# include "mille.h" + +/* + * @(#)comp.c 1.1 (Berkeley) 4/1/82 + */ + +# define V_VALUABLE 40 + +calcmove() +{ + register CARD card; + register int *value; + register PLAY *pp, *op; + register bool foundend, cango, canstop, foundlow; + register unsgn int i, count200, badcount, nummin, nummax, diff; + register int curmin, curmax; + register CARD safe, oppos; + int valbuf[HAND_SZ], count[NUM_CARDS]; + bool playit[HAND_SZ]; + + wmove(Score, ERR_Y, ERR_X); /* get rid of error messages */ + wclrtoeol(Score); + pp = &Player[COMP]; + op = &Player[PLAYER]; + safe = 0; + cango = 0; + canstop = FALSE; + foundend = FALSE; + for (i = 0; i < NUM_CARDS; i++) + count[i] = 0; + for (i = 0; i < HAND_SZ; i++) { + card = pp->hand[i]; + switch (card) { + case C_STOP: case C_CRASH: + case C_FLAT: case C_EMPTY: + if (playit[i] = canplay(pp, op, card)) + canstop = TRUE; + goto norm; + case C_LIMIT: + if ((playit[i] = canplay(pp, op, card)) + && Numseen[C_25] == Numcards[C_25] + && Numseen[C_50] == Numcards[C_50]) + canstop = TRUE; + goto norm; + case C_25: case C_50: case C_75: + case C_100: case C_200: + if ((playit[i] = canplay(pp, op, card)) + && pp->mileage + Value[card] == End) + foundend = TRUE; + goto norm; + default: + playit[i] = canplay(pp, op, card); +norm: + if (playit[i]) + ++cango; + break; + case C_GAS_SAFE: case C_DRIVE_SAFE: + case C_SPARE_SAFE: case C_RIGHT_WAY: + if (pp->battle == opposite(card) || + (pp->speed == C_LIMIT && card == C_RIGHT_WAY)) { + Movetype = M_PLAY; + Card_no = i; + return; + } + ++safe; + playit[i] = TRUE; + break; + } + ++count[card]; + } + if (pp->hand[0] == C_INIT && Topcard > Deck) { + Movetype = M_DRAW; + return; + } + if (Debug) + fprintf(outf, "CALCMOVE: cango = %d, canstop = %d, safe = %d\n", + cango, canstop, safe); + if (foundend) + foundend = !check_ext(TRUE); + for (i = 0; safe && i < HAND_SZ; i++) { + if (issafety(pp->hand[i])) { + if (onecard(op) || (foundend && cango && !canstop)) { + if (Debug) + fprintf(outf, + "CALCMOVE: onecard(op) = %d, foundend = %d\n", + onecard(op), foundend); +playsafe: + Movetype = M_PLAY; + Card_no = i; + return; + } + oppos = opposite(pp->hand[i]); + if (Numseen[oppos] == Numcards[oppos] && + !(pp->hand[i] == C_RIGHT_WAY && + Numseen[C_LIMIT] != Numcards[C_LIMIT])) + goto playsafe; + else if (!cango + && (op->can_go || !pp->can_go || Topcard < Deck)) { + card = (Topcard - Deck) - roll(1, 10); + if ((!pp->mileage) != (!op->mileage)) + card -= 7; + if (Debug) + fprintf(outf, + "CALCMOVE: card = %d, DECK_SZ / 4 = %d\n", + card, DECK_SZ / 4); + if (card < DECK_SZ / 4) + goto playsafe; + } + safe--; + playit[i] = cango; + } + } + if (!pp->can_go && !isrepair(pp->battle)) + Numneed[opposite(pp->battle)]++; +redoit: + foundlow = (cango || count[C_END_LIMIT] != 0 + || Numseen[C_LIMIT] == Numcards[C_LIMIT] + || pp->safety[S_RIGHT_WAY] != S_UNKNOWN); + foundend = FALSE; + count200 = pp->nummiles[C_200]; + badcount = 0; + curmax = -1; + curmin = 101; + nummin = -1; + nummax = -1; + value = valbuf; + for (i = 0; i < HAND_SZ; i++) { + card = pp->hand[i]; + if (issafety(card) || playit[i] == (cango != 0)) { + if (Debug) + fprintf(outf, "CALCMOVE: switch(\"%s\")\n", + C_name[card]); + switch (card) { + case C_25: case C_50: + diff = End - pp->mileage; + /* avoid getting too close */ + if (Topcard > Deck && cango && diff <= 100 + && diff / Value[card] > count[card] + && (card == C_25 || diff % 50 == 0)) { + if (card == C_50 && diff - 50 == 25 + && count[C_25] > 0) + goto okay; + *value = 0; + if (--cango <= 0) + goto redoit; + break; + } +okay: + *value = (Value[card] >> 3); + if (pp->speed == C_LIMIT) + ++*value; + else + --*value; + if (!foundlow + && (card == C_50 || count[C_50] == 0)) { + *value = (pp->mileage ? 10 : 20); + foundlow = TRUE; + } + goto miles; + case C_200: + if (++count200 > 2) { + *value = 0; + break; + } + case C_75: case C_100: + *value = (Value[card] >> 3); + if (pp->speed == C_LIMIT) + --*value; + else + ++*value; +miles: + if (pp->mileage + Value[card] > End) + *value = (End == 700 ? card : 0); + else if (pp->mileage + Value[card] == End) { + *value = (foundend ? card : V_VALUABLE); + foundend = TRUE; + } + break; + case C_END_LIMIT: + if (pp->safety[S_RIGHT_WAY] != S_UNKNOWN) + *value = (pp->safety[S_RIGHT_WAY] == + S_PLAYED ? -1 : 1); + else if (pp->speed == C_LIMIT && + End - pp->mileage <= 50) + *value = 1; + else if (pp->speed == C_LIMIT + || Numseen[C_LIMIT] != Numcards[C_LIMIT]) { + safe = S_RIGHT_WAY; + oppos = C_LIMIT; + goto repair; + } + else { + *value = 0; + --count[C_END_LIMIT]; + } + break; + case C_REPAIRS: case C_SPARE: case C_GAS: + safe = safety(card) - S_CONV; + oppos = opposite(card); + if (pp->safety[safe] != S_UNKNOWN) + *value = (pp->safety[safe] == + S_PLAYED ? -1 : 1); + else if (pp->battle != oppos + && (Numseen[oppos] == Numcards[oppos] || + Numseen[oppos] + count[card] > + Numcards[oppos])) { + *value = 0; + --count[card]; + } + else { +repair: + *value = Numcards[oppos] * 6; + *value += Numseen[card] - + Numseen[oppos]; + if (!cango) + *value /= (count[card]*count[card]); + count[card]--; + } + break; + case C_GO: + if (pp->safety[S_RIGHT_WAY] != S_UNKNOWN) + *value = (pp->safety[S_RIGHT_WAY] == + S_PLAYED ? -1 : 2); + else if (pp->can_go + && Numgos + count[C_GO] == Numneed[C_GO]) { + *value = 0; + --count[C_GO]; + } + else { + *value = Numneed[C_GO] * 3; + *value += (Numseen[C_GO] - Numgos); + *value /= (count[C_GO] * count[C_GO]); + count[C_GO]--; + } + break; + case C_LIMIT: + if (op->mileage + 50 >= End) { + *value = (End == 700 && !cango); + break; + } + if (canstop || (cango && !op->can_go)) + *value = 1; + else { + *value = (pp->safety[S_RIGHT_WAY] != + S_UNKNOWN ? 2 : 3); + safe = S_RIGHT_WAY; + oppos = C_END_LIMIT; + goto normbad; + } + break; + case C_CRASH: case C_EMPTY: case C_FLAT: + safe = safety(card) - S_CONV; + oppos = opposite(card); + *value = (pp->safety[safe]!=S_UNKNOWN ? 3 : 4); +normbad: + if (op->safety[safe] == S_PLAYED) + *value = -1; + else { + *value *= Numneed[oppos] + + Numseen[oppos] + 2; + if (!pp->mileage || foundend || + onecard(op)) + *value += 5; + if (op->mileage == 0 || onecard(op)) + *value += 5; + if (op->speed == C_LIMIT) + *value -= 3; + if (cango && + pp->safety[safe] != S_UNKNOWN) + *value += 3; + if (!cango) + *value /= ++badcount; + } + break; + case C_STOP: + if (op->safety[S_RIGHT_WAY] == S_PLAYED) + *value = -1; + else { + *value = (pp->safety[S_RIGHT_WAY] != + S_UNKNOWN ? 3 : 4); + *value *= Numcards[C_STOP] + + Numseen[C_GO]; + if (!pp->mileage || foundend || + onecard(op)) + *value += 5; + if (!cango) + *value /= ++badcount; + if (op->mileage == 0) + *value += 5; + if ((card == C_LIMIT && + op->speed == C_LIMIT) || + !op->can_go) + *value -= 5; + if (cango && pp->safety[S_RIGHT_WAY] != + S_UNKNOWN) + *value += 5; + } + break; + case C_GAS_SAFE: case C_DRIVE_SAFE: + case C_SPARE_SAFE: case C_RIGHT_WAY: + *value = cango ? 0 : 101; + break; + case C_INIT: + *value = 0; + break; + } + } + else + *value = cango ? 0 : 101; + if (card != C_INIT) { + if (*value >= curmax) { + nummax = i; + curmax = *value; + } + if (*value <= curmin) { + nummin = i; + curmin = *value; + } + } + if (Debug) + mvprintw(i + 6, 2, "%3d %-14s", *value, + C_name[pp->hand[i]]); + value++; + } + if (!pp->can_go && !isrepair(pp->battle)) + Numneed[opposite(pp->battle)]++; + if (cango) { +play_it: + mvaddstr(MOVE_Y + 1, MOVE_X, "PLAY\n"); + if (Debug) + getmove(); + if (!Debug || Movetype == M_DRAW) { + Movetype = M_PLAY; + Card_no = nummax; + } + } + else { + if (issafety(pp->hand[nummin])) { /* NEVER discard a safety */ + nummax = nummin; + goto play_it; + } + mvaddstr(MOVE_Y + 1, MOVE_X, "DISCARD\n"); + if (Debug) + getmove(); + if (!Debug || Movetype == M_DRAW) { + Movetype = M_DISCARD; + Card_no = nummin; + } + } + mvprintw(MOVE_Y + 2, MOVE_X, "%16s", C_name[pp->hand[Card_no]]); +} + +onecard(pp) +register PLAY *pp; +{ + register CARD bat, spd, card; + + bat = pp->battle; + spd = pp->speed; + card = -1; + if (pp->can_go || ((isrepair(bat) || bat == C_STOP || spd == C_LIMIT) && + Numseen[S_RIGHT_WAY] != 0) || + Numseen[safety(bat)] != 0) + switch (End - pp->mileage) { + case 200: + if (pp->nummiles[C_200] == 2) + return FALSE; + card = C_200; + /* FALLTHROUGH */ + case 100: + case 75: + if (card == -1) + card = (End - pp->mileage == 75 ? C_75 : C_100); + if (spd == C_LIMIT) + return Numseen[S_RIGHT_WAY] == 0; + case 50: + case 25: + if (card == -1) + card = (End - pp->mileage == 25 ? C_25 : C_50); + return Numseen[card] != Numcards[card]; + } + return FALSE; +} + +canplay(pp, op, card) +register PLAY *pp, *op; +register CARD card; +{ + switch (card) { + case C_200: + if (pp->nummiles[C_200] == 2) + break; + /* FALLTHROUGH */ + case C_75: case C_100: + if (pp->speed == C_LIMIT) + break; + /* FALLTHROUGH */ + case C_50: + if (pp->mileage + Value[card] > End) + break; + /* FALLTHROUGH */ + case C_25: + if (pp->can_go) + return TRUE; + break; + case C_EMPTY: case C_FLAT: case C_CRASH: + case C_STOP: + if (op->can_go && op->safety[safety(card) - S_CONV] != S_PLAYED) + return TRUE; + break; + case C_LIMIT: + if (op->speed != C_LIMIT && + op->safety[S_RIGHT_WAY] != S_PLAYED && + op->mileage + 50 < End) + return TRUE; + break; + case C_GAS: case C_SPARE: case C_REPAIRS: + if (pp->battle == opposite(card)) + return TRUE; + break; + case C_GO: + if (!pp->can_go && + (isrepair(pp->battle) || pp->battle == C_STOP)) + return TRUE; + break; + case C_END_LIMIT: + if (pp->speed == C_LIMIT) + return TRUE; + } + return FALSE; +} diff --git a/src/games/mille/end.c b/src/games/mille/end.c new file mode 100644 index 0000000..34ca469 --- /dev/null +++ b/src/games/mille/end.c @@ -0,0 +1,111 @@ +# include "mille.h" + +/* + * @(#)end.c 1.1 (Berkeley) 4/1/82 + */ + +/* + * print out the score as if it was final, and add the totals for + * the end-of-games points to the user who deserves it (if any). + */ +finalscore(pp) +reg PLAY *pp; { + + reg int temp, tot, num; + + if (pp->was_finished == Finished) + return; + + pp->was_finished = Finished; + num = pp - Player; + temp = num * 6 + 21 + 1; + for (tot = 5; tot <= 9; tot++) + mvaddstr(tot, temp, " 0"); + if (pp->mileage == End) { + mvaddstr(5, temp, "40"); + tot = SC_TRIP; + if (pp->nummiles[C_200] == 0) { + mvaddstr(6, temp, "30"); + tot = SC_TRIP + SC_SAFE; + } + if (Topcard <= Deck) { + mvaddstr(7, temp, "30"); + tot += SC_DELAY; + } + if (End == 1000) { + mvaddstr(8, temp, "20"); + tot += SC_EXTENSION; + } + if (Player[other(num)].mileage == 0) { + mvaddstr(9, temp, "50"); + tot += SC_SHUT_OUT; + } + pp->total += tot; + pp->hand_tot += tot; + } +} + +# ifdef EXTRAP +static int Last_tot[2]; /* last tot used for extrapolate */ + +/* + * print out the score as if it was final, and add the totals for + * the end-of-games points to the user who deserves it (if any). + */ +extrapolate(pp) +reg PLAY *pp; { + + reg int x, num, tot, count; + + num = pp - Player; + tot += SC_TRIP + SC_DELAY + SC_EXT; + x = num * 6 + 21 + 3; + for (tot = 5; tot <= 9; tot++) + mvaddch(tot, x, '0'); + x -= 2; + pp = &Player[other(num)]; + for (count = 0, tot = 0; tot < NUM_SAFE; tot++) + if (pp->safety[tot] != S_PLAYED) + count += SC_SAFE; + mvprintw(3, x, "%3d", count); + tot += count; + if (count == 400) { + mvaddstr(4, x, "30"); + tot += SC_ALL_SAFE; + } + pp = &Player[num]; + for (count = 0, tot = 0; tot < NUM_SAFE; tot++) + if (pp->safety[tot] != S_PLAYED) + count += SC_COUP / 10; + mvprintw(4, x - 1, "%3d", count); + tot += count; + tot += 1000 - pp->mileage; + mvaddstr(5, x, "40"); + mvaddstr(7, x, "30"); + mvaddstr(8, x, "20"); + if (pp->nummiles[C_200] == 0) { + mvaddstr(6, x, "30"); + tot = SC_TRIP + SC_SAFE; + } + if (Player[other(num)].mileage == 0) { + mvaddstr(9, x, "50"); + tot += SC_SHUT_OUT; + } + pp->total += tot; + pp->hand_tot += tot; + Last_tot[num] = tot; +} + +undoex() { + + reg PLAY *pp; + reg int i; + + i = 0; + for (pp = Player; pp < &Player[2]; pp++) { + pp->total -= Last_tot[i]; + pp->hand_tot -= Last_tot[i++]; + } +} +# endif + diff --git a/src/games/mille/extern.c b/src/games/mille/extern.c new file mode 100644 index 0000000..d762c81 --- /dev/null +++ b/src/games/mille/extern.c @@ -0,0 +1,135 @@ +# include "mille.h" + +/* + * @(#)extern.c 1.1 (Berkeley) 4/1/82 + */ + +bool Debug, /* set if debugging code on */ + Finished, /* set if current hand is finished */ + Next, /* set if changing players */ + On_exit, /* set if game saved on exiting */ + Order, /* set if hand should be sorted */ + Saved; /* set if game just saved */ + +char *C_fmt = "%-18.18s", /* format for printing cards */ + *Fromfile = NULL, /* startup file for game */ + Initstr[100], /* initial string for error field */ + *_cn[NUM_CARDS] = { /* Card name buffer */ + "", + "25", + "50", + "75", + "100", + "200", + "Out of Gas", + "Flat Tire", + "Accident", + "Stop", + "Speed Limit", + "Gasoline", + "Spare Tire", + "Repairs", + "Go", + "End of Limit", + "Extra Tank", + "Puncture Proof", + "Driving Ace", + "Right of Way" + }, + **C_name = &_cn[1]; /* Card names */ + +int Card_no, /* Card number for current move */ + End, /* End value for current hand */ + Handstart = COMP, /* Player who starts hand */ + Movetype, /* Current move type */ + Play, /* Current player */ + Numgos, /* Number of Go cards used by computer */ + Window = W_SMALL, /* Current window wanted */ + Numseen[NUM_CARDS], /* Number of cards seen in current hand */ + Value[NUM_MILES] = { /* Value of mileage cards */ + 25, 50, 75, 100, 200 + }, + Numcards[NUM_CARDS] = { /* Number of cards in deck */ + 10, /* C_25 */ + 10, /* C_50 */ + 10, /* C_75 */ + 12, /* C_100 */ + 4, /* C_200 */ + 2, /* C_EMPTY */ + 2, /* C_FLAT */ + 2, /* C_CRASH */ + 4, /* C_STOP */ + 3, /* C_LIMIT */ + 6, /* C_GAS */ + 6, /* C_SPARE */ + 6, /* C_REPAIRS */ + 14, /* C_GO */ + 6, /* C_END_LIMIT */ + 1, /* C_GAS_SAFE */ + 1, /* C_SPARE_SAFE */ + 1, /* C_DRIVE_SAFE */ + 1, /* C_RIGHT_WAY */ + 0 /* C_INIT */ + }; + Numneed[NUM_CARDS] = { /* number of cards needed per hand */ + 0, /* C_25 */ + 0, /* C_50 */ + 0, /* C_75 */ + 0, /* C_100 */ + 0, /* C_200 */ + 2, /* C_EMPTY */ + 2, /* C_FLAT */ + 2, /* C_CRASH */ + 4, /* C_STOP */ + 3, /* C_LIMIT */ + 2, /* C_GAS */ + 2, /* C_SPARE */ + 2, /* C_REPAIRS */ + 10, /* C_GO */ + 3, /* C_END_LIMIT */ + 1, /* C_GAS_SAFE */ + 1, /* C_SPARE_SAFE */ + 1, /* C_DRIVE_SAFE */ + 1, /* C_RIGHT_WAY */ + 0 /* C_INIT */ + }; + +CARD Discard, /* Top of discard pile */ + Sh_discard, /* Last discard card shown */ + *Topcard, /* Pointer to next card to be picked */ + Opposite[NUM_CARDS] = { /* Opposites of each card */ + C_25, C_50, C_75, C_100, C_200, C_GAS, C_SPARE, + C_REPAIRS, C_GO, C_END_LIMIT, C_EMPTY, C_FLAT, C_CRASH, + C_STOP, C_LIMIT, C_EMPTY, C_FLAT, C_CRASH, C_STOP, C_INIT + }, + Deck[DECK_SZ] = { /* Current deck */ + C_25, C_25, C_25, C_25, C_25, C_25, C_25, C_25, C_25, C_25, + C_50, C_50, C_50, C_50, C_50, C_50, C_50, C_50, C_50, C_50, + C_75, C_75, C_75, C_75, C_75, C_75, C_75, C_75, C_75, C_75, + C_100, C_100, C_100, C_100, C_100, C_100, C_100, C_100, C_100, + C_100, C_100, C_100, + C_200, C_200, C_200, C_200, + C_EMPTY, C_EMPTY, + C_FLAT, C_FLAT, + C_CRASH, C_CRASH, + C_STOP, C_STOP, C_STOP, C_STOP, + C_LIMIT, C_LIMIT, C_LIMIT, + C_GAS, C_GAS, C_GAS, C_GAS, C_GAS, C_GAS, + C_SPARE, C_SPARE, C_SPARE, C_SPARE, C_SPARE, C_SPARE, + C_REPAIRS, C_REPAIRS, C_REPAIRS, C_REPAIRS, C_REPAIRS, + C_REPAIRS, + C_END_LIMIT, C_END_LIMIT, C_END_LIMIT, C_END_LIMIT, C_END_LIMIT, + C_END_LIMIT, + C_GO, C_GO, C_GO, C_GO, C_GO, C_GO, C_GO, C_GO, C_GO, C_GO, + C_GO, C_GO, C_GO, C_GO, + C_GAS_SAFE, C_SPARE_SAFE, C_DRIVE_SAFE, C_RIGHT_WAY + }; + +FILE *outf; + +PLAY Player[2]; /* Player descriptions */ + +WINDOW *Board, /* Playing field screen */ + *Miles, /* Mileage screen */ + *Score; /* Score screen */ + diff --git a/src/games/mille/init.c b/src/games/mille/init.c new file mode 100644 index 0000000..32e90e9 --- /dev/null +++ b/src/games/mille/init.c @@ -0,0 +1,214 @@ +# include "mille.h" + +/* + * @(#)init.c 1.1 (Berkeley) 4/1/82 + */ + +init() { + + reg PLAY *pp; + reg int i, j; + reg CARD card; + + bzero(Numseen, sizeof Numseen); + Numgos = 0; + + for (i = 0; i < 2; i++) { + pp = &Player[i]; + pp->hand[0] = C_INIT; + for (j = 0; j < NUM_SAFE; j++) { + pp->safety[j] = S_UNKNOWN; + pp->coups[j] = FALSE; + } + for (j = 1; j < HAND_SZ; j++) { + pp->hand[j] = *--Topcard; + if (i == COMP) { + account(card = *Topcard); + if (issafety(card)) + pp->safety[card - S_CONV] = S_IN_HAND; + } + } + pp->mileage = 0; + pp->hand_tot = 0; + pp->safescore = 0; + pp->coupscore = 0; + pp->can_go = FALSE; + pp->speed = C_INIT; + pp->battle = C_INIT; + pp->new_speed = FALSE; + pp->new_battle = FALSE; + for (j = 0; j < NUM_MILES; j++) + pp->nummiles[j] = 0; + } + if (Order) + sort(Player[PLAYER].hand); + Discard = C_INIT; + Finished = FALSE; + End = 700; +} + +shuffle() { + + reg int i, r; + reg CARD temp; + + for (i = 0; i < DECK_SZ; i++) { + r = roll(1, DECK_SZ) - 1; + if (r < 0 || r > DECK_SZ - 1) { + fprintf(stderr, "shuffle: card no. error: %d\n", r); + die(); + } + temp = Deck[r]; + Deck[r] = Deck[i]; + Deck[i] = temp; + } + Topcard = &Deck[DECK_SZ]; +} + +newboard() { + + register int i; + register PLAY *pp; + static int first = TRUE; + + if (first) { + werase(Board); + werase(Score); + mvaddstr(5, 0, "--HAND--"); + mvaddch(6, 0, 'P'); + mvaddch(7, 0, '1'); + mvaddch(8, 0, '2'); + mvaddch(9, 0, '3'); + mvaddch(10, 0, '4'); + mvaddch(11, 0, '5'); + mvaddch(12, 0, '6'); + mvaddstr(13, 0, "--BATTLE--"); + mvaddstr(15, 0, "--SPEED--"); + mvaddstr(5, 20, "--DECK--"); + mvaddstr(7, 20, "--DISCARD--"); + mvaddstr(13, 20, "--BATTLE--"); + mvaddstr(15, 20, "--SPEED--"); + mvwaddstr(Miles, 0, 0, "--MILEAGE--"); + mvwaddstr(Miles, 0, 41, "--MILEAGE--"); + Sh_discard = -1; + for (pp = Player; pp <= &Player[COMP]; pp++) { + for (i = 0; i < HAND_SZ; i++) + pp->sh_hand[i] = -1; + pp->sh_battle = -1; + pp->sh_speed = -1; + pp->sh_mileage = -1; + } + first = FALSE; + } + else { + for (i = 0; i < 5; i++) { + move(i, 0); + clrtoeol(); + } + wmove(Miles, 1, 0); + wclrtobot(Miles); + wmove(Board, MOVE_Y + 1, MOVE_X); + wclrtoeol(Board); + wmove(Board, MOVE_Y + 2, MOVE_X); + wclrtoeol(Board); + } + Sh_discard = -1; + for (pp = Player; pp <= &Player[COMP]; pp++) { + for (i = 0; i < NUM_SAFE; i++) + pp->sh_safety[i] = FALSE; + for (i = 0; i < NUM_MILES; i++) + pp->sh_nummiles[i] = 0; + pp->sh_safescore = -1; + } + newscore(); +} + +newscore() { + + reg int i, new; + register PLAY *pp; + static int was_full = -1; + static int last_win = -1; + + if (was_full < 0) + was_full = (Window != W_FULL); + stdscr = Score; + move(0, 22); + new = FALSE; + if (inch() != 'Y') { + erase(); + mvaddstr(0, 22, "You Comp Value"); + mvaddstr(1, 2, "Milestones Played"); + mvaddstr(2, 8, "Each Safety"); + mvaddstr(3, 5, "All 4 Safeties"); + mvaddstr(4, 3, "Each Coup Fourre"); + mvaddstr(2, 37, "100"); + mvaddstr(3, 37, "300"); + mvaddstr(4, 37, "300"); + new = TRUE; + } + else if (((Window == W_FULL || Finished) ^ was_full) || + pp->was_finished != Finished) { + move(5, 1); + clrtobot(); + new = TRUE; + } + else if (Window != last_win) + new = TRUE; + if (new) { + for (i = 0; i < SCORE_Y; i++) + mvaddch(i, 0, '|'); + move(SCORE_Y - 1, 1); + while (addch('_') != ERR) + continue; + for (pp = Player; pp <= &Player[COMP]; pp++) { + pp->sh_hand_tot = -1; + pp->sh_total = -1; + pp->sh_games = -1; + pp->sh_safescore = -1; + } + } + Player[PLAYER].was_finished = !Finished; + Player[COMP].was_finished = !Finished; + if (Window == W_FULL || Finished) { + if (!was_full || new) { + mvaddstr(5, 5, "Trip Completed"); + mvaddstr(6, 10, "Safe Trip"); + mvaddstr(7, 5, "Delayed Action"); + mvaddstr(8, 10, "Extension"); + mvaddstr(9, 11, "Shut-Out"); + mvaddstr(10, 21, "---- ---- -----"); + mvaddstr(11, 9, "Hand Total"); + mvaddstr(12, 20, "----- -----"); + mvaddstr(13, 6, "Overall Total"); + mvaddstr(14, 15, "Games"); + mvaddstr(5, 37, "400"); + mvaddstr(6, 37, "300"); + mvaddstr(7, 37, "300"); + mvaddstr(8, 37, "200"); + mvaddstr(9, 37, "500"); + } + } + else + if (was_full || new) { + mvaddstr(5, 21, "---- ---- -----"); + mvaddstr(6, 9, "Hand Total"); + mvaddstr(7, 20, "----- -----"); + mvaddstr(8, 6, "Overall Total"); + mvaddstr(9, 15, "Games"); + mvaddstr(11, 2, "p: pick"); + mvaddstr(12, 2, "u: use #"); + mvaddstr(13, 2, "d: discard #"); + mvaddstr(14, 2, "w: toggle window"); + mvaddstr(11, 21, "q: quit"); + if (!Order) + mvaddstr(12, 21, "o: order hand"); + else + mvaddstr(12, 21, "o: stop ordering"); + mvaddstr(13, 21, "s: save"); + mvaddstr(14, 21, "r: reprint"); + } + stdscr = Board; + was_full = (Window == W_FULL || Finished); + last_win = Window; +} diff --git a/src/games/mille/mille.6 b/src/games/mille/mille.6 new file mode 100644 index 0000000..f83bdc5 --- /dev/null +++ b/src/games/mille/mille.6 @@ -0,0 +1,351 @@ +.\" Copyright (c) 1980 Regents of the University of California. +.\" All rights reserved. The Berkeley software License Agreement +.\" specifies the terms and conditions for redistribution. +.\" +.\" @(#)mille.6 6.2 (Berkeley) 5/6/86 +.\" +.TH MILLE 6 "May 6, 1986" +.UC 4 +.SH NAME +mille \- play Mille Bournes +.SH SYNOPSIS +.B /usr/games/mille +[ file ] +.SH DESCRIPTION +.I Mille +plays a two-handed game reminiscent of +the Parker Brother's game of Mille Bournes with you. +The rules are described below. +If a file name is given on the command line, +the game saved in that file is started. +.PP +When a game is started up, +the bottom of the score window will contain a list of commands. +They are: +.IP P +Pick a card from the deck. +This card is placed in the `P' slot in your hand. +.IP D +Discard a card from your hand. +To indicate which card, type the number of the card in the hand +(or \*(lqP\*(rq for the just-picked card) followed by a or . +The is required to allow recovery from typos +which can be very expensive, like discarding safeties. +.IP U +Use a card. +The card is again indicated by its number, followed by a or . +.IP O +Toggle ordering the hand. +By default off, if turned on it will sort the cards in your hand appropriately. +This is not recommended for the impatient on slow terminals. +.IP Q +Quit the game. +This will ask for confirmation, just to be sure. +Hitting (or ) is equivalent. +.IP S +Save the game in a file. +If the game was started from a file, +you will be given an opportunity to save it on the same file. +If you don't wish to, or you did not start from a file, +you will be asked for the file name. +If you type a without a name, +the save will be terminated and the game resumed. +.IP R +Redraw the screen from scratch. +The command ^L (control `L') will also work. +.IP W +Toggle window type. +This switches the score window between the startup window +(with all the command names) and the end-of-game window. +Using the end-of-game window +saves time by eliminating the switch at the end of the game +to show the final score. +Recommended for hackers and other miscreants. +.PP +If you make a mistake, an error message will be printed +on the last line of the score window, and a bell will beep. +.PP +At the end of each hand or game, +you will be asked if you wish to play another. +If not, it will ask you if you want to save the game. +If you do, and the save is unsuccessful, +play will be resumed as if you had said you wanted to play another hand/game. +This allows you to use the +.RB \*(lq S \*(rq +command to reattempt the save. +.SH AUTHOR +Ken Arnold +.br +(The game itself is a product of Parker Brothers, Inc.) +.SH "SEE ALSO" +curses(3X), +.I "Screen Updating and Cursor Movement Optimization:" +.IR "A Library Package" , +Ken Arnold +.SH CARDS +.PP +Here is some useful information. +The number in parentheses after the card name +is the number of that card in the deck: +.sp +.nf +.ne 10 +.ta \w'Speed Limit (3)'u+3n \w'Speed Limit (3)'u+\w'End of Limit (6)'u+6n +Hazard Repair Safety +.sp +Out of Gas (2) Gasoline (6) Extra Tank (1) +Flat Tire (2) Spare Tire (6) Puncture Proof (1) +Accident (2) Repairs (6) Driving Ace (1) +Stop (4) Go (14) Right of Way (1) +Speed Limit (3) End of Limit (6) +.sp +.ce +25 \- (10), 50 \- (10), 75 \- (10), 100 \- (12), 200 \- (4) +.sp +.fi +.DT +.SH RULES +.PP +.BR Object : +The point of this game is to get a total of 5000 points in several hands. +Each hand is a race to put down exactly 700 miles before your opponent does. +Beyond the points gained by putting down milestones, +there are several other ways of making points. +.PP +.BR Overview : +The game is played with a deck of 101 cards. +.I Distance +cards represent a number of miles traveled. +They come in denominations of 25, 50, 75, 100, and 200. +When one is played, +it adds that many miles to the player's trip so far this hand. +.I Hazard +cards are used to prevent your opponent from putting down Distance cards. +They can only be played if your opponent has a +.I Go +card on top of the Battle pile. +The cards are +.IR "Out of Gas" , +.IR "Accident" , +.IR "Flat Tire" , +.IR "Speed Limit" , +and +.IR "Stop" . +.I Remedy +cards fix problems caused by Hazard cards played on you by your opponent. +The cards are +.IR "Gasoline" , +.IR "Repairs" , +.IR "Spare Tire" , +.IR "End of Limit" , +and +.IR "Go" . +.I Safety +cards prevent your opponent from putting specific Hazard cards on you +in the first place. +They are +.IR "Extra Tank" , +.IR "Driving Ace" , +.IR "Puncture Proof" , +and +.IR "Right of Way" , +and there are only one of each in the deck. +.PP +.BR "Board Layout" : +The board is split into several areas. +From top to bottom, they are: +.B "SAFETY AREA" +(unlabeled): This is where the safeties will be placed as they are played. +.BR HAND : +These are the cards in your hand. +.BR BATTLE : +This is the Battle pile. +All the Hazard and Remedy Cards are played here, except the +.I "Speed Limit" +and +.I "End of Limit" +cards. Only the top card is displayed, as it is the only effective one. +.BR SPEED : +The Speed pile. The +.I "Speed Limit" +and +.I "End of Limit" +cards are played here +to control the speed at which the player is allowed to put down miles. +.BR MILEAGE : +Miles are placed here. +The total of the numbers shown here is the distance traveled so far. +.PP +.BR Play : +The first pick alternates between the two players. +Each turn usually starts with a pick from the deck. +The player then plays a card, or if this is not possible or desirable, +discards one. Normally, a play or discard of a single card +constitutes a turn. If the card played is a safety, however, +the same player takes another turn immediately. +.PP +This repeats until one of the players reaches 700 points or the deck runs out. +If someone reaches 700, they have the option of going for an +.IR Extension , +which means that the play continues until someone reaches 1000 miles. +.PP +.BR "Hazard and Remedy Cards" : +Hazard Cards are played on your opponent's Battle and Speed piles. +Remedy Cards are used for undoing the effects of your opponent's nastiness. +.PP +.RB "\ \ \ \ " Go +(Green Light) +must be the top card on your Battle pile for you to play any mileage, +unless you have played the +.I "Right of Way" +card (see below). +.br +.RB "\ \ \ \ " Stop +is played on your opponent's +.I Go +card to prevent them from playing mileage until they play a +.I Go +card. +.br +.RB "\ \ \ \ " "Speed Limit" +is played on your opponent's Speed pile. +Until they play an +.I "End of Limit" +they can only play 25 or 50 mile cards, presuming their +.I Go +card allows them to do even that. +.br +.RB "\ \ \ \ " "End of Limit" +is played on your Speed pile to nullify a +.I "Speed Limit" +played by your opponent. +.br +.RB "\ \ \ \ " "Out of Gas" +is played on your opponent's +.I Go +card. They must then play a +.I Gasoline +card, and then a +.I Go +card before they can play any more mileage. +.br +.RB "\ \ \ \ " "Flat Tire" +is played on your opponent's +.I Go +card. They must then play a +.I "Spare Tire" +card, and then a +.I Go +card before they can play any more mileage. +.br +.RB "\ \ \ \ " "Accident" +is played on your opponent's +.I Go +card. They must then play a +.I Repairs +card, and then a +.I Go +card before they can play any more mileage. +.br +.PP +.BR "Safety Cards" : +Safety cards prevent your opponent +from playing the corresponding Hazard cards on you for the rest of the hand. +It cancels an attack in progress, and +.IR "always entitles the player to an extra turn" . +.br +.RB "\ \ \ \ " "Right of Way" +prevents your opponent from playing both +.I Stop +and +.I "Speed Limit" +cards on you. It also acts as a permanent +.I Go +card for the rest of the hand, so you can play mileage +as long as there is not a Hazard card on top of your Battle pile. +In this case only, your opponent can play Hazard cards directly on a Remedy card +other than a Go card. +.br +.RB "\ \ \ \ " "Extra Tank" +When played, your opponent cannot play an +.I "Out of Gas" +on your Battle Pile. +.br +.RB "\ \ \ \ " "Puncture Proof" +When played, your opponent cannot play a +.I "Flat Tire" +on your Battle Pile. +.br +.RB "\ \ \ \ " "Driving Ace" +When played, your opponent cannot play an +.I Accident +on your Battle Pile. +.PP +.BR "Distance Cards" : +Distance cards are played when you have a +.I Go +card on your Battle pile, +or a Right of Way in your Safety area and are not stopped by a Hazard Card. +They can be played in any combination that totals exactly 700 miles, +except that +.IR "you cannot play more than two 200 mile cards in one hand" . +A hand ends whenever one player gets exactly 700 miles or the deck runs out. +In that case, play continues until neither someone reaches 700, +or neither player can use any cards in their hand. +If the trip is completed after the deck runs out, this is called +.IR "Delayed Action" . +.PP +.BR "Coup Fourr\o'\(aae'" : +This is a French fencing term for a counter-thrust move as part of a parry +to an opponents attack. +In Mille Bournes, it is used as follows: +If an opponent plays a Hazard card, +and you have the corresponding Safety in your hand, +you play it immediately, even +.I before +you draw. This immediately removes the Hazard card from your Battle pile, +and protects you from that card for the rest of the game. This +gives you more points (see \*(lqScoring\*(rq below). +.PP +.BR Scoring : +Scores are totaled at the end of each hand, +whether or not anyone completed the trip. +The terms used in the Score window have the following meanings: +.br +.RB "\ \ \ \ " "Milestones Played" : +Each player scores as many miles as they played before the trip ended. +.br +.RB "\ \ \ \ " "Each Safety" : +100 points for each safety in the Safety area. +.br +.RB "\ \ \ \ " "All 4 Safeties" : +300 points if all four safeties are played. +.br +.RB "\ \ \ \ " "Each Coup Four\o'\(aae'" : +300 points for each Coup Four\o'\(aae' accomplished. +.PP +The following bonus scores can apply only to the winning player. +.br +.RB "\ \ \ \ " "Trip Completed" : +400 points bonus for completing the trip to 700 or 1000. +.br +.RB "\ \ \ \ " "Safe Trip" : +300 points bonus for completing the trip without using any 200 mile cards. +.br +.RB "\ \ \ \ " "Delayed Action" : +300 points bonus for finishing after the deck was exhausted. +.br +.RB "\ \ \ \ " "Extension" : +200 points bonus for completing a 1000 mile trip. +.br +.RB "\ \ \ \ " "Shut-Out" : +500 points bonus for completing the trip +before your opponent played any mileage cards. +.PP +Running totals are also kept for the current score for each player +for the hand +.RB ( "Hand Total" ), +the game +.RB ( "Overall Total" ), +and number of games won +.RB ( Games ). diff --git a/src/games/mille/mille.c b/src/games/mille/mille.c new file mode 100644 index 0000000..55d9673 --- /dev/null +++ b/src/games/mille/mille.c @@ -0,0 +1,135 @@ +# include "mille.h" +# include +# ifdef attron +# include +# endif attron + +/* + * @(#)mille.c 1.3.1 (2.11BSD GTE) 1/16/95 + */ + +int rub(); + +char _sobuf[BUFSIZ]; + +main(ac, av) +reg int ac; +reg char *av[]; { + + reg bool restore; + double avs[3]; + + if (strcmp(av[0], "a.out") == 0) { + outf = fopen("q", "w"); + setbuf(outf, NULL); + Debug = TRUE; + } + restore = FALSE; + + getloadavg(avs, 3); + if (avs[2] > 4.0) { + printf("Sorry. The load average is too high.\n"); + printf("Please try again later\n"); + exit(1); + } + + switch (ac) { + case 2: + rest_f(av[1]); + restore = TRUE; + case 1: + break; + default: + printf("usage: milles [ restore_file ]\n"); + exit(-1); + /* NOTREACHED */ + } + setbuf(stdout, _sobuf); + Play = PLAYER; + initscr(); +# ifdef attron +# define CA cursor_address +# endif + if (!CA) { + printf("Sorry. Need cursor addressing to play mille\n"); + exit(-1); + } + delwin(stdscr); + stdscr = Board = newwin(BOARD_Y, BOARD_X, 0, 0); + Score = newwin(SCORE_Y, SCORE_X, 0, 40); + Miles = newwin(MILES_Y, MILES_X, 17, 0); +#ifdef attron + idlok(Board, TRUE); + idlok(Score, TRUE); + idlok(Miles, TRUE); +#endif + leaveok(Score, TRUE); + leaveok(Miles, TRUE); + clearok(curscr, TRUE); +# ifndef PROF + srandom(getpid()); +# else + srandom(0); +# endif + crmode(); + noecho(); + signal(SIGINT, rub); + for (;;) { + if (!restore || (Player[PLAYER].total >= 5000 + || Player[COMP].total >= 5000)) { + if (Player[COMP].total < Player[PLAYER].total) + Player[PLAYER].games++; + else if (Player[COMP].total > Player[PLAYER].total) + Player[COMP].games++; + Player[COMP].total = 0; + Player[PLAYER].total = 0; + } + do { + if (!restore) + Handstart = Play = other(Handstart); + if (!restore || On_exit) { + shuffle(); + init(); + } + newboard(); + if (restore) + mvwaddstr(Score, ERR_Y, ERR_X, Initstr); + prboard(); + do { + domove(); + if (Finished) + newscore(); + prboard(); + } while (!Finished); + check_more(); + restore = On_exit = FALSE; + } while (Player[COMP].total < 5000 + && Player[PLAYER].total < 5000); + } +} + +/* + * Routine to trap rubouts, and make sure they really want to + * quit. + */ +rub() { + + signal(SIGINT, SIG_IGN); + if (getyn(REALLYPROMPT)) + die(); + signal(SIGINT, rub); +} + +/* + * Time to go beddy-by + */ +die() { + + signal(SIGINT, SIG_IGN); + if (outf) + fflush(outf); + mvcur(0, COLS - 1, LINES - 1, 0); + endwin(); + exit(1); +} + diff --git a/src/games/mille/mille.h b/src/games/mille/mille.h new file mode 100644 index 0000000..433e080 --- /dev/null +++ b/src/games/mille/mille.h @@ -0,0 +1,195 @@ +# include +# include "curses.h" + +/* + * @(#)mille.h 1.1 (Berkeley) 4/1/82 + */ + +/* + * Miscellaneous constants + */ + +# define unsgn unsigned +# define CARD short + +# define ARNOLD 214 /* my uid */ + +# define GURP 28672 /* bad uid */ +# define MAXUSERS 35 /* max # of users for startup */ +# define HAND_SZ 7 /* number of cards in a hand */ +# define DECK_SZ 101 /* number of cards in decks */ +# define NUM_SAFE 4 /* number of saftey cards */ +# define NUM_MILES 5 /* number of milestones types */ +# define NUM_CARDS 20 /* number of types of cards */ +# define BOARD_Y 17 /* size of board screen */ +# define BOARD_X 40 +# define MILES_Y 7 /* size of mileage screen */ +# define MILES_X 80 +# define SCORE_Y 17 /* size of score screen */ +# define SCORE_X 40 +# define MOVE_Y 10 /* Where to print move prompt */ +# define MOVE_X 20 +# define ERR_Y 15 /* Where to print errors */ +# define ERR_X 5 +# define EXT_Y 4 /* Where to put Extension */ +# define EXT_X 9 + +# define PLAYER 0 +# define COMP 1 + +# define W_SMALL 0 /* Small (initial) window */ +# define W_FULL 1 /* Full (final) window */ + +/* + * Move types + */ + +# define M_DISCARD 0 +# define M_DRAW 1 +# define M_PLAY 2 +# define M_ORDER 3 + +/* + * Scores + */ + +# define SC_SAFETY 100 +# define SC_ALL_SAFE 300 +# define SC_COUP 300 +# define SC_TRIP 400 +# define SC_SAFE 300 +# define SC_DELAY 300 +# define SC_EXTENSION 200 +# define SC_SHUT_OUT 500 + +/* + * safety descriptions + */ + +# define S_UNKNOWN 0 /* location of safety unknown */ +# define S_IN_HAND 1 /* safety in player's hand */ +# define S_PLAYED 2 /* safety has been played */ +# define S_GAS_SAFE 0 /* Gas safety card index */ +# define S_SPARE_SAFE 1 /* Tire safety card index */ +# define S_DRIVE_SAFE 2 /* Driveing safety card index */ +# define S_RIGHT_WAY 3 /* Right-of-Way card index */ +# define S_CONV 15 /* conversion from C_ to S_ */ + +/* + * card numbers + */ + +# define C_INIT -1 +# define C_25 0 +# define C_50 1 +# define C_75 2 +# define C_100 3 +# define C_200 4 +# define C_EMPTY 5 +# define C_FLAT 6 +# define C_CRASH 7 +# define C_STOP 8 +# define C_LIMIT 9 +# define C_GAS 10 +# define C_SPARE 11 +# define C_REPAIRS 12 +# define C_GO 13 +# define C_END_LIMIT 14 +# define C_GAS_SAFE 15 +# define C_SPARE_SAFE 16 +# define C_DRIVE_SAFE 17 +# define C_RIGHT_WAY 18 + +/* + * prompt types + */ + +# define MOVEPROMPT 0 +# define REALLYPROMPT 1 +# define ANOTHERHANDPROMPT 2 +# define ANOTHERGAMEPROMPT 3 +# define SAVEGAMEPROMPT 4 +# define SAMEFILEPROMPT 5 +# define FILEPROMPT 6 +# define EXTENSIONPROMPT 7 +# define OVERWRITEFILEPROMPT 8 + +# ifdef SYSV +# define srandom(x) srand(x) +# define random() rand() + +# ifndef attron +# define erasechar() _tty.c_cc[VERASE] +# define killchar() _tty.c_cc[VKILL] +# endif +# else +# ifndef erasechar +# define erasechar() _tty.sg_erase +# define killchar() _tty.sg_kill +# endif +# endif SYSV + +typedef struct { + bool coups[NUM_SAFE]; + bool can_go; + bool new_battle; + bool new_speed; + short safety[NUM_SAFE]; + short sh_safety[NUM_SAFE]; + short nummiles[NUM_MILES]; + short sh_nummiles[NUM_MILES]; + CARD hand[HAND_SZ]; + CARD sh_hand[HAND_SZ]; + CARD battle; + CARD sh_battle; + CARD speed; + CARD sh_speed; + int mileage; + int sh_mileage; + int hand_tot; + int sh_hand_tot; + int safescore; + int sh_safescore; + int coupscore; + int total; + int sh_total; + int games; + int sh_games; + int was_finished; +} PLAY; + +/* + * macros + */ + +# define other(x) (1 - x) +# define nextplay() (Play = other(Play)) +# define nextwin(x) (1 - x) +# define opposite(x) (Opposite[x]) +# define issafety(x) (x >= C_GAS_SAFE) + +/* + * externals + */ + +extern bool Debug, Finished, Next, On_exit, Order, Saved; + +extern char *C_fmt, **C_name, *Fromfile, Initstr[]; + +extern int Card_no, End, Handstart, Movetype, Numcards[], Numgos, + Numneed[], Numseen[NUM_CARDS], Play, Value[], Window; + +extern CARD Deck[DECK_SZ], Discard, Opposite[NUM_CARDS], Sh_discard, + *Topcard; + +extern FILE *outf; + +extern PLAY Player[2]; + +extern WINDOW *Board, *Miles, *Score; + +/* + * functions + */ + +CARD getcard(); diff --git a/src/games/mille/misc.c b/src/games/mille/misc.c new file mode 100644 index 0000000..0dc04d1 --- /dev/null +++ b/src/games/mille/misc.c @@ -0,0 +1,224 @@ +#include "mille.h" +#ifndef unctrl +#include "unctrl.h" +#endif + +# include + +# ifdef attron +# include +# define _tty cur_term->Nttyb +# endif attron + +/* + * @(#)misc.c 1.2 (Berkeley) 3/28/83 + */ + +#define NUMSAFE 4 + +/* VARARGS1 */ +error(str, arg) +char *str; +{ + stdscr = Score; + mvprintw(ERR_Y, ERR_X, str, arg); + clrtoeol(); + putchar(''); + refresh(); + stdscr = Board; + return FALSE; +} + +CARD +getcard() +{ + reg int c, c1; + + for (;;) { + while ((c = readch()) == '\n' || c == '\r' || c == ' ') + continue; + if (islower(c)) + c = toupper(c); + if (c == killchar() || c == erasechar()) + return -1; + addstr(unctrl(c)); + clrtoeol(); + switch (c) { + case '1': case '2': case '3': + case '4': case '5': case '6': + c -= '0'; + break; + case '0': case 'P': case 'p': + c = 0; + break; + default: + putchar(''); + addch('\b'); + if (!isprint(c)) + addch('\b'); + c = -1; + break; + } + refresh(); + if (c >= 0) { + while ((c1=readch()) != '\r' && c1 != '\n' && c1 != ' ') + if (c1 == killchar()) + return -1; + else if (c1 == erasechar()) { + addch('\b'); + clrtoeol(); + refresh(); + goto cont; + } + else + write(0, "", 1); + return c; + } +cont: ; + } +} + +check_ext(forcomp) +reg bool forcomp; { + + + if (End == 700) + if (Play == PLAYER) { + if (getyn(EXTENSIONPROMPT)) { +extend: + if (!forcomp) + End = 1000; + return TRUE; + } + else { +done: + if (!forcomp) + Finished = TRUE; + return FALSE; + } + } + else { + reg PLAY *pp, *op; + reg int i, safe, miles; + + pp = &Player[COMP]; + op = &Player[PLAYER]; + for (safe = 0, i = 0; i < NUMSAFE; i++) + if (pp->safety[i] != S_UNKNOWN) + safe++; + if (safe < 2) + goto done; + if (op->mileage == 0 || onecard(op) + || (op->can_go && op->mileage >= 500)) + goto done; + for (miles = 0, i = 0; i < NUMSAFE; i++) + if (op->safety[i] != S_PLAYED + && pp->safety[i] == S_UNKNOWN) + miles++; + if (miles + safe == NUMSAFE) + goto extend; + for (miles = 0, i = 0; i < HAND_SZ; i++) + if ((safe = pp->hand[i]) <= C_200) + miles += Value[safe]; + if (miles + (Topcard - Deck) * 3 > 1000) + goto extend; + goto done; + } + else + goto done; +} + +/* + * Get a yes or no answer to the given question. Saves are + * also allowed. Return TRUE if the answer was yes, FALSE if no. + */ +getyn(promptno) +register int promptno; { + + reg char c; + + Saved = FALSE; + for (;;) { + leaveok(Board, FALSE); + prompt(promptno); + clrtoeol(); + refresh(); + switch (c = readch()) { + case 'n': case 'N': + addch('N'); + refresh(); + leaveok(Board, TRUE); + return FALSE; + case 'y': case 'Y': + addch('Y'); + refresh(); + leaveok(Board, TRUE); + return TRUE; + case 's': case 'S': + addch('S'); + refresh(); + Saved = save(); + continue; + default: + addstr(unctrl(c)); + refresh(); + putchar(''); + break; + } + } +} + +/* + * Check to see if more games are desired. If not, and game + * came from a saved file, make sure that they don't want to restore + * it. Exit appropriately. + */ +check_more() { + + flush_input(); + + On_exit = TRUE; + if (Player[PLAYER].total >= 5000 || Player[COMP].total >= 5000) + if (getyn(ANOTHERGAMEPROMPT)) + return; + else { + /* + * must do accounting normally done in main() + */ + if (Player[PLAYER].total > Player[COMP].total) + Player[PLAYER].games++; + else if (Player[PLAYER].total < Player[COMP].total) + Player[COMP].games++; + Player[COMP].total = 0; + Player[PLAYER].total = 0; + } + else + if (getyn(ANOTHERHANDPROMPT)) + return; + if (!Saved && getyn(SAVEGAMEPROMPT)) + if (!save()) + return; + die(); +} + +readch() +{ + reg int cnt; + static char c; + + for (cnt = 0; read(0, &c, 1) <= 0; cnt++) + if (cnt > 100) + exit(1); + return c; +} + +flush_input() +{ +# ifdef TIOCFLUSH + static int ioctl_args = FREAD; + + (void) ioctl(fileno(stdin), TIOCFLUSH, &ioctl_args); +# else + fflush(stdin); +# endif +} diff --git a/src/games/mille/move.c b/src/games/mille/move.c new file mode 100644 index 0000000..3be57fc --- /dev/null +++ b/src/games/mille/move.c @@ -0,0 +1,517 @@ +#include "mille.h" +#ifndef unctrl +#include "unctrl.h" +#endif + +# ifdef attron +# include +# define _tty cur_term->Nttyb +# endif attron + +/* + * @(#)move.c 1.2 (Berkeley) 3/28/83 + */ + +#undef CTRL +#define CTRL(c) (c - 'A' + 1) + +char *Movenames[] = { + "M_DISCARD", "M_DRAW", "M_PLAY", "M_ORDER" + }; + +domove() +{ + reg PLAY *pp; + reg int i, j; + reg bool goodplay; + + pp = &Player[Play]; + if (Play == PLAYER) + getmove(); + else + calcmove(); + Next = FALSE; + goodplay = TRUE; + switch (Movetype) { + case M_DISCARD: + if (haspicked(pp)) { + if (pp->hand[Card_no] == C_INIT) + if (Card_no == 6) + Finished = TRUE; + else + error("no card there"); + else { + if (issafety(pp->hand[Card_no])) { + error("discard a safety?"); + goodplay = FALSE; + break; + } + Discard = pp->hand[Card_no]; + pp->hand[Card_no] = C_INIT; + Next = TRUE; + if (Play == PLAYER) + account(Discard); + } + } + else + error("must pick first"); + break; + case M_PLAY: + goodplay = playcard(pp); + break; + case M_DRAW: + Card_no = 0; + if (Topcard <= Deck) + error("no more cards"); + else if (haspicked(pp)) + error("already picked"); + else { + pp->hand[0] = *--Topcard; + if (Debug) + fprintf(outf, "DOMOVE: Draw %s\n", C_name[*Topcard]); +acc: + if (Play == COMP) { + account(*Topcard); + if (issafety(*Topcard)) + pp->safety[*Topcard-S_CONV] = S_IN_HAND; + } + if (pp->hand[1] == C_INIT && Topcard > Deck) { + Card_no = 1; + pp->hand[1] = *--Topcard; + if (Debug) + fprintf(outf, "DOMOVE: Draw %s\n", C_name[*Topcard]); + goto acc; + } + pp->new_battle = FALSE; + pp->new_speed = FALSE; + } + break; + + case M_ORDER: + break; + } + /* + * move blank card to top by one of two methods. If the + * computer's hand was sorted, the randomness for picking + * between equally valued cards would be lost + */ + if (Order && Movetype != M_DRAW && goodplay && pp == &Player[PLAYER]) + sort(pp->hand); + else + for (i = 1; i < HAND_SZ; i++) + if (pp->hand[i] == C_INIT) { + for (j = 0; pp->hand[j] == C_INIT; j++) + if (j >= HAND_SZ) { + j = 0; + break; + } + pp->hand[i] = pp->hand[j]; + pp->hand[j] = C_INIT; + } + if (Topcard <= Deck) + check_go(); + if (Next) + nextplay(); +} + +/* + * Check and see if either side can go. If they cannot, + * the game is over + */ +check_go() { + + reg CARD card; + reg PLAY *pp, *op; + reg int i; + + for (pp = Player; pp < &Player[2]; pp++) { + op = (pp == &Player[COMP] ? &Player[PLAYER] : &Player[COMP]); + for (i = 0; i < HAND_SZ; i++) { + card = pp->hand[i]; + if (issafety(card) || canplay(pp, op, card)) { + if (Debug) { + fprintf(outf, "CHECK_GO: can play %s (%d), ", C_name[card], card); + fprintf(outf, "issafety(card) = %d, ", issafety(card)); + fprintf(outf, "canplay(pp, op, card) = %d\n", canplay(pp, op, card)); + } + return; + } + else if (Debug) + fprintf(outf, "CHECK_GO: cannot play %s\n", + C_name[card]); + } + } + Finished = TRUE; +} + +playcard(pp) +reg PLAY *pp; +{ + reg int v; + reg CARD card; + + /* + * check and see if player has picked + */ + switch (pp->hand[Card_no]) { + default: + if (!haspicked(pp)) +mustpick: + return error("must pick first"); + case C_GAS_SAFE: case C_SPARE_SAFE: + case C_DRIVE_SAFE: case C_RIGHT_WAY: + break; + } + + card = pp->hand[Card_no]; + if (Debug) + fprintf(outf, "PLAYCARD: Card = %s\n", C_name[card]); + Next = FALSE; + switch (card) { + case C_200: + if (pp->nummiles[C_200] == 2) + return error("only two 200's per hand"); + case C_100: case C_75: + if (pp->speed == C_LIMIT) + return error("limit of 50"); + case C_50: + if (pp->mileage + Value[card] > End) + return error("puts you over %d", End); + case C_25: + if (!pp->can_go) + return error("cannot move now"); + pp->nummiles[card]++; + v = Value[card]; + pp->total += v; + pp->hand_tot += v; + if ((pp->mileage += v) == End) + check_ext(FALSE); + break; + + case C_GAS: case C_SPARE: case C_REPAIRS: + if (pp->battle != opposite(card)) + return error("can't play \"%s\"", C_name[card]); + pp->battle = card; + if (pp->safety[S_RIGHT_WAY] == S_PLAYED) + pp->can_go = TRUE; + break; + + case C_GO: + if (pp->battle != C_INIT && pp->battle != C_STOP + && !isrepair(pp->battle)) + return error("cannot play \"Go\" on a \"%s\"", + C_name[pp->battle]); + pp->battle = C_GO; + pp->can_go = TRUE; + break; + + case C_END_LIMIT: + if (pp->speed != C_LIMIT) + return error("not limited"); + pp->speed = C_END_LIMIT; + break; + + case C_EMPTY: case C_FLAT: case C_CRASH: + case C_STOP: + pp = &Player[other(Play)]; + if (!pp->can_go) + return error("opponent cannot go"); + else if (pp->safety[safety(card) - S_CONV] == S_PLAYED) +protected: + return error("opponent is protected"); + pp->battle = card; + pp->new_battle = TRUE; + pp->can_go = FALSE; + pp = &Player[Play]; + break; + + case C_LIMIT: + pp = &Player[other(Play)]; + if (pp->speed == C_LIMIT) + return error("opponent has limit"); + if (pp->safety[S_RIGHT_WAY] == S_PLAYED) + goto protected; + pp->speed = C_LIMIT; + pp->new_speed = TRUE; + pp = &Player[Play]; + break; + + case C_GAS_SAFE: case C_SPARE_SAFE: + case C_DRIVE_SAFE: case C_RIGHT_WAY: + if (pp->battle == opposite(card) + || (card == C_RIGHT_WAY && pp->speed == C_LIMIT)) { + if (!(card == C_RIGHT_WAY && !isrepair(pp->battle))) { + pp->battle = C_GO; + pp->can_go = TRUE; + } + if (card == C_RIGHT_WAY && pp->speed == C_LIMIT) + pp->speed = C_INIT; + if (pp->new_battle + || (pp->new_speed && card == C_RIGHT_WAY)) { + pp->coups[card - S_CONV] = TRUE; + pp->total += SC_COUP; + pp->hand_tot += SC_COUP; + pp->coupscore += SC_COUP; + } + } + /* + * if not coup, must pick first + */ + else if (pp->hand[0] == C_INIT && Topcard > Deck) + goto mustpick; + pp->safety[card - S_CONV] = S_PLAYED; + pp->total += SC_SAFETY; + pp->hand_tot += SC_SAFETY; + if ((pp->safescore += SC_SAFETY) == NUM_SAFE * SC_SAFETY) { + pp->total += SC_ALL_SAFE; + pp->hand_tot += SC_ALL_SAFE; + } + if (card == C_RIGHT_WAY) { + if (pp->speed == C_LIMIT) + pp->speed = C_INIT; + if (pp->battle == C_STOP || pp->battle == C_INIT) { + pp->can_go = TRUE; + pp->battle = C_INIT; + } + if (!pp->can_go && isrepair(pp->battle)) + pp->can_go = TRUE; + } + Next = -1; + break; + + case C_INIT: + error("no card there"); + Next = -1; + break; + } + if (pp == &Player[PLAYER]) + account(card); + pp->hand[Card_no] = C_INIT; + Next = (Next == -1 ? FALSE : TRUE); + return TRUE; +} + +getmove() +{ + reg char c, *sp; + static char moveprompt[] = ">>:Move:"; +#ifdef EXTRAP + static bool last_ex = FALSE; /* set if last command was E */ + + if (last_ex) { + undoex(); + prboard(); + last_ex = FALSE; + } +#endif + for (;;) { + prompt(MOVEPROMPT); + leaveok(Board, FALSE); + refresh(); + while ((c = readch()) == killchar() || c == erasechar()) + continue; + if (islower(c)) + c = toupper(c); + if (isprint(c) && !isspace(c)) { + addch(c); + refresh(); + } + switch (c) { + case 'P': /* Pick */ + Movetype = M_DRAW; + goto ret; + case 'U': /* Use Card */ + case 'D': /* Discard Card */ + if ((Card_no = getcard()) < 0) + break; + Movetype = (c == 'U' ? M_PLAY : M_DISCARD); + goto ret; + case 'O': /* Order */ + Order = !Order; + if (Window == W_SMALL) { + if (!Order) + mvwaddstr(Score, 12, 21, + "o: order hand"); + else + mvwaddstr(Score, 12, 21, + "o: stop ordering"); + wclrtoeol(Score); + } + Movetype = M_ORDER; + goto ret; + case 'Q': /* Quit */ + rub(); /* Same as a rubout */ + break; + case 'W': /* Window toggle */ + Window = nextwin(Window); + newscore(); + prscore(TRUE); + wrefresh(Score); + break; + case 'R': /* Redraw screen */ + case CTRL('L'): + wrefresh(curscr); + break; + case 'S': /* Save game */ + On_exit = FALSE; + save(); + break; + case 'E': /* Extrapolate */ +#ifdef EXTRAP + if (last_ex) + break; + Finished = TRUE; + if (Window != W_FULL) + newscore(); + prscore(FALSE); + wrefresh(Score); + last_ex = TRUE; + Finished = FALSE; +#else + error("%c: command not implemented", c); +#endif + break; + case '\r': /* Ignore RETURNs and */ + case '\n': /* Line Feeds */ + case ' ': /* Spaces */ + case '\0': /* and nulls */ + break; + case 'Z': /* Debug code */ + if (geteuid() == ARNOLD) { + if (!Debug && outf == NULL) { + char buf[40]; +over: + prompt(FILEPROMPT); + leaveok(Board, FALSE); + refresh(); + sp = buf; + while ((*sp = readch()) != '\n') { + if (*sp == killchar()) + goto over; + else if (*sp == erasechar()) { + if (--sp < buf) + sp = buf; + else { + addch('\b'); + if (*sp < ' ') + addch('\b'); + clrtoeol(); + } + } + else + addstr(unctrl(*sp++)); + refresh(); + } + *sp = '\0'; + leaveok(Board, TRUE); + if ((outf = fopen(buf, "w")) == NULL) + perror(buf); + setbuf(outf, NULL); + } + Debug = !Debug; + break; + } + /* FALLTHROUGH */ + default: + error("unknown command: %s", unctrl(c)); + break; + } + } +ret: + leaveok(Board, TRUE); +} +/* + * return whether or not the player has picked + */ +haspicked(pp) +reg PLAY *pp; { + + reg int card; + + if (Topcard <= Deck) + return TRUE; + switch (pp->hand[Card_no]) { + case C_GAS_SAFE: case C_SPARE_SAFE: + case C_DRIVE_SAFE: case C_RIGHT_WAY: + card = 1; + break; + default: + card = 0; + break; + } + return (pp->hand[card] != C_INIT); +} + +account(card) +reg CARD card; { + + reg CARD oppos; + + if (card == C_INIT) + return; + ++Numseen[card]; + if (Play == COMP) + switch (card) { + case C_GAS_SAFE: + case C_SPARE_SAFE: + case C_DRIVE_SAFE: + oppos = opposite(card); + Numgos += Numcards[oppos] - Numseen[oppos]; + break; + case C_CRASH: + case C_FLAT: + case C_EMPTY: + case C_STOP: + Numgos++; + break; + } +} + +prompt(promptno) +int promptno; +{ + static char *names[] = { + ">>:Move:", + "Really?", + "Another hand?", + "Another game?", + "Save game?", + "Same file?", + "file:", + "Extension?", + "Overwrite file?", + }; + static int last_prompt = -1; + + if (promptno == last_prompt) + move(MOVE_Y, MOVE_X + strlen(names[promptno]) + 1); + else { + move(MOVE_Y, MOVE_X); + if (promptno == MOVEPROMPT) + standout(); + addstr(names[promptno]); + if (promptno == MOVEPROMPT) + standend(); + addch(' '); + last_prompt = promptno; + } + clrtoeol(); +} + +sort(hand) +reg CARD *hand; +{ + reg CARD *cp, *tp; + reg CARD temp; + + cp = hand; + hand += HAND_SZ; + for ( ; cp < &hand[-1]; cp++) + for (tp = cp + 1; tp < hand; tp++) + if (*cp > *tp) { + temp = *cp; + *cp = *tp; + *tp = temp; + } +} + diff --git a/src/games/mille/print.c b/src/games/mille/print.c new file mode 100644 index 0000000..ee33619 --- /dev/null +++ b/src/games/mille/print.c @@ -0,0 +1,132 @@ +# include "mille.h" + +/* + * @(#)print.c 1.1 (Berkeley) 4/1/82 + */ + +# define COMP_STRT 20 +# define CARD_STRT 2 + +prboard() { + + reg PLAY *pp; + reg int i, j, k, temp; + + for (k = 0; k < 2; k++) { + pp = &Player[k]; + temp = k * COMP_STRT + CARD_STRT; + for (i = 0; i < NUM_SAFE; i++) + if (pp->safety[i] == S_PLAYED && !pp->sh_safety[i]) { + mvaddstr(i, temp, C_name[i + S_CONV]); + if (pp->coups[i]) + mvaddch(i, temp - CARD_STRT, '*'); + pp->sh_safety[i] = TRUE; + } + show_card(14, temp, pp->battle, &pp->sh_battle); + show_card(16, temp, pp->speed, &pp->sh_speed); + for (i = C_25; i <= C_200; i++) { + reg char *name; + reg int end; + + if (pp->nummiles[i] == pp->sh_nummiles[i]) + continue; + + name = C_name[i]; + temp = k * 40; + end = pp->nummiles[i]; + for (j = pp->sh_nummiles[i]; j < end; j++) + mvwaddstr(Miles, i + 1, (j << 2) + temp, name); + pp->sh_nummiles[i] = end; + } + } + prscore(TRUE); + temp = CARD_STRT; + pp = &Player[PLAYER]; + for (i = 0; i < HAND_SZ; i++) + show_card(i + 6, temp, pp->hand[i], &pp->sh_hand[i]); + mvprintw(6, COMP_STRT + CARD_STRT, "%2d", Topcard - Deck); + show_card(8, COMP_STRT + CARD_STRT, Discard, &Sh_discard); + if (End == 1000) { + move(EXT_Y, EXT_X); + standout(); + addstr("Extension"); + standend(); + } + wrefresh(Board); + wrefresh(Miles); + wrefresh(Score); +} + +/* + * show_card: + * Show the given card if it is different from the last one shown + */ +show_card(y, x, c, lc) +int y, x; +register CARD c, *lc; +{ + if (c == *lc) + return; + + mvprintw(y, x, C_fmt, C_name[c]); + *lc = c; +} + +static char Score_fmt[] = "%4d"; + +prscore(for_real) +reg bool for_real; { + + reg PLAY *pp; + reg int x; + + stdscr = Score; + for (pp = Player; pp < &Player[2]; pp++) { + x = (pp - Player) * 6 + 21; + show_score(1, x, pp->mileage, &pp->sh_mileage); + if (pp->safescore != pp->sh_safescore) { + mvprintw(2, x, Score_fmt, pp->safescore); + if (pp->safescore == 400) + mvaddstr(3, x + 1, "300"); + else + mvaddstr(3, x + 1, " 0"); + mvprintw(4, x, Score_fmt, pp->coupscore); + pp->sh_safescore = pp->safescore; + } + if (Window == W_FULL || Finished) { +#ifdef EXTRAP + if (for_real) + finalscore(pp); + else + extrapolate(pp); +#else + finalscore(pp); +#endif + show_score(11, x, pp->hand_tot, &pp->sh_hand_tot); + show_score(13, x, pp->total, &pp->sh_total); + show_score(14, x, pp->games, &pp->sh_games); + } + else { + show_score(6, x, pp->hand_tot, &pp->sh_hand_tot); + show_score(8, x, pp->total, &pp->sh_total); + show_score(9, x, pp->games, &pp->sh_games); + } + } + stdscr = Board; +} + +/* + * show_score: + * Show a score value if it is different from the last time we + * showed it. + */ +show_score(y, x, s, ls) +int y, x; +register int s, *ls; +{ + if (s == *ls) + return; + + mvprintw(y, x, Score_fmt, s); + *ls = s; +} diff --git a/src/games/mille/roll.c b/src/games/mille/roll.c new file mode 100644 index 0000000..c25bc4a --- /dev/null +++ b/src/games/mille/roll.c @@ -0,0 +1,20 @@ +# include "mille.h" + +/* + * This routine rolls ndie nside-sided dice. + * + * @(#)roll.c 1.1 (Berkeley) 4/1/82 + * + */ + +roll(ndie, nsides) +reg int ndie, nsides; { + + reg int tot; + extern unsigned int random(); + + tot = 0; + while (ndie--) + tot += random() % nsides + 1; + return tot; +} diff --git a/src/games/mille/save.c b/src/games/mille/save.c new file mode 100644 index 0000000..bad5a11 --- /dev/null +++ b/src/games/mille/save.c @@ -0,0 +1,132 @@ +#include "mille.h" +#include +#include +#include +#ifndef unctrl +#include "unctrl.h" +#endif + +# ifdef attron +# include +# define _tty cur_term->Nttyb +# endif attron + +/* + * @(#)save.c 1.3 (2.11BSD) 1996/3/21 + */ + +typedef struct stat STAT; + +extern char *ctime(); +extern int read(), write(); + +/* + * This routine saves the current game for use at a later date + */ +extern int errno; + +save() { + + reg char *sp; + reg int outf; + reg time_t *tp; + char buf[80]; + time_t tme; + STAT junk; + + tp = &tme; + if (Fromfile && getyn(SAMEFILEPROMPT)) + strcpy(buf, Fromfile); + else { +over: + prompt(FILEPROMPT); + leaveok(Board, FALSE); + refresh(); + sp = buf; + while ((*sp = readch()) != '\n') { + if (*sp == killchar()) + goto over; + else if (*sp == erasechar()) { + if (--sp < buf) + sp = buf; + else { + addch('\b'); + /* + * if the previous char was a control + * char, cover up two characters. + */ + if (*sp < ' ') + addch('\b'); + clrtoeol(); + } + } + else + addstr(unctrl(*sp++)); + refresh(); + } + *sp = '\0'; + leaveok(Board, TRUE); + } + + /* + * check for existing files, and confirm overwrite if needed + */ + + if (sp == buf || (!Fromfile && stat(buf, &junk) > -1 + && getyn(OVERWRITEFILEPROMPT) == FALSE)) + return FALSE; + + if ((outf = creat(buf, 0644)) < 0) { + error(strerror(errno)); + return FALSE; + } + mvwaddstr(Score, ERR_Y, ERR_X, buf); + wrefresh(Score); + time(tp); /* get current time */ + strcpy(buf, ctime(tp)); + for (sp = buf; *sp != '\n'; sp++) + continue; + *sp = '\0'; + varpush(outf, write); + close(outf); + wprintw(Score, " [%s]", buf); + wclrtoeol(Score); + wrefresh(Score); + return TRUE; +} + +/* + * This does the actual restoring. It returns TRUE if the + * backup was made on exiting, in which case certain things must + * be cleaned up before the game starts. + */ +rest_f(file) +reg char *file; { + + reg char *sp; + reg int inf; + char buf[80]; + STAT sbuf; + + if ((inf = open(file, 0)) < 0) { + perror(file); + exit(1); + } + if (fstat(inf, &sbuf) < 0) { /* get file stats */ + perror(file); + exit(1); + } + varpush(inf, read); + close(inf); + strcpy(buf, ctime(&sbuf.st_mtime)); + for (sp = buf; *sp != '\n'; sp++) + continue; + *sp = '\0'; + /* + * initialize some necessary values + */ + sprintf(Initstr, "%s [%s]\n", file, buf); + Fromfile = file; + return !On_exit; +} + diff --git a/src/games/mille/table.c b/src/games/mille/table.c new file mode 100644 index 0000000..073b3a5 --- /dev/null +++ b/src/games/mille/table.c @@ -0,0 +1,21 @@ +# define DEBUG + +/* + * @(#)table.c 1.1 (Berkeley) 4/1/82 + */ + +# include "mille.h" + +main() { + + reg int i, j, count; + + printf(" %16s -> %5s %5s %4s %s\n", "Card", "cards", "count", "need", "opposite"); + for (i = 0; i < NUM_CARDS - 1; i++) { + for (j = 0, count = 0; j < DECK_SZ; j++) + if (Deck[j] == i) + count++; + printf("%2d %16s -> %5d %5d %4d %s\n", i, C_name[i], Numcards[i], count, Numneed[i], C_name[opposite(i)]); + } +} + diff --git a/src/games/mille/types.c b/src/games/mille/types.c new file mode 100644 index 0000000..2fb9677 --- /dev/null +++ b/src/games/mille/types.c @@ -0,0 +1,38 @@ +# include "mille.h" + +/* + * @(#)types.c 1.1 (Berkeley) 4/1/82 + */ + +isrepair(card) +reg CARD card; { + + return card == C_GAS || card == C_SPARE || card == C_REPAIRS || card == C_INIT; +} + +safety(card) +reg CARD card; { + + switch (card) { + case C_EMPTY: + case C_GAS: + case C_GAS_SAFE: + return C_GAS_SAFE; + case C_FLAT: + case C_SPARE: + case C_SPARE_SAFE: + return C_SPARE_SAFE; + case C_CRASH: + case C_REPAIRS: + case C_DRIVE_SAFE: + return C_DRIVE_SAFE; + case C_GO: + case C_STOP: + case C_RIGHT_WAY: + case C_LIMIT: + case C_END_LIMIT: + return C_RIGHT_WAY; + } + /* NOTREACHED */ +} + diff --git a/src/games/mille/unctrl.h b/src/games/mille/unctrl.h new file mode 100644 index 0000000..78230c8 --- /dev/null +++ b/src/games/mille/unctrl.h @@ -0,0 +1,9 @@ +/* $Header: /va/arnold/=lib/=curses/RCS/unctrl.h,v 1.1 85/02/06 12:03:20 arnold Exp $ */ + +/* + * unctrl.h + */ + +extern char *_unctrl[]; + +# define unctrl(ch) (_unctrl[ch & 0177]) diff --git a/src/games/mille/varpush.c b/src/games/mille/varpush.c new file mode 100644 index 0000000..7a45f22 --- /dev/null +++ b/src/games/mille/varpush.c @@ -0,0 +1,53 @@ +# include "mille.h" + +/* + * @(#)varpush.c 1.1 (Berkeley) 4/1/82 + */ + +int read(), write(); + +/* + * push variables around via the routine func() on the file + * channel file. func() is either read or write. + */ +varpush(file, func) +reg int file; +reg int (*func)(); { + + int temp; + + (*func)(file, (char *) &Debug, sizeof Debug); + (*func)(file, (char *) &Finished, sizeof Finished); + (*func)(file, (char *) &Order, sizeof Order); + (*func)(file, (char *) &End, sizeof End); + (*func)(file, (char *) &On_exit, sizeof On_exit); + (*func)(file, (char *) &Handstart, sizeof Handstart); + (*func)(file, (char *) &Numgos, sizeof Numgos); + (*func)(file, (char *) Numseen, sizeof Numseen); + (*func)(file, (char *) &Play, sizeof Play); + (*func)(file, (char *) &Window, sizeof Window); + (*func)(file, (char *) Deck, sizeof Deck); + (*func)(file, (char *) &Discard, sizeof Discard); + (*func)(file, (char *) Player, sizeof Player); + if (func == read) { + read(file, (char *) &temp, sizeof temp); + Topcard = &Deck[temp]; + if (Debug) { + char buf[80]; +over: + printf("Debug file:"); + gets(buf); + if ((outf = fopen(buf, "w")) == NULL) { + perror(buf); + goto over; + } + if (strcmp(buf, "/dev/null") != 0) + setbuf(outf, NULL); + } + } + else { + temp = Topcard - Deck; + write(file, (char *) &temp, sizeof temp); + } +} + diff --git a/src/games/monop/Makefile b/src/games/monop/Makefile new file mode 100644 index 0000000..09fe89d --- /dev/null +++ b/src/games/monop/Makefile @@ -0,0 +1,87 @@ +# +# Nifty foo monopoly maker +# Program: Ken Arnold +# Makefile: K.S. +# +DESTDIR= +DATFILES=brd.dat mon.dat prop.dat +CFILES= monop.c cards.c execute.c getinp.c houses.c jail.c misc.c morg.c \ + print.c prop.c rent.c roll.c spec.c strcmp.c trade.c +OBJS= monop.o cards.o execute.o getinp.o houses.o jail.o misc.o morg.o \ + print.o prop.o rent.o roll.o spec.o strcmp.o trade.o strings.o +HEADERS=monop.h deck.h +BINDIR= ${DESTDIR}/usr/games +LIBDIR= ${DESTDIR}/usr/games/lib +LIB= +CFLAGS= -O -w +SEPFLAG= -i +DAT= brd.dat monop.dat prop.dat +CC= cc +XSTR= xstr +ED= ed +AS= as +RM= rm -f +CTAGS= ctags + +# +# Be cool about compiling strings. +# +.c.o: + ${CC} -E ${CFLAGS} $*.c | ${XSTR} -c - + ${CC} -c ${CFLAGS} x.c + mv x.o $*.o + +it: monop cards.pck + +monop: ${OBJS} + ${CC} -o monop ${SEPFLAG} ${OBJS} ${LIB} + +install: monop cards.pck + ${RM} ${BINDIR}/monop ${LIBDIR}/cards.pck + install -s monop ${BINDIR} + mv cards.pck ${LIBDIR} + +new: clean ctags monop + +strings.o: strings + ${XSTR} + ${CC} -S xs.c + ${ED} - < :rofix xs.s + ${AS} -o strings.o xs.s + ${RM} xs.s xs.c + +monop.o: ${DATFILES} monop.def + ${CC} -E ${CFLAGS} monop.c | ${XSTR} -c - + ${CC} -c ${CFLAGS} x.c + mv x.o monop.o + +cards.o: deck.h + ${CC} -E ${CFLAGS} cards.c | ${XSTR} -c - + ${CC} -c ${CFLAGS} x.c + mv x.o cards.o + +newone: + ${CC} ${SEPFLAG} -o monop ${CFLAGS} ${CFILES} ${LIB} + +ctags: + ${CTAGS} ${CFILES} monop.h deck.h monop.def initdeck.c + +cards.pck: initdeck cards.inp + ./initdeck + +initdeck: initdeck.c deck.h + ${CC} -o initdeck ${CFLAGS} initdeck.c ${LIB} + +monop.tar: + tar crvf monop.tar ${CFILES} ${DATFILES} ${HEADERS} :rofix Makefile cards.inp initdeck.c monop.def monop.ext + +clean: + ${RM} ${OBJS} monop core tags x.c x.o monop.tar initdeck cards.pck errs + cp /dev/null strings + +printall: + -/usr/bin/eecs/pr monop.h deck.h monop.def monop.ext ${CFILES} ${DATFILES} | /usr/bin/lpr + -/usr/bin/lpq + +lint: + lint ${CFILES} > lint.out ; diff --git a/src/games/monop/_rofix b/src/games/monop/_rofix new file mode 100644 index 0000000..cd5fa24 --- /dev/null +++ b/src/games/monop/_rofix @@ -0,0 +1,3 @@ +g/^[ ]*\.data/s//.text/ +w +q diff --git a/src/games/monop/brd.dat b/src/games/monop/brd.dat new file mode 100644 index 0000000..7af06d8 --- /dev/null +++ b/src/games/monop/brd.dat @@ -0,0 +1,43 @@ +/* name (COLOR) owner type desc cost */ + +{"=== GO ===", -1, SAFE, 0 }, +{"Mediterranean ave. (P)", -1, PRPTY, &prop[0], 60 }, +{"Community Chest i", -1, CC, cc }, +{"Baltic ave. (P)", -1, PRPTY, &prop[1], 60 }, +{"Income Tax", -1, SPEC, inc_tax }, +{"Reading RR", -1, RR, &rr[0], 200 }, +{"Oriental ave. (L)", -1, PRPTY, &prop[2], 100 }, +{"Chance i", -1, CHANCE, chance }, +{"Vermont ave. (L)", -1, PRPTY, &prop[3], 100 }, +{"Connecticut ave. (L)", -1, PRPTY, &prop[4], 120 }, +{"Just Visiting", -1, SAFE, 0 }, +{"St. Charles pl. (V)", -1, PRPTY, &prop[5], 140 }, +{"Electric Co.", -1, UTIL, &util[0], 150 }, +{"States ave. (V)", -1, PRPTY, &prop[6], 140 }, +{"Virginia ave. (V)", -1, PRPTY, &prop[7], 160 }, +{"Pennsylvania RR", -1, RR, &rr[1], 200 }, +{"St. James pl. (O)", -1, PRPTY, &prop[8], 180 }, +{"Community Chest ii", -1, CC, cc }, +{"Tennessee ave. (O)", -1, PRPTY, &prop[9], 180 }, +{"New York ave. (O)", -1, PRPTY, &prop[10], 200 }, +{"Free Parking", -1, SAFE, 0 }, +{"Kentucky ave. (R)", -1, PRPTY, &prop[11], 220 }, +{"Chance ii", -1, CHANCE, chance }, +{"Indiana ave. (R)", -1, PRPTY, &prop[12], 220 }, +{"Illinois ave. (R)", -1, PRPTY, &prop[13], 240 }, +{"B&O RR", -1, RR, &rr[2], 200 }, +{"Atlantic ave. (Y)", -1, PRPTY, &prop[14], 260 }, +{"Ventnor ave. (Y)", -1, PRPTY, &prop[15], 260 }, +{"Water Works", -1, UTIL, &util[1], 150 }, +{"Marvin Gardens (Y)", -1, PRPTY, &prop[16], 280 }, +{"GO TO JAIL", -1, SPEC, goto_jail }, +{"Pacific ave. (G)", -1, PRPTY, &prop[17], 300 }, +{"N. Carolina ave. (G)", -1, PRPTY, &prop[18], 300 }, +{"Community Chest iii", -1, CC, cc }, +{"Pennsylvania ave. (G)", -1, PRPTY, &prop[19], 320 }, +{"Short Line RR", -1, RR, &rr[3], 200 }, +{"Chance iii", -1, CHANCE, chance }, +{"Park place (D)", -1, PRPTY, &prop[20], 350 }, +{"Luxury Tax", -1, SPEC, lux_tax }, +{"Boardwalk (D)", -1, PRPTY, &prop[21], 400 }, +{"JAIL", -1, SPEC } diff --git a/src/games/monop/cards.c b/src/games/monop/cards.c new file mode 100644 index 0000000..b61d50d --- /dev/null +++ b/src/games/monop/cards.c @@ -0,0 +1,170 @@ +# include "monop.ext" + +/* + * These routine deal with the card decks + */ + +# define GOJF 'F' /* char for get-out-of-jail-free cards */ + +# ifndef DEV +static char *cardfile = "/usr/games/lib/cards.pck"; +# else +static char *cardfile = "cards.pck"; +# endif + +static FILE *deckf; + +/* + * This routine initializes the decks from the data file, + * which it opens. + */ +init_decks() { + + if ((deckf=fopen(cardfile, "r")) == NULL) { +file_err: + perror(cardfile); + exit(1); + } + if (fread(deck, sizeof (DECK), 2, deckf) != 2) + goto file_err; + set_up(&CC_D); + set_up(&CH_D); +} +/* + * This routine sets up the offset pointers for the given deck. + */ +set_up(dp) +DECK *dp; { + + reg int r1, r2; + int i; + + dp->offsets = (long *) calloc(sizeof (long), dp->num_cards); + if (fread(dp->offsets, sizeof(long), dp->num_cards, deckf) != dp->num_cards) { + perror(cardfile); + exit(1); + } + dp->last_card = 0; + dp->gojf_used = FALSE; + for (i = 0; i < dp->num_cards; i++) { + reg long temp; + + r1 = roll(1, dp->num_cards) - 1; + r2 = roll(1, dp->num_cards) - 1; + temp = dp->offsets[r2]; + dp->offsets[r2] = dp->offsets[r1]; + dp->offsets[r1] = temp; + } +} +/* + * This routine draws a card from the given deck + */ +get_card(dp) +DECK *dp; { + + reg char type_maj, type_min; + reg int num; + int i, per_h, per_H, num_h, num_H; + OWN *op; + + do { + fseek(deckf, dp->offsets[dp->last_card], 0); + dp->last_card = ++(dp->last_card) % dp->num_cards; + type_maj = getc(deckf); + } while (dp->gojf_used && type_maj == GOJF); + type_min = getc(deckf); + num = getw(deckf); + printmes(); + switch (type_maj) { + case '+': /* get money */ + if (type_min == 'A') { + for (i = 0; i < num_play; i++) + if (i != player) + play[i].money -= num; + num = num * (num_play - 1); + } + cur_p->money += num; + break; + case '-': /* lose money */ + if (type_min == 'A') { + for (i = 0; i < num_play; i++) + if (i != player) + play[i].money += num; + num = num * (num_play - 1); + } + cur_p->money -= num; + break; + case 'M': /* move somewhere */ + switch (type_min) { + case 'F': /* move forward */ + num -= cur_p->loc; + if (num < 0) + num += 40; + break; + case 'J': /* move to jail */ + goto_jail(); + return; + case 'R': /* move to railroad */ + spec = TRUE; + num = (int)((cur_p->loc + 5)/10)*10 + 5 - cur_p->loc; + break; + case 'U': /* move to utility */ + spec = TRUE; + if (cur_p->loc >= 12 && cur_p->loc < 28) + num = 28 - cur_p->loc; + else { + num = 12 - cur_p->loc; + if (num < 0) + num += 40; + } + break; + case 'B': + num = -num; + break; + } + move(num); + break; + case 'T': /* tax */ + if (dp == &CC_D) { + per_h = 40; + per_H = 115; + } + else { + per_h = 25; + per_H = 100; + } + num_h = num_H = 0; + for (op = cur_p->own_list; op; op = op->next) + if (op->sqr->type == PRPTY) + if (op->sqr->desc->houses == 5) + ++num_H; + else + num_h += op->sqr->desc->houses; + num = per_h * num_h + per_H * num_H; + printf("You had %d Houses and %d Hotels, so that cost you $%d\n", num_h, num_H, num); + if (num == 0) + lucky(""); + else + cur_p->money -= num; + break; + case GOJF: /* get-out-of-jail-free card */ + cur_p->num_gojf++; + dp->gojf_used = TRUE; + break; + } + spec = FALSE; +} +/* + * This routine prints out the message on the card + */ +printmes() { + + reg char c; + + printline(); + fflush(stdout); + while ((c = getc(deckf)) != '\0') + putchar(c); + printline(); + fflush(stdout); +} diff --git a/src/games/monop/cards.inp b/src/games/monop/cards.inp new file mode 100644 index 0000000..1867e87 --- /dev/null +++ b/src/games/monop/cards.inp @@ -0,0 +1,122 @@ +FF +>> GET OUT OF JAIL FREE << +Keep this card until needed or sold +%% +++25 +Receive for Services $25. +%% +++200 +Bank Error in Your Favor. +Collect $200. +%% +++20 +Income Tax Refund. +Collect $20. +%% +--100 +Pay Hospital $100 +%% +++100 +Life Insurance Matures. +Collect $100 +%% +++45 +From sale of Stock You get $45. +%% +TX +You are Assessed for street repairs. + $40 per House + $115 per Hotel +%% +++100 +X-mas Fund Matures. +Collect $100. +%% +++11 +You have won Second Prize in a Beauty Contest +Collect $11 +%% +MF0 +Advance to GO +(Collect $200) +%% +++100 +You inherit $100 +%% +--150 +Pay School Tax of $150. +%% +MJ + >> GO TO JAIL << +Go Directly to Jail. Do not pass GO Do not collect $200. +%% ++A50 + >> GRAND OPERA OPENING << +Collect $50 from each player for opening night seats. +%% +--50 +Doctor's Fee: Pay $50. +%- +FF +>> GET OUT OF JAIL FREE << +Keep this card until needed or sold +%% +MR +Advance to the nearest Railroad, and pay owner +Twice the rental to which he is otherwise entitled. +If Railroad is unowned you may buy it from the bank +%% +MU +Advance to the nearest Utility. +If unowned, you may buy it from the bank. +If owned, throw dice and pay oner a total of ten times +the amount thrown. +%% +MB3 +Go Back 3 Spaces +%% +MR +Advance to the nearest Railroad, and pay owner +Twice the rental to which he is otherwise entitled. +If Railroad is unowned you may buy it from the bank +%% +MJ + >> GO DIRECTLY TO JAIL << +Do not pass GO, Do not Collect $200. +%% +MF5 +Take a Ride on the Reading. +If you pass GO, collect $200. +%% +MF39 +Take a Walk on the Board Walk. + (Advance To Board Walk) +%% +MF24 +Advance to Illinos Ave. +%% +MF0 +Advance to Go +%% +MF11 +Advance to St. Charles Place. +If you pass GO, collect $200. +%% +TX +Make general repairs on all of your Property. +For Each House pay $25. +For Each Hotel pay $100. +%% +-A50 +You have been elected Chairman of the Board. +Pay each player $50. +%% +--15 +Pay Poor Tax of $15 +%% +++50 +Bank pays you Dividend of $50. +%% +++150 +Your Building and Loan Matures. +Collect $150. diff --git a/src/games/monop/deck.h b/src/games/monop/deck.h new file mode 100644 index 0000000..3363612 --- /dev/null +++ b/src/games/monop/deck.h @@ -0,0 +1,13 @@ +# define bool char + +# define CC_D deck[0] +# define CH_D deck[1] + +struct dk_st { /* deck description structure */ + int num_cards; /* number of cards in deck */ + int last_card; /* number of last card picked */ + bool gojf_used; /* set if gojf card out of deck */ + long *offsets; /* offests for start of cards */ +}; + +typedef struct dk_st DECK; diff --git a/src/games/monop/execute.c b/src/games/monop/execute.c new file mode 100644 index 0000000..3ec23f1 --- /dev/null +++ b/src/games/monop/execute.c @@ -0,0 +1,224 @@ +# include "monop.ext" +# include +# include +# include + +# define SEGSIZE 8192 + +typedef struct stat STAT; +typedef struct tm TIME; + +extern char etext[], /* end of text space */ + rub(); + +static char buf[257], + *yn_only[] = { "yes", "no"}; + +static bool new_play; /* set if move on to new player */ + +/* + * This routine executes the given command by index number + */ +execute(com_num) +reg int com_num; { + + new_play = FALSE; /* new_play is true if fixing */ + (*func[com_num])(); + notify(); + force_morg(); + if (new_play) + next_play(); + else if (num_doub) + printf("%s rolled doubles. Goes again\n", cur_p->name); +} +/* + * This routine moves a piece around. + */ +do_move() { + + reg int r1, r2; + reg bool was_jail; + + new_play = was_jail = FALSE; + printf("roll is %d, %d\n", r1=roll(1, 6), r2=roll(1, 6)); + if (cur_p->loc == JAIL) { + was_jail++; + if (!move_jail(r1, r2)) { + new_play++; + goto ret; + } + } + else { + if (r1 == r2 && ++num_doub == 3) { + printf("That's 3 doubles. You go to jail\n"); + goto_jail(); + new_play++; + goto ret; + } + move(r1+r2); + } + if (r1 != r2 || was_jail) + new_play++; +ret: + return; +} +/* + * This routine moves a normal move + */ +move(rl) +reg int rl; { + + reg int old_loc; + + old_loc = cur_p->loc; + cur_p->loc = (cur_p->loc + rl) % N_SQRS; + if (cur_p->loc < old_loc && rl > 0) { + cur_p->money += 200; + printf("You pass %s and get $200\n", board[0].name); + } + show_move(); +} +/* + * This routine shows the results of a move + */ +show_move() { + + reg SQUARE *sqp; + + sqp = &board[cur_p->loc]; + printf("That puts you on %s\n", sqp->name); + switch (sqp->type) { + case SAFE: + printf("That is a safe place\n"); + break; + case CC: + case CHANCE: + case SPEC: + (*((int (*)())(sqp->desc)))(); + break; + case PRPTY: + case RR: + case UTIL: + if (sqp->owner < 0) { + printf("That would cost $%d\n", sqp->cost); + if (getyn("Do you want to buy? ") == 0) { + buy(player, sqp); + cur_p->money -= sqp->cost; + } + else if (num_play > 2) + bid(sqp); + } + else if (sqp->owner == player) + printf("You own it.\n"); + else + rent(sqp); + } +} +/* + * This routine saves the current game for use at a later date + */ +save() { + + reg char *sp; + reg int outf, num; + TIME tme, *tp; + int *dat_end, junk[18]; + unsgn start, end; + + tp = &tme; + printf("Which file do you wish to save it in? "); + sp = buf; + while ((*sp++=getchar()) != '\n' && !feof(stdin)) + continue; + *--sp = '\0'; + if (feof(stdin)) + clearerr(stdin); + + /* + * check for existing files, and confirm overwrite if needed + */ + + if (stat(buf, junk) > -1 + && getyn("File exists. Do you wish to overwrite? ", yn_only) > 0) + return; + + if ((outf=creat(buf, 0644)) < 0) { + perror(buf); + return; + } + printf("\"%s\" ", buf); + time(tp); /* get current time */ + strcpy(buf, ctime(tp)); + for (sp = buf; *sp != '\n'; sp++) + continue; + *sp = '\0'; +# if 0 + start = (((int) etext + (SEGSIZE-1)) / SEGSIZE ) * SEGSIZE; +# else + start = 0; +# endif + end = sbrk(0); + while (start < end) { /* write out entire data space */ + num = start + 16 * 1024 > end ? end - start : 16 * 1024; + write(outf, start, num); + start += num; + } + close(outf); + printf("[%s]\n", buf); +} +/* + * This routine restores an old game from a file + */ +restore() { + + reg char *sp; + + printf("Which file do you wish to restore from? "); + for (sp = buf; (*sp=getchar()) != '\n' && !feof(stdin); sp++) + continue; + *sp = '\0'; + if (feof(stdin)) + clearerr(stdin); + rest_f(buf); +} +/* + * This does the actual restoring. It returns TRUE if the + * backup was successful, else false. + */ +rest_f(file) +reg char *file; { + + reg char *sp; + reg int inf, num; + char buf[80]; + unsgn start, end; + STAT sbuf; + + if ((inf=open(file, 0)) < 0) { + perror(file); + return FALSE; + } + printf("\"%s\" ", file); + if (fstat(inf, &sbuf) < 0) { /* get file stats */ + perror(file); + exit(1); + } +# if 0 + start = (((int) etext + (SEGSIZE-1)) / SEGSIZE ) * SEGSIZE; +# else + start = 0; +# endif + brk(end = start + sbuf.st_size); + while (start < end) { /* write out entire data space */ + num = start + 16 * 1024 > end ? end - start : 16 * 1024; + read(inf, start, num); + start += num; + } + close(inf); + strcpy(buf, ctime(sbuf.st_mtime)); + for (sp = buf; *sp != '\n'; sp++) + continue; + *sp = '\0'; + printf("[%s]\n", buf); + return TRUE; +} diff --git a/src/games/monop/getinp.c b/src/games/monop/getinp.c new file mode 100644 index 0000000..a300c0e --- /dev/null +++ b/src/games/monop/getinp.c @@ -0,0 +1,83 @@ +# include +# include + +# define reg register + +# define LINE 70 + +static char buf[257]; + +getinp(prompt, list) +char *prompt, *list[]; { + + reg int i, n_match, match; + char *sp; + int plen; + + + for (;;) { +inter: + printf(prompt); + for (sp = buf; (*sp=getchar()) != '\n' && !feof(stdin); ) + if (*sp == -1) /* check for interupted system call */ + goto inter; + else if (sp != buf || *sp != ' ') + sp++; + if (feof(stdin)) { + clearerr(stdin); + continue; + } + if (buf[0] == '?' && buf[1] == '\n') { + printf("Valid inputs are: "); + for (i = 0, match = 18; list[i]; i++) { + if ((match+=(n_match=strlen(list[i]))) > LINE) { + printf("\n\t"); + match = n_match + 8; + } + if (*list[i] == '\0') { + match += 8; + printf(""); + } + else + printf(list[i]); + if (list[i+1]) + printf(", "); + else + putchar('\n'); + match += 2; + } + continue; + } + *sp = '\0'; + for (sp = buf; *sp; sp++) + if (isupper(*sp)) + *sp = tolower(*sp); + for (i = n_match = 0; list[i]; i++) + if (comp(list[i])) { + n_match++; + match = i; + } + if (n_match == 1) + return match; + else if (buf[0] != '\0') + printf("Illegal response: \"%s\". Use '?' to get list of valid answers\n", buf); + } +} + +static +comp(s1) +char *s1; { + + reg char *sp, *tsp, c; + + if (buf[0] != '\0') + for (sp = buf, tsp = s1; *sp; ) { + c = isupper(*tsp) ? tolower(*tsp) : *tsp; + tsp++; + if (c != *sp++) + return 0; + } + else if (*s1 != '\0') + return 0; + return 1; +} diff --git a/src/games/monop/houses.c b/src/games/monop/houses.c new file mode 100644 index 0000000..8f525b8 --- /dev/null +++ b/src/games/monop/houses.c @@ -0,0 +1,230 @@ +# include "monop.ext" + +static char *names[N_MON+2], + cur_prop[80]; + +static MON *monops[N_MON]; + +/* + * These routines deal with buying and selling houses + */ +buy_houses() { + + reg int num_mon; + reg MON *mp; + reg OWN *op; + bool good,got_morg; + int i,p; + +over: + num_mon = 0; + good = TRUE; + got_morg = FALSE; + for (op = cur_p->own_list; op && op->sqr->type != PRPTY; op = op->next) + continue; + while (op) + if (op->sqr->desc->monop) { + mp = op->sqr->desc->mon_desc; + names[num_mon] = (monops[num_mon]=mp)->name; + num_mon++; + got_morg = good = FALSE; + for (i = 0; i < mp->num_in; i++) { + if (op->sqr->desc->morg) + got_morg++; + if (op->sqr->desc->houses != 5) + good++; + op = op->next; + } + if (!good || got_morg) + --num_mon; + } + else + op = op->next; + if (num_mon == 0) { + if (got_morg) + printf("You can't build on mortgaged monopolies.\n"); + else if (!good) + printf("You can't build any more.\n"); + else + printf("But you don't have any monopolies!!\n"); + return; + } + if (num_mon == 1) + buy_h(monops[0]); + else { + names[num_mon++] = "done"; + names[num_mon--] = 0; + if ((p=getinp("Which property do you wish to buy houses for? ", names)) == num_mon) + return; + buy_h(monops[p]); + goto over; + } +} + +buy_h(mnp) +MON *mnp; { + + reg int i; + reg MON *mp; + reg int price; + shrt input[3],temp[3]; + int tot; + PROP *pp; + + mp = mnp; + price = mp->h_cost * 50; +blew_it: + list_cur(mp); + printf("Houses will cost $%d\n", price); + printf("How many houses do you wish to buy for\n"); + for (i = 0; i < mp->num_in; i++) { + pp = mp->sq[i]->desc; +over: + if (pp->houses == 5) { + printf("%s (H):\n", mp->sq[i]->name); + input[i] = 0; + temp[i] = 5; + continue; + } + sprintf(cur_prop, "%s (%d): ", mp->sq[i]->name, pp->houses); + input[i] = get_int(cur_prop); + temp[i] = input[i] + pp->houses; + if (temp[i] > 5) { + printf("That's too many. The most you can buy is %d\n", + 5 - pp->houses); + goto over; + } + } + if (mp->num_in == 3 && (abs(temp[0] - temp[1]) > 1 || + abs(temp[0] - temp[2]) > 1 || abs(temp[1] - temp[2]) > 1)) { +err: printf("That makes the spread too wide. Try again\n"); + goto blew_it; + } + else if (mp->num_in == 2 && abs(temp[0] - temp[1]) > 1) + goto err; + for (tot = i = 0; i < mp->num_in; i++) + tot += input[i]; + if (tot) { + printf("You asked for %d houses for $%d\n", tot, tot * price); + if (getyn("Is that ok? ", yn) == 0) { + cur_p->money -= tot * price; + for (tot = i = 0; i < mp->num_in; i++) + mp->sq[i]->desc->houses = temp[i]; + } + } +} + +/* + * This routine sells houses. + */ +sell_houses() { + + reg int num_mon; + reg MON *mp; + reg OWN *op; + bool good; + int p; + +over: + num_mon = 0; + good = TRUE; + for (op = cur_p->own_list; op; op = op->next) + if (op->sqr->type == PRPTY && op->sqr->desc->monop) { + mp = op->sqr->desc->mon_desc; + names[num_mon] = (monops[num_mon]=mp)->name; + num_mon++; + good = 0; + do + if (!good && op->sqr->desc->houses != 0) + good++; + while (op->next && op->sqr->desc->mon_desc == mp + && (op=op->next)); + if (!good) + --num_mon; + } + if (num_mon == 0) { + printf("You don't have any houses to sell!!\n"); + return; + } + if (num_mon == 1) + sell_h(monops[0]); + else { + names[num_mon++] = "done"; + names[num_mon--] = 0; + if ((p=getinp("Which property do you wish to sell houses from? ", names)) == num_mon) + return; + sell_h(monops[p]); + notify(); + goto over; + } +} + +sell_h(mnp) +MON *mnp; { + + reg int i; + reg MON *mp; + reg int price; + shrt input[3],temp[3]; + int tot; + PROP *pp; + + mp = mnp; + price = mp->h_cost * 25; +blew_it: + printf("Houses will get you $%d apiece\n", price); + list_cur(mp); + printf("How many houses do you wish to sell from\n"); + for (i = 0; i < mp->num_in; i++) { + pp = mp->sq[i]->desc; +over: + if (pp->houses == 0) { + printf("%s (0):\n", mp->sq[i]->name); + input[i] = temp[i] = 0; + continue; + } + if (pp->houses < 5) + sprintf(cur_prop,"%s (%d): ",mp->sq[i]->name,pp->houses); + else + sprintf(cur_prop,"%s (H): ",mp->sq[i]->name,pp->houses); + input[i] = get_int(cur_prop); + temp[i] = pp->houses - input[i]; + if (temp[i] < 0) { + printf("That's too many. The most you can sell is %d\n", pp->houses); + goto over; + } + } + if (mp->num_in == 3 && (abs(temp[0] - temp[1]) > 1 || + abs(temp[0] - temp[2]) > 1 || abs(temp[1] - temp[2]) > 1)) { +err: printf("That makes the spread too wide. Try again\n"); + goto blew_it; + } + else if (mp->num_in == 2 && abs(temp[0] - temp[1]) > 1) + goto err; + for (tot = i = 0; i < mp->num_in; i++) + tot += input[i]; + if (tot) { + printf("You asked to sell %d houses for $%d\n",tot,tot * price); + if (getyn("Is that ok? ", yn) == 0) { + cur_p->money += tot * price; + for (tot = i = 0; i < mp->num_in; i++) + mp->sq[i]->desc->houses = temp[i]; + } + } +} + +list_cur(mp) +reg MON *mp; { + + reg int i; + reg SQUARE *sqp; + + for (i = 0; i < mp->num_in; i++) { + sqp = mp->sq[i]; + if (sqp->desc->houses == 5) + printf("%s (H) ", sqp->name); + else + printf("%s (%d) ", sqp->name, sqp->desc->houses); + } + putchar('\n'); +} diff --git a/src/games/monop/initdeck.c b/src/games/monop/initdeck.c new file mode 100644 index 0000000..d0c7a3c --- /dev/null +++ b/src/games/monop/initdeck.c @@ -0,0 +1,140 @@ +# include +# include "deck.h" + +/* + * This program initializes the card files for monopoly. + * It reads in a data file with Com. Chest cards, followed by + * the Chance card. The two are seperated by a line of "%-". + * All other cards are seperated by lines of "%%". In the front + * of the file is the data for the decks in the same order. + * This includes the seek pointer for the start of each card. + * All cards start with their execution code, followed by the + * string to print, terminated with a null byte. + */ + +# define TRUE 1 +# define FALSE 0 + +# define bool char +# define reg register + +char *infile = "cards.inp", /* input file */ + *outfile = "cards.pck"; /* "packed" file */ + +long ftell(); + +DECK deck[2]; + +FILE *inf, *outf; + +main(ac, av) +int ac; +char *av[]; { + + getargs(ac, av); + if ((inf = fopen(infile, "r")) == NULL) { + perror(infile); + exit(1); + } + count(); + /* + * allocate space for pointers. + */ + CC_D.offsets = calloc(CC_D.num_cards + 1, sizeof (long)); + CH_D.offsets = calloc(CH_D.num_cards + 1, sizeof (long)); + fseek(inf, 0L, 0); + if ((outf = fopen(outfile, "w")) == NULL) { + perror(outfile); + exit(0); + } + + fwrite(deck, sizeof (DECK), 2, outf); + fwrite(CC_D.offsets, sizeof (long), CC_D.num_cards, outf); + fwrite(CH_D.offsets, sizeof (long), CH_D.num_cards, outf); + putem(); + + fclose(inf); + fseek(outf, 0, 0L); + fwrite(deck, sizeof (DECK), 2, outf); + fwrite(CC_D.offsets, sizeof (long), CC_D.num_cards, outf); + fwrite(CH_D.offsets, sizeof (long), CH_D.num_cards, outf); + fclose(outf); + printf("There were %d com. chest and %d chance cards\n", CC_D.num_cards, CH_D.num_cards); + exit(0); +} + +getargs(ac, av) +int ac; +char *av[]; { + + if (ac > 2) { + infile = av[2] ? av[2] : infile; + if (ac > 3) + outfile = av[3]; + } +} +/* + * count the cards + */ +count() { + + reg bool newline; + reg DECK *in_deck; + reg char c; + + newline = TRUE; + in_deck = &CC_D; + while ((c=getc(inf)) != EOF) + if (newline && c == '%') { + newline = FALSE; + in_deck->num_cards++; + if (getc(inf) == '-') + in_deck = &CH_D; + } + else + newline = (c == '\n'); + in_deck->num_cards++; +} +/* + * put strings in the file + */ +putem() { + + reg bool newline; + reg DECK *in_deck; + reg char c; + reg int num; + + in_deck = &CC_D; + CC_D.num_cards = 1; + CH_D.num_cards = 0; + CC_D.offsets[0] = ftell(outf); + putc(getc(inf), outf); + putc(getc(inf), outf); + for (num = 0; (c=getc(inf)) != '\n'; ) + num = num * 10 + (c - '0'); + putw(num, outf); + newline = FALSE; + while ((c=getc(inf)) != EOF) + if (newline && c == '%') { + putc('\0', outf); + newline = FALSE; + if (getc(inf) == '-') + in_deck = &CH_D; + while (getc(inf) != '\n') + continue; + in_deck->offsets[in_deck->num_cards++] = ftell(outf); + if ((c=getc(inf)) == EOF) + break; + putc(c, outf); + putc(c = getc(inf), outf); + for (num = 0; (c=getc(inf)) != EOF && c != '\n'; ) + num = num * 10 + (c - '0'); + putw(num, outf); + } + else { + putc(c, outf); + newline = (c == '\n'); + } + putc('\0', outf); +} diff --git a/src/games/monop/jail.c b/src/games/monop/jail.c new file mode 100644 index 0000000..c1309bc --- /dev/null +++ b/src/games/monop/jail.c @@ -0,0 +1,90 @@ +# include "monop.ext" + +/* + * This routine uses a get-out-of-jail-free card to get the + * player out of jail. + */ +card() { + + if (cur_p->loc != JAIL) { + printf("But you're not IN Jail\n"); + return; + } + if (cur_p->num_gojf == 0) { + printf("But you don't HAVE a get out of jail free card\n"); + return; + } + ret_card(cur_p); + cur_p->loc = 10; /* just visiting */ + cur_p->in_jail = 0; +} +/* + * This routine returns the players get-out-of-jail-free card + * to a deck. + */ +ret_card(plr) +reg PLAY *plr; { + + plr->num_gojf--; + if (CC_D.gojf_used) + CC_D.gojf_used = FALSE; + else + CH_D.gojf_used = FALSE; +} +/* + * This routine deals with paying your way out of jail. + */ +pay() { + + if (cur_p->loc != JAIL) { + printf("But you're not IN Jail\n"); + return; + } + cur_p->loc = 10; + cur_p->money -= 50; + cur_p->in_jail = 0; + printf("That cost you $50\n"); +} +/* + * This routine deals with a move in jail + */ +move_jail(r1, r2) +reg int r1, r2; { + + if (r1 != r2) { + printf("Sorry, that doesn't get you out\n"); + if (++(cur_p->in_jail) == 3) { + printf("It's your third turn and you didn't roll doubles. You have to pay $50\n"); + cur_p->money -= 50; +moveit: + cur_p->loc = 10; + cur_p->in_jail = 0; + move(r1+r2); + r1 = r2 - 1; /* kludge: stop new roll w/doub */ + return TRUE; + } + return FALSE; + } + else { + printf("Double roll gets you out.\n"); + goto moveit; + } +} +printturn() { + + if (cur_p->loc != JAIL) + return; + printf("(This is your "); + switch (cur_p->in_jail) { + case 0: + printf("1st"); + break; + case 1: + printf("2nd"); + break; + case 2: + printf("3rd (and final)"); + break; + } + printf(" turn in JAIL)\n"); +} diff --git a/src/games/monop/misc.c b/src/games/monop/misc.c new file mode 100644 index 0000000..cbf0089 --- /dev/null +++ b/src/games/monop/misc.c @@ -0,0 +1,326 @@ +# include "monop.ext" +# include +# include + +# define execsh(sh) execl(sh, shell_name[roll(1, num_names)-1], 0) + +static char *shell_def = "/bin/csh", + *shell_name[] = { + ".Hi Mom!", + ".Kick Me", + ".I'm really the next process down", + ".Hi Kids!", + ".This space for rent", + ".Singin' in the rain....", + ".I am but a Cog in the Wheel of Life", + ".Look out!!! Behind you!!!!!", + ".Looking for a good time, sailor?", + ".I don't get NO respect...", + ".Augghh! You peeked!" + }; + +static int num_names = sizeof shell_name / sizeof (char *);; + +char *shell_in(); + +/* + * This routine executes a truncated set of commands until a + * "yes or "no" answer is gotten. + */ +getyn(prompt) +reg char *prompt; { + + reg int com; + + for (;;) + if ((com=getinp(prompt, yn)) < 2) + return com; + else + (*func[com-2])(); +} +/* + * This routine tells the player if he's out of money. + */ +notify() { + + if (cur_p->money < 0) + printf("That leaves you $%d in debt\n", -cur_p->money); + else if (cur_p->money == 0) + printf("that leaves you broke\n"); + else if (fixing && !told_em && cur_p->money > 0) { + printf("-- You are now Solvent ---\n"); + told_em = TRUE; + } +} +/* + * This routine switches to the next player + */ +next_play() { + + player = ++player % num_play; + cur_p = &play[player]; + num_doub = 0; +} +/* + * This routine gets an integer from the keyboard after the + * given prompt. + */ +get_int(prompt) +reg char *prompt; { + + reg int num; + reg char *sp; + char buf[257]; + + for (;;) { +inter: + printf(prompt); + num = 0; + for (sp = buf; (*sp=getchar()) != '\n' && !feof(stdin); sp++) + if (*sp == -1) /* check for interrupted system call */ + goto inter; + if (feof(stdin)) { + clearerr(stdin); + continue; + } + if (sp == buf) + continue; + for (sp = buf; isspace(*sp); sp++) + continue; + for (; isdigit(*sp); sp++) + num = num * 10 + *sp - '0'; + if (*sp == '\n') + return num; + else + printf("I can't understand that\n"); + } +} +/* + * This routine sets the monopoly flag from the list given. + */ +set_ownlist(pl) +int pl; { + + reg int num; /* general counter */ + reg MON *orig; /* remember starting monop ptr */ + reg OWN *op; /* current owned prop */ + OWN *orig_op; /* origianl prop before loop */ + + op = play[pl].own_list; +#ifdef DEBUG + printf("op [%d] = play[pl [%d] ].own_list;\n", op, pl); +#endif + while (op) { +#ifdef DEBUG + printf("op->sqr->type = %d\n", op->sqr->type); +#endif + switch (op->sqr->type) { + case UTIL: +#ifdef DEBUG + printf(" case UTIL:\n"); +#endif + for (num = 0; op && op->sqr->type == UTIL; op = op->next) + num++; + play[pl].num_util = num; +#ifdef DEBUG + printf("play[pl].num_util = num [%d];\n", num); +#endif + break; + case RR: +#ifdef DEBUG + printf(" case RR:\n"); +#endif + for (num = 0; op && op->sqr->type == RR; op = op->next) { +#ifdef DEBUG + printf("iter: %d\n", num); + printf("op = %d, op->sqr = %d, op->sqr->type = %d\n", op, op->sqr, op->sqr->type); +#endif + num++; + } + play[pl].num_rr = num; +#ifdef DEBUG + printf("play[pl].num_rr = num [%d];\n", num); +#endif + break; + case PRPTY: +#ifdef DEBUG + printf(" case PRPTY:\n"); +#endif + orig = op->sqr->desc->mon_desc; + orig_op = op; + num = 0; + while (op && op->sqr->desc->mon_desc == orig) { +#ifdef DEBUG + printf("iter: %d\n", num); +#endif + num++; +#ifdef DEBUG + printf("op = op->next "); +#endif + op = op->next; +#ifdef DEBUG + printf("[%d];\n", op); +#endif + } +#ifdef DEBUG + printf("num = %d\n"); +#endif + if (orig == 0) { + printf("panic: bad monopoly descriptor: orig = %d\n", orig); + printf("player # %d\n", pl+1); + printhold(pl); + printf("orig_op = %d\n", orig_op); + printf("orig_op->sqr->type = %d (PRPTY)\n", op->sqr->type); + printf("orig_op->next = %d\n", op->next); + printf("orig_op->sqr->desc = %d\n", op->sqr->desc); + printf("op = %d\n", op); + printf("op->sqr->type = %d (PRPTY)\n", op->sqr->type); + printf("op->next = %d\n", op->next); + printf("op->sqr->desc = %d\n", op->sqr->desc); + printf("num = %d\n", num); + } +#ifdef DEBUG + printf("orig->num_in = %d\n", orig->num_in); +#endif + if (num == orig->num_in) + is_monop(orig, pl); + else + isnot_monop(orig); + break; + } + } +} +/* + * This routine sets things up as if it is a new monopoly + */ +is_monop(mp, pl) +reg MON *mp; +int pl; { + + reg char *sp; + reg int i; + + mp->owner = pl; + mp->num_own = mp->num_in; + for (i = 0; i < mp->num_in; i++) + mp->sq[i]->desc->monop = TRUE; + mp->name = mp->mon_n; +} +/* + * This routine sets things up as if it is no longer a monopoly + */ +isnot_monop(mp) +reg MON *mp; { + + reg char *sp; + reg int i; + + mp->owner = -1; + for (i = 0; i < mp->num_in; i++) + mp->sq[i]->desc->monop = FALSE; + mp->name = mp->not_m; +} +/* + * This routine gives a list of the current player's routine + */ +list() { + + printhold(player); +} +/* + * This routine gives a list of a given players holdings + */ +list_all() { + + reg int pl; + + while ((pl=getinp("Whose holdings do you want to see? ", name_list)) < num_play) + printhold(pl); +} +/* + * This routine gives the players a chance before it exits. + */ +quit() { + + putchar('\n'); + if (getyn("Do you all really want to quit? ", yn) == 0) + exit(0); + signal(2, quit); +} +/* + * This routine copies one structure to another + */ +cpy_st(s1, s2, size) +reg int *s1, *s2, size; { + + size /= 2; + while (size--) + *s1++ = *s2++; +} +/* + * This routine forks off a shell. It uses the users login shell + */ +shell_out() { + + static char *shell = NULL; + + printline(); + if (shell == NULL) + shell = shell_in(); + fflush(); + if (!fork()) { + signal(SIGINT, SIG_DFL); + execsh(shell); + } + ignoresigs(); + wait(); + resetsigs(); + putchar('\n'); + printline(); +} +/* + * This routine looks up the users login shell + */ +# include + +struct passwd *getpwuid(); + +char *getenv(); + +char * +shell_in() { + + reg struct passwd *pp; + reg char *sp; + + if ((sp = getenv("SHELL")) == NULL) { + pp = getpwuid(getuid()); + if (pp->pw_shell[0] != '\0') + return pp->pw_shell; + else + return shell_def; + /*return (*(pp->pw_shell) != '\0' ? pp->pw_shell : shell_def);*/ + } + return sp; +} +/* + * This routine sets things up to ignore all the signals. + */ +ignoresigs() { + + reg int i; + + for (i = 0; i < NSIG; i++) + signal(i, SIG_IGN); +} +/* + * This routine sets up things as they were before. + */ +resetsigs() { + + reg int i; + + for (i = 0; i < NSIG; i++) + signal(i, SIG_DFL); + signal(2, quit); +} diff --git a/src/games/monop/mon.dat b/src/games/monop/mon.dat new file mode 100644 index 0000000..cd49305 --- /dev/null +++ b/src/games/monop/mon.dat @@ -0,0 +1,9 @@ +/* name owner num_in num_own h_cost not_m mon_n sq */ +{0, -1, 2, 0, 1, "Purple", "PURPLE", {1,3}}, +{0, -1, 3, 0, 1, "Lt. Blue", "LT. BLUE", {6,8,9}}, +{0, -1, 3, 0, 2, "Violet", "VIOLET", {11,13,14}}, +{0, -1, 3, 0, 2, "Orange", "ORANGE", {16,18,19}}, +{0, -1, 3, 0, 3, "Red", "RED", {21,23,24}}, +{0, -1, 3, 0, 3, "Yellow", "YELLOW", {26,27,29}}, +{0, -1, 3, 0, 4, "Green", "GREEN", {31,32,34}}, +{0, -1, 2, 0, 4, "Dk. Blue", "DK. BLUE", {37,39}} diff --git a/src/games/monop/monop.6 b/src/games/monop/monop.6 new file mode 100644 index 0000000..2de9891 --- /dev/null +++ b/src/games/monop/monop.6 @@ -0,0 +1,164 @@ +.\" Copyright (c) 1980 Regents of the University of California. +.\" All rights reserved. The Berkeley software License Agreement +.\" specifies the terms and conditions for redistribution. +.\" +.\" @(#)monop.6 6.2 (Berkeley) 5/6/86 +.\" +.de Sc \" start command list macro +.ie n .PD 0 +.el .PD 0.5 +.sp +.. +.de Cm \" define command macro +.TP 10 +.ie t .BR "\\$1" : +.el .IR "\\$1" : +.. +.de Ec \" end command macro +.PD 1 +.. +.TH MONOP 6 "May 6, 1986" +.UC 4 +.SH NAME +monop \- Monopoly game +.SH SYNOPSIS +.B /usr/games/monop +[ file ] +.SH DESCRIPTION +.I Monop +is reminiscent of the Parker Brother's game Monopoly, and +monitors a game between 1 to 9 users. +It is assumed that the rules of Monopoly are known. +The game follows the standard rules, with the exception that, +if a property goes up for auction and there are only two solvent players, +no auction is held and the property remains unowned. +.PP +The game, in effect, lends the player money, +so it is possible to buy something which you cannot afford. +However, as soon as a person goes into debt, +he must \*(lqfix the problem\*(rq, +.IR i.e. , +make himself solvent, before play can continue. +If this is not possible, the player's property reverts to his debtee, +either a player or the bank. +A player can resign at any time to any person or the bank, +which puts the property back on the board, unowned. +.PP +Any time that the response to a question is a +.IR string , +e.g., a name, place or person, you can type `?' to get a list of valid answers. +It is not possible to input a negative number, nor is it ever necessary. +.Sc +.IR "A Summary of Commands" : +.Cm quit +quit game: This allows you to quit the game. It asks you if you're sure. +.Cm print +print board: This prints out the current board. +The columns have the following meanings (column headings are the same for the +.BR where , +.BR "own holdings" , +and +.B holdings +commands): +.PP +.RS 10 +.TP "\w'Name\ \ 'u" +Name +The first ten characters of the name of the square +.TP +Own +The \fInumber\fR of the owner of the property. +.TP +Price +The cost of the property (if any) +.TP +Mg +This field has a `*' in it if the property is mortgaged +.TP +# +If the property is a Utility or Railroad, this is the number +of such owned by the owner. +If the property is land, this is the number of houses on it. +.TP +Rent +Current rent on the property. If it is not owned, there is no rent. +.RE +.Cm where +where players are: Tells you where all the players are. +A `*' indicates the current player. +.Cm "own\ holdings" +List your own holdings, +.IR i.e. , +money, get-out-of-jail-free cards, and property. +.Cm holdings +holdings list: Look at anyone's holdings. +It will ask you whose holdings you wish to look at. +When you are finished, type \*(lqdone\*(rq. +.Cm shell +shell escape: Escape to a shell. When the shell dies, +the program continues where you left off. +.Cm mortgage +mortgage property: +Sets up a list of mortgageable property, and asks which you wish to mortgage. +.Cm unmortgage +unmortgage property: +Unmortgage mortgaged property. +.Cm buy +buy houses: +Sets up a list of monopolies on which you can buy houses. +If there is more than one, it asks you which you want to buy for. +It then asks you how many for each piece of property, +giving the current amount in parentheses after the property name. +If you build in an unbalanced manner +(a disparity of more than one house within the same monopoly), +it asks you to re-input things. +.Cm sell +sell houses: +Sets up a list of monopolies from which you can sell houses. +It operates in an analogous manner to +.I buy. +.Cm card +card for jail: +Use a get-out-of-jail-free card to get out of jail. +If you're not in jail, or you don't have one, it tells you so. +.Cm pay +pay for jail: +Pay $50 to get out of jail, from whence you are put on Just Visiting. +Difficult to do if you're not there. +.Cm trade +This allows you to trade with another player. +It asks you whom you wish to trade with, +and then asks you what each wishes to give up. +You can get a summary at the end, and, in all cases, +it asks for confirmation of the trade before doing it. +.Cm resign +Resign to another player or the bank. +If you resign to the bank, all property reverts to its virgin state, +and get-out-of-jail free cards revert to the deck. +.Cm save +save game: +Save the current game in a file for later play. +You can continue play after saving, +either by adding the file in which you saved the game after the +.I monop +command, or by using the +.I restore +command (see below). +It will ask you which file you wish to save it in, +and, if the file exists, confirm that you wish to overwrite it. +.Cm restore +restore game: +Read in a previously saved game from a file. +It leaves the file intact. +.Cm roll +Roll the dice and move forward to your new location. +If you simply hit the key instead of a command, +it is the same as typing +.IR roll . +.Ec +.SH AUTHOR +Ken Arnold +.SH FILES +/usr/games/lib/cards.pck Chance and Community Chest cards +.SH BUGS +No command can be given an argument instead of a response to a query. diff --git a/src/games/monop/monop.c b/src/games/monop/monop.c new file mode 100644 index 0000000..fd6023d --- /dev/null +++ b/src/games/monop/monop.c @@ -0,0 +1,121 @@ +# include "monop.def" + +/* + * This program implements a monopoly game + */ +main(ac, av) +reg int ac; +reg char *av[]; { + + + srand(getpid()); + if (ac > 1) { + if (!rest_f(av[1])) + restore(); + } + else { + getplayers(); + init_players(); + init_monops(); + } + num_luck = sizeof lucky_mes / sizeof (char *); + init_decks(); + signal(2, quit); + for (;;) { + printf("\n%s (%d) (cash $%d) on %s\n", cur_p->name, player + 1, + cur_p->money, board[cur_p->loc].name); + printturn(); + force_morg(); + execute(getinp("-- Command: ", comlist)); + } +} +/* + * This routine gets the names of the players + */ +getplayers() { + + reg char *sp; + reg int i, j; + char buf[257]; + +blew_it: + for (;;) { + if ((num_play=get_int("How many players? ")) <= 0 || + num_play > MAX_PL) + printf("Sorry. Number must range from 1 to 9\n"); + else + break; + } + cur_p = play = (PLAY *) calloc(num_play, sizeof (PLAY)); + for (i = 0; i < num_play; i++) { +over: + printf("Player %d's name: ", i + 1); + for (sp = buf; (*sp=getchar()) != '\n' && !feof(stdin); sp++) + continue; + if (feof(stdin)) + clearerr(stdin); + if (sp == buf) + goto over; + *sp++ = '\0'; + strcpy(name_list[i]=play[i].name=(char *)calloc(1,sp-buf),buf); + play[i].money = 1500; + } + name_list[i++] = "done"; + name_list[i] = 0; + for (i = 0; i < num_play; i++) + for (j = i + 1; j < num_play; j++) + if (strcmp(name_list[i], name_list[j]) == 0) { + if (i != num_play - 1) + printf("Hey!!! Some of those are IDENTICAL!! Let's try that again....\n"); + else + printf("\"done\" is a reserved word. Please try again\n"); + for (i = 0; i < num_play; i++) + cfree(play[i].name); + cfree(play); + goto blew_it; + } +} +/* + * This routine figures out who goes first + */ +init_players() { + + reg int i, rl, cur_max; + bool over; + int max_pl; + +again: + putchar('\n'); + for (cur_max = i = 0; i < num_play; i++) { + printf("%s (%d) rolls %d\n", play[i].name, i+1, rl=roll(2, 6)); + if (rl > cur_max) { + over = FALSE; + cur_max = rl; + max_pl = i; + } + else if (rl == cur_max) + over++; + } + if (over) { + printf("%d people rolled the same thing, so we'll try again\n", + over + 1); + goto again; + } + player = max_pl; + cur_p = &play[max_pl]; + printf("%s (%d) goes first\n", cur_p->name, max_pl + 1); +} +/* + * This routine initalizes the monopoly structures. + */ +init_monops() { + + reg MON *mp; + reg int i; + + for (mp = mon; mp < &mon[N_MON]; mp++) { + mp->name = mp->not_m; + for (i = 0; i < mp->num_in; i++) + mp->sq[i] = &board[(int)(mp->sq[i])]; + } +} diff --git a/src/games/monop/monop.def b/src/games/monop/monop.def new file mode 100644 index 0000000..d7acbe2 --- /dev/null +++ b/src/games/monop/monop.def @@ -0,0 +1,89 @@ +# include "monop.h" +# include "deck.h" + +bool fixing, /* set if fixing up debt */ + trading, /* set if in process of trading */ + told_em, /* set if told user he's out of debt */ + spec; /* set if moving by card to RR or UTIL */ + +char *name_list[MAX_PL+2], /* list of players' names */ + *comlist[] = { /* list of normal commands */ + "quit", /* 0 */ "print", /* 1 */ + "where", /* 2 */ "own holdings", /* 3 */ + "holdings", /* 4 */ "shell", /* 5 */ + "mortgage", /* 6 */ "unmortgage", /* 7 */ + "buy houses", /* 8 */ "sell houses", /* 9 */ + "card", /* 10 */ "pay", /* 11 */ + "trade", /* 12 */ "resign", /* 13 */ + "save", /* 14 */ "restore", /* 15 */ + "roll", /* 16 */ "", /* 17 */ + 0 + }, + *yn[] = { /* list of commands for yes/no answers */ + "yes", /* 0 */ "no", /* 1 */ + "quit", /* 2 */ "print", /* 3 */ + "where", /* 4 */ "own holdings", /* 5 */ + "holdings", /* 6 */ "shell", /* 7 */ + 0 + }, + *lucky_mes[] = { /* "got lucky" messages */ + "You lucky stiff", "You got lucky", + "What a lucky person!", "You must have a 4-leaf clover", + "My, my! Aren't we lucky!", "Luck smiles upon you", + "You got lucky this time", "Lucky person!", + "Your karma must certainly be together", + "How beautifully Cosmic", "Wow, you must be really with it" + /* "I want your autograph", -- Save for later */ + }; + +int player, /* current player number */ + num_play, /* current number of players */ + num_doub, /* # of doubles current player rolled */ + /* # of "got lucky" messages */ + num_luck = sizeof lucky_mes / sizeof (char *), + /* list of command functions */ + buy_houses(), card(), do_move(), do_move(), list(), list_all(), + mortgage(), pay(), printboard(), quit(), resign(), restore(), + rub(), save(), sell_houses(), shell_out(), trade(), + unmortgage(), where(), + (*func[])() = { /* array of function calls for commands */ + quit, /* quit game |* 0 *| */ + printboard, /* print board |* 1 *| */ + where, /* where players are |* 2 *| */ + list, /* own holdings |* 3 *| */ + list_all, /* holdings list |* 4 *| */ + shell_out, /* shell |* 5 *| */ + mortgage, /* mortgage property |* 6 *| */ + unmortgage, /* unmortgage property |* 7 *| */ + buy_houses, /* buy houses |* 8 *| */ + sell_houses, /* sell houses |* 9 *| */ + card, /* card for jail |* 10 *| */ + pay, /* pay for jail |* 11 *| */ + trade, /* trade |* 12 *| */ + resign, /* resign |* 13 *| */ + save, /* save game |* 14 *| */ + restore, /* restore game |* 15 *| */ + do_move, /* roll |* 16 *| */ + do_move /* "" |* 17 *| */ + }; + +DECK deck[2]; /* Chance and Community Chest */ + +PLAY *play, /* player structure array ("calloc"ed) */ + *cur_p; /* pointer to current player's struct */ + +RR_S rr[N_RR]; /* raildroad descriptions */ + +UTIL_S util[2]; /* utility descriptions */ + +MON mon[N_MON] = { /* monopoly descriptions */ +# include "mon.dat" +}; + +PROP prop[N_PROP] = { /* typical properties */ +# include "prop.dat" +}; + +SQUARE board[N_SQRS+1] = { /* board itself (+1 for Jail) */ +# include "brd.dat" +}; diff --git a/src/games/monop/monop.ext b/src/games/monop/monop.ext new file mode 100644 index 0000000..e487dda --- /dev/null +++ b/src/games/monop/monop.ext @@ -0,0 +1,22 @@ +# include "monop.h" +# include "deck.h" + +extern bool trading, spec, fixing, told_em; + +extern char *yn[], *comlist[], *name_list[], *lucky_mes[]; + +extern int num_play, player, num_doub, num_luck, (*func[])(); + +extern DECK deck[2]; + +extern MON mon[]; + +extern PLAY *play, *cur_p; + +extern PROP prop[]; + +extern RR_S rr[]; + +extern SQUARE board[]; + +extern UTIL_S util[]; diff --git a/src/games/monop/monop.h b/src/games/monop/monop.h new file mode 100644 index 0000000..0e53371 --- /dev/null +++ b/src/games/monop/monop.h @@ -0,0 +1,98 @@ +# include + +# define reg register +# define shrt char +# define bool char +# define unsgn unsigned + +# define TRUE (1) +# define FALSE (0) + +# define N_MON 8 /* number of monopolies */ +# define N_PROP 22 /* number of normal property squares */ +# define N_RR 4 /* number of railroads */ +# define N_UTIL 2 /* number of utilities */ +# define N_SQRS 40 /* number of squares on board */ +# define MAX_PL 9 /* maximum number of players */ +# define MAX_PRP (N_PROP+N_RR+N_UTIL) /* max # ownable property */ + + /* square type numbers */ +# define PRPTY 0 /* normal property */ +# define RR 1 /* railroad */ +# define UTIL 2 /* water works - electric co */ +# define SAFE 3 /* safe spot */ +# define CC 4 /* community chest */ +# define CHANCE 5 /* chance (surprise!!!) */ +# define SPEC 6 /* special */ + +# define JAIL 40 /* JAIL square number */ + +# define lucky(str) printf("%s%s\n",str,lucky_mes[roll(1,num_luck)-1]) +# define printline() printf("------------------------------\n") +# define sqnum(sqp) (sqp - board) +# define swap(A1,A2) if ((A1) != (A2)) { \ + (A1) ^= (A2); \ + (A2) ^= (A1); \ + (A1) ^= (A2); \ + } + +struct sqr_st { /* structure for square */ + char *name; /* place name */ + shrt owner; /* owner number */ + shrt type; /* place type */ + char *desc; /* description struct */ + int cost; /* cost */ +}; + +typedef struct sqr_st SQUARE; + +struct mon_st { /* monopoly descriptin structure */ + char *name; /* monop. name (color) */ + shrt owner; /* owner of monopoly */ + shrt num_in; /* # in monopoly */ + shrt num_own; /* # owned (-1: not poss. monop)*/ + shrt h_cost; /* price of houses */ + char *not_m; /* name if not monopoly */ + char *mon_n; /* name if a monopoly */ + SQUARE *sq[3]; /* list of squares in monop */ +}; + +typedef struct mon_st MON; + +struct prp_st { /* property description structure */ + bool morg; /* set if mortgaged */ + bool monop; /* set if monopoly */ + shrt square; /* square description */ + shrt houses; /* number of houses */ + MON *mon_desc; /* name of color */ + int rent[6]; /* rents */ +}; + +struct own_st { /* element in list owned things */ + SQUARE *sqr; /* pointer to square */ + struct own_st *next; /* next in list */ +}; + +typedef struct own_st OWN; + +struct plr_st { /* player description structure */ + char *name; /* owner name */ + shrt num_gojf; /* # of get-out-of-jail-free's */ + shrt num_rr; /* # of railroads owned */ + shrt num_util; /* # of water works/elec. co. */ + shrt loc; /* location on board */ + shrt in_jail; /* count of turns in jail */ + int money; /* amount of money */ + OWN *own_list; /* start of propery list */ +}; + +struct rr_st { /* railroad description structure */ + bool morg; /* set if morgaged */ +}; + +typedef struct plr_st PLAY; +typedef struct prp_st PROP; +typedef struct rr_st RR_S; +typedef struct rr_st UTIL_S; + +int cc(), chance(), lux_tax(), goto_jail(), inc_tax(); diff --git a/src/games/monop/morg.c b/src/games/monop/morg.c new file mode 100644 index 0000000..6a07347 --- /dev/null +++ b/src/games/monop/morg.c @@ -0,0 +1,173 @@ +# include "monop.ext" + +/* + * These routines deal with mortgaging. + */ + +static char *names[MAX_PRP+2], + *morg_coms[] = { + "quit", /* 0 */ + "print", /* 1 */ + "where", /* 2 */ + "own holdings", /* 3 */ + "holdings", /* 4 */ + "shell", /* 5 */ + "mortgage", /* 6 */ + "unmortgage", /* 7 */ + "buy", /* 8 */ + "sell", /* 9 */ + "card", /* 10 */ + "pay", /* 11 */ + "trade", /* 12 */ + "resign", /* 13 */ + "save game", /* 14 */ + "restore game", /* 15 */ + 0 + }; + +static shrt square[MAX_PRP+2]; + +static int num_good,got_houses; + +/* + * This routine is the command level response the mortgage command. + * it gets the list of mortgageable property and asks which are to + * be mortgaged. + */ +mortgage() { + + reg int prop; + + for (;;) { + if (set_mlist() == 0) { + if (got_houses) + printf("You can't mortgage property with houses on it.\n"); + else + printf("You don't have any un-mortgaged property.\n"); + return; + } + if (num_good == 1) { + printf("Your only mortageable property is %s\n",names[0]); + if (getyn("Do you want to mortgage it? ") == 0) + m(square[0]); + return; + } + prop = getinp("Which property do you want to mortgage? ",names); + if (prop == num_good) + return; + m(square[prop]); + notify(cur_p); + } +} +/* + * This routine sets up the list of mortgageable property + */ +set_mlist() { + + reg OWN *op; + + num_good = 0; + for (op = cur_p->own_list; op; op = op->next) + if (!op->sqr->desc->morg) + if (op->sqr->type == PRPTY && op->sqr->desc->houses) + got_houses++; + else { + names[num_good] = op->sqr->name; + square[num_good++] = sqnum(op->sqr); + } + names[num_good++] = "done"; + names[num_good--] = 0; + return num_good; +} +/* + * This routine actually mortgages the property. + */ +m(prop) +reg int prop; { + + reg int price; + + price = board[prop].cost/2; + board[prop].desc->morg = TRUE; + printf("That got you $%d\n",price); + cur_p->money += price; +} +/* + * This routine is the command level repsponse to the unmortgage + * command. It gets the list of mortgaged property and asks which are + * to be unmortgaged. + */ +unmortgage() { + + reg int prop; + + for (;;) { + if (set_umlist() == 0) { + printf("You don't have any mortgaged property.\n"); + return; + } + if (num_good == 1) { + printf("Your only mortaged property is %s\n",names[0]); + if (getyn("Do you want to unmortgage it? ") == 0) + unm(square[0]); + return; + } + prop = getinp("Which property do you want to unmortgage? ",names); + if (prop == num_good) + return; + unm(square[prop]); + } +} +/* + * This routine sets up the list of mortgaged property + */ +set_umlist() { + + reg OWN *op; + + num_good = 0; + for (op = cur_p->own_list; op; op = op->next) + if (op->sqr->desc->morg) { + names[num_good] = op->sqr->name; + square[num_good++] = sqnum(op->sqr); + } + names[num_good++] = "done"; + names[num_good--] = 0; + return num_good; +} +/* + * This routine actually unmortgages the property + */ +unm(prop) +reg int prop; { + + reg int price; + + price = board[prop].cost/2; + board[prop].desc->morg = FALSE; + price += price/10; + printf("That cost you $%d\n",price); + cur_p->money -= price; + set_umlist(); +} +/* + * This routine forces the indebted player to fix his + * financial woes. + */ +force_morg() { + + told_em = fixing = TRUE; + while (cur_p->money <= 0) + fix_ex(getinp("How are you going to fix it up? ",morg_coms)); + fixing = FALSE; +} +/* + * This routine is a special execute for the force_morg routine + */ +fix_ex(com_num) +reg int com_num; { + + told_em = FALSE; + (*func[com_num])(); + notify(); +} diff --git a/src/games/monop/print.c b/src/games/monop/print.c new file mode 100644 index 0000000..d7e27b6 --- /dev/null +++ b/src/games/monop/print.c @@ -0,0 +1,154 @@ +# include "monop.ext" + +static char buf[80], /* output buffer */ + *header = "Name Own Price Mg # Rent"; + +/* + * This routine prints out the current board + */ +printboard() { + + reg int i; + + printf("%s\t%s\n", header, header); + for (i = 0; i < N_SQRS/2; i++) { + printsq(i, FALSE); + putchar('\t'); + printsq(i+N_SQRS/2, TRUE); + } +} +/* + * This routine lists where each player is. + */ +where() { + + reg int i; + char *bsp; + + printf("%s Player\n", header); + for (i = 0; i < num_play; i++) { + printsq(play[i].loc, FALSE); + printf(" %s (%d)", play[i].name, i+1); + if (cur_p == &play[i]) + printf(" *"); + putchar('\n'); + } +} +/* + * This routine prints out an individual square + */ +printsq(sqn, eoln) +int sqn; +reg bool eoln; { + + reg int rnt; + reg PROP *pp; + reg SQUARE *sqp; + int i; + + sqp = &board[sqn]; + printf("%-10.10s", sqp->name); + if (sqn == JAIL) + goto spec; + switch (sqp->type) { + case SAFE: + case CC: + case CHANCE: + case SPEC: +spec: + if (!eoln) + printf(" "); + break; + case PRPTY: + pp = sqp->desc; + if (sqp->owner < 0) { + printf(" - %-8.8s %3d", pp->mon_desc->name, sqp->cost); + if (!eoln) + printf(" "); + break; + } + printf(" %d %-8.8s %3d", sqp->owner+1, pp->mon_desc->name, + sqp->cost); + printmorg(sqp); + if (pp->monop) { + if (pp->houses < 5) + if (pp->houses > 0) + printf("%d %4d", pp->houses, + pp->rent[pp->houses]); + else + printf("0 %4d", pp->rent[0] * 2); + else + printf("H %4d", pp->rent[5]); + } + else + printf(" %4d", pp->rent[0]); + break; + case UTIL: + if (sqp->owner < 0) { + printf(" - 150"); + if (!eoln) + printf(" "); + break; + } + printf(" %d 150", sqp->owner+1); + printmorg(sqp); + printf("%d", play[sqp->owner].num_util); + if (!eoln) + printf(" "); + break; + case RR: + if (sqp->owner < 0) { + printf(" - Railroad 200"); + if (!eoln) + printf(" "); + break; + } + printf(" %d Railroad 200", sqp->owner+1); + printmorg(sqp); + rnt = 25; + rnt <<= play[sqp->owner].num_rr - 1; + printf("%d %4d", play[sqp->owner].num_rr, 25 << (play[sqp->owner].num_rr - 1)); + break; + } + if (eoln) + putchar('\n'); +} +/* + * This routine prints out the mortgage flag. + */ +printmorg(sqp) +reg SQUARE *sqp; { + + if (sqp->desc->morg) + printf(" * "); + else + printf(" "); +} +/* + * This routine lists the holdings of the player given + */ +printhold(pl) +reg int pl; { + + reg OWN *op; + reg PLAY *pp; + char *bsp; + + pp = &play[pl]; + printf("%s's (%d) holdings (Total worth: $%d):\n", name_list[pl], pl+1, + pp->money + prop_worth(pp)); + printf("\t$%d", pp->money); + if (pp->num_gojf) { + printf(", %d get-out-of-jail-free card", pp->num_gojf); + if (pp->num_gojf > 1) + putchar('s'); + } + putchar('\n'); + if (pp->own_list) { + printf("\t%s\n", header); + for (op = pp->own_list; op; op = op->next) { + putchar('\t'); + printsq(sqnum(op->sqr), TRUE); + } + } +} diff --git a/src/games/monop/prop.c b/src/games/monop/prop.c new file mode 100644 index 0000000..846f2ff --- /dev/null +++ b/src/games/monop/prop.c @@ -0,0 +1,172 @@ +# include "monop.ext" + +/* + * This routine deals with buying property, setting all the + * appropriate flags. + */ +buy(player, sqrp) +reg int player; +reg SQUARE *sqrp; { + + trading = FALSE; + sqrp->owner = player; + add_list(player, &(play[player].own_list), cur_p->loc); +} +/* + * This routine adds an item to the list. + */ +add_list(plr, head, op_sqr) +int plr; +OWN **head; +int op_sqr; { + + reg int val; + reg OWN *tp, *last_tp; + MON *mp; + OWN *op; + + op = calloc(1, sizeof (OWN)); + op->sqr = &board[op_sqr]; + val = value(op->sqr); + last_tp = NULL; + for (tp = *head; tp && value(tp->sqr) < val; tp = tp->next) + if (val == value(tp->sqr)) { + cfree(op); + return; + } + else + last_tp = tp; + op->next = tp; + if (last_tp != NULL) + last_tp->next = op; + else + *head = op; + if (!trading) + set_ownlist(plr); +} +/* + * This routine deletes property from the list. + */ +del_list(plr, head, op_sqr) +int plr; +OWN **head; +shrt op_sqr; { + + reg int i; + reg OWN *op, *last_op; + + switch (board[op_sqr].type) { + case PRPTY: + board[op_sqr].desc->mon_desc->num_own--; + break; + case RR: + play[plr].num_rr--; + break; + case UTIL: + play[plr].num_util--; + break; + } + last_op = NULL; + for (op = *head; op; op = op->next) + if (op->sqr == &board[op_sqr]) + break; + else + last_op = op; + if (last_op == NULL) + *head = op->next; + else { + last_op->next = op->next; + cfree(op); + } +} +/* + * This routine calculates the value for sorting of the + * given square. + */ +value(sqp) +reg SQUARE *sqp; { + + reg int sqr; + + sqr = sqnum(sqp); + switch (sqp->type) { + case SAFE: + return 0; + case SPEC: + return 1; + case UTIL: + if (sqr == 12) + return 2; + else + return 3; + case RR: + return 4 + sqr/10; + case PRPTY: + return 8 + (PROP *)(sqp->desc) - prop; + } +} +/* + * This routine accepts bids for the current peice + * of property. + */ +bid() { + + static bool in[MAX_PL]; + reg int i, num_in, cur_max; + char buf[80]; + int cur_bid; + + printf("\nSo it goes up for auction. Type your bid after your name\n"); + for (i = 0; i < num_play; i++) + in[i] = TRUE; + i = -1; + cur_max = 0; + num_in = num_play; + while (num_in > 1 || (cur_max == 0 && num_in > 0)) { + i = ++i % num_play; + if (in[i]) { + do { + sprintf(buf, "%s: ", name_list[i]); + cur_bid = get_int(buf); + if (cur_bid == 0) { + in[i] = FALSE; + if (--num_in == 0) + break; + } + else if (cur_bid <= cur_max) { + printf("You must bid higher than %d to stay in\n", cur_max); + printf("(bid of 0 drops you out)\n"); + } + } while (cur_bid != 0 && cur_bid <= cur_max); + cur_max = (cur_bid ? cur_bid : cur_max); + } + } + if (cur_max != 0) { + while (!in[i]) + i = ++i % num_play; + printf("It goes to %s (%d) for $%d\n",play[i].name,i+1,cur_max); + buy(i, &board[cur_p->loc]); + play[i].money -= cur_max; + } + else + printf("Nobody seems to want it, so we'll leave it for later\n"); +} +/* + * This routine calculates the value of the property + * of given player. + */ +prop_worth(plp) +reg PLAY *plp; { + + reg OWN *op; + reg int worth; + + worth = 0; + for (op = plp->own_list; op; op = op->next) { + if (op->sqr->type == PRPTY && op->sqr->desc->monop) + worth += op->sqr->desc->mon_desc->h_cost * 50 * + op->sqr->desc->houses; + worth += op->sqr->cost; + } + return worth; +} diff --git a/src/games/monop/prop.dat b/src/games/monop/prop.dat new file mode 100644 index 0000000..c947b39 --- /dev/null +++ b/src/games/monop/prop.dat @@ -0,0 +1,23 @@ +/* morg monop square houses mon_desc rent */ +{0, 0, 1, 0, &mon[0], { 2, 10, 30, 90, 160, 250} }, +{0, 0, 3, 0, &mon[0], { 4, 20, 60, 180, 320, 450} }, +{0, 0, 6, 0, &mon[1], { 6, 30, 90, 270, 400, 550} }, +{0, 0, 7, 0, &mon[1], { 6, 30, 90, 270, 400, 550} }, +{0, 0, 9, 0, &mon[1], { 8, 40,100, 300, 450, 600} }, +{0, 0, 11, 0, &mon[2], {10, 50,150, 450, 625, 750} }, +{0, 0, 13, 0, &mon[2], {10, 50,150, 450, 625, 750} }, +{0, 0, 14, 0, &mon[2], {12, 60,180, 500, 700, 900} }, +{0, 0, 16, 0, &mon[3], {14, 70,200, 550, 750, 950} }, +{0, 0, 17, 0, &mon[3], {14, 70,200, 550, 750, 950} }, +{0, 0, 19, 0, &mon[3], {16, 80,220, 600, 800,1000} }, +{0, 0, 21, 0, &mon[4], {18, 90,250, 700, 875,1050} }, +{0, 0, 23, 0, &mon[4], {18, 90,250, 700, 875,1050} }, +{0, 0, 24, 0, &mon[4], {20,100,300, 750, 925,1100} }, +{0, 0, 26, 0, &mon[5], {22,110,330, 800, 975,1150} }, +{0, 0, 27, 0, &mon[5], {22,110,330, 800, 975,1150} }, +{0, 0, 29, 0, &mon[5], {24,120,360, 850,1025,1200} }, +{0, 0, 31, 0, &mon[6], {26,130,390, 900,1100,1275} }, +{0, 0, 32, 0, &mon[6], {26,130,390, 900,1100,1275} }, +{0, 0, 34, 0, &mon[6], {28,150,450,1000,1200,1400} }, +{0, 0, 37, 0, &mon[7], {35,175,500,1100,1300,1500} }, +{0, 0, 39, 0, &mon[7], {50,200,600,1400,1700,2000} } diff --git a/src/games/monop/rent.c b/src/games/monop/rent.c new file mode 100644 index 0000000..7357f8f --- /dev/null +++ b/src/games/monop/rent.c @@ -0,0 +1,55 @@ +# include "monop.ext" + +/* + * This routine has the player pay rent + */ +rent(sqp) +reg SQUARE *sqp; { + + reg int rnt; + reg PROP *pp; + PLAY *plp; + + plp = &play[sqp->owner]; + printf("Owned by %s\n", plp->name); + if (sqp->desc->morg) { + lucky("The thing is mortgaged. "); + return; + } + switch (sqp->type) { + case PRPTY: + pp = sqp->desc; + if (pp->monop) + if (pp->houses == 0) + printf("rent is %d\n", rnt=pp->rent[0] * 2); + else if (pp->houses < 5) + printf("with %d houses, rent is %d\n", + pp->houses, rnt=pp->rent[pp->houses]); + else + printf("with a hotel, rent is %d\n", + rnt=pp->rent[pp->houses]); + else + printf("rent is %d\n", rnt = pp->rent[0]); + break; + case RR: + rnt = 25; + rnt <<= (plp->num_rr - 1); + if (spec) + rnt <<= 1; + printf("rent is %d\n", rnt); + break; + case UTIL: + rnt = roll(2, 6); + if (plp->num_util == 2 || spec) { + printf("rent is 10 * roll (%d) = %d\n", rnt, rnt * 10); + rnt *= 10; + } + else { + printf("rent is 4 * roll (%d) = %d\n", rnt, rnt * 4); + rnt *= 4; + } + break; + } + cur_p->money -= rnt; + plp->money += rnt; +} diff --git a/src/games/monop/roll.c b/src/games/monop/roll.c new file mode 100644 index 0000000..b1d72a2 --- /dev/null +++ b/src/games/monop/roll.c @@ -0,0 +1,37 @@ +/* + * This routine rolls ndie nside-sided dice. + */ + +# define reg register + +# ifndef vax +# define MAXRAND 32767L + +roll(ndie, nsides) +int ndie, nsides; { + + reg long tot; + reg unsigned n, r; + + tot = 0; + n = ndie; + while (n--) + tot += rand(); + return (int) ((tot * (long) nsides) / ((long) MAXRAND + 1)) + ndie; +} + +# else + +roll(ndie, nsides) +reg int ndie, nsides; { + + reg int tot, r; + reg double num_sides; + + num_sides = nsides; + tot = 0; + while (ndie--) + tot += (r = rand()) * (num_sides / 017777777777) + 1; + return tot; +} +# endif diff --git a/src/games/monop/spec.c b/src/games/monop/spec.c new file mode 100644 index 0000000..b100f21 --- /dev/null +++ b/src/games/monop/spec.c @@ -0,0 +1,49 @@ +# include "monop.ext" + +static char *perc[] = { + "10%", "ten percent", "%", "$200", "200", 0 + }; + +inc_tax() { /* collect income tax */ + + reg int worth, com_num; + + com_num = getinp("Do you wish to lose 10%% of your total worth or $200? ", perc); + worth = cur_p->money + prop_worth(cur_p); + printf("You were worth $%d", worth); + worth /= 10; + if (com_num > 2) { + if (worth < 200) + printf(". Good try, but not quite.\n"); + else if (worth > 200) + lucky(".\nGood guess. "); + cur_p->money -= 200; + } + else { + printf(", so you pay $%d", worth); + if (worth > 200) + printf(" OUCH!!!!.\n"); + else if (worth < 200) + lucky("\nGood guess. "); + cur_p->money -= worth; + } + if (worth == 200) + lucky("\nIt makes no difference! "); +} +goto_jail() { /* move player to jail */ + + cur_p->loc = JAIL; +} +lux_tax() { /* landing on luxury tax */ + + printf("You lose $75\n"); + cur_p->money -= 75; +} +cc() { /* draw community chest card */ + + get_card(&CC_D); +} +chance() { /* draw chance card */ + + get_card(&CH_D); +} diff --git a/src/games/monop/strcmp.c b/src/games/monop/strcmp.c new file mode 100644 index 0000000..1c53627 --- /dev/null +++ b/src/games/monop/strcmp.c @@ -0,0 +1,21 @@ +# include +# include + +# define reg register + +# define makelower(c) (isupper(c) ? tolower(c) : c) + +/* + * Compare strings: s1>s2: >0 s1==s2: 0 s1 2) { + tradee = getinp("Which player do you wish to trade with? ", + name_list); + if (tradee == num_play) + return; + if (tradee == player) { + printf("You can't trade with yourself!\n"); + goto over; + } + } + else + tradee = 1 - player; + get_list(0, player); + get_list(1, tradee); + if (getyn("Do you wish a summary? ") == 0) + summate(); + if (getyn("Is the trade ok? ") == 0) + do_trade(); +} +/* + * This routine gets the list of things to be trader for the + * player, and puts in the structure given. + */ +get_list(struct_no, play_no) +int struct_no, play_no; { + + reg int sn, pn; + reg PLAY *pp; + int numin, prop, num_prp; + OWN *op; + TRADE *tp; + + for (numin = 0; numin < MAX_PRP; numin++) + used[numin] = FALSE; + sn = struct_no, pn = play_no; + pp = &play[pn]; + tp = &trades[sn]; + tp->trader = pn; + printf("player %s (%d):\n", pp->name, pn+1); + if (pp->own_list) { + numin = set_list(pp->own_list); + for (num_prp = numin; num_prp; ) { + prop = getinp("Which property do you wish to trade? ", + list); + if (prop == numin) + break; + else if (used[prop]) + printf("You've already allocated that.\n"); + else { + num_prp--; + used[prop] = TRUE; + for (op = pp->own_list; prop--; op = op->next) + continue; + add_list(pn, &(tp->prop_list), sqnum(op->sqr)); + } + } + } + if (pp->money > 0) { + printf("You have $%d. ", pp->money); + tp->cash = get_int("How much are you trading? "); + } + if (pp->num_gojf > 0) { +once_more: + printf("You have %d get-out-of-jail-free cards. ",pp->num_gojf); + tp->gojf = get_int("How many are you trading? "); + if (tp->gojf > pp->num_gojf) { + printf("You don't have that many. Try again.\n"); + goto once_more; + } + } +} +/* + * This routine sets up the list of tradable property. + */ +set_list(the_list) +reg OWN *the_list; { + + reg int i; + reg OWN *op; + + i = 0; + for (op = the_list; op; op = op->next) + if (!used[i]) + list[i++] = op->sqr->name; + list[i++] = "done"; + list[i--] = 0; + return i; +} +/* + * This routine summates the trade. + */ +summate() { + + reg bool some; + reg int i; + reg TRADE *tp; + OWN *op; + + for (i = 0; i < 2; i++) { + tp = &trades[i]; + some = FALSE; + printf("Player %s (%d) gives:\n", play[tp->trader].name, + tp->trader+1); + if (tp->cash > 0) + printf("\t$%d\n", tp->cash), some++; + if (tp->gojf > 0) + printf("\t%d get-out-of-jail-free card(s)\n", tp->gojf), + some++; + if (tp->prop_list) { + for (op = tp->prop_list; op; op = op->next) + putchar('\t'), printsq(sqnum(op->sqr), TRUE); + some++; + } + if (!some) + printf("\t-- Nothing --\n"); + } +} +/* + * This routine actually executes the trade. + */ +do_trade() { + + move_em(&trades[0], &trades[1]); + move_em(&trades[1], &trades[0]); +} +/* + * This routine does a switch from one player to another + */ +move_em(from, to) +TRADE *from, *to; { + + reg PLAY *pl_fr, *pl_to; + reg OWN *op; + + pl_fr = &play[from->trader]; + pl_to = &play[to->trader]; + + pl_fr->money -= from->cash; + pl_to->money += from->cash; + pl_fr->num_gojf -= from->gojf; + pl_to->num_gojf += from->gojf; + for (op = from->prop_list; op; op = op->next) { + add_list(to->trader, &(pl_to->own_list), sqnum(op->sqr)); + op->sqr->owner = to->trader; + del_list(from->trader, &(pl_fr->own_list), sqnum(op->sqr)); + } + set_ownlist(to->trader); +} +/* + * This routine lets a player resign + */ +resign() { + + reg int i, new_own; + reg OWN *op; + SQUARE *sqp; + + if (cur_p->money <= 0) { + switch (board[cur_p->loc].type) { + case UTIL: + case RR: + case PRPTY: + new_own = board[cur_p->loc].owner; + break; + case SPEC: + case CC: + case CHANCE: + new_own = num_play; + break; + } + if (new_own == num_play) + printf("You would resign to the bank\n"); + else + printf("You would resign to %s\n", name_list[new_own]); + } + else if (num_play == 1) { + new_own = num_play; + printf("You would resign to the bank\n"); + } + else { + name_list[num_play] = "bank"; + do { + new_own = getinp("Who do you wish to resign to? ", + name_list); + if (new_own == player) + printf("You can't resign to yourself!!\n"); + } while (new_own == player); + name_list[num_play] = "done"; + } + if (getyn("Do you really want to resign? ", yn) != 0) + return; + if (num_play == 1) { + printf("Then NOBODY wins (not even YOU!)\n"); + exit(0); + } + if (new_own < num_play) { /* resign to player */ + printf("resigning to player\n"); + trades[0].trader = new_own; + trades[0].cash = trades[0].gojf = 0; + trades[0].prop_list = NULL; + trades[1].trader = player; + trades[1].cash = cur_p->money > 0 ? cur_p->money : 0; + trades[1].gojf = cur_p->num_gojf; + trades[1].prop_list = cur_p->own_list; + do_trade(); + } + else { /* resign to bank */ + printf("resigning to bank\n"); + for (op = cur_p->own_list; op; op = op->next) { + sqp = op->sqr; + sqp->owner = -1; + sqp->desc->morg = FALSE; + if (op->type == PRPTY) { + isnot_monop(sqp->desc->mon_desc); + sqp->desc->houses = 0; + } + } + if (cur_p->num_gojf) + ret_card(cur_p); + } + for (i = player; i < num_play; i++) { + name_list[i] = name_list[i+1]; + if (i + 1 < num_play) + cpy_st(&play[i], &play[i+1], sizeof (PLAY)); + } + name_list[num_play--] = 0; + for (i = 0; i < N_SQRS; i++) + if (board[i].owner > player) + --board[i].owner; + player = --player < 0 ? num_play - 1 : player; + next_play(); + if (num_play < 2) { + printf("\nThen %s WINS!!!!!\n", play[0].name); + printhold(0); + printf("That's a grand worth of $%d.\n", + play[0].money+prop_worth(&play[0])); + exit(0); + } +} diff --git a/src/games/morse.c b/src/games/morse.c new file mode 100644 index 0000000..701c0f8 --- /dev/null +++ b/src/games/morse.c @@ -0,0 +1,89 @@ +#ifdef CROSS +# include +# include +#else +# include +# include +#endif + +char *dit = "dit"; +char *daw = "daw"; + +char *digit[] = { + "-----", + ".----", + "..---", + "...--", + "....-", + ".....", + "-....", + "--...", + "---..", + "----.", + 0 +}; + +char *alph[] = { + ".-", + "-...", + "-.-.", + "-..", + ".", + "..-.", + "--.", + "....", + "..", + ".---", + "-.-", + ".-..", + "--", + "-.", + "---", + ".--.", + "--.-", + ".-.", + "...", + "-", + "..-", + "...-", + ".--", + "-..-", + "-.--", + "--..", + 0, +}; + +void print(s) + char *s; +{ + char *p; + + for (p = s; *p; p++) { + if (*p == '.') + printf(" %s", dit); + else if (*p == '-') + printf(" %s", daw); + } + printf(",\n"); +} + +int main() +{ + register int c; + + while ((c = getchar()) != EOF) { + if (isupper(c)) + c = tolower(c); + if (isalpha(c)) + print(alph[c-'a']); + else if (isdigit(c)) + print(digit[c-'0']); + else if (c == ',') + print("--..--"); + else if (c == '.') + print(".-.-.-"); + else if (isspace(c)) + printf(" ...\n"); + } + return 0; +} diff --git a/src/games/number.6 b/src/games/number.6 new file mode 100644 index 0000000..e2036e1 --- /dev/null +++ b/src/games/number.6 @@ -0,0 +1,12 @@ +.\" @(#)number.6 6.1 (Berkeley) 5/20/85 +.\" +.TH NUMBER 6 "May 20, 1985" +.AT 3 +.SH NAME +number \- convert Arabic numerals to English +.SH SYNOPSIS +.B /usr/games/number +.SH DESCRIPTION +.I Number +copies the standard input to the standard output, +changing each decimal number to a fully spelled out version. diff --git a/src/games/number.c b/src/games/number.c new file mode 100644 index 0000000..9d1d938 --- /dev/null +++ b/src/games/number.c @@ -0,0 +1,207 @@ +#ifdef CROSS +# include +#else +# include +#endif +#include + +int flag; +int max = 21; + +const char *card[] = { + "hundred", + "thousand", + "million", + "billion", + "trillion", + "quadrillion", + "quintillion", + "sextillion", + "septillion", + "octillion", + "nonillion", + "decillion", + "undecillion", + "duodecillion", + "tredecillion", + "quattuordecillion", + "quindecillion", + "sexdecillion", + "septendecillion", + "octodecillion", + "novemdecillion", + "vigintillion" +}; + +const char *unit[] = { + "zero", + "one", + "two", + "three", + "four", + "five", + "six", + "seven", + "eight", + "nine" +}; + +const char *teen[] = { + "ten", + "eleven", + "twelve", + "thirteen", + "fourteen", + "fifteen", + "sixteen", + "seventeen", + "eighteen", + "nineteen" +}; + +const char *decade[] = { + "zero", + "ten", + "twenty", + "thirty", + "forty", + "fifty", + "sixty", + "seventy", + "eighty", + "ninety" +}; + +char line[100]; + +void print(s) + const char *s; +{ + if (flag) + printf(" "); + printf("%s", s); + flag = 1; +} + +void ones(d) +{ + if(d=='0') + return; + print(unit[d-'0']); +} + +void tens(p) + char *p; +{ + switch(p[1]) { + + case '0': + return; + + case '1': + print(teen[p[2]-'0']); + p[2] = '0'; + return; + } + + print(decade[p[1]-'0']); +} + +int digit(c) +{ + if(c < '0' || c > '9') + return(0); + return(1); +} + +void nline() +{ + if(flag) + printf(".\n"); + flag = 0; +} + +void cprint(s) + const char *s; +{ + if(flag) + print(s); +} + +void conv(p, c) + char *p; +{ + + if(c > max) { + conv(p, c-max); + print(card[max]); + nline(); + p += (c-max)*3; + c = max; + } + while(c > 1) { + c--; + conv(p, 1); + cprint(card[c]); + nline(); + p += 3; + } + ones(p[0]); + cprint(card[0]); + tens(p); + ones(p[2]); +} + +int main() +{ + register int c, i, fraction; + int r; + + fraction = 0; + while((c = getchar()) != EOF) { + if(!digit(c)) { + fraction = (c == '.'); + putchar(c); + continue; + } + if(fraction) { + while(digit(c)) { + putchar(' '); + putchar(c); + if((c=getchar()) == EOF) + exit(1); + } + putchar(' '); + goto out; + } + + putchar(' '); + i = 0; + line[i++] = '0'; + line[i++] = '0'; + while(c == '0') + if((c=getchar()) == EOF) + exit(1); + while(digit(c)) { + if(i < 98) + line[i++] = c; + if((c=getchar()) == EOF) + exit(1); + } + line[i] = 0; + r = i/3; + if(r == 0) { + print("zero"); + goto out; + } + conv(line+i-3*r, r); + +out: + fraction = (c == '.'); + nline(); + printf("...\n"); + if(c != '\n') + putchar(c); + } + return 0; +} diff --git a/src/games/phantasia/Makefile b/src/games/phantasia/Makefile new file mode 100644 index 0000000..729b906 --- /dev/null +++ b/src/games/phantasia/Makefile @@ -0,0 +1,35 @@ +# +# Copyright (c) 1980 Regents of the University of California. +# All rights reserved. The Berkeley software License Agreement +# specifies the terms and conditions for redistribution. +# +TOPSRC = $(shell cd ../../..; pwd) +include $(TOPSRC)/target.mk +#include $(TOPSRC)/cross.mk + +CFLAGS += -Os -mips16 -Werror #-Wall +CFLAGS += -DPATH=\"${DEST}\" -DWIZARD=\"daemon\" -DUID=1 \ + -DRAND=32768.0 -DACCESS=\"r+\" -DENEMY -DBSD42 -O + +OBJS = main.o func0.o func1.o func2.o fight.o +LIBS = -lm -lcurses -ltermcap +MAN = phantasia.0 +MANSRC = phant.nr + +all: phantasia $(MAN) + +phantasia: ${OBJS} + ${CC} ${LDFLAGS} -o phantasia.elf ${OBJS} ${LIBS} + ${OBJDUMP} -S phantasia.elf > phantasia.dis + ${SIZE} phantasia.elf + ${ELF2AOUT} phantasia.elf $@ && rm phantasia.elf + +${MAN}: ${MANSRC} + tbl -TX $< | ${MANROFF} > phantasia.0 + +clean: + rm -f *.o *.0 *.elf ${MAN} phantasia setfiles phant.help *.elf *.dis tags *~ + +install: all + install phantasia $(DESTDIR)/games/ + cp ${MAN} $(DESTDIR)/share/man/cat6/ diff --git a/src/games/phantasia/Makefile-linux b/src/games/phantasia/Makefile-linux new file mode 100644 index 0000000..db1811c --- /dev/null +++ b/src/games/phantasia/Makefile-linux @@ -0,0 +1,80 @@ +# Makefile for Phantasia 3.2 (1.2 2.11BSD - 1997/9/22) +# +# MODIFIED TO COMPILE WITHOUT 'XSTR'. +# +# To create game: +# +# 1) Set up a directory where the game and its support files will live. +# (It is suggested that the source be kept somewhere else.) +# 2) Set up the variables in Makefile to reflect your particular situation. +# 3) Check out ok_to_play() at the end of main.c if you want to include +# code to restrict access at certain times. +# 4) 'make install' and watch it fly. + +LIBS = -lm -lcurses -ltermcap + +# DEST is where the program and its support files reside +# If this changes then the symbolic link in the 'install' target must change. +DEST = /games/lib/phantasia + +# The following are program constants which are implementation dependent. +# +# PATH is the same as $DEST. +# WIZARD is the login of the one who will clean up things. +# UID is the uid of game wizard. +# RAND is one more than the largest number generated by rand(). +# Possible values for this are: +# 32768.0 (for 15 bit rand()) +# 65536.0 (for 16 bit rand()) +# 2147483648.0 (for 31 bit rand()) +# ACCESS is fopen() access to open a file for writing, but no +# clearing the file, e.g. "a", or "r+". (Use "r+" if you have it.) +# define OK_TO_PLAY to restrict playing access. Also see function ok_to_play() +# in main.c, and tailor to your own needs. +# define ENEMY to include code for checking of a 'hit list' of resricted +# accounts. The list of logins goes in the file 'enemy'. +# define BSD41 for 4.1bsd +# define BSD42 for 4.2bsd +# define USG3 for System III, or similar +# define USG5 for System V +CFLAGS = -DPATH=\"${DEST}\" \ + -DWIZARD=\"daemon\" \ + -DUID=1 \ + -DRAND=32768.0 \ + -DACCESS=\"r+\" \ + -DENEMY \ + -DBSD42 -O -Werror + +OFILES = main.o func0.o func1.o func2.o fight.o + +all: phantasia setfiles phant.help phantasia.0 + +phantasia: ${OFILES} + ${CC} ${OFILES} ${LIBS} -o phantasia + +setfiles: phant.h setfiles.c + ${CC} ${CFLAGS} setfiles.c -o setfiles -lm + +# the flags below on tbl and nroff are to make a line printable version +phant.help: phant.nr + tbl -TX phant.nr | nroff -man -Ttn300 > phant.help + +# DO NOT use an absolute pathname in the symbolic link below. Figure out +# what the relative path is. + +install: all phantasia.0 + rm -f ${DESTDIR}/usr/games/phantasia + ln -s lib/phantasia/phantasia ${DESTDIR}/usr/games/phantasia + -mkdir ${DESTDIR}${DEST} + cp phantasia monsters phant.help ${DESTDIR}${DEST} + chmod 755 ${DESTDIR}${DEST} + chmod 4711 ${DESTDIR}${DEST}/phantasia + chmod 644 ${DESTDIR}${DEST}/phant.help + ./setfiles + install -m 444 -o bin -g bin phantasia.0 ${DESTDIR}/usr/man/cat6 + +phantasia.0: phant.nr + tbl -TX phant.nr | nroff -man -h -Tascii > phantasia.0 + +clean: + rm -f *.o phantasia phant.help setfiles phantasia.0 diff --git a/src/games/phantasia/fight.c b/src/games/phantasia/fight.c new file mode 100644 index 0000000..370cdfc --- /dev/null +++ b/src/games/phantasia/fight.c @@ -0,0 +1,607 @@ +/* + * fight.c Phantasia monster fighting routine + * + * 1.1 (2.11BSD) 1996/10/26 + */ + +/* + * The code exists here for fight to the finish. Simply add code to + * set 'fgttofin = TRUE' as an option. Everything else is here. + */ +#include "phant.h" + +void fight(stat,particular) /* monster fighting routine */ + register struct stats *stat; + int particular; +{ + bool fghttofin = FALSE, luckout = FALSE; + char aline[80]; + double monhit, mdamage, sdamage, monspd, maxspd, inflict, monstr, temp, shield; + int ch; + register int whichm, size, hwmany, lines; + struct mstats monster; + + fghting = changed = TRUE; + shield = 0.0; + if (setjmp(fightenv) == 2) + shield = roll(100 + (stat->mxn + stat->shd)*6.2,3000); + hwmany = 0; + size = (valhala) ? stat->lvl/5 : circ(stat->x,stat->y); + if (particular >= 0) + whichm = particular; + else if (marsh) + whichm = roll(0,15); + else if (size > 24) + whichm = roll(14,86); + else if (size > 15) + whichm = roll(0,50) + roll(14,37); + else if (size > 8) + whichm = roll(0,50) + roll(14,26); + else if (size > 3) + whichm = roll(14,50); + else + whichm = roll(14,25); + +CALL: move(3,0); + clrtobot(); + move(5,0); + lines = 6; + callmonster(whichm,size,&monster); + if (stat->blind) + strcpy(monster.name,"a monster"); + ++hwmany; + if (monster.typ == 1) /* unicorn */ + if (stat->vrg) + { + printw("You just subdued %s, thanx to the virgin.",monster.name); + stat->vrg = FALSE; + goto FINISH; + } + else + { + printw("You just saw %s running away!",monster.name); + goto LEAVE; + } + if (monster.typ == 2 && stat->typ > 20) + { + strcpy(monster.name,"Morgoth"); + monster.str = rnd()*(stat->mxn + stat->shd)/1.4 + rnd()*(stat->mxn + stat->shd)/1.5; + monster.brn = stat->brn; + monster.hit = stat->str*30; + monster.typ = 23; + monster.spd = speed*1.1 + speed*(stat->typ == 90); + monster.flk = monster.trs = monster.exp = 0; + mvprintw(4,0,"You've encountered %s, Bane of the Council and Valar.",monster.name); + } + fghttofin = luckout = FALSE; + monstr = monster.str; + monhit = monster.hit; + mdamage = sdamage = 0; + monspd = maxspd = monster.spd; + *monster.name = toupper(*monster.name); + +TOP: mvprintw(5,0,"You are being attacked by %s, EXP: %.0f (Size: %d)",monster.name,monster.exp,size); + printstats(stat); + mvprintw(1,26,"%20.0f",stat->nrg + shield); + if (monster.typ == 4 && stat->bls && stat->chm) + { + mvprintw(6,0,"You just overpowered %s!",monster.name); + lines = 7; + stat->bls = FALSE; + --stat->chm; + goto FINISH; + } + monster.spd = min(monster.spd + 1,maxspd); + if (rnd()*monster.spd > rnd()*speed && monster.typ != 4 && monster.typ != 16) + { + if (monster.typ) + switch (monster.typ) /* do special things */ + { + case 5: /* Leanan-Sidhe */ + if (rnd() > 0.25) + goto NORMALHIT; + inflict = roll(1,(size - 1)/2); + inflict = min(stat->str,inflict); + mvprintw(lines++,0,"%s sapped %0.f of your strength!",monster.name,inflict); + stat->str -= inflict; + strength -= inflict; + break; + case 6: /* Saruman */ + if (stat->pal) + { + mvprintw(lines++,0,"Wormtongue stole your palantir!"); + stat->pal = FALSE; + } + else if (rnd() > 0.2) + goto NORMALHIT; + else if (rnd() > 0.5) + { + mvprintw(lines++,0,"%s transformed your gems into gold!",monster.name); + stat->gld += stat->gem; + stat->gem = 0.0; + } + else + { + mvprintw(lines++,0,"%s scrambled your stats!",monster.name); + scramble(stat); + } + break; + case 7: /* Thaumaturgist */ + if (rnd() > 0.15) + goto NORMALHIT; + mvprintw(lines++,0,"%s transported you!",monster.name); + stat->x += sgn(stat->x)*roll(50*size,250*size); + stat->y += sgn(stat->y)*roll(50*size,250*size); + goto LEAVE; + case 8: /* Balrog */ + inflict = roll(10,monster.str); + inflict = min(stat->exp,inflict); + mvprintw(lines++,0,"%s took away %0.f experience points.",monster.name,inflict); + stat->exp -= inflict; + break; + case 9: /* Vortex */ + if (rnd() > 0.2) + goto NORMALHIT; + inflict = roll(0,7.5*size); + inflict = min(stat->man,floor(inflict)); + mvprintw(lines++,0,"%s sucked up %.0f of your manna!",monster.name,inflict); + stat->man -= inflict; + break; + case 10: /* Nazgul */ + if (rnd() > 0.3) + goto NORMALHIT; + if (stat->rng.type && stat->rng.type < 10) + { + mvaddstr(lines++,0,"Will you relinguish your ring ? "); + ch = rgetch(); + if (toupper(ch) == 'Y') + { + stat->rng.type = NONE; + goto LEAVE; + } + } + mvprintw(lines++,0,"%s neutralized 1/5 of your brain!",monster.name); + stat->brn *= 0.8; + break; + case 11: /* Tiamat */ + if (rnd() > 0.6) + goto NORMALHIT; + mvprintw(lines++,0,"%s took half your gold and gems and flew off.",monster.name); + stat->gld = floor(stat->gld/2); + stat->gem = floor(stat->gem/2); + goto LEAVE; + case 12: /* Kobold */ + if (rnd() >.7) + goto NORMALHIT; + mvprintw(lines++,0,"%s stole one gold piece and ran away.",monster.name); + stat->gld = max(0,stat->gld-1); + goto LEAVE; + case 13: /* Shelob */ + if (rnd() > 0.5) + goto NORMALHIT; + mvprintw(lines++,0,"%s has bitten and poisoned you!",monster.name); + ++stat->psn; + break; + case 14: /* Faeries */ + if (!stat->hw) + goto NORMALHIT; + mvprintw(lines++,0,"Your holy water killed it!"); + --stat->hw; + goto FINISH; + case 15: /* Lamprey */ + if (rnd() > 0.7) + goto NORMALHIT; + mvprintw(lines++,0,"%s bit and poisoned you!",monster.name); + stat->psn += 0.25; + break; + case 17: /* Bonnacon */ + if (rnd() > 0.1) + goto NORMALHIT; + mvprintw(lines++,0,"%s farted and scampered off.",monster.name); + stat->nrg /= 2; + goto LEAVE; + case 18: /* Smeagol */ + if (rnd() > 0.5 || !stat->rng.type) + goto NORMALHIT; + mvprintw(lines++,0,"%s tried to steal your ring, ",monster.name); + if (rnd() > 0.1) + addstr("but was unsuccessful."); + else + { + addstr("and ran away with it!"); + stat->rng.type = NONE; + goto LEAVE; + } + break; + case 19: /* Succubus */ + if (rnd() > 0.3) + goto NORMALHIT; + inflict = roll(15,size*10); + inflict = min(inflict,stat->nrg); + mvprintw(lines++,0,"%s sapped %0.f of your energy.",monster.name,inflict); + stat->nrg -= inflict; + break; + case 20: /* Cerberus */ + if (rnd() > 0.25) + goto NORMALHIT; + mvprintw(lines++,0,"%s took all your metal treasures!",monster.name); + stat->swd = stat->shd =stat->gld = stat->crn = 0; + goto LEAVE; + case 21: /* Ungoliant */ + if (rnd() > 0.1) + goto NORMALHIT; + mvprintw(lines++,0,"%s poisoned you, and took one quik.",monster.name); + stat->psn += 5; + --stat->quk; + break; + case 22: /* Jabberwock */ + if (rnd() > 0.1) + goto NORMALHIT; + mvprintw(lines++,0,"%s flew away, and left you to contend with one of its friends.",monster.name); + whichm = 55 + 22*(rnd() > 0.5); + goto CALL; + case 24: /* Troll */ + if (rnd() > 0.5) + goto NORMALHIT; + mvprintw(lines++,0,"%s partially regenerated his energy.!",monster.name); + monster.hit += floor((monhit*size - monster.hit)/2); + monster.str = monstr; + mdamage = sdamage = 0; + maxspd = monspd; + break; + case 25: /* wraith */ + if (rnd() > 0.3 || stat->blind) + goto NORMALHIT; + mvprintw(lines++,0,"%s blindeed you!",monster.name); + stat->blind = TRUE; + break; + default: + goto NORMALHIT; + } + else +NORMALHIT: { + inflict = rnd()*monster.str + 0.5; + mvprintw(lines++,0,"%s hit you %.0f times!",monster.name,inflict); +SPECIALHIT: if ((shield -= inflict) < 0) + { + stat->nrg += shield; + shield = 0; + } + } + } + else + { + if (fghttofin) + goto MELEE; + mvaddstr(3,0,"1:Melee 2:Skirmish 3:Evade 4:Spell 5:Nick "); + if (!luckout) + if (monster.typ == 23) + addstr("6:Ally "); + else + addstr("6:Luckout "); + if (stat->rng.type > 0) + addstr("7:Use Ring "); + else + clrtoeol(); + ch = gch(stat->rng.type); + move(lines = 6,0); + clrtobot(); + switch (ch) + { + default: + case '1': /* melee */ +MELEE: inflict = roll(strength/2 + 5,1.3*strength) + (stat->rng.type < 0 ? strength : 0); + mdamage += inflict; + monster.str = monstr - mdamage/monhit*monstr/4; + goto HITMONSTER; + case '2': /* skirmish */ + inflict = roll(strength/3 + 3,1.1*strength) + (stat->rng.type < 0 ? strength : 0); + sdamage += inflict; + maxspd = monspd - sdamage/monhit*monspd/4; + goto HITMONSTER; + case '3': /* evade */ + if ((monster.typ == 4 || monster.typ == 16 + || rnd()*speed*stat->brn > rnd()*monster.spd*monster.brn) + && (monster.typ != 23)) + { + mvaddstr(lines++,0,"You got away!"); + stat->x += roll(-2,5); + stat->y += roll(-2,5); + goto LEAVE; + } + else + mvprintw(lines++,0,"%s is still after you!",monster.name); + break; + case '4': /* spell */ + lines = 7; + mvaddstr(3,0,"\n\n"); + mvaddstr(3,0,"1:All or Nothing"); + if (stat->mag >= 3) + mvaddstr(3,18,"2:Magic Bolt"); + if (stat->mag >= 7) + mvaddstr(3,32,"3:Force Field"); + if (stat->mag >= 10) + mvaddstr(3,47,"4:Transform"); + if(stat->mag >= 15) + mvaddstr(3,60,"5:Increase Might\n"); + if (stat->mag >= 20) + mvaddstr(4,0,"6:Invisibility"); + if (stat->mag >= 25) + mvaddstr(4,18,"7:Transport"); + if (stat->mag >= 30) + mvaddstr(4,32,"8:Paralyze"); + if (stat->typ > 20) + mvaddstr(4,52,"9:Specify"); + mvaddstr(6,0,"Spell ? "); + ch = rgetch(); + mvaddstr(3,0,"\n\n"); + if (monster.typ == 23 && ch != '4') + illspell(); + else + switch (ch) + { + case '1': /* all or nothing */ + { + inflict = (rnd() < 0.25) ? (monster.hit*1.0001 + 1) : 0; + if (monster.typ == 4) + inflict *= .9; + if (stat->man) + --stat->man; + maxspd *= 2; + monspd *= 2; + monster.spd = max(1,monster.spd * 2); + monstr = monster.str *= 2; + goto HITMONSTER; + } + case '2': /* magic bolt */ + if (stat->mag < 3) + illspell(); + else + { + do + { + mvaddstr(6,0,"How much manna for bolt? "); + getstring(aline,80); + sscanf(aline,"%lf",&temp); + } + while (temp < 0 || temp > stat->man); + stat->man -= floor(temp); + inflict = temp*roll(10,sqrt(stat->mag/3.0 + 1.0)); + mvaddstr(6,0,"Magic Bolt fired!\n"); + if (monster.typ == 4) + inflict = 0.0; + goto HITMONSTER; + } + case '5': /* increase might */ + { + if (stat->mag < 15) + illspell(); + else if (stat->man < 55) + nomanna(); + else + { + stat->man -= 55; + strength += (1.2*(stat->str+stat->swd)+5-strength)/2; + mvprintw(6,0,"New strength: %.0f\n",strength); + } + break; + } + case '3': /* force field */ + { + if (stat->mag < 7) + illspell(); + else if (stat->man < 20) + nomanna(); + else + { + shield = (stat->mxn + stat->shd)*4.2 + 45; + stat->man -= 20; + mvaddstr(6,0,"Force Field up.\n"); + } + break; + } + case '4': /* transform */ + { + if (stat->mag < 10) + illspell(); + else if (stat->man < 35) + nomanna(); + else + { + stat->man -= 35; + whichm = roll(0,100); + goto CALL; + } + break; + } + case '6': /* invisible */ + { + if (stat->mag < 20) + illspell(); + else if (stat->man < 45) + nomanna(); + else + { + stat->man -= 45; + speed += (1.2*(stat->quk+stat->quks)+5-speed)/2; + mvprintw(6,0,"New quik : %.0f\n",speed); + } + break; + } + case '7': /* transport */ + { + if (stat->mag < 25) + illspell(); + else if (stat->man < 50) + nomanna(); + else + { + stat->man -= 50; + if (stat->brn + stat->mag < monster.exp/300*rnd()) + { + mvaddstr(6,0,"Transport backfired!\n"); + stat->x += (250*size*rnd() + 50*size)*sgn(stat->x); + stat->y += (250*size*rnd() + 50*size)*sgn(stat->y); + goto LEAVE; + } + else + { + mvprintw(6,0,"%s is transported.\n",monster.name); + monster.trs *= (rnd() > 0.3); + goto FINISH; + } + } + break; + } + case '8': /* paralyze */ + { + if (stat->mag < 30) + illspell(); + else if (stat->man < 60) + nomanna(); + else + { + stat->man -= 60; + if (stat->mag > monster.exp/1000*rnd()) + { + mvprintw(6,0,"%s is held.\n",monster.name); + monster.spd = -2; + } + else + mvaddstr(6,0,"Monster unaffected.\n"); + } + break; + } + case '9': /* specify */ + { + if (stat->typ < 20) + illspell(); + else if (stat->man < 1000) + nomanna(); + else + { + mvaddstr(6,0,"Which monster do you want [0-99] ? "); + whichm = inflt(); + whichm = max(0,min(99,whichm)); + stat->man -= 1000; + goto CALL; + } + break; + } + } + break; + case '5': + inflict = 1 + stat->swd; + stat->exp += floor(monster.exp/10); + monster.exp *= 0.92; + maxspd += 2; + monster.spd = (monster.spd < 0) ? 0 : monster.spd + 2; + if (monster.typ == 4) + { + mvprintw(lines++,0,"You hit %s %.0f times, and made him mad!",monster.name,inflict); + stat->quk /= 2; + stat->x += sgn(stat->x)*roll(50*size,250*size); + stat->y += sgn(stat->y)*roll(50*size,250*size); + stat->y += (250*size*rnd() + 50*size)*sgn(stat->y); + goto LEAVE; + } + else + goto HITMONSTER; + case '6': /* luckout */ + if (luckout) + mvaddstr(lines++,0,"You already tried that."); + else + if (monster.typ == 23) + if (rnd() < stat->sin/100) { + mvprintw(lines++,0,"%s accepted!",monster.name); + goto LEAVE; + } + else + { + luckout = TRUE; + mvaddstr(lines++,0,"Nope, he's not interested."); + } + else + if ((rnd() + .333)*stat->brn < (rnd() + .333)*monster.brn) + { + luckout = TRUE; + mvprintw(lines++,0,"You blew it, %s.",stat->name); + } + else + { + mvaddstr(lines++,0,"You made it!"); + goto FINISH; + } + break; + case '\014': /* clear screen */ + clear(); + break; + case '7': /* use ring */ + if (stat->rng.type > 0) + { + mvaddstr(lines++,0,"Now using ring."); + stat->rng.type = -stat->rng.type; + if (abs(stat->rng.type) != DLREG) + --stat->rng.duration; + goto NORMALHIT; + } + break; + } + goto BOT; +HITMONSTER: { + inflict = floor(inflict); + mvprintw(lines++,0,"You hit %s %.0f times!",monster.name,inflict); + if ((monster.hit -= inflict) >0) + switch (monster.typ) + { + case 4: /* dark lord */ + inflict = stat->nrg + shield +1; + goto SPECIALHIT; + case 16: /* shrieker */ + mvaddstr(lines++,0,"Shreeeek!! You scared it, and it called one of its friends."); + paws(lines); + whichm = roll(70,30); + goto CALL; + } + else + { + if (monster.typ == 23) /* morgoth */ + mvaddstr(lines++,0,"You have defeated Morgoth, but he may return. . ."); + else + mvprintw(lines++,0,"You killed it. Good work, %s.",stat->name); + goto FINISH; + } + } + } +BOT: refresh(); + if (lines == 23) + { + paws(23); + move(lines = 6,0); + clrtobot(); + } + if (stat->nrg <= 0) + { + paws(lines); + death(stat); + goto LEAVE; + } + goto TOP; +FINISH: stat->exp += monster.exp; + if (rnd() < monster.flk/100.0) /* flock monster */ + { + paws(lines); + fghttofin = FALSE; + goto CALL; + } + else if (size > 1 && monster.trs && rnd() > pow(0.6,(double) (hwmany/3 + size/3))) /* this takes # of flocks and size into account */ + { + paws(lines); + treasure(stat,monster.trs,size); + } +LEAVE: stat->rng.type = abs(stat->rng.type); + paws(lines+3); + move(4,0); + clrtobot(); + fghting = FALSE; +} diff --git a/src/games/phantasia/func0.c b/src/games/phantasia/func0.c new file mode 100644 index 0000000..072dcc1 --- /dev/null +++ b/src/games/phantasia/func0.c @@ -0,0 +1,1008 @@ +/* + * func0.c Phantasia support routines + */ + +#include "phant.h" + +void treasure(stat,treastyp,size) /* select a treasure */ +register struct stats *stat; +short treastyp; +register int size; +{ +register int which; +int ch; +double temp, temp2; +char aline[35]; +FILE *fp; + + which = roll(1,3); + move(3,0); + clrtobot(); + move(5,0); + if (rnd() > 0.65) /* gold and gems */ + if (treastyp > 7) /* gems */ + { + temp = roll(1,(treastyp - 7)*(treastyp - 7)*(size - 1)/4); + printw("You have discovered %.0f gems! Will you pick them up ? ",temp); + ch = rgetch(); + addch('\n'); + if (toupper(ch) == 'Y') + if (rnd() < treastyp/40 + 0.05) /* cursed */ + { + addstr("They were cursed!\n"); + goto CURSE; + } + else + stat->gem += temp; + return; + } + else /* gold */ + { + temp = roll(treastyp*10,treastyp*treastyp*10*(size - 1)); + printw("You have found %.0f gold pieces. Do you want to pick them up ? ",temp); + ch = rgetch(); + addch('\n'); + if (toupper(ch) == 'Y') + if (rnd() < treastyp/35 + 0.04) /* cursed */ + { + addstr("They were cursed!\n"); + goto CURSE; + } + else + { + stat->gld += floor(0.9 * temp); + fp = fopen(goldfile,"r"); + if (fread((char *) &temp2,sizeof(double),1,fp) != 1) + /*ignore*/; + fclose(fp); + fp = fopen(goldfile,"w"); + temp2 += floor(temp/10); + fwrite((char *) &temp2,sizeof(double),1,fp); + fclose(fp); + } + return; + } + else /* other treasures */ + { + addstr("You have found some treasure. Do you want to inspect it ? "); + ch = rgetch(); + addch('\n'); + if (toupper(ch) != 'Y') + return; + else + if (rnd() < 0.08 && treastyp != 4) + { + addstr("It was cursed!\n"); + goto CURSE; + } + else + switch(treastyp) + { + case 1: + switch(which) + { + case 1: + addstr("You've discovered a power booster!\n"); + stat->man += roll(size*4,size*30); + break; + case 2: + addstr("You have encountered a druid.\n"); + stat->exp += roll(0,2000 + size*400); + break; + case 3: + addstr("You have found a holy orb.\n"); + stat->sin = max(0,stat->sin - 0.25); + break; + } + break; + case 2: + switch (which) + { + case 1: + addstr("You have found an amulet.\n"); + ++stat->amu; + break; + case 2: + addstr("You've found some holy water!\n"); + ++stat->hw; + break; + case 3: + addstr("You've met a hermit!\n"); + stat->sin *= 0.75; + stat->man += 12*size; + break; + } + break; + case 3: + switch (which) + { + case 1: + temp = roll(7,30 + size/10); + printw("You've found a +%.0f shield!\n",temp); + if (temp >= stat->shd) + stat->shd = temp; + else + somebetter(); + break; + case 2: + addstr("You have rescued a virgin. Will you be honorable ? "); + ch = rgetch(); + if (toupper(ch) == 'Y') + stat->vrg = TRUE; + else + { + stat->exp += 2000*size; + ++stat->sin; + } + break; + case 3: + addstr("You've discovered some athelas!\n"); + --stat->psn; + break; + } + break; + case 4: + addstr("You've found a scroll. Will you read it ? "); + ch = rgetch(); + addch('\n'); + if (toupper(ch) == 'Y') + switch ((int) roll(1,6)) + { + case 1: + addstr("It throws up a shield for you next monster.\n"); + paws(8); + longjmp(fightenv,2); + /*NOTREACHED*/ + case 2: + addstr("It makes you invisible for you next monster.\n"); + paws(8); + speed = 1e6; + longjmp(fightenv,0); + /*NOTREACHED*/ + case 3: + addstr("It increases your strength ten fold to fight your next monster.\n"); + paws(8); + strength *= 10; + longjmp(fightenv,0); + /*NOTREACHED*/ + case 4: + addstr("It is a general knowledge scroll.\n"); + stat->brn += roll(2,size); + stat->mag += roll(1,size/2); + break; + case 5: + addstr("It tells you how to pick your next monster.\n"); + addstr("Which monster do you want [0-99] ? "); + which = inflt(); + which = min(99,max(0,which)); + fight(stat,which); + break; + case 6: + addstr("It was cursed!\n"); + goto CURSE; + } + break; + case 5: + switch (which) + { + case 1: + temp = roll(size/4+5,size/2 + 9); + printw("You've discovered a +%.0f dagger.\n",temp); + if (temp >= stat->swd) + stat->swd = temp; + else + somebetter(); + break; + case 2: + temp = roll(7.5 + size*3,size * 2 + 160); + printw("You have found some +%.0f armour!\n",temp); + if (temp >= stat->shd) + stat->shd = temp; + else + somebetter(); + break; + case 3: + addstr("You've found a tablet.\n"); + stat->brn += 4.5*size; + break; + } + break; + case 6: + switch (which) + { + case 1: + addstr("You've found a priest.\n"); + stat->nrg = stat->mxn + stat->shd; + stat->sin /= 2; + stat->man += 24*size; + stat->brn += size; + break; + case 2: + addstr("You have come upon Robin Hood!\n"); + stat->shd += size*2; + stat->str += size/2.5 + 1; + break; + case 3: + temp = roll(2 + size/4,size/1.2 + 10); + printw("You have found a +%.0f axe!\n",temp); + if (temp >= stat->swd) + stat->swd = temp; + else + somebetter(); + break; + } + break; + case 7: + switch (which) + { + case 1: + addstr("You've discovered a charm!\n"); + ++stat->chm; + break; + case 2: + addstr("You have encountered Merlyn!\n"); + stat->brn += size + 5; + stat->mag += size/3 + 5; + stat->man += size*10; + break; + case 3: + temp = roll(5+size/3,size/1.5 + 20); + printw("You have found a +%.0f war hammer!\n",temp); + if (temp >= stat->swd) + stat->swd = temp; + else + somebetter(); + break; + } + break; + case 8: + switch (which) + { + case 1: + addstr("You have found a healing potion.\n"); + stat->psn = min(-2,stat->psn-2); + break; + case 2: + addstr("You have discovered a transporter. Do you wish to go anywhere ? "); + ch = rgetch(); + addch('\n'); + if (toupper(ch) == 'Y') + { + addstr("X Y Coordinates ? "); + getstring(aline,80); + sscanf(aline,"%lf %lf",&stat->x,&stat->y); + stat->x = floor(stat->x); + stat->y = floor(stat->y); + } + break; + case 3: + temp = roll(10 + size/1.2,size*3 + 30); + printw("You've found a +%.0f sword!\n",temp); + if (temp >= stat->swd) + stat->swd = temp; + else + somebetter(); + break; + } + break; + case 10: + case 11: + case 12: + case 13: + if (rnd() < 0.33) + { + if (treastyp == 10) + { + addstr("You've found a pair of elven boots!\n"); + stat->quk += 2; + break; + } + else if (treastyp == 11 && !stat->pal) + { + addstr("You've acquired Saruman's palantir.\n"); + stat->pal = TRUE; + break; + } + else if (!stat->rng.type && stat->typ < 20 && (treastyp == 12 || treastyp == 13)) + { + if (treastyp == 12) + if (rnd() < 0.8) + { + which = NAZREG; + temp = 15; + } + else + { + which = NAZBAD; + temp = 10 + rngcalc(stat->typ) + roll(0,5); + } + else + if (rnd() > 0.9) + { + which = DLREG; + temp = 0; + } + else + { + which = DLBAD; + temp = 15 + rngcalc(stat->typ) + roll(0,5); + } + addstr("You've discovered a ring. Will you pick it up ? "); + ch = rgetch(); + addch('\n'); + if (toupper(ch) == 'Y') + { + stat->rng.type = which; + stat->rng.duration = temp; + } + } + break; + } + case 9: + switch (which) + { + case 1: + if (!(stat->lvl > 1000 || stat->crn > floor((double) stat->lvl/100) + || stat->lvl < 10)) + { + addstr("You have found a golden crown!\n"); + ++stat->crn; + break; + } + case 2: + addstr("You've been blessed!\n"); + stat->bls = TRUE; + stat->sin /=3; + stat->nrg = stat->mxn + stat->shd; + stat->man += 100*size; + break; + case 3: + temp = roll(1,size/5+5); + temp = min(temp,99); + printw("You have discovered some +%.0f quicksilver!\n",temp); + if (temp >= stat->quks) + stat->quks = temp; + else + somebetter(); + break; + } + break; + } + refresh(); + return; + } +CURSE: if (stat->chm) + { + addstr("But your charm saved you!\n"); + --stat->chm; + } + else if (stat->amu) + { + addstr("But your amulet saved you!\n"); + --stat->amu; + } + else + { + stat->nrg = (stat->mxn + stat->shd)/10; + stat->psn += 0.25; + } +} + +void callmonster(which,size,mons) /* fill a structure with monster 'which' of size 'size' */ +register int which, size; +register struct mstats *mons; +{ +FILE *fp; +char instr[100]; + + which = min(which,99); + fp = fopen(monsterfile,"r"); + for (++which; which; --which) { + if (fgets(instr,100,fp) == 0) + /*ignore*/; + } + strncpy(mons->name,instr,24); + mons->name[24] = '\0'; + sscanf(instr + 24,"%lf%lf%lf%lf%lf%d%d%d",&mons->str,&mons->brn,&mons->spd,&mons->hit, + &mons->exp,&mons->trs,&mons->typ,&mons->flk); + if (mons->typ == 2) /* Modnar */ + { + mons->str *= rnd() + 0.5; + mons->brn *= rnd() + 0.5; + mons->spd *= rnd() + 0.5; + mons->hit *= rnd() + 0.5; + mons->exp *= rnd() + 0.5; + mons->trs *= rnd(); + } + else if (mons->typ == 3) /* mimic */ + { + fseek(fp,0L,0); + for (which = roll(0,100); which; --which) { + if (fgets(instr,100,fp) == 0) + /*ignore*/; + } + strncpy(mons->name,instr,24); + } + strunc(mons->name); + mons->str += (size-1)*mons->str/2; + mons->brn *= size; + mons->spd += size * 1.e-9; + mons->hit *= size; + mons->exp *= size; + fclose(fp); +} + +struct /* lookup table for rolling stats and making increases upon gaining levels */ + { + struct + { + int base; + int interval; + float increase; + } quick, strength, manna, energy, brains, magic; + } table[7] = + { +/* mag. usr: */ 30, 6, 0.0, 20, 6, 2.0, 50,51,75.0, 30,16,20.0, 60,26, 6.0, 5, 5,2.75, +/* fighter: */ 30, 6, 0.0, 40,16, 3.0, 30,21,40.0, 45,26,30.0, 25,21, 3.0, 3, 4, 1.5, +/* elf: */ 32, 7, 0.0, 35,11, 2.5, 45,46,65.0, 30,21,25.0, 40,26, 4.0, 4, 4, 2.0, +/* dwarf: */ 25, 6, 0.0, 45,21, 5.0, 25,21,30.0, 60,41,35.0, 20,21, 2.5, 2, 4, 1.0, +/* halfling: */ 34, 0, 0.0, 20, 6, 2.0, 25,21,30.0, 55,36,30.0, 40,36, 4.5, 1, 4, 1.0, +/* exprmnto: */ 27, 0, 0.0, 25, 0, 0.0, 100,0, 0.0, 35, 0, 0.0, 25, 0, 0.0, 2, 0, 0.0, +/* super: */ 38, 0, 0.0, 65, 0, 0.0, 100,0, 0.0, 80, 0, 0.0, 85, 0, 0.0, 9, 0, 0.0 + }; + +void genchar(res,type) /* init a charac struct */ +int type; +register struct stats *res; +{ +register int subscript; + + if (type < '1' || type > '6') + if (type != '7' || !su) + type = '2'; /* fighter is default */ + subscript = type - '1'; + res->quk = roll(table[subscript].quick.base,table[subscript].quick.interval); + res->str = roll(table[subscript].strength.base,table[subscript].strength.interval); + res->man = roll(table[subscript].manna.base,table[subscript].manna.interval); + res->mxn = res->nrg = roll(table[subscript].energy.base,table[subscript].energy.interval); + res->brn = roll(table[subscript].brains.base,table[subscript].brains.interval); + res->mag = roll(table[subscript].magic.base,table[subscript].magic.interval); + res->typ = subscript; + if (subscript < 6) + ++res->typ; + if (type == '5') + res->exp = roll(600,200); /* give halfling some exp. */ +} + +void movelvl(stat) /* update stats for new level */ +register struct stats *stat; +{ +register int type; +register unsigned new; +double inc; + + changed = TRUE; + type = abs(stat->typ); + if (type < 6) + ; /* normal */ + else if (type < 10) + type = roll(1,5); /* experimento */ + else if (type < 20) + { + type -= 10; /* king */ + if (type > 5) + type = roll(1,5); /* experimento */ + } + else if (type < 26) + type -= 20; /* council of wise */ + else + type = roll(1,5); /* everything else */ + new = level(stat->exp); + inc = new - stat->lvl; + --type; /* set up for subscripting into table */ + stat->str += table[type].strength.increase * inc; + stat->man += table[type].manna.increase * inc; + stat->brn += table[type].brains.increase * inc; + stat->mag += table[type].magic.increase * inc; + stat->mxn += table[type].energy.increase * inc; + stat->nrg = stat->mxn + stat->shd; + if ((stat->lvl = min(10000,new)) >= 1000) + { /* no longer able to be king */ + stat->gld += stat->crn * 5000; + stat->crn = 0; + stat->typ = abs(stat->typ); + } + if (stat->lvl >= 3000 && stat->typ < 20) + { /* make a member of the council */ + mvaddstr(6,0,"You have made it to the Council of the Wise.\nGood Luck on your search for the Holy Grail.\n"); + stat->rng.type = 0; + stat->rng.duration = 3; + stat->typ = abs(stat->typ) + (stat->typ > 10 ? 10 :20); + } +} + +char *printloc(x,y) /* return a pointer to a string specifying location */ +double x,y; /* also, set some global flags */ +{ +register int size, loc; +register char *label; +static char res[80], + *nametable[4][4] = /* names of places */ + { + "Anorien", "Ithilien", "Rohan", "Lorien", + "Gondor", "Mordor", "Dunland", "Rovanion", + "South Gondor", "Khand", "Eriador", "The Iron Hills", + "Far Harad", "Near Harad", "The Northern Waste", "Rhun" + }; + + throne = beyond = marsh = FALSE; + if (wmhl) + return (strcpy(res," is in the Wormholes")); + else if (valhala) + return (strcpy(res," is in Valhala")); + else if ((size = circ(x,y)) >= 1000) + { + if (max(abs(x),abs(y)) > 1100000) + { + label = "The Point of No Return"; + beyond = TRUE; + } + else + label = "The Ashen Mountains"; + } + else if (size >= 55) + label = "Morannon"; + else if (size >= 35) + label = "Kennaquahair"; + else if (size >= 20) + { + label = "The Dead Marshes"; + marsh = TRUE; + } + else if (size >= 9) + label = "The Outer Waste"; + else if (size >= 5) + label = "The Moors Adventurous"; + else + { + if (!x && !y) + { + label = "The Lord's Chamber"; + throne = TRUE; + } + else + { + loc = (x > 0) + 2 * (y >= 0); + label = nametable[size-1][loc]; + } + } + sprintf(res," is in %s (%.0f,%.0f)",label,x,y); + return (res); +} + +void initchar(stat) /* put in some default values */ +register struct stats *stat; +{ + stat->x = roll(-125,251); + stat->y = roll(-125,251); + stat->exp = stat->lvl = stat->sin = 0; + stat->crn = stat->psn = 0; + stat->rng.type = NONE; + stat->rng.duration = 0; + stat->blind = stat->vrg = stat->pal = FALSE; + stat->hw = stat->amu = stat->bls = 0; + stat->chm = 0; + stat->gem = 0.1; + stat->gld = roll(25,50) + roll(0,25) + 0.1; + stat->quks = stat->swd = stat->shd = 0; + stat->typ = 0; + stat->status = stat->tampered = OFF; + stat->scratch1 = stat->scratch2 = 0.0; + stat->wormhole = 0; + stat->age = 0; + stat->degen = 1; +} + +void trade(stat) /* trading post */ +register struct stats *stat; +{ +static struct + { + char *item; + int cost; + } menu[] = + { + "Manna",1, + "Shield",5, + "Book",200, + "Sword",500, + "Charm",1000, + "Quiksilver",2500, + "Blessing",7000, + "Gem",1000 /* this is only to ease changing the value of gems */ + }; +double temp; +int ch; +register int size, loop; +bool cheat = FALSE; + + changed = TRUE; + clear(); + addstr("You are at a trading post. All purchases must be made with gold."); + size = sqrt(abs(stat->x/100)) + 1; + size = min(7,size); + mvprintw(4,0,"L:Leave P:Purchase S:Sell Gems ? "); + move(6,0); + for (loop = 0; loop < size; ++loop) + printw("(%d) %-10s: %6d\n",loop+1,menu[loop].item,menu[loop].cost); +PROMPT: mvprintw(1,0,"Gold: %9.0f Gems: %9.0f Level: %6u Charms: %6d\n",stat->gld,stat->gem,stat->lvl,stat->chm); + printw("Shield:%9.0f Sword: %9.0f Quicksilver:%3d Blessed: %s", + stat->shd,stat->swd,stat->quks,(stat->bls ? " True" : "False")); + move(4,36); + ch = rgetch(); + move(15,0); + clrtobot(); + switch(toupper(ch)) + { + case 'L': + case '\n': + stat->x -= floor(stat->x/10); + stat->y -= floor(stat->y/10); + return; + case 'P': + mvaddstr(15,0,"What what would you like to buy ? "); + ch = rgetch(); + move(15,0); + clrtoeol(); + if (ch - '0' > size) + addstr("Sorry, this merchant doesn't have that."); + else + switch (toupper(ch)) + { + case '1': + printw("Manna is one per %d gold piece. How many do you want (%.0f max) ? ",menu[0].cost,floor(stat->gld/menu[0].cost)); + temp = inflt(); + if (temp * menu[0].cost > stat->gld || temp < 0) + goto CHEAT; + else + { + stat->gld -= floor(temp) * menu[0].cost; + if (rnd() < 0.02) + goto DISHON; + else + stat->man += floor(temp); + } + break; + case '2': + printw("Shields are %d per +1. How many do you want (%.0f max) ? ",menu[1].cost,floor(stat->gld/menu[1].cost)); + temp = inflt(); + if (!temp) + break; + if (temp * menu[1].cost > stat->gld || temp < 0) + goto CHEAT; + else + { + stat->gld -= floor(temp) * menu[1].cost; + if (rnd() < 0.02) + goto DISHON; + else + stat->shd = floor(temp); + } + break; + case '3': + printw("A book costs %d gp. How many do you want (%.0f max) ? ",menu[2].cost,floor(stat->gld/menu[2].cost)); + temp = inflt(); + if (temp * menu[2].cost > stat->gld || temp < 0) + goto CHEAT; + else + { + stat->gld -= floor(temp) * menu[2].cost; + if (rnd() < 0.02) + goto DISHON; + else + if (rnd()*temp > stat->lvl/10 && temp != 1) + { + printw("\nYou blew your mind!\n"); + stat->brn /= 5; + } + else + stat->brn += floor(temp)*roll(25,10); + } + break; + case '4': + printw("Swords are %d gp per +1. How many + do you want (%.0f max) ? ",menu[3].cost,floor(stat->gld/menu[3].cost)); + temp = inflt(); + if (!temp) + break; + if (temp * menu[3].cost > stat->gld || temp < 0) + goto CHEAT; + else + { + stat->gld -= floor(temp) * menu[3].cost; + if (rnd() < 0.02) + goto DISHON; + else + stat->swd = floor(temp); + } + break; + case '5': + printw("A charm costs %d gp. How many do you want (%.0f max) ? ",menu[4].cost,floor(stat->gld/menu[4].cost)); + temp = inflt(); + if (temp * menu[4].cost > stat->gld || temp < 0) + goto CHEAT; + else + { + stat->gld -= floor(temp) * menu[4].cost; + if (rnd() < 0.02) + goto DISHON; + else + stat->chm += floor(temp); + } + break; + case '6': + printw("Quicksilver is %d gp per +1. How many + do you want (%.0f max) ? ",menu[5].cost,floor(stat->gld/menu[5].cost)); + temp = inflt(); + if (!temp) + break; + if (temp * menu[5].cost > stat->gld || temp < 0) + goto CHEAT; + else + { + stat->gld -= floor(temp) * menu[5].cost; + if (rnd() < 0.02) + goto DISHON; + else + stat->quks = min(99,floor(temp)); + } + break; + case '7': + printw("A blessing requires a %d gp donation. Still want one ? ",menu[6].cost); + ch = rgetch(); + if (toupper(ch) == 'Y') + if (stat->gld < menu[6].cost) + goto CHEAT; + else + { + stat->gld -= menu[6].cost; + if (rnd() < 0.02) + goto DISHON; + else + stat->bls = TRUE; + } + break; + } + break; + case 'S': + mvprintw(15,0,"A gem is worth %d gp. How many do you want to sell (%.0f max) ? ",menu[7].cost,stat->gem); + temp = inflt(); + if (temp > stat->gem || temp < 0) + goto CHEAT; + else + { + stat->gem -= floor(temp); + stat->gld += floor(temp) * menu[7].cost; + } + } + goto PROMPT; + +CHEAT: move(17,0); + if (!cheat) + { + addstr("Come on, merchants aren't stupid. Stop cheating.\n"); + cheat = TRUE; + goto PROMPT; + } + else + { + addstr("You had your chance. This merchant happens to be\n"); + printw("a %.0f level magic user, and you made %s mad!\n",roll(size*10,size*20),(rnd() < 0.5) ? "him" : "her"); + stat->x += roll(-250,500)*size; + stat->y += roll(-250,500)*size; + stat->nrg = min(size*20,stat->mxn); + ++stat->sin; + paws(23); + } + return; + +DISHON: mvaddstr(17,0,"The merchant stole your money!"); + refresh(); + stat->x -= floor(stat->x/10); + stat->y -= floor(stat->y/10); + sleep(2); +} + +void printstats(stat) /* show characteristics */ +register struct stats *stat; +{ + mvprintw(0,0,"%s%s\n",stat->name,printloc(stat->x,stat->y)); + mvprintw(1,0,"Level :%7u Energy :%9.0f(%9.0f) Manna:%9.0f Users:%3d\n", + stat->lvl,stat->nrg,stat->mxn + stat->shd,stat->man,users); + mvprintw(2,0,"Quick :%3.0f(%3d) Strength:%9.0f(%9.0f) Gold :%9.0f ", + speed,stat->quk + stat->quks,strength,stat->str + stat->swd,stat->gld); + switch (stat->status) + { + case PLAYING: + if (stat->nrg < 0.2 * (stat->mxn + stat->shd)) + addstr("Low Energy\n"); + else if (stat->blind) + addstr("Blind\n"); + else + clrtoeol(); + break; + case CLOAKED: + addstr("Cloaked\n"); + break; + case INBATTLE: + addstr("In Battle\n"); + break; + case OFF: + addstr("Off\n"); + } +} + +void showall(stat) /* show special items */ +register struct stats *stat; +{ +static char *flags[] = + { + "False", + " True" + }; + + mvprintw(6,0,"Type: %3d -- ",stat->typ); + switch (abs(stat->typ)) + { + case 1: + case 11: + case 21: + addstr("Magic User"); + break; + case 2: + case 12: + case 22: + addstr("Fighter"); + break; + case 3: + case 13: + case 23: + addstr("Elf"); + break; + case 4: + case 14: + case 24: + addstr("Dwarf"); + break; + case 5: + case 15: + case 25: + addstr("Halfling"); + break; + case 6: + case 16: + case 26: + addstr("Experimento"); + break; + case 90: + addstr("Ex-Valar"); + break; + case 99: + addstr("Valar"); + } + if (stat->typ > 10 && stat->typ < 90) + if (stat->typ > 20) + addstr(" (Council of Wise)"); + else + addstr(" (King)"); + addch('\n'); + mvprintw(7,0,"Experience: %9.0f",stat->exp); + mvprintw(8,0,"Brains : %9.0f",stat->brn); + mvprintw(9,0,"Magic Lvl : %9.0f",stat->mag); + mvprintw(10,0,"Sin : %9.5f",stat->sin); + mvprintw(11,0,"Poison : %9.5f",stat->psn); + mvprintw(12,0,"Gems : %9.0f",stat->gem); + mvprintw(13,0,"Age : %9d",stat->age); + mvprintw(7,40,"Holy Water: %9d",stat->hw); + mvprintw(8,40,"Amulets : %9d",stat->amu); + mvprintw(9,40,"Charms : %9d",stat->chm); + mvprintw(10,40,"Crowns : %9d",stat->crn); + mvprintw(11,40,"Shield : %9.0f",stat->shd); + mvprintw(12,40,"Sword : %9.0f",stat->swd); + mvprintw(13,40,"Quickslver: %9d",stat->quks); + + mvprintw(14,0,"Blessing: %s Ring: %s Virgin: %s Palantir: %s", + flags[stat->bls],flags[stat->rng.type != 0],flags[stat->vrg],flags[stat->pal]); +} + +void neatstuff(stat) /* random things */ +register struct stats *stat; +{ +double temp; +int ch; + + switch ((int) roll(0,100)) + { + case 1: + case 2: + if (stat->psn > 0) + { + mvaddstr(5,0,"You've found a medic! How much will you offer to be cured ? "); + temp = inflt(); + if (temp < 0 || temp > stat->gld) + { + mvaddstr(6,0,"He was not amused, and made you worse.\n"); + ++stat->psn; + } + else if (rnd()/2.0 > (temp + 1)/max(stat->gld,1)) + mvaddstr(6,0,"Sorry, he wasn't interested.\n"); + else + { + mvaddstr(6,0,"He accepted."); + stat->psn = max(0,stat->psn-1); + stat->gld -= floor(temp); + } + } + break; + case 3: + mvaddstr(6,0,"You've been caught raping and pillaging!\n"); + stat->exp += 4000; + stat->sin += 0.5; + break; + case 4: + temp = roll(6,50); + mvprintw(5,0,"You've found %.0f gold pieces, want them ? ",temp); + clrtoeol(); + ch = rgetch(); + if (toupper(ch) == 'Y') + stat->gld += temp; + break; + case 5: + if (stat->sin > 1) + { + mvaddstr(6,0,"You've found a Holy Orb!\n"); + stat->sin -= 0.25; + } + break; + case 6: + if (stat->psn < 1) + { + mvaddstr(6,0,"You've been hit with a plague!\n"); + ++stat->psn; + } + break; + case 7: + mvaddstr(6,0,"You've found some holy water.\n"); + ++stat->hw; + break; + case 8: + mvaddstr(6,0,"You've met a Guru. . ."); + if (rnd()*stat->sin > 1) + addstr("You disgusted him with your sins!\n"); + else if (stat->psn > 0) + { + addstr("He looked kindly upon you, and cured you.\n"); + stat->psn = 0; + } + else + { + addstr("He rewarded you for your virtue.\n"); + stat->man += 50; + stat->shd += 2; + } + break; + case 9: + mvaddstr(6,0,"You've found an amulet.\n"); + ++stat->amu; + break; + case 10: + if (stat->blind) + { + mvaddstr(6,0,"You've regained your sight!\n"); + stat->blind = FALSE; + } + break; + default: + if (stat->psn > 0) + stat->nrg -= min(stat->psn*stat->mxn/45,0.9*stat->mxn); + stat->nrg = max(stat->nrg,floor(stat->mxn/11)); + } +} diff --git a/src/games/phantasia/func1.c b/src/games/phantasia/func1.c new file mode 100644 index 0000000..1c30a4e --- /dev/null +++ b/src/games/phantasia/func1.c @@ -0,0 +1,904 @@ +/* + * func1.c Phantasia support routines + */ + +#include "phant.h" + +bool findname(name) /* return TRUE if name in use */ +register char *name; +{ +FILE *fp; +struct stats buf; + + fp = fopen(peoplefile,"r"); + while (fread((char *) &buf,sizeof(buf),1,fp)) + if (!strcmp(buf.name,name)) + { + fclose(fp); + mvaddstr(21,0,"Name already in use.\n"); + refresh(); + return (TRUE); + } + fclose(fp); + return (FALSE); +} + +int findspace() /* allocate space for a character in peoplefile */ +{ +FILE *fp; +struct stats buf; +register int loc; + + loc = 0; + fp = fopen(peoplefile,"r"); + while (fread((char *) &buf,sizeof(buf),1,fp)) + { + if (!strcmp(buf.name,"")) + { + fclose(fp); + return (loc); + } + else + ++loc; + } + fclose(fp); + fp = fopen(peoplefile,ACCESS); + fseek(fp,(long) loc * sizeof(buf),0); + initchar(&buf); + strcpy(buf.name,"inuse"); + fwrite((char *) &buf,sizeof(buf),1,fp); + fclose(fp); + return (loc); +} + +int findchar(stat) /* retrieve a character from file */ +register struct stats *stat; +{ +register int loc = 0, loop; +char name[21]; +FILE *fp; + + if (fp = fopen(peoplefile,"r")) + { + clear(); + mvprintw(10,0,"What was your character's name ? "); + getstring(name,21); + strunc(name); + while (fread((char *) stat,sizeof(*stat),1,fp)) + { + if (!strcmp(stat->name,name)) + { + move(11,0); + refresh(); + fclose(fp); + nocrmode(); + for (loop = 0; loop < 2; ++loop) + if (!strcmp(getpass("Password ? "),stat->pswd)) + { + crmode(); + return (loc); + } + else + printf("No good.\n"); + exit1(); + /*NOTREACHED*/ + } + ++loc; + } + } + fclose(fp); + addstr("\n\nNot found.\n"); + exit1(); +/*NOTREACHED*/ +} + +void leave(stat) /* save character in file */ +register struct stats *stat; +{ +long ltemp; + + if (!stat->lvl) + strcpy(stat->name,""); + stat->status = OFF; + time(<emp); + stat->age += ltemp - secs; + update(stat,fileloc); + exit1(); + /*NOTREACHED*/ +} + +void talk(name) /* send message to all players */ +register char *name; +{ +FILE *fp; +char aline[160]; + + mvaddstr(5,0,"Message ? "); + getstring(aline,160); + fp = fopen(messfile,"w"); + if (*aline) + fprintf(fp,"%s: %s",name,aline); + fclose(fp); +} + +void death(stat) /* remove a player after dying */ +register struct stats *stat; +{ +FILE *fp; +char aline[100]; +int ch; +register int loop; +long ltemp; + + clear(); + if (stat->typ == 99) + if (stat->rng.duration) + { + addstr("Valar should be more cautious. You've been killed.\n"); + printw("You only have %d more chance(s).\n",--stat->rng.duration); + paws(3); + stat->nrg = stat->mxn; + return; + } + else + { + addstr("You had your chances, but Valar aren't totally\n"); + addstr("immortal. You are now left to wither and die . . .\n"); + paws(3); + stat->brn = stat->lvl /25; + stat->nrg = stat->mxn; + stat->quks = stat->swd = 0; + stat->typ = 90; + return; + } + if (stat->lvl > 9999) + addstr("Characters greater than level 10K must be retired. Sorry."); + switch(stat->rng.type) + { + case -DLREG: + case -NAZREG: + mvaddstr(4,0,"Your ring saved you from death!\n"); + refresh(); + stat->rng.type = NONE; + stat->nrg = stat->mxn/12+1; + stat->crn -= (stat->crn > 0); + return; + case DLBAD: + case -DLBAD: + case NAZBAD: + case -NAZBAD: + case -SPOILED: + case SPOILED: + mvaddstr(4,0,"Your ring has taken control of you and turned you into a monster!\n"); + fp = fopen(monsterfile,"r"); + for (loop = 0; loop <= 13; ++loop) { + if (! fgets(aline,100,fp)) + /*ignore*/; + } + ltemp = ftell(fp); + fclose(fp); + fp = fopen(monsterfile,ACCESS); + fseek(fp,ltemp,0); + fprintf(fp,"%-20s",stat->name); + fclose(fp); + } + initchar(stat); + fp = fopen(lastdead,"w"); + fprintf(fp,"%s Login: %s",stat->name,stat->login); + fclose(fp); + strcpy(stat->name,""); + update(stat,fileloc); + clear(); + move(10,0); + switch ((int) roll(1,5)) + { + case 1: + addstr("You've crapped out! "); + break; + case 2: + addstr("You have been disemboweled. "); + break; + case 3: + addstr("You've been mashed, mauled, and spit upon. (You're dead.)\n"); + break; + case 4: + addstr("You died! "); + break; + case 5: + addstr("You're a complete failure -- you've died!!\n"); + } + addstr("Care to give it another try ? "); + ch = rgetch(); + if (toupper(ch) == 'Y') { + endwin(); + execl(gameprog, "phantasia", "-s", (char*)0); + } + exit1(); + /*NOTREACHED*/ +} + +void +update(stat,place) /* update charac file */ + register struct stats *stat; + register int place; +{ + FILE *fp; + + fp = fopen(peoplefile,ACCESS); + fseek(fp,(long) place*sizeof(*stat),0); + fwrite((char *) stat,sizeof(*stat),1,fp); + fclose(fp); +} + +void printplayers(stat) /* show users */ +register struct stats *stat; +{ +FILE *fp; +struct stats buf; +register int loop = 0; +double loc; +long ltmp; +int ch; + + if (stat->blind) + { + mvaddstr(6,0,"You can't see anyone.\n"); + return; + } + loc = circ(stat->x,stat->y); + mvaddstr(6,0,"Name X Y Lvl Type Login\n"); + fp = fopen(peoplefile,"r"); + while (fread((char *) &buf,sizeof(buf),1,fp)) + { + if (buf.status) + { + ch = (buf.status == CLOAKED) ? '?' : 'W'; + if (stat->typ > 10 || buf.typ > 10 || loc >= circ(buf.x,buf.y) || stat->pal) + if (buf.status != CLOAKED || (stat->typ == 99 && stat->pal)) + if (buf.typ == 99) + addstr("The Valar is watching you. . .\n"); + else if (buf.wormhole) + printw("%-20s %c %c %6u %3d %-9s\n", + buf.name,ch,ch,buf.lvl,buf.typ,buf.login); + else + printw("%-20s %8.0f %8.0f %6u %3d %-9s\n", + buf.name,buf.x,buf.y,buf.lvl,buf.typ,buf.login); + else + if (buf.typ == 99) + --loop; + else + printw("%-20s ? ? %6u %3d %-9s\n", + buf.name,buf.lvl,buf.typ,buf.login); + ++loop; + } + } + fclose(fp); + time(<mp); + printw("Total users = %d %s\n",loop,ctime(<mp)); + refresh(); +} + + +void printhelp() /* print help file */ +{ +FILE *fp; +char instr[100]; + + fp = fopen(helpfile,"r"); + while (fgets(instr,100,fp)) + fputs(instr,stdout); + fclose(fp); +} + +void titlestuff() /* print out a header */ +{ +FILE *fp; +char instr[80], hiname[21], nxtname[21], aline[80]; +bool cowfound = FALSE, kingfound = FALSE; +struct stats buf; +double hiexp, nxtexp; +unsigned hilvl, nxtlvl; +register int loop; + + mvaddstr(0,15,"W e l c o m e t o P h a n t a s i a (vers. 3.2)!"); + fp = fopen(motd,"r"); + if (fgets(instr,80,fp)) + mvaddstr(2,40 - strlen(instr)/2,instr); + fclose(fp); + fp = fopen(peoplefile,"r"); + while (fread((char *) &buf,sizeof(buf),1,fp)) + if (buf.typ > 10 && buf.typ < 20) + { + sprintf(instr,"The present ruler is %s Level:%d",buf.name,buf.lvl); + mvaddstr(4,40 - strlen(instr)/2,instr); + kingfound = TRUE; + break; + } + if (!kingfound) + mvaddstr(4,24,"There is no ruler at this time."); + fseek(fp,0L,0); + while (fread((char *) &buf,sizeof(buf),1,fp)) + if (buf.typ == 99) + { + sprintf(instr,"The Valar is %s Login: %s",buf.name,buf.login); + mvaddstr(6,40 - strlen(instr)/2,instr); + break; + } + fseek(fp,0L,0); + while (fread((char *) &buf,sizeof(buf),1,fp)) + if (buf.typ > 20 && buf.typ < 90) + { + if (!cowfound) + { + mvaddstr(8,30,"Council of the Wise:"); + loop = 10; + cowfound = TRUE; + } + /* This assumes a finite (<=7) number of C.O.W.: */ + sprintf(instr,"%s Login: %s",buf.name,buf.login); + mvaddstr(loop++,40 - strlen(instr)/2,instr); + } + fseek(fp,0L,0); + *nxtname = *hiname = '\0'; + hiexp = 0.0; + nxtlvl = hilvl = 0; + while (fread((char *) &buf,sizeof(buf),1,fp)) + if (buf.exp > hiexp && buf.typ < 20) + { + nxtexp = hiexp; + hiexp = buf.exp; + nxtlvl = hilvl; + hilvl = buf.lvl; + strcpy(nxtname,hiname); + strcpy(hiname,buf.name); + } + else if (buf.exp > nxtexp && buf.typ < 20) + { + nxtexp = buf.exp; + nxtlvl = buf.lvl; + strcpy(nxtname,buf.name); + } + fclose(fp); + mvaddstr(17,28,"Highest characters are:"); + sprintf(instr,"%s Level:%d and %s Level:%d",hiname,hilvl,nxtname,nxtlvl); + mvaddstr(19,40 - strlen(instr)/2,instr); + fp = fopen(lastdead,"r"); + if (! fgets(aline,80,fp)) + /*ignore*/; + sprintf(instr,"The last character to die is %s",aline); + mvaddstr(21,40 - strlen(instr)/2,instr); + fclose(fp); + refresh(); +} + + + +void printmonster() /* do a monster list on the terminal */ +{ +FILE *fp; +register int count = 0; +char instr[100]; + + puts(" # Name Str Brains Quick Hits Exp Treas Type Flock%\n"); + fp = fopen(monsterfile,"r"); + while (fgets(instr,100,fp)) + printf("%2d %s",count++,instr); + fclose(fp); +} + +void +exit1() /* exit, but cleanup */ +{ + move(23,0); + refresh(); + nocrmode(); + endwin(); + exit(0); + /*NOTREACHED*/ +} + +void init1() /* set up for screen updating */ +{ + /* catch/ingnore signals */ + signal(SIGQUIT,SIG_IGN); + signal(SIGALRM,SIG_IGN); + signal(SIGTERM,SIG_IGN); + signal(SIGTSTP,SIG_IGN); + signal(SIGTTIN,SIG_IGN); + signal(SIGTTOU,SIG_IGN); + signal(SIGINT,SIG_IGN); + + srand((unsigned) time((long *) NULL)); /* prime random numbers */ + initscr(); + noecho(); + crmode(); + clear(); + refresh(); +} + +void +getstring(cp,mx) /* get a string from the stdscr at current y,x */ + register char *cp; + register int mx; +{ + register int loop = 0, x, y, xorig; + int ch; + + getyx(stdscr,y,xorig); + clrtoeol(); + refresh(); + while((ch = getch()) != '\n' && loop < mx - 1) + switch (ch) + { + case '\033': /* escape */ + case '\010': /* backspace */ + if (loop) + { + --loop; + getyx(stdscr,y,x); + mvaddch(y,x-1,' '); + move(y,x-1); + refresh(); + } + break; + case '\030': /* ctrl-x */ + loop = 0; + move(y,xorig); + clrtoeol(); + refresh(); + break; + default: + if (ch >= ' ') /* printing char */ + { + addch(ch); + cp[loop++] = ch; + refresh(); + } + } + cp[loop] = '\0'; +} + + +void showusers() /* print a list of all characters */ +{ +struct stats buf; +FILE *fp; + + if (fp = fopen(peoplefile,"r")) + { + puts("Current characters on file are:\n"); + while (fread((char *) &buf,sizeof(buf),1,fp)) + if (strcmp("",buf.name)) + printf("%-20s Login: %-9s Level: %6u\n",buf.name,buf.login,buf.lvl); + fclose(fp); + } +} + +void kingstuff(stat) /* stuff upon entering throne */ +register struct stats *stat; +{ +FILE *fp; +struct stats buf; +struct nrgvoid vbuf; +register int loc = 0; + + if (stat->typ < 10) /* check to see if king -- assumes crown */ + { + fp = fopen(peoplefile,"r"); + while (fread((char *) &buf,sizeof(buf),1,fp)) + if (buf.typ > 10 && buf.typ < 20) /* found old king */ + if (buf.status != OFF) + { + mvaddstr(6,0,"The king is playing, so you cannot steal his throne\n"); + stat->x = stat->y = 9; + move(3,0); + fclose(fp); + return; + } + else + { + buf.typ -= 10; + if (buf.crn) + --buf.crn; + fclose(fp); + update(&buf,loc); +KING: stat->typ = abs(stat->typ) + 10; + mvaddstr(6,0,"You have become king!\n"); + fp = fopen(messfile,"w"); + fprintf(fp,"All hail the new king!"); + fclose(fp); + /* clear all energy voids */ + fp = fopen(voidfile,"r"); + if (fread((char *) &vbuf,sizeof(vbuf),1,fp) != 1) + /*ignore*/; + fclose(fp); + fp = fopen(voidfile,"w"); + fwrite((char *) &vbuf,sizeof(vbuf),1,fp); + fclose(fp); + goto EXIT; + } + else + ++loc; + fclose(fp); /* old king not found -- install new one */ + goto KING; + } +EXIT: mvaddstr(3,0,"0:Decree "); +} + +void +paws(where) /* wait for input to continue */ + int where; +{ + mvaddstr(where,0,"-- more --"); + rgetch(); +} + +void cstat() /* examine/change stats of a character */ +{ +struct stats charac; +char s[60], flag[2]; +FILE *fp; +register int loc = 0; +int c, temp, today; +long ltemp; +double dtemp; + + flag[0] = 'F'; flag[1] = 'T'; + mvaddstr(10,0,"Which character do you want to look at ? "); + getstring(s,60); + if (fp = fopen(peoplefile,"r")) + while (fread((char *) &charac,sizeof(charac),1,fp)) + if (!strcmp(s,charac.name)) + goto FOUND; + else + ++loc; + mvaddstr(11,0,"Not found."); + exit1(); + /*NOTREACHED*/ + +FOUND: fclose(fp); + time(<emp); + today = localtime(<emp)->tm_yday; + if (!su) + strcpy(charac.pswd,"XXXXXXXX"); + clear(); +TOP: mvprintw(0,0,"a:Name %s\n",charac.name); + printw("b:Password %s\n",charac.pswd); + printw(" :Login %s\n",charac.login); + temp = today - charac.lastused; + if (temp < 0) + temp += 365; + printw("c:Used %d\n",temp); + mvprintw(5,0,"d:Experience %.0f\n",charac.exp); + printw("e:Level %d\n",charac.lvl); + printw("f:Strength %.0f\n",charac.str); + printw("g:Sword %.0f\n",charac.swd); + printw("h:Quickness %d\n",charac.quk); + printw("i:Quikslvr %d\n",charac.quks); + printw("j:Energy %.0f\n",charac.nrg); + printw("k:Max-Nrg %.0f\n",charac.mxn); + printw("l:Shield %.0f\n",charac.shd); + printw("m:Magic %.0f\n",charac.mag); + printw("n:Manna %.0f\n",charac.man); + printw("o:Brains %.0f\n",charac.brn); + mvprintw(0,40,"p:X-coord %.0f\n",charac.x); + mvprintw(1,40,"q:Y-coord %.0f\n",charac.y); + if (su) + mvprintw(2,40,"r:Wormhole %d\n",charac.wormhole); + else + mvprintw(2,40,"r:Wormhole %c\n",flag[charac.wormhole != 0]); + mvprintw(3,40,"s:Type %d\n",charac.typ); + mvprintw(5,40,"t:Sin %0.3f\n",charac.sin); + mvprintw(6,40,"u:Poison %0.3f\n",charac.psn); + mvprintw(7,40,"v:Gold %.0f\n",charac.gld); + mvprintw(8,40,"w:Gem %.0f\n",charac.gem); + mvprintw(9,40,"x:Holy Water %d\n",charac.hw); + mvprintw(10,40,"y:Charms %d\n",charac.chm); + mvprintw(11,40,"z:Crowns %d\n",charac.crn); + mvprintw(12,40,"1:Amulets %d\n",charac.amu); + mvprintw(13,40,"2:Age %d\n",charac.age); + mvprintw(18,5,"3:Virgin %c 4:Blessed %c 5:Ring %c 6:Blind %c 7:Palantir %c", + flag[charac.vrg],flag[charac.bls],flag[charac.rng.type != 0],flag[charac.blind],flag[charac.pal]); + if (!su) + exit1(); + mvaddstr(15,40,"!:Quit"); + mvaddstr(16,40,"?:Delete"); + mvaddstr(19,30,"8:Duration"); + mvaddstr(21,0,"What would you like to change? "); + c = rgetch(); + switch(c) + { + case 'p': /* change x coord */ + mvprintw(23,0,"x = %f; x = ",charac.x); + dtemp = inflt(); + if (dtemp != 0.0) + charac.x = dtemp; + break; + case 'q': /* change y coord */ + mvprintw(23,0,"y = %f; y = ",charac.y); + dtemp = inflt(); + if (dtemp != 0.0) + charac.y = dtemp; + break; + case 'd': /* change Experience */ + mvprintw(23,0,"exp = %f; exp = ",charac.exp); + dtemp = inflt(); + if (dtemp != 0.0) + charac.exp = dtemp; + break; + case 'e': /* change level */ + mvprintw(23,0,"lvl = %d; lvl;= ",charac.lvl); + dtemp = inflt(); + if (dtemp != 0.0) + charac.lvl = dtemp; + break; + case 'h': /* change quickness */ + mvprintw(23,0,"quk = %d; quk;= ",charac.quk); + dtemp = inflt(); + if (dtemp != 0.0) + charac.quk = dtemp; + break; + case 'f': /* change strength */ + mvprintw(23,0,"str = %f; str;= ",charac.str); + dtemp = inflt(); + if (dtemp != 0.0) + charac.str = dtemp; + break; + case 't': /* change Sin */ + mvprintw(23,0,"sin = %f; sin;= ",charac.sin); + dtemp = inflt(); + if (dtemp != 0.0) + charac.sin = dtemp; + break; + case 'n': /* change manna */ + mvprintw(23,0,"man = %f; man;= ",charac.man); + dtemp = inflt(); + if (dtemp != 0.0) + charac.man = dtemp; + break; + case 'v': /* change gold */ + mvprintw(23,0,"gld = %f; gld;= ",charac.gld); + dtemp = inflt(); + if (dtemp != 0.0) + charac.gld = dtemp; + break; + case 'j': /* change energy */ + mvprintw(23,0,"nrg = %f; nrg;= ",charac.nrg); + dtemp = inflt(); + if (dtemp != 0.0) + charac.nrg = dtemp; + break; + case 'k': /* change Maximum energy */ + mvprintw(23,0,"mxn = %f; mxn;= ",charac.mxn); + dtemp = inflt(); + if (dtemp != 0.0) + charac.mxn = dtemp; + break; + case 'm': /* change magic */ + mvprintw(23,0,"mag = %f; mag;= ",charac.mag); + dtemp = inflt(); + if (dtemp != 0.0) + charac.mag = dtemp; + break; + case 'o': /* change brains */ + mvprintw(23,0,"brn = %f; brn;= ",charac.brn); + dtemp = inflt(); + if (dtemp != 0.0) + charac.brn = dtemp; + break; + case 'z': /* change crowns */ + mvprintw(23,0,"crn = %d; crn;= ",charac.crn); + dtemp = inflt(); + if (dtemp != 0.0) + charac.crn = dtemp; + break; + case '5': /* change ring type */ + mvprintw(23,0,"rng-type = %d; rng-type;= ",charac.rng.type); + dtemp = inflt(); + if (dtemp != 0.0) + charac.rng.type = dtemp; + break; + case '8': /* change ring duration */ + mvprintw(23,0,"rng-duration = %d; rng-duration;= ",charac.rng.duration); + dtemp = inflt(); + if (dtemp != 0.0) + charac.rng.duration = dtemp; + break; + case '7': /* change palantir */ + mvprintw(23,0,"pal = %d; pal;= ",charac.pal); + dtemp = inflt(); + if (dtemp != 0.0) + { + charac.pal = dtemp; + charac.pal = (charac.pal != 0); + } + break; + case 'u': /* change poison */ + mvprintw(23,0,"psn = %f; psn;= ",charac.psn); + dtemp = inflt(); + if (dtemp != 0.0) + charac.psn = dtemp; + break; + case 'x': /* change holy water */ + mvprintw(23,0,"hw = %d; hw;= ",charac.hw); + dtemp = inflt(); + if (dtemp != 0.0) + charac.hw = dtemp; + break; + case '1': /* change amulet */ + mvprintw(23,0,"amu = %d; amu;= ",charac.amu); + dtemp = inflt(); + if (dtemp != 0.0) + charac.amu = dtemp; + break; + case '4': /* change Blessing */ + mvprintw(23,0,"bls = %d; bls;= ",charac.bls); + dtemp = inflt(); + if (dtemp != 0.0) + { + charac.bls = dtemp; + charac.bls = (charac.bls != 0); + } + break; + case 'y': /* change Charm */ + mvprintw(23,0,"chm = %d; chm;= ",charac.chm); + dtemp = inflt(); + if (dtemp != 0.0) + charac.chm = dtemp; + break; + case 'w': /* change Gems */ + mvprintw(23,0,"gem = %f; gem;= ",charac.gem); + dtemp = inflt(); + if (dtemp != 0.0) + charac.gem = dtemp; + break; + case 'i': /* change Quicksilver */ + mvprintw(23,0,"quks = %d; quks;= ",charac.quks); + dtemp = inflt(); + if (dtemp != 0.0) + charac.quks = dtemp; + break; + case 'g': /* change swords */ + mvprintw(23,0,"swd = %f; swd;= ",charac.swd); + dtemp = inflt(); + if (dtemp != 0.0) + charac.swd = dtemp; + break; + case 'l': /* change shields */ + mvprintw(23,0,"shd = %f; shd;= ",charac.shd); + dtemp = inflt(); + if (dtemp != 0.0) + charac.shd = dtemp; + break; + case 's': /* change type */ + mvprintw(23,0,"typ = %d; typ;= ",charac.typ); + dtemp = inflt(); + if (dtemp != 0.0) + charac.typ = dtemp; + break; + case '3': /* change virgin */ + mvprintw(23,0,"vrg = %d; vrg;= ",charac.vrg); + dtemp = inflt(); + if (dtemp != 0.0) + { + charac.vrg = dtemp; + charac.vrg = (charac.vrg != 0); + } + break; + case 'c': /* change last-used */ + mvprintw(23,0,"last-used = %d; last-used;= ",charac.lastused); + dtemp = inflt(); + if (dtemp != 0.0) + charac.lastused = dtemp; + break; + case 'b': /* change password */ + mvaddstr(23,0,"New password: "); + getstring(s,60); + if (*s) + strcpy(charac.pswd,s); + break; + case 'a': /* change name */ + mvaddstr(23,0,"New name: "); + getstring(s,60); + if (*s) + strcpy(charac.name,s); + break; + case 'r': /* change wormhole */ + mvprintw(23,0,"wormhole = %d; wormhole;= ",charac.wormhole); + dtemp = inflt(); + if (dtemp != 0.0) + charac.wormhole = dtemp; + break; + case '2': /* change age */ + mvprintw(23,0,"age = %d; age;= ",charac.age); + dtemp = inflt(); + if (dtemp != 0.0) + charac.age = dtemp; + break; + case '6': /* change blindness */ + mvprintw(23,0,"blind = %d; blind;= ",charac.blind); + dtemp = inflt(); + if (dtemp != 0.0) + { + charac.blind = dtemp; + charac.blind = (charac.blind != 0); + } + break; + case '!': /* quit, update */ + goto LEAVE; + case '?': /* delete char */ + strcpy(charac.name,""); + initchar(&charac); + goto LEAVE; + } + goto TOP; +LEAVE: charac.status = OFF; + update(&charac,loc); +} + +unsigned level(expr) /* calculate level */ +double expr; +{ + if (expr < 1.1e+7) + return (pow((expr/1000.0), 0.4875)); + else + return (pow((expr/1250.0), 0.4865)); +} + +void strunc(str) /* remove blank spaces at the end of str[] */ +register char *str; +{ +register int loop; + loop = strlen(str) - 1; + while (str[--loop] == ' ') + str[loop] = '\0'; +} + +double +inflt() /* get a floating point # from the terminal */ +{ + char aline[80]; + double res; + + getstring(aline,80); + if (sscanf(aline, "%lf", &res) < 1) + res = 0; + return (res); +} + +void checkmov(stat) /* see if beyond PONR */ +register struct stats *stat; +{ + if (beyond) + { + stat->x = sgn(stat->x) * max(abs(stat->x),1.1e+6); + stat->y = sgn(stat->y) * max(abs(stat->y),1.1e+6); + } +} +void scramble(stat) /* mix up some stats */ +register struct stats *stat; +{ +double buf[5], temp; +register int first, second; +register double *bp; + + bp = buf; + *bp++ = stat->str; + *bp++ = stat->man; + *bp++ = stat->brn; + *bp++ = stat->mag; + *bp++ = stat->nrg; + + bp = buf; + first = roll(0,5); + second = roll(0,5); + temp = bp[first]; + bp[first] = bp[second]; + bp[second] = temp; + + stat->str = *bp++; + stat->man = *bp++; + stat->brn = *bp++; + stat->mag = *bp++; + stat->nrg = *bp++; +} diff --git a/src/games/phantasia/func2.c b/src/games/phantasia/func2.c new file mode 100644 index 0000000..d13e115 --- /dev/null +++ b/src/games/phantasia/func2.c @@ -0,0 +1,850 @@ +/* + * func2.c Phantasia support routines + */ + +#include "phant.h" + +static void +voidupdate(vp,loc) /* update an energy void */ + register struct nrgvoid *vp; + register int loc; +{ + FILE *fp; + + fp = fopen(voidfile,ACCESS); + fseek(fp,(long) loc*sizeof(*vp),0); + fwrite((char *) vp,sizeof(*vp),1,fp); + fclose(fp); +} + +static void +statread(stat,loc) /* read a charac. structure */ + register struct stats *stat; + register int loc; +{ + FILE *fp; + + fp = fopen(peoplefile,"r"); + fseek(fp,(long) loc * sizeof(*stat),0); + if (fread((char *) stat,sizeof(*stat),1,fp) != 1) + /*ignore*/; + fclose(fp); +} + +static void +tampered(stat,what,bufp) /* decree'd, intervened, etc. */ + register struct stats *stat, *bufp; + int what; +{ + struct nrgvoid vbuf; + register int loc; + struct stats sbuf; + FILE *fp; + + changed = TRUE; + move(6,0); + stat->tampered = OFF; + switch ((int) what) + { + case NRGVOID: + addstr("You've hit an energy void !\n"); + stat->man /= 3; + stat->nrg /= 2; + stat->gld = floor(stat->gld/1.25) + 0.1; + stat->x += 10; + break; + case TRANSPORT: + addstr("The king transported you ! "); + if (stat->chm) + { + addstr("But your charm save you. . .\n"); + --stat->chm; + } + else + { + stat->x += roll(-50,100) * circ(stat->x,stat->y); + stat->y += roll(-50,100) * circ(stat->x,stat->y); + addch('\n'); + } + break; + case GOLD: + printw("The king has bestowed %.0f gold pieces on you !\n",bufp->scratch1); + stat->gld += bufp->scratch1; + break; + case CURSED: + addstr("You've been cursed ! "); + if (stat->bls) + { + addstr("But your blessing saved you. . .\n"); + stat->bls = FALSE; + } + else + { + addch('\n'); + stat->psn += 2; + stat->nrg = 10; + stat->mxn *= 0.95; + stat->status = PLAYING; + } + break; + case VAPORIZED: + addstr("Woops! You've been vaporized!\n"); + death(stat); + break; + case MONSTER: + addstr("The Valar zapped you with a monster!\n"); + paws(7); + fight(stat,(int) bufp->scratch1); + return; + case BLESS: + addstr("The Valar has blessed you!\n"); + stat->nrg = (stat->mxn *= 1.05) + stat->shd; + stat->man += 500; + stat->str += 0.5; + stat->brn += 0.5; + stat->mag += 0.5; + stat->psn = min(0.5,stat->psn); + break; + case MOVED: + addstr("You've been relocated. . .\n"); + stat->x = bufp->scratch1; + stat->y = bufp->scratch2; + break; + case HEAL: + addstr("You've been healed!\n"); + stat->psn -= 0.25; + stat->nrg = stat->mxn + stat->shd; + break; + case STOLEN: + addstr("You'Ve been bumped off as Valar!\n"); + stat->typ = 20 + roll(1,6); + break; + case GRAIL: + addstr("You have found The Holy Grail!!\n"); + if (stat->typ < 20) + { + addstr("However, you are not experienced enough to behold it.\n"); + stat->sin *= stat->sin; + stat->man += 1000; + } + else if (stat->typ == 99 || stat->typ == 90) + { + addstr("You have made it to the position of Valar once already.\n"); + addstr("The Grail is of no more use to you now.\n"); + } + else + { + addstr("It is now time to see if you are worthy to behold it. . .\n"); + refresh(); + sleep(4); + if (rnd() / 2.0 < stat->sin) + { + addstr("You blew this one!\n"); + stat->str = stat->man = stat->quk = stat->nrg = stat->mxn = stat->x = stat->y = + stat->mag = stat->brn = stat->exp =1; + stat->lvl = 0; + } + else + { + addstr("You made to position of Valar!\n"); + stat->typ = 99; + fp = fopen(peoplefile,"r"); + loc = 0; + while (fread((char *) &sbuf,sizeof(sbuf),1,fp)) + if (sbuf.typ == 99) + { + sbuf.tampered = STOLEN; + update(&sbuf,loc); + break; + } + else + ++loc; + fclose(fp); + } + } + vbuf.active = TRUE; + vbuf.x = roll(-1e6,2e6); + vbuf.y = roll(-1e6,2e6); + voidupdate(&vbuf,0); + break; + } +} + +void +checktampered(stat) /* see if decree'd etc. */ + register struct stats *stat; +{ + struct nrgvoid vbuf; + struct stats sbuf; + FILE *fp; + register int loc = 0; + + /* first check for energy voids */ + fp = fopen(voidfile,"r"); + while (fread((char *) &vbuf,sizeof(vbuf),1,fp)) + if (vbuf.active && vbuf.x == stat->x && vbuf.y == stat->y) + { + fclose(fp); + if (loc) + { + vbuf.active = FALSE; + voidupdate(&vbuf,loc); + tampered(stat,NRGVOID,&sbuf); + } + else if (stat->status != CLOAKED) + tampered(stat,GRAIL,&sbuf); + break; + } + else + ++loc; + fclose(fp); + /* now check for other things */ + statread(&sbuf,fileloc); + if (sbuf.tampered) + tampered(stat,sbuf.tampered,&sbuf); +} + +void +decree(stat) /* king and valar stuff */ + register struct stats *stat; +{ + FILE *fp; + short arg; + char aline[80], *cp; + struct stats sbuf; + struct nrgvoid vbuf; + double temp1 = 0.0, temp2 = 0.0; + int ch; + register int loc = 0; + + move(3,0); + clrtoeol(); + if (stat->typ < 20 && !su) /* king */ + { + addstr("1:Transport 2:Curse 3:Energy Void 4:Bestow 5:Collect Taxes "); + ch = rgetch(); + move(3,0); + clrtoeol(); + switch (ch) + { + case '1': + arg = TRANSPORT; + cp = "transport"; + break; + case '2': + arg = CURSED; + cp = "curse"; + break; + case '3': + addstr("Enter the X Y coordinates of void ? "); + getstring(aline,30); + sscanf(aline,"%lf %lf",&temp1,&temp2); + vbuf.x = floor(temp1); + vbuf.y = floor(temp2); + vbuf.active = TRUE; + voidupdate(&vbuf,allocvoid()); + goto EXIT; + case '4': + arg = GOLD; + addstr("How much gold to bestow ? "); + temp1 = inflt(); + if (temp1 > stat->gld || temp1 < 0) + { + mvaddstr(6,0,"You don't have that !\n"); + return; + } + stat->gld -= floor(temp1); + cp = "give gold to"; + break; + case '5': + fp = fopen(goldfile,"r"); + if (fread((char *) &temp1,sizeof(double),1,fp) != 1) + /*ignore*/; + fclose(fp); + mvprintw(6,0,"You have collected %.0f in gold.\n",temp1); + stat->gld += floor(temp1); + fp = fopen(goldfile,"w"); + temp1 = 0.0; + fwrite((char *) &temp1,sizeof(double),1,fp); + fclose(fp); + return; + default: + return; + } + } + else /* council of wise, valar, etc. */ + { + addstr("1:Heal "); + if (stat->pal || su) + addstr("2:Seek Grail "); + if (stat->typ == 99 || su) + addstr("3:Throw Monster 4:Relocate 5:Bless "); + if (su) + addstr("6:Vaporize "); + ch = rgetch(); + if (!su && ch > '2' && stat->typ != 99) + { + illcmd(); + return; + } + switch (ch) + { + case '1': + arg = HEAL; + cp = "heal"; + break; + case '2': + if (stat->pal) + { + fp = fopen(voidfile,"r"); + if (fread((char *) &vbuf,sizeof(vbuf),1,fp) != 1) + /*ignore*/; + fclose(fp); + temp1 = hypot(stat->x - vbuf.x,stat->y - vbuf.y); + temp1 = floor(temp1 + roll(-temp1/10.0,temp1/5.0)); + mvprintw(6,0,"The palantir says the Grail is about %.0f away.\n",temp1); + return; + } + else + { + mvaddstr(6,0,"You need a palantir to seek the Grail.\n"); + return; + } + case '3': + mvaddstr(3,0,"Which monster [0-99] ? "); + temp1 = inflt(); + temp1 = max(0,min(99,temp1)); + cp = "throw a monster at"; + arg = MONSTER; + break; + case '4': + mvaddstr(3,0,"New X Y coordinates ? "); + getstring(aline,30); + sscanf(aline,"%lf %lf",&temp1,&temp2); + cp = "relocate"; + arg = MOVED; + break; + case '5': + arg = BLESS; + cp = "bless"; + break; + case '6': + if (su) + { + cp = "vaporize"; + arg = VAPORIZED; + break; + } + default: + return; + } + } + mvprintw(3,0,"Who do you want to %s ? ",cp); + getstring(aline,21); + strunc(aline); + if (strcmp(stat->name,aline)) + { + fp = fopen(peoplefile,"r"); + while (fread((char *) &sbuf,sizeof(sbuf),1,fp)) + if (strcmp(aline,sbuf.name)) + ++loc; + else + { + fclose(fp); + if (sbuf.tampered) + { + mvaddstr(6,0,"That person has something pending already.\n"); + return; + } + else + { + sbuf.tampered = arg; + sbuf.scratch1 = floor(temp1); + sbuf.scratch2 = floor(temp2); + update(&sbuf,loc); +EXIT: mvaddstr(6,0,"It is done.\n"); + return; + } + } + fclose(fp); + mvaddstr(6,0,"There is no one by that name.\n"); + } + else + mvaddstr(6,0,"You may not do it to yourself!\n"); +} + +int +allocvoid() /* find a space to put an energy void */ +{ + FILE *fp; + register int loc = 0; + struct nrgvoid vbuf; + + fp = fopen(voidfile,"r"); + while (fread((char *) &vbuf,sizeof(vbuf),1,fp)) + if (vbuf.active) + ++loc; + else + { + fclose(fp); + return (loc); + } + fclose(fp); + return (loc); +} + +void +adjuststats(stat) /* make sure things are within limits, etc. */ + register struct stats *stat; +{ + long ltemp; + register int temp; + + stat->x = floor(stat->x); + stat->y = floor(stat->y); + valhala = (stat->typ == 99); + throne = (stat->x == 0.0 && stat->y == 0.0); + temp = abs(stat->x)/400; + if (temp > 16) + temp = 0; + if (stat->y == 0.0 && !throne && !valhala && temp == abs(stat->x)/400 && sgn(stat->x) == (int) pow(-1.0, (double) temp)) + { + if (!wmhl) + stat->wormhole = temp; + wmhl = TRUE; + } + else + wmhl = FALSE; + speed = stat->quk + stat->quks - spdcalc(stat->lvl,stat->gld,stat->gem); + strength = stat->str + stat->swd - strcalc(stat->str,stat->psn); + time(<emp); + stat->age += ltemp - secs; + secs = ltemp; + stat->quks = min(99,stat->quks); + stat->man = min(stat->man,stat->lvl*15 + 5000); + stat->chm = min(stat->chm,stat->lvl + 10); + stat->typ = (stat->crn && stat->typ < 10) ? -abs(stat->typ) : abs(stat->typ); + if (level(stat->exp) > stat->lvl) + movelvl(stat); + stat->gld = floor(stat->gld) + 0.1; + stat->gem = floor(stat->gem) + 0.1; + if (stat->rng.type) + stat->nrg = stat->mxn + stat->shd; + if (stat->rng.type && stat->rng.duration <= 0) /* clean up rings */ + switch (stat->rng.type) + { + case DLBAD: + case NAZBAD: + stat->rng.type = SPOILED; + stat->rng.duration = roll(10,25); + break; + case NAZREG: + stat->rng.type = NONE; + break; + case SPOILED: + death(stat); + break; + } /* DLREG is ok, so do nothing with it */ + stat->nrg += (stat->mxn+stat->shd)/15+stat->lvl/3+2; + stat->nrg = min(stat->nrg,stat->mxn + stat->shd); + if (stat->age > stat->degen * 2500) + { + ++stat->degen; + if (stat->quk > 23) + --stat->quk; + stat->str *= 0.97; + stat->brn *= 0.95; + stat->mag *= 0.97; + stat->mxn *= 0.95; + if (stat->quks) + --stat->quks; + stat->swd *= 0.93; + stat->shd *= 0.95; + } +} + +static void +interm(stat,who) /* interterminal battle routine */ + register struct stats *stat; + int who; +{ +#define MAXWAIT 20 +#define BLOCK sizeof(struct stats) +#define RAN 1 +#define STUCK 2 +#define BLEWIT 3 +#define KILLED 4 +#define readfoe() fseek(fin,foeplace,0); \ + if (fread((char *) foe,BLOCK,1,fin) != 1) /*ignore*/ +#define updateme() fseek(fout,myplace,0); \ + fwrite((char *) stat,BLOCK,1,fout); \ + fflush(fout) + + FILE *fin, *fout; /* pointers for input, output */ + double temp, foespeed, oldhits = 0.0, myhits; + struct stats sbuf; + register struct stats *foe; + register int loop, lines = 5; + int ch; + long myplace, foeplace; + int oldtags; + bool luckout = FALSE; + char foename[21]; + + fghting = TRUE; + mvaddstr(4,0,"Preparing for battle!\n"); + refresh(); + /* set up variables, file, etc. */ + myplace = fileloc * BLOCK; + foeplace = who * BLOCK; + fin = fopen(peoplefile,"r"); + setbuf(fin, (char *) NULL); + fout = fopen(peoplefile,ACCESS); + stat->status = INBATTLE; + myhits = stat->nrg; + stat->tampered = oldtags = 1; /* this must be non-zero to prevent a king or valar from trashing it */ + stat->scratch1 = stat->scratch2 = 0.0; + updateme(); + foe = &sbuf; + readfoe(); + foespeed = foe->quk + foe->quks - spdcalc(foe->lvl,foe->gld,foe->gem); + if (abs(stat->lvl - foe->lvl) > 20) /* see if greatly mismatched */ + { + temp = ((double) (stat->lvl - foe->lvl))/((double) max(stat->lvl,foe->lvl)); + if (temp > 0.5) /* this one outweighs his/her foe */ + foespeed *= 2.0; + else if (temp < -0.5) /* foe outweighs this one */ + speed *= 2.0; + } + if (stat->blind) + strcpy(foename,"someone"); + else + strcpy(foename,foe->name); + mvprintw(3,0,"You have encountered %s Level: %d\n",foename,foe->lvl); + refresh(); + /* now wait for foe to respond */ + for (loop = 1.5*MAXWAIT; foe->status != INBATTLE && loop; --loop) + { + readfoe(); + sleep(1); + } + if (foe->status != INBATTLE) + { + mvprintw(4,0,"%s is not responding.\n",foename); + goto LEAVE; + } + + /* otherwise, everything is set to go */ + move(4,0); + clrtoeol(); + /* check to see who goes first */ + if (speed > foespeed) + goto HITFOE; + else if (foespeed > speed) + goto WAIT; + else if (stat->lvl > foe->lvl) + goto HITFOE; + else if (foe->lvl > stat->lvl) + goto WAIT; + else /* no one is faster */ + { + printw("You can't fight %s yet.",foename); + goto LEAVE; + } + +/* routine to hit, etc */ +HITFOE: printstats(stat); + mvprintw(1,26,"%20.0f",myhits); + mvaddstr(4,0,"1:Fight 2:Run Away! 3:Power Blast "); + if (luckout) + clrtoeol(); + else + addstr("4:Luckout "); + ch = gch(stat->rng.type); + move(lines = 5,0); + clrtobot(); + switch (ch) + { + default: /* fight */ + temp = roll(2,strength); +HIT: mvprintw(lines++,0,"You hit %s %.0f times!",foename,temp); + stat->sin += 0.5; + stat->scratch1 += temp; + stat->scratch2 = FALSE; + break; + case '2': /* run away */ + --stat->scratch1; /* this value changes to indicate action */ + if (rnd() > 0.25) + { + mvaddstr(lines++,0,"You got away!"); + stat->scratch2 = RAN; + goto LEAVE; + } + mvprintw(lines++,0,"%s is still after you!",foename); + stat->scratch2 = STUCK; + break; + case '3': /* power blast */ + temp = min(stat->man,stat->lvl*5); + stat->man -= temp; + temp = (rnd() + 0.5) * temp * stat->mag * 0.2 + 2; + mvprintw(lines++,0,"You blasted %s !",foename); + goto HIT; + case '4': /* luckout */ + if (luckout || rnd() > 0.1) + { + luckout = TRUE; + mvaddstr(lines++,0,"Not this time..."); + --stat->scratch1; + stat->scratch2 = BLEWIT; + } + else + { + mvaddstr(lines++,0,"You just lucked out!"); + stat->scratch1 = foe->nrg + 5; + } + break; + } + refresh(); + stat->scratch1 = floor(stat->scratch1); /* clean up any mess */ + if (stat->scratch1 > foe->nrg) + stat->scratch2 = KILLED; + else if (rnd() * speed < rnd() * foespeed) + { /* foe's turn */ + ++stat->tampered; + updateme(); + goto WAIT; + } + updateme(); + + if (((int) stat->scratch2) == KILLED) + { + mvprintw(lines++,0,"You killed %s!",foename); + stat->exp += foe->exp; + stat->crn += (stat->lvl < 1000) ? foe->crn : 0; + stat->amu += foe->amu; + stat->chm += foe->chm; + stat->gld += foe->gld; + stat->gem += foe->gem; + stat->swd = max(stat->swd,foe->swd); + stat->shd = max(stat->shd,foe->shd); + stat->quks = max(stat->quks,foe->quks); + sleep(3); /* give other person time to die */ + goto LEAVE; + } + goto HITFOE; /* otherwise, my turn again */ + +/* routine to wait for foe to do something */ +WAIT: printstats(stat); + mvprintw(1,26,"%20.0f",myhits); + mvaddstr(4,0,"Waiting...\n"); + refresh(); + for (loop = MAXWAIT; loop; --loop) + { + readfoe(); + if (foe->scratch1 != oldhits) + switch ((int) foe->scratch2) + { + case RAN: + mvprintw(lines++,0,"%s ran away!",foename); + goto LEAVE; + case STUCK: + mvprintw(lines++,0,"%s tried to run away.",foename); + goto BOT; + case BLEWIT: + mvprintw(lines++,0,"%s tried to luckout!",foename); + goto BOT; + default: + temp = foe->scratch1 - oldhits; + mvprintw(lines++,0,"%s hit you %.0f times!",foename,temp); + myhits -= temp; + goto BOT; + } + sleep(1); + } + /* timeout */ + mvaddstr(23,0,"Timeout: waiting for response. Do you want to wait ? "); + refresh(); + ch = getch(); + move(23,0); + clrtoeol(); + if (toupper(ch) == 'Y') + goto WAIT; + goto LEAVE; + +/* routine to decide what happens next */ +BOT: refresh(); + if (lines > 21) + { + paws(lines); + move(lines = 5,0); + clrtobot(); + } + if (((int) foe->scratch2) == KILLED || myhits < 0.0) + { + myhits = -2; + goto LEAVE; /* main will pick up death */ + } + oldhits = foe->scratch1; + if (foe->tampered != oldtags) + { + oldtags = foe->tampered; + goto HITFOE; + } + goto WAIT; + +/* routine to clean up things and leave */ +LEAVE: updateme(); + fclose(fin); + fclose(fout); + stat->x += roll(5,-10); + stat->y += roll(5,-10); + stat->nrg = myhits; + stat->tampered = OFF; + stat->status = PLAYING; + changed = TRUE; + paws(lines); + move(3,0); + clrtobot(); +} + +void +checkinterm(stat) /* see if other person on same x,y */ + register struct stats *stat; +{ + FILE *fp; + struct stats sbuf; + register int foeloc = 0; + + users = 0; + fp = fopen(peoplefile,"r"); + while (fread((char *) &sbuf,sizeof(sbuf),1,fp)) + { + if (sbuf.status && (sbuf.status != CLOAKED || sbuf.typ != 99)) + { + ++users; + if (stat->x == sbuf.x && stat->y == sbuf.y + && foeloc != fileloc && sbuf.typ != 99 + && stat->typ !=99 && !stat->wormhole && !sbuf.wormhole) + { + fclose(fp); + interm(stat,foeloc); + return; + } + } + ++foeloc; + } + fclose(fp); +} + +int +gch(rngtyp) /* get a character from terminal, but check ring if crazy */ + int rngtyp; +{ + refresh(); + if (abs(rngtyp) != SPOILED) + return (getch()); + else + { + getch(); + return (roll(0,5) + '0'); + } +} + +int +rngcalc(chartyp) /* pick a duration of a ring */ + int chartyp; +{ + static int rngtab[] = { 0, 10, 20, 13, 25, 40, 20}; + + if (chartyp > 10) + chartyp -= 10; + return (rngtab[chartyp - 1]); +} + +void +interrupt(int sig) /* call when break key is hit */ +{ + char line[81]; + register int loop; + int x, y, ch; + +#ifdef USG3 + signal(SIGINT,SIG_IGN); +#endif +#ifdef USG5 + signal(SIGINT,SIG_IGN); +#endif + getyx(stdscr,y,x); + for (loop = 79; loop >= 0; --loop) /* snarf line */ + { + move(4,loop); + line[loop] = inch(); + } + line[80] = '\0'; + clrtoeol(); + if (fghting) + { + move(4,0); + clrtoeol(); + addstr("Quitting now will automatically kill your character. Still want to ? "); + ch = rgetch(); + if (toupper(ch) == 'Y') + longjmp(mainenv,DIE); + } + else + { + move(4,0); + clrtoeol(); + addstr("Do you really want to quit ? "); + ch = rgetch(); + if (toupper(ch) == 'Y') + longjmp(mainenv,QUIT); + } + mvaddstr(4,0,line); /* return screen to previous state */ + move(y,x); + refresh(); +#ifdef USG3 + signal(SIGINT,interrupt); +#endif +#ifdef USG5 + signal(SIGINT,interrupt); +#endif +} + +int +rgetch() /* refresh, then get a char. */ +{ + refresh(); + return (getch()); +} + +void +purge() /* remove old players */ +{ + FILE *fin, *fout; + struct stats sbuf; + register int loc, today, temp; + long ltime; + + loc = 0; + time(<ime); + today = localtime(<ime)->tm_yday; + fin = fopen(peoplefile,"r"); + fout = fopen(peoplefile,ACCESS); + while(fread((char *) &sbuf,sizeof(sbuf),1,fin)) + { + temp = today - sbuf.lastused; + if (temp < 0) + temp += 365; + if (temp > 9) /* ten days old --> delete */ + { + initchar(&sbuf); + strcpy(sbuf.name,""); + fseek(fout,(long) loc * sizeof(sbuf),0); + fwrite((char *) &sbuf,sizeof(sbuf),1,fout); + } + ++loc; + } + fclose(fin); + fclose(fout); +} diff --git a/src/games/phantasia/main.c b/src/games/phantasia/main.c new file mode 100644 index 0000000..373df32 --- /dev/null +++ b/src/games/phantasia/main.c @@ -0,0 +1,555 @@ +/* + * Phantasia 3.2 -- Interterminal fantasy game + * + * Edward A. Estes + * AT&T Teletype Corp., September 4, 1984 + */ + +/* + * This is the program which drives the whole mess. Hopefully, you will be + * able to wade throught the garbage if you have to fix something. + * several undocumented items exist. The program checks uid and sets the + * boolean flag 'su' (super user) if the person is allowed special powers. + * The 'su' may execute any of the valar/council options. Also, + * a 'vaporize' option exists to kill anybody at will. The 'su' can select + * character type 7, which starts out with the maximum possible in each + * category. (The resulting character is an experimento.) The 'su' may + * also change the stats of other characters with the -x option. + */ + +/* + * The program allocates as much file space as it needs to store characters, + * so the possibility exists for the character file to grow without bound. + * The file is purged upon normal entry to try to avoid that problem. + * A similar problem exists for energy voids. To alleviate the problem here, + * the void file is cleared with every new king. + */ + +/* + * The support functions are split between various files with no apparent + * order. Use of 'ctags' is recommended to find a particular function. + */ + +/* + * Put one line of text into the file 'motd' for announcements, etc. + */ + +/* + * If ENEMY is defined, a list of restricted login names is checked + * in the file 'enemy'. These names are listed, one per line, with + * no trailing blanks. + */ + +#include "phant.h" + +double strength, speed; +bool beyond, marsh, throne, valhala, changed, fghting, su, wmhl; +int fileloc, users; +jmp_buf fightenv, mainenv; +long secs; +/* + * worm hole map -- This table is carefully set up so that one can always + * return the way he/she came by inverting the initial path. + */ +struct worm_hole w_h[] = + { + 0,0,0,0, 35,22,2,0, 2,2,0,1, 59,34,64,0, + 54,47,0,60, 50,62,0,56, 19,31,25,0, 0,35,41,41, + 0,46,40,23, 24,0,29,30, 44,57,56,0, 0,44,39,40, + 61,41,0,42, 32,0,17,18, 57,0,63,64, 0,33,26,34, + 48,0,54,55, 28,23,22,13, 63,25,13,19, 34,6,18,20, + 27,26,19,21, 15,27,20,27, 1,28,34,17, 17,29,8,24, + 29,9,23,25, 18,30,24,6, 20,32,27,15, 21,20,21,26, + 22,17,46,29, 23,24,28,9, 25,38,9,31, 6,39,30,32, + 26,13,31,33, 15,40,32,35, 3,19,15,22, 7,1,33,36, + 37,37,35,37, 36,36,36,38, 30,42,37,39, 31,43,38,11, + 33,45,11,8, 12,48,7,7, 38,49,12,43, 39,51,42,44, + 11,10,43,45, 40,52,44,46, 8,53,45,28, 4,54,51,48, + 41,16,47,49, 42,55,48,50, 62,5,49,51, 43,56,50,47, + 45,58,53,53, 46,59,52,52, 47,4,55,16, 49,61,16,54, + 51,63,5,10, 10,14,59,58, 52,64,57,59, 53,3,58,57, + 60,60,4,61, 55,12,60,62, 5,50,61,63, 56,18,62,14, + 58,33,14,3 + }; + +int +main(argc,argv) /* Phantasia main routine */ + int argc; + char *argv[]; +{ + struct stats charac; + char aline[200], *login = NULL; + double x = 0.0, y = 0.0; + int ch, ch2; + register int loop, temp; + FILE *fp; + bool shrt = FALSE, examine = FALSE, header = FALSE; + + login = getlogin(); + if (! login) + login = getpwuid(getuid())->pw_name; +#ifdef ENEMY + /* check hit list of restricted accounts */ + if ((fp = fopen(enemyfile, "r")) != NULL) + { + char enemy[20]; + + while (fscanf(fp, "%s", enemy) != EOF) + if (!strcmp(login,enemy)) + { + printf ("The Phantasia privileges for the account \"%s\" have been revoked.\n", login); + printf ("Mail comments to %s.\n", WIZARD); + exit (0); + } + fclose (fp); + } +#endif + setbuf(stdin, (char *) NULL); /* this may or may not be necessary */ + su = (getuid() == UID); + fghting = FALSE; + users = 0; + if (argc > 1 && (*++argv)[0] == '-') + switch ((*argv)[1]) + { + case 'h': /* help */ + printhelp(); + exit(0); + /*NOTREACHED*/ + case 's': /* short */ + shrt = TRUE; + break; + case 'x': /* examine */ + examine = TRUE; + break; + case 'H': /* Header */ + header = TRUE; + break; + case 'm': /* monsters */ + printmonster(); + exit(0); + /*NOTREACHED*/ + case 'a': /* all users */ + showusers(); + exit(0); + /*NOTREACHED*/ + case 'p': /* purge old players */ + purge(); + exit(0); + /*NOTREACHED*/ + } + if (!isatty(0)) /* don't let non-tty's play */ + exit(0); + init1(); /* set up for screen stuff */ + if (examine) + { + cstat(); + exit1(); + /*NOTREACHED*/ + } + if (!shrt) + { + titlestuff(); + purge(); /* clean up old characters */ + } + if (header) + { + exit1(); + /*NOTREACHED*/ + } +#ifdef OK_TO_PLAY + if (!ok_to_play()) + { + mvaddstr(23,27,"Sorry, you can't play now.\n"); + exit1(); + /*NOTREACHED*/ + } +#endif + mvaddstr(23,24,"Do you have a character to run? "); + ch = rgetch(); + if (toupper(ch) == 'Y') + fileloc = findchar(&charac); + else + { + initchar(&charac); + clear(); + mvaddstr(5,21,"Which type of character do you want:"); + mvaddstr(10,4,"1:Magic User 2:Fighter 3:Elf 4:Dwarf 5:Halfling 6:Experimento ? "); + ch = rgetch(); + do + { + genchar(&charac,ch); + mvprintw(15,14,"Strength: %2.0f Manna : %3.0f Quickness : %2d", + charac.str,charac.man,charac.quk); + mvprintw(16,14,"Brains : %2.0f Magic Level: %2.0f Energy Level: %2.0f", + charac.brn,charac.mag,charac.nrg); + if (charac.typ != 6) + { + mvaddstr(17,14,"Type '1' to keep >"); + ch2 = rgetch(); + } + else + break; + } + while (ch2 != '1'); + if (charac.typ == 6) + { + mvaddstr(19,0,"Enter the X Y coordinates of your experimento ? "); + getstring(aline,80); + sscanf(aline,"%lf %lf",&x,&y); + charac.x = (abs(x) > 1.2e+6) ? sgn(x)*1.2e+6 : floor(x); + charac.y = (abs(y) > 1.2e+6) ? sgn(y)*1.2e+6 : floor(y); + } + do + { + mvaddstr(20,0,"Give your character a name [up to 20 characters] ? "); + getstring(aline,80); + strncpy(charac.name,aline,20); + charac.name[20] = '\0'; + } + while (findname(charac.name)); + putchar('\n'); + fflush(stdout); + nocrmode(); + do + { + strcpy(charac.pswd,getpass("Give your character a password [up to 8 characters] ? ")); + putchar('\n'); + strcpy(aline,getpass("One more time to verify ? ")); + } + while (strcmp(charac.pswd,aline)); + fileloc = findspace(); + } + crmode(); + if (charac.status) + { + clear(); + addstr("Your character did not exit normally last time.\n"); + addstr("If you think you have good cause to have you character saved,\n"); + printw("you may quit and mail your reason to '%s'.\n",WIZARD); + addstr("Do you want to quit ? "); + ch = rgetch(); + if (toupper(ch) == 'Y') + { + charac.quk = -100; + leave(&charac); + /*NOTREACHED*/ + } + death(&charac); + } + charac.status = PLAYING; + strcpy(charac.login,login); + time(&secs); + charac.lastused = localtime(&secs)->tm_yday; + update(&charac,fileloc); + clear(); + signal(SIGINT,interrupt); + +/* all set for now */ + +TOP: switch (setjmp(mainenv)) + { + case QUIT: + signal(SIGINT,interrupt); + leave(&charac); + /*NOTREACHED*/ + case DIE: + signal(SIGINT,interrupt); + death(&charac); + break; + } +#ifdef OK_TO_PLAY + if (!ok_to_play()) + { + mvaddstr(6,0,"Whoops! Can't play now.\n"); + leave(&charac); + /*NOTREACHED*/ + } +#endif + fghting = FALSE; + adjuststats(&charac); + if (throne && !charac.crn && (charac.typ < 10 || charac.typ > 20)) + { + mvaddstr(6,0,"You're not allowed in the Lord's Chamber without a crown.\n"); + changed = TRUE; + charac.x = charac.y = 10; + } + if (charac.status != CLOAKED && abs(charac.x) == abs(charac.y) + && floor(sqrt(fabs(charac.x/100.0))) == sqrt(fabs(charac.x/100.0)) && !throne) + { + trade(&charac); + clear(); + } + checktampered(&charac); + checkinterm(&charac); + if (charac.nrg < 0 || (charac.lvl >= 10000 && charac.typ != 99)) + death(&charac); + neatstuff(&charac); + if (changed) + { + update(&charac,fileloc); + changed = FALSE; + goto TOP; + } + move(5,0); + clrtoeol(); + fp = fopen(messfile,"r"); + if (fgets(aline,160,fp)) + addstr(aline); + fclose(fp); + printstats(&charac); + move(3,0); + clrtoeol(); + if (!wmhl) + { + if (throne) + kingstuff(&charac); + addstr("1:Move 2:Players 3:Talk 4:Stats 5:Quit "); + if (charac.lvl >= 5 && charac.mag >= 15) + addstr("6:Cloak "); + if (charac.lvl >= 10 && charac.mag >= 25) + addstr("7:Teleport "); + if (charac.typ > 20) + addstr("8:Intervention"); + ch = gch(charac.rng.type); + clrtoeol(); + move(6,0); + clrtobot(); + if (charac.typ == 99 && (ch == '1' || ch == '7')) + ch = ' '; + switch (ch2 = toupper(ch)) + { + case 'N': + charac.y += maxmove; + break; + case 'S': + charac.y -= maxmove; + break; + case 'E': + charac.x += maxmove; + break; + case 'W': + charac.x -= maxmove; + break; + default: /* rest */ + if (charac.status == CLOAKED) + if (charac.man > 3.0) + charac.man -= 3; + else + { + charac.status = PLAYING; + changed = TRUE; + } + else + { + charac.man += circ(charac.x,charac.y)/3+0.5; + charac.man += charac.lvl/5+0.5; + } + rndattack(); + break; + case '1': /* move */ + for (loop = 3; loop; --loop) + { + mvaddstr(5,0,"X Y Coordinates ? "); + getstring(aline,80); + if (sscanf(aline,"%lf %lf",&x,&y) < 2) + ; + else + if (hypot((double) charac.x - x, (double) charac.y - y) > maxmove) + illmove(); + else + { + charac.x = x; + charac.y = y; + break; + } + } + break; + case '2': /* players */ + printplayers(&charac); + break; + case '3': /* message */ + talk(charac.name); + break; + case '4': /* stats */ + showall(&charac); + break; + case '5': /* good-bye */ + leave(&charac); + /*NOTREACHED*/ + case '6': /* cloak */ + if (charac.lvl < 5 || charac.mag < 15) + illcmd(); + else if (charac.status == CLOAKED) + charac.status = PLAYING; + else if (charac.man < 35) + { + mvaddstr(6,0,"No power left.\n"); + refresh(); + } + else + { + changed = TRUE; + charac.man -= 35; + charac.status = CLOAKED; + } + break; + case '7': /* teleport */ + if (charac.lvl < 10 || charac.mag < 25) + illcmd(); + else + for (loop = 3; loop; --loop) + { + mvaddstr(5,0,"X Y Coordinates ? "); + getstring(aline,80); + if (sscanf(aline,"%lf %lf",&x,&y) == 2) + if ((temp = hypot(charac.x-x,charac.y-y)) + > (charac.lvl+charac.mag)*5+((charac.typ > 20) ? 1e+6 : 0) + && !throne) + illmove(); + else if ((temp = (temp/75+1)*20) > charac.man && !throne) + mvaddstr(6,0,"Not enough power for that distance.\n"); + else + { + charac.x = x; + charac.y = y; + if (!throne) + charac.man -= temp; + break; + } + } + break; + case '9': /* monster */ + if (throne) + mvaddstr(6,0,"No monsters in the chamber!\n"); + else if (charac.typ != 99) + { + charac.status = PLAYING; + changed = TRUE; + charac.sin += 1e-6; + fight(&charac,-1); + } + break; + case '0': /* decree */ + if (su || charac.typ > 10 && charac.typ < 20 && throne) + decree(&charac); + else + illcmd(); + break; + case '8': /* intervention */ + if (su || charac.typ > 20) + valarstuff(&charac); + else + illcmd(); + break; + case '\014': /* redo screen */ + clear(); + } + if (ch2 == 'E' || ch2 == 'W' || ch2 == 'N' || ch2 == 'S' + || ch2 == '1' || ch2 == '7') + { + checkmov(&charac); + rndattack(); + changed = TRUE; + } + } + else + { + addstr("F:Forward B:Back R:Right L:Left Q:Quit T:Talk P:Players S:Stats "); + ch = rgetch(); + move(6,0); + clrtobot(); + switch (toupper(ch)) + { + default: + if (charac.status == CLOAKED) + if (charac.man > 3.0) + charac.man -= 3; + else + { + charac.status = PLAYING; + changed = TRUE; + } + else + charac.man += charac.lvl/5+0.5; + break; + case 'F': + temp = (int) w_h[charac.wormhole].f; + goto CHKMOVE; + case 'B': + temp = (int) w_h[charac.wormhole].b; + goto CHKMOVE; + case 'R': + temp = (int) w_h[charac.wormhole].r; + goto CHKMOVE; + case 'L': + temp = (int) w_h[charac.wormhole].l; + goto CHKMOVE; + case 'Q': + leave(&charac); + /*NOTREACHED*/ + case 'T': + talk(charac.name); + break; + case 'P': + printplayers(&charac); + break; + case 'S': + showall(&charac); + break; + case '\014': /* redo screen */ + clear(); + } + goto TOP; +CHKMOVE: if (!temp) + { + charac.y = 0.0; + charac.x = pow(-1.0,(double) charac.wormhole) * charac.wormhole * 400 - 1.0; + charac.wormhole = 0; + changed = TRUE; + } + else + charac.wormhole = temp; + } + goto TOP; +} + +/* + * This function is provided to allow one to restrict access to the game. + * Tailor this routine as appropriate. + */ + +#ifdef OK_TO_PLAY +#include +#include /* used for counting users on system */ + +bool ok_to_play() /* return FALSE if playing is not allowed at this time */ +{ +#define MAXUSERS 8 /* max. number of people on system */ + register struct tm *tp; + register int numusers = 0; + FILE *fp; + long now; + struct utmp ubuf; + + if (su) + return (TRUE); + /* check time of day */ + time(&now); + if (((tp = localtime(&now))->tm_hour > 8 && tp->tm_hour < 12) /* 8-noon */ + || (tp->tm_hour > 13 && tp->tm_hour < 16)) /* 1-4 pm */ + return (FALSE); + /* check # of users */ + fp = fopen(_PATH_UTMP,"r"); + while (fread((char *) &ubuf,sizeof(ubuf),1,fp)) +#ifdef USG5 + if (ubuf.ut_type == USER_PROCESS) +#else + if (*ubuf.ut_name) +#endif + ++numusers; + fclose(fp); + if (numusers > MAXUSERS) + return (FALSE); + return (TRUE); +} +#endif diff --git a/src/games/phantasia/monsters b/src/games/phantasia/monsters new file mode 100644 index 0000000..778e211 --- /dev/null +++ b/src/games/phantasia/monsters @@ -0,0 +1,99 @@ +a Water Leaper 12 14 16 24 59 0 0 62 +a Leech 4 19 29 30 66 0 0 73 +a Urisk 13 30 15 46 127 1 0 3 +Shellycoat 28 21 18 63 226 2 0 0 +a Naiad 21 62 27 58 378 2 0 11 +a Nixie 22 58 28 108 604 3 0 6 +a Glaistig 21 106 25 127 1002 3 0 0 +a Mermaid 18 116 22 108 809 3 0 0 +a Merman 24 115 23 109 808 4 0 0 +a Siren 22 128 31 89 915 4 0 24 +a Lamprey 14 67 33 156 1562 4 15 37 +a Kopoacinth 26 36 26 206 2006 5 0 20 +a Kelpie 61 25 24 223 4025 5 0 0 +an Aspidchelone 114 104 19 898 10041 7 0 2 +an Idiot 13 14 16 28 49 0 0 0 +some Green Slime 1 5 45 100 57 0 0 26 +a Pixie 11 29 23 26 64 0 0 32 +a Serpent 10 18 25 25 79 0 0 10 +a Cluricaun 12 27 20 30 81 0 14 5 +an Imp 22 30 14 40 92 0 0 1 +a Centipede 3 8 18 15 33 0 0 61 +a Beetle 2 11 21 26 44 0 0 48 +a Fir Darrig 18 22 17 35 107 0 14 1 +Modnar 15 23 20 40 101 7 2 12 +a Gnome 7 45 26 23 111 0 0 21 +a Sprite 9 37 25 31 132 1 0 43 +a Mimic 11 55 29 47 213 1 3 2 +a Kobold 13 10 14 21 121 1 12 68 +a Spider 6 11 28 28 124 1 0 57 +an Uldra 14 37 21 32 93 1 0 6 +a Gnoll 20 25 15 40 166 1 0 61 +a Bogie 23 28 19 57 189 1 0 57 +a Fachan 9 40 15 45 139 1 14 10 +a Moron 3 1 10 10 28 0 0 100 +an Orc 25 13 16 26 141 1 0 92 +a Ghillie Dhu 12 16 13 28 104 2 14 2 +a Bogle 19 15 16 35 157 2 14 15 +a Shrieker 2 62 27 9 213 2 16 0 +a Carrion Crawler 12 20 20 65 142 2 0 42 +a Trow 15 17 23 51 136 2 0 36 +a Warg 20 10 17 45 152 2 0 88 +a Stirge 2 6 35 25 153 2 0 95 +a Crebain 5 11 31 31 82 2 0 81 +a Killmoulis 30 19 8 75 175 3 14 22 +a Hob-goblin 35 20 15 72 246 3 0 18 +a Unicorn 27 57 27 57 627 3 1 0 +a Fenoderee 16 6 21 65 222 3 0 42 +an Ogre 42 14 16 115 409 3 0 19 +a Dodo 62 12 11 76 563 3 0 3 +a Hydra 14 27 33 99 599 3 0 27 +a Hamadryad 23 47 26 62 426 3 0 12 +a Bwca 21 17 19 55 387 3 14 1 +an Owlbear 35 16 18 100 623 4 0 22 +Black Annis 37 52 15 65 786 4 0 2 +a Jello Blob 45 23 12 114 1191 4 0 0 +a Wichtlein 13 40 25 61 800 4 0 8 +a Cocodrill 39 28 24 206 1438 4 0 38 +a Troll 75 12 20 185 1013 4 24 29 +a Bonnacon 89 26 9 255 1661 4 17 14 +a Gargoyle 22 21 29 200 1753 5 0 7 +a Chaladrius 8 49 37 172 1929 5 0 20 +a Gwyllion 27 73 20 65 1888 5 0 4 +a Cinomulgus 23 2 10 199 263 5 0 18 +a Peridexion 26 32 24 98 1300 5 0 2 +Smeagol 41 33 27 373 2487 5 18 0 +a Wraith 52 102 22 200 3112 5 25 13 +a Snotgurgle 143 19 26 525 4752 6 0 3 +a Phooka 42 63 21 300 4125 5 0 12 +a Vortex 101 30 31 500 6992 6 9 4 +Shelob 147 64 28 628 5003 7 13 0 +a Thaumaturgist 35 200 23 400 7628 6 7 0 +Smaug 251 76 26 1022 9877 7 0 0 +a Cold-drake 301 102 24 1222 10888 7 0 0 +a Red Dragon 342 141 23 1299 11649 8 0 0 +Scatha the Worm 406 208 20 1790 11999 8 0 0 +Tiamat 506 381 29 2000 13001 9 11 0 +a Bandersnatch 105 98 22 450 7981 6 0 3 +a Harpy 103 49 24 263 7582 6 0 2 +a Tigris 182 38 17 809 7777 6 0 3 +a Gryphon 201 45 19 813 8888 7 0 1 +a Coblynau 205 46 18 585 8333 6 0 2 +a Chimaera 173 109 28 947 12006 7 0 0 +a Jack-in-Irons 222 36 12 1000 9119 7 0 0 +Saruman 55 373 17 1500 17101 11 6 0 +a Balrog 500 100 25 705 8103 7 8 0 +Argus 201 87 14 1500 10010 8 0 0 +a Titan 302 1483 12 1625 11011 8 0 0 +Cacus 256 43 19 1750 12012 8 0 0 +Begion 403 154 10 1875 13013 8 0 0 +Grendel 197 262 23 2000 14014 8 0 0 +a Nazgul 250 251 26 1011 9988 12 10 9 +a Succubus 186 1049 27 2007 19984 9 19 0 +Red Cap 143 50 35 1965 23456 9 0 0 +a Nuckelavee 300 75 20 2185 11111 8 0 0 +Cerberus 236 96 29 2600 25862 9 20 0 +a Jabberwock 185 136 25 2265 23256 9 22 0 +Ungoliant 399 2398 37 2784 27849 10 21 0 +Leanan-Sidhe 486 5432 46 3000 30004 9 5 0 +the Dark Lord 9999 9999 31 19999 30005 13 4 0 diff --git a/src/games/phantasia/phant.h b/src/games/phantasia/phant.h new file mode 100644 index 0000000..284372c --- /dev/null +++ b/src/games/phantasia/phant.h @@ -0,0 +1,162 @@ +/* + * phant.h Include file for Phantasia + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* ring constants */ +#define NONE 0 +#define NAZBAD 1 +#define NAZREG 2 +#define DLREG 3 +#define DLBAD 4 +#define SPOILED 5 + +/* some functions and pseudo-functions */ +#define toupper(CH) ((CH) > 96 ? (CH) ^ 32 : (CH)) /* may be upper or lower */ +#define tolower(CH) ((CH) | 32) /* must be upper */ +#define rnd() (((double) rand()) / RAND) +#define roll(BASE,INTERVAL) floor((BASE) + (INTERVAL) * rnd()) +#define sgn(x) (-(x < 0) + (x > 0)) +#define abs(x) ((x) < 0 ? -(x) : (x)) +#define circ(x,y) floor(sqrt((double) ((x) * (x) + (y) * (y))) / 125 + 1) +#define max(A,B) ((A) > (B) ? (A) : (B)) +#define min(A,B) ((A) < (B) ? (A) : (B)) +#define valarstuff(ARG) decree(ARG) +#define illcmd() mvaddstr(6,0,"Illegal command.\n") +#define maxmove floor(charac.lvl * 1.5 + 1) +#define illmove() mvaddstr(6,0,"Too far.\n") +#define rndattack() if (rnd() < 0.2 && charac.status == PLAYING && !throne) \ + fight(&charac,-1) +#define strcalc(STR,SICK) max(0,min(0.9 * STR, SICK * STR/20)) +#define spdcalc(LVL,GLD,GEM) max(0,((GLD + GEM/2) - 1000)/200.0 - LVL) +#define illspell() mvaddstr(6,0,"Illegal spell.\n") +#define nomanna() mvaddstr(6,0,"Not enough manna for that spell.\n") +#define somebetter() addstr("But you already have something better.\n") + +/* status constants */ +#define OFF 0 +#define PLAYING 1 +#define CLOAKED 2 +#define INBATTLE 3 +#define DIE 4 +#define QUIT 5 + +/* tampered constants */ +#define NRGVOID 1 +#define GRAIL 2 +#define TRANSPORT 3 +#define GOLD 4 +#define CURSED 5 +#define MONSTER 6 +#define BLESS 7 +#define MOVED 8 +#define HEAL 9 +#define VAPORIZED 10 +#define STOLEN 11 + +/* structure definitions */ +struct stats /* player stats */ + { + char name[21]; /* name */ + char pswd[9]; /* password */ + char login[10]; /* login */ + double x; /* x coord */ + double y; /* y coord */ + double exp; /* experience */ + int lvl; /* level */ + short quk; /* quick */ + double str; /* strength */ + double sin; /* sin */ + double man; /* manna */ + double gld; /* gold */ + double nrg; /* energy */ + double mxn; /* max. energy */ + double mag; /* magic level */ + double brn; /* brains */ + short crn; /* crowns */ + struct + { + short type; + short duration; + } rng; /* ring stuff */ + bool pal; /* palantir */ + double psn; /* poison */ + short hw; /* holy water */ + short amu; /* amulets */ + bool bls; /* blessing */ + short chm; /* charms */ + double gem; /* gems */ + short quks; /* quicksilver */ + double swd; /* sword */ + double shd; /* shield */ + short typ; /* character type */ + bool vrg; /* virgin */ + short lastused; /* day of year last used */ + short status; /* playing, cloaked, etc. */ + short tampered; /* decree'd, etc. flag */ + double scratch1, scratch2; /* var's for above */ + bool blind; /* blindness */ + int wormhole; /* # of wormhole, 0 = none */ + long age; /* age in seconds */ + short degen; /* age/2500 last degenerated */ + }; + +struct mstats /* monster stats */ + { + char name[26]; /* name */ + double str; /* strength */ + double brn; /* brains */ + double spd; /* speed */ + double hit; /* hits (energy) */ + double exp; /* experience */ + int trs; /* treasure type */ + int typ; /* special type */ + int flk; /* % flock */ + }; + +struct nrgvoid /* energy void */ + { + bool active; /* active or not */ + double x,y; /* coordinates */ + }; + +struct worm_hole /* worm hole */ + { + char f, b, l, r; /* forward, back, left, right */ + }; + +/* files */ +#define monsterfile PATH"/monsters" +#define peoplefile PATH"/characs" +#define gameprog PATH"/phantasia" +#define messfile PATH"/mess" +#define lastdead PATH"/lastdead" +#define helpfile PATH"/phant.help" +#define motd PATH"/motd" +#define goldfile PATH"/gold" +#define voidfile PATH"/void" +#define enemyfile PATH"/enemy" + +extern jmp_buf fightenv, mainenv; +extern double strength, speed; +extern bool beyond, marsh, throne, valhala, changed, fghting, su, wmhl; +extern struct worm_hole w_h[]; +extern long secs; +extern int fileloc, users; + +void interrupt(int sig); +void strunc(char *str); +void update(struct stats *stat, int place); +void exit1(void); +void getstring(char *cp, int mx); +void paws(int where); + +double inflt(void); diff --git a/src/games/phantasia/phant.nr b/src/games/phantasia/phant.nr new file mode 100644 index 0000000..a28d457 --- /dev/null +++ b/src/games/phantasia/phant.nr @@ -0,0 +1,1184 @@ +.de sh +.br +.ne 5 +.PP +\fB\\$1\fR +.PP +.. +.TH PHANTASIA 6 GAMES +.UC 4 +.SH NAME +phantasia \- an interterminal fantasy game +.SH SYNOPSIS +.B phantasia +[ +.B \-s +] [ +.B \-m +] [ +.B \-a +] [ +.B \-x +] [ +.B \-h +] [ +.B \-H +] [ +.B \-p +] +.SH DESCRIPTION +.I Phantasia +is a role playing game vaguely similar to dungeons and dragons. +It allows players to roll up characters of various types to fight +monsters and other players. +Progression of characters is based upon gaining experience from fighting +monsters (and other players). +.PP +Most of the game is menu driven and self-explanatory (more or less). +The screen is cursor updated, so be sure to set up the +.B TERM +variable in your environment. +.PP +The options provide for a variety of functions to support the game. +They are: +.PP +.TP .5i +.B \-s +Invokes +.I phantasia +without header information. +.TP .5i +.B \-m +Get a monster listing. +.TP .5i +.B \-a +Get a listing of all character names on file. +.TP .5i +.B \-x +Examine/change a particular character on file. +.TP .5i +.B \-h +Get a help listing (this message). +.TP .5i +.B \-H +Get header listing only. +.TP .5i +.B \-p +Purge old characters. +.PP +The characters are saved on a common file, in order to make the game +interactive between players. The characters are given a password +in order to retrieve them later. Only characters above +.B level +zero are saved. Characters unused for more than nine days will be +purged. +.SH AUTHOR +Edward Estes, AT&T Teletype Corp. +.SH PARTICULARS +.sh "Playing in General" +Certain of the player's more important statistics are almost always +displyed on the screen, with maximums (where applicable) in +parentheses. +.PP +The character is placed randomly near the center of a cartesian +system. One may move by hitting +.B E, W, N, +or +.B S +(lower case may also be used, at no time is the game case dependent). +To move to a particular (x,y) coordinate, use the +.B move +('1') command. The distance a character can move is calculated by +1 plus 1.5 per +.B level. +Moving in a particular compass direction will move the player the maximum +allowed distance in that direction. +.PP +A player may at any time see who else is playing with a +.B players +('2') option. One may see only those who are the same distance or closer +to the origin as he/she. +.B Kings, +and +.B council of the wise +can see and can be seen by everyone. A +.B palantir +removes these retrictions. +.PP +One can talk to other players with the +.B talk +('3') option. In general, this is a line or so of text. To remove a current +message, just type when prompted for a message. +.PP +The +.B stats +('4') option shows a players characteristics in more detail. +.PP +One may leave the game either with the +.B quit +('5') option, or by hitting interrupt. Quitting during battle results +in death for obvious reasons. +.PP +One may rest by default. Resting lets one regain maximum +.B energy level, +and also lets one find +.B manna +(more is found for larger levels and further distances from the origin). +.PP +One may call a monster by hitting '9'. +.PP +Several other options become available as the player progress in +.B level +and +.B magic, +or to other positions in the game ( +.B valar, council of the wise, king +). +These are described elsewhere. +In general, a control-L will force the redrawing of the screen. +.PP +Other things which may happen are more or less self-explanatory. +.sh "Fighting Monsters" +A player has several options while fighting monsters. They are as follows: +.TP 1.5i +.B melee +Inflicts damage on the monster, based upon +.B strength. +Also decreases the monster's +.B strength +some. +.TP 1.5i +.B skirmish +Inflicts a little less damage than +.B melee, +but decreases the monster's +.B quickness +instead. +.TP 1.5i +.B evade +Attempt to run away. Success is based upon both the player's and +the monster's +.B brains +and +.B quickness. +.TP 1.5i +.B spell +Several options for throwing spells (described elsewhere). +.TP 1.5i +.B nick +Hits the monster one plus the player's +.B sword, +and gives the player 10% of the monster's +.B experience. +Decreases the monster's +.B experience +an amount proportional to the amount granted. +This also increases the monster's quickness. +Paralyzed monsters wake up very fast when nicked. +.TP 1.5i +.B luckout +This is essentially a battle of wits with the monster. Success is based +upon the player's and the monster's +.B brains. +The player gets credit for slaying the monster if he/she succeeds. +Otherwise, nothing happens, and the chance to +.B luckout +is lost. +.sh "Character Statistics" +.TP 1.5i +.B strength +determines how much damage a character can inflict. +.TP 1.5i +.B quickness +determines how many chances a character gets to make decisions while +fighting. +.TP 1.5i +.B energy level +specifies how much damage a character may endure before dying. +.TP 1.5i +.B magic level +determines which spells a character may throw, and how effective those +spells will be. +.TP 1.5i +.B brains +basically, the character's intelligence; used for various fighting options +and spells. +.TP 1.5i +.B manna +used as a power source for throwing spells. +.TP 1.5i +.B experience +gained by fighting monsters and other characters. +.TP 1.5i +.B level +indicative of how much experience a character has accumulated; progresses +geometrically as +.B experience +increases. +.TP 1.5i +.B poison +sickness which degrades a character's performance (affects +.B energy level +and +.B strength +). +.TP 1.5i +.B sin +accumulated as a character does certain nasty things; used only rarely +in normal play of the game. +.TP 1.5i +.B age +number of seconds of playing time for the character. +As +.B age +increases, many personal statistics degenerate. +.sh "Character Types" +Character statistics are rolled randomly from the above list, according +to character type. The types are as follows: +.TP 1.5i +.B magic user +strong in +.B magic level +and +.B brains +, weak in other areas. Must rely on wits and magic to survive. +.TP 1.5i +.B fighter +good in +.B strength +and +.B energy level +, fairly good in other areas. This adds up to a well-equipped fighter. +.TP 1.5i +.B elf +very high +.B quickness +and above average +.B magic level +are +.B elves +selling points. +.TP 1.5i +.B dwarf +very high +.B strength +and +.B energy level +, but with a tendency to be rather slow and not too bright. +.TP 1.5i +.B halfling +rather quick and smart, with high +.B energy level +, but poor in +.B magic +and +.B strength. +Born with some +.B experience. +.TP 1.5i +.B experimento +very mediocre in all areas. However, the +.B experimento +may be placed almost anywhere within the playing grid. +.PP +The possible ranges for starting statistics are summarized in +the following table. +.PP +.TS +l c c c c c c +l c c c c c c. +Type Strength Quick Manna Energy Brains Magic +_ +Mag. User 20-25 30-35 50-100 30-45 60-85 5-9 +Fighter 40-55 30-35 30-50 45-70 25-45 3-6 +Elf 35-45 28-38 45-90 30-50 40-65 4-7 +Dwarf 50-70 25-30 25-45 60-100 20-40 2-5 +Halfling 20-25 34 25-45 55-90 40-75 1-4 +Experimento 25 27 100 35 25 2 +.TE +.PP +Not only are the starting characteristics different for the different +character types, the characteristics progress at different rates for the +different types as the character goes up in +.B level. Experimentoes' +characteristics progress randomly as one of the other types. +The progression as characters increase in +.B level +is summarized in the following table. +.PP +.TS +l c c c c c +l n n n n n. +Type Strength Manna Energy Brains Magic +_ +Mag. User 2.0 75 20 6 2.75 +Fighter 3.0 40 30 3.0 1.5 +Elf 2.5 65 25 4.0 2.0 +Dwarf 5 30 35 2.5 1 +Halfling 2.0 30 30 4.5 1 +.TE +.PP +Character types are identified by certain numeric values as follows: +.br +1: +.B Magic User +2: +.B Fighter +3: +.B Elf +4: +.B Dwarf +5: +.B Halfling +6: +.B Experimento +.PP +Characters with one or more +.B crowns +are designated as a negative type. +.B Kings +have ten added to their type; members of the +.B council of the wise +have twenty added to their type. +.B Valar +are type 99, and +.B ex-valar +are type 90. +.sh "Spells" +During the course of the game, the player may exercise his/her particular +magic powers. These cases are described below. +.TP 1.5i +.B cloak +.I magic level necessary: +15 (plus level 5) +.br +.I manna used: +35 plus 3 per rest period +.br +Used during normal play. Prevents monsters from finding the character, +as well as hiding the player from other players. His/her coordinates +show up as '?' in the +.B players +option. Players cannot collect +.B manna, +find trading posts, or discover the +.B grail +while cloaked. Calling a monster uncloaks, as well as choosing +this option while cloaked. +.br +.TP 1.5i +.B teleport +.I magic level necessary: +25 (plus level 10) +.br +.I manna used: +20 per 75 moved +.br +Used during normal play. Allows the player too move with much more freedom +than with the +.B move +option, at the price of expending manna. The maximum distance possible +to move is based upon +.B level +and +.B magic level. +.TP 1.5i +.B power blast +.I magic level necessary: +none +.br +.I manna used: +5 times +.B level +.br +Used during inter-terminal battle. Damage is based upon +.B magic level +and +.B strength. +Hits much harder than a normal hit. +.TP 1.5i +.B all or nothing +.I magic level necessary: +none +.br +.I manna used: +1 +.br +Used while combatting monsters. +Has a 25% chance of working. If it works it hits the monster just enough +to kill it. If it fails, it doesn't hit the monster, and doubles the +monster's +.B quickness +and +.B strength. +Paralyzed monsters wake up much quicker as a result of this spell. +.TP 1.5i +.B magic bolt +.I magic level necessary: +3 +.br +.I manna used: +variable +.br +Used while combatting monsters. Hits the monster based upon the amount +of +.B manna +expended and +.B magic level. +Guaranteed to hit at least 10 per +.B manna. +.TP 1.5i +.B force field +.I magic level necessary: +7 +.br +.I manna used: +20 +.br +Used during monster combat. Throws up a shield to protect from damage. +The shield is added to actual energy level, and is a fixed number, based +upon maximum energy. Normally, damage occurs first to the shield, and +then to the players actual +.B energy level. +.TP 1.5i +.B transform +.I magic level necessary: +10 +.br +.I manna used: +35 +.br +Used during monster combat. Transforms the monster randomly into one +of the other 100 monsters from the monster file. +.TP 1.5i +.B increase might +.I magic level necessary: +15 +.br +.I manna used: +55 +.br +Used during combat with monsters. Increases strength up to a certain maximum. +.TP 1.5i +.B invisibility +.I magic level necessary: +20 +.br +.I manna used: +45 +.br +Used while fighting monsters. Makes it harder for the monster to hit, +by temporarily increasing the player's +.B quickness. +This spell may be thrown several times, but a maximum level will be reached. +.TP 1.5i +.B transport +.I magic level necessary: +25 +.br +.I manna used: +50 +.br +Used during monster combat. Transports the monster away from the +player. Success is base upon player's +.B magic +and +.B brains, +and the monster's +.B experience. +If it fails the player is transported instead. 60% of the time, the monster +will drop any treasure it was carrying. +.TP 1.5i +.B paralyze +.I magic level necessary: +30 +.br +.I manna used: +60 +.br +Used during monster combat. "Freezes" the monster by putting its +.B quickness +slightly negative. The monster will slowly wake up. Success is based +upon player's +.B magic +and the monster's +.B experience. +If it fails, nothing happens. +.TP 1.5i +.B specify +.I magic level necessary: +none +.br +.I manna used: +1000 +.br +Used during monster combat only by +.B valar +or +.B council of the wise. +Allows the player to pick which monster to fight. +.sh "Monsters" +Monsters get bigger as one moves farther from the origin (0,0). Rings of +distance 125 from the origin determine the size. A monster's +.B experience, energy level, +and +.B brains +are multiplied by the size. +.B Strength +is increase 50% per size over one, and +.B quickness +remains the same, regardless of size. +.PP +Also, meaner monsters are to be found as one progress farther out +from the origin. Monsters also may flock. The percent chance of that +happening is designated as +.B flock% +in the monster listing. Monsters outside the first ring +may carry treasure, as determined by their treasure type. +Flocking monsters, and bigger monsters increase the chances of treasure. +.PP +Certain monsters have special abilities; they are as follows: +.TP 1.5i +.B Unicorn +can only be subdued if the player is in possession of a +.B virgin. +.TP 1.5i +.B Modnar +has random characteristics, including treasure type. +.TP 1.5i +.B Mimic +will pick another name from the list of monsters in order to +confuse. +.TP 1.5i +.B Dark Lord +very nasty person. Does not like to be hit (especially nicked), +and many spells do not work well against him. +One can always +.B evade +from the +.B Dark Lord. +.TP 1.5i +.B Leanan-Sidhe +also a very nasty person. She will permanently sap +.B strength +from someone. +.TP 1.5i +.B Saruman +wanders around with +.B Wormtongue +, who can steal a +.B palantir. +Also, +.B Saruman +may turn a player's gems into gold pieces, +or scramble her/his stats. +.TP 1.5i +.B Thaumaturgist +can transport a player. +.TP 1.5i +.B Balrog +inflicts damage by taking away +.B experience +, not +.B energy. +.TP 1.5i +.B Vortex +may take some +.B manna. +.TP 1.5i +.B Nazgul +may try to steal a +.B ring +or neutralize part of one's +.B brains. +.TP 1.5i +.B Tiamat +may take half a players +.B gold +and +.B gems +and escape. +.TP 1.5i +.B Kobold +may get nasty and steal one gold piece and run away. +.TP 1.5i +.B Shelob +may bite, inflicting the equivalent of one +.B poison. +.TP 1.5i +.B Assorted Faeries +These are killed if attacking someone carrying +.B holy water. +These are +.B Cluricaun, Fir Darrig, Fachan, +.B Ghille Dhu, Bogle, Killmoulis, +and +.B Bwca. +.TP 1.5i +.B Lamprey +may bite, inflicting 1/2 of a +.B poison. +.TP 1.5i +.B Shrieker +will call one of its (much bigger) buddies if picked upon. +.TP 1.5i +.B Bonnacon +will become bored with battle, fart, and run off. +.TP 1.5i +.B Smeagol +will try to steal a +.B ring +from a player, if given the chance. +.TP 1.5i +.B Succubus +may inflict damage through a +.B force field. +This subtracts from +.B energy level +instead of any shield the player may have thrown up. +This is a very easy way to die. +.TP 1.5i +.B Cerberus +loves metal and will steal all the metal treasures from +a player if able. +.TP 1.5i +.B Ungoliant +can bite and poison. This inflicts five +.B poisons +, and also takes one from the player's +.B quickness. +.TP 1.5i +.B Jabberwock +may tire of battle, and leave after calling one of his friends +( +.B Jubjub Bird +or +.B Bandersnatch +). +.TP 1.5i +.B Morgoth +actually +.B Modnar +, but reserved for +.B council of the wise, valar, +and +.B ex-valar. +Fights with +.B Morgoth +end when either he or the player dies. His characteristics +are calculated based upon the player's. The player is given +the chance to ally with him. No magic, except +.B force field +works when battling +.B Morgoth. +.TP 1.5i +.B Troll +may regenerate its +.B energy +and +.B strength +while in battle. +.TP 1.5i +.B Wraith +may make a player blind. +.sh "Treasures" +Various treasure types are as follows: +.TP 1.5i +.B Type zero +.I none +.TP 1.5i +.B Type one +.I power booster +\- adds manna. +.br +.I druid +\- adds experience. +.br +.I holy orb +\- subtracts 0.25 sin. +.TP 1.5i +.B Type two +.I amulet +\- protects from cursed treasure. +.br +.I holy water +\- kills +.B assorted faeries. +.br +.I hermit +\- reduces sin by 25% and adds some manna. +.TP 1.5i +.B Type three +.I shield +\- adds to maximum +.B energy level +.br +.I virgin +\- used to subdue a +.B unicorn +, or to give much +.B experience +(and some +.B sin +). +.br +.I athelas +\- subtracts one +.B poison. +.TP 1.5i +.B Type four (scrolls) +.I shield +* \- throws a bigger than normal +.B force field. +.br +.I invisible +* \- puts the finder's +.B quickness +to one million. +.br +.I ten fold strength +* \- multiplies finder's strength by ten. +.br +.I pick monster +\- allows finder to pick next monster to battle. +.br +.I general knowledge +\- adds to finder's +.B brains +and +.B magic level. +.PP +All the scrolls except +.B general knowledge +automatically call a monster. Those that are marked with a * preserve any +spells that were already in effect. Those that call monsters are only in +effect while in battle. +.TP 1.5i +.B Type five +.I dagger +\- adds to +.B strength. +.br +.I armour +\- same as a +.B shield, +but bigger. +.br +.I tablet +\- adds brains. +.TP 1.5i +.B Type six +.I priest +\- rests to maximum; adds +.B manna, brains; +and halves +.B sin. +.br +.I Robin Hood +\- increases +.B shield +and adds permanently to +.B strength. +.br +.I axe +\- like +.B dagger, +but bigger. +.TP 1.5i +.B Type seven +.I charm +\- protects from cursed treasure (used before +.B amulet +); used in conjunction with +.B blessing +to battle +.B Dark Lord. +.br +.I Merlyn +\- adds +.B brains, magic, +and +.B manna. +.br +.I war hammer +\- like an +.B axe, +but bigger. +.TP 1.5i +.B Type eight +.I healing potion +\- sets +.B poison +to -2, or subtracts two from +.B poison, +whichever is better. +.br +.I transporter +\- allows finder to move anywhere. +.br +.I sword +\- like a +.B war hammer +, but bigger. +.TP 1.5i +.B Type nine +.I golden crown +\- allows the player to become +.B king, +by going to (0,0). +.br +.I blessing +\- cuts +.B sin +to 1/3, adds +.B manna, +rests to max., and kills +.B Dark Lord +with a +.B charm. +.br +.I quicksilver +\- adds to +.B quickness. +.TP 1.5i +.B Type ten +.I elven boots +\- adds permanently to +.B quickness. +.TP 1.5i +.B Type eleven +.I palantir +\- allows one to see all the other players; used by +.B council of the wise +to seek the +.B grail. +.TP 1.5i +.B Type twelve/thirteen +.I ring +\- allows one to hit much harder in battle, etc. +.PP +Any treasure type 10-13 monsters may instead carry a type nine treasure. +.PP +A monster may also be carrying +.B gold +or +.B gems. +These are used at +.B trading posts +to buy things. A +.B gem +is worth 1000 gold pieces. Too much +.B gold +will slow a player down. One may carry 1000 plus 200 per +.B level +of +.B gold. +A +.B gem +weighs one half a gold piece. +Monsters of treasure type 7 or higher may carry +.B gems. +.PP +The chance of a cursed treasure is based upon treasure type. +The more valuable treasures have a greater chance of being cursed. +A cursed treasure knocks +.B energy level +very low, and adds 0.25 +.B poison. +.sh "Rings" +.B Rings +are only carried by +.B nazguls +and +.B Dark Lord. +They come in four different flavors. +All +.B rings +rest the player to maximum and cause him/her to hit much harder +in battle with monsters (assuming one has chosen to use the +.B ring +for battle.) +.PP +Two types of +.B rings +are cursed and come either from +.B nazguls +or +.B Dark Lord. +After a few times of using these types, the player falls +under the control of the +.B ring, +and strange, random things will occur. +Eventually, the player dies, and gives his/her name to a monster +on the file. +Dying before the +.B ring +is used up also renames the monster. +.PP +The two remaining types of +.B rings +are much more benign. +The one from a +.B nazgul +is good for a limited number of battle rounds, and will save +the player from death if it was being used when he/she died. +The one from +.B Dark Lord +is the same, except that it never is used up. +.B rings +disappear after saving someone from death. +In general, cursed +.B rings +occur much more often than normal ones. +It is usually not a good idea to pick one up. +The only way to get rid of a +.B ring +is to have a monster steal it. +.sh "King" +A player may become +.B king by finding a +.I crown +and going to (0,0). Players must have a +.B level +in the range of 10 to 1000 to be able to find a +.I crown. +.PP +Once a player is king, he/she may do certain things while in +the Lord's Chamber (0,0). These fall under the +.B decree +('0') option. +.TP 1.5i +.I transport +This is done to another player. It randomly moves the affected +player about. A +.B charm +protects from transports. +.TP 1.5i +.I curse +This is done to another player. It is analogous to cursed treasure, +but worse. It inflicts two +.B poison, +knocks +.B energy level +very low, and degrades the maximum energy. It also +removes a +.B cloak. +A +.B blessing +protects from king's curses. +.TP 1.5i +.I energy void +The king may put as many of these (within reason) scattered about +his/her kingdom as he/she pleases. +If a player hits one, he/she loses +.B manna, energy, +and +.B gold. +The energy void disappears after being hit. +.TP 1.5i +.I bestow +This is also done to another player. The king may +wish to reward one or more loyal subjects by sharing his/her +riches ( +.B gold +). Or it is a convenient way to dispose of some unwanted +deadweight. +.TP 1.5i +.I collect taxes +Everyone pays 10% tax on all +.B gold +collected, regardless of the existence of a +.B king. +The king may collect this amount with this option. +.PP +The +.B king +may also +.B teleport +anywhere for free by using the origin as a starting place. +.sh "Special Places" +Certain regions of the playing grid have different names. +In general, this is only to give the player some idea of +his/her present location. Some special places do exist. +.TP 1.5i +.I Trading Posts +These are located at |x| == |y| == n*n*100 for n = 1, 2...1000. +Trading posts farther out have more things for sale. +Be careful about cheating merchants there, as they have short +tempers. +Merchants are dishonest about 5% of the time. +.TP 1.5i +.I Lord's Chamber +This is located at (0,0). Only players with +.B crowns +may enter. +.TP 1.5i +.I Point of No Return +This is located beyond 1.2e+6 in any direction. +The only way to return from here is a +.B transporter +or to have a +.B valar +relocate the player. +.TP 1.5i +.I Dead Marshes +This is a band located fairly distant from the origin. The first +fourteen monsters (water monsters) can normally only be found here. +.TP 1.5i +.I Valhala +This place is where the +.B valar +resides. It is associated with no particular coordinate on the +playing grid. +.TP 1.5i +.I Wormholes +At fixed locations on the grid are several holes to underground +defects in the playing area. +Sixty-four chambers exist; sixteen of which open to the outside +world. +While in the wormholes, one move by going forward, backward, +left, or right. +One can always undo a move by going in the opposite direction. +The wormholes are mappable. +For example, to move from the first wormhole {at (-400,0)} to +the second wormhole, type 'LL'. +.sh "Miscellaneous" +There are several bits of trivial knowledge which fall under this category. +.PP +A +.I guru +will never be disgusted with your +.B sins +if they are less than one. +.PP +A +.I medic +wants half of a player's +.B gold +to be happy. Offering more than one has, or a negative amount +will anger the +.I medic, +who will make the player worse (add one +.B poison +). +.PP +The +.B Holy Grail +does little for those who are not ready to behold it. +Whenever anyone finds it, it moves. +It is always located within 1e+6 in any compass direction of the origin. +.PP +There is a maximum amount of +.B manna +and +.B charms +a player may posses, based upon +.B level. +.I Quicksilver +is always limited to to a maximum of 99. +.PP +.I Books +bought at a +.B trading post +increase +.B brains, +based upon the number bought. +It is unwise, however to buy more than 1/10 of one's +.B level +in books at a time. +.PP +Players over level 10000 are automatically retired. +.PP +A +.I blindness +goes away in random time. +.sh "Inter-terminal Battle" +When two player's coordinates correspond, they may engage in battle. +In general, the player with the highest +.B quickness +gets the first hit. +If the two players are severely mis-matched, the stronger player +is drastically handicapped for the battle. +In order to protect from being stuck in an infinite loop, +the player waiting for response may time out. Options for battle are: +.TP 1.5i +.I fight +Inflicts damage upon other person. +.TP 1.5i +.I run away +Escape from battle. Has a 75% chance of working. +.TP 1.5i +.I power blast +Battle spell. +.TP 1.5i +.I luckout +One-time chance to try to win against the foe. Has a 10% chance of working. +.PP +Sometimes waits for the other player may be excessive, because +he/she may be battling a monster. Upon slaying a player in battle +the winner gets the other's +.B experience +and treasures. +.B Rings +do not work for inter-terminal battle. +.sh "Council of the Wise, Valar" +A player automatically becomes a member of the +.B council of the wise +upon reaching level 3000. Members of the council cannot have +.B rings. +Members of the council have a few extra options which they can exercise. +These fall under the +.B intervention +('8') option. +One is to +.I heal +another player. This is just a quick way for that player to be rested +to maximum and lose a little +.B poison. +The main purpose in life for members of the council is to seek the +.B Holy Grail. +This is done with a +.B palantir +under the +.I seek grail +option. The distance cited by the seek is accurate within 10%, in order +not to make it too easy to find the grail. Seeking costs 1000 +.B manna. +A player must have infintesimally small +.B sin, +or else it's all over upon finding the grail. +In order to help members of the council on their quest, they +may +.I teleport +with greater ease. +.PP +Upon finding the grail, the player advance to position of +.B valar. +He/she may then exercise more and niftier options under +.I intervention. +These include all of the council members' option plus the +ability to move other players about, bless them, and throw monsters at +them. +.B Valar +are essentially immortal, but are actually given five lives. +If these are used up, the player is left to die, and becomes an +.B ex-valar. +.B Valar +cannot +.I move, teleport, +or call monsters. +Any monsters which a +.B valar +encounters are based upon his/her size. +Only one valar may exists at a time. +A player replaces the exiting valar upon finding the grail. +The valar is then bumped back to the council of the wise. +.SH BUGS +Many. The whole program is a hack. The handling of incorrectly +exitted characters is a kludge. The screen is set up assuming a 24 by 80 +character screen; no attempt was made to provide otherwise. +If the program is not set uid, it crashes on the first attempt to open a +data file. +If any of the data items get too big for the allotted space on the screen, +no guarantees are made about what will happen. +There should be a way to change a character's name. diff --git a/src/games/phantasia/phant_run.c b/src/games/phantasia/phant_run.c new file mode 100644 index 0000000..ffd99fd --- /dev/null +++ b/src/games/phantasia/phant_run.c @@ -0,0 +1,16 @@ +/* + This is a program to run phantasia + + David Wells, May, 1986 +*/ + +main(argc, argv) + int argc; + char **argv; +{ + char tmp[160]; + strcat(tmp,"exec nice /usr/games/lib/phantasia/phantasia "); + if (argc > 1) + strcat(tmp,argv[1]); + system(tmp); +} diff --git a/src/games/phantasia/setfiles.c b/src/games/phantasia/setfiles.c new file mode 100644 index 0000000..b69559f --- /dev/null +++ b/src/games/phantasia/setfiles.c @@ -0,0 +1,138 @@ +/* + * setfiles.c Program to set up all files for Phantasia + * + * This program tries to verify the parameters specified in + * the Makefile. Since Phantasia assumes its files exist, + * simple errors can result in core dumps. + * + * This program tries to check against this. + */ + +#include "phant.h" +#include +#include + +int +main(argc,argv) /* program to init. files for Phantasia */ + int argc; + char **argv; +{ + FILE *fp; + struct stats sbuf; + struct nrgvoid grail; + struct stat fbuf; + register int loop; + int foo; + char stbuf[128]; + +#ifdef notdef + srand((int) time(NULL)); /* prime random numbers */ + /* try to check RAND definition */ + for (loop = 1000; loop; loop--) { + if ((foo = rand()) > ((int) RAND)) { + sprintf(stbuf,"%f %f",(double) RAND, (double) foo); + Error("%s is a bad value for RAND.\n",stbuf); + } + } +#endif + umask(077); + + /* check where Phantasia lives */ + if (stat(PATH, &fbuf) < 0) { + perror(PATH); + exit(1); + /*NOTREACHED*/ + } + if (fbuf.st_mode & S_IFDIR == 0) + Error("%s is not a directory.\n", PATH); + + /* try to create data files */ + if ((fp = fopen(goldfile,"w")) == NULL) + Error("cannot create %s.\n",goldfile); + else + fclose(fp); + + if ((fp = fopen(motd,"w")) == NULL) + Error("cannot create %s.\n",motd); + else + fclose(fp); + + if ((fp = fopen(messfile,"w")) == NULL) + Error("cannot create %s.\n",messfile); + else + fclose(fp); + + /* do not reset character file if it already exists */ + if (stat(peoplefile,&fbuf) < 0) { + buildchar(&sbuf); + strcpy(sbuf.name,""); + if ((fp = fopen(peoplefile,"w")) == NULL) + Error("cannot create %s.\n",peoplefile); + else { + fwrite(&sbuf,sizeof(sbuf),1,fp); + fclose(fp); + } + } + grail.active = TRUE; + grail.x = roll(-1.0e6,2.0e6); + grail.y = roll(-1.0e6,2.0e6); + if ((fp = fopen(voidfile,"w")) == NULL) + Error("cannot create %s.\n",voidfile); + else { + fwrite(&grail,sizeof(grail),1,fp); + fclose(fp); + } + if ((fp = fopen(lastdead,"w")) == NULL) + Error("cannot create %s.\n",lastdead); + else { + fputs(" ",fp); + fclose(fp); + } +#ifdef ENEMY + if ((fp = fopen(enemyfile,"w")) == NULL) + Error("cannot create %s.\n",enemyfile); + else { + /* comment this out for now + fprintf(fp,"# Use this file to restrict access from obnoxious users.\n"); + fprintf(fp,"# Just put the login names of those restricted, one per\n"); + fprintf(fp,"# line, below.\n"); + */ + fclose(fp); + } +#endif + if (getuid() != UID) + fprintf(stderr,"Warning: UID (%d) is not equal to current uid.\n",UID); +} + +/* + * Note that this function is almost the same as initchar(). + * t is used to insure that unexpected values will not be found in a + * new character file. + */ +buildchar(stat) /* put in some default values */ + struct stats *stat; +{ + stat->x = roll(-125,251); + stat->y = roll(-125,251); + stat->exp = stat->lvl = stat->sin = 0; + stat->crn = stat->psn = 0; + stat->rng.type = NONE; + stat->rng.duration = 0; + stat->pal = FALSE; + stat->hw = stat->amu = stat->bls = 0; + stat->chm = 0; + stat->gem = 0.1; + stat->gld = roll(25,50) + roll(0,25) + 0.1; + stat->quks = stat->swd = stat->shd = 0; + stat->vrg = FALSE; + stat->typ = 0; +} + +Error(str,file) /* print an error message, and exit */ + char *str, *file; +{ + fprintf(stderr,"Error: "); + fprintf(stderr,str,file); + exit(1); + /*NOTREACHED*/ +} diff --git a/src/games/phantasia/test.c b/src/games/phantasia/test.c new file mode 100644 index 0000000..440cba0 --- /dev/null +++ b/src/games/phantasia/test.c @@ -0,0 +1,7 @@ +main() +{ +double Too_Big = 987654321; + +temp = Too_Big; +printf("Too_Big = %f, temp = %d/n",&Too_Big, &temp); +} diff --git a/src/games/ppt.c b/src/games/ppt.c new file mode 100644 index 0000000..8ab8a0a --- /dev/null +++ b/src/games/ppt.c @@ -0,0 +1,34 @@ +#ifdef CROSS +# include +#else +# include +#endif + +void putone(byte) + register int byte; +{ + register int i; + + putchar('|'); + for (i=7; i>=0; --i) { + if (i==2) + putchar('.'); + if (byte & (1 << i)) + putchar('o'); + else + putchar(' '); + } + putchar('|'); + putchar('\n'); +} + +int main() +{ + register int c; + + printf("___________\n"); + while ((c = getchar()) != EOF) + putone(c); + printf("___________\n"); + return 0; +} diff --git a/src/games/primes.c b/src/games/primes.c new file mode 100644 index 0000000..505d37a --- /dev/null +++ b/src/games/primes.c @@ -0,0 +1,143 @@ +/* + * primes [ number ] + * + * Print all primes greater than argument (or number read from stdin). + * + * A free translation of 'primes.s' + * + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#ifdef CROSS +# include +#else +# include +#endif +#include +#include + +#define TABSIZE 1000 /* size of sieve table */ +#define BIG 4294967296. /* largest unsigned int */ + +char table[TABSIZE]; /* table for sieve of Eratosthenes */ +int tabbits = 8*TABSIZE; /* number of bits in table */ + +float fstart; +unsigned start; /* lowest number to test for prime */ +char bittab[] = { /* bit positions (to save shifting) */ + 01, 02, 04, 010, 020, 040, 0100, 0200 +}; + +unsigned pt[] = { /* primes < 100 */ + 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, + 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97 +}; + +unsigned factab[] = { /* difference between succesive trial factors */ + 10, 2, 4, 2, 4, 6, 2, 6, 4, 2, 4, 6, 6, 2, 6, 4, + 2, 6, 4, 6, 8, 4, 2, 4, 2, 4, 8, 6, 4, 6, 2, 4, + 6, 2, 6, 6, 4, 2, 4, 6, 2, 6, 4, 2, 4, 2, 10, 2 +}; + +/* + * Insert all multiples of given factor into the sieve + */ +void sieve(factor) + unsigned factor; +{ + register int i; + unsigned off; + unsigned quot; + + quot = start / factor; + off = (quot * factor) - start; + if ((int)off < 0) + off += factor; + while (off < tabbits ) { + i = (int)off; + table[i>>3] |= bittab[i&07]; + off += factor; + } +} + +/* + * Error message + */ +void ouch() +{ + fprintf(stderr, "Ouch.\n"); +} + +int main(argc, argv) + int argc; + char **argv; +{ + register unsigned *fp; + register char *p; + register int i; + unsigned quot; + unsigned factor, v; + + if (argc >= 2) { /* get starting no. from arg */ + if (sscanf(argv[1], "%f", &fstart) != 1 + || fstart < 0.0 || fstart >= BIG) { + ouch(); + exit(1); + } + } else { /* get starting no. from stdin */ + while ((i = scanf("%f", &fstart)) != 1 + || fstart < 0.0 || fstart >= BIG) { + if (i == EOF) + exit(1); + ouch(); + } + } + start = (unsigned)fstart; + + /* + * Quick list of primes < 100 + */ + if (start <= 97) { + for (fp = pt; *fp < start; fp++) + ; + do + printf("%u\n", *fp); + while (++fp < &pt[sizeof(pt) / sizeof(*pt)]); + start = 100; + } + quot = start/2; + start = quot * 2 + 1; + + /* + * Loop forever: + */ + for (;;) { + /* + * Generate primes via sieve of Eratosthenes + */ + for (p = table; p < &table[TABSIZE]; p++) /* clear sieve */ + *p = '\0'; + v = (unsigned)sqrt((float)(start + tabbits)); /* highest useful factor */ + sieve(3); + sieve(5); + sieve(7); + factor = 11; + fp = &factab[1]; + do { + sieve(factor); + factor += *fp; + if (++fp >= &factab[sizeof(factab) / sizeof(*factab)]) + fp = factab; + } while (factor <= v); + + /* + * Print generated primes + */ + for (i = 0; i < 8*TABSIZE; i += 2) { + if ((table[i>>3] & bittab[i&07]) == 0) + printf("%u\n", start); + start += 2; + } + } +} diff --git a/src/games/quiz/Makefile b/src/games/quiz/Makefile new file mode 100644 index 0000000..c314721 --- /dev/null +++ b/src/games/quiz/Makefile @@ -0,0 +1,42 @@ +# @(#)Makefile 4.2 (Berkeley) 9/7/85 +# +DESTDIR= +CFLAGS= -O +SEPFLAG= -i + +quiz: quiz.c + cc ${SEPFLAG} ${CFLAGS} -o quiz quiz.c + +install: quiz quiz.k + install -s quiz ${DESTDIR}/usr/games/quiz + cp -r quiz.k ${DESTDIR}/usr/games/lib + +clean: + rm -f a.out core *.s *.o quiz + +depend: + cat x.c + for i in quiz; do \ + (echo $$i: $$i.c >>makedep; \ + /bin/grep '^#[ ]*include' x.c $$i.c | sed \ + -e 's,<\(.*\)>,"/usr/include/\1",' \ + -e 's/:[^"]*"\([^"]*\)".*/: \1/' \ + -e 's/\.c//' >>makedep); done + echo '/^# DO NOT DELETE THIS LINE/+2,$$d' >eddep + echo '$$r makedep' >>eddep + echo 'w' >>eddep + cp Makefile Makefile.bak + ed - Makefile < eddep + rm eddep makedep x.c + echo '# DEPENDENCIES MUST END AT END OF FILE' >> Makefile + echo '# IF YOU PUT STUFF HERE IT WILL GO AWAY' >> Makefile + echo '# see make depend above' >> Makefile + +# DO NOT DELETE THIS LINE -- make depend uses it + +quiz: quiz.c +quiz: /usr/include/stdio.h +quiz: /usr/include/signal.h +# DEPENDENCIES MUST END AT END OF FILE +# IF YOU PUT STUFF HERE IT WILL GO AWAY +# see make depend above diff --git a/src/games/quiz/quiz.6 b/src/games/quiz/quiz.6 new file mode 100644 index 0000000..67db6b6 --- /dev/null +++ b/src/games/quiz/quiz.6 @@ -0,0 +1,67 @@ +.\" @(#)quiz.6 6.1 (Berkeley) 5/20/85 +.\" +.TH QUIZ 6 "May 20, 1985" +.AT 3 +.SH NAME +quiz \- test your knowledge +.SH SYNOPSIS +.B /usr/games/quiz +[ +.B \-i +file ] +[ +.B \-t +] [ category1 category2 ] +.SH DESCRIPTION +.I Quiz +gives associative knowledge tests on various subjects. +It asks items chosen from +.I category1 +and expects answers from +.IR category2 . +If no categories are specified, +.I quiz +gives instructions and lists the available categories. +.PP +.I Quiz +tells a correct answer whenever you type a bare newline. +At the end of input, upon interrupt, or when questions run out, +.I quiz +reports a score and terminates. +.PP +The +.B \-t +flag specifies `tutorial' mode, where missed questions are repeated +later, and material is gradually introduced as you learn. +.PP +The +.B \-i +flag causes the named file to be substituted for the default index file. +The lines of these files have the syntax: +.RS +.nf +.ta \w'alternate 'u +line = category newline \(bv category `:' line +category = alternate \(bv category `|' alternate +alternate = empty \(bv alternate primary +primary = character \(bv `[' category `]' \(bv option +option = `{' category `}' +.fi +.RE +.PP +The first category on each line of an index file names an information file. +The remaining categories specify the order and contents of +the data in each line of the information file. +Information files have the same syntax. +Backslash `\\' is used as with +.IR sh (1) +to quote syntactically significant characters or to insert transparent +newlines into a line. +When either a question or its answer is empty, +.I quiz +will refrain from asking it. +.SH FILES +/usr/games/quiz.k/* +.SH BUGS +The construct `a\||\|ab' doesn't work in an information file. +Use `a{b}'. diff --git a/src/games/quiz/quiz.c b/src/games/quiz/quiz.c new file mode 100644 index 0000000..51da296 --- /dev/null +++ b/src/games/quiz/quiz.c @@ -0,0 +1,477 @@ + +static char sccsid[] = " quiz.c 4.2 85/01/09 "; + +#include +#include +#define NF 10 +#define NL 300 +#define NC 200 +#define SL 100 +#define NA 10 + +int tflag; +int xx[NL]; +char score[NL]; +int rights; +int wrongs; +int guesses; +FILE *input; +int nl = 0; +int na = NA; +int inc; +int ptr = 0; +int nc = 0; +char line[150]; +char response[100]; +char *tmp[NF]; +int select[NF]; + +readline() +{ + char *t; +loop: + for(t=line;(*t=getc(input))!=-1;t++) { + nc++; + if(*t==' '&&(t==line||t[-1]==' ')) + t--; + if(*t=='\n') { + if(t[-1]=='\\') /*inexact test*/ + continue; + while(t>line&&t[-1]==' ') + *--t = '\n'; + *++t = 0; + return(1); + } + if(t-line>=NC) { + printf("Too hard for me\n"); + do { + *line = getc(input); + if(*line==0377) + return(0); + } while(*line!='\n'); + goto loop; + } + } + return(0); +} + +char *eu; +char *ev; +cmp(u,v) +char *u,*v; +{ + int x; + eu = u; + ev = v; + x = disj(1); + if(x!=1) + return(x); + return(eat(1,0)); +} + +disj(s) +{ + int t, x; + char *u; + u = eu; + t = 0; + for(;;) { + x = string(s); + if(x>1) + return(x); + switch(*ev) { + case 0: + case ']': + case '}': + return(t|x&s); + case '|': + ev++; + t |= s; + s = 0; + continue; + } + if(s) eu = u; + if(string(0)>1) + return(2); + switch(*ev) { + case 0: + case ']': + return(0); + case '}': + return(1); + case '|': + ev++; + continue; + default: + return(2); + } + } +} + +string(s) +{ + int x; + for(;;) { + switch(*ev) { + case 0: + case '|': + case ']': + case '}': + return(1); + case '\\': + ev++; + if(*ev==0) + return(2); + if(*ev=='\n') { + ev++; + continue; + } + default: + if(eat(s,*ev)==1) + continue; + return(0); + case '[': + ev++; + x = disj(s); + if(*ev!=']' || x>1) + return(2); + ev++; + if(s==0) + continue; + if(x==0) + return(0); + continue; + case '{': + ev++; + x = disj(s); + if(*ev!='}'||x>1) + return(2); + ev++; + continue; + } + } +} + +eat(s,c) +char c; +{ + if(*ev!=c) + return(2); + if(s==0) { + ev++; + return(1); + } + if(fold(*eu)!=fold(c)) + return(0); + eu++; + ev++; + return(1); +} + +fold(c) +char c; +{ + if(c<'A'||c>'Z') + return(c); + return(c|040); +} + +publish(t) +char *t; +{ + ev = t; + pub1(1); +} + +pub1(s) +{ + for(;;ev++){ + switch(*ev) { + case '|': + s = 0; + ev; + continue; + case ']': + case '}': + case 0: + return; + case '[': + case '{': + ev++; + pub1(s); + ev; + continue; + case '\\': + if(*++ev=='\n') + continue; + default: + if(s) + putchar(*ev); + } + } +} + +segment(u,w) +char *u, *w[]; +{ + char *s; + int i; + char *t; + s = u; + for(i=0;i1) badinfo(); + if(x==0) + continue; + p[i] = j; + goto uloop; + } + return(0); +uloop: ; + } + return(1); +} + +find(u,m) +char *u[]; +{ + int n; + while(readline()){ + n = segment(line,tmp); + if(perm(u,m,tmp+1,n-1,select)) + return(1); + } + return(0); +} + +readindex() +{ + xx[0] = nc = 0; + while(readline()) { + xx[++nl] = nc; + if(nl>=NL) { + printf("I've forgotten some of it;\n"); + printf("I remember %d items.\n", nl); + break; + } + } +} + +talloc() +{ + int i; + char *malloc(); + + for(i=0;i1&&*argv[1]=='-') { + switch(argv[1][1]) { + case 'i': + if(argc>2) + info = argv[2]; + argc -= 2; + argv += 2; + goto loop; + case 't': + tflag = 1; + argc--; + argv++; + goto loop; + } + } + input = fopen(info,"r"); + if(input==NULL) { + printf("No info\n"); + exit(0); + } + talloc(); + if(argc<=2) + instruct(info); + signal(SIGINT,done); + argv[argc] = 0; + if(find(&argv[1],argc-1)==0) + dunno(); + fclose(input); + input = fopen(tmp[0],"r"); + if(input==NULL) + dunno(); + readindex(); + if(!tflag || na>nl) + na = nl; + stdout->_flag |= _IONBF; + for(;;) { + i = next(); + fseek(input,xx[i]+0L,0); + z = xx[i+1]-xx[i]; + for(j=0;j1) badinfo(); + if(x==1) { + printf("Right!\n"); + if(count==0) rights++; + if(++score[i]>=1 && nar&&t[-1]==' ') + *--t = '\n'; + break; + } + } + *t = 0; + return(t-r); +} + +next() +{ + int flag; + inc = inc*3125&077777; + ptr = (inc>>2)%na; + flag = 0; + while(score[ptr]>0) + if(++ptr>=na) { + ptr = 0; + if(flag) done(); + flag = 1; + } + return(ptr); +} + +done() +{ + printf("\nRights %d, wrongs %d, ", rights, wrongs); + if(guesses) + printf("extra guesses %d, ", guesses); + printf("score %d%%\n",100*rights/(rights+wrongs)); + exit(0); +} +instruct(info) +{ + char *t; + int i, n; + printf("Subjects:\n\n"); + while(readline()) { + printf("-"); + n = segment(line,tmp); + for(i=1;i +# include +#else +# include +# include +#endif +#include +#include +#include +#include +#include + +#define cursor(col, row) tputs(tgoto(CM, col, row), 1, fputchar) + +extern char *UP; +extern short ospeed; +struct sgttyb old_tty; +char *LL, *TE, *TI; + +int fputchar(c) + char c; +{ + return putchar(c); +} + +void onsig(n) + int n; +{ + tputs(LL, 1, fputchar); + if (TE) tputs(TE, 1, fputchar); + fflush(stdout); + ioctl(1, TIOCSETP, &old_tty); + kill(getpid(), n); + _exit(0); +} + +float ranf() +{ + return((float)rand()/2147483647.); +} + +int main(argc, argv) + int argc; + char *argv[]; +{ + register int x, y, j; + static int xpos[5], ypos[5]; + register char *CM, *BC, *DN, *ND; + int CO, LI; + char *tcp; + register char *term; + char tcb[100]; + struct sgttyb sg; + float cols, lines; + + setbuf(stdout, malloc(BUFSIZ)); + if (! (term = getenv("TERM"))) { + fprintf(stderr, "%s: TERM: parameter not set\n", *argv); + exit(1); + } + if (tgetent(malloc(1024), term) <= 0) { + fprintf(stderr, "%s: %s: unknown terminal type\n", *argv, term); + exit(1); + } + tcp = tcb; + if (! (CM = tgetstr("cm", &tcp))) { + fprintf(stderr, "%s: terminal not capable of cursor motion\n", *argv); + exit(1); + } + if (! (BC = tgetstr("bc", &tcp))) + BC = "\b"; + if (! (DN = tgetstr("dn", &tcp))) + DN = "\33[B"; + if (! (ND = tgetstr("nd",&tcp))) + ND = " "; + if ((CO = tgetnum("co")) == -1) + CO = 80; + if ((LI = tgetnum("li")) == -1) + LI = 24; + cols = CO - 4; + lines = LI - 4; + TE = tgetstr("te", &tcp); + TI = tgetstr("ti", &tcp); + UP = tgetstr("up", &tcp); + if (! (LL = tgetstr("ll", &tcp))) + strcpy(LL = malloc(10), tgoto(CM, 0, 23)); + ioctl(1, TIOCGETP, &sg); + ospeed = sg.sg_ospeed; + for (j = SIGHUP; j <= SIGTERM; j++) + if (signal(j, SIG_IGN) != SIG_IGN) + signal(j, onsig); + + ioctl(1, TIOCGETP, &old_tty); /* save tty bits for exit */ + ioctl(1, TIOCGETP, &sg); + sg.sg_flags &= ~(CRMOD|ECHO); + ioctl(1, TIOCSETP, &sg); + + if (TI) + tputs(TI, 1, fputchar); + tputs(tgetstr("cl", &tcp), 1, fputchar); + fflush(stdout); + for (j = 5; --j >= 0; ) { + xpos[j]=(int)(cols*ranf())+2; + ypos[j]=(int)(lines*ranf())+2; + } + for (j = 0; ; ) { + x = (int)(cols*ranf())+2; + y = (int)(lines*ranf())+2; + cursor(x, y); + fputchar('.'); + cursor(xpos[j], ypos[j]); + fputchar('o'); + if (j == 0) + j = 4; + else + --j; + cursor(xpos[j], ypos[j]); + fputchar('O'); + if (j == 0) + j = 4; + else + --j; + cursor(xpos[j], ypos[j]-1); + fputchar('-'); + tputs(DN, 1, fputchar); + tputs(BC, 1, fputchar); + tputs(BC, 1, fputchar); + fputs("|.|", stdout); + tputs(DN, 1, fputchar); + tputs(BC, 1, fputchar); + tputs(BC, 1, fputchar); + fputchar('-'); + if (j == 0) + j = 4; + else + --j; + cursor(xpos[j], ypos[j]-2); + fputchar('-'); + tputs(DN, 1, fputchar); + tputs(BC, 1, fputchar); + tputs(BC, 1, fputchar); + fputs("/ \\", stdout); + cursor(xpos[j]-2, ypos[j]); + fputs("| O |", stdout); + cursor(xpos[j]-1, ypos[j]+1); + fputs("\\ /", stdout); + tputs(DN, 1, fputchar); + tputs(BC, 1, fputchar); + tputs(BC, 1, fputchar); + fputchar('-'); + if (j == 0) + j = 4; + else + --j; + cursor(xpos[j], ypos[j]-2); + fputchar(' '); + tputs(DN, 1, fputchar); + tputs(BC, 1, fputchar); + tputs(BC, 1, fputchar); + fputchar(' '); + tputs(ND, 1, fputchar); + fputchar(' '); + cursor(xpos[j]-2, ypos[j]); + fputchar(' '); + tputs(ND, 1, fputchar); + fputchar(' '); + tputs(ND, 1, fputchar); + fputchar(' '); + cursor(xpos[j]-1, ypos[j]+1); + fputchar(' '); + tputs(ND, 1, fputchar); + fputchar(' '); + tputs(DN, 1, fputchar); + tputs(BC, 1, fputchar); + tputs(BC, 1, fputchar); + fputchar(' '); + xpos[j] = x; + ypos[j] = y; + fflush(stdout); + } +} diff --git a/src/games/robots/Makefile b/src/games/robots/Makefile new file mode 100644 index 0000000..db4e681 --- /dev/null +++ b/src/games/robots/Makefile @@ -0,0 +1,31 @@ +# +# Copyright (c) 1980 Regents of the University of California. +# All rights reserved. The Berkeley software License Agreement +# specifies the terms and conditions for redistribution. +# +# @(#)Makefile 5.2 (Berkeley) 5/15/86 +# +DESTDIR= +HDRS= robot.h +CFILES= extern.c init_field.c main.c make_level.c move.c \ + move_robs.c play_level.c query.c rnd_pos.c score.c \ + flush_in.c +OBJS= extern.o init_field.o main.o make_level.o move.o \ + move_robs.o play_level.o query.o rnd_pos.o score.o \ + flush_in.o +DEFS= -DMAX_PER_UID=5 +CFLAGS= -O ${DEFS} +SEPFLAG= -i + +robots: ${OBJS} + ${CC} ${SEPFLAG} ${CFLAGS} -o robots ${OBJS} -lcurses -ltermlib + +lint: + lint -hb ${DEFS} ${CFILES} -lcurses 2>1 > lint.out + +install: robots + install -s -m 4711 -o daemon robots ${DESTDIR}/usr/games + install -c -m 644 -o daemon /dev/null ${DESTDIR}/usr/games/lib/robots_roll + +clean: + rm -f a.out core *.o robots lint.out errs diff --git a/src/games/robots/extern.c b/src/games/robots/extern.c new file mode 100644 index 0000000..1a4c103 --- /dev/null +++ b/src/games/robots/extern.c @@ -0,0 +1,48 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +#ifndef lint +static char sccsid[] = "@(#)extern.c 5.1 (Berkeley) 5/30/85"; +#endif not lint + +# include "robots.h" + +bool Dead; /* Player is now dead */ +bool Full_clear = TRUE; /* Lots of junk for init_field to clear */ +bool Jump = FALSE; /* Jump while running, counting, or waiting */ +bool Newscore; /* There was a new score added */ +#ifdef FANCY +bool Pattern_roll = FALSE; /* Auto play for YHBJNLUK pattern */ +#endif +bool Real_time = FALSE; /* Play in real time? */ +bool Running = FALSE; /* Currently in the middle of a run */ +#ifdef FANCY +bool Stand_still = FALSE; /* Auto play for standing still pattern */ +#endif +bool Teleport = FALSE; /* Teleport automatically when player must */ +bool Waiting; /* Player is waiting for end */ +bool Was_bonus = FALSE; /* Was a bonus last level */ + +char Cnt_move; /* Command which has preceded the count */ +char Field[Y_FIELDSIZE][X_FIELDSIZE]; /* the playing field itslef */ +char *Next_move; /* Next move to be used in the pattern */ +char *Move_list = "YHBJNLUK";/* List of moves in the pattern */ +char Run_ch; /* Character for the direction we are running */ + +int Count = 0; /* Command count */ +int Level; /* Current level */ +int Num_robots; /* Number of robots left */ +int Num_scores; /* Number of scores posted */ +int Score; /* Current score */ +int Start_level = 1; /* Level on which to start */ +int Wait_bonus; /* bonus for waiting */ + +COORD Max; /* Max area robots take up */ +COORD Min; /* Min area robots take up */ +COORD My_pos; /* Player's current position */ +COORD Robots[MAXROBOTS]; /* Robots' current positions */ + +jmp_buf End_move; /* Jump to on Real_time */ diff --git a/src/games/robots/flush_in.c b/src/games/robots/flush_in.c new file mode 100644 index 0000000..9d4842d --- /dev/null +++ b/src/games/robots/flush_in.c @@ -0,0 +1,24 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +#ifndef lint +static char sccsid[] = "@(#)flush_in.c 5.1 (Berkeley) 5/30/85"; +#endif not lint + +# include + +/* + * flush_in: + * Flush all pending input. + */ +flush_in() +{ +# ifdef TIOCFLUSH + ioctl(fileno(stdin), TIOCFLUSH, NULL); +# else TIOCFLUSH + crmode(); +# endif TIOCFLUSH +} diff --git a/src/games/robots/init_field.c b/src/games/robots/init_field.c new file mode 100644 index 0000000..a72c717 --- /dev/null +++ b/src/games/robots/init_field.c @@ -0,0 +1,90 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +#ifndef lint +static char sccsid[] = "@(#)init_field.c 5.1 (Berkeley) 5/30/85"; +#endif not lint + +# include "robots.h" + +/* + * init_field: + * Lay down the initial pattern whih is constant across all levels, + * and initialize all the global variables. + */ +init_field() +{ + register int i; + register WINDOW *wp; + register int j; + static bool first = TRUE; + static char *desc[] = { + "Directions:", + "", + "y k u", + " \\|/", + "h- -l", + " /|\\", + "b j n", + "", + "Commands:", + "", + "w: wait for end", + "t: teleport", + "q: quit", + "^L: redraw screen", + "", + "Legend:", + "", + "+: robot", + "*: junk heap", + "@: you", + "", + "Score: 0", + NULL + }; + + Dead = FALSE; + Waiting = FALSE; + flushok(stdscr, TRUE); + Score = 0; + + erase(); + move(0, 0); + addch('+'); + for (i = 1; i < Y_FIELDSIZE; i++) { + move(i, 0); + addch('|'); + } + move(Y_FIELDSIZE, 0); + addch('+'); + for (i = 1; i < X_FIELDSIZE; i++) + addch('-'); + addch('+'); + if (first) + refresh(); + move(0, 1); + for (i = 1; i < X_FIELDSIZE; i++) + addch('-'); + addch('+'); + for (i = 1; i < Y_FIELDSIZE; i++) { + move(i, X_FIELDSIZE); + addch('|'); + } + if (first) + refresh(); + for (i = 0; desc[i] != NULL; i++) { + move(i, X_FIELDSIZE + 2); + addstr(desc[i]); + } + if (first) + refresh(); + first = FALSE; +#ifdef FANCY + if (Pattern_roll) + Next_move = &Move_list[-1]; +#endif +} diff --git a/src/games/robots/main.c b/src/games/robots/main.c new file mode 100644 index 0000000..df15f7a --- /dev/null +++ b/src/games/robots/main.c @@ -0,0 +1,167 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +#ifndef lint +char copyright[] = +"@(#) Copyright (c) 1980 Regents of the University of California.\n\ + All rights reserved.\n"; +#endif not lint + +#ifndef lint +static char sccsid[] = "@(#)main.c 5.1 (Berkeley) 5/30/85"; +#endif not lint + +# include "robots.h" +# include +# include + +main(ac, av) +int ac; +char **av; +{ + register char *sp; + register bool bad_arg; + register bool show_only; + extern char *Scorefile; + extern int Max_per_uid; + extern char *rindex(); + + show_only = FALSE; + if (ac > 1) { + bad_arg = FALSE; + for (++av; ac > 1 && *av[0]; av++, ac--) + if (av[0][0] != '-') + if (isdigit(av[0][0])) + Max_per_uid = atoi(av[0]); + else { + setuid(getuid()); + setgid(getgid()); + Scorefile = av[0]; +# ifdef FANCY + sp = rindex(Scorefile, '/'); + if (sp == NULL) + sp = Scorefile; + if (strcmp(sp, "pattern_roll") == 0) + Pattern_roll = TRUE; + else if (strcmp(sp, "stand_still") == 0) + Stand_still = TRUE; + if (Pattern_roll || Stand_still) + Teleport = TRUE; +# endif + } + else + for (sp = &av[0][1]; *sp; sp++) + switch (*sp) { + case 's': + show_only = TRUE; + break; + case 'r': + Real_time = TRUE; + break; + case 'a': + Start_level = 4; + break; + case 'j': + Jump = TRUE; + break; + case 't': + Teleport = TRUE; + break; + default: + fprintf(stderr, "robots: uknown option: %c\n", *sp); + bad_arg = TRUE; + break; + } + if (bad_arg) { + exit(1); + /* NOTREACHED */ + } + } + + if (show_only) { + show_score(); + exit(0); + /* NOTREACHED */ + } + + initscr(); + signal(SIGINT, quit); + crmode(); + noecho(); + nonl(); + if (LINES != Y_SIZE || COLS != X_SIZE) { + if (LINES < Y_SIZE || COLS < X_SIZE) { + endwin(); + printf("Need at least a %dx%d screen\n", Y_SIZE, X_SIZE); + exit(1); + } + delwin(stdscr); + stdscr = newwin(Y_SIZE, X_SIZE, 0, 0); + } + + srand(getpid()); + if (Real_time) + signal(SIGALRM, move_robots); + do { + init_field(); + for (Level = Start_level; !Dead; Level++) { + make_level(); + play_level(); + } + move(My_pos.y, My_pos.x); + printw("AARRrrgghhhh...."); + refresh(); + score(); + } while (another()); + quit(); +} + +/* + * quit: + * Leave the program elegantly. + */ +quit() +{ + extern int _putchar(); + + mvcur(0, COLS - 1, LINES - 1, 0); + if (CE) { + tputs(CE, 1, _putchar); + endwin(); + } + else { + endwin(); + putchar('\n'); + } + exit(0); + /* NOTREACHED */ +} + +/* + * another: + * See if another game is desired + */ +another() +{ + register int y; + +#ifdef FANCY + if ((Stand_still || Pattern_roll) && !Newscore) + return TRUE; +#endif + + if (query("Another game?")) { + if (Full_clear) { + for (y = 1; y <= Num_scores; y++) { + move(y, 1); + clrtoeol(); + } + refresh(); + } + return TRUE; + } + return FALSE; +} diff --git a/src/games/robots/make_level.c b/src/games/robots/make_level.c new file mode 100644 index 0000000..56204b4 --- /dev/null +++ b/src/games/robots/make_level.c @@ -0,0 +1,62 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +#ifndef lint +static char sccsid[] = "@(#)make_level.c 5.1 (Berkeley) 5/30/85"; +#endif not lint + +# include "robots.h" + +/* + * make_level: + * Make the current level + */ +make_level() +{ + register int i; + register COORD *cp; + register WINDOW *wp; + register int x, *endp; + + reset_count(); + for (i = 1; i < Y_FIELDSIZE; i++) + for (x = 1; x < X_FIELDSIZE; x++) + if (Field[i][x] != 0) + mvaddch(i, x, ' '); + if (My_pos.y > 0) + mvaddch(My_pos.y, My_pos.x, ' '); + + Waiting = FALSE; + Wait_bonus = 0; + leaveok(stdscr, FALSE); + for (cp = Robots; cp < &Robots[MAXROBOTS]; cp++) + cp->y = -1; + My_pos.y = -1; + + bzero(Field, sizeof Field); + Min.y = Y_FIELDSIZE; + Min.x = X_FIELDSIZE; + Max.y = 0; + Max.x = 0; + if ((i = Level * 10) > MAXROBOTS) + i = MAXROBOTS; + Num_robots = i; + while (i-- > 0) { + cp = rnd_pos(); + Robots[i] = *cp; + Field[cp->y][cp->x]++; + if (cp->y < Min.y) + Min.y = cp->y; + if (cp->x < Min.x) + Min.x = cp->x; + if (cp->y > Max.y) + Max.y = cp->y; + if (cp->x > Max.x) + Max.x = cp->x; + } + My_pos = *rnd_pos(); + refresh(); +} diff --git a/src/games/robots/move.c b/src/games/robots/move.c new file mode 100644 index 0000000..80b6230 --- /dev/null +++ b/src/games/robots/move.c @@ -0,0 +1,272 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +#ifndef lint +static char sccsid[] = "@(#)move.c 5.1 (Berkeley) 5/30/85"; +#endif not lint + +# include "robots.h" +# include + +# define ESC '\033' + +/* + * get_move: + * Get and execute a move from the player + */ +get_move() +{ + register int c; + register int y, x, lastmove; + static COORD newpos; + + if (Waiting) + return; + +#ifdef FANCY + if (Pattern_roll) { + if (Next_move >= Move_list) + lastmove = *Next_move; + else + lastmove = -1; /* flag for "first time in" */ + } +#endif + for (;;) { + if (Teleport && must_telep()) + goto teleport; + if (Running) + c = Run_ch; + else if (Count != 0) + c = Cnt_move; +#ifdef FANCY + else if (Num_robots > 1 && Stand_still) + c = '>'; + else if (Num_robots > 1 && Pattern_roll) { + if (*++Next_move == '\0') { + if (lastmove < 0) + goto over; + Next_move = Move_list; + } + c = *Next_move; + mvaddch(0, 0, c); + if (c == lastmove) + goto over; + } +#endif + else { +over: + c = getchar(); + if (isdigit(c)) { + Count = (c - '0'); + while (isdigit(c = getchar())) + Count = Count * 10 + (c - '0'); + if (c == ESC) + goto over; + Cnt_move = c; + if (Count) + leaveok(stdscr, TRUE); + } + } + + switch (c) { + case ' ': + case '.': + if (do_move(0, 0)) + goto ret; + break; + case 'y': + if (do_move(-1, -1)) + goto ret; + break; + case 'k': + if (do_move(-1, 0)) + goto ret; + break; + case 'u': + if (do_move(-1, 1)) + goto ret; + break; + case 'h': + if (do_move(0, -1)) + goto ret; + break; + case 'l': + if (do_move(0, 1)) + goto ret; + break; + case 'b': + if (do_move(1, -1)) + goto ret; + break; + case 'j': + if (do_move(1, 0)) + goto ret; + break; + case 'n': + if (do_move(1, 1)) + goto ret; + break; + case 'Y': case 'U': case 'H': case 'J': + case 'K': case 'L': case 'B': case 'N': + case '>': + Running = TRUE; + if (c == '>') + Run_ch = ' '; + else + Run_ch = tolower(c); + leaveok(stdscr, TRUE); + break; + case 'q': + case 'Q': + if (query("Really quit?")) + quit(); + refresh(); + break; + case 'w': + case 'W': + Waiting = TRUE; + leaveok(stdscr, TRUE); + flushok(stdscr, FALSE); + goto ret; + case 't': + case 'T': +teleport: + Running = FALSE; + mvaddch(My_pos.y, My_pos.x, ' '); + My_pos = *rnd_pos(); + mvaddch(My_pos.y, My_pos.x, PLAYER); + leaveok(stdscr, FALSE); + refresh(); + flush_in(); + goto ret; + case CTRL(L): + wrefresh(curscr); + break; + case EOF: + break; + default: + putchar(CTRL(G)); + reset_count(); + fflush(stdout); + break; + } + } +ret: + if (Count > 0) + if (--Count == 0) + leaveok(stdscr, FALSE); +} + +/* + * must_telep: + * Must I teleport; i.e., is there anywhere I can move without + * being eaten? + */ +must_telep() +{ + register int x, y; + static COORD newpos; + +#ifdef FANCY + if (Stand_still && Num_robots > 1 && eaten(&My_pos)) + return TRUE; +#endif + + for (y = -1; y <= 1; y++) { + newpos.y = My_pos.y + y; + if (newpos.y <= 0 || newpos.y >= Y_FIELDSIZE) + continue; + for (x = -1; x <= 1; x++) { + newpos.x = My_pos.x + x; + if (newpos.x <= 0 || newpos.x >= X_FIELDSIZE) + continue; + if (Field[newpos.y][newpos.x] > 0) + continue; + if (!eaten(&newpos)) + return FALSE; + } + } + return TRUE; +} + +/* + * do_move: + * Execute a move + */ +do_move(dy, dx) +int dy, dx; +{ + static COORD newpos; + + newpos.y = My_pos.y + dy; + newpos.x = My_pos.x + dx; + if (newpos.y <= 0 || newpos.y >= Y_FIELDSIZE || + newpos.x <= 0 || newpos.x >= X_FIELDSIZE || + Field[newpos.y][newpos.x] > 0 || eaten(&newpos)) { + if (Running) { + Running = FALSE; + leaveok(stdscr, FALSE); + move(My_pos.y, My_pos.x); + refresh(); + } + else { + putchar(CTRL(G)); + reset_count(); + } + return FALSE; + } + else if (dy == 0 && dx == 0) + return TRUE; + mvaddch(My_pos.y, My_pos.x, ' '); + My_pos = newpos; + mvaddch(My_pos.y, My_pos.x, PLAYER); + if (!jumping()) + refresh(); + return TRUE; +} + +/* + * eaten: + * Player would get eaten at this place + */ +eaten(pos) +register COORD *pos; +{ + register int x, y; + + for (y = pos->y - 1; y <= pos->y + 1; y++) { + if (y <= 0 || y >= Y_FIELDSIZE) + continue; + for (x = pos->x - 1; x <= pos->x + 1; x++) { + if (x <= 0 || x >= X_FIELDSIZE) + continue; + if (Field[y][x] == 1) + return TRUE; + } + } + return FALSE; +} + +/* + * reset_count: + * Reset the count variables + */ +reset_count() +{ + Count = 0; + Running = FALSE; + leaveok(stdscr, FALSE); + refresh(); +} + +/* + * jumping: + * See if we are jumping, i.e., we should not refresh. + */ +jumping() +{ + return (Jump && (Count || Running || Waiting)); +} diff --git a/src/games/robots/move_robs.c b/src/games/robots/move_robs.c new file mode 100644 index 0000000..3fd782c --- /dev/null +++ b/src/games/robots/move_robs.c @@ -0,0 +1,124 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +#ifndef lint +static char sccsid[] = "@(#)move_robs.c 5.1 (Berkeley) 5/30/85"; +#endif not lint + +# include "robots.h" +# include + +/* + * move_robots: + * Move the robots around + */ +move_robots(was_sig) +bool was_sig; +{ + register COORD *rp; + register int y, x; + register int mindist, d; + static COORD newpos; + + if (Real_time) + signal(SIGALRM, move_robots); +# ifdef DEBUG + move(Min.y, Min.x); + addch(inch()); + move(Max.y, Max.x); + addch(inch()); +# endif DEBUG + for (rp = Robots; rp < &Robots[MAXROBOTS]; rp++) { + if (rp->y < 0) + continue; + mvaddch(rp->y, rp->x, ' '); + Field[rp->y][rp->x]--; + rp->y += sign(My_pos.y - rp->y); + rp->x += sign(My_pos.x - rp->x); + if (rp->y <= 0) + rp->y = 0; + else if (rp->y >= Y_FIELDSIZE) + rp->y = Y_FIELDSIZE - 1; + if (rp->x <= 0) + rp->x = 0; + else if (rp->x >= X_FIELDSIZE) + rp->x = X_FIELDSIZE - 1; + Field[rp->y][rp->x]++; + } + + Min.y = Y_FIELDSIZE; + Min.x = X_FIELDSIZE; + Max.y = 0; + Max.x = 0; + for (rp = Robots; rp < &Robots[MAXROBOTS]; rp++) + if (rp->y < 0) + continue; + else if (rp->y == My_pos.y && rp->x == My_pos.x) + Dead = TRUE; + else if (Field[rp->y][rp->x] > 1) { + mvaddch(rp->y, rp->x, HEAP); + rp->y = -1; + Num_robots--; + if (Waiting) + Wait_bonus++; + add_score(ROB_SCORE); + } + else { + mvaddch(rp->y, rp->x, ROBOT); + if (rp->y < Min.y) + Min.y = rp->y; + if (rp->x < Min.x) + Min.x = rp->x; + if (rp->y > Max.y) + Max.y = rp->y; + if (rp->x > Max.x) + Max.x = rp->x; + } + + if (was_sig) { + refresh(); + if (Dead || Num_robots <= 0) + longjmp(End_move); + } + +# ifdef DEBUG + standout(); + move(Min.y, Min.x); + addch(inch()); + move(Max.y, Max.x); + addch(inch()); + standend(); +# endif DEBUG + if (Real_time) + alarm(3); +} + +/* + * add_score: + * Add a score to the overall point total + */ +add_score(add) +int add; +{ + Score += add; + move(Y_SCORE, X_SCORE); + printw("%d", Score); +} + +/* + * sign: + * Return the sign of the number + */ +sign(n) +int n; +{ + if (n < 0) + return -1; + else if (n > 0) + return 1; + else + return 0; +} diff --git a/src/games/robots/play_level.c b/src/games/robots/play_level.c new file mode 100644 index 0000000..32be7c1 --- /dev/null +++ b/src/games/robots/play_level.c @@ -0,0 +1,88 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +#ifndef lint +static char sccsid[] = "@(#)play_level.c 5.2 (Berkeley) 9/23/85"; +#endif not lint + +# include "robots.h" + +/* + * play_level: + * Let the player play the current level + */ +play_level() +{ + register COORD *cp; + register int y, x, bonus; + + move(My_pos.y, My_pos.x); + addch(PLAYER); + refresh(); + for (cp = Robots; cp < &Robots[MAXROBOTS]; cp++) { + if (cp->y < 0) + continue; + move(cp->y, cp->x); + addch(ROBOT); + } + refresh(); +# ifdef DEBUG + standout(); + move(Min.y, Min.x); + addch(inch()); + move(Max.y, Max.x); + addch(inch()); + standend(); +# endif DEBUG + setjmp(End_move); + flush_in(); + while (!Dead && Num_robots > 0) { + move(My_pos.y, My_pos.x); + if (!jumping()) + refresh(); + get_move(); + if (Real_time) + alarm(0); + if (Field[My_pos.y][My_pos.x] != 0) + Dead = TRUE; + if (!Dead) + move_robots(FALSE); + if (Was_bonus) { + move(Y_PROMPT, X_PROMPT); + clrtoeol(); + move(Y_PROMPT + 1, X_PROMPT); + clrtoeol(); + Was_bonus = FALSE; + } + } + + /* + * if the player didn't die, add on the possible bonuses + */ + + if (!Dead) { + Was_bonus = FALSE; + + if (Level == Start_level && Start_level > 1) { + move(Y_PROMPT, X_PROMPT); + printw("Advance bonus: %d", S_BONUS); + refresh(); + add_score(S_BONUS); + Was_bonus = TRUE; + } + + if (Wait_bonus != 0) { + if (!Was_bonus) + move(Y_PROMPT, X_PROMPT); + else + move(Y_PROMPT + 1, X_PROMPT); + printw("Wait bonus: %d", Wait_bonus); + refresh(); + add_score(Wait_bonus); + Was_bonus = TRUE; + } + } +} diff --git a/src/games/robots/query.c b/src/games/robots/query.c new file mode 100644 index 0000000..2624829 --- /dev/null +++ b/src/games/robots/query.c @@ -0,0 +1,33 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +#ifndef lint +static char sccsid[] = "@(#)query.c 5.1 (Berkeley) 5/30/85"; +#endif not lint + +# include "robots.h" + +/* + * query: + * Ask a question and get a yes or no answer. Default is "no". + */ +query(prompt) +char *prompt; +{ + register int c, retval; + register int y, x; + + getyx(stdscr, y, x); + move(Y_PROMPT, X_PROMPT); + addstr(prompt); + clrtoeol(); + refresh(); + retval = ((c = getchar()) == 'y' || c == 'Y'); + move(Y_PROMPT, X_PROMPT); + clrtoeol(); + move(y, x); + return retval; +} diff --git a/src/games/robots/rnd_pos.c b/src/games/robots/rnd_pos.c new file mode 100644 index 0000000..9706e0d --- /dev/null +++ b/src/games/robots/rnd_pos.c @@ -0,0 +1,41 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +#ifndef lint +static char sccsid[] = "@(#)rnd_pos.c 5.1 (Berkeley) 5/30/85"; +#endif not lint + +# include "robots.h" + +# define IS_SAME(p,y,x) ((p).y != -1 && (p).y == y && (p).x == x) + +/* + * rnd_pos: + * Pick a random, unoccupied position + */ +COORD * +rnd_pos() +{ + static COORD pos; + static int call = 0; + register int i = 0; + + do { + pos.y = rnd(Y_FIELDSIZE - 1) + 1; + pos.x = rnd(X_FIELDSIZE - 1) + 1; + refresh(); + } while (Field[pos.y][pos.x] != 0); + call++; + return &pos; +} + +rnd(range) +int range; +{ + unsigned int rand(); + + return rand() % range; +} diff --git a/src/games/robots/robots.6 b/src/games/robots/robots.6 new file mode 100644 index 0000000..46b4c9b --- /dev/null +++ b/src/games/robots/robots.6 @@ -0,0 +1,130 @@ +.\" Copyright (c) 1980 Regents of the University of California. +.\" All rights reserved. The Berkeley software License Agreement +.\" specifies the terms and conditions for redistribution. +.\" +.\" @(#)robots.6 6.1 (Berkeley) 5/20/85 +.\" +.TH ROBOTS 6 "May 20, 1985" +.UC 6 +.SH NAME +robots \- fight off villainous robots +.SH SYNOPSIS +.B /usr/games/robots +[ +.B \-sjta +] [ +.B scorefile +] +.SH DESCRIPTION +.I Robots +pits you against evil robots, +who are trying to kill you +(which is why they are evil). +Fortunately for you, +even though they are evil, +they are not very bright +and have a habit of bumping into each other, +thus destroying themselves. +In order to survive, +you must get them to kill each other off, +since you have no offensive weaponry. +.PP +Since you are stuck without offensive weaponry, +you are endowed with one piece of defensive weaponry: +a teleportation device. +When two robots run into each other or a junk pile, +they die. +If a robot runs into you, +you die. +When a robot dies, you get 10 points, +and when all the robots die, +you start on the next field. +This keeps up until they finally get you. +.PP +Robots are represented on the screen by a +.RB ` + ', +the junk heaps from their collisions by a +.RB ` \(** ', +and you +(the good guy) +by a +.RB ` @ '. +.PP +The commands are: +.sp +.nf +.ta +.ta \w'\fBHJKLBNYU\fP\ \ 'u +\fBh\fP move one square left +\fBl\fP move one square right +\fBk\fP move one square up +\fBj\fP move one square down +\fBy\fP move one square up and left +\fBu\fP move one square up and right +\fBb\fP move one square down and left +\fBn\fP move one square down and right +\fB\&.\fP (also space) do nothing for one turn +\fBHJKLBNYU\fP run as far as possible in the given direction +\fB>\fP do nothing for as long as possible +\fBt\fP teleport to a random location +\fBw\fP wait until you die or they all do +\fBq\fP quit +\fB^L\fP redraw the screen +.sp +.fi +All commands can be preceded by a count. +.PP +If you use the +.RB ` w ' +command and survive to the next level, +you will get a bonus of 10% +for each robot which died after you decided to wait. +If you die, however, you get nothing. +For all other commands, +the program will save you from typos +by stopping short of being eaten. +However, +with +.RB ` w ' +you take the risk of dying by miscalculation. +.PP +Only five scores are allowed per user on the score file. +If you make it into the score file, +you will be shown the list at the end of the game. +If an alternate score file is specified, +that will be used instead of the standard file +for scores. +.PP +The options are +.TP +.B \-s +Don't play, +just show the score file +.TP +.B \-j +Jump, +.IR i.e. , +when you run, +don't show any intermediate positions; +only show things at the end. +This is useful on slow terminals. +.TP +.B \-t +Teleport automatically when you have no other option. +This is a little disconcerting until you get used to it, +and then it is very nice. +.TP +.B \-a +Advance into the higher levels directly, +skipping the lower, easier levels. +.SH AUTHOR +Ken Arnold +.SH FILES +.ta +.ta \w'/usr/games/lib/robots_roll\ \ \ \ 'u +/usr/games/lib/robots_roll the score file +.SH BUGS +Bugs? +You +.IR crazy , +man?!? diff --git a/src/games/robots/robots.h b/src/games/robots/robots.h new file mode 100644 index 0000000..de93fd4 --- /dev/null +++ b/src/games/robots/robots.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + * + * @(#)robots.h 5.1 (Berkeley) 5/30/85 + */ + +# include +# include + +/* + * miscellaneous constants + */ + +# define Y_FIELDSIZE 23 +# define X_FIELDSIZE 60 +# define Y_SIZE 24 +# define X_SIZE 80 +# define MAXLEVELS 4 +# define MAXROBOTS (MAXLEVELS * 10) +# define ROB_SCORE 10 +# define S_BONUS (60 * ROB_SCORE) +# define Y_SCORE 21 +# define X_SCORE (X_FIELDSIZE + 9) +# define Y_PROMPT (Y_FIELDSIZE - 1) +# define X_PROMPT (X_FIELDSIZE + 2) +# define MAXSCORES (Y_SIZE - 2) +# define MAXNAME 16 +# define MS_NAME "Ten" +# define SCOREFILE "/usr/games/lib/robots_roll" + +/* + * characters on screen + */ + +# define ROBOT '+' +# define HEAP '*' +# define PLAYER '@' + +/* + * pseudo functions + */ + +# undef CTRL +# define CTRL(X) ('X' - 'A' + 1) + +/* + * type definitions + */ + +typedef struct { + int y, x; +} COORD; + +/* + * global variables + */ + +extern bool Dead, Full_clear, Jump, Newscore, Real_time, Running, + Teleport, Waiting, Was_bonus; + +#ifdef FANCY +extern bool Pattern_roll, Stand_still; +#endif + +extern char Cnt_move, Field[Y_FIELDSIZE][X_FIELDSIZE], *Next_move, + *Move_list, Run_ch; + +extern int Count, Level, Num_robots, Num_scores, Score, + Start_level, Wait_bonus; + +extern COORD Max, Min, My_pos, Robots[]; + +extern jmp_buf End_move; + +/* + * functions types + */ + +int quit(), cmp_sc(), move_robots(); + +COORD *rnd_pos(); diff --git a/src/games/robots/score.c b/src/games/robots/score.c new file mode 100644 index 0000000..31e0ed7 --- /dev/null +++ b/src/games/robots/score.c @@ -0,0 +1,155 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +#ifndef lint +static char sccsid[] = "@(#)score.c 5.1 (Berkeley) 5/30/85"; +#endif not lint + +# include "robots.h" +# include + +typedef struct { + int s_uid; + int s_score; + char s_name[MAXNAME]; +} SCORE; + +typedef struct passwd PASSWD; + +char *Scorefile = SCOREFILE; + +int Max_per_uid = MAX_PER_UID; + +static SCORE Top[MAXSCORES]; + +/* + * score: + * Post the player's score, if reasonable, and then print out the + * top list. + */ +score() +{ + register int inf; + register SCORE *scp; + register int uid; + register bool done_show = FALSE; + static int numscores, max_uid; + + Newscore = FALSE; + if ((inf = open(Scorefile, 2)) < 0) { + perror(Scorefile); + return; + } + + if (read(inf, &max_uid, sizeof max_uid) == sizeof max_uid) + read(inf, Top, sizeof Top); + else { + for (scp = Top; scp < &Top[MAXSCORES]; scp++) + scp->s_score = -1; + max_uid = Max_per_uid; + } + + uid = getuid(); + if (Top[MAXSCORES-1].s_score <= Score) { + numscores = 0; + for (scp = Top; scp < &Top[MAXSCORES]; scp++) + if (scp->s_score < 0 || + (scp->s_uid == uid && ++numscores == max_uid)) { + if (scp->s_score > Score) + break; + scp->s_score = Score; + scp->s_uid = uid; + set_name(scp); + Newscore = TRUE; + break; + } + if (scp == &Top[MAXSCORES]) { + Top[MAXSCORES-1].s_score = Score; + Top[MAXSCORES-1].s_uid = uid; + set_name(&Top[MAXSCORES-1]); + Newscore = TRUE; + } + if (Newscore) + qsort(Top, MAXSCORES, sizeof Top[0], cmp_sc); + } + + if (!Newscore) { + Full_clear = FALSE; + close(inf); + return; + } + else + Full_clear = TRUE; + + for (scp = Top; scp < &Top[MAXSCORES]; scp++) { + if (scp->s_score < 0) + break; + move((scp - Top) + 1, 15); + if (!done_show && scp->s_uid == uid && scp->s_score == Score) + standout(); + printw(" %d\t%d\t%-8.8s ", (scp - Top) + 1, scp->s_score, scp->s_name); + if (!done_show && scp->s_uid == uid && scp->s_score == Score) { + standend(); + done_show = TRUE; + } + } + Num_scores = scp - Top; + refresh(); + + if (Newscore) { + lseek(inf, 0L, 0); + write(inf, &max_uid, sizeof max_uid); + write(inf, Top, sizeof Top); + } + close(inf); +} + +set_name(scp) +register SCORE *scp; +{ + register PASSWD *pp; + + if ((pp = getpwuid(scp->s_uid)) == NULL) + pp->pw_name = "???"; + strncpy(scp->s_name, pp->pw_name, MAXNAME); +} + +/* + * cmp_sc: + * Compare two scores. + */ +cmp_sc(s1, s2) +register SCORE *s1, *s2; +{ + return s2->s_score - s1->s_score; +} + +/* + * show_score: + * Show the score list for the '-s' option. + */ +show_score() +{ + register SCORE *scp; + register int inf; + static int max_score; + + if ((inf = open(Scorefile, 0)) < 0) { + perror(Scorefile); + return; + } + + for (scp = Top; scp < &Top[MAXSCORES]; scp++) + scp->s_score = -1; + + read(inf, &max_score, sizeof max_score); + read(inf, Top, sizeof Top); + close(inf); + inf = 1; + for (scp = Top; scp < &Top[MAXSCORES]; scp++) + if (scp->s_score >= 0) + printf("%d\t%d\t%.*s\n", inf++, scp->s_score, sizeof scp->s_name, scp->s_name); +} diff --git a/src/games/rogue/CHANGES b/src/games/rogue/CHANGES new file mode 100644 index 0000000..73a7135 --- /dev/null +++ b/src/games/rogue/CHANGES @@ -0,0 +1,53 @@ +From: tektronix!zeus.TEK.COM!tims@ucbvax.Berkeley.EDU +Date: 30 Nov 87 15:08:15 PST (Mon) +To: okeeffe.Berkeley.EDU!mckusick@ucbvax.Berkeley.EDU (Kirk McKusick) +Subject: Re: Public domain rogue +Return-Path: tektronix!zeus.TEK.COM!tims@ucbvax.Berkeley.EDU + +Here is a list of discrepencies from the documentation you sent me: + +The -d option not implemented. +The -r option not implemented, use "rogue save_file" instead. +Strength is between 1 and 99, not 3 and 32. +The D command is not implemented. +Only scrolls,potions,wands,and rings may be "call"ed something. +The ^P command may be used to go 4 messages back, instead of just 1. +The @ comand is not implemented. +There are no dark rooms. +ROGUEOPTS of flush,terse,seefloor,askme,inventory are ignored. + 'askquit' is added to prevent ^\ from terminating the game accidentally. + If 'noaskquit' is + found in the ROGUEOPTS string, the the ^\ kills the game, otherwise, + the player is asked if he really wants to quit. In either case, no + score file processing is attempted. +The score is keyed to winning scores, and no player may appear twice. + + + + + + +Other differences from "standard" rogue 5.3. This list covers externally +visible differences only. + +There should be NO bugs with any severe consequences. Absolutely NO + game-stopping, or game-winning bugs should be present. +Traps fail occasionally, that is, they sometimes are sprung but miss. +The ^A command prints out some stuff you're probably not interested in. +The '&' command silently saves your screen into the file 'rogue.screen' +Any inventory selection command that takes '*' as a request to list all + appropriate items, can take one of "=?:)]!/" to list only rings, + scrolls, or whatever. +Scrolls and potions, once used, become identified. All other objects become + identified only by scroll of identification. +There is only one scroll of identification, and it works on any item. +ROGUEOPTS + Only the following are implemented: + file,jump,name,askquit,tombstone,passgo + "askquit" is used to prevent accidental termination of the game via ^\ +You may drop objects in doorways. +Prints a picture of a skull, not a tombstone, upon death. +The save/restore game function is faster and machine-independent, but sometimes + requires modification when new variables are added to the source. +The potion of detect monster lasts for the whole level. +Their is no wand of light. diff --git a/src/games/rogue/Makefile b/src/games/rogue/Makefile new file mode 100644 index 0000000..a6ed33a --- /dev/null +++ b/src/games/rogue/Makefile @@ -0,0 +1,63 @@ +# +# Copyright (c) 1987 Regents of the University of California. +# All rights reserved. +# +# Redistribution and use in source and binary forms are permitted +# provided that this notice is preserved and that due credit is given +# to the University of California at Berkeley. The name of the University +# may not be used to endorse or promote products derived from this +# software without specific written prior permission. This software +# is provided ``as is'' without express or implied warranty. +# +TOPSRC = $(shell cd ../../..; pwd) +include $(TOPSRC)/target.mk + +CFLAGS += -mips16 +CFLAGS += -Os -DUNIX -DUNIX_BSD4_2 -DCURSES -DANSI -Werror -Wall + +OBJS = curses.o \ + doprnt.o \ + hit.o \ + init.o \ + inventory.o \ + level.o \ + machdep.o \ + main.o \ + message.o \ + monster.o \ + move.o \ + object.o \ + pack.o \ + play.o \ + random.o \ + ring.o \ + room.o \ + save.o \ + score.o \ + spec_hit.o \ + throw.o \ + trap.o \ + use.o \ + zap.o +MAN = rogue.0 +MANSRC = rogue.6 + +all: rogue $(MAN) + +rogue: ${OBJS} + ${CC} ${LDFLAGS} -o rogue.elf ${OBJS} ${LIBS} + ${OBJDUMP} -S rogue.elf > rogue.dis + ${SIZE} rogue.elf + ${ELF2AOUT} rogue.elf $@ && rm rogue.elf + +${MAN}: ${MANSRC} + ${MANROFF} $< > $@ + +clean: + rm -f *.o *.0 *.elf ${MAN} rogue *.elf *.dis tags *~ + +install: all + install rogue $(DESTDIR)/games/ + cp ${MAN} $(DESTDIR)/share/man/cat6/ + +#$(OBJS): rogue.h diff --git a/src/games/rogue/Makefile-linux b/src/games/rogue/Makefile-linux new file mode 100644 index 0000000..22871f3 --- /dev/null +++ b/src/games/rogue/Makefile-linux @@ -0,0 +1,46 @@ +# +# Copyright (c) 1987 Regents of the University of California. +# All rights reserved. +# +# Redistribution and use in source and binary forms are permitted +# provided that this notice is preserved and that due credit is given +# to the University of California at Berkeley. The name of the University +# may not be used to endorse or promote products derived from this +# software without specific written prior permission. This software +# is provided ``as is'' without express or implied warranty. +# +CFLAGS = -DUNIX -DUNIX_SYSV -Werror -Wall -DCROSS -g -O0 +LDFLAGS = -g +LIBS = -lncurses + +OBJS = curses.o \ + hit.o \ + init.o \ + inventory.o \ + level.o \ + machdep.o \ + main.o \ + message.o \ + monster.o \ + move.o \ + object.o \ + pack.o \ + play.o \ + random.o \ + ring.o \ + room.o \ + save.o \ + score.o \ + spec_hit.o \ + throw.o \ + trap.o \ + use.o \ + zap.o + +all: rogue + +rogue: ${OBJS} + ${CC} ${LDFLAGS} -o $@ ${OBJS} ${LIBS} + +clean: + rm -f *.o rogue *~ diff --git a/src/games/rogue/curses.c b/src/games/rogue/curses.c new file mode 100644 index 0000000..55bd755 --- /dev/null +++ b/src/games/rogue/curses.c @@ -0,0 +1,688 @@ +/* + * This source herein may be modified and/or distributed by anybody who + * so desires, with the following restrictions: + * 1.) No portion of this notice shall be removed. + * 2.) Credit shall not be taken for the creation of this source. + * 3.) This code is not to be traded, sold, or used for personal + * gain or profit. + */ +#ifdef CURSES + +/* The following is a curses emulation package suitable for the rogue program + * in which it is included. No other suitability is claimed or suspected. + * Only those routines currently needed by this rogue program are included. + * This is being provided for those systems that don't have a suitable + * curses package and want to run this rogue program. + * + * Compile the entire program with -DCURSES to incorporate this package. + * + * The following is NOT supported: + * "%D", "%B", "%n", or "%>" inside a cursor motion (cm) termcap string. + * Terminals in which the cursor motion addresses the row differently from + * the column, as in ":cm=\E%2,%3" or ":cm=\EY%+x;%+y" + * Termcap database stored in the TERMCAP environ variable as returned + * from md_getenv(). Only the termcap file name can be stored there. + * See the comments for md_getenv() in machdep.c. + * Terminals without non-destructive backspace. Backspace (^H) is used + * for cursor motion regardless of any termcap entries. + * The ":tc=" termcap entry is ignored. + * + * Suggestions: + * Use line-feed as your termcap "do" entry: ":do=^J", ":do=\012" or + * ":do=\n" This will help cursor motion optimization. If line-feed + * won't work, then a short escape sequence will do. + */ +#include +#include "rogue.h" + +#define BS 010 +#define LF 012 +#define CR 015 +#define ESC '\033' +#define TAB '\011' + +#define ST_MASK 0x80 + +char terminal[DROWS][DCOLS]; +char buffer[DROWS][DCOLS]; + +char cm_esc[16]; +char cm_sep[16]; +char cm_end[16]; +boolean cm_reverse = 0; +boolean cm_two = 0; +boolean cm_three = 0; +boolean cm_char = 0; +short cm_inc = 0; + +boolean screen_dirty; +boolean lines_dirty[DROWS]; +boolean buf_stand_out = 0; +boolean term_stand_out = 0; + +int LINES = DROWS; +int COLS = DCOLS; +WINDOW scr_buf; +WINDOW *curscr = &scr_buf; + +char *CL = (char *) 0; +char *CM = (char *) 0; +char *UC = (char *) 0; /* UP */ +char *DO = (char *) 0; +char *VS = ""; +char *VE = ""; +char *TI = ""; +char *TE = ""; +char *SO = ""; +char *SE = ""; + +short cur_row; +short cur_col; + +#ifndef ANSI +#define BUFLEN 256 + +static boolean +tc_tname(fp, term, buf) + FILE *fp; + char *term; + char *buf; +{ + int i, j; + boolean found = 0; + char *fg; + + while (!found) { + i = 0; + fg = fgets(buf, BUFLEN, fp); + if (fg != NULL) { + if ((buf[0] != '#') && (buf[0] != ' ') && (buf[0] != TAB) && + (buf[0] != CR) && (buf[0] != LF)) + { + while (buf[i] && (!found)) { + j = 0; + while (buf[i] == term[j]) { + i++; + j++; + } + if ((!term[j]) && ((buf[i] == '|') || (buf[i] == ':'))) { + found = 1; + } else { + while (buf[i] && (buf[i] != '|') && (buf[i] != ':')) { + i++; + } + if (buf[i]) { + i++; + } + } + } + } + } else { + break; + } + } + return(found); +} + +static void +tc_gets(ibuf, tcstr) + char *ibuf; + char **tcstr; +{ + int i, j, k, n; + char obuf[BUFLEN]; + + i = 4; + j = 0; + + while (ibuf[i] && is_digit(ibuf[i])) { + i++; + } + + while (ibuf[i] && (ibuf[i] != ':')) { + if (ibuf[i] == '\\') { + i++; + switch(ibuf[i]) { + case 'E': + obuf[j] = ESC; + i++; + break; + case 'n': + obuf[j] = LF; + i++; + break; + case 'r': + obuf[j] = CR; + i++; + break; + case 'b': + obuf[j] = BS; + i++; + break; + case 't': + obuf[j] = TAB; + i++; + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + n = 0; + k = 0; + while (k < 3 && ibuf[i] && is_digit(ibuf[i])) { + n = (8 * n) + (ibuf[i] - '0'); + i++; + k++; + } + obuf[j] = (char) n; + break; + default: + obuf[j] = ibuf[i]; + i++; + } + } else if (ibuf[i] == '^') { + obuf[j] = ibuf[i+1] - 64; + i += 2; + } else { + obuf[j] = ibuf[i++]; + } + j++; + } + obuf[j] = 0; + if (!(*tcstr = md_malloc(j + 1))) { + clean_up("cannot alloc() memory"); + } + (void) strcpy(*tcstr, obuf); +} + +static void +tc_gnum(ibuf, n) + char *ibuf; + int *n; +{ + int i, r = 0; + + i = 4; + + while (is_digit(ibuf[i])) { + r = (r * 10) + (ibuf[i] - '0'); + i++; + } + *n = r; +} + +static void +tc_cmget() +{ + int i = 0, j = 0, rc_spec = 0; + + while (CM[i] && (CM[i] != '%') && (j < 15)) { + cm_esc[j++] = CM[i++]; + } + cm_esc[j] = 0; + + while (CM[i] && (rc_spec < 2)) { + if (CM[i] == '%') { + i++; + switch(CM[i]) { + case 'd': + rc_spec++; + break; + case 'i': + cm_inc = 1; + break; + case '2': + cm_two = 1; + rc_spec++; + break; + case '3': + cm_three = 1; + rc_spec++; + break; + case '.': + cm_char = 1; + rc_spec++; + break; + case 'r': + cm_reverse = 1; + break; + case '+': + i++; + cm_inc = CM[i]; + cm_char = 1; + rc_spec++; + break; + } + i++; + } else { + j = 0; + while (CM[i] && (CM[i] != '%')) { + cm_sep[j++] = CM[i++]; + } + cm_sep[j] = 0; + } + } + + j = 0; + if (rc_spec == 2) { + while (CM[i] && (j < 15)) { + cm_end[j++] = CM[i++]; + } + } + cm_end[j] = 0; +} + +static void +tc_gtdata(fp, buf) + FILE *fp; + char *buf; +{ + int i; + boolean first = 1; + + do { + if (!first) { + if ((buf[0] != TAB) && (buf[0] != ' ')) { + break; + } + } + first = 0; + i = 0; + while (buf[i]) { + while (buf[i] && (buf[i] != ':')) { + i++; + } + if (buf[i] == ':') { + if (!strncmp(buf + i, ":cl=", 4)) { + tc_gets(buf + i, &CL); + } else if (!strncmp(buf + i, ":cm=", 4)) { + tc_gets(buf + i, &CM); + } else if (!strncmp(buf + i, ":up=", 4)) { + tc_gets(buf + i, &UC); + } else if (!strncmp(buf + i, ":do=", 4)) { + tc_gets(buf + i, &DO); + } else if (!strncmp(buf + i, ":vs=", 4)) { + tc_gets(buf + i, &VS); + } else if (!strncmp(buf + i, ":ve=", 4)) { + tc_gets(buf + i, &VE); + } else if (!strncmp(buf + i, ":ti=", 4)) { + tc_gets(buf + i, &TI); + } else if (!strncmp(buf + i, ":te=", 4)) { + tc_gets(buf + i, &TE); + } else if (!strncmp(buf + i, ":so=", 4)) { + tc_gets(buf + i, &SO); + } else if (!strncmp(buf + i, ":se=", 4)) { + tc_gets(buf + i, &SE); + } else if (!strncmp(buf + i, ":li#", 4)) { + tc_gnum(buf + i, &LINES); + } else if (!strncmp(buf + i, ":co#", 4)) { + tc_gnum(buf + i, &COLS); + } + i++; + } + } + } while (fgets(buf, BUFLEN, fp) != NULL); + + if ((!CM) || (!CL)) { + clean_up("Terminal and termcap must have cm and cl"); + } + tc_cmget(); +} +#endif /* ANSI */ + +static void +get_term_info() +{ +#ifdef ANSI + /* Generic ANSI display. */ + LINES = DROWS; + COLS = DCOLS; + + CL = "\33[H\33[2J"; + UC = "\33[A"; + DO = "\12"; + SO = "\33[7m"; + SE = "\33[m"; + + cm_inc = 1; + strcpy (cm_esc, "\33["); + strcpy (cm_sep, ";"); + strcpy (cm_end, "H"); +#else + FILE *fp; + char *term, *tcf; + char buf[BUFLEN]; + char *tc_file = "/etc/termcap"; + + tcf = md_getenv("TERMCAP"); + if (tcf) { + if (strlen(tcf) > 40) { + clean_up("TERMCAP file name too long"); + } + tc_file = tcf; + } + + term = md_getenv("TERM"); + if (! term) { + clean_up("Cannot find TERM variable in environ"); + } + fp = fopen(tc_file, "r"); + if (! fp) { + sprintf(buf, "Cannot open TERMCAP file: %s", tc_file); + clean_up(buf); + } + + if (! tc_tname(fp, term, buf)) { + sprintf(buf, "Cannot find TERM type: %s in TERMCAP file: %s", term, + tc_file); + clean_up(buf); + } + tc_gtdata(fp, buf); + fclose(fp); +#endif +} + +void +initscr() +{ + clear(); + get_term_info(); + printf("%s%s", TI, VS); +} + +void +endwin() +{ + printf("%s%s", TE, VE); + md_cbreak_no_echo_nonl(0); +} + +void +move(row, col) + int row, col; +{ + curscr->_cury = row; + curscr->_curx = col; + screen_dirty = 1; +} + +void +mvaddstr(row, col, str) + int row, col; + char *str; +{ + move(row, col); + addstr(str); +} + +void +addstr(str) + char *str; +{ + while (*str) { + addch((int) *str++); + } +} + +void +addch(ch) + register int ch; +{ + int row, col; + + row = curscr->_cury; + col = curscr->_curx++; + + if (buf_stand_out) { + ch |= ST_MASK; + } + buffer[row][col] = (char) ch; + lines_dirty[row] = 1; + screen_dirty = 1; +} + +void +mvaddch(row, col, ch) + int row, col, ch; +{ + move(row, col); + addch(ch); +} + +static void +put_st_char(ch) + register int ch; +{ + if ((ch & ST_MASK) && (!term_stand_out)) { + ch &= ~ST_MASK; + printf("%s%c", SO, ch); + term_stand_out = 1; + } else if ((!(ch & ST_MASK)) && term_stand_out) { + printf("%s%c", SE, ch); + term_stand_out = 0; + } else { + ch &= ~ST_MASK; + putchar(ch); + } +} + +static void +put_cursor(row, col) + register int row, col; +{ + register int i, rdif, cdif; + int ch, t; + + rdif = (row > cur_row) ? row - cur_row : cur_row - row; + cdif = (col > cur_col) ? col - cur_col : cur_col - col; + + if (((row > cur_row) && DO) || ((cur_row > row) && UC)) { + if ((rdif < 4) && (cdif < 4)) { + for (i = 0; i < rdif; i++) { + printf("%s", ((row < cur_row) ? UC : DO)); + } + cur_row = row; + if (col == cur_col) { + return; + } + } + } + if (row == cur_row) { + if (cdif <= 6) { + for (i = 0; i < cdif; i++) { + ch = (col < cur_col) ? BS : + terminal[row][cur_col + i]; + put_st_char((int) ch); + } + cur_row = row; + cur_col = col; + return; + } + } + cur_row = row; + cur_col = col; + + row += cm_inc; + col += cm_inc; + + if (cm_reverse) { + t = row; + row = col; + col = t; + } + if (cm_two) { + printf("%s%02d%s%02d%s", cm_esc, row, cm_sep, col, cm_end); + } else if (cm_three) { + printf("%s%03d%s%03d%s", cm_esc, row, cm_sep, col, cm_end); + } else if (cm_char) { + printf("%s%c%s%c%s", cm_esc, row, cm_sep, col, cm_end); + } else { + printf("%s%d%s%d%s", cm_esc, row, cm_sep, col, cm_end); + } +} + +static void +put_char_at(row, col, ch) + register int row, col, ch; +{ + put_cursor(row, col); + put_st_char(ch); + terminal[row][col] = (char) ch; + cur_col++; +} + +void +refresh() +{ + register int i, j, line; + int old_row, old_col, first_row; + + if (screen_dirty) { + + old_row = curscr->_cury; + old_col = curscr->_curx; + first_row = cur_row; + + for (i = 0; i < DROWS; i++) { + line = (first_row + i) % DROWS; + if (lines_dirty[line]) { + for (j = 0; j < DCOLS; j++) { + if (buffer[line][j] != terminal[line][j]) { + put_char_at(line, j, buffer[line][j]); + } + } + lines_dirty[line] = 0; + } + } + put_cursor(old_row, old_col); + screen_dirty = 0; + fflush(stdout); + } +} + +void +wrefresh(scr) + WINDOW *scr; +{ + int i, col; + + printf("%s", CL); + cur_row = cur_col = 0; + + for (i = 0; i < DROWS; i++) { + col = 0; + while (col < DCOLS) { + while ((col < DCOLS) && (buffer[i][col] == ' ')) { + col++; + } + if (col < DCOLS) { + put_cursor(i, col); + } + while ((col < DCOLS) && (buffer[i][col] != ' ')) { + put_st_char((int) buffer[i][col]); + cur_col++; + col++; + } + } + } + put_cursor(curscr->_cury, curscr->_curx); + fflush(stdout); + scr = scr; /* make lint happy */ +} + +int +mvinch(row, col) + int row, col; +{ + move(row, col); + return((int) buffer[row][col]); +} + +static void +clear_buffers() +{ + register int i, j; + + screen_dirty = 0; + + for (i = 0; i < DROWS; i++) { + lines_dirty[i] = 0; + for (j = 0; j < DCOLS; j++) { + terminal[i][j] = ' '; + buffer[i][j] = ' '; + } + } +} + +void +clear() +{ + printf("%s", CL); + fflush(stdout); + cur_row = cur_col = 0; + move(0, 0); + clear_buffers(); +} + +void +clrtoeol() +{ + int row, col; + + row = curscr->_cury; + + for (col = curscr->_curx; col < DCOLS; col++) { + buffer[row][col] = ' '; + } + lines_dirty[row] = 1; +} + +void +standout() +{ + buf_stand_out = 1; +} + +void +standend() +{ + buf_stand_out = 0; +} + +void +crmode() +{ + md_cbreak_no_echo_nonl(1); +} + +void +noecho() +{ + /* crmode() takes care of this */ +} + +void +nonl() +{ + /* crmode() takes care of this */ +} + +void +tstp() +{ + endwin(); + md_tstp(); + + start_window(); + printf("%s%s", TI, VS); + wrefresh(curscr); + md_slurp(); +} + +#endif /* CURSES */ diff --git a/src/games/rogue/doprnt.c b/src/games/rogue/doprnt.c new file mode 100644 index 0000000..c5ed28d --- /dev/null +++ b/src/games/rogue/doprnt.c @@ -0,0 +1,203 @@ +/* +Copyright (c) 2013, Alexey Frunze +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +The views and conclusions contained in the software and documentation are those +of the authors and should not be interpreted as representing official policies, +either expressed or implied, of the FreeBSD Project. +*/ + +#include +#include +#include + +int _doprnt (char const *fmt, va_list pp, FILE *stream) +{ + int cnt = 0; + const char* p; + const char* phex = "0123456789abcdef"; + char s[1/*sign*/+10/*magnitude*/+1/*\0*/]; // up to 11 octal digits in 32-bit numbers + char* pc; + int n, sign, msign; + int minlen = 0, len; + int leadchar; + + for (p = fmt; *p != '\0'; p++) + { + if (*p != '%' || p[1] == '%') + { + fputc(*p, stream); + p = p + (*p == '%'); + cnt++; + continue; + } + p++; + minlen = 0; + msign = 0; + if (*p == '+') { msign = 1; p++; } + else if (*p == '-') { msign = -1; p++; } + leadchar = ' '; + if (*p >= '0' && *p <= '9') + { + if (*p == '0') + leadchar = '0'; + while (*p >= '0' && *p <= '9') + minlen = minlen * 10 + *p++ - '0'; + if (msign < 0) + minlen = -minlen; + msign = 0; + } + if (!msign) + { + if (*p == '+') { msign = 1; p++; } + else if (*p == '-') { msign = -1; p++; } + } + switch (*p) + { + case 'c': + while (minlen > 1) { fputc(' ', stream); cnt++; minlen--; } + fputc(va_arg(pp, int), stream); + while (-minlen > 1) { fputc(' ', stream); cnt++; minlen++; } + cnt++; + break; + case 's': + pc = va_arg(pp, char*); + len = 0; + if (pc) + len = strlen(pc); + while (minlen > len) { fputc(' ', stream); cnt++; minlen--; } + if (len) + while (*pc != '\0') + { + fputc(*pc++, stream); + cnt++; + } + while (-minlen > len) { fputc(' ', stream); cnt++; minlen++; } + break; + case 'i': + case 'd': + pc = &s[sizeof s - 1]; + *pc = '\0'; + len = 0; + n = va_arg(pp, int); + sign = 1 - 2 * (n < 0); + do + { + *--pc = '0' + (n - n / 10 * 10) * sign; + n = n / 10; + len++; + } while (n); + if (sign < 0) + { + *--pc = '-'; + len++; + } + else if (msign > 0) + { + *--pc = '+'; + len++; + msign = 0; + } + while (minlen > len) { fputc(leadchar, stream); cnt++; minlen--; } + while (*pc != '\0') + { + fputc(*pc++, stream); + cnt++; + } + while (-minlen > len) { fputc(' ', stream); cnt++; minlen++; } + break; + case 'u': + pc = &s[sizeof s - 1]; + *pc = '\0'; + len = 0; + n = va_arg(pp, int); + do + { + unsigned nn = n; + *--pc = '0' + nn % 10; + n = nn / 10; + len++; + } while (n); + if (msign > 0) + { + *--pc = '+'; + len++; + msign = 0; + } + while (minlen > len) { fputc(leadchar, stream); cnt++; minlen--; } + while (*pc != '\0') + { + fputc(*pc++, stream); + cnt++; + } + while (-minlen > len) { fputc(' ', stream); cnt++; minlen++; } + break; + case 'X': + phex = "0123456789ABCDEF"; + // fallthrough + case 'p': + case 'x': + pc = &s[sizeof s - 1]; + *pc = '\0'; + len = 0; + n = va_arg(pp, int); + do + { + *--pc = phex[n & 0xF]; + n = (n >> 4) & ((1 << (8 * sizeof n - 4)) - 1); // drop sign-extended bits + len++; + } while (n); + while (minlen > len) { fputc(leadchar, stream); cnt++; minlen--; } + while (*pc != '\0') + { + fputc(*pc++, stream); + cnt++; + } + while (-minlen > len) { fputc(' ', stream); cnt++; minlen++; } + break; + case 'o': + pc = &s[sizeof s - 1]; + *pc = '\0'; + len = 0; + n = va_arg(pp, int); + do + { + *--pc = '0' + (n & 7); + n = (n >> 3) & ((1 << (8 * sizeof n - 3)) - 1); // drop sign-extended bits + len++; + } while (n); + while (minlen > len) { fputc(leadchar, stream); cnt++; minlen--; } + while (*pc != '\0') + { + fputc(*pc++, stream); + cnt++; + } + while (-minlen > len) { fputc(' ', stream); cnt++; minlen++; } + break; + default: + return -1; + } + } + + return cnt; +} diff --git a/src/games/rogue/hit.c b/src/games/rogue/hit.c new file mode 100644 index 0000000..98851b7 --- /dev/null +++ b/src/games/rogue/hit.c @@ -0,0 +1,423 @@ +/* + * This source herein may be modified and/or distributed by anybody who + * so desires, with the following restrictions: + * 1.) No portion of this notice shall be removed. + * 2.) Credit shall not be taken for the creation of this source. + * 3.) This code is not to be traded, sold, or used for personal + * gain or profit. + */ +#include +#include "rogue.h" + +object *fight_monster = 0; +char hit_message[80] = ""; + +void +mon_hit(monster) + register object *monster; +{ + int damage, hit_chance; + char *mn; + float minus; + + if (fight_monster && (monster != fight_monster)) { + fight_monster = 0; + } + monster->trow = NO_ROOM; + if (cur_level >= (AMULET_LEVEL * 2)) { + hit_chance = 100; + } else { + hit_chance = monster->m_hit_chance; + hit_chance -= (((2 * rogue.exp) + (2 * ring_exp)) - r_rings); + } + if (wizard) { + hit_chance /= 2; + } + if (!fight_monster) { + interrupted = 1; + } + mn = mon_name(monster); + + if (!rand_percent(hit_chance)) { + if (!fight_monster) { + sprintf(hit_message + strlen(hit_message), "the %s misses", mn); + message(hit_message, 1); + hit_message[0] = 0; + } + return; + } + if (!fight_monster) { + sprintf(hit_message + strlen(hit_message), "the %s hit", mn); + message(hit_message, 1); + hit_message[0] = 0; + } + if (!(monster->m_flags & STATIONARY)) { + damage = get_damage(monster->m_damage, 1); + if (cur_level >= (AMULET_LEVEL * 2)) { + minus = (float) ((AMULET_LEVEL * 2) - cur_level); + } else { + minus = (float) get_armor_class(rogue.armor) * 3.00; + minus = minus/100.00 * (float) damage; + } + damage -= (int) minus; + } else { + damage = monster->stationary_damage++; + } + if (wizard) { + damage /= 3; + } + if (damage > 0) { + rogue_damage(damage, monster, 0); + } + if (monster->m_flags & SPECIAL_HIT) { + special_hit(monster); + } +} + +void +rogue_hit(monster, force_hit) + register object *monster; + boolean force_hit; +{ + int damage, hit_chance; + + if (monster) { + if (check_imitator(monster)) { + return; + } + hit_chance = force_hit ? 100 : get_hit_chance(rogue.weapon); + + if (wizard) { + hit_chance *= 2; + } + if (!rand_percent(hit_chance)) { + if (!fight_monster) { + (void) strcpy(hit_message, "you miss "); + } + goto RET; + } + damage = get_weapon_damage(rogue.weapon); + if (wizard) { + damage *= 3; + } + if (con_mon) { + s_con_mon(monster); + } + if (mon_damage(monster, damage)) { /* still alive? */ + if (!fight_monster) { + (void) strcpy(hit_message, "you hit "); + } + } +RET: check_gold_seeker(monster); + wake_up(monster); + } +} + +void +rogue_damage(d, monster, other) + int d; + object *monster; + int other; +{ + if (d >= rogue.hp_current) { + rogue.hp_current = 0; + print_stats(STAT_HP); + killed_by(monster, other); + } + if (d > 0) { + rogue.hp_current -= d; + print_stats(STAT_HP); + } +} + +int +get_damage(ds, r) + char *ds; + boolean r; +{ + register int i = 0, j, n, d, total = 0; + + while (ds[i]) { + n = get_number(ds+i); + while (ds[i++] != 'd') ; + d = get_number(ds+i); + while ((ds[i] != '/') && ds[i]) i++; + + for (j = 0; j < n; j++) { + if (r) { + total += get_rand(1, d); + } else { + total += d; + } + } + if (ds[i] == '/') { + i++; + } + } + return(total); +} + +int +get_w_damage(obj) + object *obj; +{ + char new_damage[12]; + register int to_hit, damage; + register int i = 0; + + if ((!obj) || (obj->what_is != WEAPON)) { + return(-1); + } + to_hit = get_number(obj->damage) + obj->hit_enchant; + while (obj->damage[i++] != 'd') ; + damage = get_number(obj->damage + i) + obj->d_enchant; + + sprintf(new_damage, "%dd%d", to_hit, damage); + + return(get_damage(new_damage, 1)); +} + +int +get_number(s) + register char *s; +{ + register int i = 0; + register int total = 0; + + while ((s[i] >= '0') && (s[i] <= '9')) { + total = (10 * total) + (s[i] - '0'); + i++; + } + return(total); +} + +long +lget_number(s) + char *s; +{ + int i = 0; + long total = 0; + + while ((s[i] >= '0') && (s[i] <= '9')) { + total = (10 * total) + (s[i] - '0'); + i++; + } + return(total); +} + +int +to_hit(obj) + object *obj; +{ + if (!obj) { + return(1); + } + return(get_number(obj->damage) + obj->hit_enchant); +} + +int +damage_for_strength() +{ + int strength; + + strength = rogue.str_current + add_strength; + + if (strength <= 6) { + return(strength-5); + } + if (strength <= 14) { + return(1); + } + if (strength <= 17) { + return(3); + } + if (strength <= 18) { + return(4); + } + if (strength <= 20) { + return(5); + } + if (strength <= 21) { + return(6); + } + if (strength <= 30) { + return(7); + } + return(8); +} + +int +mon_damage(monster, damage) + object *monster; + int damage; +{ + char *mn; + int row, col; + + monster->hp_to_kill -= damage; + + if (monster->hp_to_kill <= 0) { + row = monster->row; + col = monster->col; + dungeon[row][col] &= ~MONSTER; + mvaddch(row, col, (int) get_dungeon_char(row, col)); + + fight_monster = 0; + cough_up(monster); + mn = mon_name(monster); + sprintf(hit_message+strlen(hit_message), "defeated the %s", mn); + message(hit_message, 1); + hit_message[0] = 0; + add_exp(monster->kill_exp, 1); + take_from_pack(monster, &level_monsters); + + if (monster->m_flags & HOLDS) { + being_held = 0; + } + free_object(monster); + return(0); + } + return(1); +} + +void +fight(to_the_death) + boolean to_the_death; +{ + int ch, c, d; + int row, col; + boolean first_miss = 1; + int possible_damage; + object *monster; + + while (!is_direction(ch = rgetchar(), &d)) { + sound_bell(); + if (first_miss) { + message("direction?", 0); + first_miss = 0; + } + } + check_message(); + if (ch == CANCEL) { + return; + } + row = rogue.row; col = rogue.col; + get_dir_rc(d, &row, &col, 0); + + c = mvinch(row, col); + if (((c < 'A') || (c > 'Z')) || + (!can_move(rogue.row, rogue.col, row, col))) { + message("I see no monster there", 0); + return; + } + if (!(fight_monster = object_at(&level_monsters, row, col))) { + return; + } + if (!(fight_monster->m_flags & STATIONARY)) { + possible_damage = ((get_damage(fight_monster->m_damage, 0) * 2) / 3); + } else { + possible_damage = fight_monster->stationary_damage - 1; + } + while (fight_monster) { + (void) one_move_rogue(ch, 0); + if (((!to_the_death) && (rogue.hp_current <= possible_damage)) || + interrupted || (!(dungeon[row][col] & MONSTER))) { + fight_monster = 0; + } else { + monster = object_at(&level_monsters, row, col); + if (monster != fight_monster) { + fight_monster = 0; + } + } + } +} + +void +get_dir_rc(dir, row, col, allow_off_screen) + int dir; + int *row, *col; + int allow_off_screen; +{ + switch(dir) { + case LEFT: + if (allow_off_screen || (*col > 0)) { + (*col)--; + } + break; + case DOWN: + if (allow_off_screen || (*row < (DROWS-2))) { + (*row)++; + } + break; + case UPWARD: + if (allow_off_screen || (*row > MIN_ROW)) { + (*row)--; + } + break; + case RIGHT: + if (allow_off_screen || (*col < (DCOLS-1))) { + (*col)++; + } + break; + case UPLEFT: + if (allow_off_screen || ((*row > MIN_ROW) && (*col > 0))) { + (*row)--; + (*col)--; + } + break; + case UPRIGHT: + if (allow_off_screen || ((*row > MIN_ROW) && (*col < (DCOLS-1)))) { + (*row)--; + (*col)++; + } + break; + case DOWNRIGHT: + if (allow_off_screen || ((*row < (DROWS-2)) && (*col < (DCOLS-1)))) { + (*row)++; + (*col)++; + } + break; + case DOWNLEFT: + if (allow_off_screen || ((*row < (DROWS-2)) && (*col > 0))) { + (*row)++; + (*col)--; + } + break; + } +} + +int +get_hit_chance(weapon) + object *weapon; +{ + int hit_chance; + + hit_chance = 40; + hit_chance += 3 * to_hit(weapon); + hit_chance += (((2 * rogue.exp) + (2 * ring_exp)) - r_rings); + return(hit_chance); +} + +int +get_weapon_damage(weapon) + object *weapon; +{ + int damage; + + damage = get_w_damage(weapon); + damage += damage_for_strength(); + damage += ((((rogue.exp + ring_exp) - r_rings) + 1) / 2); + return(damage); +} + +void +s_con_mon(monster) + object *monster; +{ + if (con_mon) { + monster->m_flags |= CONFUSED; + monster->moves_confused += get_rand(12, 22); + message("the monster appears confused", 0); + con_mon = 0; + } +} diff --git a/src/games/rogue/init.c b/src/games/rogue/init.c new file mode 100644 index 0000000..6428810 --- /dev/null +++ b/src/games/rogue/init.c @@ -0,0 +1,300 @@ +/* + * This source herein may be modified and/or distributed by anybody who + * so desires, with the following restrictions: + * 1.) No portion of this notice shall be removed. + * 2.) Credit shall not be taken for the creation of this source. + * 3.) This code is not to be traded, sold, or used for personal + * gain or profit. + */ +#include +#include "rogue.h" + +char login_name[MAX_OPT_LEN]; +char *nick_name = (char *) 0; +char *rest_file = 0; +char cant_int = 0; +char did_int = 0; +char score_only; +char init_curses = 0; +char save_is_interactive = 1; +char ask_quit = 1; +char no_skull = 0; +char passgo = 0; +char *error_file = "rogue.esave"; +char *byebye_string = "Okay, bye bye!"; + +static void +player_init() +{ + object *obj; + + rogue.pack.next_object = (object *) 0; + + obj = alloc_object(); + get_food(obj, 1); + (void) add_to_pack(obj, &rogue.pack, 1); + + obj = alloc_object(); /* initial armor */ + obj->what_is = ARMOR; + obj->which_kind = RINGMAIL; + obj->class = RINGMAIL+2; + obj->is_protected = 0; + obj->d_enchant = 1; + (void) add_to_pack(obj, &rogue.pack, 1); + do_wear(obj); + + obj = alloc_object(); /* initial weapons */ + obj->what_is = WEAPON; + obj->which_kind = MACE; + obj->damage = "2d3"; + obj->hit_enchant = obj->d_enchant = 1; + obj->identified = 1; + (void) add_to_pack(obj, &rogue.pack, 1); + do_wield(obj); + + obj = alloc_object(); + obj->what_is = WEAPON; + obj->which_kind = BOW; + obj->damage = "1d2"; + obj->hit_enchant = 1; + obj->d_enchant = 0; + obj->identified = 1; + (void) add_to_pack(obj, &rogue.pack, 1); + + obj = alloc_object(); + obj->what_is = WEAPON; + obj->which_kind = ARROW; + obj->quantity = get_rand(25, 35); + obj->damage = "1d2"; + obj->hit_enchant = 0; + obj->d_enchant = 0; + obj->identified = 1; + (void) add_to_pack(obj, &rogue.pack, 1); +} + +static void +do_args(argc, argv) + int argc; + char *argv[]; +{ + int i, j; + + for (i = 1; i < argc; i++) { + if (argv[i][0] == '-') { + for (j = 1; argv[i][j]; j++) { + switch(argv[i][j]) { + case 's': + score_only = 1; + break; + } + } + } else { + rest_file = argv[i]; + } + } +} + +static void +env_get_value(s, e, add_blank) + char **s, *e; + boolean add_blank; +{ + int i = 0; + char *t; + + t = e; + + while ((*e) && (*e != ',')) { + if (*e == ':') { + *e = ';'; /* ':' reserved for score file purposes */ + } + e++; + if (++i >= MAX_OPT_LEN) { + break; + } + } + *s = md_malloc(MAX_OPT_LEN + 2); + (void) strncpy(*s, t, i); + if (add_blank) { + (*s)[i++] = ' '; + } + (*s)[i] = '\0'; +} + +static void +init_str(str, dflt) + char **str, *dflt; +{ + if (!(*str)) { + *str = md_malloc(MAX_OPT_LEN + 2); + (void) strcpy(*str, dflt); + } +} + +static void +do_opts() +{ + char *eptr; + + eptr = md_getenv("ROGUEOPTS"); + if (eptr) { + for (;;) { + while ((*eptr) == ' ') { + eptr++; + } + if (!(*eptr)) { + break; + } + if (!strncmp(eptr, "fruit=", 6)) { + eptr += 6; + env_get_value(&fruit, eptr, 1); + } else if (!strncmp(eptr, "file=", 5)) { + eptr += 5; + env_get_value(&save_file, eptr, 0); + } else if (!strncmp(eptr, "jump", 4)) { + jump = 1; + } else if (!strncmp(eptr, "name=", 5)) { + eptr += 5; + env_get_value(&nick_name, eptr, 0); + } else if (!strncmp(eptr, "noaskquit", 9)) { + ask_quit = 0; + } else if (!strncmp(eptr, "noskull", 5) || + !strncmp(eptr,"notomb", 6)) { + no_skull = 1; + } else if (!strncmp(eptr, "passgo", 5)) { + passgo = 1; + } + while ((*eptr) && (*eptr != ',')) { + eptr++; + } + if (!(*(eptr++))) { + break; + } + } + } + /* If some strings have not been set through ROGUEOPTS, assign defaults + * to them so that the options editor has data to work with. + */ + init_str(&nick_name, login_name); + init_str(&save_file, "rogue.save"); + init_str(&fruit, "slime-mold"); +} + +int +init(argc, argv) + int argc; + char *argv[]; +{ + char *pn; + int seed; + + pn = md_gln(); + if ((!pn) || (strlen(pn) >= MAX_OPT_LEN)) { + clean_up("Hey! Who are you?"); + } + (void) strcpy(login_name, pn); + + do_args(argc, argv); + do_opts(); + + if (!score_only && !rest_file) { + printf("Hello %s, just a moment while I dig the dungeon...", + nick_name); + fflush(stdout); + md_sleep(1); + } + + initscr(); + if ((LINES < DROWS) || (COLS < DCOLS)) { + clean_up("must be played on 24 x 80 screen"); + } + start_window(); + init_curses = 1; + + md_heed_signals(); + + if (score_only) { + put_scores((object *) 0, 0); + } + seed = md_gseed(); + (void) srrandom(seed); + if (rest_file) { + restore(rest_file); + return(1); + } + mix_colors(); + get_wand_and_ring_materials(); + make_scroll_titles(); + + level_objects.next_object = (object *) 0; + level_monsters.next_monster = (object *) 0; + player_init(); + ring_stats(0); + return(0); +} + +void +clean_up(estr) + char *estr; +{ + if (save_is_interactive) { + if (init_curses) { + move(DROWS-1, 0); + refresh(); + stop_window(); + } + printf("\n%s\n", estr); + } + md_exit(0); +} + +void +start_window() +{ + crmode(); + noecho(); +#ifndef BAD_NONL + nonl(); +#endif + md_control_keybord(0); +} + +void +stop_window() +{ + endwin(); + md_control_keybord(1); +} + +void +byebye(int sig) +{ + md_ignore_signals(); + if (ask_quit) { + quit(1); + } else { + clean_up(byebye_string); + } + md_heed_signals(); +} + +void +onintr(int sig) +{ + md_ignore_signals(); + if (cant_int) { + did_int = 1; + } else { + check_message(); + message("interrupt", 1); + } + md_heed_signals(); +} + +void +error_save(int sig) +{ + save_is_interactive = 0; + save_into_file(error_file); + clean_up(""); +} diff --git a/src/games/rogue/inventory.c b/src/games/rogue/inventory.c new file mode 100644 index 0000000..fd35370 --- /dev/null +++ b/src/games/rogue/inventory.c @@ -0,0 +1,740 @@ +/* + * This source herein may be modified and/or distributed by anybody who + * so desires, with the following restrictions: + * 1.) No portion of this notice shall be removed. + * 2.) Credit shall not be taken for the creation of this source. + * 3.) This code is not to be traded, sold, or used for personal + * gain or profit. + */ +#include +#include "rogue.h" + +char is_wood[WANDS]; +char *press_space = " --press space to continue--"; + +char *wand_materials[WAND_MATERIALS] = { + "steel ", + "bronze ", + "gold ", + "silver ", + "copper ", + "nickel ", + "cobalt ", + "tin ", + "iron ", + "magnesium ", + "chrome ", + "carbon ", + "platinum ", + "silicon ", + "titanium ", + + "teak ", + "oak ", + "cherry ", + "birch ", + "pine ", + "cedar ", + "redwood ", + "balsa ", + "ivory ", + "walnut ", + "maple ", + "mahogany ", + "elm ", + "palm ", + "wooden " +}; + +char *gems[GEMS] = { + "diamond ", + "stibotantalite ", + "lapi-lazuli ", + "ruby ", + "emerald ", + "sapphire ", + "amethyst ", + "quartz ", + "tiger-eye ", + "opal ", + "agate ", + "turquoise ", + "pearl ", + "garnet " +}; + +char *syllables[MAXSYLLABLES] = { + "blech ", + "foo ", + "barf ", + "rech ", + "bar ", + "blech ", + "quo ", + "bloto ", + "oh ", + "caca ", + "blorp ", + "erp ", + "festr ", + "rot ", + "slie ", + "snorf ", + "iky ", + "yuky ", + "ooze ", + "ah ", + "bahl ", + "zep ", + "druhl ", + "flem ", + "behil ", + "arek ", + "mep ", + "zihr ", + "grit ", + "kona ", + "kini ", + "ichi ", + "tims ", + "ogr ", + "oo ", + "ighr ", + "coph ", + "swerr ", + "mihln ", + "poxi " +}; + +#define COMS 48 + +struct id_com_s { + short com_char; + char *com_desc; +}; + +struct id_com_s com_id_tab[COMS] = { + { '?', "? prints help" }, + { 'r', "r read scroll" }, + { '/', "/ identify object" }, + { 'e', "e eat food" }, + { 'h', "h left " }, + { 'w', "w wield a weapon" }, + { 'j', "j down" }, + { 'W', "W wear armor" }, + { 'k', "k up" }, + { 'T', "T take armor off" }, + { 'l', "l right" }, + { 'P', "P put on ring" }, + { 'y', "y up & left" }, + { 'R', "R remove ring" }, + { 'u', "u up & right" }, + { 'd', "d drop object" }, + { 'b', "b down & left" }, + { 'c', "c call object" }, + { 'n', "n down & right" }, + { 0, ": run that way" }, + { ')', ") print current weapon" }, + { 0, ": run till adjacent" }, + { ']', "] print current armor" }, + { 'f', "f fight till death or near death" }, + { '=', "= print current rings" }, + { 't', "t throw something" }, + { '\001', "^A print Hp-raise average" }, + { 'm', "m move onto without picking up" }, + { 'z', "z zap a wand in a direction" }, + { 'o', "o examine/set options" }, + { '^', "^ identify trap type" }, + { '\022', "^R redraw screen" }, + { '&', "& save screen into 'rogue.screen'" }, + { 's', "s search for trap/secret door" }, + { '\020', "^P repeat last message" }, + { '>', "> go down a staircase" }, + { '\033', "^[ cancel command" }, + { '<', "< go up a staircase" }, + { 'S', "S save game" }, + { '.', ". rest for a turn" }, + { 'Q', "Q quit" }, + { ',', ", pick something up" }, + { '!', "! shell escape" }, + { 'i', "i inventory" }, + { 'F', "F fight till either of you dies" }, + { 'I', "I inventory single item" }, + { 'v', "v print version number" }, + { 'q', "q quaff potion" }, +}; + +void +inventory(pack, mask) + object *pack; + unsigned mask; +{ + object *obj; + int i = 0, j, maxlen = 0, n; + char descs[MAX_PACK_COUNT+1][DCOLS]; + int row, col; + + obj = pack->next_object; + + if (!obj) { + message("your pack is empty", 0); + return; + } + while (obj) { + if (obj->what_is & mask) { + descs[i][0] = ' '; + descs[i][1] = obj->ichar; + descs[i][2] = ((obj->what_is & ARMOR) && obj->is_protected) + ? '}' : ')'; + descs[i][3] = ' '; + get_desc(obj, descs[i]+4); + if ((n = strlen(descs[i])) > maxlen) { + maxlen = n; + } + i++; + } + obj = obj->next_object; + } + (void) strcpy(descs[i++], press_space); + if (maxlen < 27) maxlen = 27; + col = DCOLS - (maxlen + 2); + + for (row = 0; ((row < i) && (row < DROWS)); row++) { + if (row > 0) { + for (j = col; j < DCOLS; j++) { + descs[row-1][j-col] = mvinch(row, j); + } + descs[row-1][j-col] = 0; + } + mvaddstr(row, col, descs[row]); + clrtoeol(); + } + refresh(); + wait_for_ack(); + + move(0, 0); + clrtoeol(); + + for (j = 1; ((j < i) && (j < DROWS)); j++) { + mvaddstr(j, col, descs[j-1]); + } +} + +static int +get_com_id(index, ch) + int *index; + int ch; +{ + int i; + + for (i = 0; i < COMS; i++) { + if (com_id_tab[i].com_char == ch) { + *index = i; + return(1); + } + } + return(0); +} + +static int +pr_com_id(ch) + int ch; +{ + int i; + + if (! get_com_id(&i, ch)) { + return(0); + } + check_message(); + message(com_id_tab[i].com_desc, 0); + return(1); +} + +static int +pr_motion_char(ch) + int ch; +{ + if ( (ch == 'J') || + (ch == 'K') || + (ch == 'L') || + (ch == 'H') || + (ch == 'Y') || + (ch == 'U') || + (ch == 'N') || + (ch == 'B') || + (ch == '\012') || + (ch == '\013') || + (ch == '\010') || + (ch == '\014') || + (ch == '\025') || + (ch == '\031') || + (ch == '\016') || + (ch == '\002')) { + char until[18], buf[DCOLS]; + int n = 0; + + if (ch <= '\031') { + ch += 96; + (void) strcpy(until, "until adjascent"); + } else { + ch += 32; + until[0] = '\0'; + } + (void) get_com_id(&n, ch); + sprintf(buf, "run %s %s", com_id_tab[n].com_desc + 8, until); + check_message(); + message(buf, 0); + return(1); + } else { + return(0); + } +} + +void +id_com() +{ + int ch = 0; + int i, j, k; + + while (ch != CANCEL) { + check_message(); + message("Character you want help for (* for all):", 0); + + refresh(); + ch = getchar(); + + switch(ch) { + case LIST: + { + char save[(((COMS / 2) + (COMS % 2)) + 1)][DCOLS]; + int rows = (((COMS / 2) + (COMS % 2)) + 1); + boolean need_two_screens; + + if (rows > LINES) { + need_two_screens = 1; + rows = LINES; + } + k = 0; + + for (i = 0; i < rows; i++) { + for (j = 0; j < DCOLS; j++) { + save[i][j] = mvinch(i, j); + } + } +MORE: + for (i = 0; i < rows; i++) { + move(i, 0); + clrtoeol(); + } + for (i = 0; i < (rows-1); i++) { + if (i < (LINES-1)) { + if (((i + i) < COMS) && ((i+i+k) < COMS)) { + mvaddstr(i, 0, com_id_tab[i+i+k].com_desc); + } + if (((i + i + 1) < COMS) && ((i+i+k+1) < COMS)) { + mvaddstr(i, (DCOLS/2), + com_id_tab[i+i+k+1].com_desc); + } + } + } + mvaddstr(rows - 1, 0, need_two_screens ? more : press_space); + refresh(); + wait_for_ack(); + + if (need_two_screens) { + k += ((rows-1) * 2); + need_two_screens = 0; + goto MORE; + } + for (i = 0; i < rows; i++) { + move(i, 0); + for (j = 0; j < DCOLS; j++) { + addch(save[i][j]); + } + } + } + break; + default: + if (! pr_com_id(ch)) { + if (! pr_motion_char(ch)) { + check_message(); + message("unknown character", 0); + } + } + ch = CANCEL; + break; + } + } +} + +void +mix_colors() +{ + int i, j, k; + char t[35]; + + for (i = 0; i <= 32; i++) { + j = get_rand(0, (POTIONS - 1)); + k = get_rand(0, (POTIONS - 1)); + strcpy (t, id_potions[j].title); + strcpy (id_potions[j].title, id_potions[k].title); + strcpy (id_potions[k].title, t); + } +} + +void +make_scroll_titles() +{ + int i, j, n; + int sylls, s; + + for (i = 0; i < SCROLS; i++) { + sylls = get_rand(2, 5); + (void) strcpy(id_scrolls[i].title, "'"); + + for (j = 0; j < sylls; j++) { + s = get_rand(1, (MAXSYLLABLES-1)); + (void) strcat(id_scrolls[i].title, syllables[s]); + } + n = strlen(id_scrolls[i].title); + (void) strcpy(id_scrolls[i].title+(n-1), "' "); + } +} + +void +get_desc(obj, desc) + object *obj; + char *desc; +{ + char *item_name; + struct id *id_table; + char more_info[32]; + int i; + + if (obj->what_is == AMULET) { + (void) strcpy(desc, "the amulet of Yendor "); + return; + } + item_name = name_of(obj); + + if (obj->what_is == GOLD) { + sprintf(desc, "%d pieces of gold", obj->quantity); + return; + } + + if (obj->what_is != ARMOR) { + if (obj->quantity == 1) { + (void) strcpy(desc, "a "); + } else { + sprintf(desc, "%d ", obj->quantity); + } + } + if (obj->what_is == FOOD) { + if (obj->which_kind == RATION) { + if (obj->quantity > 1) { + sprintf(desc, "%d rations of ", obj->quantity); + } else { + (void) strcpy(desc, "some "); + } + } else { + (void) strcpy(desc, "a "); + } + (void) strcat(desc, item_name); + goto ANA; + } + id_table = get_id_table(obj); + + if (wizard) { + goto ID; + } + if (obj->what_is & (WEAPON | ARMOR | WAND | RING)) { + goto CHECK; + } + + switch(id_table[obj->which_kind].id_status) { + case UNIDENTIFIED: +CHECK: + switch(obj->what_is) { + case SCROL: + (void) strcat(desc, item_name); + (void) strcat(desc, "entitled: "); + (void) strcat(desc, id_table[obj->which_kind].title); + break; + case POTION: + (void) strcat(desc, id_table[obj->which_kind].title); + (void) strcat(desc, item_name); + break; + case WAND: + case RING: + if (obj->identified || + (id_table[obj->which_kind].id_status == IDENTIFIED)) { + goto ID; + } + if (id_table[obj->which_kind].id_status == CALLED) { + goto CALL; + } + (void) strcat(desc, id_table[obj->which_kind].title); + (void) strcat(desc, item_name); + break; + case ARMOR: + if (obj->identified) { + goto ID; + } + (void) strcpy(desc, id_table[obj->which_kind].title); + break; + case WEAPON: + if (obj->identified) { + goto ID; + } + (void) strcat(desc, name_of(obj)); + break; + } + break; + case CALLED: +CALL: switch(obj->what_is) { + case SCROL: + case POTION: + case WAND: + case RING: + (void) strcat(desc, item_name); + (void) strcat(desc, "called "); + (void) strcat(desc, id_table[obj->which_kind].title); + break; + } + break; + case IDENTIFIED: +ID: switch(obj->what_is) { + case SCROL: + case POTION: + (void) strcat(desc, item_name); + (void) strcat(desc, id_table[obj->which_kind].real); + break; + case RING: + if (wizard || obj->identified) { + if ((obj->which_kind == DEXTERITY) || + (obj->which_kind == ADD_STRENGTH)) { + sprintf(more_info, "%s%d ", ((obj->class > 0) ? "+" : ""), + obj->class); + (void) strcat(desc, more_info); + } + } + (void) strcat(desc, item_name); + (void) strcat(desc, id_table[obj->which_kind].real); + break; + case WAND: + (void) strcat(desc, item_name); + (void) strcat(desc, id_table[obj->which_kind].real); + if (wizard || obj->identified) { + sprintf(more_info, "[%d]", obj->class); + (void) strcat(desc, more_info); + } + break; + case ARMOR: + sprintf(desc, "%s%d ", ((obj->d_enchant >= 0) ? "+" : ""), + obj->d_enchant); + (void) strcat(desc, id_table[obj->which_kind].title); + sprintf(more_info, "[%d] ", get_armor_class(obj)); + (void) strcat(desc, more_info); + break; + case WEAPON: + sprintf(desc+strlen(desc), "%s%d,%s%d ", + ((obj->hit_enchant >= 0) ? "+" : ""), obj->hit_enchant, + ((obj->d_enchant >= 0) ? "+" : ""), obj->d_enchant); + (void) strcat(desc, name_of(obj)); + break; + } + break; + } +ANA: + if (!strncmp(desc, "a ", 2)) { + if (is_vowel(desc[2])) { + for (i = strlen(desc) + 1; i > 1; i--) { + desc[i] = desc[i-1]; + } + desc[1] = 'n'; + } + } + if (obj->in_use_flags & BEING_WIELDED) { + (void) strcat(desc, "in hand"); + } else if (obj->in_use_flags & BEING_WORN) { + (void) strcat(desc, "being worn"); + } else if (obj->in_use_flags & ON_LEFT_HAND) { + (void) strcat(desc, "on left hand"); + } else if (obj->in_use_flags & ON_RIGHT_HAND) { + (void) strcat(desc, "on right hand"); + } +} + +void +get_wand_and_ring_materials() +{ + int i, j; + boolean used[WAND_MATERIALS]; + + for (i = 0; i < WAND_MATERIALS; i++) { + used[i] = 0; + } + for (i = 0; i < WANDS; i++) { + do { + j = get_rand(0, WAND_MATERIALS-1); + } while (used[j]); + used[j] = 1; + (void) strcpy(id_wands[i].title, wand_materials[j]); + is_wood[i] = (j > MAX_METAL); + } + for (i = 0; i < GEMS; i++) { + used[i] = 0; + } + for (i = 0; i < RINGS; i++) { + do { + j = get_rand(0, GEMS-1); + } while (used[j]); + used[j] = 1; + (void) strcpy(id_rings[i].title, gems[j]); + } +} + +void +single_inv(ichar) + int ichar; +{ + int ch; + char desc[DCOLS]; + object *obj; + + ch = ichar ? ichar : pack_letter("inventory what?", ALL_OBJECTS); + + if (ch == CANCEL) { + return; + } + if (!(obj = get_letter_object(ch))) { + message("no such item.", 0); + return; + } + desc[0] = ch; + desc[1] = ((obj->what_is & ARMOR) && obj->is_protected) ? '}' : ')'; + desc[2] = ' '; + desc[3] = 0; + get_desc(obj, desc+3); + message(desc, 0); +} + +struct id * +get_id_table(obj) + object *obj; +{ + switch(obj->what_is) { + case SCROL: + return(id_scrolls); + case POTION: + return(id_potions); + case WAND: + return(id_wands); + case RING: + return(id_rings); + case WEAPON: + return(id_weapons); + case ARMOR: + return(id_armors); + } + return((struct id *) 0); +} + +void +inv_armor_weapon(is_weapon) + boolean is_weapon; +{ + if (is_weapon) { + if (rogue.weapon) { + single_inv(rogue.weapon->ichar); + } else { + message("not wielding anything", 0); + } + } else { + if (rogue.armor) { + single_inv(rogue.armor->ichar); + } else { + message("not wearing anything", 0); + } + } +} + +void +id_type() +{ + char *id; + int ch; + char buf[DCOLS]; + + message("what do you want identified?", 0); + + ch = rgetchar(); + + if ((ch >= 'A') && (ch <= 'Z')) { + id = m_names[ch-'A']; + } else if (ch < 32) { + check_message(); + return; + } else { + switch(ch) { + case '@': + id = "you"; + break; + case '%': + id = "staircase"; + break; + case '^': + id = "trap"; + break; + case '+': + id = "door"; + break; + case '-': + case '|': + id = "wall of a room"; + break; + case '.': + id = "floor"; + break; + case '#': + id = "passage"; + break; + case ' ': + id = "solid rock"; + break; + case '=': + id = "ring"; + break; + case '?': + id = "scroll"; + break; + case '!': + id = "potion"; + break; + case '/': + id = "wand or staff"; + break; + case ')': + id = "weapon"; + break; + case ']': + id = "armor"; + break; + case '*': + id = "gold"; + break; + case ':': + id = "food"; + break; + case ',': + id = "the Amulet of Yendor"; + break; + default: + id = "unknown character"; + break; + } + } + check_message(); + sprintf(buf, "'%c': %s", ch, id); + message(buf, 0); +} diff --git a/src/games/rogue/level.c b/src/games/rogue/level.c new file mode 100644 index 0000000..c1bbea8 --- /dev/null +++ b/src/games/rogue/level.c @@ -0,0 +1,860 @@ +/* + * This source herein may be modified and/or distributed by anybody who + * so desires, with the following restrictions: + * 1.) No portion of this notice shall be removed. + * 2.) Credit shall not be taken for the creation of this source. + * 3.) This code is not to be traded, sold, or used for personal + * gain or profit. + */ +#include "rogue.h" + +#define swap(x,y) {t = x; x = y; y = t;} + +short cur_level = 0; +short max_level = 1; +short cur_room; +char *new_level_message = 0; +short party_room = NO_ROOM; +short r_de; + +long level_points[MAX_EXP_LEVEL] = { + 10L, + 20L, + 40L, + 80L, + 160L, + 320L, + 640L, + 1300L, + 2600L, + 5200L, + 10000L, + 20000L, + 40000L, + 80000L, + 160000L, + 320000L, + 1000000L, + 3333333L, + 6666666L, + MAX_EXP, + 99900000L +}; + +short random_rooms[MAXROOMS] = {3, 7, 5, 2, 0, 6, 1, 4, 8}; + +static void +make_room(rn, r1, r2, r3) + int rn, r1, r2, r3; +{ + int left_col, right_col, top_row, bottom_row; + int width, height; + int row_offset, col_offset; + int i, j, ch; + + switch(rn) { + default: + case 0: + left_col = 0; + right_col = COL1-1; + top_row = MIN_ROW; + bottom_row = ROW1-1; + break; + case 1: + left_col = COL1+1; + right_col = COL2-1; + top_row = MIN_ROW; + bottom_row = ROW1-1; + break; + case 2: + left_col = COL2+1; + right_col = DCOLS-1; + top_row = MIN_ROW; + bottom_row = ROW1-1; + break; + case 3: + left_col = 0; + right_col = COL1-1; + top_row = ROW1+1; + bottom_row = ROW2-1; + break; + case 4: + left_col = COL1+1; + right_col = COL2-1; + top_row = ROW1+1; + bottom_row = ROW2-1; + break; + case 5: + left_col = COL2+1; + right_col = DCOLS-1; + top_row = ROW1+1; + bottom_row = ROW2-1; + break; + case 6: + left_col = 0; + right_col = COL1-1; + top_row = ROW2+1; + bottom_row = DROWS - 2; + break; + case 7: + left_col = COL1+1; + right_col = COL2-1; + top_row = ROW2+1; + bottom_row = DROWS - 2; + break; + case 8: + left_col = COL2+1; + right_col = DCOLS-1; + top_row = ROW2+1; + bottom_row = DROWS - 2; + break; + case BIG_ROOM: + top_row = get_rand(MIN_ROW, MIN_ROW+5); + bottom_row = get_rand(DROWS-7, DROWS-2); + left_col = get_rand(0, 10);; + right_col = get_rand(DCOLS-11, DCOLS-1); + rn = 0; + goto B; + } + height = get_rand(4, (bottom_row - top_row + 1)); + width = get_rand(7, (right_col - left_col - 2)); + + row_offset = get_rand(0, ((bottom_row - top_row) - height + 1)); + col_offset = get_rand(0, ((right_col - left_col) - width + 1)); + + top_row += row_offset; + bottom_row = top_row + height - 1; + + left_col += col_offset; + right_col = left_col + width - 1; + + if ((rn != r1) && (rn != r2) && (rn != r3) && rand_percent(40)) { + goto END; + } +B: + rooms[rn].is_room = R_ROOM; + + for (i = top_row; i <= bottom_row; i++) { + for (j = left_col; j <= right_col; j++) { + if ((i == top_row) || (i == bottom_row)) { + ch = HORWALL; + } else if ( ((i != top_row) && (i != bottom_row)) && + ((j == left_col) || (j == right_col))) { + ch = VERTWALL; + } else { + ch = FLOOR; + } + dungeon[i][j] = ch; + } + } +END: + rooms[rn].top_row = top_row; + rooms[rn].bottom_row = bottom_row; + rooms[rn].left_col = left_col; + rooms[rn].right_col = right_col; +} + +static void +make_maze(r, c, tr, br, lc, rc) + int r, c, tr, br, lc, rc; +{ + char dirs[4]; + int i, t; + + dirs[0] = UPWARD; + dirs[1] = DOWN; + dirs[2] = LEFT; + dirs[3] = RIGHT; + + dungeon[r][c] = TUNNEL; + + if (rand_percent(20)) { + for (i = 0; i < 10; i++) { + int t1, t2; + + t1 = get_rand(0, 3); + t2 = get_rand(0, 3); + + swap(dirs[t1], dirs[t2]); + } + } + for (i = 0; i < 4; i++) { + switch(dirs[i]) { + case UPWARD: + if (((r-1) >= tr) && + (dungeon[r-1][c] != TUNNEL) && + (dungeon[r-1][c-1] != TUNNEL) && + (dungeon[r-1][c+1] != TUNNEL) && + (dungeon[r-2][c] != TUNNEL)) { + make_maze((r-1), c, tr, br, lc, rc); + } + break; + case DOWN: + if (((r+1) <= br) && + (dungeon[r+1][c] != TUNNEL) && + (dungeon[r+1][c-1] != TUNNEL) && + (dungeon[r+1][c+1] != TUNNEL) && + (dungeon[r+2][c] != TUNNEL)) { + make_maze((r+1), c, tr, br, lc, rc); + } + break; + case LEFT: + if (((c-1) >= lc) && + (dungeon[r][c-1] != TUNNEL) && + (dungeon[r-1][c-1] != TUNNEL) && + (dungeon[r+1][c-1] != TUNNEL) && + (dungeon[r][c-2] != TUNNEL)) { + make_maze(r, (c-1), tr, br, lc, rc); + } + break; + case RIGHT: + if (((c+1) <= rc) && + (dungeon[r][c+1] != TUNNEL) && + (dungeon[r-1][c+1] != TUNNEL) && + (dungeon[r+1][c+1] != TUNNEL) && + (dungeon[r][c+2] != TUNNEL)) { + make_maze(r, (c+1), tr, br, lc, rc); + } + break; + } + } +} + +static void +hide_boxed_passage(row1, col1, row2, col2, n) + int row1, col1, row2, col2, n; +{ + int i, j, t; + int row, col, row_cut, col_cut; + int h, w; + + if (cur_level > 2) { + if (row1 > row2) { + swap(row1, row2); + } + if (col1 > col2) { + swap(col1, col2); + } + h = row2 - row1; + w = col2 - col1; + + if ((w >= 5) || (h >= 5)) { + row_cut = ((h >= 2) ? 1 : 0); + col_cut = ((w >= 2) ? 1 : 0); + + for (i = 0; i < n; i++) { + for (j = 0; j < 10; j++) { + row = get_rand(row1 + row_cut, row2 - row_cut); + col = get_rand(col1 + col_cut, col2 - col_cut); + if (dungeon[row][col] == TUNNEL) { + dungeon[row][col] |= HIDDEN; + break; + } + } + } + } + } +} + +static void +add_mazes() +{ + int i, j; + int start; + int maze_percent; + + if (cur_level > 1) { + start = get_rand(0, (MAXROOMS-1)); + maze_percent = (cur_level * 5) / 4; + + if (cur_level > 15) { + maze_percent += cur_level; + } + for (i = 0; i < MAXROOMS; i++) { + j = ((start + i) % MAXROOMS); + if (rooms[j].is_room & R_NOTHING) { + if (rand_percent(maze_percent)) { + rooms[j].is_room = R_MAZE; + make_maze(get_rand(rooms[j].top_row+1, rooms[j].bottom_row-1), + get_rand(rooms[j].left_col+1, rooms[j].right_col-1), + rooms[j].top_row, rooms[j].bottom_row, + rooms[j].left_col, rooms[j].right_col); + hide_boxed_passage(rooms[j].top_row, rooms[j].left_col, + rooms[j].bottom_row, rooms[j].right_col, + get_rand(0, 2)); + } + } + } + } +} + +static void +mix_random_rooms() +{ + int i, t; + int x, y; + + for (i = 0; i < (3 * MAXROOMS); i++) { + do { + x = get_rand(0, (MAXROOMS-1)); + y = get_rand(0, (MAXROOMS-1)); + } while (x == y); + swap(random_rooms[x], random_rooms[y]); + } +} + +static int +same_row(room1, room2) +{ + return((room1 / 3) == (room2 / 3)); +} + +static int +same_col(room1, room2) +{ + return((room1 % 3) == (room2 % 3)); +} + +static void +put_door(rm, dir, row, col) + room *rm; + int dir; + int *row, *col; +{ + int wall_width; + + wall_width = (rm->is_room & R_MAZE) ? 0 : 1; + + switch(dir) { + case UPWARD: + case DOWN: + *row = ((dir == UPWARD) ? rm->top_row : rm->bottom_row); + do { + *col = get_rand(rm->left_col+wall_width, + rm->right_col-wall_width); + } while (!(dungeon[*row][*col] & (HORWALL | TUNNEL))); + break; + case RIGHT: + case LEFT: + *col = (dir == LEFT) ? rm->left_col : rm->right_col; + do { + *row = get_rand(rm->top_row+wall_width, + rm->bottom_row-wall_width); + } while (!(dungeon[*row][*col] & (VERTWALL | TUNNEL))); + break; + } + if (rm->is_room & R_ROOM) { + dungeon[*row][*col] = DOOR; + } + if ((cur_level > 2) && rand_percent(HIDE_PERCENT)) { + dungeon[*row][*col] |= HIDDEN; + } + rm->doors[dir/2].door_row = *row; + rm->doors[dir/2].door_col = *col; +} + +static void +draw_simple_passage(row1, col1, row2, col2, dir) + int row1, col1, row2, col2, dir; +{ + int i, middle, t; + + if ((dir == LEFT) || (dir == RIGHT)) { + if (col1 > col2) { + swap(row1, row2); + swap(col1, col2); + } + middle = get_rand(col1+1, col2-1); + for (i = col1+1; i != middle; i++) { + dungeon[row1][i] = TUNNEL; + } + for (i = row1; i != row2; i += (row1 > row2) ? -1 : 1) { + dungeon[i][middle] = TUNNEL; + } + for (i = middle; i != col2; i++) { + dungeon[row2][i] = TUNNEL; + } + } else { + if (row1 > row2) { + swap(row1, row2); + swap(col1, col2); + } + middle = get_rand(row1+1, row2-1); + for (i = row1+1; i != middle; i++) { + dungeon[i][col1] = TUNNEL; + } + for (i = col1; i != col2; i += (col1 > col2) ? -1 : 1) { + dungeon[middle][i] = TUNNEL; + } + for (i = middle; i != row2; i++) { + dungeon[i][col2] = TUNNEL; + } + } + if (rand_percent(HIDE_PERCENT)) { + hide_boxed_passage(row1, col1, row2, col2, 1); + } +} + +static int +connect_rooms(room1, room2) + int room1, room2; +{ + int row1, col1, row2, col2, dir; + + if ((!(rooms[room1].is_room & (R_ROOM | R_MAZE))) || + (!(rooms[room2].is_room & (R_ROOM | R_MAZE)))) { + return(0); + } + if (same_row(room1, room2) && + (rooms[room1].left_col > rooms[room2].right_col)) { + put_door(&rooms[room1], LEFT, &row1, &col1); + put_door(&rooms[room2], RIGHT, &row2, &col2); + dir = LEFT; + } else if (same_row(room1, room2) && + (rooms[room2].left_col > rooms[room1].right_col)) { + put_door(&rooms[room1], RIGHT, &row1, &col1); + put_door(&rooms[room2], LEFT, &row2, &col2); + dir = RIGHT; + } else if (same_col(room1, room2) && + (rooms[room1].top_row > rooms[room2].bottom_row)) { + put_door(&rooms[room1], UPWARD, &row1, &col1); + put_door(&rooms[room2], DOWN, &row2, &col2); + dir = UPWARD; + } else if (same_col(room1, room2) && + (rooms[room2].top_row > rooms[room1].bottom_row)) { + put_door(&rooms[room1], DOWN, &row1, &col1); + put_door(&rooms[room2], UPWARD, &row2, &col2); + dir = DOWN; + } else { + return(0); + } + + do { + draw_simple_passage(row1, col1, row2, col2, dir); + } while (rand_percent(4)); + + rooms[room1].doors[dir/2].oth_room = room2; + rooms[room1].doors[dir/2].oth_row = row2; + rooms[room1].doors[dir/2].oth_col = col2; + + rooms[room2].doors[(((dir+4)%DIRS)/2)].oth_room = room1; + rooms[room2].doors[(((dir+4)%DIRS)/2)].oth_row = row1; + rooms[room2].doors[(((dir+4)%DIRS)/2)].oth_col = col1; + return(1); +} + +static void +recursive_deadend(rn, offsets, srow, scol) + int rn; + int *offsets; + int srow, scol; +{ + int i, de; + int drow, dcol, tunnel_dir; + + rooms[rn].is_room = R_DEADEND; + dungeon[srow][scol] = TUNNEL; + + for (i = 0; i < 4; i++) { + de = rn + offsets[i]; + if (((de < 0) || (de >= MAXROOMS)) || + (!(same_row(rn, de) || same_col(rn, de)))) { + continue; + } + if (!(rooms[de].is_room & R_NOTHING)) { + continue; + } + drow = (rooms[de].top_row + rooms[de].bottom_row) / 2; + dcol = (rooms[de].left_col + rooms[de].right_col) / 2; + if (same_row(rn, de)) { + tunnel_dir = (rooms[rn].left_col < rooms[de].left_col) ? + RIGHT : LEFT; + } else { + tunnel_dir = (rooms[rn].top_row < rooms[de].top_row) ? + DOWN : UPWARD; + } + draw_simple_passage(srow, scol, drow, dcol, tunnel_dir); + r_de = de; + recursive_deadend(de, offsets, drow, dcol); + } +} + +static boolean +mask_room(rn, row, col, mask) + int rn; + int *row, *col; + unsigned mask; +{ + int i, j; + + for (i = rooms[rn].top_row; i <= rooms[rn].bottom_row; i++) { + for (j = rooms[rn].left_col; j <= rooms[rn].right_col; j++) { + if (dungeon[i][j] & mask) { + *row = i; + *col = j; + return(1); + } + } + } + return(0); +} + +static void +fill_it(rn, do_rec_de) + int rn; + boolean do_rec_de; +{ + int i, tunnel_dir, door_dir, drow, dcol; + int target_room, rooms_found = 0; + int srow, scol, t; + static short offsets[4] = {-1, 1, 3, -3}; + boolean did_this = 0; + + for (i = 0; i < 10; i++) { + srow = get_rand(0, 3); + scol = get_rand(0, 3); + t = offsets[srow]; + offsets[srow] = offsets[scol]; + offsets[scol] = t; + } + for (i = 0; i < 4; i++) { + + target_room = rn + offsets[i]; + + if (((target_room < 0) || (target_room >= MAXROOMS)) || + (!(same_row(rn,target_room) || same_col(rn,target_room))) || + (!(rooms[target_room].is_room & (R_ROOM | R_MAZE)))) { + continue; + } + if (same_row(rn, target_room)) { + tunnel_dir = (rooms[rn].left_col < rooms[target_room].left_col) ? + RIGHT : LEFT; + } else { + tunnel_dir = (rooms[rn].top_row < rooms[target_room].top_row) ? + DOWN : UPWARD; + } + door_dir = ((tunnel_dir + 4) % DIRS); + if (rooms[target_room].doors[door_dir/2].oth_room != NO_ROOM) { + continue; + } + if (((!do_rec_de) || did_this) || + (!mask_room(rn, &srow, &scol, TUNNEL))) { + srow = (rooms[rn].top_row + rooms[rn].bottom_row) / 2; + scol = (rooms[rn].left_col + rooms[rn].right_col) / 2; + } + put_door(&rooms[target_room], door_dir, &drow, &dcol); + rooms_found++; + draw_simple_passage(srow, scol, drow, dcol, tunnel_dir); + rooms[rn].is_room = R_DEADEND; + dungeon[srow][scol] = TUNNEL; + + if ((i < 3) && (!did_this)) { + did_this = 1; + if (coin_toss()) { + continue; + } + } + if ((rooms_found < 2) && do_rec_de) { + recursive_deadend(rn, offsets, srow, scol); + } + break; + } +} + +static void +fill_out_level() +{ + int i, rn; + + mix_random_rooms(); + + r_de = NO_ROOM; + + for (i = 0; i < MAXROOMS; i++) { + rn = random_rooms[i]; + if ((rooms[rn].is_room & R_NOTHING) || + ((rooms[rn].is_room & R_CROSS) && coin_toss())) { + fill_it(rn, 1); + } + } + if (r_de != NO_ROOM) { + fill_it(r_de, 0); + } +} + +void +make_level() +{ + int i, j; + int must_1, must_2, must_3; + boolean big_room; + + if (cur_level < LAST_DUNGEON) { + cur_level++; + } + if (cur_level > max_level) { + max_level = cur_level; + } + must_1 = get_rand(0, 5); + + switch(must_1) { + default: + case 0: + must_1 = 0; + must_2 = 1; + must_3 = 2; + break; + case 1: + must_1 = 3; + must_2 = 4; + must_3 = 5; + break; + case 2: + must_1 = 6; + must_2 = 7; + must_3 = 8; + break; + case 3: + must_1 = 0; + must_2 = 3; + must_3 = 6; + break; + case 4: + must_1 = 1; + must_2 = 4; + must_3 = 7; + break; + case 5: + must_1 = 2; + must_2 = 5; + must_3 = 8; + break; + } + if (rand_percent(8)) { + party_room = 0; + } + big_room = ((party_room != NO_ROOM) && rand_percent(1)); + if (big_room) { + make_room(BIG_ROOM, 0, 0, 0); + } else { + for (i = 0; i < MAXROOMS; i++) { + make_room(i, must_1, must_2, must_3); + } + } + if (!big_room) { + add_mazes(); + + mix_random_rooms(); + + for (j = 0; j < MAXROOMS; j++) { + + i = random_rooms[j]; + + if (i < (MAXROOMS-1)) { + (void) connect_rooms(i, i+1); + } + if (i < (MAXROOMS-3)) { + (void) connect_rooms(i, i+3); + } + if (i < (MAXROOMS-2)) { + if (rooms[i+1].is_room & R_NOTHING) { + if (connect_rooms(i, i+2)) { + rooms[i+1].is_room = R_CROSS; + } + } + } + if (i < (MAXROOMS-6)) { + if (rooms[i+3].is_room & R_NOTHING) { + if (connect_rooms(i, i+6)) { + rooms[i+3].is_room = R_CROSS; + } + } + } + if (is_all_connected()) { + break; + } + } + fill_out_level(); + } + if (!has_amulet() && (cur_level >= AMULET_LEVEL)) { + put_amulet(); + } +} + +void +clear_level() +{ + int i, j; + + for (i = 0; i < MAXROOMS; i++) { + rooms[i].is_room = R_NOTHING; + for (j = 0; j < 4; j++) { + rooms[i].doors[j].oth_room = NO_ROOM; + } + } + + for (i = 0; i < MAX_TRAPS; i++) { + traps[i].trap_type = NO_TRAP; + } + for (i = 0; i < DROWS; i++) { + for (j = 0; j < DCOLS; j++) { + dungeon[i][j] = NOTHING; + } + } + detect_monster = see_invisible = 0; + being_held = bear_trap = 0; + party_room = NO_ROOM; + rogue.row = rogue.col = -1; + clear(); +} + +void +put_player(nr) + int nr; /* try not to put in this room */ +{ + int rn = nr, misses; + int row, col; + + for (misses = 0; ((misses < 2) && (rn == nr)); misses++) { + gr_row_col(&row, &col, (FLOOR | TUNNEL | OBJECT | STAIRS)); + rn = get_room_number(row, col); + } + rogue.row = row; + rogue.col = col; + + if (dungeon[rogue.row][rogue.col] & TUNNEL) { + cur_room = PASSAGE; + } else { + cur_room = rn; + } + if (cur_room != PASSAGE) { + light_up_room(cur_room); + } else { + light_passage(rogue.row, rogue.col); + } + rn = get_room_number(rogue.row, rogue.col); + wake_room(rn, 1, rogue.row, rogue.col); + if (new_level_message) { + message(new_level_message, 0); + new_level_message = 0; + } + mvaddch(rogue.row, rogue.col, rogue.fchar); +} + +int +drop_check() +{ + if (wizard) { + return(1); + } + if (dungeon[rogue.row][rogue.col] & STAIRS) { + if (levitate) { + message("you're floating in the air!", 0); + return(0); + } + return(1); + } + message("I see no way down", 0); + return(0); +} + +int +check_up() +{ + if (!wizard) { + if (!(dungeon[rogue.row][rogue.col] & STAIRS)) { + message("I see no way up", 0); + return(0); + } + if (!has_amulet()) { + message("your way is magically blocked", 0); + return(0); + } + } + new_level_message = "you feel a wrenching sensation in your gut"; + if (cur_level == 1) { + win(); + } else { + cur_level -= 2; + return(1); + } + return(0); +} + +static int +get_exp_level(e) + long e; +{ + int i; + + for (i = 0; i < (MAX_EXP_LEVEL - 1); i++) { + if (level_points[i] > e) { + break; + } + } + return(i+1); +} + +void +add_exp(e, promotion) + int e; + boolean promotion; +{ + char mbuf[40]; + int new_exp; + int i, hp; + + rogue.exp_points += e; + + if (rogue.exp_points >= level_points[rogue.exp-1]) { + new_exp = get_exp_level(rogue.exp_points); + if (rogue.exp_points > MAX_EXP) { + rogue.exp_points = MAX_EXP + 1; + } + for (i = rogue.exp+1; i <= new_exp; i++) { + sprintf(mbuf, "welcome to level %d", i); + message(mbuf, 0); + if (promotion) { + hp = hp_raise(); + rogue.hp_current += hp; + rogue.hp_max += hp; + } + rogue.exp = i; + print_stats(STAT_HP | STAT_EXP); + } + } else { + print_stats(STAT_EXP); + } +} + +int +hp_raise() +{ + int hp; + + hp = (wizard ? 10 : get_rand(3, 10)); + return(hp); +} + +void +show_average_hp() +{ + char mbuf[80]; + int real_average; + int effective_average; + int init_hp[2] = {INIT_HP}; + + if (rogue.exp == 1) { + real_average = effective_average = 0.00; + } else { + real_average = 100 * + ((rogue.hp_max - extra_hp - init_hp[0]) + less_hp) / (rogue.exp - 1); + effective_average = 100 * (rogue.hp_max - init_hp[0]) / (rogue.exp - 1); + + } + sprintf(mbuf, "R-Hp: %d.%02d, E-Hp: %d.%02d (!: %d, V: %d)", + real_average / 100, real_average % 100, + effective_average / 100, effective_average % 100, + extra_hp, less_hp); + message(mbuf, 0); +} diff --git a/src/games/rogue/machdep.c b/src/games/rogue/machdep.c new file mode 100644 index 0000000..00b6c56 --- /dev/null +++ b/src/games/rogue/machdep.c @@ -0,0 +1,626 @@ +/* + * This source herein may be modified and/or distributed by anybody who + * so desires, with the following restrictions: + * 1.) No portion of this notice shall be removed. + * 2.) Credit shall not be taken for the creation of this source. + * 3.) This code is not to be traded, sold, or used for personal + * gain or profit. + */ + +/* Included in this file are all system dependent routines. Extensive use + * of #ifdef's will be used to compile the appropriate code on each system: + * + * UNIX: all UNIX systems. + * UNIX_BSD4_2: UNIX BSD 4.2 and later, UTEK, (4.1 BSD too?) + * UNIX_SYSV: UNIX system V + * UNIX_V7: UNIX version 7 + * + * All UNIX code should be included between the single "#ifdef UNIX" at the + * top of this file, and the "#endif" at the bottom. + * + * To change a routine to include a new UNIX system, simply #ifdef the + * existing routine, as in the following example: + * + * To make a routine compatible with UNIX system 5, change the first + * function to the second: + * + * md_function() + * { + * code; + * } + * + * md_function() + * { + * #ifdef UNIX_SYSV + * sys5code; + * #else + * code; + * #endif + * } + * + * Appropriate variations of this are of course acceptible. + * The use of "#elseif" is discouraged because of non-portability. + * If the correct #define doesn't exist, "UNIX_SYSV" in this case, make it up + * and insert it in the list at the top of the file. Alter the CFLAGS + * in you Makefile appropriately. + */ +#ifdef UNIX + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef UNIX_BSD4_2 +#include +#include +#endif + +#ifdef UNIX_SYSV +#include +#include +#endif + +#include +#include "rogue.h" + +/* md_slurp: + * + * This routine throws away all keyboard input that has not + * yet been read. It is used to get rid of input that the user may have + * typed-ahead. + * + * This function is not necessary, so it may be stubbed. The might cause + * message-line output to flash by because the game has continued to read + * input without waiting for the user to read the message. Not such a + * big deal. + */ +void +md_slurp() +{ + long ln = 0; + +#ifdef UNIX_BSD4_2 + ioctl(0, FIONREAD, &ln); +#endif +#ifdef UNIX_SYSV + ioctl(0, TCFLSH, &ln); + ln = 0; +#endif + +#ifndef CROSS + ln += stdin->_cnt; +#endif + for (; ln > 0; ln--) { + (void) getchar(); + } +} + +/* md_control_keyboard(): + * + * This routine is much like md_cbreak_no_echo_nonl() below. It sets up the + * keyboard for appropriate input. Specifically, it prevents the tty driver + * from stealing characters. For example, ^Y is needed as a command + * character, but the tty driver intercepts it for another purpose. Any + * such behavior should be stopped. This routine could be avoided if + * we used RAW mode instead of CBREAK. But RAW mode does not allow the + * generation of keyboard signals, which the program uses. + * + * The parameter 'mode' when true, indicates that the keyboard should + * be set up to play rogue. When false, it should be restored if + * necessary. + * + * This routine is not strictly necessary and may be stubbed. This may + * cause certain command characters to be unavailable. + */ +void +md_control_keybord(mode) + boolean mode; +{ + static boolean called_before = 0; +#ifdef UNIX_BSD4_2 + static struct ltchars ltc_orig; + static struct tchars tc_orig; + struct ltchars ltc_temp; + struct tchars tc_temp; +#endif +#ifdef UNIX_SYSV + static struct termio _oldtty; + struct termio _tty; +#endif + + if (!called_before) { + called_before = 1; +#ifdef UNIX_BSD4_2 + ioctl(0, TIOCGETC, &tc_orig); + ioctl(0, TIOCGLTC, <c_orig); +#endif +#ifdef UNIX_SYSV + ioctl(0, TCGETA, &_oldtty); +#endif + } +#ifdef UNIX_BSD4_2 + ltc_temp = ltc_orig; + tc_temp = tc_orig; +#endif +#ifdef UNIX_SYSV + _tty = _oldtty; +#endif + + if (!mode) { +#ifdef UNIX_BSD4_2 + ltc_temp.t_suspc = ltc_temp.t_dsuspc = -1; + ltc_temp.t_rprntc = ltc_temp.t_flushc = -1; + ltc_temp.t_werasc = ltc_temp.t_lnextc = -1; + tc_temp.t_startc = tc_temp.t_stopc = -1; +#endif +#ifdef UNIX_SYSV + _tty.c_cc[VSWTC] = 0; +#endif + } +#ifdef UNIX_BSD4_2 + ioctl(0, TIOCSETC, &tc_temp); + ioctl(0, TIOCSLTC, <c_temp); +#endif +#ifdef UNIX_SYSV + ioctl(0, TCSETA, &_tty); +#endif +} + +/* md_heed_signals(): + * + * This routine tells the program to call particular routines when + * certain interrupts/events occur: + * + * SIGINT: call onintr() to interrupt fight with monster or long rest. + * SIGQUIT: call byebye() to check for game termination. + * SIGHUP: call error_save() to save game when terminal hangs up. + * + * On VMS, SIGINT and SIGQUIT correspond to ^C and ^Y. + * + * This routine is not strictly necessary and can be stubbed. This will + * mean that the game cannot be interrupted properly with keyboard + * input, this is not usually critical. + */ +void +md_heed_signals() +{ + signal(SIGINT, onintr); + signal(SIGQUIT, byebye); + signal(SIGHUP, error_save); +} + +/* md_ignore_signals(): + * + * This routine tells the program to completely ignore the events mentioned + * in md_heed_signals() above. The event handlers will later be turned on + * by a future call to md_heed_signals(), so md_heed_signals() and + * md_ignore_signals() need to work together. + * + * This function should be implemented or the user risks interrupting + * critical sections of code, which could cause score file, or saved-game + * file, corruption. + */ +void +md_ignore_signals() +{ + signal(SIGQUIT, SIG_IGN); + signal(SIGINT, SIG_IGN); + signal(SIGHUP, SIG_IGN); +} + +/* md_get_file_id(): + * + * This function returns an integer that uniquely identifies the specified + * file. It need not check for the file's existence. In UNIX, the inode + * number is used. + * + * This function is used to identify saved-game files. + */ +int +md_get_file_id(fname) + char *fname; +{ + struct stat sbuf; + + if (stat(fname, &sbuf)) { + return(-1); + } + return((int) sbuf.st_ino); +} + +/* md_link_count(): + * + * This routine returns the number of hard links to the specified file. + * + * This function is not strictly necessary. On systems without hard links + * this routine can be stubbed by just returning 1. + */ +int +md_link_count(fname) + char *fname; +{ + struct stat sbuf; + + stat(fname, &sbuf); + return((int) sbuf.st_nlink); +} + +/* md_gct(): (Get Current Time) + * + * This function returns the current year, month(1-12), day(1-31), hour(0-23), + * minute(0-59), and second(0-59). This is used for identifying the time + * at which a game is saved. + * + * This function is not strictly necessary. It can be stubbed by returning + * zeros instead of the correct year, month, etc. If your operating + * system doesn't provide all of the time units requested here, then you + * can provide only those that it does, and return zeros for the others. + * If you cannot provide good time values, then users may be able to copy + * saved-game files and play them. + */ +void +md_gct(rt_buf) + struct rogue_time *rt_buf; +{ + struct tm *t, *localtime(); + long seconds; + + time(&seconds); + t = localtime(&seconds); + + rt_buf->year = t->tm_year; + rt_buf->month = t->tm_mon + 1; + rt_buf->day = t->tm_mday; + rt_buf->hour = t->tm_hour; + rt_buf->minute = t->tm_min; + rt_buf->second = t->tm_sec; +} + +/* md_gfmt: (Get File Modification Time) + * + * This routine returns a file's date of last modification in the same format + * as md_gct() above. + * + * This function is not strictly necessary. It is used to see if saved-game + * files have been modified since they were saved. If you have stubbed the + * routine md_gct() above by returning constant values, then you may do + * exactly the same here. + * Or if md_gct() is implemented correctly, but your system does not provide + * file modification dates, you may return some date far in the past so + * that the program will never know that a saved-game file being modified. + * You may also do this if you wish to be able to restore games from + * saved-games that have been modified. + */ +void +md_gfmt(fname, rt_buf) + char *fname; + struct rogue_time *rt_buf; +{ + struct stat sbuf; + long seconds; + struct tm *t; + + stat(fname, &sbuf); + seconds = (long) sbuf.st_mtime; + t = localtime(&seconds); + + rt_buf->year = t->tm_year; + rt_buf->month = t->tm_mon + 1; + rt_buf->day = t->tm_mday; + rt_buf->hour = t->tm_hour; + rt_buf->minute = t->tm_min; + rt_buf->second = t->tm_sec; +} + +/* md_df: (Delete File) + * + * This function deletes the specified file, and returns true (1) if the + * operation was successful. This is used to delete saved-game files + * after restoring games from them. + * + * Again, this function is not strictly necessary, and can be stubbed + * by simply returning 1. In this case, saved-game files will not be + * deleted and can be replayed. + */ +boolean +md_df(fname) + char *fname; +{ + if (unlink(fname)) { + return(0); + } + return(1); +} + +/* md_gln: (Get login name) + * + * This routine returns the login name of the user. This string is + * used mainly for identifying users in score files. + * + * A dummy string may be returned if you are unable to implement this + * function, but then the score file would only have one name in it. + */ +char * +md_gln() +{ + struct passwd *p, *getpwuid(); + + if (!(p = getpwuid(getuid()))) + return((char *)NULL); + return(p->pw_name); +} + +/* md_sleep: + * + * This routine causes the game to pause for the specified number of + * seconds. + * + * This routine is not particularly necessary at all. It is used for + * delaying execution, which is useful to this program at some times. + */ +void +md_sleep(nsecs) + int nsecs; +{ + (void) sleep(nsecs); +} + +/* md_getenv() + * + * This routine gets certain values from the user's environment. These + * values are strings, and each string is identified by a name. The names + * of the values needed, and their use, is as follows: + * + * TERMCAP + * The name of the users's termcap file, NOT the termcap entries + * themselves. This is used ONLY if the program is compiled with + * CURSES defined (-DCURSES). Even in this case, the program need + * not find a string for TERMCAP. If it does not, it will use the + * default termcap file; + * TERM + * The name of the users's terminal. This is used ONLY if the program + * is compiled with CURSES defined (-DCURSES). In this case, the string + * value for TERM must be found, or the routines in curses.c cannot + * function, and the program will quit. + * ROGUEOPTS + * A string containing the various game options. This need not be + * defined. + * HOME + * The user's home directory. This is only used when the user specifies + * '~' as the first character of a saved-game file. This string need + * not be defined. + * SHELL + * The user's favorite shell. If not found, "/bin/sh" is assumed. + * + * If your system does not provide a means of searching for these values, + * you will have to do it yourself. None of the values above really need + * to be defined except TERM when the program is compiled with CURSES + * defined. In this case, as a bare minimum, you can check the 'name' + * parameter, and if it is "TERM" find the terminal name and return that, + * else return zero. If the program is not compiled with CURSES, you can + * get by with simply always returning zero. Returning zero indicates + * that their is no defined value for the given string. + */ +char * +md_getenv(name) + char *name; +{ + char *value; + char *getenv(); + + value = getenv(name); + + return(value); +} + +/* md_malloc() + * + * This routine allocates, and returns a pointer to, the specified number + * of bytes. This routines absolutely MUST be implemented for your + * particular system or the program will not run at all. Return zero + * when no more memory can be allocated. + */ +char * +md_malloc(n) + int n; +{ + char *t; + + t = malloc(n); + return(t); +} + +/* md_gseed() (Get Seed) + * + * This function returns a seed for the random number generator (RNG). This + * seed causes the RNG to begin generating numbers at some point in it's + * sequence. Without a random seed, the RNG will generate the same set + * of numbers, and every game will start out exactly the same way. A good + * number to use is the process id, given by getpid() on most UNIX systems. + * + * You need to find some single random integer, such as: + * process id. + * current time (minutes + seconds) returned from md_gct(), if implemented. + * + * It will not help to return "get_rand()" or "rand()" or the return value of + * any pseudo-RNG. If you don't have a random number, you can just return 1, + * but this means your games will ALWAYS start the same way, and will play + * exactly the same way given the same input. + */ +int +md_gseed() +{ + return(getpid()); +} + +/* md_exit(): + * + * This function causes the program to discontinue execution and exit. + * This function must be implemented or the program will continue to + * hang when it should quit. + */ +void +md_exit(status) + int status; +{ + exit(status); +} + +/* md_lock(): + * + * This function is intended to give the user exclusive access to the + * score file. It does so by "creat"ing a lock file, which can only + * be created if it does not already exist. The file is deleted when + * score file processing is finished. The lock file should be located + * in the same directory as the score file. These full path names should + * be defined for any particular site in rogue.h. The constants SCORE_FILE + * and LOCK_FILE define these file names. + * + * When the parameter 'l' is non-zero (true), a lock is requested. Otherwise + * the lock is released by removing the lock file. + */ +void +md_lock(l) + boolean l; +{ + int tries; + char *lock_file = LOCK_FILE; + + if (l) { + for (tries = 0; tries < 3; tries++) { + if (md_get_file_id(lock_file) == -1) { + if (creat(lock_file, 0444) != -1) { + break; + } else { + message("cannot lock score file", 0); + } + } else { + message("waiting to lock score file", 0); + } + sleep(1); + } + } else { + (void) unlink(lock_file); + } +} + +/* md_shell(): + * + * This function spawns a shell for the user to use. When this shell is + * terminated, the game continues. Since this program may often be run + * setuid to gain access to privileged files, care is taken that the shell + * is run with the user's REAL user id, and not the effective user id. + * The effective user id is restored after the shell completes. + */ +void +md_shell(shell) + char *shell; +{ + int w; + + if (fork() == 0) { + int uid; + + uid = getuid(); + setuid(uid); + execl(shell, shell, (char*)0); + } + wait(&w); +} + +/* If you have a viable curses/termlib library, then use it and don't bother + * implementing the routines below. And don't compile with -DCURSES. + */ + +#ifdef CURSES + +/* md_cbreak_no_echo_nonl: + * + * This routine sets up some terminal characteristics. The tty-driver + * must be told to: + * 1.) Not echo input. + * 2.) Transmit input characters immediately upon typing. (cbreak mode) + * 3.) Move the cursor down one line, without changing column, and + * without generating a carriage-return, when it + * sees a line-feed. This is only necessary if line-feed is ever + * used in the termcap 'do' (cursor down) entry, in which case, + * your system should must have a way of accomplishing this. + * + * When the parameter 'on' is true, the terminal is set up as specified + * above. When this parameter is false, the terminal is restored to the + * original state. + * + * Raw mode should not to be used. Keyboard signals/events/interrupts should + * be sent, although they are not strictly necessary. See notes in + * md_heed_signals(). + * + * This function must be implemented for rogue to run properly if the + * program is compiled with CURSES defined to use the enclosed curses + * emulation package. If you are not using this, then this routine is + * totally unnecessary. + * + * Notice that information is saved between calls. This is used to + * restore the terminal to an initial saved state. + * + */ +void +md_cbreak_no_echo_nonl(on) + boolean on; +{ +#ifdef UNIX_BSD4_2 + static struct sgttyb tty_buf; + static int tsave_flags; + + if (on) { + ioctl(0, TIOCGETP, &tty_buf); + tsave_flags = tty_buf.sg_flags; + tty_buf.sg_flags |= CBREAK; + tty_buf.sg_flags &= ~(ECHO | CRMOD); /* CRMOD: see note 3 above */ + ioctl(0, TIOCSETP, &tty_buf); + } else { + tty_buf.sg_flags = tsave_flags; + ioctl(0, TIOCSETP, &tty_buf); + } +#endif +#ifdef UNIX_SYSV + struct termio tty_buf; + static struct termio tty_save; + + if (on) { + ioctl(0, TCGETA, &tty_buf); + tty_save = tty_buf; + tty_buf.c_lflag &= ~(ICANON | ECHO); + tty_buf.c_oflag &= ~ONLCR; + tty_buf.c_cc[4] = 1; /* MIN */ + tty_buf.c_cc[5] = 2; /* TIME */ + ioctl(0, TCSETAF, &tty_buf); + } else { + ioctl(0, TCSETAF, &tty_save); + } +#endif +} + +/* md_tstp(): + * + * This function puts the game to sleep and returns to the shell. This + * only applies to UNIX 4.2 and 4.3. For other systems, the routine should + * be provided as a do-nothing routine. md_tstp() will only be referenced + * in the code when compiled with CURSES defined. + * + */ +void +md_tstp() +{ +#ifdef UNIX_BSD4_2 + kill(0, SIGTSTP); +#endif +} + +#endif + +#endif diff --git a/src/games/rogue/main.c b/src/games/rogue/main.c new file mode 100644 index 0000000..462ea36 --- /dev/null +++ b/src/games/rogue/main.c @@ -0,0 +1,34 @@ +/* + * This source herein may be modified and/or distributed by anybody who + * so desires, with the following restrictions: + * 1.) No portion of this notice shall be removed. + * 2.) Credit shall not be taken for the creation of this source. + * 3.) This code is not to be traded, sold, or used for personal + * gain or profit. + */ +#include "rogue.h" + +int +main(argc, argv) + int argc; + char *argv[]; +{ + if (init(argc, argv)) { /* restored game */ + goto PL; + } + + for (;;) { + clear_level(); + make_level(); + put_objects(); + put_stairs(); + add_traps(); + put_mons(); + put_player(party_room); + print_stats(STAT_ALL); +PL: + play_level(); + free_stuff(&level_objects); + free_stuff(&level_monsters); + } +} diff --git a/src/games/rogue/message.c b/src/games/rogue/message.c new file mode 100644 index 0000000..073dc95 --- /dev/null +++ b/src/games/rogue/message.c @@ -0,0 +1,343 @@ +/* + * This source herein may be modified and/or distributed by anybody who + * so desires, with the following restrictions: + * 1.) No portion of this notice shall be removed. + * 2.) Credit shall not be taken for the creation of this source. + * 3.) This code is not to be traded, sold, or used for personal + * gain or profit. + */ +#include +#include "rogue.h" + +char msgs[NMESSAGES][DCOLS] = {"", "", "", "", ""}; +short msg_col = 0, imsg = -1; +char msg_cleared = 1, rmsg = 0; +char hunger_str[8] = ""; +char *more = "-more-"; + +void +message(msg, intrpt) + char *msg; + boolean intrpt; +{ + cant_int = 1; + + if (!save_is_interactive) { + return; + } + if (intrpt) { + interrupted = 1; + md_slurp(); + } + + if (!msg_cleared) { + mvaddstr(MIN_ROW-1, msg_col, more); + refresh(); + wait_for_ack(); + check_message(); + } + if (!rmsg) { + imsg = (imsg + 1) % NMESSAGES; + (void) strcpy(msgs[imsg], msg); + } + mvaddstr(MIN_ROW-1, 0, msg); + addch(' '); + refresh(); + msg_cleared = 0; + msg_col = strlen(msg); + + cant_int = 0; + + if (did_int) { + did_int = 0; + onintr(0); + } +} + +void +remessage(c) + int c; +{ + if (imsg != -1) { + check_message(); + rmsg = 1; + while (c > imsg) { + c -= NMESSAGES; + } + message(msgs[((imsg - c) % NMESSAGES)], 0); + rmsg = 0; + move(rogue.row, rogue.col); + refresh(); + } +} + +void +check_message() +{ + if (msg_cleared) { + return; + } + move(MIN_ROW-1, 0); + clrtoeol(); + refresh(); + msg_cleared = 1; +} + +int +get_input_line(prompt, insert, buf, if_cancelled, add_blank, do_echo) + char *prompt, *buf, *insert; + char *if_cancelled; + boolean add_blank; + boolean do_echo; +{ + int ch; + int i = 0, n; + + message(prompt, 0); + n = strlen(prompt); + + if (insert[0]) { + mvaddstr(0, n + 1, insert); + (void) strcpy(buf, insert); + i = strlen(insert); + move(0, (n + i + 1)); + refresh(); + } + + while (((ch = rgetchar()) != '\r') && (ch != '\n') && (ch != CANCEL)) { + if ((ch >= ' ') && (ch <= '~') && (i < MAX_TITLE_LENGTH-2)) { + if ((ch != ' ') || (i > 0)) { + buf[i++] = ch; + if (do_echo) { + addch(ch); + } + } + } + if ((ch == '\b') && (i > 0)) { + if (do_echo) { + mvaddch(0, i + n, ' '); + move(MIN_ROW-1, i+n); + } + i--; + } + refresh(); + } + check_message(); + if (add_blank) { + buf[i++] = ' '; + } else { + while ((i > 0) && (buf[i-1] == ' ')) { + i--; + } + } + + buf[i] = 0; + + if ((ch == CANCEL) || (i == 0) || ((i == 1) && add_blank)) { + if (if_cancelled) { + message(if_cancelled, 0); + } + return(0); + } + return(i); +} + +static void +save_screen() +{ + FILE *fp; + int i, j; + char buf[DCOLS+2]; + boolean found_non_blank; + + fp = fopen("rogue.screen", "w"); + if (fp != NULL) { + for (i = 0; i < DROWS; i++) { + found_non_blank = 0; + for (j = (DCOLS - 1); j >= 0; j--) { + buf[j] = mvinch(i, j); + if (!found_non_blank) { + if ((buf[j] != ' ') || (j == 0)) { + buf[j + ((j == 0) ? 0 : 1)] = 0; + found_non_blank = 1; + } + } + } + fputs(buf, fp); + putc('\n', fp); + } + fclose(fp); + } else { + sound_bell(); + } +} + +int +rgetchar() +{ + register int ch; + + for(;;) { + ch = getchar(); + + switch(ch) { + case '\022': + wrefresh(curscr); + break; +#ifdef UNIX_BSD4_2 + case '\032': + fputs(CL, stdout); + fflush(stdout); + tstp(); + break; +#endif + case '&': + save_screen(); + break; + default: + return(ch); + } + } +} + +static void +pad(s, n) + char *s; + int n; +{ + int i; + + i = strlen(s); + while (i++ < n) { + addch(' '); + } +} + +/* + * Level: 99 Gold: 999999 Hp: 999(999) Str: 99(99) Arm: 99 Exp: 21/10000000 Hungry + * 0 5 1 5 2 5 3 5 4 5 5 5 6 5 7 5 + */ +void +print_stats(stat_mask) + register int stat_mask; +{ + char buf[16]; + boolean label; + int row = DROWS - 1; + + label = (stat_mask & STAT_LABEL) ? 1 : 0; + + if (stat_mask & STAT_LEVEL) { + if (label) { + mvaddstr(row, 0, "Level: "); + } + /* max level taken care of in make_level() */ + sprintf(buf, "%d", cur_level); + mvaddstr(row, 7, buf); + pad(buf, 2); + } + if (stat_mask & STAT_GOLD) { + if (label) { + mvaddstr(row, 10, "Gold: "); + } + if (rogue.gold > MAX_GOLD) { + rogue.gold = MAX_GOLD; + } + sprintf(buf, "%ld", rogue.gold); + mvaddstr(row, 16, buf); + pad(buf, 6); + } + if (stat_mask & STAT_HP) { + if (label) { + mvaddstr(row, 23, "Hp: "); + } + if (rogue.hp_max > MAX_HP) { + rogue.hp_current -= (rogue.hp_max - MAX_HP); + rogue.hp_max = MAX_HP; + } + sprintf(buf, "%d(%d)", rogue.hp_current, rogue.hp_max); + mvaddstr(row, 27, buf); + pad(buf, 8); + } + if (stat_mask & STAT_STRENGTH) { + if (label) { + mvaddstr(row, 36, "Str: "); + } + if (rogue.str_max > MAX_STRENGTH) { + rogue.str_current -= (rogue.str_max - MAX_STRENGTH); + rogue.str_max = MAX_STRENGTH; + } + sprintf(buf, "%d(%d)", (rogue.str_current + add_strength), + rogue.str_max); + mvaddstr(row, 41, buf); + pad(buf, 6); + } + if (stat_mask & STAT_ARMOR) { + if (label) { + mvaddstr(row, 48, "Arm: "); + } + if (rogue.armor && (rogue.armor->d_enchant > MAX_ARMOR)) { + rogue.armor->d_enchant = MAX_ARMOR; + } + sprintf(buf, "%d", get_armor_class(rogue.armor)); + mvaddstr(row, 53, buf); + pad(buf, 2); + } + if (stat_mask & STAT_EXP) { + if (label) { + mvaddstr(row, 56, "Exp: "); + } + if (rogue.exp_points > MAX_EXP) { + rogue.exp_points = MAX_EXP; + } + if (rogue.exp > MAX_EXP_LEVEL) { + rogue.exp = MAX_EXP_LEVEL; + } + sprintf(buf, "%d/%ld", rogue.exp, rogue.exp_points); + mvaddstr(row, 61, buf); + pad(buf, 11); + } + if (stat_mask & STAT_HUNGER) { + mvaddstr(row, 73, hunger_str); + clrtoeol(); + } + refresh(); +} + +void +sound_bell() +{ + putchar(7); + fflush(stdout); +} + +boolean +is_digit(ch) + int ch; +{ + return((ch >= '0') && (ch <= '9')); +} + +int +r_index(str, ch, last) + char *str; + int ch; + boolean last; +{ + int i = 0; + + if (last) { + for (i = strlen(str) - 1; i >= 0; i--) { + if (str[i] == ch) { + return(i); + } + } + } else { + for (i = 0; str[i]; i++) { + if (str[i] == ch) { + return(i); + } + } + } + return(-1); +} diff --git a/src/games/rogue/monster.c b/src/games/rogue/monster.c new file mode 100644 index 0000000..598c041 --- /dev/null +++ b/src/games/rogue/monster.c @@ -0,0 +1,841 @@ +/* + * This source herein may be modified and/or distributed by anybody who + * so desires, with the following restrictions: + * 1.) No portion of this notice shall be removed. + * 2.) Credit shall not be taken for the creation of this source. + * 3.) This code is not to be traded, sold, or used for personal + * gain or profit. + */ +#include "rogue.h" + +object level_monsters; +char mon_disappeared; + +char *m_names[] = { + "aquator", + "bat", + "centaur", + "dragon", + "emu", + "venus fly-trap", + "griffin", + "hobgoblin", + "ice monster", + "jabberwock", + "kestrel", + "leprechaun", + "medusa", + "nymph", + "orc", + "phantom", + "quagga", + "rattlesnake", + "snake", + "troll", + "black unicorn", + "vampire", + "wraith", + "xeroc", + "yeti", + "zombie" +}; + +object mon_tab[MONSTERS] = { + {(ASLEEP|WAKENS|WANDERS|RUSTS),"0d0",25,'A',20,9,18,100,0,0,0,0,0}, + {(ASLEEP|WANDERS|FLITS|FLIES),"1d3",10,'B',2,1,8,60,0,0,0,0,0}, + {(ASLEEP|WANDERS),"3d3/2d5",32,'C',15,7,16,85,0,10,0,0,0}, + {(ASLEEP|WAKENS|FLAMES),"4d6/4d9",145,'D',5000,21,126,100,0,90,0,0,0}, + {(ASLEEP|WAKENS),"1d3",11,'E',2,1,7,65,0,0,0,0,0}, + {(HOLDS|STATIONARY),"5d5",73,'F',91,12,126,80,0,0,0,0,0}, + {(ASLEEP|WAKENS|WANDERS|FLIES),"5d5/5d5",115,'G', + 2000,20,126,85,0,10,0,0,0}, + {(ASLEEP|WAKENS|WANDERS),"1d3/1d2",15,'H',3,1,10,67,0,0,0,0,0}, + {(ASLEEP|FREEZES),"0d0",15,'I',5,2,11,68,0,0,0,0,0}, + {(ASLEEP|WANDERS),"3d10/4d5",132,'J',3000,21,126,100,0,0,0,0,0}, + {(ASLEEP|WAKENS|WANDERS|FLIES),"1d4",10,'K',2,1,6,60,0,0,0,0,0}, + {(ASLEEP|STEALS_GOLD),"0d0",25,'L',21,6,16,75,0,0,0,0,0}, + {(ASLEEP|WAKENS|WANDERS|CONFUSES),"4d4/3d7",97,'M', + 250,18,126,85,0,25,0,0,0}, + {(ASLEEP|STEALS_ITEM),"0d0",25,'N',39,10,19,75,0,100,0,0,0}, + {(ASLEEP|WANDERS|WAKENS|SEEKS_GOLD),"1d6",25,'O',5,4,13,70,0,10,0,0,0}, + {(ASLEEP|INVISIBLE|WANDERS|FLITS),"5d4",76,'P',120,15,24,80,0,50,0,0,0}, + {(ASLEEP|WAKENS|WANDERS),"3d5",30,'Q',20,8,17,78,0,20,0,0,0}, + {(ASLEEP|WAKENS|WANDERS|STINGS),"2d5",19,'R',10,3,12,70,0,0,0,0,0}, + {(ASLEEP|WAKENS|WANDERS),"1d3",8,'S',2,1,9,50,0,0,0,0,0}, + {(ASLEEP|WAKENS|WANDERS),"4d6/1d4",75,'T',125,13,22,75,0,33,0,0,0}, + {(ASLEEP|WAKENS|WANDERS),"4d10",90,'U', + 200,17,26,85,0,33,0,0,0}, + {(ASLEEP|WAKENS|WANDERS|DRAINS_LIFE),"1d14/1d4",55,'V', + 350,19,126,85,0,18,0,0,0}, + {(ASLEEP|WANDERS|DROPS_LEVEL),"2d8",45,'W',55,14,23,75,0,0,0,0,0}, + {(ASLEEP|IMITATES),"4d6",42,'X',110,16,25,75,0,0,0,0,0}, + {(ASLEEP|WANDERS),"3d6",35,'Y',50,11,20,80,0,20,0,0,0}, + {(ASLEEP|WAKENS|WANDERS),"1d7",21,'Z',8,5,14,69,0,0,0,0,0} +}; + +static void +aim_monster(monster) + object *monster; +{ + int i, rn, d, r; + + rn = get_room_number(monster->row, monster->col); + r = get_rand(0, 12); + + for (i = 0; i < 4; i++) { + d = (r + i) % 4; + if (rooms[rn].doors[d].oth_room != NO_ROOM) { + monster->trow = rooms[rn].doors[d].door_row; + monster->tcol = rooms[rn].doors[d].door_col; + break; + } + } +} + +static void +put_m_at(row, col, monster) + int row, col; + object *monster; +{ + monster->row = row; + monster->col = col; + dungeon[row][col] |= MONSTER; + monster->trail_char = mvinch(row, col); + (void) add_to_pack(monster, &level_monsters, 0); + aim_monster(monster); +} + +void +put_mons() +{ + int i, n; + object *monster; + int row, col; + + n = get_rand(4, 6); + + for (i = 0; i < n; i++) { + monster = gr_monster((object *) 0, 0); + if ((monster->m_flags & WANDERS) && coin_toss()) { + wake_up(monster); + } + gr_row_col(&row, &col, (FLOOR | TUNNEL | STAIRS | OBJECT)); + put_m_at(row, col, monster); + } +} + +object * +gr_monster(monster, mn) + register object *monster; + register int mn; +{ + if (!monster) { + monster = alloc_object(); + + for (;;) { + mn = get_rand(0, MONSTERS-1); + if ((cur_level >= mon_tab[mn].first_level) && + (cur_level <= mon_tab[mn].last_level)) { + break; + } + } + } + *monster = mon_tab[mn]; + if (monster->m_flags & IMITATES) { + monster->disguise = gr_obj_char(); + } + if (cur_level > (AMULET_LEVEL + 2)) { + monster->m_flags |= HASTED; + } + monster->trow = NO_ROOM; + return(monster); +} + +static int +mtry(monster, row, col) + register object *monster; + register int row, col; +{ + if (mon_can_go(monster, row, col)) { + move_mon_to(monster, row, col); + return(1); + } + return(0); +} + +static int +move_confused(monster) + object *monster; +{ + int i, row, col; + + if (!(monster->m_flags & ASLEEP)) { + if (--monster->moves_confused <= 0) { + monster->m_flags &= (~CONFUSED); + } + if (monster->m_flags & STATIONARY) { + return(coin_toss() ? 1 : 0); + } else if (rand_percent(15)) { + return(1); + } + row = monster->row; + col = monster->col; + + for (i = 0; i < 9; i++) { + rand_around(i, &row, &col); + if ((row == rogue.row) && (col == rogue.col)) { + return(0); + } + if (mtry(monster, row, col)) { + return(1); + } + } + } + return(0); +} + +void +mv_mons() +{ + register object *monster, *next_monster; + boolean flew; + + if (haste_self % 2) { + return; + } + + monster = level_monsters.next_monster; + + while (monster) { + next_monster = monster->next_monster; + mon_disappeared = 0; + if (monster->m_flags & HASTED) { + mv_1_monster(monster, rogue.row, rogue.col); + if (mon_disappeared) { + goto NM; + } + } else if (monster->m_flags & SLOWED) { + monster->slowed_toggle = !monster->slowed_toggle; + if (monster->slowed_toggle) { + goto NM; + } + } + if ((monster->m_flags & CONFUSED) && move_confused(monster)) { + goto NM; + } + flew = 0; + if ( (monster->m_flags & FLIES) && + !(monster->m_flags & NAPPING) && + !mon_can_go(monster, rogue.row, rogue.col)) { + flew = 1; + mv_1_monster(monster, rogue.row, rogue.col); + if (mon_disappeared) { + goto NM; + } + } + if (!(flew && mon_can_go(monster, rogue.row, rogue.col))) { + mv_1_monster(monster, rogue.row, rogue.col); + } +NM: monster = next_monster; + } +} + +static int +no_room_for_monster(rn) + int rn; +{ + int i, j; + + for (i = rooms[rn].top_row+1; i < rooms[rn].bottom_row; i++) { + for (j = rooms[rn].left_col+1; j < rooms[rn].right_col; j++) { + if (!(dungeon[i][j] & MONSTER)) { + return(0); + } + } + } + return(1); +} + +void +party_monsters(rn, n) + int rn, n; +{ + int i, j; + int row, col; + object *monster; + boolean found; + + n += n; + + for (i = 0; i < MONSTERS; i++) { + mon_tab[i].first_level -= (cur_level % 3); + } + for (i = 0; i < n; i++) { + if (no_room_for_monster(rn)) { + break; + } + for (j = found = 0; ((!found) && (j < 250)); j++) { + row = get_rand(rooms[rn].top_row+1, + rooms[rn].bottom_row-1); + col = get_rand(rooms[rn].left_col+1, + rooms[rn].right_col-1); + if ((!(dungeon[row][col] & MONSTER)) && + (dungeon[row][col] & (FLOOR | TUNNEL))) { + found = 1; + } + } + if (found) { + monster = gr_monster((object *) 0, 0); + if (!(monster->m_flags & IMITATES)) { + monster->m_flags |= WAKENS; + } + put_m_at(row, col, monster); + } + } + for (i = 0; i < MONSTERS; i++) { + mon_tab[i].first_level += (cur_level % 3); + } +} + +int +gmc_row_col(row, col) + register int row, col; +{ + register object *monster; + + monster = object_at(&level_monsters, row, col); + if (monster) { + if ((!(detect_monster || see_invisible || r_see_invisible) && + (monster->m_flags & INVISIBLE)) || blind) { + return(monster->trail_char); + } + if (monster->m_flags & IMITATES) { + return(monster->disguise); + } + return(monster->m_char); + } else { + return('&'); /* BUG if this ever happens */ + } +} + +int +gmc(monster) + object *monster; +{ + if ((!(detect_monster || see_invisible || r_see_invisible) && + (monster->m_flags & INVISIBLE)) + || blind) { + return(monster->trail_char); + } + if (monster->m_flags & IMITATES) { + return(monster->disguise); + } + return(monster->m_char); +} + +static int +rogue_is_around(row, col) + register int row, col; +{ + int rdif, cdif, retval; + + rdif = row - rogue.row; + cdif = col - rogue.col; + + retval = (rdif >= -1) && (rdif <= 1) && (cdif >= -1) && (cdif <= 1); + return(retval); +} + +static int +flit(monster) + object *monster; +{ + int i, row, col; + + if (!rand_percent(FLIT_PERCENT + ((monster->m_flags & FLIES) ? 20 : 0))) { + return(0); + } + if (rand_percent(10)) { + return(1); + } + row = monster->row; + col = monster->col; + + for (i = 0; i < 9; i++) { + rand_around(i, &row, &col); + if ((row == rogue.row) && (col == rogue.col)) { + continue; + } + if (mtry(monster, row, col)) { + return(1); + } + } + return(1); +} + +void +mv_1_monster(monster, row, col) + register object *monster; + int row, col; +{ + int i, n; + boolean tried[6]; + + if (monster->m_flags & ASLEEP) { + if (monster->m_flags & NAPPING) { + if (--monster->nap_length <= 0) { + monster->m_flags &= (~(NAPPING | ASLEEP)); + } + return; + } + if ((monster->m_flags & WAKENS) && + rogue_is_around(monster->row, monster->col) && + rand_percent(((stealthy > 0) ? + (WAKE_PERCENT / (STEALTH_FACTOR + stealthy)) : + WAKE_PERCENT))) { + wake_up(monster); + } + return; + } else if (monster->m_flags & ALREADY_MOVED) { + monster->m_flags &= (~ALREADY_MOVED); + return; + } + if ((monster->m_flags & FLITS) && flit(monster)) { + return; + } + if ((monster->m_flags & STATIONARY) && + (!mon_can_go(monster, rogue.row, rogue.col))) { + return; + } + if (monster->m_flags & FREEZING_ROGUE) { + return; + } + if ((monster->m_flags & CONFUSES) && m_confuse(monster)) { + return; + } + if (mon_can_go(monster, rogue.row, rogue.col)) { + mon_hit(monster); + return; + } + if ((monster->m_flags & FLAMES) && flame_broil(monster)) { + return; + } + if ((monster->m_flags & SEEKS_GOLD) && seek_gold(monster)) { + return; + } + if ((monster->trow == monster->row) && + (monster->tcol == monster->col)) { + monster->trow = NO_ROOM; + } else if (monster->trow != NO_ROOM) { + row = monster->trow; + col = monster->tcol; + } + if (monster->row > row) { + row = monster->row - 1; + } else if (monster->row < row) { + row = monster->row + 1; + } + if ((dungeon[row][monster->col] & DOOR) && + mtry(monster, row, monster->col)) { + return; + } + if (monster->col > col) { + col = monster->col - 1; + } else if (monster->col < col) { + col = monster->col + 1; + } + if ((dungeon[monster->row][col] & DOOR) && + mtry(monster, monster->row, col)) { + return; + } + if (mtry(monster, row, col)) { + return; + } + + for (i = 0; i <= 5; i++) tried[i] = 0; + + for (i = 0; i < 6; i++) { +NEXT_TRY: n = get_rand(0, 5); + switch(n) { + case 0: + if (!tried[n] && mtry(monster, row, monster->col-1)) { + goto O; + } + break; + case 1: + if (!tried[n] && mtry(monster, row, monster->col)) { + goto O; + } + break; + case 2: + if (!tried[n] && mtry(monster, row, monster->col+1)) { + goto O; + } + break; + case 3: + if (!tried[n] && mtry(monster, monster->row-1, col)) { + goto O; + } + break; + case 4: + if (!tried[n] && mtry(monster, monster->row, col)) { + goto O; + } + break; + case 5: + if (!tried[n] && mtry(monster, monster->row+1, col)) { + goto O; + } + break; + } + if (!tried[n]) { + tried[n] = 1; + } else { + goto NEXT_TRY; + } + } +O: + if ((monster->row == monster->o_row) && (monster->col == monster->o_col)) { + if (++(monster->o) > 4) { + if ((monster->trow == NO_ROOM) && + (!mon_sees(monster, rogue.row, rogue.col))) { + monster->trow = get_rand(1, (DROWS - 2)); + monster->tcol = get_rand(0, (DCOLS - 1)); + } else { + monster->trow = NO_ROOM; + monster->o = 0; + } + } + } else { + monster->o_row = monster->row; + monster->o_col = monster->col; + monster->o = 0; + } +} + +void +move_mon_to(monster, row, col) + register object *monster; + register int row, col; +{ + int c; + register int mrow, mcol; + + mrow = monster->row; + mcol = monster->col; + + dungeon[mrow][mcol] &= ~MONSTER; + dungeon[row][col] |= MONSTER; + + c = mvinch(mrow, mcol); + + if ((c >= 'A') && (c <= 'Z')) { + if (!detect_monster) { + mvaddch(mrow, mcol, monster->trail_char); + } else { + if (rogue_can_see(mrow, mcol)) { + mvaddch(mrow, mcol, monster->trail_char); + } else { + if (monster->trail_char == '.') { + monster->trail_char = ' '; + } + mvaddch(mrow, mcol, monster->trail_char); + } + } + } + monster->trail_char = mvinch(row, col); + if (!blind && (detect_monster || rogue_can_see(row, col))) { + if ((!(monster->m_flags & INVISIBLE) || + (detect_monster || see_invisible || r_see_invisible))) { + mvaddch(row, col, gmc(monster)); + } + } + if ((dungeon[row][col] & DOOR) && + (get_room_number(row, col) != cur_room) && + (dungeon[mrow][mcol] == FLOOR) && !blind) { + mvaddch(mrow, mcol, ' '); + } + if (dungeon[row][col] & DOOR) { + dr_course(monster, ((dungeon[mrow][mcol] & TUNNEL) ? 1 : 0), + row, col); + } else { + monster->row = row; + monster->col = col; + } +} + +int +mon_can_go(monster, row, col) + register object *monster; + register int row, col; +{ + object *obj; + int dr, dc; + + dr = monster->row - row; /* check if move distance > 1 */ + if ((dr >= 2) || (dr <= -2)) { + return(0); + } + dc = monster->col - col; + if ((dc >= 2) || (dc <= -2)) { + return(0); + } + if ((!dungeon[monster->row][col]) || (!dungeon[row][monster->col])) { + return(0); + } + if ((!is_passable(row, col)) || (dungeon[row][col] & MONSTER)) { + return(0); + } + if ((monster->row!=row)&&(monster->col!=col)&&((dungeon[row][col]&DOOR) || + (dungeon[monster->row][monster->col]&DOOR))) { + return(0); + } + if (!(monster->m_flags & (FLITS | CONFUSED | CAN_FLIT)) && + (monster->trow == NO_ROOM)) { + if ((monster->row < rogue.row) && (row < monster->row)) return(0); + if ((monster->row > rogue.row) && (row > monster->row)) return(0); + if ((monster->col < rogue.col) && (col < monster->col)) return(0); + if ((monster->col > rogue.col) && (col > monster->col)) return(0); + } + if (dungeon[row][col] & OBJECT) { + obj = object_at(&level_objects, row, col); + if ((obj->what_is == SCROL) && (obj->which_kind == SCARE_MONSTER)) { + return(0); + } + } + return(1); +} + +void +wake_up(monster) + object *monster; +{ + if (!(monster->m_flags & NAPPING)) { + monster->m_flags &= (~(ASLEEP | IMITATES | WAKENS)); + } +} + +void +wake_room(rn, entering, row, col) + int rn; + boolean entering; + int row, col; +{ + object *monster; + int wake_percent; + boolean in_room; + + wake_percent = (rn == party_room) ? PARTY_WAKE_PERCENT : WAKE_PERCENT; + if (stealthy > 0) { + wake_percent /= (STEALTH_FACTOR + stealthy); + } + + monster = level_monsters.next_monster; + + while (monster) { + in_room = (rn == get_room_number(monster->row, monster->col)); + if (in_room) { + if (entering) { + monster->trow = NO_ROOM; + } else { + monster->trow = row; + monster->tcol = col; + } + } + if ((monster->m_flags & WAKENS) && + (rn == get_room_number(monster->row, monster->col))) { + if (rand_percent(wake_percent)) { + wake_up(monster); + } + } + monster = monster->next_monster; + } +} + +char * +mon_name(monster) + object *monster; +{ + int ch; + + if (blind || ((monster->m_flags & INVISIBLE) && + !(detect_monster || see_invisible || r_see_invisible))) { + return("something"); + } + if (halluc) { + ch = get_rand('A', 'Z') - 'A'; + return(m_names[ch]); + } + ch = monster->m_char - 'A'; + return(m_names[ch]); +} + +void +wanderer() +{ + object *monster; + int row, col, i; + boolean found = 0; + + for (i = 0; ((i < 15) && (!found)); i++) { + monster = gr_monster((object *) 0, 0); + if (!(monster->m_flags & (WAKENS | WANDERS))) { + free_object(monster); + } else { + found = 1; + } + } + if (found) { + found = 0; + wake_up(monster); + for (i = 0; ((i < 25) && (!found)); i++) { + gr_row_col(&row, &col, (FLOOR | TUNNEL | STAIRS | OBJECT)); + if (!rogue_can_see(row, col)) { + put_m_at(row, col, monster); + found = 1; + } + } + if (!found) { + free_object(monster); + } + } +} + +void +show_monsters() +{ + object *monster; + + detect_monster = 1; + + if (blind) { + return; + } + monster = level_monsters.next_monster; + + while (monster) { + mvaddch(monster->row, monster->col, monster->m_char); + if (monster->m_flags & IMITATES) { + monster->m_flags &= (~IMITATES); + monster->m_flags |= WAKENS; + } + monster = monster->next_monster; + } +} + +void +create_monster() +{ + int row, col; + int i; + boolean found = 0; + object *monster; + + row = rogue.row; + col = rogue.col; + + for (i = 0; i < 9; i++) { + rand_around(i, &row, &col); + if (((row == rogue.row) && (col = rogue.col)) || + (row < MIN_ROW) || (row > (DROWS-2)) || + (col < 0) || (col > (DCOLS-1))) { + continue; + } + if ((!(dungeon[row][col] & MONSTER)) && + (dungeon[row][col] & (FLOOR|TUNNEL|STAIRS|DOOR))) { + found = 1; + break; + } + } + if (found) { + monster = gr_monster((object *) 0, 0); + put_m_at(row, col, monster); + mvaddch(row, col, gmc(monster)); + if (monster->m_flags & (WANDERS | WAKENS)) { + wake_up(monster); + } + } else { + message("you hear a faint cry of anguish in the distance", 0); + } +} + +int +rogue_can_see(row, col) + register int row, col; +{ + register int retval; + + retval = !blind && + (((get_room_number(row, col) == cur_room) && + !(rooms[cur_room].is_room & R_MAZE)) || + rogue_is_around(row, col)); + + return(retval); +} + +int +gr_obj_char() +{ + int r; + char *rs = "%!?]=/):*"; + + r = get_rand(0, 8); + + return(rs[r]); +} + +void +aggravate() +{ + object *monster; + + message("you hear a high pitched humming noise", 0); + + monster = level_monsters.next_monster; + + while (monster) { + wake_up(monster); + monster->m_flags &= (~IMITATES); + if (rogue_can_see(monster->row, monster->col)) { + mvaddch(monster->row, monster->col, monster->m_char); + } + monster = monster->next_monster; + } +} + +boolean +mon_sees(monster, row, col) + object *monster; +{ + int rn, rdif, cdif, retval; + + rn = get_room_number(row, col); + + if ( (rn != NO_ROOM) && + (rn == get_room_number(monster->row, monster->col)) && + !(rooms[rn].is_room & R_MAZE)) { + return(1); + } + rdif = row - monster->row; + cdif = col - monster->col; + + retval = (rdif >= -1) && (rdif <= 1) && (cdif >= -1) && (cdif <= 1); + return(retval); +} + +void +mv_aquatars() +{ + object *monster; + + monster = level_monsters.next_monster; + + while (monster) { + if ((monster->m_char == 'A') && + mon_can_go(monster, rogue.row, rogue.col)) { + mv_1_monster(monster, rogue.row, rogue.col); + monster->m_flags |= ALREADY_MOVED; + } + monster = monster->next_monster; + } +} diff --git a/src/games/rogue/move.c b/src/games/rogue/move.c new file mode 100644 index 0000000..738c870 --- /dev/null +++ b/src/games/rogue/move.c @@ -0,0 +1,609 @@ +/* + * This source herein may be modified and/or distributed by anybody who + * so desires, with the following restrictions: + * 1.) No portion of this notice shall be removed. + * 2.) Credit shall not be taken for the creation of this source. + * 3.) This code is not to be traded, sold, or used for personal + * gain or profit. + */ +#include +#include "rogue.h" + +short m_moves = 0; +char jump = 0; +char *you_can_move_again = "you can move again"; + +static int +gr_dir() +{ + int d; + + d = get_rand(1, 8); + + switch(d) { + case 1: + d = 'j'; + break; + case 2: + d = 'k'; + break; + case 3: + d = 'l'; + break; + case 4: + d = 'h'; + break; + case 5: + d = 'y'; + break; + case 6: + d = 'u'; + break; + case 7: + d = 'b'; + break; + case 8: + d = 'n'; + break; + } + return(d); +} + +int +one_move_rogue(dirch, pickup) + int dirch, pickup; +{ + int row, col; + object *obj; + char desc[DCOLS]; + int n, status, d; + + row = rogue.row; + col = rogue.col; + + if (confused) { + dirch = gr_dir(); + } + (void) is_direction(dirch, &d); + get_dir_rc(d, &row, &col, 1); + + if (!can_move(rogue.row, rogue.col, row, col)) { + return(MOVE_FAILED); + } + if (being_held || bear_trap) { + if (!(dungeon[row][col] & MONSTER)) { + if (being_held) { + message("you are being held", 1); + } else { + message("you are still stuck in the bear trap", 0); + (void) reg_move(); + } + return(MOVE_FAILED); + } + } + if (r_teleport) { + if (rand_percent(R_TELE_PERCENT)) { + tele(); + return(STOPPED_ON_SOMETHING); + } + } + if (dungeon[row][col] & MONSTER) { + rogue_hit(object_at(&level_monsters, row, col), 0); + (void) reg_move(); + return(MOVE_FAILED); + } + if (dungeon[row][col] & DOOR) { + if (cur_room == PASSAGE) { + cur_room = get_room_number(row, col); + light_up_room(cur_room); + wake_room(cur_room, 1, row, col); + } else { + light_passage(row, col); + } + } else if ((dungeon[rogue.row][rogue.col] & DOOR) && + (dungeon[row][col] & TUNNEL)) { + light_passage(row, col); + wake_room(cur_room, 0, rogue.row, rogue.col); + darken_room(cur_room); + cur_room = PASSAGE; + } else if (dungeon[row][col] & TUNNEL) { + light_passage(row, col); + } + mvaddch(rogue.row, rogue.col, get_dungeon_char(rogue.row, rogue.col)); + mvaddch(row, col, rogue.fchar); + + if (!jump) { + refresh(); + } + rogue.row = row; + rogue.col = col; + if (dungeon[row][col] & OBJECT) { + if (levitate && pickup) { + return(STOPPED_ON_SOMETHING); + } + if (pickup && !levitate) { + obj = pick_up(row, col, &status); + if (obj) { + get_desc(obj, desc); + if (obj->what_is == GOLD) { + free_object(obj); + goto NOT_IN_PACK; + } + } else if (!status) { + goto MVED; + } else { + goto MOVE_ON; + } + } else { +MOVE_ON: + obj = object_at(&level_objects, row, col); + (void) strcpy(desc, "moved onto "); + get_desc(obj, desc+11); + goto NOT_IN_PACK; + } + n = strlen(desc); + desc[n] = '('; + desc[n+1] = obj->ichar; + desc[n+2] = ')'; + desc[n+3] = 0; +NOT_IN_PACK: + message(desc, 1); + (void) reg_move(); + return(STOPPED_ON_SOMETHING); + } + if (dungeon[row][col] & (DOOR | STAIRS | TRAP)) { + if ((!levitate) && (dungeon[row][col] & TRAP)) { + trap_player(row, col); + } + (void) reg_move(); + return(STOPPED_ON_SOMETHING); + } +MVED: if (reg_move()) { /* fainted from hunger */ + return(STOPPED_ON_SOMETHING); + } + return((confused ? STOPPED_ON_SOMETHING : MOVED)); +} + +static boolean +can_turn(nrow, ncol) + int nrow, ncol; +{ + if ((dungeon[nrow][ncol] & TUNNEL) && is_passable(nrow, ncol)) { + return(1); + } + return(0); +} + +static void +turn_passage(dir, fast) + int dir; + boolean fast; +{ + int crow = rogue.row, ccol = rogue.col, turns = 0; + int ndir; + + if ((dir != 'h') && can_turn(crow, ccol + 1)) { + turns++; + ndir = 'l'; + } + if ((dir != 'l') && can_turn(crow, ccol - 1)) { + turns++; + ndir = 'h'; + } + if ((dir != 'k') && can_turn(crow + 1, ccol)) { + turns++; + ndir = 'j'; + } + if ((dir != 'j') && can_turn(crow - 1, ccol)) { + turns++; + ndir = 'k'; + } + if (turns == 1) { + multiple_move_rogue(ndir - (fast ? 32 : 96)); + } +} + +static int +next_to_something(drow, dcol) + register int drow, dcol; +{ + int i, j, i_end, j_end, row, col; + int pass_count = 0; + unsigned s; + + if (confused) { + return(1); + } + if (blind) { + return(0); + } + i_end = (rogue.row < (DROWS-2)) ? 1 : 0; + j_end = (rogue.col < (DCOLS-1)) ? 1 : 0; + + for (i = ((rogue.row > MIN_ROW) ? -1 : 0); i <= i_end; i++) { + for (j = ((rogue.col > 0) ? -1 : 0); j <= j_end; j++) { + if ((i == 0) && (j == 0)) { + continue; + } + if (((rogue.row+i) == drow) && ((rogue.col+j) == dcol)) { + continue; + } + row = rogue.row + i; + col = rogue.col + j; + s = dungeon[row][col]; + if (s & HIDDEN) { + continue; + } + /* If the rogue used to be right, up, left, down, or right of + * row,col, and now isn't, then don't stop */ + if (s & (MONSTER | OBJECT | STAIRS)) { + if (((row == drow) || (col == dcol)) && + (!((row == rogue.row) || (col == rogue.col)))) { + continue; + } + return(1); + } + if (s & TRAP) { + if (!(s & HIDDEN)) { + if (((row == drow) || (col == dcol)) && + (!((row == rogue.row) || (col == rogue.col)))) { + continue; + } + return(1); + } + } + if ((((i - j) == 1) || ((i - j) == -1)) && (s & TUNNEL)) { + if (++pass_count > 1) { + return(1); + } + } + if ((s & DOOR) && ((i == 0) || (j == 0))) { + return(1); + } + } + } + return(0); +} + +void +multiple_move_rogue(dirch) + int dirch; +{ + int row, col; + int m; + + switch(dirch) { + case '\010': + case '\012': + case '\013': + case '\014': + case '\031': + case '\025': + case '\016': + case '\002': + do { + row = rogue.row; + col = rogue.col; + if (((m = one_move_rogue((dirch + 96), 1)) == MOVE_FAILED) || + (m == STOPPED_ON_SOMETHING) || + interrupted) { + break; + } + } while (!next_to_something(row, col)); + if ( (!interrupted) && passgo && (m == MOVE_FAILED) && + (dungeon[rogue.row][rogue.col] & TUNNEL)) { + turn_passage(dirch + 96, 0); + } + break; + case 'H': + case 'J': + case 'K': + case 'L': + case 'B': + case 'Y': + case 'U': + case 'N': + while ((!interrupted) && (one_move_rogue((dirch + 32), 1) == MOVED)) ; + + if ( (!interrupted) && passgo && + (dungeon[rogue.row][rogue.col] & TUNNEL)) { + turn_passage(dirch + 32, 1); + } + break; + } +} + +int +is_passable(row, col) + register int row, col; +{ + if ((row < MIN_ROW) || (row > (DROWS - 2)) || (col < 0) || + (col > (DCOLS-1))) { + return(0); + } + if (dungeon[row][col] & HIDDEN) { + return((dungeon[row][col] & TRAP) ? 1 : 0); + } + return(dungeon[row][col] & (FLOOR | TUNNEL | DOOR | STAIRS | TRAP)); +} + +int +can_move(row1, col1, row2, col2) +{ + if (!is_passable(row2, col2)) { + return(0); + } + if ((row1 != row2) && (col1 != col2)) { + if ((dungeon[row1][col1] & DOOR) || (dungeon[row2][col2] & DOOR)) { + return(0); + } + if ((!dungeon[row1][col2]) || (!dungeon[row2][col1])) { + return(0); + } + } + return(1); +} + +void +move_onto() +{ + int ch, d; + boolean first_miss = 1; + + while (!is_direction(ch = rgetchar(), &d)) { + sound_bell(); + if (first_miss) { + message("direction? ", 0); + first_miss = 0; + } + } + check_message(); + if (ch != CANCEL) { + (void) one_move_rogue(ch, 0); + } +} + +boolean +is_direction(c, d) + int c; + int *d; +{ + switch(c) { + case 'h': + *d = LEFT; + break; + case 'j': + *d = DOWN; + break; + case 'k': + *d = UPWARD; + break; + case 'l': + *d = RIGHT; + break; + case 'b': + *d = DOWNLEFT; + break; + case 'y': + *d = UPLEFT; + break; + case 'u': + *d = UPRIGHT; + break; + case 'n': + *d = DOWNRIGHT; + break; + case CANCEL: + break; + default: + return(0); + } + return(1); +} + +boolean +check_hunger(msg_only) + boolean msg_only; +{ + register int i, n; + boolean fainted = 0; + + if (rogue.moves_left == HUNGRY) { + (void) strcpy(hunger_str, "hungry"); + message(hunger_str, 0); + print_stats(STAT_HUNGER); + } + if (rogue.moves_left == WEAK) { + (void) strcpy(hunger_str, "weak"); + message(hunger_str, 1); + print_stats(STAT_HUNGER); + } + if (rogue.moves_left <= FAINT) { + if (rogue.moves_left == FAINT) { + (void) strcpy(hunger_str, "faint"); + message(hunger_str, 1); + print_stats(STAT_HUNGER); + } + n = get_rand(0, (FAINT - rogue.moves_left)); + if (n > 0) { + fainted = 1; + if (rand_percent(40)) { + rogue.moves_left++; + } + message("you faint", 1); + for (i = 0; i < n; i++) { + if (coin_toss()) { + mv_mons(); + } + } + message(you_can_move_again, 1); + } + } + if (msg_only) { + return(fainted); + } + if (rogue.moves_left <= STARVE) { + killed_by((object *) 0, STARVATION); + } + + switch(e_rings) { + /*case -2: + Subtract 0, i.e. do nothing. + break;*/ + case -1: + rogue.moves_left -= (rogue.moves_left % 2); + break; + case 0: + rogue.moves_left--; + break; + case 1: + rogue.moves_left--; + (void) check_hunger(1); + rogue.moves_left -= (rogue.moves_left % 2); + break; + case 2: + rogue.moves_left--; + (void) check_hunger(1); + rogue.moves_left--; + break; + } + return(fainted); +} + +static void +heal() +{ + static int heal_exp = -1, n, c = 0; + static boolean alt; + + if (rogue.hp_current == rogue.hp_max) { + c = 0; + return; + } + if (rogue.exp != heal_exp) { + heal_exp = rogue.exp; + + switch(heal_exp) { + case 1: + n = 20; + break; + case 2: + n = 18; + break; + case 3: + n = 17; + break; + case 4: + n = 14; + break; + case 5: + n = 13; + break; + case 6: + n = 10; + break; + case 7: + n = 9; + break; + case 8: + n = 8; + break; + case 9: + n = 7; + break; + case 10: + n = 4; + break; + case 11: + n = 3; + break; + case 12: + default: + n = 2; + } + } + if (++c >= n) { + c = 0; + rogue.hp_current++; + alt = !alt; + if (alt) { + rogue.hp_current++; + } + if ((rogue.hp_current += regeneration) > rogue.hp_max) { + rogue.hp_current = rogue.hp_max; + } + print_stats(STAT_HP); + } +} + +boolean +reg_move() +{ + boolean fainted; + + if ((rogue.moves_left <= HUNGRY) || (cur_level >= max_level)) { + fainted = check_hunger(0); + } else { + fainted = 0; + } + + mv_mons(); + + if (++m_moves >= 120) { + m_moves = 0; + wanderer(); + } + if (halluc) { + if (!(--halluc)) { + unhallucinate(); + } else { + hallucinate(); + } + } + if (blind) { + if (!(--blind)) { + unblind(); + } + } + if (confused) { + if (!(--confused)) { + unconfuse(); + } + } + if (bear_trap) { + bear_trap--; + } + if (levitate) { + if (!(--levitate)) { + message("you float gently to the ground", 1); + if (dungeon[rogue.row][rogue.col] & TRAP) { + trap_player(rogue.row, rogue.col); + } + } + } + if (haste_self) { + if (!(--haste_self)) { + message("you feel yourself slowing down", 0); + } + } + heal(); + if (auto_search > 0) { + search(auto_search, auto_search); + } + return(fainted); +} + +void +rest(count) +{ + int i; + + interrupted = 0; + + for (i = 0; i < count; i++) { + if (interrupted) { + break; + } + (void) reg_move(); + } +} diff --git a/src/games/rogue/object.c b/src/games/rogue/object.c new file mode 100644 index 0000000..5de8902 --- /dev/null +++ b/src/games/rogue/object.c @@ -0,0 +1,754 @@ +/* + * This source herein may be modified and/or distributed by anybody who + * so desires, with the following restrictions: + * 1.) No portion of this notice shall be removed. + * 2.) Credit shall not be taken for the creation of this source. + * 3.) This code is not to be traded, sold, or used for personal + * gain or profit. + */ +#include "rogue.h" + +object level_objects; +unsigned short dungeon[DROWS][DCOLS]; +short foods = 0; +object *free_list = (object *) 0; +char *fruit = (char *) 0; + +fighter rogue = { + INIT_AW, /* armor, weapon */ + INIT_RINGS, /* rings */ + INIT_HP, /* Hp current,max */ + INIT_STR, /* Str current,max */ + INIT_PACK, /* pack */ + INIT_GOLD, /* gold */ + INIT_EXP, /* exp level,points */ + 0, 0, /* row, col */ + INIT_CHAR, /* char */ + INIT_MOVES /* moves */ +}; + +struct id id_potions[POTIONS] = { +{100, "blue \0 ", "of increase strength ", 0}, +{250, "red \0 ", "of restore strength ", 0}, +{100, "green \0 ", "of healing ", 0}, +{200, "grey \0 ", "of extra healing ", 0}, + {10, "brown \0 ", "of poison ", 0}, +{300, "clear \0 ", "of raise level ", 0}, + {10, "pink \0 ", "of blindness ", 0}, + {25, "white \0 ", "of hallucination ", 0}, +{100, "purple \0 ", "of detect monster ", 0}, +{100, "black \0 ", "of detect things ", 0}, + {10, "yellow \0 ", "of confusion ", 0}, + {80, "plaid \0 ", "of levitation ", 0}, +{150, "burgundy \0 ", "of haste self ", 0}, +{145, "beige \0 ", "of see invisible ", 0} +}; + +struct id id_scrolls[SCROLS] = { +{505, " ", "of protect armor ", 0}, +{200, " ", "of hold monster ", 0}, +{235, " ", "of enchant weapon ", 0}, +{235, " ", "of enchant armor ", 0}, +{175, " ", "of identify ", 0}, +{190, " ", "of teleportation ", 0}, + {25, " ", "of sleep ", 0}, +{610, " ", "of scare monster ", 0}, +{210, " ", "of remove curse ", 0}, + {80, " ", "of create monster ",0}, + {25, " ", "of aggravate monster ",0}, +{180, " ", "of magic mapping ", 0}, + {90, " ", "of confuse monster ", 0} +}; + +struct id id_weapons[WEAPONS] = { + {150, "short bow ", "", 0}, + {8, "darts ", "", 0}, + {15, "arrows ", "", 0}, + {27, "daggers ", "", 0}, + {35, "shurikens ", "", 0}, + {360, "mace ", "", 0}, + {470, "long sword ", "", 0}, + {580, "two-handed sword ", "", 0} +}; + +struct id id_armors[ARMORS] = { + {300, "leather armor ", "", (UNIDENTIFIED)}, + {300, "ring mail ", "", (UNIDENTIFIED)}, + {400, "scale mail ", "", (UNIDENTIFIED)}, + {500, "chain mail ", "", (UNIDENTIFIED)}, + {600, "banded mail ", "", (UNIDENTIFIED)}, + {600, "splint mail ", "", (UNIDENTIFIED)}, + {700, "plate mail ", "", (UNIDENTIFIED)} +}; + +struct id id_wands[WANDS] = { + {25, " ", "of teleport away ",0}, + {50, " ", "of slow monster ", 0}, + {8, " ", "of invisibility ",0}, + {55, " ", "of polymorph ",0}, + {2, " ", "of haste monster ",0}, + {20, " ", "of magic missile ",0}, + {20, " ", "of cancellation ",0}, + {0, " ", "of do nothing ",0}, + {35, " ", "of drain life ",0}, + {20, " ", "of cold ",0}, + {20, " ", "of fire ",0} +}; + +struct id id_rings[RINGS] = { + {250, " ", "of stealth ",0}, + {100, " ", "of teleportation ", 0}, + {255, " ", "of regeneration ",0}, + {295, " ", "of slow digestion ",0}, + {200, " ", "of add strength ",0}, + {250, " ", "of sustain strength ",0}, + {250, " ", "of dexterity ",0}, + {25, " ", "of adornment ",0}, + {300, " ", "of see invisible ",0}, + {290, " ", "of maintain armor ",0}, + {270, " ", "of searching ",0}, +}; + +static void +plant_gold(row, col, is_maze) + int row, col; + boolean is_maze; +{ + object *obj; + + obj = alloc_object(); + obj->row = row; obj->col = col; + obj->what_is = GOLD; + obj->quantity = get_rand((2 * cur_level), (16 * cur_level)); + if (is_maze) { + obj->quantity += obj->quantity / 2; + } + dungeon[row][col] |= OBJECT; + (void) add_to_pack(obj, &level_objects, 0); +} + +static void +put_gold() +{ + int i, j; + int row, col; + boolean is_maze, is_room; + + for (i = 0; i < MAXROOMS; i++) { + is_maze = (rooms[i].is_room & R_MAZE) ? 1 : 0; + is_room = (rooms[i].is_room & R_ROOM) ? 1 : 0; + + if (!(is_room || is_maze)) { + continue; + } + if (is_maze || rand_percent(GOLD_PERCENT)) { + for (j = 0; j < 50; j++) { + row = get_rand(rooms[i].top_row+1, + rooms[i].bottom_row-1); + col = get_rand(rooms[i].left_col+1, + rooms[i].right_col-1); + if ((dungeon[row][col] == FLOOR) || + (dungeon[row][col] == TUNNEL)) { + plant_gold(row, col, is_maze); + break; + } + } + } + } +} + +static void +make_party() +{ + int n; + + party_room = gr_room(); + + n = rand_percent(99) ? party_objects(party_room) : 11; + if (rand_percent(99)) { + party_monsters(party_room, n); + } +} + +static void +rand_place(obj) + object *obj; +{ + int row, col; + + gr_row_col(&row, &col, (FLOOR | TUNNEL)); + place_at(obj, row, col); +} + +void +put_objects() +{ + int i, n; + object *obj; + + if (cur_level < max_level) { + return; + } + n = coin_toss() ? get_rand(2, 4) : get_rand(3, 5); + while (rand_percent(33)) { + n++; + } + if (party_room != NO_ROOM) { + make_party(); + } + for (i = 0; i < n; i++) { + obj = gr_object(); + rand_place(obj); + } + put_gold(); +} + +void +place_at(obj, row, col) + object *obj; +{ + obj->row = row; + obj->col = col; + dungeon[row][col] |= OBJECT; + (void) add_to_pack(obj, &level_objects, 0); +} + +object * +object_at(pack, row, col) + register object *pack; + int row, col; +{ + object *obj = (object *) 0; + + if (dungeon[row][col] & (MONSTER | OBJECT)) { + obj = pack->next_object; + + while (obj && ((obj->row != row) || (obj->col != col))) { + obj = obj->next_object; + } + if (!obj) { + message("object_at(): inconsistent", 1); + } + } + return(obj); +} + +object * +get_letter_object(ch) +{ + object *obj; + + obj = rogue.pack.next_object; + + while (obj && (obj->ichar != ch)) { + obj = obj->next_object; + } + return(obj); +} + +void +free_stuff(objlist) + object *objlist; +{ + object *obj; + + while (objlist->next_object) { + obj = objlist->next_object; + objlist->next_object = + objlist->next_object->next_object; + free_object(obj); + } +} + +char * +name_of(obj) + object *obj; +{ + char *retstring; + + switch(obj->what_is) { + case SCROL: + retstring = obj->quantity > 1 ? "scrolls " : "scroll "; + break; + case POTION: + retstring = obj->quantity > 1 ? "potions " : "potion "; + break; + case FOOD: + if (obj->which_kind == RATION) { + retstring = "food "; + } else { + retstring = fruit; + } + break; + case WAND: + retstring = is_wood[obj->which_kind] ? "staff " : "wand "; + break; + case WEAPON: + switch(obj->which_kind) { + case DART: + retstring=obj->quantity > 1 ? "darts " : "dart "; + break; + case ARROW: + retstring=obj->quantity > 1 ? "arrows " : "arrow "; + break; + case DAGGER: + retstring=obj->quantity > 1 ? "daggers " : "dagger "; + break; + case SHURIKEN: + retstring=obj->quantity > 1?"shurikens ":"shuriken "; + break; + default: + retstring = id_weapons[obj->which_kind].title; + } + break; + case ARMOR: + retstring = "armor "; + break; + case RING: + retstring = "ring "; + break; + case AMULET: + retstring = "amulet "; + break; + default: + retstring = "unknown "; + break; + } + return(retstring); +} + +static void +gr_scroll(obj) + object *obj; +{ + int percent; + + percent = get_rand(0, 91); + + obj->what_is = SCROL; + + if (percent <= 5) { + obj->which_kind = PROTECT_ARMOR; + } else if (percent <= 10) { + obj->which_kind = HOLD_MONSTER; + } else if (percent <= 20) { + obj->which_kind = CREATE_MONSTER; + } else if (percent <= 35) { + obj->which_kind = IDENTIFY; + } else if (percent <= 43) { + obj->which_kind = TELEPORT; + } else if (percent <= 50) { + obj->which_kind = SLEEP; + } else if (percent <= 55) { + obj->which_kind = SCARE_MONSTER; + } else if (percent <= 64) { + obj->which_kind = REMOVE_CURSE; + } else if (percent <= 69) { + obj->which_kind = ENCH_ARMOR; + } else if (percent <= 74) { + obj->which_kind = ENCH_WEAPON; + } else if (percent <= 80) { + obj->which_kind = AGGRAVATE_MONSTER; + } else if (percent <= 86) { + obj->which_kind = CON_MON; + } else { + obj->which_kind = MAGIC_MAPPING; + } +} + +static void +gr_potion(obj) + object *obj; +{ + int percent; + + percent = get_rand(1, 118); + + obj->what_is = POTION; + + if (percent <= 5) { + obj->which_kind = RAISE_LEVEL; + } else if (percent <= 15) { + obj->which_kind = DETECT_OBJECTS; + } else if (percent <= 25) { + obj->which_kind = DETECT_MONSTER; + } else if (percent <= 35) { + obj->which_kind = INCREASE_STRENGTH; + } else if (percent <= 45) { + obj->which_kind = RESTORE_STRENGTH; + } else if (percent <= 55) { + obj->which_kind = HEALING; + } else if (percent <= 65) { + obj->which_kind = EXTRA_HEALING; + } else if (percent <= 75) { + obj->which_kind = BLINDNESS; + } else if (percent <= 85) { + obj->which_kind = HALLUCINATION; + } else if (percent <= 95) { + obj->which_kind = CONFUSION; + } else if (percent <= 105) { + obj->which_kind = POISON; + } else if (percent <= 110) { + obj->which_kind = LEVITATION; + } else if (percent <= 114) { + obj->which_kind = HASTE_SELF; + } else { + obj->which_kind = SEE_INVISIBLE; + } +} + +static void +gr_weapon(obj, assign_wk) + object *obj; + int assign_wk; +{ + int percent; + int i; + int blessing, increment; + + obj->what_is = WEAPON; + if (assign_wk) { + obj->which_kind = get_rand(0, (WEAPONS - 1)); + } + if ((obj->which_kind == ARROW) || (obj->which_kind == DAGGER) || + (obj->which_kind == SHURIKEN) | (obj->which_kind == DART)) { + obj->quantity = get_rand(3, 15); + obj->quiver = get_rand(0, 126); + } else { + obj->quantity = 1; + } + obj->hit_enchant = obj->d_enchant = 0; + + percent = get_rand(1, 96); + blessing = get_rand(1, 3); + + if (percent <= 16) { + increment = 1; + } else if (percent <= 32) { + increment = -1; + obj->is_cursed = 1; + } + if (percent <= 32) { + for (i = 0; i < blessing; i++) { + if (coin_toss()) { + obj->hit_enchant += increment; + } else { + obj->d_enchant += increment; + } + } + } + switch(obj->which_kind) { + case BOW: + case DART: + obj->damage = "1d1"; + break; + case ARROW: + obj->damage = "1d2"; + break; + case DAGGER: + obj->damage = "1d3"; + break; + case SHURIKEN: + obj->damage = "1d4"; + break; + case MACE: + obj->damage = "2d3"; + break; + case LONG_SWORD: + obj->damage = "3d4"; + break; + case TWO_HANDED_SWORD: + obj->damage = "4d5"; + break; + } +} + +static void +gr_armor(obj) + object *obj; +{ + int percent; + int blessing; + + obj->what_is = ARMOR; + obj->which_kind = get_rand(0, (ARMORS - 1)); + obj->class = obj->which_kind + 2; + if ((obj->which_kind == PLATE) || (obj->which_kind == SPLINT)) { + obj->class--; + } + obj->is_protected = 0; + obj->d_enchant = 0; + + percent = get_rand(1, 100); + blessing = get_rand(1, 3); + + if (percent <= 16) { + obj->is_cursed = 1; + obj->d_enchant -= blessing; + } else if (percent <= 33) { + obj->d_enchant += blessing; + } +} + +void +gr_wand(obj) + object *obj; +{ + obj->what_is = WAND; + obj->which_kind = get_rand(0, (WANDS - 1)); + obj->class = get_rand(3, 7); +} + +static unsigned +gr_what_is() +{ + int percent; + unsigned what_is; + + percent = get_rand(1, 91); + + if (percent <= 30) { + what_is = SCROL; + } else if (percent <= 60) { + what_is = POTION; + } else if (percent <= 64) { + what_is = WAND; + } else if (percent <= 74) { + what_is = WEAPON; + } else if (percent <= 83) { + what_is = ARMOR; + } else if (percent <= 88) { + what_is = FOOD; + } else { + what_is = RING; + } + return(what_is); +} + +object * +gr_object() +{ + object *obj; + + obj = alloc_object(); + + if (foods < (cur_level / 3)) { + obj->what_is = FOOD; + foods++; + } else { + obj->what_is = gr_what_is(); + } + switch(obj->what_is) { + case SCROL: + gr_scroll(obj); + break; + case POTION: + gr_potion(obj); + break; + case WEAPON: + gr_weapon(obj, 1); + break; + case ARMOR: + gr_armor(obj); + break; + case WAND: + gr_wand(obj); + break; + case FOOD: + get_food(obj, 0); + break; + case RING: + gr_ring(obj, 1); + break; + } + return(obj); +} + +void +get_food(obj, force_ration) + object *obj; + boolean force_ration; +{ + obj->what_is = FOOD; + + if (force_ration || rand_percent(80)) { + obj->which_kind = RATION; + } else { + obj->which_kind = FRUIT; + } +} + +void +put_stairs() +{ + int row, col; + + gr_row_col(&row, &col, (FLOOR | TUNNEL)); + dungeon[row][col] |= STAIRS; +} + +int +get_armor_class(obj) + object *obj; +{ + if (obj) { + return(obj->class + obj->d_enchant); + } + return(0); +} + +object * +alloc_object() +{ + object *obj; + + if (free_list) { + obj = free_list; + free_list = free_list->next_object; + } else if (!(obj = (object *) md_malloc(sizeof(object)))) { + message("cannot allocate object, saving game", 0); + save_into_file(error_file); + } + obj->quantity = 1; + obj->ichar = 'L'; + obj->picked_up = obj->is_cursed = 0; + obj->in_use_flags = NOT_USED; + obj->identified = UNIDENTIFIED; + obj->damage = "1d1"; + return(obj); +} + +void +free_object(obj) + object *obj; +{ + obj->next_object = free_list; + free_list = obj; +} + +void +show_objects() +{ + object *obj; + int mc, rc, row, col; + object *monster; + + obj = level_objects.next_object; + + while (obj) { + row = obj->row; + col = obj->col; + + rc = get_mask_char(obj->what_is); + + if (dungeon[row][col] & MONSTER) { + monster = object_at(&level_monsters, row, col); + if (monster) { + monster->trail_char = rc; + } + } + mc = mvinch(row, col); + if (((mc < 'A') || (mc > 'Z')) && + ((row != rogue.row) || (col != rogue.col))) { + mvaddch(row, col, rc); + } + obj = obj->next_object; + } + + monster = level_monsters.next_object; + + while (monster) { + if (monster->m_flags & IMITATES) { + mvaddch(monster->row, monster->col, (int) monster->disguise); + } + monster = monster->next_monster; + } +} + +void +put_amulet() +{ + object *obj; + + obj = alloc_object(); + obj->what_is = AMULET; + rand_place(obj); +} + +void +c_object_for_wizard() +{ + int ch, max = 0, wk; + object *obj; + char buf[80]; + + if (pack_count((object *) 0) >= MAX_PACK_COUNT) { + message("pack full", 0); + return; + } + message("type of object?", 0); + + while (r_index("!?:)]=/,\033", (ch = rgetchar()), 0) == -1) { + sound_bell(); + } + check_message(); + + if (ch == '\033') { + return; + } + obj = alloc_object(); + + switch(ch) { + case '!': + obj->what_is = POTION; + max = POTIONS - 1; + break; + case '?': + obj->what_is = SCROL; + max = SCROLS - 1; + break; + case ',': + obj->what_is = AMULET; + break; + case ':': + get_food(obj, 0); + break; + case ')': + gr_weapon(obj, 0); + max = WEAPONS - 1; + break; + case ']': + gr_armor(obj); + max = ARMORS - 1; + break; + case '/': + gr_wand(obj); + max = WANDS - 1; + break; + case '=': + max = RINGS - 1; + obj->what_is = RING; + break; + } + if ((ch != ',') && (ch != ':')) { +GIL: + if (get_input_line("which kind?", "", buf, "", 0, 1)) { + wk = get_number(buf); + if ((wk >= 0) && (wk <= max)) { + obj->which_kind = (unsigned) wk; + if (obj->what_is == RING) { + gr_ring(obj, 0); + } + } else { + sound_bell(); + goto GIL; + } + } else { + free_object(obj); + return; + } + } + get_desc(obj, buf); + message(buf, 0); + (void) add_to_pack(obj, &rogue.pack, 1); +} diff --git a/src/games/rogue/pack.c b/src/games/rogue/pack.c new file mode 100644 index 0000000..9b769f5 --- /dev/null +++ b/src/games/rogue/pack.c @@ -0,0 +1,545 @@ +/* + * This source herein may be modified and/or distributed by anybody who + * so desires, with the following restrictions: + * 1.) No portion of this notice shall be removed. + * 2.) Credit shall not be taken for the creation of this source. + * 3.) This code is not to be traded, sold, or used for personal + * gain or profit. + */ +#include +#include "rogue.h" + +char *curse_message = "you can't, it appears to be cursed"; + +static int +next_avail_ichar() +{ + register object *obj; + register int i; + boolean ichars[26]; + + for (i = 0; i < 26; i++) { + ichars[i] = 0; + } + obj = rogue.pack.next_object; + while (obj) { + ichars[(obj->ichar - 'a')] = 1; + obj = obj->next_object; + } + for (i = 0; i < 26; i++) { + if (!ichars[i]) { + return(i + 'a'); + } + } + return('?'); +} + +static object * +check_duplicate(obj, pack) + object *obj, *pack; +{ + object *op; + + if (!(obj->what_is & (WEAPON | FOOD | SCROL | POTION))) { + return(0); + } + if ((obj->what_is == FOOD) && (obj->which_kind == FRUIT)) { + return(0); + } + op = pack->next_object; + + while (op) { + if ((op->what_is == obj->what_is) && + (op->which_kind == obj->which_kind)) { + + if ((obj->what_is != WEAPON) || + ((obj->what_is == WEAPON) && + ((obj->which_kind == ARROW) || + (obj->which_kind == DAGGER) || + (obj->which_kind == DART) || + (obj->which_kind == SHURIKEN)) && + (obj->quiver == op->quiver))) { + op->quantity += obj->quantity; + return(op); + } + } + op = op->next_object; + } + return(0); +} + +object * +add_to_pack(obj, pack, condense) + object *obj, *pack; +{ + object *op; + + if (condense) { + op = check_duplicate(obj, pack); + if (op) { + free_object(obj); + return(op); + } else { + obj->ichar = next_avail_ichar(); + } + } + if (pack->next_object == 0) { + pack->next_object = obj; + } else { + op = pack->next_object; + + while (op->next_object) { + op = op->next_object; + } + op->next_object = obj; + } + obj->next_object = 0; + return(obj); +} + +void +take_from_pack(obj, pack) + object *obj, *pack; +{ + while (pack->next_object != obj) { + pack = pack->next_object; + } + pack->next_object = pack->next_object->next_object; +} + +/* Note: *status is set to 0 if the rogue attempts to pick up a scroll + * of scare-monster and it turns to dust. *status is otherwise set to 1. + */ +object * +pick_up(row, col, status) + int *status; +{ + object *obj; + + *status = 1; + + if (levitate) { + message("you're floating in the air!", 0); + return((object *) 0); + } + obj = object_at(&level_objects, row, col); + if (!obj) { + message("pick_up(): inconsistent", 1); + return(obj); + } + if ( (obj->what_is == SCROL) && + (obj->which_kind == SCARE_MONSTER) && + obj->picked_up) { + message("the scroll turns to dust as you pick it up", 0); + dungeon[row][col] &= (~OBJECT); + vanish(obj, 0, &level_objects); + *status = 0; + if (id_scrolls[SCARE_MONSTER].id_status == UNIDENTIFIED) { + id_scrolls[SCARE_MONSTER].id_status = IDENTIFIED; + } + return((object *) 0); + } + if (obj->what_is == GOLD) { + rogue.gold += obj->quantity; + dungeon[row][col] &= ~(OBJECT); + take_from_pack(obj, &level_objects); + print_stats(STAT_GOLD); + return(obj); /* obj will be free_object()ed in caller */ + } + if (pack_count(obj) >= MAX_PACK_COUNT) { + message("pack too full", 1); + return((object *) 0); + } + dungeon[row][col] &= ~(OBJECT); + take_from_pack(obj, &level_objects); + obj = add_to_pack(obj, &rogue.pack, 1); + obj->picked_up = 1; + return(obj); +} + +void +drop() +{ + object *obj, *new; + int ch; + char desc[DCOLS]; + + if (dungeon[rogue.row][rogue.col] & (OBJECT | STAIRS | TRAP)) { + message("there's already something there", 0); + return; + } + if (!rogue.pack.next_object) { + message("you have nothing to drop", 0); + return; + } + ch = pack_letter("drop what?", ALL_OBJECTS); + if (ch == CANCEL) { + return; + } + obj = get_letter_object(ch); + if (! obj) { + message("no such item.", 0); + return; + } + if (obj->in_use_flags & BEING_WIELDED) { + if (obj->is_cursed) { + message(curse_message, 0); + return; + } + unwield(rogue.weapon); + } else if (obj->in_use_flags & BEING_WORN) { + if (obj->is_cursed) { + message(curse_message, 0); + return; + } + mv_aquatars(); + unwear(rogue.armor); + print_stats(STAT_ARMOR); + } else if (obj->in_use_flags & ON_EITHER_HAND) { + if (obj->is_cursed) { + message(curse_message, 0); + return; + } + un_put_on(obj); + } + obj->row = rogue.row; + obj->col = rogue.col; + + if ((obj->quantity > 1) && (obj->what_is != WEAPON)) { + obj->quantity--; + new = alloc_object(); + *new = *obj; + new->quantity = 1; + obj = new; + } else { + obj->ichar = 'L'; + take_from_pack(obj, &rogue.pack); + } + place_at(obj, rogue.row, rogue.col); + (void) strcpy(desc, "dropped "); + get_desc(obj, desc+8); + message(desc, 0); + (void) reg_move(); +} + +void +wait_for_ack() +{ + while (rgetchar() != ' ') ; +} + +static int +is_pack_letter(c, mask) + int *c; + unsigned *mask; +{ + if (((*c == '?') || (*c == '!') || (*c == ':') || (*c == '=') || + (*c == ')') || (*c == ']') || (*c == '/') || (*c == ','))) { + switch(*c) { + case '?': + *mask = SCROL; + break; + case '!': + *mask = POTION; + break; + case ':': + *mask = FOOD; + break; + case ')': + *mask = WEAPON; + break; + case ']': + *mask = ARMOR; + break; + case '/': + *mask = WAND; + break; + case '=': + *mask = RING; + break; + case ',': + *mask = AMULET; + break; + } + *c = LIST; + return(1); + } + return(((*c >= 'a') && (*c <= 'z')) || (*c == CANCEL) || (*c == LIST)); +} + +static boolean +mask_pack(pack, mask) + object *pack; + unsigned mask; +{ + while (pack->next_object) { + pack = pack->next_object; + if (pack->what_is & mask) { + return(1); + } + } + return(0); +} + +int +pack_letter(prompt, mask) + char *prompt; + unsigned mask; +{ + int ch; + unsigned tmask = mask; + + if (!mask_pack(&rogue.pack, mask)) { + message("nothing appropriate", 0); + return(CANCEL); + } + for (;;) { + + message(prompt, 0); + + for (;;) { + ch = rgetchar(); + if (!is_pack_letter(&ch, &mask)) { + sound_bell(); + } else { + break; + } + } + + if (ch == LIST) { + check_message(); + inventory(&rogue.pack, mask); + } else { + break; + } + mask = tmask; + } + check_message(); + return(ch); +} + +void +take_off() +{ + char desc[DCOLS]; + object *obj; + + if (rogue.armor) { + if (rogue.armor->is_cursed) { + message(curse_message, 0); + } else { + mv_aquatars(); + obj = rogue.armor; + unwear(rogue.armor); + (void) strcpy(desc, "was wearing "); + get_desc(obj, desc+12); + message(desc, 0); + print_stats(STAT_ARMOR); + (void) reg_move(); + } + } else { + message("not wearing any", 0); + } +} + +void +wear() +{ + int ch; + register object *obj; + char desc[DCOLS]; + + if (rogue.armor) { + message("your already wearing some", 0); + return; + } + ch = pack_letter("wear what?", ARMOR); + + if (ch == CANCEL) { + return; + } + if (!(obj = get_letter_object(ch))) { + message("no such item.", 0); + return; + } + if (obj->what_is != ARMOR) { + message("you can't wear that", 0); + return; + } + obj->identified = 1; + (void) strcpy(desc, "wearing "); + get_desc(obj, desc + 8); + message(desc, 0); + do_wear(obj); + print_stats(STAT_ARMOR); + (void) reg_move(); +} + +void +unwear(obj) + object *obj; +{ + if (obj) { + obj->in_use_flags &= (~BEING_WORN); + } + rogue.armor = (object *) 0; +} + +void +do_wear(obj) + object *obj; +{ + rogue.armor = obj; + obj->in_use_flags |= BEING_WORN; + obj->identified = 1; +} + +void +wield() +{ + int ch; + register object *obj; + char desc[DCOLS]; + + if (rogue.weapon && rogue.weapon->is_cursed) { + message(curse_message, 0); + return; + } + ch = pack_letter("wield what?", WEAPON); + + if (ch == CANCEL) { + return; + } + if (!(obj = get_letter_object(ch))) { + message("No such item.", 0); + return; + } + if (obj->what_is & (ARMOR | RING)) { + sprintf(desc, "you can't wield %s", + ((obj->what_is == ARMOR) ? "armor" : "rings")); + message(desc, 0); + return; + } + if (obj->in_use_flags & BEING_WIELDED) { + message("in use", 0); + } else { + unwield(rogue.weapon); + (void) strcpy(desc, "wielding "); + get_desc(obj, desc + 9); + message(desc, 0); + do_wield(obj); + (void) reg_move(); + } +} + +void +do_wield(obj) + object *obj; +{ + rogue.weapon = obj; + obj->in_use_flags |= BEING_WIELDED; +} + +void +unwield(obj) + object *obj; +{ + if (obj) { + obj->in_use_flags &= (~BEING_WIELDED); + } + rogue.weapon = (object *) 0; +} + +void +call_it() +{ + int ch; + register object *obj; + struct id *id_table; + char buf[MAX_TITLE_LENGTH+2]; + + ch = pack_letter("call what?", (SCROL | POTION | WAND | RING)); + + if (ch == CANCEL) { + return; + } + if (!(obj = get_letter_object(ch))) { + message("no such item.", 0); + return; + } + if (!(obj->what_is & (SCROL | POTION | WAND | RING))) { + message("surely you already know what that's called", 0); + return; + } + id_table = get_id_table(obj); + + if (get_input_line("call it:","",buf,id_table[obj->which_kind].title,1,1)) { + id_table[obj->which_kind].id_status = CALLED; + (void) strcpy(id_table[obj->which_kind].title, buf); + } +} + +int +pack_count(new_obj) + object *new_obj; +{ + object *obj; + int count = 0; + + obj = rogue.pack.next_object; + + while (obj) { + if (obj->what_is != WEAPON) { + count += obj->quantity; + } else if (!new_obj) { + count++; + } else if ((new_obj->what_is != WEAPON) || + ((obj->which_kind != ARROW) && + (obj->which_kind != DAGGER) && + (obj->which_kind != DART) && + (obj->which_kind != SHURIKEN)) || + (new_obj->which_kind != obj->which_kind) || + (obj->quiver != new_obj->quiver)) { + count++; + } + obj = obj->next_object; + } + return(count); +} + +int +has_amulet() +{ + return(mask_pack(&rogue.pack, AMULET)); +} + +void +kick_into_pack() +{ + object *obj; + char desc[DCOLS]; + int n, stat; + + if (!(dungeon[rogue.row][rogue.col] & OBJECT)) { + message("nothing here", 0); + } else { + obj = pick_up(rogue.row, rogue.col, &stat); + if (obj) { + get_desc(obj, desc); + if (obj->what_is == GOLD) { + message(desc, 0); + free_object(obj); + } else { + n = strlen(desc); + desc[n] = '('; + desc[n+1] = obj->ichar; + desc[n+2] = ')'; + desc[n+3] = 0; + message(desc, 0); + } + } + if (obj || (!stat)) { + (void) reg_move(); + } + } +} diff --git a/src/games/rogue/play.c b/src/games/rogue/play.c new file mode 100644 index 0000000..6782459 --- /dev/null +++ b/src/games/rogue/play.c @@ -0,0 +1,283 @@ +/* + * This source herein may be modified and/or distributed by anybody who + * so desires, with the following restrictions: + * 1.) No portion of this notice shall be removed. + * 2.) Credit shall not be taken for the creation of this source. + * 3.) This code is not to be traded, sold, or used for personal + * gain or profit. + */ +#include "rogue.h" + +char interrupted = 0; +char *unknown_command = "unknown command"; + +void +play_level() +{ + int ch; + int count; + int esc_level = 0; + + for (;;) { + interrupted = 0; + if (hit_message[0]) { + message(hit_message, 1); + hit_message[0] = 0; + } + if (trap_door) { + trap_door = 0; + return; + } + move(rogue.row, rogue.col); + refresh(); +NEXT: + ch = rgetchar(); +CMCH: + switch (esc_level) { + default: + case 0: + if (ch == '\33') { + /* Escape sequence detected. */ + esc_level = 1; + goto NEXT; + } + /* Single symbol. */ + break; + case 1: + if (ch == '[' || ch == 'O') { + /* Escape sequence continued. */ + esc_level = 2; + } else { + /* Unknown escape sequence, ignore. */ + esc_level = 0; + } + goto NEXT; + case 2: + /* Decode single-symbol escape sequence. */ + esc_level = 0; + switch (ch) { + case 'A': ch = 'k'; break; + case 'B': ch = 'j'; break; + case 'C': ch = 'l'; break; + case 'D': ch = 'h'; break; + default: goto CMCH; + } + break; + } + check_message(); + count = 0; +CH: + switch(ch) { + case '.': + rest((count > 0) ? count : 1); + break; + case 's': + search(((count > 0) ? count : 1), 0); + break; + case 'i': + inventory(&rogue.pack, ALL_OBJECTS); + break; + case 'f': + fight(0); + break; + case 'F': + fight(1); + break; + case 'h': + case 'j': + case 'k': + case 'l': + case 'y': + case 'u': + case 'n': + case 'b': + (void) one_move_rogue(ch, 1); + break; + case 'H': + case 'J': + case 'K': + case 'L': + case 'B': + case 'Y': + case 'U': + case 'N': + case '\010': + case '\012': + case '\013': + case '\014': + case '\031': + case '\025': + case '\016': + case '\002': + multiple_move_rogue(ch); + break; + case 'e': + eat(); + break; + case 'q': + quaff(); + break; + case 'r': + read_scroll(); + break; + case 'm': + move_onto(); + break; + case ',': + kick_into_pack(); + break; + case 'd': + drop(); + break; + case 'P': + put_on_ring(); + break; + case 'R': + remove_ring(); + break; + case '\020': + do { + remessage(count++); + ch = rgetchar(); + } while (ch == '\020'); + goto CMCH; + break; + case '\027': + wizardize(); + break; + case '>': + if (drop_check()) { + return; + } + break; + case '<': + if (check_up()) { + return; + } + break; + case ')': + case ']': + inv_armor_weapon(ch == ')'); + break; + case '=': + inv_rings(); + break; + case '^': + id_trap(); + break; + case '/': + id_type(); + break; + case '?': + id_com(); + break; + case '!': + do_shell(); + break; + case 'o': + edit_opts(); + break; + case 'I': + single_inv(0); + break; + case 'T': + take_off(); + break; + case 'W': + wear(); + break; + case 'w': + wield(); + break; + case 'c': + call_it(); + break; + case 'z': + zapp(); + break; + case 't': + throw(); + break; + case 'v': + message("rogue-clone: Version III. (Tim Stoehr was here), tektronix!zeus!tims", 0); + break; + case 'Q': + quit(0); + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + move(rogue.row, rogue.col); + refresh(); + do { + if (count < 100) { + count = (10 * count) + (ch - '0'); + } + ch = rgetchar(); + } while (is_digit(ch)); + if (ch != CANCEL) { + goto CH; + } + break; + case ' ': + break; + case '\011': + if (wizard) { + inventory(&level_objects, ALL_OBJECTS); + } else { + message(unknown_command, 0); + } + break; + case '\023': + if (wizard) { + draw_magic_map(); + } else { + message(unknown_command, 0); + } + break; + case '\024': + if (wizard) { + show_traps(); + } else { + message(unknown_command, 0); + } + break; + case '\017': + if (wizard) { + show_objects(); + } else { + message(unknown_command, 0); + } + break; + case '\001': + show_average_hp(); + break; + case '\003': + if (wizard) { + c_object_for_wizard(); + } else { + message(unknown_command, 0); + } + break; + case '\015': + if (wizard) { + show_monsters(); + } else { + message(unknown_command, 0); + } + break; + case 'S': + save_game(); + break; + default: + message(unknown_command, 0); + break; + } + } +} diff --git a/src/games/rogue/random.c b/src/games/rogue/random.c new file mode 100644 index 0000000..ff15672 --- /dev/null +++ b/src/games/rogue/random.c @@ -0,0 +1,93 @@ +#include "rogue.h" + +static long rntb[32] = { + 3, 0x9a319039, 0x32d9c024, 0x9b663182, 0x5da1f342, + 0xde3b81e0, 0xdf0a6fb5, 0xf103bc02, 0x48f340fb, 0x7449e56b, + 0xbeb1dbb0, 0xab5c5918, 0x946554fd, 0x8c2e680f, 0xeb3d799f, + 0xb11ee0b7, 0x2d436b86, 0xda672e2a, 0x1588ca88, 0xe369735d, + 0x904f35f7, 0xd7158fd6, 0x6fa6f051, 0x616e6b96, 0xac94efdc, + 0x36413f93, 0xc622c298, 0xf5a42ab8, 0x8a88d77b, 0xf5ad9d0e, + 0x8999220b, 0x27fb47b9 +}; + +static long *fptr = &rntb[4]; +static long *rptr = &rntb[1]; +static long *state = &rntb[1]; +static int rand_type = 3; +static int rand_deg = 31; +static int rand_sep = 3; +static long *end_ptr = &rntb[32]; + +void +srrandom(x) + int x; +{ + register int i; + long rrandom(); + + state[0] = (long) x; + if (rand_type != 0) { + for (i = 1; i < rand_deg; i++) { + state[i] = 1103515245 * state[i - 1] + 12345; + } + fptr = &state[rand_sep]; + rptr = &state[0]; + for (i = 0; i < 10 * rand_deg; i++) { + (void) rrandom(); + } + } +} + +long +rrandom() +{ + long i; + + if (rand_type == 0) { + i = state[0] = (state[0]*1103515245 + 12345) & 0x7fffffff; + } else { + *fptr += *rptr; + i = (*fptr >> 1) & 0x7fffffff; + if (++fptr >= end_ptr) { + fptr = state; + ++rptr; + } else { + if (++rptr >= end_ptr) { + rptr = state; + } + } + } + return(i); +} + +int +get_rand(x, y) + register int x, y; +{ + register int r, t; + long lr; + + if (x > y) { + t = y; + y = x; + x = t; + } + lr = rrandom(); + lr &= (long) 0x00003fff; + r = (int) lr; + r = (r % ((y - x) + 1)) + x; + return(r); +} + +int +rand_percent(percentage) + register int percentage; +{ + return(get_rand(1, 100) <= percentage); +} + +int +coin_toss() +{ + return(((rrandom() & 01) ? 1 : 0)); +} diff --git a/src/games/rogue/ring.c b/src/games/rogue/ring.c new file mode 100644 index 0000000..64347b9 --- /dev/null +++ b/src/games/rogue/ring.c @@ -0,0 +1,296 @@ +/* + * This source herein may be modified and/or distributed by anybody who + * so desires, with the following restrictions: + * 1.) No portion of this notice shall be removed. + * 2.) Credit shall not be taken for the creation of this source. + * 3.) This code is not to be traded, sold, or used for personal + * gain or profit. + */ +#include +#include "rogue.h" + +char *left_or_right = "left or right hand?"; +char *no_ring = "there's no ring on that hand"; +short stealthy; +short r_rings; +short add_strength; +short e_rings; +short regeneration; +short ring_exp; +short auto_search; +char r_teleport; +char r_see_invisible; +char sustain_strength; +char maintain_armor; + +void +put_on_ring() +{ + int ch; + char desc[DCOLS]; + object *ring; + + if (r_rings == 2) { + message("wearing two rings already", 0); + return; + } + if ((ch = pack_letter("put on what?", RING)) == CANCEL) { + return; + } + if (!(ring = get_letter_object(ch))) { + message("no such item.", 0); + return; + } + if (!(ring->what_is & RING)) { + message("that's not a ring", 0); + return; + } + if (ring->in_use_flags & (ON_LEFT_HAND | ON_RIGHT_HAND)) { + message("that ring is already being worn", 0); + return; + } + if (r_rings == 1) { + ch = (rogue.left_ring ? 'r' : 'l'); + } else { + message(left_or_right, 0); + do { + ch = rgetchar(); + } while ((ch != CANCEL) && (ch != 'l') && (ch != 'r') && (ch != '\n') && + (ch != '\r')); + } + if ((ch != 'l') && (ch != 'r')) { + check_message(); + return; + } + if (((ch == 'l') && rogue.left_ring)||((ch == 'r') && rogue.right_ring)) { + check_message(); + message("there's already a ring on that hand", 0); + return; + } + if (ch == 'l') { + do_put_on(ring, 1); + } else { + do_put_on(ring, 0); + } + ring_stats(1); + check_message(); + get_desc(ring, desc); + message(desc, 0); + (void) reg_move(); +} + +/* + * Do not call ring_stats() from within do_put_on(). It will cause + * serious problems when do_put_on() is called from read_pack() in restore(). + */ +void +do_put_on(ring, on_left) + object *ring; + boolean on_left; +{ + if (on_left) { + ring->in_use_flags |= ON_LEFT_HAND; + rogue.left_ring = ring; + } else { + ring->in_use_flags |= ON_RIGHT_HAND; + rogue.right_ring = ring; + } +} + +void +remove_ring() +{ + boolean left = 0, right = 0; + int ch; + char buf[DCOLS]; + object *ring = 0; + + if (r_rings == 0) { + inv_rings(); + } else if (rogue.left_ring && !rogue.right_ring) { + left = 1; + } else if (!rogue.left_ring && rogue.right_ring) { + right = 1; + } else { + message(left_or_right, 0); + do { + ch = rgetchar(); + } while ((ch != CANCEL) && (ch != 'l') && (ch != 'r') && + (ch != '\n') && (ch != '\r')); + left = (ch == 'l'); + right = (ch == 'r'); + check_message(); + } + if (left || right) { + if (left) { + if (rogue.left_ring) { + ring = rogue.left_ring; + } else { + message(no_ring, 0); + } + } else { + if (rogue.right_ring) { + ring = rogue.right_ring; + } else { + message(no_ring, 0); + } + } + if (ring->is_cursed) { + message(curse_message, 0); + } else { + un_put_on(ring); + (void) strcpy(buf, "removed "); + get_desc(ring, buf + 8); + message(buf, 0); + (void) reg_move(); + } + } +} + +void +un_put_on(ring) + object *ring; +{ + if (ring && (ring->in_use_flags & ON_LEFT_HAND)) { + ring->in_use_flags &= (~ON_LEFT_HAND); + rogue.left_ring = 0; + } else if (ring && (ring->in_use_flags & ON_RIGHT_HAND)) { + ring->in_use_flags &= (~ON_RIGHT_HAND); + rogue.right_ring = 0; + } + ring_stats(1); +} + +void +gr_ring(ring, assign_wk) + object *ring; + boolean assign_wk; +{ + ring->what_is = RING; + if (assign_wk) { + ring->which_kind = get_rand(0, (RINGS - 1)); + } + ring->class = 0; + + switch(ring->which_kind) { + /* + case STEALTH: + break; + case SLOW_DIGEST: + break; + case REGENERATION: + break; + case R_SEE_INVISIBLE: + break; + case SUSTAIN_STRENGTH: + break; + case R_MAINTAIN_ARMOR: + break; + case SEARCHING: + break; + */ + case R_TELEPORT: + ring->is_cursed = 1; + break; + case ADD_STRENGTH: + case DEXTERITY: + while ((ring->class = (get_rand(0, 4) - 2)) == 0) ; + ring->is_cursed = (ring->class < 0); + break; + case ADORNMENT: + ring->is_cursed = coin_toss(); + break; + } +} + +void +inv_rings() +{ + char buf[DCOLS]; + + if (r_rings == 0) { + message("not wearing any rings", 0); + } else { + if (rogue.left_ring) { + get_desc(rogue.left_ring, buf); + message(buf, 0); + } + if (rogue.right_ring) { + get_desc(rogue.right_ring, buf); + message(buf, 0); + } + } + if (wizard) { + sprintf(buf, "ste %d, r_r %d, e_r %d, r_t %d, s_s %d, a_s %d, reg %d, r_e %d, s_i %d, m_a %d, aus %d", + stealthy, r_rings, e_rings, r_teleport, sustain_strength, + add_strength, regeneration, ring_exp, r_see_invisible, + maintain_armor, auto_search); + message(buf, 0); + } +} + +void +ring_stats(pr) + boolean pr; +{ + int i; + object *ring; + + stealthy = 0; + r_rings = 0; + e_rings = 0; + r_teleport = 0; + sustain_strength = 0; + add_strength = 0; + regeneration = 0; + ring_exp = 0; + r_see_invisible = 0; + maintain_armor = 0; + auto_search = 0; + + for (i = 0; i < 2; i++) { + if (!(ring = ((i == 0) ? rogue.left_ring : rogue.right_ring))) { + continue; + } + r_rings++; + e_rings++; + switch(ring->which_kind) { + case STEALTH: + stealthy++; + break; + case R_TELEPORT: + r_teleport = 1; + break; + case REGENERATION: + regeneration++; + break; + case SLOW_DIGEST: + e_rings -= 2; + break; + case ADD_STRENGTH: + add_strength += ring->class; + break; + case SUSTAIN_STRENGTH: + sustain_strength = 1; + break; + case DEXTERITY: + ring_exp += ring->class; + break; + case ADORNMENT: + break; + case R_SEE_INVISIBLE: + r_see_invisible = 1; + break; + case MAINTAIN_ARMOR: + maintain_armor = 1; + break; + case SEARCHING: + auto_search += 2; + break; + } + } + if (pr) { + print_stats(STAT_STRENGTH); + relight(); + } +} diff --git a/src/games/rogue/rogue.6 b/src/games/rogue/rogue.6 new file mode 100644 index 0000000..6770874 --- /dev/null +++ b/src/games/rogue/rogue.6 @@ -0,0 +1,93 @@ +.\" Copyright (c) 1980 Regents of the University of California. +.\" All rights reserved. The Berkeley software License Agreement +.\" specifies the terms and conditions for redistribution. +.\" +.\" @(#)rogue.6 6.2 (Berkeley) 5/6/86 +.\" +.TH ROGUE 6 "May 6, 1986" +.UC 4 +.SH NAME +rogue \- Exploring The Dungeons of Doom +.SH SYNOPSIS +.B /usr/games/rogue +[ +.B \-r +] +[ +.I save_file +] +[ +.B \-s +] +[ +.B \-d +] +.SH DESCRIPTION +.PP +.I Rogue +is a computer fantasy game with a new twist. It is crt oriented and the +object of the game is to survive the attacks of various monsters and get +a lot of gold, rather than the puzzle solving orientation of most computer +fantasy games. +.PP +To get started you really only need to know two commands. The command +.B ? +will give you a list of the available commands and the command +.B / +will identify the things you see on the screen. +.PP +To win the game (as opposed to merely playing to beat other people's high +scores) you must locate the Amulet of Yendor which is somewhere below +the 20th level of the dungeon and get it out. Nobody has achieved this +yet and if somebody does, they will probably go down in history as a hero +among heroes. +.PP +When the game ends, either by your death, when you quit, or if you (by +some miracle) manage to win, +.I rogue +will give you a list of the top-ten scorers. The scoring is based entirely +upon how much gold you get. There is a 10% penalty for getting yourself +killed. +.PP +If +.I save_file +is specified, +rogue will be restored from the specified saved game file. +If the +.B \-r +option is used, the save game file is presumed to be the default. +.PP +The +.B \-s +option will print out the list of scores. +.PP +The +.B \-d +option will kill you and try to add you to the score file. +.PP +For more detailed directions, read the document +.I "A Guide to the Dungeons of Doom." +.SH AUTHORS +Michael C. Toy, +Kenneth C. R. C. Arnold, +Glenn Wichman +.SH FILES +.DT +.ta \w'/usr/games/lib/rogue_roll\ \ \ 'u +/usr/games/lib/rogue_roll Score file +.br +\fB~\fP/rogue.save Default save file +.SH SEE ALSO +Michael C. Toy +and +Kenneth C. R. C. Arnold, +.I "A guide to the Dungeons of Doom" +.SH BUGS +.PP +Probably infinite +(although countably infinite). +However, +that Ice Monsters sometimes transfix you permanently is +.I not +a bug. +It's a feature. diff --git a/src/games/rogue/rogue.h b/src/games/rogue/rogue.h new file mode 100644 index 0000000..e5ec471 --- /dev/null +++ b/src/games/rogue/rogue.h @@ -0,0 +1,696 @@ +/* + * This source herein may be modified and/or distributed by anybody who + * so desires, with the following restrictions: + * 1.) This notice shall not be removed. + * 2.) Credit shall not be taken for the creation of this source. + * 3.) This code is not to be traded, sold, or used for personal + * gain or profit. + */ +#define boolean int + +#define NOTHING ((unsigned short) 0) +#define OBJECT ((unsigned short) 01) +#define MONSTER ((unsigned short) 02) +#define STAIRS ((unsigned short) 04) +#define HORWALL ((unsigned short) 010) +#define VERTWALL ((unsigned short) 020) +#define DOOR ((unsigned short) 040) +#define FLOOR ((unsigned short) 0100) +#define TUNNEL ((unsigned short) 0200) +#define TRAP ((unsigned short) 0400) +#define HIDDEN ((unsigned short) 01000) + +#define ARMOR ((unsigned short) 01) +#define WEAPON ((unsigned short) 02) +#define SCROL ((unsigned short) 04) +#define POTION ((unsigned short) 010) +#define GOLD ((unsigned short) 020) +#define FOOD ((unsigned short) 040) +#define WAND ((unsigned short) 0100) +#define RING ((unsigned short) 0200) +#define AMULET ((unsigned short) 0400) +#define ALL_OBJECTS ((unsigned short) 0777) + +#define LEATHER 0 +#define RINGMAIL 1 +#define SCALE 2 +#define CHAIN 3 +#define BANDED 4 +#define SPLINT 5 +#define PLATE 6 +#define ARMORS 7 + +#define BOW 0 +#define DART 1 +#define ARROW 2 +#define DAGGER 3 +#define SHURIKEN 4 +#define MACE 5 +#define LONG_SWORD 6 +#define TWO_HANDED_SWORD 7 +#define WEAPONS 8 + +#define MAX_PACK_COUNT 24 + +#define PROTECT_ARMOR 0 +#define HOLD_MONSTER 1 +#define ENCH_WEAPON 2 +#define ENCH_ARMOR 3 +#define IDENTIFY 4 +#define TELEPORT 5 +#define SLEEP 6 +#define SCARE_MONSTER 7 +#define REMOVE_CURSE 8 +#define CREATE_MONSTER 9 +#define AGGRAVATE_MONSTER 10 +#define MAGIC_MAPPING 11 +#define CON_MON 12 +#define SCROLS 13 + +#define INCREASE_STRENGTH 0 +#define RESTORE_STRENGTH 1 +#define HEALING 2 +#define EXTRA_HEALING 3 +#define POISON 4 +#define RAISE_LEVEL 5 +#define BLINDNESS 6 +#define HALLUCINATION 7 +#define DETECT_MONSTER 8 +#define DETECT_OBJECTS 9 +#define CONFUSION 10 +#define LEVITATION 11 +#define HASTE_SELF 12 +#define SEE_INVISIBLE 13 +#define POTIONS 14 + +#define TELE_AWAY 0 +#define SLOW_MONSTER 1 +#define INVISIBILITY 2 +#define POLYMORPH 3 +#define HASTE_MONSTER 4 +#define MAGIC_MISSILE 5 +#define CANCELLATION 6 +#define DO_NOTHING 7 +#define DRAIN_LIFE 8 +#define COLD 9 +#define FIRE 10 +#define WANDS 11 + +#define STEALTH 0 +#define R_TELEPORT 1 +#define REGENERATION 2 +#define SLOW_DIGEST 3 +#define ADD_STRENGTH 4 +#define SUSTAIN_STRENGTH 5 +#define DEXTERITY 6 +#define ADORNMENT 7 +#define R_SEE_INVISIBLE 8 +#define MAINTAIN_ARMOR 9 +#define SEARCHING 10 +#define RINGS 11 + +#define RATION 0 +#define FRUIT 1 + +#define NOT_USED ((unsigned short) 0) +#define BEING_WIELDED ((unsigned short) 01) +#define BEING_WORN ((unsigned short) 02) +#define ON_LEFT_HAND ((unsigned short) 04) +#define ON_RIGHT_HAND ((unsigned short) 010) +#define ON_EITHER_HAND ((unsigned short) 014) +#define BEING_USED ((unsigned short) 017) + +#define NO_TRAP -1 +#define TRAP_DOOR 0 +#define BEAR_TRAP 1 +#define TELE_TRAP 2 +#define DART_TRAP 3 +#define SLEEPING_GAS_TRAP 4 +#define RUST_TRAP 5 +#define TRAPS 6 + +#define STEALTH_FACTOR 3 +#define R_TELE_PERCENT 8 + +#define UNIDENTIFIED ((unsigned short) 00) /* MUST BE ZERO! */ +#define IDENTIFIED ((unsigned short) 01) +#define CALLED ((unsigned short) 02) + +#define DROWS 24 +#define DCOLS 80 +#define NMESSAGES 5 +#define MAX_TITLE_LENGTH 30 +#define MAXSYLLABLES 40 +#define MAX_METAL 14 +#define WAND_MATERIALS 30 +#define GEMS 14 + +#define GOLD_PERCENT 46 + +#define SCORE_FILE "/games/lib/rogue.scores" +#define LOCK_FILE "/games/lib/rogue.lock" + +#define MAX_OPT_LEN 40 + +struct id { + short value; + char title[35]; + char *real; + unsigned short id_status; +}; + +/* The following #defines provide more meaningful names for some of the + * struct object fields that are used for monsters. This, since each monster + * and object (scrolls, potions, etc) are represented by a struct object. + * Ideally, this should be handled by some kind of union structure. + */ + +#define m_damage damage +#define hp_to_kill quantity +#define m_char ichar +#define first_level is_protected +#define last_level is_cursed +#define m_hit_chance class +#define stationary_damage identified +#define drop_percent which_kind +#define trail_char d_enchant +#define slowed_toggle quiver +#define moves_confused hit_enchant +#define nap_length picked_up +#define disguise what_is +#define next_monster next_object + +struct obj { /* comment is monster meaning */ + long m_flags; /* monster flags */ + char *damage; /* damage it does */ + short quantity; /* hit points to kill */ + short ichar; /* 'A' is for aquatar */ + short kill_exp; /* exp for killing it */ + short is_protected; /* level starts */ + short is_cursed; /* level ends */ + short class; /* chance of hitting you */ + short identified; /* 'F' damage, 1,2,3... */ + unsigned short which_kind; /* item carry/drop % */ + short o_row, o_col, o; /* o is how many times stuck at o_row, o_col */ + short row, col; /* current row, col */ + short d_enchant; /* room char when detect_monster */ + short quiver; /* monster slowed toggle */ + short trow, tcol; /* target row, col */ + short hit_enchant; /* how many moves is confused */ + unsigned short what_is; /* imitator's charactor (?!%: */ + short picked_up; /* sleep from wand of sleep */ + unsigned short in_use_flags; + struct obj *next_object; /* next monster */ +}; + +typedef struct obj object; + +#define INIT_AW (object*)0,(object*)0 +#define INIT_RINGS (object*)0,(object*)0 +#define INIT_HP 12,12 +#define INIT_STR 16,16 +#define INIT_EXP 1,0 +#define INIT_PACK {0} +#define INIT_GOLD 0 +#define INIT_CHAR '@' +#define INIT_MOVES 1250 + +struct fightr { + object *armor; + object *weapon; + object *left_ring, *right_ring; + short hp_current; + short hp_max; + short str_current; + short str_max; + object pack; + long gold; + short exp; + long exp_points; + short row, col; + short fchar; + short moves_left; +}; + +typedef struct fightr fighter; + +struct dr { + short oth_room; + short oth_row, + oth_col; + short door_row, + door_col; +}; + +typedef struct dr door; + +struct rm { + short bottom_row, right_col, left_col, top_row; + door doors[4]; + unsigned short is_room; +}; + +typedef struct rm room; + +#define MAXROOMS 9 +#define BIG_ROOM 10 + +#define NO_ROOM -1 + +#define PASSAGE -3 /* cur_room value */ + +#define AMULET_LEVEL 26 + +#define R_NOTHING ((unsigned short) 01) +#define R_ROOM ((unsigned short) 02) +#define R_MAZE ((unsigned short) 04) +#define R_DEADEND ((unsigned short) 010) +#define R_CROSS ((unsigned short) 020) + +#define MAX_EXP_LEVEL 21 +#define MAX_EXP 10000001L +#define MAX_GOLD 999999 +#define MAX_ARMOR 99 +#define MAX_HP 999 +#define MAX_STRENGTH 99 +#define LAST_DUNGEON 99 + +#define STAT_LEVEL 01 +#define STAT_GOLD 02 +#define STAT_HP 04 +#define STAT_STRENGTH 010 +#define STAT_ARMOR 020 +#define STAT_EXP 040 +#define STAT_HUNGER 0100 +#define STAT_LABEL 0200 +#define STAT_ALL 0377 + +#define PARTY_TIME 10 /* one party somewhere in each 10 level span */ + +#define MAX_TRAPS 10 /* maximum traps per level */ + +#define HIDE_PERCENT 12 + +struct tr { + short trap_type; + short trap_row, trap_col; +}; + +typedef struct tr trap; + +extern fighter rogue; +extern room rooms[]; +extern trap traps[]; +extern unsigned short dungeon[DROWS][DCOLS]; +extern object level_objects; + +extern struct id id_scrolls[]; +extern struct id id_potions[]; +extern struct id id_wands[]; +extern struct id id_rings[]; +extern struct id id_weapons[]; +extern struct id id_armors[]; + +extern object mon_tab[]; +extern object level_monsters; + +#define MONSTERS 26 + +#define HASTED 01L +#define SLOWED 02L +#define INVISIBLE 04L +#define ASLEEP 010L +#define WAKENS 020L +#define WANDERS 040L +#define FLIES 0100L +#define FLITS 0200L +#define CAN_FLIT 0400L /* can, but usually doesn't, flit */ +#define CONFUSED 01000L +#define RUSTS 02000L +#define HOLDS 04000L +#define FREEZES 010000L +#define STEALS_GOLD 020000L +#define STEALS_ITEM 040000L +#define STINGS 0100000L +#define DRAINS_LIFE 0200000L +#define DROPS_LEVEL 0400000L +#define SEEKS_GOLD 01000000L +#define FREEZING_ROGUE 02000000L +#define RUST_VANISHED 04000000L +#define CONFUSES 010000000L +#define IMITATES 020000000L +#define FLAMES 040000000L +#define STATIONARY 0100000000L /* damage will be 1,2,3,... */ +#define NAPPING 0200000000L /* can't wake up for a while */ +#define ALREADY_MOVED 0400000000L + +#define SPECIAL_HIT (RUSTS|HOLDS|FREEZES|STEALS_GOLD|STEALS_ITEM|STINGS|DRAINS_LIFE|DROPS_LEVEL) + +#define WAKE_PERCENT 45 +#define FLIT_PERCENT 40 +#define PARTY_WAKE_PERCENT 75 + +#define HYPOTHERMIA 1 +#define STARVATION 2 +#define POISON_DART 3 +#define QUIT 4 +#define WIN 5 +#define KFIRE 6 + +#define UPWARD 0 +#define UPRIGHT 1 +#define RIGHT 2 +#define DOWNRIGHT 3 +#define DOWN 4 +#define DOWNLEFT 5 +#define LEFT 6 +#define UPLEFT 7 +#define DIRS 8 + +#define ROW1 7 +#define ROW2 15 + +#define COL1 26 +#define COL2 52 + +#define MOVED 0 +#define MOVE_FAILED -1 +#define STOPPED_ON_SOMETHING -2 +#define CANCEL '\033' +#define LIST '*' + +#define HUNGRY 300 +#define WEAK 150 +#define FAINT 20 +#define STARVE 0 + +#define MIN_ROW 1 + +struct rogue_time { + short year; /* >= 1987 */ + short month; /* 1 - 12 */ + short day; /* 1 - 31 */ + short hour; /* 0 - 23 */ + short minute; /* 0 - 59 */ + short second; /* 0 - 59 */ +}; + +#ifdef CURSES +struct _win_st { + short _cury, _curx; + short _maxy, _maxx; +}; + +typedef struct _win_st WINDOW; + +extern int LINES, COLS; +extern WINDOW *curscr; +extern char *CL; + +void initscr(void); +void endwin(void); +void noecho(void); +void crmode(void); +void nonl(void); +void refresh(void); +void wrefresh(WINDOW *scr); +void clear(void); +void clrtoeol(void); +void tstp(void); +void standout(void); +void standend(void); +void addstr(char *str); +void addch(int ch); +void move(int row, int col); +void mvaddch(int row, int col, int ch); +void mvaddstr(int row, int col, char *str); +int mvinch(int row, int col); + +#else +#include +#endif + +#ifdef CROSS +# include +#else +# include +#endif + +extern char ask_quit; +extern char being_held; +extern char cant_int; +extern char con_mon; +extern char detect_monster; +extern char did_int; +extern char interrupted; +extern char jump; +extern char maintain_armor; +extern char mon_disappeared; +extern char msg_cleared; +extern char no_skull; +extern char passgo; +extern char r_see_invisible; +extern char r_teleport; +extern char save_is_interactive; +extern char score_only; +extern char see_invisible; +extern char sustain_strength; +extern char trap_door; +extern char wizard; +extern char *byebye_string; +extern char *curse_message; +extern char *error_file; +extern char *fruit; +extern char *m_names[]; +extern char *more; +extern char *new_level_message; +extern char *nick_name; +extern char *press_space; +extern char *save_file; +extern char *you_can_move_again; +extern char hit_message[]; +extern char hunger_str[]; +extern char login_name[]; +extern long level_points[]; +extern char is_wood[]; +extern short add_strength; +extern short auto_search; +extern short bear_trap; +extern short blind; +extern short confused; +extern short cur_level; +extern short cur_room; +extern short e_rings; +extern short extra_hp; +extern short foods; +extern short halluc; +extern short haste_self; +extern short less_hp; +extern short levitate; +extern short max_level; +extern short m_moves; +extern short party_room; +extern short regeneration; +extern short ring_exp; +extern short r_rings; +extern short stealthy; + +void rand_around(int i, int *r, int *c); +void place_at(object *obj, int row, int col); +void message(char *msg, boolean intrpt); +void sound_bell(void); +void check_message(void); +void unwield(object *obj); +void mv_aquatars(void); +void unwear(object *obj); +void print_stats(int stat_mask); +void un_put_on(object *ring); +void wake_up(object *monster); +void check_gold_seeker(object *monster); +void s_con_mon(object *monster); +void vanish(object *obj, int rm, object *pack); +void get_dir_rc(int dir, int *row, int *col, int allow_off_screen); +void rogue_damage(int d, object *monster, int other); +void mv_1_monster(object *monster, int row, int col); +void move_mon_to(object *monster, int row, int col); +void do_wear(object *obj); +void do_wield(object *obj); +void do_put_on(object *ring, boolean on_left); +void inv_rings(void); +void ring_stats(boolean pr); +void rust(object *monster); +void tele(void); +void unhallucinate(void); +void unblind(void); +void relight(void); +void take_a_nap(void); +void cnfs(void); +void unconfuse(void); +void special_hit(object *monster); +void killed_by(object *monster, int other); +void cough_up(object *monster); +void add_exp(int e, boolean promotion); +void take_from_pack(object *obj, object *pack); +void free_object(object *obj); +void put_amulet(void); +void md_cbreak_no_echo_nonl(boolean on); +void md_tstp(void); +void md_slurp(void); +void start_window(void); +void stop_window(void); +void gr_row_col(int *row, int *col, unsigned mask); +void light_up_room(int rn); +void light_passage(int row, int col); +void wake_room(int rn, boolean entering, int row, int col); +void win(void); +void clean_up(char *estr); +void multiple_move_rogue(int dirch); +void get_food(object *obj, boolean force_ration); +void put_scores(object *monster, int other); +void xxxx(char *buf, int n); +void md_heed_signals(void); +void srrandom(int x); +void restore(char *fname); +void mix_colors(void); +void get_wand_and_ring_materials(void); +void make_scroll_titles(void); +void md_exit(int status); +void md_control_keybord(boolean mode); +void md_ignore_signals(void); +void quit(boolean from_intrpt); +void save_into_file(char *sfile); +void get_desc(object *obj, char *desc); +void wait_for_ack(void); +void make_level(void); +void clear_level(void); +void put_objects(void); +void put_stairs(void); +void add_traps(void); +void put_mons(void); +void put_player(int nr); +void play_level(void); +void free_stuff(object *objlist); +void mon_hit(object *monster); +void dr_course(object *monster, boolean entering, int row, int col); +void rogue_hit(object *monster, boolean force_hit); +void darken_room(int rn); +void trap_player(int row, int col); +void mv_mons(void); +void wanderer(void); +void hallucinate(void); +void search(int n, boolean is_auto); +void party_monsters(int rn, int n); +void gr_ring(object *ring, boolean assign_wk); +void inventory(object *pack, unsigned mask); +void rest(int count); +void fight(boolean to_the_death); +void eat(void); +void quaff(void); +void read_scroll(void); +void move_onto(void); +void kick_into_pack(void); +void drop(void); +void put_on_ring(void); +void remove_ring(void); +void remessage(int c); +void wizardize(void); +void inv_armor_weapon(boolean is_weapon); +void id_trap(void); +void id_type(void); +void id_com(void); +void do_shell(void); +void edit_opts(void); +void single_inv(int ichar); +void take_off(void); +void wear(void); +void wield(void); +void call_it(void); +void zapp(void); +void throw(void); +void draw_magic_map(void); +void show_traps(void); +void show_objects(void); +void show_average_hp(void); +void c_object_for_wizard(void); +void show_monsters(void); +void save_game(void); +void md_shell(char *shell); +void md_gct(struct rogue_time *rt_buf); +void md_gfmt(char *fname, struct rogue_time *rt_buf); +void md_lock(boolean l); +void bounce(int ball, int dir, int row, int col, int r); +void create_monster(void); +void aggravate(void); +void md_sleep(int nsecs); +void onintr(int sig); +void byebye(int sig); +void error_save(int sig); + +int rogue_can_see(int row, int col); +int get_dungeon_char(int row, int col); +int rgetchar(void); +int pack_letter(char *prompt, unsigned mask); +int get_hit_chance(object *weapon); +int get_weapon_damage(object *weapon); +int rand_percent(int percentage); +int get_rand(int x, int y); +int mon_damage(object *monster, int damage); +int get_mask_char(unsigned mask); +int imitating(int row, int col); +int get_damage(char *ds, boolean r); +int get_armor_class(object *obj); +int check_imitator(object *monster); +int get_number(char *s); +int can_move(int row1, int col1, int row2, int col2); +int one_move_rogue(int dirch, int pickup); +int is_all_connected(void); +int coin_toss(void); +int has_amulet(void); +int get_room_number(int row, int col); +int hp_raise(void); +int md_gseed(void); +int is_vowel(int ch); +int init(int argc, char **argv); +int gr_obj_char(void); +int mon_can_go(object *monster, int row, int col); +int m_confuse(object *monster); +int flame_broil(object *monster); +int seek_gold(object *monster); +int is_passable(int row, int col); +int gr_room(void); +int party_objects(int rn); +int pack_count(object *new_obj); +int r_index(char *str, int ch, boolean last); +int get_input_line(char *prompt, char *insert, char *buf, char *if_cancelled, + boolean add_blank, boolean do_echo); +int drop_check(void); +int check_up(void); +int gmc_row_col(int row, int col); +int md_get_file_id(char *fname); +int md_link_count(char *fname); +int gmc(object *monster); + +long xxx(boolean st); +long lget_number(char *s); + +boolean is_direction(int c, int *d); +boolean mon_sees(object *monster, int row, int col); +boolean reg_move(void); +boolean is_digit(int ch); +boolean md_df(char *fname); + +char *md_getenv(char *name); +char *md_malloc(int n); +char *md_gln(void); +char *mon_name(object *monster); +char *name_of(object *obj); + +object *alloc_object(void); +object *object_at(object *pack, int row, int col); +object *add_to_pack(object *obj, object *pack, int condense); +object *get_letter_object(int ch); +object *gr_object(void); +object *gr_monster(object *monster, int mn); +object *pick_up(int row, int col, int *status); + +struct id *get_id_table(object *obj); diff --git a/src/games/rogue/room.c b/src/games/rogue/room.c new file mode 100644 index 0000000..e434768 --- /dev/null +++ b/src/games/rogue/room.c @@ -0,0 +1,622 @@ +/* + * This source herein may be modified and/or distributed by anybody who + * so desires, with the following restrictions: + * 1.) No portion of this notice shall be removed. + * 2.) Credit shall not be taken for the creation of this source. + * 3.) This code is not to be traded, sold, or used for personal + * gain or profit. + */ +#include +#include "rogue.h" + +room rooms[MAXROOMS]; +char rooms_visited[MAXROOMS]; + +#define NOPTS 7 + +struct option { + char *prompt; + boolean is_bool; + char **strval; + char *bval; +} options[NOPTS] = { + { + "Show position only at end of run (\"jump\"): ", + 1, (char **) 0, &jump + }, + { + "Follow turnings in passageways (\"passgo\"): ", + 1, (char **) 0, &passgo + }, + { + "Don't print skull when killed (\"noskull\" or \"notombstone\"): ", + 1, (char **) 0, &no_skull + }, + { + "Ask player before saying 'Okay, bye-bye!' (\"askquit\"): ", + 1, (char **) 0, &ask_quit + }, + { + "Name (\"name\"): ", + 0, &nick_name + }, + { + "Fruit (\"fruit\"): ", + 0, &fruit + }, + { + "Save file (\"file\"): ", + 0, &save_file + } +}; + +void +light_up_room(rn) + int rn; +{ + int i, j; + + if (!blind) { + for (i = rooms[rn].top_row; + i <= rooms[rn].bottom_row; i++) { + for (j = rooms[rn].left_col; + j <= rooms[rn].right_col; j++) { + if (dungeon[i][j] & MONSTER) { + object *monster; + + monster = object_at(&level_monsters, i, j); + if (monster) { + dungeon[monster->row][monster->col] &= (~MONSTER); + monster->trail_char = + get_dungeon_char(monster->row, monster->col); + dungeon[monster->row][monster->col] |= MONSTER; + } + } + mvaddch(i, j, get_dungeon_char(i, j)); + } + } + mvaddch(rogue.row, rogue.col, rogue.fchar); + } +} + +void +light_passage(row, col) +{ + int i, j, i_end, j_end; + + if (blind) { + return; + } + i_end = (row < (DROWS-2)) ? 1 : 0; + j_end = (col < (DCOLS-1)) ? 1 : 0; + + for (i = ((row > MIN_ROW) ? -1 : 0); i <= i_end; i++) { + for (j = ((col > 0) ? -1 : 0); j <= j_end; j++) { + if (can_move(row, col, row+i, col+j)) { + mvaddch(row+i, col+j, get_dungeon_char(row+i, col+j)); + } + } + } +} + +void +darken_room(rn) + int rn; +{ + int i, j; + + for (i = rooms[rn].top_row + 1; i < rooms[rn].bottom_row; i++) { + for (j = rooms[rn].left_col + 1; j < rooms[rn].right_col; j++) { + if (blind) { + mvaddch(i, j, ' '); + } else { + if (!(dungeon[i][j] & (OBJECT | STAIRS)) && + !(detect_monster && (dungeon[i][j] & MONSTER))) { + if (!imitating(i, j)) { + mvaddch(i, j, ' '); + } + if ((dungeon[i][j] & TRAP) && (!(dungeon[i][j] & HIDDEN))) { + mvaddch(i, j, '^'); + } + } + } + } + } +} + +int +get_dungeon_char(row, col) + register int row, col; +{ + register unsigned mask = dungeon[row][col]; + + if (mask & MONSTER) { + return(gmc_row_col(row, col)); + } + if (mask & OBJECT) { + object *obj; + + obj = object_at(&level_objects, row, col); + return(get_mask_char(obj->what_is)); + } + if (mask & (TUNNEL | STAIRS | HORWALL | VERTWALL | FLOOR | DOOR)) { + if ((mask & (TUNNEL| STAIRS)) && (!(mask & HIDDEN))) { + return(((mask & STAIRS) ? '%' : '#')); + } + if (mask & HORWALL) { + return('-'); + } + if (mask & VERTWALL) { + return('|'); + } + if (mask & FLOOR) { + if (mask & TRAP) { + if (!(dungeon[row][col] & HIDDEN)) { + return('^'); + } + } + return('.'); + } + if (mask & DOOR) { + if (mask & HIDDEN) { + if (((col > 0) && (dungeon[row][col-1] & HORWALL)) || + ((col < (DCOLS-1)) && (dungeon[row][col+1] & HORWALL))) { + return('-'); + } else { + return('|'); + } + } else { + return('+'); + } + } + } + return(' '); +} + +int +get_mask_char(mask) + register unsigned int mask; +{ + switch(mask) { + case SCROL: + return('?'); + case POTION: + return('!'); + case GOLD: + return('*'); + case FOOD: + return(':'); + case WAND: + return('/'); + case ARMOR: + return(']'); + case WEAPON: + return(')'); + case RING: + return('='); + case AMULET: + return(','); + default: + return('~'); /* unknown, something is wrong */ + } +} + +void +gr_row_col(row, col, mask) + int *row, *col; + unsigned mask; +{ + int rn; + int r, c; + + do { + r = get_rand(MIN_ROW, DROWS-2); + c = get_rand(0, DCOLS-1); + rn = get_room_number(r, c); + } while ((rn == NO_ROOM) || + (!(dungeon[r][c] & mask)) || + (dungeon[r][c] & (~mask)) || + (!(rooms[rn].is_room & (R_ROOM | R_MAZE))) || + ((r == rogue.row) && (c == rogue.col))); + + *row = r; + *col = c; +} + +int +gr_room() +{ + int i; + + do { + i = get_rand(0, MAXROOMS-1); + } while (!(rooms[i].is_room & (R_ROOM | R_MAZE))); + + return(i); +} + +int +party_objects(rn) +{ + int i, j, nf = 0; + object *obj; + int n, N, row, col; + boolean found; + + N = ((rooms[rn].bottom_row - rooms[rn].top_row) - 1) * + ((rooms[rn].right_col - rooms[rn].left_col) - 1); + n = get_rand(5, 10); + if (n > N) { + n = N - 2; + } + for (i = 0; i < n; i++) { + for (j = found = 0; ((!found) && (j < 250)); j++) { + row = get_rand(rooms[rn].top_row+1, + rooms[rn].bottom_row-1); + col = get_rand(rooms[rn].left_col+1, + rooms[rn].right_col-1); + if ((dungeon[row][col] == FLOOR) || (dungeon[row][col] == TUNNEL)) { + found = 1; + } + } + if (found) { + obj = gr_object(); + place_at(obj, row, col); + nf++; + } + } + return(nf); +} + +int +get_room_number(row, col) + register int row, col; +{ + int i; + + for (i = 0; i < MAXROOMS; i++) { + if ((row >= rooms[i].top_row) && (row <= rooms[i].bottom_row) && + (col >= rooms[i].left_col) && (col <= rooms[i].right_col)) { + return(i); + } + } + return(NO_ROOM); +} + +static void +visit_rooms(rn) + int rn; +{ + int i, oth_rn; + + rooms_visited[rn] = 1; + + for (i = 0; i < 4; i++) { + oth_rn = rooms[rn].doors[i].oth_room; + if ((oth_rn >= 0) && (!rooms_visited[oth_rn])) { + visit_rooms(oth_rn); + } + } +} + +int +is_all_connected() +{ + int i, starting_room = 0; + + for (i = 0; i < MAXROOMS; i++) { + rooms_visited[i] = 0; + if (rooms[i].is_room & (R_ROOM | R_MAZE)) { + starting_room = i; + } + } + + visit_rooms(starting_room); + + for (i = 0; i < MAXROOMS; i++) { + if ((rooms[i].is_room & (R_ROOM | R_MAZE)) && (!rooms_visited[i])) { + return(0); + } + } + return(1); +} + +void +draw_magic_map() +{ + int i, j, ch, och; + unsigned mask = (HORWALL | VERTWALL | DOOR | TUNNEL | TRAP | STAIRS | MONSTER); + unsigned s; + + for (i = 0; i < DROWS; i++) { + for (j = 0; j < DCOLS; j++) { + s = dungeon[i][j]; + if (s & mask) { + if (((ch = mvinch(i, j)) == ' ') || + ((ch >= 'A') && (ch <= 'Z')) || (s & (TRAP | HIDDEN))) { + och = ch; + dungeon[i][j] &= (~HIDDEN); + if (s & HORWALL) { + ch = '-'; + } else if (s & VERTWALL) { + ch = '|'; + } else if (s & DOOR) { + ch = '+'; + } else if (s & TRAP) { + ch = '^'; + } else if (s & STAIRS) { + ch = '%'; + } else if (s & TUNNEL) { + ch = '#'; + } else { + continue; + } + if ((!(s & MONSTER)) || (och == ' ')) { + addch(ch); + } + if (s & MONSTER) { + object *monster; + + monster = object_at(&level_monsters, i, j); + if (monster) { + monster->trail_char = ch; + } + } + } + } + } + } +} + +static int +get_oth_room(rn, row, col) + int rn, *row, *col; +{ + int d = -1; + + if (*row == rooms[rn].top_row) { + d = UPWARD/2; + } else if (*row == rooms[rn].bottom_row) { + d = DOWN/2; + } else if (*col == rooms[rn].left_col) { + d = LEFT/2; + } else if (*col == rooms[rn].right_col) { + d = RIGHT/2; + } + if ((d != -1) && (rooms[rn].doors[d].oth_room >= 0)) { + *row = rooms[rn].doors[d].oth_row; + *col = rooms[rn].doors[d].oth_col; + return(1); + } + return(0); +} + +void +dr_course(monster, entering, row, col) + object *monster; + boolean entering; + int row, col; +{ + int i, j, k, rn; + int r, rr; + + monster->row = row; + monster->col = col; + + if (mon_sees(monster, rogue.row, rogue.col)) { + monster->trow = NO_ROOM; + return; + } + rn = get_room_number(row, col); + + if (entering) { /* entering room */ + /* look for door to some other room */ + r = get_rand(0, MAXROOMS-1); + for (i = 0; i < MAXROOMS; i++) { + rr = (r + i) % MAXROOMS; + if ((!(rooms[rr].is_room & (R_ROOM | R_MAZE))) || (rr == rn)) { + continue; + } + for (k = 0; k < 4; k++) { + if (rooms[rr].doors[k].oth_room == rn) { + monster->trow = rooms[rr].doors[k].oth_row; + monster->tcol = rooms[rr].doors[k].oth_col; + if ((monster->trow == row) && + (monster->tcol == col)) { + continue; + } + return; + } + } + } + /* look for door to dead end */ + for (i = rooms[rn].top_row; i <= rooms[rn].bottom_row; i++) { + for (j = rooms[rn].left_col; j <= rooms[rn].right_col; j++) { + if ((i != monster->row) && (j != monster->col) && + (dungeon[i][j] & DOOR)) { + monster->trow = i; + monster->tcol = j; + return; + } + } + } + /* return monster to room that he came from */ + for (i = 0; i < MAXROOMS; i++) { + for (j = 0; j < 4; j++) { + if (rooms[i].doors[j].oth_room == rn) { + for (k = 0; k < 4; k++) { + if (rooms[rn].doors[k].oth_room == i) { + monster->trow = rooms[rn].doors[k].oth_row; + monster->tcol = rooms[rn].doors[k].oth_col; + return; + } + } + } + } + } + /* no place to send monster */ + monster->trow = NO_ROOM; + } else { /* exiting room */ + if (!get_oth_room(rn, &row, &col)) { + monster->trow = NO_ROOM; + } else { + monster->trow = row; + monster->tcol = col; + } + } +} + +static void +opt_erase(i) + int i; +{ + struct option *opt = &options[i]; + + mvaddstr(i, 0, opt->prompt); + clrtoeol(); +} + +static void +opt_show(i) + int i; +{ + char *s; + struct option *opt = &options[i]; + + opt_erase(i); + + if (opt->is_bool) { + s = *(opt->bval) ? "True" : "False"; + } else { + s = *(opt->strval); + } + addstr(s); +} + +static void +opt_go(i) + int i; +{ + move(i, strlen(options[i].prompt)); +} + +void +edit_opts() +{ + char save[NOPTS+1][DCOLS]; + int i, j; + int ch; + boolean done = 0; + char buf[MAX_OPT_LEN + 2]; + + for (i = 0; i < NOPTS+1; i++) { + for (j = 0; j < DCOLS; j++) { + save[i][j] = mvinch(i, j); + } + if (i < NOPTS) { + opt_show(i); + } + } + opt_go(0); + i = 0; + + while (!done) { + refresh(); + ch = rgetchar(); +CH: + switch(ch) { + case '\033': + done = 1; + break; + case '\012': + case '\015': + if (i == (NOPTS - 1)) { + mvaddstr(NOPTS, 0, press_space); + refresh(); + wait_for_ack(); + done = 1; + } else { + i++; + opt_go(i); + } + break; + case '-': + if (i > 0) { + opt_go(--i); + } else { + sound_bell(); + } + break; + case 't': + case 'T': + case 'f': + case 'F': + if (options[i].is_bool) { + *(options[i].bval) = (((ch == 't') || (ch == 'T')) ? 1 : 0); + opt_show(i); + opt_go(++i); + break; + } + default: + if (options[i].is_bool) { + sound_bell(); + break; + } + j = 0; + if ((ch == '\010') || ((ch >= ' ') && (ch <= '~'))) { + opt_erase(i); + do { + if ((ch >= ' ') && (ch <= '~') && (j < MAX_OPT_LEN)) { + buf[j++] = ch; + buf[j] = '\0'; + addch(ch); + } else if ((ch == '\010') && (j > 0)) { + buf[--j] = '\0'; + move(i, j + strlen(options[i].prompt)); + addch(' '); + move(i, j + strlen(options[i].prompt)); + } + refresh(); + ch = rgetchar(); + } while ((ch != '\012') && (ch != '\015') && (ch != '\033')); + if (j != 0) { + (void) strcpy(*(options[i].strval), buf); + } + opt_show(i); + goto CH; + } else { + sound_bell(); + } + break; + } + } + + for (i = 0; i < NOPTS+1; i++) { + move(i, 0); + for (j = 0; j < DCOLS; j++) { + addch(save[i][j]); + } + } +} + +void +do_shell() +{ +#ifdef UNIX + char *sh; + + md_ignore_signals(); + sh = md_getenv("SHELL"); + if (! sh) { + sh = "/bin/sh"; + } + move(LINES-1, 0); + refresh(); + stop_window(); + printf("\nCreating new shell...\n"); + md_shell(sh); + start_window(); + wrefresh(curscr); + md_heed_signals(); +#endif +} diff --git a/src/games/rogue/save.c b/src/games/rogue/save.c new file mode 100644 index 0000000..82374c6 --- /dev/null +++ b/src/games/rogue/save.c @@ -0,0 +1,376 @@ +/* + * This source herein may be modified and/or distributed by anybody who + * so desires, with the following restrictions: + * 1.) No portion of this notice shall be removed. + * 2.) Credit shall not be taken for the creation of this source. + * 3.) This code is not to be traded, sold, or used for personal + * gain or profit. + */ +#include +#include "rogue.h" + +short write_failed = 0; +char *save_file = (char *) 0; + +void +save_game() +{ + char fname[64]; + + if (!get_input_line("file name?", save_file, fname, "game not saved", + 0, 1)) { + return; + } + check_message(); + message(fname, 0); + save_into_file(fname); +} + +static void +r_write(fp, buf, n) + FILE *fp; + char *buf; + int n; +{ + if (!write_failed) { + if (fwrite(buf, sizeof(char), n, fp) != n) { + message("write() failed, don't know why", 0); + sound_bell(); + write_failed = 1; + } + } +} + +static void +write_string(s, fp) + char *s; + FILE *fp; +{ + short n; + + n = strlen(s) + 1; + xxxx(s, n); + r_write(fp, (char *) &n, sizeof(short)); + r_write(fp, s, n); +} + +static void +write_pack(pack, fp) + object *pack; + FILE *fp; +{ + object t; + + while ((pack = pack->next_object)) { + r_write(fp, (char *) pack, sizeof(object)); + } + t.ichar = t.what_is = 0; + r_write(fp, (char *) &t, sizeof(object)); +} + +static void +r_read(fp, buf, n) + FILE *fp; + char *buf; + int n; +{ + if (fread(buf, sizeof(char), n, fp) != n) { + clean_up("read() failed, don't know why"); + } +} + +static void +rw_dungeon(fp, rw) + FILE *fp; + boolean rw; +{ + int i, j; + char buf[DCOLS]; + + for (i = 0; i < DROWS; i++) { + if (rw) { + r_write(fp, (char *) dungeon[i], (DCOLS * sizeof(dungeon[0][0]))); + for (j = 0; j < DCOLS; j++) { + buf[j] = mvinch(i, j); + } + r_write(fp, buf, DCOLS); + } else { + r_read(fp, (char *) dungeon[i], (DCOLS * sizeof(dungeon[0][0]))); + r_read(fp, buf, DCOLS); + for (j = 0; j < DCOLS; j++) { + mvaddch(i, j, buf[j]); + } + } + } +} + +static void +read_string(s, fp) + char *s; + FILE *fp; +{ + short n; + + r_read(fp, (char *) &n, sizeof(short)); + r_read(fp, s, n); + xxxx(s, n); +} + +static void +rw_id(id_table, fp, n, wr) + struct id id_table[]; + FILE *fp; + int n; + boolean wr; +{ + int i; + + for (i = 0; i < n; i++) { + if (wr) { + r_write(fp, (char *) &(id_table[i].value), sizeof(short)); + r_write(fp, (char *) &(id_table[i].id_status), + sizeof(unsigned short)); + write_string(id_table[i].title, fp); + } else { + r_read(fp, (char *) &(id_table[i].value), sizeof(short)); + r_read(fp, (char *) &(id_table[i].id_status), + sizeof(unsigned short)); + read_string(id_table[i].title, fp); + } + } +} + +static void +rw_rooms(fp, rw) + FILE *fp; + boolean rw; +{ + int i; + + for (i = 0; i < MAXROOMS; i++) { + rw ? r_write(fp, (char *) (rooms + i), sizeof(room)) : + r_read(fp, (char *) (rooms + i), sizeof(room)); + } +} + +void +save_into_file(sfile) + char *sfile; +{ + FILE *fp; + int file_id; + char name_buffer[80]; + char *hptr; + struct rogue_time rt_buf; + + if (sfile[0] == '~') { + hptr = md_getenv("HOME"); + if (hptr) { + (void) strcpy(name_buffer, hptr); + (void) strcat(name_buffer, sfile+1); + sfile = name_buffer; + } + } + if ( ((fp = fopen(sfile, "w")) == NULL) || + ((file_id = md_get_file_id(sfile)) == -1)) { + message("problem accessing the save file", 0); + return; + } + md_ignore_signals(); + write_failed = 0; + (void) xxx(1); + r_write(fp, (char *) &detect_monster, sizeof(detect_monster)); + r_write(fp, (char *) &cur_level, sizeof(cur_level)); + r_write(fp, (char *) &max_level, sizeof(max_level)); + write_string(hunger_str, fp); + write_string(login_name, fp); + r_write(fp, (char *) &party_room, sizeof(party_room)); + write_pack(&level_monsters, fp); + write_pack(&level_objects, fp); + r_write(fp, (char *) &file_id, sizeof(file_id)); + rw_dungeon(fp, 1); + r_write(fp, (char *) &foods, sizeof(foods)); + r_write(fp, (char *) &rogue, sizeof(fighter)); + write_pack(&rogue.pack, fp); + rw_id(id_potions, fp, POTIONS, 1); + rw_id(id_scrolls, fp, SCROLS, 1); + rw_id(id_wands, fp, WANDS, 1); + rw_id(id_rings, fp, RINGS, 1); + r_write(fp, (char *) traps, (MAX_TRAPS * sizeof(trap))); + r_write(fp, (char *) is_wood, (WANDS * sizeof(boolean))); + r_write(fp, (char *) &cur_room, sizeof(cur_room)); + rw_rooms(fp, 1); + r_write(fp, (char *) &being_held, sizeof(being_held)); + r_write(fp, (char *) &bear_trap, sizeof(bear_trap)); + r_write(fp, (char *) &halluc, sizeof(halluc)); + r_write(fp, (char *) &blind, sizeof(blind)); + r_write(fp, (char *) &confused, sizeof(confused)); + r_write(fp, (char *) &levitate, sizeof(levitate)); + r_write(fp, (char *) &haste_self, sizeof(haste_self)); + r_write(fp, (char *) &see_invisible, sizeof(see_invisible)); + r_write(fp, (char *) &detect_monster, sizeof(detect_monster)); + r_write(fp, (char *) &wizard, sizeof(wizard)); + r_write(fp, (char *) &score_only, sizeof(score_only)); + r_write(fp, (char *) &m_moves, sizeof(m_moves)); + md_gct(&rt_buf); + rt_buf.second += 10; /* allow for some processing time */ + r_write(fp, (char *) &rt_buf, sizeof(rt_buf)); + fclose(fp); + + if (write_failed) { + (void) md_df(sfile); /* delete file */ + } else { + clean_up(""); + } +} + +static void +read_pack(pack, fp, is_rogue) + object *pack; + FILE *fp; + boolean is_rogue; +{ + object read_obj, *new_obj; + + for (;;) { + r_read(fp, (char *) &read_obj, sizeof(object)); + if (read_obj.ichar == 0) { + pack->next_object = (object *) 0; + break; + } + new_obj = alloc_object(); + *new_obj = read_obj; + if (is_rogue) { + if (new_obj->in_use_flags & BEING_WORN) { + do_wear(new_obj); + } else if (new_obj->in_use_flags & BEING_WIELDED) { + do_wield(new_obj); + } else if (new_obj->in_use_flags & (ON_EITHER_HAND)) { + do_put_on(new_obj, + ((new_obj->in_use_flags & ON_LEFT_HAND) ? 1 : 0)); + } + } + pack->next_object = new_obj; + pack = new_obj; + } +} + +static boolean +has_been_touched(saved_time, mod_time) + struct rogue_time *saved_time, *mod_time; +{ + if (saved_time->year < mod_time->year) { + return(1); + } else if (saved_time->year > mod_time->year) { + return(0); + } + if (saved_time->month < mod_time->month) { + return(1); + } else if (saved_time->month > mod_time->month) { + return(0); + } + if (saved_time->day < mod_time->day) { + return(1); + } else if (saved_time->day > mod_time->day) { + return(0); + } + if (saved_time->hour < mod_time->hour) { + return(1); + } else if (saved_time->hour > mod_time->hour) { + return(0); + } + if (saved_time->minute < mod_time->minute) { + return(1); + } else if (saved_time->minute > mod_time->minute) { + return(0); + } + if (saved_time->second < mod_time->second) { + return(1); + } + return(0); +} + +void +restore(fname) + char *fname; +{ + FILE *fp; + struct rogue_time saved_time, mod_time; + char buf[4]; + char tbuf[40]; + int new_file_id, saved_file_id; + + new_file_id = md_get_file_id(fname); + if (new_file_id == -1) { + clean_up("no save file"); + } + fp = fopen(fname, "r"); + if (! fp) { + clean_up("cannot open file"); + } + if (md_link_count(fname) > 1) { + clean_up("file has link"); + } + (void) xxx(1); + r_read(fp, (char *) &detect_monster, sizeof(detect_monster)); + r_read(fp, (char *) &cur_level, sizeof(cur_level)); + r_read(fp, (char *) &max_level, sizeof(max_level)); + read_string(hunger_str, fp); + + (void) strcpy(tbuf, login_name); + read_string(login_name, fp); + if (strcmp(tbuf, login_name)) { + clean_up("you're not the original player"); + } + + r_read(fp, (char *) &party_room, sizeof(party_room)); + read_pack(&level_monsters, fp, 0); + read_pack(&level_objects, fp, 0); + r_read(fp, (char *) &saved_file_id, sizeof(saved_file_id)); + if (new_file_id != saved_file_id) { + clean_up("sorry, saved game is not in the same file"); + } + rw_dungeon(fp, 0); + r_read(fp, (char *) &foods, sizeof(foods)); + r_read(fp, (char *) &rogue, sizeof(fighter)); + read_pack(&rogue.pack, fp, 1); + rw_id(id_potions, fp, POTIONS, 0); + rw_id(id_scrolls, fp, SCROLS, 0); + rw_id(id_wands, fp, WANDS, 0); + rw_id(id_rings, fp, RINGS, 0); + r_read(fp, (char *) traps, (MAX_TRAPS * sizeof(trap))); + r_read(fp, (char *) is_wood, (WANDS * sizeof(boolean))); + r_read(fp, (char *) &cur_room, sizeof(cur_room)); + rw_rooms(fp, 0); + r_read(fp, (char *) &being_held, sizeof(being_held)); + r_read(fp, (char *) &bear_trap, sizeof(bear_trap)); + r_read(fp, (char *) &halluc, sizeof(halluc)); + r_read(fp, (char *) &blind, sizeof(blind)); + r_read(fp, (char *) &confused, sizeof(confused)); + r_read(fp, (char *) &levitate, sizeof(levitate)); + r_read(fp, (char *) &haste_self, sizeof(haste_self)); + r_read(fp, (char *) &see_invisible, sizeof(see_invisible)); + r_read(fp, (char *) &detect_monster, sizeof(detect_monster)); + r_read(fp, (char *) &wizard, sizeof(wizard)); + r_read(fp, (char *) &score_only, sizeof(score_only)); + r_read(fp, (char *) &m_moves, sizeof(m_moves)); + r_read(fp, (char *) &saved_time, sizeof(saved_time)); + + if (fread(buf, sizeof(char), 1, fp) > 0) { + clear(); + clean_up("extra characters in file"); + } + + md_gfmt(fname, &mod_time); /* get file modification time */ + + if (has_been_touched(&saved_time, &mod_time)) { + clear(); + clean_up("sorry, file has been touched"); + } + if ((!wizard) && !md_df(fname)) { + clean_up("cannot delete file"); + } + msg_cleared = 0; + ring_stats(0); + fclose(fp); +} diff --git a/src/games/rogue/score.c b/src/games/rogue/score.c new file mode 100644 index 0000000..95965ec --- /dev/null +++ b/src/games/rogue/score.c @@ -0,0 +1,544 @@ +/* + * This source herein may be modified and/or distributed by anybody who + * so desires, with the following restrictions: + * 1.) No portion of this notice shall be removed. + * 2.) Credit shall not be taken for the creation of this source. + * 3.) This code is not to be traded, sold, or used for personal + * gain or profit. + */ +#include +#include "rogue.h" + +static void +center(row, buf) + int row; + char *buf; +{ + int margin; + + margin = ((DCOLS - strlen(buf)) / 2); + mvaddstr(row, margin, buf); +} + +void +killed_by(monster, other) + object *monster; + int other; +{ + char buf[128]; + + md_ignore_signals(); + + if (other != QUIT) { + rogue.gold = ((rogue.gold * 9) / 10); + } + + if (other) { + switch(other) { + case HYPOTHERMIA: + (void) strcpy(buf, "died of hypothermia"); + break; + case STARVATION: + (void) strcpy(buf, "died of starvation"); + break; + case POISON_DART: + (void) strcpy(buf, "killed by a dart"); + break; + case QUIT: + (void) strcpy(buf, "quit"); + break; + case KFIRE: + (void) strcpy(buf, "killed by fire"); + break; + } + } else { + (void) strcpy(buf, "Killed by "); + if (is_vowel(m_names[monster->m_char - 'A'][0])) { + (void) strcat(buf, "an "); + } else { + (void) strcat(buf, "a "); + } + (void) strcat(buf, m_names[monster->m_char - 'A']); + } + (void) strcat(buf, " with "); + sprintf(buf+strlen(buf), "%ld gold", rogue.gold); + if ((!other) && (!no_skull)) { + clear(); + mvaddstr(4, 32, "__---------__"); + mvaddstr(5, 30, "_~ ~_"); + mvaddstr(6, 29, "/ \\"); + mvaddstr(7, 28, "~ ~"); + mvaddstr(8, 27, "/ \\"); + mvaddstr(9, 27, "| XXXX XXXX |"); + mvaddstr(10, 27, "| XXXX XXXX |"); + mvaddstr(11, 27, "| XXX XXX |"); + mvaddstr(12, 28, "\\ @ /"); + mvaddstr(13, 29, "--\\ @@@ /--"); + mvaddstr(14, 30, "| | @@@ | |"); + mvaddstr(15, 30, "| | | |"); + mvaddstr(16, 30, "| vvVvvvvvvvVvv |"); + mvaddstr(17, 30, "| ^^^^^^^^^^^ |"); + mvaddstr(18, 31, "\\_ _/"); + mvaddstr(19, 33, "~---------~"); + center(21, nick_name); + center(22, buf); + } else { + message(buf, 0); + } + message("", 0); + put_scores(monster, other); +} + +static int +get_value(obj) + object *obj; +{ + int wc; + int val = 0; + + wc = obj->which_kind; + + switch(obj->what_is) { + case WEAPON: + val = id_weapons[wc].value; + if ((wc == ARROW) || (wc == DAGGER) || (wc == SHURIKEN) || + (wc == DART)) { + val *= obj->quantity; + } + val += (obj->d_enchant * 85); + val += (obj->hit_enchant * 85); + break; + case ARMOR: + val = id_armors[wc].value; + val += (obj->d_enchant * 75); + if (obj->is_protected) { + val += 200; + } + break; + case WAND: + val = id_wands[wc].value * (obj->class + 1); + break; + case SCROL: + val = id_scrolls[wc].value * obj->quantity; + break; + case POTION: + val = id_potions[wc].value * obj->quantity; + break; + case AMULET: + val = 5000; + break; + case RING: + val = id_rings[wc].value * (obj->class + 1); + break; + } + if (val <= 0) { + val = 10; + } + return(val); +} + +static void +sell_pack() +{ + object *obj; + int row = 2, val; + char buf[DCOLS]; + + obj = rogue.pack.next_object; + + clear(); + mvaddstr(1, 0, "Value Item"); + + while (obj) { + if (obj->what_is != FOOD) { + obj->identified = 1; + val = get_value(obj); + rogue.gold += val; + + if (row < DROWS) { + sprintf(buf, "%5d ", val); + get_desc(obj, buf+11); + mvaddstr(row++, 0, buf); + } + } + obj = obj->next_object; + } + refresh(); + if (rogue.gold > MAX_GOLD) { + rogue.gold = MAX_GOLD; + } + message("", 0); +} + +static void +id_all() +{ + int i; + + for (i = 0; i < SCROLS; i++) { + id_scrolls[i].id_status = IDENTIFIED; + } + for (i = 0; i < WEAPONS; i++) { + id_weapons[i].id_status = IDENTIFIED; + } + for (i = 0; i < ARMORS; i++) { + id_armors[i].id_status = IDENTIFIED; + } + for (i = 0; i < WANDS; i++) { + id_wands[i].id_status = IDENTIFIED; + } + for (i = 0; i < POTIONS; i++) { + id_potions[i].id_status = IDENTIFIED; + } +} + +void +win() +{ + unwield(rogue.weapon); /* disarm and relax */ + unwear(rogue.armor); + un_put_on(rogue.left_ring); + un_put_on(rogue.right_ring); + + clear(); + mvaddstr(10, 11, "@ @ @@@ @ @ @ @ @ @@@ @ @ @"); + mvaddstr(11, 11, " @ @ @ @ @ @ @ @ @ @ @ @@ @ @"); + mvaddstr(12, 11, " @ @ @ @ @ @ @ @ @ @ @ @ @ @"); + mvaddstr(13, 11, " @ @ @ @ @ @ @ @ @ @ @ @@"); + mvaddstr(14, 11, " @ @@@ @@@ @@ @@ @@@ @ @ @"); + mvaddstr(17, 11, "Congratulations, you have been admitted to the"); + mvaddstr(18, 11, "Fighters' Guild. You return home, sell all your"); + mvaddstr(19, 11, "treasures at great profit and retire into comfort."); + message("", 0); + message("", 0); + id_all(); + sell_pack(); + put_scores((object *) 0, WIN); +} + +void +quit(from_intrpt) + boolean from_intrpt; +{ + char buf[128]; + int i, orow = 0, ocol = 0; + boolean mc = 0; + + md_ignore_signals(); + + if (from_intrpt) { + orow = rogue.row; + ocol = rogue.col; + + mc = msg_cleared; + + for (i = 0; i < DCOLS; i++) { + buf[i] = mvinch(0, i); + } + } + check_message(); + message("really quit?", 1); + if (rgetchar() != 'y') { + md_heed_signals(); + check_message(); + if (from_intrpt) { + for (i = 0; i < DCOLS; i++) { + mvaddch(0, i, buf[i]); + } + msg_cleared = mc; + move(orow, ocol); + refresh(); + } + return; + } + if (from_intrpt) { + clean_up(byebye_string); + } + check_message(); + killed_by((object *) 0, QUIT); +} + +static void +insert_score(scores, n_names, n_name, rank, n, monster, other) + char scores[][82]; + char n_names[][30]; + char *n_name; + int rank, n; + object *monster; +{ + int i; + char buf[128]; + + if (n > 0) { + for (i = n; i > rank; i--) { + if ((i < 10) && (i > 0)) { + (void) strcpy(scores[i], scores[i-1]); + (void) strcpy(n_names[i], n_names[i-1]); + } + } + } + sprintf(buf, "%2d %6d %s: ", rank+1, (int)rogue.gold, login_name); + + if (other) { + switch(other) { + case HYPOTHERMIA: + (void) strcat(buf, "died of hypothermia"); + break; + case STARVATION: + (void) strcat(buf, "died of starvation"); + break; + case POISON_DART: + (void) strcat(buf, "killed by a dart"); + break; + case QUIT: + (void) strcat(buf, "quit"); + break; + case WIN: + (void) strcat(buf, "a total winner"); + break; + case KFIRE: + (void) strcpy(buf, "killed by fire"); + break; + } + } else { + (void) strcat(buf, "killed by "); + if (is_vowel(m_names[monster->m_char - 'A'][0])) { + (void) strcat(buf, "an "); + } else { + (void) strcat(buf, "a "); + } + (void) strcat(buf, m_names[monster->m_char - 'A']); + } + sprintf(buf+strlen(buf), " on level %d ", max_level); + if ((other != WIN) && has_amulet()) { + (void) strcat(buf, "with amulet"); + } + for (i = strlen(buf); i < 79; i++) { + buf[i] = ' '; + } + buf[79] = 0; + (void) strcpy(scores[rank], buf); + (void) strcpy(n_names[rank], n_name); +} + +static void +nickize(buf, score, n_name) + char *buf, *score, *n_name; +{ + int i = 15, j; + + if (!n_name[0]) { + (void) strcpy(buf, score); + } else { + (void) strncpy(buf, score, 16); + + while (score[i] != ':') { + i++; + } + + (void) strcpy(buf+15, n_name); + j = strlen(buf); + + while (score[i]) { + buf[j++] = score[i++]; + } + buf[j] = 0; + buf[79] = 0; + } +} + +static void +sf_error() +{ + md_lock(0); + message("", 1); + clean_up("sorry, score file is out of order"); +} + +static int +name_cmp(s1, s2) + char *s1, *s2; +{ + int i = 0; + int r; + + while(s1[i] != ':') { + i++; + } + s1[i] = 0; + r = strcmp(s1, s2); + s1[i] = ':'; + return(r); +} + +void +put_scores(monster, other) + object *monster; + int other; +{ + int i, n, rank = 10, x, ne = 0, found_player = -1; + char scores[10][82]; + char n_names[10][30]; + char buf[128]; + FILE *fp; + long s; + boolean pause = score_only; + + md_lock(1); + + if ((fp = fopen(SCORE_FILE, "a+")) == NULL) { + message("cannot read/write/create score file", 0); + sf_error(); + } + rewind(fp); + (void) xxx(1); + + for (i = 0; i < 10; i++) { + if (((n = fread(scores[i], sizeof(char), 80, fp)) < 80) && (n != 0)) { + sf_error(); + } else if (n != 0) { + xxxx(scores[i], 80); + if ((n = fread(n_names[i], sizeof(char), 30, fp)) < 30) { + sf_error(); + } + xxxx(n_names[i], 30); + } else { + break; + } + ne++; + if ((!score_only) && (found_player == -1)) { + if (!name_cmp(scores[i]+15, login_name)) { + x = 5; + while (scores[i][x] == ' ') { + x++; + } + s = lget_number(scores[i] + x); + if (rogue.gold < s) { + score_only = 1; + } else { + found_player = i; + } + } + } + } + if (found_player != -1) { + ne--; + for (i = found_player; i < ne; i++) { + (void) strcpy(scores[i], scores[i+1]); + (void) strcpy(n_names[i], n_names[i+1]); + } + } + if (!score_only) { + for (i = 0; i < ne; i++) { + x = 5; + while (scores[i][x] == ' ') { + x++; + } + s = lget_number(scores[i] + x); + + if (rogue.gold >= s) { + rank = i; + break; + } + } + if (ne == 0) { + rank = 0; + } else if ((ne < 10) && (rank == 10)) { + rank = ne; + } + if (rank < 10) { + insert_score(scores, n_names, nick_name, rank, ne, monster, + other); + if (ne < 10) { + ne++; + } + } + rewind(fp); + } + + clear(); + mvaddstr(3, 30, "Top Ten Rogueists"); + mvaddstr(8, 0, "Rank Score Name"); + + md_ignore_signals(); + + (void) xxx(1); + + for (i = 0; i < ne; i++) { + if (i == rank) { + standout(); + } + if (i == 9) { + scores[i][0] = '1'; + scores[i][1] = '0'; + } else { + scores[i][0] = ' '; + scores[i][1] = i + '1'; + } + nickize(buf, scores[i], n_names[i]); + mvaddstr(i+10, 0, buf); + if (rank < 10) { + xxxx(scores[i], 80); + fwrite(scores[i], sizeof(char), 80, fp); + xxxx(n_names[i], 30); + fwrite(n_names[i], sizeof(char), 30, fp); + } + if (i == rank) { + standend(); + } + } + md_lock(0); + refresh(); + fclose(fp); + message("", 0); + if (pause) { + message("", 0); + } + clean_up(""); +} + +int +is_vowel(ch) + int ch; +{ + return( (ch == 'a') || + (ch == 'e') || + (ch == 'i') || + (ch == 'o') || + (ch == 'u') ); +} + +void +xxxx(buf, n) + char *buf; + int n; +{ + int i; + unsigned char c; + + for (i = 0; i < n; i++) { + + /* It does not matter if accuracy is lost during this assignment */ + c = (unsigned char) xxx(0); + + buf[i] ^= c; + } +} + +long +xxx(st) + boolean st; +{ + static long f, s; + long r; + + if (st) { + f = 37; + s = 7; + return(0L); + } + r = ((f * s) + 9337) % 8887; + f = s; + s = r; + return(r); +} diff --git a/src/games/rogue/spec_hit.c b/src/games/rogue/spec_hit.c new file mode 100644 index 0000000..7ad9a1d --- /dev/null +++ b/src/games/rogue/spec_hit.c @@ -0,0 +1,504 @@ +/* + * This source herein may be modified and/or distributed by anybody who + * so desires, with the following restrictions: + * 1.) No portion of this notice shall be removed. + * 2.) Credit shall not be taken for the creation of this source. + * 3.) This code is not to be traded, sold, or used for personal + * gain or profit. + */ +#include +#include "rogue.h" + +short less_hp = 0; +char being_held; + +static void +freeze(monster) + object *monster; +{ + int freeze_percent = 99; + int i, n; + + if (rand_percent(12)) { + return; + } + freeze_percent -= (rogue.str_current+(rogue.str_current / 2)); + freeze_percent -= ((rogue.exp + ring_exp) * 4); + freeze_percent -= (get_armor_class(rogue.armor) * 5); + freeze_percent -= (rogue.hp_max / 3); + + if (freeze_percent > 10) { + monster->m_flags |= FREEZING_ROGUE; + message("you are frozen", 1); + + n = get_rand(4, 8); + for (i = 0; i < n; i++) { + mv_mons(); + } + if (rand_percent(freeze_percent)) { + for (i = 0; i < 50; i++) { + mv_mons(); + } + killed_by((object *)0, HYPOTHERMIA); + } + message(you_can_move_again, 1); + monster->m_flags &= (~FREEZING_ROGUE); + } +} + +static void +disappear(monster) + object *monster; +{ + int row, col; + + row = monster->row; + col = monster->col; + + dungeon[row][col] &= ~MONSTER; + if (rogue_can_see(row, col)) { + mvaddch(row, col, get_dungeon_char(row, col)); + } + take_from_pack(monster, &level_monsters); + free_object(monster); + mon_disappeared = 1; +} + +static void +steal_gold(monster) + object *monster; +{ + int amount; + + if ((rogue.gold <= 0) || rand_percent(10)) { + return; + } + + amount = get_rand((cur_level * 10), (cur_level * 30)); + + if (amount > rogue.gold) { + amount = rogue.gold; + } + rogue.gold -= amount; + message("your purse feels lighter", 0); + print_stats(STAT_GOLD); + disappear(monster); +} + +static void +steal_item(monster) + object *monster; +{ + object *obj; + int i, n, t = 0; + char desc[80]; + boolean has_something = 0; + + if (rand_percent(15)) { + return; + } + obj = rogue.pack.next_object; + + if (!obj) { + goto DSPR; + } + while (obj) { + if (!(obj->in_use_flags & BEING_USED)) { + has_something = 1; + break; + } + obj = obj->next_object; + } + if (!has_something) { + goto DSPR; + } + n = get_rand(0, MAX_PACK_COUNT); + obj = rogue.pack.next_object; + + for (i = 0; i <= n; i++) { + obj = obj->next_object; + while ((!obj) || (obj->in_use_flags & BEING_USED)) { + if (!obj) { + obj = rogue.pack.next_object; + } else { + obj = obj->next_object; + } + } + } + (void) strcpy(desc, "she stole "); + if (obj->what_is != WEAPON) { + t = obj->quantity; + obj->quantity = 1; + } + get_desc(obj, desc+10); + message(desc, 0); + + obj->quantity = ((obj->what_is != WEAPON) ? t : 1); + + vanish(obj, 0, &rogue.pack); +DSPR: + disappear(monster); +} + +static void +sting(monster) + object *monster; +{ + int sting_chance = 35; + char msg[80]; + + if ((rogue.str_current <= 3) || sustain_strength) { + return; + } + sting_chance += (6 * (6 - get_armor_class(rogue.armor))); + + if ((rogue.exp + ring_exp) > 8) { + sting_chance -= (6 * ((rogue.exp + ring_exp) - 8)); + } + if (rand_percent(sting_chance)) { + sprintf(msg, "the %s's bite has weakened you", + mon_name(monster)); + message(msg, 0); + rogue.str_current--; + print_stats(STAT_STRENGTH); + } +} + +static void +drop_level() +{ + int hp; + + if (rand_percent(80) || (rogue.exp <= 5)) { + return; + } + rogue.exp_points = level_points[rogue.exp-2] - get_rand(9, 29); + rogue.exp -= 2; + hp = hp_raise(); + if ((rogue.hp_current -= hp) <= 0) { + rogue.hp_current = 1; + } + if ((rogue.hp_max -= hp) <= 0) { + rogue.hp_max = 1; + } + add_exp(1, 0); +} + +static void +drain_life() +{ + int n; + + if (rand_percent(60) || (rogue.hp_max <= 30) || (rogue.hp_current < 10)) { + return; + } + n = get_rand(1, 3); /* 1 Hp, 2 Str, 3 both */ + + if ((n != 2) || (!sustain_strength)) { + message("you feel weaker", 0); + } + if (n != 2) { + rogue.hp_max--; + rogue.hp_current--; + less_hp++; + } + if (n != 1) { + if ((rogue.str_current > 3) && (!sustain_strength)) { + rogue.str_current--; + if (coin_toss()) { + rogue.str_max--; + } + } + } + print_stats((STAT_STRENGTH | STAT_HP)); +} + +void +special_hit(monster) + object *monster; +{ + if ((monster->m_flags & CONFUSED) && rand_percent(66)) { + return; + } + if (monster->m_flags & RUSTS) { + rust(monster); + } + if ((monster->m_flags & HOLDS) && !levitate) { + being_held = 1; + } + if (monster->m_flags & FREEZES) { + freeze(monster); + } + if (monster->m_flags & STINGS) { + sting(monster); + } + if (monster->m_flags & DRAINS_LIFE) { + drain_life(); + } + if (monster->m_flags & DROPS_LEVEL) { + drop_level(); + } + if (monster->m_flags & STEALS_GOLD) { + steal_gold(monster); + } else if (monster->m_flags & STEALS_ITEM) { + steal_item(monster); + } +} + +void +rust(monster) + object *monster; +{ + if ((!rogue.armor) || (get_armor_class(rogue.armor) <= 1) || + (rogue.armor->which_kind == LEATHER)) { + return; + } + if ((rogue.armor->is_protected) || maintain_armor) { + if (monster && (!(monster->m_flags & RUST_VANISHED))) { + message("the rust vanishes instantly", 0); + monster->m_flags |= RUST_VANISHED; + } + } else { + rogue.armor->d_enchant--; + message("your armor weakens", 0); + print_stats(STAT_ARMOR); + } +} + +static int +try_to_cough(row, col, obj) + int row, col; + object *obj; +{ + if ((row < MIN_ROW) || (row > (DROWS-2)) || (col < 0) || (col>(DCOLS-1))) { + return(0); + } + if ((!(dungeon[row][col] & (OBJECT | STAIRS | TRAP))) && + (dungeon[row][col] & (TUNNEL | FLOOR | DOOR))) { + place_at(obj, row, col); + if (((row != rogue.row) || (col != rogue.col)) && + (!(dungeon[row][col] & MONSTER))) { + mvaddch(row, col, get_dungeon_char(row, col)); + } + return(1); + } + return(0); +} + +void +cough_up(monster) + object *monster; +{ + object *obj; + int row, col, i, n; + + if (cur_level < max_level) { + return; + } + + if (monster->m_flags & STEALS_GOLD) { + obj = alloc_object(); + obj->what_is = GOLD; + obj->quantity = get_rand((cur_level * 15), (cur_level * 30)); + } else { + if (!rand_percent((int) monster->drop_percent)) { + return; + } + obj = gr_object(); + } + row = monster->row; + col = monster->col; + + for (n = 0; n <= 5; n++) { + for (i = -n; i <= n; i++) { + if (try_to_cough(row+n, col+i, obj)) { + return; + } + if (try_to_cough(row-n, col+i, obj)) { + return; + } + } + for (i = -n; i <= n; i++) { + if (try_to_cough(row+i, col-n, obj)) { + return; + } + if (try_to_cough(row+i, col+n, obj)) { + return; + } + } + } + free_object(obj); +} + +static int +gold_at(row, col) + int row, col; +{ + if (dungeon[row][col] & OBJECT) { + object *obj; + + obj = object_at(&level_objects, row, col); + if (obj && (obj->what_is == GOLD)) { + return(1); + } + } + return(0); +} + +int +seek_gold(monster) + object *monster; +{ + int i, j, rn, s; + + rn = get_room_number(monster->row, monster->col); + if (rn < 0) { + return(0); + } + for (i = rooms[rn].top_row+1; i < rooms[rn].bottom_row; i++) { + for (j = rooms[rn].left_col+1; j < rooms[rn].right_col; j++) { + if ((gold_at(i, j)) && !(dungeon[i][j] & MONSTER)) { + monster->m_flags |= CAN_FLIT; + s = mon_can_go(monster, i, j); + monster->m_flags &= (~CAN_FLIT); + if (s) { + move_mon_to(monster, i, j); + monster->m_flags |= ASLEEP; + monster->m_flags &= (~(WAKENS | SEEKS_GOLD)); + return(1); + } + monster->m_flags &= (~SEEKS_GOLD); + monster->m_flags |= CAN_FLIT; + mv_1_monster(monster, i, j); + monster->m_flags &= (~CAN_FLIT); + monster->m_flags |= SEEKS_GOLD; + return(1); + } + } + } + return(0); +} + +void +check_gold_seeker(monster) + object *monster; +{ + monster->m_flags &= (~SEEKS_GOLD); +} + +int +check_imitator(monster) + object *monster; +{ + char msg[80]; + + if (monster->m_flags & IMITATES) { + wake_up(monster); + if (!blind) { + mvaddch(monster->row, monster->col, + get_dungeon_char(monster->row, monster->col)); + check_message(); + sprintf(msg, "wait, that's a %s!", mon_name(monster)); + message(msg, 1); + } + return(1); + } + return(0); +} + +int +imitating(row, col) + register int row, col; +{ + object *monster; + + if (dungeon[row][col] & MONSTER) { + monster = object_at(&level_monsters, row, col); + if (monster && (monster->m_flags & IMITATES)) { + return(1); + } + } + return(0); +} + +int +m_confuse(monster) + object *monster; +{ + char msg[80]; + + if (!rogue_can_see(monster->row, monster->col)) { + return(0); + } + if (rand_percent(45)) { + monster->m_flags &= (~CONFUSES); /* will not confuse the rogue */ + return(0); + } + if (rand_percent(55)) { + monster->m_flags &= (~CONFUSES); + sprintf(msg, "the gaze of the %s has confused you", mon_name(monster)); + message(msg, 1); + cnfs(); + return(1); + } + return(0); +} + +static int +get_dir(srow, scol, drow, dcol) + int srow, scol, drow, dcol; +{ + if (srow == drow) { + if (scol < dcol) { + return(RIGHT); + } else { + return(LEFT); + } + } + if (scol == dcol) { + if (srow < drow) { + return(DOWN); + } else { + return(UPWARD); + } + } + if ((srow > drow) && (scol > dcol)) { + return(UPLEFT); + } + if ((srow < drow) && (scol < dcol)) { + return(DOWNRIGHT); + } + if ((srow < drow) && (scol > dcol)) { + return(DOWNLEFT); + } + /*if ((srow > drow) && (scol < dcol)) {*/ + return(UPRIGHT); + /*}*/ +} + +int +flame_broil(monster) + object *monster; +{ + int row, col, dir; + + if ((!mon_sees(monster, rogue.row, rogue.col)) || coin_toss()) { + return(0); + } + row = rogue.row - monster->row; + col = rogue.col - monster->col; + if (row < 0) { + row = -row; + } + if (col < 0) { + col = -col; + } + if (((row != 0) && (col != 0) && (row != col)) || + ((row > 7) || (col > 7))) { + return(0); + } + dir = get_dir(monster->row, monster->col, row, col); + bounce(FIRE, dir, monster->row, monster->col, 0); + + return(1); +} diff --git a/src/games/rogue/throw.c b/src/games/rogue/throw.c new file mode 100644 index 0000000..565e53c --- /dev/null +++ b/src/games/rogue/throw.c @@ -0,0 +1,280 @@ +/* + * This source herein may be modified and/or distributed by anybody who + * so desires, with the following restrictions: + * 1.) No portion of this notice shall be removed. + * 2.) Credit shall not be taken for the creation of this source. + * 3.) This code is not to be traded, sold, or used for personal + * gain or profit. + */ +#include +#include "rogue.h" + +static void +flop_weapon(weapon, row, col) + object *weapon; + int row, col; +{ + object *new_weapon, *monster; + int i = 0; + char msg[80]; + boolean found = 0; + int mch, dch; + unsigned mon; + + while ((i < 9) && dungeon[row][col] & ~(FLOOR | TUNNEL | DOOR | MONSTER)) { + rand_around(i++, &row, &col); + if ((row > (DROWS-2)) || (row < MIN_ROW) || + (col > (DCOLS-1)) || (col < 0) || (!dungeon[row][col]) || + (dungeon[row][col] & ~(FLOOR | TUNNEL | DOOR | MONSTER))) { + continue; + } + found = 1; + break; + } + + if (found || (i == 0)) { + new_weapon = alloc_object(); + *new_weapon = *weapon; + new_weapon->in_use_flags = NOT_USED; + new_weapon->quantity = 1; + new_weapon->ichar = 'L'; + place_at(new_weapon, row, col); + if (rogue_can_see(row, col) && + ((row != rogue.row) || (col != rogue.col))) { + mon = dungeon[row][col] & MONSTER; + dungeon[row][col] &= (~MONSTER); + dch = get_dungeon_char(row, col); + if (mon) { + mch = mvinch(row, col); + monster = object_at(&level_monsters, row, col); + if (monster) { + monster->trail_char = dch; + } + if ((mch < 'A') || (mch > 'Z')) { + mvaddch(row, col, dch); + } + } else { + mvaddch(row, col, dch); + } + dungeon[row][col] |= mon; + } + } else { + int t; + + t = weapon->quantity; + weapon->quantity = 1; + sprintf(msg, "the %svanishes as it hits the ground", + name_of(weapon)); + weapon->quantity = t; + message(msg, 0); + } +} + +int +throw_at_monster(monster, weapon) + object *monster, *weapon; +{ + int damage, hit_chance; + int t; + + hit_chance = get_hit_chance(weapon); + damage = get_weapon_damage(weapon); + if ((weapon->which_kind == ARROW) && + (rogue.weapon && (rogue.weapon->which_kind == BOW))) { + damage += get_weapon_damage(rogue.weapon); + damage = ((damage * 2) / 3); + hit_chance += (hit_chance / 3); + } else if ((weapon->in_use_flags & BEING_WIELDED) && + ((weapon->which_kind == DAGGER) || + (weapon->which_kind == SHURIKEN) || + (weapon->which_kind == DART))) { + damage = ((damage * 3) / 2); + hit_chance += (hit_chance / 3); + } + t = weapon->quantity; + weapon->quantity = 1; + sprintf(hit_message, "the %s", name_of(weapon)); + weapon->quantity = t; + + if (!rand_percent(hit_chance)) { + (void) strcat(hit_message, "misses "); + return(0); + } + s_con_mon(monster); + (void) strcat(hit_message, "hit "); + (void) mon_damage(monster, damage); + return(1); +} + +static object * +get_thrown_at_monster(obj, dir, row, col) + object *obj; + int dir; + int *row, *col; +{ + int orow, ocol; + int i, ch; + + orow = *row; ocol = *col; + + ch = get_mask_char(obj->what_is); + + for (i = 0; i < 24; i++) { + get_dir_rc(dir, row, col, 0); + if ( (((*col <= 0) || (*col >= DCOLS-1)) || + (dungeon[*row][*col] == NOTHING)) || + ((dungeon[*row][*col] & (HORWALL | VERTWALL | HIDDEN)) && + (!(dungeon[*row][*col] & TRAP)))) { + *row = orow; + *col = ocol; + return(0); + } + if ((i != 0) && rogue_can_see(orow, ocol)) { + mvaddch(orow, ocol, get_dungeon_char(orow, ocol)); + } + if (rogue_can_see(*row, *col)) { + if (!(dungeon[*row][*col] & MONSTER)) { + mvaddch(*row, *col, ch); + } + refresh(); + } + orow = *row; ocol = *col; + if (dungeon[*row][*col] & MONSTER) { + if (!imitating(*row, *col)) { + return(object_at(&level_monsters, *row, *col)); + } + } + if (dungeon[*row][*col] & TUNNEL) { + i += 2; + } + } + return(0); +} + +void +throw() +{ + int wch, d; + boolean first_miss = 1; + object *weapon; + int dir, row, col; + object *monster; + + while (!is_direction(dir = rgetchar(), &d)) { + sound_bell(); + if (first_miss) { + message("direction? ", 0); + first_miss = 0; + } + } + check_message(); + if (dir == CANCEL) { + return; + } + if ((wch = pack_letter("throw what?", WEAPON)) == CANCEL) { + return; + } + check_message(); + + if (!(weapon = get_letter_object(wch))) { + message("no such item.", 0); + return; + } + if ((weapon->in_use_flags & BEING_USED) && weapon->is_cursed) { + message(curse_message, 0); + return; + } + row = rogue.row; col = rogue.col; + + if ((weapon->in_use_flags & BEING_WIELDED) && (weapon->quantity <= 1)) { + unwield(rogue.weapon); + } else if (weapon->in_use_flags & BEING_WORN) { + mv_aquatars(); + unwear(rogue.armor); + print_stats(STAT_ARMOR); + } else if (weapon->in_use_flags & ON_EITHER_HAND) { + un_put_on(weapon); + } + monster = get_thrown_at_monster(weapon, d, &row, &col); + mvaddch(rogue.row, rogue.col, rogue.fchar); + refresh(); + + if (rogue_can_see(row, col) && ((row != rogue.row) || (col != rogue.col))){ + mvaddch(row, col, get_dungeon_char(row, col)); + } + if (monster) { + wake_up(monster); + check_gold_seeker(monster); + + if (! throw_at_monster(monster, weapon)) { + flop_weapon(weapon, row, col); + } + } else { + flop_weapon(weapon, row, col); + } + vanish(weapon, 1, &rogue.pack); +} + +void +rand_around(i, r, c) + int i, *r, *c; +{ + static char pos[] = "\010\007\001\003\004\005\002\006\0"; + static int row, col; + int j; + + if (i == 0) { + int x, y, o, t; + + row = *r; + col = *c; + + o = get_rand(1, 8); + + for (j = 0; j < 5; j++) { + x = get_rand(0, 8); + y = (x + o) % 9; + t = pos[x]; + pos[x] = pos[y]; + pos[y] = t; + } + } + switch((int)pos[i]) { + case 0: + *r = row + 1; + *c = col + 1; + break; + case 1: + *r = row + 1; + *c = col - 1; + break; + case 2: + *r = row - 1; + *c = col + 1; + break; + case 3: + *r = row - 1; + *c = col - 1; + break; + case 4: + *r = row; + *c = col + 1; + break; + case 5: + *r = row + 1; + *c = col; + break; + case 6: + *r = row; + *c = col; + break; + case 7: + *r = row - 1; + *c = col; + break; + case 8: + *r = row; + *c = col - 1; + break; + } +} diff --git a/src/games/rogue/trap.c b/src/games/rogue/trap.c new file mode 100644 index 0000000..5eb628c --- /dev/null +++ b/src/games/rogue/trap.c @@ -0,0 +1,239 @@ +/* + * This source herein may be modified and/or distributed by anybody who + * so desires, with the following restrictions: + * 1.) No portion of this notice shall be removed. + * 2.) Credit shall not be taken for the creation of this source. + * 3.) This code is not to be traded, sold, or used for personal + * gain or profit. + */ +#include "rogue.h" + +trap traps[MAX_TRAPS]; +char trap_door = 0; +short bear_trap = 0; + +char *trap_strings[TRAPS * 2] = { + "trap door", + "you fell down a trap", + "bear trap", + "you are caught in a bear trap", + "teleport trap", + "teleport", + "poison dart trap", + "a small dart just hit you in the shoulder", + "sleeping gas trap", + "a strange white mist envelops you and you fall asleep", + "rust trap", + "a gush of water hits you on the head" +}; + +int +trap_at(row, col) + register int row, col; +{ + int i; + + for (i = 0; ((i < MAX_TRAPS) && (traps[i].trap_type != NO_TRAP)); i++) { + if ((traps[i].trap_row == row) && (traps[i].trap_col == col)) { + return(traps[i].trap_type); + } + } + return(NO_TRAP); +} + +void +trap_player(row, col) + int row, col; +{ + int t; + + t = trap_at(row, col); + if (t == NO_TRAP) { + return; + } + dungeon[row][col] &= (~HIDDEN); + if (rand_percent(rogue.exp + ring_exp)) { + message("the trap failed", 1); + return; + } + switch(t) { + case TRAP_DOOR: + trap_door = 1; + new_level_message = trap_strings[(t*2)+1]; + break; + case BEAR_TRAP: + message(trap_strings[(t*2)+1], 1); + bear_trap = get_rand(4, 7); + break; + case TELE_TRAP: + mvaddch(rogue.row, rogue.col, '^'); + tele(); + break; + case DART_TRAP: + message(trap_strings[(t*2)+1], 1); + rogue.hp_current -= get_damage("1d6", 1); + if (rogue.hp_current <= 0) { + rogue.hp_current = 0; + } + if ((!sustain_strength) && rand_percent(40) && + (rogue.str_current >= 3)) { + rogue.str_current--; + } + print_stats(STAT_HP | STAT_STRENGTH); + if (rogue.hp_current <= 0) { + killed_by((object *) 0, POISON_DART); + } + break; + case SLEEPING_GAS_TRAP: + message(trap_strings[(t*2)+1], 1); + take_a_nap(); + break; + case RUST_TRAP: + message(trap_strings[(t*2)+1], 1); + rust((object *) 0); + break; + } +} + +void +add_traps() +{ + int i, n, tries = 0; + int row, col; + + if (cur_level <= 2) { + n = 0; + } else if (cur_level <= 7) { + n = get_rand(0, 2); + } else if (cur_level <= 11) { + n = get_rand(1, 2); + } else if (cur_level <= 16) { + n = get_rand(2, 3); + } else if (cur_level <= 21) { + n = get_rand(2, 4); + } else if (cur_level <= (AMULET_LEVEL + 2)) { + n = get_rand(3, 5); + } else { + n = get_rand(5, MAX_TRAPS); + } + for (i = 0; i < n; i++) { + traps[i].trap_type = get_rand(0, (TRAPS - 1)); + + if ((i == 0) && (party_room != NO_ROOM)) { + do { + row = get_rand((rooms[party_room].top_row+1), + (rooms[party_room].bottom_row-1)); + col = get_rand((rooms[party_room].left_col+1), + (rooms[party_room].right_col-1)); + tries++; + } while (((dungeon[row][col] & (OBJECT|STAIRS|TRAP|TUNNEL)) || + (dungeon[row][col] == NOTHING)) && (tries < 15)); + if (tries >= 15) { + gr_row_col(&row, &col, (FLOOR | MONSTER)); + } + } else { + gr_row_col(&row, &col, (FLOOR | MONSTER)); + } + traps[i].trap_row = row; + traps[i].trap_col = col; + dungeon[row][col] |= (TRAP | HIDDEN); + } +} + +void +id_trap() +{ + int dir, row, col, d, t; + + message("direction? ", 0); + + while (!is_direction(dir = rgetchar(), &d)) { + sound_bell(); + } + check_message(); + + if (dir == CANCEL) { + return; + } + row = rogue.row; + col = rogue.col; + + get_dir_rc(d, &row, &col, 0); + + if ((dungeon[row][col] & TRAP) && (!(dungeon[row][col] & HIDDEN))) { + t = trap_at(row, col); + message(trap_strings[t*2], 0); + } else { + message("no trap there", 0); + } +} + +void +show_traps() +{ + int i, j; + + for (i = 0; i < DROWS; i++) { + for (j = 0; j < DCOLS; j++) { + if (dungeon[i][j] & TRAP) { + mvaddch(i, j, '^'); + } + } + } +} + +void +search(n, is_auto) + int n; + boolean is_auto; +{ + int s, i, j, row, col, t; + int shown = 0, found = 0; + static boolean reg_search; + + for (i = -1; i <= 1; i++) { + for (j = -1; j <= 1; j++) { + row = rogue.row + i; + col = rogue.col + j; + if ((row < MIN_ROW) || (row >= (DROWS-1)) || + (col < 0) || (col >= DCOLS)) { + continue; + } + if (dungeon[row][col] & HIDDEN) { + found++; + } + } + } + for (s = 0; s < n; s++) { + for (i = -1; i <= 1; i++) { + for (j = -1; j <= 1; j++) { + row = rogue.row + i; + col = rogue.col + j ; + if ((row < MIN_ROW) || (row >= (DROWS-1)) || + (col < 0) || (col >= DCOLS)) { + continue; + } + if (dungeon[row][col] & HIDDEN) { + if (rand_percent(17 + (rogue.exp + ring_exp))) { + dungeon[row][col] &= (~HIDDEN); + if ((!blind) && ((row != rogue.row) || + (col != rogue.col))) { + mvaddch(row, col, get_dungeon_char(row, col)); + } + shown++; + if (dungeon[row][col] & TRAP) { + t = trap_at(row, col); + message(trap_strings[t*2], 1); + } + } + } + if (((shown == found) && (found > 0)) || interrupted) { + return; + } + } + } + if ((!is_auto) && (reg_search = !reg_search)) { + (void) reg_move(); + } + } +} diff --git a/src/games/rogue/use.c b/src/games/rogue/use.c new file mode 100644 index 0000000..ab8b8ea --- /dev/null +++ b/src/games/rogue/use.c @@ -0,0 +1,582 @@ +/* + * This source herein may be modified and/or distributed by anybody who + * so desires, with the following restrictions: + * 1.) No portion of this notice shall be removed. + * 2.) Credit shall not be taken for the creation of this source. + * 3.) This code is not to be traded, sold, or used for personal + * gain or profit. + */ +#include "rogue.h" + +short halluc = 0; +short blind = 0; +short confused = 0; +short levitate = 0; +short haste_self = 0; +char see_invisible = 0; +short extra_hp = 0; +char detect_monster = 0; +char con_mon = 0; +char *strange_feeling = "you have a strange feeling for a moment, then it passes"; + +static void +potion_heal(extra) +{ + float ratio; + int add; + + rogue.hp_current += rogue.exp; + + ratio = ((float)rogue.hp_current) / rogue.hp_max; + + if (ratio >= 1.00) { + rogue.hp_max += (extra ? 2 : 1); + extra_hp += (extra ? 2 : 1); + rogue.hp_current = rogue.hp_max; + } else if (ratio >= 0.90) { + rogue.hp_max += (extra ? 1 : 0); + extra_hp += (extra ? 1 : 0); + rogue.hp_current = rogue.hp_max; + } else { + if (ratio < 0.33) { + ratio = 0.33; + } + if (extra) { + ratio += ratio; + } + add = (int) (ratio * ((float)rogue.hp_max - rogue.hp_current)); + rogue.hp_current += add; + if (rogue.hp_current > rogue.hp_max) { + rogue.hp_current = rogue.hp_max; + } + } + if (blind) { + unblind(); + } + if (confused && extra) { + unconfuse(); + } else if (confused) { + confused = (confused / 2) + 1; + } + if (halluc && extra) { + unhallucinate(); + } else if (halluc) { + halluc = (halluc / 2) + 1; + } +} + +static void +go_blind() +{ + int i, j; + + if (!blind) { + message("a cloak of darkness falls around you", 0); + } + blind += get_rand(500, 800); + + if (detect_monster) { + object *monster; + + monster = level_monsters.next_monster; + + while (monster) { + mvaddch(monster->row, monster->col, monster->trail_char); + monster = monster->next_monster; + } + } + if (cur_room >= 0) { + for (i = rooms[cur_room].top_row + 1; + i < rooms[cur_room].bottom_row; i++) { + for (j = rooms[cur_room].left_col + 1; + j < rooms[cur_room].right_col; j++) { + mvaddch(i, j, ' '); + } + } + } + mvaddch(rogue.row, rogue.col, rogue.fchar); +} + +void +quaff() +{ + int ch; + char buf[80]; + object *obj; + + ch = pack_letter("quaff what?", POTION); + + if (ch == CANCEL) { + return; + } + if (!(obj = get_letter_object(ch))) { + message("no such item.", 0); + return; + } + if (obj->what_is != POTION) { + message("you can't drink that", 0); + return; + } + switch(obj->which_kind) { + case INCREASE_STRENGTH: + message("you feel stronger now, what bulging muscles!", + 0); + rogue.str_current++; + if (rogue.str_current > rogue.str_max) { + rogue.str_max = rogue.str_current; + } + break; + case RESTORE_STRENGTH: + rogue.str_current = rogue.str_max; + message("this tastes great, you feel warm all over", 0); + break; + case HEALING: + message("you begin to feel better", 0); + potion_heal(0); + break; + case EXTRA_HEALING: + message("you begin to feel much better", 0); + potion_heal(1); + break; + case POISON: + if (!sustain_strength) { + rogue.str_current -= get_rand(1, 3); + if (rogue.str_current < 1) { + rogue.str_current = 1; + } + } + message("you feel very sick now", 0); + if (halluc) { + unhallucinate(); + } + break; + case RAISE_LEVEL: + rogue.exp_points = level_points[rogue.exp - 1]; + message("you suddenly feel much more skillful", 0); + add_exp(1, 1); + break; + case BLINDNESS: + go_blind(); + break; + case HALLUCINATION: + message("oh wow, everything seems so cosmic", 0); + halluc += get_rand(500, 800); + break; + case DETECT_MONSTER: + show_monsters(); + if (!(level_monsters.next_monster)) { + message(strange_feeling, 0); + } + break; + case DETECT_OBJECTS: + if (level_objects.next_object) { + if (!blind) { + show_objects(); + } + } else { + message(strange_feeling, 0); + } + break; + case CONFUSION: + message((halluc ? "what a trippy feeling" : + "you feel confused"), 0); + cnfs(); + break; + case LEVITATION: + message("you start to float in the air", 0); + levitate += get_rand(15, 30); + being_held = bear_trap = 0; + break; + case HASTE_SELF: + message("you feel yourself moving much faster", 0); + haste_self += get_rand(11, 21); + if (!(haste_self % 2)) { + haste_self++; + } + break; + case SEE_INVISIBLE: + sprintf(buf, "hmm, this potion tastes like %sjuice", fruit); + message(buf, 0); + if (blind) { + unblind(); + } + see_invisible = 1; + relight(); + break; + } + print_stats((STAT_STRENGTH | STAT_HP)); + if (id_potions[obj->which_kind].id_status != CALLED) { + id_potions[obj->which_kind].id_status = IDENTIFIED; + } + vanish(obj, 1, &rogue.pack); +} + +static void +idntfy() +{ + int ch; + object *obj; + struct id *id_table; + char desc[DCOLS]; +AGAIN: + ch = pack_letter("what would you like to identify?", ALL_OBJECTS); + + if (ch == CANCEL) { + return; + } + if (!(obj = get_letter_object(ch))) { + message("no such item, try again", 0); + message("", 0); + check_message(); + goto AGAIN; + } + obj->identified = 1; + if (obj->what_is & (SCROL | POTION | WEAPON | ARMOR | WAND | RING)) { + id_table = get_id_table(obj); + id_table[obj->which_kind].id_status = IDENTIFIED; + } + get_desc(obj, desc); + message(desc, 0); +} + +void +hold_monster() +{ + int i, j; + int mcount = 0; + object *monster; + int row, col; + + for (i = -2; i <= 2; i++) { + for (j = -2; j <= 2; j++) { + row = rogue.row + i; + col = rogue.col + j; + if ((row < MIN_ROW) || (row > (DROWS-2)) || (col < 0) || + (col > (DCOLS-1))) { + continue; + } + if (dungeon[row][col] & MONSTER) { + monster = object_at(&level_monsters, row, col); + monster->m_flags |= ASLEEP; + monster->m_flags &= (~WAKENS); + mcount++; + } + } + } + if (mcount == 0) { + message("you feel a strange sense of loss", 0); + } else if (mcount == 1) { + message("the monster freezes", 0); + } else { + message("the monsters around you freeze", 0); + } +} + +static void +uncurse_all() +{ + object *obj; + + obj = rogue.pack.next_object; + + while (obj) { + obj->is_cursed = 0; + obj = obj->next_object; + } +} + +static char * +get_ench_color() +{ + if (halluc) { + return(id_potions[get_rand(0, POTIONS-1)].title); + } else if (con_mon) { + return("red "); + } + return("blue "); +} + +void +read_scroll() +{ + int ch; + object *obj; + char msg[DCOLS]; + + ch = pack_letter("read what?", SCROL); + + if (ch == CANCEL) { + return; + } + if (!(obj = get_letter_object(ch))) { + message("no such item.", 0); + return; + } + if (obj->what_is != SCROL) { + message("you can't read that", 0); + return; + } + switch(obj->which_kind) { + case SCARE_MONSTER: + message("you hear a maniacal laughter in the distance", + 0); + break; + case HOLD_MONSTER: + hold_monster(); + break; + case ENCH_WEAPON: + if (rogue.weapon) { + if (rogue.weapon->what_is == WEAPON) { + sprintf(msg, "your %sglow%s %sfor a moment", + name_of(rogue.weapon), + ((rogue.weapon->quantity <= 1) ? "s" : ""), + get_ench_color()); + message(msg, 0); + if (coin_toss()) { + rogue.weapon->hit_enchant++; + } else { + rogue.weapon->d_enchant++; + } + } + rogue.weapon->is_cursed = 0; + } else { + message("your hands tingle", 0); + } + break; + case ENCH_ARMOR: + if (rogue.armor) { + sprintf(msg, "your armor glows %sfor a moment", + get_ench_color()); + message(msg, 0); + rogue.armor->d_enchant++; + rogue.armor->is_cursed = 0; + print_stats(STAT_ARMOR); + } else { + message("your skin crawls", 0); + } + break; + case IDENTIFY: + message("this is a scroll of identify", 0); + obj->identified = 1; + id_scrolls[obj->which_kind].id_status = IDENTIFIED; + idntfy(); + break; + case TELEPORT: + tele(); + break; + case SLEEP: + message("you fall asleep", 0); + take_a_nap(); + break; + case PROTECT_ARMOR: + if (rogue.armor) { + message( "your armor is covered by a shimmering gold shield",0); + rogue.armor->is_protected = 1; + rogue.armor->is_cursed = 0; + } else { + message("your acne seems to have disappeared", 0); + } + break; + case REMOVE_CURSE: + message((!halluc) ? + "you feel as though someone is watching over you" : + "you feel in touch with the universal oneness", 0); + uncurse_all(); + break; + case CREATE_MONSTER: + create_monster(); + break; + case AGGRAVATE_MONSTER: + aggravate(); + break; + case MAGIC_MAPPING: + message("this scroll seems to have a map on it", 0); + draw_magic_map(); + break; + case CON_MON: + con_mon = 1; + sprintf(msg, "your hands glow %sfor a moment", get_ench_color()); + message(msg, 0); + break; + } + if (id_scrolls[obj->which_kind].id_status != CALLED) { + id_scrolls[obj->which_kind].id_status = IDENTIFIED; + } + vanish(obj, (obj->which_kind != SLEEP), &rogue.pack); +} + +/* vanish() does NOT handle a quiver of weapons with more than one + * arrow (or whatever) in the quiver. It will only decrement the count. + */ +void +vanish(obj, rm, pack) + object *obj; + int rm; + object *pack; +{ + if (obj->quantity > 1) { + obj->quantity--; + } else { + if (obj->in_use_flags & BEING_WIELDED) { + unwield(obj); + } else if (obj->in_use_flags & BEING_WORN) { + unwear(obj); + } else if (obj->in_use_flags & ON_EITHER_HAND) { + un_put_on(obj); + } + take_from_pack(obj, pack); + free_object(obj); + } + if (rm) { + (void) reg_move(); + } +} + +void +eat() +{ + int ch; + int moves; + object *obj; + char buf[70]; + + ch = pack_letter("eat what?", FOOD); + + if (ch == CANCEL) { + return; + } + if (!(obj = get_letter_object(ch))) { + message("no such item.", 0); + return; + } + if (obj->what_is != FOOD) { + message("you can't eat that", 0); + return; + } + if ((obj->which_kind == FRUIT) || rand_percent(60)) { + moves = get_rand(950, 1150); + if (obj->which_kind == RATION) { + message("yum, that tasted good", 0); + } else { + sprintf(buf, "my, that was a yummy %s", fruit); + message(buf, 0); + } + } else { + moves = get_rand(750, 950); + message("yuk, that food tasted awful", 0); + add_exp(2, 1); + } + rogue.moves_left /= 3; + rogue.moves_left += moves; + hunger_str[0] = 0; + print_stats(STAT_HUNGER); + + vanish(obj, 1, &rogue.pack); +} + +void +tele() +{ + mvaddch(rogue.row, rogue.col, get_dungeon_char(rogue.row, rogue.col)); + + if (cur_room >= 0) { + darken_room(cur_room); + } + put_player(get_room_number(rogue.row, rogue.col)); + being_held = 0; + bear_trap = 0; +} + +void +hallucinate() +{ + object *obj, *monster; + int ch; + + if (blind) return; + + obj = level_objects.next_object; + + while (obj) { + ch = mvinch(obj->row, obj->col); + if (((ch < 'A') || (ch > 'Z')) && + ((obj->row != rogue.row) || (obj->col != rogue.col))) + if ((ch != ' ') && (ch != '.') && (ch != '#') && (ch != '+')) { + addch(gr_obj_char()); + } + obj = obj->next_object; + } + monster = level_monsters.next_monster; + + while (monster) { + ch = mvinch(monster->row, monster->col); + if ((ch >= 'A') && (ch <= 'Z')) { + addch(get_rand('A', 'Z')); + } + monster = monster->next_monster; + } +} + +void +unhallucinate() +{ + halluc = 0; + relight(); + message("everything looks SO boring now", 1); +} + +void +unblind() +{ + blind = 0; + message("the veil of darkness lifts", 1); + relight(); + if (halluc) { + hallucinate(); + } + if (detect_monster) { + show_monsters(); + } +} + +void +relight() +{ + if (cur_room == PASSAGE) { + light_passage(rogue.row, rogue.col); + } else { + light_up_room(cur_room); + } + mvaddch(rogue.row, rogue.col, rogue.fchar); +} + +void +take_a_nap() +{ + int i; + + i = get_rand(2, 5); + md_sleep(1); + + while (i--) { + mv_mons(); + } + md_sleep(1); + message(you_can_move_again, 0); +} + +void +cnfs() +{ + confused += get_rand(12, 22); +} + +void +unconfuse() +{ + char msg[80]; + + confused = 0; + sprintf(msg, "you feel less %s now", (halluc ? "trippy" : "confused")); + message(msg, 1); +} diff --git a/src/games/rogue/zap.c b/src/games/rogue/zap.c new file mode 100644 index 0000000..1726a72 --- /dev/null +++ b/src/games/rogue/zap.c @@ -0,0 +1,365 @@ +/* + * This source herein may be modified and/or distributed by anybody who + * so desires, with the following restrictions: + * 1.) No portion of this notice shall be removed. + * 2.) Credit shall not be taken for the creation of this source. + * 3.) This code is not to be traded, sold, or used for personal + * gain or profit. + */ +#include +#include "rogue.h" + +char wizard = 0; + +static void +wdrain_life(monster) + object *monster; +{ + int hp; + object *lmon, *nm; + + hp = rogue.hp_current / 3; + rogue.hp_current = (rogue.hp_current + 1) / 2; + + if (cur_room >= 0) { + lmon = level_monsters.next_monster; + while (lmon) { + nm = lmon->next_monster; + if (get_room_number(lmon->row, lmon->col) == cur_room) { + wake_up(lmon); + (void) mon_damage(lmon, hp); + } + lmon = nm; + } + } else { + if (monster) { + wake_up(monster); + (void) mon_damage(monster, hp); + } + } + print_stats(STAT_HP); + relight(); +} + +static void +tele_away(monster) + object *monster; +{ + int row, col; + + if (monster->m_flags & HOLDS) { + being_held = 0; + } + gr_row_col(&row, &col, (FLOOR | TUNNEL | STAIRS | OBJECT)); + mvaddch(monster->row, monster->col, monster->trail_char); + dungeon[monster->row][monster->col] &= ~MONSTER; + monster->row = row; monster->col = col; + dungeon[row][col] |= MONSTER; + monster->trail_char = mvinch(row, col); + if (detect_monster || rogue_can_see(row, col)) { + mvaddch(row, col, gmc(monster)); + } +} + +static void +zap_monster(monster, kind) + object *monster; + unsigned kind; +{ + int row, col; + object *nm; + int tc; + + row = monster->row; + col = monster->col; + + switch(kind) { + case SLOW_MONSTER: + if (monster->m_flags & HASTED) { + monster->m_flags &= (~HASTED); + } else { + monster->slowed_toggle = 0; + monster->m_flags |= SLOWED; + } + break; + case HASTE_MONSTER: + if (monster->m_flags & SLOWED) { + monster->m_flags &= (~SLOWED); + } else { + monster->m_flags |= HASTED; + } + break; + case TELE_AWAY: + tele_away(monster); + break; + case INVISIBILITY: + monster->m_flags |= INVISIBLE; + break; + case POLYMORPH: + if (monster->m_flags & HOLDS) { + being_held = 0; + } + nm = monster->next_monster; + tc = monster->trail_char; + (void) gr_monster(monster, get_rand(0, MONSTERS-1)); + monster->row = row; + monster->col = col; + monster->next_monster = nm; + monster->trail_char = tc; + if (!(monster->m_flags & IMITATES)) { + wake_up(monster); + } + break; + case MAGIC_MISSILE: + rogue_hit(monster, 1); + break; + case CANCELLATION: + if (monster->m_flags & HOLDS) { + being_held = 0; + } + if (monster->m_flags & STEALS_ITEM) { + monster->drop_percent = 0; + } + monster->m_flags &= (~(FLIES | FLITS | SPECIAL_HIT | INVISIBLE | + FLAMES | IMITATES | CONFUSES | SEEKS_GOLD | HOLDS)); + break; + case DO_NOTHING: + message("nothing happens", 0); + break; + } +} + +static object * +get_zapped_monster(dir, row, col) + int dir; + int *row, *col; +{ + int orow, ocol; + + for (;;) { + orow = *row; ocol = *col; + get_dir_rc(dir, row, col, 0); + if (((*row == orow) && (*col == ocol)) || + (dungeon[*row][*col] & (HORWALL | VERTWALL)) || + (dungeon[*row][*col] == NOTHING)) { + return(0); + } + if (dungeon[*row][*col] & MONSTER) { + if (!imitating(*row, *col)) { + return(object_at(&level_monsters, *row, *col)); + } + } + } +} + +void +zapp() +{ + int wch; + boolean first_miss = 1; + object *wand; + int dir, d, row, col; + object *monster; + + while (!is_direction(dir = rgetchar(), &d)) { + sound_bell(); + if (first_miss) { + message("direction? ", 0); + first_miss = 0; + } + } + check_message(); + if (dir == CANCEL) { + return; + } + if ((wch = pack_letter("zap with what?", WAND)) == CANCEL) { + return; + } + check_message(); + + if (!(wand = get_letter_object(wch))) { + message("no such item.", 0); + return; + } + if (wand->what_is != WAND) { + message("you can't zap with that", 0); + return; + } + if (wand->class <= 0) { + message("nothing happens", 0); + } else { + wand->class--; + row = rogue.row; col = rogue.col; + if ((wand->which_kind == COLD) || (wand->which_kind == FIRE)) { + bounce((int) wand->which_kind, d, row, col, 0); + } else { + monster = get_zapped_monster(d, &row, &col); + if (wand->which_kind == DRAIN_LIFE) { + wdrain_life(monster); + } else if (monster) { + wake_up(monster); + s_con_mon(monster); + zap_monster(monster, wand->which_kind); + relight(); + } + } + } + (void) reg_move(); +} + +void +wizardize() +{ + char buf[100]; + + if (wizard) { + wizard = 0; + message("not wizard anymore", 0); + } else { + if (get_input_line("wizard's password:", "", buf, "", 0, 0)) { + (void) xxx(1); + xxxx(buf, strlen(buf)); + if (!strncmp(buf, "\247\104\126\272\115\243\027", 7)) { + wizard = 1; + score_only = 1; + message("Welcome, mighty wizard!", 0); + } else { + message("sorry", 0); + } + } + } +} + +void +bounce(ball, dir, row, col, r) + int ball, dir, row, col, r; +{ + int orow, ocol; + char buf[DCOLS], *s; + int i, ch, new_dir = -1, damage; + static int btime; + + if (++r == 1) { + btime = get_rand(3, 6); + } else if (r > btime) { + return; + } + + if (ball == FIRE) { + s = "fire"; + } else { + s = "ice"; + } + if (r > 1) { + sprintf(buf, "the %s bounces", s); + message(buf, 0); + } + orow = row; + ocol = col; + do { + ch = mvinch(orow, ocol); + standout(); + mvaddch(orow, ocol, ch); + get_dir_rc(dir, &orow, &ocol, 1); + } while (!( (ocol <= 0) || + (ocol >= DCOLS-1) || + (dungeon[orow][ocol] == NOTHING) || + (dungeon[orow][ocol] & MONSTER) || + (dungeon[orow][ocol] & (HORWALL | VERTWALL)) || + ((orow == rogue.row) && (ocol == rogue.col)))); + standend(); + refresh(); + do { + orow = row; + ocol = col; + ch = mvinch(row, col); + mvaddch(row, col, ch); + get_dir_rc(dir, &row, &col, 1); + } while (!( (col <= 0) || + (col >= DCOLS-1) || + (dungeon[row][col] == NOTHING) || + (dungeon[row][col] & MONSTER) || + (dungeon[row][col] & (HORWALL | VERTWALL)) || + ((row == rogue.row) && (col == rogue.col)))); + + if (dungeon[row][col] & MONSTER) { + object *monster; + + monster = object_at(&level_monsters, row, col); + + wake_up(monster); + if (rand_percent(33)) { + sprintf(buf, "the %s misses the %s", s, mon_name(monster)); + message(buf, 0); + goto ND; + } + if (ball == FIRE) { + if (!(monster->m_flags & RUSTS)) { + if (monster->m_flags & FREEZES) { + damage = monster->hp_to_kill; + } else if (monster->m_flags & FLAMES) { + damage = (monster->hp_to_kill / 10) + 1; + } else { + damage = get_rand((rogue.hp_current / 3), rogue.hp_max); + } + } else { + damage = (monster->hp_to_kill / 2) + 1; + } + sprintf(buf, "the %s hits the %s", s, mon_name(monster)); + message(buf, 0); + (void) mon_damage(monster, damage); + } else { + damage = -1; + if (!(monster->m_flags & FREEZES)) { + if (rand_percent(33)) { + message("the monster is frozen", 0); + monster->m_flags |= (ASLEEP | NAPPING); + monster->nap_length = get_rand(3, 6); + } else { + damage = rogue.hp_current / 4; + } + } else { + damage = -2; + } + if (damage != -1) { + sprintf(buf, "the %s hits the %s", s, mon_name(monster)); + message(buf, 0); + (void) mon_damage(monster, damage); + } + } + } else if ((row == rogue.row) && (col == rogue.col)) { + if (rand_percent(10 + (3 * get_armor_class(rogue.armor)))) { + sprintf(buf, "the %s misses", s); + message(buf, 0); + goto ND; + } else { + damage = get_rand(3, (3 * rogue.exp)); + if (ball == FIRE) { + damage = (damage * 3) / 2; + damage -= get_armor_class(rogue.armor); + } + sprintf(buf, "the %s hits", s); + rogue_damage(damage, (object *) 0, + ((ball == FIRE) ? KFIRE : HYPOTHERMIA)); + message(buf, 0); + } + } else { + int nrow, ncol; + +ND: for (i = 0; i < 10; i++) { + dir = get_rand(0, DIRS-1); + nrow = orow; + ncol = ocol; + get_dir_rc(dir, &nrow, &ncol, 1); + if (((ncol >= 0) && (ncol <= DCOLS-1)) && + (dungeon[nrow][ncol] != NOTHING) && + (!(dungeon[nrow][ncol] & (VERTWALL | HORWALL)))) { + new_dir = dir; + break; + } + } + if (new_dir != -1) { + bounce(ball, new_dir, orow, ocol, r); + } + } +} diff --git a/src/games/sail/Makefile b/src/games/sail/Makefile new file mode 100644 index 0000000..ef28867 --- /dev/null +++ b/src/games/sail/Makefile @@ -0,0 +1,35 @@ +# +# Copyright (c) 1980 Regents of the University of California. +# All rights reserved. The Berkeley software License Agreement +# specifies the terms and conditions for redistribution. +# +TOPSRC = $(shell cd ../../..; pwd) +include $(TOPSRC)/target.mk +#include $(TOPSRC)/cross.mk + +CFLAGS += -Os -mips16 -Werror -Wall + +OBJS = main.o pl_main.o pl_1.o pl_2.o pl_3.o pl_4.o pl_5.o pl_6.o pl_7.o \ + dr_main.o dr_1.o dr_2.o dr_3.o dr_4.o dr_5.o lo_main.o \ + assorted.o game.o globals.o misc.o parties.o sync.o version.o doprnt.o +LIBS = -lcurses -ltermcap +MAN = sail.0 +MANSRC = sail.6 + +all: sail $(MAN) + +sail: ${OBJS} + ${CC} ${LDFLAGS} -o sail.elf ${OBJS} ${LIBS} + ${OBJDUMP} -S sail.elf > sail.dis + ${SIZE} sail.elf + ${ELF2AOUT} sail.elf $@ && rm sail.elf + +${MAN}: ${MANSRC} + ${MANROFF} $< > $@ + +clean: + rm -f *.o *.0 *.elf ${MAN} sail *.elf *.dis tags *~ + +install: all + install sail $(DESTDIR)/games/ + cp ${MAN} $(DESTDIR)/share/man/cat6/ diff --git a/src/games/sail/Makefile-linux b/src/games/sail/Makefile-linux new file mode 100644 index 0000000..a78f602 --- /dev/null +++ b/src/games/sail/Makefile-linux @@ -0,0 +1,21 @@ +# +# Copyright (c) 1980 Regents of the University of California. +# All rights reserved. The Berkeley software License Agreement +# specifies the terms and conditions for redistribution. +# +# @(#)Makefile 5.2 (Berkeley) 9/17/85 +# +CFLAGS = -O -Werror -Wall + +OBJS = main.o pl_main.o pl_1.o pl_2.o pl_3.o pl_4.o pl_5.o pl_6.o pl_7.o \ + dr_main.o dr_1.o dr_2.o dr_3.o dr_4.o dr_5.o lo_main.o \ + assorted.o game.o globals.o misc.o parties.o sync.o version.o +LIBS = -lcurses -ltermcap + +all: sail sail.0 + +sail: $(OBJS) + $(CC) -o sail $(OBJS) $(LIBS) + +clean: + rm -f *.o *~ sail sail.0 diff --git a/src/games/sail/assorted.c b/src/games/sail/assorted.c new file mode 100644 index 0000000..4448782 --- /dev/null +++ b/src/games/sail/assorted.c @@ -0,0 +1,245 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "externs.h" + +static void +strike(ship, from) + register struct ship *ship, *from; +{ + int points; + + if (ship->file->struck) + return; + Write(W_STRUCK, ship, 0, 1, 0, 0, 0); + points = ship->specs->pts + from->file->points; + Write(W_POINTS, from, 0, points, 0, 0, 0); + unboard(ship, ship, 0); /* all offense */ + unboard(ship, ship, 1); /* all defense */ + switch (die()) { + case 3: + case 4: /* ship may sink */ + Write(W_SINK, ship, 0, 1, 0, 0, 0); + break; + case 5: + case 6: /* ship may explode */ + Write(W_EXPLODE, ship, 0, 1, 0, 0, 0); + break; + } + Write(W_SIGNAL, ship, 1, (int) "striking her colours!", 0, 0, 0); +} + +void +table(rig, shot, hittable, on, from, roll) + struct ship *on, *from; + int rig, shot, hittable, roll; +{ + register int hhits = 0, chits = 0, ghits = 0, rhits = 0; + int Ghit = 0, Hhit = 0, Rhit = 0, Chit = 0; + int guns, car, pc, hull; + int crew[3]; + register int n; + int rigg[4]; + char *message = 0; + struct Tables *tp; + + pc = on->file->pcrew; + hull = on->specs->hull; + crew[0] = on->specs->crew1; + crew[1] = on->specs->crew2; + crew[2] = on->specs->crew3; + rigg[0] = on->specs->rig1; + rigg[1] = on->specs->rig2; + rigg[2] = on->specs->rig3; + rigg[3] = on->specs->rig4; + if (shot == L_GRAPE) + Chit = chits = hittable; + else { + tp = &(rig ? RigTable : HullTable)[hittable][roll-1]; + Chit = chits = tp->C; + Rhit = rhits = tp->R; + Hhit = hhits = tp->H; + Ghit = ghits = tp->G; + if (on->file->FS) + rhits *= 2; + if (shot == L_CHAIN) { + Ghit = ghits = 0; + Hhit = hhits = 0; + } + } + if (on->file->captured != 0) { + pc -= (chits + 1) / 2; + chits /= 2; + } + for (n = 0; n < 3; n++) + if (chits > crew[n]) { + chits -= crew[n]; + crew[n] = 0; + } else { + crew[n] -= chits; + chits = 0; + } + for (n = 0; n < 3; n++) + if (rhits > rigg[n]){ + rhits -= rigg[n]; + rigg[n] = 0; + } else { + rigg[n] -= rhits; + rhits = 0; + } + if (rigg[3] != -1 && rhits > rigg[3]) { + rhits -= rigg[3]; + rigg[3] = 0; + } else if (rigg[3] != -1) { + rigg[3] -= rhits; + } + if (rig && !rigg[2] && (!rigg[3] || rigg[3] == -1)) + makesignal(on, "dismasted!", (struct ship *)0, 0, 0, 0); + if (portside(from, on, 0)) { + guns = on->specs->gunR; + car = on->specs->carR; + } else { + guns = on->specs->gunL; + car = on->specs->carL; + } + if (ghits > car) { + ghits -= car; + car = 0; + } else { + car -= ghits; + ghits = 0; + } + if (ghits > guns){ + ghits -= guns; + guns = 0; + } else { + guns -= ghits; + ghits = 0; + } + hull -= ghits; + if (Ghit) + Write(portside(from, on, 0) ? W_GUNR : W_GUNL, + on, 0, guns, car, 0, 0); + hull -= hhits; + hull = hull < 0 ? 0 : hull; + if (on->file->captured != 0 && Chit) + Write(W_PCREW, on, 0, pc, 0, 0, 0); + if (Hhit) + Write(W_HULL, on, 0, hull, 0, 0, 0); + if (Chit) + Write(W_CREW, on, 0, crew[0], crew[1], crew[2], 0); + if (Rhit) + Write(W_RIGG, on, 0, rigg[0], rigg[1], rigg[2], rigg[3]); + switch (shot) { + case L_ROUND: + message = "firing round shot on %s (%c%c)"; + break; + case L_GRAPE: + message = "firing grape shot on %s (%c%c)"; + break; + case L_CHAIN: + message = "firing chain shot on %s (%c%c)"; + break; + case L_DOUBLE: + message = "firing double shot on %s (%c%c)"; + break; + case L_EXPLODE: + message = "exploding shot on %s (%c%c)"; + } + makesignal(from, message, on, 0, 0, 0); + if (roll == 6 && rig) { + switch(Rhit) { + case 0: + message = "fore topsail sheets parted"; + break; + case 1: + message = "mizzen shrouds parted"; + break; + case 2: + message = "main topsail yard shot away"; + break; + case 4: + message = "fore topmast and foremast shrouds shot away"; + break; + case 5: + message = "mizzen mast and yard shot through"; + break; + case 6: + message = "foremast and spritsail yard shattered"; + break; + case 7: + message = "main topmast and mizzen mast shattered"; + break; + } + makesignal(on, message, (struct ship *)0, 0, 0, 0); + } else if (roll == 6) { + switch (Hhit) { + case 0: + message = "anchor cables severed"; + break; + case 1: + message = "two anchor stocks shot away"; + break; + case 2: + message = "quarterdeck bulwarks damaged"; + break; + case 3: + message = "three gun ports shot away"; + break; + case 4: + message = "four guns dismounted"; + break; + case 5: + message = "rudder cables shot through"; + Write(W_TA, on, 0, 0, 0, 0, 0); + break; + case 6: + message = "shot holes below the water line"; + break; + } + makesignal(on, message, (struct ship *)0, 0, 0, 0); + } + /* + if (Chit > 1 && on->file->readyL&R_INITIAL && on->file->readyR&R_INITIAL) { + on->specs->qual--; + if (on->specs->qual <= 0) { + makesignal(on, "crew mutinying!", (struct ship *)0, 0, 0, 0); + on->specs->qual = 5; + Write(W_CAPTURED, on, 0, on->file->index, 0, 0, 0); + } else + makesignal(on, "crew demoralized", (struct ship *)0, 0, 0, 0); + Write(W_QUAL, on, 0, on->specs->qual, 0, 0, 0); + } + */ + if (!hull) + strike(on, from); +} + +void +Cleansnag(from, to, all, flag) + register struct ship *from, *to; + int all, flag; +{ + if (flag & 1) { + Write(W_UNGRAP, from, 0, to->file->index, all, 0, 0); + Write(W_UNGRAP, to, 0, from->file->index, all, 0, 0); + } + if (flag & 2) { + Write(W_UNFOUL, from, 0, to->file->index, all, 0, 0); + Write(W_UNFOUL, to, 0, from->file->index, all, 0, 0); + } + if (!snagged2(from, to)) { + if (!snagged(from)) { + unboard(from, from, 1); /* defense */ + unboard(from, from, 0); /* defense */ + } else + unboard(from, to, 0); /* offense */ + if (!snagged(to)) { + unboard(to, to, 1); /* defense */ + unboard(to, to, 0); /* defense */ + } else + unboard(to, from, 0); /* offense */ + } +} diff --git a/src/games/sail/doprnt.c b/src/games/sail/doprnt.c new file mode 100644 index 0000000..c5ed28d --- /dev/null +++ b/src/games/sail/doprnt.c @@ -0,0 +1,203 @@ +/* +Copyright (c) 2013, Alexey Frunze +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +The views and conclusions contained in the software and documentation are those +of the authors and should not be interpreted as representing official policies, +either expressed or implied, of the FreeBSD Project. +*/ + +#include +#include +#include + +int _doprnt (char const *fmt, va_list pp, FILE *stream) +{ + int cnt = 0; + const char* p; + const char* phex = "0123456789abcdef"; + char s[1/*sign*/+10/*magnitude*/+1/*\0*/]; // up to 11 octal digits in 32-bit numbers + char* pc; + int n, sign, msign; + int minlen = 0, len; + int leadchar; + + for (p = fmt; *p != '\0'; p++) + { + if (*p != '%' || p[1] == '%') + { + fputc(*p, stream); + p = p + (*p == '%'); + cnt++; + continue; + } + p++; + minlen = 0; + msign = 0; + if (*p == '+') { msign = 1; p++; } + else if (*p == '-') { msign = -1; p++; } + leadchar = ' '; + if (*p >= '0' && *p <= '9') + { + if (*p == '0') + leadchar = '0'; + while (*p >= '0' && *p <= '9') + minlen = minlen * 10 + *p++ - '0'; + if (msign < 0) + minlen = -minlen; + msign = 0; + } + if (!msign) + { + if (*p == '+') { msign = 1; p++; } + else if (*p == '-') { msign = -1; p++; } + } + switch (*p) + { + case 'c': + while (minlen > 1) { fputc(' ', stream); cnt++; minlen--; } + fputc(va_arg(pp, int), stream); + while (-minlen > 1) { fputc(' ', stream); cnt++; minlen++; } + cnt++; + break; + case 's': + pc = va_arg(pp, char*); + len = 0; + if (pc) + len = strlen(pc); + while (minlen > len) { fputc(' ', stream); cnt++; minlen--; } + if (len) + while (*pc != '\0') + { + fputc(*pc++, stream); + cnt++; + } + while (-minlen > len) { fputc(' ', stream); cnt++; minlen++; } + break; + case 'i': + case 'd': + pc = &s[sizeof s - 1]; + *pc = '\0'; + len = 0; + n = va_arg(pp, int); + sign = 1 - 2 * (n < 0); + do + { + *--pc = '0' + (n - n / 10 * 10) * sign; + n = n / 10; + len++; + } while (n); + if (sign < 0) + { + *--pc = '-'; + len++; + } + else if (msign > 0) + { + *--pc = '+'; + len++; + msign = 0; + } + while (minlen > len) { fputc(leadchar, stream); cnt++; minlen--; } + while (*pc != '\0') + { + fputc(*pc++, stream); + cnt++; + } + while (-minlen > len) { fputc(' ', stream); cnt++; minlen++; } + break; + case 'u': + pc = &s[sizeof s - 1]; + *pc = '\0'; + len = 0; + n = va_arg(pp, int); + do + { + unsigned nn = n; + *--pc = '0' + nn % 10; + n = nn / 10; + len++; + } while (n); + if (msign > 0) + { + *--pc = '+'; + len++; + msign = 0; + } + while (minlen > len) { fputc(leadchar, stream); cnt++; minlen--; } + while (*pc != '\0') + { + fputc(*pc++, stream); + cnt++; + } + while (-minlen > len) { fputc(' ', stream); cnt++; minlen++; } + break; + case 'X': + phex = "0123456789ABCDEF"; + // fallthrough + case 'p': + case 'x': + pc = &s[sizeof s - 1]; + *pc = '\0'; + len = 0; + n = va_arg(pp, int); + do + { + *--pc = phex[n & 0xF]; + n = (n >> 4) & ((1 << (8 * sizeof n - 4)) - 1); // drop sign-extended bits + len++; + } while (n); + while (minlen > len) { fputc(leadchar, stream); cnt++; minlen--; } + while (*pc != '\0') + { + fputc(*pc++, stream); + cnt++; + } + while (-minlen > len) { fputc(' ', stream); cnt++; minlen++; } + break; + case 'o': + pc = &s[sizeof s - 1]; + *pc = '\0'; + len = 0; + n = va_arg(pp, int); + do + { + *--pc = '0' + (n & 7); + n = (n >> 3) & ((1 << (8 * sizeof n - 3)) - 1); // drop sign-extended bits + len++; + } while (n); + while (minlen > len) { fputc(leadchar, stream); cnt++; minlen--; } + while (*pc != '\0') + { + fputc(*pc++, stream); + cnt++; + } + while (-minlen > len) { fputc(' ', stream); cnt++; minlen++; } + break; + default: + return -1; + } + } + + return cnt; +} diff --git a/src/games/sail/dr_1.c b/src/games/sail/dr_1.c new file mode 100644 index 0000000..26946b0 --- /dev/null +++ b/src/games/sail/dr_1.c @@ -0,0 +1,438 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "driver.h" + +void +unfoul() +{ + register struct ship *sp; + struct ship *to; + register int nat; + register int i; + + foreachship(sp) { + if (sp->file->captain[0]) + continue; + nat = capship(sp)->nationality; + foreachship(to) { + if (nat != capship(to)->nationality && + !toughmelee(sp, to, 0, 0)) + continue; + for (i = fouled2(sp, to); --i >= 0;) + if (die() <= 2) + cleanfoul(sp, to, 0); + } + } +} + +void +boardcomp() +{ + int crew[3]; + register struct ship *sp, *sq; + + foreachship(sp) { + if (*sp->file->captain) + continue; + if (sp->file->dir == 0) + continue; + if (sp->file->struck || sp->file->captured != 0) + continue; + if (!snagged(sp)) + continue; + crew[0] = sp->specs->crew1 != 0; + crew[1] = sp->specs->crew2 != 0; + crew[2] = sp->specs->crew3 != 0; + foreachship(sq) { + if (!Xsnagged2(sp, sq)) + continue; + if (meleeing(sp, sq)) + continue; + if (!sq->file->dir + || sp->nationality == capship(sq)->nationality) + continue; + switch (sp->specs->class - sq->specs->class) { + case -3: case -4: case -5: + if (crew[0]) { + /* OBP */ + sendbp(sp, sq, crew[0]*100, 0); + crew[0] = 0; + } else if (crew[1]){ + /* OBP */ + sendbp(sp, sq, crew[1]*10, 0); + crew[1] = 0; + } + break; + case -2: + if (crew[0] || crew[1]) { + /* OBP */ + sendbp(sp, sq, crew[0]*100+crew[1]*10, + 0); + crew[0] = crew[1] = 0; + } + break; + case -1: case 0: case 1: + if (crew[0]) { + /* OBP */ + sendbp(sp, sq, crew[0]*100+crew[1]*10, + 0); + crew[0] = crew[1] = 0; + } + break; + case 2: case 3: case 4: case 5: + /* OBP */ + sendbp(sp, sq, crew[0]*100+crew[1]*10+crew[2], + 0); + crew[0] = crew[1] = crew[2] = 0; + break; + } + } + } +} + +int +fightitout(from, to, key) + struct ship *from, *to; + int key; +{ + struct ship *fromcap, *tocap; + int crewfrom[3], crewto[3], menfrom, mento; + int pcto, pcfrom, fromstrength, strengthto, frominjured, toinjured; + int topoints; + int index, totalfrom = 0, totalto = 0; + int count; + char message[60]; + + menfrom = mensent(from, to, crewfrom, &fromcap, &pcfrom, key); + mento = mensent(to, from, crewto, &tocap, &pcto, 0); + if (fromcap == 0) + fromcap = from; + if (tocap == 0) + tocap = to; + if (key) { + if (!menfrom) { /* if crew surprised */ + if (fromcap == from) + menfrom = from->specs->crew1 + + from->specs->crew2 + + from->specs->crew3; + else + menfrom = from->file->pcrew; + } else { + menfrom *= 2; /* DBP's fight at an advantage */ + } + } + fromstrength = menfrom * fromcap->specs->qual; + strengthto = mento * tocap->specs->qual; + for (count = 0; + ((fromstrength < strengthto * 3 && strengthto < fromstrength * 3) + || fromstrength == -1) && count < 4; + count++) { + index = fromstrength/10; + if (index > 8) + index = 8; + toinjured = MT[index][2 - die() / 3]; + totalto += toinjured; + index = strengthto/10; + if (index > 8) + index = 8; + frominjured = MT[index][2 - die() / 3]; + totalfrom += frominjured; + menfrom -= frominjured; + mento -= toinjured; + fromstrength = menfrom * fromcap->specs->qual; + strengthto = mento * tocap->specs->qual; + } + if (fromstrength >= strengthto * 3 || count == 4) { + unboard(to, from, 0); + subtract(from, totalfrom, crewfrom, fromcap, pcfrom); + subtract(to, totalto, crewto, tocap, pcto); + makesignal(from, "boarders from %s repelled", to, 0, 0, 0); + (void) sprintf(message, "killed in melee: %d. %s: %d", + totalto, from->shipname, totalfrom); + Write(W_SIGNAL, to, 1, (int) message, 0, 0, 0); + if (key) + return 1; + } else if (strengthto >= fromstrength * 3) { + unboard(from, to, 0); + subtract(from, totalfrom, crewfrom, fromcap, pcfrom); + subtract(to, totalto, crewto, tocap, pcto); + if (key) { + if (fromcap != from) + Write(W_POINTS, fromcap, 0, + fromcap->file->points - + from->file->struck + ? from->specs->pts + : 2 * from->specs->pts, + 0, 0, 0); + +/* ptr1 points to the shipspec for the ship that was just unboarded. + I guess that what is going on here is that the pointer is multiplied + or something. */ + + Write(W_CAPTURED, from, 0, to->file->index, 0, 0, 0); + topoints = 2 * from->specs->pts + to->file->points; + if (from->file->struck) + topoints -= from->specs->pts; + Write(W_POINTS, to, 0, topoints, 0, 0, 0); + mento = crewto[0] ? crewto[0] : crewto[1]; + if (mento) { + subtract(to, mento, crewto, tocap, pcto); + subtract(from, - mento, crewfrom, to, 0); + } + (void) sprintf(message, "captured by the %s!", + to->shipname); + Write(W_SIGNAL, from, 1, (int) message, 0, 0, 0); + (void) sprintf(message, "killed in melee: %d. %s: %d", + totalto, from->shipname, totalfrom); + Write(W_SIGNAL, to, 1, (int) message, 0, 0, 0); + mento = 0; + return 0; + } + } + return 0; +} + +void +resolve() +{ + int thwart; + register struct ship *sp, *sq; + + foreachship(sp) { + if (sp->file->dir == 0) + continue; + for (sq = sp + 1; sq < ls; sq++) + if (sq->file->dir && meleeing(sp, sq) && meleeing(sq, sp)) + (void) fightitout(sp, sq, 0); + thwart = 2; + foreachship(sq) { + if (sq->file->dir && meleeing(sq, sp)) + thwart = fightitout(sp, sq, 1); + if (!thwart) + break; + } + if (!thwart) { + foreachship(sq) { + if (sq->file->dir && meleeing(sq, sp)) + unboard(sq, sp, 0); + unboard(sp, sq, 0); + } + unboard(sp, sp, 1); + } else if (thwart == 2) + unboard(sp, sp, 1); + } +} + +void +compcombat() +{ + register int n; + register struct ship *sp; + struct ship *closest; + int crew[3], men = 0, target, temp; + int r, guns, ready, load, car; + int index, rakehim, sternrake; + int shootat, hit; + + foreachship(sp) { + if (sp->file->captain[0] || sp->file->dir == 0) + continue; + crew[0] = sp->specs->crew1; + crew[1] = sp->specs->crew2; + crew[2] = sp->specs->crew3; + for (n = 0; n < 3; n++) { + if (sp->file->OBP[n].turnsent) + men += sp->file->OBP[n].mensent; + } + for (n = 0; n < 3; n++) { + if (sp->file->DBP[n].turnsent) + men += sp->file->DBP[n].mensent; + } + if (men){ + crew[0] = men/100 ? 0 : crew[0] != 0; + crew[1] = (men%100)/10 ? 0 : crew[1] != 0; + crew[2] = men%10 ? 0 : crew[2] != 0; + } + for (r = 0; r < 2; r++) { + if (!crew[2]) + continue; + if (sp->file->struck) + continue; + if (r) { + ready = sp->file->readyR; + guns = sp->specs->gunR; + car = sp->specs->carR; + } else { + ready = sp->file->readyL; + guns = sp->specs->gunL; + car = sp->specs->carL; + } + if (!guns && !car) + continue; + if ((ready & R_LOADED) == 0) + continue; + closest = closestenemy(sp, r ? 'r' : 'l', 0); + if (closest == 0) + continue; + if (range(closest, sp) > range(sp, closestenemy(sp, r ? 'r' : 'l', 1))) + continue; + if (closest->file->struck) + continue; + target = range(sp, closest); + if (target > 10) + continue; + if (!guns && target >= 3) + continue; + load = L_ROUND; + if (target == 1 && sp->file->loadwith == L_GRAPE) + load = L_GRAPE; + if (target <= 3 && closest->file->FS) + load = L_CHAIN; + if (target == 1 && load != L_GRAPE) + load = L_DOUBLE; + if (load > L_CHAIN && target < 6) + shootat = HULL; + else + shootat = RIGGING; + rakehim = gunsbear(sp, closest) + && !gunsbear(closest, sp); + temp = portside(closest, sp, 1) + - closest->file->dir + 1; + if (temp < 1) + temp += 8; + if (temp > 8) + temp -= 8; + sternrake = temp > 4 && temp < 6; + index = guns; + if (target < 3) + index += car; + index = (index - 1) / 3; + index = index > 8 ? 8 : index; + if (!rakehim) + hit = HDT[index][target-1]; + else + hit = HDTrake[index][target-1]; + if (rakehim && sternrake) + hit++; + hit += QUAL[index][capship(sp)->specs->qual - 1]; + for (n = 0; n < 3 && sp->file->captured == 0; n++) + if (!crew[n]) { + if (index <= 5) + hit--; + else + hit -= 2; + } + if (ready & R_INITIAL) { + if (!r) + sp->file->readyL &= ~R_INITIAL; + else + sp->file->readyR &= ~R_INITIAL; + if (index <= 3) + hit++; + else + hit += 2; + } + if (sp->file->captured != 0) { + if (index <= 1) + hit--; + else + hit -= 2; + } + hit += AMMO[index][load - 1]; + temp = sp->specs->class; + if ((temp >= 5 || temp == 1) && windspeed == 5) + hit--; + if (windspeed == 6 && temp == 4) + hit -= 2; + if (windspeed == 6 && temp <= 3) + hit--; + if (hit >= 0) { + if (load != L_GRAPE) + hit = hit > 10 ? 10 : hit; + table(shootat, load, hit, closest, sp, die()); + } + } + } +} + +int +next() +{ + if (++turn % 55 == 0) { + if (alive) + alive = 0; + else + people = 0; + } + if (people <= 0 || windspeed == 7) { + register struct ship *s; + struct ship *bestship = 0; + float net, best = 0.0; + foreachship(s) { + if (*s->file->captain) + continue; + net = (float)s->file->points / s->specs->pts; + if (net > best) { + best = net; + bestship = s; + } + } + if (best > 0.0) { + char *p = getenv("WOTD"); + if (p == 0) + p = "Driver"; + if (islower(*p)) + *p = toupper(*p); + (void) strncpy(bestship->file->captain, p, + sizeof bestship->file->captain); + bestship->file->captain + [sizeof bestship->file->captain - 1] = 0; + logmsg(bestship); + } + return -1; + } + Write(W_TURN, SHIP(0), 0, turn, 0, 0, 0); + if (turn % 7 == 0 && (die() >= cc->windchange || !windspeed)) { + switch (die()) { + case 1: + winddir = 1; + break; + case 2: + break; + case 3: + winddir++; + break; + case 4: + winddir--; + break; + case 5: + winddir += 2; + break; + case 6: + winddir -= 2; + break; + } + if (winddir > 8) + winddir -= 8; + if (winddir < 1) + winddir += 8; + if (windspeed) + switch (die()) { + case 1: + case 2: + windspeed--; + break; + case 5: + case 6: + windspeed++; + break; + } + else + windspeed++; + Write(W_WIND, SHIP(0), 0, winddir, windspeed, 0, 0); + } + return 0; +} diff --git a/src/games/sail/dr_2.c b/src/games/sail/dr_2.c new file mode 100644 index 0000000..e92b2e2 --- /dev/null +++ b/src/games/sail/dr_2.c @@ -0,0 +1,252 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "driver.h" + +#define couldwin(f,t) (f->specs->crew2 > t->specs->crew2 * 1.5) + +void +thinkofgrapples() +{ + register struct ship *sp, *sq; + char friendly; + + foreachship(sp) { + if (sp->file->captain[0] || sp->file->dir == 0) + continue; + foreachship(sq) { + friendly = sp->nationality == capship(sq)->nationality; + if (!friendly) { + if (sp->file->struck || sp->file->captured != 0) + continue; + if (range(sp, sq) != 1) + continue; + if (grappled2(sp, sq)) + if (toughmelee(sp, sq, 0, 0)) + ungrap(sp, sq); + else + grap(sp, sq); + else if (couldwin(sp, sq)) { + grap(sp, sq); + sp->file->loadwith = L_GRAPE; + } + } else + ungrap(sp, sq); + } + } +} + +void +checkup() +{ + register struct ship *sp, *sq; + register char explode, sink; + + foreachship(sp) { + if (sp->file->dir == 0) + continue; + explode = sp->file->explode; + sink = sp->file->sink; + if (explode != 1 && sink != 1) + continue; + if (die() < 5) + continue; + Write(sink == 1 ? W_SINK : W_EXPLODE, sp, 0, 2, 0, 0, 0); + Write(W_DIR, sp, 0, 0, 0, 0, 0); + if (snagged(sp)) + foreachship(sq) + cleansnag(sp, sq, 1); + if (sink != 1) { + makesignal(sp, "exploding!", (struct ship *)0, 0, 0, 0); + foreachship(sq) { + if (sp != sq && sq->file->dir && range(sp, sq) < 4) + table(RIGGING, L_EXPLODE, sp->specs->guns/13, sq, sp, 6); + } + } else + makesignal(sp, "sinking!", (struct ship *)0, 0, 0, 0); + } +} + +void +prizecheck() +{ + register struct ship *sp; + + foreachship(sp) { + if (sp->file->captured == 0) + continue; + if (sp->file->struck || sp->file->dir == 0) + continue; + if (sp->specs->crew1 + sp->specs->crew2 + sp->specs->crew3 > sp->file->pcrew * 6) { + Write(W_SIGNAL, sp, 1, + (int)"prize crew overthrown", 0, 0, 0); + Write(W_POINTS, sp->file->captured, 0, sp->file->captured->file->points - 2 * sp->specs->pts, 0, 0, 0); + Write(W_CAPTURED, sp, 0, -1, 0, 0, 0); + } + } +} + +int +strend(str) + char *str; +{ + register char *p; + + for (p = str; *p; p++) + ; + return p == str ? 0 : p[-1]; +} + +int dtab[] = {0,1,1,2,3,4,4,5}; /* diagonal distances in x==y */ + +static void +move(p, ship, dir, row, col, drift) + register char *p; + register struct ship *ship; + register char *dir; + register short *row, *col; + register char *drift; +{ + int dist; + char moved = 0; + + for (; *p; p++) { + switch (*p) { + case 'r': + if (++*dir == 9) + *dir = 1; + break; + case 'l': + if (--*dir == 0) + *dir = 8; + break; + case '1': case '2': case '3': case '4': + case '5': case '6': case '7': + moved++; + if (*dir % 2 == 0) + dist = dtab[*p - '0']; + else + dist = *p - '0'; + *row -= dr[(int)*dir] * dist; + *col -= dc[(int)*dir] * dist; + break; + } + } + if (!moved) { + if (windspeed != 0 && ++*drift > 2) { + if ((ship->specs->class >= 3 && !snagged(ship)) + || (turn & 1) == 0) { + *row -= dr[winddir]; + *col -= dc[winddir]; + } + } + } else + *drift = 0; +} + +static int +score(movement, ship, to, onlytemp) + char movement[]; + register struct ship *ship, *to; + int onlytemp; +{ + char drift; + int row, col, dir, total, ran; + register struct File *fp = ship->file; + + if ((dir = fp->dir) == 0) + return 0; + row = fp->row; + col = fp->col; + drift = fp->drift; + move(movement, ship, &fp->dir, &fp->row, &fp->col, &drift); + if (!*movement) + (void) strcpy(movement, "d"); + + ran = range(ship, to); + total = -50 * ran; + if (ran < 4 && gunsbear(ship, to)) + total += 60; + if ((ran = portside(ship, to, 1) - fp->dir) == 4 || ran == -4) + total = -30000; + + if (!onlytemp) { + fp->row = row; + fp->col = col; + fp->dir = dir; + } + return total; +} + +static void +rmend(str) + char *str; +{ + register char *p; + + for (p = str; *p; p++) + ; + if (p != str) + *--p = 0; +} + +static void +try(command, temp, ma, ta, af, vma, dir, f, t, high, rakeme) + register struct ship *f, *t; + int ma, ta, af, *high, rakeme; + char command[], temp[]; +{ + register int new, n; + char st[4]; +#define rakeyou (gunsbear(f, t) && !gunsbear(t, f)) + + if ((n = strend(temp)) < '1' || n > '9') + for (n = 1; vma - n >= 0; n++) { + (void) sprintf(st, "%d", n); + (void) strcat(temp, st); + new = score(temp, f, t, rakeme); + if (new > *high && (!rakeme || rakeyou)) { + *high = new; + (void) strcpy(command, temp); + } + try(command, temp, ma-n, ta, af, vma-n, + dir, f, t, high, rakeme); + rmend(temp); + } + if ((ma > 0 && ta > 0 && (n = strend(temp)) != 'l' && n != 'r') || !strlen(temp)) { + (void) strcat(temp, "r"); + new = score(temp, f, t, rakeme); + if (new > *high && (!rakeme || (gunsbear(f, t) && !gunsbear(t, f)))) { + *high = new; + (void) strcpy(command, temp); + } + try(command, temp, ma-1, ta-1, af, min(ma-1, maxmove(f, (dir == 8 ? 1 : dir+1), 0)), (dir == 8 ? 1 : dir+1),f,t,high,rakeme); + rmend(temp); + } + if ((ma > 0 && ta > 0 && (n = strend(temp)) != 'l' && n != 'r') || !strlen(temp)){ + (void) strcat(temp, "l"); + new = score(temp, f, t, rakeme); + if (new > *high && (!rakeme || (gunsbear(f, t) && !gunsbear(t, f)))){ + *high = new; + (void) strcpy(command, temp); + } + try(command, temp, ma-1, ta-1, af, (min(ma-1, maxmove(f, (dir-1 ? dir-1 : 8), 0))), (dir-1 ? dir -1 : 8), f, t, high, rakeme); + rmend(temp); + } +} + +void +closeon(from, to, command, ta, ma, af) + register struct ship *from, *to; + char command[]; + int ma, ta, af; +{ + int high; + char temp[10]; + + temp[0] = command[0] = '\0'; + high = -30000; + try(command, temp, ma, ta, af, ma, from->file->dir, from, to, &high, 0); +} diff --git a/src/games/sail/dr_3.c b/src/games/sail/dr_3.c new file mode 100644 index 0000000..5a62f40 --- /dev/null +++ b/src/games/sail/dr_3.c @@ -0,0 +1,323 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "driver.h" + +static int +stillmoving(k) + register int k; +{ + register struct ship *sp; + + foreachship(sp) + if (sp->file->movebuf[k]) + return 1; + return 0; +} + +static void +step(com, sp, moved) + int com; + register struct ship *sp; + char *moved; +{ + register int dist; + + switch (com) { + case 'r': + if (++sp->file->dir == 9) + sp->file->dir = 1; + break; + case 'l': + if (--sp->file->dir == 0) + sp->file->dir = 8; + break; + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + if (sp->file->dir % 2 == 0) + dist = dtab[com - '0']; + else + dist = com - '0'; + sp->file->row -= dr[(int)sp->file->dir] * dist; + sp->file->col -= dc[(int)sp->file->dir] * dist; + *moved = 1; + break; + case 'b': + break; + case 'd': + if (!*moved) { + if (windspeed != 0 && ++sp->file->drift > 2 && + ((sp->specs->class >= 3 && !snagged(sp)) + || (turn & 1) == 0)) { + sp->file->row -= dr[winddir]; + sp->file->col -= dc[winddir]; + } + } else + sp->file->drift = 0; + break; + } +} + +static int +isolated(ship) + register struct ship *ship; +{ + register struct ship *sp; + + foreachship(sp) { + if (ship != sp && range(ship, sp) <= 10) + return 0; + } + return 1; +} + +static int +push(from, to) + register struct ship *from, *to; +{ + register int bs, sb; + + sb = to->specs->guns; + bs = from->specs->guns; + if (sb > bs) + return 1; + if (sb < bs) + return 0; + return from < to; +} + +void +moveall() /* move all comp ships */ +{ + register struct ship *sp, *sq; /* r11, r10 */ + register int n; /* r9 */ + register int k, l; /* r8, r7 */ + int row[NSHIP], col[NSHIP], dir[NSHIP], drift[NSHIP]; + char moved[NSHIP]; + + /* + * first try to create moves for OUR ships + */ + foreachship(sp) { + struct ship *closest; + int ma, ta; + char af; + + if (sp->file->captain[0] || sp->file->dir == 0) + continue; + if (!sp->file->struck && windspeed && !snagged(sp) + && sp->specs->crew3) { + ta = maxturns(sp, &af); + ma = maxmove(sp, sp->file->dir, 0); + closest = closestenemy(sp, 0, 0); + if (closest == 0) + *sp->file->movebuf = '\0'; + else + closeon(sp, closest, sp->file->movebuf, + ta, ma, af); + } else + *sp->file->movebuf = '\0'; + } + /* + * Then execute the moves for ALL ships (dead ones too), + * checking for collisions and snags at each step. + * The old positions are saved in row[], col[], dir[]. + * At the end, we compare and write out the changes. + */ + n = 0; + foreachship(sp) { + if (snagged(sp)) + (void) strcpy(sp->file->movebuf, "d"); + else + if (*sp->file->movebuf != 'd') + (void) strcat(sp->file->movebuf, "d"); + row[n] = sp->file->row; + col[n] = sp->file->col; + dir[n] = sp->file->dir; + drift[n] = sp->file->drift; + moved[n] = 0; + n++; + } + /* + * Now resolve collisions. + * This is the tough part. + */ + for (k = 0; stillmoving(k); k++) { + /* + * Step once. + * And propagate the nulls at the end of sp->file->movebuf. + */ + n = 0; + foreachship(sp) { + if (!sp->file->movebuf[k]) + sp->file->movebuf[k+1] = '\0'; + else if (sp->file->dir) + step(sp->file->movebuf[k], sp, &moved[n]); + n++; + } + /* + * The real stuff. + */ + n = 0; + foreachship(sp) { + if (sp->file->dir == 0 || isolated(sp)) + goto cont1; + l = 0; + foreachship(sq) { + char snap = 0; + + if (sp == sq) + goto cont2; + if (sq->file->dir == 0) + goto cont2; + if (!push(sp, sq)) + goto cont2; + if (snagged2(sp, sq) && range(sp, sq) > 1) + snap++; + if (!range(sp, sq) && !fouled2(sp, sq)) { + makesignal(sp, + "collision with %s (%c%c)", sq, 0, 0, 0); + if (die() < 4) { + makesignal(sp, + "fouled with %s (%c%c)", + sq, 0, 0, 0); + Write(W_FOUL, sp, 0, l, 0, 0, 0); + Write(W_FOUL, sq, 0, n, 0, 0, 0); + } + snap++; + } + if (snap) { + sp->file->movebuf[k + 1] = 0; + sq->file->movebuf[k + 1] = 0; + sq->file->row = sp->file->row - 1; + if (sp->file->dir == 1 + || sp->file->dir == 5) + sq->file->col = + sp->file->col - 1; + else + sq->file->col = sp->file->col; + sq->file->dir = sp->file->dir; + } + cont2: + l++; + } + cont1: + n++; + } + } + /* + * Clear old moves. And write out new pos. + */ + n = 0; + foreachship(sp) { + if (sp->file->dir != 0) { + *sp->file->movebuf = 0; + if (row[n] != sp->file->row) + Write(W_ROW, sp, 0, sp->file->row, 0, 0, 0); + if (col[n] != sp->file->col) + Write(W_COL, sp, 0, sp->file->col, 0, 0, 0); + if (dir[n] != sp->file->dir) + Write(W_DIR, sp, 0, sp->file->dir, 0, 0, 0); + if (drift[n] != sp->file->drift) + Write(W_DRIFT, sp, 0, sp->file->drift, 0, 0, 0); + } + n++; + } +} + +void +sendbp(from, to, sections, isdefense) + register struct ship *from, *to; + int sections; + int isdefense; +{ + int n; + register struct BP *bp; + + bp = isdefense ? from->file->DBP : from->file->OBP; + for (n = 0; n < NBP && bp[n].turnsent; n++) + ; + if (n < NBP && sections) { + Write(isdefense ? W_DBP : W_OBP, from, 0, + n, turn, to->file->index, sections); + if (isdefense) + makesignal(from, "repelling boarders", + (struct ship *)0, 0, 0, 0); + else + makesignal(from, "boarding the %s (%c%c)", to, 0, 0, 0); + } +} + +int +toughmelee(ship, to, isdefense, count) + register struct ship *ship, *to; + int isdefense, count; +{ + register struct BP *bp; + register int obp = 0; + int n, OBP = 0, DBP = 0, dbp = 0; + int qual; + + qual = ship->specs->qual; + bp = isdefense ? ship->file->DBP : ship->file->OBP; + for (n = 0; n < NBP; n++, bp++) { + if (bp->turnsent && (to == bp->toship || isdefense)) { + obp += bp->mensent / 100 + ? ship->specs->crew1 * qual : 0; + obp += (bp->mensent % 100)/10 + ? ship->specs->crew2 * qual : 0; + obp += bp->mensent % 10 + ? ship->specs->crew3 * qual : 0; + } + } + if (count || isdefense) + return obp; + OBP = toughmelee(to, ship, 0, count + 1); + dbp = toughmelee(ship, to, 1, count + 1); + DBP = toughmelee(to, ship, 1, count + 1); + if (OBP > obp + 10 || OBP + DBP >= obp + dbp + 10) + return 1; + else + return 0; +} + +void +reload() +{ + register struct ship *sp; + + foreachship(sp) { + sp->file->loadwith = 0; + } +} + +void +checksails() +{ + register struct ship *sp; + register int rig, full; + struct ship *close; + + foreachship(sp) { + if (sp->file->captain[0] != 0) + continue; + rig = sp->specs->rig1; + if (windspeed == 6 || (windspeed == 5 && sp->specs->class > 4)) + rig = 0; + if (rig && sp->specs->crew3) { + close = closestenemy(sp, 0, 0); + if (close != 0) { + if (range(sp, close) > 9) + full = 1; + else + full = 0; + } else + full = 0; + } else + full = 0; + if ((sp->file->FS != 0) != full) + Write(W_FS, sp, 0, full, 0, 0, 0); + } +} diff --git a/src/games/sail/dr_4.c b/src/games/sail/dr_4.c new file mode 100644 index 0000000..d7ef62d --- /dev/null +++ b/src/games/sail/dr_4.c @@ -0,0 +1,35 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "externs.h" + +void +ungrap(from, to) + register struct ship *from, *to; +{ + register int k; + int friend; + + if ((k = grappled2(from, to)) == 0) + return; + friend = capship(from)->nationality == capship(to)->nationality; + while (--k >= 0) { + if (friend || die() < 3) { + cleangrapple(from, to, 0); + makesignal(from, "ungrappling %s (%c%c)", to, 0, 0, 0); + } + } +} + +void +grap(from, to) + register struct ship *from, *to; +{ + if (capship(from)->nationality != capship(to)->nationality && die() > 2) + return; + Write(W_GRAP, from, 0, to->file->index, 0, 0, 0); + Write(W_GRAP, to, 0, from->file->index, 0, 0, 0); + makesignal(from, "grappled with %s (%c%c)", to, 0, 0, 0); +} diff --git a/src/games/sail/dr_5.c b/src/games/sail/dr_5.c new file mode 100644 index 0000000..ce56c60 --- /dev/null +++ b/src/games/sail/dr_5.c @@ -0,0 +1,63 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "externs.h" + +void +subtract(from, totalfrom, crewfrom, fromcap, pcfrom) + struct ship *from, *fromcap; + int pcfrom; + register int totalfrom, crewfrom[3]; +{ + register int n; + + if (fromcap == from && totalfrom) { /* if not captured */ + for (n = 0; n < 3; n++) { + if (totalfrom > crewfrom[n]) { + totalfrom -= crewfrom[n]; + crewfrom[n] = 0; + } else { + crewfrom[n] -= totalfrom; + totalfrom = 0; + } + } + Write(W_CREW, from, 0, crewfrom[0], crewfrom[1], crewfrom[2], 0); + } else if (totalfrom) { + pcfrom -= totalfrom; + pcfrom = pcfrom < 0 ? 0 : pcfrom; + Write(W_PCREW, from, 0, pcfrom, 0, 0, 0); + } +} + +int +mensent(from, to, crew, captured, pc, isdefense) + struct ship *from, *to, **captured; + int crew[3], *pc; + int isdefense; +{ /* returns # of crew squares sent */ + int men = 0; + register int n; + int c1, c2, c3; + register struct BP *bp; + + *pc = from->file->pcrew; + *captured = from->file->captured; + crew[0] = from->specs->crew1; + crew[1] = from->specs->crew2; + crew[2] = from->specs->crew3; + bp = isdefense ? from->file->DBP : from->file->OBP; + for (n=0; n < NBP; n++, bp++) { + if (bp->turnsent && bp->toship == to) + men += bp->mensent; + } + if (men) { + c1 = men/100 ? crew[0] : 0; + c2 = (men%100)/10 ? crew[1] : 0; + c3 = men/10 ? crew[2] : 0; + c3 = *captured == 0 ? crew[2] : *pc; + } else + c1 = c2 = c3 = 0; + return(c1 + c2 + c3); +} diff --git a/src/games/sail/dr_main.c b/src/games/sail/dr_main.c new file mode 100644 index 0000000..ca4dfa0 --- /dev/null +++ b/src/games/sail/dr_main.c @@ -0,0 +1,79 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "driver.h" + +int +dr_main() +{ + register int n; + register struct ship *sp; + int nat[NNATION]; + int value = 0; + + (void) signal(SIGINT, SIG_IGN); + (void) signal(SIGQUIT, SIG_IGN); + (void) signal(SIGTSTP, SIG_IGN); +#if 0 + if (issetuid) + (void) setruid(geteuid()); +#endif + if (game < 0 || game >= NSCENE) { + fprintf(stderr, "DRIVER: Bad game number %d\n", game); + exit(1); + } + cc = &scene[game]; + ls = SHIP(cc->vessels); + if (sync_open() < 0) { + perror("driver: syncfile"); + exit(1); + } + for (n = 0; n < NNATION; n++) + nat[n] = 0; + foreachship(sp) { + if (sp->file == NULL && + (sp->file = (struct File *)calloc(1, sizeof (struct File))) == NULL) { + (void) fprintf(stderr, "DRIVER: Out of memory.\n"); + exit(1); + } + sp->file->index = sp - SHIP(0); + sp->file->loadL = L_ROUND; + sp->file->loadR = L_ROUND; + sp->file->readyR = R_LOADED|R_INITIAL; + sp->file->readyL = R_LOADED|R_INITIAL; + sp->file->stern = nat[(int)sp->nationality]++; + sp->file->dir = sp->shipdir; + sp->file->row = sp->shiprow; + sp->file->col = sp->shipcol; + } + windspeed = cc->windspeed; + winddir = cc->winddir; + people = 0; + for (;;) { + sleep(7); + if (Sync() < 0) { + value = 1; + break; + } + if (next() < 0) + break; + unfoul(); + checkup(); + prizecheck(); + moveall(); + thinkofgrapples(); + boardcomp(); + compcombat(); + resolve(); + reload(); + checksails(); + if (Sync() < 0) { + value = 1; + break; + } + } + sync_close(1); + return value; +} diff --git a/src/games/sail/driver.h b/src/games/sail/driver.h new file mode 100644 index 0000000..8691cb9 --- /dev/null +++ b/src/games/sail/driver.h @@ -0,0 +1,10 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + * + * @(#)driver.h 5.1 (Berkeley) 5/29/85 + */ +#include "externs.h" + +extern int dtab[]; diff --git a/src/games/sail/externs.h b/src/games/sail/externs.h new file mode 100644 index 0000000..a74de59 --- /dev/null +++ b/src/games/sail/externs.h @@ -0,0 +1,351 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + * + * @(#)externs.h 5.1 (Berkeley) 5/29/85 + */ +#include +#include +#include +#include +#include +#include +#include +#include "machdep.h" + + /* program mode */ +int mode; +jmp_buf restart; +#define MODE_PLAYER 1 +#define MODE_DRIVER 2 +#define MODE_LOGGER 3 + + /* command line flags */ +char debug; /* -D */ +char randomize; /* -x, give first available ship */ +char longfmt; /* -l, print score in long format */ +char nobells; /* -b, don't ring bell before Signal */ + + /* other initial modes */ +char issetuid; /* running setuid */ + +#define die() ((rand() >> 3) % 6 + 1) +#define sqr(a) ((a) * (a)) +#define abs(a) ((a) > 0 ? (a) : -(a)) +#define min(a,b) ((a) < (b) ? (a) : (b)) + +#define grappled(a) ((a)->file->ngrap) +#define fouled(a) ((a)->file->nfoul) +#define snagged(a) (grappled(a) + fouled(a)) + +#define grappled2(a, b) ((a)->file->grap[(b)->file->index].sn_count) +#define fouled2(a, b) ((a)->file->foul[(b)->file->index].sn_count) +#define snagged2(a, b) (grappled2(a, b) + fouled2(a, b)) + +#define Xgrappled2(a, b) ((a)->file->grap[(b)->file->index].sn_turn < turn-1 ? grappled2(a, b) : 0) +#define Xfouled2(a, b) ((a)->file->foul[(b)->file->index].sn_turn < turn-1 ? fouled2(a, b) : 0) +#define Xsnagged2(a, b) (Xgrappled2(a, b) + Xfouled2(a, b)) + +#define cleangrapple(a, b, c) Cleansnag(a, b, c, 1) +#define cleanfoul(a, b, c) Cleansnag(a, b, c, 2) +#define cleansnag(a, b, c) Cleansnag(a, b, c, 3) + +#define sterncolour(sp) ((sp)->file->stern+'0'-((sp)->file->captured?10:0)) +#define sternrow(sp) ((sp)->file->row + dr[(int)(sp)->file->dir]) +#define sterncol(sp) ((sp)->file->col + dc[(int)(sp)->file->dir]) + +#define capship(sp) ((sp)->file->captured?(sp)->file->captured:(sp)) + +#define readyname(r) ((r) & R_LOADING ? '*' : ((r) & R_INITIAL ? '!' : ' ')) + +/* loadL and loadR, should match loadname[] */ +#define L_EMPTY 0 /* should be 0, don't change */ +#define L_GRAPE 1 +#define L_CHAIN 2 +#define L_ROUND 3 +#define L_DOUBLE 4 +#define L_EXPLODE 5 + +/* + * readyL and readyR, these are bits, except R_EMPTY + */ +#define R_EMPTY 0 /* not loaded and not loading */ +#define R_LOADING 1 /* loading */ +#define R_DOUBLE 2 /* loading double */ +#define R_LOADED 4 /* loaded */ +#define R_INITIAL 8 /* loaded initial */ + +#define HULL 0 +#define RIGGING 1 + +#define W_CAPTAIN 1 +#define W_CAPTURED 2 +#define W_CLASS 3 +#define W_CREW 4 +#define W_DBP 5 +#define W_DRIFT 6 +#define W_EXPLODE 7 +#define W_FILE 8 +#define W_FOUL 9 +#define W_GUNL 10 +#define W_GUNR 11 +#define W_HULL 12 +#define W_MOVE 13 +#define W_OBP 14 +#define W_PCREW 15 +#define W_UNFOUL 16 +#define W_POINTS 17 +#define W_QUAL 18 +#define W_UNGRAP 19 +#define W_RIGG 20 +#define W_COL 21 +#define W_DIR 22 +#define W_ROW 23 +#define W_SIGNAL 24 +#define W_SINK 25 +#define W_STRUCK 26 +#define W_TA 27 +#define W_ALIVE 28 +#define W_TURN 29 +#define W_WIND 30 +#define W_FS 31 +#define W_GRAP 32 +#define W_RIG1 33 +#define W_RIG2 34 +#define W_RIG3 35 +#define W_RIG4 36 +#define W_BEGIN 37 +#define W_END 38 +#define W_DDEAD 39 + +#define NLOG 10 +struct logs { + char l_name[20]; + int l_uid; + int l_shipnum; + int l_gamenum; + int l_netpoints; +}; + +struct BP { + short turnsent; + struct ship *toship; + short mensent; +}; + +struct snag { + short sn_count; + short sn_turn; +}; + +#define NSCENE nscene +#define NSHIP 10 +#define NBP 3 + +#define NNATION 8 +#define N_A 0 +#define N_B 1 +#define N_S 2 +#define N_F 3 +#define N_J 4 +#define N_D 5 +#define N_K 6 +#define N_O 7 + +struct File { + int index; + char captain[20]; /* 0 */ + short points; /* 20 */ + char loadL; /* 22 */ + char loadR; /* 24 */ + char readyL; /* 26 */ + char readyR; /* 28 */ + struct BP OBP[NBP]; /* 30 */ + struct BP DBP[NBP]; /* 48 */ + char struck; /* 66 */ + struct ship *captured; /* 68 */ + short pcrew; /* 70 */ + char movebuf[10]; /* 72 */ + char drift; /* 82 */ + short nfoul; + short ngrap; + struct snag foul[NSHIP]; /* 84 */ + struct snag grap[NSHIP]; /* 124 */ + char RH; /* 224 */ + char RG; /* 226 */ + char RR; /* 228 */ + char FS; /* 230 */ + char explode; /* 232 */ + char sink; /* 234 */ + char dir; + short col; + short row; + char loadwith; + char stern; +}; + +struct ship { + char *shipname; /* 0 */ + struct shipspecs *specs; /* 2 */ + char nationality; /* 4 */ + short shiprow; /* 6 */ + short shipcol; /* 8 */ + char shipdir; /* 10 */ + struct File *file; /* 12 */ +}; + +struct scenario { + char winddir; /* 0 */ + char windspeed; /* 2 */ + char windchange; /* 4 */ + char vessels; /* 12 */ + char *name; /* 14 */ + struct ship ship[NSHIP]; /* 16 */ +}; +extern struct scenario scene[]; +int nscene; + +struct shipspecs { + char bs; + char fs; + char ta; + short guns; + char class; + char hull; + char qual; + char crew1; + char crew2; + char crew3; + char gunL; + char gunR; + char carL; + char carR; + char rig1; + char rig2; + char rig3; + char rig4; + short pts; +}; +extern struct shipspecs specs[]; + +struct scenario *cc; /* the current scenario */ +struct ship *ls; /* &cc->ship[cc->vessels] */ + +#define SHIP(s) (&cc->ship[(int)s]) +#define foreachship(sp) for ((sp) = cc->ship; (sp) < ls; (sp)++) + +struct windeffects { + char A, B, C, D; +}; +struct windeffects WET[7][6]; + +struct Tables { + char H, G, C, R; +}; +struct Tables RigTable[11][6]; +struct Tables HullTable[11][6]; + +char AMMO[9][4]; +char HDT[9][10]; +char HDTrake[9][10]; +char QUAL[9][5]; +char MT[9][3]; + +extern char *countryname[]; +extern char *classname[]; +extern char *directionname[]; +extern char *qualname[]; +extern char loadname[]; + +extern char rangeofshot[]; + +extern char dr[], dc[]; + +int winddir; +int windspeed; +int turn; +int game; +int alive; +int people; +char hasdriver; + +char *info(); +char *quality(); +double arctan(); +char *saywhat(); +struct ship *closestenemy(); + +int pl_main(void); +int dr_main(void); +int lo_main(void); +int sync_exists(int game); +int sync_open(void); +int Sync(void); +int sgetch(char *p, struct ship *ship, int flag); +int range(struct ship *from, struct ship *to); +int gunsbear(struct ship *from, struct ship *to); +int portside(struct ship *from, struct ship *on, int quick); +int colours(struct ship *sp); +int maxturns(struct ship *ship, char *af); +int maxmove(struct ship *ship, int dir, int fs); +int meleeing(struct ship *from, struct ship *to); +int boarding(struct ship *from, int isdefense); +int next(void); +int toughmelee(struct ship *ship, struct ship *to, int isdefense, int count); +int mensent(struct ship *from, struct ship *to, int crew[3], + struct ship **captured, int *pc, int isdefense); + +void logmsg(struct ship *s); +void leave(int conditions); +void sync_close(int remove); +void Write(int type, struct ship *ship, int isstr, int a, int b, int c, int d); +void initscreen(void); +void draw_board(void); +void newturn(int sig); +void Signal(char *fmt, struct ship *ship, int a, int b, int c, int d); +void play(void); +void makesignal(struct ship *from, char *fmt, struct ship *ship, int a, int b, int c); +void cleanupscreen(void); +void acceptmove(void); +void acceptsignal(void); +void grapungrap(void); +void unfoulplayer(void); +void acceptboard(void); +void acceptcombat(void); +void loadplayer(void); +void changesail(void); +void repair(void); +void unboard(struct ship *ship, struct ship *to, int isdefense); +void centerview(void); +void blockalarm(void); +void unblockalarm(void); +void draw_screen(void); +void eyeball(struct ship *ship); +void draw_view(void); +void upview(void); +void downview(void); +void leftview(void); +void rightview(void); +void lookout(void); +void draw_turn(void); +void table(int rig, int shot, int hittable, struct ship *on, struct ship *from, int roll); +void draw_stat(void); +void Cleansnag(struct ship *from, struct ship *to, int all, int flag); +void sgetstr(char *pr, char *buf, int n); +void draw_slot(void); +void unfoul(void); +void checkup(void); +void prizecheck(void); +void moveall(void); +void thinkofgrapples(void); +void boardcomp(void); +void compcombat(void); +void resolve(void); +void reload(void); +void checksails(void); +void sendbp(struct ship *from, struct ship *to, int sections, int isdefense); +void subtract(struct ship *from, int totalfrom, int crewfrom[3], struct ship *fromcap, int pcfrom); +void grap(struct ship *from, struct ship *to); +void ungrap(struct ship *from, struct ship *to); +void closeon(struct ship *from, struct ship *to, char command[], int ta, int ma, int af); diff --git a/src/games/sail/game.c b/src/games/sail/game.c new file mode 100644 index 0000000..36bb67f --- /dev/null +++ b/src/games/sail/game.c @@ -0,0 +1,58 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "externs.h" + +int +maxturns(ship, af) + register struct ship *ship; + char *af; +{ + register int turns; + + turns = ship->specs->ta; + *af = (ship->file->drift > 1 && turns); + if (*af) { + turns--; + if (ship->file->FS == 1) + turns = 0; + } + return turns; +} + +int +maxmove(ship, dir, fs) + register struct ship *ship; + int dir, fs; +{ + register int riggone = 0, Move, flank = 0; + + Move = ship->specs->bs; + if (!ship->specs->rig1) + riggone++; + if (!ship->specs->rig2) + riggone++; + if (!ship->specs->rig3) + riggone++; + if (!ship->specs->rig4) + riggone++; + if ((ship->file->FS || fs) && fs != -1) { + flank = 1; + Move = ship->specs->fs; + } + if (dir == winddir) + Move -= 1 + WET[windspeed][ship->specs->class-1].B; + else if (dir == winddir + 2 || dir == winddir - 2 || dir == winddir - 6 || dir == winddir + 6) + Move -= 1 + WET[windspeed][ship->specs->class-1].C; + else if (dir == winddir + 3 || dir == winddir - 3 || dir == winddir - 5 || dir == winddir + 5) + Move = (flank ? 2 : 1) - WET[windspeed][ship->specs->class-1].D; + else if (dir == winddir + 4 || dir == winddir - 4) + Move = 0; + else + Move -= WET[windspeed][ship->specs->class-1].A; + Move -= riggone; + Move = Move < 0 ? 0 : Move; + return(Move); +} diff --git a/src/games/sail/globals.c b/src/games/sail/globals.c new file mode 100644 index 0000000..4759544 --- /dev/null +++ b/src/games/sail/globals.c @@ -0,0 +1,475 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "externs.h" + +struct scenario scene[] = { + /* + * int winddir; + * int windspeed; + * int windchange; + * int vessels; + * char *name; + * struct ship ship[NSHIP]; + */ + { 5, 3, 5, 2, "Ranger vs. Drake", + { + { "Ranger", specs+0, N_A, 7, 20, 4, 0 }, + { "Drake", specs+1, N_B, 7, 31, 5, 0 } + }}, + { 1, 3, 6, 2, "The Battle of Flamborough Head", + { + { "Bonhomme Rich", specs+2, N_A, 13, 40, 2, 0 }, + { "Serapis", specs+3, N_B, 2, 42, 2, 0 } + }}, + { 5, 5, 5, 10, "Arbuthnot and Des Touches", + { + { "America", specs+4, N_B, 7, 37, 4, 0 }, + { "Befford", specs+5, N_B, 5, 35, 4, 0 }, + { "Adamant", specs+6, N_B, 3, 33, 4, 0 }, + { "London", specs+7, N_B, 1, 31, 4, 0 }, + { "Royal Oak", specs+8, N_B, -1, 29, 4, 0 }, + { "Neptune", specs+9, N_F, 6, 44, 4, 0 }, + { "Duc Bougogne", specs+10, N_F, 8, 46, 4, 0 }, + { "Conquerant", specs+48, N_F, 10, 48, 4, 0 }, + { "Provence", specs+11, N_F, 12, 50, 4, 0 }, + { "Romulus", specs+12, N_F, 20, 58, 4, 0 } + }}, + { 1, 3, 5, 10, "Suffren and Hughes", + { + { "Monmouth", specs+52, N_B, 9, 45, 2, 0 }, + { "Hero", specs+5, N_B, 13, 49, 2, 0 }, + { "Isis", specs+6, N_B, 12, 48, 2, 0 }, + { "Superb", specs+50, N_B, 10, 46, 2, 0 }, + { "Burford", specs+48, N_B, 11, 47, 2, 0 }, + { "Flamband", specs+13, N_F, 7, 59, 4, 0 }, + { "Annibal", specs+9, N_F, 4, 56, 4, 0 }, + { "Severe", specs+11, N_F, 2, 54, 4, 0 }, + { "Brilliant", specs+49, N_F, -1, 51, 4, 0 }, + { "Sphinx", specs+51, N_F, -5, 47, 4, 0 } + }}, + { 1, 3, 4, 2, "Nymphe vs. Cleopatre", + { + { "Nymphe", specs+14, N_B, 13, 30, 2, 0 }, + { "Cleopatre", specs+15, N_F, 3, 41, 2, 0 } + }}, + { 1, 3, 5, 2, "Mars vs. Hercule", + { + { "Mars", specs+16, N_B, 13, 30, 2, 0 }, + { "Hercule", specs+17, N_F, 3, 41, 2, 0 } + }}, + { 5, 3, 5, 2, "Ambuscade vs. Baionnaise", + { + { "Ambuscade", specs+18, N_B, 13, 30, 2, 0 }, + { "Baionnaise", specs+19, N_F, 3, 41, 2, 0 } + }}, + { 1, 5, 6, 2, "Constellation vs. Insurgent", + { + { "Constellation", specs+20, N_A, 9, 50, 8, 0 }, + { "Insurgent", specs+22, N_F, 4, 24, 2, 0 } + }}, + { 1, 3, 5, 2, "Constellation vs. Vengeance", + { + { "Constellation", specs+20, N_A, 12, 40, 2, 0 }, + { "Vengeance", specs+21, N_F, 1, 43, 2, 0 } + }}, + { 1, 3, 6, 10, "The Battle of Lissa", + { + { "Amphion", specs+23, N_B, 8, 50, 4, 0 }, + { "Active", specs+24, N_B, 6, 48, 4, 0 }, + { "Volage", specs+25, N_B, 4, 46, 4, 0 }, + { "Cerberus", specs+26, N_B, 2, 44, 4, 0 }, + { "Favorite", specs+27, N_F, 9, 34, 2, 0 }, + { "Flore", specs+21, N_F, 13, 39, 2, 0 }, + { "Danae", specs+64, N_F, 15, 37, 2, 0 }, + { "Bellona", specs+28, N_F, 17, 35, 2, 0 }, + { "Corona", specs+29, N_F, 12, 31, 2, 0 }, + { "Carolina", specs+30, N_F, 15, 28, 2, 0 } + }}, + { 2, 5, 6, 2, "Constitution vs. Guerriere", + { + { "Constitution", specs+31, N_A, 7, 35, 1, 0 }, + { "Guerriere", specs+32, N_B, 7, 47, 4, 0 } + }}, + { 1, 3, 5, 2, "United States vs. Macedonian", + { + { "United States", specs+33, N_A, 1, 52, 6, 0 }, + { "Macedonian", specs+34, N_B, 14, 40, 1, 0 } + }}, + { 1, 3, 6, 2, "Constitution vs. Java", + { + { "Constitution", specs+31, N_A, 1, 40, 2, 0 }, + { "Java", specs+35, N_B, 11, 40, 2, 0 } + }}, + { 1, 3, 5, 2, "Chesapeake vs. Shannon", + { + { "Chesapeake", specs+36, N_A, 13, 40, 2, 0 }, + { "Shannon", specs+37, N_B, 1, 42, 2, 0 } + }}, + { 1, 1, 6, 5, "The Battle of Lake Erie", + { + { "Lawrence", specs+38, N_A, 4, 55, 8, 0 }, + { "Niagara", specs+42, N_A, 7, 61, 8, 0 }, + { "Lady Prevost", specs+39, N_B, 4, 25, 2, 0 }, + { "Detroit", specs+40, N_B, 7, 22, 2, 0 }, + { "Q. Charlotte", specs+41, N_B, 10, 19, 2, 0 } + }}, + { 1, 1, 5, 2, "Wasp vs. Reindeer", + { + { "Wasp", specs+42, N_A, 3, 41, 2, 0 }, + { "Reindeer", specs+43, N_B, 10, 48, 2, 0 } + }}, + { 1, 2, 5, 3, "Constitution vs. Cyane and Levant", + { + { "Constitution", specs+31, N_A, 10, 45, 2, 0 }, + { "Cyane", specs+44, N_B, 3, 37, 2, 0 }, + { "Levant", specs+45, N_B, 5, 35, 2, 0 } + }}, + { 5, 5, 5, 3, "Pellew vs. Droits de L'Homme", + { + { "Indefatigable", specs+46, N_B, 12, 45, 6, 0 }, + { "Amazon", specs+47, N_B, 9, 48, 6, 0 }, + { "Droits L'Hom", specs+48, N_F, 3, 28, 5, 0 } + }}, + { 2, 2, 3, 10, "Algeciras", + { + { "Caesar", specs+49, N_B, 7, 70, 6, 0 }, + { "Pompee", specs+50, N_B, 5, 72, 6, 0 }, + { "Spencer", specs+5, N_B, 3, 74, 6, 0 }, + { "Hannibal", specs+7, N_B, 1, 76, 6, 0 }, + { "Real-Carlos", specs+53, N_S, 9, 20, 3, 0 }, + { "San Fernando", specs+54, N_S, 11, 16, 3, 0 }, + { "Argonauta", specs+55, N_S, 10, 14, 4, 0 }, + { "San Augustine", specs+56, N_S, 6, 22, 4, 0 }, + { "Indomptable", specs+51, N_F, 7, 23, 5, 0 }, + { "Desaix", specs+52, N_F, 7, 27, 7, 0 } + }}, + { 5, 3, 6, 7, "Lake Champlain", + { + { "Saratoga", specs+60, N_A, 8, 10, 1, 0 }, + { "Eagle", specs+61, N_A, 9, 13, 2, 0 }, + { "Ticonderoga", specs+62, N_A, 12, 17, 3, 0 }, + { "Preble", specs+63, N_A, 14, 20, 2, 0 }, + { "Confiance", specs+57, N_B, 4, 70, 6, 0 }, + { "Linnet", specs+58, N_B, 7, 68, 6, 0 }, + { "Chubb", specs+59, N_B, 10, 65, 6, 0 } + }}, + { 5, 3, 6, 4, "Last Voyage of the USS President", + { + { "President", specs+67, N_A, 12, 42, 5, 0 }, + { "Endymion", specs+64, N_B, 5, 42, 5, 0 }, + { "Pomone", specs+65, N_B, 7, 82, 6, 0 }, + { "Tenedos", specs+66, N_B, 7, -1, 4, 0 } + }}, + { 7, 5, 5, 2, "Hornblower and the Natividad", + { + { "Lydia", specs+68, N_B, 12, 40, 2, 0 }, + { "Natividad", specs+69, N_S, 2, 40, 4, 0 } + }}, + { 1, 3, 6, 2, "Curse of the Flying Dutchman", + { + { "Piece of Cake", specs+19, N_S, 7, 40, 2, 0 }, + { "Flying Dutchy", specs+71, N_F, 7, 41, 1, 0 } + }}, + { 1, 4, 1, 4, "The South Pacific", + { + { "USS Scurvy", specs+70, N_A, 7, 40, 1, 0 }, + { "HMS Tahiti", specs+71, N_B, 12, 60, 1, 0 }, + { "Australian", specs+18, N_S, 5, 20, 8, 0 }, + { "Bikini Atoll", specs+63, N_F, 2, 60, 4, 0 } + }}, + { 7, 3, 6, 5, "Hornblower and the battle of Rosas bay", + { + { "Sutherland", specs+5, N_B, 13, 30, 2, 0 }, + { "Turenne", specs+10, N_F, 9, 35, 6, 0 }, + { "Nightmare", specs+9, N_F, 7, 37, 6, 0 }, + { "Paris", specs+53, N_F, 3, 45, 4, 0 }, + { "Napolean", specs+56, N_F, 1, 40, 6, 0 } + }}, + { 6, 4, 7, 5, "Cape Horn", + { + { "Concord", specs+51, N_A, 3, 20, 4, 0 }, + { "Berkeley", specs+7, N_A, 5, 50, 5, 0 }, + { "Thames", specs+71, N_B, 10, 40, 1, 0 }, + { "Madrid", specs+53, N_S, 13, 60, 8, 0 }, + { "Musket", specs+10, N_F, 10, 60, 7, 0 } + }}, + { 8, 3, 7, 3, "New Orleans", + { + { "Alligator", specs+71, N_A, 13, 5, 1, 0 }, + { "Firefly", specs+50, N_B, 10, 20, 8, 0 }, + { "Cypress", specs+46, N_B, 5, 10, 6, 0 } + }}, + { 5, 3, 7, 3, "Botany Bay", + { + { "Shark", specs+11, N_B, 6, 15, 4, 0 }, + { "Coral Snake", specs+31, N_F, 3, 30, 6, 0 }, + { "Sea Lion", specs+33, N_F, 13, 50, 8, 0 } + }}, + { 4, 3, 6, 4, "Voyage to the Bottom of the Sea", + { + { "Seaview", specs+71, N_A, 6, 3, 3, 0 }, + { "Flying Sub", specs+64, N_A, 8, 3, 3, 0 }, + { "Mermaid", specs+70, N_B, 2, 5, 5, 0 }, + { "Giant Squid", specs+53, N_S, 10, 30, 8, 0 } + }}, + { 7, 3, 6, 3, "Frigate Action", + { + { "Killdeer", specs+21, N_A, 7, 20, 8, 0 }, + { "Sandpiper", specs+27, N_B, 5, 40, 8, 0 }, + { "Curlew", specs+34, N_S, 10, 60, 8, 0 } + }}, + { 7, 2, 5, 6, "The Battle of Midway", + { + { "Enterprise", specs+49, N_A, 10, 70, 8, 0 }, + { "Yorktown", specs+51, N_A, 3, 70, 7, 0 }, + { "Hornet", specs+52, N_A, 6, 70, 7, 0 }, + { "Akagi", specs+53, N_J, 6, 10, 4, 0 }, + { "Kaga", specs+54, N_J, 4, 12, 4, 0 }, + { "Soryu", specs+55, N_J, 2, 14, 4, 0 } + }}, + { 1, 3, 4, 8, "Star Trek", + { + { "Enterprise", specs+76, N_D,-10, 60, 7, 0 }, + { "Yorktown", specs+77, N_D, 0, 70, 7, 0 }, + { "Reliant", specs+78, N_D, 10, 70, 7, 0 }, + { "Galileo", specs+79, N_D, 20, 60, 7, 0 }, + { "Kobayashi Maru", specs+80, N_K, 0,120, 7, 0 }, + { "Klingon II", specs+81, N_K, 10,120, 7, 0 }, + { "Red Orion", specs+82, N_O, 0, 0, 3, 0 }, + { "Blue Orion", specs+83, N_O, 10, 0, 3, 0 } + }}, +}; +int nscene = sizeof scene / sizeof (struct scenario); + +struct shipspecs specs[] = { +/* bs fs ta guns hull crew1 crew3 gunR carR rig2 rig4 pts */ +/* class qual crew2 gunL carL rig1 rig3 */ +/*00*/ { 4, 7, 3, 19, 5, 5, 4, 2, 2, 2, 2, 2, 0, 0, 4, 4, 4, 4, 7 }, +/*01*/ { 4, 7, 3, 17, 5, 5, 4, 2, 2, 2, 0, 0, 4, 4, 3, 3, 3, 3, 6 }, +/*02*/ { 3, 5, 2, 42, 4, 7, 4, 2, 2, 2, 2, 2, 0, 0, 5, 5, 5, -1, 11 }, +/*03*/ { 4, 6, 3, 44, 3, 7, 4, 2, 2, 2, 3, 3, 0, 0, 5, 5, 5, 5, 12 }, +/*04*/ { 3, 5, 2, 64, 2, 17, 4, 8, 6, 6, 12, 12, 2, 2, 7, 7, 7, -1, 20 }, +/*05*/ { 3, 5, 2, 74, 2, 20, 4, 8, 8, 8, 16, 16, 2, 2, 7, 7, 7, -1, 26 }, +/*06*/ { 3, 5, 2, 50, 2, 12, 4, 6, 4, 4, 8, 8, 2, 2, 6, 6, 6, -1, 17 }, +/*07*/ { 3, 5, 1, 98, 1, 23, 4, 10, 10, 10, 18, 18, 2, 2, 8, 8, 8, -1, 28 }, +/*08*/ { 3, 5, 2, 74, 2, 20, 4, 8, 8, 8, 16, 16, 2, 2, 7, 7, 7, -1, 26 }, +/*09*/ { 3, 5, 2, 74, 2, 21, 3, 10, 10, 8, 20, 20, 0, 0, 7, 7, 7, -1, 24 }, +/*10*/ { 3, 5, 1, 80, 1, 23, 3, 12, 12, 10, 22, 22, 0, 0, 7, 7, 7, -1, 27 }, +/*11*/ { 3, 5, 2, 64, 2, 18, 3, 8, 8, 6, 12, 12, 0, 0, 7, 7, 7, -1, 18 }, +/*12*/ { 3, 5, 2, 44, 2, 11, 3, 4, 4, 4, 6, 6, 2, 2, 5, 5, 5, -1, 10 }, +/*13*/ { 3, 5, 2, 50, 2, 14, 3, 6, 6, 4, 8, 8, 0, 0, 6, 6, 6, -1, 14 }, +/*14*/ { 4, 6, 3, 36, 3, 11, 4, 4, 4, 2, 4, 4, 2, 2, 5, 5, 5, 5, 11 }, +/*15*/ { 4, 6, 3, 36, 3, 11, 3, 4, 4, 4, 4, 4, 2, 2, 5, 5, 5, 5, 10 }, +/*16*/ { 3, 5, 2, 74, 2, 21, 4, 10, 8, 8, 18, 18, 2, 2, 7, 7, 7, -1, 26 }, +/*17*/ { 3, 5, 2, 74, 2, 21, 3, 10, 10, 8, 20, 20, 2, 2, 7, 7, 7, -1, 23 }, +/*18*/ { 4, 6, 3, 32, 3, 8, 3, 4, 2, 2, 4, 4, 2, 2, 5, 5, 5, 5, 9 }, +/*19*/ { 4, 6, 3, 24, 4, 6, 3, 4, 4, 4, 2, 2, 0, 0, 4, 4, 4, 4, 9 }, +/*20*/ { 4, 7, 3, 38, 4, 14, 5, 6, 4, 4, 4, 4, 6, 6, 5, 5, 5, 5, 17 }, +/*21*/ { 4, 6, 3, 40, 3, 15, 3, 8, 6, 6, 6, 6, 4, 4, 5, 5, 5, 5, 15 }, +/*22*/ { 4, 7, 3, 36, 4, 11, 3, 6, 6, 4, 4, 4, 2, 2, 5, 5, 5, 5, 11 }, +/*23*/ { 4, 6, 3, 32, 3, 11, 5, 4, 4, 2, 4, 4, 2, 2, 5, 5, 5, 5, 13 }, +/*24*/ { 4, 6, 3, 38, 3, 14, 5, 4, 4, 4, 6, 6, 4, 4, 5, 5, 5, 5, 18 }, +/*25*/ { 4, 6, 3, 22, 3, 6, 5, 2, 2, 2, 0, 0, 8, 8, 4, 4, 4, 4, 11 }, +/*26*/ { 4, 6, 3, 32, 3, 11, 5, 4, 4, 2, 4, 4, 2, 2, 5, 5, 5, 5, 13 }, +/*27*/ { 4, 6, 3, 40, 3, 14, 3, 6, 6, 4, 6, 6, 4, 4, 5, 5, 5, 5, 15 }, +/*28*/ { 4, 6, 3, 32, 3, 11, 2, 4, 4, 4, 4, 4, 0, 0, 5, 5, 5, 5, 9 }, +/*29*/ { 4, 6, 3, 40, 3, 14, 2, 6, 6, 4, 6, 6, 4, 4, 5, 5, 5, 5, 12 }, +/*30*/ { 4, 6, 3, 32, 3, 8, 2, 4, 4, 1, 2, 2, 0, 0, 4, 4, 4, 4, 7 }, +/*31*/ { 4, 7, 3, 44, 4, 18, 5, 6, 6, 6, 8, 8, 6, 6, 6, 6, 6, 6, 24 }, +/*32*/ { 4, 6, 3, 38, 3, 14, 4, 4, 4, 2, 6, 6, 4, 4, 5, 5, 5, 5, 15 }, +/*33*/ { 4, 5, 3, 44, 3, 18, 5, 8, 6, 6, 8, 8, 8, 8, 6, 6, 6, 6, 24 }, +/*34*/ { 4, 6, 3, 38, 3, 14, 4, 4, 4, 4, 6, 6, 4, 4, 5, 5, 5, 5, 16 }, +/*35*/ { 4, 7, 3, 38, 4, 14, 4, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 19 }, +/*36*/ { 4, 6, 3, 38, 3, 14, 3, 6, 6, 4, 6, 6, 6, 6, 5, 5, 5, 5, 14 }, +/*37*/ { 4, 6, 3, 38, 3, 14, 5, 6, 4, 4, 6, 6, 6, 6, 5, 5, 5, 5, 17 }, +/*38*/ { 4, 7, 3, 20, 5, 6, 4, 4, 2, 2, 0, 0, 6, 6, 4, 4, 4, 4, 9 }, +/*39*/ { 4, 7, 3, 13, 6, 3, 4, 0, 2, 2, 0, 0, 2, 2, 2, 2, 2, 2, 5 }, +/*40*/ { 4, 7, 3, 19, 5, 5, 4, 2, 2, 2, 2, 2, 0, 0, 4, 4, 4, 4, 7 }, +/*41*/ { 4, 7, 3, 17, 5, 5, 4, 2, 2, 2, 2, 2, 0, 0, 3, 3, 3, 3, 6 }, +/*42*/ { 4, 7, 3, 20, 5, 6, 5, 4, 2, 2, 0, 0, 6, 6, 4, 4, 4, 4, 12 }, +/*43*/ { 4, 7, 3, 18, 5, 5, 5, 2, 2, 2, 0, 0, 6, 6, 4, 4, 4, 4, 9 }, +/*44*/ { 4, 7, 3, 24, 5, 6, 4, 4, 2, 2, 0, 0,10,10, 4, 4, 4, 4, 11 }, +/*45*/ { 4, 7, 3, 20, 5, 6, 4, 2, 2, 2, 0, 0, 8, 8, 4, 4, 4, 4, 10 }, +/*46*/ { 4, 6, 3, 44, 3, 11, 5, 4, 4, 4, 4, 4, 2, 2, 5, 5, 5, 5, 14 }, +/*47*/ { 4, 6, 3, 36, 3, 12, 4, 4, 4, 4, 6, 6, 2, 2, 5, 5, 5, 5, 14 }, +/*48*/ { 3, 5, 2, 74, 2, 21, 3, 10, 8, 8, 20, 20, 2, 2, 4, 4, 7, -1, 24 }, +/*49*/ { 3, 5, 2, 80, 2, 24, 4, 10, 8, 8, 20, 20, 2, 2, 8, 8, 8, -1, 31 }, +/*50*/ { 3, 5, 2, 74, 2, 21, 4, 8, 8, 6, 16, 16, 4, 4, 7, 7, 7, -1, 27 }, +/*51*/ { 3, 5, 2, 80, 2, 24, 3, 12, 12, 10, 22, 22, 2, 2, 7, 7, 7, -1, 27 }, +/*52*/ { 3, 5, 2, 74, 2, 21, 3, 10, 10, 8, 20, 20, 2, 2, 7, 7, 7, -1, 24 }, +/*53*/ { 3, 5, 1, 112, 1, 27, 2, 12, 12, 12, 24, 24, 0, 0, 9, 9, 9, -1, 27 }, +/*54*/ { 3, 5, 1, 96, 1, 24, 2, 12, 12, 10, 20, 20, 0, 0, 8, 8, 8, -1, 24 }, +/*55*/ { 3, 5, 2, 80, 2, 23, 2, 10, 10, 8, 20, 20, 0, 0, 7, 7, 7, -1, 23 }, +/*56*/ { 3, 5, 2, 74, 2, 21, 2, 10, 8, 8, 16, 16, 4, 4, 7, 7, 7, -1, 20 }, +/*57*/ { 4, 6, 3, 37, 3, 12, 4, 4, 4, 2, 6, 6, 4, 4, 5, 5, 5, 5, 14 }, +/*58*/ { 4, 7, 3, 16, 5, 5, 5, 2, 2, 2, 0, 0, 4, 4, 4, 4, 4, 4, 10 }, +/*59*/ { 4, 7, 3, 11, 6, 3, 4, 2, 2, 2, 0, 0, 2, 2, 2, 2, 2, 2, 5 }, +/*60*/ { 4, 7, 3, 26, 5, 6, 4, 4, 2, 2, 2, 2, 6, 6, 4, 4, 4, 4, 12 }, +/*61*/ { 4, 7, 3, 20, 5, 6, 4, 4, 2, 2, 0, 0, 6, 6, 4, 4, 4, 4, 11 }, +/*62*/ { 4, 7, 3, 17, 5, 5, 4, 2, 2, 2, 0, 0, 6, 6, 4, 4, 4, 4, 9 }, +/*63*/ { 4, 7, 3, 7, 6, 3, 4, 0, 2, 2, 0, 0, 2, 2, 2, 2, 2, 2, 4 }, +/*64*/ { 4, 6, 3, 40, 3, 15, 4, 4, 4, 4, 8, 8, 6, 6, 5, 5, 5, 5, 17 }, +/*65*/ { 4, 6, 3, 44, 3, 15, 4, 8, 8, 6, 10, 10, 2, 2, 6, 6, 6, 6, 20 }, +/*66*/ { 4, 6, 3, 38, 3, 14, 4, 4, 4, 4, 6, 6, 6, 6, 5, 5, 5, 5, 15 }, +/*67*/ { 4, 5, 3, 44, 3, 18, 5, 8, 6, 6, 8, 8, 8, 8, 6, 6, 6, 6, 24 }, +/*68*/ { 4, 6, 3, 36, 3, 9, 5, 4, 4, 2, 4, 4, 2, 2, 5, 5, 5, 5, 13 }, +/*69*/ { 3, 5, 2, 50, 2, 14, 2, 6, 6, 6, 8, 8, 0, 0, 6, 6, 6, -1, 14 }, +/*70*/ { 3, 5, 1, 136, 1, 30, 1, 8, 14, 14, 28, 28, 0, 0, 9, 9, 9, -1, 27 }, +/*71*/ { 3, 5, 1, 120, 1, 27, 5, 16, 14, 14, 28, 28, 2, 2, 9, 9, 9, -1, 43 }, +/*72*/ { 3, 5, 1, 120, 2, 21, 5, 15, 17, 15, 25, 25, 7, 7, 9, 9, 9, -1, 36 }, +/*73*/ { 3, 5, 1, 90, 3, 18, 4, 13, 15, 13, 20, 20, 6, 6, 5, 5, 5, 5, 28 }, +/*74*/ { 4, 7, 3, 6, 6, 3, 4, 2, 2, 2, 20, 20, 6, 6, 2, 2, 3, 3, 5 }, +/*75*/ { 3, 5, 1, 110, 2, 20, 4, 14, 15, 11, 26, 26, 8, 8, 7, 8, 9, -1, 34 }, +/*76*/ { 4, 7, 3, 450, 1, 99, 5, 50, 40, 40, 50, 50,25,25, 9, 9, 9, -1, 75 }, +/*77*/ { 4, 7, 3, 450, 1, 99, 5, 50, 40, 40, 50, 50,25,25, 9, 9, 9, -1, 75 }, +/*78*/ { 4, 7, 3, 450, 1, 99, 5, 50, 40, 40, 50, 50,25,25, 9, 9, 9, -1, 75 }, +/*79*/ { 4, 7, 3, 450, 1, 99, 5, 50, 40, 40, 50, 50,25,25, 9, 9, 9, -1, 75 }, +/*80*/ { 4, 7, 3, 450, 1, 99, 5, 50, 40, 40, 50, 50,25,25, 9, 9, 9, -1, 75 }, +/*81*/ { 4, 7, 3, 450, 1, 99, 5, 50, 40, 40, 50, 50,25,25, 9, 9, 9, -1, 75 }, +/*82*/ { 4, 7, 3, 450, 1, 99, 5, 50, 40, 40, 50, 50,25,25, 9, 9, 9, -1, 75 }, +/*83*/ { 4, 7, 3, 450, 1, 99, 5, 50, 40, 40, 50, 50,25,25, 9, 9, 9, -1, 75 }, +/* bs fs ta guns hull crew1 crew3 gunR carR rig2 rig4 pts */ +/* class qual crew2 gunL carL rig1 rig3 */ +}; + +struct windeffects WET[7][6] = { + { {9,9,9,9}, {9,9,9,9}, {9,9,9,9}, {9,9,9,9}, {9,9,9,9}, {9,9,9,9} }, + { {3,2,2,0}, {3,2,1,0}, {3,2,1,0}, {3,2,1,0}, {2,1,0,0}, {2,1,0,0} }, + { {1,1,1,0}, {1,1,0,0}, {1,0,0,0}, {1,0,0,0}, {1,0,0,0}, {1,0,0,0} }, + { {0,0,0,0}, {0,0,0,0}, {0,0,0,0}, {0,0,0,0}, {0,0,0,0}, {0,0,0,0} }, + { {0,0,0,0}, {1,0,0,0}, {1,1,0,0}, {1,1,0,0}, {2,2,1,0}, {2,2,1,0} }, + { {1,0,0,0}, {1,1,0,0}, {1,1,1,0}, {1,1,1,0}, {3,2,2,0}, {3,2,2,0} }, + { {2,1,1,0}, {3,2,1,0}, {3,2,1,0}, {3,2,1,0}, {3,3,2,0}, {3,3,2,0} } +}; + +struct Tables RigTable[11][6] = { + { {0,0,0,0}, {0,0,0,0}, {0,0,0,0}, {0,0,0,0}, {0,0,0,1}, {0,0,1,0} }, + { {0,0,0,0}, {0,0,0,0}, {0,0,0,1}, {0,0,1,0}, {1,0,0,1}, {0,1,1,1} }, + { {0,0,0,0}, {0,0,0,1}, {0,0,1,1}, {0,1,0,1}, {0,1,0,1}, {1,0,1,2} }, + { {0,0,0,0}, {0,0,1,1}, {0,1,0,1}, {0,0,0,2}, {0,1,0,2}, {1,0,1,2} }, + { {0,1,0,1}, {1,0,0,1}, {0,1,1,2}, {0,1,0,2}, {0,0,1,3}, {1,0,1,4} }, + { {0,0,1,1}, {0,1,0,2}, {1,0,0,3}, {0,1,1,3}, {1,0,0,4}, {1,1,1,4} }, + { {0,0,1,2}, {0,1,1,2}, {1,1,0,3}, {0,1,0,4}, {1,0,0,4}, {1,0,1,5} }, + { {0,0,1,2}, {0,1,0,3}, {1,1,0,3}, {1,0,2,4}, {0,2,1,5}, {2,1,0,5} }, + { {0,2,1,3}, {1,0,0,3}, {2,1,0,4}, {0,1,1,4}, {0,1,0,5}, {1,0,2,6} }, + { {1,1,0,4}, {1,0,1,4}, {2,0,0,5}, {0,2,1,5}, {0,1,2,6}, {0,2,0,7} }, + { {1,0,1,5}, {0,2,0,6}, {1,2,0,6}, {1,1,1,6}, {2,0,2,6}, {1,1,2,7} } +}; +struct Tables HullTable[11][6] = { + { {0,0,0,0}, {0,0,0,0}, {0,0,0,0}, {0,0,0,0}, {1,0,0,0}, {0,1,0,0} }, + { {0,0,0,0}, {0,0,0,0}, {0,1,0,0}, {1,1,0,0}, {1,0,1,0}, {1,0,1,1} }, + { {0,1,0,0}, {1,0,0,0}, {1,1,0,0}, {1,0,1,0}, {1,0,1,1}, {2,1,0,0} }, + { {0,1,1,0}, {1,0,0,0}, {1,1,1,0}, {2,0,0,1}, {2,0,1,0}, {2,2,0,0} }, + { {0,1,1,0}, {1,0,0,1}, {2,1,0,1}, {2,2,1,0}, {3,0,1,0}, {3,1,0,0} }, + { {1,1,1,0}, {2,0,2,1}, {2,1,1,0}, {2,2,0,0}, {3,1,0,1}, {3,1,1,0} }, + { {1,2,2,0}, {2,0,2,1}, {2,1,0,1}, {2,2,0,0}, {3,1,1,0}, {4,2,1,0} }, + { {2,1,1,0}, {2,0,1,1}, {3,2,2,0}, {3,2,0,0}, {4,2,1,0}, {4,2,1,1} }, + { {2,1,2,0}, {3,1,1,1}, {3,2,2,0}, {4,2,1,0}, {4,1,0,2}, {4,2,2,0} }, + { {2,3,1,0}, {3,2,2,0}, {3,2,2,1}, {4,2,2,0}, {4,1,0,3}, {5,1,2,0} }, + { {2,2,4,0}, {3,3,1,1}, {4,2,1,1}, {5,1,0,2}, {5,1,2,1}, {6,2,2,0} }, +}; + +char AMMO[9][4] = { + { -1, 1, 0, 1 }, + { -1, 1, 0, 1 }, + { -1, 1, 0, 1 }, + { -2, 1, 0, 2 }, + { -2, 2, 0, 2 }, + { -2, 2, 0, 2 }, + { -3, 2, 0, 2 }, + { -3, 2, 0, 3 }, + { -3, 2, 0, 3 } +}; + +char HDT[9][10] = { + { 1, 0,-1,-2,-3,-3,-4,-4,-4,-4 }, + { 1, 1, 0,-1,-2,-2,-3,-3,-3,-3 }, + { 2, 1, 0,-1,-2,-2,-3,-3,-3,-3 }, + { 2, 2, 1, 0,-1,-1,-2,-2,-2,-2 }, + { 3, 2, 1, 0,-1,-1,-2,-2,-2,-2 }, + { 3, 3, 2, 1, 0, 0,-1,-1,-1,-1 }, + { 4, 3, 2, 1, 0, 0,-1,-1,-1,-1 }, + { 4, 4, 3, 2, 1, 1, 0, 0, 0, 0 }, + { 5, 4, 3, 2, 1, 1, 0, 0, 0, 0 } +}; + +char HDTrake[9][10] = { + { 2, 1, 0,-1,-2,-2,-3,-3,-3,-3 }, + { 2, 2, 1, 0,-1,-1,-2,-2,-2,-2 }, + { 3, 2, 1, 0,-1,-1,-2,-2,-2,-2 }, + { 4, 3, 2, 1, 0, 0,-1,-1,-1,-1 }, + { 5, 4, 3, 2, 1, 1, 0, 0, 0, 0 }, + { 6, 5, 4, 3, 2, 2, 1, 1, 1, 1 }, + { 7, 6, 5, 4, 3, 3, 2, 2, 2, 2 }, + { 8, 7, 6, 5, 4, 4, 3, 3, 3, 3 }, + { 9, 8, 7, 6, 5, 5, 4, 4, 4, 4 } +}; + +char QUAL[9][5] = { + { -1, 0, 0, 1, 1 }, + { -1, 0, 0, 1, 1 }, + { -1, 0, 0, 1, 2 }, + { -1, 0, 0, 1, 2 }, + { -1, 0, 0, 2, 2 }, + { -1,-1, 0, 2, 2 }, + { -2,-1, 0, 2, 2 }, + { -2,-1, 0, 2, 2 }, + { -2,-1, 0, 2, 3 } +}; + +char MT[9][3] = { + { 1, 0, 0 }, + { 1, 1, 0 }, + { 2, 1, 0 }, + { 2, 1, 1 }, + { 2, 2, 1 }, + { 3, 2, 1 }, + { 3, 2, 2 }, + { 4, 3, 2 }, + { 4, 4, 2 } +}; + +char rangeofshot[] = { + 0, + 1, /* grape */ + 3, /* chain */ + 10, /* round */ + 1 /* double */ +}; + +char *countryname[] = { + "American", "British", "Spanish", "French", "Japanese", + "Federation", "Klingon", "Orion" +}; + +char *classname[] = { + "Drift wood", + "Ship of the Line", + "Ship of the Line", + "Frigate", + "Corvette", + "Sloop", + "Brig" +}; + +char *directionname[] = { + "dead ahead", + "off the starboard bow", + "off the starboard beam", + "off the starboard quarter", + "dead astern", + "off the port quarter", + "off the port beam", + "off the port bow", + "dead ahead" +}; + +char *qualname[] = { "dead", "mutinous", "green", "mundane", "crack", "elite" }; + +char loadname[] = { '-', 'G', 'C', 'R', 'D', 'E' }; + +char dr[] = { 0, 1, 1, 0, -1, -1, -1, 0, 1 }; +char dc[] = { 0, 0, -1, -1, -1, 0, 1, 1, 1 }; diff --git a/src/games/sail/lo_main.c b/src/games/sail/lo_main.c new file mode 100644 index 0000000..dbe4d4f --- /dev/null +++ b/src/games/sail/lo_main.c @@ -0,0 +1,62 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +/* + * Print out the top ten SAILors + * + * -l force a long listing (print out real usernames) + */ +#include +#include "externs.h" + +char *title[] = { + "Admiral", "Commodore", "Captain", "Captain", + "Captain", "Captain", "Captain", "Commander", + "Commander", "Lieutenant" +}; + +int +lo_main() +{ + FILE *fp; + char sbuf[32]; + int n = 0, people; + struct passwd *getpwuid(), *pass; + struct logs log; + struct ship *ship; + + if ((fp = fopen(LOGFILE, "r")) == 0) { + perror(LOGFILE); + exit(1); + } + switch (fread((char *)&people, sizeof people, 1, fp)) { + case 0: + printf("Nobody has sailed yet.\n"); + exit(0); + case 1: + break; + default: + perror(LOGFILE); + exit(1); + } + while (fread((char *)&log, sizeof log, 1, fp) == 1 && + log.l_name[0] != '\0') { + int equiv; + + if (longfmt && (pass = getpwuid(log.l_uid)) != NULL) + (void) sprintf(sbuf, "%10.10s (%s)", + log.l_name, pass->pw_name); + else + (void) sprintf(sbuf, "%20.20s", log.l_name); + ship = &scene[log.l_gamenum].ship[log.l_shipnum]; + equiv = 100 * log.l_netpoints / ship->specs->pts; + printf("%-10s %21s of the %15s %3d points, %d.%02d equiv\n", + title[n++], sbuf, ship->shipname, log.l_netpoints, + equiv / 100, equiv % 100); + } + printf("\n%d people have played.\n", people); + return 0; +} diff --git a/src/games/sail/machdep.h b/src/games/sail/machdep.h new file mode 100644 index 0000000..6b02191 --- /dev/null +++ b/src/games/sail/machdep.h @@ -0,0 +1,11 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + * + * @(#)machdep.h 5.1.1 (2.11BSD) 1997/9/9 + */ + +#define LOGFILE "/usr/games/lib/saillog" /* has to match the makefile */ + +#define TIMEOUT 300 /* Sync() timeout in seconds */ diff --git a/src/games/sail/main.c b/src/games/sail/main.c new file mode 100644 index 0000000..8a13ca5 --- /dev/null +++ b/src/games/sail/main.c @@ -0,0 +1,102 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "externs.h" + +/*ARGSUSED*/ +int +main(argc, argv) + int argc; + register char **argv; +{ + register char *p; + int i; + char stdobuf[BUFSIZ]; + + setbuf(stdout, stdobuf); + (void) srand(getpid()); + issetuid = getuid() != geteuid(); + p = strrchr(*argv, '/'); + if (p) + p++; + else + p = *argv; + if (strcmp(p, "driver") == 0 || strcmp(p, "saildriver") == 0) + mode = MODE_DRIVER; + else if (strcmp(p, "sail.log") == 0) + mode = MODE_LOGGER; + else + mode = MODE_PLAYER; + while ((p = *++argv) && *p == '-') + switch (p[1]) { + case 'd': + mode = MODE_DRIVER; + break; + case 's': + mode = MODE_LOGGER; + break; + case 'D': + debug++; + break; + case 'x': + randomize++; + break; + case 'l': + longfmt++; + break; + case 'b': + nobells++; + break; + default: + fprintf(stderr, "SAIL: Unknown flag %s.\n", p); + exit(1); + } + if (*argv) + game = atoi(*argv); + else + game = -1; + i = setjmp(restart); + if (i) + mode = i; + switch (mode) { + case MODE_PLAYER: + return pl_main(); + case MODE_DRIVER: + return dr_main(); + case MODE_LOGGER: + return lo_main(); + default: + fprintf(stderr, "SAIL: Unknown mode %d.\n", mode); + abort(); + } + /*NOTREACHED*/ +} + +/* + * These used to be macros in machdep.h. The macros were wrong (didn't use + * sigmask() and thus only computed 16 bit signal masks). The signal handling + * in 2.11BSD is now that of 4.4BSD and the macros were fixed (i.e. rewritten) + * and made into routines to avoid the plethora of inline 'long' operations. + */ +void +blockalarm() +{ + sigset_t set; + + sigemptyset(&set); + sigaddset(&set, SIGALRM); + + (void)sigprocmask(SIG_BLOCK, &set, NULL); +} + +void +unblockalarm() +{ + sigset_t set; + + sigemptyset(&set); + sigaddset(&set, SIGALRM); + (void)sigprocmask(SIG_UNBLOCK, &set, NULL); +} diff --git a/src/games/sail/misc.c b/src/games/sail/misc.c new file mode 100644 index 0000000..8020192 --- /dev/null +++ b/src/games/sail/misc.c @@ -0,0 +1,207 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "externs.h" + +#define distance(x,y) (abs(x) >= abs(y) ? abs(x) + abs(y)/2 : abs(y) + abs(x)/2) + +/* XXX */ +int +range(from, to) + struct ship *from, *to; +{ + register int bow1r, bow1c, bow2r, bow2c; + int stern1r, stern1c, stern2c, stern2r; + register int bb, bs, sb, ss, result; + + if (!to->file->dir) + return -1; + stern1r = bow1r = from->file->row; + stern1c = bow1c = from->file->col; + stern2r = bow2r = to->file->row; + stern2c = bow2c = to->file->col; + result = bb = distance(bow2r - bow1r, bow2c - bow1c); + if (bb < 5) { + stern2r += dr[(int)to->file->dir]; + stern2c += dc[(int)to->file->dir]; + stern1r += dr[(int)from->file->dir]; + stern1c += dc[(int)from->file->dir]; + bs = distance((bow2r - stern1r), (bow2c - stern1c)); + sb = distance((bow1r - stern2r), (bow1c - stern2c)); + ss = distance((stern2r - stern1r) ,(stern2c - stern1c)); + result = min(bb, min(bs, min(sb, ss))); + } + return result; +} + +struct ship * +closestenemy(from, side, anyship) + register struct ship *from; + int side, anyship; +{ + register struct ship *sp; + register char a; + int olddist = 30000, dist; + struct ship *closest = 0; + + a = capship(from)->nationality; + foreachship(sp) { + if (sp == from) + continue; + if (sp->file->dir == 0) + continue; + if (a == capship(sp)->nationality && !anyship) + continue; + if (side && gunsbear(from, sp) != side) + continue; + dist = range(from, sp); + if (dist < olddist) { + closest = sp; + olddist = dist; + } + } + return closest; +} + +int +angle(dr, dc) + register int dr, dc; +{ + register int i; + + if (dc >= 0 && dr > 0) + i = 0; + else if (dr <= 0 && dc > 0) + i = 2; + else if (dc <= 0 && dr < 0) + i = 4; + else + i = 6; + dr = abs(dr); + dc = abs(dc); + if ((i == 0 || i == 4) && dc * 2.4 > dr) { + i++; + if (dc > dr * 2.4) + i++; + } else if ((i == 2 || i == 6) && dr * 2.4 > dc) { + i++; + if (dr > dc * 2.4) + i++; + } + return i % 8 + 1; +} + +int +gunsbear(from, to) /* checks for target bow or stern */ + register struct ship *from, *to; +{ + int Dr, Dc, i; + register int ang; + + Dr = from->file->row - to->file->row; + Dc = to->file->col - from->file->col; + for (i = 2; i; i--) { + if ((ang = angle(Dr, Dc) - from->file->dir + 1) < 1) + ang += 8; + if (ang >= 2 && ang <= 4) + return 'r'; + if (ang >= 6 && ang <= 7) + return 'l'; + Dr += dr[(int)to->file->dir]; + Dc += dc[(int)to->file->dir]; + } + return 0; +} + +int +portside(from, on, quick) + register struct ship *from, *on; + int quick; /* returns true if fromship is */ +{ /* shooting at onship's starboard side */ + register int ang; + register int Dr, Dc; + + Dr = from->file->row - on->file->row; + Dc = on->file->col - from->file->col; + if (quick == -1) { + Dr += dr[(int)on->file->dir]; + Dc += dc[(int)on->file->dir]; + } + ang = angle(Dr, Dc); + if (quick != 0) + return ang; + ang = (ang + 4 - on->file->dir - 1) % 8 + 1; + return ang < 5; +} + +int +colours(sp) + register struct ship *sp; +{ + register char flag; + + if (sp->file->struck) + flag = '!'; + if (sp->file->explode) + flag = '#'; + if (sp->file->sink) + flag = '~'; + if (sp->file->struck) + return flag; + flag = *countryname[(int)capship(sp)->nationality]; + return sp->file->FS ? flag : tolower(flag); +} + +#include + +void +logmsg(s) + register struct ship *s; +{ + FILE *fp; + int persons; + int n; + struct logs log[NLOG]; + float net; + register struct logs *lp; + + if ((fp = fopen(LOGFILE, "r+")) == NULL) + return; +#ifdef LOCK_EX + if (flock(fileno(fp), LOCK_EX) < 0) + return; +#endif + net = (float)s->file->points / s->specs->pts; + persons = getw(fp); + n = fread((char *)log, sizeof(struct logs), NLOG, fp); + for (lp = &log[n]; lp < &log[NLOG]; lp++) + lp->l_name[0] = lp->l_uid = lp->l_shipnum + = lp->l_gamenum = lp->l_netpoints = 0; + rewind(fp); + if (persons < 0) + (void) putw(1, fp); + else + (void) putw(persons + 1, fp); + for (lp = log; lp < &log[NLOG]; lp++) + if (net > (float)lp->l_netpoints + / scene[lp->l_gamenum].ship[lp->l_shipnum].specs->pts) { + (void) fwrite((char *)log, + sizeof (struct logs), lp - log, fp); + (void) strcpy(log[NLOG-1].l_name, s->file->captain); + log[NLOG-1].l_uid = getuid(); + log[NLOG-1].l_shipnum = s->file->index; + log[NLOG-1].l_gamenum = game; + log[NLOG-1].l_netpoints = s->file->points; + (void) fwrite((char *)&log[NLOG-1], + sizeof (struct logs), 1, fp); + (void) fwrite((char *)lp, + sizeof (struct logs), &log[NLOG-1] - lp, fp); + break; + } +#ifdef LOCK_EX + (void) flock(fileno(fp), LOCK_UN); +#endif + (void) fclose(fp); +} diff --git a/src/games/sail/parties.c b/src/games/sail/parties.c new file mode 100644 index 0000000..6923976 --- /dev/null +++ b/src/games/sail/parties.c @@ -0,0 +1,47 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "externs.h" + +int +meleeing(from, to) + struct ship *from; + register struct ship *to; +{ + register struct BP *p = from->file->OBP; + register struct BP *q = p + NBP; + + for (; p < q; p++) + if (p->turnsent && p->toship == to) + return 1; + return 0; +} + +int +boarding(from, isdefense) + register struct ship *from; + int isdefense; +{ + register struct BP *p = isdefense ? from->file->DBP : from->file->OBP; + register struct BP *q = p + NBP; + + for (; p < q; p++) + if (p->turnsent) + return 1; + return 0; +} + +void +unboard(ship, to, isdefense) + register struct ship *ship, *to; + register int isdefense; +{ + register struct BP *p = isdefense ? ship->file->DBP : ship->file->OBP; + register int n; + + for (n = 0; n < NBP; p++, n++) + if (p->turnsent && (p->toship == to || isdefense || ship == to)) + Write(isdefense ? W_DBP : W_OBP, ship, 0, n, 0, 0, 0); +} diff --git a/src/games/sail/pl_1.c b/src/games/sail/pl_1.c new file mode 100644 index 0000000..369b792 --- /dev/null +++ b/src/games/sail/pl_1.c @@ -0,0 +1,104 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "player.h" +#include +#include + +/* + * If we get here before a ship is chosen, then ms == 0 and + * we don't want to update the score file, or do any Write's either. + * We can assume the sync file is already created and may need + * to be removed. + * Of course, we don't do any more Sync()'s if we got here + * because of a Sync() failure. + */ +void +leave(conditions) + int conditions; +{ + (void) signal(SIGHUP, SIG_IGN); + (void) signal(SIGINT, SIG_IGN); + (void) signal(SIGQUIT, SIG_IGN); + (void) signal(SIGALRM, SIG_IGN); + (void) signal(SIGCHLD, SIG_IGN); + + if (done_curses) { + Signal("It looks like you've had it!", + (struct ship *)0, 0, 0, 0, 0); + switch (conditions) { + case LEAVE_QUIT: + break; + case LEAVE_CAPTURED: + Signal("Your ship was captured.", + (struct ship *)0, 0, 0, 0, 0); + break; + case LEAVE_HURRICAN: + Signal("Hurricane! All ships destroyed.", + (struct ship *)0, 0, 0, 0, 0); + break; + case LEAVE_DRIVER: + Signal("The driver died.", (struct ship *)0, 0, 0, 0, 0); + break; + case LEAVE_SYNC: + Signal("Synchronization error.", (struct ship *)0, 0, 0, 0, 0); + break; + default: + Signal("A funny thing happened (%d).", + (struct ship *)0, conditions, 0, 0, 0); + } + } else { + switch (conditions) { + case LEAVE_QUIT: + break; + case LEAVE_DRIVER: + printf("The driver died.\n"); + break; + case LEAVE_FORK: + perror("fork"); + break; + case LEAVE_SYNC: + printf("Synchronization error\n."); + break; + default: + printf("A funny thing happened (%d).\n", + conditions); + } + } + + if (ms != 0) { + logmsg(ms); + if (conditions != LEAVE_SYNC) { + makesignal(ms, "Captain %s relinquishing.", + (struct ship *)0, (int)mf->captain, 0, 0); + Write(W_END, ms, 0, 0, 0, 0, 0); + (void) Sync(); + } + } + sync_close(!hasdriver); + cleanupscreen(); + exit(0); +} + +void +choke(int sig) +{ + leave(LEAVE_QUIT); +} + +void +child(int sig) +{ + int status; + int pid; + + (void) signal(SIGCHLD, SIG_IGN); + do { + pid = wait3(&status, WNOHANG, (struct rusage *)0); + if (pid < 0 || (pid > 0 && !WIFSTOPPED(status))) + hasdriver = 0; + } while (pid > 0); + (void) signal(SIGCHLD, child); +} diff --git a/src/games/sail/pl_2.c b/src/games/sail/pl_2.c new file mode 100644 index 0000000..daeaa4e --- /dev/null +++ b/src/games/sail/pl_2.c @@ -0,0 +1,123 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "player.h" + +void +play() +{ + register struct ship *sp; + + for (;;) { + switch (sgetch("~\b", (struct ship *)0, 0)) { + case 'm': + acceptmove(); + break; + case 's': + acceptsignal(); + break; + case 'g': + grapungrap(); + break; + case 'u': + unfoulplayer(); + break; + case 'v': + Signal("%s", (struct ship *)0, (int)version, 0, 0, 0); + break; + case 'b': + acceptboard(); + break; + case 'f': + acceptcombat(); + break; + case 'l': + loadplayer(); + break; + case 'c': + changesail(); + break; + case 'r': + repair(); + break; + case 'B': + Signal("'Hands to stations!'", (struct ship *)0, 0, 0, 0, 0); + unboard(ms, ms, 1); /* cancel DBP's */ + unboard(ms, ms, 0); /* cancel offense */ + break; + case '\f': + centerview(); + blockalarm(); + draw_board(); + draw_screen(); + unblockalarm(); + break; + case 'L': + mf->loadL = L_EMPTY; + mf->loadR = L_EMPTY; + mf->readyL = R_EMPTY; + mf->readyR = R_EMPTY; + Signal("Broadsides unloaded", (struct ship *)0, 0, 0, 0, 0); + break; + case 'q': + Signal("Type 'Q' to quit", (struct ship *)0, 0, 0, 0, 0); + break; + case 'Q': + leave(LEAVE_QUIT); + break; + case 'I': + foreachship(sp) + if (sp != ms) + eyeball(sp); + break; + case 'i': + if ((sp = closestenemy(ms, 0, 1)) == 0) + Signal("No more ships left.", (struct ship *)0, 0, 0, 0, 0); + else + eyeball(sp); + break; + case 'C': + centerview(); + blockalarm(); + draw_view(); + unblockalarm(); + break; + case 'U': + upview(); + blockalarm(); + draw_view(); + unblockalarm(); + break; + case 'D': + case 'N': + downview(); + blockalarm(); + draw_view(); + unblockalarm(); + break; + case 'H': + leftview(); + blockalarm(); + draw_view(); + unblockalarm(); + break; + case 'J': + rightview(); + blockalarm(); + draw_view(); + unblockalarm(); + break; + case 'F': + lookout(); + break; + case 'S': + dont_adjust = !dont_adjust; + blockalarm(); + draw_turn(); + unblockalarm(); + break; + } + } +} diff --git a/src/games/sail/pl_3.c b/src/games/sail/pl_3.c new file mode 100644 index 0000000..7ef433a --- /dev/null +++ b/src/games/sail/pl_3.c @@ -0,0 +1,247 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "player.h" + +void +acceptcombat() +{ + int men = 0; + int target, temp; + int n, r; + int index, rakehim, sternrake; + int hhits = 0, ghits = 0, rhits = 0, chits = 0; + int crew[3]; + int load; + int guns, car, ready, shootat, hit; + int roll; + struct ship *closest; + + crew[0] = mc->crew1; + crew[1] = mc->crew2; + crew[2] = mc->crew3; + for (n = 0; n < 3; n++) { + if (mf->OBP[n].turnsent) + men += mf->OBP[n].mensent; + } + for (n = 0; n < 3; n++) { + if (mf->DBP[n].turnsent) + men += mf->DBP[n].mensent; + } + if (men) { + crew[0] = men/100 ? 0 : crew[0] != 0; + crew[1] = (men%100)/10 ? 0 : crew[1] != 0; + crew[2] = men%10 ? 0 : crew[2] != 0; + } + for (r = 0; r < 2; r++) { + if (r) { + ready = mf->readyR; + load = mf->loadR; + guns = mc->gunR; + car = mc->carR; + } else { + ready = mf->readyL; + load = mf->loadL; + guns = mc->gunL; + car = mc->carL; + } + if ((!guns && !car) || load == L_EMPTY || (ready & R_LOADED) == 0) + goto cant; + if (mf->struck || !crew[2]) + goto cant; + closest = closestenemy(ms, (r ? 'r' : 'l'), 1); + if (closest == 0) + goto cant; + if (closest->file->struck) + goto cant; + target = range(ms, closest); + if (target > rangeofshot[load] || (!guns && target >= 3)) + goto cant; + Signal("%s (%c%c) within range of %s broadside.", + closest, (int) (r ? "right" : "left"), 0, 0, 0); + if (load > L_CHAIN && target < 6) { + switch (sgetch("Aim for hull or rigging? ", + (struct ship *)0, 1)) { + case 'r': + shootat = RIGGING; + break; + case 'h': + shootat = HULL; + break; + default: + shootat = -1; + Signal("'Avast there! Hold your fire.'", + (struct ship *)0, 0, 0, 0, 0); + } + } else { + if (sgetch("Fire? ", (struct ship *)0, 1) == 'n') { + shootat = -1; + Signal("Belay that! Hold your fire.", + (struct ship *)0, 0, 0, 0, 0); + } else + shootat = RIGGING; + } + if (shootat == -1) + continue; + fired = 1; + rakehim = gunsbear(ms, closest) && !gunsbear(closest, ms); + temp = portside(closest, ms, 1) - closest->file->dir + 1; + if (temp < 1) + temp += 8; + else if (temp > 8) + temp -= 8; + sternrake = temp > 4 && temp < 6; + if (rakehim) { + if (!sternrake) + Signal("Raking the %s!", closest, 0, 0, 0, 0); + else + Signal("Stern Rake! %s splintering!", closest, 0, 0, 0, 0); + } + index = guns; + if (target < 3) + index += car; + index = (index - 1)/3; + index = index > 8 ? 8 : index; + if (!rakehim) + hit = HDT[index][target-1]; + else + hit = HDTrake[index][target-1]; + if (rakehim && sternrake) + hit++; + hit += QUAL[index][mc->qual-1]; + for (n = 0; n < 3 && mf->captured == 0; n++) + if (!crew[n]) { + if (index <= 5) + hit--; + else + hit -= 2; + } + if (ready & R_INITIAL) { + if (index <= 3) + hit++; + else + hit += 2; + } + if (mf->captured != 0) { + if (index <= 1) + hit--; + else + hit -= 2; + } + hit += AMMO[index][load - 1]; + if (((temp = mc->class) >= 5 || temp == 1) && windspeed == 5) + hit--; + if (windspeed == 6 && temp == 4) + hit -= 2; + if (windspeed == 6 && temp <= 3) + hit--; + if (hit >= 0) { + roll = die(); + if (load == L_GRAPE) + chits = hit; + else { + struct Tables *t; + if (hit > 10) + hit = 10; + t = &(shootat == RIGGING ? RigTable : HullTable) + [hit][roll-1]; + chits = t->C; + rhits = t->R; + hhits = t->H; + ghits = t->G; + if (closest->file->FS) + rhits *= 2; + if (load == L_CHAIN) { + ghits = 0; + hhits = 0; + } + } + table(shootat, load, hit, closest, ms, roll); + } + Signal("Damage inflicted on the %s:", + (struct ship *)0, (int)closest->shipname, 0, 0, 0); + Signal("\t%d HULL, %d GUNS, %d CREW, %d RIGGING", + (struct ship *)0, hhits, ghits, chits, rhits); + if (!r) { + mf->loadL = L_EMPTY; + mf->readyL = R_EMPTY; + } else { + mf->loadR = L_EMPTY; + mf->readyR = R_EMPTY; + } + continue; + cant: + Signal("Unable to fire %s broadside", + (struct ship *)0, (int) (r ? "right" : "left"), 0, 0, 0); + } + blockalarm(); + draw_stat(); + unblockalarm(); +} + +void +grapungrap() +{ + register struct ship *sp; + register int i; + + foreachship(sp) { + if (sp == ms || sp->file->dir == 0) + continue; + if (range(ms, sp) > 1 && !grappled2(ms, sp)) + continue; + switch (sgetch("Attempt to grapple or ungrapple %s (%c%c): ", + sp, 1)) { + case 'g': + if (die() < 3 + || ms->nationality == capship(sp)->nationality) { + Write(W_GRAP, ms, 0, sp->file->index, 0, 0, 0); + Write(W_GRAP, sp, 0, player, 0, 0, 0); + Signal("Attempt succeeds!", (struct ship *)0, 0, 0, 0, 0); + makesignal(ms, "grappled with %s (%c%c)", sp, 0, 0, 0); + } else + Signal("Attempt fails.", (struct ship *)0, 0, 0, 0, 0); + break; + case 'u': + for (i = grappled2(ms, sp); --i >= 0;) { + if (ms->nationality + == capship(sp)->nationality + || die() < 3) { + cleangrapple(ms, sp, 0); + Signal("Attempt succeeds!", + (struct ship *)0, 0, 0, 0, 0); + makesignal(ms, + "ungrappling with %s (%c%c)", + sp, 0, 0, 0); + } else + Signal("Attempt fails.", + (struct ship *)0, 0, 0, 0, 0); + } + break; + } + } +} + +void +unfoulplayer() +{ + register struct ship *to; + register int i; + + foreachship(to) { + if (fouled2(ms, to) == 0) + continue; + if (sgetch("Attempt to unfoul with the %s (%c%c)? ", to, 1) != 'y') + continue; + for (i = fouled2(ms, to); --i >= 0;) { + if (die() <= 2) { + cleanfoul(ms, to, 0); + Signal("Attempt succeeds!", (struct ship *)0, 0, 0, 0, 0); + makesignal(ms, "Unfouling %s (%c%c)", to, 0, 0, 0); + } else + Signal("Attempt fails.", (struct ship *)0, 0, 0, 0, 0); + } + } +} diff --git a/src/games/sail/pl_4.c b/src/games/sail/pl_4.c new file mode 100644 index 0000000..d39a5ca --- /dev/null +++ b/src/games/sail/pl_4.c @@ -0,0 +1,101 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "player.h" + +void +changesail() +{ + int rig, full; + + rig = mc->rig1; + full = mf->FS; + if (windspeed == 6 || (windspeed == 5 && mc->class > 4)) + rig = 0; + if (mc->crew3 && rig) { + if (!full) { + if (sgetch("Increase to Full sails? ", + (struct ship *)0, 1) == 'y') { + changed = 1; + Write(W_FS, ms, 0, 1, 0, 0, 0); + } + } else { + if (sgetch("Reduce to Battle sails? ", + (struct ship *)0, 1) == 'y') { + Write(W_FS, ms, 0, 0, 0, 0, 0); + changed = 1; + } + } + } else if (!rig) + Signal("Sails rent to pieces", (struct ship *)0, 0, 0, 0, 0); +} + +void +acceptsignal() +{ + char buf[60]; + register char *p = buf; + + *p++ = '"'; + sgetstr("Message? ", p, sizeof buf - 2); + while (*p++) + ; + p[-1] = '"'; + *p = 0; + Write(W_SIGNAL, ms, 1, (int)buf, 0, 0, 0); +} + +void +lookout() +{ + register struct ship *sp; + char buf[3]; + register char c; + + sgetstr("What ship? ", buf, sizeof buf); + foreachship(sp) { + c = *countryname[(int)sp->nationality]; + if ((c == *buf || tolower(c) == *buf || colours(sp) == *buf) + && (sp->file->stern == buf[1] || sterncolour(sp) == buf[1] + || buf[1] == '?')) { + eyeball(sp); + } + } +} + +char * +saywhat(sp, flag) + register struct ship *sp; + int flag; +{ + if (sp->file->captain[0]) + return sp->file->captain; + else if (sp->file->struck) + return "(struck)"; + else if (sp->file->captured != 0) + return "(captured)"; + else if (flag) + return "(available)"; + else + return "(computer)"; +} + +void +eyeball(ship) + register struct ship *ship; +{ + int i; + + if (ship->file->dir != 0) { + Signal("Sail ho! (range %d, %s)", + (struct ship *)0, range(ms, ship), (int)saywhat(ship, 0), 0, 0); + i = portside(ms, ship, 1) - mf->dir; + if (i <= 0) + i += 8; + Signal("%s (%c%c) %s %s %s.", + ship, (int)countryname[(int)ship->nationality], + (int)classname[(int)ship->specs->class], (int)directionname[i], 0); + } +} diff --git a/src/games/sail/pl_5.c b/src/games/sail/pl_5.c new file mode 100644 index 0000000..e7ba6fc --- /dev/null +++ b/src/games/sail/pl_5.c @@ -0,0 +1,225 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "player.h" + +#define turnfirst(x) (*x == 'r' || *x == 'l') + +void +acceptmove() +{ + int ta; + int ma; + char af; + int moved = 0; + int vma, dir; + char prompt[60]; + char buf[60], last = '\0'; + register char *p; + + if (!mc->crew3 || snagged(ms) || !windspeed) { + Signal("Unable to move", (struct ship *)0, 0, 0, 0, 0); + return; + } + + ta = maxturns(ms, &af); + ma = maxmove(ms, mf->dir, 0); + (void) sprintf(prompt, "move (%d,%c%d): ", ma, af ? '\'' : ' ', ta); + sgetstr(prompt, buf, sizeof buf); + dir = mf->dir; + vma = ma; + for (p = buf; *p; p++) + switch (*p) { + case 'l': + dir -= 2; + case 'r': + if (++dir == 0) + dir = 8; + else if (dir == 9) + dir = 1; + if (last == 't') { + Signal("Ship can't turn that fast.", + (struct ship *)0, 0, 0, 0, 0); + *p-- = '\0'; + } + last = 't'; + ma--; + ta--; + vma = min(ma, maxmove(ms, dir, 0)); + if ((ta < 0 && moved) || (vma < 0 && moved)) + *p-- = '\0'; + break; + case 'b': + ma--; + vma--; + last = 'b'; + if ((ta < 0 && moved) || (vma < 0 && moved)) + *p-- = '\0'; + break; + case '0': + case 'd': + *p-- = '\0'; + break; + case '\n': + *p-- = '\0'; + break; + case '1': case '2': case '3': case '4': + case '5': case '6': case '7': + if (last == '0') { + Signal("Can't move that fast.", + (struct ship *)0, 0, 0, 0, 0); + *p-- = '\0'; + } + last = '0'; + moved = 1; + ma -= *p - '0'; + vma -= *p - '0'; + if ((ta < 0 && moved) || (vma < 0 && moved)) + *p-- = '\0'; + break; + default: + if (!isspace(*p)) { + Signal("Input error.", (struct ship *)0, 0, 0, 0, 0); + *p-- = '\0'; + } + } + if ((ta < 0 && moved) || (vma < 0 && moved) + || (af && turnfirst(buf) && moved)) { + Signal("Movement error.", (struct ship *)0, 0, 0, 0, 0); + if (ta < 0 && moved) { + if (mf->FS == 1) { + Write(W_FS, ms, 0, 0, 0, 0, 0); + Signal("No hands to set full sails.", + (struct ship *)0, 0, 0, 0, 0); + } + } else if (ma >= 0) + buf[1] = '\0'; + } + if (af && !moved) { + if (mf->FS == 1) { + Write(W_FS, ms, 0, 0, 0, 0, 0); + Signal("No hands to set full sails.", + (struct ship *)0, 0, 0, 0, 0); + } + } + if (*buf) + (void) strcpy(movebuf, buf); + else + (void) strcpy(movebuf, "d"); + Write(W_MOVE, ms, 1, (int)movebuf, 0, 0, 0); + Signal("Helm: %s.", (struct ship *)0, (int)movebuf, 0, 0, 0); +} + +static void +parties(crew, to, isdefense, buf) + register struct ship *to; + int crew[3]; + int isdefense; + int buf; +{ + register int k, j, men; + struct BP *ptr; + int temp[3]; + + for (k = 0; k < 3; k++) + temp[k] = crew[k]; + if (isdigit(buf)) { + ptr = isdefense ? to->file->DBP : to->file->OBP; + for (j = 0; j < NBP && ptr[j].turnsent; j++) + ; + if (!ptr[j].turnsent && buf > '0') { + men = 0; + for (k = 0; k < 3 && buf > '0'; k++) { + men += crew[k] + * (k == 0 ? 100 : (k == 1 ? 10 : 1)); + crew[k] = 0; + if (men) + buf--; + } + if (buf > '0') + Signal("Sending all crew sections.", + (struct ship *)0, 0, 0, 0, 0); + Write(isdefense ? W_DBP : W_OBP, ms, 0, + j, turn, to->file->index, men); + if (isdefense) { + (void) wmove(slot_w, 2, 0); + for (k=0; k < NBP; k++) + if (temp[k] && !crew[k]) + (void) waddch(slot_w, k + '1'); + else + (void) wmove(slot_w, 2, 1 + k); + (void) mvwaddstr(slot_w, 3, 0, "DBP"); + makesignal(ms, "repelling boarders", + (struct ship *)0, 0, 0, 0); + } else { + (void) wmove(slot_w, 0, 0); + for (k=0; k < NBP; k++) + if (temp[k] && !crew[k]) + (void) waddch(slot_w, k + '1'); + else + (void) wmove(slot_w, 0, 1 + k); + (void) mvwaddstr(slot_w, 1, 0, "OBP"); + makesignal(ms, "boarding the %s (%c%c)", to, 0, 0, 0); + } + blockalarm(); + (void) wrefresh(slot_w); + unblockalarm(); + } else + Signal("Sending no crew sections.", (struct ship *)0, 0, 0, 0, 0); + } +} + +void +acceptboard() +{ + register struct ship *sp; + register int n; + int crew[3]; + int men = 0; + char c; + + crew[0] = mc->crew1; + crew[1] = mc->crew2; + crew[2] = mc->crew3; + for (n = 0; n < NBP; n++) { + if (mf->OBP[n].turnsent) + men += mf->OBP[n].mensent; + } + for (n = 0; n < NBP; n++) { + if (mf->DBP[n].turnsent) + men += mf->DBP[n].mensent; + } + if (men) { + crew[0] = men/100 ? 0 : crew[0] != 0; + crew[1] = (men%100)/10 ? 0 : crew[1] != 0; + crew[2] = men%10 ? 0 : crew[2] != 0; + } else { + crew[0] = crew[0] != 0; + crew[1] = crew[1] != 0; + crew[2] = crew[2] != 0; + } + foreachship(sp) { + if (sp == ms || sp->file->dir == 0 || range(ms, sp) > 1) + continue; + if (ms->nationality == capship(sp)->nationality) + continue; + if (meleeing(ms, sp) && crew[2]) { + c = sgetch("How many more to board the %s (%c%c)? ", + sp, 1); + parties(crew, sp, 0, c); + } else if ((fouled2(ms, sp) || grappled2(ms, sp)) && crew[2]) { + c = sgetch("Crew sections to board the %s (%c%c) (3 max) ?", sp, 1); + parties(crew, sp, 0, c); + } + } + if (crew[2]) { + c = sgetch("How many sections to repel boarders? ", + (struct ship *)0, 1); + parties(crew, ms, 1, c); + } + blockalarm(); + draw_slot(); + unblockalarm(); +} diff --git a/src/games/sail/pl_6.c b/src/games/sail/pl_6.c new file mode 100644 index 0000000..38ef530 --- /dev/null +++ b/src/games/sail/pl_6.c @@ -0,0 +1,167 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "player.h" + +static int +turned() +{ + register char *p; + + for (p = movebuf; *p; p++) + if (*p == 'r' || *p == 'l') + return 1; + return 0; +} + +void +repair() +{ + char c; + register char *repairs; + register struct shipspecs *ptr = mc; + register int count; + +#define FIX(x, m) (m - ptr->x > count \ + ? (ptr->x += count, count = 0) : (count -= m - ptr->x, ptr->x = m)) + + if (repaired || loaded || fired || changed || turned()) { + Signal("No hands free to repair", (struct ship *)0, 0, 0, 0, 0); + return; + } + c = sgetch("Repair (hull, guns, rigging)? ", (struct ship *)0, 1); + switch (c) { + case 'h': + repairs = &mf->RH; + break; + case 'g': + repairs = &mf->RG; + break; + case 'r': + repairs = &mf->RR; + break; + default: + Signal("Avast heaving!", (struct ship *)0, 0, 0, 0, 0); + return; + } + if (++*repairs >= 3) { + count = 2; + switch (c) { + case 'h': { + int max = ptr->guns/4; + if (ptr->hull < max) { + FIX(hull, max); + Write(W_HULL, ms, 0, ptr->hull, 0, 0, 0); + } + break; + } + case 'g': + if (ptr->gunL < ptr->gunR) { + int max = ptr->guns/5 - ptr->carL; + if (ptr->gunL < max) { + FIX(gunL, max); + Write(W_GUNL, ms, 0, ptr->gunL, + ptr->carL, 0, 0); + } + } else { + int max = ptr->guns/5 - ptr->carR; + if (ptr->gunR < max) { + FIX(gunR, max); + Write(W_GUNR, ms, 0, ptr->gunR, + ptr->carR, 0, 0); + } + } + break; + case 'r': +#define X 2 + if (ptr->rig4 >= 0 && ptr->rig4 < X) { + FIX(rig4, X); + Write(W_RIG4, ms, 0, ptr->rig4, 0, 0, 0); + } + if (count && ptr->rig3 < X) { + FIX(rig3, X); + Write(W_RIG3, ms, 0, ptr->rig3, 0, 0, 0); + } + if (count && ptr->rig2 < X) { + FIX(rig2, X); + Write(W_RIG2, ms, 0, ptr->rig2, 0, 0, 0); + } + if (count && ptr->rig1 < X) { + FIX(rig1, X); + Write(W_RIG1, ms, 0, ptr->rig1, 0, 0, 0); + } + break; + } + if (count == 2) { + Signal("Repairs completed.", (struct ship *)0, 0, 0, 0, 0); + *repairs = 2; + } else { + *repairs = 0; + blockalarm(); + draw_stat(); + unblockalarm(); + } + } + blockalarm(); + draw_slot(); + unblockalarm(); + repaired = 1; +} + +void +loadplayer() +{ + int c; + register int loadL, loadR, ready, load; + + if (!mc->crew3) { + Signal("Out of crew", (struct ship *)0, 0, 0, 0, 0); + return; + } + loadL = mf->loadL; + loadR = mf->loadR; + if (!loadL && !loadR) { + c = sgetch("Load which broadside (left or right)? ", + (struct ship *)0, 1); + if (c == 'r') + loadL = 1; + else + loadR = 1; + } + if ((!loadL && loadR) || (loadL && !loadR)) { + c = sgetch("Reload with (round, double, chain, grape)? ", + (struct ship *)0, 1); + switch (c) { + case 'r': + load = L_ROUND; + ready = 0; + break; + case 'd': + load = L_DOUBLE; + ready = R_DOUBLE; + break; + case 'c': + load = L_CHAIN; + ready = 0; + break; + case 'g': + load = L_GRAPE; + ready = 0; + break; + default: + Signal("Broadside not loaded.", + (struct ship *)0, 0, 0, 0, 0); + return; + } + if (!loadR) { + mf->loadR = load; + mf->readyR = ready|R_LOADING; + } else { + mf->loadL = load; + mf->readyL = ready|R_LOADING; + } + loaded = 1; + } +} diff --git a/src/games/sail/pl_7.c b/src/games/sail/pl_7.c new file mode 100644 index 0000000..8177498 --- /dev/null +++ b/src/games/sail/pl_7.c @@ -0,0 +1,468 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "player.h" + +/* + * Display interface + */ + +static char sc_hasprompt; +static char *sc_prompt; +static char *sc_buf; +static int sc_line; + +#ifdef SIGTSTP +void +susp(int sig) +{ + blockalarm(); + //tstp(); + signal(SIGTSTP, susp); + unblockalarm(); +} +#endif + +void +initscreen() +{ + /* initscr() already done in SCREENTEST() */ + view_w = newwin(VIEW_Y, VIEW_X, VIEW_T, VIEW_L); + slot_w = newwin(SLOT_Y, SLOT_X, SLOT_T, SLOT_L); + scroll_w = newwin(SCROLL_Y, SCROLL_X, SCROLL_T, SCROLL_L); + stat_w = newwin(STAT_Y, STAT_X, STAT_T, STAT_L); + turn_w = newwin(TURN_Y, TURN_X, TURN_T, TURN_L); + done_curses++; + (void) leaveok(view_w, 1); + (void) leaveok(slot_w, 1); + (void) leaveok(stat_w, 1); + (void) leaveok(turn_w, 1); +#ifdef SIGTSTP + { + signal(SIGTSTP, susp); + } +#endif + noecho(); + crmode(); +} + +void +cleanupscreen() +{ + /* alarm already turned off */ + if (done_curses) { + (void) wmove(scroll_w, SCROLL_Y - 1, 0); + (void) wclrtoeol(scroll_w); + draw_screen(); + endwin(); + } +} + +static void +adjustview() +{ + if (dont_adjust) + return; + if (mf->row < viewrow + VIEW_Y/4) + viewrow = mf->row - (VIEW_Y - VIEW_Y/4); + else if (mf->row > viewrow + (VIEW_Y - VIEW_Y/4)) + viewrow = mf->row - VIEW_Y/4; + if (mf->col < viewcol + VIEW_X/8) + viewcol = mf->col - (VIEW_X - VIEW_X/8); + else if (mf->col > viewcol + (VIEW_X - VIEW_X/8)) + viewcol = mf->col - VIEW_X/8; +} + +void +newturn(int sig) +{ + repaired = loaded = fired = changed = 0; + movebuf[0] = '\0'; + + (void) alarm(0); + if (mf->readyL & R_LOADING) { + if (mf->readyL & R_DOUBLE) + mf->readyL = R_LOADING; + else + mf->readyL = R_LOADED; + } + if (mf->readyR & R_LOADING) { + if (mf->readyR & R_DOUBLE) + mf->readyR = R_LOADING; + else + mf->readyR = R_LOADED; + } + if (!hasdriver) + Write(W_DDEAD, SHIP(0), 0, 0, 0, 0, 0); + + if (sc_hasprompt) { + (void) wmove(scroll_w, sc_line, 0); + (void) wclrtoeol(scroll_w); + } + if (Sync() < 0) + leave(LEAVE_SYNC); + if (!hasdriver) + leave(LEAVE_DRIVER); + if (sc_hasprompt) + (void) wprintw(scroll_w, "%s%s", sc_prompt, sc_buf); + + if (turn % 50 == 0) + Write(W_ALIVE, SHIP(0), 0, 0, 0, 0, 0); + if (mf->FS && (!mc->rig1 || windspeed == 6)) + Write(W_FS, ms, 0, 0, 0, 0, 0); + if (mf->FS == 1) + Write(W_FS, ms, 0, 2, 0, 0, 0); + + if (mf->struck) + leave(LEAVE_QUIT); + if (mf->captured != 0) + leave(LEAVE_CAPTURED); + if (windspeed == 7) + leave(LEAVE_HURRICAN); + + adjustview(); + draw_screen(); + + signal(SIGALRM, newturn); + (void) alarm(7); +} + +static void +Scroll() +{ + if (++sc_line >= SCROLL_Y) + sc_line = 0; + (void) wmove(scroll_w, sc_line, 0); + (void) wclrtoeol(scroll_w); +} + +/*VARARGS2*/ +void +Signal(fmt, ship, a, b, c, d) + char *fmt; + register struct ship *ship; + int a, b, c, d; +{ + if (!done_curses) + return; + if (*fmt == '\7') + putchar(*fmt++); + if (ship == 0) + (void) wprintw(scroll_w, fmt, a, b, c, d); + else + (void) wprintw(scroll_w, fmt, ship->shipname, + colours(ship), sterncolour(ship), a, b, c, d); + Scroll(); +} + +void +prompt(p, ship) + register char *p; + struct ship *ship; +{ + static char buf[60]; + + if (ship != 0) + p = (char *) sprintf(buf, p, ship->shipname, colours(ship), + sterncolour(ship)); + sc_prompt = p; + sc_buf = ""; + sc_hasprompt = 1; + (void) waddstr(scroll_w, p); +} + +void +endprompt(flag) + int flag; +{ + sc_hasprompt = 0; + if (flag) + Scroll(); +} + +int +sgetch(p, ship, flag) + char *p; + struct ship *ship; + int flag; +{ + register int c; + + prompt(p, ship); + blockalarm(); + (void) wrefresh(scroll_w); + unblockalarm(); + while ((c = wgetch(scroll_w)) == EOF) + ; + if (flag && c >= ' ' && c < 0x7f) + (void) waddch(scroll_w, c); + endprompt(flag); + return c; +} + +void +sgetstr(pr, buf, n) + char *pr; + register char *buf; + register int n; +{ + register int c; + register char *p = buf; + + prompt(pr, (struct ship *)0); + sc_buf = buf; + for (;;) { + *p = 0; + blockalarm(); + (void) wrefresh(scroll_w); + unblockalarm(); + while ((c = wgetch(scroll_w)) == EOF) + ; + switch (c) { + case '\n': + case '\r': + endprompt(1); + return; + case '\b': + if (p > buf) { + (void) waddstr(scroll_w, "\b \b"); + p--; + } + break; + default: + if (c >= ' ' && c < 0x7f && p < buf + n - 1) { + *p++ = c; + (void) waddch(scroll_w, c); + } else + (void) putchar('\7'); + } + } +} + +void +draw_screen() +{ + draw_view(); + draw_turn(); + draw_stat(); + draw_slot(); + (void) wrefresh(scroll_w); /* move the cursor */ +} + +void +draw_view() +{ + register struct ship *sp; + + (void) werase(view_w); + foreachship(sp) { + if (sp->file->dir + && sp->file->row > viewrow + && sp->file->row < viewrow + VIEW_Y + && sp->file->col > viewcol + && sp->file->col < viewcol + VIEW_X) { + (void) wmove(view_w, sp->file->row - viewrow, + sp->file->col - viewcol); + (void) waddch(view_w, colours(sp)); + (void) wmove(view_w, + sternrow(sp) - viewrow, + sterncol(sp) - viewcol); + (void) waddch(view_w, sterncolour(sp)); + } + } + (void) wrefresh(view_w); +} + +void +draw_turn() +{ + (void) wmove(turn_w, 0, 0); + (void) wprintw(turn_w, "%cTurn %d", dont_adjust?'*':'-', turn); + (void) wrefresh(turn_w); +} + +void +draw_stat() +{ + (void) wmove(stat_w, STAT_1, 0); + (void) wprintw(stat_w, "Points %3d\n", mf->points); + (void) wprintw(stat_w, "Fouls %2d\n", fouled(ms)); + (void) wprintw(stat_w, "Grapples %2d\n", grappled(ms)); + + (void) wmove(stat_w, STAT_2, 0); + (void) wprintw(stat_w, " 0 %c(%c)\n", + maxmove(ms, winddir + 3, -1) + '0', + maxmove(ms, winddir + 3, 1) + '0'); + (void) waddstr(stat_w, " \\|/\n"); + (void) wprintw(stat_w, " -^-%c(%c)\n", + maxmove(ms, winddir + 2, -1) + '0', + maxmove(ms, winddir + 2, 1) + '0'); + (void) waddstr(stat_w, " /|\\\n"); + (void) wprintw(stat_w, " | %c(%c)\n", + maxmove(ms, winddir + 1, -1) + '0', + maxmove(ms, winddir + 1, 1) + '0'); + (void) wprintw(stat_w, " %c(%c)\n", + maxmove(ms, winddir, -1) + '0', + maxmove(ms, winddir, 1) + '0'); + + (void) wmove(stat_w, STAT_3, 0); + (void) wprintw(stat_w, "Load %c%c %c%c\n", + loadname[(int)mf->loadL], readyname((int)mf->readyL), + loadname[(int)mf->loadR], readyname((int)mf->readyR)); + (void) wprintw(stat_w, "Hull %2d\n", mc->hull); + (void) wprintw(stat_w, "Crew %2d %2d %2d\n", + mc->crew1, mc->crew2, mc->crew3); + (void) wprintw(stat_w, "Guns %2d %2d\n", mc->gunL, mc->gunR); + (void) wprintw(stat_w, "Carr %2d %2d\n", mc->carL, mc->carR); + (void) wprintw(stat_w, "Rigg %d %d %d ", mc->rig1, mc->rig2, mc->rig3); + if (mc->rig4 < 0) + (void) waddch(stat_w, '-'); + else + (void) wprintw(stat_w, "%d", mc->rig4); + (void) wrefresh(stat_w); +} + +void +draw_slot() +{ + if (!boarding(ms, 0)) { + (void) mvwaddstr(slot_w, 0, 0, " "); + (void) mvwaddstr(slot_w, 1, 0, " "); + } else + (void) mvwaddstr(slot_w, 1, 0, "OBP"); + if (!boarding(ms, 1)) { + (void) mvwaddstr(slot_w, 2, 0, " "); + (void) mvwaddstr(slot_w, 3, 0, " "); + } else + (void) mvwaddstr(slot_w, 3, 0, "DBP"); + + (void) wmove(slot_w, SLOT_Y-4, 0); + if (mf->RH) + (void) wprintw(slot_w, "%dRH", mf->RH); + else + (void) waddstr(slot_w, " "); + (void) wmove(slot_w, SLOT_Y-3, 0); + if (mf->RG) + (void) wprintw(slot_w, "%dRG", mf->RG); + else + (void) waddstr(slot_w, " "); + (void) wmove(slot_w, SLOT_Y-2, 0); + if (mf->RR) + (void) wprintw(slot_w, "%dRR", mf->RR); + else + (void) waddstr(slot_w, " "); + +#define Y (SLOT_Y/2) + (void) wmove(slot_w, 7, 1); + (void) wprintw(slot_w,"%d", windspeed); + (void) mvwaddch(slot_w, Y, 0, ' '); + (void) mvwaddch(slot_w, Y, 2, ' '); + (void) mvwaddch(slot_w, Y-1, 0, ' '); + (void) mvwaddch(slot_w, Y-1, 1, ' '); + (void) mvwaddch(slot_w, Y-1, 2, ' '); + (void) mvwaddch(slot_w, Y+1, 0, ' '); + (void) mvwaddch(slot_w, Y+1, 1, ' '); + (void) mvwaddch(slot_w, Y+1, 2, ' '); + (void) wmove(slot_w, Y - dr[winddir], 1 - dc[winddir]); + switch (winddir) { + case 1: + case 5: + (void) waddch(slot_w, '|'); + break; + case 2: + case 6: + (void) waddch(slot_w, '/'); + break; + case 3: + case 7: + (void) waddch(slot_w, '-'); + break; + case 4: + case 8: + (void) waddch(slot_w, '\\'); + break; + } + (void) mvwaddch(slot_w, Y + dr[winddir], 1 + dc[winddir], '+'); + (void) wrefresh(slot_w); +} + +void +draw_board() +{ + register int n; + + (void) clear(); + (void) werase(view_w); + (void) werase(slot_w); + (void) werase(scroll_w); + (void) werase(stat_w); + (void) werase(turn_w); + + sc_line = 0; + + (void) move(BOX_T, BOX_L); + for (n = 0; n < BOX_X; n++) + (void) addch('-'); + (void) move(BOX_B, BOX_L); + for (n = 0; n < BOX_X; n++) + (void) addch('-'); + for (n = BOX_T+1; n < BOX_B; n++) { + (void) mvaddch(n, BOX_L, '|'); + (void) mvaddch(n, BOX_R, '|'); + } + (void) mvaddch(BOX_T, BOX_L, '+'); + (void) mvaddch(BOX_T, BOX_R, '+'); + (void) mvaddch(BOX_B, BOX_L, '+'); + (void) mvaddch(BOX_B, BOX_R, '+'); + (void) refresh(); + +#define WSaIM "Wooden Ships & Iron Men" + (void) wmove(view_w, 2, (VIEW_X - sizeof WSaIM - 1) / 2); + (void) waddstr(view_w, WSaIM); + (void) wmove(view_w, 4, (VIEW_X - strlen(cc->name)) / 2); + (void) waddstr(view_w, cc->name); + (void) wrefresh(view_w); + + (void) move(LINE_T, LINE_L); + (void) printw("Class %d %s (%d guns) '%s' (%c%c)", + mc->class, + classname[(int)mc->class], + mc->guns, + ms->shipname, + colours(ms), + sterncolour(ms)); + (void) refresh(); +} + +void +centerview() +{ + viewrow = mf->row - VIEW_Y / 2; + viewcol = mf->col - VIEW_X / 2; +} + +void +upview() +{ + viewrow -= VIEW_Y / 3; +} + +void +downview() +{ + viewrow += VIEW_Y / 3; +} + +void +leftview() +{ + viewcol -= VIEW_X / 5; +} + +void +rightview() +{ + viewcol += VIEW_X / 5; +} diff --git a/src/games/sail/pl_main.c b/src/games/sail/pl_main.c new file mode 100644 index 0000000..1fefcea --- /dev/null +++ b/src/games/sail/pl_main.c @@ -0,0 +1,229 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "player.h" +#include +#include + +static void +initialize() +{ + register struct File *fp; + register struct ship *sp; + char captain[80]; + char message[60]; + int load; + register int n; + char *nameptr; + int nat[NNATION]; + + if (game < 0) { + (void) puts("Choose a scenario:\n"); + (void) puts("\tNUMBER\tSHIPS\tIN PLAY\tTITLE"); + for (n = 0; n < NSCENE; n++) { + /* ( */ + printf("\t%d):\t%d\t%s\t%s\n", n, scene[n].vessels, + sync_exists(n) ? "YES" : "no", + scene[n].name); + } +reprint: + printf("\nScenario number? "); + (void) fflush(stdout); + if (scanf("%d", &game) != 1) { + puts("Bad number."); + exit(1); + } + while (getchar() != '\n') + ; + } + if (game < 0 || game >= NSCENE) { + (void) puts("Very funny."); + exit(1); + } + cc = &scene[game]; + ls = SHIP(cc->vessels); + + for (n = 0; n < NNATION; n++) + nat[n] = 0; + foreachship(sp) { + if (sp->file == NULL && + (sp->file = (struct File *)calloc(1, sizeof (struct File))) == NULL) { + (void) puts("OUT OF MEMORY"); + exit(1); + } + sp->file->index = sp - SHIP(0); + sp->file->stern = nat[(int)sp->nationality]++; + sp->file->dir = sp->shipdir; + sp->file->row = sp->shiprow; + sp->file->col = sp->shipcol; + } + windspeed = cc->windspeed; + winddir = cc->winddir; + + (void) signal(SIGHUP, choke); + (void) signal(SIGINT, choke); + + hasdriver = sync_exists(game); + if (sync_open() < 0) { + perror("sail: syncfile"); + exit(1); + } + + if (hasdriver) { + (void) puts("Synchronizing with the other players..."); + (void) fflush(stdout); + if (Sync() < 0) + leave(LEAVE_SYNC); + } + for (;;) { + foreachship(sp) + if (sp->file->captain[0] == 0 && !sp->file->struck + && sp->file->captured == 0) + break; + if (sp >= ls) { + (void) puts("All ships taken in that scenario."); + foreachship(sp) + free((char *)sp->file); + sync_close(0); + people = 0; + goto reprint; + } + if (randomize) { + player = sp - SHIP(0); + } else { + printf("%s\n\n", cc->name); + foreachship(sp) + printf(" %2d: %-10s %-15s (%-2d pts) %s\n", + sp->file->index, + countryname[(int)sp->nationality], + sp->shipname, + sp->specs->pts, + saywhat(sp, 1)); + printf("\nWhich ship (0-%d)? ", cc->vessels-1); + (void) fflush(stdout); + if (scanf("%d", &player) != 1 || player < 0 + || player >= cc->vessels) { + while (getchar() != '\n') + ; + (void) puts("Say what?"); + player = -1; + } else + while (getchar() != '\n') + ; + } + if (player < 0) + continue; + if (Sync() < 0) + leave(LEAVE_SYNC); + fp = SHIP(player)->file; + if (fp->captain[0] || fp->struck || fp->captured != 0) + (void) puts("That ship is taken."); + else + break; + } + + ms = SHIP(player); + mf = ms->file; + mc = ms->specs; + + Write(W_BEGIN, ms, 0, 0, 0, 0, 0); + if (Sync() < 0) + leave(LEAVE_SYNC); + + (void) signal(SIGCHLD, child); + if (!hasdriver) + switch (fork()) { + case 0: + longjmp(restart, MODE_DRIVER); + /*NOTREACHED*/ + case -1: + perror("fork"); + leave(LEAVE_FORK); + break; + default: + hasdriver++; + } + + printf("Your ship is the %s, a %d gun %s (%s crew).\n", + ms->shipname, mc->guns, classname[(int)mc->class], + qualname[(int)mc->qual]); + if ((nameptr = (char *) getenv("SAILNAME")) && *nameptr) + (void) strncpy(captain, nameptr, sizeof captain); + else { + (void) printf("Your name, Captain? "); + (void) fflush(stdout); + if (! gets(captain)) { + puts("Bad name."); + exit(1); + } + if (!*captain) + (void) strcpy(captain, "no name"); + } + captain[sizeof captain - 1] = '\0'; + Write(W_CAPTAIN, ms, 1, (int)captain, 0, 0, 0); + for (n = 0; n < 2; n++) { + char buf[10]; + + printf("\nInitial broadside %s (grape, chain, round, double): ", + n ? "right" : "left"); + (void) fflush(stdout); + if (scanf("%s", buf) != 1) { + puts("Bad value."); + exit(1); + } + switch (*buf) { + case 'g': + load = L_GRAPE; + break; + case 'c': + load = L_CHAIN; + break; + case 'r': + load = L_ROUND; + break; + case 'd': + load = L_DOUBLE; + break; + default: + load = L_ROUND; + } + if (n) { + mf->loadR = load; + mf->readyR = R_LOADED|R_INITIAL; + } else { + mf->loadL = load; + mf->readyL = R_LOADED|R_INITIAL; + } + } + + initscr(); + initscreen(); + draw_board(); + (void) sprintf(message, "Captain %s assuming command", captain); + Write(W_SIGNAL, ms, 1, (int)message, 0, 0, 0); + newturn(0); +} + +/*ARGSUSED*/ +int +pl_main() +{ + if (! initscr()) { +failed: printf("Can't sail on this terminal.\n"); + exit(1); + } +#ifdef SIGTSTP + if (signal(SIGTSTP, SIG_DFL) == SIG_ERR) + goto failed; +#endif + if (STAT_R >= COLS || SCROLL_Y <= 0) + goto failed; + endwin(); + + initialize(); + Signal("Aye aye, Sir", (struct ship *)0, 0, 0, 0, 0); + play(); + return 0; /* for lint, play() never returns */ +} diff --git a/src/games/sail/player.h b/src/games/sail/player.h new file mode 100644 index 0000000..890514b --- /dev/null +++ b/src/games/sail/player.h @@ -0,0 +1,92 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + * + * @(#)player.h 5.1.1 (2.11BSD GTE) 1/1/94 + */ + +#include +#include "externs.h" + +/* sizes and coordinates for the screen */ + +#define LINE_T 0 +#define LINE_L 0 +#define LINE_X COLS +#define LINE_Y 1 +#define LINE_B (LINE_T+LINE_Y-1) +#define LINE_R (LINE_L+LINE_X-1) + +#define BOX_T 1 +#define BOX_L 0 +#define BOX_X 65 +#define BOX_Y 16 +#define BOX_B (BOX_T+BOX_Y-1) +#define BOX_R (BOX_L+BOX_X-1) + +#define TURN_T BOX_B +#define TURN_Y 1 +#define TURN_L ((BOX_L+BOX_R-TURN_X)/2) +#define TURN_X 9 +#define TURN_B (TURN_T+TURN_Y+1) +#define TURN_R (TURN_L+TURN_X+1) + +#define STAT_T 0 +#define STAT_B BOX_B +#define STAT_L (BOX_R+2) +#define STAT_X 14 +#define STAT_Y (STAT_B-STAT_T+1) +#define STAT_R (STAT_L+STAT_X-1) +#define STAT_1 0 +#define STAT_2 (STAT_1+4) +#define STAT_3 (STAT_2+7) + +#define SCROLL_T (BOX_B+1) +#define SCROLL_L 0 +#define SCROLL_B (LINES-1) +#define SCROLL_R (COLS-1) +#define SCROLL_X (SCROLL_R-SCROLL_L+1) +#define SCROLL_Y (SCROLL_B-SCROLL_T+1) + +#define VIEW_T (BOX_T+1) +#define VIEW_L (BOX_L+1) +#define VIEW_X (BOX_X-5) +#define VIEW_Y (BOX_Y-2) +#define VIEW_B (VIEW_T+VIEW_Y-1) +#define VIEW_R (VIEW_L+VIEW_X-1) + +#define SLOT_T VIEW_T +#define SLOT_L (VIEW_R+1) +#define SLOT_X 3 +#define SLOT_Y VIEW_Y +#define SLOT_B VIEW_B +#define SLOT_R (SLOT_L+SLOT_X-1) + +WINDOW *view_w; +WINDOW *slot_w; +WINDOW *scroll_w; +WINDOW *stat_w; +WINDOW *turn_w; + +char done_curses; +char loaded, fired, changed, repaired; +char dont_adjust; +int viewrow, viewcol; +char movebuf[sizeof SHIP(0)->file->movebuf]; +extern char version[]; +int player; +struct ship *ms; /* memorial structure, &cc->ship[player] */ +struct File *mf; /* ms->file */ +struct shipspecs *mc; /* ms->specs */ + +/* condition codes for leave() */ +#define LEAVE_QUIT 0 +#define LEAVE_CAPTURED 1 +#define LEAVE_HURRICAN 2 +#define LEAVE_DRIVER 3 +#define LEAVE_FORK 4 +#define LEAVE_SYNC 5 + +void choke(int sig); +void child(int sig); diff --git a/src/games/sail/sail.6 b/src/games/sail/sail.6 new file mode 100644 index 0000000..76a1330 --- /dev/null +++ b/src/games/sail/sail.6 @@ -0,0 +1,872 @@ +.\" Copyright (c) 1985 Regents of the University of California. +.\" All rights reserved. The Berkeley software License Agreement +.\" specifies the terms and conditions for redistribution. +.\" +.\" @(#)sail.6 6.2 (Berkeley) 5/6/86 +.\" +.TH SAIL 6 "May 6, 1986" +.UC 6 +.SH NAME +sail \- multi-user wooden ships and iron men +.SH SYNOPSIS +.B sail +[ +.B \-s +[ +.B \-l +] ] [ +.B \-x +] [ +.B \-b +] [ +.B num +] +.br +.fi +.SH DESCRIPTION +.I Sail +is a computer version of Avalon Hill's game of fighting sail +originally developed by S. Craig Taylor. +.PP +Players of +.I Sail +take command of an old fashioned Man of War and fight other +players or the computer. They may re-enact one of the many +historical sea battles recorded in the game, or they can choose +a fictional battle. +.PP +As a sea captain in the +.I Sail +Navy, the player has complete control over the workings of his ship. +He must order every maneuver, change the set of his sails, and judge the +right moment to let loose the terrible destruction of his broadsides. +In addition to fighting the enemy, he must harness the powers of the wind +and sea to make them work for him. The outcome of many battles during the +age of sail was decided by the ability of one captain to hold the `weather +gage.' +.PP +The flags are: +.TP +.B \-s +Print the names and ships of the top ten sailors. +.TP +.B \-l +Show the login name. Only effective with \fB-s\fP. +.TP +.B \-x +Play the first available ship instead of prompting for a choice. +.TP +.B \-b +No bells. +.SH IMPLEMENTATION +.I Sail +is really two programs in one. Each player starts up a process which +runs his own ship. In addition, a +.I driver +process is forked (by the first player) to run the computer ships +and take care of global bookkeeping. +.PP +Because the +.I driver +must calculate moves for each ship it controls, the +more ships the computer is playing, the slower the game will appear. +.PP +If a player joins a game in progress, he will synchronize +with the other players (a rather slow process for everyone), and +then he may play along with the rest. +.PP +To implement a multi-user game in Version 7 UNIX, which was the operating +system +.I Sail +was first written under, the communicating processes must use a common +temporary file as a place to read and write messages. In addition, a +locking mechanism must be provided to ensure exclusive access to the +shared file. For example, +.I Sail +uses a temporary file named /tmp/#sailsink.21 for scenario 21, and +corresponding file names for the other scenarios. To provide exclusive +access to the temporary file, +.I Sail +uses a technique stolen from an old game called "pubcaves" by Jeff Cohen. +Processes do a busy wait in the loop +.br +.sp +.ce 2 + for (n = 0; link(sync_file, sync_lock) < 0 && n < 30; n++) + sleep(2); +.br +.sp +until they are able to create a link to a file named "/tmp/#saillock.??". +The "??" correspond to the scenario number of the game. Since UNIX +guarantees that a link will point to only one file, the process that succeeds +in linking will have exclusive access to the temporary file. +.PP +Whether or not this really works is open to speculation. When ucbmiro +was rebooted after a crash, the file system check program found 3 links +between the +.I Sail +temporary file and its link file. +.SH CONSEQUENCES OF SEPARATE PLAYER AND DRIVER PROCESSES +When players do something of global interest, such as moving or firing, +the driver must coordinate the action with the other ships in the game. +For example, if a player wants to move in a certain direction, he writes a +message into the temporary file requesting the driver to move his ship. +Each ``turn,'' the driver reads all the messages sent from the players and +decides what happened. It then writes back into the temporary file new +values of variables, etc. +.PP +The most noticeable effect this communication has on the game is the +delay in moving. Suppose a player types a move for his ship and hits +return. What happens then? The player process saves up messages to +be written to the temporary file in a buffer. Every 7 seconds or so, the +player process gets exclusive access to the temporary file and writes +out its buffer to the file. The driver, running asynchronously, must +read in the movement command, process it, and write out the results. This +takes two exclusive accesses to the temporary file. Finally, when the player +process gets around to doing another 7 second update, the results of the +move are displayed on the screen. Hence, every movement requires four +exclusive accesses to the temporary file (anywhere from 7 to 21 seconds +depending upon asynchrony) before the player sees the results of his moves. +.PP +In practice, the delays are not as annoying as they would appear. There +is room for "pipelining" in the movement. After the player writes out +a first movement message, a second movement command can then be issued. +The first message will be in the temporary file waiting for the driver, and +the second will be in the file buffer waiting to be written to the file. +Thus, by always typing moves a turn ahead of the time, the player can +sail around quite quickly. +.PP +If the player types several movement commands between two 7 second updates, +only the last movement command typed will be seen by the driver. Movement +commands within the same update "overwrite" each other, in a sense. +.SH THE HISTORY OF SAIL +I wrote the first version of +.I Sail +on a PDP 11/70 in the fall of 1980. Needless to say, the code was horrendous, +not portable in any sense of the word, and didn't work. The program was not +very modular and had fseeks() and fwrites() every few lines. After a +tremendous rewrite from the top down, I got the first working version up by +1981. There were several annoying bugs concerning firing broadsides and +finding angles. +.I Sail +uses no floating point, by the way, so the direction routines are rather +tricky. +Ed Wang rewrote my angle() routine in 1981 to be more correct (although +it still doesn't work perfectly), and he added code to let a player select +which ship he wanted at the start of the game (instead of the first one +available). +.PP +Captain Happy (Craig Leres) is responsible for making +.I Sail +portable for the first time. This was no easy task, by the way. Constants +like 2 and 10 were very frequent in the code. I also became famous for +using "Riggle Memorial Structures" in +.I Sail. +Many of my structure references are so long that they run off the line +printer page. Here is an example, if you promise not to laugh. +.br +.sp +.ce +specs[scene[flog.fgamenum].ship[flog.fshipnum].shipnum].pts +.br +.sp +.PP +.I Sail +received its fourth and most thorough rewrite in the summer and fall +of 1983. Ed Wang rewrote and modularized the code (a monumental feat) +almost from scratch. Although he introduced many new bugs, the final +result was very much cleaner and (?) faster. He added window movement +commands and find ship commands. +.SH HISTORICAL INFO +Old Square Riggers were very maneuverable ships capable of intricate +sailing. Their only disadvantage was an inability to sail very +close to the wind. The design of a wooden ship allowed only for the +guns to bear to the left and right sides. A few guns of small +aspect (usually 6 or 9 pounders) could point forward, but their +effect was small compared to a 68 gun broadside of 24 or 32 pounders. +The guns bear approximately like so: +.nf + + \\ + b---------------- + ---0 + \\ + \\ + \\ up to a range of ten (for round shot) + \\ + \\ + \\ + +.fi +An interesting phenomenon occurred when a broadside was fired +down the length of an enemy ship. The shot tended to bounce along +the deck and did several times more damage. This phenomenon was called +a rake. Because the bows of a ship are very strong and present a smaller +target than the stern, a stern rake (firing from the stern to the bow) causes +more damage than a bow rake. +.nf + + b + 00 ---- Stern rake! + a + +.fi +Most ships were equipped with carronades, which were very large, close +range cannons. American ships from the revolution until the War of 1812 +were almost entirely armed with carronades. +.PP +The period of history covered in +.I Sail +is approximately from the 1770's until the end of Napoleanic France in 1815. +There are many excellent books about the age of sail. My favorite author +is Captain Frederick Marryat. More contemporary authors include C.S. Forester +and Alexander Kent. +.PP +Fighting ships came in several sizes classed by armament. The mainstays of +any fleet were its "Ships of the Line", or "Line of Battle Ships". They +were so named because these ships fought together in great lines. They were +close enough for mutual support, yet every ship could fire both its broadsides. +We get the modern words "ocean liner," or "liner," and "battleship" from +"ship of the line." The most common size was the the 74 gun two decked +ship of the line. The two gun decks usually mounted 18 and 24 pounder guns. +.PP +The pride of the fleet were the first rates. These were huge three decked +ships of the line mounting 80 to 136 guns. The guns in the three tiers +were usually 18, 24, and 32 pounders in that order from top to bottom. +.PP +Various other ships came next. They were almost all "razees," or ships +of the line with one deck sawed off. They mounted 40-64 guns and were +a poor cross between a frigate and a line of battle ship. They neither +had the speed of the former nor the firepower of the latter. +.PP +Next came the "eyes of the fleet." Frigates came in many sizes mounting +anywhere from 32 to 44 guns. They were very handy vessels. They could +outsail anything bigger and outshoot anything smaller. Frigates didn't +fight in lines of battle as the much bigger 74's did. Instead, they +harassed the enemy's rear or captured crippled ships. They were much +more useful in missions away from the fleet, such as cutting out expeditions +or boat actions. They could hit hard and get away fast. +.PP +Lastly, there were the corvettes, sloops, and brigs. These were smaller +ships mounting typically fewer than 20 guns. A corvette was only slightly +smaller than a frigate, so one might have up to 30 guns. Sloops were used +for carrying dispatches or passengers. Brigs were something you built for +land-locked lakes. +.SH SAIL PARTICULARS +Ships in +.I Sail +are represented by two characters. One character represents the bow of +the ship, and the other represents the stern. Ships have nationalities +and numbers. The first ship of a nationality is number 0, the second +number 1, etc. Therefore, the first British ship in a game would be +printed as "b0". The second Brit would be "b1", and the fifth Don +would be "s4". +.PP +Ships can set normal sails, called Battle Sails, or bend on extra canvas +called Full Sails. A ship under full sail is a beautiful sight indeed, +and it can move much faster than a ship under Battle Sails. The only +trouble is, with full sails set, there is so much tension on sail and +rigging that a well aimed round shot can burst a sail into ribbons where +it would only cause a little hole in a loose sail. For this reason, +rigging damage is doubled on a ship with full sails set. Don't let +that discourage you from using full sails. I like to keep them up +right into the heat of battle. A ship +with full sails set has a capital letter for its nationality. E.g., +a Frog, "f0", with full sails set would be printed as "F0". +.PP +When a ship is battered into a listing hulk, the last man aboard "strikes +the colors." This ceremony is the ship's formal surrender. The nationality +character +of a surrendered ship is printed as "!". E.g., the Frog of our last example +would soon be "!0". +.PP +A ship has a random chance of catching fire or sinking when it reaches the +stage of listing hulk. A sinking ship has a "~" printed for its nationality, +and a ship on fire and about to explode has a "#" printed. +.PP +Captured ships become the nationality of the prize crew. Therefore, if +an American ship captures a British ship, the British ship will have an +"a" printed for its nationality. In addition, the ship number is changed +to "&","'", "(", ,")", "*", or "+" depending upon the original number, +be it 0,1,2,3,4, or 5. E.g., the "b0" captured by an American becomes the +"a&". The "s4" captured by a Frog becomes the "f*". +.PP +The ultimate example is, of course, an exploding Brit captured by an +American: "#&". +.SH MOVEMENT +Movement is the most confusing part of +.I Sail +to many. Ships can head in 8 directions: +.nf + + 0 0 0 + b b b0 b b b 0b b + 0 0 0 + +.fi +The stern of a ship moves when it turns. The bow remains stationary. +Ships can always turn, regardless of the wind (unless they are becalmed). +All ships drift when they lose headway. If a ship doesn't move forward +at all for two turns, it will begin to drift. If a ship has begun to +drift, then it must move forward before it turns, if it plans to do +more than make a right or left turn, which is always possible. +.PP +Movement commands to +.I Sail +are a string of forward moves and turns. An example is "l3". It will +turn a ship left and then move it ahead 3 spaces. In the drawing above, +the "b0" made 7 successive left turns. When +.I Sail +prompts you for a move, it prints three characters of import. E.g., +.nf + move (7, 4): +.fi +The first number is the maximum number of moves you can make, +including turns. The second number is the maximum number of turns +you can make. Between the numbers is sometimes printed a quote "'". +If the quote is present, it means that your ship has been drifting, and +you must move ahead to regain headway before you turn (see note above). +Some of the possible moves for the example above are as follows: +.nf + + move (7, 4): 7 + move (7, 4): 1 + move (7, 4): d /* drift, or do nothing */ + move (7, 4): 6r + move (7, 4): 5r1 + move (7, 4): 4r1r + move (7, 4): l1r1r2 + move (7, 4): 1r1r1r1 + +.fi +Because square riggers performed so poorly sailing into the wind, if at +any point in a movement command you turn into the wind, the movement stops +there. E.g., +.nf + + move (7, 4): l1l4 + Movement Error; + Helm: l1l + +.fi +Moreover, whenever you make a turn, your movement allowance drops to +min(what's left, what you would have at the new attitude). In short, +if you turn closer to the wind, you most likely won't be able to sail the +full allowance printed in the "move" prompt. +.PP +Old sailing captains had to keep an eye constantly on the wind. Captains +in +.I Sail +are no different. A ship's ability to move depends on its attitide to the +wind. The best angle possible is to have the wind off your quarter, that is, +just off the stern. The direction rose on the side of the screen gives the +possible movements for your ship at all positions to the wind. Battle +sail speeds are given first, and full sail speeds are given in parenthesis. +.nf + + 0 1(2) + \\|/ + -^-3(6) + /|\\ + | 4(7) + 3(6) + +.fi +Pretend the bow of your ship (the "^") is pointing upward and the wind is +blowing from the bottom to the top of the page. The +numbers at the bottom "3(6)" will be your speed under battle or full +sails in such a situation. If the wind is off your quarter, then you +can move "4(7)". If the wind is off your beam, "3(6)". If the wind is +off your bow, then you can only move "1(2)". Facing into the wind, you +can't move at all. Ships facing into the wind were said to be "in irons". +.SH WINDSPEED AND DIRECTION +The windspeed and direction is displayed as a little weather vane on the +side of the screen. The number in the middle of the vane indicates the wind +speed, and the + to - indicates the wind direction. The wind blows from +the + sign (high pressure) to the - sign (low pressure). E.g., +.nf + + | + 3 + + + +.fi +.PP +The wind speeds are 0 = becalmed, 1 = light breeze, 2 = moderate breeze, +3 = fresh breeze, 4 = strong breeze, 5 = gale, 6 = full gale, 7 = hurricane. +If a hurricane shows up, all ships are destroyed. +.SH GRAPPLING AND FOULING +If two ships collide, they run the risk of becoming tangled together. This +is called "fouling." Fouled ships are stuck together, and neither can move. +They can unfoul each other if they want to. Boarding parties can only be +sent across to ships when the antagonists are either fouled or grappled. +.PP +Ships can grapple each other by throwing grapnels into the rigging of +the other. +.PP +The number of fouls and grapples you have are displayed on the upper +right of the screen. +.SH BOARDING +Boarding was a very costly venture in terms of human life. Boarding parties +may be formed in +.I Sail +to either board an enemy ship or to defend your own ship against attack. +Men organized as Defensive Boarding Parties fight twice as hard to save +their ship as men left unorganized. +.PP +The boarding strength of a crew depends upon its quality and upon the +number of men sent. +.SH CREW QUALITY +The British seaman was world renowned for his sailing abilities. American +sailors, however, were actually the best seamen in the world. Because the +American Navy offered twice the wages of the Royal Navy, British seamen +who liked the sea defected to America by the thousands. +.PP +In +.I Sail, +crew quality is quantized into 5 energy levels. "Elite" crews can outshoot +and outfight all other sailors. "Crack" crews are next. "Mundane" crews +are average, and "Green" and "Mutinous" crews are below average. A good +rule of thumb is that "Crack" or "Elite" crews get one extra hit +per broadside compared to "Mundane" crews. Don't expect too much from +"Green" crews. +.SH BROADSIDES +Your two broadsides may be loaded with four kinds of shot: grape, chain, +round, and double. You have guns and carronades in both the port and starboard +batteries. Carronades only have a range of two, so you have to get in +close to be able to fire them. You have the choice of firing at the hull +or rigging of another ship. If the range of the ship is greater than 6, +then you may only shoot at the rigging. +.PP +The types of shot and their advantages are: +.SH ROUND +Range of 10. Good for hull or rigging hits. +.SH DOUBLE +Range of 1. Extra good for hull or rigging hits. +Double takes two turns to load. +.SH CHAIN +Range of 3. Excellent for tearing down rigging. +Cannot damage hull or guns, though. +.SH GRAPE +Range of 1. Sometimes devastating against enemy crews. +.PP +On the side of the screen is displayed some vital information about your +ship: +.nf + + Load D! R! + Hull 9 + Crew 4 4 2 + Guns 4 4 + Carr 2 2 + Rigg 5 5 5 5 + +.fi +"Load" shows what your port (left) and starboard (right) broadsides are +loaded with. A "!" after the type of shot indicates that it is an initial +broadside. Initial broadside were loaded with care before battle and before +the decks ran red with blood. As a consequence, initial broadsides are a +little more effective than broadsides loaded later. A "*" after the type of +shot indicates that the gun +crews are still loading it, and you cannot fire yet. "Hull" shows how much +hull you have left. "Crew" shows your three sections of crew. As your +crew dies off, your ability to fire decreases. "Guns" and "Carr" show +your port and starboard guns. As you lose guns, your ability to fire +decreases. "Rigg" shows how much rigging you have on your 3 or 4 masts. +As rigging is shot away, you lose mobility. +.SH EFFECTIVENESS OF FIRE +It is very dramatic when a ship fires its thunderous broadsides, but the +mere opportunity to fire them does not guarantee any hits. Many factors +influence the destructive force of a broadside. First of all, and the chief +factor, is distance. It is harder to hit a ship at range ten than it is +to hit one sloshing alongside. Next is raking. Raking fire, as +mentioned before, +can sometimes dismast a ship at range ten. Next, crew size and quality affects +the damage done by a broadside. The number of guns firing also bears on the +point, +so to speak. Lastly, weather affects the accuracy of a broadside. If the +seas are high (5 or 6), then the lower gunports of ships of the line can't +even be opened to run out the guns. This gives frigates and other flush +decked vessels an advantage in a storm. The scenario +.I Pellew vs. The Droits de L'Homme +takes advantage of this peculiar circumstance. +.SH REPAIRS +Repairs may be made to your Hull, Guns, and Rigging at the slow rate of +two points per three turns. The message "Repairs Completed" will be +printed if no more repairs can be made. +.SH PECULIARITIES OF COMPUTER SHIPS +Computer ships in +.I Sail +follow all the rules above with a few exceptions. Computer ships never +repair damage. If they did, the players could never beat them. They +play well enough as it is. As a consolation, the computer ships can fire double +shot every turn. That fluke is a good reason to keep your distance. The +.I +Driver +figures out the moves of the computer ships. It computes them with a typical +A.I. distance function and a depth first search to find the maximum "score." +It seems to work fairly well, although I'll be the first to admit it isn't +perfect. +.SH HOW TO PLAY +Commands are given to +.I Sail +by typing a single character. You will then be prompted for further +input. A brief summary of the commands follows. +.bp +.SH COMMAND SUMMARY +.nf + + 'f' Fire broadsides if they bear + 'l' Reload + 'L' Unload broadsides (to change ammo) + 'm' Move + 'i' Print the closest ship + 'I' Print all ships + 'F' Find a particular ship or ships (e.g. "a?" for all Americans) + 's' Send a message around the fleet + 'b' Attempt to board an enemy ship + 'B' Recall boarding parties + 'c' Change set of sail + 'r' Repair + 'u' Attempt to unfoul + 'g' Grapple/ungrapple + 'v' Print version number of game + '^L' Redraw screen + 'Q' Quit + + 'C' Center your ship in the window + 'U' Move window up + 'D','N' Move window down + 'H' Move window left + 'J' Move window right + 'S' Toggle window to follow your ship or stay where it is + +.fi +.bg +.SH SCENARIOS +Here is a summary of the scenarios in +.I Sail: + +.br +.SH Ranger vs. Drake: +.nf +Wind from the N, blowing a fresh breeze. + +(a) Ranger 19 gun Sloop (crack crew) (7 pts) +(b) Drake 17 gun Sloop (crack crew) (6 pts) +.SH The Battle of Flamborough Head: +.nf +Wind from the S, blowing a fresh breeze. + +.fi +This is John Paul Jones' first famous battle. Aboard the Bonhomme +Richard, he was able to overcome the Serapis's greater firepower +by quickly boarding her. +.nf + +(a) Bonhomme Rich 42 gun Corvette (crack crew) (11 pts) +(b) Serapis 44 gun Frigate (crack crew) (12 pts) +.SH Arbuthnot and Des Touches: +.nf +Wind from the N, blowing a gale. + +(b) America 64 gun Ship of the Line (crack crew) (20 pts) +(b) Befford 74 gun Ship of the Line (crack crew) (26 pts) +(b) Adamant 50 gun Ship of the Line (crack crew) (17 pts) +(b) London 98 gun 3 Decker SOL (crack crew) (28 pts) +(b) Royal Oak 74 gun Ship of the Line (crack crew) (26 pts) +(f) Neptune 74 gun Ship of the Line (average crew) (24 pts) +(f) Duc Bougogne 80 gun 3 Decker SOL (average crew) (27 pts) +(f) Conquerant 74 gun Ship of the Line (average crew) (24 pts) +(f) Provence 64 gun Ship of the Line (average crew) (18 pts) +(f) Romulus 44 gun Ship of the Line (average crew) (10 pts) +.SH Suffren and Hughes: +.nf + +Wind from the S, blowing a fresh breeze. + +(b) Monmouth 74 gun Ship of the Line (average crew) (24 pts) +(b) Hero 74 gun Ship of the Line (crack crew) (26 pts) +(b) Isis 50 gun Ship of the Line (crack crew) (17 pts) +(b) Superb 74 gun Ship of the Line (crack crew) (27 pts) +(b) Burford 74 gun Ship of the Line (average crew) (24 pts) +(f) Flamband 50 gun Ship of the Line (average crew) (14 pts) +(f) Annibal 74 gun Ship of the Line (average crew) (24 pts) +(f) Severe 64 gun Ship of the Line (average crew) (18 pts) +(f) Brilliant 80 gun Ship of the Line (crack crew) (31 pts) +(f) Sphinx 80 gun Ship of the Line (average crew) (27 pts) +.SH Nymphe vs. Cleopatre: +.nf +Wind from the S, blowing a fresh breeze. + +(b) Nymphe 36 gun Frigate (crack crew) (11 pts) +(f) Cleopatre 36 gun Frigate (average crew) (10 pts) +.SH Mars vs. Hercule: +Wind from the S, blowing a fresh breeze. +.nf +(b) Mars 74 gun Ship of the Line (crack crew) (26 pts) +(f) Hercule 74 gun Ship of the Line (average crew) (23 pts) +.SH Ambuscade vs. Baionnaise: +.nf +Wind from the N, blowing a fresh breeze. + +(b) Ambuscade 32 gun Frigate (average crew) (9 pts) +(f) Baionnaise 24 gun Corvette (average crew) (9 pts) +.SH Constellation vs. Insurgent: +.nf +Wind from the S, blowing a gale. + +(a) Constellation 38 gun Corvette (elite crew) (17 pts) +(f) Insurgent 36 gun Corvette (average crew) (11 pts) +.SH Constellation vs. Vengeance: +.nf +Wind from the S, blowing a fresh breeze. + +(a) Constellation 38 gun Corvette (elite crew) (17 pts) +(f) Vengeance 40 gun Frigate (average crew) (15 pts) +.SH The Battle of Lissa: +.nf +Wind from the S, blowing a fresh breeze. + +(b) Amphion 32 gun Frigate (elite crew) (13 pts) +(b) Active 38 gun Frigate (elite crew) (18 pts) +(b) Volage 22 gun Frigate (elite crew) (11 pts) +(b) Cerberus 32 gun Frigate (elite crew) (13 pts) +(f) Favorite 40 gun Frigate (average crew) (15 pts) +(f) Flore 40 gun Frigate (average crew) (15 pts) +(f) Danae 40 gun Frigate (crack crew) (17 pts) +(f) Bellona 32 gun Frigate (green crew) (9 pts) +(f) Corona 40 gun Frigate (green crew) (12 pts) +(f) Carolina 32 gun Frigate (green crew) (7 pts) +.SH Constitution vs. Guerriere: +.nf +Wind from the SW, blowing a gale. + +(a) Constitution 44 gun Corvette (elite crew) (24 pts) +(b) Guerriere 38 gun Frigate (crack crew) (15 pts) +.SH United States vs. Macedonian: +.nf +Wind from the S, blowing a fresh breeze. + +(a) United States 44 gun Frigate (elite crew) (24 pts) +(b) Macedonian 38 gun Frigate (crack crew) (16 pts) +.SH Constitution vs. Java: +.nf +Wind from the S, blowing a fresh breeze. + +(a) Constitution 44 gun Corvette (elite crew) (24 pts) +(b) Java 38 gun Corvette (crack crew) (19 pts) +.SH Chesapeake vs. Shannon: +.nf +Wind from the S, blowing a fresh breeze. + +(a) Chesapeake 38 gun Frigate (average crew) (14 pts) +(b) Shannon 38 gun Frigate (elite crew) (17 pts) +.SH The Battle of Lake Erie: +.nf +Wind from the S, blowing a light breeze. + +(a) Lawrence 20 gun Sloop (crack crew) (9 pts) +(a) Niagara 20 gun Sloop (elite crew) (12 pts) +(b) Lady Prevost 13 gun Brig (crack crew) (5 pts) +(b) Detroit 19 gun Sloop (crack crew) (7 pts) +(b) Q. Charlotte 17 gun Sloop (crack crew) (6 pts) +.SH Wasp vs. Reindeer: +.nf +Wind from the S, blowing a light breeze. + +(a) Wasp 20 gun Sloop (elite crew) (12 pts) +(b) Reindeer 18 gun Sloop (elite crew) (9 pts) +.SH Constitution vs. Cyane and Levant: +.br +Wind from the S, blowing a moderate breeze. + +(a) Constitution 44 gun Corvette (elite crew) (24 pts) +(b) Cyane 24 gun Sloop (crack crew) (11 pts) +(b) Levant 20 gun Sloop (crack crew) (10 pts) +.br +.SH Pellew vs. Droits de L'Homme: +.nf +Wind from the N, blowing a gale. + +(b) Indefatigable 44 gun Frigate (elite crew) (14 pts) +(b) Amazon 36 gun Frigate (crack crew) (14 pts) +(f) Droits L'Hom 74 gun Ship of the Line (average crew) (24 pts) +.SH Algeciras: +.nf +Wind from the SW, blowing a moderate breeze. + +(b) Caesar 80 gun Ship of the Line (crack crew) (31 pts) +(b) Pompee 74 gun Ship of the Line (crack crew) (27 pts) +(b) Spencer 74 gun Ship of the Line (crack crew) (26 pts) +(b) Hannibal 98 gun 3 Decker SOL (crack crew) (28 pts) +(s) Real-Carlos 112 gun 3 Decker SOL (green crew) (27 pts) +(s) San Fernando 96 gun 3 Decker SOL (green crew) (24 pts) +(s) Argonauta 80 gun Ship of the Line (green crew) (23 pts) +(s) San Augustine 74 gun Ship of the Line (green crew) (20 pts) +(f) Indomptable 80 gun Ship of the Line (average crew) (27 pts) +(f) Desaix 74 gun Ship of the Line (average crew) (24 pts) +.SH Lake Champlain: +.nf +Wind from the N, blowing a fresh breeze. + +(a) Saratoga 26 gun Sloop (crack crew) (12 pts) +(a) Eagle 20 gun Sloop (crack crew) (11 pts) +(a) Ticonderoga 17 gun Sloop (crack crew) (9 pts) +(a) Preble 7 gun Brig (crack crew) (4 pts) +(b) Confiance 37 gun Frigate (crack crew) (14 pts) +(b) Linnet 16 gun Sloop (elite crew) (10 pts) +(b) Chubb 11 gun Brig (crack crew) (5 pts) +.SH Last Voyage of the USS President: +.nf +Wind from the N, blowing a fresh breeze. + +(a) President 44 gun Frigate (elite crew) (24 pts) +(b) Endymion 40 gun Frigate (crack crew) (17 pts) +(b) Pomone 44 gun Frigate (crack crew) (20 pts) +(b) Tenedos 38 gun Frigate (crack crew) (15 pts) +.SH Hornblower and the Natividad: +.nf +Wind from the E, blowing a gale. + +.fi +A scenario for you Horny fans. Remember, he sank the Natividad +against heavy odds and winds. Hint: don't try to board the Natividad, +her crew is much bigger, albeit green. +.nf + +(b) Lydia 36 gun Frigate (elite crew) (13 pts) +(s) Natividad 50 gun Ship of the Line (green crew) (14 pts) +.SH Curse of the Flying Dutchman: +.nf +Wind from the S, blowing a fresh breeze. + +Just for fun, take the Piece of cake. + +(s) Piece of Cake 24 gun Corvette (average crew) (9 pts) +(f) Flying Dutchy 120 gun 3 Decker SOL (elite crew) (43 pts) +.SH The South Pacific: +.nf +Wind from the S, blowing a strong breeze. + +(a) USS Scurvy 136 gun 3 Decker SOL (mutinous crew) (27 pts) +(b) HMS Tahiti 120 gun 3 Decker SOL (elite crew) (43 pts) +(s) Australian 32 gun Frigate (average crew) (9 pts) +(f) Bikini Atoll 7 gun Brig (crack crew) (4 pts) +.SH Hornblower and the battle of Rosas bay: +.nf +Wind from the E, blowing a fresh breeze. + +The only battle Hornblower ever lost. He was able to dismast one +ship and stern rake the others though. See if you can do as well. +.nf + +(b) Sutherland 74 gun Ship of the Line (crack crew) (26 pts) +(f) Turenne 80 gun 3 Decker SOL (average crew) (27 pts) +(f) Nightmare 74 gun Ship of the Line (average crew) (24 pts) +(f) Paris 112 gun 3 Decker SOL (green crew) (27 pts) +(f) Napolean 74 gun Ship of the Line (green crew) (20 pts) +.SH Cape Horn: +.nf +Wind from the NE, blowing a strong breeze. + +(a) Concord 80 gun Ship of the Line (average crew) (27 pts) +(a) Berkeley 98 gun 3 Decker SOL (crack crew) (28 pts) +(b) Thames 120 gun 3 Decker SOL (elite crew) (43 pts) +(s) Madrid 112 gun 3 Decker SOL (green crew) (27 pts) +(f) Musket 80 gun 3 Decker SOL (average crew) (27 pts) +.SH New Orleans: +.nf +Wind from the SE, blowing a fresh breeze. + +Watch that little Cypress go! + +(a) Alligator 120 gun 3 Decker SOL (elite crew) (43 pts) +(b) Firefly 74 gun Ship of the Line (crack crew) (27 pts) +(b) Cypress 44 gun Frigate (elite crew) (14 pts) +.SH Botany Bay: +.nf +Wind from the N, blowing a fresh breeze. + +(b) Shark 64 gun Ship of the Line (average crew) (18 pts) +(f) Coral Snake 44 gun Corvette (elite crew) (24 pts) +(f) Sea Lion 44 gun Frigate (elite crew) (24 pts) +.SH Voyage to the Bottom of the Sea: +.nf +Wind from the NW, blowing a fresh breeze. + +This one is dedicated to Richard Basehart and David Hedison. + +(a) Seaview 120 gun 3 Decker SOL (elite crew) (43 pts) +(a) Flying Sub 40 gun Frigate (crack crew) (17 pts) +(b) Mermaid 136 gun 3 Decker SOL (mutinous crew) (27 pts) +(s) Giant Squid 112 gun 3 Decker SOL (green crew) (27 pts) +.SH Frigate Action: +.nf +Wind from the E, blowing a fresh breeze. + +(a) Killdeer 40 gun Frigate (average crew) (15 pts) +(b) Sandpiper 40 gun Frigate (average crew) (15 pts) +(s) Curlew 38 gun Frigate (crack crew) (16 pts) +.SH The Battle of Midway: +.nf +Wind from the E, blowing a moderate breeze. + +(a) Enterprise 80 gun Ship of the Line (crack crew) (31 pts) +(a) Yorktown 80 gun Ship of the Line (average crew) (27 pts) +(a) Hornet 74 gun Ship of the Line (average crew) (24 pts) +(j) Akagi 112 gun 3 Decker SOL (green crew) (27 pts) +(j) Kaga 96 gun 3 Decker SOL (green crew) (24 pts) +(j) Soryu 80 gun Ship of the Line (green crew) (23 pts) + +.SH Star Trek: +.nf +Wind from the S, blowing a fresh breeze. + +(a) Enterprise 450 gun Ship of the Line (elite crew) (75 pts) +(a) Yorktown 450 gun Ship of the Line (elite crew) (75 pts) +(a) Reliant 450 gun Ship of the Line (elite crew) (75 pts) +(a) Galileo 450 gun Ship of the Line (elite crew) (75 pts) +(k) Kobayashi Maru 450 gun Ship of the Line (elite crew) (75 pts) +(k) Klingon II 450 gun Ship of the Line (elite crew) (75 pts) +(o) Red Orion 450 gun Ship of the Line (elite crew) (75 pts) +(o) Blue Orion 450 gun Ship of the Line (elite crew) (75 pts) + +.SH CONCLUSION + +.I Sail +has been a group effort. + +.SH "Ken Arnold Code" +curses library (pu!) +.SH AUTHOR +Dave Riggle +.SH CO-AUTHOR +Ed Wang +.SH REFITTING +Craig Leres +.SH CONSULTANTS +.nf +Chris Guthrie +Captain Happy +Horatio Nelson +Nancy Reagan + and many valiant others... +.fi +.SH "REFERENCES" +.nf +Wooden Ships & Iron Men, by Avalon Hill +Captain Horatio Hornblower Novels, (13 of them) by C.S. Forester +Captain Richard Bolitho Novels, (12 of them) by Alexander Kent +The Complete Works of Captain Frederick Marryat, (about 20) especially + Mr. Midshipman Easy + Peter Simple + Jacob Faithful + Japhet in Search of a Father + Snarleyyow, or The Dog Fiend + Frank Mildmay, or The Naval Officer +.fi +.SH "SEE ALSO" +midway(PUBLIC) +.SH BUGS +Probably a few, and please report them to "riggle@ernie" and "edward@arpa." diff --git a/src/games/sail/sync.c b/src/games/sail/sync.c new file mode 100644 index 0000000..2522f47 --- /dev/null +++ b/src/games/sail/sync.c @@ -0,0 +1,399 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "externs.h" +#include +#include +#include +#include +#include + +#define BUFSIZE 4096 + +static char sync_buf[BUFSIZE]; +static char *sync_bp = sync_buf; +static char sync_lock[25]; +static char sync_file[25]; +static long sync_seek; +static FILE *sync_fp; +#define SF "/tmp/#sailsink.%d" +#define LF "/tmp/#saillock.%d" + +/*VARARGS3*/ +void +makesignal(from, fmt, ship, a, b, c) + struct ship *from; + char *fmt; + register struct ship *ship; +{ + char message[80]; + + if (ship == 0) + (void) sprintf(message, fmt, a, b, c); + else + (void) sprintf(message, fmt, + ship->shipname, colours(ship), + sterncolour(ship), a, b, c); + Write(W_SIGNAL, from, 1, (int)message, 0, 0, 0); +} + +int +sync_exists(game) +{ + char buf[sizeof sync_file]; + struct stat s; + time_t t; + + (void) sprintf(buf, SF, game); + (void) time(&t); + if (stat(buf, &s) < 0) + return 0; + if (s.st_mtime < t - 60*60*2) { /* 2 hours */ + (void) unlink(buf); + (void) sprintf(buf, LF, game); + (void) unlink(buf); + return 0; + } else + return 1; +} + +int +sync_open() +{ + if (sync_fp != NULL) + (void) fclose(sync_fp); + (void) sprintf(sync_lock, LF, game); + (void) sprintf(sync_file, SF, game); + if (access(sync_file, 0) < 0) { + int omask = umask(issetuid ? 077 : 011); + sync_fp = fopen(sync_file, "w+"); + (void) umask(omask); + } else + sync_fp = fopen(sync_file, "r+"); + if (sync_fp == NULL) + return -1; + sync_seek = 0; + return 0; +} + +void +sync_close(remove) + int remove; +{ + if (sync_fp != 0) + (void) fclose(sync_fp); + if (remove) + (void) unlink(sync_file); +} + +static int +sync_update(type, ship, a, b, c, d) + int type; + register struct ship *ship; + int a, b, c, d; +{ + switch (type) { + case W_DBP: { + register struct BP *p = &ship->file->DBP[a]; + p->turnsent = b; + p->toship = SHIP(c); + p->mensent = d; + break; + } + case W_OBP: { + register struct BP *p = &ship->file->OBP[a]; + p->turnsent = b; + p->toship = SHIP(c); + p->mensent = d; + break; + } + case W_FOUL: { + register struct snag *p = &ship->file->foul[a]; + if (SHIP(a)->file->dir == 0) + break; + if (p->sn_count++ == 0) + p->sn_turn = turn; + ship->file->nfoul++; + break; + } + case W_GRAP: { + register struct snag *p = &ship->file->grap[a]; + if (SHIP(a)->file->dir == 0) + break; + if (p->sn_count++ == 0) + p->sn_turn = turn; + ship->file->ngrap++; + break; + } + case W_UNFOUL: { + register struct snag *p = &ship->file->foul[a]; + if (p->sn_count > 0) { + if (b) { + ship->file->nfoul -= p->sn_count; + p->sn_count = 0; + } else { + ship->file->nfoul--; + p->sn_count--; + } + } + break; + } + case W_UNGRAP: { + register struct snag *p = &ship->file->grap[a]; + if (p->sn_count > 0) { + if (b) { + ship->file->ngrap -= p->sn_count; + p->sn_count = 0; + } else { + ship->file->ngrap--; + p->sn_count--; + } + } + break; + } + case W_SIGNAL: + if (mode == MODE_PLAYER) { + if (nobells) + Signal("%s (%c%c): %s", ship, a, 0, 0, 0); + else + Signal("\7%s (%c%c): %s", ship, a, 0, 0, 0); + } + break; + case W_CREW: { + register struct shipspecs *s = ship->specs; + s->crew1 = a; + s->crew2 = b; + s->crew3 = c; + break; + } + case W_CAPTAIN: + (void) strncpy(ship->file->captain, (char *)a, + sizeof ship->file->captain - 1); + ship->file->captain[sizeof ship->file->captain - 1] = 0; + break; + case W_CAPTURED: + if (a < 0) + ship->file->captured = 0; + else + ship->file->captured = SHIP(a); + break; + case W_CLASS: + ship->specs->class = a; + break; + case W_DRIFT: + ship->file->drift = a; + break; + case W_EXPLODE: + if ((ship->file->explode = a) == 2) + ship->file->dir = 0; + break; + case W_FS: + ship->file->FS = a; + break; + case W_GUNL: { + register struct shipspecs *s = ship->specs; + s->gunL = a; + s->carL = b; + break; + } + case W_GUNR: { + register struct shipspecs *s = ship->specs; + s->gunR = a; + s->carR = b; + break; + } + case W_HULL: + ship->specs->hull = a; + break; + case W_MOVE: + (void) strncpy(ship->file->movebuf, (char *)a, + sizeof ship->file->movebuf - 1); + ship->file->movebuf[sizeof ship->file->movebuf - 1] = 0; + break; + case W_PCREW: + ship->file->pcrew = a; + break; + case W_POINTS: + ship->file->points = a; + break; + case W_QUAL: + ship->specs->qual = a; + break; + case W_RIGG: { + register struct shipspecs *s = ship->specs; + s->rig1 = a; + s->rig2 = b; + s->rig3 = c; + s->rig4 = d; + break; + } + case W_RIG1: + ship->specs->rig1 = a; + break; + case W_RIG2: + ship->specs->rig2 = a; + break; + case W_RIG3: + ship->specs->rig3 = a; + break; + case W_RIG4: + ship->specs->rig4 = a; + break; + case W_COL: + ship->file->col = a; + break; + case W_DIR: + ship->file->dir = a; + break; + case W_ROW: + ship->file->row = a; + break; + case W_SINK: + if ((ship->file->sink = a) == 2) + ship->file->dir = 0; + break; + case W_STRUCK: + ship->file->struck = a; + break; + case W_TA: + ship->specs->ta = a; + break; + case W_ALIVE: + alive = 1; + break; + case W_TURN: + turn = a; + break; + case W_WIND: + winddir = a; + windspeed = b; + break; + case W_BEGIN: + (void) strcpy(ship->file->captain, "begin"); + people++; + break; + case W_END: + *ship->file->captain = 0; + ship->file->points = 0; + people--; + break; + case W_DDEAD: + hasdriver = 0; + break; + default: + fprintf(stderr, "sync_update: unknown type %d\r\n", type); + return -1; + } + return 0; +} + +void +Write(type, ship, isstr, a, b, c, d) + int type; + struct ship *ship; + int isstr; + int a, b, c, d; +{ + if (isstr) + (void) sprintf(sync_bp, "%d %d %d %s\n", + type, ship->file->index, isstr, (char*) a); + else + (void) sprintf(sync_bp, "%d %d %d %d %d %d %d\n", + type, ship->file->index, isstr, a, b, c, d); + while (*sync_bp++) + ; + sync_bp--; + if (sync_bp >= &sync_buf[sizeof sync_buf]) + abort(); + (void) sync_update(type, ship, a, b, c, d); +} + +int +Sync() +{ + void (*sighup)(int), (*sigint)(int); + register int n; + int type, shipnum, isstr, a, b, c, d; + char buf[80]; + int erred = 0; + + sighup = signal(SIGHUP, SIG_IGN); + sigint = signal(SIGINT, SIG_IGN); + for (n = TIMEOUT; --n >= 0;) { +#ifdef LOCK_EX + if (flock(fileno(sync_fp), LOCK_EX|LOCK_NB) >= 0) + break; + if (errno != EWOULDBLOCK) + return -1; +#else + if (link(sync_file, sync_lock) >= 0) + break; + if (errno != EEXIST) + return -1; +#endif + sleep(1); + } + if (n <= 0) + return -1; + (void) fseek(sync_fp, sync_seek, 0); + for (;;) { + switch (fscanf(sync_fp, "%d%d%d", &type, &shipnum, &isstr)) { + case 3: + break; + case EOF: + goto out; + default: + goto bad; + } + if (shipnum < 0 || shipnum >= cc->vessels) + goto bad; + if (isstr != 0 && isstr != 1) + goto bad; + if (isstr) { + register char *p; + for (p = buf;;) { + switch (*p++ = getc(sync_fp)) { + case '\n': + p--; + case EOF: + break; + default: + if (p >= buf + sizeof buf) + p--; + continue; + } + break; + } + *p = 0; + for (p = buf; *p == ' '; p++) + ; + a = (int)p; + b = c = d = 0; + } else + if (fscanf(sync_fp, "%d%d%d%d", &a, &b, &c, &d) != 4) + goto bad; + if (sync_update(type, SHIP(shipnum), a, b, c, d) < 0) + goto bad; + } +bad: + erred++; +out: + if (!erred && sync_bp != sync_buf) { + (void) fseek(sync_fp, 0L, 2); + (void) fwrite(sync_buf, sizeof *sync_buf, sync_bp - sync_buf, + sync_fp); + (void) fflush(sync_fp); + sync_bp = sync_buf; + } + sync_seek = ftell(sync_fp); +#ifdef LOCK_EX + (void) flock(fileno(sync_fp), LOCK_UN); +#else + (void) unlink(sync_lock); +#endif + (void) signal(SIGHUP, sighup); + (void) signal(SIGINT, sigint); + return erred ? -1 : 0; +} diff --git a/src/games/sail/version.c b/src/games/sail/version.c new file mode 100644 index 0000000..b67942c --- /dev/null +++ b/src/games/sail/version.c @@ -0,0 +1,6 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +char version[] = "Wooden Ships and Iron Men, Version 5.1 (85/05/29)"; diff --git a/src/games/snake/Makefile b/src/games/snake/Makefile new file mode 100644 index 0000000..18588cf --- /dev/null +++ b/src/games/snake/Makefile @@ -0,0 +1,41 @@ +# +# Copyright (c) 1980 Regents of the University of California. +# All rights reserved. The Berkeley software License Agreement +# specifies the terms and conditions for redistribution. +# +# @(#)Makefile 5.1.1 (2.11BSD GTE) 1/16/95 +# +DESTDIR= +CFLAGS= -O -DCHECKBUSY +LIBS= -lm -ltermcap +BIN= $(DESTDIR)/usr/games +LIB= $(DESTDIR)/usr/games/lib +USER= daemon +UTILS= snscore busy +OBJS= snake.o move.o +ALL= snake ${UTILS} +SEPFLAG= -i + +all: ${ALL} + +snake: $(OBJS) + cc ${SEPFLAG} $(OBJS) -o snake $(LIBS) + +snake.o move.o:snake.h + +snscore: snscore.c + cc ${SEPFLAG} $(CFLAGS) snscore.c -o snscore + +busy: busy.c + cc ${SEPFLAG} $(CFLAGS) busy.c -o busy + +install: all + install -s -m 4755 -o ${USER} snake ${BIN}/snake + install -s -m 755 -o ${USER} snscore ${BIN}/snscore + install -s -m 755 -o ${USER} busy ${LIB}/busy + cat /dev/null >> $(LIB)/snakerawscores + chmod 644 $(LIB)/snakerawscores + chown $(USER) $(LIB)/snakerawscores + +clean: + rm -f *.o ${ALL} diff --git a/src/games/snake/busy.c b/src/games/snake/busy.c new file mode 100644 index 0000000..4467ea9 --- /dev/null +++ b/src/games/snake/busy.c @@ -0,0 +1,36 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +#if defined(DOSCCS) && !defined(lint) +static char sccsid[] = "@(#)busy.c 5.1.2 (2.11BSD GTE) 1/16/95"; +#endif + +/* + * busy: print an indication of how busy the system is for games. + */ +#ifndef MAX +# define MAX 30 +#endif + +#include +main(argc, argv) +char **argv; +{ + double la[3]; + double max; + + getloadavg(la, 3); + max = la[0]; + if (la[1] > max) max = la[1]; + if (la[2] > max) max = la[2]; + if (argc > 1) + printf("1=%g, 5=%g, 15=%g, max=%g\n", la[0], la[1], la[2], max); + if (max > MAX) + printf("100\n"); /* incredibly high, no games allowed */ + else + printf("0\n"); + exit(0); +} diff --git a/src/games/snake/move.c b/src/games/snake/move.c new file mode 100644 index 0000000..c0138c1 --- /dev/null +++ b/src/games/snake/move.c @@ -0,0 +1,634 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +#if !defined(lint) && defined(DOSCCS) +static char sccsid[] = "@(#)move.c 5.1.1 (2.11BSD) 1997/3/28"; +#endif + +/************************************************************************* + * + * MOVE LIBRARY + * + * This set of subroutines moves a cursor to a predefined + * location, independent of the terminal type. If the + * terminal has an addressable cursor, it uses it. If + * not, it optimizes for tabs (currently) even if you don't + * have them. + * + * At all times the current address of the cursor must be maintained, + * and that is available as structure cursor. + * + * The following calls are allowed: + * move(sp) move to point sp. + * up() move up one line. + * down() move down one line. + * bs() move left one space (except column 0). + * nd() move right one space(no write). + * clear() clear screen. + * home() home. + * ll() move to lower left corner of screen. + * cr() carriage return (no line feed). + * printf() just like standard printf, but keeps track + * of cursor position. (Uses pstring). + * aprintf() same as printf, but first argument is &point. + * (Uses pstring). + * pstring(s) output the string of printing characters. + * However, '\r' is interpreted to mean return + * to column of origination AND do linefeed. + * '\n' causes . + * putpad(str) calls tputs to output character with proper + * padding. + * outch() the output routine for a character used by + * tputs. It just calls putchar. + * pch(ch) output character to screen and update + * cursor address (must be a standard + * printing character). WILL SCROLL. + * pchar(ps,ch) prints one character if it is on the + * screen at the specified location; + * otherwise, dumps it.(no wrap-around). + * + * getcap() initializes strings for later calls. + * cap(string) outputs the string designated in the termcap + * data base. (Should not move the cursor.) + * done(int) returns the terminal to intial state. If int + * is not 0, it exits. + * + * same(&p1,&p2) returns 1 if p1 and p2 are the same point. + * point(&p,x,y) return point set to x,y. + * + * baudrate(x) returns the baudrate of the terminal. + * delay(t) causes an approximately constant delay + * independent of baudrate. + * Duration is ~ t/20 seconds. + * + ******************************************************************************/ + +#include "snake.h" + +int CMlength; +int NDlength; +int BSlength; +int delaystr[10]; +short ospeed; + +static char str[80]; + +move(sp) +struct point *sp; +{ + int distance; + int tabcol,ct; + struct point z; + + if (sp->line <0 || sp->col <0 || sp->col > COLUMNS){ + printf("move to [%d,%d]?",sp->line,sp->col); + return; + } + if (sp->line >= LINES){ + move(point(&z,sp->col,LINES-1)); + while(sp->line-- >= LINES)putchar('\n'); + return; + } + + if (CM != 0) { + char *cmstr = tgoto(CM, sp->col, sp->line); + + CMlength = strlen(cmstr); + if(cursor.line == sp->line){ + distance = sp->col - cursor.col; + if(distance == 0)return; /* Already there! */ + if(distance > 0){ /* Moving to the right */ + if(distance*NDlength < CMlength){ + right(sp); + return; + } + if(TA){ + ct=sp->col&7; + tabcol=(cursor.col|7)+1; + do{ + ct++; + tabcol=(tabcol|7)+1; + } + while(tabcolcol); + if(ctcol < CMlength){ + cr(); + right(sp); + return; + } + /* No more optimizations on same row. */ + } + distance = sp->col - cursor.col; + distance = distance > 0 ? + distance*NDlength : -distance * BSlength; +if(distance < 0)printf("ERROR: distance is negative: %d",distance); + distance += abs(sp->line - cursor.line); + if(distance >= CMlength){ + putpad(cmstr); + cursor.line = sp->line; + cursor.col = sp->col; + return; + } + } + + /* + * If we get here we have a terminal that can't cursor + * address but has local motions or one which can cursor + * address but can get there quicker with local motions. + */ + gto(sp); +} +gto(sp) +struct point *sp; +{ + + int distance,f,tfield,j; + + if (cursor.line > LINES || cursor.line <0 || + cursor.col <0 || cursor.col > COLUMNS) + printf("ERROR: cursor is at %d,%d\n", + cursor.line,cursor.col); + if (sp->line > LINES || sp->line <0 || + sp->col <0 || sp->col > COLUMNS) + printf("ERROR: target is %d,%d\n",sp->line,sp->col); + tfield = (sp->col) >> 3; + if (sp->line == cursor.line){ + if (sp->col > cursor.col)right(sp); + else{ + distance = (cursor.col -sp->col)*BSlength; + if (((TA) && + (distance > tfield+((sp->col)&7)*NDlength) + ) || + (((cursor.col)*NDlength) < distance) + ){ + cr(); + right(sp); + } + else{ + while(cursor.col > sp->col) bs(); + } + } + return; + } + /*must change row */ + if (cursor.col - sp->col > (cursor.col >> 3)){ + if (cursor.col == 0)f = 0; + else f = -1; + } + else f = cursor.col >> 3; + if (((sp->line << 1) + 1 < cursor.line - f) && (HO != 0)){ + /* + * home quicker than rlf: + * (sp->line + f > cursor.line - sp->line) + */ + putpad(HO); + cursor.col = cursor.line = 0; + gto(sp); + return; + } + if (((sp->line << 1) > cursor.line + LINES+1 + f) && (LL != 0)){ + /* home,rlf quicker than lf + * (LINES+1 - sp->line + f < sp->line - cursor.line) + */ + if (cursor.line > f + 1){ + /* is home faster than wraparound lf? + * (cursor.line + 20 - sp->line > 21 - sp->line + f) + */ + ll(); + gto(sp); + return; + } + } + if ((LL != 0) && (sp->line > cursor.line + (LINES >> 1) - 1)) + cursor.line += LINES; + while(sp->line > cursor.line)down(); + while(sp->line < cursor.line)up(); + gto(sp); /*can recurse since cursor.line = sp->line */ +} + +right(sp) +struct point *sp; +{ + int field,tfield; + int tabcol,strlength; + + if (sp->col < cursor.col) + printf("ERROR:right() can't move left\n"); + if(TA){ /* If No Tabs: can't send tabs because ttydrive + * loses count with control characters. + */ + field = cursor.col >> 3; +/* + * This code is useful for a terminal which wraps around on backspaces. + * (Mine does.) Unfortunately, this is not specified in termcap, and + * most terminals don't work that way. (Of course, most terminals + * have addressible cursors, too). + */ + if (BW && (CM == 0) && + ((sp->col << 1) - field > (COLUMNS - 8) << 1 ) + ){ + if (cursor.line == 0){ + outch('\n'); + } + outch('\r'); + cursor.col = COLUMNS + 1; + while(cursor.col > sp->col)bs(); + if (cursor.line != 0) outch('\n'); + return; + } + + tfield = sp->col >> 3; + + while (field < tfield){ + putpad(TA); + cursor.col = ++field << 3; + } + tabcol = (cursor.col|7) + 1; + strlength = (tabcol - sp->col)*BSlength + 1; + /* length of sequence to overshoot */ + if (((sp->col - cursor.col)*NDlength > strlength) && + (tabcol < COLUMNS) + ){ + /* + * Tab past and backup + */ + putpad(TA); + cursor.col = (cursor.col | 7) + 1; + while(cursor.col > sp->col)bs(); + } + } + while (sp->col > cursor.col){ + nd(); + } +} + +cr(){ + outch('\r'); + cursor.col = 0; +} + +clear(){ + int i; + + if (CL){ + putpad(CL); + cursor.col=cursor.line=0; + } else { + for(i=0; i= LINES)cursor.line=LINES-1; +} +bs(){ + if (cursor.col > 0){ + putpad(BS); + cursor.col--; + } +} + +nd(){ + putpad(ND); + cursor.col++; + if (cursor.col == COLUMNS+1){ + cursor.line++; + cursor.col = 0; + if (cursor.line >= LINES)cursor.line=LINES-1; + } +} + +pch(c) +{ + outch(c); + if(++cursor.col >= COLUMNS && AM) { + cursor.col = 0; + ++cursor.line; + } +} + +aprintf(ps,st,v0,v1,v2,v3,v4,v5,v6,v7,v8,v9) +struct point *ps; +char *st; +int v0,v1,v2,v3,v4,v5,v6,v7,v8,v9; + +{ + struct point p; + + p.line = ps->line+1; p.col = ps->col+1; + move(&p); + sprintf(str,st,v0,v1,v2,v3,v4,v5,v6,v7,v8,v9); + pstring(str); +} + +printf(st,v0,v1,v2,v3,v4,v5,v6,v7,v8,v9) +char *st; +int v0,v1,v2,v3,v4,v5,v6,v7,v8,v9; +{ + sprintf(str,st,v0,v1,v2,v3,v4,v5,v6,v7,v8,v9); + pstring(str); +} + +pstring(s) +char *s;{ + struct point z; + int stcol; + + stcol = cursor.col; + while (s[0] != '\0'){ + switch (s[0]){ + case '\n': + move(point(&z,0,cursor.line+1)); + break; + case '\r': + move(point(&z,stcol,cursor.line+1)); + break; + case '\t': + z.col = (((cursor.col + 8) >> 3) << 3); + z.line = cursor.line; + move(&z); + break; + case '\b': + bs(); + break; + case CTRL(g): + outch(CTRL(g)); + break; + default: + if (s[0] < ' ')break; + pch(s[0]); + } + s++; + } +} + +pchar(ps,ch) +struct point *ps; +char ch;{ + struct point p; + p.col = ps->col + 1; p.line = ps->line + 1; + if ( + (p.col >= 0) && + (p.line >= 0) && + ( + ( + (p.line < LINES) && + (p.col < COLUMNS) + ) || + ( + (p.col == COLUMNS) && + (p.line < LINES-1) + ) + ) + ){ + move(&p); + pch(ch); + } +} + + +outch(c) +{ + putchar(c); +} + +putpad(str) +char *str; +{ + if (str) + tputs(str, 1, outch); +} +baudrate() +{ + + switch (orig.sg_ospeed){ + case B300: + return(300); + case B1200: + return(1200); + case B4800: + return(4800); + case B9600: + return(9600); + default: + return(0); + } +} +delay(t) +int t; +{ + int k,j; + + k = baudrate() * t / 300; + for(j=0;jline == sp2->line) && (sp1->col == sp2->col))return(1); + return(0); +} + +struct point *point(ps,x,y) +struct point *ps; +int x,y; +{ + ps->col=x; + ps->line=y; + return(ps); +} + +char *ap; + +getcap() +{ + char *getenv(); + char *term; + char *xPC; + struct point z; + int stop(); + + term = getenv("TERM"); + if (term==0) { + fprintf(stderr, "No TERM in environment\n"); + exit(1); + } + + switch (tgetent(tbuf, term)) { + case -1: + fprintf(stderr, "Cannot open termcap file\n"); + exit(2); + case 0: + fprintf(stderr, "%s: unknown terminal", term); + exit(3); + } + + ap = tcapbuf; + + LINES = tgetnum("li"); + COLUMNS = tgetnum("co"); + lcnt = LINES; + ccnt = COLUMNS - 1; + + AM = tgetflag("am"); + BW = tgetflag("bw"); + + ND = tgetstr("nd", &ap); + UP = tgetstr("up", &ap); + + DO = tgetstr("do", &ap); + if (DO == 0) + DO = "\n"; + + BS = tgetstr("bc", &ap); + if (BS == 0 && tgetflag("bs")) + BS = "\b"; + if (BS) + xBC = *BS; + + TA = tgetstr("ta", &ap); + if (TA == 0 && tgetflag("pt")) + TA = "\t"; + + HO = tgetstr("ho", &ap); + CL = tgetstr("cl", &ap); + CM = tgetstr("cm", &ap); + LL = tgetstr("ll", &ap); + + KL = tgetstr("kl", &ap); + KR = tgetstr("kr", &ap); + KU = tgetstr("ku", &ap); + KD = tgetstr("kd", &ap); + Klength = strlen(KL); + /* NOTE: If KL, KR, KU, and KD are not + * all the same length, some problems + * may arise, since tests are made on + * all of them together. + */ + + TI = tgetstr("ti", &ap); + TE = tgetstr("te", &ap); + KS = tgetstr("ks", &ap); + KE = tgetstr("ke", &ap); + + xPC = tgetstr("pc", &ap); + if (xPC) + PC = *xPC; + + NDlength = strlen(ND); + BSlength = strlen(BS); + if ((CM == 0) && + (HO == 0 | UP==0 || BS==0 || ND==0)) { + fprintf(stderr, "Terminal must have addressible "); + fprintf(stderr, "cursor or home + 4 local motions\n"); + exit(5); + } + if (tgetflag("os")) { + fprintf(stderr, "Terminal must not overstrike\n"); + exit(5); + } + if (LINES <= 0 || COLUMNS <= 0) { + fprintf(stderr, "Must know the screen size\n"); + exit(5); + } + + gtty(0, &orig); + new=orig; + new.sg_flags &= ~(ECHO|CRMOD|XTABS); + new.sg_flags |= CBREAK; + signal(SIGINT,stop); + ospeed = orig.sg_ospeed; +#ifdef TIOCGLTC + ioctl(0, TIOCGLTC, &olttyc); + nlttyc = olttyc; + nlttyc.t_suspc = '\377'; + nlttyc.t_dsuspc = '\377'; +#endif + raw(); + + if ((orig.sg_flags & XTABS) == XTABS) TA=0; + putpad(KS); + putpad(TI); + point(&cursor,0,LINES-1); +} diff --git a/src/games/snake/snake.6 b/src/games/snake/snake.6 new file mode 100644 index 0000000..0a6760d --- /dev/null +++ b/src/games/snake/snake.6 @@ -0,0 +1,93 @@ +.\" Copyright (c) 1980 Regents of the University of California. +.\" All rights reserved. The Berkeley software License Agreement +.\" specifies the terms and conditions for redistribution. +.\" +.\" @(#)snake.6 6.1 (Berkeley) 5/20/85 +.\" +.TH SNAKE 6 "May 20, 1985" +.UC 4 +.SH NAME +snake, snscore \- display chase game +.SH SYNOPSIS +.B /usr/games/snake +[ +.BI \-w n +] [ +.BI \-l n +] +.br +.B /usr/games/snscore +.SH DESCRIPTION +Snake is a display-based game which must be played on a CRT terminal +from among those supported by vi(1). +The object of the game is to make as much money as possible without +getting eaten by the snake. The +.B \-l +and +.B \-w +options allow you to specify the length and width of the field. +By default the entire screen (except for the last column) is used. +.PP +You are represented on the screen by an I. +The snake is 6 squares long and is represented by S's. +The money is $, and an exit is #. +Your score is posted in the upper left hand corner. +.PP +You can move around using the same conventions as vi(1), +the h, j, k, and l keys work, as do the arrow keys. +Other possibilities include: +.IP sefc +These keys are like hjkl but form a directed pad around the d key. +.IP HJKL +These keys move you all the way in the indicated direction to the +same row or column as the money. This does +.I not +let you jump away from the snake, but rather saves you from having +to type a key repeatedly. The snake still gets all his turns. +.IP SEFC +Likewise for the upper case versions on the left. +.IP ATPB +These keys move you to the four edges of the screen. +Their position on the keyboard is the mnemonic, e.g. +P is at the far right of the keyboard. +.IP x +This lets you quit the game at any time. +.IP p +Points in a direction you might want to go. +.IP w +Space warp to get out of tight squeezes, at a price. +.IP ! +Shell escape +.IP ^Z +Suspend the snake game, on systems which support it. +Otherwise an interactive shell is started up. +.PP +To earn money, move to the same square the money is on. +A new $ will appear when you earn the current one. +As you get richer, the snake gets hungrier. +To leave the game, move to the exit (#). +.PP +A record is kept of the personal best score of each player. +Scores are only counted if you leave at the exit, +getting eaten by the snake is worth nothing. +.PP +As in pinball, matching the last digit of your score to the number +which appears after the game is worth a bonus. +.PP +To see who wastes time playing snake, run +.I /usr/games/snscore . +.SH FILES +.nf +.ta \w'/usr/games/lib/snakerawscores 'u +/usr/games/lib/snakerawscores database of personal bests +/usr/games/lib/snake.log log of games played +/usr/games/busy program to determine if system too busy +.DT +.fi +.SH BUGS +.PP +When playing on a small screen, +it's hard to tell when you hit the edge of the screen. +.PP +The scoring function takes into account the size of the screen. +A perfect function to do this equitably has not been devised. diff --git a/src/games/snake/snake.c b/src/games/snake/snake.c new file mode 100644 index 0000000..62b813b --- /dev/null +++ b/src/games/snake/snake.c @@ -0,0 +1,914 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +#if !defined(lint) && defined(DOSCCS) +char copyright[] = +"@(#) Copyright (c) 1980 Regents of the University of California.\n\ + All rights reserved.\n"; + +static char sccsid[] = "@(#)snake.c 5.1.1 (2.11BSD) 1997/7/29"; +#endif + +/* + * snake - crt hack game. + * + * You move around the screen with arrow keys trying to pick up money + * without getting eaten by the snake. hjkl work as in vi in place of + * arrow keys. You can leave at the exit any time. + * + * compile as follows: + * cc -O snake.c move.c -o snake -lm -ltermlib + */ + +#include "snake.h" +#include + + /* + * If CHECKBUSY is defined, the file BUSY must be executable + * and must return a value which is used to determine the priority + * a which snake runs. A zero value means no nice. + * If BUSY does not exist, snake won't play. + */ +#ifndef BUSY +#define BUSY "/usr/games/lib/busy" +#endif + + /* + * This is the data file for scorekeeping. + */ +#ifndef SNAKERAWSCORES +#define SNAKERAWSCORES "/usr/games/lib/snakerawscores" +#endif + + /* + * If it exists, a log is kept here. Otherwise it isn't. + */ +#ifndef LOGFILE +#define LOGFILE "/usr/games/lib/snake.log" +#endif + +#define PENALTY 10 /* % penalty for invoking spacewarp */ + +#define EOT '\004' +#define LF '\n' +#define DEL '\177' + +#define ME 'I' +#define SNAKEHEAD 'S' +#define SNAKETAIL 's' +#define TREASURE '$' +#define GOAL '#' + +#define BSIZE 80 + +struct point you; +struct point money; +struct point finish; +struct point snake[6]; + +int loot, penalty; +int long tl, tm=0L; +int argcount; +char **argval; +int moves; +static char str[BSIZE]; +char stri[BSIZE]; +char *p; +char ch, savec; +char *kl, *kr, *ku, *kd; +int fast=1; +int repeat=1; +long tv; +char *tn; + +main(argc,argv) +int argc; +char **argv; +{ + int i,k; + int j; + long time(); + int stop(); + char stdbuf[BUFSIZ]; + + argcount = argc; + argval = argv; + penalty = loot = 0; + getcap(); + ccnt -= 2; lcnt -= 2; /* compensate for border */ + busy(); + time(&tv); + + for (i=1; i= '0')) { + ungetc(c,stdin); + j = scanf("%d",&repeat); + c = getchar() & 0177; + } else { + if (c != '.') repeat = 1; + } + if (c == '.') { + c = lastc; + } + if ((Klength > 0) && + (c == *KL || c == *KR || c == *KU || c == *KD)) { + savec = c; + match = 0; + kl = KL; + kr = KR; + ku = KU; + kd = KD; + for (j=Klength;j>0;j--){ + if (match != 1) { + match = 0; + if (*kl++ == c) { + ch = 'h'; + match++; + } + if (*kr++ == c) { + ch = 'l'; + match++; + } + if (*ku++ == c) { + ch = 'k'; + match++; + } + if (*kd++ == c) { + ch = 'j'; + match++; + } + if (match == 0) { + ungetc(c,stdin); + ch = savec; + /* Oops! + * This works if we figure it out on second character. + */ + break; + } + } + savec = c; + if(j != 1) c = getchar() & 0177; + } + c = ch; + } + if (!fast) flushi(); + lastc = c; + switch (c){ + case CTRL(z): + case CTRL(c): + suspend(); + continue; + case EOT: + case 'x': + case 0177: /* del or end of file */ + ll(); + length(moves); + logit("quit"); + done(); + case '!': + cook(); + putchar('\n'); + putchar(c); + fflush(stdout); + j = read(0,stri,BSIZE); + stri[j] = 0; + if (fork() == 0) { + setuid(getuid()); + system(stri); + } else + wait(0); + printf("READY?\n"); + fflush(stdout); + raw(); + c = getchar(); + ungetc(c,stdin); + putpad(KS); + putpad(TI); + point(&cursor,0,lcnt-1); + case CTRL(l): + setup(); + winnings(cashvalue); + continue; + case 'p': + case 'd': + snap(); + continue; + case 'w': + spacewarp(0); + continue; + case 'A': + repeat = you.col; + c = 'h'; + break; + case 'H': + case 'S': + repeat = you.col - money.col; + c = 'h'; + break; + case 'T': + repeat = you.line; + c = 'k'; + break; + case 'K': + case 'E': + repeat = you.line - money.line; + c = 'k'; + break; + case 'P': + repeat = ccnt - 1 - you.col; + c = 'l'; + break; + case 'L': + case 'F': + repeat = money.col - you.col; + c = 'l'; + break; + case 'B': + repeat = lcnt - 1 - you.line; + c = 'j'; + break; + case 'J': + case 'C': + repeat = money.line - you.line; + c = 'j'; + break; + } + for(k=1;k<=repeat;k++){ + moves++; + switch(c) { + case 's': + case 'h': + case '\b': + if (you.col >0) { + if((fast)||(k == 1)) + pchar(&you,' '); + you.col--; + if((fast) || (k == repeat) || + (you.col == 0)) + pchar(&you,ME); + } + break; + case 'f': + case 'l': + case ' ': + if (you.col < ccnt-1) { + if((fast)||(k == 1)) + pchar(&you,' '); + you.col++; + if((fast) || (k == repeat) || + (you.col == ccnt-1)) + pchar(&you,ME); + } + break; + case CTRL(p): + case 'e': + case 'k': + case 'i': + if (you.line > 0) { + if((fast)||(k == 1)) + pchar(&you,' '); + you.line--; + if((fast) || (k == repeat) || + (you.line == 0)) + pchar(&you,ME); + } + break; + case CTRL(n): + case 'c': + case 'j': + case LF: + case 'm': + if (you.line+1 < lcnt) { + if((fast)||(k == 1)) + pchar(&you,' '); + you.line++; + if((fast) || (k == repeat) || + (you.line == lcnt-1)) + pchar(&you,ME); + } + break; + } + + if (same(&you,&money)) + { + char xp[20]; + struct point z; + loot += 25; + if(k < repeat) + pchar(&you,' '); + do { + random(&money); + } while (money.col == finish.col && money.line == finish.line || + money.col < 5 && money.line == 0 || + money.col == you.col && money.line == you.line); + pchar(&money,TREASURE); + winnings(cashvalue); + continue; + } + if (same(&you,&finish)) + { + win(&finish); + ll(); + cook(); + printf("You have won with $%d.\n",cashvalue); + fflush(stdout); + logit("won"); + post(cashvalue,0); + length(moves); + done(0); + } + if (pushsnake())break; + } + fflush(stdout); + } +} + +setup(){ /* + * setup the board + */ + int i; + + clear(); + pchar(&you,ME); + pchar(&finish,GOAL); + pchar(&money,TREASURE); + for(i=1; i<6; i++) { + pchar(&snake[i],SNAKETAIL); + } + pchar(&snake[0], SNAKEHEAD); + drawbox(); + fflush(stdout); +} + +drawbox() +{ + register int i; + struct point p; + + p.line = -1; + for (i= 0; icol = sp->line = -1; /* impossible */ + do { + issame = 0; + p.col = ((rand()>>8) & 0377)% ccnt; + p.line = ((rand()>>8) & 0377)% lcnt; + + /* make sure it's not on top of something else */ + if (p.line == 0 && p.col <5) issame++; + if(same(&p, &you)) issame++; + if(same(&p, &money)) issame++; + if(same(&p, &finish)) issame++; + for (i=0; i<5; i++) + if(same(&p, &snake[i])) issame++; + + } while (issame); + *sp = p; +} + +busy() +{ + FILE *pip, *popen(); + char c; + int b,r; + float a; + +#ifdef CHECKBUSY + if (! strcmp (argval[0], "test")) return; + if ((access(BUSY,1) != 0) || (pip = popen(BUSY,"r")) == NULL){ + printf("Sorry, no snake just now.\n"); + done(); + } + fscanf(pip,"%d",&b); + pclose(pip); + if (b > 20) { + printf("Sorry, the system is too heavily loaded right now.\n"); + done(); + } + nice(b); +#endif +} + +post(iscore, flag) +int iscore, flag; +{ + short score = iscore; + int rawscores; + short uid; + short oldbest=0; + short allbwho=0, allbscore=0; + struct passwd *p, *getpwuid(); + + /* + * Neg uid, 0, and 1 cannot have scores recorded. + */ + if ((uid=getuid()) > 1 && (rawscores=open(SNAKERAWSCORES,2))>=0) { + /* Figure out what happened in the past */ + read(rawscores, &allbscore, sizeof(short)); + read(rawscores, &allbwho, sizeof(short)); + lseek(rawscores, ((long)uid)*sizeof(short), 0); + read(rawscores, &oldbest, sizeof(short)); + if (flag) return (score > oldbest ? 1 : 0); + + /* Update this jokers best */ + if (score > oldbest) { + lseek(rawscores, ((long)uid)*sizeof(short), 0); + write(rawscores, &score, sizeof(short)); + printf("You bettered your previous best of $%d\n", oldbest); + } else + printf("Your best to date is $%d\n", oldbest); + + /* See if we have a new champ */ + p = getpwuid(allbwho); + if (p == NULL || score > allbscore) { + lseek(rawscores, (long)0, 0); + write(rawscores, &score, sizeof(short)); + write(rawscores, &uid, sizeof(short)); + if (p != NULL) + printf("You beat %s's old record of $%d!\n", p->pw_name, allbscore); + else + printf("You set a new record!\n"); + } else + printf("The highest is %s with $%d\n", p->pw_name, allbscore); + close(rawscores); + } else + if (!flag) + printf("Unable to post score.\n"); + return (1); +} + +/* + * Flush typeahead to keep from buffering a bunch of chars and then + * overshooting. This loses horribly at 9600 baud, but works nicely + * if the terminal gets behind. + */ +flushi() +{ + stty(0, &new); +} +int mx [8] = { + 0, 1, 1, 1, 0,-1,-1,-1}; +int my [8] = { + -1,-1, 0, 1, 1, 1, 0,-1}; +float absv[8]= { + 1, 1.4, 1, 1.4, 1, 1.4, 1, 1.4 +}; +int oldw=0; +chase (np, sp) +struct point *sp, *np; +{ + /* this algorithm has bugs; otherwise the + snake would get too good */ + struct point d; + int w, i, wt[8]; + double sqrt(), v1, v2, vp, max; + point(&d,you.col-sp->col,you.line-sp->line); + v1 = sqrt( (double) (d.col*d.col + d.line*d.line) ); + w=0; + max=0; + for(i=0; i<8; i++) + { + vp = d.col*mx[i] + d.line*my[i]; + v2 = absv[i]; + if (v1>0) + vp = ((double)vp)/(v1*v2); + else vp=1.0; + if (vp>max) + { + max=vp; + w=i; + } + } + for(i=0; i<8; i++) + { + point(&d,sp->col+mx[i],sp->line+my[i]); + wt[i]=0; + if (d.col<0 || d.col>=ccnt || d.line<0 || d.line>=lcnt) + continue; + if (d.line == 0 && d.col < 5) continue; + if (same(&d,&money)) continue; + if (same(&d,&finish)) continue; + wt[i]= i==w ? loot/10 : 1; + if (i==oldw) wt [i] += loot/20; + } + for(w=i=0; i<8; i++) + w+= wt[i]; + vp = (( rand() >> 6 ) & 01777) %w; + for(i=0; i<8; i++) + if (vp col+mx[w],sp->line+my[w]); +} + +spacewarp(w) +int w;{ + struct point p; + int j; + + random(&you); + point(&p,COLUMNS/2 - 8,LINES/2 - 1); + if (p.col < 0) + p.col = 0; + if (p.line < 0) + p.line = 0; + if (w) { + sprintf(str,"BONUS!!!"); + loot = loot - penalty; + penalty = 0; + } else { + sprintf(str,"SPACE WARP!!!"); + penalty += loot/PENALTY; + } + for(j=0;j<3;j++){ + clear(); + delay(5); + aprintf(&p,str); + delay(10); + } + setup(); + winnings(cashvalue); +} +snap() +{ + struct point p; + int i; + + if(you.line < 3){ + pchar(point(&p,you.col,0),'-'); + } + if(you.line > lcnt-4){ + pchar(point(&p,you.col,lcnt-1),'_'); + } + if(you.col < 10){ + pchar(point(&p,0,you.line),'('); + } + if(you.col > ccnt-10){ + pchar(point(&p,ccnt-1,you.line),')'); + } + if (! stretch(&money)) if (! stretch(&finish)) delay(10); + if(you.line < 3){ + point(&p,you.col,0); + remove(&p); + } + if(you.line > lcnt-4){ + point(&p,you.col,lcnt-1); + remove(&p); + } + if(you.col < 10){ + point(&p,0,you.line); + remove(&p); + } + if(you.col > ccnt-10){ + point(&p,ccnt-1,you.line); + remove(&p); + } + fflush(stdout); +} +stretch(ps) +struct point *ps;{ + struct point p; + + point(&p,you.col,you.line); + if(abs(ps->col-you.col) < 6){ + if(you.line < ps->line){ + for (p.line = you.line+1;p.line <= ps->line;p.line++) + pchar(&p,'v'); + delay(10); + for (;p.line > you.line;p.line--) + remove(&p); + } else { + for (p.line = you.line-1;p.line >= ps->line;p.line--) + pchar(&p,'^'); + delay(10); + for (;p.line < you.line;p.line++) + remove(&p); + } + return(1); + } else if(abs(ps->line-you.line) < 3){ + p.line = you.line; + if(you.col < ps->col){ + for (p.col = you.col+1;p.col <= ps->col;p.col++) + pchar(&p,'>'); + delay(10); + for (;p.col > you.col;p.col--) + remove(&p); + } else { + for (p.col = you.col-1;p.col >= ps->col;p.col--) + pchar(&p,'<'); + delay(10); + for (;p.col < you.col;p.col++) + remove(&p); + } + return(1); + } + return(0); +} + +surround(ps) +struct point *ps;{ + struct point x; + int i,j; + + if(ps->col == 0)ps->col++; + if(ps->line == 0)ps->line++; + if(ps->line == LINES -1)ps->line--; + if(ps->col == COLUMNS -1)ps->col--; + aprintf(point(&x,ps->col-1,ps->line-1),"/*\\\r* *\r\\*/"); + for (j=0;j<20;j++){ + pchar(ps,'@'); + delay(1); + pchar(ps,' '); + delay(1); + } + if (post(cashvalue,1)) { + aprintf(point(&x,ps->col-1,ps->line-1)," \ro.o\r\\_/"); + delay(6); + aprintf(point(&x,ps->col-1,ps->line-1)," \ro.-\r\\_/"); + delay(6); + } + aprintf(point(&x,ps->col-1,ps->line-1)," \ro.o\r\\_/"); +} +win(ps) +struct point *ps; +{ + struct point x; + int j,k; + int boxsize; /* actually diameter of box, not radius */ + + boxsize = fast ? 10 : 4; + point(&x,ps->col,ps->line); + for(j=1;j=0; i--) + if (same(&snake[i], &snake[5])) + issame++; + if (!issame) + pchar(&snake[5],' '); + for(i=4; i>=0; i--) + snake[i+1]= snake[i]; + chase(&snake[0], &snake[1]); + pchar(&snake[1],SNAKETAIL); + pchar(&snake[0],SNAKEHEAD); + for(i=0; i<6; i++) + { + if (same(&snake[i],&you)) + { + surround(&you); + i = (cashvalue) % 10; + bonus = ((rand()>>8) & 0377)% 10; + ll(); + printf("%d\n", bonus); + delay(30); + if (bonus == i) { + spacewarp(1); + logit("bonus"); + flushi(); + return(1); + } + if ( loot >= penalty ){ + printf("You and your $%d have been eaten\n",cashvalue); + } else { + printf("The snake ate you. You owe $%d.\n",-cashvalue); + } + logit("eaten"); + length(moves); + done(); + } + } + return(0); +} + +remove(sp) +struct point *sp; +{ + int j; + + if (same(sp,&money)) { + pchar(sp,TREASURE); + return(2); + } + if (same(sp,&finish)) { + pchar(sp,GOAL); + return(3); + } + if (same(sp,&snake[0])) { + pchar(sp,SNAKEHEAD); + return(4); + } + for(j=1;j<6;j++){ + if(same(sp,&snake[j])){ + pchar(sp,SNAKETAIL); + return(4); + } + } + if ((sp->col < 4) && (sp->line == 0)){ + winnings(cashvalue); + if((you.line == 0) && (you.col < 4)) pchar(&you,ME); + return(5); + } + if (same(sp,&you)) { + pchar(sp,ME); + return(1); + } + pchar(sp,' '); + return(0); +} +winnings(won) +int won; +{ + struct point p; + + p.line = p.col = 1; + if(won>0){ + move(&p); + printf("$%d",won); + } +} + +stop(){ + signal(SIGINT,1); + ll(); + length(moves); + done(); +} + +suspend() +{ + char *sh; + + cook(); +#ifdef SIGTSTP + kill(getpid(), SIGTSTP); +#else + sh = getenv("SHELL"); + if (sh == NULL) + sh = "/bin/sh"; + system(sh); +#endif + raw(); + setup(); + winnings(cashvalue); +} + +length(num) +int num; +{ + printf("You made %d moves.\n",num); +} + +logit(msg) +char *msg; +{ + FILE *logfile; + long t; + + if ((logfile=fopen(LOGFILE, "a")) != NULL) { + time(&t); + fprintf(logfile, "%s $%d %dx%d %s %s", getlogin(), cashvalue, lcnt, ccnt, msg, ctime(&t)); + fclose(logfile); + } +} diff --git a/src/games/snake/snake.h b/src/games/snake/snake.h new file mode 100644 index 0000000..0f9dbf0 --- /dev/null +++ b/src/games/snake/snake.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + * + * @(#)snake.h 5.1 (Berkeley) 5/30/85 + */ + +# include +# include +# include +# include +# include +# include + +#define ESC '\033' + +struct tbuffer { + long t[4]; +} tbuffer; + +char *CL, *UP, *DO, *ND, *BS, + *HO, *CM, + *TA, *LL, + *KL, *KR, *KU, *KD, + *TI, *TE, *KS, *KE; +int LINES, COLUMNS; /* physical screen size. */ +int lcnt, ccnt; /* user's idea of screen size */ +char xBC, PC; +int AM, BW; +char tbuf[1024], tcapbuf[128]; +char *tgetstr(), *tgoto(); +int Klength; /* length of KX strings */ +int chunk; /* amount of money given at a time */ +#ifdef debug +#define cashvalue (loot-penalty)/25 +#else +#define cashvalue chunk*(loot-penalty)/25 +#endif + +struct point { + int col, line; +}; +struct point cursor; +struct sgttyb orig, new; +#ifdef TIOCLGET +struct ltchars olttyc, nlttyc; +#endif +struct point *point(); diff --git a/src/games/snake/snscore.c b/src/games/snake/snscore.c new file mode 100644 index 0000000..66f8032 --- /dev/null +++ b/src/games/snake/snscore.c @@ -0,0 +1,83 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +#ifndef lint +static char sccsid[] = "@(#)snscore.c 5.1 (Berkeley) 5/30/85"; +#endif not lint + +#include +#include +char *recfile = "/usr/games/lib/snakerawscores"; +#define MAXPLAYERS 256 + +struct passwd *getpwuid(); +char *malloc(); + +struct player { + short uids; + short scores; + char *name; +} players[MAXPLAYERS], temp; + +main() +{ + char buf[80], cp; + short uid, score; + FILE *fd; + int noplayers; + int i, j, notsorted; + short whoallbest, allbest; + char *q; + struct passwd *p; + + fd = fopen(recfile, "r"); + if (fd == NULL) { + perror(recfile); + exit(1); + } + printf("Snake players scores to date\n"); + fread(&whoallbest, sizeof(short), 1, fd); + fread(&allbest, sizeof(short), 1, fd); + for (uid=2;;uid++) { + if(fread(&score, sizeof(short), 1, fd) == 0) + break; + if (score > 0) { + if (noplayers > MAXPLAYERS) { + printf("too many players\n"); + exit(2); + } + players[noplayers].uids = uid; + players[noplayers].scores = score; + p = getpwuid(uid); + if (p == NULL) + continue; + q = p -> pw_name; + players[noplayers].name = malloc(strlen(q)+1); + strcpy(players[noplayers].name, q); + noplayers++; + } + } + + /* bubble sort scores */ + for (notsorted=1; notsorted; ) { + notsorted = 0; + for (i=0; i players[i+1].scores) + j = i+2; + } + exit(0); +} diff --git a/src/games/trek/Makefile b/src/games/trek/Makefile new file mode 100644 index 0000000..2c2993a --- /dev/null +++ b/src/games/trek/Makefile @@ -0,0 +1,42 @@ +# +# Copyright (c) 1980 Regents of the University of California. +# All rights reserved. The Berkeley software License Agreement +# specifies the terms and conditions for redistribution. +# +TOPSRC = $(shell cd ../../..; pwd) +include $(TOPSRC)/target.mk +#include $(TOPSRC)/cross.mk + +CFLAGS += -Os -Werror -Wall + +OBJS = abandon.o attack.o autover.o capture.o check_out.o checkcond.o \ + compkl.o computer.o damage.o damaged.o dcrept.o destruct.o \ + dock.o dumpgame.o dumpme.o dumpssradio.o events.o externs.o \ + getcodi.o getpar.o help.o impulse.o initquad.o kill.o klmove.o \ + lose.o lrscan.o main.o move.o nova.o out.o phaser.o play.o ram.o \ + ranf.o rest.o schedule.o score.o setup.o setwarp.o shell.o \ + shield.o snova.o srscan.o systemname.o torped.o utility.o \ + visual.o warp.o win.o +LIBS = -lm +MAN = trek.0 +MANSRC = trek.6 + +all: trek $(MAN) + +trek: ${OBJS} + ${CC} ${LDFLAGS} -o trek.elf ${OBJS} ${LIBS} + ${OBJDUMP} -S trek.elf > trek.dis + ${SIZE} trek.elf + ${ELF2AOUT} trek.elf $@ && rm trek.elf + +${MAN}: ${MANSRC} + ${MANROFF} $< > $@ + +clean: + rm -f *.o *.0 *.elf ${MAN} trek *.elf *.dis tags *~ + +install: all + install trek $(DESTDIR)/games/ + cp ${MAN} $(DESTDIR)/share/man/cat6/ + +#$(OBJS): trek.h diff --git a/src/games/trek/README b/src/games/trek/README new file mode 100644 index 0000000..cb38c29 --- /dev/null +++ b/src/games/trek/README @@ -0,0 +1,4 @@ +These are the Version 6 sources for trek. They must be modernized before +trek will compile. Everything is under SCCS ready for some willing person +to come along. Documentation is in ./doc. +Kirk McKusick 3/25/83 diff --git a/src/games/trek/abandon.c b/src/games/trek/abandon.c new file mode 100644 index 0000000..0fd157d --- /dev/null +++ b/src/games/trek/abandon.c @@ -0,0 +1,129 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +# include "trek.h" + +/* +** Abandon Ship +** +** The ship is abandoned. If your current ship is the Faire +** Queene, or if your shuttlecraft is dead, you're out of +** luck. You need the shuttlecraft in order for the captain +** (that's you!!) to escape. +** +** Your crew can beam to an inhabited starsystem in the +** quadrant, if there is one and if the transporter is working. +** If there is no inhabited starsystem, or if the transporter +** is out, they are left to die in outer space. +** +** These currently just count as regular deaths, but they +** should count very heavily against you. +** +** If there are no starbases left, you are captured by the +** Klingons, who torture you mercilessly. However, if there +** is at least one starbase, you are returned to the +** Federation in a prisoner of war exchange. Of course, this +** can't happen unless you have taken some prisoners. +** +** Uses trace flag 40 +*/ +void +abandon() +{ + register struct quad *q; + register int i; + int j; + register struct event *e; + + if (Ship.ship == QUEENE) { + printf("You may not abandon ye Faire Queene\n"); + return; + } + if (Ship.cond != DOCKED) + { + if (damaged(SHUTTLE)) { + out(SHUTTLE); + return; + } + printf("Officers escape in shuttlecraft\n"); + /* decide on fate of crew */ + q = &Quad[Ship.quadx][Ship.quady]; + if (q->qsystemname == 0 || damaged(XPORTER)) + { + printf("Entire crew of %d left to die in outer space\n", + Ship.crew); + Game.deaths += Ship.crew; + } + else + { + printf("Crew beams down to planet %s\n", systemname(q)); + } + } + /* see if you can be exchanged */ + if (Now.bases == 0 || Game.captives < 20 * Game.skill) + lose(L_CAPTURED); + /* re-outfit new ship */ + printf("You are hereby put in charge of an antiquated but still\n"); + printf(" functional ship, the Fairie Queene.\n"); + Ship.ship = QUEENE; + Ship.shipname = "Fairie Queene"; + Param.energy = Ship.energy = 3000; + Param.torped = Ship.torped = 6; + Param.shield = Ship.shield = 1250; + Ship.shldup = 0; + Ship.cloaked = 0; + Ship.warp = 5.0; + Ship.warp2 = 25.0; + Ship.warp3 = 125.0; + Ship.cond = GREEN; + /* clear out damages on old ship */ + for (i = 0; i < MAXEVENTS; i++) + { + e = &Event[i]; + if (e->evcode != E_FIXDV) + continue; + unschedule(e); + } + /* get rid of some devices and redistribute probabilities */ + i = Param.damprob[SHUTTLE] + Param.damprob[CLOAK]; + Param.damprob[SHUTTLE] = Param.damprob[CLOAK] = 0; + while (i > 0) + for (j = 0; j < NDEV; j++) + { + if (Param.damprob[j] != 0) + { + Param.damprob[j] += 1; + i--; + if (i <= 0) + break; + } + } + /* pick a starbase to restart at */ + i = ranf(Now.bases); + Ship.quadx = Now.base[i].x; + Ship.quady = Now.base[i].y; + /* setup that quadrant */ + while (1) + { + initquad(1); + Sect[Ship.sectx][Ship.secty] = EMPTY; + for (i = 0; i < 5; i++) + { + Ship.sectx = Etc.starbase.x + ranf(3) - 1; + if (Ship.sectx < 0 || Ship.sectx >= NSECTS) + continue; + Ship.secty = Etc.starbase.y + ranf(3) - 1; + if (Ship.secty < 0 || Ship.secty >= NSECTS) + continue; + if (Sect[Ship.sectx][Ship.secty] == EMPTY) + { + Sect[Ship.sectx][Ship.secty] = QUEENE; + dock(); + compkldist(0); + return; + } + } + } +} diff --git a/src/games/trek/attack.c b/src/games/trek/attack.c new file mode 100644 index 0000000..4323e6a --- /dev/null +++ b/src/games/trek/attack.c @@ -0,0 +1,156 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +# include "trek.h" + +/* +** Klingon Attack Routine +** +** This routine performs the Klingon attack provided that +** (1) Something happened this move (i.e., not free), and +** (2) You are not cloaked. Note that if you issue the +** cloak command, you are not considered cloaked until you +** expend some time. +** +** Klingons are permitted to move both before and after the +** attack. They will tend to move toward you before the +** attack and away from you after the attack. +** +** Under certain conditions you can get a critical hit. This +** sort of hit damages devices. The probability that a given +** device is damaged depends on the device. Well protected +** devices (such as the computer, which is in the core of the +** ship and has considerable redundancy) almost never get +** damaged, whereas devices which are exposed (such as the +** warp engines) or which are particularly delicate (such as +** the transporter) have a much higher probability of being +** damaged. +** +** The actual amount of damage (i.e., how long it takes to fix +** it) depends on the amount of the hit and the "damfac[]" +** entry for the particular device. +** +** Casualties can also occur. +*/ +void +attack(resting) + int resting; /* set if attack while resting */ +{ + register int hit, i, l; + int maxhit, tothit, shldabsb; + double chgfac, propor, extradm; + double dustfac, tothe; + int cas; + int hitflag; + + if (Move.free) + return; + if (Etc.nkling <= 0 || Quad[Ship.quadx][Ship.quady].stars < 0) + return; + if (Ship.cloaked && Ship.cloakgood) + return; + /* move before attack */ + klmove(0); + if (Ship.cond == DOCKED) + { + if (!resting) + printf("Starbase shields protect the %s\n", Ship.shipname); + return; + } + /* setup shield effectiveness */ + chgfac = 1.0; + if (Move.shldchg) + chgfac = 0.25 + 0.50 * franf(); + maxhit = tothit = 0; + hitflag = 0; + + /* let each Klingon do his damndest */ + for (i = 0; i < Etc.nkling; i++) + { + /* if he's low on power he won't attack */ + if (Etc.klingon[i].power < 20) + continue; + if (!hitflag) + { + printf("\nStardate %.2f: Klingon attack:\n", + Now.date); + hitflag++; + } + /* complete the hit */ + dustfac = 0.90 + 0.01 * franf(); + tothe = Etc.klingon[i].avgdist; + hit = Etc.klingon[i].power * pow(dustfac, tothe) * Param.hitfac; + /* deplete his energy */ + dustfac = Etc.klingon[i].power; + Etc.klingon[i].power = dustfac * Param.phasfac * (1.0 + (franf() - 0.5) * 0.2); + /* see how much of hit shields will absorb */ + shldabsb = 0; + if (Ship.shldup || Move.shldchg) + { + propor = Ship.shield; + propor /= Param.shield; + shldabsb = propor * chgfac * hit; + if (shldabsb > Ship.shield) + shldabsb = Ship.shield; + Ship.shield -= shldabsb; + } + /* actually do the hit */ + printf("HIT: %d units", hit); + if (!damaged(SRSCAN)) + printf(" from %d,%d", Etc.klingon[i].x, Etc.klingon[i].y); + cas = (shldabsb * 100) / hit; + hit -= shldabsb; + if (shldabsb > 0) + printf(", shields absorb %d%%, effective hit %d\n", + cas, hit); + else + printf("\n"); + tothit += hit; + if (hit > maxhit) + maxhit = hit; + Ship.energy -= hit; + /* see if damages occurred */ + if (hit >= (15 - Game.skill) * (25 - ranf(12))) + { + printf("CRITICAL HIT!!!\n"); + /* select a device from probability vector */ + cas = ranf(1000); + for (l = 0; cas >= 0; l++) + cas -= Param.damprob[l]; + l -= 1; + /* compute amount of damage */ + extradm = (hit * Param.damfac[l]) / (75 + ranf(25)) + 0.5; + /* damage the device */ + damage(l, extradm); + if (damaged(SHIELD)) + { + if (Ship.shldup) + printf("Sulu: Shields knocked down, captain.\n"); + Ship.shldup = 0; + Move.shldchg = 0; + } + } + if (Ship.energy <= 0) + lose(L_DSTRYD); + } + + /* see what our casualities are like */ + if (maxhit >= 200 || tothit >= 500) + { + cas = tothit * 0.015 * franf(); + if (cas >= 2) + { + printf("McCoy: we suffered %d casualties in that attack.\n", + cas); + Game.deaths += cas; + Ship.crew -= cas; + } + } + + /* allow Klingons to move after attacking */ + klmove(1); + + return; +} diff --git a/src/games/trek/autover.c b/src/games/trek/autover.c new file mode 100644 index 0000000..39d2aee --- /dev/null +++ b/src/games/trek/autover.c @@ -0,0 +1,45 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +# include "trek.h" + +/* +** Automatic Override +** +** If we should be so unlucky as to be caught in a quadrant +** with a supernova in it, this routine is called. It is +** called from checkcond(). +** +** It sets you to a random warp (guaranteed to be over 6.0) +** and starts sending you off "somewhere" (whereever that is). +** +** Please note that it is VERY important that you reset your +** warp speed after the automatic override is called. The new +** warp factor does not stay in effect for just this routine. +** +** This routine will never try to send you more than sqrt(2) +** quadrants, since that is all that is needed. +*/ +void +autover() +{ + double dist; + register int course; + + printf("RED ALERT: The %s is in a supernova quadrant\n", Ship.shipname); + printf("*** Emergency override attempts to hurl %s to safety\n", Ship.shipname); + /* let's get our ass out of here */ + Ship.warp = 6.0 + 2.0 * franf(); + Ship.warp2 = Ship.warp * Ship.warp; + Ship.warp3 = Ship.warp2 * Ship.warp; + dist = 0.75 * Ship.energy / (Ship.warp3 * (Ship.shldup + 1)); + if (dist > 1.4142) + dist = 1.4142; + course = ranf(360); + Etc.nkling = -1; + Ship.cond = RED; + warp(-1, course, dist); + attack(0); +} diff --git a/src/games/trek/board.x b/src/games/trek/board.x new file mode 100644 index 0000000..0892a6d --- /dev/null +++ b/src/games/trek/board.x @@ -0,0 +1,59 @@ +# include "trek.h" + +/* +** BOARD A KLINGON +** +** A Klingon battle cruiser is boarded. If the boarding party +** is successful, they take over the vessel, otherwise, you +** have wasted a move. Needless to say, this move is not free. +** +** User parameters are the Klingon to be boarded and the size of +** the boarding party. +** +** Three things are computed. The first is the probability that +** the party takes over the Klingon. This is dependent on the +** size of the party, the condition of the Klingon (for which +** the energy left is used, which is definately incorrect), and +** the number of losses that the boarding party sustains. If too +** many of the boarding party are killed, the probability drops +** to zero. The second quantity computed is the losses that the +** boarding party sustains. This counts in your score. It +** depends on the absolute and relative size of the boarding +** party and the strength of the Klingon. The third quantity +** computed is the number of Klingon captives you get to take. +** It is actually computed as the number of losses they sustain +** subtracted from the size of their crew. It depends on the +** relative size of the party. All of these quantities are +** randomized in some fashion. +*/ + +board() +{ + int prob; + int losses; + int captives; + float t; + int party; + + if (checkout(XPORTER)) + return; + + k = selectklingon(); + if (!k->srndreq) + { + return (printf("But captain! You must request surrender first\n")); + } + + t = party / Param.crew; + + prob = 1000 * t; + prob =- 500 * k->power / Param.klingpwr; + + losses = party * k->power * t * 0.5 / Param.klingpwr * (franf() + 1.0); + if (losses * 4 > party) + prob = 0; + + captives = %%% * (1.0 - t) * 0.5 * (franf() + 1.0); + + if (prob > ranf(1000)) + success!!!; diff --git a/src/games/trek/capture.c b/src/games/trek/capture.c new file mode 100644 index 0000000..7d10045 --- /dev/null +++ b/src/games/trek/capture.c @@ -0,0 +1,98 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +# include "trek.h" + +/* +** Ask a Klingon To Surrender +** +** (Fat chance) +** +** The Subspace Radio is needed to ask a Klingon if he will kindly +** surrender. A random Klingon from the ones in the quadrant is +** chosen. +** +** The Klingon is requested to surrender. The probability of this +** is a function of that Klingon's remaining power, our power, +** etc. +*/ +void +capture() +{ + register int i; + register struct kling *k; + double x; + extern struct kling *selectklingon(); + + /* check for not cloaked */ + if (Ship.cloaked) + { + printf("Ship-ship communications out when cloaked\n"); + return; + } + if (damaged(SSRADIO)) { + out(SSRADIO); + return; + } + /* find out if there are any at all */ + if (Etc.nkling <= 0) + { + printf("Uhura: Getting no response, sir\n"); + return; + } + + /* if there is more than one Klingon, find out which one */ + k = selectklingon(); + Move.free = 0; + Move.time = 0.05; + + /* check out that Klingon */ + k->srndreq++; + x = Param.klingpwr; + x *= Ship.energy; + x /= k->power * Etc.nkling; + x *= Param.srndrprob; + i = x; +# ifdef xTRACE + if (Trace) + printf("Prob = %d (%.4f)\n", i, x); +# endif + if (i > ranf(100)) + { + /* guess what, he surrendered!!! */ + printf("Klingon at %d,%d surrenders\n", k->x, k->y); + i = ranf(Param.klingcrew); + if ( i > 0 ) + printf("%d klingons commit suicide rather than be taken captive\n", Param.klingcrew - i); + if (i > Ship.brigfree) + i = Ship.brigfree; + Ship.brigfree -= i; + printf("%d captives taken\n", i); + killk(k->x, k->y); + return; + } + + /* big surprise, he refuses to surrender */ + printf("Fat chance, captain\n"); + return; +} + + +/* +** SELECT A KLINGON +** +** Cruddy, just takes one at random. Should ask the captain. +*/ + +struct kling *selectklingon() +{ + register int i; + + if (Etc.nkling < 2) + i = 0; + else + i = ranf(Etc.nkling); + return (&Etc.klingon[i]); +} diff --git a/src/games/trek/check_out.c b/src/games/trek/check_out.c new file mode 100644 index 0000000..8eace5d --- /dev/null +++ b/src/games/trek/check_out.c @@ -0,0 +1,38 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +# include "trek.h" + +/* +** CHECK IF A DEVICE IS OUT +** +** The indicated device is checked to see if it is disabled. If +** it is, an attempt is made to use the starbase device. If both +** of these fails, it returns non-zero (device is REALLY out), +** otherwise it returns zero (I can get to it somehow). +** +** It prints appropriate messages too. +*/ +int +check_out(device) + int device; +{ + register int dev; + + dev = device; + + /* check for device ok */ + if (!damaged(dev)) + return (0); + + /* report it as being dead */ + out(dev); + + /* but if we are docked, we can go ahead anyhow */ + if (Ship.cond != DOCKED) + return (1); + printf(" Using starbase %s\n", Device[dev].name); + return (0); +} diff --git a/src/games/trek/checkcond.c b/src/games/trek/checkcond.c new file mode 100644 index 0000000..a2ea68e --- /dev/null +++ b/src/games/trek/checkcond.c @@ -0,0 +1,69 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +# include "trek.h" + +/* +** Check for Condition After a Move +** +** Various ship conditions are checked. First we check +** to see if we have already lost the game, due to running +** out of life support reserves, running out of energy, +** or running out of crew members. The check for running +** out of time is in events(). +** +** If we are in automatic override mode (Etc.nkling < 0), we +** don't want to do anything else, lest we call autover +** recursively. +** +** In the normal case, if there is a supernova, we call +** autover() to help us escape. If after calling autover() +** we are still in the grips of a supernova, we get burnt +** up. +** +** If there are no Klingons in this quadrant, we nullify any +** distress calls which might exist. +** +** We then set the condition code, based on the energy level +** and battle conditions. +*/ +void +checkcond() +{ + /* see if we are still alive and well */ + if (Ship.reserves < 0.0) + lose(L_NOLIFE); + if (Ship.energy <= 0) + lose(L_NOENGY); + if (Ship.crew <= 0) + lose(L_NOCREW); + /* if in auto override mode, ignore the rest */ + if (Etc.nkling < 0) + return; + /* call in automatic override if appropriate */ + if (Quad[Ship.quadx][Ship.quady].stars < 0) + autover(); + if (Quad[Ship.quadx][Ship.quady].stars < 0) + lose(L_SNOVA); + /* nullify distress call if appropriate */ + if (Etc.nkling <= 0) + killd(Ship.quadx, Ship.quady, 1); + + /* set condition code */ + if (Ship.cond == DOCKED) + return; + + if (Etc.nkling > 0) + { + Ship.cond = RED; + return; + } + if (Ship.energy < Param.energylow) + { + Ship.cond = YELLOW; + return; + } + Ship.cond = GREEN; +} diff --git a/src/games/trek/compkl.c b/src/games/trek/compkl.c new file mode 100644 index 0000000..094fb58 --- /dev/null +++ b/src/games/trek/compkl.c @@ -0,0 +1,79 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +# include "trek.h" + +/* +** sort klingons +** +** bubble sort on ascending distance +*/ +void +sortkl() +{ + struct kling t; + register int f, i, m; + + m = Etc.nkling - 1; + f = 1; + while (f) + { + f = 0; + for (i = 0; i < m; i++) + if (Etc.klingon[i].dist > Etc.klingon[i+1].dist) + { + bmove(&Etc.klingon[i], &t, sizeof t); + bmove(&Etc.klingon[i+1], &Etc.klingon[i], sizeof t); + bmove(&t, &Etc.klingon[i+1], sizeof t); + f = 1; + } + } +} + +/* +** compute klingon distances +** +** The klingon list has the distances for all klingons recomputed +** and sorted. The parameter is a Boolean flag which is set if +** we have just entered a new quadrant. +** +** This routine is used every time the Enterprise or the Klingons +** move. +*/ +void +compkldist(f) + int f; /* set if new quadrant */ +{ + register int i, dx, dy; + double d; + double temp; + + if (Etc.nkling == 0) + return; + for (i = 0; i < Etc.nkling; i++) + { + /* compute distance to the Klingon */ + dx = Ship.sectx - Etc.klingon[i].x; + dy = Ship.secty - Etc.klingon[i].y; + d = dx * dx + dy * dy; + d = sqrt(d); + + /* compute average of new and old distances to Klingon */ + if (!f) + { + temp = Etc.klingon[i].dist; + Etc.klingon[i].avgdist = 0.5 * (temp + d); + } + else + { + /* new quadrant: average is current */ + Etc.klingon[i].avgdist = d; + } + Etc.klingon[i].dist = d; + } + + /* leave them sorted */ + sortkl(); +} diff --git a/src/games/trek/computer.c b/src/games/trek/computer.c new file mode 100644 index 0000000..b9fcdbf --- /dev/null +++ b/src/games/trek/computer.c @@ -0,0 +1,311 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +# include "trek.h" +# include "getpar.h" +# include + +/* +** On-Board Computer +** +** A computer request is fetched from the captain. The requests +** are: +** +** chart -- print a star chart of the known galaxy. This includes +** every quadrant that has ever had a long range or +** a short range scan done of it, plus the location of +** all starbases. This is of course updated by any sub- +** space radio broadcasts (unless the radio is out). +** The format is the same as that of a long range scan +** except that ".1." indicates that a starbase exists +** but we know nothing else. +** +** trajectory -- gives the course and distance to every know +** Klingon in the quadrant. Obviously this fails if the +** short range scanners are out. +** +** course -- gives a course computation from whereever you are +** to any specified location. If the course begins +** with a slash, the current quadrant is taken. +** Otherwise the input is quadrant and sector coordi- +** nates of the target sector. +** +** move -- identical to course, except that the move is performed. +** +** score -- prints out the current score. +** +** pheff -- "PHaser EFFectiveness" at a given distance. Tells +** you how much stuff you need to make it work. +** +** warpcost -- Gives you the cost in time and units to move for +** a given distance under a given warp speed. +** +** impcost -- Same for the impulse engines. +** +** distresslist -- Gives a list of the currently known starsystems +** or starbases which are distressed, together with their +** quadrant coordinates. +** +** If a command is terminated with a semicolon, you remain in +** the computer; otherwise, you escape immediately to the main +** command processor. +*/ + +struct cvntab Cputab[] = +{ + { "ch", "art", (void (*)())1, 0 }, + { "t", "rajectory", (void (*)())2, 0 }, + { "c", "ourse", (void (*)())3, 0 }, + { "m", "ove", (void (*)())3, 1 }, + { "s", "core", (void (*)())4, 0 }, + { "p", "heff", (void (*)())5, 0 }, + { "w", "arpcost", (void (*)())6, 0 }, + { "i", "mpcost", (void (*)())7, 0 }, + { "d", "istresslist", (void (*)())8, 0 }, + { 0 }, +}; + +void +prkalc(course, dist) + int course; + double dist; +{ + printf(": course %d dist %.3f\n", course, dist); +} + +/* +** Course Calculation +** +** Computes and outputs the course and distance from position +** sqx,sqy/ssx,ssy to tqx,tqy/tsx,tsy. +*/ +int +kalc(tqx, tqy, tsx, tsy, dist) + int tqx; + int tqy; + int tsx; + int tsy; + double *dist; +{ + double dx, dy; + double quadsize; + double angle; + register int course; + + /* normalize to quadrant distances */ + quadsize = NSECTS; + dx = (Ship.quadx + Ship.sectx / quadsize) - (tqx + tsx / quadsize); + dy = (tqy + tsy / quadsize) - (Ship.quady + Ship.secty / quadsize); + + /* get the angle */ + angle = atan2(dy, dx); + /* make it 0 -> 2 pi */ + if (angle < 0.0) + angle += 6.283185307; + /* convert from radians to degrees */ + course = angle * 57.29577951 + 0.5; + dx = dx * dx + dy * dy; + *dist = sqrt(dx); + return (course); +} + +void +computer() +{ + int ix, iy; + register int i, j; + int tqx, tqy; + struct cvntab *r; + int cost; + int course; + double dist, time; + double warpfact; + struct quad *q; + register struct event *e; + + if (check_out(COMPUTER)) + return; + while (1) + { + r = getcodpar("\nRequest", Cputab); + switch ((int) r->value) + { + + case 1: /* star chart */ + printf("Computer record of galaxy for all long range sensor scans\n\n"); + printf(" "); + /* print top header */ + for (i = 0; i < NQUADS; i++) + printf("-%d- ", i); + printf("\n"); + for (i = 0; i < NQUADS; i++) + { + printf("%d ", i); + for (j = 0; j < NQUADS; j++) + { + if (i == Ship.quadx && j == Ship.quady) + { + printf("$$$ "); + continue; + } + q = &Quad[i][j]; + /* 1000 or 1001 is special case */ + if (q->scanned >= 1000) + if (q->scanned > 1000) + printf(".1. "); + else + printf("/// "); + else + if (q->scanned < 0) + printf("... "); + else + printf("%3d ", q->scanned); + } + printf("%d\n", i); + } + printf(" "); + /* print bottom footer */ + for (i = 0; i < NQUADS; i++) + printf("-%d- ", i); + printf("\n"); + break; + + case 2: /* trajectory */ + if (check_out(SRSCAN)) + { + break; + } + if (Etc.nkling <= 0) + { + printf("No Klingons in this quadrant\n"); + break; + } + /* for each Klingon, give the course & distance */ + for (i = 0; i < Etc.nkling; i++) + { + printf("Klingon at %d,%d", Etc.klingon[i].x, Etc.klingon[i].y); + course = kalc(Ship.quadx, Ship.quady, Etc.klingon[i].x, Etc.klingon[i].y, &dist); + prkalc(course, dist); + } + break; + + case 3: /* course calculation */ + if (readdelim('/')) + { + tqx = Ship.quadx; + tqy = Ship.quady; + } + else + { + ix = getintpar("Quadrant"); + if (ix < 0 || ix >= NSECTS) + break; + iy = getintpar("q-y"); + if (iy < 0 || iy >= NSECTS) + break; + tqx = ix; + tqy = iy; + } + ix = getintpar("Sector"); + if (ix < 0 || ix >= NSECTS) + break; + iy = getintpar("s-y"); + if (iy < 0 || iy >= NSECTS) + break; + course = kalc(tqx, tqy, ix, iy, &dist); + if (r->value2) + { + warp(-1, course, dist); + break; + } + printf("%d,%d/%d,%d to %d,%d/%d,%d", + Ship.quadx, Ship.quady, Ship.sectx, Ship.secty, tqx, tqy, ix, iy); + prkalc(course, dist); + break; + + case 4: /* score */ + score(); + break; + + case 5: /* phaser effectiveness */ + dist = getfltpar("range"); + if (dist < 0.0) + break; + dist *= 10.0; + cost = pow(0.90, dist) * 98.0 + 0.5; + printf("Phasers are %d%% effective at that range\n", cost); + break; + + case 6: /* warp cost (time/energy) */ + dist = getfltpar("distance"); + if (dist < 0.0) + break; + warpfact = getfltpar("warp factor"); + if (warpfact <= 0.0) + warpfact = Ship.warp; + cost = (dist + 0.05) * warpfact * warpfact * warpfact; + time = Param.warptime * dist / (warpfact * warpfact); + printf("Warp %.2f distance %.2f cost %.2f stardates %d (%d w/ shlds up) units\n", + warpfact, dist, time, cost, cost + cost); + break; + + case 7: /* impulse cost */ + dist = getfltpar("distance"); + if (dist < 0.0) + break; + cost = 20 + 100 * dist; + time = dist / 0.095; + printf("Distance %.2f cost %.2f stardates %d units\n", + dist, time, cost); + break; + + case 8: /* distresslist */ + j = 1; + printf("\n"); + /* scan the event list */ + for (i = 0; i < MAXEVENTS; i++) + { + e = &Event[i]; + /* ignore hidden entries */ + if (e->evcode & E_HIDDEN) + continue; + switch (e->evcode & E_EVENT) + { + + case E_KDESB: + printf("Klingon is attacking starbase in quadrant %d,%d\n", + e->x, e->y); + j = 0; + break; + + case E_ENSLV: + case E_REPRO: + printf("Starsystem %s in quadrant %d,%d is distressed\n", + Systemname[(int)e->systemname], e->x, e->y); + j = 0; + break; + } + } + if (j) + printf("No known distress calls are active\n"); + break; + + } + + /* skip to next semicolon or newline. Semicolon + * means get new computer request; newline means + * exit computer mode. */ + while ((i = fgetc(stdin)) != ';') + { + if (i == '\0') + exit(1); + if (i == '\n') + { + ungetc(i, stdin); + return; + } + } + } +} diff --git a/src/games/trek/damage.c b/src/games/trek/damage.c new file mode 100644 index 0000000..24c7813 --- /dev/null +++ b/src/games/trek/damage.c @@ -0,0 +1,59 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +# include "trek.h" + +/* +** Schedule Ship.damages to a Device +** +** Device `dev1' is damaged in an amount `dam'. Dam is measured +** in stardates, and is an additional amount of damage. It should +** be the amount to occur in non-docked mode. The adjustment +** to docked mode occurs automatically if we are docked. +** +** Note that the repair of the device occurs on a DATE, meaning +** that the dock() and undock() have to reschedule the event. +*/ +void +damage(dev1, dam) + int dev1; /* device index */ + double dam; /* time to repair */ +{ + register int i; + register struct event *e; + int f; + register int dev; + + /* ignore zero damages */ + if (dam <= 0.0) + return; + dev = dev1; + + printf("\t%s damaged\n", Device[dev].name); + + /* find actual length till it will be fixed */ + if (Ship.cond == DOCKED) + dam *= Param.dockfac; + /* set the damage flag */ + f = damaged(dev); + if (!f) + { + /* new damages -- schedule a fix */ + schedule(E_FIXDV, dam, 0, 0, dev); + return; + } + /* device already damaged -- add to existing damages */ + /* scan for old damages */ + for (i = 0; i < MAXEVENTS; i++) + { + e = &Event[i]; + if (e->evcode != E_FIXDV || e->systemname != dev) + continue; + /* got the right one; add on the new damages */ + reschedule(e, e->date - Now.date + dam); + return; + } + syserr("Cannot find old damages %d\n", dev); +} diff --git a/src/games/trek/damaged.c b/src/games/trek/damaged.c new file mode 100644 index 0000000..9be2b4b --- /dev/null +++ b/src/games/trek/damaged.c @@ -0,0 +1,35 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +# include "trek.h" + +/* DAMAGED -- check for device damaged +** +** This is a boolean function which returns non-zero if the +** specified device is broken. It does this by checking the +** event list for a "device fix" action on that device. +*/ +int +damaged(dev) + int dev; +{ + register int d; + register struct event *e; + register int i; + + d = dev; + + for (i = 0; i < MAXEVENTS; i++) + { + e = &Event[i]; + if (e->evcode != E_FIXDV) + continue; + if (e->systemname == d) + return (1); + } + + /* device fix not in event list -- device must not be broken */ + return (0); +} diff --git a/src/games/trek/dcrept.c b/src/games/trek/dcrept.c new file mode 100644 index 0000000..12956ac --- /dev/null +++ b/src/games/trek/dcrept.c @@ -0,0 +1,67 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +# include "trek.h" + +/* +** damage control report +** +** Print damages and time to fix. This is taken from the event +** list. A couple of factors are set up, based on whether or not +** we are docked. (One of these factors will always be 1.0.) +** The event list is then scanned for damage fix events, the +** time until they occur is determined, and printed out. The +** magic number DAMFAC is used to tell how much faster you can +** fix things if you are docked. +*/ +void +dcrept() +{ + register int i, f; + double x; + double m1, m2; + register struct event *e; + + /* set up the magic factors to output the time till fixed */ + if (Ship.cond == DOCKED) + { + m1 = 1.0 / Param.dockfac; + m2 = 1.0; + } + else + { + m1 = 1.0; + m2 = Param.dockfac; + } + printf("Damage control report:\n"); + f = 1; + + /* scan for damages */ + for (i = 0; i < MAXEVENTS; i++) + { + e = &Event[i]; + if (e->evcode != E_FIXDV) + continue; + + /* output the title first time */ + if (f) + { + printf("\t\t\t repair times\n"); + printf("device\t\t\tin flight docked\n"); + f = 0; + } + + /* compute time till fixed, then adjust by the magic factors */ + x = e->date - Now.date; + printf("%-24s%7.2f %7.2f\n", + Device[(int)e->systemname].name, x * m1 + 0.005, x * m2 + 0.005); + + /* do a little consistancy checking */ + } + + /* if everything was ok, reassure the nervous captain */ + if (f) + printf("All devices functional\n"); +} diff --git a/src/games/trek/destruct.c b/src/games/trek/destruct.c new file mode 100644 index 0000000..fff7c52 --- /dev/null +++ b/src/games/trek/destruct.c @@ -0,0 +1,83 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +# include "trek.h" +# include "getpar.h" + +/* +** Self Destruct Sequence +** +** The computer starts up the self destruct sequence. Obviously, +** if the computer is out nothing can happen. You get a countdown +** and a request for password. This must match the password that +** you entered at the start of the game. +** +** You get to destroy things when you blow up; hence, it is +** possible to win the game by destructing if you take the last +** Klingon with you. +** +** By the way, the \032 in the message is a ^Z, which is because +** the terminal in my office is an ADM-3, which uses that char- +** acter to clear the screen. I also stick in a \014 (form feed) +** because that clears some other screens. +** +** Uses trace flag 41 +*/ +void +destruct() +{ + char checkpass[15]; + register int i, j; + double zap; + + if (damaged(COMPUTER)) { + out(COMPUTER); + return; + } + printf("\n --- WORKING ---\n"); + sleep(3); + /* output the count 10 9 8 7 6 */ + for (i = 10; i > 5; i--) + { + for (j = 10; j > i; j--) + printf(" "); + printf("%d\n", i); + sleep(1); + } + /* check for password on new line only */ + skiptonl(0); + getstrpar("Enter password verification", checkpass, 14, 0); + sleep(2); + if (!sequal(checkpass, Game.passwd)) { + printf("Self destruct sequence aborted\n"); + return; + } + printf("Password verified; self destruct sequence continues:\n"); + sleep(2); + /* output count 5 4 3 2 1 0 */ + for (i = 5; i >= 0; i--) + { + sleep(1); + for (j = 5; j > i; j--) + printf(" "); + printf("%d\n", i); + } + sleep(2); + printf("\032\014***** %s destroyed *****\n", Ship.shipname); + Game.killed = 1; + /* let's see what we can blow up!!!! */ + zap = 20.0 * Ship.energy; + Game.deaths += Ship.crew; + for (i = 0; i < Etc.nkling; ) + { + if (Etc.klingon[i].power * Etc.klingon[i].dist <= zap) + killk(Etc.klingon[i].x, Etc.klingon[i].y); + else + i++; + } + /* if we didn't kill the last Klingon (detected by killk), */ + /* then we lose.... */ + lose(L_DSTRCT); +} diff --git a/src/games/trek/dock.c b/src/games/trek/dock.c new file mode 100644 index 0000000..3b49bb2 --- /dev/null +++ b/src/games/trek/dock.c @@ -0,0 +1,113 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +# include "trek.h" + +/* +** DOCK TO STARBASE +** +** The starship is docked to a starbase. For this to work you +** must be adjacent to a starbase. +** +** You get your supplies replenished and your captives are +** disembarked. Note that your score is updated now, not when +** you actually take the captives. +** +** Any repairs that need to be done are rescheduled to take +** place sooner. This provides for the faster repairs when you +** are docked. +*/ +void +dock() +{ + register int i, j; + int ok; + register struct event *e; + + if (Ship.cond == DOCKED) { + printf("Chekov: But captain, we are already docked\n"); + return; + } + /* check for ok to dock, i.e., adjacent to a starbase */ + ok = 0; + for (i = Ship.sectx - 1; i <= Ship.sectx + 1 && !ok; i++) + { + if (i < 0 || i >= NSECTS) + continue; + for (j = Ship.secty - 1; j <= Ship.secty + 1; j++) + { + if (j < 0 || j >= NSECTS) + continue; + if (Sect[i][j] == BASE) + { + ok++; + break; + } + } + } + if (!ok) { + printf("Chekov: But captain, we are not adjacent to a starbase.\n"); + return; + } + + /* restore resources */ + Ship.energy = Param.energy; + Ship.torped = Param.torped; + Ship.shield = Param.shield; + Ship.crew = Param.crew; + Game.captives += Param.brigfree - Ship.brigfree; + Ship.brigfree = Param.brigfree; + + /* reset ship's defenses */ + Ship.shldup = 0; + Ship.cloaked = 0; + Ship.cond = DOCKED; + Ship.reserves = Param.reserves; + + /* recalibrate space inertial navigation system */ + Ship.sinsbad = 0; + + /* output any saved radio messages */ + dumpssradio(); + + /* reschedule any device repairs */ + for (i = 0; i < MAXEVENTS; i++) + { + e = &Event[i]; + if (e->evcode != E_FIXDV) + continue; + reschedule(e, (e->date - Now.date) * Param.dockfac); + } +} + + +/* +** LEAVE A STARBASE +** +** This is the inverse of dock(). The main function it performs +** is to reschedule any damages so that they will take longer. +*/ +void +undock() +{ + register struct event *e; + register int i; + + if (Ship.cond != DOCKED) { + printf("Sulu: Pardon me captain, but we are not docked.\n"); + return; + } + Ship.cond = GREEN; + Move.free = 0; + + /* reschedule device repair times (again) */ + for (i = 0; i < MAXEVENTS; i++) + { + e = &Event[i]; + if (e->evcode != E_FIXDV) + continue; + reschedule(e, (e->date - Now.date) / Param.dockfac); + } +} diff --git a/src/games/trek/docs/read_me.nr b/src/games/trek/docs/read_me.nr new file mode 100644 index 0000000..226b8ff --- /dev/null +++ b/src/games/trek/docs/read_me.nr @@ -0,0 +1,251 @@ +.de @h +'sp 4 +'tl 'TREK SETUP INSTRUCTIONS''%' +'sp 2 +.ns +.. +.de @f +'bp +.. +.wh 0 @h +.wh -6 @f +.de pp +.sp +.ne 2 +.ti +5 +.. +.de s1 +.sp 2 +.nr S1 +1 +.nr S2 0 +.ne 5 +.in 4 +.ti 0 +\\n(S1.\ \ \c +.. +.de s2 +.sp 1 +.nr S2 +1 +.ne 3 +.in 8 +.ti 4 +\\n(S2.\ \ \c +.. +.br +.ce +TREK SETUP INSTRUCTIONS +.sp 2 +.pp +This document describes all sorts of nifty things +you should know +before you start to muck around +with the trek source code. +Please read them carefully. +.s1 +MAINTENANCE +.s2 +There are a number of shell files +which you may use to maintain the system. +"Prtrek" produces a copy of the source code. +It pipes its output to lpr +and runs in background. +"Comp" compiles up to nine source modules +and leaves them in .o files. +"Compile" is the same as "comp" +except that it loads after compiling. +If stated without any arguments, +it loads from .o files. +"Compall" compiles all the .c files +into .o files, +but does not load. +It redirects its output to the file "output". +To recompile the entire system, +type +.ti +8 +compall +.ti +8 +compile +.br +.s2 +Main.c contains a variable called "Mother". +This is initialized to the result of the +"getuid()" call for the maintainer of trek +at your installation. +Only Mother is allowed to set trace flags +and run the game at other than the default priority. +.s2 +Speaking of priorities, +trek eats up a lot of system resources. +Hence, it normally runs at a very low priority. +This makes it almost impossible to play +if the system is loaded. +However, +the -pN flag sets the priority to N, +which makes it possible to debug +when the system is loaded. +The default priority is set by a #define of +PRIO, +which is set to 10 in the default system. +.s2 +Trace information is provided +which may be useful in debugging things in the system. +If you are in a bad way for space, +comment out the #define xTRACE +which appears in trek.h. +This will cause the trace stuff to not occur +in the object. +.s2 +The version of trek released to you +is compiled with the -f flag (for no floating point) +and should work without problems on your machine. +You can edit out the -f flag +in "compile" if you have floating point hardware +on your machine +so that it will take less space. +.s1 +THE PORTABLE C LIBRARY +.pp +The portable C library was used +to do I/O in trek. +Unfortunately, +the version which we had at Berkeley +had a number of small bugs +which caused trek to do bad things at times. +For some unknown reason +(temporary insanity perhaps) +I rewrote the portable C library. +This version is much smaller than the old version +and has cleaner code. +It also works right +(???). +However, there are a few minor differences +which you should be aware of. +.s2 +Scanf no longer ignores the noise characters "\\n", +"\\t", and space in the format string; +i.e., +these characters now require a match +in the input stream. +.s2 +A variable +f_log +has been added +which is the file descriptor +of a "log" file. +If f_log is greater than zero +a copy of everything read from +the standard input +and written to +the standard output +is written in the file f_log. +.s1 +DISCLAIMERS +.s2 +Frankly, +I am getting pretty sick of playing this game. +Hence, +the version which you get may have several bugs +in it; +I freely admit +that it is probably buggier +than some previous versions. +Sorry about that. +.s2 +Along with being buggy, +the game never had quite everything implemented +that was originally intended. +If you see things that look weird, +that may be why. +There are even some features which I have taken out +(like ghost starsystems) +upon deciding that I didn't have the energy +to implement them correctly. +.s1 +REQUESTS +.pp +There are several things that I would like to ask of anyone +who does work on the source code. +.s2 +Please let me know of any bugs which you find +in the code, +and any fixes which you may have. +Other copies will probably be going out to other people later, +and it would be nice if those copies where less buggy. +Also, +I would be interested in hearing about any +enhancements of the game which you might install. +.s2 +Please note that I have a distinct coding style. +I feel that it is cleaner +and easier to read than a more +casual style. +If possible, +please stick to it, +especially if you end up sending tapes back to me. +This goes along with my whole belief in clean code: +I ask you to please avoid obscure code +whenever possible. +If you throw some in, +please don't let me see it. +It just depresses me. +.s2 +Unfortunately, +the game is huge. +There are many neat things +which could go in, +if there were only enough space. +However, +I have specifically not gone to seperated I/D +space. +The main reason is that I would like future versions +of the game +to be 11/40 compatible. +.s1 +SUGGESTIONS FOR THE FUTURE +.pp +If you happen to have more energy than I do, +you may want to examine the following areas. +These are things that I may get to, +but don't hold your breath. +.s2 +Frankly, +making the portable C library work +(even without bugs) +was a bitch. +I should have done the I/O in a more +ad hoc manner. +It is my intent to rewrite the I/O +routines to bypass the portable C library entirely. +.s2 +The routine "capture" is quite unclean. +First, it should have a manner of selecting Klingons +other than random, +either selecting the most likely +or asking the captain (probably best). +It should either be fully implemented, +which includes adding a "board" routine +(half written, +on some tapes as board.x) +which sends a boarding party to forcefully +take over the Klingon, +or it should go out completely, +which is probably what I will end up doing. +When this happens, +the transporter will go completely. +It seems that the space may be better used +for something which more directly enhances the game. +.sp 3 +.in 0 +Well, that's about it. +To get hold of me, +write to: +.nf +.sp +Eric P Allman +Electronics Research Laboratory +University of California +Berkeley, California 94720 +.fi + +Happy trekking!! +.pp diff --git a/src/games/trek/docs/things b/src/games/trek/docs/things new file mode 100644 index 0000000..535a0c9 --- /dev/null +++ b/src/games/trek/docs/things @@ -0,0 +1,10 @@ +* tractor beams +* power distribution +* Romulans: +- plasma bolts +- neutral zone +- cloaking device +* the thing +* ion storms +* torpedoes with time delays +* Put removal from event list into killk diff --git a/src/games/trek/docs/trekmanual.nr b/src/games/trek/docs/trekmanual.nr new file mode 100644 index 0000000..33ead48 --- /dev/null +++ b/src/games/trek/docs/trekmanual.nr @@ -0,0 +1,895 @@ +.br +.po 10 +.if n \!. +.sp 15 +.tr ^ \" +.ce 88 +^****^^^^*****^^^^^^*^^^^^^****^ +*^^^^^^^^^^*^^^^^^^*^*^^^^^*^^^* +^***^^^^^^^*^^^^^^*****^^^^****^ +^^^^*^^^^^^*^^^^^^*^^^*^^^^*^^*^ +****^^^^^^^*^^^^^^*^^^*^^^^*^^^* + + +*****^^^^****^^^^^*****^^^^*^^^* +^^*^^^^^^*^^^*^^^^*^^^^^^^^*^^*^ +^^*^^^^^^****^^^^^***^^^^^^***^^ +^^*^^^^^^*^^*^^^^^*^^^^^^^^*^^*^ +^^*^^^^^^*^^^*^^^^*****^^^^*^^^* + + +by + +Eric Allman +University of California +Berkeley +.ce 0 +.tr ^^ +.de HE +'sp 4 +'tl 'STAR TREK''%' +'sp 3 +.. +.de FO +'bp +.. +.wh 0 HE +.wh -5 FO +.de pp +.sp +.ti +4 +.. +.bp 1 +.ce +INTRODUCTION +.pp +Well, the federation is once again at war with the Klingon empire. +It is up to you, +as captain of the U.S.S. Enterprise, +to wipe out the invasion fleet and save the Federation. +.pp +For the purposes of the game +the galaxy is divided into 64 quadrants +on an eight by eight grid, +with quadrant 0,0 in the upper left hand corner. +Each quadrant is divided into 100 sectors +on a ten by ten grid. +Each sector contains one object +(e.g., the Enterprise, a Klingon, or a star). +.pp +Navigation is handled in degrees, +with zero being straight up +and ninty being to the right. +Distances are measured in quadrants. +One tenth quadrant is one sector. +.pp +The galaxy contains starbases, +at which you can dock to refuel, +repair damages, etc. +The galaxy also contains stars. +Stars usually have a knack for getting in your way, +but they can be triggered into going nova +by shooting a photon torpedo at one, +thereby (hopefully) destroying any adjacent Klingons. +This is not a good practice however, +because you are penalized for destroying stars. +Also, a star will sometimes go supernova, +which obliterates an entire quadrant. +You must never stop in a supernova quadrant, +although you may "jump over" one. +.pp +Some starsystems +have inhabited planets. +Klingons can attack inhabited planets +and enslave the populace, +which they then put to work building more Klingon battle cruisers. +.bp +.ce +STARTING UP THE GAME +.pp +To request the game, issue the command +.sp +.ti +12 +/usr/games/trek +.sp +from the shell. +If a filename is stated, +a log of the game is written +onto that file. +If omitted, +the file is not written. +If the "-a" flag is stated before the filename, +that file is appended to +rather than created. +.pp +The game will ask you what length game +you would like. +Valid responses are "short", "medium", and "long". +Ideally the length of the game does not +affect the difficulty, +but currently the shorter games +tend to be harder than the longer ones. +You may also type "restart", +which restarts a previously saved game. +.pp +You will then be prompted for the skill, +to which you must respond +"novice", "fair", "good", "expert", +"commadore", or "impossible". +You should start out with a novice +and work up, +but if you really want to see how fast +you can be slaughtered, +start out with an impossible game. +.pp +In general, +throughout the game, +if you forget what is appropriate +the game will tell you what it expects +if you just type in +a question mark. +.pp +To get a copy of these rules, +execute the command +.sp +.ti +12 +nroff /usr/games/trekmanual.nr +.sp +.bp +.ce +ISSUING COMMANDS +.pp +If the game expects you to enter a command, +.hc ^ +it will say ^"Command:\ " +and wait for your response. +Most commands can be abbreviated. +.pp +At almost any time you can type more than one thing on a line. +For example, +to move straight up one quadrant, +you can type +.ti +12 +move 0 1 +.br +or you could just type +.ti +12 +move +.br +and the game would prompt you with +.ti +12 +Course: +.br +to which you could type +.ti +12 +0 1 +.br +The "1" is the distance, +which could be put on still another line. +Also, the "move" command +could have been abbreviated +"mov", "mo", or just "m". +.pp +If you are partway through a command +and you change your mind, +you can usually type "-1" +to cancel the command. +.pp +Klingons generally cannot hit you +if you don't consume anything +(e.g., time or energy), +so some commands are considered "free". +As soon as you consume anything though -- POW! +.bp +.de ** +.if \\n+l .** +.as x * +.. +.de bl +.nr l \\w'\\$1' -\\w'*' +.ds x **** +.** +.sp 3 +.ne 3 +\\*x +.br +.if t *\h'\w'*'u'\fB\\$1\fP\h'\w'*'u'* +.if n * \\$1 * +.br +\\*x +.sp +.in +8 +.nf +.. +.de FF +.in -8 +.fi +.. +.if !\n(.V .ta \w'Full Commands: '+1 +.if \n(.V .ta \w'Full Commands: 'u +.ce +THE COMMANDS +.bl "Short Range Scan" +Mnemonic: srscan +Shortest Appreviation: s +Full Commands: srscan + srscan yes/no +Consumes: nothing +.FF +.pp +The short range scan +gives you a picture +of the quadrant you are in, +and (if you say "yes") +a status report +which tells you +a whole bunch +of interesting stuff. +You can get a status report alone +by using the +.ul +status +command. +An example follows: +.sp +.nf +.in +4 +Short range sensor scan + 0 1 2 3 4 5 6 7 8 9 +0 . . . . . . . * . * 0 stardate 3702.16 +1 . . E . . . . . . . 1 condition RED +2 . . . . . . . . . * 2 position 0,3/1,2 +3 * . . . . # . . . . 3 warp factor 5.0 +4 . . . . . . . . . . 4 total energy 4376 +5 . . * . * . . . . . 5 torpedoes 9 +6 . . . @ . . . . . 6 shields down, 78% +7 . . . . . . . . . . 7 Klingons left 3 +8 . . . K . . . . . . 8 time left 6.43 +9 . . . . . . * . . . 9 life support damaged, reserves = 2.4 + 0 1 2 3 4 5 6 7 8 9 +Distressed Starsystem Marcus XII + +.in +8 +.ti -8 +The cast of characters is as follows: +E the hero +K the villain +# the starbase +* stars +@ inhabited starsystem +\&. empty space + a black hole +.in -12 +.fi +.pp +The name of the starsystem is listed underneath +the short range scan. +The word "distressed", if present, +means that the starsystem +is under attack. +.pp +Short range scans are absolutely free. +They use no time, no energy, +and they don't give the Klingons +another chance to hit you. +.bl "Status Report" +Mnemonic: status +Shortest Abbreviation: st +Consumes: nothing +.FF +.pp +This command gives you information +about the current status +of the game and your ship, as follows: +.in +8 +.de qq +.sp +.ti -4 +.. +.qq +Stardate -- The current stardate. +.qq +Condition -- as follows: +.in +4 +.nf +RED -- in battle +YELLOW -- low on energy +GREEN -- normal state +DOCKED -- docked at starbase +CLOAKED -- the cloaking device is activated +.fi +.in -4 +.qq +Position -- Your current quadrant and sector. +.qq +Warp Factor -- The speed you will move at +when you move under warp power +(with the +.ul +move +command). +.qq +Total Energy -- Your energy reserves. +If they drop to zero, +you die. +Energy regenerates, +but the higher the skill of the game, +the slower it regenerates. +.qq +Torpedoes -- How many photon torpedoes you have left. +.qq +Shields -- Whether your shields are up or down, +and how effective they are if up +(what percentage of a hit they will absorb). +.qq +Klingons Left -- Guess. +.qq +Time Left -- How long the Federation can hold out +if you sit on your fat ass and do nothing. +If you kill Klingons quickly, +this number goes up, +otherwise, +it goes down. +If it hits zero, +the Federation is conquered. +.qq +Life Support -- If "active", everything is fine. +If "damaged", your reserves tell you +how long you have +to repair your life support +or get to a starbase +before you starve, suffocate, +or something equally unpleasant. +.qq +Current Crew -- The number of crew members +left. +This figures does not include officers. +.qq +Brig Space -- The space left in your brig +for Klingon captives. +.qq +Klingon Power -- The number of units +needed to kill a Klingon. +Remember, as Klingons fire at you +they use up their own energy, +so you probably need somewhat less +than this. +.qq +Skill, Length -- The skill and length +of the game you are playing. +.in -8 +.pp +Status information is absolutely free. +.bl "Long Range Scan" +Mnemonic: lrscan +Shortest Abbreviation: l +Consumes: nothing +.FF +.pp +Long range scan gives you information about the +eight quadrants +that surround the quadrant +you're in. +A sample long range scan follows: +.sp +.in +12 +.nf +Long range scan for quadrant 0,3 + + 2 3 4 + ------------------- + ! * ! * ! * ! + ------------------- +0 ! 108 ! 6 ! 19 ! + ------------------- +1 ! 9 ! /// ! 8 ! + ------------------- +.sp +.in -12 +.fi +.pp +The three digit numbers +tell the number of objects +in the quadrants. +The units digit tells the number of stars, +the tens digit the number of starbases, +and the hundreds digit is the number of Klingons. +"*" indicates the negative energy barrier +at the edge of the galaxy, +which you cannot enter. +"///" means that that is a supernova quadrant +and must not be entered. +.bl "Damage Report" +Mnemonic: damages +Shortest Abbreviation: da +Consumes: nothing +.FF +.pp +A damage report tells you what devices are damaged +and how long it will take to repair them. +Repairs proceed faster +when you are docked +at a starbase. +.bl "Set Warp Factor" +Mnemonic: warp +Shortest Abbreviation: w +Full Command: warp factor +Consumes: nothing +.FF +.pp +The warp factor tells the speed of your starship +when you move under warp power +(with the +.ul +move +command). +The higher the warp factor, +the faster you go, +and the more energy you use. +.pp +The minimum warp factor is 1.0 +and the maximum is 10.0. +At speeds above warp 6 +there is danger of the warp engines +being damaged. +The probability of this +increases at higher warp speeds. +Above warp 9.0 there is a chance of entering +a time warp. +.bl "Move Under Warp Power" +Mnemonic: move +Shortest Abbreviation: m +Full Command: move course distance +Consumes: time and energy +.FF +.pp +This is the usual way of moving. +The course is in degrees and the distance is in quadrants. +To move one sector specify a distance of 0.1. +.pp +Time is consumed proportionately to +the inverse of the warp factor squared, +and directly to the distance. +Energy is consumed as the warp factor cubed, +and directly to the distance. +If you move with your shields up +it doubles the amount of energy consumed. +.pp +When you move in a quadrant containing Klingons, +they get a chance to attack you. +.pp +The computer detects navigation errors. +If the computer is out, +you run the risk of running into things. +.pp +The course is determined by the +Space Inertial Navigation System +[SINS]. +As described in +Star Fleet Technical Order TO:02:06:12, +the SINS is calibrated, +after which it becomes the base for navigation. +If damaged, +navigation becomes inaccurate. +When it is fixed, +Spock recalibrates it, +however, +it cannot be calibrated extremely accurately +until you dock at starbase. +.bl "Move Under Impulse Power" +Mnemonic: impulse +Shortest Abbreviation: i +Full Command: impulse course distance +Consumes: time and energy +.FF +.pp +The impulse engines give you a chance to maneuver +when your warp engines are damaged; +however, they are incredibly slow +(0.095 quadrants/stardate). +They require 20 units of energy to engage, +and ten units per sector to move. +.pp +The same comments about the computer and the SINS +apply as above. +.pp +There is no penalty to move under impulse power +with shields up. +.bl "Deflector Shields" +Mnemonic: shields +Shortest Abbreviation: sh +Full Command: shields up/down +Consumes: energy +.FF +.pp +Shields protect you from Klingon attack +and nearby novas. +As they protect you, +they weaken. +A shield which is 78% effective +will absorb 78% of a hit +and let 22% in to hurt you. +.pp +The Klingons have a chance to attack you +every time you raise or lower shields. +Shields do not rise and lower +instantaneously, +so the hit you receive +will be computed with the shields +at an intermediate effectiveness. +.pp +It takes energy to raise shields, +but not to drop them. +.bl "Cloaking Device" +Mnemonic: cloak +Shortest Abbreviation: cl +Full Command: cloak up/down +Consumes: energy +.FF +.pp +When you are cloaked, +Klingons cannot see you, +and hence they do not fire at you. +They are useful for entering +a quadrant +and selecting a good position, +however, +weapons cannot be fired through +the cloak +due to the huge energy drain +that it requires. +.pp +The cloak up command +only starts the cloaking process; +Klingons will continue +to fire at you +until you do something +which consumes time. +.bl "Fire Phasers" +Mnmemonic: phasers +Shortest Abbreviation: p +Full Commands: phasers automatic amount + phasers manual amt1 course1 spread1 ... +Consumes: energy +.FF +.pp +Phasers are energy weapons; +the energy comes from your ship's reserves +("total energy" on a srscan). +It takes about 250 units of hits +to kill a Klingon. +Hits are cumulative as long as you stay +in the quadrant. +.pp +Phasers become less effective +the further from a Klingon you are. +Adjacent Klingons receive about +90% of what you fire, +at five sectors about 60%, +and at ten sectors about 35%. +They have no effect outside of the quadrant. +.pp +Phasers cannot be fired while shields are up; +to do so would fry you. +They have no effect on starbases or stars. +.pp +In automatic mode +the computer decides how to divide up the energy +among the Klingons present; +in manual mode you do that yourself. +.pp +In manual mode firing +you specify a direction, +amount (number of units to fire) +and spread (0 -> 1.0) +for each of the six phaser banks. +A zero amount +terminates the manual input. +.bl "Fire Photon Torpedoes" +Mnemonic: torpedo +Shortest Abbreviation: t +Full Command: torpedo course [yes/no] [burst angle] +Consumes: torpedoes +.FF +.pp +Torpedoes are projectile weapons -- there are no partial hits. +You either hit your target or you don't. +A hit on a Klingon destroys him. +A hit on a starbase destroys that starbase +(woops!). +Hitting a star usually causes it to go nova, +and occasionally supernova. +.pp +Photon torpedoes cannot be aimed precisely. +They can be fired with shields up, +but they get even more random +as they pass through the shields. +.pp +Torpedoes may be fired in bursts of three. +If this is desired, +the burst angle is the angle +between the three shots, +which may vary from one to fifteen. +The word "no" +says that a burst is not wanted; +the word "yes" +(which may be omitted +if stated on the same line as the course) +says that a burst is wanted. +.pp +Photon torpedoes +have no effect +outside the quadrant. +.bl "Onboard Computer Request" +Mnemonic: computer +Shortest Abbreviation: c +Full Command: computer request; request;... +Consumes: nothing +.FF +.pp +The computer command gives you access to the facilities +of the onboard computer, +which allows you to do all sorts of fascinating stuff. +Computer requests are: +.in +8 +.qq +score -- Shows your current score. +.qq +course quad/sect -- Computes the course and distance from whereever +you are to the given location. +If you type "course /x,y" +you will be given the course +to sector x,y in the current quadrant. +.qq +move quad/sect -- Identical to the course +request, +except that the move is executed. +.qq +chart -- prints a chart of the known galaxy, +i.e., +everything that you have seen with a long range scan. +The format is the same as on a long range scan, +except that "..." means +that you don't yet know what is there, +and ".1." means that you know that a starbase +exists, but you don't know anything else. +"$$$" mans the quadrant +that you are currently in. +.qq +trajectory -- prints the course and distance +to all the Klingons in the quadrant. +.qq +warpcost dist warp_factor -- computes the cost in time and energy +to move `dist' quadrants at warp `warp_factor'. +.qq +impcost dist -- same as warpcost for impulse engines. +.qq +pheff range -- tells how effective your phasers are +at a given range. +.qq +distresslist -- gives a list of currently distressed +starbases +and starsystems. +.in -8 +.pp +More than one request may be stated +on a line +by seperating them +with semicolons. +.bl "Dock at Starbase" +Mnemonic: dock +Shortest Abbreviation: do +Consumes: nothing +.FF +.pp +You may dock at a starbase +when you are in one of the eight +adjacent sectors. +.pp +When you dock you are resupplied +with energy, photon torpedoes, and life support reserves. +Repairs are also done faster at starbase. +Any prisoners you have taken +are unloaded. +You do not recieve points +for taking prisoners +until this time. +.pp +Starbases have their own deflector shields, +so you are safe from attack while docked. +.bl "Undock from Starbase" +Mnemonic: undock +Shortest Abbreviation: u +Consumes: nothing +.FF +.pp +This just allows you to leave starbase +so that you may proceed on your way. +.bl "Rest" +Mnemonic: rest +Shortest Abbreviation: r +Full Command: rest time +Consumes: time +.FF +.pp +This command allows you to rest to repair damages. +It is not advisable to rest while under attack. +.bl "Call Starbase For Help" +Mnemonic: help +Shortest Abbreviation: help +Consumes: nothing +.FF +.pp +You may call starbase for help via your subspace radio. +Starbase has long range transporter beams to get you. +Problem is, +they can't always rematerialize you. +.pp +You should avoid using this command unless absolutely necessary, +for the above reason and because it counts heavily against you +in the scoring. +.bl "Capture Klingon" +Mnemonic: capture +Shortest Abbreviation: ca +Consumes: time +.FF +.pp +You may request that a Klingon surrender +to you. +If he accepts, +you get to take captives +(but only as many as your brig +can hold). +It is good if you do this, +because you get points for captives. +Also, +if you ever get captured, +you want to be sure that the Federation +has prisoners to exchange for you. +.pp +You must go to a starbase +to turn over your prisoners +to Federation authorities. +.bl "Visual Scan" +Mnemonic: visual +Shortest Abbreviation: v +Full Command: visual course +Consumes: time +.FF +.pp +When your short range scanners are out, +you can still see what is out "there" +by doing a visual scan. +Unfortunately, +you can only see three sectors at one time, +and it takes 0.005 stardates to perform. +.pp +The three sectors in the general direction +of the course specified +are examined +and displayed. +.bl "Abandon Ship" +Mnemonic: abandon +Shortest Abbreviation: abandon +Consumes: nothing +.FF +.pp +The officers escape the Enterprise in the shuttlecraft. +If the transporter is working +and there is an inhabitable starsystem +in the area, +the crew beams down, +otherwise you leave them to die. +You are given an old but still usable ship, +the Faire Queene. +.bl "Ram" +Mnemonic: ram +Shortest Abbreviation: ram +Full Command: ram course distance +Consumes: time and energy +.FF +.pp +This command is identical to "move", +except that the computer +doesn't stop you +from making navigation errors. +.pp +You get very nearly slaughtered +if you ram anything. +.bl "Self Destruct" +Mnemonic: destruct +Shortest Abbreviation: destruct +Consumes: everything +.FF +.pp +Your starship is self-destructed. +Chances are you will destroy +any Klingons +(and stars, +and starbases) +left in your quadrant. +.bl "Terminate the Game" +Mnemonic: terminate +Shortest Abbreviation: terminate +Full Command: terminate yes/no +.FF +.pp +Cancels the current game. +No score is computed. +If you answer yes, +a new game will be started, +otherwise trek exits. +.bl "Call the Shell" +Mnemonic: shell +Shortest Abbreviation: shell +.FF +.pp +Temporarily escapes to the shell. +When you log out of the shell +you will return to the game. +.bp +.ce +SCORING +.in +4 +.pp +The scoring algorithm is rather complicated. +Basically, +you get points for each Klingon you kill, +for your Klingon per stardate kill rate, +and a bonus if you win the game. +You lose +points for the number of Klingons left +in the galaxy +at the end of the game, +for getting killed, +for each star, starbase, or inhabited starsystem +you destroy, +for calling for help, +and for each casualty you incur. +.pp +You will be promoted +if you play very well. +You will never get a promotion if you +call for help, +abandon the Enterprise, +get killed, +destroy a starbase or inhabited starsystem, +or destroy too many stars. +.bp +.ce +REFERENCE PAGE +.sp 2 +.ta 36 56 +.nf +.ul +Command Uses Consumes + +ABANDON shuttlecraft, - + transporter +CApture subspace radio time +CLoak Up/Down cloaking device energy +Computer request; request;... computer - +DAmages - - +DESTRUCT computer - +DOck - - +HELP subspace radio - +Impulse course distance impulse engines, time, energy + computer, SINS +Lrscan L.R. sensors - +Move course distance warp engines, time, energy + computer, SINS +Phasers Automatic amount phasers, computer energy +Phasers Manual amt1 course1 spread1 ... phasers energy +Torpedo course [Yes] angle/No torpedo tubes torpedoes +RAM course distance warp engines, time, energy + computer, SINS +Rest time - time +SHELL - - +SHields Up/Down shields energy +Srscan [Yes/No] S.R. sensors - +STatus - - +TERMINATE Yes/No - - +Undock - - +Visual course - time +Warp warp_factor - - +.fi diff --git a/src/games/trek/dumpgame.c b/src/games/trek/dumpgame.c new file mode 100644 index 0000000..eb9101e --- /dev/null +++ b/src/games/trek/dumpgame.c @@ -0,0 +1,130 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +# include "trek.h" +# include + +/*** THIS CONSTANT MUST CHANGE AS THE DATA SPACES CHANGE ***/ +# define VERSION 2 + +struct dump +{ + char *area; + int count; +}; + +struct dump Dump_template[] = +{ + { (char *)&Ship, sizeof (Ship) }, + { (char *)&Now, sizeof (Now) }, + { (char *)&Param, sizeof (Param) }, + { (char *)&Etc, sizeof (Etc) }, + { (char *)&Game, sizeof (Game) }, + { (char *)Sect, sizeof (Sect) }, + { (char *)Quad, sizeof (Quad) }, + { (char *)&Move, sizeof (Move) }, + { (char *)Event, sizeof (Event) }, + { 0 }, +}; + +/* +** DUMP GAME +** +** This routine dumps the game onto the file "trek.dump". The +** first two bytes of the file are a version number, which +** reflects whether this image may be used. Obviously, it must +** change as the size, content, or order of the data structures +** output change. +*/ +void +dumpgame() +{ + int version; + register int fd; + register struct dump *d; + register int i; + + fd = creat("trek.dump", 0644); + if (fd < 0) { + printf("cannot dump\n"); + return; + } + version = VERSION; + write(fd, &version, sizeof version); + + /* output the main data areas */ + for (d = Dump_template; d->area; d++) + { + write(fd, &d->area, sizeof d->area); + i = d->count; + write(fd, d->area, i); + } + + close(fd); +} + +/* +** READ DUMP +** +** This is the business end of restartgame(). It reads in the +** areas. +** +** Returns zero for success, one for failure. +*/ +int +readdump(fd1) + int fd1; +{ + register int fd; + register struct dump *d; + register int i; + int junk; + + fd = fd1; + + for (d = Dump_template; d->area; d++) + { + if (read(fd, &junk, sizeof junk) != (sizeof junk)) + return (1); + if ((char *)junk != d->area) + return (1); + i = d->count; + if (read(fd, d->area, i) != i) + return (1); + } + + /* make quite certain we are at EOF */ + return (read(fd, &junk, 1)); +} + +/* +** RESTORE GAME +** +** The game is restored from the file "trek.dump". In order for +** this to succeed, the file must exist and be readable, must +** have the correct version number, and must have all the appro- +** priate data areas. +** +** Return value is zero for success, one for failure. +*/ +int +restartgame() +{ + register int fd; + int version; + + if ((fd = open("trek.dump", 0)) < 0 || + read(fd, &version, sizeof version) != sizeof version || + version != VERSION || + readdump(fd)) + { + printf("cannot restart\n"); + close(fd); + return (1); + } + + close(fd); + return (0); +} diff --git a/src/games/trek/dumpme.c b/src/games/trek/dumpme.c new file mode 100644 index 0000000..fa21cc1 --- /dev/null +++ b/src/games/trek/dumpme.c @@ -0,0 +1,56 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +# include "trek.h" + +/* +** Dump the starship somewhere in the galaxy +** +** Parameter is zero if bounce off of negative energy barrier, +** one if through a black hole +** +** Note that the quadrant is NOT initialized here. This must +** be done from the calling routine. +** +** Repair of devices must be deferred. +*/ +void +dumpme(flag) + int flag; +{ + register int f; + double x; + register struct event *e; + register int i; + + f = flag; + Ship.quadx = ranf(NQUADS); + Ship.quady = ranf(NQUADS); + Ship.sectx = ranf(NSECTS); + Ship.secty = ranf(NSECTS); + x = 1.5 * franf(); + Move.time += x; + if (f) + { + printf("%s falls into a black hole.\n", Ship.shipname); + } + else + { + printf("Computer applies full reverse power to avoid hitting the\n"); + printf(" negative energy barrier. A space warp was entered.\n"); + } + /* bump repair dates forward */ + for (i = 0; i < MAXEVENTS; i++) + { + e = &Event[i]; + if (e->evcode != E_FIXDV) + continue; + reschedule(e, (e->date - Now.date) + x); + } + events(1); + printf("You are now in quadrant %d,%d. It is stardate %.2f\n", + Ship.quadx, Ship.quady, Now.date); + Move.time = 0; +} diff --git a/src/games/trek/dumpssradio.c b/src/games/trek/dumpssradio.c new file mode 100644 index 0000000..e98bb1a --- /dev/null +++ b/src/games/trek/dumpssradio.c @@ -0,0 +1,53 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +# include "trek.h" + +/** + ** output hidden distress calls + **/ +int +dumpssradio() +{ + register struct event *e; + register int j; + register int chkrest; + + chkrest = 0; + for (j = 0; j < MAXEVENTS; j++) + { + e = &Event[j]; + /* if it is not hidden, then just ignore it */ + if ((e->evcode & E_HIDDEN) == 0) + continue; + if (e->evcode & E_GHOST) + { + unschedule(e); + printf("Starsystem %s in quadrant %d,%d is no longer distressed\n", + Systemname[(int)e->systemname], e->x, e->y); + continue; + } + + switch (e->evcode) + { + + case E_KDESB: + printf("Starbase in quadrant %d,%d is under attack\n", + e->x, e->y); + chkrest++; + break; + + case E_ENSLV: + case E_REPRO: + printf("Starsystem %s in quadrant %d,%d is distressed\n", + Systemname[(int)e->systemname], e->x, e->y); + chkrest++; + break; + + } + } + + return (chkrest); +} diff --git a/src/games/trek/events.c b/src/games/trek/events.c new file mode 100644 index 0000000..578ae13 --- /dev/null +++ b/src/games/trek/events.c @@ -0,0 +1,435 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +# include "trek.h" +# include "getpar.h" + +/* +** CAUSE TIME TO ELAPSE +** +** This routine does a hell of a lot. It elapses time, eats up +** energy, regenerates energy, processes any events that occur, +** and so on. +*/ +int +events(warp) + int warp; /* set if called in a time warp */ +{ + register int i; + int j; + struct kling *k; + double rtime; + double xdate; + double idate; + struct event *ev, *xsched(), *schedule(); + int ix, iy; + register struct quad *q; + register struct event *e; + int evnum; + int restcancel; + void *vp; + + /* if nothing happened, just allow for any Klingons killed */ + if (Move.time <= 0.0) + { + Now.time = Now.resource / Now.klings; + return (0); + } + + /* indicate that the cloaking device is now working */ + Ship.cloakgood = 1; + + /* idate is the initial date */ + idate = Now.date; + + /* schedule attacks if resting too long */ + if (Move.time > 0.5 && Move.resting) + schedule(E_ATTACK, 0.5, 0, 0, 0); + + /* scan the event list */ + while (1) + { + restcancel = 0; + evnum = -1; + /* xdate is the date of the current event */ + xdate = idate + Move.time; + + /* find the first event that has happened */ + ev = 0; + for (i = 0; i < MAXEVENTS; i++) + { + e = &Event[i]; + if (e->evcode == 0 || (e->evcode & E_GHOST)) + continue; + if (e->date < xdate) + { + xdate = e->date; + ev = e; + evnum = i; + } + } + e = ev; + + /* find the time between events */ + rtime = xdate - Now.date; + + /* decrement the magic "Federation Resources" pseudo-variable */ + Now.resource -= Now.klings * rtime; + /* and recompute the time left */ + Now.time = Now.resource / Now.klings; + + /* move us up to the next date */ + Now.date = xdate; + + /* check for out of time */ + if (Now.time <= 0.0) + lose(L_NOTIME); +# ifdef xTRACE + if (evnum >= 0 && Trace) + printf("xdate = %.2f, evcode %d params %d %d %d\n", + xdate, e->evcode, e->x, e->y, e->systemname); +# endif + + /* if evnum < 0, no events occurred */ + if (evnum < 0) + break; + + /* otherwise one did. Find out what it is */ + switch (e->evcode & E_EVENT) + { + + case E_SNOVA: /* supernova */ + /* cause the supernova to happen */ + snova(-1, -1); + /* and schedule the next one */ + xresched(e, E_SNOVA, 1); + break; + + case E_LRTB: /* long range tractor beam */ + /* schedule the next one */ + xresched(e, E_LRTB, Now.klings); + /* LRTB cannot occur if we are docked */ + if (Ship.cond != DOCKED) + { + /* pick a new quadrant */ + i = ranf(Now.klings) + 1; + for (ix = 0; ix < NQUADS; ix++) + { + for (iy = 0; iy < NQUADS; iy++) + { + q = &Quad[ix][iy]; + if (q->stars >= 0) + if ((i -= q->klings) <= 0) + break; + } + if (i <= 0) + break; + } + + /* test for LRTB to same quadrant */ + if (Ship.quadx == ix && Ship.quady == iy) + break; + + /* nope, dump him in the new quadrant */ + Ship.quadx = ix; + Ship.quady = iy; + printf("\n%s caught in long range tractor beam\n", Ship.shipname); + printf("*** Pulled to quadrant %d,%d\n", Ship.quadx, Ship.quady); + Ship.sectx = ranf(NSECTS); + Ship.secty = ranf(NSECTS); + initquad(0); + /* truncate the move time */ + Move.time = xdate - idate; + } + break; + + case E_KATSB: /* Klingon attacks starbase */ + /* if out of bases, forget it */ + if (Now.bases <= 0) + { + unschedule(e); + break; + } + + /* check for starbase and Klingons in same quadrant */ + for (i = 0; i < Now.bases; i++) + { + ix = Now.base[i].x; + iy = Now.base[i].y; + /* see if a Klingon exists in this quadrant */ + q = &Quad[ix][iy]; + if (q->klings <= 0) + continue; + + /* see if already distressed */ + for (j = 0; j < MAXEVENTS; j++) + { + e = &Event[j]; + if ((e->evcode & E_EVENT) != E_KDESB) + continue; + if (e->x == ix && e->y == iy) + break; + } + if (j < MAXEVENTS) + continue; + + /* got a potential attack */ + break; + } + e = ev; + if (i >= Now.bases) + { + /* not now; wait a while and see if some Klingons move in */ + reschedule(e, 0.5 + 3.0 * franf()); + break; + } + /* schedule a new attack, and a destruction of the base */ + xresched(e, E_KATSB, 1); + e = xsched(E_KDESB, 1, ix, iy, 0); + + /* report it if we can */ + if (!damaged(SSRADIO)) + { + printf("\nUhura: Captain, we have recieved a distress signal\n"); + printf(" from the starbase in quadrant %d,%d.\n", + ix, iy); + restcancel++; + } + else + /* SSRADIO out, make it so we can't see the distress call */ + /* but it's still there!!! */ + e->evcode |= E_HIDDEN; + break; + + case E_KDESB: /* Klingon destroys starbase */ + unschedule(e); + q = &Quad[(int)e->x][(int)e->y]; + /* if the base has mysteriously gone away, or if the Klingon + got tired and went home, ignore this event */ + if (q->bases <=0 || q->klings <= 0) + break; + /* are we in the same quadrant? */ + if (e->x == Ship.quadx && e->y == Ship.quady) + { + /* yep, kill one in this quadrant */ + printf("\nSpock: "); + killb(Ship.quadx, Ship.quady); + } + else + /* kill one in some other quadrant */ + killb(e->x, e->y); + break; + + case E_ISSUE: /* issue a distress call */ + xresched(e, E_ISSUE, 1); + /* if we already have too many, throw this one away */ + if (Ship.distressed >= MAXDISTR) + break; + /* try a whole bunch of times to find something suitable */ + for (i = 0; i < 100; i++) + { + ix = ranf(NQUADS); + iy = ranf(NQUADS); + q = &Quad[ix][iy]; + /* need a quadrant which is not the current one, + which has some stars which are inhabited and + not already under attack, which is not + supernova'ed, and which has some Klingons in it */ + if (!((ix == Ship.quadx && iy == Ship.quady) || q->stars < 0 || + (q->qsystemname & Q_DISTRESSED) || + (q->qsystemname & Q_SYSTEM) == 0 || q->klings <= 0)) + break; + } + if (i >= 100) + /* can't seem to find one; ignore this call */ + break; + + /* got one!! Schedule its enslavement */ + Ship.distressed++; + e = xsched(E_ENSLV, 1, ix, iy, q->qsystemname); + q->qsystemname = (e - Event) | Q_DISTRESSED; + + /* tell the captain about it if we can */ + if (!damaged(SSRADIO)) + { + printf("\nUhura: Captain, starsystem %s in quadrant %d,%d is under attack\n", + Systemname[(int)e->systemname], ix, iy); + restcancel++; + } + else + /* if we can't tell him, make it invisible */ + e->evcode |= E_HIDDEN; + break; + + case E_ENSLV: /* starsystem is enslaved */ + unschedule(e); + /* see if current distress call still active */ + q = &Quad[(int)e->x][(int)e->y]; + if (q->klings <= 0) + { + /* no Klingons, clean up */ + /* restore the system name */ + q->qsystemname = e->systemname; + break; + } + + /* play stork and schedule the first baby */ + e = schedule(E_REPRO, Param.eventdly[E_REPRO] * franf(), e->x, e->y, e->systemname); + + /* report the disaster if we can */ + if (!damaged(SSRADIO)) + { + printf("\nUhura: We've lost contact with starsystem %s\n", + Systemname[(int)e->systemname]); + printf(" in quadrant %d,%d.\n", + e->x, e->y); + } + else + e->evcode |= E_HIDDEN; + break; + + case E_REPRO: /* Klingon reproduces */ + /* see if distress call is still active */ + q = &Quad[(int)e->x][(int)e->y]; + if (q->klings <= 0) + { + unschedule(e); + q->qsystemname = e->systemname; + break; + } + xresched(e, E_REPRO, 1); + /* reproduce one Klingon */ + ix = e->x; + iy = e->y; + if (Now.klings == 127) + break; /* full right now */ + if (q->klings >= MAXKLQUAD) + { + /* this quadrant not ok, pick an adjacent one */ + j = 0; + for (i = ix - 1; i <= ix + 1; i++) + { + if (i < 0 || i >= NQUADS) + continue; + for (j = iy - 1; j <= iy + 1; j++) + { + if (j < 0 || j >= NQUADS) + continue; + q = &Quad[i][j]; + /* check for this quad ok (not full & no snova) */ + if (q->klings >= MAXKLQUAD || q->stars < 0) + continue; + break; + } + if (j <= iy + 1) + break; + } + if (j > iy + 1) + /* cannot create another yet */ + break; + ix = i; + iy = j; + } + /* deliver the child */ + q->klings++; + Now.klings++; + if (ix == Ship.quadx && iy == Ship.quady) + { + /* we must position Klingon */ + sector(&ix, &iy); + Sect[ix][iy] = KLINGON; + k = &Etc.klingon[(int)Etc.nkling++]; + k->x = ix; + k->y = iy; + k->power = Param.klingpwr; + k->srndreq = 0; + compkldist(Etc.klingon[0].dist == Etc.klingon[0].avgdist ? 0 : 1); + } + + /* recompute time left */ + Now.time = Now.resource / Now.klings; + break; + + case E_SNAP: /* take a snapshot of the galaxy */ + xresched(e, E_SNAP, 1); + vp = Etc.snapshot; + vp = bmove(Quad, vp, sizeof (Quad)); + vp = bmove(Event, vp, sizeof (Event)); + vp = bmove(&Now, vp, sizeof (Now)); + Game.snap = 1; + break; + + case E_ATTACK: /* Klingons attack during rest period */ + if (!Move.resting) + { + unschedule(e); + break; + } + attack(1); + reschedule(e, 0.5); + break; + + case E_FIXDV: + i = e->systemname; + unschedule(e); + + /* de-damage the device */ + printf("%s reports repair work on the %s finished.\n", + Device[i].person, Device[i].name); + + /* handle special processing upon fix */ + switch (i) + { + + case LIFESUP: + Ship.reserves = Param.reserves; + break; + + case SINS: + if (Ship.cond == DOCKED) + break; + printf("Spock has tried to recalibrate your Space Internal Navigation System,\n"); + printf(" but he has no standard base to calibrate to. Suggest you get\n"); + printf(" to a starbase immediately so that you can properly recalibrate.\n"); + Ship.sinsbad = 1; + break; + + case SSRADIO: + restcancel = dumpssradio(); + break; + } + break; + + default: + break; + } + + if (restcancel && Move.resting && getynpar("Spock: Shall we cancel our rest period")) + Move.time = xdate - idate; + + } + + /* unschedule an attack during a rest period */ + e = Now.eventptr[E_ATTACK]; + if (e) + unschedule(e); + + if (!warp) + { + /* eat up energy if cloaked */ + if (Ship.cloaked) + Ship.energy -= Param.cloakenergy * Move.time; + + /* regenerate resources */ + rtime = 1.0 - exp(-Param.regenfac * Move.time); + Ship.shield += (Param.shield - Ship.shield) * rtime; + Ship.energy += (Param.energy - Ship.energy) * rtime; + + /* decrement life support reserves */ + if (damaged(LIFESUP) && Ship.cond != DOCKED) + Ship.reserves -= Move.time; + } + return (0); +} diff --git a/src/games/trek/externs.c b/src/games/trek/externs.c new file mode 100644 index 0000000..4b56993 --- /dev/null +++ b/src/games/trek/externs.c @@ -0,0 +1,66 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +# include "trek.h" + +/* +** global variable definitions +*/ + +struct device Device[NDEV] = +{ + { "warp drive", "Scotty" }, + { "S.R. scanners", "Scotty" }, + { "L.R. scanners", "Scotty" }, + { "phasers", "Sulu" }, + { "photon tubes", "Sulu" }, + { "impulse engines", "Scotty" }, + { "shield control", "Sulu" }, + { "computer", "Spock" }, + { "subspace radio", "Uhura" }, + { "life support", "Scotty" }, + { "navigation system", "Chekov" }, + { "cloaking device", "Scotty" }, + { "transporter", "Scotty" }, + { "shuttlecraft", "Scotty" }, + { "*ERR 14*", "Nobody" }, + { "*ERR 15*", "Nobody" }, +}; + +char *Systemname[NINHAB] = +{ + "ERROR", + "Talos IV", + "Rigel III", + "Deneb VII", + "Canopus V", + "Icarus I", + "Prometheus II", + "Omega VII", + "Elysium I", + "Scalos IV", + "Procyon IV", + "Arachnid I", + "Argo VIII", + "Triad III", + "Echo IV", + "Nimrod III", + "Nemisis IV", + "Centarurus I", + "Kronos III", + "Spectros V", + "Beta III", + "Gamma Tranguli VI", + "Pyris III", + "Triachus", + "Marcus XII", + "Kaland", + "Ardana", + "Stratos", + "Eden", + "Arrikis", + "Epsilon Eridani IV", + "Exo III" +}; diff --git a/src/games/trek/getcodi.c b/src/games/trek/getcodi.c new file mode 100644 index 0000000..a1a45c6 --- /dev/null +++ b/src/games/trek/getcodi.c @@ -0,0 +1,35 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +# include "getpar.h" + +/* +** get course and distance +** +** The user is asked for a course and distance. This is used by +** move, impulse, and some of the computer functions. +** +** The return value is zero for success, one for an invalid input +** (meaning to drop the request). +*/ +int +getcodi(co, di) + int *co; + double *di; +{ + *co = getintpar("Course"); + + /* course must be in the interval [0, 360] */ + if (*co < 0 || *co > 360) + return (1); + *di = getfltpar("Distance"); + + /* distance must be in the interval [0, 15] */ + if (*di <= 0.0 || *di > 15.0) + return (1); + + /* good return */ + return (0); +} diff --git a/src/games/trek/getpar.c b/src/games/trek/getpar.c new file mode 100644 index 0000000..f1ba993 --- /dev/null +++ b/src/games/trek/getpar.c @@ -0,0 +1,288 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +# include +# include +# include "getpar.h" + +/** + ** test for valid terminator + **/ +static int +testterm() +{ + register char c; + + c = fgetc(stdin); + if (c == '.') + return (0); + if (c == '\n' || c == ';') + ungetc(c, stdin); + return (1); +} + +/** + ** get integer parameter + **/ +int +getintpar(s) + char *s; +{ + register int i; + int n; + + while (1) + { + if (testnl() && s) + printf("%s: ", s); + i = scanf("%d", &n); + if (i < 0) + exit(1); + if (i > 0 && testterm()) + return (n); + printf("invalid input; please enter an integer\n"); + skiptonl(0); + } +} + +/** + ** get floating parameter + **/ +double +getfltpar(s) + char *s; +{ + register int i; + double d; + + while (1) + { + if (testnl() && s) + printf("%s: ", s); + i = scanf("%lf", &d); + if (i < 0) + exit(1); + if (i > 0 && testterm()) + return (d); + printf("invalid input; please enter a double\n"); + skiptonl(0); + } +} + +/** + ** get yes/no parameter + **/ +struct cvntab Yntab[] = { + { "y", "es", (void (*)())1, 0 }, + { "n", "o", (void (*)())0, 0 }, + { 0 }, +}; + +int +getynpar(s) + char *s; +{ + struct cvntab *r; + + r = getcodpar(s, Yntab); + return ((int) r->value); +} + + +/* +** STRING CONCATENATE +** +** The strings `s1' and `s2' are concatenated and stored into +** `s3'. It is ok for `s1' to equal `s3', but terrible things +** will happen if `s2' equals `s3'. The return value is is a +** pointer to the end of `s3' field. +*/ +char * +concat(s1, s2, s3) + char *s1, *s2, *s3; +{ + register char *p; + register char *q; + + p = s3; + q = s1; + while (*q) + *p++ = *q++; + q = s2; + while (*q) + *p++ = *q++; + *p = 0; + return (p); +} + + +/** + ** get coded parameter + **/ +struct cvntab * +getcodpar(s, tab) + char *s; + struct cvntab tab[]; +{ + char input[100]; + register struct cvntab *r; + int flag; + register char *p, *q; + int c; + int f; + + flag = 0; + while (1) + { + flag |= (f = testnl()); + if (flag) + printf("%s: ", s); + if (f) + fgetc(stdin); /* throw out the newline */ + scanf("%*[ \t;]"); + if ((c = scanf("%[^ \t;\n]", input)) < 0) + exit(1); + if (c == 0) + continue; + flag = 1; + + /* if command list, print four per line */ + if (input[0] == '?' && input[1] == 0) + { + c = 4; + for (r = tab; r->abrev; r++) + { + concat(r->abrev, r->full, input); + printf("%14.14s", input); + if (--c > 0) + continue; + c = 4; + printf("\n"); + } + if (c != 4) + printf("\n"); + continue; + } + + /* search for in table */ + for (r = tab; r->abrev; r++) + { + p = input; + for (q = r->abrev; *q; q++) + if (*p++ != *q) + break; + if (!*q) + { + for (q = r->full; *p && *q; q++, p++) + if (*p != *q) + break; + if (!*p || !*q) + break; + } + } + + /* check for not found */ + if (!r->abrev) + { + printf("invalid input; ? for valid inputs\n"); + skiptonl(0); + } + else + return (r); + } +} + + +/** + ** get string parameter + **/ +void +getstrpar(s, r, l, t) + char *s; + char *r; + int l; + char *t; +{ + register int i; + char format[20]; + register int f; + + if (t == 0) + t = " \t\n;"; + sprintf(format, "%%%d[^%s]", l, t); + while (1) + { + if ((f = testnl()) && s) + printf("%s: ", s); + if (f) + fgetc(stdin); + scanf("%*[\t ;]"); + i = scanf(format, r); + if (i < 0) + exit(1); + if (i != 0) + return; + } +} + + +/** + ** test if newline is next valid character + **/ +int +testnl() +{ + register char c; + + while ((c = fgetc(stdin)) != '\n') + if ((c >= '0' && c <= '9') || c == '.' || c == '!' || + (c >= 'A' && c <= 'Z') || + (c >= 'a' && c <= 'z') || c == '-') + { + ungetc(c, stdin); + return(0); + } + ungetc(c, stdin); + return (1); +} + + +/** + ** scan for newline + **/ +void +skiptonl(c) + int c; +{ + while (c != '\n') + if (!(c = fgetc(stdin))) + return; + ungetc('\n', stdin); +} + + +/* +** TEST FOR SPECIFIED DELIMETER +** +** The standard input is scanned for the parameter. If found, +** it is thrown away and non-zero is returned. If not found, +** zero is returned. +*/ +int +readdelim(d) + int d; +{ + register char c; + + while ((c = fgetc(stdin))) { + if (c == d) + return (1); + if (c == ' ') + continue; + ungetc(c, stdin); + break; + } + return (0); +} diff --git a/src/games/trek/getpar.h b/src/games/trek/getpar.h new file mode 100644 index 0000000..87ff767 --- /dev/null +++ b/src/games/trek/getpar.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + * + * @(#)getpar.h 5.1 (Berkeley) 5/30/85 + */ + +struct cvntab /* used for getcodpar() paramater list */ +{ + char *abrev; + char *full; + void (*value)(); + int value2; +}; + +void skiptonl(int c); +void getstrpar(char *s, char *r, int l, char *t); + +int getintpar(char *s); +int getynpar(char *s); +int testnl(void); + +double getfltpar(char *s); + +struct cvntab *getcodpar(char *s, struct cvntab *tab); diff --git a/src/games/trek/help.c b/src/games/trek/help.c new file mode 100644 index 0000000..a1cf55c --- /dev/null +++ b/src/games/trek/help.c @@ -0,0 +1,131 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +# include "trek.h" +# include + +/* +** call starbase for help +** +** First, the closest starbase is selected. If there is a +** a starbase in your own quadrant, you are in good shape. +** This distance takes quadrant distances into account only. +** +** A magic number is computed based on the distance which acts +** as the probability that you will be rematerialized. You +** get three tries. +** +** When it is determined that you should be able to be remater- +** ialized (i.e., when the probability thing mentioned above +** comes up positive), you are put into that quadrant (anywhere). +** Then, we try to see if there is a spot adjacent to the star- +** base. If not, you can't be rematerialized!!! Otherwise, +** it drops you there. It only tries five times to find a spot +** to drop you. After that, it's your problem. +*/ + +char *Cntvect[3] = {"first", "second", "third"}; + +void +help() +{ + register int i; + double dist, x; + register int dx, dy; + int j, l; + + /* check to see if calling for help is reasonable ... */ + if (Ship.cond == DOCKED) { + printf("Uhura: But Captain, we're already docked\n"); + return; + } + /* or possible */ + if (damaged(SSRADIO)) { + out(SSRADIO); + return; + } + if (Now.bases <= 0) { + printf("Uhura: I'm not getting any response from starbase\n"); + return; + } + /* tut tut, there goes the score */ + Game.helps += 1; + + /* find the closest base */ + dist = DBL_MAX; + if (Quad[Ship.quadx][Ship.quady].bases <= 0) + { + /* there isn't one in this quadrant */ + l = 0; + for (i = 0; i < Now.bases; i++) + { + /* compute distance */ + dx = Now.base[i].x - Ship.quadx; + dy = Now.base[i].y - Ship.quady; + x = dx * dx + dy * dy; + x = sqrt(x); + + /* see if better than what we already have */ + if (x < dist) + { + dist = x; + l = i; + } + } + + /* go to that quadrant */ + Ship.quadx = Now.base[l].x; + Ship.quady = Now.base[l].y; + initquad(1); + } + else + { + dist = 0.0; + } + + /* dematerialize the Enterprise */ + Sect[Ship.sectx][Ship.secty] = EMPTY; + printf("Starbase in %d,%d responds\n", Ship.quadx, Ship.quady); + + /* this next thing acts as a probability that it will work */ + x = pow(1.0 - pow(0.94, dist), 0.3333333); + + /* attempt to rematerialize */ + for (i = 0; i < 3; i++) + { + sleep(2); + printf("%s attempt to rematerialize ", Cntvect[i]); + if (franf() > x) + { + /* ok, that's good. let's see if we can set her down */ + for (j = 0; j < 5; j++) + { + dx = Etc.starbase.x + ranf(3) - 1; + if (dx < 0 || dx >= NSECTS) + continue; + dy = Etc.starbase.y + ranf(3) - 1; + if (dy < 0 || dy >= NSECTS || Sect[dx][dy] != EMPTY) + continue; + break; + } + if (j < 5) + { + /* found an empty spot */ + printf("succeeds\n"); + Ship.sectx = dx; + Ship.secty = dy; + Sect[dx][dy] = Ship.ship; + dock(); + compkldist(0); + return; + } + /* the starbase must have been surrounded */ + } + printf("fails\n"); + } + + /* one, two, three strikes, you're out */ + lose(L_NOHELP); +} diff --git a/src/games/trek/impulse.c b/src/games/trek/impulse.c new file mode 100644 index 0000000..b7bdd5e --- /dev/null +++ b/src/games/trek/impulse.c @@ -0,0 +1,53 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +# include "trek.h" +# include "getpar.h" + +/** + ** move under impulse power + **/ +void +impulse() +{ + int course; + register int power; + double dist, time; + register int percent; + extern double move(); + + if (Ship.cond == DOCKED) { + printf("Scotty: Sorry captain, but we are still docked.\n"); + return; + } + if (damaged(IMPULSE)) { + out(IMPULSE); + return; + } + if (getcodi(&course, &dist)) + return; + power = 20 + 100 * dist; + percent = 100 * power / Ship.energy + 0.5; + if (percent >= 85) + { + printf("Scotty: That would consume %d%% of our remaining energy.\n", + percent); + if (!getynpar("Are you sure that is wise")) + return; + printf("Aye aye, sir\n"); + } + time = dist / 0.095; + percent = 100 * time / Now.time + 0.5; + if (percent >= 85) + { + printf("Spock: That would take %d%% of our remaining time.\n", + percent); + if (!getynpar("Are you sure that is wise")) + return; + printf("(He's finally gone mad)\n"); + } + Move.time = move(0, course, time, 0.095); + Ship.energy -= 20 + 100 * Move.time * 0.095; +} diff --git a/src/games/trek/initquad.c b/src/games/trek/initquad.c new file mode 100644 index 0000000..267cd4b --- /dev/null +++ b/src/games/trek/initquad.c @@ -0,0 +1,118 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +# include "trek.h" + +void +sector(x, y) + int *x, *y; +{ + register int i, j; + + do { + i = ranf(NSECTS); + j = ranf(NSECTS); + } while (Sect[i][j] != EMPTY); + *x = i; + *y = j; +} + +/* +** Paramize Quadrant Upon Entering +** +** A quadrant is initialized from the information held in the +** Quad matrix. Basically, everything is just initialized +** randomly, except for the starship, which goes into a fixed +** sector. +** +** If there are Klingons in the quadrant, the captain is informed +** that the condition is RED, and he is given a chance to put +** his shields up if the computer is working. +** +** The flag `f' is set to disable the check for condition red. +** This mode is used in situations where you know you are going +** to be docked, i.e., abandon() and help(). +*/ +void +initquad(f) + int f; +{ + register int i, j; + int rx, ry; + int nbases, nstars; + register struct quad *q; + int nholes; + + q = &Quad[Ship.quadx][Ship.quady]; + + /* ignored supernova'ed quadrants (this is checked again later anyway */ + if (q->stars < 0) + return; + Etc.nkling = q->klings; + nbases = q->bases; + nstars = q->stars; + nholes = q->holes; + + /* have we blundered into a battle zone w/ shields down? */ + if (Etc.nkling > 0 && !f) + { + printf("Condition RED\n"); + Ship.cond = RED; + if (!damaged(COMPUTER)) + shield(1); + } + + /* clear out the quadrant */ + for (i = 0; i < NSECTS; i++) + for (j = 0; j < NSECTS; j++) + Sect[i][j] = EMPTY; + + /* initialize Enterprise */ + Sect[Ship.sectx][Ship.secty] = Ship.ship; + + /* initialize Klingons */ + for (i = 0; i < Etc.nkling; i++) + { + sector(&rx, &ry); + Sect[rx][ry] = KLINGON; + Etc.klingon[i].x = rx; + Etc.klingon[i].y = ry; + Etc.klingon[i].power = Param.klingpwr; + Etc.klingon[i].srndreq = 0; + } + compkldist(1); + + /* initialize star base */ + if (nbases > 0) + { + sector(&rx, &ry); + Sect[rx][ry] = BASE; + Etc.starbase.x = rx; + Etc.starbase.y = ry; + } + + /* initialize inhabited starsystem */ + if (q->qsystemname != 0) + { + sector(&rx, &ry); + Sect[rx][ry] = INHABIT; + nstars -= 1; + } + + /* initialize black holes */ + for (i = 0; i < nholes; i++) + { + sector(&rx, &ry); + Sect[rx][ry] = HOLE; + } + + /* initialize stars */ + for (i = 0; i < nstars; i++) + { + sector(&rx, &ry); + Sect[rx][ry] = STAR; + } + Move.newquad = 1; +} diff --git a/src/games/trek/kill.c b/src/games/trek/kill.c new file mode 100644 index 0000000..e769272 --- /dev/null +++ b/src/games/trek/kill.c @@ -0,0 +1,192 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +# include "trek.h" +# include + +/* +** KILL KILL KILL !!! +** +** This file handles the killing off of almost anything. +*/ + +/* +** Handle a Klingon's death +** +** The Klingon at the sector given by the parameters is killed +** and removed from the Klingon list. Notice that it is not +** removed from the event list; this is done later, when the +** the event is to be caught. Also, the time left is recomputed, +** and the game is won if that was the last klingon. +*/ +void +killk(ix, iy) + int ix, iy; +{ + register int i; + + printf(" *** Klingon at %d,%d destroyed ***\n", ix, iy); + + /* remove the scoundrel */ + Now.klings -= 1; + Sect[ix][iy] = EMPTY; + Quad[Ship.quadx][Ship.quady].klings -= 1; + /* %%% IS THIS SAFE???? %%% */ + Quad[Ship.quadx][Ship.quady].scanned -= 100; + Game.killk += 1; + + /* find the Klingon in the Klingon list */ + for (i = 0; i < Etc.nkling; i++) + if (ix == Etc.klingon[i].x && iy == Etc.klingon[i].y) + { + /* purge him from the list */ + Etc.nkling -= 1; + for (; i < Etc.nkling; i++) + bmove(&Etc.klingon[i+1], &Etc.klingon[i], sizeof Etc.klingon[i]); + break; + } + + /* find out if that was the last one */ + if (Now.klings <= 0) + win(); + + /* recompute time left */ + Now.time = Now.resource / Now.klings; +} + + +/* +** handle a starbase's death +*/ +void +killb(qx, qy) + int qx, qy; +{ + register struct quad *q; + register struct xy *b; + + q = &Quad[qx][qy]; + + if (q->bases <= 0) + return; + if (!damaged(SSRADIO)) { + /* then update starchart */ + if (q->scanned < 1000) + q->scanned -= 10; + else if (q->scanned > 1000) + q->scanned = -1; + } + q->bases = 0; + Now.bases -= 1; + for (b = Now.base; ; b++) + if (qx == b->x && qy == b->y) + break; + bmove(&Now.base[(int)Now.bases], b, sizeof *b); + if (qx == Ship.quadx && qy == Ship.quady) + { + Sect[(int)Etc.starbase.x][(int)Etc.starbase.y] = EMPTY; + if (Ship.cond == DOCKED) + undock(); + printf("Starbase at %d,%d destroyed\n", Etc.starbase.x, Etc.starbase.y); + } + else + { + if (!damaged(SSRADIO)) + { + printf("Uhura: Starfleet command reports that the starbase in\n"); + printf(" quadrant %d,%d has been destroyed\n", qx, qy); + } + else + schedule(E_KATSB | E_GHOST, DBL_MAX, qx, qy, 0); + } +} + +/** + ** kill an inhabited starsystem + **/ +void +kills(x, y, f) + int x, y; /* quad coords if f == 0, else sector coords */ + int f; /* f != 0 -- this quad; f < 0 -- Enterprise's fault */ +{ + register struct quad *q; + register struct event *e; + register char *name; + + if (f) + { + /* current quadrant */ + q = &Quad[Ship.quadx][Ship.quady]; + Sect[x][y] = EMPTY; + name = systemname(q); + if (name == 0) + return; + printf("Inhabited starsystem %s at %d,%d destroyed\n", + name, x, y); + if (f < 0) + Game.killinhab += 1; + } + else + { + /* different quadrant */ + q = &Quad[x][y]; + } + if (q->qsystemname & Q_DISTRESSED) + { + /* distressed starsystem */ + e = &Event[q->qsystemname & Q_SYSTEM]; + printf("Distress call for %s invalidated\n", + Systemname[(int)e->systemname]); + unschedule(e); + } + q->qsystemname = 0; + q->stars -= 1; +} + +/** + ** "kill" a distress call + **/ +void +killd(x, y, f) + int x, y; /* quadrant coordinates */ + int f; /* set if user is to be informed */ +{ + register struct event *e; + register int i; + register struct quad *q; + + q = &Quad[x][y]; + for (i = 0; i < MAXEVENTS; i++) + { + e = &Event[i]; + if (e->x != x || e->y != y) + continue; + switch (e->evcode) + { + case E_KDESB: + if (f) + { + printf("Distress call for starbase in %d,%d nullified\n", + x, y); + unschedule(e); + } + break; + + case E_ENSLV: + case E_REPRO: + if (f) + { + printf("Distress call for %s in quadrant %d,%d nullified\n", + Systemname[(int)e->systemname], x, y); + q->qsystemname = e->systemname; + unschedule(e); + } + else + { + e->evcode |= E_GHOST; + } + } + } +} diff --git a/src/games/trek/klmove.c b/src/games/trek/klmove.c new file mode 100644 index 0000000..88d2bdb --- /dev/null +++ b/src/games/trek/klmove.c @@ -0,0 +1,152 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +# include "trek.h" + +/* +** Move Klingons Around +** +** This is a largely incomprehensible block of code that moves +** Klingons around in a quadrant. It was written in a very +** "program as you go" fashion, and is a prime candidate for +** rewriting. +** +** The flag `fl' is zero before an attack, one after an attack, +** and two if you are leaving a quadrant. This serves to +** change the probability and distance that it moves. +** +** Basically, what it will try to do is to move a certain number +** of steps either toward you or away from you. It will avoid +** stars whenever possible. Nextx and nexty are the next +** sector to move to on a per-Klingon basis; they are roughly +** equivalent to Ship.sectx and Ship.secty for the starship. Lookx and +** looky are the sector that you are going to look at to see +** if you can move their. Dx and dy are the increment. Fudgex +** and fudgey are the things you change around to change your +** course around stars. +*/ +void +klmove(fl) + int fl; +{ + int n; + register struct kling *k; + double dx, dy; + int nextx, nexty; + register int lookx, looky; + int motion; + int fudgex, fudgey; + int qx, qy; + double bigger; + int i; + +# ifdef xTRACE + if (Trace) + printf("klmove: fl = %d, Etc.nkling = %d\n", fl, Etc.nkling); +# endif + for (n = 0; n < Etc.nkling; n+=k?1:0) + { + k = &Etc.klingon[n]; + i = 100; + if (fl) + i = 100.0 * k->power / Param.klingpwr; + if (ranf(i) >= Param.moveprob[2 * Move.newquad + fl]) + continue; + /* compute distance to move */ + motion = ranf(75) - 25; + motion *= k->avgdist * Param.movefac[2 * Move.newquad + fl]; + /* compute direction */ + dx = Ship.sectx - k->x + ranf(3) - 1; + dy = Ship.secty - k->y + ranf(3) - 1; + bigger = dx; + if (dy > bigger) + bigger = dy; + if (bigger == 0.0) + bigger = 1.0; + dx = dx / bigger + 0.5; + dy = dy / bigger + 0.5; + if (motion < 0) + { + motion = -motion; + dx = -dx; + dy = -dy; + } + fudgex = fudgey = 1; + /* try to move the klingon */ + nextx = k->x; + nexty = k->y; + for (; motion > 0; motion--) + { + lookx = nextx + dx; + looky = nexty + dy; + if (lookx < 0 || lookx >= NSECTS || looky < 0 || looky >= NSECTS) + { + /* new quadrant */ + qx = Ship.quadx; + qy = Ship.quady; + if (lookx < 0) + qx -= 1; + else + if (lookx >= NSECTS) + qx += 1; + if (looky < 0) + qy -= 1; + else + if (looky >= NSECTS) + qy += 1; + if (qx < 0 || qx >= NQUADS || qy < 0 || qy >= NQUADS || + Quad[qx][qy].stars < 0 || Quad[qx][qy].klings > MAXKLQUAD - 1) + break; + if (!damaged(SRSCAN)) + { + printf("Klingon at %d,%d escapes to quadrant %d,%d\n", + k->x, k->y, qx, qy); + motion = Quad[qx][qy].scanned; + if (motion >= 0 && motion < 1000) + Quad[qx][qy].scanned += 100; + motion = Quad[Ship.quadx][Ship.quady].scanned; + if (motion >= 0 && motion < 1000) + Quad[Ship.quadx][Ship.quady].scanned -= 100; + } + Sect[(int)k->x][(int)k->y] = EMPTY; + Quad[qx][qy].klings += 1; + Etc.nkling -= 1; + bmove(&Etc.klingon[(int)Etc.nkling], k, sizeof *k); + Quad[Ship.quadx][Ship.quady].klings -= 1; + k = 0; + break; + } + if (Sect[lookx][looky] != EMPTY) + { + lookx = nextx + fudgex; + if (lookx < 0 || lookx >= NSECTS) + lookx = nextx + dx; + if (Sect[lookx][looky] != EMPTY) + { + fudgex = -fudgex; + looky = nexty + fudgey; + if (looky < 0 || looky >= NSECTS || Sect[lookx][looky] != EMPTY) + { + fudgey = -fudgey; + break; + } + } + } + nextx = lookx; + nexty = looky; + } + if (k && (k->x != nextx || k->y != nexty)) + { + if (!damaged(SRSCAN)) + printf("Klingon at %d,%d moves to %d,%d\n", + k->x, k->y, nextx, nexty); + Sect[(int)k->x][(int)k->y] = EMPTY; + k->x = nextx; + k->y = nexty; + Sect[(int)k->x][(int)k->y] = KLINGON; + } + } + compkldist(0); +} diff --git a/src/games/trek/lose.c b/src/games/trek/lose.c new file mode 100644 index 0000000..ec69782 --- /dev/null +++ b/src/games/trek/lose.c @@ -0,0 +1,54 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +# include "trek.h" +# include + +/* +** PRINT OUT LOSER MESSAGES +** +** The messages are printed out, the score is computed and +** printed, and the game is restarted. Oh yeh, any special +** actions which need be taken are taken. +*/ + +char *Losemsg[] = +{ + "You ran out of time", + "You ran out of energy", + "You have been destroyed", + "You ran into the negative energy barrier", + "You destroyed yourself by nova'ing that star", + "You have been caught in a supernova", + "You just suffocated in outer space", + "You could not be rematerialized", + "\n\032\014 *** Ship's hull has imploded ***", + "You have burned up in a star", + "Well, you destroyed yourself, but it didn't do any good", + "You have been captured by Klingons and mercilessly tortured", + "Your last crew member died", +}; + +void +lose(why) + int why; +{ + extern jmp_buf env; + + Game.killed = 1; + sleep(1); + printf("\n%s\n", Losemsg[why - 1]); + switch (why) + { + + case L_NOTIME: + Game.killed = 0; + break; + } + Move.endgame = -1; + score(); + skiptonl(0); + longjmp(env, 1); +} diff --git a/src/games/trek/lrscan.c b/src/games/trek/lrscan.c new file mode 100644 index 0000000..ad82352 --- /dev/null +++ b/src/games/trek/lrscan.c @@ -0,0 +1,74 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +# include "trek.h" + +/* +** LONG RANGE OF SCANNERS +** +** A summary of the quadrants that surround you is printed. The +** hundreds digit is the number of Klingons in the quadrant, +** the tens digit is the number of starbases, and the units digit +** is the number of stars. If the printout is "///" it means +** that that quadrant is rendered uninhabitable by a supernova. +** It also updates the "scanned" field of the quadrants it scans, +** for future use by the "chart" option of the computer. +*/ +void +lrscan() +{ + register int i, j; + register struct quad *q; + + if (check_out(LRSCAN)) + { + return; + } + printf("Long range scan for quadrant %d,%d\n\n", Ship.quadx, Ship.quady); + + /* print the header on top */ + for (j = Ship.quady - 1; j <= Ship.quady + 1; j++) + { + if (j < 0 || j >= NQUADS) + printf(" "); + else + printf(" %1d", j); + } + + /* scan the quadrants */ + for (i = Ship.quadx - 1; i <= Ship.quadx + 1; i++) + { + printf("\n -------------------\n"); + if (i < 0 || i >= NQUADS) + { + /* negative energy barrier */ + printf(" ! * ! * ! * !"); + continue; + } + + /* print the left hand margin */ + printf("%1d !", i); + for (j = Ship.quady - 1; j <= Ship.quady + 1; j++) + { + if (j < 0 || j >= NQUADS) + { + /* negative energy barrier again */ + printf(" * !"); + continue; + } + q = &Quad[i][j]; + if (q->stars < 0) + { + /* supernova */ + printf(" /// !"); + q->scanned = 1000; + continue; + } + q->scanned = q->klings * 100 + q->bases * 10 + q->stars; + printf(" %3d !", q->scanned); + } + } + printf("\n -------------------\n"); +} diff --git a/src/games/trek/main.c b/src/games/trek/main.c new file mode 100644 index 0000000..b9bec06 --- /dev/null +++ b/src/games/trek/main.c @@ -0,0 +1,202 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +# include "trek.h" +# include "getpar.h" +# include +# include +# include +# include +# include + +# define PRIO 00 /* default priority */ + +int Mother = 51 + (51 << 8); + +/* +** #### ##### # #### ##### #### ##### # # +** # # # # # # # # # # # # +** ### # ##### #### # #### ### ### +** # # # # # # # # # # # # +** #### # # # # # # # # ##### # # +** +** C version by Eric P. Allman 5/76 (U.C. Berkeley) with help +** from Jeff Poskanzer and Pete Rubinstein. +** +** I also want to thank everyone here at Berkeley who +** where crazy enough to play the undebugged game. I want to +** particularly thank Nick Whyte, who made considerable +** suggestions regarding the content of the game. Why, I'll +** never forget the time he suggested the name for the +** "capture" command. +** +** Please send comments, questions, and suggestions about this +** game to: +** Eric P. Allman +** Project INGRES +** Electronics Research Laboratory +** Cory Hall +** University of California +** Berkeley, California 94720 +** +** If you make ANY changes in the game, I sure would like to +** know about them. It is sort of an ongoing project for me, +** and I very much want to put in any bug fixes and improvements +** that you might come up with. +** +** FORTRASH version by Kay R. Fisher (DEC) "and countless others". +** That was adapted from the "original BASIC program" (ha!) by +** Mike Mayfield (Centerline Engineering). +** +** Additional inspiration taken from FORTRAN version by +** David Matuszek and Paul Reynolds which runs on the CDC +** 7600 at Lawrence Berkeley Lab, maintained there by +** Andy Davidson. This version is also available at LLL +** and at LMSC. In all fairness, this version was the +** major inspiration for this version of the game (trans- +** lation: I ripped off a whole lot of code). +** +** Minor other input from the "Battelle Version 7A" by Joe Miller +** (Graphics Systems Group, Battelle-Columbus Labs) and +** Ross Pavlac (Systems Programmer, Battelle Memorial +** Institute). That version was written in December '74 +** and extensively modified June '75. It was adapted +** from the FTN version by Ron Williams of CDC Sunnyvale, +** which was adapted from the Basic version distributed +** by DEC. It also had "neat stuff swiped" from T. T. +** Terry and Jim Korp (University of Texas), Hicks (Penn +** U.), and Rick Maus (Georgia Tech). Unfortunately, it +** was not as readable as it could have been and so the +** translation effort was severely hampered. None the +** less, I got the idea of inhabited starsystems from this +** version. +** +** Permission is given for use, copying, and modification of +** all or part of this program and related documentation, +** provided that all reference to the authors are maintained. +** +** +********************************************************************** +** +** NOTES TO THE MAINTAINER: +** +** There is a compilation option xTRACE which must be set for any +** trace information to be generated. It is probably defined in +** the version that you get. It can be removed, however, if you +** have trouble finding room in core. +** +** Many things in trek are not as clear as they might be, but are +** done to reduce space. I compile with the -f and -O flags. I +** am constrained to running with non-seperated I/D space, since +** we don't have doubleing point hardware here; even if we did, I +** would like trek to be available to the large number of people +** who either have an 11/40 or do not have FP hardware. I also +** found it desirable to make the code run reentrant, so this +** added even more space constraints. +** +** I use the portable C library to do my I/O. This is done be- +** cause I wanted the game easily transportable to other C +** implementations, and because I was too lazy to do the doubleing +** point input myself. Little did I know. The portable C library +** released by Bell Labs has more bugs than you would believe, so +** I ended up rewriting the whole blessed thing. Trek excercises +** many of the bugs in it, as well as bugs in some of the section +** III UNIX routines. We have fixed them here. One main problem +** was a bug in alloc() that caused it to always ask for a large +** hunk of memory, which worked fine unless you were almost out, +** which I inevitably was. If you want the code for all of this +** stuff, it is also available through me. +** +*********************************************************************** +*/ + +jmp_buf env; + +int +main(argc, argv) + int argc; + char **argv; +{ + long vect; + /* extern FILE *f_log; */ + register char opencode; + int prio; + register int ac; + register char **av; + struct sgttyb argp; + + av = argv; + ac = argc; + av++; + time(&vect); + srand(vect); + opencode = 'w'; + prio = PRIO; + if (ioctl(1, TIOCGETP, &argp) == 0) + { + if ((argp.sg_ispeed ) < B1200) + Etc.fast++; + } + while (ac > 1 && av[0][0] == '-') + { + switch (av[0][1]) + { + case 'a': /* append to log file */ + opencode = 'a'; + break; + + case 'f': /* set fast mode */ + Etc.fast++; + break; + + case 's': /* set slow mode */ + Etc.fast = 0; + break; + +# ifdef xTRACE + case 't': /* trace */ + if (getuid() != Mother) + goto badflag; + Trace++; + break; +# endif + + case 'p': /* set priority */ + if (getuid() != Mother) + goto badflag; + if (sscanf(&av[0][2], "%d", &prio) > 0) + break; + + default: + badflag: + printf("Invalid option: %s\n", av[0]); + + } + ac--; + av++; + } + if (ac > 2) + syserr(0, "arg count"); + /* + if (ac > 1) + f_log = fopen(av[0], opencode); + */ + + printf("\n * * * S T A R T R E K * * *\n\nPress return to continue.\n"); + + if (setjmp(env)) + { + if ( !getynpar("Another game") ) + exit(0); + } + do + { + setup(); + play(); + } while (getynpar("Another game")); + + fflush(stdout); + return 0; +} diff --git a/src/games/trek/move.c b/src/games/trek/move.c new file mode 100644 index 0000000..b848f02 --- /dev/null +++ b/src/games/trek/move.c @@ -0,0 +1,199 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +# include "trek.h" +# include + +/* +** Move Under Warp or Impulse Power +** +** `Ramflag' is set if we are to be allowed to ram stars, +** Klingons, etc. This is passed from warp(), which gets it from +** either play() or ram(). Course is the course (0 -> 360) at +** which we want to move. `Speed' is the speed we +** want to go, and `time' is the expected time. It +** can get cut short if a long range tractor beam is to occur. We +** cut short the move so that the user doesn't get docked time and +** energy for distance which he didn't travel. +** +** We check the course through the current quadrant to see that he +** doesn't run into anything. After that, though, space sort of +** bends around him. Note that this puts us in the awkward posi- +** tion of being able to be dropped into a sector which is com- +** pletely surrounded by stars. Oh Well. +** +** If the SINS (Space Inertial Navigation System) is out, we ran- +** domize the course accordingly before ever starting to move. +** We will still move in a straight line. +** +** Note that if your computer is out, you ram things anyway. In +** other words, if your computer and sins are both out, you're in +** potentially very bad shape. +** +** Klingons get a chance to zap you as you leave the quadrant. +** By the way, they also try to follow you (heh heh). +** +** Return value is the actual amount of time used. +** +** +** Uses trace flag 4. +*/ +double +move(ramflag, course, time, speed) + int ramflag; + int course; + double time; + double speed; +{ + double angle; + double x, y, dx, dy; + register int ix, iy; + double bigger; + int n; + register int i; + double dist; + double sectsize; + double xn; + double evtime; + +# ifdef xTRACE + if (Trace) + printf("move: ramflag %d course %d time %.2f speed %.2f\n", + ramflag, course, time, speed); +# endif + sectsize = NSECTS; + /* initialize delta factors for move */ + angle = course * 0.0174532925; + if (damaged(SINS)) + angle += Param.navigcrud[1] * (franf() - 0.5); + else + if (Ship.sinsbad) + angle += Param.navigcrud[0] * (franf() - 0.5); + dx = -cos(angle); + dy = sin(angle); + bigger = fabs(dx); + dist = fabs(dy); + if (dist > bigger) + bigger = dist; + dx /= bigger; + dy /= bigger; + + /* check for long range tractor beams */ + /**** TEMPORARY CODE == DEBUGGING ****/ + evtime = Now.eventptr[E_LRTB]->date - Now.date; +# ifdef xTRACE + if (Trace) + printf("E.ep = %p, ->evcode = %d, ->date = %.2f, evtime = %.2f\n", + Now.eventptr[E_LRTB], Now.eventptr[E_LRTB]->evcode, + Now.eventptr[E_LRTB]->date, evtime); +# endif + if (time > evtime && Etc.nkling < 3) + { + /* then we got a LRTB */ + evtime += 0.005; + time = evtime; + } + else + evtime = -DBL_MAX; + dist = time * speed; + + /* move within quadrant */ + Sect[Ship.sectx][Ship.secty] = EMPTY; + x = Ship.sectx + 0.5; + y = Ship.secty + 0.5; + xn = NSECTS * dist * bigger; + n = xn + 0.5; +# ifdef xTRACE + if (Trace) + printf("dx = %.2f, dy = %.2f, xn = %.2f, n = %d\n", dx, dy, xn, n); +# endif + Move.free = 0; + + ix = iy = 0; + for (i = 0; i < n; i++) + { + ix = (x += dx); + iy = (y += dy); +# ifdef xTRACE + if (Trace) + printf("ix = %d, x = %.2f, iy = %d, y = %.2f\n", ix, x, iy, y); +# endif + if (x < 0.0 || y < 0.0 || x >= sectsize || y >= sectsize) + { + /* enter new quadrant */ + dx = Ship.quadx * NSECTS + Ship.sectx + dx * xn; + dy = Ship.quady * NSECTS + Ship.secty + dy * xn; + if (dx < 0.0) + ix = -1; + else + ix = dx + 0.5; + if (dy < 0.0) + iy = -1; + else + iy = dy + 0.5; +# ifdef xTRACE + if (Trace) + printf("New quad: ix = %d, iy = %d\n", ix, iy); +# endif + Ship.sectx = x; + Ship.secty = y; + compkldist(0); + Move.newquad = 2; + attack(0); + checkcond(); + Ship.quadx = ix / NSECTS; + Ship.quady = iy / NSECTS; + Ship.sectx = ix % NSECTS; + Ship.secty = iy % NSECTS; + if (ix < 0 || Ship.quadx >= NQUADS || iy < 0 || Ship.quady >= NQUADS) { + if (! damaged(COMPUTER)) { + dumpme(0); + } else + lose(L_NEGENB); + } + initquad(0); + n = 0; + break; + } + if (Sect[ix][iy] != EMPTY) + { + /* we just hit something */ + if (!damaged(COMPUTER) && ramflag <= 0) + { + ix = x - dx; + iy = y - dy; + printf("Computer reports navigation error; %s stopped at %d,%d\n", + Ship.shipname, ix, iy); + Ship.energy -= Param.stopengy * speed; + break; + } + /* test for a black hole */ + if (Sect[ix][iy] == HOLE) + { + /* get dumped elsewhere in the galaxy */ + dumpme(1); + initquad(0); + n = 0; + break; + } + ram(ix, iy); + break; + } + } + if (n > 0) + { + dx = Ship.sectx - ix; + dy = Ship.secty - iy; + dist = sqrt(dx * dx + dy * dy) / NSECTS; + time = dist / speed; + if (evtime > time) + time = evtime; /* spring the LRTB trap */ + Ship.sectx = ix; + Ship.secty = iy; + } + Sect[Ship.sectx][Ship.secty] = Ship.ship; + compkldist(0); + return (time); +} diff --git a/src/games/trek/nova.c b/src/games/trek/nova.c new file mode 100644 index 0000000..cd31a93 --- /dev/null +++ b/src/games/trek/nova.c @@ -0,0 +1,108 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +# include "trek.h" + +/* +** CAUSE A NOVA TO OCCUR +** +** A nova occurs. It is the result of having a star hit with +** a photon torpedo. There are several things which may happen. +** The star may not be affected. It may go nova. It may turn +** into a black hole. Any (yummy) it may go supernova. +** +** Stars that go nova cause stars which surround them to undergo +** the same probabilistic process. Klingons next to them are +** destroyed. And if the starship is next to it, it gets zapped. +** If the zap is too much, it gets destroyed. +*/ +void +nova(x, y) + int x, y; +{ + register int i, j; + register int se; + + if (Sect[x][y] != STAR || Quad[Ship.quadx][Ship.quady].stars < 0) + return; + if (ranf(100) < 15) + { + printf("Spock: Star at %d,%d failed to nova.\n", x, y); + return; + } + if (ranf(100) < 5) { + snova(x, y); + return; + } + printf("Spock: Star at %d,%d gone nova\n", x, y); + + if (ranf(4) != 0) + Sect[x][y] = EMPTY; + else + { + Sect[x][y] = HOLE; + Quad[Ship.quadx][Ship.quady].holes += 1; + } + Quad[Ship.quadx][Ship.quady].stars -= 1; + Game.kills += 1; + for (i = x - 1; i <= x + 1; i++) + { + if (i < 0 || i >= NSECTS) + continue; + for (j = y - 1; j <= y + 1; j++) + { + if (j < 0 || j >= NSECTS) + continue; + se = Sect[i][j]; + switch (se) + { + + case EMPTY: + case HOLE: + break; + + case KLINGON: + killk(i, j); + break; + + case STAR: + nova(i, j); + break; + + case INHABIT: + kills(i, j, -1); + break; + + case BASE: + killb(i, j); + Game.killb += 1; + break; + + case ENTERPRISE: + case QUEENE: + se = 2000; + if (Ship.shldup) { + if (Ship.shield >= se) { + Ship.shield -= se; + se = 0; + } else { + se -= Ship.shield; + Ship.shield = 0; + } + } + Ship.energy -= se; + if (Ship.energy <= 0) + lose(L_SUICID); + break; + + default: + printf("Unknown object %c at %d,%d destroyed\n", + se, i, j); + Sect[i][j] = EMPTY; + break; + } + } + } +} diff --git a/src/games/trek/out.c b/src/games/trek/out.c new file mode 100644 index 0000000..becbabc --- /dev/null +++ b/src/games/trek/out.c @@ -0,0 +1,24 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +# include "trek.h" + +/* +** Announce Device Out +*/ +void +out(dev) + int dev; +{ + register struct device *d; + + d = &Device[dev]; + printf("%s reports %s ", d->person, d->name); + if (d->name[length(d->name) - 1] == 's') + printf("are"); + else + printf("is"); + printf(" damaged\n"); +} diff --git a/src/games/trek/phaser.c b/src/games/trek/phaser.c new file mode 100644 index 0000000..251eab6 --- /dev/null +++ b/src/games/trek/phaser.c @@ -0,0 +1,344 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +# include "trek.h" +# include "getpar.h" + +/* factors for phaser hits; see description below */ + +# define ALPHA 3.0 /* spread */ +# define BETA 3.0 /* franf() */ +# define GAMMA 0.30 /* cos(angle) */ +# define EPSILON 150.0 /* dist ** 2 */ +# define OMEGA 10.596 /* overall scaling factor */ + +/* OMEGA ~= 100 * (ALPHA + 1) * (BETA + 1) / (EPSILON + 1) */ + +/* +** Phaser Control +** +** There are up to NBANKS phaser banks which may be fired +** simultaneously. There are two modes, "manual" and +** "automatic". In manual mode, you specify exactly which +** direction you want each bank to be aimed, the number +** of units to fire, and the spread angle. In automatic +** mode, you give only the total number of units to fire. +** +** The spread is specified as a number between zero and +** one, with zero being minimum spread and one being maximum +** spread. You will normally want zero spread, unless your +** short range scanners are out, in which case you probably +** don't know exactly where the Klingons are. In that case, +** you really don't have any choice except to specify a +** fairly large spread. +** +** Phasers spread slightly, even if you specify zero spread. +** +** Uses trace flag 30 +*/ + +struct cvntab Matab[] = +{ + { "m", "anual", (void (*)())1, 0 }, + { "a", "utomatic", 0, 0 }, + { 0 }, +}; + +struct banks +{ + int units; + double angle; + double spread; +}; + +void +phaser() +{ + register int i; + int j; + register struct kling *k; + double dx, dy; + double anglefactor, distfactor; + register struct banks *b; + int manual, flag, extra; + int hit; + double tot; + int n; + int hitreqd[NBANKS]; + struct banks bank[NBANKS]; + struct cvntab *ptr; + + if (Ship.cond == DOCKED) { + printf("Phasers cannot fire through starbase shields\n"); + return; + } + if (damaged(PHASER)) { + out(PHASER); + return; + } + if (Ship.shldup) { + printf("Sulu: Captain, we cannot fire through shields.\n"); + return; + } + if (Ship.cloaked) + { + printf("Sulu: Captain, surely you must realize that we cannot fire\n"); + printf(" phasers with the cloaking device up.\n"); + return; + } + + /* decide if we want manual or automatic mode */ + manual = 0; + if (testnl()) + { + if (damaged(COMPUTER)) + { + printf("%s", Device[COMPUTER].name); + manual++; + } + else + if (damaged(SRSCAN)) + { + printf("%s", Device[SRSCAN].name); + manual++; + } + if (manual) + printf(" damaged, manual mode selected\n"); + } + + if (!manual) + { + ptr = getcodpar("Manual or automatic", Matab); + manual = (int) ptr->value; + } + if (!manual && damaged(COMPUTER)) + { + printf("Computer damaged, manual selected\n"); + skiptonl(0); + manual++; + } + + /* initialize the bank[] array */ + flag = 1; + for (i = 0; i < NBANKS; i++) + bank[i].units = 0; + if (manual) + { + /* collect manual mode statistics */ + while (flag) + { + printf("%d units available\n", Ship.energy); + extra = 0; + flag = 0; + for (i = 0; i < NBANKS; i++) + { + b = &bank[i]; + printf("\nBank %d:\n", i); + hit = getintpar("units"); + if (hit < 0) + return; + if (hit == 0) + break; + extra += hit; + if (extra > Ship.energy) + { + printf("available energy exceeded. "); + skiptonl(0); + flag++; + break; + } + b->units = hit; + hit = getintpar("course"); + if (hit < 0 || hit > 360) + return; + b->angle = hit * 0.0174532925; + b->spread = getfltpar("spread"); + if (b->spread < 0 || b->spread > 1) + return; + } + Ship.energy -= extra; + } + extra = 0; + } + else + { + /* automatic distribution of power */ + if (Etc.nkling <= 0) { + printf("Sulu: But there are no Klingons in this quadrant\n"); + return; + } + printf("Phasers locked on target. "); + while (flag) + { + printf("%d units available\n", Ship.energy); + hit = getintpar("Units to fire"); + if (hit <= 0) + return; + if (hit > Ship.energy) + { + printf("available energy exceeded. "); + skiptonl(0); + continue; + } + flag = 0; + Ship.energy -= hit; + extra = hit; + n = Etc.nkling; + if (n > NBANKS) + n = NBANKS; + tot = n * (n + 1) / 2; + for (i = 0; i < n; i++) + { + k = &Etc.klingon[i]; + b = &bank[i]; + distfactor = k->dist; + anglefactor = ALPHA * BETA * OMEGA / (distfactor * distfactor + EPSILON); + anglefactor *= GAMMA; + distfactor = k->power; + distfactor /= anglefactor; + hitreqd[i] = distfactor + 0.5; + dx = Ship.sectx - k->x; + dy = k->y - Ship.secty; + b->angle = atan2(dy, dx); + b->spread = 0.0; + b->units = ((n - i) / tot) * extra; +# ifdef xTRACE + if (Trace) + { + printf("b%d hr%d u%d df%.2f af%.2f\n", + i, hitreqd[i], b->units, + distfactor, anglefactor); + } +# endif + extra -= b->units; + hit = b->units - hitreqd[i]; + if (hit > 0) + { + extra += hit; + b->units -= hit; + } + } + + /* give out any extra energy we might have around */ + if (extra > 0) + { + for (i = 0; i < n; i++) + { + b = &bank[i]; + hit = hitreqd[i] - b->units; + if (hit <= 0) + continue; + if (hit >= extra) + { + b->units += extra; + extra = 0; + break; + } + b->units = hitreqd[i]; + extra -= hit; + } + if (extra > 0) + printf("%d units overkill\n", extra); + } + } + } + +# ifdef xTRACE + if (Trace) + { + for (i = 0; i < NBANKS; i++) + { + b = &bank[i]; + printf("b%d u%d", i, b->units); + if (b->units > 0) + printf(" a%.2f s%.2f\n", b->angle, b->spread); + else + printf("\n"); + } + } +# endif + + /* actually fire the shots */ + Move.free = 0; + for (i = 0; i < NBANKS; i++) + { + b = &bank[i]; + if (b->units <= 0) + { + continue; + } + printf("\nPhaser bank %d fires:\n", i); + n = Etc.nkling; + k = Etc.klingon; + for (j = 0; j < n; j++) + { + if (b->units <= 0) + break; + /* + ** The formula for hit is as follows: + ** + ** zap = OMEGA * [(sigma + ALPHA) * (rho + BETA)] + ** / (dist ** 2 + EPSILON)] + ** * [cos(delta * sigma) + GAMMA] + ** * hit + ** + ** where sigma is the spread factor, + ** rho is a random number (0 -> 1), + ** GAMMA is a crud factor for angle (essentially + ** cruds up the spread factor), + ** delta is the difference in radians between the + ** angle you are shooting at and the actual + ** angle of the klingon, + ** ALPHA scales down the significance of sigma, + ** BETA scales down the significance of rho, + ** OMEGA is the magic number which makes everything + ** up to "* hit" between zero and one, + ** dist is the distance to the klingon + ** hit is the number of units in the bank, and + ** zap is the amount of the actual hit. + ** + ** Everything up through dist squared should maximize + ** at 1.0, so that the distance factor is never + ** greater than one. Conveniently, cos() is + ** never greater than one, but the same restric- + ** tion applies. + */ + distfactor = BETA + franf(); + distfactor *= ALPHA + b->spread; + distfactor *= OMEGA; + anglefactor = k->dist; + distfactor /= anglefactor * anglefactor + EPSILON; + distfactor *= b->units; + dx = Ship.sectx - k->x; + dy = k->y - Ship.secty; + anglefactor = atan2(dy, dx) - b->angle; + anglefactor = cos((anglefactor * b->spread) + GAMMA); + if (anglefactor < 0.0) + { + k++; + continue; + } + hit = anglefactor * distfactor + 0.5; + k->power -= hit; + printf("%d unit hit on Klingon", hit); + if (!damaged(SRSCAN)) + printf(" at %d,%d", k->x, k->y); + printf("\n"); + b->units -= hit; + if (k->power <= 0) + { + killk(k->x, k->y); + continue; + } + k++; + } + } + + /* compute overkill */ + for (i = 0; i < NBANKS; i++) + extra += bank[i].units; + if (extra > 0) + printf("\n%d units expended on empty space\n", extra); +} diff --git a/src/games/trek/play.c b/src/games/trek/play.c new file mode 100644 index 0000000..1bed9f9 --- /dev/null +++ b/src/games/trek/play.c @@ -0,0 +1,81 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +# include "trek.h" +# include "getpar.h" +# include + +/* +** INSTRUCTION READ AND MAIN PLAY LOOP +** +** Well folks, this is it. Here we have the guts of the game. +** This routine executes moves. It sets up per-move variables, +** gets the command, and executes the command. After the command, +** it calls events() to use up time, attack() to have Klingons +** attack if the move was not free, and checkcond() to check up +** on how we are doing after the move. +*/ +extern void abandon(), capture(), shield(), computer(), dcrept(), + destruct(), dock(), help(), impulse(), lrscan(), + warp(), dumpgame(), rest(), shell(), srscan(), + myreset(), torped(), visual(), setwarp(), undock(), phaser(); + +struct cvntab Comtab[] = +{ + { "abandon", "", abandon, 0 }, + { "ca", "pture", capture, 0 }, + { "cl", "oak", shield, -1 }, + { "c", "omputer", computer, 0 }, + { "da", "mages", dcrept, 0 }, + { "destruct", "", destruct, 0 }, + { "do", "ck", dock, 0 }, + { "help", "", help, 0 }, + { "i", "mpulse", impulse, 0 }, + { "l", "rscan", lrscan, 0 }, + { "m", "ove", warp, 0 }, + { "p", "hasers", phaser, 0 }, + { "ram", "", warp, 1 }, + { "dump", "", dumpgame, 0 }, + { "r", "est", rest, 0 }, + { "shell", "", shell, 0 }, + { "sh", "ield", shield, 0 }, + { "s", "rscan", srscan, 0 }, + { "st", "atus", srscan, -1 }, + { "terminate", "", myreset, 0 }, + { "t", "orpedo", torped, 0 }, + { "u", "ndock", undock, 0 }, + { "v", "isual", visual, 0 }, + { "w", "arp", setwarp, 0 }, + { 0 }, +}; + +void +myreset() +{ + extern jmp_buf env; + + longjmp(env, 1); +} + +void +play() +{ + struct cvntab *r; + + while (1) + { + Move.free = 1; + Move.time = 0.0; + Move.shldchg = 0; + Move.newquad = 0; + Move.resting = 0; + skiptonl(0); + r = getcodpar("\nCommand", Comtab); + (*r->value)(r->value2); + events(0); + attack(0); + checkcond(); + } +} diff --git a/src/games/trek/ram.c b/src/games/trek/ram.c new file mode 100644 index 0000000..246830e --- /dev/null +++ b/src/games/trek/ram.c @@ -0,0 +1,69 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +# include "trek.h" + +/* +** RAM SOME OBJECT +** +** You have run into some sort of object. It may be a Klingon, +** a star, or a starbase. If you run into a star, you are really +** stupid, because there is no hope for you. +** +** If you run into something else, you destroy that object. You +** also rack up incredible damages. +*/ +void +ram(ix, iy) + int ix, iy; +{ + register int i; + register char c; + + printf("RED ALERT: collision imminent\n"); + c = Sect[ix][iy]; + switch (c) + { + + case KLINGON: + printf("%s rams Klingon at %d,%d\n", Ship.shipname, ix, iy); + killk(ix, iy); + break; + + case STAR: + case INHABIT: + printf("Yeoman Rand: Captain, isn't it getting hot in here?\n"); + sleep(2); + printf("Spock: Hull temperature approaching 550 Degrees Kelvin.\n"); + lose(L_STAR); + + case BASE: + printf("You ran into the starbase at %d,%d\n", ix, iy); + killb(Ship.quadx, Ship.quady); + /* don't penalize the captain if it wasn't his fault */ + if (!damaged(SINS)) + Game.killb += 1; + break; + } + sleep(2); + printf("%s heavily damaged\n", Ship.shipname); + + /* select the number of deaths to occur */ + i = 10 + ranf(20 * Game.skill); + Game.deaths += i; + Ship.crew -= i; + printf("McCoy: Take it easy Jim; we had %d casualties.\n", i); + + /* damage devices with an 80% probability */ + for (i = 0; i < NDEV; i++) + { + if (ranf(100) < 20) + continue; + damage(i, (2.5 * (franf() + franf()) + 1.0) * Param.damfac[i]); + } + + /* no chance that your shields remained up in all that */ + Ship.shldup = 0; +} diff --git a/src/games/trek/ranf.c b/src/games/trek/ranf.c new file mode 100644 index 0000000..ebb2dd2 --- /dev/null +++ b/src/games/trek/ranf.c @@ -0,0 +1,27 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +# include +# include "trek.h" + +int +ranf(max) + int max; +{ + register int t; + + if (max <= 0) + return (0); + t = rand() >> 5; + return (t % max); +} + +double +franf() +{ + double t; + t = rand() & 077777; + return (t / 32767.0); +} diff --git a/src/games/trek/rest.c b/src/games/trek/rest.c new file mode 100644 index 0000000..4fd9f0d --- /dev/null +++ b/src/games/trek/rest.c @@ -0,0 +1,48 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +# include "trek.h" +# include "getpar.h" + +/* +** REST FOR REPAIRS +** +** You sit around and wait for repairs to happen. Actually, you +** sit around and wait for anything to happen. I do want to point +** out however, that Klingons are not as patient as you are, and +** they tend to attack you while you are resting. +** +** You can never rest through a long range tractor beam. +** +** In events() you will be given an opportunity to cancel the +** rest period if anything momentous happens. +*/ +void +rest() +{ + double t; + register int percent; + + /* get the time to rest */ + t = getfltpar("How long"); + if (t <= 0.0) + return; + percent = 100 * t / Now.time + 0.5; + if (percent >= 70) + { + printf("Spock: That would take %d%% of our remaining time.\n", + percent); + if (!getynpar("Are you really certain that is wise")) + return; + } + Move.time = t; + + /* boundary condition is the LRTB */ + t = Now.eventptr[E_LRTB]->date - Now.date; + if (Ship.cond != DOCKED && Move.time > t) + Move.time = t + 0.0001; + Move.free = 0; + Move.resting = 1; +} diff --git a/src/games/trek/schedule.c b/src/games/trek/schedule.c new file mode 100644 index 0000000..79ca80f --- /dev/null +++ b/src/games/trek/schedule.c @@ -0,0 +1,141 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +# include "trek.h" +# include + +/* +** SCHEDULE AN EVENT +** +** An event of type 'type' is scheduled for time NOW + 'offset' +** into the first available slot. 'x', 'y', and 'z' are +** considered the attributes for this event. +** +** The address of the slot is returned. +*/ +struct event * +schedule(type, offset, x, y, z) + int type; + double offset; + int x, y; + int z; +{ + register struct event *e; + register int i; + double date; + + date = Now.date + offset; + for (i = 0; i < MAXEVENTS; i++) + { + e = &Event[i]; + if (e->evcode) + continue; + /* got a slot */ +# ifdef xTRACE + if (Trace) + printf("schedule: type %d @ %.2f slot %d parm %d %d %d\n", + type, date, i, x, y, z); +# endif + e->evcode = type; + e->date = date; + e->x = x; + e->y = y; + e->systemname = z; + Now.eventptr[type] = e; + return (e); + } + syserr("Cannot schedule event %d parm %d %d %d", type, x, y, z); + return 0; +} + + +/* +** RESCHEDULE AN EVENT +** +** The event pointed to by 'e' is rescheduled to the current +** time plus 'offset'. +*/ +void +reschedule(e1, offset) + struct event *e1; + double offset; +{ + double date; + register struct event *e; + + e = e1; + + date = Now.date + offset; + e->date = date; +# ifdef xTRACE + if (Trace) + printf("reschedule: type %d parm %d %d %d @ %.2f\n", + e->evcode, e->x, e->y, e->systemname, date); +# endif +} + + +/* +** UNSCHEDULE AN EVENT +** +** The event at slot 'e' is deleted. +*/ +void +unschedule(e1) + struct event *e1; +{ + register struct event *e; + + e = e1; + +# ifdef xTRACE + if (Trace) + printf("unschedule: type %d @ %.2f parm %d %d %d\n", + e->evcode, e->date, e->x, e->y, e->systemname); +# endif + Now.eventptr[e->evcode & E_EVENT] = 0; + e->date = DBL_MAX; + e->evcode = 0; +} + + +/* +** Abreviated schedule routine +** +** Parameters are the event index and a factor for the time +** figure. +*/ +struct event * +xsched(ev1, factor, x, y, z) + int ev1; + int factor; + int x, y, z; +{ + register int ev; + + ev = ev1; + return (schedule(ev, -Param.eventdly[ev] * Param.time * log(franf()) / factor, x, y, z)); +} + + +/* +** Simplified reschedule routine +** +** Parameters are the event index, the initial date, and the +** division factor. Look at the code to see what really happens. +*/ +void +xresched(e1, ev1, factor) + struct event *e1; + int ev1; + int factor; +{ + register int ev; + register struct event *e; + + ev = ev1; + e = e1; + reschedule(e, -Param.eventdly[ev] * Param.time * log(franf()) / factor); +} diff --git a/src/games/trek/score.c b/src/games/trek/score.c new file mode 100644 index 0000000..2b96a80 --- /dev/null +++ b/src/games/trek/score.c @@ -0,0 +1,72 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +# include "trek.h" +# include "getpar.h" + +/* +** PRINT OUT THE CURRENT SCORE +*/ +long +score() +{ + register int u; + register int t; + long s; + double r; + extern struct cvntab Skitab[]; + + printf("\n*** Your score:\n"); + s = t = Param.klingpwr / 4 * (u = Game.killk); + if (t != 0) + printf("%d Klingons killed\t\t\t%6d\n", u, t); + r = Now.date - Param.date; + if (r < 1.0) + r = 1.0; + r = Game.killk / r; + s += (t = 400 * r); + if (t != 0) + printf("Kill rate %.2f Klingons/stardate \t%6d\n", r, t); + r = Now.klings; + r /= Game.killk + 1; + s += (t = -400 * r); + if (t != 0) + printf("Penalty for %d klingons remaining\t%6d\n", Now.klings, t); + if (Move.endgame > 0) + { + s += (t = 100 * (u = Game.skill)); + printf("Bonus for winning a %s%s game\t\t%6d\n", Skitab[u - 1].abrev, Skitab[u - 1].full, t); + } + if (Game.killed) + { + s -= 500; + printf("Penalty for getting killed\t\t -500\n"); + } + s += (t = -100 * (u = Game.killb)); + if (t != 0) + printf("%d starbases killed\t\t\t%6d\n", u, t); + s += (t = -100 * (u = Game.helps)); + if (t != 0) + printf("%d calls for help\t\t\t%6d\n", u, t); + s += (t = -5 * (u = Game.kills)); + if (t != 0) + printf("%d stars destroyed\t\t\t%6d\n", u, t); + s += (t = -150 * (u = Game.killinhab)); + if (t != 0) + printf("%d inhabited starsystems destroyed\t%6d\n", u, t); + if (Ship.ship != ENTERPRISE) + { + s -= 200; + printf("penalty for abandoning ship\t\t -200\n"); + } + s += (t = 3 * (u = Game.captives)); + if (t != 0) + printf("%d Klingons captured\t\t\t%6d\n", u, t); + s += (t = -(u = Game.deaths)); + if (t != 0) + printf("%d casualties\t\t\t\t%6d\n", u, t); + printf("\n*** TOTAL\t\t\t%14ld\n", s); + return (s); +} diff --git a/src/games/trek/setup.c b/src/games/trek/setup.c new file mode 100644 index 0000000..f4df9a6 --- /dev/null +++ b/src/games/trek/setup.c @@ -0,0 +1,273 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +# include "trek.h" +# include "getpar.h" +# include +# include + +/* +** INITIALIZE THE GAME +** +** The length, skill, and password are read, and the game +** is initialized. It is far too difficult to describe all +** that goes on in here, but it is all straight-line code; +** give it a look. +** +** Game restart and tournament games are handled here. +*/ + +struct cvntab Lentab[] = +{ + { "s", "hort", (void (*)())1, 0 }, + { "m", "edium", (void (*)())2, 0 }, + { "l", "ong", (void (*)())4, 0 }, + { "restart", "", 0, 0 }, + { 0 }, +}; + +struct cvntab Skitab[] = +{ + { "n", "ovice", (void (*)())1, 0 }, + { "f", "air", (void (*)())2, 0 }, + { "g", "ood", (void (*)())3, 0 }, + { "e", "xpert", (void (*)())4, 0 }, + { "c", "ommodore", (void (*)())5, 0 }, + { "i", "mpossible", (void (*)())6, 0 }, + { 0 }, +}; + +void +setup() +{ + struct cvntab *r; + register int i, j; + double f; + int d; + int klump; + int ix, iy; + register struct quad *q; + struct event *e; + + while (1) + { + r = getcodpar("What length game", Lentab); + Game.length = (int) r->value; + if (Game.length == 0) + { + if (restartgame()) + continue; + return; + } + break; + } + r = getcodpar("What skill game", Skitab); + Game.skill = (int) r->value; + Game.tourn = 0; + getstrpar("Enter a password", Game.passwd, 14, 0); + if (sequal(Game.passwd, "tournament")) + { + getstrpar("Enter tournament code", Game.passwd, 14, 0); + Game.tourn = 1; + d = 0; + for (i = 0; Game.passwd[i]; i++) + d += Game.passwd[i] << i; + srand(d); + } + Param.bases = Now.bases = ranf(6 - Game.skill) + 2; + if (Game.skill == 6) + Param.bases = Now.bases = 1; + Param.time = Now.time = 6.0 * Game.length + 2.0; + i = Game.skill; + j = Game.length; + Param.klings = Now.klings = i * j * 3.5 * (franf() + 0.75); + if (Param.klings < i * j * 5) + Param.klings = Now.klings = i * j * 5; + if (Param.klings <= i) /* numerical overflow problems */ + Param.klings = Now.klings = 127; + Param.energy = Ship.energy = 5000; + Param.torped = Ship.torped = 10; + Ship.ship = ENTERPRISE; + Ship.shipname = "Enterprise"; + Param.shield = Ship.shield = 1500; + Param.resource = Now.resource = Param.klings * Param.time; + Param.reserves = Ship.reserves = (6 - Game.skill) * 2.0; + Param.crew = Ship.crew = 387; + Param.brigfree = Ship.brigfree = 400; + Ship.shldup = 1; + Ship.cond = GREEN; + Ship.warp = 5.0; + Ship.warp2 = 25.0; + Ship.warp3 = 125.0; + Ship.sinsbad = 0; + Ship.cloaked = 0; + Param.date = Now.date = (ranf(20) + 20) * 100; + f = Game.skill; + f = log(f + 0.5); + for (i = 0; i < NDEV; i++) + if (Device[i].name[0] == '*') + Param.damfac[i] = 0; + else + Param.damfac[i] = f; + /* these probabilities must sum to 1000 */ + Param.damprob[WARP] = 70; /* warp drive 7.0% */ + Param.damprob[SRSCAN] = 110; /* short range scanners 11.0% */ + Param.damprob[LRSCAN] = 110; /* long range scanners 11.0% */ + Param.damprob[PHASER] = 125; /* phasers 12.5% */ + Param.damprob[TORPED] = 125; /* photon torpedoes 12.5% */ + Param.damprob[IMPULSE] = 75; /* impulse engines 7.5% */ + Param.damprob[SHIELD] = 150; /* shield control 15.0% */ + Param.damprob[COMPUTER] = 20; /* computer 2.0% */ + Param.damprob[SSRADIO] = 35; /* subspace radio 3.5% */ + Param.damprob[LIFESUP] = 30; /* life support 3.0% */ + Param.damprob[SINS] = 20; /* navigation system 2.0% */ + Param.damprob[CLOAK] = 50; /* cloaking device 5.0% */ + Param.damprob[XPORTER] = 80; /* transporter 8.0% */ + /* check to see that I didn't blow it */ + for (i = j = 0; i < NDEV; i++) + j += Param.damprob[i]; + if (j != 1000) + syserr("Device probabilities sum to %d", j); + Param.dockfac = 0.5; + Param.regenfac = (5 - Game.skill) * 0.05; + if (Param.regenfac < 0.0) + Param.regenfac = 0.0; + Param.warptime = 10; + Param.stopengy = 50; + Param.shupengy = 40; + i = Game.skill; + Param.klingpwr = 100 + 150 * i; + if (i >= 6) + Param.klingpwr += 150; + Param.phasfac = 0.8; + Param.hitfac = 0.5; + Param.klingcrew = 200; + Param.srndrprob = 0.0035; + Param.moveprob[KM_OB] = 45; + Param.movefac[KM_OB] = .09; + Param.moveprob[KM_OA] = 40; + Param.movefac[KM_OA] = -0.05; + Param.moveprob[KM_EB] = 40; + Param.movefac[KM_EB] = 0.075; + Param.moveprob[KM_EA] = 25 + 5 * Game.skill; + Param.movefac[KM_EA] = -0.06 * Game.skill; + Param.moveprob[KM_LB] = 0; + Param.movefac[KM_LB] = 0.0; + Param.moveprob[KM_LA] = 10 + 10 * Game.skill; + Param.movefac[KM_LA] = 0.25; + Param.eventdly[E_SNOVA] = 0.5; + Param.eventdly[E_LRTB] = 25.0; + Param.eventdly[E_KATSB] = 1.0; + Param.eventdly[E_KDESB] = 3.0; + Param.eventdly[E_ISSUE] = 1.0; + Param.eventdly[E_SNAP] = 0.5; + Param.eventdly[E_ENSLV] = 0.5; + Param.eventdly[E_REPRO] = 2.0; + Param.navigcrud[0] = 1.50; + Param.navigcrud[1] = 0.75; + Param.cloakenergy = 1000; + Param.energylow = 1000; + for (i = 0; i < MAXEVENTS; i++) + { + e = &Event[i]; + e->date = DBL_MAX; + e->evcode = 0; + } + xsched(E_SNOVA, 1, 0, 0, 0); + xsched(E_LRTB, Param.klings, 0, 0, 0); + xsched(E_KATSB, 1, 0, 0, 0); + xsched(E_ISSUE, 1, 0, 0, 0); + xsched(E_SNAP, 1, 0, 0, 0); + Ship.sectx = ranf(NSECTS); + Ship.secty = ranf(NSECTS); + Game.killk = Game.kills = Game.killb = 0; + Game.deaths = Game.negenbar = 0; + Game.captives = 0; + Game.killinhab = 0; + Game.helps = 0; + Game.killed = 0; + Game.snap = 0; + Move.endgame = 0; + + /* setup stars */ + for (i = 0; i < NQUADS; i++) + for (j = 0; j < NQUADS; j++) + { + q = &Quad[i][j]; + q->klings = q->bases = 0; + q->scanned = -1; + q->stars = ranf(9) + 1; + q->holes = ranf(3) - q->stars / 5; + q->qsystemname = 0; + } + + /* select inhabited starsystems */ + for (d = 1; d < NINHAB; d++) + { + do + { + i = ranf(NQUADS); + j = ranf(NQUADS); + q = &Quad[i][j]; + } while (q->qsystemname); + q->qsystemname = d; + } + + /* position starbases */ + for (i = 0; i < Param.bases; i++) + { + while (1) + { + ix = ranf(NQUADS); + iy = ranf(NQUADS); + q = &Quad[ix][iy]; + if (q->bases > 0) + continue; + break; + } + q->bases = 1; + Now.base[i].x = ix; + Now.base[i].y = iy; + q->scanned = 1001; + /* start the Enterprise near starbase */ + if (i == 0) + { + Ship.quadx = ix; + Ship.quady = iy; + } + } + + /* position klingons */ + for (i = Param.klings; i > 0; ) + { + klump = ranf(4) + 1; + if (klump > i) + klump = i; + while (1) + { + ix = ranf(NQUADS); + iy = ranf(NQUADS); + q = &Quad[ix][iy]; + if (q->klings + klump > MAXKLQUAD) + continue; + q->klings += klump; + i -= klump; + break; + } + } + + /* initialize this quadrant */ + printf("%d Klingons\n%d starbase", Param.klings, Param.bases); + if (Param.bases > 1) + printf("s"); + printf(" at %d,%d", Now.base[0].x, Now.base[0].y); + for (i = 1; i < Param.bases; i++) + printf(", %d,%d", Now.base[i].x, Now.base[i].y); + printf("\nIt takes %d units to kill a Klingon\n", Param.klingpwr); + Move.free = 0; + initquad(0); + srscan(1); + attack(0); +} diff --git a/src/games/trek/setwarp.c b/src/games/trek/setwarp.c new file mode 100644 index 0000000..1b05e64 --- /dev/null +++ b/src/games/trek/setwarp.c @@ -0,0 +1,36 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +# include "trek.h" +# include "getpar.h" + +/* +** SET WARP FACTOR +** +** The warp factor is set for future move commands. It is +** checked for consistancy. +*/ +void +setwarp() +{ + double warpfac; + + warpfac = getfltpar("Warp factor"); + if (warpfac < 0.0) + return; + if (warpfac < 1.0) { + printf("Minimum warp speed is 1.0\n"); + return; + } + if (warpfac > 10.0) { + printf("Maximum speed is warp 10.0\n"); + return; + } + if (warpfac > 6.0) + printf("Damage to warp engines may occur above warp 6.0\n"); + Ship.warp = warpfac; + Ship.warp2 = Ship.warp * warpfac; + Ship.warp3 = Ship.warp2 * warpfac; +} diff --git a/src/games/trek/shell.c b/src/games/trek/shell.c new file mode 100644 index 0000000..de50d3c --- /dev/null +++ b/src/games/trek/shell.c @@ -0,0 +1,33 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +# include "trek.h" +# include +# include + +/* +** CALL THE SHELL +*/ +void +shell() +{ + int i; + register int pid; + register sig_t savint, savquit; + + pid = fork(); + if (! pid) { + setuid(getuid()); + nice(0); + execl("/bin/csh", "-", (char*)0); + syserr("cannot execute /bin/csh"); + } + savint = signal(SIGINT, SIG_IGN); + savquit = signal(SIGQUIT, SIG_IGN); + while (wait(&i) != pid) + ; + signal(SIGINT, savint); + signal(SIGQUIT, savquit); +} diff --git a/src/games/trek/shield.c b/src/games/trek/shield.c new file mode 100644 index 0000000..ab13486 --- /dev/null +++ b/src/games/trek/shield.c @@ -0,0 +1,113 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +# include "trek.h" +# include "getpar.h" + +/* +** SHIELD AND CLOAKING DEVICE CONTROL +** +** 'f' is one for auto shield up (in case of Condition RED), +** zero for shield control, and negative one for cloaking +** device control. +** +** Called with an 'up' or 'down' on the same line, it puts +** the shields/cloak into the specified mode. Otherwise it +** reports to the user the current mode, and asks if she wishes +** to change. +** +** This is not a free move. Hits that occur as a result of +** this move appear as though the shields are half up/down, +** so you get partial hits. +*/ + +struct cvntab Udtab[] = +{ + { "u", "p", (void (*)())1, 0 }, + { "d", "own", 0, 0 }, + { 0 }, +}; + +void +shield(f) + int f; +{ + register int i; + struct cvntab *r; + char s[100]; + char *device, *dev2, *dev3; + int ind; + char *stat; + + if (f > 0 && (Ship.shldup || damaged(SRSCAN))) + return; + if (f < 0) + { + /* cloaking device */ + if (Ship.ship == QUEENE) { + printf("Ye Faire Queene does not have the cloaking device.\n"); + return; + } + device = "Cloaking device"; + dev2 = "is"; + ind = CLOAK; + dev3 = "it"; + stat = &Ship.cloaked; + } + else + { + /* shields */ + device = "Shields"; + dev2 = "are"; + dev3 = "them"; + ind = SHIELD; + stat = &Ship.shldup; + } + if (damaged(ind)) + { + if (f <= 0) + out(ind); + return; + } + if (Ship.cond == DOCKED) + { + printf("%s %s down while docked\n", device, dev2); + return; + } + if (f <= 0 && !testnl()) + { + r = getcodpar("Up or down", Udtab); + i = (int) r->value; + } + else + { + if (*stat) + sprintf(s, "%s %s up. Do you want %s down", device, dev2, dev3); + else + sprintf(s, "%s %s down. Do you want %s up", device, dev2, dev3); + if (!getynpar(s)) + return; + i = !*stat; + } + if (*stat == i) + { + printf("%s already ", device); + if (i) + printf("up\n"); + else + printf("down\n"); + return; + } + if (i) { + if (f >= 0) + Ship.energy -= Param.shupengy; + else + Ship.cloakgood = 0; + } + Move.free = 0; + if (f >= 0) + Move.shldchg = 1; + *stat = i; +} diff --git a/src/games/trek/snova.c b/src/games/trek/snova.c new file mode 100644 index 0000000..0fbbc85 --- /dev/null +++ b/src/games/trek/snova.c @@ -0,0 +1,123 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +# include "trek.h" + +/* +** CAUSE SUPERNOVA TO OCCUR +** +** A supernova occurs. If 'ix' < 0, a random quadrant is chosen; +** otherwise, the current quadrant is taken, and (ix, iy) give +** the sector quadrants of the star which is blowing up. +** +** If the supernova turns out to be in the quadrant you are in, +** you go into "emergency override mode", which tries to get you +** out of the quadrant as fast as possible. However, if you +** don't have enough fuel, or if you by chance run into something, +** or some such thing, you blow up anyway. Oh yeh, if you are +** within two sectors of the star, there is nothing that can +** be done for you. +** +** When a star has gone supernova, the quadrant becomes uninhab- +** itable for the rest of eternity, i.e., the game. If you ever +** try stopping in such a quadrant, you will go into emergency +** override mode. +*/ +void +snova(x, y) + int x, y; +{ + int qx, qy; + register int ix, iy; + int f; + int dx, dy; + int n; + register struct quad *q; + + f = 0; + ix = x; + if (ix < 0) + { + /* choose a quadrant */ + while (1) + { + qx = ranf(NQUADS); + qy = ranf(NQUADS); + q = &Quad[qx][qy]; + if (q->stars > 0) + break; + } + if (Ship.quadx == qx && Ship.quady == qy) + { + /* select a particular star */ + n = ranf(q->stars); + for (ix = 0; ix < NSECTS; ix++) + { + for (iy = 0; iy < NSECTS; iy++) + if (Sect[ix][iy] == STAR || Sect[ix][iy] == INHABIT) + if ((n -= 1) <= 0) + break; + if (n <= 0) + break; + } + f = 1; + } + } + else + { + /* current quadrant */ + iy = y; + qx = Ship.quadx; + qy = Ship.quady; + q = &Quad[qx][qy]; + f = 1; + } + if (f) + { + /* supernova is in same quadrant as Enterprise */ + printf("\nRED ALERT: supernova occuring at %d,%d\n", ix, iy); + dx = ix - Ship.sectx; + dy = iy - Ship.secty; + if (dx * dx + dy * dy <= 2) + { + printf("*** Emergency override attem"); + sleep(1); + printf("\n"); + lose(L_SNOVA); + } + q->scanned = 1000; + } + else + { + if (!damaged(SSRADIO)) + { + q->scanned = 1000; + printf("\nUhura: Captain, Starfleet Command reports a supernova\n"); + printf(" in quadrant %d,%d. Caution is advised\n", qx, qy); + } + } + + /* clear out the supernova'ed quadrant */ + dx = q->klings; + dy = q->stars; + Now.klings -= dx; + if (x >= 0) { + /* Enterprise caused supernova */ + Game.kills += dy; + if (q->bases) + killb(qx, qy); + Game.killk += dx; + } else + if (q->bases) + killb(qx, qy); + killd(qx, qy, (x >= 0)); + q->stars = -1; + q->klings = 0; + if (Now.klings <= 0) + { + printf("Lucky devil, that supernova destroyed the last klingon\n"); + win(); + } +} diff --git a/src/games/trek/srscan.c b/src/games/trek/srscan.c new file mode 100644 index 0000000..24b4940 --- /dev/null +++ b/src/games/trek/srscan.c @@ -0,0 +1,161 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +# include "trek.h" +# include "getpar.h" + +/* +** SHORT RANGE SENSOR SCAN +** +** A short range scan is taken of the current quadrant. If the +** flag 'f' is one, it is an "auto srscan", which is not done +** unless in 'fast' mode. It does a status report and a srscan. +** If 'f' is -1, you get a status report only. If it is zero, +** you get a srscan and an optional status report. The status +** report is taken if you enter "srscan yes"; for all srscans +** thereafter you get a status report with your srscan until +** you type "srscan no". It defaults to on. +** +** The current quadrant is filled in on the computer chart. +*/ + +char *Color[4] = +{ + "GREEN", + "DOCKED", + "YELLOW", + "RED" +}; + +void +srscan(f) + int f; +{ + register int i, j; + register int statinfo; + char *s; + int percent; + struct quad *q = 0; + extern struct cvntab Skitab[]; + extern struct cvntab Lentab[]; + struct cvntab *p; + + if (f >= 0 && check_out(SRSCAN)) + { + return; + } + if (f) + statinfo = 1; + else + { + if (!testnl()) + Etc.statreport = getynpar("status report"); + statinfo = Etc.statreport; + } + if (f > 0) + { + Etc.statreport = 1; + if (!Etc.fast) + return; + } + if (f >= 0) + { + printf("\nShort range sensor scan\n"); + q = &Quad[Ship.quadx][Ship.quady]; + q->scanned = q->klings * 100 + q->bases * 10 + q->stars; + printf(" "); + for (i = 0; i < NSECTS; i++) + { + printf("%d ", i); + } + printf("\n"); + } + + for (i = 0; i < NSECTS; i++) + { + if (f >= 0) + { + printf("%d ", i); + for (j = 0; j < NSECTS; j++) + printf("%c ", Sect[i][j]); + printf("%d", i); + if (statinfo) + printf(" "); + } + if (statinfo) + switch (i) + { + case 0: + printf("stardate %.2f", Now.date); + break; + case 1: + printf("condition %s", Color[(int)Ship.cond]); + if (Ship.cloaked) + printf(", CLOAKED"); + break; + case 2: + printf("position %d,%d/%d,%d",Ship.quadx, Ship.quady, Ship.sectx, Ship.secty); + break; + case 3: + printf("warp factor %.1f", Ship.warp); + break; + case 4: + printf("total energy %d", Ship.energy); + break; + case 5: + printf("torpedoes %d", Ship.torped); + break; + case 6: + s = "down"; + if (Ship.shldup) + s = "up"; + if (damaged(SHIELD)) + s = "damaged"; + percent = 100.0 * Ship.shield / Param.shield; + printf("shields %s, %d%%", s, percent); + break; + case 7: + printf("Klingons left %d", Now.klings); + break; + case 8: + printf("time left %.2f", Now.time); + break; + case 9: + printf("life support "); + if (damaged(LIFESUP)) + { + printf("damaged, reserves = %.2f", Ship.reserves); + break; + } + printf("active"); + break; + } + printf("\n"); + } + if (f < 0) + { + printf("current crew %d\n", Ship.crew); + printf("brig space %d\n", Ship.brigfree); + printf("Klingon power %d\n", Param.klingpwr); + p = &Lentab[Game.length - 1]; + if (Game.length > 2) + p--; + printf("Length, Skill %s%s, ", p->abrev, p->full); + p = &Skitab[Game.skill - 1]; + printf("%s%s\n", p->abrev, p->full); + return; + } + printf(" "); + for (i = 0; i < NSECTS; i++) + printf("%d ", i); + printf("\n"); + + if (q) { + if (q->qsystemname & Q_DISTRESSED) + printf("Distressed "); + if (q->qsystemname) + printf("Starsystem %s\n", systemname(q)); + } +} diff --git a/src/games/trek/systemname.c b/src/games/trek/systemname.c new file mode 100644 index 0000000..a3665ca --- /dev/null +++ b/src/games/trek/systemname.c @@ -0,0 +1,35 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +# include "trek.h" + +/* +** RETRIEVE THE STARSYSTEM NAME +** +** Very straightforward, this routine just gets the starsystem +** name. It returns zero if none in the specified quadrant +** (which, by the way, is passed it). +** +** This routine knows all about such things as distressed +** starsystems, etc. +*/ +char * +systemname(q1) + struct quad *q1; +{ + register struct quad *q; + register int i; + + q = q1; + + i = q->qsystemname; + if (i & Q_DISTRESSED) + i = Event[i & Q_SYSTEM].systemname; + + i &= Q_SYSTEM; + if (i == 0) + return (0); + return (Systemname[i]); +} diff --git a/src/games/trek/torped.c b/src/games/trek/torped.c new file mode 100644 index 0000000..de0e4cd --- /dev/null +++ b/src/games/trek/torped.c @@ -0,0 +1,217 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +# include +# include +# include "trek.h" +# include "getpar.h" + +/* +** RANDOMIZE COURSE +** +** This routine randomizes the course for torpedo number 'n'. +** Other things handled by this routine are misfires, damages +** to the tubes, etc. +*/ +static int +randcourse(n) + int n; +{ + double r; + register int d; + + d = ((franf() + franf()) - 1.0) * 20; + if (abs(d) > 12) + { + printf("Photon tubes misfire"); + if (n < 0) + printf("\n"); + else + printf(" on torpedo %d\n", n); + if (ranf(2)) + { + damage(TORPED, 0.2 * abs(d) * (franf() + 1.0)); + } + d *= 1.0 + 2.0 * franf(); + } + if (Ship.shldup || Ship.cond == DOCKED) + { + r = Ship.shield; + r = 1.0 + r / Param.shield; + if (Ship.cond == DOCKED) + r = 2.0; + d *= r; + } + return (d); +} + +/* +** PHOTON TORPEDO CONTROL +** +** Either one or three photon torpedoes are fired. If three +** are fired, it is called a "burst" and you also specify +** a spread angle. +** +** Torpedoes are never 100% accurate. There is always a random +** cludge factor in their course which is increased if you have +** your shields up. Hence, you will find that they are more +** accurate at close range. However, they have the advantage that +** at long range they don't lose any of their power as phasers +** do, i.e., a hit is a hit is a hit, by any other name. +** +** When the course spreads too much, you get a misfire, and the +** course is randomized even more. You also have the chance that +** the misfire damages your torpedo tubes. +*/ +void +torped() +{ + register int ix, iy; + double x, y, dx, dy; + double angle; + int course, course2; + register int k; + double bigger; + double sectsize; + int burst; + int n; + + if (Ship.cloaked) { + printf("Federation regulations do not permit attack while cloaked.\n"); + return; + } + if (check_out(TORPED)) + return; + if (Ship.torped <= 0) { + printf("All photon torpedos expended\n"); + return; + } + + /* get the course */ + course = getintpar("Torpedo course"); + if (course < 0 || course > 360) + return; + burst = -1; + + /* need at least three torpedoes for a burst */ + if (Ship.torped < 3) + { + printf("No-burst mode selected\n"); + burst = 0; + } + else + { + /* see if the user wants one */ + if (!testnl()) + { + k = ungetc(fgetc(stdin), stdin); + if (k >= '0' && k <= '9') + burst = 1; + } + } + if (burst < 0) + { + burst = getynpar("Do you want a burst"); + } + if (burst) + { + burst = getintpar("burst angle"); + if (burst <= 0) + return; + if (burst > 15) { + printf("Maximum burst angle is 15 degrees\n"); + return; + } + } + sectsize = NSECTS; + n = -1; + if (burst) + { + n = 1; + course -= burst; + } + for (; n && n <= 3; n++) + { + /* select a nice random course */ + course2 = course + randcourse(n); + angle = course2 * 0.0174532925; /* convert to radians */ + dx = -cos(angle); + dy = sin(angle); + bigger = fabs(dx); + x = fabs(dy); + if (x > bigger) + bigger = x; + dx /= bigger; + dy /= bigger; + x = Ship.sectx + 0.5; + y = Ship.secty + 0.5; + if (Ship.cond != DOCKED) + Ship.torped -= 1; + printf("Torpedo track"); + if (n > 0) + printf(", torpedo number %d", n); + printf(":\n%6.1f\t%4.1f\n", x, y); + while (1) + { + ix = x += dx; + iy = y += dy; + if (x < 0.0 || x >= sectsize || y < 0.0 || y >= sectsize) + { + printf("Torpedo missed\n"); + break; + } + printf("%6.1f\t%4.1f\n", x, y); + switch (Sect[ix][iy]) + { + case EMPTY: + continue; + + case HOLE: + printf("Torpedo disappears into a black hole\n"); + break; + + case KLINGON: + for (k = 0; k < Etc.nkling; k++) + { + if (Etc.klingon[k].x != ix || Etc.klingon[k].y != iy) + continue; + Etc.klingon[k].power -= 500 + ranf(501); + if (Etc.klingon[k].power > 0) + { + printf("*** Hit on Klingon at %d,%d: extensive damages\n", + ix, iy); + break; + } + killk(ix, iy); + break; + } + break; + + case STAR: + nova(ix, iy); + break; + + case INHABIT: + kills(ix, iy, -1); + break; + + case BASE: + killb(Ship.quadx, Ship.quady); + Game.killb += 1; + break; + default: + printf("Unknown object %c at %d,%d destroyed\n", + Sect[ix][iy], ix, iy); + Sect[ix][iy] = EMPTY; + break; + } + break; + } + if (damaged(TORPED) || Quad[Ship.quadx][Ship.quady].stars < 0) + break; + course += burst; + } + Move.free = 0; +} diff --git a/src/games/trek/trek.6 b/src/games/trek/trek.6 new file mode 100644 index 0000000..ad2d52d --- /dev/null +++ b/src/games/trek/trek.6 @@ -0,0 +1,63 @@ +.\" Copyright (c) 1980 Regents of the University of California. +.\" All rights reserved. The Berkeley software License Agreement +.\" specifies the terms and conditions for redistribution. +.\" +.\" @(#)trek.6 6.1 (Berkeley) 5/20/85 +.\" +.TH TREK 6 "May 20, 1985" +.UC 4 +.SH NAME +trek \- trekkie game +.SH SYNOPSIS +.B /usr/games/trek +[ [ +.B \-a +] file ] +.SH DESCRIPTION +.I Trek +is a game of space glory and war. Below is a summary of commands. +For complete documentation, see +.IR Trek +by Eric Allman. +.PP +If a filename is given, a log of the game is written onto that file. +If the +.B \-a +flag is given before the filename, that file is appended to, not truncated. +.PP +The game will ask you what length game you would like. +Valid responses are \*(lqshort\*(rq, \*(lqmedium\*(rq, and \*(lqlong\*(rq. +You may also type \*(lqrestart\*(rq, which restarts a previously saved game. +You will then be prompted for the skill, to which you must respond +\*(lqnovice\*(rq, \*(lqfair\*(rq, \*(lqgood\*(rq, \*(lqexpert\*(rq, +\*(lqcommadore\*(rq, or \*(lqimpossible\*(rq. +You should normally start out with a novice and work up. +.PP +In general, throughout the game, if you forget what is appropriate +the game will tell you what it expects if you just type in a question mark. +.SH AUTHOR +Eric Allman +.SH "SEE ALSO" +/usr/doc/trek +.SH "COMMAND SUMMARY" +.ie t .ds f \fB +.el .ds f \fI +.ta 3i +.nf +\*fabandon\fR \*fca\fRpture +\*fcl\fRoak \*fu\fRp/\*fd\fRown +\*fc\fRomputer request; ... \*fda\fRmages +\*fdestruct\fR \*fdo\fRck +\*fhelp\fR \*fi\fRmpulse course distance +\*fl\fRrscan \*fm\fRove course distance +\*fp\fRhasers \*fa\fRutomatic amount +\*fp\fRhasers \*fm\fRanual amt1 course1 spread1 ... +\*ft\fRorpedo course [\*fy\fRes] angle/\*fn\fRo +\*fram\fR course distance \*fr\fRest time +\*fshell\fR \*fsh\fRields \*fu\fRp/\*fd\fRown +\*fs\fRrscan [\*fy\fRes/\*fn\fRo] +\*fst\fRatus \*fterminate\fR \*fy\fRes/\*fn\fRo +\*fu\fRndock \*fv\fRisual course +\*fw\fRarp warp_factor +.fi +.DT diff --git a/src/games/trek/trek.h b/src/games/trek/trek.h new file mode 100644 index 0000000..34db4c5 --- /dev/null +++ b/src/games/trek/trek.h @@ -0,0 +1,403 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + * + * @(#)trek.h 5.1 (Berkeley) 1/29/86 + */ +# include +# include +# include + +/* +** Global Declarations +** +** Virtually all non-local variable declarations are made in this +** file. Exceptions are those things which are initialized, which +** are defined in "externs.c", and things which are local to one +** program file. +** +** So far as I know, nothing in here must be preinitialized to +** zero. +** +** You may have problems from the loader if you move this to a +** different machine. These things actually get allocated in each +** source file, which UNIX allows; however, you may (on other +** systems) have to change everything in here to be "extern" and +** actually allocate stuff in "externs.c" +*/ + +/********************* GALAXY **************************/ + +/* galactic parameters */ +# define NSECTS 10 /* dimensions of quadrant in sectors */ +# define NQUADS 8 /* dimension of galazy in quadrants */ +# define NINHAB 32 /* number of quadrants which are inhabited */ + +struct quad /* definition for each quadrant */ +{ + char bases; /* number of bases in this quadrant */ + char klings; /* number of Klingons in this quadrant */ + char holes; /* number of black holes in this quadrant */ + int scanned; /* star chart entry (see below) */ + char stars; /* number of stars in this quadrant */ + char qsystemname; /* starsystem name (see below) */ +}; + +# define Q_DISTRESSED 0200 +# define Q_SYSTEM 077 + +/* systemname conventions: + * 1 -> NINHAB index into Systemname table for live system. + * + Q_DISTRESSED distressed starsystem -- systemname & Q_SYSTEM + * is the index into the Event table which will + * have the system name + * 0 dead or nonexistent starsystem + * + * starchart ("scanned") conventions: + * 0 -> 999 taken as is + * -1 not yet scanned ("...") + * 1000 supernova ("///") + * 1001 starbase + ??? (".1.") +*/ + +/* ascii names of systems */ +extern char *Systemname[NINHAB]; + +/* quadrant definition */ +struct quad Quad[NQUADS][NQUADS]; + +/* defines for sector map (below) */ +# define EMPTY '.' +# define STAR '*' +# define BASE '#' +# define ENTERPRISE 'E' +# define QUEENE 'Q' +# define KLINGON 'K' +# define INHABIT '@' +# define HOLE ' ' + +/* current sector map */ +char Sect[NSECTS][NSECTS]; + + +/************************ DEVICES ******************************/ + +# define NDEV 16 /* max number of devices */ + +/* device tokens */ +# define WARP 0 /* warp engines */ +# define SRSCAN 1 /* short range scanners */ +# define LRSCAN 2 /* long range scanners */ +# define PHASER 3 /* phaser control */ +# define TORPED 4 /* photon torpedo control */ +# define IMPULSE 5 /* impulse engines */ +# define SHIELD 6 /* shield control */ +# define COMPUTER 7 /* on board computer */ +# define SSRADIO 8 /* subspace radio */ +# define LIFESUP 9 /* life support systems */ +# define SINS 10 /* Space Inertial Navigation System */ +# define CLOAK 11 /* cloaking device */ +# define XPORTER 12 /* transporter */ +# define SHUTTLE 13 /* shuttlecraft */ + +/* device names */ +struct device +{ + char *name; /* device name */ + char *person; /* the person who fixes it */ +}; + +struct device Device[NDEV]; + +/*************************** EVENTS ****************************/ + +# define NEVENTS 12 /* number of different event types */ + +# define E_LRTB 1 /* long range tractor beam */ +# define E_KATSB 2 /* Klingon attacks starbase */ +# define E_KDESB 3 /* Klingon destroys starbase */ +# define E_ISSUE 4 /* distress call is issued */ +# define E_ENSLV 5 /* Klingons enslave a quadrant */ +# define E_REPRO 6 /* a Klingon is reproduced */ +# define E_FIXDV 7 /* fix a device */ +# define E_ATTACK 8 /* Klingon attack during rest period */ +# define E_SNAP 9 /* take a snapshot for time warp */ +# define E_SNOVA 10 /* supernova occurs */ + +# define E_GHOST 0100 /* ghost of a distress call if ssradio out */ +# define E_HIDDEN 0200 /* event that is unreportable because ssradio out */ +# define E_EVENT 077 /* mask to get event code */ + +struct event +{ + char x, y; /* coordinates */ + double date; /* trap stardate */ + char evcode; /* event type */ + char systemname; /* starsystem name */ +}; +/* systemname conventions: + * 1 -> NINHAB index into Systemname table for reported distress calls + * + * evcode conventions: + * 1 -> NEVENTS-1 event type + * + E_HIDDEN unreported (SSradio out) + * + E_GHOST actually already expired + * 0 unallocated + */ + +# define MAXEVENTS 25 /* max number of concurrently pending events */ + +struct event Event[MAXEVENTS]; /* dynamic event list; one entry per pending event */ + +/***************************** KLINGONS *******************************/ + +struct kling +{ + char x, y; /* coordinates */ + int power; /* power left */ + double dist; /* distance to Enterprise */ + double avgdist; /* average over this move */ + char srndreq; /* set if surrender has been requested */ +}; + +# define MAXKLQUAD 9 /* maximum klingons per quadrant */ + +/********************** MISCELLANEOUS ***************************/ + +/* condition codes */ +# define GREEN 0 +# define DOCKED 1 +# define YELLOW 2 +# define RED 3 + +/* starbase coordinates */ +# define MAXBASES 9 /* maximum number of starbases in galaxy */ + +/* distress calls */ +# define MAXDISTR 5 /* maximum concurrent distress calls */ + +/* phaser banks */ +# define NBANKS 6 /* number of phaser banks */ + +struct xy +{ + char x, y; /* coordinates */ +}; + + +/* + * note that much of the stuff in the following structs CAN NOT + * be moved around!!!! + */ + + +/* information regarding the state of the starship */ +struct +{ + double warp; /* warp factor */ + double warp2; /* warp factor squared */ + double warp3; /* warp factor cubed */ + char shldup; /* shield up flag */ + char cloaked; /* set if cloaking device on */ + int energy; /* starship's energy */ + int shield; /* energy in shields */ + double reserves; /* life support reserves */ + int crew; /* ship's complement */ + int brigfree; /* space left in brig */ + char torped; /* torpedoes */ + char cloakgood; /* set if we have moved */ + int quadx; /* quadrant x coord */ + int quady; /* quadrant y coord */ + int sectx; /* sector x coord */ + int secty; /* sector y coord */ + char cond; /* condition code */ + char sinsbad; /* Space Inertial Navigation System condition */ + char *shipname; /* name of current starship */ + char ship; /* current starship */ + int distressed; /* number of distress calls */ +} Ship; + +/* sinsbad is set if SINS is working but not calibrated */ + +/* game related information, mostly scoring */ +struct +{ + int killk; /* number of klingons killed */ + int deaths; /* number of deaths onboard Enterprise */ + char negenbar; /* number of hits on negative energy barrier */ + char killb; /* number of starbases killed */ + int kills; /* number of stars killed */ + char skill; /* skill rating of player */ + char length; /* length of game */ + char killed; /* set if you were killed */ + char killinhab; /* number of inhabited starsystems killed */ + char tourn; /* set if a tournament game */ + char passwd[15]; /* game password */ + char snap; /* set if snapshot taken */ + char helps; /* number of help calls */ + int captives; /* total number of captives taken */ +} Game; + +/* per move information */ +struct +{ + char free; /* set if a move is free */ + char endgame; /* end of game flag */ + char shldchg; /* set if shields changed this move */ + char newquad; /* set if just entered this quadrant */ + char resting; /* set if this move is a rest */ + double time; /* time used this move */ +} Move; + +/* parametric information */ +struct +{ + char bases; /* number of starbases */ + char klings; /* number of klingons */ + double date; /* stardate */ + double time; /* time left */ + double resource; /* Federation resources */ + int energy; /* starship's energy */ + int shield; /* energy in shields */ + double reserves; /* life support reserves */ + int crew; /* size of ship's complement */ + int brigfree; /* max possible number of captives */ + char torped; /* photon torpedos */ + double damfac[NDEV]; /* damage factor */ + double dockfac; /* docked repair time factor */ + double regenfac; /* regeneration factor */ + int stopengy; /* energy to do emergency stop */ + int shupengy; /* energy to put up shields */ + int klingpwr; /* Klingon initial power */ + int warptime; /* time chewer multiplier */ + double phasfac; /* Klingon phaser power eater factor */ + char moveprob[6]; /* probability that a Klingon moves */ + double movefac[6]; /* Klingon move distance multiplier */ + double eventdly[NEVENTS]; /* event time multipliers */ + double navigcrud[2]; /* navigation crudup factor */ + int cloakenergy; /* cloaking device energy per stardate */ + double damprob[NDEV]; /* damage probability */ + double hitfac; /* Klingon attack factor */ + int klingcrew; /* number of Klingons in a crew */ + double srndrprob; /* surrender probability */ + int energylow; /* low energy mark (cond YELLOW) */ +} Param; + +/* Sum of damage probabilities must add to 1000 */ + +/* other information kept in a snapshot */ +struct +{ + char bases; /* number of starbases */ + char klings; /* number of klingons */ + double date; /* stardate */ + double time; /* time left */ + double resource; /* Federation resources */ + char distressed; /* number of currently distressed quadrants */ + struct event *eventptr[NEVENTS]; /* pointer to event structs */ + struct xy base[MAXBASES]; /* locations of starbases */ +} Now; + +/* Other stuff, not dumped in a snapshot */ +struct +{ + struct kling klingon[MAXKLQUAD]; /* sorted Klingon list */ + char nkling; /* number of Klingons in this sector */ + /* < 0 means automatic override mode */ + char fast; /* set if speed > 300 baud */ + struct xy starbase; /* starbase in current quadrant */ + char snapshot[sizeof Quad + sizeof Event + sizeof Now]; /* snapshot for time warp */ + char statreport; /* set to get a status report on a srscan */ +} Etc; + +/* + * eventptr is a pointer to the event[] entry of the last + * scheduled event of each type. Zero if no such event scheduled. + */ + +/* Klingon move indicies */ +# define KM_OB 0 /* Old quadrant, Before attack */ +# define KM_OA 1 /* Old quadrant, After attack */ +# define KM_EB 2 /* Enter quadrant, Before attack */ +# define KM_EA 3 /* Enter quadrant, After attack */ +# define KM_LB 4 /* Leave quadrant, Before attack */ +# define KM_LA 5 /* Leave quadrant, After attack */ + +/* you lose codes */ +# define L_NOTIME 1 /* ran out of time */ +# define L_NOENGY 2 /* ran out of energy */ +# define L_DSTRYD 3 /* destroyed by a Klingon */ +# define L_NEGENB 4 /* ran into the negative energy barrier */ +# define L_SUICID 5 /* destroyed in a nova */ +# define L_SNOVA 6 /* destroyed in a supernova */ +# define L_NOLIFE 7 /* life support died (so did you) */ +# define L_NOHELP 8 /* you could not be rematerialized */ +# define L_TOOFAST 9 /* pretty stupid going at warp 10 */ +# define L_STAR 10 /* ran into a star */ +# define L_DSTRCT 11 /* self destructed */ +# define L_CAPTURED 12 /* captured by Klingons */ +# define L_NOCREW 13 /* you ran out of crew */ + +/****************** COMPILE OPTIONS ***********************/ + +/* Trace info */ +# define xTRACE 1 +int Trace; + +struct event *schedule(int type, double offset, int x, int y, int z); +struct event * xsched(int ev1, int factor, int x, int y, int z); + +char *systemname(struct quad *q1); + +void *bmove(void *a, void *b, int l); + +int damaged(int dev); +int ranf(int max); +int check_out(int device); +int readdelim(int d); +int cgetc(int i); +int sequal(char *a, char *b); +int dumpssradio(void); +int events(int warp); +int getcodi(int *co, double *di); +int length(char *s); +int restartgame(void); + +long score(void); + +double franf(void); +double move(int ramflag, int course, double time, double speed); + +void out(int dev); +void lose(int why); +void unschedule(struct event *e1); +void initquad(int f); +void dock(void); +void compkldist(int f); +void klmove(int fl); +void damage(int dev1, double dam); +void warp(int fl, int c, double d); +void attack(int resting); +void capture(void); +void killk(int ix, int iy); +void killd(int x, int y, int f); +void autover(void); +void reschedule(struct event *e1, double offset); +void syserr(char *fmt, ...); +void skiptonl(int c); +void snova(int x, int y); +void xresched(struct event *e1, int ev1, int factor); +void killb(int qx, int qy); +void sector(int *x, int *y); +void shield(int f); +void win(void); +void undock(void); +void setup(void); +void play(void); +void checkcond(void); +void dumpme(int flag); +void ram(int ix, int iy); +void kills(int x, int y, int f); +void srscan(int f); +void nova(int x, int y); diff --git a/src/games/trek/utility.c b/src/games/trek/utility.c new file mode 100644 index 0000000..22ae1b7 --- /dev/null +++ b/src/games/trek/utility.c @@ -0,0 +1,98 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +# include "trek.h" +# include +# include +# include + +/* +** ASSORTED UTILITY ROUTINES +*/ + +/* +** BLOCK MOVE +** +** Moves a block of storage of length `l' bytes from the data +** area pointed to by `a' to the area pointed to by `b'. +** Returns the address of the byte following the `b' field. +** Overflow of `b' is not tested. +*/ +void * +bmove(a, b, l) + void *a, *b; + int l; +{ + register int n; + register char *p, *q; + + p = a; + q = b; + n = l; + while (n--) + *q++ = *p++; + return (q); +} + + +/* +** STRING EQUALITY TEST +** null-terminated strings `a' and `b' are tested for +** absolute equality. +** returns one if equal, zero otherwise. +*/ +int +sequal(a, b) + char *a, *b; +{ + register char *p, *q; + + p = a; + q = b; + while (*p || *q) + if (*p++ != *q++) + return(0); + return(1); +} + + +/* +** FIND STRING LENGTH +** +** The length of string `s' (excluding the null byte which +** terminates the string) is returned. +*/ +int +length(s) + char *s; +{ + register int l; + register char *p; + + l = 0; + p = s; + while (*p++) + l++; + return(l); +} + + +/* +** SYSTEM ERROR +*/ +void +syserr(char *fmt, ...) +{ + va_list ap; + + printf("\n\07TREK SYSERR: "); + va_start(ap, fmt); + vprintf(fmt, ap); + va_end(ap); + printf("\n"); + if (errno) + printf("\tsystem error %d\n", errno); + exit(-1); +} diff --git a/src/games/trek/visual.c b/src/games/trek/visual.c new file mode 100644 index 0000000..a99c80c --- /dev/null +++ b/src/games/trek/visual.c @@ -0,0 +1,71 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +# include "trek.h" +# include "getpar.h" + +/* +** VISUAL SCAN +** +** A visual scan is made in a particular direction of three sectors +** in the general direction specified. This takes time, and +** Klingons can attack you, so it should be done only when sensors +** are out. +*/ + +/* This struct[] has the delta x, delta y for particular directions */ +struct xy Visdelta[11] = +{ + { -1, -1 }, + { -1, 0 }, + { -1, 1 }, + { 0, 1 }, + { 1, 1 }, + { 1, 0 }, + { 1, -1 }, + { 0, -1 }, + { -1, -1 }, + { -1, 0 }, + { -1, 1 }, +}; + +void +visual() +{ + register int ix, iy; + int co; + register struct xy *v; + + co = getintpar("direction"); + if (co < 0 || co > 360) + return; + co = (co + 22) / 45; + v = &Visdelta[co]; + ix = Ship.sectx + v->x; + iy = Ship.secty + v->y; + if (ix < 0 || ix >= NSECTS || iy < 0 || iy >= NSECTS) + co = '?'; + else + co = Sect[ix][iy]; + printf("%d,%d %c ", ix, iy, co); + v++; + ix = Ship.sectx + v->x; + iy = Ship.secty + v->y; + if (ix < 0 || ix >= NSECTS || iy < 0 || iy >= NSECTS) + co = '?'; + else + co = Sect[ix][iy]; + printf("%c ", co); + v++; + ix = Ship.sectx + v->x; + iy = Ship.secty + v->y; + if (ix < 0 || ix >= NSECTS || iy < 0 || iy >= NSECTS) + co = '?'; + else + co = Sect[ix][iy]; + printf("%c %d,%d\n", co, ix, iy); + Move.time = 0.05; + Move.free = 0; +} diff --git a/src/games/trek/warp.c b/src/games/trek/warp.c new file mode 100644 index 0000000..6fbadc5 --- /dev/null +++ b/src/games/trek/warp.c @@ -0,0 +1,151 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +# include "trek.h" +# include "getpar.h" + +/* +** MOVE UNDER WARP POWER +** +** This is both the "move" and the "ram" commands, differing +** only in the flag 'fl'. It is also used for automatic +** emergency override mode, when 'fl' is < 0 and 'c' and 'd' +** are the course and distance to be moved. If 'fl' >= 0, +** the course and distance are asked of the captain. +** +** The guts of this routine are in the routine move(), which +** is shared with impulse(). Also, the working part of this +** routine is very small; the rest is to handle the slight chance +** that you may be moving at some riduculous speed. In that +** case, there is code to handle time warps, etc. +*/ +void +warp(fl, c, d) + int fl, c; + double d; +{ + int course; + double power; + double dist; + double time; + double speed; + double frac; + register int percent; + register int i; + char *cp; + + if (Ship.cond == DOCKED) { + printf("%s is docked\n", Ship.shipname); + return; + } + if (damaged(WARP)) { + out(WARP); + return; + } + if (fl < 0) { + course = c; + dist = d; + } + else if (getcodi(&course, &dist)) + return; + + /* check to see that we are not using an absurd amount of power */ + power = (dist + 0.05) * Ship.warp3; + percent = 100 * power / Ship.energy + 0.5; + if (percent >= 85) + { + printf("Scotty: That would consume %d%% of our remaining energy.\n", + percent); + if (!getynpar("Are you sure that is wise")) + return; + } + + /* compute the speed we will move at, and the time it will take */ + speed = Ship.warp2 / Param.warptime; + time = dist / speed; + + /* check to see that that value is not ridiculous */ + percent = 100 * time / Now.time + 0.5; + if (percent >= 85) + { + printf("Spock: That would take %d%% of our remaining time.\n", + percent); + if (!getynpar("Are you sure that is wise")) + return; + } + + /* compute how far we will go if we get damages */ + if (Ship.warp > 6.0 && ranf(100) < 20 + 15 * (Ship.warp - 6.0)) + { + frac = franf(); + dist *= frac; + time *= frac; + damage(WARP, (frac + 1.0) * Ship.warp * (franf() + 0.25) * 0.20); + } + + /* do the move */ + Move.time = move(fl, course, time, speed); + + /* see how far we actually went, and decrement energy appropriately */ + dist = Move.time * speed; + Ship.energy -= dist * Ship.warp3 * (Ship.shldup + 1); + + /* test for bizarre events */ + if (Ship.warp <= 9.0) + return; + printf("\n\n ___ Speed exceeding warp nine ___\n\n"); + sleep(2); + printf("Ship's safety systems malfunction\n"); + sleep(2); + printf("Crew experiencing extreme sensory distortion\n"); + sleep(4); + if (ranf(100) >= 100 * dist) { + printf("Equilibrium restored -- all systems normal\n"); + return; + } + + /* select a bizzare thing to happen to us */ + percent = ranf(100); + if (percent < 70) + { + /* time warp */ + if (percent < 35 || !Game.snap) + { + /* positive time warp */ + time = (Ship.warp - 8.0) * dist * (franf() + 1.0); + Now.date += time; + printf("Positive time portal entered -- it is now Stardate %.2f\n", + Now.date); + for (i = 0; i < MAXEVENTS; i++) + { + percent = Event[i].evcode; + if (percent == E_FIXDV || percent == E_LRTB) + Event[i].date += time; + } + return; + } + + /* s/he got lucky: a negative time portal */ + time = Now.date; + cp = Etc.snapshot; + bmove(cp, Quad, sizeof Quad); + bmove(cp += sizeof Quad, Event, sizeof Event); + bmove(cp += sizeof Event, &Now, sizeof Now); + printf("Negative time portal entered -- it is now Stardate %.2f\n", + Now.date); + for (i = 0; i < MAXEVENTS; i++) + if (Event[i].evcode == E_FIXDV) + reschedule(&Event[i], Event[i].date - time); + return; + } + + /* test for just a lot of damage */ + if (percent < 80) + lose(L_TOOFAST); + printf("Equilibrium restored -- extreme damage occured to ship systems\n"); + for (i = 0; i < NDEV; i++) + damage(i, (3.0 * (franf() + franf()) + 1.0) * Param.damfac[i]); + Ship.shldup = 0; +} diff --git a/src/games/trek/win.c b/src/games/trek/win.c new file mode 100644 index 0000000..50a020f --- /dev/null +++ b/src/games/trek/win.c @@ -0,0 +1,57 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +# include "trek.h" +# include "getpar.h" +# include + +/* +** Signal game won +** +** This routine prints out the win message, arranges to print out +** your score, tells you if you have a promotion coming to you, +** cleans up the current input line, and arranges to have you +** asked whether or not you want another game (via the reset() +** call). +** +** Pretty straightforward, although the promotion algorithm is +** pretty off the wall. +*/ +void +win() +{ + long s; + extern jmp_buf env; + extern long score(); + extern struct cvntab Skitab[]; + register struct cvntab *p; + + sleep(1); + printf("\nCongratulations, you have saved the Federation\n"); + Move.endgame = 1; + + /* print and return the score */ + s = score(); + + /* decide if she gets a promotion */ + if (Game.helps == 0 && Game.killb == 0 && Game.killinhab == 0 && 5 * Game.kills + Game.deaths < 100 && + s >= 1000 && Ship.ship == ENTERPRISE) + { + printf("In fact, you are promoted one step in rank,\n"); + if (Game.skill >= 6) + printf("to the exalted rank of Commodore Emeritus\n"); + else + { + p = &Skitab[Game.skill - 1]; + printf("from %s%s ", p->abrev, p->full); + p++; + printf("to %s%s\n", p->abrev, p->full); + } + } + + /* clean out input, and request new game */ + skiptonl(0); + longjmp(env, 1); +} diff --git a/src/games/warp/EXTERN.h b/src/games/warp/EXTERN.h new file mode 100644 index 0000000..d171f42 --- /dev/null +++ b/src/games/warp/EXTERN.h @@ -0,0 +1,24 @@ +/* $Header: EXTERN.h,v 7.0.1.1 86/12/12 16:46:50 lwall Exp $ + * + * $Log: EXTERN.h,v $ + * Revision 7.0.1.1 86/12/12 16:46:50 lwall + * Guarded the undefs. + * + * Revision 7.0 86/10/08 15:11:31 lwall + * Split into separate files. Added amoebas and pirates. + * + */ + +#ifdef EXT +#undef EXT +#endif +#define EXT extern + +#ifdef INIT +#undef INIT +#endif +#define INIT(x) + +#ifdef DOINIT +#undef DOINIT +#endif diff --git a/src/games/warp/INTERN.h b/src/games/warp/INTERN.h new file mode 100644 index 0000000..c736b03 --- /dev/null +++ b/src/games/warp/INTERN.h @@ -0,0 +1,22 @@ +/* $Header: INTERN.h,v 7.0.1.1 86/12/12 16:51:45 lwall Exp $ + * + * $Log: INTERN.h,v $ + * Revision 7.0.1.1 86/12/12 16:51:45 lwall + * Guarded the undefs. + * + * Revision 7.0 86/10/08 15:11:37 lwall + * Split into separate files. Added amoebas and pirates. + * + */ + +#ifdef EXT +#undef EXT +#endif +#define EXT + +#ifdef INIT +#undef INIT +#endif +#define INIT(x) = x + +#define DOINIT diff --git a/src/games/warp/MANIFEST b/src/games/warp/MANIFEST new file mode 100644 index 0000000..013eaff --- /dev/null +++ b/src/games/warp/MANIFEST @@ -0,0 +1,58 @@ +After all the warp kits are run you should have the following files: + +Filename Kit Description +-------- --- ----------- +Configure 1 An entertaining little shell script +EXTERN.h 6 Set up for external .h files +INTERN.h 6 Set up for internal .h files +MANIFEST 1 This file +Makefile.SH 5 Makefile for warp +README 5 Instructions--please read +bang.c 5 Routines having to do with blast propagation +bang.h 6 Visible declarations for above +config.H 4 Sample config.h for if you can't Configure +init.c 3 Initialization for a wave. +init.h 2 Visible declarations for above +intrp.c 4 Code to interpret % substitutions +intrp.h 6 Visible declarations for above +makedepend.SH 6 Generates makefile dependencies +makedir.SH 6 Makes multilevel directories +move.c 3 Object movement and display +move.h 6 Visible declarations for above +ndir.c 5 Directory manipulation routines +ndir.h 5 Visible declarations for above +object.c 6 Object management +object.h 6 Visible declarations for above +patchlevel.h 4 How patched the kit is +play.c 5 What to do each second +play.h 6 Visible declarations for above +score.c 2 Scoring and saving +score.h 6 Visible declarations for above +sig.c 5 Signal handling +sig.h 6 Visible declarations for above +sm.c 6 Starmap translator +smp.0 3 "Straight Grid" scenario +smp.1 6 "Offset Grid" scenario +smp.2 6 "Shooting Gallery" scenario +smp.3 6 "Superfortress" scenario +smp.4 6 "Blocks" scenario +smp.5 6 "Microfortress" scenario +smp.6 6 "Passage" scenario +smp.7 6 "Wall" scenario +term.c 2 Terminal handling +term.h 5 Visible declarations for above +them.c 5 Smarts for enemies +them.h 6 Visible declarations for above +us.c 4 Smarts for us +us.h 6 Visible declarations for above +util.c 1 Utility routines +util.h 5 Visible declarations for above +version.c 6 Prints version number. +version.h 1 Visible declarations for above +warp.c 2 Main loop +warp.doc 4 How to play warp +warp.h 4 Visible declarations for everyone +warp.man 5 How to start warp +warp.news 5 Sample startup message +weapon.c 3 Our firepower +weapon.h 6 Visible declarations for above diff --git a/src/games/warp/Makefile b/src/games/warp/Makefile new file mode 100644 index 0000000..d114ccf --- /dev/null +++ b/src/games/warp/Makefile @@ -0,0 +1,56 @@ +TOPSRC = $(shell cd ../../..; pwd) +include $(TOPSRC)/target.mk +#include $(TOPSRC)/cross.mk + +CFLAGS += -Os -mips16 -Werror #-Wall + +OBJS = bang.o init.o intrp.o move.o \ + object.o play.o score.o \ + sig.o term.o them.o us.o \ + util.o version.o warp.o weapon.o +LIBS = -ltermcap -lm +MAN = warp.0 +MANSRC = warp.man +PRIVATE = warp.doc smap.0 smap.1 smap.2 smap.3 smap.4 smap.5 smap.6 smap.7 +PRIVLIB = $(DESTDIR)/games/lib/warp + +all: warp $(MAN) $(PRIVATE) + +warp: ${OBJS} + ${CC} ${LDFLAGS} -o warp.elf ${OBJS} ${LIBS} + ${OBJDUMP} -S warp.elf > warp.dis + ${SIZE} warp.elf + ${ELF2AOUT} warp.elf $@ && rm warp.elf + +smap.0: smp.0 sm + ./sm smap.0 +smap.1: smp.1 sm + ./sm smap.1 +smap.2: smp.2 sm + ./sm smap.2 +smap.3: smp.3 sm + ./sm smap.3 +smap.4: smp.4 sm + ./sm smap.4 +smap.5: smp.5 sm + ./sm smap.5 +smap.6: smp.6 sm + ./sm smap.6 +smap.7: smp.7 sm + ./sm smap.7 +sm: sm.c + cc -O -Wall -Werror sm.c -o sm + +${MAN}: ${MANSRC} + ${MANROFF} $< > $@ + +clean: + rm -f *.o *.elf ${MAN} warp *.elf *.dis tags *~ smap.* sm + +install: warp $(PRIVATE) + install warp $(DESTDIR)/games/ + cp ${MAN} $(DESTDIR)/share/man/cat6/ + mkdir -p $(PRIVLIB) + cp $(PRIVATE) $(PRIVLIB) + cp /dev/null $(PRIVLIB)/save.blurfl + [ -f $(PRIVLIB)/warp.news ] || cp warp.news $(PRIVLIB) diff --git a/src/games/warp/Makefile-linux b/src/games/warp/Makefile-linux new file mode 100644 index 0000000..6b16f62 --- /dev/null +++ b/src/games/warp/Makefile-linux @@ -0,0 +1,57 @@ +# $Header: Makefile.SH,v 1.1 87/07/03 01:45:30 games Exp $ +# +# Revision 7.0.1.1a 87/26/08 03:45:03 games +# Fix minor shell continuation bug and put in a pdp-11 overlay scheme. +# +# Revision 7.0.1.1 86/12/12 16:54:03 lwall +# Frozen for net release. +# +# Revision 7.0 86/10/08 15:11:42 lwall +# Split into separate files. Added amoebas and pirates. +# +# +CFLAGS = -g -O -Werror -DTERMIO #-Wall +LDFLAGS = +PRIVLIB = /usr/games/lib/warp +LIBS = -ltermcap -lm + +PRIVATE = warp.doc smap.0 smap.1 smap.2 smap.3 smap.4 smap.5 smap.6 smap.7 + +OBJ = bang.o init.o intrp.o move.o \ + object.o play.o score.o \ + sig.o term.o them.o us.o \ + util.o version.o warp.o weapon.o + +all: warp $(PRIVATE) + +warp: $(OBJ) + $(CC) $(LDFLAGS) $(OBJ) $(LIBS) -o warp + +install: warp $(PRIVATE) + install warp $(bin) + mkdir -p $(PRIVLIB) + cp $(PRIVATE) $(PRIVLIB) + cp /dev/null $(PRIVLIB)/save.blurfl + [ -f $(PRIVLIB)/warp.news ] || cp warp.news $(PRIVLIB) + +clean: + rm -f core *.o warp smap.* sm + +smap.0: smp.0 sm + ./sm smap.0 +smap.1: smp.1 sm + ./sm smap.1 +smap.2: smp.2 sm + ./sm smap.2 +smap.3: smp.3 sm + ./sm smap.3 +smap.4: smp.4 sm + ./sm smap.4 +smap.5: smp.5 sm + ./sm smap.5 +smap.6: smp.6 sm + ./sm smap.6 +smap.7: smp.7 sm + ./sm smap.7 +sm: sm.c + cc -O -Wall -Werror sm.c -o sm diff --git a/src/games/warp/README b/src/games/warp/README new file mode 100644 index 0000000..5308706 --- /dev/null +++ b/src/games/warp/README @@ -0,0 +1,95 @@ + Warp Kit, Version 7.0 + + Copyright (c) 1986, Larry Wall + +You may copy the warp kit in whole or in part as long as you don't try to +make money off it, or pretend that you wrote it. +-------------------------------------------------------------------------- + +Warp is a real-time space war game that doesn't get boring very quickly. +Read warp.doc and the manual page for more information. + +Warp will probably not run on V7 systems that don't have a non-blocking read, +or on machines with a small address space like the PDP-11. Caveat Emptor. + +Please read all the directions below before you proceed any further, and +then follow them carefully. Failure to do so may void your warranty. :-) + +After you have unpacked your kit, you should have all the files listed +in MANIFEST. + + IMPORTANT + +You must choose the uid that you want warp to run under, since warp runs +setuid to protect its files. Choose a uid (not root) that is used only +by trustworthy persons. If you do your make install as root, the installed +version will be chowned to this uid. Otherwise, you should login to your +selected uid before proceeding. The Configure script will ask you which +uid you want warp to run under. + +Installation + +1) Run Configure. This will figure out various things about your system. + Some things Configure will figure out for itself, other things it will + ask you about. It will then proceed to make config.h, config.sh, and + Makefile. + + You might possibly have to trim # comments from the front of Configure + if your sh doesn't handle them, but all other # comments will be taken + care of. + + (If you don't have sh, you'll have to copy the sample file config.H to + config.h and edit the config.h to reflect your system's peculiarities.) + +2) Glance through config.h to make sure system dependencies are correct. + Most of them should have been taken care of by running the Configure script. + + If you have any additional changes to make to the C definitions, they + can be done in the Makefile, or in config.h. Bear in mind that they will + get undone next time you run Configure. + +3) make depend + + This will look for all the includes and modify Makefile accordingly. + Configure will offer to do this for you. + +4) make + + This will attempt to make warp in the current directory. + +5) make install + + This will put warp into a public directory (normally /usr/games). + It will also try to put the man pages in a reasonable place. It will not + nroff the man page, however. You may need to be root to do this. If + you are not root, you must own the directories in question and you should + ignore any messages about chown not working. + +6) Read the manual entry before running warp. + +7) Feel free to edit warp.news. + +8) IMPORTANT! Help save the world! Communicate any problems and + suggested patches to me, lwall@sdcrdcf.UUCP (Larry Wall), so we can + keep the world in sync. If you have a problem, there's someone else + out there who either has had or will have the same problem. + + If possible, send in patches such that the patch program will apply them. + Context diffs are the best, then normal diffs. Don't send ed scripts-- + I've probably changed my copy since the version you have. + + Watch for warp patches in comp.sources.bugs. Patches will generally be + in a form usable by the patch program. If you are just now bringing up + warp and aren't sure how many patches there are, write to me and I'll + send any you don't have. Your current patch level is shown in patchlevel.h. + + +NEW FEATURES IN THIS RELEASE + +Uses a Configure script for greater portability. +Space Amoebas!!! +Pirates +Friendly Freighters +Harry Mudd +Damage +Keyboard mapping diff --git a/src/games/warp/bang.c b/src/games/warp/bang.c new file mode 100644 index 0000000..d820d87 --- /dev/null +++ b/src/games/warp/bang.c @@ -0,0 +1,153 @@ +/* $Header: bang.c,v 7.0.1.3 86/12/12 16:57:00 lwall Exp $ */ + +/* $Log: bang.c,v $ + * Revision 7.0.1.3 86/12/12 16:57:00 lwall + * Made circular explosions. + * + * Revision 7.0.1.2 86/10/20 14:36:02 lwall + * Picked some lint. + * + * Revision 7.0.1.1 86/10/16 10:49:45 lwall + * Added Damage. Fixed random bugs. + * + * Revision 7.0 86/10/08 15:11:57 lwall + * Split into separate files. Added amoebas and pirates. + * + */ + +#include "EXTERN.h" +#include "warp.h" +#include "object.h" +#include "move.h" +#include "sig.h" +#include "term.h" +#include "them.h" +#include "INTERN.h" +#include "bang.h" + +void +bang_init() +{ + ; +} + +void +make_plink(y,x) +register int x; +register int y; +{ + register OBJECT *obj; + + move(y+1,x*2,0); + beg_qwrite(); + *filler = '@'; + qwrite(); + obj = occupant[y][x]; + if (obj) { + if (numamoebas && obj->image == ' ') + qaddc(amb[y][x]); + else + qaddc(obj->image); + } + else if (numamoebas) + qaddc(amb[y][x]); + else + qaddspace(); + end_qwrite(); +} + +void +make_blast(y,x,mass,size) +register int x; +register int y; +int size; +long mass; +{ + bangy[nxtbang] = y; + bangx[nxtbang] = x; + bangm[nxtbang] = mass; + bangs[nxtbang++] = size; + assert(nxtbang <= XSIZE * YSIZE); + if (numamoebas && amb[y][x] == '~') { + if (mass > 10000) + modify_amoeba(y,x,1,'~', 10); + else if (mass > 100) + modify_amoeba(y,x,1,'~', 5); + bangs[nxtbang-1] = 0; /* don't propagate */ + return; + } + else if (mass >= 0) { + register OBJECT *obj; + + move(y+1,x*2,0); + beg_qwrite(); + *filler = '@'; + qwrite(); + *filler = '#'; + qwrite(); + *filler = '@'; + qwrite(); + *filler = '#'; + qwrite(); + *filler = '@'; + qwrite(); + obj = occupant[y][x]; + if (obj) { + if (numamoebas && obj->image == ' ') + qaddc(amb[y][x]); + else + qaddc(obj->image); + } + else if (numamoebas) + qaddc(amb[y][x]); + else + qaddspace(); + end_qwrite(); + } +} + +void +do_bangs() +{ + register int x; + register int y; + register int i; + register int j; + register int k; + register int lastxy; + register OBJECT *obj; + + /* read blast list and update blast array */ + assert(nxtbang >= 0 && nxtbang <= XSIZE * YSIZE); + for (i=0; i= MAXBDIST) + lastxy = MAXBDIST - 1; + for (y=bangy[i]-bangs[i],x=bangx[i]-bangs[i],j=lastxy; + j>=0; + y++,x++,--j) { + yblasted[yy[j] = (y+YSIZE00) % YSIZE] |= 1; + xblasted[xx[j] = (x+XSIZE00) % XSIZE] |= 1; + } + blasted = TRUE; + for (y=lastxy;y>=0;--y) { + for (x=lastxy;x>=0;--x) { + if (lastxy > 2) { + j = abs(y-bangs[i]); + k = abs(x-bangs[i]); + if (j < k) /* distance is long + 1/2 short */ + j += k + k; + else + j += j + k; + if (--j > lastxy) + continue; + } + if (bangm[i] != 32767 || + !(obj=occupant[yy[y]][xx[x]]) || obj->type != Web) + blast[yy[y]][xx[x]] += bangm[i]; + } + } + } +} diff --git a/src/games/warp/bang.h b/src/games/warp/bang.h new file mode 100644 index 0000000..3d2d643 --- /dev/null +++ b/src/games/warp/bang.h @@ -0,0 +1,30 @@ +/* $Header: bang.h,v 7.0 86/10/08 15:12:03 lwall Exp $ */ + +/* $Log: bang.h,v $ + * Revision 7.0 86/10/08 15:12:03 lwall + * Split into separate files. Added amoebas and pirates. + * + */ + +EXT long blast[YSIZE][XSIZE]; +EXT bool blasted; +EXT bool xblasted[XSIZE]; +EXT bool yblasted[YSIZE]; + +EXT char bangy[YSIZE*XSIZE]; +EXT char bangx[YSIZE*XSIZE]; +EXT char bangs[YSIZE*XSIZE]; + +EXT long bangm[YSIZE*XSIZE]; + +#define MAXBDIST 40 +EXT int xx[MAXBDIST]; +EXT int yy[MAXBDIST]; + +EXT int nxtbang; +EXT bool banging; + +void make_plink(); +void make_blast(); +void do_bangs(); +void bang_init(); diff --git a/src/games/warp/init.c b/src/games/warp/init.c new file mode 100644 index 0000000..f7e05c4 --- /dev/null +++ b/src/games/warp/init.c @@ -0,0 +1,531 @@ +/* $Header: init.c,v 7.0.1.4 86/12/12 16:58:03 lwall Exp $ */ + +/* $Log: init.c,v $ + * Revision 7.0.1.4 86/12/12 16:58:03 lwall + * Baseline for net release. + * + * Revision 7.0.1.3 86/10/20 14:35:31 lwall + * Picked some lint. + * + * Revision 7.0.1.2 86/10/17 15:53:30 lwall + * Added random walk star fields. + * + * Revision 7.0.1.1 86/10/16 10:51:19 lwall + * Added Damage. Fixed random bugs. + * + * Revision 7.0 86/10/08 15:12:10 lwall + * Split into separate files. Added amoebas and pirates. + * + */ + +#include "EXTERN.h" +#include "warp.h" +#include "bang.h" +#include "object.h" +#include "move.h" +#include "play.h" +#include "score.h" +#include "term.h" +#include "them.h" +#include "us.h" +#include "util.h" +#include "weapon.h" +#include "INTERN.h" +#include "init.h" + +void +initialize() +{ + register int i; + register int x; + register int y; + register int dist; + register int ydist; + register int xdist; + long e; + int yoff, xoff, ypred, xpred; + register OBJECT *obj; + char ch; + FILE *mapfp = NULL; + bool tmptholspec; + int inhabjackpot; + long inhenergy; + int walksplit = 200; + static char *distname[] = + {" #"," -"," \\"," /", + " |"," *"," `"," '"}; + + cloaking = madgorns = FALSE; + deados = madfriends = 0; + curscore = possiblescore = 0L; + yamblast = xamblast = ambsize = 0; + if (smarts > 90) + massacre = TRUE; + scandist = (massacre?20:15); + antibase = (smarts>60?1:(smarts>40?2:(smarts>25?4:100))); + sm35 = (smarts>35?35:smarts); + sm45 = (smarts>45?45:smarts); + sm50 = (smarts>50?50:smarts); + sm55 = (smarts>55?55:smarts); + sm80 = (smarts>80?80:smarts); + sm95 = (smarts>95?95:smarts); + super = (smarts>50?smarts-50:0); + enemshields = 10 + super/2; /* (scaled by 10) 1 @ 50 .. 3 @ 90 */ + if (smarts>90) + enemshields += (smarts-90)*10; /* lay it on thick: ~13 @ 99 */ + entmax = (smarts>=75?5000:(smarts>=50?4000:(smarts>=40?3000:2000))); + basemax = (smarts>=75?20000:(smarts>=50?15000:(smarts>=40?12500:10000))); + + clear(); + while (root.next != &root) { + root.next = root.next->next; + free_object(root.next->prev); + } + root.prev = &root; + enemies = movers = NULL; + numos = numxes = 0; + for (y=0;y 85) + inumstars = exdis(800) + rand_mod(100) + 1; + else /* too few stars makes 50..85 too hard */ + inumstars = exdis(700) + rand_mod(150-super*2) + 50+super*2; + tmptholspec = (smarts > 15 && inumstars < 450 && ! rand_mod(90-sm80)); + if (!klingspec) { + inumenemies = rand_mod((smarts+1)/2) + 1; + if (massacre || tmptholspec) + inumenemies += 10; + } + if (!friendspec) + inumfriends = rand_mod(smarts/8+1); + if (!piratespec) + inumpirates = rand_mod(inumfriends/2+1); + if (inumfriends+inumenemies+inumstars > YSIZE*XSIZE-20) + inumstars = YSIZE*XSIZE-20 - inumenemies - inumfriends; + if (inumstars < 0) { + inumfriends += inumstars; + inumstars = 0; + } + if (inumfriends < 0) { + inumenemies += inumfriends; + inumfriends = 0; + } + if (inumenemies < 0) + inumenemies = 0; + numstars = inumstars; + inuminhab = numinhab = 0; + inumroms = inumthols = inumgorns = 0; + numapollos = apolspec || massacre ? 1 : + ((!numstars || rand_mod(2) || smarts < 10) ? 0 : 1); + inumapollos = apolloflag = 0; + realapollo = NULL; + inumcrushes = numcrushes = + crushspec||massacre?1:(rand_mod(2000) < inumstars); + inumenemies += inumcrushes; + inumamoebas = numamoebas = (amoebaspec ? 1 : + !rand_mod(inumcrushes?3-massacre:8) ); /* < and & are fun together */ + inumenemies += inumamoebas; + if (!rand_mod(40)) { + inhabjackpot = 32767; + inumfriends += rand_mod(10); + inumpirates += rand_mod(10); + } + else + inhabjackpot = inumpirates; + inhenergy = 30000-super*150; + if (!rand_mod(10)) + inhenergy = 50000; + if (!rand_mod(4)) + inhenergy += rand_mod(3500+super*150); + numfriends = inumfriends; + numpirates = inumpirates; + numenemies = inumenemies; + deadmudds = 0; + + /* do stars */ + +stars_again: + if (prespec) + dist = 4; + else if (numstars > 750) + dist = 0; + else + dist = rand_mod(starspec||smarts<=5?3:5); + if (debugging) { + real_y = real_x = -100; + printf("\r\n"); + } + switch (dist) { + case 0: /* uniform random */ + ydist = xdist = 0; + if (inumstars < 700 && !rand_mod(3-(inumstars<50))) { + ydist = xdist = 6; /* well, maybe not so random */ + y = rand_mod(YSIZE); + x = rand_mod(XSIZE); + if (rand_mod(2)) + walksplit = inumstars/(exdis(40)+1); + } + if (debugging) + printf(" R\r\n"); + break; + case 1: case 2: /* clumped, maybe skewed, maybe superposed */ + ydist = rand_mod(4); + xdist = rand_mod(2); + if (debugging) + printf("%s\r\n",distname[ydist+4*xdist]); + yoff = rand_mod(YSIZE); + xoff = rand_mod(XSIZE); + if (dist == 2) + dist = numstars/2 + exdis(numstars/2) - exdis(numstars/2); + else + dist = 0; + break; + case 3: case 4: /* predefined or residual */ + scenario_again: + if (debugging) + printf(" P\r\n"); + dist = 0; + Sprintf(spbuf,"smap.%d", + (prescene>=0?prescene:rand_mod(MAPS)) ); + if ((mapfp = fopen(spbuf,"r")) != NULL && + fgets(spbuf,10,mapfp) != NULL ) { + inumstars = numstars = atoi(spbuf); + if (inumenemies+inumstars > YSIZE*XSIZE-20) + inumstars = numstars = YSIZE*XSIZE-20 - inumenemies; + ydist = rand_mod(2) + 4; /* flip y axis? */ + xdist = rand_mod(2) + 4; /* flip x axis? */ + yoff = rand_mod(YSIZE); /* how much to shift y */ + xoff = rand_mod(XSIZE); /* how much to shift x */ + } + else { + prespec = FALSE; + prescene = -1; + if (rand_mod(2)) + goto scenario_again; + goto stars_again; + } + break; + } + for (i = 1; i <= numstars; i++) { + if (dist && i == dist) { /* flip to another skewing? */ + ydist = rand_mod(4); + xdist = rand_mod(2); + if (!rand_mod(4)) { + ydist = xdist = 6; + if (debugging) + printf("&\r\n"); + } + else if (debugging) + printf("%s\r\n",distname[ydist+4*xdist]); + yoff = rand_mod(YSIZE); + xoff = rand_mod(XSIZE); + dist = 0; + } + do { /* until an open spot found */ + switch (xdist) { + case 0: + x = rand_mod(XSIZE); /* pick from 0..39, uniform */ + break; + case 1: case 2: case 3: + x = (int)((((double)(myrand()-HALFRAND)) * + ((double)(myrand()-HALFRAND))/RANDRAND) + * 20.0) + xoff; /* pick from -20..20, clumped */ + break; + case 4: + if (fscanf(mapfp,"%d %d\n",&ypred,&xpred) == EOF) + ydist = xdist = 0; + x = xpred + xoff; + break; + case 5: + if (fscanf(mapfp,"%d %d\n",&ypred,&xpred) == EOF) + ydist = xdist = 0; + x = -xpred + xoff; + break; + case 6: + x += rand_mod(3) - 1; + break; + } + switch (ydist) { + case 0: + y = rand_mod(YSIZE); + break; + case 1: + y = (int)((((double)(myrand()-HALFRAND)) * + ((double)(myrand()-HALFRAND))/RANDRAND) + * 12.0) + yoff; /* pick from -12..12, clumped */ + break; + case 2: + y = (int)((((double)(myrand()-HALFRAND)) * + ((double)(myrand()-HALFRAND))/RANDRAND) + * 12.0) + yoff + x*YSIZE/XSIZE; + /* clumped & skewed */ + break; + case 3: + y = (int)((((double)(myrand()-HALFRAND)) * + ((double)(myrand()-HALFRAND))/RANDRAND) + * 12.0) + yoff - x*YSIZE/XSIZE; + /* clumped & skewed */ + break; + case 4: + y = ypred + yoff; + break; + case 5: + y = -ypred + yoff; + break; + case 6: + y += rand_mod(3) - 1; + if (!rand_mod(walksplit)) { + y = rand_mod(YSIZE); + x = rand_mod(XSIZE); + } + break; + } + while (x<0) x += XSIZE00; + while (y<0) y += YSIZE00; + x %= XSIZE; + y %= YSIZE; + } while (occupant[y][x]); + e = rand_mod(32768); + if (--inhabjackpot > 0 || e >= inhenergy) { + ch = '@'; + if (inhabjackpot && e < 10000) + e += 10000; + inuminhab = ++numinhab; + } + else { + ch = '*'; + } + obj = make_object(Star,ch,y,x,0,0,e+rand_mod(super*100+1),e/4,&root); + obj->flags |= STATIC; + } + if (inumstars > 30 && inhabjackpot <= 0 && + !rand_mod(3 - (inumstars > 400) - (inhenergy > 32768)) ) { + int initx; + int inity; + + x = initx = obj->posx; + y = inity = obj->posy; + while (rand_mod(2) && inuminhab < inumstars/2) { + for (i=rand_mod(smarts)*2+20; i; i--) { + if ((obj = occupant[y][x]) && obj->image == '*') { + setimage(obj,'@'); + if (obj->energy < 10000) + obj->energy += 20000; /* the benefits of civilization */ + inuminhab = ++numinhab; + } + if (i&15) { + y = (y + rand_mod(3) + YSIZE99) % YSIZE; + x = (x + rand_mod(3) + XSIZE99) % XSIZE; + } + else { /* don't wander too far */ + y = inity; + x = initx; + } + } + x = initx = rand_mod(XSIZE); + y = inity = rand_mod(YSIZE); + } + } + if (mapfp != NULL) + Fclose(mapfp); + if (numcrushes) { + do { + x = rand_mod(XSIZE); + y = rand_mod(YSIZE); + } while (occupant[y][x]); + movers = make_object(Crusher,'<',y,x,0,1,32767L,32768L,&root); + possiblescore += 10000; + } + ient = (numents != 0); + if (ient) { + do { + x = rand_mod(XSIZE); + y = rand_mod(YSIZE); + } while (occupant[y][x]); + e = entmax; + ent = make_object(Enterprise,'E',y,x,0,0,e,e/2,&root); + if (!movers) + movers = ent; + } + ibase = (numbases != 0); + if (ibase) { + e = 52-super; + do { + x = rand_mod(XSIZE); + y = rand_mod(YSIZE); + } while (occupant[y][x] || lookaround(y,x,Star) * 7 < e--); + e = basemax; + base = make_object(Base, 'B',y,x,0,0,e,e/4,&root); + if (!movers) + movers = base; + } + if (numamoebas) { + do { + x = rand_mod(XSIZE); + y = rand_mod(YSIZE); + } while (occupant[y][x]); + nuke = make_object(Enemy,'&',y,x,0,0,32767L, + (long)entmax+entmax+rand_mod(entmax),&root); + possiblescore += 10000; + amb[y][x] = '~'; + if (rand_mod(2)) + modify_amoeba(y,x,2,'~',(int)rand_mod(smarts<<1));/* just make blob */ + else { + for (i=smarts/10+1; i; i--) { + nuke->strategy = rand_mod(256); /* random direction */ + modify_amoeba(y,x,2,'~',(int)rand_mod(5)); + modify_amoeba(y,x,2,'~',(int)rand_mod(5)); + modify_amoeba(y,x,2,'~',(int)rand_mod(5)); + modify_amoeba(y,x,2,'~',(int)rand_mod(5)); /* extend pseudopod */ + } + } + if (!enemies) + enemies = nuke; + if (!movers) + movers = nuke; + } + if (rand_mod(27-sm50/2) && !romspec && !gornspec) + dist = 27-sm50/2; + else + dist = rand_mod(4) + 1; + for (i = 1+inumcrushes+inumamoebas; i <= numenemies; i++) { + do { + x = rand_mod(XSIZE); + y = rand_mod(YSIZE); + } while (occupant[y][x]); + if (rand_mod(dist)) { + if (!tholspec && !tmptholspec && rand_mod((inumstars*3)/sm50+2)) + ch = 'K'; + else { + ch = 'T'; + inumthols++; + } + } + else { + if (romspec == gornspec) + e = 50; + else if (gornspec) + e = 10; + else + e = 90; + if (rand_mod(100) < e) { + ch = 'R'; + inumroms++; + } + else { + ch = 'G'; + inumgorns++; + } + } + if (possiblescore > ENTBOUNDARY - 10000) + e = (ENTBOUNDARY - possiblescore) / 5; + else + e = 250 + (sm50-1) * 30 * 20 / numenemies+1; + e = exdis((int)e) + e - exdis((int)e); + obj = make_object(Enemy,ch,y,x,0,0, + e + rand_mod(super*200+2) + 10000*massacre,e/4,&root); + e /= 4; + switch (ch) { + case 'K': + possiblescore += e; + break; + case 'T': + possiblescore += e*3/2; + break; + case 'G': + possiblescore += e*2; + break; + case 'R': + possiblescore += e*3; + obj->flags |= CLOAKS; + break; + } + if (!enemies) + enemies = obj; + if (!movers) + movers = obj; + } + numgorns = inumgorns; + for (i=0; i 0) { + obj->flags |= PIRATE; + if (smarts >= 20 && !rand_mod(10-smarts/10)) + obj->flags |= CLOAKS; + } + obj->flags |= FRIENDLY; + if (!enemies) + enemies = obj; + if (!movers) + movers = obj; + } + if (!movers) + movers = &root; + if (!enemies) + enemies = &root; + if (ent) + mvaddch(ent->posy+1, ent->posx*2, ent->image); + if (base) + mvaddch(base->posy+1, base->posx*2, base->image); + sleep(2); + { + register OBJECT *curobj; + + for (curobj = root.next; curobj != &root; curobj = curobj->next) { + mvaddch(curobj->posy+1, curobj->posx*2, curobj->image); + } + } + + for (i=0;i<2;i++) for (y=0;y<3;y++) for (x=0;x<3;x++) + isatorp[i][y][x]=0; + + whenok = 0; + timer = 0; + finish = 0; + bombed_out = FALSE; + if (ent) + entmode = status = 0; + else + if (base) + status = 2; + else + status = 3; + + Sprintf(spbuf, + "%-4s E: %4d %2d B: %5d %3d Enemies: %-3d Stars: %-3d Stardate%5d.%1d %9ld", + " ", 0, 0, 0, 0, 0, 0, smarts * 100, 0, 0L); + mvaddstr(0,0,spbuf); + oldeenergy = oldbenergy = oldcurscore = + oldstatus = oldetorp = oldbtorp = oldstrs = oldenemies = -1; + /* force everything to fill in */ + damage = olddamage = 0; + for (i=0; i +#include + +/* name of this host */ +struct utsname uts; + +#ifdef TILDENAME +static char *tildename = Nullch; +static char *tildedir = Nullch; +#endif + +char *dointerp(); +char *getrealname(); +#ifdef CONDSUB +char *skipinterp(); +#endif + +static void abort_interp(); + +void +intrp_init(tcbuf) +char *tcbuf; +{ + + /* get environmental stuff */ + + /* get home directory */ + + homedir = getenv("HOME"); + if (homedir == Nullch) + homedir = getenv("LOGDIR"); + + dotdir = getval("DOTDIR",homedir); + + /* get login name */ + + logname = getenv("USER"); + if (logname == Nullch) + logname = getenv("LOGNAME"); +#ifdef GETLOGIN + if (logname == Nullch) + logname = savestr(getlogin()); +#endif + + /* get the real name of the person (%N) */ + /* Must be done after logname is read in */ + + strcpy(tcbuf,getrealname(getuid())); + realname = savestr(tcbuf); + + /* name of this host (%H) */ + /* get sysname */ + uname(&uts); + hostname = savestr(uts.nodename); + + warplib = savestr(filexp(WARPLIB)); + + if (scorespec) /* that getwd below takes ~1/3 sec. */ + return; /* and we do not need it for -s */ + if (! getwd(tcbuf)) { /* find working directory name */ + perror("getcwd"); + exit(1); + } + origdir = savestr(tcbuf); /* and remember it */ +} + +/* expand filename via %, ~, and $ interpretation */ +/* returns pointer to static area */ +/* Note that there is a 1-deep cache of ~name interpretation */ + +char * +filexp(s) +register char *s; +{ + static char filename[CBUFLEN]; + char scrbuf[CBUFLEN]; + register char *d; + +#ifdef DEBUGGING + if (debug & DEB_FILEXP) + printf("< %s\r\n",s); +#endif + interp(filename, (sizeof filename), s); /* interpret any % escapes */ +#ifdef DEBUGGING + if (debug & DEB_FILEXP) + printf("%% %s\r\n",filename); +#endif + s = filename; + if (*s == '~') { /* does destination start with ~? */ + if (!*(++s) || *s == '/') { + Sprintf(scrbuf,"%s%s",homedir,s); + /* swap $HOME for it */ +#ifdef DEBUGGING + if (debug & DEB_FILEXP) + printf("~ %s\r\n",scrbuf); +#endif + strcpy(filename,scrbuf); + } + else { +#ifdef TILDENAME + for (d=scrbuf; isalnum(*s); s++,d++) + *d = *s; + *d = '\0'; + if (tildedir && strEQ(tildename,scrbuf)) { + strcpy(scrbuf,tildedir); + strcat(scrbuf, s); + strcpy(filename, scrbuf); +#ifdef DEBUGGING + if (debug & DEB_FILEXP) + printf("r %s %s\r\n",tildename,tildedir); +#endif + } + else { + if (tildename) { + free(tildename); + free(tildedir); + } + tildedir = Nullch; + tildename = savestr(scrbuf); + { + struct passwd *pwd = getpwnam(tildename); + + Sprintf(scrbuf,"%s%s",pwd->pw_dir,s); + tildedir = savestr(pwd->pw_dir); + strcpy(filename,scrbuf); + endpwent(); + } + } +#else /* !TILDENAME */ +#ifdef VERBOSE + IF(verbose) + fputs("~loginname not implemented.\r\n",stdout); + ELSE +#endif +#ifdef TERSE + fputs("~login not impl.\r\n",stdout); +#endif +#endif + } + } + else if (*s == '$') { /* starts with some env variable? */ + d = scrbuf; + *d++ = '%'; + if (s[1] == '{') + strcpy(d,s+2); + else { + *d++ = '{'; + for (s++; isalnum(*s); s++) *d++ = *s; + /* skip over token */ + *d++ = '}'; + strcpy(d,s); + } +#ifdef DEBUGGING + if (debug & DEB_FILEXP) + printf("$ %s\r\n",scrbuf); +#endif + interp(filename, (sizeof filename), scrbuf); + /* this might do some extra '%'s but */ + /* that is how the Mercedes Benz */ + } +#ifdef DEBUGGING + if (debug & DEB_FILEXP) + printf("> %s\r\n",filename); +#endif + return filename; +} + +#ifdef CONDSUB +/* skip interpolations */ + +char * +skipinterp(pattern,stoppers) +register char *pattern; +char *stoppers; +{ + + while (*pattern && (!stoppers || !strchr(stoppers,*pattern))) { +#ifdef DEBUGGING + if (debug & 8) + printf("skipinterp till %s at %s\r\n",stoppers?stoppers:"",pattern); +#endif + if (*pattern == '%' && pattern[1]) { + switch (*++pattern) { + case '{': + for (pattern++; *pattern && *pattern != '}'; pattern++) + if (*pattern == '\\') + pattern++; + break; +#ifdef CONDSUB + case '(': { + pattern = skipinterp(pattern+1,"!="); + if (!*pattern) + goto getout; + for (pattern++; *pattern && *pattern != '?'; pattern++) + if (*pattern == '\\') + pattern++; + if (!*pattern) + goto getout; + pattern = skipinterp(pattern+1,":)"); + if (*pattern == ':') + pattern = skipinterp(pattern+1,")"); + break; + } +#endif +#ifdef BACKTICK + case '`': { + pattern = skipinterp(pattern+1,"`"); + break; + } +#endif +#ifdef PROMPTTTY + case '"': + pattern = skipinterp(pattern+1,"\""); + break; +#endif + default: + break; + } + pattern++; + } + else { + if (*pattern == '^' && pattern[1]) + pattern += 2; + else if (*pattern == '\\' && pattern[1]) + pattern += 2; + else + pattern++; + } + } +getout: + return pattern; /* where we left off */ +} +#endif + +/* interpret interpolations */ + +char * +dointerp(dest,destsize,pattern,stoppers) +register char *dest; +register int destsize; +register char *pattern; +char *stoppers; +{ + register char *s; + register int i; + char scrbuf[512]; + bool upper = FALSE; + bool lastcomp = FALSE; + int metabit = 0; + + while (*pattern && (!stoppers || !strchr(stoppers,*pattern))) { +#ifdef DEBUGGING + if (debug & 8) + printf("dointerp till %s at %s\r\n",stoppers?stoppers:"",pattern); +#endif + if (*pattern == '%' && pattern[1]) { + upper = FALSE; + lastcomp = FALSE; + for (s=Nullch; !s; ) { + switch (*++pattern) { + case '^': + upper = TRUE; + break; + case '_': + lastcomp = TRUE; + break; + case '{': + pattern = cpytill(scrbuf,pattern+1,'}'); + if (s = strchr(scrbuf,'-')) + *s++ = '\0'; + else + s = nullstr; + s = getval(scrbuf,s); + break; +#ifdef CONDSUB + case '(': { + char rch; + bool matched; + + pattern = dointerp(dest,destsize,pattern+1,"!="); + rch = *pattern; + if (rch == '!') + pattern++; + if (*pattern != '=') + goto getout; + pattern = cpytill(scrbuf,pattern+1,'?'); + if (!*pattern) + goto getout; + if (*scrbuf == '^' && scrbuf[strlen(scrbuf)-1] == '$') { + scrbuf[strlen(scrbuf)-1] = '\0'; + matched = strEQ(scrbuf+1,dest); + } + else + matched = instr(dest,scrbuf) != Nullch; + if (matched==(rch == '=')) { + pattern = dointerp(dest,destsize,pattern+1,":)"); + if (*pattern == ':') + pattern = skipinterp(pattern+1,")"); + } + else { + pattern = skipinterp(pattern+1,":)"); + if (*pattern == ':') + pattern++; + pattern = dointerp(dest,destsize,pattern,")"); + } + s = dest; + break; + } +#endif +#ifdef BACKTICK + case '`': { + FILE *pipefp, *popen(); + + pattern = dointerp(scrbuf,(sizeof scrbuf),pattern+1,"`"); + pipefp = popen(scrbuf,"r"); + if (pipefp != Nullfp) { + int len; + + len = fread(scrbuf,sizeof(char),(sizeof scrbuf)-1, + pipefp); + scrbuf[len] = '\0'; + pclose(pipefp); + } + else { + printf("\r\nCan't run %s\r\n",scrbuf); + *scrbuf = '\0'; + } + for (s=scrbuf; *s; s++) { + if (*s == '\n') { + if (s[1]) + *s = ' '; + else + *s = '\0'; + } + } + s = scrbuf; + break; + } +#endif +#ifdef PROMPTTTY + case '"': + pattern = dointerp(scrbuf,(sizeof scrbuf),pattern+1,"\""); + fputs(scrbuf,stdout); + resetty(); + if (! gets(scrbuf)) + /* ignore */; + crmode(); + raw(); + noecho(); + nonl(); + s = scrbuf; + break; +#endif + case '~': + s = homedir; + break; + case '.': + s = dotdir; + break; + case '$': + s = scrbuf; + Sprintf(s,"%d",getpid()); + break; + case 'H': /* host name */ + s = hostname; + break; + case 'L': /* login id */ + s = logname; + break; + case 'N': /* full name */ + s = getval("NAME",realname); + break; + case 'O': + s = origdir; + break; + case 'p': + s = cwd; + break; + case 'X': /* warp library */ + s = warplib; + break; + default: + if (--destsize <= 0) + abort_interp(); + *dest++ = *pattern | metabit; + s = nullstr; + break; + } + } + if (!s) + s = nullstr; + pattern++; + if (upper || lastcomp) { + char *t; + + if (s != scrbuf) { + Safecpy(scrbuf,s,(sizeof scrbuf)); + s = scrbuf; + } + if (upper || !(t=strrchr(s,'/'))) + t = s; + while (*t && !isalpha(*t)) + t++; + if (islower(*t)) + *t = toupper(*t); + } + i = metabit; /* maybe get into register */ + if (s == dest) { + while (*dest) { + if (--destsize <= 0) + abort_interp(); + *dest++ |= i; + } + } + else { + while (*s) { + if (--destsize <= 0) + abort_interp(); + *dest++ = *s++ | i; + } + } + } + else { + if (--destsize <= 0) + abort_interp(); + if (*pattern == '^' && pattern[1]) { + ++pattern; /* skip uparrow */ + i = *pattern; /* get char into a register */ + if (i == '?') + *dest++ = '\177' | metabit; + else if (i == '(') { + metabit = 0200; + destsize++; + } + else if (i == ')') { + metabit = 0; + destsize++; + } + else + *dest++ = i & 037 | metabit; + pattern++; + } + else if (*pattern == '\\' && pattern[1]) { + ++pattern; /* skip backslash */ + i = *pattern; /* get char into a register */ + + /* this used to be a switch but the if may save space */ + + if (i >= '0' && i <= '7') { + i = 1; + while (i < 01000 && *pattern >= '0' && *pattern <= '7') { + i <<= 3; + i += *pattern++ - '0'; + } + *dest++ = i & 0377 | metabit; + --pattern; + } + else if (i == 'b') + *dest++ = '\b' | metabit; + else if (i == 'f') + *dest++ = '\f' | metabit; + else if (i == 'n') + *dest++ = '\n' | metabit; + else if (i == 'r') + *dest++ = '\r' | metabit; + else if (i == 't') + *dest++ = '\t' | metabit; + else + *dest++ = i | metabit; + pattern++; + } + else + *dest++ = *pattern++ | metabit; + } + } + *dest = '\0'; +getout: + return pattern; /* where we left off */ +} + +void +interp(dest,destsize,pattern) +char *dest; +int destsize; +char *pattern; +{ + (void) dointerp(dest,destsize,pattern,Nullch); +#ifdef DEBUGGING + if (debug & DEB_FILEXP) + fputs(dest,stdout); +#endif +} + +/* get the person's real name from /etc/passwd */ +/* (string is overwritten, so it must be copied) */ + +char * +getrealname(uid) +int uid; +{ + char *s, *c; + + struct passwd *pwd = getpwuid(uid); + + s = pwd->pw_gecos; + if ((c = strchr(s, ',')) != Nullch) + *c = '\0'; + if ((c = strchr(s, ';')) != Nullch) + *c = '\0'; + s = cpytill(buf,s,'&'); + if (*s == '&') { /* whoever thought this one up was */ + c = buf + strlen(buf); /* in the middle of the night */ + strcat(c,logname); /* before the morning after */ + strcat(c,s+1); + if (islower(*c)) + *c = toupper(*c); /* gack and double gack */ + } + endpwent(); + return buf; /* return something static */ +} + +static void +abort_interp() +{ + fputs("\r\n% interp buffer overflow!\r\n",stdout); + sig_catcher(0); +} diff --git a/src/games/warp/intrp.h b/src/games/warp/intrp.h new file mode 100644 index 0000000..c159dc0 --- /dev/null +++ b/src/games/warp/intrp.h @@ -0,0 +1,23 @@ +/* $Header: intrp.h,v 7.0.1.1 86/12/12 16:59:45 lwall Exp $ + * + * $Log: intrp.h,v $ + * Revision 7.0.1.1 86/12/12 16:59:45 lwall + * Baseline for net release. + * + * Revision 7.0 86/10/08 15:12:27 lwall + * Split into separate files. Added amoebas and pirates. + * + */ + +EXT char *origdir INIT(Nullch); /* cwd when warp invoked */ +EXT char *homedir INIT(Nullch); /* login directory */ +EXT char *dotdir INIT(Nullch); /* where . files go */ +EXT char *logname INIT(Nullch); /* login id */ +EXT char *hostname INIT(Nullch); /* host name */ +EXT char *realname INIT(Nullch); /* real name from /etc/passwd */ + +void intrp_init(); +char *filexp(); +char *dointerp(); +void interp(); +char *getrealname(); diff --git a/src/games/warp/move.c b/src/games/warp/move.c new file mode 100644 index 0000000..a52bc96 --- /dev/null +++ b/src/games/warp/move.c @@ -0,0 +1,676 @@ +/* $Header: move.c,v 7.0.1.2 86/10/20 14:37:06 lwall Exp $ */ + +/* $Log: move.c,v $ + * Revision 7.0.1.2 86/10/20 14:37:06 lwall + * Picked some lint. + * + * Revision 7.0.1.1 86/10/16 10:52:09 lwall + * Added Damage. Fixed random bugs. + * + * Revision 7.0 86/10/08 15:12:40 lwall + * Split into separate files. Added amoebas and pirates. + * + */ + +#include "EXTERN.h" +#include "warp.h" +#include "bang.h" +#include "object.h" +#include "move.h" +#include "play.h" +#include "score.h" +#include "term.h" +#include "them.h" +#include "us.h" +#include "util.h" +#include "weapon.h" +#include "INTERN.h" +#include "move.h" + +void +move_init() +{ + ; +} + +void +bounce(obj) +register OBJECT *obj; +{ + register int x; + register int y; + register int count=0; + + y = (obj->posy - sgn(obj->vely) + YSIZE00) % YSIZE; + x = (obj->posx - sgn(obj->velx) + XSIZE00) % XSIZE; + while (occupant[y][x]) { + y = (y + rand_mod(3) - 1 + YSIZE00) % YSIZE; + x = (x + rand_mod(3) - 1 + XSIZE00) % XSIZE; + if (++count > 10000) { /* if universe full, get out of it fast */ + unmake_object(obj); + if (ent) unmake_object(ent); + if (base) unmake_object(base); + finish = 1; + return; + } + } + obj->posy = y; + obj->posx = x; + obj->vely = 0; + obj->velx = 0; + occupant[y][x] = obj; + if (numamoebas && obj->image == ' ') + mvaddc(y+1, x*2, amb[y][x]); + else + mvaddc(y+1, x*2, obj->image); +} + +void +move_universe() +{ + register OBJECT *curobj; + register int x; + register int y; + register OBJECT *temp; + OBJECT *thenext; + + for (curobj = movers; curobj != &root; curobj = curobj->next) { + x = curobj->posx; + y = curobj->posy; + if (curobj == occupant[y][x]) { + occupant[y][x] = 0; + } + else if (curobj->type != Torp && curobj->type != Web) { + resetty(); + abort(); + } + } + for (curobj = movers; curobj != &root; curobj = thenext) { + thenext = curobj->next; + if (curobj->vely || curobj->velx) { + y = curobj->posy; + x = curobj->posx; + if (curobj->image != ' ' && + (!(temp=occupant[y][x]) || temp->image==' ') ) { + move(y+1, x*2, numamoebas ? amb[y][x] : ' '); + } + y = (y + curobj->vely + YSIZE00) % YSIZE; + x = (x + curobj->velx + XSIZE00) % XSIZE; + if (!(temp=occupant[y][x]) || temp->type != Star || + curobj->type != Torp || curobj->image == '+' || + curobj->image == 'x') { + curobj->posy = y; + curobj->posx = x; + } + else { + if (curobj->image == '0') { + curobj->vely = rand_mod(3)-1; + curobj->velx = rand_mod(3)-1; + } + else + curobj->vely = curobj->velx = 0; + y = curobj->posy; + x = curobj->posx; + } + } + else { /* not moving */ + y = curobj->posy; + x = curobj->posx; + if (curobj->type == Torp || + curobj->type == Star || + curobj->type == Web) { + curobj->flags |= STATIC; + curobj->next->prev = curobj->prev; + curobj->prev->next = curobj->next; + curobj->prev = movers->prev; + curobj->next = movers; + movers->prev->next = curobj; + movers->prev = curobj; + } + } + if (temp = occupant[y][x]) { /* already occupied? */ + if (!temp->contend) { + if (temp->type == Torp) { + if (temp->image == '+') + blast[y][x] += 1250; + else if (temp->image == 'o' && (base||ent)) + blast[y][x] += 500+super*20; + else if (temp->image == 'O' && (base||ent)) + blast[y][x] += 5000+super*100; + } + } + yblasted[y] |= 1; + xblasted[x] |= 1; + blasted = TRUE; + curobj->contend = temp; + occupant[y][x] = curobj; + switch (curobj->type) { + case Enemy: + if (numamoebas && curobj == nuke && temp->image == '+') + blast[y][x] += 80000; + else if (temp->type == Enemy) + blast[y][x] += 10; + else + goto defblast; + break; + case Crusher: + if (curobj->velx) + blast[y][x] += 100000; + else + goto defblast; + break; + case Torp: + if (curobj->image == '+') + blast[y][x] += (temp==nuke ? 80000 : 1250); + else if (curobj->image == 'o') + blast[y][x] += 500+super*20; + else if (curobj->image == 'O') + blast[y][x] += 5000+super*100; + goto defblast; + case Star: + if (temp == ent) + goto damshield; + goto defblast; + case Enterprise: + if (temp->type == Star) { + damshield: + if (!rand_mod(10)) { + if (!damflag[NOSHIELDS]) + damage++; + if (damflag[NOSHIELDS] < 100) + damflag[NOSHIELDS] += rand_mod(smarts)/5+2; + } + } + goto defblast; + default: + defblast: + blast[y][x] += rand_mod(751)+1; + break; + } + } + else { + occupant[y][x] = curobj; + if (curobj->image != ' ' && + (curobj->velx || curobj->vely || + curobj->type == Torp || curobj->type == Web) ) { + mvaddc(y+1, x*2, curobj->image); + } + if (curobj->type == Crusher && curobj->velx) { + blast[y][x] += 100000; + yblasted[y] |= 1; + xblasted[x] |= 1; + blasted = TRUE; + } + } + } + if (blasted) { + register int minxblast = -1; + register int maxxblast = -2; + register long tmpblast; + + blasted = numamoebas; + for (x=0; ximage == '&') + tmpblast >>= 1; + else if (temp->type == Web) + tmpblast = 100000; + else + tmpblast += 50 + temp->energy/100; + if (tmpblast > 250 && !rand_mod(5+(inumstars>>4))) + modify_amoeba(y,x,1,'~',5); + } + xblasted[x] = 2; + yblasted[y] = 2; + } + if (tmpblast) { + register OBJECT *biggie = 0; + + blast[y][x] = 0; + temp = occupant[y][x]; + if (tmpblast < 0) { + if (numamoebas && tmpblast < -1000000 && + amb[y][x] == '~' && temp != nuke) { + amb[y][x] = ' '; + if (!temp) + make_plink(y,x); + ambsize--; + } + tmpblast = 0; + } + if (temp) { + if ((!numamoebas || amb[y][x]==' ') && + tmpblast < 100000) + make_plink(y,x); + for ( ;temp; + temp = curobj->contend,curobj->contend = 0){ + curobj = temp; + switch (curobj->type) { + case Enterprise: { + long tmp = curobj->energy; + + if (ent->energy>500 || apolloflag & 1) + curobj->energy -= tmpblast / + ((apolloflag & 1) + ? 20 + : (5+abs(ent->velx)+abs(ent->vely)) + / ((damflag[NOSHIELDS]>>3)+1)+1); + else + curobj->energy -= tmpblast; + if (rand_mod(1 + tmp - curobj->energy) > 100 + || ent->energy < (entmax>>1)) { + if (debug & 128 || + (damage <= smarts/10 && + !rand_mod(6-smarts/20-massacre) )) { + tmp = rand_mod(MAXDAMAGE); + if (damflag[tmp]) { + if (damflag[tmp] < 60) + damflag[tmp] += rand_mod(60); + } + else { + damflag[tmp] = + rand_mod(smarts+10)+2; + damage++; + } + } + } + break; + } + case Base: + if (base->energy > 1000 || apolloflag & 2) + curobj->energy -= tmpblast / + ((apolloflag & 2)?20:5); + else + curobj->energy -= tmpblast; + break; + case Crusher: + if (tmpblast > 132767) + curobj->energy -= (tmpblast - 100000); + else if (tmpblast >= 100000) { + curobj->energy += (tmpblast - 100000); + if (curobj->energy > 32767) + curobj->energy = 32767; + } + else /* vulnerable while feeding */ + curobj->energy -= tmpblast; + break; + case Enemy: + curobj->energy -= tmpblast*10/enemshields; + break; + default: + curobj->energy -= tmpblast; + break; + } + if (curobj->energy < 0) { /* killed it? */ + switch (curobj->image) { + case 'A': + tmpblast = 100000; + make_blast(y,x,8192L,1); + numapollos = apolloflag = 0; + numstars--; + numenemies--; + curscore += 5000; + deados = 0; + break; + case 'E': case 'e': case 'C': case 'c': + ent = 0; + numents--; + if (base) + status = 2; + else + status = 3; + deados = 0; + break; + case 'B': case 'b': + base = 0; + numbases--; + if (ent) + status = entmode; + else + status = 3; + deados = 0; + break; + case '&': { + int i, xxx, yyy; + + for (i = 0; i < YSIZE; i++) + yblasted[i] &= 1; + for (i = 0; i < XSIZE; i++) + xblasted[i] &= 1; + numamoebas = 0; /* ignore amb[][] now */ + for (yyy = 0; yyy < YSIZE; yyy++) { + for (xxx = 0; xxx < XSIZE; xxx++) { + if (amb[yyy][xxx] == '~' && + !occupant[yyy][xxx]) { + mvaddch(yyy+1,xxx*2,' '); + } + } + } + numenemies--; + curscore += 10000; + if (curobj == enemies) + enemies = curobj->next; + deados = 0; + break; + } + case '<': case '>': { + int i; + + numenemies--; + numcrushes = 0; + curscore += 10000; + if (curobj == movers) + movers = curobj->next; + if (curobj == enemies) + enemies = curobj->next; + deados = 0; + + tmpblast = 100000; + make_blast(y,(x+XSIZE00)%XSIZE,10000L,0); + if (curobj->image == '<') { + for (i=XSIZE00; i<=XSIZE01; i++) + make_blast(y,(x+i)%XSIZE, + 10000L,0); + for (i=XSIZE00; i<=XSIZE02; i++) + make_blast(y,(x+i)%XSIZE, + 10000L,0); + make_blast(y,(x+XSIZE03)%XSIZE, + 10000L,1); + for (i=XSIZE00; i<=XSIZE08; i++) + make_blast(y,(x+i)%XSIZE, + 10000L,0); + } + else { + for (i=XSIZE00; i>=XSIZE99; i--) + make_blast(y,(x+i)%XSIZE, + 10000L,0); + for (i=XSIZE00; i>=XSIZE98; i--) + make_blast(y,(x+i)%XSIZE, + 10000L,0); + make_blast(y,(x+XSIZE97)%XSIZE, + 10000L,1); + for (i=XSIZE00; i>=XSIZE92; i--) + make_blast(y,(x+i)%XSIZE, + 10000L,0); + } + } + break; + case 'K': + numenemies--; + curscore += curobj->mass; + if (curobj == enemies) + enemies = curobj->next; + deados = 0; + break; + case 'T': + numenemies--; + curscore += curobj->mass*3/2; + if (curobj == enemies) + enemies = curobj->next; + deados = 0; + break; + case 'R': case ' ': case 'P': + numenemies--; + if (curobj->flags & PIRATE) + curscore += curobj->mass; + else + curscore += curobj->mass*3; + if (curobj == enemies) + enemies = curobj->next; + deados = 0; + break; + case 'G': + numenemies--; + numgorns--; + tmpblast = 100000; + if (madgorns) + curscore += curobj->mass/2; + else + curscore += curobj->mass*2; + if (curobj == enemies) + enemies = curobj->next; + { + int xxx,yyy; + + for (xxx = -1; xxx<=1; xxx++) + for (yyy = -1; yyy<=1; yyy++) + if (rand_mod(2+massacre)) + fire_torp(curobj, + yyy,xxx); + } + deados = 0; + break; + case '@': + numinhab--; + /* FALL THROUGH */ + case '*': + banging = TRUE; + numstars--; + break; + case '|': case '-': case '/': case '\\': + tmpblast = 100000; + make_blast(y,x,curobj->mass,1); + banging = TRUE; + deados = 0; + break; + case 'x': + curscore += 10; + deados = 0; + break; + case 'X': + curscore += 100; + numxes--; + deados = 0; + break; + case '0': + curscore += 35; + numos--; + deados += 3; + break; + case 'o': + curscore += 100; + numos--; + deados++; + break; + case 'O': + curscore += 200; + numos--; + deados += 2; + break; + case 'M': + deadmudds++; + inumfriends--; + numfriends--; + if (curobj == enemies) + enemies = curobj->next; + break; + case 'Q': case 'W': case 'Y': case 'U': + case 'I': case 'S': case 'D': case 'H': + case 'J': case 'L': case 'Z': case 'V': + case 'F': + numfriends--; + if (curobj == enemies) + enemies = curobj->next; + if (inumfriends < 10) + madfriends += 500; + else + madfriends += 10000/inumfriends; + break; + } + if (tmpblast < 100000) + make_blast(y,x,curobj->mass,1); + unmake_object(curobj); + } + else { /* didn't kill anything */ + if (!biggie) + biggie = curobj; + else { + if (biggie->mass > curobj->mass) + bounce(curobj); + else { + bounce(biggie); + biggie = curobj; + } + } + } + } + if (biggie) { + occupant[y][x] = biggie; + if (numamoebas && biggie->image == ' ') + mvaddch(y+1,x*2, amb[y][x]); + else + mvaddch(y+1,x*2, biggie->image); + } + else { + occupant[y][x] = 0; + mvaddch(y+1, x*2, numamoebas ? amb[y][x] : ' '); + } + } + } + } + } + } + } + do_bangs(); + if (numcrushes && movers->type == Crusher) + movers->vely = 0; + if (curobj = base) { + char ch; + + curobj->velx = 0; + curobj->vely = 0; + curobj->energy += 25*lookaround(curobj->posy,curobj->posx,Star); + if (curobj->energy > basemax) + curobj->energy = basemax; + if (curobj->energy >= 1000) + ch = 'B'; + else + ch = 'b'; + if (ch != curobj->image) { + setimage(curobj, ch); + } + } + if (curobj = ent) { + char ch; + + if (entmode == 0) { + curobj->velx = 0; + curobj->vely = 0; + } + if (base && !cloaking && !curobj->velx && !curobj->vely && + lookfor(curobj->posy,curobj->posx,Base)) { + int tmp; + + tmp = (int) (base->energy - 1000 < entmax - curobj->energy ? + base->energy - 1000 : entmax - curobj->energy); + if (tmp < 0) + tmp = 0; + curobj->energy += tmp; + base->energy -= tmp; + tmp = (btorp < 50 - etorp ? + btorp : 50 - etorp); + etorp += tmp; + btorp -= tmp; + if (damage) { + tmp = rand_mod(MAXDAMAGE); + if (damflag[tmp] > 5) { + damflag[tmp] = rand_mod(5)+1; + } + } + } + if (curobj->energy >= 500 && (!damage || !damflag[NOSHIELDS])) + ch = cloaked?'C':'E'; + else + ch = cloaked?'c':'e'; + if (ch != curobj->image) { + setimage(curobj, ch); + } + } +} + +int +lookaround(y, x, what) +register int y; +register int x; +register char what; +{ + register OBJECT *obj; + register int count=0; + register int xp; + register int xm; + + if ((obj=occupant[y][xp=(x+XSIZE01)%XSIZE])&&obj->type == what) /* 0, 1 */ + count++; + if ((obj=occupant[y][xm=(x+XSIZE99)%XSIZE])&&obj->type == what) /* 0, -1 */ + count++; + if ((obj=occupant[y=(y+YSIZE99)%YSIZE][xp])&&obj->type == what) /* -1, 1 */ + count++; + if ((obj=occupant[y][x])&&obj->type == what) /* -1, 0 */ + count++; + if ((obj=occupant[y][xm])&&obj->type == what) /* -1, -1 */ + count++; + if ((obj=occupant[y=(y+2)%YSIZE][xp])&&obj->type == what) /* 1, 1 */ + count++; + if ((obj=occupant[y][x])&&obj->type == what) /* 1, 0 */ + count++; + if ((obj=occupant[y][xm])&&obj->type == what) /* 1, -1 */ + count++; + return (count); +} + +int +lookfor(y, x, what) +register int y; +register int x; +register char what; +{ + register OBJECT *obj; + register int xp; + register int xm; + + if ((obj=occupant[y][xp=(x+XSIZE01)%XSIZE])&&obj->type == what ||/* 0, 1 */ + (obj=occupant[y][xm=(x+XSIZE99)%XSIZE])&&obj->type == what ||/* 0, -1 */ + (obj=occupant[y=(y+YSIZE99)%YSIZE][xp])&&obj->type == what ||/* -1, 1 */ + (obj=occupant[y][x])&&obj->type == what ||/* -1, 0 */ + (obj=occupant[y][xm])&&obj->type == what ||/* -1,-1 */ + (obj=occupant[y=(y+2)%YSIZE][xp])&&obj->type == what ||/* 1, 1 */ + (obj=occupant[y][x])&&obj->type == what ||/* 1, 0 */ + (obj=occupant[y][xm])&&obj->type == what) /* 1, -1 */ + return(1); + return (0); +} + +OBJECT* +lookimg(y, x, what) +register int y; +register int x; +register char what; +{ + register OBJECT *obj; + register int xp; + register int xm; + + if ((obj=occupant[y][xp=(x+XSIZE01)%XSIZE])&&obj->image==what ||/* 0, 1 */ + (obj=occupant[y][xm=(x+XSIZE99)%XSIZE])&&obj->image==what ||/* 0, -1 */ + (obj=occupant[y=(y+YSIZE99)%YSIZE][xp])&&obj->image==what ||/* -1, 1 */ + (obj=occupant[y][x])&&obj->image==what ||/* -1, 0 */ + (obj=occupant[y][xm])&&obj->image==what ||/* -1,-1 */ + (obj=occupant[y=(y+2)%YSIZE][xp])&&obj->image==what ||/* 1, 1 */ + (obj=occupant[y][x])&&obj->image==what ||/* 1, 0 */ + (obj=occupant[y][xm])&&obj->image==what) /* 1, -1 */ + return obj; + return Null(OBJECT*); +} diff --git a/src/games/warp/move.h b/src/games/warp/move.h new file mode 100644 index 0000000..60719d8 --- /dev/null +++ b/src/games/warp/move.h @@ -0,0 +1,14 @@ +/* $Header: move.h,v 7.0 86/10/08 15:12:46 lwall Exp $ */ + +/* $Log: move.h,v $ + * Revision 7.0 86/10/08 15:12:46 lwall + * Split into separate files. Added amoebas and pirates. + * + */ + +void bounce(); +void move_universe(); +int lookaround(); +int lookfor(); +OBJECT *lookimg(); +void move_init(); diff --git a/src/games/warp/object.c b/src/games/warp/object.c new file mode 100644 index 0000000..b826c70 --- /dev/null +++ b/src/games/warp/object.c @@ -0,0 +1,78 @@ +/* $Header: object.c,v 7.0 86/10/08 15:12:55 lwall Exp $ */ + +/* $Log: object.c,v $ + * Revision 7.0 86/10/08 15:12:55 lwall + * Split into separate files. Added amoebas and pirates. + * + */ + +#include "EXTERN.h" +#include "warp.h" +#include "INTERN.h" +#include "object.h" + +void +object_init() +{ + ; +} + +OBJECT * +make_object(typ, img, py, px, vy, vx, energ, mas, where) +char typ; +char img; +int px, py, vx, vy; +long energ, mas; +OBJECT *where; +{ + register OBJECT *obj; + + if (free_root.next == &free_root) + obj = (OBJECT *) malloc(sizeof root); + else { + obj = free_root.next; + free_root.next = obj->next; + obj->next->prev = &free_root; + } + obj->type = typ; + obj->image = img; + obj->next = where; + obj->prev = where->prev; + where->prev = obj; + obj->prev->next = obj; + obj->velx = vx; + obj->vely = vy; + obj->contend = 0; + obj->strategy = 0; + obj->flags = 0; + obj->posx = px; + obj->posy = py; + if (typ != Torp && typ != Web) { + occupant[py][px] = obj; + } + obj->energy = energ; + obj->mass = mas; + return(obj); +} + +void +unmake_object(curobj) +register OBJECT *curobj; +{ + curobj->prev->next = curobj->next; + curobj->next->prev = curobj->prev; + if (curobj == movers) { + movers = curobj->next; + } + free_object(curobj); +} + +void +free_object(curobj) +register OBJECT *curobj; +{ + curobj->next = free_root.next; + curobj->prev = &free_root; + free_root.next->prev = curobj; + free_root.next = curobj; +} diff --git a/src/games/warp/object.h b/src/games/warp/object.h new file mode 100644 index 0000000..8784073 --- /dev/null +++ b/src/games/warp/object.h @@ -0,0 +1,67 @@ +/* $Header: object.h,v 7.0.1.2 86/12/12 17:01:38 lwall Exp $ */ + +/* $Log: object.h,v $ + * Revision 7.0.1.2 86/12/12 17:01:38 lwall + * Baseline for net release. + * + * Revision 7.0.1.1 86/10/16 10:52:30 lwall + * Added Damage. Fixed random bugs. + * + * Revision 7.0 86/10/08 15:13:04 lwall + * Split into separate files. Added amoebas and pirates. + * + */ + +#define Root 0 +#define Base 1 +#define Enterprise 2 +#define Star 3 +#define Torp 4 +#define Enemy 5 +#define Web 6 +#define Crusher 7 + +typedef struct object { + char posx, posy; + char velx, vely; + struct object *next, *prev, *contend; + long energy; + long mass; + char type; + char image; + char strategy; + char flags; +} OBJECT; + +#define PIRATE 1 /* we may mutiny */ +#define FRIENDLY 2 /* we aren't really an enemy, for now */ +#define STATIC 4 /* we are not in the movers list at the moment */ +#define COUNTDOWN 8 /* we are counting down for something */ +#define CLOAKS 16 /* we can cloak */ + +#ifdef DOINIT +OBJECT root = {0, 0, 0, 0, &root, &root, 0, 0, 0, Root, '?', 0, 0}; +#else +EXT OBJECT root; +#endif + +#ifdef DOINIT +OBJECT free_root = {0, 0, 0, 0, &free_root, &free_root, 0, 0, 0, Root, '?', 0, 0}; +#else +EXT OBJECT free_root; +#endif + +EXT OBJECT *ent; +EXT OBJECT *base; +EXT OBJECT *enemies; +EXT OBJECT *movers; +EXT OBJECT *realapollo; +EXT OBJECT *nuke; + +EXT OBJECT *occupant[YSIZE][XSIZE]; + +OBJECT *make_object(); + +void unmake_object(); +void free_object(); +void object_init(); diff --git a/src/games/warp/patchlevel.h b/src/games/warp/patchlevel.h new file mode 100644 index 0000000..558d48c --- /dev/null +++ b/src/games/warp/patchlevel.h @@ -0,0 +1 @@ +#define PATCHLEVEL 3 diff --git a/src/games/warp/play.c b/src/games/warp/play.c new file mode 100644 index 0000000..d1e8af3 --- /dev/null +++ b/src/games/warp/play.c @@ -0,0 +1,180 @@ +/* $Header: play.c,v 7.0.1.1 86/10/16 10:52:39 lwall Exp $ */ + +/* $Log: play.c,v $ + * Revision 7.0.1.1 86/10/16 10:52:39 lwall + * Added Damage. Fixed random bugs. + * + * Revision 7.0 86/10/08 15:13:09 lwall + * Split into separate files. Added amoebas and pirates. + * + */ + +#include "EXTERN.h" +#include "warp.h" +#include "bang.h" +#include "score.h" +#include "object.h" +#include "move.h" +#include "term.h" +#include "them.h" +#include "us.h" +#include "util.h" +#include "weapon.h" +#include "INTERN.h" +#include "play.h" + +void +play_init() +{ + ; +} + +void +play() +{ + bool done = FALSE; + register OBJECT *curobj; + register OBJECT *to; + register int i; + register int x; + register int y; + + display_status(); +#ifdef TIOCOUTQ + while (output_pending() > charsperhalfsec) + sleep(1); /* allow buffers to empty */ +#endif + sleep(3); + do { + timer++; + nxtbang = 0; + banging = FALSE; + display_status(); +#ifdef TIOCOUTQ + while (output_pending() > charsperhalfsec) + sleep(1); +#endif + if (lowspeed) + roundsleep(2); + else + roundsleep(1); + if (ent) { + evely = ent->vely; + evelx = ent->velx; + if (cloaking && ent->energy >= 250 && !damflag[NOCLOAKING]) { + if (!rand_mod(300)) { + damage++; + damflag[NOCLOAKING] = rand_mod(smarts+1)+2; + } + ent->energy -= ent->energy/40; + } + else + cloaking = FALSE; + cloaked = cloaking; + } + if (base) { + bvely = base->vely; + bvelx = base->velx; + } + get_commands(&done); + if (done) + break; + their_smarts(); + apolloflag = 0; + if (ent) { + if (numapollos) { + if (numstars) { + if (realapollo) { + if (lookfor(realapollo->posy,realapollo->posx, + Enterprise)) { + apolloflag = 1; + } + } + else if (lookfor(root.next->posy,root.next->posx, + Enterprise)) { + apolloflag = 1; + realapollo = root.next; + mvaddch(realapollo->posy+1,realapollo->posx*2, + 'A'); + realapollo->image = 'A'; + realapollo->mass = 6000; + inumapollos = 1; + numenemies++; + inumenemies++; + possiblescore += 5000; + } + if (apolloflag) { + if (blast[realapollo->posy][realapollo->posx] <= 32000) + evely = evelx = 0; + realapollo->energy = 32000; + } + } + else + numapollos = 0; + } + ent->vely = evely; + ent->velx = evelx; + } + if (base) { + if (numapollos) { + if (numstars) { + if (realapollo) { + if (lookfor(realapollo->posy,realapollo->posx, + Base)) { + apolloflag |= 2; + } + } + else if (lookfor(root.next->posy,root.next->posx, + Base)) { + apolloflag |= 2; + realapollo = root.next; + mvaddch(realapollo->posy+1,realapollo->posx*2, + 'A'); + realapollo->image = 'A'; + realapollo->mass = 6000; + inumapollos = 1; + numenemies++; + inumenemies++; + possiblescore += 5000; + } + if (apolloflag & 2) { + if (blast[realapollo->posy][realapollo->posx] <= 32000) + bvely = bvelx = 0; + realapollo->energy = 32000; + } + } + else + numapollos = 0; + } + base->vely = bvely; + base->velx = bvelx; + } + if (aretorps) { + aretorps = 0; + for (i=0;i<2;i++) for (y=0;y<3;y++) for (x=0;x<3;x++) { + if (curobj = isatorp[i][y][x]) { + to = occupant[(curobj->posy+curobj->vely+YSIZE00)%YSIZE] + [(curobj->posx+curobj->velx+XSIZE00)%XSIZE]; + if (to && !to->vely && !to->velx) { + unmake_object(curobj); + if (i) + btorp++; + else + etorp++; + } + isatorp[i][y][x]=0; + } + } + } + move_universe(); + if (finish) { + finish--; + if (!finish && (!(numenemies || numos) || (!ent && !base))) { + done = TRUE; + timer -= 5; + } + } + else if (!banging && (!(numenemies || numos) || (!ent && !base))) + finish = 5; + } while (!done); +} diff --git a/src/games/warp/play.h b/src/games/warp/play.h new file mode 100644 index 0000000..1092cf0 --- /dev/null +++ b/src/games/warp/play.h @@ -0,0 +1,13 @@ +/* $Header: play.h,v 7.0 86/10/08 15:13:12 lwall Exp $ */ + +/* $Log: play.h,v $ + * Revision 7.0 86/10/08 15:13:12 lwall + * Split into separate files. Added amoebas and pirates. + * + */ + +EXT int finish INIT(0); +EXT int timer; + +void play(); +void play_init(); diff --git a/src/games/warp/score.c b/src/games/warp/score.c new file mode 100644 index 0000000..513d007 --- /dev/null +++ b/src/games/warp/score.c @@ -0,0 +1,694 @@ +/* $Header: /usr/src/games/warp/RCS/score.c,v 1.1.1 95/01/21 02:13:26 games Exp $ */ + +/* $Log: score.c,v $ + * Revision 7.0.1.2a 87/07/03 02:13:26 games + * Fixed numerous long vs. int bugs in printfs, etc. + * + * Revision 7.0.1.2 86/10/20 12:06:56 lwall + * Made all exits reset tty. + * + * Revision 7.0.1.1 86/10/16 10:52:47 lwall + * Added Damage. Fixed random bugs. + * + * Revision 7.0 86/10/08 15:13:14 lwall + * Split into separate files. Added amoebas and pirates. + * + */ + +#include "EXTERN.h" +#include "warp.h" +#include "intrp.h" +#include "object.h" +#include "play.h" +#include "sig.h" +#include "term.h" +#include "us.h" +#include "util.h" +#include "weapon.h" +#include "INTERN.h" +#include "score.h" +#include +#include +#include + +void +score_init() +{ + register char *s; + register int i; + FILE *savfil; + + if (stat(SAVEDIR,&filestat)) { + printf("Cannot access %s\r\n",SAVEDIR); + finalize(1); + } + if (filestat.st_uid != geteuid()) { + printf("Warp will not run right without being setuid.\r\n"); + finalize(1); + } + if ((filestat.st_mode & 0605) != 0605) { + printf("%s is not protected correctly (must be u+rw o+rx).\r\n",SAVEDIR); + finalize(1); + } + + interp(longlognam, sizeof longlognam, "%L"); + for (i=strlen(longlognam); i<8; i++) + longlognam[i] = ' '; /* make sure it is 8 long for strncmp */ + longlognam[8] = '\0'; + + if (scorespec) + wscore(); + + Sprintf(savefilename, "save.%s", logname); + + savfil = experimenting ? NULL : fopen(savefilename,"r"); + if (savfil != NULL && fgets(spbuf,100,savfil) != NULL) { + char tmpbuf[80]; + + spbuf[strlen(spbuf)-1] = '\0'; + if (fgets(tmpbuf,80,savfil) != NULL) { + int processnum; + + tmpbuf[strlen(tmpbuf)-1] = '\0'; + printf("You seem to have left a game %s.\r\n",tmpbuf+9); + s = strchr(tmpbuf+9, ','); + *s = '\0'; + processnum = atoi(s+11); + if (kill(processnum, SIGINT)) { + /* does process not exist? */ + /* (warp ignores SIGINT) */ + printf("\r\n\ +That process does not seem to exist anymore, so you'll have to start the\r\n"); + printf( +"last wave over.\r\n\n"); + printf( +" [type anything to continue]"); + Fflush(stdout); + eat_typeahead(); + getcmd(tmpbuf); + if (*tmpbuf == INTRCH) + finalize(0); + printf("\r\n"); + } + else { + if (strcmp(term+8,tmpbuf+23)) { + printf( +"That is not your current terminal--you are on %s.\r\n", term+5); + printf("\r\nYour options:\r\n"); + printf(" 1) Exit and find the terminal it's running on\r\n"); + } + else { + printf("\r\nYour options:\r\n"); + printf(" 1) Exit and try to foreground it\r\n"); + } + printf(" 2) Let me terminate the other game\r\n\n"); + printf("What do you want to do? "); + Fflush(stdout); + eat_typeahead(); + getcmd(tmpbuf); + printf("\r\n"); + if (*tmpbuf == INTRCH) + finalize(0); + if (*tmpbuf == '1') { + printf( +"If you don't succeed, come back and do option 2 instead. Good luck.\r\n"); + finalize(0); + } + printf( +"Ok, hang on a few moments \r\n"); + Fclose(savfil); + if (kill(processnum, SIGQUIT)) { + printf("Unable to kill process #%d!\r\n",processnum); + roundsleep(2); + } + else { +#ifdef SIGCONT + kill(processnum, SIGCONT); +#endif + for (i=15; i; --i) { + sleep(1); + if (kill(processnum,SIGINT)) + /* does process not exist? */ + /* (warp ignores SIGINT) */ + break; + } + didkill++; + } + savfil = fopen(savefilename,"r"); + if (savfil != NULL) { + if (fgets(spbuf,100,savfil) == 0) + /*ignore*/; + } + } + } + } + else + savfil = NULL; + if (savfil == NULL) { + totalscore = smarts = cumsmarts = wave = 0; + numents = 5; + numbases = 3; + } + else { + totalscore = atol(spbuf+9); + smarts = atoi(spbuf+20); + cumsmarts = atoi(spbuf+24); + numents = atoi(spbuf+30); + numbases = atoi(spbuf+33); + wave = atoi(spbuf+36); + apolspec = (spbuf[40] == 'a'); + beginner = (spbuf[41] == 'b'); + crushspec = (spbuf[42] == 'c'); + gornspec = (spbuf[43] == 'g'); + massacre = (spbuf[44] == 'm'); + romspec = (spbuf[45] == 'r'); + tholspec = (spbuf[46] == 't'); + lowspeed = (spbuf[47] == 'l') || lowspeed; + amoebaspec = (spbuf[48] == '&'); + Fclose(savfil); + } + + if (!ismarts) { + ismarts = 1; + clear(); + page(NEWSFILE,FALSE); + if (smarts) { + printf("\r\nSaved game: SCORE DIFF CUMDIFF ENTERPRISES BASES WAVE"); + printf("\r\n %7ld %2d %4d %1d %1d %3d", + totalscore,smarts,cumsmarts,numents,numbases,wave); + } + printf("\r\nWould you like instructions? "); + Fflush(stdout); + eat_typeahead(); + getcmd(buf); + printf("\r\n"); + if (*buf == INTRCH) + finalize(0); + if (*buf == 'Y' || *buf == 'y') { + page(HELPFILE,FALSE); + printf("\r\nWould you like to play easy games for a while? "); + Fflush(stdout); + eat_typeahead(); + getcmd(buf); + printf("\r\n"); + if (*buf == 'Y' || *buf == 'y') { + beginner = TRUE; + lowspeed = TRUE; + } + } + } + if (!smarts) + smarts = ismarts; +} + +void +wscore() +{ + clear(); + printf(" TOP WARPISTS\r\n\n"); + printf("RANK WHO AKA SCORE DIFF CUMDIFF WHEN\r\n"); + page(SCOREBOARD,TRUE); + printf(" [Type anything to continue]"); + Fflush(stdout); + getcmd(spbuf); + if (*spbuf == INTRCH) + finalize(0); + clear(); + printf(" TOP LOW-SPEED WARPISTS\r\n\n"); + printf("RANK WHO AKA SCORE DIFF CUMDIFF WHEN\r\n"); + page(LSCOREBOARD,TRUE); + printf(" [Type anything to continue]"); + Fflush(stdout); + getcmd(spbuf); + if (*spbuf == INTRCH) + finalize(0); + clear(); + printf(" TOP FUNNY WARPISTS\r\n\n"); + printf("RANK WHO AKA SCORE DIFF CUMDIFF WHEN\r\n"); + page(FSCOREBOARD,TRUE); + printf(" [Type anything to continue]"); + Fflush(stdout); + getcmd(spbuf); + if (*spbuf == INTRCH) + finalize(0); + clear(); + printf(" GAMES SAVED OR IN PROGRESS\r\n\n"); + printf("WHO SCORE DF CDF E B WV FLAGS\r\n"); + resetty(); + Sprintf(spbuf,"/bin/cat %ssave.*",SAVEDIR); + execl("/bin/sh", "sh", "-c", spbuf, (char*)0); + finalize(1); +} + + +void +display_status() +{ + register int tmp; + static char *status_names[] = {"Impl", "Warp", "Base", "****" }; + + if (oldstatus != status) { + Sprintf(spbuf,"%-4s",status_names[status]); + mvaddstr(0,0, spbuf); + oldstatus = status; + } + if (ent) { + if (ent->energy != oldeenergy) { + oldeenergy = ent->energy; + Sprintf(spbuf,"%4ld",oldeenergy); + mvaddstr(0,8, spbuf); + } + if (etorp != oldetorp) { + Sprintf(spbuf,"%2d",etorp); + mvaddstr(0,13, spbuf); + oldetorp = etorp; + } + } + else { + if (etorp >= 0) { + etorp = -1; + mvaddstr(0,8,"*******"); + damage = 0; + } + } + if (base) { + if (base->energy != oldbenergy) { + oldbenergy = base->energy; + Sprintf(spbuf,"%5ld",oldbenergy); + mvaddstr(0,19, spbuf); + } + if (btorp != oldbtorp) { + Sprintf(spbuf,"%3d",btorp); + mvaddstr(0,25, spbuf); + oldbtorp = btorp; + } + } + else { + if (btorp >= 0) { + btorp = -1; + mvaddstr(0,19,"*********"); + } + } + if (damage) { + if (!olddamage) + mvaddstr(0,42,"*** "); + if (damage > 1 || !damflag[dam]) { + do { + if (++dam == MAXDAMAGE) + dam = 0; + } while (!damflag[dam]); + } + if (!--damflag[dam]) { + olddamage = damage; + damage--; + Sprintf(spbuf,"%s OK *** ",dammess[dam]); + spbuf[15] = '\0'; + mvaddstr(0,46,spbuf); + } + else if (dam == NOSHIELDS) { + olddamage = damage; + tmp = (34 - damflag[dam]) * 3 - rand_mod(3); + if (tmp < 0) + tmp = 0; + Sprintf(spbuf,"%d%% %s *** ",tmp,dammess[dam]); + spbuf[15] = '\0'; + mvaddstr(0,46,spbuf); + } + else if (dam != lastdam || !olddamage) { + olddamage = damage; + Sprintf(spbuf,"NO %s *** ",dammess[dam]); + spbuf[15] = '\0'; + mvaddstr(0,46,spbuf); + } + if (status < 2) { + if (dam == NOIMPULSE && !entmode) + status = entmode = 1; + if (dam == NOWARP && entmode) + status = entmode = 0; + } + tmp = damflag[dam] * damage; + Sprintf(spbuf,"%3d.%1d ETR",tmp/10,tmp%10); + mvaddstr(0,69,spbuf); + lastdam = dam; + } + else { + if (olddamage) { + Sprintf(spbuf,"Stars: %-3d Stardate",numstars); + mvaddstr(0,42,spbuf); + lastdam = -1; + olddamage = 0; + oldcurscore = -1; + } + else if (numstars != oldstrs) { + Sprintf(spbuf,"%-3d",numstars); + mvaddstr(0,49, spbuf); + } + oldstrs = numstars; + } + if (numenemies != oldenemies) { + Sprintf(spbuf,"%-3d",numenemies); + mvaddstr(0,38, spbuf); + oldenemies = numenemies; + } + if (tmp = timer%10) { + Sprintf(spbuf,"%1d",tmp); + mvaddstr(0,67, spbuf); + } + else { + Sprintf(spbuf,"%5d.%1d",timer/10+smarts*100,tmp); + mvaddstr(0,61, spbuf); + } + if ((!damage || !damflag[dam]) && curscore != oldcurscore) { + Sprintf(spbuf,"%9ld",curscore); + mvaddstr(0,69, spbuf); + oldcurscore = curscore; + } +} + +void +wavescore() +{ + double power, effectscore, starscore, pi_over_2; + long bonuses; + long tmp; + FILE *mapfp; + int row; + + clear(); + if (curscore > possiblescore) + curscore = possiblescore; + pi_over_2 = 3.14159265 / 2.0; + power = pow((double)inumenemies+ /* total number of enemies */ + inumroms*2+ /* count roms 3 times */ + inumgorns+ /* count gorns 2 times */ + inumthols+ /* count thols 2 times */ + inumapollos*4+ /* count apollo 5 times */ + inumcrushes*3+ /* count crushers 4 times */ + inumamoebas*5 /* count amoebas 6 times */ + , 0.50) * /* skew it a little */ + (double)smarts; /* average energy and intelligence */ + if (inumstars < 350 && inumenemies > 5) + power += (350.0 - (double)inumstars) * ((double)inumenemies - 5.0); + if (inumstars > 850 && inumenemies > 2) + power += ((double)inumstars - 850.0) * ((double)inumenemies - 2.0); + effectscore = ((double)curscore / possiblescore) * + atan2(power, (double) timer + 1.0) / pi_over_2; + if (inumstars) + starscore = (double) numstars / (double) inumstars; + else + starscore = 1.0; + wave++; + Sprintf(spbuf,"Wave = %d, Difficulty = %d, cumulative difficulty = %d", + wave, smarts, cumsmarts); + mvaddstr(1, 13+(smarts<10), spbuf); + mvaddstr( 4, 68, " BONUS"); + Sprintf(spbuf,"Efficiency rating: %1.8f (diff=%0.2f,time=%d)", + effectscore, power, timer + 1); + mvaddstr( 5,5, spbuf); + if (effectscore < 0.8) + bonuses = tmp = 0; + else + bonuses = tmp = (long) ((effectscore-0.8) * smarts * 1000); + Sprintf(spbuf, "%6ld", tmp); + mvaddstr( 5, 68, spbuf); + Sprintf(spbuf,"Star save ratio: %1.8f (%d/%d)", + starscore, numstars, inumstars); + mvaddstr( 6,5, spbuf); + bonuses += tmp = (long) (((double)curscore / possiblescore) * + (starscore*starscore) * smarts * 20); + Sprintf(spbuf, "%6ld", tmp); + mvaddstr( 6, 68, spbuf); + row = 7; + if (inuminhab != numinhab) { + Sprintf(spbuf, "Inhabited stars depopulated: %5d", inuminhab-numinhab); + mvaddstr(row,5, spbuf); + bonuses += tmp = (long) (inuminhab-numinhab) * -500; + Sprintf(spbuf, "%6ld", tmp); + mvaddstr(row, 68, spbuf); + row++; + } + if (inumfriends != numfriends) { + Sprintf(spbuf, "Friendly craft destroyed: %5d", + inumfriends-numfriends); + mvaddstr(row,5, spbuf); + bonuses += tmp = (long) (inumfriends-numfriends) * -250; + Sprintf(spbuf, "%6ld", tmp); + mvaddstr(row, 68, spbuf); + row++; + } + if (deadmudds) { + mvaddstr(row,5,"For destroying Harry Mudd:"); + bonuses += tmp = (long) rand_mod(deadmudds * 20 + 1) - deadmudds*10; + Sprintf(spbuf, "%6ld", tmp); + mvaddstr(row, 68, spbuf); + row++; + } + if (bombed_out) { + mvaddstr(row,5, "For running away from reality:"); + bonuses += tmp = (long) -possiblescore/2; + Sprintf(spbuf, "%6ld", tmp); + mvaddstr(row, 68, spbuf); + row++; + } + if (row < 9) + row++; + Sprintf(spbuf, "Enterprise: %-9s%5d remaining", + !ient?"":ent?"saved":"destroyed", numents); + mvaddstr(row,5, spbuf); + bonuses += tmp = ent && !bombed_out ? (smarts+1)*15 : 0; + Sprintf(spbuf, "%6ld", tmp); + mvaddstr(row, 68, spbuf); + row++; + Sprintf(spbuf, "Base: %-9s %5d remaining", + !ibase?"":base?"saved":"destroyed", numbases); + mvaddstr(row,5, spbuf); + bonuses += tmp = base && !bombed_out ? (smarts+1)*10 : 0; + Sprintf(spbuf, "%6ld", tmp); + mvaddstr(row, 68, spbuf); + if (beginner) { + mvaddstr(13+(row>11),19, "(Special games count only a tenth as much)"); + curscore /= 10; + bonuses /= 10; + } + Sprintf(spbuf, "Previous point total:%10ld",lastscore); + mvaddstr(15,24, spbuf); + Sprintf(spbuf, "Points this round: %10ld",curscore); + mvaddstr(16,24, spbuf); + Sprintf(spbuf, "Bonuses: %10ld",bonuses); + mvaddstr(17,24, spbuf); + totalscore = lastscore + curscore + bonuses; + Sprintf(spbuf, "New point total: %10ld",totalscore); + mvaddstr(18,24, spbuf); + if (lastscore / ENTBOUNDARY < totalscore / ENTBOUNDARY) { + mvaddstr(row-1,42,"+ 1 new"); + numents++; + } + else if (numents>0 && + lastscore / ENTBOUNDARY > totalscore / ENTBOUNDARY) { + mvaddstr(row-1,42,"- 1 obsolete"); + numents--; + } + if (lastscore / BASEBOUNDARY < totalscore / BASEBOUNDARY) { + mvaddstr(row,42,"+ 1 new"); + numbases++; + } + else if (numbases>0 && + lastscore / BASEBOUNDARY > totalscore / BASEBOUNDARY) { + mvaddstr(row,42,"- 1 obsolete"); + numbases--; + } + if (starscore < 0.8 && inumstars > 200 && numstars > 50) { + Sprintf(spbuf, "smap.%d",rand_mod(MAPS-PERMMAPS)+PERMMAPS); + if ((mapfp = fopen(spbuf,"w")) != NULL) { + register OBJECT *obj; + + fprintf(mapfp,"%d\n",numstars); + for (obj = root.next; obj != &root; obj = obj->next) { + if (obj->type == Star) { + fprintf(mapfp,"%d %d\n",obj->posy,obj->posx); + } + } + Fclose(mapfp); + } + } +} + +void +score() +{ + char tmp, *retval, cdate[30]; + register FILE *logfd; + register FILE *outfd; + register int i; + long nowtime; + char *scoreboard; + + for (i=0; link(LOGFILE, LOCKFILE) == -1 && i<10; i++) + sleep(1); + nowtime = time((long *)0); + strcpy(cdate,ctime(&nowtime)); + if ((logfd = fopen(LOGFILE,"a")) != NULL) { + fprintf(logfd, + "%-24s%-9s%7ld%c%2d %4d %s", + realname, logname, totalscore, c,smarts, cumsmarts, cdate); + Fclose(logfd); + } + strcpy(cdate+11,cdate+20); + if (beginner) + scoreboard = FSCOREBOARD; + else if (lowspeed) + scoreboard = LSCOREBOARD; + else + scoreboard = SCOREBOARD; + if (eaccess(scoreboard,0)) { + if ((logfd = fopen(scoreboard,"w")) != NULL) + Fclose(logfd); + } + if ((logfd = fopen(scoreboard,"r")) != NULL && + (outfd = fopen(TMPSCOREBOARD,"w")) != NULL) { + for (i=0; i<20; i++) { + if ((retval = fgets(buf, 100, logfd)) == NULL) + break; + if (atol(buf+32) < totalscore) + break; + if (strnEQ(buf+COMPOFF,COMPNAME,COMPLEN)) { + i = 100; + break; + } + fprintf(outfd, "%s", buf); + } + if (i == 100) { + mvaddstr(20,21, "You did not better your previous score"); + Fclose(outfd); + unlink(TMPSCOREBOARD); + } + else if (i < 20) { + fprintf(outfd, "%-24s%-8s%8ld%c %2d %4d %s", + realname, logname, totalscore, c,smarts, cumsmarts, cdate); + i++; + Sprintf(spbuf, " Congratulations--you've placed %d%s", + i, i==1?"st":(i==2?"nd":(i==3?"rd":"th"))); + if (retval != NULL) { + if (strnNE(buf+COMPOFF,COMPNAME,COMPLEN)) { + fprintf(outfd, "%s", buf); + i++; + } + else + strcpy(spbuf,"Congratulations--you've bettered your score"); + while (i<20) { + if (fgets(buf, 100, logfd) == NULL) + break; + if (strnNE(buf+COMPOFF,COMPNAME,COMPLEN)) { + fprintf(outfd, "%s", buf); + i++; + } + } + } + mvaddstr(20,19, spbuf); + Fclose(logfd); + Fclose(outfd); + while (unlink(scoreboard) == 0) + ; + link(TMPSCOREBOARD,scoreboard) >= 0; + unlink(TMPSCOREBOARD); + logfd = fopen(scoreboard,"r"); + } + else { + mvaddstr(20,22,"You did not place within the top 20"); + Fclose(outfd); + } + } + else { + Sprintf(spbuf,"(Cannot access %s file, error %d)", + (logfd==NULL?"log":"tmp"),errno); + mvaddstr(20,22,spbuf); + } + move(23,0,0); + erase_eol(); + mvaddstr(23,11, + "[Hit space for scoreboard, 'r' for new game, 'q' to quit]"); + unlink(LOCKFILE); + Fflush(stdout); + eat_typeahead(); + do { + getcmd(&tmp); + } while (tmp != INTRCH && tmp != BREAKCH && !strchr(" rqQ",tmp)); + if (strchr("qQr",tmp)) { + justonemoretime = (tmp == 'r'); + if (logfd != NULL) + Fclose(logfd); + } + else { + clear(); + if (logfd != NULL) { + fseek(logfd, 0L, 0); + if (beginner) + mvaddstr(0,31,"TOP FUNNY WARPISTS"); + else if (lowspeed) + mvaddstr(0,29,"TOP LOW-SPEED WARPISTS"); + else + mvaddstr(0,33,"TOP WARPISTS"); + mvaddstr(2,0,"RANK WHO AKA SCORE DIFF CUMDIFF WHEN"); + for (i=1; i<=20; i++) { + if (fgets(buf, 100, logfd) == NULL) + break; + buf[strlen(buf)-1] = '\0'; + Sprintf(spbuf, " %2d %s", i, buf); + mvaddstr(i+2,0, spbuf); + } + Fclose(logfd); + } + roundsleep(1); + mvaddstr(23,25,"Would you like to play again?"); + eat_typeahead(); + do { + getcmd(&tmp); + } while (tmp != INTRCH && tmp != BREAKCH && !strchr("nNyY \n\r",tmp)); + if (tmp == 'n' || tmp == 'N' || tmp == INTRCH || tmp == BREAKCH) + justonemoretime = FALSE; + } + + smarts = ismarts; + totalscore = cumsmarts = wave = 0; + numents = 5; + numbases = 3; + apolspec = FALSE; + beginner = FALSE; + crushspec = FALSE; + gornspec = FALSE; + massacre = (ismarts >= 40); + romspec = FALSE; + tholspec = FALSE; +} + +void +save_game() +{ + FILE *savfil; + + if (experimenting) + return; + if ((savfil = fopen(savefilename,"w")) == NULL) { + resetty(); + printf("Cannot save game\r\n"); + finalize(1); + } + fprintf(savfil, "%-8s %10ld, %2d,%5d,%2d,%2d,%3d %c%c%c%c%c%c%c%c\n", + logname, totalscore, smarts, cumsmarts, numents, numbases, wave, + apolspec ? 'a' : ' ', + beginner ? 'b' : ' ', + crushspec ? 'c' : ' ', + gornspec ? 'g' : ' ', + massacre ? 'm' : ' ', + romspec ? 'r' : ' ', + tholspec ? 't' : ' ', + lowspeed ? 'l' : ' ', + amoebaspec ? '&' : ' ' + ); + Fclose(savfil); + resetty(); + if (panic) + finalize(0); + clear(); + finalize(0); +} diff --git a/src/games/warp/score.h b/src/games/warp/score.h new file mode 100644 index 0000000..76acdac --- /dev/null +++ b/src/games/warp/score.h @@ -0,0 +1,49 @@ +/* $Header: score.h,v 7.0 86/10/08 15:13:21 lwall Exp $ */ + +/* $Log: score.h,v $ + * Revision 7.0 86/10/08 15:13:21 lwall + * Split into separate files. Added amoebas and pirates. + * + */ + +#define ENTBOUNDARY 100000 /* point boundary across which a new E is + awarded */ + +#define BASEBOUNDARY 250000 /* point boundary across which a new B is + awarded */ + +EXT int oldstatus; +EXT int oldetorp; +EXT int oldbtorp; +EXT int oldstrs; +EXT int oldenemies; + +EXT long totalscore; +EXT long lastscore INIT(0); +EXT long curscore; +EXT long possiblescore; +EXT long oldeenergy; +EXT long oldbenergy; +EXT long oldcurscore; + +EXT char savefilename[40]; + +#ifdef SCOREFULL +#define COMPOFF 0 +#define COMPNAME longlognam +#define COMPLEN 24 +#else +#define COMPOFF 24 +#define COMPNAME longlognam +#define COMPLEN 8 +#endif +EXT char longlognam[128]; + +EXT char c INIT(' '); + +void score_init(); +void wscore(); +void display_status(); +void wavescore(); +void score(); +void save_game(); diff --git a/src/games/warp/sig.c b/src/games/warp/sig.c new file mode 100644 index 0000000..93d3be6 --- /dev/null +++ b/src/games/warp/sig.c @@ -0,0 +1,220 @@ +/* $Header: /usr/src/games/warp/RCS/sig.c,v 1.1 87/07/03 01:47:11 games Exp $ */ + +/* $Log: sig.c,v $ + * Revision 7.0.1.2 99/10/24 + * Update to sigprocmask. + * + * Revision 7.0.1.1a 87/07/03 01:47:11 games + * Changed sigsetmask to use sigmask instead of calculating it (incorrectly) + * by hand. + * + * Revision 7.0.1.1 86/12/12 17:02:44 lwall + * Baseline for net release. + * + * Revision 7.0 86/10/08 15:13:24 lwall + * Split into separate files. Added amoebas and pirates. + * + */ + +#include "EXTERN.h" +#include "warp.h" +#include "play.h" +#include "score.h" +#include "term.h" +#include "util.h" +#include "INTERN.h" +#include "sig.h" + +void +sig_init() +{ + sigignore(SIGINT); /* for inquiry of existence via kill call */ +#ifdef SIGTTOU + sigignore(SIGTTOU); +#endif + + sigset(SIGHUP, sig_catcher); + if (!debugging) { + sigset(SIGQUIT, sig_catcher); + sigset(SIGILL, sig_catcher); + sigset(SIGFPE, sig_catcher); + sigset(SIGBUS, sig_catcher); + sigset(SIGSEGV, sig_catcher); + sigset(SIGSYS, sig_catcher); + sigset(SIGTERM, sig_catcher); + } +#ifdef SIGXCPU + sigset(SIGXCPU, sig_catcher); +#endif +#ifdef SIGCONT + sigset(SIGCONT, cont_catcher); +#endif +#ifdef SIGTSTP + sigset(SIGTSTP, stop_catcher); + sigset(SIGSTOP, stop_catcher); +#endif +} + +#ifdef SIGTSTP +void +cont_catcher() +{ + sigset(SIGCONT,cont_catcher); + savetty(); + crmode(); + raw(); + noecho(); + nonl(); +} +#endif + +void +mytstp() +{ + resetty(); +#ifdef SIGTSTP + kill(0,SIGTSTP); +#else + if (fork()) + wait(0); + else { + char *shell = getenv("SHELL"); + + setuid(getuid()); + if (!*shell) + shell = "/bin/sh"; + execl(shell,shell,0); + exit(1); + } +#endif + rewrite(); +} + +void /* very much void */ +finalize(status) +int status; +{ + if (bizarre) + resetty(); + if (status < 0) { + chdir("/usr/tmp"); + sigset(SIGILL,SIG_DFL); + abort(); + } + exit(status); +} + +/* come here on signal other than interrupt, stop, or cont */ + +void +sig_catcher(signo) +{ +#ifdef VERBOSE + static char *signame[] = { + "", + "HUP", + "INT", + "QUIT", + "ILL", + "TRAP", + "IOT", + "EMT", + "FPE", + "KILL", + "BUS", + "SEGV", + "SYS", + "PIPE", + "ALRM", + "TERM", + "???" +#ifdef SIGTSTP + ,"STOP", + "TSTP", + "CONT", + "CHLD", + "TTIN", + "TTOU", + "TINT", + "XCPU", + "XFSZ" +#ifdef SIGPROF + ,"VTALARM", + "PROF" +#endif +#endif + }; +#endif + +#ifdef SIGTTOU + sigignore(SIGTTOU); +#endif +#ifdef DEBUGGING + if (debug) { + printf("\r\nSIG%s--game not saved in debug\r\n",signame[signo]); + finalize(-1); + } +#endif + panic++; + if (panic >= 2) { + if (panic >= 3) + abort(); + chdir(SAVEDIR); + kill(0,SIGIOT); + } + (void) sigset(SIGILL,SIG_DFL); + if (signo == SIGHUP && (timer < 10 || didkill)) + signo = SIGQUIT; + if (signo == SIGQUIT) { /* can't let them bomb out without penalty */ + if (smarts < 20) + smarts += 4; + else if (smarts < 35) + smarts += 2; + else + smarts++; + totalscore -= possiblescore / 2; + } + save_game(); + if (signo != SIGHUP && signo != SIGQUIT) +#ifdef VERBOSE + IF(verbose) + printf("\r\nCaught %s%s--%s\r\n", + signo ? "a SIG" : "an internal error", signame[signo], + experimenting ? "game saved" : "bye bye"); + ELSE +#endif +#ifdef TERSE + printf("\r\nSignal %d--bye bye\r\n",signo); +#endif + switch (signo) { + case SIGBUS: + case SIGILL: + case SIGSEGV: + finalize(-signo); + } + finalize(1); /* and blow up */ +} + +#ifdef SIGTSTP +/* come here on stop signal */ + +void +stop_catcher() +{ + sigset_t set; + + if (!waiting) { + resetty(); /* this is the point of all this */ +#ifdef DEBUGGING + if (debug) + write(2,"stop_catcher\r\n",13); +#endif + sigset(SIGTSTP,SIG_DFL); /* enable stop */ + sigemptyset(&set); + sigaddset(&set, SIGTSTP); + (void)sigprocmask(SIG_UNBLOCK, &set, NULL); + kill(0,SIGTSTP); /* and do the stop */ + } + sigset(SIGTSTP,stop_catcher); /* unenable the stop */ +} +#endif diff --git a/src/games/warp/sig.h b/src/games/warp/sig.h new file mode 100644 index 0000000..e36aeb2 --- /dev/null +++ b/src/games/warp/sig.h @@ -0,0 +1,16 @@ +/* $Header: sig.h,v 7.0 86/10/08 15:13:32 lwall Exp $ */ + +/* $Log: sig.h,v $ + * Revision 7.0 86/10/08 15:13:32 lwall + * Split into separate files. Added amoebas and pirates. + * + */ + +void sig_catcher(); +#ifdef SIGTSTP +void cont_catcher(); +void stop_catcher(); +#endif +void mytstp(); +void sig_init(); +void finalize(); diff --git a/src/games/warp/sm.c b/src/games/warp/sm.c new file mode 100644 index 0000000..b58da8f --- /dev/null +++ b/src/games/warp/sm.c @@ -0,0 +1,90 @@ +/* $Header: sm.c,v 7.0 86/10/08 15:13:35 lwall Exp $ */ + +/* $Log: sm.c,v $ + * Revision 7.0 86/10/08 15:13:35 lwall + * Split into separate files. Added amoebas and pirates. + * + */ +#include +#include +#include + +int main() +{ + char screen[23][90]; + register int y; + register int x; + int tmpy, tmpx; + + for (x=0; x<79; x++) + screen[0][x] = ' '; + screen[0][79] = '\0'; + + if (fgets(screen[0], 90, stdin) == 0) { + perror("stdin"); + return 1; + } + if (isdigit(screen[0][0])) { + int numstars = atoi(screen[0]); + + for (y=0; y<23; y++) { + for (x=0; x<79; x++) + screen[y][x] = ' '; + screen[y][79] = '\0'; + } + + for ( ; numstars; numstars--) { + if (scanf("%d %d\n", &tmpy, &tmpx) != 2) { + perror("two numbers expected"); + return 1; + } + + y = tmpy; + x = tmpx; + screen[y][x+x] = '*'; + } + + for (y=0; y<23; y++) { + printf("%s\n",screen[y]); + } + } + else { + register int numstars = 0; + + for (y=1; y<23; y++) { + for (x=0; x<79; x++) + screen[y][x] = ' '; + screen[y][79] = '\0'; + } + + for (y=1; y<23; y++) { + if (fgets(screen[y], 90, stdin) == 0) { + perror("stdin"); + return 1; + } + } + + for (y=0; y<23; y++) { + for (x=0; x<80; x += 2) { + if (screen[y][x] == '*') { + numstars++; + } + else if (screen[y][x] == '\t' || screen[y][x+1] == '\t') { + fprintf(stderr,"Cannot have tabs in starmap--please expand.\n"); + exit(1); + } + } + } + + printf("%d\n",numstars); + + for (y=0; y<23; y++) { + for (x=0; x<80; x += 2) { + if (screen[y][x] == '*') { + printf("%d %d\n",y,x/2); + } + } + } + } + exit(0); +} diff --git a/src/games/warp/smp.0 b/src/games/warp/smp.0 new file mode 100644 index 0000000..13e075f --- /dev/null +++ b/src/games/warp/smp.0 @@ -0,0 +1,23 @@ +* * * * * * * * * * * * * * * * * * * * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* * * * * * * * * * * * * * * * * * * * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* * * * * * * * * * * * * * * * * * * * +* * * * * * * * * * * * * * * * * * * * +* * * * * * * * * * * * * * * * * * * * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* * * * * * * * * * * * * * * * * * * * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* * * * * * * * * * * * * * * * * * * * +* * * * * * * * * * * * * * * * * * * * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* * * * * * * * * * * * * * * * * * * * +* * * * * * * * * * * * * * * * * * * * +* * * * * * * * * * * * * * * * * * * * +* * * * * * * * * * * * * * * * * * * * +* * * * * * * * * * * * * * * * * * * * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* * * * * * * * * * * * * * * * * * * * +* * * * * * * * * * * * * * * * * * * * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * diff --git a/src/games/warp/smp.1 b/src/games/warp/smp.1 new file mode 100644 index 0000000..ac822ad --- /dev/null +++ b/src/games/warp/smp.1 @@ -0,0 +1,23 @@ + * * * * * * * * * * * * * * * * * * * * + * * * * * * * * * * * * * * * * * * * * + * * * * * * * * * * * * * * * * * * * * +* * * * * * * * * * * * * * * * * * * * +* * * * * * * * * * * * * * * * * * * * +* * * * * * * * * * * * * * * * * * * * +* * * * * * * * * * * * * * * * * * * * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * * * * * * * * * * * * * * * * * * * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* * * * * * * * * * * * * * * * * * * * +* * * * * * * * * * * * * * * * * * * * +* * * * * * * * * * * * * * * * * * * * +* * * * * * * * * * * * * * * * * * * * + * * * * * * * * * * * * * * * * * * * * + * * * * * * * * * * * * * * * * * * * * + * * * * * * * * * * * * * * * * * * * * diff --git a/src/games/warp/smp.2 b/src/games/warp/smp.2 new file mode 100644 index 0000000..4ad56ac --- /dev/null +++ b/src/games/warp/smp.2 @@ -0,0 +1,23 @@ +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* * * * * * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* * * * * * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* * * * * * +* * * * * * +* * * * * * +* * * * * * +* * * * * * +* * * * * * +* * * * * * +* * * * * * +* * * * * * +* * * * * * +* * * * * * +* * * * * * +* * * * * * +* * * * * * +* * * * * * diff --git a/src/games/warp/smp.3 b/src/games/warp/smp.3 new file mode 100644 index 0000000..58feef9 --- /dev/null +++ b/src/games/warp/smp.3 @@ -0,0 +1,23 @@ + * * * * + * * * * * * + * * * * * * * * + * * * * * * * * +* * * * * * * * +* * * * * * * * +* * * * * * * * +* * * * * * * * + * * * * * * * * + * * * * * * * * + * * * * * * + * * * * + + + + + + + + + + + diff --git a/src/games/warp/smp.4 b/src/games/warp/smp.4 new file mode 100644 index 0000000..21f3ca9 --- /dev/null +++ b/src/games/warp/smp.4 @@ -0,0 +1,23 @@ +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + diff --git a/src/games/warp/smp.5 b/src/games/warp/smp.5 new file mode 100644 index 0000000..7d8948f --- /dev/null +++ b/src/games/warp/smp.5 @@ -0,0 +1,23 @@ +* * * +* * +* * * + + + + + + + + + * * * + * * + * * * + + + + + + + + + diff --git a/src/games/warp/smp.6 b/src/games/warp/smp.6 new file mode 100644 index 0000000..268c051 --- /dev/null +++ b/src/games/warp/smp.6 @@ -0,0 +1,23 @@ + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* * * * * * * * * * * * * * * * * * * * * * * * * * * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* * * * * * * * * * * * * * * * * * * * * * * * * * * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * diff --git a/src/games/warp/smp.7 b/src/games/warp/smp.7 new file mode 100644 index 0000000..8c67dea --- /dev/null +++ b/src/games/warp/smp.7 @@ -0,0 +1,23 @@ +* * * * * * +* * * * * * * + * * * * * * * + * * * * * * * * * * * + * * * * * * * * * * * * * + * * * * * * * * * * + * * * * * * * * + * * * * * * * * * + * * * * * * * + * * * * * * * * + * * * * * * * * + * * * * * * + * * * * * * * * + * * * * * * * * * * + * * * * * * * * * * * + * * * * * * * * * + * * * * * * * * * * * * * + * * * + * * * + * * * + * * * * * + * * * * * * * * * + * * * diff --git a/src/games/warp/term.c b/src/games/warp/term.c new file mode 100644 index 0000000..b8d8397 --- /dev/null +++ b/src/games/warp/term.c @@ -0,0 +1,776 @@ +/* $Header: term.c,v 7.0.1.2 86/12/12 17:04:09 lwall Exp $ */ + +/* $Log: term.c,v $ + * Revision 7.0.1.2 86/12/12 17:04:09 lwall + * Baseline for net release. + * + * Revision 7.0.1.1 86/10/16 10:53:20 lwall + * Added Damage. Fixed random bugs. + * + * Revision 7.0 86/10/08 15:14:02 lwall + * Split into separate files. Added amoebas and pirates. + * + */ + +#include "EXTERN.h" +#include "warp.h" +#include "bang.h" +#include "intrp.h" +#include "object.h" +#include "play.h" +#include "score.h" +#include "sig.h" +#include "us.h" +#include "util.h" +#include "weapon.h" +#include "INTERN.h" +#include "term.h" +#include + +int typeahead = FALSE; + +char tcarea[TCSIZE]; /* area for "compiled" termcap strings */ + +/* guarantee capability pointer != Nullch */ +/* (I believe terminfo will ignore the &tmpaddr argument.) */ + +#define Tgetstr(key) ((tstr = tgetstr(key,&tmpaddr)) ? tstr : nullstr) + +#ifdef PUSHBACK +struct keymap { + char km_type[128]; + union km_union { + struct keymap *km_km; + char *km_str; + } km_ptr[128]; +}; + +#define KM_NOTHIN 0 +#define KM_STRING 1 +#define KM_KEYMAP 2 +#define KM_BOGUS 3 + +#define KM_TMASK 3 +#define KM_GSHIFT 4 +#define KM_GMASK 7 + +typedef struct keymap KEYMAP; + +KEYMAP *topmap INIT(Null(KEYMAP*)); + +void mac_init(); +KEYMAP *newkeymap(); +void pushstring(); +#endif + +/* terminal initialization */ + +void +term_init() +{ + savetty(); /* remember current tty state */ + +#ifdef TERMIO + ospeed = _tty.c_cflag & CBAUD; /* for tputs() */ + ERASECH = _tty.c_cc[VERASE]; /* for finish_command() */ + KILLCH = _tty.c_cc[VKILL]; /* for finish_command() */ +#else + ospeed = _tty.sg_ospeed; /* for tputs() */ + ERASECH = _tty.sg_erase; /* for finish_command() */ + KILLCH = _tty.sg_kill; /* for finish_command() */ +#endif +} + +/* set terminal characteristics */ + +void +term_set(tcbuf) +char *tcbuf; /* temp area for "uncompiled" termcap entry */ +{ + char *tmpaddr; /* must not be register */ + register char *tstr; + char *tgetstr(); + char *s; + int retval; + +#ifdef PENDING +#ifndef FIONREAD + /* do no delay reads on something that always gets closed on exit */ + + devtty = open("/dev/tty",0); + if (devtty < 0) { + printf(cantopen,"/dev/tty"); + finalize(1); + } + fcntl(devtty,F_SETFL,O_NDELAY); +#endif +#endif + + /* get all that good termcap stuff */ + + retval = tgetent(tcbuf,getenv("TERM")); /* get termcap entry */ + if (retval < 1) { +#ifdef VERBOSE + printf("No termcap %s found.\n", retval ? "file" : "entry"); +#else + fputs("Termcap botch\n",stdout); +#endif + finalize(1); + } + tmpaddr = tcarea; /* set up strange tgetstr pointer */ + s = Tgetstr("pc"); /* get pad character */ + PC = *s; /* get it where tputs wants it */ + if (!tgetflag("bs")) { /* is backspace not used? */ + BC = Tgetstr("bc"); /* find out what is */ + if (BC == nullstr) /* terminfo grok's 'bs' but not 'bc' */ + BC = Tgetstr("le"); + } else + BC = "\b"; /* make a backspace handy */ + UP = Tgetstr("up"); /* move up a line */ + ND = Tgetstr("nd"); /* non-destructive move cursor right */ + DO = Tgetstr("do"); /* move cursor down */ + if (!*DO) + DO = Tgetstr("nl"); + CL = Tgetstr("cl"); /* get clear string */ + CE = Tgetstr("ce"); /* clear to end of line string */ + CM = Tgetstr("cm"); /* cursor motion - PWP */ + HO = Tgetstr("ho"); /* home cursor if no CM - PWP */ + CD = Tgetstr("cd"); /* clear to end of display - PWP */ + SO = Tgetstr("so"); /* begin standout */ + SE = Tgetstr("se"); /* end standout */ + if ((SG = tgetnum("sg"))<0) + SG = 0; /* blanks left by SG, SE */ + US = Tgetstr("us"); /* start underline */ + UE = Tgetstr("ue"); /* end underline */ + if ((UG = tgetnum("ug"))<0) + UG = 0; /* blanks left by US, UE */ + if (*US) + UC = nullstr; /* UC must not be NULL */ + else + UC = Tgetstr("uc"); /* underline a character */ + if (!*US && !*UC) { /* no underline mode? */ + US = SO; /* substitute standout mode */ + UE = SE; + UG = SG; + } + LINES = tgetnum("li"); /* lines per page */ + COLS = tgetnum("co"); /* columns on page */ + AM = tgetflag("am"); /* terminal wraps automatically? */ + XN = tgetflag("xn"); /* then eats next newline? */ + VB = Tgetstr("vb"); + if (!*VB) + VB = "\007"; + CR = Tgetstr("cr"); + if (!*CR) { + if (tgetflag("nc") && *UP) { + CR = safemalloc((MEM_SIZE)strlen(UP)+2); + Sprintf(CR,"%s\r",UP); + } + else + CR = "\r"; + } + if (LINES <= 0) + LINES = 24; + if (COLS <= 0) + COLS = 80; + + BCsize = comp_tc(bsptr,BC,1); + BC = bsptr; + + if (!*ND) /* not defined? */ + NDsize = 1000; /* force cursor addressing */ + else { + NDsize = comp_tc(cmbuffer,ND,1); + myND = malloc((unsigned)NDsize); + movc3(NDsize,cmbuffer,myND); + if (debugging) { + int scr; + + printf("ND"); + for (scr=0; scr= B9600 ? 480 : + ospeed == B4800 ? 240 : + ospeed == B2400 ? 120 : + ospeed == B1200 ? 60 : + ospeed == B600 ? 30 : + /* speed is 300 (?) */ 15; + + gfillen = ospeed >= B9600 ? (sizeof filler) : + ospeed == B4800 ? 13 : + ospeed == B2400 ? 7 : + ospeed == B1200 ? 4 : + 1+BCsize; + if (ospeed < B2400) + lowspeed = TRUE; + + strcpy(term,ttyname(2)); + + if (!*CM || !BCsize) + no_can_do("dumb"); + if (!scorespec && (LINES < 24 || COLS < 80)) + no_can_do("puny"); + + crmode(); + raw(); + noecho(); /* turn off echo */ + nonl(); + +#ifdef PUSHBACK + mac_init(tcbuf); +#endif +} + +#ifdef PUSHBACK +void +mac_init(tcbuf) +char *tcbuf; +{ + char tmpbuf[1024]; + + tmpfp = fopen(filexp(getval("WARPMACRO",WARPMACRO)),"r"); + if (tmpfp != Nullfp) { + while (fgets(tcbuf,1024,tmpfp) != Nullch) { + mac_line(tcbuf,tmpbuf,(sizeof tmpbuf)); + } + Fclose(tmpfp); + } +} + +void +mac_line(line,tmpbuf,tbsize) +char *line; +char *tmpbuf; +int tbsize; +{ + register char *s; + register char *m; + register KEYMAP *curmap; + register int ch; + register int garbage = 0; + static char override[] = "\r\nkeymap overrides string\r\n"; + + if (topmap == Null(KEYMAP*)) + topmap = newkeymap(); + if (*line == '#' || *line == '\n') + return; + if (line[ch = strlen(line)-1] == '\n') + line[ch] = '\0'; + m = dointerp(tmpbuf,tbsize,line," \t"); + if (!*m) + return; + while (*m == ' ' || *m == '\t') m++; + for (s=tmpbuf,curmap=topmap; *s; s++) { + ch = *s & 0177; + if (s[1] == '+' && isdigit(s[2])) { + s += 2; + garbage = (*s & KM_GMASK) << KM_GSHIFT; + } + else + garbage = 0; + if (s[1]) { + if ((curmap->km_type[ch] & KM_TMASK) == KM_STRING) { + puts(override); + free(curmap->km_ptr[ch].km_str); + curmap->km_ptr[ch].km_str = Nullch; + } + curmap->km_type[ch] = KM_KEYMAP + garbage; + if (curmap->km_ptr[ch].km_km == Null(KEYMAP*)) + curmap->km_ptr[ch].km_km = newkeymap(); + curmap = curmap->km_ptr[ch].km_km; + } + else { + if ((curmap->km_type[ch] & KM_TMASK) == KM_KEYMAP) + puts(override); + else { + curmap->km_type[ch] = KM_STRING + garbage; + curmap->km_ptr[ch].km_str = savestr(m); + } + } + } +} + +KEYMAP* +newkeymap() +{ + register int i; + register KEYMAP *map; + + map = (KEYMAP*)safemalloc(sizeof(KEYMAP)); + for (i=127; i>=0; --i) { + map->km_ptr[i].km_km = Null(KEYMAP*); + map->km_type[i] = KM_NOTHIN; + } + return map; +} + +#endif + +/* print out a file, stopping at form feeds */ + +void +page(filename,num) +char *filename; +bool num; +{ + int linenum = 1; + + tmpfp = fopen(filename,"r"); + if (tmpfp != NULL) { + while (fgets(spbuf,(sizeof spbuf),tmpfp) != NULL) { + if (*spbuf == '\f') { + printf("[Type anything to continue] "); + Fflush(stdout); + getcmd(spbuf); + printf("\r\n"); + if (*spbuf == INTRCH) + finalize(0); + if (*spbuf == 'q' || *spbuf == 'Q') + break; + } + else { + if (num) + printf("%3d %s\r",linenum++,spbuf); + else + printf("%s\r",spbuf); + } + } + Fclose(tmpfp); + } +} + +void +move(y, x, chadd) +int y, x; +int chadd; +{ + register int ydist; + register int xdist; + register int i; + register char *s; + + ydist = y - real_y; + xdist = x - real_x; + i = ydist * (ydist < 0 ? -UPsize : DOsize) + + xdist * (xdist < 0 ? -BCsize : NDsize); + beg_qwrite(); + if (i <= CMsize) { + if (ydist < 0) + for (; ydist; ydist++) + for (i=UPsize,s=myUP; i; i--) + qaddch(*s++); + else + for (; ydist; ydist--) + for (i=DOsize,s=myDO; i; i--) + qaddch(*s++); + if (xdist < 0) + for (; xdist; xdist++) + for (i=BCsize,s=BC; i; i--) + qaddch(*s++); + else + for (; xdist; xdist--) + for (i=NDsize,s=myND; i; i--) + qaddch(*s++); + } + else { + tputs(tgoto(CM,x,y),0,cmstore); + } + real_y = y; + real_x = x; + if (chadd) { + qaddch(chadd); + } + if (maxcmstring != cmbuffer) + end_qwrite(); +} + +void +do_tc(s,l) +char *s; +int l; +{ + beg_qwrite(); + tputs(s,l,cmstore); + end_qwrite(); +} + +int +comp_tc(dest,s,l) +char *dest; +char *s; +int l; +{ + maxcmstring = dest; + tputs(s,l,cmstore); + return(maxcmstring-dest); +} + +void +helper() +{ + clear(); + mvaddstr(0,4,"h or 4 left"); + mvaddstr(1,4,"j or 2 down Use with SHIFT to fire torpedoes."); + mvaddstr(2,4,"k or 8 up Use with CTRL or FUNCT to fire"); + mvaddstr(3,4,"l or 6 right phasers or turbolasers."); + mvaddstr(4,4,"b or 1 down and left Use preceded by 'a' or 'r' for"); + mvaddstr(5,4,"n or 3 down and right attractors or repulsors."); + mvaddstr(6,4,"y or 7 up and left Use normally for E or B motion."); + mvaddstr(7,4,"u or 9 up and right"); + mvaddstr(8,4,""); + mvaddstr(9,4,"del or % fire photon torpedoes in every (reasonable) direction."); + mvaddstr(10,4,"s stop all torpedoes."); + mvaddstr(11,4,"S or 0 stop the Enterprise when in warp mode."); + mvaddstr(12,4,"d/D destruct all torpedoes/current vessel."); + mvaddstr(13,4,"i/w switch to Enterprise & put into impulse/warp mode."); + mvaddstr(14,4,"c/v switch to Enterprise & make cloaked/visible."); + mvaddstr(15,4,"p switch to Base."); + mvaddstr(16,4,"o toggle to other vessel (from E to B, or vice versa.)"); + mvaddstr(17,4,"z zap (suppress) blasts near Enterprise next cycle"); + mvaddstr(18,4,""); + mvaddstr(19,4,"^R refresh the screen. ^Z suspend the game."); + mvaddstr(20,4,"q exit this round (if you haven't typed q within 10 cycles)."); + mvaddstr(21,4,"Q exit this game."); + mvaddstr(22,4,""); + mvaddstr(23,4," [Hit space to continue]"); + Fflush(stdout); + do { + getcmd(spbuf); + } while (*spbuf != ' '); + rewrite(); + +} + +void +rewrite() +{ + register int x; + register int y; + register OBJECT *obj; + + clear(); + for (y=0; yimage != ' ') + mvaddc(y+1,x*2,obj->image); + } + } + } + Sprintf(spbuf, + "%-4s E: %4d %2d B: %5d %3d Enemies: %-3d Stars: %-3d Stardate%5d.%1d %9ld", + " ", 0, 0, 0, 0, 0, 0, timer/10+smarts*100, timer%10, 0L); + mvaddstr(0,0,spbuf); + oldeenergy = oldbenergy = oldcurscore = + oldstatus = oldetorp = oldbtorp = oldstrs = oldenemies = -1; + /* force everything to fill in */ + if (damage) + olddamage = 0; + if (!ent) + etorp = 0; + if (!base) + btorp = 0; + display_status(); +} + +char +cmstore(ch) +register char ch; +{ + *maxcmstring++ = ch; +} + +/* discard any characters typed ahead */ + +void +eat_typeahead() +{ +#ifdef PUSHBACK + if (!typeahead && nextin==nextout) /* cancel only keyboard stuff */ +#else + if (!typeahead) +#endif + { +#ifdef PENDING + while (input_pending()) + Read_tty(buf,sizeof(buf)); +#else /* this is probably v7, with no rdchk() */ + ioctl(_tty_ch,TIOCSETP,&_tty); +#endif + } +} + +void +settle_down() +{ + dingaling(); + Fflush(stdout); + sleep(1); +#ifdef PUSHBACK + nextout = nextin; /* empty circlebuf */ +#endif + eat_typeahead(); +} + +#ifdef PUSHBACK +/* read a character from the terminal, with multi-character pushback */ + +int +read_tty(addr,size) +char *addr; +int size; /* ignored for now */ +{ + if (nextout != nextin) { + *addr = circlebuf[nextout++]; + nextout %= PUSHSIZE; + return 1; + } + else { + size = read(0,addr,1); + if (size < 0) + sig_catcher(SIGHUP); + if (metakey) { + if (*addr & 0200) { + pushchar(*addr & 0177); + *addr = '\001'; + } + } + else + *addr &= 0177; + return 1; + } +} + +#ifdef PENDING +#ifndef FIONREAD +int +circfill() +{ + register int howmany; + register int i; + + assert (nextin == nextout); + howmany = read(devtty,circlebuf+nextin,metakey?1:PUSHSIZE-nextin); + if (howmany > 0) { + if (metakey) { + if (circlebuf[nextin] & 0200) { + circlebuf[nextin] &= 0177; + pushchar('\001'); + } + } + else + for (i = howmany+nextin-1; i >= nextin; i--) + circlebuf[i] &= 0177; + nextin += howmany; + nextin %= PUSHSIZE; /* may end up 1 if metakey */ + } + return howmany; +} +#endif /* FIONREAD */ +#endif /* PENDING */ + +void +pushchar(ch) +char ch; +{ + nextout--; + if (nextout < 0) + nextout = PUSHSIZE - 1; + if (nextout == nextin) { + fputs("\r\npushback buffer overflow\r\n",stdout); + sig_catcher(0); + } + circlebuf[nextout] = ch; +} + +#else /* PUSHBACK */ +#ifndef read_tty +/* read a character from the terminal, with hacks for O_NDELAY reads */ + +int +read_tty(addr,size) +char *addr; +int size; +{ + if (is_input) { + *addr = pending_ch; + is_input = FALSE; + return 1; + } + else { + size = read(0,addr,size); + if (size < 0) + sig_catcher(SIGHUP); + if (metakey) { + if (*addr & 0200) { + pending_ch = *addr & 0177; + is_input = TRUE; + *addr = '\001'; + } + } + else + *addr &= 0177; + return size; + } +} +#endif /* read_tty */ +#endif /* PUSHBACK */ + +int +read_nd(buff, siz) +char *buff; +int siz; +{ + if (!input_pending()) + return 0; + + getcmd(buff); + return 1; +} + +/* get a character into a buffer */ + +void +getcmd(whatbuf) +register char *whatbuf; +{ +#ifdef PUSHBACK + register KEYMAP *curmap; + register int i; + bool no_macros; + int times = 0; /* loop detector */ + char scrchar; + +tryagain: + curmap = topmap; +/* no_macros = (whatbuf != buf && nextin == nextout); */ + no_macros = FALSE; +#endif + for (;;) { + errno = 0; + if (read_tty(whatbuf,1) < 0 && !errno) + errno = EINTR; +#ifdef read_tty + if (metakey) { + if (*whatbuf & 0200) { + *what_buf &= 037; /* punt and hope they don't notice */ + } + } + else + *whatbuf &= 0177; +#endif /* read_tty */ + if (errno && errno != EINTR) { + perror(readerr); + sig_catcher(0); + } +#ifdef PUSHBACK + if (*whatbuf & 0200 || no_macros) { + *whatbuf &= 0177; + goto got_canonical; + } + if (curmap == Null(KEYMAP*)) + goto got_canonical; + for (i = (curmap->km_type[*whatbuf] >> KM_GSHIFT) & KM_GMASK; i; --i){ + Read_tty(&scrchar,1); + } + switch (curmap->km_type[*whatbuf] & KM_TMASK) { + case KM_NOTHIN: /* no entry? */ + if (curmap == topmap) /* unmapped canonical */ + goto got_canonical; + settle_down(); + goto tryagain; + case KM_KEYMAP: /* another keymap? */ + curmap = curmap->km_ptr[*whatbuf].km_km; + assert(curmap != Null(KEYMAP*)); + break; + case KM_STRING: /* a string? */ + pushstring(curmap->km_ptr[*whatbuf].km_str); + if (++times > 20) { /* loop? */ + fputs("\r\nmacro loop?\r\n",stdout); + settle_down(); + } + no_macros = FALSE; + goto tryagain; + } +#else + *whatbuf &= 0177; + break; +#endif + } + +got_canonical: +#ifndef TERMIO + if (*whatbuf == '\r') + *whatbuf = '\n'; +#endif + if (whatbuf == buf) + whatbuf[1] = FINISHCMD; /* tell finish_command to work */ +} + +#ifdef PUSHBACK +void +pushstring(str) +char *str; +{ + register int i; + char tmpbuf[PUSHSIZE]; + register char *s = tmpbuf; + + assert(str != Nullch); + interp(s,PUSHSIZE,str); + for (i = strlen(s)-1; i >= 0; --i) { + s[i] ^= 0200; + pushchar(s[i]); + } +} +#endif diff --git a/src/games/warp/term.h b/src/games/warp/term.h new file mode 100644 index 0000000..eb026ba --- /dev/null +++ b/src/games/warp/term.h @@ -0,0 +1,259 @@ +/* $Header: term.h,v 7.0.1.2 86/12/12 17:05:15 lwall Exp $ */ + +/* $Log: term.h,v $ + * Revision 7.0.1.2 86/12/12 17:05:15 lwall + * Baseline for net release. + * + * Revision 7.0.1.1 86/10/16 10:53:33 lwall + * Added Damage. Fixed random bugs. + * + * Revision 7.0 86/10/08 15:14:07 lwall + * Split into separate files. Added amoebas and pirates. + * + */ + +/* warp will still work without the following, but may get ahead at low speed */ +#ifdef TIOCOUTQ /* chars left in output queue */ +#define output_pending() (ioctl(1, TIOCOUTQ, &iocount),iocount) +#endif + +/* If some of the following look something like curses calls, it is because + * warp used to use curses but doesn't now. Warp was neither as efficient nor + * as portable with curses, and since the program had to cheat on curses all + * over the place anyway, we ripped it out. + */ +#define setimage(of,to) (mvaddch(of->posy+1,of->posx*2,of->image=(to))) + +#define mvaddch(y,x,ch) move((y),(x),(ch)) +/* #define addch(ch) (tmpchr=(ch), write(1,&tmpchr,1), real_x++) */ +#define mvaddc(y,x,ch) move((y),(x),(ch)) +#define addc(ch) (write(1,&(ch),1), real_x++) +#define addspace() (write(1," ",1), real_x++) +#define mvaddstr(y,x,s) (move((y),(x),0), tmpstr = (s), \ + tmplen = strlen(tmpstr), write(1, tmpstr, tmplen) >= 0, real_x += tmplen) + +EXT int tmplen; +EXT char *tmpstr; +/* EXT char tmpchr; */ + +/* The following macros are like the pseudo-curses macros above, but do + * certain amount of controlled output buffering. + * + * NOTE: a beg_qwrite()..end_qwrite() sequence must NOT contain a cursor + * movement (move), because the move() routine uses beg_qwrite()..end_qwrite() + * itself. + */ + +#define beg_qwrite() (maxcmstring = cmbuffer) +#define qwrite() (movc3(gfillen,filler,maxcmstring), maxcmstring += gfillen) +#define qaddc(ch) (*maxcmstring++ = (ch), real_x++) +#define qaddch(ch) (*maxcmstring++ = (ch), real_x++) +#define qaddspace() (*maxcmstring++ = ' ', real_x++) +#define end_qwrite() (write(1,cmbuffer,maxcmstring-cmbuffer) > 0) + +/* setting a ??size to infinity forces cursor addressing in that direction */ + +EXT int CMsize; +EXT int BCsize INIT(1); +EXT int DOsize INIT(1000); +EXT int UPsize INIT(1000); +EXT int NDsize INIT(1000); + +EXT int charsperhalfsec; + +EXT int real_y INIT(-100); +EXT int real_x INIT(-100); + +#ifdef DOINIT +char filler[] = {0,'\b',0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; +#else +EXT char filler[]; +#endif + +EXT char *bsptr INIT(filler+1); + +EXT char term[12]; + +EXT char gfillen INIT(25); + +EXT char *maxcmstring; +EXT char cmbuffer[512]; + +#define BREAKCH '\0' + +EXT char INTRCH INIT('\03'); + +#ifdef PUSHBACK + EXT char circlebuf[PUSHSIZE]; + EXT int nextin INIT(0); + EXT int nextout INIT(0); +# ifdef PENDING +# ifdef FIONREAD + EXT long iocount INIT(0); +# define input_pending() (nextin!=nextout || (ioctl(0, FIONREAD, &iocount),(int)iocount)) +# else /* FIONREAD */ + int circfill(); +# ifndef O_NDELAY /* assert O_NDELAY */ +# error PENDING is not defined correctly in warp.h +# endif + EXT int devtty INIT(0); +# define input_pending() (nextin!=nextout || circfill()) +# endif /* FIONREAD */ +# else /* PENDING */ +# error warp wont work without PENDING +# define input_pending() (nextin!=nextout) +# endif /* PENDING */ +#else /* PUSHBACK */ +# ifdef PENDING +# ifdef FIONREAD /* must have FIONREAD or O_NDELAY for input_pending() */ +# define read_tty(addr,size) read(0,addr,size) +# define input_pending() (ioctl(0, FIONREAD, &iocount), (int)iocount) + EXT long iocount INIT(0); +# else /* FIONREAD */ +# ifdef RDCHK /* actually, they can have rdchk() too */ +# define read_tty(addr,size) read(0,addr,size) +# define input_pending() rdchk(0) +# else /* RDCHK */ +# ifndef O_NDELAY /* assert O_NDELAY */ +# error PENDING is not defined correctly in warp.h +# endif + EXT int devtty INIT(0); + EXT bool is_input INIT(FALSE); + EXT char pending_ch INIT(0); +# define input_pending() (is_input || (is_input=read(devtty,&pending_ch,1))) +# endif /* RDCHK */ +# endif /* FIONREAD */ +# else /* PENDING */ +# error warp wont work without PENDING +# define read_tty(addr,size) read(0,addr,size) +# define input_pending() (FALSE) +# endif /* PENDING */ +#endif /* PUSHBACK */ + +/* stuff wanted by terminal mode diddling routines */ + +#ifdef TERMIO +EXT struct termio _tty, _oldtty; +#else +EXT struct sgttyb _tty; +EXT int _res_flg INIT(0); +#endif + +EXT int _tty_ch INIT(2); +EXT bool bizarre INIT(FALSE); /* do we need to restore terminal? */ + +/* terminal mode diddling routines */ + +#ifdef TERMIO + +#define raw() ((bizarre=1),_tty.c_lflag &=~ISIG,_tty.c_cc[VMIN] = 1,ioctl(_tty_ch,TCSETAF,&_tty)) +#define noraw() ((bizarre=1),_tty.c_lflag |= ISIG,_tty.c_cc[VEOF] = CEOF,ioctl(_tty_ch,TCSETAF,&_tty)) +#define crmode() ((bizarre=1),_tty.c_lflag &=~ICANON,_tty.c_cc[VMIN] = 1,ioctl(_tty_ch,TCSETAF,&_tty)) +#define nocrmode() ((bizarre=1),_tty.c_lflag |= ICANON,_tty.c_cc[VEOF] = CEOF,ioctl(_tty_ch,TCSETAF,&_tty)) +#define echo() ((bizarre=1),_tty.c_lflag |= ECHO, ioctl(_tty_ch, TCSETAW, &_tty)) +#define noecho() ((bizarre=1),_tty.c_lflag &=~ECHO, ioctl(_tty_ch, TCSETAW, &_tty)) +#define nl() ((bizarre=1),_tty.c_iflag |= ICRNL,_tty.c_oflag |= ONLCR,ioctl(_tty_ch, TCSETAW, &_tty)) +#define nonl() ((bizarre=1),_tty.c_iflag &=~ICRNL,_tty.c_oflag &=~ONLCR,ioctl(_tty_ch, TCSETAW, &_tty)) +#define savetty() (ioctl(_tty_ch, TCGETA, &_oldtty),ioctl(_tty_ch, TCGETA, &_tty)) +#define resetty() ((bizarre=0),ioctl(_tty_ch, TCSETAF, &_oldtty)) +#define unflush_output() + +#else + +#define raw() ((bizarre=1),_tty.sg_flags|=RAW, stty(_tty_ch,&_tty)) +#define noraw() ((bizarre=1),_tty.sg_flags&=~RAW,stty(_tty_ch,&_tty)) +#define crmode() ((bizarre=1),_tty.sg_flags |= CBREAK, stty(_tty_ch,&_tty)) +#define nocrmode() ((bizarre=1),_tty.sg_flags &= ~CBREAK,stty(_tty_ch,&_tty)) +#define echo() ((bizarre=1),_tty.sg_flags |= ECHO, stty(_tty_ch, &_tty)) +#define noecho() ((bizarre=1),_tty.sg_flags &= ~ECHO, stty(_tty_ch, &_tty)) +#define nl() ((bizarre=1),_tty.sg_flags |= CRMOD,stty(_tty_ch, &_tty)) +#define nonl() ((bizarre=1),_tty.sg_flags &= ~CRMOD, stty(_tty_ch, &_tty)) +#define savetty() (gtty(_tty_ch, &_tty), _res_flg = _tty.sg_flags) +#define resetty() ((bizarre=0),_tty.sg_flags = _res_flg, stty(_tty_ch, &_tty)) +#endif /* TERMIO */ + +#ifdef TIOCSTI +#define forceme(c) ioctl(_tty_ch,TIOCSTI,c) /* pass character in " " */ +#else +#define forceme(c) +#endif + +/* termcap stuff */ + +/* + * NOTE: if you don't have termlib you'll have to define these strings, + * the tputs routine, and the tgoto routine. + * The tgoto routine simply produces a cursor addressing string for a given + * x and y. The 1st argument is a generic string to be interpreted. + * If you are hardwiring it you might just ignore the 1st argument. + * The tputs routine interprets any leading number as a padding factor, possibly + * scaled by the number of lines (2nd argument), puts out the string (1st arg) + * and the padding using the routine specified as the 3rd argument. + */ +EXT char *BC INIT(Nullch); /* backspace character */ +EXT char *UP INIT(Nullch); /* move cursor up one line */ +EXT char *myUP; +EXT char *ND INIT(Nullch); /* non-destructive cursor right */ +EXT char *myND; +EXT char *DO INIT(Nullch); /* move cursor down one line */ +EXT char *myDO; +EXT char *CR INIT(Nullch); /* get to left margin, somehow */ +EXT char *VB INIT(Nullch); /* visible bell */ +EXT char *CL INIT(Nullch); /* home and clear screen */ +EXT char *CE INIT(Nullch); /* clear to end of line */ +EXT char *CM INIT(Nullch); /* cursor motion -- PWP */ +EXT char *HO INIT(Nullch); /* home cursor -- PWP */ +EXT char *CD INIT(Nullch); /* clear to end of display -- PWP */ +EXT char *SO INIT(Nullch); /* begin standout mode */ +EXT char *SE INIT(Nullch); /* end standout mode */ +EXT int SG INIT(0); /* blanks left by SO and SE */ +EXT char *US INIT(Nullch); /* start underline mode */ +EXT char *UE INIT(Nullch); /* end underline mode */ +EXT char *UC INIT(Nullch); /* underline a character, if that's how it's done */ +EXT int UG INIT(0); /* blanks left by US and UE */ +EXT bool AM INIT(FALSE); /* does terminal have automatic margins? */ +EXT bool XN INIT(FALSE); /* does it eat 1st newline after automatic wrap? */ +EXT char PC INIT(0); /* pad character for use by tputs() */ +EXT short ospeed INIT(0); /* terminal output speed, for use by tputs() */ +EXT int LINES INIT(0), COLS INIT(0); /* size of screen */ + /* (number of nulls) */ +EXT char ERASECH; /* rubout character */ +EXT char KILLCH; /* line delete character */ + +/* define a few handy macros */ + +#define clear() (do_tc(CL,LINES),real_y=real_x=0) +#define erase_eol() do_tc(CE,1) +#define backspace() (do_tc(BC,0),real_x--) +#define clear_rest() do_tc(CD,LINES) +#define underline() do_tc(US,1) +#define un_underline() do_tc(UE,1) +#define underchar() do_tc(UC,0) +#define standout() do_tc(SO,1) +#define un_standout() do_tc(SE,1) +#define up_line() do_tc(UP,1) +#define carriage_return() do_tc(CR,1) +#define dingaling() do_tc(VB,1) + +void term_init(); +void term_set(); +#ifdef PUSHBACK +void pushchar(); +void mac_init(); +void mac_line(); +#endif +void eat_typeahead(); +void settle_down(); +#ifndef read_tty + int read_tty(); +#endif +void getcmd(); + +int read_nd(); +void page(); +void move(); +void do_tc(); +int comp_tc(); +void helper(); +void rewrite(); +char cmstore(); diff --git a/src/games/warp/them.c b/src/games/warp/them.c new file mode 100644 index 0000000..a883655 --- /dev/null +++ b/src/games/warp/them.c @@ -0,0 +1,403 @@ +/* $Header: them.c,v 7.0.1.5 86/12/12 17:05:41 lwall Exp $ */ + +/* $Log: them.c,v $ + * Revision 7.0.1.5 86/12/12 17:05:41 lwall + * Baseline for net release. + * + * Revision 7.0.1.4 86/10/20 12:32:38 lwall + * Wasn't clearing FRIENDLY flag on pirate creation. + * + * Revision 7.0.1.3 86/10/20 12:15:33 lwall + * Was trying to create pirates from cloaked pirates. + * + * Revision 7.0.1.2 86/10/17 10:03:44 lwall + * Fixed Romulan writing spaces while cloaked. + * + * Revision 7.0.1.1 86/10/16 10:53:39 lwall + * Added Damage. Fixed random bugs. + * + * Revision 7.0 86/10/08 15:14:15 lwall + * Split into separate files. Added amoebas and pirates. + * + */ + +#include "EXTERN.h" +#include "warp.h" +#include "bang.h" +#include "object.h" +#include "move.h" +#include "score.h" +#include "term.h" +#include "us.h" +#include "util.h" +#include "weapon.h" +#include "INTERN.h" +#include "them.h" + +void +them_init() +{ + ; +} + +void +their_smarts() +{ + register OBJECT *curkl; + register OBJECT *obj; + register int prob; + register int count; + register int y; + register int x; + + if (numcrushes && (obj=movers)->type == Crusher) { + if (numamoebas) { + y = obj->posy; + x = (obj->posx+(obj->image=='<'?1:-1)+XSIZE00)%XSIZE; + if (amb[y][x] == '~') { + obj->velx = 0; /* stop and munch amoeba */ + modify_amoeba(y,x,1,' ',(int)rand_mod(5+ambsize/10)+1); + if (occupant[y][x] == nuke) /* except go for nucleus */ + obj->velx = (obj->image=='<' ? 1 : -1); + } + else if (!obj->velx) { + if (!rand_mod(4)) + obj->image = rand_mod(2) ? '<' : '>'; + obj->velx = obj->image == '<' ? 1 : -1; + } + } + obj->vely += (rand_mod(222) - 111) / 100; + if (!(rand_mod(100))) { + setimage(obj, (obj->velx *= -1) < 0 ? '>' : '<'); + } + } + if (numamoebas) { + if (!rand_mod(3)) + nuke->velx = nuke->vely = 0; + if (nuke->strategy && ambsize < 90 && !rand_mod(200-smarts)) + modify_amoeba(0,0,0,'~',(int)rand_mod(10)); + if (ambsize > 200 || (ambsize > 100 && !rand_mod(15))) + modify_amoeba(yamblast,xamblast,2,' ',(ambsize-100)/5); + } + for (curkl = enemies; curkl->type == Enemy; curkl = curkl->next) { + if ((curkl->flags & (CLOAKS|FRIENDLY)) == CLOAKS && + (curkl->image != ' ') && + (curkl->energy > 300 || massacre) ) { + setimage(curkl, ' '); + } + if (madgorns) + prob = 3; + else if (curkl->vely || curkl->velx) + prob = massacre?10:20; + else if ((curkl->flags & (PIRATE|FRIENDLY)) == PIRATE) { + /* pirates want to sit sometimes */ + if (curkl->strategy) { + if ((obj = lookimg(curkl->posy, curkl->posx, '@')) || + (obj = lookimg(curkl->posy, curkl->posx, 'B')) ) { + make_plink(obj->posy, obj->posx); + if (!--curkl->strategy) { /* clock ran down */ + if (obj->image == '@') { + obj->image = '*'; + numinhab--; + if (obj->flags & STATIC) + mvaddch(obj->posy+1,obj->posx*2,obj->image); + if (curkl->energy < 20000) + curkl->energy += 5000; + } + prob = 2; /* our work here is done */ + } + else if (obj->image == 'B') { + btorp -= rand_mod(50); + if (btorp < 0) + btorp = 0; + obj->energy -= rand_mod(500); + if (obj->energy < 0) + obj->energy = 0; + prob = 10000; /* stay here */ + } + else + prob = 10000; + } + else { /* it went away--go elsewhere */ + prob = 4; + curkl->strategy = 0; + } + } + else if (lookimg(curkl->posy, curkl->posx, '@') || + lookimg(curkl->posy, curkl->posx, 'B')) { + curkl->strategy = rand_mod(15)+5; + prob = 10000; + } + else + prob = 4; + } + else if (curkl->image == 'M') { /* Mudd wants to sit sometimes */ + if ((obj = lookimg(curkl->posy, curkl->posx, 'E')) || + (obj = lookimg(curkl->posy, curkl->posx, 'B')) ) { + if (obj->image == 'B') { + btorp -= rand_mod(40); + if (btorp < 0) + btorp = 0; + obj->energy -= rand_mod(100); + if (obj->energy < 0) + obj->energy = 0; + } + else if (!obj->vely && !obj->velx) { + etorp -= rand_mod(10); + if (etorp < 0) + etorp = 0; + obj->energy -= rand_mod(20); + if (obj->energy < 0) + obj->energy = 0; + } + prob = 10000; /* stay here */ + } + else /* it went away--go elsewhere */ + prob = 4; + } + else if (curkl->flags & FRIENDLY) { + if (curkl->energy < 10000 && + lookimg(curkl->posy, curkl->posx, '@') ) { + curkl->energy += 100; + prob = 20; /* do some loading */ + } + else + prob = 4; + } + else if (curkl->image == '&') { + if (curkl->flags & COUNTDOWN) { + if (curkl->strategy) + curkl->strategy--; + else + curkl->flags &= ~COUNTDOWN; + prob = 100; /* someone's feeding us, so sit still */ + } + else + prob = 4; + } + else + prob = 4; /* don't sit still too long */ + count = 11; + for (;;) { + if (--count <= 0) /* no opening, just ram something */ + break; + + if (!(rand_mod(prob))) /* turn randomly occasionally */ + goto accell; + + y=(curkl->posy+curkl->vely+YSIZE00)%YSIZE; /* find prospective */ + x=(curkl->posx+curkl->velx+XSIZE00)%XSIZE; /* new position */ + + if (numamoebas) { + if (curkl == nuke) { + if (amb[y][x] != '~') + goto accell; /* never move nucleus from protoplasm */ + } + else { + if (amb[y][x] == '~' && rand_mod(2)) { + yamblast = y; + xamblast = x; + goto accell; + } + } + } + + obj = occupant[y][x]; + if (!obj) break; /* is anyone there? */ + + switch (obj->type) { + case Star: + if (obj->image == '@' && (curkl->flags & PIRATE)) { + if (curkl->image != 'P' && curkl->image != ' ') { + if (curkl->flags & FRIENDLY) { + curkl->flags &= ~FRIENDLY; + curkl->energy += 1000; + possiblescore += curkl->mass; + inumfriends--; + numfriends--; + inumenemies++; + numenemies++; + } + curkl->image = 'P'; + } + break; /* go ahead and ram the star */ + } + goto accell; /* try not to ram stars */ + case Torp: + if (!obj->vely && !obj->velx && (rand_mod(100) <= smarts) && + (obj->image == 'o' || obj->image == 'O' || obj->image == 'X')) + goto accell; /* try not to ram "friendly" torps */ + break; + case Web: + if (curkl->image != 'T') + goto accell; /* non-Tholians shouldn't ram web */ + if (count <= 5) + break; /* Tholians retrace web if desperate */ + if (obj->image == + (curkl->vely? + (curkl->velx? + (curkl->velx==curkl->vely? + '\\' + : + '/' + ) + : + '|' + ) + : + '-' + ) + ) goto accell; /* Tholians try not to retrace web */ + break; /* No problem with crossing web */ + } + break; /* okay to move over object */ + + accell: + /* determine maximum velocity */ + if (massacre && curkl->image != 'T') { + curkl->vely = rand_mod(7) - 3; + curkl->velx = rand_mod(7) - 3; + } + else if (curkl->image == '&') { + if (rand_mod(2)) { + curkl->vely = rand_mod(3) - 1; + curkl->velx = rand_mod(3) - 1; + } + else { + curkl->vely = curkl->strategy & 3; + if (curkl->vely & 2) + curkl->vely = -1; + curkl->velx = (curkl->strategy >> 2) & 3; + if (curkl->velx & 2) + curkl->velx = -1; + } + } + else if (curkl->energy >= 2500 && curkl->image != 'T') { + curkl->vely = rand_mod(5) - 2; + curkl->velx = rand_mod(5) - 2; + } + else { + curkl->vely = rand_mod(3) - 1; + curkl->velx = rand_mod(3) - 1; + } + } + if (count != 10) { + if (curkl->image == ' ') { + setimage(curkl, curkl->flags & PIRATE ? 'P' : 'R'); + } + if (!count) { + curkl->vely = 0; + curkl->velx = 0; + } + } + if (curkl->image == 'G' && (base||ent) && + !rand_mod((103-smarts)*10) ) { + int xxx,yyy; + + for (xxx = -1; xxx<=1; xxx++) + for (yyy = -1; yyy<=1; yyy++) + if ((xxx||yyy) && rand_mod(2)) + fire_torp(curkl,yyy,xxx); + } + else if (curkl->image == 'T' && (curkl->velx || curkl->vely)) { + Make_object(Web, + curkl->vely? + (curkl->velx? + (curkl->velx==curkl->vely? + '\\' + : + '/' + ) + : + '|' + ) + : + '-', + curkl->posy,curkl->posx,0,0,32767L,32767L,&root); + if (obj && obj->type == Web) { + unmake_object(obj); + occupant[y][x] = Null(OBJECT*); + } + } + } + /* klingon-style fighting */ + if (numamoebas) + attack(nuke); + attack(base); + if (ent && (!cloaked || ent->image=='E' || ent->image=='e')) + attack(ent); +} + +void +modify_amoeba(y,x,where,ch,quant) +register int y; +register int x; +int where; +register int ch; +register int quant; +{ + register int dy; + register int dx; + register int count = 15; + + if (!numamoebas) + return; + if (!where || (where==1 && rand_mod(2))) { + y = nuke->posy; + x = nuke->posx; + } + if (nuke->strategy && rand_mod(3)) { + dy = nuke->strategy & 3; + if (dy & 2) + dy = -1; + dx = (nuke->strategy >> 2) & 3; + if (dx & 2) + dx = -1; + if (ch == ' ') { /* take from the tail */ + dy = -dy; + dx = -dx; + } + if (!rand_mod(100)) + nuke->strategy = rand_mod(256); + } + else { + dy = rand_mod(3) - 1; + dx = rand_mod(3) - 1; + } + if (!dy && !dx) + return; + do { + if (--count < 0) + return; + y = (y + dy + YSIZE00) % YSIZE; + x = (x + dx + XSIZE00) % XSIZE; + } while (amb[y][x] != ' '); + if (ch == ' ') { + y = (y - dy + YSIZE00) % YSIZE; + x = (x - dx + XSIZE00) % XSIZE; + } + if (ambsize > 100 && quant > 2) { + quant >>= (ambsize/100); + } + if ((nuke->energy += quant << 6) > 32767) + nuke->energy = 32767; + count = quant << 3; /* endless loop catcher */ + while (count-- > 0 && quant > 0) { + if (amb[y][x] != ch) { + quant--; + amb[y][x] = ch; + if (ch == '~') { + ambsize++; + yblasted[y] |= 2; + xblasted[x] |= 2; + blasted = TRUE; + } + else + ambsize--; + if (!occupant[y][x]) + mvaddch(y+1,x*2,ch); + } + y = (y + rand_mod(3) + YSIZE99) % YSIZE; + x = (x + rand_mod(3) + XSIZE99) % XSIZE; + } +} diff --git a/src/games/warp/them.h b/src/games/warp/them.h new file mode 100644 index 0000000..711437b --- /dev/null +++ b/src/games/warp/them.h @@ -0,0 +1,11 @@ +/* $Header: them.h,v 7.0 86/10/08 15:14:19 lwall Exp $ */ + +/* $Log: them.h,v $ + * Revision 7.0 86/10/08 15:14:19 lwall + * Split into separate files. Added amoebas and pirates. + * + */ + +void their_smarts(); +void modify_amoeba(); +void them_init(); diff --git a/src/games/warp/us.c b/src/games/warp/us.c new file mode 100644 index 0000000..b657c3a --- /dev/null +++ b/src/games/warp/us.c @@ -0,0 +1,510 @@ +/* $Header: us.c,v 7.0.1.3 87/01/13 17:13:21 lwall Exp $ */ + +/* $Log: us.c,v $ + * Revision 7.0.1.3 87/01/13 17:13:21 lwall + * Partially fixed ^S behavior. It now just ignores ^S. + * + * Revision 7.0.1.2 86/12/12 17:06:09 lwall + * Baseline for net release. + * + * Revision 7.0.1.1 86/10/16 10:53:50 lwall + * Added Damage. Fixed random bugs. + * + * Revision 7.0 86/10/08 15:14:21 lwall + * Split into separate files. Added amoebas and pirates. + * + */ + +#include "EXTERN.h" +#include "warp.h" +#include "bang.h" +#include "object.h" +#include "play.h" +#include "sig.h" +#include "term.h" +#include "util.h" +#include "weapon.h" +#include "INTERN.h" +#include "us.h" + +void +us_init() +{ + ; +} + +void +do_direction(dy,dx) +int dy, dx; +{ + register int decr; + register OBJECT *obj; + + if (status < 2) { + if (cloaking) { + char ch; + + cloaked = FALSE; + ch = (ent->energy >= 500?'E':'e'); + if (ch != ent->image) { + setimage(ent, ch); + } + } + decr = 5+abs(evely)+abs(evelx)+tractor*tractor; + if (ent->energy >= decr) { + ent->energy -= decr; + if (tractor) { + if (!damage || !damflag[NOTRACTORS]) { + if (!rand_mod(50)) { + damage++; + damflag[NOTRACTORS] = rand_mod(smarts+10)+2; + } + if (tract(ent,dy,dx,tractor)) { + evely += tractor*dy; + evelx += tractor*dx; + } + } + } + else if (!damage || + (!entmode && !damflag[NOIMPULSE]) || + (entmode && !damflag[NOWARP]) ) { + if (!rand_mod(30+500/(abs(evely)+abs(evelx)+1))) { + damage++; + damflag[entmode?NOWARP:NOIMPULSE] = rand_mod(smarts+10)+2; + } + evely += dy; + evelx += dx; + } + if (inumthols && + (obj=occupant[(ent->posy+evely+YSIZE00)%YSIZE] + [(ent->posx+evelx+XSIZE00)%XSIZE] ) && + obj->type == Web) + evely = evelx = 0; + } + } + else if (status == 2) { + decr = 500+abs(bvely)*5+abs(bvelx)*5+tractor*tractor*100; + if (base->energy >= decr) { + base->energy -= decr; + if (tractor) { + if (tract(base,dy,dx,tractor)) { + bvely += tractor*dy; + bvelx += tractor*dx; + } + } + else { + bvely += dy; + bvelx += dx; + } + if (inumthols && + (obj=occupant[(base->posy+bvely+YSIZE00)%YSIZE] + [(base->posx+bvelx+XSIZE00)%XSIZE] ) && + obj->type == Web) + bvely = bvelx = 0; + } + } + tractor = 0; +} + +void +ctrl_direction(dy,dx) +int dy, dx; +{ + if (status < 2) { + if (cloaking) { + char ch; + + cloaked = FALSE; + ch = (ent->energy >= 500?'E':'e'); + if (ch != ent->image) { + setimage(ent, ch); + } + } + if (!damage || !damflag[NOPHASERS]) { + if (!rand_mod(200)) { + damage++; + damflag[NOPHASERS] = rand_mod(smarts+10)+2; + } + fire_phaser(ent, dy, dx); + } + } + else if (status == 2) + fire_phaser(base, dy, dx); +} + +void +shift_direction(dy,dx) +int dy, dx; +{ + if (status < 2) { + if (cloaking) { + char ch; + + cloaked = FALSE; + ch = (ent->energy >= 500?'E':'e'); + if (ch != ent->image) { + setimage(ent, ch); + } + } + if (!damage || !damflag[NOTORPS]) { + if (!rand_mod(300)) { + damage++; + damflag[NOTORPS] = rand_mod(smarts+10)+2; + } + fire_torp(ent, dy, dx); + } + } + else if (status == 2) + fire_torp(base, dy, dx); +} + +void +get_commands(done) +bool *done; +{ + static char ch[80]; + register int i; + register int count; + register bool ctrla = FALSE; + char numdestructs = 0, numzaps = 0; + +top: + while (count = read_nd(ch,(sizeof ch))) { + for (i=0; i= whenok) { + mvaddstr(12,22,quest); + do { + getcmd(&ch[i]); + } while (ch[i] != 'y' && ch[i] != 'n'); + if (ch[i] == 'y') { + bombed_out = TRUE; + *done = TRUE; + return; + } + else { + for (x=11; x<=28; x++) { + mvaddch(12,x*2, + occupant[11][x] + ? occupant[11][x]->image + : numamoebas + ? amb[11][x] + : ' '); + addspace(); + } + roundsleep(2); + whenok = timer + 10; + goto top; + } + } + else { + write(1,"\07",1); + goto top; + } + } + } + for (i=0; ienergy >= 250) + cloaking = TRUE; + } + break; + case 'z': + if (ent && (!damage || !damflag[NOZAPPER])) { + ++numzaps; + if (!rand_mod(100/numzaps)) { + damage++; + damflag[NOZAPPER] = rand_mod(smarts+10)+2; + } + if (nxtbang && bangm[nxtbang-1] < 0) + --nxtbang; /* consolidate zaps */ + make_blast(evely*2+ent->posy,evelx*2+ent->posx, + -5000000L, 3*numzaps); + ent->energy /= 2; + } + break; + case 'D': + if (status < 2 && (!damage || !damflag[NODESTRUCT])) { + if (ent && !rand_mod(10)) { + damage++; + damflag[NODESTRUCT] = rand_mod(smarts+10)+2; + } + if (++numdestructs <= 2) + make_blast(evely*2+ent->posy,evelx*2+ent->posx, + 15000L, 3); + ent->energy /= 4; + } + else if (status == 2) { + if (numdestructs) + base->energy = base->energy / 2; + if (++numdestructs <= 2) + make_blast(base->posy, base->posx, 15000L, 5); + } + break; + case 'd': + if ((!damage || !damflag[NODESTRUCT]) && (base||ent)) { + register OBJECT *obj; + int x, y; + + if (ent && !rand_mod(200)) { + damage++; + damflag[NODESTRUCT] = rand_mod(smarts+10)+2; + } + for (obj = root.prev; + obj != &root; + obj = obj->prev) { + if (obj->image == '+') { + blast[y=(obj->posy+obj->vely+YSIZE00)%YSIZE] + [x=(obj->posx+obj->velx+XSIZE00)%XSIZE] + += 1; + yblasted[y] |= 1; + xblasted[x] |= 1; + blasted = TRUE; + obj->mass = (massacre?3000:4000); + } + } + } + break; + case 's': + if ((!damage || !damflag[NODESTRUCT]) && (base||ent)) { + register OBJECT *obj; + if (ent && !rand_mod(200)) { + damage++; + damflag[NODESTRUCT] = rand_mod(smarts+10)+2; + } + for (obj = root.prev; + obj->type == Torp || obj->type == Web || + obj->type == Star; + obj = obj->prev) { + if (obj->image == '+') + obj->vely = obj->velx = 0; + } + } + break; + case '\001': + ctrla = TRUE; + break; + case '\002': + case '\003': + case '\004': + case '\005': + case '\006': + case '\007': + case '\010': + case '\011': + case '\012': + case '\013': + case '\014': + case '\015': + case '\016': + case '\017': + case '\020': + case '\021': + case '\022': + case '\023': + case '\024': + case '\025': + case '\026': + case '\027': + case '\030': + case '\031': + case '\032': + ch[i] += 96; + i--; + ctrla = TRUE; + break; + case '\033': + tractor = 0; + break; + case 'a': + tractor++; + break; + case 'r': + tractor--; + break; + case '1': case 'b': + do_direction(1,-1); + break; + case '2': case 'j': + do_direction(1,0); + break; + case '3': case 'n': + do_direction(1,1); + break; + case '4': case 'h': + do_direction(0,-1); + break; + case '6': case 'l': + do_direction(0,1); + break; + case '7': case 'y': + do_direction(-1,-1); + break; + case '8': case 'k': + do_direction(-1,0); + break; + case '9': case 'u': + do_direction(-1,1); + break; + case '0': case 'S': + if (status < 2) { + evely = 0; + evelx = 0; + } + break; + case '-': + if (status < 2 && ent->energy >= 10) { + evely *= -1; + evelx *= -1; + ent->energy -= 10; + } + break; + case '%': case '\177': case '_': + shift_direction(0, -1); + shift_direction(0, 1); + shift_direction(-1, 0); + shift_direction(1, 0); + shift_direction(-1, -1); + shift_direction(-1, 1); + shift_direction(1, -1); + shift_direction(1, 1); + break; + case '!': case 'B': + shift_direction(1, -1); + break; + case '@': case 'J': + shift_direction(1, 0); + break; + case '#': case 'N': + shift_direction(1, 1); + break; + case '$': case 'H': + shift_direction(0, -1); + break; + case '^': case 'L': + shift_direction(0, 1); + break; + case '&': case 'Y': + shift_direction(-1, -1); + break; + case '*': case 'K': + shift_direction(-1, 0); + break; + case '(': case 'U': + shift_direction(-1, 1); + break; + case '?': + helper(); + roundsleep(3); + goto top; + default: + break; + } + } + } + } +} diff --git a/src/games/warp/us.h b/src/games/warp/us.h new file mode 100644 index 0000000..ce29b42 --- /dev/null +++ b/src/games/warp/us.h @@ -0,0 +1,61 @@ +/* $Header: us.h,v 7.0.1.1 86/10/16 10:53:58 lwall Exp $ */ + +/* $Log: us.h,v $ + * Revision 7.0.1.1 86/10/16 10:53:58 lwall + * Added Damage. Fixed random bugs. + * + * Revision 7.0 86/10/08 15:14:27 lwall + * Split into separate files. Added amoebas and pirates. + * + */ + +EXT bool cloaking; +EXT bool cloaked; + +EXT int status; +EXT int entmode; + +EXT int evely; +EXT int evelx; +EXT int bvely; +EXT int bvelx; + +#define MAXDAMAGE 9 +#define NOWARP 0 +#define NOIMPULSE 1 +#define NOPHASERS 2 +#define NOTORPS 3 +#define NOCLOAKING 4 +#define NOSHIELDS 5 +#define NOZAPPER 6 +#define NODESTRUCT 7 +#define NOTRACTORS 8 + +EXT int dam INIT(0); +EXT int lastdam INIT(-1); +EXT int damage INIT(0); +EXT int olddamage INIT(-1); + +#ifdef DOINIT +char *dammess[MAXDAMAGE] = { + "WARP", + "IMPULSE", + "PHASERS", + "TORPS", + "CLOAKING", + "SHIELDS", + "ZAPPER", + "DESTRUCT", + "TRACTORS" +}; +char damflag[MAXDAMAGE] = {0,0,0,0,0,0,0,0,0}; +#else +extern char *dammess[]; +extern char damflag[]; +#endif + +void do_direction(); +void ctrl_direction(); +void shift_direction(); +void get_commands(); +void us_init(); diff --git a/src/games/warp/util.c b/src/games/warp/util.c new file mode 100644 index 0000000..709ac96 --- /dev/null +++ b/src/games/warp/util.c @@ -0,0 +1,197 @@ +/* $Header: util.c,v 7.0.1.2 86/10/20 12:07:46 lwall Exp $ */ + +/* $Log: util.c,v $ + * Revision 7.0.1.2 86/10/20 12:07:46 lwall + * Made all exits reset tty. + * + * Revision 7.0.1.1 86/10/16 10:54:02 lwall + * Added Damage. Fixed random bugs. + * + * Revision 7.0 86/10/08 15:14:31 lwall + * Split into separate files. Added amoebas and pirates. + * + */ + +#include "EXTERN.h" +#include "warp.h" +#include "object.h" +#include "sig.h" +#include "term.h" +#include "INTERN.h" +#include "util.h" + +void +util_init() +{ + ; +} + +void +movc3(len,src,dest) +register char *dest; +register char *src; +register int len; +{ + if (dest <= src) { + for (; len; len--) { + *dest++ = *src++; + } + } + else { + dest += len; + src += len; + for (; len; len--) { + *--dest = *--src; + } + } +} + +void +no_can_do(what) +char *what; +{ + fprintf(stderr,"Sorry, your terminal is too %s to play warp.\r\n",what); + finalize(1); +} + +int +exdis(maxnum) +int maxnum; +{ + double temp, temp2; + double exp(); + double log(); + + temp = (double) maxnum; + temp2 = (double) myrand(); + return (int) exp(temp2 * log(temp)/0x7fff); +} + +static char nomem[] = "warp: out of memory!\r\n"; + +/* paranoid version of malloc */ + +char * +safemalloc(size) +MEM_SIZE size; +{ + char *ptr; + + ptr = malloc(size?size:1); /* malloc(0) is NASTY on our system */ + if (ptr != Nullch) + return ptr; + else { + fputs(nomem,stdout); + sig_catcher(0); + } + /*NOTREACHED*/ +} + +/* safe version of string copy */ + +char * +safecpy(to,from,len) +char *to; +register char *from; +register int len; +{ + register char *dest = to; + + if (from != Nullch) + for (len--; len && (*dest++ = *from++); len--) ; + *dest = '\0'; + return to; +} + +/* copy a string up to some (non-backslashed) delimiter, if any */ + +char * +cpytill(to,from,delim) +register char *to; +register char *from; +register int delim; +{ + for (; *from; from++,to++) { + if (*from == '\\' && from[1] == delim) + from++; + else if (*from == delim) + break; + *to = *from; + } + *to = '\0'; + return from; +} + +/* return ptr to little string in big string, NULL if not found */ + +char * +instr(big, little) +char *big, *little; + +{ + register char *t; + register char *s; + register char *x; + + for (t = big; *t; t++) { + for (x=t,s=little; *s; x++,s++) { + if (!*x) + return Nullch; + if (*s != *x) + break; + } + if (!*s) + return t; + } + return Nullch; +} + +/* effective access */ + +#ifdef SETUIDGID +int +eaccess(filename, mod) +char *filename; +int mod; +{ + int protection, euid; + + mod &= 7; /* remove extraneous garbage */ + if (stat(filename, &filestat) < 0) + return -1; + euid = geteuid(); + if (euid == 0) + return 0; + protection = 7 & (filestat.st_mode >> + (filestat.st_uid == euid ? 6 : + (filestat.st_gid == getegid() ? 3 : 0) + )); + if ((mod & protection) == mod) + return 0; + errno = EACCES; + return -1; +} +#endif + +/* copy a string to a safe spot */ + +char * +savestr(str) +char *str; +{ + register char *newaddr = safemalloc((MEM_SIZE)(strlen(str)+1)); + + strcpy(newaddr,str); + return newaddr; +} + +char * +getval(nam,def) +char *nam,*def; +{ + char *val; + + if ((val = getenv(nam)) == Nullch || !*val) + val = def; + return val; +} diff --git a/src/games/warp/util.h b/src/games/warp/util.h new file mode 100644 index 0000000..04430d1 --- /dev/null +++ b/src/games/warp/util.h @@ -0,0 +1,33 @@ +/* $Header: util.h,v 7.0 86/10/08 15:14:37 lwall Exp $ */ + +/* $Log: util.h,v $ + * Revision 7.0 86/10/08 15:14:37 lwall + * Split into separate files. Added amoebas and pirates. + * + */ + +#define RANDRAND 268435456.0 /* that's 2**28 */ +#define HALFRAND 0x4000 /* that's 2**14 */ +int rand(); +#define myrand() (rand()&32767) +#define rand_mod(m) ((int)((double)myrand() / 32768.0 * ((double)(m)))) +/* pick number in 0..m-1 */ + +#define roundsleep(x) sleep(x) + +void movc3(); +void no_can_do(); +int exdis(); + +EXT bool waiting INIT(FALSE); /* are we waiting for subprocess (in doshell)? */ + +void util_init(); +char *safemalloc(); +char *safecpy(); +char *cpytill(); +char *instr(); +#ifdef SETUIDGID + int eaccess(); +#endif +char *savestr(); +char *getval(); diff --git a/src/games/warp/version.c b/src/games/warp/version.c new file mode 100644 index 0000000..99a8ace --- /dev/null +++ b/src/games/warp/version.c @@ -0,0 +1,22 @@ +/* $Header: version.c,v 7.0 86/10/08 15:14:39 lwall Exp $ + * + * $Log: version.c,v $ + * Revision 7.0 86/10/08 15:14:39 lwall + * Split into separate files. Added amoebas and pirates. + * + */ + +#include "patchlevel.h" +#include "INTERN.h" +#include "version.h" +#include + +/* Print out the version number. */ + +void +version() +{ + extern char rcsid[]; + + printf("%s\r\nPatch level: %d\r\n", rcsid, PATCHLEVEL); +} diff --git a/src/games/warp/version.h b/src/games/warp/version.h new file mode 100644 index 0000000..646d06d --- /dev/null +++ b/src/games/warp/version.h @@ -0,0 +1,9 @@ +/* $Header: version.h,v 7.0 86/10/08 15:14:43 lwall Exp $ + * + * $Log: version.h,v $ + * Revision 7.0 86/10/08 15:14:43 lwall + * Split into separate files. Added amoebas and pirates. + * + */ + +void version(); diff --git a/src/games/warp/warp.6 b/src/games/warp/warp.6 new file mode 100644 index 0000000..a5b0ced --- /dev/null +++ b/src/games/warp/warp.6 @@ -0,0 +1,133 @@ +.TH WARP 6 +.SH NAME +warp - a real-time space war game +.SH SYNOPSIS +.B warp [options] +.SH DESCRIPTION +.I Warp +is a real-time space war game that requires skill and quick thinking. +"Real-time" in this context means that the enemies keep moving (and shooting) +even if you don't. +A unique feature of +.I warp +is that blast propagates; it is unhealthy to remain near things that are +in the process of blowing up. +If a given universe is above a critical density it may chain react. +Scoring is like many popular arcade games--there are multiple waves which +get harder and harder as you go along. +Nobody has ever maxed out the scoreboard without cheating. +.PP +Unlike many space-war games, +.I warp +is not simply a shooting gallery. +Along with phasers and photon torpedoes, you have tractor beams and a cloaking +device. +Skill in navigation is important. +It helps to be schizophrenic, because you must manage an Enterprise and a Base +simultaneously. +And enemies do not simply shoot back. +You can get tailed, absorbed, snuck up upon, hemmed in, rammed, loved to death, +reprimanded for destroying civilized life, dragged around, robbed, damaged +and eaten. +And if you should happen to get bored by the enemies (a trifle unlikely), +you can always watch the interesting star patterns. +In fact, you'll have to, since your tactics will depend upon what kind of +universe you find yourself in. +.PP +.I Warp +is played in a double wraparound universe, i.e. the bottom is connected to the +top, and the right is connected to the left. +You need a crt with random cursor addressing and at least 24 lines by 80 +columns. +For more information about about how to play, simply run +.I warp +and say "y" when it asks if you want to see the instructions. +There is also a single-page command summary that you can get while playing +by typing a "?". +.PP +Command line options include: +.TP 5 +.B -b +Put +.I warp +into beginner mode. +Makes the difficulty increase more slowly, but penalizes you for it. +.TP 5 +.B -d +Sets the initial difficulty to +.BR n . +.TP 5 +.B -l +Play a low-speed game. +Changes the basic cycle time from 1 second to 2 seconds. +This switch is automatically set at baud rates below 2400. +You may want to set it at higher speeds if your terminal cannot keep up +with the output. +(This should never happen on BSD systems, which have an IOCTL call to +determine output queue length.) +Because this makes the game easier, a separate scoreboard is kept for +low-speed games. +.TP 5 +.B -m +Terminal has a meta key which turns on the eighth bit. Ordinarily the +eighth bit is stripped in order to ignore parity. +Metacharacters will appear to the keymap as prefixed with a ^A, and will +subsequently have the same effect as a control character, unless otherwise +mapped. +.TP 5 +.B -s +Just prints out the scoreboards and saved games and then exits. +.TP 5 +.B -v +Prints out the version number. +.TP 5 +.B -x +Play an experimental game. +This causes +.I warp +to ignore any saved game, and disables the ability to save +the current game. +Thus you can play around with something or show +.I warp +to someone without jeopardizing a currently saved game. +.SH ENVIRONMENT +.TP 5 +.B WARPMACRO +If defined, names a file containing keyboard mappings and macros. +If not defined, the value %X/Kbmap.%{TERM} is assumed. +The macro file contains lines of the following form: +.sp + +.sp +You may use certain % interpolations and ^ control characters. +For possible % interpolations see warp.h. +Sequences in the canonical-keystroke-sequence bounded by ^(...^) are +subject to reinterpretation via the keymap. +This file has two major uses. +First, you can set up your commands to use any kind of prefix key your terminal +might have, or change the key bindings in any other way you choose. +Second, you can define arbitrary macros, such as this: +.sp +# define Corbamite maneuver += DDllllll +.SH AUTHOR +Larry Wall +.SH FILES +~/.fullname, if full names aren't in /etc/passwd +.SH DIAGNOSTICS +Generally self-documenting, as they say. +.SH BUGS +Addicting. +At the end of a wave, all you have to do to keep going is hit a space. +You see the message "Hit space to continue" and automatically hit space. +About 2 seconds later you remember you wanted to go home, but by then +it's too late to escape without penalty. +.PP +You can't kill a backgrounded +.I warp +process directly, because it is running setuid. +You have to use the killer built in to +.IR warp . +.PP +Now that there is a space amoeba, there ought to be tribbles. +But it might be too much trouble... diff --git a/src/games/warp/warp.c b/src/games/warp/warp.c new file mode 100644 index 0000000..fb213e4 --- /dev/null +++ b/src/games/warp/warp.c @@ -0,0 +1,381 @@ +char rcsid[] = "@(#)$Header: warp.c,v 7.0.1.3 86/12/12 17:07:44 lwall Exp $"; + +/* warp -- a real-time space war program + * author: Larry Wall + * helpers: Jonathan and Mark Biggar, and Dan Faigin + * special thanks to my sweetie Gloria who suggested the Planet Crusher + * + * Copyright (C) 1986, Larry Wall + * + * This program may be copied as long as this copyright notice is + * included, and as long as it is not being copied for purposes + * of profit. If you want to modify this program in any way other + * than normal configuration changes, common decency would suggest + * that you also modify the name of the program so that my good name + * (what there is of it) is not impugned. (Calling it something like + * "warpx" or "superwarp" would be fine.) Also, give it another + * WARPDIR so that the scoreboards don't get confused. + * + * version 5.0 04/20/83 + * 5.1 05/05/83 various tidbits + * 5.2 05/12/83 VAX -> vax, ifdef'ed a SIGCONT + * 5.3 05/24/83 RCS + * + * $Log: warp.c,v $ + * Revision 7.0.1.3 86/12/12 17:07:44 lwall + * Baseline for net release. + * + * Revision 7.0.1.2 86/10/20 12:08:00 lwall + * Made all exits reset tty. + * + * Revision 7.0.1.1 86/10/16 10:54:13 lwall + * Added Damage. Fixed random bugs. + * + * Revision 7.0 86/10/08 15:14:47 lwall + * Split into separate files. Added amoebas and pirates. + * + * Revision 6.4 83/12/16 13:11:45 lwall + * Handled 15 bit random number generators. + * + * Fixed array overflow bug on multiple zaps. + * + * Multiple zaps now consolidated to minimize output. + * + * Tholian jackpot games outlawed under difficulty 15. + * + * Revision 6.3 83/08/24 11:17:49 lwall + * Fixed array overflow bug on multiple zap. + * + * Revision 6.2 83/08/23 18:06:37 lwall + * Added zap command. + * Warp -s should now work on dumb terminals + * Specifying difficulty >= 40 now just makes it a special game. + * SIGTTOU #ifdef'ed. + * No-delay read provided as alternative to FIONREAD. + * Warp won't report "-1 obsolete" when there are no Enterprises left. + * Some high-difficulty tuning. + * + * Revision 6.1 83/08/17 08:49:03 lwall + * Fixed obscure bug in storing UP that caused a %. in CM to occasionally + * foist garbage onto the screen. + * + * Revision 6.0 83/08/08 17:09:26 lwall + * New baseline version for net release. + * + * Revision 5.5 83/08/01 10:59:56 lwall + * Cloaking for the Enterprise. + * Difficulty now goes to 99, and many activities depending on difficulty + * have been adjusted in frequency. + * Simplified exit sequence, and reduced dependencies on control + * characters. You needn't see the scoreboard if you don't want to. + * Hitting i,w,c, or v switches to Enterprise. Hitting p switches to Base. + * Excessive use of q is not allowed. + * Excessive use of D is not allowed. + * Scoreboard may depend on either full name or login name. + * Integrated scoreboard lister. Login name now shows up on scoreboard. + * "Hidden" startup options are now upper case. + * Checks upon startup for no cursor movement, or screen too small. + * Checks upon startup that WARPDIR is correctly protected, and that warp + * is running setuid. As an additional bonus this prevents root from + * running warp, which mucks things up, UN*X be blessed. + * All gets's turned into fgets's for safety. + * Bonus Enterprises and Bases. + * Escalating bonuses for saving Base and Enterprise. + * Escalating Enterprise energy. + * Turbolasers decrease with distance. + * Really smart enemies can see through stars occasionally. + * Occasional Tholian jackpot waves. Tholians are a trifle nastier. + * Choleric Gorns. + * An O or o can miss seeing you. Enemies can avoid a stationary O, o, or X. + * Warp 3 enemies and other nastinesses are possible in massacre mode. + * Enemies that decide to navigate when they see you can do other things than + * just come toward you. + * Gorns occasionally launch a salvo for the fun of it. + * Only star and enemy explosions can keep the round going now. + * Bounces don't always go back to starting spot now. + * Better full name processing. USG quirks handled. & substitution also + * handled now (whoever dreamed up that one must have been in the middle + * of the night before the morning after). + * Catch ^D on fgets. + * Version number printer. + * Less signal catching during debugging. + * + * Revision 5.4 83/06/24 09:28:38 lwall + * 16 bit random number generators are now supported. + * Made warp not blow up on a null save file. + * Warp now prints E and B before the stars. + * Fixed bug which caused torp count to get decremented even when no torp + * was launched because of an obstacle. + * Put %ld formats where appropriate. + * Fixed E: 0 0 bug on refresh. + * + * Revision 5.3 83/05/24 14:03:10 lwall + * Starting RCS + * + */ + +#include "INTERN.h" +#include "warp.h" +#include "EXTERN.h" +#include "bang.h" +#include "init.h" +#include "intrp.h" +#include "object.h" +#include "move.h" +#include "play.h" +#include "score.h" +#include "sig.h" +#include "term.h" +#include "them.h" +#include "us.h" +#include "util.h" +#include "version.h" +#include "weapon.h" + +main(argc,argv) +int argc; +char *argv[]; +{ + char tmp, *s, *tcbuf; + + int i; + + FILE *savfil; + +rand_ok: + + while (--argc > 0 && (*++argv)[0] == '-') + for (s = argv[0]+1; *s != '\0'; s++) + switch (*s) { + case '&': + amoebaspec = TRUE; + beginner = TRUE; + break; + case 'A': + apolspec = TRUE; + beginner = TRUE; + break; + case 'b': + beginner = TRUE; + break; + case 'C': + crushspec = TRUE; + beginner = TRUE; + break; + case 'D': + debugging = TRUE; +#ifdef DEBUGGING + debug = atoi(++s); +#endif + s += strlen(s)-1; + break; + case 'd': + s++; + if (*s == '=') s++; + ismarts = atoi(s); + if (ismarts <= 0) + ismarts = 1; + if (ismarts > 99) + ismarts = 99; + if (ismarts > 40) + beginner = TRUE; + s += strlen(s)-1; + break; + case 'E': + klingspec = TRUE; + beginner = TRUE; + s++; + if (*s == '=') s++; + inumenemies = atoi(s); + s += strlen(s)-1; + break; + case 'F': + friendspec = TRUE; + beginner = TRUE; + s++; + if (*s == '=') s++; + inumfriends = atoi(s); + s += strlen(s)-1; + break; + case 'G': + gornspec = TRUE; + beginner = TRUE; + break; + case 'l': + lowspeed = TRUE; + break; + case 'm': + metakey = TRUE; + break; + case 'M': + massacre = TRUE; + break; + case 'P': + piratespec = TRUE; + beginner = TRUE; + s++; + if (*s == '=') s++; + inumpirates = atoi(s); + s += strlen(s)-1; + break; + case 'S': + prespec = TRUE; + beginner = TRUE; + s++; + if (*s == '=') s++; + if (*s) + prescene = atoi(s); + else + prescene = -1; + s += strlen(s)-1; + break; + case 'R': + romspec = TRUE; + beginner = TRUE; + break; + case '*': + starspec = TRUE; + beginner = TRUE; + s++; + if (*s == '=') s++; + inumstars = atoi(s); + s += strlen(s)-1; + break; + case 's': + scorespec = TRUE; + break; + case 'T': + tholspec = TRUE; + beginner = TRUE; + break; + case 'x': + experimenting = TRUE; + break; + case 'v': + version(); + exit(0); + break; + default: + fprintf(stderr,"warp: illegal option %c\n", *s); + fprintf(stderr, "Usage: warp -dn -b -x -v -s\n"); + exit(1); + } + if (argc != 0) { + fprintf(stderr, "Usage: warp -dn -b -x -v -s\n"); + exit(1); + } + bang_init(); + move_init(); + object_init(); + play_init(); + them_init(); + us_init(); + util_init(); + weapon_init(); + + tcbuf = malloc(1024); + intrp_init(tcbuf); + + if (chdir(warplib) < 0) + fprintf(stderr,nocd,warplib); + + term_init(); + + term_set(tcbuf); + free(tcbuf); + + umask(022); /* mustn't rely on incoming umask--could be 033 which */ + /* would disable people from running wscore */ + + score_init(); + + sig_init(); + + if (totalscore) { + clear(); + mvaddstr(12,25,"*** restoring saved game ***"); + roundsleep(1); + } + + srand(getpid()); + + do { + for (keepgoing = TRUE;;) { + if (!experimenting) { + if ((savfil = fopen(savefilename,"w")) == NULL) { + resetty(); + printf("Can't open savefile\r\n"); + finalize(1); + } + fprintf(savfil, + "%-8s %10ld, %2d,%5d,%2d,%2d,%3d %c%c%c%c%c%c%c%c%c\n", + logname, totalscore, smarts, cumsmarts, + numents, numbases, wave, + apolspec ? 'a' : ' ', + beginner ? 'b' : ' ', + crushspec ? 'c' : ' ', + gornspec ? 'g' : ' ', + massacre ? 'm' : ' ', + romspec ? 'r' : ' ', + tholspec ? 't' : ' ', + lowspeed ? 'l' : ' ', + amoebaspec ? '&' : ' ' + ); + fprintf(savfil," running on %s, process #%d\n", + term+5,getpid()); + Fclose(savfil); + } + + lastscore = totalscore; + initialize(); + play(); + cumsmarts += smarts; + wavescore(); + if (numents<=0 && numbases<=0) + keepgoing = FALSE; + if (!keepgoing) break; + do { + if (experimenting) { + mvaddstr(23,15, + " [Hit space to continue, 'q' to quit] "); + } + else { + mvaddstr(23,15, + "[Hit space to continue, 's' to save, 'q' to quit]"); + } + sleep(1); + Fflush(stdout); + eat_typeahead(); + getcmd(&tmp); + if (tmp == BREAKCH || tmp == INTRCH) { + mvaddstr(23,15, + " "); + mvaddstr(23,33, + "Really quit? "); + getcmd(&tmp); + if (tmp == 'y' || tmp == 'Y') + tmp = 'q'; + else + tmp = 1; + } + } while (tmp != INTRCH && tmp != BREAKCH && !strchr(" qQs",tmp)); + if (tmp != ' ' && tmp != 's') break; + if (!beginner && smarts < 20) + smarts += 4; + else if (!beginner && smarts < 35) + smarts += 2; + else if (smarts < 99) + smarts++; + if (tmp == 's') save_game(); + } + score(); + + } while (justonemoretime); + + if (!experimenting) + unlink(savefilename); + + clear(); + resetty(); + exit(0); +} diff --git a/src/games/warp/warp.doc b/src/games/warp/warp.doc new file mode 100644 index 0000000..bd4c19e --- /dev/null +++ b/src/games/warp/warp.doc @@ -0,0 +1,193 @@ +Warp is a real-time space war game. This means that the enemies will keep +playing even when you sit still. Another peculiarity is that things which +blow up can damage other things around them. Universes above a critical +density may chain react. + +The game starts at difficulty 1, and gets more difficult with each +succeeding wave, up to difficulty 99. You're not likely to get that far. +(Invoking warp with a -b switch causes the difficulty to increase more +slowly, but games count only a tenth as much.) The game starts with +5 Enterprises and 3 Bases, and you get more for surviving long enough. +The game is over when you run out of Enterprises and Bases. + +The object of the game is to get as many points as possible. This is done +by destroying as many enemies as possible. This is not a trivial task. +Each wave starts with one Enterprise and one Base, and continues until +either both the Enterprise and Base are destroyed, or all the enemies +(including any homing torpedoes) are destroyed. It is possible to abort a +wave, but you will be penalized for it. The game may be saved between waves. + +A -x switch causes any saved game to be ignored, and causes the new game +not to be saveable. Hence it is possible to run test games without +invalidating a currently saved game. + +The game is played in a 23 x 40 double wrap-around universe. Everybody +(both you and the enemies) gets the chance to move once every second, +unless a -l (low-speed) switch was given or you are under 2400 baud, in +which case it's every two seconds. The following symbols are displayed: + + FRIENDS +E Enterprise with shields e Enterprise without shields +C Cloaked E with shields c Cloaked E without shields +B Base with shields b Base without shields ++ Friendly torpedo M Harry Mudd + + ENEMIES +K Klingon G Gorn +R Romulan A Apollo + Romulan with cloaking device! & Space Amoeba Nucleus +T Tholian >,< Planet crusher +x,X Hostile torpedo o,O Homing torpedo +P Pirate M Harry Mudd + + MISCELLANEOUS +* Star @ Inhabited star +|,-,/,\ Web ~ Protoplasm +other Friendly Freighter, for now... + +The following keys control the DIRECTION of your various actions: + + h or 4 left + j or 2 down + k or 8 up + l or 6 right + b or 1 down and left + n or 3 down and right + y or 7 up and left + u or 9 up and right + +(You will note that the letters are the same as other visual games, and the +numbers are for use with a keypad.) By themselves, these keys move either +the Enterprise or the Base, whichever is the current vessel. When shifted, +they fire photon torpedoes in the specified direction from the current +vessel. When used with either the CTRL key or the FUNCT key, phasers +(turbo-lasers for the Base) are fired in the specified direction. (CTRL +won't work with numbers, and FUNCT probably doesn't exist on non-TVI +terminals.) When preceded by an 'a', an attractor beam is fired in the +specified direction, and when preceded by an 'r', a repulsor beam is fired. + +These keys have special functions: + + del or % fire photon torpedoes in every (reasonable) direction + s stop all friendly torpedoes + S or 0 stop the Enterprise when in warp mode + d destruct all friendly torpedoes (quite useful) + D destruct the current vessel (commit suicide) + i/w switch to Enterprise and put into impulse/warp mode + c/v switch to Enterprise and put into cloaking/visible mode + p switch to Base (not very mnemonic, but 'b' is taken) + o switch from Enterprise to Base, or vice versa + z zap explosions (multiple zaps extend further) (E only) + + ^R refresh the screen + ^Z suspend the game (on a bsd system) + q asks if you want to exit this wave (will not work + within 10 cycles of previous q command) + Q exit this game (not wave) + ? display a summary of these commands + +There may be additional commands listed in your terminal's keymap file. +Unrecognized keystrokes are ignored. IF YOU FORGET ALL THE OTHER COMMANDS, +REMEMBER "?", which gives you help. + +Commands for moving the Enterprise may operate in one of two ways. If it +is in impulse mode, movement commands affect the position of the ship; +if it is in warp mode, movement commands affect the velocity instead. +The Base always moves in impulse mode. Since multiple commands may be +entered in one turn (if you can type fast enough), it is possible to jump +over things even in impulse mode. In a crowded universe this may be the +only way to go. + +(Actually, motion commands always change the velocity--the actual motion +does not occur until the next turn. Impulse mode simply causes the +velocity to be zeroed out at the end of every turn. Phaser commands, on +the other hand, are executed immediately. If you want to move and fire a +phaser, you must wait for the motion to actually occur before typing the +phaser command, or the phaser fires from your old position. This is a +feature, not a bug, and is intended to reflect reality. Really.) + +If multiple torpedo launching commands are given in a turn, a single torpedo +is launched with extra velocity. You can thus launch photon torpedoes over +objects in the way, and get them where you want them quickly. This feature +works well with the destruct button. Variations on this may be useful +against the Space Amoeba. + +NOTE: Phasers destroy the target by blasting the projected next location of +the object hit. This means that if the object hit, be it Klingon, Romulan or +Enterprise, changes velocity in the same turn, it can elude the effect of +the phaser! (Note that this also means that if you phaser a Klingon or +torpedo that is about to ram you, you will be phasered as well as he/she/it. +This can be embarrassing, not to mention deadly.) Smart players move +immediately upon phasering something at short range, or whenever they +think they might get phasered (in other words, most of the time). + +Objects with larger mass can bounce objects with smaller mass out of the way. +In a crowded universe the bouncee can bounce quite a way before finding an +empty place to land. If you let the Tholians fill up the universe with web, +so that there is no place to bounce to, the Tholians win that wave. + +The status line across the top gives the current mode, the number of +points accumulated this wave, the Enterprise's energy and torpedoes, the +Base's energy and torpedoes, the number of stars, the number of enemies, +and the stardate. You will note that nice things happen to your energy levels +when you put the Enterprise next to the Base, or the Base next to some stars. +Bad things happen inside an Amoeba. + +An object is destroyed when its energy goes negative, either from a direct +hit, or from the blast of the previous turn's explosions. Enemies and +stars start with random amounts of energy. High energy enemies can go warp +2. A Romulan with sufficient energy maintains a cloaking device. Tholians +spin web, Gorns shoot homing torpedoes, and the Planet Crusher munches +anything in its way, even Apollo. Apollo won't let you go unless you kill +him, but he loves you very much and beefs up your shields considerably. +Both Apollo and the Planet Crusher recharge themselves, so you must hit +them hard in a single turn to do them in. (Yes, the Planet Crusher must be +shot in the mouth--he can only die of gluttony--and he blasts out of his +mouth when he dies.) Tholian web may be crossed only by coasting across it +in warp mode, or by blasting it (but web blasts extend twice as far as +normal blasts, so keep your distance). The Space Amoeba sucks energy and +grows, and you must destroy the nucleus. Somehow. There are at least four +ways. Phasers won't work on the big ones. + +Pirates turn inhabited star systems into uninhabited ones. Even Friendly +Freighters will take potshots at you if you get them mad enough. + +Note that because of the size of the Base's turbo-lasers (the Base does not +have phasers) they cannot shoot anything next to the Base. (This is why the +Death Star died!) In part, this is to protect the Enterprise. It also lets +you shoot over one adjacent star. The Enterprise's phasers will shoot over +a arbitrary number of adjacent, contiguous stars, including inhabited ones. +Phasers die away with distance, so don't expect them to kill everything with +one blow. + +While the Enterprise's shields are up (when it is displayed as "E" rather +than "e"), hits on it count only a fifth as much (or even less if you are +moving in warp mode). The shields are automatically maintained as long as +there are more than 500 units of energy for the Enterprise. The Base also +has shields, which stay up as long as it has at least 1000 units of energy. + +Aside from losing energy, the Enterprise can also take damage, either random +damage from getting blasted, or specific damage when a system is in use +and breaks down under the load. In place of the score you will see the +Estimated Time to Repair. Sometimes docking helps to get things fixed faster. +If you lose both your warp and impulse engines, try the tractors. The +Base doesn't take damage because it has much more redundancy than the +Enterprise. + +You get points for destroying enemies and hostile torpedoes. At the end of +a wave, you also get bonus points for saving stars, saving the Enterprise +and Base, and for having an efficiency rating higher that 0.8. You get +NEGATIVE bonus points for letting friendly life forms get blown up, and for +giving up. Bonuses tend to be scaled by the ratio of the number of points +you got over the number of points you could have got. If you think you are +done with a wave, but it won't quit, there may be homing torpedoes that you +haven't destroyed--you must make the universe safe for posterity, you know. + +When you have used up your Enterprises and Bases (or quit), your score will +be posted to the scoreboard. You may see the scoreboard outside of the game +simply by giving the command "warp -s". + +If you get bored, you can always play with some of the undocumented switches +that are used to test warp. Such funny games go on their own scoreboard. +For kicks try "warp -x -d50 -C -\& -G -T -E400 -S5" and then go hide. Quick. + diff --git a/src/games/warp/warp.h b/src/games/warp/warp.h new file mode 100644 index 0000000..0682a73 --- /dev/null +++ b/src/games/warp/warp.h @@ -0,0 +1,402 @@ +/* $Header: warp.h,v 7.0.1.3 95/21/1 17:08:42 lwall Exp $ */ + +/* $Log: warp.h,v $ + * Revision 7.0.1.3 95/21/1 18:40:00 sms + * Remove ifdefs around pwd.h + * + * Revision 7.0.1.2 86/12/12 17:08:42 lwall + * Baseline for net release. + * + * Revision 7.0.1.1 86/10/16 10:54:26 lwall + * Added Damage. Fixed random bugs. + * + * Revision 7.0 86/10/08 15:17:55 lwall + * Split into separate files. Added amoebas and pirates. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include + +/* WARPLIB must be readable and writeable by warp, but not by anyone who you + * don't trust. In other words, to set up warp so everyone can play and + * no one can cheat, give warp a uid of its own and make warp setuid to + * that uid. WARPLIB must then NOT be made writeable by the world, + * since no attempt is made to encrypt saved games or anything. + * (It must be readable by the world, however, due to a strangeness in + * access.) + */ + +#define SAVEDIR "./" +#define NEWSFILE "warp.news" +#define HELPFILE "warp.doc" +#define LOCKFILE ".warp.lock" +#define LOGFILE "warp.log" +#define SCOREBOARD "warp.top" +#define LSCOREBOARD "warp.lowtop" +#define FSCOREBOARD "warp.funtop" +#define TMPSCOREBOARD "warp.topnew" +#define WARPMACRO "%X/Kbmap.%{TERM}" + +/* warp library */ +#ifndef WARPLIB /* ~ and %l only ("~%l" is permissable) */ +# define WARPLIB "/usr/games/warp" +#endif + +EXT char *warplib; + +#define PERMMAPS 8 /* how many starmaps are permanent */ +#define MAPS 20 /* how many starmaps to choose from */ + /* (MAPS - PERMMAPS is # of half-gone universes) */ + +/* + * Screen size info, minimum screen size is 23x40 (actually 24x80). + * YSIZE and XSIZE should be relatively prime so that a torpedo launched + * at an angle will eventually cover the whole screen. + * To calculate a new position for something: + * new_position = (current_position + delta + ?SIZE00) % ?SIZE + * This allows for negative deltas of up to ?SIZE00 (% doesn't work right + * on negative numbers). + * ?SIZE01, etc. are fudges for efficiency--they already include a delta. + */ + +#define XYSIZE 920 +#define XYSIZEx4 3680 + +#define YSIZE 23 +#define YSIZE00 2300 +#define YSIZE01 2301 +#define YSIZE99 2299 + +#define XSIZE 40 +#define XSIZE00 4000 +#define XSIZE01 4001 +#define XSIZE99 3999 +#define XSIZE02 4002 +#define XSIZE98 3998 +#define XSIZE03 4003 +#define XSIZE97 3997 +#define XSIZE08 4008 +#define XSIZE92 3992 + +EXT char amb[YSIZE][XSIZE]; + +#ifndef isalnum +# define isalnum(c) (isalpha(c) || isdigit(c)) +#endif + +#include +#include +#include + +#ifdef TERMIO +# include +#else +# include +#endif + +#define BITSPERBYTE 8 +#define LBUFLEN 512 /* line buffer length */ + +#define CBUFLEN 256 /* command buffer length */ +#define PUSHSIZE 128 +#define MAXFILENAME 128 +#define FINISHCMD 0177 + +/* some handy defs */ + +#define bool char +#define TRUE (1) +#define FALSE (0) +#define Null(t) ((t)0) +#define Nullch Null(char *) +#define Nullfp Null(FILE *) + +#define Ctl(ch) (ch & 037) + +#define strNE(s1,s2) (strcmp(s1,s2)) +#define strEQ(s1,s2) (!strcmp(s1,s2)) +#define strnNE(s1,s2,l) (strncmp(s1,s2,l)) +#define strnEQ(s1,s2,l) (!strncmp(s1,s2,l)) + +#define sgn(x) ((x) < 0 ? -1 : (x) > 0) + +/* Things we can figure out ourselves */ + +#ifdef SIGPROF +# define BSD42 /* do we have Berkeley 4.2? */ +#endif + +#ifdef FIONREAD +# define PENDING +#else +# ifdef O_NDELAY +# define PENDING +# endif +#endif + +#ifdef EUNICE +# define UNLINK(victim) while (!unlink(victim)) +#else +# define UNLINK(victim) unlink(victim) +#endif + +/* Valid substitutions for strings marked with % comment are: + * %H Host name (yours) + * %L Login name (yours) + * %N Full name (yours) + * %O Original working directory (where you ran warp from) + * %X Warp library directory + * %~ Home directory + * %. Directory containing . files + * %$ current process number + * %{name} Environment variable "name". %{name-default} form allowed. + * %"prompt" + * Print prompt and insert what is typed. + * %`command` + * Insert output of command. + * %(test_text=pattern?if_text:else_text) + * Substitute if_text if test_text matches pattern, otherwise + * substitute else_text. Use != for negated match. + * % substitutions are done on test_text, if_text, and else_text. + * (Note: %() only works if CONDSUB defined.) + */ + +/* *** System Dependent Stuff *** */ + +/* NOTE: many of these are defined in the config.h file */ + +#ifndef LOGDIRFIELD +# define LOGDIRFIELD 6 /* Which field (origin 1) is the */ + /* login directory in /etc/passwd? */ + /* (If it is not kept in passwd, */ + /* but getpwnam() returns it, */ + /* define the symbol GETPWENT) */ +#endif +#ifndef GCOSFIELD +# define GCOSFIELD 5 +#endif + +/* Undefine any of the following features to save both I and D space */ +/* In general, earlier ones are easier to get along without */ +/* Pdp11's without split I and D may have to undefine them all */ +#define DEBUGGING /* include debugging code */ +#define PUSHBACK /* macros and keymaps using pushback buffer */ +#define CONDSUB /* allow %(cond?text:text) */ +#define BACKTICK /* allow %`command` */ +#define PROMPTTTY /* allow %"prompt" */ +#define GETLOGIN /* use getlogin() routine as backup to environment */ + /* variables USER or LOGNAME */ +#define TILDENAME /* allow ~logname expansion */ +#define SETUIDGID /* substitute eaccess() for access() so that rn */ + /* can run setuid or setgid */ + /* if not setuid or setgid, you don't need it */ +#define VERBOSE /* compile in more informative messages */ +#define TERSE /* compile in shorter messages */ + +/* some dependencies among options */ + +#ifndef SETUIDGID +# define eaccess access +#endif + +#ifdef VERBOSE +# ifdef TERSE +# define IF(c) if (c) +# define ELSE else +# else /* !TERSE */ +# define IF(c) +# define ELSE +# endif +#else /* !VERBOSE */ +# ifndef TERSE +# define TERSE +# endif +# define IF(c) "IF" outside of VERBOSE??? +# define ELSE "ELSE" outside of VERBOSE??? +#endif + +#ifdef DEBUGGING +# define assert(ex) {if (!(ex)){fprintf(stderr,"Assertion failed: file %s, line %d\r\n", __FILE__, __LINE__);sig_catcher(0);}} +#else +# define assert(ex) ; +#endif + +#define TCSIZE 512 /* capacity for termcap strings */ + +/* End of Space Conservation Section */ + +/* More System Dependencies */ +#define sigset signal +#define sigignore(sig) signal(sig,SIG_IGN) + +/* preferred shell for use in doshell routine */ +/* ksh or sh would be okay here */ +#ifndef PREFSHELL +# define PREFSHELL "/bin/csh" +#endif + +/* path to fastest starting shell */ +#ifndef SH +# define SH "/bin/sh" +#endif + +/* location of macro file */ +#ifndef WARPMACRO +# ifdef PUSHBACK +# define WARPMACRO "%./.warpmac" +# endif +#endif + +/* a motd-like file for warp */ +#ifndef WARPNEWSNAME /* % and ~ */ +# define WARPNEWSNAME "%X/warp.news" +#endif + +/* typedefs */ + +typedef unsigned int MEM_SIZE; /* for passing to malloc */ + +/* *** end of the machine dependent stuff *** */ + +/* GLOBAL THINGS */ + +/* file statistics area */ + +EXT struct stat filestat; + +EXT char buf[LBUFLEN+1]; /* general purpose line buffer */ + +EXT char *cwd INIT(Nullch); /* current working directory */ + +/* switches */ + +#ifdef DEBUGGING + EXT int debug INIT(0); /* -D */ +# define DEB_FILEXP 64 +#endif + +#ifdef VERBOSE +# ifdef TERSE + EXT bool verbose INIT(TRUE); /* +t */ +# endif +#endif + +/* miscellania */ + +EXT FILE *tmpfp INIT(Nullfp); /* scratch fp */ + +#define NOMARKING 0 +#define STANDOUT 1 +#define UNDERLINE 2 + +/* Factored strings */ + +EXT char nullstr[] INIT(""); +EXT char readerr[] INIT("warp read error"); +EXT char cantopen[] INIT("Can't open %s\r\n"); + +#ifdef VERBOSE + EXT char nocd[] INIT("Can't chdir to directory %s\r\n"); +#else + EXT char nocd[] INIT("Can't find %s\r\n"); +#endif + +extern int errno; + +EXT bool justonemoretime INIT(TRUE); +EXT bool keepgoing INIT(TRUE); + +EXT bool friendspec INIT(FALSE); +EXT bool piratespec INIT(FALSE); +EXT bool amoebaspec INIT(FALSE); +EXT bool starspec INIT(FALSE); +EXT bool klingspec INIT(FALSE); +EXT bool apolspec INIT(FALSE); +EXT bool crushspec INIT(FALSE); +EXT bool romspec INIT(FALSE); +EXT bool prespec INIT(FALSE); +EXT bool tholspec INIT(FALSE); +EXT bool gornspec INIT(FALSE); +EXT bool beginner INIT(FALSE); +EXT bool massacre INIT(FALSE); +EXT bool lowspeed INIT(FALSE); +EXT bool debugging INIT(FALSE); +EXT bool didkill INIT(FALSE); +EXT bool experimenting INIT(FALSE); +EXT bool scorespec INIT(FALSE); +EXT bool metakey INIT(FALSE); + +EXT bool bombed_out; +EXT bool panic INIT(FALSE); +EXT bool madgorns; + +EXT int madfriends; + +EXT int inumpirates; +EXT int numpirates; +EXT int inumfriends; +EXT int numfriends; +EXT int inumamoebas; +EXT int numamoebas; +EXT int inumstars; +EXT int numstars; +EXT int inumenemies; +EXT int numenemies; +EXT int inumroms; +EXT int inumthols; +EXT int inumapollos; +EXT int numapollos; +EXT int apolloflag; +EXT int inumcrushes; +EXT int numcrushes; +EXT int inumgorns; +EXT int numgorns; +EXT int deados; +EXT int deadmudds; +EXT int smarts; +EXT int ismarts INIT(0); +EXT int numos INIT(0); +EXT int numxes INIT(0); +EXT int ient; +EXT int numents; +EXT int ibase; +EXT int numbases; +EXT int inuminhab; +EXT int numinhab; +EXT int wave; +EXT int cumsmarts; +EXT int prescene INIT(-1); +EXT int scandist; +EXT int antibase; +EXT int sm35; +EXT int sm45; +EXT int sm50; +EXT int sm55; +EXT int sm80; +EXT int sm95; +EXT int entmax; +EXT int basemax; +EXT int enemshields; +EXT int super; +EXT int whenok; +EXT int yamblast; +EXT int xamblast; +EXT int ambsize; + +EXT char spbuf[512]; + +#define Fclose (void)fclose +#define Fflush (void)fflush +#define Sprintf (void)sprintf +#define Signal (void)signal +#define Safecpy (void)safecpy +#define Cpytill (void)cpytill +#define Tract (void)tract +#define Make_object (void)make_object +#define Read_tty (void)read_tty diff --git a/src/games/warp/warp.man b/src/games/warp/warp.man new file mode 100644 index 0000000..a5b0ced --- /dev/null +++ b/src/games/warp/warp.man @@ -0,0 +1,133 @@ +.TH WARP 6 +.SH NAME +warp - a real-time space war game +.SH SYNOPSIS +.B warp [options] +.SH DESCRIPTION +.I Warp +is a real-time space war game that requires skill and quick thinking. +"Real-time" in this context means that the enemies keep moving (and shooting) +even if you don't. +A unique feature of +.I warp +is that blast propagates; it is unhealthy to remain near things that are +in the process of blowing up. +If a given universe is above a critical density it may chain react. +Scoring is like many popular arcade games--there are multiple waves which +get harder and harder as you go along. +Nobody has ever maxed out the scoreboard without cheating. +.PP +Unlike many space-war games, +.I warp +is not simply a shooting gallery. +Along with phasers and photon torpedoes, you have tractor beams and a cloaking +device. +Skill in navigation is important. +It helps to be schizophrenic, because you must manage an Enterprise and a Base +simultaneously. +And enemies do not simply shoot back. +You can get tailed, absorbed, snuck up upon, hemmed in, rammed, loved to death, +reprimanded for destroying civilized life, dragged around, robbed, damaged +and eaten. +And if you should happen to get bored by the enemies (a trifle unlikely), +you can always watch the interesting star patterns. +In fact, you'll have to, since your tactics will depend upon what kind of +universe you find yourself in. +.PP +.I Warp +is played in a double wraparound universe, i.e. the bottom is connected to the +top, and the right is connected to the left. +You need a crt with random cursor addressing and at least 24 lines by 80 +columns. +For more information about about how to play, simply run +.I warp +and say "y" when it asks if you want to see the instructions. +There is also a single-page command summary that you can get while playing +by typing a "?". +.PP +Command line options include: +.TP 5 +.B -b +Put +.I warp +into beginner mode. +Makes the difficulty increase more slowly, but penalizes you for it. +.TP 5 +.B -d +Sets the initial difficulty to +.BR n . +.TP 5 +.B -l +Play a low-speed game. +Changes the basic cycle time from 1 second to 2 seconds. +This switch is automatically set at baud rates below 2400. +You may want to set it at higher speeds if your terminal cannot keep up +with the output. +(This should never happen on BSD systems, which have an IOCTL call to +determine output queue length.) +Because this makes the game easier, a separate scoreboard is kept for +low-speed games. +.TP 5 +.B -m +Terminal has a meta key which turns on the eighth bit. Ordinarily the +eighth bit is stripped in order to ignore parity. +Metacharacters will appear to the keymap as prefixed with a ^A, and will +subsequently have the same effect as a control character, unless otherwise +mapped. +.TP 5 +.B -s +Just prints out the scoreboards and saved games and then exits. +.TP 5 +.B -v +Prints out the version number. +.TP 5 +.B -x +Play an experimental game. +This causes +.I warp +to ignore any saved game, and disables the ability to save +the current game. +Thus you can play around with something or show +.I warp +to someone without jeopardizing a currently saved game. +.SH ENVIRONMENT +.TP 5 +.B WARPMACRO +If defined, names a file containing keyboard mappings and macros. +If not defined, the value %X/Kbmap.%{TERM} is assumed. +The macro file contains lines of the following form: +.sp + +.sp +You may use certain % interpolations and ^ control characters. +For possible % interpolations see warp.h. +Sequences in the canonical-keystroke-sequence bounded by ^(...^) are +subject to reinterpretation via the keymap. +This file has two major uses. +First, you can set up your commands to use any kind of prefix key your terminal +might have, or change the key bindings in any other way you choose. +Second, you can define arbitrary macros, such as this: +.sp +# define Corbamite maneuver += DDllllll +.SH AUTHOR +Larry Wall +.SH FILES +~/.fullname, if full names aren't in /etc/passwd +.SH DIAGNOSTICS +Generally self-documenting, as they say. +.SH BUGS +Addicting. +At the end of a wave, all you have to do to keep going is hit a space. +You see the message "Hit space to continue" and automatically hit space. +About 2 seconds later you remember you wanted to go home, but by then +it's too late to escape without penalty. +.PP +You can't kill a backgrounded +.I warp +process directly, because it is running setuid. +You have to use the killer built in to +.IR warp . +.PP +Now that there is a space amoeba, there ought to be tribbles. +But it might be too much trouble... diff --git a/src/games/warp/warp.news b/src/games/warp/warp.news new file mode 100644 index 0000000..eef59cd --- /dev/null +++ b/src/games/warp/warp.news @@ -0,0 +1,4 @@ + *** WARP NEWS *** + +Welcome to warp! Please send any gripes, comments, fantastic ideas, etc. +to lwall@sdcrdcf.uucp (Larry Wall). diff --git a/src/games/warp/weapon.c b/src/games/warp/weapon.c new file mode 100644 index 0000000..5be9c91 --- /dev/null +++ b/src/games/warp/weapon.c @@ -0,0 +1,688 @@ +/* $Header: weapon.c,v 7.0.1.2 86/10/20 14:36:33 lwall Exp $ */ + +/* $Log: weapon.c,v $ + * Revision 7.0.1.2 86/10/20 14:36:33 lwall + * Picked some lint. + * + * Revision 7.0.1.1 86/10/16 10:54:42 lwall + * Added Damage. Fixed random bugs. + * + * Revision 7.0 86/10/08 15:18:08 lwall + * Split into separate files. Added amoebas and pirates. + * + */ + +#include "EXTERN.h" +#include "warp.h" +#include "bang.h" +#include "object.h" +#include "move.h" +#include "score.h" +#include "sig.h" +#include "term.h" +#include "them.h" +#include "us.h" +#include "util.h" +#include "INTERN.h" +#include "weapon.h" + +void +weapon_init() +{ + ; +} + +void +fire_torp(from, ydir, xdir) +register OBJECT *from; +register int ydir; +register int xdir; +{ + register OBJECT *to; + + if (from->type == Enemy || + (from == ent && etorp > 0) || + (from == base && btorp > 0)) { + to = occupant[(from->posy+from->vely+ydir+YSIZE00)%YSIZE] + [(from->posx+from->velx+xdir+XSIZE00)%XSIZE]; + if (from->type != Enemy || !to || to->vely || to->velx) { + if (from->type != Enemy && + (to = isatorp[from==base][ydir+1][xdir+1])) { + to->vely += ydir; + to->velx += xdir; + } + else { + if (from == ent) { + to = make_object(Torp, '+', from->posy,from->posx, + from->vely+ydir,from->velx+xdir, 0L, 1L,&root); + aretorps++; + isatorp[0][ydir+1][xdir+1] = to; + etorp--; + } + else if (from == base) { + to = make_object(Torp, '+', from->posy,from->posx, + from->vely+ydir,from->velx+xdir, 0L, 1L,&root); + aretorps++; + isatorp[1][ydir+1][xdir+1] = to; + btorp--; + } + else if (from->image == 'G') { + numos++; + to = make_object(Torp, 'o', from->posy,from->posx, + from->vely+ydir,from->velx+xdir, 100L, 1L,&root); + if (madgorns) { + possiblescore += 35; + to->image = '0'; + to->mass = 2000; + to->energy = 2000; + } + else if (rand_mod(120)+10 > smarts) + possiblescore += 100; + else { + possiblescore += 200; + to->image = 'O'; + } + } + else { + to = make_object(Torp, 'x', from->posy,from->posx, + from->vely+ydir,from->velx+xdir, 0L, 1L,&root); + if (rand_mod(160)+10 > smarts) + possiblescore += 10; + else { + possiblescore += 100; + to->image = 'X'; + to->mass = 1000+super*20; + numxes++; + } + } + } + } + } +} + +void +attack(attackee) +register OBJECT *attackee; +{ + register int dx; + register int dy; + register int curx; + register int cury; + register int prob; + register OBJECT *obj; + register bool torps; + register bool webnear = FALSE; + register bool thru_stars; + int nukey; + int nukex; + int nukedist; + + if (attackee) { + if (attackee == nuke) { + if (amb[attackee->posy][attackee->posx] != '~') + return; + nukey = nukex = 0; + nukedist = 100; + } + for (dx= -1; dx<=1 ; dx++) { + for (dy= -1; dy<=1; dy++) { + if (dx||dy) { + cury = attackee->posy; + curx = attackee->posx; + torps = thru_stars = FALSE; + if (massacre || madgorns || !rand_mod(53-super) ) + webnear += rand_mod(2); + else + webnear = FALSE; + for (prob = scandist;prob;prob--) { + cury = (cury + dy + YSIZE00) % YSIZE; + curx = (curx + dx + XSIZE00) % XSIZE; + if (obj = occupant[cury][curx]) { + switch (obj->image) { + case 'P': case 'K': case 'R': case ' ': + pot_shot: + if (attackee == nuke) { + if (rand_mod(2+scandist-prob) < + rand_mod(smarts/40+1)) + Tract(nuke,dy,dx,rand_mod(3)?1:-1); + } + if (rand_mod(51 - sm50) <= prob) { + switch (obj->strategy||thru_stars?0: + rand_mod(ent?4:2)) { + case 1: case 2: + if (-dy + attackee->vely == obj->vely + && -dx + attackee->velx == obj->velx) + fire_torp(obj, + -dy + attackee->vely, + -dx + attackee->velx); + else + fire_torp(obj, + -dy + attackee->vely - obj->vely, + -dx + attackee->velx - obj->velx); + if (obj->image == ' ') + setimage(obj, + obj->flags & PIRATE ? 'P' : 'R'); + break; + case 3: { + int newspeed = + rand_mod(prob<5&&smarts>70?4:3)-1; + + obj->vely = -dy * newspeed; + obj->velx = -dx * newspeed; + if (newspeed >= 0 && + !rand_mod(82-sm80)) { + obj->vely += attackee->vely; + obj->velx += attackee->velx; + } + break; + } + case 0: + if (!torps && obj->energy > 1000) { + fire_phaser(obj, -dy, -dx); + if (smarts > 40 && + (scandist-prob > 5 + || attackee==base) && + (massacre || obj->strategy || + rand_mod(2))) + while (rand_mod(2)) + fire_phaser(obj, -dy, -dx); + if (obj->image == ' ') + setimage(obj, + obj->flags&PIRATE ? 'P':'R'); + } + if (obj->strategy) { + obj->velx = obj->vely = 0; + if (obj->energy < 1000 || + bvely || bvelx) + obj->strategy = 0; + } + else if ((attackee==base || + (cloaking && attackee==ent) + ) && + scandist-prob > 5 && + !(rand_mod( + ent?antibase*2:antibase)) ) + obj->strategy = 1; + break; + } + } + goto bombout; + case 'G': + if (thru_stars && obj->strategy < 7) + goto bombout; + if (attackee == nuke) { + if (rand_mod(2+scandist-prob) < + rand_mod(smarts/40+1)) + Tract(nuke,dy,dx,rand_mod(3)?1:-1); + goto bombout; + } + if (obj->strategy) { + if (madgorns || !rand_mod(4)) { + obj->vely = attackee->vely; + obj->velx = attackee->velx; + } + obj->strategy += (!torps && deados > 10); + if (obj->strategy > 4) + madgorns = TRUE; + if (!torps && obj->strategy > 5) { + do { + fire_phaser(obj, -dy, -dx); + } while (rand_mod(2)); + } + } + else if (numgorns >= numenemies-1 && + deados > 15+numgorns*5) + obj->strategy = 1; + if (madgorns || rand_mod(51 - sm50) <= prob) { + if (-dy + attackee->vely == obj->vely + && -dx + attackee->velx == obj->velx) + fire_torp(obj, + -dy + attackee->vely, + -dx + attackee->velx); + else + fire_torp(obj, + -dy + attackee->vely - obj->vely, + -dx + attackee->velx - obj->velx); + } + goto bombout; + case 'T': + if (attackee == nuke) { + if (rand_mod(2+scandist-prob) < + rand_mod(smarts/40+1)) + Tract(nuke,dy,dx,rand_mod(3)?1:-1); + } + if (thru_stars) + goto bombout; + if (webnear && scandist-prob > 5) { + if (massacre || rand_mod(50) < super) { + if (!torps && obj->energy > 1000) { + fire_phaser(obj, -dy, -dx); + while (!rand_mod(57-sm55)) + fire_phaser(obj, -dy, -dx); + } + } + } + goto bombout; + case 'C': case 'c': + if (thru_stars) + goto bombout; + break; + case 'Q': case 'W': case 'Y': case 'U': + case 'I': case 'S': case 'D': case 'H': case 'J': + case 'L': case 'Z': case 'V': case 'M': case 'F': + if (attackee == nuke) { + if (rand_mod(2+scandist-prob) < + rand_mod(smarts/40+1)) + Tract(nuke,dy,dx,rand_mod(3)?1:-1); + if (rand_mod(2)) + goto pot_shot; + } + if (madfriends > 1000) { + madfriends -= 200; + goto pot_shot; + } + /* FALL THROUGH */ + case '+': + if (attackee == nuke) { + if (smarts > 70) { + if ( + (obj->posx + obj->velx + XSIZE00)%XSIZE + == attackee->posx && + (obj->posy + obj->vely + YSIZE00)%YSIZE + == attackee->posy ) { + Tract(nuke,dy,dx,-1); + } + else + while (!rand_mod(82-sm80)) + Tract(nuke,dy,dx,-1); + } + else if (smarts > 60 || + rand_mod(2+scandist-prob) < + rand_mod(smarts/20+1)) + Tract(nuke,dy,dx,rand_mod(3)?1:-1); + } + torps = FALSE; + thru_stars = FALSE; + break; + case '|': case '-': case '/': case '\\': + if (thru_stars) + goto bombout; + webnear = (scandist-prob < 3); + torps = FALSE; + break; + case 'x': + if (attackee == nuke) { + if (rand_mod(2+scandist-prob) < + rand_mod(smarts/20+1)) + Tract(nuke,dy,dx,rand_mod(3)?1:-1); + } + if (thru_stars) + goto bombout; + torps = TRUE; + break; + case 'o': case 'O': case '0': + if (attackee == nuke) { + if (rand_mod(2+scandist-prob) < + rand_mod(smarts/20+1)) + Tract(nuke,dy,dx,rand_mod(3)?1:-1); + } + if (thru_stars) + goto bombout; + torps = TRUE; + if (rand_mod(99+3*scandist) < smarts+3*prob) { + obj->vely = -dy + attackee->vely; + obj->velx = -dx + attackee->velx; + if (obj->flags & STATIC) {/* not a mover? */ + obj->flags &= ~STATIC; + obj->prev->next = obj->next; + obj->next->prev = obj->prev; + root.prev->next = obj; + obj->prev = root.prev; + root.prev = obj; + obj->next = &root; + } + } + if (obj->image != '0') + break; + /* DROP THROUGH! */ + case 'X': + if (attackee == nuke) { + if (rand_mod(2+scandist-prob) < + rand_mod(smarts/20+1)) + Tract(nuke,dy,dx,rand_mod(3)?1:-1); + } + torps = TRUE; + if (thru_stars) + goto bombout; + if (prob == scandist) { + int y, x; + + blast[y=(obj->posy+obj->vely+YSIZE00)%YSIZE] + [x=(obj->posx+obj->velx+XSIZE00)%XSIZE] + += (obj->image == '0' ? 2000 : 200); + yblasted[y] |= 1; + xblasted[x] |= 1; + blasted = TRUE; + } + break; + case 'A': + if (attackee != nuke) { + if (scandist-prob>1 && !rand_mod(51-super)) + Tract(obj,-dy,-dx,1); + } + /* FALL THROUGH */ + case '*': case '@': + if (attackee == nuke) { + if (amb[cury][curx] != '~') { + if (scandist-prob < nukedist) { + nukedist = scandist-prob; + nukey = dy; /* nearest food in */ + nukex = dx; /* this direction */ + } + if (smarts > 55 && scandist-prob > 8) { + if (rand_mod(30+scandist-prob) < + rand_mod(smarts/20+1)) + Tract(nuke,dy,dx,1); + } + } + else if (obj->vely || obj->velx) { + Tract(nuke,dy,dx,1); /* for looks */ + obj->vely = obj->velx = 0; + } + } + if (!thru_stars) + if (rand_mod(97-sm95)) + goto bombout; + else + thru_stars = TRUE; + break; + case '<': case '>': + if (attackee == nuke) { + if ((!dy && scandist-prob < 8) || + rand_mod(2+scandist-prob) < + rand_mod(smarts/20+1) ) { + nuke->mass += 10000; + Tract(nuke,dy,dx,-1); + nuke->mass -= 10000; + } + } + goto bombout; + case 'E': case 'B': + if (attackee == nuke) { + if (rand_mod(2+scandist-prob) < + rand_mod(smarts/40+1)) + Tract(nuke,dy,dx,rand_mod(3)?1:-1); + } + goto bombout; + default: + goto bombout; + } + } + else { + if (thru_stars) + goto bombout; + } + } +bombout: ; /* end of loop */ + } + } + } + if (attackee == nuke && nukedist < 100) {/* aim amoeba at nearest */ + if (nukey < 0) /* free star */ + nukey = 2; + if (nukex < 0) + nukex = 2; + nuke->strategy = nukey + (nukex << 2); + } + } +} + +void +fire_phaser(obj, dy, dx) +register OBJECT *obj; +register int dy; +register int dx; +{ + register int y; + register int x; + register int skipping; + register int size=5000; + int decr = 50, oldy, oldx; + static char curchar[] = "@* "; + + if (obj == ent) + decr = 100; + else if (obj == base) { + decr = 1000; + size = 200; + } + if (!dy) + curchar[2] = '-'; + else if (!dx) + curchar[2] = '!'; + else if (dy == dx) + curchar[2] = '\\'; + else + curchar[2] = '/'; + if (obj->energy >= decr) { + obj->energy -= decr; + for ( + /* initialize */ + skipping = (obj != base), + y = (obj->posy+(obj==base?dy*2:dy)+YSIZE00)%YSIZE, + x = (obj->posx+(obj==base?dx*2:dx)+XSIZE00)%XSIZE; + /* while */ + size && (!occupant[y][x]||(skipping && occupant[y][x]->type==Star)); + /* at end of loop */ + y = (y+dy+YSIZE00) % YSIZE, + x = (x+dx+XSIZE00) % XSIZE, + size = size * 3 / 4 ) { + move(y+1,x*2,0); + beg_qwrite(); + if (obj == base || obj->image == 'T') { + *filler = '@'; + qwrite(); + *filler = '#'; + qwrite(); + *filler = '~'; + qwrite(); + *filler = '%'; + qwrite(); + *filler = ':'; + qwrite(); + *filler = '@'; + } + else { + *filler = size >= 500 ? + *curchar : (size >= 50 ? + curchar[1] : + curchar[2]); + } + qwrite(); + if (occupant[y][x]) + qaddc(occupant[y][x]->image); + else { + if (numamoebas) + qaddc(amb[y][x]); + else + qaddspace(); + if (skipping) + skipping = 0; + } + end_qwrite(); + } + if (size) { + char img; + + assert(occupant[y][x]); + img = occupant[y][x]->image; + if (occupant[y][x]->type == Crusher) { + if (dy) + return; + if (dx==(img == '<' ? 1 : -1) ) { + occupant[y][x]->image = + (occupant[y][x]->velx *= -1) < 0 ? '>' : '<'; + return; + } + } + else if (occupant[y][x]->flags & FRIENDLY) + madfriends += 200; + if (numamoebas && amb[y][x] == '~' && smarts % 3 && + (smarts > 70 || rand_mod(smarts) > rand_mod(20)) ) { + if (size > 10000) + modify_amoeba(y,x,1,'~',10); + else if (size > 1000) + modify_amoeba(y,x,1,'~',7); + else if (size > 50) + modify_amoeba(y,x,1,'~',5); + else + modify_amoeba(y,x,1,'~',2); + if (occupant[y][x] == nuke) { + nuke->strategy = rand_mod(30); + nuke->flags |= COUNTDOWN; + } + return; + } + else { + move(y+1,x*2,0); + beg_qwrite(); + if (img == ' ') { + *filler = occupant[y][x]->flags & PIRATE ? 'P' : 'R'; + occupant[y][x]->image = *filler; + occupant[y][x]->strategy = 0; + qwrite(); + qwrite(); + } + else if (img == 'C' || img == 'c') { + cloaked = 0; + img += 2; + occupant[y][x]->image = img; + *filler = img; + qwrite(); + qwrite(); + } + else if (img == 'K' && size > 50) + occupant[y][x]->strategy = 0; + *filler = '@'; + qwrite(); + *filler = '#'; + qwrite(); + *filler = '@'; + qwrite(); + *filler = '#'; + qwrite(); + *filler = '@'; + qwrite(); + qaddc(img); + end_qwrite(); + oldy = y; + oldx = x; + y = (occupant[oldy][oldx]->posy + occupant[oldy][oldx]->vely + + YSIZE00) % YSIZE; + x = (occupant[oldy][oldx]->posx + occupant[oldy][oldx]->velx + + XSIZE00) % XSIZE; + if (occupant[y][x] && occupant[y][x]->type == Star) { + y = occupant[oldy][oldx]->posy; + x = occupant[oldy][oldx]->posx; + } + if (obj==base) + blast[y][x] += size>50 ? 15000 : (size>15 ? 1500 : 150); + else if (obj==ent) + blast[y][x] += size*4; + else if (obj->image=='T') + blast[y][x] += 15000; + else + blast[y][x] += size*smarts/25; + yblasted[y] |= 1; + xblasted[x] |= 1; + blasted = TRUE; + } + } + } +} + +int +tract(obj, dy, dx, to_or_fro) +register OBJECT *obj; +register int dy; +register int dx; +int to_or_fro; +{ + register int y; + register int x; + register int size=10; + static char ch; + register OBJECT *tractee; + + if (!dy) + ch = '|'; + else if (!dx) + ch = '-'; + else if (dy == dx) + ch = '/'; + else + ch = '\\'; + { + for ( + y = (obj->posy+dy+YSIZE00)%YSIZE, + x = (obj->posx+dx+XSIZE00)%XSIZE; + size && (!occupant[y][x]); + y = (y+dy+YSIZE00) % YSIZE, x = (x+dx+XSIZE00) % XSIZE, size--) { + move(y+1,x*2,0); + beg_qwrite(); + *filler = ch; + qwrite(); + qwrite(); + if (numamoebas) + qaddch(amb[y][x]); + else + qaddspace(); + end_qwrite(); + } + tractee = occupant[y][x]; + if (size) { + assert(tractee); + if (numamoebas && obj != nuke && amb[y][x] == '~') { + if (to_or_fro > 0) + modify_amoeba(y,x,2,'~',size); + else + modify_amoeba(y,x,1,' ',size); + } + if (tractee->type != Web && + (tractee->mass < obj->mass * 5 || + (tractee->type == Crusher && !dx) ) ) { + if (tractee == ent) { + evely -= dy * to_or_fro; + evelx -= dx * to_or_fro; + } + else if (tractee == base) { + bvely -= dy * to_or_fro; + bvelx -= dx * to_or_fro; + } + else { + tractee->vely -= dy * to_or_fro; + tractee->velx -= dx * to_or_fro; + } + if (tractee->type == Torp || + tractee->type == Star) { + if (tractee->flags & STATIC) { /* not a mover? */ + tractee->flags &= ~STATIC; + tractee->prev->next = tractee->next; + tractee->next->prev = tractee->prev; + root.prev->next = tractee; + tractee->prev = root.prev; + root.prev = tractee; + tractee->next = &root; + } + } + } + else if (tractee->type == Crusher && !dy && + dx==(tractee->image == '<' ? 1 : -1) ) { + setimage(tractee, (tractee->velx *= -1) < 0 ? '>' : '<'); + } + if (tractee->mass * 5 > obj->mass) + return(1); + } + } + return(0); +} diff --git a/src/games/warp/weapon.h b/src/games/warp/weapon.h new file mode 100644 index 0000000..a25c139 --- /dev/null +++ b/src/games/warp/weapon.h @@ -0,0 +1,22 @@ +/* $Header: weapon.h,v 7.0 86/10/08 15:18:20 lwall Exp $ */ + +/* $Log: weapon.h,v $ + * Revision 7.0 86/10/08 15:18:20 lwall + * Split into separate files. Added amoebas and pirates. + * + */ + +EXT int tractor INIT(0); + +EXT int etorp; +EXT int btorp; + +EXT OBJECT *isatorp[2][3][3]; + +EXT int aretorps; + +void fire_torp(); +void attack(); +void fire_phaser(); +int tract(); +void weapon_init(); diff --git a/src/games/worm.6 b/src/games/worm.6 new file mode 100644 index 0000000..4f63893 --- /dev/null +++ b/src/games/worm.6 @@ -0,0 +1,39 @@ +.\" Copyright (c) 1980 Regents of the University of California. +.\" All rights reserved. The Berkeley software License Agreement +.\" specifies the terms and conditions for redistribution. +.\" +.\" @(#)worm.6 6.1 (Berkeley) 5/20/85 +.\" +.TH WORM 6 "May 20, 1985" +.UC 4 +.SH NAME +worm \- Play the growing worm game +.SH SYNOPSIS +.B /usr/games/worm +[ +.I size +] +.SH DESCRIPTION +.PP +In +.I worm, +you are a little worm, your body is the "o"'s on the screen +and your head is the "@". You move with the hjkl keys (as in the game +snake). If you don't press any keys, you continue in the direction you +last moved. The upper case HJKL keys move you as if you had pressed +several (9 for HL and 5 for JK) of the corresponding lower case key +(unless you run into a digit, then it stops). +.PP +On the screen you will see a digit, if your worm eats the digit is will +grow longer, the actual amount longer depends on which digit it was +that you ate. The object of the game is to see how long you can make +the worm grow. +.PP +The game ends when the worm runs into either the sides of the screen, +or itself. The current score (how much the worm has grown) is kept in +the upper left corner of the screen. +.PP +The optional argument, if present, is the initial length of the worm. +.SH BUGS +If the initial length of the worm is set to less than one or more +than 75, various strange things happen. diff --git a/src/games/worm.c b/src/games/worm.c new file mode 100644 index 0000000..a188b44 --- /dev/null +++ b/src/games/worm.c @@ -0,0 +1,257 @@ +/* + * Worm. Written by Michael Toy + * UCSC + * + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#ifdef CROSS +# define FILE int /* quick hack for macosx */ +# include +# include +# undef FILE +#else +# include +# include +#endif +#include +#include +#include + +#define newlink() (struct body *) malloc(sizeof (struct body)); +#define HEAD '@' +#define BODY 'o' +#define LENGTH 7 +#define RUNLEN 8 +#define CNTRL(p) (p & 037) + +WINDOW *tv; +WINDOW *stw; + +struct body { + int x; + int y; + struct body *prev; + struct body *next; +} *head, *tail, goody; + +int growing = 0; +int running = 0; +int score = 0; +int start_len = LENGTH; +char lastch; + +extern int printf(const char *, ...); + +void display(pos, chr) + struct body *pos; + char chr; +{ + wmove(tv, pos->y, pos->x); + waddch(tv, chr); +} + +void life() +{ + register struct body *bp, *np = 0; + register int i; + + head = newlink(); + head->x = start_len+2; + head->y = 12; + head->next = NULL; + display(head, HEAD); + for (i = 0, bp = head; i < start_len; i++, bp = np) { + np = newlink(); + np->next = bp; + bp->prev = np; + np->x = bp->x - 1; + np->y = bp->y; + display(np, BODY); + } + tail = np; + tail->prev = NULL; +} + +void leave() +{ + endwin(); + exit(0); +} + +void setup() +{ + clear(); + refresh(); + touchwin(stw); + wrefresh(stw); + touchwin(tv); + wrefresh(tv); + alarm(1); +} + +void suspend() +{ + move(LINES-1, 0); + refresh(); + endwin(); +#ifdef SIGTSTP + kill(getpid(), SIGTSTP); + signal(SIGTSTP, suspend); +#else + { + char *sh = getenv("SHELL"); + if (sh == NULL) + sh = "/bin/sh"; + system(sh); + } +#endif + crmode(); + noecho(); + setup(); +} + +void crash() +{ + sleep(1); + clear(); + move(23, 0); + refresh(); + printf("Well you ran into something and the game is over.\r\n"); + printf("Your final score was %d\r\n", score); + leave(); +} + +int rnd(range) +{ + return abs((rand()>>5)+(rand()>>5)) % range; +} + +void newpos(bp) + struct body * bp; +{ + do { + bp->y = rnd(LINES-3)+ 2; + bp->x = rnd(COLS-3) + 1; + wmove(tv, bp->y, bp->x); + } while (winch(tv) != ' '); +} + +void prize() +{ + int value; + + value = rnd(9) + 1; + newpos(&goody); + waddch(tv, value+'0'); + wrefresh(tv); +} + +void process(ch) + char ch; +{ + register int x,y; + struct body *nh; + + alarm(0); + x = head->x; + y = head->y; + switch (ch) { + case 'h': x--; break; + case 'j': y++; break; + case 'k': y--; break; + case 'l': x++; break; + case 'H': x--; running = RUNLEN; ch = tolower(ch); break; + case 'J': y++; running = RUNLEN/2; ch = tolower(ch); break; + case 'K': y--; running = RUNLEN/2; ch = tolower(ch); break; + case 'L': x++; running = RUNLEN; ch = tolower(ch); break; + case '\f': setup(); return; + case CNTRL('Z'): suspend(); return; + case CNTRL('C'): crash(); return; + case CNTRL('D'): crash(); return; + default: if (! running) alarm(1); return; + } + lastch = ch; + if (growing == 0) { + display(tail, ' '); + tail->next->prev = NULL; + nh = tail->next; + free(tail); + tail = nh; + } else + growing--; + display(head, BODY); + wmove(tv, y, x); + if (isdigit(ch = winch(tv))) { + growing += ch-'0'; + prize(); + score += growing; + running = 0; + wmove(stw, 0, 68); + wprintw(stw, "Score: %3d", score); + wrefresh(stw); + } else if (ch != ' ') + crash(); + nh = newlink(); + nh->next = NULL; + nh->prev = head; + head->next = nh; + nh->y = y; + nh->x = x; + display(nh, HEAD); + head = nh; + if (! running) + wrefresh(tv); + if (! running) + alarm(1); +} + +void wake() +{ + signal(SIGALRM, wake); + process(lastch); +} + +int main(argc, argv) + char **argv; +{ + char ch; + + if (argc == 2) + start_len = atoi(argv[1]); + if ((start_len <= 0) || (start_len > 500)) + start_len = LENGTH; + srand(getpid()); + signal(SIGALRM, wake); + signal(SIGINT, leave); + signal(SIGQUIT, leave); +#ifdef SIGTSTP + signal(SIGTSTP, suspend); /* process control signal */ +#endif + initscr(); + crmode(); + noecho(); + clear(); + stw = newwin(1, COLS-1, 0, 0); + tv = newwin(LINES-1, COLS-1, 1, 0); + box(tv, '*', '*'); + scrollok(tv, FALSE); + scrollok(stw, FALSE); + wmove(stw, 0, 0); + wprintw(stw, " Worm"); + refresh(); + wrefresh(stw); + wrefresh(tv); + life(); /* Create the worm */ + prize(); /* Put up a goal */ + while (1) { + if (running) { + running--; + process(lastch); + } else { + if (read(0, &ch, 1) >= 0) + process(ch); + } + } +} diff --git a/src/games/worms.6 b/src/games/worms.6 new file mode 100644 index 0000000..259c71d --- /dev/null +++ b/src/games/worms.6 @@ -0,0 +1,48 @@ +.\" Copyright (c) 1980 Regents of the University of California. +.\" All rights reserved. The Berkeley software License Agreement +.\" specifies the terms and conditions for redistribution. +.\" +.\" @(#)worms.6 6.1 (Berkeley) 5/20/85 +.\" +.TH WORMS 6 "May 20, 1985" +.UC 4 +.SH NAME +worms \- animate worms on a display terminal +.SH SYNOPSIS +.B /usr/games/worms +[ +.B \-field +] [ +.B \-length +# ] [ +.B \-number +# ] [ +.B \-trail +] +.SH DESCRIPTION +.ad b +Brian Horn (cithep!bdh) showed me a +.I TOPS-20 +program on the DEC-2136 machine called +.IR WORM , +and suggested that I write a similar program that would run under +.IR Unix . +I did, and no apologies. +.PP +.B \-field +makes a "field" for the worm(s) to eat; +.B \-trail +causes each worm to leave a trail behind it. You can figure +out the rest by yourself. +.SH FILES +/etc/termcap +.SH AUTHOR +Eric P. Scott +.SH SEE ALSO +.IR Snails , +by Karl Heuer +.SH BUGS +The lower-right-hand character position will not be updated properly +on a terminal that wraps at the right margin. +.PP +Terminal initialization is not performed. diff --git a/src/games/worms.c b/src/games/worms.c new file mode 100644 index 0000000..eb3b2b0 --- /dev/null +++ b/src/games/worms.c @@ -0,0 +1,354 @@ +/* + * @@@ @@@ @@@@@@@@@@ @@@@@@@@@@@ @@@@@@@@@@@@ + * @@@ @@@ @@@@@@@@@@@@ @@@@@@@@@@@@ @@@@@@@@@@@@@ + * @@@ @@@ @@@@ @@@@ @@@@ @@@@ @@@ @@@@ + * @@@ @@ @@@ @@@ @@@ @@@ @@@ @@@ @@@ + * @@@ @@@@ @@@ @@@ @@@ @@@ @@@ @@@ @@@ + * @@@@ @@@@ @@@@ @@@ @@@ @@@ @@@ @@@ @@@ + * @@@@@@@@@@@@ @@@@ @@@@ @@@ @@@ @@@ @@@ + * @@@@ @@@@ @@@@@@@@@@@@ @@@ @@@ @@@ @@@ + * @@ @@ @@@@@@@@@@ @@@ @@@ @@@ @@@ + * + * Eric P. Scott + * Caltech High Energy Physics + * October, 1980 + */ +#define BSD + +#ifdef CROSS +# include +# include +#else +# include +# include +#endif +#include +#include +#include +#include + +#define cursor(col,row) tputs(tgoto(CM,col,row),1,fputchar) + +extern char *UP; +extern short ospeed; + +int Wrap; +short *ref[24]; + +static char flavor[] = { + 'O', '*', '#', '$', '%', '0' +}; + +static short xinc[] = { + 1, 1, 1, 0, -1, -1, -1, 0 +}; + +static short yinc[] = { + -1, 0, 1, 1, 1, 0, -1, -1 +}; + +static struct worm { + int orientation, head; + short *xpos, *ypos; +} worm[40]; + +static char *field; +static int length = 16, number = 3, trail = ' '; + +static struct options { + int nopts; + int opts[3]; +} normal[8]={ + { 3, { 7, 0, 1 } }, + { 3, { 0, 1, 2 } }, + { 3, { 1, 2, 3 } }, + { 3, { 2, 3, 4 } }, + { 3, { 3, 4, 5 } }, + { 3, { 4, 5, 6 } }, + { 3, { 5, 6, 7 } }, + { 3, { 6, 7, 0 } } +}, upper[8]={ + { 1, { 1, 0, 0 } }, + { 2, { 1, 2, 0 } }, + { 0, { 0, 0, 0 } }, + { 0, { 0, 0, 0 } }, + { 0, { 0, 0, 0 } }, + { 2, { 4, 5, 0 } }, + { 1, { 5, 0, 0 } }, + { 2, { 1, 5, 0 } } +}, left[8]={ + { 0, { 0, 0, 0 } }, + { 0, { 0, 0, 0 } }, + { 0, { 0, 0, 0 } }, + { 2, { 2, 3, 0 } }, + { 1, { 3, 0, 0 } }, + { 2, { 3, 7, 0 } }, + { 1, { 7, 0, 0 } }, + { 2, { 7, 0, 0 } } +}, right[8]={ + { 1, { 7, 0, 0 } }, + { 2, { 3, 7, 0 } }, + { 1, { 3, 0, 0 } }, + { 2, { 3, 4, 0 } }, + { 0, { 0, 0, 0 } }, + { 0, { 0, 0, 0 } }, + { 0, { 0, 0, 0 } }, + { 2, { 6, 7, 0 } } +}, lower[8]={ + { 0, { 0, 0, 0 } }, + { 2, { 0, 1, 0 } }, + { 1, { 1, 0, 0 } }, + { 2, { 1, 5, 0 } }, + { 1, { 5, 0, 0 } }, + { 2, { 5, 6, 0 } }, + { 0, { 0, 0, 0 } }, + { 0, { 0, 0, 0 } } +}, upleft[8]={ + { 0, { 0, 0, 0 } }, + { 0, { 0, 0, 0 } }, + { 0, { 0, 0, 0 } }, + { 0, { 0, 0, 0 } }, + { 0, { 0, 0, 0 } }, + { 1, { 3, 0, 0 } }, + { 2, { 1, 3, 0 } }, + { 1, { 1, 0, 0 } } +}, upright[8]={ + { 2, { 3, 5, 0 } }, + { 1, { 3, 0, 0 } }, + { 0, { 0, 0, 0 } }, + { 0, { 0, 0, 0 } }, + { 0, { 0, 0, 0 } }, + { 0, { 0, 0, 0 } }, + { 0, { 0, 0, 0 } }, + { 1, { 5, 0, 0 } } +}, lowleft[8]={ + { 3, { 7, 0, 1 } }, + { 0, { 0, 0, 0 } }, + { 0, { 0, 0, 0 } }, + { 1, { 1, 0, 0 } }, + { 2, { 1, 7, 0 } }, + { 1, { 7, 0, 0 } }, + { 0, { 0, 0, 0 } }, + { 0, { 0, 0, 0 } } +}, lowright[8]={ + { 0, { 0, 0, 0 } }, + { 1, { 7, 0, 0 } }, + { 2, { 5, 7, 0 } }, + { 1, { 5, 0, 0 } }, + { 0, { 0, 0, 0 } }, + { 0, { 0, 0, 0 } }, + { 0, { 0, 0, 0 } }, + { 0, { 0, 0, 0 } } +}; + +char *TE; + +int fputchar(c) + char c; +{ + return putchar(c); +} + +void quit() +{ + signal(SIGINT, SIG_IGN); + tputs(TE,1,fputchar); + exit(0); +} + +float ranf() +{ + return((float)rand()/2147483647.); +} + +int main(argc, argv) + int argc; + char *argv[]; +{ + register int x, y; + register int n; + register struct worm *w; + register struct options *op; + register int h; + register short *ip; + char *AL, *BC, *CM, *EI, *HO, *IC, *IM, *IP, *SR; + int CO, IN, LI, last, bottom; + char *tcp; + register char *term; + char tcb[100]; + struct sgttyb sg; + + setbuf(stdout,malloc(BUFSIZ)); + for (x=1;x1024) { + fprintf(stderr,"%s: Invalid length\n",*argv); + exit(1); + } + break; + case 'n': + if (++x==argc) goto usage; + if ((number=atoi(argv[x]))<1||number>40) { + fprintf(stderr,"%s: Invalid number of worms\n",*argv); + exit(1); + } + break; + case 't': + trail='.'; + break; + default: + usage: + fprintf(stderr, + "usage: %s [-field] [-length #] [-number #] [-trail]\n",*argv); + exit(1); + break; + } + } + if (!(term=getenv("TERM"))) { + fprintf(stderr,"%s: TERM: parameter not set\n",*argv); + exit(1); + } + if (tgetent(malloc(1024),term)<=0) { + fprintf(stderr,"%s: %s: unknown terminal type\n",*argv,term); + exit(1); + } + tcp=tcb; + if (!(CM=tgetstr("cm",&tcp))) { + fprintf(stderr,"%s: terminal not capable of cursor motion\n",*argv); + exit(1); + } + AL=tgetstr("al",&tcp); + BC=tgetflag("bs") ? "\b" : tgetstr("bc",&tcp); + if ((CO=tgetnum("co"))<=0) CO=80; + last=CO-1; + EI=tgetstr("ei",&tcp); + HO=tgetstr("ho",&tcp); + IC=tgetstr("ic",&tcp); + IM=tgetstr("im",&tcp); + IN=tgetflag("in"); + IP=tgetstr("ip",&tcp); + if ((LI=tgetnum("li"))<=0) LI=24; + bottom=LI-1; + SR=tgetstr("sr",&tcp); + TE=tgetstr("te",&tcp); + UP=tgetstr("up",&tcp); + ioctl(fileno(stdout),TIOCSETP,&sg); + ospeed=sg.sg_ospeed; + Wrap=tgetflag("am"); + ip=(short *)malloc(LI*CO*sizeof (short)); + for (n=0;n=0;) *ip++=0; + if (Wrap) ref[bottom][last]=1; + for (n=number, w= &worm[0];--n>=0;w++) { + w->orientation=w->head=0; + if (!(ip=(short *)malloc(length*sizeof (short)))) { + fprintf(stderr,"%s: out of memory\n",*argv); + exit(1); + } + w->xpos=ip; + for (x=length;--x>=0;) *ip++ = -1; + if (!(ip=(short *)malloc(length*sizeof (short)))) { + fprintf(stderr,"%s: out of memory\n",*argv); + exit(1); + } + w->ypos=ip; + for (y=length;--y>=0;) *ip++ = -1; + } + signal(SIGINT, quit); + tputs(tgetstr("ti",&tcp),1,fputchar); + tputs(tgetstr("cl",&tcp),1,fputchar); + if (field) { + register char *p; + p=field; + for (y=bottom;--y>=0;) { + for (x=CO;--x>=0;) { + putchar(*p++); + if (!*p) p=field; + } + if (!Wrap) putchar('\n'); + fflush(stdout); + } + if (Wrap) { + if (IM&&!IN) { + for (x=last;--x>0;) { + putchar(*p++); + if (!*p) p=field; + } + y= *p++; if (!*p) p=field; + putchar(*p); + if (BC) tputs(BC,1,fputchar); + else cursor(last-1,bottom); + tputs(IM,1,fputchar); + if (IC) tputs(IC,1,fputchar); + putchar(y); + if (IP) tputs(IP,1,fputchar); + tputs(EI,1,fputchar); + } + else if (SR||AL) { + if (HO) tputs(HO,1,fputchar); + else cursor(0,0); + if (SR) tputs(SR,1,fputchar); + else tputs(AL,LI,fputchar); + for (x=CO;--x>=0;) { + putchar(*p++); + if (!*p) p=field; + } + } + else for (x=last;--x>=0;) { + putchar(*p++); + if (!*p) p=field; + } + } + else for (x=CO;--x>=0;) { + putchar(*p++); + if (!*p) p=field; + } + } + fflush(stdout); + for (;;) { + for (n=0,w= &worm[0];nxpos[h=w->head])<0) { + cursor(x=w->xpos[h]=0,y=w->ypos[h]=bottom); + putchar(flavor[n%6]); + ref[y][x]++; + } + else y=w->ypos[h]; + if (++h==length) h=0; + if (w->xpos[w->head=h]>=0) { + register int x1, y1; + x1=w->xpos[h]; y1=w->ypos[h]; + if (--ref[y1][x1]==0) { + cursor(x1,y1); putchar(trail); + } + } + op= &(x==0 ? (y==0 ? upleft : (y==bottom ? lowleft : left)) : + (x==last ? (y==0 ? upright : (y==bottom ? lowright : right)) : + (y==0 ? upper : (y==bottom ? lower : normal))))[w->orientation]; + switch (op->nopts) { + case 0: + fflush(stdout); + abort(); + return 0; + case 1: + w->orientation=op->opts[0]; + break; + default: + w->orientation=op->opts[(int)(ranf()*(float)op->nopts)]; + } + cursor(x+=xinc[w->orientation], y+=yinc[w->orientation]); + if (!Wrap||x!=last||y!=bottom) putchar(flavor[n%6]); + ref[w->ypos[h]=y][w->xpos[h]=x]++; + } + fflush(stdout); + } +} diff --git a/src/games/wump.6 b/src/games/wump.6 new file mode 100644 index 0000000..b0c45d1 --- /dev/null +++ b/src/games/wump.6 @@ -0,0 +1,26 @@ +.\" @(#)wump.6 6.1 (Berkeley) 5/20/85 +.\" +.TH WUMP 6 "May 20, 1985" +.AT 3 +.SH NAME +wump \- the game of hunt-the-wumpus +.SH SYNOPSIS +.B /usr/games/wump +.SH DESCRIPTION +.I Wump +plays the game of `Hunt the Wumpus.' +A Wumpus is a creature that lives in a cave with several rooms +connected by tunnels. +You wander among the rooms, trying to +shoot the Wumpus with an arrow, meanwhile avoiding +being eaten by the Wumpus and falling into Bottomless Pits. +There are also Super Bats which are likely to pick you up +and drop you in some random room. +.PP +The program asks various questions which you answer one per line; +it will give a more detailed description if you want. +.PP +This program is based on one described in +.I "People's Computer Company," +.I 2, +2 (November 1973). diff --git a/src/games/wump.c b/src/games/wump.c new file mode 100644 index 0000000..b52605d --- /dev/null +++ b/src/games/wump.c @@ -0,0 +1,398 @@ +/* + * wumpus + * stolen from PCC Vol 2 No 1 + */ +#ifdef CROSS +# include +#else +# include +#endif +#include +#include +#include + +#define NBAT 3 +#define NROOM 20 +#define NTUNN 3 +#define NPIT 3 +#ifdef pdp11 +#define BIGINT 32768.0 +#else +#define BIGINT 2147483648.0 +#endif + +struct room +{ + int tunn[NTUNN]; + int flag; +} room[NROOM]; + +char *intro[] = +{ + "\n", + "Welcome to 'Hunt the Wumpus.'\n", + "\n", + "The Wumpus lives in a cave of %d rooms.\n", + "Each room has %d tunnels leading to other rooms.\n", + "\n", + "Hazards:\n", + "\n", + "Bottomless Pits - Some rooms have Bottomless Pits in them.\n", + " If you go there, you fall into the pit and lose!\n", + "Super Bats - Some other rooms have super bats.\n", + " If you go there, a bat will grab you and take you to\n", + " somewhere else in the cave where you could\n", + " fall into a pit or run into the . . .\n", + "\n", + "Wumpus:\n", + "\n", + "The Wumpus is not bothered by the hazards since\n", + "he has sucker feet and is too big for a bat to lift.\n", + "\n", + "Usually he is asleep.\n", + "Two things wake him up:\n", + " your entering his room\n", + " your shooting an arrow anywhere in the cave.\n", + "If the wumpus wakes, he either decides to move one room or\n", + "stay where he was. But if he ends up where you are,\n", + "he eats you up and you lose!\n", + "\n", + "You:\n", + "\n", + "Each turn you may either move or shoot a crooked arrow.\n", + "\n", + "Moving - You can move to one of the adjoining rooms;\n", + " that is, to one that has a tunnel connecting it with\n", + " the room you are in.\n", + "\n", + "Shooting - You have 5 arrows. You lose when you run out.\n", + " Each arrow can go from 1 to 5 rooms.\n", + " You aim by telling the computer\n", + " The arrow's path is a list of room numbers\n", + " telling the arrow which room to go to next.\n", + " The list is terminated with a 0.\n", + " The first room in the path must be connected to the\n", + " room you are in. Each succeeding room must be\n", + " connected to the previous room.\n", + " If there is no tunnel between two of the rooms\n", + " in the arrow's path, the arrow chooses one of the\n", + " three tunnels from the room it's in and goes its\n", + " own way.\n", + "\n", + " If the arrow hits the wumpus, you win!\n", + " If the arrow hits you, you lose!\n", + "\n", + "Warnings:\n", + "\n", + "When you are one or two rooms away from the wumpus,\n", + "the computer says:\n", + " 'I smell a Wumpus'\n", + "When you are one room away from some other hazard, it says:\n", + " Bat - 'Bats nearby'\n", + " Pit - 'I feel a draft'\n", + "\n", + 0, +}; + +#define BAT 01 +#define PIT 02 +#define WUMP 04 + +int arrow; +int loc; +int wloc; +int tchar; + +int rnum(n) +{ + static short first[2]; + + if(first[1] == 0) { + time(first); + if(first[1]==0) first[1] = 1; + srand((first[1]*first[0])^first[1]); + } + return((int)((rand()/BIGINT) * n)); +} + +int tunnel(i) +{ + register struct room *p; + register int n, j; + int c; + + c = 20; +loop: + n = rnum(NROOM); + if(n == i) + if(--c > 0) + goto loop; + p = &room[n]; + for(j=0; jtunn[j] == -1) { + p->tunn[j] = i; + return(n); + } + goto loop; +} + +int rline() +{ + register char c, r; + + while ((c = getchar()) == ' '); + r = c; + while (c != '\n' && c != ' ') { + if (c == EOF) + exit(0); + c = getchar(); + } + tchar = c; + return(r); +} + +int rin() +{ + register int n, c; + + n = 0; + c = getchar(); + while(c != '\n' && c != ' ') { + if(c<'0' || c>'9') { + while(c != '\n') { + if(c == EOF) + exit(0); + c = getchar(); + } + return(0); + } + n = n*10 + c-'0'; + c = getchar(); + } + return(n); +} + +int near(ap, ahaz) + struct room *ap; +{ + register struct room *p; + register int haz, i; + + p = ap; + haz = ahaz; + for(i=0; itunn[i]].flag & haz) + return (1); + return(0); +} + +int icomp(p1, p2) + int *p1, *p2; +{ + return(*p1 - *p2); +} + +void drain() +{ + fflush (stdin); +#if 0 + struct sgttyb arg; + if (gtty(0, &arg) != -1) + stty(0, &arg); +#endif +} + +int main() +{ + register int i, j; + register struct room *p; + int k; + + printf("Instructions? (y-n) "); + if(rline() == 'y') + for(i=0; intro[i]; i++) + printf(intro[i], i&1? NROOM: NTUNN); + + +/* + * initialize the room connections + */ + +init: + p = &room[0]; + for(i=0; itunn[j] = -1; + p++; + } + k = 0; + for(i=1; itunn[0] >= 0 || p->tunn[1] >= 0) + continue; + p->tunn[1] = k; + room[k].tunn[0] = j; + k = j; + i++; + } + p = &room[0]; + for(i=0; itunn[j] < 0) + p->tunn[j] = tunnel(i); + if(p->tunn[j] == i) + goto init; + for(k=0; ktunn[j] == p->tunn[k]) + goto init; + } + qsort(&p->tunn[0], NTUNN, sizeof(p->tunn[0]), icomp); + p++; + } + +/* + * put in player, wumpus, + * pits and bats + */ + +setup: + arrow = 5; + p = &room[0]; + for(i=0; iflag = 0; + p++; + } + for(i=0; iflag&PIT) == 0) { + p->flag |= PIT; + i++; + } + } + for(i=0; iflag&(PIT|BAT)) == 0) { + p->flag |= BAT; + i++; + } + } + i = rnum(NROOM); + wloc = i; + room[i].flag |= WUMP; + for(;;) { + i = rnum(NROOM); + if((room[i].flag&(PIT|BAT|WUMP)) == 0) { + loc = i; + break; + } + } + +/* + * main loop of the game + */ + +loop: + printf("You are in room %d\n", loc+1); + p = &room[loc]; + if(p->flag&PIT) { + printf("You fell into a pit\n"); + goto done; + } + if(p->flag&WUMP) { + printf("You were eaten by the wumpus\n"); + goto done; + } + if(p->flag&BAT) { + printf("Theres a bat in your room\n"); + loc = rnum(NROOM); + goto loop; + } + for(i=0; itunn[i]], WUMP)) + goto nearwump; + if (near(p, WUMP)) { + nearwump: + printf("I smell a wumpus\n"); + } + if (near(p, BAT)) + printf("Bats nearby\n"); + if (near(p, PIT)) + printf("I feel a draft\n"); + printf("There are tunnels to"); + for(i=0; itunn[i]+1); + printf("\n"); + +again: + printf("Move or shoot (m-s) "); + switch(rline()) { + case 'm': + if(tchar == '\n') + printf("which room? "); + i = rin()-1; + for(j=0; jtunn[j]) + goto groom; + printf("You hit the wall\n"); + goto again; + groom: + loc = i; + if(i == wloc) + goto mwump; + goto loop; + + case 's': + if(tchar == '\n') + printf("Give list of rooms terminated by 0\n"); + for(i=0; i<5; i++) { + j = rin()-1; + if(j == -1) + break; + ranarw: + for(k=0; ktunn[k]) + goto garow; + j = rnum(NROOM); + goto ranarw; + garow: + p = &room[j]; + if(j == loc) { + printf("You shot yourself\n"); + goto done; + } + if(p->flag&WUMP) { + printf("You slew the wumpus\n"); + goto done; + } + } + if(--arrow == 0) { + printf("That was your last shot\n"); + goto done; + } + goto mwump; + } + + goto again; + +mwump: + p = &room[wloc]; + p->flag &= ~WUMP; + i = rnum(NTUNN+1); + if(i != NTUNN) + wloc = p->tunn[i]; + room[wloc].flag |= WUMP; + goto loop; + +done: + drain(); + printf("Another game? (y-n) "); + if(rline() != 'n') { + drain(); + printf("Same room setup? (y-n) "); + if(rline() != 'n') + goto setup; + goto init; + } + return 0; +} diff --git a/src/libc/Makefile b/src/libc/Makefile new file mode 100644 index 0000000..3d0c081 --- /dev/null +++ b/src/libc/Makefile @@ -0,0 +1,59 @@ +# +# Copyright (c) 1980 Regents of the University of California. +# All rights reserved. The Berkeley software License Agreement +# specifies the terms and conditions for redistribution. +# +# Machine dependent routines are located in a subtree which parallels +# the top directories. This subtree is identified by the machine name. +# +# Compatibility routines are kept in directories with a prefixing +# ``compat'' (so they all sort together). +# +# The C run-time startup code is always machine dependent and expected +# to be located in ../startup-${MACHINE}. +# +# All files contain sccsid strings, but these are not compiled into +# library objects by default, as a space-saving measure. To produce +# a library that contains these strings in every object except +# system call stubs, add -DLIBC_SCCS to DEFS below; to put these +# strings into system call stubs, use -DSYSLIBC_SCCS. +# +# To compile a non-floating point versions of some standard library +# routines add -DNONFP. This will speed up some operations if you don't +# have hardware floating point. To compile a non-separate I&D version add +# -DNONSEPARATE. +# +TOPSRC = $(shell cd ../..; pwd) +include $(TOPSRC)/target.mk + +DEFS = -Wall -Werror +ALL = gen stdio stdlib string inet compat ${MACHINE} + +all: ../libc.a + +../libc.a: ${ALL} + rm -rf tmp + mkdir tmp + cd tmp; for i in ${ALL}; do $(AR) x ../$$i/$$i.a; done; \ + $(AR) cr ../$@ *.o +# $(AR) cr ../$@ `sh ../../cmd/lorder.sh *.o | tsort` + rm -rf tmp + +${ALL}: FRC + cd $@; make ${MFLAGS} DEFS="${DEFS}" + +FRC: + +install: ../libc.a + ${INSTALLDIR} ${DESTDIR}/lib +# ${INSTALL} ../libc.a ${DESTDIR}/lib/libc.a +# $(RANLIB) ${DESTDIR}/lib/libc.a + +clean: + for i in ${ALL}; \ + do (cd $$i; make ${MFLAGS} clean); done + rm -rf tmp *.a *~ + +depend: + for i in ${ALL}; \ + do (cd $$i; make ${MFLAGS} DEFS="${DEFS}" depend); done diff --git a/src/libc/compat/Makefile b/src/libc/compat/Makefile new file mode 100644 index 0000000..917649e --- /dev/null +++ b/src/libc/compat/Makefile @@ -0,0 +1,50 @@ +# +# Copyright (c) 1980 Regents of the University of California. +# All rights reserved. The Berkeley software License Agreement +# specifies the terms and conditions for redistribution. +# +TOPSRC = $(shell cd ../../..; pwd) +include $(TOPSRC)/target.mk + +CFLAGS += ${DEFS} -Os + +SRCS = creat.c ftime.c gethostid.c gtty.c memccpy.c memchr.c memcmp.c \ + memcpy.c memset.c nice.c pause.c rand.c sethostid.c \ + setregid.c setreuid.c setrgid.c setruid.c sigcompat.c \ + strchr.c strrchr.c stty.c times.c tmpnam.c utime.c +OBJS = creat.o ftime.o gethostid.o gtty.o memccpy.o memchr.o memcmp.o \ + memcpy.o memset.o nice.o pause.o rand.o sethostid.o \ + setregid.o setreuid.o setrgid.o setruid.o sigcompat.o \ + strchr.o strrchr.o stty.o times.o tmpnam.o utime.o + +compat.a: ${OBJS} + @echo "buiding compat.a" + @$(AR) cru compat.a ${OBJS} + +tags: + cwd=`pwd`; \ + for i in ${SRCS}; do \ + ctags -a -f ${TAGSFILE} $$cwd/$$i; \ + done + +clean: + rm -f compat.a *.o *~ profiled/*.o tags Makefile.bak + +depend: + for i in ${SRCS}; do \ + cc -M ${CFLAGS} $$i | 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 } ' >> makedep; done + echo '/^# DO NOT DELETE THIS LINE/+2,$$d' >eddep + echo '$$r makedep' >>eddep + echo 'w' >>eddep + cp Makefile Makefile.bak + ed - Makefile < eddep + rm eddep makedep + echo '# DEPENDENCIES MUST END AT END OF FILE' >> Makefile + echo '# IF YOU PUT STUFF HERE IT WILL GO AWAY' >> Makefile + echo '# see make depend above' >> Makefile + +# DO NOT DELETE THIS LINE -- make depend uses it diff --git a/src/libc/compat/creat.c b/src/libc/compat/creat.c new file mode 100644 index 0000000..3be80dd --- /dev/null +++ b/src/libc/compat/creat.c @@ -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. + */ +#include + +int +creat (path, mode) + const char *path; + mode_t mode; +{ + return open (path, O_WRONLY | O_CREAT | O_TRUNC, mode); +} diff --git a/src/libc/compat/ftime.c b/src/libc/compat/ftime.c new file mode 100644 index 0000000..c8bf403 --- /dev/null +++ b/src/libc/compat/ftime.c @@ -0,0 +1,35 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include +#include + +/* + * Backwards compatible ftime. + */ + +/* from old timeb.h */ +struct timeb { + time_t time; + u_short millitm; + short timezone; + short dstflag; +}; + +int +ftime(tp) + register struct timeb *tp; +{ + struct timeval t; + struct timezone tz; + + if (gettimeofday(&t, &tz) < 0) + return (-1); + tp->time = t.tv_sec; + tp->millitm = t.tv_usec / 1000; + tp->timezone = tz.tz_minuteswest; + tp->dstflag = tz.tz_dsttime; + return 0; +} diff --git a/src/libc/compat/gethostid.c b/src/libc/compat/gethostid.c new file mode 100644 index 0000000..4213eaa --- /dev/null +++ b/src/libc/compat/gethostid.c @@ -0,0 +1,49 @@ +/* + * 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. + */ +#include +#include + +u_long +gethostid() +{ + int mib[2]; + size_t size; + u_long value; + + mib[0] = CTL_KERN; + mib[1] = KERN_HOSTID; + size = sizeof value; + if (sysctl(mib, 2, &value, &size, NULL, 0) == -1) + return (-1); + return (value); +} diff --git a/src/libc/compat/gtty.c b/src/libc/compat/gtty.c new file mode 100644 index 0000000..c064413 --- /dev/null +++ b/src/libc/compat/gtty.c @@ -0,0 +1,17 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +/* + * Writearound to old gtty system call. + */ +#include + +int +gtty(fd, ap) + struct sgtty *ap; +{ + return ioctl(fd, TIOCGETP, ap); +} diff --git a/src/libc/compat/memccpy.c b/src/libc/compat/memccpy.c new file mode 100644 index 0000000..2f8ca7e --- /dev/null +++ b/src/libc/compat/memccpy.c @@ -0,0 +1,25 @@ +/* + * Copyright (c) 1985 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include + +/* + * Sys5 compat routine + */ +void * +memccpy(vt, vf, c, n) + void *vt; + const void *vf; + register int c; + register size_t n; +{ + register char *t = vt; + register const char *f = vf; + + while (--n >= 0) + if ((*t++ = *f++) == c) + return (t); + return (0); +} diff --git a/src/libc/compat/memchr.c b/src/libc/compat/memchr.c new file mode 100644 index 0000000..12597a9 --- /dev/null +++ b/src/libc/compat/memchr.c @@ -0,0 +1,23 @@ +/* + * Copyright (c) 1985 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include + +/* + * Sys5 compat routine + */ +void * +memchr(vs, c, n) + const void *vs; + register int c; + register size_t n; +{ + register const char *s = vs; + + while (--n >= 0) + if (*s++ == c) + return (void*) --s; + return (0); +} diff --git a/src/libc/compat/memcmp.c b/src/libc/compat/memcmp.c new file mode 100644 index 0000000..bca8b1c --- /dev/null +++ b/src/libc/compat/memcmp.c @@ -0,0 +1,22 @@ +/* + * Copyright (c) 1985 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include + +/* + * Sys5 compat routine + */ +int +memcmp (vs1, vs2, n) + const void *vs1, *vs2; + register size_t n; +{ + register const char *s1 = vs1, *s2 = vs2; + + while (--n >= 0) + if (*s1++ != *s2++) + return (*--s1 - *--s2); + return (0); +} diff --git a/src/libc/compat/memcpy.c b/src/libc/compat/memcpy.c new file mode 100644 index 0000000..a167c90 --- /dev/null +++ b/src/libc/compat/memcpy.c @@ -0,0 +1,24 @@ +/* + * Copyright (c) 1985 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include + +/* + * Sys5 compat routine + */ +void * +memcpy (vt, vf, n) + void *vt; + const void *vf; + register size_t n; +{ + register char *t = vt; + register const char *f = vf; + + while (--n >= 0) + *t++ = *f++; + + return vt; +} diff --git a/src/libc/compat/memset.c b/src/libc/compat/memset.c new file mode 100644 index 0000000..7fe2be0 --- /dev/null +++ b/src/libc/compat/memset.c @@ -0,0 +1,23 @@ +/* + * Copyright (c) 1985 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include + +/* + * Sys5 compat routine + */ +void * +memset (vs, c, n) + void *vs; + register int c; + register size_t n; +{ + register char *s = vs; + + while (--n >= 0) + *s++ = c; + + return vs; +} diff --git a/src/libc/compat/nice.c b/src/libc/compat/nice.c new file mode 100644 index 0000000..d4fa0a1 --- /dev/null +++ b/src/libc/compat/nice.c @@ -0,0 +1,24 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include +#include + +/* + * Backwards compatible nice. + */ +int +nice(incr) + int incr; +{ + int prio; + extern int errno; + + errno = 0; + prio = getpriority(PRIO_PROCESS, 0); + if (prio == -1 && errno) + return (-1); + return setpriority(PRIO_PROCESS, 0, prio + incr); +} diff --git a/src/libc/compat/pause.c b/src/libc/compat/pause.c new file mode 100644 index 0000000..b4d38c2 --- /dev/null +++ b/src/libc/compat/pause.c @@ -0,0 +1,19 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include + +/* + * Backwards compatible pause. + */ +int +pause() +{ + sigset_t set; + + sigemptyset(&set); + sigsuspend(&set); + return 0; +} diff --git a/src/libc/compat/rand.c b/src/libc/compat/rand.c new file mode 100644 index 0000000..383fce3 --- /dev/null +++ b/src/libc/compat/rand.c @@ -0,0 +1,23 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +static long randx = 1; + +void +srand(x) + unsigned x; +{ + randx = x; +} + +int +rand() +{ +#ifdef pdp11 + return(((randx = randx * 1103515245 + 12345)>>16) & 0x7fff); +#else + return((randx = randx * 1103515245 + 12345) & 0x7fffffff); +#endif +} diff --git a/src/libc/compat/sethostid.c b/src/libc/compat/sethostid.c new file mode 100644 index 0000000..570e8b5 --- /dev/null +++ b/src/libc/compat/sethostid.c @@ -0,0 +1,47 @@ +/* + * 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. + */ +#include +#include + +u_long +sethostid(hostid) + u_long hostid; +{ + int mib[2]; + + mib[0] = CTL_KERN; + mib[1] = KERN_HOSTID; + if (sysctl(mib, 2, NULL, NULL, &hostid, sizeof hostid) == -1) + return (-1); + return (0); +} diff --git a/src/libc/compat/setregid.c b/src/libc/compat/setregid.c new file mode 100644 index 0000000..7ebe2eb --- /dev/null +++ b/src/libc/compat/setregid.c @@ -0,0 +1,58 @@ +/* + * 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. + */ +#include +#include +#include + +int +setregid(rgid, egid) + register gid_t rgid, egid; +{ + static gid_t savedgid = -1; + + if (savedgid == -1) + savedgid = getegid(); + /* + * we assume that the intent here is to be able to + * get back rgid priviledge. So we make sure that + * we will be able to do so, but do not actually + * set the rgid. + */ + if (rgid != -1 && rgid != getgid() && rgid != savedgid) { + errno = EPERM; + return (-1); + } + if (egid != -1 && setegid(egid) < 0) + return (-1); + return (0); +} diff --git a/src/libc/compat/setreuid.c b/src/libc/compat/setreuid.c new file mode 100644 index 0000000..10439af --- /dev/null +++ b/src/libc/compat/setreuid.c @@ -0,0 +1,58 @@ +/* + * 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. + */ +#include +#include +#include + +int +setreuid(ruid, euid) + register uid_t ruid, euid; +{ + static uid_t saveduid = -1; + + if (saveduid == -1) + saveduid = geteuid(); + /* + * we assume that the intent here is to be able to + * get back ruid priviledge. So we make sure that + * we will be able to do so, but do not actually + * set the ruid. + */ + if (ruid != -1 && ruid != getuid() && ruid != saveduid) { + errno = EPERM; + return (-1); + } + if (euid != -1 && seteuid(euid) < 0) + return (-1); + return (0); +} diff --git a/src/libc/compat/setrgid.c b/src/libc/compat/setrgid.c new file mode 100644 index 0000000..4f7c2eb --- /dev/null +++ b/src/libc/compat/setrgid.c @@ -0,0 +1,40 @@ +/* + * 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. + */ +#include + +int +setrgid(rgid) + int rgid; +{ + return (setregid(rgid, -1)); +} diff --git a/src/libc/compat/setruid.c b/src/libc/compat/setruid.c new file mode 100644 index 0000000..0d17758 --- /dev/null +++ b/src/libc/compat/setruid.c @@ -0,0 +1,40 @@ +/* + * 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. + */ +#include + +int +setruid(ruid) + int ruid; +{ + return (setreuid(ruid, -1)); +} diff --git a/src/libc/compat/sigcompat.c b/src/libc/compat/sigcompat.c new file mode 100644 index 0000000..e4a8be8 --- /dev/null +++ b/src/libc/compat/sigcompat.c @@ -0,0 +1,82 @@ +/* + * 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. + */ +#include +#include + +int +sigvec(signo, sv, osv) + int signo; + register struct sigvec *sv, *osv; +{ + int ret; + + if (sv) + sv->sv_flags ^= SV_INTERRUPT; /* !SA_INTERRUPT */ + ret = sigaction(signo, (struct sigaction *)sv, (struct sigaction *)osv); + if (ret == 0 && osv) + osv->sv_flags ^= SV_INTERRUPT; /* !SA_INTERRUPT */ + return(ret); +} + +int +sigsetmask(mask) + int mask; +{ + long omask; + int n; + + n = sigprocmask(SIG_SETMASK, (sigset_t *) &mask, (sigset_t *) &omask); + if (n) + return((long)n); + return(omask); +} + +int +sigblock(mask) + int mask; +{ + long omask; + int n; + + n = sigprocmask(SIG_BLOCK, (sigset_t *) &mask, (sigset_t *) &omask); + if (n) + return((long)n); + return(omask); +} + +int +sigpause(mask) + int mask; +{ + return(sigsuspend((sigset_t *)&mask)); +} diff --git a/src/libc/compat/strchr.c b/src/libc/compat/strchr.c new file mode 100644 index 0000000..4250406 --- /dev/null +++ b/src/libc/compat/strchr.c @@ -0,0 +1,17 @@ +/* + * Return the ptr in sp at which the character c appears; + * NULL if not found + * + * this routine is just "index" renamed. + */ +char * +strchr (sp, c) + register const char *sp; + register int c; +{ + do { + if (*sp == c) + return (char*) sp; + } while (*sp++); + return 0; +} diff --git a/src/libc/compat/strrchr.c b/src/libc/compat/strrchr.c new file mode 100644 index 0000000..b1c4e48 --- /dev/null +++ b/src/libc/compat/strrchr.c @@ -0,0 +1,20 @@ +/* + * Return the ptr in sp at which the character c last + * appears; NULL if not found + * + * This routine is just "rindex" renamed. + */ +char * +strrchr(sp, c) + register const char *sp; + register int c; +{ + register char *r; + + r = 0; + do { + if (*sp == c) + r = (char*) sp; + } while (*sp++); + return(r); +} diff --git a/src/libc/compat/stty.c b/src/libc/compat/stty.c new file mode 100644 index 0000000..b1f95aa --- /dev/null +++ b/src/libc/compat/stty.c @@ -0,0 +1,17 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +/* + * Writearound to old stty system call. + */ +#include + +int +stty(fd, ap) + struct sgtty *ap; +{ + return ioctl (fd, TIOCSETP, ap); +} diff --git a/src/libc/compat/times.c b/src/libc/compat/times.c new file mode 100644 index 0000000..8805f9a --- /dev/null +++ b/src/libc/compat/times.c @@ -0,0 +1,34 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include +#include +#include +#include + +static long +scale60(tvp) + register struct timeval *tvp; +{ + return (tvp->tv_sec * 60 + tvp->tv_usec / 16667); +} + +int +times(tmsp) + register struct tms *tmsp; +{ + struct rusage ru; + long scale60(); + + if (getrusage(RUSAGE_SELF, &ru) < 0) + return (-1); + tmsp->tms_utime = scale60(&ru.ru_utime); + tmsp->tms_stime = scale60(&ru.ru_stime); + if (getrusage(RUSAGE_CHILDREN, &ru) < 0) + return (-1); + tmsp->tms_cutime = scale60(&ru.ru_utime); + tmsp->tms_cstime = scale60(&ru.ru_stime); + return (0); +} diff --git a/src/libc/compat/tmpnam.c b/src/libc/compat/tmpnam.c new file mode 100644 index 0000000..a0605ad --- /dev/null +++ b/src/libc/compat/tmpnam.c @@ -0,0 +1,76 @@ +/* + * 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. + */ +#include +#include +#include +#include +#include +#include + +FILE * +tmpfile() +{ + FILE *fp; + char *f, *tmpnam(); + + if (!(f = tmpnam((char *)NULL)) || !(fp = fopen(f, "w+"))) { + fprintf(stderr, "tmpfile: cannot open %s.\n", f); + return(NULL); + } + (void)unlink(f); + return(fp); +} + +char * +tmpnam(s) + char *s; +{ + if (!s && !(s = malloc((u_int)MAXPATHLEN))) + return(NULL); + strcpy(s, _PATH_USRTMP "XXXXXX"); + return mktemp(s); +} + +char * +tempnam(dir, pfx) + char *dir, *pfx; +{ + char *f, *name; + + if (!(name = malloc((u_int)MAXPATHLEN))) + return(NULL); + + f = getenv("TMPDIR"); + if (f) { + (void)sprintf(name, "%s/%sXXXXXX", f, pfx ? "" : pfx); + f = mktemp(name); + if (f) + return(f); + } + if (dir) { + (void)sprintf(name, "%s/%sXXXXXX", dir, pfx ? "" : pfx); + f = mktemp(name); + if (f) + return(f); + } + (void)sprintf(name, _PATH_USRTMP "%sXXXXXX", pfx ? "" : pfx); + f = mktemp(name); + if (f) + return(f); + (void)sprintf(name, "/tmp/%sXXXXXX", pfx ? "" : pfx); + return(mktemp(name)); +} diff --git a/src/libc/compat/utime.c b/src/libc/compat/utime.c new file mode 100644 index 0000000..8b8687f --- /dev/null +++ b/src/libc/compat/utime.c @@ -0,0 +1,22 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include +#include + +/* + * Backwards compatible utime. + */ +int +utime(name, otv) + char *name; + time_t otv[]; +{ + struct timeval tv[2]; + + tv[0].tv_sec = otv[0]; tv[0].tv_usec = 0; + tv[1].tv_sec = otv[1]; tv[1].tv_usec = 0; + return utimes(name, tv); +} diff --git a/src/libc/gen/Makefile b/src/libc/gen/Makefile new file mode 100644 index 0000000..f6ceacd --- /dev/null +++ b/src/libc/gen/Makefile @@ -0,0 +1,78 @@ +# +# Copyright (c) 1980 Regents of the University of California. +# All rights reserved. The Berkeley software License Agreement +# specifies the terms and conditions for redistribution. +# +TOPSRC = $(shell cd ../../..; pwd) +include $(TOPSRC)/target.mk + +CFLAGS += ${DEFS} -Os -Wall -Werror + +SRCS = ${STDSRC} +OBJS = ${STDOBJ} + +STDSRC = abort.c alarm.c atof.c atoi.c atol.c calloc.c closedir.c crypt.c \ + ctime.c ctype_.c daemon.c devname.c ecvt.c err.c \ + execvp.c fakcu.c frexp.c fstab.c gcvt.c getenv.c getgrent.c \ + getgrgid.c getgrnam.c getlogin.c \ + getgrouplist.c gethostname.c getpagesize.c \ + getpass.c getpwent.c getloadavg.c getmntinfo.c \ + getttyent.c getttynam.c getusershell.c getwd.c \ + initgroups.c isatty.c isinff.c isnanf.c ldexp.c malloc.c mktemp.c \ + modff.c ndbm.c nlist.c knlist.c opendir.c perror.c popen.c \ + psignal.c qsort.c random.c readdir.c regex.c scandir.c \ + seekdir.c setmode.c sethostname.c setenv.c siglist.c \ + signal.c siginterrupt.c sigsetops.c \ + sleep.c strcasecmp.c strftime.c swab.c sysctl.c syslog.c system.c \ + strcat.c strncat.c strcpy.c strncpy.c strncmp.c \ + telldir.c time.c timezone.c ttyname.c ttyslot.c ualarm.c usleep.c \ + strdup.c uname.c wait.c wait3.c waitpid.c + +STDOBJ = abort.o alarm.o atof.o atoi.o atol.o calloc.o closedir.o crypt.o \ + ctime.o ctype_.o daemon.o devname.o ecvt.o err.o \ + execvp.o fakcu.o frexp.o fstab.o gcvt.o getenv.o getgrent.o \ + getgrgid.o getgrnam.o getlogin.o \ + getgrouplist.o gethostname.o getpagesize.o \ + getpass.o getpwent.o getloadavg.o getmntinfo.o \ + getttyent.o getttynam.o getusershell.o getwd.o \ + initgroups.o isatty.o isinff.o isnanf.o ldexp.o malloc.o mktemp.o \ + modff.o ndbm.o nlist.o knlist.o opendir.o perror.o popen.o \ + psignal.o qsort.o random.o readdir.o regex.o scandir.o \ + seekdir.o setmode.o sethostname.o setenv.o siglist.o \ + signal.o siginterrupt.o sigsetops.o \ + sleep.o strcasecmp.o strftime.o swab.o sysctl.o syslog.o system.o \ + strcat.o strncat.o strcpy.o strncpy.o strncmp.o \ + telldir.o time.o timezone.o ttyname.o ttyslot.o ualarm.o usleep.o \ + strdup.o uname.o wait.o wait3.o waitpid.o + +gen.a: ${OBJS} + @echo "buiding gen.a" + @$(AR) cru gen.a ${OBJS} + +tags: + cwd=`pwd`; \ + for i in ${SRCS}; do \ + ctags -a -f ${TAGSFILE} $$cwd/$$i; \ + done + +clean: + rm -f gen.a *.o *~ profiled/*.o tags Makefile.bak + +depend: + for i in ${SRCS}; do \ + cc -M ${CFLAGS} $$i | 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 } ' >> makedep; done + echo '/^# DO NOT DELETE THIS LINE/+2,$$d' >eddep + echo '$$r makedep' >>eddep + echo 'w' >>eddep + cp Makefile Makefile.bak + ed - Makefile < eddep + rm eddep makedep + echo '# DEPENDENCIES MUST END AT END OF FILE' >> Makefile + echo '# IF YOU PUT STUFF HERE IT WILL GO AWAY' >> Makefile + echo '# see make depend above' >> Makefile + +# DO NOT DELETE THIS LINE -- make depend uses it diff --git a/src/libc/gen/abort.c b/src/libc/gen/abort.c new file mode 100644 index 0000000..b853e36 --- /dev/null +++ b/src/libc/gen/abort.c @@ -0,0 +1,59 @@ +/* + * 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. + */ +#include +#include +#include + +void +abort() +{ + sigset_t mask; + + sigfillset(&mask); + /* + * don't block SIGABRT to give any handler a chance; we ignore + * any errors -- X311J doesn't allow abort to return anyway. + */ + sigdelset(&mask, SIGABRT); + (void)sigprocmask(SIG_SETMASK, &mask, (sigset_t *)NULL); + (void)kill(getpid(), SIGABRT); + + /* + * if SIGABRT ignored, or caught and the handler returns, do + * it again, only harder. + */ + (void)signal(SIGABRT, SIG_DFL); + (void)sigprocmask(SIG_SETMASK, &mask, (sigset_t *)NULL); + (void)kill(getpid(), SIGABRT); + exit(1); +} diff --git a/src/libc/gen/abs.c b/src/libc/gen/abs.c new file mode 100644 index 0000000..feb1d87 --- /dev/null +++ b/src/libc/gen/abs.c @@ -0,0 +1,11 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +abs(arg) + int arg; +{ + return(arg < 0 ? -arg : arg); +} diff --git a/src/libc/gen/alarm.c b/src/libc/gen/alarm.c new file mode 100644 index 0000000..b14f26a --- /dev/null +++ b/src/libc/gen/alarm.c @@ -0,0 +1,27 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +/* + * Backwards compatible alarm. + */ +#include + +int +alarm(secs) + int secs; +{ + struct itimerval it, oitv; + register struct itimerval *itp = ⁢ + + timerclear(&itp->it_interval); + itp->it_value.tv_sec = secs; + itp->it_value.tv_usec = 0; + if (setitimer(ITIMER_REAL, itp, &oitv) < 0) + return (-1); + if (oitv.it_value.tv_usec) + oitv.it_value.tv_sec++; + return (oitv.it_value.tv_sec); +} diff --git a/src/libc/gen/atof.c b/src/libc/gen/atof.c new file mode 100644 index 0000000..da73221 --- /dev/null +++ b/src/libc/gen/atof.c @@ -0,0 +1,99 @@ +/* + * C library - ascii to floating + * Copyright (c) 1987 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include +#include + +double +atof(p) +register char *p; +{ + register int c; + double fl, flexp, exp5; + double big = 72057594037927936.; /*2^56*/ + int nd; + register int eexp, exp, neg, negexp, bexp; + + neg = 1; + while((c = *p++) == ' ') + ; + if (c == '-') + neg = -1; + else if (c=='+') + ; + else + --p; + + exp = 0; + fl = 0; + nd = 0; + while ((c = *p++), isdigit(c)) { + if (fl>= 1; + if (exp==0) + break; + exp5 *= exp5; + } + if (negexp<0) + fl /= flexp; + else + fl *= flexp; + fl = ldexp(fl, negexp*bexp); + if (neg<0) + fl = -fl; + return(fl); +} diff --git a/src/libc/gen/atoi.c b/src/libc/gen/atoi.c new file mode 100644 index 0000000..8e26535 --- /dev/null +++ b/src/libc/gen/atoi.c @@ -0,0 +1,25 @@ +int +atoi(p) + register char *p; +{ + register int n; + register int f; + + n = 0; + f = 0; + for(;;p++) { + switch(*p) { + case ' ': + case '\t': + continue; + case '-': + f++; + case '+': + p++; + } + break; + } + while(*p >= '0' && *p <= '9') + n = n*10 + *p++ - '0'; + return(f? -n: n); +} diff --git a/src/libc/gen/atol.c b/src/libc/gen/atol.c new file mode 100644 index 0000000..bc80d48 --- /dev/null +++ b/src/libc/gen/atol.c @@ -0,0 +1,25 @@ +long +atol(p) + register char *p; +{ + long n; + register int f; + + n = 0; + f = 0; + for(;;p++) { + switch(*p) { + case ' ': + case '\t': + continue; + case '-': + f++; + case '+': + p++; + } + break; + } + while(*p >= '0' && *p <= '9') + n = n*10 + *p++ - '0'; + return(f? -n: n); +} diff --git a/src/libc/gen/bcmp-disabled.c b/src/libc/gen/bcmp-disabled.c new file mode 100644 index 0000000..a2becfd --- /dev/null +++ b/src/libc/gen/bcmp-disabled.c @@ -0,0 +1,23 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +/* + * bcmp -- vax cmpc3 instruction + */ +int +bcmp(v1, v2, length) + const void *v1, *v2; + unsigned long length; +{ + register const char *b1 = v1; + register const char *b2 = v2; + if (length) + do + if (*b1++ != *b2++) + break; + while (--length); + return(length); +} diff --git a/src/libc/gen/bcopy-disabled.c b/src/libc/gen/bcopy-disabled.c new file mode 100644 index 0000000..97cad8f --- /dev/null +++ b/src/libc/gen/bcopy-disabled.c @@ -0,0 +1,27 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +/* + * bcopy -- vax movc3 instruction + */ +bcopy(src, dst, length) + register char *src, *dst; + register unsigned int length; +{ + if (length && src != dst) + if (dst < src) + do + *dst++ = *src++; + while (--length); + else { /* copy backwards */ + src += length; + dst += length; + do + *--dst = *--src; + while (--length); + } + return(0); +} diff --git a/src/libc/gen/bzero-disabled.c b/src/libc/gen/bzero-disabled.c new file mode 100644 index 0000000..b5000eb --- /dev/null +++ b/src/libc/gen/bzero-disabled.c @@ -0,0 +1,19 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +/* + * bzero -- vax movc5 instruction + */ +bzero(b, length) + register char *b; + register unsigned int length; +{ + if (length) + do + *b++ = '\0'; + while (--length); + return(length); +} diff --git a/src/libc/gen/calloc.c b/src/libc/gen/calloc.c new file mode 100644 index 0000000..03283bf --- /dev/null +++ b/src/libc/gen/calloc.c @@ -0,0 +1,28 @@ +/* + * Calloc - allocate and clear memory block + */ +#include +#include +#include + +void * +calloc(num, size) + size_t num, size; +{ + register char *p; + + size *= num; + p = malloc(size); + if (p) + bzero(p, size); + return (p); +} + +void +cfree(p, num, size) + char *p; + unsigned num; + unsigned size; +{ + free(p); +} diff --git a/src/libc/gen/closedir.c b/src/libc/gen/closedir.c new file mode 100644 index 0000000..809c203 --- /dev/null +++ b/src/libc/gen/closedir.c @@ -0,0 +1,22 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include +#include +#include +#include + +/* + * close a directory. + */ +void +closedir(dirp) + register DIR *dirp; +{ + close(dirp->dd_fd); + dirp->dd_fd = -1; + dirp->dd_loc = 0; + free(dirp); +} diff --git a/src/libc/gen/crypt.c b/src/libc/gen/crypt.c new file mode 100644 index 0000000..9c96e09 --- /dev/null +++ b/src/libc/gen/crypt.c @@ -0,0 +1,378 @@ +/* + * This program implements the + * Proposed Federal Information Processing + * Data Encryption Standard. + * See Federal Register, March 17, 1975 (40FR12134) + */ + +/* + * Initial permutation, + */ +static char IP[] = { + 58,50,42,34,26,18,10, 2, + 60,52,44,36,28,20,12, 4, + 62,54,46,38,30,22,14, 6, + 64,56,48,40,32,24,16, 8, + 57,49,41,33,25,17, 9, 1, + 59,51,43,35,27,19,11, 3, + 61,53,45,37,29,21,13, 5, + 63,55,47,39,31,23,15, 7, +}; + +/* + * Final permutation, FP = IP^(-1) + */ +static char FP[] = { + 40, 8,48,16,56,24,64,32, + 39, 7,47,15,55,23,63,31, + 38, 6,46,14,54,22,62,30, + 37, 5,45,13,53,21,61,29, + 36, 4,44,12,52,20,60,28, + 35, 3,43,11,51,19,59,27, + 34, 2,42,10,50,18,58,26, + 33, 1,41, 9,49,17,57,25, +}; + +/* + * Permuted-choice 1 from the key bits + * to yield C and D. + * Note that bits 8,16... are left out: + * They are intended for a parity check. + */ +static char PC1_C[] = { + 57,49,41,33,25,17, 9, + 1,58,50,42,34,26,18, + 10, 2,59,51,43,35,27, + 19,11, 3,60,52,44,36, +}; + +static char PC1_D[] = { + 63,55,47,39,31,23,15, + 7,62,54,46,38,30,22, + 14, 6,61,53,45,37,29, + 21,13, 5,28,20,12, 4, +}; + +/* + * Sequence of shifts used for the key schedule. +*/ +static char shifts[] = { + 1,1,2,2,2,2,2,2,1,2,2,2,2,2,2,1, +}; + +/* + * Permuted-choice 2, to pick out the bits from + * the CD array that generate the key schedule. + */ +static char PC2_C[] = { + 14,17,11,24, 1, 5, + 3,28,15, 6,21,10, + 23,19,12, 4,26, 8, + 16, 7,27,20,13, 2, +}; + +static char PC2_D[] = { + 41,52,31,37,47,55, + 30,40,51,45,33,48, + 44,49,39,56,34,53, + 46,42,50,36,29,32, +}; + +/* + * The C and D arrays used to calculate the key schedule. + */ + +static char C[28]; +static char D[28]; +/* + * The key schedule. + * Generated from the key. + */ +static char KS[16][48]; + +/* + * The E bit-selection table. + */ +static char E[48]; +static char e[] = { + 32, 1, 2, 3, 4, 5, + 4, 5, 6, 7, 8, 9, + 8, 9,10,11,12,13, + 12,13,14,15,16,17, + 16,17,18,19,20,21, + 20,21,22,23,24,25, + 24,25,26,27,28,29, + 28,29,30,31,32, 1, +}; + +/* + * Set up the key schedule from the key. + */ +void +setkey(key) +char *key; +{ + register int i, j, k; + int t; + + /* + * First, generate C and D by permuting + * the key. The low order bit of each + * 8-bit char is not used, so C and D are only 28 + * bits apiece. + */ + for (i=0; i<28; i++) { + C[i] = key[PC1_C[i]-1]; + D[i] = key[PC1_D[i]-1]; + } + /* + * To generate Ki, rotate C and D according + * to schedule and pick up a permutation + * using PC2. + */ + for (i=0; i<16; i++) { + /* + * rotate. + */ + for (k=0; k>3)&01; + f[t+1] = (k>>2)&01; + f[t+2] = (k>>1)&01; + f[t+3] = (k>>0)&01; + } + /* + * The new R is L ^ f(R, K). + * The f here has to be permuted first, though. + */ + for (j=0; j<32; j++) + R[j] = L[j] ^ f[P[j]-1]; + /* + * Finally, the new L (the original R) + * is copied back. + */ + for (j=0; j<32; j++) + L[j] = tempL[j]; + } + /* + * The output L and R are reversed. + */ + for (j=0; j<32; j++) { + t = L[j]; + L[j] = R[j]; + R[j] = t; + } + /* + * The final output + * gets the inverse permutation of the very original. + */ + for (j=0; j<64; j++) + block[j] = L[FP[j]-1]; +} + +char * +crypt(pw,salt) +char *pw; +char *salt; +{ + register int i, j, c; + int temp; + static char block[66], iobuf[16]; + + for(i=0; i<66; i++) + block[i] = 0; + for(i=0; (c= *pw) && i<64; pw++){ + for(j=0; j<7; j++, i++) + block[i] = (c>>(6-j)) & 01; + i++; + } + + setkey(block); + + for(i=0; i<66; i++) + block[i] = 0; + + for(i=0;i<2;i++){ + c = *salt++; + iobuf[i] = c; + if(c>'Z') c -= 6; + if(c>'9') c -= 7; + c -= '.'; + for(j=0;j<6;j++){ + if((c>>j) & 01){ + temp = E[6*i+j]; + E[6*i+j] = E[6*i+j+24]; + E[6*i+j+24] = temp; + } + } + } + + for(i=0; i<25; i++) + encrypt(block,0); + + for(i=0; i<11; i++){ + c = 0; + for(j=0; j<6; j++){ + c <<= 1; + c |= block[6*i+j]; + } + c += '.'; + if(c>'9') c += 7; + if(c>'Z') c += 6; + iobuf[i+2] = c; + } + iobuf[i+2] = 0; + if(iobuf[1]==0) + iobuf[1] = iobuf[0]; + return(iobuf); +} diff --git a/src/libc/gen/ctime.c b/src/libc/gen/ctime.c new file mode 100644 index 0000000..c47a873 --- /dev/null +++ b/src/libc/gen/ctime.c @@ -0,0 +1,391 @@ +/* + * Copyright (c) 1987 Regents of the University of California. + * This file may be freely redistributed provided that this + * notice remains attached. + */ +#include "sys/param.h" +#include "sys/time.h" +#include "stdio.h" +#include "string.h" +#include "unistd.h" +#include "fcntl.h" +#include "alloca.h" +#include "tzfile.h" +#include "paths.h" + +char * +ctime(t) +time_t *t; +{ + struct tm *localtime(); + char *asctime(); + + return(asctime(localtime(t))); +} + +/* +** A la X3J11 +*/ + +char * +asctime(timeptr) +register struct tm * timeptr; +{ + static char wday_name[DAYS_PER_WEEK][3] = { + "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" + }; + static char mon_name[MONS_PER_YEAR][3] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" + }; + static char result[26]; + + (void) sprintf(result, "%.3s %.3s%3d %02d:%02d:%02d %d\n", + wday_name[timeptr->tm_wday], + mon_name[timeptr->tm_mon], + timeptr->tm_mday, timeptr->tm_hour, + timeptr->tm_min, timeptr->tm_sec, + TM_YEAR_BASE + timeptr->tm_year); + return result; +} + +#ifndef TRUE +#define TRUE 1 +#define FALSE 0 +#endif /* !TRUE */ + +extern char * getenv(); +extern char * strcpy(); +extern char * strcat(); +struct tm * offtime(); + +struct ttinfo { /* time type information */ + long tt_gmtoff; /* GMT offset in seconds */ + int tt_isdst; /* used to set tm_isdst */ + int tt_abbrind; /* abbreviation list index */ +}; + +struct state { + int timecnt; + int typecnt; + int charcnt; + time_t ats[TZ_MAX_TIMES]; + unsigned char types[TZ_MAX_TIMES]; + struct ttinfo ttis[TZ_MAX_TYPES]; + char chars[TZ_MAX_CHARS + 1]; +}; + +static struct state s; + +static int tz_is_set; + +char * tzname[2] = { + "GMT", + "GMT" +}; + +#ifdef USG_COMPAT +time_t timezone = 0; +int daylight = 0; +#endif /* USG_COMPAT */ + +static long +detzcode(codep) +char * codep; +{ + register long result; + register int i; + + result = 0; + for (i = 0; i < 4; ++i) + result = (result << 8) | (codep[i] & 0xff); + return result; +} + +static int +tzload(name) +register char * name; +{ + register int i; + register int fid; + + if (name == 0 && (name = _PATH_LOCALTIME) == 0) + return -1; + { + register char * p; + register int doaccess; + char * fullname; + + doaccess = name[0] == '/'; + if (!doaccess) { + if ((p = _PATH_ZONEINFO) == 0) + return -1; + if ((strlen(p) + strlen(name) + 1) >= MAXPATHLEN) + return -1; + fullname = alloca(MAXPATHLEN); + (void) strcpy(fullname, p); + (void) strcat(fullname, "/"); + (void) strcat(fullname, name); + /* + ** Set doaccess if '.' (as in "../") shows up in name. + */ + while (*name != '\0') + if (*name++ == '.') + doaccess = TRUE; + name = fullname; + } + if (doaccess && access(name, 4) != 0) + return -1; + if ((fid = open(name, 0)) == -1) + return -1; + } + { + register char * p; + register struct tzhead * tzhp; + char * buf; + + buf = alloca(sizeof s); + i = read(fid, buf, sizeof s); + if (close(fid) != 0 || i < sizeof *tzhp) + return -1; + tzhp = (struct tzhead *) buf; + s.timecnt = (int) detzcode(tzhp->tzh_timecnt); + s.typecnt = (int) detzcode(tzhp->tzh_typecnt); + s.charcnt = (int) detzcode(tzhp->tzh_charcnt); + if (s.timecnt > TZ_MAX_TIMES || + s.typecnt == 0 || + s.typecnt > TZ_MAX_TYPES || + s.charcnt > TZ_MAX_CHARS) + return -1; + if (i < sizeof *tzhp + + s.timecnt * (4 + sizeof (char)) + + s.typecnt * (4 + 2 * sizeof (char)) + + s.charcnt * sizeof (char)) + return -1; + p = buf + sizeof *tzhp; + for (i = 0; i < s.timecnt; ++i) { + s.ats[i] = detzcode(p); + p += 4; + } + for (i = 0; i < s.timecnt; ++i) + s.types[i] = (unsigned char) *p++; + for (i = 0; i < s.typecnt; ++i) { + register struct ttinfo * ttisp; + + ttisp = &s.ttis[i]; + ttisp->tt_gmtoff = detzcode(p); + p += 4; + ttisp->tt_isdst = (unsigned char) *p++; + ttisp->tt_abbrind = (unsigned char) *p++; + } + for (i = 0; i < s.charcnt; ++i) + s.chars[i] = *p++; + s.chars[i] = '\0'; /* ensure '\0' at end */ + } + /* + ** Check that all the local time type indices are valid. + */ + for (i = 0; i < s.timecnt; ++i) + if (s.types[i] >= s.typecnt) + return -1; + /* + ** Check that all abbreviation indices are valid. + */ + for (i = 0; i < s.typecnt; ++i) + if (s.ttis[i].tt_abbrind >= s.charcnt) + return -1; + /* + ** Set tzname elements to initial values. + */ + tzname[0] = tzname[1] = &s.chars[0]; +#ifdef USG_COMPAT + timezone = s.ttis[0].tt_gmtoff; + daylight = 0; +#endif /* USG_COMPAT */ + for (i = 1; i < s.typecnt; ++i) { + register struct ttinfo * ttisp; + + ttisp = &s.ttis[i]; + if (ttisp->tt_isdst) { + tzname[1] = &s.chars[ttisp->tt_abbrind]; +#ifdef USG_COMPAT + daylight = 1; +#endif /* USG_COMPAT */ + } else { + tzname[0] = &s.chars[ttisp->tt_abbrind]; +#ifdef USG_COMPAT + timezone = ttisp->tt_gmtoff; +#endif /* USG_COMPAT */ + } + } + return 0; +} + +static int +tzsetkernel() +{ + struct timeval tv; + struct timezone tz; + + if (gettimeofday(&tv, &tz)) + return -1; + s.timecnt = 0; /* UNIX counts *west* of Greenwich */ + s.ttis[0].tt_gmtoff = tz.tz_minuteswest * -SECS_PER_MIN; + s.ttis[0].tt_abbrind = 0; + (void)strcpy(s.chars, tztab(tz.tz_minuteswest, 0)); + tzname[0] = tzname[1] = s.chars; +#ifdef USG_COMPAT + timezone = tz.tz_minuteswest * 60; + daylight = tz.tz_dsttime; +#endif /* USG_COMPAT */ + return 0; +} + +static void +tzsetgmt() +{ + s.timecnt = 0; + s.ttis[0].tt_gmtoff = 0; + s.ttis[0].tt_abbrind = 0; + (void) strcpy(s.chars, "GMT"); + tzname[0] = tzname[1] = s.chars; +#ifdef USG_COMPAT + timezone = 0; + daylight = 0; +#endif /* USG_COMPAT */ +} + +void +tzset() +{ + register char * name; + + tz_is_set = TRUE; + name = getenv("TZ"); + if (!name || *name) { /* did not request GMT */ + if (name && !tzload(name)) /* requested name worked */ + return; + if (!tzload((char *)0)) /* default name worked */ + return; + if (!tzsetkernel()) /* kernel guess worked */ + return; + } + tzsetgmt(); /* GMT is default */ +} + +struct tm * +localtime(timep) +time_t * timep; +{ + register struct ttinfo * ttisp; + register struct tm * tmp; + register int i; + time_t t; + + if (!tz_is_set) + (void) tzset(); + t = *timep; + if (s.timecnt == 0 || t < s.ats[0]) { + i = 0; + while (s.ttis[i].tt_isdst) + if (++i >= s.timecnt) { + i = 0; + break; + } + } else { + for (i = 1; i < s.timecnt; ++i) + if (t < s.ats[i]) + break; + i = s.types[i - 1]; + } + ttisp = &s.ttis[i]; + /* + ** To get (wrong) behavior that's compatible with System V Release 2.0 + ** you'd replace the statement below with + ** tmp = offtime((time_t) (t + ttisp->tt_gmtoff), 0L); + */ + tmp = offtime(&t, ttisp->tt_gmtoff); + tmp->tm_isdst = ttisp->tt_isdst; + tzname[tmp->tm_isdst] = &s.chars[ttisp->tt_abbrind]; + tmp->tm_zone = &s.chars[ttisp->tt_abbrind]; + return tmp; +} + +struct tm * +gmtime(clock) +time_t * clock; +{ + register struct tm * tmp; + + tmp = offtime(clock, 0L); + tzname[0] = "GMT"; + tmp->tm_zone = "GMT"; /* UCT ? */ + return tmp; +} + +static int mon_lengths[2][MONS_PER_YEAR] = { + { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, + { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, +}; + +static int year_lengths[2] = { + DAYS_PER_NYEAR, DAYS_PER_LYEAR +}; + +struct tm * +offtime(clock, offset) +time_t * clock; +long offset; +{ + register struct tm * tmp; + register long days; + register long rem; + register int y; + register int yleap; + register int * ip; + static struct tm tm; + + tmp = &tm; + days = *clock / SECS_PER_DAY; + rem = *clock % SECS_PER_DAY; + rem += offset; + while (rem < 0) { + rem += SECS_PER_DAY; + --days; + } + while (rem >= SECS_PER_DAY) { + rem -= SECS_PER_DAY; + ++days; + } + tmp->tm_hour = (int) (rem / SECS_PER_HOUR); + rem = rem % SECS_PER_HOUR; + tmp->tm_min = (int) (rem / SECS_PER_MIN); + tmp->tm_sec = (int) (rem % SECS_PER_MIN); + tmp->tm_wday = (int) ((EPOCH_WDAY + days) % DAYS_PER_WEEK); + if (tmp->tm_wday < 0) + tmp->tm_wday += DAYS_PER_WEEK; + y = EPOCH_YEAR; + if (days >= 0) + for ( ; ; ) { + yleap = isleap(y); + if (days < (long) year_lengths[yleap]) + break; + ++y; + days = days - (long) year_lengths[yleap]; + } + else do { + --y; + yleap = isleap(y); + days = days + (long) year_lengths[yleap]; + } while (days < 0); + tmp->tm_year = y - TM_YEAR_BASE; + tmp->tm_yday = (int) days; + ip = mon_lengths[yleap]; + for (tmp->tm_mon = 0; days >= (long) ip[tmp->tm_mon]; ++(tmp->tm_mon)) + days = days - (long) ip[tmp->tm_mon]; + tmp->tm_mday = (int) (days + 1); + tmp->tm_isdst = 0; + tmp->tm_zone = ""; + tmp->tm_gmtoff = offset; + return tmp; +} diff --git a/src/libc/gen/ctype_.c b/src/libc/gen/ctype_.c new file mode 100644 index 0000000..66471ef --- /dev/null +++ b/src/libc/gen/ctype_.c @@ -0,0 +1,21 @@ +#include + +char _ctype_[1 + 256] = { + 0, + _C, _C, _C, _C, _C, _C, _C, _C, + _C, _C|_S, _C|_S, _C|_S, _C|_S, _C|_S, _C, _C, + _C, _C, _C, _C, _C, _C, _C, _C, + _C, _C, _C, _C, _C, _C, _C, _C, + _S|_B, _P, _P, _P, _P, _P, _P, _P, + _P, _P, _P, _P, _P, _P, _P, _P, + _N, _N, _N, _N, _N, _N, _N, _N, + _N, _N, _P, _P, _P, _P, _P, _P, + _P, _U|_X, _U|_X, _U|_X, _U|_X, _U|_X, _U|_X, _U, + _U, _U, _U, _U, _U, _U, _U, _U, + _U, _U, _U, _U, _U, _U, _U, _U, + _U, _U, _U, _P, _P, _P, _P, _P, + _P, _L|_X, _L|_X, _L|_X, _L|_X, _L|_X, _L|_X, _L, + _L, _L, _L, _L, _L, _L, _L, _L, + _L, _L, _L, _L, _L, _L, _L, _L, + _L, _L, _L, _P, _P, _P, _P, _C +}; diff --git a/src/libc/gen/daemon.c b/src/libc/gen/daemon.c new file mode 100644 index 0000000..1f376e8 --- /dev/null +++ b/src/libc/gen/daemon.c @@ -0,0 +1,69 @@ +/*- + * 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. + */ +#include +#include +#include +#include + +int +daemon(nochdir, noclose) + int nochdir, noclose; +{ + register int fd; + + switch (fork()) { + case -1: + return (-1); + case 0: + break; + default: + _exit(0); + } + + if ((fd = open(_PATH_TTY, O_RDWR)) >= 0) { + ioctl(fd, TIOCNOTTY, 0); + close(fd); + } + + if (!nochdir) + (void)chdir("/"); + + if (!noclose && (fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) { + (void)dup2(fd, 0); + (void)dup2(fd, 1); + (void)dup2(fd, 2); + if (fd > 2) + (void)close(fd); + } + return(0); +} diff --git a/src/libc/gen/devname.c b/src/libc/gen/devname.c new file mode 100644 index 0000000..2b57c4e --- /dev/null +++ b/src/libc/gen/devname.c @@ -0,0 +1,71 @@ +/* + * 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. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +char * +devname(dev, type) + dev_t dev; + mode_t type; +{ + DIR *dir; + struct direct *entry; + char filename[40]; + struct stat st; + + dir = opendir("/dev"); + if (dir == NULL) { + perror("/dev"); + return "??"; + } + strcpy(filename, "/dev/"); + while ((entry = readdir(dir)) != NULL) { + strcpy(filename+5, entry->d_name); + if (stat (filename, &st) < 0) + continue; + if (! S_ISCHR(st.st_mode) && ! S_ISBLK(st.st_mode)) + continue; + if (st.st_rdev == dev) { + closedir(dir); + return entry->d_name; + } + } + closedir(dir); + return "??"; +} diff --git a/src/libc/gen/ecvt.c b/src/libc/gen/ecvt.c new file mode 100644 index 0000000..8629c0e --- /dev/null +++ b/src/libc/gen/ecvt.c @@ -0,0 +1,104 @@ +/* + * ecvt converts to decimal + * the number of digits is specified by ndigit + * decpt is set to the position of the decimal point + * sign is set to 0 for positive, 1 for negative + */ +#include + +#define NDIG 80 + +static char * +cvt(arg, ndigits, decpt, sign, eflag) + double arg; + int ndigits, *decpt, *sign; +{ + register int r2; + double fi, fj; + register char *p, *p1; + static char buf[NDIG]; + double modf(); + + if (ndigits < 0) + ndigits = 0; + if (ndigits >= NDIG-1) + ndigits = NDIG-2; + r2 = 0; + *sign = 0; + p = &buf[0]; + if (arg < 0) { + *sign = 1; + arg = -arg; + } + arg = modf(arg, &fi); + p1 = &buf[NDIG]; + /* + * Do integer part + */ + if (fi != 0) { + p1 = &buf[NDIG]; + while (fi != 0) { + fj = modf(fi/10, &fi); + *--p1 = (int)((fj+.03)*10) + '0'; + r2++; + } + while (p1 < &buf[NDIG]) + *p++ = *p1++; + } else if (arg > 0) { + while ((fj = arg*10) < 1) { + arg = fj; + r2--; + } + } + p1 = &buf[ndigits]; + if (eflag == 0) + p1 += r2; + *decpt = r2; + if (p1 < &buf[0]) { + buf[0] = '\0'; + return(buf); + } + while (p <= p1 && p < &buf[NDIG]) { + arg *= 10; + arg = modf(arg, &fj); + *p++ = (int)fj + '0'; + } + if (p1 >= &buf[NDIG]) { + buf[NDIG-1] = '\0'; + return(buf); + } + p = p1; + *p1 += 5; + while (*p1 > '9') { + *p1 = '0'; + if (p1 > buf) + ++*--p1; + else { + *p1 = '1'; + (*decpt)++; + if (eflag == 0) { + if (p > buf) + *p = '0'; + p++; + } + } + } + *p = '\0'; + return(buf); +} + +char * +ecvt(arg, ndigits, decpt, sign) + double arg; + int ndigits, *decpt, *sign; +{ + return cvt(arg, ndigits, decpt, sign, 1); +} + +char * +fcvt(arg, ndigits, decpt, sign) + double arg; + int ndigits, *decpt, *sign; +{ + return cvt(arg, ndigits, decpt, sign, 0); +} diff --git a/src/libc/gen/err.c b/src/libc/gen/err.c new file mode 100644 index 0000000..9cc313c --- /dev/null +++ b/src/libc/gen/err.c @@ -0,0 +1,201 @@ +/*- + * 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. + */ +#include +#include +#include +#include +#include + +#ifdef __STDC__ +#include +#else +#include +#endif + +/* + * Helper routines. Repeated constructs of the form "%s: " used up too + * much D space. On a pdp-11 code can be overlaid but Data space is worth + * conserving. An extra function call or two handling an error condition is + * a reasonable trade for 20 or 30 bytes of D space. + */ +static void +putcolsp() +{ + fputc (':', stderr); + fputc (' ', stderr); +} + +static void +putprog() +{ + fputs (__progname, stderr); + putcolsp(); +} + +void +verr (eval, fmt, ap) + int eval; + const char *fmt; + va_list ap; +{ + int sverrno; + + sverrno = errno; + putprog(); + if (fmt != NULL) { + (void)vfprintf(stderr, fmt, ap); + putcolsp(); + } + (void)fputs(strerror(sverrno), stderr); + (void)fputc('\n', stderr); + exit(eval); +} + +void +#ifdef __STDC__ +err (int eval, const char *fmt, ...) +#else +err (eval, 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 + verr(eval, fmt, ap); + va_end(ap); +} + +void +verrx (eval, fmt, ap) + int eval; + const char *fmt; + va_list ap; +{ + putprog(); + if (fmt != NULL) + (void)vfprintf(stderr, fmt, ap); + (void)fputc('\n', stderr); + exit(eval); +} + +void +#if __STDC__ +errx (int eval, const char *fmt, ...) +#else +errx (eval, 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 + verrx(eval, fmt, ap); + va_end(ap); +} + +void +vwarn (fmt, ap) + const char *fmt; + va_list ap; +{ + int sverrno; + + sverrno = errno; + putprog(); + if (fmt != NULL) { + (void)vfprintf(stderr, fmt, ap); + putcolsp(); + } + (void)fputs(strerror(sverrno), stderr); + (void)fputc('\n', stderr); +} + +void +#if __STDC__ +warn (const char *fmt, ...) +#else +warn(fmt, va_alist) + 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); +} + +void +vwarnx (fmt, ap) + const char *fmt; + va_list ap; +{ + putprog(); + if (fmt != NULL) + (void)vfprintf(stderr, fmt, ap); + (void)fputc('\n', stderr); +} + +void +#ifdef __STDC__ +warnx (const char *fmt, ...) +#else +warnx(fmt, va_alist) + char *fmt; + va_dcl +#endif +{ + va_list ap; +#ifdef __STDC__ + va_start(ap, fmt); +#else + va_start(ap); +#endif + vwarnx(fmt, ap); + va_end(ap); +} diff --git a/src/libc/gen/execvp.c b/src/libc/gen/execvp.c new file mode 100644 index 0000000..adc120c --- /dev/null +++ b/src/libc/gen/execvp.c @@ -0,0 +1,88 @@ +/* + * execlp(name, arg,...,0) (like execl, but does path search) + * execvp(name, argv) (like execv, but does path search) + */ +#include +#include +#include +#include +#include + +static char shell[] = "/bin/sh"; + +int +execlp(name, argv) + const char *name, *argv; +{ + return execvp (name, (char * const*) &argv); +} + +static char * +execat(s1, s2, si) + register char *s1, *s2; + char *si; +{ + register char *s; + + s = si; + while (*s1 && *s1 != ':') + *s++ = *s1++; + if (si != s) + *s++ = '/'; + while (*s2) + *s++ = *s2++; + *s = '\0'; + return(*s1? ++s1: 0); +} + +int +execvp(name, argv) + const char *name; + char *const *argv; +{ + char *pathstr; + register char *cp; + char fname[128]; + char *newargs[256]; + int i; + register unsigned etxtbsy = 1; + register int eacces = 0; + + pathstr = getenv("PATH"); + if (! pathstr) + pathstr = _PATH_STDPATH; + cp = strchr(name, '/') ? "" : pathstr; + + do { + cp = execat(cp, name, fname); + retry: + execv(fname, argv); + switch(errno) { + case ENOEXEC: + newargs[0] = "sh"; + newargs[1] = fname; + for (i=1; (newargs[i+1] = argv[i]); i++) { + if (i>=254) { + errno = E2BIG; + return(-1); + } + } + execv(shell, newargs); + return(-1); + case ETXTBSY: + if (++etxtbsy > 5) + return(-1); + sleep(etxtbsy); + goto retry; + case EACCES: + eacces++; + break; + case ENOMEM: + case E2BIG: + return(-1); + } + } while (cp); + if (eacces) + errno = EACCES; + return(-1); +} diff --git a/src/libc/gen/fabs.c b/src/libc/gen/fabs.c new file mode 100644 index 0000000..e384dca --- /dev/null +++ b/src/libc/gen/fabs.c @@ -0,0 +1,11 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +double +fabs(arg) + double arg; +{ + return(arg < 0 ? -arg : arg); +} diff --git a/src/libc/gen/fakcu.c b/src/libc/gen/fakcu.c new file mode 100644 index 0000000..c8437b9 --- /dev/null +++ b/src/libc/gen/fakcu.c @@ -0,0 +1,7 @@ +/* + * Null cleanup routine to resolve reference in exit() + * if not using stdio. + */ +void __attribute__((weak)) _cleanup() +{ +} diff --git a/src/libc/gen/ffs-disabled.c b/src/libc/gen/ffs-disabled.c new file mode 100644 index 0000000..348ea66 --- /dev/null +++ b/src/libc/gen/ffs-disabled.c @@ -0,0 +1,20 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +/* + * ffs -- vax ffs instruction + */ +ffs(mask) + register long mask; +{ + register int cnt; + + if (mask == 0) + return(0); + for (cnt = 1; !(mask&1); cnt++) + mask >>= 1; + return(cnt); +} diff --git a/src/libc/gen/frexp.c b/src/libc/gen/frexp.c new file mode 100644 index 0000000..3cc8a03 --- /dev/null +++ b/src/libc/gen/frexp.c @@ -0,0 +1,40 @@ +/* + * the call + * x = frexp(arg,&exp); + * must return a double fp quantity x which is <1.0 + * and the corresponding binary exponent "exp". + * such that + * arg = x*2^exp + * if the argument is 0.0, return 0.0 mantissa and 0 exponent. + */ +#include + +double +frexp(x, i) + double x; + int *i; +{ + int neg; + int j; + + j = 0; + neg = 0; + if (x < 0) { + x = -x; + neg = 1; + } + if (x >= 1.0) + while (x >= 1.0) { + j = j+1; + x = x/2; + } + else if (x < 0.5 && x != 0.0) + while (x < 0.5) { + j = j-1; + x = 2*x; + } + *i = j; + if (neg) + x = -x; + return(x); +} diff --git a/src/libc/gen/fstab.c b/src/libc/gen/fstab.c new file mode 100644 index 0000000..306872c --- /dev/null +++ b/src/libc/gen/fstab.c @@ -0,0 +1,209 @@ +/* + * 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. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +static FILE *_fs_fp; +static struct fstab _fs_fstab; + +static void error(); +static int fstabscan(); + +static int +fstabscan() +{ + char *cp; + register char *bp; +#define MAXLINELENGTH 256 + static char line[MAXLINELENGTH]; + char subline[MAXLINELENGTH], *colon = ":"; + int typexx; + + for (;;) { + if (!fgets(line, sizeof(line), _fs_fp)) + return(0); + bp = index(line, '\n'); + if (!bp) + return(0); + *bp = '\0'; + cp = line; +/* OLD_STYLE_FSTAB */ + if (!strpbrk(cp, " \t")) { + _fs_fstab.fs_spec = strsep(&cp, colon); + _fs_fstab.fs_file = strsep(&cp, colon); + _fs_fstab.fs_type = strsep(&cp, colon); + if (_fs_fstab.fs_type) { + if (!strcmp(_fs_fstab.fs_type, FSTAB_XX)) + continue; + _fs_fstab.fs_mntops = _fs_fstab.fs_type; + _fs_fstab.fs_vfstype = + strcmp(_fs_fstab.fs_type, FSTAB_SW) ? + "ufs" : "swap"; + bp = strsep(&cp, colon); + if (bp) { + _fs_fstab.fs_freq = atoi(bp); + bp = strsep(&cp, colon); + if (bp) { + _fs_fstab.fs_passno = atoi(bp); + return(1); + } + } + } + goto bad; + } +/* OLD_STYLE_FSTAB */ + _fs_fstab.fs_spec = strtok(cp, " \t"); + if (!_fs_fstab.fs_spec || *_fs_fstab.fs_spec == '#') + continue; + _fs_fstab.fs_file = strtok((char *)NULL, " \t"); + _fs_fstab.fs_vfstype = strtok((char *)NULL, " \t"); + _fs_fstab.fs_mntops = strtok((char *)NULL, " \t"); + if (_fs_fstab.fs_mntops == NULL) + goto bad; + _fs_fstab.fs_freq = 0; + _fs_fstab.fs_passno = 0; + if ((cp = strtok((char *)NULL, " \t")) != NULL) { + _fs_fstab.fs_freq = atoi(cp); + if ((cp = strtok((char *)NULL, " \t")) != NULL) + _fs_fstab.fs_passno = atoi(cp); + } + strcpy(subline, _fs_fstab.fs_mntops); + for (typexx = 0, cp = strtok(subline, ","); cp; + cp = strtok((char *)NULL, ",")) { + if (strlen(cp) != 2) + continue; + if (!strcmp(cp, FSTAB_RW)) { + _fs_fstab.fs_type = FSTAB_RW; + break; + } + if (!strcmp(cp, FSTAB_RQ)) { + _fs_fstab.fs_type = FSTAB_RQ; + break; + } + if (!strcmp(cp, FSTAB_RO)) { + _fs_fstab.fs_type = FSTAB_RO; + break; + } + if (!strcmp(cp, FSTAB_SW)) { + _fs_fstab.fs_type = FSTAB_SW; + break; + } + if (!strcmp(cp, FSTAB_XX)) { + _fs_fstab.fs_type = FSTAB_XX; + typexx++; + break; + } + } + if (typexx) + continue; + if (cp != NULL) + return(1); + +bad: /* no way to distinguish between EOF and syntax error */ + error(EFTYPE); + } + /* NOTREACHED */ +} + +struct fstab * +getfsent() +{ + if (! _fs_fp && ! setfsent()) + return 0; + if (! fstabscan()) + return 0; + return &_fs_fstab; +} + +struct fstab * +getfsspec(name) + register char *name; +{ + if (setfsent()) + while (fstabscan()) + if (!strcmp(_fs_fstab.fs_spec, name)) + return(&_fs_fstab); + return((struct fstab *)NULL); +} + +struct fstab * +getfsfile(name) + register char *name; +{ + if (setfsent()) + while (fstabscan()) + if (!strcmp(_fs_fstab.fs_file, name)) + return(&_fs_fstab); + return((struct fstab *)NULL); +} + +int +setfsent() +{ + if (_fs_fp) { + rewind(_fs_fp); + return(1); + } + _fs_fp = fopen(_PATH_FSTAB, "r"); + if (_fs_fp) + return(1); + error(errno); + return(0); +} + +void +endfsent() +{ + if (_fs_fp) { + (void)fclose(_fs_fp); + _fs_fp = NULL; + } +} + +static void +error(err) + int err; +{ + register int saverrno; + + saverrno = errno; + errno = err; + warn("%s", _PATH_FSTAB); + errno = saverrno; +} diff --git a/src/libc/gen/gcvt.c b/src/libc/gen/gcvt.c new file mode 100644 index 0000000..6ed0148 --- /dev/null +++ b/src/libc/gen/gcvt.c @@ -0,0 +1,61 @@ +/* + * gcvt - Floating output conversion to + * minimal length string + */ +#include + +char * +gcvt(number, ndigit, buf) +double number; +char *buf; +{ + int sign, decpt; + register char *p1, *p2; + register int i; + + p1 = ecvt(number, ndigit, &decpt, &sign); + p2 = buf; + if (sign) + *p2++ = '-'; + for (i=ndigit-1; i>0 && p1[i]=='0'; i--) + ndigit--; + if ((decpt >= 0 && decpt-ndigit > 4) || + (decpt < 0 && decpt < -3)) { /* use E-style */ + decpt--; + *p2++ = *p1++; + *p2++ = '.'; + for (i=1; i +#include +#include +#include + +/* + * getenv(name) -- + * Returns ptr to value associated with name, if any, else NULL. + */ +char * +getenv(name) + char *name; +{ + int offset; + char *_findenv(); + + return(_findenv(name,&offset)); +} + +/* + * _findenv(name,offset) -- + * Returns pointer to value associated with name, if any, else NULL. + * Sets offset to be the offset of the name/value combination in the + * environmental array, for use by setenv(3) and unsetenv(3). + * Explicitly removes '=' in argument name. + * + * This routine *should* be a static; don't use it. + */ +char * +_findenv(name, offset) + register const char *name; + int *offset; +{ + register int len; + register char **P, *C; + register const char *E; + + len = 0; + for (E = name; *E && *E != '='; ++E) + ++len; + for (P = environ; *P; ++P) + if (!strncmp(*P, name, len)) + if (*(C = *P + len) == '=') { + *offset = P - environ; + return(++C); + } + return(NULL); +} diff --git a/src/libc/gen/getgrent.c b/src/libc/gen/getgrent.c new file mode 100644 index 0000000..c5571e1 --- /dev/null +++ b/src/libc/gen/getgrent.c @@ -0,0 +1,64 @@ +#include +#include +#include + +#define MAXGRP 200 + +static char GROUP[] = "/etc/group"; +static FILE *grf = NULL; +static char line[256+1]; +static struct group group; +static char *gr_mem[MAXGRP]; + +void +setgrent() +{ + if (!grf) + grf = fopen(GROUP, "r"); + else + rewind(grf); +} + +void +endgrent() +{ + if (grf) { + fclose(grf); + grf = NULL; + } +} + +static char * +grskip(p,c) + register char *p; + register int c; +{ + while(*p && *p != c) ++p; + if (*p) *p++ = 0; + return(p); +} + +struct group * +getgrent() +{ + register char *p, **q; + + if (!grf && !(grf = fopen(GROUP, "r"))) + return(NULL); + if (!(p = fgets(line, sizeof(line)-1, grf))) + return(NULL); + group.gr_name = p; + group.gr_passwd = p = grskip(p,':'); + group.gr_gid = atoi(p = grskip(p,':')); + group.gr_mem = gr_mem; + p = grskip(p,':'); + grskip(p,'\n'); + q = gr_mem; + while (*p) { + if (q < &gr_mem[MAXGRP-1]) + *q++ = p; + p = grskip(p,','); + } + *q = NULL; + return(&group); +} diff --git a/src/libc/gen/getgrgid.c b/src/libc/gen/getgrgid.c new file mode 100644 index 0000000..7b3f204 --- /dev/null +++ b/src/libc/gen/getgrgid.c @@ -0,0 +1,14 @@ +#include +#include + +struct group * +getgrgid(gid) + register gid_t gid; +{ + register struct group *p; + + setgrent(); + while ((p = getgrent()) && p->gr_gid != gid); + endgrent(); + return(p); +} diff --git a/src/libc/gen/getgrnam.c b/src/libc/gen/getgrnam.c new file mode 100644 index 0000000..1a492a6 --- /dev/null +++ b/src/libc/gen/getgrnam.c @@ -0,0 +1,15 @@ +#include +#include +#include + +struct group * +getgrnam(name) + register const char *name; +{ + register struct group *p; + + setgrent(); + while ((p = getgrent()) && strcmp(p->gr_name, name)); + endgrent(); + return(p); +} diff --git a/src/libc/gen/getgrouplist.c b/src/libc/gen/getgrouplist.c new file mode 100644 index 0000000..97e483c --- /dev/null +++ b/src/libc/gen/getgrouplist.c @@ -0,0 +1,83 @@ +/* + * 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. + */ + +/* + * get credential + */ +#include +#include +#include + +int +getgrouplist(uname, agroup, groups, grpcnt) + char *uname; + gid_t agroup; + register gid_t *groups; + int *grpcnt; +{ + register struct group *grp; + int i, ngroups, ret, maxgroups; + + ret = 0; + ngroups = 0; + maxgroups = *grpcnt; + /* + * When installing primary group, duplicate it; + * the first element of groups is the effective gid + * and will be overwritten when a setgid file is executed. + */ + groups[ngroups++] = agroup; + if (maxgroups > 1) + groups[ngroups++] = agroup; + /* + * Scan the group file to find additional groups. + */ + setgrent(); + while ((grp = getgrent())) { + if (grp->gr_gid == agroup) + continue; + for (i = 0; grp->gr_mem[i]; i++) { + if (!strcmp(grp->gr_mem[i], uname)) { + if (ngroups >= maxgroups) { + ret = -1; + break; + } + groups[ngroups++] = grp->gr_gid; + break; + } + } + } + endgrent(); + *grpcnt = ngroups; + return (ret); +} diff --git a/src/libc/gen/gethostname.c b/src/libc/gen/gethostname.c new file mode 100644 index 0000000..e6c804c --- /dev/null +++ b/src/libc/gen/gethostname.c @@ -0,0 +1,50 @@ +/* + * 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. + */ +#include +#include + +int +gethostname(name, namelen) + char *name; + int namelen; +{ + int mib[2]; + size_t size; + + mib[0] = CTL_KERN; + mib[1] = KERN_HOSTNAME; + size = namelen; + if (sysctl(mib, 2, name, &size, NULL, 0) == -1) + return (-1); + return (0); +} diff --git a/src/libc/gen/getloadavg.c b/src/libc/gen/getloadavg.c new file mode 100644 index 0000000..111284f --- /dev/null +++ b/src/libc/gen/getloadavg.c @@ -0,0 +1,63 @@ +/*- + * 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. + */ +#include +#include +#include + +/* + * getloadavg() -- Get system load averages. + * + * Put `nelem' samples into `loadavg' array. + * Return number of samples retrieved, or -1 on error. + */ +int +getloadavg(loadavg, nelem) + unsigned loadavg[]; + register int nelem; +{ + struct loadavg loadinfo; + register int i; + int mib[2]; + size_t size; + + mib[0] = CTL_VM; + mib[1] = VM_LOADAVG; + size = sizeof(loadinfo); + if (sysctl(mib, 2, &loadinfo, &size, NULL, 0) < 0) + return (-1); + + nelem = MIN(nelem, sizeof(loadinfo.ldavg) / sizeof(short)); + for (i = 0; i < nelem; i++) + loadavg[i] = 100 * loadinfo.ldavg[i] / loadinfo.fscale; + return (nelem); +} diff --git a/src/libc/gen/getlogin.c b/src/libc/gen/getlogin.c new file mode 100644 index 0000000..0b73b44 --- /dev/null +++ b/src/libc/gen/getlogin.c @@ -0,0 +1,46 @@ +/* + * 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. + */ +#include + +char * +getlogin() +{ + return 0; +} + +int +setlogin (name) + const char *name; +{ + return 0; +} diff --git a/src/libc/gen/getmntinfo.c b/src/libc/gen/getmntinfo.c new file mode 100644 index 0000000..fdd335e --- /dev/null +++ b/src/libc/gen/getmntinfo.c @@ -0,0 +1,64 @@ +/* + * 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. + */ +#include +#include +#include + +/* + * Return information about mounted filesystems. + */ +int +getmntinfo(mntbufp, flags) + register struct statfs **mntbufp; + int flags; +{ + static struct statfs *mntbuf; + static int mntsize; + static int bufsize; + + if (mntsize <= 0 && (mntsize = getfsstat(0, 0, MNT_NOWAIT)) < 0) + return (0); + if (bufsize > 0 && (mntsize = getfsstat(mntbuf, bufsize, flags)) < 0) + return (0); + while (bufsize <= mntsize * sizeof(struct statfs)) { + if (mntbuf) + free(mntbuf); + bufsize = (mntsize + 1) * sizeof(struct statfs); + if ((mntbuf = (struct statfs *)malloc(bufsize)) == 0) + return (0); + if ((mntsize = getfsstat(mntbuf, bufsize, flags)) < 0) + return (0); + } + *mntbufp = mntbuf; + return (mntsize); +} diff --git a/src/libc/gen/getpagesize.c b/src/libc/gen/getpagesize.c new file mode 100644 index 0000000..c7b5925 --- /dev/null +++ b/src/libc/gen/getpagesize.c @@ -0,0 +1,48 @@ +/* + * 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. + */ +#include +#include + +int +getpagesize() +{ + size_t size; + int mib[2], value; + + mib[0] = CTL_HW; + mib[1] = HW_PAGESIZE; + size = sizeof(value); + if (sysctl(mib, 2, &value, &size, NULL, 0) == -1) + return (-1); + return (value); +} diff --git a/src/libc/gen/getpass.c b/src/libc/gen/getpass.c new file mode 100644 index 0000000..389deb4 --- /dev/null +++ b/src/libc/gen/getpass.c @@ -0,0 +1,41 @@ +#include +#include +#include +#include + +char * +getpass(prompt) +char *prompt; +{ + struct sgttyb ttyb; + int flags; + register char *p; + register int c; + FILE *fi; + static char pbuf[9]; + sig_t sig; + + fi = fdopen(open("/dev/tty", 2), "r"); + if (! fi) + fi = stdin; + else + setbuf(fi, (char *)NULL); + sig = signal(SIGINT, SIG_IGN); + ioctl(fileno(fi), TIOCGETP, &ttyb); + flags = ttyb.sg_flags; + ttyb.sg_flags &= ~ECHO; + ioctl(fileno(fi), TIOCSETP, &ttyb); + fprintf(stderr, "%s", prompt); fflush(stderr); + for (p=pbuf; (c = getc(fi))!='\n' && c!=EOF;) { + if (p < &pbuf[8]) + *p++ = c; + } + *p = '\0'; + fprintf(stderr, "\n"); fflush(stderr); + ttyb.sg_flags = flags; + ioctl(fileno(fi), TIOCSETP, &ttyb); + signal(SIGINT, sig); + if (fi != stdin) + fclose(fi); + return(pbuf); +} diff --git a/src/libc/gen/getpwent.c b/src/libc/gen/getpwent.c new file mode 100644 index 0000000..a4b5420 --- /dev/null +++ b/src/libc/gen/getpwent.c @@ -0,0 +1,208 @@ +/* + * Copyright (c) 1988 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static FILE *_pw_fp; +static struct passwd _pw_entry; +static int _pw_stayopen; +static char *_pw_file = _PATH_PASSWD; + +#define MAXLINELENGTH 256 +static char line[MAXLINELENGTH]; + +static int +start_pw() +{ + if (_pw_fp) { + rewind(_pw_fp); + return(1); + } + _pw_fp = fopen(_pw_file, "r"); + if (_pw_fp) + return(1); + return(0); +} + +static int +scanpw() +{ + register char *cp; + char *bp; + register int ch; + + for (;;) { + if (!(fgets(line, sizeof(line), _pw_fp))) + return(0); + /* skip lines that are too big */ + cp = strchr(line, '\n'); + if (! cp) { + while ((ch = fgetc(_pw_fp)) != '\n' && ch != EOF) + ; + continue; + } + *cp = '\0'; + bp = line; + _pw_entry.pw_name = strsep(&bp, ":"); + _pw_entry.pw_passwd = strsep(&bp, ":"); + cp = strsep(&bp, ":"); + if (! cp) + continue; + _pw_entry.pw_uid = atoi(cp); + cp = strsep(&bp, ":"); + if (! cp) + continue; + _pw_entry.pw_gid = atoi(cp); + _pw_entry.pw_gecos = strsep(&bp, ":"); + _pw_entry.pw_dir = strsep(&bp, ":"); + _pw_entry.pw_shell = strsep(&bp, ":"); + if (!_pw_entry.pw_shell) + continue; + return(1); + } + /* NOTREACHED */ +} + +static void +getpw() +{ + static char pwbuf[50]; + off_t lseek(); + long pos; + int fd, n; + register char *p; + + if (geteuid()) + return; + /* + * special case; if it's the official password file, look in + * the master password file, otherwise, look in the file itself. + */ + p = strcmp(_pw_file, _PATH_PASSWD) == 0 ? _PATH_SHADOW : _pw_file; + if ((fd = open(p, O_RDONLY, 0)) < 0) + return; + pos = atol(_pw_entry.pw_passwd); + if (lseek(fd, pos, L_SET) != pos) + goto bad; + if ((n = read(fd, pwbuf, sizeof(pwbuf) - 1)) < 0) + goto bad; + pwbuf[n] = '\0'; + for (p = pwbuf; *p; ++p) + if (*p == ':') { + *p = '\0'; + _pw_entry.pw_passwd = pwbuf; + break; + } +bad: (void)close(fd); +} + +struct passwd * +getpwent() +{ + register int rval; + + if (!_pw_fp && !start_pw()) + return((struct passwd *)NULL); + rval = scanpw(); + if (! rval) + return 0; + getpw(); + return &_pw_entry; +} + +struct passwd * +getpwnam(nam) + char *nam; +{ + register int rval; + + if (!start_pw()) + return((struct passwd *)NULL); + for (rval = 0; scanpw();) { + if (!strcmp(nam, _pw_entry.pw_name)) { + rval = 1; + break; + } + } + if (!_pw_stayopen) + endpwent(); + if (! rval) + return 0; + getpw(); + return &_pw_entry; +} + +struct passwd * +getpwuid(uid) + int uid; +{ + register int rval; + + if (!start_pw()) + return((struct passwd *)NULL); + for (rval = 0; scanpw();) { + if (_pw_entry.pw_uid == uid) { + rval = 1; + break; + } + } + if (!_pw_stayopen) + endpwent(); + if (! rval) + return 0; + getpw(); + return &_pw_entry; +} + +int +setpwent() +{ + return(setpassent(0)); +} + +int +setpassent(stayopen) + int stayopen; +{ + if (!start_pw()) + return(0); + _pw_stayopen = stayopen; + return(1); +} + +void +endpwent() +{ + if (_pw_fp) { + (void)fclose(_pw_fp); + _pw_fp = 0; + } +} + +void +setpwfile(file) + char *file; +{ + _pw_file = file; +} diff --git a/src/libc/gen/getttyent.c b/src/libc/gen/getttyent.c new file mode 100644 index 0000000..a70f01f --- /dev/null +++ b/src/libc/gen/getttyent.c @@ -0,0 +1,136 @@ +/* + * Copyright (c) 1985 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include +#include +#include +#include + +static char TTYFILE[] = "/etc/ttys"; +static int zapchar; +static FILE *tf = NULL; +#define LINE 256 +static char line[LINE]; +static struct ttyent tty; + +void +setttyent() +{ + if (tf == NULL) + tf = fopen(TTYFILE, "r"); + else + rewind(tf); +} + +void +endttyent() +{ + if (tf != NULL) { + (void) fclose(tf); + tf = NULL; + } +} + +#define QUOTED 1 + +/* + * Skip over the current field, removing quotes, + * and return a pointer to the next field. + */ +static char * +skip(p) + register char *p; +{ + register char *t = p; + register int c; + register int q = 0; + + for (; (c = *p) != '\0'; p++) { + if (c == '"') { + q ^= QUOTED; /* obscure, but nice */ + continue; + } + if (q == QUOTED && *p == '\\' && *(p+1) == '"') + p++; + *t++ = *p; + if (q == QUOTED) + continue; + if (c == '#') { + zapchar = c; + *p = 0; + break; + } + if (c == '\t' || c == ' ' || c == '\n') { + zapchar = c; + *p++ = 0; + while ((c = *p) == '\t' || c == ' ' || c == '\n') + p++; + break; + } + } + *--t = '\0'; + return (p); +} + +static char * +value(p) + register char *p; +{ + if ((p = index(p,'=')) == 0) + return(NULL); + p++; /* get past the = sign */ + return(p); +} + +struct ttyent * +getttyent() +{ + register char *p; + register int c; + + if (tf == NULL) { + if ((tf = fopen(TTYFILE, "r")) == NULL) + return (NULL); + } + do { + p = fgets(line, LINE, tf); + if (p == NULL) + return (NULL); + while ((c = *p) == '\t' || c == ' ' || c == '\n') + p++; + } while (c == '\0' || c == '#'); + zapchar = 0; + tty.ty_name = p; + p = skip(p); + tty.ty_getty = p; + p = skip(p); + tty.ty_type = p; + p = skip(p); + tty.ty_status = 0; + tty.ty_window = NULL; + for (; *p; p = skip(p)) { +#define space(x) ((c = p[x]) == ' ' || c == '\t' || c == '\n') + if (strncmp(p, "on", 2) == 0 && space(2)) + tty.ty_status |= TTY_ON; + else if (strncmp(p, "off", 3) == 0 && space(3)) + tty.ty_status &= ~TTY_ON; + else if (strncmp(p, "secure", 6) == 0 && space(6)) + tty.ty_status |= TTY_SECURE; + else if (strncmp(p, "window=", 7) == 0) + tty.ty_window = value(p); + else + break; + } + if (zapchar == '#' || *p == '#') + while ((c = *++p) == ' ' || c == '\t') + ; + tty.ty_comment = p; + if (*p == 0) + tty.ty_comment = 0; + p = index(p, '\n'); + if (p) + *p = '\0'; + return(&tty); +} diff --git a/src/libc/gen/getttynam.c b/src/libc/gen/getttynam.c new file mode 100644 index 0000000..f98e64d --- /dev/null +++ b/src/libc/gen/getttynam.c @@ -0,0 +1,22 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include +#include + +struct ttyent * +getttynam(tty) + const char *tty; +{ + register struct ttyent *t; + + setttyent(); + while ((t = getttyent())) { + if (strcmp(tty, t->ty_name) == 0) + break; + } + endttyent(); + return (t); +} diff --git a/src/libc/gen/getusershell.c b/src/libc/gen/getusershell.c new file mode 100644 index 0000000..09edff4 --- /dev/null +++ b/src/libc/gen/getusershell.c @@ -0,0 +1,115 @@ +/* + * Copyright (c) 1985 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. + */ +#include +#include +#include +#include +#include +#include +#include + +#define SHELLS "/etc/shells" + +/* + * Do not add local shells here. They should be added in /etc/shells + */ +static char *okshells[] = + { "/bin/sh", "/bin/csh", 0 }; + +static char **shells, *strings; +static char **curshell = NULL; + +static char ** +initshells() +{ + register char **sp, *cp; + register FILE *fp; + struct stat statb; + + if (shells != NULL) + free((char *)shells); + shells = NULL; + if (strings != NULL) + free(strings); + strings = NULL; + if ((fp = fopen(SHELLS, "r")) == (FILE *)0) + return(okshells); + if (fstat(fileno(fp), &statb) == -1) { + (void)fclose(fp); + return(okshells); + } + if ((strings = malloc((unsigned)statb.st_size)) == NULL) { + (void)fclose(fp); + return(okshells); + } + shells = (char **)calloc((unsigned)statb.st_size / 3, sizeof (char *)); + if (shells == NULL) { + (void)fclose(fp); + free(strings); + strings = NULL; + return(okshells); + } + sp = shells; + cp = strings; + while (fgets(cp, MAXPATHLEN + 1, fp) != NULL) { + while (*cp != '#' && *cp != '/' && *cp != '\0') + cp++; + if (*cp == '#' || *cp == '\0') + continue; + *sp++ = cp; + while (!isspace(*cp) && *cp != '#' && *cp != '\0') + cp++; + *cp++ = '\0'; + } + *sp = (char *)0; + (void)fclose(fp); + return (shells); +} + +/* + * Get a list of shells from SHELLS, if it exists. + */ +char * +getusershell() +{ + char *ret; + + if (curshell == NULL) + curshell = initshells(); + ret = *curshell; + if (ret != NULL) + curshell++; + return (ret); +} + +void +endusershell() +{ + if (shells != NULL) + free((char *)shells); + shells = NULL; + if (strings != NULL) + free(strings); + strings = NULL; + curshell = NULL; +} + +void +setusershell() +{ + curshell = initshells(); +} diff --git a/src/libc/gen/getwd.c b/src/libc/gen/getwd.c new file mode 100644 index 0000000..1ced912 --- /dev/null +++ b/src/libc/gen/getwd.c @@ -0,0 +1,110 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +/* + * getwd() returns the pathname of the current working directory. On error + * an error message is copied to pathname and null pointer is returned. + */ +#include +#include +#include +#include +#include + +#define GETWDERR(s) strcpy(pathname, (s)); + +static int pathsize; /* pathname length */ + +/* + * prepend() tacks a directory name onto the front of a pathname. + */ +static char * +prepend(dirname, pathname) + register char *dirname; + register char *pathname; +{ + register int i; /* directory name size counter */ + + for (i = 0; *dirname != '\0'; i++, dirname++) + continue; + if ((pathsize += i) < MAXPATHLEN) + while (i-- > 0) + *--pathname = *--dirname; + return (pathname); +} + +char * +getwd(pathname) + char *pathname; +{ + char pathbuf[MAXPATHLEN]; /* temporary pathname buffer */ + char *pnptr = &pathbuf[(sizeof pathbuf)-1]; /* pathname pointer */ + char curdir[MAXPATHLEN]; /* current directory buffer */ + char *dptr = curdir; /* directory pointer */ + dev_t cdev, rdev; /* current & root device number */ + ino_t cino, rino; /* current & root inode number */ + DIR *dirp; /* directory stream */ + struct direct *dir; /* directory entry struct */ + struct stat d, dd; /* file status struct */ + + pathsize = 0; + *pnptr = '\0'; + if (stat("/", &d) < 0) { + GETWDERR("getwd: can't stat /"); + return (NULL); + } + rdev = d.st_dev; + rino = d.st_ino; + strcpy(dptr, "./"); + dptr += 2; + if (stat(curdir, &d) < 0) { + GETWDERR("getwd: can't stat ."); + return (NULL); + } + for (;;) { + if (d.st_ino == rino && d.st_dev == rdev) + break; /* reached root directory */ + cino = d.st_ino; + cdev = d.st_dev; + strcpy(dptr, "../"); + dptr += 3; + if ((dirp = opendir(curdir)) == NULL) { + GETWDERR("getwd: can't open .."); + return (NULL); + } + fstat(dirp->dd_fd, &d); + if (cdev == d.st_dev) { + if (cino == d.st_ino) { + /* reached root directory */ + closedir(dirp); + break; + } + do { + if ((dir = readdir(dirp)) == NULL) { + closedir(dirp); + GETWDERR("getwd: read error in .."); + return (NULL); + } + } while (dir->d_ino != cino); + } else + do { + if ((dir = readdir(dirp)) == NULL) { + closedir(dirp); + GETWDERR("getwd: read error in .."); + return (NULL); + } + strcpy(dptr, dir->d_name); + lstat(curdir, &dd); + } while(dd.st_ino != cino || dd.st_dev != cdev); + closedir(dirp); + pnptr = prepend("/", prepend(dir->d_name, pnptr)); + } + if (*pnptr == '\0') /* current dir == root dir */ + strcpy(pathname, "/"); + else + strcpy(pathname, pnptr); + return (pathname); +} diff --git a/src/libc/gen/index-disabled.c b/src/libc/gen/index-disabled.c new file mode 100644 index 0000000..f525edb --- /dev/null +++ b/src/libc/gen/index-disabled.c @@ -0,0 +1,17 @@ +/* + * Return the ptr in sp at which the character c appears; + * NULL if not found + */ + +#define NULL 0 + +char * +index(sp, c) +register char *sp, c; +{ + do { + if (*sp == c) + return(sp); + } while (*sp++); + return(NULL); +} diff --git a/src/libc/gen/initgroups.c b/src/libc/gen/initgroups.c new file mode 100644 index 0000000..02caea4 --- /dev/null +++ b/src/libc/gen/initgroups.c @@ -0,0 +1,46 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +/* + * initgroups + */ +#include +#include +#include +#include + +int +initgroups(uname, agroup) + char *uname; + int agroup; +{ + gid_t groups[NGROUPS]; + register struct group *grp; + register int i, ngroups = 0; + + if (agroup >= 0) + groups[ngroups++] = agroup; + setgrent(); + while ((grp = getgrent())) { + if (grp->gr_gid == agroup) + continue; + for (i = 0; grp->gr_mem[i]; i++) + if (!strcmp(grp->gr_mem[i], uname)) { + if (ngroups == NGROUPS) { +fprintf(stderr, "initgroups: %s is in too many groups\n", uname); + goto toomany; + } + groups[ngroups++] = grp->gr_gid; + } + } +toomany: + endgrent(); + if (setgroups(ngroups, groups) < 0) { + perror("setgroups"); + return (-1); + } + return (0); +} diff --git a/src/libc/gen/insque.c b/src/libc/gen/insque.c new file mode 100644 index 0000000..d496f08 --- /dev/null +++ b/src/libc/gen/insque.c @@ -0,0 +1,25 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +/* + * insque -- vax insque instruction + * + * NOTE: this implementation is non-atomic!! + */ + +struct vaxque { /* queue format expected by VAX queue instructions */ + struct vaxque *vq_next; + struct vaxque *vq_prev; +}; + +insque(e, prev) + register struct vaxque *e, *prev; +{ + e->vq_prev = prev; + e->vq_next = prev->vq_next; + prev->vq_next->vq_prev = e; + prev->vq_next = e; +} diff --git a/src/libc/gen/isatty.c b/src/libc/gen/isatty.c new file mode 100644 index 0000000..616d418 --- /dev/null +++ b/src/libc/gen/isatty.c @@ -0,0 +1,15 @@ +/* + * Returns 1 iff file is a tty + */ +#include + +int +isatty(f) + int f; +{ + struct sgttyb ttyb; + + if (ioctl(f, TIOCGETP, &ttyb) < 0) + return(0); + return(1); +} diff --git a/src/libc/gen/isinf.c b/src/libc/gen/isinf.c new file mode 100644 index 0000000..f8d1a88 --- /dev/null +++ b/src/libc/gen/isinf.c @@ -0,0 +1,22 @@ +/* + * Written by J.T. Conklin . + * Changed to return -1 for -Inf by Ulrich Drepper . + * Public domain. + */ +#include + +/* + * isinf(x) returns 1 is x is inf, -1 if x is -inf, else 0; + * no branching! + */ +int isinf (double x) +{ + long hx, lx; + + lx = *(unsigned long long*) &x; + hx = (*(unsigned long long*) &x) >> 32; + + lx |= (hx & 0x7fffffff) ^ 0x7ff00000; + lx |= -lx; + return ~(lx >> 31) & (hx >> 30); +} diff --git a/src/libc/gen/isinff.c b/src/libc/gen/isinff.c new file mode 100644 index 0000000..1755a65 --- /dev/null +++ b/src/libc/gen/isinff.c @@ -0,0 +1,30 @@ +/* + * Written by Serge Vakulenko . + * + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + */ +#include + +/* + * isinff(x) returns 1 is x is inf, -1 if x is -inf, else 0; + * no branching! + */ +int isinff (float x) +{ + union { + long s32; + float f32; + } u; + long v; + + u.f32 = x; + v = (u.s32 & 0x7fffffff) ^ 0x7f800000; + return ~((v | -v) >> 31) & (u.s32 >> 30); +} + +/* + * For PIC32, double is the same as float. + */ +int isinf (double x) __attribute__((alias ("isinff"))); diff --git a/src/libc/gen/isnan.c b/src/libc/gen/isnan.c new file mode 100644 index 0000000..b1d0a44 --- /dev/null +++ b/src/libc/gen/isnan.c @@ -0,0 +1,26 @@ +/* + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + */ +#include + +/* + * isnan(x) returns 1 is x is nan, else 0; + * no branching! + */ +int isnan (double x) +{ + long hx, lx; + + lx = *(unsigned long long*) &x; + hx = (*(unsigned long long*) &x) >> 32; + + hx &= 0x7fffffff; + hx |= (unsigned long) (lx | (-lx)) >> 31; + hx = 0x7ff00000 - hx; + return (int) (((unsigned long) hx) >> 31); +} diff --git a/src/libc/gen/isnanf.c b/src/libc/gen/isnanf.c new file mode 100644 index 0000000..dda3938 --- /dev/null +++ b/src/libc/gen/isnanf.c @@ -0,0 +1,30 @@ +/* + * Written by Serge Vakulenko . + * + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + */ +#include + +/* + * isnan(x) returns 1 is x is nan, else 0; + * no branching! + */ +int isnanf (float x) +{ + union { + long s32; + float f32; + } u; + unsigned long ul; + + u.f32 = x; + ul = 0x7f800000 - (u.s32 & 0x7fffffff); + return ul >> 31; +} + +/* + * For PIC32, double is the same as float. + */ +int isnan (double x) __attribute__((alias ("isnanf"))); diff --git a/src/libc/gen/knlist.c b/src/libc/gen/knlist.c new file mode 100644 index 0000000..0415638 --- /dev/null +++ b/src/libc/gen/knlist.c @@ -0,0 +1,33 @@ +#include +#include +#include +#include +#include + +int +knlist(list) + struct nlist *list; +{ + register struct nlist *p; + int mib[2], entries = 0; + size_t size; + + mib[0] = CTL_MACHDEP; + mib[1] = CPU_NLIST; + + /* + * Clean out any left-over information for all valid entries. + * Type and value defined to be 0 if not found; historical + * versions cleared other and desc as well. + */ + for (p=list; p->n_name && p->n_name[0]; ++p) { + size = sizeof(p->n_value); + if (sysctl(mib, 2, &p->n_value, &size, + p->n_name, 1 + strlen(p->n_name)) < 0) { + p->n_value = 0; + continue; + } + ++entries; + } + return entries; +} diff --git a/src/libc/gen/ldexp.c b/src/libc/gen/ldexp.c new file mode 100644 index 0000000..46c1807 --- /dev/null +++ b/src/libc/gen/ldexp.c @@ -0,0 +1,46 @@ +#include + +double +ldexp(fr, exp) + double fr; + int exp; +{ + double huge = 1.701411834604692293e38; + int neg; + int i; + + neg = 0; + if (fr < 0) { + fr = -fr; + neg = 1; + } + fr = frexp(fr, &i); + while (fr < 0.5) { + fr = 2*fr; + i = i-1; + } + exp = exp+i; + if (exp > 127) { + if (neg) + return(-huge); + else + return(huge); + } + if (exp < -127) + return(0); + while (exp > 30) { + fr = fr*(1L<<30); + exp = exp-30; + } + while (exp < -30) { + fr = fr/(1L<<30); + exp = exp+30; + } + if (exp > 0) + fr = fr*(1L< +#include + +#ifdef debug +#include +#include + +#define ASSERT(p) if(!(p))botch("p") + +/* + * Can't use 'printf' below because that can call malloc(). If the malloc + * arena is corrupt malloc() calls botch() which calls printf which calls malloc + * ... result is a recursive loop which underflows the stack. +*/ + +static botch(s) +char *s; +{ + struct iovec iov[3]; + register struct iovec *v = iov; + char *ab = "assertion botched: "; + + v->iov_base = ab; + v->iov_len = strlen(ab); + v++; + v->iov_base = s; + v->iov_len = strlen(s); + v++; + v->iov_base = "\n"; + v->iov_len = 1; + + writev(STDOUT_FILENO, iov, 3); + abort(); +} +#else +#define ASSERT(p) +#endif /* debug */ + +/* + * The origins of the following ifdef are lost. The only comment attached + * to it, "avoid break bug", probably has something to do with a bug in + * an older PDP-11 kernel. Maybe it's still a bug in the current kernel. + * We'll probably never know ... + */ +#ifdef pdp11 +# define GRANULE 64 +#else +# define GRANULE 0 +#endif + +/* + * C storage allocator + * + * Uses circular first-fit strategy. Works with a noncontiguous, but + * monotonically linked, arena. Each block is preceded by a ptr to the + * pointer of the next following block. Blocks are exact number of words + * long aligned to the data type requirements of ALIGN. + * + * Bit 0 (LSB) of pointers is used to indicate whether the block associated + * with the pointer is in use. A 1 indicates a busy block and a 0 a free + * block (obviously pointers can't point at odd addresses). Gaps in arena + * are merely noted as busy blocks. The last block of the arena (pointed + * to by alloct) is empty and has a pointer to first. Idle blocks are + * coalesced during space search + * + * Different implementations may need to redefine ALIGN, NALIGN, BLOCK, + * BUSY, INT where INT is integer type to which a pointer can be cast. + */ +#define INT int +#define ALIGN int +#define NALIGN 1 +#define WORD sizeof(union store) +#define BLOCK 1024 /* a multiple of WORD */ + +#define BUSY 1 + +#define testbusy(p) ((INT)(p)&BUSY) +#define setbusy(p) (union store *)((INT)(p)|BUSY) +#define clearbusy(p) (union store *)((INT)(p)&~BUSY) + +union store { + union store *ptr; + ALIGN dummy[NALIGN]; + int calloc; /* calloc clears an array of integers */ +}; + +static union store allocs[2]; /* initial arena */ +static union store *allocp; /* search ptr */ +static union store *alloct; /* arena top */ +static union store *allocx; /* for benefit of realloc */ + +void * +malloc(nbytes) + size_t nbytes; +{ + register union store *p, *q; + register int nw; + static int temp; /* coroutines assume no auto */ + + if (nbytes == 0) + return(NULL); + if (allocs[0].ptr == 0) { /* first time */ + allocs[0].ptr = setbusy(&allocs[1]); + allocs[1].ptr = setbusy(&allocs[0]); + alloct = &allocs[1]; + allocp = &allocs[0]; + } + nw = (nbytes+WORD+WORD-1)/WORD; + ASSERT(allocp >= allocs && allocp <= alloct); + ASSERT(allock()); + for (p = allocp; ; ) { + for (temp = 0; ; ) { + if (!testbusy(p->ptr)) { + while(!testbusy((q = p->ptr)->ptr)) { + ASSERT(q > p && q < alloct); + p->ptr = q->ptr; + } + if (q >= p+nw && p+nw >= p) + goto found; + } + q = p; + p = clearbusy(p->ptr); + if (p > q) + ASSERT(p <= alloct); + else if (q != alloct || p != allocs) { + ASSERT(q == alloct && p == allocs); + return(NULL); + } else if (++temp > 1) + break; + } + q = (union store *)sbrk(0); + /* + * Line up on page boundry so we can get the last drip at + * the end ... + */ + temp = ((((unsigned)q + WORD*nw + BLOCK-1)/BLOCK)*BLOCK + - (unsigned)q) / WORD; + if (q+temp+GRANULE < q) + return(NULL); + q = (union store *)sbrk(temp*WORD); + if ((INT)q == -1) + return(NULL); + ASSERT(q > alloct); + alloct->ptr = q; + if (q != alloct+1) + alloct->ptr = setbusy(alloct->ptr); + alloct = q->ptr = q+temp-1; + alloct->ptr = setbusy(allocs); + } +found: + allocp = p + nw; + ASSERT(allocp <= alloct); + if (q > allocp) { + allocx = allocp->ptr; + allocp->ptr = p->ptr; + } + p->ptr = setbusy(allocp); + return((char *)(p+1)); +} + +/* + * Freeing strategy tuned for LIFO allocation. + */ +void free(ap) + register void *ap; +{ + register union store *p = (union store *)ap; + + if (p == NULL) + return; + ASSERT(p > clearbusy(allocs[1].ptr) && p <= alloct); + ASSERT(allock()); + allocp = --p; + ASSERT(testbusy(p->ptr)); + p->ptr = clearbusy(p->ptr); + ASSERT(p->ptr > allocp && p->ptr <= alloct); +} + +/* + * Realloc(p, nbytes) reallocates a block obtained from malloc() and freed + * since last call of malloc() to have new size nbytes, and old content + * returns new location, or 0 on failure. + */ +void * +realloc(vp, nbytes) + register void *vp; + size_t nbytes; +{ + register union store *p = vp; + register union store *q; + union store *s, *t; + register unsigned nw; + unsigned onw; + + if (p == NULL) + return malloc(nbytes); + if (testbusy(p[-1].ptr)) + free((char *)p); + onw = p[-1].ptr - p; + q = (union store *)malloc(nbytes); + if (q == NULL || q == p) + return((char *)q); + s = p; + t = q; + nw = (nbytes+WORD-1)/WORD; + if (nw < onw) + onw = nw; + while (onw-- != 0) + *t++ = *s++; + if (q < p && q+nw >= p) + (q+(q+nw-p))->ptr = allocx; + return((char *)q); +} + +#ifdef debug +static allock() +{ +#ifdef longdebug + register union store *p; + int x; + x = 0; + for (p= &allocs[0]; clearbusy(p->ptr) > p; p=clearbusy(p->ptr)) { + if (p == allocp) + x++; + } + ASSERT(p == alloct); + return((x == 1) | (p == allocp)); +#else + return(1); +#endif +} +#endif /* debug */ diff --git a/src/libc/gen/mktemp.c b/src/libc/gen/mktemp.c new file mode 100644 index 0000000..1f0cba2 --- /dev/null +++ b/src/libc/gen/mktemp.c @@ -0,0 +1,94 @@ +/* + * Copyright (c) 1987 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#define YES 1 +#define NO 0 + +static int +_gettemp(as, doopen) + char *as; + register int *doopen; +{ + extern int errno; + register char *start, *trv; + struct stat sbuf; + u_int pid; + + pid = getpid(); + + /* extra X's get set to 0's */ + for (trv = as; *trv; ++trv); + while (*--trv == 'X') { + *trv = (pid % 10) + '0'; + pid /= 10; + } + + /* + * check for write permission on target directory; if you have + * six X's and you can't write the directory, this will run for + * a *very* long time. + */ + for (start = ++trv; trv > as && *trv != '/'; --trv); + if (*trv == '/') { + *trv = '\0'; + if (stat(as, &sbuf) || !(sbuf.st_mode & S_IFDIR)) + return(NO); + *trv = '/'; + } + else if (stat(".", &sbuf) == -1) + return(NO); + + for (;;) { + if (doopen) { + if ((*doopen = open(as, O_CREAT|O_EXCL|O_RDWR, 0600)) >= 0) + return(YES); + if (errno != EEXIST) + return(NO); + } + else if (stat(as, &sbuf)) + return(errno == ENOENT ? YES : NO); + + /* tricky little algorithm for backward compatibility */ + for (trv = start;;) { + if (!*trv) + return(NO); + if (*trv == 'z') + *trv++ = 'a'; + else { + if (isdigit(*trv)) + *trv = 'a'; + else + ++*trv; + break; + } + } + } + /*NOTREACHED*/ +} + +int +mkstemp(as) + char *as; +{ + int fd; + + return (_gettemp(as, &fd) ? fd : -1); +} + +char * +mktemp(as) + char *as; +{ + return(_gettemp(as, (int *)NULL) ? as : (char *)NULL); +} diff --git a/src/libc/gen/modf.c b/src/libc/gen/modf.c new file mode 100644 index 0000000..a331a26 --- /dev/null +++ b/src/libc/gen/modf.c @@ -0,0 +1,79 @@ +/* + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + */ +#include + +/* Get two 32 bit ints from a double. */ + +#define EXTRACT_WORDS(high,low,d) \ + high = *(unsigned long long*) &d; \ + low = (*(unsigned long long*) &d) >> 32 + + +/* Set a double from two 32 bit ints. */ + +#define INSERT_WORDS(d,high,low) \ + *(unsigned long long*) &(x) = (unsigned long long) (high) << 32 | (low) + +/* + * modf(double x, double *iptr) + * return fraction part of x, and return x's integral part in *iptr. + * Method: + * Bit twiddling. + * + * Exception: + * No exception. + */ +static const double one = 1.0; + +double modf (double x, double *iptr) +{ + long i0, i1, j0; + unsigned long i; + + EXTRACT_WORDS (i0, i1, x); + j0 = ((i0 >> 20) & 0x7ff) - 0x3ff; /* exponent of x */ + if (j0 < 20) { /* integer part in high x */ + if (j0 < 0) { /* |x|<1 */ + INSERT_WORDS (*iptr, i0 & 0x80000000, 0); + /* *iptr = +-0 */ + return x; + } else { + i = (0x000fffff) >> j0; + if (((i0 & i) | i1) == 0) { /* x is integral */ + *iptr = x; + INSERT_WORDS (x, i0 & 0x80000000, 0); + /* return +-0 */ + return x; + } else { + INSERT_WORDS (*iptr, i0 & (~i), 0); + return x - *iptr; + } + } + } else if (j0 > 51) { /* no fraction part */ + *iptr = x * one; + /* We must handle NaNs separately. */ + if (j0 == 0x400 && ((i0 & 0xfffff) | i1)) + return x * one; + + INSERT_WORDS (x, i0 & 0x80000000, 0); + /* return +-0 */ + return x; + } else { /* fraction part in low x */ + i = ((unsigned long) (0xffffffff)) >> (j0 - 20); + if ((i1 & i) == 0) { /* x is integral */ + *iptr = x; + INSERT_WORDS (x, i0 & 0x80000000, 0); + /* return +-0 */ + return x; + } else { + INSERT_WORDS (*iptr, i0, i1 & (~i)); + return x - *iptr; + } + } +} diff --git a/src/libc/gen/modff.c b/src/libc/gen/modff.c new file mode 100644 index 0000000..7eeac60 --- /dev/null +++ b/src/libc/gen/modff.c @@ -0,0 +1,55 @@ +/* + * Written by Serge Vakulenko . + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + */ +#include + +/* + * modff(float x, float *iptr) + * return fraction part of x, and return x's integral part in *iptr. + */ +static const float one = 1.0; + +float modff (float fx, float *iptr) +{ + union { + unsigned u32; + float f32; + } x; + unsigned hx, s; + + x.f32 = fx; + hx = x.u32 & ~0x80000000; + if (hx >= 0x4b000000) { /* x is NaN, infinite, or integral */ + *iptr = x.f32; + if (hx <= 0x7f800000) + x.u32 &= 0x80000000; + return x.f32; + } + + if (hx < 0x3f800000) { /* |x| < 1 */ + float ret = x.f32; + x.u32 &= 0x80000000; + *iptr = x.f32; + return ret; + } + + /* split x at the binary point */ + s = x.u32 & 0x80000000; + fx = x.f32; + x.u32 &= ~((1 << (0x96 - (hx >> 23))) - 1); + *iptr = x.f32; + x.f32 = fx - *iptr; + + /* restore sign in case difference is 0 */ + x.u32 = (x.u32 & ~0x80000000) | s; + return x.f32; +} + +/* + * For PIC32, double is the same as float. + */ +double modf (double x, double *iptr) __attribute__((alias ("modff"))); diff --git a/src/libc/gen/ndbm.c b/src/libc/gen/ndbm.c new file mode 100644 index 0000000..70447df --- /dev/null +++ b/src/libc/gen/ndbm.c @@ -0,0 +1,504 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define BYTESIZ 8 +#undef setbit + +static int hitab[16] +/* ken's +{ + 055,043,036,054,063,014,004,005, + 010,064,077,000,035,027,025,071, +}; +*/ + = { 61, 57, 53, 49, 45, 41, 37, 33, + 29, 25, 21, 17, 13, 9, 5, 1, +}; +static long hltab[64] + = { + 06100151277L,06106161736L,06452611562L,05001724107L, + 02614772546L,04120731531L,04665262210L,07347467531L, + 06735253126L,06042345173L,03072226605L,01464164730L, + 03247435524L,07652510057L,01546775256L,05714532133L, + 06173260402L,07517101630L,02431460343L,01743245566L, + 00261675137L,02433103631L,03421772437L,04447707466L, + 04435620103L,03757017115L,03641531772L,06767633246L, + 02673230344L,00260612216L,04133454451L,00615531516L, + 06137717526L,02574116560L,02304023373L,07061702261L, + 05153031405L,05322056705L,07401116734L,06552375715L, + 06165233473L,05311063631L,01212221723L,01052267235L, + 06000615237L,01075222665L,06330216006L,04402355630L, + 01451177262L,02000133436L,06025467062L,07121076461L, + 03123433522L,01010635225L,01716177066L,05161746527L, + 01736635071L,06243505026L,03637211610L,01756474365L, + 04723077174L,03642763134L,05750130273L,03655541561L, +}; + +static long +dcalchash(item) + datum item; +{ + register int s, c, j; + register char *cp; + register long hashl; + register int hashi; + + hashl = 0; + hashi = 0; + for (cp = item.dptr, s=item.dsize; --s >= 0; ) { + c = *cp++; + for (j=0; j>= 4; + } + } + return (hashl); +} + +static datum +makdatum(buf, n) + char buf[PBLKSIZ]; +{ + register short *sp; + register int t; + datum item; + + sp = (short *)buf; + if ((unsigned)n >= sp[0]) { + item.dptr = NULL; + item.dsize = 0; + return (item); + } + t = PBLKSIZ; + if (n > 0) + t = sp[n]; + item.dptr = buf+sp[n+1]; + item.dsize = t - sp[n+1]; + return (item); +} + +DBM * +dbm_open(file, flags, mode) + char *file; + int flags, mode; +{ + struct stat statb; + register DBM *db; + + if ((db = (DBM *)malloc(sizeof *db)) == 0) { + errno = ENOMEM; + return ((DBM *)0); + } + db->dbm_flags = (flags & 03) == O_RDONLY ? _DBM_RDONLY : 0; + if ((flags & 03) == O_WRONLY) + flags = (flags & ~03) | O_RDWR; + strcpy(db->dbm_pagbuf, file); + strcat(db->dbm_pagbuf, ".pag"); + db->dbm_pagf = open(db->dbm_pagbuf, flags, mode); + if (db->dbm_pagf < 0) + goto bad; + strcpy(db->dbm_pagbuf, file); + strcat(db->dbm_pagbuf, ".dir"); + db->dbm_dirf = open(db->dbm_pagbuf, flags, mode); + if (db->dbm_dirf < 0) + goto bad1; + fstat(db->dbm_dirf, &statb); + db->dbm_maxbno = statb.st_size*BYTESIZ-1; + db->dbm_pagbno = db->dbm_dirbno = -1; + return (db); +bad1: + (void) close(db->dbm_pagf); +bad: + free((char *)db); + return ((DBM *)0); +} + +void +dbm_close(db) + DBM *db; +{ + + (void) close(db->dbm_dirf); + (void) close(db->dbm_pagf); + free((char *)db); +} + +static int +getbit(db) + register DBM *db; +{ + long bn, b; + register int i, n; + + if (db->dbm_bitno > db->dbm_maxbno) + return (0); + n = db->dbm_bitno % BYTESIZ; + bn = db->dbm_bitno / BYTESIZ; + i = bn % DBLKSIZ; + b = bn / DBLKSIZ; + if (b != db->dbm_dirbno) { + db->dbm_dirbno = b; + (void) lseek(db->dbm_dirf, b*DBLKSIZ, L_SET); + if (read(db->dbm_dirf, db->dbm_dirbuf, DBLKSIZ) != DBLKSIZ) + bzero(db->dbm_dirbuf, DBLKSIZ); + } + return (db->dbm_dirbuf[i] & (1<dbm_hmask=0;; db->dbm_hmask=(db->dbm_hmask<<1)+1) { + db->dbm_blkno = hash & db->dbm_hmask; + db->dbm_bitno = db->dbm_blkno + db->dbm_hmask; + if (getbit(db) == 0) + break; + } + return (db->dbm_blkno); +} + +static void +dbm_access(db, hash) + register DBM *db; + long hash; +{ + + for (db->dbm_hmask=0;; db->dbm_hmask=(db->dbm_hmask<<1)+1) { + db->dbm_blkno = hash & db->dbm_hmask; + db->dbm_bitno = db->dbm_blkno + db->dbm_hmask; + if (getbit(db) == 0) + break; + } + if (db->dbm_blkno != db->dbm_pagbno) { + db->dbm_pagbno = db->dbm_blkno; + (void) lseek(db->dbm_pagf, db->dbm_blkno*PBLKSIZ, L_SET); + if (read(db->dbm_pagf, db->dbm_pagbuf, PBLKSIZ) != PBLKSIZ) + bzero(db->dbm_pagbuf, PBLKSIZ); +#ifdef DEBUG + else if (chkblk(db->dbm_pagbuf) < 0) + db->dbm_flags |= _DBM_IOERR; +#endif + } +} + +static int +finddatum(buf, item) + char buf[PBLKSIZ]; + datum item; +{ + register short *sp; + register int i, n, j; + + sp = (short *)buf; + n = PBLKSIZ; + for (i=0, j=sp[0]; idbm_pagbuf, key)) >= 0) { + item = makdatum(db->dbm_pagbuf, i+1); + if (item.dptr != NULL) + return (item); + } +err: + item.dptr = NULL; + item.dsize = 0; + return (item); +} + +/* + * Delete pairs of items (n & n+1). + */ +static int +delitem(buf, n) + char buf[PBLKSIZ]; +{ + register short *sp, *sp1; + register int i1, i2; + + sp = (short *)buf; + i2 = sp[0]; + if ((unsigned)n >= i2 || (n & 1)) + return (0); + if (n == i2-2) { + sp[0] -= 2; + return (1); + } + i1 = PBLKSIZ; + if (n > 0) + i1 = sp[n]; + i1 -= sp[n+2]; + if (i1 > 0) { + i2 = sp[i2]; + bcopy(&buf[i2], &buf[i2 + i1], sp[n+2] - i2); + } + sp[0] -= 2; + for (sp1 = sp + sp[0], sp += n+1; sp <= sp1; sp++) + sp[0] = sp[2] + i1; + return (1); +} + +int +dbm_delete(db, key) + register DBM *db; + datum key; +{ + register int i; + + if (dbm_error(db)) + return (-1); + if (dbm_rdonly(db)) { + errno = EPERM; + return (-1); + } + dbm_access(db, dcalchash(key)); + if ((i = finddatum(db->dbm_pagbuf, key)) < 0) + return (-1); + if (!delitem(db->dbm_pagbuf, i)) + goto err; + db->dbm_pagbno = db->dbm_blkno; + (void) lseek(db->dbm_pagf, db->dbm_blkno*PBLKSIZ, L_SET); + if (write(db->dbm_pagf, db->dbm_pagbuf, PBLKSIZ) != PBLKSIZ) { + err: + db->dbm_flags |= _DBM_IOERR; + return (-1); + } + return (0); +} + +static void +setbit(db) + register DBM *db; +{ + long bn, b; + register int i, n; + + if (db->dbm_bitno > db->dbm_maxbno) + db->dbm_maxbno = db->dbm_bitno; + n = db->dbm_bitno % BYTESIZ; + bn = db->dbm_bitno / BYTESIZ; + i = bn % DBLKSIZ; + b = bn / DBLKSIZ; + if (b != db->dbm_dirbno) { + db->dbm_dirbno = b; + (void) lseek(db->dbm_dirf, b*DBLKSIZ, L_SET); + if (read(db->dbm_dirf, db->dbm_dirbuf, DBLKSIZ) != DBLKSIZ) + bzero(db->dbm_dirbuf, DBLKSIZ); + } + db->dbm_dirbuf[i] |= 1<dbm_dirbno = b; + (void) lseek(db->dbm_dirf, (long)b*DBLKSIZ, L_SET); + if (write(db->dbm_dirf, db->dbm_dirbuf, DBLKSIZ) != DBLKSIZ) + db->dbm_flags |= _DBM_IOERR; +} + +/* + * Add pairs of items (item & item1). + */ +static int +additem(buf, item, item1) + char buf[PBLKSIZ]; + datum item, item1; +{ + register short *sp; + register int i1, i2; + + sp = (short *)buf; + i1 = PBLKSIZ; + i2 = sp[0]; + if (i2 > 0) + i1 = sp[i2]; + i1 -= item.dsize + item1.dsize; + if (i1 <= (int)((i2+3) * sizeof(short))) + return (0); + sp[0] += 2; + sp[++i2] = i1 + item1.dsize; + bcopy(item.dptr, &buf[i1 + item1.dsize], item.dsize); + sp[++i2] = i1; + bcopy(item1.dptr, &buf[i1], item1.dsize); + return (1); +} + +int +dbm_store(db, key, dat, replace) + register DBM *db; + datum key, dat; + int replace; +{ + register int i; + datum item, item1; + char ovfbuf[PBLKSIZ]; + + if (dbm_error(db)) + return (-1); + if (dbm_rdonly(db)) { + errno = EPERM; + return (-1); + } +loop: + dbm_access(db, dcalchash(key)); + if ((i = finddatum(db->dbm_pagbuf, key)) >= 0) { + if (!replace) + return (1); + if (!delitem(db->dbm_pagbuf, i)) { + db->dbm_flags |= _DBM_IOERR; + return (-1); + } + } + if (!additem(db->dbm_pagbuf, key, dat)) + goto split; + db->dbm_pagbno = db->dbm_blkno; + (void) lseek(db->dbm_pagf, db->dbm_blkno*PBLKSIZ, L_SET); + if (write(db->dbm_pagf, db->dbm_pagbuf, PBLKSIZ) != PBLKSIZ) { + db->dbm_flags |= _DBM_IOERR; + return (-1); + } + return (0); + +split: + if (key.dsize+dat.dsize+3*sizeof(short) >= PBLKSIZ) { + db->dbm_flags |= _DBM_IOERR; + errno = ENOSPC; + return (-1); + } + bzero(ovfbuf, PBLKSIZ); + for (i=0;;) { + item = makdatum(db->dbm_pagbuf, i); + if (item.dptr == NULL) + break; + if (dcalchash(item) & (db->dbm_hmask+1)) { + item1 = makdatum(db->dbm_pagbuf, i+1); + if (item1.dptr == NULL) { + fprintf(stderr, "ndbm: split not paired\n"); + db->dbm_flags |= _DBM_IOERR; + break; + } + if (!additem(ovfbuf, item, item1) || + !delitem(db->dbm_pagbuf, i)) { + db->dbm_flags |= _DBM_IOERR; + return (-1); + } + continue; + } + i += 2; + } + db->dbm_pagbno = db->dbm_blkno; + (void) lseek(db->dbm_pagf, db->dbm_blkno*PBLKSIZ, L_SET); + if (write(db->dbm_pagf, db->dbm_pagbuf, PBLKSIZ) != PBLKSIZ) { + db->dbm_flags |= _DBM_IOERR; + return (-1); + } + (void) lseek(db->dbm_pagf, (db->dbm_blkno+db->dbm_hmask+1)*PBLKSIZ, L_SET); + if (write(db->dbm_pagf, ovfbuf, PBLKSIZ) != PBLKSIZ) { + db->dbm_flags |= _DBM_IOERR; + return (-1); + } + setbit(db); + goto loop; +} + +datum +dbm_firstkey(db) + DBM *db; +{ + + db->dbm_blkptr = 0L; + db->dbm_keyptr = 0; + return (dbm_nextkey(db)); +} + +datum +dbm_nextkey(db) + register DBM *db; +{ + struct stat statb; + datum item; + + if (dbm_error(db) || fstat(db->dbm_pagf, &statb) < 0) + goto err; + statb.st_size /= PBLKSIZ; + for (;;) { + if (db->dbm_blkptr != db->dbm_pagbno) { + db->dbm_pagbno = db->dbm_blkptr; + (void) lseek(db->dbm_pagf, db->dbm_blkptr*PBLKSIZ, L_SET); + if (read(db->dbm_pagf, db->dbm_pagbuf, PBLKSIZ) != PBLKSIZ) + bzero(db->dbm_pagbuf, PBLKSIZ); +#ifdef DEBUG + else if (chkblk(db->dbm_pagbuf) < 0) + db->dbm_flags |= _DBM_IOERR; +#endif + } + if (db->dbm_pagbuf[0] != 0 && db->dbm_pagbuf[1] != 0) { + item = makdatum(db->dbm_pagbuf, db->dbm_keyptr); + if (item.dptr != NULL) { + db->dbm_keyptr += 2; + return (item); + } + db->dbm_keyptr = 0; + } + if (++db->dbm_blkptr >= statb.st_size) + break; + } +err: + item.dptr = NULL; + item.dsize = 0; + return (item); +} + +#ifdef DEBUG +static +chkblk(buf) + char buf[PBLKSIZ]; +{ + register short *sp; + register t, i; + + sp = (short *)buf; + t = PBLKSIZ; + for (i=0; i t) + return (-1); + t = sp[i+1]; + } + if (t < (sp[0]+1)*sizeof(short)) + return (-1); + return (0); +} +#endif diff --git a/src/libc/gen/nlist.c b/src/libc/gen/nlist.c new file mode 100644 index 0000000..e12ee28 --- /dev/null +++ b/src/libc/gen/nlist.c @@ -0,0 +1,97 @@ +/* + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that: (1) source distributions retain this entire copyright + * notice and comment, and (2) distributions including binaries display + * the following acknowledgement: ``This product includes software + * developed by the University of California, Berkeley and its contributors'' + * in the documentation or other materials provided with the distribution + * and in all advertising materials mentioning features or use of this + * software. Neither the name of the University nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ +#include +#include +#include +#include +#include + +#define ISVALID(p) (p->n_name && p->n_name[0]) + +int +nlist(name, list) + char *name; + struct nlist *list; +{ + register struct nlist *p; + struct exec ebuf; + register FILE *fsym; + off_t symbol_offset, symbol_size; + int entries, len, maxlen, type; + register int c; + register unsigned value; + char sbuf[128]; + + entries = -1; + + if (!(fsym = fopen(name, "r"))) + return(-1); + if (fread((char *)&ebuf, 1, sizeof(ebuf), fsym) != sizeof (ebuf) || + N_BADMAG(ebuf)) + goto done; + + symbol_offset = N_SYMOFF(ebuf); + symbol_size = ebuf.a_syms; + if (fseek(fsym, symbol_offset, L_SET)) + goto done; + + /* + * clean out any left-over information for all valid entries. + * Type and value defined to be 0 if not found; historical + * versions cleared other and desc as well. Also figure out + * the largest string length so don't read any more of the + * string table than we have to. + */ + for (p = list, entries = maxlen = 0; ISVALID(p); ++p, ++entries) { + p->n_type = 0; + p->n_value = 0; + if ((len = strlen(p->n_name)) > maxlen) + maxlen = len; + } + if (++maxlen > sizeof(sbuf)) { /* for the NULL */ + (void)fprintf(stderr, "nlist: sym 2 big\n"); + entries = -1; + goto done; + } + + for (; symbol_size; symbol_size -= len + 6) { + len = getc (fsym); + if (len <= 0) + break; + + type = getc (fsym); + value = getc (fsym); + value |= getc (fsym) << 8; + value |= getc (fsym) << 16; + value |= getc (fsym) << 24; + for (c=0; cn_name, sbuf) == 0) { + p->n_value = value; + p->n_type = type; + if (!--entries) + goto done; + } + } +done: (void)fclose(fsym); + return(entries); +} diff --git a/src/libc/gen/opendir.c b/src/libc/gen/opendir.c new file mode 100644 index 0000000..993f89e --- /dev/null +++ b/src/libc/gen/opendir.c @@ -0,0 +1,31 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include +#include +#include +#include +#include + +/* + * open a directory. + */ +DIR * +opendir(name) + const char *name; +{ + register DIR *dirp; + register int fd; + + if ((fd = open(name, 0)) == -1) + return NULL; + if ((dirp = (DIR *)malloc(sizeof(DIR))) == NULL) { + close (fd); + return NULL; + } + dirp->dd_fd = fd; + dirp->dd_loc = 0; + return dirp; +} diff --git a/src/libc/gen/perror.c b/src/libc/gen/perror.c new file mode 100644 index 0000000..8a89add --- /dev/null +++ b/src/libc/gen/perror.c @@ -0,0 +1,62 @@ +/* + * 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. + */ +#include +#include +#include +#include +#include +#include + +void +perror(s) + const char *s; +{ + register struct iovec *v; + struct iovec iov[4]; + + v = iov; + if (s && *s) { + v->iov_base = (char *)s; + v->iov_len = strlen(s); + v++; + v->iov_base = ": "; + v->iov_len = 2; + v++; + } + v->iov_base = (void*) strerror(errno); + v->iov_len = strlen(v->iov_base); + v++; + v->iov_base = "\n"; + v->iov_len = 1; + (void)writev(STDERR_FILENO, iov, (v - iov) + 1); +} diff --git a/src/libc/gen/popen.c b/src/libc/gen/popen.c new file mode 100644 index 0000000..e591a38 --- /dev/null +++ b/src/libc/gen/popen.c @@ -0,0 +1,133 @@ +/* + * Copyright (c) 1988 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software written by Ken Arnold and + * published in UNIX Review, Vol. 6, No. 8. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +static int *pids; + +FILE * +popen(program, type) + const char *program; + register const char *type; +{ + register FILE *iop; + int pdes[2], fds, pid; + + if (*type != 'r' && *type != 'w') + return (NULL); + if (type[1]) + return (NULL); + + if (pids == NULL) { + if ((fds = getdtablesize()) <= 0) + return (NULL); + if ((pids = (int *)malloc((u_int)(fds * sizeof(int)))) == NULL) + return (NULL); + bzero((char *)pids, fds * sizeof(int)); + } + if (pipe(pdes) < 0) + return (NULL); + switch (pid = vfork()) { + case -1: /* error */ + (void) close(pdes[0]); + (void) close(pdes[1]); + return (NULL); + /* NOTREACHED */ + case 0: /* child */ + if (*type == 'r') { + if (pdes[1] != fileno(stdout)) { + (void) dup2(pdes[1], fileno(stdout)); + (void) close(pdes[1]); + } + (void) close(pdes[0]); + } else { + if (pdes[0] != fileno(stdin)) { + (void) dup2(pdes[0], fileno(stdin)); + (void) close(pdes[0]); + } + (void) close(pdes[1]); + } + execl("/bin/sh", "sh", "-c", program, (char*)0); + _exit(127); + /* NOTREACHED */ + } + /* parent; assume fdopen can't fail... */ + if (*type == 'r') { + iop = fdopen(pdes[0], type); + (void) close(pdes[1]); + } else { + iop = fdopen(pdes[1], type); + (void) close(pdes[0]); + } + pids[fileno(iop)] = pid; + return (iop); +} + +int +pclose(iop) + FILE *iop; +{ + register int fdes; + sigset_t omask, nmask; + union wait pstat; + register int pid; + + /* + * pclose returns -1 if stream is not associated with a + * `popened' command, if already `pclosed', or waitpid + * returns an error. + */ + if (pids == NULL || pids[fdes = fileno(iop)] == 0) + return (-1); + (void) fclose(iop); + sigemptyset(&nmask); + sigaddset(&nmask, SIGINT); + sigaddset(&nmask, SIGQUIT); + sigaddset(&nmask, SIGHUP); + (void) sigprocmask(SIG_BLOCK, &nmask, &omask); + do { + pid = waitpid(pids[fdes], (int *) &pstat, 0); + } while (pid == -1 && errno == EINTR); + (void) sigprocmask(SIG_SETMASK, &omask, NULL); + pids[fdes] = 0; + return (pid == -1 ? -1 : pstat.w_status); +} diff --git a/src/libc/gen/psignal.c b/src/libc/gen/psignal.c new file mode 100644 index 0000000..f26b203 --- /dev/null +++ b/src/libc/gen/psignal.c @@ -0,0 +1,35 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include +#include +#include + +/* + * Print the name of the signal indicated + * along with the supplied message. + */ + +extern char *sys_siglist[]; + +void +psignal(sig, s) + unsigned sig; + char *s; +{ + register char *c; + register int n; + + c = "Unknown signal"; + if (sig < NSIG) + c = sys_siglist[sig]; + n = strlen(s); + if (n) { + write(2, s, n); + write(2, ": ", 2); + } + write(2, c, strlen(c)); + write(2, "\n", 1); +} diff --git a/src/libc/gen/qsort.c b/src/libc/gen/qsort.c new file mode 100644 index 0000000..226a01d --- /dev/null +++ b/src/libc/gen/qsort.c @@ -0,0 +1,202 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +/* + * qsort.c: + * Our own version of the system qsort routine which is faster by an average + * of 25%, with lows and highs of 10% and 50%. + * The THRESHold below is the insertion sort threshold, and has been adjusted + * for records of size 48 bytes. + * The MTHREShold is where we stop finding a better median. + */ + +#define THRESH 4 /* threshold for insertion */ +#define MTHRESH 6 /* threshold for median */ + +static int (*qcmp)(); /* the comparison routine */ +static int qsz; /* size of each record */ +static int thresh; /* THRESHold in chars */ +static int mthresh; /* MTHRESHold in chars */ + +/* + * qst: + * Do a quicksort + * First, find the median element, and put that one in the first place as the + * discriminator. (This "median" is just the median of the first, last and + * middle elements). (Using this median instead of the first element is a big + * win). Then, the usual partitioning/swapping, followed by moving the + * discriminator into the right place. Then, figure out the sizes of the two + * partions, do the smaller one recursively and the larger one via a repeat of + * this code. Stopping when there are less than THRESH elements in a partition + * and cleaning up with an insertion sort (in our caller) is a huge win. + * All data swaps are done in-line, which is space-losing but time-saving. + * (And there are only three places where this is done). + */ +static void +qst(base, max) + char *base, *max; +{ + register char c, *i, *j, *jj; + register int ii; + char *mid, *tmp; + unsigned int lo, hi; + + /* + * At the top here, lo is the number of characters of elements in the + * current partition. (Which should be max - base). + * Find the median of the first, last, and middle element and make + * that the middle element. Set j to largest of first and middle. + * If max is larger than that guy, then it's that guy, else compare + * max with loser of first and take larger. Things are set up to + * prefer the middle, then the first in case of ties. + */ + lo = max - base; /* number of elements as chars */ + do { + mid = i = base + qsz * ((lo / qsz) >> 1); + if (lo >= mthresh) { + j = (qcmp((jj = base), i) > 0 ? jj : i); + if (qcmp(j, (tmp = max - qsz)) > 0) { + /* switch to first loser */ + j = (j == jj ? i : jj); + if (qcmp(j, tmp) < 0) + j = tmp; + } + if (j != i) { + ii = qsz; + do { + c = *i; + *i++ = *j; + *j++ = c; + } while (--ii); + } + } + /* + * Semi-standard quicksort partitioning/swapping + */ + for (i = base, j = max - qsz; ; ) { + while (i < mid && qcmp(i, mid) <= 0) + i += qsz; + while (j > mid) { + if (qcmp(mid, j) <= 0) { + j -= qsz; + continue; + } + tmp = i + qsz; /* value of i after swap */ + if (i == mid) { + /* j <-> mid, new mid is j */ + mid = jj = j; + } else { + /* i <-> j */ + jj = j; + j -= qsz; + } + goto swap; + } + if (i == mid) { + break; + } else { + /* i <-> mid, new mid is i */ + jj = mid; + tmp = mid = i; /* value of i after swap */ + j -= qsz; + } + swap: + ii = qsz; + do { + c = *i; + *i++ = *jj; + *jj++ = c; + } while (--ii); + i = tmp; + } + /* + * Look at sizes of the two partitions, do the smaller + * one first by recursion, then do the larger one by + * making sure lo is its size, base and max are update + * correctly, and branching back. But only repeat + * (recursively or by branching) if the partition is + * of at least size THRESH. + */ + i = (j = mid) + qsz; + if ((lo = j - base) <= (hi = max - i)) { + if (lo >= thresh) + qst(base, j); + base = i; + lo = hi; + } else { + if (hi >= thresh) + qst(i, max); + max = j; + } + } while (lo >= thresh); +} + +/* + * qsort: + * First, set up some global parameters for qst to share. Then, quicksort + * with qst(), and then a cleanup insertion sort ourselves. Sound simple? + * It's not... + */ +void +qsort(base, n, size, compar) + char *base; + int n; + int size; + int (*compar)(); +{ + register char c, *i, *j, *lo, *hi; + char *min, *max; + + if (n <= 1) + return; + qsz = size; + qcmp = compar; + thresh = qsz * THRESH; + mthresh = qsz * MTHRESH; + max = base + n * qsz; + if (n >= THRESH) { + qst(base, max); + hi = base + thresh; + } else { + hi = max; + } + /* + * First put smallest element, which must be in the first THRESH, in + * the first position as a sentinel. This is done just by searching + * the first THRESH elements (or the first n if n < THRESH), finding + * the min, and swapping it into the first position. + */ + for (j = lo = base; (lo += qsz) < hi; ) + if (qcmp(j, lo) > 0) + j = lo; + if (j != base) { + /* swap j into place */ + for (i = base, hi = base + qsz; i < hi; ) { + c = *j; + *j++ = *i; + *i++ = c; + } + } + /* + * With our sentinel in place, we now run the following hyper-fast + * insertion sort. For each remaining element, min, from [1] to [n-1], + * set hi to the index of the element AFTER which this one goes. + * Then, do the standard insertion sort shift on a character at a time + * basis for each element in the frob. + */ + for (min = base; (hi = min += qsz) < max; ) { + while (qcmp(hi -= qsz, min) > 0) + /* void */; + if ((hi += qsz) != min) { + for (lo = min + qsz; --lo >= min; ) { + c = *lo; + for (i = j = lo; (j -= qsz) >= hi; i = j) + *i = *j; + *i = c; + } + } + } +} diff --git a/src/libc/gen/random.c b/src/libc/gen/random.c new file mode 100644 index 0000000..c85e02b --- /dev/null +++ b/src/libc/gen/random.c @@ -0,0 +1,318 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include +#include + +/* + * random.c: + * An improved random number generation package. In addition to the standard + * rand()/srand() like interface, this package also has a special state info + * interface. The initstate() routine is called with a seed, an array of + * bytes, and a count of how many bytes are being passed in; this array is then + * initialized to contain information for random number generation with that + * much state information. Good sizes for the amount of state information are + * 32, 64, 128, and 256 bytes. The state can be switched by calling the + * setstate() routine with the same array as was initiallized with initstate(). + * By default, the package runs with 128 bytes of state information and + * generates far better random numbers than a linear congruential generator. + * If the amount of state information is less than 32 bytes, a simple linear + * congruential R.N.G. is used. + * Internally, the state information is treated as an array of longs; the + * zeroeth element of the array is the type of R.N.G. being used (small + * integer); the remainder of the array is the state information for the + * R.N.G. Thus, 32 bytes of state information will give 7 longs worth of + * state information, which will allow a degree seven polynomial. (Note: the + * zeroeth word of state information also has some other information stored + * in it -- see setstate() for details). + * The random number generation technique is a linear feedback shift register + * approach, employing trinomials (since there are fewer terms to sum up that + * way). In this approach, the least significant bit of all the numbers in + * the state table will act as a linear feedback shift register, and will have + * period 2^deg - 1 (where deg is the degree of the polynomial being used, + * assuming that the polynomial is irreducible and primitive). The higher + * order bits will have longer periods, since their values are also influenced + * by pseudo-random carries out of the lower bits. The total period of the + * generator is approximately deg*(2**deg - 1); thus doubling the amount of + * state information has a vast influence on the period of the generator. + * Note: the deg*(2**deg - 1) is an approximation only good for large deg, + * when the period of the shift register is the dominant factor. With deg + * equal to seven, the period is actually much longer than the 7*(2**7 - 1) + * predicted by this formula. + */ + +/* + * For each of the currently supported random number generators, we have a + * break value on the amount of state information (you need at least this + * many bytes of state info to support this random number generator), a degree + * for the polynomial (actually a trinomial) that the R.N.G. is based on, and + * the separation between the two lower order coefficients of the trinomial. + */ +#define TYPE_0 0 /* linear congruential */ +#define BREAK_0 8 +#define DEG_0 0 +#define SEP_0 0 + +#define TYPE_1 1 /* x**7 + x**3 + 1 */ +#define BREAK_1 32 +#define DEG_1 7 +#define SEP_1 3 + +#define TYPE_2 2 /* x**15 + x + 1 */ +#define BREAK_2 64 +#define DEG_2 15 +#define SEP_2 1 + +#define TYPE_3 3 /* x**31 + x**3 + 1 */ +#define BREAK_3 128 +#define DEG_3 31 +#define SEP_3 3 + +#define TYPE_4 4 /* x**63 + x + 1 */ +#define BREAK_4 256 +#define DEG_4 63 +#define SEP_4 1 + + +/* + * Array versions of the above information to make code run faster -- relies + * on fact that TYPE_i == i. + */ +#define MAX_TYPES 5 /* max number of types above */ + +static int degrees[MAX_TYPES] = { DEG_0, DEG_1, DEG_2, DEG_3, DEG_4 }; + +static int seps[MAX_TYPES] = { SEP_0, SEP_1, SEP_2, SEP_3, SEP_4 }; + + +/* + * Initially, everything is set up as if from : + * initstate(1, &randtbl, 128); + * Note that this initialization takes advantage of the fact that srandom() + * advances the front and rear pointers 10*rand_deg times, and hence the + * rear pointer which starts at 0 will also end up at zero; thus the zeroeth + * element of the state information, which contains info about the current + * position of the rear pointer is just + * MAX_TYPES*(rptr - state) + TYPE_3 == TYPE_3. + */ +static long randtbl[DEG_3 + 1] = { TYPE_3, + 0x9a319039, 0x32d9c024, 0x9b663182, 0x5da1f342, + 0xde3b81e0, 0xdf0a6fb5, 0xf103bc02, 0x48f340fb, + 0x7449e56b, 0xbeb1dbb0, 0xab5c5918, 0x946554fd, + 0x8c2e680f, 0xeb3d799f, 0xb11ee0b7, 0x2d436b86, + 0xda672e2a, 0x1588ca88, 0xe369735d, 0x904f35f7, + 0xd7158fd6, 0x6fa6f051, 0x616e6b96, 0xac94efdc, + 0x36413f93, 0xc622c298, 0xf5a42ab8, 0x8a88d77b, + 0xf5ad9d0e, 0x8999220b, 0x27fb47b9 }; + +/* + * fptr and rptr are two pointers into the state info, a front and a rear + * pointer. These two pointers are always rand_sep places aparts, as they cycle + * cyclically through the state information. (Yes, this does mean we could get + * away with just one pointer, but the code for random() is more efficient this + * way). The pointers are left positioned as they would be from the call + * initstate(1, randtbl, 128) + * (The position of the rear pointer, rptr, is really 0 (as explained above + * in the initialization of randtbl) because the state table pointer is set + * to point to randtbl[1] (as explained below). + */ +static long *fptr = &randtbl[SEP_3 + 1]; +static long *rptr = &randtbl[1]; + +/* + * The following things are the pointer to the state information table, + * the type of the current generator, the degree of the current polynomial + * being used, and the separation between the two pointers. + * Note that for efficiency of random(), we remember the first location of + * the state information, not the zeroeth. Hence it is valid to access + * state[-1], which is used to store the type of the R.N.G. + * Also, we remember the last location, since this is more efficient than + * indexing every time to find the address of the last element to see if + * the front and rear pointers have wrapped. + */ +static long *state = &randtbl[1]; + +static int rand_type = TYPE_3; +static int rand_deg = DEG_3; +static int rand_sep = SEP_3; + +static long *end_ptr = &randtbl[DEG_3 + 1]; + +/* + * srandom: + * Initialize the random number generator based on the given seed. If the + * type is the trivial no-state-information type, just remember the seed. + * Otherwise, initializes state[] based on the given "seed" via a linear + * congruential generator. Then, the pointers are set to known locations + * that are exactly rand_sep places apart. Lastly, it cycles the state + * information a given number of times to get rid of any initial dependencies + * introduced by the L.C.R.N.G. + * Note that the initialization of randtbl[] for default usage relies on + * values produced by this routine. + */ +void +srandom (x) + unsigned x; +{ + register int i; + + if (rand_type == TYPE_0) { + state[0] = x; + } else { + state[0] = x; + for(i = 1; i < rand_deg; i++) { + state[i] = 1103515245*state[i - 1] + 12345; + } + fptr = &state[rand_sep]; + rptr = &state[0]; + for(i = 0; i < 10*rand_deg; i++) random(); + } +} + +/* + * initstate: + * Initialize the state information in the given array of n bytes for + * future random number generation. Based on the number of bytes we + * are given, and the break values for the different R.N.G.'s, we choose + * the best (largest) one we can and set things up for it. srandom() is + * then called to initialize the state information. + * Note that on return from srandom(), we set state[-1] to be the type + * multiplexed with the current value of the rear pointer; this is so + * successive calls to initstate() won't lose this information and will + * be able to restart with setstate(). + * Note: the first thing we do is save the current state, if any, just like + * setstate() so that it doesn't matter when initstate is called. + * Returns a pointer to the old state. + */ +char * +initstate (seed, arg_state, n) + unsigned seed; /* seed for R. N. G. */ + char *arg_state; /* pointer to state array */ + int n; /* # bytes of state info */ +{ + register char *ostate = (char *)(&state[-1]); + + if (rand_type == TYPE_0) state[-1] = rand_type; + else state[-1] = MAX_TYPES*(rptr - state) + rand_type; + if (n < BREAK_1) { + if (n < BREAK_0) { + fprintf(stderr, "initstate: not enough state (%d bytes) with which to do jack; ignored.\n", n); + return 0; + } + rand_type = TYPE_0; + rand_deg = DEG_0; + rand_sep = SEP_0; + } else { + if (n < BREAK_2) { + rand_type = TYPE_1; + rand_deg = DEG_1; + rand_sep = SEP_1; + } else { + if (n < BREAK_3) { + rand_type = TYPE_2; + rand_deg = DEG_2; + rand_sep = SEP_2; + } else { + if (n < BREAK_4) { + rand_type = TYPE_3; + rand_deg = DEG_3; + rand_sep = SEP_3; + } else { + rand_type = TYPE_4; + rand_deg = DEG_4; + rand_sep = SEP_4; + } + } + } + } + state = &(((long *)arg_state)[1]); /* first location */ + end_ptr = &state[rand_deg]; /* must set end_ptr before srandom */ + srandom(seed); + if (rand_type == TYPE_0) + state[-1] = rand_type; + else + state[-1] = MAX_TYPES*(rptr - state) + rand_type; + return(ostate); +} + +/* + * setstate: + * Restore the state from the given state array. + * Note: it is important that we also remember the locations of the pointers + * in the current state information, and restore the locations of the pointers + * from the old state information. This is done by multiplexing the pointer + * location into the zeroeth word of the state information. + * Note that due to the order in which things are done, it is OK to call + * setstate() with the same state as the current state. + * Returns a pointer to the old state information. + */ +char * +setstate (arg_state) + char *arg_state; +{ + register long *new_state = (long *)arg_state; + register int type = new_state[0]%MAX_TYPES; + register int rear = new_state[0]/MAX_TYPES; + char *ostate = (char *)(&state[-1]); + + if (rand_type == TYPE_0) state[-1] = rand_type; + else state[-1] = MAX_TYPES*(rptr - state) + rand_type; + switch(type) { + case TYPE_0: + case TYPE_1: + case TYPE_2: + case TYPE_3: + case TYPE_4: + rand_type = type; + rand_deg = degrees[type]; + rand_sep = seps[type]; + break; + + default: + fprintf(stderr, "setstate: state info has been munged; not changed.\n"); + } + state = &new_state[1]; + if (rand_type != TYPE_0) { + rptr = &state[rear]; + fptr = &state[(rear + rand_sep)%rand_deg]; + } + end_ptr = &state[rand_deg]; /* set end_ptr too */ + return(ostate); +} + +/* + * random: + * If we are using the trivial TYPE_0 R.N.G., just do the old linear + * congruential bit. Otherwise, we do our fancy trinomial stuff, which is the + * same in all ther other cases due to all the global variables that have been + * set up. The basic operation is to add the number at the rear pointer into + * the one at the front pointer. Then both pointers are advanced to the next + * location cyclically in the table. The value returned is the sum generated, + * reduced to 31 bits by throwing away the "least random" low bit. + * Note: the code takes advantage of the fact that both the front and + * rear pointers can't wrap on the same call by not testing the rear + * pointer if the front one has wrapped. + * Returns a 31-bit random number. + */ +long +random() +{ + long i; + + if (rand_type == TYPE_0) { + i = state[0] = (state[0]*1103515245 + 12345)&0x7fffffff; + } else { + *fptr += *rptr; + i = (*fptr >> 1)&0x7fffffff; /* chucking least random bit */ + if (++fptr >= end_ptr) { + fptr = state; + ++rptr; + } else { + if (++rptr >= end_ptr) + rptr = state; + } + } + return(i); +} diff --git a/src/libc/gen/readdir.c b/src/libc/gen/readdir.c new file mode 100644 index 0000000..0b4762b --- /dev/null +++ b/src/libc/gen/readdir.c @@ -0,0 +1,39 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include +#include +#include + +/* + * get next entry in a directory. + */ +struct direct * +readdir(dirp) + register DIR *dirp; +{ + register struct direct *dp; + + for (;;) { + if (dirp->dd_loc == 0) { + dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf, + DIRBLKSIZ); + if (dirp->dd_size <= 0) + return NULL; + } + if (dirp->dd_loc >= dirp->dd_size) { + dirp->dd_loc = 0; + continue; + } + dp = (struct direct *)(dirp->dd_buf + dirp->dd_loc); + if (dp->d_reclen <= 0 || + dp->d_reclen > DIRBLKSIZ + 1 - dirp->dd_loc) + return NULL; + dirp->dd_loc += dp->d_reclen; + if (dp->d_ino == 0) + continue; + return (dp); + } +} diff --git a/src/libc/gen/regex.c b/src/libc/gen/regex.c new file mode 100644 index 0000000..f84abbf --- /dev/null +++ b/src/libc/gen/regex.c @@ -0,0 +1,400 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +/* + * routines to do regular expression matching + * + * Entry points: + * + * re_comp(s) + * char *s; + * ... returns 0 if the string s was compiled successfully, + * a pointer to an error message otherwise. + * If passed 0 or a null string returns without changing + * the currently compiled re (see note 11 below). + * + * re_exec(s) + * char *s; + * ... returns 1 if the string s matches the last compiled regular + * expression, + * 0 if the string s failed to match the last compiled + * regular expression, and + * -1 if the compiled regular expression was invalid + * (indicating an internal error). + * + * The strings passed to both re_comp and re_exec may have trailing or + * embedded newline characters; they are terminated by nulls. + * + * The identity of the author of these routines is lost in antiquity; + * this is essentially the same as the re code in the original V6 ed. + * + * The regular expressions recognized are described below. This description + * is essentially the same as that for ed. + * + * A regular expression specifies a set of strings of characters. + * A member of this set of strings is said to be matched by + * the regular expression. In the following specification for + * regular expressions the word `character' means any character but NUL. + * + * 1. Any character except a special character matches itself. + * Special characters are the regular expression delimiter plus + * \ [ . and sometimes ^ * $. + * 2. A . matches any character. + * 3. A \ followed by any character except a digit or ( ) + * matches that character. + * 4. A nonempty string s bracketed [s] (or [^s]) matches any + * character in (or not in) s. In s, \ has no special meaning, + * and ] may only appear as the first letter. A substring + * a-b, with a and b in ascending ASCII order, stands for + * the inclusive range of ASCII characters. + * 5. A regular expression of form 1-4 followed by * matches a + * sequence of 0 or more matches of the regular expression. + * 6. A regular expression, x, of form 1-8, bracketed \(x\) + * matches what x matches. + * 7. A \ followed by a digit n matches a copy of the string that the + * bracketed regular expression beginning with the nth \( matched. + * 8. A regular expression of form 1-8, x, followed by a regular + * expression of form 1-7, y matches a match for x followed by + * a match for y, with the x match being as long as possible + * while still permitting a y match. + * 9. A regular expression of form 1-8 preceded by ^ (or followed + * by $), is constrained to matches that begin at the left + * (or end at the right) end of a line. + * 10. A regular expression of form 1-9 picks out the longest among + * the leftmost matches in a line. + * 11. An empty regular expression stands for a copy of the last + * regular expression encountered. + */ + +/* + * constants for re's + */ +#define CBRA 1 +#define CCHR 2 +#define CDOT 4 +#define CCL 6 +#define NCCL 8 +#define CDOL 10 +#define CEOF 11 +#define CKET 12 +#define CBACK 18 + +#define CSTAR 01 + +#define ESIZE 512 +#define NBRA 9 + +static char expbuf[ESIZE], *braslist[NBRA], *braelist[NBRA]; +static char circf; + +/* + * compile the regular expression argument into a dfa + */ +char * +re_comp(sp) + register char *sp; +{ + register int c; + register char *ep = expbuf; + int cclcnt, numbra = 0; + char *lastep = 0; + char bracket[NBRA]; + char *bracketp = &bracket[0]; + static char *retoolong = "Regular expression too long"; + +#define comerr(msg) {expbuf[0] = 0; numbra = 0; return(msg); } + + if (sp == 0 || *sp == '\0') { + if (*ep == 0) + return("No previous regular expression"); + return(0); + } + if (*sp == '^') { + circf = 1; + sp++; + } + else + circf = 0; + for (;;) { + if (ep >= &expbuf[ESIZE]) + comerr(retoolong); + if ((c = *sp++) == '\0') { + if (bracketp != bracket) + comerr("unmatched \\("); + *ep++ = CEOF; + *ep++ = 0; + return(0); + } + if (c != '*') + lastep = ep; + switch (c) { + + case '.': + *ep++ = CDOT; + continue; + + case '*': + if (lastep == 0 || *lastep == CBRA || *lastep == CKET) + goto defchar; + *lastep |= CSTAR; + continue; + + case '$': + if (*sp != '\0') + goto defchar; + *ep++ = CDOL; + continue; + + case '[': + *ep++ = CCL; + *ep++ = 0; + cclcnt = 1; + if ((c = *sp++) == '^') { + c = *sp++; + ep[-2] = NCCL; + } + do { + if (c == '\0') + comerr("missing ]"); + if (c == '-' && ep [-1] != 0) { + if ((c = *sp++) == ']') { + *ep++ = '-'; + cclcnt++; + break; + } + while (ep[-1] < c) { + *ep = ep[-1] + 1; + ep++; + cclcnt++; + if (ep >= &expbuf[ESIZE]) + comerr(retoolong); + } + } + *ep++ = c; + cclcnt++; + if (ep >= &expbuf[ESIZE]) + comerr(retoolong); + } while ((c = *sp++) != ']'); + lastep[1] = cclcnt; + continue; + + case '\\': + if ((c = *sp++) == '(') { + if (numbra >= NBRA) + comerr("too many \\(\\) pairs"); + *bracketp++ = numbra; + *ep++ = CBRA; + *ep++ = numbra++; + continue; + } + if (c == ')') { + if (bracketp <= bracket) + comerr("unmatched \\)"); + *ep++ = CKET; + *ep++ = *--bracketp; + continue; + } + if (c >= '1' && c < ('1' + NBRA)) { + *ep++ = CBACK; + *ep++ = c - '1'; + continue; + } + *ep++ = CCHR; + *ep++ = c; + continue; + + defchar: + default: + *ep++ = CCHR; + *ep++ = c; + } + } +} + +static int +cclass(set, c, af) + register char *set, c; + int af; +{ + register int n; + + if (c == 0) + return(0); + n = *set++; + while (--n) + if (*set++ == c) + return(af); + return(! af); +} + +static int +backref(i, lp) + register int i; + register char *lp; +{ + register char *bp; + + bp = braslist[i]; + while (*bp++ == *lp++) + if (bp >= braelist[i]) + return(1); + return(0); +} + +/* + * try to match the next thing in the dfa + */ +static int +advance(lp, ep) + register char *lp, *ep; +{ + register char *curlp; + int ct, i; + int rv; + + for (;;) + switch (*ep++) { + + case CCHR: + if (*ep++ == *lp++) + continue; + return(0); + + case CDOT: + if (*lp++) + continue; + return(0); + + case CDOL: + if (*lp == '\0') + continue; + return(0); + + case CEOF: + return(1); + + case CCL: + if (cclass(ep, *lp++, 1)) { + ep += *ep; + continue; + } + return(0); + + case NCCL: + if (cclass(ep, *lp++, 0)) { + ep += *ep; + continue; + } + return(0); + + case CBRA: + braslist[(unsigned char)*ep++] = lp; + continue; + + case CKET: + braelist[(unsigned char)*ep++] = lp; + continue; + + case CBACK: + if (braelist[i = *ep++] == 0) + return(-1); + if (backref(i, lp)) { + lp += braelist[i] - braslist[i]; + continue; + } + return(0); + + case CBACK|CSTAR: + if (braelist[i = *ep++] == 0) + return(-1); + curlp = lp; + ct = braelist[i] - braslist[i]; + while (backref(i, lp)) + lp += ct; + while (lp >= curlp) { + rv = advance(lp, ep); + if (rv) + return(rv); + lp -= ct; + } + continue; + + case CDOT|CSTAR: + curlp = lp; + while (*lp++) + ; + goto star; + + case CCHR|CSTAR: + curlp = lp; + while (*lp++ == *ep) + ; + ep++; + goto star; + + case CCL|CSTAR: + case NCCL|CSTAR: + curlp = lp; + while (cclass(ep, *lp++, ep[-1] == (CCL|CSTAR))) + ; + ep += *ep; + goto star; + + star: + do { + lp--; + rv = advance(lp, ep); + if (rv) + return(rv); + } while (lp > curlp); + return(0); + + default: + return(-1); + } +} + +/* + * match the argument string against the compiled re + */ +int +re_exec(p1) + register char *p1; +{ + register char *p2 = expbuf; + register int c; + int rv; + + for (c = 0; c < NBRA; c++) { + braslist[c] = 0; + braelist[c] = 0; + } + if (circf) + return((advance(p1, p2))); + /* + * fast check for first character + */ + if (*p2 == CCHR) { + c = p2[1]; + do { + if (*p1 != c) + continue; + rv = advance(p1, p2); + if (rv) + return(rv); + } while (*p1++); + return(0); + } + /* + * regular algorithm + */ + do { + rv = advance(p1, p2); + if (rv) + return(rv); + } while (*p1++); + return(0); +} diff --git a/src/libc/gen/remque.c b/src/libc/gen/remque.c new file mode 100644 index 0000000..a0555da --- /dev/null +++ b/src/libc/gen/remque.c @@ -0,0 +1,23 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +/* + * remque -- vax remque instruction + * + * NOTE: this implementation is non-atomic!! + */ + +struct vaxque { /* queue format expected by VAX queue instructions */ + struct vaxque *vq_next; + struct vaxque *vq_prev; +}; + +remque(e) + register struct vaxque *e; +{ + e->vq_prev->vq_next = e->vq_next; + e->vq_next->vq_prev = e->vq_prev; +} diff --git a/src/libc/gen/rindex-disabled.c b/src/libc/gen/rindex-disabled.c new file mode 100644 index 0000000..45e2368 --- /dev/null +++ b/src/libc/gen/rindex-disabled.c @@ -0,0 +1,20 @@ +/* + * Return the ptr in sp at which the character c last + * appears; NULL if not found + */ + +#define NULL 0 + +char * +rindex(sp, c) +register char *sp, c; +{ + register char *r; + + r = NULL; + do { + if (*sp == c) + r = sp; + } while (*sp++); + return(r); +} diff --git a/src/libc/gen/scandir.c b/src/libc/gen/scandir.c new file mode 100644 index 0000000..1cacad3 --- /dev/null +++ b/src/libc/gen/scandir.c @@ -0,0 +1,92 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +/* + * Scan the directory dirname calling select to make a list of selected + * directory entries then sort using qsort and compare routine dcomp. + * Returns the number of entries and a pointer to a list of pointers to + * struct direct (through namelist). Returns -1 if there were any errors. + */ +#include +#include +#include +#include +#include +#include + +int +scandir(dirname, namelist, select, dcomp) + char *dirname; + struct direct *(*namelist[]); + int (*select)(), (*dcomp)(); +{ + register struct direct *d, *p, **names; + register int nitems; + register char *cp1, *cp2; + struct stat stb; + int arraysz; + DIR *dirp; + + if ((dirp = opendir(dirname)) == NULL) + return(-1); + if (fstat(dirp->dd_fd, &stb) < 0) + return(-1); + + /* + * estimate the array size by taking the size of the directory file + * and dividing it by a multiple of the minimum size entry. + */ + arraysz = (stb.st_size / 24); + names = (struct direct **)malloc(arraysz * sizeof(struct direct *)); + if (names == NULL) + return(-1); + + nitems = 0; + while ((d = readdir(dirp)) != NULL) { + if (select != NULL && !(*select)(d)) + continue; /* just selected names */ + /* + * Make a minimum size copy of the data + */ + p = (struct direct *)malloc(DIRSIZ(d)); + if (p == NULL) + return(-1); + p->d_ino = d->d_ino; + p->d_reclen = d->d_reclen; + p->d_namlen = d->d_namlen; + for (cp1 = p->d_name, cp2 = d->d_name; (*cp1++ = *cp2++); ); + + /* + * Check to make sure the array has space left and + * realloc the maximum size. + */ + if (++nitems >= arraysz) { + if (fstat(dirp->dd_fd, &stb) < 0) + return(-1); /* just might have grown */ + arraysz = stb.st_size / 12; + names = (struct direct **)realloc((char *)names, + arraysz * sizeof(struct direct *)); + if (names == NULL) + return(-1); + } + names[nitems-1] = p; + } + closedir(dirp); + if (nitems && dcomp != NULL) + qsort(names, nitems, sizeof(struct direct *), dcomp); + *namelist = names; + return(nitems); +} + +/* + * Alphabetic order comparison routine for those who want it. + */ +int +alphasort(d1, d2) + struct direct **d1, **d2; +{ + return(strcmp((*d1)->d_name, (*d2)->d_name)); +} diff --git a/src/libc/gen/seekdir.c b/src/libc/gen/seekdir.c new file mode 100644 index 0000000..47bf58c --- /dev/null +++ b/src/libc/gen/seekdir.c @@ -0,0 +1,35 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +#include +#include + +/* + * seek to an entry in a directory. + * Only values returned by "telldir" should be passed to seekdir. + */ +void +seekdir(dirp, loc) + register DIR *dirp; + long loc; +{ + long curloc, base, offset; + struct direct *dp; + extern long lseek(); + + curloc = telldir(dirp); + if (loc == curloc) + return; + base = loc & ~(DIRBLKSIZ - 1); + offset = loc & (DIRBLKSIZ - 1); + (void) lseek(dirp->dd_fd, base, 0); + dirp->dd_loc = 0; + while (dirp->dd_loc < offset) { + dp = readdir(dirp); + if (dp == NULL) + return; + } +} diff --git a/src/libc/gen/setenv.c b/src/libc/gen/setenv.c new file mode 100644 index 0000000..73872c1 --- /dev/null +++ b/src/libc/gen/setenv.c @@ -0,0 +1,88 @@ +/* + * Copyright (c) 1987 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include +#include +#include +#include +#include +#include + +/* + * setenv(name,value,rewrite) + * Set the value of the environmental variable "name" to be + * "value". If rewrite is set, replace any current value. + */ +int +setenv(name, value, rewrite) + register const char *name, + *value; + int rewrite; +{ + static int alloced; /* if allocated space before */ + register char *C; + register const char *E; + int l_value, offset; + + if (*value == '=') /* no `=' in value */ + ++value; + l_value = strlen(value); + if ((C = _findenv(name,&offset))) { /* find if already exists */ + if (!rewrite) + return(0); + if (strlen(C) >= l_value) { /* old larger; copy over */ + while ((*C++ = *value++)); + return(0); + } + } + else { /* create new slot */ + register int cnt; + register char **P; + + for (P = environ,cnt = 0;*P;++P,++cnt); + if (alloced) { /* just increase size */ + environ = (char **)realloc((char *)environ, + (u_int)(sizeof(char *) * (cnt + 2))); + if (!environ) + return(-1); + } + else { /* get new space */ + alloced = 1; /* copy old entries into it */ + P = (char **)malloc((u_int)(sizeof(char *) * + (cnt + 2))); + if (!P) + return(-1); + bcopy(environ,P,cnt * sizeof(char *)); + environ = P; + } + environ[cnt + 1] = NULL; + offset = cnt; + } + for (E = name; *E && *E != '='; ++E); /* no `=' in name */ + if (!(environ[offset] = /* name + `=' + value */ + malloc((u_int)((int)(E - name) + l_value + 2)))) + return(-1); + for (C = environ[offset]; (*C = *name++) && *C != '='; ++C); + for (*C++ = '='; (*C++ = *value++); ); + return(0); +} + +/* + * unsetenv(name) -- + * Delete environmental variable "name". + */ +int +unsetenv(name) + const char *name; +{ + register char **P; + int offset; + + while (_findenv(name,&offset)) /* if set multiple times */ + for (P = &environ[offset];;++P) + if (!(*P = *(P + 1))) + break; + return 0; +} diff --git a/src/libc/gen/sethostname.c b/src/libc/gen/sethostname.c new file mode 100644 index 0000000..0a8a472 --- /dev/null +++ b/src/libc/gen/sethostname.c @@ -0,0 +1,48 @@ +/* + * 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. + */ +#include +#include + +int +sethostname(name, namelen) + char *name; + int namelen; +{ + int mib[2]; + + mib[0] = CTL_KERN; + mib[1] = KERN_HOSTNAME; + if (sysctl(mib, 2, NULL, NULL, (void *)name, namelen) == -1) + return (-1); + return (0); +} diff --git a/src/libc/gen/setmode.c b/src/libc/gen/setmode.c new file mode 100644 index 0000000..98f6cea --- /dev/null +++ b/src/libc/gen/setmode.c @@ -0,0 +1,453 @@ +/* + * 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 + * Dave Borman at Cray Research, 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. + */ +#include +#include + +#include +#include +#include +#include + +#ifdef SETMODE_DEBUG +#include +#endif + +#define SET_LEN 6 /* initial # of bitcmd struct to malloc */ +#define SET_LEN_INCR 4 /* # of bitcmd structs to add as needed */ + +typedef struct bitcmd { + char cmd; + char cmd2; + mode_t bits; +} BITCMD; + +#define CMD2_CLR 0x01 +#define CMD2_SET 0x02 +#define CMD2_GBITS 0x04 +#define CMD2_OBITS 0x08 +#define CMD2_UBITS 0x10 + +static BITCMD *addcmd(); +static int compress_mode(); +#ifdef SETMODE_DEBUG +static void dumpmode(); +#endif + +/* + * Given the old mode and an array of bitcmd structures, apply the operations + * described in the bitcmd structures to the old mode, and return the new mode. + * Note that there is no '=' command; a strict assignment is just a '-' (clear + * bits) followed by a '+' (set bits). + */ +mode_t +getmode(bbox, omode) + void *bbox; + mode_t omode; +{ + register BITCMD *set; + register mode_t clrval, newmode, value; + + set = (BITCMD *)bbox; + newmode = omode; + for (value = 0;; set++) + switch(set->cmd) { + /* + * When copying the user, group or other bits around, we "know" + * where the bits are in the mode so that we can do shifts to + * copy them around. If we don't use shifts, it gets real + * grundgy with lots of single bit checks and bit sets. + */ + case 'u': + value = (newmode & S_IRWXU) >> 6; + goto common; + + case 'g': + value = (newmode & S_IRWXG) >> 3; + goto common; + + case 'o': + value = newmode & S_IRWXO; +common: if (set->cmd2 & CMD2_CLR) { + clrval = + (set->cmd2 & CMD2_SET) ? S_IRWXO : value; + if (set->cmd2 & CMD2_UBITS) + newmode &= ~((clrval<<6) & set->bits); + if (set->cmd2 & CMD2_GBITS) + newmode &= ~((clrval<<3) & set->bits); + if (set->cmd2 & CMD2_OBITS) + newmode &= ~(clrval & set->bits); + } + if (set->cmd2 & CMD2_SET) { + if (set->cmd2 & CMD2_UBITS) + newmode |= (value<<6) & set->bits; + if (set->cmd2 & CMD2_GBITS) + newmode |= (value<<3) & set->bits; + if (set->cmd2 & CMD2_OBITS) + newmode |= value & set->bits; + } + break; + + case '+': + newmode |= set->bits; + break; + + case '-': + newmode &= ~set->bits; + break; + + case 'X': + if (omode & (S_IFDIR|S_IXUSR|S_IXGRP|S_IXOTH)) + newmode |= set->bits; + break; + + case '\0': + default: +#ifdef SETMODE_DEBUG + (void)printf("getmode:%04o -> %04o\n", omode, newmode); +#endif + return (newmode); + } +} + +#define ADDCMD(a, b, c, d) \ + if (set >= endset) { \ + register BITCMD *newset; \ + setlen += SET_LEN_INCR; \ + newset = (BITCMD *)realloc(saveset, sizeof(BITCMD) * setlen); \ + if (!saveset) \ + return ((void *)NULL); \ + set = newset + (set - saveset); \ + saveset = newset; \ + endset = newset + (setlen - 2); \ + } \ + set = addcmd(set, (a), (b), (c), (d)) + +#define STANDARD_BITS (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO) + +void * +setmode(p) + register char *p; +{ + register int perm, who; + char op; + BITCMD *set, *saveset, *endset; +#ifdef notnow + sigset_t sigset, sigoset; +#endif + mode_t mask; + int equalopdone = 0, permXbits, setlen; + + if (!*p) + return ((void *)NULL); + +#ifdef notnow + /* + * Get a copy of the mask for the permissions that are mask relative. + * Flip the bits, we want what's not set. Since it's possible that + * the caller is opening files inside a signal handler, protect them + * as best we can. + */ + sigfillset(&sigset); + (void)sigprocmask(SIG_BLOCK, &sigset, &sigoset); +#endif + (void)umask(mask = umask(0)); + mask = ~mask; +#ifdef notnow + (void)sigprocmask(SIG_SETMASK, &sigoset, NULL); +#endif + + setlen = SET_LEN + 2; + + if ((set = (BITCMD *)malloc((u_int)(sizeof(BITCMD) * setlen))) == NULL) + return ((void *)NULL); + saveset = set; + endset = set + (setlen - 2); + + /* + * If an absolute number, get it and return; disallow non-octal digits + * or illegal bits. + */ + if (isdigit(*p)) { + perm = (mode_t)strtol(p, NULL, 8); + if (perm & ~(STANDARD_BITS|S_ISVTX)) { + free(saveset); + return ((void *)NULL); + } + while (*++p) + if (*p < '0' || *p > '7') { + free(saveset); + return ((void *)NULL); + } + ADDCMD('=', (STANDARD_BITS|S_ISVTX), perm, mask); + return ((void *)saveset); + } + + /* + * Build list of structures to set/clear/copy bits as described by + * each clause of the symbolic mode. + */ + for (;;) { + /* First, find out which bits might be modified. */ + for (who = 0;; ++p) { + switch (*p) { + case 'a': + who |= STANDARD_BITS; + break; + case 'u': + who |= S_ISUID|S_IRWXU; + break; + case 'g': + who |= S_ISGID|S_IRWXG; + break; + case 'o': + who |= S_IRWXO; + break; + default: + goto getop; + } + } + +getop: if ((op = *p++) != '+' && op != '-' && op != '=') { + free(saveset); + return ((void *)NULL); + } + if (op == '=') + equalopdone = 0; + + who &= ~S_ISVTX; + for (perm = 0, permXbits = 0;; ++p) { + switch (*p) { + case 'r': + perm |= S_IRUSR|S_IRGRP|S_IROTH; + break; + case 's': + /* If only "other" bits ignore set-id. */ + if (who & ~S_IRWXO) + perm |= S_ISUID|S_ISGID; + break; + case 't': + /* If only "other" bits ignore sticky. */ + if (who & ~S_IRWXO) { + who |= S_ISVTX; + perm |= S_ISVTX; + } + break; + case 'w': + perm |= S_IWUSR|S_IWGRP|S_IWOTH; + break; + case 'X': + permXbits = S_IXUSR|S_IXGRP|S_IXOTH; + break; + case 'x': + perm |= S_IXUSR|S_IXGRP|S_IXOTH; + break; + case 'u': + case 'g': + case 'o': + /* + * When ever we hit 'u', 'g', or 'o', we have + * to flush out any partial mode that we have, + * and then do the copying of the mode bits. + */ + if (perm) { + ADDCMD(op, who, perm, mask); + perm = 0; + } + if (op == '=') + equalopdone = 1; + if (op == '+' && permXbits) { + ADDCMD('X', who, permXbits, mask); + permXbits = 0; + } + ADDCMD(*p, who, op, mask); + break; + + default: + /* + * Add any permissions that we haven't already + * done. + */ + if (perm || (op == '=' && !equalopdone)) { + if (op == '=') + equalopdone = 1; + ADDCMD(op, who, perm, mask); + perm = 0; + } + if (permXbits) { + ADDCMD('X', who, permXbits, mask); + permXbits = 0; + } + goto apply; + } + } + +apply: if (!*p) + break; + if (*p != ',') + goto getop; + ++p; + } + set->cmd = 0; +#ifdef SETMODE_DEBUG + (void)printf("Before compress_mode()\n"); + dumpmode(saveset); +#endif + compress_mode(saveset); +#ifdef SETMODE_DEBUG + (void)printf("After compress_mode()\n"); + dumpmode(saveset); +#endif + return ((void *)saveset); +} + +static BITCMD * +addcmd(set, op, who, oparg, mask) + BITCMD *set; + register int oparg, who; + register int op; + u_int mask; +{ + switch (op) { + case '=': + set->cmd = '-'; + set->bits = who ? who : STANDARD_BITS; + set++; + + op = '+'; + /* FALLTHROUGH */ + case '+': + case '-': + case 'X': + set->cmd = op; + set->bits = (who ? who : mask) & oparg; + break; + + case 'u': + case 'g': + case 'o': + set->cmd = op; + if (who) { + set->cmd2 = ((who & S_IRUSR) ? CMD2_UBITS : 0) | + ((who & S_IRGRP) ? CMD2_GBITS : 0) | + ((who & S_IROTH) ? CMD2_OBITS : 0); + set->bits = ~0; + } else { + set->cmd2 = CMD2_UBITS | CMD2_GBITS | CMD2_OBITS; + set->bits = mask; + } + + if (oparg == '+') + set->cmd2 |= CMD2_SET; + else if (oparg == '-') + set->cmd2 |= CMD2_CLR; + else if (oparg == '=') + set->cmd2 |= CMD2_SET|CMD2_CLR; + break; + } + return (set + 1); +} + +#ifdef SETMODE_DEBUG +static void +dumpmode(set) + register BITCMD *set; +{ + for (; set->cmd; ++set) + (void)printf("cmd: '%c' bits %04o%s%s%s%s%s%s\n", + set->cmd, set->bits, set->cmd2 ? " cmd2:" : "", + set->cmd2 & CMD2_CLR ? " CLR" : "", + set->cmd2 & CMD2_SET ? " SET" : "", + set->cmd2 & CMD2_UBITS ? " UBITS" : "", + set->cmd2 & CMD2_GBITS ? " GBITS" : "", + set->cmd2 & CMD2_OBITS ? " OBITS" : ""); +} +#endif + +/* + * Given an array of bitcmd structures, compress by compacting consecutive + * '+', '-' and 'X' commands into at most 3 commands, one of each. The 'u', + * 'g' and 'o' commands continue to be separate. They could probably be + * compacted, but it's not worth the effort. + */ +static int +compress_mode(set) + register BITCMD *set; +{ + register BITCMD *nset; + register int setbits, clrbits, Xbits, op; + + for (nset = set;;) { + /* Copy over any 'u', 'g' and 'o' commands. */ + while ((op = nset->cmd) != '+' && op != '-' && op != 'X') { + *set++ = *nset++; + if (!op) + return 0; + } + + for (setbits = clrbits = Xbits = 0;; nset++) { + if ((op = nset->cmd) == '-') { + clrbits |= nset->bits; + setbits &= ~nset->bits; + Xbits &= ~nset->bits; + } else if (op == '+') { + setbits |= nset->bits; + clrbits &= ~nset->bits; + Xbits &= ~nset->bits; + } else if (op == 'X') + Xbits |= nset->bits & ~setbits; + else + break; + } + if (clrbits) { + set->cmd = '-'; + set->cmd2 = 0; + set->bits = clrbits; + set++; + } + if (setbits) { + set->cmd = '+'; + set->cmd2 = 0; + set->bits = setbits; + set++; + } + if (Xbits) { + set->cmd = 'X'; + set->cmd2 = 0; + set->bits = Xbits; + set++; + } + } +} diff --git a/src/libc/gen/siginterrupt.c b/src/libc/gen/siginterrupt.c new file mode 100644 index 0000000..2fe4bbe --- /dev/null +++ b/src/libc/gen/siginterrupt.c @@ -0,0 +1,57 @@ +/* + * 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. + */ +#include + +/* + * Set signal state to prevent restart of system calls + * after an instance of the indicated signal. + */ +int +siginterrupt(sig, flag) + int sig, flag; +{ + extern sigset_t _sigintr; + struct sigaction sa; + int ret; + + if ((ret = sigaction(sig, (struct sigaction *)0, &sa)) < 0) + return (ret); + if (flag) { + sigaddset(&_sigintr, sig); + sa.sa_flags &= ~SA_RESTART; + } else { + sigdelset(&_sigintr, sig); + sa.sa_flags |= SA_RESTART; + } + return (sigaction(sig, &sa, (struct sigaction *)0)); +} diff --git a/src/libc/gen/siglist.c b/src/libc/gen/siglist.c new file mode 100644 index 0000000..cceccf0 --- /dev/null +++ b/src/libc/gen/siglist.c @@ -0,0 +1,41 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include + +char *sys_siglist[NSIG] = { + "Signal 0", + "Hangup", /* SIGHUP */ + "Interrupt", /* SIGINT */ + "Quit", /* SIGQUIT */ + "Illegal instruction", /* SIGILL */ + "Trace/BPT trap", /* SIGTRAP */ + "IOT trap", /* SIGIOT */ + "EMT trap", /* SIGEMT */ + "Floating point exception", /* SIGFPE */ + "Killed", /* SIGKILL */ + "Bus error", /* SIGBUS */ + "Segmentation fault", /* SIGSEGV */ + "Bad system call", /* SIGSYS */ + "Broken pipe", /* SIGPIPE */ + "Alarm clock", /* SIGALRM */ + "Terminated", /* SIGTERM */ + "Urgent I/O condition", /* SIGURG */ + "Stopped (signal)", /* SIGSTOP */ + "Stopped", /* SIGTSTP */ + "Continued", /* SIGCONT */ + "Child exited", /* SIGCHLD */ + "Stopped (tty input)", /* SIGTTIN */ + "Stopped (tty output)", /* SIGTTOU */ + "I/O possible", /* SIGIO */ + "Cputime limit exceeded", /* SIGXCPU */ + "Filesize limit exceeded", /* SIGXFSZ */ + "Virtual timer expired", /* SIGVTALRM */ + "Profiling timer expired", /* SIGPROF */ + "Window size changes", /* SIGWINCH */ + "Signal 29", + "User defined signal 1", /* SIGUSR1 */ + "User defined signal 2" /* SIGUSR2 */ +}; diff --git a/src/libc/gen/signal.c b/src/libc/gen/signal.c new file mode 100644 index 0000000..9a5bc2e --- /dev/null +++ b/src/libc/gen/signal.c @@ -0,0 +1,56 @@ +/* + * Copyright (c) 1985, 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. + */ + +/* + * Almost backwards compatible signal. + */ +#include + +sigset_t _sigintr; /* shared with siginterrupt */ + +sig_t +signal(s, a) + int s; + sig_t a; +{ + struct sigaction sa, osa; + + sa.sa_handler = a; + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + if (!sigismember(&_sigintr, s)) + sa.sa_flags |= SA_RESTART; + if (sigaction(s, &sa, &osa) < 0) + return (SIG_ERR); + return (osa.sa_handler); +} diff --git a/src/libc/gen/sigsetops.c b/src/libc/gen/sigsetops.c new file mode 100644 index 0000000..0b83a2a --- /dev/null +++ b/src/libc/gen/sigsetops.c @@ -0,0 +1,81 @@ +/*- + * 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. + */ +#include + +#undef sigemptyset +#undef sigfillset +#undef sigaddset +#undef sigdelset +#undef sigismember + +int +sigemptyset(set) + sigset_t *set; +{ + *set = 0; + return (0); +} + +int +sigfillset(set) + sigset_t *set; +{ + *set = ~(sigset_t)0; + return (0); +} + +int +sigaddset(set, signo) + sigset_t *set; + int signo; +{ + *set |= sigmask(signo); + return (0); +} + +int +sigdelset(set, signo) + sigset_t *set; + int signo; +{ + *set &= ~sigmask(signo); + return (0); +} + +int +sigismember(set, signo) + sigset_t *set; + int signo; +{ + return ((*set & ~sigmask(signo)) != 0); +} diff --git a/src/libc/gen/sleep.c b/src/libc/gen/sleep.c new file mode 100644 index 0000000..09f395d --- /dev/null +++ b/src/libc/gen/sleep.c @@ -0,0 +1,47 @@ +/* + * Program: sleep.c + * Copyright: 1997, sms + * Author: Steven M. Schultz + * + * Version Date Modification + * 1.0 1997/9/25 1. Initial release. + */ + +#include /* For NULL */ +#include +#include +#include + +/* + * This implements the sleep(3) function using only 3 system calls instead of + * the 9 that the old implementation required. Also this version avoids using + * signals (with the attendant system overhead) and returns the amount of + * time left unslept if an interrupt occurs. + * + * The error status of gettimeofday is not checked because if that fails the + * program has scrambled the stack so badly that a sleep() failure is the least + * problem the program has. The select() call either completes successfully + * or is interrupted - no errors to be checked for. + */ +u_int +sleep(seconds) + u_int seconds; +{ + struct timeval f, s; + + if (seconds) { + gettimeofday(&f, NULL); + s.tv_sec = seconds; + s.tv_usec = 0; + select(0, NULL, NULL, NULL, &s); + gettimeofday(&s, NULL); + seconds -= (s.tv_sec - f.tv_sec); +/* + * ONLY way this can happen is if the system time gets set back while we're + * in the select() call. In this case return 0 instead of a bogus number. + */ + if (seconds < 0) + seconds = 0; + } + return(seconds); +} diff --git a/src/libc/gen/strcasecmp.c b/src/libc/gen/strcasecmp.c new file mode 100644 index 0000000..606ea9c --- /dev/null +++ b/src/libc/gen/strcasecmp.c @@ -0,0 +1,71 @@ +/* + * Copyright (c) 1987 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include + +/* + * This array is designed for mapping upper and lower case letter + * together for a case independent comparison. The mappings are + * based upon ascii character sequences. + */ +static char charmap[] = { + '\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007', + '\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017', + '\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027', + '\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037', + '\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047', + '\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057', + '\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067', + '\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077', + '\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147', + '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157', + '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167', + '\170', '\171', '\172', '\133', '\134', '\135', '\136', '\137', + '\140', '\141', '\142', '\143', '\144', '\145', '\146', '\147', + '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157', + '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167', + '\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177', + '\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', '\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', '\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', +}; + +int +strcasecmp(s1, s2) + register const char *s1, *s2; +{ + register char *cm = charmap; + + while (cm[(unsigned char)*s1] == cm[(unsigned char)*s2++]) + if (*s1++ == '\0') + return(0); + return(cm[(unsigned char)*s1] - cm[(unsigned char)*--s2]); +} + +int +strncasecmp(s1, s2, n) + register const char *s1, *s2; + register size_t n; +{ + register char *cm = charmap; + + while (--n >= 0 && cm[(unsigned char)*s1] == cm[(unsigned char)*s2++]) + if (*s1++ == '\0') + return(0); + return(n < 0 ? 0 : cm[(unsigned char)*s1] - cm[(unsigned char)*--s2]); +} diff --git a/src/libc/gen/strcat.c b/src/libc/gen/strcat.c new file mode 100644 index 0000000..16d1a15 --- /dev/null +++ b/src/libc/gen/strcat.c @@ -0,0 +1,21 @@ +/* + * Concatenate s2 on the end of s1. S1's space must be large enough. + * Return s1. + */ +#include + +char * +strcat(s1, s2) + register char *s1; + register const char *s2; +{ + register char *os1; + + os1 = s1; + while (*s1++) + ; + --s1; + while ((*s1++ = *s2++)) + ; + return(os1); +} diff --git a/src/libc/gen/strcmp-disabled.c b/src/libc/gen/strcmp-disabled.c new file mode 100644 index 0000000..f860673 --- /dev/null +++ b/src/libc/gen/strcmp-disabled.c @@ -0,0 +1,14 @@ +/* + * Compare strings: s1>s2: >0 s1==s2: 0 s1 + +strcmp(s1, s2) +register char *s1, *s2; +{ + + while (*s1 == *s2++) + if (*s1++=='\0') + return(0); + return(*s1 - *--s2); +} diff --git a/src/libc/gen/strcpy.c b/src/libc/gen/strcpy.c new file mode 100644 index 0000000..f6b2c10 --- /dev/null +++ b/src/libc/gen/strcpy.c @@ -0,0 +1,18 @@ +/* + * Copy string s2 to s1. s1 must be large enough. + * return s1 + */ +#include + +char * +strcpy(s1, s2) + register char *s1; + register const char *s2; +{ + register char *os1; + + os1 = s1; + while ((*s1++ = *s2++)) + ; + return(os1); +} diff --git a/src/libc/gen/strdup.c b/src/libc/gen/strdup.c new file mode 100644 index 0000000..a1ed7a6 --- /dev/null +++ b/src/libc/gen/strdup.c @@ -0,0 +1,35 @@ +/* + * Copyright (c) 1988 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ +#include +#include +#include +#include +#include + +char * +strdup(str) + const char *str; +{ + int len; + char *copy; + + len = strlen(str) + 1; + if (!(copy = malloc((u_int)len))) + return((char *)NULL); + bcopy(str, copy, len); + return(copy); +} diff --git a/src/libc/gen/strftime.c b/src/libc/gen/strftime.c new file mode 100644 index 0000000..d417843 --- /dev/null +++ b/src/libc/gen/strftime.c @@ -0,0 +1,264 @@ +/* + * 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. + */ +#include +#include +#include +#include +#include + +static char *Afmt[] = { + "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", + "Saturday", +}; +static char *Bfmt[] = { + "January", "February", "March", "April", "May", "June", "July", + "August", "September", "October", "November", "December", +}; + +static size_t gsize; +static char *pt; + +static int +_add(str) + register char *str; +{ + for (;; ++pt, --gsize) { + if (!gsize) + return(0); + if (!(*pt = *str++)) + return(1); + } +} + +static int +_conv(n, digits, pad) + int n, digits, pad; +{ + static char buf[10]; + register char *p; + + for (p = buf + sizeof(buf) - 2; n > 0 && p > buf; n /= 10, --digits) + *p-- = n % 10 + '0'; + while (p > buf && digits-- > 0) + *p-- = pad; + return(_add(++p)); +} + +static size_t +_fmt(format, t) + register const char *format; + register const struct tm *t; +{ + char ch, *cp, junk[4]; + + for (; *format; ++format) { + if (*format == '%') + switch(ch = *++format) { + case '\0': + --format; + break; + case 'A': + case 'a': + if (t->tm_wday < 0 || t->tm_wday > 6) + return(0); + if (ch == 'a') + { + bcopy(Afmt[t->tm_wday], junk, 3); + junk[3] = '\0'; + cp = junk; + } + else + cp = Afmt[t->tm_wday]; + if (!_add(cp)) + return(0); + continue; + case 'B': + case 'b': + case 'h': + if (t->tm_mon < 0 || t->tm_mon > 11) + return(0); + if (ch == 'b') + { + bcopy(Bfmt[t->tm_mon], junk, 3); + junk[3] = '\0'; + cp = junk; + } + else + cp = Bfmt[t->tm_mon]; + if (!_add(cp)) + return(0); + continue; + case 'C': + if (!_fmt("%a %b %e %H:%M:%S %Y", t)) + return(0); + continue; + case 'c': + if (!_fmt("%m/%d/%y %H:%M:%S", t)) + return(0); + continue; + case 'D': + if (!_fmt("%m/%d/%y", t)) + return(0); + continue; + case 'd': + if (!_conv(t->tm_mday, 2, '0')) + return(0); + continue; + case 'e': + if (!_conv(t->tm_mday, 2, ' ')) + return(0); + continue; + case 'H': + if (!_conv(t->tm_hour, 2, '0')) + return(0); + continue; + case 'I': + if (!_conv(t->tm_hour % 12 ? + t->tm_hour % 12 : 12, 2, '0')) + return(0); + continue; + case 'j': + if (!_conv(t->tm_yday + 1, 3, '0')) + return(0); + continue; + case 'k': + if (!_conv(t->tm_hour, 2, ' ')) + return(0); + continue; + case 'l': + if (!_conv(t->tm_hour % 12 ? + t->tm_hour % 12 : 12, 2, ' ')) + return(0); + continue; + case 'M': + if (!_conv(t->tm_min, 2, '0')) + return(0); + continue; + case 'm': + if (!_conv(t->tm_mon + 1, 2, '0')) + return(0); + continue; + case 'n': + if (!_add("\n")) + return(0); + continue; + case 'p': + if (!_add(t->tm_hour >= 12 ? "PM" : "AM")) + return(0); + continue; + case 'R': + if (!_fmt("%H:%M", t)) + return(0); + continue; + case 'r': + if (!_fmt("%I:%M:%S %p", t)) + return(0); + continue; + case 'S': + if (!_conv(t->tm_sec, 2, '0')) + return(0); + continue; + case 'T': + case 'X': + if (!_fmt("%H:%M:%S", t)) + return(0); + continue; + case 't': + if (!_add("\t")) + return(0); + continue; + case 'U': + if (!_conv((t->tm_yday + 7 - t->tm_wday) / 7, + 2, '0')) + return(0); + continue; + case 'W': + if (!_conv((t->tm_yday + 7 - + (t->tm_wday ? (t->tm_wday - 1) : 6)) + / 7, 2, '0')) + return(0); + continue; + case 'w': + if (!_conv(t->tm_wday, 1, '0')) + return(0); + continue; + case 'x': + if (!_fmt("%m/%d/%y", t)) + return(0); + continue; + case 'y': + if (!_conv((t->tm_year + TM_YEAR_BASE) + % 100, 2, '0')) + return(0); + continue; + case 'Y': + if (!_conv(t->tm_year + TM_YEAR_BASE, 4, '0')) + return(0); + continue; + case 'Z': + if (!t->tm_zone || !_add(t->tm_zone)) + return(0); + continue; + case '%': + /* + * X311J/88-090 (4.12.3.5): if conversion char is + * undefined, behavior is undefined. Print out the + * character itself as printf(3) does. + */ + default: + break; + } + if (!gsize--) + return(0); + *pt++ = *format; + } + return(gsize); +} + +size_t +strftime(s, maxsize, format, t) + char *s; + size_t maxsize; + const char *format; + const struct tm *t; +{ + + pt = s; + if ((gsize = maxsize) < 1) + return(0); + if (_fmt(format, t)) { + *pt = '\0'; + return(maxsize - gsize); + } + return(0); +} diff --git a/src/libc/gen/strlen-disabled.c b/src/libc/gen/strlen-disabled.c new file mode 100644 index 0000000..45d6c58 --- /dev/null +++ b/src/libc/gen/strlen-disabled.c @@ -0,0 +1,17 @@ +/* + * Returns the number of + * non-NULL bytes in string argument. + */ +#include + +int +strlen(s) + register char *s; +{ + register n; + + n = 0; + while (*s++) + n++; + return(n); +} diff --git a/src/libc/gen/strncat.c b/src/libc/gen/strncat.c new file mode 100644 index 0000000..84ae4ef --- /dev/null +++ b/src/libc/gen/strncat.c @@ -0,0 +1,26 @@ +/* + * Concatenate s2 on the end of s1. S1's space must be large enough. + * At most n characters are moved. + * Return s1. + */ +#include + +char * +strncat(s1, s2, n) + register char *s1; + register const char *s2; + register size_t n; +{ + register char *os1; + + os1 = s1; + while (*s1++) + ; + --s1; + while ((*s1++ = *s2++)) + if (--n < 0) { + *--s1 = '\0'; + break; + } + return(os1); +} diff --git a/src/libc/gen/strncmp.c b/src/libc/gen/strncmp.c new file mode 100644 index 0000000..82eaca2 --- /dev/null +++ b/src/libc/gen/strncmp.c @@ -0,0 +1,19 @@ +/* + * Compare strings (at most n bytes): s1>s2: >0 s1==s2: 0 s1 + +int +strncmp (s1, s2, n) + register const char *s1, *s2; + register size_t n; +{ + for (;;) { + if (n-- == 0) + return 0; + if (*s1 != *s2++) + return *s1 - *--s2; + if (*s1++ == '\0') + return 0; + } +} diff --git a/src/libc/gen/strncpy.c b/src/libc/gen/strncpy.c new file mode 100644 index 0000000..33d68c3 --- /dev/null +++ b/src/libc/gen/strncpy.c @@ -0,0 +1,24 @@ +/* + * Copy s2 to s1, truncating or null-padding to always copy n bytes + * return s1 + */ +#include + +char * +strncpy(s1, s2, n) + register char *s1; + register const char *s2; + size_t n; +{ + register int i; + register char *os1; + + os1 = s1; + for (i = 0; i < n; i++) + if ((*s1++ = *s2++) == '\0') { + while (++i < n) + *s1++ = '\0'; + return(os1); + } + return(os1); +} diff --git a/src/libc/gen/swab.c b/src/libc/gen/swab.c new file mode 100644 index 0000000..8fb0d18 --- /dev/null +++ b/src/libc/gen/swab.c @@ -0,0 +1,26 @@ +/* + * Swab bytes + * Jeffrey Mogul, Stanford + */ +void +swab (from, to, n) + register char *from, *to; + register int n; +{ +#ifdef pdp11 + register int temp; +#else + register unsigned long temp; +#endif + + n >>= 1; n++; +#define STEP temp = *from++,*to++ = *from++,*to++ = temp + /* round to multiple of 8 */ + while ((--n) & 07) + STEP; + n >>= 3; + while (--n >= 0) { + STEP; STEP; STEP; STEP; + STEP; STEP; STEP; STEP; + } +} diff --git a/src/libc/gen/sysctl.c b/src/libc/gen/sysctl.c new file mode 100644 index 0000000..dd17650 --- /dev/null +++ b/src/libc/gen/sysctl.c @@ -0,0 +1,126 @@ +/*- + * 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. + */ +#include +#include +#include +#include +#include + +int +sysctl(name, namelen, oldp, oldlenp, newp, newlen) + int *name; + u_int namelen; + void *oldp, *newp; + size_t *oldlenp, newlen; +{ + if (name[0] != CTL_USER) + return (__sysctl(name, namelen, oldp, oldlenp, newp, newlen)); + + if (newp != NULL) { + errno = EPERM; + return (-1); + } + if (namelen != 2) { + errno = EINVAL; + return (-1); + } + +/* + * This idea behind this section is silly. Other than 'bc' who cares about + * half of these? A 3/4 hearted attempt is made however to return numbers + * that are not totally bogus. + * + * Rather than port over the raft of include files with the attendant plethora + * of #define statements we just plug in the numbers from 4.4-Lite. + */ + + switch (name[1]) { + case USER_CS_PATH: + if (oldp && *oldlenp < sizeof(_PATH_SYSPATH)) + return (ENOMEM); + *oldlenp = sizeof(_PATH_SYSPATH); + if (oldp != NULL) + strcpy(oldp, _PATH_SYSPATH); + return (0); + } + + if (oldp && *oldlenp < sizeof(int)) + return (ENOMEM); + *oldlenp = sizeof(int); + if (oldp == NULL) + return (0); + + switch (name[1]) { + case USER_BC_BASE_MAX: + case USER_BC_SCALE_MAX: + *(int *)oldp = 99; + return (0); + case USER_BC_DIM_MAX: + *(int *)oldp = 2048; + return (0); + case USER_BC_STRING_MAX: + *(int *)oldp = 1000; + return (0); + case USER_EXPR_NEST_MAX: + *(int *)oldp = 32; + return (0); + case USER_LINE_MAX: + *(int *)oldp = 1024; + return (0); + case USER_RE_DUP_MAX: + *(int *)oldp = 255; + return (0); + case USER_COLL_WEIGHTS_MAX: + case USER_POSIX2_VERSION: + case USER_POSIX2_C_BIND: + case USER_POSIX2_C_DEV: + case USER_POSIX2_CHAR_TERM: + case USER_POSIX2_FORT_DEV: + case USER_POSIX2_FORT_RUN: + case USER_POSIX2_LOCALEDEF: + case USER_POSIX2_SW_DEV: + case USER_POSIX2_UPE: + *(int *)oldp = 0; + return (0); + case USER_STREAM_MAX: + *(int *)oldp = 20; + return (0); + case USER_TZNAME_MAX: + *(int *)oldp = 63; + return (0); + default: + errno = EINVAL; + return (-1); + } + /* NOTREACHED */ +} diff --git a/src/libc/gen/syslog.c b/src/libc/gen/syslog.c new file mode 100644 index 0000000..51276fe --- /dev/null +++ b/src/libc/gen/syslog.c @@ -0,0 +1,231 @@ +/* + * 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. + */ +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define STDERR_FILENO 2 + +static int LogFile = -1; /* fd for log */ +static int connected; /* have done connect */ +static int LogStat = 0; /* status bits, set by openlog() */ +static const char *LogTag = NULL; /* string to tag the entry with */ +static int LogFacility = LOG_USER; /* default facility code */ +static int LogMask = 0xff; /* mask of priorities to be logged */ +static char logfile[] = _PATH_MESSAGES; + +extern int errno; /* error number */ + +/* + * syslog, vsyslog -- + * print message on log file; output is intended for syslogd(8). + * No sockets: logfile is used. + */ +void +vsyslog(pri, fmt, ap) + int pri; + register const char *fmt; + va_list ap; +{ + int cnt; + char ch; + register char *p, *t; + time_t now; + int fd, saved_errno; + char *stdp = 0, tbuf[640], fmt_cpy[512]; + pid_t pid; + +#define INTERNALLOG LOG_ERR|LOG_CONS|LOG_PERROR|LOG_PID + /* Check for invalid bits. */ + if (pri & ~(LOG_PRIMASK|LOG_FACMASK)) { + syslog(INTERNALLOG, + "syslog: bad fac/pri: %x", pri); + pri &= LOG_PRIMASK|LOG_FACMASK; + } + + /* Check priority against setlogmask values. */ + if (! LOG_MASK(LOG_PRI(pri)) && LogMask) + return; + + saved_errno = errno; + + /* Set default facility if none specified. */ + if ((pri & LOG_FACMASK) == 0) + pri |= LogFacility; + + /* Build the message. */ + (void)time(&now); + p = tbuf + sprintf(tbuf, "<%d>", pri); + p += strftime(p, sizeof (tbuf) - (p - tbuf), "%h %e %T ", + localtime(&now)); + if (LogStat & LOG_PERROR) + stdp = p; + if (LogTag == NULL) + LogTag = __progname; + if (LogTag != NULL) + p += sprintf(p, "%s", LogTag); + if (LogStat & LOG_PID) + p += sprintf(p, "[%d]", getpid()); + if (LogTag != NULL) { + *p++ = ':'; + *p++ = ' '; + } + + /* Substitute error message for %m. */ + for (t = fmt_cpy; (ch = *fmt); ++fmt) + if (ch == '%' && fmt[1] == 'm') { + ++fmt; + t += sprintf(t, "%s", strerror(saved_errno)); + } else + *t++ = ch; + *t = '\0'; + + p += vsprintf(p, fmt_cpy, ap); + cnt = p - tbuf; + + /* Output to stderr if requested. */ + if (LogStat & LOG_PERROR) { + struct iovec iov[2]; + register struct iovec *v = iov; + + v->iov_base = stdp; + v->iov_len = cnt - (stdp - tbuf); + ++v; + v->iov_base = "\n"; + v->iov_len = 1; + (void)writev(STDERR_FILENO, iov, 2); + } + + /* Get connected, output the message to the local logger. */ + if (!connected) + openlog(LogTag, LogStat | LOG_NDELAY, 0); + (void)strcat(tbuf, "\r\n"); + cnt += 2; + if (write(LogFile, tbuf, cnt) == cnt) + return; + + /* + * Output the message to the console; don't worry about blocking, + * if console blocks everything will. Make sure the error reported + * is the one from the syslogd failure. + * + * 2.11BSD has to do a more complicated dance because we do not + * want to acquire a controlling terminal (bad news for 'init'!). + * Until either the tty driver is ported from 4.4 or O_NOCTTY + * is implemented we have to fork and let the child do the open of + * the console. + */ + if (LogStat & LOG_CONS) { + pid = vfork(); + if (pid == -1) + return; + if (pid == 0) { + fd = open(_PATH_CONSOLE, O_WRONLY, 0); + p = index(tbuf, '>') + 1; + (void)write(fd, p, cnt - (p - tbuf)); + (void)close(fd); + _exit(0); + } + while (waitpid(pid, NULL, NULL) == -1 && (errno == EINTR)) + ; + } +} + +void +syslog (int pri, const char *fmt, ...) +{ + va_list ap; + + va_start (ap, fmt); + vsyslog (pri, fmt, ap); + va_end (ap); +} + +void +openlog(ident, logstat, logfac) + const char *ident; + int logstat; + register int logfac; +{ + if (ident != NULL) + LogTag = ident; + LogStat = logstat; + if (logfac != 0 && (logfac &~ LOG_FACMASK) == 0) + LogFacility = logfac; + + if (LogFile == -1) { + if (LogStat & LOG_NDELAY) { + LogFile = open(logfile, O_WRONLY|O_APPEND); + connected = 1; + if (LogFile == -1) + return; + (void)fcntl(LogFile, F_SETFD, 1); + } + } + if (LogFile != -1 && !connected) { + (void)close(LogFile); + LogFile = -1; + } +} + +void +closelog() +{ + (void)close(LogFile); + LogFile = -1; + connected = 0; +} + +/* setlogmask -- set the log mask level */ +int +setlogmask(pmask) + register int pmask; +{ + register int omask; + + omask = LogMask; + if (pmask != 0) + LogMask = pmask; + return (omask); +} diff --git a/src/libc/gen/system.c b/src/libc/gen/system.c new file mode 100644 index 0000000..60cb754 --- /dev/null +++ b/src/libc/gen/system.c @@ -0,0 +1,72 @@ +/* + * Copyright (c) 1988 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include +#include +#include +#include +#include + +int +system(command) + char *command; +{ + union wait pstat; + register int pid; + sigset_t omask, nmask; + sig_t intsave, quitsave; + + if (!command) /* just checking... */ + return(1); + + sigemptyset(&nmask); + sigaddset(&nmask, SIGCHLD); + (void)sigprocmask(SIG_BLOCK, &nmask, &omask); + switch(pid = vfork()) { + case -1: /* error */ + (void)sigprocmask(SIG_SETMASK, &omask, NULL); + pstat.w_status = 0; + pstat.w_retcode = 127; + return(pstat.w_status); + case 0: /* child */ + (void)sigprocmask(SIG_SETMASK, &omask, NULL); + execl("/bin/sh", "sh", "-c", command, (char *)NULL); + _exit(127); + } + intsave = signal(SIGINT, SIG_IGN); + quitsave = signal(SIGQUIT, SIG_IGN); + pid = waitpid(pid, (int *)&pstat, 0); + (void)sigprocmask(SIG_SETMASK, &omask, NULL); + (void)signal(SIGINT, intsave); + (void)signal(SIGQUIT, quitsave); + return(pid == -1 ? -1 : pstat.w_status); +} diff --git a/src/libc/gen/telldir.c b/src/libc/gen/telldir.c new file mode 100644 index 0000000..ab768d4 --- /dev/null +++ b/src/libc/gen/telldir.c @@ -0,0 +1,19 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include +#include + +/* + * return a pointer into a directory + */ +long +telldir(dirp) + DIR *dirp; +{ + extern long lseek(); + + return (lseek(dirp->dd_fd, 0L, 1) - dirp->dd_size + dirp->dd_loc); +} diff --git a/src/libc/gen/time.c b/src/libc/gen/time.c new file mode 100644 index 0000000..8be45f2 --- /dev/null +++ b/src/libc/gen/time.c @@ -0,0 +1,24 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +/* + * Backwards compatible time call. + */ +#include +#include + +long +time(t) + time_t *t; +{ + struct timeval tt; + + if (gettimeofday(&tt, (struct timezone *)0) < 0) + return (-1); + if (t) + *t = tt.tv_sec; + return (tt.tv_sec); +} diff --git a/src/libc/gen/timezone.c b/src/libc/gen/timezone.c new file mode 100644 index 0000000..7d5fa9b --- /dev/null +++ b/src/libc/gen/timezone.c @@ -0,0 +1,99 @@ +/* + * Copyright (c) 1987 Regents of the University of California. + * This file may be freely redistributed provided that this + * notice remains attached. + */ +#include +#include +#include +#include +#include +#include +#include + +/* + * timezone -- + * The arguments are the number of minutes of time you are westward + * from Greenwich and whether DST is in effect. It returns a string + * giving the name of the local timezone. Should be replaced, in the + * application code, by a call to localtime. + */ + +static char czone[TZ_MAX_CHARS]; /* space for zone name */ + +char * +timezone(zone, dst) + int zone, + dst; +{ + register char *beg, + *end; + + beg = getenv("TZNAME"); + if (beg) { /* set in environment */ + end = index(beg, ','); + if (end) { /* "PST,PDT" */ + if (dst) + return(++end); + *end = '\0'; + (void)strncpy(czone,beg,sizeof(czone) - 1); + czone[sizeof(czone) - 1] = '\0'; + *end = ','; + return(czone); + } + return(beg); + } + return(tztab(zone,dst)); /* default: table or created zone */ +} + +static struct zone { + int offset; + char *stdzone; + char *dlzone; +} zonetab[] = { + { -1*60, "MET", "MET DST" }, /* Middle European */ + { -2*60, "EET", "EET DST" }, /* Eastern European */ + { 4*60, "AST", "ADT" }, /* Atlantic */ + { 5*60, "EST", "EDT" }, /* Eastern */ + { 6*60, "CST", "CDT" }, /* Central */ + { 7*60, "MST", "MDT" }, /* Mountain */ + { 8*60, "PST", "PDT" }, /* Pacific */ + { 0, "GMT", 0 }, /* Greenwich */ + { -10*60, "EST", "EST" }, /* Aust: Eastern */ + { -10*60+30, "CST", "CST" }, /* Aust: Central */ + { -8*60, "WST", 0 }, /* Aust: Western */ + { -1 }, +}; + +/* + * tztab -- + * check static tables or create a new zone name; broken out so that + * we can make a guess as to what the zone is if the standard tables + * aren't in place in /usr/share/misc. DO NOT USE THIS ROUTINE OUTSIDE + * OF THE STANDARD LIBRARY. + */ +char * +tztab(zone,dst) + register int zone; + int dst; +{ + register struct zone *zp; + register char sign; + + for (zp = zonetab; zp->offset != -1;++zp) /* static tables */ + if (zp->offset == zone) { + if (dst && zp->dlzone) + return(zp->dlzone); + if (!dst && zp->stdzone) + return(zp->stdzone); + } + + if (zone < 0) { /* create one */ + zone = -zone; + sign = '+'; + } + else + sign = '-'; + (void)sprintf(czone,"GMT%c%d:%02d",sign,zone / 60,zone % 60); + return(czone); +} diff --git a/src/libc/gen/ttyname.c b/src/libc/gen/ttyname.c new file mode 100644 index 0000000..a1d0aec --- /dev/null +++ b/src/libc/gen/ttyname.c @@ -0,0 +1,46 @@ +/* + * ttyname(f): return "/dev/ttyXX" which the the name of the + * tty belonging to file f. + * NULL if it is not a tty + */ +#include +#include +#include +#include +#include + +static char dev[] = "/dev/"; + +char * +ttyname(f) +{ + struct stat fsb; + struct stat tsb; + register struct direct *db; + register DIR *df; + static char rbuf[32]; + + if (isatty(f)==0) + return 0; + if (fstat(f, &fsb) < 0) + return 0; + if ((fsb.st_mode&S_IFMT) != S_IFCHR) + return 0; + df = opendir(dev); + if (! df) + return 0; + while ((db = readdir(df))) { + if (db->d_ino != fsb.st_ino) + continue; + strcpy(rbuf, dev); + strcat(rbuf, db->d_name); + if (stat(rbuf, &tsb) < 0) + continue; + if (tsb.st_dev == fsb.st_dev && tsb.st_ino == fsb.st_ino) { + closedir(df); + return(rbuf); + } + } + closedir(df); + return 0; +} diff --git a/src/libc/gen/ttyslot.c b/src/libc/gen/ttyslot.c new file mode 100644 index 0000000..d5d8c26 --- /dev/null +++ b/src/libc/gen/ttyslot.c @@ -0,0 +1,43 @@ +/* + * Copyright (c) 1984 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +/* + * Return the number of the slot in the utmp file + * corresponding to the current user: try for file 0, 1, 2. + * Definition is the line number in the /etc/ttys file. + */ +#include +#include +#include + +int +ttyslot() +{ + register struct ttyent *ty; + register char *tp, *p; + register int s; + + if (! (tp = ttyname(0)) && + ! (tp = ttyname(1)) && + ! (tp = ttyname(2))) + return 0; + p = strrchr(tp, '/'); + if (! p) + p = tp; + else + p++; + setttyent(); + s = 0; + while ((ty = getttyent())) { + s++; + if (strcmp(ty->ty_name, p) == 0) { + endttyent(); + return s; + } + } + endttyent(); + return 0; +} diff --git a/src/libc/gen/ualarm.c b/src/libc/gen/ualarm.c new file mode 100644 index 0000000..412f376 --- /dev/null +++ b/src/libc/gen/ualarm.c @@ -0,0 +1,32 @@ +/* + * Copyright (c) 1985 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include + +#define USPS 1000000 /* # of microseconds in a second */ + +/* + * Generate a SIGALRM signal in ``usecs'' microseconds. + * If ``reload'' is non-zero, keep generating SIGALRM + * every ``reload'' microseconds after the first signal. + */ +unsigned +ualarm(usecs, reload) + register unsigned usecs; + register unsigned reload; +{ + struct itimerval new, old; + + new.it_interval.tv_usec = reload % USPS; + new.it_interval.tv_sec = reload / USPS; + + new.it_value.tv_usec = usecs % USPS; + new.it_value.tv_sec = usecs / USPS; + + if (setitimer(ITIMER_REAL, &new, &old) == 0) + return (old.it_value.tv_sec * USPS + old.it_value.tv_usec); + /* else */ + return (-1); +} diff --git a/src/libc/gen/uname.c b/src/libc/gen/uname.c new file mode 100644 index 0000000..d0cf8ef --- /dev/null +++ b/src/libc/gen/uname.c @@ -0,0 +1,87 @@ +/*- + * 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. + */ +#include +#include +#include + +int +uname(name) + register struct utsname *name; +{ + int mib[2], rval; + size_t len; + register char *p; + + rval = 0; + + mib[0] = CTL_KERN; + mib[1] = KERN_OSTYPE; + len = sizeof(name->sysname); + if (sysctl(mib, 2, &name->sysname, &len, NULL, 0) == -1) + rval = -1; + + mib[0] = CTL_KERN; + mib[1] = KERN_HOSTNAME; + len = sizeof(name->nodename); + if (sysctl(mib, 2, &name->nodename, &len, NULL, 0) == -1) + rval = -1; + + mib[0] = CTL_KERN; + mib[1] = KERN_OSRELEASE; + len = sizeof(name->release); + if (sysctl(mib, 2, &name->release, &len, NULL, 0) == -1) + rval = -1; + + /* The version may have newlines in it, turn them into spaces. */ + mib[0] = CTL_KERN; + mib[1] = KERN_VERSION; + len = sizeof(name->version); + if (sysctl(mib, 2, &name->version, &len, NULL, 0) == -1) + rval = -1; + else + for (p = name->version; len--; ++p) { + if (*p == '\n' || *p == '\t') { + if (len > 1) + *p = ' '; + else + *p = '\0'; + } + } + + mib[0] = CTL_HW; + mib[1] = HW_MACHINE; + len = sizeof(name->machine); + if (sysctl(mib, 2, &name->machine, &len, NULL, 0) == -1) + rval = -1; + return (rval); +} diff --git a/src/libc/gen/usleep.c b/src/libc/gen/usleep.c new file mode 100644 index 0000000..39bbf8b --- /dev/null +++ b/src/libc/gen/usleep.c @@ -0,0 +1,32 @@ +/* + * Program: sleep.c + * Copyright: 1997, sms + * Author: Steven M. Schultz + * + * Version Date Modification + * 1.0 1997/9/26 1. Initial release. + */ +#include /* For NULL */ +#include +#include + +/* + * This implements the usleep(3) function using only 1 system call (select) + * instead of the 9 that the old implementation required. Also this version + * avoids using signals (with the attendant system overhead). + * + * Nothing is returned and if less than ~20000 microseconds is specified the + * select will return without any delay at all. + */ +void +usleep(micros) + long micros; +{ + struct timeval s; + + if (micros > 0) { + s.tv_sec = micros / 1000000L; + s.tv_usec = micros % 1000000L; + select(0, NULL, NULL, NULL, &s); + } +} diff --git a/src/libc/gen/valloc.c b/src/libc/gen/valloc.c new file mode 100644 index 0000000..2fab9a4 --- /dev/null +++ b/src/libc/gen/valloc.c @@ -0,0 +1,26 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include + +char * +valloc(i) + int i; +{ +#ifdef pdp11 + /* + * page boudaries don't mean anything on a PDP-11 and the cost in + * memory is just too prohibitive to blindly use the non-PDP-11 + * algorithm. + */ + return(malloc(i)); +#else + int valsiz = getpagesize(), j; + char *cp = malloc(i + (valsiz-1)); + + j = ((int)cp + (valsiz-1)) &~ (valsiz-1); + return ((char *)j); +#endif +} diff --git a/src/libc/gen/wait.c b/src/libc/gen/wait.c new file mode 100644 index 0000000..8fc6ac9 --- /dev/null +++ b/src/libc/gen/wait.c @@ -0,0 +1,43 @@ +/* + * Copyright (c) 1988 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include +#include +#include +#include + +int +wait(istat) + int *istat; +{ + return (wait4(WAIT_ANY, istat, 0, (struct rusage *)0)); +} diff --git a/src/libc/gen/wait3.c b/src/libc/gen/wait3.c new file mode 100644 index 0000000..f1621a2 --- /dev/null +++ b/src/libc/gen/wait3.c @@ -0,0 +1,45 @@ +/* + * Copyright (c) 1988 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include +#include +#include +#include + +int +wait3(istat, options, rup) + int *istat; + int options; + struct rusage *rup; +{ + return (wait4(WAIT_ANY, istat, options, rup)); +} diff --git a/src/libc/gen/waitpid.c b/src/libc/gen/waitpid.c new file mode 100644 index 0000000..0edcd96 --- /dev/null +++ b/src/libc/gen/waitpid.c @@ -0,0 +1,45 @@ +/* + * Copyright (c) 1988 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include +#include +#include +#include + +int +waitpid(pid, istat, options) + int pid; + int *istat; + int options; +{ + return (wait4(pid, istat, options, (struct rusage *)0)); +} diff --git a/src/libc/inet/Makefile b/src/libc/inet/Makefile new file mode 100644 index 0000000..dde564f --- /dev/null +++ b/src/libc/inet/Makefile @@ -0,0 +1,46 @@ +# +# Copyright (c) 1980 Regents of the University of California. +# All rights reserved. The Berkeley software License Agreement +# specifies the terms and conditions for redistribution. +# +TOPSRC = $(shell cd ../../..; pwd) +include $(TOPSRC)/target.mk + +SRCS = inet_addr.c inet_network.c inet_netof.c \ + inet_ntoa.c inet_lnaof.c inet_maddr.c +OBJS = inet_addr.o inet_network.o inet_netof.o \ + inet_ntoa.o inet_lnaof.o inet_maddr.o + +CFLAGS += ${DEFS} -Os + +inet.a: ${OBJS} + @echo "building inet.a" + @ar cru inet.a ${OBJS} + +tags: + cwd=`pwd`; \ + for i in ${SRCS}; do \ + ctags -a -f ${TAGSFILE} $$cwd/$$i; \ + done + +clean: + rm -f *.a *~ *.o profiled/*.o errs a.out core tags Makefile.bak + +depend: + for i in ${SRCS}; do \ + cc -M ${CFLAGS} $$i | 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 } ' >> makedep; done + echo '/^# DO NOT DELETE THIS LINE/+2,$$d' >eddep + echo '$$r makedep' >>eddep + echo 'w' >>eddep + cp Makefile Makefile.bak + ed - Makefile < eddep + rm eddep makedep + echo '# DEPENDENCIES MUST END AT END OF FILE' >> Makefile + echo '# IF YOU PUT STUFF HERE IT WILL GO AWAY' >> Makefile + echo '# see make depend above' >> Makefile + +# DO NOT DELETE THIS LINE -- make depend uses it diff --git a/src/libc/inet/inet_addr.c b/src/libc/inet/inet_addr.c new file mode 100644 index 0000000..4015add --- /dev/null +++ b/src/libc/inet/inet_addr.c @@ -0,0 +1,99 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include +#include +#include +#include + +/* + * Internet address interpretation routine. + * All the network library routines call this + * routine to interpret entries in the data bases + * which are expected to be an address. + * The value returned is in network order. + */ +u_long +inet_addr(cp) + register char *cp; +{ + register u_long val, base; + register u_int n; /* can't switch on longs - should be an int anyway */ + register char c; + u_long parts[4], *pp = parts; + +again: + /* + * Collect number up to ``.''. + * Values are specified as for C: + * 0x=hex, 0=octal, other=decimal. + */ + val = 0; base = 10; + if (*cp == '0') + base = 8, cp++; + if (*cp == 'x' || *cp == 'X') + base = 16, cp++; + while ((c = *cp)) { + if (isdigit(c)) { + val = (val * base) + (c - '0'); + cp++; + continue; + } + if (base == 16 && isxdigit(c)) { + val = (val << 4) + (c + 10 - (islower(c) ? 'a' : 'A')); + cp++; + continue; + } + break; + } + if (*cp == '.') { + /* + * Internet format: + * a.b.c.d + * a.b.c (with c treated as 16-bits) + * a.b (with b treated as 24 bits) + */ + if (pp >= parts + 4) + return (-1); + *pp++ = val, cp++; + goto again; + } + /* + * Check for trailing characters. + */ + if (*cp && !isspace(*cp)) + return (-1); + *pp++ = val; + /* + * Concoct the address according to + * the number of parts specified. + */ + n = pp - parts; + switch (n) { + + case 1: /* a -- 32 bits */ + val = parts[0]; + break; + + case 2: /* a.b -- 8.24 bits */ + val = (parts[0] << 24) | (parts[1] & 0xffffff); + break; + + case 3: /* a.b.c -- 8.8.16 bits */ + val = (parts[0] << 24) | ((parts[1] & 0xff) << 16) | + (parts[2] & 0xffffL); + break; + + case 4: /* a.b.c.d -- 8.8.8.8 bits */ + val = (parts[0] << 24) | ((parts[1] & 0xff) << 16) | + ((parts[2] & 0xff) << 8) | (parts[3] & 0xff); + break; + + default: + return (-1); + } + val = htonl(val); + return (val); +} diff --git a/src/libc/inet/inet_lnaof.c b/src/libc/inet/inet_lnaof.c new file mode 100644 index 0000000..a35dbf1 --- /dev/null +++ b/src/libc/inet/inet_lnaof.c @@ -0,0 +1,27 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include +#include +#include + +/* + * Return the local network address portion of an + * internet address; handles class a/b/c network + * number formats. + */ +u_long +inet_lnaof(in) + struct in_addr in; +{ + register u_long i = ntohl(in.s_addr); + + if (IN_CLASSA(i)) + return ((i)&IN_CLASSA_HOST); + else if (IN_CLASSB(i)) + return ((i)&IN_CLASSB_HOST); + else + return ((i)&IN_CLASSC_HOST); +} diff --git a/src/libc/inet/inet_maddr.c b/src/libc/inet/inet_maddr.c new file mode 100644 index 0000000..e94112d --- /dev/null +++ b/src/libc/inet/inet_maddr.c @@ -0,0 +1,28 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include +#include +#include + +/* + * Formulate an Internet address from network + host. Used in + * building addresses stored in the ifnet structure. + */ +struct in_addr +inet_makeaddr(net, host) + long net, host; +{ + u_long addr; + + if (net < 128) + addr = (net << IN_CLASSA_NSHIFT) | (host & IN_CLASSA_HOST); + else if (net < 65536L) + addr = (net << IN_CLASSB_NSHIFT) | (host & IN_CLASSB_HOST); + else + addr = (net << IN_CLASSC_NSHIFT) | (host & IN_CLASSC_HOST); + addr = htonl(addr); + return (*(struct in_addr *)&addr); +} diff --git a/src/libc/inet/inet_netof.c b/src/libc/inet/inet_netof.c new file mode 100644 index 0000000..fb0aeb9 --- /dev/null +++ b/src/libc/inet/inet_netof.c @@ -0,0 +1,53 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include +#include +#include + +/* + * Return the network number from an internet + * address; handles class a/b/c network #'s. + */ +u_long +inet_netof(in) + struct in_addr in; +{ + u_long i = ntohl(in.s_addr); + + if (IN_CLASSA(i)) + return (((i)&IN_CLASSA_NET) >> IN_CLASSA_NSHIFT); + else if (IN_CLASSB(i)) + return (((i)&IN_CLASSB_NET) >> IN_CLASSB_NSHIFT); + else + return (((i)&IN_CLASSC_NET) >> IN_CLASSC_NSHIFT); +} diff --git a/src/libc/inet/inet_network.c b/src/libc/inet/inet_network.c new file mode 100644 index 0000000..eb22fa5 --- /dev/null +++ b/src/libc/inet/inet_network.c @@ -0,0 +1,61 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include +#include +#include +#include + +/* + * Internet network address interpretation routine. + * The library routines call this routine to interpret + * network numbers. + */ +u_long +inet_network(cp) + register char *cp; +{ + register u_long val, base, n; + register char c; + u_long parts[4], *pp = parts; + register int i; + +again: + val = 0; base = 10; + if (*cp == '0') + base = 8, cp++; + if (*cp == 'x' || *cp == 'X') + base = 16, cp++; + while ((c = *cp)) { + if (isdigit(c)) { + val = (val * base) + (c - '0'); + cp++; + continue; + } + if (base == 16 && isxdigit(c)) { + val = (val << 4) + (c + 10 - (islower(c) ? 'a' : 'A')); + cp++; + continue; + } + break; + } + if (*cp == '.') { + if (pp >= parts + 4) + return (-1); + *pp++ = val, cp++; + goto again; + } + if (*cp && !isspace(*cp)) + return (-1); + *pp++ = val; + n = pp - parts; + if (n > 4) + return (-1); + for (val = 0, i = 0; i < n; i++) { + val <<= 8; + val |= parts[i] & 0xff; + } + return (val); +} diff --git a/src/libc/inet/inet_ntoa.c b/src/libc/inet/inet_ntoa.c new file mode 100644 index 0000000..50dd42d --- /dev/null +++ b/src/libc/inet/inet_ntoa.c @@ -0,0 +1,27 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +/* + * Convert network-format internet address + * to base 256 d.d.d.d representation. + */ +#include +#include +#include +#include + +char * +inet_ntoa(in) + struct in_addr in; +{ + static char b[18]; + register char *p; + + p = (char *)∈ +#define UC(b) (((int)b)&0xff) + sprintf(b, "%d.%d.%d.%d", UC(p[0]), UC(p[1]), UC(p[2]), UC(p[3])); + return (b); +} diff --git a/src/libc/mips/Makefile b/src/libc/mips/Makefile new file mode 100644 index 0000000..87fb931 --- /dev/null +++ b/src/libc/mips/Makefile @@ -0,0 +1,35 @@ +# +# Copyright (c) 1987 Regents of the University of California. +# All rights reserved. The Berkeley software License Agreement +# specifies the terms and conditions for redistribution. +# +# Machine dependent routines for the MIPS are located here +# +TOPSRC = $(shell cd ../../..; pwd) +include $(TOPSRC)/target.mk + +ALL = gen string sys + +mips.a: ${ALL} + -mkdir tmp + for i in ${ALL}; do (cd tmp; $(AR) x ../$$i/$$i.a); done + $(AR) cr mips.a `ls tmp/*.o | sort` + rm -rf tmp + +${ALL}: FRC + cd $@; make ${MFLAGS} DEFS=${DEFS} + +FRC: + +tags: + for i in ${ALL}; do \ + (cd $$i; make ${MFLAGS} TAGSFILE=../${TAGSFILE} tags); \ + done + +clean: + for i in ${ALL}; do (cd $$i; make ${MFLAGS} clean); done + rm -rf *.a tmp *~ + +depend: + for i in ${ALL}; do \ + (cd $$i; make ${MFLAGS} DEFS=${DEFS} depend); done diff --git a/src/libc/mips/gen/Makefile b/src/libc/mips/gen/Makefile new file mode 100644 index 0000000..57bf27e --- /dev/null +++ b/src/libc/mips/gen/Makefile @@ -0,0 +1,44 @@ +# +# Copyright (c) 1980 Regents of the University of California. +# All rights reserved. The Berkeley software License Agreement +# specifies the terms and conditions for redistribution. +# +TOPSRC = $(shell cd ../../../..; pwd) +include $(TOPSRC)/target.mk + +CFLAGS += ${DEFS} + +SRCS = _setjmp.S htonl.S htons.S setjmp.S sigsetjmp.S +OBJS = _setjmp.o htonl.o htons.o setjmp.o sigsetjmp.o + +gen.a: ${OBJS} + @echo "buiding gen.a" + @$(AR) cru gen.a ${OBJS} + +tags: + cwd=`pwd`; \ + for i in ${SRCS}; do \ + ctags -a -f ${TAGSFILE} $$cwd/$$i; \ + done + +clean: + rm -f gen.a *.o *~ profiled/*.o tags Makefile.bak + +depend: + for i in ${SRCS}; do \ + cc -M ${CFLAGS} $$i | 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 } ' >> makedep; done + echo '/^# DO NOT DELETE THIS LINE/+2,$$d' >eddep + echo '$$r makedep' >>eddep + echo 'w' >>eddep + cp Makefile Makefile.bak + ed - Makefile < eddep + rm eddep makedep + echo '# DEPENDENCIES MUST END AT END OF FILE' >> Makefile + echo '# IF YOU PUT STUFF HERE IT WILL GO AWAY' >> Makefile + echo '# see make depend above' >> Makefile + +# DO NOT DELETE THIS LINE -- make depend uses it diff --git a/src/libc/mips/gen/_setjmp.S b/src/libc/mips/gen/_setjmp.S new file mode 100644 index 0000000..56767d4 --- /dev/null +++ b/src/libc/mips/gen/_setjmp.S @@ -0,0 +1,85 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Ralph Campbell. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * C library -- _setjmp, _longjmp + * + * _longjmp(a,v) + * will generate a "return(v)" from + * the last call to + * _setjmp(a) + * by restoring registers from the stack, + * The previous signal state is NOT restored. + */ + .set noreorder + + .type _setjmp, @function +_setjmp: .globl _setjmp + + sw $s0, (0 * 4) ($a0) # save register variables s0-s8 + sw $s1, (1 * 4) ($a0) + sw $s2, (2 * 4) ($a0) + sw $s3, (3 * 4) ($a0) + sw $s4, (4 * 4) ($a0) + sw $s5, (5 * 4) ($a0) + sw $s6, (6 * 4) ($a0) + sw $s7, (7 * 4) ($a0) + sw $s8, (8 * 4) ($a0) # frame pointer + sw $ra, (9 * 4) ($a0) # return address + sw $gp, (10 * 4) ($a0) # global data pointer + sw $sp, (11 * 4) ($a0) # stack pointer + + # For compatibility with longjmp and siglongjmp + sw $zero, (12 * 4) ($a0) # signal mask saved + sw $zero, (13 * 4) ($a0) # signal mask + + j $ra + move $v0, $zero # return a zero for the setjmp call + + .type _longjmp, @function +_longjmp: .globl _longjmp + + lw $s0, (0 * 4) ($a0) # restore register variables s0-s8 + lw $s1, (1 * 4) ($a0) + lw $s2, (2 * 4) ($a0) + lw $s3, (3 * 4) ($a0) + lw $s4, (4 * 4) ($a0) + lw $s5, (5 * 4) ($a0) + lw $s6, (6 * 4) ($a0) + lw $s7, (7 * 4) ($a0) + lw $s8, (8 * 4) ($a0) # frame pointer + lw $ra, (9 * 4) ($a0) # return address + lw $gp, (10 * 4) ($a0) # global data pointer + lw $sp, (11 * 4) ($a0) # stack pointer + + j $ra # transfer back to setjmp() + move $v0, $a1 # get return value in 1st arg diff --git a/src/libc/mips/gen/htonl.S b/src/libc/mips/gen/htonl.S new file mode 100644 index 0000000..f9b18c7 --- /dev/null +++ b/src/libc/mips/gen/htonl.S @@ -0,0 +1,58 @@ +/*- + * Copyright (c) 1997 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Neil A. Carson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +# +# a0 = 0x11223344, return 0x44332211 +# + .type htonl, @function +htonl: .globl htonl + .type ntohl, @function +ntohl: .globl ntohl + +#ifdef __MIPSEB__ + move $v0, $a0 +#else + srl $v1, $a0, 24 # v1 = 0x00000011 + sll $v0, $a0, 24 # v0 = 0x44000000 + or $v0, $v0, $v1 + andi $v1, $a0, 0xff00 + sll $v1, $v1, 8 # v1 = 0x00330000 + or $v0, $v0, $v1 + srl $v1, $a0, 8 + andi $v1, $v1, 0xff00 # v1 = 0x00002200 + or $v0, $v0, $v1 +#endif + j $ra diff --git a/src/libc/mips/gen/htons.S b/src/libc/mips/gen/htons.S new file mode 100644 index 0000000..d4905c7 --- /dev/null +++ b/src/libc/mips/gen/htons.S @@ -0,0 +1,50 @@ +/*- + * Copyright (c) 1999 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Charles M. Hannum. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + + .type htons, @function +htons: .globl htons + .type ntohs, @function +ntohs: .globl ntohs +#ifdef __MIPSEB__ + move $v0, $a0 +#else + srl $v0, $a0, 8 + andi $v0, $v0, 0xff + sll $v1, $a0, 8 + andi $v1, $v1, 0xff00 + or $v0, $v0, $v1 +#endif + j $ra diff --git a/src/libc/mips/gen/setjmp.S b/src/libc/mips/gen/setjmp.S new file mode 100644 index 0000000..d18116d --- /dev/null +++ b/src/libc/mips/gen/setjmp.S @@ -0,0 +1,117 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Ralph Campbell. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * C library -- setjmp, longjmp + * + * longjmp(a,v) + * will generate a "return(v)" from + * the last call to + * setjmp(a) + * by restoring registers from the stack, + * and a struct sigcontext, see + * + * From: Chris Dearman + */ + .set noreorder + + .type setjmp, @function +setjmp: .globl setjmp + + subu $sp, 24 + sw $ra, 20($sp) + sw $a0, 24($sp) + + /* Get the signal mask. */ + addu $a2, $a0, 13*4 # &omask + li $a0, 1 # SIG_BLOCK + jal sigprocmask # get current signal mask + move $a1, $0 # BDS: NULL + + lw $a0, 24($sp) + lw $ra, 20($sp) + addu $sp, 24 + + li $t0, 1 + sw $t0, (12 * 4)($a0) + + sw $s0, (0 * 4) ($a0) # save register variables s0-s8 + sw $s1, (1 * 4) ($a0) + sw $s2, (2 * 4) ($a0) + sw $s3, (3 * 4) ($a0) + sw $s4, (4 * 4) ($a0) + sw $s5, (5 * 4) ($a0) + sw $s6, (6 * 4) ($a0) + sw $s7, (7 * 4) ($a0) + sw $s8, (8 * 4) ($a0) # frame pointer + sw $ra, (9 * 4) ($a0) # return address + sw $gp, (10 * 4) ($a0) # global data pointer + sw $sp, (11 * 4) ($a0) # stack pointer + + j $ra + move $v0, $zero # BDS: return a zero for the setjmp call + + + .type longjmp, @function +longjmp: .globl longjmp + + subu $sp, 24 + sw $ra, 20($sp) + sw $a0, 24($sp) + sw $a1, 28($sp) + + /* Restore signal mask. */ + addu $a1, $a0, 13*4 # &omask + move $a2, $0 # NULL + jal sigprocmask # set current signal mask + li $a0, 3 # BDS: SIG_SETMASK + + lw $a1, 28($sp) + lw $a0, 24($sp) + lw $ra, 20($sp) + addu $sp, 24 + + lw $s0, (0 * 4) ($a0) # restore register variables s0-s8 + lw $s1, (1 * 4) ($a0) + lw $s2, (2 * 4) ($a0) + lw $s3, (3 * 4) ($a0) + lw $s4, (4 * 4) ($a0) + lw $s5, (5 * 4) ($a0) + lw $s6, (6 * 4) ($a0) + lw $s7, (7 * 4) ($a0) + lw $s8, (8 * 4) ($a0) # frame pointer + lw $ra, (9 * 4) ($a0) # return address + lw $gp, (10 * 4) ($a0) # global data pointer + lw $sp, (11 * 4) ($a0) # stack pointer + + j $ra + move $v0, $a1 # BDS: return value from longjmp diff --git a/src/libc/mips/gen/sigsetjmp.S b/src/libc/mips/gen/sigsetjmp.S new file mode 100644 index 0000000..4af651f --- /dev/null +++ b/src/libc/mips/gen/sigsetjmp.S @@ -0,0 +1,67 @@ +/*- + * Copyright (c) 1991, 1993, 1995, + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Havard Eidnes. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * C library -- sigsetjmp, siglongjmp + * + * siglongjmp(a,v) + * will generate a "return(v)" from + * the last call to + * sigsetjmp(a, savemask) + * by restoring registers from the stack, + * and dependent on savemask restores the + * signal mask. + * + * From: Chris Dearman + */ + .set noreorder + + .type sigsetjmp, @function +sigsetjmp: .globl sigsetjmp + + bne $a1, 0x0, 1f # do saving of signal mask? + nop + j _setjmp + nop +1: j setjmp + nop + + .type siglongjmp, @function +siglongjmp: .globl siglongjmp + + lw $t0, (12 * 4)($a0) + bnez $t0, 1f + nop + j _longjmp + nop +1: j longjmp + nop diff --git a/src/libc/mips/string/Makefile b/src/libc/mips/string/Makefile new file mode 100644 index 0000000..0189b95 --- /dev/null +++ b/src/libc/mips/string/Makefile @@ -0,0 +1,52 @@ +# +# Copyright (c) 1980 Regents of the University of California. +# All rights reserved. The Berkeley software License Agreement +# specifies the terms and conditions for redistribution. +# +TOPSRC = $(shell cd ../../../..; pwd) +include $(TOPSRC)/target.mk + +CFLAGS += ${DEFS} + +# +# Endian-independent assembly-code aliases for unaligned memory accesses. +# Little endian. +# +ASFLAGS += -DLWHI=lwr -DLWLO=lwl -DSWHI=swr -DSWLO=swl + +SRCS = bcopy.S bzero.S ffs.S memcpy.S memmove.S memset.S \ + strlen.S bcmp.S index.S rindex.S strcmp.S +OBJS = bcopy.o bzero.o ffs.o memcpy.o memmove.o memset.o \ + strlen.o bcmp.o index.o rindex.o strcmp.o + +string.a: ${OBJS} + @echo "buiding string.a" + @$(AR) cru string.a ${OBJS} + +tags: + cwd=`pwd`; \ + for i in ${SRCS}; do \ + ctags -a -f ${TAGSFILE} $$cwd/$$i; \ + done + +clean: + rm -f string.a *.o *~ profiled/*.o tags Makefile.bak + +depend: + for i in ${SRCS}; do \ + cc -M ${CFLAGS} $$i | 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 } ' >> makedep; done + echo '/^# DO NOT DELETE THIS LINE/+2,$$d' >eddep + echo '$$r makedep' >>eddep + echo 'w' >>eddep + cp Makefile Makefile.bak + ed - Makefile < eddep + rm eddep makedep + echo '# DEPENDENCIES MUST END AT END OF FILE' >> Makefile + echo '# IF YOU PUT STUFF HERE IT WILL GO AWAY' >> Makefile + echo '# see make depend above' >> Makefile + +# DO NOT DELETE THIS LINE -- make depend uses it diff --git a/src/libc/mips/string/bcmp.S b/src/libc/mips/string/bcmp.S new file mode 100644 index 0000000..bd6ab21 --- /dev/null +++ b/src/libc/mips/string/bcmp.S @@ -0,0 +1,113 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Ralph Campbell. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* bcmp(s1, s2, n) */ + + .type bcmp, @function +bcmp: .globl bcmp + .set noreorder + .set noat + + slti $at, $a2, 16 # small amount to clear? + bnez $at, small # is it worth any trouble? + xor $v0, $a0, $a1 # compare low two bits of addresses + andi $v0, $v0, 3 + subu $a3, $zero, $a1 # compute # bytes to word align address + bne $v0, $zero, unaligned # not possible to align addresses + andi $a3, $a3, 3 + + beq $a3, $zero, 1f + subu $a2, $a2, $a3 # subtract from remaining count + move $v0, $v1 # init v0,v1 so unmodified bytes match + LWHI $v0, 0($a0) # read 1, 2, or 3 bytes + LWHI $v1, 0($a1) + addu $a1, $a1, $a3 + bne $v0, $v1, nomatch + addu $a0, $a0, $a3 +1: + li $at, ~3 + and $a3, $a2, $at # compute number of whole words left + subu $a2, $a2, $a3 # which has to be >= (16-3) & ~3 + addu $a3, $a3, $a0 # compute ending address +2: + lw $v0, 0($a0) # compare words + lw $v1, 0($a1) + addiu $a0, $a0, 4 + bne $v0, $v1, nomatch + addiu $a1, $a1, 4 + bne $a0, $a3, 2b + nop + b small # finish remainder + nop +unaligned: + beq $a3, $zero, 2f + subu $a2, $a2, $a3 # subtract from remaining count + addu $a3, $a3, $a0 # compute ending address +1: + lbu $v0, 0($a0) # compare bytes until a1 word aligned + lbu $v1, 0($a1) + addiu $a0, $a0, 1 + bne $v0, $v1, nomatch + addiu $a1, $a1, 1 + bne $a0, $a3, 1b + nop +2: + li $at, ~3 + and $a3, $a2, $at # compute number of whole words left + subu $a2, $a2, $a3 # which has to be >= (16-3) & ~3 + addu $a3, $a3, $a0 # compute ending address +3: + LWHI $v0, 0($a0) # compare words a0 unaligned, a1 aligned + LWLO $v0, 3($a0) + lw $v1, 0($a1) + addiu $a0, $a0, 4 + bne $v0, $v1, nomatch + addiu $a1, $a1, 4 + bne $a0, $a3, 3b + nop +small: + blez $a2, match + addu $a3, $a2, $a0 # compute ending address +1: + lbu $v0, 0($a0) + lbu $v1, 0($a1) + addiu $a0, $a0, 1 + bne $v0, $v1, nomatch + addiu $a1, $a1, 1 + bne $a0, $a3, 1b + nop +match: + j $ra + move $v0, $zero +nomatch: + j $ra + li $v0, 1 diff --git a/src/libc/mips/string/bcopy.S b/src/libc/mips/string/bcopy.S new file mode 100644 index 0000000..1890880 --- /dev/null +++ b/src/libc/mips/string/bcopy.S @@ -0,0 +1,270 @@ +/* + * Fast copy routine. Derived from aligned_block_copy. + ^ + * bcopy(caddr_t src, caddr_t dst, unsigned int len) + * + * a0 src address + * a1 dst address + * a2 length + * + * Author: Chris Maeda + * Date: June 1993 + * + * Mach Operating System + * Copyright (c) 1993 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +#if defined(MEMCOPY) || defined(MEMMOVE) +# ifdef MEMCOPY +# define FUNCTION memcpy +# else +# define FUNCTION memmove +# endif +# define SRCREG $a1 +# define DSTREG $a0 +#else +# define FUNCTION bcopy +# define SRCREG $a0 +# define DSTREG $a1 +#endif + +#define SIZEREG $a2 + + .globl FUNCTION + .type FUNCTION, @function +FUNCTION: + .set noat + .set noreorder + +#if defined(MEMCOPY) || defined(MEMMOVE) + /* set up return value, while we still can */ + move $v0,DSTREG +#endif + # + # Make sure we can copy forwards. + # + sltu $t0,SRCREG,DSTREG # t0 == SRCREG < DSTREG + bne $t0,$zero,6f # copy backwards + + # + # There are four alignment cases (with frequency) + # (Based on measurements taken with a DECstation 5000/200 + # inside a Mach kernel.) + # + # aligned -> aligned (mostly) + # unaligned -> aligned (sometimes) + # aligned,unaligned -> unaligned (almost never) + # + # Note that we could add another case that checks if + # the destination and source are unaligned but the + # copy is alignable. eg if src and dest are both + # on a halfword boundary. + # + andi $t1,DSTREG,3 # get last 3 bits of dest + bne $t1,$zero,3f + andi $t0,SRCREG,3 # get last 3 bits of src + bne $t0,$zero,5f + + # + # Forward aligned->aligned copy, 8*4 bytes at a time. + # + li $at,-32 + and $t0,SIZEREG,$at # count truncated to multiple of 32 */ + addu $a3,SRCREG,$t0 # run fast loop up to this address + sltu $at,SRCREG,$a3 # any work to do? + beq $at,$zero,2f + subu SIZEREG,$t0 + + # + # loop body + # +1: # cp + lw $t3,0(SRCREG) + lw $v1,4(SRCREG) + lw $t0,8(SRCREG) + lw $t1,12(SRCREG) + addiu SRCREG,32 + sw $t3,0(DSTREG) + sw $v1,4(DSTREG) + sw $t0,8(DSTREG) + sw $t1,12(DSTREG) + lw $t1,-4(SRCREG) + lw $t0,-8(SRCREG) + lw $v1,-12(SRCREG) + lw $t3,-16(SRCREG) + addiu DSTREG,32 + sw $t1,-4(DSTREG) + sw $t0,-8(DSTREG) + sw $v1,-12(DSTREG) + bne SRCREG,$a3,1b + sw $t3,-16(DSTREG) + + # + # Copy a word at a time, no loop unrolling. + # +2: # wordcopy + andi $t2,SIZEREG,3 # get byte count / 4 + subu $t2,SIZEREG,$t2 # t2 = number of words to copy * 4 + beq $t2,$zero,3f + addu $t0,SRCREG,$t2 # stop at t0 + subu SIZEREG,SIZEREG,$t2 +1: + lw $t3,0(SRCREG) + addiu SRCREG,4 + sw $t3,0(DSTREG) + bne SRCREG,$t0,1b + addiu DSTREG,4 + +3: # bytecopy + beq SIZEREG,$zero,4f # nothing left to do? + nop +1: + lb $t3,0(SRCREG) + addiu SRCREG,1 + sb $t3,0(DSTREG) + addiu SIZEREG,-1 + bgtz SIZEREG,1b + addiu DSTREG,1 + +4: # copydone + j $ra + nop + + # + # Copy from unaligned source to aligned dest. + # +5: # destaligned + andi $t0,SIZEREG,3 # t0 = bytecount mod 4 + subu $a3,SIZEREG,$t0 # number of words to transfer + beq $a3,$zero,3b + nop + move SIZEREG,$t0 # this many to do after we are done + addu $a3,SRCREG,$a3 # stop point + +1: + LWHI $t3,0(SRCREG) + LWLO $t3,3(SRCREG) + addi SRCREG,4 + sw $t3,0(DSTREG) + bne SRCREG,$a3,1b + addi DSTREG,4 + + j 3b + nop + +6: # backcopy -- based on above + addu SRCREG,SIZEREG + addu DSTREG,SIZEREG + andi $t1,DSTREG,3 # get last 3 bits of dest + bne $t1,$zero,3f + andi $t0,SRCREG,3 # get last 3 bits of src + bne $t0,$zero,5f + + # + # Forward aligned->aligned copy, 8*4 bytes at a time. + # + li $at,-32 + and $t0,SIZEREG,$at # count truncated to multiple of 32 + beq $t0,$zero,2f # any work to do? + subu SIZEREG,$t0 + subu $a3,SRCREG,$t0 + + # + # loop body + # +1: # cp + lw $t3,-16(SRCREG) + lw $v1,-12(SRCREG) + lw $t0,-8(SRCREG) + lw $t1,-4(SRCREG) + addiu SRCREG,-32 + sw $t3,-16(DSTREG) + sw $v1,-12(DSTREG) + sw $t0,-8(DSTREG) + sw $t1,-4(DSTREG) + lw $t1,12(SRCREG) + lw $t0,8(SRCREG) + lw $v1,4(SRCREG) + lw $t3,0(SRCREG) + addiu DSTREG,-32 + sw $t1,12(DSTREG) + sw $t0,8(DSTREG) + sw $v1,4(DSTREG) + bne SRCREG,$a3,1b + sw $t3,0(DSTREG) + + # + # Copy a word at a time, no loop unrolling. + # +2: # wordcopy + andi $t2,SIZEREG,3 # get byte count / 4 + subu $t2,SIZEREG,$t2 # t2 = number of words to copy * 4 + beq $t2,$zero,3f + subu $t0,SRCREG,$t2 # stop at t0 + subu SIZEREG,SIZEREG,$t2 +1: + lw $t3,-4(SRCREG) + addiu SRCREG,-4 + sw $t3,-4(DSTREG) + bne SRCREG,$t0,1b + addiu DSTREG,-4 + +3: # bytecopy + beq SIZEREG,$zero,4f # nothing left to do? + nop +1: + lb $t3,-1(SRCREG) + addiu SRCREG,-1 + sb $t3,-1(DSTREG) + addiu SIZEREG,-1 + bgtz SIZEREG,1b + addiu DSTREG,-1 + +4: # copydone + j $ra + nop + + # + # Copy from unaligned source to aligned dest. + # +5: # destaligned + andi $t0,SIZEREG,3 # t0 = bytecount mod 4 + subu $a3,SIZEREG,$t0 # number of words to transfer + beq $a3,$zero,3b + nop + move SIZEREG,$t0 # this many to do after we are done + subu $a3,SRCREG,$a3 # stop point + +1: + LWHI $t3,-4(SRCREG) + LWLO $t3,-1(SRCREG) + addiu SRCREG,-4 + sw $t3,-4(DSTREG) + bne SRCREG,$a3,1b + addiu DSTREG,-4 + + j 3b + nop + + .set reorder + .set at diff --git a/src/libc/mips/string/bzero.S b/src/libc/mips/string/bzero.S new file mode 100644 index 0000000..9cb5226 --- /dev/null +++ b/src/libc/mips/string/bzero.S @@ -0,0 +1,68 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Ralph Campbell. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* bzero(s1, n) */ + +#define SZREG 4 + + .type bzero, @function +bzero: .globl bzero + .set noreorder + .set noat + + slti $at, $a1, 3*SZREG # small amount to clear? + bnez $at, smallclr + subu $a3, $zero, $a0 # compute # bytes to word align address + andi $a3, $a3, SZREG-1 + beqz $a3, 1f # skip if word aligned + subu $a1, $a1, $a3 # subtract from remaining count + SWHI $zero, 0($a0) # clear 1, 2, or 3 bytes to align + addu $a0, $a0, $a3 +1: + andi $v0, $a1, SZREG-1 # compute number of words left + subu $a3, $a1, $v0 + move $a1, $v0 + addu $a3, $a3, $a0 # compute ending address +2: + addiu $a0, $a0, SZREG # clear words + bne $a0, $a3, 2b # unrolling loop doesnt help + sw $zero, -SZREG($a0) # since we are limited by memory speed +smallclr: + blez $a1, 2f + addu $a3, $a1, $a0 # compute ending address +1: + addiu $a0, $a0, 1 # clear bytes + bne $a0, $a3, 1b + sb $zero, -1($a0) +2: + j $ra + nop diff --git a/src/libc/mips/string/ffs.S b/src/libc/mips/string/ffs.S new file mode 100644 index 0000000..c07b893 --- /dev/null +++ b/src/libc/mips/string/ffs.S @@ -0,0 +1,46 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Ralph Campbell. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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 = ffs(value) */ + .set reorder + .type ffs, @function +ffs: .globl ffs + + move $v0, $zero + beq $a0, $zero, done +1: + andi $v1, $a0, 1 # bit set? + addiu $v0, $v0, 1 + srl $a0, $a0, 1 + beq $v1, $zero, 1b # no, continue +done: + j $ra diff --git a/src/libc/mips/string/index.S b/src/libc/mips/string/index.S new file mode 100644 index 0000000..cb7dad3 --- /dev/null +++ b/src/libc/mips/string/index.S @@ -0,0 +1,45 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Ralph Campbell. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + .set reorder + .type index, @function +index: .globl index +1: + lbu $a2, 0($a0) # get a byte + addiu $a0, $a0, 1 + beq $a2, $a1, fnd + bnez $a2, 1b +notfnd: + move $v0, $zero + j $ra +fnd: + addiu $v0, $a0, -1 + j $ra diff --git a/src/libc/mips/string/memcpy.S b/src/libc/mips/string/memcpy.S new file mode 100644 index 0000000..1617c71 --- /dev/null +++ b/src/libc/mips/string/memcpy.S @@ -0,0 +1,2 @@ +#define MEMCOPY +#include "bcopy.S" diff --git a/src/libc/mips/string/memmove.S b/src/libc/mips/string/memmove.S new file mode 100644 index 0000000..f5a94ed --- /dev/null +++ b/src/libc/mips/string/memmove.S @@ -0,0 +1,2 @@ +#define MEMMOVE +#include "bcopy.S" diff --git a/src/libc/mips/string/memset.S b/src/libc/mips/string/memset.S new file mode 100644 index 0000000..286fac3 --- /dev/null +++ b/src/libc/mips/string/memset.S @@ -0,0 +1,43 @@ +# +# memset(void *s1, int c, int len) +# + .type memset, @function +memset: .globl memset + .set noreorder + .set noat + + slti $at, $a2, 12 # small amount to clear? + bnez $at, smallclr + move $v0, $a0 # save s1 for result + + sll $t1, $a1, 8 # compute c << 8 in t1 + or $t1, $t1, $a1 # compute c << 8 | c in 11 + sll $t2, $t1, 16 # shift that left 16 + or $t1, $t2, $t1 # or together + + subu $t0, $zero, $a0 # compute # bytes to word align address + andi $t0, $t0, 3 + beqz $t0, 1f # skip if word aligned + subu $a2, $a2, $t0 # subtract from remaining count + SWHI $t1, 0($a0) # store 1, 2, or 3 bytes to align + addu $a0, $a0, $t0 +1: + andi $v1, $a2, 3 # compute number of whole words left + subu $t0, $a2, $v1 + subu $a2, $a2, $t0 + addu $t0, $t0, $a0 # compute ending address +2: + addiu $a0, $a0, 4 # clear words + bne $a0, $t0, 2b # unrolling loop does not help + sw $t1, -4($a0) # since we are limited by memory speed + +smallclr: + blez $a2, 2f + addu $t0, $a2, $a0 # compute ending address +1: + addiu $a0, $a0, 1 # clear bytes + bne $a0, $t0, 1b + sb $a1, -1($a0) +2: + j $ra + nop diff --git a/src/libc/mips/string/rindex.S b/src/libc/mips/string/rindex.S new file mode 100644 index 0000000..3c46932 --- /dev/null +++ b/src/libc/mips/string/rindex.S @@ -0,0 +1,44 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Ralph Campbell. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + .set reorder + .type rindex, @function +rindex: .globl rindex + + move $v0, $zero # default if not found +1: + lbu $a3, 0($a0) # get a byte + addiu $a0, $a0, 1 + bne $a3, $a1, 2f + addiu $v0, $a0, -1 # save address of last match +2: + bnez $a3, 1b # continue if not end + j $ra diff --git a/src/libc/mips/string/strcmp.S b/src/libc/mips/string/strcmp.S new file mode 100644 index 0000000..ed20654 --- /dev/null +++ b/src/libc/mips/string/strcmp.S @@ -0,0 +1,55 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Ralph Campbell. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +# +# NOTE: this version assumes unsigned chars in order to be "8 bit clean". +# + .set reorder + .type strcmp, @function +strcmp: .globl strcmp +1: + lbu $t0, 0($a0) # get two bytes and compare them + lbu $t1, 0($a1) + beqz $t0, LessOrEq # end of first string? + bne $t0, $t1, NotEq + lbu $t0, 1($a0) # unroll loop + lbu $t1, 1($a1) + addi $a0, $a0, 2 + beqz $t0, LessOrEq # end of first string? + addi $a1, $a1, 2 + beq $t0, $t1, 1b +NotEq: + subu $v0, $t0, $t1 + j $ra +LessOrEq: + subu $v0, $zero, $t1 + j $ra diff --git a/src/libc/mips/string/strlen.S b/src/libc/mips/string/strlen.S new file mode 100644 index 0000000..b218479 --- /dev/null +++ b/src/libc/mips/string/strlen.S @@ -0,0 +1,42 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Ralph Campbell. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + .set reorder + .type strlen, @function +strlen: .globl strlen + + addiu $v1, $a0, 1 +1: + lb $v0, 0($a0) # get byte from string + addiu $a0, $a0, 1 # increment pointer + bne $v0, $zero, 1b # continue if not end + subu $v0, $a0, $v1 # compute length - 1 for '\0' char + j $ra diff --git a/src/libc/mips/sys/Makefile b/src/libc/mips/sys/Makefile new file mode 100644 index 0000000..a513cdb --- /dev/null +++ b/src/libc/mips/sys/Makefile @@ -0,0 +1,51 @@ +TOPSRC = $(shell cd ../../../..; pwd) +include $(TOPSRC)/target.mk + +ASFLAGS += ${DEFS} +CFLAGS += -Os + +# modules which can not use SYSCALL and must be assembled from sources. The +# rest of the system calls are generated with printf(1) and do not have +# source files associated with them. + +COBJS = sbrk.o execl.o execle.o execv.o + +ASMOBJS = _exit.o _brk.o pipe.o ptrace.o sigaction.o + +SYSOBJS = __sysctl.o accept.o access.o adjtime.o bind.o chdir.o \ + chflags.o chmod.o chown.o chroot.o close.o connect.o dup.o \ + dup2.o execve.o fchdir.o fchflags.o fchmod.o fchown.o \ + fcntl.o flock.o fork.o fstat.o fsync.o ftruncate.o \ + getdtablesize.o getgroups.o getitimer.o getsockname.o \ + getpeername.o getpriority.o getrlimit.o getrusage.o getsockopt.o \ + gettimeofday.o ioctl.o kill.o killpg.o link.o listen.o lstat.o mkdir.o \ + mknod.o mount.o open.o pselect.o quota.o read.o readlink.o readv.o \ + reboot.o \ + recv.o recvfrom.o recvmsg.o rename.o rmdir.o select.o send.o sendmsg.o \ + sendto.o setgroups.o setitimer.o setpgrp.o setpriority.o setquota.o \ + setuid.o seteuid.o setgid.o setegid.o \ + setrlimit.o setsockopt.o settimeofday.o shutdown.o \ + sigaltstack.o socket.o socketpair.o stat.o symlink.o \ + sigprocmask.o sigstack.o sigwait.o \ + statfs.o fstatfs.o getfsstat.o \ + truncate.o umount.o unlink.o utimes.o wait4.o write.o writev.o \ + lseek.o sigsuspend.o \ + getgid.o getegid.o getpgrp.o getpid.o \ + getppid.o getuid.o geteuid.o profil.o sigpending.o sync.o \ + ufetch.o ustore.o ucall.o umask.o vfork.o vhangup.o \ + rdglob.o wrglob.o msec.o kmemdev.o + +OBJS = ${COBJS} ${ASMOBJS} ${SYSOBJS} + +TAGSFILE = tags + +sys.a: ${OBJS} + @echo "building sys.a" + @$(AR) cru sys.a ${OBJS} + +${SYSOBJS}: SYS.h + @echo creating $*.o + @printf '#include "SYS.h"\nSYS($*)\n' | $(AS) ${ASFLAGS} - -c -o $*.o + +clean: + rm -f *~ *.o a.out sys.a diff --git a/src/libc/mips/sys/SYS.h b/src/libc/mips/sys/SYS.h new file mode 100644 index 0000000..1f7f4d5 --- /dev/null +++ b/src/libc/mips/sys/SYS.h @@ -0,0 +1,17 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include + +#define ENTRY(s) s: .globl s; \ + .type s, @function + +#define SYS(s) ENTRY(s); \ + .set noreorder; \ + syscall SYS_##s; \ + lui $t1, %hi(errno); \ + sw $t0, %lo(errno)($t1); \ + .set reorder; \ + jr $ra diff --git a/src/libc/mips/sys/_brk.S b/src/libc/mips/sys/_brk.S new file mode 100644 index 0000000..a0ae2a6 --- /dev/null +++ b/src/libc/mips/sys/_brk.S @@ -0,0 +1,15 @@ +/* + * Copyright (c) 1987 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "SYS.h" + +ENTRY(_brk) + .set noreorder + syscall SYS_sbrk + lui $t1, %hi(errno) # return here on error + sw $t0, %lo(errno)($t1) + .set reorder + + jr $ra # return here on success diff --git a/src/libc/mips/sys/_exit.S b/src/libc/mips/sys/_exit.S new file mode 100644 index 0000000..9e0929b --- /dev/null +++ b/src/libc/mips/sys/_exit.S @@ -0,0 +1,9 @@ +/* + * Copyright (c) 1987 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "SYS.h" + +ENTRY(_exit) + syscall SYS_exit diff --git a/src/libc/mips/sys/execl.c b/src/libc/mips/sys/execl.c new file mode 100644 index 0000000..0b52628 --- /dev/null +++ b/src/libc/mips/sys/execl.c @@ -0,0 +1,14 @@ +/* + * Copyright (c) 1987 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include + +extern char **environ; + +int +execl (const char *name, const char *arg, ...) +{ + return execve (name, (char *const*) &arg, environ); +} diff --git a/src/libc/mips/sys/execle.c b/src/libc/mips/sys/execle.c new file mode 100644 index 0000000..7d11e4b --- /dev/null +++ b/src/libc/mips/sys/execle.c @@ -0,0 +1,22 @@ +/* + * Copyright (c) 1987 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include +#include + +int +execle (const char *name, const char *arg, ...) +{ + va_list ap; + char **envp; + + va_start (ap, arg); + while ((va_arg (ap, char *)) != NULL) + continue; + envp = va_arg (ap, char **); + va_end (ap); + + return execve (name, (char *const*) &arg, envp); +} diff --git a/src/libc/mips/sys/execv.c b/src/libc/mips/sys/execv.c new file mode 100644 index 0000000..f34b7aa --- /dev/null +++ b/src/libc/mips/sys/execv.c @@ -0,0 +1,16 @@ +/* + * Copyright (c) 1987 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include + +extern char **environ; + +int +execv (name, argv) + const char *name; + char *const *argv; +{ + return execve (name, argv, environ); +} diff --git a/src/libc/mips/sys/pipe.S b/src/libc/mips/sys/pipe.S new file mode 100644 index 0000000..1e59ba0 --- /dev/null +++ b/src/libc/mips/sys/pipe.S @@ -0,0 +1,22 @@ +/* + * Copyright (c) 1987 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "SYS.h" + +ENTRY(pipe) + .set noreorder + syscall SYS_pipe + j 1f # return here on error + nop + .set reorder + + sw $v0, 0($a0) # return here on success + sw $v1, 4($a0) + move $v0, $zero + jr $ra +1: + lui $t1, %hi(errno) + sw $t0, %lo(errno)($t1) + jr $ra diff --git a/src/libc/mips/sys/ptrace.S b/src/libc/mips/sys/ptrace.S new file mode 100644 index 0000000..03096e3 --- /dev/null +++ b/src/libc/mips/sys/ptrace.S @@ -0,0 +1,21 @@ +/* + * Copyright (c) 1987 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "SYS.h" + +ENTRY(ptrace) + # -1 is a legitimate return + # value so we must clear errno + # so the caller may disambiguate + lui $t1, %hi(errno) + sw $zero, %lo(errno)($t1) + + .set noreorder + syscall SYS_ptrace + lui $t1, %hi(errno) # return here on error + sw $t0, %lo(errno)($t1) + + .set reorder + jr $ra # return here on success diff --git a/src/libc/mips/sys/sbrk.c b/src/libc/mips/sys/sbrk.c new file mode 100644 index 0000000..58b56e6 --- /dev/null +++ b/src/libc/mips/sys/sbrk.c @@ -0,0 +1,41 @@ +/* + * Copyright (c) 1987 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include + +extern char _end[]; +const char *_curbrk = _end; + +void * +sbrk (incr) + int incr; +{ + void *oldbrk = (void*) _curbrk; + + if (incr != 0) { + /* calculate and pass break address */ + const void *addr = _curbrk + incr; + if (_brk (addr) != -1) { + /* add increment to curbrk */ + _curbrk = addr; + } + } + /* return old break address */ + return oldbrk; +} + +void * +brk (addr) + const void *addr; +{ + int ret; + + if (addr < (void*) _end) /* break request too low? */ + addr = _end; /* yes, knock the request up to _end */ + ret = _brk (addr); /* ask for break */ + if (ret != -1) + _curbrk = addr; /* and remember it if it succeeded */ + return (void*) ret; +} diff --git a/src/libc/mips/sys/sigaction.S b/src/libc/mips/sys/sigaction.S new file mode 100644 index 0000000..5e0156a --- /dev/null +++ b/src/libc/mips/sys/sigaction.S @@ -0,0 +1,77 @@ +/* + * Copyright (c) 1987 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +/* + * error = sigaction(sig, vec, ovec) + * int error, sig; + * struct sigaction *vec, *ovec; + * + * We pass one additional parameter to the sigaction sys call: the address of + * the "Trampoline Code", sigtramp - the code that handles saving and restoring + * register context and so on for signals. On the VAX-11 under BSD4.3 it isn't + * necessary to pass this address since the trampoline code is stored in the + * user structure in u.u_pcb.pcb_sigc at a known address in user space. It + * really doesn't introduce much extra overhead, so our method for doing it on + * a PDP-11 is alright too. + */ +#include "SYS.h" + +ENTRY(sigaction) + la $a3, sigtramp # arg4: address of sigtramp + + .set noreorder + syscall SYS_sigaction + lui $t1, %hi(errno) # return here on error + sw $t0, %lo(errno)($t1) + .set reorder + + jr $ra # return here on success + +/* + * sigtramp - Signal "Trampoline Code" + * + * This code is transfered to by the kernel when a signal is delivered to a + * process. In general, the idea is that sigtramp saves the process' register + * context and then vectors on to the real signal action routine. Upon return + * from the signal action routine sigtramp restores the process' register + * context and performs a sigreturn. + * + * In the case of the PDP-11, the kernel will have already saved r0 and r1 for + * sigtramp in a sigcontext structure it passes to us. Sigtramp vectors onto + * the signal action routine whose address has been left in r0 by the kernel + * (sigtramp assumes the signal action routine will save any other registers + * it uses (as all C routines will)). Upon return from the signal action + * routine, sigtramp will execute a sigreturn with the sigcontext structure + * given to us by the kernel. + * + * When the kernel transfers control to sigtramp the stack looks like: + * + * ------------------------- + * | sigcontext structure | SIG_SC = sp + 8 + * |-----------------------| + * | unused | + * |-----------------------| + * | $a2: ptr to sigcontext| + * |-----------------------| + * | $a1: code | + * |-----------------------| + *sp -> | $a0: signal number | + * ------------------------- + * + * The important features of this as far as sigtramp is concerned are: + * 1. The fact that the signal number, signal code, and signal context + * pointer are already set up as parameters to the signal action + * routine. + * 2. There's no need to save r0 & r1 because the kernel's already saved + * them for us in the sigcontext structure (C routines save all + * registers except r0 & r1 automatically). + * + * Note that the stack offset SIG_SC will NOT have to be recomputed if the + * sigcontext structure changes. + */ +sigtramp: + syscall SYS_sigreturn # attempt the sigreturn + syscall SYS_exit # die if the sigreturn fails ... diff --git a/src/libc/net/Makefile b/src/libc/net/Makefile new file mode 100644 index 0000000..d622392 --- /dev/null +++ b/src/libc/net/Makefile @@ -0,0 +1,111 @@ +# +# Copyright (c) 1988 Regents of the University of California. +# All rights reserved. +# +# Redistribution and use in source and binary forms are permitted +# provided that this notice is preserved and that due credit is given +# to the University of California at Berkeley. The name of the University +# may not be used to endorse or promote products derived from this +# software without specific prior written permission. This software +# is provided ``as is'' without express or implied warranty. +# +# @(#)Makefile 5.16 (Berkeley) 3/14/88 +# +SRCS= getnbyaddr.c getnbyname.c getnent.c getpent.c getpname.c \ + getproto.c getsbyname.c getsbyport.c getsent.c herror.c \ + rcmd.c res_comp.c res_debug.c res_init.c res_mkquery.c \ + res_query.c res_send.c \ + rexec.c ruserpass.c + +OBJS= getnbyaddr.o getnbyname.o getnent.o getpent.o getpname.o \ + getproto.o getsbyname.o getsbyport.o getsent.o rcmd.o herror.o \ + rcmd.o res_comp.o res_debug.o res_init.o res_mkquery.o \ + res_query.o res_send.o rexec.o ruserpass.o + +CFLAGS+= ${DEFS} +TAGSFILE=tags + +.c.o: + ${CC} -p -c ${CFLAGS} $*.c + -ld -X -r $*.o + mv a.out profiled/$*.o + ${CC} ${CFLAGS} -c $*.c + -ld -x -r $*.o + mv a.out $*.o + +netlib netlib_p: ${OBJS} + @echo "building profiled netlib" + @cd profiled; ar cru ../netlib_p ${OBJS} + @echo "building normal netlib" + @ar cru netlib ${OBJS} + +tags: + cwd=`pwd`; \ + for i in ${SRCS}; do \ + ctags -a -f ${TAGSFILE} $$cwd/$$i; \ + done + +clean: + rm -f *.o profiled/*.o errs a.out core netlib netlib_p tags + +depend: + mkdep ${CFLAGS} ${SRCS} + +# DO NOT DELETE THIS LINE -- mkdep uses it. +# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY. + +getnbyaddr.o: getnbyaddr.c /usr/include/netdb.h +getnbyname.o: getnbyname.c /usr/include/netdb.h +getnent.o: getnent.c /usr/include/stdio.h /usr/include/sys/types.h +getnent.o: /usr/include/sys/socket.h /usr/include/arpa/inet.h +getnent.o: /usr/include/netdb.h /usr/include/ctype.h +getpent.o: getpent.c /usr/include/stdio.h /usr/include/sys/types.h +getpent.o: /usr/include/sys/socket.h /usr/include/netdb.h /usr/include/ctype.h +getpname.o: getpname.c /usr/include/netdb.h +getproto.o: getproto.c /usr/include/netdb.h +getsbyname.o: getsbyname.c /usr/include/netdb.h +getsbyport.o: getsbyport.c /usr/include/netdb.h +getsent.o: getsent.c /usr/include/stdio.h /usr/include/sys/types.h +getsent.o: /usr/include/sys/socket.h /usr/include/netinet/in.h +getsent.o: /usr/include/netdb.h /usr/include/ctype.h +herror.o: herror.c /usr/include/sys/types.h /usr/include/sys/uio.h +rcmd.o: rcmd.c /usr/include/stdio.h /usr/include/ctype.h /usr/include/pwd.h +rcmd.o: /usr/include/sys/param.h /usr/include/sys/localopts.h +rcmd.o: /usr/include/machine/machparam.h /usr/include/sys/types.h +rcmd.o: /usr/include/signal.h /usr/include/sys/types.h /usr/include/sys/file.h +rcmd.o: /usr/include/sys/signal.h /usr/include/sys/socket.h +rcmd.o: /usr/include/sys/stat.h /usr/include/netinet/in.h /usr/include/netdb.h +rcmd.o: /usr/include/errno.h +res_comp.o: res_comp.c /usr/include/sys/types.h /usr/include/stdio.h +res_comp.o: /usr/include/arpa/nameser.h +res_debug.o: res_debug.c /usr/include/sys/types.h /usr/include/netinet/in.h +res_debug.o: /usr/include/stdio.h /usr/include/arpa/nameser.h +res_init.o: res_init.c /usr/include/sys/types.h /usr/include/sys/socket.h +res_init.o: /usr/include/netinet/in.h /usr/include/stdio.h +res_init.o: /usr/include/arpa/nameser.h /usr/include/resolv.h +res_mkquery.o: res_mkquery.c /usr/include/stdio.h /usr/include/sys/types.h +res_mkquery.o: /usr/include/netinet/in.h /usr/include/arpa/nameser.h +res_mkquery.o: /usr/include/resolv.h +res_query.o: res_query.c /usr/include/sys/param.h /usr/include/sys/localopts.h +res_query.o: /usr/include/machine/machparam.h /usr/include/sys/types.h +res_query.o: /usr/include/signal.h /usr/include/sys/types.h +res_query.o: /usr/include/sys/socket.h /usr/include/netinet/in.h +res_query.o: /usr/include/ctype.h /usr/include/netdb.h /usr/include/stdio.h +res_query.o: /usr/include/errno.h /usr/include/strings.h +res_query.o: /usr/include/arpa/inet.h /usr/include/arpa/nameser.h +res_query.o: /usr/include/resolv.h +res_send.o: res_send.c /usr/include/sys/param.h /usr/include/sys/localopts.h +res_send.o: /usr/include/machine/machparam.h /usr/include/sys/types.h +res_send.o: /usr/include/signal.h /usr/include/sys/types.h +res_send.o: /usr/include/sys/time.h /usr/include/time.h +res_send.o: /usr/include/sys/socket.h /usr/include/sys/uio.h +res_send.o: /usr/include/netinet/in.h /usr/include/stdio.h /usr/include/errno.h +res_send.o: /usr/include/arpa/nameser.h /usr/include/resolv.h +rexec.o: rexec.c /usr/include/sys/types.h /usr/include/sys/socket.h +rexec.o: /usr/include/netinet/in.h /usr/include/stdio.h /usr/include/netdb.h +rexec.o: /usr/include/errno.h +ruserpass.o: ruserpass.c /usr/include/stdio.h /usr/include/utmp.h +ruserpass.o: /usr/include/ctype.h /usr/include/sys/types.h +ruserpass.o: /usr/include/sys/stat.h /usr/include/errno.h + +# IF YOU PUT ANYTHING HERE IT WILL GO AWAY diff --git a/src/libc/net/getnbyaddr.c b/src/libc/net/getnbyaddr.c new file mode 100644 index 0000000..18fd4b5 --- /dev/null +++ b/src/libc/net/getnbyaddr.c @@ -0,0 +1,29 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)getnetbyaddr.c 5.3 (Berkeley) 5/19/86"; +#endif LIBC_SCCS and not lint + +#include + +extern int _net_stayopen; + +struct netent * +getnetbyaddr(net, type) + register long net; + register int type; +{ + register struct netent *p; + + setnetent(_net_stayopen); + while (p = getnetent()) + if (p->n_addrtype == type && p->n_net == net) + break; + if (!_net_stayopen) + endnetent(); + return (p); +} diff --git a/src/libc/net/getnbyname.c b/src/libc/net/getnbyname.c new file mode 100644 index 0000000..c944ae5 --- /dev/null +++ b/src/libc/net/getnbyname.c @@ -0,0 +1,34 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)getnetbyname.c 5.3 (Berkeley) 5/19/86"; +#endif LIBC_SCCS and not lint + +#include + +extern int _net_stayopen; + +struct netent * +getnetbyname(name) + register char *name; +{ + register struct netent *p; + register char **cp; + + setnetent(_net_stayopen); + while (p = getnetent()) { + if (strcmp(p->n_name, name) == 0) + break; + for (cp = p->n_aliases; *cp != 0; cp++) + if (strcmp(*cp, name) == 0) + goto found; + } +found: + if (!_net_stayopen) + endnetent(); + return (p); +} diff --git a/src/libc/net/getnent.c b/src/libc/net/getnent.c new file mode 100644 index 0000000..74dd4b2 --- /dev/null +++ b/src/libc/net/getnent.c @@ -0,0 +1,109 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)getnetent.c 5.3 (Berkeley) 5/19/86"; +#endif LIBC_SCCS and not lint + +#include +#include +#include +#include +#include +#include + +#define MAXALIASES 35 + +static char NETDB[] = "/etc/networks"; +static FILE *netf = NULL; +static char line[256+1]; +static struct netent net; +static char *net_aliases[MAXALIASES]; +int _net_stayopen; +static char *any(); + +setnetent(f) + int f; +{ + if (netf == NULL) + netf = fopen(NETDB, "r" ); + else + rewind(netf); + _net_stayopen |= f; +} + +endnetent() +{ + if (netf) { + fclose(netf); + netf = NULL; + } + _net_stayopen = 0; +} + +struct netent * +getnetent() +{ + char *p; + register char *cp, **q; + + if (netf == NULL && (netf = fopen(NETDB, "r" )) == NULL) + return (NULL); +again: + p = fgets(line, sizeof(line)-1, netf); + if (p == NULL) + return (NULL); + if (*p == '#') + goto again; + cp = any(p, "#\n"); + if (cp == NULL) + goto again; + *cp = '\0'; + net.n_name = p; + cp = any(p, " \t"); + if (cp == NULL) + goto again; + *cp++ = '\0'; + while (*cp == ' ' || *cp == '\t') + cp++; + p = any(cp, " \t"); + if (p != NULL) + *p++ = '\0'; + net.n_net = inet_network(cp); + net.n_addrtype = AF_INET; + q = net.n_aliases = net_aliases; + if (p != NULL) + cp = p; + while (cp && *cp) { + if (*cp == ' ' || *cp == '\t') { + cp++; + continue; + } + if (q < &net_aliases[MAXALIASES - 1]) + *q++ = cp; + cp = any(cp, " \t"); + if (cp != NULL) + *cp++ = '\0'; + } + *q = NULL; + return (&net); +} + +static char * +any(cp, match) + register char *cp; + char *match; +{ + register char *mp, c; + + while (c = *cp) { + for (mp = match; *mp; mp++) + if (*mp == c) + return (cp); + cp++; + } + return ((char *)0); +} diff --git a/src/libc/net/getpent.c b/src/libc/net/getpent.c new file mode 100644 index 0000000..938a67c --- /dev/null +++ b/src/libc/net/getpent.c @@ -0,0 +1,107 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)getprotoent.c 5.3 (Berkeley) 5/19/86"; +#endif LIBC_SCCS and not lint + +#include +#include +#include +#include +#include + +#define MAXALIASES 35 + +static char PROTODB[] = "/etc/protocols"; +static FILE *protof = NULL; +static char line[256+1]; +static struct protoent proto; +static char *proto_aliases[MAXALIASES]; +static char *any(); +int _proto_stayopen; + +setprotoent(f) + int f; +{ + if (protof == NULL) + protof = fopen(PROTODB, "r" ); + else + rewind(protof); + _proto_stayopen |= f; +} + +endprotoent() +{ + if (protof) { + fclose(protof); + protof = NULL; + } + _proto_stayopen = 0; +} + +struct protoent * +getprotoent() +{ + char *p; + register char *cp, **q; + + if (protof == NULL && (protof = fopen(PROTODB, "r" )) == NULL) + return (NULL); +again: + if ((p = fgets(line, sizeof(line)-1, protof)) == NULL) + return (NULL); + if (*p == '#') + goto again; + cp = any(p, "#\n"); + if (cp == NULL) + goto again; + *cp = '\0'; + proto.p_name = p; + cp = any(p, " \t"); + if (cp == NULL) + goto again; + *cp++ = '\0'; + while (*cp == ' ' || *cp == '\t') + cp++; + p = any(cp, " \t"); + if (p != NULL) + *p++ = '\0'; + proto.p_proto = atoi(cp); + q = proto.p_aliases = proto_aliases; + if (p != NULL) { + cp = p; + while (cp && *cp) { + if (*cp == ' ' || *cp == '\t') { + cp++; + continue; + } + if (q < &proto_aliases[MAXALIASES - 1]) + *q++ = cp; + cp = any(cp, " \t"); + if (cp != NULL) + *cp++ = '\0'; + } + } + *q = NULL; + return (&proto); +} + +static char * +any(cp, match) + register char *cp; + char *match; +{ + register char *mp, c; + + while (c = *cp) { + for (mp = match; *mp; mp++) + if (*mp == c) + return (cp); + cp++; + } + return ((char *)0); +} diff --git a/src/libc/net/getpname.c b/src/libc/net/getpname.c new file mode 100644 index 0000000..872303f --- /dev/null +++ b/src/libc/net/getpname.c @@ -0,0 +1,34 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)getprotoname.c 5.3 (Berkeley) 5/19/86"; +#endif LIBC_SCCS and not lint + +#include + +extern int _proto_stayopen; + +struct protoent * +getprotobyname(name) + register char *name; +{ + register struct protoent *p; + register char **cp; + + setprotoent(_proto_stayopen); + while (p = getprotoent()) { + if (strcmp(p->p_name, name) == 0) + break; + for (cp = p->p_aliases; *cp != 0; cp++) + if (strcmp(*cp, name) == 0) + goto found; + } +found: + if (!_proto_stayopen) + endprotoent(); + return (p); +} diff --git a/src/libc/net/getproto.c b/src/libc/net/getproto.c new file mode 100644 index 0000000..f35a6d6 --- /dev/null +++ b/src/libc/net/getproto.c @@ -0,0 +1,28 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)getproto.c 5.3 (Berkeley) 5/19/86"; +#endif LIBC_SCCS and not lint + +#include + +extern int _proto_stayopen; + +struct protoent * +getprotobynumber(proto) + register int proto; +{ + register struct protoent *p; + + setprotoent(_proto_stayopen); + while (p = getprotoent()) + if (p->p_proto == proto) + break; + if (!_proto_stayopen) + endprotoent(); + return (p); +} diff --git a/src/libc/net/getsbyname.c b/src/libc/net/getsbyname.c new file mode 100644 index 0000000..40c784d --- /dev/null +++ b/src/libc/net/getsbyname.c @@ -0,0 +1,37 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)getservbyname.c 5.3 (Berkeley) 5/19/86"; +#endif LIBC_SCCS and not lint + +#include + +extern int _serv_stayopen; + +struct servent * +getservbyname(name, proto) + char *name, *proto; +{ + register struct servent *p; + register char **cp; + + setservent(_serv_stayopen); + while (p = getservent()) { + if (strcmp(name, p->s_name) == 0) + goto gotname; + for (cp = p->s_aliases; *cp; cp++) + if (strcmp(name, *cp) == 0) + goto gotname; + continue; +gotname: + if (proto == 0 || strcmp(p->s_proto, proto) == 0) + break; + } + if (!_serv_stayopen) + endservent(); + return (p); +} diff --git a/src/libc/net/getsbyport.c b/src/libc/net/getsbyport.c new file mode 100644 index 0000000..d3632a2 --- /dev/null +++ b/src/libc/net/getsbyport.c @@ -0,0 +1,32 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)getservbyport.c 5.3 (Berkeley) 5/19/86"; +#endif LIBC_SCCS and not lint + +#include + +extern int _serv_stayopen; + +struct servent * +getservbyport(port, proto) + int port; + char *proto; +{ + register struct servent *p; + + setservent(_serv_stayopen); + while (p = getservent()) { + if (p->s_port != port) + continue; + if (proto == 0 || strcmp(p->s_proto, proto) == 0) + break; + } + if (!_serv_stayopen) + endservent(); + return (p); +} diff --git a/src/libc/net/getsent.c b/src/libc/net/getsent.c new file mode 100644 index 0000000..02fab5b --- /dev/null +++ b/src/libc/net/getsent.c @@ -0,0 +1,110 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)getservent.c 5.3.1 (2.11BSD GTE) 6/27/94"; +#endif LIBC_SCCS and not lint + +#include +#include +#include +#include +#include +#include + +#define MAXALIASES 16 + +static char SERVDB[] = "/etc/services"; +static FILE *servf = NULL; +static char line[160+1]; +static struct servent serv; +static char *serv_aliases[MAXALIASES]; +static char *any(); +int _serv_stayopen; + +setservent(f) + int f; +{ + if (servf == NULL) + servf = fopen(SERVDB, "r" ); + else + rewind(servf); + _serv_stayopen |= f; +} + +endservent() +{ + if (servf) { + fclose(servf); + servf = NULL; + } + _serv_stayopen = 0; +} + +struct servent * +getservent() +{ + char *p; + register char *cp, **q; + + if (servf == NULL && (servf = fopen(SERVDB, "r" )) == NULL) + return (NULL); +again: + if ((p = fgets(line, sizeof(line)-1, servf)) == NULL) + return (NULL); + if (*p == '#') + goto again; + cp = any(p, "#\n"); + if (cp == NULL) + goto again; + *cp = '\0'; + serv.s_name = p; + p = any(p, " \t"); + if (p == NULL) + goto again; + *p++ = '\0'; + while (*p == ' ' || *p == '\t') + p++; + cp = any(p, ",/"); + if (cp == NULL) + goto again; + *cp++ = '\0'; + serv.s_port = htons((u_short)atoi(p)); + serv.s_proto = cp; + q = serv.s_aliases = serv_aliases; + cp = any(cp, " \t"); + if (cp != NULL) + *cp++ = '\0'; + while (cp && *cp) { + if (*cp == ' ' || *cp == '\t') { + cp++; + continue; + } + if (q < &serv_aliases[MAXALIASES - 1]) + *q++ = cp; + cp = any(cp, " \t"); + if (cp != NULL) + *cp++ = '\0'; + } + *q = NULL; + return (&serv); +} + +static char * +any(cp, match) + register char *cp; + char *match; +{ + register char *mp, c; + + while (c = *cp) { + for (mp = match; *mp; mp++) + if (*mp == c) + return (cp); + cp++; + } + return ((char *)0); +} diff --git a/src/libc/net/herror.c b/src/libc/net/herror.c new file mode 100644 index 0000000..a59e4a5 --- /dev/null +++ b/src/libc/net/herror.c @@ -0,0 +1,49 @@ +/* + * Copyright (c) 1987 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)herror.c 6.1 (Berkeley) 12/4/87"; +#endif LIBC_SCCS and not lint + +#include +#include + +char *h_errlist[] = { + "Error 0", + "Unknown host", /* 1 HOST_NOT_FOUND */ + "Host name lookup failure", /* 2 TRY_AGAIN */ + "Unknown server error", /* 3 NO_RECOVERY */ + "No address associated with name", /* 4 NO_ADDRESS */ +}; +int h_nerr = { sizeof(h_errlist)/sizeof(h_errlist[0]) }; + +extern int h_errno; + +/* + * herror -- + * print the error indicated by the h_errno value. + */ +herror(s) + char *s; +{ + struct iovec iov[4]; + register struct iovec *v = iov; + + if (s && *s) { + v->iov_base = s; + v->iov_len = strlen(s); + v++; + v->iov_base = ": "; + v->iov_len = 2; + v++; + } + v->iov_base = h_errno < h_nerr ? h_errlist[h_errno] : "Unknown error"; + v->iov_len = strlen(v->iov_base); + v++; + v->iov_base = "\n"; + v->iov_len = 1; + writev(2, iov, (v - iov) + 1); +} diff --git a/src/libc/net/hosttable/Makefile b/src/libc/net/hosttable/Makefile new file mode 100644 index 0000000..80d6e97 --- /dev/null +++ b/src/libc/net/hosttable/Makefile @@ -0,0 +1,56 @@ + +# +# Copyright (c) 1983 Regents of the University of California. +# All rights reserved. The Berkeley software License Agreement +# specifies the terms and conditions for redistribution. +# +# @(#)Makefile 5.4 (Berkeley) 9/5/85 +# + +OBJS= gethnamadr.o gethostent.o +SRCS= gethnamadr.c gethostent.c +CFLAGS= -O ${DEFS} + +.c.o: + ${CC} -p -c ${CFLAGS} $*.c + -ld -X -r $*.o + mv a.out profiled/$*.o + ${CC} ${CFLAGS} -c $*.c + -ld -x -r $*.o + mv a.out $*.o + +hostlib hostlib_p: ${OBJS} + @echo "building profiled hostlib" + @cd profiled; ar cru ../hostlib_p ${OBJS} + @echo "building normal netlib" + @ar cru hostlib ${OBJS} + +tags: + cwd=`pwd`; \ + for i in ${SRCS}; do \ + ctags -a -f ${TAGSFILE} $$cwd/$$i; \ + done + +clean: + rm -f *.o errs a.out core hostlib hostlib_p profiled/*.o \ + tags Makefile.bak + +depend: + for i in ${SRCS}; do \ + cc -M ${CFLAGS} $$i | 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 } ' >> makedep; done + echo '/^# DO NOT DELETE THIS LINE/+2,$$d' >eddep + echo '$$r makedep' >>eddep + echo 'w' >>eddep + cp Makefile Makefile.bak + ed - Makefile < eddep + rm eddep makedep + echo '# DEPENDENCIES MUST END AT END OF FILE' >> Makefile + echo '# IF YOU PUT STUFF HERE IT WILL GO AWAY' >> Makefile + echo '# see make depend above' >> Makefile + +# DO NOT DELETE THIS LINE -- make depend uses it + diff --git a/src/libc/net/hosttable/gethnamadr.c b/src/libc/net/hosttable/gethnamadr.c new file mode 100644 index 0000000..8ae3c52 --- /dev/null +++ b/src/libc/net/hosttable/gethnamadr.c @@ -0,0 +1,156 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)gethostnamadr.c 5.5 (Berkeley) 3/9/86"; +#endif LIBC_SCCS and not lint + +#include +#include +#include +#include +#include +#include + +#define MAXALIASES 20 +#define MAXADDRS 10 + +static struct hostent host; +static char hostbuf[256]; +static char *host_aliases[MAXALIASES]; +static char *host_addrs[MAXADDRS]; + +int h_errno; + +/* + * The following is shared with gethostent.c + */ +extern char *_host_file; +DBM *_host_db = (DBM *)NULL; +int _host_stayopen; /* set by sethostent(), cleared by endhostent() */ + +static struct hostent * +fetchhost(key) + datum key; +{ + register char *cp, *tp, **ap; + int naliases, naddrs; + + if (key.dptr == 0) + return ((struct hostent *)NULL); + key = dbm_fetch(_host_db, key); + if (key.dptr == 0) + return ((struct hostent *)NULL); + cp = key.dptr; + tp = hostbuf; + host.h_name = tp; + while (*tp++ = *cp++) + ; + bcopy(cp, (char *)&naliases, sizeof(int)); + cp += sizeof (int); + for (ap = host_aliases; naliases > 0; naliases--) { + *ap++ = tp; + while (*tp++ = *cp++) + ; + } + *ap = (char *)NULL; + host.h_aliases = host_aliases; + bcopy(cp, (char *)&host.h_addrtype, sizeof (int)); + cp += sizeof (int); + bcopy(cp, (char *)&host.h_length, sizeof (int)); + cp += sizeof (int); + host.h_addr_list = host_addrs; + naddrs = (key.dsize - (cp - key.dptr)) / host.h_length; + if (naddrs > MAXADDRS) + naddrs = MAXADDRS; + for (ap = host_addrs; naddrs; naddrs--) { + *ap++ = tp; + bcopy(cp, tp, host.h_length); + cp += host.h_length; + tp += host.h_length; + } + *ap = (char *)NULL; + return (&host); +} + +struct hostent * +gethostbyname(nam) + register char *nam; +{ + register struct hostent *hp; + register char **cp; + datum key; + char lowname[128]; + register char *lp = lowname; + + while (*nam) + if (isupper(*nam)) + *lp++ = tolower(*nam++); + else + *lp++ = *nam++; + *lp = '\0'; + + if ((_host_db == (DBM *)NULL) + && ((_host_db = dbm_open(_host_file, O_RDONLY)) == (DBM *)NULL)) { + sethostent(_host_stayopen); + while (hp = gethostent()) { + if (strcmp(hp->h_name, lowname) == 0) + break; + for (cp = hp->h_aliases; cp != 0 && *cp != 0; cp++) + if (strcmp(*cp, lowname) == 0) + goto found; + } + found: + if (!_host_stayopen) + endhostent(); + return (hp); + } + key.dptr = lowname; + key.dsize = strlen(lowname); + hp = fetchhost(key); + if (!_host_stayopen) { + dbm_close(_host_db); + _host_db = (DBM *)NULL; + } + if ( hp == NULL) + h_errno = HOST_NOT_FOUND; + return (hp); +} + +struct hostent * +gethostbyaddr(addr, length, type) + char *addr; + register int length; + register int type; +{ + register struct hostent *hp; + datum key; + + if ((_host_db == (DBM *)NULL) + && ((_host_db = dbm_open(_host_file, O_RDONLY)) == (DBM *)NULL)) { + sethostent(_host_stayopen); + while (hp = gethostent()) { + if (hp->h_addrtype == type && hp->h_length == length + && bcmp(hp->h_addr, addr, length) == 0) + break; + } + if (!_host_stayopen) + endhostent(); + if ( hp == NULL) + h_errno = HOST_NOT_FOUND; + return (hp); + } + key.dptr = addr; + key.dsize = length; + hp = fetchhost(key); + if (!_host_stayopen) { + dbm_close(_host_db); + _host_db = (DBM *)NULL; + } + if ( hp == NULL) + h_errno = HOST_NOT_FOUND; + return (hp); +} diff --git a/src/libc/net/hosttable/gethostent.c b/src/libc/net/hosttable/gethostent.c new file mode 100644 index 0000000..70e3806 --- /dev/null +++ b/src/libc/net/hosttable/gethostent.c @@ -0,0 +1,133 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)gethostent.c 5.3 (Berkeley) 3/9/86"; +#endif LIBC_SCCS and not lint + +#include +#include +#include +#include +#include +#include +#include + +/* + * Internet version. + */ +#define MAXALIASES 20 +#define MAXADDRSIZE (sizeof (u_long)) + +static FILE *hostf = NULL; +static char line[160+1]; +static char hostaddr[MAXADDRSIZE]; +static struct hostent host; +static char *host_aliases[MAXALIASES]; +static char *host_addrs[] = { + hostaddr, + NULL +}; + +/* + * The following is shared with gethostnamadr.c + */ +char *_host_file = "/etc/hosts"; +int _host_stayopen; +DBM *_host_db; /* set by gethostbyname(), gethostbyaddr() */ + +static char *any(); + +sethostent(f) + int f; +{ + if (hostf != NULL) + rewind(hostf); + _host_stayopen |= f; +} + +endhostent() +{ + if (hostf) { + fclose(hostf); + hostf = NULL; + } + if (_host_db) { + dbm_close(_host_db); + _host_db = (DBM *)NULL; + } + _host_stayopen = 0; +} + +struct hostent * +gethostent() +{ + char *p; + register char *cp, **q; + + if (hostf == NULL && (hostf = fopen(_host_file, "r" )) == NULL) + return (NULL); +again: + if ((p = fgets(line, sizeof(line)-1, hostf)) == NULL) + return (NULL); + if (*p == '#') + goto again; + cp = any(p, "#\n"); + if (cp == NULL) + goto again; + *cp = '\0'; + cp = any(p, " \t"); + if (cp == NULL) + goto again; + *cp++ = '\0'; + /* THIS STUFF IS INTERNET SPECIFIC */ + host.h_addr_list = host_addrs; + *((u_long *)host.h_addr) = inet_addr(p); + host.h_length = sizeof (u_long); + host.h_addrtype = AF_INET; + while (*cp == ' ' || *cp == '\t') + cp++; + host.h_name = cp; + q = host.h_aliases = host_aliases; + cp = any(cp, " \t"); + if (cp != NULL) + *cp++ = '\0'; + while (cp && *cp) { + if (*cp == ' ' || *cp == '\t') { + cp++; + continue; + } + if (q < &host_aliases[MAXALIASES - 1]) + *q++ = cp; + cp = any(cp, " \t"); + if (cp != NULL) + *cp++ = '\0'; + } + *q = NULL; + return (&host); +} + +sethostfile(file) + char *file; +{ + _host_file = file; +} + +static char * +any(cp, match) + register char *cp; + char *match; +{ + register char *mp, c; + + while (c = *cp) { + for (mp = match; *mp; mp++) + if (*mp == c) + return (cp); + cp++; + } + return ((char *)0); +} diff --git a/src/libc/net/named/Makefile b/src/libc/net/named/Makefile new file mode 100644 index 0000000..b741fa3 --- /dev/null +++ b/src/libc/net/named/Makefile @@ -0,0 +1,57 @@ +# +# Copyright (c) 1983 Regents of the University of California. +# All rights reserved. The Berkeley software License Agreement +# specifies the terms and conditions for redistribution. +# +# @(#)Makefile 6.4 (Berkeley) 6/6/87 +# + +OBJS= gethnamadr.o sethostent.o + +SRCS= gethnamadr.c sethostent.c + +CFLAGS= -O ${DEFS} +TAGSFILE= tags +DESTDIR= + +.c.o: + ${CC} -p -c ${CFLAGS} $*.c + -ld -X -r $*.o + mv a.out profiled/$*.o + ${CC} ${CFLAGS} -c $*.c + -ld -x -r $*.o + mv a.out $*.o + +hostlib hostlib_p: ${OBJS} + @echo "building profiled hostlib" + @cd profiled; ar cru ../hostlib_p ${OBJS} + @echo "building normal hostlib" + @ar cru hostlib ${OBJS} + +tags: + cwd=`pwd`; \ + for i in ${SRCS}; do \ + ctags -a -f ${TAGSFILE} $$cwd/$$i; \ + done + +clean: + rm -f *.o errs a.out core hostlib hostlib_p profiled/*.o tags + +depend: + mkdep ${CFLAGS} ${SRCS} + +# DO NOT DELETE THIS LINE -- mkdep uses it. +# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY. + +gethnamadr.o: gethnamadr.c /usr/include/sys/param.h +gethnamadr.o: /usr/include/sys/localopts.h /usr/include/machine/machparam.h +gethnamadr.o: /usr/include/sys/types.h /usr/include/signal.h +gethnamadr.o: /usr/include/sys/types.h /usr/include/sys/socket.h +gethnamadr.o: /usr/include/netinet/in.h /usr/include/ctype.h +gethnamadr.o: /usr/include/netdb.h /usr/include/stdio.h /usr/include/errno.h +gethnamadr.o: /usr/include/arpa/inet.h /usr/include/arpa/nameser.h +gethnamadr.o: /usr/include/resolv.h +sethostent.o: sethostent.c /usr/include/sys/types.h /usr/include/arpa/nameser.h +sethostent.o: /usr/include/netinet/in.h /usr/include/resolv.h + +# IF YOU PUT ANYTHING HERE IT WILL GO AWAY diff --git a/src/libc/net/named/gethnamadr.c b/src/libc/net/named/gethnamadr.c new file mode 100644 index 0000000..89a7146 --- /dev/null +++ b/src/libc/net/named/gethnamadr.c @@ -0,0 +1,401 @@ +/* + * 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 this notice is preserved and that due credit is given + * to the University of California at Berkeley. The name of the University + * may not be used to endorse or promote products derived from this + * software without specific prior written permission. This software + * is provided ``as is'' without express or implied warranty. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)gethostnamadr.c 6.31.2 (2.11BSD GTE) 6/27/94"; +#endif /* LIBC_SCCS and not lint */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAXALIASES 16 +#define MAXADDRS 16 + +static char *h_addr_ptrs[MAXADDRS + 1]; + +static struct hostent host; +static char *host_aliases[MAXALIASES]; +static char hostbuf[256+1]; +static struct in_addr host_addr; +static char HOSTDB[] = "/etc/hosts"; +static FILE *hostf = NULL; +static char hostaddr[MAXADDRS]; +static char *host_addrs[2]; +static int stayopen = 0; +static char *any(); + +#if PACKETSZ > 1024 +#define MAXPACKET PACKETSZ +#else +#define MAXPACKET 1024 +#endif + +typedef union { + HEADER hdr; + u_char buf[MAXPACKET]; +} querybuf; + +static union { + long al; + char ac; +} align; + + +int h_errno; +extern errno; + +static struct hostent * +getanswer(answer, anslen, iquery) + querybuf *answer; + int anslen; + int iquery; +{ + register HEADER *hp; + register u_char *cp; + register int n; + u_char *eom; + char *bp, **ap; + int type, class, buflen, ancount, qdcount; + int haveanswer, getclass = C_ANY; + char **hap; + + eom = answer->buf + anslen; + /* + * find first satisfactory answer + */ + hp = &answer->hdr; + ancount = ntohs(hp->ancount); + qdcount = ntohs(hp->qdcount); + bp = hostbuf; + buflen = sizeof(hostbuf); + cp = answer->buf + sizeof(HEADER); + if (qdcount) { + if (iquery) { + if ((n = dn_expand((char *)answer->buf, eom, + cp, bp, buflen)) < 0) { + h_errno = NO_RECOVERY; + return ((struct hostent *) NULL); + } + cp += n + QFIXEDSZ; + host.h_name = bp; + n = strlen(bp) + 1; + bp += n; + buflen -= n; + } else + cp += dn_skipname(cp, eom) + QFIXEDSZ; + while (--qdcount > 0) + cp += dn_skipname(cp, eom) + QFIXEDSZ; + } else if (iquery) { + if (hp->aa) + h_errno = HOST_NOT_FOUND; + else + h_errno = TRY_AGAIN; + return ((struct hostent *) NULL); + } + ap = host_aliases; + host.h_aliases = host_aliases; + hap = h_addr_ptrs; +#if BSD >= 43 || defined(h_addr) /* new-style hostent structure */ + host.h_addr_list = h_addr_ptrs; +#endif + haveanswer = 0; + while (--ancount >= 0 && cp < eom) { + if ((n = dn_expand((char *)answer->buf, eom, cp, bp, buflen)) < 0) + break; + cp += n; + type = _getshort(cp); + cp += sizeof(u_short); + class = _getshort(cp); + cp += sizeof(u_short) + sizeof(u_long); + n = _getshort(cp); + cp += sizeof(u_short); + if (type == T_CNAME) { + cp += n; + if (ap >= &host_aliases[MAXALIASES-1]) + continue; + *ap++ = bp; + n = strlen(bp) + 1; + bp += n; + buflen -= n; + continue; + } + if (iquery && type == T_PTR) { + if ((n = dn_expand((char *)answer->buf, eom, + cp, bp, buflen)) < 0) { + cp += n; + continue; + } + cp += n; + host.h_name = bp; + return(&host); + } + if (iquery || type != T_A) { +#ifdef DEBUG + if (_res.options & RES_DEBUG) + printf("unexpected answer type %d, size %d\n", + type, n); +#endif + cp += n; + continue; + } + if (haveanswer) { + if (n != host.h_length) { + cp += n; + continue; + } + if (class != getclass) { + cp += n; + continue; + } + } else { + host.h_length = n; + getclass = class; + host.h_addrtype = (class == C_IN) ? AF_INET : AF_UNSPEC; + if (!iquery) { + host.h_name = bp; + bp += strlen(bp) + 1; + } + } + + bp += sizeof(align) - ((u_long)bp % sizeof(align)); + + if (bp + n >= &hostbuf[sizeof(hostbuf)]) { +#ifdef DEBUG + if (_res.options & RES_DEBUG) + printf("size (%d) too big\n", n); +#endif + break; + } + bcopy(cp, *hap++ = bp, n); + bp +=n; + cp += n; + haveanswer++; + } + if (haveanswer) { + *ap = NULL; +#if BSD >= 43 || defined(h_addr) /* new-style hostent structure */ + *hap = NULL; +#else + host.h_addr = h_addr_ptrs[0]; +#endif + return (&host); + } else { + h_errno = TRY_AGAIN; + return ((struct hostent *) NULL); + } +} + +struct hostent * +gethostbyname(name) + char *name; +{ + querybuf buf; + register char *cp; + int n; + struct hostent *hp, *gethostdomain(); + extern struct hostent *_gethtbyname(); + + /* + * disallow names consisting only of digits/dots, unless + * they end in a dot. + */ + if (isdigit(name[0])) + for (cp = name;; ++cp) { + if (!*cp) { + if (*--cp == '.') + break; + h_errno = HOST_NOT_FOUND; + return ((struct hostent *) NULL); + } + if (!isdigit(*cp) && *cp != '.') + break; + } + + if ((n = res_search(name, C_IN, T_A, buf.buf, sizeof(buf))) < 0) { +#ifdef DEBUG + if (_res.options & RES_DEBUG) + printf("res_search failed\n"); +#endif + if (errno == ECONNREFUSED) + return (_gethtbyname(name)); + else + return ((struct hostent *) NULL); + } + return (getanswer(&buf, n, 0)); +} + +struct hostent * +gethostbyaddr(addr, len, type) + char *addr; + int len, type; +{ + int n; + querybuf buf; + register struct hostent *hp; + char qbuf[MAXDNAME]; + extern struct hostent *_gethtbyaddr(); + + if (type != AF_INET) + return ((struct hostent *) NULL); + (void)sprintf(qbuf, "%d.%d.%d.%d.in-addr.arpa", + ((unsigned)addr[3] & 0xff), + ((unsigned)addr[2] & 0xff), + ((unsigned)addr[1] & 0xff), + ((unsigned)addr[0] & 0xff)); + n = res_query(qbuf, C_IN, T_PTR, (char *)&buf, sizeof(buf)); + if (n < 0) { +#ifdef DEBUG + if (_res.options & RES_DEBUG) + printf("res_query failed\n"); +#endif + if (errno == ECONNREFUSED) + hp = _gethtbyaddr(addr, len, type); + return ((struct hostent *) NULL); + } + hp = getanswer(&buf, n, 1); + if (hp == NULL) + return ((struct hostent *) NULL); + hp->h_addrtype = type; + hp->h_length = len; + h_addr_ptrs[0] = (char *)&host_addr; + h_addr_ptrs[1] = (char *)0; + host_addr = *(struct in_addr *)addr; + return(hp); +} + +_sethtent(f) + int f; +{ + if (hostf == NULL) + hostf = fopen(HOSTDB, "r" ); + else + rewind(hostf); + stayopen |= f; +} + +_endhtent() +{ + if (hostf && !stayopen) { + (void) fclose(hostf); + hostf = NULL; + } +} + +struct hostent * +_gethtent() +{ + char *p; + register char *cp, **q; + + if (hostf == NULL && (hostf = fopen(HOSTDB, "r" )) == NULL) + return (NULL); +again: + if ((p = fgets(hostbuf, sizeof(hostbuf)-1, hostf)) == NULL) + return (NULL); + if (*p == '#') + goto again; + cp = any(p, "#\n"); + if (cp == NULL) + goto again; + *cp = '\0'; + cp = any(p, " \t"); + if (cp == NULL) + goto again; + *cp++ = '\0'; + /* THIS STUFF IS INTERNET SPECIFIC */ +#if BSD >= 43 || defined(h_addr) /* new-style hostent structure */ + host.h_addr_list = host_addrs; +#endif + host.h_addr = hostaddr; + *((u_long *)host.h_addr) = inet_addr(p); + host.h_length = sizeof (u_long); + host.h_addrtype = AF_INET; + while (*cp == ' ' || *cp == '\t') + cp++; + host.h_name = cp; + q = host.h_aliases = host_aliases; + cp = any(cp, " \t"); + if (cp != NULL) + *cp++ = '\0'; + while (cp && *cp) { + if (*cp == ' ' || *cp == '\t') { + cp++; + continue; + } + if (q < &host_aliases[MAXALIASES - 1]) + *q++ = cp; + cp = any(cp, " \t"); + if (cp != NULL) + *cp++ = '\0'; + } + *q = NULL; + return (&host); +} + +static char * +any(cp, match) + register char *cp; + char *match; +{ + register char *mp, c; + + while (c = *cp) { + for (mp = match; *mp; mp++) + if (*mp == c) + return (cp); + cp++; + } + return ((char *)0); +} + +struct hostent * +_gethtbyname(name) + char *name; +{ + register struct hostent *p; + register char **cp; + + _sethtent(0); + while (p = _gethtent()) { + if (strcasecmp(p->h_name, name) == 0) + break; + for (cp = p->h_aliases; *cp != 0; cp++) + if (strcasecmp(*cp, name) == 0) + goto found; + } +found: + _endhtent(); + return (p); +} + +struct hostent * +_gethtbyaddr(addr, len, type) + char *addr; + int len, type; +{ + register struct hostent *p; + + _sethtent(0); + while (p = _gethtent()) + if (p->h_addrtype == type && !bcmp(p->h_addr, addr, len)) + break; + _endhtent(); + return (p); +} diff --git a/src/libc/net/named/sethostent.c b/src/libc/net/named/sethostent.c new file mode 100644 index 0000000..0acfe9c --- /dev/null +++ b/src/libc/net/named/sethostent.c @@ -0,0 +1,34 @@ +/* + * Copyright (c) 1985 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)sethostent.c 6.3 (Berkeley) 4/10/86"; +#endif LIBC_SCCS and not lint + +#include +#include +#include +#include + +sethostent(stayopen) +{ + if (stayopen) + _res.options |= RES_STAYOPEN | RES_USEVC; +} + +endhostent() +{ + _res.options &= ~(RES_STAYOPEN | RES_USEVC); + _res_close(); +} + +sethostfile(name) +char *name; +{ +#ifdef lint +name = name; +#endif +} diff --git a/src/libc/net/rcmd.c b/src/libc/net/rcmd.c new file mode 100644 index 0000000..d97cbbe --- /dev/null +++ b/src/libc/net/rcmd.c @@ -0,0 +1,339 @@ +/* + * Copyright (c) 1983 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)rcmd.c 5.20.1 (2.11BSD) 1999/10/24"; +#endif /* LIBC_SCCS and not lint */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +rcmd(ahost, rport, locuser, remuser, cmd, fd2p) + char **ahost; + u_short rport; + char *locuser, *remuser, *cmd; + int *fd2p; +{ + int s, timo = 1, pid; + sigset_t oldmask, nmask; + struct sockaddr_in sin, sin2, from; + char c; + int lport = IPPORT_RESERVED - 1; + struct hostent *hp; + fd_set reads; + + pid = getpid(); + hp = gethostbyname(*ahost); + if (hp == 0) { + herror(*ahost); + return (-1); + } + *ahost = hp->h_name; + sigemptyset(&nmask); + sigaddset(&nmask, SIGURG); + (void)sigprocmask(SIG_BLOCK, &nmask, &oldmask); + + for (;;) { + s = rresvport(&lport); + if (s < 0) { + if (errno == EAGAIN) + fprintf(stderr, "socket: All ports in use\n"); + else + perror("rcmd: socket"); + sigprocmask(SIG_SETMASK, &oldmask, NULL); + return (-1); + } + fcntl(s, F_SETOWN, pid); + sin.sin_family = hp->h_addrtype; + bcopy(hp->h_addr_list[0], (caddr_t)&sin.sin_addr, hp->h_length); + sin.sin_port = rport; + if (connect(s, (caddr_t)&sin, sizeof (sin), 0) >= 0) + break; + (void) close(s); + if (errno == EADDRINUSE) { + lport--; + continue; + } + if (errno == ECONNREFUSED && timo <= 16) { + sleep(timo); + timo *= 2; + continue; + } + if (hp->h_addr_list[1] != NULL) { + int oerrno = errno; + + fprintf(stderr, + "connect to address %s: ", inet_ntoa(sin.sin_addr)); + errno = oerrno; + perror(0); + hp->h_addr_list++; + bcopy(hp->h_addr_list[0], (caddr_t)&sin.sin_addr, + hp->h_length); + fprintf(stderr, "Trying %s...\n", + inet_ntoa(sin.sin_addr)); + continue; + } + perror(hp->h_name); + sigprocmask(SIG_SETMASK, &oldmask, NULL); + return (-1); + } + lport--; + if (fd2p == 0) { + write(s, "", 1); + lport = 0; + } else { + char num[8]; + int s2 = rresvport(&lport), s3; + int len = sizeof (from); + + if (s2 < 0) + goto bad; + listen(s2, 1); + (void) sprintf(num, "%d", lport); + if (write(s, num, strlen(num)+1) != strlen(num)+1) { + perror("write: setting up stderr"); + (void) close(s2); + goto bad; + } + FD_ZERO(&reads); + FD_SET(s, &reads); + FD_SET(s2, &reads); + errno = 0; + if (select(32, &reads, 0, 0, 0) < 1 || + !FD_ISSET(s2, &reads)) { + if (errno != 0) + perror("select: setting up stderr"); + else + fprintf(stderr, + "select: protocol failure in circuit setup.\n"); + (void) close(s2); + goto bad; + } + s3 = accept(s2, &from, &len, 0); + (void) close(s2); + if (s3 < 0) { + perror("accept"); + lport = 0; + goto bad; + } + *fd2p = s3; + from.sin_port = ntohs((u_short)from.sin_port); + if (from.sin_family != AF_INET || + from.sin_port >= IPPORT_RESERVED || + from.sin_port < IPPORT_RESERVED / 2) { + fprintf(stderr, + "socket: protocol failure in circuit setup.\n"); + goto bad2; + } + } + (void) write(s, locuser, strlen(locuser)+1); + (void) write(s, remuser, strlen(remuser)+1); + (void) write(s, cmd, strlen(cmd)+1); + if (read(s, &c, 1) != 1) { + perror(*ahost); + goto bad2; + } + if (c != 0) { + while (read(s, &c, 1) == 1) { + (void) write(2, &c, 1); + if (c == '\n') + break; + } + goto bad2; + } + sigprocmask(SIG_SETMASK, &oldmask, NULL); + return (s); +bad2: + if (lport) + (void) close(*fd2p); +bad: + (void) close(s); + sigprocmask(SIG_SETMASK, &oldmask, NULL); + return (-1); +} + +rresvport(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, (caddr_t)&sin, sizeof (sin)) >= 0) + return (s); + if (errno != EADDRINUSE) { + (void) close(s); + return (-1); + } + (*alport)--; + if (*alport == IPPORT_RESERVED/2) { + (void) close(s); + errno = EAGAIN; /* close */ + return (-1); + } + } +} + +int _check_rhosts_file = 1; + +ruserok(rhost, superuser, ruser, luser) + char *rhost; + int superuser; + char *ruser, *luser; +{ + FILE *hostf; + char fhost[MAXHOSTNAMELEN]; + int first = 1; + register char *sp, *p; + int baselen = -1; + + sp = rhost; + p = fhost; + while (*sp) { + if (*sp == '.') { + if (baselen == -1) + baselen = sp - rhost; + *p++ = *sp++; + } else { + *p++ = isupper(*sp) ? tolower(*sp++) : *sp++; + } + } + *p = '\0'; + hostf = superuser ? (FILE *)0 : fopen("/etc/hosts.equiv", "r"); +again: + if (hostf) { + if (!_validuser(hostf, fhost, luser, ruser, baselen)) { + (void) fclose(hostf); + return(0); + } + (void) fclose(hostf); + } + if (first == 1 && (_check_rhosts_file || superuser)) { + struct stat sbuf; + struct passwd *pwd; + char pbuf[MAXPATHLEN]; + + first = 0; + if ((pwd = getpwnam(luser)) == NULL) + return(-1); + (void)strcpy(pbuf, pwd->pw_dir); + (void)strcat(pbuf, "/.rhosts"); + if ((hostf = fopen(pbuf, "r")) == NULL) + return(-1); + /* + * if owned by someone other than user or root or if + * writeable by anyone but the owner, quit + */ + if (fstat(fileno(hostf), &sbuf) || + sbuf.st_uid && sbuf.st_uid != pwd->pw_uid || + sbuf.st_mode&022) { + fclose(hostf); + return(-1); + } + goto again; + } + return (-1); +} + +/* don't make static, used by lpd(8) */ +_validuser(hostf, rhost, luser, ruser, baselen) + char *rhost, *luser, *ruser; + FILE *hostf; + int baselen; +{ + char *user; + char ahost[MAXHOSTNAMELEN]; + register char *p; + + while (fgets(ahost, sizeof (ahost), hostf)) { + p = ahost; + while (*p != '\n' && *p != ' ' && *p != '\t' && *p != '\0') { + *p = isupper(*p) ? tolower(*p) : *p; + p++; + } + if (*p == ' ' || *p == '\t') { + *p++ = '\0'; + while (*p == ' ' || *p == '\t') + p++; + user = p; + while (*p != '\n' && *p != ' ' && *p != '\t' && *p != '\0') + p++; + } else + user = p; + *p = '\0'; + if (_checkhost(rhost, ahost, baselen) && + !strcmp(ruser, *user ? user : luser)) { + return (0); + } + } + return (-1); +} + +static +_checkhost(rhost, lhost, len) + char *rhost, *lhost; + int len; +{ + static char ldomain[MAXHOSTNAMELEN + 1]; + static char *domainp = NULL; + static int nodomain = 0; + register char *cp; + + if (len == -1) + return(!strcmp(rhost, lhost)); + if (strncmp(rhost, lhost, len)) + return(0); + if (!strcmp(rhost, lhost)) + return(1); + if (*(lhost + len) != '\0') + return(0); + if (nodomain) + return(0); + if (!domainp) { + if (gethostname(ldomain, sizeof(ldomain)) == -1) { + nodomain = 1; + return(0); + } + ldomain[MAXHOSTNAMELEN] = NULL; + if ((domainp = index(ldomain, '.')) == (char *)NULL) { + nodomain = 1; + return(0); + } + for (cp = ++domainp; *cp; ++cp) + if (isupper(*cp)) + *cp = tolower(*cp); + } + return(!strcmp(domainp, rhost + len +1)); +} diff --git a/src/libc/net/res_comp.c b/src/libc/net/res_comp.c new file mode 100644 index 0000000..ab23d6a --- /dev/null +++ b/src/libc/net/res_comp.c @@ -0,0 +1,310 @@ +/* + * Copyright (c) 1985 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that this notice is preserved and that due credit is given + * to the University of California at Berkeley. The name of the University + * may not be used to endorse or promote products derived from this + * software without specific prior written permission. This software + * is provided ``as is'' without express or implied warranty. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)res_comp.c 6.13 (Berkeley) 3/13/88"; +#endif /* LIBC_SCCS and not lint */ + +#include +#include +#include + + +/* + * Expand compressed domain name 'comp_dn' to full domain name. + * 'msg' is a pointer to the begining of the message, + * 'eomorig' points to the first location after the message, + * 'exp_dn' is a pointer to a buffer of size 'length' for the result. + * Return size of compressed name or -1 if there was an error. + */ +dn_expand(msg, eomorig, comp_dn, exp_dn, length) + u_char *msg, *eomorig, *comp_dn, *exp_dn; + int length; +{ + register u_char *cp, *dn; + register int n, c; + u_char *eom; + int len = -1, checked = 0; + + dn = exp_dn; + cp = comp_dn; + eom = exp_dn + length - 1; + /* + * fetch next label in domain name + */ + while (n = *cp++) { + /* + * Check for indirection + */ + switch (n & INDIR_MASK) { + case 0: + if (dn != exp_dn) { + if (dn >= eom) + return (-1); + *dn++ = '.'; + } + if (dn+n >= eom) + return (-1); + checked += n + 1; + while (--n >= 0) { + if ((c = *cp++) == '.') { + if (dn+n+1 >= eom) + return (-1); + *dn++ = '\\'; + } + *dn++ = c; + if (cp >= eomorig) /* out of range */ + return(-1); + } + break; + + case INDIR_MASK: + if (len < 0) + len = cp - comp_dn + 1; + cp = msg + (((n & 0x3f) << 8) | (*cp & 0xff)); + if (cp < msg || cp >= eomorig) /* out of range */ + return(-1); + checked += 2; + /* + * Check for loops in the compressed name; + * if we've looked at the whole message, + * there must be a loop. + */ + if (checked >= eomorig - msg) + return (-1); + break; + + default: + return (-1); /* flag error */ + } + } + *dn = '\0'; + if (len < 0) + len = cp - comp_dn; + return (len); +} + +/* + * Compress domain name 'exp_dn' into 'comp_dn'. + * Return the size of the compressed name or -1. + * 'length' is the size of the array pointed to by 'comp_dn'. + * 'dnptrs' is a list of pointers to previous compressed names. dnptrs[0] + * is a pointer to the beginning of the message. The list ends with NULL. + * 'lastdnptr' is a pointer to the end of the arrary pointed to + * by 'dnptrs'. Side effect is to update the list of pointers for + * labels inserted into the message as we compress the name. + * If 'dnptr' is NULL, we don't try to compress names. If 'lastdnptr' + * is NULL, we don't update the list. + */ +dn_comp(exp_dn, comp_dn, length, dnptrs, lastdnptr) + u_char *exp_dn, *comp_dn; + int length; + u_char **dnptrs, **lastdnptr; +{ + register u_char *cp, *dn; + register int c, l; + u_char **cpp, **lpp, *sp, *eob; + u_char *msg; + + dn = exp_dn; + cp = comp_dn; + eob = cp + length; + if (dnptrs != NULL) { + if ((msg = *dnptrs++) != NULL) { + for (cpp = dnptrs; *cpp != NULL; cpp++) + ; + lpp = cpp; /* end of list to search */ + } + } else + msg = NULL; + for (c = *dn++; c != '\0'; ) { + /* look to see if we can use pointers */ + if (msg != NULL) { + if ((l = dn_find(dn-1, msg, dnptrs, lpp)) >= 0) { + if (cp+1 >= eob) + return (-1); + *cp++ = (l >> 8) | INDIR_MASK; + *cp++ = l % 256; + return (cp - comp_dn); + } + /* not found, save it */ + if (lastdnptr != NULL && cpp < lastdnptr-1) { + *cpp++ = cp; + *cpp = NULL; + } + } + sp = cp++; /* save ptr to length byte */ + do { + if (c == '.') { + c = *dn++; + break; + } + if (c == '\\') { + if ((c = *dn++) == '\0') + break; + } + if (cp >= eob) + return (-1); + *cp++ = c; + } while ((c = *dn++) != '\0'); + /* catch trailing '.'s but not '..' */ + if ((l = cp - sp - 1) == 0 && c == '\0') { + cp--; + break; + } + if (l <= 0 || l > MAXLABEL) + return (-1); + *sp = l; + } + if (cp >= eob) + return (-1); + *cp++ = '\0'; + return (cp - comp_dn); +} + +/* + * Skip over a compressed domain name. Return the size or -1. + */ +dn_skipname(comp_dn, eom) + u_char *comp_dn, *eom; +{ + register u_char *cp; + register int n; + + cp = comp_dn; + while (cp < eom && (n = *cp++)) { + /* + * check for indirection + */ + switch (n & INDIR_MASK) { + case 0: /* normal case, n == len */ + cp += n; + continue; + default: /* illegal type */ + return (-1); + case INDIR_MASK: /* indirection */ + cp++; + } + break; + } + return (cp - comp_dn); +} + +/* + * Search for expanded name from a list of previously compressed names. + * Return the offset from msg if found or -1. + * dnptrs is the pointer to the first name on the list, + * not the pointer to the start of the message. + */ +static +dn_find(exp_dn, msg, dnptrs, lastdnptr) + u_char *exp_dn, *msg; + u_char **dnptrs, **lastdnptr; +{ + register u_char *dn, *cp, **cpp; + register int n; + u_char *sp; + + for (cpp = dnptrs; cpp < lastdnptr; cpp++) { + dn = exp_dn; + sp = cp = *cpp; + while (n = *cp++) { + /* + * check for indirection + */ + switch (n & INDIR_MASK) { + case 0: /* normal case, n == len */ + while (--n >= 0) { + if (*dn == '\\') + dn++; + if (*dn++ != *cp++) + goto next; + } + if ((n = *dn++) == '\0' && *cp == '\0') + return (sp - msg); + if (n == '.') + continue; + goto next; + + default: /* illegal type */ + return (-1); + + case INDIR_MASK: /* indirection */ + cp = msg + (((n & 0x3f) << 8) | *cp); + } + } + if (*dn == '\0') + return (sp - msg); + next: ; + } + return (-1); +} + +/* + * Routines to insert/extract short/long's. Must account for byte + * order and non-alignment problems. This code at least has the + * advantage of being portable. + * + * used by sendmail. + */ + +u_short +_getshort(msgp) + u_char *msgp; +{ + register u_char *p = (u_char *) msgp; +#ifdef vax + /* + * vax compiler doesn't put shorts in registers + */ + register u_long u; +#else + register u_short u; +#endif + + u = *p++ << 8; + return ((u_short)(u | *p)); +} + +u_long +_getlong(msgp) + u_char *msgp; +{ + register u_char *p = (u_char *) msgp; + register u_long u; + + u = *p++; u <<= 8; + u |= *p++; u <<= 8; + u |= *p++; u <<= 8; + return (u | *p); +} + + +putshort(s, msgp) + register u_short s; + register u_char *msgp; +{ + + msgp[1] = s; + msgp[0] = s >> 8; +} + +putlong(l, msgp) + register u_long l; + register u_char *msgp; +{ + + msgp[3] = l; + msgp[2] = (l >>= 8); + msgp[1] = (l >>= 8); + msgp[0] = l >> 8; +} diff --git a/src/libc/net/res_debug.c b/src/libc/net/res_debug.c new file mode 100644 index 0000000..8bcecb5 --- /dev/null +++ b/src/libc/net/res_debug.c @@ -0,0 +1,439 @@ +/* + * Copyright (c) 1985 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that this notice is preserved and that due credit is given + * to the University of California at Berkeley. The name of the University + * may not be used to endorse or promote products derived from this + * software without specific prior written permission. This software + * is provided ``as is'' without express or implied warranty. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)res_debug.c 5.22 (Berkeley) 3/7/88"; +#endif /* LIBC_SCCS and not lint */ + +#if defined(lint) && !defined(DEBUG) +#define DEBUG +#endif + +#include +#include +#include +#include + +extern char *p_cdname(), *p_rr(), *p_type(), *p_class(); +extern char *inet_ntoa(); + +char *_res_opcodes[] = { + "QUERY", + "IQUERY", + "CQUERYM", + "CQUERYU", + "4", + "5", + "6", + "7", + "8", + "UPDATEA", + "UPDATED", + "UPDATEDA", + "UPDATEM", + "UPDATEMA", + "ZONEINIT", + "ZONEREF", +}; + +char *_res_resultcodes[] = { + "NOERROR", + "FORMERR", + "SERVFAIL", + "NXDOMAIN", + "NOTIMP", + "REFUSED", + "6", + "7", + "8", + "9", + "10", + "11", + "12", + "13", + "14", + "NOCHANGE", +}; + +p_query(msg) + char *msg; +{ +#ifdef DEBUG + fp_query(msg,stdout); +#endif +} + +/* + * Print the contents of a query. + * This is intended to be primarily a debugging routine. + */ +fp_query(msg,file) + char *msg; + FILE *file; +{ +#ifdef DEBUG + register char *cp; + register HEADER *hp; + register int n; + + /* + * Print header fields. + */ + hp = (HEADER *)msg; + cp = msg + sizeof(HEADER); + fprintf(file,"HEADER:\n"); + fprintf(file,"\topcode = %s", _res_opcodes[hp->opcode]); + fprintf(file,", id = %d", ntohs(hp->id)); + fprintf(file,", rcode = %s\n", _res_resultcodes[hp->rcode]); + fprintf(file,"\theader flags: "); + if (hp->qr) + fprintf(file," qr"); + if (hp->aa) + fprintf(file," aa"); + if (hp->tc) + fprintf(file," tc"); + if (hp->rd) + fprintf(file," rd"); + if (hp->ra) + fprintf(file," ra"); + if (hp->pr) + fprintf(file," pr"); + fprintf(file,"\n\tqdcount = %d", ntohs(hp->qdcount)); + fprintf(file,", ancount = %d", ntohs(hp->ancount)); + fprintf(file,", nscount = %d", ntohs(hp->nscount)); + fprintf(file,", arcount = %d\n\n", ntohs(hp->arcount)); + /* + * Print question records. + */ + if (n = ntohs(hp->qdcount)) { + fprintf(file,"QUESTIONS:\n"); + while (--n >= 0) { + fprintf(file,"\t"); + cp = p_cdname(cp, msg, file); + if (cp == NULL) + return; + fprintf(file,", type = %s", p_type(_getshort(cp))); + cp += sizeof(u_short); + fprintf(file,", class = %s\n\n", p_class(_getshort(cp))); + cp += sizeof(u_short); + } + } + /* + * Print authoritative answer records + */ + if (n = ntohs(hp->ancount)) { + fprintf(file,"ANSWERS:\n"); + while (--n >= 0) { + fprintf(file,"\t"); + cp = p_rr(cp, msg, file); + if (cp == NULL) + return; + } + } + /* + * print name server records + */ + if (n = ntohs(hp->nscount)) { + fprintf(file,"NAME SERVERS:\n"); + while (--n >= 0) { + fprintf(file,"\t"); + cp = p_rr(cp, msg, file); + if (cp == NULL) + return; + } + } + /* + * print additional records + */ + if (n = ntohs(hp->arcount)) { + fprintf(file,"ADDITIONAL RECORDS:\n"); + while (--n >= 0) { + fprintf(file,"\t"); + cp = p_rr(cp, msg, file); + if (cp == NULL) + return; + } + } +#endif +} + +char * +p_cdname(cp, msg, file) + char *cp, *msg; + FILE *file; +{ +#ifdef DEBUG + char name[MAXDNAME]; + int n; + + if ((n = dn_expand(msg, msg + 512, cp, name, sizeof(name))) < 0) + return (NULL); + if (name[0] == '\0') { + name[0] = '.'; + name[1] = '\0'; + } + fputs(name, file); + return (cp + n); +#endif +} + +/* + * Print resource record fields in human readable form. + */ +char * +p_rr(cp, msg, file) + char *cp, *msg; + FILE *file; +{ +#ifdef DEBUG + int type, class, dlen, n, c; + struct in_addr inaddr; + char *cp1; + + if ((cp = p_cdname(cp, msg, file)) == NULL) + return (NULL); /* compression error */ + fprintf(file,"\n\ttype = %s", p_type(type = _getshort(cp))); + cp += sizeof(u_short); + fprintf(file,", class = %s", p_class(class = _getshort(cp))); + cp += sizeof(u_short); + fprintf(file,", ttl = %lu", _getlong(cp)); + cp += sizeof(u_long); + fprintf(file,", dlen = %d\n", dlen = _getshort(cp)); + cp += sizeof(u_short); + cp1 = cp; + /* + * Print type specific data, if appropriate + */ + switch (type) { + case T_A: + switch (class) { + case C_IN: + bcopy(cp, (char *)&inaddr, sizeof(inaddr)); + if (dlen == 4) { + fprintf(file,"\tinternet address = %s\n", + inet_ntoa(inaddr)); + cp += dlen; + } else if (dlen == 7) { + fprintf(file,"\tinternet address = %s", + inet_ntoa(inaddr)); + fprintf(file,", protocol = %d", cp[4]); + fprintf(file,", port = %d\n", + (cp[5] << 8) + cp[6]); + cp += dlen; + } + break; + default: + cp += dlen; + } + break; + case T_CNAME: + case T_MB: +#ifdef OLDRR + case T_MD: + case T_MF: +#endif /* OLDRR */ + case T_MG: + case T_MR: + case T_NS: + case T_PTR: + fprintf(file,"\tdomain name = "); + cp = p_cdname(cp, msg, file); + fprintf(file,"\n"); + break; + + case T_HINFO: + if (n = *cp++) { + fprintf(file,"\tCPU=%.*s\n", n, cp); + cp += n; + } + if (n = *cp++) { + fprintf(file,"\tOS=%.*s\n", n, cp); + cp += n; + } + break; + + case T_SOA: + fprintf(file,"\torigin = "); + cp = p_cdname(cp, msg, file); + fprintf(file,"\n\tmail addr = "); + cp = p_cdname(cp, msg, file); + fprintf(file,"\n\tserial=%ld", _getlong(cp)); + cp += sizeof(u_long); + fprintf(file,", refresh=%ld", _getlong(cp)); + cp += sizeof(u_long); + fprintf(file,", retry=%ld", _getlong(cp)); + cp += sizeof(u_long); + fprintf(file,", expire=%ld", _getlong(cp)); + cp += sizeof(u_long); + fprintf(file,", min=%ld\n", _getlong(cp)); + cp += sizeof(u_long); + break; + + case T_MX: + fprintf(file,"\tpreference = %d,",_getshort(cp)); + cp += sizeof(u_short); + fprintf(file," name = "); + cp = p_cdname(cp, msg, file); + break; + + case T_MINFO: + fprintf(file,"\trequests = "); + cp = p_cdname(cp, msg, file); + fprintf(file,"\n\terrors = "); + cp = p_cdname(cp, msg, file); + break; + + case T_UINFO: + fprintf(file,"\t%s\n", cp); + cp += dlen; + break; + + case T_UID: + case T_GID: + if (dlen == 4) { + fprintf(file,"\t%ld\n", _getlong(cp)); + cp += sizeof(int); + } + break; + + case T_WKS: + if (dlen < sizeof(u_long) + 1) + break; + bcopy(cp, (char *)&inaddr, sizeof(inaddr)); + cp += sizeof(u_long); + fprintf(file,"\tinternet address = %s, protocol = %d\n\t", + inet_ntoa(inaddr), *cp++); + n = 0; + while (cp < cp1 + dlen) { + c = *cp++; + do { + if (c & 0200) + fprintf(file," %d", n); + c <<= 1; + } while (++n & 07); + } + putc('\n',file); + break; + +#ifdef ALLOW_T_UNSPEC + case T_UNSPEC: + { + int NumBytes = 8; + char *DataPtr; + int i; + + if (dlen < NumBytes) NumBytes = dlen; + fprintf(file, "\tFirst %d bytes of hex data:", + NumBytes); + for (i = 0, DataPtr = cp; i < NumBytes; i++, DataPtr++) + fprintf(file, " %x", *DataPtr); + fputs("\n", file); + cp += dlen; + } + break; +#endif /* ALLOW_T_UNSPEC */ + + default: + fprintf(file,"\t???\n"); + cp += dlen; + } + if (cp != cp1 + dlen) + fprintf(file,"packet size error (%#x != %#x)\n", cp, cp1+dlen); + fprintf(file,"\n"); + return (cp); +#endif +} + +static char nbuf[20]; + +/* + * Return a string for the type + */ +char * +p_type(type) + int type; +{ + switch (type) { + case T_A: + return("A"); + case T_NS: /* authoritative server */ + return("NS"); +#ifdef OLDRR + case T_MD: /* mail destination */ + return("MD"); + case T_MF: /* mail forwarder */ + return("MF"); +#endif /* OLDRR */ + case T_CNAME: /* connonical name */ + return("CNAME"); + case T_SOA: /* start of authority zone */ + return("SOA"); + case T_MB: /* mailbox domain name */ + return("MB"); + case T_MG: /* mail group member */ + return("MG"); + case T_MX: /* mail routing info */ + return("MX"); + case T_MR: /* mail rename name */ + return("MR"); + case T_NULL: /* null resource record */ + return("NULL"); + case T_WKS: /* well known service */ + return("WKS"); + case T_PTR: /* domain name pointer */ + return("PTR"); + case T_HINFO: /* host information */ + return("HINFO"); + case T_MINFO: /* mailbox information */ + return("MINFO"); + case T_AXFR: /* zone transfer */ + return("AXFR"); + case T_MAILB: /* mail box */ + return("MAILB"); + case T_MAILA: /* mail address */ + return("MAILA"); + case T_ANY: /* matches any type */ + return("ANY"); + case T_UINFO: + return("UINFO"); + case T_UID: + return("UID"); + case T_GID: + return("GID"); +#ifdef ALLOW_T_UNSPEC + case T_UNSPEC: + return("UNSPEC"); +#endif /* ALLOW_T_UNSPEC */ + default: + (void)sprintf(nbuf, "%d", type); + return(nbuf); + } +} + +/* + * Return a mnemonic for class + */ +char * +p_class(class) + int class; +{ + + switch (class) { + case C_IN: /* internet class */ + return("IN"); + case C_ANY: /* matches any class */ + return("ANY"); + default: + (void)sprintf(nbuf, "%d", class); + return(nbuf); + } +} diff --git a/src/libc/net/res_init.c b/src/libc/net/res_init.c new file mode 100644 index 0000000..022179e --- /dev/null +++ b/src/libc/net/res_init.c @@ -0,0 +1,138 @@ +/* + * Copyright (c) 1985 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that this notice is preserved and that due credit is given + * to the University of California at Berkeley. The name of the University + * may not be used to endorse or promote products derived from this + * software without specific prior written permission. This software + * is provided ``as is'' without express or implied warranty. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)res_init.c 6.8 (Berkeley) 3/7/88"; +#endif /* LIBC_SCCS and not lint */ + +#include +#include +#include +#include +#include +#include + +/* + * Resolver configuration file. Contains the address of the + * inital name server to query and the default domain for + * non fully qualified domain names. + */ + +#ifndef CONFFILE +#define CONFFILE "/etc/resolv.conf" +#endif + +/* + * Resolver state default settings + */ + +struct state _res = { + RES_TIMEOUT, /* retransmition time interval */ + 4, /* number of times to retransmit */ + RES_DEFAULT, /* options flags */ + 1, /* number of name servers */ +}; + +/* + * Set up default settings. If the configuration file exist, the values + * there will have precedence. Otherwise, the server address is set to + * INADDR_ANY and the default domain name comes from the gethostname(). + * + * The configuration file should only be used if you want to redefine your + * domain or run without a server on your machine. + * + * Return 0 if completes successfully, -1 on error + */ +res_init() +{ + register FILE *fp; + register char *cp, **pp; + char buf[BUFSIZ]; + extern u_long inet_addr(); + extern char *index(); + extern char *strcpy(), *strncpy(); + extern char *getenv(); + int n = 0; /* number of nameserver records read from file */ + + _res.nsaddr.sin_addr.s_addr = INADDR_ANY; + _res.nsaddr.sin_family = AF_INET; + _res.nsaddr.sin_port = htons(NAMESERVER_PORT); + _res.nscount = 1; + _res.defdname[0] = '\0'; + + if ((fp = fopen(CONFFILE, "r")) != NULL) { + /* read the config file */ + while (fgets(buf, sizeof(buf), fp) != NULL) { + /* read default domain name */ + if (!strncmp(buf, "domain", sizeof("domain") - 1)) { + cp = buf + sizeof("domain") - 1; + while (*cp == ' ' || *cp == '\t') + cp++; + if (*cp == '\0') + continue; + (void)strncpy(_res.defdname, cp, sizeof(_res.defdname)); + _res.defdname[sizeof(_res.defdname) - 1] = '\0'; + if ((cp = index(_res.defdname, '\n')) != NULL) + *cp = '\0'; + continue; + } + /* read nameservers to query */ + if (!strncmp(buf, "nameserver", + sizeof("nameserver") - 1) && (n < MAXNS)) { + cp = buf + sizeof("nameserver") - 1; + while (*cp == ' ' || *cp == '\t') + cp++; + if (*cp == '\0') + continue; + _res.nsaddr_list[n].sin_addr.s_addr = inet_addr(cp); + if (_res.nsaddr_list[n].sin_addr.s_addr == (unsigned)-1) + _res.nsaddr_list[n].sin_addr.s_addr = INADDR_ANY; + _res.nsaddr_list[n].sin_family = AF_INET; + _res.nsaddr_list[n].sin_port = htons(NAMESERVER_PORT); + if ( ++n >= MAXNS) { + n = MAXNS; +#ifdef DEBUG + if ( _res.options & RES_DEBUG ) + printf("MAXNS reached, reading resolv.conf\n"); +#endif DEBUG + } + continue; + } + } + if ( n > 1 ) + _res.nscount = n; + (void) fclose(fp); + } + if (_res.defdname[0] == 0) { + if (gethostname(buf, sizeof(_res.defdname)) == 0 && + (cp = index(buf, '.'))) + (void)strcpy(_res.defdname, cp + 1); + } + + /* Allow user to override the local domain definition */ + if ((cp = getenv("LOCALDOMAIN")) != NULL) + (void)strncpy(_res.defdname, cp, sizeof(_res.defdname)); + + /* find components of local domain that might be searched */ + pp = _res.dnsrch; + *pp++ = _res.defdname; + for (cp = _res.defdname, n = 0; *cp; cp++) + if (*cp == '.') + n++; + cp = _res.defdname; + for (; n >= LOCALDOMAINPARTS && pp < _res.dnsrch + MAXDNSRCH; n--) { + cp = index(cp, '.'); + *pp++ = ++cp; + } + _res.options |= RES_INIT; + return(0); +} diff --git a/src/libc/net/res_mkquery.c b/src/libc/net/res_mkquery.c new file mode 100644 index 0000000..f9bb7d7 --- /dev/null +++ b/src/libc/net/res_mkquery.c @@ -0,0 +1,200 @@ +/* + * Copyright (c) 1985 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that this notice is preserved and that due credit is given + * to the University of California at Berkeley. The name of the University + * may not be used to endorse or promote products derived from this + * software without specific prior written permission. This software + * is provided ``as is'' without express or implied warranty. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)res_mkquery.c 6.7 (Berkeley) 3/7/88"; +#endif /* LIBC_SCCS and not lint */ + +#include +#include +#include +#include +#include + +/* + * Form all types of queries. + * Returns the size of the result or -1. + */ +res_mkquery(op, dname, class, type, data, datalen, newrr, buf, buflen) + int op; /* opcode of query */ + char *dname; /* domain name */ + int class, type; /* class and type of query */ + char *data; /* resource record data */ + int datalen; /* length of data */ + struct rrec *newrr; /* new rr for modify or append */ + char *buf; /* buffer to put query */ + int buflen; /* size of buffer */ +{ + register HEADER *hp; + register char *cp; + register int n; + char dnbuf[MAXDNAME]; + char *dnptrs[10], **dpp, **lastdnptr; + extern char *index(); + +#ifdef DEBUG + if (_res.options & RES_DEBUG) + printf("res_mkquery(%d, %s, %d, %d)\n", op, dname, class, type); +#endif DEBUG + /* + * Initialize header fields. + */ + hp = (HEADER *) buf; + hp->id = htons(++_res.id); + hp->opcode = op; + hp->qr = hp->aa = hp->tc = hp->ra = 0; + hp->pr = (_res.options & RES_PRIMARY) != 0; + hp->rd = (_res.options & RES_RECURSE) != 0; + hp->rcode = NOERROR; + hp->qdcount = 0; + hp->ancount = 0; + hp->nscount = 0; + hp->arcount = 0; + cp = buf + sizeof(HEADER); + buflen -= sizeof(HEADER); + dpp = dnptrs; + *dpp++ = buf; + *dpp++ = NULL; + lastdnptr = dnptrs + sizeof(dnptrs)/sizeof(dnptrs[0]); + /* + * If the domain name contains no dots (single label), then + * append the default domain name to the one given. + */ + if ((_res.options & RES_DEFNAMES) && dname != 0 && dname[0] != '\0' && + index(dname, '.') == NULL) { + if (!(_res.options & RES_INIT)) + if (res_init() == -1) + return(-1); + if (_res.defdname[0] != '\0') { + (void)sprintf(dnbuf, "%s.%s", dname, _res.defdname); + dname = dnbuf; + } + } + /* + * perform opcode specific processing + */ + switch (op) { + case QUERY: + buflen -= QFIXEDSZ; + if ((n = dn_comp(dname, cp, buflen, dnptrs, lastdnptr)) < 0) + return (-1); + cp += n; + buflen -= n; + putshort(type, cp); + cp += sizeof(u_short); + putshort(class, cp); + cp += sizeof(u_short); + hp->qdcount = htons(1); + if (op == QUERY || data == NULL) + break; + /* + * Make an additional record for completion domain. + */ + buflen -= RRFIXEDSZ; + if ((n = dn_comp(data, cp, buflen, dnptrs, lastdnptr)) < 0) + return (-1); + cp += n; + buflen -= n; + putshort(T_NULL, cp); + cp += sizeof(u_short); + putshort(class, cp); + cp += sizeof(u_short); + putlong((long)0, cp); + cp += sizeof(u_long); + putshort(0, cp); + cp += sizeof(u_short); + hp->arcount = htons(1); + break; + + case IQUERY: + /* + * Initialize answer section + */ + if (buflen < 1 + RRFIXEDSZ + datalen) + return (-1); + *cp++ = '\0'; /* no domain name */ + putshort(type, cp); + cp += sizeof(u_short); + putshort(class, cp); + cp += sizeof(u_short); + putlong((long)0, cp); + cp += sizeof(u_long); + putshort(datalen, cp); + cp += sizeof(u_short); + if (datalen) { + bcopy(data, cp, datalen); + cp += datalen; + } + hp->ancount = htons(1); + break; + +#ifdef ALLOW_UPDATES + /* + * For UPDATEM/UPDATEMA, do UPDATED/UPDATEDA followed by UPDATEA + * (Record to be modified is followed by its replacement in msg.) + */ + case UPDATEM: + case UPDATEMA: + + case UPDATED: + /* + * The res code for UPDATED and UPDATEDA is the same; user + * calls them differently: specifies data for UPDATED; server + * ignores data if specified for UPDATEDA. + */ + case UPDATEDA: + buflen -= RRFIXEDSZ + datalen; + if ((n = dn_comp(dname, cp, buflen, dnptrs, lastdnptr)) < 0) + return (-1); + cp += n; + putshort(type, cp); + cp += sizeof(u_short); + putshort(class, cp); + cp += sizeof(u_short); + putlong((long)0, cp); + cp += sizeof(u_long); + putshort(datalen, cp); + cp += sizeof(u_short); + if (datalen) { + bcopy(data, cp, datalen); + cp += datalen; + } + if ( (op == UPDATED) || (op == UPDATEDA) ) { + hp->ancount = htons(0); + break; + } + /* Else UPDATEM/UPDATEMA, so drop into code for UPDATEA */ + + case UPDATEA: /* Add new resource record */ + buflen -= RRFIXEDSZ + datalen; + if ((n = dn_comp(dname, cp, buflen, dnptrs, lastdnptr)) < 0) + return (-1); + cp += n; + putshort(newrr->r_type, cp); + cp += sizeof(u_short); + putshort(newrr->r_class, cp); + cp += sizeof(u_short); + putlong((long)0, cp); + cp += sizeof(u_long); + putshort(newrr->r_size, cp); + cp += sizeof(u_short); + if (newrr->r_size) { + bcopy(newrr->r_data, cp, newrr->r_size); + cp += newrr->r_size; + } + hp->ancount = htons(0); + break; + +#endif ALLOW_UPDATES + } + return (cp - buf); +} diff --git a/src/libc/net/res_query.c b/src/libc/net/res_query.c new file mode 100644 index 0000000..e0fe2d1 --- /dev/null +++ b/src/libc/net/res_query.c @@ -0,0 +1,248 @@ +/* + * Copyright (c) 1988 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that this notice is preserved and that due credit is given + * to the University of California at Berkeley. The name of the University + * may not be used to endorse or promote products derived from this + * software without specific prior written permission. This software + * is provided ``as is'' without express or implied warranty. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)res_query.c 5.3 (Berkeley) 4/5/88"; +#endif /* LIBC_SCCS and not lint */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if PACKETSZ > 1024 +#define MAXPACKET PACKETSZ +#else +#define MAXPACKET 1024 +#endif + +extern int errno; +int h_errno; + +/* + * Formulate a normal query, send, and await answer. + * Returned answer is placed in supplied buffer "answer". + * Perform preliminary check of answer, returning success only + * if no error is indicated and the answer count is nonzero. + * Return the size of the response on success, -1 on error. + * Error number is left in h_errno. + * Caller must parse answer and determine whether it answers the question. + */ +res_query(name, class, type, answer, anslen) + char *name; /* domain name */ + int class, type; /* class and type of query */ + u_char *answer; /* buffer to put answer */ + int anslen; /* size of answer buffer */ +{ + char buf[MAXPACKET]; + HEADER *hp; + int n; + + if ((_res.options & RES_INIT) == 0 && res_init() == -1) + return (-1); +#ifdef DEBUG + if (_res.options & RES_DEBUG) + printf("res_query(%s, %d, %d)\n", name, class, type); +#endif + n = res_mkquery(QUERY, name, class, type, (char *)NULL, 0, NULL, + buf, sizeof(buf)); + + if (n <= 0) { +#ifdef DEBUG + if (_res.options & RES_DEBUG) + printf("res_query: mkquery failed\n"); +#endif + h_errno = NO_RECOVERY; + return (n); + } + n = res_send(buf, n, answer, anslen); + if (n < 0) { +#ifdef DEBUG + if (_res.options & RES_DEBUG) + printf("res_query: send error\n"); +#endif + h_errno = TRY_AGAIN; + return(n); + } + + hp = (HEADER *) answer; + if (hp->rcode != NOERROR || ntohs(hp->ancount) == 0) { +#ifdef DEBUG + if (_res.options & RES_DEBUG) + printf("rcode = %d, ancount=%d\n", hp->rcode, + ntohs(hp->ancount)); +#endif + switch (hp->rcode) { + case NXDOMAIN: + h_errno = HOST_NOT_FOUND; + break; + case SERVFAIL: + h_errno = TRY_AGAIN; + break; + case NOERROR: + h_errno = NO_DATA; + break; + case FORMERR: + case NOTIMP: + case REFUSED: + default: + h_errno = NO_RECOVERY; + break; + } + return (-1); + } + return(n); +} + +/* + * Formulate a normal query, send, and retrieve answer in supplied buffer. + * Return the size of the response on success, -1 on error. + * If enabled, implement search rules until answer or unrecoverable failure + * is detected. Error number is left in h_errno. + * Only useful for queries in the same name hierarchy as the local host + * (not, for example, for host address-to-name lookups in domain in-addr.arpa). + */ +res_search(name, class, type, answer, anslen) + char *name; /* domain name */ + int class, type; /* class and type of query */ + u_char *answer; /* buffer to put answer */ + int anslen; /* size of answer */ +{ + register char *cp, **domain; + int n, ret; + char *hostalias(); + + if ((_res.options & RES_INIT) == 0 && res_init() == -1) + return (-1); + + errno = 0; + h_errno = HOST_NOT_FOUND; /* default, if we never query */ + for (cp = name, n = 0; *cp; cp++) + if (*cp == '.') + n++; + if (n == 0 && (cp = hostalias(name))) + return (res_query(cp, class, type, answer, anslen)); + + if ((n == 0 || *--cp != '.') && (_res.options & RES_DEFNAMES)) + for (domain = _res.dnsrch; *domain; domain++) { + h_errno = 0; + ret = res_querydomain(name, *domain, class, type, + answer, anslen); + if (ret > 0) + return (ret); + /* + * If no server present, give up. + * If name isn't found in this domain, + * keep trying higher domains in the search list + * (if that's enabled). + * On a NO_DATA error, keep trying, otherwise + * a wildcard entry of another type could keep us + * from finding this entry higher in the domain. + * If we get some other error (non-authoritative negative + * answer or server failure), then stop searching up, + * but try the input name below in case it's fully-qualified. + */ + if (errno == ECONNREFUSED) { + h_errno = TRY_AGAIN; + return (-1); + } + if ((h_errno != HOST_NOT_FOUND && h_errno != NO_DATA) || + (_res.options & RES_DNSRCH) == 0) + break; + } + /* + * If the search/default failed, try the name as fully-qualified, + * but only if it contained at least one dot (even trailing). + */ + if (n) + return (res_querydomain(name, (char *)NULL, class, type, + answer, anslen)); + return (-1); +} + +/* + * Perform a call on res_query on the concatenation of name and domain, + * removing a trailing dot from name if domain is NULL. + */ +res_querydomain(name, domain, class, type, answer, anslen) + char *name, *domain; + int class, type; /* class and type of query */ + u_char *answer; /* buffer to put answer */ + int anslen; /* size of answer */ +{ + char nbuf[2*MAXDNAME+2]; + char *longname = nbuf; + int n; + +#ifdef DEBUG + if (_res.options & RES_DEBUG) + printf("res_querydomain(%s, %s, %d, %d)\n", + name, domain, class, type); +#endif + if (domain == NULL) { + /* + * Check for trailing '.'; + * copy without '.' if present. + */ + n = strlen(name) - 1; + if (name[n] == '.' && n < sizeof(nbuf) - 1) { + bcopy(name, nbuf, n); + nbuf[n] = '\0'; + } else + longname = name; + } else + (void)sprintf(nbuf, "%.*s.%.*s", + MAXDNAME, name, MAXDNAME, domain); + + return (res_query(longname, class, type, answer, anslen)); +} + +char * +hostalias(name) + register char *name; +{ + register char *C1, *C2; + FILE *fp; + char *file, *getenv(), *strcpy(), *strncpy(); + char buf[BUFSIZ]; + static char abuf[MAXDNAME]; + + file = getenv("HOSTALIASES"); + if (file == NULL || (fp = fopen(file, "r")) == NULL) + return (NULL); + buf[sizeof(buf) - 1] = '\0'; + while (fgets(buf, sizeof(buf), fp)) { + for (C1 = buf; *C1 && !isspace(*C1); ++C1); + if (!*C1) + break; + *C1 = '\0'; + if (!strcasecmp(buf, name)) { + while (isspace(*++C1)); + if (!*C1) + break; + for (C2 = C1 + 1; *C2 && !isspace(*C2); ++C2); + abuf[sizeof(abuf) - 1] = *C2 = '\0'; + (void)strncpy(abuf, C1, sizeof(abuf) - 1); + fclose(fp); + return (abuf); + } + } + fclose(fp); + return (NULL); +} diff --git a/src/libc/net/res_send.c b/src/libc/net/res_send.c new file mode 100644 index 0000000..f13d8ab --- /dev/null +++ b/src/libc/net/res_send.c @@ -0,0 +1,364 @@ +/* + * Copyright (c) 1985 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that this notice is preserved and that due credit is given + * to the University of California at Berkeley. The name of the University + * may not be used to endorse or promote products derived from this + * software without specific prior written permission. This software + * is provided ``as is'' without express or implied warranty. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)res_send.c 6.19.1 (Berkeley) 6/27/94"; +#endif /* LIBC_SCCS and not lint */ + +/* + * Send query to name server and wait for reply. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern int errno; + +static int s = -1; /* socket used for communications */ +static struct sockaddr no_addr; + + +#ifndef FD_SET +#define NFDBITS 32 +#define FD_SETSIZE 32 +#define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS))) +#define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS))) +#define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS))) +#define FD_ZERO(p) bzero((char *)(p), sizeof(*(p))) +#endif + +#define KEEPOPEN (RES_USEVC|RES_STAYOPEN) + +res_send(buf, buflen, answer, anslen) + char *buf; + int buflen; + char *answer; + int anslen; +{ + register int n; + int retry, v_circuit, resplen, ns; + int gotsomewhere = 0, connected = 0; + u_short id, len; + char *cp; + fd_set dsmask; + struct timeval timeout; + HEADER *hp = (HEADER *) buf; + HEADER *anhp = (HEADER *) answer; + struct iovec iov[2]; + int terrno = ETIMEDOUT; + char junk[16]; + +#ifdef DEBUG + if (_res.options & RES_DEBUG) { + printf("res_send()\n"); + p_query(buf); + } +#endif DEBUG + if (!(_res.options & RES_INIT)) + if (res_init() == -1) { + return(-1); + } + v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ; + id = hp->id; + /* + * Send request, RETRY times, or until successful + */ + for (retry = _res.retry; retry > 0; retry--) { + for (ns = 0; ns < _res.nscount; ns++) { +#ifdef DEBUG + if (_res.options & RES_DEBUG) + printf("Querying server (# %d) address = %s\n", ns+1, + inet_ntoa(_res.nsaddr_list[ns].sin_addr)); +#endif DEBUG + if (v_circuit) { + int truncated = 0; + + /* + * Use virtual circuit. + */ + if (s < 0) { + s = socket(AF_INET, SOCK_STREAM, 0); + if (s < 0) { + terrno = errno; +#ifdef DEBUG + if (_res.options & RES_DEBUG) + perror("socket failed"); +#endif DEBUG + continue; + } + if (connect(s, &(_res.nsaddr_list[ns]), + sizeof(struct sockaddr)) < 0) { + terrno = errno; +#ifdef DEBUG + if (_res.options & RES_DEBUG) + perror("connect failed"); +#endif DEBUG + (void) close(s); + s = -1; + continue; + } + } + /* + * Send length & message + */ + len = htons((u_short)buflen); + iov[0].iov_base = (caddr_t)&len; + iov[0].iov_len = sizeof(len); + iov[1].iov_base = buf; + iov[1].iov_len = buflen; + if (writev(s, iov, 2) != sizeof(len) + buflen) { + terrno = errno; +#ifdef DEBUG + if (_res.options & RES_DEBUG) + perror("write failed"); +#endif DEBUG + (void) close(s); + s = -1; + continue; + } + /* + * Receive length & response + */ + cp = answer; + len = sizeof(short); + while (len != 0 && + (n = read(s, (char *)cp, (int)len)) > 0) { + cp += n; + len -= n; + } + if (n <= 0) { + terrno = errno; +#ifdef DEBUG + if (_res.options & RES_DEBUG) + perror("read failed"); +#endif DEBUG + (void) close(s); + s = -1; + continue; + } + cp = answer; + if ((resplen = ntohs(*(u_short *)cp)) > anslen) { +#ifdef DEBUG + if (_res.options & RES_DEBUG) + fprintf(stderr, "response truncated\n"); +#endif DEBUG + len = anslen; + truncated = 1; + } else + len = resplen; + while (len != 0 && + (n = read(s, (char *)cp, (int)len)) > 0) { + cp += n; + len -= n; + } + if (n <= 0) { + terrno = errno; +#ifdef DEBUG + if (_res.options & RES_DEBUG) + perror("read failed"); +#endif DEBUG + (void) close(s); + s = -1; + continue; + } + if (truncated) { + /* + * Flush rest of answer + * so connection stays in synch. + */ + anhp->tc = 1; + len = resplen - anslen; + while (len != 0) { + n = (len > sizeof(junk) ? + sizeof(junk) : len); + if ((n = read(s, junk, n)) > 0) + len -= n; + else + break; + } + } + } else { + /* + * Use datagrams. + */ + if (s < 0) + s = socket(AF_INET, SOCK_DGRAM, 0); +#if BSD >= 43 + if (_res.nscount == 1 || retry == _res.retry) { + /* + * Don't use connect if we might + * still receive a response + * from another server. + */ + if (connected == 0) { + if (connect(s, &_res.nsaddr_list[ns], + sizeof(struct sockaddr)) < 0) { +#ifdef DEBUG + if (_res.options & RES_DEBUG) + perror("connect"); +#endif DEBUG + continue; + } + connected = 1; + } + if (send(s, buf, buflen, 0) != buflen) { +#ifdef DEBUG + if (_res.options & RES_DEBUG) + perror("send"); +#endif DEBUG + continue; + } + } else +#endif BSD + if (sendto(s, buf, buflen, 0, &_res.nsaddr_list[ns], + sizeof(struct sockaddr)) != buflen) { +#ifdef DEBUG + if (_res.options & RES_DEBUG) + perror("sendto"); +#endif DEBUG + continue; + } + + /* + * Wait for reply + */ + timeout.tv_sec = (_res.retrans << (_res.retry - retry)) + / _res.nscount; + if (timeout.tv_sec <= 0) + timeout.tv_sec = 1; + timeout.tv_usec = 0; +wait: + FD_ZERO(&dsmask); + FD_SET(s, &dsmask); + n = select(s+1, &dsmask, (fd_set *)NULL, + (fd_set *)NULL, &timeout); + if (n < 0) { +#ifdef DEBUG + if (_res.options & RES_DEBUG) + perror("select"); +#endif DEBUG + continue; + } + if (n == 0) { + /* + * timeout + */ +#ifdef DEBUG + if (_res.options & RES_DEBUG) + printf("timeout\n"); +#endif DEBUG + /* + * Disconnect if we want to listen + * for responses from more than one server. + */ + if (_res.nscount > 1 && connected) { + (void) connect(s, &no_addr, + sizeof(no_addr)); + connected = 0; + } + gotsomewhere = 1; + continue; + } + if ((resplen = recv(s, answer, anslen, 0)) <= 0) { +#ifdef DEBUG + if (_res.options & RES_DEBUG) + perror("recvfrom"); +#endif DEBUG + continue; + } + gotsomewhere = 1; + if (id != anhp->id) { + /* + * response from old query, ignore it + */ +#ifdef DEBUG + if (_res.options & RES_DEBUG) { + printf("old answer:\n"); + p_query(answer); + } +#endif DEBUG + goto wait; + } + if (!(_res.options & RES_IGNTC) && anhp->tc) { + /* + * get rest of answer + */ +#ifdef DEBUG + if (_res.options & RES_DEBUG) + printf("truncated answer\n"); +#endif DEBUG + (void) close(s); + s = -1; + /* + * retry decremented on continue + * to desired starting value + */ + retry = _res.retry + 1; + v_circuit = 1; + continue; + } + } +#ifdef DEBUG + if (_res.options & RES_DEBUG) { + printf("got answer:\n"); + p_query(answer); + } +#endif DEBUG + /* + * We are going to assume that the first server is preferred + * over the rest (i.e. it is on the local machine) and only + * keep that one open. + */ + if ((_res.options & KEEPOPEN) == KEEPOPEN && ns == 0) { + return (resplen); + } else { + (void) close(s); + s = -1; + return (resplen); + } + } + } + if (s >= 0) { + (void) close(s); + s = -1; + } + if (v_circuit == 0) + if (gotsomewhere == 0) + errno = ECONNREFUSED; + else + errno = ETIMEDOUT; + else + errno = terrno; + return (-1); +} + +/* + * This routine is for closing the socket if a virtual circuit is used and + * the program wants to close it. This provides support for endhostent() + * which expects to close the socket. + * + * This routine is not expected to be user visible. + */ +_res_close() +{ + if (s != -1) { + (void) close(s); + s = -1; + } +} diff --git a/src/libc/net/rexec.c b/src/libc/net/rexec.c new file mode 100644 index 0000000..681f6f4 --- /dev/null +++ b/src/libc/net/rexec.c @@ -0,0 +1,116 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)rexec.c 5.2.1 (2.11BSD) 1997/10/2"; +#endif LIBC_SCCS and not lint + +#include +#include + +#include + +#include +#include +#include + +int rexecoptions; + +rexec(ahost, rport, name, pass, cmd, fd2p) + char **ahost; + int rport; + char *name, *pass, *cmd; + int *fd2p; +{ + int s, timo = 1, s3; + struct sockaddr_in sin, sin2, from; + char c; + u_short port; + struct hostent *hp; + + hp = gethostbyname(*ahost); + if (hp == 0) { + fprintf(stderr, "%s: unknown host\n", *ahost); + return (-1); + } + *ahost = hp->h_name; + ruserpass(hp->h_name, &name, &pass); +retry: + s = socket(AF_INET, SOCK_STREAM, 0); + if (s < 0) { + perror("rexec: socket"); + return (-1); + } + sin.sin_family = hp->h_addrtype; + sin.sin_port = rport; + bcopy(hp->h_addr, (caddr_t)&sin.sin_addr, hp->h_length); + if (connect(s, &sin, sizeof(sin)) < 0) { + if (errno == ECONNREFUSED && timo <= 16) { + (void) close(s); + sleep(timo); + timo *= 2; + goto retry; + } + perror(hp->h_name); + return (-1); + } + if (fd2p == 0) { + (void) write(s, "", 1); + port = 0; + } else { + char num[8]; + int s2, sin2len; + + s2 = socket(AF_INET, SOCK_STREAM, 0); + if (s2 < 0) { + (void) close(s); + return (-1); + } + listen(s2, 1); + sin2len = sizeof (sin2); + if (getsockname(s2, (char *)&sin2, &sin2len) < 0 || + sin2len != sizeof (sin2)) { + perror("getsockname"); + (void) close(s2); + goto bad; + } + port = ntohs((u_short)sin2.sin_port); + (void) sprintf(num, "%u", port); + (void) write(s, num, strlen(num)+1); + { int len = sizeof (from); + s3 = accept(s2, &from, &len, 0); + close(s2); + if (s3 < 0) { + perror("accept"); + port = 0; + goto bad; + } + } + *fd2p = s3; + } + (void) write(s, name, strlen(name) + 1); + /* should public key encypt the password here */ + (void) write(s, pass, strlen(pass) + 1); + (void) write(s, cmd, strlen(cmd) + 1); + if (read(s, &c, 1) != 1) { + perror(*ahost); + goto bad; + } + if (c != 0) { + while (read(s, &c, 1) == 1) { + (void) write(2, &c, 1); + if (c == '\n') + break; + } + goto bad; + } + return (s); +bad: + if (port) + (void) close(*fd2p); + (void) close(s); + return (-1); +} diff --git a/src/libc/net/ruserpass.c b/src/libc/net/ruserpass.c new file mode 100644 index 0000000..d5a8588 --- /dev/null +++ b/src/libc/net/ruserpass.c @@ -0,0 +1,810 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)ruserpass.c 5.2.1 (2.11BSD) 1996/11/16"; +#endif LIBC_SCCS and not lint + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +char *renvlook(); +struct utmp *getutmp(); +static FILE *cfile; + +ruserpass(host, aname, apass) + char *host, **aname, **apass; +{ + + renv(host, aname, apass); + if (*aname == 0 || *apass == 0) + rnetrc(host, aname, apass); + if (*aname == 0) { + char *myname = getlogin(); + *aname = (char *)malloc(16); + printf("Name (%s:%s): ", host, myname); + fflush(stdout); + if (read(2, *aname, 16) <= 0) + exit(1); + if ((*aname)[0] == '\n') + *aname = myname; + else + if (index(*aname, '\n')) + *index(*aname, '\n') = 0; + } + if (*aname && *apass == 0) { + printf("Password (%s:%s): ", host, *aname); + fflush(stdout); + *apass = getpass(""); + } +} + +static +renv(host, aname, apass) + char *host, **aname, **apass; +{ + register char *cp; + char *stemp, fgetlogin, *comma; + + cp = renvlook(host); + if (cp == NULL) + return; + if (!isalpha(cp[0])) + return; + comma = index(cp, ','); + if (comma == 0) + return; + if (*aname == 0) { + *aname = (char *)malloc(comma - cp + 1); + strncpy(*aname, cp, comma - cp); + } else + if (strncmp(*aname, cp, comma - cp)) + return; + comma++; + cp = (char *)malloc(strlen(comma)+1); + strcpy(cp, comma); + *apass = (char *)malloc(16); + mkpwclear(cp, host[0], *apass); +} + +static +char * +renvlook(host) + char *host; +{ + register char *cp, **env; + + env = environ; + for (env = environ; *env != NULL; env++) + if (!strncmp(*env, "MACH", 4)) { + cp = index(*env, '='); + if (cp == 0) + continue; + if (strncmp(*env+4, host, cp-(*env+4))) + continue; + return (cp+1); + } + return (NULL); +} + +#define DEFAULT 1 +#define LOGIN 2 +#define PASSWD 3 +#define NOTIFY 4 +#define WRITE 5 +#define YES 6 +#define NO 7 +#define COMMAND 8 +#define FORCE 9 +#define ID 10 +#define MACHINE 11 + +static char tokval[100]; + +static struct toktab { + char *tokstr; + int tval; +} toktab[]= { + "default", DEFAULT, + "login", LOGIN, + "password", PASSWD, + "notify", NOTIFY, + "write", WRITE, + "yes", YES, + "y", YES, + "no", NO, + "n", NO, + "command", COMMAND, + "force", FORCE, + "machine", MACHINE, + 0, 0 +}; + +static +rnetrc(host, aname, apass) + char *host, **aname, **apass; +{ + char *hdir, buf[BUFSIZ]; + int t; + struct stat stb; + extern int errno; + + hdir = getenv("HOME"); + if (hdir == NULL) + hdir = "."; + sprintf(buf, "%s/.netrc", hdir); + cfile = fopen(buf, "r"); + if (cfile == NULL) { + if (errno != ENOENT) + perror(buf); + return; + } +next: + while ((t = token())) switch(t) { + + case DEFAULT: + (void) token(); + continue; + + case MACHINE: + if (token() != ID || strcmp(host, tokval)) + continue; + while ((t = token()) && t != MACHINE) switch(t) { + + case LOGIN: + if (token()) + if (*aname == 0) { + *aname = (char *)malloc(strlen(tokval) + 1); + strcpy(*aname, tokval); + } else { + if (strcmp(*aname, tokval)) + goto next; + } + break; + case PASSWD: + if (fstat(fileno(cfile), &stb) >= 0 + && (stb.st_mode & 077) != 0) { + fprintf(stderr, "Error - .netrc file not correct mode.\n"); + fprintf(stderr, "Remove password or correct mode.\n"); + exit(1); + } + if (token() && *apass == 0) { + *apass = (char *)malloc(strlen(tokval) + 1); + strcpy(*apass, tokval); + } + break; + case COMMAND: + case NOTIFY: + case WRITE: + case FORCE: + (void) token(); + break; + default: + fprintf(stderr, "Unknown .netrc option %s\n", tokval); + break; + } + goto done; + } +done: + fclose(cfile); +} + +static +token() +{ + char *cp; + int c; + struct toktab *t; + + if (feof(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); +} +/* rest is nbs.c stolen from berknet */ + +char *deblknot(), *deblkclr(); +char *nbs8decrypt(), *nbs8encrypt(); +static char E[48]; + +/* + * The E bit-selection table. + */ +static char e[] = { + 32, 1, 2, 3, 4, 5, + 4, 5, 6, 7, 8, 9, + 8, 9,10,11,12,13, + 12,13,14,15,16,17, + 16,17,18,19,20,21, + 20,21,22,23,24,25, + 24,25,26,27,28,29, + 28,29,30,31,32, 1, +}; +static +char *nbsencrypt(str,key,result) + char *result; + char *str, *key; { + static char buf[20],oldbuf[20]; + register int j; + result[0] = 0; + strcpy(oldbuf,key); + while(*str){ + for(j=0;j<10;j++)buf[j] = 0; + for(j=0;j<8 && *str;j++)buf[j] = *str++; + strcat(result,nbs8encrypt(buf,oldbuf)); + strcat(result,"$"); + strcpy(oldbuf,buf); + } + return(result); + } +static +char *nbsdecrypt(cpt,key,result) + char *result; + char *cpt,*key; { + char *s; + char c,oldbuf[20]; + result[0] = 0; + strcpy(oldbuf,key); + while(*cpt){ + for(s = cpt;*s && *s != '$';s++); + c = *s; + *s = 0; + strcpy(oldbuf,nbs8decrypt(cpt,oldbuf)); + strcat(result,oldbuf); + if(c == 0)break; + cpt = s + 1; + } + return(result); + } + +static +char *nbs8encrypt(str,key) +char *str, *key; { + static char keyblk[100], blk[100]; + register int i; + + enblkclr(keyblk,key); + nbssetkey(keyblk); + + for(i=0;i<48;i++) E[i] = e[i]; + enblkclr(blk,str); + blkencrypt(blk,0); /* forward dir */ + + return(deblknot(blk)); +} + +static +char *nbs8decrypt(crp,key) +char *crp, *key; { + static char keyblk[100], blk[100]; + register int i; + + enblkclr(keyblk,key); + nbssetkey(keyblk); + + for(i=0;i<48;i++) E[i] = e[i]; + enblknot(blk,crp); + blkencrypt(blk,1); /* backward dir */ + + return(deblkclr(blk)); +} + +static +enblkclr(blk,str) /* ignores top bit of chars in string str */ +char *blk,*str; { + register int i,j; + char c; + for(i=0;i<70;i++)blk[i] = 0; + for(i=0; (c= *str) && i<64; str++){ + for(j=0; j<7; j++, i++) + blk[i] = (c>>(6-j)) & 01; + i++; + } + } + +static +char *deblkclr(blk) +char *blk; { + register int i,j; + char c; + static char iobuf[30]; + for(i=0; i<10; i++){ + c = 0; + for(j=0; j<7; j++){ + c <<= 1; + c |= blk[8*i+j]; + } + iobuf[i] = c; + } + iobuf[i] = 0; + return(iobuf); + } + +static +enblknot(blk,crp) +char *blk; +char *crp; { + register int i,j; + char c; + for(i=0;i<70;i++)blk[i] = 0; + for(i=0; (c= *crp) && i<64; crp++){ + if(c>'Z') c -= 6; + if(c>'9') c -= 7; + c -= '.'; + for(j=0; j<6; j++, i++) + blk[i] = (c>>(5-j)) & 01; + } + } + +static +char *deblknot(blk) +char *blk; { + register int i,j; + char c; + static char iobuf[30]; + for(i=0; i<11; i++){ + c = 0; + for(j=0; j<6; j++){ + c <<= 1; + c |= blk[6*i+j]; + } + c += '.'; + if(c > '9')c += 7; + if(c > 'Z')c += 6; + iobuf[i] = c; + } + iobuf[i] = 0; + return(iobuf); +} + +/* + * This program implements the + * Proposed Federal Information Processing + * Data Encryption Standard. + * See Federal Register, March 17, 1975 (40FR12134) + */ + +/* + * Initial permutation, + */ +static char IP[] = { + 58,50,42,34,26,18,10, 2, + 60,52,44,36,28,20,12, 4, + 62,54,46,38,30,22,14, 6, + 64,56,48,40,32,24,16, 8, + 57,49,41,33,25,17, 9, 1, + 59,51,43,35,27,19,11, 3, + 61,53,45,37,29,21,13, 5, + 63,55,47,39,31,23,15, 7, +}; + +/* + * Final permutation, FP = IP^(-1) + */ +static char FP[] = { + 40, 8,48,16,56,24,64,32, + 39, 7,47,15,55,23,63,31, + 38, 6,46,14,54,22,62,30, + 37, 5,45,13,53,21,61,29, + 36, 4,44,12,52,20,60,28, + 35, 3,43,11,51,19,59,27, + 34, 2,42,10,50,18,58,26, + 33, 1,41, 9,49,17,57,25, +}; + +/* + * Permuted-choice 1 from the key bits + * to yield C and D. + * Note that bits 8,16... are left out: + * They are intended for a parity check. + */ +static char PC1_C[] = { + 57,49,41,33,25,17, 9, + 1,58,50,42,34,26,18, + 10, 2,59,51,43,35,27, + 19,11, 3,60,52,44,36, +}; + +static char PC1_D[] = { + 63,55,47,39,31,23,15, + 7,62,54,46,38,30,22, + 14, 6,61,53,45,37,29, + 21,13, 5,28,20,12, 4, +}; + +/* + * Sequence of shifts used for the key schedule. +*/ +static char shifts[] = { + 1,1,2,2,2,2,2,2,1,2,2,2,2,2,2,1, +}; + +/* + * Permuted-choice 2, to pick out the bits from + * the CD array that generate the key schedule. + */ +static char PC2_C[] = { + 14,17,11,24, 1, 5, + 3,28,15, 6,21,10, + 23,19,12, 4,26, 8, + 16, 7,27,20,13, 2, +}; + +static char PC2_D[] = { + 41,52,31,37,47,55, + 30,40,51,45,33,48, + 44,49,39,56,34,53, + 46,42,50,36,29,32, +}; + +/* + * The C and D arrays used to calculate the key schedule. + */ + +static char C[28]; +static char D[28]; +/* + * The key schedule. + * Generated from the key. + */ +static char KS[16][48]; + +/* + * Set up the key schedule from the key. + */ + +static +nbssetkey(key) +char *key; +{ + register i, j, k; + int t; + + /* + * First, generate C and D by permuting + * the key. The low order bit of each + * 8-bit char is not used, so C and D are only 28 + * bits apiece. + */ + for (i=0; i<28; i++) { + C[i] = key[PC1_C[i]-1]; + D[i] = key[PC1_D[i]-1]; + } + /* + * To generate Ki, rotate C and D according + * to schedule and pick up a permutation + * using PC2. + */ + for (i=0; i<16; i++) { + /* + * rotate. + */ + for (k=0; k>3)&01; + f[t+1] = (k>>2)&01; + f[t+2] = (k>>1)&01; + f[t+3] = (k>>0)&01; + } + /* + * The new R is L ^ f(R, K). + * The f here has to be permuted first, though. + */ + for (j=0; j<32; j++) + R[j] = L[j] ^ f[P[j]-1]; + /* + * Finally, the new L (the original R) + * is copied back. + */ + for (j=0; j<32; j++) + L[j] = tempL[j]; + } + /* + * The output L and R are reversed. + */ + for (j=0; j<32; j++) { + t = L[j]; + L[j] = R[j]; + R[j] = t; + } + /* + * The final output + * gets the inverse permutation of the very original. + */ + for (j=0; j<64; j++) + block[j] = L[FP[j]-1]; +} +/* + getutmp() + return a pointer to the system utmp structure associated with + terminal sttyname, e.g. "/dev/tty3" + Is version independent-- will work on v6 systems + return NULL if error +*/ +static +struct utmp *getutmp(sttyname) +char *sttyname; +{ + static struct utmp utmpstr; + FILE *fdutmp; + + if(sttyname == NULL || sttyname[0] == 0)return(NULL); + + fdutmp = fopen(_PATH_UTMP,"r"); + if(fdutmp == NULL)return(NULL); + + while(fread(&utmpstr,1,sizeof utmpstr,fdutmp) == sizeof utmpstr) + if(strcmp(utmpstr.ut_line,sttyname+5) == 0){ + fclose(fdutmp); + return(&utmpstr); + } + fclose(fdutmp); + return(NULL); +} + +static +sreverse(sto, sfrom) + register char *sto, *sfrom; +{ + register int i; + + i = strlen(sfrom); + while (i >= 0) + *sto++ = sfrom[i--]; +} + +static +char *mkenvkey(mch) + char mch; +{ + static char skey[40]; + register struct utmp *putmp; + char stemp[40], stemp1[40], sttyname[30]; + register char *sk,*p; + + if (isatty(2)) + strcpy(sttyname,ttyname(2)); + else if (isatty(0)) + strcpy(sttyname,ttyname(0)); + else if (isatty(1)) + strcpy(sttyname,ttyname(1)); + else + return (NULL); + putmp = getutmp(sttyname); + if (putmp == NULL) + return (NULL); + sk = skey; + p = putmp->ut_line; + while (*p) + *sk++ = *p++; + *sk++ = mch; + sprintf(stemp, "%ld", putmp->ut_time); + sreverse(stemp1, stemp); + p = stemp1; + while (*p) + *sk++ = *p++; + *sk = 0; + return (skey); +} + +mkpwunclear(spasswd,mch,sencpasswd) + char mch, *spasswd, *sencpasswd; +{ + register char *skey; + + if (spasswd[0] == 0) { + sencpasswd[0] = 0; + return; + } + skey = mkenvkey(mch); + if (skey == NULL) { + fprintf(stderr, "Can't make key\n"); + exit(1); + } + nbsencrypt(spasswd, skey, sencpasswd); +} + +mkpwclear(sencpasswd,mch,spasswd) + char mch, *spasswd, *sencpasswd; +{ + register char *skey; + + if (sencpasswd[0] == 0) { + spasswd[0] = 0; + return; + } + skey = mkenvkey(mch); + if (skey == NULL) { + fprintf(stderr, "Can't make key\n"); + exit(1); + } + nbsdecrypt(sencpasswd, skey, spasswd); +} diff --git a/src/libc/ns/Makefile b/src/libc/ns/Makefile new file mode 100644 index 0000000..c9b22ed --- /dev/null +++ b/src/libc/ns/Makefile @@ -0,0 +1,61 @@ +# +# Copyright (c) 1980 Regents of the University of California. +# All rights reserved. The Berkeley software License Agreement +# specifies the terms and conditions for redistribution. +# +# @(#)Makefile 6.1 (Berkeley) 1/29/86 +# + +SRCS= ns_addr.c ns_ntoa.c +OBJS= ns_addr.o ns_ntoa.o +CFLAGS+= ${DEFS} +TAGSFILE=tags + +.c.o: + ${CC} -p -c ${CFLAGS} $*.c + -ld -X -r $*.o + mv a.out profiled/$*.o + ${CC} ${CFLAGS} -c $*.c + -ld -x -r $*.o + mv a.out $*.o + +nslib nslib_p: ${OBJS} + @echo "building profiled nslib" + @cd profiled; ar cru ../nslib_p ${OBJS} + @echo "building normal nslib" + @ar cru nslib ${OBJS} + +tags: + cwd=`pwd`; \ + for i in ${SRCS}; do \ + ctags -a -f ${TAGSFILE} $$cwd/$$i; \ + done + +clean: + rm -f nslib nslib_p *.o profiled/*.o errs a.out core \ + tags Makefile.bak + +depend: + for i in ${SRCS}; do \ + cc -M ${CFLAGS} $$i | 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 } ' >> makedep; done + echo '/^# DO NOT DELETE THIS LINE/+2,$$d' >eddep + echo '$$r makedep' >>eddep + echo 'w' >>eddep + cp Makefile Makefile.bak + ed - Makefile < eddep + rm eddep makedep + echo '# DEPENDENCIES MUST END AT END OF FILE' >> Makefile + echo '# IF YOU PUT STUFF HERE IT WILL GO AWAY' >> Makefile + echo '# see make depend above' >> Makefile + +# DO NOT DELETE THIS LINE -- make depend uses it + +ns_addr.o: ns_addr.c /usr/include/sys/types.h /usr/include/netns/ns.h +ns_ntoa.o: ns_ntoa.c /usr/include/sys/types.h /usr/include/netns/ns.h +# DEPENDENCIES MUST END AT END OF FILE +# IF YOU PUT STUFF HERE IT WILL GO AWAY +# see make depend above diff --git a/src/libc/ns/ns_addr.c b/src/libc/ns/ns_addr.c new file mode 100644 index 0000000..d182487 --- /dev/null +++ b/src/libc/ns/ns_addr.c @@ -0,0 +1,196 @@ +/* + * Copyright (c) 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + * + * Includes material written at Cornell University, by J. Q. Johnson. + * Used by permission. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)ns_addr.c 6.2 (Berkeley) 3/9/86"; +#endif LIBC_SCCS and not lint + +#include +#include + +static struct ns_addr addr, zero_addr; + +struct ns_addr +ns_addr(name) + char *name; +{ + u_long net; + u_short socket; + char separator = '.'; + char *hostname, *socketname, *cp; + char buf[50]; + extern char *index(); + + addr = zero_addr; + strncpy(buf, name, 49); + + /* + * First, figure out what he intends as a field separtor. + * Despite the way this routine is written, the prefered + * form 2-272.AA001234H.01777, i.e. XDE standard. + * Great efforts are made to insure backward compatability. + */ + if (hostname = index(buf, '#')) + separator = '#'; + else { + hostname = index(buf, '.'); + if ((cp = index(buf, ':')) && + ( (hostname && cp < hostname) || (hostname == 0))) { + hostname = cp; + separator = ':'; + } + } + if (hostname) + *hostname++ = 0; + Field(buf, addr.x_net.c_net, 4); + if (hostname == 0) + return (addr); /* No separator means net only */ + + socketname = index(hostname, separator); + if (socketname) { + *socketname++ = 0; + Field(socketname, &addr.x_port, 2); + } + + Field(hostname, addr.x_host.c_host, 6); + + return (addr); +} + +static +Field(buf, out, len) +char *buf; +u_char *out; +int len; +{ + register char *bp = buf; + int i, ibase, base16 = 0, base10 = 0, clen = 0; + int hb[6], *hp; + char *fmt; + + /* + * first try 2-273#2-852-151-014#socket + */ + if ((*buf != '-') && + (1 < (i = sscanf(buf, "%d-%d-%d-%d-%d", + &hb[0], &hb[1], &hb[2], &hb[3], &hb[4])))) { + cvtbase(1000, 256, hb, i, out, len); + return; + } + /* + * try form 8E1#0.0.AA.0.5E.E6#socket + */ + if (1 < (i = sscanf(buf,"%x.%x.%x.%x.%x.%x", + &hb[0], &hb[1], &hb[2], &hb[3], &hb[4], &hb[5]))) { + cvtbase(256, 256, hb, i, out, len); + return; + } + /* + * try form 8E1#0:0:AA:0:5E:E6#socket + */ + if (1 < (i = sscanf(buf,"%x:%x:%x:%x:%x:%x", + &hb[0], &hb[1], &hb[2], &hb[3], &hb[4], &hb[5]))) { + cvtbase(256, 256, hb, i, out, len); + return; + } + /* + * This is REALLY stretching it but there was a + * comma notation separting shorts -- definitely non standard + */ + if (1 < (i = sscanf(buf,"%x,%x,%x", + &hb[0], &hb[1], &hb[2]))) { + hb[0] = htons(hb[0]); hb[1] = htons(hb[1]); + hb[2] = htons(hb[2]); + cvtbase(65536, 256, hb, i, out, len); + return; + } + + /* Need to decide if base 10, 16 or 8 */ + while (*bp) switch (*bp++) { + + case '0': case '1': case '2': case '3': case '4': case '5': + case '6': case '7': case '-': + break; + + case '8': case '9': + base10 = 1; + break; + + case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': + case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': + base16 = 1; + break; + + case 'x': case 'X': + *--bp = '0'; + base16 = 1; + break; + + case 'h': case 'H': + base16 = 1; + /* fall into */ + + default: + *--bp = 0; /* Ends Loop */ + } + if (base16) { + fmt = "%3x"; + ibase = 4096; + } else if (base10 == 0 && *buf == '0') { + fmt = "%3o"; + ibase = 512; + } else { + fmt = "%3d"; + ibase = 1000; + } + + for (bp = buf; *bp++; ) clen++; + if (clen == 0) clen++; + if (clen > 18) clen = 18; + i = ((clen - 1) / 3) + 1; + bp = clen + buf - 3; + hp = hb + i - 1; + + while (hp > hb) { + sscanf(bp, fmt, hp); + bp[0] = 0; + hp--; + bp -= 3; + } + sscanf(buf, fmt, hp); + cvtbase(ibase, 256, hb, i, out, len); +} + +static +cvtbase(oldbase,newbase,input,inlen,result,reslen) + long oldbase; + int newbase; + int input[]; + int inlen; + unsigned char result[]; + int reslen; +{ + int d, e; + long sum; + + e = 1; + while (e > 0 && reslen > 0) { + d = 0; e = 0; sum = 0; + /* long division: input=input/newbase */ + while (d < inlen) { + sum = sum*oldbase + (long) input[d]; + e += (sum > 0); + input[d++] = sum / newbase; + sum %= newbase; + } + result[--reslen] = sum; /* accumulate remainder */ + } + for (d=0; d < reslen; d++) + result[d] = 0; +} diff --git a/src/libc/ns/ns_ntoa.c b/src/libc/ns/ns_ntoa.c new file mode 100644 index 0000000..f72ca71 --- /dev/null +++ b/src/libc/ns/ns_ntoa.c @@ -0,0 +1,73 @@ +/* + * Copyright (c) 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + * + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)ns_ntoa.c 6.3 (Berkeley) 3/9/86"; +#endif LIBC_SCCS and not lint + +#include +#include + +char * +ns_ntoa(addr) +struct ns_addr addr; +{ + static char obuf[40]; + char *spectHex(); + union { union ns_net net_e; u_long long_e; } net; + u_short port = htons(addr.x_port); + register char *cp; + char *cp2; + register u_char *up = addr.x_host.c_host; + u_char *uplim = up + 6; + + net.net_e = addr.x_net; + sprintf(obuf, "%lx", ntohl(net.long_e)); + cp = spectHex(obuf); + cp2 = cp + 1; + while (*up==0 && up < uplim) up++; + if (up == uplim) { + if (port) { + sprintf(cp, ".0"); + cp += 2; + } + } else { + sprintf(cp, ".%x", *up++); + while (up < uplim) { + while (*cp) cp++; + sprintf(cp, "%02x", *up++); + } + cp = spectHex(cp2); + } + if (port) { + sprintf(cp, ".%x", port); + spectHex(cp + 1); + } + return (obuf); +} + +static char * +spectHex(p0) +char *p0; +{ + int ok = 0; + int nonzero = 0; + register char *p = p0; + for (; *p; p++) switch (*p) { + + case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': + *p += ('A' - 'a'); + /* fall into . . . */ + case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': + ok = 1; + case '1': case '2': case '3': case '4': case '5': + case '6': case '7': case '8': case '9': + nonzero = 1; + } + if (nonzero && !ok) { *p++ = 'H'; *p = 0; } + return (p); +} diff --git a/src/libc/runtime/CREDITS.txt b/src/libc/runtime/CREDITS.txt new file mode 100644 index 0000000..818f4fa --- /dev/null +++ b/src/libc/runtime/CREDITS.txt @@ -0,0 +1,24 @@ +This file is a partial list of people who have contributed to the LLVM/CompilerRT +project. If you have contributed a patch or made some other contribution to +LLVM/CompilerRT, please submit a patch to this file to add yourself, and it will be +done! + +The list is sorted by surname and formatted to allow easy grepping and +beautification by scripts. The fields are: name (N), email (E), web-address +(W), PGP key ID and fingerprint (P), description (D), and snail-mail address +(S). + +N: Craig van Vliet +E: cvanvliet@auroraux.org +W: http://www.auroraux.org +D: Code style and Readability fixes. + +N: Edward O'Callaghan +E: eocallaghan@auroraux.org +W: http://www.auroraux.org +D: CMake'ify Compiler-RT build system +D: Maintain Solaris & AuroraUX ports of Compiler-RT + +N: Howard Hinnant +E: hhinnant@apple.com +D: Architect and primary author of compiler-rt diff --git a/src/libc/runtime/LICENSE.txt b/src/libc/runtime/LICENSE.txt new file mode 100644 index 0000000..f717942 --- /dev/null +++ b/src/libc/runtime/LICENSE.txt @@ -0,0 +1,97 @@ +============================================================================== +compiler_rt License +============================================================================== + +The compiler_rt library is dual licensed under both the University of Illinois +"BSD-Like" license and the MIT license. As a user of this code you may choose +to use it under either license. As a contributor, you agree to allow your code +to be used under both. + +Full text of the relevant licenses is included below. + +============================================================================== + +University of Illinois/NCSA +Open Source License + +Copyright (c) 2009-2012 by the contributors listed in CREDITS.TXT + +All rights reserved. + +Developed by: + + LLVM Team + + University of Illinois at Urbana-Champaign + + http://llvm.org + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal with +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimers. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimers in the + documentation and/or other materials provided with the distribution. + + * Neither the names of the LLVM Team, University of Illinois at + Urbana-Champaign, nor the names of its contributors may be used to + endorse or promote products derived from this Software without specific + prior written permission. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE +SOFTWARE. + +============================================================================== + +Copyright (c) 2009-2012 by the contributors listed in CREDITS.TXT + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +============================================================================== +Copyrights and Licenses for Third Party Software Distributed with LLVM: +============================================================================== +The LLVM software contains code written by third parties. Such software will +have its own individual LICENSE.TXT file in the directory in which it appears. +This file will describe the copyrights, license, and restrictions which apply +to that code. + +The disclaimer of warranty in the University of Illinois Open Source License +applies to all code in the LLVM Distribution, and nothing in any of the +other licenses gives permission to use the names of the LLVM Team or the +University of Illinois to endorse or promote products derived from this +Software. + +The following pieces of software have additional or alternate copyrights, +licenses, and/or restrictions: + +Program Directory +------- --------- +mach_override lib/interception/mach_override diff --git a/src/libc/runtime/Makefile b/src/libc/runtime/Makefile new file mode 100644 index 0000000..ccf3c79 --- /dev/null +++ b/src/libc/runtime/Makefile @@ -0,0 +1,37 @@ +# +# 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 redistribution 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. +# +TOPSRC = $(shell cd ../../..; pwd) +include $(TOPSRC)/target.mk + +CFLAGS += ${DEFS} + +OBJS = addsf3.o comparesf2.o divsf3.o fixsfsi.o floatsisf.o \ + mulsf3.o negsf2.o subsf3.o sc_case.o + +all: ${OBJS} + +clean: + rm -f *.a *.o *~ profiled/*.o tags + +cleandir: clean + rm -f .depend + +install: all +# cp ../libgcc.a ${DESTDIR}/lib/ +# $(RANLIB) -t ${DESTDIR}/lib/libgcc.a +# cp libgcc_p.a ${DESTDIR}/lib/ +# $(RANLIB) -t ${DESTDIR}/lib/libgcc_p.a diff --git a/src/libc/runtime/README.txt b/src/libc/runtime/README.txt new file mode 100644 index 0000000..b37c0ae --- /dev/null +++ b/src/libc/runtime/README.txt @@ -0,0 +1,343 @@ +Compiler-RT +================================ + +This directory and its subdirectories contain source code for the compiler +support routines. + +Compiler-RT is open source software. You may freely distribute it under the +terms of the license agreement found in LICENSE.txt. + +================================ + +This is a replacement library for libgcc. Each function is contained +in its own file. Each function has a corresponding unit test under +test/Unit. + +A rudimentary script to test each file is in the file called +test/Unit/test. + +Here is the specification for this library: + +http://gcc.gnu.org/onlinedocs/gccint/Libgcc.html#Libgcc + +Here is a synopsis of the contents of this library: + +typedef int si_int; +typedef unsigned su_int; + +typedef long long di_int; +typedef unsigned long long du_int; + +// Integral bit manipulation + +di_int __ashldi3(di_int a, si_int b); // a << b +ti_int __ashlti3(ti_int a, si_int b); // a << b + +di_int __ashrdi3(di_int a, si_int b); // a >> b arithmetic (sign fill) +ti_int __ashrti3(ti_int a, si_int b); // a >> b arithmetic (sign fill) +di_int __lshrdi3(di_int a, si_int b); // a >> b logical (zero fill) +ti_int __lshrti3(ti_int a, si_int b); // a >> b logical (zero fill) + +si_int __clzsi2(si_int a); // count leading zeros +si_int __clzdi2(di_int a); // count leading zeros +si_int __clzti2(ti_int a); // count leading zeros +si_int __ctzsi2(si_int a); // count trailing zeros +si_int __ctzdi2(di_int a); // count trailing zeros +si_int __ctzti2(ti_int a); // count trailing zeros + +si_int __ffsdi2(di_int a); // find least significant 1 bit +si_int __ffsti2(ti_int a); // find least significant 1 bit + +si_int __paritysi2(si_int a); // bit parity +si_int __paritydi2(di_int a); // bit parity +si_int __parityti2(ti_int a); // bit parity + +si_int __popcountsi2(si_int a); // bit population +si_int __popcountdi2(di_int a); // bit population +si_int __popcountti2(ti_int a); // bit population + +uint32_t __bswapsi2(uint32_t a); // a byteswapped, arm only +uint64_t __bswapdi2(uint64_t a); // a byteswapped, arm only + +// Integral arithmetic + +di_int __negdi2 (di_int a); // -a +ti_int __negti2 (ti_int a); // -a +di_int __muldi3 (di_int a, di_int b); // a * b +ti_int __multi3 (ti_int a, ti_int b); // a * b +si_int __divsi3 (si_int a, si_int b); // a / b signed +di_int __divdi3 (di_int a, di_int b); // a / b signed +ti_int __divti3 (ti_int a, ti_int b); // a / b signed +su_int __udivsi3 (su_int n, su_int d); // a / b unsigned +du_int __udivdi3 (du_int a, du_int b); // a / b unsigned +tu_int __udivti3 (tu_int a, tu_int b); // a / b unsigned +si_int __modsi3 (si_int a, si_int b); // a % b signed +di_int __moddi3 (di_int a, di_int b); // a % b signed +ti_int __modti3 (ti_int a, ti_int b); // a % b signed +su_int __umodsi3 (su_int a, su_int b); // a % b unsigned +du_int __umoddi3 (du_int a, du_int b); // a % b unsigned +tu_int __umodti3 (tu_int a, tu_int b); // a % b unsigned +du_int __udivmoddi4(du_int a, du_int b, du_int* rem); // a / b, *rem = a % b unsigned +tu_int __udivmodti4(tu_int a, tu_int b, tu_int* rem); // a / b, *rem = a % b unsigned +su_int __udivmodsi4(su_int a, su_int b, su_int* rem); // a / b, *rem = a % b unsigned +si_int __divmodsi4(si_int a, si_int b, si_int* rem); // a / b, *rem = a % b signed + + + +// Integral arithmetic with trapping overflow + +si_int __absvsi2(si_int a); // abs(a) +di_int __absvdi2(di_int a); // abs(a) +ti_int __absvti2(ti_int a); // abs(a) + +si_int __negvsi2(si_int a); // -a +di_int __negvdi2(di_int a); // -a +ti_int __negvti2(ti_int a); // -a + +si_int __addvsi3(si_int a, si_int b); // a + b +di_int __addvdi3(di_int a, di_int b); // a + b +ti_int __addvti3(ti_int a, ti_int b); // a + b + +si_int __subvsi3(si_int a, si_int b); // a - b +di_int __subvdi3(di_int a, di_int b); // a - b +ti_int __subvti3(ti_int a, ti_int b); // a - b + +si_int __mulvsi3(si_int a, si_int b); // a * b +di_int __mulvdi3(di_int a, di_int b); // a * b +ti_int __mulvti3(ti_int a, ti_int b); // a * b + + +// Integral arithmetic which returns if overflow + +si_int __mulosi4(si_int a, si_int b, int* overflow); // a * b, overflow set to one if result not in signed range +di_int __mulodi4(di_int a, di_int b, int* overflow); // a * b, overflow set to one if result not in signed range +ti_int __muloti4(ti_int a, ti_int b, int* overflow); // a * b, overflow set to + one if result not in signed range + + +// Integral comparison: a < b -> 0 +// a == b -> 1 +// a > b -> 2 + +si_int __cmpdi2 (di_int a, di_int b); +si_int __cmpti2 (ti_int a, ti_int b); +si_int __ucmpdi2(du_int a, du_int b); +si_int __ucmpti2(tu_int a, tu_int b); + +// Integral / floating point conversion + +di_int __fixsfdi( float a); +di_int __fixdfdi( double a); +di_int __fixxfdi(long double a); + +ti_int __fixsfti( float a); +ti_int __fixdfti( double a); +ti_int __fixxfti(long double a); +uint64_t __fixtfdi(long double input); // ppc only, doesn't match documentation + +su_int __fixunssfsi( float a); +su_int __fixunsdfsi( double a); +su_int __fixunsxfsi(long double a); + +du_int __fixunssfdi( float a); +du_int __fixunsdfdi( double a); +du_int __fixunsxfdi(long double a); + +tu_int __fixunssfti( float a); +tu_int __fixunsdfti( double a); +tu_int __fixunsxfti(long double a); +uint64_t __fixunstfdi(long double input); // ppc only + +float __floatdisf(di_int a); +double __floatdidf(di_int a); +long double __floatdixf(di_int a); +long double __floatditf(int64_t a); // ppc only + +float __floattisf(ti_int a); +double __floattidf(ti_int a); +long double __floattixf(ti_int a); + +float __floatundisf(du_int a); +double __floatundidf(du_int a); +long double __floatundixf(du_int a); +long double __floatunditf(uint64_t a); // ppc only + +float __floatuntisf(tu_int a); +double __floatuntidf(tu_int a); +long double __floatuntixf(tu_int a); + +// Floating point raised to integer power + +float __powisf2( float a, si_int b); // a ^ b +double __powidf2( double a, si_int b); // a ^ b +long double __powixf2(long double a, si_int b); // a ^ b +long double __powitf2(long double a, si_int b); // ppc only, a ^ b + +// Complex arithmetic + +// (a + ib) * (c + id) + + float _Complex __mulsc3( float a, float b, float c, float d); + double _Complex __muldc3(double a, double b, double c, double d); +long double _Complex __mulxc3(long double a, long double b, + long double c, long double d); +long double _Complex __multc3(long double a, long double b, + long double c, long double d); // ppc only + +// (a + ib) / (c + id) + + float _Complex __divsc3( float a, float b, float c, float d); + double _Complex __divdc3(double a, double b, double c, double d); +long double _Complex __divxc3(long double a, long double b, + long double c, long double d); +long double _Complex __divtc3(long double a, long double b, + long double c, long double d); // ppc only + + +// Runtime support + +// __clear_cache() is used to tell process that new instructions have been +// written to an address range. Necessary on processors that do not have +// a unified instuction and data cache. +void __clear_cache(void* start, void* end); + +// __enable_execute_stack() is used with nested functions when a trampoline +// function is written onto the stack and that page range needs to be made +// executable. +void __enable_execute_stack(void* addr); + +// __gcc_personality_v0() is normally only called by the system unwinder. +// C code (as opposed to C++) normally does not need a personality function +// because there are no catch clauses or destructors to be run. But there +// is a C language extension __attribute__((cleanup(func))) which marks local +// variables as needing the cleanup function "func" to be run when the +// variable goes out of scope. That includes when an exception is thrown, +// so a personality handler is needed. +_Unwind_Reason_Code __gcc_personality_v0(int version, _Unwind_Action actions, + uint64_t exceptionClass, struct _Unwind_Exception* exceptionObject, + _Unwind_Context_t context); + +// for use with some implementations of assert() in +void __eprintf(const char* format, const char* assertion_expression, + const char* line, const char* file); + + + +// Power PC specific functions + +// There is no C interface to the saveFP/restFP functions. They are helper +// functions called by the prolog and epilog of functions that need to save +// a number of non-volatile float point registers. +saveFP +restFP + +// PowerPC has a standard template for trampoline functions. This function +// generates a custom trampoline function with the specific realFunc +// and localsPtr values. +void __trampoline_setup(uint32_t* trampOnStack, int trampSizeAllocated, + const void* realFunc, void* localsPtr); + +// adds two 128-bit double-double precision values ( x + y ) +long double __gcc_qadd(long double x, long double y); + +// subtracts two 128-bit double-double precision values ( x - y ) +long double __gcc_qsub(long double x, long double y); + +// multiples two 128-bit double-double precision values ( x * y ) +long double __gcc_qmul(long double x, long double y); + +// divides two 128-bit double-double precision values ( x / y ) +long double __gcc_qdiv(long double a, long double b); + + +// ARM specific functions + +// There is no C interface to the switch* functions. These helper functions +// are only needed by Thumb1 code for efficient switch table generation. +switch16 +switch32 +switch8 +switchu8 + +// There is no C interface to the *_vfp_d8_d15_regs functions. There are +// called in the prolog and epilog of Thumb1 functions. When the C++ ABI use +// SJLJ for exceptions, each function with a catch clause or destuctors needs +// to save and restore all registers in it prolog and epliog. But there is +// no way to access vector and high float registers from thumb1 code, so the +// compiler must add call outs to these helper functions in the prolog and +// epilog. +restore_vfp_d8_d15_regs +save_vfp_d8_d15_regs + + +// Note: long ago ARM processors did not have floating point hardware support. +// Floating point was done in software and floating point parameters were +// passed in integer registers. When hardware support was added for floating +// point, new *vfp functions were added to do the same operations but with +// floating point parameters in floating point registers. + +// Undocumented functions + +float __addsf3vfp(float a, float b); // Appears to return a + b +double __adddf3vfp(double a, double b); // Appears to return a + b +float __divsf3vfp(float a, float b); // Appears to return a / b +double __divdf3vfp(double a, double b); // Appears to return a / b +int __eqsf2vfp(float a, float b); // Appears to return one + // iff a == b and neither is NaN. +int __eqdf2vfp(double a, double b); // Appears to return one + // iff a == b and neither is NaN. +double __extendsfdf2vfp(float a); // Appears to convert from + // float to double. +int __fixdfsivfp(double a); // Appears to convert from + // double to int. +int __fixsfsivfp(float a); // Appears to convert from + // float to int. +unsigned int __fixunssfsivfp(float a); // Appears to convert from + // float to unsigned int. +unsigned int __fixunsdfsivfp(double a); // Appears to convert from + // double to unsigned int. +double __floatsidfvfp(int a); // Appears to convert from + // int to double. +float __floatsisfvfp(int a); // Appears to convert from + // int to float. +double __floatunssidfvfp(unsigned int a); // Appears to convert from + // unisgned int to double. +float __floatunssisfvfp(unsigned int a); // Appears to convert from + // unisgned int to float. +int __gedf2vfp(double a, double b); // Appears to return __gedf2 + // (a >= b) +int __gesf2vfp(float a, float b); // Appears to return __gesf2 + // (a >= b) +int __gtdf2vfp(double a, double b); // Appears to return __gtdf2 + // (a > b) +int __gtsf2vfp(float a, float b); // Appears to return __gtsf2 + // (a > b) +int __ledf2vfp(double a, double b); // Appears to return __ledf2 + // (a <= b) +int __lesf2vfp(float a, float b); // Appears to return __lesf2 + // (a <= b) +int __ltdf2vfp(double a, double b); // Appears to return __ltdf2 + // (a < b) +int __ltsf2vfp(float a, float b); // Appears to return __ltsf2 + // (a < b) +double __muldf3vfp(double a, double b); // Appears to return a * b +float __mulsf3vfp(float a, float b); // Appears to return a * b +int __nedf2vfp(double a, double b); // Appears to return __nedf2 + // (a != b) +double __negdf2vfp(double a); // Appears to return -a +float __negsf2vfp(float a); // Appears to return -a +float __negsf2vfp(float a); // Appears to return -a +double __subdf3vfp(double a, double b); // Appears to return a - b +float __subsf3vfp(float a, float b); // Appears to return a - b +float __truncdfsf2vfp(double a); // Appears to convert from + // double to float. +int __unorddf2vfp(double a, double b); // Appears to return __unorddf2 +int __unordsf2vfp(float a, float b); // Appears to return __unordsf2 + + +Preconditions are listed for each function at the definition when there are any. +Any preconditions reflect the specification at +http://gcc.gnu.org/onlinedocs/gccint/Libgcc.html#Libgcc. + +Assumptions are listed in "int_lib.h", and in individual files. Where possible +assumptions are checked at compile time. diff --git a/src/libc/runtime/addsf3.c b/src/libc/runtime/addsf3.c new file mode 100644 index 0000000..0394b35 --- /dev/null +++ b/src/libc/runtime/addsf3.c @@ -0,0 +1,150 @@ +//===-- lib/addsf3.c - Single-precision addition ------------------*- C -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements single-precision soft-float addition with the IEEE-754 +// default rounding (to nearest, ties to even). +// +//===----------------------------------------------------------------------===// + +#define SINGLE_PRECISION +#include "fp_lib.h" + +fp_t +__addsf3(fp_t a, fp_t b) +{ + rep_t aRep = toRep(a); + rep_t bRep = toRep(b); + const rep_t aAbs = aRep & absMask; + const rep_t bAbs = bRep & absMask; + + // Detect if a or b is zero, infinity, or NaN. + if (aAbs - 1U >= infRep - 1U || bAbs - 1U >= infRep - 1U) { + + // NaN + anything = qNaN + if (aAbs > infRep) return fromRep(toRep(a) | quietBit); + // anything + NaN = qNaN + if (bAbs > infRep) return fromRep(toRep(b) | quietBit); + + if (aAbs == infRep) { + // +/-infinity + -/+infinity = qNaN + if ((toRep(a) ^ toRep(b)) == signBit) return fromRep(qnanRep); + // +/-infinity + anything remaining = +/- infinity + else return a; + } + + // anything remaining + +/-infinity = +/-infinity + if (bAbs == infRep) return b; + + // zero + anything = anything + if (!aAbs) { + // but we need to get the sign right for zero + zero + if (!bAbs) return fromRep(toRep(a) & toRep(b)); + else return b; + } + + // anything + zero = anything + if (!bAbs) return a; + } + + // Swap a and b if necessary so that a has the larger absolute value. + if (bAbs > aAbs) { + const rep_t temp = aRep; + aRep = bRep; + bRep = temp; + } + + // Extract the exponent and significand from the (possibly swapped) a and b. + int aExponent = aRep >> significandBits & maxExponent; + int bExponent = bRep >> significandBits & maxExponent; + rep_t aSignificand = aRep & significandMask; + rep_t bSignificand = bRep & significandMask; + + // Normalize any denormals, and adjust the exponent accordingly. + if (aExponent == 0) aExponent = normalize(&aSignificand); + if (bExponent == 0) bExponent = normalize(&bSignificand); + + // The sign of the result is the sign of the larger operand, a. If they + // have opposite signs, we are performing a subtraction; otherwise addition. + const rep_t resultSign = aRep & signBit; + const int subtraction = ((aRep ^ bRep) & signBit) != 0; + + // Shift the significands to give us round, guard and sticky, and or in the + // implicit significand bit. (If we fell through from the denormal path it + // was already set by normalize( ), but setting it twice won't hurt + // anything.) + aSignificand = (aSignificand | implicitBit) << 3; + bSignificand = (bSignificand | implicitBit) << 3; + + // Shift the significand of b by the difference in exponents, with a sticky + // bottom bit to get rounding correct. + const unsigned int align = aExponent - bExponent; + if (align) { + if (align < typeWidth) { + const int sticky = (bSignificand << (typeWidth - align)) != 0; + bSignificand = bSignificand >> align | sticky; + } else { + bSignificand = 1; // sticky; b is known to be non-zero. + } + } + + if (subtraction) { + aSignificand -= bSignificand; + + // If a == -b, return +zero. + if (aSignificand == 0) return fromRep(0); + + // If partial cancellation occured, we need to left-shift the result + // and adjust the exponent: + if (aSignificand < implicitBit << 3) { + const int shift = rep_clz(aSignificand) - rep_clz(implicitBit << 3); + aSignificand <<= shift; + aExponent -= shift; + } + } + + else /* addition */ { + aSignificand += bSignificand; + + // If the addition carried up, we need to right-shift the result and + // adjust the exponent: + if (aSignificand & implicitBit << 4) { + const int sticky = aSignificand & 1; + aSignificand = aSignificand >> 1 | sticky; + aExponent += 1; + } + } + + // If we have overflowed the type, return +/- infinity: + if (aExponent >= maxExponent) return fromRep(infRep | resultSign); + + if (aExponent <= 0) { + // Result is denormal before rounding; the exponent is zero and we + // need to shift the significand. + const int shift = 1 - aExponent; + const int sticky = (aSignificand << (typeWidth - shift)) != 0; + aSignificand = aSignificand >> shift | sticky; + aExponent = 0; + } + + // Low three bits are round, guard, and sticky. + const int roundGuardSticky = aSignificand & 0x7; + + // Shift the significand into place, and mask off the implicit bit. + rep_t result = aSignificand >> 3 & significandMask; + + // Insert the exponent and sign. + result |= (rep_t)aExponent << significandBits; + result |= resultSign; + + // Final rounding. The result may overflow to infinity, but that is the + // correct result in that case. + if (roundGuardSticky > 0x4) result++; + if (roundGuardSticky == 0x4) result += result & 1; + return fromRep(result); +} diff --git a/src/libc/runtime/comparesf2.c b/src/libc/runtime/comparesf2.c new file mode 100644 index 0000000..83f87f8 --- /dev/null +++ b/src/libc/runtime/comparesf2.c @@ -0,0 +1,143 @@ +//===-- lib/comparesf2.c - Single-precision comparisons -----------*- C -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the following soft-fp_t comparison routines: +// +// __eqsf2 __gesf2 __unordsf2 +// __lesf2 __gtsf2 +// __ltsf2 +// __nesf2 +// +// The semantics of the routines grouped in each column are identical, so there +// is a single implementation for each, and wrappers to provide the other names. +// +// The main routines behave as follows: +// +// __lesf2(a,b) returns -1 if a < b +// 0 if a == b +// 1 if a > b +// 1 if either a or b is NaN +// +// __gesf2(a,b) returns -1 if a < b +// 0 if a == b +// 1 if a > b +// -1 if either a or b is NaN +// +// __unordsf2(a,b) returns 0 if both a and b are numbers +// 1 if either a or b is NaN +// +// Note that __lesf2( ) and __gesf2( ) are identical except in their handling of +// NaN values. +// +//===----------------------------------------------------------------------===// + +#define SINGLE_PRECISION +#include "fp_lib.h" + +enum LE_RESULT { + LE_LESS = -1, + LE_EQUAL = 0, + LE_GREATER = 1, + LE_UNORDERED = 1 +}; + +enum LE_RESULT +__lesf2(fp_t a, fp_t b) +{ + const srep_t aInt = toRep(a); + const srep_t bInt = toRep(b); + const rep_t aAbs = aInt & absMask; + const rep_t bAbs = bInt & absMask; + + // If either a or b is NaN, they are unordered. + if (aAbs > infRep || bAbs > infRep) return LE_UNORDERED; + + // If a and b are both zeros, they are equal. + if ((aAbs | bAbs) == 0) return LE_EQUAL; + + // If at least one of a and b is positive, we get the same result comparing + // a and b as signed integers as we would with a fp_ting-point compare. + if ((aInt & bInt) >= 0) { + if (aInt < bInt) return LE_LESS; + else if (aInt == bInt) return LE_EQUAL; + else return LE_GREATER; + } + + // Otherwise, both are negative, so we need to flip the sense of the + // comparison to get the correct result. (This assumes a twos- or ones- + // complement integer representation; if integers are represented in a + // sign-magnitude representation, then this flip is incorrect). + else { + if (aInt > bInt) return LE_LESS; + else if (aInt == bInt) return LE_EQUAL; + else return LE_GREATER; + } +} + +enum GE_RESULT { + GE_LESS = -1, + GE_EQUAL = 0, + GE_GREATER = 1, + GE_UNORDERED = -1 // Note: different from LE_UNORDERED +}; + +enum GE_RESULT +__gesf2(fp_t a, fp_t b) +{ + const srep_t aInt = toRep(a); + const srep_t bInt = toRep(b); + const rep_t aAbs = aInt & absMask; + const rep_t bAbs = bInt & absMask; + + if (aAbs > infRep || bAbs > infRep) return GE_UNORDERED; + if ((aAbs | bAbs) == 0) return GE_EQUAL; + if ((aInt & bInt) >= 0) { + if (aInt < bInt) return GE_LESS; + else if (aInt == bInt) return GE_EQUAL; + else return GE_GREATER; + } else { + if (aInt > bInt) return GE_LESS; + else if (aInt == bInt) return GE_EQUAL; + else return GE_GREATER; + } +} + +int +__unordsf2(fp_t a, fp_t b) +{ + const rep_t aAbs = toRep(a) & absMask; + const rep_t bAbs = toRep(b) & absMask; + return aAbs > infRep || bAbs > infRep; +} + +// The following are alternative names for the preceeding routines. + +enum LE_RESULT +__eqsf2(fp_t a, fp_t b) +{ + return __lesf2(a, b); +} + +enum LE_RESULT +__ltsf2(fp_t a, fp_t b) +{ + return __lesf2(a, b); +} + +enum LE_RESULT +__nesf2(fp_t a, fp_t b) +{ + return __lesf2(a, b); +} + +enum GE_RESULT +__gtsf2(fp_t a, fp_t b) +{ + return __gesf2(a, b); +} diff --git a/src/libc/runtime/divsf3.c b/src/libc/runtime/divsf3.c new file mode 100644 index 0000000..57178ad --- /dev/null +++ b/src/libc/runtime/divsf3.c @@ -0,0 +1,165 @@ +//===-- lib/divsf3.c - Single-precision division ------------------*- C -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements single-precision soft-float division +// with the IEEE-754 default rounding (to nearest, ties to even). +// +// For simplicity, this implementation currently flushes denormals to zero. +// It should be a fairly straightforward exercise to implement gradual +// underflow with correct rounding. +// +//===----------------------------------------------------------------------===// + +#define SINGLE_PRECISION +#include "fp_lib.h" + +fp_t +__divsf3(fp_t a, fp_t b) +{ + const unsigned int aExponent = toRep(a) >> significandBits & maxExponent; + const unsigned int bExponent = toRep(b) >> significandBits & maxExponent; + const rep_t quotientSign = (toRep(a) ^ toRep(b)) & signBit; + + rep_t aSignificand = toRep(a) & significandMask; + rep_t bSignificand = toRep(b) & significandMask; + int scale = 0; + + // Detect if a or b is zero, denormal, infinity, or NaN. + if (aExponent-1U >= maxExponent-1U || bExponent-1U >= maxExponent-1U) { + + const rep_t aAbs = toRep(a) & absMask; + const rep_t bAbs = toRep(b) & absMask; + + // NaN / anything = qNaN + if (aAbs > infRep) return fromRep(toRep(a) | quietBit); + // anything / NaN = qNaN + if (bAbs > infRep) return fromRep(toRep(b) | quietBit); + + if (aAbs == infRep) { + // infinity / infinity = NaN + if (bAbs == infRep) return fromRep(qnanRep); + // infinity / anything else = +/- infinity + else return fromRep(aAbs | quotientSign); + } + + // anything else / infinity = +/- 0 + if (bAbs == infRep) return fromRep(quotientSign); + + if (!aAbs) { + // zero / zero = NaN + if (!bAbs) return fromRep(qnanRep); + // zero / anything else = +/- zero + else return fromRep(quotientSign); + } + // anything else / zero = +/- infinity + if (!bAbs) return fromRep(infRep | quotientSign); + + // one or both of a or b is denormal, the other (if applicable) is a + // normal number. Renormalize one or both of a and b, and set scale to + // include the necessary exponent adjustment. + if (aAbs < implicitBit) scale += normalize(&aSignificand); + if (bAbs < implicitBit) scale -= normalize(&bSignificand); + } + + // Or in the implicit significand bit. (If we fell through from the + // denormal path it was already set by normalize( ), but setting it twice + // won't hurt anything.) + aSignificand |= implicitBit; + bSignificand |= implicitBit; + int quotientExponent = aExponent - bExponent + scale; + + // Align the significand of b as a Q31 fixed-point number in the range + // [1, 2.0) and get a Q32 approximate reciprocal using a small minimax + // polynomial approximation: reciprocal = 3/4 + 1/sqrt(2) - b/2. This + // is accurate to about 3.5 binary digits. + uint32_t q31b = bSignificand << 8; + uint32_t reciprocal = UINT32_C(0x7504f333) - q31b; + + // Now refine the reciprocal estimate using a Newton-Raphson iteration: + // + // x1 = x0 * (2 - x0 * b) + // + // This doubles the number of correct binary digits in the approximation + // with each iteration, so after three iterations, we have about 28 binary + // digits of accuracy. + uint32_t correction; + correction = -((uint64_t)reciprocal * q31b >> 32); + reciprocal = (uint64_t)reciprocal * correction >> 31; + correction = -((uint64_t)reciprocal * q31b >> 32); + reciprocal = (uint64_t)reciprocal * correction >> 31; + correction = -((uint64_t)reciprocal * q31b >> 32); + reciprocal = (uint64_t)reciprocal * correction >> 31; + + // Exhaustive testing shows that the error in reciprocal after three steps + // is in the interval [-0x1.f58108p-31, 0x1.d0e48cp-29], in line with our + // expectations. We bump the reciprocal by a tiny value to force the error + // to be strictly positive (in the range [0x1.4fdfp-37,0x1.287246p-29], to + // be specific). This also causes 1/1 to give a sensible approximation + // instead of zero (due to overflow). + reciprocal -= 2; + + // The numerical reciprocal is accurate to within 2^-28, lies in the + // interval [0x1.000000eep-1, 0x1.fffffffcp-1], and is strictly smaller + // than the true reciprocal of b. Multiplying a by this reciprocal thus + // gives a numerical q = a/b in Q24 with the following properties: + // + // 1. q < a/b + // 2. q is in the interval [0x1.000000eep-1, 0x1.fffffffcp0) + // 3. the error in q is at most 2^-24 + 2^-27 -- the 2^24 term comes + // from the fact that we truncate the product, and the 2^27 term + // is the error in the reciprocal of b scaled by the maximum + // possible value of a. As a consequence of this error bound, + // either q or nextafter(q) is the correctly rounded + rep_t quotient = (uint64_t)reciprocal*(aSignificand << 1) >> 32; + + // Two cases: quotient is in [0.5, 1.0) or quotient is in [1.0, 2.0). + // In either case, we are going to compute a residual of the form + // + // r = a - q*b + // + // We know from the construction of q that r satisfies: + // + // 0 <= r < ulp(q)*b + // + // if r is greater than 1/2 ulp(q)*b, then q rounds up. Otherwise, we + // already have the correct result. The exact halfway case cannot occur. + // We also take this time to right shift quotient if it falls in the [1,2) + // range and adjust the exponent accordingly. + rep_t residual; + if (quotient < (implicitBit << 1)) { + residual = (aSignificand << 24) - quotient * bSignificand; + quotientExponent--; + } else { + quotient >>= 1; + residual = (aSignificand << 23) - quotient * bSignificand; + } + + const int writtenExponent = quotientExponent + exponentBias; + + if (writtenExponent >= maxExponent) { + // If we have overflowed the exponent, return infinity. + return fromRep(infRep | quotientSign); + } + else if (writtenExponent < 1) { + // Flush denormals to zero. In the future, it would be nice to add + // code to round them correctly. + return fromRep(quotientSign); + } + else { + int round = (residual << 1) > bSignificand; + // Clear the implicit bit + rep_t absResult = quotient & significandMask; + // Insert the exponent + absResult |= (rep_t)writtenExponent << significandBits; + // Round + absResult += round; + // Insert the sign and return + return fromRep(absResult | quotientSign); + } +} diff --git a/src/libc/runtime/fixsfsi.c b/src/libc/runtime/fixsfsi.c new file mode 100644 index 0000000..e683d55 --- /dev/null +++ b/src/libc/runtime/fixsfsi.c @@ -0,0 +1,46 @@ +//===-- lib/fixsfsi.c - Single-precision -> integer conversion ----*- C -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements single-precision to integer conversion for the +// compiler-rt library. No range checking is performed; the behavior of this +// conversion is undefined for out of range values in the C standard. +// +//===----------------------------------------------------------------------===// + +#define SINGLE_PRECISION +#include "fp_lib.h" + +int +__fixsfsi(fp_t a) +{ + // Break a into sign, exponent, significand + const rep_t aRep = toRep(a); + const rep_t aAbs = aRep & absMask; + const int sign = aRep & signBit ? -1 : 1; + const int exponent = (aAbs >> significandBits) - exponentBias; + const rep_t significand = (aAbs & significandMask) | implicitBit; + + // If 0 < exponent < significandBits, right shift to get the result. + if ((unsigned int)exponent < significandBits) { + return sign * (significand >> (significandBits - exponent)); + } + + // If exponent is negative, the result is zero. + else if (exponent < 0) { + return 0; + } + + // If significandBits < exponent, left shift to get the result. This shift + // may end up being larger than the type width, which incurs undefined + // behavior, but the conversion itself is undefined in that case, so + // whatever the compiler decides to do is fine. + else { + return sign * (significand << (exponent - significandBits)); + } +} diff --git a/src/libc/runtime/floatsisf.c b/src/libc/runtime/floatsisf.c new file mode 100644 index 0000000..5a1277a --- /dev/null +++ b/src/libc/runtime/floatsisf.c @@ -0,0 +1,57 @@ +//===-- lib/floatsisf.c - integer -> single-precision conversion --*- C -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements integer to single-precision conversion for the +// compiler-rt library in the IEEE-754 default round-to-nearest, ties-to-even +// mode. +// +//===----------------------------------------------------------------------===// + +#define SINGLE_PRECISION +#include "fp_lib.h" + +//#include "int_lib.h" + +fp_t +__floatsisf(int a) +{ + const int aWidth = sizeof a * CHAR_BIT; + + // Handle zero as a special case to protect clz + if (a == 0) + return fromRep(0); + + // All other cases begin by extracting the sign and absolute value of a + rep_t sign = 0; + if (a < 0) { + sign = signBit; + a = -a; + } + + // Exponent of (fp_t)a is the width of abs(a). + const int exponent = (aWidth - 1) - __builtin_clz(a); + rep_t result; + + // Shift a into the significand field, rounding if it is a right-shift + if (exponent <= significandBits) { + const int shift = significandBits - exponent; + result = (rep_t)a << shift ^ implicitBit; + } else { + const int shift = exponent - significandBits; + result = (rep_t)a >> shift ^ implicitBit; + rep_t round = (rep_t)a << (typeWidth - shift); + if (round > signBit) result++; + if (round == signBit) result += result & 1; + } + + // Insert the exponent + result += (rep_t)(exponent + exponentBias) << significandBits; + // Insert the sign bit and return + return fromRep(result | sign); +} diff --git a/src/libc/runtime/fp_lib.h b/src/libc/runtime/fp_lib.h new file mode 100644 index 0000000..35d7a2c --- /dev/null +++ b/src/libc/runtime/fp_lib.h @@ -0,0 +1,155 @@ +//===-- lib/fp_lib.h - Floating-point utilities -------------------*- C -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a configuration header for soft-float routines in compiler-rt. +// This file does not provide any part of the compiler-rt interface, but defines +// many useful constants and utility routines that are used in the +// implementation of the soft-float routines in compiler-rt. +// +// Assumes that float and double correspond to the IEEE-754 binary32 and +// binary64 types, respectively, and that integer endianness matches floating +// point endianness on the target platform. +// +//===----------------------------------------------------------------------===// + +#ifndef FP_LIB_HEADER +#define FP_LIB_HEADER + +#include +#include + +typedef unsigned long long uint64_t; + +#define UINT32_C(x) (x##U) + +#if defined SINGLE_PRECISION + +typedef uint32_t rep_t; +typedef int32_t srep_t; +typedef float fp_t; +#define REP_C UINT32_C +#define significandBits 23 + +static inline int rep_clz(rep_t a) +{ + return __builtin_clz(a); +} + +// 32x32 --> 64 bit multiply +static inline void wideMultiply(rep_t a, rep_t b, rep_t *hi, rep_t *lo) +{ + const uint64_t product = (uint64_t)a*b; + *hi = product >> 32; + *lo = product; +} + +#elif defined DOUBLE_PRECISION + +typedef uint64_t rep_t; +typedef int64_t srep_t; +typedef double fp_t; +#define REP_C UINT64_C +#define significandBits 52 + +static inline int rep_clz(rep_t a) +{ +#if defined __LP64__ + return __builtin_clzl(a); +#else + if (a & REP_C(0xffffffff00000000)) + return __builtin_clz(a >> 32); + else + return 32 + __builtin_clz(a & REP_C(0xffffffff)); +#endif +} + +#define loWord(a) (a & 0xffffffffU) +#define hiWord(a) (a >> 32) + +// 64x64 -> 128 wide multiply for platforms that don't have such an operation; +// many 64-bit platforms have this operation, but they tend to have hardware +// floating-point, so we don't bother with a special case for them here. +static inline void wideMultiply(rep_t a, rep_t b, rep_t *hi, rep_t *lo) +{ + // Each of the component 32x32 -> 64 products + const uint64_t plolo = loWord(a) * loWord(b); + const uint64_t plohi = loWord(a) * hiWord(b); + const uint64_t philo = hiWord(a) * loWord(b); + const uint64_t phihi = hiWord(a) * hiWord(b); + // Sum terms that contribute to lo in a way that allows us to get the carry + const uint64_t r0 = loWord(plolo); + const uint64_t r1 = hiWord(plolo) + loWord(plohi) + loWord(philo); + *lo = r0 + (r1 << 32); + // Sum terms contributing to hi with the carry from lo + *hi = hiWord(plohi) + hiWord(philo) + hiWord(r1) + phihi; +} + +#else +#error Either SINGLE_PRECISION or DOUBLE_PRECISION must be defined. +#endif + +#define typeWidth (sizeof(rep_t)*CHAR_BIT) +#define exponentBits (typeWidth - significandBits - 1) +#define maxExponent ((1 << exponentBits) - 1) +#define exponentBias (maxExponent >> 1) + +#define implicitBit (REP_C(1) << significandBits) +#define significandMask (implicitBit - 1U) +#define signBit (REP_C(1) << (significandBits + exponentBits)) +#define absMask (signBit - 1U) +#define exponentMask (absMask ^ significandMask) +#define oneRep ((rep_t)exponentBias << significandBits) +#define infRep exponentMask +#define quietBit (implicitBit >> 1) +#define qnanRep (exponentMask | quietBit) + +static inline rep_t toRep(fp_t x) +{ + const union { fp_t f; rep_t i; } rep = {.f = x}; + return rep.i; +} + +static inline fp_t fromRep(rep_t x) +{ + const union { fp_t f; rep_t i; } rep = {.i = x}; + return rep.f; +} + +static inline int normalize(rep_t *significand) +{ + const int shift = rep_clz(*significand) - rep_clz(implicitBit); + *significand <<= shift; + return 1 - shift; +} + +static inline void wideLeftShift(rep_t *hi, rep_t *lo, int count) +{ + *hi = *hi << count | *lo >> (typeWidth - count); + *lo = *lo << count; +} + +static inline void wideRightShiftWithSticky(rep_t *hi, rep_t *lo, unsigned int count) +{ + if (count < typeWidth) { + int sticky = (*lo << (typeWidth - count)) != 0; + *lo = *hi << (typeWidth - count) | *lo >> count | sticky; + *hi = *hi >> count; + } + else if (count < 2*typeWidth) { + int sticky = (*hi << (2*typeWidth - count) | *lo) != 0; + *lo = *hi >> (count - typeWidth) | sticky; + *hi = 0; + } else { + int sticky = (*hi | *lo) != 0; + *lo = sticky; + *hi = 0; + } +} + +#endif // FP_LIB_HEADER diff --git a/src/libc/runtime/mulsf3.c b/src/libc/runtime/mulsf3.c new file mode 100644 index 0000000..0b848fb --- /dev/null +++ b/src/libc/runtime/mulsf3.c @@ -0,0 +1,110 @@ +//===-- lib/mulsf3.c - Single-precision multiplication ------------*- C -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements single-precision soft-float multiplication +// with the IEEE-754 default rounding (to nearest, ties to even). +// +//===----------------------------------------------------------------------===// + +#define SINGLE_PRECISION +#include "fp_lib.h" + +fp_t +__mulsf3(fp_t a, fp_t b) +{ + const unsigned int aExponent = toRep(a) >> significandBits & maxExponent; + const unsigned int bExponent = toRep(b) >> significandBits & maxExponent; + const rep_t productSign = (toRep(a) ^ toRep(b)) & signBit; + + rep_t aSignificand = toRep(a) & significandMask; + rep_t bSignificand = toRep(b) & significandMask; + int scale = 0; + + // Detect if a or b is zero, denormal, infinity, or NaN. + if (aExponent-1U >= maxExponent-1U || bExponent-1U >= maxExponent-1U) { + + const rep_t aAbs = toRep(a) & absMask; + const rep_t bAbs = toRep(b) & absMask; + + // NaN * anything = qNaN + if (aAbs > infRep) return fromRep(toRep(a) | quietBit); + // anything * NaN = qNaN + if (bAbs > infRep) return fromRep(toRep(b) | quietBit); + + if (aAbs == infRep) { + // infinity * non-zero = +/- infinity + if (bAbs) return fromRep(aAbs | productSign); + // infinity * zero = NaN + else return fromRep(qnanRep); + } + + if (bAbs == infRep) { + // non-zero * infinity = +/- infinity + if (aAbs) return fromRep(bAbs | productSign); + // zero * infinity = NaN + else return fromRep(qnanRep); + } + + // zero * anything = +/- zero + if (!aAbs) return fromRep(productSign); + // anything * zero = +/- zero + if (!bAbs) return fromRep(productSign); + + // one or both of a or b is denormal, the other (if applicable) is a + // normal number. Renormalize one or both of a and b, and set scale to + // include the necessary exponent adjustment. + if (aAbs < implicitBit) scale += normalize(&aSignificand); + if (bAbs < implicitBit) scale += normalize(&bSignificand); + } + + // Or in the implicit significand bit. (If we fell through from the + // denormal path it was already set by normalize( ), but setting it twice + // won't hurt anything.) + aSignificand |= implicitBit; + bSignificand |= implicitBit; + + // Get the significand of a*b. Before multiplying the significands, shift + // one of them left to left-align it in the field. Thus, the product will + // have (exponentBits + 2) integral digits, all but two of which must be + // zero. Normalizing this result is just a conditional left-shift by one + // and bumping the exponent accordingly. + rep_t productHi, productLo; + wideMultiply(aSignificand, bSignificand << exponentBits, + &productHi, &productLo); + + int productExponent = aExponent + bExponent - exponentBias + scale; + + // Normalize the significand, adjust exponent if needed. + if (productHi & implicitBit) productExponent++; + else wideLeftShift(&productHi, &productLo, 1); + + // If we have overflowed the type, return +/- infinity. + if (productExponent >= maxExponent) return fromRep(infRep | productSign); + + if (productExponent <= 0) { + // Result is denormal before rounding, the exponent is zero and we + // need to shift the significand. + wideRightShiftWithSticky(&productHi, &productLo, 1U - (unsigned)productExponent); + } + + else { + // Result is normal before rounding; insert the exponent. + productHi &= significandMask; + productHi |= (rep_t)productExponent << significandBits; + } + + // Insert the sign of the result: + productHi |= productSign; + + // Final rounding. The final result may overflow to infinity, or underflow + // to zero, but those are the correct results in those cases. + if (productLo > signBit) productHi++; + if (productLo == signBit) productHi += productHi & 1; + return fromRep(productHi); +} diff --git a/src/libc/runtime/negsf2.c b/src/libc/runtime/negsf2.c new file mode 100644 index 0000000..ed7ba4c --- /dev/null +++ b/src/libc/runtime/negsf2.c @@ -0,0 +1,21 @@ +//===-- lib/negsf2.c - single-precision negation ------------------*- C -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements single-precision soft-float negation. +// +//===----------------------------------------------------------------------===// + +#define SINGLE_PRECISION +#include "fp_lib.h" + +fp_t +__negsf2(fp_t a) +{ + return fromRep(toRep(a) ^ signBit); +} diff --git a/src/libc/runtime/sc_case.S b/src/libc/runtime/sc_case.S new file mode 100644 index 0000000..3376a98 --- /dev/null +++ b/src/libc/runtime/sc_case.S @@ -0,0 +1,34 @@ + .set reorder + .text +# +# $v0 = value to switch on +# 0($sp) = pointer to list of value,ptr cases +# ended where ptr=0, value is used as pointer to jump to in default case +# looks like stack is popped as part of this +# FIXME - The assembler/linker only stores the bottom 16 bits +# of the labels in pair, so we construct the address by merging the 16 bits +# in the cell with the upper 16 bits in the return address of the code that +# called this. Is there a way to get the assembler linker to store the full +# address? If so, that should be used instead. +# + .globl __sc_case +__sc_case: + lw $t1, 16($sp) # t1=pointer to list of value/ptr pairs + addiu $sp, $sp, 4 # pop stack that held pointer +1: + lw $t2, 0($t1) # get value from pair + lw $t3, 4($t1) # get ptr from pair + beq $t3, $zero, 2f + + beq $t2, $v0, 3f + + addiu $t1, $t1, 8 # t1 += size of pair + j 1b + +2: + move $t3, $t2 +3: + lui $t2, 0xffff + and $t2, $t2, $ra + or $t3, $t3, $t2 + jr $t3 diff --git a/src/libc/runtime/subsf3.c b/src/libc/runtime/subsf3.c new file mode 100644 index 0000000..ff1dd94 --- /dev/null +++ b/src/libc/runtime/subsf3.c @@ -0,0 +1,25 @@ +//===-- lib/subsf3.c - Single-precision subtraction ---------------*- C -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements single-precision soft-float subtraction with the +// IEEE-754 default rounding (to nearest, ties to even). +// +//===----------------------------------------------------------------------===// + +#define SINGLE_PRECISION +#include "fp_lib.h" + +fp_t __addsf3(fp_t a, fp_t b); + +// Subtraction; flip the sign bit of b and add. +fp_t +__subsf3(fp_t a, fp_t b) +{ + return __addsf3(a, fromRep(toRep(b) ^ signBit)); +} diff --git a/src/libc/stdio/Makefile b/src/libc/stdio/Makefile new file mode 100644 index 0000000..4238c6d --- /dev/null +++ b/src/libc/stdio/Makefile @@ -0,0 +1,61 @@ +# +# Copyright (c) 1980 Regents of the University of California. +# All rights reserved. The Berkeley software License Agreement +# specifies the terms and conditions for redistribution. +# +TOPSRC = $(shell cd ../../..; pwd) +include $(TOPSRC)/target.mk + +CFLAGS += ${DEFS} -Os + +SRCS = ${STDSRC} fgetc.c fgets.c fputc.c fputs.c gets.c puts.c \ + feof.c ferror.c fileno.c +OBJS = ${STDOBJ} fgetc.o fgets.o fputc.o fputs.o gets.o puts.o \ + feof.o ferror.o fileno.o + +STDSRC = clrerr.c doscan.c exit.c fdopen.c filbuf.c findiop.c \ + flsbuf.c fopen.c fprintf.c fread.c freopen.c fseek.c \ + ftell.c fwrite.c getchar.c getw.c printf.c putchar.c putw.c \ + rew.c scanf.c setbuf.c setbuffer.c setvbuf.c snprintf.c sprintf.c \ + strout.c ungetc.c vfprintf.c vprintf.c vsprintf.c doprnt.c \ + remove.c +STDOBJ = clrerr.o doscan.o exit.o fdopen.o filbuf.o findiop.o \ + flsbuf.o fopen.o fprintf.o fread.o freopen.o fseek.o \ + ftell.o fwrite.o getchar.o getw.o printf.o putchar.o putw.o \ + rew.o scanf.o setbuf.o setbuffer.o setvbuf.o snprintf.o sprintf.o \ + strout.o ungetc.o vfprintf.o vprintf.o vsprintf.o doprnt.o \ + remove.o + +TAGSFILE = tags + +stdio.a: ${OBJS} + @echo "building stdio.a" + @ar cru stdio.a ${OBJS} + +tags: + cwd=`pwd`; \ + for i in ${SRCS}; do \ + ctags -a -f ${TAGSFILE} $$cwd/$$i; \ + done + +clean: + rm -f stdio.a *.o *~ profiled/*.o tags Makefile.bak + +depend: + for i in ${SRCS}; do \ + cc -M ${CFLAGS} $$i | 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 } ' >> makedep; done + echo '/^# DO NOT DELETE THIS LINE/+2,$$d' >eddep + echo '$$r makedep' >>eddep + echo 'w' >>eddep + cp Makefile Makefile.bak + ed - Makefile < eddep + rm eddep makedep + echo '# DEPENDENCIES MUST END AT END OF FILE' >> Makefile + echo '# IF YOU PUT STUFF HERE IT WILL GO AWAY' >> Makefile + echo '# see make depend above' >> Makefile + +# DO NOT DELETE THIS LINE -- make depend uses it diff --git a/src/libc/stdio/clrerr.c b/src/libc/stdio/clrerr.c new file mode 100644 index 0000000..9104c25 --- /dev/null +++ b/src/libc/stdio/clrerr.c @@ -0,0 +1,9 @@ +#include +#undef clearerr + +void +clearerr(iop) + register FILE *iop; +{ + iop->_flag &= ~(_IOERR|_IOEOF); +} diff --git a/src/libc/stdio/doprnt.c b/src/libc/stdio/doprnt.c new file mode 100644 index 0000000..eea7f09 --- /dev/null +++ b/src/libc/stdio/doprnt.c @@ -0,0 +1,780 @@ +/* + * Scaled down version of printf(3). + * Based on FreeBSD sources, heavily rewritten. + * + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +/* + * Two additional formats: + * + * The format %b is supported to decode error registers. + * Its usage is: + * + * printf("reg=%b\n", regval, "*"); + * + * where is the output base expressed as a control character, e.g. + * \10 gives octal; \20 gives hex. Each arg is a sequence of characters, + * the first of which gives the bit number to be inspected (origin 1), and + * the next characters (up to a control character, i.e. a character <= 32), + * give the name of the register. Thus: + * + * kvprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n"); + * + * would produce output: + * + * reg=3 + * + * The format %D -- Hexdump, takes a pointer. Sharp flag - use `:' as + * a separator, instead of a space. For example: + * + * ("%6D", ptr) -> XX XX XX XX XX XX + * ("%#*D", len, ptr) -> XX:XX:XX:XX ... + */ +#include +#include +#include +#include +#include +#include +#include + +/* Max number conversion buffer length: a long in base 2, plus NUL byte. */ +#define MAXNBUF (sizeof(long) * 8 + 1) + +static unsigned char *ksprintn (unsigned char *buf, unsigned long v, unsigned char base, + int width, unsigned char *lp); +static unsigned char mkhex (unsigned char ch); + +static int cvt (double number, int prec, int sharpflag, unsigned char *negp, + unsigned char fmtch, unsigned char *startp, unsigned char *endp); + +int +_doprnt (char const *fmt, va_list ap, FILE *stream) +{ +#define PUTC(c) { putc (c, stream); ++retval; } + unsigned char nbuf [MAXNBUF], padding, *q; + const unsigned char *s; + unsigned char c, base, lflag, ladjust, sharpflag, neg, dot, size; + int n, width, dwidth, retval, uppercase, extrazeros, sign; + unsigned long ul; + + if (! stream) + return 0; + if (! fmt) + fmt = "(null)\n"; + + retval = 0; + for (;;) { + while ((c = *fmt++) != '%') { + if (! c) + return retval; + PUTC (c); + } + padding = ' '; + width = 0; extrazeros = 0; + lflag = 0; ladjust = 0; sharpflag = 0; neg = 0; + sign = 0; dot = 0; uppercase = 0; dwidth = -1; +reswitch: switch (c = *fmt++) { + case '.': + dot = 1; + padding = ' '; + dwidth = 0; + goto reswitch; + + case '#': + sharpflag = 1; + goto reswitch; + + case '+': + sign = -1; + goto reswitch; + + case '-': + ladjust = 1; + goto reswitch; + + case '%': + PUTC (c); + break; + + case '*': + if (! dot) { + width = va_arg (ap, int); + if (width < 0) { + ladjust = !ladjust; + width = -width; + } + } else { + dwidth = va_arg (ap, int); + } + goto reswitch; + + case '0': + if (! dot) { + padding = '0'; + goto reswitch; + } + case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + for (n=0; ; ++fmt) { + n = n * 10 + c - '0'; + c = *fmt; + if (c < '0' || c > '9') + break; + } + if (dot) + dwidth = n; + else + width = n; + goto reswitch; + + case 'b': + ul = va_arg (ap, int); + s = va_arg (ap, const unsigned char*); + q = ksprintn (nbuf, ul, *s++, -1, 0); + while (*q) + PUTC (*q--); + + if (! ul) + break; + size = 0; + while (*s) { + n = *s++; + if ((char) (ul >> (n-1)) & 1) { + PUTC (size ? ',' : '<'); + for (; (n = *s) > ' '; ++s) + PUTC (n); + size = 1; + } else + while (*s > ' ') + ++s; + } + if (size) + PUTC ('>'); + break; + + case 'c': + if (! ladjust && width > 0) + while (width--) + PUTC (' '); + + PUTC (va_arg (ap, int)); + + if (ladjust && width > 0) + while (width--) + PUTC (' '); + break; + + case 'D': + s = va_arg (ap, const unsigned char*); + if (! width) + width = 16; + if (sharpflag) + padding = ':'; + while (width--) { + c = *s++; + PUTC (mkhex (c >> 4)); + PUTC (mkhex (c)); + if (width) + PUTC (padding); + } + break; + + case 'd': + ul = lflag ? va_arg (ap, long) : va_arg (ap, int); + if (! sign) sign = 1; + base = 10; + goto number; + + case 'l': + lflag = 1; + goto reswitch; + + case 'o': + ul = lflag ? va_arg (ap, unsigned long) : + va_arg (ap, unsigned int); + base = 8; + goto nosign; + + case 'p': + ul = (size_t) va_arg (ap, void*); + if (! ul) { + s = (const unsigned char*) "(nil)"; + goto string; + } + base = 16; + sharpflag = (width == 0); + goto nosign; + + case 'n': + ul = lflag ? va_arg (ap, unsigned long) : + sign ? (unsigned long) va_arg (ap, int) : + va_arg (ap, unsigned int); + base = 10; + goto number; + + case 's': + s = va_arg (ap, unsigned char*); + if (! s) + s = (const unsigned char*) "(null)"; +string: if (! dot) + n = strlen ((char*)s); + else + for (n=0; n 0) + while (width--) + PUTC (' '); + while (n--) + PUTC (*s++); + if (ladjust && width > 0) + while (width--) + PUTC (' '); + break; + + case 'r': + /* Saturated counters. */ + base = 10; + if (lflag) { + ul = va_arg (ap, unsigned long); + if (ul == -1) { +cnt_unknown: if (ladjust) + PUTC ('-'); + while (--width > 0) + PUTC (' '); + if (! ladjust) + PUTC ('-'); + break; + } + if (ul >= -2) { + ul = -3; + neg = '>'; + goto nosign; + } + } else { + ul = va_arg (ap, unsigned int); + if (ul == (unsigned short) -1) + goto cnt_unknown; + if (ul >= (unsigned short) -2) { + ul = (unsigned short) -3; + neg = '>'; + goto nosign; + } + } + goto nosign; + + case 'u': + ul = lflag ? va_arg (ap, unsigned long) : + va_arg (ap, unsigned int); + base = 10; + goto nosign; + + case 'x': + case 'X': + ul = lflag ? va_arg (ap, unsigned long) : + va_arg (ap, unsigned int); + base = 16; + uppercase = (c == 'X'); + goto nosign; + case 'z': + case 'Z': + ul = lflag ? va_arg (ap, unsigned long) : + sign ? (unsigned long) va_arg (ap, int) : + va_arg (ap, unsigned int); + base = 16; + uppercase = (c == 'Z'); + goto number; + +nosign: sign = 0; +number: if (sign && ((long) ul != 0L)) { + if ((long) ul < 0L) { + neg = '-'; + ul = -(long) ul; + } else if (sign < 0) + neg = '+'; + } + if (dwidth >= (int) sizeof(nbuf)) { + extrazeros = dwidth - sizeof(nbuf) + 1; + dwidth = sizeof(nbuf) - 1; + } + s = ksprintn (nbuf, ul, base, dwidth, &size); + if (sharpflag && ul != 0) { + if (base == 8) + size++; + else if (base == 16) + size += 2; + } + if (neg) + size++; + + if (! ladjust && width && padding == ' ' && + (width -= size) > 0) + do { + PUTC (' '); + } while (--width > 0); + + if (neg) + PUTC (neg); + + if (sharpflag && ul != 0) { + if (base == 8) { + PUTC ('0'); + } else if (base == 16) { + PUTC ('0'); + PUTC (uppercase ? 'X' : 'x'); + } + } + + if (extrazeros) + do { + PUTC ('0'); + } while (--extrazeros > 0); + + if (! ladjust && width && (width -= size) > 0) + do { + PUTC (padding); + } while (--width > 0); + + for (; *s; --s) { + if (uppercase && *s>='a' && *s<='z') { + PUTC (*s + 'A' - 'a'); + } else { + PUTC (*s); + } + } + + if (ladjust && width && (width -= size) > 0) + do { + PUTC (' '); + } while (--width > 0); + break; + + case 'e': + case 'E': + case 'f': + case 'F': + case 'g': + case 'G': { + double d = va_arg (ap, double); + /* + * don't do unrealistic precision; just pad it with + * zeroes later, so buffer size stays rational. + */ + if (dwidth > DBL_DIG) { + if ((c != 'g' && c != 'G') || sharpflag) + extrazeros = dwidth - DBL_DIG; + dwidth = DBL_DIG; + } else if (dwidth == -1) { + dwidth = (lflag ? DBL_DIG : FLT_DIG); + } + /* + * softsign avoids negative 0 if d is < 0 and + * no significant digits will be shown + */ + if (d < 0) { + neg = 1; + d = -d; + } + /* + * cvt may have to round up past the "start" of the + * buffer, i.e. ``intf("%.2f", (double)9.999);''; + * if the first char isn't NULL, it did. + */ + if (isnan (d) || isinf (d)) { + strcpy ((char*)nbuf, isnan (d) ? "NaN" : "Inf"); + size = 3; + extrazeros = 0; + s = nbuf; + } else { + *nbuf = 0; + size = cvt (d, dwidth, sharpflag, &neg, c, + nbuf, nbuf + sizeof(nbuf) - 1); + if (*nbuf) { + s = nbuf; + nbuf [size] = 0; + } else { + s = nbuf + 1; + nbuf [size + 1] = 0; + } + } + if (neg) + size++; + if (! ladjust && width && padding == ' ' && + (width -= size) > 0) + do { + PUTC (' '); + } while (--width > 0); + + if (neg) + PUTC ('-'); + + if (! ladjust && width && (width -= size) > 0) + do { + PUTC (padding); + } while (--width > 0); + + for (; *s; ++s) { + if (extrazeros && (*s == 'e' || *s == 'E')) + do { + PUTC ('0'); + } while (--extrazeros > 0); + + PUTC (*s); + } + if (extrazeros) + do { + PUTC ('0'); + } while (--extrazeros > 0); + + if (ladjust && width && (width -= size) > 0) + do { + PUTC (' '); + } while (--width > 0); + break; + } + default: + PUTC ('%'); + if (lflag) + PUTC ('l'); + PUTC (c); + break; + } + } +} + +/* + * Put a NUL-terminated ASCII number (base <= 16) in a buffer in reverse + * order; return an optional length and a pointer to the last character + * written in the buffer (i.e., the first character of the string). + * The buffer pointed to by `nbuf' must have length >= MAXNBUF. + */ +static unsigned char * +ksprintn (unsigned char *nbuf, unsigned long ul, unsigned char base, int width, + unsigned char *lenp) +{ + unsigned char *p; + + p = nbuf; + *p = 0; + for (;;) { + *++p = mkhex (ul % base); + ul /= base; + if (--width > 0) + continue; + if (! ul) + break; + } + if (lenp) + *lenp = p - nbuf; + return (p); +} + +static unsigned char +mkhex (unsigned char ch) +{ + ch &= 15; + if (ch > 9) + return ch + 'a' - 10; + return ch + '0'; +} + +static unsigned char * +cvtround (double fract, int *exp, unsigned char *start, unsigned char *end, unsigned char ch, + unsigned char *negp) +{ + double tmp; + + if (fract) { + modf (fract * 10, &tmp); + } else { + tmp = ch - '0'; + } + if (tmp > 4) { + for (;; --end) { + if (*end == '.') { + --end; + } + if (++*end <= '9') { + break; + } + *end = '0'; + if (end == start) { + if (exp) { /* e/E; increment exponent */ + *end = '1'; + ++*exp; + } else { /* f; add extra digit */ + *--end = '1'; + --start; + } + break; + } + } + } else if (*negp) { + /* + * ``"%.3f", (double)-0.0004'' gives you a negative 0. + */ + for (;; --end) { + if (*end == '.') { + --end; + } + if (*end != '0') { + break; + } + if (end == start) { + *negp = 0; + } + } + } + return start; +} + +static unsigned char * +exponent (unsigned char *p, int exp, unsigned char fmtch) +{ + unsigned char expbuf [8], *t; + + *p++ = fmtch; + if (exp < 0) { + exp = -exp; + *p++ = '-'; + } else { + *p++ = '+'; + } + t = expbuf + sizeof(expbuf); + if (exp > 9) { + do { + *--t = exp % 10 + '0'; + } while ((exp /= 10) > 9); + *--t = exp + '0'; + for (; t < expbuf + sizeof(expbuf); *p++ = *t++) + continue; + } else { + *p++ = '0'; + *p++ = exp + '0'; + } + return p; +} + +static int +cvt (double number, int prec, int sharpflag, unsigned char *negp, unsigned char fmtch, + unsigned char *startp, unsigned char *endp) +{ + unsigned char *p, *t; + double fract; + int dotrim, expcnt, gformat; + double integer, tmp; + + expcnt = 0; + dotrim = expcnt = gformat = 0; + fract = modf (number, &integer); + + /* + * get an extra slot for rounding + */ + t = ++startp; + + /* + * get integer portion of number; put into the end of the buffer; the + * .01 is added for modf (356.0 / 10, &integer) returning .59999999... + */ + for (p = endp - 1; integer; ++expcnt) { + tmp = modf (integer / 10, &integer); + *p-- = (int) ((tmp + .01) * 10) + '0'; + } + switch (fmtch) { + case 'f': + /* reverse integer into beginning of buffer */ + if (expcnt) { + for (; ++p < endp; *t++ = *p); + } else { + *t++ = '0'; + } + + /* + * if precision required or alternate flag set, add in a + * decimal point. + */ + if (prec || sharpflag) { + *t++ = '.'; + } + + /* + * if requires more precision and some fraction left + */ + if (fract) { + if (prec) { + do { + fract = modf (fract * 10, &tmp); + *t++ = (int)tmp + '0'; + } while (--prec && fract); + } + if (fract) { + startp = cvtround (fract, 0, startp, + t - 1, '0', negp); + } + } + for (; prec--; *t++ = '0'); + break; + case 'e': + case 'E': +eformat: if (expcnt) { + *t++ = *++p; + if (prec || sharpflag) { + *t++ = '.'; + } + + /* + * if requires more precision and some integer left + */ + for (; prec && ++p < endp; --prec) { + *t++ = *p; + } + + /* + * if done precision and more of the integer component, + * round using it; adjust fract so we don't re-round + * later. + */ + if (! prec && ++p < endp) { + fract = 0; + startp = cvtround (0, &expcnt, startp, + t - 1, *p, negp); + } + /* + * adjust expcnt for digit in front of decimal + */ + --expcnt; + } + /* + * until first fractional digit, decrement exponent + */ + else if (fract) { + /* + * adjust expcnt for digit in front of decimal + */ + for (expcnt = -1;; --expcnt) { + fract = modf (fract * 10, &tmp); + if (tmp) { + break; + } + } + *t++ = (int)tmp + '0'; + if (prec || sharpflag) { + *t++ = '.'; + } + } else { + *t++ = '0'; + if (prec || sharpflag) { + *t++ = '.'; + } + } + /* + * if requires more precision and some fraction left + */ + if (fract) { + if (prec) { + do { + fract = modf (fract * 10, &tmp); + *t++ = (int)tmp + '0'; + } while (--prec && fract); + } + if (fract) { + startp = cvtround (fract, &expcnt, startp, + t - 1, '0', negp); + } + } + /* + * if requires more precision + */ + for (; prec--; *t++ = '0'); + + /* + * unless alternate flag, trim any g/G format trailing 0's + */ + if (gformat && ! sharpflag) { + while (t > startp && *--t == '0'); + if (*t == '.') { + --t; + } + ++t; + } + t = exponent (t, expcnt, fmtch); + break; + case 'g': + case 'G': + /* + * a precision of 0 is treated as a precision of 1 + */ + if (!prec) { + ++prec; + } + + /* + * ``The style used depends on the value converted; style e + * will be used only if the exponent resulting from the + * conversion is less than -4 or greater than the precision.'' + * -- ANSI X3J11 + */ + if (expcnt > prec || (! expcnt && fract && fract < .0001)) { + /* + * g/G format counts "significant digits, not digits of + * precision; for the e/E format, this just causes an + * off-by-one problem, i.e. g/G considers the digit + * before the decimal point significant and e/E doesn't + * count it as precision. + */ + --prec; + fmtch -= 2; /* G->E, g->e */ + gformat = 1; + goto eformat; + } + /* + * reverse integer into beginning of buffer, + * note, decrement precision + */ + if (expcnt) { + for (; ++p < endp; *t++ = *p, --prec); + } else { + *t++ = '0'; + } + /* + * if precision required or alternate flag set, add in a + * decimal point. If no digits yet, add in leading 0. + */ + if (prec || sharpflag) { + dotrim = 1; + *t++ = '.'; + } else { + dotrim = 0; + } + /* + * if requires more precision and some fraction left + */ + while (prec && fract) { + fract = modf (fract * 10, &tmp); + *t++ = (int)tmp + '0'; + prec--; + } + if (fract) { + startp = cvtround (fract, 0, startp, t - 1, '0', negp); + } + /* + * alternate format, adds 0's for precision, else trim 0's + */ + if (sharpflag) { + for (; prec--; *t++ = '0'); + } else if (dotrim) { + while (t > startp && *--t == '0'); + if (*t != '.') { + ++t; + } + } + } + return t - startp; +} diff --git a/src/libc/stdio/doscan.c b/src/libc/stdio/doscan.c new file mode 100644 index 0000000..c596612 --- /dev/null +++ b/src/libc/stdio/doscan.c @@ -0,0 +1,290 @@ +#include +#include +#include + +#define SPC 01 +#define STP 02 + +#define SHORT 0 +#define REGULAR 1 +#define LONG 2 +#define INT 0 +#define FLOAT 1 + +static char *_getccl(); + +static char _sctab[256] = { + 0,0,0,0,0,0,0,0, + 0,SPC,SPC,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + SPC,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, +}; + +static int +_instr (ptr, type, len, iop, eofptr) + register char *ptr; + register FILE *iop; + int *eofptr; +{ + register int ch; + register char *optr; + int ignstp; + + *eofptr = 0; + optr = ptr; + if (type=='c' && len==30000) + len = 1; + ignstp = 0; + if (type=='s') + ignstp = SPC; + while ((ch = getc(iop)) != EOF && _sctab[ch] & ignstp) + ; + ignstp = SPC; + if (type=='c') + ignstp = 0; + else if (type=='[') + ignstp = STP; + while (ch!=EOF && (_sctab[ch]&ignstp)==0) { + if (ptr) + *ptr++ = ch; + if (--len <= 0) + break; + ch = getc(iop); + } + if (ch != EOF) { + if (len > 0) + ungetc(ch, iop); + *eofptr = 0; + } else + *eofptr = 1; + if (ptr && ptr!=optr) { + if (type!='c') + *ptr++ = '\0'; + return(1); + } + return(0); +} + +static int +_innum (ptr, type, len, size, iop, eofptr) + int *ptr, *eofptr; + FILE *iop; +{ + register char *np; + char numbuf[64]; + register int c, base; + int expseen, scale, negflg, c1, ndigit; + long lcval; + + if (type=='c' || type=='s' || type=='[') + return(_instr((char*)ptr, type, len, iop, eofptr)); + lcval = 0; + ndigit = 0; + scale = INT; + if (type=='e'||type=='f') + scale = FLOAT; + base = 10; + if (type=='o') + base = 8; + else if (type=='x') + base = 16; + np = numbuf; + expseen = 0; + negflg = 0; + while ((c = getc(iop))==' ' || c=='\t' || c=='\n'); + if (c=='-') { + negflg++; + *np++ = c; + c = getc(iop); + len--; + } else if (c=='+') { + len--; + c = getc(iop); + } + for ( ; --len>=0; *np++ = c, c = getc(iop)) { + if (isdigit(c) || + (base==16 && (('a'<=c && c<='f') || ('A'<=c && c<='F')))) { + ndigit++; + if (base==8) + lcval <<=3; + else if (base==10) + lcval = ((lcval<<2) + lcval)<<1; + else + lcval <<= 4; + c1 = c; + if (isdigit(c)) + c -= '0'; + else if ('a'<=c && c<='f') + c -= 'a'-10; + else + c -= 'A'-10; + lcval += c; + c = c1; + continue; + } else if (c=='.') { + if (base!=10 || scale==INT) + break; + ndigit++; + continue; + } else if ((c=='e'||c=='E') && expseen==0) { + if (base!=10 || scale==INT || ndigit==0) + break; + expseen++; + *np++ = c; + c = getc(iop); + if (c!='+'&&c!='-'&&('0'>c||c>'9')) + break; + } else + break; + } + if (negflg) + lcval = -lcval; + if (c != EOF) { + ungetc(c, iop); + *eofptr = 0; + } else + *eofptr = 1; + if (ptr==NULL || np==numbuf || (negflg && np==numbuf+1) )/* gene dykes*/ + return(0); + *np++ = 0; + switch((scale<<4) | size) { +#if HAVE_FLOAT + case (FLOAT<<4) | SHORT: + case (FLOAT<<4) | REGULAR: + *(float*)ptr = atof(numbuf); + break; + + case (FLOAT<<4) | LONG: + *(double*)ptr = atof(numbuf); + break; +#endif + case (INT<<4) | SHORT: + *(short*)ptr = lcval; + break; + + case (INT<<4) | REGULAR: + *(int*)ptr = lcval; + break; + + case (INT<<4) | LONG: + *(long*)ptr = lcval; + break; + } + return(1); +} + +int +_doscan (iop, fmt, argp) + FILE *iop; + register const char *fmt; + va_list argp; +{ + register int ch; + int nmatch, len, ch1; + int *ptr, fileended, size; + + nmatch = 0; + fileended = 0; + for (;;) switch (ch = *fmt++) { + case '\0': + return (nmatch); + case '%': + if ((ch = *fmt++) == '%') + goto def; + if (ch == '*') { + ptr = 0; + ch = *fmt++; + } else + ptr = va_arg (argp, int*); + len = 0; + size = REGULAR; + while (isdigit(ch)) { + len = len*10 + ch - '0'; + ch = *fmt++; + } + if (len == 0) + len = 30000; + if (ch=='l') { + size = LONG; + ch = *fmt++; + } else if (ch=='h') { + size = SHORT; + ch = *fmt++; + } else if (ch=='[') + fmt = _getccl(fmt); + if (isupper(ch)) { + ch = tolower(ch); + size = LONG; + } + if (ch == '\0') + return(-1); + if (_innum(ptr, ch, len, size, iop, &fileended) && ptr) + nmatch++; + if (fileended) + return(nmatch? nmatch: -1); + break; + + case ' ': + case '\n': + case '\t': + while ((ch1 = getc(iop))==' ' || ch1=='\t' || ch1=='\n') + ; + if (ch1 != EOF) + ungetc(ch1, iop); + break; + + default: + def: + ch1 = getc(iop); + if (ch1 != ch) { + if (ch1==EOF) + return(-1); + ungetc(ch1, iop); + return(nmatch); + } + } +} + +static char * +_getccl(s) +register unsigned char *s; +{ + register int c, t; + + t = 0; + if (*s == '^') { + t++; + s++; + } + for (c = 0; c < (sizeof _sctab / sizeof _sctab[0]); c++) + if (t) + _sctab[c] &= ~STP; + else + _sctab[c] |= STP; + if ((c = *s) == ']' || c == '-') { /* first char is special */ + if (t) + _sctab[c] |= STP; + else + _sctab[c] &= ~STP; + s++; + } + while ((c = *s++) != ']') { + if (c==0) + return((char *)--s); + else if (c == '-' && *s != ']' && s[-2] < *s) { + for (c = s[-2] + 1; c < *s; c++) + if (t) + _sctab[c] |= STP; + else + _sctab[c] &= ~STP; + } else if (t) + _sctab[c] |= STP; + else + _sctab[c] &= ~STP; + } + return((char *)s); +} diff --git a/src/libc/stdio/exit.c b/src/libc/stdio/exit.c new file mode 100644 index 0000000..4f7624b --- /dev/null +++ b/src/libc/stdio/exit.c @@ -0,0 +1,21 @@ +#include +#include + +int errno; + +/* + * This stub is linked in, when application uses no stdio calls. + */ +__attribute__((weak)) +void _cleanup() +{ + /* Nothing to do. */ +} + +void +exit (code) + int code; +{ + _cleanup(); + _exit (code); +} diff --git a/src/libc/stdio/fdopen.c b/src/libc/stdio/fdopen.c new file mode 100644 index 0000000..23770f7 --- /dev/null +++ b/src/libc/stdio/fdopen.c @@ -0,0 +1,57 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +/* + * Unix routine to do an "fopen" on file descriptor + * The mode has to be repeated because you can't query its + * status + */ +#include +#include +#include +#include + +FILE * +fdopen(fd, mode) + register const char *mode; +{ + static int nofile = -1; + register FILE *iop; + + if (nofile < 0) + nofile = getdtablesize(); + + if (fd < 0 || fd >= nofile) + return (NULL); + + iop = _findiop(); + if (iop == NULL) + return (NULL); + + iop->_cnt = 0; + iop->_file = fd; + iop->_bufsiz = 0; + iop->_base = iop->_ptr = NULL; + + switch (*mode) { + case 'r': + iop->_flag = _IOREAD; + break; + case 'a': + lseek(fd, (off_t)0, L_XTND); + /* fall into ... */ + case 'w': + iop->_flag = _IOWRT; + break; + default: + return (NULL); + } + + if (mode[1] == '+') + iop->_flag = _IORW; + + return (iop); +} diff --git a/src/libc/stdio/feof.c b/src/libc/stdio/feof.c new file mode 100644 index 0000000..5376dba --- /dev/null +++ b/src/libc/stdio/feof.c @@ -0,0 +1,14 @@ +/* + * A subroutine version of the macro feof + */ +#define USE_STDIO_MACROS +#include + +#undef feof + +int +feof(fp) + register FILE *fp; +{ + return feof(fp); +} diff --git a/src/libc/stdio/ferror.c b/src/libc/stdio/ferror.c new file mode 100644 index 0000000..16d7925 --- /dev/null +++ b/src/libc/stdio/ferror.c @@ -0,0 +1,14 @@ +/* + * A subroutine version of the macro ferror + */ +#define USE_STDIO_MACROS +#include + +#undef ferror + +int +ferror(fp) + register FILE *fp; +{ + return ferror(fp); +} diff --git a/src/libc/stdio/fgetc.c b/src/libc/stdio/fgetc.c new file mode 100644 index 0000000..5cb095c --- /dev/null +++ b/src/libc/stdio/fgetc.c @@ -0,0 +1,8 @@ +#include + +int +fgetc(fp) + register FILE *fp; +{ + return getc(fp); +} diff --git a/src/libc/stdio/fgets.c b/src/libc/stdio/fgets.c new file mode 100644 index 0000000..b0fd176 --- /dev/null +++ b/src/libc/stdio/fgets.c @@ -0,0 +1,22 @@ +#include + +char * +fgets(s, n, iop) + char *s; + int n; + register FILE *iop; +{ + register int c = EOF; + register char *cs; + + cs = s; + while (--n>0 && (c = getc(iop)) != EOF) { + *cs++ = c; + if (c=='\n') + break; + } + if (c == EOF && cs==s) + return(NULL); + *cs++ = '\0'; + return(s); +} diff --git a/src/libc/stdio/filbuf.c b/src/libc/stdio/filbuf.c new file mode 100644 index 0000000..0a54f7f --- /dev/null +++ b/src/libc/stdio/filbuf.c @@ -0,0 +1,67 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include +#include +#include +#include +#include + +int +_filbuf(iop) +register FILE *iop; +{ + int size; + struct stat stbuf; + extern char *_smallbuf; + char c; + + if (iop->_flag & _IORW) + iop->_flag |= _IOREAD; + + if ((iop->_flag&_IOREAD) == 0) + return(EOF); + if (iop->_flag&(_IOSTRG|_IOEOF)) + return(EOF); +tryagain: + if (iop->_base==NULL) { + if (iop->_flag&_IONBF) { + iop->_base = _smallbuf ? &_smallbuf[fileno(iop)] : &c; + goto tryagain; + } + if (fstat(fileno(iop), &stbuf) < 0 || stbuf.st_blksize <= NULL) + size = BUFSIZ; + else + size = stbuf.st_blksize; + if ((iop->_base = malloc(size)) == NULL) { + iop->_flag |= _IONBF; + goto tryagain; + } + iop->_flag |= _IOMYBUF; + iop->_bufsiz = size; + } + if (iop == stdin) { + if (stdout->_flag&_IOLBF) + fflush(stdout); + if (stderr->_flag&_IOLBF) + fflush(stderr); + } + iop->_cnt = read(fileno(iop), iop->_base, + iop->_flag & _IONBF ? 1 : iop->_bufsiz); + iop->_ptr = iop->_base; + if (iop->_flag & _IONBF && iop->_base == &c) + iop->_base = NULL; + if (--iop->_cnt < 0) { + if (iop->_cnt == -1) { + iop->_flag |= _IOEOF; + if (iop->_flag & _IORW) + iop->_flag &= ~_IOREAD; + } else + iop->_flag |= _IOERR; + iop->_cnt = 0; + return(EOF); + } + return(*iop->_ptr++&0377); +} diff --git a/src/libc/stdio/fileno.c b/src/libc/stdio/fileno.c new file mode 100644 index 0000000..c7e1abb --- /dev/null +++ b/src/libc/stdio/fileno.c @@ -0,0 +1,14 @@ +/* + * A subroutine version of the macro fileno + */ +#define USE_STDIO_MACROS +#include + +#undef fileno + +int +fileno(fp) + register FILE *fp; +{ + return fileno(fp); +} diff --git a/src/libc/stdio/findiop.c b/src/libc/stdio/findiop.c new file mode 100644 index 0000000..95ef0c0 --- /dev/null +++ b/src/libc/stdio/findiop.c @@ -0,0 +1,124 @@ +/* + * Copyright (c) 1983, 1985 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include +#include +#include +#include + +extern int errno; + +#define active(iop) ((iop)->_flag & (_IOREAD|_IOWRT|_IORW)) + +#define NSTATIC 20 /* stdin + stdout + stderr + the usual */ + +FILE _iob[NSTATIC] = { + { 0, NULL, NULL, 0, _IOREAD, 0 }, /* stdin */ + { 0, NULL, NULL, 0, _IOWRT, 1 }, /* stdout */ + { 0, NULL, NULL, 0, _IOWRT|_IONBF, 2 }, /* stderr */ +}; + +static char sbuf[NSTATIC]; +char *_smallbuf = sbuf; +static FILE **iobglue; +static FILE **endglue; + +static int +_f_morefiles() +{ + register FILE **iov; + register FILE *fp; + int nfiles; + + nfiles = getdtablesize(); + + iobglue = (FILE **)calloc(nfiles, sizeof *iobglue); + if (iobglue == NULL) + return (0); + + endglue = iobglue + nfiles; + + for (fp = _iob, iov = iobglue; fp < &_iob[NSTATIC]; /* void */) + *iov++ = fp++; + + _smallbuf = calloc(nfiles, sizeof(*_smallbuf)); + return (1); +} + +/* + * Find a free FILE for fopen et al. + * We have a fixed static array of entries, and in addition + * may allocate additional entries dynamically, up to the kernel + * limit on the number of open files. + * At first just check for a free slot in the fixed static array. + * If none are available, then we allocate a structure to glue together + * the old and new FILE entries, which are then no longer contiguous. + */ +FILE * +_findiop() +{ + register FILE **iov, *iop; + + if (iobglue == 0) { + for (iop = _iob; iop < _iob + NSTATIC; iop++) + if (!active(iop)) + return (iop); + + if (_f_morefiles() == 0) { + errno = ENOMEM; + return (NULL); + } + } + + iov = iobglue; + while (*iov != NULL && active(*iov)) + if (++iov >= endglue) { + errno = EMFILE; + return (NULL); + } + + if (*iov == NULL) + *iov = (FILE *)calloc(1, sizeof **iov); + + return (*iov); +} + +void +f_prealloc() +{ + register FILE **iov; + + if (iobglue == NULL && _f_morefiles() == 0) + return; + + for (iov = iobglue; iov < endglue; iov++) + if (*iov == NULL) + *iov = (FILE *)calloc(1, sizeof **iov); +} + +void +_fwalk(function) + register int (*function)(); +{ + register FILE **iov; + register FILE *fp; + + if (iobglue == NULL) { + for (fp = _iob; fp < &_iob[NSTATIC]; fp++) + if (active(fp)) + (*function)(fp); + } else { + for (iov = iobglue; iov < endglue; iov++) + if (*iov && active(*iov)) + (*function)(*iov); + } +} + +void _cleanup() +{ + extern int fclose(); + + _fwalk(fclose); +} diff --git a/src/libc/stdio/flsbuf.c b/src/libc/stdio/flsbuf.c new file mode 100644 index 0000000..5f462fd --- /dev/null +++ b/src/libc/stdio/flsbuf.c @@ -0,0 +1,118 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include +#include +#include +#include +#include + +int _flsbuf(c, iop) + unsigned char c; + register FILE *iop; +{ + register char *base; + register int n, rn; + char c1; + int size; + struct stat stbuf; + + if (iop->_flag & _IORW) { + iop->_flag |= _IOWRT; + iop->_flag &= ~(_IOEOF|_IOREAD); + } + + if ((iop->_flag&_IOWRT)==0) + return(EOF); +tryagain: + if (iop->_flag&_IOLBF) { + base = iop->_base; + *iop->_ptr++ = c; + if (iop->_ptr >= base+iop->_bufsiz || c == '\n') { + n = write(fileno(iop), base, rn = iop->_ptr - base); + iop->_ptr = base; + iop->_cnt = 0; + } else + rn = n = 0; + } else if (iop->_flag&_IONBF) { + c1 = c; + rn = 1; + n = write(fileno(iop), &c1, rn); + iop->_cnt = 0; + } else { + if ((base=iop->_base)==NULL) { + if (fstat(fileno(iop), &stbuf) < 0 || + stbuf.st_blksize <= NULL) + size = BUFSIZ; + else + size = stbuf.st_blksize; + if ((iop->_base=base=malloc(size)) == NULL) { + iop->_flag |= _IONBF; + goto tryagain; + } + iop->_flag |= _IOMYBUF; + iop->_bufsiz = size; + if (iop==stdout && isatty(fileno(stdout))) { + iop->_flag |= _IOLBF; + iop->_ptr = base; + goto tryagain; + } + rn = n = 0; + } else if ((rn = n = iop->_ptr - base) > 0) { + iop->_ptr = base; + n = write(fileno(iop), base, n); + } + iop->_cnt = iop->_bufsiz-1; + *base++ = c; + iop->_ptr = base; + } + if (rn != n) { + iop->_flag |= _IOERR; + return(EOF); + } + return(c); +} + +int +fflush(iop) +register FILE *iop; +{ + register char *base; + register int n; + + if ((iop->_flag&(_IONBF|_IOWRT))==_IOWRT + && (base=iop->_base)!=NULL && (n=iop->_ptr-base)>0) { + iop->_ptr = base; + iop->_cnt = (iop->_flag&(_IOLBF|_IONBF)) ? 0 : iop->_bufsiz; + if (write(fileno(iop), base, n)!=n) { + iop->_flag |= _IOERR; + return(EOF); + } + } + return(0); +} + +int +fclose(iop) + register FILE *iop; +{ + register int r; + + r = EOF; + if (iop->_flag&(_IOREAD|_IOWRT|_IORW) && (iop->_flag&_IOSTRG)==0) { + r = fflush(iop); + if (close(fileno(iop)) < 0) + r = EOF; + if (iop->_flag&_IOMYBUF) + free(iop->_base); + } + iop->_cnt = 0; + iop->_base = (char *)NULL; + iop->_ptr = (char *)NULL; + iop->_bufsiz = 0; + iop->_flag = 0; + iop->_file = 0; + return(r); +} diff --git a/src/libc/stdio/fopen.c b/src/libc/stdio/fopen.c new file mode 100644 index 0000000..db10607 --- /dev/null +++ b/src/libc/stdio/fopen.c @@ -0,0 +1,59 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include +#include +#include +#include +#include + +FILE * +fopen(file, mode) + const char *file; + register const char *mode; +{ + register FILE *iop; + register int f, rw, oflags; + extern FILE *_findiop(); + + iop = _findiop(); + if (iop == NULL) + return (NULL); + + rw = (mode[1] == '+'); + + switch (*mode) { + case 'a': + oflags = O_CREAT | (rw ? O_RDWR : O_WRONLY); + break; + case 'r': + oflags = rw ? O_RDWR : O_RDONLY; + break; + case 'w': + oflags = O_TRUNC | O_CREAT | (rw ? O_RDWR : O_WRONLY); + break; + default: + return (NULL); + } + + f = open(file, oflags, 0666); + if (f < 0) + return (NULL); + + if (*mode == 'a') + lseek(f, (off_t)0, L_XTND); + + iop->_cnt = 0; + iop->_file = f; + iop->_bufsiz = 0; + if (rw) + iop->_flag = _IORW; + else if (*mode == 'r') + iop->_flag = _IOREAD; + else + iop->_flag = _IOWRT; + iop->_base = iop->_ptr = NULL; + return (iop); +} diff --git a/src/libc/stdio/fprintf.c b/src/libc/stdio/fprintf.c new file mode 100644 index 0000000..5bfa3dc --- /dev/null +++ b/src/libc/stdio/fprintf.c @@ -0,0 +1,30 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include +#include +#include + +int +fprintf (register FILE *iop, const char *fmt, ...) +{ + va_list ap; + + va_start (ap, fmt); + if (iop->_flag & _IONBF) { + iop->_flag &= ~_IONBF; + iop->_ptr = iop->_base = alloca(BUFSIZ); + iop->_bufsiz = BUFSIZ; + _doprnt(fmt, ap, iop); + fflush(iop); + iop->_flag |= _IONBF; + iop->_base = NULL; + iop->_bufsiz = NULL; + iop->_cnt = 0; + } else + _doprnt(fmt, ap, iop); + va_end (ap); + return(ferror(iop)? EOF: 0); +} diff --git a/src/libc/stdio/fputc.c b/src/libc/stdio/fputc.c new file mode 100644 index 0000000..1b06908 --- /dev/null +++ b/src/libc/stdio/fputc.c @@ -0,0 +1,9 @@ +#include + +int +fputc (c, fp) + register int c; + register FILE *fp; +{ + return putc (c, fp); +} diff --git a/src/libc/stdio/fputs.c b/src/libc/stdio/fputs.c new file mode 100644 index 0000000..6ac2450 --- /dev/null +++ b/src/libc/stdio/fputs.c @@ -0,0 +1,36 @@ +/* + * Copyright (c) 1984 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include +#include + +int +fputs(s, iop) + register const char *s; + register FILE *iop; +{ + register int r = 0, c; + int unbuffered; + + unbuffered = iop->_flag & _IONBF; + if (unbuffered) { + iop->_flag &= ~_IONBF; + iop->_ptr = iop->_base = alloca(BUFSIZ); + iop->_bufsiz = BUFSIZ; + } + + while ((c = *s++)) + r = putc(c, iop); + + if (unbuffered) { + fflush(iop); + iop->_flag |= _IONBF; + iop->_base = NULL; + iop->_bufsiz = NULL; + iop->_cnt = 0; + } + + return(r); +} diff --git a/src/libc/stdio/fread.c b/src/libc/stdio/fread.c new file mode 100644 index 0000000..f5e5445 --- /dev/null +++ b/src/libc/stdio/fread.c @@ -0,0 +1,44 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include +#include + +size_t +fread (vptr, size, count, iop) + register void *vptr; + size_t size, count; + register FILE *iop; +{ + register char *ptr = vptr; + register unsigned s; + int c; + + s = size * count; + while (s > 0) { + if (iop->_cnt < s) { + if (iop->_cnt > 0) { + bcopy(iop->_ptr, ptr, iop->_cnt); + ptr += iop->_cnt; + s -= iop->_cnt; + } + /* + * filbuf clobbers _cnt & _ptr, + * so don't waste time setting them. + */ + if ((c = _filbuf(iop)) == EOF) + break; + *ptr++ = c; + s--; + } + if (iop->_cnt >= s) { + bcopy(iop->_ptr, ptr, s); + iop->_ptr += s; + iop->_cnt -= s; + return (count); + } + } + return (size != 0 ? count - ((s + size - 1) / size) : 0); +} diff --git a/src/libc/stdio/freopen.c b/src/libc/stdio/freopen.c new file mode 100644 index 0000000..5074e50 --- /dev/null +++ b/src/libc/stdio/freopen.c @@ -0,0 +1,56 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include +#include +#include +#include +#include + +FILE * +freopen(file, mode, iop) + const char *file; + register const char *mode; + register FILE *iop; +{ + register int f, rw, oflags; + + rw = (mode[1] == '+'); + + fclose(iop); + + switch (*mode) { + case 'a': + oflags = O_CREAT | (rw ? O_RDWR : O_WRONLY); + break; + case 'r': + oflags = rw ? O_RDWR : O_RDONLY; + break; + case 'w': + oflags = O_TRUNC | O_CREAT | (rw ? O_RDWR : O_WRONLY); + break; + default: + return (NULL); + } + + f = open(file, oflags, 0666); + if (f < 0) + return (NULL); + + if (*mode == 'a') + lseek(f, (off_t)0, L_XTND); + + iop->_cnt = 0; + iop->_file = f; + iop->_bufsiz = 0; + if (rw) + iop->_flag = _IORW; + else if (*mode == 'r') + iop->_flag = _IOREAD; + else + iop->_flag = _IOWRT; + iop->_base = iop->_ptr = NULL; + return (iop); +} diff --git a/src/libc/stdio/fseek.c b/src/libc/stdio/fseek.c new file mode 100644 index 0000000..3fe3c58 --- /dev/null +++ b/src/libc/stdio/fseek.c @@ -0,0 +1,59 @@ +/* + * Seek for standard library. Coordinates with buffering. + */ +#include +#include + +int +fseek(iop, offset, ptrname) + register FILE *iop; + long offset; +{ + register int resync, c; + long p = -1; /* can't happen? */ + + iop->_flag &= ~_IOEOF; + if (iop->_flag&_IOREAD) { + if (ptrname<2 && iop->_base && + !(iop->_flag&_IONBF)) { + c = iop->_cnt; + p = offset; + if (ptrname==0) { + long curpos = lseek(fileno(iop), 0L, 1); + if (curpos == -1) + return (-1); + p += c - curpos; + } else + offset -= c; + if(!(iop->_flag&_IORW) && c>0&&p<=c + && p>=iop->_base-iop->_ptr){ + iop->_ptr += (int)p; + iop->_cnt -= (int)p; + return(0); + } + resync = offset&01; + } else + resync = 0; + if (iop->_flag & _IORW) { + iop->_ptr = iop->_base; + iop->_flag &= ~_IOREAD; + resync = 0; + } + p = lseek(fileno(iop), offset-resync, ptrname); + iop->_cnt = 0; + if (resync && p != -1) + if (getc(iop) == EOF) + p = -1; + } + else if (iop->_flag & (_IOWRT|_IORW)) { + p = fflush(iop); + if (iop->_flag & _IORW) { + iop->_cnt = 0; + iop->_flag &= ~_IOWRT; + iop->_ptr = iop->_base; + } + return(lseek(fileno(iop), offset, ptrname) == -1 || p == EOF ? + -1 : 0); + } + return(p==-1?-1:0); +} diff --git a/src/libc/stdio/ftell.c b/src/libc/stdio/ftell.c new file mode 100644 index 0000000..5002ee2 --- /dev/null +++ b/src/libc/stdio/ftell.c @@ -0,0 +1,29 @@ +/* + * Return file offset. + * Coordinates with buffering. + */ +#include +#include + +long ftell(iop) + register FILE *iop; +{ + register long tres; + register int adjust; + + if (iop->_cnt < 0) + iop->_cnt = 0; + if (iop->_flag&_IOREAD) + adjust = - iop->_cnt; + else if (iop->_flag&(_IOWRT|_IORW)) { + adjust = 0; + if (iop->_flag&_IOWRT && iop->_base && (iop->_flag&_IONBF)==0) + adjust = iop->_ptr - iop->_base; + } else + return(-1); + tres = lseek(fileno(iop), 0L, 1); + if (tres<0) + return(tres); + tres += adjust; + return(tres); +} diff --git a/src/libc/stdio/fwrite.c b/src/libc/stdio/fwrite.c new file mode 100644 index 0000000..7c2aec0 --- /dev/null +++ b/src/libc/stdio/fwrite.c @@ -0,0 +1,47 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include +#include + +size_t +fwrite(vptr, size, count, iop) + const void *vptr; + size_t size, count; + register FILE *iop; +{ + register const char *ptr = vptr; + register unsigned s; + + s = size * count; + if (iop->_flag & _IOLBF) + while (s > 0) { + if (--iop->_cnt > -iop->_bufsiz && *ptr != '\n') + *iop->_ptr++ = *ptr++; + else if (_flsbuf(*(unsigned char *)ptr++, iop) == EOF) + break; + s--; + } + else while (s > 0) { + if (iop->_cnt < s) { + if (iop->_cnt > 0) { + bcopy(ptr, iop->_ptr, iop->_cnt); + ptr += iop->_cnt; + iop->_ptr += iop->_cnt; + s -= iop->_cnt; + } + if (_flsbuf(*(unsigned char *)ptr++, iop) == EOF) + break; + s--; + } + if (iop->_cnt >= s) { + bcopy(ptr, iop->_ptr, s); + iop->_ptr += s; + iop->_cnt -= s; + return (count); + } + } + return (size != 0 ? count - ((s + size - 1) / size) : 0); +} diff --git a/src/libc/stdio/getchar.c b/src/libc/stdio/getchar.c new file mode 100644 index 0000000..df53c6f --- /dev/null +++ b/src/libc/stdio/getchar.c @@ -0,0 +1,13 @@ +/* + * A subroutine version of the macro getchar. + */ +#define USE_STDIO_MACROS +#include + +#undef getchar + +int +getchar() +{ + return getc(stdin); +} diff --git a/src/libc/stdio/gets.c b/src/libc/stdio/gets.c new file mode 100644 index 0000000..ca9e064 --- /dev/null +++ b/src/libc/stdio/gets.c @@ -0,0 +1,17 @@ +#include + +char * +gets(s) +char *s; +{ + register int c; + register char *cs; + + cs = s; + while ((c = getchar()) != '\n' && c != EOF) + *cs++ = c; + if (c == EOF && cs==s) + return(NULL); + *cs++ = '\0'; + return(s); +} diff --git a/src/libc/stdio/getw.c b/src/libc/stdio/getw.c new file mode 100644 index 0000000..b043330 --- /dev/null +++ b/src/libc/stdio/getw.c @@ -0,0 +1,35 @@ +#include + +int +getw(iop) + register FILE *iop; +{ + register int i; + register char *p; + int w; + + p = (char *)&w; + for (i=sizeof(int); --i>=0;) + *p++ = getc(iop); + if (feof(iop)) + return(EOF); + return(w); +} + +#ifdef pdp11 +long +getlw(iop) +register FILE *iop; +{ + register int i; + register char *p; + long w; + + p = (char *)&w; + for (i=sizeof(long); --i>=0;) + *p++ = getc(iop); + if (feof(iop)) + return(EOF); + return(w); +} +#endif diff --git a/src/libc/stdio/printf.c b/src/libc/stdio/printf.c new file mode 100644 index 0000000..59ce5ae --- /dev/null +++ b/src/libc/stdio/printf.c @@ -0,0 +1,13 @@ +#include +#include + +int +printf (const char *fmt, ...) +{ + va_list args; + + va_start (args, fmt); + _doprnt (fmt, args, stdout); + va_end (args); + return ferror (stdout) ? EOF : 0; +} diff --git a/src/libc/stdio/putchar.c b/src/libc/stdio/putchar.c new file mode 100644 index 0000000..24adc7b --- /dev/null +++ b/src/libc/stdio/putchar.c @@ -0,0 +1,14 @@ +/* + * A subroutine version of the macro putchar + */ +#define USE_STDIO_MACROS +#include + +#undef putchar + +int +putchar(c) + register int c; +{ + return putc(c, stdout); +} diff --git a/src/libc/stdio/puts.c b/src/libc/stdio/puts.c new file mode 100644 index 0000000..357e5d4 --- /dev/null +++ b/src/libc/stdio/puts.c @@ -0,0 +1,12 @@ +#include + +int +puts(s) + register const char *s; +{ + register int c; + + while ((c = *s++)) + putchar(c); + return(putchar('\n')); +} diff --git a/src/libc/stdio/putw.c b/src/libc/stdio/putw.c new file mode 100644 index 0000000..de2cccb --- /dev/null +++ b/src/libc/stdio/putw.c @@ -0,0 +1,30 @@ +#include + +int +putw(w, iop) + register FILE *iop; +{ + register char *p; + register int i; + + p = (char *)&w; + for (i=sizeof(int); --i>=0;) + putc(*p++, iop); + return(ferror(iop)); +} + +#ifdef pdp11 +int +putlw(w, iop) + long w; + register FILE *iop; +{ + register char *p; + register int i; + + p = (char *)&w; + for (i=sizeof(long); --i>=0;) + putc(*p++, iop); + return(ferror(iop)); +} +#endif diff --git a/src/libc/stdio/remove.c b/src/libc/stdio/remove.c new file mode 100644 index 0000000..e127ed9 --- /dev/null +++ b/src/libc/stdio/remove.c @@ -0,0 +1,48 @@ +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Chris Torek. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include +#include +#include +#include + +int +remove(file) + const char *file; +{ + struct stat sb; + + if (lstat(file, &sb) < 0) + return (-1); + if (S_ISDIR(sb.st_mode)) + return (rmdir(file)); + return (unlink(file)); +} diff --git a/src/libc/stdio/rew.c b/src/libc/stdio/rew.c new file mode 100644 index 0000000..0913752 --- /dev/null +++ b/src/libc/stdio/rew.c @@ -0,0 +1,15 @@ +#include +#include + +void +rewind(iop) + register FILE *iop; +{ + fflush(iop); + lseek(fileno(iop), 0L, 0); + iop->_cnt = 0; + iop->_ptr = iop->_base; + iop->_flag &= ~(_IOERR|_IOEOF); + if (iop->_flag & _IORW) + iop->_flag &= ~(_IOREAD|_IOWRT); +} diff --git a/src/libc/stdio/scanf.c b/src/libc/stdio/scanf.c new file mode 100644 index 0000000..8d5c6f9 --- /dev/null +++ b/src/libc/stdio/scanf.c @@ -0,0 +1,45 @@ +#include +#include + +int +scanf (const char *fmt, ...) +{ + va_list args; + int n; + + va_start (args, fmt); + n = _doscan (stdin, fmt, args); + va_end (args); + return n; +} + +int +fscanf (FILE *iop, const char *fmt, ...) +{ + va_list args; + int n; + + va_start (args, fmt); + n = _doscan(iop, fmt, args); + va_end (args); + return n; +} + +int +sscanf (const char *str, const char *fmt, ...) +{ + FILE _strbuf; + va_list args; + int n; + + _strbuf._flag = _IOREAD|_IOSTRG; + _strbuf._ptr = _strbuf._base = (void*) str; + _strbuf._cnt = 0; + while (*str++) + _strbuf._cnt++; + _strbuf._bufsiz = _strbuf._cnt; + va_start (args, fmt); + n = _doscan(&_strbuf, fmt, args); + va_end (args); + return n; +} diff --git a/src/libc/stdio/setbuf.c b/src/libc/stdio/setbuf.c new file mode 100644 index 0000000..ff37c29 --- /dev/null +++ b/src/libc/stdio/setbuf.c @@ -0,0 +1,44 @@ +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Chris Torek. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include + +void +setbuf(fp, buf) + FILE *fp; + char *buf; +{ + (void) setvbuf(fp, buf, buf ? _IOFBF : _IONBF, BUFSIZ); +} diff --git a/src/libc/stdio/setbuffer.c b/src/libc/stdio/setbuffer.c new file mode 100644 index 0000000..567f690 --- /dev/null +++ b/src/libc/stdio/setbuffer.c @@ -0,0 +1,57 @@ +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Chris Torek. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include +#include + +void +setbuffer(fp, buf, size) + register FILE *fp; + char *buf; + size_t size; +{ + setvbuf(fp, buf, buf ? _IOFBF : _IONBF, size); +} + +/* + * set line buffering + */ +void +setlinebuf(fp) + FILE *fp; +{ + + setvbuf(fp, (char *)NULL, _IOLBF, (size_t)0); +} diff --git a/src/libc/stdio/setvbuf.c b/src/libc/stdio/setvbuf.c new file mode 100644 index 0000000..bd37990 --- /dev/null +++ b/src/libc/stdio/setvbuf.c @@ -0,0 +1,125 @@ +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Chris Torek. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include +#include +#include + +/* + * This has been slightly trimmed from the 4.4BSD version for use with 2.11BSD. + * In particular 1) the flag names were changed back to the original ones + * since I didn't feel like porting all of 4.4's stdio package right now and + * 2) The constant BUFSIZ is used rather than importing the "optimum buffer + * size selection" logic from 4.4 (besides, a PDP11 can't afford more than 1kb + * most of the time anyhow). + * + * Set one of the three kinds of buffering, optionally including + * a buffer. + */ +int +setvbuf(fp, buf, mode, size) + register FILE *fp; + char *buf; + register int mode; + size_t size; +{ + int ret; + register int flags; + +/* + * Verify arguments. Note, buf and size are ignored when setting _IONBF. + */ + if (mode != _IONBF) + if ((mode != _IOFBF && mode != _IOLBF) || (int)size < 0) + return (EOF); + + /* + * Write current buffer, if any. Discard unread input, cancel + * line buffering, and free old buffer if malloc()ed. + */ + (void)fflush(fp); + fp->_cnt = fp->_bufsiz = 0; + flags = fp->_flag; + if (flags & _IOMYBUF) + free((void *)fp->_base); + flags &= ~(_IOLBF | _IONBF | _IOMYBUF); + ret = 0; + + /* If setting unbuffered mode, skip all the hard work. */ + if (mode == _IONBF) + goto nbf; + + if (size == 0) { + buf = NULL; /* force local allocation */ + size = BUFSIZ; + } + + /* Allocate buffer if needed. */ + if (buf == NULL) { + if ((buf = (char *)malloc(size)) == NULL) { + /* + * Unable to honor user's request. We will return + * failure, but try again with file system size. + */ + ret = EOF; + if (size != BUFSIZ) { + size = BUFSIZ; + buf = (char *)malloc(size); + } + } + if (buf == NULL) { + /* No luck; switch to unbuffered I/O. */ +nbf: + fp->_flag = flags | _IONBF; + fp->_base = fp->_ptr = NULL; + return (ret); + } + flags |= _IOMYBUF; + } + + /* + * Fix up the FILE fields. If in r/w mode, go to the unknown state + * so that the the first read performs its initial call to _filbuf and + * the first write has an empty buffer to fill. + */ + if (mode == _IOLBF) + flags |= _IOLBF; + if (flags & _IORW) + flags &= ~(_IOREAD | _IOWRT); + fp->_flag = flags; + fp->_base = fp->_ptr = (char *)buf; + fp->_bufsiz = size; + return (ret); +} diff --git a/src/libc/stdio/snprintf.c b/src/libc/stdio/snprintf.c new file mode 100644 index 0000000..64f58eb --- /dev/null +++ b/src/libc/stdio/snprintf.c @@ -0,0 +1,34 @@ +/* + * 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. + */ +#include +#include + +int +snprintf (char *str, size_t nbytes, const char *fmt, ...) +{ + FILE _strbuf; + va_list args; + + _strbuf._flag = _IOWRT+_IOSTRG; + _strbuf._ptr = str; + _strbuf._cnt = nbytes; + va_start (args, fmt); + _doprnt (fmt, args, &_strbuf); + va_end (args); + *_strbuf._ptr = 0; + return _strbuf._ptr - str; +} diff --git a/src/libc/stdio/sprintf.c b/src/libc/stdio/sprintf.c new file mode 100644 index 0000000..aaa045e --- /dev/null +++ b/src/libc/stdio/sprintf.c @@ -0,0 +1,34 @@ +/* + * 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. + */ +#include +#include + +int +sprintf (char *str, const char *fmt, ...) +{ + FILE _strbuf; + va_list args; + + _strbuf._flag = _IOWRT+_IOSTRG; + _strbuf._ptr = str; + _strbuf._cnt = 32767; + va_start (args, fmt); + _doprnt (fmt, args, &_strbuf); + va_end (args); + *_strbuf._ptr = 0; + return _strbuf._ptr - str; +} diff --git a/src/libc/stdio/strout.c b/src/libc/stdio/strout.c new file mode 100644 index 0000000..b6afe78 --- /dev/null +++ b/src/libc/stdio/strout.c @@ -0,0 +1,24 @@ +#include + +void +_strout(count, string, adjust, file, fillch) + register char *string; + register int count; + int adjust; + register FILE *file; +{ + while (adjust < 0) { + if (*string=='-' && fillch=='0') { + putc(*string++, file); + count--; + } + putc(fillch, file); + adjust++; + } + while (--count>=0) + putc(*string++, file); + while (adjust) { + putc(fillch, file); + adjust--; + } +} diff --git a/src/libc/stdio/ungetc.c b/src/libc/stdio/ungetc.c new file mode 100644 index 0000000..4f58f49 --- /dev/null +++ b/src/libc/stdio/ungetc.c @@ -0,0 +1,22 @@ +#include + +int +ungetc(c, iop) + register FILE *iop; +{ + if (c == EOF || (iop->_flag & (_IOREAD|_IORW)) == 0 || + iop->_ptr == NULL || iop->_base == NULL) + return (EOF); + + if (iop->_ptr == iop->_base) { + if (iop->_cnt == 0) + iop->_ptr++; + else + return (EOF); + } + + iop->_cnt++; + *--iop->_ptr = c; + + return (c); +} diff --git a/src/libc/stdio/vfprintf.c b/src/libc/stdio/vfprintf.c new file mode 100644 index 0000000..350aa0a --- /dev/null +++ b/src/libc/stdio/vfprintf.c @@ -0,0 +1,42 @@ +/* + * 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. + */ +#include +#include +#include + +int +vfprintf (iop, fmt, ap) + FILE *iop; + const char *fmt; + va_list ap; +{ + int len; + + if (iop->_flag & _IONBF) { + iop->_flag &= ~_IONBF; + iop->_ptr = iop->_base = alloca(BUFSIZ); + len = _doprnt(fmt, ap, iop); + (void) fflush(iop); + iop->_flag |= _IONBF; + iop->_base = NULL; + iop->_bufsiz = 0; + iop->_cnt = 0; + } else + len = _doprnt(fmt, ap, iop); + + return (ferror(iop) ? EOF : len); +} diff --git a/src/libc/stdio/vprintf.c b/src/libc/stdio/vprintf.c new file mode 100644 index 0000000..284f184 --- /dev/null +++ b/src/libc/stdio/vprintf.c @@ -0,0 +1,29 @@ +/* + * 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. + */ +#include +#include + +int +vprintf (fmt, ap) + const char *fmt; + va_list ap; +{ + int len; + + len = _doprnt(fmt, ap, stdout); + return (ferror(stdout) ? EOF : len); +} diff --git a/src/libc/stdio/vsprintf.c b/src/libc/stdio/vsprintf.c new file mode 100644 index 0000000..701366e --- /dev/null +++ b/src/libc/stdio/vsprintf.c @@ -0,0 +1,34 @@ +/* + * 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. + */ +#include +#include + +int +vsprintf(str, fmt, ap) + char *str; + const char *fmt; + va_list ap; +{ + FILE f; + + f._flag = _IOWRT+_IOSTRG; + f._ptr = str; + f._cnt = 32767; + _doprnt(fmt, ap, &f); + *f._ptr = 0; + return (f._ptr - str); +} diff --git a/src/libc/stdlib/Makefile b/src/libc/stdlib/Makefile new file mode 100644 index 0000000..952f211 --- /dev/null +++ b/src/libc/stdlib/Makefile @@ -0,0 +1,34 @@ +# +# This is the Makefile for 'stdlib'. New routines ported from 4.4BSD's +# libc/stdlib directory go here but existing libc/gen files are being left +# where they are. +# +TOPSRC = $(shell cd ../../..; pwd) +include $(TOPSRC)/target.mk + +DEFS = +CFLAGS += ${DEFS} -Os + +SRCS = getopt.c getsubopt.c strtol.c strtoul.c strtod.c +OBJS = getopt.o getsubopt.o strtol.o strtoul.o strtod.o + +all: stdlib.a + +stdlib.a: ${OBJS} + @echo "building stdlib" + @ar cru stdlib.a ${OBJS} + +clean: + rm -f *.o *~ profiled/*.o tags Makefile.bak stdlib.a stdlib_p.s + +depend: ${SRCS} + mkdep ${CFLAGS} ${SRCS} + +tags: + cwd=`pwd`; \ + for i in ${SRCS}; do \ + ctags -a -f ${TAGSFILE} $$cwd/$$i; \ + done + +# DO NOT DELETE THIS LINE -- mkdep uses it. +# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY. diff --git a/src/libc/stdlib/getopt.c b/src/libc/stdlib/getopt.c new file mode 100644 index 0000000..b20a466 --- /dev/null +++ b/src/libc/stdlib/getopt.c @@ -0,0 +1,112 @@ +/* + * 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. + */ +#include +#include +#include +#include + +int opterr = 1, /* if error message should be printed */ + optind = 1, /* index into parent argv vector */ + optopt, /* character checked for validity */ + optreset; /* reset getopt */ +char *optarg; /* argument associated with option */ + +#define BADCH (int)'?' +#define BADARG (int)':' +#define EMSG "" + +/* + * getopt -- + * Parse argc/argv argument vector. + */ +int +getopt(nargc, nargv, ostr) + int nargc; + char * const nargv[]; + const char *ostr; +{ + static char *place = EMSG; /* option letter processing */ + char *oli; /* option letter list index */ + + if (optreset || !*place) { /* update scanning pointer */ + optreset = 0; + if (optind >= nargc || *(place = nargv[optind]) != '-') { + place = EMSG; + return (EOF); + } + if (place[1] && *++place == '-') { /* found "--" */ + ++optind; + place = EMSG; + return (EOF); + } + } /* option letter okay? */ + if ((optopt = (int)*place++) == (int)':' || + !(oli = strchr(ostr, optopt))) { + /* + * if the user didn't specify '-' as an option, + * assume it means EOF. + */ + if (optopt == (int)'-') + return (EOF); + if (!*place) + ++optind; + if (opterr && *ostr != ':') + (void)fprintf(stderr, + "%s: illegal option -- %c\n", __progname, optopt); + return (BADCH); + } + if (*++oli != ':') { /* don't need argument */ + optarg = NULL; + if (!*place) + ++optind; + } + else { /* need an argument */ + if (*place) /* no white space */ + optarg = place; + else if (nargc <= ++optind) { /* no arg */ + place = EMSG; + if (*ostr == ':') + return (BADARG); + if (opterr) + (void)fprintf(stderr, + "%s: option requires an argument -- %c\n", + __progname, optopt); + return (BADCH); + } + else /* white space */ + optarg = nargv[optind]; + place = EMSG; + ++optind; + } + return (optopt); /* dump back option letter */ +} diff --git a/src/libc/stdlib/getsubopt.c b/src/libc/stdlib/getsubopt.c new file mode 100644 index 0000000..bfe64c3 --- /dev/null +++ b/src/libc/stdlib/getsubopt.c @@ -0,0 +1,94 @@ +/*- + * 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. + */ +#include +#include + +/* + * The SVID interface to getsubopt provides no way of figuring out which + * part of the suboptions list wasn't matched. This makes error messages + * tricky... The extern variable suboptarg is a pointer to the token + * which didn't match. + */ +char *suboptarg; + +int +getsubopt(optionp, tokens, valuep) + register char **optionp, **valuep; + register char **tokens; +{ + register int cnt; + register char *p; + + suboptarg = *valuep = NULL; + + if (!optionp || !*optionp) + return(-1); + + /* skip leading white-space, commas */ + for (p = *optionp; *p && (*p == ',' || *p == ' ' || *p == '\t'); ++p); + + if (!*p) { + *optionp = p; + return(-1); + } + + /* save the start of the token, and skip the rest of the token. */ + for (suboptarg = p; + *++p && *p != ',' && *p != '=' && *p != ' ' && *p != '\t';); + + if (*p) { + /* + * If there's an equals sign, set the value pointer, and + * skip over the value part of the token. Terminate the + * token. + */ + if (*p == '=') { + *p = '\0'; + for (*valuep = ++p; + *p && *p != ',' && *p != ' ' && *p != '\t'; ++p); + if (*p) + *p++ = '\0'; + } else + *p++ = '\0'; + /* Skip any whitespace or commas after this token. */ + for (; *p && (*p == ',' || *p == ' ' || *p == '\t'); ++p); + } + + /* set optionp for next round. */ + *optionp = p; + + for (cnt = 0; *tokens; ++tokens, ++cnt) + if (!strcmp(suboptarg, *tokens)) + return(cnt); + return(-1); +} diff --git a/src/libc/stdlib/strtod.c b/src/libc/stdlib/strtod.c new file mode 100644 index 0000000..dc19564 --- /dev/null +++ b/src/libc/stdlib/strtod.c @@ -0,0 +1,200 @@ +/* + * double strtodx (char *string, char **endPtr, int radix) + * This procedure converts a floating-point number from an ASCII + * decimal representation to internal double-precision format. + * + * Original sources taken from 386bsd and modified for variable radix + * by Serge Vakulenko, . + * + * Arguments: + * string + * A decimal ASCII floating-point number, optionally preceded + * by white space. Must have form "-I.FE-X", where I is the integer + * part of the mantissa, F is the fractional part of the mantissa, + * and X is the exponent. Either of the signs may be "+", "-", or + * omitted. Either I or F may be omitted, or both. The decimal point + * isn't necessary unless F is present. The "E" may actually be an "e", + * or "E", "S", "s", "F", "f", "D", "d", "L", "l". + * E and X may both be omitted (but not just one). + * + * endPtr + * If non-NULL, store terminating character's address here. + * + * radix + * Radix of floating point, one of 2, 8, 10, 16. + * + * The return value is the double-precision floating-point + * representation of the characters in string. If endPtr isn't + * NULL, then *endPtr is filled in with the address of the + * next character after the last one that was part of the + * floating-point number. + */ +#include +#include + +double strtod (const char *string, char **endPtr) +{ + int sign = 0, expSign = 0, i; + double fraction, dblExp; + register const char *p; + register char c; + + /* Exponent read from "EX" field. */ + int exp = 0; + + /* Exponent that derives from the fractional part. Under normal + * circumstances, it is the negative of the number of digits in F. + * However, if I is very long, the last digits of I get dropped + * (otherwise a long I with a large negative exponent could cause an + * unnecessary overflow on I alone). In this case, fracExp is + * incremented one for each dropped digit. */ + int fracExp = 0; + + /* Number of digits in mantissa. */ + int mantSize; + + /* Number of mantissa digits BEFORE decimal point. */ + int decPt; + + /* Temporarily holds location of exponent in string. */ + const char *pExp; + + /* Largest possible base 10 exponent. + * Any exponent larger than this will already + * produce underflow or overflow, so there's + * no need to worry about additional digits. */ + static int maxExponent = 307; + + /* Table giving binary powers of 10. + * Entry is 10^2^i. Used to convert decimal + * exponents into floating-point numbers. */ + static double powersOf10[] = { + 1e1, 1e2, 1e4, 1e8, 1e16, 1e32, //1e64, 1e128, 1e256, + }; +#if 0 + static double powersOf2[] = { + 2, 4, 16, 256, 65536, 4.294967296e9, 1.8446744073709551616e19, + //3.4028236692093846346e38, 1.1579208923731619542e77, 1.3407807929942597099e154, + }; + static double powersOf8[] = { + 8, 64, 4096, 2.81474976710656e14, 7.9228162514264337593e28, + //6.2771017353866807638e57, 3.9402006196394479212e115, 1.5525180923007089351e231, + }; + static double powersOf16[] = { + 16, 256, 65536, 1.8446744073709551616e19, + //3.4028236692093846346e38, 1.1579208923731619542e77, 1.3407807929942597099e154, + }; +#endif + /* + * Strip off leading blanks and check for a sign. + */ + p = string; + while (*p==' ' || *p=='\t') + ++p; + if (*p == '-') { + sign = 1; + ++p; + } else if (*p == '+') + ++p; + + /* + * Count the number of digits in the mantissa (including the decimal + * point), and also locate the decimal point. + */ + decPt = -1; + for (mantSize=0; ; ++mantSize) { + c = *p; + if (! isdigit (c)) { + if (c != '.' || decPt >= 0) + break; + decPt = mantSize; + } + ++p; + } + + /* + * Now suck up the digits in the mantissa. Use two integers to + * collect 9 digits each (this is faster than using floating-point). + * If the mantissa has more than 18 digits, ignore the extras, since + * they can't affect the value anyway. + */ + pExp = p; + p -= mantSize; + if (decPt < 0) + decPt = mantSize; + else + --mantSize; /* One of the digits was the point. */ + + if (mantSize > 2 * 9) + mantSize = 2 * 9; + fracExp = decPt - mantSize; + if (mantSize == 0) { + fraction = 0.0; + p = string; + goto done; + } else { + int frac1, frac2; + + for (frac1=0; mantSize>9; --mantSize) { + c = *p++; + if (c == '.') + c = *p++; + frac1 = frac1 * 10 + (c - '0'); + } + for (frac2=0; mantSize>0; --mantSize) { + c = *p++; + if (c == '.') + c = *p++; + frac2 = frac2 * 10 + (c - '0'); + } + fraction = (double) 1000000000 * frac1 + frac2; + } + + /* + * Skim off the exponent. + */ + p = pExp; + if (*p=='E' || *p=='e' || *p=='S' || *p=='s' || *p=='F' || *p=='f' || + *p=='D' || *p=='d' || *p=='L' || *p=='l') { + ++p; + if (*p == '-') { + expSign = 1; + ++p; + } else if (*p == '+') + ++p; + while (isdigit (*p)) + exp = exp * 10 + (*p++ - '0'); + } + if (expSign) + exp = fracExp - exp; + else + exp = fracExp + exp; + + /* + * Generate a floating-point number that represents the exponent. + * Do this by processing the exponent one bit at a time to combine + * many powers of 2 of 10. Then combine the exponent with the + * fraction. + */ + if (exp < 0) { + expSign = 1; + exp = -exp; + } else + expSign = 0; + if (exp > maxExponent) + exp = maxExponent; + dblExp = 1.0; + for (i=0; exp; exp>>=1, ++i) + if (exp & 01) + dblExp *= powersOf10[i]; + if (expSign) + fraction /= dblExp; + else + fraction *= dblExp; + +done: + if (endPtr) + *endPtr = (char*) p; + + return sign ? -fraction : fraction; +} diff --git a/src/libc/stdlib/strtol.c b/src/libc/stdlib/strtol.c new file mode 100644 index 0000000..2d39de4 --- /dev/null +++ b/src/libc/stdlib/strtol.c @@ -0,0 +1,123 @@ +/*- + * 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. + */ +#include +#include +#include +#include + +/* + * Convert a string to a long integer. + * + * Ignores `locale' stuff. Assumes that the upper and lower case + * alphabets and digits are each contiguous. + */ +long +strtol(nptr, endptr, base) + char *nptr; + char **endptr; + register int base; +{ + register char *s = nptr; + register unsigned long acc; + register int c; + register unsigned long cutoff; + register int neg = 0, any, cutlim; + + /* + * Skip white space and pick up leading +/- sign if any. + * If base is 0, allow 0x for hex and 0 for octal, else + * assume decimal; if base is already 16, allow 0x. + */ + do { + c = *s++; + } while (isspace(c)); + if (c == '-') { + neg = 1; + c = *s++; + } else if (c == '+') + c = *s++; + if ((base == 0 || base == 16) && + c == '0' && (*s == 'x' || *s == 'X')) { + c = s[1]; + s += 2; + base = 16; + } + if (base == 0) + base = c == '0' ? 8 : 10; + + /* + * Compute the cutoff value between legal numbers and illegal + * numbers. That is the largest legal value, divided by the + * base. An input number that is greater than this value, if + * followed by a legal input character, is too big. One that + * is equal to this value may be valid or not; the limit + * between valid and invalid numbers is then based on the last + * digit. For instance, if the range for longs is + * [-2147483648..2147483647] and the input base is 10, + * cutoff will be set to 214748364 and cutlim to either + * 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated + * a value > 214748364, or equal but the next digit is > 7 (or 8), + * the number is too big, and we will return a range error. + * + * Set any if any `digits' consumed; make it negative to indicate + * overflow. + */ + cutoff = neg ? -(unsigned long)LONG_MIN : LONG_MAX; + cutlim = cutoff % (unsigned long)base; + cutoff /= (unsigned long)base; + for (acc = 0, any = 0;; c = *s++) { + if (isdigit(c)) + c -= '0'; + else if (isalpha(c)) + c -= isupper(c) ? 'A' - 10 : 'a' - 10; + else + break; + if (c >= base) + break; + if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) + any = -1; + else { + any = 1; + acc *= base; + acc += c; + } + } + if (any < 0) { + acc = neg ? LONG_MIN : LONG_MAX; + errno = ERANGE; + } else if (neg) + acc = -acc; + if (endptr != 0) + *endptr = (char *)(any ? s - 1 : nptr); + return (acc); +} diff --git a/src/libc/stdlib/strtoul.c b/src/libc/stdlib/strtoul.c new file mode 100644 index 0000000..93e16d2 --- /dev/null +++ b/src/libc/stdlib/strtoul.c @@ -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. + */ +#include +#include +#include +#include + +/* + * Convert a string to an unsigned long integer. + * + * Ignores `locale' stuff. Assumes that the upper and lower case + * alphabets and digits are each contiguous. + */ +unsigned long +strtoul(nptr, endptr, base) + char *nptr; + char **endptr; + register int base; +{ + register char *s = nptr; + register unsigned long acc; + register int c; + register unsigned long cutoff; + register int neg = 0, any, cutlim; + + /* + * See strtol for comments as to the logic used. + */ + do { + c = *s++; + } while (isspace(c)); + if (c == '-') { + neg = 1; + c = *s++; + } else if (c == '+') + c = *s++; + if ((base == 0 || base == 16) && + c == '0' && (*s == 'x' || *s == 'X')) { + c = s[1]; + s += 2; + base = 16; + } + if (base == 0) + base = c == '0' ? 8 : 10; + cutoff = (unsigned long)ULONG_MAX / (unsigned long)base; + cutlim = (unsigned long)ULONG_MAX % (unsigned long)base; + for (acc = 0, any = 0;; c = *s++) { + if (isdigit(c)) + c -= '0'; + else if (isalpha(c)) + c -= isupper(c) ? 'A' - 10 : 'a' - 10; + else + break; + if (c >= base) + break; + if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) + any = -1; + else { + any = 1; + acc *= base; + acc += c; + } + } + if (any < 0) { + acc = ULONG_MAX; + errno = ERANGE; + } else if (neg) + acc = -acc; + if (endptr != 0) + *endptr = (char *)(any ? s - 1 : nptr); + return (acc); +} diff --git a/src/libc/string/Makefile b/src/libc/string/Makefile new file mode 100644 index 0000000..d1fc06b --- /dev/null +++ b/src/libc/string/Makefile @@ -0,0 +1,34 @@ +# +# This is the Makefile for the 'string' functions. New routines ported from +# 4.4BSD's libc/string directory go here but existing libc/gen files are +# being left where they are. +# +TOPSRC = $(shell cd ../../..; pwd) +include $(TOPSRC)/target.mk + +DEFS = +CFLAGS += ${DEFS} -Os + +SRCS = strcspn.c strpbrk.c strerror.c strsep.c strspn.c strstr.c strtok.c strtok_r.c +OBJS = strcspn.o strpbrk.o strerror.o strsep.o strspn.o strstr.o strtok.o strtok_r.o + +all: string.a + +string.a: ${OBJS} + @echo "building normal string.a" + @ar cru string.a ${OBJS} + +clean: + rm -f *.o *~ profiled/*.o tags Makefile.bak string.a string_p.a + +depend: ${SRCS} + mkdep ${CFLAGS} ${SRCS} + +tags: + cwd=`pwd`; \ + for i in ${SRCS}; do \ + ctags -a -f ${TAGSFILE} $$cwd/$$i; \ + done + +# DO NOT DELETE THIS LINE -- mkdep uses it. +# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY. diff --git a/src/libc/string/strcspn.c b/src/libc/string/strcspn.c new file mode 100644 index 0000000..e988ad0 --- /dev/null +++ b/src/libc/string/strcspn.c @@ -0,0 +1,63 @@ +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Chris Torek. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include +#include + +/* + * Span the complement of string s2. + */ +size_t +strcspn (s1, s2) + const char *s1; + const char *s2; +{ + register const char *p, *spanp; + register char c, sc; + + /* + * Stop as soon as we find any character from s2. Note that there + * must be a NUL in s2; it suffices to stop when we find that, too. + */ + for (p = s1;;) { + c = *p++; + spanp = s2; + do { + if ((sc = *spanp++) == c) + return (p - 1 - s1); + } while (sc != 0); + } + /* NOTREACHED */ +} diff --git a/src/libc/string/strerror.c b/src/libc/string/strerror.c new file mode 100644 index 0000000..7b17952 --- /dev/null +++ b/src/libc/string/strerror.c @@ -0,0 +1,73 @@ +/* + * 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. + */ +#include +#include +#include + +char * +strerror(errnum) + register int errnum; +{ + static char msgstr[64]; + int mib[3]; + size_t size; + + /* Read an error message from kernel to a static buffer. */ + mib[0] = CTL_MACHDEP; + mib[1] = CPU_ERRMSG; + mib[2] = errnum; + size = sizeof (msgstr); + if (sysctl(mib, 3, msgstr, &size, NULL, 0) == -1) { + /* Do this by hand, so we don't include stdio(3). */ + static const char unknown[] = "Unknown error: "; + register char *p, *t; + const char *q; + char tmp[20]; + + t = tmp; + do { + *t++ = '0' + ((unsigned)errnum % 10); + errnum = (unsigned)errnum / 10; + } while (errnum != 0); + + p = msgstr; + for (q=unknown; *q; q++) { + *p++ = *q; + } + do { + *p++ = *--t; + } while (t > tmp); + *p = 0; + } + return msgstr; +} diff --git a/src/libc/string/strpbrk.c b/src/libc/string/strpbrk.c new file mode 100644 index 0000000..a33bc32 --- /dev/null +++ b/src/libc/string/strpbrk.c @@ -0,0 +1,55 @@ +/* + * 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. + */ +#include +#include +#include /* for NULL */ + +/* + * Find the first occurrence in s1 of a character in s2 (excluding NUL). + */ +char * +strpbrk(s1, s2) + register const char *s1; + const char *s2; +{ + register const char *scanp; + register int c; + int sc; + + while ((c = *s1++) != 0) { + for (scanp = s2; (sc = *scanp++) != 0;) + if (sc == c) + return ((char *)(s1 - 1)); + } + return (NULL); +} diff --git a/src/libc/string/strsep.c b/src/libc/string/strsep.c new file mode 100644 index 0000000..e71334e --- /dev/null +++ b/src/libc/string/strsep.c @@ -0,0 +1,75 @@ +/*- + * 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. + */ +#include +#include +#include + +/* + * Get next token from string *stringp, where tokens are possibly-empty + * strings separated by characters from delim. + * + * Writes NULs into the string at *stringp to end tokens. + * delim need not remain constant from call to call. + * On return, *stringp points past the last NUL written (if there might + * be further tokens), or is NULL (if there are definitely no more tokens). + * + * If *stringp is NULL, strsep returns NULL. + */ +char * +strsep(stringp, delim) + register char **stringp; + const char *delim; +{ + register char *s; + register const char *spanp; + int c, sc; + char *tok; + + if ((s = *stringp) == NULL) + return (NULL); + for (tok = s;;) { + c = *s++; + spanp = delim; + do { + if ((sc = *spanp++) == c) { + if (c == 0) + s = NULL; + else + s[-1] = 0; + *stringp = s; + return (tok); + } + } while (sc != 0); + } + /* NOTREACHED */ +} diff --git a/src/libc/string/strspn.c b/src/libc/string/strspn.c new file mode 100644 index 0000000..edadc91 --- /dev/null +++ b/src/libc/string/strspn.c @@ -0,0 +1,56 @@ +/* + * 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. + */ +#include +#include + +/* + * Span the string s2 (skip characters that are in s2). + */ +size_t +strspn(s1, s2) + const char *s1; + const char *s2; +{ + register const char *p = s1, *spanp; + register char c, sc; + + /* + * Skip any characters in s2, excluding the terminating \0. + */ +cont: + c = *p++; + for (spanp = s2; (sc = *spanp++) != 0;) + if (sc == c) + goto cont; + return (p - 1 - s1); +} diff --git a/src/libc/string/strstr.c b/src/libc/string/strstr.c new file mode 100644 index 0000000..0907385 --- /dev/null +++ b/src/libc/string/strstr.c @@ -0,0 +1,60 @@ +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Chris Torek. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include + +/* + * Find the first occurrence of find in s. + */ +char * +strstr(s, find) + register const char *s, *find; +{ + register char c; + char sc; + size_t len; + + if ((c = *find++) != 0) { + len = strlen(find); + do { + do { + if ((sc = *s++) == 0) + return (NULL); + } while (sc != c); + } while (strncmp(s, find, len) != 0); + s--; + } + return ((char *)s); +} diff --git a/src/libc/string/strtok.c b/src/libc/string/strtok.c new file mode 100644 index 0000000..7863554 --- /dev/null +++ b/src/libc/string/strtok.c @@ -0,0 +1,85 @@ +/* + * 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. + */ +#include +#include + +char * +strtok(s, delim) + register char *s; + register const char *delim; +{ + register char *spanp; + int c, sc; + char *tok; + static char *last; + + + if (s == NULL && (s = last) == NULL) + return (NULL); + + /* + * Skip (span) leading delimiters (s += strspn(s, delim), sort of). + */ +cont: + c = *s++; + for (spanp = (char *)delim; (sc = *spanp++) != 0;) { + if (c == sc) + goto cont; + } + + if (c == 0) { /* no non-delimiter characters */ + last = NULL; + return (NULL); + } + tok = s - 1; + + /* + * Scan token (scan for delimiters: s += strcspn(s, delim), sort of). + * Note that delim must have one NUL; we stop if we see that, too. + */ + for (;;) { + c = *s++; + spanp = (char *)delim; + do { + if ((sc = *spanp++) == c) { + if (c == 0) + s = NULL; + else + s[-1] = 0; + last = s; + return (tok); + } + } while (sc != 0); + } + /* NOTREACHED */ +} diff --git a/src/libc/string/strtok_r.c b/src/libc/string/strtok_r.c new file mode 100644 index 0000000..3b5465d --- /dev/null +++ b/src/libc/string/strtok_r.c @@ -0,0 +1,80 @@ +/* + * 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. + */ +#include +#include + +char *strtok_r(char *s, const char *delim, char **last) +{ + char *spanp, *tok; + int c, sc; + + if (s == NULL && (s = *last) == NULL) + return (NULL); + + /* + * Skip (span) leading delimiters (s += strspn(s, delim), sort of). + */ +cont: + c = *s++; + for (spanp = (char *)delim; (sc = *spanp++) != 0;) { + if (c == sc) + goto cont; + } + + if (c == 0) { /* no non-delimiter characters */ + *last = NULL; + return (NULL); + } + tok = s - 1; + + /* + * Scan token (scan for delimiters: s += strcspn(s, delim), sort of). + * Note that delim must have one NUL; we stop if we see that, too. + */ + for (;;) { + c = *s++; + spanp = (char *)delim; + do { + if ((sc = *spanp++) == c) { + if (c == 0) + s = NULL; + else + s[-1] = '\0'; + *last = s; + return (tok); + } + } while (sc != 0); + } + /* NOTREACHED */ +} + diff --git a/src/libcurses/Makefile b/src/libcurses/Makefile new file mode 100644 index 0000000..1fec46a --- /dev/null +++ b/src/libcurses/Makefile @@ -0,0 +1,75 @@ +# Copyright (c) 1980 Regents of the University of California. +# All rights reserved. The Berkeley software License Agreement +# specifies the terms and conditions for redistribution. +# +# curses package +# +TOPSRC = $(shell cd ../..; pwd) +include $(TOPSRC)/target.mk + +CFILES= addch.c addstr.c box.c clear.c clrtobot.c clrtoeol.c cr_put.c \ + cr_tty.c curses.c delch.c deleteln.c delwin.c endwin.c erase.c \ + fullname.c getch.c getstr.c idlok.c id_subwins.c initscr.c insch.c \ + insertln.c longname.c move.c mvprintw.c mvscanw.c mvwin.c newwin.c \ + overlay.c overwrite.c printw.c putchar.c refresh.c scanw.c scroll.c \ + toucholap.c standout.c touchwin.c tstp.c unctrl.c +OBJS= addch.o addstr.o box.o clear.o clrtobot.o clrtoeol.o cr_put.o \ + cr_tty.o curses.o delch.o deleteln.o delwin.o endwin.o erase.o \ + fullname.o getch.o getstr.o idlok.o id_subwins.o initscr.o insch.o \ + insertln.o longname.o move.o mvprintw.o mvscanw.o mvwin.o newwin.o \ + overlay.o overwrite.o printw.o putchar.o refresh.o scanw.o scroll.o \ + toucholap.o standout.o touchwin.o tstp.o unctrl.o +POBJS= ../addch.o ../addstr.o ../box.o ../clear.o ../clrtobot.o ../clrtoeol.o ../cr_put.o \ + ../cr_tty.o ../curses.o ../delch.o ../deleteln.o ../delwin.o ../endwin.o ../erase.o \ + ../fullname.o ../getch.o ../getstr.o ../idlok.o ../id_subwins.o ../initscr.o ../insch.o \ + ../insertln.o ../longname.o ../move.o ../mvprintw.o ../mvscanw.o ../mvwin.o ../newwin.o \ + ../overlay.o ../overwrite.o ../printw.o ../putchar.o ../refresh.o ../scanw.o ../scroll.o \ + ../toucholap.o ../standout.o ../touchwin.o ../tstp.o ../unctrl.o + +CTAGS= ctags +DEFS= -DNOSCCS +CFLAGS= -O -Wall -Werror $(DEFS) +TAGSFILE=tags + +all: ../libcurses.a + +../libcurses.a: ${OBJS} + @echo building normal ../libcurses.a + @$(AR) ru ../libcurses.a ${OBJS} + $(RANLIB) ../libcurses.a + +../libcurses_p.a: ${OBJS} + @echo building profiled ../libcurses.a + @cd profiled; $(AR) ru ../../libcurses_p.a ${POBJS} + $(RANLIB) ../libcurses_p.a + +install: all +# cp ../libcurses.a ${DESTDIR}/lib/libcurses.a +# $(RANLIB) ${DESTDIR}/lib/libcurses.a +# cp ../libcurses_p.a ${DESTDIR}/lib/libcurses_p.a +# $(RANLIB) ${DESTDIR}/lib/libcurses_p.a + +tags: + cwd=`pwd`; \ + for i in ${CFILES}; do \ + ctags -a -f ${TAGSFILE} $$cwd/$$i; \ + done + +clean: + rm -f ${OBJS} profiled/*.o a.out core test errs \ + ../libcurses.a ../libcurses_p.a tags + +ctags: + ${CTAGS} ${CFILES} curses.h + +lint: + lint -hxb ${CFILES} -lcurses > lint.out + +test: libcurses test.o + ${CC} ${LDFLAGS} ${CFLAGS} -o test test.o libcurses -ltermlib + +test.o: test.c + ${CC} ${CFLAGS} -c test.c + +ar: + ar crv curses.ar ${CFILES} curses.h curses.ext Makefile diff --git a/src/libcurses/addch.c b/src/libcurses/addch.c new file mode 100644 index 0000000..06b576b --- /dev/null +++ b/src/libcurses/addch.c @@ -0,0 +1,97 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "curses.ext" + +/* + * set_ch: + * Set the first and last change flags for this window. + */ +static void +set_ch(win, y, x, ch) + reg WINDOW *win; + int y, x; +{ +# ifdef FULLDEBUG + fprintf(outf, "SET_CH(%0.2o, %d, %d)\n", win, y, x); +# endif + if (win->_y[y][x] != ch) { + x += win->_ch_off; + if (win->_firstch[y] == _NOCHANGE) + win->_firstch[y] = win->_lastch[y] = x; + else if (x < win->_firstch[y]) + win->_firstch[y] = x; + else if (x > win->_lastch[y]) + win->_lastch[y] = x; +# ifdef FULLDEBUG + fprintf(outf, "SET_CH: change gives f/l: %d/%d [%d/%d]\n", + win->_firstch[y], win->_lastch[y], + win->_firstch[y] - win->_ch_off, + win->_lastch[y] - win->_ch_off); +# endif + } +} + +/* + * This routine adds the character to the current position + */ +int waddch(win, c) + reg WINDOW *win; + char c; +{ + reg int x, y; + reg int newx; + + x = win->_curx; + y = win->_cury; +# ifdef FULLDEBUG + fprintf(outf, "ADDCH('%c') at (%d, %d)\n", c, y, x); +# endif + switch (c) { + case '\t': + for (newx = x + (8 - (x & 07)); x < newx; x++) + if (waddch(win, ' ') == ERR) + return ERR; + return OK; + + default: +# ifdef FULLDEBUG + fprintf(outf, "ADDCH: 1: y = %d, x = %d, firstch = %d, lastch = %d\n", y, x, win->_firstch[y], win->_lastch[y]); +# endif + if (win->_flags & _STANDOUT) + c |= _STANDOUT; + set_ch(win, y, x, c); + win->_y[y][x++] = c; + if (x >= win->_maxx) { + x = 0; +newline: + if (++y >= win->_maxy) { + if (! win->_scroll) + return ERR; + scroll(win); + --y; + } + } +# ifdef FULLDEBUG + fprintf(outf, "ADDCH: 2: y = %d, x = %d, firstch = %d, lastch = %d\n", y, x, win->_firstch[y], win->_lastch[y]); +# endif + break; + case '\n': + wclrtoeol(win); + if (!NONL) + x = 0; + goto newline; + case '\r': + x = 0; + break; + case '\b': + if (--x < 0) + x = 0; + break; + } + win->_curx = x; + win->_cury = y; + return OK; +} diff --git a/src/libcurses/addstr.c b/src/libcurses/addstr.c new file mode 100644 index 0000000..687bae9 --- /dev/null +++ b/src/libcurses/addstr.c @@ -0,0 +1,23 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "curses.ext" + +/* + * This routine adds a string starting at (_cury,_curx) + */ +int +waddstr(win, str) + reg WINDOW *win; + reg char *str; +{ +# ifdef DEBUG + fprintf(outf, "WADDSTR(\"%s\")\n", str); +# endif + while (*str) + if (waddch(win, *str++) == ERR) + return ERR; + return OK; +} diff --git a/src/libcurses/box.c b/src/libcurses/box.c new file mode 100644 index 0000000..029f6c2 --- /dev/null +++ b/src/libcurses/box.c @@ -0,0 +1,35 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "curses.ext" + +/* + * This routine draws a box around the given window with "vert" + * as the vertical delimiting char, and "hor", as the horizontal one. + * + */ +void +box(win, vert, hor) + reg WINDOW *win; + char vert, hor; +{ + + reg int i; + reg int endy, endx; + reg char *fp, *lp; + + endx = win->_maxx; + endy = win->_maxy - 1; + fp = win->_y[0]; + lp = win->_y[endy]; + for (i = 0; i < endx; i++) + fp[i] = lp[i] = hor; + endx--; + for (i = 0; i <= endy; i++) + win->_y[i][0] = (win->_y[i][endx] = vert); + if (!win->_scroll && (win->_flags&_SCROLLWIN)) + fp[0] = fp[endx] = lp[0] = lp[endx] = ' '; + touchwin(win); +} diff --git a/src/libcurses/clear.c b/src/libcurses/clear.c new file mode 100644 index 0000000..083b136 --- /dev/null +++ b/src/libcurses/clear.c @@ -0,0 +1,17 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "curses.ext" + +/* + * This routine clears the window. + */ +int wclear(win) + reg WINDOW *win; +{ + werase(win); + win->_clear = TRUE; + return OK; +} diff --git a/src/libcurses/clrtobot.c b/src/libcurses/clrtobot.c new file mode 100644 index 0000000..5be4beb --- /dev/null +++ b/src/libcurses/clrtobot.c @@ -0,0 +1,35 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "curses.ext" + +/* + * This routine erases everything on the window. + */ +void +wclrtobot(win) + reg WINDOW *win; +{ + reg int y; + reg char *sp, *end, *maxx; + reg int startx, minx; + + startx = win->_curx; + for (y = win->_cury; y < win->_maxy; y++) { + minx = _NOCHANGE; + maxx = 0; + end = &win->_y[y][win->_maxx]; + for (sp = &win->_y[y][startx]; sp < end; sp++) + if (*sp != ' ') { + maxx = sp; + if (minx == _NOCHANGE) + minx = sp - win->_y[y]; + *sp = ' '; + } + if (minx != _NOCHANGE) + touchline(win, y, minx, maxx - &win->_y[y][0]); + startx = 0; + } +} diff --git a/src/libcurses/clrtoeol.c b/src/libcurses/clrtoeol.c new file mode 100644 index 0000000..3992f18 --- /dev/null +++ b/src/libcurses/clrtoeol.c @@ -0,0 +1,39 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "curses.ext" + +/* + * This routine clears up to the end of line + */ +void +wclrtoeol(win) + reg WINDOW *win; +{ + reg char *sp, *end; + reg int y, x; + reg char *maxx; + reg int minx; + + y = win->_cury; + x = win->_curx; + end = &win->_y[y][win->_maxx]; + minx = _NOCHANGE; + maxx = &win->_y[y][x]; + for (sp = maxx; sp < end; sp++) + if (*sp != ' ') { + maxx = sp; + if (minx == _NOCHANGE) + minx = sp - win->_y[y]; + *sp = ' '; + } + /* + * update firstch and lastch for the line + */ + touchline(win, y, win->_curx, win->_maxx - 1); +# ifdef DEBUG + fprintf(outf, "CLRTOEOL: minx = %d, maxx = %d, firstch = %d, lastch = %d\n", minx, maxx - win->_y[y], win->_firstch[y], win->_lastch[y]); +# endif +} diff --git a/src/libcurses/cr_put.c b/src/libcurses/cr_put.c new file mode 100644 index 0000000..875ae8a --- /dev/null +++ b/src/libcurses/cr_put.c @@ -0,0 +1,390 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "curses.ext" +#include + +#define HARDTABS 8 + +/* + * Terminal driving and line formatting routines. + * Basic motion optimizations are done here as well + * as formatting of lines (printing of control characters, + * line numbering and the like). + */ + +/* + * Sync the position of the output cursor. + * Most work here is rounding for terminal boundaries getting the + * column position implied by wraparound or the lack thereof and + * rolling up the screen to get destline on the screen. + */ + +static int outcol, outline, destcol, destline; + +WINDOW *_win; + +/* + * Move (slowly) to destination. + * Hard thing here is using home cursor on really deficient terminals. + * Otherwise just use cursor motions, hacking use of tabs and overtabbing + * and backspace. + */ + +static int plodcnt, plodflg; + +static int +plodput(c) +{ + if (plodflg) { + plodcnt--; + return 0; + } + return _putchar(c); +} + +/* + * Return the column number that results from being in column col and + * hitting a tab, where tabs are set every ts columns. Work right for + * the case where col > COLS, even if ts does not divide COLS. + */ +static int +tabcol(col, ts) + int col, ts; +{ + int offset; + + if (col >= COLS) { + offset = COLS * (col / COLS); + col -= offset; + } + else + offset = 0; + return col + ts - (col % ts) + offset; +} + +static int +plod(cnt) +{ + register int i, j, k; + register int soutcol, soutline; + + plodcnt = plodflg = cnt; + soutcol = outcol; + soutline = outline; + /* + * Consider homing and moving down/right from there, vs moving + * directly with local motions to the right spot. + */ + if (HO) { + /* + * i is the cost to home and tab/space to the right to + * get to the proper column. This assumes ND space costs + * 1 char. So i+destcol is cost of motion with home. + */ + if (GT) + i = (destcol / HARDTABS) + (destcol % HARDTABS); + else + i = destcol; + /* + * j is cost to move locally without homing + */ + if (destcol >= outcol) { /* if motion is to the right */ + j = destcol / HARDTABS - outcol / HARDTABS; + if (GT && j) + j += destcol % HARDTABS; + else + j = destcol - outcol; + } + else + /* leftward motion only works if we can backspace. */ + if (outcol - destcol <= i && (BS || BC)) + i = j = outcol - destcol; /* cheaper to backspace */ + else + j = i + 1; /* impossibly expensive */ + + /* k is the absolute value of vertical distance */ + k = outline - destline; + if (k < 0) + k = -k; + j += k; + + /* + * Decision. We may not have a choice if no UP. + */ + if (i + destline < j || (!UP && destline < outline)) { + /* + * Cheaper to home. Do it now and pretend it's a + * regular local motion. + */ + tputs(HO, 0, plodput); + outcol = outline = 0; + } + else if (LL) { + /* + * Quickly consider homing down and moving from there. + * Assume cost of LL is 2. + */ + k = (LINES - 1) - destline; + if (i + k + 2 < j && (k<=0 || UP)) { + tputs(LL, 0, plodput); + outcol = 0; + outline = LINES - 1; + } + } + } + else + /* + * No home and no up means it's impossible. + */ + if (!UP && destline < outline) + return -1; + if (GT) + i = destcol % HARDTABS + destcol / HARDTABS; + else + i = destcol; +/* + if (BT && outcol > destcol && (j = (((outcol+7) & ~7) - destcol - 1) >> 3)) { + j *= (k = strlen(BT)); + if ((k += (destcol&7)) > 4) + j += 8 - (destcol&7); + else + j += k; + } + else +*/ + j = outcol - destcol; + /* + * If we will later need a \n which will turn into a \r\n by + * the system or the terminal, then don't bother to try to \r. + */ + if ((NONL || !_pfast) && outline < destline) + goto dontcr; + /* + * If the terminal will do a \r\n and there isn't room for it, + * then we can't afford a \r. + */ + if (NC && outline >= destline) + goto dontcr; + /* + * If it will be cheaper, or if we can't back up, then send + * a return preliminarily. + */ + if (j > i + 1 || (outcol > destcol && !BS && !BC)) { + /* + * BUG: this doesn't take the (possibly long) length + * of CR into account. + */ + if (CR) + tputs(CR, 0, plodput); + else + plodput('\r'); + if (NC) { + if (NL) + tputs(NL, 0, plodput); + else + plodput('\n'); + outline++; + } + outcol = 0; + } +dontcr: + while (outline < destline) { + outline++; + if (NL) + tputs(NL, 0, plodput); + else + plodput('\n'); + if (plodcnt < 0) + goto out; + if (NONL || _pfast == 0) + outcol = 0; + } + if (BT) + k = strlen(BT); + while (outcol > destcol) { + if (plodcnt < 0) + goto out; +/* + if (BT && outcol - destcol > k + 4) { + tputs(BT, 0, plodput); + outcol--; + outcol &= ~7; + continue; + } +*/ + outcol--; + if (BC) + tputs(BC, 0, plodput); + else + plodput('\b'); + } + while (outline > destline) { + outline--; + tputs(UP, 0, plodput); + if (plodcnt < 0) + goto out; + } + if (GT && destcol - outcol > 1) { + for (;;) { + i = tabcol(outcol, HARDTABS); + if (i > destcol) + break; + if (TA) + tputs(TA, 0, plodput); + else + plodput('\t'); + outcol = i; + } + if (destcol - outcol > 4 && i < COLS && (BC || BS)) { + if (TA) + tputs(TA, 0, plodput); + else + plodput('\t'); + outcol = i; + while (outcol > destcol) { + outcol--; + if (BC) + tputs(BC, 0, plodput); + else + plodput('\b'); + } + } + } + while (outcol < destcol) { + /* + * move one char to the right. We don't use ND space + * because it's better to just print the char we are + * moving over. + */ + if (_win != NULL) + if (plodflg) /* avoid a complex calculation */ + plodcnt--; + else { + i = curscr->_y[outline][outcol]; + if ((i&_STANDOUT) == (curscr->_flags&_STANDOUT)) + _putchar(i); + else + goto nondes; + } + else +nondes: + if (ND) + tputs(ND, 0, plodput); + else + plodput(' '); + outcol++; + if (plodcnt < 0) + goto out; + } +out: + if (plodflg) { + outcol = soutcol; + outline = soutline; + } + return(plodcnt); +} + +void +fgoto() +{ + reg char *cgp; + reg int l, c; + + if (destcol >= COLS) { + destline += destcol / COLS; + destcol %= COLS; + } + if (outcol >= COLS) { + l = (outcol + 1) / COLS; + outline += l; + outcol %= COLS; + if (AM == 0) { + while (l > 0) { + if (_pfast) { + if (CR) + _puts(CR); + else + _putchar('\r'); + } + if (NL) + _puts(NL); + else + _putchar('\n'); + l--; + } + outcol = 0; + } + if (outline > LINES - 1) { + destline -= outline - (LINES - 1); + outline = LINES - 1; + } + } + if (destline >= LINES) { + l = destline; + destline = LINES - 1; + if (outline < LINES - 1) { + c = destcol; + if (_pfast == 0 && !CA) + destcol = 0; + fgoto(); + destcol = c; + } + while (l >= LINES) { + /* + * The following linefeed (or simulation thereof) + * is supposed to scroll up the screen, since we + * are on the bottom line. We make the assumption + * that linefeed will scroll. If ns is in the + * capability list this won't work. We should + * probably have an sc capability but sf will + * generally take the place if it works. + * + * Superbee glitch: in the middle of the screen we + * have to use esc B (down) because linefeed screws up + * in "Efficient Paging" (what a joke) mode (which is + * essential in some SB's because CRLF mode puts garbage + * in at end of memory), but you must use linefeed to + * scroll since down arrow won't go past memory end. + * I turned this off after recieving Paul Eggert's + * Superbee description which wins better. + */ + if (NL /* && !XB */ && _pfast) + _puts(NL); + else + _putchar('\n'); + l--; + if (_pfast == 0) + outcol = 0; + } + } + if (destline < outline && !(CA || UP)) + destline = outline; + if (CA) { + cgp = tgoto(CM, destcol, destline); + if (plod(strlen(cgp)) > 0) + plod(0); + else + tputs(cgp, 0, _putchar); + } + else + plod(0); + outline = destline; + outcol = destcol; +} + +void +mvcur(ly, lx, y, x) + int ly, lx, y, x; +{ +#ifdef DEBUG + fprintf(outf, "MVCUR: moving cursor from (%d,%d) to (%d,%d)\n", ly, lx, y, x); +#endif + destcol = x; + destline = y; + outcol = lx; + outline = ly; + fgoto(); +} diff --git a/src/libcurses/cr_tty.c b/src/libcurses/cr_tty.c new file mode 100644 index 0000000..057c8b7 --- /dev/null +++ b/src/libcurses/cr_tty.c @@ -0,0 +1,197 @@ +/* + * Terminal initialization routines. + * + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "curses.ext" +#include +#include + +static bool *sflags[] = { + &AM, &BS, &DA, &DB, &EO, &HC, &HZ, &IN, &MI, + &MS, &NC, &NS, &OS, &UL, &XB, &XN, &XT, &XS, + &XX + }; + +static char *_PC, + **sstrs[] = { + &AL, &BC, &BT, &CD, &CE, &CL, &CM, &CR, &CS, + &DC, &DL, &DM, &DO, &ED, &EI, &K0, &K1, &K2, + &K3, &K4, &K5, &K6, &K7, &K8, &K9, &HO, &IC, + &IM, &IP, &KD, &KE, &KH, &KL, &KR, &KS, &KU, + &LL, &MA, &ND, &NL, &_PC, &RC, &SC, &SE, &SF, + &SO, &SR, &TA, &TE, &TI, &UC, &UE, &UP, &US, + &VB, &VS, &VE, &AL_PARM, &DL_PARM, &UP_PARM, + &DOWN_PARM, &LEFT_PARM, &RIGHT_PARM, + }; + +char _tspace[2048]; /* Space for capability strings */ + +static char *aoftspace; /* Address of _tspace for relocation */ + +static int destcol, destline; + +/* + * This routine does terminal type initialization routines, and + * calculation of flags at entry. It is almost entirely stolen from + * Bill Joy's ex version 2.6. + */ +short ospeed = -1; + +void +gettmode() +{ + if (ioctl(_tty_ch, TIOCGETP, &_tty) < 0) + return; + savetty(); + if (ioctl(_tty_ch, TIOCSETP, &_tty) < 0) + _tty.sg_flags = _res_flg; + ospeed = _tty.sg_ospeed; + _res_flg = _tty.sg_flags; + GT = ((_tty.sg_flags & XTABS) == 0); + NONL = ((_tty.sg_flags & CRMOD) == 0); + _tty.sg_flags &= ~XTABS; + ioctl(_tty_ch, TIOCSETP, &_tty); +# ifdef DEBUG + fprintf(outf, "GETTMODE: GT = %s\n", GT ? "TRUE" : "FALSE"); + fprintf(outf, "GETTMODE: NONL = %s\n", NONL ? "TRUE" : "FALSE"); + fprintf(outf, "GETTMODE: ospeed = %d\n", ospeed); +# endif +} + +/* + * This routine gets all the terminal flags from the termcap database + */ +static void +zap() +{ + register char *namp; + register bool **fp; + register char ***sp; +#ifdef DEBUG + register char *cp; +#endif + + namp = "ambsdadbeohchzinmimsncnsosulxbxnxtxsxx"; + fp = sflags; + do { + *(*fp++) = tgetflag(namp); +#ifdef DEBUG + fprintf(outf, "%2.2s = %s\n", namp, *fp[-1] ? "TRUE" : "FALSE"); +#endif + namp += 2; + } while (*namp); + namp = "albcbtcdceclcmcrcsdcdldmdoedeik0k1k2k3k4k5k6k7k8k9hoicimipkdkekhklkrkskullmandnlpcrcscsesfsosrtatetiucueupusvbvsveALDLUPDOLERI"; + sp = sstrs; + do { + *(*sp++) = tgetstr(namp, &aoftspace); +#ifdef DEBUG + fprintf(outf, "%2.2s = %s", namp, *sp[-1] == NULL ? "NULL\n" : "\""); + if (*sp[-1] != NULL) { + for (cp = *sp[-1]; *cp; cp++) + fprintf(outf, "%s", unctrl(*cp)); + fprintf(outf, "\"\n"); + } +#endif + namp += 2; + } while (*namp); + if (XS) + SO = SE = NULL; + else { + if (tgetnum("sg") > 0) + SO = NULL; + if (tgetnum("ug") > 0) + US = NULL; + if (!SO && US) { + SO = US; + SE = UE; + } + } +} + +int +setterm(type) + reg char *type; +{ + reg int unknown; + static char genbuf[1024]; +# ifdef TIOCGWINSZ + struct winsize win; +# endif + +# ifdef DEBUG + fprintf(outf, "SETTERM(\"%s\")\n", type); + fprintf(outf, "SETTERM: LINES = %d, COLS = %d\n", LINES, COLS); +# endif + if (type[0] == '\0') + type = "xx"; + unknown = FALSE; + if (tgetent(genbuf, type) != 1) { + unknown++; + strcpy(genbuf, "xx|dumb:"); + } +# ifdef DEBUG + fprintf(outf, "SETTERM: tty = %s\n", type); +# endif +# ifdef TIOCGWINSZ + if (ioctl(_tty_ch, TIOCGWINSZ, &win) >= 0) { + if (LINES == 0) + LINES = win.ws_row; + if (COLS == 0) + COLS = win.ws_col; + } +# endif + + if (LINES == 0) + LINES = tgetnum("li"); + if (LINES <= 5) + LINES = 24; + + if (COLS == 0) + COLS = tgetnum("co"); + if (COLS <= 4) + COLS = 80; + +# ifdef DEBUG + fprintf(outf, "SETTERM: LINES = %d, COLS = %d\n", LINES, COLS); +# endif + aoftspace = _tspace; + zap(); /* get terminal description */ + + /* + * Handle funny termcap capabilities + */ + if (CS && SC && RC) AL=DL=""; + if (AL_PARM && AL==NULL) AL=""; + if (DL_PARM && DL==NULL) DL=""; + if (IC && IM==NULL) IM=""; + if (IC && EI==NULL) EI=""; + if (!GT) BT=NULL; /* If we can't tab, we can't backtab either */ + + if (tgoto(CM, destcol, destline)[0] == 'O') + CA = FALSE, CM = 0; + else + CA = TRUE; + + PC = _PC ? _PC[0] : FALSE; + aoftspace = _tspace; + strncpy(ttytype, longname(genbuf, type), sizeof(ttytype) - 1); + ttytype[sizeof(ttytype) - 1] = '\0'; + if (unknown) + return ERR; + return OK; +} + +/* + * return a capability from termcap + */ +char * +getcap(name) +char *name; +{ + char *tgetstr(); + + return tgetstr(name, &aoftspace); +} diff --git a/src/libcurses/curses.c b/src/libcurses/curses.c new file mode 100644 index 0000000..625826d --- /dev/null +++ b/src/libcurses/curses.c @@ -0,0 +1,49 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +/* + * Define global variables + * + */ +#include "curses.h" + +bool _echoit = TRUE, /* set if stty indicates ECHO */ + _rawmode = FALSE,/* set if stty indicates RAW mode */ + My_term = FALSE,/* set if user specifies terminal type */ + _endwin = FALSE;/* set if endwin has been called */ + +char ttytype[50], /* long name of tty */ + *Def_term = "unknown"; /* default terminal type */ + +int _tty_ch = 1, /* file channel which is a tty */ + LINES, /* number of lines allowed on screen */ + COLS, /* number of columns allowed on screen */ + _res_flg; /* sgtty flags for reseting later */ + +WINDOW *stdscr = NULL, + *curscr = NULL; + +# ifdef DEBUG +FILE *outf; /* debug output file */ +# endif + +SGTTY _tty; /* tty modes */ + +bool AM, BS, CA, DA, DB, EO, HC, HZ, IN, MI, MS, NC, NS, OS, UL, XB, XN, + XT, XS, XX; +char *AL, *BC, *BT, *CD, *CE, *CL, *CM, *CR, *CS, *DC, *DL, *DM, + *DO, *ED, *EI, *K0, *K1, *K2, *K3, *K4, *K5, *K6, *K7, *K8, + *K9, *HO, *IC, *IM, *IP, *KD, *KE, *KH, *KL, *KR, *KS, *KU, + *LL, *MA, *ND, *NL, *RC, *SC, *SE, *SF, *SO, *SR, *TA, *TE, + *TI, *UC, *UE, *UP, *US, *VB, *VS, *VE, *AL_PARM, *DL_PARM, + *UP_PARM, *DOWN_PARM, *LEFT_PARM, *RIGHT_PARM; +char PC; + +/* + * From the tty modes... + */ + +bool GT, NONL, normtty, _pfast; diff --git a/src/libcurses/curses.ext b/src/libcurses/curses.ext new file mode 100644 index 0000000..502b983 --- /dev/null +++ b/src/libcurses/curses.ext @@ -0,0 +1,40 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + * + * @(#)curses.ext 5.2 (Berkeley) 6/19/85 + */ + +/* + * External variables for the curses library + */ + +/* LINTLIBRARY */ + +#include "curses.h" +#include + +extern bool _echoit, _rawmode, My_term, _endwin; + +extern char ttytype[50], *_unctrl[]; + +extern int _tty_ch, LINES, COLS; + +extern SGTTY _tty; + +int _putchar (int); +void _id_subwins (WINDOW *); +void gettmode (void); +void tstp (int); +int _sprintw (WINDOW *, char *, va_list); +int _sscans (WINDOW *, char *, int *); +void _swflags_ (WINDOW *); +void _set_subwin_ (WINDOW *, WINDOW *); +void mvcur (int, int, int, int); + +#ifdef DEBUG +# define outf _outf + +FILE *outf; +#endif diff --git a/src/libcurses/delch.c b/src/libcurses/delch.c new file mode 100644 index 0000000..49e56e9 --- /dev/null +++ b/src/libcurses/delch.c @@ -0,0 +1,27 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "curses.ext" + +/* + * This routine performs an insert-char on the line, leaving + * (_cury,_curx) unchanged. + */ +int +wdelch(win) + reg WINDOW *win; +{ + reg char *temp1, *temp2; + reg char *end; + + end = &win->_y[win->_cury][win->_maxx - 1]; + temp1 = &win->_y[win->_cury][win->_curx]; + temp2 = temp1 + 1; + while (temp1 < end) + *temp1++ = *temp2++; + *temp1 = ' '; + touchline(win, win->_cury, win->_curx, win->_maxx - 1); + return OK; +} diff --git a/src/libcurses/deleteln.c b/src/libcurses/deleteln.c new file mode 100644 index 0000000..44d948d --- /dev/null +++ b/src/libcurses/deleteln.c @@ -0,0 +1,42 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "curses.ext" +#include + +/* + * This routine deletes a line from the screen. It leaves + * (_cury,_curx) unchanged. + */ +int +wdeleteln(win) + reg WINDOW *win; +{ + reg char *temp; + reg int y; + reg char *end; + +# ifdef DEBUG + fprintf(outf, "DELETELN(%0.2o)\n", win); +# endif + temp = win->_y[win->_cury]; + for (y = win->_cury; y < win->_maxy - 1; y++) { + if (win->_orig == NULL) + win->_y[y] = win->_y[y + 1]; + else + bcopy(win->_y[y + 1], win->_y[y], win->_maxx); + touchline(win, y, 0, win->_maxx - 1); + } + if (win->_orig == NULL) + win->_y[y] = temp; + else + temp = win->_y[y]; + for (end = &temp[win->_maxx]; temp < end; ) + *temp++ = ' '; + touchline(win, win->_cury, 0, win->_maxx - 1); + if (win->_orig == NULL) + _id_subwins(win); + return OK; +} diff --git a/src/libcurses/delwin.c b/src/libcurses/delwin.c new file mode 100644 index 0000000..afb60d3 --- /dev/null +++ b/src/libcurses/delwin.c @@ -0,0 +1,48 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "curses.ext" +#include + +/* + * This routine deletes a window and releases it back to the system. + */ +int +delwin(win) + reg WINDOW *win; +{ + reg int i; + reg WINDOW *wp, *np; + + if (win->_orig == NULL) { + /* + * If we are the original window, delete the space for + * all the subwindows, and the array of space as well. + */ + for (i = 0; i < win->_maxy && win->_y[i]; i++) + free(win->_y[i]); + free(win->_firstch); + free(win->_lastch); + wp = win->_nextp; + while (wp != win) { + np = wp->_nextp; + delwin(wp); + wp = np; + } + } else { + /* + * If we are a subwindow, take ourselves out of the + * list. NOTE: if we are a subwindow, the minimum list + * is orig followed by this subwindow, so there are + * always at least two windows in the list. + */ + for (wp = win->_nextp; wp->_nextp != win; wp = wp->_nextp) + continue; + wp->_nextp = win->_nextp; + } + free(win->_y); + free(win); + return 0; +} diff --git a/src/libcurses/endwin.c b/src/libcurses/endwin.c new file mode 100644 index 0000000..9ad9d5d --- /dev/null +++ b/src/libcurses/endwin.c @@ -0,0 +1,23 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "curses.ext" + +/* + * Clean things up before exiting + */ +void endwin() +{ + resetty(); + _puts(VE); + _puts(TE); + if (curscr) { + if (curscr->_flags & _STANDOUT) { + _puts(SE); + curscr->_flags &= ~_STANDOUT; + } + _endwin = TRUE; + } +} diff --git a/src/libcurses/erase.c b/src/libcurses/erase.c new file mode 100644 index 0000000..53fba48 --- /dev/null +++ b/src/libcurses/erase.c @@ -0,0 +1,38 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "curses.ext" + +/* + * This routine erases everything on the window. + */ +void +werase(win) + reg WINDOW *win; +{ + reg int y; + reg char *sp, *end, *start, *maxx; + reg int minx; + +# ifdef DEBUG + fprintf(outf, "WERASE(%0.2o)\n", win); +# endif + for (y = 0; y < win->_maxy; y++) { + minx = _NOCHANGE; + maxx = 0; + start = win->_y[y]; + end = &start[win->_maxx]; + for (sp = start; sp < end; sp++) + if (*sp != ' ') { + maxx = sp; + if (minx == _NOCHANGE) + minx = sp - start; + *sp = ' '; + } + if (minx != _NOCHANGE) + touchline(win, y, minx, maxx - win->_y[y]); + } + win->_curx = win->_cury = 0; +} diff --git a/src/libcurses/fullname.c b/src/libcurses/fullname.c new file mode 100644 index 0000000..1c585f1 --- /dev/null +++ b/src/libcurses/fullname.c @@ -0,0 +1,33 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#define reg register + +/* + * This routine fills in "def" with the full name of the terminal. + * This is assumed to be the last name in the list of aliases. + * + */ +char * +fullname(bp, def) + reg char *bp, *def; +{ + + reg char *cp; + + *def = 0; /* in case no name */ + + while (*bp && *bp != ':') { + cp = def; /* start of answer */ + while (*bp && *bp != ':' && *bp != '|') { + *cp++ = *bp++; /* copy name over */ + } + *cp = 0; /* zero end of name */ + if (*bp == '|') { + bp++; /* skip over '|' if that is case */ + } + } + return(def); +} diff --git a/src/libcurses/getch.c b/src/libcurses/getch.c new file mode 100644 index 0000000..f3faee2 --- /dev/null +++ b/src/libcurses/getch.c @@ -0,0 +1,39 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "curses.ext" + +/* + * This routine reads in a character from the window. + */ +int wgetch(win) + reg WINDOW *win; +{ + reg bool weset = FALSE; + reg char inp; + + if (!win->_scroll && (win->_flags&_FULLWIN) + && win->_curx == win->_maxx - 1 && win->_cury == win->_maxy - 1) + return ERR; +# ifdef DEBUG + fprintf(outf, "WGETCH: _echoit = %c, _rawmode = %c\n", _echoit ? 'T' : 'F', _rawmode ? 'T' : 'F'); +# endif + if (_echoit && !_rawmode) { + cbreak(); + weset++; + } + inp = getchar(); +# ifdef DEBUG + fprintf(outf,"WGETCH got '%s'\n",unctrl(inp)); +# endif + if (_echoit) { + mvwaddch(curscr, win->_cury + win->_begy, + win->_curx + win->_begx, inp); + waddch(win, inp); + } + if (weset) + nocbreak(); + return inp; +} diff --git a/src/libcurses/getstr.c b/src/libcurses/getstr.c new file mode 100644 index 0000000..3efc1ef --- /dev/null +++ b/src/libcurses/getstr.c @@ -0,0 +1,24 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "curses.ext" + +/* + * This routine gets a string starting at (_cury,_curx) + */ +int +wgetstr(win, str) + reg WINDOW *win; + reg char *str; +{ + while ((*str = wgetch(win)) != ERR && *str != '\n') + str++; + if (*str == ERR) { + *str = '\0'; + return ERR; + } + *str = '\0'; + return OK; +} diff --git a/src/libcurses/id_subwins.c b/src/libcurses/id_subwins.c new file mode 100644 index 0000000..33e4b14 --- /dev/null +++ b/src/libcurses/id_subwins.c @@ -0,0 +1,33 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "curses.ext" + +/* + * _id_subwins: + * Re-sync the pointers to _y for all the subwindows. + */ +void +_id_subwins(orig) + register WINDOW *orig; +{ + register WINDOW *win; + register int realy; + register int y, oy; + + realy = orig->_begy + orig->_cury; + for (win = orig->_nextp; win != orig; win = win->_nextp) { + /* + * If the window ends before our current position, + * don't need to do anything. + */ + if (win->_begy + win->_maxy <= realy) + continue; + + oy = orig->_cury; + for (y = realy - win->_begy; y < win->_maxy; y++, oy++) + win->_y[y] = &orig->_y[oy][win->_ch_off]; + } +} diff --git a/src/libcurses/idlok.c b/src/libcurses/idlok.c new file mode 100644 index 0000000..4885be7 --- /dev/null +++ b/src/libcurses/idlok.c @@ -0,0 +1,22 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "curses.ext" + +/* + * idlok: + * Turn on and off using insert/deleteln sequences for the given + * window. + */ +void +idlok(win, bf) + register WINDOW *win; + bool bf; +{ + if (bf) + win->_flags |= _IDLINE; + else + win->_flags &= ~_IDLINE; +} diff --git a/src/libcurses/initscr.c b/src/libcurses/initscr.c new file mode 100644 index 0000000..364955f --- /dev/null +++ b/src/libcurses/initscr.c @@ -0,0 +1,65 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "curses.ext" +#include +#include +#include + +/* + * This routine initializes the current and standard screen. + */ +WINDOW * +initscr() +{ + reg char *sp; + int nfd; + +# ifdef DEBUG + fprintf(outf, "INITSCR()\n"); +# endif + if (My_term) + setterm(Def_term); + else { + nfd = getdtablesize(); + for (_tty_ch = 0; _tty_ch < nfd; _tty_ch++) + if (isatty(_tty_ch)) + break; + gettmode(); + sp = getenv("TERM"); + if (! sp) + sp = Def_term; + setterm(sp); +# ifdef DEBUG + fprintf(outf, "INITSCR: term = %s\n", sp); +# endif + } + _puts(TI); + _puts(VS); +# ifdef SIGTSTP + signal(SIGTSTP, (sig_t)tstp); +# endif + if (curscr != NULL) { +# ifdef DEBUG + fprintf(outf, "INITSCR: curscr = 0%o\n", curscr); +# endif + delwin(curscr); + } +# ifdef DEBUG + fprintf(outf, "LINES = %d, COLS = %d\n", LINES, COLS); +# endif + if ((curscr = newwin(LINES, COLS, 0, 0)) == ERR) + return ERR; + clearok(curscr, TRUE); + curscr->_flags &= ~_FULLLINE; + if (stdscr != NULL) { +# ifdef DEBUG + fprintf(outf, "INITSCR: stdscr = 0%o\n", stdscr); +# endif + delwin(stdscr); + } + stdscr = newwin(LINES, COLS, 0, 0); + return stdscr; +} diff --git a/src/libcurses/insch.c b/src/libcurses/insch.c new file mode 100644 index 0000000..9be2439 --- /dev/null +++ b/src/libcurses/insch.c @@ -0,0 +1,35 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "curses.ext" + +/* + * This routine performs an insert-char on the line, leaving + * (_cury,_curx) unchanged. + */ +int +winsch(win, c) + reg WINDOW *win; + char c; +{ + reg char *temp1, *temp2; + reg char *end; + + end = &win->_y[win->_cury][win->_curx]; + temp1 = &win->_y[win->_cury][win->_maxx - 1]; + temp2 = temp1 - 1; + while (temp1 > end) + *temp1-- = *temp2--; + *temp1 = c; + touchline(win, win->_cury, win->_curx, win->_maxx - 1); + if (win->_cury == LINES - 1 && win->_y[LINES-1][COLS-1] != ' ') { + if (! win->_scroll) + return ERR; + wrefresh(win); + scroll(win); + win->_cury--; + } + return OK; +} diff --git a/src/libcurses/insertln.c b/src/libcurses/insertln.c new file mode 100644 index 0000000..9f284b5 --- /dev/null +++ b/src/libcurses/insertln.c @@ -0,0 +1,42 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "curses.ext" +#include + +/* + * This routine performs an insert-line on the window, leaving + * (_cury,_curx) unchanged. + */ +void +winsertln(win) + reg WINDOW *win; +{ + reg char *temp = 0; + reg int y; + reg char *end; + +#ifdef DEBUG + fprintf(outf, "INSERTLN(%0.2o)\n", win); +#endif + if (win->_orig == NULL) + temp = win->_y[win->_maxy - 1]; + for (y = win->_maxy - 1; y > win->_cury; --y) { + if (win->_orig == NULL) + win->_y[y] = win->_y[y - 1]; + else + bcopy(win->_y[y - 1], win->_y[y], win->_maxx); + touchline(win, y, 0, win->_maxx - 1); + } + if (win->_orig == NULL) + win->_y[y] = temp; + else + temp = win->_y[y]; + for (end = &temp[win->_maxx]; temp < end; ) + *temp++ = ' '; + touchline(win, y, 0, win->_maxx - 1); + if (win->_orig == NULL) + _id_subwins(win); +} diff --git a/src/libcurses/longname.c b/src/libcurses/longname.c new file mode 100644 index 0000000..a15e67d --- /dev/null +++ b/src/libcurses/longname.c @@ -0,0 +1,27 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#define reg register + +/* + * This routine fills in "def" with the long name of the terminal. + */ +char * +longname(bp, def) + reg char *bp, *def; +{ + reg char *cp; + + while (*bp && *bp != ':' && *bp != '|') + bp++; + if (*bp == '|') { + bp++; + cp = def; + while (*bp && *bp != ':' && *bp != '|') + *cp++ = *bp++; + *cp = 0; + } + return def; +} diff --git a/src/libcurses/move.c b/src/libcurses/move.c new file mode 100644 index 0000000..e45523c --- /dev/null +++ b/src/libcurses/move.c @@ -0,0 +1,25 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "curses.ext" + +/* + * This routine moves the cursor to the given point + */ +int wmove(win, y, x) + reg WINDOW *win; + reg int y, x; +{ +#ifdef DEBUG + fprintf(outf, "MOVE to (%d, %d)\n", y, x); +#endif + if (x < 0 || y < 0) + return ERR; + if (x >= win->_maxx || y >= win->_maxy) + return ERR; + win->_curx = x; + win->_cury = y; + return OK; +} diff --git a/src/libcurses/mvprintw.c b/src/libcurses/mvprintw.c new file mode 100644 index 0000000..1766cff --- /dev/null +++ b/src/libcurses/mvprintw.c @@ -0,0 +1,30 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "curses.ext" + +/* + * implement the mvprintw commands. Due to the variable number of + * arguments, they cannot be macros. Sigh.... + * + */ +int +mvprintw(y, x, fmt, args) + reg int y, x; + char *fmt; + int args; +{ + return move(y, x) == OK ? _sprintw(stdscr, fmt, &args) : ERR; +} + +int +mvwprintw(win, y, x, fmt, args) + reg WINDOW *win; + reg int y, x; + char *fmt; + int args; +{ + return wmove(win, y, x) == OK ? _sprintw(win, fmt, &args) : ERR; +} diff --git a/src/libcurses/mvscanw.c b/src/libcurses/mvscanw.c new file mode 100644 index 0000000..ec7d5ac --- /dev/null +++ b/src/libcurses/mvscanw.c @@ -0,0 +1,29 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "curses.ext" + +/* + * implement the mvscanw commands. Due to the variable number of + * arguments, they cannot be macros. Another sigh.... + */ +int +mvscanw(y, x, fmt, args) + reg int y, x; + char *fmt; + int args; +{ + return move(y, x) == OK ? _sscans(stdscr, fmt, &args) : ERR; +} + +int +mvwscanw(win, y, x, fmt, args) + reg WINDOW *win; + reg int y, x; + char *fmt; + int args; +{ + return wmove(win, y, x) == OK ? _sscans(win, fmt, &args) : ERR; +} diff --git a/src/libcurses/mvwin.c b/src/libcurses/mvwin.c new file mode 100644 index 0000000..b729133 --- /dev/null +++ b/src/libcurses/mvwin.c @@ -0,0 +1,45 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "curses.ext" + +/* + * relocate the starting position of a window + */ +int +mvwin(win, by, bx) + reg WINDOW *win; + reg int by, bx; +{ + register WINDOW *orig; + register int dy, dx; + + if (by + win->_maxy > LINES || bx + win->_maxx > COLS) + return ERR; + dy = by - win->_begy; + dx = bx - win->_begx; + orig = win->_orig; + if (orig == NULL) { + orig = win; + do { + win->_begy += dy; + win->_begx += dx; + _swflags_(win); + win = win->_nextp; + } while (win != orig); + } + else { + if (by < orig->_begy || win->_maxy + dy > orig->_maxy) + return ERR; + if (bx < orig->_begx || win->_maxx + dx > orig->_maxx) + return ERR; + win->_begy = by; + win->_begx = bx; + _swflags_(win); + _set_subwin_(orig, win); + } + touchwin(win); + return OK; +} diff --git a/src/libcurses/newwin.c b/src/libcurses/newwin.c new file mode 100644 index 0000000..86df112 --- /dev/null +++ b/src/libcurses/newwin.c @@ -0,0 +1,199 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +/* + * allocate space for and set up defaults for a new window + * + */ +#include "curses.ext" +#include + +#define SMALLOC (short*)malloc + +#undef nl /* don't need it here, and it interferes */ + +/* + * This routine sets up a window buffer and returns a pointer to it. + */ +static WINDOW * +makenew(num_lines, num_cols, begy, begx) + int num_lines, num_cols, begy, begx; +{ + reg WINDOW *win; + reg int by, bx, nl, nc; + + by = begy; + bx = begx; + nl = num_lines; + nc = num_cols; + +# ifdef DEBUG + fprintf(outf, "MAKENEW(%d, %d, %d, %d)\n", nl, nc, by, bx); +# endif + if ((win = (WINDOW *) malloc(sizeof *win)) == NULL) + return NULL; +# ifdef DEBUG + fprintf(outf, "MAKENEW: nl = %d\n", nl); +# endif + if ((win->_y = (char **) malloc(nl * sizeof win->_y[0])) == NULL) { + free(win); + return NULL; + } +# ifdef DEBUG + fprintf(outf, "MAKENEW: nc = %d\n", nc); +# endif + win->_cury = win->_curx = 0; + win->_clear = FALSE; + win->_maxy = nl; + win->_maxx = nc; + win->_begy = by; + win->_begx = bx; + win->_flags = 0; + win->_scroll = win->_leave = FALSE; + _swflags_(win); +# ifdef DEBUG + fprintf(outf, "MAKENEW: win->_clear = %d\n", win->_clear); + fprintf(outf, "MAKENEW: win->_leave = %d\n", win->_leave); + fprintf(outf, "MAKENEW: win->_scroll = %d\n", win->_scroll); + fprintf(outf, "MAKENEW: win->_flags = %0.2o\n", win->_flags); + fprintf(outf, "MAKENEW: win->_maxy = %d\n", win->_maxy); + fprintf(outf, "MAKENEW: win->_maxx = %d\n", win->_maxx); + fprintf(outf, "MAKENEW: win->_begy = %d\n", win->_begy); + fprintf(outf, "MAKENEW: win->_begx = %d\n", win->_begx); +# endif + return win; +} + +WINDOW * +newwin(num_lines, num_cols, begy, begx) + int num_lines, num_cols, begy, begx; +{ + reg WINDOW *win; + reg char *sp; + reg int i, by, bx, nl, nc; + reg int j; + + by = begy; + bx = begx; + nl = num_lines; + nc = num_cols; + + if (nl == 0) + nl = LINES - by; + if (nc == 0) + nc = COLS - bx; + if ((win = makenew(nl, nc, by, bx)) == NULL) + return ERR; + if ((win->_firstch = SMALLOC(nl * sizeof win->_firstch[0])) == NULL) { + free(win->_y); + free(win); + return NULL; + } + if ((win->_lastch = SMALLOC(nl * sizeof win->_lastch[0])) == NULL) { + free(win->_y); + free(win->_firstch); + free(win); + return NULL; + } + win->_nextp = win; + for (i = 0; i < nl; i++) { + win->_firstch[i] = _NOCHANGE; + win->_lastch[i] = _NOCHANGE; + } + for (i = 0; i < nl; i++) + if ((win->_y[i] = malloc(nc * sizeof win->_y[0])) == NULL) { + for (j = 0; j < i; j++) + free(win->_y[j]); + free(win->_firstch); + free(win->_lastch); + free(win->_y); + free(win); + return ERR; + } + else + for (sp = win->_y[i]; sp < win->_y[i] + nc; ) + *sp++ = ' '; + win->_ch_off = 0; +# ifdef DEBUG + fprintf(outf, "NEWWIN: win->_ch_off = %d\n", win->_ch_off); +# endif + return win; +} + +WINDOW * +subwin(orig, num_lines, num_cols, begy, begx) + reg WINDOW *orig; + int num_lines, num_cols, begy, begx; +{ + reg WINDOW *win; + reg int by, bx, nl, nc; + + by = begy; + bx = begx; + nl = num_lines; + nc = num_cols; + + /* + * make sure window fits inside the original one + */ +# ifdef DEBUG + fprintf(outf, "SUBWIN(%0.2o, %d, %d, %d, %d)\n", orig, nl, nc, by, bx); +# endif + if (by < orig->_begy || bx < orig->_begx + || by + nl > orig->_maxy + orig->_begy + || bx + nc > orig->_maxx + orig->_begx) + return ERR; + if (nl == 0) + nl = orig->_maxy + orig->_begy - by; + if (nc == 0) + nc = orig->_maxx + orig->_begx - bx; + if ((win = makenew(nl, nc, by, bx)) == NULL) + return ERR; + win->_nextp = orig->_nextp; + orig->_nextp = win; + win->_orig = orig; + _set_subwin_(orig, win); + return win; +} + +/* + * this code is shared with mvwin() + */ +void +_set_subwin_(orig, win) + register WINDOW *orig, *win; +{ + register int i, j, k; + + j = win->_begy - orig->_begy; + k = win->_begx - orig->_begx; + win->_ch_off = k; +# ifdef DEBUG + fprintf(outf, "_SET_SUBWIN_: win->_ch_off = %d\n", win->_ch_off); +# endif + win->_firstch = &orig->_firstch[j]; + win->_lastch = &orig->_lastch[j]; + for (i = 0; i < win->_maxy; i++, j++) + win->_y[i] = &orig->_y[j][k]; +} + +void +_swflags_(win) + register WINDOW *win; +{ + win->_flags &= ~(_ENDLINE|_FULLLINE|_FULLWIN|_SCROLLWIN); + if (win->_begx + win->_maxx == COLS) { + win->_flags |= _ENDLINE; + if (win->_begx == 0) { + if (AL && DL) + win->_flags |= _FULLLINE; + if (win->_maxy == LINES && win->_begy == 0) + win->_flags |= _FULLWIN; + } + if (win->_begy + win->_maxy == LINES) + win->_flags |= _SCROLLWIN; + } +} diff --git a/src/libcurses/overlay.c b/src/libcurses/overlay.c new file mode 100644 index 0000000..9e4e88d --- /dev/null +++ b/src/libcurses/overlay.c @@ -0,0 +1,54 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "curses.ext" +#include +#include + +#define min(a,b) (a < b ? a : b) +#define max(a,b) (a > b ? a : b) + +/* + * This routine writes win1 on win2 non-destructively. + */ +void +overlay(win1, win2) + reg WINDOW *win1, *win2; +{ + + reg char *sp, *end; + reg int x, y, endy, endx, starty, startx; + reg int y1,y2; + +# ifdef DEBUG + fprintf(outf, "OVERLAY(%0.2o, %0.2o);\n", win1, win2); +# endif + starty = max(win1->_begy, win2->_begy); + startx = max(win1->_begx, win2->_begx); + endy = min(win1->_maxy + win1->_begy, win2->_maxy + win2->_begx); + endx = min(win1->_maxx + win1->_begx, win2->_maxx + win2->_begx); +# ifdef DEBUG + fprintf(outf, "OVERLAY:from (%d,%d) to (%d,%d)\n", starty, startx, endy, endx); +# endif + if (starty >= endy || startx >= endx) + return; + x = endx - startx; + for (y = starty; y < endy; y++) { + bcopy(&win1->_y[y - win1->_begy][startx - win1->_begx], + &win2->_y[y - win2->_begy][startx - win2->_begx], x); + touchline(win2, y, startx - win2->_begx, endx - win2->_begx); + } + y1 = starty - win1->_begy; + y2 = starty - win2->_begy; + for (y = starty; y < endy; y++, y1++, y2++) { + end = &win1->_y[y1][endx - win1->_begx]; + x = startx - win2->_begx; + for (sp = &win1->_y[y1][startx - win1->_begx]; sp < end; sp++) { + if (!isspace(*sp)) + mvwaddch(win2, y2, x, *sp); + x++; + } + } +} diff --git a/src/libcurses/overwrite.c b/src/libcurses/overwrite.c new file mode 100644 index 0000000..28daf81 --- /dev/null +++ b/src/libcurses/overwrite.c @@ -0,0 +1,40 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "curses.ext" +#include +#include + +#define min(a,b) (a < b ? a : b) +#define max(a,b) (a > b ? a : b) + +/* + * This routine writes win1 on win2 destructively. + */ +void +overwrite(win1, win2) + reg WINDOW *win1, *win2; +{ + reg int x, y, endy, endx, starty, startx; + +# ifdef DEBUG + fprintf(outf, "OVERWRITE(%0.2o, %0.2o);\n", win1, win2); +# endif + starty = max(win1->_begy, win2->_begy); + startx = max(win1->_begx, win2->_begx); + endy = min(win1->_maxy + win1->_begy, win2->_maxy + win2->_begx); + endx = min(win1->_maxx + win1->_begx, win2->_maxx + win2->_begx); + if (starty >= endy || startx >= endx) + return; +# ifdef DEBUG + fprintf(outf, "OVERWRITE:from (%d,%d) to (%d,%d)\n", starty, startx, endy, endx); +# endif + x = endx - startx; + for (y = starty; y < endy; y++) { + bcopy(&win1->_y[y - win1->_begy][startx - win1->_begx], + &win2->_y[y - win2->_begy][startx - win2->_begx], x); + touchline(win2, y, startx - win2->_begx, endx - win2->_begx); + } +} diff --git a/src/libcurses/printw.c b/src/libcurses/printw.c new file mode 100644 index 0000000..6fcbae1 --- /dev/null +++ b/src/libcurses/printw.c @@ -0,0 +1,58 @@ +/* + * printw and friends + * + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "curses.ext" + +/* + * This routine actually executes the printf and adds it to the window + * + * This is really a modified version of "sprintf". As such, + * it assumes that sprintf interfaces with the other printf functions + * in a certain way. If this is not how your system works, you + * will have to modify this routine to use the interface that your + * "sprintf" uses. + */ +int _sprintw (WINDOW *win, char *fmt, va_list args) +{ + FILE junk; + char buf[512]; + + junk._flag = _IOWRT + _IOSTRG; + junk._ptr = buf; + junk._cnt = 32767; + _doprnt(fmt, args, &junk); + putc('\0', &junk); + return waddstr(win, buf); +} + +/* + * This routine implements a printf on the standard screen. + */ +int printw (char *fmt, ...) +{ + va_list args; + int ret; + + va_start (args, fmt); + ret = _sprintw (stdscr, fmt, args); + va_end (args); + return ret; +} + +/* + * This routine implements a printf on the given window. + */ +int wprintw (WINDOW *win, char *fmt, ...) +{ + va_list args; + int ret; + + va_start (args, fmt); + ret = _sprintw (win, fmt, &args); + va_end (args); + return ret; +} diff --git a/src/libcurses/putchar.c b/src/libcurses/putchar.c new file mode 100644 index 0000000..9859bd1 --- /dev/null +++ b/src/libcurses/putchar.c @@ -0,0 +1,17 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "curses.ext" + +int +_putchar(c) + reg int c; +{ + putchar(c); +#ifdef DEBUG + fprintf(outf, "_PUTCHAR(%s)\n", unctrl(c)); +#endif + return 0; +} diff --git a/src/libcurses/refresh.c b/src/libcurses/refresh.c new file mode 100644 index 0000000..783a4fc --- /dev/null +++ b/src/libcurses/refresh.c @@ -0,0 +1,302 @@ +/* + * make the current screen look like "win" over the area coverd by + * win. + * + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include +#include "curses.ext" + +#ifdef DEBUG +# define STATIC +#else +# define STATIC static +#endif + +STATIC short ly, lx; + +STATIC bool curwin; + +WINDOW *_win = NULL; + +/* + * perform a mvcur, leaving standout mode if necessary + */ +STATIC void +domvcur(oy, ox, ny, nx) + int oy, ox, ny, nx; +{ + if (curscr->_flags & _STANDOUT && !MS) { + _puts(SE); + curscr->_flags &= ~_STANDOUT; + } + mvcur(oy, ox, ny, nx); +} + +/* + * make a change on the screen + */ +STATIC int +makech(win, wy) +reg WINDOW *win; +short wy; +{ + reg char *nsp, *csp, *ce; + reg short wx, lch, y; + reg int nlsp = 0, clsp; /* last space in lines */ + + wx = win->_firstch[wy] - win->_ch_off; + if (wx >= win->_maxx) + return OK; + else if (wx < 0) + wx = 0; + lch = win->_lastch[wy] - win->_ch_off; + if (lch < 0) + return OK; + else if (lch >= win->_maxx) + lch = win->_maxx - 1;; + y = wy + win->_begy; + + if (curwin) + csp = " "; + else + csp = &curscr->_y[wy + win->_begy][wx + win->_begx]; + + nsp = &win->_y[wy][wx]; + if (CE && !curwin) { + for (ce = &win->_y[wy][win->_maxx - 1]; *ce == ' '; ce--) + if (ce <= win->_y[wy]) + break; + nlsp = ce - win->_y[wy]; + } + + if (!curwin) + ce = CE; + else + ce = NULL; + + while (wx <= lch) { + if (*nsp != *csp) { + domvcur(ly, lx, y, wx + win->_begx); +# ifdef DEBUG + fprintf(outf, "MAKECH: 1: wx = %d, lx = %d\n", wx, lx); +# endif + ly = y; + lx = wx + win->_begx; + while (*nsp != *csp && wx <= lch) { + if (ce != NULL && wx >= nlsp && *nsp == ' ') { + /* + * check for clear to end-of-line + */ + ce = &curscr->_y[ly][COLS - 1]; + while (*ce == ' ') + if (ce-- <= csp) + break; + clsp = ce - curscr->_y[ly] - win->_begx; +# ifdef DEBUG + fprintf(outf, "MAKECH: clsp = %d, nlsp = %d\n", clsp, nlsp); +# endif + if (clsp - nlsp >= strlen(CE) + && clsp < win->_maxx) { +# ifdef DEBUG + fprintf(outf, "MAKECH: using CE\n"); +# endif + _puts(CE); + lx = wx + win->_begx; + while (wx++ <= clsp) + *csp++ = ' '; + return OK; + } + ce = NULL; + } + /* + * enter/exit standout mode as appropriate + */ + if (SO && (*nsp&_STANDOUT) != (curscr->_flags&_STANDOUT)) { + if (*nsp & _STANDOUT) { + _puts(SO); + curscr->_flags |= _STANDOUT; + } + else { + _puts(SE); + curscr->_flags &= ~_STANDOUT; + } + } + wx++; + if (wx >= win->_maxx && wy == win->_maxy - 1) { + if (win->_scroll) { + if ((curscr->_flags&_STANDOUT) && + (win->_flags & _ENDLINE)) + if (!MS) { + _puts(SE); + curscr->_flags &= ~_STANDOUT; + } + if (!curwin) + _putchar((*csp = *nsp) & 0177); + else + _putchar(*nsp & 0177); + if (win->_flags&_FULLWIN && !curwin) + scroll(curscr); + ly = win->_begy+win->_cury; + lx = win->_begx+win->_curx; + return OK; + } + else if (win->_flags&_SCROLLWIN) { + lx = --wx; + return ERR; + } + } + if (!curwin) + _putchar((*csp++ = *nsp) & 0177); + else + _putchar(*nsp & 0177); +# ifdef FULLDEBUG + fprintf(outf, + "MAKECH:putchar(%c)\n", *nsp & 0177); +# endif + if (UC && (*nsp & _STANDOUT)) { + _putchar('\b'); + _puts(UC); + } + nsp++; + } +# ifdef DEBUG + fprintf(outf, "MAKECH: 2: wx = %d, lx = %d\n", wx, lx); +# endif + if (lx == wx + win->_begx) /* if no change */ + break; + lx = wx + win->_begx; + if (lx >= COLS && AM) { + lx = 0; + ly++; + /* + * xn glitch: chomps a newline after auto-wrap. + * we just feed it now and forget about it. + */ + if (XN) { + _putchar('\n'); + _putchar('\r'); + } + } + } + else if (wx <= lch) + while (*nsp == *csp && wx <= lch) { + nsp++; + if (!curwin) + csp++; + ++wx; + } + else + break; +# ifdef DEBUG + fprintf(outf, "MAKECH: 3: wx = %d, lx = %d\n", wx, lx); +# endif + } + return OK; +} + +int wrefresh(win) + reg WINDOW *win; +{ + reg short wy; + reg int retval; + + /* + * make sure were in visual state + */ + if (_endwin) { + _puts(VS); + _puts(TI); + _endwin = FALSE; + } + + /* + * initialize loop parameters + */ + + ly = curscr->_cury; + lx = curscr->_curx; + wy = 0; + _win = win; + curwin = (win == curscr); + + if (win->_clear || curscr->_clear || curwin) { + if ((win->_flags & _FULLWIN) || curscr->_clear) { + _puts(CL); + ly = 0; + lx = 0; + if (!curwin) { + curscr->_clear = FALSE; + curscr->_cury = 0; + curscr->_curx = 0; + werase(curscr); + } + touchwin(win); + } + win->_clear = FALSE; + } + if (!CA) { + if (win->_curx != 0) + _putchar('\n'); + if (!curwin) + werase(curscr); + } +# ifdef DEBUG + fprintf(outf, "REFRESH(%0.2o): curwin = %d\n", win, curwin); + fprintf(outf, "REFRESH:\n\tfirstch\tlastch\n"); +# endif + for (wy = 0; wy < win->_maxy; wy++) { +# ifdef DEBUG + fprintf(outf, "%d\t%d\t%d\n", wy, win->_firstch[wy], + win->_lastch[wy]); +# endif + if (win->_firstch[wy] != _NOCHANGE) { + if (makech(win, wy) == ERR) + return ERR; + else { + if (win->_firstch[wy] >= win->_ch_off) + win->_firstch[wy] = win->_maxx + + win->_ch_off; + if (win->_lastch[wy] < win->_maxx + + win->_ch_off) + win->_lastch[wy] = win->_ch_off; + if (win->_lastch[wy] < win->_firstch[wy]) + win->_firstch[wy] = _NOCHANGE; + } + } +# ifdef DEBUG + fprintf(outf, "\t%d\t%d\n", win->_firstch[wy], + win->_lastch[wy]); +# endif + } + + if (win == curscr) + domvcur(ly, lx, win->_cury, win->_curx); + else { + if (win->_leave) { + curscr->_cury = ly; + curscr->_curx = lx; + ly -= win->_begy; + lx -= win->_begx; + if (ly >= 0 && ly < win->_maxy && lx >= 0 && + lx < win->_maxx) { + win->_cury = ly; + win->_curx = lx; + } + else + win->_cury = win->_curx = 0; + } + else { + domvcur(ly, lx, win->_cury + win->_begy, + win->_curx + win->_begx); + curscr->_cury = win->_cury + win->_begy; + curscr->_curx = win->_curx + win->_begx; + } + } + retval = OK; + _win = NULL; + fflush(stdout); + return retval; +} diff --git a/src/libcurses/scanw.c b/src/libcurses/scanw.c new file mode 100644 index 0000000..0c2a18e --- /dev/null +++ b/src/libcurses/scanw.c @@ -0,0 +1,60 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +/* + * scanw and friends + * + */ +#include +#include "curses.ext" + +/* + * This routine implements a scanf on the standard screen. + */ +int +scanw(fmt, args) + char *fmt; + int args; +{ + return _sscans(stdscr, fmt, &args); +} +/* + * This routine implements a scanf on the given window. + */ +int +wscanw(win, fmt, args) + WINDOW *win; + char *fmt; + int args; +{ + return _sscans(win, fmt, &args); +} + +/* + * This routine actually executes the scanf from the window. + * + * This is really a modified version of "sscanf". As such, + * it assumes that sscanf interfaces with the other scanf functions + * in a certain way. If this is not how your system works, you + * will have to modify this routine to use the interface that your + * "sscanf" uses. + */ +int +_sscans(win, fmt, args) + WINDOW *win; + char *fmt; + int *args; +{ + char buf[100]; + FILE junk; + + junk._flag = _IOREAD|_IOSTRG; + junk._base = junk._ptr = buf; + if (wgetstr(win, buf) == ERR) + return ERR; + junk._cnt = strlen(buf); + return _doscan(&junk, fmt, args); +} diff --git a/src/libcurses/scroll.c b/src/libcurses/scroll.c new file mode 100644 index 0000000..0c2292f --- /dev/null +++ b/src/libcurses/scroll.c @@ -0,0 +1,38 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "curses.ext" + +/* + * This routine scrolls the window up a line. + */ +int +scroll(win) + register WINDOW *win; +{ + register int oy, ox; + +# ifdef DEBUG + fprintf(outf, "SCROLL(%0.2o)\n", win); +# endif + + if (! win->_scroll) + return ERR; + + getyx(win, oy, ox); + wmove(win, 0, 0); + wdeleteln(win); + wmove(win, oy, ox); + + if (win == curscr) { + _putchar('\n'); + if (!NONL) + win->_curx = 0; +# ifdef DEBUG + fprintf(outf, "SCROLL: win == curscr\n"); +# endif + } + return OK; +} diff --git a/src/libcurses/standout.c b/src/libcurses/standout.c new file mode 100644 index 0000000..ff2fade --- /dev/null +++ b/src/libcurses/standout.c @@ -0,0 +1,36 @@ +/* + * routines dealing with entering and exiting standout mode + * + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "curses.ext" + +/* + * enter standout mode + */ +char * +wstandout(win) + reg WINDOW *win; +{ + if (!SO && !UC) + return FALSE; + + win->_flags |= _STANDOUT; + return (SO ? SO : UC); +} + +/* + * exit standout mode + */ +char * +wstandend(win) + reg WINDOW *win; +{ + if (!SO && !UC) + return FALSE; + + win->_flags &= ~_STANDOUT; + return (SE ? SE : UC); +} diff --git a/src/libcurses/test.c b/src/libcurses/test.c new file mode 100644 index 0000000..b639bde --- /dev/null +++ b/src/libcurses/test.c @@ -0,0 +1,26 @@ +#include + +#define YPOSBOX 0 +#define XPOSBOX 0 +#define YBOX 20 +#define XBOX 80 + +#define YPOSSBOX 2 +#define XPOSSBOX 10 +#define YSBOX 17 +#define XSBOX 66 + +WINDOW *boxing,*sub_box; +main() +{ + boxing = newwin(YBOX,XBOX,YPOSBOX,XPOSBOX); + sub_box = subwin(boxing,YSBOX,XSBOX,YPOSSBOX,XPOSSBOX); + initscr(); + box(boxing,'|','-'); + wrefresh(boxing); + box(sub_box,'.','.'); + overlay(sub_box,boxing);/* overlays sub_box on top of boxing */ + wrefresh(sub_box); + mvcur(0,COLS-1,LINES-1,0); /* move to bottom of screen */ + endwin(); +} diff --git a/src/libcurses/toucholap.c b/src/libcurses/toucholap.c new file mode 100644 index 0000000..e7d5cf3 --- /dev/null +++ b/src/libcurses/toucholap.c @@ -0,0 +1,41 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "curses.ext" + +#define min(a,b) (a < b ? a : b) +#define max(a,b) (a > b ? a : b) + +/* + * Touch, on win2, the part that overlaps with win1. + */ +void +touchoverlap(win1, win2) + reg WINDOW *win1, *win2; +{ + reg int y, endy, endx, starty, startx; + +# ifdef DEBUG + fprintf(outf, "TOUCHOVERLAP(%0.2o, %0.2o);\n", win1, win2); +# endif + starty = max(win1->_begy, win2->_begy); + startx = max(win1->_begx, win2->_begx); + endy = min(win1->_maxy + win1->_begy, win2->_maxy + win2->_begx); + endx = min(win1->_maxx + win1->_begx, win2->_maxx + win2->_begx); +# ifdef DEBUG + fprintf(outf, "TOUCHOVERLAP:from (%d,%d) to (%d,%d)\n", starty, startx, endy, endx); + fprintf(outf, "TOUCHOVERLAP:win1 (%d,%d) to (%d,%d)\n", win1->_begy, win1->_begx, win1->_begy + win1->_maxy, win1->_begx + win1->_maxx); + fprintf(outf, "TOUCHOVERLAP:win2 (%d,%d) to (%d,%d)\n", win2->_begy, win2->_begx, win2->_begy + win2->_maxy, win2->_begx + win2->_maxx); +# endif + if (starty >= endy || startx >= endx) + return; + starty -= win2->_begy; + startx -= win2->_begx; + endy -= win2->_begy; + endx -= win2->_begx; + endx--; + for (y = starty; y < endy; y++) + touchline(win2, y, startx, endx); +} diff --git a/src/libcurses/touchwin.c b/src/libcurses/touchwin.c new file mode 100644 index 0000000..c71dc02 --- /dev/null +++ b/src/libcurses/touchwin.c @@ -0,0 +1,53 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "curses.ext" + +/* + * make it look like the whole window has been changed. + * + */ +int touchwin(win) + register WINDOW *win; +{ + register int y, maxy; + +# ifdef DEBUG + fprintf(outf, "TOUCHWIN(%0.2o)\n", win); +# endif + maxy = win->_maxy; + for (y = 0; y < maxy; y++) + touchline(win, y, 0, win->_maxx - 1); + return OK; +} + +/* + * touch a given line + */ +int touchline(win, y, sx, ex) + register WINDOW *win; + register int y, sx, ex; +{ +# ifdef DEBUG + fprintf(outf, "TOUCHLINE(%0.2o, %d, %d, %d)\n", win, y, sx, ex); + fprintf(outf, "TOUCHLINE:first = %d, last = %d\n", win->_firstch[y], win->_lastch[y]); +# endif + sx += win->_ch_off; + ex += win->_ch_off; + if (win->_firstch[y] == _NOCHANGE) { + win->_firstch[y] = sx; + win->_lastch[y] = ex; + } + else { + if (win->_firstch[y] > sx) + win->_firstch[y] = sx; + if (win->_lastch[y] < ex) + win->_lastch[y] = ex; + } +# ifdef DEBUG + fprintf(outf, "TOUCHLINE:first = %d, last = %d\n", win->_firstch[y], win->_lastch[y]); +# endif + return OK; +} diff --git a/src/libcurses/tstp.c b/src/libcurses/tstp.c new file mode 100644 index 0000000..fd38619 --- /dev/null +++ b/src/libcurses/tstp.c @@ -0,0 +1,56 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include +#include "curses.ext" + +/* + * handle stop and start signals + */ +void tstp(sig) +{ + SGTTY tty; + sigset_t oset, set; +#ifdef DEBUG + if (outf) + fflush(outf); +#endif + /* + * Block window change and timer signals. The latter is because + * applications use timers to decide when to repaint the screen. + */ + (void)sigemptyset(&set); + (void)sigaddset(&set, SIGALRM); + (void)sigaddset(&set, SIGWINCH); + (void)sigprocmask(SIG_BLOCK, &set, &oset); + + tty = _tty; + mvcur(0, COLS - 1, LINES - 1, 0); + endwin(); + fflush(stdout); + + /* Unblock SIGTSTP. */ + (void)sigemptyset(&set); + (void)sigaddset(&set, SIGTSTP); + (void)sigprocmask(SIG_UNBLOCK, &set, NULL); + + /* Stop ourselves. */ + signal(SIGTSTP, SIG_DFL); + kill(0, SIGTSTP); + + /* Time passes ... */ + + /* Reset the SIGTSTP handler. */ + signal(SIGTSTP, (sig_t)tstp); + + _tty = tty; + ioctl(_tty_ch, TIOCSETP, &_tty); + + /* Repaint the screen. */ + wrefresh(curscr); + + /* Reset the signals. */ + (void)sigprocmask(SIG_SETMASK, &oset, NULL); +} diff --git a/src/libcurses/unctrl.c b/src/libcurses/unctrl.c new file mode 100644 index 0000000..595225f --- /dev/null +++ b/src/libcurses/unctrl.c @@ -0,0 +1,23 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +/* + * define unctrl codes for each character + * + */ + +/* LINTLIBRARY */ +char *_unctrl[] = { /* unctrl codes for ttys */ + "^@", "^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", "{", "|", "}", "~", "^?" +}; diff --git a/src/libicache/icache.ld b/src/libicache/icache.ld new file mode 100644 index 0000000..e4396c9 --- /dev/null +++ b/src/libicache/icache.ld @@ -0,0 +1,300 @@ +OUTPUT_FORMAT("elf32-tradlittlemips") +OUTPUT_FORMAT("elf32-tradlittlemips") +OUTPUT_ARCH(pic32mx) + +ENTRY(_icstart_) + +MEMORY +{ + /* 96K internal CPU RAM */ + cpu_ram (rwx) : ORIGIN = 0x7F008000, LENGTH = 0x18000 + + /* 512K, loaded on demand into instruction cache from executable file */ + file_rom (rx!w) : ORIGIN = 0x40000000, LENGTH = 0x80000 +} + +SECTIONS +{ + /* Code Sections */ + + /* !!! fix this ugliness with '.', 'ORIGIN(cpu_ram)' and 'ORIGIN(file_rom)' !!! */ + + . = ORIGIN(cpu_ram); + + + .ictext ALIGN(4): + { + *icache?.o(.text .stub .text.* .gnu.linkonce.t.*) + . = ALIGN(4); + } > cpu_ram + + .startup : /* contains code */ + { + KEEP (*(.startup)) + } > cpu_ram + + + __icache_tmp__ = .; + . = ORIGIN(file_rom); + + + .text ALIGN(64): /* instruction cache uses 32-byte cache lines 32-bytes-aligned */ + { + _text_begin = .; + *(.text .stub .text.* .gnu.linkonce.t.*) + KEEP (*(.text.*personality*)) + *(.gnu.warning) + *(.mips16.fn.*) + *(.mips16.call.*) + . = ALIGN(64); /* instruction cache uses 32-byte cache lines 32-bytes-aligned */ + _text_end = .; + } > file_rom = 0 + + + . = __icache_tmp__; + + + /* Various initialization/finalization constructor/destructor sections */ + + .init : /* contains code, right? */ + { + KEEP (*crti.o(.init)) + KEEP (*crtbegin.o(.init)) + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o *crtn.o ).init)) + KEEP (*crtend.o(.init)) + KEEP (*crtn.o(.init)) + } > cpu_ram + + .fini : /* contains code, right? */ + { + KEEP (*(.fini)) + } > cpu_ram + + .preinit_array : /* contains data, right? */ + { + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + } > cpu_ram + + .init_array : /* contains data, right? */ + { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + } > cpu_ram + + .fini_array : /* contains data, right? */ + { + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(SORT(.fini_array.*))) + KEEP (*(.fini_array)) + PROVIDE_HIDDEN (__fini_array_end = .); + } > cpu_ram + + .ctors : /* contains data */ + { + /* gcc uses crtbegin.o to find the start of + the constructors, so we make sure it is + first. Because this is a wildcard, it + doesn't matter if the user does not + actually link against crtbegin.o; the + linker won't look for a file to match a + wildcard. The wildcard also means that it + doesn't matter which directory crtbegin.o + is in. */ + KEEP (*crtbegin.o(.ctors)) + KEEP (*crtbegin?.o(.ctors)) + /* We don't want to include the .ctor section from + the crtend.o file until after the sorted ctors. + The .ctor section from the crtend file contains the + end of ctors marker and it must be last */ + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } > cpu_ram + + .dtors : /* contains data */ + { + KEEP (*crtbegin.o(.dtors)) + KEEP (*crtbegin?.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } > cpu_ram + + .preinit_array : /* contains data, right? */ + { + KEEP (*(.preinit_array)) + } > cpu_ram + + /* Data Sections */ + + /* Read-only sections */ + + /* + * Small initialized constant global and static data can be placed in the + * .sdata2 section. This is different from .sdata, which contains small + * initialized non-constant global and static data. + */ + .sdata2 ALIGN(4): + { + *(.sdata2 .sdata2.* .gnu.linkonce.s2.*) + . = ALIGN(4); + } > cpu_ram + + /* + * Uninitialized constant global and static data (i.e., variables which will + * always be zero). Again, this is different from .sbss, which contains + * small non-initialized, non-constant global and static data. + */ + .sbss2 ALIGN(4): + { + *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) + . = ALIGN(4); + } > cpu_ram + + .dbg_data (NOLOAD): + { + . += (DEFINED (_DEBUGGER) ? 0x200 : 0x0); + } > cpu_ram + + /* Persistent data */ + .persist ALIGN(4): + { + _persist_begin = .; + *(.persist .persist.*) + . = ALIGN(4); + _persist_end = .; + } > cpu_ram + +/* !!! .rodata moved from code sections !!! */ + .rodata ALIGN(4): + { + *(.rodata .rodata.* .gnu.linkonce.r.*) + *(.rodata1) + . = ALIGN(4); + } > cpu_ram + + _data_begin = .; + .data ALIGN(4): + { + *(.data .data.* .gnu.linkonce.d.*) + KEEP (*(.gnu.linkonce.d.*personality*)) + *(.data1) + . = ALIGN(4); + } > cpu_ram + + . = .; + _gp = ALIGN(16) + 0x7ff0; + .got ALIGN(4): + { + *(.got.plt) *(.got) + } > cpu_ram + + /* + * We want the small data sections together, so single-instruction offsets + * can access them all, and initialized data all before uninitialized, so + * we can shorten the on-disk segment size. + */ + .sdata ALIGN(4): + { + _sdata_begin = .; + *(.sdata .sdata.* .gnu.linkonce.s.*) + _sdata_end = .; + } > cpu_ram + .lit8 : + { + *(.lit8) + } > cpu_ram + .lit4 : + { + *(.lit4) + } > cpu_ram + . = ALIGN(4); + _data_end = .; + + _bss_begin = .; + .sbss ALIGN(4): + { + _sbss_begin = .; + *(.dynsbss) + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) + . = ALIGN(4); + _sbss_end = .; + } > cpu_ram + + .bss ALIGN(4): + { + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* + * Align here to ensure that the .bss section occupies space up to + * _end. Align after .bss to ensure correct alignment even if the + * .bss section disappears because there are no input sections. + */ + . = ALIGN(4); + } > cpu_ram + . = ALIGN(4); + _bss_end = .; + + _end = .; + + /* The .pdr section belongs in the absolute section */ + /DISCARD/ : { *(.pdr) } + /* We don't load .reginfo onto the target, so don't locate it + * in real memory + */ + /DISCARD/ : { *(.reginfo) } + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + /DISCARD/ : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + /DISCARD/ : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /* DWARF 3 */ + .debug_pubtypes 0 : { *(.debug_pubtypes) } + .debug_ranges 0 : { *(.debug_ranges) } + .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) } + .gptab.sdata : { *(.gptab.data) *(.gptab.sdata) } + .gptab.sbss : { *(.gptab.bss) *(.gptab.sbss) } + .mdebug.abi32 : { KEEP(*(.mdebug.abi32)) } + .mdebug.abiN32 : { KEEP(*(.mdebug.abiN32)) } + .mdebug.abi64 : { KEEP(*(.mdebug.abi64)) } + .mdebug.abiO64 : { KEEP(*(.mdebug.abiO64)) } + .mdebug.eabi32 : { KEEP(*(.mdebug.eabi32)) } + .mdebug.eabi64 : { KEEP(*(.mdebug.eabi64)) } + /DISCARD/ : { *(.rel.dyn) } + /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) } +} diff --git a/src/libicache/icachec.c b/src/libicache/icachec.c new file mode 100644 index 0000000..66d4068 --- /dev/null +++ b/src/libicache/icachec.c @@ -0,0 +1,1262 @@ +/* +Copyright (c) 2013, Alexey Frunze +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +The views and conclusions contained in the software and documentation are those +of the authors and should not be interpreted as representing official policies, +either expressed or implied, of the FreeBSD Project. +*/ + +/*****************************************************************************/ +/* */ +/* MIPS icache */ +/* */ +/*****************************************************************************/ + +// the For best performance, this file should be compiled using gcc's -O3 option. + +// Define this macro to enable statistics +//#define STATS + +// Define this macro to do a more rigorous check +// for invalid/unsupported instructions +// (at the expense of performance, of course). +//#define CHECK_INVALID_INSTR + +#define STATIC static + +// Rename non-static functions and variables +// to prevent name collisions with other code +// when compiling together with it. +#define DoSysCall _icDoSysCall_ +#define main _icmain_ +#define Regs _icRegs_ +#define HostRegs _icHostRegs_ + +typedef unsigned char uchar, uint8; +typedef signed char schar, int8; +typedef unsigned short ushort, uint16; +typedef short int16; +typedef unsigned uint, uint32, size_t; +typedef int int32, ssize_t, off_t; +typedef unsigned long ulong; +typedef long long longlong, int64; +typedef unsigned long long ulonglong, uint64; + +#define C_ASSERT(expr) extern char CAssertExtern[(expr)?1:-1] + +//C_ASSERT(CHAR_BIT == 8); +C_ASSERT(sizeof(int) == 4); +C_ASSERT(sizeof(long) == 4); +C_ASSERT(sizeof(longlong) == 8); +C_ASSERT(sizeof(void*) == 4); +C_ASSERT(sizeof(void(*)()) == 4); +C_ASSERT(sizeof(size_t) == 4); +C_ASSERT(sizeof(ssize_t) == 4); +C_ASSERT(sizeof(off_t) == 4); +C_ASSERT(sizeof(uint16) == 2); +C_ASSERT(sizeof(uint32) == 4); +C_ASSERT(sizeof(uint64) == 8); + + +#pragma pack(push,1) + +typedef struct +{ + uint32 a_magic; /* magic number */ +#define OMAGIC 0407 /* old impure format */ + + uint32 a_text; /* size of text segment */ + uint32 a_data; /* size of initialized data */ + uint32 a_bss; /* size of uninitialized data */ + uint32 a_reltext; /* size of text relocation info */ + uint32 a_reldata; /* size of data relocation info */ + uint32 a_syms; /* size of symbol table */ + uint32 a_entry; /* entry point */ +} AoutHdr; + +#pragma pack(pop) + +C_ASSERT(sizeof(AoutHdr) == 32); + + +static inline +void* memset(void* dst, int ch, size_t size) +{ + unsigned char *p = dst; + while (size--) + *p++ = ch; + return dst; +} + +// flags for RetroBSD's open(): +#define O_RDONLY 0x0000 +#define O_WRONLY 0x0001 +#define O_RDWR 0x0002 +#define O_APPEND 0x0008 +#define O_CREAT 0x0200 +#define O_TRUNC 0x0400 +#define O_TEXT 0x0000 +#define O_BINARY 0x0000 + +// flags for RetroBSD's lseek(): +#define SEEK_SET 0 +#define SEEK_CUR 1 +#define SEEK_END 2 + +static +void exit(int code) +{ + asm volatile ("move $4, %0\n" + "syscall 1" // SYS_exit + : + : "r" (code) + : "$2", "$4"); +} + +static +int open(const char* name, int oflags) +{ + int handle; + asm volatile ("move $4, %1\n" + "move $5, %2\n" + "syscall 5\n" // SYS_open + "nop\n" + "nop\n" + "move %0, $2\n" + : "=r" (handle) + : "r" (name), "r" (oflags) + : "$2", "$4", "$5"); + return handle; +} + +static +ssize_t read(int handle, void* buf, size_t size) +{ + ssize_t sz; + asm volatile ("move $4, %1\n" + "move $5, %2\n" + "move $6, %3\n" + "syscall 3\n" // SYS_read + "nop\n" + "nop\n" + "move %0, $2\n" + : "=r" (sz) + : "r" (handle), "r" (buf), "r" (size) + : "$2", "$4", "$5", "$6", "memory"); + return sz; +} + +static +ssize_t write(int handle, const void* buf, size_t size) +{ + ssize_t sz; + asm volatile ("move $4, %1\n" + "move $5, %2\n" + "move $6, %3\n" + "syscall 4\n" // SYS_write + "nop\n" + "nop\n" + "move %0, $2\n" + : "=r" (sz) + : "r" (handle), "r" (buf), "r" (size) + : "$2", "$4", "$5", "$6", "memory"); // WTF? I shouldn't need "memory" here !!! + return sz; +} + +static +off_t lseek(int handle, off_t pos, int whence) +{ + off_t p; + asm volatile ("move $4, %1\n" + "move $5, %2\n" + "move $6, %3\n" + "syscall 19\n" // SYS_lseek + "nop\n" + "nop\n" + "move %0, $2\n" + : "=r" (p) + : "r" (handle), "r" (pos), "r" (whence) + : "$2", "$4", "$5", "$6"); + return p; +} + +#if 0 +// close() is unused. We rely on the system to close +// all files/handles on process termination. +static +int close(int handle) +{ + int err; + asm volatile ("move $4, %1\n" + "syscall 6\n" // SYS_close + "nop\n" + "nop\n" + "move %0, $2\n" + : "=r" (err) + : "r" (handle) + : "$2", "$4"); + return err; +} +#endif + +static +void printchr(int ch) +{ + char c = ch; + write(1, &c, 1); +} + +static +void printstr(const char* s) +{ + while (*s != '\0') + write(1, s++, 1); +} + +#ifdef STATS +static +void printdec(int n) +{ + unsigned un = n; + if (n < 0) + { + un = -un; + printchr('-'); + } + if (un >= 10) + printdec(un / 10); + printchr('0' + un % 10); +} + +static +char* Bin64ToDec(uint64 n) +{ + // log10(x) = log2(x) / log2(10) ~= log2(x) / 3.322 + static char s[64 / 3 + 1 + 1]; + char* p = s; + int i; + + memset(s, '0', sizeof s - 1); + s[sizeof s - 1] = '\0'; + + for (i = 0; i < 64; i++) + { + int j, carry; + + // Extract the most significant bit of n into carry + carry = (n >> 63) & 1; + // Shift n left + n <<= 1; + + // Add s[] to itself in decimal, doubling it, + // and add carry to it + for (j = sizeof s - 2; j >= 0; j--) + { + s[j] += s[j] - '0' + carry; + + carry = s[j] > '9'; + + if (carry) + s[j] -= 10; + } + } + + while ((*p == '0') && (p < &s[sizeof s - 2])) + p++; + + return p; +} + +static +void printdec64(int64 n) +{ + uint64 un = n; + if (n < 0) + { + un = -un; + printchr('-'); + } + printstr(Bin64ToDec(un)); +} +#endif + +static +void printhex(unsigned n) +{ + int i; + for (i = 0; i < 8; i++) + printchr("0123456789ABCDEF"[(n >> 28) & 15]), n <<= 4; +} + +#ifdef STATS +uint64 EmulateCnt = 0; +uint64 CacheHits = 0; +uint64 CacheHits2 = 0; +uint64 CacheMisses = 0; +#endif + + +#define REG_GP 28 +#define REG_SP 29 +#define REG_RA 31 +#define REG_LO 32 +#define REG_HI 33 +#define REG_PC 34 +uint32 Regs[32 + 3]; +uint32 HostRegs[32 + 3]; + + +#define CACHE_BYTES_PER_INSTR 4 +#ifndef CACHE_INSTRS_PER_ENTRY +#define CACHE_INSTRS_PER_ENTRY 8 +#endif +#define CACHE_BYTES_PER_ENTRY (CACHE_BYTES_PER_INSTR * CACHE_INSTRS_PER_ENTRY) + +#ifndef CACHE_ENTRIES_PER_WAY +#define CACHE_ENTRIES_PER_WAY 64 +#endif +#ifndef CACHE_WAYS +#define CACHE_WAYS 4 +#endif +#define CACHE_ENTRIES_TOTAL (CACHE_ENTRIES_PER_WAY * CACHE_WAYS) + +#define CACHE_SIZE (CACHE_BYTES_PER_ENTRY * CACHE_ENTRIES_TOTAL) + +STATIC uint32 Cache[CACHE_ENTRIES_PER_WAY][CACHE_WAYS][CACHE_INSTRS_PER_ENTRY]; +STATIC uint32 CacheTagAndValid[CACHE_ENTRIES_PER_WAY][CACHE_WAYS]; + +STATIC int CachedCnt = 0; +STATIC uint32* CachedInstr = &Cache[0][0][0]; + + +extern void _icstart_(int argc, char** argv, char** env); +STATIC void Emulate(void); + +STATIC int ExeHandle = -1; +STATIC uint32 ExeOffs = 0; + +int main(int argc, char** argv, char** env) +{ + AoutHdr aoutHdr; + + if ((ExeHandle = open(argv[0], O_BINARY | O_RDONLY)) < 0) + { + printstr("Can't open "); printstr(argv[0]); printchr('\n'); + exit(-1); + } + + if (read(ExeHandle, &aoutHdr, sizeof aoutHdr) != sizeof aoutHdr) + { + printstr("Can't read "); printstr(argv[0]); printchr('\n'); + exit(-1); + } + + if (aoutHdr.a_magic != OMAGIC) + { + printstr(argv[0]); printstr(" is not an a.out file\n"); + exit(-1); + } + + ExeOffs = sizeof aoutHdr + aoutHdr.a_text + aoutHdr.a_data; + + memset(CacheTagAndValid, 0xFF, sizeof CacheTagAndValid); // invalidate cache + Regs[4] = argc; + Regs[5] = (uint32)argv; + Regs[6] = (uint32)env; + // Regs[REG_SP] = ...; // _icstart() has done this + // Regs[REG_GP] = (uint32)&_gp; // _start() will do this if needed + Regs[REG_PC] = (uint32)&_icstart_; + Emulate(); // isn't supposed to return... + exit(-1); // ... but let's exit explicitly just in case + return -1; +} + +extern const char _text_begin; +extern const char _text_end; + +STATIC inline +uint32 FetchProgramWord(uint32 Addr) +{ + uint32 ofs, idx, tag, way; + + if (CachedCnt > 0) + { + CachedCnt--; + // Cache hit +#ifdef STATS + CacheHits++; + CacheHits2++; +#endif + return *++CachedInstr; + } + + if (Addr < (uint32)&_text_begin || + Addr >= (uint32)&_text_end) + { + CachedCnt = 0; + CachedInstr = (uint32*)Addr; + return *CachedInstr; + } + + ofs = Addr % CACHE_BYTES_PER_ENTRY / CACHE_BYTES_PER_INSTR; + idx = Addr / CACHE_BYTES_PER_ENTRY % CACHE_ENTRIES_PER_WAY; + tag = Addr / CACHE_BYTES_PER_ENTRY / CACHE_ENTRIES_PER_WAY; + for (way = 0; way < CACHE_WAYS; way++) + { + if (CacheTagAndValid[idx][way] == tag) + { + // Cache hit +#ifdef STATS + CacheHits++; +#endif + CachedCnt = CACHE_INSTRS_PER_ENTRY - 1 - ofs; + CachedInstr = &Cache[idx][way][ofs]; + return *CachedInstr; + } + } + + // Cache miss +#ifdef STATS + CacheMisses++; +#endif + + for (way = 0; way < CACHE_WAYS; way++) + { + if (CacheTagAndValid[idx][way] & 0x80000000) + { + // Use an invalid entry + goto lreuse; + } + } + + // Reuse a valid entry (need to choose one for eviction and refill, + // preferably not penalizing the same entry over and over again) + { + static uint32 w = CACHE_WAYS - 1; + w = (w + 1) % CACHE_WAYS; // pseudo-LRU + way = w; + } + +lreuse: + + if (lseek(ExeHandle, + ExeOffs + (Addr / CACHE_BYTES_PER_ENTRY * CACHE_BYTES_PER_ENTRY - (uint32)&_text_begin), + SEEK_SET) < 0 || + read(ExeHandle, Cache[idx][way], CACHE_BYTES_PER_ENTRY) != CACHE_BYTES_PER_ENTRY) + { + printstr("\nCan't read into the cache from the executable file\n"); + exit(-1); + } + + CacheTagAndValid[idx][way] = tag; + + CachedCnt = CACHE_INSTRS_PER_ENTRY - 1 - ofs; + CachedInstr = &Cache[idx][way][ofs]; + return *CachedInstr; +} + +extern int DoSysCall(uint32 instr); + +#ifdef STATS +STATIC +int DoSysCall2(uint32 instr) +{ + uint32 code = (instr >> 6) & 0xFFFFF; + + // intercept exit() syscall + if ((code == 0 && Regs[2] == 10) || // SPIM's exit() + (code == /*SYS_exit*/1)) // RetroBSD's exit() + { + uint32 idx, way, used = 0; + for (idx = 0; idx < CACHE_ENTRIES_PER_WAY; idx++) + for (way = 0; way < CACHE_WAYS; way++) + used += CacheTagAndValid[idx][way] < 0x80000000; + printstr("\n"); printdec64(EmulateCnt); printstr(" instruction(s) emulated\n"); + printdec((int)used); printchr('/'); printdec(CACHE_ENTRIES_TOTAL); printstr(" cache entries used\n"); + printdec64(CacheHits); printchr('('); + printdec64(CacheHits2); printstr(")/"); + printdec64(CacheMisses); printstr(" cache hits(hits2)/misses\n"); + } + return DoSysCall(instr); +} +#undef DoSysCall +#define DoSysCall DoSysCall2 +#endif + +static inline uint8 ReadByte(uint32 Addr) +{ + return *(uint8*)Addr; +} +static inline void WriteByte(uint32 Addr, uint8 Val) +{ + *(uint8*)Addr = Val; +} + +static inline uint16 ReadHalfWord(uint32 Addr) +{ + return *(uint16*)Addr; +} +static inline void WriteHalfWord(uint32 Addr, uint16 Val) +{ + *(uint16*)Addr = Val; +} + +static inline uint32 ReadWord(uint32 Addr) +{ + return *(uint32*)Addr; +} +static inline void WriteWord(uint32 Addr, uint32 Val) +{ + *(uint32*)Addr = Val; +} + +/* + Supported instructions: + + add, addi, addiu, addu, and, andi, + bal, beq, beql, bgez, bgezal, bgezall, + bgezl, bgtz, bgtzl, blez, blezl, bltz, + bltzal, bltzall, bltzl, bne, bnel, break, + clo, clz, + div, divu, + ext, + ins, + j, jal, jalr, jr, + lb, lbu, lh, lhu, lui, lw, lwl, lwr, + madd, maddu, mfhi, mflo, movn, movz, msub, + msubu, mthi, mtlo, mul, mult, multu, + nop, nor, + or, ori, + rotr, rotrv, + sb, seb, seh, sh, sll, sllv, slt, slti, sltiu, + sltu, sra, srav, srl, srlv, sub, subu, sw, + swl, swlr, syscall, + teq, teqi, tge, tgei, tgeiu, tgeu, tlt, tlti, + tltiu, tltu, tne, tnei, + wsbh, + xor, xori + + Unsupported instructions: + + bc2f, bc2fl, bc2t, bc2tl, + cache, cfc2, cop0, cop2, ctc2, + deret, di, + ehb, ei, eret, + jalr.hb, jr.hb, + ll, lwc2, + mfc0, mfc2, mtc0, mtc2, mthc2, + pref, + rdhwr, rdpgpr, + sc, sdbbp, ssnop, swc2, sync, synci, + wait, wrpgpr +*/ + +STATIC void DoBreak(uint32 instr); +STATIC void DoTrap(uint32 instr); +STATIC void DoOverflow(void); +STATIC void DoInvalidInstruction(uint32 instr); + +STATIC +uint32 CountLeadingZeroes(uint32 n) +{ +#if 0 + uint32 c = 0; + if (n == 0) + return 32; + while (n < 0x80000000) + n <<= 1, c++; +#else + uint32 c; + asm volatile("clz %0, %1" : "=r" (c) : "r" (n)); +#endif + return c; +} + +STATIC +uint32 CountLeadingOnes(uint32 n) +{ +#if 0 + uint32 c = 0; + while (n >= 0x80000000) + n <<= 1, c++; +#else + uint32 c; + asm volatile("clo %0, %1" : "=r" (c) : "r" (n)); +#endif + return c; +} + +STATIC +uint32 ShiftRightArithm(uint32 n, uint32 c) +{ +#if 0 + uint32 s = -(n >> 31); + n >>= c; + n |= s << (31 - c) << 1; + return n; +#else + uint32 nn; + asm volatile("srav %0, %1, %2" : "=r" (nn) : "r" (n), "r" (c)); + return nn; +#endif +} + +STATIC +uint32 RotateRight(uint32 n, uint32 c) +{ +#if 0 + return (n >> c) | (n << (31 - c) << 1); +#else + uint32 nn; + asm volatile("rotrv %0, %1, %2" : "=r" (nn) : "r" (n), "r" (c)); + return nn; +#endif +} + +STATIC +void Emulate(void) +{ + int delaySlot = 0; + uint32 postDelaySlotPc = 0; + uint32 instr = 0; + + for (;;) + { + const uint32 pc = Regs[REG_PC]; + uint32 nextPc = pc + 4; + /*const uint32*/ instr = FetchProgramWord(pc); +#if 0 + const uint32 op = instr >> 26; + const uint32 r1 = (instr >> 21) & 0x1F; + const uint32 r2 = (instr >> 16) & 0x1F; + const uint32 r3 = (instr >> 11) & 0x1F; + const uint32 shft = (instr >> 6) & 0x1F; + const uint32 fxn = instr & 0x3F; + const uint32 imm16 = instr & 0xFFFF; + const uint32 simm16 = (int16)imm16; + const uint32 jtgt = instr & 0x3FFFFFF; +#else +#define op (instr >> 26) +#define r1 ((instr >> 21) & 0x1F) +#define r2 ((instr >> 16) & 0x1F) +#define r3 ((instr >> 11) & 0x1F) +#define shft ((instr >> 6) & 0x1F) +#define fxn (instr & 0x3F) +#define imm16 (instr & 0xFFFF) +#define simm16 ((int16)imm16) +#define jtgt (instr & 0x3FFFFFF) +#endif + + switch (op) + { + case 0: + switch (fxn) + { + case 0: +#ifdef CHECK_INVALID_INSTR + if (r1) + goto lInvalidInstruction; +#endif + Regs[r3] = Regs[r2] << shft; + break; // sll d,w,shft + case 2: + switch (r1) + { + case 0: Regs[r3] = Regs[r2] >> shft; break; // srl d,w,shft + case 1: Regs[r3] = RotateRight(Regs[r2], shft); break; // rotr d,w,shft + default: goto lInvalidInstruction; + } + break; + case 3: +#ifdef CHECK_INVALID_INSTR + if (r1) + goto lInvalidInstruction; +#endif + Regs[r3] = ShiftRightArithm(Regs[r2], shft); + break; // sra d,w,shft + case 4: +#ifdef CHECK_INVALID_INSTR + if (shft) + goto lInvalidInstruction; +#endif + Regs[r3] = Regs[r2] << (Regs[r1] & 31); + break; // sllv d,w,s + case 6: + switch (shft) + { + case 0: Regs[r3] = Regs[r2] >> (Regs[r1] & 31); break; // srlv d,w,s + case 1: Regs[r3] = RotateRight(Regs[r2], Regs[r1] & 31); break; // rotrv d,w,s + default: goto lInvalidInstruction; + } + break; + case 7: +#ifdef CHECK_INVALID_INSTR + if (shft) + goto lInvalidInstruction; +#endif + Regs[r3] = ShiftRightArithm(Regs[r2], Regs[r1] & 31); + break; // srav d,w,s + case 8: +#ifdef CHECK_INVALID_INSTR + if (r2 | r3 | shft) + goto lInvalidInstruction; +#endif + nextPc = Regs[r1]; delaySlot = 1; + break; // jr s + case 9: +#ifdef CHECK_INVALID_INSTR + if (r2 | shft) + goto lInvalidInstruction; +#endif + Regs[r3] = nextPc + 4; nextPc = Regs[r1]; delaySlot = 1; + break; // jalr [d,] s + case 10: +#ifdef CHECK_INVALID_INSTR + if (shft) + goto lInvalidInstruction; +#endif + if (Regs[r2] == 0) Regs[r3] = Regs[r1]; + break; // movz d,s,t + case 11: +#ifdef CHECK_INVALID_INSTR + if (shft) + goto lInvalidInstruction; +#endif + if (Regs[r2]) Regs[r3] = Regs[r1]; + break; // movn d,s,t + case 12: + { + // RetroBSD may advance PC on returning from a syscall handler, + // skipping 2 instructions that follow the syscall instruction. + // Those 2 instructions typically set C's errno variable and + // are either executed on error or skipped on success. + // Account for this peculiarity. + uint32 skip = DoSysCall(instr); + nextPc += skip * 4; CachedCnt -= skip; CachedInstr += skip; + } + break; // syscall code + case 13: goto lBreak; break; // break code + case 16: +#ifdef CHECK_INVALID_INSTR + if (r1 | r2 | shft) + goto lInvalidInstruction; +#endif + Regs[r3] = Regs[REG_HI]; + break; // mfhi d + case 17: +#ifdef CHECK_INVALID_INSTR + if (r2 | r3 | shft) + goto lInvalidInstruction; +#endif + Regs[REG_HI] = Regs[r1]; + break; // mthi s + case 18: +#ifdef CHECK_INVALID_INSTR + if (r1 | r2 | shft) + goto lInvalidInstruction; +#endif + Regs[r3] = Regs[REG_LO]; + break; // mflo d + case 19: +#ifdef CHECK_INVALID_INSTR + if (r2 | r3 | shft) + goto lInvalidInstruction; +#endif + Regs[REG_LO] = Regs[r1]; + break; // mtlo s + case 24: +#ifdef CHECK_INVALID_INSTR + if (r3 | shft) + goto lInvalidInstruction; +#endif + { + int64 p = (int64)(int32)Regs[r1] * (int32)Regs[r2]; + Regs[REG_LO] = (uint32)p; + Regs[REG_HI] = (uint32)(p >> 32); + } + break; // mult s,t + case 25: +#ifdef CHECK_INVALID_INSTR + if (r3 | shft) + goto lInvalidInstruction; +#endif + { + uint64 p = (uint64)Regs[r1] * Regs[r2]; + Regs[REG_LO] = (uint32)p; + Regs[REG_HI] = (uint32)(p >> 32); + } + break; // multu s,t + case 26: +#ifdef CHECK_INVALID_INSTR + if (r3 | shft) + goto lInvalidInstruction; +#endif + if (!(Regs[r2] == 0 || (Regs[r1] == 0x80000000 && Regs[r2] == 0xFFFFFFFF))) + Regs[REG_LO] = (int32)Regs[r1] / (int32)Regs[r2], Regs[REG_HI] = (int32)Regs[r1] % (int32)Regs[r2]; + break; // div s,t + case 27: +#ifdef CHECK_INVALID_INSTR + if (r3 | shft) + goto lInvalidInstruction; +#endif + if (Regs[r2]) + Regs[REG_LO] = Regs[r1] / Regs[r2], Regs[REG_HI] = Regs[r1] % Regs[r2]; + break; // divu s,t + case 32: +#ifdef CHECK_INVALID_INSTR + if (shft) + goto lInvalidInstruction; +#endif + { + uint32 sum = Regs[r1] + Regs[r2]; + if (((Regs[r1] ^ Regs[r2] ^ 0x80000000) & 0x80000000) && + ((sum ^ Regs[r1]) & 0x80000000)) + goto lOverflow; + Regs[r3] = sum; + } + break; // add d,s,t + case 33: +#ifdef CHECK_INVALID_INSTR + if (shft) + goto lInvalidInstruction; +#endif + Regs[r3] = Regs[r1] + Regs[r2]; + break; // addu d,s,t + case 34: +#ifdef CHECK_INVALID_INSTR + if (shft) + goto lInvalidInstruction; +#endif + { + uint32 diff = Regs[r1] - Regs[r2]; + if (((Regs[r1] ^ Regs[r2]) & 0x80000000) && + ((diff ^ Regs[r1]) & 0x80000000)) + goto lOverflow; + Regs[r3] = diff; + } + break; // sub d,s,t + case 35: +#ifdef CHECK_INVALID_INSTR + if (shft) + goto lInvalidInstruction; +#endif + Regs[r3] = Regs[r1] - Regs[r2]; + break; // subu d,s,t + case 36: +#ifdef CHECK_INVALID_INSTR + if (shft) + goto lInvalidInstruction; +#endif + Regs[r3] = Regs[r1] & Regs[r2]; + break; // and d,s,t + case 37: +#ifdef CHECK_INVALID_INSTR + if (shft) + goto lInvalidInstruction; +#endif + Regs[r3] = Regs[r1] | Regs[r2]; + break; // or d,s,t + case 38: +#ifdef CHECK_INVALID_INSTR + if (shft) + goto lInvalidInstruction; +#endif + Regs[r3] = Regs[r1] ^ Regs[r2]; + break; // xor d,s,t + case 39: +#ifdef CHECK_INVALID_INSTR + if (shft) + goto lInvalidInstruction; +#endif + Regs[r3] = ~(Regs[r1] | Regs[r2]); + break; // nor d,s,t + case 42: +#ifdef CHECK_INVALID_INSTR + if (shft) + goto lInvalidInstruction; +#endif + Regs[r3] = (int32)Regs[r1] < (int32)Regs[r2]; + break; // slt d,s,t + case 43: +#ifdef CHECK_INVALID_INSTR + if (shft) + goto lInvalidInstruction; +#endif + Regs[r3] = Regs[r1] < Regs[r2]; + break; // sltu d,s,t + + case 48: if ((int32)Regs[r1] >= (int32)Regs[r2]) goto lTrap; break; // tge s,t + case 49: if (Regs[r1] >= Regs[r2]) goto lTrap; break; // tgeu s,t + case 50: if ((int32)Regs[r1] < (int32)Regs[r2]) goto lTrap; break; // tlt s,t + case 51: if (Regs[r1] < Regs[r2]) goto lTrap; break; // tltu s,t + case 52: if (Regs[r1] == Regs[r2]) goto lTrap; break; // teq s,t + case 53: if (Regs[r1] != Regs[r2]) goto lTrap; break; // tne s,t + + default: goto lInvalidInstruction; + } + break; + + case 1: + switch (r2) + { + case 0: if ((int32)Regs[r1] < 0) nextPc += simm16 << 2, delaySlot = 1; break; // bltz s,p + case 1: if ((int32)Regs[r1] >= 0) nextPc += simm16 << 2, delaySlot = 1; break; // bgez s,p + case 2: if ((int32)Regs[r1] < 0) nextPc += simm16 << 2, delaySlot = 1; else nextPc += 4, CachedCnt--, ++CachedInstr; break; // bltzl s,p + case 3: if ((int32)Regs[r1] >= 0) nextPc += simm16 << 2, delaySlot = 1; else nextPc += 4, CachedCnt--, ++CachedInstr; break; // bgezl s,p + + case 8: if ((int32)Regs[r1] >= (int32)simm16) goto lTrap; break; // tgei s,j + case 9: if (Regs[r1] >= (uint32)simm16) goto lTrap; break; // tgeiu s,j + case 10: if ((int32)Regs[r1] < (int32)simm16) goto lTrap; break; // tlti s,j + case 11: if (Regs[r1] < (uint32)simm16) goto lTrap; break; // tltiu s,j + case 12: if (Regs[r1] == (uint32)simm16) goto lTrap; break; // teqi s,j + case 14: if (Regs[r1] != (uint32)simm16) goto lTrap; break; // tnei s,j + + case 16: Regs[REG_RA] = nextPc + 4; if ((int32)Regs[r1] < 0) nextPc += simm16 << 2, delaySlot = 1; break; // bltzal s,p + case 17: Regs[REG_RA] = nextPc + 4; if ((int32)Regs[r1] >= 0) nextPc += simm16 << 2, delaySlot = 1; break; // bgezal s,p + case 18: Regs[REG_RA] = nextPc + 4; if ((int32)Regs[r1] < 0) nextPc += simm16 << 2, delaySlot = 1; else nextPc += 4, CachedCnt--, ++CachedInstr; break; // bltzall s,p + case 19: Regs[REG_RA] = nextPc + 4; if ((int32)Regs[r1] >= 0) nextPc += simm16 << 2, delaySlot = 1; else nextPc += 4, CachedCnt--, ++CachedInstr; break; // bgezall s,p + + default: goto lInvalidInstruction; + } + break; + + case 2: nextPc = (pc & 0xF0000000) | (jtgt << 2); delaySlot = 1; break; // j target + case 3: Regs[REG_RA] = nextPc + 4; nextPc = (pc & 0xF0000000) | (jtgt << 2); delaySlot = 1; break; // jal target + + case 4: if (Regs[r1] == Regs[r2]) nextPc += simm16 << 2, delaySlot = 1; break; // beq s,t,p + case 5: if (Regs[r1] != Regs[r2]) nextPc += simm16 << 2, delaySlot = 1; break; // bne s,t,p + case 6: +#ifdef CHECK_INVALID_INSTR + if (r2) + goto lInvalidInstruction; +#endif + if ((int32)Regs[r1] <= 0) nextPc += simm16 << 2, delaySlot = 1; break; // blez s,p + case 7: +#ifdef CHECK_INVALID_INSTR + if (r2) + goto lInvalidInstruction; +#endif + if ((int32)Regs[r1] > 0) nextPc += simm16 << 2, delaySlot = 1; break; // bgtz s,p + + case 8: + { + uint32 sum = Regs[r1] + simm16; + if (((Regs[r1] ^ simm16 ^ 0x80000000) & 0x80000000) && + ((sum ^ Regs[r1]) & 0x80000000)) + goto lOverflow; + Regs[r2] = sum; + } + break; // addi d,s,const + case 9: Regs[r2] = Regs[r1] + simm16; break; // addiu d,s,const + case 10: Regs[r2] = (int32)Regs[r1] < (int32)simm16; break; // slti d,s,const + case 11: Regs[r2] = Regs[r1] < imm16; break; // sltiu d,s,const + case 12: Regs[r2] = Regs[r1] & imm16; break; // andi d,s,const + case 13: Regs[r2] = Regs[r1] | imm16; break; // ori d,s,const + case 14: Regs[r2] = Regs[r1] ^ imm16; break; // xori d,s,const + case 15: +#ifdef CHECK_INVALID_INSTR + if (r1) + goto lInvalidInstruction; +#endif + Regs[r2] = imm16 << 16; break; // lui d,const + + case 20: if (Regs[r1] == Regs[r2]) nextPc += simm16 << 2, delaySlot = 1; else nextPc += 4, CachedCnt--, ++CachedInstr; break; // beql s,t,p + case 21: if (Regs[r1] != Regs[r2]) nextPc += simm16 << 2, delaySlot = 1; else nextPc += 4, CachedCnt--, ++CachedInstr; break; // bnel s,t,p + case 22: +#ifdef CHECK_INVALID_INSTR + if (r2) + goto lInvalidInstruction; +#endif + if ((int32)Regs[r1] <= 0) nextPc += simm16 << 2, delaySlot = 1; else nextPc += 4, CachedCnt--, ++CachedInstr; break; // blezl s,p + case 23: +#ifdef CHECK_INVALID_INSTR + if (r2) + goto lInvalidInstruction; +#endif + if ((int32)Regs[r1] > 0) nextPc += simm16 << 2, delaySlot = 1; else nextPc += 4, CachedCnt--, ++CachedInstr; break; // bgtzl s,p + + case 28: +#ifdef CHECK_INVALID_INSTR + if (shft) + goto lInvalidInstruction; +#endif + switch (fxn) + { + case 0: +#ifdef CHECK_INVALID_INSTR + if (r3) + goto lInvalidInstruction; +#endif + { + int64 p = (int64)(int32)Regs[r1] * (int32)Regs[r2]; + if (Regs[REG_LO] > 0xFFFFFFFF - (uint32)p) + Regs[REG_HI]++; + Regs[REG_LO] += (uint32)p; + Regs[REG_HI] += (uint32)(p >> 32); + } + break; // madd s,t + case 1: +#ifdef CHECK_INVALID_INSTR + if (r3) + goto lInvalidInstruction; +#endif + { + uint64 p = (uint64)Regs[r1] * Regs[r2]; + if (Regs[REG_LO] > 0xFFFFFFFF - (uint32)p) + Regs[REG_HI]++; + Regs[REG_LO] += (uint32)p; + Regs[REG_HI] += (uint32)(p >> 32); + } + break; // maddu s,t + case 2: Regs[r3] = Regs[r1] * Regs[r2]; break; // mul d,s,t + case 4: +#ifdef CHECK_INVALID_INSTR + if (r3) + goto lInvalidInstruction; +#endif + { + int64 p = (int64)(int32)Regs[r1] * (int32)Regs[r2]; + if (Regs[REG_LO] < (uint32)p) + Regs[REG_HI]--; + Regs[REG_LO] -= (uint32)p; + Regs[REG_HI] -= (uint32)(p >> 32); + } + break; // msub s,t + case 5: +#ifdef CHECK_INVALID_INSTR + if (r3) + goto lInvalidInstruction; +#endif + { + uint64 p = (uint64)Regs[r1] * Regs[r2]; + if (Regs[REG_LO] < (uint32)p) + Regs[REG_HI]--; + Regs[REG_LO] -= (uint32)p; + Regs[REG_HI] -= (uint32)(p >> 32); + } + break; // msubu s,t + + case 32: +#ifdef CHECK_INVALID_INSTR + if (r1 != r2) + goto lInvalidInstruction; +#endif + Regs[r3] = CountLeadingZeroes(Regs[r2]); break; // clz d,s + case 33: +#ifdef CHECK_INVALID_INSTR + if (r1 != r2) + goto lInvalidInstruction; +#endif + Regs[r3] = CountLeadingOnes(Regs[r2]); break; // clo d,s + + default: goto lInvalidInstruction; + } + break; + + case 31: + switch (fxn) + { + case 0: + if (shft + r3 <= 31) + { + uint size = r3 + 1; + uint32 mask = (0xFFFFFFFF >> (32 - size)) << shft; + Regs[r2] = (Regs[r1] & mask) >> shft; + } + break; // ext t,s,pos,sz + case 4: + if (r3 >= shft) + { + uint size = r3 - shft + 1; + uint32 mask = (0xFFFFFFFF >> (32 - size)) << shft; + Regs[r2] = (Regs[r2] & ~mask) | ((Regs[r1] << shft) & mask); + } + break; // ins t,s,pos,sz + case 32: +#ifdef CHECK_INVALID_INSTR + if (r1) + goto lInvalidInstruction; +#endif + switch (shft) + { + case 2: Regs[r3] = ((Regs[r2] & 0x00FF) << 8) | + ((Regs[r2] & 0xFF00) >> 8) | + ((Regs[r2] & 0x00FF0000) << 8) | + ((Regs[r2] & 0xFF000000) >> 8); break; // wsbh d,t + case 16: Regs[r3] = (int8)Regs[r2]; break; // seb d,t + case 24: Regs[r3] = (int16)Regs[r2]; break; // seh d,t + default: goto lInvalidInstruction; + } + break; + + default: goto lInvalidInstruction; + } + break; + + case 32: Regs[r2] = (int8)ReadByte(Regs[r1] + simm16); break; // lb t,o(b) + case 33: Regs[r2] = (int16)ReadHalfWord(Regs[r1] + simm16); break; // lh t,o(b) + case 34: + { + uint32 v = ReadByte(Regs[r1] + simm16); + v = (v << 8) | ReadByte(Regs[r1] + simm16 - 1); + Regs[r2] = (Regs[r2] & 0xFFFF) | (v << 16); + } + break; // lwl t,o(b) + case 35: Regs[r2] = ReadWord(Regs[r1] + simm16); break; // lw t,o(b) + case 36: Regs[r2] = ReadByte(Regs[r1] + simm16); break; // lbu t,o(b) + case 37: Regs[r2] = ReadHalfWord(Regs[r1] + simm16); break; // lhu t,o(b) + case 38: + { + uint32 v = ReadByte(Regs[r1] + simm16); + v |= (uint32)ReadByte(Regs[r1] + simm16 + 1) << 8; + Regs[r2] = (Regs[r2] & 0xFFFF0000) | v; + } + break; // lwr t,o(b) + + case 40: WriteByte(Regs[r1] + simm16, (uint8)Regs[r2]); break; // sb t,o(b) + case 41: WriteHalfWord(Regs[r1] + simm16, (uint16)Regs[r2]); break; // sh t,o(b) + case 42: + WriteByte(Regs[r1] + simm16, (uint8)(Regs[r2] >> 24)); + WriteByte(Regs[r1] + simm16 - 1, (uint8)(Regs[r2] >> 16)); + break; // swl t,o(b) + case 43: WriteWord(Regs[r1] + simm16, Regs[r2]); break; // sw t,o(b) + case 46: + WriteByte(Regs[r1] + simm16, (uint8)Regs[r2]); + WriteByte(Regs[r1] + simm16 + 1, (uint8)(Regs[r2] >> 8)); + break; // swr t,o(b) + + default: + goto lInvalidInstruction; + } + + Regs[0] = 0; + + Regs[REG_PC] = nextPc; + + if (delaySlot) + { + if (delaySlot == 1) + { + postDelaySlotPc = nextPc; + Regs[REG_PC] = pc + 4; + delaySlot = 2; + } + else + { + Regs[REG_PC] = postDelaySlotPc; + delaySlot = 0; + CachedCnt = 0; + } + } + +#ifdef STATS + EmulateCnt++; +#endif + } // for (;;) + +lBreak: + DoBreak(instr); + return; + +lTrap: + DoTrap(instr); + return; + +lOverflow: + DoOverflow(); + return; + +lInvalidInstruction: + DoInvalidInstruction(instr); + return; +#if 01 +#undef op +#undef r1 +#undef r2 +#undef r3 +#undef shft +#undef fxn +#undef imm16 +#undef simm16 +#undef jtgt +#endif +} + +STATIC +void DoBreak(uint32 instr) +{ + uint32 code = (instr >> 16) & 0x3FF; // are there really another/extra 10 bits of the code? + + switch (code) + { + case 6: + printstr("\nBreak: Signed division overflow"); + break; + case 7: + printstr("\nBreak: Division by 0"); + break; + default: + printstr("\nBreak: Code: 0x"); printhex(code); + break; + } + printstr(" at PC = 0x"); printhex(Regs[REG_PC]); printchr('\n'); + exit(-1); +} + +STATIC +void DoTrap(uint32 instr) +{ + uint32 code = (instr >> 6) & 0x3FF; + + switch (code) + { + case 6: + printstr("\nTrap: Signed division overflow"); + break; + case 7: + printstr("\nTrap: Division by 0"); + break; + default: + printstr("\nTrap: Code: 0x"); printhex(code); + break; + } + printstr(" at PC = 0x"); printhex(Regs[REG_PC]); printchr('\n'); + exit(-1); +} + +STATIC +void DoOverflow(void) +{ + printstr("Signed integer addition/subtraction overflow"); + printstr(" at PC = 0x"); printhex(Regs[REG_PC]); printchr('\n'); + exit(-1); +} + +STATIC +void DoInvalidInstruction(uint32 instr) +{ + printstr("Invalid/unsupported instruction: Opcode: 0x"); printhex(instr); + printstr(" at PC = 0x"); printhex(Regs[REG_PC]); printchr('\n'); + exit(-1); +} diff --git a/src/libicache/icaches.s b/src/libicache/icaches.s new file mode 100644 index 0000000..837971f --- /dev/null +++ b/src/libicache/icaches.s @@ -0,0 +1,285 @@ + # /* + # Copyright (c) 2013, Alexey Frunze + # All rights reserved. + # + # Redistribution and use in source and binary forms, with or without + # modification, are permitted provided that the following conditions are met: + # + # 1. Redistributions of source code must retain the above copyright notice, this + # list of conditions and the following disclaimer. + # 2. Redistributions in binary form must reproduce the above copyright notice, + # this list of conditions and the following disclaimer in the documentation + # and/or other materials provided with the distribution. + # + # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + # + # The views and conclusions contained in the software and documentation are those + # of the authors and should not be interpreted as representing official policies, + # either expressed or implied, of the FreeBSD Project. + # */ + # + # /*****************************************************************************/ + # /* */ + # /* MIPS icache */ + # /* */ + # /*****************************************************************************/ + + .text + + .extern _gp + .extern _icRegs_ + .extern _icHostRegs_ + .extern _icmain_ + + .globl _icstart_ + .type _icstart_, @function +_icstart_: + la $28, _gp + subu $29, $29, 1024 # allocate 1K of stack for us + sw $29, _icRegs_ + 4*29 # leave the rest to the program + addu $29, $29, 1024 - 16 + j _icmain_ + + .globl _icDoSysCall_ + .type _icDoSysCall_, @function +_icDoSysCall_: + sw $4, $_icsyscall_ # patch the syscall instruction + # We need to write back the data cache and invalidate the instruction + # cache for the location of the modified instruction before we can + # actually execute it + la $4, $_icsyscall_ + synci 0($4) # does nothing on MIPS32 M4K since it has no caches + + # sw $1, _icHostRegs_ + 4*1 # ar + # lw $1, _icRegs_ + 4*1 # + # sw $2, _icHostRegs_ + 4*2 # v0 + lw $2, _icRegs_ + 4*2 # + # sw $3, _icHostRegs_ + 4*3 # v1 + lw $3, _icRegs_ + 4*3 # + # sw $4, _icHostRegs_ + 4*4 # a0 + lw $4, _icRegs_ + 4*4 # + # sw $5, _icHostRegs_ + 4*5 # a1 + lw $5, _icRegs_ + 4*5 # + # sw $6, _icHostRegs_ + 4*6 # a2 + lw $6, _icRegs_ + 4*6 # + # sw $7, _icHostRegs_ + 4*7 # a3 + lw $7, _icRegs_ + 4*7 # + # sw $8, _icHostRegs_ + 4*8 # t0 + lw $8, _icRegs_ + 4*8 # + # sw $9, _icHostRegs_ + 4*9 # t1 + lw $9, _icRegs_ + 4*9 # + # sw $10, _icHostRegs_ + 4*10 # t2 + lw $10, _icRegs_ + 4*10 # + # sw $11, _icHostRegs_ + 4*11 # t3 + lw $11, _icRegs_ + 4*11 # + # sw $12, _icHostRegs_ + 4*12 # t4 + lw $12, _icRegs_ + 4*12 # + # sw $13, _icHostRegs_ + 4*13 # t5 + lw $13, _icRegs_ + 4*13 # + # sw $14, _icHostRegs_ + 4*14 # t6 + lw $14, _icRegs_ + 4*14 # + # sw $15, _icHostRegs_ + 4*15 # t7 + lw $15, _icRegs_ + 4*15 # + sw $16, _icHostRegs_ + 4*16 + lw $16, _icRegs_ + 4*16 + sw $17, _icHostRegs_ + 4*17 + lw $17, _icRegs_ + 4*17 + sw $18, _icHostRegs_ + 4*18 + lw $18, _icRegs_ + 4*18 + sw $19, _icHostRegs_ + 4*19 + lw $19, _icRegs_ + 4*19 + sw $20, _icHostRegs_ + 4*20 + lw $20, _icRegs_ + 4*20 + sw $21, _icHostRegs_ + 4*21 + lw $21, _icRegs_ + 4*21 + sw $22, _icHostRegs_ + 4*22 + lw $22, _icRegs_ + 4*22 + sw $23, _icHostRegs_ + 4*23 + lw $23, _icRegs_ + 4*23 + # sw $24, _icHostRegs_ + 4*24 # t8 + lw $24, _icRegs_ + 4*24 # + # sw $25, _icHostRegs_ + 4*25 # t9 + lw $25, _icRegs_ + 4*25 # + # sw $26, _icHostRegs_ + 4*26 # k0 + # lw $26, _icRegs_ + 4*26 # + # sw $27, _icHostRegs_ + 4*27 # k1 + # lw $27, _icRegs_ + 4*27 # + sw $28, _icHostRegs_ + 4*28 # gp + lw $28, _icRegs_ + 4*28 # + sw $29, _icHostRegs_ + 4*29 # sp + # lw $29, _icRegs_ + 4*29 # + # Make sure sp is updated "atomically" and not part by part + .set noat + lw $1, _icRegs_ + 4*29 # + move $29, $1 # + .set at + sw $30, _icHostRegs_ + 4*30 + lw $30, _icRegs_ + 4*30 + # sw $31, _icHostRegs_ + 4*31 # ra + # lw $31, _icRegs_ + 4*31 # ra + +$_icsyscall_: + # This instruction gets patched, so it can have + # the requested system call number embedded in it + syscall + + # RetroBSD may advance PC on returning from a syscall handler, + # skipping 2 instructions that follow the syscall instruction. + # Those 2 instructions typically set C's errno variable and + # are either executed on error or skipped on success. + # Account for this peculiarity. + j $_icsyscall_error_ + nop +$_icsyscall_success_: + + # sw $1, _icRegs_ + 4*1 # ar + # lw $1, _icHostRegs_ + 4*1 # + sw $2, _icRegs_ + 4*2 # v0 + # lw $2, _icHostRegs_ + 4*2 # + sw $3, _icRegs_ + 4*3 # v1 + # lw $3, _icHostRegs_ + 4*3 # + sw $4, _icRegs_ + 4*4 # a0 + # lw $4, _icHostRegs_ + 4*4 # + sw $5, _icRegs_ + 4*5 # a1 + # lw $5, _icHostRegs_ + 4*5 # + sw $6, _icRegs_ + 4*6 # a2 + # lw $6, _icHostRegs_ + 4*6 # + sw $7, _icRegs_ + 4*7 # a3 + # lw $7, _icHostRegs_ + 4*7 # + sw $8, _icRegs_ + 4*8 # t0 + # lw $8, _icHostRegs_ + 4*8 # + sw $9, _icRegs_ + 4*9 # t1 + # lw $9, _icHostRegs_ + 4*9 # + sw $10, _icRegs_ + 4*10 # t2 + # lw $10, _icHostRegs_ + 4*10 # + sw $11, _icRegs_ + 4*11 # t3 + # lw $11, _icHostRegs_ + 4*11 # + sw $12, _icRegs_ + 4*12 # t4 + # lw $12, _icHostRegs_ + 4*12 # + sw $13, _icRegs_ + 4*13 # t5 + # lw $13, _icHostRegs_ + 4*13 # + sw $14, _icRegs_ + 4*14 # t6 + # lw $14, _icHostRegs_ + 4*14 # + sw $15, _icRegs_ + 4*15 # t7 + # lw $15, _icHostRegs_ + 4*15 # + sw $16, _icRegs_ + 4*16 + lw $16, _icHostRegs_ + 4*16 + sw $17, _icRegs_ + 4*17 + lw $17, _icHostRegs_ + 4*17 + sw $18, _icRegs_ + 4*18 + lw $18, _icHostRegs_ + 4*18 + sw $19, _icRegs_ + 4*19 + lw $19, _icHostRegs_ + 4*19 + sw $20, _icRegs_ + 4*20 + lw $20, _icHostRegs_ + 4*20 + sw $21, _icRegs_ + 4*21 + lw $21, _icHostRegs_ + 4*21 + sw $22, _icRegs_ + 4*22 + lw $22, _icHostRegs_ + 4*22 + sw $23, _icRegs_ + 4*23 + lw $23, _icHostRegs_ + 4*23 + sw $24, _icRegs_ + 4*24 # t8 + # lw $24, _icHostRegs_ + 4*24 # + sw $25, _icRegs_ + 4*25 # t9 + # lw $25, _icHostRegs_ + 4*25 # + # sw $26, _icRegs_ + 4*26 # k0 + # lw $26, _icHostRegs_ + 4*26 # + # sw $27, _icRegs_ + 4*27 # k1 + # lw $27, _icHostRegs_ + 4*27 # + sw $28, _icRegs_ + 4*28 # gp + lw $28, _icHostRegs_ + 4*28 # + sw $29, _icRegs_ + 4*29 # sp + # lw $29, _icHostRegs_ + 4*29 # + # Make sure sp is updated "atomically" and not part by part + .set noat + lw $1, _icHostRegs_ + 4*29 # + move $29, $1 + .set at + sw $30, _icRegs_ + 4*30 + lw $30, _icHostRegs_ + 4*30 + # sw $31, _icRegs_ + 4*31 # ra + # lw $31, _icHostRegs_ + 4*31 # + + li $2, 2 # success, 2 instructions skipped + j $31 + +$_icsyscall_error_: + # sw $1, _icRegs_ + 4*1 # ar + # lw $1, _icHostRegs_ + 4*1 # + sw $2, _icRegs_ + 4*2 # v0 + # lw $2, _icHostRegs_ + 4*2 # + sw $3, _icRegs_ + 4*3 # v1 + # lw $3, _icHostRegs_ + 4*3 # + sw $4, _icRegs_ + 4*4 # a0 + # lw $4, _icHostRegs_ + 4*4 # + sw $5, _icRegs_ + 4*5 # a1 + # lw $5, _icHostRegs_ + 4*5 # + sw $6, _icRegs_ + 4*6 # a2 + # lw $6, _icHostRegs_ + 4*6 # + sw $7, _icRegs_ + 4*7 # a3 + # lw $7, _icHostRegs_ + 4*7 # + sw $8, _icRegs_ + 4*8 # t0 + # lw $8, _icHostRegs_ + 4*8 # + sw $9, _icRegs_ + 4*9 # t1 + # lw $9, _icHostRegs_ + 4*9 # + sw $10, _icRegs_ + 4*10 # t2 + # lw $10, _icHostRegs_ + 4*10 # + sw $11, _icRegs_ + 4*11 # t3 + # lw $11, _icHostRegs_ + 4*11 # + sw $12, _icRegs_ + 4*12 # t4 + # lw $12, _icHostRegs_ + 4*12 # + sw $13, _icRegs_ + 4*13 # t5 + # lw $13, _icHostRegs_ + 4*13 # + sw $14, _icRegs_ + 4*14 # t6 + # lw $14, _icHostRegs_ + 4*14 # + sw $15, _icRegs_ + 4*15 # t7 + # lw $15, _icHostRegs_ + 4*15 # + sw $16, _icRegs_ + 4*16 + lw $16, _icHostRegs_ + 4*16 + sw $17, _icRegs_ + 4*17 + lw $17, _icHostRegs_ + 4*17 + sw $18, _icRegs_ + 4*18 + lw $18, _icHostRegs_ + 4*18 + sw $19, _icRegs_ + 4*19 + lw $19, _icHostRegs_ + 4*19 + sw $20, _icRegs_ + 4*20 + lw $20, _icHostRegs_ + 4*20 + sw $21, _icRegs_ + 4*21 + lw $21, _icHostRegs_ + 4*21 + sw $22, _icRegs_ + 4*22 + lw $22, _icHostRegs_ + 4*22 + sw $23, _icRegs_ + 4*23 + lw $23, _icHostRegs_ + 4*23 + sw $24, _icRegs_ + 4*24 # t8 + # lw $24, _icHostRegs_ + 4*24 # + sw $25, _icRegs_ + 4*25 # t9 + # lw $25, _icHostRegs_ + 4*25 # + # sw $26, _icRegs_ + 4*26 # k0 + # lw $26, _icHostRegs_ + 4*26 # + # sw $27, _icRegs_ + 4*27 # k1 + # lw $27, _icHostRegs_ + 4*27 # + sw $28, _icRegs_ + 4*28 # gp + lw $28, _icHostRegs_ + 4*28 # + sw $29, _icRegs_ + 4*29 # sp + # lw $29, _icHostRegs_ + 4*29 # + # Make sure sp is updated "atomically" and not part by part + .set noat + lw $1, _icHostRegs_ + 4*29 # + move $29, $1 # + .set at + sw $30, _icRegs_ + 4*30 + lw $30, _icHostRegs_ + 4*30 + # sw $31, _icRegs_ + 4*31 # ra + # lw $31, _icHostRegs_ + 4*31 # + + li $2, 0 # failure, 0 instructions skipped + j $31 diff --git a/src/libicache/license.txt b/src/libicache/license.txt new file mode 100644 index 0000000..449e8ed --- /dev/null +++ b/src/libicache/license.txt @@ -0,0 +1,26 @@ +Copyright (c) 2013, Alexey Frunze +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +The views and conclusions contained in the software and documentation are those +of the authors and should not be interpreted as representing official policies, +either expressed or implied, of the FreeBSD Project. diff --git a/src/libicache/readme.txt b/src/libicache/readme.txt new file mode 100644 index 0000000..8cdb63b --- /dev/null +++ b/src/libicache/readme.txt @@ -0,0 +1,10 @@ +icache is a MIPS emulator + software instruction cache. + +With it one may be able to run large programs on MIPS32 processors +that would otherwise not fit into small on-chip RAMs of ~128KB. + +Supported platform: RetroBSD. +http://www.retrobsd.org/ + +See the Wiki for more up-to-date details: +http://github.com/alexfru/icacheMips/wiki diff --git a/src/libm/Makefile b/src/libm/Makefile new file mode 100644 index 0000000..1a70446 --- /dev/null +++ b/src/libm/Makefile @@ -0,0 +1,31 @@ +TOPSRC = $(shell cd ../..; pwd) +include $(TOPSRC)/target.mk + +CFLAGS += ${DEFS} -Werror -Wall + +SRCS = login.c logout.c logwtmp.c +OBJS = asin.o atan.o exp.o erf.o floor.o fmod.o hypot.o j0.o j1.o \ + jn.o log.o pow.o sin.o sinh.o sqrt.o tan.o tanh.o + +all: ../libm.a + +../libm.a: ${OBJS} + $(AR) cru $@ ${OBJS} + $(RANLIB) $@ + +install: all +# ${INSTALLDIR} ${DESTDIR}/lib +# ${INSTALL} ../libm.a ${DESTDIR}/lib/libm.a +# $(RANLIB) ${DESTDIR}/lib/libm.a + +clean: + rm -f ../libm.a *.o *~ tags + +cleandir: clean + rm -f .depend + +depend: + mkdep ${CFLAGS} ${SRCS} + +tags: + ctags ${SRCS} diff --git a/src/libm/asin.c b/src/libm/asin.c new file mode 100644 index 0000000..8373f93 --- /dev/null +++ b/src/libm/asin.c @@ -0,0 +1,53 @@ +/* + * asin(arg) and acos(arg) return the arcsin, arccos, + * respectively of their arguments. + * + * Arctan is called after appropriate range reduction. + */ +#include +#include + +int errno; + +static double pio2 = 1.570796326794896619; + +double +asin(arg) + double arg; +{ + double sign, temp; + + sign = 1.; + if(arg <0){ + arg = -arg; + sign = -1.; + } + + if(arg > 1.){ + errno = EDOM; + return(0.); + } + + temp = sqrt(1. - arg*arg); + if(arg > 0.7) + temp = pio2 - atan(temp/arg); + else + temp = atan(arg/temp); + + return(sign*temp); +} + +double +acos(arg) + double arg; +{ + if(arg < 0) + arg = -arg; + + if(arg > 1.){ + errno = EDOM; + return(0.); + } + + return(pio2 - asin(arg)); +} diff --git a/src/libm/atan.c b/src/libm/atan.c new file mode 100644 index 0000000..a249167 --- /dev/null +++ b/src/libm/atan.c @@ -0,0 +1,99 @@ +/* + * floating-point arctangent + * + * atan returns the value of the arctangent of its + * argument in the range [-pi/2,pi/2]. + * + * atan2 returns the arctangent of arg1/arg2 + * in the range [-pi,pi]. + * + * there are no error returns. + * + * coefficients are #5077 from Hart & Cheney. (19.56D) + */ +#include + +double static sq2p1 =2.414213562373095048802e0; +static double sq2m1 = .414213562373095048802e0; +static double pio2 =1.570796326794896619231e0; +static double pio4 = .785398163397448309615e0; +static double p4 = .161536412982230228262e2; +static double p3 = .26842548195503973794141e3; +static double p2 = .11530293515404850115428136e4; +static double p1 = .178040631643319697105464587e4; +static double p0 = .89678597403663861959987488e3; +static double q4 = .5895697050844462222791e2; +static double q3 = .536265374031215315104235e3; +static double q2 = .16667838148816337184521798e4; +static double q1 = .207933497444540981287275926e4; +static double q0 = .89678597403663861962481162e3; + +/* + * xatan evaluates a series valid in the + * range [-0.414...,+0.414...]. + */ +static double +xatan(arg) +double arg; +{ + double argsq; + double value; + + argsq = arg*arg; + value = ((((p4*argsq + p3)*argsq + p2)*argsq + p1)*argsq + p0); + value = value/(((((argsq + q4)*argsq + q3)*argsq + q2)*argsq + q1)*argsq + q0); + return(value*arg); +} + +/* + * satan reduces its argument (known to be positive) + * to the range [0,0.414...] and calls xatan. + */ +static double +satan(arg) +double arg; +{ + if(arg < sq2m1) + return(xatan(arg)); + else if(arg > sq2p1) + return(pio2 - xatan(1.0/arg)); + else + return(pio4 + xatan((arg-1.0)/(arg+1.0))); +} + +/* + * atan makes its argument positive and + * calls the inner routine satan. + */ +double +atan(arg) +double arg; +{ + if(arg>0) + return(satan(arg)); + else + return(-satan(-arg)); +} + + +/* + * atan2 discovers what quadrant the angle + * is in and calls atan. + */ +double +atan2(arg1,arg2) +double arg1,arg2; +{ + if((arg1+arg2)==arg1) + if(arg1 >= 0.) return(pio2); + else return(-pio2); + else if(arg2 <0.) + if(arg1 >= 0.) + return(pio2+pio2 - satan(-arg1/arg2)); + else + return(-pio2-pio2 + satan(arg1/arg2)); + else if(arg1>0) + return(satan(arg1/arg2)); + else + return(-satan(-arg1/arg2)); +} diff --git a/src/libm/erf.c b/src/libm/erf.c new file mode 100644 index 0000000..e83bbd3 --- /dev/null +++ b/src/libm/erf.c @@ -0,0 +1,118 @@ +/* + * C program for floating point error function + * + * erf(x) returns the error function of its argument + * erfc(x) returns 1.0-erf(x) + * + * erf(x) is defined by + * ${2 over sqrt(pi)} int from 0 to x e sup {-t sup 2} dt$ + * + * the entry for erfc is provided because of the + * extreme loss of relative accuracy if erf(x) is + * called for large x and the result subtracted + * from 1. (e.g. for x= 10, 12 places are lost). + * + * There are no error returns. + * + * Calls exp. + * + * Coefficients for large x are #5667 from Hart & Cheney (18.72D). + */ +#include + +#define M 7 +#define N 9 + +int errno; +static double torp = 1.1283791670955125738961589031; +static double p1[] = { + 0.804373630960840172832162e5, + 0.740407142710151470082064e4, + 0.301782788536507577809226e4, + 0.380140318123903008244444e2, + 0.143383842191748205576712e2, + -.288805137207594084924010e0, + 0.007547728033418631287834e0, +}; +static double q1[] = { + 0.804373630960840172826266e5, + 0.342165257924628539769006e5, + 0.637960017324428279487120e4, + 0.658070155459240506326937e3, + 0.380190713951939403753468e2, + 0.100000000000000000000000e1, + 0.0, +}; +static double p2[] = { + 0.18263348842295112592168999e4, + 0.28980293292167655611275846e4, + 0.2320439590251635247384768711e4, + 0.1143262070703886173606073338e4, + 0.3685196154710010637133875746e3, + 0.7708161730368428609781633646e2, + 0.9675807882987265400604202961e1, + 0.5641877825507397413087057563e0, + 0.0, +}; +static double q2[] = { + 0.18263348842295112595576438e4, + 0.495882756472114071495438422e4, + 0.60895424232724435504633068e4, + 0.4429612803883682726711528526e4, + 0.2094384367789539593790281779e4, + 0.6617361207107653469211984771e3, + 0.1371255960500622202878443578e3, + 0.1714980943627607849376131193e2, + 1.0, +}; + +double +erf(arg) double arg;{ + double erfc(); + int sign; + double argsq; + double d, n; + int i; + + errno = 0; + sign = 1; + if(arg < 0.){ + arg = -arg; + sign = -1; + } + if(arg < 0.5){ + argsq = arg*arg; + for(n=0,d=0,i=M-1; i>=0; i--){ + n = n*argsq + p1[i]; + d = d*argsq + q1[i]; + } + return(sign*torp*arg*n/d); + } + if(arg >= 10.) + return(sign*1.); + return(sign*(1. - erfc(arg))); +} + +double +erfc(arg) double arg;{ + double erf(); + double exp(); + double n, d; + int i; + + errno = 0; + if(arg < 0.) + return(2. - erfc(-arg)); +/* + if(arg < 0.5) + return(1. - erf(arg)); +*/ + if(arg >= 10.) + return(0.); + + for(n=0,d=0,i=N-1; i>=0; i--){ + n = n*arg + p2[i]; + d = d*arg + q2[i]; + } + return(exp(-arg*arg)*n/d); +} diff --git a/src/libm/exp.c b/src/libm/exp.c new file mode 100644 index 0000000..a72fc2b --- /dev/null +++ b/src/libm/exp.c @@ -0,0 +1,44 @@ +/* + * exp returns the exponential function of its + * floating-point argument. + * + * The coefficients are #1069 from Hart and Cheney. (22.35D) + */ +#include +#include + +int errno; +static double p0 = .2080384346694663001443843411e7; +static double p1 = .3028697169744036299076048876e5; +static double p2 = .6061485330061080841615584556e2; +static double q0 = .6002720360238832528230907598e7; +static double q1 = .3277251518082914423057964422e6; +static double q2 = .1749287689093076403844945335e4; +static double log2e = 1.4426950408889634073599247; +static double sqrt2 = 1.4142135623730950488016887; +static double maxf = 10000; + +double +exp(arg) +double arg; +{ + double fract; + double temp1, temp2, xsq; + int ent; + + if(arg == 0.) + return(1.); + if(arg < -maxf) + return(0.); + if(arg > maxf) { + errno = ERANGE; + return(HUGE); + } + arg *= log2e; + ent = floor(arg); + fract = (arg-ent) - 0.5; + xsq = fract*fract; + temp1 = ((p2*xsq+p1)*xsq+p0)*fract; + temp2 = ((1.0*xsq+q2)*xsq+q1)*xsq + q0; + return(ldexp(sqrt2*(temp2+temp1)/(temp2-temp1), ent)); +} diff --git a/src/libm/fabs.c b/src/libm/fabs.c new file mode 100644 index 0000000..c84a7dc --- /dev/null +++ b/src/libm/fabs.c @@ -0,0 +1,11 @@ +#include + +double +fabs(arg) + double arg; +{ + + if(arg < 0.) + arg = -arg; + return(arg); +} diff --git a/src/libm/floor.c b/src/libm/floor.c new file mode 100644 index 0000000..67fb9d7 --- /dev/null +++ b/src/libm/floor.c @@ -0,0 +1,29 @@ +/* + * floor and ceil-- greatest integer <= arg + * (resp least >=) + */ +#include + +double +floor(d) + double d; +{ + double fract; + + if (d<0.0) { + d = -d; + fract = modf(d, &d); + if (fract != 0.0) + d += 1; + d = -d; + } else + modf(d, &d); + return(d); +} + +double +ceil(d) + double d; +{ + return(-floor(-d)); +} diff --git a/src/libm/fmod.c b/src/libm/fmod.c new file mode 100644 index 0000000..cc46ffb --- /dev/null +++ b/src/libm/fmod.c @@ -0,0 +1,111 @@ +#include +#include + +#include "ieee.h" + +static const double one = 1.0, Zero[] = {0.0, -0.0,}; + +double fmod(double x, double y) +{ + int32_t n=0,hx=0,hy=0,hz=0,ix=0,iy=0,sx=0,i=0; + uint32_t lx=0,ly=0,lz=0; + + EXTRACT_WORDS(hx,lx,x); + EXTRACT_WORDS(hy,ly,y); + sx = hx&0x80000000; /* sign of x */ + hx ^=sx; /* |x| */ + hy &= 0x7fffffff; /* |y| */ + + /* purge off exception values */ + if((hy|ly)==0||(hx>=0x7ff00000)|| /* y=0,or x not finite */ + ((hy|((ly|-ly)>>31))>0x7ff00000)) /* or y is NaN */ + return (x*y)/(x*y); + if(hx<=hy) { + if((hx>31]; /* |x|=|y| return x*0*/ + } + + /* determine ix = ilogb(x) */ + if(hx<0x00100000) { /* subnormal x */ + if(hx==0) { + for (ix = -1043, i=lx; i>0; i<<=1) ix -=1; + } else { + for (ix = -1022,i=(hx<<11); i>0; i<<=1) ix -=1; + } + } else ix = (hx>>20)-1023; + + /* determine iy = ilogb(y) */ + if(hy<0x00100000) { /* subnormal y */ + if(hy==0) { + for (iy = -1043, i=ly; i>0; i<<=1) iy -=1; + } else { + for (iy = -1022,i=(hy<<11); i>0; i<<=1) iy -=1; + } + } else iy = (hy>>20)-1023; + + /* set up {hx,lx}, {hy,ly} and align y to x */ + if(ix >= -1022) + hx = 0x00100000|(0x000fffff&hx); + else { /* subnormal x, shift x to normal */ + n = -1022-ix; + if(n<=31) { + hx = (hx<>(32-n)); + lx <<= n; + } else { + hx = lx<<(n-32); + lx = 0; + } + } + if(iy >= -1022) + hy = 0x00100000|(0x000fffff&hy); + else { /* subnormal y, shift y to normal */ + n = -1022-iy; + if(n<=31) { + hy = (hy<>(32-n)); + ly <<= n; + } else { + hy = ly<<(n-32); + ly = 0; + } + } + + /* fix point fmod */ + n = ix - iy; + while(n--) { + hz=hx-hy;lz=lx-ly; if(lx>31); lx = lx+lx;} + else { + if((hz|lz)==0) /* return sign(x)*0 */ + return Zero[(uint32_t)sx>>31]; + hx = hz+hz+(lz>>31); lx = lz+lz; + } + } + hz=hx-hy;lz=lx-ly; if(lx=0) {hx=hz;lx=lz;} + + /* convert back to floating value and restore the sign */ + if((hx|lx)==0) /* return sign(x)*0 */ + return Zero[(uint32_t)sx>>31]; + while(hx<0x00100000) { /* normalize x */ + hx = hx+hx+(lx>>31); lx = lx+lx; + iy -= 1; + } + if(iy>= -1022) { /* normalize output */ + hx = ((hx-0x00100000)|((iy+1023)<<20)); + INSERT_WORDS(x,hx|sx,lx); + } else { /* subnormal output */ + n = -1022 - iy; + if(n<=20) { + lx = (lx>>n)|((uint32_t)hx<<(32-n)); + hx >>= n; + } else if (n<=31) { + lx = (hx<<(32-n))|(lx>>n); hx = sx; + } else { + lx = hx>>(n-32); hx = sx; + } + INSERT_WORDS(x,hx|sx,lx); + x *= one; /* create necessary signal */ + } + return x; /* exact output */ +} diff --git a/src/libm/hypot.c b/src/libm/hypot.c new file mode 100644 index 0000000..88854c8 --- /dev/null +++ b/src/libm/hypot.c @@ -0,0 +1,45 @@ +/* + * sqrt(a^2 + b^2) + * (but carefully) + */ +#include + +double +hypot(a, b) + double a, b; +{ + double t; + + if (a < 0) + a = -a; + if (b < 0) + b = -b; + if (a > b) { + t = a; + a = b; + b = t; + } + if (b==0) + return(0.); + a /= b; + /* + * pathological overflow possible + * in the next line. + */ + return(b*sqrt(1. + a*a)); +} + +#if 0 +struct complex +{ + double r; + double i; +}; + +double +cabs(arg) + struct complex arg; +{ + return(hypot(arg.r, arg.i)); +} +#endif diff --git a/src/libm/ieee.h b/src/libm/ieee.h new file mode 100644 index 0000000..20a8eee --- /dev/null +++ b/src/libm/ieee.h @@ -0,0 +1,23 @@ +/* Get two 32 bit ints from a double. */ + +#define EXTRACT_WORDS(high,low,d) \ + high = *(unsigned long long*) &d; \ + low = (*(unsigned long long*) &d) >> 32 + + +/* Set a double from two 32 bit ints. */ + +#define INSERT_WORDS(d,high,low) \ + *(unsigned long long*) &(x) = (unsigned long long) (high) << 32 | (low) + + +typedef union +{ + double value; + struct + { + uint32_t lsw; + uint32_t msw; + } parts; +} ieee_double_shape_type; + diff --git a/src/libm/j0.c b/src/libm/j0.c new file mode 100644 index 0000000..6775fd6 --- /dev/null +++ b/src/libm/j0.c @@ -0,0 +1,192 @@ +/* + * floating point Bessel's function + * of the first and second kinds + * of order zero + * + * j0(x) returns the value of J0(x) + * for all real values of x. + * + * There are no error returns. + * Calls sin, cos, sqrt. + * + * There is a niggling bug in J0 which + * causes errors up to 2e-16 for x in the + * interval [-8,8]. + * The bug is caused by an inappropriate order + * of summation of the series. rhm will fix it + * someday. + * + * Coefficients are from Hart & Cheney. + * #5849 (19.22D) + * #6549 (19.25D) + * #6949 (19.41D) + * + * y0(x) returns the value of Y0(x) + * for positive real values of x. + * For x<=0, error number EDOM is set and a + * large negative value is returned. + * + * Calls sin, cos, sqrt, log, j0. + * + * The values of Y0 have not been checked + * to more than ten places. + * + * Coefficients are from Hart & Cheney. + * #6245 (18.78D) + * #6549 (19.25D) + * #6949 (19.41D) + */ +#include +#include + +int errno; +static double pzero, qzero; +static double tpi = .6366197723675813430755350535e0; +static double pio4 = .7853981633974483096156608458e0; +static double p1[] = { + 0.4933787251794133561816813446e21, + -.1179157629107610536038440800e21, + 0.6382059341072356562289432465e19, + -.1367620353088171386865416609e18, + 0.1434354939140344111664316553e16, + -.8085222034853793871199468171e13, + 0.2507158285536881945555156435e11, + -.4050412371833132706360663322e8, + 0.2685786856980014981415848441e5, +}; +static double q1[] = { + 0.4933787251794133562113278438e21, + 0.5428918384092285160200195092e19, + 0.3024635616709462698627330784e17, + 0.1127756739679798507056031594e15, + 0.3123043114941213172572469442e12, + 0.6699987672982239671814028660e9, + 0.1114636098462985378182402543e7, + 0.1363063652328970604442810507e4, + 1.0 +}; +static double p2[] = { + 0.5393485083869438325262122897e7, + 0.1233238476817638145232406055e8, + 0.8413041456550439208464315611e7, + 0.2016135283049983642487182349e7, + 0.1539826532623911470917825993e6, + 0.2485271928957404011288128951e4, + 0.0, +}; +static double q2[] = { + 0.5393485083869438325560444960e7, + 0.1233831022786324960844856182e8, + 0.8426449050629797331554404810e7, + 0.2025066801570134013891035236e7, + 0.1560017276940030940592769933e6, + 0.2615700736920839685159081813e4, + 1.0, +}; +static double p3[] = { + -.3984617357595222463506790588e4, + -.1038141698748464093880530341e5, + -.8239066313485606568803548860e4, + -.2365956170779108192723612816e4, + -.2262630641933704113967255053e3, + -.4887199395841261531199129300e1, + 0.0, +}; +static double q3[] = { + 0.2550155108860942382983170882e6, + 0.6667454239319826986004038103e6, + 0.5332913634216897168722255057e6, + 0.1560213206679291652539287109e6, + 0.1570489191515395519392882766e5, + 0.4087714673983499223402830260e3, + 1.0, +}; +static double p4[] = { + -.2750286678629109583701933175e20, + 0.6587473275719554925999402049e20, + -.5247065581112764941297350814e19, + 0.1375624316399344078571335453e18, + -.1648605817185729473122082537e16, + 0.1025520859686394284509167421e14, + -.3436371222979040378171030138e11, + 0.5915213465686889654273830069e8, + -.4137035497933148554125235152e5, +}; +static double q4[] = { + 0.3726458838986165881989980e21, + 0.4192417043410839973904769661e19, + 0.2392883043499781857439356652e17, + 0.9162038034075185262489147968e14, + 0.2613065755041081249568482092e12, + 0.5795122640700729537480087915e9, + 0.1001702641288906265666651753e7, + 0.1282452772478993804176329391e4, + 1.0, +}; + +static void +asympt(arg) + double arg; +{ + double zsq, n, d; + int i; + zsq = 64./(arg*arg); + for(n=0,d=0,i=6;i>=0;i--){ + n = n*zsq + p2[i]; + d = d*zsq + q2[i]; + } + pzero = n/d; + for(n=0,d=0,i=6;i>=0;i--){ + n = n*zsq + p3[i]; + d = d*zsq + q3[i]; + } + qzero = (8./arg)*(n/d); +} + +double +j0(arg) + double arg; +{ + double argsq, n, d; + double sin(), cos(), sqrt(); + int i; + + if(arg < 0.) arg = -arg; + if(arg > 8.){ + asympt(arg); + n = arg - pio4; + return(sqrt(tpi/arg)*(pzero*cos(n) - qzero*sin(n))); + } + argsq = arg*arg; + for(n=0,d=0,i=8;i>=0;i--){ + n = n*argsq + p1[i]; + d = d*argsq + q1[i]; + } + return(n/d); +} + +double +y0(arg) + double arg; +{ + double argsq, n, d; + double sin(), cos(), sqrt(), log(), j0(); + int i; + + errno = 0; + if(arg <= 0.){ + errno = EDOM; + return(-HUGE); + } + if(arg > 8.){ + asympt(arg); + n = arg - pio4; + return(sqrt(tpi/arg)*(pzero*sin(n) + qzero*cos(n))); + } + argsq = arg*arg; + for(n=0,d=0,i=8;i>=0;i--){ + n = n*argsq + p4[i]; + d = d*argsq + q4[i]; + } + return(n/d + tpi*j0(arg)*log(arg)); +} diff --git a/src/libm/j1.c b/src/libm/j1.c new file mode 100644 index 0000000..4a70987 --- /dev/null +++ b/src/libm/j1.c @@ -0,0 +1,198 @@ +/* + * floating point Bessel's function + * of the first and second kinds + * of order one + * + * j1(x) returns the value of J1(x) + * for all real values of x. + * + * There are no error returns. + * Calls sin, cos, sqrt. + * + * There is a niggling bug in J1 which + * causes errors up to 2e-16 for x in the + * interval [-8,8]. + * The bug is caused by an inappropriate order + * of summation of the series. rhm will fix it + * someday. + * + * Coefficients are from Hart & Cheney. + * #6050 (20.98D) + * #6750 (19.19D) + * #7150 (19.35D) + * + * y1(x) returns the value of Y1(x) + * for positive real values of x. + * For x<=0, error number EDOM is set and a + * large negative value is returned. + * + * Calls sin, cos, sqrt, log, j1. + * + * The values of Y1 have not been checked + * to more than ten places. + * + * Coefficients are from Hart & Cheney. + * #6447 (22.18D) + * #6750 (19.19D) + * #7150 (19.35D) + */ +#include +#include + +int errno; +static double pzero, qzero; +static double tpi = .6366197723675813430755350535e0; +static double pio4 = .7853981633974483096156608458e0; +static double p1[] = { + 0.581199354001606143928050809e21, + -.6672106568924916298020941484e20, + 0.2316433580634002297931815435e19, + -.3588817569910106050743641413e17, + 0.2908795263834775409737601689e15, + -.1322983480332126453125473247e13, + 0.3413234182301700539091292655e10, + -.4695753530642995859767162166e7, + 0.2701122710892323414856790990e4, +}; +static double q1[] = { + 0.1162398708003212287858529400e22, + 0.1185770712190320999837113348e20, + 0.6092061398917521746105196863e17, + 0.2081661221307607351240184229e15, + 0.5243710262167649715406728642e12, + 0.1013863514358673989967045588e10, + 0.1501793594998585505921097578e7, + 0.1606931573481487801970916749e4, + 1.0, +}; +static double p2[] = { + -.4435757816794127857114720794e7, + -.9942246505077641195658377899e7, + -.6603373248364939109255245434e7, + -.1523529351181137383255105722e7, + -.1098240554345934672737413139e6, + -.1611616644324610116477412898e4, + 0.0, +}; +static double q2[] = { + -.4435757816794127856828016962e7, + -.9934124389934585658967556309e7, + -.6585339479723087072826915069e7, + -.1511809506634160881644546358e7, + -.1072638599110382011903063867e6, + -.1455009440190496182453565068e4, + 1.0, +}; +static double p3[] = { + 0.3322091340985722351859704442e5, + 0.8514516067533570196555001171e5, + 0.6617883658127083517939992166e5, + 0.1849426287322386679652009819e5, + 0.1706375429020768002061283546e4, + 0.3526513384663603218592175580e2, + 0.0, +}; +static double q3[] = { + 0.7087128194102874357377502472e6, + 0.1819458042243997298924553839e7, + 0.1419460669603720892855755253e7, + 0.4002944358226697511708610813e6, + 0.3789022974577220264142952256e5, + 0.8638367769604990967475517183e3, + 1.0, +}; +static double p4[] = { + -.9963753424306922225996744354e23, + 0.2655473831434854326894248968e23, + -.1212297555414509577913561535e22, + 0.2193107339917797592111427556e20, + -.1965887462722140658820322248e18, + 0.9569930239921683481121552788e15, + -.2580681702194450950541426399e13, + 0.3639488548124002058278999428e10, + -.2108847540133123652824139923e7, + 0.0, +}; +static double q4[] = { + 0.5082067366941243245314424152e24, + 0.5435310377188854170800653097e22, + 0.2954987935897148674290758119e20, + 0.1082258259408819552553850180e18, + 0.2976632125647276729292742282e15, + 0.6465340881265275571961681500e12, + 0.1128686837169442121732366891e10, + 0.1563282754899580604737366452e7, + 0.1612361029677000859332072312e4, + 1.0, +}; + +static void +asympt(arg) + double arg; +{ + double zsq, n, d; + int i; + zsq = 64./(arg*arg); + for(n=0,d=0,i=6;i>=0;i--){ + n = n*zsq + p2[i]; + d = d*zsq + q2[i]; + } + pzero = n/d; + for(n=0,d=0,i=6;i>=0;i--){ + n = n*zsq + p3[i]; + d = d*zsq + q3[i]; + } + qzero = (8./arg)*(n/d); +} + +double +j1(arg) + double arg; +{ + double xsq, n, d, x; + double sin(), cos(), sqrt(); + int i; + + x = arg; + if(x < 0.) x = -x; + if(x > 8.){ + asympt(x); + n = x - 3.*pio4; + n = sqrt(tpi/x)*(pzero*cos(n) - qzero*sin(n)); + if(arg <0.) n = -n; + return(n); + } + xsq = x*x; + for(n=0,d=0,i=8;i>=0;i--){ + n = n*xsq + p1[i]; + d = d*xsq + q1[i]; + } + return(arg*n/d); +} + +double +y1(arg) + double arg; +{ + double xsq, n, d, x; + double sin(), cos(), sqrt(), log(), j1(); + int i; + + errno = 0; + x = arg; + if(x <= 0.){ + errno = EDOM; + return(-HUGE); + } + if(x > 8.){ + asympt(x); + n = x - 3*pio4; + return(sqrt(tpi/x)*(pzero*sin(n) + qzero*cos(n))); + } + xsq = x*x; + for(n=0,d=0,i=9;i>=0;i--){ + n = n*xsq + p4[i]; + d = d*xsq + q4[i]; + } + return(x*n/d + tpi*(j1(x)*log(x)-1./x)); +} diff --git a/src/libm/jn.c b/src/libm/jn.c new file mode 100644 index 0000000..d58f187 --- /dev/null +++ b/src/libm/jn.c @@ -0,0 +1,103 @@ +/* + * floating point Bessel's function of + * the first and second kinds and of integer order. + * + * int n; + * double x; + * jn(n,x); + * + * returns the value of Jn(x) for all + * integer values of n and all real values of x. + * + * There are no error returns. + * Calls j0, j1. + * + * For n=0, j0(x) is called, + * for n=1, j1(x) is called, + * for nx, a continued fraction approximation to + * j(n,x)/j(n-1,x) is evaluated and then backward + * recursion is used starting from a supposed value + * for j(n,x). The resulting value of j(0,x) is + * compared with the actual value to correct the + * supposed value of j(n,x). + * + * yn(n,x) is similar in all respects, except + * that forward recursion is used for all values of n>1. + */ +#include +#include + +int errno; + +double +jn(n,x) int n; double x;{ + int i; + double a, b, temp; + double xsq, t; + double j0(), j1(); + + if(n<0){ + n = -n; + x = -x; + } + if(n==0) return(j0(x)); + if(n==1) return(j1(x)); + if(x == 0.) return(0.); + if(n>x) goto recurs; + + a = j0(x); + b = j1(x); + for(i=1;in;i--){ + t = xsq/(2.*i - t); + } + t = x/(2.*n-t); + + a = t; + b = 1; + for(i=n-1;i>0;i--){ + temp = b; + b = (2.*i/x)*b - a; + a = temp; + } + return(t*j0(x)/b); +} + +double +yn(n,x) int n; double x;{ + int i; + int sign; + double a, b, temp; + double y0(), y1(); + + if (x <= 0) { + errno = EDOM; + return(-HUGE); + } + sign = 1; + if(n<0){ + n = -n; + if(n%2 == 1) sign = -1; + } + if(n==0) return(y0(x)); + if(n==1) return(sign*y1(x)); + + a = y0(x); + b = y1(x); + for(i=1;i +#include + +int errno; + +static double log2 = 0.693147180559945309e0; +static double ln10 = 2.302585092994045684; +static double sqrto2 = 0.707106781186547524e0; +static double p0 = -.240139179559210510e2; +static double p1 = 0.309572928215376501e2; +static double p2 = -.963769093368686593e1; +static double p3 = 0.421087371217979714e0; +static double q0 = -.120069589779605255e2; +static double q1 = 0.194809660700889731e2; +static double q2 = -.891110902798312337e1; + +double +log(arg) +double arg; +{ + double x,z, zsq, temp; + int exp; + + if(arg <= 0.) { + errno = EDOM; + return(-HUGE); + } + x = frexp(arg,&exp); + while(x<0.5) { + x = x*2; + exp = exp-1; + } + if(x +#include + +int errno; + +double +pow(arg1,arg2) + double arg1, arg2; +{ + double temp; + long l; + + if(arg1 <= 0.) { + if(arg1 == 0.) { + if(arg2 <= 0.) + goto domain; + return(0.); + } + l = arg2; + if(l != arg2) + goto domain; + temp = exp(arg2 * log(-arg1)); + if(l & 1) + temp = -temp; + return(temp); + } + return(exp(arg2 * log(arg1))); + +domain: + errno = EDOM; + return(0.); +} diff --git a/src/libm/sin.c b/src/libm/sin.c new file mode 100644 index 0000000..f08c64f --- /dev/null +++ b/src/libm/sin.c @@ -0,0 +1,75 @@ +/* + * C program for floating point sin/cos. + * Calls modf. + * There are no error exits. + * Coefficients are #3370 from Hart & Cheney (18.80D). + */ +#include + +static double twoopi = 0.63661977236758134308; +static double p0 = .1357884097877375669092680e8; +static double p1 = -.4942908100902844161158627e7; +static double p2 = .4401030535375266501944918e6; +static double p3 = -.1384727249982452873054457e5; +static double p4 = .1459688406665768722226959e3; +static double q0 = .8644558652922534429915149e7; +static double q1 = .4081792252343299749395779e6; +static double q2 = .9463096101538208180571257e4; +static double q3 = .1326534908786136358911494e3; + +static double +sinus(arg, quad) + double arg; + int quad; +{ + double modf(); + double e, f; + double ysq; + double x,y; + int k; + double temp1, temp2; + + x = arg; + if(x<0) { + x = -x; + quad = quad + 2; + } + x = x*twoopi; /*underflow?*/ + if(x>32764){ + y = modf(x,&e); + e = e + quad; + modf(0.25*e,&f); + quad = e - 4*f; + }else{ + k = x; + y = x - k; + quad = (quad + k) & 03; + } + if (quad & 01) + y = 1-y; + if(quad > 1) + y = -y; + + ysq = y*y; + temp1 = ((((p4*ysq+p3)*ysq+p2)*ysq+p1)*ysq+p0)*y; + temp2 = ((((ysq+q3)*ysq+q2)*ysq+q1)*ysq+q0); + return(temp1/temp2); +} + +double +cos(arg) + double arg; +{ + double sinus(); + if(arg<0) + arg = -arg; + return(sinus(arg, 1)); +} + +double +sin(arg) + double arg; +{ + double sinus(); + return(sinus(arg, 0)); +} diff --git a/src/libm/sinh.c b/src/libm/sinh.c new file mode 100644 index 0000000..a78dd8b --- /dev/null +++ b/src/libm/sinh.c @@ -0,0 +1,66 @@ +/* + * sinh(arg) returns the hyperbolic sine of its floating- + * point argument. + * + * The exponential function is called for arguments + * greater in magnitude than 0.5. + * + * A series is used for arguments smaller in magnitude than 0.5. + * The coefficients are #2029 from Hart & Cheney. (20.36D) + * + * cosh(arg) is computed from the exponential function for + * all arguments. + */ +#include + +static double p0 = -0.6307673640497716991184787251e+6; +static double p1 = -0.8991272022039509355398013511e+5; +static double p2 = -0.2894211355989563807284660366e+4; +static double p3 = -0.2630563213397497062819489e+2; +static double q0 = -0.6307673640497716991212077277e+6; +static double q1 = 0.1521517378790019070696485176e+5; +static double q2 = -0.173678953558233699533450911e+3; + +double +sinh(arg) + double arg; +{ + double temp, argsq; + register int sign; + + sign = 1; + if(arg < 0) { + arg = - arg; + sign = -1; + } + + if(arg > 21.) { + temp = exp(arg)/2; + if (sign>0) + return(temp); + else + return(-temp); + } + + if(arg > 0.5) { + return(sign*(exp(arg) - exp(-arg))/2); + } + + argsq = arg*arg; + temp = (((p3*argsq+p2)*argsq+p1)*argsq+p0)*arg; + temp /= (((argsq+q2)*argsq+q1)*argsq+q0); + return(sign*temp); +} + +double +cosh(arg) + double arg; +{ + if(arg < 0) + arg = - arg; + if(arg > 21.) { + return(exp(arg)/2); + } + + return((exp(arg) + exp(-arg))/2); +} diff --git a/src/libm/sqrt.c b/src/libm/sqrt.c new file mode 100644 index 0000000..a025bbe --- /dev/null +++ b/src/libm/sqrt.c @@ -0,0 +1,55 @@ +/* + * sqrt returns the square root of its floating + * point argument. Newton's method. + * + * calls frexp + */ +#include +#include + +int errno; + +double +sqrt(arg) + double arg; +{ + double x, temp; + int exp; + int i; + + if(arg <= 0.) { + if(arg < 0.) + errno = EDOM; + return(0.); + } + x = frexp(arg,&exp); + while(x < 0.5) { + x *= 2; + exp--; + } + /* + * NOTE + * this wont work on 1's comp + */ + if(exp & 1) { + x *= 2; + exp--; + } + temp = 0.5*(1.0+x); + + while(exp > 60) { + temp *= (1L<<30); + exp -= 60; + } + while(exp < -60) { + temp /= (1L<<30); + exp += 60; + } + if(exp >= 0) + temp *= 1L << (exp/2); + else + temp /= 1L << (-exp/2); + for(i=0; i<=4; i++) + temp = 0.5*(temp + arg/temp); + return(temp); +} diff --git a/src/libm/tan.c b/src/libm/tan.c new file mode 100644 index 0000000..8c76123 --- /dev/null +++ b/src/libm/tan.c @@ -0,0 +1,73 @@ +/* + * floating point tangent + * + * A series is used after range reduction. + * Coefficients are #4285 from Hart & Cheney. (19.74D) + */ +#include +#include + +int errno; + +static double invpi = 1.27323954473516268; +static double p0 = -0.1306820264754825668269611177e+5; +static double p1 = 0.1055970901714953193602353981e+4; +static double p2 = -0.1550685653483266376941705728e+2; +static double p3 = 0.3422554387241003435328470489e-1; +static double p4 = 0.3386638642677172096076369e-4; +static double q0 = -0.1663895238947119001851464661e+5; +static double q1 = 0.4765751362916483698926655581e+4; +static double q2 = -0.1555033164031709966900124574e+3; + +double +tan(arg) + double arg; +{ + double modf(); + double sign, temp, e, x, xsq; + int flag, i; + + flag = 0; + sign = 1.; + if(arg < 0.){ + arg = -arg; + sign = -1.; + } + arg = arg*invpi; /*overflow?*/ + x = modf(arg,&e); + i = e; + switch(i%4) { + case 1: + x = 1. - x; + flag = 1; + break; + + case 2: + sign = - sign; + flag = 1; + break; + + case 3: + x = 1. - x; + sign = - sign; + break; + + case 0: + break; + } + + xsq = x*x; + temp = ((((p4*xsq+p3)*xsq+p2)*xsq+p1)*xsq+p0)*x; + temp = temp/(((1.0*xsq+q2)*xsq+q1)*xsq+q0); + + if(flag == 1) { + if(temp == 0.) { + errno = ERANGE; + if (sign>0) + return(HUGE); + return(-HUGE); + } + temp = 1./temp; + } + return(sign*temp); +} diff --git a/src/libm/tanh.c b/src/libm/tanh.c new file mode 100644 index 0000000..f6a66dd --- /dev/null +++ b/src/libm/tanh.c @@ -0,0 +1,26 @@ +/* + * tanh(arg) computes the hyperbolic tangent of its floating + * point argument. + * + * sinh and cosh are called except for large arguments, which + * would cause overflow improperly. + */ +#include + +double +tanh(arg) + double arg; +{ + double sign; + + sign = 1.; + if(arg < 0.){ + arg = -arg; + sign = -1.; + } + + if(arg > 21.) + return(sign); + + return(sign*sinh(arg)/cosh(arg)); +} diff --git a/src/libtcl/Makefile b/src/libtcl/Makefile new file mode 100644 index 0000000..2e6378e --- /dev/null +++ b/src/libtcl/Makefile @@ -0,0 +1,40 @@ +TOPSRC = $(shell cd ../..; pwd) +include $(TOPSRC)/target.mk +#include $(TOPSRC)/cross.mk + +CFLAGS += ${DEFS} -Os -Wall -Werror -Wno-error=pointer-sign -Wno-pointer-sign +CFLAGS += -DTCL_FILE_CMDS -DTCL_ENV_CMDS + +OBJS = tclget.o tclproc.o tclvar.o tclassem.o \ + tclcmdah.o tclcmdmz.o tclhash.o tclparse.o \ + tclcmdil.o tclbasic.o tclexpr.o tclutil.o \ + regexp.o regsub.o tclenv.o tclglob.o \ + tclunxaz.o tcluxstr.o tcluxutl.o + +../libtcl.a: ${OBJS} + $(AR) cru $@ ${OBJS} + $(RANLIB) $@ + +clean: + rm -f ../libtcl.a *.o *~ + +### +regexp.o: regexp.c regexp.h regpriv.h +regsub.o: regsub.c regexp.h regpriv.h +tclassem.o: tclassem.c internal.h hash.h +tclbasic.o: tclbasic.c internal.h hash.h +tclcmdah.o: tclcmdah.c internal.h hash.h +tclcmdil.o: tclcmdil.c internal.h hash.h +tclcmdmz.o: tclcmdmz.c internal.h hash.h regexp.h regpriv.h +tclenv.o: tclenv.c internal.h hash.h +tclexpr.o: tclexpr.c internal.h hash.h +tclget.o: tclget.c internal.h hash.h +tclglob.o: tclglob.c internal.h hash.h +tclhash.o: tclhash.c internal.h hash.h +tclparse.o: tclparse.c internal.h hash.h +tclproc.o: tclproc.c internal.h hash.h +tclunxaz.o: tclunxaz.c internal.h hash.h +tclutil.o: tclutil.c internal.h hash.h regexp.h +tcluxstr.o: tcluxstr.c internal.h hash.h +tcluxutl.o: tcluxutl.c internal.h hash.h +tclvar.o: tclvar.c internal.h hash.h diff --git a/src/libtcl/doc/AddErrInfo.3 b/src/libtcl/doc/AddErrInfo.3 new file mode 100644 index 0000000..dc28c9c --- /dev/null +++ b/src/libtcl/doc/AddErrInfo.3 @@ -0,0 +1,136 @@ +'\" +'\" Copyright 1989 Regents of the University of California +'\" Permission to use, copy, modify, and distribute this +'\" documentation for any purpose and without fee is hereby +'\" granted, provided that this notice appears in all copies. +'\" The University of California makes no representations about +'\" the suitability of this material for any purpose. It is +'\" provided "as is" without express or implied warranty. +'\" +'\" $Header: /cvsroot/PROCPLACE/pptinytcl/doc/AddErrInfo.3,v 1.1.1.1 2001/04/20 15:03:06 karl Exp $ SPRITE (Berkeley) +'\" +.so man.macros +.HS Tcl_AddErrorInfo tcl +.BS +.SH NAME +Tcl_AddErrorInfo, Tcl_SetErrorCode, Tcl_UnixError, Tcl_CheckStatus \- record information about errors +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +char * +\fBTcl_AddErrorInfo\fR(\fIinterp, message\fR) +.sp +.VS +void +\fBTcl_SetErrorCode\fR(\fIinterp, element, element, ...\fR) +.sp +char * +\fBTcl_UnixError\fR(\fIinterp\fR) +.VE +.SH ARGUMENTS +.AS Tcl_Interp *message +.AP Tcl_Interp *interp in +Interpreter in which to record information. +.AP char *message in +Identifying string to record in \fBerrorInfo\fR variable. +.AP char *element in +.VS +String to record as one element of \fBerrorCode\fR variable. +Last \fIelement\fR argument must be NULL. +.VE +.BE + +.SH DESCRIPTION +.PP +.VS +These procedures are used to manipulate two global variables +that hold information about errors. +The variable \fBerrorInfo\fR holds a stack trace of the +operations that were in progress when an error occurred, and +is intended to be human-readable. +The variable \fBerrorCode\fR holds a list of items that +are intended to be machine-readable. +The first item in \fBerrorCode\fR identifies the class of +error that occurred (e.g. UNIX means an error occurred in +a Unix system call) and additional elements in \fBerrorCode\fR +hold additional pieces of information that depend on the class. +See the Tcl overview manual entry for details on the various +formats for \fBerrorCode\fR. +.PP +The \fBerrorInfo\fR variable is gradually built up as an +error unwinds through the nested operations. +Each time an error code is returned to \fBTcl_Eval\fR +it calls the procedure \fBTcl_AddErrorInfo\fR to add +additional text to \fBerrorInfo\fR describing the +command that was being executed when the error occurred. +By the time the error has been passed all the way back +to the application, it will contain a complete trace +of the activity in progress when the error occurred. +.PP +It is sometimes useful to add additional information to +\fBerrorInfo\fR beyond what can be supplied automatically +by \fBTcl_Eval\fR. +\fBTcl_AddErrorInfo\fR may be used for this purpose: +its \fImessage\fR argument contains an additional +string to be appended to \fBerrorInfo\fR. +For example, the \fBsource\fR command calls \fBTcl_AddErrorInfo\fR +to record the name of the file being processed and the +line number on which the error occurred; for Tcl procedures, the +procedure name and line number within the procedure are recorded, +and so on. +The best time to call \fBTcl_AddErrorInfo\fR is just after +\fBTcl_Eval\fR has returned \fBTCL_ERROR\fR. +In calling \fBTcl_AddErrorInfo\fR, you may find it useful to +use the \fBerrorLine\fR field of the interpreter (see the +\fBTcl_Interp\fR manual entry for details). +.PP +The procedure \fBTcl_SetErrorCode\fR is used to set the +\fBerrorCode\fR variable. +Its \fIelement\fR arguments give one or more strings to record +in \fBerrorCode\fR: each \fIelement\fR will become one item +of a properly-formed Tcl list stored in \fBerrorCode\fR. +\fBTcl_SetErrorCode\fR is typically invoked just before returning +an error. +If an error is returned without calling \fBTcl_SetErrorCode\fR +then the Tcl interpreter automatically sets \fBerrorCode\fR +to \fBNONE\fR. +.PP +\fBTcl_UnixError\fR sets the \fBerrorCode\fR variable after an error +in a UNIX kernel call. +It reads the value of the \fBerrno\fR C variable and calls +\fBTcl_SetErrorCode\fR to set \fBerrorCode\fR in the +\fBUNIX\fR format. +In addition, \fBTcl_UnixError\fR returns a human-readable +diagnostic message for the error (this is the same value that +will appear as the third element in \fBerrorCode\fR). +It may be convenient to include this string as part of the +error message returned to the application in \fIinterp->result\fR. +.PP +It is important to call the procedures described here rather than +setting \fBerrorInfo\fR or \fBerrorCode\fR directly with +\fBTcl_SetVar\fR. +The reason for this is that the Tcl interpreter keeps information +about whether these procedures have been called. +For example, the first time \fBTcl_AppendResult\fR is called +for an error, it clears the existing value of \fBerrorInfo\fR +and adds the error message in \fIinterp->result\fR to the variable +before appending \fImessage\fR; in subsequent calls, it just +appends the new \fImessage\fR. +When \fBTcl_SetErrorCode\fR is called, it sets a flag indicating +that \fBerrorCode\fR has been set; this allows the Tcl interpreter +to set \fBerrorCode\fR to \fBNONE\fB if it receives an error return +when \fBTcl_SetErrorCode\fR hasn't been called. +.PP +If the procedure \fBTcl_ResetResult\fR is called, it clears all +of the state associated with \fBerrorInfo\fR and \fBerrorCode\fR +(but it doesn't actually modify the variables). +If an error had occurred, this will clear the error state to +make it appear as if no error had occurred after all. +.VE + +.SH "SEE ALSO" +Tcl_ResetResult, Tcl_Interp + +.SH KEYWORDS +error, stack, trace, variable diff --git a/src/libtcl/doc/AssembCmd.3 b/src/libtcl/doc/AssembCmd.3 new file mode 100644 index 0000000..54a42d7 --- /dev/null +++ b/src/libtcl/doc/AssembCmd.3 @@ -0,0 +1,87 @@ +'\" +'\" Copyright 1989-1992 Regents of the University of California +'\" Permission to use, copy, modify, and distribute this +'\" documentation for any purpose and without fee is hereby +'\" granted, provided that this notice appears in all copies. +'\" The University of California makes no representations about +'\" the suitability of this material for any purpose. It is +'\" provided "as is" without express or implied warranty. +'\" +'\" $Header: /cvsroot/PROCPLACE/pptinytcl/doc/AssembCmd.3,v 1.1.1.1 2001/04/20 15:03:06 karl Exp $ SPRITE (Berkeley) +'\" +.so man.macros +.HS Tcl_AssembleCmd tcl +.BS +.SH NAME +Tcl_CreateCmdBuf, Tcl_AssembleCmd, Tcl_DeleteCmdBuf \- buffer pieces of Tcl commands +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +Tcl_CmdBuf +\fBTcl_CreateCmdBuf\fR() +.sp +\fBTcl_DeleteCmdBuf\fR(\fIbuffer\fR) +.sp +char * +.VS +\fBTcl_AssembleCmd\fR(\fIbuffer\fR, \fIstring\fR) +.VE +.sp +int +\fBTcl_CommandComplete\fR(\fIcmd\fR) +.SH ARGUMENTS +.AS Tcl_CmdBuf *string; +.AP Tcl_CmdBuf buffer in +Token for a command buffer (the result of some previous call to +\fBTcl_CreateCmdBuf\fR). +.AP char *string in +Additional piece of command input to be added to anything currently +buffered. +.AP char *cmd in +.VS +Command string to test for completeness. +.VE +.BE + +.SH DESCRIPTION +.PP +These procedures provide a convenient mechanism for assembling +Tcl commands from an input source where command boundaries are not +obvious. For example, if input is being read from a terminal, a user +may type commands that span multiple lines. In situations like +this, \fBTcl_AssembleCmd\fR can be called with the individual lines +as they are received. It buffers the lines internally and returns +full commands when they are complete. +.PP +A command buffer is created by calling \fBTcl_CreateCmdBuf\fR, and +it is deleted by calling \fBTcl_DeleteCmdBuf\fR. There may be any +number of command buffers for a particular program or even for a +particular interpreter; in most cases there should be one +buffer for each independent source of command input. +.PP +When input arrives from a source you should call \fBTcl_AssembleCmd\fR, +passing it the new input as the \fIstring\fR argument. +\fBTcl_AssembleCmd\fR will add the new input to anything currently +buffered in \fIbuffer\fR. If the information now buffered represents +a complete Tcl command (i.e. there are no unclosed quotes, braces, +brackets, or variable references), +then \fBTcl_AssembleCmd\fR returns a pointer to the complete command +and arranges for the buffer to be cleared on the next call to +\fBTcl_AssembleCmd\fR. If the command is still incomplete (because, +for example, there are unmatched braces) then \fBTcl_AssembleCmd\fR +returns NULL. \fBTcl_AssembleCmd\fR keeps a private copy of the +command being assembled, so that the caller need not preserve the +contents of \fIstring\fR between calls to \fBTcl_AssembleCmd\fR. +\fBTcl_AssembleCmd\fR supports commands of arbitrary length (up to +the total memory limit imposed by the operating system, if any). +.PP +.VS +The procedure \fBTcl_CommandComplete\fR takes a Tcl command string +as argument and determines whether the command string is complete +in the sense defined above. +If so then it returns 1; otherwise it returns 0. +.VE + +.SH KEYWORDS +assemble, buffer, partial command diff --git a/src/libtcl/doc/Backslash.3 b/src/libtcl/doc/Backslash.3 new file mode 100644 index 0000000..1453244 --- /dev/null +++ b/src/libtcl/doc/Backslash.3 @@ -0,0 +1,57 @@ +'\" +'\" Copyright 1989 Regents of the University of California +'\" Permission to use, copy, modify, and distribute this +'\" documentation for any purpose and without fee is hereby +'\" granted, provided that this notice appears in all copies. +'\" The University of California makes no representations about +'\" the suitability of this material for any purpose. It is +'\" provided "as is" without express or implied warranty. +'\" +'\" $Header: /cvsroot/PROCPLACE/pptinytcl/doc/Backslash.3,v 1.1.1.1 2001/04/20 15:03:06 karl Exp $ SPRITE (Berkeley) +'\" +.so man.macros +.HS Tcl_Backslash tcl +.BS +.SH NAME +Tcl_Backslash \- parse a backslash sequence +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +char +\fBTcl_Backslash\fR(\fIsrc, countPtr\fR) +.SH ARGUMENTS +.AS char *countPtr +.AP char *src in +Pointer to a string starting with a backslash. +.AP int *countPtr out +If \fIcountPtr\fR isn't NULL, \fI*countPtr\fR gets filled +in with number of characters in the backslash sequence, including +the backslash character. +.BE + +.SH DESCRIPTION +.PP +This is a utility procedure used by several of the Tcl +commands. It parses a backslash sequence and returns +the single character corresponding to the sequence. +.VS +If the backslash sequence should be replaced by no character +at all (e.g. backslash-newline) then \fBTcl_Backslash\fR returns 0. +.VE +\fBTcl_Backslash\fR modifies \fI*countPtr\fR to contain the number +of characters in the backslash sequence. +If \fIsrc\fR doesn't point to a backslash +sequence understood by Tcl, then Tcl_Backslash returns a backslash +as its result and \fI*countPtr\fR gets set to 1 (in this case the +backslash character should not get any special treatment). +.PP +See the Tcl manual entry for information on the valid +backslash sequences. +.VS +All of the sequences described in the Tcl +manual entry are supported by \fBTcl_Backslash\fR. +.VE + +.SH KEYWORDS +backslash, parse diff --git a/src/libtcl/doc/Concat.3 b/src/libtcl/doc/Concat.3 new file mode 100644 index 0000000..0e1663b --- /dev/null +++ b/src/libtcl/doc/Concat.3 @@ -0,0 +1,55 @@ +'\" +'\" Copyright 1989 Regents of the University of California +'\" Permission to use, copy, modify, and distribute this +'\" documentation for any purpose and without fee is hereby +'\" granted, provided that this notice appears in all copies. +'\" The University of California makes no representations about +'\" the suitability of this material for any purpose. It is +'\" provided "as is" without express or implied warranty. +'\" +'\" $Header: /cvsroot/PROCPLACE/pptinytcl/doc/Concat.3,v 1.1.1.1 2001/04/20 15:03:06 karl Exp $ SPRITE (Berkeley) +'\" +.so man.macros +.HS Tcl_Concat tcl +.BS +.SH NAME +Tcl_Concat \- concatenate a collection of strings +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +char * +\fBTcl_Concat\fR(\fIargc, argv\fR) +.SH ARGUMENTS +.AP int argc in +Number of strings. +.AP char *argv[] in +Array of strings to concatenate. Must have \fIargc\fR entries. +.BE + +.SH DESCRIPTION +.PP +\fBTcl_Concat\fR is a utility procedure used by several of the +Tcl commands. Given a collection of strings, it concatenates +them together into a single string, with the original strings +separated by spaces. This procedure behaves differently than +\fBTcl_Merge\fR, in that the arguments are simply concatenated: +no effort is made to ensure proper list structure. +.VS +However, in most common usage the arguments will all be proper +lists themselves; if this is true, then the result will also have +proper list structure. +.PP +\fBTcl_Concat\fR eliminates leading and trailing white space as it +copies strings from \fBargv\fR to the result. If an element of +\fBargv\fR consists of nothing but white space, then that string +is ignored entirely. This white-space removal was added to make +the output of the \fBconcat\fR command cleaner-looking. +.VE +.PP +The result string is dynamically allocated +using \fBmalloc()\fR; the caller must eventually release the space +by calling \fBfree()\fR. + +.SH KEYWORDS +concatenate, strings diff --git a/src/libtcl/doc/CrtCommand.3 b/src/libtcl/doc/CrtCommand.3 new file mode 100644 index 0000000..c314d01 --- /dev/null +++ b/src/libtcl/doc/CrtCommand.3 @@ -0,0 +1,124 @@ +'\" +'\" Copyright 1989 Regents of the University of California +'\" Permission to use, copy, modify, and distribute this +'\" documentation for any purpose and without fee is hereby +'\" granted, provided that this notice appears in all copies. +'\" The University of California makes no representations about +'\" the suitability of this material for any purpose. It is +'\" provided "as is" without express or implied warranty. +'\" +'\" $Header: /cvsroot/PROCPLACE/pptinytcl/doc/CrtCommand.3,v 1.1.1.1 2001/04/20 15:03:06 karl Exp $ SPRITE (Berkeley) +'\" +.so man.macros +.HS Tcl_CreateCommand tcl +.BS +.SH NAME +Tcl_CreateCommand, Tcl_DeleteCommand \- define application-specific command bindings +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +\fBTcl_CreateCommand\fR(\fIinterp, cmdName, proc, clientData, deleteProc\fR) +.sp +int +\fBTcl_DeleteCommand\fR(\fIinterp, cmdName\fR) +.SH ARGUMENTS +.AS Tcl_CmdDeleteProc (*deleteProc)() +.AP Tcl_Interp *interp in +Interpreter in which to create new command. +.AP char *cmdName in +Name of command to create or delete. +.AP Tcl_CmdProc *proc in +Implementation of new command: \fIproc\fR will be called whenever +\fIcmdName\fR is invoked as a command. +.AP ClientData clientData in +Arbitrary one-word value to pass to \fIproc\fR and \fIdeleteProc\fR. +.AP Tcl_CmdDeleteProc *deleteProc in +Procedure to call before \fIcmdName\fR is deleted from the interpreter; +allows for command-specific cleanup. If NULL, then no procedure is +called before the command is deleted. +.BE + +.SH DESCRIPTION +.PP +\fBTcl_CreateCommand\fR defines a new command in \fIinterp\fR and associates +it with procedure \fIproc\fR such that whenever \fIcmdName\fR is +invoked as a Tcl command (via a call to \fBTcl_Eval\fR) the Tcl interpreter +will call \fIproc\fR +to process the command. If there is already a command \fIcmdName\fR +associated with the interpreter, it is deleted. \fIProc\fP should +have arguments and result that match the type \fBTcl_CmdProc\fR: +.nf +.RS +typedef int Tcl_CmdProc( +.RS +ClientData \fIclientData\fR, +Tcl_Interp *\fIinterp\fR, +int \fIargc\fR, +char *\fIargv\fR[]); +.RE +.RE +.fi +When \fIproc\fR is invoked the \fIclientData\fP and \fIinterp\fR +parameters will be copies of the \fIclientData\fP and \fIinterp\fR +arguments given to \fBTcl_CreateCommand\fR. +Typically, \fIclientData\fR points to an application-specific +data structure that describes what to do when the command procedure +is invoked. \fIArgc\fR and \fIargv\fR describe the arguments to +the command, \fIargc\fR giving the number of arguments (including +the command name) and \fIargv\fR giving the values of the arguments +as strings. The \fIargv\fR array will contain \fIargc\fR+1 values; +the first \fIargc\fR values point to the argument strings, and the +last value is NULL. +.PP +\fIProc\fR must return an integer code that is either \fBTCL_OK\fR, \fBTCL_ERROR\fR, +\fBTCL_RETURN\fR, \fBTCL_BREAK\fR, or \fBTCL_CONTINUE\fR. See the Tcl overview man page +for details on what these codes mean. Most normal commands will only +return \fBTCL_OK\fR or \fBTCL_ERROR\fR. In addition, \fIproc\fR must set +\fIinterp->result\fR to point to a string value; +in the case of a \fBTCL_OK\fR return code this gives the result +of the command, and in the case of \fBTCL_ERROR\fR it gives an error message. +The \fBTcl_SetResult\fR procedure provides an easy interface for setting +the return value; for complete details on how the \fIinterp->result\fR +field is managed, see the \fBTcl_Interp\fR man page. +Before invoking a command procedure, +\fBTcl_Eval\fR sets \fIinterp->result\fR to point to an empty string, so simple +commands can return an empty result by doing nothing at all. +.PP +The contents of the \fIargv\fR array are copies made by the Tcl interpreter +for the use of \fIproc\fR. \fIProc\fR may alter any of the strings +in \fIargv\fR. However, the \fIargv\fR array +is recycled as soon as \fIproc\fR returns, so \fIproc\fR must not set +\fIinterp->result\fR to point anywhere within the \fIargv\fR values +(call Tcl_SetResult +with status \fBTCL_VOLATILE\fR if you want to return something from the +\fIargv\fR array). +.PP +\fIDeleteProc\fR will be invoked when (if) \fIcmdName\fR is deleted. +This can occur through a call to \fBTcl_DeleteCommand\fR or \fBTcl_DeleteInterp\fR, +or by replacing \fIcmdName\fR in another call to Tcl_CreateCommand. +\fIDeleteProc\fR is invoked before the command is deleted, and gives the +application an opportunity to release any structures associated +with the command. \fIDeleteProc\fR should have arguments and +result that match the type \fBTcl_CmdDeleteProc\fR: +.nf +.RS +.sp +typedef void Tcl_CmdDeleteProc(ClientData \fIclientData\fR); +.sp +.RE +.fi +The \fIclientData\fR argument will be the same as the \fIclientData\fR +argument passed to \fBTcl_CreateCommand\fR. +.PP +\fBTcl_DeleteCommand\fR deletes a command from a command interpreter. +Once the call completes, attempts to invoke \fIcmdName\fR in +\fIinterp\fR will result in errors. +If \fIcmdName\fR isn't bound as a command in \fIinterp\fR then +\fBTcl_DeleteCommand\fR does nothing and returns -1; otherwise +it returns 0. +There are no restrictions on \fIcmdName\fR: it may refer to +a built-in command, an application-specific command, or a Tcl procedure. + +.SH KEYWORDS +bind, command, create, delete, interpreter diff --git a/src/libtcl/doc/CrtInterp.3 b/src/libtcl/doc/CrtInterp.3 new file mode 100644 index 0000000..ffc3e65 --- /dev/null +++ b/src/libtcl/doc/CrtInterp.3 @@ -0,0 +1,50 @@ +'\" +'\" Copyright 1989 Regents of the University of California +'\" Permission to use, copy, modify, and distribute this +'\" documentation for any purpose and without fee is hereby +'\" granted, provided that this notice appears in all copies. +'\" The University of California makes no representations about +'\" the suitability of this material for any purpose. It is +'\" provided "as is" without express or implied warranty. +'\" +'\" $Header: /cvsroot/PROCPLACE/pptinytcl/doc/CrtInterp.3,v 1.1.1.1 2001/04/20 15:03:06 karl Exp $ SPRITE (Berkeley) +'\" +.so man.macros +.HS Tcl_CreateInterp tcl +.BS +.SH NAME +Tcl_CreateInterp, Tcl_DeleteInterp \- create and delete Tcl command interpreters +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +Tcl_Interp * +\fBTcl_CreateInterp\fR() +.sp +\fBTcl_DeleteInterp\fR(\fIinterp\fR) +.SH ARGUMENTS +.AS Tcl_Interp *interp +.AP Tcl_Interp *interp in +Token for interpreter to be destroyed. +.BE + +.SH DESCRIPTION +.PP +\fBTcl_CreateInterp\fR creates a new interpreter structure and returns +a token for it. The token is required in calls to most other Tcl +procedures, such as \fBTcl_CreateCommand\fR, \fBTcl_Eval\fR, and +\fBTcl_DeleteInterp\fR. +Clients are only allowed to access a few of the fields of +Tcl_Interp structures; see the Tcl_Interp +and \fBTcl_CreateCommand\fR man pages for details. +The new interpreter is initialized with no defined variables and only +the built-in Tcl commands. To bind in additional commands, call +\fBTcl_CreateCommand\fR. +.PP +\fBTcl_DeleteInterp\fR destroys a command interpreter and releases all of +the resources associated with it, including variables, procedures, +and application-specific command bindings. After \fBTcl_DeleteInterp\fR +returns the caller should never again use the \fIinterp\fR token. + +.SH KEYWORDS +command, create, delete, interpreter diff --git a/src/libtcl/doc/CrtPipelin.3 b/src/libtcl/doc/CrtPipelin.3 new file mode 100644 index 0000000..fc2714d --- /dev/null +++ b/src/libtcl/doc/CrtPipelin.3 @@ -0,0 +1,105 @@ +'\" +'\" Copyright 1989 Regents of the University of California +'\" Permission to use, copy, modify, and distribute this +'\" documentation for any purpose and without fee is hereby +'\" granted, provided that this notice appears in all copies. +'\" The University of California makes no representations about +'\" the suitability of this material for any purpose. It is +'\" provided "as is" without express or implied warranty. +'\" +'\" $Header: /cvsroot/PROCPLACE/pptinytcl/doc/CrtPipelin.3,v 1.1.1.1 2001/04/20 15:03:06 karl Exp $ SPRITE (Berkeley) +'\" +.so man.macros +.HS Tcl_CreatePipeline tcl +.VS +.BS +.SH NAME +Tcl_CreatePipeline \- create one or more child processes, with I/O redirection +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +int +\fBTcl_CreatePipeline\fR(\fIinterp, argc, argv, pidArrayPtr, inPipePtr, outPipePtr, errFilePtr\fR) +.SH ARGUMENTS +.AS Tcl_Interp **pidArrayPtr +.AP Tcl_Interp *interp in +Interpreter to use for error reporting. +.AP int argc in +Number of strings in \fIargv\fR array. +.AP char **argv in +Array of strings describing command(s) and I/O redirection. +.AP int **pidArrayPtr out +The value at \fI*pidArrayPtr\fR is modified to hold a pointer to +an array of process identifiers. The array is dynamically +allocated and must be freed by the caller. +.AP char *inPipePtr out +If this argument is NULL then standard input for the first command +in the pipeline comes from the current standard input. +If \fIinPipePtr\fR is not NULL then \fBTcl_CreatePipeline\fR will +create a pipe, arrange for it to be used for standard input +to the first command, +and store a file id for writing to that pipe at \fI*inPipePtr\fR. +If the command specified its own input using redirection, then +no pipe is created and -1 is stored at \fI*inPipePtr\fR. +.AP char *outPipePtr out +If this argument is NULL then standard output for the last command +in the pipeline goes to the current standard output. +If \fIoutPipePtr\fR is not NULL then \fBTcl_CreatePipeline\fR will +create a pipe, arrange for it to be used for standard output from +the last command, and store a file id for reading from that +pipe at \fI*outPipePtr\fR. +If the command specified its own output using redirection then +no pipe is created and -1 is stored at \fI*outPipePtr\fR. +.AP char *errFilePtr out +If this argument is NULL then error output for all the commands +in the pipeline will go to the current standard error file. +If \fIerrFilePtr\fR is not NULL, error output from all the commands +in the pipeline will go to a temporary file created by +\fBTcl_CreatePipeline\fR. +A file id to read from that file will be stored at \fI*errFilePtr\fR. +The file will already have been removed, so closing the file +descriptor at \fI*errFilePtr\fR will cause the file to be flushed +completely. +.BE + +.SH DESCRIPTION +.PP +\fBTcl_CreatePipeline\fR processes the \fIargv\fR array and sets +up one or more child processes in a pipeline configuration. +\fBTcl_CreatePipeline\fR handles pipes specified with ``|'', +input redirection specified with ``<'' or ``<<'', and output +redirection specified with ``>''; see the documentation for +the \fBexec\fR command for details on these specifications. +The return value from \fBTcl_CreatePipeline\fR is a count of +the number of child processes created; the process identifiers +for those processes are stored in a \fImalloc\fR-ed array and +a pointer to that array is stored at \fI*pidArrayPtr\fR. +It is the caller's responsibility to free the array when finished +with it. +.PP +If the \fIinPipePtr\fR, \fIoutPipePtr\fR, and \fIerrFilePtr\fR +arguments are NULL then the pipeline's standard input, standard +output, and standard error are taken from the corresponding +streams of the process. Non-NULL values may be specified for +these arguments to use pipes for standard input and standard +output and a file for standard error. \fBTcl_CreatePipeline\fR +will create the requested pipes or file and return file identifiers +that may be used to read or write them. It is the caller's +responsibility to close all of these files when they are no +longer needed. If \fIargv\fR specifies redirection for standard +input or standard output, then pipes will not be created even +if requested by the \fIinPipePtr\fR and \fIoutPipePtr\fR +arguments. +.PP +If an error occurs in \fBTcl_CreatePipeline\fR (e.g. ``|'' or +``<'' was the last argument in \fIargv\fR, or it wasn't possible +to fork off a child), then -1 is returned +and \fIinterp->result\fR is set to an error message. + +.SH "SEE ALSO" +\fBTcl_WaitPids\fR, \fBTcl_DetachPids\fR + +.SH KEYWORDS +background, child, detach, fork, process, status, wait +.VE diff --git a/src/libtcl/doc/CrtTrace.3 b/src/libtcl/doc/CrtTrace.3 new file mode 100644 index 0000000..7c60493 --- /dev/null +++ b/src/libtcl/doc/CrtTrace.3 @@ -0,0 +1,114 @@ +'\" +'\" Copyright 1989 Regents of the University of California +'\" Permission to use, copy, modify, and distribute this +'\" documentation for any purpose and without fee is hereby +'\" granted, provided that this notice appears in all copies. +'\" The University of California makes no representations about +'\" the suitability of this material for any purpose. It is +'\" provided "as is" without express or implied warranty. +'\" +'\" $Header: /cvsroot/PROCPLACE/pptinytcl/doc/CrtTrace.3,v 1.1.1.1 2001/04/20 15:03:06 karl Exp $ SPRITE (Berkeley) +'\" +.so man.macros +.HS Tcl_CreateTrace tcl +.BS +.SH NAME +Tcl_CreateTrace, Tcl_DeleteTrace \- arrange for command execution to be traced +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +Tcl_Trace +\fBTcl_CreateTrace\fR(\fIinterp, level, proc, clientData\fR) +.sp +\fBTcl_DeleteTrace\fR(\fIinterp, trace\fR) +.SH ARGUMENTS +.AS Tcl_CmdTraceProc (clientData)() +.AP Tcl_Interp *interp in +Interpreter containing command to be traced or untraced. +.AP int level in +Only commands at or below this nesting level will be traced. 1 means +top-level commands only, 2 means top-level commands or those that are +invoked as immediate consequences of executing top-level commands +(procedure bodies, bracketed commands, etc.) and so on. +.AP Tcl_CmdTraceProc *proc in +Procedure to call for each command that's executed. See below for +details on the calling sequence. +.AP ClientData clientData in +Arbitrary one-word value to pass to \fIproc\fR. +.AP Tcl_Trace trace in +Token for trace to be removed (return value from previous call +to \fBTcl_CreateTrace\fR). +.BE + +.SH DESCRIPTION +.PP +\fBTcl_CreateTrace\fR arranges for command tracing. From now on, \fIproc\fR +will be invoked before Tcl calls command procedures to process +commands in \fIinterp\fR. The return value from +\fBTcl_CreateTrace\fR is a token for the trace, +which may be passed to \fBTcl_DeleteTrace\fR to remove the trace. There may +be many traces in effect simultaneously for the same command interpreter. +.PP +\fIProc\fR should have arguments and result that match the +type \fBTcl_CmdTraceProc\fR: +.nf +.sp +.RS +typedef void Tcl_CmdTraceProc( +.RS +ClientData \fIclientData\fR, +Tcl_Interp *\fIinterp\fR, +int \fIlevel\fR, +char *\fIcommand\fR, +Tcl_CmdProc *\fIcmdProc\fR, +ClientData \fIcmdClientData\fR, +int \fIargc\fR, +char *\fIargv\fR[])); +.sp +.RE +.RE +.fi +The \fIclientData\fP and \fIinterp\fP parameters are +copies of the corresponding arguments given to \fBTcl_CreateTrace\fR. +\fIClientData\fR typically points to an application-specific +data structure that describes what to do when \fIproc\fR +is invoked. \fILevel\fR gives the nesting level of the command +(1 for top-level commands passed to \fBTcl_Eval\fR by the application, +2 for the next-level commands passed to \fBTcl_Eval\fR as part of parsing +or interpreting level-1 commands, and so on). \fICommand\fR +points to a string containing the text of the +command, before any argument substitution. +\fICmdProc\fR contains the address of the command procedure that +will be called to process the command (i.e. the \fIproc\fR argument +of some previous call to \fBTcl_CreateCommand\fR) and \fIcmdClientData\fR +contains the associated client data for \fIcmdProc\fR (the \fIclientData\fR +value passed to \fBTcl_CreateCommand\fR). \fIArgc\fR and \fIargv\fR give +the final argument information that will be passed to \fIcmdProc\fR, after +command, variable, and backslash substitution. +\fIProc\fR must not modify the \fIcommand\fR or \fIargv\fR strings. +.PP +Tracing will only occur for commands at nesting level less than +or equal to the \fIlevel\fR parameter (i.e. the \fIlevel\fR +parameter to \fIproc\fR will always be less than or equal to the +\fIlevel\fR parameter to \fBTcl_CreateTrace\fR). +.PP +Calls to \fIproc\fR will be made by the Tcl parser immediately before +it calls the command procedure for the command (\fIcmdProc\fR). This +occurs after argument parsing and substitution, so tracing for +substituted commands occurs before tracing of the commands +containing the substitutions. If there is a syntax error in a +command, or if there is no command procedure associated with a +command name, then no tracing will occur for that command. If a +string passed to Tcl_Eval contains multiple commands (bracketed, or +on different lines) then multiple calls to \fIproc\fR will occur, +one for each command. The \fIcommand\fR string for each of these +trace calls will reflect only a single command, not the entire string +passed to Tcl_Eval. +.PP +\fBTcl_DeleteTrace\fR removes a trace, so that no future calls will be +made to the procedure associated with the trace. After \fBTcl_DeleteTrace\fR +returns, the caller should never again use the \fItrace\fR token. + +.SH KEYWORDS +command, create, delete, interpreter, trace diff --git a/src/libtcl/doc/Eval.3 b/src/libtcl/doc/Eval.3 new file mode 100644 index 0000000..4e04654 --- /dev/null +++ b/src/libtcl/doc/Eval.3 @@ -0,0 +1,124 @@ +'\" +'\" Copyright 1989 Regents of the University of California +'\" Permission to use, copy, modify, and distribute this +'\" documentation for any purpose and without fee is hereby +'\" granted, provided that this notice appears in all copies. +'\" The University of California makes no representations about +'\" the suitability of this material for any purpose. It is +'\" provided "as is" without express or implied warranty. +'\" +'\" $Header: /cvsroot/PROCPLACE/pptinytcl/doc/Eval.3,v 1.1.1.1 2001/04/20 15:03:06 karl Exp $ SPRITE (Berkeley) +'\" +.so man.macros +.HS Tcl_Eval tcl +.BS +.SH NAME +Tcl_Eval, Tcl_VarEval, Tcl_EvalFile, Tcl_GlobalEval \- execute Tcl commands +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +int +\fBTcl_Eval\fR(\fIinterp, cmd, flags, termPtr\fR) +.sp +int +\fBTcl_VarEval\fR(\fIinterp, string, string, ... \fB(char *) NULL\fR) +.sp +int +\fBTcl_EvalFile\fR(\fIinterp, fileName\fR) +.sp +.VS +int +\fBTcl_GlobalEval\fR(\fIinterp, cmd\fR) +.VE +.SH ARGUMENTS +.AS Tcl_Interp **termPtr; +.AP Tcl_Interp *interp in +Interpreter in which to execute the command. String result will be +stored in \fIinterp->result\fR. +.AP char *cmd in +Command (or sequence of commands) to execute. Must be in writable +memory (Tcl_Eval makes temporary modifications to the command). +.AP int flags in +Either \fBTCL_BRACKET_TERM\fR or 0. +If 0, then \fBTcl_Eval\fR will process commands from \fIcmd\fR until +it reaches the null character at the end of the string. +If \fBTCL_BRACKET_TERM\fR, +then \fBTcl_Eval\fR will process comands from \fIcmd\fR until either it +reaches a null character or it encounters a close bracket that isn't +backslashed or enclosed in braces, at which point it will return. +Under normal conditions, \fIflags\fR should be 0. +.AP char **termPtr out +If \fItermPtr\fR is non-NULL, \fBTcl_Eval\fR fills in *\fItermPtr\fR with +the address of the character just after the last one in the last command +successfully executed (normally the null character at the end of \fIcmd\fR). +If an error occurs in the first command in \fIcmd\fR, then \fI*termPtr\fR +will be set to \fIcmd\fR. +.AP char *string in +String forming part of Tcl command. +.AP char *fileName in +Name of file containing Tcl command string. +.BE + +.SH DESCRIPTION +.PP +All four of these procedures execute Tcl commands. +\fBTcl_Eval\fR is the core procedure: it parses commands +from \fIcmd\fR and executes them in +order until either an error occurs or \fBTcl_Eval\fR reaches a terminating +character (']' or '\e0', depending on the value of \fIflags\fR). +The return value from \fBTcl_Eval\fR is one +of the Tcl return codes \fBTCL_OK\fR, \fBTCL_ERROR\fR, \fBTCL_RETURN\fR, \fBTCL_BREAK\fR, or +\fBTCL_CONTINUE\fR, and \fIinterp->result\fR will point to +a string with additional information (result value or error message). +This return information corresponds to the last command executed from +\fIcmd\fR. +.PP +\fBTcl_VarEval\fR takes any number of string arguments +of any length, concatenates +them into a single string, then calls \fBTcl_Eval\fR to +execute that string as a Tcl command. +It returns the result of the command and also modifies +\fIinterp->result\fR in the usual fashion for Tcl commands. The +last argument to \fBTcl_VarEval\fR must be NULL to indicate the end +of arguments. +.PP +\fBTcl_EvalFile\fR reads the file given by \fIfileName\fR and evaluates +its contents as a Tcl command by calling \fBTcl_Eval\fR. It returns +a standard Tcl result that reflects the result of evaluating the +file. +If the file couldn't be read then a Tcl error is returned to describe +why the file couldn't be read. +.PP +.VS +\fBTcl_GlobalEval\fR is similar to \fBTcl_Eval\fR except that it +processes the command at global level. +This means that the variable context for the command consists of +global variables only (it ignores any Tcl procedure that is active). +This produces an effect similar to the Tcl command ``\fBuplevel 0\fR''. +.VE +.PP +During the processing of a Tcl command it is legal to make nested +calls to evaluate other commands (this is how conditionals, loops, +and procedures are implemented). +If a code other than +\fBTCL_OK\fR is returned from a nested \fBTcl_Eval\fR invocation, then the +caller should normally return immediately, passing that same +return code back to its caller, and so on until the top-level application is +reached. A few commands, like \fBfor\fR, will check for certain +return codes, like \fBTCL_BREAK\fR and \fBTCL_CONTINUE\fR, and process them +specially without returning. +.PP +\fBTcl_Eval\fR keeps track of how many nested Tcl_Eval invocations are +in progress for \fIinterp\fR. +If a code of \fBTCL_RETURN\fR, \fBTCL_BREAK\fR, or \fBTCL_CONTINUE\fR is +about to be returned from the topmost \fBTcl_Eval\fR invocation for +\fIinterp\fR, then \fBTcl_Eval\fR converts the return code to \fBTCL_ERROR\fR +and sets \fIinterp->result\fR to point to an error message indicating that +the \fBreturn\fR, \fBbreak\fR, or \fBcontinue\fR command was +invoked in an inappropriate place. This means that top-level +applications should never see a return code from \fBTcl_Eval\fR other then +\fBTCL_OK\fR or \fBTCL_ERROR\fR. + +.SH KEYWORDS +command, execute, file, global, interpreter, variable diff --git a/src/libtcl/doc/ExprLong.3 b/src/libtcl/doc/ExprLong.3 new file mode 100644 index 0000000..68a09c8 --- /dev/null +++ b/src/libtcl/doc/ExprLong.3 @@ -0,0 +1,102 @@ +'\" +'\" Copyright 1989 Regents of the University of California +'\" Permission to use, copy, modify, and distribute this +'\" documentation for any purpose and without fee is hereby +'\" granted, provided that this notice appears in all copies. +'\" The University of California makes no representations about +'\" the suitability of this material for any purpose. It is +'\" provided "as is" without express or implied warranty. +'\" +'\" $Header: /cvsroot/PROCPLACE/pptinytcl/doc/ExprLong.3,v 1.1.1.1 2001/04/20 15:03:06 karl Exp $ SPRITE (Berkeley) +'\" +.so man.macros +.HS Tcl_ExprLong tcl +.BS +.SH NAME +Tcl_ExprLong, Tcl_ExprDouble, Tcl_ExprBool, Tcl_ExprString \- evaluate an expression +.SH SYNOPSIS +.nf +\fB#include \fR +.VS +.sp +int +\fBTcl_ExprLong\fR(\fIinterp, string, longPtr\fR) +.sp +int +\fBTcl_ExprDouble\fR(\fIinterp, string, doublePtr\fR) +.sp +int +\fBTcl_ExprBoolean\fR(\fIinterp, string, booleanPtr\fR) +.sp +int +\fBTcl_ExprString\fR(\fIinterp, string\fR) +.SH ARGUMENTS +.AS Tcl_Interp *booleanPtr +.AP Tcl_Interp *interp in +Interpreter in whose context to evaluate \fIstring\fR. +.AP char *string in +Expression to be evaluated. Must be in writable memory (the expression +parser makes temporary modifications to the string during parsing, which +it undoes before returning). +.AP long *longPtr out +Pointer to location in which to store the integer value of the +expression. +.AP int *doublePtr out +Pointer to location in which to store the floating-point value of the +expression. +.AP int *booleanPtr out +Pointer to location in which to store the 0/1 boolean value of the +expression. +.BE + +.SH DESCRIPTION +.PP +These four procedures all evaluate a string expression, returning +the result in one of four different forms. +The expression is given by the \fIstring\fR argument, and it +can have any of the forms accepted by the \fBexpr\fR command. +The \fIinterp\fR argument refers to an interpreter used to +evaluate the expression (e.g. for variables and nested Tcl +commands) and to return error information. \fIInterp->result\fR +is assumed to be initialized in the standard fashion when any +of the procedures are invoked. +.PP +For all of these procedures the return value is a standard +Tcl result: \fBTCL_OK\fR means the expression was succesfully +evaluated, and \fBTCL_ERROR\fR means that an error occurred while +evaluating the expression. If \fBTCL_ERROR\fR is returned then +\fIinterp->result\fR will hold a message describing the error. +If an error occurs while executing a Tcl command embedded in +\fIstring\fR, then that error will be returned. +.PP +If the expression is successfully evaluated, then its value will +be returned in one of four forms, depending on which procedure +is invoked. +\fBTcl_ExprLong\fR stores an integer value at \fI*longPtr\fR. +If the expression's actual value was a floating-point number, +then it is truncated to an integer. +If the expression's actual value was a non-numeric string then +an error is returned. +.PP +\fBTcl_ExprDouble\fR stores a floating-point value at \fI*doublePtr\fR. +If the expression's actual value was an integer, it is converted to +floating-point. +If the expression's actual value was a non-numeric string then +an error is returned. +.PP +\fBTcl_ExprBoolean\fR stores a 0/1 integer value at \fI*booleanPtr\fR. +If the expression's actual value was an integer or floating-point +number, then \fBTcl_ExprBoolean\fR stores 0 at \fI*booleanPtr\fR if +the value was zero and 1 otherwise. +If the expression's actual value was a non-numeric string then +an error is returned. +.PP +\fBTcl_ExprString\fR returns the value of the expression as a +string stored in \fIinterp->result\fR. +If the expression's actual value was an integer or floating-point +number, then \fBTcl_ExprString\fR converts it to string (using \fBsprintf\fR +with a ``%d'' or ``%g'' converter). + +.SH KEYWORDS +boolean, double, evaluate, expression, integer, string +.VE diff --git a/src/libtcl/doc/Fork.3 b/src/libtcl/doc/Fork.3 new file mode 100644 index 0000000..63bb7e0 --- /dev/null +++ b/src/libtcl/doc/Fork.3 @@ -0,0 +1,150 @@ +'\" +'\" Copyright 1989 Regents of the University of California +'\" Permission to use, copy, modify, and distribute this +'\" documentation for any purpose and without fee is hereby +'\" granted, provided that this notice appears in all copies. +'\" The University of California makes no representations about +'\" the suitability of this material for any purpose. It is +'\" provided "as is" without express or implied warranty. +'\" +'\" $Header: /cvsroot/PROCPLACE/pptinytcl/doc/Fork.3,v 1.1.1.1 2001/04/20 15:03:06 karl Exp $ SPRITE (Berkeley) +'\" +.so man.macros +.HS Tcl_Fork tcl +.BS +.VS +.SH NAME +Tcl_Fork, Tcl_WaitPids, Tcl_DetachPids \- manage child processes +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +int +\fBTcl_Fork\fR( ) +.sp +int +\fBTcl_WaitPids\fR(\fInumPids, pidPtr, statusPtr\fR) +.sp +int +\fBTcl_DetachPids\fR(\fInumPids, pidPtr\fR) +.SH ARGUMENTS +.AS int *statusPtr +.AP int numPids in +Number of process ids contained in the array pointed to by \fIpidPtr\fR. +.AP int *pidPtr in +Address of array containing \fInumPids\fR process ids. +.AP int *statusPtr out +Address of place to store status returned by exited/suspended process. +.BE + +.SH DESCRIPTION +.PP +These procedures keep track of child processes in order to make it +easier for one application to manage several children. +If an application uses +the UNIX \fIfork\fR and \fIwait\fR kernel calls directly, +problems occur in situations like the following: +.IP [1] +One part of an application creates child C1. It plans to +let the child run in background, then later wait for it to +complete. +.IP [2] +Some other part of the application creates another child C2, +not knowing anything about C1. +.IP [3] +The second part of the application uses \fIwait\fR to wait for C2 +to complete. +.IP [4] +C1 completes before C2, so C1 is returned by the +\fIwait\fR kernel call. +.IP [5] +The second part of the application doesn't recognize C1, so it +ignores it and calls \fIwait\fR again. This time C2 +completes. +.IP [6] +The first part of the application eventually decides to wait +for its child to complete. When it calls \fIwait\fR there are +no children left, so \fIwait\fR returns an error and the +application never gets to examine the exit status for C1. +.PP +The procedures \fBTcl_Fork\fR, \fBTcl_WaitPids\fR, and \fBTcl_DetachPids\fR +get around this problem by keeping a table of child processes and +their exit statuses. +They also provide a more flexible waiting +mechanism than the \fIwait\fR kernel call. +Tcl-based applications should never call \fIfork\fR and +\fIwait\fR directly; they should use \fBTcl_Fork\fR, +\fBTcl_WaitPids\fR, and \fBTcl_DetachPids\fR. +.PP +\fBTcl_Fork\fR calls \fIfork\fR and returns the result of +the \fIfork\fR kernel call. +If the \fIfork\fR call was successful then \fBTcl_Fork\fR also +enters the new process into its internal table of child +proceses. +If \fIfork\fR returns an error then \fBTcl_Fork\fR returns that +same error. +.PP +\fBTcl_WaitPids\fR calls \fIwait\fR repeatedly until one of the processes +in the \fIpidPtr\fR array has exited or been killed or suspended by a +signal. +When this occurs, \fBTcl_WaitPids\fR returns the process +identifier for the process and stores its wait status at +\fI*statusPtr\fR. +If the process no longer exists (it exited or was killed by a signal), +then \fBTcl_WaitPids\fR removes its entry from the internal +process table. +If \fIwait\fR returns a process that isn't +in the \fIpidPtr\fR array, \fBTcl_WaitPids\fR saves its wait +status in the internal process table and calls \fIwait\fR again. +If one of the processes in the \fIpidPtr\fR array has already +exited (or suspended or been killed) when \fBTcl_WaitPids\fR +is called, that process and its wait status are returned +immediately without calling \fIwait\fR. +.PP +\fBTcl_WaitPids\fR provides two advantages. First, it allows +processes to exit in any order, and saves their wait statuses. +Second, it allows waiting on a number of processes simultaneously, +returning when any of the processes is returned by \fIwait\fR. +.PP +\fBTcl_DetachPids\fR is used to indicate that the application +no longer cares about the processes given by the \fIpidPtr\fR +array and will never use \fBTcl_WaitPids\fR to wait for them. +This occurs, for example, if one or more children are to be +executed in background and the parent doesn't care whether +they complete successfully. +When \fBTcl_DetachPids\fR is called, the internal process +table entries for the processes are marked so that the +entries will be removed as soon as the processes exit or +are killed. +.PP +If none of the pids passed to \fBTcl_WaitPids\fR exists in +the internal process table, then -1 is returned and \fIerrno\fR +is set to ECHILD. +If a \fIwait\fR kernel call returns an error, +then \fBTcl_WaitPids\fR returns that same error. +If a \fIwait\fR kernel call returns a process that isn't in +the internal process table, \fBTcl_WaitPids\fR panics and +aborts the application. +If this situation occurs, it means that a process has been +created without calling \fBTcl_Fork\fR and that its exit +status is about to be lost. +.PP +\fBTcl_WaitPids\fR defines wait statuses to have type \fIint\fR, +which is correct for POSIX and many variants of UNIX. +Some BSD-based UNIX systems still use type \fIunion wait\fR for +wait statuses; it should be safe to cast a pointer to a +\fIunion wait\fR structure to \fI(int *)\fR before passing +it to \fBTcl_WaitPids\fR as in the following code: +.nf +.RS + +\fBunion wait status; +int pid1, pid2; +\&... +pid2 = Tcl_WaitPids(1, &pid1, (int *) &status);\fR +.RE +.fi + +.SH KEYWORDS +background, child, detach, fork, process, status, wait +.VE diff --git a/src/libtcl/doc/GetInt.3 b/src/libtcl/doc/GetInt.3 new file mode 100644 index 0000000..11ff501 --- /dev/null +++ b/src/libtcl/doc/GetInt.3 @@ -0,0 +1,85 @@ +'\" +'\" Copyright 1989 Regents of the University of California +'\" Permission to use, copy, modify, and distribute this +'\" documentation for any purpose and without fee is hereby +'\" granted, provided that this notice appears in all copies. +'\" The University of California makes no representations about +'\" the suitability of this material for any purpose. It is +'\" provided "as is" without express or implied warranty. +'\" +'\" $Header: /cvsroot/PROCPLACE/pptinytcl/doc/GetInt.3,v 1.1.1.1 2001/04/20 15:03:06 karl Exp $ SPRITE (Berkeley) +'\" +.so man.macros +.HS Tcl_GetInt tcl +.BS +.SH NAME +Tcl_GetInt, Tcl_GetDouble, Tcl_GetBoolean \- convert from string to integer, double, or boolean +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +int +\fBTcl_GetInt\fR(\fIinterp, string, intPtr\fR) +.sp +int +\fBTcl_GetDouble\fR(\fIinterp, string, doublePtr\fR) +.sp +int +\fBTcl_GetBoolean\fR(\fIinterp, string, boolPtr\fR) +.SH ARGUMENTS +.AS Tcl_Interp *doublePtr +.AP Tcl_Interp *interp in +Interpreter to use for error reporting. +.AP char *string in +Textual value to be converted. +.AP int *intPtr out +Points to place to store integer value converted from \fIstring\fR. +.AP double *doublePtr out +Points to place to store double-precision floating-point +value converted from \fIstring\fR. +.AP int *boolPtr out +Points to place to store boolean value (0 or 1) converted from \fIstring\fR. +.BE + +.SH DESCRIPTION +.PP +These procedures convert from strings to integers or double-precision +floating-point values or booleans (represented as 0- or 1-valued +integers). Each of the procedures takes a \fIstring\fR argument, +converts it to an internal form of a particular type, and stores +the converted value at the location indicated by the procedure's +third argument. If all goes well, each of the procedures returns +TCL_OK. If \fIstring\fR doesn't have the proper syntax for the +desired type then TCL_ERROR is returned, an error message is left +in \fIinterp->result\fR, and nothing is stored at *\fIintPtr\fR +or *\fIdoublePtr\fR or *\fIboolPtr\fR. +.PP +\fBTcl_GetInt\fR expects \fIstring\fR to consist of a collection +of integer digits, optionally signed and optionally preceded by +white space. If the first two characters of \fIstring\fR are ``0x'' +then \fIstring\fR is expected to be in hexadecimal form; otherwise, +if the first character of \fIstring\fR is ``0'' then \fIstring\fR +is expected to be in octal form; otherwise, \fIstring\fR is +expected to be in decimal form. +.PP +\fBTcl_GetDouble\fR expects \fIstring\fR to consist of a floating-point +number, which is: white space; a sign; a sequence of digits; a +decimal point; a sequence of digits; the letter ``e''; and a +signed decimal exponent. Any of the fields may be omitted, except that +the digits either before or after the decimal point must be present +and if the ``e'' is present then it must be followed by the +exponent number. +.PP +\fBTcl_GetBoolean\fR expects \fIstring\fR to specify a boolean +value. If \fIstring\fR is any of \fB0\fR, \fBfalse\fR, +.VS +\fBno\fR, or \fBoff\fR, then \fBTcl_GetBoolean\fR stores a zero +value at \fI*boolPtr\fR. +If \fIstring\fR is any of \fB1\fR, \fBtrue\fR, \fByes\fR, or \fBon\fR, +.VE +then 1 is stored at \fI*boolPtr\fR. +Any of these values may be abbreviated, and upper-case spellings +are also acceptable. + +.SH KEYWORDS +boolean, conversion, double, floating-point, integer diff --git a/src/libtcl/doc/Hash.3 b/src/libtcl/doc/Hash.3 new file mode 100644 index 0000000..2b7808c --- /dev/null +++ b/src/libtcl/doc/Hash.3 @@ -0,0 +1,211 @@ +'\" +'\" Copyright 1989 Regents of the University of California +'\" Permission to use, copy, modify, and distribute this +'\" documentation for any purpose and without fee is hereby +'\" granted, provided that this notice appears in all copies. +'\" The University of California makes no representations about +'\" the suitability of this material for any purpose. It is +'\" provided "as is" without express or implied warranty. +'\" +'\" $Header: /cvsroot/PROCPLACE/pptinytcl/doc/Hash.3,v 1.1.1.1 2001/04/20 15:03:06 karl Exp $ SPRITE (Berkeley) +'\" +.so man.macros +.HS Tcl_Hash tcl +.BS +.SH NAME +.na +Tcl_InitHashTable, Tcl_DeleteHashTable, Tcl_CreateHashEntry, Tcl_DeleteHashEntry, Tcl_FindHashEntry, Tcl_GetHashValue, Tcl_SetHashValue, Tcl_GetHashKey, Tcl_FirstHashEntry, Tcl_NextHashEntry, Tcl_HashStats \- procedures to manage hash tables +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +\fBTcl_InitHashTable\fR(\fItablePtr, keyType\fR) +.sp +\fBTcl_DeleteHashTable\fR(\fItablePtr\fR) +.sp +Tcl_HashEntry * +\fBTcl_CreateHashEntry\fR(\fItablePtr, key, newPtr\fR) +.sp +\fBTcl_DeleteHashEntry\fR(\fIentryPtr\fR) +.sp +Tcl_HashEntry * +\fBTcl_FindHashEntry\fR(\fItablePtr, key\fR) +.sp +ClientData +\fBTcl_GetHashValue\fR(\fIentryPtr\fR) +.sp +\fBTcl_SetHashValue\fR(\fIentryPtr, value\fR) +.sp +char * +\fBTcl_GetHashKey\fR(\fItablePtr, entryPtr\fR) +.sp +Tcl_HashEntry * +\fBTcl_FirstHashEntry\fR(\fItablePtr, searchPtr\fR) +.sp +Tcl_HashEntry * +\fBTcl_NextHashEntry\fR(\fIsearchPtr\fR) +.sp +char * +\fBTcl_HashStats\fR(\fItablePtr\fR) +.SH ARGUMENTS +.AS Tcl_HashSearch *searchPtr +.AP Tcl_HashTable *tablePtr in +Address of hash table structure (for all procedures but +\fBTcl_InitHashTable\fR, this must have been initialized by +previous call to \fBTcl_InitHashTable\fR). +.AP int keyType in +Kind of keys to use for new hash table. Must be either +TCL_STRING_KEYS, TCL_ONE_WORD_KEYS, or an integer value +greater than 1. +.AP char *key in +Key to use for probe into table. Exact form depends on +\fIkeyType\fR used to create table. +.AP int *newPtr out +The word at \fI*newPtr\fR is set to 1 if a new entry was created +and 0 if there was already an entry for \fIkey\fR. +.AP Tcl_HashEntry *entryPtr in +Pointer to hash table entry. +.AP ClientData value in +New value to assign to hash table entry. Need not have type +ClientData, but must fit in same space as ClientData. +.AP Tcl_HashSearch *searchPtr in +Pointer to record to use to keep track of progress in enumerating +all the entries in a hash table. +.BE + +.SH DESCRIPTION +.PP +A hash table consists of zero or more entries, each consisting of +a key and a value. +Given the key for an entry, the hashing routines can very quickly +locate the entry, and hence its value. +There may be at most one entry in a hash table with a +particular key, but many entries may have the same value. +Keys can take one of three forms: strings, +one-word values, or integer arrays. +All of the keys in a given table have the same form, which is +specified when the table is initialized. +.PP +The value of a hash table entry can be anything that fits in +the same space as a ``char *'' pointer. +Values for hash table entries are managed entirely by clients, +not by the hash module itself. +Typically each entry's value is a pointer to a data structure +managed by client code. +.PP +Hash tables grow gracefully as the number of entries increases, +so that there are always less than three entries per hash bucket, +on average. +This allows for fast lookups regardless of the number of entries +in a table. +.PP +\fBTcl_InitHashTable\fR initializes a structure that describes +a new hash table. +The space for the structure is provided by the caller, not by +the hash module. +The value of \fIkeyType\fR indicates what kinds of keys will +be used for all entries in the table. \fIKeyType\fR must have +one of the following values: +.IP \fBTCL_STRING_KEYS\fR 25 +Keys are null-terminated ASCII strings. +They are passed to hashing routines using the address of the +first character of the string. +.IP \fBTCL_ONE_WORD_KEYS\fR 25 +Keys are single-word values; they are passed to hashing routines +and stored in hash table entries as ``char *'' values. +The pointer value is the key; it need not (and usually doesn't) +actually point to a string. +.IP \fIother\fR 25 +If \fIkeyType\fR is not TCL_STRING_KEYS or TCL_ONE_WORD_KEYS, +then it must be an integer value greater than 1. +In this case the keys will be arrays of ``int'' values, where +\fIkeyType\fR gives the number of ints in each key. +This allows structures to be used as keys. +All keys must have the same size. +Array keys are passed into hashing functions using the address +of the first int in the array. +.PP +\fBTcl_DeleteHashTable\fR deletes all of the entries in a hash +table and frees up the memory associated with the table's +bucket array and entries. +It does not free the actual table structure (pointed to +by \fItablePtr\fR), since that memory is assumed to be managed +by the client. +\fBTcl_DeleteHashTable\fR also does not free or otherwise +manipulate the values of the hash table entries. +If the entry values point to dynamically-allocated memory, then +it is the client's responsibility to free these structures +before deleting the table. +.PP +\fBTcl_CreateHashEntry\fR locates the entry corresponding to a +particular key, creating a new entry in the table if there +wasn't already one with the given key. +If an entry already existed with the given key then \fI*newPtr\fR +is set to zero. +If a new entry was created, then \fI*newPtr\fR is set to a non-zero +value and the value of the new entry will be set to zero. +The return value from \fBTcl_CreateHashEntry\fR is a pointer to +the entry, which may be used to retrieve and modify the entry's +value or to delete the entry from the table. +.PP +\fBTcl_DeleteHashEntry\fR will remove an existing entry from a +table. +The memory associated with the entry itself will be freed, but +the client is responsible for any cleanup associated with the +entry's value, such as freeing a structure that it points to. +.PP +\fBTcl_FindHashEntry\fR is similar to \fBTcl_CreateHashEntry\fR +except that it doesn't create a new entry if the key doesn't exist; +instead, it returns NULL as result. +.PP +\fBTcl_GetHashValue\fR and \fBTcl_SetHashValue\fR are used to +read and write an entry's value, respectively. +Values are stored and retrieved as type ``ClientData'', which is +large enough to hold a pointer value. On almost all machines this is +large enough to hold an integer value too. +.PP +\fBTcl_GetHashKey\fR returns the key for a given hash table entry, +either as a pointer to a string, a one-word (``char *'') key, or +as a pointer to the first word of an array of integers, depending +on the \fIkeyType\fR used to create a hash table. +In all cases \fBTcl_GetHashKey\fR returns a result with type +``char *''. +When the key is a string or array, the result of \fBTcl_GetHashKey\fR +points to information in the table entry; this information will +remain valid until the entry is deleted or its table is deleted. +.PP +\fBTcl_FirstHashEntry\fR and \fBTcl_NextHashEntry\fR may be used +to scan all of the entries in a hash table. +A structure of type ``Tcl_HashSearch'', provided by the client, +is used to keep track of progress through the table. +\fBTcl_FirstHashEntry\fR initializes the search record and +returns the first entry in the table (or NULL if the table is +empty). +Each susequent call to \fBTcl_NextHashEntry\fR returns the +next entry in the table or +NULL if the end of the table has been reached. +A call to \fBTcl_FirstHashEntry\fR followed by calls to +\fBTcl_NextHashEntry\fR will return each of the entries in +the table exactly once, in an arbitrary order. +It is unadvisable to modify the structure of the table, e.g. +by creating or deleting entries, while the search is in +progress. +.PP +\fBTcl_HashStats\fR returns a dynamically-allocated string with +overall information about a hash table, such as the number of +entries it contains, the number of buckets in its hash array, +and the utilization of the buckets. +It is the caller's responsibility to free the result string +by passing it to \fBfree\fR. +.PP +The header file \fBtclHash.h\fR defines the actual data structures +used to implement hash tables. +This is necessary so that clients can allocate Tcl_HashTable +structures and so that macros can be used to read and write +the values of entries. +However, users of the hashing routines should never refer directly +to any of the fields of any of the hash-related data structures; +use the procedures and macros defined here. + +.SH KEYWORDS +hash table, key, lookup, search, value diff --git a/src/libtcl/doc/History.3 b/src/libtcl/doc/History.3 new file mode 100644 index 0000000..f531a83 --- /dev/null +++ b/src/libtcl/doc/History.3 @@ -0,0 +1,72 @@ +'\" +'\" Copyright 1989 Regents of the University of California +'\" Permission to use, copy, modify, and distribute this +'\" documentation for any purpose and without fee is hereby +'\" granted, provided that this notice appears in all copies. +'\" The University of California makes no representations about +'\" the suitability of this material for any purpose. It is +'\" provided "as is" without express or implied warranty. +'\" +'\" $Header: /cvsroot/PROCPLACE/pptinytcl/doc/History.3,v 1.1.1.1 2001/04/20 15:03:06 karl Exp $ SPRITE (Berkeley) +'\" +.so man.macros +.HS Tcl_InitHistory tcl +.BS +.SH NAME +Tcl_InitHistory, Tcl_RecordAndEval \- procedures for managing history list +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +.VS +\fBTcl_InitHistory\fR(\fIinterp\fR) +.VE +.sp +int +\fBTcl_RecordAndEval\fR(\fIinterp, cmd, flags\fR) +.SH ARGUMENTS +.AS Tcl_Interp *interp; +.AP Tcl_Interp *interp in +Tcl interpreter in which history facilities are being used. +.AP char *cmd in +Command (or sequence of commands) to execute. +.AP char flags in +Flags to pass to \fBTcl_Eval\fR (normally 0). If -1, then the +command is not executed; it's just recorded. +.BE + +.SH DESCRIPTION +.PP +The procedure \fBTcl_InitHistory\fR is invoked to enable the +.VS +history facilities in an interpreter (by default there is no +\fBhistory\fR command in an interpreter). +After this command has been executed the \fBhistory\fR +command will be available in \fIinterp\fR and the history facilities +will be initialized. +\fBTcl_InitHistory\fR is invoked automatically by +\fBTcl_RecordAndEval\fR, so it need not be invoked explicitly +unless the \fBhistory\fR command is to +be used before \fBTcl_RecordAndEval\fR has been called. +.VE +.PP +\fBTcl_RecordAndEval\fR is invoked to record a command on the history +list and then execute it. Programs that do not wish to use the history +mechanism should not call \fBTcl_RecordAndEval\fR; they should call +\fBTcl_Eval\fR instead. Furthermore, \fBTcl_RecordAndEval\fR should +only be called with top-level commands typed by the user, since the +purpose of history is to allow the user to re-issue recently-invoked +commands. +.PP +\fBTcl_RecordAndEval\fR does three things. +First, it calls \fBTcl_InitHistory\fR to initialize history for the +interpreter \fIinterp\fR, if this hasn't already been done. +Second, \fBTcl_RecordAndEval\fR saves \fIcommand\fR in +the history list for \fIinterp\fR, making a new event to hold the +command. +Third, \fBTcl_RecordAndEval\fR executes the command by passing it +and \fIflags\fR to \fBTcl_Eval\fR. If \fIflags\fR is -1 then only +the first two steps are taken; the command will not be executed. + +.SH KEYWORDS +command, event, execute, history, interpreter, record diff --git a/src/libtcl/doc/Interp.3 b/src/libtcl/doc/Interp.3 new file mode 100644 index 0000000..2e00585 --- /dev/null +++ b/src/libtcl/doc/Interp.3 @@ -0,0 +1,127 @@ +'\" +'\" Copyright 1989 Regents of the University of California +'\" Permission to use, copy, modify, and distribute this +'\" documentation for any purpose and without fee is hereby +'\" granted, provided that this notice appears in all copies. +'\" The University of California makes no representations about +'\" the suitability of this material for any purpose. It is +'\" provided "as is" without express or implied warranty. +'\" +'\" $Header: /cvsroot/PROCPLACE/pptinytcl/doc/Interp.3,v 1.1.1.1 2001/04/20 15:03:06 karl Exp $ SPRITE (Berkeley) +'\" +.so man.macros +.HS Tcl_Interp tcl +.BS +.SH NAME +Tcl_Interp \- client-visible fields of interpreter structures +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +typedef struct { + char *\fIresult\fR; +.VS + Tcl_FreeProc *\fIfreeProc\fR; +.VE + int \fIerrorLine\fR; +} Tcl_Interp; + +.VS +typedef void Tcl_FreeProc(char *\fIblockPtr\fR); +.VE +.BE + +.SH DESCRIPTION +.PP +The \fBTcl_CreateInterp\fR procedure returns a pointer to a Tcl_Interp +structure. This pointer is then passed into other Tcl procedures +to process commands in the interpreter and perform other operations +on the interpreter. Interpreter structures contain many many fields +that are used by Tcl, but only three that may be accessed by +.VS +clients: \fIresult\fR, \fIfreeProc\fR, and \fIerrorLine\fR. +.PP +The \fIresult\fR and \fIfreeProc\fR fields are used to return +results or error messages from commands. +This information is returned by command procedures back to \fBTcl_Eval\fR, +and by \fBTcl_Eval\fR back to its callers. +The \fIresult\fR field points to the string that represents the +result or error message, and the \fIfreeProc\fR field tells how +to dispose of the storage for the string when it isn't needed anymore. +The easiest way for command procedures to manipulate these +fields is to call procedures like \fBTcl_SetResult\fR +or \fBTcl_AppendResult\fR; they +will hide all the details of managing the fields. +The description below is for those procedures that manipulate the +fields directly. +.PP +Whenever a command procedure returns, it must ensure +that the \fIresult\fR field of its interpreter points to the string +being returned by the command. +The \fIresult\fR field must always point to a valid string. +If a command wishes to return no result then \fIinterp->result\fR +should point to an empty string. +Normally, results are assumed to be statically allocated, +which means that the contents will not change before the next time +\fBTcl_Eval\fR is called or some other command procedure is invoked. +In this case, the \fIfreeProc\fR field must be zero. +Alternatively, a command procedure may dynamically +allocate its return value (e.g. using \fBmalloc\fR) +and store a pointer to it in \fIinterp->result\fR. +In this case, the command procedure must also set \fIinterp->freeProc\fR +to the address of a procedure that can free the value (usually \fBfree\fR). +If \fIinterp->freeProc\fR is non-zero, then Tcl will call \fIfreeProc\fR +to free the space pointed to by \fIinterp->result\fR before it +invokes the next command. +If a client procedure overwrites \fIinterp->result\fR when +\fIinterp->freeProc\fR is non-zero, then it is responsible for calling +\fIfreeProc\fR to free the old \fIinterp->result\fR (the \fBTcl_FreeResult\fR +macro should be used for this purpose). +.PP +\fIFreeProc\fR should have arguments and result that match the +\fBTcl_FreeProc\fR declaration above: it receives a single +argument which is a pointer to the result value to free. +In most applications \fBfree\fR is the only non-zero value ever +used for \fIfreeProc\fR. +However, an application may store a different procedure address +in \fIfreeProc\fR in order to use an alternate memory allocator +or in order to do other cleanup when the result memory is freed. +.PP +As part of processing each command, \fBTcl_Eval\fR initializes +\fIinterp->result\fR +and \fIinterp->freeProc\fR just before calling the command procedure for +the command. The \fIfreeProc\fR field will be initialized to zero, +and \fIinterp->result\fR will point to an empty string. Commands that +do not return any value can simply leave the fields alone. +.VE +Furthermore, the empty string pointed to by \fIresult\fR is actually +part of an array of \fBTCL_RESULT_SIZE\fR characters (approximately 200). +If a command wishes to return a short string, it can simply copy +it to the area pointed to by \fIinterp->result\fR. Or, it can use +the sprintf procedure to generate a short result string at the location +pointed to by \fIinterp->result\fR. +.PP +It is a general convention in Tcl-based applications that the result +of an interpreter is normally in the initialized state described +in the previous paragraph. +Procedures that manipulate an interpreter's result (e.g. by +returning an error) will generally assume that the result +has been initialized when the procedure is called. +If such a procedure is to be called after the result has been +changed, then \fBTcl_ResetResult\fR should be called first to +reset the result to its initialized state. +.PP +The \fIerrorLine\fR +field is valid only after \fBTcl_Eval\fR returns +a \fBTCL_ERROR\fR return code. In this situation the \fIerrorLine\fR +field identifies the line number of the command being executed when +the error occurred. The line numbers are relative to the command +being executed: 1 means the first line of the command passed to +\fBTcl_Eval\fR, 2 means the second line, and so on. +The \fIerrorLine\fR field is typically used in conjunction with +\fBTcl_AddErrorInfo\fR to report information about where an error +occurred. +\fIErrorLine\fR should not normally be modified except by \fBTcl_Eval\fR. + +.SH KEYWORDS +free, initialized, interpreter, malloc, result diff --git a/src/libtcl/doc/SetResult.3 b/src/libtcl/doc/SetResult.3 new file mode 100644 index 0000000..fa87d29 --- /dev/null +++ b/src/libtcl/doc/SetResult.3 @@ -0,0 +1,163 @@ +'\" +'\" Copyright 1989 Regents of the University of California +'\" Permission to use, copy, modify, and distribute this +'\" documentation for any purpose and without fee is hereby +'\" granted, provided that this notice appears in all copies. +'\" The University of California makes no representations about +'\" the suitability of this material for any purpose. It is +'\" provided "as is" without express or implied warranty. +'\" +'\" $Header: /cvsroot/PROCPLACE/pptinytcl/doc/SetResult.3,v 1.1.1.1 2001/04/20 15:03:06 karl Exp $ SPRITE (Berkeley) +'\" +.so man.macros +.HS Tcl_SetResult tcl +.BS +.SH NAME +Tcl_SetResult, Tcl_AppendResult, Tcl_AppendElement, Tcl_ResetResult \- manipulate Tcl result string +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +.VS +\fBTcl_SetResult\fR(\fIinterp, string, freeProc\fR) +.VE +.sp +\fBTcl_AppendResult(\fIinterp, string, string, ... , \fB(char *) NULL\fR) +.sp +.VS +\fBTcl_AppendElement\fR(\fIinterp, string, noSep\fR) +.sp +\fBTcl_ResetResult\fR(\fIinterp\fR) +.sp +\fBTcl_FreeResult\fR(\fIinterp\fR) +.VE +.SH ARGUMENTS +.AS Tcl_FreeProc freeProc +.AP Tcl_Interp *interp out +Interpreter whose result is to be modified. +.AP char *string in +String value to become result for \fIinterp\fR or to be +appended to existing result. +.AP Tcl_FreeProc freeProc in +.VS +Address of procedure to call to release storage at +\fIstring\fR, or \fBTCL_STATIC\fR, \fBTCL_DYNAMIC\fR, or +\fBTCL_VOLATILE\fR. +.AP int noSep in +If non-zero then don't output a space character before this element, +even if the element isn't the first thing in the result string. +.VE +.BE + +.SH DESCRIPTION +.PP +The procedures described here are utilities for setting the +result/error string in a Tcl interpreter. +.PP +\fBTcl_SetResult\fR +arranges for \fIstring\fR to be the return string for the current Tcl +command in \fIinterp\fR, replacing any existing result. +.VS +If \fIfreeProc\fR is \fBTCL_STATIC\fR it means that \fIstring\fR +refers to an area of static storage that is guaranteed not to be +modified until at least the next call to \fBTcl_Eval\fR. +If \fIfreeProc\fR +is \fBTCL_DYNAMIC\fR it means that \fIstring\fR was allocated with a call +to \fBmalloc()\fR and is now the property of the Tcl system. +\fBTcl_SetResult\fR will arrange for the string's storage to be +released by calling \fBfree()\fR when it is no longer needed. +If \fIfreeProc\fR is \fBTCL_VOLATILE\fR it means that \fIstring\fR +points to an area of memory that is likely to be overwritten when +\fBTcl_SetResult\fR returns (e.g. it points to something in a stack frame). +In this case \fBTcl_SetResult\fR will make a copy of the string in +dynamically allocated storage and arrange for the copy to be the +return string for the current Tcl command. +.PP +If \fIfreeProc\fR isn't one of the values \fBTCL_STATIC\fR, +\fBTCL_DYNAMIC\fR, and \fBTCL_VOLATILE\fR, then it is the address +of a procedure that Tcl should call to free the string. +This allows applications to use non-standard storage allocators. +When Tcl no longer needs the storage for the string, it will +call \fIfreeProc\fR. \fIFreeProc\fR should have arguments and +result that match the type \fBTcl_FreeProc\fR: +.nf +.RS + +typedef void Tcl_FreeProc(char *\fIblockPtr\fR); + +.RE +.fi +When \fIfreeProc\fR is called, its \fIblockPtr\fR will be set to +the value of \fIstring\fR passed to \fBTcl_SetResult\fR. +.VE +.PP +If \fIstring\fR is \fBNULL\fR, then \fIfreeProc\fR is ignored +and \fBTcl_SetResult\fR +re-initializes \fIinterp\fR's result to point to the pre-allocated result +area, with an empty string in the result area. +.PP +.VS +If \fBTcl_SetResult\fR is called at a time when \fIinterp\fR holds a +result, \fBTcl_SetResult\fR does whatever is necessary to dispose +of the old result (see the \fBTcl_Interp\fR manual entry for details +on this). +.VE +.PP +\fBTcl_AppendResult\fR makes it easy to build up Tcl results in pieces. +It takes each of its \fIstring\fR arguments and appends them in order +to the current result associated with \fIinterp\fR. +.VS +If the result is in its initialized empty state (e.g. a command procedure +was just invoked or \fBTcl_ResetResult\fR was just called), +then \fBTcl_AppendResult\fR sets the result to the concatenation of +its \fIstring\fR arguments. +.VE +\fBTcl_AppendResult\fR may be called repeatedly as additional pieces +of the result are produced. +\fBTcl_AppendResult\fR takes care of all the +storage management issues associated with managing \fIinterp\fR's +result, such as allocating a larger result area if necessary. +Any number of \fIstring\fR arguments may be passed in a single +call; the last argument in the list must be a NULL pointer. +.PP +\fBTcl_AppendElement\fR is similar to \fBTcl_AppendResult\fR in +.VS +that it allows results to be built up in pieces. +However, \fBTcl_AppendElement\fR takes only a single \fIstring\fR +argument and it appends that argument to the current result +as a proper Tcl list element. +\fBTcl_AppendElement\fR adds backslashes or braces if necessary +to ensure that \fIinterp\fR's result can be parsed as a list and that +\fIstring\fR will be extracted as a single element. +Under normal conditions, \fBTcl_AppendElement\fR will add a space +character to \fIinterp\fR's result just before adding the new +list element, so that the list elements in the result are properly +separated. +However, if \fIinterp\fR's result is empty when \fBTcl_AppendElement\fR +is called, or if the \fInoSep\fR argument is 1, then no space +is added. +.PP +\fBTcl_ResetResult\fR clears the result for \fIinterp\fR, +freeing the memory associated with it if the current result was +dynamically allocated. +It leaves the result in its normal initialized state with +\fIinterp->result\fR pointing to a static buffer containing +\fBTCL_RESULT_SIZE\fR characters, of which the first character +is zero. +\fBTcl_ResetResult\fR also clears the error state managed by +\fBTcl_AddErrorInfo\fR and \fBTcl_SetErrorCode\fR. +.PP +\fBTcl_FreeResult\fR is a macro that performs part of the work +of \fBTcl_ResetResult\fR. +It frees up the memory associated with \fIinterp\fR's result +and sets \fIinterp->freeProc\fR to zero, but it doesn't +change \fIinterp->result\fR or clear error state. +\fBTcl_FreeResult\fR is most commonly used when a procedure +is about to replace one result value with another. +.VE + +.SH "SEE ALSO" +Tcl_AddErrorInfo, Tcl_SetErrorCode, Tcl_Interp + +.SH KEYWORDS +append, command, element, list, result, return value, interpreter diff --git a/src/libtcl/doc/SetVar.3 b/src/libtcl/doc/SetVar.3 new file mode 100644 index 0000000..d7d74c0 --- /dev/null +++ b/src/libtcl/doc/SetVar.3 @@ -0,0 +1,156 @@ +'\" +'\" Copyright 1989 Regents of the University of California +'\" Permission to use, copy, modify, and distribute this +'\" documentation for any purpose and without fee is hereby +'\" granted, provided that this notice appears in all copies. +'\" The University of California makes no representations about +'\" the suitability of this material for any purpose. It is +'\" provided "as is" without express or implied warranty. +'\" +'\" $Header: /cvsroot/PROCPLACE/pptinytcl/doc/SetVar.3,v 1.1.1.1 2001/04/20 15:03:06 karl Exp $ SPRITE (Berkeley) +'\" +.so man.macros +.HS Tcl_SetVar tcl +.BS +.VS +.SH NAME +Tcl_SetVar, Tcl_SetVar2, Tcl_GetVar, Tcl_GetVar2, Tcl_UnsetVar, Tcl_UnsetVar2 \- manipulate Tcl variables +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +char * +\fBTcl_SetVar\fR(\fIinterp, varName, newValue, flags\fR) +.sp +char * +\fBTcl_SetVar2\fR(\fIinterp, name1, name2, newValue, flags\fR) +.sp +char * +\fBTcl_GetVar\fR(\fIinterp, varName, flags\fR) +.sp +char * +\fBTcl_GetVar2\fR(\fIinterp, name1, name2, flags\fR) +.sp +int +\fBTcl_UnsetVar\fR(\fIinterp, varName, flags\fR) +.sp +int +\fBTcl_UnsetVar2\fR(\fIinterp, name1, name2, flags\fR) +.SH ARGUMENTS +.AS Tcl_Interp *newValue +.AP Tcl_Interp *interp in +Interpreter containing variable. +.AP char *varName in +Name of variable. May refer to a scalar variable or an element of +an array variable. +.AP char *newValue in +New value for variable. +.AP int flags in +OR-ed combination of bits providing additional information for +operation. See below for valid values. +.AP char *name1 in +Name of scalar variable, or name of array variable if \fIname2\fR +is non-NULL. +.AP char *name2 in +If non-NULL, gives name of element within array and \fIname1\fR +must refer to an array variable. +.BE + +.SH DESCRIPTION +.PP +These procedures may be used to create, modify, read, and delete +Tcl variables from C code. +\fBTcl_SetVar\fR and \fBTcl_SetVar2\fR will create a new variable +or modify an existing one. +Both of these procedures set the given variable to the value +given by \fInewValue\fR, and they return a pointer to a +copy of the variable's new value, which is stored in Tcl's +variable structure. +Tcl keeps a private copy of the variable's value, so the caller +may change \fInewValue\fR after these procedures return without +affecting the value of the variable. +If an error occurs in setting the variable (e.g. an array +variable is referenced without giving an index into the array), +then NULL is returned. +.PP +The name of the variable may be specified in either of two ways. +If \fBTcl_SetVar\fR is called, the variable name is given as +a single string, \fIvarName\fR. +If \fIvarName\fR contains an open parenthesis and ends with a +close parenthesis, then the value between the parentheses is +treated as an index (which can have any string value) and +the characters before the first open +parenthesis are treated as the name of an array variable. +If \fIvarName\fR doesn't have parentheses as described above, then +the entire string is treated as the name of a scalar variable. +If \fBTcl_SetVar2\fR is called, then the array name and index +have been separated by the caller into two separate strings, +\fIname1\fR and \fIname2\fR respectively; if \fIname2\fR is +zero it means that a scalar variable is being referenced. +.PP +The \fIflags\fR argument may be used to specify any of several +options to the procedures. +It consists of an OR-ed combination of any of the following +bits: +.IP TCL_GLOBAL_ONLY +Under normal circumstances the procedures look up variables +at the current level of procedure call for \fIinterp\fR, or +at global level if there is no call active. +However, if this bit is set in \fIflags\fR then the variable +is looked up at global level even if there is a procedure +call active. +.IP TCL_LEAVE_ERR_MSG +If an error is returned and this bit is set in \fIflags\fR, then +an error message will be left in \fI\%interp->result\fR. If this +flag bit isn't set then no error message is left (\fI\%interp->result\fR +will not be modified). +.IP TCL_APPEND_VALUE +If this bit is set then \fInewValue\fR is appended to the current +value, instead of replacing it. +If the variable is currently undefined, then this bit is ignored. +.IP TCL_LIST_ELEMENT +If this bit is set, then \fInewValue\fR is converted to a valid +Tcl list element before setting (or appending to) the variable. +If the list element is being appended to an non-empty value, then +a space character is appended before the new list element to +separate it from previous elements. +.IP TCL_NO_SPACE +If this bit is set, it prevents the output of a separating space +character in TCL_LIST_ELEMENT appends. +This bit has no effect if the TCL_LIST_ELEMENT bit isn't set. +.PP +\fBTcl_GetVar\fR and \fBTcl_GetVar2\fR return the current value +of a variable. +The arguments to these procedures are treated in the same way +as the arguments to \fBTcl_SetVar\fR and \fBTcl_SetVar2\fR. +Under normal circumstances, the return value is a pointer +to the variable's value (which is stored in Tcl's variable +structure and will not change before the next call to \fBTcl_SetVar\fR +or \fBTcl_SetVar2\fR). +The only bits of \fIflags\fR that are used are TCL_GLOBAL_ONLY +and TCL_LEAVE_ERR_MSG, both of +which have +the same meaning as for \fBTcl_SetVar\fR. +If an error occurs in reading the variable (e.g. the variable +doesn't exist or an array element is specified for a scalar +variable), then NULL is returned. +.PP +\fBTcl_UnsetVar\fR and \fBTcl_UnsetVar2\fR may be used to remove +a variable, so that future calls to \fBTcl_GetVar\fR or \fBTcl_GetVar2\fR +for the variable will return an error. +The arguments to these procedures are treated in the same way +as the arguments to \fBTcl_GetVar\fR and \fBTcl_GetVar2\fR. +If the variable is successfully removed then 0 is returned. +If the variable cannot be removed because it doesn't exist +or because a trace is active for it, then -1 is returned. +If an array element is specified, the given element is removed +but the array remains. +If an array name is specified without an index, then the entire +array is removed. + +.SH "SEE ALSO" +Tcl_TraceVar + +.SH KEYWORDS +array, interpreter, scalar, set, unset, variable +.VE diff --git a/src/libtcl/doc/SplitList.3 b/src/libtcl/doc/SplitList.3 new file mode 100644 index 0000000..175e5a0 --- /dev/null +++ b/src/libtcl/doc/SplitList.3 @@ -0,0 +1,159 @@ +'\" +'\" Copyright 1989-1991 Regents of the University of California +'\" Permission to use, copy, modify, and distribute this +'\" documentation for any purpose and without fee is hereby +'\" granted, provided that this notice appears in all copies. +'\" The University of California makes no representations about +'\" the suitability of this material for any purpose. It is +'\" provided "as is" without express or implied warranty. +'\" +'\" $Header: /cvsroot/PROCPLACE/pptinytcl/doc/SplitList.3,v 1.1.1.1 2001/04/20 15:03:06 karl Exp $ SPRITE (Berkeley) +'\" +.so man.macros +.HS Tcl_SplitList tcl +.BS +.SH NAME +Tcl_SplitList, Tcl_Merge, Tcl_ScanElement, Tcl_ConvertElement \- manipulate Tcl lists +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +int +\fBTcl_SplitList\fR(\fIinterp, list, argcPtr, argvPtr\fR) +.sp +char * +\fBTcl_Merge\fR(\fIargc, argv\fR) +.sp +.VS +int +\fBTcl_ScanElement\fR(\fIsrc, flagsPtr\fR) +.sp +int +\fBTcl_ConvertElement\fR(\fIsrc, dst, flags\fR) +.VE +.SH ARGUMENTS +.AS Tcl_Interp ***argvPtr +.AP Tcl_Interp *interp out +Interpreter to use for error reporting. +.AP char *list in +Pointer to a string with proper list structure. +.AP int *argcPtr out +Filled in with number of elements in \fIlist\fR. +.AP char ***argvPtr out +\fI*argvPtr\fR will be filled in with the address of an array of +pointers to the strings that are the extracted elements of \fIlist\fR. +There will be \fI*argcPtr\fR valid entries in the array, followed by +a NULL entry. +.AP int argc in +Number of elements in \fIargv\fR. +.AP char **argv in +Array of strings to merge together into a single list. +Each string will become a separate element of the list. +.AP char *src in +.VS +String that is to become an element of a list. +.AP int *flagsPtr in +Pointer to word to fill in with information about \fIsrc\fR. +The value of *\fIflagsPtr\fR must be passed to \fBTcl_ConvertElement\fR. +.AP char *dst in +Place to copy converted list element. Must contain enough characters +to hold converted string. +.AP int flags in +Information about \fIsrc\fR. Must be value returned by previous +call to \fBTcl_ScanElement\fR, possibly OR-ed +with \fBTCL_DONT_USE_BRACES\fR. +.VE +.BE + +.SH DESCRIPTION +.PP +These procedures may be used to disassemble and reassemble Tcl lists. +\fBTcl_SplitList\fR breaks a list up into its constituent elements, +returning an array of pointers to the elements using +\fIargcPtr\fR and \fIargvPtr\fR. +While extracting the arguments, \fBTcl_SplitList\fR obeys the usual +rules for backslash substitutions and braces. The area of +memory pointed to by \fI*argvPtr\fR is dynamically allocated; in +addition to the array of pointers, it +also holds copies of all the list elements. It is the caller's +responsibility to free up all of this storage by calling +.DS +\fBfree\fR((char *) \fI*argvPtr\fR) +.DE +when the list elements are no longer needed. +.PP +\fBTcl_SplitList\fR normally returns \fBTCL_OK\fR, which means the list was +successfully parsed. +If there was a syntax error in \fIlist\fR, then \fBTCL_ERROR\fR is returned +and \fIinterp->result\fR will point to an error message describing the +problem. +If \fBTCL_ERROR\fR is returned then no memory is allocated and \fI*argvPtr\fR +is not modified. +.PP +\fBTcl_Merge\fR is the inverse of \fBTcl_SplitList\fR: it +takes a collection of strings given by \fIargc\fR +and \fIargv\fR and generates a result string +that has proper list structure. +This means that commands like \fBindex\fR may be used to +extract the original elements again. +In addition, if the result of \fBTcl_Merge\fR is passed to \fBTcl_Eval\fR, +it will be parsed into \fIargc\fR words whose values will +be the same as the \fIargv\fR strings passed to \fBTcl_Merge\fR. +\fBTcl_Merge\fR will modify the list elements with braces and/or +backslashes in order to produce proper Tcl list structure. +The result string is dynamically allocated +using \fBmalloc()\fR; the caller must eventually release the space +using \fBfree()\fR. +.PP +If the result of \fBTcl_Merge\fR is passed to \fBTcl_SplitList\fR, +the elements returned by \fBTcl_SplitList\fR will be identical to +those passed into \fBTcl_Merge\fR. +However, the converse is not true: if \fBTcl_SplitList\fR +is passed a given string, and the resulting \fIargc\fR and +\fIargv\fR are passed to \fBTcl_Merge\fR, the resulting string +may not be the same as the original string passed to \fBTcl_SplitList\fR. +This is because \fBTcl_Merge\fR may use backslashes and braces +differently than the original string. +.PP +.VS +\fBTcl_ScanElement\fR and \fBTcl_ConvertElement\fR are the +procedures that do all of the real work of \fBTcl_Merge\fR. +\fBTcl_ScanElement\fR scans its \fIsrc\fR argument +and determines how to use backslashes and braces +when converting it to a list element. +It returns an overestimate of the number of characters +required to represent \fIsrc\fR as a list element, and +it stores information in \fI*flagsPtr\fR that is needed +by \fBTcl_ConvertElement\fR. +.PP +\fBTcl_ConvertElement\fR is a companion procedure to \fBTcl_ScanElement\fR. +It does the actual work of converting a string to a list element. +Its \fIflags\fR argument must be the same as the value returned +by \fBTcl_ScanElement\fR. +\fBTcl_ConvertElement\fR writes a proper list element to memory +starting at *\fIdst\fR and returns a count of the total number +of characters written, which will be no more than the result +returned by \fBTcl_ScanElement\fR. +\fBTcl_ConvertElement\fR writes out only the actual list element +without any leading or trailing spaces: it is up to the caller to +include spaces between adjacent list elements. +.PP +\fBTcl_ConvertElement\fR uses one of two different approaches to +handle the special characters in \fIsrc\fR. Wherever possible, it +handles special characters by surrounding the string with braces. +This produces clean-looking output, but can't be used in some situations, +such as when \fIsrc\fR contains unmatched braces. +In these situations, \fBTcl_ConvertElement\fR handles special +characters by generating backslash sequences for them. +The caller may insist on the second approach by OR-ing the +flag value returned by \fBTcl_ScanElement\fR with +\fBTCL_DONT_USE_BRACES\fR. +Although this will produce an uglier result, it is useful in some +special situations, such as when \fBTcl_ConvertElement\fR is being +used to generate a portion of an argument for a Tcl command. +In this case, surrounding \fIsrc\fR with curly braces would cause +the command not to be parsed correctly. +.VE + +.SH KEYWORDS +backslash, convert, element, list, merge, split, strings diff --git a/src/libtcl/doc/StrMatch.3 b/src/libtcl/doc/StrMatch.3 new file mode 100644 index 0000000..f11114f --- /dev/null +++ b/src/libtcl/doc/StrMatch.3 @@ -0,0 +1,41 @@ +'\" +'\" Copyright 1989 Regents of the University of California +'\" Permission to use, copy, modify, and distribute this +'\" documentation for any purpose and without fee is hereby +'\" granted, provided that this notice appears in all copies. +'\" The University of California makes no representations about +'\" the suitability of this material for any purpose. It is +'\" provided "as is" without express or implied warranty. +'\" +'\" $Header: /cvsroot/PROCPLACE/pptinytcl/doc/StrMatch.3,v 1.1.1.1 2001/04/20 15:03:06 karl Exp $ SPRITE (Berkeley) +'\" +.so man.macros +.HS Tcl_StringMatch tcl +.BS +.SH NAME +Tcl_StringMatch \- test whether a string matches a pattern +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +int +\fBTcl_StringMatch\fR(\fIstring\fR, \fIpattern\fR) +.SH ARGUMENTS +.AP char *string in +String to test. +.AP char *pattern in +Pattern to match against string. May contain special +characters from the set *?\e[]. +.BE + +.SH DESCRIPTION +.PP +This utility procedure determines whether a string matches +a given pattern. If it does, then \fBTcl_StringMatch\fR returns +1. Otherwise \fBTcl_StringMatch\fR returns 0. The algorithm +used for matching is the same algorithm used in the ``string match'' +Tcl command and is similar to the algorithm used by the C-shell +for file name matching; see the Tcl manual entry for details. + +.SH KEYWORDS +match, pattern, string diff --git a/src/libtcl/doc/Tcl.n b/src/libtcl/doc/Tcl.n new file mode 100644 index 0000000..c503c8a --- /dev/null +++ b/src/libtcl/doc/Tcl.n @@ -0,0 +1,2832 @@ +'\" +'\" Copyright 1989-1992 Regents of the University of California +'\" Permission to use, copy, modify, and distribute this +'\" documentation for any purpose and without fee is hereby +'\" granted, provided that this notice appears in all copies. +'\" The University of California makes no representations about +'\" the suitability of this material for any purpose. It is +'\" provided "as is" without express or implied warranty. +'\" +'\" $Header: /cvsroot/PROCPLACE/pptinytcl/doc/Tcl.n,v 1.1.1.1 2001/04/20 15:03:06 karl Exp $ SPRITE (Berkeley) +' +.so man.macros +.de UL +\\$1\l'|0\(ul'\\$2 +.. +.HS Tcl tcl +.BS +.SH NAME +Tcl \- overview of tool command language facilities +.BE + +.SH INTRODUCTION +.PP +Tcl stands for ``tool command language'' and is pronounced ``tickle.'' +It is actually two things: +a language and a library. +First, Tcl is a simple textual language, +intended primarily for issuing commands to interactive programs such +as text editors, debuggers, illustrators, and shells. It has +a simple syntax and is also programmable, so +Tcl users can write command procedures to provide more powerful +commands than those in the built-in set. +.PP +Second, Tcl is a library package that can be embedded in application +programs. The Tcl library consists of a parser for the Tcl +language, routines to implement the Tcl built-in commands, and +procedures that allow each application to extend Tcl with additional +commands specific to that application. The application program +generates Tcl commands and passes them to the Tcl parser for +execution. Commands may be generated +by reading characters from an input +source, or by associating command strings with elements of the +application's user interface, such as menu entries, buttons, or +keystrokes. +When the Tcl library receives commands it parses them +into component fields and executes built-in commands directly. +For commands implemented by the +application, Tcl calls back to the application to execute the +commands. In many cases commands will invoke recursive invocations +of the Tcl interpreter by passing in additional strings to execute +(procedures, looping commands, and conditional commands all work +in this way). +.PP +An application program gains three advantages by using Tcl for +its command language. First, Tcl provides a standard syntax: once +users know Tcl, they will be able to issue commands easily +to any Tcl-based application. Second, Tcl provides programmability. +All a Tcl application needs to do is to implement a few +application-specific low-level commands. Tcl provides many utility +commands plus a general programming interface for building up +complex command procedures. By using Tcl, applications need not +re-implement these features. Third, Tcl can be used as +.VS +a common language for communicating between applications. +Inter-application communication is not built into the Tcl core +described here, but various add-on libraries, such as the Tk toolkit, +allow applications to issue commands to each other. +This makes it possible for applications to work together in much +more powerful ways than was previously possible. +.VE +.PP +This manual page focuses primarily on the Tcl language. It describes +the language syntax and the built-in commands that will be available in +any application based on Tcl. The individual library +procedures are described in more detail in separate manual pages, one +per procedure. + +.SH "INTERPRETERS" +.PP +The central data structure in Tcl is an interpreter (C type +``Tcl_Interp''). An interpreter consists of a set of command +bindings, a set of variable values, and a few other miscellaneous +pieces of state. Each Tcl command is interpreted in the context +of a particular interpreter. +Some Tcl-based applications will maintain +multiple interpreters simultaneously, each associated with a +different widget or portion of the application. +Interpreters are relatively lightweight structures. They can +be created and deleted quickly, so application programmers should feel free to +use multiple interpreters if that simplifies the application. +Eventually Tcl will provide a mechanism for sending Tcl commands +and results back and forth between interpreters, even if the +interpreters are managed by different processes. + +.SH "DATA TYPES" +.PP +Tcl supports only one type of data: strings. All commands, +all arguments to commands, all command results, and all variable values +are strings. +Where commands require numeric arguments or return numeric results, +the arguments and results are passed as strings. +Many commands expect their string arguments to have certain formats, +but this interpretation is +up to the individual commands. For example, arguments often contain +Tcl command strings, which may get executed as part of the commands. +The easiest way to understand the Tcl interpreter is to remember that +everything is just an operation on a string. In many cases Tcl constructs +will look similar to more structured constructs from other languages. +However, the Tcl constructs +are not structured at all; they are just strings of characters, and this +gives them a different behavior than the structures they may look like. +.PP +Although the exact interpretation of a Tcl string depends on who is +doing the interpretation, there are three common forms that strings +take: commands, expressions, and lists. The major sections below +discuss these three forms in more detail. + +.SH "BASIC COMMAND SYNTAX" +.PP +The Tcl language has syntactic similarities to both the Unix shells +and Lisp. However, the interpretation of commands is different +in Tcl than in either of those other two systems. +A Tcl command string consists of one or more commands separated +by newline characters or semi-colons. +Each command consists of a collection of fields separated by +white space (spaces or tabs). +The first field must be the name of a command, and the +additional fields, if any, are arguments that will be passed to +that command. For example, the command +.DS +\fBset a 22\fR +.DE +has three fields: the first, \fBset\fR, is the name of a Tcl command, and +the last two, \fBa\fR and \fB22\fR, will be passed as arguments to +the \fBset\fR command. The command name may refer either to a built-in +Tcl command, an application-specific command bound in with the library +procedure \fBTcl_CreateCommand\fR, or a command procedure defined with the +\fBproc\fR built-in command. +Arguments are passed literally as +text strings. Individual commands may interpret those strings in any +fashion they wish. The \fBset\fR command, for example, will treat its +first argument as the name of a variable and its second argument as a +string value to assign to that variable. For other commands arguments +may be interpreted as integers, lists, file names, or Tcl commands. +.PP +.VS +Command names should normally be typed completely (e.g. no abbreviations). +However, if the Tcl interpreter cannot locate a command it invokes a +special command named \fBunknown\fR which attempts to find or create +the command. +For example, at many sites \fBunknown\fR will search +through library directories for the desired command and create it +as a Tcl procedure if it is found. +The \fBunknown\fR command often provides automatic completion of +abbreviated commands, but usually only for commands that were typed +interactively. +It's probably a bad idea to use abbreviations in command scripts +and other forms that will be re-used over time: changes +to the command set may cause abbreviations to become ambiguous, +resulting in scripts that no longer work. +.VE + +.SH "COMMENTS" +.PP +If the first non-blank character in a command is \fB#\fR, then everything +from the \fB#\fR up through the next newline character is treated as +a comment and ignored. When comments are embedded inside nested +commands (e.g. fields enclosed in braces) they must have properly-matched +braces (this is necessary because when Tcl parses the top-level command +it doesn't yet know that the nested field will be used as a command so +it cannot process the nested comment character as a comment). + +.SH "GROUPING ARGUMENTS WITH DOUBLE-QUOTES" +.PP +Normally each argument field ends at the next white space, but +double-quotes may be used to create arguments with embedded +space. If an argument +field begins with a double-quote, then the argument isn't +terminated by white space (including newlines) or a semi-colon +(see below for information on semi-colons); instead it ends at the next +double-quote character. The double-quotes are not included +in the resulting argument. For example, the +command +.DS +\fBset a "This is a single argument"\fR +.DE +will pass two arguments to \fBset\fR: \fBa\fR and +\fBThis is a single argument\fR. Within double-quotes, command +substitutions, variable substitutions, and backslash substitutions +still occur, as described below. If the first character of a +command field is not a quote, then quotes receive no special +interpretation in the parsing of that field. + +.SH "GROUPING ARGUMENTS WITH BRACES" +.PP +Curly braces may also be used for grouping arguments. They are +similar to quotes except for two differences. First, they nest; +this makes them easier to use for complicated arguments like nested Tcl +command strings. Second, the substitutions described below for +commands, variables, and backslashes do \fInot\fR occur in arguments +enclosed in braces, so braces can be used to prevent substitutions +where they are undesirable. +If an argument field +begins with a left brace, then the argument ends at the matching +right brace. Tcl will strip off the outermost layer of braces +and pass the information between the braces to the command without +any further modification. For example, in the command +.DS +\fBset a {xyz a {b c d}}\fR +.DE +the \fBset\fR command will receive two arguments: \fBa\fR +and \fBxyz a {b c d}\fR. +.PP +When braces or quotes are in effect, the matching brace +or quote need not be on +the same line as the starting quote or brace; in this case +the newline will be +included in the argument field along with any other characters up to the +matching brace or quote. For example, the \fBeval\fR command +takes one +argument, which is a command string; \fBeval\fR invokes the Tcl +interpreter to execute the command string. The command +.DS +\fBeval { + set a 22 + set b 33 +}\fR +.DE +will assign the value \fB22\fR to \fBa\fR and \fB33\fR to \fBb\fR. +.PP +If the first character of a command field is not a left +brace, then neither left nor right +braces in the field will be treated specially (except as part of +variable substitution; see below). + +.SH "COMMAND SUBSTITUTION WITH BRACKETS" +.PP +If an open bracket occurs in a field of a command, then +command substitution occurs (except for fields enclosed in +braces). All of the text up to the matching +close bracket is treated as a Tcl command and executed immediately. +Then the result of that command is substituted for the bracketed +text. For example, consider the command +.DS +\fBset a [set b]\fR +.DE +When the \fBset\fR command has only a single argument, it is the +name of a variable and \fBset\fR returns the contents of that +variable. In this case, if variable \fBb\fR has the value \fBfoo\fR, +then the command above is equivalent to the command +.DS +\fBset a foo\fR +.DE +Brackets can be used in more complex ways. For example, if the +variable \fBb\fR has the value \fBfoo\fR and the variable \fBc\fR +has the value \fBgorp\fR, then the command +.DS +\fBset a xyz[set b].[set c]\fR +.DE +is equivalent to the command +.DS +\fBset a xyzfoo.gorp\fR +.DE +.VS +A bracketed command may contain multiple commands separated by +newlines or semi-colons in the usual fashion. +In this case the value of the last command is used for substitution. +For example, the command +.DS +\fBset a x[set b 22 +expr $b+2]x\fR +.DE +is equivalent to the command +.DS +\fBset a x24x\fR +.DE +.VE +If a field is enclosed in braces then the brackets and the characters +between them are not interpreted specially; they are passed through +to the argument verbatim. + +.SH "VARIABLE SUBSTITUTION WITH $" +.PP +The dollar sign (\fB$\fR) may be used as a special shorthand form +for substituting variable values. +If \fB$\fR appears in an argument that isn't enclosed in braces +then variable substitution will occur. The characters after +the \fB$\fR, up to the first character that isn't a number, letter, or +underscore, are taken as a variable name and the string value of that +variable is substituted for the name. +.VS +For example, if variable \fBfoo\fR +has the value \fBtest\fR, then the command +.DS C +\fBset a $foo.c\fR +.DE +is equivalent to the command +.DS C +\fBset a test.c\fR +.DE +.PP +There are two special forms for variable substitution. +If the next character after the name of the variable is an +open parenthesis, then the variable is assumed to be an array +name, and all of the characters between the open parenthesis +and the next close parenthesis are taken as an index into the array. +Command substitutions and variable substitutions are +performed on the information between the parentheses before it is +used as an index. +For example, if the variable \fBx\fR is an array with one element +named \fBfirst\fR and value \fB87\fR and another element named +\fB14\fR and value \fBmore\fR, then the command +.DS C +\fBset a xyz$x(first)zyx +.DE +is equivalent to the command +.DS C +\fBset a xyz87zyx\fR +.DE +If the variable \fBindex\fR has the value \fB14\fR, then the command +.DS C +\fBset a xyz$x($index)zyx +.DE +is equivalent to the command +.DS C +\fBset a xyzmorezyx +.DE +For more information on arrays, see VARIABLES AND ARRAYS below. +.PP +The second special form for variables occurs when +the dollar sign is followed by an open curly brace. +In this case the variable name consists of all the characters +up to the next curly brace. +Array references are not possible in this form: the name +between braces is assumed to refer to a scalar variable. +For example, if variable \fBfoo\fR has the value \fBtest\fR, +then the command +.DS C +\fBset a abc${foo}bar\fR +.DE +is equivalent to the command +.DS C +\fBset a abctestbar\fR +.DE +.VE +Variable substitution does not occur in arguments that are enclosed +in braces: the +dollar sign and variable name are passed through to the argument verbatim. +.PP +The dollar sign abbreviation is simply a shorthand form. \fB$a\fR is +completely equivalent to \fB[set a]\fR; it is provided as a convenience +to reduce typing. + +.SH "SEPARATING COMMANDS WITH SEMI-COLONS" +.PP +Normally, each command occupies one line (the command is terminated by +a newline character). However, semi-colon (``;'') is treated +as a command separator character; multiple commands may be placed +on one line by separating them with a semi-colon. Semi-colons are +not treated as command separators if they appear within curly braces +or double-quotes. + +.SH "BACKSLASH SUBSTITUTION" +.PP +Backslashes may be used to insert non-printing characters into +command fields and also to insert special characters like +braces and brackets into fields +without them being interpreted specially as described above. +The backslash sequences understood by the Tcl interpreter are +listed below. In each case, the backslash +sequence is replaced by the given character: +.TP 20 +\fB\eb\fR +Backspace (0x8). +.TP 20 +\fB\ef\fR +Form feed (0xc). +.TP 20 +\fB\en\fR +Newline (0xa). +.TP 20 +\fB\er\fR +Carriage-return (0xd). +.TP 20 +\fB\et\fR +Tab (0x9). +.TP 20 +\fB\ev\fR +Vertical tab (0xb). +.TP 20 +\fB\e{\fR +Left brace (``{''). +.TP 20 +\fB\e}\fR +Right brace (``}''). +.TP 20 +\fB\e[\fR +Open bracket (``[''). +.TP 20 +\fB\e]\fR +Close bracket (``]''). +.TP 20 +\fB\e$\fR +Dollar sign (``$''). +.TP 20 +\fB\e\fR +Space (`` ''): doesn't terminate argument. +.br +.TP 20 +\fB\e;\fR +Semi-colon: doesn't terminate command. +.TP 20 +\fB\e"\fR +Double-quote. +.TP 20 +\fB\e\fR +Nothing: this joins two lines together +into a single line. This backslash feature is unique in that +it will be applied even when the sequence occurs within braces. +.TP 20 +\fB\e\e\fR +Backslash (``\e''). +.TP 20 +\fB\e\fIddd\fR +The digits \fIddd\fR (one, two, or three of them) give the octal value of +the character. Null characters may not be embedded in command fields; +if \fIddd\fR is zero then the backslash sequence is ignored (i.e. it +maps to an empty string). +.PP +For example, in the command +.DS +\fBset a \e{x\e[\e\0yz\e141\fR +.DE +the second argument to \fBset\fR will be ``\fB{x[\0yza\fR''. +.PP +If a backslash is followed by something other than one of the options +described above, then the backslash is transmitted to the argument +field without any special processing, and the Tcl scanner continues +normal processing with the next character. For example, in the +command +.DS +\fBset \e*a \e\e\e{foo\fR +.DE +The first argument to \fBset\fR will be \fB\e*a\fR and the second +argument will be \fB\e{foo\fR. +.PP +If an argument is enclosed in braces, then backslash sequences inside +the argument are parsed but no substitution occurs (except for +backslash-newline): the backslash +sequence is passed through to the argument as is, without making +any special interpretation of the characters in the backslash sequence. +In particular, backslashed braces are not counted in locating the +matching right brace that terminates the argument. +For example, in the +command +.DS +\fBset a {\e{abc}\fR +.DE +the second argument to \fBset\fR will be \fB\e{abc\fR. +.PP +This backslash mechanism is not sufficient to generate absolutely +any argument structure; it only covers the +most common cases. To produce particularly complicated arguments +it is probably easiest to use the \fBformat\fR command along with +command substitution. + +.SH "COMMAND SUMMARY" +.IP [1] +A command is just a string. +.IP [2] +Within a string commands are separated by newlines or semi-colons +(unless the newline or semi-colon is within braces or brackets +or is backslashed). +.IP [3] +A command consists of fields. The first field is the name of the command. +The other fields are strings that are passed to that command as arguments. +.IP [4] +Fields are normally separated by white space. +.IP [5] +Double-quotes allow white space and semi-colons to appear within +a single argument. +Command substitution, variable substitution, and backslash substitution +still occur inside quotes. +.IP [6] +Braces defer interpretation of special characters. +If a field begins with a left brace, then it consists of everything +between the left brace and the matching right brace. The +braces themselves are not included in the argument. +No further processing is done on the information between the braces +except that backslash-newline sequences are eliminated. +.IP [7] +If a field doesn't begin with a brace then backslash, +variable, and command substitution are done on the field. Only a +single level of processing is done: the results of one substitution +are not scanned again for further substitutions or any other +special treatment. Substitution can +occur on any field of a command, including the command name +as well as the arguments. +.IP [8] +If the first non-blank character of a command is a \fB#\fR, everything +from the \fB#\fR up through the next newline is treated as a comment +and ignored. + +.SH "EXPRESSIONS" +.VS +.PP +The second major interpretation applied to strings in Tcl is +as expressions. Several commands, such as \fBexpr\fR, \fBfor\fR, +and \fBif\fR, treat one or more of their arguments as expressions +and call the Tcl expression processors (\fBTcl_ExprLong\fR, +\fBTcl_ExprBoolean\fR, etc.) to evaluate them. +The operators permitted in Tcl expressions are a subset of +the operators permitted in C expressions, and they have the +same meaning and precedence as the corresponding C operators. +Expressions almost always yield numeric results +(integer or floating-point values). +For example, the expression +.DS +\fB8.2 + 6\fR +.DE +evaluates to 14.2. +Tcl expressions differ from C expressions in the way that +operands are specified, and in that Tcl expressions support +non-numeric operands and string comparisons. +.PP +A Tcl expression consists of a combination of operands, operators, +and parentheses. +White space may be used between the operands and operators and +parentheses; it is ignored by the expression processor. +Where possible, operands are interpreted as integer values. +Integer values may be specified in decimal (the normal case), in octal (if the +first character of the operand is \fB0\fR), or in hexadecimal (if the first +two characters of the operand are \fB0x\fR). +If an operand does not have one of the integer formats given +above, then it is treated as a floating-point number if that is +possible. Floating-point numbers may be specified in any of the +ways accepted by an ANSI-compliant C compiler (except that the +``f'', ``F'', ``l'', and ``L'' suffixes will not be permitted in +most installations). For example, all of the +following are valid floating-point numbers: 2.1, 3., 6e4, 7.91e+16. +If no numeric interpretation is possible, then an operand is left +as a string (and only a limited set of operators may be applied to +it). +.PP +Operands may be specified in any of the following ways: +.IP [1] +As an numeric value, either integer or floating-point. +.IP [2] +As a Tcl variable, using standard \fB$\fR notation. +The variable's value will be used as the operand. +.IP [3] +As a string enclosed in double-quotes. +The expression parser will perform backslash, variable, and +command substitutions on the information between the quotes, +and use the resulting value as the operand +.IP [4] +As a string enclosed in braces. +The characters between the open brace and matching close brace +will be used as the operand without any substitutions. +.IP [5] +As a Tcl command enclosed in brackets. +The command will be executed and its result will be used as +the operand. +.LP +Where substitutions occur above (e.g. inside quoted strings), they +are performed by the expression processor. +However, an additional layer of substitution may already have +been performed by the command parser before the expression +processor was called. +As discussed below, it is usually best to enclose expressions +in braces to prevent the command parser from performing substitutions +on the contents. +.PP +For some examples of simple expressions, suppose the variable +\fBa\fR has the value 3 and +the variable \fBb\fR has the value 6. +Then the expression on the left side of each of the lines below +will evaluate to the value on the right side of the line: +.DS +.ta 6c +\fB3.1 + $a 6.1 +2 + "$a.$b" 5.6 +4*[llength "6 2"] 8 +{word one} < "word $a" 0\fR +.DE +.PP +The valid operators are listed below, grouped in decreasing order +of precedence: +.TP 20 +\fB\-\0\0~\0\0!\fR +Unary minus, bit-wise NOT, logical NOT. None of these operands +may be applied to string operands, and bit-wise NOT may be +applied only to integers. +.TP 20 +\fB*\0\0/\0\0%\fR +Multiply, divide, remainder. None of these operands may be +applied to string operands, and remainder may be applied only +to integers. +.TP 20 +\fB+\0\0\-\fR +Add and subtract. Valid for any numeric operands. +.TP 20 +\fB<<\0\0>>\fR +Left and right shift. Valid for integer operands only. +.TP 20 +\fB<\0\0>\0\0<=\0\0>=\fR +Boolean less, greater, less than or equal, and greater than or equal. +Each operator produces 1 if the condition is true, 0 otherwise. +These operators may be applied to strings as well as numeric operands, +in which case string comparison is used. +.TP 20 +\fB==\0\0!=\fR +Boolean equal and not equal. Each operator produces a zero/one result. +Valid for all operand types. +.TP 20 +\fB&\fR +Bit-wise AND. Valid for integer operands only. +.TP 20 +\fB^\fR +Bit-wise exclusive OR. Valid for integer operands only. +.TP 20 +\fB|\fR +Bit-wise OR. Valid for integer operands only. +.TP 20 +\fB&&\fR +Logical AND. Produces a 1 result if both operands are non-zero, 0 otherwise. +Valid for numeric operands only (integers or floating-point). +.TP 20 +\fB||\fR +Logical OR. Produces a 0 result if both operands are zero, 1 otherwise. +Valid for numeric operands only (integers or floating-point). +.TP 20 +\fIx\fB?\fIy\fB:\fIz\fR +If-then-else, as in C. If \fIx\fR +evaluates to non-zero, then the result is the value of \fIy\fR. +Otherwise the result is the value of \fIz\fR. +The \fIx\fR operand must have a numeric value. +.LP +See the C manual for more details on the results +produced by each operator. +All of the binary operators group left-to-right within the same +precedence level. For example, the expression +.DS +\fB4*2 < 7\fR +.DE +evaluates to 0. +.PP +The \fB&&\fP, \fB||\fP, and \fB?:\fP operators have ``lazy +evaluation'', just as in C, +which means that operands are not evaluated if they are +not needed to determine the outcome. For example, in +.DS +\fB$v ? [a] : [b]\fR +.DE +only one of \fB[a]\fR or \fB[b]\fR will actually be evaluated, +depending on the value of \fB$v\fP. +.PP +All internal computations involving integers are done with the C type +\fIlong\fP, and all internal computations involving floating-point are +done with the C type \fIdouble\fP. +When converting a string to floating-point, exponent overflow is +detected and results in a Tcl error. +For conversion to integer from string, detection of overflow depends +on the behavior of some routines in the local C library, so it should +be regarded as unreliable. +In any case, overflow and underflow are generally not detected +reliably for intermediate results. +.PP +Conversion among internal representations for integer, floating-point, +and string operands is done automatically as needed. +For arithmetic computations, integers are used until some +floating-point number is introduced, after which floating-point is used. +For example, +.DS +\fB5 / 4\fR +.DE +yields the result 1, while +.DS +\fB5 / 4.0\fR +\fB5 / ( [string length "abcd"] + 0.0 ) +.DE +both yield the result 1.25. +.PP +String values may be used as operands of the comparison operators, +although the expression evaluator tries to do comparisons as integer +or floating-point when it can. +If one of the operands of a comparison is a string and the other +has a numeric value, the numeric operand is converted back to +a string using the C \fIsprintf\fP format specifier +\fB%d\fR for integers and \fB%g\fR for floating-point values. +For example, the expressions +.DS +\fB"0x03" > "2"\fR +\fB"0y" < "0x12"\fR +.DE +both evaluate to 1. The first comparison is done using integer +comparison, and the second is done using string comparison after +the second operand is converted to the string ``18''. +.VE +.PP +In general it is safest to enclose an expression in braces when +entering it in a command: otherwise, if the expression contains +any white space then the Tcl interpreter will split it +among several arguments. For example, the command +.DS C +\fBexpr $a + $b\fR +.DE +results in three arguments being passed to \fBexpr\fR: \fB$a\fR, +\fB+\fR, and \fB$b\fR. In addition, if the expression isn't in braces +then the Tcl interpreter will perform variable and command substitution +immediately (it will happen in the command parser rather than in +the expression parser). In many cases the expression is being +passed to a command that will evaluate the expression later (or +even many times if, for example, the expression is to be used to +decide when to exit a loop). Usually the desired goal is to re-do +the variable or command substitutions each time the expression is +evaluated, rather than once and for all at the beginning. For example, +the command +.DS C +.ta 7c +\fBfor {set i 1} $i<=10 {incr i} {...}\fR *** WRONG *** +.DE +is probably intended to iterate over all values of \fBi\fR from 1 to 10. +After each iteration of the body of the loop, \fBfor\fR will pass +its second argument to the expression evaluator to see whether or not +to continue processing. Unfortunately, in this case the value of \fBi\fR +in the second argument will be substituted once and for all when the +\fBfor\fR command is parsed. If \fBi\fR was 0 before the \fBfor\fR +command was invoked then \fBfor\fR's second argument will be \fB0<=10\fR +which will always evaluate to 1, even though \fBi\fR's value eventually +becomes greater than 10. In the above case the loop will never +terminate. Instead, the expression should be placed in braces: +.DS C +.ta 7c +\fBfor {set i 1} {$i<=10} {incr i} {...}\fR *** RIGHT *** +.DE +This causes the substitution of \fBi\fR's +value to be delayed; it will be re-done each time the expression is +evaluated, which is the desired result. + +.SH LISTS +.PP +The third major way that strings are interpreted in Tcl is as lists. +A list is just a string with a list-like structure +consisting of fields separated by white space. For example, the +string +.DS +\fBAl Sue Anne John\fR +.DE +is a list with four elements or fields. +Lists have the same basic structure as command strings, except +that a newline character in a list is treated as a field separator +just like space or tab. Conventions for braces and quotes +and backslashes are the same for lists as for commands. For example, +the string +.DS +\fBa b\e c {d e {f g h}}\fR +.DE +is a list with three elements: \fBa\fR, \fBb c\fR, and \fBd e {f g h}\fR. +Whenever an element +is extracted from a list, the same rules about braces and quotes and +backslashes are applied as for commands. Thus in the example above +when the third element is extracted from the list, the result is +.DS +\fBd e {f g h}\fR +.DE +(when the field was extracted, all that happened was to strip off +the outermost layer of braces). Command substitution and +variable substitution are never +made on a list (at least, not by the list-processing commands; the +list can always be passed to the Tcl interpreter for evaluation). +.PP +The Tcl commands \fBconcat\fR, \fBforeach\fR, +.VS +\fBlappend\fR, \fBlindex\fR, \fBlinsert\fR, \fBlist\fR, \fBllength\fR, +\fBlrange\fR, \fBlreplace\fR, \fBlsearch\fR, and \fBlsort\fR allow +you to build lists, +.VE +extract elements from them, search them, and perform other list-related +functions. + +.SH "REGULAR EXPRESSIONS" +.VS +.PP +Tcl provides two commands that support string matching using +\fBegrep\fR-style regular expressions: \fBregexp\fR and \fBregsub\fR. +Regular expressions are implemented using Henry Spencer's package, +and the description of regular expressions below is copied verbatim +from his manual entry. +.PP +A regular expression is zero or more \fIbranches\fR, separated by ``|''. +It matches anything that matches one of the branches. +.PP +A branch is zero or more \fIpieces\fR, concatenated. +It matches a match for the first, followed by a match for the second, etc. +.PP +A piece is an \fIatom\fR possibly followed by ``*'', ``+'', or ``?''. +An atom followed by ``*'' matches a sequence of 0 or more matches of the atom. +An atom followed by ``+'' matches a sequence of 1 or more matches of the atom. +An atom followed by ``?'' matches a match of the atom, or the null string. +.PP +An atom is a regular expression in parentheses (matching a match for the +regular expression), a \fIrange\fR (see below), ``.'' +(matching any single character), ``^'' (matching the null string at the +beginning of the input string), ``$'' (matching the null string at the +end of the input string), a ``\e'' followed by a single character (matching +that character), or a single character with no other significance +(matching that character). +.PP +A \fIrange\fR is a sequence of characters enclosed in ``[]''. +It normally matches any single character from the sequence. +If the sequence begins with ``^'', +it matches any single character \fInot\fR from the rest of the sequence. +If two characters in the sequence are separated by ``\-'', this is shorthand +for the full list of ASCII characters between them +(e.g. ``[0-9]'' matches any decimal digit). +To include a literal ``]'' in the sequence, make it the first character +(following a possible ``^''). +To include a literal ``\-'', make it the first or last character. +.PP +If a regular expression could match two different parts of a string, +it will match the one which begins earliest. +If both begin in the same place but match different lengths, or match +the same length in different ways, life gets messier, as follows. +.PP +In general, the possibilities in a list of branches are considered in +left-to-right order, the possibilities for ``*'', ``+'', and ``?'' are +considered longest-first, nested constructs are considered from the +outermost in, and concatenated constructs are considered leftmost-first. +The match that will be chosen is the one that uses the earliest +possibility in the first choice that has to be made. +If there is more than one choice, the next will be made in the same manner +(earliest possibility) subject to the decision on the first choice. +And so forth. +.PP +For example, ``(ab|a)b*c'' could match ``abc'' in one of two ways. +The first choice is between ``ab'' and ``a''; since ``ab'' is earlier, and does +lead to a successful overall match, it is chosen. +Since the ``b'' is already spoken for, +the ``b*'' must match its last possibility\(emthe empty string\(emsince +it must respect the earlier choice. +.PP +In the particular case where no ``|''s are present and there is only one +``*'', ``+'', or ``?'', the net effect is that the longest possible +match will be chosen. +So ``ab*'', presented with ``xabbbby'', will match ``abbbb''. +Note that if ``ab*'' is tried against ``xabyabbbz'', it +will match ``ab'' just after ``x'', due to the begins-earliest rule. +(In effect, the decision on where to start the match is the first choice +to be made, hence subsequent choices must respect it even if this leads them +to less-preferred alternatives.) +.VE + +.SH "COMMAND RESULTS" +.PP +Each command produces two results: a code and a string. The +code indicates whether the command completed successfully or not, +and the string gives additional information. The valid codes are +defined in tcl.h, and are: +.RS +.TP 20 +\fBTCL_OK\fR +This is the normal return code, and indicates that the command completed +successfully. The string gives the command's return value. +.TP 20 +\fBTCL_ERROR\fR +Indicates that an error occurred; the string gives a message describing +the error. +.VS +In addition, the global variable \fBerrorInfo\fR will contain +human-readable information +describing which commands and procedures were being executed when the +error occurred, and the global variable \fBerrorCode\fR will contain +machine-readable details about the error, if they are available. +See the section BUILT-IN VARIABLES below for more information. +.VE +.VE +.TP 20 +\fBTCL_RETURN\fR +Indicates that the \fBreturn\fR command has been invoked, and that the +current procedure (or top-level command or \fBsource\fR command) +should return immediately. The +string gives the return value for the procedure or command. +.TP 20 +\fBTCL_BREAK\fR +Indicates that the \fBbreak\fR command has been invoked, so the +innermost loop should abort immediately. The string should always +be empty. +.TP 20 +\fBTCL_CONTINUE\fR +Indicates that the \fBcontinue\fR command has been invoked, so the +innermost loop should go on to the next iteration. The string +should always be empty. +.RE +Tcl programmers do not normally need to think about return codes, +since TCL_OK is almost always returned. If anything else is returned +by a command, then the Tcl interpreter immediately stops processing +commands and returns to its caller. If there are several nested +invocations of the Tcl interpreter in progress, then each nested +command will usually return the error to its caller, until eventually +the error is reported to the top-level application code. The +application will then display the error message for the user. +.PP +In a few cases, some commands will handle certain ``error'' conditions +themselves and not return them upwards. For example, the \fBfor\fR +command checks for the TCL_BREAK code; if it occurs, then \fBfor\fR +stops executing the body of the loop and returns TCL_OK to its +caller. The \fBfor\fR command also handles TCL_CONTINUE codes and the +procedure interpreter handles TCL_RETURN codes. The \fBcatch\fR +command allows Tcl programs to catch errors and handle them without +aborting command interpretation any further. + +.SH PROCEDURES +.PP +Tcl allows you to extend the command interface by defining +procedures. A Tcl procedure can be invoked just like any other Tcl +command (it has a name and it receives one or more arguments). +The only difference is that its body isn't a piece of C code linked +into the program; it is a string containing one or more other +Tcl commands. See the \fBproc\fR command for information on +how to define procedures and what happens when they are invoked. + +.SH VARIABLES \- SCALARS AND ARRAYS +.VS +.PP +Tcl allows the definition of variables and the use of their values +either through \fB$\fR-style variable substitution, the \fBset\fR +command, or a few other mechanisms. +Variables need not be declared: a new variable will automatically +be created each time a new variable name is used. +.PP +Tcl supports two types of variables: scalars and arrays. +A scalar variable has a single value, whereas an array variable +can have any number of elements, each with a name (called +its ``index'') and a value. +Array indexes may be arbitrary strings; they need not be numeric. +Parentheses are used refer to array elements in Tcl commands. +For example, the command +.DS C +\fBset x(first) 44\fR +.DE +will modify the element of \fBx\fR whose index is \fBfirst\fR +so that its new value is \fB44\fR. +Two-dimensional arrays can be simulated in Tcl by using indexes +that contain multiple concatenated values. +For example, the commands +.DS C +\fBset a(2,3) 1\fR +\fBset a(3,6) 2\fR +.DE +set the elements of \fBa\fR whose indexes are \fB2,3\fR and \fB3,6\fR. +.PP +In general, array elements may be used anywhere in Tcl that scalar +variables may be used. +If an array is defined with a particular name, then there may +not be a scalar variable with the same name. +Similarly, if there is a scalar variable with a particular +name then it is not possible to make array references to the +variable. +To convert a scalar variable to an array or vice versa, remove +the existing variable with the \fBunset\fR command. +.PP +The \fBarray\fR command provides several features for dealing +with arrays, such as querying the names of all the elements of +the array and searching through the array one element at a time. +.VE +.PP +Variables may be either global or local. If a variable +name is used when a procedure isn't being executed, then it +automatically refers to a global variable. Variable names used +within a procedure normally refer to local variables associated with that +invocation of the procedure. Local variables are deleted whenever +a procedure exits. The \fBglobal\fR command may be used to request +that a name refer to a global variable for the duration of the current +procedure (this is somewhat analogous to \fBextern\fR in C). + +.SH "BUILT-IN COMMANDS" +.PP +The Tcl library provides the following built-in commands, which will +be available in any application using Tcl. In addition to these +built-in commands, there may be additional commands defined by each +application, plus commands defined as Tcl procedures. +In the command syntax descriptions below, words in boldface are +literals that you type verbatim to Tcl. +Words in italics are meta-symbols; they serve as names for any of +a range of values that you can type. +Optional arguments or groups of arguments are indicated by enclosing them +in question-marks. +Ellipses (``...'') indicate that any number of additional +arguments or groups of arguments may appear, in the same format +as the preceding argument(s). +.TP +\fBappend \fIvarName value \fR?\fIvalue value ...\fR? +.VS +Append all of the \fIvalue\fR arguments to the current value +of variable \fIvarName\fR. If \fIvarName\fR doesn't exist, +it is given a value equal to the concatenation of all the +\fIvalue\fR arguments. +This command provides an efficient way to build up long +variables incrementally. +For example, ``\fBappend a $b\fR'' is much more efficient than +``\fBset a $a$b\fR'' if \fB$a\fR is long. +.VE +.TP +\fBarray \fIoption arrayName\fR ?\fIarg arg ...\fR? +.VS +This command performs one of several operations on the +variable given by \fIarrayName\fR. +\fIArrayName\fR must be the name of an existing array variable. +The \fIoption\fR argument determines what action is carried +out by the command. +The legal \fIoptions\fR (which may be abbreviated) are: +.RS +.TP +\fBarray anymore \fIarrayName searchId\fR +Returns 1 if there are any more elements left to be processed +in an array search, 0 if all elements have already been +returned. +\fISearchId\fR indicates which search on \fIarrayName\fR to +check, and must have been the return value from a previous +invocation of \fBarray startsearch\fR. +This option is particularly useful if an array has an element +with an empty name, since the return value from +\fBarray nextelement\fR won't indicate whether the search +has been completed. +.TP +\fBarray donesearch \fIarrayName searchId\fR +This command terminates an array search and destroys all the +state associated with that search. \fISearchId\fR indicates +which search on \fIarrayName\fR to destroy, and must have +been the return value from a previous invocation of +\fBarray startsearch\fR. Returns an empty string. +.TP +\fBarray names \fIarrayName\fR +Returns a list containing the names of all of the elements in +the array. +If there are no elements in the array then an empty string is +returned. +.TP +\fBarray nextelement \fIarrayName searchId\fR +Returns the name of the next element in \fIarrayName\fR, or +an empty string if all elements of \fIarrayName\fR have +already been returned in this search. The \fIsearchId\fR +argument identifies the search, and must have +been the return value of an \fBarray startsearch\fR command. +Warning: if elements are added to or deleted from the array, +then all searches are automatically terminated just as if +\fBarray donesearch\fR had been invoked; this will cause +\fBarray nextelement\fR operations to fail for those searches. +.TP +\fBarray size \fIarrayName\fR +Returns a decimal string giving the number of elements in the +array. +.TP +\fBarray startsearch \fIarrayName\fR +This command initializes an element-by-element search through the +array given by \fIarrayName\fR, such that invocations of the +\fBarray nextelement\fR command will return the names of the +individual elements in the array. +When the search has been completed, the \fBarray donesearch\fR +command should be invoked. +The return value is a +search identifier that must be used in \fBarray nextelement\fR +and \fBarray donesearch\fR commands; it allows multiple +searches to be underway simultaneously for the same array. +.VE +.RE +.TP +\fBbreak\fR +This command may be invoked only inside the body of a loop command +such as \fBfor\fR or \fBforeach\fR or \fBwhile\fR. It returns a TCL_BREAK code +to signal the innermost containing loop command to return immediately. +.TP +\fBcase\fI string \fR?\fBin\fR? \fIpatList body \fR?\fIpatList body \fR...? +.TP +\fBcase\fI string \fR?\fBin\fR? {\fIpatList body \fR?\fIpatList body \fR...?} +Match \fIstring\fR against each of the \fIpatList\fR arguments +in order. If one matches, then evaluate the following \fIbody\fR argument +by passing it recursively to the Tcl interpreter, and return the result +of that evaluation. Each \fIpatList\fR argument consists of a single +pattern or list of patterns. Each pattern may contain any of the wild-cards +described under \fBstring match\fR. If a \fIpatList\fR +argument is \fBdefault\fR, the corresponding body will be evaluated +if no \fIpatList\fR matches \fIstring\fR. If no \fIpatList\fR argument +matches \fIstring\fR and no default is given, then the \fBcase\fR +command returns an empty string. +.RS +.PP +Two syntaxes are provided. +The first uses a separate argument for each of the patterns and commands; +this form is convenient if substitutions are desired on some of the +patterns or commands. +.VS +The second form places all of the patterns and commands together into +a single argument; the argument must have proper list structure, with +the elements of the list being the patterns and commands. +The second form makes it easy to construct multi-line case commands, +since the braces around the whole list make it unnecessary to include a +backslash at the end of each line. +Since the \fIpatList\fR arguments are in braces in the second form, +no command or variable substitutions are performed on them; this makes +the behavior of the second form different than the first form in some +cases. +.PP +Below are some examples of \fBcase\fR commands: +.DS +\fBcase abc in {a b} {format 1} default {format 2} a* {format 3} +.DE +will return \fB3\fR, +.DS +.ta .5c 1c +\fBcase a in { + {a b} {format 1} + default {format 2} + a* {format 3} +} +.DE +will return \fB1\fR, and +.DS +.ta .5c 1c +\fBcase xyz { + {a b} + {format 1} + default + {format 2} + a* + {format 3} +} +.DE +will return \fB2\fR. +.VE +.RE +.TP +\fBcatch\fI command \fR?\fIvarName\fR? +The \fBcatch\fR command may be used to prevent errors from aborting +command interpretation. \fBCatch\fR calls the Tcl interpreter recursively +to execute \fIcommand\fR, and always returns a TCL_OK code, regardless of +any errors that might occur while executing \fIcommand\fR. The return +value from \fBcatch\fR is a decimal string giving the +code returned by the Tcl interpreter after executing \fIcommand\fR. +This will be \fB0\fR (TCL_OK) if there were no errors in \fIcommand\fR; otherwise +it will have a non-zero value corresponding to one of the exceptional +return codes (see tcl.h for the definitions of code values). If the +\fIvarName\fR argument is given, then it gives the name of a variable; +\fBcatch\fR will set the value of the variable to the string returned +from \fIcommand\fR (either a result or an error message). +.TP +\fBcd \fR?\fIdirName\fR? +.VS +Change the current working directory to \fIdirName\fR, or to the +home directory (as specified in the HOME environment variable) if +\fIdirName\fR is not given. +If \fIdirName\fR starts with a tilde, then tilde-expansion is +done as described for \fBTcl_TildeSubst\fR. +Returns an empty string. +This command can potentially be disruptive to an application, +so it may be removed in some applications. +.TP +\fBclose \fIfileId\fR +Closes the file given by \fIfileId\fR. +\fIFileId\fR must be the return value from a previous invocation +of the \fBopen\fR command; after this command, it should not be +used anymore. +If \fIfileId\fR refers to a command pipeline instead of a file, +then \fBclose\fR waits for the children to complete. +The normal result of this command is an empty string, but errors +are returned if there are problems in closing the file or waiting +for children to complete. +.VE +.TP +\fBconcat\fI arg \fR?\fIarg ...\fR? +This command treats each argument as a list and concatenates them +into a single list. It permits any number of arguments. For example, +the command +.RS +.DS +\fBconcat a b {c d e} {f {g h}}\fR +.DE +will return +.DS +\fBa b c d e f {g h}\fR +.DE +as its result. +.RE +.TP +\fBcontinue\fR +This command may be invoked only inside the body of a loop command +such as \fBfor\fR or \fBforeach\fR or \fBwhile\fR. It +returns a TCL_CONTINUE code +to signal the innermost containing loop command to skip the +remainder of the loop's body +but continue with the next iteration of the loop. +.TP +\fBeof \fIfileId\fR +.VS +Returns 1 if an end-of-file condition has occurred on \fIfileId\fR, +0 otherwise. +\fIFileId\fR must have been the return +value from a previous call to \fBopen\fR, or it may be \fBstdin\fR, +\fBstdout\fR, or \fBstderr\fR to refer to one of the standard I/O +channels. +.VE +.TP +\fBerror \fImessage\fR ?\fIinfo\fR? ?\fIcode\fR? +Returns a TCL_ERROR code, which causes command interpretation to be +unwound. \fIMessage\fR is a string that is returned to the application +to indicate what went wrong. +.RS +.PP +If the \fIinfo\fR argument is provided and is non-empty, +it is used to initialize the global variable \fBerrorInfo\fR. +\fBerrorInfo\fR is used to accumulate a stack trace of what +was in progress when an error occurred; as nested commands unwind, +the Tcl interpreter adds information to \fBerrorInfo\fR. If the +\fIinfo\fR argument is present, it is used to initialize +\fBerrorInfo\fR and the first increment of unwind information +will not be added by the Tcl interpreter. In other +words, the command containing the \fBerror\fR command will not appear +in \fBerrorInfo\fR; in its place will be \fIinfo\fR. +This feature is most useful in conjunction with the \fBcatch\fR command: +if a caught error cannot be handled successfully, \fIinfo\fR can be used +to return a stack trace reflecting the original point of occurrence +of the error: +.DS +\fBcatch {...} errMsg +set savedInfo $errorInfo +\&... +error $errMsg $savedInfo\fR +.DE +.PP +.VS +If the \fIcode\fR argument is present, then its value is stored +in the \fBerrorCode\fR global variable. This variable is intended +to hold a machine-readable description of the error in cases where +such information is available; see the section BUILT-IN VARIABLES +below for information on the proper format for the variable. +If the \fIcode\fR argument is not +present, then \fBerrorCode\fR is automatically reset to +``NONE'' by the Tcl interpreter as part of processing the +error generated by the command. +.VE +.RE +.TP +\fBeval \fIarg \fR?\fIarg ...\fR? +\fBEval\fR takes one or more arguments, which together comprise a Tcl +command (or collection of Tcl commands separated by newlines in the +usual way). \fBEval\fR concatenates all its arguments in the same +fashion as the \fBconcat\fR command, passes the concatenated string to the +Tcl interpreter recursively, and returns the result of that +evaluation (or any error generated by it). +.TP +\fBexec \fIarg \fR?\fIarg ...\fR? +.VS +This command treats its arguments as the specification +of one or more UNIX commands to execute as subprocesses. +The commands take the form of a standard shell pipeline; +``|'' arguments separate commands in the +pipeline and cause standard output of the preceding command +to be piped into standard input of the next command. +.RS +.PP +Under normal conditions the result of the \fBexec\fR command +consists of the standard output produced by the last command +in the pipeline. +If any of the commands in the pipeline exit abnormally or +are killed or suspended, then \fBexec\fR will return an error +and the error message will include the pipeline's output followed by +error messages describing the abnormal terminations; the +\fBerrorCode\fR variable will contain additional information +about the last abnormal termination encountered. +If any of the commands writes to its standard error file, +then \fBexec\fR will return an error, and the error message +will include the pipeline's output, followed by messages +about abnormal terminations (if any), followed by the standard error +output. +.PP +If the last character of the result or error message +is a newline then that character is deleted from the result +or error message for consistency with normal +Tcl return values. +.PP +If an \fIarg\fR has the value ``>'' then the +following argument is taken as the name of a file and +the standard output of the last command in the pipeline +is redirected to the file. In this situation \fBexec\fR +will normally return an empty string. +.PP +If an \fIarg\fR has the value ``<'' then the following +argument is taken as the name of a file to use +for standard input to the first command in the +pipeline. +If an argument has the value ``<<'' then the following +argument is taken as an immediate value to be passed to +the first command as standard input. +If there is no ``<'' or ``<<'' argument then the standard +input for the first command in the pipeline is taken from +the application's current standard input. +.PP +If the last \fIarg\fR is ``&'' then the command will be +executed in background. +In this case the standard output from the last command +in the pipeline will +go to the application's standard output unless +redirected in the command, and error output from all +the commands in the pipeline will go to the application's +standard error file. +.PP +Each \fIarg\fR becomes one word for a command, except for +``|'', ``<'', ``<<'', ``>'', and ``&'' arguments, and the +arguments that follow ``<'', ``<<'', and ``>''. +The first word in each command is taken as the command name; +tilde-substitution is performed on it, and the directories +in the PATH environment variable are searched for +an executable by the given name. +No ``glob'' expansion or other shell-like substitutions +are performed on the arguments to commands. +.RE +.TP +\fBexit \fR?returnCode\fR? +Terminate the process, returning \fIreturnCode\fR to the +parent as the exit status. +If \fIreturnCode\fR isn't specified then it defaults +to 0. +.VE +.TP +\fBexpr \fIarg\fR +Calls the expression processor to evaluate \fIarg\fR, and returns +the result as a string. See the section EXPRESSIONS above. +.TP +\fBfile \fIoption\fR \fIname\fR ?\fIarg arg ...\fR? +.VS +Operate on a file or a file name. \fIName\fR is the name of a file; +if it starts with a tilde, then tilde substitution is done before +executing the command (see the manual entry for \fBTcl_TildeSubst\fR +for details). +\fIOption\fR indicates what to do with the file name. Any unique +abbreviation for \fIoption\fR is acceptable. The valid options are: +.RS +.TP +\fBfile \fBatime \fIname\fR +Return a decimal string giving the time at which file \fIname\fR +was last accessed. The time is measured in the standard UNIX +fashion as seconds from a fixed starting time (often January 1, 1970). +If the file doesn't exist or its access time cannot be queried then an +error is generated. +.TP +\fBfile \fBdirname \fIname\fR +Return all of the characters in \fIname\fR up to but not including +the last slash character. If there are no slashes in \fIname\fR +then return ``.''. If the last slash in \fIname\fR is its first +character, then return ``/''. +.TP +\fBfile \fBexecutable \fIname\fR +Return \fB1\fR if file \fIname\fR is executable by +the current user, \fB0\fR otherwise. +.TP +\fBfile \fBexists \fIname\fR +Return \fB1\fR if file \fIname\fR exists and the current user has +search privileges for the directories leading to it, \fB0\fR otherwise. +.TP +\fBfile \fBextension \fIname\fR +Return all of the characters in \fIname\fR after and including the +last dot in \fIname\fR. If there is no dot in \fIname\fR then return +the empty string. +.TP +\fBfile \fBisdirectory \fIname\fR +Return \fB1\fR if file \fIname\fR is a directory, +\fB0\fR otherwise. +.TP +\fBfile \fBisfile \fIname\fR +Return \fB1\fR if file \fIname\fR is a regular file, +\fB0\fR otherwise. +.TP +\fBfile lstat \fIname varName\fR +Same as \fBstat\fR option (see below) except uses the \fIlstat\fR +kernel call instead of \fIstat\fR. This means that if \fIname\fR +refers to a symbolic link the information returned in \fIvarName\fR +is for the link rather than the file it refers to. On systems that +don't support symbolic links this option behaves exactly the same +as the \fBstat\fR option. +.TP +\fBfile \fBmtime \fIname\fR +Return a decimal string giving the time at which file \fIname\fR +was last modified. The time is measured in the standard UNIX +fashion as seconds from a fixed starting time (often January 1, 1970). +If the file doesn't exist or its modified time cannot be queried then an +error is generated. +.TP +\fBfile \fBowned \fIname\fR +Return \fB1\fR if file \fIname\fR is owned by the current user, +\fB0\fR otherwise. +.TP +\fBfile \fBreadable \fIname\fR +Return \fB1\fR if file \fIname\fR is readable by +the current user, \fB0\fR otherwise. +.TP +\fBfile readlink \fIname\fR +Returns the value of the symbolic link given by \fIname\fR (i.e. the +name of the file it points to). If +\fIname\fR isn't a symbolic link or its value cannot be read, then +an error is returned. On systems that don't support symbolic links +this option is undefined. +.TP +\fBfile \fBrootname \fIname\fR +Return all of the characters in \fIname\fR up to but not including +the last ``.'' character in the name. If \fIname\fR doesn't contain +a dot, then return \fIname\fR. +.TP +\fBfile \fBsize \fIname\fR +Return a decimal string giving the size of file \fIname\fR in bytes. +If the file doesn't exist or its size cannot be queried then an +error is generated. +.TP +\fBfile \fBstat \fIname varName\fR +Invoke the \fBstat\fR kernel call on \fIname\fR, and use the +variable given by \fIvarName\fR to hold information returned from +the kernel call. +\fIVarName\fR is treated as an array variable, +and the following elements of that variable are set: \fBatime\fR, +\fBctime\fR, \fBdev\fR, \fBgid\fR, \fBino\fR, \fBmode\fR, \fBmtime\fR, +\fBnlink\fR, \fBsize\fR, \fBtype\fR, \fBuid\fR. +Each element except \fBtype\fR is a decimal string with the value of +the corresponding field from the \fBstat\fR return structure; see the +manual entry for \fBstat\fR for details on the meanings of the values. +The \fBtype\fR element gives the type of the file in the same form +returned by the command \fBfile type\fR. +This command returns an empty string. +.TP +\fBfile \fBtail \fIname\fR +Return all of the characters in \fIname\fR after the last slash. +If \fIname\fR contains no slashes then return \fIname\fR. +.TP +\fBfile \fBtype \fIname\fR +Returns a string giving the type of file \fIname\fR, which will be +one of \fBfile\fR, \fBdirectory\fR, \fBcharacterSpecial\fR, +\fBblockSpecial\fR, \fBfifo\fR, \fBlink\fR, or \fBsocket\fR. +.TP +\fBfile \fBwritable \fIname\fR +Return \fB1\fR if file \fIname\fR is writable by +the current user, \fB0\fR otherwise. +.RE +.IP +The \fBfile\fR commands that return 0/1 results are often used in +conditional or looping commands, for example: +.RS +.DS +\fBif {![file exists foo]} then {error {bad file name}} else {...}\fR +.DE +.VE +.RE +.TP +\fBflush \fIfileId\fR +.VS +Flushes any output that has been buffered for \fIfileId\fR. +\fIFileId\fR must have been the return +value from a previous call to \fBopen\fR, or it may be +\fBstdout\fR or \fBstderr\fR to access one of the standard I/O streams; +it must refer to a file that was opened for writing. +This command returns an empty string. +.VE +.TP +\fBfor \fIstart test next body\fR +\fBFor\fR is a looping command, similar in structure to the C +\fBfor\fR statement. The \fIstart\fR, \fInext\fR, and +\fIbody\fR arguments must be Tcl command strings, and \fItest\fR +is an expression string. +The \fBfor\fR command first invokes the Tcl interpreter to +execute \fIstart\fR. Then it repeatedly evaluates \fItest\fR as +an expression; if the result is non-zero it invokes the Tcl +interpreter on \fIbody\fR, then invokes the Tcl interpreter on \fInext\fR, +then repeats the loop. The command terminates when \fItest\fR evaluates +to 0. If a \fBcontinue\fR command is invoked within \fIbody\fR then +any remaining commands in the current execution of \fIbody\fR are skipped; +processing continues by invoking the Tcl interpreter on \fInext\fR, then +evaluating \fItest\fR, and so on. If a \fBbreak\fR command is invoked +within \fIbody\fR +or \fInext\fR, +then the \fBfor\fR command will +return immediately. +The operation of \fBbreak\fR and \fBcontinue\fR are similar to the +corresponding statements in C. +\fBFor\fR returns an empty string. +.TP +\fBforeach \fIvarname list body\fR +In this command, \fIvarname\fR is the name of a variable, \fIlist\fR +is a list of values to assign to \fIvarname\fR, and \fIbody\fR is a +collection of Tcl commands. For each field in \fIlist\fR (in order +from left to right), \fBforeach\fR assigns the contents of the +field to \fIvarname\fR (as if the \fBlindex\fR command had been used +to extract the field), then calls the Tcl interpreter to execute +\fIbody\fR. The \fBbreak\fR and \fBcontinue\fR statements may be +invoked inside \fIbody\fR, with the same effect as in the \fBfor\fR +command. \fBForeach\fR returns an empty string. +.TP +\fBformat \fIformatString \fR?\fIarg arg ...\fR? +This command generates a formatted string in the same way as the +C \fBsprintf\fR procedure (it uses \fBsprintf\fR in its +implementation). \fIFormatString\fR indicates how to format +the result, using \fB%\fR fields as in \fBsprintf\fR, and the additional +arguments, if any, provide values to be substituted into the result. +All of the \fBsprintf\fR options are valid; see the \fBsprintf\fR +man page for details. Each \fIarg\fR must match the expected type +from the \fB%\fR field in \fIformatString\fR; the \fBformat\fR command +converts each argument to the correct type (floating, integer, etc.) +before passing it to \fBsprintf\fR for formatting. +The only unusual conversion is for \fB%c\fR; in this case the argument +must be a decimal string, which will then be converted to the corresponding +ASCII character value. +\fBFormat\fR does backslash substitution on its \fIformatString\fR +argument, so backslash sequences in \fIformatString\fR will be handled +correctly even if the argument is in braces. +The return value from \fBformat\fR +is the formatted string. +.TP +\fBgets \fIfileId\fR ?\fIvarName\fR? +.VS +Reads the next line from the file given by \fIfileId\fR and discards +the terminating newline character. +If \fIvarName\fR is specified, then the line is placed in the variable +by that name and the return value is a count of the number of characters +read (not including the newline). +If the end of the file is reached before reading +any characters then \-1 is returned and \fIvarName\fR is set to an +empty string. +If \fIvarName\fR is not specified then the return value will be +the line (minus the newline character) or an empty string if +the end of the file is reached before reading any characters. +An empty string will also be returned if a line contains no characters +except the newline, so \fBeof\fR may have to be used to determine +what really happened. +If the last character in the file is not a newline character, then +\fBgets\fR behaves as if there were an additional newline character +at the end of the file. +\fIFileId\fR must be \fBstdin\fR or the return value from a previous +call to \fBopen\fR; it must refer to a file that was opened +for reading. +.VE +.TP +\fBglob \fR?\fB\-nocomplain\fR? \fIfilename\fR ?\fIfilename ...\fR? +This command performs filename globbing, using csh rules. The returned +value from \fBglob\fR is the list of expanded filenames. +.VS +If \fB\-nocomplain\fR is specified as the first argument then an empty +list may be returned; otherwise an error is returned if the expanded +list is empty. The \fB\-nocomplain\fR argument must be provided +exactly: an abbreviation will not be accepted. +.VE +.TP +\fBglobal \fIvarname \fR?\fIvarname ...\fR? +This command is ignored unless a Tcl procedure is being interpreted. +If so, then it declares the given \fIvarname\fR's to be global variables +rather than local ones. For the duration of the current procedure +(and only while executing in the current procedure), any reference to +any of the \fIvarname\fRs will be bound to a global variable instead +of a local one. +.TP +\fBhistory \fR?\fIoption\fR? ?\fIarg arg ...\fR? +Note: this command may not be available in all Tcl-based applications. +Typically, only those that receive command input in a typescript +form will support history. +The \fBhistory\fR command performs one of several operations related to +recently-executed commands recorded in a history list. Each of +these recorded commands is referred to as an ``event''. When +specifying an event to the \fBhistory\fR command, the following +forms may be used: +.RS +.IP [1] +A number: if positive, it refers to the event with +that number (all events are numbered starting at 1). If the number +is negative, it selects an event relative to the current event +(\fB\-1\fR refers to the previous event, \fB\-2\fR to the one before that, and +so on). +.IP [2] +A string: selects the most recent event that matches the string. +An event is considered to match the string either if the string is +the same as the first characters of the event, or if the string +matches the event in the sense of the \fBstring match\fR command. +.LP +The \fBhistory\fR command can take any of the following forms: +.TP +\fBhistory\fR +Same +.VS +as \fBhistory info\fR, described below. +.VE +.TP +\fBhistory add\fI command \fR?\fBexec\fR? +Add the \fIcommand\fR argument to the history list as a new event. If +\fBexec\fR is specified (or abbreviated) then the command is also +executed and its result is returned. If \fBexec\fR isn't specified +then an empty string is returned as result. +.TP +\fBhistory change\fI newValue\fR ?\fIevent\fR? +Replace the value recorded for an event with \fInewValue\fR. \fIEvent\fR +specifies the event to replace, and +defaults to the \fIcurrent\fR event (not event \fB\-1\fR). This command +is intended for use in commands that implement new forms of history +substitution and wish to replace the current event (which invokes the +substitution) with the command created through substitution. The return +value is an empty string. +.TP +\fBhistory event\fR ?\fIevent\fR? +Returns the value of the event given by \fIevent\fR. \fIEvent\fR +defaults to \fB\-1\fR. This command causes history revision to occur: +see below for details. +.TP +\fBhistory info \fR?\fIcount\fR? +Returns a formatted string (intended for humans to read) giving +the event number and contents for each of the events in the history +list except the current event. If \fIcount\fR is specified +then only the most recent \fIcount\fR events are returned. +.TP +\fBhistory keep \fIcount\fR +This command may be used to change the size of the history list to +\fIcount\fR events. Initially, 20 events are retained in the history +list. This command returns an empty string. +.TP +\fBhistory nextid\fR +Returns the number of the next event to be recorded +in the history list. It is useful for things like printing the +event number in command-line prompts. +.TP +\fBhistory redo \fR?\fIevent\fR? +Re-execute the command indicated by \fIevent\fR and return its result. +\fIEvent\fR defaults to \fB\-1\fR. This command results in history +revision: see below for details. +.TP +\fBhistory substitute \fIold new \fR?\fIevent\fR? +Retrieve the command given by \fIevent\fR +(\fB\-1\fR by default), replace any occurrences of \fIold\fR by +\fInew\fR in the command (only simple character equality is supported; +no wild cards), execute the resulting command, and return the result +of that execution. This command results in history +revision: see below for details. +.TP +\fBhistory words \fIselector\fR ?\fIevent\fR? +Retrieve from the command given by \fIevent\fR (\fB\-1\fR by default) +the words given by \fIselector\fR, and return those words in a string +separated by spaces. The \fBselector\fR argument has three forms. +If it is a single number then it selects the word given by that +number (\fB0\fR for the command name, \fB1\fR for its first argument, +and so on). If it consists of two numbers separated by a dash, +then it selects all the arguments between those two. Otherwise +\fBselector\fR is treated as a pattern; all words matching that +pattern (in the sense of \fBstring match\fR) are returned. In +the numeric forms \fB$\fR may be used +to select the last word of a command. +For example, suppose the most recent command in the history list is +.RS +.DS +\fBformat {%s is %d years old} Alice [expr $ageInMonths/12]\fR +.DE +Below are some history commands and the results they would produce: +.DS +.ta 4c +.fi +.UL Command " " +.UL Result +.nf + +\fBhistory words $ [expr $ageInMonths/12]\fR +\fBhistory words 1-2 {%s is %d years old} Alice\fR +\fBhistory words *a*o* {%s is %d years old} [expr $ageInMonths/12]\fR +.DE +\fBHistory words\fR results in history revision: see below for details. +.RE +The history options \fBevent\fR, \fBredo\fR, \fBsubstitute\fR, +and \fBwords\fR result in ``history revision''. +When one of these options is invoked then the current event +is modified to eliminate the history command and replace it with +the result of the history command. +For example, suppose that the most recent command in the history +list is +.DS +\fBset a [expr $b+2]\fR +.DE +and suppose that the next command invoked is one of the ones on +the left side of the table below. The command actually recorded in +the history event will be the corresponding one on the right side +of the table. +.ne 1.5c +.DS +.ta 4c +.fi +.UL "Command Typed" " " +.UL "Command Recorded" +.nf + +\fBhistory redo set a [expr $b+2]\fR +\fBhistory s a b set b [expr $b+2]\fR +\fBset c [history w 2] set c [expr $b+2]\fR +.DE +.VS +History revision is needed because event specifiers like \fB\-1\fR +are only valid at a particular time: once more events have been +added to the history list a different event specifier would be +needed. +History revision occurs even when \fBhistory\fR is invoked +indirectly from the current event (e.g. a user types a command +that invokes a Tcl procedure that invokes \fBhistory\fR): the +top-level command whose execution eventually resulted in a +\fBhistory\fR command is replaced. +If you wish to invoke commands like \fBhistory words\fR without +history revision, you can use \fBhistory event\fR to save the +current history event and then use \fBhistory change\fR to +restore it later. +.VE +.RE +.TP +\fBif \fIexpr1 \fR?\fBthen\fR? \fIbody1 \fBelseif \fIexpr2 \fR?\fBthen\fR? \fIbody2\fR \fBelseif\fR ... \fR?\fBelse\fR? ?\fIbodyN\fR? +.VS +The \fIif\fR command evaluates \fIexpr1\fR as an expression (in the +same way that \fBexpr\fR evaluates its argument). The value of the +expression must be numeric; if it +is non-zero then \fIbody1\fR is executed by passing it to the +Tcl interpreter. +Otherwise \fIexpr2\fR is evaluated as an expression and if it is non-zero +then \fBbody2\fR is executed, and so on. +If none of the expressions evaluates to non-zero then \fIbodyN\fR is +executed. +The \fBthen\fR and \fBelse\fR arguments are optional +``noise words'' to make the command easier to read. +There may be any number of \fBelseif\fR clauses, including zero. +\fIBodyN\fR may also be omitted as long as \fBelse\fR is omitted too. +The return value from the command is the result of the body script +that was executed, or an empty string +if none of the expressions was non-zero and there was no \fIbodyN\fR. +.VE +.TP +\fBincr \fIvarName \fR?\fIincrement\fR? +.VS +Increment the value stored in the variable whose name is \fIvarName\fR. +The value of the variable must be integral. +If \fIincrement\fR is supplied then its value (which must be an +integer) is added to the value of variable \fIvarName\fR; otherwise +1 is added to \fIvarName\fR. +The new value is stored as a decimal string in variable \fIvarName\fR +and also returned as result. +.VE +.TP +\fBinfo \fIoption \fR?\fIarg arg ...\fR? +Provide information about various internals to the Tcl interpreter. +The legal \fIoption\fR's (which may be abbreviated) are: +.RS +.TP +\fBinfo args \fIprocname\fR +Returns a list containing the names of the arguments to procedure +\fIprocname\fR, in order. \fIProcname\fR must be the name of a +Tcl command procedure. +.TP +\fBinfo body \fIprocname\fR +Returns the body of procedure \fIprocname\fR. \fIProcname\fR must be +the name of a Tcl command procedure. +.TP +\fBinfo cmdcount\fR +Returns a count of the total number of commands that have been invoked +in this interpreter. +.TP +\fBinfo commands \fR?\fIpattern\fR? +If \fIpattern\fR isn't specified, returns a list of names of all the +Tcl commands, including both the built-in commands written in C and +the command procedures defined using the \fBproc\fR command. +If \fIpattern\fR is specified, only those names matching \fIpattern\fR +are returned. Matching is determined using the same rules as for +\fBstring match\fR. +.TP +\fBinfo complete \fIcommand\fR +.VS +Returns 1 if \fIcommand\fR is a complete Tcl command in the sense of +having no unclosed quotes, braces, brackets or array element names, +If the command doesn't appear to be complete then 0 is returned. +This command is typically used in line-oriented input environments +to allow users to type in commands that span multiple lines; if the +command isn't complete, the script can delay evaluating it until additional +lines have been typed to complete the command. +.VE +.TP +\fBinfo default \fIprocname arg varname\fR +\fIProcname\fR must be the name of a Tcl command procedure and \fIarg\fR +must be the name of an argument to that procedure. If \fIarg\fR +doesn't have a default value then the command returns \fB0\fR. +Otherwise it returns \fB1\fR and places the default value of \fIarg\fR +into variable \fIvarname\fR. +.TP +\fBinfo exists \fIvarName\fR +Returns \fB1\fR if the variable named \fIvarName\fR exists in the +current context (either as a global or local variable), returns \fB0\fR +otherwise. +.TP +\fBinfo globals \fR?\fIpattern\fR? +If \fIpattern\fR isn't specified, returns a list of all the names +of currently-defined global variables. +If \fIpattern\fR is specified, only those names matching \fIpattern\fR +are returned. Matching is determined using the same rules as for +\fBstring match\fR. +.TP +\fBinfo level\fR ?\fInumber\fR? +If \fInumber\fR is not specified, this command returns a number +giving the stack level of the invoking procedure, or 0 if the +command is invoked at top-level. If \fInumber\fR is specified, +then the result is a list consisting of the name and arguments for the +procedure call at level \fInumber\fR on the stack. If \fInumber\fR +is positive then it selects a particular stack level (1 refers +to the top-most active procedure, 2 to the procedure it called, and +so on); otherwise it gives a level relative to the current level +(0 refers to the current procedure, -1 to its caller, and so on). +See the \fBuplevel\fR command for more information on what stack +levels mean. +.TP +\fBinfo library\fR +.VS +Returns the name of the library directory in which standard Tcl +scripts are stored. +The default value for the library is compiled into Tcl, but it +.VS +may be overridden by setting the TCL_LIBRARY environment variable. +If there is no TCL_LIBRARY variable and no compiled-in value then +and error is generated. +.VE +See the \fBlibrary\fR manual entry for details of the facilities +provided by the Tcl script library. +Normally each application will have its own application-specific +script library in addition to the Tcl script library; I suggest that +each application set a global variable with a name like +.VS +\fB$\fIapp\fB_library\fR (where \fIapp\fR is the application's name) +.VE +to hold the location of that application's library directory. +.VE +.TP +\fBinfo locals \fR?\fIpattern\fR? +If \fIpattern\fR isn't specified, returns a list of all the names +of currently-defined local variables, including arguments to the +current procedure, if any. +.VS +Variables defined with the \fBglobal\fR and \fBupvar\fR commands +will not be returned. +.VE +If \fIpattern\fR is specified, only those names matching \fIpattern\fR +are returned. Matching is determined using the same rules as for +\fBstring match\fR. +.TP +\fBinfo procs \fR?\fIpattern\fR? +If \fIpattern\fR isn't specified, returns a list of all the +names of Tcl command procedures. +If \fIpattern\fR is specified, only those names matching \fIpattern\fR +are returned. Matching is determined using the same rules as for +\fBstring match\fR. +.TP +\fBinfo script\fR +.VS +If a Tcl script file is currently being evaluated (i.e. there is a +call to \fBTcl_EvalFile\fR active or there is an active invocation +of the \fBsource\fR command), then this command returns the name +of the innermost file being processed. Otherwise the command returns an +empty string. +.VE +.TP +\fBinfo tclversion\fR +Returns the version number for this version of Tcl in the form \fIx.y\fR, +where changes to \fIx\fR represent major changes with probable +incompatibilities and changes to \fIy\fR represent small enhancements and +bug fixes that retain backward compatibility. +.TP +\fBinfo vars\fR ?\fIpattern\fR? +If \fIpattern\fR isn't specified, +returns a list of all the names of currently-visible variables, including +both locals and currently-visible globals. +If \fIpattern\fR is specified, only those names matching \fIpattern\fR +are returned. Matching is determined using the same rules as for +\fBstring match\fR. +.RE +.TP +\fBjoin \fIlist \fR?\fIjoinString\fR? +.VS +The \fIlist\fR argument must be a valid Tcl list. +This command returns the string +formed by joining all of the elements of \fIlist\fR together with +\fIjoinString\fR separating each adjacent pair of elements. +The \fIjoinString\fR argument defaults to a space character. +.VE +.TP +\fBlappend \fIvarName value \fR?\fIvalue value ...\fR? +.VS +Treat the variable given by \fIvarName\fR as a list and append +each of the \fIvalue\fR arguments to that list as a separate +element, with spaces between elements. +If \fIvarName\fR doesn't exist, it is created as a list with elements +given by the \fIvalue\fR arguments. +\fBLappend\fR is similar to \fBappend\fR except that the \fIvalue\fRs +are appended as list elements rather than raw text. +This command provides a relatively efficient way to build up +large lists. For example, ``\fBlappend a $b\fR'' is much +more efficient than ``\fBset a [concat $a [list $b]]\fR'' when +\fB$a\fR is long. +.TP +\fBlindex \fIlist index\fR +Treats \fIlist\fR as a Tcl list and returns the \fIindex\fR'th element +from it (0 refers to the first element of the list). +In extracting the element, \fIlindex\fR observes the same rules +concerning braces and quotes and backslashes as the Tcl command +interpreter; however, variable +substitution and command substitution do not occur. +If \fIindex\fR is negative or greater than or equal to the number +of elements in \fIvalue\fR, then an empty +string is returned. +.TP +\fBlinsert \fIlist index element \fR?\fIelement element ...\fR? +This command produces a new list from \fIlist\fR by inserting all +of the \fIelement\fR arguments just before the \fIindex\fRth +element of \fIlist\fR. Each \fIelement\fR argument will become +a separate element of the new list. If \fIindex\fR is less than +or equal to zero, then the new elements are inserted at the +beginning of the list. If \fIindex\fR is greater than or equal +to the number of elements in the list, then the new elements are +appended to the list. +.VE +.TP +\fBlist \fIarg \fR?\fIarg ...\fR? +This command returns a list comprised of all the \fIarg\fRs. Braces +and backslashes get added as necessary, so that the \fBindex\fR command +may be used on the result to re-extract the original arguments, and also +so that \fBeval\fR may be used to execute the resulting list, with +\fIarg1\fR comprising the command's name and the other \fIarg\fRs comprising +its arguments. \fBList\fR produces slightly different results than +\fBconcat\fR: \fBconcat\fR removes one level of grouping before forming +the list, while \fBlist\fR works directly from the original arguments. +For example, the command +.RS +.DS +\fBlist a b {c d e} {f {g h}} +.DE +will return +.DS +\fBa b {c d e} {f {g h}} +.DE +while \fBconcat\fR with the same arguments will return +.DS +\fBa b c d e f {g h}\fR +.DE +.RE +.br +.VS +.TP +\fBllength \fIlist\fR +Treats \fIlist\fR as a list and returns a decimal string giving +the number of elements in it. +.TP +\fBlrange \fIlist first last +\fIList\fR must be a valid Tcl list. This command will +return a new list consisting of elements +\fIfirst\fR through \fIlast\fR, inclusive. +\fILast\fR may be \fBend\fR (or any +abbreviation of it) to refer to the last element of the list. +If \fIfirst\fR is less than zero, it is treated as if it were zero. +If \fIlast\fR is greater than or equal to the number of elements +in the list, then it is treated as if it were \fBend\fR. +If \fIfirst\fR is greater than \fIlast\fR then an empty string +is returned. +Note: ``\fBlrange \fIlist first first\fR'' does not always produce the +same result as ``\fBlindex \fIlist first\fR'' (although it often does +for simple fields that aren't enclosed in braces); it does, however, +produce exactly the same results as ``\fBlist [lindex \fIlist first\fB]\fR'' +.TP +\fBlreplace \fIlist first last \fR?\fIelement element ...\fR? +Returns a new list formed by replacing one or more elements of +\fIlist\fR with the \fIelement\fR arguments. +\fIFirst\fR gives the index in \fIlist\fR of the first element +to be replaced. +If \fIfirst\fR is less than zero then it refers to the first +element of \fIlist\fR; the element indicated by \fIfirst\fR +must exist in the list. +\fILast\fR gives the index in \fIlist\fR of the last element +to be replaced; it must be greater than or equal to \fIfirst\fR. +\fILast\fR may be \fBend\fR (or any abbreviation of it) to indicate +that all elements between \fIfirst\fR and the end of the list should +be replaced. +The \fIelement\fR arguments specify zero or more new arguments to +be added to the list in place of those that were deleted. +Each \fIelement\fR argument will become a separate element of +the list. +If no \fIelement\fR arguments are specified, then the elements +between \fIfirst\fR and \fIlast\fR are simply deleted. +.TP +\fBlsearch \fIlist pattern\fR +Search the elements of \fIlist\fR to see if one of them matches +\fIpattern\fR. +If so, the command returns the index of the first matching +element. +If not, the command returns \fB\-1\fR. +Pattern matching is done in the same way as for the \fBstring match\fR +command. +.TP +\fBlsort \fIlist\fR +Sort the elements of \fIlist\fR, returning a new list in sorted +order. +ASCII sorting is used, with the result in increasing order. +.VE +.TP +\fBopen \fIfileName\fR ?\fIaccess\fR? +.VS +Opens a file and returns an identifier +that may be used in future invocations +of commands like \fBread\fR, \fBputs\fR, and \fBclose\fR. +\fIFileName\fR gives the name of the file to open; if it starts with +a tilde then tilde substitution is performed as described for +\fBTcl_TildeSubst\fR. +If the first character of \fIfileName\fR is ``|'' then the +remaining characters of \fIfileName\fR are treated as a command +pipeline to invoke, in the same style as for \fBexec\fR. +In this case, the identifier returned by \fBopen\fR may be used +to write to the command's input pipe or read from its output pipe. +The \fIaccess\fR argument indicates the way in which the file +(or command pipeline) is to be accessed. +It may have any of the following values: +.RS +.TP +\fBr\fR +Open the file for reading only; the file must already exist. +.TP +\fBr+\fR +Open the file for both reading and writing; the file must +already exist. +.TP +\fBw\fR +Open the file for writing only. Truncate it if it exists. If it doesn't +exist, create a new file. +.TP +\fBw+\fR +Open the file for reading and writing. Truncate it if it exists. +If it doesn't exist, create a new file. +.TP +\fBa\fR +Open the file for writing only. The file must already exist, and the file +is positioned so that new data is appended to the file. +.TP +\fBa+\fR +Open the file for reading and writing. If the file doesn't exist, +create a new empty file. +Set the initial access position to the end of the file. +.PP +\fIAccess\fR defaults to \fBr\fR. +If a file is opened for both reading and writing, then \fBseek\fR +must be invoked between a read and a write, or vice versa (this +restriction does not apply to command pipelines opened with \fBopen\fR). +When \fIfileName\fR specifies a command pipeline and a write-only access +is used, then standard output from the pipeline is directed to the +current standard output unless overridden by the command. +When \fIfileName\fR specifies a command pipeline and a read-only access +is used, then standard input from the pipeline is taken from the +current standard input unless overridden by the command. +.RE +.VE +.TP +\fBproc \fIname args body\fR +The \fBproc\fR command creates a new Tcl command procedure, +\fIname\fR, replacing +any existing command there may have been by that name. Whenever the +new command is invoked, the contents of \fIbody\fR will be executed +by the Tcl interpreter. \fIArgs\fR specifies the formal arguments to the +procedure. It consists of a list, possibly empty, each of whose +elements specifies +one argument. Each argument specifier is also a list with either +one or two fields. If there is only a single field in the specifier, +then it is the name of the argument; if there are two fields, then +the first is the argument name and the second is its default value. +braces and backslashes may be used in the usual way to specify +complex default values. +.IP +When \fIname\fR is invoked, a local variable +will be created for each of the formal arguments to the procedure; its +value will be the value of corresponding argument in the invoking command +or the argument's default value. +Arguments with default values need not be +specified in a procedure invocation. However, there must be enough +actual arguments for all the +formal arguments that don't have defaults, and there must not be any extra +actual arguments. There is one special case to permit procedures with +variable numbers of arguments. If the last formal argument has the name +\fBargs\fR, then a call to the procedure may contain more actual arguments +than the procedure has formals. In this case, all of the actual arguments +starting at the one that would be assigned to \fBargs\fR are combined into +a list (as if the \fBlist\fR command had been used); this combined value +is assigned to the local variable \fBargs\fR. +.IP +When \fIbody\fR is being executed, variable names normally refer to +local variables, which are created automatically when referenced and +deleted when the procedure returns. One local variable is automatically +created for each of the procedure's arguments. +Global variables can only be accessed by invoking +the \fBglobal\fR command. +.IP +The \fBproc\fR command returns the null string. When a procedure is +invoked, the procedure's return value is the value specified in a +\fBreturn\fR command. If the procedure doesn't execute an explicit +\fBreturn\fR, then its return value is the value of the last command +executed in the procedure's body. +If an error occurs while executing the procedure +body, then the procedure-as-a-whole will return that same error. +.TP +\fBputs \fR?\fB\-nonewline\fR? ?\fIfileId\fR? \fIstring\fR +.VS +Writes the characters given by \fIstring\fR to the file given +by \fIfileId\fR. +\fIFileId\fR must have been the return +value from a previous call to \fBopen\fR, or it may be +\fBstdout\fR or \fBstderr\fR to refer to one of the standard I/O +channels; it must refer to a file that was opened for +writing. +If no \fIfileId\fR is specified then it defaults to \fBstdout\fR. +\fBPuts\fR normally outputs a newline character after \fIstring\fR, +.VS +but this feature may be suppressed by specifying the \fB\-nonewline\fR +switch. +.VE +Output to files is buffered internally by Tcl; the \fBflush\fR +command may be used to force buffered characters to be output. +.TP +\fBpwd\fR +.br +Returns the path name of the current working directory. +.TP +\fBread \fR?\fB\-nonewline\fR? \fIfileId\fR +.VS +.TP +\fBread \fIfileId numBytes\fR +In the first form, all of the remaining bytes are read from the file +given by \fIfileId\fR; they are returned as the result of the command. +If the \fB\-nonewline\fR switch is specified then the last +character of the file is discarded if it is a newline. +.VE +In the second form, the extra argument specifies how many bytes to read; +exactly this many bytes will be read and returned, unless there are fewer than +\fInumBytes\fR bytes left in the file; in this case, all the remaining +bytes are returned. +\fIFileId\fR must be \fBstdin\fR or the return +value from a previous call to \fBopen\fR; it must +refer to a file that was opened for reading. +.TP +\fBregexp \fR?\fB\-indices\fR? \fR?\fB\-nocase\fR? \fIexp string \fR?\fImatchVar\fR? ?\fIsubMatchVar subMatchVar ...\fR? +Determines whether the regular expression \fIexp\fR matches part or +all of \fIstring\fR and returns 1 if it does, 0 if it doesn't. +See REGULAR EXPRESSIONS above for complete information on the +syntax of \fIexp\fR and how it is matched against \fIstring\fR. +.RS +.LP +If the \fB\-nocase\fR switch is specified then upper-case +characters in \fIstring\fR +are treated as lower case during the matching process. +The \fB\-nocase\fR switch must be specified before \fIexp\fR and +may not be abbreviated. +.LP +If additional arguments are specified after \fIstring\fR then they +are treated as the names of variables to use to return +information about which part(s) of \fIstring\fR matched \fIexp\fR. +\fIMatchVar\fR will be set to the range of \fIstring\fR that +matched all of \fIexp\fR. The first \fIsubMatchVar\fR will contain +the characters in \fIstring\fR that matched the leftmost parenthesized +subexpression within \fIexp\fR, the next \fIsubMatchVar\fR will +contain the characters that matched the next parenthesized +subexpression to the right in \fIexp\fR, and so on. +.LP +Normally, \fImatchVar\fR and the \fIsubMatchVar\fRs are set to hold +the matching characters from \fBstring\fR. +However, if the \fB\-indices\fR switch is specified then each variable +will contain a list of two decimal strings giving the indices +in \fIstring\fR of the first and last characters in the matching +range of characters. +The \fB\-indices\fR switch must be specified before the \fIexp\fR +argument and may not be abbreviated. +.LP +If there are more \fIsubMatchVar\fR's than parenthesized +subexpressions within \fIexp\fR, or if a particular subexpression +in \fIexp\fR doesn't match the string (e.g. because it was in a +portion of the expression that wasn't matched), then the corresponding +\fIsubMatchVar\fR will be set to ``\fB\-1 \-1\fR'' if \fB\-indices\fR +has been specified or to an empty string otherwise. +.RE +.TP +\fBregsub \fR?\fB\-all\fR? ?\fB\-nocase\fR? \fIexp string subSpec varName\fR +This command matches the regular expression \fIexp\fR against +\fIstring\fR using the rules described in REGULAR EXPRESSIONS +above. +If there is no match, then the command returns 0 and does nothing +else. +If there is a match, then the command returns 1 and also copies +\fIstring\fR to the variable whose name is given by \fIvarName\fR. +When copying \fIstring\fR, the portion of \fIstring\fR that +matched \fIexp\fR is replaced with \fIsubSpec\fR. +If \fIsubSpec\fR contains a ``&'' or ``\e0'', then it is replaced +in the substitution with the portion of \fIstring\fR that +matched \fIexp\fR. +If \fIsubSpec\fR contains a ``\e\fIn\fR'', where \fIn\fR is a digit +between 1 and 9, then it is replaced in the substitution with +the portion of \fIstring\fR that matched the \fIn\fR-th +parenthesized subexpression of \fIexp\fR. +Additional backslashes may be used in \fIsubSpec\fR to prevent special +interpretation of ``&'' or ``\e0'' or ``\e\fIn\fR'' or +backslash. +The use of backslashes in \fIsubSpec\fR tends to interact badly +with the Tcl parser's use of backslashes, so it's generally +safest to enclose \fIsubSpec\fR in braces if it includes +backslashes. +If the \fB\-all\fR argument is specified, then all ranges in +\fIstring\fR that match \fIexp\fR are found and substitution is +performed for each of these ranges; otherwise only the first +matching range is found and substituted. +If \fB\-all\fR is specified, then ``&'' and ``\e\fIn\fR'' +sequences are handled for each substitution using the information +from the corresponding match. +If the \fB\-nocase\fR argument is specified, then upper-case +characters in \fIstring\fR are converted to lower-case before +matching against \fIexp\fR; however, substitutions specified +by \fIsubSpec\fR use the original unconverted form of \fIstring\fR. +The \fB\-all\fR and \fB\-nocase\fR arguments must be specified +exactly: no abbreviations are permitted. +.VE +.TP +\fBrename \fIoldName newName\fR +Rename the command that used to be called \fIoldName\fR so that it +is now called \fInewName\fR. If \fInewName\fR is an empty string +(e.g. {}) then \fIoldName\fR is deleted. The \fBrename\fR command +returns an empty string as result. +.TP +\fBreturn \fR?\fIvalue\fR? +Return immediately from the current procedure +(or top-level command or \fBsource\fR command), +with \fIvalue\fR as the return value. If \fIvalue\fR is not specified, +an empty string will be returned as result. +.TP +\fBscan \fIstring format varname1 \fR?\fIvarname2 ...\fR? +This command parses fields from an input string in the same fashion +as the C \fBsscanf\fR procedure. \fIString\fR gives the input to +be parsed and \fIformat\fR indicates how to parse it, using \fB%\fR +fields as in \fBsscanf\fR. All of the \fBsscanf\fR options are valid; +see the \fBsscanf\fR man page for details. Each \fIvarname\fR gives +the name of a variable; when a field is scanned from \fIstring\fR, +the result is converted back into a string and assigned to the +corresponding \fIvarname\fR. The only unusual conversion is for +\fB%c\fR. For \fB%c\fR conversions a single character value is +converted to a decimal string, which is then assigned to the +corresponding \fIvarname\fR; +.VS +no field width may be specified for this conversion. +.TP +\fBseek \fIfileId offset \fR?\fIorigin\fR? +Change the current access position for \fIfileId\fR. +The \fIoffset\fR and \fIorigin\fR arguments specify the position at +which the next read or write will occur for \fIfileId\fR. +\fIOffset\fR must be a number (which may be negative) and \fIorigin\fR +must be one of the following: +.RS +.TP +\fBstart\fR +The new access position will be \fIoffset\fR bytes from the start +of the file. +.TP +\fBcurrent\fR +The new access position will be \fIoffset\fR bytes from the current +access position; a negative \fIoffset\fR moves the access position +backwards in the file. +.TP +\fBend\fR +The new access position will be \fIoffset\fR bytes from the end of +the file. A negative \fIoffset\fR places the access position before +the end-of-file, and a positive \fIoffset\fR places the access position +after the end-of-file. +.LP +The \fIorigin\fR argument defaults to \fBstart\fR. +\fIFileId\fR must have been the return +value from a previous call to \fBopen\fR, or it may be \fBstdin\fR, +\fBstdout\fR, or \fBstderr\fR to refer to one of the standard I/O +channels. +This command returns an empty string. +.RE +.VE +.TP +\fBset \fIvarname \fR?\fIvalue\fR? +Returns the value of variable \fIvarname\fR. +If \fIvalue\fR is specified, then set +the value of \fIvarname\fR to \fIvalue\fR, creating a new variable +if one doesn't already exist, and return its value. +.VS +If \fIvarName\fR contains an open parenthesis and ends with a +close parenthesis, then it refers to an array element: the characters +before the open parenthesis are the name of the array, and the characters +between the parentheses are the index within the array. +Otherwise \fIvarName\fR refers to a scalar variable. +.VE +If no procedure is active, then \fIvarname\fR refers to a global +variable. +If a procedure is active, then \fIvarname\fR refers to a parameter +or local variable of the procedure, unless the \fIglobal\fR command +has been invoked to declare \fIvarname\fR to be global. +.TP +\fBsource \fIfileName\fR +Read file \fIfileName\fR and pass the contents to the Tcl interpreter +as a sequence of commands to execute in the normal fashion. The return +value of \fBsource\fR is the return value of the last command executed +from the file. If an error occurs in executing the contents of the +file, then the \fBsource\fR command will return that error. +If a \fBreturn\fR command is invoked from within the file, the remainder of +the file will be skipped and the \fBsource\fR command will return +normally with the result from the \fBreturn\fR command. +If \fIfileName\fR starts with a tilde, then it is tilde-substituted +as described in the \fBTcl_TildeSubst\fR manual entry. +.TP +\fBsplit \fIstring \fR?\fIsplitChars\fR? +Returns a list created by splitting \fIstring\fR at each character +that is in the \fIsplitChars\fR argument. +Each element of the result list will consist of the +characters from \fIstring\fR between instances of the +characters in \fIsplitChars\fR. +Empty list elements will be generated if \fIstring\fR contains +adjacent characters in \fIsplitChars\fR, or if the first or last +character of \fIstring\fR is in \fIsplitChars\fR. +If \fIsplitChars\fR is an empty string then each character of +\fIstring\fR becomes a separate element of the result list. +\fISplitChars\fR defaults to the standard white-space characters. +For example, +.RS +.DS +\fBsplit "comp.unix.misc" .\fR +.DE +returns \fB"comp unix misc"\fR and +.DS +\fBsplit "Hello world" {}\fR +.DE +returns \fB"H e l l o { } w o r l d"\fR. +.VE +.RE +.TP +\fBstring \fIoption arg \fR?\fIarg ...?\fR +Perform one of several string operations, depending on \fIoption\fR. +The legal \fIoption\fRs (which may be abbreviated) are: +.RS +.TP +\fBstring compare \fIstring1 string2\fR +Perform a character-by-character comparison of strings \fIstring1\fR and +\fIstring2\fR in the same way as the C \fBstrcmp\fR procedure. Return +-1, 0, or 1, depending on whether \fIstring1\fR is lexicographically +less than, equal to, or greater than \fIstring2\fR. +.TP +\fBstring first \fIstring1 string2\fR +Search \fIstring2\fR for a sequence of characters that exactly match +the characters in \fIstring1\fR. If found, return the index of the +first character in the first such match within \fIstring2\fR. If not +found, return -1. +.br +.VS +.TP +\fBstring index \fIstring charIndex\fR +Returns the \fIcharIndex\fR'th character of the \fIstring\fR +argument. A \fIcharIndex\fR of 0 corresponds to the first +character of the string. +If \fIcharIndex\fR is less than 0 or greater than +or equal to the length of the string then an empty string is +returned. +.VE +.TP +\fBstring last \fIstring1 string2\fR +Search \fIstring2\fR for a sequence of characters that exactly match +the characters in \fIstring1\fR. If found, return the index of the +first character in the last such match within \fIstring2\fR. If there +is no match, then return \-1. +.br +.VS +.TP +\fBstring length \fIstring\fR +Returns a decimal string giving the number of characters in \fIstring\fR. +.VE +.TP +\fBstring match \fIpattern\fR \fIstring\fR +See if \fIpattern\fR matches \fIstring\fR; return 1 if it does, 0 +if it doesn't. Matching is done in a fashion similar to that +used by the C-shell. For the two strings to match, their contents +must be identical except that the following special sequences +may appear in \fIpattern\fR: +.RS +.IP \fB*\fR 10 +Matches any sequence of characters in \fIstring\fR, +including a null string. +.IP \fB?\fR 10 +Matches any single character in \fIstring\fR. +.IP \fB[\fIchars\fB]\fR 10 +Matches any character in the set given by \fIchars\fR. If a sequence +of the form +\fIx\fB\-\fIy\fR appears in \fIchars\fR, then any character +between \fIx\fR and \fIy\fR, inclusive, will match. +.IP \fB\e\fIx\fR 10 +Matches the single character \fIx\fR. This provides a way of +avoiding the special interpretation of the characters +\fB*?[]\e\fR in \fIpattern\fR. +.RE +.br +.VS +.TP +\fBstring range \fIstring first last\fR +Returns a range of consecutive characters from \fIstring\fR, starting +with the character whose index is \fIfirst\fR and ending with the +character whose index is \fIlast\fR. An index of 0 refers to the +first character of the string. \fILast\fR may be \fBend\fR (or any +abbreviation of it) to refer to the last character of the string. +If \fIfirst\fR is less than zero then it is treated as if it were zero, and +if \fIlast\fR is greater than or equal to the length of the string then +it is treated as if it were \fBend\fR. If \fIfirst\fR is greater than +\fIlast\fR then an empty string is returned. +.TP +\fBstring tolower \fIstring\fR +Returns a value equal to \fIstring\fR except that all upper case +letters have been converted to lower case. +.TP +\fBstring toupper \fIstring\fR +Returns a value equal to \fIstring\fR except that all lower case +letters have been converted to upper case. +.TP +\fBstring trim \fIstring\fR ?\fIchars\fR? +Returns a value equal to \fIstring\fR except that any leading +or trailing characters from the set given by \fIchars\fR are +removed. +If \fIchars\fR is not specified then white space is removed +(spaces, tabs, newlines, and carriage returns). +.TP +\fBstring trimleft \fIstring\fR ?\fIchars\fR? +Returns a value equal to \fIstring\fR except that any +leading characters from the set given by \fIchars\fR are +removed. +If \fIchars\fR is not specified then white space is removed +(spaces, tabs, newlines, and carriage returns). +.TP +\fBstring trimright \fIstring\fR ?\fIchars\fR? +Returns a value equal to \fIstring\fR except that any +trailing characters from the set given by \fIchars\fR are +removed. +If \fIchars\fR is not specified then white space is removed +(spaces, tabs, newlines, and carriage returns). +.RE +.TP +\fBtell \fIfileId\fR +Returns a decimal string giving the current access position in +\fIfileId\fR. +\fIFileId\fR must have been the return +value from a previous call to \fBopen\fR, or it may be \fBstdin\fR, +\fBstdout\fR, or \fBstderr\fR to refer to one of the standard I/O +channels. +.VE +.TP +\fBtime \fIcommand\fR ?\fIcount\fR? +This command will call the Tcl interpreter \fIcount\fR +times to execute \fIcommand\fR (or once if \fIcount\fR isn't +specified). It will then return a string of the form +.RS +.DS +\fB503 microseconds per iteration\fR +.DE +which indicates the average amount of time required per iteration, +in microseconds. +Time is measured in elapsed time, not CPU time. +.RE +.TP +\fBtrace \fIoption\fR ?\fIarg arg ...\fR? +.VS +Cause Tcl commands to be executed whenever certain operations are +invoked. At present, only variable tracing is implemented. The +legal \fIoption\fR's (which may be abbreviated) are: +.RS +.TP +\fBtrace variable \fIname ops command\fR +Arrange for \fIcommand\fR to be executed whenever variable \fIname\fR +is accessed in one of the ways given by \fIops\fR. \fIName\fR may +refer to a normal variable, an element of an array, or to an array +as a whole (i.e. \fIname\fR may be just the name of an array, with no +parenthesized index). If \fIname\fR refers to a whole array, then +\fIcommand\fR is invoked whenever any element of the array is +manipulated. +.RS +.LP +\fIOps\fR indicates which operations are of interest, and consists of +one or more of the following letters: +.RS +.TP +\fBr\fR +Invoke \fIcommand\fR whenever the variable is read. +.TP +\fBw\fR +Invoke \fIcommand\fR whenever the variable is written. +.TP +\fBu\fR +Invoke \fIcommand\fR whenever the variable is unset. Variables +can be unset explicitly with the \fBunset\fR command, or +implicitly when procedures return (all of their local variables +are unset). Variables are also unset when interpreters are +deleted, but traces will not be invoked because there is no +interpreter in which to execute them. +.RE +.LP +When the trace triggers, three arguments are appended to +\fIcommand\fR so that the actual command is as follows: +.DS C +\fIcommand name1 name2 op\fR +.DE +\fIName1\fR and \fIname2\fR give the name(s) for the variable +being accessed: if the variable is a scalar then \fIname1\fR +gives the variable's name and \fIname2\fR is an empty string; +if the variable is an array element then \fIname1\fR gives the +name of the array and name2 gives the index into the array; +if an entire array is being deleted and the trace was registered +on the overall array, rather than a single element, then \fIname1\fR +gives the array name and \fIname2\fR is an empty string. +\fIOp\fR indicates what operation is being performed on the +variable, and is one of \fBr\fR, \fBw\fR, or \fBu\fR as +defined above. +.LP +\fICommand\fR executes in the same context as the code that invoked +the traced operation: if the variable was accessed as part of a +Tcl procedure, then \fIcommand\fR will have access to the same +local variables as code in the procedure. This context may be +different than the context in which the trace was created. +If \fIcommand\fR invokes a procedure (which it normally does) then +the procedure will have to use \fBupvar\fR or \fBuplevel\fR if it +wishes to access the traced variable. +Note also that \fIname1\fR may not necessarily be the same as the name +used to set the trace on the variable; differences can occur if +the access is made through a variable defined with the \fBupvar\fR +command. +.LP +For read and write traces, \fIcommand\fR can modify +the variable to affect the result of the traced operation. +If \fIcommand\fR modifies the value of a variable during a +read or write trace, then the new value will be returned as the +result of the traced operation. +The return value from \fIcommand\fR is ignored except that +if it returns an error of any sort then the traced operation +is aborted with an error message saying that the access was denied +(this mechanism can be used to implement read-only variables, for +example). +For write traces, \fIcommand\fR is invoked after the variable's +value has been changed; it can write a new value into the variable +to override the original value specified in the write operation. +To implement read-only variables, \fIcommand\fR will have to restore +the old value of the variable. +.LP +While \fIcommand\fR is executing during a read or write trace, traces +on the variable are temporarily disabled. +This means that reads and writes invoked by +\fIcommand\fR will occur directly, without invoking \fIcommand\fR +(or any other traces) again. +.LP +When an unset trace is invoked, the variable has already been +deleted: it will appear to be undefined with no traces. +If an unset occurs because of a procedure return, then the +trace will be invoked in the variable context of the procedure +being returned to: the stack frame of the returning procedure +will no longer exist. +Traces are not disabled during unset traces, so if an unset trace +command creates a new trace and accesses the variable, the +trace will be invoked. +.LP +If there are multiple traces on a variable they are invoked +in order of creation, most-recent first. +If one trace returns an error, then no further traces are +invoked for the variable. +If an array element has a trace set, and there is also a trace +set on the array as a whole, the trace on the overall array +is invoked before the one on the element. +.LP +Once created, the trace remains in effect either until the +trace is removed with the \fBtrace vdelete\fR command described +below, until the variable is unset, or until the interpreter +is deleted. +Unsetting an element of array will remove any traces on that +element, but will not remove traces on the overall array. +.LP +This command returns an empty string. +.RE +.TP +\fBtrace vdelete \fIname ops command\fR +If there is a trace set on variable \fIname\fR with the +operations and command given by \fIops\fR and \fIcommand\fR, +then the trace is removed, so that \fIcommand\fR will never +again be invoked. +Returns an empty string. +.TP +\fBtrace vinfo \fIname\fR +Returns a list containing one element for each trace +currently set on variable \fIname\fR. +Each element of the list is itself a list containing two +elements, which are the \fIops\fR and \fIcommand\fR associated +with the trace. +If \fIname\fR doesn't exist or doesn't have any traces set, then +the result of the command will be an empty string. +.RE +.TP +\fBunknown \fIcmdName \fR?\fIarg arg ...\fR? +This command doesn't actually exist as part of Tcl, but Tcl will +invoke it if it does exist. +If the Tcl interpreter encounters a command name for which there +is not a defined command, then Tcl checks for the existence of +a command named \fBunknown\fR. +If there is no such command, then the interpeter returns an +error. +If the \fBunknown\fR command exists, then it is invoked with +arguments consisting of the fully-substituted name and arguments +for the original non-existent command. +The \fBunknown\fR command typically does things like searching +through library directories for a command procedure with the name +\fIcmdName\fR, or expanding abbreviated command names to full-length, +or automatically executing unknown commands as UNIX sub-processes. +In some cases (such as expanding abbreviations) \fBunknown\fR will +change the original command slightly and then (re-)execute it. +The result of the \fBunknown\fR command is used as the result for +the original non-existent command. +.TP +\fBunset \fIname \fR?\fIname name ...\fR? +Remove one or more variables. +Each \fIname\fR is a variable name, specified in any of the +ways acceptable to the \fBset\fR command. +If a \fIname\fR refers to an element of an array, then that +element is removed without affecting the rest of the array. +If a \fIname\fR consists of an array name with no parenthesized +index, then the entire array is deleted. +The \fBunset\fR command returns an empty string as result. +An error occurs if any of the variables doesn't exist. +.VE +.TP +\fBuplevel \fR?\fIlevel\fR?\fI command \fR?\fIcommand ...\fR? +All of the \fIcommand\fR arguments are concatenated as if they had +been passed to \fBconcat\fR; the result is then evaluated in the +variable context indicated by \fIlevel\fR. \fBUplevel\fR returns +the result of that evaluation. If \fIlevel\fR is an integer, then +it gives a distance (up the procedure calling stack) to move before +executing the command. If \fIlevel\fR consists of \fB#\fR followed by +a number then the number gives an absolute level number. If \fIlevel\fR +is omitted then it defaults to \fB1\fR. \fILevel\fR cannot be +defaulted if the first \fIcommand\fR argument starts with a digit or \fB#\fR. +For example, suppose that procedure \fBa\fR was invoked +from top-level, and that it called \fBb\fR, and that \fBb\fR called \fBc\fR. +Suppose that \fBc\fR invokes the \fBuplevel\fR command. If \fIlevel\fR +is \fB1\fR or \fB#2\fR or omitted, then the command will be executed +in the variable context of \fBb\fR. If \fIlevel\fR is \fB2\fR or \fB#1\fR +then the command will be executed in the variable context of \fBa\fR. +If \fIlevel\fR is \fB3\fR or \fB#0\fR then the command will be executed +at top-level (only global variables will be visible). +The \fBuplevel\fR command causes the invoking procedure to disappear +from the procedure calling stack while the command is being executed. +In the above example, suppose \fBc\fR invokes the command +.RS +.DS +\fBuplevel 1 {set x 43; d} +.DE +where \fBd\fR is another Tcl procedure. The \fBset\fR command will +modify the variable \fBx\fR in \fBb\fR's context, and \fBd\fR will execute +at level 3, as if called from \fBb\fR. If it in turn executes +the command +.DS +\fBuplevel {set x 42} +.DE +then the \fBset\fR command will modify the same variable \fBx\fR in \fBb\fR's +context: the procedure \fBc\fR does not appear to be on the call stack +when \fBd\fR is executing. The command ``\fBinfo level\fR'' may +be used to obtain the level of the current procedure. +\fBUplevel\fR makes it possible to implement new control +constructs as Tcl procedures (for example, \fBuplevel\fR could +be used to implement the \fBwhile\fR construct as a Tcl procedure). +.RE +.TP +\fBupvar \fR?\fIlevel\fR? \fIotherVar myVar \fR?\fIotherVar myVar \fR...? +.VS +This command arranges for one or more local variables in the current +procedure to refer to variables in an enclosing procedure call or +to global variables. +\fILevel\fR may have any of the forms permitted for the \fBuplevel\fR +command, and may be omitted if the first letter of the first \fIotherVar\fR +isn't \fB#\fR or a digit (it defaults to \fB1\fR). +For each \fIotherVar\fR argument, \fBupvar\fR makes the variable +by that name in the procedure frame given by \fIlevel\fR (or at +global level, if \fIlevel\fR is \fB#0\fR) accessible +in the current procedure by the name given in the corresponding +\fImyVar\fR argument. +The variable named by \fIotherVar\fR need not exist at the time of the +call; it will be created the first time \fImyVar\fR is referenced, just like +an ordinary variable. +\fBUpvar\fR may only be invoked from within procedures. +Neither \fIotherVar\fR or \fImyVar\fR may refer to an element of an +array. +\fBUpvar\fR returns an empty string. +.RS +.LP +The \fBupvar\fR command simplifies the implementation of call-by-name +procedure calling and also makes it easier to build new control constructs +as Tcl procedures. +For example, consider the following procedure: +.DS +.ta 1c 2c 3c +\fBproc add2 name { + upvar $name x + set x [expr $x+2] +} +.DE +\fBAdd2\fR is invoked with an argument giving the name of a variable, +and it adds two to the value of that variable. +Although \fBadd2\fR could have been implemented using \fBuplevel\fR +instead of \fBupvar\fR, \fBupvar\fR makes it simpler for \fBadd2\fR +to access the variable in the caller's procedure frame. +.VE +.RE +.TP +\fBwhile \fItest body +.VS +The \fIwhile\fR command evaluates \fItest\fR as an expression +(in the same way that \fBexpr\fR evaluates its argument). +The value of the expression must be numeric; if it is non-zero +then \fIbody\fR is executed by passing it to the Tcl interpreter. +Once \fIbody\fR has been executed then \fItest\fR is evaluated +again, and the process repeats until eventually \fItest\fR +evaluates to a zero numeric value. \fBContinue\fR +commands may be executed inside \fIbody\fR to terminate the current +iteration of the loop, and \fBbreak\fR +commands may be executed inside \fIbody\fR to cause immediate +termination of the \fBwhile\fR command. The \fBwhile\fR command +always returns an empty string. +.VE + +.SH "BUILT-IN VARIABLES" +.PP +The following global variables are created and managed automatically +by the Tcl library. Except where noted below, these variables should +normally be treated as read-only by application-specific code and by users. +.TP +\fBenv\fR +.br +.VS +This variable is maintained by Tcl as an array +whose elements are the environment variables for the process. +Reading an element will return the value of the corresponding +environment variable. +Setting an element of the array will modify the corresponding +environment variable or create a new one if it doesn't already +exist. +Unsetting an element of \fBenv\fR will remove the corresponding +environment variable. +Changes to the \fBenv\fR array will affect the environment +passed to children by commands like \fBexec\fR. +If the entire \fBenv\fR array is unset then Tcl will stop +monitoring \fBenv\fR accesses and will not update environment +variables. +.TP +\fBerrorCode\fR +After an error has occurred, this variable will be set to hold +additional information about the error in a form that is easy +to process with programs. +\fBerrorCode\fR consists of a Tcl list with one or more elements. +The first element of the list identifies a general class of +errors, and determines the format of the rest of the list. +The following formats for \fBerrorCode\fR are used by the +Tcl core; individual applications may define additional formats. +.RS +.TP +\fBCHILDKILLED\fI pid sigName msg\fR +This format is used when a child process has been killed because of +a signal. The second element of \fBerrorCode\fR will be the +process's identifier (in decimal). +The third element will be the symbolic name of the signal that caused +the process to terminate; it will be one of the names from the +include file signal.h, such as \fBSIGPIPE\fR. +The fourth element will be a short human-readable message +describing the signal, such as ``write on pipe with no readers'' +for \fBSIGPIPE\fR. +.TP +\fBCHILDSTATUS\fI pid code\fR +This format is used when a child process has exited with a non-zero +exit status. The second element of \fBerrorCode\fR will be the +process's identifier (in decimal) and the third element will be the exit +code returned by the process (also in decimal). +.TP +\fBCHILDSUSP\fI pid sigName msg\fR +This format is used when a child process has been suspended because +of a signal. +The second element of \fBerrorCode\fR will be the process's identifier, +in decimal. +The third element will be the symbolic name of the signal that caused +the process to suspend; this will be one of the names from the +include file signal.h, such as \fBSIGTTIN\fR. +The fourth element will be a short human-readable message +describing the signal, such as ``background tty read'' +for \fBSIGTTIN\fR. +.TP +\fBNONE\fR +.br +This format is used for errors where no additional information is +available for an error besides the message returned with the +error. In these cases \fBerrorCode\fR will consist of a list +containing a single element whose contents are \fBNONE\fR. +.TP +\fBUNIX \fIerrName msg\fR +If the first element of \fBerrorCode\fR is \fBUNIX\fR, then +the error occurred during a UNIX kernel call. +The second element of the list will contain the symbolic name +of the error that occurred, such as \fBENOENT\fR; this will +be one of the values defined in the include file errno.h. +The third element of the list will be a human-readable +message corresponding to \fIerrName\fR, such as +``no such file or directory'' for the \fBENOENT\fR case. +.PP +To set \fBerrorCode\fR, applications should use library +procedures such as \fBTcl_SetErrorCode\fR and +\fBTcl_UnixError\fR, or they may invoke the \fBerror\fR command. +If one of these methods hasn't been used, then the Tcl +interpreter will reset the variable to \fBNONE\fR after +the next error. +.RE +.VE +.TP +\fBerrorInfo\fR +After an error has occurred, this string will contain one or more lines +identifying the Tcl commands and procedures that were being executed +when the most recent error occurred. +Its contents take the form of a stack trace showing the various +nested Tcl commands that had been invoked at the time of the error. + +.SH AUTHOR +John Ousterhout, University of California at Berkeley (ouster@sprite.berkeley.edu) +.sp +Many people have contributed to Tcl in various ways, but the following +people have made unusually large contributions: +.sp +.nf +Bill Carpenter +Peter Da Silva +Mark Diekhans +Karl Lehenbauer +Mary Ann May-Pumphrey diff --git a/src/libtcl/doc/TildeSubst.3 b/src/libtcl/doc/TildeSubst.3 new file mode 100644 index 0000000..df65ffa --- /dev/null +++ b/src/libtcl/doc/TildeSubst.3 @@ -0,0 +1,58 @@ +'\" +'\" Copyright 1989 Regents of the University of California +'\" Permission to use, copy, modify, and distribute this +'\" documentation for any purpose and without fee is hereby +'\" granted, provided that this notice appears in all copies. +'\" The University of California makes no representations about +'\" the suitability of this material for any purpose. It is +'\" provided "as is" without express or implied warranty. +'\" +'\" $Header: /cvsroot/PROCPLACE/pptinytcl/doc/TildeSubst.3,v 1.1.1.1 2001/04/20 15:03:06 karl Exp $ SPRITE (Berkeley) +'\" +.so man.macros +.HS Tcl_TildeSubst tcl +.BS +.SH NAME +Tcl_TildeSubst \- replace tilde with home directory in a file name +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +char * +\fBTcl_TildeSubst\fR(\fIinterp\fR, \fIname\fR) +.SH ARGUMENTS +.AS Tcl_Interp *interp +.AP Tcl_Interp *interp in +Interpreter in which to report an error, if any. +.AP char *name in +File name, which may start with a ``~''. +.BE + +.SH DESCRIPTION +.PP +This utility procedure does tilde substition. If \fIname\fR doesn't +start with a ``~'' character, then the procedure returns \fIname\fR. +If \fIname\fR does start with a tilde, then \fBTcl_TildeSubst\fR +returns a new string identical to \fIname\fR except that the first +element of \fIname\fR is replaced with the location of the home +directory for the given user. The substitution is carried out in +the same way that it would be done by \fIcsh\fR. If the tilde is +followed immediately by a slash, then the \fB$HOME\fR environment +variable is substituted. Otherwise the characters between the +tilde and the next slash are taken as a user name, which is +looked up in the password file; the user's home directory is +retrieved from the password file and substituted. +.PP +The string returned by \fBTcl_TildeSubst\fR is a static string +belonging to \fBTcl_TildeSubst\fR. Its value will only persist +until the next call to \fBTcl_TildeSubst\fR; the caller should +make a copy of the result if it needs to live a long time. +.PP +If an error occurs (e.g. because there was no user by the given +name) then NULL is returned and an error message will be left +at \fIinterp->result\fR. It is assumed that \fIinterp->result\fR +has been initialized in the standard way when \fBTcl_TildeSubst\fR +is invoked. + +.SH KEYWORDS +file name, home directory, tilde, user diff --git a/src/libtcl/doc/TraceVar.3 b/src/libtcl/doc/TraceVar.3 new file mode 100644 index 0000000..035c861 --- /dev/null +++ b/src/libtcl/doc/TraceVar.3 @@ -0,0 +1,340 @@ +'\" +'\" Copyright 1989 Regents of the University of California +'\" Permission to use, copy, modify, and distribute this +'\" documentation for any purpose and without fee is hereby +'\" granted, provided that this notice appears in all copies. +'\" The University of California makes no representations about +'\" the suitability of this material for any purpose. It is +'\" provided "as is" without express or implied warranty. +'\" +'\" $Header: /cvsroot/PROCPLACE/pptinytcl/doc/TraceVar.3,v 1.1.1.1 2001/04/20 15:03:06 karl Exp $ SPRITE (Berkeley) +'\" +.so man.macros +.HS Tcl_TraceVar tcl +.VS +.BS +.SH NAME +Tcl_TraceVar, Tcl_TraceVar2, Tcl_UntraceVar, Tcl_UntraceVar2, Tcl_VarTraceInfo, Tcl_VarTraceInfo2 \- monitor accesses to a variable +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +int +\fBTcl_TraceVar(\fIinterp, varName, flags, proc, clientData\fB)\fR +.sp +int +\fBTcl_TraceVar2(\fIinterp, name1, name2, flags, proc, clientData\fB)\fR +.sp +\fBTcl_UnTraceVar(\fIinterp, varName, flags, proc, clientData\fB)\fR +.sp +\fBTcl_UnTraceVar2(\fIinterp, name1, name2, flags, proc, clientData\fB)\fR +.sp +ClientData +\fBTcl_VarTraceInfo(\fIinterp, varName, flags, proc, prevClientData\fB)\fR +.sp +ClientData +\fBTcl_VarTraceInfo2(\fIinterp, name1, name2, flags, proc, prevClientData\fB)\fR +.SH ARGUMENTS +.AS Tcl_VarTraceProc prevClientData +.AP Tcl_Interp *interp in +Interpreter containing variable. +.AP char *varName in +Name of variable. May refer to a scalar variable, to +an array variable with no index, or to an array variable +with a parenthesized index. +.AP int flags in +OR-ed combination of the values TCL_TRACE_READS, TCL_TRACE_WRITES, and +TCL_TRACE_UNSETS, and TCL_GLOBAL_ONLY. Not all flags are used by all +procedures. See below for more information. +.AP Tcl_VarTraceProc *proc in +Procedure to invoke whenever one of the traced operations occurs. +.AP ClientData clientData in +Arbitrary one-word value to pass to \fIproc\fR. +.AP char *name1 in +Name of scalar or array variable (without array index). +.AP char *name2 in +For a trace on an element of an array, gives the index of the +element. For traces on scalar variables or on whole arrays, +is NULL. +.AP ClientData prevClientData in +If non-NULL, gives last value returned by \fBTcl_VarTraceInfo\fR or +\fBTcl_VarTraceInfo2\fR, so this call will return information about +next trace. If NULL, this call will return information about first +trace. +.BE + +.SH DESCRIPTION +.PP +\fBTcl_TraceVar\fR allows a C procedure to monitor and control +access to a Tcl variable, so that the C procedure is invoked +whenever the variable is read or written or unset. +If the trace is created successfully then \fBTcl_TraceVar\fR returns +TCL_OK. If an error occurred (e.g. \fIvarName\fR specifies an element +of an array, but the actual variable isn't an array) then TCL_ERROR +is returned and an error message is left in \fIinterp->result\fR. +.PP +The \fIflags\fR argument to \fBTcl_TraceVar\fR indicates when the +trace procedure is to be invoked and provides information +for setting up the trace. It consists of an OR-ed combination +of any of the following values: +.TP +\fBTCL_GLOBAL_ONLY\fR +Normally, the variable will be looked up at the current level of +procedure call; if this bit is set then the variable will be looked +up at global level, ignoring any active procedures. +.TP +\fBTCL_TRACE_READS\fR +Invoke \fIproc\fR whenever an attempt is made to read the variable. +.TP +\fBTCL_TRACE_WRITES\fR +Invoke \fIproc\fR whenever an attempt is made to modify the variable. +.TP +\fBTCL_TRACE_UNSETS\fR +Invoke \fIproc\fR whenever the variable is unset. +A variable may be unset either explicitly by an \fBunset\fR command, +or implicitly when a procedure returns (its local variables are +automatically unset) or when the interpreter is deleted (all +variables are automatically unset). +.PP +Whenever one of the specified operations occurs on the variable, +\fIproc\fR will be invoked. +It should have arguments and result that match the type +\fBTcl_VarTraceProc\fR: +.nf +.RS +typedef char *Tcl_VarTraceProc( +.RS +ClientData \fIclientData\fR, +Tcl_Interp *\fIinterp\fR, +char *\fIname1\fR, +char *\fIname2\fR, +int \fIflags\fR); +.RE +.RE +.fi +The \fIclientData\fP and \fIinterp\fP parameters will +have the same values as those passed to \fBTcl_TraceVar\fR when the +trace was created. +\fIClientData\fR typically points to an application-specific +data structure that describes what to do when \fIproc\fR +is invoked. +\fIName1\fR and \fIname2\fR give the name of the traced variable +in the normal two-part form (see the description of \fBTcl_TraceVar2\fR +below for details). +\fIFlags\fR is an OR-ed combination of bits providing several +pieces of information. +One of the bits TCL_TRACE_READS, TCL_TRACE_WRITES, or TCL_TRACE_UNSETS +will be set in \fIflags\fR to indicate which operation is being performed +on the variable. +The bit TCL_GLOBAL_ONLY will be set whenever the variable being +accessed is a global one not accessible from the current level of +procedure call: the trace procedure will need to pass this flag +back to variable-related procedures like \fBTcl_GetVar\fR if it +attempts to access the variable. +The bit TCL_TRACE_DESTROYED will be set in \fIflags\fR if the trace is +about to be destroyed; this information may be useful to \fIproc\fR +so that it can clean up its own internal data structures (see +the section TCL_TRACE_DESTROYED below for more details). +Lastly, the bit TCL_INTERP_DESTROYED will be set if the entire +interpreter is being destroyed. +When this bit is set, \fIproc\fR must be especially careful in +the things it does (see the section TCL_INTERP_DESTROYED below). +The trace procedure's return value should normally be NULL; see +ERROR RETURNS below for information on other possibilities. +.PP +\fBTcl_UntraceVar\fR may be used to remove a trace. +If the variable specified by \fIinterp\fR, \fIvarName\fR, and \fIflags\fR +has a trace set with \fIflags\fR, \fIproc\fR, and +\fIclientData\fR, then the corresponding trace is removed. +If no such trace exists, then the call to \fBTcl_UntraceVar\fR +has no effect. +The same bits are valid for \fIflags\fR as for calls to \fBTcl_TraceVars\fR. +.PP +\fBTcl_VarTraceInfo\fR may be used to retrieve information about +traces set on a given variable. +The return value from \fBTcl_VarTraceInfo\fR is the \fIclientData\fR +associated with a particular trace. +The trace must be on the variable specified by the \fIinterp\fR, +\fIvarName\fR, and \fIflags\fR arguments (only the TCL_GLOBAL_ONLY +bit from \fIflags\fR is used; other bits are ignored) and its trace procedure +must the same as the \fIproc\fR argument. +If the \fIprevClientData\fR argument is NULL then the return +value corresponds to the first (most recently created) matching +trace, or NULL if there are no matching traces. +If the \fIprevClientData\fR argument isn't NULL, then it should +be the return value from a previous call to \fBTcl_VarTraceInfo\fR. +In this case, the new return value will correspond to the next +matching trace after the one whose \fIclientData\fR matches +\fIprevClientData\fR, or NULL if no trace matches \fIprevClientData\fR +or if there are no more matching traces after it. +This mechanism makes it possible to step through all of the +traces for a given variable that have the same \fIproc\fR. + +.SH "TWO-PART NAMES" +.PP +The procedures \fBTcl_TraceVar2\fR, \fBTcl_UntraceVar2\fR, and +\fBTcl_VarTraceInfo2\fR are identical to \fBTcl_TraceVar\fR, +\fBTcl_UntraceVar\fR, and \fBTcl_VarTraceInfo\fR, respectively, +except that the name of the variable has already been +separated by the caller into two parts. +\fIName1\fR gives the name of a scalar variable or array, +and \fIname2\fR gives the name of an element within an +array. +If \fIname2\fR is NULL it means that either the variable is +a scalar or the trace is to be set on the entire array rather +than an individual element (see WHOLE-ARRAY TRACES below for +more information). + +.SH "ACCESSING VARIABLES DURING TRACES" +.PP +During read and write traces, the +trace procedure can read or write the value of the traced +variable using \fBTcl_GetVar2\fR, \fBTcl_SetVar2\fR, and +other procedures. +While \fIproc\fR is executing, traces are temporarily disabled +for the variable, so that calls to \fBTcl_GetVar2\fR and +\fBTcl_SetVar2\fR will not cause \fIproc\fR or other trace procedures +to be invoked again. +Disabling only occurs for the variable whose trace procedure +is active; accesses to other variables will still be traced. +.PP +During unset traces the variable has already been completely +expunged. +It is possible for the trace procedure to read or write the +variable, but this will be a new version of the variable. +Traces are not disabled during unset traces as they are for +read and write traces, but existing traces have been removed +from the variable before any trace procedures are invoked. +If new traces are set by unset trace procedures, these traces +will be invoked on accesses to the variable by the trace +procedures. + +.SH "CALLBACK TIMING" +.PP +When read tracing has been specified for a variable, the trace +procedure will be invoked whenever the variable's value is +read. This includes \fBset\fR Tcl commands, \fB$\fR-notation +in Tcl commands, and invocations of the \fBTcl_GetVar\fR +and \fBTcl_GetVar2\fR procedures. +\fIProc\fR is invoked just before the variable's value is +returned. +It may modify the value of the variable to affect what +is returned by the traced access. +.PP +When write tracing has been specified for a variable, the +trace procedure will be invoked whenever the variable's value +is modified. This includes \fBset\fR commands\fR, +commands that modify variables as side effects (such as +\fBcatch\fR and \fBscan\fR), and calls to the \fBTcl_SetVar\fR +and \fBTcl_SetVar2\fR procedures). +\fIProc\fR will be invoked after the variable's value has been +modified, but before the new value of the variable has been +returned. +It may modify the value of the variable to override the change +and to determine the value actually returned by the traced +access. +.PP +When unset tracing has been specified, the trace procedure +will be invoked whenever the variable is destroyed. +The traces will be called after the variable has been +completely unset. + +.SH "WHOLE-ARRAY TRACES" +.PP +If a call to \fBTcl_TraceVar\fR or \fBTcl_TraceVar2\fR specifies +the name of an array variable without an index into the array, +then the trace will be set on the array as a whole. +This means that \fIproc\fR will be invoked whenever any +element of the array is accessed in the ways specified by +\fIflags\fR. +When an array is unset, a whole-array trace will be invoked +just once, with \fIname1\fR equal to the name of the array +and \fIname2\fR NULL; it will not be invoked once for each +element. + +.SH "MULTIPLE TRACES" +.PP +It is possible for multiple traces to exist on the same variable. +When this happens, all of the trace procedures will be invoked on each +access, in order from most-recently-created to least-recently-created. +When there exist whole-array traces for an array as well as +traces on individual elements, the whole-array traces are invoked +before the individual-element traces. + +.SH "ERROR RETURNS" +.PP +Under normal conditions trace procedures should return NULL, indicating +successful completion. +If \fIproc\fR returns a non-NULL value it signifies that an +error occurred. +The return value must be a pointer to a static character string +containing an error message. +If a trace procedure returns an error, no further traces are +invoked for the access and the traced access aborts with the +given message. +Trace procedures can use this facility to make variables +read-only, for example (but note that the value of the variable +will already have been modified before the trace procedure is +called, so the trace procedure will have to restore the correct +value). +.PP +The return value from \fIproc\fR is only used during read and +write tracing. +During unset traces, the return value is ignored and all relevant +trace procedures will always be invoked. + +.SH "RESTRICTIONS" +.PP +It is not legal to delete a variable while a trace procedure +is active for the variable. +.PP +.VS +Also, a trace procedure can be called at any time, even when there +is a partically-formed result in the interpreter's result area. If +the trace procedure does anything that could damage this result (such +as calling \fBTcl_Eval\fR) then it must save the original values of +the interpreter's \fBresult\fR and \fBfreeProc\fR fields and restore +them before it returns. +.VE + +.SH "UNDEFINED VARIABLES" +.PP +It is legal to set a trace on an undefined variable. +The variable will still appear to be undefined until the +first time its value is set. +If an undefined variable is traced and then unset, the unset will fail +with an error (``no such variable''), but the trace +procedure will still be invoked. + +.SH "TCL_TRACE_DELETED FLAG" +.PP +In an unset callback to \fIproc\fR, the TCL_TRACE_DELETED bit +is set in \fIflags\fR if the trace is being removed as part +of the deletion. +Traces on a variable are always removed whenever the variable +is deleted; the only time TCL_TRACE_DELETED isn't set is for +a whole-array trace invoked when only a single element of an +array is unset. + +.SH "TCL_INTERP_DESTROYED" +.PP +When an interpreter is destroyed, unset traces are called for +all of its variables. +The TCL_INTERP_DESTROYED bit will be set in the \fIflags\fR +argument passed to the trace procedures. +Trace procedures must be extremely careful in what they do if +the TCL_INTERP_DESTROYED bit is set. +It is not safe for the procedures to invoke any Tcl procedures +on the interpreter, since its state is partially deleted. +All that trace procedures should do under these circumstances is +to clean up and free their own internal data structures. + +.SH BUGS +.PP +Tcl doesn't do any error checking to prevent trace procedures +from misusing the interpreter during traces with TCL_INTERP_DESTROYED +set. + +.SH KEYWORDS +clientData, trace, variable +.VE diff --git a/src/libtcl/doc/library.n b/src/libtcl/doc/library.n new file mode 100644 index 0000000..f538c19 --- /dev/null +++ b/src/libtcl/doc/library.n @@ -0,0 +1,228 @@ +'\" +'\" Copyright 1991-1992 Regents of the University of California +'\" Permission to use, copy, modify, and distribute this +'\" documentation for any purpose and without fee is hereby +'\" granted, provided that this notice appears in all copies. +'\" The University of California makes no representations about +'\" the suitability of this material for any purpose. It is +'\" provided "as is" without express or implied warranty. +'\" +'\" $Header: /cvsroot/PROCPLACE/pptinytcl/doc/library.n,v 1.1.1.1 2001/04/20 15:03:06 karl Exp $ SPRITE (Berkeley) +' +.so man.macros +.de UL +\\$1\l'|0\(ul'\\$2 +.. +.HS library tcl +.BS +.SH NAME +library \- standard library of Tcl procedures +.SH SYNOPSIS +.nf +\fBauto_execok \fIcmd\fR +\fBauto_load \fIcmd\fR +\fBauto_mkindex \fIdir pattern\fR +\fBauto_reset\fR +\fBparray \fIarrayName\fR +\fBunknown \fIcmd \fR?\fIarg arg ...\fR? +.fi +.BE + +.SH INTRODUCTION +.PP +Tcl includes a library of Tcl procedures for commonly-needed functions. +The procedures defined in the Tcl library are generic ones suitable +for use by many different applications. +The location of the Tcl library is returned by the \fBinfo library\fR +command. +In addition to the Tcl library, each application will normally have +its own library of support procedures as well; the location of this +.VS +library is normally given by the value of the \fB$\fIapp\fB_library\fR +global variable, where \fIapp\fR is the name of the application. +For example, the location of the Tk library is kept in the variable +\fB$tk_library\fR. +.VE +.PP +To access the procedures in the Tcl library, an application should +source the file \fBinit.tcl\fR in the library, for example with +the Tcl command +.DS +\fBsource [info library]/init.tcl +.DE +This will define the \fBunknown\fR procedure and arrange for the +other procedures to be loaded on-demand using the auto-load +mechanism defined below. + +.SH "COMMAND PROCEDURES" +.PP +The following procedures are provided in the Tcl library: +.TP +\fBauto_execok \fIcmd\fR +Determines whether there is an executable file by the name \fIcmd\fR. +This command examines the directories in the current search path +(given by the PATH enviornment variable) to see if there is an +executable file named \fIcmd\fR in any of those directories. +If so, it returns 1; if not it returns 0. \fBAuto_exec\fR +remembers information about previous searches in an array +named \fBauto_execs\fR; this avoids the path search in +future calls for the same \fIcmd\fR. The command \fBauto_reset\fR +may be used to force \fBauto_execok\fR to forget its cached +information. +.TP +\fBauto_load \fIcmd\fR +This command attempts to load the definition for a Tcl procedure named +\fIcmd\fR. +To do this, it searches an \fIauto-load path\fR, which is a list of +one or more directories. +The auto-load path is given by the global variable \fB$auto_path\fR +if it exists. +If there is no \fB$auto_path\fR variable, then the TCLLIBPATH environment +variable is used, if it exists. +Otherwise the auto-load path consists of just the Tcl library directory. +Within each directory in the auto-load path there must be a file +\fBtclIndex\fR that describes the procedures defined in that directory +and the file in which each procedure is defined. The \fBtclIndex\fR +file should be generated with the \fBauto_mkindex\fR command. +If \fIcmd\fR is found in an index file, then the appropriate +script is \fBsource\fRd to create the procedure. +The \fBauto_load\fR command returns 1 if the script was successfully +sourced and \fIcmd\fR now exists. +The command returns 0 if there was no index entry for \fIcmd\fR +or if the script didn't actually define \fIcmd\fR (e.g. because +index information is out of date). +If an error occurs while processing the script, then that error +is returned. +\fBAuto_load\fR only reads the index information once and saves it +in the array \fBauto_index\fR; future calls to \fBauto_load\fR +check for \fIcmd\fR in the array rather than re-reading the index +files. +The cached index information may be deleted with the command +\fBauto_reset\fR. +This will force the next \fBauto_load\fR command to reload the +index database from disk. +.TP +\fBauto_mkindex \fIdir pattern\fR +Generates an index suitable for use by \fBauto_load\fR. +The command searches \fIdir\fR for all files whose names match +\fIpattern\fR (matching is done with the \fBglob\fR command), +generates an index of all the Tcl command +procedures defined in all the matching files, and stores the +index information in a file named \fBtclIndex\fR in \fIdir\fR. +For example, the command +.RS +.DS +\fBauto_mkindex foo *.tcl\fR +.DE +.LP +will read all the \fB.tcl\fR files in subdirectory \fBfoo\fR +and generate a new index file \fBfoo/tclIndex\fR. +.PP +\fBAuto_mkindex\fR parses the Tcl scripts in a relatively +unsophisticated way: if any line contains the word \fBproc\fR +as its first characters then it is assumed to be a procedure +definition and the next word of the line is taken as the +procedure's name. +Procedure definitions that don't appear in this way (e.g. they +have spaces before the \fBproc\fR) will not be indexed. +.RE +.TP +\fBauto_reset\fR +Destroys all the information cached by \fBauto_execok\fR and +\fBauto_load\fR. +This information will be re-read from disk the next time it is +needed. +.VS +\fBAuto_reset\fR also deletes any procedures listed in the auto-load +index, so that fresh copies of them will be loaded the next time +that they're used. +.VE +.TP +\fBparray \fIarrayName\fR +Prints on standard output the names and values of all the elements +in the array \fIarrayName\fR. +.VS +\fBArrayName\fR must be an array accessible to the caller of \fBparray\fR. +It may be either local or global. +.VE +.TP +\fBunknown \fIcmd \fR?\fIarg arg ...\fR? +This procedure is invoked automatically by the Tcl interpreter +whenever the name of a command doesn't exist. +The \fBunknown\fR procedure receives as its arguments the +name and arguments of the missing command. +\fBUnknown\fR first calls \fBauto_load\fR to load a procedure for +the command. +If this succeeds, then it executes the original command with its +original arguments. +If the auto-load fails then \fBunknown\fR calls \fBauto_execok\fR +to see if there is an executable file by the name \fIcmd\fR. +If so, it invokes the Tcl \fBexec\fR command +with \fIcmd\fR and all the \fIargs\fR as arguments. +If \fIcmd\fR can't be auto-executed, \fBunknown\fR checks to +see if the command was invoked at top-level and outside of any +script. If so, then \fBunknown\fR takes takes two additional steps. +First, it sees if \fIcmd\fR has one of the following three forms: +\fB!!\fR, \fB!\fIevent\fR, or \fB^\fIold\fB^\fInew\fR?\fB^\fR?. +If so, then \fBunknown\fR carries out history substitution +in the same way that \fBcsh\fR would for these constructs. +Second, and last, \fBunknown\fR checks to see if \fIcmd\fR is +a unique abbreviation for an existing Tcl command. +If so, it expands the command name and executes the command with +the original arguments. +If none of the above efforts has been able to execute +the command, \fBunknown\fR generates an error return. +If the global variable \fBauto_noload\fR is defined, then the auto-load +step is skipped. +If the global variable \fBauto_noexec\fR is defined then the +auto-exec step is skipped. +Under normal circumstances the return value from \fBunknown\fR +is the return value from the command that was eventually +executed. + +.SH "VARIABLES" +.PP +The following global variables are defined or used by the procedures in +the Tcl library: +.TP +\fBauto_execs\fR +Used by \fBauto_execok\fR to record information about whether +particular commands exist as executable files. +.TP +\fBauto_index\fR +Used by \fBauto_load\fR to save the index information read from +disk. +.TP +\fBauto_noexec\fR +If set to any value, then \fBunknown\fR will not attempt to auto-exec +any commands. +.TP +\fBauto_noload\fR +If set to any value, then \fBunknown\fR will not attempt to auto-load +any commands. +.TP +\fBauto_path\fR +If set, then it must contain a valid Tcl list giving directories to +search during auto-load operations. +.TP +\fBenv(TCL_LIBRARY)\fR +.VS +If set, then it specifies the location of the directory containing +library scripts (the value of this variable will be returned by +the command \fBinfo library\fR). If this variable isn't set then +a default value is used. +.VE +.TP +\fBenv(TCLLIBPATH)\fR +If set, then it must contain a valid Tcl list giving directories to +search during auto-load operations. +This variable is only used if \fBauto_path\fR is not defined. +.TP +\fBunknown_active\fR +This variable is set by \fBunknown\fR to indicate that it is active. +It is used to detect errors where \fBunknown\fR recurses on itself +infinitely. +The variable is unset before \fBunknown\fR returns. + +.SH KEYWORDS +auto-exec, auto-load, library, unknown diff --git a/src/libtcl/doc/man.macros b/src/libtcl/doc/man.macros new file mode 100644 index 0000000..ec45668 --- /dev/null +++ b/src/libtcl/doc/man.macros @@ -0,0 +1,176 @@ +.\" The definitions below are for supplemental macros used in Tcl/Tk +.\" manual entries. +.\" +.\" .HS name section [date [version]] +.\" Replacement for .TH in other man pages. See below for valid +.\" section names. +.\" +.\" .AP type name in/out [indent] +.\" Start paragraph describing an argument to a library procedure. +.\" type is type of argument (int, etc.), in/out is either "in", "out", +.\" or "in/out" to describe whether procedure reads or modifies arg, +.\" and indent is equivalent to second arg of .IP (shouldn't ever be +.\" needed; use .AS below instead) +.\" +.\" .AS [type [name]] +.\" Give maximum sizes of arguments for setting tab stops. Type and +.\" name are examples of largest possible arguments that will be passed +.\" to .AP later. If args are omitted, default tab stops are used. +.\" +.\" .BS +.\" Start box enclosure. From here until next .BE, everything will be +.\" enclosed in one large box. +.\" +.\" .BE +.\" End of box enclosure. +.\" +.\" .VS +.\" Begin vertical sidebar, for use in marking newly-changed parts +.\" of man pages. +.\" +.\" .VE +.\" End of vertical sidebar. +.\" +.\" .DS +.\" Begin an indented unfilled display. +.\" +.\" .DE +.\" End of indented unfilled display. +.\" +'\" # Heading for Tcl/Tk man pages +.de HS +.if '\\$2'cmds' .TH \\$1 1 \\$3 \\$4 +.if '\\$2'lib' .TH \\$1 3 \\$3 \\$4 +.if '\\$2'tcl' .TH \\$1 3 \\$3 \\$4 +.if '\\$2'tk' .TH \\$1 3 \\$3 \\$4 +.if t .wh -1.3i ^B +.nr ^l \\n(.l +.ad b +.. +'\" # Start an argument description +.de AP +.ie !"\\$4"" .TP \\$4 +.el \{\ +. ie !"\\$2"" .TP \\n()Cu +. el .TP 15 +.\} +.ie !"\\$3"" \{\ +.ta \\n()Au \\n()Bu +\&\\$1 \\fI\\$2\\fP (\\$3) +.\".b +.\} +.el \{\ +.br +.ie !"\\$2"" \{\ +\&\\$1 \\fI\\$2\\fP +.\} +.el \{\ +\&\\fI\\$1\\fP +.\} +.\} +.. +'\" # define tabbing values for .AP +.de AS +.nr )A 10n +.if !"\\$1"" .nr )A \\w'\\$1'u+3n +.nr )B \\n()Au+15n +.\" +.if !"\\$2"" .nr )B \\w'\\$2'u+\\n()Au+3n +.nr )C \\n()Bu+\\w'(in/out)'u+2n +.. +'\" # BS - start boxed text +'\" # ^y = starting y location +'\" # ^b = 1 +.de BS +.br +.mk ^y +.nr ^b 1u +.if n .nf +.if n .ti 0 +.if n \l'\\n(.lu\(ul' +.if n .fi +.. +'\" # BE - end boxed text (draw box now) +.de BE +.nf +.ti 0 +.mk ^t +.ie n \l'\\n(^lu\(ul' +.el \{\ +.\" Draw four-sided box normally, but don't draw top of +.\" box if the box started on an earlier page. +.ie !\\n(^b-1 \{\ +\h'-1.5n'\L'|\\n(^yu-1v'\l'\\n(^lu+3n\(ul'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul' +.\} +.el \}\ +\h'-1.5n'\L'|\\n(^yu-1v'\h'\\n(^lu+3n'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul' +.\} +.\} +.fi +.br +.nr ^b 0 +.. +'\" # VS - start vertical sidebar +'\" # ^Y = starting y location +'\" # ^v = 1 (for troff; for nroff this doesn't matter) +.de VS +.mk ^Y +.ie n 'mc \s12\(br\s0 +.el .nr ^v 1u +.. +'\" # VE - end of vertical sidebar +.de VE +.ie n 'mc +.el \{\ +.ev 2 +.nf +.ti 0 +.mk ^t +\h'|\\n(^lu+3n'\L'|\\n(^Yu-1v\(bv'\v'\\n(^tu+1v-\\n(^Yu'\h'-|\\n(^lu+3n' +.sp -1 +.fi +.ev +.\} +.nr ^v 0 +.. +'\" # Special macro to handle page bottom: finish off current +'\" # box/sidebar if in box/sidebar mode, then invoked standard +'\" # page bottom macro. +.de ^B +.ev 2 +'ti 0 +'nf +.mk ^t +.if \\n(^b \{\ +.\" Draw three-sided box if this is the box's first page, +.\" draw two sides but no top otherwise. +.ie !\\n(^b-1 \h'-1.5n'\L'|\\n(^yu-1v'\l'\\n(^lu+3n\(ul'\L'\\n(^tu+1v-\\n(^yu'\h'|0u'\c +.el \h'-1.5n'\L'|\\n(^yu-1v'\h'\\n(^lu+3n'\L'\\n(^tu+1v-\\n(^yu'\h'|0u'\c +.\} +.if \\n(^v \{\ +.nr ^x \\n(^tu+1v-\\n(^Yu +\kx\h'-\\nxu'\h'|\\n(^lu+3n'\ky\L'-\\n(^xu'\v'\\n(^xu'\h'|0u'\c +.\} +.bp +'fi +.ev +.if \\n(^b \{\ +.mk ^y +.nr ^b 2 +.\} +.if \\n(^v \{\ +.mk ^Y +.\} +.. +'\" # DS - begin display +.de DS +.RS +.nf +.sp +.. +'\" # DE - end display +.de DE +.fi +.RE +.sp .5 +.. diff --git a/src/libtcl/hash.h b/src/libtcl/hash.h new file mode 100644 index 0000000..6181f87 --- /dev/null +++ b/src/libtcl/hash.h @@ -0,0 +1,125 @@ +/* + * tclHash.h -- + * + * This header file declares the facilities provided by the + * Tcl hash table procedures. + * + * Copyright 1991 Regents of the University of California + * 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. The University of California + * makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without + * express or implied warranty. + */ + +/* + * Structure definition for an entry in a hash table. No-one outside + * Tcl should access any of these fields directly; use the macros + * defined below. + */ +typedef struct Tcl_HashEntry { + struct Tcl_HashEntry *nextPtr; /* Pointer to next entry in this + * hash bucket, or NULL for end of + * chain. */ + struct Tcl_HashTable *tablePtr; /* Pointer to table containing entry. */ + struct Tcl_HashEntry **bucketPtr; /* Pointer to bucket that points to + * first entry in this entry's chain: + * used for deleting the entry. */ + void *clientData; /* Application stores something here + * with Tcl_SetHashValue. */ + union { /* Key has one of these forms: */ + unsigned char *oneWordValue; /* One-word value for key. */ + int words[1]; /* Multiple integer words for key. + * The actual size will be as large + * as necessary for this table's + * keys. */ + unsigned char string[4]; /* String for key. The actual size + * will be as large as needed to hold + * the key. */ + } key; /* MUST BE LAST FIELD IN RECORD!! */ +} Tcl_HashEntry; + +/* + * Structure definition for a hash table. Must be in tcl.h so clients + * can allocate space for these structures, but clients should never + * access any fields in this structure. + */ +#define TCL_SMALL_HASH_TABLE 4 + +typedef struct Tcl_HashTable { + Tcl_HashEntry **buckets; /* Pointer to bucket array. Each + * element points to first entry in + * bucket's hash chain, or NULL. */ + Tcl_HashEntry *staticBuckets[TCL_SMALL_HASH_TABLE]; + /* Bucket array used for small tables + * (to avoid mallocs and frees). */ + int numBuckets; /* Total number of buckets allocated + * at **bucketPtr. */ + int numEntries; /* Total number of entries present + * in table. */ + int rebuildSize; /* Enlarge table when numEntries gets + * to be this large. */ + int downShift; /* Shift count used in hashing + * function. Designed to use high- + * order bits of randomized keys. */ + int mask; /* Mask value used in hashing + * function. */ + int keyType; /* Type of keys used in this table. + * It's either TCL_STRING_KEYS, + * TCL_ONE_WORD_KEYS, or an integer + * giving the number of ints in a + */ + Tcl_HashEntry *(*findProc) (struct Tcl_HashTable *tablePtr, unsigned char *key); + Tcl_HashEntry *(*createProc) (struct Tcl_HashTable *tablePtr, + unsigned char *key, int *newPtr); +} Tcl_HashTable; + +/* + * Structure definition for information used to keep track of searches + * through hash tables: + */ +typedef struct Tcl_HashSearch { + Tcl_HashTable *tablePtr; /* Table being searched. */ + int nextIndex; /* Index of next bucket to be + * enumerated after present one. */ + Tcl_HashEntry *nextEntryPtr; /* Next entry to be enumerated in the + * the current bucket. */ +} Tcl_HashSearch; + +/* + * Acceptable key types for hash tables: + */ +#define TCL_STRING_KEYS 0 +#define TCL_ONE_WORD_KEYS 1 + +/* + * Macros for clients to use to access fields of hash entries: + */ +#define Tcl_GetHashValue(h) ((h)->clientData) +#define Tcl_SetHashValue(h, value) ((h)->clientData = (void*) (value)) +#define Tcl_GetHashKey(tablePtr, h) \ + (((tablePtr)->keyType == TCL_ONE_WORD_KEYS) ? (h)->key.oneWordValue \ + : (h)->key.string) + +/* + * Macros to use for clients to use to invoke find and create procedures + * for hash tables: + */ +#define Tcl_FindHashEntry(tablePtr, key) \ + (*((tablePtr)->findProc))(tablePtr, key) +#define Tcl_CreateHashEntry(tablePtr, key, newPtr) \ + (*((tablePtr)->createProc))(tablePtr, key, newPtr) + +/* + * Exported procedures: + */ +extern void Tcl_DeleteHashEntry (Tcl_HashEntry *entryPtr); +extern void Tcl_DeleteHashTable (Tcl_HashTable *tablePtr); +extern Tcl_HashEntry * Tcl_FirstHashEntry (Tcl_HashTable *tablePtr, + Tcl_HashSearch *searchPtr); +extern unsigned char * Tcl_HashStats (Tcl_HashTable *tablePtr); +extern void Tcl_InitHashTable (Tcl_HashTable *tablePtr, + int keyType); +extern Tcl_HashEntry * Tcl_NextHashEntry (Tcl_HashSearch *searchPtr); diff --git a/src/libtcl/internal.h b/src/libtcl/internal.h new file mode 100644 index 0000000..1aba810 --- /dev/null +++ b/src/libtcl/internal.h @@ -0,0 +1,689 @@ +/* + * tclInt.h -- + * + * Declarations of things used internally by the Tcl interpreter. + * + * Copyright 1987-1991 Regents of the University of California + * 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. The University of California + * makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without + * express or implied warranty. + */ + +/* + * Common include files needed by most of the Tcl source files are + * included here, so that system-dependent personalizations for the + * include files only have to be made in once place. + */ +#ifdef CROSS +# include +# include +#else +# include +# include +#endif +#include +#include +#include +#include "hash.h" + +/* + *---------------------------------------------------------------- + * Data structures related to variables. These are used primarily + * in tclVar.c + *---------------------------------------------------------------- + */ + +/* + * The following structure defines a variable trace, which is used to + * invoke a specific C procedure whenever certain operations are performed + * on a variable. + */ +typedef struct VarTrace { + Tcl_VarTraceProc *traceProc;/* Procedure to call when operations given + * by flags are performed on variable. */ + void *clientData; /* Argument to pass to proc. */ + unsigned char flags; /* What events the trace procedure is + * interested in: OR-ed combination of + * TCL_TRACE_READS, TCL_TRACE_WRITES, and + * TCL_TRACE_UNSETS. */ + struct VarTrace *nextPtr; /* Next in list of traces associated with + * a particular variable. */ +} VarTrace; + +/* + * When a variable trace is active (i.e. its associated procedure is + * executing), one of the following structures is linked into a list + * associated with the variable's interpreter. The information in + * the structure is needed in order for Tcl to behave reasonably + * if traces are deleted while traces are active. + */ +typedef struct ActiveVarTrace { + struct ActiveVarTrace *nextPtr; + /* Next in list of all active variable + * traces for the interpreter, or NULL + * if no more. */ + VarTrace *nextTracePtr; /* Next trace to check after current + * trace procedure returns; if this + * trace gets deleted, must update pointer + * to avoid using free'd memory. */ +} ActiveVarTrace; + +/* + * The following structure describes an enumerative search in progress on + * an array variable; this are invoked with options to the "array" + * command. + */ +typedef struct ArraySearch { + unsigned short id; /* Integer id used to distinguish among + * multiple concurrent searches for the + * same array. */ + struct Var *varPtr; /* Pointer to array variable that's being + * searched. */ + Tcl_HashSearch search; /* Info kept by the hash module about + * progress through the array. */ + Tcl_HashEntry *nextEntry; /* Non-null means this is the next element + * to be enumerated (it's leftover from + * the Tcl_FirstHashEntry call or from + * an "array anymore" command). NULL + * means must call Tcl_NextHashEntry + * to get value to return. */ + struct ArraySearch *nextPtr;/* Next in list of all active searches + * for this variable, or NULL if this is + * the last one. */ +} ArraySearch; + +/* + * The structure below defines a variable, which associates a string name + * with a string value. Pointers to these structures are kept as the + * values of hash table entries, and the name of each variable is stored + * in the hash entry. + */ +typedef struct Var { + unsigned short valueLength; /* Holds the number of non-null bytes + * actually occupied by the variable's + * current value in value.string (extra + * space is sometimes left for expansion). + * For array and global variables this is + * meaningless. */ + unsigned short valueSpace; /* Total number of bytes of space allocated + * at value. */ + unsigned short upvarUses; /* Counts number of times variable is + * is referenced via global or upvar variables + * (i.e. how many variables have "upvarPtr" + * pointing to this variable). Variable + * can't be deleted until this count reaches + * 0. */ + VarTrace *tracePtr; /* First in list of all traces set for this + * variable. */ + ArraySearch *searchPtr; /* First in list of all searches active + * for this variable, or NULL if none. */ + unsigned char flags; /* Miscellaneous bits of information about + * variable. See below for definitions. */ + union { + unsigned char string[4]; /* String value of variable. The actual + * length of this field is given by the + * valueSpace field above. */ + Tcl_HashTable *tablePtr;/* For array variables, this points to + * information about the hash table used + * to implement the associative array. + * Points to malloc-ed data. */ + Tcl_HashEntry *upvarPtr; + /* If this is a global variable being + * referred to in a procedure, or a variable + * created by "upvar", this field points to + * the hash table entry for the higher-level + * variable. */ + } value; /* MUST BE LAST FIELD IN STRUCTURE!!! */ +} Var; + +/* + * Flag bits for variables: + * + * VAR_ARRAY - 1 means this is an array variable rather + * than a scalar variable. + * VAR_UPVAR - 1 means this variable just contains a + * pointer to another variable that has the + * real value. Variables like this come + * about through the "upvar" and "global" + * commands. + * VAR_UNDEFINED - 1 means that the variable is currently + * undefined. Undefined variables usually + * go away completely, but if an undefined + * variable has a trace on it, or if it is + * a global variable being used by a procedure, + * then it stays around even when undefined. + * VAR_ELEMENT_ACTIVE - Used only in array variables; 1 means that + * an element of the array is currently being + * manipulated in some way, so that it isn't + * safe to delete the whole array. + * VAR_TRACE_ACTIVE - 1 means that trace processing is currently + * underway for a read or write access, so + * new read or write accesses should not cause + * trace procedures to be called and the + * variable can't be deleted. + */ +#define VAR_ARRAY 1 +#define VAR_UPVAR 2 +#define VAR_UNDEFINED 4 +#define VAR_ELEMENT_ACTIVE 0x10 +#define VAR_TRACE_ACTIVE 0x20 +#define VAR_SEARCHES_POSSIBLE 0x40 + +/* + *---------------------------------------------------------------- + * Data structures related to procedures. These are used primarily + * in tclProc.c + *---------------------------------------------------------------- + */ + +/* + * The structure below defines an argument to a procedure, which + * consists of a name and an (optional) default value. + */ +typedef struct Arg { + struct Arg *nextPtr; /* Next argument for this procedure, + * or NULL if this is the last argument. */ + unsigned char *defValue; /* Pointer to arg's default value, or NULL + * if no default value. */ + unsigned char name[4]; /* Name of argument starts here. The name + * is followed by space for the default, + * if there is one. The actual size of this + * field will be as large as necessary to + * hold both name and default value. THIS + * MUST BE THE LAST FIELD IN THE STRUCTURE!! */ +} Arg; + +/* + * The structure below defines a command procedure, which consists of + * a collection of Tcl commands plus information about arguments and + * variables. + */ +typedef struct Proc { + struct Interp *iPtr; /* Interpreter for which this command + * is defined. */ + unsigned char *command; /* Command that constitutes the body of + * the procedure (dynamically allocated). */ + Arg *argPtr; /* Pointer to first of procedure's formal + * arguments, or NULL if none. */ +} Proc; + +/* + * The structure below defines a command trace. This is used to allow Tcl + * clients to find out whenever a command is about to be executed. + */ +typedef struct Trace { + unsigned short level; /* Only trace commands at nesting level + * less than or equal to this. */ + Tcl_CmdTraceProc *proc; /* Procedure to call to trace command. */ + void *clientData; /* Arbitrary value to pass to proc. */ + struct Trace *nextPtr; /* Next in list of traces for this interp. */ +} Trace; + +/* + * The structure below defines a frame, which is a procedure invocation. + * These structures exist only while procedures are being executed, and + * provide a sort of call stack. + */ +typedef struct CallFrame { + Tcl_HashTable varTable; /* Hash table containing all of procedure's + * local variables. */ + unsigned short level; /* Level of this procedure, for "uplevel" + * purposes (i.e. corresponds to nesting of + * callerVarPtr's, not callerPtr's). 1 means + * outer-most procedure, 0 means top-level. */ + int argc; /* This and argv below describe name and + * arguments for this procedure invocation. */ + unsigned char **argv; /* Array of arguments. */ + struct CallFrame *callerPtr; + /* Value of interp->framePtr when this + * procedure was invoked (i.e. next in + * stack of all active procedures). */ + struct CallFrame *callerVarPtr; + /* Value of interp->varFramePtr when this + * procedure was invoked (i.e. determines + * variable scoping within caller; same + * as callerPtr unless an "uplevel" command + * or something equivalent was active in + * the caller). */ +} CallFrame; + +/* + * The structure below defines one history event (a previously-executed + * command that can be re-executed in whole or in part). + */ +typedef struct { + unsigned char *command; /* String containing previously-executed + * command. */ + unsigned short bytesAvl; /* Total # of bytes available at *event (not + * all are necessarily in use now). */ +} HistoryEvent; + +/* + *---------------------------------------------------------------- + * Data structures related to history. These are used primarily + * in tclHistory.c + *---------------------------------------------------------------- + */ + +/* + * The structure below defines a pending revision to the most recent + * history event. Changes are linked together into a list and applied + * during the next call to Tcl_RecordHistory. See the comments at the + * beginning of tclHistory.c for information on revisions. + */ +typedef struct HistoryRev { + unsigned short firstIndex; /* Index of the first byte to replace in + * current history event. */ + unsigned short lastIndex; /* Index of last byte to replace in + * current history event. */ + unsigned short newSize; /* Number of bytes in newBytes. */ + unsigned char *newBytes; /* Replacement for the range given by + * firstIndex and lastIndex. */ + struct HistoryRev *nextPtr; /* Next in chain of revisions to apply, or + * NULL for end of list. */ +} HistoryRev; + +/* + *---------------------------------------------------------------- + * Data structures related to files. These are used primarily in + * tclUnixUtil.c and tclUnixAZ.c. + *---------------------------------------------------------------- + */ + +/* + * The data structure below defines an open file (or connection to + * a process pipeline) as returned by the "open" command. + */ +typedef struct OpenFile { + FILE *f; /* Stdio file to use for reading and/or + * writing. */ + FILE *f2; /* Normally NULL. In the special case of + * a command pipeline with pipes for both + * input and output, this is a stdio file + * to use for writing to the pipeline. */ + int readable; /* Non-zero means file may be read. */ + int writable; /* Non-zero means file may be written. */ + int numPids; /* If this is a connection to a process + * pipeline, gives number of processes + * in pidPtr array below; otherwise it + * is 0. */ + int *pidPtr; /* Pointer to malloc-ed array of child + * process ids (numPids of them), or NULL + * if this isn't a connection to a process + * pipeline. */ + int errorId; /* File id of file that receives error + * output from pipeline. -1 means not + * used (i.e. this is a normal file). */ +} OpenFile; + +/* + *---------------------------------------------------------------- + * This structure defines an interpreter, which is a collection of + * commands plus other state information related to interpreting + * commands, such as variable storage. Primary responsibility for + * this data structure is in tclBasic.c, but almost every Tcl + * source file uses something in here. + *---------------------------------------------------------------- + */ +typedef struct Command { + Tcl_CmdProc *proc; /* Procedure to process command. */ + void *clientData; /* Arbitrary value to pass to proc. */ + Tcl_CmdDeleteProc *deleteProc; + /* Procedure to invoke when deleting + * command. */ +} Command; + +#define CMD_SIZE(nameLength) ((unsigned) sizeof(Command) + nameLength - 3) + +typedef struct Interp { + + /* + * Note: the first four fields must match exactly the fields in + * a Tcl_Interp struct (see tcl.h). If you change one, be sure to + * change the other. + */ + + unsigned char *result; /* Points to result returned by last + * command. */ + Tcl_FreeProc *freeProc; /* Zero means result is statically allocated. + * If non-zero, gives address of procedure + * to invoke to free the result. Must be + * freed by Tcl_Eval before executing next + * command. */ + int errorLine; /* When TCL_ERROR is returned, this gives + * the line number within the command where + * the error occurred (1 means first line). */ + Tcl_HashTable commandTable; /* Contains all of the commands currently + * registered in this interpreter. Indexed + * by strings; values have type (Command *). */ + + /* + * Information related to procedures and variables. See tclProc.c + * and tclvar.c for usage. + */ + + Tcl_HashTable globalTable; /* Contains all global variables for + * interpreter. */ + unsigned short numLevels; /* Keeps track of how many nested calls to + * Tcl_Eval are in progress for this + * interpreter. It's used to delay deletion + * of the table until all Tcl_Eval invocations + * are completed. */ + CallFrame *framePtr; /* Points to top-most in stack of all nested + * procedure invocations. NULL means there + * are no active procedures. */ + CallFrame *varFramePtr; /* Points to the call frame whose variables + * are currently in use (same as framePtr + * unless an "uplevel" command is being + * executed). NULL means no procedure is + * active or "uplevel 0" is being exec'ed. */ + ActiveVarTrace *activeTracePtr; + /* First in list of active traces for interp, + * or NULL if no active traces. */ + + /* + * Information related to history: + */ + unsigned short numEvents; /* Number of previously-executed commands + * to retain. */ + HistoryEvent *events; /* Array containing numEvents entries + * (dynamically allocated). */ + unsigned short curEvent; /* Index into events of place where current + * (or most recent) command is recorded. */ + unsigned short curEventNum; /* Event number associated with the slot + * given by curEvent. */ + HistoryRev *revPtr; /* First in list of pending revisions. */ + unsigned char *historyFirst; /* First char. of current command executed + * from history module or NULL if none. */ + unsigned short revDisables; /* 0 means history revision OK; > 0 gives + * a count of number of times revision has + * been disabled. */ + unsigned char *evalFirst; /* If TCL_RECORD_BOUNDS flag set, Tcl_Eval + * sets this field to point to the first + * char. of text from which the current + * command came. Otherwise Tcl_Eval sets + * this to NULL. */ + unsigned char *evalLast; /* Similar to evalFirst, except points to + * last character of current command. */ + + /* + * Information used by Tcl_AppendResult to keep track of partial + * results. See Tcl_AppendResult code for details. + */ + unsigned char *appendResult; /* Storage space for results generated + * by Tcl_AppendResult. Malloc-ed. NULL + * means not yet allocated. */ + unsigned short appendAvl; /* Total amount of space available at + * partialResult. */ + unsigned short appendUsed; /* Number of non-null bytes currently + * stored at partialResult. */ + + /* + * Information related to files. See tclUnixAZ.c and tclUnixUtil.c + * for details. + */ + unsigned short numFiles; /* Number of entries in filePtrArray + * below. 0 means array hasn't been + * created yet. */ + OpenFile **filePtrArray; /* Pointer to malloc-ed array of pointers + * to information about open files. Entry + * N corresponds to the file with fileno N. + * If an entry is NULL then the corresponding + * file isn't open. If filePtrArray is NULL + * it means no files have been used, so even + * stdin/stdout/stderr entries haven't been + * setup yet. */ + /* + * A cache of compiled regular expressions. See TclCompileRegexp + * in tclUtil.c for details. + */ +#define NUM_REGEXPS 5 + unsigned char *patterns [NUM_REGEXPS]; + /* Strings corresponding to compiled + * regular expression patterns. NULL + * means that this slot isn't used. + * Malloc-ed. */ + unsigned short patLengths [NUM_REGEXPS]; + /* Number of non-null characters in + * corresponding entry in patterns. + * -1 means entry isn't used. */ + struct _regexp_t *regexps [NUM_REGEXPS]; + /* Compiled forms of above strings. Also + * malloc-ed, or NULL if not in use yet. */ + + + /* + * Miscellaneous information: + */ + unsigned long cmdCount; /* Total number of times a command procedure + * has been called for this interpreter. */ + unsigned char *scriptFile; /* NULL means there is no nested source + * command active; otherwise this points to + * the name of the file being sourced (it's + * not malloc-ed: it points to an argument + * to Tcl_EvalFile. */ + unsigned char noEval; /* Non-zero means no commands should actually + * be executed: just parse only. Used in + * expressions when the result is already + * determined. */ + unsigned char flags; /* Various flag bits. See below. */ + Trace *tracePtr; /* List of traces for this interpreter. */ + unsigned char resultSpace [TCL_RESULT_SIZE+1]; + /* Static space for storing small results. */ +} Interp; + +/* + * Flag bits for Interp structures: + * + * DELETED: Non-zero means the interpreter has been deleted: + * don't process any more commands for it, and destroy + * the structure as soon as all nested invocations of + * Tcl_Eval are done. + * ERR_IN_PROGRESS: Non-zero means an error unwind is already in progress. + * Zero means a command proc has been invoked since last + * error occured. + * ERR_ALREADY_LOGGED: Non-zero means information has already been logged + * in $errorInfo for the current Tcl_Eval instance, + * so Tcl_Eval needn't log it (used to implement the + * "error message log" command). + * ERROR_CODE_SET: Non-zero means that Tcl_SetErrorCode has been + * called to record information for the current + * error. Zero means Tcl_Eval must clear the + * errorCode variable if an error is returned. + */ +#define DELETED 1 +#define ERR_IN_PROGRESS 2 +#define ERR_ALREADY_LOGGED 4 +#define ERROR_CODE_SET 8 + +/* + *---------------------------------------------------------------- + * Data structures related to command parsing. These are used in + * tclParse.c and its clients. + *---------------------------------------------------------------- + */ + +/* + * The following data structure is used by various parsing procedures + * to hold information about where to store the results of parsing + * (e.g. the substituted contents of a quoted argument, or the result + * of a nested command). At any given time, the space available + * for output is fixed, but a procedure may be called to expand the + * space available if the current space runs out. + */ +typedef struct ParseValue { + unsigned char *buffer; /* Address of first character in + * output buffer. */ + unsigned char *next; /* Place to store next character in + * output buffer. */ + unsigned char *end; /* Address of the last usable character + * in the buffer. */ + void (*expandProc) (struct ParseValue *pvPtr, unsigned short needed); + /* Procedure to call when space runs out; + * it will make more space. */ + void *clientData; /* Arbitrary information for use of + * expandProc. */ +} ParseValue; + +/* + * Possible values returned by CHAR_TYPE: + * + * TCL_NORMAL - All characters that don't have special significance + * to the Tcl language. + * TCL_SPACE - Character is space, tab, or return. + * TCL_COMMAND_END - Character is newline or null or semicolon or + * close-bracket. + * TCL_QUOTE - Character is a double-quote. + * TCL_OPEN_BRACKET - Character is a "[". + * TCL_OPEN_BRACE - Character is a "{". + * TCL_CLOSE_BRACE - Character is a "}". + * TCL_BACKSLASH - Character is a "\". + * TCL_DOLLAR - Character is a "$". + */ +#define TCL_NORMAL 0 +#define TCL_SPACE 1 +#define TCL_COMMAND_END 2 +#define TCL_QUOTE 3 +#define TCL_OPEN_BRACKET 4 +#define TCL_OPEN_BRACE 5 +#define TCL_CLOSE_BRACE 6 +#define TCL_BACKSLASH 7 +#define TCL_DOLLAR 8 + +/* + * Additional flags passed to Tcl_Eval. See tcl.h for other flags to + * Tcl_Eval; these ones are only used internally by Tcl. + * + * TCL_RECORD_BOUNDS Tells Tcl_Eval to record information in the + * evalFirst and evalLast fields for each command + * executed directly from the string (top-level + * commands and those from command substitution). + */ +#define TCL_RECORD_BOUNDS 0x100 + +/* + * Maximum number of levels of nesting permitted in Tcl commands. + */ +#define MAX_NESTING_DEPTH 100 + +/* + *---------------------------------------------------------------- + * Procedures shared among Tcl modules but not used by the outside + * world: + *---------------------------------------------------------------- + */ +extern struct _regexp_t *TclCompileRegexp (Tcl_Interp *interp, + unsigned char *string); +extern void TclCopyAndCollapse (int count, unsigned char *src, + unsigned char *dst); +extern void TclDeleteVars (Interp *iPtr, + Tcl_HashTable *tablePtr); +extern void TclExpandParseValue (ParseValue *pvPtr, + unsigned short needed); +extern int TclFindElement (Tcl_Interp *interp, + unsigned char *list, unsigned char **elementPtr, + unsigned char **nextPtr, int *sizePtr, int *bracePtr); +extern Proc * TclFindProc (Interp *iPtr, + unsigned char *procName); +extern int TclGetFrame (Tcl_Interp *interp, + unsigned char *string, CallFrame **framePtrPtr); +extern int TclGetListIndex (Tcl_Interp *interp, + unsigned char *string, int *indexPtr); +extern int TclGetOpenFile (Tcl_Interp *interp, + unsigned char *string, OpenFile **filePtrPtr); +extern Proc * TclIsProc (Command *cmdPtr); +extern void TclMakeFileTable (Interp *iPtr, + int index); +extern int TclParseBraces (Tcl_Interp *interp, + unsigned char *string, unsigned char **termPtr, + ParseValue *pvPtr); +extern int TclParseNestedCmd (Tcl_Interp *interp, + unsigned char *string, int flags, unsigned char **termPtr, + ParseValue *pvPtr); +extern int TclParseQuotes (Tcl_Interp *interp, + unsigned char *string, int termChar, int flags, + unsigned char **termPtr, ParseValue *pvPtr); +extern int TclParseWords (Tcl_Interp *interp, + unsigned char *string, int flags, int maxWords, + unsigned char **termPtr, int *argcPtr, unsigned char **argv, + ParseValue *pvPtr); +extern void TclSetupEnv (Tcl_Interp *interp); +extern unsigned char * TclWordEnd (unsigned char *start, int nested); +extern unsigned char * Tcl_UnixError (Tcl_Interp *interp); + +/* + *---------------------------------------------------------------- + * Command procedures in the generic core: + *---------------------------------------------------------------- + */ +extern int Tcl_AppendCmd (void *clientData, Tcl_Interp *interp, int argc, unsigned char **argv); +extern int Tcl_ArrayCmd (void *clientData, Tcl_Interp *interp, int argc, unsigned char **argv); +extern int Tcl_BreakCmd (void *clientData, Tcl_Interp *interp, int argc, unsigned char **argv); +extern int Tcl_CaseCmd (void *clientData, Tcl_Interp *interp, int argc, unsigned char **argv); +extern int Tcl_CatchCmd (void *clientData, Tcl_Interp *interp, int argc, unsigned char **argv); +extern int Tcl_ConcatCmd (void *clientData, Tcl_Interp *interp, int argc, unsigned char **argv); +extern int Tcl_ContinueCmd (void *clientData, Tcl_Interp *interp, int argc, unsigned char **argv); +extern int Tcl_ErrorCmd (void *clientData, Tcl_Interp *interp, int argc, unsigned char **argv); +extern int Tcl_EvalCmd (void *clientData, Tcl_Interp *interp, int argc, unsigned char **argv); +extern int Tcl_ExprCmd (void *clientData, Tcl_Interp *interp, int argc, unsigned char **argv); +extern int Tcl_ForCmd (void *clientData, Tcl_Interp *interp, int argc, unsigned char **argv); +extern int Tcl_ForeachCmd (void *clientData, Tcl_Interp *interp, int argc, unsigned char **argv); +extern int Tcl_FormatCmd (void *clientData, Tcl_Interp *interp, int argc, unsigned char **argv); +extern int Tcl_GlobalCmd (void *clientData, Tcl_Interp *interp, int argc, unsigned char **argv); +extern int Tcl_HistoryCmd (void *clientData, Tcl_Interp *interp, int argc, unsigned char **argv); +extern int Tcl_IfCmd (void *clientData, Tcl_Interp *interp, int argc, unsigned char **argv); +extern int Tcl_IncrCmd (void *clientData, Tcl_Interp *interp, int argc, unsigned char **argv); +extern int Tcl_InfoCmd (void *clientData, Tcl_Interp *interp, int argc, unsigned char **argv); +extern int Tcl_JoinCmd (void *clientData, Tcl_Interp *interp, int argc, unsigned char **argv); +extern int Tcl_LappendCmd (void *clientData, Tcl_Interp *interp, int argc, unsigned char **argv); +extern int Tcl_LindexCmd (void *clientData, Tcl_Interp *interp, int argc, unsigned char **argv); +extern int Tcl_LinsertCmd (void *clientData, Tcl_Interp *interp, int argc, unsigned char **argv); +extern int Tcl_LlengthCmd (void *clientData, Tcl_Interp *interp, int argc, unsigned char **argv); +extern int Tcl_ListCmd (void *clientData, Tcl_Interp *interp, int argc, unsigned char **argv); +extern int Tcl_LrangeCmd (void *clientData, Tcl_Interp *interp, int argc, unsigned char **argv); +extern int Tcl_LreplaceCmd (void *clientData, Tcl_Interp *interp, int argc, unsigned char **argv); +extern int Tcl_LsearchCmd (void *clientData, Tcl_Interp *interp, int argc, unsigned char **argv); +extern int Tcl_LsortCmd (void *clientData, Tcl_Interp *interp, int argc, unsigned char **argv); +extern int Tcl_ProcCmd (void *clientData, Tcl_Interp *interp, int argc, unsigned char **argv); +extern int Tcl_RegexpCmd (void *clientData, Tcl_Interp *interp, int argc, unsigned char **argv); +extern int Tcl_RegsubCmd (void *clientData, Tcl_Interp *interp, int argc, unsigned char **argv); +extern int Tcl_RenameCmd (void *clientData, Tcl_Interp *interp, int argc, unsigned char **argv); +extern int Tcl_ReturnCmd (void *clientData, Tcl_Interp *interp, int argc, unsigned char **argv); +extern int Tcl_ScanCmd (void *clientData, Tcl_Interp *interp, int argc, unsigned char **argv); +extern int Tcl_SetCmd (void *clientData, Tcl_Interp *interp, int argc, unsigned char **argv); +extern int Tcl_SplitCmd (void *clientData, Tcl_Interp *interp, int argc, unsigned char **argv); +extern int Tcl_StringCmd (void *clientData, Tcl_Interp *interp, int argc, unsigned char **argv); +extern int Tcl_TraceCmd (void *clientData, Tcl_Interp *interp, int argc, unsigned char **argv); +extern int Tcl_UnsetCmd (void *clientData, Tcl_Interp *interp, int argc, unsigned char **argv); +extern int Tcl_UplevelCmd (void *clientData, Tcl_Interp *interp, int argc, unsigned char **argv); +extern int Tcl_UpvarCmd (void *clientData, Tcl_Interp *interp, int argc, unsigned char **argv); +extern int Tcl_WhileCmd (void *clientData, Tcl_Interp *interp, int argc, unsigned char **argv); +extern int Tcl_Cmd (void *clientData, Tcl_Interp *interp, int argc, unsigned char **argv); +extern int Tcl_Cmd (void *clientData, Tcl_Interp *interp, int argc, unsigned char **argv); + +/* + *---------------------------------------------------------------- + * Command procedures in the UNIX core: + *---------------------------------------------------------------- + */ +extern int Tcl_CdCmd (void *clientData, Tcl_Interp *interp, int argc, unsigned char **argv); +extern int Tcl_CloseCmd (void *clientData, Tcl_Interp *interp, int argc, unsigned char **argv); +extern int Tcl_EofCmd (void *clientData, Tcl_Interp *interp, int argc, unsigned char **argv); +extern int Tcl_ExecCmd (void *clientData, Tcl_Interp *interp, int argc, unsigned char **argv); +extern int Tcl_ExitCmd (void *clientData, Tcl_Interp *interp, int argc, unsigned char **argv); +extern int Tcl_FileCmd (void *clientData, Tcl_Interp *interp, int argc, unsigned char **argv); +extern int Tcl_FlushCmd (void *clientData, Tcl_Interp *interp, int argc, unsigned char **argv); +extern int Tcl_GetsCmd (void *clientData, Tcl_Interp *interp, int argc, unsigned char **argv); +extern int Tcl_GlobCmd (void *clientData, Tcl_Interp *interp, int argc, unsigned char **argv); +extern int Tcl_OpenCmd (void *clientData, Tcl_Interp *interp, int argc, unsigned char **argv); +extern int Tcl_PutsCmd (void *clientData, Tcl_Interp *interp, int argc, unsigned char **argv); +extern int Tcl_PwdCmd (void *clientData, Tcl_Interp *interp, int argc, unsigned char **argv); +extern int Tcl_ReadCmd (void *clientData, Tcl_Interp *interp, int argc, unsigned char **argv); +extern int Tcl_SeekCmd (void *clientData, Tcl_Interp *interp, int argc, unsigned char **argv); +extern int Tcl_SourceCmd (void *clientData, Tcl_Interp *interp, int argc, unsigned char **argv); +extern int Tcl_TellCmd (void *clientData, Tcl_Interp *interp, int argc, unsigned char **argv); +extern int Tcl_TimeCmd (void *clientData, Tcl_Interp *interp, int argc, unsigned char **argv); diff --git a/src/libtcl/regexp.c b/src/libtcl/regexp.c new file mode 100644 index 0000000..e614239 --- /dev/null +++ b/src/libtcl/regexp.c @@ -0,0 +1,1227 @@ +/* + * regcomp and regexec -- regsub is elsewhere + * + * Copyright (c) 1986 by University of Toronto. + * Written by Henry Spencer. Not derived from licensed software. + * + * Permission is granted to anyone to use this software for any + * purpose on any computer system, and to redistribute it freely, + * subject to the following restrictions: + * + * 1. The author is not responsible for the consequences of use of + * this software, no matter how awful, even if they arise + * from defects in it. + * + * 2. The origin of this software must not be misrepresented, either + * by explicit claim or by omission. + * + * 3. Altered versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + *** THIS IS AN ALTERED VERSION. It was altered by Serge Vakulenko, + *** vak@cronyx.ru, on 10 Novc 2002, to make it thread-safe. + *** THIS IS AN ALTERED VERSION. It was altered by John Gilmore, + *** hoptoad!gnu, on 27 Dec 1986, to add \n as an alternative to | + *** to assist in implementing egrep. + *** THIS IS AN ALTERED VERSION. It was altered by John Gilmore, + *** hoptoad!gnu, on 27 Dec 1986, to add \< and \> for word-matching + *** as in BSD grep and ex. + *** THIS IS AN ALTERED VERSION. It was altered by John Gilmore, + *** hoptoad!gnu, on 28 Dec 1986, to optimize characters quoted with \. + *** THIS IS AN ALTERED VERSION. It was altered by James A. Woods, + *** ames!jaw, on 19 June 1987, to quash a regcomp() redundancy. + * + * Beware that some of this code is subtly aware of the way operator + * precedence is structured in regular expressions. Serious changes in + * regular-expression syntax might require a total rethink. + */ +#include +#include +#include "regexp.h" +#include "regpriv.h" + +/* + * Structure for regexp "program". This is essentially a linear encoding + * of a nondeterministic finite-state machine (aka syntax charts or + * "railroad normal form" in parsing technology). Each node is an opcode + * plus a "next" pointer, possibly plus an operand. "Next" pointers of + * all nodes except BRANCH implement concatenation; a "next" pointer with + * a BRANCH on both ends of it is connecting two alternatives. (Here we + * have one of the subtle syntax dependencies: an individual BRANCH (as + * opposed to a collection of them) is never concatenated with anything + * because of operator precedence.) The operand of some types of node is + * a literal string; for others, it is a node leading into a sub-FSM. In + * particular, the operand of a BRANCH node is the first node of the branch. + * (NB this is *not* a tree structure: the tail of the branch connects + * to the thing following the set of BRANCHes.) The opcodes are: + */ + +/* definition number opnd? meaning */ +#define END 0 /* no End of program. */ +#define BOL 1 /* no Match "" at beginning of line. */ +#define EOL 2 /* no Match "" at end of line. */ +#define ANY 3 /* no Match any one character. */ +#define ANYOF 4 /* str Match any character in this string. */ +#define ANYBUT 5 /* str Match any character not in this string. */ +#define BRANCH 6 /* node Match this alternative, or the next... */ +#define BACK 7 /* no Match "", "next" ptr points backward. */ +#define EXACTLY 8 /* str Match this string. */ +#define NOTHING 9 /* no Match empty string. */ +#define STAR 10 /* node Match this (simple) thing 0 or more times. */ +#define PLUS 11 /* node Match this (simple) thing 1 or more times. */ +#define WORDA 12 /* no Match "" at wordchar, where prev is nonword */ +#define WORDZ 13 /* no Match "" at nonwordchar, where prev is word */ +#define OPEN 20 /* no Mark this point in input as start of #n. */ + /* OPEN+1 is number 1, etc. */ +#define CLOSE 30 /* no Analogous to OPEN. */ + +/* + * Opcode notes: + * + * BRANCH The set of branches constituting a single choice are hooked + * together with their "next" pointers, since precedence prevents + * anything being concatenated to any individual branch. The + * "next" pointer of the last BRANCH in a choice points to the + * thing following the whole choice. This is also where the + * final "next" pointer of each individual branch points; each + * branch starts with the operand node of a BRANCH node. + * + * BACK Normal "next" pointers all implicitly point forward; BACK + * exists to make loop structures possible. + * + * STAR,PLUS '?', and complex '*' and '+', are implemented as circular + * BRANCH structures using BACK. Simple cases (one character + * per match) are implemented with STAR and PLUS for speed + * and to minimize recursive plunges. + * + * OPEN,CLOSE ...are numbered at compile time. + */ + +/* + * A node is one char of opcode followed by two chars of "next" pointer. + * "Next" pointers are stored as two 8-bit pieces, high order first. The + * value is a positive offset from the opcode of the node containing it. + * An operand, if any, simply follows the node. (Note that much of the + * code generation knows about this implicit relationship.) + * + * Using two bytes for the "next" pointer is vast overkill for most things, + * but allows patterns to get big without disasters. + */ +#define OP(p) (*(p)) +#define NEXT(p) (((*((p)+1)&0377)<<8) + (*((p)+2)&0377)) +#define OPERAND(p) ((p) + 3) + +/* + * Utility definitions. + */ +#define ISMULT(c) ((c) == '*' || (c) == '+' || (c) == '?') +#define ISALNUM(c) (((c)>='a' && (c)<='z') || \ + ((c)>='A' && (c)<='Z') || \ + ((c)>='0' && (c)<='9') || \ + ((c)>=0300)) + +/* + * Flags to be passed up and down. + */ +#define HASWIDTH 01 /* Known never to match null string. */ +#define SIMPLE 02 /* Simple enough to be STAR/PLUS operand. */ +#define SPSTART 04 /* Starts with * or +. */ +#define WORST 0 /* Worst case. */ + +/* + * Global work variables for regcomp(). + */ +typedef struct { + unsigned const char *parse; /* Input-scan pointer. */ + unsigned char npar; /* () count. */ + unsigned char *code; /* Code-emit pointer; ®dummy = don't. */ + unsigned short size; /* Code size. */ +} compile_t; + +static unsigned char regdummy; + +/* + * Forward declarations for regcomp()'s friends. + */ +static unsigned char *reg (compile_t *x, unsigned char paren, unsigned char *flagp); +static unsigned char *regbranch (compile_t *x, unsigned char *flagp); +static unsigned char *regpiece (compile_t *x, unsigned char *flagp); +static unsigned char *regatom (compile_t *x, unsigned char *flagp); +static unsigned char *regnode (compile_t *x, unsigned char op); +static void regc (compile_t *x, unsigned char b); +static void reginsert (compile_t *x, unsigned char op, unsigned char *opnd); +static unsigned char *regnext (unsigned char *p); +static void regtail (unsigned char *p, unsigned char *val); +static void regoptail (unsigned char *p, unsigned char *val); + +/* + * Global work variables for regexec(). + */ +typedef struct { + const unsigned char *input; /* String-input pointer. */ + const unsigned char *bol; /* Beginning of input, for ^ check. */ + const unsigned char **startp; /* Pointer to startp array. */ + const unsigned char **endp; /* Ditto for endp. */ +} execute_t; + +/* + * Forwards. + */ +static unsigned char regtry (regexp_t *prog, execute_t *z, const unsigned char *string); +static unsigned char regmatch (execute_t *z, unsigned char *prog); +static unsigned short regrepeat (execute_t *z, unsigned char *p); + +#ifdef DEBUG_REGEXP +#include +static unsigned char *regprop (unsigned char *op); +#endif + +/* + * Determine the required size. + * On failure, returns 0. + */ +unsigned +regexp_size (const unsigned char *exp) +{ + compile_t x; + unsigned char flags; + + if (! exp) { + /* FAIL("NULL argument"); */ + return 0; + } + + x.parse = exp; + x.npar = 1; + x.size = 0L; + x.code = ®dummy; + regc (&x, MAGIC); + if (! reg (&x, 0, &flags)) + return 0; + + return sizeof (regexp_t) + x.size; +} + +/* + * Compile a regular expression into internal code. + * Returns 1 on success, or 0 on failure. + * + * We can't allocate space until we know how big the compiled form will be, + * but we can't compile it (and thus know how big it is) until we've got a + * place to put the code. So we cheat: we compile it twice, once with code + * generation turned off and size counting turned on, and once "for real". + * This also means that we don't allocate space until we are sure that the + * thing really will compile successfully, and we never have to move the + * code and thus invalidate pointers into it. (Note that it has to be in + * one piece because free() must be able to free it all.) + * + * Beware that the optimization-preparation code in here knows about some + * of the structure of the compiled regexp. + */ +bool_t +regexp_compile (regexp_t *r, const unsigned char *exp) +{ + unsigned char *scan; + unsigned char *longest; + compile_t x; + unsigned short len; + unsigned char flags; + + if (! r || ! exp) { + /* FAIL("NULL argument"); */ + return 0; + } + + /* Second pass: emit code. */ + x.parse = exp; + x.npar = 1; + x.code = r->program; + regc (&x, MAGIC); + if (! reg (&x, 0, &flags)) + return 0; + + /* Dig out information for optimizations. */ + r->start = '\0'; /* Worst-case defaults. */ + r->anchor = 0; + r->must = 0; + r->mustlen = 0; + scan = r->program+1; /* First BRANCH. */ + if (OP (regnext (scan)) == END) { /* Only one top-level choice. */ + scan = OPERAND(scan); + + /* Starting-point info. */ + if (OP(scan) == EXACTLY) + r->start = *OPERAND(scan); + else if (OP(scan) == BOL) + r->anchor++; + + /* + * If there's something expensive in the r.e., find the + * longest literal string that must appear and make it the + * `must'. Resolve ties in favor of later strings, since + * the start check works with the beginning of the r.e. + * and avoiding duplication strengthens checking. Not a + * strong reason, but sufficient in the absence of others. + */ + if (flags & SPSTART) { + longest = 0; + len = 0; + for (; scan; scan=regnext(scan)) + if (OP(scan) == EXACTLY && + strlen (OPERAND (scan)) >= len) { + longest = OPERAND (scan); + len = strlen(OPERAND (scan)); + } + r->must = longest; + r->mustlen = len; + } + } + return 1; +} + +/* + - reg - regular expression, i.e. main body or parenthesized thing + * + * Caller must absorb opening parenthesis. + * + * Combining parenthesis handling with the base level of regular expression + * is a trifle forced, but the need to tie the tails of the branches to what + * follows makes it hard to avoid. + */ +static unsigned char * +reg (compile_t *x, unsigned char paren, unsigned char *flagp) +{ + unsigned char *ret; + unsigned char *br; + unsigned char *ender; + unsigned char parno = 0; + unsigned char flags; + + *flagp = HASWIDTH; /* Tentatively. */ + + /* Make an OPEN node, if parenthesized. */ + if (paren) { + if (x->npar >= NSUBEXP) { + /* FAIL("too many ()"); */ + return 0; + } + parno = x->npar; + x->npar++; + ret = regnode (x, OPEN+parno); + } else + ret = 0; + + /* Pick up the branches, linking them together. */ + br = regbranch (x, &flags); + if (! br) + return 0; + + if (ret) + regtail (ret, br); /* OPEN -> first. */ + else + ret = br; + + if (!(flags&HASWIDTH)) + *flagp &= ~HASWIDTH; + *flagp |= flags & SPSTART; + while (*x->parse == '|' || *x->parse == '\n') { + x->parse++; + br = regbranch (x, &flags); + if (! br) + return 0; + + regtail (ret, br); /* BRANCH -> BRANCH. */ + if (!(flags & HASWIDTH)) + *flagp &= ~HASWIDTH; + *flagp |= flags & SPSTART; + } + + /* Make a closing node, and hook it on the end. */ + ender = regnode (x, paren ? CLOSE+parno : END); + regtail (ret, ender); + + /* Hook the tails of the branches to the closing node. */ + for (br=ret; br; br=regnext(br)) + regoptail (br, ender); + + /* Check for proper termination. */ + if (paren && *x->parse++ != ')') { + /* FAIL("unmatched ()"); */ + return 0; + } + if (! paren && *x->parse != '\0') { + if (*x->parse == ')') { + /* FAIL("unmatched ()"); */ + return 0; + } + /* "Can't happen". */ + /* FAIL("junk on end"); */ + return 0; + /* NOTREACHED */ + } + return ret; +} + +/* + - regbranch - one alternative of an | operator + * + * Implements the concatenation operator. + */ +static unsigned char * +regbranch (compile_t *x, unsigned char *flagp) +{ + unsigned char *ret; + unsigned char *chain; + unsigned char *latest; + unsigned char flags; + + *flagp = WORST; /* Tentatively. */ + + ret = regnode (x, BRANCH); + chain = 0; + while (*x->parse != '\0' && *x->parse != ')' && + *x->parse != '\n' && *x->parse != '|') { + latest = regpiece (x, &flags); + if (! latest) + return 0; + + *flagp |= flags & HASWIDTH; + if (! chain) /* First piece. */ + *flagp |= flags & SPSTART; + else + regtail (chain, latest); + chain = latest; + } + if (! chain) /* Loop ran zero times. */ + regnode (x, NOTHING); + + return ret; +} + +/* + - regpiece - something followed by possible [*+?] + * + * Note that the branching code sequences used for ? and the general cases + * of * and + are somewhat optimized: they use the same NOTHING node as + * both the endmarker for their branch list and the body of the last branch. + * It might seem that this node could be dispensed with entirely, but the + * endmarker role is not redundant. + */ +static unsigned char * +regpiece (compile_t *x, unsigned char *flagp) +{ + unsigned char *ret; + unsigned char op; + unsigned char *next; + unsigned char flags; + + ret = regatom (x, &flags); + if (! ret) + return 0; + + op = *x->parse; + if (! ISMULT (op)) { + *flagp = flags; + return ret; + } + + if (!(flags&HASWIDTH) && op != '?') { + /* FAIL("*+ operand could be empty"); */ + return 0; + } + *flagp = (op != '+') ? (WORST | SPSTART) : (WORST | HASWIDTH); + + if (op == '*' && (flags&SIMPLE)) + reginsert (x, STAR, ret); + else if (op == '*') { + /* Emit x* as (x&|), where & means "self". */ + reginsert (x, BRANCH, ret); /* Either x */ + regoptail (ret, regnode (x, BACK)); /* and loop */ + regoptail (ret, ret); /* back */ + regtail (ret, regnode (x, BRANCH)); /* or */ + regtail (ret, regnode (x, NOTHING)); /* null. */ + } else if (op == '+' && (flags&SIMPLE)) + reginsert (x, PLUS, ret); + else if (op == '+') { + /* Emit x+ as x(&|), where & means "self". */ + next = regnode (x, BRANCH); /* Either */ + regtail (ret, next); + regtail (regnode (x, BACK), ret); /* loop back */ + regtail (next, regnode (x, BRANCH)); /* or */ + regtail (ret, regnode (x, NOTHING)); /* null. */ + } else if (op == '?') { + /* Emit x? as (x|) */ + reginsert (x, BRANCH, ret); /* Either x */ + regtail (ret, regnode (x, BRANCH)); /* or */ + next = regnode (x, NOTHING); /* null. */ + regtail (ret, next); + regoptail (ret, next); + } + x->parse++; + if (ISMULT (*x->parse)) { + /* FAIL("nested *?+"); */ + return 0; + } + return ret; +} + +/* + - regatom - the lowest level + * + * Optimization: gobbles an entire sequence of ordinary characters so that + * it can turn them into a single node, which is smaller to store and + * faster to run. Backslashed characters are exceptions, each becoming a + * separate node; the code is simpler that way and it's not worth fixing. + */ +static unsigned char * +regatom (compile_t *x, unsigned char *flagp) +{ + unsigned char *ret; + unsigned char flags; + + *flagp = WORST; /* Tentatively. */ + + switch (*x->parse++) { + /* FIXME: these chars only have meaning at beg/end of pat? */ + case '^': + ret = regnode (x, BOL); + break; + case '$': + ret = regnode (x, EOL); + break; + case '.': + ret = regnode (x, ANY); + *flagp |= HASWIDTH | SIMPLE; + break; + case '[': { + unsigned char class, classend; + + if (*x->parse == '^') { /* Complement of range. */ + ret = regnode (x, ANYBUT); + x->parse++; + } else + ret = regnode (x, ANYOF); + if (*x->parse == ']' || *x->parse == '-') + regc (x, *x->parse++); + while (*x->parse != '\0' && *x->parse != ']') { + if (*x->parse == '-') { + x->parse++; + if (*x->parse == ']' || *x->parse == '\0') + regc (x, '-'); + else { + class = UCHARAT(x->parse-2); + classend = UCHARAT(x->parse); + if (class > classend) { + /* FAIL("invalid [] range"); */ + return 0; + } + for (class++; class <= classend; class++) + regc (x, class); + x->parse++; + } + } else + regc (x, *x->parse++); + } + regc (x, '\0'); + if (*x->parse != ']') { + /* FAIL("unmatched []"); */ + return 0; + } + x->parse++; + *flagp |= HASWIDTH | SIMPLE; + } + break; + case '(': + ret = reg (x, 1, &flags); + if (! ret) + return 0; + *flagp |= flags & (HASWIDTH | SPSTART); + break; + case '\0': + case '|': + case '\n': + case ')': + /* Supposed to be caught earlier. */ + /* FAIL("internal urp"); */ + return 0; + case '?': + case '+': + case '*': + /* FAIL("?+* follows nothing"); */ + return 0; + case '\\': + switch (*x->parse++) { + case '\0': + /* FAIL("trailing \\"); */ + return 0; + case '<': + ret = regnode (x, WORDA); + break; + case '>': + ret = regnode (x, WORDZ); + break; + /* FIXME: Someday handle \1, \2, ... */ + default: + /* Handle general quoted chars in exact-match routine */ + goto de_fault; + } + break; + de_fault: + default: + /* + * Encode a string of characters to be matched exactly. + * + * This is a bit tricky due to quoted chars and due to + * '*', '+', and '?' taking the SINGLE char previous + * as their operand. + * + * On entry, the char at regparse[-1] is going to go + * into the string, no matter what it is. (It could be + * following a \ if we are entered from the '\' case.) + * + * Basic idea is to pick up a good char in ch and + * examine the next char. If it's *+? then we twiddle. + * If it's \ then we frozzle. If it's other magic char + * we push ch and terminate the string. If none of the + * above, we push ch on the string and go around again. + * + * `Regprev' is used to remember where "the current char" + * starts in the string, if due to a *+? we need to back + * up and put the current char in a separate, 1-char, string. + * When `regprev' is NULL, ch is the only char in the + * string; this is used in *+? handling, and in setting + * flags |= SIMPLE at the end. + */ + { + const unsigned char *regprev; + unsigned char ch; + + x->parse--; /* Look at cur char */ + ret = regnode (x, EXACTLY); + regprev = 0; + for (;;) { + ch = *x->parse++; /* Get current char */ + switch (*x->parse) { /* look at next one */ + + default: + regc (x, ch); /* Add cur to string */ + break; + + case '.': case '[': case '(': + case ')': case '|': case '\n': + case '$': case '^': + case '\0': + /* FIXME, $ and ^ should not always be magic */ + magic: + regc (x, ch); /* dump cur char */ + goto done; /* and we are done */ + + case '?': case '+': case '*': + if (! regprev) /* If just ch in str, */ + goto magic; /* use it */ + /* End mult-char string one early */ + x->parse = regprev; /* Back up parse */ + goto done; + + case '\\': + regc (x, ch); /* Cur char OK */ + switch (x->parse[1]){ /* Look after \ */ + case '\0': + case '<': + case '>': + /* FIXME: Someday handle \1, \2, ... */ + goto done; /* Not quoted */ + default: + /* Backup point is \, scan * point is after it. */ + regprev = x->parse; + x->parse++; + continue; /* NOT break; */ + } + } + regprev = x->parse; /* Set backup point */ + } + done: + regc (x, '\0'); + *flagp |= HASWIDTH; + if (! regprev) /* One char? */ + *flagp |= SIMPLE; + } + break; + } + + return ret; +} + +/* + - regnode - emit a node + */ +static unsigned char * /* Location. */ +regnode (compile_t *x, unsigned char op) +{ + unsigned char *ret; + unsigned char *ptr; + + ret = x->code; + if (ret == ®dummy) { + x->size += 3; + return ret; + } + + ptr = ret; + *ptr++ = op; + *ptr++ = '\0'; /* Null "next" pointer. */ + *ptr++ = '\0'; + x->code = ptr; + + return ret; +} + +/* + - regc - emit (if appropriate) a byte of code + */ +static void +regc (compile_t *x, unsigned char b) +{ + if (x->code != ®dummy) + *x->code++ = b; + else + x->size++; +} + +/* + - reginsert - insert an operator in front of already-emitted operand + * + * Means relocating the operand. + */ +static void +reginsert (compile_t *x, unsigned char op, unsigned char *opnd) +{ + unsigned char *src; + unsigned char *dst; + unsigned char *place; + + if (x->code == ®dummy) { + x->size += 3; + return; + } + + src = x->code; + x->code += 3; + dst = x->code; + while (src > opnd) + *--dst = *--src; + + place = opnd; /* Op node, where operand used to be. */ + *place++ = op; + *place++ = '\0'; + *place++ = '\0'; +} + +/* + - regtail - set the next-pointer at the end of a node chain + */ +static void +regtail (unsigned char *p, unsigned char *val) +{ + unsigned char *scan; + unsigned char *temp; + unsigned short offset; + + if (p == ®dummy) + return; + + /* Find last node. */ + scan = p; + for (;;) { + temp = regnext (scan); + if (! temp) + break; + scan = temp; + } + + if (OP(scan) == BACK) + offset = scan - val; + else + offset = val - scan; + *(scan+1) = (offset >> 8) & 0377; + *(scan+2) = offset & 0377; +} + +/* + - regoptail - regtail on operand of first argument; nop if operandless + */ +static void +regoptail (unsigned char *p, unsigned char *val) +{ + /* "Operandless" and "op != BRANCH" are synonymous in practice. */ + if (! p || p == ®dummy || OP(p) != BRANCH) + return; + regtail (OPERAND(p), val); +} + +/* + * regexec and friends + */ + +/* + * Match a regular expression against a string. + * Returns 1 on success, or 0 on failure. + */ +bool_t +regexp_execute (regexp_t *prog, const unsigned char *string) +{ + execute_t z; + const unsigned char *s; + + /* Be paranoid... */ + if (! prog || ! string) { + /* regerror("NULL parameter"); */ + return 0; + } + + /* Check validity of program. */ + if (UCHARAT (prog->program) != MAGIC) { + /* regerror("corrupted program"); */ + return 0; + } + + /* If there is a "must appear" string, look for it. */ + if (prog->must) { + s = string; + while ((s = strchr (s, prog->must[0])) != 0) { + if (strncmp (s, prog->must, prog->mustlen) == 0) + break; /* Found it. */ + s++; + } + if (! s) /* Not present. */ + return 0; + } + + /* Mark beginning of line for ^ . */ + z.bol = string; + + /* Simplest case: anchored match need be tried only once. */ + if (prog->anchor) + return regtry (prog, &z, string); + + /* Messy cases: unanchored match. */ + s = string; + if (prog->start != '\0') + /* We know what char it must start with. */ + while ((s = strchr (s, prog->start)) != 0) { + if (regtry (prog, &z, s)) + return 1; + s++; + } + else + /* We don't -- general case. */ + do { + if (regtry (prog, &z, s)) + return 1; + } while (*s++ != '\0'); + + /* Failure. */ + return 0; +} + +/* + - regtry - try match at specific point + */ +static unsigned char /* 0 failure, 1 success */ +regtry (regexp_t *prog, execute_t *z, const unsigned char *string) +{ + unsigned char i; + const unsigned char **sp; + const unsigned char **ep; + + z->input = string; + z->startp = prog->startp; + z->endp = prog->endp; + + sp = prog->startp; + ep = prog->endp; + for (i=NSUBEXP; i>0; i--) { + *sp++ = 0; + *ep++ = 0; + } + if (regmatch (z, prog->program + 1)) { + prog->startp[0] = string; + prog->endp[0] = z->input; + return 1; + } + return 0; +} + +/* + - regmatch - main matching routine + * + * Conceptually the strategy is simple: check to see whether the current + * node matches, call self recursively to see whether the rest matches, + * and then act accordingly. In practice we make some effort to avoid + * recursion, in particular by going through "ordinary" nodes (that don't + * need to know whether the rest of the match failed) by a loop instead of + * by recursion. + */ +static unsigned char /* 0 failure, 1 success */ +regmatch (execute_t *z, unsigned char *prog) +{ + unsigned char *scan; /* Current node. */ + unsigned char *next; /* Next node. */ + + scan = prog; +#ifdef DEBUG_REGEXP + if (scan && regsub_narrate) + fprintf (stderr, "%s(\n", regprop (scan)); +#endif + while (scan) { +#ifdef DEBUG_REGEXP + if (regsub_narrate) + fprintf (stderr, "%s...\n", regprop (scan)); +#endif + next = regnext (scan); + + switch (OP(scan)) { + case BOL: + if (z->input != z->bol) + return 0; + break; + case EOL: + if (*z->input != '\0') + return 0; + break; + case WORDA: + /* Must be looking at a letter, digit, or _ */ + if ((!ISALNUM((unsigned char)*z->input)) && *z->input != '_') + return 0; + /* Prev must be BOL or nonword */ + if (z->input > z->bol && + (ISALNUM((unsigned char)z->input[-1]) || z->input[-1] == '_')) + return 0; + break; + case WORDZ: + /* Must be looking at non letter, digit, or _ */ + if (ISALNUM((unsigned char)*z->input) || *z->input == '_') + return 0; + /* We don't care what the previous char was */ + break; + case ANY: + if (*z->input == '\0') + return 0; + z->input++; + break; + case EXACTLY: { + unsigned short len; + unsigned char *opnd; + + opnd = OPERAND(scan); + /* Inline the first character, for speed. */ + if (*opnd != *z->input) + return 0; + len = strlen(opnd); + if (len > 1 && strncmp(opnd, z->input, len) != 0) + return 0; + z->input += len; + } + break; + case ANYOF: + if (*z->input == '\0' || strchr(OPERAND(scan), *z->input) == 0) + return 0; + z->input++; + break; + case ANYBUT: + if (*z->input == '\0' || strchr(OPERAND(scan), *z->input) != 0) + return 0; + z->input++; + break; + case NOTHING: + break; + case BACK: + break; + case OPEN+1: + case OPEN+2: + case OPEN+3: + case OPEN+4: + case OPEN+5: + case OPEN+6: + case OPEN+7: + case OPEN+8: + case OPEN+9: { + unsigned char no; + const unsigned char *save; + + no = OP(scan) - OPEN; + save = z->input; + + if (regmatch (z, next)) { + /* + * Don't set startp if some later + * invocation of the same parentheses + * already has. + */ + if (! z->startp[no]) + z->startp[no] = save; + return 1; + } + return 0; + } + break; + case CLOSE+1: + case CLOSE+2: + case CLOSE+3: + case CLOSE+4: + case CLOSE+5: + case CLOSE+6: + case CLOSE+7: + case CLOSE+8: + case CLOSE+9: { + unsigned char no; + const unsigned char *save; + + no = OP(scan) - CLOSE; + save = z->input; + + if (regmatch (z, next)) { + /* + * Don't set endp if some later + * invocation of the same parentheses + * already has. + */ + if (! z->endp[no]) + z->endp[no] = save; + return 1; + } + return 0; + } + break; + case BRANCH: { + const unsigned char *save; + + if (OP(next) != BRANCH) /* No choice. */ + next = OPERAND(scan); /* Avoid recursion. */ + else { + do { + save = z->input; + if (regmatch (z, OPERAND(scan))) + return 1; + z->input = save; + scan = regnext (scan); + } while (scan && OP(scan) == BRANCH); + return 0; + /* NOTREACHED */ + } + } + break; + case STAR: + case PLUS: { + unsigned char nextch; + unsigned short no, min; + const unsigned char *save; + + /* + * Lookahead to avoid useless match attempts + * when we know what character comes next. + */ + nextch = '\0'; + if (OP(next) == EXACTLY) + nextch = *OPERAND(next); + min = (OP(scan) == STAR) ? 0 : 1; + save = z->input; + no = regrepeat (z, OPERAND(scan)); + while (no >= min) { + /* If it could work, try it. */ + if (nextch == '\0' || *z->input == nextch) + if (regmatch (z, next)) + return 1; + /* Couldn't or didn't -- back up. */ + no--; + z->input = save + no; + } + return 0; + } + break; + case END: + return 1; /* Success! */ + default: + /* regerror("memory corruption"); */ + return 0; + } + + scan = next; + } + + /* + * We get here only if there's trouble -- normally "case END" is + * the terminating point. + */ + /* regerror("corrupted pointers"); */ + return 0; +} + +/* + - regrepeat - repeatedly match something simple, report how many + */ +static unsigned short +regrepeat (execute_t *z, unsigned char *p) +{ + unsigned short count = 0; + const unsigned char *scan; + unsigned char *opnd; + + scan = z->input; + opnd = OPERAND(p); + switch (OP(p)) { + case ANY: + count = strlen(scan); + scan += count; + break; + case EXACTLY: + while (*opnd == *scan) { + count++; + scan++; + } + break; + case ANYOF: + while (*scan != '\0' && strchr(opnd, *scan) != 0) { + count++; + scan++; + } + break; + case ANYBUT: + while (*scan != '\0' && strchr(opnd, *scan) == 0) { + count++; + scan++; + } + break; + default: /* Oh dear. Called inappropriately. */ + /* regerror("internal foulup"); */ + count = 0; /* Best compromise. */ + break; + } + z->input = scan; + + return count; +} + +/* + - regnext - dig the "next" pointer out of a node + */ +static unsigned char * +regnext (unsigned char *p) +{ + unsigned short offset; + + if (p == ®dummy) + return 0; + + offset = NEXT(p); + if (offset == 0) + return 0; + + if (OP(p) == BACK) + return p - offset; + else + return p + offset; +} + +#ifdef DEBUG_REGEXP + +/* + * Dump a regexp onto stdout in vaguely comprehensible form + */ +void +regsub_dump (regexp_t *r) +{ + unsigned char *s; + unsigned char op = EXACTLY; /* Arbitrary non-END op. */ + unsigned char *next; + + s = r->program + 1; + while (op != END) { /* While that wasn't END last time... */ + op = OP(s); + printf("%2d%s", s-r->program, regprop (s)); /* Where, what. */ + next = regnext (s); + if (! next) /* Next ptr. */ + printf("(0)"); + else + printf("(%d)", (s-r->program)+(next-s)); + s += 3; + if (op == ANYOF || op == ANYBUT || op == EXACTLY) { + /* Literal string, where present. */ + while (*s != '\0') { + putchar(*s); + s++; + } + s++; + } + putchar('\n'); + } + + /* Header fields of interest. */ + if (r->start != '\0') + printf("start `%c' ", r->start); + if (r->anchor) + printf("anchored "); + if (r->must) + printf("must have \"%s\"", r->must); + printf("\n"); +} + +/* + - regprop - printable representation of opcode + */ +static unsigned char * +regprop (unsigned char *op) +{ + unsigned char *p; + static unsigned char buf[50]; + + strcpy (buf, ":"); + + switch (OP(op)) { + case BOL: p = "BOL"; break; + case EOL: p = "EOL"; break; + case ANY: p = "ANY"; break; + case ANYOF: p = "ANYOF"; break; + case ANYBUT: p = "ANYBUT"; break; + case BRANCH: p = "BRANCH"; break; + case EXACTLY: p = "EXACTLY"; break; + case NOTHING: p = "NOTHING"; break; + case BACK: p = "BACK"; break; + case END: p = "END"; break; + case STAR: p = "STAR"; break; + case PLUS: p = "PLUS"; break; + case WORDA: p = "WORDA"; break; + case WORDZ: p = "WORDZ"; break; + case OPEN+1: + case OPEN+2: + case OPEN+3: + case OPEN+4: + case OPEN+5: + case OPEN+6: + case OPEN+7: + case OPEN+8: + case OPEN+9: + sprintf (buf + strlen (buf), "OPEN%d", OP(op) - OPEN); + p = 0; + break; + case CLOSE+1: + case CLOSE+2: + case CLOSE+3: + case CLOSE+4: + case CLOSE+5: + case CLOSE+6: + case CLOSE+7: + case CLOSE+8: + case CLOSE+9: + sprintf (buf + strlen (buf), "CLOSE%d", OP(op) - CLOSE); + p = 0; + break; + default: + /* corrupted opcode */ + p = "???"; + break; + } + if (p) + strcat (buf, p); + return buf; +} +#endif diff --git a/src/libtcl/regexp.h b/src/libtcl/regexp.h new file mode 100644 index 0000000..8228a0a --- /dev/null +++ b/src/libtcl/regexp.h @@ -0,0 +1,29 @@ +/* + * Definitions etc. for regexp(3) routines. + */ +typedef struct _regexp_t regexp_t; + +/* + * Determine the required size. + * On failure, returns 0. + */ +unsigned regexp_size (const unsigned char *pattern); + +/* + * Compile a regular expression into internal code. + * Returns 1 on success, or 0 on failure. + */ +bool_t regexp_compile (regexp_t *re, const unsigned char *pattern); + +/* + * Match a regular expression against a string. + * Returns 1 on success, or 0 on failure. + */ +bool_t regexp_execute (regexp_t *re, const unsigned char *str); + +/* + * Perform substitutions after a regexp match. + * Returns 1 on success, or 0 on failure. + */ +bool_t regexp_substitute (const regexp_t *re, + const unsigned char *src, unsigned char *dst); diff --git a/src/libtcl/regpriv.h b/src/libtcl/regpriv.h new file mode 100644 index 0000000..66002a4 --- /dev/null +++ b/src/libtcl/regpriv.h @@ -0,0 +1,49 @@ +/* + * Internal definitions for regexp(3) routines. + */ +#define NSUBEXP 10 + +/* + * The "internal use only" fields in regexp.h are present to pass info from + * compile to execute that permits the execute phase to run lots faster on + * simple cases. They are: + * + * start char that must begin a match; '\0' if none obvious + * anchor is the match anchored (at beginning-of-line only)? + * must string (pointer into program) that match must include, or NULL + * mustlen length of `must' string + * + * `Start' and `anchor' permit very fast decisions on suitable starting points + * for a match, cutting down the work a lot. `Must' permits fast rejection + * of lines that cannot possibly match. The `must' tests are costly enough + * that regcomp() supplies a `must' only if the r.e. contains something + * potentially expensive (at present, the only such thing detected is * or + + * at the start of the r.e., which can involve a lot of backup). `Mustlen' is + * supplied because the test in regexec() needs it and regcomp() is computing + * it anyway. + */ +struct _regexp_t { + const unsigned char *startp [NSUBEXP]; + const unsigned char *endp [NSUBEXP]; + unsigned char start; + unsigned char anchor; + unsigned char *must; + unsigned short mustlen; + unsigned char program [1]; +}; + +/* + * Utility definitions. + */ +#define UCHARAT(p) (*(unsigned char*)(p)) + +/* + * The first byte of the regexp internal "program" is actually this magic + * number; the start node begins in the second byte. + */ +#define MAGIC 0234 + +#ifdef DEBUG_REGEXP +unsigned char regsub_narrate; +void regsub_dump (regexp_t *r); +#endif diff --git a/src/libtcl/regsub.c b/src/libtcl/regsub.c new file mode 100644 index 0000000..c0b9a4b --- /dev/null +++ b/src/libtcl/regsub.c @@ -0,0 +1,69 @@ +/* + * Copyright (c) 1986 by University of Toronto. + * Written by Henry Spencer. Not derived from licensed software. + * + * Permission is granted to anyone to use this software for any + * purpose on any computer system, and to redistribute it freely, + * subject to the following restrictions: + * + * 1. The author is not responsible for the consequences of use of + * this software, no matter how awful, even if they arise + * from defects in it. + * + * 2. The origin of this software must not be misrepresented, either + * by explicit claim or by omission. + * + * 3. Altered versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + */ +#include +#include +#include "regexp.h" +#include "regpriv.h" + +/* + * Perform substitutions after a regexp match. + * Returns 1 on success, or 0 on failure. + */ +bool_t +regexp_substitute (const regexp_t *prog, const unsigned char *src, unsigned char *dst) +{ + unsigned char c; + unsigned char no; + unsigned short len; + + if (! prog || ! src || ! dst) { + /* regerror("NULL parm to regsub"); */ + return 0; + } + if (UCHARAT(prog->program) != MAGIC) { + /* regerror("damaged regexp fed to regsub"); */ + return 0; + } + + while ((c = *src++) != '\0') { + if (c == '&') + no = 0; + else if (c == '\\' && '0' <= *src && *src <= '9') + no = *src++ - '0'; + else + no = 10; + if (no > 9) { + /* Ordinary character. */ + if (c == '\\' && (*src == '\\' || *src == '&')) + c = *src++; + *dst++ = c; + } else if (prog->startp[no] && prog->endp[no]) { + len = prog->endp[no] - prog->startp[no]; + strncpy (dst, prog->startp[no], len); + dst += len; + if (len != 0 && dst[-1] == '\0') { + /* strncpy hit NUL. */ + /* regerror("damaged match string"); */ + return 0; + } + } + } + *dst = '\0'; + return 1; +} diff --git a/src/libtcl/tclassem.c b/src/libtcl/tclassem.c new file mode 100644 index 0000000..e729fca --- /dev/null +++ b/src/libtcl/tclassem.c @@ -0,0 +1,232 @@ +/* + * tclAssem.c -- + * + * This file contains procedures to help assemble Tcl commands + * from an input source where commands may arrive in pieces, e.g. + * several lines of type-in corresponding to one command. + * + * Copyright 1990-1991 Regents of the University of California + * 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. The University of California + * makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without + * express or implied warranty. + */ +#include "internal.h" + +/* + * The structure below is the internal representation for a command + * buffer, which is used to hold a piece of a command until a full + * command is available. When a full command is available, it will + * be returned to the user, but it will also be retained in the buffer + * until the NEXT call to Tcl_AssembleCmd, at which point it will be + * removed. + */ + +typedef struct { + unsigned char *buffer; /* Storage for command being assembled. + * Malloc-ed, and grows as needed. */ + int bufSize; /* Total number of bytes in buffer. */ + int bytesUsed; /* Number of bytes in buffer currently + * occupied (0 means there is not a + * buffered incomplete command). */ +} CmdBuf; + +/* + * Default amount of space to allocate in command buffer: + */ + +#define CMD_BUF_SIZE 100 + +/* + *---------------------------------------------------------------------- + * + * Tcl_CreateCmdBuf -- + * + * Allocate and initialize a command buffer. + * + * Results: + * The return value is a token that may be passed to + * Tcl_AssembleCmd and Tcl_DeleteCmdBuf. + * + * Side effects: + * Memory is allocated. + * + *---------------------------------------------------------------------- + */ + +Tcl_CmdBuf +Tcl_CreateCmdBuf () +{ + register CmdBuf *cbPtr; + + cbPtr = (CmdBuf*) malloc (sizeof(CmdBuf)); + cbPtr->buffer = malloc (CMD_BUF_SIZE); + cbPtr->buffer[0] = '\0'; + cbPtr->bufSize = CMD_BUF_SIZE; + cbPtr->bytesUsed = 0; + return (Tcl_CmdBuf) cbPtr; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_DeleteCmdBuf -- + * + * Release all of the resources associated with a command buffer. + * The caller should never again use buffer again. + * + * Results: + * None. + * + * Side effects: + * Memory is released. + * + *---------------------------------------------------------------------- + */ + +void +Tcl_DeleteCmdBuf(buffer) + Tcl_CmdBuf buffer; /* Token for command buffer (return value + * from previous call to Tcl_CreateCmdBuf). */ +{ + register CmdBuf *cbPtr = (CmdBuf *) buffer; + + free (cbPtr->buffer); + free (cbPtr); +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_AssembleCmd -- + * + * This is a utility procedure to assist in situations where + * commands may be read piece-meal from some input source. Given + * some input text, it adds the text to an input buffer and returns + * whole commands when they are ready. + * + * Results: + * If the addition of string to any currently-buffered information + * results in one or more complete Tcl commands, then the return value + * is a pointer to the complete command(s). The command value will + * only be valid until the next call to this procedure with the + * same buffer. If the addition of string leaves an incomplete + * command at the end of the buffer, then NULL is returned. + * + * Side effects: + * If string leaves a command incomplete, the partial command + * information is buffered for use in later calls to this procedure. + * Once a command has been returned, that command is deleted from + * the buffer on the next call to this procedure. + * + *---------------------------------------------------------------------- + */ + +unsigned char * +Tcl_AssembleCmd (buffer, string) + Tcl_CmdBuf buffer; /* Token for a command buffer previously + * created by Tcl_CreateCmdBuf. */ + unsigned char *string; /* Bytes to be appended to command stream. + * Note: if the string is zero length, + * then whatever is buffered will be + * considered to be a complete command + * regardless of whether parentheses are + * matched or not. */ +{ + register CmdBuf *cbPtr = (CmdBuf *) buffer; + int length, totalLength, c; + + /* + * If an empty string is passed in, just pretend the current + * command is complete, whether it really is or not. + */ + + length = strlen(string); + if (length == 0) { + cbPtr->buffer[cbPtr->bytesUsed] = 0; + cbPtr->bytesUsed = 0; + return cbPtr->buffer; + } + + /* + * Add the new information to the buffer. If the current buffer + * isn't large enough, grow it by at least a factor of two, or + * enough to hold the new text. + */ + + length = strlen(string); + totalLength = cbPtr->bytesUsed + length + 1; + if (totalLength > cbPtr->bufSize) { + unsigned int newSize; + unsigned char *newBuf; + + newSize = cbPtr->bufSize*2; + if (newSize < totalLength) { + newSize = totalLength; + } + newBuf = malloc (newSize); + strcpy(newBuf, cbPtr->buffer); + free(cbPtr->buffer); + cbPtr->buffer = newBuf; + cbPtr->bufSize = newSize; + } + strcpy(cbPtr->buffer+cbPtr->bytesUsed, string); + cbPtr->bytesUsed += length; + + /* + * See if there is now a complete command in the buffer. + */ + + c = cbPtr->buffer[cbPtr->bytesUsed-1]; + if ((c != '\n') && (c != ';')) { + return 0; + } + if (Tcl_CommandComplete(cbPtr->buffer)) { + cbPtr->bytesUsed = 0; + return cbPtr->buffer; + } + return 0; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_CommandComplete -- + * + * Given a partial or complete Tcl command, this procedure + * determines whether the command is complete in the sense + * of having matched braces and quotes and brackets. + * + * Results: + * 1 is returned if the command is complete, 0 otherwise. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +Tcl_CommandComplete(cmd) + unsigned char *cmd; /* Command to check. */ +{ + register unsigned char *p = cmd; + + p = cmd; + while (1) { + while (isspace(*p)) { + p++; + } + if (*p == 0) { + return 1; + } + p = TclWordEnd(p, 0); + if (*p == 0) { + return 0; + } + p++; + } +} diff --git a/src/libtcl/tclbasic.c b/src/libtcl/tclbasic.c new file mode 100644 index 0000000..268fe88 --- /dev/null +++ b/src/libtcl/tclbasic.c @@ -0,0 +1,1059 @@ +/* + * tclBasic.c -- + * + * Contains the basic facilities for TCL command interpretation, + * including interpreter creation and deletion, command creation + * and deletion, and command parsing and execution. + * + * Copyright 1987-1992 Regents of the University of California + * 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. The University of California + * makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without + * express or implied warranty. + */ +#include "internal.h" +#include + +/* + * The following structure defines all of the commands in the Tcl core, + * and the C procedures that execute them. + */ +typedef struct { + unsigned char *name; /* Name of command. */ + Tcl_CmdProc *proc; /* Procedure that executes command. */ +} CmdInfo; + +/* + * Built-in commands, and the procedures associated with them: + */ + +static CmdInfo builtin_cmds[] = { + /* + * Commands in the generic core: + */ + + {(unsigned char*) "append", Tcl_AppendCmd}, + {(unsigned char*) "array", Tcl_ArrayCmd}, + {(unsigned char*) "break", Tcl_BreakCmd}, + {(unsigned char*) "case", Tcl_CaseCmd}, + {(unsigned char*) "catch", Tcl_CatchCmd}, + {(unsigned char*) "concat", Tcl_ConcatCmd}, + {(unsigned char*) "continue", Tcl_ContinueCmd}, + {(unsigned char*) "error", Tcl_ErrorCmd}, + {(unsigned char*) "eval", Tcl_EvalCmd}, + {(unsigned char*) "expr", Tcl_ExprCmd}, + {(unsigned char*) "for", Tcl_ForCmd}, + {(unsigned char*) "foreach", Tcl_ForeachCmd}, + {(unsigned char*) "format", Tcl_FormatCmd}, + {(unsigned char*) "global", Tcl_GlobalCmd}, + {(unsigned char*) "if", Tcl_IfCmd}, + {(unsigned char*) "incr", Tcl_IncrCmd}, + {(unsigned char*) "info", Tcl_InfoCmd}, + {(unsigned char*) "join", Tcl_JoinCmd}, + {(unsigned char*) "lappend", Tcl_LappendCmd}, + {(unsigned char*) "lindex", Tcl_LindexCmd}, + {(unsigned char*) "linsert", Tcl_LinsertCmd}, + {(unsigned char*) "list", Tcl_ListCmd}, + {(unsigned char*) "llength", Tcl_LlengthCmd}, + {(unsigned char*) "lrange", Tcl_LrangeCmd}, + {(unsigned char*) "lreplace", Tcl_LreplaceCmd}, + {(unsigned char*) "lsearch", Tcl_LsearchCmd}, + {(unsigned char*) "lsort", Tcl_LsortCmd}, + {(unsigned char*) "proc", Tcl_ProcCmd}, + {(unsigned char*) "regexp", Tcl_RegexpCmd}, + {(unsigned char*) "regsub", Tcl_RegsubCmd}, + {(unsigned char*) "rename", Tcl_RenameCmd}, + {(unsigned char*) "return", Tcl_ReturnCmd}, + {(unsigned char*) "scan", Tcl_ScanCmd}, + {(unsigned char*) "set", Tcl_SetCmd}, + {(unsigned char*) "split", Tcl_SplitCmd}, + {(unsigned char*) "string", Tcl_StringCmd}, + {(unsigned char*) "trace", Tcl_TraceCmd}, + {(unsigned char*) "unset", Tcl_UnsetCmd}, + {(unsigned char*) "uplevel", Tcl_UplevelCmd}, + {(unsigned char*) "upvar", Tcl_UpvarCmd}, + {(unsigned char*) "while", Tcl_WhileCmd}, + + /* + * Commands in the UNIX core: + */ +#ifdef TCL_FILE_CMDS + {(unsigned char*) "glob", Tcl_GlobCmd}, + {(unsigned char*) "cd", Tcl_CdCmd}, + {(unsigned char*) "close", Tcl_CloseCmd}, + {(unsigned char*) "eof", Tcl_EofCmd}, + {(unsigned char*) "exit", Tcl_ExitCmd}, + {(unsigned char*) "file", Tcl_FileCmd}, + {(unsigned char*) "flush", Tcl_FlushCmd}, + {(unsigned char*) "gets", Tcl_GetsCmd}, + {(unsigned char*) "open", Tcl_OpenCmd}, + {(unsigned char*) "puts", Tcl_PutsCmd}, + {(unsigned char*) "pwd", Tcl_PwdCmd}, + {(unsigned char*) "read", Tcl_ReadCmd}, + {(unsigned char*) "seek", Tcl_SeekCmd}, + {(unsigned char*) "source", Tcl_SourceCmd}, + {(unsigned char*) "tell", Tcl_TellCmd}, +#endif + {0, 0} +}; + +/* + *---------------------------------------------------------------------- + * + * Tcl_CreateInterp -- + * + * Create a new TCL command interpreter. + * + * Results: + * The return value is a token for the interpreter, which may be + * used in calls to procedures like Tcl_CreateCmd, Tcl_Eval, or + * Tcl_DeleteInterp. + * + * Side effects: + * The command interpreter is initialized with an empty variable + * table and the built-in commands. + * + *---------------------------------------------------------------------- + */ + +Tcl_Interp * +Tcl_CreateInterp () +{ + Interp *iPtr; + Command *c; + CmdInfo *ci; + int i; + + iPtr = (Interp*) malloc (sizeof(Interp)); + iPtr->result = iPtr->resultSpace; + iPtr->freeProc = 0; + iPtr->errorLine = 0; + Tcl_InitHashTable (&iPtr->commandTable, TCL_STRING_KEYS); + Tcl_InitHashTable (&iPtr->globalTable, TCL_STRING_KEYS); + iPtr->numLevels = 0; + iPtr->framePtr = 0; + iPtr->varFramePtr = 0; + iPtr->activeTracePtr = 0; + iPtr->numEvents = 0; + iPtr->events = 0; + iPtr->curEvent = 0; + iPtr->curEventNum = 0; + iPtr->revPtr = 0; + iPtr->historyFirst = 0; + iPtr->revDisables = 1; + iPtr->evalFirst = iPtr->evalLast = 0; + iPtr->appendResult = 0; + iPtr->appendAvl = 0; + iPtr->appendUsed = 0; + iPtr->numFiles = 0; + iPtr->filePtrArray = 0; + for (i = 0; i < NUM_REGEXPS; i++) { + iPtr->patterns[i] = 0; + iPtr->patLengths[i] = -1; + iPtr->regexps[i] = 0; + } + iPtr->cmdCount = 0; + iPtr->noEval = 0; + iPtr->scriptFile = 0; + iPtr->flags = 0; + iPtr->tracePtr = 0; + iPtr->resultSpace[0] = 0; + + /* + * Create the built-in commands. Do it here, rather than calling + * Tcl_CreateCommand, because it's faster (there's no need to + * check for a pre-existing command by the same name). + */ + for (ci = builtin_cmds; ci->name != 0; ci++) { + int new; + Tcl_HashEntry *he; + + he = Tcl_CreateHashEntry (&iPtr->commandTable, ci->name, &new); + if (new) { + c = (Command*) malloc (sizeof(Command)); + c->proc = ci->proc; + c->clientData = (void*) 0; + c->deleteProc = 0; + Tcl_SetHashValue (he, c); + } + } +#ifdef TCL_ENV_CMDS + TclSetupEnv ((Tcl_Interp *) iPtr); +#endif + return (Tcl_Interp *) iPtr; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_DeleteInterp -- + * + * Delete an interpreter and free up all of the resources associated + * with it. + * + * Results: + * None. + * + * Side effects: + * The interpreter is destroyed. The caller should never again + * use the interp token. + * + *---------------------------------------------------------------------- + */ + +void +Tcl_DeleteInterp(interp) + Tcl_Interp *interp; /* Token for command interpreter (returned + * by a previous call to Tcl_CreateInterp). */ +{ + Interp *iPtr = (Interp *) interp; + Tcl_HashEntry *he; + Tcl_HashSearch search; + register Command *c; + int i; + + /* + * If the interpreter is in use, delay the deletion until later. + */ + + iPtr->flags |= DELETED; + if (iPtr->numLevels != 0) { + return; + } + + /* + * Free up any remaining resources associated with the + * interpreter. + */ + + for (he = Tcl_FirstHashEntry(&iPtr->commandTable, &search); + he != 0; he = Tcl_NextHashEntry(&search)) { + c = (Command *) Tcl_GetHashValue(he); + if (c->deleteProc != 0) { + (*c->deleteProc)(c->clientData); + } + free (c); + } + Tcl_DeleteHashTable(&iPtr->commandTable); + TclDeleteVars(iPtr, &iPtr->globalTable); + if (iPtr->events != 0) { + int i; + + for (i = 0; i < iPtr->numEvents; i++) { + free(iPtr->events[i].command); + } + free (iPtr->events); + } + while (iPtr->revPtr != 0) { + HistoryRev *nextPtr = iPtr->revPtr->nextPtr; + + free (iPtr->revPtr); + iPtr->revPtr = nextPtr; + } + if (iPtr->appendResult != 0) { + free(iPtr->appendResult); + } +#ifdef TCL_FILE_CMDS + if (iPtr->numFiles > 0) { + for (i = 0; i < iPtr->numFiles; i++) { + OpenFile *filePtr; + + filePtr = iPtr->filePtrArray[i]; + if (filePtr == 0) { + continue; + } + if (i >= 3) { + fclose(filePtr->f); + if (filePtr->f2 != 0) { + fclose(filePtr->f2); + } + if (filePtr->numPids > 0) { + /* Tcl_DetachPids(filePtr->numPids, filePtr->pidPtr); */ + free (filePtr->pidPtr); + } + } + free (filePtr); + } + free (iPtr->filePtrArray); + } +#endif + for (i = 0; i < NUM_REGEXPS; i++) { + if (iPtr->patterns[i] == 0) { + break; + } + free (iPtr->patterns[i]); + free (iPtr->regexps[i]); + } + while (iPtr->tracePtr != 0) { + Trace *nextPtr = iPtr->tracePtr->nextPtr; + + free (iPtr->tracePtr); + iPtr->tracePtr = nextPtr; + } + free (iPtr); +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_CreateCommand -- + * + * Define a new command in a command table. + * + * Results: + * None. + * + * Side effects: + * If a command named cmdName already exists for interp, it is + * deleted. In the future, when cmdName is seen as the name of + * a command by Tcl_Eval, proc will be called. When the command + * is deleted from the table, deleteProc will be called. See the + * manual entry for details on the calling sequence. + * + *---------------------------------------------------------------------- + */ + +void +Tcl_CreateCommand(interp, cmdName, proc, clientData, deleteProc) + Tcl_Interp *interp; /* Token for command interpreter (returned + * by a previous call to Tcl_CreateInterp). */ + unsigned char *cmdName; /* Name of command. */ + Tcl_CmdProc *proc; /* Command procedure to associate with + * cmdName. */ + void *clientData; /* Arbitrary one-word value to pass to proc. */ + Tcl_CmdDeleteProc *deleteProc; + /* If not NULL, gives a procedure to call when + * this command is deleted. */ +{ + Interp *iPtr = (Interp *) interp; + register Command *c; + Tcl_HashEntry *he; + int new; + + he = Tcl_CreateHashEntry(&iPtr->commandTable, cmdName, &new); + if (!new) { + /* + * Command already exists: delete the old one. + */ + + c = (Command *) Tcl_GetHashValue(he); + if (c->deleteProc != 0) { + (*c->deleteProc)(c->clientData); + } + } else { + c = (Command*) malloc (sizeof(Command)); + Tcl_SetHashValue(he, c); + } + c->proc = proc; + c->clientData = clientData; + c->deleteProc = deleteProc; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_DeleteCommand -- + * + * Remove the given command from the given interpreter. + * + * Results: + * 0 is returned if the command was deleted successfully. + * -1 is returned if there didn't exist a command by that + * name. + * + * Side effects: + * CmdName will no longer be recognized as a valid command for + * interp. + * + *---------------------------------------------------------------------- + */ + +int +Tcl_DeleteCommand(interp, cmdName) + Tcl_Interp *interp; /* Token for command interpreter (returned + * by a previous call to Tcl_CreateInterp). */ + unsigned char *cmdName; /* Name of command to remove. */ +{ + Interp *iPtr = (Interp *) interp; + Tcl_HashEntry *he; + Command *c; + + he = Tcl_FindHashEntry(&iPtr->commandTable, cmdName); + if (he == 0) { + return -1; + } + c = (Command *) Tcl_GetHashValue(he); + if (c->deleteProc != 0) { + (*c->deleteProc)(c->clientData); + } + free (c); + Tcl_DeleteHashEntry(he); + return 0; +} + +/* + *----------------------------------------------------------------- + * + * Tcl_Eval -- + * + * Parse and execute a command in the Tcl language. + * + * Results: + * The return value is one of the return codes defined in tcl.hd + * (such as TCL_OK), and interp->result contains a string value + * to supplement the return code. The value of interp->result + * will persist only until the next call to Tcl_Eval: copy it or + * lose it! *TermPtr is filled in with the character just after + * the last one that was part of the command (usually a NULL + * character or a closing bracket). + * + * Side effects: + * Almost certainly; depends on the command. + * + *----------------------------------------------------------------- + */ + +int +Tcl_Eval(interp, cmd, flags, termPtr) + Tcl_Interp *interp; /* Token for command interpreter (returned + * by a previous call to Tcl_CreateInterp). */ + unsigned char *cmd; /* Pointer to TCL command to interpret. */ + int flags; /* OR-ed combination of flags like + * TCL_BRACKET_TERM and TCL_RECORD_BOUNDS. */ + unsigned char **termPtr; /* If non-NULL, fill in the address it points + * to with the address of the char. just after + * the last one that was part of cmd. See + * the man page for details on this. */ +{ + /* + * The storage immediately below is used to generate a copy + * of the command, after all argument substitutions. Pv will + * contain the argv values passed to the command procedure. + */ + +# define NUM_CHARS 200 + unsigned char copyStorage[NUM_CHARS]; + ParseValue pv; + unsigned char *oldBuffer; + + /* + * This procedure generates an (argv, argc) array for the command, + * It starts out with stack-allocated space but uses dynamically- + * allocated storage to increase it if needed. + */ + +# define NUM_ARGS 10 + unsigned char *(argStorage[NUM_ARGS]); + unsigned char **argv = argStorage; + int argc; + int argSize = NUM_ARGS; + + register unsigned char *src; /* Points to current character + * in cmd. */ + char termChar; /* Return when this character is found + * (either ']' or '\0'). Zero means + * that newlines terminate commands. */ + int result; /* Return value. */ + register Interp *iPtr = (Interp *) interp; + Tcl_HashEntry *he; + Command *c; + unsigned char *dummy; /* Make termPtr point here if it was + * originally NULL. */ + unsigned char *cmdStart; /* Points to first non-blank char. in + * command (used in calling trace + * procedures). */ + unsigned char *ellipsis = (unsigned char*) ""; + /* Used in setting errorInfo variable; + * set to "..." to indicate that not + * all of offending command is included + * in errorInfo. "" means that the + * command is all there. */ + register Trace *tracePtr; + + /* + * Initialize the result to an empty string and clear out any + * error information. This makes sure that we return an empty + * result if there are no commands in the command string. + */ + + Tcl_FreeResult((Tcl_Interp *) iPtr); + iPtr->result = iPtr->resultSpace; + iPtr->resultSpace[0] = 0; + result = TCL_OK; + + /* + * Check depth of nested calls to Tcl_Eval: if this gets too large, + * it's probably because of an infinite loop somewhere. + */ + + iPtr->numLevels++; + if (iPtr->numLevels > MAX_NESTING_DEPTH) { + iPtr->numLevels--; + iPtr->result = (unsigned char*) "too many nested calls to Tcl_Eval (infinite loop?)"; + return TCL_ERROR; + } + + /* + * Initialize the area in which command copies will be assembled. + */ + + pv.buffer = copyStorage; + pv.end = copyStorage + NUM_CHARS - 1; + pv.expandProc = TclExpandParseValue; + pv.clientData = (void*) 0; + + src = cmd; + if (flags & TCL_BRACKET_TERM) { + termChar = ']'; + } else { + termChar = 0; + } + if (termPtr == 0) { + termPtr = &dummy; + } + *termPtr = src; + cmdStart = src; + + /* + * There can be many sub-commands (separated by semi-colons or + * newlines) in one command string. This outer loop iterates over + * individual commands. + */ + + while (*src != termChar) { + iPtr->flags &= ~(ERR_IN_PROGRESS | ERROR_CODE_SET); + + /* + * Skim off leading white space and semi-colons, and skip + * comments. + */ + while (1) { + switch (*src) { + case '\t': + case '\v': + case '\f': + case '\r': + case '\n': + case ' ': + case ':': + ++src; + continue; + } + break; + } + if (*src == '#') { + for (src++; *src != 0; src++) { + if ((*src == '\n') && (src[-1] != '\\')) { + src++; + break; + } + } + continue; + } + cmdStart = src; + + /* + * Parse the words of the command, generating the argc and + * argv for the command procedure. May have to call + * TclParseWords several times, expanding the argv array + * between calls. + */ + + pv.next = oldBuffer = pv.buffer; + argc = 0; + while (1) { + int newArgs, maxArgs; + unsigned char **newArgv; + int i; + + /* + * Note: the "- 2" below guarantees that we won't use the + * last two argv slots here. One is for a NULL pointer to + * mark the end of the list, and the other is to leave room + * for inserting the command name "unknown" as the first + * argument (see below). + */ + + maxArgs = argSize - argc - 2; + result = TclParseWords((Tcl_Interp *) iPtr, src, flags, + maxArgs, termPtr, &newArgs, &argv[argc], &pv); + src = *termPtr; + if (result != TCL_OK) { + ellipsis = (unsigned char*) "..."; + goto done; + } + + /* + * Careful! Buffer space may have gotten reallocated while + * parsing words. If this happened, be sure to update all + * of the older argv pointers to refer to the new space. + */ + + if (oldBuffer != pv.buffer) { + int i; + + for (i = 0; i < argc; i++) { + argv[i] = pv.buffer + (argv[i] - oldBuffer); + } + oldBuffer = pv.buffer; + } + argc += newArgs; + if (newArgs < maxArgs) { + argv[argc] = 0; + break; + } + + /* + * Args didn't all fit in the current array. Make it bigger. + */ + + argSize *= 2; + newArgv = (unsigned char**) malloc ((unsigned) + argSize * sizeof(char *)); + for (i = 0; i < argc; i++) { + newArgv[i] = argv[i]; + } + if (argv != argStorage) { + free (argv); + } + argv = newArgv; + } + + /* + * If this is an empty command (or if we're just parsing + * commands without evaluating them), then just skip to the + * next command. + */ + + if ((argc == 0) || iPtr->noEval) { + continue; + } + argv[argc] = 0; + + /* + * Save information for the history module, if needed. + */ + + if (flags & TCL_RECORD_BOUNDS) { + iPtr->evalFirst = cmdStart; + iPtr->evalLast = src-1; + } + + /* + * Find the procedure to execute this command. If there isn't + * one, then see if there is a command "unknown". If so, + * invoke it instead, passing it the words of the original + * command as arguments. + */ + + he = Tcl_FindHashEntry(&iPtr->commandTable, argv[0]); + if (he == 0) { + int i; + + he = Tcl_FindHashEntry(&iPtr->commandTable, (unsigned char*) "unknown"); + if (he == 0) { + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, "invalid command name: \"", + argv[0], "\"", 0); + result = TCL_ERROR; + goto done; + } + for (i = argc; i >= 0; i--) { + argv[i+1] = argv[i]; + } + argv[0] = (unsigned char*) "unknown"; + argc++; + } + c = (Command *) Tcl_GetHashValue(he); + + /* + * Call trace procedures, if any. + */ + + for (tracePtr = iPtr->tracePtr; tracePtr != 0; + tracePtr = tracePtr->nextPtr) { + char saved; + + if (tracePtr->level < iPtr->numLevels) { + continue; + } + saved = *src; + *src = 0; + (*tracePtr->proc)(tracePtr->clientData, interp, iPtr->numLevels, + cmdStart, c->proc, c->clientData, argc, argv); + *src = saved; + } + + /* + * At long last, invoke the command procedure. Reset the + * result to its default empty value first (it could have + * gotten changed by earlier commands in the same command + * string). + */ + + iPtr->cmdCount++; + Tcl_FreeResult ((Tcl_Interp*) iPtr); + iPtr->result = iPtr->resultSpace; + iPtr->resultSpace[0] = 0; + result = (*c->proc)(c->clientData, interp, argc, argv); + if (result != TCL_OK) { + break; + } + } + + /* + * Free up any extra resources that were allocated. + */ + + done: + if (pv.buffer != copyStorage) { + free (pv.buffer); + } + if (argv != argStorage) { + free (argv); + } + iPtr->numLevels--; + if (iPtr->numLevels == 0) { + if (result == TCL_RETURN) { + result = TCL_OK; + } + if ((result != TCL_OK) && (result != TCL_ERROR)) { + Tcl_ResetResult(interp); + if (result == TCL_BREAK) { + iPtr->result = (unsigned char*) "invoked \"break\" outside of a loop"; + } else if (result == TCL_CONTINUE) { + iPtr->result = (unsigned char*) "invoked \"continue\" outside of a loop"; + } else { + iPtr->result = iPtr->resultSpace; + sprintf(iPtr->resultSpace, "command returned bad code: %d", + result); + } + result = TCL_ERROR; + } + if (iPtr->flags & DELETED) { + Tcl_DeleteInterp(interp); + } + } + + /* + * If an error occurred, record information about what was being + * executed when the error occurred. + */ + + if ((result == TCL_ERROR) && !(iPtr->flags & ERR_ALREADY_LOGGED)) { + int numChars; + register unsigned char *p; + + /* + * Compute the line number where the error occurred. + */ + + iPtr->errorLine = 1; + for (p = cmd; p != cmdStart; p++) { + if (*p == '\n') { + iPtr->errorLine++; + } + } + for ( ; isspace(*p) || (*p == ';'); p++) { + if (*p == '\n') { + iPtr->errorLine++; + } + } + + /* + * Figure out how much of the command to print in the error + * message (up to a certain number of characters, or up to + * the first new-line). + */ + + numChars = src - cmdStart; + if (numChars > (NUM_CHARS-50)) { + numChars = NUM_CHARS-50; + ellipsis = (unsigned char*) " ..."; + } + + if (!(iPtr->flags & ERR_IN_PROGRESS)) { + sprintf(copyStorage, "\n while executing\n\"%.*s%s\"", + numChars, cmdStart, ellipsis); + } else { + sprintf(copyStorage, "\n invoked from within\n\"%.*s%s\"", + numChars, cmdStart, ellipsis); + } + Tcl_AddErrorInfo(interp, copyStorage); + iPtr->flags &= ~ERR_ALREADY_LOGGED; + } else { + iPtr->flags &= ~ERR_ALREADY_LOGGED; + } + return result; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_CreateTrace -- + * + * Arrange for a procedure to be called to trace command execution. + * + * Results: + * The return value is a token for the trace, which may be passed + * to Tcl_DeleteTrace to eliminate the trace. + * + * Side effects: + * From now on, proc will be called just before a command procedure + * is called to execute a Tcl command. Calls to proc will have the + * following form: + * + * void + * proc(clientData, interp, level, command, cmdProc, cmdClientData, + * argc, argv) + * void *clientData; + * Tcl_Interp *interp; + * int level; + * unsigned char *command; + * int (*cmdProc)(); + * void *cmdClientData; + * int argc; + * unsigned char **argv; + * { + * } + * + * The clientData and interp arguments to proc will be the same + * as the corresponding arguments to this procedure. Level gives + * the nesting level of command interpretation for this interpreter + * (0 corresponds to top level). Command gives the ASCII text of + * the raw command, cmdProc and cmdClientData give the procedure that + * will be called to process the command and the ClientData value it + * will receive, and argc and argv give the arguments to the + * command, after any argument parsing and substitution. Proc + * does not return a value. + * + *---------------------------------------------------------------------- + */ + +Tcl_Trace +Tcl_CreateTrace(interp, level, proc, clientData) + Tcl_Interp *interp; /* Interpreter in which to create the trace. */ + int level; /* Only call proc for commands at nesting level + * <= level (1 => top level). */ + Tcl_CmdTraceProc *proc; /* Procedure to call before executing each + * command. */ + void *clientData; /* Arbitrary one-word value to pass to proc. */ +{ + register Trace *tracePtr; + register Interp *iPtr = (Interp *) interp; + + tracePtr = (Trace*) malloc (sizeof(Trace)); + tracePtr->level = level; + tracePtr->proc = proc; + tracePtr->clientData = clientData; + tracePtr->nextPtr = iPtr->tracePtr; + iPtr->tracePtr = tracePtr; + + return (Tcl_Trace) tracePtr; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_DeleteTrace -- + * + * Remove a trace. + * + * Results: + * None. + * + * Side effects: + * From now on there will be no more calls to the procedure given + * in trace. + * + *---------------------------------------------------------------------- + */ + +void +Tcl_DeleteTrace(interp, trace) + Tcl_Interp *interp; /* Interpreter that contains trace. */ + Tcl_Trace trace; /* Token for trace (returned previously by + * Tcl_CreateTrace). */ +{ + register Interp *iPtr = (Interp *) interp; + register Trace *tracePtr = (Trace *) trace; + register Trace *tracePtr2; + + if (iPtr->tracePtr == tracePtr) { + iPtr->tracePtr = tracePtr->nextPtr; + free (tracePtr); + } else { + for (tracePtr2 = iPtr->tracePtr; tracePtr2 != 0; + tracePtr2 = tracePtr2->nextPtr) { + if (tracePtr2->nextPtr == tracePtr) { + tracePtr2->nextPtr = tracePtr->nextPtr; + free (tracePtr); + return; + } + } + } +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_AddErrorInfo -- + * + * Add information to a message being accumulated that describes + * the current error. + * + * Results: + * None. + * + * Side effects: + * The contents of message are added to the "errorInfo" variable. + * If Tcl_Eval has been called since the current value of errorInfo + * was set, errorInfo is cleared before adding the new message. + * + *---------------------------------------------------------------------- + */ + +void +Tcl_AddErrorInfo(interp, message) + Tcl_Interp *interp; /* Interpreter to which error information + * pertains. */ + unsigned char *message; /* Message to record. */ +{ + register Interp *iPtr = (Interp *) interp; + + /* + * If an error is already being logged, then the new errorInfo + * is the concatenation of the old info and the new message. + * If this is the first piece of info for the error, then the + * new errorInfo is the concatenation of the message in + * interp->result and the new message. + */ + + if (!(iPtr->flags & ERR_IN_PROGRESS)) { + Tcl_SetVar2(interp, (unsigned char*) "errorInfo", 0, interp->result, + TCL_GLOBAL_ONLY); + iPtr->flags |= ERR_IN_PROGRESS; + + /* + * If the errorCode variable wasn't set by the code that generated + * the error, set it to "NONE". + */ + + if (!(iPtr->flags & ERROR_CODE_SET)) { + Tcl_SetVar2(interp, (unsigned char*) "errorCode", 0, + (unsigned char*) "NONE", TCL_GLOBAL_ONLY); + } + } + Tcl_SetVar2(interp, (unsigned char*) "errorInfo", 0, message, + TCL_GLOBAL_ONLY|TCL_APPEND_VALUE); +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_VarEval -- + * + * Given a variable number of string arguments, concatenate them + * all together and execute the result as a Tcl command. + * + * Results: + * A standard Tcl return result. An error message or other + * result may be left in interp->result. + * + * Side effects: + * Depends on what was done by the command. + * + *---------------------------------------------------------------------- + */ + /* VARARGS2 */ /* ARGSUSED */ +int +Tcl_VarEval (Tcl_Interp *interp,/* Interpreter in which to execute command. */ + ...) /* One or more strings to concatenate, + * terminated with a NULL string. */ +{ + va_list argList; +#define FIXED_SIZE 200 + unsigned char fixedSpace[FIXED_SIZE+1]; + int spaceAvl, spaceUsed, length; + unsigned char *string, *cmd; + int result; + + /* + * Copy the strings one after the other into a single larger + * string. Use stack-allocated space for small commands, but if + * the commands gets too large than call mem_alloc to create the + * space. + */ + va_start(argList, interp); + spaceAvl = FIXED_SIZE; + spaceUsed = 0; + cmd = fixedSpace; + while (1) { + string = va_arg(argList, unsigned char *); + if (string == 0) { + break; + } + length = strlen(string); + if ((spaceUsed + length) > spaceAvl) { + unsigned char *new; + + spaceAvl = spaceUsed + length; + spaceAvl += spaceAvl/2; + new = malloc ((unsigned) spaceAvl); + memcpy ((void*) new, (void*) cmd, spaceUsed); + if (cmd != fixedSpace) { + free(cmd); + } + cmd = new; + } + strcpy(cmd + spaceUsed, string); + spaceUsed += length; + } + va_end(argList); + cmd[spaceUsed] = '\0'; + + result = Tcl_Eval(interp, cmd, 0, 0); + if (cmd != fixedSpace) { + free(cmd); + } + return result; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_GlobalEval -- + * + * Evaluate a command at global level in an interpreter. + * + * Results: + * A standard Tcl result is returned, and interp->result is + * modified accordingly. + * + * Side effects: + * The command string is executed in interp, and the execution + * is carried out in the variable context of global level (no + * procedures active), just as if an "uplevel #0" command were + * being executed. + * + *---------------------------------------------------------------------- + */ + +int +Tcl_GlobalEval(interp, command) + Tcl_Interp *interp; /* Interpreter in which to evaluate command. */ + unsigned char *command; /* Command to evaluate. */ +{ + register Interp *iPtr = (Interp *) interp; + int result; + CallFrame *savedVarFramePtr; + + savedVarFramePtr = iPtr->varFramePtr; + iPtr->varFramePtr = 0; + result = Tcl_Eval(interp, command, 0, 0); + iPtr->varFramePtr = savedVarFramePtr; + return result; +} diff --git a/src/libtcl/tclcmdah.c b/src/libtcl/tclcmdah.c new file mode 100644 index 0000000..a3f7923 --- /dev/null +++ b/src/libtcl/tclcmdah.c @@ -0,0 +1,885 @@ +/* + * tclCmdAH.c -- + * + * This file contains the top-level command routines for most of + * the Tcl built-in commands whose names begin with the letters + * A to H. + * + * Copyright 1987-1991 Regents of the University of California + * 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. The University of California + * makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without + * express or implied warranty. + */ +#include "internal.h" + +/* + *---------------------------------------------------------------------- + * + * Tcl_BreakCmd -- + * + * This procedure is invoked to process the "break" Tcl command. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *---------------------------------------------------------------------- + */ + + /* ARGSUSED */ +int +Tcl_BreakCmd(dummy, interp, argc, argv) + void *dummy; /* Not used. */ + Tcl_Interp *interp; /* Current interpreter. */ + int argc; /* Number of arguments. */ + unsigned char **argv; /* Argument strings. */ +{ + if (argc != 1) { + Tcl_AppendResult(interp, "wrong # args: should be \"", + argv[0], "\"", 0); + return TCL_ERROR; + } + return TCL_BREAK; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_CaseCmd -- + * + * This procedure is invoked to process the "case" Tcl command. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *---------------------------------------------------------------------- + */ + + /* ARGSUSED */ +int +Tcl_CaseCmd(dummy, interp, argc, argv) + void *dummy; /* Not used. */ + Tcl_Interp *interp; /* Current interpreter. */ + int argc; /* Number of arguments. */ + unsigned char **argv; /* Argument strings. */ +{ + int i, result; + int body; + unsigned char *string; + int caseArgc, splitArgs; + unsigned char **caseArgv; + + if (argc < 3) { + Tcl_AppendResult(interp, "wrong # args: should be \"", + argv[0], " string ?in? patList body ... ?default body?\"", 0); + return TCL_ERROR; + } + string = argv[1]; + body = -1; + if (strcmp(argv[2], (unsigned char*) "in") == 0) { + i = 3; + } else { + i = 2; + } + caseArgc = argc - i; + caseArgv = argv + i; + + /* + * If all of the pattern/command pairs are lumped into a single + * argument, split them out again. + */ + + splitArgs = 0; + if (caseArgc == 1) { + result = Tcl_SplitList(interp, caseArgv[0], &caseArgc, &caseArgv); + if (result != TCL_OK) { + return result; + } + splitArgs = 1; + } + + for (i = 0; i < caseArgc; i += 2) { + int patArgc, j; + unsigned char **patArgv; + register unsigned char *p; + + if (i == (caseArgc-1)) { + interp->result = (unsigned char*) "extra case pattern with no body"; + result = TCL_ERROR; + goto cleanup; + } + + /* + * Check for special case of single pattern (no list) with + * no backslash sequences. + */ + + for (p = caseArgv[i]; *p != 0; p++) { + if (isspace(*p) || (*p == '\\')) { + break; + } + } + if (*p == 0) { + if ((*caseArgv[i] == 'd') + && (strcmp(caseArgv[i], (unsigned char*) "default") == 0)) { + body = i+1; + } + if (Tcl_StringMatch(string, caseArgv[i])) { + body = i+1; + goto match; + } + continue; + } + + /* + * Break up pattern lists, then check each of the patterns + * in the list. + */ + + result = Tcl_SplitList(interp, caseArgv[i], &patArgc, &patArgv); + if (result != TCL_OK) { + goto cleanup; + } + for (j = 0; j < patArgc; j++) { + if (Tcl_StringMatch(string, patArgv[j])) { + body = i+1; + break; + } + } + free (patArgv); + if (j < patArgc) { + break; + } + } + + match: + if (body != -1) { + result = Tcl_Eval(interp, caseArgv[body], 0, 0); + if (result == TCL_ERROR) { + unsigned char msg[100]; + sprintf(msg, "\n (\"%.50s\" arm line %d)", caseArgv[body-1], + interp->errorLine); + Tcl_AddErrorInfo(interp, msg); + } + goto cleanup; + } + + /* + * Nothing matched: return nothing. + */ + + result = TCL_OK; + + cleanup: + if (splitArgs) { + free (caseArgv); + } + return result; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_CatchCmd -- + * + * This procedure is invoked to process the "catch" Tcl command. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *---------------------------------------------------------------------- + */ + + /* ARGSUSED */ +int +Tcl_CatchCmd(dummy, interp, argc, argv) + void *dummy; /* Not used. */ + Tcl_Interp *interp; /* Current interpreter. */ + int argc; /* Number of arguments. */ + unsigned char **argv; /* Argument strings. */ +{ + int result; + + if ((argc != 2) && (argc != 3)) { + Tcl_AppendResult(interp, "wrong # args: should be \"", + argv[0], " command ?varName?\"", 0); + return TCL_ERROR; + } + result = Tcl_Eval(interp, argv[1], 0, 0); + if (argc == 3) { + if (Tcl_SetVar(interp, argv[2], interp->result, 0) == 0) { + Tcl_SetResult(interp, (unsigned char*) "couldn't save command result in variable", + TCL_STATIC); + return TCL_ERROR; + } + } + Tcl_ResetResult(interp); + sprintf(interp->result, "%d", result); + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_ConcatCmd -- + * + * This procedure is invoked to process the "concat" Tcl command. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *---------------------------------------------------------------------- + */ + + /* ARGSUSED */ +int +Tcl_ConcatCmd(dummy, interp, argc, argv) + void *dummy; /* Not used. */ + Tcl_Interp *interp; /* Current interpreter. */ + int argc; /* Number of arguments. */ + unsigned char **argv; /* Argument strings. */ +{ + if (argc == 1) { + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " arg ?arg ...?\"", 0); + return TCL_ERROR; + } + + interp->result = Tcl_Concat (argc-1, argv+1); + interp->freeProc = (Tcl_FreeProc *) free; + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_ContinueCmd -- + * + * This procedure is invoked to process the "continue" Tcl command. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *---------------------------------------------------------------------- + */ + + /* ARGSUSED */ +int +Tcl_ContinueCmd(dummy, interp, argc, argv) + void *dummy; /* Not used. */ + Tcl_Interp *interp; /* Current interpreter. */ + int argc; /* Number of arguments. */ + unsigned char **argv; /* Argument strings. */ +{ + if (argc != 1) { + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + "\"", 0); + return TCL_ERROR; + } + return TCL_CONTINUE; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_ErrorCmd -- + * + * This procedure is invoked to process the "error" Tcl command. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *---------------------------------------------------------------------- + */ + + /* ARGSUSED */ +int +Tcl_ErrorCmd(dummy, interp, argc, argv) + void *dummy; /* Not used. */ + Tcl_Interp *interp; /* Current interpreter. */ + int argc; /* Number of arguments. */ + unsigned char **argv; /* Argument strings. */ +{ + Interp *iPtr = (Interp *) interp; + + if ((argc < 2) || (argc > 4)) { + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " message ?errorInfo? ?errorCode?\"", 0); + return TCL_ERROR; + } + if ((argc >= 3) && (argv[2][0] != 0)) { + Tcl_AddErrorInfo(interp, argv[2]); + iPtr->flags |= ERR_ALREADY_LOGGED; + } + if (argc == 4) { + Tcl_SetVar2(interp, (unsigned char*) "errorCode", 0, argv[3], + TCL_GLOBAL_ONLY); + iPtr->flags |= ERROR_CODE_SET; + } + Tcl_SetResult(interp, argv[1], TCL_VOLATILE); + return TCL_ERROR; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_EvalCmd -- + * + * This procedure is invoked to process the "eval" Tcl command. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *---------------------------------------------------------------------- + */ + + /* ARGSUSED */ +int +Tcl_EvalCmd(dummy, interp, argc, argv) + void *dummy; /* Not used. */ + Tcl_Interp *interp; /* Current interpreter. */ + int argc; /* Number of arguments. */ + unsigned char **argv; /* Argument strings. */ +{ + int result; + unsigned char *cmd; + + if (argc < 2) { + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " arg ?arg ...?\"", 0); + return TCL_ERROR; + } + if (argc == 2) { + result = Tcl_Eval(interp, argv[1], 0, 0); + } else { + + /* + * More than one argument: concatenate them together with spaces + * between, then evaluate the result. + */ + + cmd = Tcl_Concat (argc-1, argv+1); + result = Tcl_Eval(interp, cmd, 0, 0); + free(cmd); + } + if (result == TCL_ERROR) { + unsigned char msg[60]; + sprintf(msg, "\n (\"eval\" body line %d)", interp->errorLine); + Tcl_AddErrorInfo(interp, msg); + } + return result; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_ExprCmd -- + * + * This procedure is invoked to process the "expr" Tcl command. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *---------------------------------------------------------------------- + */ + + /* ARGSUSED */ +int +Tcl_ExprCmd(dummy, interp, argc, argv) + void *dummy; /* Not used. */ + Tcl_Interp *interp; /* Current interpreter. */ + int argc; /* Number of arguments. */ + unsigned char **argv; /* Argument strings. */ +{ + if (argc != 2) { + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " expression\"", 0); + return TCL_ERROR; + } + + return Tcl_ExprString(interp, argv[1]); +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_ForCmd -- + * + * This procedure is invoked to process the "for" Tcl command. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *---------------------------------------------------------------------- + */ + + /* ARGSUSED */ +int +Tcl_ForCmd(dummy, interp, argc, argv) + void *dummy; /* Not used. */ + Tcl_Interp *interp; /* Current interpreter. */ + int argc; /* Number of arguments. */ + unsigned char **argv; /* Argument strings. */ +{ + int result, value; + + if (argc != 5) { + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " start test next command\"", 0); + return TCL_ERROR; + } + + result = Tcl_Eval(interp, argv[1], 0, 0); + if (result != TCL_OK) { + if (result == TCL_ERROR) { + Tcl_AddErrorInfo(interp, (unsigned char*) "\n (\"for\" initial command)"); + } + return result; + } + while (1) { + result = Tcl_ExprBoolean(interp, argv[2], &value); + if (result != TCL_OK) { + return result; + } + if (!value) { + break; + } + result = Tcl_Eval(interp, argv[4], 0, 0); + if (result == TCL_CONTINUE) { + result = TCL_OK; + } else if (result != TCL_OK) { + if (result == TCL_ERROR) { + unsigned char msg[60]; + sprintf(msg, "\n (\"for\" body line %d)", interp->errorLine); + Tcl_AddErrorInfo(interp, msg); + } + break; + } + result = Tcl_Eval(interp, argv[3], 0, 0); + if (result == TCL_BREAK) { + break; + } else if (result != TCL_OK) { + if (result == TCL_ERROR) { + Tcl_AddErrorInfo(interp, (unsigned char*) "\n (\"for\" loop-end command)"); + } + return result; + } + } + if (result == TCL_BREAK) { + result = TCL_OK; + } + if (result == TCL_OK) { + Tcl_ResetResult(interp); + } + return result; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_ForeachCmd -- + * + * This procedure is invoked to process the "foreach" Tcl command. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *---------------------------------------------------------------------- + */ + + /* ARGSUSED */ +int +Tcl_ForeachCmd(dummy, interp, argc, argv) + void *dummy; /* Not used. */ + Tcl_Interp *interp; /* Current interpreter. */ + int argc; /* Number of arguments. */ + unsigned char **argv; /* Argument strings. */ +{ + int listArgc, i, result; + unsigned char **listArgv; + + if (argc != 4) { + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " varName list command\"", 0); + return TCL_ERROR; + } + + /* + * Break the list up into elements, and execute the command once + * for each value of the element. + */ + + result = Tcl_SplitList(interp, argv[2], &listArgc, &listArgv); + if (result != TCL_OK) { + return result; + } + for (i = 0; i < listArgc; i++) { + if (Tcl_SetVar(interp, argv[1], listArgv[i], 0) == 0) { + Tcl_SetResult(interp, (unsigned char*) "couldn't set loop variable", TCL_STATIC); + result = TCL_ERROR; + break; + } + + result = Tcl_Eval(interp, argv[3], 0, 0); + if (result != TCL_OK) { + if (result == TCL_CONTINUE) { + result = TCL_OK; + } else if (result == TCL_BREAK) { + result = TCL_OK; + break; + } else if (result == TCL_ERROR) { + unsigned char msg[100]; + sprintf(msg, "\n (\"foreach\" body line %d)", + interp->errorLine); + Tcl_AddErrorInfo(interp, msg); + break; + } else { + break; + } + } + } + free (listArgv); + if (result == TCL_OK) { + Tcl_ResetResult(interp); + } + return result; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_FormatCmd -- + * + * This procedure is invoked to process the "format" Tcl command. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *---------------------------------------------------------------------- + */ + + /* ARGSUSED */ +int +Tcl_FormatCmd(dummy, interp, argc, argv) + void *dummy; /* Not used. */ + Tcl_Interp *interp; /* Current interpreter. */ + int argc; /* Number of arguments. */ + unsigned char **argv; /* Argument strings. */ +{ + register unsigned char *format; /* Used to read characters from the format + * string. */ + unsigned char newFormat[40]; /* A new format specifier is generated here. */ + int width; /* Field width from field specifier, or 0 if + * no width given. */ + int precision; /* Field precision from field specifier, or 0 + * if no precision given. */ + int size; /* Number of bytes needed for result of + * conversion, based on type of conversion + * ("e", "s", etc.) and width from above. */ + unsigned char *oneWordValue = 0; /* Used to hold value to pass to sprintf, if + * it's a one-word value. */ + unsigned char *dst = interp->result; /* Where result is stored. Starts off at + * interp->resultSpace, but may get dynamically + * re-allocated if this isn't enough. */ + int dstSize = 0; /* Number of non-null characters currently + * stored at dst. */ + int dstSpace = TCL_RESULT_SIZE; + /* Total amount of storage space available + * in dst (not including null terminator. */ + int noPercent; /* Special case for speed: indicates there's + * no field specifier, just a string to copy. */ + unsigned char **curArg; /* Remainder of argv array. */ + int useShort; /* Value to be printed is short (half word). */ + + /* + * This procedure is a bit nasty. The goal is to use sprintf to + * do most of the dirty work. There are several problems: + * 1. this procedure can't trust its arguments. + * 2. we must be able to provide a large enough result area to hold + * whatever's generated. This is hard to estimate. + * 2. there's no way to move the arguments from argv to the call + * to sprintf in a reasonable way. This is particularly nasty + * because some of the arguments may be two-word values (doubles). + * So, what happens here is to scan the format string one % group + * at a time, making many individual calls to sprintf. + */ + + if (argc < 2) { + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " formatString ?arg arg ...?\"", 0); + return TCL_ERROR; + } + curArg = argv+2; + argc -= 2; + for (format = argv[1]; *format != 0; ) { + register unsigned char *newPtr = newFormat; + + width = precision = noPercent = useShort = 0; + + /* + * Get rid of any characters before the next field specifier. + * Collapse backslash sequences found along the way. + */ + + if (*format != '%') { + register unsigned char *p; + int bsSize; + + oneWordValue = p = format; + while ((*format != '%') && (*format != 0)) { + if (*format == '\\') { + *p = Tcl_Backslash(format, &bsSize); + if (*p != 0) { + p++; + } + format += bsSize; + } else { + *p = *format; + p++; + format++; + } + } + size = p - oneWordValue; + noPercent = 1; + goto doField; + } + + if (format[1] == '%') { + oneWordValue = format; + size = 1; + noPercent = 1; + format += 2; + goto doField; + } + + /* + * Parse off a field specifier, compute how many characters + * will be needed to store the result, and substitute for + * "*" size specifiers. + */ + + *newPtr = '%'; + newPtr++; + format++; + while ((*format == '-') || (*format == '#') || (*format == '0') + || (*format == ' ') || (*format == '+')) { + *newPtr = *format; + newPtr++; + format++; + } + if (isdigit(*format)) { + width = atoi(format); + do { + format++; + } while (isdigit(*format)); + } else if (*format == '*') { + if (argc <= 0) { + goto notEnoughArgs; + } + if (Tcl_GetInt(interp, *curArg, &width) != TCL_OK) { + goto fmtError; + } + argc--; + curArg++; + format++; + } + if (width != 0) { + sprintf(newPtr, "%d", width); + while (*newPtr != 0) { + newPtr++; + } + } + if (*format == '.') { + *newPtr = '.'; + newPtr++; + format++; + } + if (isdigit(*format)) { + precision = atoi(format); + do { + format++; + } while (isdigit(*format)); + } else if (*format == '*') { + if (argc <= 0) { + goto notEnoughArgs; + } + if (Tcl_GetInt(interp, *curArg, &precision) != TCL_OK) { + goto fmtError; + } + argc--; + curArg++; + format++; + } + if (precision != 0) { + sprintf(newPtr, "%d", precision); + while (*newPtr != 0) { + newPtr++; + } + } + if (*format == 'l') { + format++; + } else if (*format == 'h') { + useShort = 1; + *newPtr = 'h'; + newPtr++; + format++; + } + *newPtr = *format; + newPtr++; + *newPtr = 0; + if (argc <= 0) { + goto notEnoughArgs; + } + switch (*format) { + case 'D': + case 'O': + case 'U': + if (!useShort) { + newPtr++; + } else { + useShort = 0; + } + newPtr[-1] = tolower(*format); + newPtr[-2] = 'l'; + *newPtr = 0; + case 'd': + case 'o': + case 'u': + case 'x': + case 'X': + if (Tcl_GetInt(interp, *curArg, (void*) &oneWordValue) + != TCL_OK) { + goto fmtError; + } + size = 40; + break; + case 's': + oneWordValue = *curArg; + size = strlen(*curArg); + break; + case 'c': + if (Tcl_GetInt(interp, *curArg, (void*) &oneWordValue) + != TCL_OK) { + goto fmtError; + } + size = 1; + break; + case 0: + interp->result = (unsigned char*) + "format string ended in middle of field specifier"; + goto fmtError; + default: + sprintf(interp->result, + "bad field specifier \"%c\"", *format); + goto fmtError; + } + argc--; + curArg++; + format++; + + /* + * Make sure that there's enough space to hold the formatted + * result, then format it. + */ + + doField: + if (width > size) { + size = width; + } + if ((dstSize + size) > dstSpace) { + unsigned char *newDst; + int newSpace; + + newSpace = 2*(dstSize + size); + newDst = malloc ((unsigned) newSpace+1); + if (dstSize != 0) { + memcpy ((void*) newDst, (void*) dst, dstSize); + } + if (dstSpace != TCL_RESULT_SIZE) { + free (dst); + } + dst = newDst; + dstSpace = newSpace; + } + if (noPercent) { + memcpy ((void*) (dst+dstSize), (void*) oneWordValue, size); + dstSize += size; + dst[dstSize] = 0; + } else { + if (useShort) { + /* + * The double cast below is needed for a few machines + * (e.g. Pyramids as of 1/93) that don't like casts + * directly from pointers to shorts. + */ + sprintf(dst+dstSize, (char*) newFormat, (short) (int) oneWordValue); + } else { + sprintf(dst+dstSize, (char*) newFormat, oneWordValue); + } + dstSize += strlen(dst+dstSize); + } + } + + interp->result = dst; + if (dstSpace != TCL_RESULT_SIZE) { + interp->freeProc = (Tcl_FreeProc *) free; + } else { + interp->freeProc = 0; + } + return TCL_OK; + + notEnoughArgs: + interp->result = (unsigned char*) "not enough arguments for all format specifiers"; + fmtError: + if (dstSpace != TCL_RESULT_SIZE) { + free(dst); + } + return TCL_ERROR; +} diff --git a/src/libtcl/tclcmdil.c b/src/libtcl/tclcmdil.c new file mode 100644 index 0000000..fa02f82 --- /dev/null +++ b/src/libtcl/tclcmdil.c @@ -0,0 +1,1156 @@ +/* + * tclCmdIL.c -- + * + * This file contains the top-level command routines for most of + * the Tcl built-in commands whose names begin with the letters + * I through L. It contains only commands in the generic core + * (i.e. those that don't depend much upon UNIX facilities). + * + * Copyright 1987-1991 Regents of the University of California + * 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. The University of California + * makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without + * express or implied warranty. + */ +#include "internal.h" + +/* + * Forward declarations for procedures defined in this file: + */ + +static int SortCompareProc (const void *first, const void *second); + +/* + *---------------------------------------------------------------------- + * + * Tcl_IfCmd -- + * + * This procedure is invoked to process the "if" Tcl command. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *---------------------------------------------------------------------- + */ + + /* ARGSUSED */ +int +Tcl_IfCmd(dummy, interp, argc, argv) + void *dummy; /* Not used. */ + Tcl_Interp *interp; /* Current interpreter. */ + int argc; /* Number of arguments. */ + unsigned char **argv; /* Argument strings. */ +{ + int i, result, value; + + i = 1; + while (1) { + /* + * At this point in the loop, argv and argc refer to an expression + * to test, either for the main expression or an expression + * following an "elseif". The arguments after the expression must + * be "then" (optional) and a script to execute if the expression is + * true. + */ + + if (i >= argc) { + Tcl_AppendResult(interp, "wrong # args: no expression after \"", + argv[i-1], "\" argument", 0); + return TCL_ERROR; + } + result = Tcl_ExprBoolean(interp, argv[i], &value); + if (result != TCL_OK) { + return result; + } + i++; + if ((i < argc) && (strcmp(argv[i], (unsigned char*) "then") == 0)) { + i++; + } + if (i >= argc) { + Tcl_AppendResult(interp, "wrong # args: no script following \"", + argv[i-1], "\" argument", 0); + return TCL_ERROR; + } + if (value) { + return Tcl_Eval(interp, argv[i], 0, 0); + } + + /* + * The expression evaluated to false. Skip the command, then + * see if there is an "else" or "elseif" clause. + */ + + i++; + if (i >= argc) { + return TCL_OK; + } + if ((argv[i][0] == 'e') && (strcmp(argv[i], (unsigned char*) "elseif") == 0)) { + i++; + continue; + } + break; + } + + /* + * Couldn't find a "then" or "elseif" clause to execute. Check now + * for an "else" clause. We know that there's at least one more + * argument when we get here. + */ + + if (strcmp(argv[i], (unsigned char*) "else") == 0) { + i++; + if (i >= argc) { + Tcl_AppendResult(interp, + "wrong # args: no script following \"else\" argument", 0); + return TCL_ERROR; + } + } + return Tcl_Eval(interp, argv[i], 0, 0); +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_IncrCmd -- + * + * This procedure is invoked to process the "incr" Tcl command. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *---------------------------------------------------------------------- + */ + + /* ARGSUSED */ +int +Tcl_IncrCmd(dummy, interp, argc, argv) + void *dummy; /* Not used. */ + Tcl_Interp *interp; /* Current interpreter. */ + int argc; /* Number of arguments. */ + unsigned char **argv; /* Argument strings. */ +{ + int value; + unsigned char *oldString, *result; + unsigned char newString[30]; + + if ((argc != 2) && (argc != 3)) { + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " varName ?increment?\"", 0); + return TCL_ERROR; + } + + oldString = Tcl_GetVar(interp, argv[1], TCL_LEAVE_ERR_MSG); + if (oldString == 0) { + return TCL_ERROR; + } + if (Tcl_GetInt(interp, oldString, &value) != TCL_OK) { + Tcl_AddErrorInfo(interp, (unsigned char*) + "\n (reading value of variable to increment)"); + return TCL_ERROR; + } + if (argc == 2) { + value += 1; + } else { + int increment; + + if (Tcl_GetInt(interp, argv[2], &increment) != TCL_OK) { + Tcl_AddErrorInfo(interp, (unsigned char*) + "\n (reading increment)"); + return TCL_ERROR; + } + value += increment; + } + sprintf(newString, "%d", value); + result = Tcl_SetVar(interp, argv[1], newString, TCL_LEAVE_ERR_MSG); + if (result == 0) { + return TCL_ERROR; + } + interp->result = result; + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_InfoCmd -- + * + * This procedure is invoked to process the "info" Tcl command. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *---------------------------------------------------------------------- + */ + + /* ARGSUSED */ +int +Tcl_InfoCmd(dummy, interp, argc, argv) + void *dummy; /* Not used. */ + Tcl_Interp *interp; /* Current interpreter. */ + int argc; /* Number of arguments. */ + unsigned char **argv; /* Argument strings. */ +{ + register Interp *iPtr = (Interp *) interp; + int length; + char c; + Arg *argPtr; + Proc *procPtr; + Var *varPtr; + Command *cmdPtr; + Tcl_HashEntry *hPtr; + Tcl_HashSearch search; + + if (argc < 2) { + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " option ?arg arg ...?\"", 0); + return TCL_ERROR; + } + c = argv[1][0]; + length = strlen(argv[1]); + if ((c == 'a') && (strncmp(argv[1], (unsigned char*) "args", length)) == 0) { + if (argc != 3) { + Tcl_AppendResult(interp, "wrong # args: should be \"", + argv[0], " args procname\"", 0); + return TCL_ERROR; + } + procPtr = TclFindProc(iPtr, argv[2]); + if (procPtr == 0) { + infoNoSuchProc: + Tcl_AppendResult(interp, "\"", argv[2], + "\" isn't a procedure", 0); + return TCL_ERROR; + } + for (argPtr = procPtr->argPtr; argPtr != 0; + argPtr = argPtr->nextPtr) { + Tcl_AppendElement(interp, argPtr->name, 0); + } + return TCL_OK; + } else if ((c == 'b') && (strncmp(argv[1], (unsigned char*) "body", length)) == 0) { + if (argc != 3) { + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " body procname\"", 0); + return TCL_ERROR; + } + procPtr = TclFindProc(iPtr, argv[2]); + if (procPtr == 0) { + goto infoNoSuchProc; + } + iPtr->result = procPtr->command; + return TCL_OK; + } else if ((c == 'c') && (strncmp(argv[1], (unsigned char*) "cmdcount", length) == 0) + && (length >= 2)) { + if (argc != 2) { + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " cmdcount\"", 0); + return TCL_ERROR; + } + sprintf(iPtr->result, "%ld", iPtr->cmdCount); + return TCL_OK; + } else if ((c == 'c') && (strncmp(argv[1], (unsigned char*) "commands", length) == 0) + && (length >= 4)) { + if (argc > 3) { + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " commands [pattern]\"", 0); + return TCL_ERROR; + } + for (hPtr = Tcl_FirstHashEntry(&iPtr->commandTable, &search); + hPtr != 0; hPtr = Tcl_NextHashEntry(&search)) { + unsigned char *name = Tcl_GetHashKey(&iPtr->commandTable, hPtr); + if ((argc == 3) && !Tcl_StringMatch(name, argv[2])) { + continue; + } + Tcl_AppendElement(interp, name, 0); + } + return TCL_OK; + } else if ((c == 'c') && (strncmp(argv[1], (unsigned char*) "complete", length) == 0) + && (length >= 4)) { + if (argc != 3) { + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " complete command\"", 0); + return TCL_ERROR; + } + if (Tcl_CommandComplete(argv[2])) { + interp->result = (unsigned char*) "1"; + } else { + interp->result = (unsigned char*) "0"; + } + return TCL_OK; + } else if ((c == 'd') && (strncmp(argv[1], (unsigned char*) "default", length)) == 0) { + if (argc != 5) { + Tcl_AppendResult(interp, "wrong # args: should be \"", + argv[0], " default procname arg varname\"", 0); + return TCL_ERROR; + } + procPtr = TclFindProc(iPtr, argv[2]); + if (procPtr == 0) { + goto infoNoSuchProc; + } + for (argPtr = procPtr->argPtr; ; argPtr = argPtr->nextPtr) { + if (argPtr == 0) { + Tcl_AppendResult(interp, "procedure \"", argv[2], + "\" doesn't have an argument \"", argv[3], + "\"", 0); + return TCL_ERROR; + } + if (strcmp(argv[3], argPtr->name) == 0) { + if (argPtr->defValue != 0) { + if (Tcl_SetVar((Tcl_Interp *) iPtr, argv[4], + argPtr->defValue, 0) == 0) { + defStoreError: + Tcl_AppendResult(interp, + "couldn't store default value in variable \"", + argv[4], "\"", 0); + return TCL_ERROR; + } + iPtr->result = (unsigned char*) "1"; + } else { + if (Tcl_SetVar((Tcl_Interp *) iPtr, argv[4], (unsigned char*) "", 0) + == 0) { + goto defStoreError; + } + iPtr->result = (unsigned char*) "0"; + } + return TCL_OK; + } + } + } else if ((c == 'e') && (strncmp(argv[1], (unsigned char*) "exists", length) == 0)) { + unsigned char *p; + if (argc != 3) { + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " exists varName\"", 0); + return TCL_ERROR; + } + p = Tcl_GetVar((Tcl_Interp *) iPtr, argv[2], 0); + + /* + * The code below handles the special case where the name is for + * an array: Tcl_GetVar will reject this since you can't read + * an array variable without an index. + */ + + if (p == 0) { + Tcl_HashEntry *hPtr; + Var *varPtr; + + if (strchr(argv[2], '(') != 0) { + noVar: + iPtr->result = (unsigned char*) "0"; + return TCL_OK; + } + if (iPtr->varFramePtr == 0) { + hPtr = Tcl_FindHashEntry(&iPtr->globalTable, argv[2]); + } else { + hPtr = Tcl_FindHashEntry(&iPtr->varFramePtr->varTable, argv[2]); + } + if (hPtr == 0) { + goto noVar; + } + varPtr = (Var *) Tcl_GetHashValue(hPtr); + if (varPtr->flags & VAR_UPVAR) { + varPtr = (Var *) Tcl_GetHashValue(varPtr->value.upvarPtr); + } + if (!(varPtr->flags & VAR_ARRAY)) { + goto noVar; + } + } + iPtr->result = (unsigned char*) "1"; + return TCL_OK; + } else if ((c == 'g') && (strncmp(argv[1], (unsigned char*) "globals", length) == 0)) { + unsigned char *name; + + if (argc > 3) { + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " globals [pattern]\"", 0); + return TCL_ERROR; + } + for (hPtr = Tcl_FirstHashEntry(&iPtr->globalTable, &search); + hPtr != 0; hPtr = Tcl_NextHashEntry(&search)) { + varPtr = (Var *) Tcl_GetHashValue(hPtr); + if (varPtr->flags & VAR_UNDEFINED) { + continue; + } + name = Tcl_GetHashKey(&iPtr->globalTable, hPtr); + if ((argc == 3) && !Tcl_StringMatch(name, argv[2])) { + continue; + } + Tcl_AppendElement(interp, name, 0); + } + return TCL_OK; + } else if ((c == 'l') && (strncmp(argv[1], (unsigned char*) "level", length) == 0) + && (length >= 2)) { + if (argc == 2) { + if (iPtr->varFramePtr == 0) { + iPtr->result = (unsigned char*) "0"; + } else { + sprintf(iPtr->result, "%d", iPtr->varFramePtr->level); + } + return TCL_OK; + } else if (argc == 3) { + int level; + CallFrame *framePtr; + + if (Tcl_GetInt(interp, argv[2], &level) != TCL_OK) { + return TCL_ERROR; + } + if (level <= 0) { + if (iPtr->varFramePtr == 0) { + levelError: + Tcl_AppendResult(interp, "bad level \"", argv[2], + "\"", 0); + return TCL_ERROR; + } + level += iPtr->varFramePtr->level; + } + for (framePtr = iPtr->varFramePtr; framePtr != 0; + framePtr = framePtr->callerVarPtr) { + if (framePtr->level == level) { + break; + } + } + if (framePtr == 0) { + goto levelError; + } + iPtr->result = Tcl_Merge (framePtr->argc, framePtr->argv); + iPtr->freeProc = (Tcl_FreeProc *) free; + return TCL_OK; + } + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " level [number]\"", 0); + return TCL_ERROR; +#ifdef TCL_FILE_CMDS + } else if ((c == 'l') && (strncmp(argv[1], "library", length) == 0) + && (length >= 2)) { + if (argc != 2) { + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " library\"", 0); + return TCL_ERROR; + } + interp->result = getenv("TCL_LIBRARY"); + if (interp->result == 0) { +#ifdef TCL_LIBRARY + interp->result = TCL_LIBRARY; +#else + interp->result = "there is no Tcl library at this installation"; + return TCL_ERROR; +#endif + } + return TCL_OK; +#endif + } else if ((c == 'l') && (strncmp(argv[1], (unsigned char*) "locals", length) == 0) + && (length >= 2)) { + unsigned char *name; + + if (argc > 3) { + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " locals [pattern]\"", 0); + return TCL_ERROR; + } + if (iPtr->varFramePtr == 0) { + return TCL_OK; + } + for (hPtr = Tcl_FirstHashEntry(&iPtr->varFramePtr->varTable, &search); + hPtr != 0; hPtr = Tcl_NextHashEntry(&search)) { + varPtr = (Var *) Tcl_GetHashValue(hPtr); + if (varPtr->flags & (VAR_UNDEFINED|VAR_UPVAR)) { + continue; + } + name = Tcl_GetHashKey(&iPtr->varFramePtr->varTable, hPtr); + if ((argc == 3) && !Tcl_StringMatch(name, argv[2])) { + continue; + } + Tcl_AppendElement(interp, name, 0); + } + return TCL_OK; + } else if ((c == 'p') && (strncmp(argv[1], (unsigned char*) "procs", length)) == 0) { + if (argc > 3) { + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " procs [pattern]\"", 0); + return TCL_ERROR; + } + for (hPtr = Tcl_FirstHashEntry(&iPtr->commandTable, &search); + hPtr != 0; hPtr = Tcl_NextHashEntry(&search)) { + unsigned char *name = Tcl_GetHashKey(&iPtr->commandTable, hPtr); + + cmdPtr = (Command *) Tcl_GetHashValue(hPtr); + if (!TclIsProc(cmdPtr)) { + continue; + } + if ((argc == 3) && !Tcl_StringMatch(name, argv[2])) { + continue; + } + Tcl_AppendElement(interp, name, 0); + } + return TCL_OK; + } else if ((c == 's') && (strncmp(argv[1], (unsigned char*) "script", length) == 0)) { + if (argc != 2) { + Tcl_AppendResult(interp, "wrong # args: should be \"", + argv[0], " script\"", 0); + return TCL_ERROR; + } + if (iPtr->scriptFile != 0) { + interp->result = iPtr->scriptFile; + } + return TCL_OK; + } else if ((c == 't') && (strncmp(argv[1], (unsigned char*) "tclversion", length) == 0)) { + if (argc != 2) { + Tcl_AppendResult(interp, "wrong # args: should be \"", + argv[0], " tclversion\"", 0); + return TCL_ERROR; + } + + /* + * Note: TCL_VERSION below is expected to be set with a "-D" + * switch in the Makefile. + */ + + strcpy(iPtr->result, (unsigned char*) TCL_VERSION); + return TCL_OK; + } else if ((c == 'v') && (strncmp(argv[1], (unsigned char*) "vars", length)) == 0) { + Tcl_HashTable *tablePtr; + unsigned char *name; + + if (argc > 3) { + Tcl_AppendResult(interp, "wrong # args: should be \"", + argv[0], " vars [pattern]\"", 0); + return TCL_ERROR; + } + if (iPtr->varFramePtr == 0) { + tablePtr = &iPtr->globalTable; + } else { + tablePtr = &iPtr->varFramePtr->varTable; + } + for (hPtr = Tcl_FirstHashEntry(tablePtr, &search); + hPtr != 0; hPtr = Tcl_NextHashEntry(&search)) { + varPtr = (Var *) Tcl_GetHashValue(hPtr); + if (varPtr->flags & VAR_UNDEFINED) { + continue; + } + name = Tcl_GetHashKey(tablePtr, hPtr); + if ((argc == 3) && !Tcl_StringMatch(name, argv[2])) { + continue; + } + Tcl_AppendElement(interp, name, 0); + } + return TCL_OK; + } else { + Tcl_AppendResult(interp, "bad option \"", argv[1], + "\": should be args, body, cmdcount, commands, ", + "complete, default, ", + "exists, globals, level, library, locals, procs, ", + "script, tclversion, or vars", 0); + return TCL_ERROR; + } +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_JoinCmd -- + * + * This procedure is invoked to process the "join" Tcl command. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *---------------------------------------------------------------------- + */ + + /* ARGSUSED */ +int +Tcl_JoinCmd(dummy, interp, argc, argv) + void *dummy; /* Not used. */ + Tcl_Interp *interp; /* Current interpreter. */ + int argc; /* Number of arguments. */ + unsigned char **argv; /* Argument strings. */ +{ + unsigned char *joinString; + unsigned char **listArgv; + int listArgc, i; + + if (argc == 2) { + joinString = (unsigned char*) " "; + } else if (argc == 3) { + joinString = argv[2]; + } else { + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " list ?joinString?\"", 0); + return TCL_ERROR; + } + + if (Tcl_SplitList(interp, argv[1], &listArgc, &listArgv) != TCL_OK) { + return TCL_ERROR; + } + for (i = 0; i < listArgc; i++) { + if (i == 0) { + Tcl_AppendResult(interp, listArgv[0], 0); + } else { + Tcl_AppendResult(interp, joinString, listArgv[i], 0); + } + } + free (listArgv); + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_LindexCmd -- + * + * This procedure is invoked to process the "lindex" Tcl command. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *---------------------------------------------------------------------- + */ + + /* ARGSUSED */ +int +Tcl_LindexCmd(dummy, interp, argc, argv) + void *dummy; /* Not used. */ + Tcl_Interp *interp; /* Current interpreter. */ + int argc; /* Number of arguments. */ + unsigned char **argv; /* Argument strings. */ +{ + unsigned char *p, *element; + int index, size, parenthesized, result; + + if (argc != 3) { + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " list index\"", 0); + return TCL_ERROR; + } + if (Tcl_GetInt(interp, argv[2], &index) != TCL_OK) { + return TCL_ERROR; + } + if (index < 0) { + return TCL_OK; + } + for (p = argv[1] ; index >= 0; index--) { + result = TclFindElement(interp, p, &element, &p, &size, + &parenthesized); + if (result != TCL_OK) { + return result; + } + } + if (size == 0) { + return TCL_OK; + } + if (size >= TCL_RESULT_SIZE) { + interp->result = malloc ((unsigned) size + 1); + interp->freeProc = (Tcl_FreeProc *) free; + } + if (parenthesized) { + memcpy((void *) interp->result, (void *) element, size); + interp->result[size] = 0; + } else { + TclCopyAndCollapse(size, element, interp->result); + } + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_LinsertCmd -- + * + * This procedure is invoked to process the "linsert" Tcl command. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *---------------------------------------------------------------------- + */ + + /* ARGSUSED */ +int +Tcl_LinsertCmd(dummy, interp, argc, argv) + void *dummy; /* Not used. */ + Tcl_Interp *interp; /* Current interpreter. */ + int argc; /* Number of arguments. */ + unsigned char **argv; /* Argument strings. */ +{ + unsigned char *p, *element, savedChar; + int i, index, count, result, size; + + if (argc < 4) { + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " list index element ?element ...?\"", 0); + return TCL_ERROR; + } + if (Tcl_GetInt(interp, argv[2], &index) != TCL_OK) { + return TCL_ERROR; + } + + /* + * Skip over the first "index" elements of the list, then add + * all of those elements to the result. + */ + + size = 0; + element = argv[1]; + for (count = 0, p = argv[1]; (count < index) && (*p != 0); count++) { + result = TclFindElement(interp, p, &element, &p, &size, (int *) 0); + if (result != TCL_OK) { + return result; + } + } + if (*p == 0) { + Tcl_AppendResult(interp, argv[1], 0); + } else { + unsigned char *end; + + end = element+size; + if (element != argv[1]) { + while ((*end != 0) && !isspace(*end)) { + end++; + } + } + savedChar = *end; + *end = 0; + Tcl_AppendResult(interp, argv[1], 0); + *end = savedChar; + } + + /* + * Add the new list elements. + */ + + for (i = 3; i < argc; i++) { + Tcl_AppendElement(interp, argv[i], 0); + } + + /* + * Append the remainder of the original list. + */ + + if (*p != 0) { + Tcl_AppendResult(interp, " ", p, 0); + } + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_ListCmd -- + * + * This procedure is invoked to process the "list" Tcl command. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *---------------------------------------------------------------------- + */ + + /* ARGSUSED */ +int +Tcl_ListCmd(dummy, interp, argc, argv) + void *dummy; /* Not used. */ + Tcl_Interp *interp; /* Current interpreter. */ + int argc; /* Number of arguments. */ + unsigned char **argv; /* Argument strings. */ +{ + if (argc < 2) { + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " arg ?arg ...?\"", 0); + return TCL_ERROR; + } + interp->result = Tcl_Merge (argc-1, argv+1); + interp->freeProc = (Tcl_FreeProc *) free; + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_LlengthCmd -- + * + * This procedure is invoked to process the "llength" Tcl command. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *---------------------------------------------------------------------- + */ + + /* ARGSUSED */ +int +Tcl_LlengthCmd(dummy, interp, argc, argv) + void *dummy; /* Not used. */ + Tcl_Interp *interp; /* Current interpreter. */ + int argc; /* Number of arguments. */ + unsigned char **argv; /* Argument strings. */ +{ + int count, result; + unsigned char *element, *p; + + if (argc != 2) { + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " list\"", 0); + return TCL_ERROR; + } + for (count = 0, p = argv[1]; *p != 0 ; count++) { + result = TclFindElement(interp, p, &element, &p, (int *) 0, + (int *) 0); + if (result != TCL_OK) { + return result; + } + if (*element == 0) { + break; + } + } + sprintf(interp->result, "%d", count); + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_LrangeCmd -- + * + * This procedure is invoked to process the "lrange" Tcl command. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *---------------------------------------------------------------------- + */ + + /* ARGSUSED */ +int +Tcl_LrangeCmd(notUsed, interp, argc, argv) + void *notUsed; /* Not used. */ + Tcl_Interp *interp; /* Current interpreter. */ + int argc; /* Number of arguments. */ + unsigned char **argv; /* Argument strings. */ +{ + int first, last, result; + unsigned char *begin, *end, c, *dummy; + int count; + + if (argc != 4) { + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " list first last\"", 0); + return TCL_ERROR; + } + if (Tcl_GetInt(interp, argv[2], &first) != TCL_OK) { + return TCL_ERROR; + } + if (first < 0) { + first = 0; + } + if ((*argv[3] == 'e') && (strncmp(argv[3], (unsigned char*) "end", strlen(argv[3])) == 0)) { + last = 30000; + } else { + if (Tcl_GetInt(interp, argv[3], &last) != TCL_OK) { + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, + "expected integer or \"end\" but got \"", + argv[3], "\"", 0); + return TCL_ERROR; + } + } + if (first > last) { + return TCL_OK; + } + + /* + * Extract a range of fields. + */ + + for (count = 0, begin = argv[1]; count < first; count++) { + result = TclFindElement(interp, begin, &dummy, &begin, (int *) 0, + (int *) 0); + if (result != TCL_OK) { + return result; + } + if (*begin == 0) { + break; + } + } + for (count = first, end = begin; (count <= last) && (*end != 0); + count++) { + result = TclFindElement(interp, end, &dummy, &end, (int *) 0, + (int *) 0); + if (result != TCL_OK) { + return result; + } + } + + /* + * Chop off trailing spaces. + */ + + while (isspace(end[-1])) { + end--; + } + c = *end; + *end = 0; + Tcl_SetResult(interp, begin, TCL_VOLATILE); + *end = c; + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_LreplaceCmd -- + * + * This procedure is invoked to process the "lreplace" Tcl command. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *---------------------------------------------------------------------- + */ + + /* ARGSUSED */ +int +Tcl_LreplaceCmd(notUsed, interp, argc, argv) + void *notUsed; /* Not used. */ + Tcl_Interp *interp; /* Current interpreter. */ + int argc; /* Number of arguments. */ + unsigned char **argv; /* Argument strings. */ +{ + unsigned char *p1, *p2, *element, savedChar, *dummy; + int i, first, last, count, result, size; + + if (argc < 4) { + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " list first last ?element element ...?\"", 0); + return TCL_ERROR; + } + if (Tcl_GetInt(interp, argv[2], &first) != TCL_OK) { + return TCL_ERROR; + } + if (TclGetListIndex(interp, argv[3], &last) != TCL_OK) { + return TCL_ERROR; + } + if (first < 0) { + first = 0; + } + if (last < 0) { + last = 0; + } + if (first > last) { + Tcl_AppendResult(interp, "first index must not be greater than second", 0); + return TCL_ERROR; + } + + /* + * Skip over the elements of the list before "first". + */ + + size = 0; + element = argv[1]; + for (count = 0, p1 = argv[1]; (count < first) && (*p1 != 0); count++) { + result = TclFindElement(interp, p1, &element, &p1, &size, + (int *) 0); + if (result != TCL_OK) { + return result; + } + } + if (*p1 == 0) { + Tcl_AppendResult(interp, "list doesn't contain element ", + argv[2], 0); + return TCL_ERROR; + } + + /* + * Skip over the elements of the list up through "last". + */ + + for (p2 = p1 ; (count <= last) && (*p2 != 0); count++) { + result = TclFindElement(interp, p2, &dummy, &p2, (int *) 0, + (int *) 0); + if (result != TCL_OK) { + return result; + } + } + + /* + * Add the elements before "first" to the result. Be sure to + * include quote or brace characters that might terminate the + * last of these elements. + */ + + p1 = element+size; + if (element != argv[1]) { + while ((*p1 != 0) && !isspace(*p1)) { + p1++; + } + } + savedChar = *p1; + *p1 = 0; + Tcl_AppendResult(interp, argv[1], 0); + *p1 = savedChar; + + /* + * Add the new list elements. + */ + + for (i = 4; i < argc; i++) { + Tcl_AppendElement(interp, argv[i], 0); + } + + /* + * Append the remainder of the original list. + */ + + if (*p2 != 0) { + if (*interp->result == 0) { + Tcl_SetResult(interp, p2, TCL_VOLATILE); + } else { + Tcl_AppendResult(interp, " ", p2, 0); + } + } + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_LsearchCmd -- + * + * This procedure is invoked to process the "lsearch" Tcl command. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *---------------------------------------------------------------------- + */ + + /* ARGSUSED */ +int +Tcl_LsearchCmd(notUsed, interp, argc, argv) + void *notUsed; /* Not used. */ + Tcl_Interp *interp; /* Current interpreter. */ + int argc; /* Number of arguments. */ + unsigned char **argv; /* Argument strings. */ +{ + int listArgc; + unsigned char **listArgv; + int i, match; + + if (argc != 3) { + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " list pattern\"", 0); + return TCL_ERROR; + } + if (Tcl_SplitList(interp, argv[1], &listArgc, &listArgv) != TCL_OK) { + return TCL_ERROR; + } + match = -1; + for (i = 0; i < listArgc; i++) { + if (Tcl_StringMatch(listArgv[i], argv[2])) { + match = i; + break; + } + } + sprintf (interp->result, "%d", match); + free (listArgv); + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_LsortCmd -- + * + * This procedure is invoked to process the "lsort" Tcl command. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *---------------------------------------------------------------------- + */ + + /* ARGSUSED */ +int +Tcl_LsortCmd(notUsed, interp, argc, argv) + void *notUsed; /* Not used. */ + Tcl_Interp *interp; /* Current interpreter. */ + int argc; /* Number of arguments. */ + unsigned char **argv; /* Argument strings. */ +{ + int listArgc; + unsigned char **listArgv; + + if (argc != 2) { + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " list\"", 0); + return TCL_ERROR; + } + if (Tcl_SplitList(interp, argv[1], &listArgc, &listArgv) != TCL_OK) { + return TCL_ERROR; + } + qsort((void *) listArgv, listArgc, sizeof (char*), SortCompareProc); + interp->result = Tcl_Merge (listArgc, listArgv); + interp->freeProc = (Tcl_FreeProc *) free; + free (listArgv); + return TCL_OK; +} + +/* + * The procedure below is called back by qsort to determine + * the proper ordering between two elements. + */ + +static int +SortCompareProc(first, second) + const void *first, *second; /* Elements to be compared. */ +{ + return strcmp(*((unsigned char **) first), *((unsigned char **) second)); +} diff --git a/src/libtcl/tclcmdmz.c b/src/libtcl/tclcmdmz.c new file mode 100644 index 0000000..d5d5622 --- /dev/null +++ b/src/libtcl/tclcmdmz.c @@ -0,0 +1,1372 @@ +/* + * tclCmdMZ.c -- + * + * This file contains the top-level command routines for most of + * the Tcl built-in commands whose names begin with the letters + * M to Z. It contains only commands in the generic core (i.e. + * those that don't depend much upon UNIX facilities). + * + * Copyright 1987-1991 Regents of the University of California + * 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. The University of California + * makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without + * express or implied warranty. + */ +#include "internal.h" +#include "regexp.h" +#include "regpriv.h" + +/* + * Structure used to hold information about variable traces: + */ + +typedef struct { + int flags; /* Operations for which Tcl command is + * to be invoked. */ + int length; /* Number of non-NULL chars. in command. */ + unsigned char command[4]; /* Space for Tcl command to invoke. Actual + * size will be as large as necessary to + * hold command. This field must be the + * last in the structure, so that it can + * be larger than 4 bytes. */ +} TraceVarInfo; + +/* + * Forward declarations for procedures defined in this file: + */ + +static unsigned char * TraceVarProc (void *clientData, + Tcl_Interp *interp, unsigned char *name1, + unsigned char *name2, int flags); + +/* + *---------------------------------------------------------------------- + * + * Tcl_RegexpCmd -- + * + * This procedure is invoked to process the "regexp" Tcl command. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *---------------------------------------------------------------------- + */ + + /* ARGSUSED */ +int +Tcl_RegexpCmd(dummy, interp, argc, argv) + void *dummy; /* Not used. */ + Tcl_Interp *interp; /* Current interpreter. */ + int argc; /* Number of arguments. */ + unsigned char **argv; /* Argument strings. */ +{ + int noCase = 0; + int indices = 0; + regexp_t *regexpPtr; + unsigned char **argPtr, *string; + int match, i; + + if (argc < 3) { + wrongNumArgs: + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " ?-nocase? exp string ?matchVar? ?subMatchVar ", + "subMatchVar ...?\"", 0); + return TCL_ERROR; + } + argPtr = argv+1; + argc--; + while ((argc > 0) && (argPtr[0][0] == '-')) { + if (strcmp(argPtr[0], (unsigned char*) "-indices") == 0) { + argPtr++; + argc--; + indices = 1; + } else if (strcmp(argPtr[0], (unsigned char*) "-nocase") == 0) { + argPtr++; + argc--; + noCase = 1; + } else { + break; + } + } + if (argc < 2) { + goto wrongNumArgs; + } + regexpPtr = TclCompileRegexp(interp, argPtr[0]); + if (regexpPtr == 0) { + return TCL_ERROR; + } + + /* + * Convert the string to lower case, if desired, and perform + * the match. + */ + if (noCase) { + register unsigned char *dst, *src; + + string = malloc (strlen(argPtr[1]) + 1); + for (src = argPtr[1], dst = string; *src != 0; src++, dst++) { + if (isupper(*src)) { + *dst = tolower(*src); + } else { + *dst = *src; + } + } + *dst = 0; + } else { + string = argPtr[1]; + } + match = regexp_execute (regexpPtr, string); + if (string != argPtr[1]) { + free(string); + } + if (match) { + interp->result = (unsigned char*) "0"; + return TCL_OK; + } + + /* + * If additional variable names have been specified, return + * index information in those variables. + */ + + argc -= 2; + if (argc > 10) { + interp->result = (unsigned char*) "too many substring variables"; + return TCL_ERROR; + } + for (i = 0; i < argc; i++) { + unsigned char *result, info[50]; + + if (regexpPtr->startp[i] == 0) { + if (indices) { + result = Tcl_SetVar(interp, argPtr[i+2], (unsigned char*) "-1 -1", 0); + } else { + result = Tcl_SetVar(interp, argPtr[i+2], (unsigned char*) "", 0); + } + } else { + if (indices) { + sprintf(info, "%d %d", (int) (regexpPtr->startp[i] - string), + (int) (regexpPtr->endp[i] - string - 1)); + result = Tcl_SetVar(interp, argPtr[i+2], info, 0); + } else { + unsigned char savedChar, *first, *last; + + first = argPtr[1] + (regexpPtr->startp[i] - string); + last = argPtr[1] + (regexpPtr->endp[i] - string); + savedChar = *last; + *last = 0; + result = Tcl_SetVar(interp, argPtr[i+2], first, 0); + *last = savedChar; + } + } + if (result == 0) { + Tcl_AppendResult(interp, "couldn't set variable \"", + argPtr[i+2], "\"", 0); + return TCL_ERROR; + } + } + interp->result = (unsigned char*) "1"; + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_RegsubCmd -- + * + * This procedure is invoked to process the "regsub" Tcl command. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *---------------------------------------------------------------------- + */ + + /* ARGSUSED */ +int +Tcl_RegsubCmd(dummy, interp, argc, argv) + void *dummy; /* Not used. */ + Tcl_Interp *interp; /* Current interpreter. */ + int argc; /* Number of arguments. */ + unsigned char **argv; /* Argument strings. */ +{ + int noCase = 0, all = 0; + regexp_t *regexpPtr; + unsigned char *string, *p, *firstChar, *newValue, **argPtr; + int match, result, flags; + register unsigned char *src, c; + + if (argc < 5) { + wrongNumArgs: + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " ?-nocase? ?-all? exp string subSpec varName\"", 0); + return TCL_ERROR; + } + argPtr = argv+1; + argc--; + while (argPtr[0][0] == '-') { + if (strcmp(argPtr[0], (unsigned char*) "-nocase") == 0) { + argPtr++; + argc--; + noCase = 1; + } else if (strcmp(argPtr[0], (unsigned char*) "-all") == 0) { + argPtr++; + argc--; + all = 1; + } else { + break; + } + } + if (argc != 4) { + goto wrongNumArgs; + } + regexpPtr = TclCompileRegexp(interp, argPtr[0]); + if (regexpPtr == 0) { + return TCL_ERROR; + } + + /* + * Convert the string to lower case, if desired. + */ + + if (noCase) { + register unsigned char *dst; + + string = malloc (strlen(argPtr[1]) + 1); + for (src = argPtr[1], dst = string; *src != 0; src++, dst++) { + if (isupper(*src)) { + *dst = tolower(*src); + } else { + *dst = *src; + } + } + *dst = 0; + } else { + string = argPtr[1]; + } + + /* + * The following loop is to handle multiple matches within the + * same source string; each iteration handles one match and its + * corresponding substitution. If "-all" hasn't been specified + * then the loop body only gets executed once. + */ + + flags = 0; + for (p = string; *p != 0; ) { + match = regexp_execute (regexpPtr, p); + if (match) { + break; + } + + /* + * Copy the portion of the source string before the match to the + * result variable. + */ + + src = argPtr[1] + (regexpPtr->startp[0] - string); + c = *src; + *src = 0; + newValue = Tcl_SetVar(interp, argPtr[3], argPtr[1] + (p - string), + flags); + *src = c; + flags = TCL_APPEND_VALUE; + if (newValue == 0) { + cantSet: + Tcl_AppendResult(interp, "couldn't set variable \"", + argPtr[3], "\"", 0); + result = TCL_ERROR; + goto done; + } + + /* + * Append the subSpec argument to the variable, making appropriate + * substitutions. This code is a bit hairy because of the backslash + * conventions and because the code saves up ranges of characters in + * subSpec to reduce the number of calls to Tcl_SetVar. + */ + for (src = firstChar = argPtr[2], c = *src; c != 0; src++, c = *src) { + int index; + + if (c == '&') { + index = 0; + } else if (c == '\\') { + c = src[1]; + if ((c >= '0') && (c <= '9')) { + index = c - '0'; + } else if ((c == '\\') || (c == '&')) { + *src = c; + src[1] = 0; + newValue = Tcl_SetVar(interp, argPtr[3], firstChar, + TCL_APPEND_VALUE); + *src = '\\'; + src[1] = c; + if (newValue == 0) { + goto cantSet; + } + firstChar = src+2; + src++; + continue; + } else { + continue; + } + } else { + continue; + } + if (firstChar != src) { + c = *src; + *src = 0; + newValue = Tcl_SetVar(interp, argPtr[3], firstChar, + TCL_APPEND_VALUE); + *src = c; + if (newValue == 0) { + goto cantSet; + } + } + if ((index < 10) && (regexpPtr->startp[index] != 0) + && (regexpPtr->endp[index] != 0)) { + unsigned char *first, *last, saved; + + first = argPtr[1] + (regexpPtr->startp[index] - string); + last = argPtr[1] + (regexpPtr->endp[index] - string); + saved = *last; + *last = 0; + newValue = Tcl_SetVar(interp, argPtr[3], first, + TCL_APPEND_VALUE); + *last = saved; + if (newValue == 0) { + goto cantSet; + } + } + if (*src == '\\') { + src++; + } + firstChar = src+1; + } + if (firstChar != src) { + if (Tcl_SetVar(interp, argPtr[3], firstChar, + TCL_APPEND_VALUE) == 0) { + goto cantSet; + } + } + p = (unsigned char*) regexpPtr->endp[0]; + if (!all) { + break; + } + } + + /* + * If there were no matches at all, then return a "0" result. + */ + + if (p == string) { + interp->result = (unsigned char*) "0"; + result = TCL_OK; + goto done; + } + + /* + * Copy the portion of the source string after the last match to the + * result variable. + */ + + if (*p != 0) { + if (Tcl_SetVar(interp, argPtr[3], p, TCL_APPEND_VALUE) == 0) { + goto cantSet; + } + } + interp->result = (unsigned char*) "1"; + result = TCL_OK; + + done: + if (string != argPtr[1]) { + free(string); + } + return result; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_RenameCmd -- + * + * This procedure is invoked to process the "rename" Tcl command. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *---------------------------------------------------------------------- + */ + + /* ARGSUSED */ +int +Tcl_RenameCmd(dummy, interp, argc, argv) + void *dummy; /* Not used. */ + Tcl_Interp *interp; /* Current interpreter. */ + int argc; /* Number of arguments. */ + unsigned char **argv; /* Argument strings. */ +{ + register Command *cmdPtr; + Interp *iPtr = (Interp *) interp; + Tcl_HashEntry *hPtr; + int new; + + if (argc != 3) { + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " oldName newName\"", 0); + return TCL_ERROR; + } + if (argv[2][0] == '\0') { + if (Tcl_DeleteCommand(interp, argv[1]) != 0) { + Tcl_AppendResult(interp, "can't delete \"", argv[1], + "\": command doesn't exist", 0); + return TCL_ERROR; + } + return TCL_OK; + } + hPtr = Tcl_FindHashEntry(&iPtr->commandTable, argv[2]); + if (hPtr != 0) { + Tcl_AppendResult(interp, "can't rename to \"", argv[2], + "\": command already exists", 0); + return TCL_ERROR; + } + hPtr = Tcl_FindHashEntry(&iPtr->commandTable, argv[1]); + if (hPtr == 0) { + Tcl_AppendResult(interp, "can't rename \"", argv[1], + "\": command doesn't exist", 0); + return TCL_ERROR; + } + cmdPtr = (Command *) Tcl_GetHashValue(hPtr); + Tcl_DeleteHashEntry(hPtr); + hPtr = Tcl_CreateHashEntry(&iPtr->commandTable, argv[2], &new); + Tcl_SetHashValue(hPtr, cmdPtr); + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_ReturnCmd -- + * + * This procedure is invoked to process the "return" Tcl command. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *---------------------------------------------------------------------- + */ + + /* ARGSUSED */ +int +Tcl_ReturnCmd(dummy, interp, argc, argv) + void *dummy; /* Not used. */ + Tcl_Interp *interp; /* Current interpreter. */ + int argc; /* Number of arguments. */ + unsigned char **argv; /* Argument strings. */ +{ + if (argc > 2) { + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " ?value?\"", 0); + return TCL_ERROR; + } + if (argc == 2) { + Tcl_SetResult(interp, argv[1], TCL_VOLATILE); + } + return TCL_RETURN; +} + +/* + * This procedure is invoked to process the "scan" Tcl command. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + */ + /* ARGSUSED */ +int +Tcl_ScanCmd(dummy, interp, argc, argv) + void *dummy; /* Not used. */ + Tcl_Interp *interp; /* Current interpreter. */ + int argc; /* Number of arguments. */ + unsigned char **argv; /* Argument strings. */ +{ + int arg1Length; /* Number of bytes in argument to be + * scanned. This gives an upper limit + * on string field sizes. */ +# define MAX_FIELDS 20 + typedef struct { + unsigned char fmt; /* Format for field. */ + int size; /* How many bytes to allow for + * field. */ + unsigned char *location; /* Where field will be stored. */ + } Field; + Field fields[MAX_FIELDS]; /* Info about all the fields in the + * format string. */ + register Field *curField; + int numFields = 0; /* Number of fields actually + * specified. */ + int suppress; /* Current field is assignment- + * suppressed. */ + int totalSize = 0; /* Number of bytes needed to store + * all results combined. */ + unsigned char *results; /* Where scanned output goes. */ + int numScanned; /* sscanf's result. */ + register unsigned char *fmt; + int i, widthSpecified; + + if (argc < 3) { + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " string format ?varName varName ...?\"", 0); + return TCL_ERROR; + } + + /* + * This procedure operates in four stages: + * 1. Scan the format string, collecting information about each field. + * 2. Allocate an array to hold all of the scanned fields. + * 3. Call sscanf to do all the dirty work, and have it store the + * parsed fields in the array. + * 4. Pick off the fields from the array and assign them to variables. + */ + arg1Length = (strlen(argv[1]) + 4) & ~03; + for (fmt = argv[2]; *fmt != 0; fmt++) { + if (*fmt != '%') { + continue; + } + fmt++; + if (*fmt == '*') { + suppress = 1; + fmt++; + } else { + suppress = 0; + } + widthSpecified = 0; + while (isdigit(*fmt)) { + widthSpecified = 1; + fmt++; + } + if (suppress) { + continue; + } + if (numFields == MAX_FIELDS) { + interp->result = (unsigned char*) "too many fields to scan"; + return TCL_ERROR; + } + curField = &fields[numFields]; + numFields++; + switch (*fmt) { + case 'D': + case 'O': + case 'X': + case 'd': + case 'o': + case 'x': + curField->fmt = 'd'; + curField->size = sizeof(int); + break; + + case 's': + curField->fmt = 's'; + curField->size = arg1Length; + break; + + case 'c': + if (widthSpecified) { + interp->result = (unsigned char*) + "field width may not be specified in %c conversion"; + return TCL_ERROR; + } + curField->fmt = 'c'; + curField->size = sizeof(int); + break; + case '[': + curField->fmt = 's'; + curField->size = arg1Length; + do { + fmt++; + } while (*fmt != ']'); + break; + + default: + sprintf(interp->result, + "bad scan conversion character \"%c\"", *fmt); + return TCL_ERROR; + } + totalSize += curField->size; + } + + if (numFields != (argc-3)) { + interp->result = (unsigned char*) + "different numbers of variable names and field specifiers"; + return TCL_ERROR; + } + + /* + * Step 2: + */ + results = malloc (totalSize); + for (i = 0, totalSize = 0, curField = fields; + i < numFields; i++, curField++) { + curField->location = results + totalSize; + totalSize += curField->size; + } + + /* + * Fill in the remaining fields with NULL; the only purpose of + * this is to keep some memory analyzers, like Purify, from + * complaining. + */ + for ( ; i < MAX_FIELDS; i++, curField++) { + curField->location = 0; + } + + /* + * Step 3: + */ + numScanned = sscanf(argv[1], (char*) argv[2], + fields[0].location, fields[1].location, fields[2].location, + fields[3].location, fields[4].location, fields[5].location, + fields[6].location, fields[7].location, fields[8].location, + fields[9].location, fields[10].location, fields[11].location, + fields[12].location, fields[13].location, fields[14].location, + fields[15].location, fields[16].location, fields[17].location, + fields[18].location, fields[19].location); + + /* + * Step 4: + */ + if (numScanned < numFields) { + numFields = numScanned; + } + for (i = 0, curField = fields; i < numFields; i++, curField++) { + switch (curField->fmt) { + unsigned char string[120]; + + case 'd': + sprintf(string, "%d", *((int *) curField->location)); + if (Tcl_SetVar(interp, argv[i+3], string, 0) == 0) { + storeError: + Tcl_AppendResult(interp, + "couldn't set variable \"", argv[i+3], "\"", 0); + free (results); + return TCL_ERROR; + } + break; + + case 'c': + sprintf(string, "%d", *curField->location & 0xff); + if (Tcl_SetVar(interp, argv[i+3], string, 0) == 0) { + goto storeError; + } + break; + + case 's': + if (Tcl_SetVar(interp, argv[i+3], curField->location, 0) + == 0) { + goto storeError; + } + break; + } + } + free(results); + sprintf(interp->result, "%d", numScanned); + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_SplitCmd -- + * + * This procedure is invoked to process the "split" Tcl command. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *---------------------------------------------------------------------- + */ + + /* ARGSUSED */ +int +Tcl_SplitCmd(dummy, interp, argc, argv) + void *dummy; /* Not used. */ + Tcl_Interp *interp; /* Current interpreter. */ + int argc; /* Number of arguments. */ + unsigned char **argv; /* Argument strings. */ +{ + unsigned char *splitChars; + register unsigned char *p, *p2; + unsigned char *elementStart; + + if (argc == 2) { + splitChars = (unsigned char*) " \n\t\r"; + } else if (argc == 3) { + splitChars = argv[2]; + } else { + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " string ?splitChars?\"", 0); + return TCL_ERROR; + } + + /* + * Handle the special case of splitting on every character. + */ + + if (*splitChars == 0) { + unsigned char string[2]; + string[1] = 0; + for (p = argv[1]; *p != 0; p++) { + string[0] = *p; + Tcl_AppendElement(interp, string, 0); + } + return TCL_OK; + } + + /* + * Normal case: split on any of a given set of characters. + * Discard instances of the split characters. + */ + + for (p = elementStart = argv[1]; *p != 0; p++) { + unsigned char c = *p; + for (p2 = splitChars; *p2 != 0; p2++) { + if (*p2 == c) { + *p = 0; + Tcl_AppendElement(interp, elementStart, 0); + *p = c; + elementStart = p+1; + break; + } + } + } + if (p != argv[1]) { + Tcl_AppendElement(interp, elementStart, 0); + } + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_StringCmd -- + * + * This procedure is invoked to process the "string" Tcl command. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *---------------------------------------------------------------------- + */ + + /* ARGSUSED */ +int +Tcl_StringCmd(dummy, interp, argc, argv) + void *dummy; /* Not used. */ + Tcl_Interp *interp; /* Current interpreter. */ + int argc; /* Number of arguments. */ + unsigned char **argv; /* Argument strings. */ +{ + int length; + register unsigned char *p, c; + int match; + int first; + int left = 0, right = 0; + + if (argc < 2) { + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " option arg ?arg ...?\"", 0); + return TCL_ERROR; + } + c = argv[1][0]; + length = strlen(argv[1]); + if ((c == 'c') && (strncmp(argv[1], (unsigned char*) "compare", length) == 0)) { + if (argc != 4) { + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " compare string1 string2\"", 0); + return TCL_ERROR; + } + match = strcmp(argv[2], argv[3]); + if (match > 0) { + interp->result = (unsigned char*) "1"; + } else if (match < 0) { + interp->result = (unsigned char*) "-1"; + } else { + interp->result = (unsigned char*) "0"; + } + return TCL_OK; + } else if ((c == 'f') && (strncmp(argv[1], (unsigned char*) "first", length) == 0)) { + if (argc != 4) { + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " first string1 string2\"", 0); + return TCL_ERROR; + } + first = 1; + + firstLast: + match = -1; + c = *argv[2]; + length = strlen(argv[2]); + for (p = argv[3]; *p != 0; p++) { + if (*p != c) { + continue; + } + if (strncmp(argv[2], p, length) == 0) { + match = p-argv[3]; + if (first) { + break; + } + } + } + sprintf(interp->result, "%d", match); + return TCL_OK; + } else if ((c == 'i') && (strncmp(argv[1], (unsigned char*) "index", length) == 0)) { + int index; + + if (argc != 4) { + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " index string charIndex\"", 0); + return TCL_ERROR; + } + if (Tcl_GetInt(interp, argv[3], &index) != TCL_OK) { + return TCL_ERROR; + } + if ((index >= 0) && (index < strlen(argv[2]))) { + interp->result[0] = argv[2][index]; + interp->result[1] = 0; + } + return TCL_OK; + } else if ((c == 'l') && (strncmp(argv[1], (unsigned char*) "last", length) == 0) + && (length >= 2)) { + if (argc != 4) { + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " last string1 string2\"", 0); + return TCL_ERROR; + } + first = 0; + goto firstLast; + } else if ((c == 'l') && (strncmp(argv[1], (unsigned char*) "length", length) == 0) + && (length >= 2)) { + if (argc != 3) { + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " length string\"", 0); + return TCL_ERROR; + } + sprintf(interp->result, "%u", (unsigned int) strlen(argv[2])); + return TCL_OK; + } else if ((c == 'm') && (strncmp(argv[1], (unsigned char*) "match", length) == 0)) { + if (argc != 4) { + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " match pattern string\"", 0); + return TCL_ERROR; + } + if (Tcl_StringMatch(argv[3], argv[2]) != 0) { + interp->result = (unsigned char*) "1"; + } else { + interp->result = (unsigned char*) "0"; + } + return TCL_OK; + } else if ((c == 'r') && (strncmp(argv[1], (unsigned char*) "range", length) == 0)) { + int first, last, stringLength; + + if (argc != 5) { + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " range string first last\"", 0); + return TCL_ERROR; + } + stringLength = strlen(argv[2]); + if (Tcl_GetInt(interp, argv[3], &first) != TCL_OK) { + return TCL_ERROR; + } + if ((*argv[4] == 'e') + && (strncmp(argv[4], (unsigned char*) "end", strlen(argv[4])) == 0)) { + last = stringLength-1; + } else { + if (Tcl_GetInt(interp, argv[4], &last) != TCL_OK) { + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, + "expected integer or \"end\" but got \"", + argv[4], "\"", 0); + return TCL_ERROR; + } + } + if (first < 0) { + first = 0; + } + if (last >= stringLength) { + last = stringLength-1; + } + if (last >= first) { + unsigned char saved, *p; + + p = argv[2] + last + 1; + saved = *p; + *p = 0; + Tcl_SetResult(interp, argv[2] + first, TCL_VOLATILE); + *p = saved; + } + return TCL_OK; + } else if ((c == 't') && (strncmp(argv[1], (unsigned char*) "tolower", length) == 0) + && (length >= 3)) { + register unsigned char *p; + + if (argc != 3) { + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " tolower string\"", 0); + return TCL_ERROR; + } + Tcl_SetResult(interp, argv[2], TCL_VOLATILE); + for (p = interp->result; *p != 0; p++) { + if (isupper(*p)) { + *p = tolower(*p); + } + } + return TCL_OK; + } else if ((c == 't') && (strncmp(argv[1], (unsigned char*) "toupper", length) == 0) + && (length >= 3)) { + register unsigned char *p; + + if (argc != 3) { + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " toupper string\"", 0); + return TCL_ERROR; + } + Tcl_SetResult(interp, argv[2], TCL_VOLATILE); + for (p = interp->result; *p != 0; p++) { + if (islower(*p)) { + *p = toupper(*p); + } + } + return TCL_OK; + } else if ((c == 't') && (strncmp(argv[1], (unsigned char*) "trim", length) == 0) + && (length == 4)) { + unsigned char *trimChars; + register unsigned char *p, *checkPtr; + + left = right = 1; + + trim: + if (argc == 4) { + trimChars = argv[3]; + } else if (argc == 3) { + trimChars = (unsigned char*) " \t\n\r"; + } else { + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " ", argv[1], " string ?chars?\"", 0); + return TCL_ERROR; + } + p = argv[2]; + if (left) { + for (c = *p; c != 0; p++, c = *p) { + for (checkPtr = trimChars; *checkPtr != c; checkPtr++) { + if (*checkPtr == 0) { + goto doneLeft; + } + } + } + } + doneLeft: + Tcl_SetResult(interp, p, TCL_VOLATILE); + if (right) { + unsigned char *donePtr; + + p = interp->result + strlen(interp->result) - 1; + donePtr = &interp->result[-1]; + for (c = *p; p != donePtr; p--, c = *p) { + for (checkPtr = trimChars; *checkPtr != c; checkPtr++) { + if (*checkPtr == 0) { + goto doneRight; + } + } + } + doneRight: + p[1] = 0; + } + return TCL_OK; + } else if ((c == 't') && (strncmp(argv[1], (unsigned char*) "trimleft", length) == 0) + && (length > 4)) { + left = 1; + argv[1] = (unsigned char*) "trimleft"; + goto trim; + } else if ((c == 't') && (strncmp(argv[1], (unsigned char*) "trimright", length) == 0) + && (length > 4)) { + right = 1; + argv[1] = (unsigned char*) "trimright"; + goto trim; + } else { + Tcl_AppendResult(interp, "bad option \"", argv[1], + "\": should be compare, first, index, last, length, match, ", + "range, tolower, toupper, trim, trimleft, or trimright", 0); + return TCL_ERROR; + } +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_TraceCmd -- + * + * This procedure is invoked to process the "trace" Tcl command. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *---------------------------------------------------------------------- + */ + + /* ARGSUSED */ +int +Tcl_TraceCmd(dummy, interp, argc, argv) + void *dummy; /* Not used. */ + Tcl_Interp *interp; /* Current interpreter. */ + int argc; /* Number of arguments. */ + unsigned char **argv; /* Argument strings. */ +{ + char c; + int length; + + if (argc < 2) { + Tcl_AppendResult(interp, "too few args: should be \"", + argv[0], " option [arg arg ...]\"", 0); + return TCL_ERROR; + } + c = argv[1][1]; + length = strlen(argv[1]); + if ((c == 'a') && (strncmp(argv[1], (unsigned char*) "variable", length) == 0) + && (length >= 2)) { + unsigned char *p; + int flags, length; + TraceVarInfo *tvarPtr; + + if (argc != 5) { + Tcl_AppendResult(interp, "wrong # args: should be \"", + argv[0], " variable name ops command\"", 0); + return TCL_ERROR; + } + + flags = 0; + for (p = argv[3] ; *p != 0; p++) { + if (*p == 'r') { + flags |= TCL_TRACE_READS; + } else if (*p == 'w') { + flags |= TCL_TRACE_WRITES; + } else if (*p == 'u') { + flags |= TCL_TRACE_UNSETS; + } else { + goto badOps; + } + } + if (flags == 0) { + goto badOps; + } + + length = strlen(argv[4]); + tvarPtr = (TraceVarInfo*) malloc ((unsigned) + (sizeof(TraceVarInfo) - sizeof(tvarPtr->command) + length + 1)); + tvarPtr->flags = flags; + tvarPtr->length = length; + flags |= TCL_TRACE_UNSETS; + strcpy(tvarPtr->command, argv[4]); + if (Tcl_TraceVar(interp, argv[2], flags, TraceVarProc, + (void*) tvarPtr) != TCL_OK) { + free (tvarPtr); + return TCL_ERROR; + } + } else if ((c == 'd') && (strncmp(argv[1], (unsigned char*) "vdelete", length) + && (length >= 2)) == 0) { + unsigned char *p; + int flags, length; + TraceVarInfo *tvarPtr; + void *clientData; + + if (argc != 5) { + Tcl_AppendResult(interp, "wrong # args: should be \"", + argv[0], " vdelete name ops command\"", 0); + return TCL_ERROR; + } + + flags = 0; + for (p = argv[3] ; *p != 0; p++) { + if (*p == 'r') { + flags |= TCL_TRACE_READS; + } else if (*p == 'w') { + flags |= TCL_TRACE_WRITES; + } else if (*p == 'u') { + flags |= TCL_TRACE_UNSETS; + } else { + goto badOps; + } + } + if (flags == 0) { + goto badOps; + } + + /* + * Search through all of our traces on this variable to + * see if there's one with the given command. If so, then + * delete the first one that matches. + */ + + length = strlen(argv[4]); + clientData = 0; + while ((clientData = Tcl_VarTraceInfo(interp, argv[2], 0, + TraceVarProc, clientData)) != 0) { + tvarPtr = (TraceVarInfo *) clientData; + if ((tvarPtr->length == length) && (tvarPtr->flags == flags) + && (strncmp(argv[4], tvarPtr->command, length) == 0)) { + Tcl_UntraceVar(interp, argv[2], flags | TCL_TRACE_UNSETS, + TraceVarProc, clientData); + free (tvarPtr); + break; + } + } + } else if ((c == 'i') && (strncmp(argv[1], (unsigned char*) "vinfo", length) == 0) + && (length >= 2)) { + void *clientData; + unsigned char ops[4], *p; + unsigned char *prefix = (unsigned char*) "{"; + + if (argc != 3) { + Tcl_AppendResult(interp, "wrong # args: should be \"", + argv[0], " vinfo name\"", 0); + return TCL_ERROR; + } + clientData = 0; + while ((clientData = Tcl_VarTraceInfo(interp, argv[2], 0, + TraceVarProc, clientData)) != 0) { + TraceVarInfo *tvarPtr = (TraceVarInfo *) clientData; + p = ops; + if (tvarPtr->flags & TCL_TRACE_READS) { + *p = 'r'; + p++; + } + if (tvarPtr->flags & TCL_TRACE_WRITES) { + *p = 'w'; + p++; + } + if (tvarPtr->flags & TCL_TRACE_UNSETS) { + *p = 'u'; + p++; + } + *p = '\0'; + Tcl_AppendResult(interp, prefix, 0); + Tcl_AppendElement(interp, ops, 1); + Tcl_AppendElement(interp, tvarPtr->command, 0); + Tcl_AppendResult(interp, "}", 0); + prefix = (unsigned char*) " {"; + } + } else { + Tcl_AppendResult(interp, "bad option \"", argv[1], + "\": should be variable, vdelete, or vinfo", 0); + return TCL_ERROR; + } + return TCL_OK; + + badOps: + Tcl_AppendResult(interp, "bad operations \"", argv[3], + "\": should be one or more of rwu", 0); + return TCL_ERROR; +} + +/* + *---------------------------------------------------------------------- + * + * TraceVarProc -- + * + * This procedure is called to handle variable accesses that have + * been traced using the "trace" command. + * + * Results: + * Normally returns NULL. If the trace command returns an error, + * then this procedure returns an error string. + * + * Side effects: + * Depends on the command associated with the trace. + * + *---------------------------------------------------------------------- + */ + + /* ARGSUSED */ +static unsigned char * +TraceVarProc(clientData, interp, name1, name2, flags) + void *clientData; /* Information about the variable trace. */ + Tcl_Interp *interp; /* Interpreter containing variable. */ + unsigned char *name1; /* Name of variable or array. */ + unsigned char *name2; /* Name of element within array; NULL means + * scalar variable is being referenced. */ + int flags; /* OR-ed bits giving operation and other + * information. */ +{ + TraceVarInfo *tvarPtr = (TraceVarInfo *) clientData; + unsigned char *result; + int code, cmdLength, flags1, flags2; + Interp dummy; +#define STATIC_SIZE 199 + unsigned char staticSpace[STATIC_SIZE+1]; + unsigned char *cmdPtr, *p; + + result = 0; + if ((tvarPtr->flags & flags) && !(flags & TCL_INTERP_DESTROYED)) { + + /* + * Generate a command to execute by appending list elements + * for the two variable names and the operation. The five + * extra characters are for three space, the opcode character, + * and the terminating null. + */ + + if (name2 == 0) { + name2 = (unsigned char*) ""; + } + cmdLength = tvarPtr->length + Tcl_ScanElement(name1, &flags1) + + Tcl_ScanElement(name2, &flags2) + 5; + if (cmdLength < STATIC_SIZE) { + cmdPtr = staticSpace; + } else { + cmdPtr = malloc (cmdLength); + } + p = cmdPtr; + strcpy(p, tvarPtr->command); + p += tvarPtr->length; + *p = ' '; + p++; + p += Tcl_ConvertElement(name1, p, flags1); + *p = ' '; + p++; + p += Tcl_ConvertElement(name2, p, flags2); + *p = ' '; + if (flags & TCL_TRACE_READS) { + p[1] = 'r'; + } else if (flags & TCL_TRACE_WRITES) { + p[1] = 'w'; + } else if (flags & TCL_TRACE_UNSETS) { + p[1] = 'u'; + } + p[2] = '\0'; + + /* + * Execute the command. Be careful to save and restore the + * result from the interpreter used for the command. + */ + + if (interp->freeProc == 0) { + dummy.freeProc = (Tcl_FreeProc *) 0; + dummy.result = (unsigned char*) ""; + Tcl_SetResult((Tcl_Interp *) &dummy, interp->result, TCL_VOLATILE); + } else { + dummy.freeProc = interp->freeProc; + dummy.result = interp->result; + } + code = Tcl_Eval(interp, cmdPtr, 0, 0); + if (cmdPtr != staticSpace) { + free(cmdPtr); + } + if (code != TCL_OK) { + result = (unsigned char*) "access disallowed by trace command"; + Tcl_ResetResult(interp); /* Must clear error state. */ + } + Tcl_FreeResult(interp); + interp->result = dummy.result; + interp->freeProc = dummy.freeProc; + } + if (flags & TCL_TRACE_DESTROYED) { + free (tvarPtr); + } + return result; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_WhileCmd -- + * + * This procedure is invoked to process the "while" Tcl command. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *---------------------------------------------------------------------- + */ + + /* ARGSUSED */ +int +Tcl_WhileCmd(dummy, interp, argc, argv) + void *dummy; /* Not used. */ + Tcl_Interp *interp; /* Current interpreter. */ + int argc; /* Number of arguments. */ + unsigned char **argv; /* Argument strings. */ +{ + int result, value; + + if (argc != 3) { + Tcl_AppendResult(interp, "wrong # args: should be \"", + argv[0], " test command\"", 0); + return TCL_ERROR; + } + + while (1) { + result = Tcl_ExprBoolean(interp, argv[1], &value); + if (result != TCL_OK) { + return result; + } + if (!value) { + break; + } + result = Tcl_Eval(interp, argv[2], 0, 0); + if (result == TCL_CONTINUE) { + result = TCL_OK; + } else if (result != TCL_OK) { + if (result == TCL_ERROR) { + unsigned char msg[60]; + sprintf(msg, "\n (\"while\" body line %d)", + interp->errorLine); + Tcl_AddErrorInfo(interp, msg); + } + break; + } + } + if (result == TCL_BREAK) { + result = TCL_OK; + } + if (result == TCL_OK) { + Tcl_ResetResult(interp); + } + return result; +} diff --git a/src/libtcl/tclenv.c b/src/libtcl/tclenv.c new file mode 100644 index 0000000..40f44f4 --- /dev/null +++ b/src/libtcl/tclenv.c @@ -0,0 +1,501 @@ +/* + * tclEnv.c -- + * + * Tcl support for environment variables, including a setenv + * procedure. + * + * Copyright 1991 Regents of the University of California + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without + * fee is hereby granted, provided that this copyright + * notice appears in all copies. The University of California + * makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without + * express or implied warranty. + */ +#include "internal.h" + +extern char **environ; + +/* + * The structure below is used to keep track of all of the interpereters + * for which we're managing the "env" array. It's needed so that they + * can all be updated whenever an environment variable is changed + * anywhere. + */ + +typedef struct EnvInterp { + Tcl_Interp *interp; /* Interpreter for which we're managing + * the env array. */ + struct EnvInterp *nextPtr; /* Next in list of all such interpreters, + * or zero. */ +} EnvInterp; + +static EnvInterp *firstInterpPtr; + /* First in list of all managed interpreters, + * or NULL if none. */ + +static int environSize = 0; /* Non-zero means that the all of the + * environ-related information is malloc-ed + * and the environ array itself has this + * many total entries allocated to it (not + * all may be in use at once). Zero means + * that the environment array is in its + * original static state. */ + +/* + * Declarations for local procedures defined in this file: + */ + +static void EnvInit (void); +static unsigned char * EnvTraceProc (void *clientData, + Tcl_Interp *interp, unsigned char *name1, + unsigned char *name2, int flags); +static int FindVariable (const char *name, + int *lengthPtr); +int unsetenv (const char *name); + +/* + *---------------------------------------------------------------------- + * + * TclSetupEnv -- + * + * This procedure is invoked for an interpreter to make environment + * variables accessible from that interpreter via the "env" + * associative array. + * + * Results: + * None. + * + * Side effects: + * The interpreter is added to a list of interpreters managed + * by us, so that its view of envariables can be kept consistent + * with the view in other interpreters. If this is the first + * call to Tcl_SetupEnv, then additional initialization happens, + * such as copying the environment to dynamically-allocated space + * for ease of management. + * + *---------------------------------------------------------------------- + */ + +void +TclSetupEnv(interp) + Tcl_Interp *interp; /* Interpreter whose "env" array is to be + * managed. */ +{ + EnvInterp *eiPtr; + int i; + + /* + * First, initialize our environment-related information, if + * necessary. + */ + + if (environSize == 0) { + EnvInit(); + } + + /* + * Next, add the interpreter to the list of those that we manage. + */ + + eiPtr = (EnvInterp *) malloc(sizeof(EnvInterp)); + eiPtr->interp = interp; + eiPtr->nextPtr = firstInterpPtr; + firstInterpPtr = eiPtr; + + /* + * Store the environment variable values into the interpreter's + * "env" array, and arrange for us to be notified on future + * writes and unsets to that array. + */ + + (void) Tcl_UnsetVar2(interp, "env", (char *) NULL, TCL_GLOBAL_ONLY); + for (i = 0; ; i++) { + char *p, *p2; + + p = environ[i]; + if (p == NULL) { + break; + } + for (p2 = p; *p2 != '='; p2++) { + /* Empty loop body. */ + } + *p2 = 0; + (void) Tcl_SetVar2(interp, "env", p, p2+1, TCL_GLOBAL_ONLY); + *p2 = '='; + } + Tcl_TraceVar2(interp, "env", (char *) NULL, + TCL_GLOBAL_ONLY | TCL_TRACE_WRITES | TCL_TRACE_UNSETS, + EnvTraceProc, (void*) NULL); +} + +/* + *---------------------------------------------------------------------- + * + * FindVariable -- + * + * Locate the entry in environ for a given name. + * + * Results: + * The return value is the index in environ of an entry with the + * name "name", or -1 if there is no such entry. The integer at + * *lengthPtr is filled in with the length of name (if a matching + * entry is found) or the length of the environ array (if no matching + * entry is found). + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static int +FindVariable(name, lengthPtr) + const char *name; /* Name of desired environment variable. */ + int *lengthPtr; /* Used to return length of name (for + * successful searches) or number of non-NULL + * entries in environ (for unsuccessful + * searches). */ +{ + int i; + const register char *p1, *p2; + + for (i = 0, p1 = environ[i]; p1 != NULL; i++, p1 = environ[i]) { + for (p2 = name; *p2 == *p1; p1++, p2++) { + /* NULL loop body. */ + } + if ((*p1 == '=') && (*p2 == '\0')) { + *lengthPtr = p2-name; + return i; + } + } + *lengthPtr = i; + return -1; +} + +/* + *---------------------------------------------------------------------- + * + * setenv -- + * + * Set an environment variable, replacing an existing value + * or creating a new variable if there doesn't exist a variable + * by the given name. + * + * Results: + * None. + * + * Side effects: + * The environ array gets updated, as do all of the interpreters + * that we manage. + * + *---------------------------------------------------------------------- + */ + +int +setenv(name, value, overwrite) + const char *name; /* Name of variable whose value is to be + * set. */ + const char *value; /* New value for variable. */ +{ + int index, length, nameLength; + char *p; + EnvInterp *eiPtr; + + if (environSize == 0) { + EnvInit(); + } + + /* + * Figure out where the entry is going to go. If the name doesn't + * already exist, enlarge the array if necessary to make room. If + * the name exists, free its old entry. + */ + + index = FindVariable(name, &length); + if (index == -1) { + if ((length+2) > environSize) { + char **newEnviron; + + newEnviron = (char **) malloc((unsigned) + ((length+5) * sizeof(char *))); + memcpy((void *) newEnviron, (void *) environ, + length*sizeof(char *)); + free((char *) environ); + environ = newEnviron; + environSize = length+5; + } + index = length; + environ[index+1] = NULL; + nameLength = strlen(name); + } else { + /* + * Compare the new value to the existing value. If they're + * the same then quit immediately (e.g. don't rewrite the + * value or propagate it to other interpeters). Otherwise, + * when there are N interpreters there will be N! propagations + * of the same value among the interpreters. + */ + + if (strcmp(value, environ[index]+length+1) == 0) { + return 0; + } + free(environ[index]); + nameLength = length; + } + + /* + * Create a new entry and enter it into the table. + */ + + p = (char *) malloc((unsigned) (nameLength + strlen(value) + 2)); + environ[index] = p; + strcpy(p, name); + p += nameLength; + *p = '='; + strcpy(p+1, value); + + /* + * Update all of the interpreters. + */ + + for (eiPtr= firstInterpPtr; eiPtr != NULL; eiPtr = eiPtr->nextPtr) { + (void) Tcl_SetVar2(eiPtr->interp, "env", (char *) name, + p+1, TCL_GLOBAL_ONLY); + } + return 0; +} + +/* + *---------------------------------------------------------------------- + * + * putenv -- + * + * Set an environment variable. Similar to setenv except that + * the information is passed in a single string of the form + * NAME=value, rather than as separate name strings. This procedure + * is a stand-in for the standard UNIX procedure by the same name, + * so that applications using that procedure will interface + * properly to Tcl. + * + * Results: + * None. + * + * Side effects: + * The environ array gets updated, as do all of the interpreters + * that we manage. + * + *---------------------------------------------------------------------- + */ + +int +putenv(string) + char *string; /* Info about environment variable in the + * form NAME=value. */ +{ + int nameLength; + char *name, *value; + + if (string == NULL) { + return 0; + } + + /* + * Separate the string into name and value parts, then call + * setenv to do all of the real work. + */ + + value = strchr(string, '='); + if (value == NULL) { + return 0; + } + nameLength = value - string; + if (nameLength == 0) { + return 0; + } + name = malloc(nameLength+1); + memcpy(name, string, nameLength); + name[nameLength] = 0; + setenv(name, value+1, 1); + free(name); + return 0; +} + +/* + *---------------------------------------------------------------------- + * + * unsetenv -- + * + * Remove an environment variable, updating the "env" arrays + * in all interpreters managed by us. + * + * Results: + * None. + * + * Side effects: + * Interpreters are updated, as is environ. + * + *---------------------------------------------------------------------- + */ + +int +unsetenv(name) + const char *name; /* Name of variable to remove. */ +{ + int index, dummy; + char **envPtr; + EnvInterp *eiPtr; + + if (environSize == 0) { + EnvInit(); + } + + /* + * Update the environ array. + */ + + index = FindVariable(name, &dummy); + if (index == -1) { + return 0; + } + free(environ[index]); + for (envPtr = environ+index+1; ; envPtr++) { + envPtr[-1] = *envPtr; + if (*envPtr == NULL) { + break; + } + } + + /* + * Update all of the interpreters. + */ + + for (eiPtr = firstInterpPtr; eiPtr != NULL; eiPtr = eiPtr->nextPtr) { + (void) Tcl_UnsetVar2(eiPtr->interp, "env", (char *) name, + TCL_GLOBAL_ONLY); + } + return 0; +} + +/* + *---------------------------------------------------------------------- + * + * EnvTraceProc -- + * + * This procedure is invoked whenever an environment variable + * is modified or deleted. It propagates the change to the + * "environ" array and to any other interpreters for whom + * we're managing an "env" array. + * + * Results: + * Always returns NULL to indicate success. + * + * Side effects: + * Environment variable changes get propagated. If the whole + * "env" array is deleted, then we stop managing things for + * this interpreter (usually this happens because the whole + * interpreter is being deleted). + * + *---------------------------------------------------------------------- + */ + + /* ARGSUSED */ +static unsigned char * +EnvTraceProc(clientData, interp, name1, name2, flags) + void *clientData; /* Not used. */ + Tcl_Interp *interp; /* Interpreter whose "env" variable is + * being modified. */ + unsigned char *name1; /* Better be "env". */ + unsigned char *name2; /* Name of variable being modified, or + * NULL if whole array is being deleted. */ + int flags; /* Indicates what's happening. */ +{ + /* + * First see if the whole "env" variable is being deleted. If + * so, just forget about this interpreter. + */ + + if (name2 == NULL) { + register EnvInterp *eiPtr, *prevPtr; + + if ((flags & (TCL_TRACE_UNSETS|TCL_TRACE_DESTROYED)) + != (TCL_TRACE_UNSETS|TCL_TRACE_DESTROYED)) { + fprintf(stderr, "EnvTraceProc called with confusing arguments\n"); + abort(); + } + eiPtr = firstInterpPtr; + if (eiPtr->interp == interp) { + firstInterpPtr = eiPtr->nextPtr; + } else { + for (prevPtr = eiPtr, eiPtr = eiPtr->nextPtr; ; + prevPtr = eiPtr, eiPtr = eiPtr->nextPtr) { + if (eiPtr == NULL) { + fprintf(stderr, "EnvTraceProc couldn't find interpreter\n"); + abort(); + } + if (eiPtr->interp == interp) { + prevPtr->nextPtr = eiPtr->nextPtr; + break; + } + } + } + free((char *) eiPtr); + return NULL; + } + + /* + * If a value is being set, call setenv to do all of the work. + */ + + if (flags & TCL_TRACE_WRITES) { + setenv(name2, Tcl_GetVar2(interp, "env", name2, TCL_GLOBAL_ONLY), 1); + } + + if (flags & TCL_TRACE_UNSETS) { + unsetenv(name2); + } + return NULL; +} + +/* + *---------------------------------------------------------------------- + * + * EnvInit -- + * + * This procedure is called to initialize our management + * of the environ array. + * + * Results: + * None. + * + * Side effects: + * Environ gets copied to malloc-ed storage, so that in + * the future we don't have to worry about which entries + * are malloc-ed and which are static. + * + *---------------------------------------------------------------------- + */ + +static void +EnvInit() +{ + char **newEnviron; + int i, length; + + if (environSize != 0) { + return; + } + for (length = 0; environ[length] != NULL; length++) { + /* Empty loop body. */ + } + environSize = length+5; + newEnviron = (char **) malloc((unsigned) + (environSize * sizeof(char *))); + for (i = 0; i < length; i++) { + newEnviron[i] = (char *) malloc((unsigned) (strlen(environ[i]) + 1)); + strcpy(newEnviron[i], environ[i]); + } + newEnviron[length] = NULL; + environ = newEnviron; +} diff --git a/src/libtcl/tclexpr.c b/src/libtcl/tclexpr.c new file mode 100644 index 0000000..2d6c093 --- /dev/null +++ b/src/libtcl/tclexpr.c @@ -0,0 +1,1053 @@ +/* + * tclExpr.c -- + * + * This file contains the code to evaluate expressions for + * Tcl. + * + * This implementation of floating-point support was modelled + * after an initial implementation by Bill Carpenter. + * + * Copyright 1987-1991 Regents of the University of California + * 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. The University of California + * makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without + * express or implied warranty. + */ +#include "internal.h" + +/* + * The data structure below is used to describe an expression value, + * which can be either an integer (the usual case), or a string. + * A given number has only one value at a time. + */ +#define STATIC_STRING_SPACE 40 + +typedef struct { + unsigned char type; /* Type: TYPE_INT or TYPE_STRING. */ + long int_value; /* Integer value, if any. */ + ParseValue pv; /* A string value, if any. */ + unsigned char static_space [STATIC_STRING_SPACE]; + /* Storage for small strings; + * large ones are malloc-ed. */ +} Value_t; + +/* + * Valid values for type: + */ +#define TYPE_INT 0 +#define TYPE_STRING 1 + +/* + * The data structure below describes the state of parsing an expression. + * It's passed among the routines in this module. + */ +typedef struct { + unsigned char *original_expr; + /* The entire expression, as originally + * passed to Tcl_Expr. */ + unsigned char *expr; /* Position to the next character to be + * scanned from the expression string. */ + unsigned char token; /* Type of the last token to be parsed from + * expr. See below for definitions. + * Corresponds to the characters just + * before expr. */ +} Expr_info_t; + +/* + * The token types are defined below. In addition, there is a table + * associating a precedence with each operator. The order of types + * is important. Consult the code before changing it. + */ +#define VALUE 0 +#define OPEN_PAREN 1 +#define CLOSE_PAREN 2 +#define END 3 +#define UNKNOWN 4 + +/* + * Binary operators: + */ +#define MULT 8 +#define DIVIDE 9 +#define MOD 10 +#define PLUS 11 +#define MINUS 12 +#define LEFT_SHIFT 13 +#define RIGHT_SHIFT 14 +#define LESS 15 +#define GREATER 16 +#define LEQ 17 +#define GEQ 18 +#define EQUAL 19 +#define NEQ 20 +#define BIT_AND 21 +#define BIT_XOR 22 +#define BIT_OR 23 +#define AND 24 +#define OR 25 +#define QUESTY 26 +#define COLON 27 + +/* + * Unary operators: + */ +#define UNARY_MINUS 28 +#define NOT 29 +#define BIT_NOT 30 + +/* + * Precedence table. The values for non-operator token types are ignored. + */ +static unsigned char prec_table [] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 11, 11, 11, /* MULT, DIVIDE, MOD */ + 10, 10, /* PLUS, MINUS */ + 9, 9, /* LEFT_SHIFT, RIGHT_SHIFT */ + 8, 8, 8, 8, /* LESS, GREATER, LEQ, GEQ */ + 7, 7, /* EQUAL, NEQ */ + 6, /* BIT_AND */ + 5, /* BIT_XOR */ + 4, /* BIT_OR */ + 3, /* AND */ + 2, /* OR */ + 1, 1, /* QUESTY, COLON */ + 12, 12, 12 /* UNARY_MINUS, NOT, BIT_NOT */ +}; + +/* + * Mapping from operator numbers to strings; used for error messages. + */ +static char *operator_strings[] = { + "VALUE", "(", ")", "END", "UNKNOWN", "5", "6", "7", + "*", "/", "%", "+", "-", "<<", ">>", "<", ">", "<=", + ">=", "==", "!=", "&", "^", "|", "&&", "||", "?", ":", + "-", "!", "~" +}; + +/* + * Declarations for local procedures to this file: + */ +static void make_string (Value_t *valuePtr); + +/* + * Given a string (such as one coming from command or variable + * substitution), make a Value_t based on the string. The value + * will be a floating-point or integer, if possible, or else it + * will just be a copy of the string. + * + * Results: + * TCL_OK is returned under normal circumstances, and TCL_ERROR + * is returned if a floating-point overflow or underflow occurred + * while reading in a number. The value at *valuePtr is modified + * to hold a number, if possible. + * + * Side effects: + * None. + */ +static unsigned char +parse_string (Tcl_Interp *interp, /* Where to store error message. */ + unsigned char *string, /* String to turn into value. */ + Value_t *valuePtr) /* Where to store value information. + * Caller must have initialized pv field. */ +{ + char c; + + /* + * Try to convert the string to a number. + */ + c = *string; + if (((c >= '0') && (c <= '9')) || (c == '-')) { + unsigned char *term; + + valuePtr->type = TYPE_INT; + valuePtr->int_value = strtol (string, &term, 0); + c = *term; + if (c == '\0') { + return TCL_OK; + } + } + + /* + * Not a valid number. Save a string value (but don't do anything + * if it's already the value). + */ + valuePtr->type = TYPE_STRING; + if (string != valuePtr->pv.buffer) { + unsigned short length, space; + + length = strlen (string); + valuePtr->pv.next = valuePtr->pv.buffer; + space = valuePtr->pv.end - valuePtr->pv.buffer; + if (length > space) { + (*valuePtr->pv.expandProc) (&valuePtr->pv, length - space); + } + strcpy (valuePtr->pv.buffer, string); + } + return TCL_OK; +} + +/* + * Lexical analyzer for expression parser: parses a single value, + * operator, or other syntactic element from an expression string. + * + * Results: + * TCL_OK is returned unless an error occurred while doing lexical + * analysis or executing an embedded command. In that case a + * standard Tcl error is returned, using interp->result to hold + * an error message. In the event of a successful return, the token + * and field in infoPtr is updated to refer to the next symbol in + * the expression string, and the expr field is advanced past that + * token; if the token is a value, then the value is stored at + * valuePtr. + * + * Side effects: + * None. + */ +static unsigned char +get_lex (Tcl_Interp *interp, /* Interpreter to use for error reporting. */ + Expr_info_t *infoPtr, /* Describes the state of the parse. */ + Value_t *valuePtr) /* Where to store value, if that is + * what's parsed from string. Caller + * must have initialized pv field correctly. */ +{ + unsigned char *p, c, *var, *term; + unsigned char result; + + p = infoPtr->expr; + c = *p; + while (isspace(c)) { + p++; + c = *p; + } + infoPtr->expr = p+1; + switch (c) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + + /* + * Number. First read an integer. Then if it looks like + * there's a floating-point number (or if it's too big a + * number to fit in an integer), parse it as a floating-point + * number. + */ + + infoPtr->token = VALUE; + valuePtr->type = TYPE_INT; + valuePtr->int_value = strtoul (p, &term, 0); + c = *term; + infoPtr->expr = term; + return TCL_OK; + + case '$': + + /* + * Variable. Fetch its value, then see if it makes sense + * as an integer or floating-point number. + */ + + infoPtr->token = VALUE; + var = Tcl_ParseVar(interp, p, &infoPtr->expr); + if (var == 0) { + return TCL_ERROR; + } + if (((Interp *) interp)->noEval) { + valuePtr->type = TYPE_INT; + valuePtr->int_value = 0; + return TCL_OK; + } + return parse_string(interp, var, valuePtr); + + case '[': + infoPtr->token = VALUE; + result = Tcl_Eval(interp, p+1, TCL_BRACKET_TERM, + &infoPtr->expr); + if (result != TCL_OK) { + return result; + } + infoPtr->expr++; + if (((Interp *) interp)->noEval) { + valuePtr->type = TYPE_INT; + valuePtr->int_value = 0; + Tcl_ResetResult(interp); + return TCL_OK; + } + result = parse_string(interp, interp->result, valuePtr); + if (result != TCL_OK) { + return result; + } + Tcl_ResetResult(interp); + return TCL_OK; + + case '"': + infoPtr->token = VALUE; + result = TclParseQuotes(interp, infoPtr->expr, '"', 0, + &infoPtr->expr, &valuePtr->pv); + if (result != TCL_OK) { + return result; + } + return parse_string(interp, valuePtr->pv.buffer, valuePtr); + + case '{': + infoPtr->token = VALUE; + result = TclParseBraces(interp, infoPtr->expr, &infoPtr->expr, + &valuePtr->pv); + if (result != TCL_OK) { + return result; + } + return parse_string(interp, valuePtr->pv.buffer, valuePtr); + + case '(': + infoPtr->token = OPEN_PAREN; + return TCL_OK; + + case ')': + infoPtr->token = CLOSE_PAREN; + return TCL_OK; + + case '*': + infoPtr->token = MULT; + return TCL_OK; + + case '/': + infoPtr->token = DIVIDE; + return TCL_OK; + + case '%': + infoPtr->token = MOD; + return TCL_OK; + + case '+': + infoPtr->token = PLUS; + return TCL_OK; + + case '-': + infoPtr->token = MINUS; + return TCL_OK; + + case '?': + infoPtr->token = QUESTY; + return TCL_OK; + + case ':': + infoPtr->token = COLON; + return TCL_OK; + + case '<': + switch (p[1]) { + case '<': + infoPtr->expr = p+2; + infoPtr->token = LEFT_SHIFT; + break; + case '=': + infoPtr->expr = p+2; + infoPtr->token = LEQ; + break; + default: + infoPtr->token = LESS; + break; + } + return TCL_OK; + + case '>': + switch (p[1]) { + case '>': + infoPtr->expr = p+2; + infoPtr->token = RIGHT_SHIFT; + break; + case '=': + infoPtr->expr = p+2; + infoPtr->token = GEQ; + break; + default: + infoPtr->token = GREATER; + break; + } + return TCL_OK; + + case '=': + if (p[1] == '=') { + infoPtr->expr = p+2; + infoPtr->token = EQUAL; + } else { + infoPtr->token = UNKNOWN; + } + return TCL_OK; + + case '!': + if (p[1] == '=') { + infoPtr->expr = p+2; + infoPtr->token = NEQ; + } else { + infoPtr->token = NOT; + } + return TCL_OK; + + case '&': + if (p[1] == '&') { + infoPtr->expr = p+2; + infoPtr->token = AND; + } else { + infoPtr->token = BIT_AND; + } + return TCL_OK; + + case '^': + infoPtr->token = BIT_XOR; + return TCL_OK; + + case '|': + if (p[1] == '|') { + infoPtr->expr = p+2; + infoPtr->token = OR; + } else { + infoPtr->token = BIT_OR; + } + return TCL_OK; + + case '~': + infoPtr->token = BIT_NOT; + return TCL_OK; + + case 0: + infoPtr->token = END; + infoPtr->expr = p; + return TCL_OK; + + default: + infoPtr->expr = p+1; + infoPtr->token = UNKNOWN; + return TCL_OK; + } +} + +/* + * Parse a "value" from the remainder of the expression in infoPtr. + * + * Results: + * Normally TCL_OK is returned. The value of the expression is + * returned in *valuePtr. If an error occurred, then interp->result + * contains an error message and TCL_ERROR is returned. + * InfoPtr->token will be left pointing to the token AFTER the + * expression, and infoPtr->expr will point to the character just + * after the terminating token. + * + * Side effects: + * None. + */ +static unsigned char +get_value (Tcl_Interp *interp, /* Interpreter to use for error reporting. */ + Expr_info_t *infoPtr, /* Describes the state of the parse just + * before the value (i.e. get_lex will be + * called to get first token of value). */ + int prec, /* Treat any un-parenthesized operator + * with precedence <= this as the end + * of the expression. */ + Value_t *valuePtr) /* Where to store the value of the + * expression. Caller must have + * initialized pv field. */ +{ + Interp *iPtr = (Interp *) interp; + Value_t value2; /* Second operand for current + * operator. */ + int operator; /* Current operator (either unary + * or binary). */ + int gotOp; /* Non-zero means already lexed the + * operator (while picking up value + * for unary operator). Don't lex + * again. */ + unsigned char result; + + /* + * There are two phases to this procedure. First, pick off an initial + * value. Then, parse (binary operator, value) pairs until done. + */ + + gotOp = 0; + value2.pv.buffer = value2.pv.next = value2.static_space; + value2.pv.end = value2.pv.buffer + STATIC_STRING_SPACE - 1; + value2.pv.expandProc = TclExpandParseValue; + value2.pv.clientData = (void*) 0; + result = get_lex(interp, infoPtr, valuePtr); + if (result != TCL_OK) { + goto done; + } + if (infoPtr->token == OPEN_PAREN) { + + /* + * Parenthesized sub-expression. + */ + + result = get_value(interp, infoPtr, -1, valuePtr); + if (result != TCL_OK) { + goto done; + } + if (infoPtr->token != CLOSE_PAREN) { + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, + "unmatched parentheses in expression \"", + infoPtr->original_expr, "\"", 0); + result = TCL_ERROR; + goto done; + } + } else { + if (infoPtr->token == MINUS) { + infoPtr->token = UNARY_MINUS; + } + if (infoPtr->token >= UNARY_MINUS) { + + /* + * Process unary operators. + */ + + operator = infoPtr->token; + result = get_value(interp, infoPtr, prec_table[infoPtr->token], + valuePtr); + if (result != TCL_OK) { + goto done; + } + switch (operator) { + case UNARY_MINUS: + if (valuePtr->type == TYPE_INT) { + valuePtr->int_value = -valuePtr->int_value; + } else { + goto illegalType; + } + break; + case NOT: + if (valuePtr->type == TYPE_INT) { + valuePtr->int_value = !valuePtr->int_value; + } else { + goto illegalType; + } + break; + case BIT_NOT: + if (valuePtr->type == TYPE_INT) { + valuePtr->int_value = ~valuePtr->int_value; + } else { + goto illegalType; + } + break; + } + gotOp = 1; + } else if (infoPtr->token != VALUE) { + goto syntaxError; + } + } + + /* + * Got the first operand. Now fetch (operator, operand) pairs. + */ + + if (!gotOp) { + result = get_lex(interp, infoPtr, &value2); + if (result != TCL_OK) { + goto done; + } + } + while (1) { + operator = infoPtr->token; + value2.pv.next = value2.pv.buffer; + if ((operator < MULT) || (operator >= UNARY_MINUS)) { + if ((operator == END) || (operator == CLOSE_PAREN)) { + result = TCL_OK; + goto done; + } else { + goto syntaxError; + } + } + if (prec_table[operator] <= prec) { + result = TCL_OK; + goto done; + } + + /* + * If we're doing an AND or OR and the first operand already + * determines the result, don't execute anything in the + * second operand: just parse. Same style for ?: pairs. + */ + + if ((operator == AND) || (operator == OR) || (operator == QUESTY)) { + if (valuePtr->type == TYPE_STRING) { + goto illegalType; + } + if (((operator == AND) && !valuePtr->int_value) + || ((operator == OR) && valuePtr->int_value)) { + iPtr->noEval++; + result = get_value(interp, infoPtr, prec_table[operator], + &value2); + iPtr->noEval--; + } else if (operator == QUESTY) { + if (valuePtr->int_value != 0) { + valuePtr->pv.next = valuePtr->pv.buffer; + result = get_value(interp, infoPtr, prec_table[operator], + valuePtr); + if (result != TCL_OK) { + goto done; + } + if (infoPtr->token != COLON) { + goto syntaxError; + } + value2.pv.next = value2.pv.buffer; + iPtr->noEval++; + result = get_value(interp, infoPtr, prec_table[operator], + &value2); + iPtr->noEval--; + } else { + iPtr->noEval++; + result = get_value(interp, infoPtr, prec_table[operator], + &value2); + iPtr->noEval--; + if (result != TCL_OK) { + goto done; + } + if (infoPtr->token != COLON) { + goto syntaxError; + } + valuePtr->pv.next = valuePtr->pv.buffer; + result = get_value(interp, infoPtr, prec_table[operator], + valuePtr); + } + } else { + result = get_value(interp, infoPtr, prec_table[operator], + &value2); + } + } else { + result = get_value(interp, infoPtr, prec_table[operator], + &value2); + } + if (result != TCL_OK) { + goto done; + } + if ((infoPtr->token < MULT) && (infoPtr->token != VALUE) + && (infoPtr->token != END) + && (infoPtr->token != CLOSE_PAREN)) { + goto syntaxError; + } + + /* + * At this point we've got two values and an operator. Check + * to make sure that the particular data types are appropriate + * for the particular operator, and perform type conversion + * if necessary. + */ + + switch (operator) { + + /* + * For the operators below, no strings are allowed and + * ints get converted to floats if necessary. + */ + + case MULT: case DIVIDE: case PLUS: case MINUS: + if ((valuePtr->type == TYPE_STRING) + || (value2.type == TYPE_STRING)) { + goto illegalType; + } + break; + + /* + * For the operators below, only integers are allowed. + */ + + case MOD: case LEFT_SHIFT: case RIGHT_SHIFT: + case BIT_AND: case BIT_XOR: case BIT_OR: + if (valuePtr->type != TYPE_INT) { + goto illegalType; + } else if (value2.type != TYPE_INT) { + goto illegalType; + } + break; + + /* + * For the operators below, any type is allowed but the + * two operands must have the same type. Convert integers + * to floats and either to strings, if necessary. + */ + + case LESS: case GREATER: case LEQ: case GEQ: + case EQUAL: case NEQ: + if (valuePtr->type == TYPE_STRING) { + if (value2.type != TYPE_STRING) { + make_string (&value2); + } + } else if (value2.type == TYPE_STRING) { + if (valuePtr->type != TYPE_STRING) { + make_string (valuePtr); + } + } + break; + + /* + * For the operators below, no strings are allowed. + */ + case AND: case OR: + if (valuePtr->type == TYPE_STRING) { + goto illegalType; + } + if (value2.type == TYPE_STRING) { + goto illegalType; + } + break; + + /* + * For the operators below, type and conversions are + * irrelevant: they're handled elsewhere. + */ + + case QUESTY: case COLON: + break; + + /* + * Any other operator is an error. + */ + + default: + interp->result = (unsigned char*) "unknown operator in expression"; + result = TCL_ERROR; + goto done; + } + + /* + * If necessary, convert one of the operands to the type + * of the other. If the operands are incompatible with + * the operator (e.g. "+" on strings) then return an + * error. + */ + + switch (operator) { + case MULT: + if (valuePtr->type == TYPE_INT) { + valuePtr->int_value *= value2.int_value; + } + break; + case DIVIDE: + if (valuePtr->type == TYPE_INT) { + if (value2.int_value == 0) { + divideByZero: + interp->result = (unsigned char*) "divide by zero"; + result = TCL_ERROR; + goto done; + } + valuePtr->int_value /= value2.int_value; + } + break; + case MOD: + if (value2.int_value == 0) { + goto divideByZero; + } + valuePtr->int_value %= value2.int_value; + break; + case PLUS: + if (valuePtr->type == TYPE_INT) { + valuePtr->int_value += value2.int_value; + } + break; + case MINUS: + if (valuePtr->type == TYPE_INT) { + valuePtr->int_value -= value2.int_value; + } + break; + case LEFT_SHIFT: + valuePtr->int_value <<= value2.int_value; + break; + case RIGHT_SHIFT: + /* + * The following code is a bit tricky: it ensures that + * right shifts propagate the sign bit even on machines + * where ">>" won't do it by default. + */ + + if (valuePtr->int_value < 0) { + valuePtr->int_value = + ~((~valuePtr->int_value) >> value2.int_value); + } else { + valuePtr->int_value >>= value2.int_value; + } + break; + case LESS: + if (valuePtr->type == TYPE_INT) { + valuePtr->int_value = + valuePtr->int_value < value2.int_value; + } else { + valuePtr->int_value = + strcmp(valuePtr->pv.buffer, value2.pv.buffer) < 0; + } + valuePtr->type = TYPE_INT; + break; + case GREATER: + if (valuePtr->type == TYPE_INT) { + valuePtr->int_value = + valuePtr->int_value > value2.int_value; + } else { + valuePtr->int_value = + strcmp(valuePtr->pv.buffer, value2.pv.buffer) > 0; + } + valuePtr->type = TYPE_INT; + break; + case LEQ: + if (valuePtr->type == TYPE_INT) { + valuePtr->int_value = + valuePtr->int_value <= value2.int_value; + } else { + valuePtr->int_value = + strcmp(valuePtr->pv.buffer, value2.pv.buffer) <= 0; + } + valuePtr->type = TYPE_INT; + break; + case GEQ: + if (valuePtr->type == TYPE_INT) { + valuePtr->int_value = + valuePtr->int_value >= value2.int_value; + } else { + valuePtr->int_value = + strcmp(valuePtr->pv.buffer, value2.pv.buffer) >= 0; + } + valuePtr->type = TYPE_INT; + break; + case EQUAL: + if (valuePtr->type == TYPE_INT) { + valuePtr->int_value = + valuePtr->int_value == value2.int_value; + } else { + valuePtr->int_value = + strcmp(valuePtr->pv.buffer, value2.pv.buffer) == 0; + } + valuePtr->type = TYPE_INT; + break; + case NEQ: + if (valuePtr->type == TYPE_INT) { + valuePtr->int_value = + valuePtr->int_value != value2.int_value; + } else { + valuePtr->int_value = + strcmp(valuePtr->pv.buffer, value2.pv.buffer) != 0; + } + valuePtr->type = TYPE_INT; + break; + case BIT_AND: + valuePtr->int_value &= value2.int_value; + break; + case BIT_XOR: + valuePtr->int_value ^= value2.int_value; + break; + case BIT_OR: + valuePtr->int_value |= value2.int_value; + break; + + case AND: + valuePtr->int_value = valuePtr->int_value && value2.int_value; + break; + case OR: + valuePtr->int_value = valuePtr->int_value || value2.int_value; + break; + + case COLON: + interp->result = (unsigned char*) "can't have : operator without ? first"; + result = TCL_ERROR; + goto done; + } + } + + done: + if (value2.pv.buffer != value2.static_space) { + free (value2.pv.buffer); + } + return result; + + syntaxError: + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, "syntax error in expression \"", + infoPtr->original_expr, "\"", 0); + result = TCL_ERROR; + goto done; + + illegalType: + Tcl_AppendResult(interp, "can't use non-numeric string as operand of \"", + operator_strings[operator], "\"", 0); + result = TCL_ERROR; + goto done; +} + +/* + * Convert a value from int representation to a string. + * + * Results: + * The information at *valuePtr gets converted to string + * format, if it wasn't that way already. + * + * Side effects: + * None. + */ +static void +make_string (Value_t *valuePtr) /* Value to be converted. */ +{ + unsigned short space; + + space = valuePtr->pv.end - valuePtr->pv.buffer; + if (20 > space) { + (*valuePtr->pv.expandProc) (&valuePtr->pv, 20 - space); + } + if (valuePtr->type == TYPE_INT) { + sprintf (valuePtr->pv.buffer, "%ld", valuePtr->int_value); + } + valuePtr->type = TYPE_STRING; +} + +/* + * This procedure provides top-level functionality shared by + * procedures like Tcl_ExprInt, etc. + * + * Results: + * The result is a standard Tcl return value. If an error + * occurs then an error message is left in interp->result. + * The value of the expression is returned in *valuePtr, in + * whatever form it ends up in (could be string or integer). + * Caller may need to convert result. Caller + * is also responsible for freeing string memory in *valuePtr, + * if any was allocated. + * + * Side effects: + * None. + */ +static unsigned char +evaluate (Tcl_Interp *interp, /* Context in which to evaluate the + * expression. */ + unsigned char *string, /* Expression to evaluate. */ + Value_t *valuePtr) /* Where to store result. Should + * not be initialized by caller. */ +{ + Expr_info_t info; + unsigned char result; + + info.original_expr = string; + info.expr = string; + valuePtr->pv.buffer = valuePtr->pv.next = valuePtr->static_space; + valuePtr->pv.end = valuePtr->pv.buffer + STATIC_STRING_SPACE - 1; + valuePtr->pv.expandProc = TclExpandParseValue; + valuePtr->pv.clientData = (void*) 0; + + result = get_value(interp, &info, -1, valuePtr); + if (result != TCL_OK) { + return result; + } + if (info.token != END) { + Tcl_AppendResult(interp, "syntax error in expression \"", + string, "\"", 0); + return TCL_ERROR; + } + return TCL_OK; +} + +/* + * Procedures to evaluate an expression and return its value + * in a particular form. + * + * Results: + * Each of the procedures below returns a standard Tcl result. + * If an error occurs then an error message is left in + * interp->result. Otherwise the value of the expression, + * in the appropriate form, is stored at *resultPtr. If + * the expression had a result that was incompatible with the + * desired form then an error is returned. + * + * Side effects: + * None. + */ +int +Tcl_ExprLong (Tcl_Interp *interp, /* Context in which to evaluate the + * expression. */ + unsigned char *string, /* Expression to evaluate. */ + long *ptr) /* Where to store result. */ +{ + Value_t value; + unsigned char result; + + result = evaluate (interp, string, &value); + if (result == TCL_OK) { + if (value.type == TYPE_INT) { + *ptr = value.int_value; + } else { + interp->result = (unsigned char*) "expression didn't have numeric value"; + result = TCL_ERROR; + } + } + if (value.pv.buffer != value.static_space) { + free (value.pv.buffer); + } + return result; +} + +int +Tcl_ExprBoolean (Tcl_Interp *interp, /* Context in which to evaluate the + * expression. */ + unsigned char *string, /* Expression to evaluate. */ + int *ptr) /* Where to store 0/1 result. */ +{ + Value_t value; + unsigned char result; + + result = evaluate (interp, string, &value); + if (result == TCL_OK) { + if (value.type == TYPE_INT) { + *ptr = value.int_value != 0; + } else { + interp->result = (unsigned char*) "expression didn't have numeric value"; + result = TCL_ERROR; + } + } + if (value.pv.buffer != value.static_space) { + free (value.pv.buffer); + } + return result; +} + +/* + * Evaluate an expression and return its value in string form. + * + * Results: + * A standard Tcl result. If the result is TCL_OK, then the + * interpreter's result is set to the string value of the + * expression. If the result is TCL_OK, then interp->result + * contains an error message. + * + * Side effects: + * None. + */ +int +Tcl_ExprString (Tcl_Interp *interp, /* Context in which to evaluate the + * expression. */ + unsigned char *string) /* Expression to evaluate. */ +{ + Value_t value; + unsigned char result; + + result = evaluate (interp, string, &value); + if (result == TCL_OK) { + if (value.type == TYPE_INT) { + sprintf (interp->result, "%ld", value.int_value); + } else { + if (value.pv.buffer != value.static_space) { + interp->result = value.pv.buffer; + interp->freeProc = (Tcl_FreeProc *) free; + value.pv.buffer = value.static_space; + } else { + Tcl_SetResult (interp, value.pv.buffer, TCL_VOLATILE); + } + } + } + if (value.pv.buffer != value.static_space) { + free (value.pv.buffer); + } + return result; +} diff --git a/src/libtcl/tclget.c b/src/libtcl/tclget.c new file mode 100644 index 0000000..6b427a3 --- /dev/null +++ b/src/libtcl/tclget.c @@ -0,0 +1,136 @@ +/* + * tclGet.c -- + * + * This file contains procedures to convert strings into + * other forms, like integers or floating-point numbers or + * booleans, doing syntax checking along the way. + * + * Copyright 1990-1991 Regents of the University of California + * 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. The University of California + * makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without + * express or implied warranty. + */ +#include "internal.h" + +/* + *---------------------------------------------------------------------- + * + * Tcl_GetInt -- + * + * Given a string, produce the corresponding integer value. + * + * Results: + * The return value is normally TCL_OK; in this case *intPtr + * will be set to the integer value equivalent to string. If + * string is improperly formed then TCL_ERROR is returned and + * an error message will be left in interp->result. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +Tcl_GetInt(interp, string, intPtr) + Tcl_Interp *interp; /* Interpreter to use for error reporting. */ + unsigned char *string; /* String containing a (possibly signed) + * integer in a form acceptable to strtol. */ + int *intPtr; /* Place to store converted result. */ +{ + unsigned char *end; + int i; + + i = strtol(string, &end, 0); + while ((*end != '\0') && isspace(*end)) { + end++; + } + if ((end == string) || (*end != 0)) { + Tcl_AppendResult(interp, "expected integer but got \"", string, + "\"", (char *) 0); + return TCL_ERROR; + } + *intPtr = i; + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_GetBoolean -- + * + * Given a string, return a 0/1 boolean value corresponding + * to the string. + * + * Results: + * The return value is normally TCL_OK; in this case *boolPtr + * will be set to the 0/1 value equivalent to string. If + * string is improperly formed then TCL_ERROR is returned and + * an error message will be left in interp->result. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +Tcl_GetBoolean(interp, string, boolPtr) + Tcl_Interp *interp; /* Interpreter to use for error reporting. */ + unsigned char *string; /* String containing a boolean number + * specified either as 1/0 or true/false or + * yes/no. */ + int *boolPtr; /* Place to store converted result, which + * will be 0 or 1. */ +{ + char c; + unsigned char lowerCase[10]; + int i, length; + + /* + * Convert the input string to all lower-case. + */ + + for (i = 0; i < 9; i++) { + c = string[i]; + if (c == 0) { + break; + } + if ((c >= 'A') && (c <= 'Z')) { + c += 'a' - 'A'; + } + lowerCase[i] = c; + } + lowerCase[i] = 0; + + length = strlen(lowerCase); + c = lowerCase[0]; + if ((c == '0') && (lowerCase[1] == '\0')) { + *boolPtr = 0; + } else if ((c == '1') && (lowerCase[1] == '\0')) { + *boolPtr = 1; + } else if ((c == 'y') && (strncmp(lowerCase, (unsigned char*) "yes", length) == 0)) { + *boolPtr = 1; + } else if ((c == 'n') && (strncmp(lowerCase, (unsigned char*) "no", length) == 0)) { + *boolPtr = 0; + } else if ((c == 't') && (strncmp(lowerCase, (unsigned char*) "true", length) == 0)) { + *boolPtr = 1; + } else if ((c == 'f') && (strncmp(lowerCase, (unsigned char*) "false", length) == 0)) { + *boolPtr = 0; + } else if ((c == 'o') && (length >= 2)) { + if (strncmp(lowerCase, (unsigned char*) "on", length) == 0) { + *boolPtr = 1; + } else if (strncmp(lowerCase, (unsigned char*) "off", length) == 0) { + *boolPtr = 0; + } + } else { + Tcl_AppendResult(interp, "expected boolean value but got \"", + string, "\"", (char *) 0); + return TCL_ERROR; + } + return TCL_OK; +} diff --git a/src/libtcl/tclglob.c b/src/libtcl/tclglob.c new file mode 100644 index 0000000..ec565a4 --- /dev/null +++ b/src/libtcl/tclglob.c @@ -0,0 +1,566 @@ +/* + * tclGlob.c -- + * + * This file provides procedures and commands for file name + * manipulation, such as tilde expansion and globbing. + * + * Copyright 1990-1991 Regents of the University of California + * 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. The University of California + * makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without + * express or implied warranty. + */ +#include "internal.h" +#include +#include +#include +#ifdef CROSS +# include +#else +# include +# define dirent direct +#endif + +/* + * The structure below is used to keep track of a globbing result + * being built up (i.e. a partial list of file names). The list + * grows dynamically to be as big as needed. + */ + +typedef struct { + char *result; /* Pointer to result area. */ + int totalSpace; /* Total number of characters allocated + * for result. */ + int spaceUsed; /* Number of characters currently in use + * to hold the partial result (not including + * the terminating NULL). */ + int dynamic; /* 0 means result is static space, 1 means + * it's dynamic. */ +} GlobResult; + +/* + * Declarations for procedures local to this file: + */ + +static void AppendResult (Tcl_Interp *interp, + char *dir, char *separator, char *name, + int nameLength); +static int DoGlob (Tcl_Interp *interp, char *dir, + char *rem); + +/* + *---------------------------------------------------------------------- + * + * AppendResult -- + * + * Given two parts of a file name (directory and element within + * directory), concatenate the two together and append them to + * the result building up in interp. + * + * Results: + * There is no return value. + * + * Side effects: + * Interp->result gets extended. + * + *---------------------------------------------------------------------- + */ + +static void +AppendResult(interp, dir, separator, name, nameLength) + Tcl_Interp *interp; /* Interpreter whose result should be + * appended to. */ + char *dir; /* Name of directory, without trailing + * slash except for root directory. */ + char *separator; /* Separator string so use between dir and + * name: either "/" or "" depending on dir. */ + char *name; /* Name of file withing directory (NOT + * necessarily null-terminated!). */ + int nameLength; /* Number of characters in name. */ +{ + int dirFlags, nameFlags; + char *p, saved; + + /* + * Next, see if we can put together a valid list element from dir + * and name by calling Tcl_AppendResult. + */ + + if (*dir == 0) { + dirFlags = 0; + } else { + Tcl_ScanElement(dir, &dirFlags); + } + saved = name[nameLength]; + name[nameLength] = 0; + Tcl_ScanElement(name, &nameFlags); + if ((dirFlags == 0) && (nameFlags == 0)) { + if (*interp->result != 0) { + Tcl_AppendResult(interp, " ", dir, separator, name, (char *) NULL); + } else { + Tcl_AppendResult(interp, dir, separator, name, (char *) NULL); + } + name[nameLength] = saved; + return; + } + + /* + * This name has weird characters in it, so we have to convert it to + * a list element. To do that, we have to merge the characters + * into a single name. To do that, malloc a buffer to hold everything. + */ + + p = (char *) malloc((unsigned) (strlen(dir) + strlen(separator) + + nameLength + 1)); + sprintf(p, "%s%s%s", dir, separator, name); + name[nameLength] = saved; + Tcl_AppendElement(interp, p, 0); + free(p); +} + +/* + *---------------------------------------------------------------------- + * + * DoGlob -- + * + * This recursive procedure forms the heart of the globbing + * code. It performs a depth-first traversal of the tree + * given by the path name to be globbed. + * + * Results: + * The return value is a standard Tcl result indicating whether + * an error occurred in globbing. After a normal return the + * result in interp will be set to hold all of the file names + * given by the dir and rem arguments. After an error the + * result in interp will hold an error message. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static int +DoGlob(interp, dir, rem) + Tcl_Interp *interp; /* Interpreter to use for error + * reporting (e.g. unmatched brace). */ + char *dir; /* Name of a directory at which to + * start glob expansion. This name + * is fixed: it doesn't contain any + * globbing chars. */ + char *rem; /* Path to glob-expand. */ +{ + /* + * When this procedure is entered, the name to be globbed may + * already have been partly expanded by ancestor invocations of + * DoGlob. The part that's already been expanded is in "dir" + * (this may initially be empty), and the part still to expand + * is in "rem". This procedure expands "rem" one level, making + * recursive calls to itself if there's still more stuff left + * in the remainder. + */ + + register char *p; + register char c; + char *openBrace, *closeBrace; + int gotSpecial, result; + char *separator; + + /* + * Figure out whether we'll need to add a slash between the directory + * name and file names within the directory when concatenating them + * together. + */ + + if ((dir[0] == 0) || ((dir[0] == '/') && (dir[1] == 0))) { + separator = ""; + } else { + separator = "/"; + } + + /* + * When generating information for the next lower call, + * use static areas if the name is short, and malloc if the name + * is longer. + */ + +#define STATIC_SIZE 200 + + /* + * First, find the end of the next element in rem, checking + * along the way for special globbing characters. + */ + + gotSpecial = 0; + openBrace = closeBrace = NULL; + for (p = rem; ; p++) { + c = *p; + if ((c == '\0') || (c == '/')) { + break; + } + if ((c == '{') && (openBrace == NULL)) { + openBrace = p; + } + if ((c == '}') && (closeBrace == NULL)) { + closeBrace = p; + } + if ((c == '*') || (c == '[') || (c == '\\') || (c == '?')) { + gotSpecial = 1; + } + } + + /* + * If there is an open brace in the argument, then make a recursive + * call for each element between the braces. In this case, the + * recursive call to DoGlob uses the same "dir" that we got. + * If there are several brace-pairs in a single name, we just handle + * one here, and the others will be handled in recursive calls. + */ + + if (openBrace != NULL) { + int remLength, l1, l2; + char static1[STATIC_SIZE]; + char *element, *newRem; + + if (closeBrace == NULL) { + Tcl_ResetResult(interp); + interp->result = "unmatched open-brace in file name"; + return TCL_ERROR; + } + remLength = strlen(rem) + 1; + if (remLength <= STATIC_SIZE) { + newRem = static1; + } else { + newRem = (char *) malloc((unsigned) remLength); + } + l1 = openBrace-rem; + strncpy(newRem, rem, l1); + p = openBrace; + for (p = openBrace; *p != '}'; ) { + element = p+1; + for (p = element; ((*p != '}') && (*p != ',')); p++) { + /* Empty loop body: just find end of this element. */ + } + l2 = p - element; + strncpy(newRem+l1, element, l2); + strcpy(newRem+l1+l2, closeBrace+1); + if (DoGlob(interp, dir, newRem) != TCL_OK) { + return TCL_ERROR; + } + } + if (remLength > STATIC_SIZE) { + free(newRem); + } + return TCL_OK; + } + + /* + * If there were any pattern-matching characters, then scan through + * the directory to find all the matching names. + */ + + if (gotSpecial) { + DIR *d; + struct dirent *entryPtr; + int l1, l2; + char *pattern, *newDir, *dirName; + char static1[STATIC_SIZE], static2[STATIC_SIZE]; + struct stat statBuf; + + /* + * Be careful not to do any actual file system operations on a + * directory named ""; instead, use ".". This is needed because + * some versions of UNIX don't treat "" like "." automatically. + */ + + if (*dir == '\0') { + dirName = "."; + } else { + dirName = dir; + } + if ((stat(dirName, &statBuf) != 0) || !S_ISDIR(statBuf.st_mode)) { + return TCL_OK; + } + d = opendir(dirName); + if (d == NULL) { + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, "couldn't read directory \"", + dirName, "\": ", Tcl_UnixError(interp), (char *) NULL); + return TCL_ERROR; + } + l1 = strlen(dir); + l2 = (p - rem); + if (l2 < STATIC_SIZE) { + pattern = static2; + } else { + pattern = (char *) malloc((unsigned) (l2+1)); + } + strncpy(pattern, rem, l2); + pattern[l2] = '\0'; + result = TCL_OK; + while (1) { + entryPtr = readdir(d); + if (entryPtr == NULL) { + break; + } + + /* + * Don't match names starting with "." unless the "." is + * present in the pattern. + */ + + if ((*entryPtr->d_name == '.') && (*pattern != '.')) { + continue; + } + if (Tcl_StringMatch(entryPtr->d_name, pattern)) { + int nameLength = strlen(entryPtr->d_name); + if (*p == 0) { + AppendResult(interp, dir, separator, entryPtr->d_name, + nameLength); + } else { + if ((l1+nameLength+2) <= STATIC_SIZE) { + newDir = static1; + } else { + newDir = (char *) malloc((unsigned) (l1+nameLength+2)); + } + sprintf(newDir, "%s%s%s", dir, separator, entryPtr->d_name); + result = DoGlob(interp, newDir, p+1); + if (newDir != static1) { + free(newDir); + } + if (result != TCL_OK) { + break; + } + } + } + } + closedir(d); + if (pattern != static2) { + free(pattern); + } + return result; + } + + /* + * This is the simplest case: just another path element. Move + * it to the dir side and recurse (or just add the name to the + * list, if we're at the end of the path). + */ + + if (*p == 0) { + AppendResult(interp, dir, separator, rem, p-rem); + } else { + int l1, l2; + char *newDir; + char static1[STATIC_SIZE]; + + l1 = strlen(dir); + l2 = l1 + (p - rem) + 2; + if (l2 <= STATIC_SIZE) { + newDir = static1; + } else { + newDir = (char *) malloc((unsigned) l2); + } + sprintf(newDir, "%s%s%.*s", dir, separator, (int) (p - rem), rem); + result = DoGlob(interp, newDir, p+1); + if (newDir != static1) { + free(newDir); + } + if (result != TCL_OK) { + return TCL_ERROR; + } + } + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_TildeSubst -- + * + * Given a name starting with a tilde, produce a name where + * the tilde and following characters have been replaced by + * the home directory location for the named user. + * + * Results: + * The result is a pointer to a static string containing + * the new name. This name will only persist until the next + * call to Tcl_TildeSubst; save it if you care about it for + * the long term. If there was an error in processing the + * tilde, then an error message is left in interp->result + * and the return value is NULL. + * + * Side effects: + * None that the caller needs to worry about. + * + *---------------------------------------------------------------------- + */ + +unsigned char * +Tcl_TildeSubst(interp, name) + Tcl_Interp *interp; /* Interpreter in which to store error + * message (if necessary). */ + unsigned char *name; /* File name, which may begin with "~/" + * (to indicate current user's home directory) + * or "~/" (to indicate any user's + * home directory). */ +{ +#define STATIC_BUF_SIZE 50 + static char staticBuf[STATIC_BUF_SIZE]; + static int curSize = STATIC_BUF_SIZE; + static char *curBuf = staticBuf; + char *dir; + int length; + int fromPw = 0; + register unsigned char *p; + + if (name[0] != '~') { + return name; + } + + /* + * First, find the directory name corresponding to the tilde entry. + */ + + if ((name[1] == '/') || (name[1] == '\0')) { + dir = getenv("HOME"); + if (dir == NULL) { + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, "couldn't find HOME environment ", + "variable to expand \"", name, "\"", (char *) NULL); + return NULL; + } + p = name+1; + } else { + struct passwd *pwPtr; + + for (p = &name[1]; (*p != 0) && (*p != '/'); p++) { + /* Null body; just find end of name. */ + } + length = p - &name[1]; + if (length >= curSize) { + length = curSize-1; + } + memcpy((void *) curBuf, (void *) (name+1), length); + curBuf[length] = '\0'; + pwPtr = getpwnam(curBuf); + if (pwPtr == NULL) { + endpwent(); + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, "user \"", curBuf, + "\" doesn't exist", (char *) NULL); + return NULL; + } + dir = pwPtr->pw_dir; + fromPw = 1; + } + + /* + * Grow the buffer if necessary to make enough space for the + * full file name. + */ + + length = strlen(dir) + strlen(p); + if (length >= curSize) { + if (curBuf != staticBuf) { + free(curBuf); + } + curSize = length + 1; + curBuf = (char *) malloc((unsigned) curSize); + } + + /* + * Finally, concatenate the directory name with the remainder + * of the path in the buffer. + */ + + strcpy(curBuf, dir); + strcat(curBuf, p); + if (fromPw) { + endpwent(); + } + return curBuf; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_GlobCmd -- + * + * This procedure is invoked to process the "glob" Tcl command. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *---------------------------------------------------------------------- + */ + + /* ARGSUSED */ +int +Tcl_GlobCmd(dummy, interp, argc, argv) + void *dummy; /* Not used. */ + Tcl_Interp *interp; /* Current interpreter. */ + int argc; /* Number of arguments. */ + unsigned char **argv; /* Argument strings. */ +{ + int i, result, noComplain; + + if (argc < 2) { + notEnoughArgs: + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " ?-nocomplain? name ?name ...?\"", (char *) NULL); + return TCL_ERROR; + } + noComplain = 0; + if ((argv[1][0] == '-') && (strcmp(argv[1], "-nocomplain") == 0)) { + if (argc < 3) { + goto notEnoughArgs; + } + noComplain = 1; + } + + for (i = 1 + noComplain; i < argc; i++) { + char *thisName; + + /* + * Do special checks for names starting at the root and for + * names beginning with ~. Then let DoGlob do the rest. + */ + + thisName = argv[i]; + if (*thisName == '~') { + thisName = Tcl_TildeSubst(interp, thisName); + if (thisName == NULL) { + return TCL_ERROR; + } + } + if (*thisName == '/') { + result = DoGlob(interp, "/", thisName+1); + } else { + result = DoGlob(interp, "", thisName); + } + if (result != TCL_OK) { + return result; + } + } + if ((*interp->result == 0) && !noComplain) { + char *sep = ""; + + Tcl_AppendResult(interp, "no files matched glob pattern", + (argc == 2) ? " \"" : "s \"", (char *) NULL); + for (i = 1; i < argc; i++) { + Tcl_AppendResult(interp, sep, argv[i], (char *) NULL); + sep = " "; + } + Tcl_AppendResult(interp, "\"", (char *) NULL); + return TCL_ERROR; + } + return TCL_OK; +} diff --git a/src/libtcl/tclhash.c b/src/libtcl/tclhash.c new file mode 100644 index 0000000..3f729e9 --- /dev/null +++ b/src/libtcl/tclhash.c @@ -0,0 +1,908 @@ +/* + * tclHash.c -- + * + * Implementation of in-memory hash tables for Tcl and Tcl-based + * applications. + * + * Copyright 1991 Regents of the University of California + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without + * fee is hereby granted, provided that this copyright + * notice appears in all copies. The University of California + * makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without + * express or implied warranty. + */ +#include "internal.h" +#include + +/* + * When there are this many entries per bucket, on average, rebuild + * the hash table to make it larger. + */ + +#define REBUILD_MULTIPLIER 3 + + +/* + * The following macro takes a preliminary integer hash value and + * produces an index into a hash tables bucket list. The idea is + * to make it so that preliminary values that are arbitrarily similar + * will end up in different buckets. The hash function was taken + * from a random-number generator. + */ + +#define RANDOM_INDEX(tablePtr, i) \ + (((((size_t) (i))*1103515245) >> (tablePtr)->downShift) & (tablePtr)->mask) + +/* + * Procedure prototypes for static procedures in this file: + */ + +static Tcl_HashEntry * ArrayFind (Tcl_HashTable *tablePtr, unsigned char *key); +static Tcl_HashEntry * ArrayCreate (Tcl_HashTable *tablePtr, unsigned char *key, + int *newPtr); +static Tcl_HashEntry * BogusFind (Tcl_HashTable *tablePtr, unsigned char *key); +static Tcl_HashEntry * BogusCreate (Tcl_HashTable *tablePtr, unsigned char *key, + int *newPtr); +static unsigned int HashString (unsigned char *string); +static void RebuildTable (Tcl_HashTable *tablePtr); +static Tcl_HashEntry * StringFind (Tcl_HashTable *tablePtr, unsigned char *key); +static Tcl_HashEntry * StringCreate (Tcl_HashTable *tablePtr, unsigned char *key, + int *newPtr); +static Tcl_HashEntry * OneWordFind (Tcl_HashTable *tablePtr, unsigned char *key); +static Tcl_HashEntry * OneWordCreate (Tcl_HashTable *tablePtr, unsigned char *key, + int *newPtr); + +/* + *---------------------------------------------------------------------- + * + * Tcl_InitHashTable -- + * + * Given storage for a hash table, set up the fields to prepare + * the hash table for use. + * + * Results: + * None. + * + * Side effects: + * TablePtr is now ready to be passed to Tcl_FindHashEntry and + * Tcl_CreateHashEntry. + * + *---------------------------------------------------------------------- + */ + +void +Tcl_InitHashTable(Tcl_HashTable *tablePtr, /* Pointer to table record, which + * is supplied by the caller. */ + int keyType) /* Type of keys to use in table: + * TCL_STRING_KEYS, TCL_ONE_WORD_KEYS, + * or an integer >= 2. */ +{ + tablePtr->buckets = tablePtr->staticBuckets; + tablePtr->staticBuckets[0] = tablePtr->staticBuckets[1] = 0; + tablePtr->staticBuckets[2] = tablePtr->staticBuckets[3] = 0; + tablePtr->numBuckets = TCL_SMALL_HASH_TABLE; + tablePtr->numEntries = 0; + tablePtr->rebuildSize = TCL_SMALL_HASH_TABLE*REBUILD_MULTIPLIER; + tablePtr->downShift = 28; + tablePtr->mask = 3; + tablePtr->keyType = keyType; + if (keyType == TCL_STRING_KEYS) { + tablePtr->findProc = StringFind; + tablePtr->createProc = StringCreate; + } else if (keyType == TCL_ONE_WORD_KEYS) { + tablePtr->findProc = OneWordFind; + tablePtr->createProc = OneWordCreate; + } else { + tablePtr->findProc = ArrayFind; + tablePtr->createProc = ArrayCreate; + }; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_DeleteHashEntry -- + * + * Remove a single entry from a hash table. + * + * Results: + * None. + * + * Side effects: + * The entry given by entryPtr is deleted from its table and + * should never again be used by the caller. It is up to the + * caller to free the clientData field of the entry, if that + * is relevant. + * + *---------------------------------------------------------------------- + */ + +void +Tcl_DeleteHashEntry(entryPtr) + Tcl_HashEntry *entryPtr; +{ + register Tcl_HashEntry *prevPtr; + + if (*entryPtr->bucketPtr == entryPtr) { + *entryPtr->bucketPtr = entryPtr->nextPtr; + } else { + for (prevPtr = *entryPtr->bucketPtr; ; prevPtr = prevPtr->nextPtr) { + assert (prevPtr != 0); + if (prevPtr->nextPtr == entryPtr) { + prevPtr->nextPtr = entryPtr->nextPtr; + break; + } + } + } + entryPtr->tablePtr->numEntries--; + free (entryPtr); +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_DeleteHashTable -- + * + * Free up everything associated with a hash table except for + * the record for the table itself. + * + * Results: + * None. + * + * Side effects: + * The hash table is no longer useable. + * + *---------------------------------------------------------------------- + */ + +void +Tcl_DeleteHashTable(tablePtr) + register Tcl_HashTable *tablePtr; /* Table to delete. */ +{ + register Tcl_HashEntry *hPtr, *nextPtr; + int i; + + /* + * Free up all the entries in the table. + */ + for (i = 0; i < tablePtr->numBuckets; i++) { + hPtr = tablePtr->buckets[i]; + while (hPtr != 0) { + nextPtr = hPtr->nextPtr; + free (hPtr); + hPtr = nextPtr; + } + } + + /* + * Free up the bucket array, if it was dynamically allocated. + */ + if (tablePtr->buckets != tablePtr->staticBuckets) { + free (tablePtr->buckets); + } + + /* + * Arrange for panics if the table is used again without + * re-initialization. + */ + tablePtr->findProc = BogusFind; + tablePtr->createProc = BogusCreate; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_FirstHashEntry -- + * + * Locate the first entry in a hash table and set up a record + * that can be used to step through all the remaining entries + * of the table. + * + * Results: + * The return value is a pointer to the first entry in tablePtr, + * or NULL if tablePtr has no entries in it. The memory at + * *searchPtr is initialized so that subsequent calls to + * Tcl_NextHashEntry will return all of the entries in the table, + * one at a time. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +Tcl_HashEntry * +Tcl_FirstHashEntry(tablePtr, searchPtr) + Tcl_HashTable *tablePtr; /* Table to search. */ + Tcl_HashSearch *searchPtr; /* Place to store information about + * progress through the table. */ +{ + searchPtr->tablePtr = tablePtr; + searchPtr->nextIndex = 0; + searchPtr->nextEntryPtr = 0; + return Tcl_NextHashEntry(searchPtr); +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_NextHashEntry -- + * + * Once a hash table enumeration has been initiated by calling + * Tcl_FirstHashEntry, this procedure may be called to return + * successive elements of the table. + * + * Results: + * The return value is the next entry in the hash table being + * enumerated, or NULL if the end of the table is reached. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +Tcl_HashEntry * +Tcl_NextHashEntry(searchPtr) + register Tcl_HashSearch *searchPtr; /* Place to store information about + * progress through the table. Must + * have been initialized by calling + * Tcl_FirstHashEntry. */ +{ + Tcl_HashEntry *hPtr; + + while (searchPtr->nextEntryPtr == 0) { + if (searchPtr->nextIndex >= searchPtr->tablePtr->numBuckets) { + return 0; + } + searchPtr->nextEntryPtr = + searchPtr->tablePtr->buckets[searchPtr->nextIndex]; + searchPtr->nextIndex++; + } + hPtr = searchPtr->nextEntryPtr; + searchPtr->nextEntryPtr = hPtr->nextPtr; + return hPtr; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_HashStats -- + * + * Return statistics describing the layout of the hash table + * in its hash buckets. + * + * Results: + * The return value is a malloc-ed string containing information + * about tablePtr. It is the caller's responsibility to free + * this string. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +unsigned char * +Tcl_HashStats (Tcl_HashTable *tablePtr) /* Table for which to produce stats. */ +{ +#define NUM_COUNTERS 10 + int count[NUM_COUNTERS], overflow, i, j, size; +/* double average, tmp;*/ + register Tcl_HashEntry *hPtr; + unsigned char *result, *p; + + /* + * Compute a histogram of bucket usage. + */ + + memset (count, 0, sizeof (count)); + overflow = 0; +/* average = 0.0;*/ + for (i = 0; i < tablePtr->numBuckets; i++) { + j = 0; + for (hPtr = tablePtr->buckets[i]; hPtr != 0; hPtr = hPtr->nextPtr) { + j++; + } + if (j < NUM_COUNTERS) { + count[j]++; + } else { + overflow++; + } +/* tmp = j;*/ +/* average += (tmp+1.0)*(tmp/tablePtr->numEntries)/2.0;*/ + } + + /* + * Print out the histogram and a few other pieces of information. + */ + size = NUM_COUNTERS*60 + 300; + result = malloc (size); + sprintf(result, "%d entries in table, %d buckets\n", + tablePtr->numEntries, tablePtr->numBuckets); + p = result + strlen(result); + for (i = 0; i < NUM_COUNTERS; i++) { + sprintf(p, "number of buckets with %d entries: %d\n", i, count[i]); + p += strlen(p); + } + sprintf(p, "number of buckets with more %d or more entries: %d", + NUM_COUNTERS, overflow); +/* p += strlen(p);*/ +/* sprintf(p, "\naverage search distance for entry: %.1f", average);*/ + return result; +} + +/* + *---------------------------------------------------------------------- + * + * HashString -- + * + * Compute a one-word summary of a text string, which can be + * used to generate a hash index. + * + * Results: + * The return value is a one-word summary of the information in + * string. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static unsigned int +HashString(string) + register unsigned char *string; /* String from which to compute hash value. */ +{ + register unsigned int result; + register int c; + + /* + * I tried a zillion different hash functions and asked many other + * people for advice. Many people had their own favorite functions, + * all different, but no-one had much idea why they were good ones. + * I chose the one below (multiply by 9 and add new character) + * because of the following reasons: + * + * 1. Multiplying by 10 is perfect for keys that are decimal strings, + * and multiplying by 9 is just about as good. + * 2. Times-9 is (shift-left-3) plus (old). This means that each + * character's bits hang around in the low-order bits of the + * hash value for ever, plus they spread fairly rapidly up to + * the high-order bits to fill out the hash value. This seems + * works well both for decimal and non-decimal strings. + */ + + result = 0; + while (1) { + c = *string; + string++; + if (c == 0) { + break; + } + result += (result<<3) + c; + } + return result; +} + +/* + *---------------------------------------------------------------------- + * + * StringFind -- + * + * Given a hash table with string keys, and a string key, find + * the entry with a matching key. + * + * Results: + * The return value is a token for the matching entry in the + * hash table, or NULL if there was no matching entry. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static Tcl_HashEntry * +StringFind(tablePtr, key) + Tcl_HashTable *tablePtr; /* Table in which to lookup entry. */ + unsigned char *key; /* Key to use to find matching entry. */ +{ + register Tcl_HashEntry *hPtr; + register unsigned char *p1, *p2; + int index; + + index = HashString(key) & tablePtr->mask; + + /* + * Search all of the entries in the appropriate bucket. + */ + + for (hPtr = tablePtr->buckets[index]; hPtr != 0; + hPtr = hPtr->nextPtr) { + for (p1 = key, p2 = hPtr->key.string; ; p1++, p2++) { + if (*p1 != *p2) { + break; + } + if (*p1 == '\0') { + return hPtr; + } + } + } + return 0; +} + +/* + *---------------------------------------------------------------------- + * + * StringCreate -- + * + * Given a hash table with string keys, and a string key, find + * the entry with a matching key. If there is no matching entry, + * then create a new entry that does match. + * + * Results: + * The return value is a pointer to the matching entry. If this + * is a newly-created entry, then *newPtr will be set to a non-zero + * value; otherwise *newPtr will be set to 0. If this is a new + * entry the value stored in the entry will initially be 0. + * + * Side effects: + * A new entry may be added to the hash table. + * + *---------------------------------------------------------------------- + */ + +static Tcl_HashEntry * +StringCreate(tablePtr, key, newPtr) + Tcl_HashTable *tablePtr; /* Table in which to lookup entry. */ + unsigned char *key; /* Key to use to find or create matching + * entry. */ + int *newPtr; /* Store info here telling whether a new + * entry was created. */ +{ + register Tcl_HashEntry *hPtr; + register unsigned char *p1, *p2; + int index; + + index = HashString(key) & tablePtr->mask; + + /* + * Search all of the entries in this bucket. + */ + + for (hPtr = tablePtr->buckets[index]; hPtr != 0; + hPtr = hPtr->nextPtr) { + for (p1 = key, p2 = hPtr->key.string; ; p1++, p2++) { + if (*p1 != *p2) { + break; + } + if (*p1 == '\0') { + *newPtr = 0; + return hPtr; + } + } + } + + /* + * Entry not found. Add a new one to the bucket. + */ + + *newPtr = 1; + hPtr = (Tcl_HashEntry*) malloc ((unsigned) + (sizeof(Tcl_HashEntry) + strlen(key) - (sizeof(hPtr->key) -1))); + hPtr->tablePtr = tablePtr; + hPtr->bucketPtr = &(tablePtr->buckets[index]); + hPtr->nextPtr = *hPtr->bucketPtr; + hPtr->clientData = 0; + strcpy(hPtr->key.string, key); + *hPtr->bucketPtr = hPtr; + tablePtr->numEntries++; + + /* + * If the table has exceeded a decent size, rebuild it with many + * more buckets. + */ + + if (tablePtr->numEntries >= tablePtr->rebuildSize) { + RebuildTable(tablePtr); + } + return hPtr; +} + +/* + *---------------------------------------------------------------------- + * + * OneWordFind -- + * + * Given a hash table with one-word keys, and a one-word key, find + * the entry with a matching key. + * + * Results: + * The return value is a token for the matching entry in the + * hash table, or NULL if there was no matching entry. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static Tcl_HashEntry * +OneWordFind(tablePtr, key) + Tcl_HashTable *tablePtr; /* Table in which to lookup entry. */ + register unsigned char *key; /* Key to use to find matching entry. */ +{ + register Tcl_HashEntry *hPtr; + int index; + + index = RANDOM_INDEX(tablePtr, key); + + /* + * Search all of the entries in the appropriate bucket. + */ + + for (hPtr = tablePtr->buckets[index]; hPtr != 0; + hPtr = hPtr->nextPtr) { + if (hPtr->key.oneWordValue == key) { + return hPtr; + } + } + return 0; +} + +/* + *---------------------------------------------------------------------- + * + * OneWordCreate -- + * + * Given a hash table with one-word keys, and a one-word key, find + * the entry with a matching key. If there is no matching entry, + * then create a new entry that does match. + * + * Results: + * The return value is a pointer to the matching entry. If this + * is a newly-created entry, then *newPtr will be set to a non-zero + * value; otherwise *newPtr will be set to 0. If this is a new + * entry the value stored in the entry will initially be 0. + * + * Side effects: + * A new entry may be added to the hash table. + * + *---------------------------------------------------------------------- + */ + +static Tcl_HashEntry * +OneWordCreate(tablePtr, key, newPtr) + Tcl_HashTable *tablePtr; /* Table in which to lookup entry. */ + register unsigned char *key; /* Key to use to find or create matching + * entry. */ + int *newPtr; /* Store info here telling whether a new + * entry was created. */ +{ + register Tcl_HashEntry *hPtr; + int index; + + index = RANDOM_INDEX(tablePtr, key); + + /* + * Search all of the entries in this bucket. + */ + + for (hPtr = tablePtr->buckets[index]; hPtr != 0; + hPtr = hPtr->nextPtr) { + if (hPtr->key.oneWordValue == key) { + *newPtr = 0; + return hPtr; + } + } + + /* + * Entry not found. Add a new one to the bucket. + */ + + *newPtr = 1; + hPtr = (Tcl_HashEntry*) malloc (sizeof(Tcl_HashEntry)); + hPtr->tablePtr = tablePtr; + hPtr->bucketPtr = &(tablePtr->buckets[index]); + hPtr->nextPtr = *hPtr->bucketPtr; + hPtr->clientData = 0; + hPtr->key.oneWordValue = key; + *hPtr->bucketPtr = hPtr; + tablePtr->numEntries++; + + /* + * If the table has exceeded a decent size, rebuild it with many + * more buckets. + */ + + if (tablePtr->numEntries >= tablePtr->rebuildSize) { + RebuildTable(tablePtr); + } + return hPtr; +} + +/* + *---------------------------------------------------------------------- + * + * ArrayFind -- + * + * Given a hash table with array-of-int keys, and a key, find + * the entry with a matching key. + * + * Results: + * The return value is a token for the matching entry in the + * hash table, or NULL if there was no matching entry. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static Tcl_HashEntry * +ArrayFind(tablePtr, key) + Tcl_HashTable *tablePtr; /* Table in which to lookup entry. */ + unsigned char *key; /* Key to use to find matching entry. */ +{ + register Tcl_HashEntry *hPtr; + int *arrayPtr = (int *) key; + register int *iPtr1, *iPtr2; + int index, count; + + for (index = 0, count = tablePtr->keyType, iPtr1 = arrayPtr; + count > 0; count--, iPtr1++) { + index += *iPtr1; + } + index = RANDOM_INDEX(tablePtr, index); + + /* + * Search all of the entries in the appropriate bucket. + */ + + for (hPtr = tablePtr->buckets[index]; hPtr != 0; + hPtr = hPtr->nextPtr) { + for (iPtr1 = arrayPtr, iPtr2 = hPtr->key.words, + count = tablePtr->keyType; ; count--, iPtr1++, iPtr2++) { + if (count == 0) { + return hPtr; + } + if (*iPtr1 != *iPtr2) { + break; + } + } + } + return 0; +} + +/* + *---------------------------------------------------------------------- + * + * ArrayCreate -- + * + * Given a hash table with one-word keys, and a one-word key, find + * the entry with a matching key. If there is no matching entry, + * then create a new entry that does match. + * + * Results: + * The return value is a pointer to the matching entry. If this + * is a newly-created entry, then *newPtr will be set to a non-zero + * value; otherwise *newPtr will be set to 0. If this is a new + * entry the value stored in the entry will initially be 0. + * + * Side effects: + * A new entry may be added to the hash table. + * + *---------------------------------------------------------------------- + */ + +static Tcl_HashEntry * +ArrayCreate(tablePtr, key, newPtr) + Tcl_HashTable *tablePtr; /* Table in which to lookup entry. */ + register unsigned char *key; /* Key to use to find or create matching + * entry. */ + int *newPtr; /* Store info here telling whether a new + * entry was created. */ +{ + register Tcl_HashEntry *hPtr; + int *arrayPtr = (int *) key; + register int *iPtr1, *iPtr2; + int index, count; + + for (index = 0, count = tablePtr->keyType, iPtr1 = arrayPtr; + count > 0; count--, iPtr1++) { + index += *iPtr1; + } + index = RANDOM_INDEX(tablePtr, index); + + /* + * Search all of the entries in the appropriate bucket. + */ + + for (hPtr = tablePtr->buckets[index]; hPtr != 0; + hPtr = hPtr->nextPtr) { + for (iPtr1 = arrayPtr, iPtr2 = hPtr->key.words, + count = tablePtr->keyType; ; count--, iPtr1++, iPtr2++) { + if (count == 0) { + *newPtr = 0; + return hPtr; + } + if (*iPtr1 != *iPtr2) { + break; + } + } + } + + /* + * Entry not found. Add a new one to the bucket. + */ + + *newPtr = 1; + hPtr = (Tcl_HashEntry*) malloc ((unsigned) + (sizeof(Tcl_HashEntry) + (tablePtr->keyType*sizeof(int)) - 4)); + hPtr->tablePtr = tablePtr; + hPtr->bucketPtr = &(tablePtr->buckets[index]); + hPtr->nextPtr = *hPtr->bucketPtr; + hPtr->clientData = 0; + for (iPtr1 = arrayPtr, iPtr2 = hPtr->key.words, count = tablePtr->keyType; + count > 0; count--, iPtr1++, iPtr2++) { + *iPtr2 = *iPtr1; + } + *hPtr->bucketPtr = hPtr; + tablePtr->numEntries++; + + /* + * If the table has exceeded a decent size, rebuild it with many + * more buckets. + */ + + if (tablePtr->numEntries >= tablePtr->rebuildSize) { + RebuildTable(tablePtr); + } + return hPtr; +} + +/* + *---------------------------------------------------------------------- + * + * BogusFind -- + * + * This procedure is invoked when an Tcl_FindHashEntry is called + * on a table that has been deleted. + * + * Results: + * If panic returns (which it shouldn't) this procedure returns + * NULL. + * + * Side effects: + * Generates a panic. + * + *---------------------------------------------------------------------- + */ + + /* ARGSUSED */ +static Tcl_HashEntry * +BogusFind(tablePtr, key) + Tcl_HashTable *tablePtr; /* Table in which to lookup entry. */ + unsigned char *key; /* Key to use to find matching entry. */ +{ + assert (0); + return 0; +} + +/* + *---------------------------------------------------------------------- + * + * BogusCreate -- + * + * This procedure is invoked when an Tcl_CreateHashEntry is called + * on a table that has been deleted. + * + * Results: + * If panic returns (which it shouldn't) this procedure returns + * NULL. + * + * Side effects: + * Generates a panic. + * + *---------------------------------------------------------------------- + */ + + /* ARGSUSED */ +static Tcl_HashEntry * +BogusCreate(tablePtr, key, newPtr) + Tcl_HashTable *tablePtr; /* Table in which to lookup entry. */ + unsigned char *key; /* Key to use to find or create matching + * entry. */ + int *newPtr; /* Store info here telling whether a new + * entry was created. */ +{ + assert (0); + return 0; +} + +/* + *---------------------------------------------------------------------- + * + * RebuildTable -- + * + * This procedure is invoked when the ratio of entries to hash + * buckets becomes too large. It creates a new table with a + * larger bucket array and moves all of the entries into the + * new table. + * + * Results: + * None. + * + * Side effects: + * Memory gets reallocated and entries get re-hashed to new + * buckets. + * + *---------------------------------------------------------------------- + */ + +static void +RebuildTable(tablePtr) + register Tcl_HashTable *tablePtr; /* Table to enlarge. */ +{ + int oldSize, count, index; + Tcl_HashEntry **oldBuckets; + register Tcl_HashEntry **oldChainPtr, **newChainPtr; + register Tcl_HashEntry *hPtr; + + oldSize = tablePtr->numBuckets; + oldBuckets = tablePtr->buckets; + + /* + * Allocate and initialize the new bucket array, and set up + * hashing constants for new array size. + */ + + tablePtr->numBuckets *= 4; + tablePtr->buckets = (Tcl_HashEntry**) malloc ((unsigned) + (tablePtr->numBuckets * sizeof(Tcl_HashEntry *))); + for (count = tablePtr->numBuckets, newChainPtr = tablePtr->buckets; + count > 0; count--, newChainPtr++) { + *newChainPtr = 0; + } + tablePtr->rebuildSize *= 4; + tablePtr->downShift -= 2; + tablePtr->mask = (tablePtr->mask << 2) + 3; + + /* + * Rehash all of the existing entries into the new bucket array. + */ + + for (oldChainPtr = oldBuckets; oldSize > 0; oldSize--, oldChainPtr++) { + for (hPtr = *oldChainPtr; hPtr != 0; hPtr = *oldChainPtr) { + *oldChainPtr = hPtr->nextPtr; + if (tablePtr->keyType == TCL_STRING_KEYS) { + index = HashString(hPtr->key.string) & tablePtr->mask; + } else if (tablePtr->keyType == TCL_ONE_WORD_KEYS) { + index = RANDOM_INDEX(tablePtr, hPtr->key.oneWordValue); + } else { + register int *iPtr; + int count; + + for (index = 0, count = tablePtr->keyType, + iPtr = hPtr->key.words; count > 0; count--, iPtr++) { + index += *iPtr; + } + index = RANDOM_INDEX(tablePtr, index); + } + hPtr->bucketPtr = &(tablePtr->buckets[index]); + hPtr->nextPtr = *hPtr->bucketPtr; + *hPtr->bucketPtr = hPtr; + } + } + + /* + * Free up the old bucket array, if it was dynamically allocated. + */ + + if (oldBuckets != tablePtr->staticBuckets) { + free (oldBuckets); + } +} diff --git a/src/libtcl/tclparse.c b/src/libtcl/tclparse.c new file mode 100644 index 0000000..2324b37 --- /dev/null +++ b/src/libtcl/tclparse.c @@ -0,0 +1,1212 @@ +/* + * tclParse.c -- + * + * This file contains a collection of procedures that are used + * to parse Tcl commands or parts of commands (like quoted + * strings or nested sub-commands). + * + * Copyright 1991 Regents of the University of California. + * 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. The University of California + * makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without + * express or implied warranty. + */ +#include "internal.h" + +/* + * A table used to classify input characters to assist in parsing + * Tcl commands. The table should be indexed with a signed character + * using the CHAR_TYPE macro. The character may have a negative + * value. + */ +#define CHAR_TYPE(c) tclTypeTable [(unsigned char)(c)] + +/* + * The following table assigns a type to each character. Only types + * meaningful to Tcl parsing are represented here. The table indexes + * all 256 characters, with the negative ones first, then the positive + * ones. + */ +static const char tclTypeTable[] = { +/*0*/ + TCL_COMMAND_END, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_SPACE, TCL_COMMAND_END, TCL_SPACE, + TCL_SPACE, TCL_SPACE, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, +/*32*/ + TCL_SPACE, TCL_NORMAL, TCL_QUOTE, TCL_NORMAL, + TCL_DOLLAR, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_COMMAND_END, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, +/*64*/ + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_OPEN_BRACKET, + TCL_BACKSLASH, TCL_COMMAND_END, TCL_NORMAL, TCL_NORMAL, +/*96*/ + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_OPEN_BRACE, + TCL_NORMAL, TCL_CLOSE_BRACE, TCL_NORMAL, TCL_NORMAL, +/*-128*/ + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, +/*-96*/ + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, +/*-64*/ + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, +/*-32*/ + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, + TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, +}; + +/* + * Function prototypes for procedures local to this file: + */ + +static unsigned char * QuoteEnd (unsigned char *string, int term); +static unsigned char * VarNameEnd (unsigned char *string); + +/* + *---------------------------------------------------------------------- + * + * Tcl_Backslash -- + * + * Figure out how to handle a backslash sequence. + * + * Results: + * The return value is the character that should be substituted + * in place of the backslash sequence that starts at src, or 0 + * if the backslash sequence should be replace by nothing (e.g. + * backslash followed by newline). If readPtr isn't NULL then + * it is filled in with a count of the number of characters in + * the backslash sequence. Note: if the backslash isn't followed + * by characters that are understood here, then the backslash + * sequence is only considered to be one character long, and it + * is replaced by a backslash char. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +char +Tcl_Backslash(src, readPtr) + unsigned char *src; /* Points to the backslash character of + * a backslash sequence. */ + int *readPtr; /* Fill in with number of characters read + * from src, unless NULL. */ +{ + register unsigned char *p = src+1; + char result; + int count; + + count = 2; + + switch (*p) { + case 'b': + result = '\b'; + break; + case 'e': + result = 033; + break; + case 'f': + result = '\f'; + break; + case 'n': + result = '\n'; + break; + case 'r': + result = '\r'; + break; + case 't': + result = '\t'; + break; + case 'v': + result = '\v'; + break; + case 'C': + p++; + if (isspace(*p) || (*p == 0)) { + result = 'C'; + count = 1; + break; + } + count = 3; + if (*p == 'M') { + p++; + if (isspace(*p) || (*p == 0)) { + result = 'M' & 037; + break; + } + count = 4; + result = (*p & 037) | '\200'; + break; + } + count = 3; + result = *p & 037; + break; + case 'M': + p++; + if (isspace(*p) || (*p == 0)) { + result = 'M'; + count = 1; + break; + } + count = 3; + result = *p + '\200'; + break; + case '}': + case '{': + case ']': + case '[': + case '$': + case ' ': + case ';': + case '"': + case '\\': + result = *p; + break; + case '\n': + result = 0; + break; + default: + if (isdigit(*p)) { + result = *p - '0'; + p++; + if (!isdigit(*p)) { + break; + } + count = 3; + result = (result << 3) + (*p - '0'); + p++; + if (!isdigit(*p)) { + break; + } + count = 4; + result = (result << 3) + (*p - '0'); + break; + } + result = '\\'; + count = 1; + break; + } + + if (readPtr != 0) { + *readPtr = count; + } + return result; +} + +/* + *-------------------------------------------------------------- + * + * TclParseQuotes -- + * + * This procedure parses a double-quoted string such as a + * quoted Tcl command argument or a quoted value in a Tcl + * expression. This procedure is also used to parse array + * element names within parentheses, or anything else that + * needs all the substitutions that happen in quotes. + * + * Results: + * The return value is a standard Tcl result, which is + * TCL_OK unless there was an error while parsing the + * quoted string. If an error occurs then interp->result + * contains a standard error message. *TermPtr is filled + * in with the address of the character just after the + * last one successfully processed; this is usually the + * character just after the matching close-quote. The + * fully-substituted contents of the quotes are stored in + * standard fashion in *pvPtr, null-terminated with + * pvPtr->next pointing to the terminating null character. + * + * Side effects: + * The buffer space in pvPtr may be enlarged by calling its + * expandProc. + * + *-------------------------------------------------------------- + */ + +int +TclParseQuotes(interp, string, termChar, flags, termPtr, pvPtr) + Tcl_Interp *interp; /* Interpreter to use for nested command + * evaluations and error messages. */ + unsigned char *string; /* Character just after opening double- + * quote. */ + int termChar; /* Character that terminates "quoted" string + * (usually double-quote, but sometimes + * right-paren or something else). */ + int flags; /* Flags to pass to nested Tcl_Eval calls. */ + unsigned char **termPtr; /* Store address of terminating character + * here. */ + ParseValue *pvPtr; /* Information about where to place + * fully-substituted result of parse. */ +{ + register unsigned char *src, *dst, c; + + src = string; + dst = pvPtr->next; + + while (1) { + if (dst == pvPtr->end) { + /* + * Target buffer space is about to run out. Make more space. + */ + + pvPtr->next = dst; + (*pvPtr->expandProc) (pvPtr, 1); + dst = pvPtr->next; + } + + c = *src; + src++; + if (c == termChar) { + *dst = '\0'; + pvPtr->next = dst; + *termPtr = src; + return TCL_OK; + } else if (CHAR_TYPE(c) == TCL_NORMAL) { + copy: + *dst = c; + dst++; + continue; + } else if (c == '$') { + int length; + unsigned char *value; + + value = Tcl_ParseVar(interp, src-1, termPtr); + if (value == 0) { + return TCL_ERROR; + } + src = *termPtr; + length = strlen(value); + if ((pvPtr->end - dst) <= length) { + pvPtr->next = dst; + (*pvPtr->expandProc) (pvPtr, length); + dst = pvPtr->next; + } + strcpy(dst, value); + dst += length; + continue; + } else if (c == '[') { + int result; + + pvPtr->next = dst; + result = TclParseNestedCmd(interp, src, flags, termPtr, pvPtr); + if (result != TCL_OK) { + return result; + } + src = *termPtr; + dst = pvPtr->next; + continue; + } else if (c == '\\') { + int numRead; + + src--; + *dst = Tcl_Backslash(src, &numRead); + if (*dst != 0) { + dst++; + } + src += numRead; + continue; + } else if (c == '\0') { + Tcl_ResetResult(interp); + sprintf(interp->result, "missing %c", termChar); + *termPtr = string-1; + return TCL_ERROR; + } else { + goto copy; + } + } +} + +/* + *-------------------------------------------------------------- + * + * TclParseNestedCmd -- + * + * This procedure parses a nested Tcl command between + * brackets, returning the result of the command. + * + * Results: + * The return value is a standard Tcl result, which is + * TCL_OK unless there was an error while executing the + * nested command. If an error occurs then interp->result + * contains a standard error message. *TermPtr is filled + * in with the address of the character just after the + * last one processed; this is usually the character just + * after the matching close-bracket, or the null character + * at the end of the string if the close-bracket was missing + * (a missing close bracket is an error). The result returned + * by the command is stored in standard fashion in *pvPtr, + * null-terminated, with pvPtr->next pointing to the null + * character. + * + * Side effects: + * The storage space at *pvPtr may be expanded. + * + *-------------------------------------------------------------- + */ + +int +TclParseNestedCmd(interp, string, flags, termPtr, pvPtr) + Tcl_Interp *interp; /* Interpreter to use for nested command + * evaluations and error messages. */ + unsigned char *string; /* Character just after opening bracket. */ + int flags; /* Flags to pass to nested Tcl_Eval. */ + unsigned char **termPtr; /* Store address of terminating character + * here. */ + register ParseValue *pvPtr; /* Information about where to place + * result of command. */ +{ + int result, length, shortfall; + Interp *iPtr = (Interp *) interp; + + result = Tcl_Eval(interp, string, flags | TCL_BRACKET_TERM, termPtr); + if (result != TCL_OK) { + /* + * The increment below results in slightly cleaner message in + * the errorInfo variable (the close-bracket will appear). + */ + + if (**termPtr == ']') { + *termPtr += 1; + } + return result; + } + (*termPtr) += 1; + length = strlen(iPtr->result); + shortfall = length + 1 - (pvPtr->end - pvPtr->next); + if (shortfall > 0) { + (*pvPtr->expandProc) (pvPtr, shortfall); + } + strcpy(pvPtr->next, iPtr->result); + pvPtr->next += length; + Tcl_FreeResult ((Tcl_Interp*) iPtr); + iPtr->result = iPtr->resultSpace; + iPtr->resultSpace[0] = '\0'; + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * + * TclParseBraces -- + * + * This procedure scans the information between matching + * curly braces. + * + * Results: + * The return value is a standard Tcl result, which is + * TCL_OK unless there was an error while parsing string. + * If an error occurs then interp->result contains a + * standard error message. *TermPtr is filled + * in with the address of the character just after the + * last one successfully processed; this is usually the + * character just after the matching close-brace. The + * information between curly braces is stored in standard + * fashion in *pvPtr, null-terminated with pvPtr->next + * pointing to the terminating null character. + * + * Side effects: + * The storage space at *pvPtr may be expanded. + * + *-------------------------------------------------------------- + */ + +int +TclParseBraces(interp, string, termPtr, pvPtr) + Tcl_Interp *interp; /* Interpreter to use for nested command + * evaluations and error messages. */ + unsigned char *string; /* Character just after opening bracket. */ + unsigned char **termPtr; /* Store address of terminating character + * here. */ + register ParseValue *pvPtr; /* Information about where to place + * result of command. */ +{ + int level; + register unsigned char *src, *dst, *end; + register char c; + + src = string; + dst = pvPtr->next; + end = pvPtr->end; + level = 1; + + /* + * Copy the characters one at a time to the result area, stopping + * when the matching close-brace is found. + */ + + while (1) { + c = *src; + src++; + if (dst == end) { + pvPtr->next = dst; + (*pvPtr->expandProc) (pvPtr, 20); + dst = pvPtr->next; + end = pvPtr->end; + } + *dst = c; + dst++; + if (CHAR_TYPE(c) == TCL_NORMAL) { + continue; + } else if (c == '{') { + level++; + } else if (c == '}') { + level--; + if (level == 0) { + dst--; /* Don't copy the last close brace. */ + break; + } + } else if (c == '\\') { + int count; + + /* + * Must always squish out backslash-newlines, even when in + * braces. This is needed so that this sequence can appear + * anywhere in a command, such as the middle of an expression. + */ + + if (*src == '\n') { + dst--; + src++; + } else { + (void) Tcl_Backslash(src-1, &count); + while (count > 1) { + if (dst == end) { + pvPtr->next = dst; + (*pvPtr->expandProc) (pvPtr, 20); + dst = pvPtr->next; + end = pvPtr->end; + } + *dst = *src; + dst++; + src++; + count--; + } + } + } else if (c == '\0') { + Tcl_SetResult(interp, (unsigned char*) "missing close-brace", TCL_STATIC); + *termPtr = string-1; + return TCL_ERROR; + } + } + + *dst = '\0'; + pvPtr->next = dst; + *termPtr = src; + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * + * TclParseWords -- + * + * This procedure parses one or more words from a command + * string and creates argv-style pointers to fully-substituted + * copies of those words. + * + * Results: + * The return value is a standard Tcl result. + * + * *argcPtr is modified to hold a count of the number of words + * successfully parsed, which may be 0. At most maxWords words + * will be parsed. If 0 <= *argcPtr < maxWords then it + * means that a command separator was seen. If *argcPtr + * is maxWords then it means that a command separator was + * not seen yet. + * + * *TermPtr is filled in with the address of the character + * just after the last one successfully processed in the + * last word. This is either the command terminator (if + * *argcPtr < maxWords), the character just after the last + * one in a word (if *argcPtr is maxWords), or the vicinity + * of an error (if the result is not TCL_OK). + * + * The pointers at *argv are filled in with pointers to the + * fully-substituted words, and the actual contents of the + * words are copied to the buffer at pvPtr. + * + * If an error occurrs then an error message is left in + * interp->result and the information at *argv, *argcPtr, + * and *pvPtr may be incomplete. + * + * Side effects: + * The buffer space in pvPtr may be enlarged by calling its + * expandProc. + * + *-------------------------------------------------------------- + */ + +int +TclParseWords(interp, string, flags, maxWords, termPtr, argcPtr, argv, pvPtr) + Tcl_Interp *interp; /* Interpreter to use for nested command + * evaluations and error messages. */ + unsigned char *string; /* First character of word. */ + int flags; /* Flags to control parsing (same values as + * passed to Tcl_Eval). */ + int maxWords; /* Maximum number of words to parse. */ + unsigned char **termPtr; /* Store address of terminating character + * here. */ + int *argcPtr; /* Filled in with actual number of words + * parsed. */ + unsigned char **argv; /* Store addresses of individual words here. */ + register ParseValue *pvPtr; /* Information about where to place + * fully-substituted word. */ +{ + register unsigned char *src, *dst; + register char c; + int type, result, argc; + unsigned char *oldBuffer; /* Used to detect when pvPtr's buffer gets + * reallocated, so we can adjust all of the + * argv pointers. */ + + src = string; + oldBuffer = pvPtr->buffer; + dst = pvPtr->next; + for (argc = 0; argc < maxWords; argc++) { + argv[argc] = dst; + + /* + * Skip leading space. + */ + + skipSpace: + c = *src; + type = CHAR_TYPE(c); + while (type == TCL_SPACE) { + src++; + c = *src; + type = CHAR_TYPE(c); + } + + /* + * Handle the normal case (i.e. no leading double-quote or brace). + */ + + if (type == TCL_NORMAL) { + normalArg: + while (1) { + if (dst == pvPtr->end) { + /* + * Target buffer space is about to run out. Make + * more space. + */ + + pvPtr->next = dst; + (*pvPtr->expandProc) (pvPtr, 1); + dst = pvPtr->next; + } + + if (type == TCL_NORMAL) { + copy: + *dst = c; + dst++; + src++; + } else if (type == TCL_SPACE) { + goto wordEnd; + } else if (type == TCL_DOLLAR) { + int length; + unsigned char *value; + + value = Tcl_ParseVar(interp, src, termPtr); + if (value == 0) { + return TCL_ERROR; + } + src = *termPtr; + length = strlen(value); + if ((pvPtr->end - dst) <= length) { + pvPtr->next = dst; + (*pvPtr->expandProc) (pvPtr, length); + dst = pvPtr->next; + } + strcpy(dst, value); + dst += length; + } else if (type == TCL_COMMAND_END) { + if ((c == ']') && !(flags & TCL_BRACKET_TERM)) { + goto copy; + } + + /* + * End of command; simulate a word-end first, so + * that the end-of-command can be processed as the + * first thing in a new word. + */ + + goto wordEnd; + } else if (type == TCL_OPEN_BRACKET) { + pvPtr->next = dst; + result = TclParseNestedCmd(interp, src+1, flags, termPtr, + pvPtr); + if (result != TCL_OK) { + return result; + } + src = *termPtr; + dst = pvPtr->next; + } else if (type == TCL_BACKSLASH) { + int numRead; + + *dst = Tcl_Backslash(src, &numRead); + if (*dst != 0) { + dst++; + } + src += numRead; + } else { + goto copy; + } + c = *src; + type = CHAR_TYPE(c); + } + } else { + + /* + * Check for the end of the command. + */ + + if (type == TCL_COMMAND_END) { + if (flags & TCL_BRACKET_TERM) { + if (c == '\0') { + Tcl_SetResult(interp, (unsigned char*) "missing close-bracket", + TCL_STATIC); + return TCL_ERROR; + } + } else { + if (c == ']') { + goto normalArg; + } + } + goto done; + } + + /* + * Now handle the special cases: open braces, double-quotes, + * and backslash-newline. + */ + + pvPtr->next = dst; + if (type == TCL_QUOTE) { + result = TclParseQuotes(interp, src+1, '"', flags, + termPtr, pvPtr); + } else if (type == TCL_OPEN_BRACE) { + result = TclParseBraces(interp, src+1, termPtr, pvPtr); + } else if ((type == TCL_BACKSLASH) && (src[1] == '\n')) { + src += 2; + goto skipSpace; + } else { + goto normalArg; + } + if (result != TCL_OK) { + return result; + } + + /* + * Back from quotes or braces; make sure that the terminating + * character was the end of the word. Have to be careful here + * to handle continuation lines (i.e. lines ending in backslash). + */ + + c = **termPtr; + if ((c == '\\') && ((*termPtr)[1] == '\n')) { + c = (*termPtr)[2]; + } + type = CHAR_TYPE(c); + if ((type != TCL_SPACE) && (type != TCL_COMMAND_END)) { + if (*src == '"') { + Tcl_SetResult(interp, (unsigned char*) "extra characters after close-quote", + TCL_STATIC); + } else { + Tcl_SetResult(interp, (unsigned char*) "extra characters after close-brace", + TCL_STATIC); + } + return TCL_ERROR; + } + src = *termPtr; + dst = pvPtr->next; + + } + + /* + * We're at the end of a word, so add a null terminator. Then + * see if the buffer was re-allocated during this word. If so, + * update all of the argv pointers. + */ + + wordEnd: + *dst = '\0'; + dst++; + if (oldBuffer != pvPtr->buffer) { + int i; + + for (i = 0; i <= argc; i++) { + argv[i] = pvPtr->buffer + (argv[i] - oldBuffer); + } + oldBuffer = pvPtr->buffer; + } + } + + done: + pvPtr->next = dst; + *termPtr = src; + *argcPtr = argc; + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * + * TclExpandParseValue -- + * + * This procedure is commonly used as the value of the + * expandProc in a ParseValue. It uses malloc to allocate + * more space for the result of a parse. + * + * Results: + * The buffer space in *pvPtr is reallocated to something + * larger, and if pvPtr->clientData is non-zero the old + * buffer is freed. Information is copied from the old + * buffer to the new one. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +void +TclExpandParseValue (ParseValue *pvPtr, /* Information about buffer that + * must be expanded. If the clientData + * in the structure is non-zero, it + * means that the current buffer is + * dynamically allocated. */ + unsigned short needed) /* Minimum amount of additional space + * to allocate. */ +{ + int newSpace; + unsigned char *new; + + /* + * Either double the size of the buffer or add enough new space + * to meet the demand, whichever produces a larger new buffer. + */ + + newSpace = (pvPtr->end - pvPtr->buffer) + 1; + if (newSpace < needed) { + newSpace += needed; + } else { + newSpace += newSpace; + } + new = malloc (newSpace); + + /* + * Copy from old buffer to new, free old buffer if needed, and + * mark new buffer as malloc-ed. + */ + memcpy ((void*) new, (void*) pvPtr->buffer, pvPtr->next - pvPtr->buffer); + pvPtr->next = new + (pvPtr->next - pvPtr->buffer); + if (pvPtr->clientData != 0) { + free(pvPtr->buffer); + } + pvPtr->buffer = new; + pvPtr->end = new + newSpace - 1; + pvPtr->clientData = (void*) 1; +} + +/* + *---------------------------------------------------------------------- + * + * TclWordEnd -- + * + * Given a pointer into a Tcl command, find the end of the next + * word of the command. + * + * Results: + * The return value is a pointer to the last character that's part + * of the word pointed to by "start". If the word doesn't end + * properly within the string then the return value is the address + * of the null character at the end of the string. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +unsigned char * +TclWordEnd(start, nested) + unsigned char *start; /* Beginning of a word of a Tcl command. */ + int nested; /* Zero means this is a top-level command. + * One means this is a nested command (close + * brace is a word terminator). */ +{ + register unsigned char *p; + int count; + + p = start; + while (isspace(*p)) { + p++; + } + + /* + * Handle words beginning with a double-quote or a brace. + */ + + if (*p == '"') { + p = QuoteEnd(p+1, '"'); + if (*p == 0) { + return p; + } + p++; + } else if (*p == '{') { + int braces = 1; + while (braces != 0) { + p++; + while (*p == '\\') { + (void) Tcl_Backslash(p, &count); + p += count; + } + if (*p == '}') { + braces--; + } else if (*p == '{') { + braces++; + } else if (*p == 0) { + return p; + } + } + p++; + } + + /* + * Handle words that don't start with a brace or double-quote. + * This code is also invoked if the word starts with a brace or + * double-quote and there is garbage after the closing brace or + * quote. This is an error as far as Tcl_Eval is concerned, but + * for here the garbage is treated as part of the word. + */ + + while (1) { + if (*p == '[') { + for (p++; *p != ']'; p++) { + p = TclWordEnd(p, 1); + if (*p == 0) { + return p; + } + } + p++; + } else if (*p == '\\') { + (void) Tcl_Backslash(p, &count); + p += count; + if ((*p == 0) && (count == 2) && (p[-1] == '\n')) { + return p; + } + } else if (*p == '$') { + p = VarNameEnd(p); + if (*p == 0) { + return p; + } + p++; + } else if (*p == ';') { + /* + * Include the semi-colon in the word that is returned. + */ + + return p; + } else if (isspace(*p)) { + return p-1; + } else if ((*p == ']') && nested) { + return p-1; + } else if (*p == 0) { + if (nested) { + /* + * Nested commands can't end because of the end of the + * string. + */ + return p; + } + return p-1; + } else { + p++; + } + } +} + +/* + *---------------------------------------------------------------------- + * + * QuoteEnd -- + * + * Given a pointer to a string that obeys the parsing conventions + * for quoted things in Tcl, find the end of that quoted thing. + * The actual thing may be a quoted argument or a parenthesized + * index name. + * + * Results: + * The return value is a pointer to the last character that is + * part of the quoted string (i.e the character that's equal to + * term). If the quoted string doesn't terminate properly then + * the return value is a pointer to the null character at the + * end of the string. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static unsigned char * +QuoteEnd(string, term) + unsigned char *string; /* Pointer to character just after opening + * "quote". */ + int term; /* This character will terminate the + * quoted string (e.g. '"' or ')'). */ +{ + register unsigned char *p = string; + int count; + + while (*p != term) { + if (*p == '\\') { + (void) Tcl_Backslash(p, &count); + p += count; + } else if (*p == '[') { + for (p++; *p != ']'; p++) { + p = TclWordEnd(p, 1); + if (*p == 0) { + return p; + } + } + p++; + } else if (*p == '$') { + p = VarNameEnd(p); + if (*p == 0) { + return p; + } + p++; + } else if (*p == 0) { + return p; + } else { + p++; + } + } + return p-1; +} + +/* + *---------------------------------------------------------------------- + * + * VarNameEnd -- + * + * Given a pointer to a variable reference using $-notation, find + * the end of the variable name spec. + * + * Results: + * The return value is a pointer to the last character that + * is part of the variable name. If the variable name doesn't + * terminate properly then the return value is a pointer to the + * null character at the end of the string. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static unsigned char * +VarNameEnd(string) + unsigned char *string; /* Pointer to dollar-sign character. */ +{ + register unsigned char *p = string+1; + + if (*p == '{') { + for (p++; (*p != '}') && (*p != 0); p++) { + /* Empty loop body. */ + } + return p; + } + while (isalnum(*p) || (*p == '_')) { + p++; + } + if ((*p == '(') && (p != string+1)) { + return QuoteEnd(p+1, ')'); + } + return p-1; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_ParseVar -- + * + * Given a string starting with a $ sign, parse off a variable + * name and return its value. + * + * Results: + * The return value is the contents of the variable given by + * the leading characters of string. If termPtr isn't NULL, + * *termPtr gets filled in with the address of the character + * just after the last one in the variable specifier. If the + * variable doesn't exist, then the return value is NULL and + * an error message will be left in interp->result. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +unsigned char * +Tcl_ParseVar(interp, string, termPtr) + Tcl_Interp *interp; /* Context for looking up variable. */ + register unsigned char *string; /* String containing variable name. + * First character must be "$". */ + unsigned char **termPtr; /* If non-NULL, points to word to fill + * in with character just after last + * one in the variable specifier. */ + +{ + unsigned char *name1, *name1End, c, *result; + register unsigned char *name2; +#define NUM_CHARS 200 + unsigned char copyStorage[NUM_CHARS]; + ParseValue pv; + + /* + * There are three cases: + * 1. The $ sign is followed by an open curly brace. Then the variable + * name is everything up to the next close curly brace, and the + * variable is a scalar variable. + * 2. The $ sign is not followed by an open curly brace. Then the + * variable name is everything up to the next character that isn't + * a letter, digit, or underscore. If the following character is an + * open parenthesis, then the information between parentheses is + * the array element name, which can include any of the substitutions + * permissible between quotes. + * 3. The $ sign is followed by something that isn't a letter, digit, + * or underscore: in this case, there is no variable name, and "$" + * is returned. + */ + + name2 = 0; + string++; + if (*string == '{') { + string++; + name1 = string; + while (*string != '}') { + if (*string == 0) { + Tcl_SetResult(interp, (unsigned char*) "missing close-brace for variable name", + TCL_STATIC); + if (termPtr != 0) { + *termPtr = string; + } + return 0; + } + string++; + } + name1End = string; + string++; + } else { + name1 = string; + while (isalnum(*string) || (*string == '_')) { + string++; + } + if (string == name1) { + if (termPtr != 0) { + *termPtr = string; + } + return (unsigned char*) "$"; + } + name1End = string; + if (*string == '(') { + unsigned char *end; + + /* + * Perform substitutions on the array element name, just as + * is done for quotes. + */ + + pv.buffer = pv.next = copyStorage; + pv.end = copyStorage + NUM_CHARS - 1; + pv.expandProc = TclExpandParseValue; + pv.clientData = (void*) 0; + if (TclParseQuotes(interp, string+1, ')', 0, &end, &pv) + != TCL_OK) { + unsigned char msg[100]; + sprintf(msg, "\n (parsing index for array \"%.*s\")", + (int) (string - name1), name1); + Tcl_AddErrorInfo(interp, msg); + result = 0; + name2 = pv.buffer; + if (termPtr != 0) { + *termPtr = end; + } + goto done; + } + string = end; + name2 = pv.buffer; + } + } + if (termPtr != 0) { + *termPtr = string; + } + + if (((Interp *) interp)->noEval) { + return (unsigned char*) ""; + } + c = *name1End; + *name1End = 0; + result = Tcl_GetVar2(interp, name1, name2, TCL_LEAVE_ERR_MSG); + *name1End = c; + + done: + if ((name2 != 0) && (pv.buffer != copyStorage)) { + free(pv.buffer); + } + return result; +} diff --git a/src/libtcl/tclproc.c b/src/libtcl/tclproc.c new file mode 100644 index 0000000..396f266 --- /dev/null +++ b/src/libtcl/tclproc.c @@ -0,0 +1,575 @@ +/* + * tclProc.c -- + * + * This file contains routines that implement Tcl procedures, + * including the "proc" and "uplevel" commands. + * + * Copyright 1987-1991 Regents of the University of California + * 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. The University of California + * makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without + * express or implied warranty. + */ +#include "internal.h" + +/* + * Forward references to procedures defined later in this file: + */ +static int InterpProc (void *clientData, Tcl_Interp *interp, + int argc, unsigned char **argv); +static void ProcDeleteProc (void *clientData); + +/* + *---------------------------------------------------------------------- + * + * Tcl_ProcCmd -- + * + * This procedure is invoked to process the "proc" Tcl command. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result value. + * + * Side effects: + * A new procedure gets created. + * + *---------------------------------------------------------------------- + */ + + /* ARGSUSED */ +int +Tcl_ProcCmd(dummy, interp, argc, argv) + void *dummy; /* Not used. */ + Tcl_Interp *interp; /* Current interpreter. */ + int argc; /* Number of arguments. */ + unsigned char **argv; /* Argument strings. */ +{ + register Interp *iPtr = (Interp *) interp; + register Proc *procPtr; + int result, argCount, i; + unsigned char **argArray = 0; + Arg *lastArgPtr; + register Arg *argPtr = 0; /* Initialization not needed, but + * prevents compiler warning. */ + + if (argc != 4) { + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " name args body\"", (char *) 0); + return TCL_ERROR; + } + + procPtr = (Proc*) malloc (sizeof(Proc)); + procPtr->iPtr = iPtr; + procPtr->command = malloc (strlen(argv[3]) + 1); + strcpy(procPtr->command, argv[3]); + procPtr->argPtr = 0; + + /* + * Break up the argument list into argument specifiers, then process + * each argument specifier. + */ + + result = Tcl_SplitList(interp, argv[2], &argCount, &argArray); + if (result != TCL_OK) { + goto procError; + } + lastArgPtr = 0; + for (i = 0; i < argCount; i++) { + int fieldCount, nameLength, valueLength; + unsigned char **fieldValues; + + /* + * Now divide the specifier up into name and default. + */ + + result = Tcl_SplitList(interp, argArray[i], &fieldCount, + &fieldValues); + if (result != TCL_OK) { + goto procError; + } + if (fieldCount > 2) { + free((char *) fieldValues); + Tcl_AppendResult(interp, + "too many fields in argument specifier \"", + argArray[i], "\"", (char *) 0); + result = TCL_ERROR; + goto procError; + } + if ((fieldCount == 0) || (*fieldValues[0] == 0)) { + free((char *) fieldValues); + Tcl_AppendResult(interp, "procedure \"", argv[1], + "\" has argument with no name", (char *) 0); + result = TCL_ERROR; + goto procError; + } + nameLength = strlen(fieldValues[0]) + 1; + if (fieldCount == 2) { + valueLength = strlen(fieldValues[1]) + 1; + } else { + valueLength = 0; + } + argPtr = (Arg*) malloc ((unsigned) (sizeof(Arg) - sizeof(argPtr->name) + + nameLength + valueLength)); + if (lastArgPtr == 0) { + procPtr->argPtr = argPtr; + } else { + lastArgPtr->nextPtr = argPtr; + } + lastArgPtr = argPtr; + argPtr->nextPtr = 0; + strcpy(argPtr->name, fieldValues[0]); + if (fieldCount == 2) { + argPtr->defValue = argPtr->name + nameLength; + strcpy(argPtr->defValue, fieldValues[1]); + } else { + argPtr->defValue = 0; + } + free((char *) fieldValues); + } + + Tcl_CreateCommand(interp, argv[1], InterpProc, (void*) procPtr, + ProcDeleteProc); + free((char *) argArray); + return TCL_OK; + + procError: + free(procPtr->command); + while (procPtr->argPtr != 0) { + argPtr = procPtr->argPtr; + procPtr->argPtr = argPtr->nextPtr; + free((char *) argPtr); + } + free((char *) procPtr); + if (argArray != 0) { + free((char *) argArray); + } + return result; +} + +/* + *---------------------------------------------------------------------- + * + * TclGetFrame -- + * + * Given a description of a procedure frame, such as the first + * argument to an "uplevel" or "upvar" command, locate the + * call frame for the appropriate level of procedure. + * + * Results: + * The return value is -1 if an error occurred in finding the + * frame (in this case an error message is left in interp->result). + * 1 is returned if string was either a number or a number preceded + * by "#" and it specified a valid frame. 0 is returned if string + * isn't one of the two things above (in this case, the lookup + * acts as if string were "1"). The variable pointed to by + * framePtrPtr is filled in with the address of the desired frame + * (unless an error occurs, in which case it isn't modified). + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +TclGetFrame(interp, string, framePtrPtr) + Tcl_Interp *interp; /* Interpreter in which to find frame. */ + unsigned char *string; /* String describing frame. */ + CallFrame **framePtrPtr; /* Store pointer to frame here (or NULL + * if global frame indicated). */ +{ + register Interp *iPtr = (Interp *) interp; + int level, result; + CallFrame *framePtr; + + if (iPtr->varFramePtr == 0) { + iPtr->result = (unsigned char*) "already at top level"; + return -1; + } + + /* + * Parse string to figure out which level number to go to. + */ + + result = 1; + if (*string == '#') { + if (Tcl_GetInt(interp, string+1, &level) != TCL_OK) { + return -1; + } + if (level < 0) { + levelError: + Tcl_AppendResult(interp, "bad level \"", string, "\"", + (char *) 0); + return -1; + } + } else if (isdigit(*string)) { + if (Tcl_GetInt(interp, string, &level) != TCL_OK) { + return -1; + } + level = iPtr->varFramePtr->level - level; + } else { + level = iPtr->varFramePtr->level - 1; + result = 0; + } + + /* + * Figure out which frame to use, and modify the interpreter so + * its variables come from that frame. + */ + + if (level == 0) { + framePtr = 0; + } else { + for (framePtr = iPtr->varFramePtr; framePtr != 0; + framePtr = framePtr->callerVarPtr) { + if (framePtr->level == level) { + break; + } + } + if (framePtr == 0) { + goto levelError; + } + } + *framePtrPtr = framePtr; + return result; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_UplevelCmd -- + * + * This procedure is invoked to process the "uplevel" Tcl command. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result value. + * + * Side effects: + * See the user documentation. + * + *---------------------------------------------------------------------- + */ + + /* ARGSUSED */ +int +Tcl_UplevelCmd(dummy, interp, argc, argv) + void *dummy; /* Not used. */ + Tcl_Interp *interp; /* Current interpreter. */ + int argc; /* Number of arguments. */ + unsigned char **argv; /* Argument strings. */ +{ + register Interp *iPtr = (Interp *) interp; + int result; + CallFrame *savedVarFramePtr, *framePtr; + + if (argc < 2) { + uplevelSyntax: + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " ?level? command ?arg ...?\"", (char *) 0); + return TCL_ERROR; + } + + /* + * Find the level to use for executing the command. + */ + + result = TclGetFrame(interp, argv[1], &framePtr); + if (result == -1) { + return TCL_ERROR; + } + argc -= (result+1); + if (argc == 0) { + goto uplevelSyntax; + } + argv += (result+1); + + /* + * Modify the interpreter state to execute in the given frame. + */ + + savedVarFramePtr = iPtr->varFramePtr; + iPtr->varFramePtr = framePtr; + + /* + * Execute the residual arguments as a command. + */ + + if (argc == 1) { + result = Tcl_Eval(interp, argv[0], 0, 0); + } else { + unsigned char *cmd; + + cmd = Tcl_Concat (argc, argv); + result = Tcl_Eval (interp, cmd, 0, 0); + free(cmd); + } + if (result == TCL_ERROR) { + unsigned char msg[60]; + sprintf(msg, "\n (\"uplevel\" body line %d)", + interp->errorLine); + Tcl_AddErrorInfo(interp, msg); + } + + /* + * Restore the variable frame, and return. + */ + + iPtr->varFramePtr = savedVarFramePtr; + return result; +} + +/* + *---------------------------------------------------------------------- + * + * TclFindProc -- + * + * Given the name of a procedure, return a pointer to the + * record describing the procedure. + * + * Results: + * NULL is returned if the name doesn't correspond to any + * procedure. Otherwise the return value is a pointer to + * the procedure's record. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +Proc * +TclFindProc(iPtr, procName) + Interp *iPtr; /* Interpreter in which to look. */ + unsigned char *procName; /* Name of desired procedure. */ +{ + Tcl_HashEntry *hPtr; + Command *cmdPtr; + + hPtr = Tcl_FindHashEntry(&iPtr->commandTable, procName); + if (hPtr == 0) { + return 0; + } + cmdPtr = (Command *) Tcl_GetHashValue(hPtr); + if (cmdPtr->proc != InterpProc) { + return 0; + } + return (Proc *) cmdPtr->clientData; +} + +/* + *---------------------------------------------------------------------- + * + * TclIsProc -- + * + * Tells whether a command is a Tcl procedure or not. + * + * Results: + * If the given command is actuall a Tcl procedure, the + * return value is the address of the record describing + * the procedure. Otherwise the return value is 0. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +Proc * +TclIsProc(cmdPtr) + Command *cmdPtr; /* Command to test. */ +{ + if (cmdPtr->proc == InterpProc) { + return (Proc *) cmdPtr->clientData; + } + return (Proc *) 0; +} + +/* + *---------------------------------------------------------------------- + * + * InterpProc -- + * + * When a Tcl procedure gets invoked, this routine gets invoked + * to interpret the procedure. + * + * Results: + * A standard Tcl result value, usually TCL_OK. + * + * Side effects: + * Depends on the commands in the procedure. + * + *---------------------------------------------------------------------- + */ + +static int +InterpProc(clientData, interp, argc, argv) + void *clientData; /* Record describing procedure to be + * interpreted. */ + Tcl_Interp *interp; /* Interpreter in which procedure was + * invoked. */ + int argc; /* Count of number of arguments to this + * procedure. */ + unsigned char **argv; /* Argument values. */ +{ + register Proc *procPtr = (Proc *) clientData; + register Arg *argPtr; + register Interp *iPtr = (Interp *) interp; + unsigned char **args; + CallFrame frame; + unsigned char *value, *end; + int result; + + /* + * Set up a call frame for the new procedure invocation. + */ + + iPtr = procPtr->iPtr; + Tcl_InitHashTable (&frame.varTable, TCL_STRING_KEYS); + if (iPtr->varFramePtr != 0) { + frame.level = iPtr->varFramePtr->level + 1; + } else { + frame.level = 1; + } + frame.argc = argc; + frame.argv = argv; + frame.callerPtr = iPtr->framePtr; + frame.callerVarPtr = iPtr->varFramePtr; + iPtr->framePtr = &frame; + iPtr->varFramePtr = &frame; + + /* + * Match the actual arguments against the procedure's formal + * parameters to compute local variables. + */ + + for (argPtr = procPtr->argPtr, args = argv+1, argc -= 1; + argPtr != 0; + argPtr = argPtr->nextPtr, args++, argc--) { + + /* + * Handle the special case of the last formal being "args". When + * it occurs, assign it a list consisting of all the remaining + * actual arguments. + */ + + if ((argPtr->nextPtr == 0) && + (strcmp (argPtr->name, (unsigned char*) "args") == 0)) { + if (argc < 0) { + argc = 0; + } + value = Tcl_Merge (argc, args); + Tcl_SetVar (interp, argPtr->name, value, 0); + free (value); + argc = 0; + break; + } else if (argc > 0) { + value = *args; + } else if (argPtr->defValue != 0) { + value = argPtr->defValue; + } else { + Tcl_AppendResult(interp, "no value given for parameter \"", + argPtr->name, "\" to \"", argv[0], "\"", 0); + result = TCL_ERROR; + goto procDone; + } + Tcl_SetVar(interp, argPtr->name, value, 0); + } + if (argc > 0) { + Tcl_AppendResult(interp, "called \"", argv[0], + "\" with too many arguments", 0); + result = TCL_ERROR; + goto procDone; + } + + /* + * Invoke the commands in the procedure's body. + */ + + result = Tcl_Eval(interp, procPtr->command, 0, &end); + if (result == TCL_RETURN) { + result = TCL_OK; + } else if (result == TCL_ERROR) { + unsigned char msg[100]; + + /* + * Record information telling where the error occurred. + */ + + sprintf(msg, "\n (procedure \"%.50s\" line %d)", argv[0], + iPtr->errorLine); + Tcl_AddErrorInfo(interp, msg); + } else if (result == TCL_BREAK) { + iPtr->result = (unsigned char*) "invoked \"break\" outside of a loop"; + result = TCL_ERROR; + } else if (result == TCL_CONTINUE) { + iPtr->result = (unsigned char*) "invoked \"continue\" outside of a loop"; + result = TCL_ERROR; + } + + /* + * Delete the call frame for this procedure invocation (it's + * important to remove the call frame from the interpreter + * before deleting it, so that traces invoked during the + * deletion don't see the partially-deleted frame). + */ + + procDone: + iPtr->framePtr = frame.callerPtr; + iPtr->varFramePtr = frame.callerVarPtr; + TclDeleteVars(iPtr, &frame.varTable); + return result; +} + +/* + *---------------------------------------------------------------------- + * + * ProcDeleteProc -- + * + * This procedure is invoked just before a command procedure is + * removed from an interpreter. Its job is to release all the + * resources allocated to the procedure. + * + * Results: + * None. + * + * Side effects: + * Memory gets freed. + * + *---------------------------------------------------------------------- + */ + +static void +ProcDeleteProc(clientData) + void *clientData; /* Procedure to be deleted. */ +{ + register Proc *procPtr = (Proc *) clientData; + register Arg *argPtr; + + free (procPtr->command); + for (argPtr = procPtr->argPtr; argPtr != 0; ) { + Arg *nextPtr = argPtr->nextPtr; + + free (argPtr); + argPtr = nextPtr; + } + free (procPtr); +} + +/* + * Free up result of interpreter. + */ +void +Tcl_FreeResult (Tcl_Interp *interp) +{ + if (interp->freeProc != 0) { + if (interp->freeProc == TCL_DYNAMIC) + free (interp->result); + else + (*interp->freeProc) (interp->result); + interp->freeProc = 0; + } +} diff --git a/src/libtcl/tclunxaz.c b/src/libtcl/tclunxaz.c new file mode 100644 index 0000000..125095e --- /dev/null +++ b/src/libtcl/tclunxaz.c @@ -0,0 +1,1719 @@ +/* + * tclUnixAZ.c -- + * + * This file contains the top-level command procedures for + * commands in the Tcl core that require UNIX facilities + * such as files and process execution. Much of the code + * in this file is based on earlier versions contributed + * by Karl Lehenbauer, Mark Diekhans and Peter da Silva. + * + * Copyright 1991 Regents of the University of California + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without + * fee is hereby granted, provided that this copyright + * notice appears in all copies. The University of California + * makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without + * express or implied warranty. + */ +#include "internal.h" +#include +#include +#include +#include +#include +#ifdef CROSS +# include +#else +# include +#endif + +/* + * The variable below caches the name of the current working directory + * in order to avoid repeated calls to getwd. The string is malloc-ed. + * NULL means the cache needs to be refreshed. + */ + +static char *currentDir = NULL; + +/* + * Prototypes for local procedures defined in this file: + */ + +static int CleanupChildren (Tcl_Interp *interp, + int numPids, int *pidPtr, int errorId); +static char * GetFileType (int mode); +static int StoreStatData (Tcl_Interp *interp, + char *varName, struct stat *statPtr); + +/* + *---------------------------------------------------------------------- + * + * Tcl_CdCmd -- + * + * This procedure is invoked to process the "cd" Tcl command. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *---------------------------------------------------------------------- + */ + + /* ARGSUSED */ +int +Tcl_CdCmd(dummy, interp, argc, argv) + void *dummy; /* Not used. */ + Tcl_Interp *interp; /* Current interpreter. */ + int argc; /* Number of arguments. */ + unsigned char **argv; /* Argument strings. */ +{ + char *dirName; + + if (argc > 2) { + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " dirName\"", (char *) NULL); + return TCL_ERROR; + } + + if (argc == 2) { + dirName = argv[1]; + } else { + dirName = "~"; + } + dirName = Tcl_TildeSubst(interp, dirName); + if (dirName == NULL) { + return TCL_ERROR; + } + if (currentDir != NULL) { + free(currentDir); + currentDir = NULL; + } + if (chdir(dirName) != 0) { + Tcl_AppendResult(interp, "couldn't change working directory to \"", + dirName, "\": ", Tcl_UnixError(interp), (char *) NULL); + return TCL_ERROR; + } + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_CloseCmd -- + * + * This procedure is invoked to process the "close" Tcl command. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *---------------------------------------------------------------------- + */ + + /* ARGSUSED */ +int +Tcl_CloseCmd(dummy, interp, argc, argv) + void *dummy; /* Not used. */ + Tcl_Interp *interp; /* Current interpreter. */ + int argc; /* Number of arguments. */ + unsigned char **argv; /* Argument strings. */ +{ + OpenFile *filePtr; + int result = TCL_OK; + + if (argc != 2) { + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " fileId\"", (char *) NULL); + return TCL_ERROR; + } + if (TclGetOpenFile(interp, argv[1], &filePtr) != TCL_OK) { + return TCL_ERROR; + } + ((Interp *) interp)->filePtrArray[(int)fileno(filePtr->f)] = NULL; + + /* + * First close the file (in the case of a process pipeline, there may + * be two files, one for the pipe at each end of the pipeline). + */ + + if (filePtr->f2 != NULL) { + if (fclose(filePtr->f2) == EOF) { + Tcl_AppendResult(interp, "error closing \"", argv[1], + "\": ", Tcl_UnixError(interp), "\n", (char *) NULL); + result = TCL_ERROR; + } + } + if (fclose(filePtr->f) == EOF) { + Tcl_AppendResult(interp, "error closing \"", argv[1], + "\": ", Tcl_UnixError(interp), "\n", (char *) NULL); + result = TCL_ERROR; + } + + /* + * If the file was a connection to a pipeline, clean up everything + * associated with the child processes. + */ + + if (filePtr->numPids > 0) { + if (CleanupChildren(interp, filePtr->numPids, filePtr->pidPtr, + filePtr->errorId) != TCL_OK) { + result = TCL_ERROR; + } + } + + free((char *) filePtr); + return result; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_EofCmd -- + * + * This procedure is invoked to process the "eof" Tcl command. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *---------------------------------------------------------------------- + */ + + /* ARGSUSED */ +int +Tcl_EofCmd(notUsed, interp, argc, argv) + void *notUsed; /* Not used. */ + Tcl_Interp *interp; /* Current interpreter. */ + int argc; /* Number of arguments. */ + unsigned char **argv; /* Argument strings. */ +{ + OpenFile *filePtr; + + if (argc != 2) { + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " fileId\"", (char *) NULL); + return TCL_ERROR; + } + if (TclGetOpenFile(interp, argv[1], &filePtr) != TCL_OK) { + return TCL_ERROR; + } + if (feof(filePtr->f)) { + interp->result = "1"; + } else { + interp->result = "0"; + } + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_ExecCmd -- + * + * This procedure is invoked to process the "exec" Tcl command. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *---------------------------------------------------------------------- + */ + + /* ARGSUSED */ +int +Tcl_ExecCmd(dummy, interp, argc, argv) + void *dummy; /* Not used. */ + Tcl_Interp *interp; /* Current interpreter. */ + int argc; /* Number of arguments. */ + unsigned char **argv; /* Argument strings. */ +{ + int outputId; /* File id for output pipe. -1 + * means command overrode. */ + int errorId; /* File id for temporary file + * containing error output. */ + int *pidPtr; + int numPids, result; + + /* + * See if the command is to be run in background; if so, create + * the command, detach it, and return. + */ + + if ((argv[argc-1][0] == '&') && (argv[argc-1][1] == 0)) { + argc--; + argv[argc] = NULL; + numPids = Tcl_CreatePipeline(interp, argc-1, argv+1, &pidPtr, + (int *) NULL, (int *) NULL, (int *) NULL); + if (numPids < 0) { + return TCL_ERROR; + } + Tcl_DetachPids(numPids, pidPtr); + free((char *) pidPtr); + return TCL_OK; + } + + /* + * Create the command's pipeline. + */ + + numPids = Tcl_CreatePipeline(interp, argc-1, argv+1, &pidPtr, + (int *) NULL, &outputId, &errorId); + if (numPids < 0) { + return TCL_ERROR; + } + + /* + * Read the child's output (if any) and put it into the result. + */ + + result = TCL_OK; + if (outputId != -1) { + while (1) { +# define BUFFER_SIZE 1000 + char buffer[BUFFER_SIZE+1]; + int count; + + count = read(outputId, buffer, BUFFER_SIZE); + + if (count == 0) { + break; + } + if (count < 0) { + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, + "error reading from output pipe: ", + Tcl_UnixError(interp), (char *) NULL); + result = TCL_ERROR; + break; + } + buffer[count] = 0; + Tcl_AppendResult(interp, buffer, (char *) NULL); + } + close(outputId); + } + + if (CleanupChildren(interp, numPids, pidPtr, errorId) != TCL_OK) { + result = TCL_ERROR; + } + return result; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_ExitCmd -- + * + * This procedure is invoked to process the "exit" Tcl command. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *---------------------------------------------------------------------- + */ + + /* ARGSUSED */ +int +Tcl_ExitCmd(dummy, interp, argc, argv) + void *dummy; /* Not used. */ + Tcl_Interp *interp; /* Current interpreter. */ + int argc; /* Number of arguments. */ + unsigned char **argv; /* Argument strings. */ +{ + int value; + + if ((argc != 1) && (argc != 2)) { + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " ?returnCode?\"", (char *) NULL); + return TCL_ERROR; + } + if (argc == 1) { + exit(0); + } + if (Tcl_GetInt(interp, argv[1], &value) != TCL_OK) { + return TCL_ERROR; + } + exit(value); + return TCL_OK; /* Better not ever reach this! */ +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_FileCmd -- + * + * This procedure is invoked to process the "file" Tcl command. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *---------------------------------------------------------------------- + */ + + /* ARGSUSED */ +int +Tcl_FileCmd(dummy, interp, argc, argv) + void *dummy; /* Not used. */ + Tcl_Interp *interp; /* Current interpreter. */ + int argc; /* Number of arguments. */ + unsigned char **argv; /* Argument strings. */ +{ + char *p; + int length, statOp; + int mode = 0; /* Initialized only to prevent + * compiler warning message. */ + struct stat statBuf; + char *fileName, c; + + if (argc < 3) { + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " option name ?arg ...?\"", (char *) NULL); + return TCL_ERROR; + } + c = argv[1][0]; + length = strlen(argv[1]); + + /* + * First handle operations on the file name. + */ + + fileName = Tcl_TildeSubst(interp, argv[2]); + if (fileName == NULL) { + return TCL_ERROR; + } + if ((c == 'd') && (strncmp(argv[1], "dirname", length) == 0)) { + if (argc != 3) { + argv[1] = "dirname"; + not3Args: + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " ", argv[1], " name\"", (char *) NULL); + return TCL_ERROR; + } + p = strrchr(fileName, '/'); + if (p == NULL) { + interp->result = "."; + } else if (p == fileName) { + interp->result = "/"; + } else { + *p = 0; + Tcl_SetResult(interp, fileName, TCL_VOLATILE); + *p = '/'; + } + return TCL_OK; + } else if ((c == 'r') && (strncmp(argv[1], "rootname", length) == 0) + && (length >= 2)) { + char *lastSlash; + + if (argc != 3) { + argv[1] = "rootname"; + goto not3Args; + } + p = strrchr(fileName, '.'); + lastSlash = strrchr(fileName, '/'); + if ((p == NULL) || ((lastSlash != NULL) && (lastSlash > p))) { + Tcl_SetResult(interp, fileName, TCL_VOLATILE); + } else { + *p = 0; + Tcl_SetResult(interp, fileName, TCL_VOLATILE); + *p = '.'; + } + return TCL_OK; + } else if ((c == 'e') && (strncmp(argv[1], "extension", length) == 0) + && (length >= 3)) { + char *lastSlash; + + if (argc != 3) { + argv[1] = "extension"; + goto not3Args; + } + p = strrchr(fileName, '.'); + lastSlash = strrchr(fileName, '/'); + if ((p != NULL) && ((lastSlash == NULL) || (lastSlash < p))) { + Tcl_SetResult(interp, p, TCL_VOLATILE); + } + return TCL_OK; + } else if ((c == 't') && (strncmp(argv[1], "tail", length) == 0) + && (length >= 2)) { + if (argc != 3) { + argv[1] = "tail"; + goto not3Args; + } + p = strrchr(fileName, '/'); + if (p != NULL) { + Tcl_SetResult(interp, p+1, TCL_VOLATILE); + } else { + Tcl_SetResult(interp, fileName, TCL_VOLATILE); + } + return TCL_OK; + } + + /* + * Next, handle operations that can be satisfied with the "access" + * kernel call. + */ + + if (fileName == NULL) { + return TCL_ERROR; + } + if ((c == 'r') && (strncmp(argv[1], "readable", length) == 0) + && (length >= 5)) { + if (argc != 3) { + argv[1] = "readable"; + goto not3Args; + } + mode = R_OK; + checkAccess: + if (access(fileName, mode) == -1) { + interp->result = "0"; + } else { + interp->result = "1"; + } + return TCL_OK; + } else if ((c == 'w') && (strncmp(argv[1], "writable", length) == 0)) { + if (argc != 3) { + argv[1] = "writable"; + goto not3Args; + } + mode = W_OK; + goto checkAccess; + } else if ((c == 'e') && (strncmp(argv[1], "executable", length) == 0) + && (length >= 3)) { + if (argc != 3) { + argv[1] = "executable"; + goto not3Args; + } + mode = X_OK; + goto checkAccess; + } else if ((c == 'e') && (strncmp(argv[1], "exists", length) == 0) + && (length >= 3)) { + if (argc != 3) { + argv[1] = "exists"; + goto not3Args; + } + mode = F_OK; + goto checkAccess; + } + + /* + * Lastly, check stuff that requires the file to be stat-ed. + */ + + if ((c == 'a') && (strncmp(argv[1], "atime", length) == 0)) { + if (argc != 3) { + argv[1] = "atime"; + goto not3Args; + } + if (stat(fileName, &statBuf) == -1) { + goto badStat; + } + sprintf(interp->result, "%ld", statBuf.st_atime); + return TCL_OK; + } else if ((c == 'i') && (strncmp(argv[1], "isdirectory", length) == 0) + && (length >= 3)) { + if (argc != 3) { + argv[1] = "isdirectory"; + goto not3Args; + } + statOp = 2; + } else if ((c == 'i') && (strncmp(argv[1], "isfile", length) == 0) + && (length >= 3)) { + if (argc != 3) { + argv[1] = "isfile"; + goto not3Args; + } + statOp = 1; + } else if ((c == 'l') && (strncmp(argv[1], "lstat", length) == 0)) { + if (argc != 4) { + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " lstat name varName\"", (char *) NULL); + return TCL_ERROR; + } + + if (lstat(fileName, &statBuf) == -1) { + Tcl_AppendResult(interp, "couldn't lstat \"", argv[2], + "\": ", Tcl_UnixError(interp), (char *) NULL); + return TCL_ERROR; + } + return StoreStatData(interp, argv[3], &statBuf); + } else if ((c == 'm') && (strncmp(argv[1], "mtime", length) == 0)) { + if (argc != 3) { + argv[1] = "mtime"; + goto not3Args; + } + if (stat(fileName, &statBuf) == -1) { + goto badStat; + } + sprintf(interp->result, "%ld", statBuf.st_mtime); + return TCL_OK; + } else if ((c == 'o') && (strncmp(argv[1], "owned", length) == 0)) { + if (argc != 3) { + argv[1] = "owned"; + goto not3Args; + } + statOp = 0; +#ifdef S_IFLNK + /* + * This option is only included if symbolic links exist on this system + * (in which case S_IFLNK should be defined). + */ + } else if ((c == 'r') && (strncmp(argv[1], "readlink", length) == 0) + && (length >= 5)) { + char linkValue[MAXPATHLEN+1]; + int linkLength; + + if (argc != 3) { + argv[1] = "readlink"; + goto not3Args; + } + linkLength = readlink(fileName, linkValue, sizeof(linkValue) - 1); + if (linkLength == -1) { + Tcl_AppendResult(interp, "couldn't readlink \"", argv[2], + "\": ", Tcl_UnixError(interp), (char *) NULL); + return TCL_ERROR; + } + linkValue[linkLength] = 0; + Tcl_SetResult(interp, linkValue, TCL_VOLATILE); + return TCL_OK; +#endif + } else if ((c == 's') && (strncmp(argv[1], "size", length) == 0) + && (length >= 2)) { + if (argc != 3) { + argv[1] = "size"; + goto not3Args; + } + if (stat(fileName, &statBuf) == -1) { + goto badStat; + } + sprintf(interp->result, "%ld", statBuf.st_size); + return TCL_OK; + } else if ((c == 's') && (strncmp(argv[1], "stat", length) == 0) + && (length >= 2)) { + if (argc != 4) { + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " stat name varName\"", (char *) NULL); + return TCL_ERROR; + } + + if (stat(fileName, &statBuf) == -1) { + badStat: + Tcl_AppendResult(interp, "couldn't stat \"", argv[2], + "\": ", Tcl_UnixError(interp), (char *) NULL); + return TCL_ERROR; + } + return StoreStatData(interp, argv[3], &statBuf); + } else if ((c == 't') && (strncmp(argv[1], "type", length) == 0) + && (length >= 2)) { + if (argc != 3) { + argv[1] = "type"; + goto not3Args; + } + if (lstat(fileName, &statBuf) == -1) { + goto badStat; + } + interp->result = GetFileType((int) statBuf.st_mode); + return TCL_OK; + } else { + Tcl_AppendResult(interp, "bad option \"", argv[1], + "\": should be atime, dirname, executable, exists, ", + "extension, isdirectory, isfile, lstat, mtime, owned, ", + "readable, ", +#ifdef S_IFLNK + "readlink, ", +#endif + "root, size, stat, tail, type, ", + "or writable", + (char *) NULL); + return TCL_ERROR; + } + if (stat(fileName, &statBuf) == -1) { + interp->result = "0"; + return TCL_OK; + } + switch (statOp) { + case 0: + mode = (geteuid() == statBuf.st_uid); + break; + case 1: + mode = S_ISREG(statBuf.st_mode); + break; + case 2: + mode = S_ISDIR(statBuf.st_mode); + break; + } + if (mode) { + interp->result = "1"; + } else { + interp->result = "0"; + } + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * StoreStatData -- + * + * This is a utility procedure that breaks out the fields of a + * "stat" structure and stores them in textual form into the + * elements of an associative array. + * + * Results: + * Returns a standard Tcl return value. If an error occurs then + * a message is left in interp->result. + * + * Side effects: + * Elements of the associative array given by "varName" are modified. + * + *---------------------------------------------------------------------- + */ + +static int +StoreStatData(interp, varName, statPtr) + Tcl_Interp *interp; /* Interpreter for error reports. */ + char *varName; /* Name of associative array variable + * in which to store stat results. */ + struct stat *statPtr; /* Pointer to buffer containing + * stat data to store in varName. */ +{ + char string[30]; + + sprintf(string, "%d", statPtr->st_dev); + if (Tcl_SetVar2(interp, varName, "dev", string, TCL_LEAVE_ERR_MSG) + == NULL) { + return TCL_ERROR; + } + sprintf(string, "%d", statPtr->st_ino); + if (Tcl_SetVar2(interp, varName, "ino", string, TCL_LEAVE_ERR_MSG) + == NULL) { + return TCL_ERROR; + } + sprintf(string, "%d", statPtr->st_mode); + if (Tcl_SetVar2(interp, varName, "mode", string, TCL_LEAVE_ERR_MSG) + == NULL) { + return TCL_ERROR; + } + sprintf(string, "%d", statPtr->st_nlink); + if (Tcl_SetVar2(interp, varName, "nlink", string, TCL_LEAVE_ERR_MSG) + == NULL) { + return TCL_ERROR; + } + sprintf(string, "%d", statPtr->st_uid); + if (Tcl_SetVar2(interp, varName, "uid", string, TCL_LEAVE_ERR_MSG) + == NULL) { + return TCL_ERROR; + } + sprintf(string, "%d", statPtr->st_gid); + if (Tcl_SetVar2(interp, varName, "gid", string, TCL_LEAVE_ERR_MSG) + == NULL) { + return TCL_ERROR; + } + sprintf(string, "%ld", statPtr->st_size); + if (Tcl_SetVar2(interp, varName, "size", string, TCL_LEAVE_ERR_MSG) + == NULL) { + return TCL_ERROR; + } + sprintf(string, "%ld", statPtr->st_atime); + if (Tcl_SetVar2(interp, varName, "atime", string, TCL_LEAVE_ERR_MSG) + == NULL) { + return TCL_ERROR; + } + sprintf(string, "%ld", statPtr->st_mtime); + if (Tcl_SetVar2(interp, varName, "mtime", string, TCL_LEAVE_ERR_MSG) + == NULL) { + return TCL_ERROR; + } + sprintf(string, "%ld", statPtr->st_ctime); + if (Tcl_SetVar2(interp, varName, "ctime", string, TCL_LEAVE_ERR_MSG) + == NULL) { + return TCL_ERROR; + } + if (Tcl_SetVar2(interp, varName, "type", + GetFileType((int) statPtr->st_mode), TCL_LEAVE_ERR_MSG) == NULL) { + return TCL_ERROR; + } + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * GetFileType -- + * + * Given a mode word, returns a string identifying the type of a + * file. + * + * Results: + * A static text string giving the file type from mode. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static char * +GetFileType(mode) + int mode; +{ + if (S_ISREG(mode)) { + return "file"; + } else if (S_ISDIR(mode)) { + return "directory"; + } else if (S_ISCHR(mode)) { + return "characterSpecial"; + } else if (S_ISBLK(mode)) { + return "blockSpecial"; +#ifdef S_ISFIFO + } else if (S_ISFIFO(mode)) { + return "fifo"; +#endif + } else if (S_ISLNK(mode)) { + return "link"; + } else if (S_ISSOCK(mode)) { + return "socket"; + } + return "unknown"; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_FlushCmd -- + * + * This procedure is invoked to process the "flush" Tcl command. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *---------------------------------------------------------------------- + */ + + /* ARGSUSED */ +int +Tcl_FlushCmd(notUsed, interp, argc, argv) + void *notUsed; /* Not used. */ + Tcl_Interp *interp; /* Current interpreter. */ + int argc; /* Number of arguments. */ + unsigned char **argv; /* Argument strings. */ +{ + OpenFile *filePtr; + FILE *f; + + if (argc != 2) { + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " fileId\"", (char *) NULL); + return TCL_ERROR; + } + if (TclGetOpenFile(interp, argv[1], &filePtr) != TCL_OK) { + return TCL_ERROR; + } + if (!filePtr->writable) { + Tcl_AppendResult(interp, "\"", argv[1], + "\" wasn't opened for writing", (char *) NULL); + return TCL_ERROR; + } + f = filePtr->f2; + if (f == NULL) { + f = filePtr->f; + } + if (fflush(f) == EOF) { + Tcl_AppendResult(interp, "error flushing \"", argv[1], + "\": ", Tcl_UnixError(interp), (char *) NULL); + clearerr(f); + return TCL_ERROR; + } + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_GetsCmd -- + * + * This procedure is invoked to process the "gets" Tcl command. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *---------------------------------------------------------------------- + */ + + /* ARGSUSED */ +int +Tcl_GetsCmd(notUsed, interp, argc, argv) + void *notUsed; /* Not used. */ + Tcl_Interp *interp; /* Current interpreter. */ + int argc; /* Number of arguments. */ + unsigned char **argv; /* Argument strings. */ +{ +# define BUF_SIZE 200 + char buffer[BUF_SIZE+1]; + int totalCount, done, flags; + OpenFile *filePtr; + register FILE *f; + + if ((argc != 2) && (argc != 3)) { + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " fileId ?varName?\"", (char *) NULL); + return TCL_ERROR; + } + if (TclGetOpenFile(interp, argv[1], &filePtr) != TCL_OK) { + return TCL_ERROR; + } + if (!filePtr->readable) { + Tcl_AppendResult(interp, "\"", argv[1], + "\" wasn't opened for reading", (char *) NULL); + return TCL_ERROR; + } + + /* + * We can't predict how large a line will be, so read it in + * pieces, appending to the current result or to a variable. + */ + + totalCount = 0; + done = 0; + flags = 0; + f = filePtr->f; + while (!done) { + register int c, count; + register char *p; + + for (p = buffer, count = 0; count < BUF_SIZE-1; count++, p++) { + c = getc(f); + if (c == EOF) { + if (ferror(filePtr->f)) { + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, "error reading \"", argv[1], + "\": ", Tcl_UnixError(interp), (char *) NULL); + clearerr(filePtr->f); + return TCL_ERROR; + } else if (feof(filePtr->f)) { + if ((totalCount == 0) && (count == 0)) { + totalCount = -1; + } + done = 1; + break; + } + } + if (c == '\n') { + done = 1; + break; + } + *p = c; + } + *p = 0; + if (argc == 2) { + Tcl_AppendResult(interp, buffer, (char *) NULL); + } else { + if (Tcl_SetVar(interp, argv[2], buffer, flags|TCL_LEAVE_ERR_MSG) + == NULL) { + return TCL_ERROR; + } + flags = TCL_APPEND_VALUE; + } + totalCount += count; + } + + if (argc == 3) { + sprintf(interp->result, "%d", totalCount); + } + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_OpenCmd -- + * + * This procedure is invoked to process the "open" Tcl command. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *---------------------------------------------------------------------- + */ + + /* ARGSUSED */ +int +Tcl_OpenCmd(notUsed, interp, argc, argv) + void *notUsed; /* Not used. */ + Tcl_Interp *interp; /* Current interpreter. */ + int argc; /* Number of arguments. */ + unsigned char **argv; /* Argument strings. */ +{ + Interp *iPtr = (Interp *) interp; + int pipeline, fd; + char *access; + register OpenFile *filePtr; + + if (argc == 2) { + access = "r"; + } else if (argc == 3) { + access = argv[2]; + } else { + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " filename ?access?\"", (char *) NULL); + return TCL_ERROR; + } + + filePtr = (OpenFile *) malloc(sizeof(OpenFile)); + filePtr->f = NULL; + filePtr->f2 = NULL; + filePtr->readable = 0; + filePtr->writable = 0; + filePtr->numPids = 0; + filePtr->pidPtr = NULL; + filePtr->errorId = -1; + + /* + * Verify the requested form of access. + */ + + pipeline = 0; + if (argv[1][0] == '|') { + pipeline = 1; + } + switch (access[0]) { + case 'r': + filePtr->readable = 1; + break; + case 'w': + filePtr->writable = 1; + break; + case 'a': + filePtr->writable = 1; + break; + default: + badAccess: + Tcl_AppendResult(interp, "illegal access mode \"", access, + "\"", (char *) NULL); + goto error; + } + if (access[1] == '+') { + filePtr->readable = filePtr->writable = 1; + if (access[2] != 0) { + goto badAccess; + } + } else if (access[1] != 0) { + goto badAccess; + } + + /* + * Open the file or create a process pipeline. + */ + + if (!pipeline) { + char *fileName = argv[1]; + + if (fileName[0] == '~') { + fileName = Tcl_TildeSubst(interp, fileName); + if (fileName == NULL) { + goto error; + } + } + filePtr->f = fopen(fileName, access); + if (filePtr->f == NULL) { + Tcl_AppendResult(interp, "couldn't open \"", argv[1], + "\": ", Tcl_UnixError(interp), (char *) NULL); + goto error; + } + } else { + int *inPipePtr, *outPipePtr; + int cmdArgc, inPipe, outPipe; + unsigned char **cmdArgv; + + if (Tcl_SplitList(interp, argv[1]+1, &cmdArgc, &cmdArgv) != TCL_OK) { + goto error; + } + inPipePtr = (filePtr->writable) ? &inPipe : NULL; + outPipePtr = (filePtr->readable) ? &outPipe : NULL; + inPipe = outPipe = -1; + filePtr->numPids = Tcl_CreatePipeline(interp, cmdArgc, cmdArgv, + &filePtr->pidPtr, inPipePtr, outPipePtr, &filePtr->errorId); + free((char *) cmdArgv); + if (filePtr->numPids < 0) { + goto error; + } + if (filePtr->readable) { + if (outPipe == -1) { + if (inPipe != -1) { + close(inPipe); + } + Tcl_AppendResult(interp, "can't read output from command:", + " standard output was redirected", (char *) NULL); + goto error; + } + filePtr->f = fdopen(outPipe, "r"); + } + if (filePtr->writable) { + if (inPipe == -1) { + Tcl_AppendResult(interp, "can't write input to command:", + " standard input was redirected", (char *) NULL); + goto error; + } + if (filePtr->f != NULL) { + filePtr->f2 = fdopen(inPipe, "w"); + } else { + filePtr->f = fdopen(inPipe, "w"); + } + } + } + + /* + * Enter this new OpenFile structure in the table for the + * interpreter. May have to expand the table to do this. + */ + + fd = fileno(filePtr->f); + TclMakeFileTable(iPtr, fd); + if (iPtr->filePtrArray[fd] != NULL) { + fprintf (stderr, "Tcl_OpenCmd found file already open\n"); + abort(); + } + iPtr->filePtrArray[fd] = filePtr; + sprintf(interp->result, "file%d", fd); + return TCL_OK; + + error: + if (filePtr->f != NULL) { + fclose(filePtr->f); + } + if (filePtr->f2 != NULL) { + fclose(filePtr->f2); + } + if (filePtr->numPids > 0) { + Tcl_DetachPids(filePtr->numPids, filePtr->pidPtr); + free((char *) filePtr->pidPtr); + } + if (filePtr->errorId != -1) { + close(filePtr->errorId); + } + free((char *) filePtr); + return TCL_ERROR; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_PwdCmd -- + * + * This procedure is invoked to process the "pwd" Tcl command. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *---------------------------------------------------------------------- + */ + + /* ARGSUSED */ +int +Tcl_PwdCmd(dummy, interp, argc, argv) + void *dummy; /* Not used. */ + Tcl_Interp *interp; /* Current interpreter. */ + int argc; /* Number of arguments. */ + unsigned char **argv; /* Argument strings. */ +{ + char buffer[MAXPATHLEN+1]; + + if (argc != 1) { + Tcl_AppendResult(interp, "wrong # args: should be \"", + argv[0], "\"", (char *) NULL); + return TCL_ERROR; + } + if (currentDir == NULL) { +#if TCL_GETWD + if (getwd(buffer) == NULL) { + Tcl_AppendResult(interp, "error getting working directory name: ", + buffer, (char *) NULL); + return TCL_ERROR; + } +#else + if (getwd(buffer) == NULL) { + if (errno == ERANGE) { + interp->result = "working directory name is too long"; + } else { + Tcl_AppendResult(interp, + "error getting working directory name: ", + Tcl_UnixError(interp), (char *) NULL); + } + return TCL_ERROR; + } +#endif + currentDir = (char *) malloc((unsigned) (strlen(buffer) + 1)); + strcpy(currentDir, buffer); + } + interp->result = currentDir; + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_PutsCmd -- + * + * This procedure is invoked to process the "puts" Tcl command. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *---------------------------------------------------------------------- + */ + + /* ARGSUSED */ +int +Tcl_PutsCmd(dummy, interp, argc, argv) + void *dummy; /* Not used. */ + Tcl_Interp *interp; /* Current interpreter. */ + int argc; /* Number of arguments. */ + unsigned char **argv; /* Argument strings. */ +{ + OpenFile *filePtr; + FILE *f; + int i, newline; + char *fileId; + + i = 1; + newline = 1; + if ((argc >= 2) && (strcmp(argv[1], "-nonewline") == 0)) { + newline = 0; + i++; + } + if ((i < (argc-3)) || (i >= argc)) { + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + "\" ?-nonewline? ?fileId? string", (char *) NULL); + return TCL_ERROR; + } + + /* + * The code below provides backwards compatibility with an old + * form of the command that is no longer recommended or documented. + */ + + if (i == (argc-3)) { + if (strncmp(argv[i+2], "nonewline", strlen(argv[i+2])) != 0) { + Tcl_AppendResult(interp, "bad argument \"", argv[i+2], + "\": should be \"nonewline\"", (char *) NULL); + return TCL_ERROR; + } + newline = 0; + } + if (i == (argc-1)) { + fileId = "stdout"; + } else { + fileId = argv[i]; + i++; + } + + if (TclGetOpenFile(interp, fileId, &filePtr) != TCL_OK) { + return TCL_ERROR; + } + if (!filePtr->writable) { + Tcl_AppendResult(interp, "\"", fileId, + "\" wasn't opened for writing", (char *) NULL); + return TCL_ERROR; + } + f = filePtr->f2; + if (f == NULL) { + f = filePtr->f; + } + + fputs(argv[i], f); + if (newline) { + fputc('\n', f); + } + if (ferror(f)) { + Tcl_AppendResult(interp, "error writing \"", fileId, + "\": ", Tcl_UnixError(interp), (char *) NULL); + clearerr(f); + return TCL_ERROR; + } + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_ReadCmd -- + * + * This procedure is invoked to process the "read" Tcl command. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *---------------------------------------------------------------------- + */ + + /* ARGSUSED */ +int +Tcl_ReadCmd(dummy, interp, argc, argv) + void *dummy; /* Not used. */ + Tcl_Interp *interp; /* Current interpreter. */ + int argc; /* Number of arguments. */ + unsigned char **argv; /* Argument strings. */ +{ + OpenFile *filePtr; + int bytesLeft, bytesRead, count; +#define READ_BUF_SIZE 4096 + char buffer[READ_BUF_SIZE+1]; + int newline, i; + + if ((argc != 2) && (argc != 3)) { + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " fileId ?numBytes?\" or \"", argv[0], + " ?-nonewline? fileId\"", (char *) NULL); + return TCL_ERROR; + } + i = 1; + newline = 1; + if ((argc == 3) && (strcmp(argv[1], "-nonewline") == 0)) { + newline = 0; + i++; + } + + if (TclGetOpenFile(interp, argv[i], &filePtr) != TCL_OK) { + return TCL_ERROR; + } + if (!filePtr->readable) { + Tcl_AppendResult(interp, "\"", argv[i], + "\" wasn't opened for reading", (char *) NULL); + return TCL_ERROR; + } + + /* + * Compute how many bytes to read, and see whether the final + * newline should be dropped. + */ + + if ((argc >= (i + 2)) && isdigit(argv[i+1][0])) { + if (Tcl_GetInt(interp, argv[i+1], &bytesLeft) != TCL_OK) { + return TCL_ERROR; + } + } else { + bytesLeft = 1<<30; + + /* + * The code below provides backward compatibility for an + * archaic earlier version of this command. + */ + + if (argc >= (i + 2)) { + if (strncmp(argv[i+1], "nonewline", strlen(argv[i+1])) == 0) { + newline = 0; + } else { + Tcl_AppendResult(interp, "bad argument \"", argv[i+1], + "\": should be \"nonewline\"", (char *) NULL); + return TCL_ERROR; + } + } + } + + /* + * Read the file in one or more chunks. + */ + + bytesRead = 0; + while (bytesLeft > 0) { + count = READ_BUF_SIZE; + if (bytesLeft < READ_BUF_SIZE) { + count = bytesLeft; + } + count = fread(buffer, 1, count, filePtr->f); + if (ferror(filePtr->f)) { + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, "error reading \"", argv[i], + "\": ", Tcl_UnixError(interp), (char *) NULL); + clearerr(filePtr->f); + return TCL_ERROR; + } + if (count == 0) { + break; + } + buffer[count] = 0; + Tcl_AppendResult(interp, buffer, (char *) NULL); + bytesLeft -= count; + bytesRead += count; + } + if ((newline == 0) && (bytesRead > 0) + && (interp->result[bytesRead-1] == '\n')) { + interp->result[bytesRead-1] = 0; + } + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_SeekCmd -- + * + * This procedure is invoked to process the "seek" Tcl command. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *---------------------------------------------------------------------- + */ + + /* ARGSUSED */ +int +Tcl_SeekCmd(notUsed, interp, argc, argv) + void *notUsed; /* Not used. */ + Tcl_Interp *interp; /* Current interpreter. */ + int argc; /* Number of arguments. */ + unsigned char **argv; /* Argument strings. */ +{ + OpenFile *filePtr; + int offset, mode; + + if ((argc != 3) && (argc != 4)) { + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " fileId offset ?origin?\"", (char *) NULL); + return TCL_ERROR; + } + if (TclGetOpenFile(interp, argv[1], &filePtr) != TCL_OK) { + return TCL_ERROR; + } + if (Tcl_GetInt(interp, argv[2], &offset) != TCL_OK) { + return TCL_ERROR; + } + mode = SEEK_SET; + if (argc == 4) { + int length; + char c; + + length = strlen(argv[3]); + c = argv[3][0]; + if ((c == 's') && (strncmp(argv[3], "start", length) == 0)) { + mode = SEEK_SET; + } else if ((c == 'c') && (strncmp(argv[3], "current", length) == 0)) { + mode = SEEK_CUR; + } else if ((c == 'e') && (strncmp(argv[3], "end", length) == 0)) { + mode = SEEK_END; + } else { + Tcl_AppendResult(interp, "bad origin \"", argv[3], + "\": should be start, current, or end", (char *) NULL); + return TCL_ERROR; + } + } + if (fseek(filePtr->f, (long) offset, mode) == -1) { + Tcl_AppendResult(interp, "error during seek: ", + Tcl_UnixError(interp), (char *) NULL); + clearerr(filePtr->f); + return TCL_ERROR; + } + + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_SourceCmd -- + * + * This procedure is invoked to process the "source" Tcl command. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *---------------------------------------------------------------------- + */ + + /* ARGSUSED */ +int +Tcl_SourceCmd(dummy, interp, argc, argv) + void *dummy; /* Not used. */ + Tcl_Interp *interp; /* Current interpreter. */ + int argc; /* Number of arguments. */ + unsigned char **argv; /* Argument strings. */ +{ + if (argc != 2) { + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " fileName\"", (char *) NULL); + return TCL_ERROR; + } + return Tcl_EvalFile(interp, argv[1]); +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_TellCmd -- + * + * This procedure is invoked to process the "tell" Tcl command. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *---------------------------------------------------------------------- + */ + + /* ARGSUSED */ +int +Tcl_TellCmd(notUsed, interp, argc, argv) + void *notUsed; /* Not used. */ + Tcl_Interp *interp; /* Current interpreter. */ + int argc; /* Number of arguments. */ + unsigned char **argv; /* Argument strings. */ +{ + OpenFile *filePtr; + + if (argc != 2) { + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " fileId\"", (char *) NULL); + return TCL_ERROR; + } + if (TclGetOpenFile(interp, argv[1], &filePtr) != TCL_OK) { + return TCL_ERROR; + } + sprintf(interp->result, "%ld", ftell(filePtr->f)); + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_TimeCmd -- + * + * This procedure is invoked to process the "time" Tcl command. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *---------------------------------------------------------------------- + */ + + /* ARGSUSED */ +int +Tcl_TimeCmd(dummy, interp, argc, argv) + void *dummy; /* Not used. */ + Tcl_Interp *interp; /* Current interpreter. */ + int argc; /* Number of arguments. */ + unsigned char **argv; /* Argument strings. */ +{ + int count, i, result; + double timePer; + struct timeval start, stop; + struct timezone tz; + int micros; + + if (argc == 2) { + count = 1; + } else if (argc == 3) { + if (Tcl_GetInt(interp, argv[2], &count) != TCL_OK) { + return TCL_ERROR; + } + } else { + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " command ?count?\"", (char *) NULL); + return TCL_ERROR; + } + gettimeofday(&start, &tz); + for (i = count ; i > 0; i--) { + result = Tcl_Eval(interp, argv[1], 0, NULL); + if (result != TCL_OK) { + if (result == TCL_ERROR) { + char msg[60]; + sprintf(msg, "\n (\"time\" body line %d)", + interp->errorLine); + Tcl_AddErrorInfo(interp, msg); + } + return result; + } + } + gettimeofday(&stop, &tz); + micros = (stop.tv_sec - start.tv_sec)*1000000 + + (stop.tv_usec - start.tv_usec); + timePer = micros; + + Tcl_ResetResult(interp); + sprintf(interp->result, "%.0f microseconds per iteration", timePer/count); + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * CleanupChildren -- + * + * This is a utility procedure used to wait for child processes + * to exit, record information about abnormal exits, and then + * collect any stderr output generated by them. + * + * Results: + * The return value is a standard Tcl result. If anything at + * weird happened with the child processes, TCL_ERROR is returned + * and a message is left in interp->result. + * + * Side effects: + * If the last character of interp->result is a newline, then it + * is removed. File errorId gets closed, and pidPtr is freed + * back to the storage allocator. + * + *---------------------------------------------------------------------- + */ + +static int +CleanupChildren(interp, numPids, pidPtr, errorId) + Tcl_Interp *interp; /* Used for error messages. */ + int numPids; /* Number of entries in pidPtr array. */ + int *pidPtr; /* Array of process ids of children. */ + int errorId; /* File descriptor index for file containing + * stderr output from pipeline. -1 means + * there isn't any stderr output. */ +{ + int result = TCL_OK; + int i, pid, length; +#define WAIT_STATUS_TYPE int + WAIT_STATUS_TYPE waitStatus; + + for (i = 0; i < numPids; i++) { + pid = Tcl_WaitPids(1, &pidPtr[i], (int *) &waitStatus); + if (pid == -1) { + Tcl_AppendResult(interp, "error waiting for process to exit: ", + Tcl_UnixError(interp), (char *) NULL); + continue; + } + + /* + * Create error messages for unusual process exits. An + * extra newline gets appended to each error message, but + * it gets removed below (in the same fashion that an + * extra newline in the command's output is removed). + */ + + if (!WIFEXITED(waitStatus) || (WEXITSTATUS(waitStatus) != 0)) { + char msg1[20], msg2[20]; + + result = TCL_ERROR; + sprintf(msg1, "%d", pid); + if (WIFEXITED(waitStatus)) { + sprintf(msg2, "%d", WEXITSTATUS(waitStatus)); + Tcl_SetErrorCode(interp, "CHILDSTATUS", msg1, msg2, + (char *) NULL); + } else if (WIFSIGNALED(waitStatus)) { + char *p; + + p = Tcl_SignalMsg((int) (WTERMSIG(waitStatus))); + Tcl_SetErrorCode(interp, "CHILDKILLED", msg1, + Tcl_SignalId((int) (WTERMSIG(waitStatus))), p, + (char *) NULL); + Tcl_AppendResult(interp, "child killed: ", p, "\n", + (char *) NULL); + } else if (WIFSTOPPED(waitStatus)) { + char *p; + + p = Tcl_SignalMsg((int) (WSTOPSIG(waitStatus))); + Tcl_SetErrorCode(interp, "CHILDSUSP", msg1, + Tcl_SignalId((int) (WSTOPSIG(waitStatus))), p, (char *) NULL); + Tcl_AppendResult(interp, "child suspended: ", p, "\n", + (char *) NULL); + } else { + Tcl_AppendResult(interp, + "child wait status didn't make sense\n", + (char *) NULL); + } + } + } + free((char *) pidPtr); + + /* + * Read the standard error file. If there's anything there, + * then return an error and add the file's contents to the result + * string. + */ + + if (errorId >= 0) { + while (1) { +# define BUFFER_SIZE 1000 + char buffer[BUFFER_SIZE+1]; + int count; + + count = read(errorId, buffer, BUFFER_SIZE); + + if (count == 0) { + break; + } + if (count < 0) { + Tcl_AppendResult(interp, + "error reading stderr output file: ", + Tcl_UnixError(interp), (char *) NULL); + break; + } + buffer[count] = 0; + Tcl_AppendResult(interp, buffer, (char *) NULL); + } + close(errorId); + } + + /* + * If the last character of interp->result is a newline, then remove + * the newline character (the newline would just confuse things). + */ + + length = strlen(interp->result); + if ((length > 0) && (interp->result[length-1] == '\n')) { + interp->result[length-1] = '\0'; + } + + return result; +} diff --git a/src/libtcl/tclutil.c b/src/libtcl/tclutil.c new file mode 100644 index 0000000..6c1a9a6 --- /dev/null +++ b/src/libtcl/tclutil.c @@ -0,0 +1,1389 @@ +/* + * tclUtil.c -- + * + * This file contains utility procedures that are used by many Tcl + * commands. + * + * Copyright 1987-1991 Regents of the University of California + * 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. The University of California + * makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without + * express or implied warranty. + */ +#include "internal.h" +#include "regexp.h" +#include + +/* + * The following values are used in the flags returned by Tcl_ScanElement + * and used by Tcl_ConvertElement. The value TCL_DONT_USE_BRACES is also + * defined in tcl.h; make sure its value doesn't overlap with any of the + * values below. + * + * TCL_DONT_USE_BRACES - 1 means the string mustn't be enclosed in + * braces (e.g. it contains unmatched braces, + * or ends in a backslash character, or user + * just doesn't want braces); handle all + * special characters by adding backslashes. + * USE_BRACES - 1 means the string contains a special + * character that can be handled simply by + * enclosing the entire argument in braces. + * BRACES_UNMATCHED - 1 means that braces aren't properly matched + * in the argument. + */ + +#define USE_BRACES 2 +#define BRACES_UNMATCHED 4 + +/* + * Function prototypes for local procedures in this file: + */ + +static void SetupAppendBuffer (Interp *iPtr, int newSpace); + +/* + *---------------------------------------------------------------------- + * + * TclFindElement -- + * + * Given a pointer into a Tcl list, locate the first (or next) + * element in the list. + * + * Results: + * The return value is normally TCL_OK, which means that the + * element was successfully located. If TCL_ERROR is returned + * it means that list didn't have proper list structure; + * interp->result contains a more detailed error message. + * + * If TCL_OK is returned, then *elementPtr will be set to point + * to the first element of list, and *nextPtr will be set to point + * to the character just after any white space following the last + * character that's part of the element. If this is the last argument + * in the list, then *nextPtr will point to the NULL character at the + * end of list. If sizePtr is non-NULL, *sizePtr is filled in with + * the number of characters in the element. If the element is in + * braces, then *elementPtr will point to the character after the + * opening brace and *sizePtr will not include either of the braces. + * If there isn't an element in the list, *sizePtr will be zero, and + * both *elementPtr and *termPtr will refer to the null character at + * the end of list. Note: this procedure does NOT collapse backslash + * sequences. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +TclFindElement(interp, list, elementPtr, nextPtr, sizePtr, bracePtr) + Tcl_Interp *interp; /* Interpreter to use for error reporting. */ + register unsigned char *list; /* String containing Tcl list with zero + * or more elements (possibly in braces). */ + unsigned char **elementPtr; /* Fill in with location of first significant + * character in first element of list. */ + unsigned char **nextPtr; /* Fill in with location of character just + * after all white space following end of + * argument (i.e. next argument or end of + * list). */ + int *sizePtr; /* If non-zero, fill in with size of + * element. */ + int *bracePtr; /* If non-zero fill in with non-zero/zero + * to indicate that arg was/wasn't + * in braces. */ +{ + register unsigned char *p; + int openBraces = 0; + int inQuotes = 0; + int size; + + /* + * Skim off leading white space and check for an opening brace or quote. + */ + while (isspace (*list)) { + list++; + } + if (*list == '{') { + openBraces = 1; + list++; + } else if (*list == '"') { + inQuotes = 1; + list++; + } + if (bracePtr != 0) { + *bracePtr = openBraces; + } + p = list; + + /* + * Find the end of the element (either a space or a close brace or + * the end of the string). + */ + + while (1) { + switch (*p) { + + /* + * Open brace: don't treat specially unless the element is + * in braces. In this case, keep a nesting count. + */ + + case '{': + if (openBraces != 0) { + openBraces++; + } + break; + + /* + * Close brace: if element is in braces, keep nesting + * count and quit when the last close brace is seen. + */ + + case '}': + if (openBraces == 1) { + unsigned char *p2; + + size = p - list; + p++; + if ((isspace (*p)) || (*p == 0)) { + goto done; + } + for (p2 = p; (*p2 != 0) && (!isspace(*p2)) && (p2 < p+20); + p2++) { + /* null body */ + } + Tcl_ResetResult(interp); + sprintf(interp->result, + "list element in braces followed by \"%.*s\" instead of space", + (int) (p2 - p), p); + return TCL_ERROR; + } else if (openBraces != 0) { + openBraces--; + } + break; + + /* + * Backslash: skip over everything up to the end of the + * backslash sequence. + */ + + case '\\': { + int size; + + (void) Tcl_Backslash(p, &size); + p += size - 1; + break; + } + + /* + * Space: ignore if element is in braces or quotes; otherwise + * terminate element. + */ + + case ' ': + case '\f': + case '\n': + case '\r': + case '\t': + case '\v': + if ((openBraces == 0) && !inQuotes) { + size = p - list; + goto done; + } + break; + + /* + * Double-quote: if element is in quotes then terminate it. + */ + + case '"': + if (inQuotes) { + unsigned char *p2; + + size = p-list; + p++; + if (isspace (*p) || (*p == 0)) { + goto done; + } + for (p2 = p; (*p2 != 0) && (!isspace(*p2)) && (p2 < p+20); + p2++) { + /* null body */ + } + Tcl_ResetResult(interp); + sprintf(interp->result, + "list element in quotes followed by \"%.*s\" %s", + (int) (p2 - p), p, "instead of space"); + return TCL_ERROR; + } + break; + + /* + * End of list: terminate element. + */ + + case 0: + if (openBraces != 0) { + Tcl_SetResult(interp, (unsigned char*) "unmatched open brace in list", + TCL_STATIC); + return TCL_ERROR; + } else if (inQuotes) { + Tcl_SetResult(interp, (unsigned char*) "unmatched open quote in list", + TCL_STATIC); + return TCL_ERROR; + } + size = p - list; + goto done; + + } + p++; + } + + done: + while (isspace (*p)) { + p++; + } + *elementPtr = list; + *nextPtr = p; + if (sizePtr != 0) { + *sizePtr = size; + } + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * TclCopyAndCollapse -- + * + * Copy a string and eliminate any backslashes that aren't in braces. + * + * Results: + * There is no return value. Count chars. get copied from src + * to dst. Along the way, if backslash sequences are found outside + * braces, the backslashes are eliminated in the copy. + * After scanning count chars. from source, a null character is + * placed at the end of dst. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +void +TclCopyAndCollapse(count, src, dst) + int count; /* Total number of characters to copy + * from src. */ + register unsigned char *src; /* Copy from here... */ + register unsigned char *dst; /* ... to here. */ +{ + register char c; + int numRead; + + for (c = *src; count > 0; src++, c = *src, count--) { + if (c == '\\') { + *dst = Tcl_Backslash(src, &numRead); + if (*dst != 0) { + dst++; + } + src += numRead-1; + count -= numRead-1; + } else { + *dst = c; + dst++; + } + } + *dst = 0; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_SplitList -- + * + * Splits a list up into its constituent fields. + * + * Results + * The return value is normally TCL_OK, which means that + * the list was successfully split up. If TCL_ERROR is + * returned, it means that "list" didn't have proper list + * structure; interp->result will contain a more detailed + * error message. + * + * *argvPtr will be filled in with the address of an array + * whose elements point to the elements of list, in order. + * *argcPtr will get filled in with the number of valid elements + * in the array. A single block of memory is dynamically allocated + * to hold both the argv array and a copy of the list (with + * backslashes and braces removed in the standard way). + * The caller must eventually free this memory by calling free() + * on *argvPtr. Note: *argvPtr and *argcPtr are only modified + * if the procedure returns normally. + * + * Side effects: + * Memory is allocated. + * + *---------------------------------------------------------------------- + */ + +int +Tcl_SplitList(interp, list, argcPtr, argvPtr) + Tcl_Interp *interp; /* Interpreter to use for error reporting. */ + unsigned char *list; /* Pointer to string with list structure. */ + int *argcPtr; /* Pointer to location to fill in with + * the number of elements in the list. */ + unsigned char ***argvPtr; /* Pointer to place to store pointer to array + * of pointers to list elements. */ +{ + unsigned char **argv; + register unsigned char *p; + int size, i, result, elSize, brace; + unsigned char *element; + + /* + * Figure out how much space to allocate. There must be enough + * space for both the array of pointers and also for a copy of + * the list. To estimate the number of pointers needed, count + * the number of space characters in the list. + */ + + for (size = 1, p = list; *p != 0; p++) { + if (isspace(*p)) { + size++; + } + } + size++; /* Leave space for final NULL pointer. */ + argv = (unsigned char**) malloc ((unsigned) + ((size * sizeof(char *)) + (p - list) + 1)); + for (i = 0, p = ((unsigned char *) argv) + size*sizeof(char *); + *list != 0; i++) { + result = TclFindElement(interp, list, &element, &list, &elSize, &brace); + if (result != TCL_OK) { + free (argv); + return result; + } + if (*element == 0) { + break; + } + if (i >= size) { + free (argv); + Tcl_SetResult(interp, (unsigned char*) "internal error in Tcl_SplitList", + TCL_STATIC); + return TCL_ERROR; + } + argv[i] = p; + if (brace) { + strncpy(p, element, elSize); + p += elSize; + *p = 0; + p++; + } else { + TclCopyAndCollapse(elSize, element, p); + p += elSize+1; + } + } + + argv[i] = 0; + *argvPtr = argv; + *argcPtr = i; + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_ScanElement -- + * + * This procedure is a companion procedure to Tcl_ConvertElement. + * It scans a string to see what needs to be done to it (e.g. + * add backslashes or enclosing braces) to make the string into + * a valid Tcl list element. + * + * Results: + * The return value is an overestimate of the number of characters + * that will be needed by Tcl_ConvertElement to produce a valid + * list element from string. The word at *flagPtr is filled in + * with a value needed by Tcl_ConvertElement when doing the actual + * conversion. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +Tcl_ScanElement(string, flagPtr) + unsigned char *string; /* String to convert to Tcl list element. */ + int *flagPtr; /* Where to store information to guide + * Tcl_ConvertElement. */ +{ + int flags, nestingLevel; + register unsigned char *p; + + /* + * This procedure and Tcl_ConvertElement together do two things: + * + * 1. They produce a proper list, one that will yield back the + * argument strings when evaluated or when disassembled with + * Tcl_SplitList. This is the most important thing. + * + * 2. They try to produce legible output, which means minimizing the + * use of backslashes (using braces instead). However, there are + * some situations where backslashes must be used (e.g. an element + * like "{abc": the leading brace will have to be backslashed. For + * each element, one of three things must be done: + * + * (a) Use the element as-is (it doesn't contain anything special + * characters). This is the most desirable option. + * + * (b) Enclose the element in braces, but leave the contents alone. + * This happens if the element contains embedded space, or if it + * contains characters with special interpretation ($, [, ;, or \), + * or if it starts with a brace or double-quote, or if there are + * no characters in the element. + * + * (c) Don't enclose the element in braces, but add backslashes to + * prevent special interpretation of special characters. This is a + * last resort used when the argument would normally fall under case + * (b) but contains unmatched braces. It also occurs if the last + * character of the argument is a backslash or if the element contains + * a backslash followed by newline. + * + * The procedure figures out how many bytes will be needed to store + * the result (actually, it overestimates). It also collects information + * about the element in the form of a flags word. + */ + + nestingLevel = 0; + flags = 0; + if (string == 0) { + string = (unsigned char*) ""; + } + p = string; + if ((*p == '{') || (*p == '"') || (*p == 0)) { + flags |= USE_BRACES; + } + for ( ; *p != 0; p++) { + switch (*p) { + case '{': + nestingLevel++; + break; + case '}': + nestingLevel--; + if (nestingLevel < 0) { + flags |= TCL_DONT_USE_BRACES|BRACES_UNMATCHED; + } + break; + case '[': + case '$': + case ';': + case ' ': + case '\f': + case '\n': + case '\r': + case '\t': + case '\v': + flags |= USE_BRACES; + break; + case '\\': + if ((p[1] == 0) || (p[1] == '\n')) { + flags = TCL_DONT_USE_BRACES; + } else { + int size; + + (void) Tcl_Backslash(p, &size); + p += size-1; + flags |= USE_BRACES; + } + break; + } + } + if (nestingLevel != 0) { + flags = TCL_DONT_USE_BRACES | BRACES_UNMATCHED; + } + *flagPtr = flags; + + /* + * Allow enough space to backslash every character plus leave + * two spaces for braces. + */ + + return 2*(p-string) + 2; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_ConvertElement -- + * + * This is a companion procedure to Tcl_ScanElement. Given the + * information produced by Tcl_ScanElement, this procedure converts + * a string to a list element equal to that string. + * + * Results: + * Information is copied to *dst in the form of a list element + * identical to src (i.e. if Tcl_SplitList is applied to dst it + * will produce a string identical to src). The return value is + * a count of the number of characters copied (not including the + * terminating NULL character). + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +Tcl_ConvertElement(src, dst, flags) + register unsigned char *src; /* Source information for list element. */ + unsigned char *dst; /* Place to put list-ified element. */ + int flags; /* Flags produced by Tcl_ScanElement. */ +{ + register unsigned char *p = dst; + + /* + * See the comment block at the beginning of the Tcl_ScanElement + * code for details of how this works. + */ + + if (src == 0) { + src = (unsigned char*) ""; + } + if ((flags & USE_BRACES) && !(flags & TCL_DONT_USE_BRACES)) { + *p = '{'; + p++; + for ( ; *src != 0; src++, p++) { + *p = *src; + } + *p = '}'; + p++; + } else if (*src == 0) { + /* + * If string is empty but can't use braces, then use special + * backslash sequence that maps to empty string. + */ + + p[0] = '\\'; + p[1] = '0'; + p += 2; + } else { + for (; *src != 0 ; src++) { + switch (*src) { + case ']': + case '[': + case '$': + case ';': + case ' ': + case '\\': + case '"': + *p = '\\'; + p++; + break; + case '{': + case '}': + if (flags & BRACES_UNMATCHED) { + *p = '\\'; + p++; + } + break; + case '\f': + *p = '\\'; + p++; + *p = 'f'; + p++; + continue; + case '\n': + *p = '\\'; + p++; + *p = 'n'; + p++; + continue; + case '\r': + *p = '\\'; + p++; + *p = 'r'; + p++; + continue; + case '\t': + *p = '\\'; + p++; + *p = 't'; + p++; + continue; + case '\v': + *p = '\\'; + p++; + *p = 'v'; + p++; + continue; + } + *p = *src; + p++; + } + } + *p = '\0'; + return p-dst; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_Merge -- + * + * Given a collection of strings, merge them together into a + * single string that has proper Tcl list structured (i.e. + * Tcl_SplitList may be used to retrieve strings equal to the + * original elements, and Tcl_Eval will parse the string back + * into its original elements). + * + * Results: + * The return value is the address of a dynamically-allocated + * string containing the merged list. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ +unsigned char * +Tcl_Merge (int argc, /* How many strings to merge. */ + unsigned char **argv) /* Array of string values. */ +{ +# define LOCAL_SIZE 20 + int localFlags[LOCAL_SIZE], *flagPtr; + int numChars; + unsigned char *result; + register unsigned char *dst; + int i; + + /* + * Pass 1: estimate space, gather flags. + */ + + if (argc <= LOCAL_SIZE) { + flagPtr = localFlags; + } else { + flagPtr = (int*) malloc ((unsigned) argc*sizeof(int)); + } + numChars = 1; + for (i = 0; i < argc; i++) { + numChars += Tcl_ScanElement(argv[i], &flagPtr[i]) + 1; + } + + /* + * Pass two: copy into the result area. + */ + + result = malloc (numChars); + dst = result; + for (i = 0; i < argc; i++) { + numChars = Tcl_ConvertElement(argv[i], dst, flagPtr[i]); + dst += numChars; + *dst = ' '; + dst++; + } + if (dst == result) { + *dst = 0; + } else { + dst[-1] = 0; + } + + if (flagPtr != localFlags) { + free (flagPtr); + } + return result; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_Concat -- + * + * Concatenate a set of strings into a single large string. + * + * Results: + * The return value is dynamically-allocated string containing + * a concatenation of all the strings in argv, with spaces between + * the original argv elements. + * + * Side effects: + * Memory is allocated for the result; the caller is responsible + * for freeing the memory. + * + *---------------------------------------------------------------------- + */ + +unsigned char * +Tcl_Concat (int argc, /* Number of strings to concatenate. */ + unsigned char **argv) /* Array of strings to concatenate. */ +{ + int totalSize, i; + register unsigned char *p; + unsigned char *result; + + for (totalSize = 1, i = 0; i < argc; i++) { + totalSize += strlen(argv[i]) + 1; + } + result = malloc (totalSize); + if (argc == 0) { + *result = '\0'; + return result; + } + for (p = result, i = 0; i < argc; i++) { + unsigned char *element; + int length; + + /* + * Clip white space off the front and back of the string + * to generate a neater result, and ignore any empty + * elements. + */ + + element = argv[i]; + while (isspace(*element)) { + element++; + } + for (length = strlen(element); + (length > 0) && (isspace(element[length-1])); + length--) { + /* Null loop body. */ + } + if (length == 0) { + continue; + } + (void) strncpy(p, element, length); + p += length; + *p = ' '; + p++; + } + if (p != result) { + p[-1] = 0; + } else { + *p = 0; + } + return result; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_StringMatch -- + * + * See if a particular string matches a particular pattern. + * + * Results: + * The return value is 1 if string matches pattern, and + * 0 otherwise. The matching operation permits the following + * special characters in the pattern: *?\[] (see the manual + * entry for details on what these mean). + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +Tcl_StringMatch(string, pattern) + register unsigned char *string; /* String. */ + register unsigned char *pattern; /* Pattern, which may contain + * special characters. */ +{ + char c2; + + while (1) { + /* See if we're at the end of both the pattern and the string. + * If so, we succeeded. If we're at the end of the pattern + * but not at the end of the string, we failed. + */ + + if (*pattern == 0) { + if (*string == 0) { + return 1; + } else { + return 0; + } + } + if ((*string == 0) && (*pattern != '*')) { + return 0; + } + + /* Check for a "*" as the next pattern character. It matches + * any substring. We handle this by calling ourselves + * recursively for each postfix of string, until either we + * match or we reach the end of the string. + */ + + if (*pattern == '*') { + pattern += 1; + if (*pattern == 0) { + return 1; + } + while (1) { + if (Tcl_StringMatch(string, pattern)) { + return 1; + } + if (*string == 0) { + return 0; + } + string += 1; + } + } + + /* Check for a "?" as the next pattern character. It matches + * any single character. + */ + + if (*pattern == '?') { + goto thisCharOK; + } + + /* Check for a "[" as the next pattern character. It is followed + * by a list of characters that are acceptable, or by a range + * (two characters separated by "-"). + */ + + if (*pattern == '[') { + pattern += 1; + while (1) { + if ((*pattern == ']') || (*pattern == 0)) { + return 0; + } + if (*pattern == *string) { + break; + } + if (pattern[1] == '-') { + c2 = pattern[2]; + if (c2 == 0) { + return 0; + } + if ((*pattern <= *string) && (c2 >= *string)) { + break; + } + if ((*pattern >= *string) && (c2 <= *string)) { + break; + } + pattern += 2; + } + pattern += 1; + } + while ((*pattern != ']') && (*pattern != 0)) { + pattern += 1; + } + goto thisCharOK; + } + + /* If the next pattern character is '/', just strip off the '/' + * so we do exact matching on the character that follows. + */ + + if (*pattern == '\\') { + pattern += 1; + if (*pattern == 0) { + return 0; + } + } + + /* There's no special character. Just make sure that the next + * characters of each string match. + */ + + if (*pattern != *string) { + return 0; + } + + thisCharOK: pattern += 1; + string += 1; + } +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_SetResult -- + * + * Arrange for "string" to be the Tcl return value. + * + * Results: + * None. + * + * Side effects: + * interp->result is left pointing either to "string" (if "copy" is 0) + * or to a copy of string. + * + *---------------------------------------------------------------------- + */ + +void +Tcl_SetResult(interp, string, freeProc) + Tcl_Interp *interp; /* Interpreter with which to associate the + * return value. */ + unsigned char *string; /* Value to be returned. If NULL, + * the result is set to an empty string. */ + Tcl_FreeProc *freeProc; /* Gives information about the string: + * TCL_STATIC, TCL_VOLATILE, or the address + * of a Tcl_FreeProc such as free. */ +{ + register Interp *iPtr = (Interp *) interp; + int length; + Tcl_FreeProc *oldFreeProc = iPtr->freeProc; + unsigned char *oldResult = iPtr->result; + + iPtr->freeProc = freeProc; + if (string == 0) { + iPtr->resultSpace[0] = 0; + iPtr->result = iPtr->resultSpace; + iPtr->freeProc = 0; + } else if (freeProc == TCL_VOLATILE) { + length = strlen(string); + if (length > TCL_RESULT_SIZE) { + iPtr->result = malloc (length+1); + iPtr->freeProc = (Tcl_FreeProc *) free; + } else { + iPtr->result = iPtr->resultSpace; + iPtr->freeProc = 0; + } + strcpy(iPtr->result, string); + } else { + iPtr->result = string; + } + + /* + * If the old result was dynamically-allocated, free it up. Do it + * here, rather than at the beginning, in case the new result value + * was part of the old result value. + */ + + if (oldFreeProc != 0) { + if (oldFreeProc == TCL_DYNAMIC) { + free(oldResult); + } else { + (*oldFreeProc)(oldResult); + } + } +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_AppendResult -- + * + * Append a variable number of strings onto the result already + * present for an interpreter. + * + * Results: + * None. + * + * Side effects: + * The result in the interpreter given by the first argument + * is extended by the strings given by the second and following + * arguments (up to a terminating NULL argument). + * + *---------------------------------------------------------------------- + */ + + /* VARARGS2 */ +void +Tcl_AppendResult (Tcl_Interp *interp, /* Interpreter whose result is to be + * extended. */ + ...) /* One or more strings to add to the + * result, terminated with NULL. */ +{ + va_list argList; + register Interp *iPtr = (Interp *) interp; + unsigned char *string; + int newSpace; + + /* + * First, scan through all the arguments to see how much space is + * needed. + */ + va_start(argList, interp); + newSpace = 0; + while (1) { + string = va_arg(argList, unsigned char *); + if (string == 0) { + break; + } + newSpace += strlen(string); + } + va_end(argList); + + /* + * If the append buffer isn't already setup and large enough + * to hold the new data, set it up. + */ + if ((iPtr->result != iPtr->appendResult) + || ((newSpace + iPtr->appendUsed) >= iPtr->appendAvl)) { + SetupAppendBuffer(iPtr, newSpace); + } + + /* + * Final step: go through all the argument strings again, copying + * them into the buffer. + */ + va_start(argList, interp); + while (1) { + string = va_arg(argList, unsigned char *); + if (string == 0) { + break; + } + strcpy(iPtr->appendResult + iPtr->appendUsed, string); + iPtr->appendUsed += strlen(string); + } + va_end(argList); +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_AppendElement -- + * + * Convert a string to a valid Tcl list element and append it + * to the current result (which is ostensibly a list). + * + * Results: + * None. + * + * Side effects: + * The result in the interpreter given by the first argument + * is extended with a list element converted from string. If + * the original result wasn't empty, then a blank is added before + * the converted list element. + * + *---------------------------------------------------------------------- + */ + +void +Tcl_AppendElement(interp, string, noSep) + Tcl_Interp *interp; /* Interpreter whose result is to be + * extended. */ + unsigned char *string; /* String to convert to list element and + * add to result. */ + int noSep; /* If non-zero, then don't output a + * space character before this element, + * even if the element isn't the first + * thing in the output buffer. */ +{ + register Interp *iPtr = (Interp *) interp; + int size, flags; + unsigned char *dst; + + /* + * See how much space is needed, and grow the append buffer if + * needed to accommodate the list element. + */ + + size = Tcl_ScanElement(string, &flags) + 1; + if ((iPtr->result != iPtr->appendResult) + || ((size + iPtr->appendUsed) >= iPtr->appendAvl)) { + SetupAppendBuffer(iPtr, size+iPtr->appendUsed); + } + + /* + * Convert the string into a list element and copy it to the + * buffer that's forming. + */ + + dst = iPtr->appendResult + iPtr->appendUsed; + if (!noSep && (iPtr->appendUsed != 0)) { + iPtr->appendUsed++; + *dst = ' '; + dst++; + } + iPtr->appendUsed += Tcl_ConvertElement(string, dst, flags); +} + +/* + *---------------------------------------------------------------------- + * + * SetupAppendBuffer -- + * + * This procedure makes sure that there is an append buffer + * properly initialized for interp, and that it has at least + * enough room to accommodate newSpace new bytes of information. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static void +SetupAppendBuffer(iPtr, newSpace) + register Interp *iPtr; /* Interpreter whose result is being set up. */ + int newSpace; /* Make sure that at least this many bytes + * of new information may be added. */ +{ + int totalSpace; + + /* + * Make the append buffer larger, if that's necessary, then + * copy the current result into the append buffer and make the + * append buffer the official Tcl result. + */ + + if (iPtr->result != iPtr->appendResult) { + /* + * If an oversized buffer was used recently, then free it up + * so we go back to a smaller buffer. This avoids tying up + * memory forever after a large operation. + */ + + if (iPtr->appendAvl > 500) { + free (iPtr->appendResult); + iPtr->appendResult = 0; + iPtr->appendAvl = 0; + } + iPtr->appendUsed = strlen(iPtr->result); + } + totalSpace = newSpace + iPtr->appendUsed; + if (totalSpace >= iPtr->appendAvl) { + unsigned char *new; + + if (totalSpace < 100) { + totalSpace = 200; + } else { + totalSpace *= 2; + } + new = malloc (totalSpace); + strcpy(new, iPtr->result); + if (iPtr->appendResult != 0) { + free (iPtr->appendResult); + } + iPtr->appendResult = new; + iPtr->appendAvl = totalSpace; + } else if (iPtr->result != iPtr->appendResult) { + strcpy(iPtr->appendResult, iPtr->result); + } + Tcl_FreeResult ((Tcl_Interp*) iPtr); + iPtr->result = iPtr->appendResult; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_ResetResult -- + * + * This procedure restores the result area for an interpreter + * to its default initialized state, freeing up any memory that + * may have been allocated for the result and clearing any + * error information for the interpreter. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +void +Tcl_ResetResult(interp) + Tcl_Interp *interp; /* Interpreter for which to clear result. */ +{ + register Interp *iPtr = (Interp *) interp; + + Tcl_FreeResult ((Tcl_Interp*) iPtr); + iPtr->result = iPtr->resultSpace; + iPtr->resultSpace[0] = 0; + iPtr->flags &= + ~(ERR_ALREADY_LOGGED | ERR_IN_PROGRESS | ERROR_CODE_SET); +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_SetErrorCode -- + * + * This procedure is called to record machine-readable information + * about an error that is about to be returned. + * + * Results: + * None. + * + * Side effects: + * The errorCode global variable is modified to hold all of the + * arguments to this procedure, in a list form with each argument + * becoming one element of the list. A flag is set internally + * to remember that errorCode has been set, so the variable doesn't + * get set automatically when the error is returned. + * + *---------------------------------------------------------------------- + */ + /* VARARGS2 */ +void +Tcl_SetErrorCode (Tcl_Interp *interp, /* Interpreter whose errorCode variable is + * to be set. */ + ...) /* One or more elements to add to errorCode, + * terminated with NULL. */ +{ + va_list argList; + unsigned char *string; + int flags; + Interp *iPtr = (Interp *) interp; + + /* + * Scan through the arguments one at a time, appending them to + * $errorCode as list elements. + */ + va_start(argList, interp); + flags = TCL_GLOBAL_ONLY | TCL_LIST_ELEMENT; + while (1) { + string = va_arg(argList, unsigned char *); + if (string == 0) { + break; + } + Tcl_SetVar2((Tcl_Interp *) iPtr, (unsigned char*) "errorCode", + 0, string, flags); + flags |= TCL_APPEND_VALUE; + } + va_end(argList); + iPtr->flags |= ERROR_CODE_SET; +} + +/* + *---------------------------------------------------------------------- + * + * TclGetListIndex -- + * + * Parse a list index, which may be either an integer or the + * value "end". + * + * Results: + * The return value is either TCL_OK or TCL_ERROR. If it is + * TCL_OK, then the index corresponding to string is left in + * *indexPtr. If the return value is TCL_ERROR, then string + * was bogus; an error message is returned in interp->result. + * If a negative index is specified, it is rounded up to 0. + * The index value may be larger than the size of the list + * (this happens when "end" is specified). + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +TclGetListIndex(interp, string, indexPtr) + Tcl_Interp *interp; /* Interpreter for error reporting. */ + unsigned char *string; /* String containing list index. */ + int *indexPtr; /* Where to store index. */ +{ + if (isdigit(*string) || (*string == '-')) { + if (Tcl_GetInt(interp, string, indexPtr) != TCL_OK) { + return TCL_ERROR; + } + if (*indexPtr < 0) { + *indexPtr = 0; + } + } else if (strncmp(string, (unsigned char*) "end", strlen(string)) == 0) { + *indexPtr = 32767; + } else { + Tcl_AppendResult(interp, "bad index \"", string, + "\": must be integer or \"end\"", 0); + return TCL_ERROR; + } + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * TclCompileRegexp -- + * + * Compile a regular expression into a form suitable for fast + * matching. This procedure retains a small cache of pre-compiled + * regular expressions in the interpreter, in order to avoid + * compilation costs as much as possible. + * + * Results: + * The return value is a pointer to the compiled form of string, + * suitable for passing to regexec. If an error occurred while + * compiling the pattern, then NULL is returned and an error + * message is left in interp->result. + * + * Side effects: + * The cache of compiled regexp's in interp will be modified to + * hold information for string, if such information isn't already + * present in the cache. + * + *---------------------------------------------------------------------- + */ + +regexp_t * +TclCompileRegexp(interp, string) + Tcl_Interp *interp; /* For use in error reporting. */ + unsigned char *string; /* String for which to produce + * compiled regular expression. */ +{ + register Interp *iPtr = (Interp *) interp; + int i, length, size; + regexp_t *result; + + length = strlen(string); + for (i = 0; i < NUM_REGEXPS; i++) { + if ((length == iPtr->patLengths[i]) + && (strcmp(string, iPtr->patterns[i]) == 0)) { + /* + * Move the matched pattern to the first slot in the + * cache and shift the other patterns down one position. + */ + + if (i != 0) { + int j; + unsigned char *cachedString; + + cachedString = iPtr->patterns[i]; + result = iPtr->regexps[i]; + for (j = i-1; j >= 0; j--) { + iPtr->patterns[j+1] = iPtr->patterns[j]; + iPtr->patLengths[j+1] = iPtr->patLengths[j]; + iPtr->regexps[j+1] = iPtr->regexps[j]; + } + iPtr->patterns[0] = cachedString; + iPtr->patLengths[0] = length; + iPtr->regexps[0] = result; + } + return iPtr->regexps[0]; + } + } + + /* + * No match in the cache. Compile the string and add it to the + * cache. + */ + size = regexp_size (string); + if (size <= 0) { + Tcl_AppendResult(interp, "invalid regular expression pattern", 0); + return 0; + } + result = (regexp_t*) malloc (size); + if (! regexp_compile (result, string)) { + Tcl_AppendResult(interp, "couldn't compile regular expression pattern", 0); + return 0; + } + if (iPtr->patterns[NUM_REGEXPS-1] != 0) { + free (iPtr->patterns[NUM_REGEXPS-1]); + free (iPtr->regexps[NUM_REGEXPS-1]); + } + for (i = NUM_REGEXPS - 2; i >= 0; i--) { + iPtr->patterns[i+1] = iPtr->patterns[i]; + iPtr->patLengths[i+1] = iPtr->patLengths[i]; + iPtr->regexps[i+1] = iPtr->regexps[i]; + } + iPtr->patterns[0] = malloc (length+1); + strcpy(iPtr->patterns[0], string); + iPtr->patLengths[0] = length; + iPtr->regexps[0] = result; + return result; +} diff --git a/src/libtcl/tcluxstr.c b/src/libtcl/tcluxstr.c new file mode 100644 index 0000000..17245eb --- /dev/null +++ b/src/libtcl/tcluxstr.c @@ -0,0 +1,725 @@ +/* + * tclUnixStr.c -- + * + * This file contains procedures that generate strings + * corresponding to various UNIX-related codes, such + * as errno and signals. + * + * Copyright 1991 Regents of the University of California + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without + * fee is hereby granted, provided that this copyright + * notice appears in all copies. The University of California + * makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without + * express or implied warranty. + */ +#include "internal.h" +#ifdef CROSS +# include +#else +# include +#endif + +/* + *---------------------------------------------------------------------- + * + * Tcl_ErrnoId -- + * + * Return a textual identifier for the current errno value. + * + * Results: + * This procedure returns a machine-readable textual identifier + * that corresponds to the current errno value (e.g. "EPERM"). + * The identifier is the same as the #define name in errno.h. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +unsigned char * +Tcl_ErrnoId() +{ + switch (errno) { +#ifdef E2BIG + case E2BIG: return "E2BIG"; +#endif +#ifdef EACCES + case EACCES: return "EACCES"; +#endif +#ifdef EADDRINUSE + case EADDRINUSE: return "EADDRINUSE"; +#endif +#ifdef EADDRNOTAVAIL + case EADDRNOTAVAIL: return "EADDRNOTAVAIL"; +#endif +#ifdef EADV + case EADV: return "EADV"; +#endif +#ifdef EAFNOSUPPORT + case EAFNOSUPPORT: return "EAFNOSUPPORT"; +#endif +#ifdef EAGAIN + case EAGAIN: return "EAGAIN"; +#endif +#ifdef EALIGN + case EALIGN: return "EALIGN"; +#endif +#ifdef EALREADY + case EALREADY: return "EALREADY"; +#endif +#ifdef EBADE + case EBADE: return "EBADE"; +#endif +#ifdef EBADF + case EBADF: return "EBADF"; +#endif +#ifdef EBADFD + case EBADFD: return "EBADFD"; +#endif +#ifdef EBADMSG + case EBADMSG: return "EBADMSG"; +#endif +#ifdef EBADR + case EBADR: return "EBADR"; +#endif +#ifdef EBADRPC + case EBADRPC: return "EBADRPC"; +#endif +#ifdef EBADRQC + case EBADRQC: return "EBADRQC"; +#endif +#ifdef EBADSLT + case EBADSLT: return "EBADSLT"; +#endif +#ifdef EBFONT + case EBFONT: return "EBFONT"; +#endif +#ifdef EBUSY + case EBUSY: return "EBUSY"; +#endif +#ifdef ECHILD + case ECHILD: return "ECHILD"; +#endif +#ifdef ECHRNG + case ECHRNG: return "ECHRNG"; +#endif +#ifdef ECOMM + case ECOMM: return "ECOMM"; +#endif +#ifdef ECONNABORTED + case ECONNABORTED: return "ECONNABORTED"; +#endif +#ifdef ECONNREFUSED + case ECONNREFUSED: return "ECONNREFUSED"; +#endif +#ifdef ECONNRESET + case ECONNRESET: return "ECONNRESET"; +#endif +#if defined(EDEADLK) && (!defined(EWOULDBLOCK) || (EDEADLK != EWOULDBLOCK)) + case EDEADLK: return "EDEADLK"; +#endif +/* +#ifdef EDEADLOCK + case EDEADLOCK: return "EDEADLOCK"; +#endif +*/ +#ifdef EDESTADDRREQ + case EDESTADDRREQ: return "EDESTADDRREQ"; +#endif +#ifdef EDIRTY + case EDIRTY: return "EDIRTY"; +#endif +#ifdef EDOM + case EDOM: return "EDOM"; +#endif +#ifdef EDOTDOT + case EDOTDOT: return "EDOTDOT"; +#endif +#ifdef EDQUOT + case EDQUOT: return "EDQUOT"; +#endif +#ifdef EDUPPKG + case EDUPPKG: return "EDUPPKG"; +#endif +#ifdef EEXIST + case EEXIST: return "EEXIST"; +#endif +#ifdef EFAULT + case EFAULT: return "EFAULT"; +#endif +#ifdef EFBIG + case EFBIG: return "EFBIG"; +#endif +#ifdef EHOSTDOWN + case EHOSTDOWN: return "EHOSTDOWN"; +#endif +#ifdef EHOSTUNREACH + case EHOSTUNREACH: return "EHOSTUNREACH"; +#endif +#ifdef EIDRM + case EIDRM: return "EIDRM"; +#endif +#ifdef EINIT + case EINIT: return "EINIT"; +#endif +#ifdef EINPROGRESS + case EINPROGRESS: return "EINPROGRESS"; +#endif +#ifdef EINTR + case EINTR: return "EINTR"; +#endif +#ifdef EINVAL + case EINVAL: return "EINVAL"; +#endif +#ifdef EIO + case EIO: return "EIO"; +#endif +#ifdef EISCONN + case EISCONN: return "EISCONN"; +#endif +#ifdef EISDIR + case EISDIR: return "EISDIR"; +#endif +#ifdef EISNAME + case EISNAM: return "EISNAM"; +#endif +#ifdef ELBIN + case ELBIN: return "ELBIN"; +#endif +#ifdef EL2HLT + case EL2HLT: return "EL2HLT"; +#endif +#ifdef EL2NSYNC + case EL2NSYNC: return "EL2NSYNC"; +#endif +#ifdef EL3HLT + case EL3HLT: return "EL3HLT"; +#endif +#ifdef EL3RST + case EL3RST: return "EL3RST"; +#endif +#ifdef ELIBACC + case ELIBACC: return "ELIBACC"; +#endif +#ifdef ELIBBAD + case ELIBBAD: return "ELIBBAD"; +#endif +#ifdef ELIBEXEC + case ELIBEXEC: return "ELIBEXEC"; +#endif +#ifdef ELIBMAX + case ELIBMAX: return "ELIBMAX"; +#endif +#ifdef ELIBSCN + case ELIBSCN: return "ELIBSCN"; +#endif +#ifdef ELNRNG + case ELNRNG: return "ELNRNG"; +#endif +#ifdef ELOOP + case ELOOP: return "ELOOP"; +#endif +#ifdef EMFILE + case EMFILE: return "EMFILE"; +#endif +#ifdef EMLINK + case EMLINK: return "EMLINK"; +#endif +#ifdef EMSGSIZE + case EMSGSIZE: return "EMSGSIZE"; +#endif +#ifdef EMULTIHOP + case EMULTIHOP: return "EMULTIHOP"; +#endif +#ifdef ENAMETOOLONG + case ENAMETOOLONG: return "ENAMETOOLONG"; +#endif +#ifdef ENAVAIL + case ENAVAIL: return "ENAVAIL"; +#endif +#ifdef ENET + case ENET: return "ENET"; +#endif +#ifdef ENETDOWN + case ENETDOWN: return "ENETDOWN"; +#endif +#ifdef ENETRESET + case ENETRESET: return "ENETRESET"; +#endif +#ifdef ENETUNREACH + case ENETUNREACH: return "ENETUNREACH"; +#endif +#ifdef ENFILE + case ENFILE: return "ENFILE"; +#endif +#ifdef ENOANO + case ENOANO: return "ENOANO"; +#endif +#if defined(ENOBUFS) && (!defined(ENOSR) || (ENOBUFS != ENOSR)) + case ENOBUFS: return "ENOBUFS"; +#endif +#ifdef ENOCSI + case ENOCSI: return "ENOCSI"; +#endif +#ifdef ENODATA + case ENODATA: return "ENODATA"; +#endif +#ifdef ENODEV + case ENODEV: return "ENODEV"; +#endif +#ifdef ENOENT + case ENOENT: return "ENOENT"; +#endif +#ifdef ENOEXEC + case ENOEXEC: return "ENOEXEC"; +#endif +#ifdef ENOLCK + case ENOLCK: return "ENOLCK"; +#endif +#ifdef ENOLINK + case ENOLINK: return "ENOLINK"; +#endif +#ifdef ENOMEM + case ENOMEM: return "ENOMEM"; +#endif +#ifdef ENOMSG + case ENOMSG: return "ENOMSG"; +#endif +#ifdef ENONET + case ENONET: return "ENONET"; +#endif +#ifdef ENOPKG + case ENOPKG: return "ENOPKG"; +#endif +#ifdef ENOPROTOOPT + case ENOPROTOOPT: return "ENOPROTOOPT"; +#endif +#ifdef ENOSPC + case ENOSPC: return "ENOSPC"; +#endif +#ifdef ENOSR + case ENOSR: return "ENOSR"; +#endif +#ifdef ENOSTR + case ENOSTR: return "ENOSTR"; +#endif +#ifdef ENOSYM + case ENOSYM: return "ENOSYM"; +#endif +#ifdef ENOSYS + case ENOSYS: return "ENOSYS"; +#endif +#ifdef ENOTBLK + case ENOTBLK: return "ENOTBLK"; +#endif +#ifdef ENOTCONN + case ENOTCONN: return "ENOTCONN"; +#endif +#ifdef ENOTDIR + case ENOTDIR: return "ENOTDIR"; +#endif +#if defined(ENOTEMPTY) && (!defined(EEXIST) || (ENOTEMPTY != EEXIST)) + case ENOTEMPTY: return "ENOTEMPTY"; +#endif +#ifdef ENOTNAM + case ENOTNAM: return "ENOTNAM"; +#endif +#ifdef ENOTSOCK + case ENOTSOCK: return "ENOTSOCK"; +#endif +#ifdef ENOTTY + case ENOTTY: return "ENOTTY"; +#endif +#ifdef ENOTUNIQ + case ENOTUNIQ: return "ENOTUNIQ"; +#endif +#ifdef ENXIO + case ENXIO: return "ENXIO"; +#endif +#ifdef EOPNOTSUPP + case EOPNOTSUPP: return "EOPNOTSUPP"; +#endif +#ifdef EPERM + case EPERM: return "EPERM"; +#endif +#ifdef EPFNOSUPPORT + case EPFNOSUPPORT: return "EPFNOSUPPORT"; +#endif +#ifdef EPIPE + case EPIPE: return "EPIPE"; +#endif +#ifdef EPROCLIM + case EPROCLIM: return "EPROCLIM"; +#endif +#ifdef EPROCUNAVAIL + case EPROCUNAVAIL: return "EPROCUNAVAIL"; +#endif +#ifdef EPROGMISMATCH + case EPROGMISMATCH: return "EPROGMISMATCH"; +#endif +#ifdef EPROGUNAVAIL + case EPROGUNAVAIL: return "EPROGUNAVAIL"; +#endif +#ifdef EPROTO + case EPROTO: return "EPROTO"; +#endif +#ifdef EPROTONOSUPPORT + case EPROTONOSUPPORT: return "EPROTONOSUPPORT"; +#endif +#ifdef EPROTOTYPE + case EPROTOTYPE: return "EPROTOTYPE"; +#endif +#ifdef ERANGE + case ERANGE: return "ERANGE"; +#endif +#if defined(EREFUSED) && (!defined(ECONNREFUSED) || (EREFUSED != ECONNREFUSED)) + case EREFUSED: return "EREFUSED"; +#endif +#ifdef EREMCHG + case EREMCHG: return "EREMCHG"; +#endif +#ifdef EREMDEV + case EREMDEV: return "EREMDEV"; +#endif +#ifdef EREMOTE + case EREMOTE: return "EREMOTE"; +#endif +#ifdef EREMOTEIO + case EREMOTEIO: return "EREMOTEIO"; +#endif +#ifdef EREMOTERELEASE + case EREMOTERELEASE: return "EREMOTERELEASE"; +#endif +#ifdef EROFS + case EROFS: return "EROFS"; +#endif +#ifdef ERPCMISMATCH + case ERPCMISMATCH: return "ERPCMISMATCH"; +#endif +#ifdef ERREMOTE + case ERREMOTE: return "ERREMOTE"; +#endif +#ifdef ESHUTDOWN + case ESHUTDOWN: return "ESHUTDOWN"; +#endif +#ifdef ESOCKTNOSUPPORT + case ESOCKTNOSUPPORT: return "ESOCKTNOSUPPORT"; +#endif +#ifdef ESPIPE + case ESPIPE: return "ESPIPE"; +#endif +#ifdef ESRCH + case ESRCH: return "ESRCH"; +#endif +#ifdef ESRMNT + case ESRMNT: return "ESRMNT"; +#endif +#ifdef ESTALE + case ESTALE: return "ESTALE"; +#endif +#ifdef ESUCCESS + case ESUCCESS: return "ESUCCESS"; +#endif +#ifdef ETIME + case ETIME: return "ETIME"; +#endif +#ifdef ETIMEDOUT + case ETIMEDOUT: return "ETIMEDOUT"; +#endif +#ifdef ETOOMANYREFS + case ETOOMANYREFS: return "ETOOMANYREFS"; +#endif +#ifdef ETXTBSY + case ETXTBSY: return "ETXTBSY"; +#endif +#ifdef EUCLEAN + case EUCLEAN: return "EUCLEAN"; +#endif +#ifdef EUNATCH + case EUNATCH: return "EUNATCH"; +#endif +#ifdef EUSERS + case EUSERS: return "EUSERS"; +#endif +#ifdef EVERSION + case EVERSION: return "EVERSION"; +#endif +#if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN)) + case EWOULDBLOCK: return "EWOULDBLOCK"; +#endif +#ifdef EXDEV + case EXDEV: return "EXDEV"; +#endif +#ifdef EXFULL + case EXFULL: return "EXFULL"; +#endif + } + return "unknown error"; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_SignalId -- + * + * Return a textual identifier for a signal number. + * + * Results: + * This procedure returns a machine-readable textual identifier + * that corresponds to sig. The identifier is the same as the + * #define name in signal.h. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +unsigned char * +Tcl_SignalId(sig) + int sig; /* Number of signal. */ +{ + switch (sig) { +#ifdef SIGABRT + case SIGABRT: return "SIGABRT"; +#endif +#ifdef SIGALRM + case SIGALRM: return "SIGALRM"; +#endif +#ifdef SIGBUS + case SIGBUS: return "SIGBUS"; +#endif +#ifdef SIGCHLD + case SIGCHLD: return "SIGCHLD"; +#endif +#if defined(SIGCLD) && (!defined(SIGCHLD) || (SIGCLD != SIGCHLD)) + case SIGCLD: return "SIGCLD"; +#endif +#ifdef SIGCONT + case SIGCONT: return "SIGCONT"; +#endif +#if defined(SIGEMT) && (!defined(SIGXCPU) || (SIGEMT != SIGXCPU)) + case SIGEMT: return "SIGEMT"; +#endif +#ifdef SIGFPE + case SIGFPE: return "SIGFPE"; +#endif +#ifdef SIGHUP + case SIGHUP: return "SIGHUP"; +#endif +#ifdef SIGILL + case SIGILL: return "SIGILL"; +#endif +#ifdef SIGINT + case SIGINT: return "SIGINT"; +#endif +#ifdef SIGIO + case SIGIO: return "SIGIO"; +#endif +#if defined(SIGIOT) && (!defined(SIGABRT) || (SIGIOT != SIGABRT)) + case SIGIOT: return "SIGIOT"; +#endif +#ifdef SIGKILL + case SIGKILL: return "SIGKILL"; +#endif +#if defined(SIGLOST) && (!defined(SIGIOT) || (SIGLOST != SIGIOT)) && (!defined(SIGURG) || (SIGLOST != SIGURG)) + case SIGLOST: return "SIGLOST"; +#endif +#ifdef SIGPIPE + case SIGPIPE: return "SIGPIPE"; +#endif +#if defined(SIGPOLL) && (!defined(SIGIO) || (SIGPOLL != SIGIO)) + case SIGPOLL: return "SIGPOLL"; +#endif +#ifdef SIGPROF + case SIGPROF: return "SIGPROF"; +#endif +#if defined(SIGPWR) && (!defined(SIGXFSZ) || (SIGPWR != SIGXFSZ)) + case SIGPWR: return "SIGPWR"; +#endif +#ifdef SIGQUIT + case SIGQUIT: return "SIGQUIT"; +#endif +#ifdef SIGSEGV + case SIGSEGV: return "SIGSEGV"; +#endif +#ifdef SIGSTOP + case SIGSTOP: return "SIGSTOP"; +#endif +#ifdef SIGSYS + case SIGSYS: return "SIGSYS"; +#endif +#ifdef SIGTERM + case SIGTERM: return "SIGTERM"; +#endif +#ifdef SIGTRAP + case SIGTRAP: return "SIGTRAP"; +#endif +#ifdef SIGTSTP + case SIGTSTP: return "SIGTSTP"; +#endif +#ifdef SIGTTIN + case SIGTTIN: return "SIGTTIN"; +#endif +#ifdef SIGTTOU + case SIGTTOU: return "SIGTTOU"; +#endif +#if defined(SIGURG) && (!defined(SIGIO) || (SIGURG != SIGIO)) + case SIGURG: return "SIGURG"; +#endif +#ifdef SIGUSR1 + case SIGUSR1: return "SIGUSR1"; +#endif +#ifdef SIGUSR2 + case SIGUSR2: return "SIGUSR2"; +#endif +#ifdef SIGVTALRM + case SIGVTALRM: return "SIGVTALRM"; +#endif +#ifdef SIGWINCH + case SIGWINCH: return "SIGWINCH"; +#endif +#ifdef SIGXCPU + case SIGXCPU: return "SIGXCPU"; +#endif +#ifdef SIGXFSZ + case SIGXFSZ: return "SIGXFSZ"; +#endif + } + return "unknown signal"; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_SignalMsg -- + * + * Return a human-readable message describing a signal. + * + * Results: + * This procedure returns a string describing sig that should + * make sense to a human. It may not be easy for a machine + * to parse. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +unsigned char * +Tcl_SignalMsg(sig) + int sig; /* Number of signal. */ +{ + switch (sig) { +#ifdef SIGABRT + case SIGABRT: return "SIGABRT"; +#endif +#ifdef SIGALRM + case SIGALRM: return "alarm clock"; +#endif +#ifdef SIGBUS + case SIGBUS: return "bus error"; +#endif +#ifdef SIGCHLD + case SIGCHLD: return "child status changed"; +#endif +#if defined(SIGCLD) && (!defined(SIGCHLD) || (SIGCLD != SIGCHLD)) + case SIGCLD: return "child status changed"; +#endif +#ifdef SIGCONT + case SIGCONT: return "continue after stop"; +#endif +#if defined(SIGEMT) && (!defined(SIGXCPU) || (SIGEMT != SIGXCPU)) + case SIGEMT: return "EMT instruction"; +#endif +#ifdef SIGFPE + case SIGFPE: return "floating-point exception"; +#endif +#ifdef SIGHUP + case SIGHUP: return "hangup"; +#endif +#ifdef SIGILL + case SIGILL: return "illegal instruction"; +#endif +#ifdef SIGINT + case SIGINT: return "interrupt"; +#endif +#ifdef SIGIO + case SIGIO: return "input/output possible on file"; +#endif +#if defined(SIGIOT) && (!defined(SIGABRT) || (SIGABRT != SIGIOT)) + case SIGIOT: return "IOT instruction"; +#endif +#ifdef SIGKILL + case SIGKILL: return "kill signal"; +#endif +#if defined(SIGLOST) && (!defined(SIGIOT) || (SIGLOST != SIGIOT)) && (!defined(SIGURG) || (SIGLOST != SIGURG)) + case SIGLOST: return "resource lost"; +#endif +#ifdef SIGPIPE + case SIGPIPE: return "write on pipe with no readers"; +#endif +#if defined(SIGPOLL) && (!defined(SIGIO) || (SIGPOLL != SIGIO)) + case SIGPOLL: return "input/output possible on file"; +#endif +#ifdef SIGPROF + case SIGPROF: return "profiling alarm"; +#endif +#if defined(SIGPWR) && (!defined(SIGXFSZ) || (SIGPWR != SIGXFSZ)) + case SIGPWR: return "power-fail restart"; +#endif +#ifdef SIGQUIT + case SIGQUIT: return "quit signal"; +#endif +#ifdef SIGSEGV + case SIGSEGV: return "segmentation violation"; +#endif +#ifdef SIGSTOP + case SIGSTOP: return "stop"; +#endif +#ifdef SIGSYS + case SIGSYS: return "bad argument to system call"; +#endif +#ifdef SIGTERM + case SIGTERM: return "software termination signal"; +#endif +#ifdef SIGTRAP + case SIGTRAP: return "trace trap"; +#endif +#ifdef SIGTSTP + case SIGTSTP: return "stop signal from tty"; +#endif +#ifdef SIGTTIN + case SIGTTIN: return "background tty read"; +#endif +#ifdef SIGTTOU + case SIGTTOU: return "background tty write"; +#endif +#if defined(SIGURG) && (!defined(SIGIO) || (SIGURG != SIGIO)) + case SIGURG: return "urgent I/O condition"; +#endif +#ifdef SIGUSR1 + case SIGUSR1: return "user-defined signal 1"; +#endif +#ifdef SIGUSR2 + case SIGUSR2: return "user-defined signal 2"; +#endif +#ifdef SIGVTALRM + case SIGVTALRM: return "virtual time alarm"; +#endif +#ifdef SIGWINCH + case SIGWINCH: return "window changed"; +#endif +#ifdef SIGXCPU + case SIGXCPU: return "exceeded CPU time limit"; +#endif +#ifdef SIGXFSZ + case SIGXFSZ: return "exceeded file size limit"; +#endif + } + return "unknown signal"; +} diff --git a/src/libtcl/tcluxutl.c b/src/libtcl/tcluxutl.c new file mode 100644 index 0000000..f7b75bd --- /dev/null +++ b/src/libtcl/tcluxutl.c @@ -0,0 +1,1016 @@ +/* + * tclUnixUtil.c -- + * + * This file contains a collection of utility procedures that + * are present in the Tcl's UNIX core but not in the generic + * core. For example, they do file manipulation and process + * manipulation. + * + * The Tcl_Fork and Tcl_WaitPids procedures are based on code + * contributed by Karl Lehenbauer, Mark Diekhans and Peter + * da Silva. + * + * Copyright 1991 Regents of the University of California + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without + * fee is hereby granted, provided that this copyright + * notice appears in all copies. The University of California + * makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without + * express or implied warranty. + */ +#include "internal.h" +#include +#include +#include +#include +#include +#ifdef CROSS +# include +#else +# include +#endif + +/* + * Data structures of the following type are used by Tcl_Fork and + * Tcl_WaitPids to keep track of child processes. + */ +#define WAIT_STATUS_TYPE int + +typedef struct { + int pid; /* Process id of child. */ + WAIT_STATUS_TYPE status; /* Status returned when child exited or + * suspended. */ + int flags; /* Various flag bits; see below for + * definitions. */ +} WaitInfo; + +/* + * Flag bits in WaitInfo structures: + * + * WI_READY - Non-zero means process has exited or + * suspended since it was forked or last + * returned by Tcl_WaitPids. + * WI_DETACHED - Non-zero means no-one cares about the + * process anymore. Ignore it until it + * exits, then forget about it. + */ + +#define WI_READY 1 +#define WI_DETACHED 2 + +static WaitInfo *waitTable = NULL; +static int waitTableSize = 0; /* Total number of entries available in + * waitTable. */ +static int waitTableUsed = 0; /* Number of entries in waitTable that + * are actually in use right now. Active + * entries are always at the beginning + * of the table. */ +#define WAIT_TABLE_GROW_BY 4 + +/* + *---------------------------------------------------------------------- + * + * Tcl_EvalFile -- + * + * Read in a file and process the entire file as one gigantic + * Tcl command. + * + * Results: + * A standard Tcl result, which is either the result of executing + * the file or an error indicating why the file couldn't be read. + * + * Side effects: + * Depends on the commands in the file. + * + *---------------------------------------------------------------------- + */ + +int +Tcl_EvalFile(interp, fileName) + Tcl_Interp *interp; /* Interpreter in which to process file. */ + unsigned char *fileName; /* Name of file to process. Tilde-substitution + * will be performed on this name. */ +{ + int fileId, result; + struct stat statBuf; + unsigned char *cmdBuffer, *end, *oldScriptFile; + Interp *iPtr = (Interp *) interp; + + oldScriptFile = iPtr->scriptFile; + iPtr->scriptFile = fileName; + fileName = Tcl_TildeSubst(interp, fileName); + if (fileName == NULL) { + goto error; + } + fileId = open(fileName, O_RDONLY, 0); + if (fileId < 0) { + Tcl_AppendResult(interp, "couldn't read file \"", fileName, + "\": ", Tcl_UnixError(interp), (char *) NULL); + goto error; + } + if (fstat(fileId, &statBuf) == -1) { + Tcl_AppendResult(interp, "couldn't stat file \"", fileName, + "\": ", Tcl_UnixError(interp), (char *) NULL); + close(fileId); + goto error; + } + cmdBuffer = (unsigned char *) malloc((unsigned) statBuf.st_size+1); + if (read(fileId, cmdBuffer, (int) statBuf.st_size) != statBuf.st_size) { + Tcl_AppendResult(interp, "error in reading file \"", fileName, + "\": ", Tcl_UnixError(interp), (char *) NULL); + close(fileId); + free(cmdBuffer); + goto error; + } + if (close(fileId) != 0) { + Tcl_AppendResult(interp, "error closing file \"", fileName, + "\": ", Tcl_UnixError(interp), (char *) NULL); + free(cmdBuffer); + goto error; + } + cmdBuffer[statBuf.st_size] = 0; + result = Tcl_Eval(interp, cmdBuffer, 0, &end); + if (result == TCL_RETURN) { + result = TCL_OK; + } + if (result == TCL_ERROR) { + char msg[200]; + + /* + * Record information telling where the error occurred. + */ + + sprintf(msg, "\n (file \"%.150s\" line %d)", fileName, + interp->errorLine); + Tcl_AddErrorInfo(interp, msg); + } + free(cmdBuffer); + iPtr->scriptFile = oldScriptFile; + return result; + + error: + iPtr->scriptFile = oldScriptFile; + return TCL_ERROR; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_Fork -- + * + * Create a new process using the vfork system call, and keep + * track of it for "safe" waiting with Tcl_WaitPids. + * + * Results: + * The return value is the value returned by the vfork system + * call (0 means child, > 0 means parent (value is child id), + * < 0 means error). + * + * Side effects: + * A new process is created, and an entry is added to an internal + * table of child processes if the process is created successfully. + * + *---------------------------------------------------------------------- + */ + +int +Tcl_Fork() +{ + WaitInfo *waitPtr; + pid_t pid; + + /* + * Disable SIGPIPE signals: if they were allowed, this process + * might go away unexpectedly if children misbehave. This code + * can potentially interfere with other application code that + * expects to handle SIGPIPEs; what's really needed is an + * arbiter for signals to allow them to be "shared". + */ + + if (waitTable == NULL) { + (void) signal(SIGPIPE, SIG_IGN); + } + + /* + * Enlarge the wait table if there isn't enough space for a new + * entry. + */ + + if (waitTableUsed == waitTableSize) { + int newSize; + WaitInfo *newWaitTable; + + newSize = waitTableSize + WAIT_TABLE_GROW_BY; + newWaitTable = (WaitInfo *) malloc((unsigned) + (newSize * sizeof(WaitInfo))); + memcpy((void *) newWaitTable, (void *) waitTable, + (waitTableSize * sizeof(WaitInfo))); + if (waitTable != NULL) { + free((char *) waitTable); + } + waitTable = newWaitTable; + waitTableSize = newSize; + } + + /* + * Make a new process and enter it into the table if the fork + * is successful. + */ + + waitPtr = &waitTable[waitTableUsed]; + pid = fork(); + if (pid > 0) { + waitPtr->pid = pid; + waitPtr->flags = 0; + waitTableUsed++; + } + return pid; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_WaitPids -- + * + * This procedure is used to wait for one or more processes created + * by Tcl_Fork to exit or suspend. It records information about + * all processes that exit or suspend, even those not waited for, + * so that later waits for them will be able to get the status + * information. + * + * Results: + * -1 is returned if there is an error in the wait kernel call. + * Otherwise the pid of an exited/suspended process from *pidPtr + * is returned and *statusPtr is set to the status value returned + * by the wait kernel call. + * + * Side effects: + * Doesn't return until one of the pids at *pidPtr exits or suspends. + * + *---------------------------------------------------------------------- + */ + +int +Tcl_WaitPids(numPids, pidPtr, statusPtr) + int numPids; /* Number of pids to wait on: gives size + * of array pointed to by pidPtr. */ + int *pidPtr; /* Pids to wait on: return when one of + * these processes exits or suspends. */ + int *statusPtr; /* Wait status is returned here. */ +{ + int i, count, pid; + register WaitInfo *waitPtr; + int anyProcesses; + WAIT_STATUS_TYPE status; + + while (1) { + /* + * Scan the table of child processes to see if one of the + * specified children has already exited or suspended. If so, + * remove it from the table and return its status. + */ + + anyProcesses = 0; + for (waitPtr = waitTable, count = waitTableUsed; + count > 0; waitPtr++, count--) { + for (i = 0; i < numPids; i++) { + if (pidPtr[i] != waitPtr->pid) { + continue; + } + anyProcesses = 1; + if (waitPtr->flags & WI_READY) { + *statusPtr = *((int *) &waitPtr->status); + pid = waitPtr->pid; + if (WIFEXITED(waitPtr->status) + || WIFSIGNALED(waitPtr->status)) { + *waitPtr = waitTable[waitTableUsed-1]; + waitTableUsed--; + } else { + waitPtr->flags &= ~WI_READY; + } + return pid; + } + } + } + + /* + * Make sure that the caller at least specified one valid + * process to wait for. + */ + + if (!anyProcesses) { + errno = ECHILD; + return -1; + } + + /* + * Wait for a process to exit or suspend, then update its + * entry in the table and go back to the beginning of the + * loop to see if it's one of the desired processes. + */ + + pid = wait(&status); + if (pid < 0) { + return pid; + } + for (waitPtr = waitTable, count = waitTableUsed; ; + waitPtr++, count--) { + if (count == 0) { + break; /* Ignore unknown processes. */ + } + if (pid != waitPtr->pid) { + continue; + } + + /* + * If the process has been detached, then ignore anything + * other than an exit, and drop the entry on exit. + */ + + if (waitPtr->flags & WI_DETACHED) { + if (WIFEXITED(status) || WIFSIGNALED(status)) { + *waitPtr = waitTable[waitTableUsed-1]; + waitTableUsed--; + } + } else { + waitPtr->status = status; + waitPtr->flags |= WI_READY; + } + break; + } + } +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_DetachPids -- + * + * This procedure is called to indicate that one or more child + * processes have been placed in background and are no longer + * cared about. They should be ignored in future calls to + * Tcl_WaitPids. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +void +Tcl_DetachPids(numPids, pidPtr) + int numPids; /* Number of pids to detach: gives size + * of array pointed to by pidPtr. */ + int *pidPtr; /* Array of pids to detach: must have + * been created by Tcl_Fork. */ +{ + register WaitInfo *waitPtr; + int i, count, pid; + + for (i = 0; i < numPids; i++) { + pid = pidPtr[i]; + for (waitPtr = waitTable, count = waitTableUsed; + count > 0; waitPtr++, count--) { + if (pid != waitPtr->pid) { + continue; + } + + /* + * If the process has already exited then destroy its + * table entry now. + */ + + if ((waitPtr->flags & WI_READY) && (WIFEXITED(waitPtr->status) + || WIFSIGNALED(waitPtr->status))) { + *waitPtr = waitTable[waitTableUsed-1]; + waitTableUsed--; + } else { + waitPtr->flags |= WI_DETACHED; + } + goto nextPid; + } + fprintf (stderr, "Tcl_Detach couldn't find process\n"); + abort(); +nextPid: + continue; + } +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_CreatePipeline -- + * + * Given an argc/argv array, instantiate a pipeline of processes + * as described by the argv. + * + * Results: + * The return value is a count of the number of new processes + * created, or -1 if an error occurred while creating the pipeline. + * *pidArrayPtr is filled in with the address of a dynamically + * allocated array giving the ids of all of the processes. It + * is up to the caller to free this array when it isn't needed + * anymore. If inPipePtr is non-NULL, *inPipePtr is filled in + * with the file id for the input pipe for the pipeline (if any): + * the caller must eventually close this file. If outPipePtr + * isn't NULL, then *outPipePtr is filled in with the file id + * for the output pipe from the pipeline: the caller must close + * this file. If errFilePtr isn't NULL, then *errFilePtr is filled + * with a file id that may be used to read error output after the + * pipeline completes. + * + * Side effects: + * Processes and pipes are created. + * + *---------------------------------------------------------------------- + */ + +int +Tcl_CreatePipeline(interp, argc, argv, pidArrayPtr, inPipePtr, + outPipePtr, errFilePtr) + Tcl_Interp *interp; /* Interpreter to use for error reporting. */ + int argc; /* Number of entries in argv. */ + unsigned char **argv; /* Array of strings describing commands in + * pipeline plus I/O redirection with <, + * <<, and >. Argv[argc] must be NULL. */ + int **pidArrayPtr; /* Word at *pidArrayPtr gets filled in with + * address of array of pids for processes + * in pipeline (first pid is first process + * in pipeline). */ + int *inPipePtr; /* If non-NULL, input to the pipeline comes + * from a pipe (unless overridden by + * redirection in the command). The file + * id with which to write to this pipe is + * stored at *inPipePtr. -1 means command + * specified its own input source. */ + int *outPipePtr; /* If non-NULL, output to the pipeline goes + * to a pipe, unless overriden by redirection + * in the command. The file id with which to + * read frome this pipe is stored at + * *outPipePtr. -1 means command specified + * its own output sink. */ + int *errFilePtr; /* If non-NULL, all stderr output from the + * pipeline will go to a temporary file + * created here, and a descriptor to read + * the file will be left at *errFilePtr. + * The file will be removed already, so + * closing this descriptor will be the end + * of the file. If this is NULL, then + * all stderr output goes to our stderr. */ +{ + int *pidPtr = NULL; /* Points to malloc-ed array holding all + * the pids of child processes. */ + int numPids = 0; /* Actual number of processes that exist + * at *pidPtr right now. */ + int cmdCount; /* Count of number of distinct commands + * found in argc/argv. */ + char *input = NULL; /* Describes input for pipeline, depending + * on "inputFile". NULL means take input + * from stdin/pipe. */ + int inputFile = 0; /* Non-zero means input is name of input + * file. Zero means input holds actual + * text to be input to command. */ + char *output = NULL; /* Holds name of output file to pipe to, + * or NULL if output goes to stdout/pipe. */ + int inputId = -1; /* Readable file id input to current command in + * pipeline (could be file or pipe). -1 + * means use stdin. */ + int outputId = -1; /* Writable file id for output from current + * command in pipeline (could be file or pipe). + * -1 means use stdout. */ + int errorId = -1; /* Writable file id for all standard error + * output from all commands in pipeline. -1 + * means use stderr. */ + int lastOutputId = -1; /* Write file id for output from last command + * in pipeline (could be file or pipe). + * -1 means use stdout. */ + int pipeIds[2]; /* File ids for pipe that's being created. */ + int firstArg, lastArg; /* Indexes of first and last arguments in + * current command. */ + int lastBar; + char *execName; + int i, j, pid; + + if (inPipePtr != NULL) { + *inPipePtr = -1; + } + if (outPipePtr != NULL) { + *outPipePtr = -1; + } + if (errFilePtr != NULL) { + *errFilePtr = -1; + } + pipeIds[0] = pipeIds[1] = -1; + + /* + * First, scan through all the arguments to figure out the structure + * of the pipeline. Count the number of distinct processes (it's the + * number of "|" arguments). If there are "<", "<<", or ">" arguments + * then make note of input and output redirection and remove these + * arguments and the arguments that follow them. + */ + + cmdCount = 1; + lastBar = -1; + for (i = 0; i < argc; i++) { + if ((argv[i][0] == '|') && ((argv[i][1] == 0))) { + if ((i == (lastBar+1)) || (i == (argc-1))) { + interp->result = "illegal use of | in command"; + return -1; + } + lastBar = i; + cmdCount++; + continue; + } else if (argv[i][0] == '<') { + if (argv[i][1] == 0) { + input = argv[i+1]; + inputFile = 1; + } else if ((argv[i][1] == '<') && (argv[i][2] == 0)) { + input = argv[i+1]; + inputFile = 0; + } else { + continue; + } + } else if ((argv[i][0] == '>') && (argv[i][1] == 0)) { + output = argv[i+1]; + } else { + continue; + } + if (i >= (argc-1)) { + Tcl_AppendResult(interp, "can't specify \"", argv[i], + "\" as last word in command", (char *) NULL); + return -1; + } + for (j = i+2; j < argc; j++) { + argv[j-2] = argv[j]; + } + argc -= 2; + i--; /* Process new arg from same position. */ + } + if (argc == 0) { + interp->result = "didn't specify command to execute"; + return -1; + } + + /* + * Set up the redirected input source for the pipeline, if + * so requested. + */ + + if (input != NULL) { + if (!inputFile) { + /* + * Immediate data in command. Create temporary file and + * put data into file. + */ + +# define TMP_STDIN_NAME "/tmp/tcl.in.XXXXXX" + char inName[sizeof(TMP_STDIN_NAME) + 1]; + int length; + + strcpy(inName, TMP_STDIN_NAME); + mktemp(inName); + inputId = open(inName, O_RDWR|O_CREAT|O_TRUNC, 0600); + if (inputId < 0) { + Tcl_AppendResult(interp, + "couldn't create input file for command: ", + Tcl_UnixError(interp), (char *) NULL); + goto error; + } + length = strlen(input); + if (write(inputId, input, length) != length) { + Tcl_AppendResult(interp, + "couldn't write file input for command: ", + Tcl_UnixError(interp), (char *) NULL); + goto error; + } + if ((lseek(inputId, 0L, 0) == -1) || (unlink(inName) == -1)) { + Tcl_AppendResult(interp, + "couldn't reset or remove input file for command: ", + Tcl_UnixError(interp), (char *) NULL); + goto error; + } + } else { + /* + * File redirection. Just open the file. + */ + + inputId = open(input, O_RDONLY, 0); + if (inputId < 0) { + Tcl_AppendResult(interp, + "couldn't read file \"", input, "\": ", + Tcl_UnixError(interp), (char *) NULL); + goto error; + } + } + } else if (inPipePtr != NULL) { + if (pipe(pipeIds) != 0) { + Tcl_AppendResult(interp, + "couldn't create input pipe for command: ", + Tcl_UnixError(interp), (char *) NULL); + goto error; + } + inputId = pipeIds[0]; + *inPipePtr = pipeIds[1]; + pipeIds[0] = pipeIds[1] = -1; + } + + /* + * Set up the redirected output sink for the pipeline from one + * of two places, if requested. + */ + + if (output != NULL) { + /* + * Output is to go to a file. + */ + + lastOutputId = open(output, O_WRONLY|O_CREAT|O_TRUNC, 0666); + if (lastOutputId < 0) { + Tcl_AppendResult(interp, + "couldn't write file \"", output, "\": ", + Tcl_UnixError(interp), (char *) NULL); + goto error; + } + } else if (outPipePtr != NULL) { + /* + * Output is to go to a pipe. + */ + + if (pipe(pipeIds) != 0) { + Tcl_AppendResult(interp, + "couldn't create output pipe: ", + Tcl_UnixError(interp), (char *) NULL); + goto error; + } + lastOutputId = pipeIds[1]; + *outPipePtr = pipeIds[0]; + pipeIds[0] = pipeIds[1] = -1; + } + + /* + * Set up the standard error output sink for the pipeline, if + * requested. Use a temporary file which is opened, then deleted. + * Could potentially just use pipe, but if it filled up it could + * cause the pipeline to deadlock: we'd be waiting for processes + * to complete before reading stderr, and processes couldn't complete + * because stderr was backed up. + */ + + if (errFilePtr != NULL) { +# define TMP_STDERR_NAME "/tmp/tcl.err.XXXXXX" + char errName[sizeof(TMP_STDERR_NAME) + 1]; + + strcpy(errName, TMP_STDERR_NAME); + mktemp(errName); + errorId = open(errName, O_WRONLY|O_CREAT|O_TRUNC, 0600); + if (errorId < 0) { + errFileError: + Tcl_AppendResult(interp, + "couldn't create error file for command: ", + Tcl_UnixError(interp), (char *) NULL); + goto error; + } + *errFilePtr = open(errName, O_RDONLY, 0); + if (*errFilePtr < 0) { + goto errFileError; + } + if (unlink(errName) == -1) { + Tcl_AppendResult(interp, + "couldn't remove error file for command: ", + Tcl_UnixError(interp), (char *) NULL); + goto error; + } + } + + /* + * Scan through the argc array, forking off a process for each + * group of arguments between "|" arguments. + */ + + pidPtr = (int *) malloc((unsigned) (cmdCount * sizeof(int))); + for (i = 0; i < numPids; i++) { + pidPtr[i] = -1; + } + for (firstArg = 0; firstArg < argc; numPids++, firstArg = lastArg+1) { + for (lastArg = firstArg; lastArg < argc; lastArg++) { + if ((argv[lastArg][0] == '|') && (argv[lastArg][1] == 0)) { + break; + } + } + argv[lastArg] = NULL; + if (lastArg == argc) { + outputId = lastOutputId; + } else { + if (pipe(pipeIds) != 0) { + Tcl_AppendResult(interp, "couldn't create pipe: ", + Tcl_UnixError(interp), (char *) NULL); + goto error; + } + outputId = pipeIds[1]; + } + execName = Tcl_TildeSubst(interp, argv[firstArg]); + pid = Tcl_Fork(); + if (pid == -1) { + Tcl_AppendResult(interp, "couldn't fork child process: ", + Tcl_UnixError(interp), (char *) NULL); + goto error; + } + if (pid == 0) { + char errSpace[200]; + + if (((inputId != -1) && (dup2(inputId, 0) == -1)) + || ((outputId != -1) && (dup2(outputId, 1) == -1)) + || ((errorId != -1) && (dup2(errorId, 2) == -1))) { + char *err; + err = "forked process couldn't set up input/output\n"; + write(errorId < 0 ? 2 : errorId, err, strlen(err)); + _exit(1); + } + for (i = 3; (i <= outputId) || (i <= inputId) || (i <= errorId); + i++) { + close(i); + } + execvp(execName, (char**) &argv[firstArg]); + sprintf(errSpace, "couldn't find \"%.150s\" to execute\n", + argv[firstArg]); + write(2, errSpace, strlen(errSpace)); + _exit(1); + } else { + pidPtr[numPids] = pid; + } + + /* + * Close off our copies of file descriptors that were set up for + * this child, then set up the input for the next child. + */ + + if (inputId != -1) { + close(inputId); + } + if (outputId != -1) { + close(outputId); + } + inputId = pipeIds[0]; + pipeIds[0] = pipeIds[1] = -1; + } + *pidArrayPtr = pidPtr; + + /* + * All done. Cleanup open files lying around and then return. + */ + +cleanup: + if (inputId != -1) { + close(inputId); + } + if (lastOutputId != -1) { + close(lastOutputId); + } + if (errorId != -1) { + close(errorId); + } + return numPids; + + /* + * An error occurred. There could have been extra files open, such + * as pipes between children. Clean them all up. Detach any child + * processes that have been created. + */ + + error: + if ((inPipePtr != NULL) && (*inPipePtr != -1)) { + close(*inPipePtr); + *inPipePtr = -1; + } + if ((outPipePtr != NULL) && (*outPipePtr != -1)) { + close(*outPipePtr); + *outPipePtr = -1; + } + if ((errFilePtr != NULL) && (*errFilePtr != -1)) { + close(*errFilePtr); + *errFilePtr = -1; + } + if (pipeIds[0] != -1) { + close(pipeIds[0]); + } + if (pipeIds[1] != -1) { + close(pipeIds[1]); + } + if (pidPtr != NULL) { + for (i = 0; i < numPids; i++) { + if (pidPtr[i] != -1) { + Tcl_DetachPids(1, &pidPtr[i]); + } + } + free((char *) pidPtr); + } + numPids = -1; + goto cleanup; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_UnixError -- + * + * This procedure is typically called after UNIX kernel calls + * return errors. It stores machine-readable information about + * the error in $errorCode returns an information string for + * the caller's use. + * + * Results: + * The return value is a human-readable string describing the + * error, as returned by strerror. + * + * Side effects: + * The global variable $errorCode is reset. + * + *---------------------------------------------------------------------- + */ + +unsigned char * +Tcl_UnixError(interp) + Tcl_Interp *interp; /* Interpreter whose $errorCode variable + * is to be changed. */ +{ + char *id; + const char *msg; + + id = Tcl_ErrnoId(); + msg = strerror(errno); + Tcl_SetErrorCode(interp, "UNIX", id, msg, (char *) NULL); + return (unsigned char *) msg; +} + +/* + *---------------------------------------------------------------------- + * + * TclMakeFileTable -- + * + * Create or enlarge the file table for the interpreter, so that + * there is room for a given index. + * + * Results: + * None. + * + * Side effects: + * The file table for iPtr will be created if it doesn't exist + * (and entries will be added for stdin, stdout, and stderr). + * If it already exists, then it will be grown if necessary. + * + *---------------------------------------------------------------------- + */ + +void +TclMakeFileTable(iPtr, index) + Interp *iPtr; /* Interpreter whose table of files is + * to be manipulated. */ + int index; /* Make sure table is large enough to + * hold at least this index. */ +{ + /* + * If the table doesn't even exist, then create it and initialize + * entries for standard files. + */ + + if (iPtr->numFiles == 0) { + OpenFile *filePtr; + int i; + + if (index < 2) { + iPtr->numFiles = 3; + } else { + iPtr->numFiles = index+1; + } + iPtr->filePtrArray = (OpenFile **) malloc((unsigned) + ((iPtr->numFiles)*sizeof(OpenFile *))); + for (i = iPtr->numFiles-1; i >= 0; i--) { + iPtr->filePtrArray[i] = NULL; + } + + filePtr = (OpenFile *) malloc(sizeof(OpenFile)); + filePtr->f = stdin; + filePtr->f2 = NULL; + filePtr->readable = 1; + filePtr->writable = 0; + filePtr->numPids = 0; + filePtr->pidPtr = NULL; + filePtr->errorId = -1; + iPtr->filePtrArray[0] = filePtr; + + filePtr = (OpenFile *) malloc(sizeof(OpenFile)); + filePtr->f = stdout; + filePtr->f2 = NULL; + filePtr->readable = 0; + filePtr->writable = 1; + filePtr->numPids = 0; + filePtr->pidPtr = NULL; + filePtr->errorId = -1; + iPtr->filePtrArray[1] = filePtr; + + filePtr = (OpenFile *) malloc(sizeof(OpenFile)); + filePtr->f = stderr; + filePtr->f2 = NULL; + filePtr->readable = 0; + filePtr->writable = 1; + filePtr->numPids = 0; + filePtr->pidPtr = NULL; + filePtr->errorId = -1; + iPtr->filePtrArray[2] = filePtr; + } else if (index >= iPtr->numFiles) { + int newSize; + OpenFile **newPtrArray; + int i; + + newSize = index+1; + newPtrArray = (OpenFile **) malloc((unsigned) + ((newSize)*sizeof(OpenFile *))); + memcpy((void *) newPtrArray, (void *) iPtr->filePtrArray, + iPtr->numFiles*sizeof(OpenFile *)); + for (i = iPtr->numFiles; i < newSize; i++) { + newPtrArray[i] = NULL; + } + free((char *) iPtr->filePtrArray); + iPtr->numFiles = newSize; + iPtr->filePtrArray = newPtrArray; + } +} + +/* + *---------------------------------------------------------------------- + * + * TclGetOpenFile -- + * + * Given a string identifier for an open file, find the corresponding + * open file structure, if there is one. + * + * Results: + * A standard Tcl return value. If the open file is successfully + * located, *filePtrPtr is modified to point to its structure. + * If TCL_ERROR is returned then interp->result contains an error + * message. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +TclGetOpenFile(interp, string, filePtrPtr) + Tcl_Interp *interp; /* Interpreter in which to find file. */ + unsigned char *string; /* String that identifies file. */ + OpenFile **filePtrPtr; /* Address of word in which to store pointer + * to structure about open file. */ +{ + int fd = 0; /* Initial value needed only to stop compiler + * warnings. */ + Interp *iPtr = (Interp *) interp; + + if ((string[0] == 'f') && (string[1] == 'i') && (string[2] == 'l') + & (string[3] == 'e')) { + unsigned char *end; + + fd = strtoul(string+4, &end, 10); + if ((end == string+4) || (*end != 0)) { + goto badId; + } + } else if ((string[0] == 's') && (string[1] == 't') + && (string[2] == 'd')) { + if (strcmp(string+3, "in") == 0) { + fd = 0; + } else if (strcmp(string+3, "out") == 0) { + fd = 1; + } else if (strcmp(string+3, "err") == 0) { + fd = 2; + } else { + goto badId; + } + } else { + badId: + Tcl_AppendResult(interp, "bad file identifier \"", string, + "\"", (char *) NULL); + return TCL_ERROR; + } + + if (fd >= iPtr->numFiles) { + if ((iPtr->numFiles == 0) && (fd <= 2)) { + TclMakeFileTable(iPtr, fd); + } else { + notOpen: + Tcl_AppendResult(interp, "file \"", string, "\" isn't open", + (char *) NULL); + return TCL_ERROR; + } + } + if (iPtr->filePtrArray[fd] == NULL) { + goto notOpen; + } + *filePtrPtr = iPtr->filePtrArray[fd]; + return TCL_OK; +} diff --git a/src/libtcl/tclvar.c b/src/libtcl/tclvar.c new file mode 100644 index 0000000..01ffdc2 --- /dev/null +++ b/src/libtcl/tclvar.c @@ -0,0 +1,2254 @@ +/* + * tclVar.c -- + * + * This file contains routines that implement Tcl variables + * (both scalars and arrays). + * + * The implementation of arrays is modelled after an initial + * implementation by Karl Lehenbauer, Mark Diekhans and + * Peter da Silva. + * + * Copyright 1987-1991 Regents of the University of California + * 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. The University of California + * makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without + * express or implied warranty. + */ +#include "internal.h" +#include + +/* + * The strings below are used to indicate what went wrong when a + * variable access is denied. + */ + +static unsigned char *noSuchVar + = (unsigned char*) "no such variable"; +static unsigned char *isArray + = (unsigned char*) "variable is array"; +static unsigned char *needArray + = (unsigned char*) "variable isn't array"; +static unsigned char *noSuchElement + = (unsigned char*) "no such element in array"; +static unsigned char *traceActive + = (unsigned char*) "trace is active on variable"; + +/* + * Forward references to procedures defined later in this file: + */ + +static unsigned char * CallTraces (Interp *iPtr, Var *arrayPtr, + Tcl_HashEntry *hPtr, unsigned char *part1, + unsigned char *part2, int flags); +static void DeleteSearches (Var *arrayVarPtr); +static void DeleteArray (Interp *iPtr, unsigned char *arrayName, + Var *varPtr, int flags); +static Var * NewVar (int space); +static ArraySearch * ParseSearchId (Tcl_Interp *interp, + Var *varPtr, unsigned char *varName, + unsigned char *string); +static void VarErrMsg (Tcl_Interp *interp, + unsigned char *part1, unsigned char *part2, + unsigned char *operation, unsigned char *reason); + +/* + *---------------------------------------------------------------------- + * + * Tcl_GetVar -- + * + * Return the value of a Tcl variable. + * + * Results: + * The return value points to the current value of varName. If + * the variable is not defined or can't be read because of a clash + * in array usage then a NULL pointer is returned and an error + * message is left in interp->result if the TCL_LEAVE_ERR_MSG + * flag is set. Note: the return value is only valid up until + * the next call to Tcl_SetVar or Tcl_SetVar2; if you depend on + * the value lasting longer than that, then make yourself a private + * copy. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +unsigned char * +Tcl_GetVar(interp, varName, flags) + Tcl_Interp *interp; /* Command interpreter in which varName is + * to be looked up. */ + unsigned char *varName; /* Name of a variable in interp. */ + int flags; /* OR-ed combination of TCL_GLOBAL_ONLY + * or TCL_LEAVE_ERR_MSG bits. */ +{ + register unsigned char *p; + + /* + * If varName refers to an array (it ends with a parenthesized + * element name), then handle it specially. + */ + + for (p = varName; *p != '\0'; p++) { + if (*p == '(') { + unsigned char *result; + unsigned char *open = p; + + do { + p++; + } while (*p != '\0'); + p--; + if (*p != ')') { + goto scalar; + } + *open = '\0'; + *p = '\0'; + result = Tcl_GetVar2(interp, varName, open+1, flags); + *open = '('; + *p = ')'; + return result; + } + } + + scalar: + return Tcl_GetVar2(interp, varName, 0, flags); +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_GetVar2 -- + * + * Return the value of a Tcl variable, given a two-part name + * consisting of array name and element within array. + * + * Results: + * The return value points to the current value of the variable + * given by part1 and part2. If the specified variable doesn't + * exist, or if there is a clash in array usage, then NULL is + * returned and a message will be left in interp->result if the + * TCL_LEAVE_ERR_MSG flag is set. Note: the return value is + * only valid up until the next call to Tcl_SetVar or Tcl_SetVar2; + * if you depend on the value lasting longer than that, then make + * yourself a private copy. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +unsigned char * +Tcl_GetVar2(interp, part1, part2, flags) + Tcl_Interp *interp; /* Command interpreter in which variable is + * to be looked up. */ + unsigned char *part1; /* Name of array (if part2 is NULL) or + * name of variable. */ + unsigned char *part2; /* If non-null, gives name of element in + * array. */ + int flags; /* OR-ed combination of TCL_GLOBAL_ONLY + * or TCL_LEAVE_ERR_MSG bits. */ +{ + Tcl_HashEntry *hPtr; + Var *varPtr; + Interp *iPtr = (Interp *) interp; + Var *arrayPtr = 0; + + /* + * Lookup the first name. + */ + + if ((flags & TCL_GLOBAL_ONLY) || (iPtr->varFramePtr == 0)) { + hPtr = Tcl_FindHashEntry(&iPtr->globalTable, part1); + } else { + hPtr = Tcl_FindHashEntry(&iPtr->varFramePtr->varTable, part1); + } + if (hPtr == 0) { + if (flags & TCL_LEAVE_ERR_MSG) { + VarErrMsg(interp, part1, part2, (unsigned char*) "read", noSuchVar); + } + return 0; + } + varPtr = (Var *) Tcl_GetHashValue(hPtr); + if (varPtr->flags & VAR_UPVAR) { + hPtr = varPtr->value.upvarPtr; + varPtr = (Var *) Tcl_GetHashValue(hPtr); + } + + /* + * If this is an array reference, then remember the traces on the array + * and lookup the element within the array. + */ + if (part2 != 0) { + if (varPtr->flags & VAR_UNDEFINED) { + if (flags & TCL_LEAVE_ERR_MSG) { + VarErrMsg(interp, part1, part2, (unsigned char*) "read", noSuchVar); + } + return 0; + } else if (!(varPtr->flags & VAR_ARRAY)) { + if (flags & TCL_LEAVE_ERR_MSG) { + VarErrMsg(interp, part1, part2, (unsigned char*) "read", needArray); + } + return 0; + } + arrayPtr = varPtr; + hPtr = Tcl_FindHashEntry(varPtr->value.tablePtr, part2); + if (hPtr == 0) { + if (flags & TCL_LEAVE_ERR_MSG) { + VarErrMsg(interp, part1, part2, (unsigned char*) "read", noSuchElement); + } + return 0; + } + varPtr = (Var *) Tcl_GetHashValue(hPtr); + } + + /* + * Invoke any traces that have been set for the variable. + */ + + if ((varPtr->tracePtr != 0) + || ((arrayPtr != 0) && (arrayPtr->tracePtr != 0))) { + unsigned char *msg; + + msg = CallTraces(iPtr, arrayPtr, hPtr, part1, part2, + (flags & TCL_GLOBAL_ONLY) | TCL_TRACE_READS); + if (msg != 0) { + VarErrMsg(interp, part1, part2, (unsigned char*) "read", msg); + return 0; + } + + /* + * Watch out! The variable could have gotten re-allocated to + * a larger size. Fortunately the hash table entry will still + * be around. + */ + + varPtr = (Var *) Tcl_GetHashValue(hPtr); + } + if (varPtr->flags & (VAR_UNDEFINED|VAR_UPVAR|VAR_ARRAY)) { + if (flags & TCL_LEAVE_ERR_MSG) { + VarErrMsg(interp, part1, part2, (unsigned char*) "read", noSuchVar); + } + return 0; + } + return varPtr->value.string; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_SetVar -- + * + * Change the value of a variable. + * + * Results: + * Returns a pointer to the malloc'ed string holding the new + * value of the variable. The caller should not modify this + * string. If the write operation was disallowed then NULL + * is returned; if the TCL_LEAVE_ERR_MSG flag is set, then + * an explanatory message will be left in interp->result. + * + * Side effects: + * If varName is defined as a local or global variable in interp, + * its value is changed to newValue. If varName isn't currently + * defined, then a new global variable by that name is created. + * + *---------------------------------------------------------------------- + */ + +unsigned char * +Tcl_SetVar(interp, varName, newValue, flags) + Tcl_Interp *interp; /* Command interpreter in which varName is + * to be looked up. */ + unsigned char *varName; /* Name of a variable in interp. */ + unsigned char *newValue; /* New value for varName. */ + int flags; /* Various flags that tell how to set value: + * any of TCL_GLOBAL_ONLY, TCL_APPEND_VALUE, + * TCL_LIST_ELEMENT, TCL_NO_SPACE, or + * TCL_LEAVE_ERR_MSG. */ +{ + register unsigned char *p; + + /* + * If varName refers to an array (it ends with a parenthesized + * element name), then handle it specially. + */ + + for (p = varName; *p != '\0'; p++) { + if (*p == '(') { + unsigned char *result; + unsigned char *open = p; + + do { + p++; + } while (*p != '\0'); + p--; + if (*p != ')') { + goto scalar; + } + *open = '\0'; + *p = '\0'; + result = Tcl_SetVar2(interp, varName, open+1, newValue, flags); + *open = '('; + *p = ')'; + return result; + } + } + + scalar: + return Tcl_SetVar2(interp, varName, 0, newValue, flags); +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_SetVar2 -- + * + * Given a two-part variable name, which may refer either to a + * scalar variable or an element of an array, change the value + * of the variable. If the named scalar or array or element + * doesn't exist then create one. + * + * Results: + * Returns a pointer to the malloc'ed string holding the new + * value of the variable. The caller should not modify this + * string. If the write operation was disallowed because an + * array was expected but not found (or vice versa), then NULL + * is returned; if the TCL_LEAVE_ERR_MSG flag is set, then + * an explanatory message will be left in interp->result. + * + * Side effects: + * The value of the given variable is set. If either the array + * or the entry didn't exist then a new one is created. + * + *---------------------------------------------------------------------- + */ + +unsigned char * +Tcl_SetVar2(interp, part1, part2, newValue, flags) + Tcl_Interp *interp; /* Command interpreter in which variable is + * to be looked up. */ + unsigned char *part1; /* If part2 is NULL, this is name of scalar + * variable. Otherwise it is name of array. */ + unsigned char *part2; /* Name of an element within array, or NULL. */ + unsigned char *newValue; /* New value for variable. */ + int flags; /* Various flags that tell how to set value: + * any of TCL_GLOBAL_ONLY, TCL_APPEND_VALUE, + * TCL_LIST_ELEMENT, and TCL_NO_SPACE, or + * TCL_LEAVE_ERR_MSG . */ +{ + Tcl_HashEntry *hPtr; + register Var *varPtr = 0; + /* Initial value only used to stop compiler + * from complaining; not really needed. */ + register Interp *iPtr = (Interp *) interp; + int length, new, listFlags; + Var *arrayPtr = 0; + + /* + * Lookup the first name. + */ + + if ((flags & TCL_GLOBAL_ONLY) || (iPtr->varFramePtr == 0)) { + hPtr = Tcl_CreateHashEntry(&iPtr->globalTable, part1, &new); + } else { + hPtr = Tcl_CreateHashEntry(&iPtr->varFramePtr->varTable, + part1, &new); + } + if (!new) { + varPtr = (Var *) Tcl_GetHashValue(hPtr); + if (varPtr->flags & VAR_UPVAR) { + hPtr = varPtr->value.upvarPtr; + varPtr = (Var *) Tcl_GetHashValue(hPtr); + } + } + + /* + * If this is an array reference, then create a new array (if + * needed), remember any traces on the array, and lookup the + * element within the array. + */ + + if (part2 != 0) { + if (new) { + varPtr = NewVar (0); + Tcl_SetHashValue(hPtr, varPtr); + varPtr->flags = VAR_ARRAY; + varPtr->value.tablePtr = (Tcl_HashTable*) + malloc (sizeof(Tcl_HashTable)); + Tcl_InitHashTable (varPtr->value.tablePtr, TCL_STRING_KEYS); + } else { + if (varPtr->flags & VAR_UNDEFINED) { + varPtr->flags = VAR_ARRAY; + varPtr->value.tablePtr = (Tcl_HashTable*) + malloc (sizeof(Tcl_HashTable)); + Tcl_InitHashTable (varPtr->value.tablePtr, TCL_STRING_KEYS); + } else if (!(varPtr->flags & VAR_ARRAY)) { + if (flags & TCL_LEAVE_ERR_MSG) { + VarErrMsg(interp, part1, part2, (unsigned char*) "set", needArray); + } + return 0; + } + arrayPtr = varPtr; + } + hPtr = Tcl_CreateHashEntry(varPtr->value.tablePtr, part2, &new); + } + + /* + * Compute how many bytes will be needed for newValue (leave space + * for a separating space between list elements). + */ + + if (flags & TCL_LIST_ELEMENT) { + length = Tcl_ScanElement(newValue, &listFlags) + 1; + } else { + length = strlen(newValue); + } + + /* + * If the variable doesn't exist then create a new one. If it + * does exist then clear its current value unless this is an + * append operation. + */ + + if (new) { + varPtr = NewVar (length); + Tcl_SetHashValue(hPtr, varPtr); + if ((arrayPtr != 0) && (arrayPtr->searchPtr != 0)) { + DeleteSearches(arrayPtr); + } + } else { + varPtr = (Var *) Tcl_GetHashValue(hPtr); + if (varPtr->flags & VAR_ARRAY) { + if (flags & TCL_LEAVE_ERR_MSG) { + VarErrMsg(interp, part1, part2, (unsigned char*) "set", isArray); + } + return 0; + } + if (!(flags & TCL_APPEND_VALUE) || (varPtr->flags & VAR_UNDEFINED)) { + varPtr->valueLength = 0; + } + } + + /* + * Make sure there's enough space to hold the variable's + * new value. If not, enlarge the variable's space. + */ + + if ((length + varPtr->valueLength) >= varPtr->valueSpace) { + Var *newVarPtr; + int newSize; + + newSize = 2*varPtr->valueSpace; + if (newSize <= (length + varPtr->valueLength)) { + newSize += length; + } + newVarPtr = NewVar (newSize); + newVarPtr->valueLength = varPtr->valueLength; + newVarPtr->upvarUses = varPtr->upvarUses; + newVarPtr->tracePtr = varPtr->tracePtr; + newVarPtr->searchPtr = varPtr->searchPtr; + newVarPtr->flags = varPtr->flags; + strcpy(newVarPtr->value.string, varPtr->value.string); + Tcl_SetHashValue(hPtr, newVarPtr); + free (varPtr); + varPtr = newVarPtr; + } + + /* + * Append the new value to the variable, either as a list + * element or as a string. + */ + + if (flags & TCL_LIST_ELEMENT) { + if ((varPtr->valueLength > 0) && !(flags & TCL_NO_SPACE)) { + varPtr->value.string[varPtr->valueLength] = ' '; + varPtr->valueLength++; + } + varPtr->valueLength += Tcl_ConvertElement(newValue, + varPtr->value.string + varPtr->valueLength, listFlags); + varPtr->value.string[varPtr->valueLength] = 0; + } else { + strcpy(varPtr->value.string + varPtr->valueLength, newValue); + varPtr->valueLength += length; + } + varPtr->flags &= ~VAR_UNDEFINED; + + /* + * Invoke any write traces for the variable. + */ + + if ((varPtr->tracePtr != 0) + || ((arrayPtr != 0) && (arrayPtr->tracePtr != 0))) { + unsigned char *msg; + + msg = CallTraces(iPtr, arrayPtr, hPtr, part1, part2, + (flags & TCL_GLOBAL_ONLY) | TCL_TRACE_WRITES); + if (msg != 0) { + VarErrMsg(interp, part1, part2, (unsigned char*) "set", msg); + return 0; + } + + /* + * Watch out! The variable could have gotten re-allocated to + * a larger size. Fortunately the hash table entry will still + * be around. + */ + + varPtr = (Var *) Tcl_GetHashValue(hPtr); + } + return varPtr->value.string; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_UnsetVar -- + * + * Delete a variable, so that it may not be accessed anymore. + * + * Results: + * Returns 0 if the variable was successfully deleted, -1 + * if the variable can't be unset. In the event of an error, + * if the TCL_LEAVE_ERR_MSG flag is set then an error message + * is left in interp->result. + * + * Side effects: + * If varName is defined as a local or global variable in interp, + * it is deleted. + * + *---------------------------------------------------------------------- + */ + +int +Tcl_UnsetVar(interp, varName, flags) + Tcl_Interp *interp; /* Command interpreter in which varName is + * to be looked up. */ + unsigned char *varName; /* Name of a variable in interp. May be + * either a scalar name or an array name + * or an element in an array. */ + int flags; /* OR-ed combination of any of + * TCL_GLOBAL_ONLY or TCL_LEAVE_ERR_MSG. */ +{ + register unsigned char *p; + int result; + + /* + * Figure out whether this is an array reference, then call + * Tcl_UnsetVar2 to do all the real work. + */ + + for (p = varName; *p != '\0'; p++) { + if (*p == '(') { + unsigned char *open = p; + + do { + p++; + } while (*p != '\0'); + p--; + if (*p != ')') { + goto scalar; + } + *open = '\0'; + *p = '\0'; + result = Tcl_UnsetVar2(interp, varName, open+1, flags); + *open = '('; + *p = ')'; + return result; + } + } + + scalar: + return Tcl_UnsetVar2(interp, varName, 0, flags); +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_UnsetVar2 -- + * + * Delete a variable, given a 2-part name. + * + * Results: + * Returns 0 if the variable was successfully deleted, -1 + * if the variable can't be unset. In the event of an error, + * if the TCL_LEAVE_ERR_MSG flag is set then an error message + * is left in interp->result. + * + * Side effects: + * If part1 and part2 indicate a local or global variable in interp, + * it is deleted. If part1 is an array name and part2 is NULL, then + * the whole array is deleted. + * + *---------------------------------------------------------------------- + */ + +int +Tcl_UnsetVar2(interp, part1, part2, flags) + Tcl_Interp *interp; /* Command interpreter in which varName is + * to be looked up. */ + unsigned char *part1; /* Name of variable or array. */ + unsigned char *part2; /* Name of element within array or NULL. */ + int flags; /* OR-ed combination of any of + * TCL_GLOBAL_ONLY or TCL_LEAVE_ERR_MSG. */ +{ + Tcl_HashEntry *hPtr, dummyEntry; + Var *varPtr, dummyVar; + Interp *iPtr = (Interp *) interp; + Var *arrayPtr = 0; + + if ((flags & TCL_GLOBAL_ONLY) || (iPtr->varFramePtr == 0)) { + hPtr = Tcl_FindHashEntry(&iPtr->globalTable, part1); + } else { + hPtr = Tcl_FindHashEntry(&iPtr->varFramePtr->varTable, part1); + } + if (hPtr == 0) { + if (flags & TCL_LEAVE_ERR_MSG) { + VarErrMsg(interp, part1, part2, (unsigned char*) "unset", noSuchVar); + } + return -1; + } + varPtr = (Var *) Tcl_GetHashValue(hPtr); + + /* + * For global variables referenced in procedures, leave the procedure's + * reference variable in place, but unset the global variable. Can't + * decrement the actual variable's use count, since we didn't delete + * the reference variable. + */ + + if (varPtr->flags & VAR_UPVAR) { + hPtr = varPtr->value.upvarPtr; + varPtr = (Var *) Tcl_GetHashValue(hPtr); + } + + /* + * If the variable being deleted is an element of an array, then + * remember trace procedures on the overall array and find the + * element to delete. + */ + + if (part2 != 0) { + if (!(varPtr->flags & VAR_ARRAY)) { + if (flags & TCL_LEAVE_ERR_MSG) { + VarErrMsg(interp, part1, part2, (unsigned char*) "unset", needArray); + } + return -1; + } + if (varPtr->searchPtr != 0) { + DeleteSearches(varPtr); + } + arrayPtr = varPtr; + hPtr = Tcl_FindHashEntry(varPtr->value.tablePtr, part2); + if (hPtr == 0) { + if (flags & TCL_LEAVE_ERR_MSG) { + VarErrMsg(interp, part1, part2, (unsigned char*) "unset", noSuchElement); + } + return -1; + } + varPtr = (Var *) Tcl_GetHashValue(hPtr); + } + + /* + * If there is a trace active on this variable or if the variable + * is already being deleted then don't delete the variable: it + * isn't safe, since there are procedures higher up on the stack + * that will use pointers to the variable. Also don't delete an + * array if there are traces active on any of its elements. + */ + + if (varPtr->flags & + (VAR_TRACE_ACTIVE|VAR_ELEMENT_ACTIVE)) { + if (flags & TCL_LEAVE_ERR_MSG) { + VarErrMsg(interp, part1, part2, (unsigned char*) "unset", traceActive); + } + return -1; + } + + /* + * The code below is tricky, because of the possibility that + * a trace procedure might try to access a variable being + * deleted. To handle this situation gracefully, copy the + * contents of the variable and its hash table entry to + * dummy variables, then clean up the actual variable so that + * it's been completely deleted before the traces are called. + * Then call the traces, and finally clean up the variable's + * storage using the dummy copies. + */ + + dummyVar = *varPtr; + Tcl_SetHashValue(&dummyEntry, &dummyVar); + if (varPtr->upvarUses == 0) { + Tcl_DeleteHashEntry(hPtr); + free (varPtr); + } else { + varPtr->flags = VAR_UNDEFINED; + varPtr->tracePtr = 0; + } + + /* + * Call trace procedures for the variable being deleted and delete + * its traces. + */ + + if ((dummyVar.tracePtr != 0) + || ((arrayPtr != 0) && (arrayPtr->tracePtr != 0))) { + (void) CallTraces(iPtr, arrayPtr, &dummyEntry, part1, part2, + (flags & TCL_GLOBAL_ONLY) | TCL_TRACE_UNSETS); + while (dummyVar.tracePtr != 0) { + VarTrace *tracePtr = dummyVar.tracePtr; + dummyVar.tracePtr = tracePtr->nextPtr; + free (tracePtr); + } + } + + /* + * If the variable is an array, delete all of its elements. This + * must be done after calling the traces on the array, above (that's + * the way traces are defined). + */ + + if (dummyVar.flags & VAR_ARRAY) { + DeleteArray(iPtr, part1, &dummyVar, + (flags & TCL_GLOBAL_ONLY) | TCL_TRACE_UNSETS); + } + if (dummyVar.flags & VAR_UNDEFINED) { + if (flags & TCL_LEAVE_ERR_MSG) { + VarErrMsg(interp, part1, part2, (unsigned char*) "unset", + (part2 == 0) ? noSuchVar : noSuchElement); + } + return -1; + } + return 0; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_TraceVar -- + * + * Arrange for reads and/or writes to a variable to cause a + * procedure to be invoked, which can monitor the operations + * and/or change their actions. + * + * Results: + * A standard Tcl return value. + * + * Side effects: + * A trace is set up on the variable given by varName, such that + * future references to the variable will be intermediated by + * proc. See the manual entry for complete details on the calling + * sequence for proc. + * + *---------------------------------------------------------------------- + */ + +int +Tcl_TraceVar(interp, varName, flags, proc, clientData) + Tcl_Interp *interp; /* Interpreter in which variable is + * to be traced. */ + unsigned char *varName; /* Name of variable; may end with "(index)" + * to signify an array reference. */ + int flags; /* OR-ed collection of bits, including any + * of TCL_TRACE_READS, TCL_TRACE_WRITES, + * TCL_TRACE_UNSETS, and TCL_GLOBAL_ONLY. */ + Tcl_VarTraceProc *proc; /* Procedure to call when specified ops are + * invoked upon varName. */ + void *clientData; /* Arbitrary argument to pass to proc. */ +{ + register unsigned char *p; + + /* + * If varName refers to an array (it ends with a parenthesized + * element name), then handle it specially. + */ + + for (p = varName; *p != '\0'; p++) { + if (*p == '(') { + int result; + unsigned char *open = p; + + do { + p++; + } while (*p != '\0'); + p--; + if (*p != ')') { + goto scalar; + } + *open = '\0'; + *p = '\0'; + result = Tcl_TraceVar2(interp, varName, open+1, flags, + proc, clientData); + *open = '('; + *p = ')'; + return result; + } + } + + scalar: + return Tcl_TraceVar2(interp, varName, 0, flags, proc, clientData); +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_TraceVar2 -- + * + * Arrange for reads and/or writes to a variable to cause a + * procedure to be invoked, which can monitor the operations + * and/or change their actions. + * + * Results: + * A standard Tcl return value. + * + * Side effects: + * A trace is set up on the variable given by part1 and part2, such + * that future references to the variable will be intermediated by + * proc. See the manual entry for complete details on the calling + * sequence for proc. + * + *---------------------------------------------------------------------- + */ + +int +Tcl_TraceVar2(interp, part1, part2, flags, proc, clientData) + Tcl_Interp *interp; /* Interpreter in which variable is + * to be traced. */ + unsigned char *part1; /* Name of scalar variable or array. */ + unsigned char *part2; /* Name of element within array; NULL means + * trace applies to scalar variable or array + * as-a-whole. */ + int flags; /* OR-ed collection of bits, including any + * of TCL_TRACE_READS, TCL_TRACE_WRITES, + * TCL_TRACE_UNSETS, and TCL_GLOBAL_ONLY. */ + Tcl_VarTraceProc *proc; /* Procedure to call when specified ops are + * invoked upon varName. */ + void *clientData; /* Arbitrary argument to pass to proc. */ +{ + Tcl_HashEntry *hPtr; + Var *varPtr = 0; /* Initial value only used to stop compiler + * from complaining; not really needed. */ + Interp *iPtr = (Interp *) interp; + register VarTrace *tracePtr; + int new; + + /* + * Locate the variable, making a new (undefined) one if necessary. + */ + + if ((flags & TCL_GLOBAL_ONLY) || (iPtr->varFramePtr == 0)) { + hPtr = Tcl_CreateHashEntry(&iPtr->globalTable, part1, &new); + } else { + hPtr = Tcl_CreateHashEntry(&iPtr->varFramePtr->varTable, part1, &new); + } + if (!new) { + varPtr = (Var *) Tcl_GetHashValue(hPtr); + if (varPtr->flags & VAR_UPVAR) { + hPtr = varPtr->value.upvarPtr; + varPtr = (Var *) Tcl_GetHashValue(hPtr); + } + } + + /* + * If the trace is to be on an array element, make sure that the + * variable is an array variable. If the variable doesn't exist + * then define it as an empty array. Then find the specific + * array element. + */ + + if (part2 != 0) { + if (new) { + varPtr = NewVar (0); + Tcl_SetHashValue(hPtr, varPtr); + varPtr->flags = VAR_ARRAY; + varPtr->value.tablePtr = (Tcl_HashTable*) + malloc (sizeof(Tcl_HashTable)); + Tcl_InitHashTable (varPtr->value.tablePtr, TCL_STRING_KEYS); + } else { + if (varPtr->flags & VAR_UNDEFINED) { + varPtr->flags = VAR_ARRAY; + varPtr->value.tablePtr = (Tcl_HashTable*) + malloc (sizeof(Tcl_HashTable)); + Tcl_InitHashTable (varPtr->value.tablePtr, TCL_STRING_KEYS); + } else if (!(varPtr->flags & VAR_ARRAY)) { + iPtr->result = needArray; + return TCL_ERROR; + } + } + hPtr = Tcl_CreateHashEntry(varPtr->value.tablePtr, part2, &new); + } + + if (new) { + if ((part2 != 0) && (varPtr->searchPtr != 0)) { + DeleteSearches(varPtr); + } + varPtr = NewVar (0); + varPtr->flags = VAR_UNDEFINED; + Tcl_SetHashValue(hPtr, varPtr); + } else { + varPtr = (Var *) Tcl_GetHashValue(hPtr); + } + + /* + * Set up trace information. + */ + + tracePtr = (VarTrace*) malloc (sizeof(VarTrace)); + tracePtr->traceProc = proc; + tracePtr->clientData = clientData; + tracePtr->flags = flags & + (TCL_TRACE_READS|TCL_TRACE_WRITES|TCL_TRACE_UNSETS); + tracePtr->nextPtr = varPtr->tracePtr; + varPtr->tracePtr = tracePtr; + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_UntraceVar -- + * + * Remove a previously-created trace for a variable. + * + * Results: + * None. + * + * Side effects: + * If there exists a trace for the variable given by varName + * with the given flags, proc, and clientData, then that trace + * is removed. + * + *---------------------------------------------------------------------- + */ + +void +Tcl_UntraceVar(interp, varName, flags, proc, clientData) + Tcl_Interp *interp; /* Interpreter containing traced variable. */ + unsigned char *varName; /* Name of variable; may end with "(index)" + * to signify an array reference. */ + int flags; /* OR-ed collection of bits describing + * current trace, including any of + * TCL_TRACE_READS, TCL_TRACE_WRITES, + * TCL_TRACE_UNSETS, and TCL_GLOBAL_ONLY. */ + Tcl_VarTraceProc *proc; /* Procedure assocated with trace. */ + void *clientData; /* Arbitrary argument to pass to proc. */ +{ + register unsigned char *p; + + /* + * If varName refers to an array (it ends with a parenthesized + * element name), then handle it specially. + */ + + for (p = varName; *p != '\0'; p++) { + if (*p == '(') { + unsigned char *open = p; + + do { + p++; + } while (*p != '\0'); + p--; + if (*p != ')') { + goto scalar; + } + *open = '\0'; + *p = '\0'; + Tcl_UntraceVar2(interp, varName, open+1, flags, proc, clientData); + *open = '('; + *p = ')'; + return; + } + } + + scalar: + Tcl_UntraceVar2(interp, varName, 0, flags, proc, clientData); +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_UntraceVar2 -- + * + * Remove a previously-created trace for a variable. + * + * Results: + * None. + * + * Side effects: + * If there exists a trace for the variable given by part1 + * and part2 with the given flags, proc, and clientData, then + * that trace is removed. + * + *---------------------------------------------------------------------- + */ + +void +Tcl_UntraceVar2(interp, part1, part2, flags, proc, clientData) + Tcl_Interp *interp; /* Interpreter containing traced variable. */ + unsigned char *part1; /* Name of variable or array. */ + unsigned char *part2; /* Name of element within array; NULL means + * trace applies to scalar variable or array + * as-a-whole. */ + int flags; /* OR-ed collection of bits describing + * current trace, including any of + * TCL_TRACE_READS, TCL_TRACE_WRITES, + * TCL_TRACE_UNSETS, and TCL_GLOBAL_ONLY. */ + Tcl_VarTraceProc *proc; /* Procedure assocated with trace. */ + void *clientData; /* Arbitrary argument to pass to proc. */ +{ + register VarTrace *tracePtr; + VarTrace *prevPtr; + Var *varPtr; + Interp *iPtr = (Interp *) interp; + Tcl_HashEntry *hPtr; + ActiveVarTrace *activePtr; + + /* + * First, lookup the variable. + */ + + if ((flags & TCL_GLOBAL_ONLY) || (iPtr->varFramePtr == 0)) { + hPtr = Tcl_FindHashEntry(&iPtr->globalTable, part1); + } else { + hPtr = Tcl_FindHashEntry(&iPtr->varFramePtr->varTable, part1); + } + if (hPtr == 0) { + return; + } + varPtr = (Var *) Tcl_GetHashValue(hPtr); + if (varPtr->flags & VAR_UPVAR) { + hPtr = varPtr->value.upvarPtr; + varPtr = (Var *) Tcl_GetHashValue(hPtr); + } + if (part2 != 0) { + if (!(varPtr->flags & VAR_ARRAY)) { + return; + } + hPtr = Tcl_FindHashEntry(varPtr->value.tablePtr, part2); + if (hPtr == 0) { + return; + } + varPtr = (Var *) Tcl_GetHashValue(hPtr); + } + + flags &= (TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS); + for (tracePtr = varPtr->tracePtr, prevPtr = 0; ; + prevPtr = tracePtr, tracePtr = tracePtr->nextPtr) { + if (tracePtr == 0) { + return; + } + if ((tracePtr->traceProc == proc) && (tracePtr->flags == flags) + && (tracePtr->clientData == clientData)) { + break; + } + } + + /* + * The code below makes it possible to delete traces while traces + * are active: it makes sure that the deleted trace won't be + * processed by CallTraces. + */ + + for (activePtr = iPtr->activeTracePtr; activePtr != 0; + activePtr = activePtr->nextPtr) { + if (activePtr->nextTracePtr == tracePtr) { + activePtr->nextTracePtr = tracePtr->nextPtr; + } + } + if (prevPtr == 0) { + varPtr->tracePtr = tracePtr->nextPtr; + } else { + prevPtr->nextPtr = tracePtr->nextPtr; + } + free (tracePtr); +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_VarTraceInfo -- + * + * Return the clientData value associated with a trace on a + * variable. This procedure can also be used to step through + * all of the traces on a particular variable that have the + * same trace procedure. + * + * Results: + * The return value is the clientData value associated with + * a trace on the given variable. Information will only be + * returned for a trace with proc as trace procedure. If + * the clientData argument is NULL then the first such trace is + * returned; otherwise, the next relevant one after the one + * given by clientData will be returned. If the variable + * doesn't exist, or if there are no (more) traces for it, + * then NULL is returned. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +void * +Tcl_VarTraceInfo(interp, varName, flags, proc, prevClientData) + Tcl_Interp *interp; /* Interpreter containing variable. */ + unsigned char *varName; /* Name of variable; may end with "(index)" + * to signify an array reference. */ + int flags; /* 0 or TCL_GLOBAL_ONLY. */ + Tcl_VarTraceProc *proc; /* Procedure assocated with trace. */ + void *prevClientData; /* If non-NULL, gives last value returned + * by this procedure, so this call will + * return the next trace after that one. + * If NULL, this call will return the + * first trace. */ +{ + register unsigned char *p; + + /* + * If varName refers to an array (it ends with a parenthesized + * element name), then handle it specially. + */ + + for (p = varName; *p != '\0'; p++) { + if (*p == '(') { + void *result; + unsigned char *open = p; + + do { + p++; + } while (*p != '\0'); + p--; + if (*p != ')') { + goto scalar; + } + *open = '\0'; + *p = '\0'; + result = Tcl_VarTraceInfo2(interp, varName, open+1, flags, proc, + prevClientData); + *open = '('; + *p = ')'; + return result; + } + } + + scalar: + return Tcl_VarTraceInfo2(interp, varName, 0, flags, proc, prevClientData); +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_VarTraceInfo2 -- + * + * Same as Tcl_VarTraceInfo, except takes name in two pieces + * instead of one. + * + * Results: + * Same as Tcl_VarTraceInfo. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +void * +Tcl_VarTraceInfo2(interp, part1, part2, flags, proc, prevClientData) + Tcl_Interp *interp; /* Interpreter containing variable. */ + unsigned char *part1; /* Name of variable or array. */ + unsigned char *part2; /* Name of element within array; NULL means + * trace applies to scalar variable or array + * as-a-whole. */ + int flags; /* 0 or TCL_GLOBAL_ONLY. */ + Tcl_VarTraceProc *proc; /* Procedure assocated with trace. */ + void *prevClientData; /* If non-NULL, gives last value returned + * by this procedure, so this call will + * return the next trace after that one. + * If NULL, this call will return the + * first trace. */ +{ + register VarTrace *tracePtr; + Var *varPtr; + Interp *iPtr = (Interp *) interp; + Tcl_HashEntry *hPtr; + + /* + * First, lookup the variable. + */ + if ((flags & TCL_GLOBAL_ONLY) || (iPtr->varFramePtr == 0)) { + hPtr = Tcl_FindHashEntry(&iPtr->globalTable, part1); + } else { + hPtr = Tcl_FindHashEntry(&iPtr->varFramePtr->varTable, part1); + } + if (hPtr == 0) { + return 0; + } + varPtr = (Var *) Tcl_GetHashValue(hPtr); + if (varPtr->flags & VAR_UPVAR) { + hPtr = varPtr->value.upvarPtr; + varPtr = (Var *) Tcl_GetHashValue(hPtr); + } + if (part2 != 0) { + if (!(varPtr->flags & VAR_ARRAY)) { + return 0; + } + hPtr = Tcl_FindHashEntry(varPtr->value.tablePtr, part2); + if (hPtr == 0) { + return 0; + } + varPtr = (Var *) Tcl_GetHashValue(hPtr); + } + + /* + * Find the relevant trace, if any, and return its clientData. + */ + + tracePtr = varPtr->tracePtr; + if (prevClientData != 0) { + for ( ; tracePtr != 0; tracePtr = tracePtr->nextPtr) { + if ((tracePtr->clientData == prevClientData) + && (tracePtr->traceProc == proc)) { + tracePtr = tracePtr->nextPtr; + break; + } + } + } + for ( ; tracePtr != 0; tracePtr = tracePtr->nextPtr) { + if (tracePtr->traceProc == proc) { + return tracePtr->clientData; + } + } + return 0; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_SetCmd -- + * + * This procedure is invoked to process the "set" Tcl command. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result value. + * + * Side effects: + * A variable's value may be changed. + * + *---------------------------------------------------------------------- + */ + + /* ARGSUSED */ +int +Tcl_SetCmd(dummy, interp, argc, argv) + void *dummy; /* Not used. */ + register Tcl_Interp *interp; /* Current interpreter. */ + int argc; /* Number of arguments. */ + unsigned char **argv; /* Argument strings. */ +{ + if (argc == 2) { + unsigned char *value; + + value = Tcl_GetVar(interp, argv[1], TCL_LEAVE_ERR_MSG); + if (value == 0) { + return TCL_ERROR; + } + interp->result = value; + return TCL_OK; + } else if (argc == 3) { + unsigned char *result; + + result = Tcl_SetVar(interp, argv[1], argv[2], TCL_LEAVE_ERR_MSG); + if (result == 0) { + return TCL_ERROR; + } + interp->result = result; + return TCL_OK; + } else { + Tcl_AppendResult(interp, "wrong # args: should be \"", + argv[0], " varName ?newValue?\"", 0); + return TCL_ERROR; + } +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_UnsetCmd -- + * + * This procedure is invoked to process the "unset" Tcl command. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result value. + * + * Side effects: + * See the user documentation. + * + *---------------------------------------------------------------------- + */ + + /* ARGSUSED */ +int +Tcl_UnsetCmd(dummy, interp, argc, argv) + void *dummy; /* Not used. */ + register Tcl_Interp *interp; /* Current interpreter. */ + int argc; /* Number of arguments. */ + unsigned char **argv; /* Argument strings. */ +{ + int i; + + if (argc < 2) { + Tcl_AppendResult(interp, "wrong # args: should be \"", + argv[0], " varName ?varName ...?\"", 0); + return TCL_ERROR; + } + for (i = 1; i < argc; i++) { + if (Tcl_UnsetVar(interp, argv[i], TCL_LEAVE_ERR_MSG) != 0) { + return TCL_ERROR; + } + } + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_AppendCmd -- + * + * This procedure is invoked to process the "append" Tcl command. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result value. + * + * Side effects: + * A variable's value may be changed. + * + *---------------------------------------------------------------------- + */ + + /* ARGSUSED */ +int +Tcl_AppendCmd(dummy, interp, argc, argv) + void *dummy; /* Not used. */ + register Tcl_Interp *interp; /* Current interpreter. */ + int argc; /* Number of arguments. */ + unsigned char **argv; /* Argument strings. */ +{ + int i; + unsigned char *result = 0; /* (Initialization only needed to keep + * the compiler from complaining) */ + + if (argc < 3) { + Tcl_AppendResult(interp, "wrong # args: should be \"", + argv[0], " varName value ?value ...?\"", 0); + return TCL_ERROR; + } + + for (i = 2; i < argc; i++) { + result = Tcl_SetVar(interp, argv[1], argv[i], + TCL_APPEND_VALUE|TCL_LEAVE_ERR_MSG); + if (result == 0) { + return TCL_ERROR; + } + } + interp->result = result; + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_LappendCmd -- + * + * This procedure is invoked to process the "lappend" Tcl command. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result value. + * + * Side effects: + * A variable's value may be changed. + * + *---------------------------------------------------------------------- + */ + + /* ARGSUSED */ +int +Tcl_LappendCmd(dummy, interp, argc, argv) + void *dummy; /* Not used. */ + register Tcl_Interp *interp; /* Current interpreter. */ + int argc; /* Number of arguments. */ + unsigned char **argv; /* Argument strings. */ +{ + int i; + unsigned char *result = 0; /* (Initialization only needed to keep + * the compiler from complaining) */ + + if (argc < 3) { + Tcl_AppendResult(interp, "wrong # args: should be \"", + argv[0], " varName value ?value ...?\"", 0); + return TCL_ERROR; + } + + for (i = 2; i < argc; i++) { + result = Tcl_SetVar(interp, argv[1], argv[i], + TCL_APPEND_VALUE|TCL_LIST_ELEMENT|TCL_LEAVE_ERR_MSG); + if (result == 0) { + return TCL_ERROR; + } + } + interp->result = result; + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_ArrayCmd -- + * + * This procedure is invoked to process the "array" Tcl command. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result value. + * + * Side effects: + * See the user documentation. + * + *---------------------------------------------------------------------- + */ + + /* ARGSUSED */ +int +Tcl_ArrayCmd(dummy, interp, argc, argv) + void *dummy; /* Not used. */ + register Tcl_Interp *interp; /* Current interpreter. */ + int argc; /* Number of arguments. */ + unsigned char **argv; /* Argument strings. */ +{ + int length; + char c; + Var *varPtr; + Tcl_HashEntry *hPtr; + Interp *iPtr = (Interp *) interp; + + if (argc < 3) { + Tcl_AppendResult(interp, "wrong # args: should be \"", + argv[0], " option arrayName ?arg ...?\"", 0); + return TCL_ERROR; + } + + /* + * Locate the array variable (and it better be an array). + */ + + if (iPtr->varFramePtr == 0) { + hPtr = Tcl_FindHashEntry(&iPtr->globalTable, argv[2]); + } else { + hPtr = Tcl_FindHashEntry(&iPtr->varFramePtr->varTable, argv[2]); + } + if (hPtr == 0) { + notArray: + Tcl_AppendResult(interp, "\"", argv[2], "\" isn't an array", 0); + return TCL_ERROR; + } + varPtr = (Var *) Tcl_GetHashValue(hPtr); + if (varPtr->flags & VAR_UPVAR) { + varPtr = (Var *) Tcl_GetHashValue(varPtr->value.upvarPtr); + } + if (!(varPtr->flags & VAR_ARRAY)) { + goto notArray; + } + + /* + * Dispatch based on the option. + */ + + c = argv[1][0]; + length = strlen(argv[1]); + if ((c == 'a') && (strncmp(argv[1], (unsigned char*) "anymore", length) == 0)) { + ArraySearch *searchPtr; + + if (argc != 4) { + Tcl_AppendResult(interp, "wrong # args: should be \"", + argv[0], " anymore arrayName searchId\"", 0); + return TCL_ERROR; + } + searchPtr = ParseSearchId(interp, varPtr, argv[2], argv[3]); + if (searchPtr == 0) { + return TCL_ERROR; + } + while (1) { + Var *varPtr2; + + if (searchPtr->nextEntry != 0) { + varPtr2 = (Var *) Tcl_GetHashValue(searchPtr->nextEntry); + if (!(varPtr2->flags & VAR_UNDEFINED)) { + break; + } + } + searchPtr->nextEntry = Tcl_NextHashEntry(&searchPtr->search); + if (searchPtr->nextEntry == 0) { + interp->result = (unsigned char*) "0"; + return TCL_OK; + } + } + interp->result = (unsigned char*) "1"; + return TCL_OK; + } else if ((c == 'd') && (strncmp(argv[1], (unsigned char*) "donesearch", length) == 0)) { + ArraySearch *searchPtr, *prevPtr; + + if (argc != 4) { + Tcl_AppendResult(interp, "wrong # args: should be \"", + argv[0], " donesearch arrayName searchId\"", 0); + return TCL_ERROR; + } + searchPtr = ParseSearchId(interp, varPtr, argv[2], argv[3]); + if (searchPtr == 0) { + return TCL_ERROR; + } + if (varPtr->searchPtr == searchPtr) { + varPtr->searchPtr = searchPtr->nextPtr; + } else { + for (prevPtr = varPtr->searchPtr; ; prevPtr = prevPtr->nextPtr) { + if (prevPtr->nextPtr == searchPtr) { + prevPtr->nextPtr = searchPtr->nextPtr; + break; + } + } + } + free (searchPtr); + } else if ((c == 'n') && (strncmp(argv[1], (unsigned char*) "names", length) == 0) + && (length >= 2)) { + Tcl_HashSearch search; + Var *varPtr2; + + if (argc != 3) { + Tcl_AppendResult(interp, "wrong # args: should be \"", + argv[0], " names arrayName\"", 0); + return TCL_ERROR; + } + for (hPtr = Tcl_FirstHashEntry(varPtr->value.tablePtr, &search); + hPtr != 0; hPtr = Tcl_NextHashEntry(&search)) { + varPtr2 = (Var *) Tcl_GetHashValue(hPtr); + if (varPtr2->flags & VAR_UNDEFINED) { + continue; + } + Tcl_AppendElement(interp, + Tcl_GetHashKey(varPtr->value.tablePtr, hPtr), 0); + } + } else if ((c == 'n') && (strncmp(argv[1], (unsigned char*) "nextelement", length) == 0) + && (length >= 2)) { + ArraySearch *searchPtr; + Tcl_HashEntry *hPtr; + + if (argc != 4) { + Tcl_AppendResult(interp, "wrong # args: should be \"", + argv[0], " nextelement arrayName searchId\"", 0); + return TCL_ERROR; + } + searchPtr = ParseSearchId(interp, varPtr, argv[2], argv[3]); + if (searchPtr == 0) { + return TCL_ERROR; + } + while (1) { + Var *varPtr2; + + hPtr = searchPtr->nextEntry; + if (hPtr == 0) { + hPtr = Tcl_NextHashEntry(&searchPtr->search); + if (hPtr == 0) { + return TCL_OK; + } + } else { + searchPtr->nextEntry = 0; + } + varPtr2 = (Var *) Tcl_GetHashValue(hPtr); + if (!(varPtr2->flags & VAR_UNDEFINED)) { + break; + } + } + interp->result = Tcl_GetHashKey(varPtr->value.tablePtr, hPtr); + } else if ((c == 's') && (strncmp(argv[1], (unsigned char*) "size", length) == 0) + && (length >= 2)) { + Tcl_HashSearch search; + Var *varPtr2; + int size; + + if (argc != 3) { + Tcl_AppendResult(interp, "wrong # args: should be \"", + argv[0], " size arrayName\"", 0); + return TCL_ERROR; + } + size = 0; + for (hPtr = Tcl_FirstHashEntry(varPtr->value.tablePtr, &search); + hPtr != 0; hPtr = Tcl_NextHashEntry(&search)) { + varPtr2 = (Var *) Tcl_GetHashValue(hPtr); + if (varPtr2->flags & VAR_UNDEFINED) { + continue; + } + size++; + } + sprintf(interp->result, "%d", size); + } else if ((c == 's') && (strncmp(argv[1], (unsigned char*) "startsearch", length) == 0) + && (length >= 2)) { + ArraySearch *searchPtr; + + if (argc != 3) { + Tcl_AppendResult(interp, "wrong # args: should be \"", + argv[0], " startsearch arrayName\"", 0); + return TCL_ERROR; + } + searchPtr = (ArraySearch*) malloc (sizeof(ArraySearch)); + if (varPtr->searchPtr == 0) { + searchPtr->id = 1; + Tcl_AppendResult(interp, "s-1-", argv[2], 0); + } else { + unsigned char string[20]; + + searchPtr->id = varPtr->searchPtr->id + 1; + sprintf(string, "%u", searchPtr->id); + Tcl_AppendResult(interp, "s-", string, "-", argv[2], 0); + } + searchPtr->varPtr = varPtr; + searchPtr->nextEntry = Tcl_FirstHashEntry(varPtr->value.tablePtr, + &searchPtr->search); + searchPtr->nextPtr = varPtr->searchPtr; + varPtr->searchPtr = searchPtr; + } else { + Tcl_AppendResult(interp, "bad option \"", argv[1], + "\": should be anymore, donesearch, names, nextelement, ", + "size, or startsearch", 0); + return TCL_ERROR; + } + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_GlobalCmd -- + * + * This procedure is invoked to process the "global" Tcl command. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result value. + * + * Side effects: + * See the user documentation. + * + *---------------------------------------------------------------------- + */ + + /* ARGSUSED */ +int +Tcl_GlobalCmd(dummy, interp, argc, argv) + void *dummy; /* Not used. */ + Tcl_Interp *interp; /* Current interpreter. */ + int argc; /* Number of arguments. */ + unsigned char **argv; /* Argument strings. */ +{ + Var *varPtr, *gVarPtr; + register Interp *iPtr = (Interp *) interp; + Tcl_HashEntry *hPtr, *hPtr2; + int new; + + if (argc < 2) { + Tcl_AppendResult((Tcl_Interp *) iPtr, "wrong # args: should be \"", + argv[0], " varName ?varName ...?\"", 0); + return TCL_ERROR; + } + if (iPtr->varFramePtr == 0) { + return TCL_OK; + } + + for (argc--, argv++; argc > 0; argc--, argv++) { + hPtr = Tcl_CreateHashEntry(&iPtr->globalTable, *argv, &new); + if (new) { + gVarPtr = NewVar (0); + gVarPtr->flags |= VAR_UNDEFINED; + Tcl_SetHashValue(hPtr, gVarPtr); + } else { + gVarPtr = (Var *) Tcl_GetHashValue(hPtr); + } + hPtr2 = Tcl_CreateHashEntry(&iPtr->varFramePtr->varTable, *argv, &new); + if (!new) { + Var *varPtr; + varPtr = (Var *) Tcl_GetHashValue(hPtr2); + if (varPtr->flags & VAR_UPVAR) { + continue; + } else { + Tcl_AppendResult((Tcl_Interp *) iPtr, "variable \"", *argv, + "\" already exists", 0); + return TCL_ERROR; + } + } + varPtr = NewVar (0); + varPtr->flags |= VAR_UPVAR; + varPtr->value.upvarPtr = hPtr; + gVarPtr->upvarUses++; + Tcl_SetHashValue(hPtr2, varPtr); + } + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_UpvarCmd -- + * + * This procedure is invoked to process the "upvar" Tcl command. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result value. + * + * Side effects: + * See the user documentation. + * + *---------------------------------------------------------------------- + */ + + /* ARGSUSED */ +int +Tcl_UpvarCmd(dummy, interp, argc, argv) + void *dummy; /* Not used. */ + Tcl_Interp *interp; /* Current interpreter. */ + int argc; /* Number of arguments. */ + unsigned char **argv; /* Argument strings. */ +{ + register Interp *iPtr = (Interp *) interp; + int result; + CallFrame *framePtr; + Var *varPtr = 0; + Tcl_HashTable *upVarTablePtr; + Tcl_HashEntry *hPtr, *hPtr2; + int new; + Var *upVarPtr; + + if (argc < 3) { + upvarSyntax: + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " ?level? otherVar localVar ?otherVar localVar ...?\"", 0); + return TCL_ERROR; + } + + /* + * Find the hash table containing the variable being referenced. + */ + + result = TclGetFrame(interp, argv[1], &framePtr); + if (result == -1) { + return TCL_ERROR; + } + argc -= result+1; + argv += result+1; + if (framePtr == 0) { + upVarTablePtr = &iPtr->globalTable; + } else { + upVarTablePtr = &framePtr->varTable; + } + + if ((argc & 1) != 0) { + goto upvarSyntax; + } + + /* + * Iterate over all the pairs of (local variable, other variable) + * names. For each pair, create a hash table entry in the upper + * context (if the name wasn't there already), then associate it + * with a new local variable. + */ + + while (argc > 0) { + hPtr = Tcl_CreateHashEntry(upVarTablePtr, argv[0], &new); + if (new) { + upVarPtr = NewVar (0); + upVarPtr->flags |= VAR_UNDEFINED; + Tcl_SetHashValue(hPtr, upVarPtr); + } else { + upVarPtr = (Var *) Tcl_GetHashValue(hPtr); + if (upVarPtr->flags & VAR_UPVAR) { + hPtr = upVarPtr->value.upvarPtr; + upVarPtr = (Var *) Tcl_GetHashValue(hPtr); + } + } + + hPtr2 = Tcl_CreateHashEntry(&iPtr->varFramePtr->varTable, + argv[1], &new); + if (!new) { + Tcl_AppendResult((Tcl_Interp *) iPtr, "variable \"", argv[1], + "\" already exists", 0); + return TCL_ERROR; + } + varPtr = NewVar (0); + varPtr->flags |= VAR_UPVAR; + varPtr->value.upvarPtr = hPtr; + upVarPtr->upvarUses++; + Tcl_SetHashValue(hPtr2, varPtr); + + argc -= 2; + argv += 2; + } + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * TclDeleteVars -- + * + * This procedure is called to recycle all the storage space + * associated with a table of variables. For this procedure + * to work correctly, it must not be possible for any of the + * variable in the table to be accessed from Tcl commands + * (e.g. from trace procedures). + * + * Results: + * None. + * + * Side effects: + * Variables are deleted and trace procedures are invoked, if + * any are declared. + * + *---------------------------------------------------------------------- + */ + +void +TclDeleteVars(iPtr, tablePtr) + Interp *iPtr; /* Interpreter to which variables belong. */ + Tcl_HashTable *tablePtr; /* Hash table containing variables to + * delete. */ +{ + Tcl_HashSearch search; + Tcl_HashEntry *hPtr; + register Var *varPtr; + int flags, globalFlag; + + flags = TCL_TRACE_UNSETS; + if (tablePtr == &iPtr->globalTable) { + flags |= TCL_INTERP_DESTROYED | TCL_GLOBAL_ONLY; + } + for (hPtr = Tcl_FirstHashEntry(tablePtr, &search); hPtr != 0; + hPtr = Tcl_NextHashEntry(&search)) { + varPtr = (Var *) Tcl_GetHashValue(hPtr); + + /* + * For global/upvar variables referenced in procedures, free up the + * local space and then decrement the reference count on the + * variable referred to. If there are no more references to the + * global/upvar and it is undefined and has no traces set, then + * follow on and delete the referenced variable too. + */ + + globalFlag = 0; + if (varPtr->flags & VAR_UPVAR) { + hPtr = varPtr->value.upvarPtr; + free (varPtr); + varPtr = (Var *) Tcl_GetHashValue(hPtr); + varPtr->upvarUses--; + if ((varPtr->upvarUses != 0) || !(varPtr->flags & VAR_UNDEFINED) + || (varPtr->tracePtr != 0)) { + continue; + } + globalFlag = TCL_GLOBAL_ONLY; + } + + /* + * Invoke traces on the variable that is being deleted, then + * free up the variable's space (no need to free the hash entry + * here, unless we're dealing with a global variable: the + * hash entries will be deleted automatically when the whole + * table is deleted). + */ + + if (varPtr->tracePtr != 0) { + (void) CallTraces(iPtr, (Var *) 0, hPtr, + Tcl_GetHashKey(tablePtr, hPtr), 0, + flags | globalFlag); + while (varPtr->tracePtr != 0) { + VarTrace *tracePtr = varPtr->tracePtr; + varPtr->tracePtr = tracePtr->nextPtr; + free (tracePtr); + } + } + if (varPtr->flags & VAR_ARRAY) { + DeleteArray(iPtr, Tcl_GetHashKey(tablePtr, hPtr), varPtr, + flags | globalFlag); + } + if (globalFlag) { + Tcl_DeleteHashEntry(hPtr); + } + free (varPtr); + } + Tcl_DeleteHashTable(tablePtr); +} + +/* + *---------------------------------------------------------------------- + * + * CallTraces -- + * + * This procedure is invoked to find and invoke relevant + * trace procedures associated with a particular operation on + * a variable. This procedure invokes traces both on the + * variable and on its containing array (where relevant). + * + * Results: + * The return value is 0 if no trace procedures were invoked, or + * if all the invoked trace procedures returned successfully. + * The return value is non-zero if a trace procedure returned an + * error (in this case no more trace procedures were invoked after + * the error was returned). In this case the return value is a + * pointer to a static string describing the error. + * + * Side effects: + * Almost anything can happen, depending on trace; this procedure + * itself doesn't have any side effects. + * + *---------------------------------------------------------------------- + */ + +static unsigned char * +CallTraces (iPtr, arrayPtr, hPtr, part1, part2, flags) + Interp *iPtr; /* Interpreter containing variable. */ + register Var *arrayPtr; /* Pointer to array variable that + * contains the variable, or 0 if + * the variable isn't an element of an + * array. */ + Tcl_HashEntry *hPtr; /* Hash table entry corresponding to + * variable whose traces are to be + * invoked. */ + unsigned char *part1, *part2; /* Variable's two-part name. */ + int flags; /* Flags to pass to trace procedures: + * indicates what's happening to + * variable, plus other stuff like + * TCL_GLOBAL_ONLY and + * TCL_INTERP_DESTROYED. */ +{ + Var *varPtr; + register VarTrace *tracePtr; + ActiveVarTrace active; + unsigned char *result; + int savedArrayFlags = 0; /* (Initialization not needed except + * to prevent compiler warning) */ + + /* + * If there are already similar trace procedures active for the + * variable, don't call them again. + */ + + varPtr = (Var *) Tcl_GetHashValue(hPtr); + if (varPtr->flags & VAR_TRACE_ACTIVE) { + return 0; + } + varPtr->flags |= VAR_TRACE_ACTIVE; + + /* + * Invoke traces on the array containing the variable, if relevant. + */ + + result = 0; + active.nextPtr = iPtr->activeTracePtr; + iPtr->activeTracePtr = &active; + if (arrayPtr != 0) { + savedArrayFlags = arrayPtr->flags; + arrayPtr->flags |= VAR_ELEMENT_ACTIVE; + for (tracePtr = arrayPtr->tracePtr; tracePtr != 0; + tracePtr = active.nextTracePtr) { + active.nextTracePtr = tracePtr->nextPtr; + if (!(tracePtr->flags & flags)) { + continue; + } + result = (*tracePtr->traceProc)(tracePtr->clientData, + (Tcl_Interp *) iPtr, part1, part2, flags); + if (result != 0) { + if (flags & TCL_TRACE_UNSETS) { + result = 0; + } else { + goto done; + } + } + } + } + + /* + * Invoke traces on the variable itself. + */ + + if (flags & TCL_TRACE_UNSETS) { + flags |= TCL_TRACE_DESTROYED; + } + for (tracePtr = varPtr->tracePtr; tracePtr != 0; + tracePtr = active.nextTracePtr) { + active.nextTracePtr = tracePtr->nextPtr; + if (!(tracePtr->flags & flags)) { + continue; + } + result = (*tracePtr->traceProc)(tracePtr->clientData, + (Tcl_Interp *) iPtr, part1, part2, flags); + if (result != 0) { + if (flags & TCL_TRACE_UNSETS) { + result = 0; + } else { + goto done; + } + } + } + + /* + * Restore the variable's flags, remove the record of our active + * traces, and then return. Remember that the variable could have + * been re-allocated during the traces, but its hash entry won't + * change. + */ + + done: + if (arrayPtr != 0) { + arrayPtr->flags = savedArrayFlags; + } + varPtr = (Var *) Tcl_GetHashValue(hPtr); + varPtr->flags &= ~VAR_TRACE_ACTIVE; + iPtr->activeTracePtr = active.nextPtr; + return result; +} + +/* + *---------------------------------------------------------------------- + * + * NewVar -- + * + * Create a new variable with a given initial value. + * + * Results: + * The return value is a pointer to the new variable structure. + * The variable will not be part of any hash table yet, and its + * upvarUses count is initialized to 0. Its initial value will + * be empty, but "space" bytes will be available in the value + * area. + * + * Side effects: + * Storage gets allocated. + * + *---------------------------------------------------------------------- + */ + +static Var * +NewVar (int space) /* Minimum amount of space to allocate + * for variable's value. */ +{ + int extra; + register Var *varPtr; + + extra = space - sizeof(varPtr->value); + if (extra < 0) { + extra = 0; + space = sizeof(varPtr->value); + } + varPtr = (Var*) malloc ((unsigned) (sizeof(Var) + extra)); + varPtr->valueLength = 0; + varPtr->valueSpace = space; + varPtr->upvarUses = 0; + varPtr->tracePtr = 0; + varPtr->searchPtr = 0; + varPtr->flags = 0; + varPtr->value.string[0] = 0; + return varPtr; +} + +/* + *---------------------------------------------------------------------- + * + * ParseSearchId -- + * + * This procedure translates from a string to a pointer to an + * active array search (if there is one that matches the string). + * + * Results: + * The return value is a pointer to the array search indicated + * by string, or 0 if there isn't one. If 0 is returned, + * interp->result contains an error message. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static ArraySearch * +ParseSearchId(interp, varPtr, varName, string) + Tcl_Interp *interp; /* Interpreter containing variable. */ + Var *varPtr; /* Array variable search is for. */ + unsigned char *varName; /* Name of array variable that search is + * supposed to be for. */ + unsigned char *string; /* String containing id of search. Must have + * form "search-num-var" where "num" is a + * decimal number and "var" is a variable + * name. */ +{ + unsigned char *end; + int id; + ArraySearch *searchPtr; + + /* + * Parse the id into the three parts separated by dashes. + */ + + if ((string[0] != 's') || (string[1] != '-')) { + syntax: + Tcl_AppendResult(interp, "illegal search identifier \"", string, + "\"", 0); + return 0; + } + id = strtoul(string+2, &end, 10); + if ((end == (string+2)) || (*end != '-')) { + goto syntax; + } + if (strcmp(end+1, varName) != 0) { + Tcl_AppendResult(interp, "search identifier \"", string, + "\" isn't for variable \"", varName, "\"", 0); + return 0; + } + + /* + * Search through the list of active searches on the interpreter + * to see if the desired one exists. + */ + + for (searchPtr = varPtr->searchPtr; searchPtr != 0; + searchPtr = searchPtr->nextPtr) { + if (searchPtr->id == id) { + return searchPtr; + } + } + Tcl_AppendResult(interp, "couldn't find search \"", string, "\"", 0); + return 0; +} + +/* + *---------------------------------------------------------------------- + * + * DeleteSearches -- + * + * This procedure is called to free up all of the searches + * associated with an array variable. + * + * Results: + * None. + * + * Side effects: + * Memory is released to the storage allocator. + * + *---------------------------------------------------------------------- + */ + +static void +DeleteSearches(arrayVarPtr) + register Var *arrayVarPtr; /* Variable whose searches are + * to be deleted. */ +{ + ArraySearch *searchPtr; + + while (arrayVarPtr->searchPtr != 0) { + searchPtr = arrayVarPtr->searchPtr; + arrayVarPtr->searchPtr = searchPtr->nextPtr; + free (searchPtr); + } +} + +/* + *---------------------------------------------------------------------- + * + * DeleteArray -- + * + * This procedure is called to free up everything in an array + * variable. It's the caller's responsibility to make sure + * that the array is no longer accessible before this procedure + * is called. + * + * Results: + * None. + * + * Side effects: + * All storage associated with varPtr's array elements is deleted + * (including the hash table). Any delete trace procedures for + * array elements are invoked. + * + *---------------------------------------------------------------------- + */ +static void +DeleteArray(iPtr, arrayName, varPtr, flags) + Interp *iPtr; /* Interpreter containing array. */ + unsigned char *arrayName; /* Name of array (used for trace + * callbacks). */ + Var *varPtr; /* Pointer to variable structure. */ + int flags; /* Flags to pass to CallTraces: + * TCL_TRACE_UNSETS and sometimes + * TCL_INTERP_DESTROYED and/or + * TCL_GLOBAL_ONLY. */ +{ + Tcl_HashSearch search; + register Tcl_HashEntry *hPtr; + register Var *elPtr; + + DeleteSearches(varPtr); + for (hPtr = Tcl_FirstHashEntry(varPtr->value.tablePtr, &search); + hPtr != 0; hPtr = Tcl_NextHashEntry(&search)) { + elPtr = (Var *) Tcl_GetHashValue(hPtr); + if (elPtr->tracePtr != 0) { + (void) CallTraces(iPtr, (Var *) 0, hPtr, arrayName, + Tcl_GetHashKey(varPtr->value.tablePtr, hPtr), flags); + while (elPtr->tracePtr != 0) { + VarTrace *tracePtr = elPtr->tracePtr; + elPtr->tracePtr = tracePtr->nextPtr; + free (tracePtr); + } + } + assert ((elPtr->flags & VAR_SEARCHES_POSSIBLE) == 0); + + free (elPtr); + } + Tcl_DeleteHashTable(varPtr->value.tablePtr); + free (varPtr->value.tablePtr); +} + +/* + *---------------------------------------------------------------------- + * + * VarErrMsg -- + * + * Generate a reasonable error message describing why a variable + * operation failed. + * + * Results: + * None. + * + * Side effects: + * Interp->result is reset to hold a message identifying the + * variable given by part1 and part2 and describing why the + * variable operation failed. + * + *---------------------------------------------------------------------- + */ + +static void +VarErrMsg(interp, part1, part2, operation, reason) + Tcl_Interp *interp; /* Interpreter in which to record message. */ + unsigned char *part1, *part2; /* Variable's two-part name. */ + unsigned char *operation; /* String describing operation that failed, + * e.g. "read", "set", or "unset". */ + unsigned char *reason; /* String describing why operation failed. */ +{ + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, "can't ", operation, " \"", part1, 0); + if (part2 != 0) { + Tcl_AppendResult(interp, "(", part2, ")", 0); + } + Tcl_AppendResult(interp, "\": ", reason, 0); +} diff --git a/src/libtermlib/Makefile b/src/libtermlib/Makefile new file mode 100644 index 0000000..386f77b --- /dev/null +++ b/src/libtermlib/Makefile @@ -0,0 +1,63 @@ +# +# Copyright (c) 1980 Regents of the University of California. +# All rights reserved. The Berkeley software License Agreement +# specifies the terms and conditions for redistribution. +# +TOPSRC = $(shell cd ../..; pwd) +include $(TOPSRC)/target.mk + +DEFS = -DNOSCCS +CFLAGS = -O -DCM_N -DCM_GT -DCM_B -DCM_D $(DEFS) -Wall -Werror +LD = $(CC) +SRCS = termcap.c tgoto.c tputs.c tcattr.c +OBJS = termcap.o tgoto.o tputs.o tcattr.o +POBJS = ../termcap.o ../tgoto.o ../tputs.o ../tcattr.o +TAGSFILE= tags + +#.c.o: +# $(CC) $(CFLAGS) -c -p $*.c +# $(LD) $(LDFLAGS) -x -r -o profiled/$*.o $*.o +# $(CC) $(CFLAGS) -c $*.c +# $(LD) $(LDFLAGS) -X -r $*.o +# mv a.out $*.o + +all: ../libtermcap.a termcap + +.PHONY: termcap + +termcap: + cd termcap && make + +../libtermcap.a: ${OBJS} + $(AR) cr ../libtermcap.a ${OBJS} + +../libtermcap_p.a: ${OBJS} + cd profiled; $(AR) cr ../../libtermcap_p.a ${POBJS} + +install: all +# cp ../libtermcap.a ${DESTDIR}/lib/libtermcap.a +# @-rm -f ${DESTDIR}/lib/libtermlib.a +# ln ${DESTDIR}/lib/libtermcap.a ${DESTDIR}/lib/libtermlib.a +# $(RANLIB) ${DESTDIR}/lib/libtermcap.a + $(MAKE) -C termcap install +# cp ../libtermcap_p.a ${DESTDIR}/lib/libtermcap_p.a +# @-rm -f ${DESTDIR}/lib/libtermlib_p.a +# ln ${DESTDIR}/lib/libtermcap_p.a ${DESTDIR}/lib/libtermlib_p.a +# $(RANLIB) ${DESTDIR}/lib/libtermcap_p.a + +tags: + cwd=`pwd`; \ + for i in ${SRCS}; do \ + ctags -a -f ${TAGSFILE} $$cwd/$$i; \ + done + +clean: + -rm -f *.o profiled/*.o + -rm -f ../libtermcap.a ../libtermcap_p.a + -rm -f termcap/termcap + +VGRIND= csh /usr/ucb/vgrind +vgrind: + cp /dev/null index + ${VGRIND} -h "Termcap library" termcap.c tputs.c tgoto.c + ${VGRIND} -h "Termcap library" -x index diff --git a/src/libtermlib/tc1.c b/src/libtermlib/tc1.c new file mode 100644 index 0000000..e5071ed --- /dev/null +++ b/src/libtermlib/tc1.c @@ -0,0 +1,26 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +/* + * tc1 [term] + * dummy program to test termlib. + * gets entry, counts it, and prints it. + */ +#include +char buf[1024]; +char *getenv(); + +main(argc, argv) char **argv; { + char *p; + int rc; + + if (argc < 2) + p = getenv("TERM"); + else + p = argv[1]; + rc = tgetent(buf,p); + printf("tgetent returns %d, len=%d, text=\n'%s'\n",rc,strlen(buf),buf); +} diff --git a/src/libtermlib/tc2.c b/src/libtermlib/tc2.c new file mode 100644 index 0000000..2a19835 --- /dev/null +++ b/src/libtermlib/tc2.c @@ -0,0 +1,53 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +/* + * tc2 [term] + * Dummy program to test out termlib. + * Commands are "tcc\n" where t is type (s for string, f for flag, + * or n for number) and cc is the name of the capability. + */ +#include +char buf[1024]; +char *getenv(), *tgetstr(); + +main(argc, argv) char **argv; { + char *p, *q; + int rc; + char b[3], c; + char area[200]; + + if (argc < 2) + p = getenv("TERM"); + else + p = argv[1]; + rc = tgetent(buf,p); + for (;;) { + c = getchar(); + if (c < 0) + exit(0); + b[0] = getchar(); + if (b[0] < ' ') + exit(0); + b[1] = getchar(); + b[2] = 0; + getchar(); + switch(c) { + case 'f': + printf("%s: %d\n",b,tgetflag(b)); + break; + case 'n': + printf("%s: %d\n",b,tgetnum(b)); + break; + case 's': + q = area; + printf("%s: %s\n",b,tgetstr(b,&q)); + break; + default: + exit(0); + } + } +} diff --git a/src/libtermlib/tc3.c b/src/libtermlib/tc3.c new file mode 100644 index 0000000..7563a41 --- /dev/null +++ b/src/libtermlib/tc3.c @@ -0,0 +1,78 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +/* + * tc3 [term] + * Dummy program to test out termlib. + * Input two numbers and it prints out the tgoto string generated. + */ +#include +char buf[1024]; +char *getenv(), *tgetstr(); +char *rdchar(); +char *tgoto(); +char *CM; +char cmbuff[30]; +char *x; +char *UP; +char *tgout; + +main(argc, argv) char **argv; { + char *p; + int rc; + int row, col; + + if (argc < 2) + p = getenv("TERM"); + else + p = argv[1]; + rc = tgetent(buf,p); + x = cmbuff; + UP = tgetstr("up", &x); + printf("UP = %x = ", UP); pr(UP); printf("\n"); + if (UP && *UP==0) + UP = 0; + CM = tgetstr("cm", &x); + printf("CM = "); pr(CM); printf("\n"); + for (;;) { + if (scanf("%d %d", &row, &col) < 2) + exit(0); + tgout = tgoto(CM, row, col); + pr(tgout); + printf("\n"); + } +} + +pr(p) +register char *p; +{ + for (; *p; p++) + printf("%s", rdchar(*p)); +} + +/* + * rdchar: returns a readable representation of an ASCII char, using ^ notation. + */ +#include +char *rdchar(c) +char c; +{ + static char ret[4]; + register char *p; + + /* + * Due to a bug in isprint, this prints spaces as ^`, but this is OK + * because we want something to show up on the screen. + */ + ret[0] = ((c&0377) > 0177) ? '\'' : ' '; + c &= 0177; + ret[1] = isprint(c) ? ' ' : '^'; + ret[2] = isprint(c) ? c : c^0100; + ret[3] = 0; + for (p=ret; *p==' '; p++) + ; + return (p); +} diff --git a/src/libtermlib/tcattr.c b/src/libtermlib/tcattr.c new file mode 100644 index 0000000..f7e51e0 --- /dev/null +++ b/src/libtermlib/tcattr.c @@ -0,0 +1,35 @@ +// +// TODO: termios support +// +#if 0 +#include +#include + +int tcgetattr(int fd, struct termios *t) +{ + + return (ioctl(fd, TIOCGETA, t)); +} + +int tcsetattr(int fd, int opt, struct termios *t) +{ + struct termios localterm; + + if (opt & TCSASOFT) { + localterm = *t; + localterm.c_cflag |= CIGNORE; + t = &localterm; + } + switch (opt & ~TCSASOFT) { + case TCSANOW: + return (ioctl(fd, TIOCSETA, t)); + case TCSADRAIN: + return (ioctl(fd, TIOCSETAW, t)); + case TCSAFLUSH: + return (ioctl(fd, TIOCSETAF, t)); + default: + errno = EINVAL; + return (-1); + } +} +#endif diff --git a/src/libtermlib/termcap.c b/src/libtermlib/termcap.c new file mode 100644 index 0000000..b0b1943 --- /dev/null +++ b/src/libtermlib/termcap.c @@ -0,0 +1,351 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include +#include +#include +#include +#include +#include + +#define BUFSIZ 1024 +#define MAXHOP 32 /* max number of tc= indirections */ +#define E_TERMCAP "/etc/termcap" + +/* + * 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 */ + +/* + * 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. + */ +static int +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++; + } +} + +/* + * 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. + */ +static int +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) != 1) { + hopcount = 0; /* unwind recursion */ + return(0); + } + for (q=tcbuf; *q != ':'; q++) + ; + l = p - holdtbuf + strlen(q); + if (l > BUFSIZ) { + write(2, "Termcap entry too long\n", 23); + q[BUFSIZ - (p-tbuf)] = 0; + } + strcpy(p, q+1); + tbuf = holdtbuf; + hopcount = 0; /* unwind recursion */ + return(1); +} + +/* + * Get an entry for terminal name in buffer bp, + * from the termcap file. Parse is very rudimentary; + * we just notice escaped newlines. + */ +int +tgetent(bp, name) + char *bp, *name; +{ + register char *cp; + register int c; + register int i = 0, cnt = 0; + char ibuf[BUFSIZ]; + int tf; + + tbuf = bp; + tf = -1; +#ifndef V6 + cp = getenv("TERMCAP"); + /* + * 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 == '/') { + tf = open(cp, 0); + } else { + tbuf = cp; + c = tnamatch(name); + tbuf = bp; + if (c) { + strcpy(bp,cp); + return(tnchktc()); + } + } + } + if (tf < 0) + tf = open(E_TERMCAP, 0); +#else + tf = open(E_TERMCAP, 0); +#endif + 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,"Termcap entry too long\n", 23); + break; + } else + *cp++ = c; + } + *cp = 0; + + /* + * The real work for the match. + */ + if (tnamatch(name)) { + close(tf); + return(tnchktc()); + } + } +} + +/* + * 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. + */ +int +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. + */ +int +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); + } + } +} + +/* + * 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); +} + +/* + * 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)); + } +} diff --git a/src/libtermlib/termcap/Makefile b/src/libtermlib/termcap/Makefile new file mode 100644 index 0000000..6a3e4f2 --- /dev/null +++ b/src/libtermlib/termcap/Makefile @@ -0,0 +1,29 @@ +# +# Copyright (c) 1980 Regents of the University of California. +# All rights reserved. The Berkeley software License Agreement +# specifies the terms and conditions for redistribution. +# +# @(#)Makefile 5.2.4 (2.11BSD GTE) 1997/9/22 +# +# reorder gives an editor command for most common terminals +# (in reverse order from n'th to 1'st most commonly used) +# to move them to the front of termcap +# +DESTDIR = ../../.. + +termcap: reorder termcap.src + ex - termcap.src < reorder + +install: termcap + install -c -m 444 termcap ${DESTDIR}/etc/termcap + +tabset: FRC + rm -fr ${DESTDIR}/usr/share/tabset + mkdir ${DESTDIR}/usr/share/tabset + chmod 755 ${DESTDIR}/usr/share/tabset + install -c -m 444 tabset/* ${DESTDIR}/usr/share/tabset + +clean: + rm -f termcap + +FRC: diff --git a/src/libtermlib/termcap/README b/src/libtermlib/termcap/README new file mode 100644 index 0000000..bda82d5 --- /dev/null +++ b/src/libtermlib/termcap/README @@ -0,0 +1,42 @@ +To install this directory on your system: + +First determine a list of "common terminals" for your system. +This list will probably be small, and can be empty if you like, +but you should probably put your own terminal in it. + +Second, edit the editor script "reorder" to use this list instead +of the list built in to it. The changes will be evident from looking +at the script. Notice that the script contains the terminals in order +from least common to most common, since the move commands will move them +to the front in that order, the effect will be to put the most common +at the front of termcap since that's moved last. The s.* terminals +are specials, and although they don't have to go to the front, they are +probably quite common and really should go near the front. + +Third, if you are not a super user and cannot create the directory +/usr/share/tabset, make a corresponding directory somewhere you can and +add a line to reorder to globally change all /usr/share/tabset's to your +own path name. This change is better than just changing the termcap.src +file because it makes it easier to diff it from newer distributed versions. +Try to keep the source as is whenever possible, and put mungings into reorder. + +Now you can run "make install" which will create an /etc/termcap. Again, +if you aren't a super user change the cp command to put it where you can. +In this case you will have to redefine E_TERMCAP in "local/uparm.h", which +will probably be in subdirectories with the other UCB software. + + +Finally, if you make additions or fixes to termcap, please mail a note +explaining what you did with the fixed termcap entry (not the whole file, +please!) to me at one of the addresses below, so it can be incorporated +back into the original source. I will normally include anything unless +there is a good reason not to, but I reserve the right to redo it differently. + + ucbvax!termcap (uucp) + termcap@berkeley (Arpanet) +or + Kevin Layer + Computer Science Division + Evans Hall + University of California + Berkeley, California 94720 diff --git a/src/libtermlib/termcap/map3270 b/src/libtermlib/termcap/map3270 new file mode 100644 index 0000000..de5c073 --- /dev/null +++ b/src/libtermlib/termcap/map3270 @@ -0,0 +1,539 @@ +# /usr/share/misc/map3270 +# mail corrections and additions to "termcap" +# +# this file contains mappings between characters entered from the keyboard, +# and 3270 keys, for use by programs (like tn3270) doing 3270 emulation +# from unix. +# +# inside the single quotes, a caret ("^") introduces a control character +# sequence (rub out = ^?, by the way). also inside the single quotes, +# a backslash ('\') introduces an escaped character. Also, \n, \r, \t, +# are all as in c, and \E is another way of representing escape. +# +# NOTE that while we are defining lots of function, much of that +# function (ie: local editing keys) may not yet be available from +# tn3270. + + +3a | adm3a { + enter = '^m'; + clear = '^z'; + + nl = '^n' | '^^'; + tab = '^i'; + btab = '^b'; + left = '^h'; + right = '^l'; + up = '^k'; + down = '^j'; + home = '^@'; + + delete = '^d' | '^?'; + eeof = '^e'; + einp = '^w'; + insrt = '\E '; + dp = '^u'; + fm = '^y'; + + # pf keys + 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 = '^f13'; pfk14 = '^f14'; pfk15 = '^f15'; pfk16 = '^f16'; + pfk17 = '^f17'; pfk18 = '^f18'; pfk19 = '^f19'; pfk20 = '^f20'; + pfk21 = '^f21'; pfk22 = '^f22'; pfk23 = '^f23'; pfk24 = '^f24'; + + # program attention keys + pa1 = '^p1'; + pa2 = '^p2'; + pa3 = '^p3'; + + # other keys + cursel = '\E.'; + + # local control keys + + reset = '^t'; # well, there is a little confusion here... + master_reset = '^g'; + flinp = '^x'; + reshow = '^v'; # redisplay screen + escape = '^c'; # escape to telnet command mode + + # local editing keys + settab = '\E;'; + clrtab = '\E+'; + setmrg = '\E('; + sethom = '\E!'; + coltab = '\Ei'; + colbak = '\Eb'; + indent = '\El'; + undent = '\Eh'; + +} # end of adm3a + +920c | tvi920c { # tvi920c definitions... + + # command keys + enter = '^m'; + clear = '^z'; + + # cursor movement keys + nl = '^^'; + tab = '^i'; + btab = '^b'; + left = '^h'; + right = '^l'; + up = '^k'; + down = '^j'; + home = '^@'; + + # edit control keys + delete = '^?' | '^d'; + eeof = '^e'; + einp = '^w'; + insrt = '\E '; + dp = '^u'; + fm = '^y'; + + # program function keys + pfk1 = '^a@^m'; pfk2 = '^aA^m'; pfk3 = '^aB^m'; pfk4 = '^aC^m'; + pfk5 = '^aD^m'; pfk6 = '^aE^m'; pfk7 = '^aF^m'; pfk8 = '^aG^m'; + pfk9 = '^aH^m'; pfk10 = '^aI^m'; pfk11 = '^aJ^m' | '\E^a@^m'; + pfk12 = '^aj^m' | '\E^aA^m'; + pfk13 = '\E^aB^m'; pfk14 = '\E^aC^m'; pfk15 = '\E^aD^m'; pfk16 = '\E^aE^m'; + pfk17 = '\E^aF^m'; pfk18 = '\E^aG^m'; pfk19 = '\E^aH^m'; pfk20 = '\E^aI^m'; + pfk21 = '\E^a`^m'; pfk22 = '\E^aa^m'; pfk23 = '\E^ab^m'; pfk24 = '\E^ac^m'; + + # program attention keys + + pa1 = '^a`^m'; + pa2 = '^aa^m'; + pa3 = '^ab^m'; + + # miscellaneous 3270 keys + + cursel = '\E.'; + + # local control keys + + reset = '^t'; # there is some confusion here... + master_reset = '^g'; + flinp = '^x'; + reshow = '^v'; + escape = '^c'; # escape to telnet command mode + + # local editing keys + + settab = '\E;'; + clrtab = '\E:'; + setmrg = '\E*'; + sethom = '\E!'; + coltab = '\Ei' | '\EI'; + colbak = '\Eb' | '\EB'; + indent = '\El' | '\EL'; + undent = '\Eh' | '\EH'; +} # end of tvi920c table... + +925 | tvi925 | 925vb | tvi925vb | televideo 925 { + + # command keys + + enter = '^m'; + clear = '^z'; + + # cursor movement keys + + nl = '^j'; + tab = '^i'; + btab = '\EI'; + left = '^h'; + right = '^l'; + up = '^k'; + down = '^v'; + home = '^^'; + + # edit control keys + + delete = '^?'; # that's rubout... + eeof = '^e'; + einp = '^w'; + insrt = '\E ' | '\EW'; + + # program function keys + + pfk1 = '^a@^m'; + pfk2 = '^aA^m'; + pfk3 = '^aB^m'; + pfk4 = '^aC^m'; + pfk5 = '^aD^m'; + pfk6 = '^aE^m'; + pfk7 = '^aF^m'; + pfk8 = '^aG^m'; + pfk9 = '^aH^m'; + pfk10 = '^aI^m'; + pfk11 = '^aJ^m'; + pfk12 = '\EQ'; + pfk13 = '\E^a@^m'; + pfk14 = '\E^aA^m'; + pfk15 = '\E^aB^m'; + pfk16 = '\E^aC^m'; + pfk17 = '\E^aD^m'; + pfk18 = '\E^aE^m'; + pfk19 = '\E^aF^m'; + pfk20 = '\E^aG^m'; + pfk21 = '\E^aH^m'; + pfk22 = '\E^aI^m'; + pfk23 = '\E^aJ^m'; + pfk24 = '\E\EQ'; + + # program attention keys + + pa1 = '^a`^m'; + pa2 = '^aa^m'; + pa3 = '^ab^m'; + + # other keys + + # local control keys + + reset = '^t'; # again, there is some confusion here... + master_reset = '^g'; + flinp = '^x'; + reshow = '^b'; + escape = '^c'; # escape to telnet command mode + +# local editing keys + + settab = '\EY'; + deltab = '\Ey'; + clrtab = '\E:'; + setmrg = '\ET'; + sethom = '\Et'; + coltab = '^p'; + colbak = '^o'; + indent = '\ER'; + undent = '\EE'; +} + + +924 | tvi924 { + + # command keys + + enter = '^m'; + clear = '^z'; + + # cursor movement keys + + nl = '^j'; + tab = '^i'; + btab = '\EI'; + left = '^h'; + right = '^l'; + up = '^k'; + down = '^v'; + home = '^^'; + + # edit control keys + + delete = '^?'; # that's rubout... + eeof = '^e'; + einp = '^w'; + insrt = '\E ' | '\EW'; + dp = '^u'; + fm = '^y'; + + # program function keys + + pfk1 = '^a@^m'; + pfk2 = '^aA^m'; + pfk3 = '^aB^m'; + pfk4 = '^aC^m'; + pfk5 = '^aD^m'; + pfk6 = '^aE^m'; + pfk7 = '^aF^m'; + pfk8 = '^aG^m'; + pfk9 = '^aH^m'; + pfk10 = '^aI^m'; + pfk11 = '^aJ^m'; + pfk12 = '^aK^m'; + pfk13 = '\E^a@^m'; + pfk14 = '\E^aA^m'; + pfk15 = '\E^aB^m'; + pfk16 = '\E^aC^m'; + pfk17 = '\E^aD^m'; + pfk18 = '\E^aE^m'; + pfk19 = '\E^aF^m'; + pfk20 = '\E^aG^m'; + pfk21 = '\E^aH^m'; + pfk22 = '\E^aI^m'; + pfk23 = '\E^aJ^m'; + pfk24 = '\E^aK^m'; + + # program attention keys + + pa1 = '^a`^m'; + pa2 = '^aa^m'; + pa3 = '^ab^m'; + + # other keys + + # local control keys + + reset = '^t'; # again, there is some confusion here... + master_reset = '^g'; + flinp = '^x'; + reshow = '^b'; + escape = '^c'; # escape to telnet command mode + + # local editing keys + + settab = '\EY'; + deltab = '\Ey'; + clrtab = '\E:'; + setmrg = '\ET'; + sethom = '\Et'; + coltab = '^p'; + colbak = '^o'; + indent = '\ER'; + undent = '\EE'; +} + +#kb | h19 | heath | h19b | heathkit | heath-19 | z19 | zenith { + kb | h19 | heath | h19b | heathkit | z19 | zenith { #coughs on heath-19 +enter = '^m'; +clear = '^z'; + +nl = '^n' | '^?'; +tab = '^i'; +btab = '^b'; +left = '^h'; +right = '^l'; +up = '^k'; +down = '^j'; +home = '^@'; + +delete = '^d'; +eeof = '^e'; +einp = '^w'; +insrt = '\E '; + +# pf keys +pfk1 = '\E?p\E?q'; pfk2 = '\E?p\E?r'; pfk3 = '\E?p\E?s'; pfk4 = '\E?p\E?t'; +pfk5 = '\E?p\E?u'; pfk6 = '\E?p\E?v'; pfk7 = '\E?p\E?w'; pfk8 = '\E?p\E?x'; +pfk9 = '\E?p\E?y'; pfk10 = '\E?q\E?p'; pfk11 = '\E?q\E?q'; pfk12 = '\E?q\E?r'; +pfk13 = '\E?q\E?s'; pfk14 = '\E?q\E?t'; pfk15 = '\E?q\E?u'; pfk16 = '\E?q\E?v'; +pfk17 = '\E?q\E?w'; pfk18 = '\E?q\E?x'; pfk19 = '\E?q\E?y'; pfk20 = '\E?r\E?p'; +pfk21 = '\E?r\E?q'; pfk22 = '\E?r\E?r'; pfk23 = '\E?r\E?s'; pfk24 = '\E?r\E?t'; + +# program attention keys +pa1 = '\EP'; +pa2 = '\EQ'; +pa3 = '\ER'; + +# other keys +# cursel = '\E.'; # find out what this does +master_reset = '^g'; + +# local control keys + +reset = '^t'; # well, there is a little confusion here... +flinp = '^x'; +reshow = '^v'; # redisplay screen +escape = '^c'; # escape to telnet command mode + +# local editing keys +settab = '\E;'; +clrtab = '\E:'; +setmrg = '\E\''; +sethom = '\E!'; +coltab = '\Ei'; +colbak = '\Eb'; +indent = '\El'; +undent = '\Eh'; + +} # end of h19 + + +#co | c100 | concept | c100-4p | concept100 { +co | c100 | concept | concept100 { # coughs on c100-4p +enter = '^m'; +clear = '^z' | '^\2'; + +nl = '^n'; +tab = '^i'; +btab = '^b'; +left = '^h' | '\E>'; +right = '^l' | '\E='; +up = '^k' | '\E;'; +down = '^j' | '\E<'; +home = '\E?'; + +delete = '^d' | '^?' | '^\1'; +eeof = '^e' | '^\3'; +einp = '^w'; +insrt = '^\0'; + +# pf keys +pfk1 = '\E\E1' | '^\5'; pfk2 = '\E\E2' | '^\6'; pfk3 = '\E\E3' | '^\7'; +pfk4 = '\E\E4' | '^\8'; pfk5 = '\E\E5' | '^\9'; pfk6 = '\E\E6' | '^\:'; +pfk7 = '\E\E7' | '^\;'; pfk8 = '\E\E8' | '^\<'; pfk9 = '\E\E9' | '^\='; +pfk10 = '\E\E0' | '^\>'; pfk11 = '\E\E-' | '^\?'; pfk12 = '^\@'; +pfk13 = '^\A'; pfk14 = '^\B'; pfk15 = '^\)'; pfk16 = '^\*'; +pfk17 = '^\+'; pfk18 = '^\,'; pfk19 = '^\-'; pfk20 = '^\.'; +pfk21 = '^\/'; pfk22 = '^\C'; pfk23 = '^\D'; pfk24 = '^\E'; + +# program attention keys +pa1 = '^\%'; +pa2 = '^\&' | '\E+'; +pa3 = '^\\''; + +# other keys +cursel = '\E.'; +aplon = '\E{'; +aplend = '\E}'; +aploff = '\E_'; +master_reset = '^g'; + +# local control keys + +reset = '^t'; # well, there is a little confusion here... +flinp = '^x'; +reshow = '^v'; # redisplay screen +escape = '^c'; # escape to telnet command mode + +# local editing keys +settab = '\E\E;'; +clrtab = '\E\E:'; +setmrg = '\E\E*'; +sethom = '\E\E!'; +coltab = '\E\Ei'; +colbak = '\E\Eb'; +indent = '\E\El'; +undent = '\E\Eh'; + +} # end of concept +avt | vt100 | vt100nam | pt100 | vt125 | vt102 | direct831 { +enter = '^m'; +clear = '^z' | '\EOM'; # Keypad enter key + +nl = '^?'; +tab = '^i'; +btab = '^b'; +left = '^h' | '\E[D' | '\EOD'; # Arrow key (application/numeric modes) +right = '^l' | '\E[C' | '\EOC'; # Arrow key (application/numeric modes) +up = '^k' | '\E[A' | '\EOA'; # Arrow key (application/numeric modes) +down = '^j' | '\E[B' | '\EOB'; # Arrow key (application/numeric modes) +home = '\EOn'; # Keypad period key + +delete = '^d'; +eeof = '^e'; +einp = '^w'; +insrt = '^ '; + +# pfk keys +# Keypad digits 1-9 correspond to pf keys 1-9 +pfk1 = '\EOq' | '\E1'; pfk2 = '\EOr' | '\E2'; pfk3 = '\EOs' | '\E3'; +pfk4 = '\EOt' | '\E4'; pfk5 = '\EOu' | '\E5'; pfk6 = '\EOv' | '\E6'; +pfk7 = '\EOw' | '\E7'; pfk8 = '\EOx' | '\E8'; pfk9 = '\EOy' | '\E9'; + +# Keypad digits 0-9 prefixed by pf1 (gold key) correspond to pfk10-19 +pfk10 = '\EOP\EOp' | '\E0'; pfk11 = '\EOP\EOq' | '\E-'; +pfk12 = '\EOP\EOr' | '\E='; pfk13 = '\EOP\EOs' | '^f13'; +pfk14 = '\EOP\EOt' | '^f14'; pfk15 = '\EOP\EOu' | '^f15'; +pfk16 = '\EOP\EOv' | '^f16'; pfk17 = '\EOP\EOw' | '^f17'; +pfk18 = '\EOP\EOx' | '^f18'; pfk19 = '\EOP\EOy' | '^f19'; + +# Keypad digits 0-9 prefixed by pf2 correspond to pfk20,21 +pfk20 = '\EOQ\EOp' | '^f20'; pfk21 = '\EOQ\EOq' | '^f21'; + +# program attention keys +pa1 = '\E\EOP' | '^p1'; # pa1 is Escape pf1 +pa2 = '\E\EOQ' | '^p2'; # pa2 is Escape pf2 + +# local control keys + +reset = '^t'; # well, there is a little confusion here... +flinp = '^x'; +reshow = '^v'; # redisplay screen +escape = '^c'; # escape to telnet command mode +master_reset = '^g'; + +# local editing keys +settab = '\E;'; # Escape key +deltab = '\E\''; # Escape \ +clrtab = '\E:'; # Escape : +setmrg = '\E,'; # Escape , +sethom = '\E.'; # Escape . +coltab = '\E\E[B' | '\E\EOB'; # Escape down-arrow +colbak = '\E\E[A' | '\E\EOA'; # Escape up-arrow +indent = '\E\E[C' | '\E\EOC'; # Escape right-arrow +undent = '\E\E[D' | '\E\EOD'; # Escape left-arrow +} # end of vt100, etc. + +tvipt | vp | televideopt { + enter = '^m'; + clear = '^z'; + + nl = '^n'; + tab = '^i'; + btab = '^b'; + left = '^h'; + right = '^l'; + up = '^k'; + down = '^j'; + home = '^^'; + + delete = '^?'; + eeof = '^e'; + einp = '^w'; + insrt = '\E '; + + # pf keys + pfk1 = '\E1' | '^A@^m'; + pfk2 = '\E2' | '^AA^m'; + pfk3 = '\E3' | '^AB^m'; + pfk4 = '\E4' | '^AC^m'; + pfk5 = '\E5' | '^AD^m'; + pfk6 = '\E6' | '^AE^m'; + pfk7 = '\E7' | '^AF^m'; + pfk8 = '\E8'; + pfk9 = '\E9'; + pfk10 = '\E0'; + pfk11 = '\E!' | '\E^A@^m'; + pfk12 = '\E@' | '\E^AA^m'; + pfk13 = '\E#' | '\E^AB^m'; + pfk14 = '\E$' | '\E^AC^m'; + pfk15 = '\E%' | '\E^AD^m'; + pfk16 = '\E^AE^m' | '\E\^'; + pfk17 = '\E&' | '\E^AF^m'; + pfk18 = '\E*'; + pfk19 = '\E('; + pfk20 = '\E)'; + + # program attention keys + pa1 = '^AG^m'; + pa2 = '^AH^m'; + pa3 = '^AI^m'; + + # other keys +# # cursel = '\E.'; + + # local control keys + + reset = '^t'; # well, there is a little confusion here... + master_reset = '^g'; + flinp = '^x'; + reshow = '^v'; # redisplay screen + escape = '^c'; # escape to telnet command mode + + # local editing keys + settab = '\E;'; + clrtab = '\E:'; + setmrg = '\E['; + sethom = '\E+'; + coltab = '\Ei' | '\EI'; + colbak = '\Eb' | '\EB'; + indent = '\El' | '\EL'; + undent = '\Eh' | '\EH'; +} # end of tvipt diff --git a/src/libtermlib/termcap/reorder b/src/libtermlib/termcap/reorder new file mode 100644 index 0000000..8964771 --- /dev/null +++ b/src/libtermlib/termcap/reorder @@ -0,0 +1,40 @@ +$r termcap.local +/|c100|/;.,/^[^ ]/-m9 +/|c100-rv|/;.,/^[^ ]/-m9 +/|c100-rv-pp|/;.,/^[^ ]/-m9 +/|c108-4p|/;.,/^[^ ]/-m9 +/|c108-rv-4p|/;.,/^[^ ]/-m9 +/|c108-8p|/;.,/^[^ ]/-m9 +/|c108-rv-8p|/;.,/^[^ ]/-m9 +/|avt|/;.,/^[^ ]/-m9 +/|avt-rv|/;.,/^[^ ]/-m9 +/|avt-4p-s|/;.,/^[^ ]/-m9 +/|avt-8p-s|/;.,/^[^ ]/-m9 +/|sun-17|/;.,/^[^ ]/-m9 +/|sun-24|/;.,/^[^ ]/-m9 +/|sun-34|/;.,/^[^ ]/-m9 +/|sun-48|/;.,/^[^ ]/-m9 +/|sun-s-e|/;.,/^[^ ]/-m9 +/|sun-s|/;.,/^[^ ]/-m9 +/|sun-e|/;.,/^[^ ]/-m9 +/|sun|/;.,/^[^ ]/-m9 +/|xterms|/;.,/^[^ ]/-m9 +/|xterm|/;.,/^[^ ]/-m9 +/|adm3|/;.,/^[^ ]/-m9 +/|adm31|/;.,/^[^ ]/-m9 +/|adm3a|/;.,/^[^ ]/-m9 +/|vt100|/;.,/^[^ ]/-m9 +/|vt220|/;.,/^[^ ]/-m9 +/|2645|/;.,/^[^ ]/-m9 +/|2621-nl|/;.,/^[^ ]/-m9 +/|2621|/;.,/^[^ ]/-m9 +/|h29|/;.,/^[^ ]/-m9 +/|h19|/;.,/^[^ ]/-m9 +/|h19-u|/;.,/^[^ ]/-m9 +/|h19-us|/;.,/^[^ ]/-m9 +/|h19-e|/;.,/^[^ ]/-m9 +/|h19-g|/;.,/^[^ ]/-m9 +/|5620|/;.,/^[^ ]/-m9 +/^s/;.,/^#/-m9 +w! termcap +q diff --git a/src/libtermlib/termcap/tabset/3101 b/src/libtermlib/termcap/tabset/3101 new file mode 100644 index 0000000..dab586b --- /dev/null +++ b/src/libtermlib/termcap/tabset/3101 @@ -0,0 +1 @@ +H 0 0 0 0 0 0 0 0 0 diff --git a/src/libtermlib/termcap/tabset/aa b/src/libtermlib/termcap/tabset/aa new file mode 100644 index 0000000..5784745 --- /dev/null +++ b/src/libtermlib/termcap/tabset/aa @@ -0,0 +1 @@ + 1 1 1 1 1 1 1 1 1  diff --git a/src/libtermlib/termcap/tabset/aed512 b/src/libtermlib/termcap/tabset/aed512 new file mode 100644 index 0000000..2c9d5fc --- /dev/null +++ b/src/libtermlib/termcap/tabset/aed512 @@ -0,0 +1 @@ +\EG1MMM.`40K0001202080K8001????00^L\EC80L80{80^L\EK010100????K0601??0000c818100\EG1HHH.\07210000019A27FD006A280D002A200A52429FE8524861086118612861360N031B4C3F3F1800N041B0C1B4C38301800N001B3B313030301800N011B3B313030341800N021B3B313030381800N050800N061B3B313335301800\07211000015A58E8D5011A58F8D5111A5908D5211A5918D531160\07212000015AD5011858EAD5111858FAD52118590AD5311859160\0721300004B2071C5858E0A18658E0A0A858EA900858F268FA5278590A50A29018591A9F51865908590A90165918591A59038E58E8590A591E58F290185912071C5180A0A0A0901858EA900858F268F60\0721350000BA9472031DEA9502031DE60\E\E\E\EG1MMM.^A diff --git a/src/libtermlib/termcap/tabset/beehive b/src/libtermlib/termcap/tabset/beehive new file mode 100644 index 0000000..6d30c69 --- /dev/null +++ b/src/libtermlib/termcap/tabset/beehive @@ -0,0 +1,2 @@ + +                                                                                diff --git a/src/libtermlib/termcap/tabset/diablo b/src/libtermlib/termcap/tabset/diablo new file mode 100644 index 0000000..8acc53f --- /dev/null +++ b/src/libtermlib/termcap/tabset/diablo @@ -0,0 +1,3 @@ + 9 +2 1 1 1 !1 )1 11 91 A1 I1 Q1 Y1 a1 i1 q1 y1 + 9 diff --git a/src/libtermlib/termcap/tabset/dtc382 b/src/libtermlib/termcap/tabset/dtc382 new file mode 100644 index 0000000..79257c3 --- /dev/null +++ b/src/libtermlib/termcap/tabset/dtc382 @@ -0,0 +1 @@ +  1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 \ No newline at end of file diff --git a/src/libtermlib/termcap/tabset/ibm3101 b/src/libtermlib/termcap/tabset/ibm3101 new file mode 100644 index 0000000..7e510ef --- /dev/null +++ b/src/libtermlib/termcap/tabset/ibm3101 @@ -0,0 +1 @@ +H 0 0 0 0 0 0 0 0 0 \ No newline at end of file diff --git a/src/libtermlib/termcap/tabset/std b/src/libtermlib/termcap/tabset/std new file mode 100644 index 0000000..e93f737 --- /dev/null +++ b/src/libtermlib/termcap/tabset/std @@ -0,0 +1 @@ + 3 1 1 1 1 1 1 1 1 1 1 1 1 1 diff --git a/src/libtermlib/termcap/tabset/stdcrt b/src/libtermlib/termcap/tabset/stdcrt new file mode 100644 index 0000000..66ba12f --- /dev/null +++ b/src/libtermlib/termcap/tabset/stdcrt @@ -0,0 +1 @@ + 3 1 1 1 1 1 1 1 1 1 \ No newline at end of file diff --git a/src/libtermlib/termcap/tabset/tandem653 b/src/libtermlib/termcap/tabset/tandem653 new file mode 100644 index 0000000..4588c34 --- /dev/null +++ b/src/libtermlib/termcap/tabset/tandem653 @@ -0,0 +1 @@ +3 1 1 1 1 1 1 1 1 1 1 diff --git a/src/libtermlib/termcap/tabset/teleray b/src/libtermlib/termcap/tabset/teleray new file mode 100644 index 0000000..46158f3 --- /dev/null +++ b/src/libtermlib/termcap/tabset/teleray @@ -0,0 +1 @@ +GY9(FY90FY98FY9@FY9HFY9PFY9XFY9`FY9hF \ No newline at end of file diff --git a/src/libtermlib/termcap/tabset/vt100 b/src/libtermlib/termcap/tabset/vt100 new file mode 100644 index 0000000..a65f743 --- /dev/null +++ b/src/libtermlib/termcap/tabset/vt100 @@ -0,0 +1,3 @@ + + +H H H H H H H H H H H H H H H H diff --git a/src/libtermlib/termcap/tabset/wyse-adds b/src/libtermlib/termcap/tabset/wyse-adds new file mode 100644 index 0000000..996ed66 --- /dev/null +++ b/src/libtermlib/termcap/tabset/wyse-adds @@ -0,0 +1,3 @@ +Setting tabs... 2 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 + + diff --git a/src/libtermlib/termcap/tabset/xerox1720 b/src/libtermlib/termcap/tabset/xerox1720 new file mode 100644 index 0000000..7437292 --- /dev/null +++ b/src/libtermlib/termcap/tabset/xerox1720 @@ -0,0 +1 @@ +2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 \ No newline at end of file diff --git a/src/libtermlib/termcap/tabset/xerox1730 b/src/libtermlib/termcap/tabset/xerox1730 new file mode 100644 index 0000000000000000000000000000000000000000..47da660ff7b099f1b4fa4f8a7e4aa3156644a783 GIT binary patch literal 222 zcmc)4p$dR76o%2+yn`Dog8WIFakiC-(WX(b7>!2XUcRUBgcE{%3qR4UK}Bt?Gs-Gu c*CaC~SwkK5G*Y5W3$3)%K^NWh(5vL}1F{bdYybcN literal 0 HcmV?d00001 diff --git a/src/libtermlib/termcap/tabset/xerox1730-lm b/src/libtermlib/termcap/tabset/xerox1730-lm new file mode 100644 index 0000000000000000000000000000000000000000..00b5ec5031c2f48d9ce9b7f819c87a697399d805 GIT binary patch literal 224 zcmc)Cp%Oq)5Jusv*|0$|WBx=FSG$D~HKG|s6h&{(c?u_d@uVbQ(@$wqr%`pOLslre c2AL^j6*SO74*?lwSYU%4PPpKPN8$DzU)78a!T - +# Certain abbreviations (e.g. c100 for concept100) are also allowed +# for upward compatibility. The part to the left of the dash, if a +# dash is present, describes the particular hardware of the terminal. +# The part to the right can be used for flags indicating special ROM's, +# extra memory, particular terminal modes, or user preferences. +# All names are always in lower case, for consistency in typing. +# +# The following are conventionally used flags: +# rv Terminal in reverse video mode (black on white) +# 2p Has two pages of memory. Likewise 4p, 8p, etc. +# w Wide - in 132 column mode. +# pp Has a printer port which is used. +# na No arrow keys - termcap ignores arrow keys which are +# actually there on the terminal, so the user can use +# the arrow keys locally. +# +# There are some cases where the same name is used for two different +# terminals, e.g. "teleray" or "2621" or "vt100". In these cases, +# if a site has one of these, they should choose a local default and +# bring that terminal to the front in the reorder script. This works +# because tgetent picks the first match in /etc/termcap. +# The list of names intentionally duplicated is: +# 2621, c108, dtc, hp2621, teleray, tvi, vt100. +# +# To easily test a new terminal description, put it in $HOME/.termcap +# and programs will look there before looking in /etc/termcap. +# You can also setenv TERMPATH to a list of full pathnames (separated +# by spaces or colons) to be searched by tgetent() in the order listed. +# The TERMCAP environment variable is usually set to the termcap +# entry itself to avoid reading files when starting up a program. +# +# If you absolutely MUST check for a specific terminal (this is discouraged) +# check for the 2nd entry (the canonical form) since all other codes are +# subject to change. The two letter codes are there for version 6 and are +# EXTREMELY subject to change, or even to go away if version 6 becomes for +# all practical purposes obsolete. We would much rather put in special +# capabilities to describe your terminal rather than having you key on the +# name. +# +# Special manufacturer codes: +# A: hardcopy daisy wheel terminals +# M: Misc. (with only a few terminals) +# q: Homemade +# s: special (dialup, etc.) +# +# Comments in this file begin with # - they cannot appear in the middle +# of a termcap entry. Individual entries are commented out by +# placing a period between the colon and the capability name. +# +# This file is to be installed with an editor script (reorder) +# that moves the most common terminals to the front of the file. +# If the source is not available, it can be constructed by sorting +# the above entries by the 2 char initial code. +# # -------------------------------- +# +# A: DAISY WHEEL PRINTERS +# +# The A manufacturer represents Diablo, DTC, Xerox, Qume, and other Daisy +# wheel terminals until such time as termcap distinguishes between them +# enough to justify separate codes. +# This is an "experimental" entry for the SRI Agiles. +# It has been tried in a minimal way -- the Agile did not blow up! +# However, it has not been exhaustively tested. +# Anyone who tries it and finds it wanting should get in touch with: +# Ralph Keirstead (ralph@sri-unix); +# EK352; SRI International; 333 Ravenswood Avenue; Menlo Park, CA 94025 +Aa|agile|agiles|sri agiles:\ + :bs:hc:os:pl:co#132:do=^J:kb=^H:up=\E\n:\ + :hu=\E0:hd=\E9:if=/usr/share/tabset/std:is=\EE\EF\EJ: +A6|1620|1720|450|ipsi|diablo 1620:\ + :do=^J:ct=\E2:st=\E1:ch=\E\t%i%.:\ + :if=/usr/share/tabset/xerox1720:\ + :kb=^H:le=^H:bs:co#132:hc:hu=\EU:hd=\ED:os:pt:up=\E\n: +A7|1620-m8|1640-m8|diablo 1620 w/8 column left margin:\ + :do=^J:co#124:is=\r \E9:tc=1620: +A8|1640|1740|630|1730|x1700|diablo|xerox|diablo 1640:\ + :if=/usr/share/tabset/xerox1730:\ + :us=\EE:ue=\ER:so=\EW:se=\E&:tc=1620: +Am|1640-lm|1740-lm|630-lm|1730-lm|x1700-lm|diablo-lm|xerox-lm|\ + diablo 1640 with idented left margin:\ + :if=/usr/share/tabset/xerox1730-lm:\ + :co#124:us=\EE:ue=\ER:so=\EW:se=\E&:tc=1620: +# DTC 382 with VDU. Has no cd so we fake it with ce. Standout works but +# won't go away without dynamite. The terminal has tabs, but I'm getting +# tired of fighting the braindamage. If no tab is set or the terminal's +# in a bad mood, it glitches the screen around all of memory. Note that +# return puts a blank ("a return character") in the space the cursor was +# at, so we use ^P return (and thus ^P newline for newline). Note also +# that if you turn off pt and let Unix expand tabs, curses won't work +# (current version) because it doesn't turn off this bit, and cursor +# addressing sends a tab for row/column 9. What a losing terminal! I +# have been unable to get tabs set in all 96 lines - it always leaves at +# least one line with no tabs in it, and once you tab through that line, +# it completely weirds out. +Ac|dtc|ps|dtc382|382:\ + :do=^J:al=^P^Z:am:le=^H:\ + :bs:co#80:ce=^P^U:cl=20^P^]:cm=%r^P^Q%.%.:dc=^X:\ + :dl=^P^S:ei=^Pi:ho=^P^R:im=^PI:ve=^Pb:vs=^PB:pc=\177:te=20^P^]:\ + :li#24:nd=^PR:.se=^P \200:.so=^P \002^PF:us=^P \020:ue=^P \200:\ + :up=^P^L:nc:xr:xs:da:db:.pt:cr=^P^M:cd=^P^U^P^S^P^S:\ + :if=/usr/share/tabset/dtc382: +Ad|dtc300s|300|300s|dtc 300s:\ + :ct=\E3:st=\E1:do=^J:\ + :kb=^h:le=^H:bs:co#132:hc:hu=\EH:hd=\Eh:os:pt:up=^Z: +Ag|gsi:\ + :le=^H:bs:co#132:hc:hd=\Eh:hu=\EH:os:pt:up=^Z:do=^J: +# This used to have :pl: - maybe they meant :pt:? +Aj|aj830|aj832|aj|anderson jacobson:\ + :do=^J:le=^H:bs:hc:hd=\E9:hu=\E8:os:up=\E7: +# From Chris Torek Thu, 7 Nov 85 18:21:58 EST +AJ|aj510|AJ510|Anderson-Jacobson model 510:\ + :ic=:ip=.1*:so=\E"I:us=\E"U:cd=\E'P:ce=\E'L:cl=^L:cm=\E#%+ %+ :\ + :dl=2*\E&D:ue=\E"U:co#80:li#24:se=\E"I:al=2*\E&I:im=\E'I:ei=\E'J:\ + :dc=.1*\E'D:up=\EY:nd=\EX:bs:am:mi:ti=\E"N:te=\E"N:\ + :ku=\EY:kd=\EZ:kl=\EW:kr=\EX:pc=\177: +# From cbosg!ucbvax!pur-ee!cincy!chris Thu Aug 20 09:09:18 1981 +# This is incomplete, but it's a start. +An|5520|nec|spinwriter|nec 5520:\ + :ct=\E3:st=\E1:do=^J:kb=^h:le=^H:bs:co#132:hc:hu=\E]s\E9\E]W:\ + :hd=\E]s\n\E]W:os:pt:up=\E9: +Aq|qume5|qume|Qume Sprint 5:\ + :ct=\E3:st=\E1:do=^J:\ + :kb=^h:le=^H:bs:co#80:hc:hu=\EH:hd=\Eh:os:pt:up=^Z: +Ar|q102|qume102|Qume 102:\ + :al=\EE:am:bs:bt=\EI:\ + :cd=\EY:ce=\ET:cl=^Z:cm=\E=%+ %+ :co#80:ct=\E3:\ + :dc=\EW:dl=\ER:do=^J:ei=:ho=^^:ic=\EQ:im=:\ + :k0=^A@\r:k1=^AA\r:k2=^AB\r:k3=^AC\r:kd=^J:kl=^H:kr=^L:ku=^K:\ + :le=^H:li#24:ma=^K^P^L :nd=^L:\ + :se=\EG0:sg#1:so=\EG4:st=\E1:\ + :ue=\EG0:ug#1:up=^K:us=\EG8: +# From ucbvax!mtxinu!sybase!tim (Tim Wood) Fri Sep 27 10:25:24 PDT 1985 +# This entry supports line and character insert and delete, scroll up and +# down and the arrow keys. To use it, perform the following on your qvt-101 +# 1) enter SET-UP mode, select the SET 3 line; +# 2) move the cursor to the EMULATION item and hit SPACE +# until QVT-101B appears +# 3) enter SHIFT-S +# 4) exit SET-UP - the terminal is now configured +Aq|q101|qvt101|qvt-101|Qume 101 $310 special:\ + :al=\EE:am:bt=\EI:ce=\Et:cl=\E*:dc=\EW:\ + :dl=\ER:do=^J:ic=\EQ:ei=:im=:md=\E(:me=\EG0:mh=\E):\ + :le=^H:bs:cm=\E=%+ %+ :cl=1^Z:co#80:ho=^^:li#24:ma=^K^P:nd=^L:ku=^K:\ + :vs=\EM4\040\200\200\200:mr=\EG4:ms:so=\EG4:se=\EG1: +# I suspect the xerox1720 is the same as the diablo 1620. +Ax|x1720|x1700|1700|x1750|xerox 1720:\ + :co#132:le=^H:bs:hc:os:pt:do=^J:ct=\E2:st=\E1: +# # -------------------------------- +# +# B: AT&T ATT +# +# AT&T Teletype 5410 Terminal (a.k.a. 4410) +# From: carvalho%kepler@Berkeley.EDU (Marcio de Carvalho) +# Date: Thu, 26 Feb 87 09:16:50 PST +# +# Although the 5410 supports labels, it blanks the screen after +# each label is programmed creating to much visual activity. +# To use the labels, use FL=\E[%d;00q%-16s +# +Ba|5410|4410|tty5410|att4410|AT&T Teletype 5410 terminal with 80 columns:\ + :al=\E[L:am:bs:cd=\E[J:ce=\E[K:cl=\E[H\E[J:\ + :cm=5\E[%i%2;%2H:co#80:dc=\E[P:dl=\E[M:im=:ei=:ic=\E[@:\ + :kd=\E[B:kh=\E[H:kl=\E[D:kr=\E[C:ku=\E[A:\ + :li#24:nd=\E[C:se=\E[m:so=\E[2;7m:sr=\EM:\ + :ue=\E[m:up=\E[A:us=\E[4m:EE=\E[m:BO=\E[0;7m:DS=\E[2m:\ + :KM=/usr/share/ua/kmap.5410:is=\E[0m^O\E[?6l:kn#8:\ + :k1=\EOc:k2=\EOd:k3=\EOe:k4=\EOf:k4=\EOg:k6=\EOh:\ + :k7=\EOi:k8=\EOj:ko=nd,up,ho: +# AT&T Teletype 5420 Terminal (a.k.a. 4415) June 5, 1985 +Bb|5420|4415|tty5420|att4415|AT&T Teletype 5420 terminal:\ + :al=\E[L:am:bs:cd=\E[J:ce=\E[K:cl=\E[H\E[J:\ + :cm=\E[%i%2;%2H:co#80:dc=\E[P:dl=\E[M:im=\E[4h:ei=\E[4l:\ + :kd=\E[B:kh=\E[H:kl=\E[D:kr=\E[C:ku=\E[A:\ + :li#24:nd=\E[C:se=\E[m:so=\E[2;7m:sr=\EM:\ + :ue=\E[m:up=\E[A:us=\E[4m:EE=\E[m:BO=\E[0;7m:DS=\E[2m:\ + :KM=/usr/share/ua/kmap.5420:\ + :is=\E[0m^O\E[1;2;3;4;6l\E[12;13;14;20l\E[?6;97;99l\E[?7h\E[4i\Ex\E[25;1j\212\E[8;0j\E[9;0j\E[10;0j\E[19;1j:\ + :db:mi:pt:kn#8:k1=\EOc:k2=\EOd:k3=\EOe:k4=\EOf:k5=\EOg:k6=\EOh:\ + :k7=\EOi:k8=\EOj:ve=\E[11;0j:\ + :vs=\E[11;1j:ko=bt,nd,up,dc,dl,ho,im,al: +# AT&T Teletype 5425 Terminal (a.k.a 4425) June 5, 1985 +Bc|5425|4425|tty5425|att4425|AT&T Teletype 5425:\ + :FL=\E[%d;00q%-16s\E~:FE=\E|:KM=/usr/share/ua/kmap.5425:\ + :is=\E[0m^O\E[1;2;3;4;6l\E[12;13;14;20l\E[?6l\E[?7h\E[4i\E[9;0j\E[10;0j\E[11;0j\E[21;1j\E[25;1j\212:\ + :ve=\E[12;0j:vs=\E[12;1j:tc=5420: +Bd|t4|4420|tty4420|Teletype 4420:\ + :vs=\ER:ve=\ER:am:da:db:mi:cr=\EG:\ + :im=:ei=:dm=:ed=:nl=\EG\EB:li#23:\ + :co#80:cl=\EH\EJ:cd=\EJ:cm=\EY%+ %+ :\ + :bs:up=\E7:do=\EB:nd=\EC:al=\EL:\ + :dl=\EM:dc=\EP:ic=\E\136:sf=\EH\EM\EY5 :sr=\ET:kb=^H: +Be|pc6300plus|6300|6300plus:\ + :al=\E[1L:am:bs:cd=\E[0J:ce=\E[0K:cl=\E[2J\E[H:cm=\E[%i%2;%2H:co#80:\ + :dc=\E[1P:dl=\E[1M:do=\E[B:ei=:ho=\E[H:\ + :ic=\E[1@:im=:kb=\10:kd=\E[B:kl=\E[D:kr=\E[C:ku=\E[A:li#24:\ + :k1=\EOc:k2=\EOd:k3=\EOe:k4=\EOf:k5=\EOg:k6=\EOh:k7=\EOi:k8=\EOj:\ + :k9=\EOk:k10=\EOu:nd=\E[C:se=\E[m:so=\E[7m:ue=\E[m:up=\E[A:us=\E[4m:\ + :EE=\E[m:BO=\E[0;7m:CV=\E[=C:CI=\E[=1C:KM=/usr/share/ua/kmap.s5: +Bf|s4|PC7300|unixpc|pc7300|7300|3b1|Safari 4:\ + :so=\E[2;7m:DS=\E[2m:XS=\E[9m:KM=/usr/share/ua/kmap.s4:tc=pc6300plus: +# AT&T Teletype 610 Terminal +Bg|b610|610|610bct|tty610:\ + :CV=\E[25h:CI=\E[25l:KM=/usr/share/ua/kmap.s4:\ + :FL=\E[%d;00q%-16s\E[0p:FE=\E[2p:cl=\E[1;1H\E[J:\ + :is=\E[0m^O\E[25;1|^J\E[8;0|\E[4;13;20l\E[?5l\E[12h\E[?7h\E[?4i:\ + :ve=\E[?12l:vs=\E[?12h:tc=5420: +# # -------------------------------- +# +# C: CONTROL DATA +# +Ca|cdc456|cdc:\ + :do=^J:li#24:co#80:cl=^Y^X:nd=^L:up=^Z:le=^H:bs:\ + :cm=\E1%+ %+ :ho=^Y:al=\E\114:dl=\E\112:ce=^V:cd=^X:am: +Cc|cdc456tst:\ + :do=^J:li#24:co#80:cl=^y^x:le=^H:bs:cm=\E1%+ %+ :am: +# # -------------------------------- +# +# D: DATAMEDIA +# +D0|dm1520|dm1521|1521|1520|datamedia 1520:\ + :do=^J:am:le=^H:bs:cd=^K:ce=^]:cl=^L:cm=^^%r%+ %+ :co#80:ho=^Y:\ + :ku=^_:kd=^J:kl=^H:kr=^\:kh=^Y:\ + :li#24:nd=^\:up=^_:xn:ma=^\ ^_^P^YH:pt: +D2|dm2500|datamedia2500|2500|datamedia 2500:\ + :do=^J:al=15^P\n^X^]^X^]:le=^H:bs:ce=^W:cl=^^^^\177:\ + :cm=^L%r%n%.%.:co#80:dc=10*^P\b^X^]:dl=10*^P^Z^X^]:\ + :dm=^P:ed=^X^]:ei=10\377\377^X^]:ho=^B:ic=10*^P^\^X^]:\ + :im=^P:li#24:nc:nd=^\:pc=\377:so@=^N:se=^X^]:up=^Z: +D3|dm3025|datamedia 3025a:\ + :MT:is=\EQ\EU\EV:do=^J:\ + :al=130\EP\n\EQ:le=^H:bs:cd=2\EJ:ce=\EK:cl=2\EM:cm=\EY%r%+ %+ :\ + :co#80:dc=6\b:dl=130\EP\EA\EQ:dm=\EP:ed=\EQ:ei=\EQ:ho=\EH:\ + :im=\EP:ip=6:li#24:nd=\EC:pt:so=\EO1:se=\EO0:up=\EA: +D4|3045|dm3045|datamedia 3045a:\ + :is=\EU\EV:do=^J:\ + :am:le=^H:bs:cd=2\EJ:ce=\EK:cl=2\EM:cm=\EY%r%+ %+ :co#80:\ + :dc=6\EB:dm=:ed=:ei=\EP:ho=\EH:ic=:im=\EP:ip=6:\ + :k0=\Ey\r:k1=\Ep\r:k2=\Eq\r:k3=\Er\r:k4=\Es\r:\ + :k5=\Et\r:k6=\Eu\r:k7=\Ev\r:k8=\Ew\r:k9=\Ex\r:\ + :kh=\EH:ku=\EA:kr=\EC:li#24:nd=\EC:pc=\177:pt:eo:ul:up=\EA:xn: +# dt80/1 is a vt100 lookalike, but it doesn't seem to need any padding. +D5|dt80|dmdt80|dm80|datamedia dt80/1:\ + :do=^J:cd=\E[J:ce=\E[K:cl=\E[2J\E[H:cm=%i\E[%d;%dH:ho=\E[H:\ + :nd=\E[C:sr=\EM:so=\E[7m:se=\E[m:up=\E[A:us=\E[4m:ue=\E[m:tc=vt100: +# except in 132 column mode, where it needs a little padding. +# This is still less padding than the vt100, and you can always turn on +# the ^S/^Q handshaking, so you can use vt100 flavors for things like +# reverse video. +D6|dt80w|dmdt80w|dm80w|datamedia dt80/1 in 132 char mode:\ + :do=^J:cd=20\E[0J:co#132:ce=20\E[0K:\ + :cm=5\E[%i%d;%dH:cl=50\E[H\E[2J:up=5\E[A:tc=dmdt80: +# # -------------------------------- +# +# H: HAZELTINE +# +# Since nd is blank, when you want to erase something you +# are out of luck. You will have to do ^L's a lot to +# redraw the screen. h1000 is untested. It doesn't work in +# vi - this terminal is too dumb for even vi. (The code is +# there but it isn't debugged for this case.) +H1|h1000|hazeltine 1000:\ + :le=^H:bs:ho=^K:cl=^L:nd= :co#80:li#12:do=^J: +# Note: the h1552 appears to be the first Hazeltine terminal which +# is not braindamaged. It has tildes and backprimes and everything! +# Be sure the auto lf/cr switch is set to cr. +H2|h1552|hazeltine 1552:\ + :do=^J:al=\EE:dl=\EO:k1=\EP:l1=blue:k2=\EQ:\ + :l2=red:k3=\ER:l3=green:tc=vt52: +H3|h1552rv|hazeltine 1552 reverse video:\ + :do=^J:so=\ES:se=\ET:tc=h1552: +# From cbosg!ucbvax!pur-ee!cincy!chris Thu Aug 20 09:09:18 1981 +H4|h1420|hazeltine 1420:\ + :do=^J:le=^H:bs:am:li#24:co#80:al=\E^Z:dl=\E^S:cd=\E^X:cl=\E\034:\ + :up=\E^L:nd=^P:ce=\E^O:ta=^N:cm=\E^Q%r%.%+ :so=\E\037:se=\E^Y: +H5|h1500|hazeltine 1500:\ + :do=^J:al=40~^Z:am:le=^H:bs:cd=10~^X:ce=~^O:cl=~^\:cm=~^Q%r%.%.:\ + :co#80:dl=40~^S:do=~^K:hz:li#24:nd=^P:.se=~^_:.so=~^Y:up=~^L: +# h1510 assumed to be in sane escape mode. Else use h1500. +H6|h1510|hazeltine 1510:\ + :do=^J:al=\E^Z:am:le=^H:bs:cd=\E^X:ce=\E^O:cl=\E^\:cm=\E^Q%r%.%.:\ + :co#80:dl=\E^S:do=\E^K:hz:li#24:nd=^P:.se=\E^_:.so=\E^Y:up=\E^L: +H8|h1520|hazeltine 1520:\ + :do=^J:al=~^Z:am:le=^H:bs:cd=~^X:ce=~^O:cl=~\034:cm=~^Q%r%.%.\200:\ + :co#80:dl=~^S:do=~^K:hz:li#24:nd=^P:se=~^Y:so=~\037:up=~^L:ho=~^R: +# Note: h2000 won't work well because of a clash between upper case and ~'s. +H7|h2000|hazeltine 2000:\ + :do=^J:al=6~^z:am:le=^H:bs:cl=6~^\:cm=~^q%r%.%.:co#74:\ + :dl=6~^s:ho=~^r:li#27:nc:pc=\177: +# Hazeltine esprit entries from Univ of Utah Tue Feb 1 06:39:37 1983 +# J.Lepreau, lepreau@utah-cs, harpo!utah-cs!lepreau +HE|esprit|hazeltine esprit:\ + :al=40\E^Z:bs:cd=5\E^X:ce=\E^O:cl=\E^\:cm=\E^Q%r%>^^ %+`%+`:co#80:\ + :dl=40\E^S:do=\E^K:ho=\E^R:li#24:nd=^P:se=\E^Y:so=\E^_:up=\E^L: +HF|esprit-am|hazeltine esprit auto-margin:\ + :am:tc=esprit: +# # -------------------------------- +# +# I: IBM +# +# ibm61 and ibm63 from Warren Gish (cswarren@violet.berkeley.edu). +# installed 12-17-86. +# 3161 only opens a new line if a null line exists on the screen. +# To ensure a null line exists, an SBA is performed, positioning the +# Buffer Address in column 0 of the last line. The last line is then +# cleared to nulls, BA mode is cancelled, and the new line is opened +# at the cursor position. +I1|ibm61|ibm3161|3161|IBM 3161-11:\ + :am:bs:bw:cl=\EL:li#24:co#80:cd=\EJ:al=\EX7 \EI\E Z\EN:\ + :ce=\EI:cm=\EY%+\040%+\040:nd=\EC:up=\EA:do=\EB:\ + :dl=\EO:dc=\EQ:kd=\EB:ku=\EA:kl=\ED:kr=\EC:kh=\EH:\ + :us=\E4\102:ue=\E4\100:so=\E4\110:se=\E4\100: +I3|ibm63|ibm3163|3163|i3163|IBM 3163:\ + :tc=ibm61: +I4|ibm|ibm3101|3101|i3101|IBM 3101-10:\ + :do=^J:ct=\EH:st=\E0:\ + :if=/usr/share/tabset/ibm3101:\ + :am:le=^H:bs:cl=\EK:li#24:co#80:nd=\EC:up=\EA:cd=\EJ:ce=\EI:\ + :kd=\EB:kl=\ED:kr=\EC:ku=\EA:ho=\EH:cm=\EY%+\40%+\40:pt: +Ia|ibm-apl|apl|IBM apl terminal simulator:\ + :li#25:tc=dm1520: +# ibmapa* and ibmmono entries come from ACIS 4.3 distribution +Ib|rtpc|ibmapa16|ibm6155|IBM 6155 Extended Monochrome Graphics Display:\ + :ts=\Ej\EY@%+ \Eo:ds=\Ej\EY@\40\EI\Ek:li#32:tc=ibmconsole: +# Advanced Monochrome (6153) and Color (6154) Graphics Display: +Ic|ibmapa8c|ibmapa8|ibm6154|ibm6153|IBM 6153/4 Advanced Graphics Display:\ + :ts=\Ej\EY?%+ \Eo:ds=\Ej\EY?\40\EI\Ek:li#31:tc=ibmconsole: +Id|ibmapa8c-c|ibm6154-c|IBM 6154 Advanced Color Graphics Display color termcap:\ + :ts=\Ej\EY?%+ \Eo:ds=\Ej\EY?\40\EI\Ek:li#31:mh=\EF\Ef7;:tc=ibmega-c: +Ie|ibmmono|ibmconsole|ibm5151|IBM workstation monochrome:\ + :se=\Ez:so=\EZ:sr=\EA:al=\EL:dl=\EM:\ + :kb=^H:us=\EW:ue=\Ew:\ + :k1=\ES:k2=\ET:k3=\EU:k4=\EV:k5=\EW:k6=\EP:k7=\EQ:k8=\ER:k9=\EY:\ + :k0=\E<:I0=f10:kI=\000:kh=\EH:kR=\EG:kP=\Eg:kF=\EE:kN=\EE:\ + :md=\EZ:me=\Ew\Eq\Ez\EB:mk=\EF\Ef0;\Eb0;:mr=\Ep:\ + :ts=\Ej\EY8%+ \Eo:fs=\Ek:ds=\Ej\EY8\40\EI\Ek:es:hs:sb:tc=ibm3101: +If|ibmega-c|ibm5154-c|IBM Enhanced Color Display color termcap:\ + :se=\EB:so=\EF\Ef3;:ue=\EB:us=\EF\Ef2;:tc=ibmconsole: +# # -------------------------------- +# +# M: MISCELLANEOUS TERMINALS +# +# The tab 132 uses xon/xoff, so no padding needed. +# ks/ke have nothing to do with arrow keys. +# is sets 80 col mode, normal video, autowrap on (for am). +# Seems to be no way to get rid of status line. +M0|abm80|amtek business machines 80:\ + :do=^J:al=\E^Z:am:le=^H:bs:cd=\E^X:ce=\E^O:cl=\E^\:cm=\E^Q%r%+ %+ :\ + :co#80:dl=\E^S:do=\E^K:li#24:nd=^P:.so=\E^_:.se=\E^Y:up=\E^L:\ + :bw:bt=^T:ho=\E^R: +M1|tab132|tab|tab132/15|tab 132/15:\ + :is=\E[?7h\E[?3l\E[?5l:dN@:ks@:ke@:do=^J:\ + :da:db:al=\E[L:dl=\E[M:dc=\E[P:ei=\E[4l:im=\E[4h:cm=\E[%i%d;%dH:\ + :ku=\E[A:kd=\E[B:kl=\E[D:tc=vt100: +M2|tab132w:\ + :co#132:is=\E[?7h\E[?3h\E[?5l:tc=tab132: +M3|tab132rv:\ + :is=\E[?7h\E[?3l\E[?5h:tc=tab132: +M4|tab132wrv:\ + :is=\E[?7h\E[?3h\E[?5h:tc=tab132w: +# This used to say "de#001202" which presumably refers to the stty bits +# that need to be set for some version of Unix. We need the real delay +# requirements in MS. +M5|mw2|Multiwriter 2:\ + :do=^J:co#132:hc:os: +M6|trs80|trs-80|radio shack trs-80 Model I:\ + :do=^J:am:le=^H:bs:co#64:li#16: +M7|d800|Direct 800/A:\ + :do=^J:co#80:li#24:am:cl=\E[1;1H\E[2J:le=^H:bs:cm=\E[%i%d;%dH:\ + :nd=\E[C:up=\E[A:ce=\E[K:cd=\E[J:\ + :so=\E[7m:se=\E[0m:us=\E[4m:ue=\E[0m:xs:vs=\E[>12l:ve=\E[>12h:\ + :sf=\ED:sr=\EM:da:db:as=\E[1m:ae=\E[0m:ms:pt:\ + :kl=\E[D:kr=\E[C:ku=\E[A:kd=\E[B:\ + :k1=\EOP:k2=\EOQ:k3=\EOR:k4=\EOS:\ + :k5=\EOT:k6=\EOU:k7=\EOV:k8=\EOW: +M8|vc404|volker-craig 404:\ + :do=^J:am:le=^H:bs:cd=40^W:ce=20^V:cl=40^X:cm=^P%+ %+ :co#80:\ + :ho=40^Y:kd=^J:kl=^H:kr=^U:ku=^Z:li#24:ma=^Z^P^U :nd=^U:up=^Z: +M9|vc404-s|volker-craig 404 w/standout mode:\ + :do=^J:se=^O:so=^N:tc=vc404: +MA|vc404-na|volker-craig 404 w/no arrow keys:\ + :ma@:kr@:ku@:tc=vc404: +MB|vc404-s-na|volker-craig 404 w/standout mode and no arrow keys:\ + :se=^O:so=^N:tc=vc404-na: +# missing in vc303a and vc303 descriptions: they scroll 2 lines at a time +MC|vc303a|vc403a|volker-craig 303a:\ + :do=^J:am:le=^H:bs:ce=20^V:cl=40^X:co#80:ho=40^Y:kd=^J:kl=^H::kr=^U:\ + :ku=^Z:li#24:ll=^P^@W:nd=^U:ns:up=^Z: +MD|vc303|vc103|vc203|volker-craig 303:\ + :do=^J:am:le=^H:bs:cl=40^L:co#80:ho=40^K:kd=^J:kl=^H:\ + :kr=^I:ku=^N:li#24:ll=^O\200W:nd=^I:ns:up=^N: +# Test version for Falco ts-1. See "arpavax.hickman@ucb" for info +ME|falco|ts1|ts-1|falco ts-1:is=\Eu\E3:\ + :do=^J:al=\EE:am:bs:ce=\ET\EG0^h:cm=\E=%+ %+ :cl=\E*:cd=\EY:co#80:\ + :dc=\EW:dl=\ER:ei=\Er:ho=^^:im=\Eq:k0=^A0\r:kd=^J:kl=^H:pt:\ + :kr=^L:ku=^K:li#24:nd=^L:se=\Eg0:so=\Eg1:up=^K:us=\Eg1:ue=\Eg0: +MF|falco-p|falco ts-1sp|falco with paging option:\ + :is=\EZ\E3\E_c:\ + :al=\EE:am:bs:ce=\ET\EG0^H\Eg0:cl=\E*:cd=\EY:co#80:dc=\EW:\ + :dl=\ER:kd=\E[B:kl=\E[D:ei=\Er:im=\Eq:pt:db:\ + :kr=\E[C:ku=\E[A:li#24:nd=\E[C:se=\Eg0:so=\Eg4:\ + :up=\E[A:us=\Eg1:ti=\E_d:te=\E_b:\ + :ue=\Eg0:do=\E[B:cm=\E=%+ %+ :ms:kh=\E[H:da:mi:bt=\EI: +#NOTE: bg can scroll, it just would rather not (ns) - rwells 3/13/81. +# (Shouldn't you take out ns and put in an nl instead? - mrh) +MG|bg|bitgraph|BBN BitGraph terminal:\ + :do=^J:al=2*\E[L:bs:cd=150\E[J:ce=2\E[K:\ + :cl=150\E[H\E[J:cm=%i\E[%d;%dH:co#85:\ + :dl=2*\E[M:k0=\EP:k1=\EQ:k2=\ER:k3=\ES:kd=\EB:ke=\E>:kl=\ED:kr=\EC:\ + :ks=\E=:ku=\EA:li#64:nd=\E[C:ns:pt:se=\E[0m:so=\E[7m:up=\E[A:sf=280\n: +MH|d132|datagraphix|datagraphix 132a:\ + :do=^J:co#80:li#30:cl=^l:ho=\Et:da:db:sf=\Ev:sr=\Ew:\ + :up=\Ek:nd=\El:vs=\ex:ve=\Em\En:\ + :al=\E3:ic=\E5:dc=\E6:in:ic=\E5: +MI|soroc|Soroc 120:\ + :do=^J:cd=\EY:ce=\ET:cl=2\E*:ma=^K^P^R^L^L :\ + :kl=^H:ku=^K:kr=^L:kd=^J:tc=adm3a: +# From: ma179abu%sdcc3@sdcsvax.ucsd.edu (Bill Houle) +MI|iq140|soroc140|Soroc IQ140 with inverse & dim:\ + :ic=\EQ:dc=\EW:al=\EE:dl=\ER:ce=\ET:cd=\EY:cl=\E+:cm=\E=%+ %+ :\ + :up=^K:do=^J:le=^H:nd=^L:ho=^^:ta=\Ei:ma=^Kk^Jj^Hh^Ll^^h:am:bs:\ + :co#80:li#24:ei=:im=:kb=^H:kh=^^:ku=^K:kd=^J:kl=^H:kr=^L:\ + :k0=^AI:k1=^A@:k2=^AA:k3=^AB:k4=^AC:k5=^AD:k6=^AE:k7=^AF:\ + :k8=^AG:k9=^AH:se=\E:so=\E:us=\E):ue=\E(: +# tec is untested, and taken from CB/Unix virtual terminal driver. +# Upper case terminal, uses lower case for control sequences!!! +# The driver shows the C ~ operator used on CM coordinates. +# Without the terminal in front of me, I can't figure out what's +# going on, so I've dotted out the cm. Note there is no ~ in tgoto. +MJ|tec400|tec scope:\ + :do=^J:.cm=l%r%.%.:up=x:do=h:nd=g:le=w:ho=i:so={:se=|:sg#1:\ + :cl=f:al=e:dl=u:ic=d:dc=t:ce=c:cd=s: +# From ucbvax!geoff Mon Sep 21 21:15:45 1981 +# This entry has been tested. +MK|tec500|tec 500:\ + :do=^J:am:le=^H:bs:cm=\E=%+ %+ :cl=20^Z:\ + :co#80:ho=^^:li#24:nd=^L:up=^K:so=^]:se=^\: +# I would appreciate more information on this terminal, such as the +# manufacturer and the model number. There are too many tecs in here. +ML|tec:\ + :li#24:co#80:cl=^l:up=^k:nd=\037:\ + :am:le=^H:bs:ho=\036:ma=^K^P^_ :do=^J: +MM|teletec|Teletec Datascreen:\ + :do=^J:am:le=^H:bs:co#80:cl=^l:ho=^^:li#24:nd=^_:up=^k: +# From cbosg!ucbvax!SRC:george Fri Sep 11 22:38:32 1981 +MN|ampex|d80|dialogue|dialogue80|ampex dialogue 80:\ + :ct=\E3:st=\E1:do=^J:is=\EA:us=\El:ue=\Em:\ + :am:le=^H:bs:pt:cl=75\E*:cm=\E=%+ %+ :\ + :al=5*\EE:bt=\EI:ic=\EQ:im=:ei=:dl=5*\ER:dc=\EW:\ + :ce=\Et:cd=\Ey:so=\Ej:se=\Ek:li#24:co#80:nd=^L:up=^K: +# From: atd!dsd!rcb@ucbvax.berkeley.edu (Richard Bascove) +A2|a210|210|ampex210|ampex a210:\ + :am:bs:cl=\E*:cm=\E=%+ %+ :al=\EE:bt=\EI:ic=\EQ:im=:ei=:\ + :dl=\ER:dc=\EW:ho=^^:xn:ce=\Et:cd=\Ey:li#24:co#80:nd=^L:up=^K:\ + :pt:if=/usr/share/tabset/std:is=\EC\Eu\E'\E(\El\EA\E%\E{\E.2\EG0\Ed\En:\ + :kl=^H:kr=^L:kd=^V:ku=^K:kh=^^:hs:ts=\E.0\Eg\E}\Ef:fs=\E.2:\ + :kn#10:k0=^A0^M:k1=^A1^M:k2=^A2^M:k3=^A3^M:k4=^A4^M:k5=^A5^M:\ + :vb=\EU\EX\EU\EX\EU\EX\EU\EX:k6=^A6^M:k7=^A7^M:k8=^A8^M:k9=^A9^M:\ + :so=\EG4:se=\EG0:us=\EG8:ue=\EG0:ug#1:sg#1: +MO|digilog|333|digilog 333:\ + :le=^H:bs:co#80:ce=\030:ho=^n:li#16:nd=^i:up=^o:do=^J: +MP|ep48|ep4080|execuport 4080:\ + :am:le=^H:bs:os:co#80:hu=\036:hd=\034:do=^J: +MQ|ep40|ep4000|execuport 4000:\ + :am:le=^H:bs:os:co#136:hu=\036:hd=\034:do=^J: +MR|terminet1200|terminet300|tn1200|tn300|terminet|GE terminet 1200:\ + :co#120:hc:os:do=^J: +# AED 512 +# by giles Billingsley (gilesb%ucbcad@berkeley) +# rewritten 8/82 for newer AEDs and better operation of vi,etc. +MS|aed|AED|aed512|AED512|aed 512:\ + :db:co#64:li#40:cl=^L:bs:nd=\Ei0800\001:\ + :up=^K:ve=\E\E\E\E\E\E\E\072004=000200??\001:\ + :vb=\EK0001??0000K0001202080\001:\ + :us=\E\07200>8000140\001:ue=\E\07200>8000100\001:\ + :uc=\Ei???>l0800i0102\001:\ + :ti=\E\07200>8000140{<04<0??00001010L<0\072004=0002??00\001:\ + :te=\E\07200>8000100{804<0??00001000L80\072004=000200??\001:\ + :so=\E\07200>8000140[80C00\001:se=\E[00C80\001:\ + :is=\EG1MMM.`40K0001202080K8001????00^L\EC80L80{80^L\EK010100????K060\ +1??0000c818100\EG1HHH.\07210000019A27FD006A280D002A200A52429FE852486108611861\ +2861360N031B4C3F3F1800N041B0C1B4C38301800N001B3B313030301800N011B3B3130303418\ +00N021B3B313030381800N050800N061B3B313335301800\07211000015A58E8D5011A58F8D51\ +11A5908D5211A5918D531160\07212000015AD5011858EAD5111858FAD52118590AD531185916\ +0\0721300004B2071C5858E0A18658E0A0A858EA900858F268FA5278590A50A29018591A9F518\ +65908590A90165918591A59038E58E8590A591E58F290185912071C5180A0A0A0901858EA9008\ +58F268F60\0721350000BA9472031DEA9502031DE60\E\E\E\EG1MMM.^A: +zL|aed-ucb|AED-UCB|aed512-ucb|AED512-UCB|aed 512 w/o UCB ROM:\ + :db:co#64:li#40:cl=^L:bs:nd=\Ei0800\001:up=^K:\ + :ve=\E\E\E\E\E\E\E\072004=000200??\001:\ + :vb=\EK0001??0000K0001202080\001:\ + :us=\E\07200>8000140\001:ue=\E\07200>8000100\001:\ + :uc=\Ei???>l0800i0102\001:\ + :ti=\E\07200>8000140{<04<0??00001010L<0\072004=0002??00\001:\ + :te=\E\07200>8000100{804<0??00001000L80\072004=000200??\001:\ + :so=\E\07200>8000140[80C00\001:se=\E[00C80\001:\ + :if=/usr/share/tabset/aed512: +# CIT 80 - vt 100 emulator, the termcap has been modified to remove +# the delay times and do an auto tab set rather than the indirect +# file used in vt100. +MT|cit80|cit 80|Citoh 80:\ + :co#80:li#24:am:cl=\E[;H\EJ:bs:cm=\E[%i%2;%2H:nd=\E[C:up=\E[A:\ + :ce=\EK:cd=\EJ:is=\E>:ks=\E[?1h\E=:ke=\E[?1l\E>:\ + :ku=\EOA:kd=\EOB:kr=\EOC:kl=\EOD: +# From mtxinu!sybase!tim (Tim Wood) Fri Sep 27 09:39:12 PDT 1985 +# Alternate cit101 (vt100 em) file used in vt100. +# Uses 23 lines so can run citsys (like h19sys). +# 24 May 85 (mtxinu!sybase!tim) - removed 2-byte limit on 'cm' cursor +# coordinates otherwise there is garbling on long lines in +# co#132 mode; also added support for multipage memory on the Itoh. +MU|citc|Citoh fast vt100:\ + :co#80:li#23:am:cl=\E[;H\E[2J:bs:cm=\E[%i%d;%dH:nd=\E[C:up=\E[A:\ + :ce=\E[K:cd=\E[J:so=\E[7m:se=\E[m:us=\E[4m:ue=\E[m:\ + :is=\E>\E[?3l\E[?4l\E[?5l\E[?7h\E[?8h\E[3g\E[>5g:\ + :ks=\E[?1h\E=:ke=\E[?1l\E>:ku=\EOA:kd=\EOB:kr=\EOC:kl=\EOD:\ + :vb=\E[?5h\200\200\200\200\200\200\200\200\200\200\200\200\200\200\200\200\200\200\200\200\200\200\200\200\E[?5l:\ + :dc=\E[P:al=\E[L:im=:ei=:dl=\E[M:ic=\E[@:vs=\E7\E[U:ve=\E[V\E8:xn: +MV|cita|:\ + :co#80:li#23:am:cl=\E[;H\E[2J:bs:cm=\E[%i%d;%dH:nd=\E[C:up=\E[A:\ + :ce=\E[K:cd=\E[J:so=\E[7m:se=\E[m:us=\E[4m:ue=\E[m:\ + :is=\E>\E[?3l\E[?4l\E[?5l\E[?7h\E[?8h\E[3g\E[>5g:\ + :ks=\E[?1h\E=:ke=\E[?1l\E>:\ + :ku=\EOA:kd=\EOB:kr=\EOC:kl=\EOD:vs=\E7\E[U:ve=\E[V\E8:\ + :vb=\E[?5h\200\200\200\200\200\200\200\200\200\200\200\200\200\200\200\200\200\200\200\200\200\200\200\200\E[?5l:xn: +MW|cit101:li#24:vb@:tc=citc +MX|cit101b:li#24:tc=citc +Mh|cit500|cit-500|cit 500:\ + :co#80:li#40:cl=50\E[;H\E[2J:bs:am:cm=5\E[%i%2;%2H:nd=2\E[C:up=2\E[A:\ + :ce=3\E[K:cd=50\E[J:so=2\E[7m:se=2\E[m:us=2\E[4m:ue=2\E[m:\ + :is=\E(B\E)0\E>\E[?3l\E[?7h\E[?8h:ks=\E[?1h\E=:ke=\E[?1l\E>:\ + :if=/usr/share/tabset/vt100:ku=\EOA:kd=\EOB:kr=\EOC:kl=\EOD:\ + :kh=\E[H:k1=\EOP:k2=\EOQ:k3=\EOR:k4=\EOS:pt:sr=5\EM:xn:\ + :do=\ED:al=\E[L:dc=\E[P:dl=\E[M: +# Note several versions of blit. I don't know exactly what is what +# so please send me any corrections to this -- mrh +# From research!ikeya!rob Tue Aug 31 23:41 EDT 1982 +MY|blit|jerq|blit-pb|blit running teletype rom:\ + :do=^J:IC=\Ef%+ :DC=\Ee%+ :AL=\EF%+ :DL=\EE%+ :\ + :mi:dl=\EE!:ic=\Ef!:dc=\Ee!:al=\EF!:\ + :ce=\EK:cl=^L:cm=\EY%r%+ %+ :co#87:li#72:nd=\EC:\ + :up=\EA:ku=\EA:kd=\EB:kr=\EC:kl=\ED:kb=^H:am:ul:pt:eo: +MZ|cbblit|columbus enhanced tty blit:\ + :vb=\E^G:so=\EU!:se=\EV!:us=\EU":ue=\EV":cd=\EJ:\ + :im=\EQ:ei=\ER:ic@:co#88:sf=\EG:tc=blit: +Ma|oblit|ojerq|first version of blit rom:\ + :do=^J:AL=\Ef%+ :DL=\Ee%+ :mi:dl=\EE:ei=\ER:im=\EQ:dc=\EO:da:db:\ + :al=\EF:cd=\EJ:ce=\EK:cl=^L:cm=\EY%r%+ %+ :co#88:li#72:nd=\EC:\ + :up=\EA:vb=\E^G:am:ul:pt:eo: +Mb|daleblit|daleterm|blit running Dale DeJager's ROM:\ + :ku=\EA:kd=\EB:kr=\EC:kl=\ED:so=\EU!:se=\EV!:us=\EU":ue=\EV":\ + :da@:db@:tc=oblit: +Mc|datapoint|dp3|dp3360|datapoint 3360:\ + :do=^J:am:le=^H:bs:cd=^_:ce=^^:cl=^]^_:co#82:ho=^]:li#25:nd=^x:up=^z: +#From: cbosgd!utcs!romwa@ucbvax.berkeley.edu (mark dornfeld) +# This termcap is for the LANPAR Technologies VISION 3220 +# terminal. The function key definitions k0-k5 represent the +# edit keypad: FIND, INSERT HERE, REMOVE, SELECT, PREV SCREEN, +# NEXT SCREEN. The key definitions k6-k9 represent the PF1 to +# PF4 keys. +v0|v3220|LANPAR Vision II model 3220/3221/3222:\ + :co#80:li#24:cl=\E[H\E[J:bs:am:cm=\E[%i%d;%dH:nd=\E[C:up=\E[A:\ + :ce=\E[K:cd=\E[J:so=\E[7m:se=\E[m:us=\E[4m:ue=\E[m:\ + :is=\E>\E[?3l\E[?7h\E[?8h\E[p:ks=\E=:ke=\E>:\ + :kn#10:k0=\E[1~:k1=\E[2~:k2=\E[3~:k3=\E[4~:k4=\E[5~:k5=\E[6~:\ + :k6=\E[OP:k7=\E[OQ:k8=\E[OR:k9=\E[OS:\ + :ku=\E[A:kd=\E[B:kr=\E[C:kl=\E[D:\ + :kh=\E[H:pt:sr=\EM:xn:\ + :dl=\E[M:dc=\E[P:ei=\E[4l:al=\E[L:im=\E[4h:mi: +# From ucbvax!faletti (Faletti@Berkeley) +# FREEDOM 100 by Liberty Electronics USA, SF. +# :kh=^^: left out because it precludes using change-to-alternate-file in vi. +# Basic Freedom 100 entry, works with VI at 1200 baud. +Md|f100|freedom100|freedom|freedom 100 no padding:\ + :am:bs:bw:mi:ms:pt:co#80:kn#20:li#24:\ + :ct=\E3:st=\E1:is=\Eg\Ef\r\Ed:kr=^L:\ + :cl=^Z:do=^J:ho=^^:kb=^H:kl=^H:\:kd=^V:\ + :ko=dc,al,dl,cl,bt,ce,cd:ku=^K:le=^H:nd=^L:\ + :ch=\E]%+ :cm=\E=%+ %+ :cv=\E[%+ :sr=\Ej:up=^K:\ + :al=\EE:bt=\EI:cd=\EY:ce=\ET:dc=\EW:dl=\ER:ei=\Er:im=\Eq:\ + :se=\EG0:so=\EG4:ue=\EG0:us=\EG8:as=\E$:ae=\E%:\ + :vb=\Eb\200\200\Ed:\ + :k1=^A@\r:k2=^AA\r:k3=^AB\r:k4=^AC\r:k5=^AD\r:\ + :k6=^AE\r:k7=^AF\r:k8=^AG\r:k9=^AH\r:k0=^AI\r:\ + :hs:ts=\Eg\Ef:fs=\r:ds=\Eg\Ef\r: +Me|f100-rv|freedom100-rv|freedom-rv|freedom100 with reverse video at 1200:\ + :is=\Eg\Ef\r\Eb:vb=\Ed\200\200\Eb:tc=freedom100: +# VI at 9600 baud (or EMACS at 1200 -- but may be more than is needed for emacs) +Mf|f100-v|freedom100-v|freedom-v|freedom100 for 9600 vi or 1200 emacs:\ + :al=6.5*\EE:dl=11.5*\ER:\ + :vb=\Eb\200\200\200\200\200\200\200\200\200\200\200\200\200\200\200\Ed:\ + :tc=freedom100: +Mx|f100-v-rv|freedom100-v-rv|freedom-v-rv|freedom100 rev. vid. for 9600 vi:\ + :al=6.5*\EE:dl=11.5*\ER:is=\Eg\Ef\r\Eb:\ + :vb=\Ed\200\200\200\200\200\200\200\200\200\200\200\200\200\200\200\Eb:\ + :tc=freedom100: +# EMACS at 9600 baud -- this still needs some more work on the padding +My|f100-e|freedom100-e|freedom-e|freedom100 for 9600 emacs:\ + :al=8.5*\EE:dl=11.5*\ER:ip=6:\ + :vb=\Eb\200\200\200\200\200\200\200\200\200\200\200\200\200\200\200\Ed:\ + :tc=freedom100: +Mz|f100-e-rv|freedom100-e-rv|freedom-e-rv|freedom100 rev. vid. for emacs 9600:\ + :al=8.5*\EE:dl=11.5*\ER:ip=6:is=\Eg\Ef\r\Eb:\ + :vb=\Ed\200\200\200\200\200\200\200\200\200\200\200\200\200\200\200\Eb:\ + :tc=freedom100: +zM|f110-v|freedom110-v|freedom110 for 9600 vi or 1200 emacs:\ + :is=\Eg\Ef\r\Ed\EO:dc=\EO\EW:im=\EO\Eq:\ + :al=6.5*\EE:dl=11.5*\ER:\ + :vb=\Eb\200\200\200\200\200\200\200\200\200\200\200\200\200\200\200\Ed:\ + :tc=freedom100: +# (from kerch@lll-crg) +Q1|f200|freedom200| Freedom 200 VDT by Liberty Electronics :\ + :if=/usr/share/tabset/stdcrt:al=\EE:am:bs:bt=\EI:cd=\EY:\ + :ce=\ET:cl=^Z:cm=\E=%+ %+ :co#80:dc=\EW:dl=\ER:do=^V:\ + :ds=\Eh:ei=\Er:im=\Eq:is=\Eg\El\E\041\062:\ + :k1=^A@\r:k2=^AA\r:k3=^AB\r:k4=^AC\r:k5=^AD\r:\ + :k6=^AE\r:k7=^AE\r:k8=^AF\r:k9=^AG\r:kd=^V:kr=L:\ + :ku=^K:li#24:ms:nd=^L:se=\EG0:so=\EG4:sr=\Ej:\ + :te=\EJ\E\\2\E|\041\061^L^Y:ti=\E\\1\EK\E|\041\061L^Y:\ + :ts=\Ef:ue=\EG0:up=^K:us=\EG8:vb=\Eb\Ed:hs:i2=\E^O\Eg:\ + :ts=\Ef:fs=^M:ds=\E^N: +Mg|dg|dg6053|data general 6053:\ + :do=^J:am:le=^H:bs:cm=^P%r%.%.:cl=^L:ho=^H:nd=^S:\ + :up=^W:ce=^K:co#80:li#24: +# dg450 and dg200 from cornell +Mj|dg450|dg6134|data general 6134:\ + :nd=\030:bs@:tc=dg200: +Mk|dg200|data general Dasher 200:\ + :am:bc=^Y:bs=0:ce=^K:cl=^L:cm=^P%r%+\200%+\200:co#80:do=^Z:\ + :ho=^H:li#24:\ + :ll=\036FP0017:se=\036E:so=\036D:up=^W:\ + :is=\036O\036FQ2\036FB000\036FE\036FA\036FQ2: +# Note: lesser Dasher terminals will not work with vi because vi insists upon +# having a command to move straight down from any position on the bottom line +# and scroll the screen up, or a direct vertical scroll command. The 460 and +# above have both, the D210/211, for instance, has neither. We must use ANSI +# mode rather than DG mode because standard UNIX tty drivers assume that ^H is +# backspace on all terminals. This is not so in DG mode. +zF|dg460-ansi|Data General Dasher 460, ANSI-mode:\ + :al=\E[L:am:bs:cd=\E[J:ce=\E[K:cl=\E[2J:\ + :cm=\E[%i%2;%2H:co#80:dc=\E[P:dl=\E[M:do=\E[B:\ + :ei=:ho=\E[H:ic=\E[@:im=:ue=\E[05:ul:up=\E[A:us=\E[4m:is=\036F@:\ + :k0=\E[001z:k1=\E[002z:k2=\E[003z:k3=\E[004z:k4=\E[005z:k5=\E[006z:\ + :k6=\E[007z:k7=\E[008z:k8=\E[009z:k9=\E[00\:z:\ + :kb=\E[D:kd=\E[B:kh=\E[H:kl=\E[D:kr=\E[C:ku=\E[A:kn#6:\ + :l0=f1:l1=f2:l2=f3:l3=f4:l4=f5:l5=f6:l6=f7:l7=f8:l9=f10:\ + :le=^H:li#24:mb=\E[5m:me=\E[0m:mh=\E[2m:mr=\E[7m:ms:mu=\EW:\ + :nd=\E[C:nl=\ED:pt:se=\E[0m:sf=\E[S:so=\E[7m:sr=\E[T: +Mi|cdi|cdi1203:\ + :am:le=^H:bs:hc:os:co#80:dC#200:do=^J: +# ^S is an arrow key! Boy is this guy in for a surprise on v7! +Ml|sol:\ + :do=^J:am:le=^Y:ho=^H:bs:cm=\E^1%.\E^2%.:cl=^K:ho=^N:co#64:li#16:\ + :nd=^S:up=^W:kl=^A:kr=^S:ku=^W:kd=^Z:ma=^A^H^S ^W^P^Z^N: +Mn|xl83|Cybernex XL-83:\ + :do=^J:am:le=^H:bs:cd=62^P:ce=3^O:cl=62^L:cm=^W%+ %+ :co#80:ho=^K:\ + :kd=^J:kl=^H:ku=^N:li#24:up=^N:nd=^I: +Mo|omron|Omron 8025AG:\ + :do=^J:al=\EL:am:le=^H:bs:cd=\ER:co#80:ce=\EK:cl=\EJ:\ + :da:db:dc=\EP:dl=\EM:ho=\EH:li#24:nd=\EC:se=\E4:sf=\ES:\ + :so=\Ef:sr=\ET:up=\EA:ve=:vs=\EN: +Mp|plasma|plasma panel:\ + :am:le=^H:bs:cl=^L:co#85:ho=^^:li#45:nd=\030:up=\026:do=^J: +Mq|pty|psuedo teletype:\ + :do=^J:co#80:li#24:am:cl=\EJ:le=^H:bs:cm=\EG%+ %+ :nd=\EC:\ + :up=\EA:ce=\EK:cd=\EL:al=\EP:dl=\EN:ic=\EO:\ + :so=\Ea$:se=\Eb$:us=\Ea!:ue=\Eb!: +Mr|remote|virtual remote terminal:\ + :co#79:am@:nl@:tc=virtual: +Ms|swtp|ct82|southwest technical products ct82:\ + :do=^J:am:le=^d:bc=^d:\ + :al=^\^y:cd=^v:ce=^F:cl=^L:cm=%r^k%.%.:co#82:li#20:\ + :dl=^z:nd=^s:up=^a:so=^^^v:se=^^^F:dc=^\^h:ic=^\^x:ho=^p:\ + :ei=:sf=^n:sr=^o:ll=^c:im=:\ + :is=^\^r^^^s^^^d^]^w^i^s^^^]^^^o^]^w^r^i: +Mt|terak|Terak emulating Datamedia 1520:\ + :tc=dm1520: +Mu|sun|Sun Microsystems Workstation console:\ + :li#34:co#80:cl=^L:cm=\E[%i%d;%dH:nd=\E[C:up=\E[A:\ + :am:bs:mi:ms:pt:\ + :ce=\E[K:cd=\E[J:so=\E[7m:se=\E[m:\ + :kd=\E[B:kl=\E[D:ku=\E[A:kr=\E[C:kh=\E[H:\ + :k1=\EOP:k2=\EOQ:k3=\EOR:k4=\EOS:\ + :al=\E[L:dl=\E[M:im=:ei=:ic=\E[@:dc=\E[P:\ + :AL=\E[%dL:DL=\E[%dM: +# From john@ucbrenoir Tue Sep 24 13:14:44 1985 +Mu|sun-s|Sun Microsystems Workstation window with status line:\ + :hs:ts=\E]l:fs=\E\\:ds=\E]l\E\\:tc=sun: +Mu|sun-e-s|sun-s-e|Sun Microsystems Workstation with status hacked for emacs:\ + :hs:ts=\E]l:fs=\E\\:ds=\E]l\E\\:tc=sun-e: +M0|sun-48|Sun 48-line window:\ + :li#48:co#80:tc=sun: +M1|sun-34|Sun 34-line window:\ + :li#34:co#80:tc=sun: +M2|sun-24|Sun 24-line window:\ + :li#24:co#80:tc=sun: +M3|sun-17|Sun 17-line window:\ + :li#17:co#80:tc=sun: +M4|sun-12|Sun 12-line window:\ + :li#12:co#80:tc=sun: +M5|sun-1|Sun 1-line window for sysline:\ + :li#1:co#80:es:hs:ts=\r:fs=\E[K:ds=^L:tc=sun: +M6|sun-e|sun-nic|sune|Sun Microsystems Workstation without insert character:\ + :ic@:im@:ei@:tc=sun: +LS|apollo:\ + :al=\EI:am:bs:cd=\EJ:ce=\EK:ch=\EN%d:cl=^L:cm=\EM%+ %d):\ + :cv=\EO+ :dc=\EP:dl=\EL:do=\EB:ei=\ER:im=\EQ:mi:nd=\EC:se=\ET:sf=\EE:\ + :so=\ES:sr=\ED:te=\EX:ti=\EW:ue=\EV:up=\EA:us=\EU:co#88:li#53: +# Apollo termcaps from Gary Darland, goodmanc@garnet +LP|apollo_15P|apollo 15 inch display:\ + :dN@:tc=vt132: +LQ|apollo_19L|apollo 19 inch display:\ + :dN@:tc=vt132: +LR|apollo_color|apollo color display:\ + :dN@:tc=vt132: +Mv|virtual|VIRTUAL|cb unix virtual terminal:\ + :do=^J:co#80:li#24:am:cl=\E\112:le=^H:bs:cm=\E\107%r%.%.:nd=\E\103:\ + :up=\E\101:ce=\E\113:cd=\E\114:al=\E\120:dl=\E\116:im=:ei=:ic=\E\117:\ + :da:db:kl=\E\104:kr=\E\103:ku=\E\101:kd=\E\102:kh=\E\105:\ + :so=\E\141\004:se=\E\142\004:us=\E\141\001:ue=\E\142\001: +Mw|it2|intertube2|intertec data systems intertube 2:\ + :do=^J:am:bs:cl=^L:co#80:ho=^A:li#25:up=^Z:ce=\EK:\ + :cm=^N%+ %+ :ch=^P%\102%.:cv=^K%.:nd=^F:do=\n:ll=^K^X\r:\ + :so=\E0P:se=\E0@: +Mx|delta|dd5000|delta data 5000:\ + :do=^J:am:le=^H:bs:cl=^NR:cm=^O%\068%+9%\068%+9:co#80:li#27:\ + :ho=^NQ:nc:nd=^Y:up=^Z:ce=^NU:dc=^NV:ma=^K^J^Z^P^Y :xr: +My|mdl110|cybernex mdl-110:\ + :cm=^P%+ %+ :co#80:li#24:am:cl=70^X:le=^H:bs:do=^J:\ + :nd=^U:up=^Z:ho=^Y:ce=145^N@^V:cd=145^NA^W:al=65^NA^N^]:\ + :dl=40^NA^N^^:im=:ei=:ic=3.5^NA^]:dm=:ed=:dc=3.5^NA^^:\ + :so=^NF:se=^NG:ta=43\t:ma=^Z^P:cd=6^N@^V +Mz|zen30|z30|zentec 30:\ + :do=^J:mi:co#80:li#24:ma=^L ^R^L^K^P:ul:\ + :al=1.5*\EE:le=^H:bs:ce=1.0*\ET:cm=\E=%+ %+ :cl=\E*:\ + :ho=^^:nd=^L:se=\EG0:so=\EG6:up=^K:im=\Eq:ei=\Er:\ + :am:dc=\EW:dl=1.5*\ER:cd=\EY: +m0|modgraph|mod|Modgraph terminal emulating vt100, 24x80:\ + :xn@:rf@:sr=5\EM\E[K:vs=\E\^9;0s\E\^7;1s:\ + :is=\E\^9;0s\E\^7;1s\E[3g\E\^11;9s\E\^11;17s\E\^11;25s\E\^11;33s\E\^11;41s\E\^11;49s\E\^11;57s\E\^11;65s\E\^11;73s\E\^11;81s\E\^11;89s:\ + :tc=vt100: +# dmchat is like DM2500, but DOES need "all that padding" (jcm 1/31/82) +# also, has a meta-key (MT) +# from goldberger@su-csli.arpa +MX|dmchat|dmchat version of datamedia 2500:\ + :al=1*^P\n^X^]^X^]:\ + :MT:km:\ + :dl=2^P^Z^X^]:\ + :tc=dm2500: +#from Carol Block at ear (cblock@ear) +# +m7|mt70|m70|morrow mt70:\ + :is=EGO\E"5:\ + :cl=^Z:\ + :cm=\E=%+ %+ :\ + :do=^J:\ + :im=:ic=\EQ:ei:\ + :dm=:dc=\EW:ed=:\ + :kl=\034L:kr=\034M:ku=\034J:kd=\034K:\ + :so=\EG4:se=\EGO:\ + :us=\EG1:ue=\EGO:\ + :vs=\E"2:ve=\E"5\E(:\ + :tc=adm31: +# from keith bostic (bostic@monet) +# +m2|mod2|Modgraph GX-1000, set to 80x24, keypad not enabled:\ + :is=\E<\E\^5;2s\E\^7;1s\E[3g\E\^11;9s\E\^11;17s\E\^11;25s\E\^11;33s\E\^11;41s\E\^11;49s\E\^11;57s\E\^11;65s\E\^11;73s\E\^11;81s\E\^11;89s\E\^12;0s\E\^14;2s\E\^15;9s\E\^25;1s\E\^9;1s\E\^27;1:\ + :bs:cd=50\EJ:ce=3\EK:cl=50\EH\EJ:cm=5\EY%+ %+ :co#80:li#24:nd=2\EC:\ + :pt:sr=5\EI:up=2\EA:da:db:am: +S1|wsiris|iris40|iris emulating a 40 line visual 50 (approximately):\ + :am:al=\EL:is=\E7B0\E7F7\E7C2\E7R3:\ + :bs:cd=\EJ:ce=\EK:cl=\EH\EJ:ho=\EH:cm=\EY%+ %+ :co#80:li#40:nd=\EC:\ + :pt:sr=\EI:up=\EA:ku=\EA:kd=\EB:kr=\EC:kl=\ED:\ + :k0=\E0:k1=\E1:k2=\E2:k3=\E3:k4=\E4:k5=\E5:k6=\E6:k7=\E7:k8=\E8:k9=\E9:\ + :vs=\E;:ve=\E>:cl=\Ev:ho=\EH:dl=\EM:so=\E9P:se=\E0@:\ + :HS=\E7F2:HE=\E7F7:\ + :us=\E7R2\E9P:ue=\E7R3\E0@:\ + :CT#2:CZ=*Bblack,red,green,yellow,blue,magenta,cyan,*Fwhite: + +# # -------------------------------- +# +# N: ANN ARBOR +# +# Needs function keys added. +# Originally from Mike O'Brien@Rand and Howard Katseff at Bell Labs. +# Highly modified 6/22 by Mike O'Brien. +# split out into several for the various screen sizes by dave-yost@rand +# Modifications made 3/82 by Mark Horton +# Modified by Tom Quarles at UCB for greater efficiency and more diversity +# status line moved to top of screen, vb removed 5/82 +# +# assumes the following setup: +# A menu: 0000 1010 0001 0000 +# B menu: 9600 0100 1000 0000 0000 1000 0000 17 19 +# C menu: 56 66 0 0 9600 0110 1100 +# D menu: 0110 1001 1 0 +# +# Briefly, the settings are for the following modes: +# (values are for bit set/clear with * indicating our preference +# and the value used to test these termcaps) +# Note that many of these settings are irelevent to the termcap +# and are just set to the default mode of the terminal as shipped +# by the factory. +# +# A menu: 0000 1010 0001 0000 +# Block/underline cursor* +# blinking/nonblinking cursor* +# key click/no key click* +# bell/no bell at column 72* +# +# key pad is cursor control*/key pad is numeric +# return and line feed/return for key * +# repeat after .5 sec*/no repeat +# repeat at 25/15 chars per sec. * +# +# hold data until pause pressed/process data unless pause pressed* +# slow scroll/no slow scroll* +# Hold in area/don't hold in area* +# functions keys have default*/function keys disabled on powerup +# +# show/don't show position of cursor during page transmit* +# unused +# unused +# unused +# +# B menu: 9600 0100 1000 0000 0000 1000 0000 17 19 +# Baud rate (9600*) +# +# 2 bits of parity - 00=odd,01=even*,10=space,11=mark +# 1 stop bit*/2 stop bits +# parity error detection off*/on +# +# keyboard local/on line* +# half/full duplex* +# disable/do not disable keyboard after data transmission* +# +# transmit entire page/stop transmission at cursor* +# transfer/do not transfer protected characters* +# transmit all characters/transmit only selected characters* +# transmit all selected areas/transmit only 1 selected area* +# +# transmit/do not transmit line seperators to host* +# transmit/do not transmit page tab stops tabs to host* +# transmit/do not transmit column tab stop tabs to host* +# transmit/do not transmit graphics control (underline,inverse..)* +# +# enable*/disable auto XON/XOFF control +# require/do not require receipt of a DC1 from host after each LF* +# pause key acts as a meta key/pause key is pause* +# unused +# +# unused +# unused +# unused +# unused +# +# XON character (17*) +# XOFF character (19*) +# +# C menu: 56 66 0 0 9600 0110 1100 +# number of lines to print data on (printer) (56*) +# +# number of lines on a sheet of paper (printer) (66*) +# +# left margin (printer) (0*) +# +# number of pad chars on new line to printer (0*) +# +# printer baud rate (9600*) +# +# printer parity: 00=odd,01=even*,10=space,11=mark +# printer stop bits: 2*/1 +# print/do not print guarded areas* +# +# new line is: 01=LF,10=CR,11=CRLF* +# unused +# unused +# +# D menu: 0110 1001 1 0 +# LF is newline/LF is down one line, same column* +# wrap to preceeding line if move left from col 1*/don't wrap +# wrap to next line if move right from col 80*/don't wrap +# backspace is/is not destructive* +# +# display*/ignore DEL character +# display will not/will scroll* +# page/column tab stops* +# erase everything*/erase unprotected only +# +# editing extent: 0=display,1=line*,2=field,3=area +# +# unused +# +NA|aaa-unk|ann arbor ambassador (internal - don't use this directly):\ + :do=^J:al=3\E[L:am:le=^H:bs:\ + :cd=\E[J:ce=5\E[K:cl=156\E[H\E[J:cm=\E[%i%d;%dH:co#80:\ + :dc=4\E[P:dl=3\E[M:ho=\E[H:ic=4\E[@:\ + :md=\E[1m:mr=\E[7m:mb=\E[5m:mk=\E[8m:me=\E[m:\ + :ku=\EM:kd=\ED:kl=\E[D:kr=\E[C:kh=\E[H:ko=cl,dc,dl,ce,cd:\ + :ks=\EP`?z~[H~[[J`>z~[[J`8xz~[M`4xz~[[D`6xz~[[C`2xz~[D\E\\:\ + :ke=\EP`?y~[H~[[J`>y~[[2J`8xy~[M`4xy~[[D`6xy~[[C`2xy~[D\E\\:\ + :ch=\E[%i%d`:ei=:im=:pt:bw:bt=\E[Z:\ + :mi:nd=\E[C:se=\E[m:so=\E[7m:ue=\E[m:us=\E[4m:up=\EM: +NB|aaa-18|ann arbor ambassador/18 lines:\ + :ti=\E[2J\E[18;0;0;18p:te=\E[60;0;0;18p\E[18;1H\E[J:\ + :is=\EP`+x~M\E\\\E[m\E7\E[60;0;0;18p\E[3g\E[f\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E8\E[>6h\E[1Q:\ + :li#18:tc=aaa-unk: +NC|aaa-20|ann arbor ambassador/20 lines:\ + :ti=\E[2J\E[20;0;0;20p:te=\E[60;0;0;20p\E[20;1H\E[J:\ + :is=\EP`+x~M\E\\\E[m\E7\E[60;0;0;20p\E[3g\E[f\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E8\E[>6h\E[1Q:\ + :li#20:tc=aaa-unk: +ND|aaa-22|ann arbor ambassador/22 lines:\ + :ti=\E[2J\E[22;0;0;22p:te=\E[60;0;0;22p\E[22;1H\E[J:\ + :is=\EP`+x~M\E\\\E[m\E7\E[60;0;0;22p\E[3g\E[f\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E8\E[>6h\E[1Q:\ + :li#22:tc=aaa-unk: +NE|aaa-24|ann arbor ambassador/24 lines:\ + :ti=\E[2J\E[24;0;0;24p:te=\E[60;0;0;24p\E[24;1H\E[J:\ + :is=\EP`+x~M\E\\\E[m\E7\E[60;0;0;24p\E[3g\E[f\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E8\E[>6h\E[1Q:\ + :li#24:tc=aaa-unk: +NF|aaa-26|ann arbor ambassador/26 lines:\ + :ti=\E[2J\E[26;0;0;26p:te=\E[60;0;0;26p\E[26;1H\E[J:\ + :is=\EP`+x~M\E\\\E[m\E7\E[60;0;0;26p\E[3g\E[f\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E8\E[>6h\E[1Q:\ + :li#26:tc=aaa-unk: +NG|aaa-28|ann arbor ambassador/28 lines:\ + :ti=\E[2J\E[28;0;0;28p:te=\E[60;0;0;28p\E[28;1H\E[J:\ + :is=\EP`+x~M\E\\\E[m\E7\E[60;0;0;28p\E[3g\E[f\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E8\E[>6h\E[1Q:\ + :li#28:tc=aaa-unk: +NH|aaa|aaa-30|ambas|ambassador|ann arbor ambassador/30 lines:\ + :ti=\E[2J\E[30;0;0;30p:te=\E[60;0;0;30p\E[30;1H\E[J:\ + :is=\EP`+x~M\E\\\E[m\E7\E[60;0;0;30p\E[3g\E[f\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E8\E[>6h\E[1Q:\ + :li#30:tc=aaa-unk: +NI|aaa-36|ann arbor ambassador/36 lines:\ + :ti=\E[2J\E[36;0;0;36p:te=\E[60;0;0;36p\E[36;1H\E[J:\ + :is=\EP`+x~M\E\\\E[m\E7\E[60;0;0;36p\E[3g\E[f\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E8\E[>6h\E[1Q:\ + :li#36:tc=aaa-unk: +NJ|aaa-40|ann arbor ambassador/40 lines:\ + :ti=\E[2J\E[40;0;0;40p:te=\E[60;0;0;40p\E[40;1H\E[J:\ + :is=\EP`+x~M\E\\\E[m\E7\E[60;0;0;40p\E[3g\E[f\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E8\E[>6h\E[1Q:\ + :li#40:tc=aaa-unk: +NK|aaa-48|ann arbor ambassador/48 lines:\ + :ti=\E[2J\E[48;0;0;48p:te=\E[60;0;0;48p\E[48;1H\E[J:\ + :is=\EP`+x~M\E\\\E[m\E7\E[60;0;0;48p\E[3g\E[f\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E8\E[>6h\E[1Q:\ + :li#48:tc=aaa-unk: +NL|aaa-60|ann arbor ambassador/60 lines:\ + :ti=\E[2J\E[60;0;0;60p:te=\E[60;0;0;60p\E[60;1H\E[J:\ + :is=\EP`+x~M\E\\\E[m\E7\E[60;0;0;60p\E[3g\E[f\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E8\E[>6h\E[1Q:\ + :li#60:tc=aaa-unk: +NS|aaa-unk-s|ann arbor ambassador unknown with/status:\ + :es:hs:i2=\E7\E[>51h\E[H\E[2K\E[>51l\E8:\ + :ts=\E7\E[>51h\E[H\E[2K\E[%i%d`:fs=\E[>51l\E8:\ + :ds=\E7\E[>51h\E[H\E[2K\E[>51l\E8:\ + :tc=aaa-unk: +NM|aaa-18-s|ambassador|ann arbor ambassador/18 lines + status line:\ + :ti=\E[2J\E[18;1;0;18p:\ + :te=\E[60;1;0;18p\E[17;1H\E[J:\ + :is=\EP`+x~M\E\\\E[m\E7\E[60;1;0;18p\E[3g\E[f\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E8\E[>6h\E[1Q:\ + :li#17:tc=aaa-unk-s: +NN|aaa-20-s|ambassador|ann arbor ambassador/20 lines + status line:\ + :ti=\E[2J\E[20;1;0;20p:\ + :te=\E[60;1;0;20p\E[19;1H\E[J:\ + :is=\EP`+x~M\E\\\E[m\E7\E[60;1;0;20p\E[3g\E[f\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E8\E[>6h\E[1Q:\ + :li#19:tc=aaa-unk-s: +NO|aaa-22-s|ambassador|ann arbor ambassador/22 lines + status line:\ + :ti=\E[2J\E[22;1;0;22p:\ + :te=\E[60;1;0;22p\E[21;1H\E[J:\ + :is=\EP`+x~M\E\\\E[m\E7\E[60;1;0;22p\E[3g\E[f\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E8\E[>6h\E[1Q:\ + :li#21:tc=aaa-unk-s: +NP|aaa-24-s|ambassador|ann arbor ambassador/24 lines + status line:\ + :ti=\E[2J\E[24;1;0;24p:\ + :te=\E[60;1;0;24p\E[23;1H\E[J:\ + :is=\EP`+x~M\E\\\E[m\E7\E[60;1;0;24p\E[3g\E[f\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E8\E[>6h\E[1Q:\ + :li#23:tc=aaa-unk-s: +NQ|aaa-26-s|ambassador|ann arbor ambassador/26 lines + status line:\ + :ti=\E[2J\E[26;1;0;26p:\ + :te=\E[60;1;0;26p\E[25;1H\E[J:\ + :is=\EP`+x~M\E\\\E[m\E7\E[60;1;0;26p\E[3g\E[f\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E8\E[>6h\E[1Q:\ + :li#25:tc=aaa-unk-s: +NR|aaa-28-s|ambassador|ann arbor ambassador/28 lines + status line:\ + :ti=\E[2J\E[28;1;0;28p:\ + :te=\E[60;1;0;28p\E[27;1H\E[J:\ + :is=\EP`+x~M\E\\\E[m\E7\E[60;1;0;28p\E[3g\E[f\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E8\E[>6h\E[1Q:\ + :li#27:tc=aaa-unk-s: +NT|aaa-30-s|ambassador|ann arbor ambassador/30 lines + status line:\ + :ti=\E[2J\E[30;1;0;30p:\ + :te=\E[60;1;0;30p\E[29;1H\E[J:\ + :is=\EP`+x~M\E\\\E[m\E7\E[60;1;0;30p\E[3g\E[f\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E8\E[>6h\E[1Q:\ + :li#29:tc=aaa-unk-s: +NU|aaa-36-s|ambassador|ann arbor ambassador/36 lines + status line:\ + :ti=\E[2J\E[36;1;0;36p:\ + :te=\E[60;1;0;36p\E[35;1H\E[J:\ + :is=\EP`+x~M\E\\\E[m\E7\E[60;1;0;36p\E[3g\E[f\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E8\E[>6h\E[1Q:\ + :li#35:tc=aaa-unk-s: +NV|aaa-40-s|ambassador|ann arbor ambassador/40 lines + status line:\ + :ti=\E[2J\E[40;1;0;40p:\ + :te=\E[60;1;0;40p\E[39;1H\E[J:\ + :is=\EP`+x~M\E\\\E[m\E7\E[60;1;0;40p\E[3g\E[f\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E8\E[>6h\E[1Q:\ + :li#39:tc=aaa-unk-s: +NW|aaa-48-s|ann arbor ambassador/48 lines+sl:\ + :ti=\E[2J\E[48;1;0;48p:te=\E[60;1;0;48p\E[47;1H\E[J:\ + :is=\EP`+x~M\E\\\E[m\EP`?y~[[2J~[[H\E7\E[60;1;0;48p\E[3g\E[f\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E8\E[>6h\E[1Q:\ + :li#47:tc=aaa-unk-s: +NX|aaa-60-s|ambassador|ann arbor ambassador/60 lines + status line:\ + :ti=\E[2J\E[60;1;0;60p:te=\E[60;1;0;60p\E[59;1H\E[J:\ + :is=\EP`+x~M\E\\\E[m\E7\E[60;1;0;60p\E[3g\E[f\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E8\E[>6h\E[1Q:\ + :li#59:tc=aaa-unk-s: +NY|aaa-18-rv|ambassador/18 lines+rv:\ + :md=\E[1;7m:mr=\E[m:mb=\E[5;7m:mk=\E[7;8m:me=\E[7m:\ + :us=\E[4;7m:ue=\E[7m:se=\E[7m:so=\E[m:\ + :is=\EP`+x~M\E\\\E[7m\E7\E[60;0;0;18p\E[3g\E[f\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E8\E[>6h\E[1Q:\ + :tc=aaa-18: +NZ|aaa-20-rv|ambassador/20 lines+rv:\ + :md=\E[1;7m:mr=\E[m:mb=\E[5;7m:mk=\E[7;8m:me=\E[7m:\ + :us=\E[4;7m:ue=\E[7m:se=\E[7m:so=\E[m:\ + :is=\EP`+x~M\E\\\E[7m\E7\E[60;0;0;20p\E[3g\E[f\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E8\E[>6h\E[1Q:\ + :tc=aaa-20: +Na|aaa-22-rv|ambassador/22 lines+rv:\ + :md=\E[1;7m:mr=\E[m:mb=\E[5;7m:mk=\E[7;8m:me=\E[7m:\ + :us=\E[4;7m:ue=\E[7m:se=\E[7m:so=\E[m:\ + :is=\EP`+x~M\E\\\E[7m\E7\E[60;0;0;22p\E[3g\E[f\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E8\E[>6h\E[1Q:\ + :tc=aaa-22: +Nb|aaa-24-rv|ambassador/24 lines+rv:\ + :md=\E[1;7m:mr=\E[m:mb=\E[5;7m:mk=\E[7;8m:me=\E[7m:\ + :us=\E[4;7m:ue=\E[7m:se=\E[7m:so=\E[m:\ + :is=\EP`+x~M\E\\\E[7m\E7\E[60;0;0;24p\E[3g\E[f\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E8\E[>6h\E[1Q:\ + :tc=aaa-24: +Nc|aaa-26-rv|ambassador/26 lines+rv:\ + :md=\E[1;7m:mr=\E[m:mb=\E[5;7m:mk=\E[7;8m:me=\E[7m:\ + :us=\E[4;7m:ue=\E[7m:se=\E[7m:so=\E[m:\ + :is=\EP`+x~M\E\\\E[7m\E7\E[60;0;0;26p\E[3g\E[f\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E8\E[>6h\E[1Q:\ + :tc=aaa-26: +Nd|aaa-28-rv|ambassador/28 lines+rv:\ + :md=\E[1;7m:mr=\E[m:mb=\E[5;7m:mk=\E[7;8m:me=\E[7m:\ + :us=\E[4;7m:ue=\E[7m:se=\E[7m:so=\E[m:\ + :is=\EP`+x~M\E\\\E[7m\E7\E[60;0;0;28p\E[3g\E[f\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E8\E[>6h\E[1Q:\ + :tc=aaa-28: +Ne|aaa-30-rv|ann arbor ambassador/30 lines in reverse video:\ + :md=\E[1;7m:mr=\E[m:mb=\E[5;7m:mk=\E[7;8m:me=\E[7m:\ + :us=\E[4;7m:ue=\E[7m:se=\E[7m:so=\E[m:\ + :is=\EP`+x~M\E\\\E[7m\E7\E[60;0;0;30p\E[3g\E[f\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E8\E[>6h\E[1Q:\ + :tc=aaa-30: +Nf|aaa-36-rv|ann arbor ambassador/36 lines in reverse video:\ + :md=\E[1;7m:mr=\E[m:mb=\E[5;7m:mk=\E[7;8m:me=\E[7m:\ + :us=\E[4;7m:ue=\E[7m:se=\E[7m:so=\E[m:\ + :is=\EP`+x~M\E\\\E[7m\E7\E[60;0;0;36p\E[3g\E[f\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E8\E[>6h\E[1Q:\ + :tc=aaa-36: +Ng|aaa-40-rv|ann arbor ambassador/40 lines in reverse video:\ + :md=\E[1;7m:mr=\E[m:mb=\E[5;7m:mk=\E[7;8m:me=\E[7m:\ + :us=\E[4;7m:ue=\E[7m:se=\E[7m:so=\E[m:\ + :is=\EP`+x~M\E\\\E[7m\E7\E[60;0;0;40p\E[3g\E[f\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E8\E[>6h\E[1Q:\ + :tc=aaa-40: +Nh|aaa-48-rv|ann arbor ambassador/48 lines in reverse video:\ + :md=\E[1;7m:mr=\E[m:mb=\E[5;7m:mk=\E[7;8m:me=\E[7m:\ + :us=\E[4;7m:ue=\E[7m:se=\E[7m:so=\E[m:\ + :is=\EP`+x~M\E\\\E[7m\E7\E[60;0;0;48p\E[3g\E[f\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E8\E[>6h\E[1Q:\ + :tc=aaa-48: +Ni|aaa-60-rv|ann arbor ambassador/60 lines in reverse video:\ + :md=\E[1;7m:mr=\E[m:mb=\E[5;7m:mk=\E[7;8m:me=\E[7m:\ + :us=\E[4;7m:ue=\E[7m:se=\E[7m:so=\E[m:\ + :is=\EP`+x~M\E\\\E[7m\E7\E[60;0;0;60p\E[3g\E[f\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E8\E[>6h\E[1Q:\ + :tc=aaa-60: +Nj|aaa-18-rv-s|aaa-18-s-rv|ambassador/18 lines+sl+rv:\ + :md=\E[1;7m:mr=\E[m:mb=\E[5;7m:mk=\E[7;8m:me=\E[7m:\ + :us=\E[4;7m:ue=\E[7m:se=\E[7m:so=\E[m:\ + :ti=\E[2J\E[18;1;0;18p:te=\E[60;1;0;18p\E[17;1H\E[J:li#17:\ + :is=\EP`+x~M\E\\\E[7m\E7\E[60;1;0;18p\E[3g\E[f\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E8\E[>6h\E[1Q:\ + :tc=aaa-unk-s: +Nk|aaa-20-rv-s|aaa-20-s-rv|ambassador/20 lines+sl+rv:\ + :md=\E[1;7m:mr=\E[m:mb=\E[5;7m:mk=\E[7;8m:me=\E[7m:\ + :us=\E[4;7m:ue=\E[7m:se=\E[7m:so=\E[m:\ + :ti=\E[2J\E[20;1;0;20p:te=\E[60;1;0;20p\E[19;1H\E[J:li#19:\ + :is=\EP`+x~M\E\\\E[7m\E7\E[60;1;0;20p\E[3g\E[f\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E8\E[>6h\E[1Q:\ + :tc=aaa-unk-s: +Nl|aaa-22-rv-s|aaa-22-s-rv|ambassador/22 lines+sl+rv:\ + :md=\E[1;7m:mr=\E[m:mb=\E[5;7m:mk=\E[7;8m:me=\E[7m:\ + :us=\E[4;7m:ue=\E[7m:se=\E[7m:so=\E[m:\ + :ti=\E[2J\E[22;1;0;22p:te=\E[60;1;0;22p\E[21;1H\E[J:li#21:\ + :is=\EP`+x~M\E\\\E[7m\E7\E[60;1;0;22p\E[3g\E[f\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E8\E[>6h\E[1Q:\ + :tc=aaa-unk-s: +Nm|aaa-24-rv-s|aaa-24-s-rv|ambassador/24 lines+sl+rv:\ + :md=\E[1;7m:mr=\E[m:mb=\E[5;7m:mk=\E[7;8m:me=\E[7m:\ + :us=\E[4;7m:ue=\E[7m:se=\E[7m:so=\E[m:\ + :ti=\E[2J\E[24;1;0;24p:te=\E[60;1;0;24p\E[23;1H\E[J:li#23:\ + :is=\EP`+x~M\E\\\E[7m\E7\E[60;1;0;24p\E[3g\E[f\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E8\E[>6h\E[1Q:\ + :tc=aaa-unk-s: +Nn|aaa-26-rv-s|aaa-26-s-rv|ambassador/26 lines+sl+rv:\ + :md=\E[1;7m:mr=\E[m:mb=\E[5;7m:mk=\E[7;8m:me=\E[7m:\ + :us=\E[4;7m:ue=\E[7m:se=\E[7m:so=\E[m:\ + :ti=\E[2J\E[26;1;0;26p:te=\E[60;1;0;26p\E[25;1H\E[J:li#25:\ + :is=\EP`+x~M\E\\\E[7m\E7\E[60;1;0;26p\E[3g\E[f\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E8\E[>6h\E[1Q:\ + :tc=aaa-unk-s: +No|aaa-28-rv-s|aaa-28-s-rv|ambassador/28 lines+sl+rv:\ + :md=\E[1;7m:mr=\E[m:mb=\E[5;7m:mk=\E[7;8m:me=\E[7m:\ + :us=\E[4;7m:ue=\E[7m:se=\E[7m:so=\E[m:\ + :ti=\E[2J\E[28;1;0;28p:te=\E[60;1;0;28p\E[27;1H\E[J:li#27:\ + :is=\EP`+x~M\E\\\E[7m\E7\E[60;1;0;28p\E[3g\E[f\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E8\E[>6h\E[1Q:\ + :tc=aaa-unk-s: +Np|aaa-rv|aaa-30-rv-s|aaa-30-s-rv|ambassador/30 lines+sl+rv:\ + :md=\E[1;7m:mr=\E[m:mb=\E[5;7m:mk=\E[7;8m:me=\E[7m:\ + :us=\E[4;7m:ue=\E[7m:se=\E[7m:so=\E[m:\ + :ti=\E[2J\E[30;1;0;30p:te=\E[60;1;0;30p\E[29;1H\E[J:li#29:\ + :is=\EP`+x~M\E\\\E[7m\E7\E[60;1;0;30p\E[3g\E[f\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E8\E[>6h\E[1Q:\ + :tc=aaa-unk-s: +Nq|aaa-36-rv-s|aaa-36-s-rv|ambassador/36 lines+sl+rv:\ + :md=\E[1;7m:mr=\E[m:mb=\E[5;7m:mk=\E[7;8m:me=\E[7m:\ + :us=\E[4;7m:ue=\E[7m:se=\E[7m:so=\E[m:\ + :ti=\E[2J\E[36;1;0;36p:te=\E[60;1;0;36p\E[35;1H\E[J:li#35:\ + :is=\EP`+x~M\E\\\E[7m\E7\E[60;1;0;36p\E[3g\E[f\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E8\E[>6h\E[1Q:\ + :tc=aaa-unk-s: +Nr|aaa-40-rv-s|aaa-40-s-rv|ambassador/40 lines+sl+rv:\ + :md=\E[1;7m:mr=\E[m:mb=\E[5;7m:mk=\E[7;8m:me=\E[7m:\ + :us=\E[4;7m:ue=\E[7m:se=\E[7m:so=\E[m:\ + :ti=\E[2J\E[40;1;0;40p:te=\E[60;1;0;40p\E[39;1H\E[J:li#39:\ + :is=\EP`+x~M\E\\\E[7m\E7\E[60;1;0;40p\E[3g\E[f\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E8\E[>6h\E[1Q:\ + :tc=aaa-unk-s: +Ns|aaa-48-rv-s|aaa-48-s-rv|ambassador/48 lines+sl+rv:\ + :md=\E[1;7m:mr=\E[m:mb=\E[5;7m:mk=\E[7;8m:me=\E[7m:\ + :us=\E[4;7m:ue=\E[7m:se=\E[7m:so=\E[m:\ + :ti=\E[2J\E[48;1;0;48p:te=\E[60;1;0;48p\E[47;1H\E[J:li#47:\ + :is=\EP`+x~M\E\\\E[7m\E7\E[60;1;0;48p\E[3g\E[f\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E8\E[>6h\E[1Q:\ + :tc=aaa-unk-s: +Nt|aaa-60-rv-s|aaa-60-s-rv|ambassador/60 lines+sl+rv:\ + :md=\E[1;7m:mr=\E[m:mb=\E[5;7m:mk=\E[7;8m:me=\E[7m:\ + :us=\E[4;7m:ue=\E[7m:se=\E[7m:so=\E[m:\ + :ti=\E[2J\E[60;1;0;60p:te=\E[60;1;0;60p\E[59;1H\E[J:li#59:\ + :is=\EP`+x~M\E\\\E[7m\E7\E[60;1;0;60p\E[3g\E[f\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E8\E[>6h\E[1Q:\ + :tc=aaa-unk-s: +NL|aaa-24-ctxt|ann arbor ambassador/24 lines:\ + :ti=\E[30;1H\E[K\E[24;0;0;24p:te=\E[60;1;0;24p\E[60;1H\E[K:tc=aaa-24: +NL|aaa-24-rv-ctxt|ambassador/24+rv:\ + :ti=\E[30;1H\E[K\E[24;0;0;24p:te=\E[60;1;0;24p\E[60;1H\E[K:tc=aaa-24-rv: +NL|aaa-s-ctxt|aaa-30-s-ctxt|hairy aaa:\ + :ti=\E[30;1H\E[K\E[30;1;0;30p:te=\E[60;1;0;30p\E[59;1H\E[K:tc=aaa-30-s: +NL|aaa-s-rv-ctxt|aaa-30-s-rv-ctxt|hairy aaa:\ + :md=\E[1;7m:mr=\E[m:mb=\E[5;7m:mk=\E[7;8m:me=\E[7m:\ + :us=\E[4;7m:ue=\E[7m:se=\E[7m:so=\E[m:\ + :is=\EP`+x~M\E\\\E[7m\E7\E[60;1;0;30p\E[3g\E[f\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E8\E[>6h\E[1Q:\ + :ti=\E[30;1H\E[K\E[30;1;0;30p:te=\E[60;1;0;30p\E[59;1H\E[K:\ + :li#29:tc=aaa-unk-s: +NH|aaa-ctxt|aaa-30-ctxt|ann arbor ambassador/30 lines:\ + :ti=\E[30;0;0;30p:te=\E[60;0;0;30p\E[60;1H\E[K:tc=aaa-30: +NH|aaa-rv-ctxt|aaa-30-rv-ctxt|ann arbor ambassador/30 lines:\ + :ti=\E[30;0;0;30p:te=\E[60;0;0;30p\E[60;1H\E[K:\ + :md=\E[1;7m:mr=\E[m:mb=\E[5;7m:mk=\E[7;8m:me=\E[7m:\ + :us=\E[4;7m:ue=\E[7m:se=\E[7m:so=\E[m:\ + :is=\EP`+x~M\E\\\E[7m\E7\E[60;0;0;30p\E[3g\E[f\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E[8a\EH\E8\E[>6h\E[1Q:\ + :li#30:tc=aaa-unk: +Nd|aaa-db|ann arbor ambassador 30/destructive backspace:\ + :ti=\E[H\E[J\E[30;0;0;30p:te=\E7\E[60;0;0;30p\E8:li#30:\ + :is=\E[60;0;0;30p\E[H\E[J\E[1Q\E[m\E[20l\E[>30h:le=\E[D:bc=\E[D:bs@:\ + :tc=aaa-unk: +N1|aa|annarbor|4080|ann arbor 4080:\ + :do=^J:pt:ct=^\^P^P:st=^]^P1:cm=^O%r%\066%.%>^S^L%+@:\ + :co#80:li#40:le=^H:bs:cl=2^L:up=^N:nd=^_:ho=^K:am:\ + :kb=^^:kd=^J:ku=^N:kl=^H:kr=^_:kh=^K:ma=^_ ^N^P: +# # -------------------------------- +# +# P: PC entries for use with kermit +# +# greg small (gts@populi) +# +# Cannot use :pt:, it does not work (why?). :ho: seems required (why?). [gts] +# Caution: 4.3 BSD tset does not pass li#25 to stty rows except during login? +# :cl: clears attributes and sets wrap at margin before clearing the screen. +P1|ansi.sys|ansisys|PC-DOS 3.1 ANSI.SYS:\ + :am:bs:ce=\E[K:cl=\E[m\E[7h\E[2J:cm=\E[%i%d;%dH:co#80:\ + :ku=^K:kd=^J:kl=^H:kr=^L:kh=^^:ma=^Hh\012j^Kk^Ll^^H:\ + :ho=\E[H:li#25:nd=\E[C:up=\E[A:\ + :ms:md=\E[1m:me=\E[m:mr=\E[7m:se=\E[m:so=\E[1m:ue=\E[m:us=\E[4m:\ + :is=U1 PC-DOS 3.1 ANSI.SYS 9-23-86\n\E[m\E[7h: +# +# Define IBM PC keypad keys for vi as per MS-Kermit while using ANSI.SYS. +# This should only be used when the terminal emulator cannot redefine the keys. +# Since redefining keys with ansi.sys also affects PC-DOS programs, the key +# definitions must be restored. If the terminal emulator is quit while in vi +# or others using :ks:ke:, the keypad keys will not be defined as per PC-DOS. +# The PgUp and PgDn are prefixed with ESC so that tn3270 can be used on Unix +# (^U and ^D are already defined for tn3270). The ESC is safe for vi but it +# does "beep". ESC ESC i is used for Ins to avoid tn3270 ESC i for coltab. +# Left arrow is always BS, because PC-dos can tolerate this change. +# Caution: vi is limited to 256 string bytes, longer crashes or wierds vi. +# Consequently the End keypad key could not be set (it is relatively safe and +# actually useful because it sends ^@ O, which beeps and opens a line above). +P2|ansi.sysk|ansisysk|PC-DOS 3.1 ANSI.SYS with keypad redefined for vi:\ + :ks=\E[;71;30p\E[;72;11p\E[;73;27;21p\E[;77;12p\E[;80;10p\E[;81;27;4p\E[;82;27;27;105p\E[;83;127p:\ + :ke=\E[;71;0;71p\E[;72;0;72p\E[;73;0;73p\E[;77;0;77p\E[;80;0;80p\E[;81;0;81p\E[;82;0;82p\E[;83;0;83p:\ + :is=U2 PC-DOS 3.1 ANSI.SYS with keypad redefined for vi 9-29-86\n\E[;75;8p:\ + :tc=ansi.sys +# +# Adds ins/del line/character, hence vi reverse scrolls/inserts/deletes nicer. +P3|nansi.sys|nansisys||PC-DOS Public Domain NANSI.SYS:\ + :al=\E[1L:dl=\E[1M:ic=\E[1@:dc=\E[1P:\ + :is=U3 PC-DOS Public Domain NANSI.SYS 9-23-86\n:\ + :tc=ansi.sys: +# +# See U2 ansi.sysk and U3 nansi.sys above. +P4|nansi.sysk|nansisysk|PC-DOS Public Domain NANSI.SYS with keypad redefined for vi:\ + :al=\E[1L:dl=\E[1M:ic=\E[1@:dc=\E[1P:\ + :is=U4 PC-DOS Public Domain NANSI.SYS with keypad redefined for vi 9-29-86\n\E[;75;8p:\ + :tc=ansi.sysk: +# # -------------------------------- +# +# T: TELETYPE +# +# We need descriptions for the model 40. There are known to be at least three +# flavors of the 40, both seem more like IBM half duplex forms fillers than +# ASCII terminals. They have lots of awful braindamage, such as printing +# a visible newline indicator after each newline. The 40-1 is a half duplex +# terminal and is hopeless. The 40-2 is braindamaged but has hope and is +# described here. The 40-4 is a 3270 lookalike and beyond hope. +# The terminal has visible bell but I don't know it - it's +# null here to prevent it from showing the BL character. +# There is an \EG in nl because of a bug in vi (if stty says you have +# a "newline" style terminal (-crmode) vi figures all it needs is nl +# to get crlf, even if cr is not ^M.) +T0|40|tty40|ds40|ds40/2|ds40-2|dataspeed40|teletype dataspeed 40/2:\ + :cl=160\ER:cd=160\EJ:al=160\EL:dl=160\EM:dc=50\EP:im=:ei=:ic=50\E\^:\ + :nd=\EC:up=\E7:bs:cr=\EG:nl=\EG\EB:do=\EB:co#80:li#24:vb=:\ + :so=\E3:se=\E4: +T3|33|tty33|tty|model 33 teletype:\ + :do=^J:co#72:hc:os: +T4|43|tty43|model 43 teletype:\ + :do=^J:kb=^h:am:le=^H:bs:hc:os:co#132: +T7|37|tty37|model 37 teletype:\ + :do=^J:le=^H:bs:hc:hu=\E8:hd=\E9:up=\E7:os: +# From jwb Wed Mar 31 13:25:09 1982 remote from ihuxp +# This entry appears to avoid the top line - I have no idea why. +TT|4424|tty4424|teletype 4424M:\ + :al=\EL:da:db:ip=2:im=:ei=:ic=\E\^:dc=\EP:dl=\EM:\ + :co#80:li#23:am:cl=\E[2;H\E[J:bs:cm=\E[%i%2;%2H\E[B:\ + :nd=\E[C:up=\E[A:pt:mi:sr=\ET:\ + :ce=\E[K:so=\E[7m:se=\E[m:us=\E[4m:ue=\E[m:\ + :is=\E[m\E[2;24r:\ + :kd=\E[B:kl=\E[D:ku=\E[A:kr=\E[C:\ + :kh=\E[H:k1=\EOP:k2=\EOQ:k3=\EOR:k4=\EOS: +# Teletype blit. +TD|dmd|5620|ttydmd|tty5620|5620 terminal 88 columns:\ + :co#88:li#70:am:bs:pt:cm=\E[%i%d;%dH:nd=\E[C:up=\E[A:\ + :cl=\E[H\E[J:cd=\E[J:ce=\E[K:al=\E[L:dl=\E[M:do=^J:\ + :im=:ei=:ic=\E[@:dc=\E[P:sr=\E[T:sf=\E[S:le=^H:kb=^H:\ + :kl=\E[D:kr=\E[C:ku=\E[A:kd=\E[B:kh=\E[H:ho=\E[H:ll=\E[70;1H:\ + :AL=\E[%dL:DL=\E[%dM:IC=\E[%d@:DC=\E[%dP:rc=\E8:rs=\Ec:sc=\E7:\ + :so=\E[7m:se=\E[0m:us=\E[4m:ue=\E[0m:ms:me=\E[0m:mr=\E[7m: +# # -------------------------------- +# +# V: VISUAL +# +# The Visual 200 beeps when you type a character in insert mode. +# This is a horribly obnoxious misfeature, and some of the entries +# below try to get around the problem by ignoring the feature or +# turning it off when inputting a character. They are said not to +# work well at 300 baud. (You could always cut the wire to the bell!) +#From mike@brl-vgr Mon Nov 14 08:34:29 1983 +V2|vi200|vis200|visual 200 with function keys:\ + :so=\E4:se=\E3:ms:do=^J:\ + :al=\EL:am:le=^H:bs:cd=\Ey:ce=\Ex:cl=\Ev:\ + :cm=\EY%+ %+ :co#80:dc=\EO:dl=\EM:ho=\EH:\ + :im=:ei=:ic=\Ei \b\Ej:\ + :is=\E3\Eb\Ej\E\\\El\EG\Ec\Ek:\ + :k0=\EP:k1=\EQ:k2=\ER:k3=\E :k4=\E!:k5=\E":k6=\E#:\ + :k7=\E$:k8=\E%:k9=\E&:kl=\ED:kr=\EC:ku=\EA:kd=\EB:kh=\EH:\ + :li#24:nd=\EC:pt:sr=\EI:up=\EA:vs=\Ed:ve=\Ec: +VR|vi200-rv-ic|visual 200 reverse video using insert char:\ + :ei=\Ej:im=\Ei:ic@:tc=vi200-rv: +# The older Visuals didn't come with function keys. This entry uses +# ks and ke so that the keypad keys can be used as function keys. +# If your version of vi doesn't support function keys you may want +# to use V2. +Vf|vi200-f|visual|visual 200 no function keys:\ + :do=^J:al=\EL:am:le=^H:bs:cd=\Ey:ce=4*\Ex:cl=\Ev:\ + :cm=\EY%+ %+ :co#80:dc=4*\EO:dl=4*\EM:ho=\EH:\ + :im=:ei=:ic=\Ei \b\Ej:\ + :is=\E3\Eb\Ej\E\\\El\EG\Ed\Ek:ks=\E=:ke=\E>:\ + :k0=\E?p:k1=\E?q:k2=\E?r:k3=\E?s:k4=\E?t:k5=\E?u:k6=\E?v:\ + :k7=\E?w:k8=\E?x:k9=\E?y:kl=\ED:kr=\EC:ku=\EA:kd=\EB:kh=\EH:\ + :li#24:nd=\EC:pt:sr=\EI:up=\EA:vs=\Ed:ve=\Ec: +Vr|vi200-rv|visual 200 reverse video:\ + :so=\E4:se=\E3:sr@:vs@:ve@:tc=vi200: +Vt|vi200-ic|visual 200 using insert char:\ + :ei=\Ej:im=\Ei:ic@:tc=vi200: +# From: jbs@athena.mit.edu Jeff Siegal +V5|vi55|Visual 55:\ + :im=\Ea:ei=\Eb:mi:dc=\Ew:dm=:ed=:al=\EL:dl=\EM:cs=\E_%+A%+A:\ + :ho=\EH:cl=\Ev:is=\Ev\E_AX\Eb\EW\E9P\ET:so=\EU:se=\ET:ms:\ + :do=^J:le=^H:bs:cd=\EJ:ce=\EK:cm=\EY%+ %+ :co#80:li#24:\ + :nd=\EC:pt:sr=\EI:up=\EA:ku=\EA:kd=\EB:kr=\EC:kl=\ED:kb=^H: +# # -------------------------------- +# +# X: TEKTRONIX +# +Xa|tek|tek4012|4012|tektronix 4012:\ + :do=^J:is=\E^O:le=^H:bs:cl=1000\E^L:co#75:ns:li#35:os: +Xb|tek4013|4013|tektronix 4013:\ + :as=\E^N:ae=\E^O:dF#1000:tc=4012: +Xc|tek4014|4014|tektronix 4014:\ + :is=\E^O\E9:co#81:li#38:dF#1000:tc=tek4012: +Xd|tek4015|4015|tektronix 4015:\ + :as=\E^N:ae=\E^O:tc=4014: +Xe|tek4014-sm|4014-sm|tektronix 4014 in small font:\ + :is=\E^O\E\072:co#121:li#58:tc=tek4014: +Xf|tek4015-sm|4015-sm|tektronix 4015 in small font:\ + :as=\E^N:ae=\E^O:tc=4014-sm: +# I think the 1000UP is supposed to be so expensive it never happens. +X4|tek4023|4023|tex|tektronix 4023:\ + :do=^J:so=^_P:se=^_@:cm=\034%r%+ %+ :nd=\t:le=^H:\ + :bs:cl=4\E^L:co#80:li#24:am:up=1000UP:vt#4: +# Can't use cursor motion because it's memory relative, and because +# it only works in the workspace, not the monitor. Same for home. +# Likewise, standout only works in the workspace. +# 145 ms padding on al and AL taken out since it doesn't seem to be needed much. +X5|4025|4027|4024|tek4025|tek4027|tek4024|4025cu|4027cu|tektronix 4024/4025/4027:\ + :sf=^F^J:do=^F^J:is=\41com 31\r\n^_sto 9 17 25 33 41 49 57 65 73\r:\ + :ks=^_lea p4 /h/\r^_lea p8 /k/\r^_lea p6 / /\r^_lea p2 /j/\r^_lea f5 /H/\r^_lea p5 /H/\r:\ + :ke=^_lea p2\r^_lea p4\r^_lea p6\r^_lea p8\r^_lea p5\r^_lea f5\r:\ + :am:le=^H:bs:da:db:pt:li#34:co#80:cl=^_era\r\n\n:up=^K:nd=^_rig\r:\ + :al=^_up\r^_ili\r:dl=^_dli\r^F:\ + :dc=^_dch\r:im=^_ich\r:ei=^F^_dow\r^K:nl=^F\n:\ + :cd=^_dli 50\r:CC=^_:AL=^_up\r^_ili %d\r:DL=^_dli %d\r^F:\ + :UP=^_up %d\r:DO=^_dow %d\r:LE=^_lef %d\r:RI=^_rig %d\r: +X7|4025-17|4027-17|tek 4025 17 line window:\ + :li#17:tc=4025: +X8|4025-17ws|4027-17ws|tek 4025 17 line window in workspace:\ + :is=\41com 31\r\n^_sto 9,17,25,33,41,49,57,65,73\r^_wor 17\r^_mon 17\r:\ + :ti=^_wor h\r:te=^_mon h\r:so=^_att e\r:se=^_att s\r:tc=4025-17: +X9|4025ex|4027ex|tek 4025 w/!:\ + :ti=\41com 31\r:te=^_com 33\r:\ + :is=^_com 33\r\n\41sto 9,17,25,33,41,49,57,65,73\r:tc=4025: +# From jcoker@ucbic +Xp|4107|tek4107|Tektronix 4107 graphics terminal with memory:\ + :ti=\E[?6l\E[H\E[J:te=\E[?6h\E%!0\ELBP0\E%!1\E[32;1f:\ + :is=\E%!0\ELBP0\E%!1\E[H\E[2g\EH\E[8C\EH\E[8C\EH\E[8C\EH\E[8C\EH\E[8C\EH\E[8C\EH\E[8C\EH\E[8C\EH\E[8C\EH\E[J:\ + :li#32:do=^J:al=3\E[L:xn:am:le=^H:bs:cd=\E[J:\ + :ce=5\E[K:cl=156\E[H\E[J:cm=\E[%i%d;%dH:co#80:dc=4\E[P:dl=3\E[M:\ + :ho=\E[H:ic=4\E[@:md=\E[1m:mr=\E[7m:mb=\E[5m:me=\E[m:ku=\EM:\ + :kd=\ED:kl=\E[D:kr=\E[C:kh=\E[H:\ + :ei=:im=:pt:bw:bt=\E[Z:mi:nd=\E[C:se=\E[m:so=\E[7m:\ + :ue=\E[m:us=\E[4m:up=\EM: +# Tektronix 4107 with sysline +Xq|4107-s|tek4107-s|Tektronix 4107 with sysline but no memory:\ + :is=\E%!1\E[2;32r\E[132D\E[2g\EH\E[8C\EH\E[8C\EH\E[8C\EH\E[8C\EH\E[8C\EH\E[8C\EH\E[8C\EH\E[8C\EH\E[8C\EH\E[J:\ + :es:hs:i2=\E7\E[?6l\E[2K\E[?6h\E8:ts=\E7\E[?6l\E[2K\E[;%i%df:\ + :fs=\E[?6h\E8:ds=\E7\E[?6l\E[2K\E[?6h\E8:tc=4107: +# From cbosg!teklabs!davem Wed Sep 16 21:11:41 1981 +# Here's the comamnd file that I use to get rogue to work on the 4025. +# It should work with any program using the old curses (e.g. it better +# not try to scroll, or cursor addressing won't work. Also, you can't +# see the cursor.) +# (This "learns" the arrow keys for rogue. I have adapted it for termcap - mrh) +Xr|4025-cr|tek 4025 for curses and rogue:\ + :is=\41com 31\r\n^_sto 9 17 25 33 41 49 57 65 73\r:\ + :am:le=^H:bs:pt:li#33:co#80:cm=^_jum%i%d,%d;:up=^K:\ + :do=^F^J:cl=^_era;:nd=^_rig;:nl=^F\n:ti=^_wor 33h:te=^_wor 0: +# next two lines commented out since curses only allows 128 chars, sigh. +# :ti=^_lea p1/b/^_lea p2/j/^_lea p3/n/^_lea p4/h/^_lea p5/ /^_lea p6/l/^_lea p7/y/^_lea p8/k/^_lea p9/u/^_lea p./f/^_lea pt/`era w/13^_lea p0/s/^_wor 33h:\ +# :te=^_lea p1^_lea p2^_lea p3^_lea p4^_lea pt^_lea p5^_lea p6^_lea p7^_lea p8^_lea p9/la/13^_lea p.^_lea p0^_wor 0: +# The 4110 series may be a wonderful graphics series, but they make the 4025 +# look good for screen editing. In the dialog area, you can't move the cursor +# off the bottom line. Out of the dialog area, ^K moves it up, but there +# is no way to scroll. +Xs|4112|4114|tek4112|tektronix 4110 series:\ + :is=\E3!1:li#34:co#80:am:al=\E[L:bs:bt=\E[Z:\ + :cd=\E[0J:ce=\E[0K:cl=\E[2J\E[0;0H:cm=\E[%i%d;%dH:\ + :db:dc=\E[P:dl=\E[M:ic=\E[@:im=:nd=\E[C:se=\E[m:\ + :so=\E[7m:ue=\E[m:up=\EM:us=\E[4m:vs=:ve=:\ + :sr=\E7\E[0;0H\E[L\E8:sf=\E7\E[0;0H\E[M\E8: +Xt|4112-nd|4112 not in dialog area:up=^K:ns:tc=4112: +Xu|4112-5|4112 in 5 line dialog area:li#5:tc=4112: +Xv|4113|tek4113|tektronix 4113 color graphics, 5 line dialog area:\ + :le=^H:do=^J:eo:da:bs:am:li#5:co#80:is=\EKA1\ELL5\ELV0\ELV1:\ + :vb=\ERBA4\ERBA4\ERBA4\ERBA4\ERBA4\ERBA4\ERBA4\ERBA4\ERBA4\ERBA4\ERB0:\ + :cl=\ELZ:uc=^H\ELM1_\ELM0:nd=\LM1 \LM0:\ + :.as=\E^N:.ae=\E^O: +Xw|4113-34|tek4113-34|tektronix 4113 color graphics, 34 line dialog area:\ + :is=\EKA1\ELLB2\ELV0\ELV1:li#34:tc=tek4113: +# ns hidden from vi to allow visual mode. APL font (as, ae) not supported here. +# uc is slow, but looks nice. Suggest setenv MORE -up . vb needs enough delay +# to let you see the background color being toggled. +Xy|4113-nd|tek4113-nd|tektronix 4113 color graphics, no dialog area:\ + :le=^H:do=^J:nd=\t:up=^K:ll=\ELF hl @:ho=\ELF7l\177 @:\ + :eo:bs:am:li#34:co#80:is=\ELZ\EKA0\ELF7l\177 @:vs=\ELZ\EKA0:\ + :vb=\ERBA4\ERBA4\ERBA4\ERBA4\ERBA4\ERBA4\ERBA4\ERBA4\ERBA4\ERBA4\ERB0:\ + :cl=\E\f:uc=^H\EMG1_\EMG0:so=\EMT2:se=\EMT1:\ + :.ns:.as=\E^N:.ae=\E^O: +Xz|4105|tek4105:\ + :al=\E[1L:am:bs:cd=\E[J:ce=\E[K:cl=\E[2J\E[H:cm=\E[%i%2;%2H:co#80:\ + :dc=\E[1P:dl=\E[1M:dn=\E[1B:ho=\E[H:im=\E[4h:li#30:mi:nd=\E[1C:\ + :as=\E[1m:ae=\E[0m:ms:pt:se=\E[0m:so=\E[7m:up=\E[1A:kb=^h:ku=\E[1A:\ + :kd=\E[1B:kl=\E[1D:kr=\E[1C:us=\E[4m:ue=\E[0m:is=\E%!1\E[?6l\E[0m:\ + :mr=\E[<3m:md=\E[<4m:mh=\E[<6m:mb=\E[<7m:me=\E[<1m:ti=\E%!1\E[?6l:xt: +# This entry is from Tek. Inc. (Brian Biehl) +Xz|4115|tek4115|Tektronix 4115:\ + :co#80:li#34:\ + :al=\E[L:am:bc=\E[D:bs:bt=\E[Z:cd=\E[J:ce=\E[K:\ + :cl=\E[;H\E[2J:cm=\E[%i%d;%dH:da:db:dc=\E[P:dl=\E[M:do=\E[B:\ + :ei=\E[4l:eo:ho=\E[;H:im=\E[4h:if=/usr/share/tabset/vt100:\ + :is=\E%\0410\E%\014\ELV0\EKA1\ELBB2\ENU@\075\ELLB2\ELM0\ELV1\EKYA?\E%\0411\E[<1l\E[?7h\E[?8h\E[34;1H\E[34B\E[0m:\ + :kb=^H:ke=\E>:ks=\E=:nd=\E[C:pt:se=\E[m:so=\E[7m:sr=\EM:\ + :te=\E%\0410\ELBG8\E%\0411\E[34;1H\E[J: + :ti=\E%\0410\ELBB2\E%\0411:\ + :ue=\E[m:up=\E[A:us=\E[4m:\ + :ve=\E%\0410\ELBG8\E%\0411\E[34;1H:\ + :vs=\E%\0410\ELBB2\E%\0411: +# The tek4125 emulates a vt100 incorrectly - the scrolling region +# command is ignored. The following entry replaces the cs with the +# needed al, dl, and im; removes some cursor pad commands that the tek4125 +# chokes on; and adds a lot of initialization for the tek dialog area. +# Note that this entry uses all 34 lines and sets the cursor color to green. +# Steve Jacobson 8/85 +XB|tek4125:\ + :ks=\E=:li#34:\ + :is=\E%\!0\EQD1\EUX03\EKA\ELBB2\ELCE0\ELI100\ELJ2\ELLB2\ELM0\ELS1\ELX00\ELV1\E%\!1\E>\E[?3l\E[?4l\E[?5l\E[?7h\E[?8h:dl=\E[1M:\ + :al=\E[1L:cs@:sc@:rc@:im=\E1:tc=vt100: +# From carolyn@dali.berkeley.edu Thu Oct 31 12:54:27 1985 +XA|4404|tek4404:\ + :al=\E[1L:bs:cd=\E[J:ce=\E[K:cl=\E[;H\E[2J:cm=\E[%i%d;%dH:co#80:\ + :cs=\E[%i%d;%dr:dc=\E[P:dl=\E[1M:do=^J:ei=\E[4l:ho=\E[H:im=\E[4h:\ + :kd=\E[B:ke=\E[?1h:kl=\E[D:kr=\E[C:ks=\E[?1l:ku=\E[A:li#32::mb=\E[5m:\ + :md=\E[1m:me=\E[m:nd=\E[C:pt:rc=\E8:sc=\E7:se=\E[27m:so=\E[7m:\ + :ta=\E[2I:ti=\E%\!1\E[1;32r\E[?6l\E>:te=\E[1;1H\E[0J\E[?6h\E[?1l:\ + :ue=\E[m:up=\E[A:us=\E[4m: +# # -------------------------------- +# +# Z: Miscellaneous +# +# These compucolors appear similar, but they at least have different +# sized screens. I don't know what's going on here. +Z1|8001|ISC8001|compucolor|intecolor:\ + :do=^J:al=\EU:am:le=^Z:bc=^Z:cl=3*^L:cm=^C%r%.%.:\ + :co#80:cd=\EQ:dm=\EQ:ed=\EF:dc=\177:dl=\EV:ei=\EF:\ + :im=\EQ:li#40:nd=1^Y:ta=8\t:up=^\:ho=1^H:pc=^@: +Z2|compucolor2|compucolorII:\ + :do=^J:pt:am:cm=%r^C%.%.:le=^Z:bc=^Z:li#32:co#64:\ + :cl=^L:ho=^H:nd=^Y:up=^\: +# From cithep!eric Wed Sep 16 08:06:44 1981 +Z3|intext|Interactive Systems Corporation modified owl 1200:\ + :do=^J:al=5.5*\020:am:le=^_:bc=^_:le=^H:bs:bt=^Y:cd=5.5*\026J:\ + :ce=^K\160^R:cl=132\014:cm=\017%+ %+ :co#80:dc=5.5*\022:dl=5.5*\021:\ + :ei=\026\074:im=\026\073:ip=5.5*:li#24:nd=\036:pt:up=\034:\ + :se=^V# :sg#1:so=^V$,:ma=^K^P^R^L^L :\ + :kl=^_:kd=^J:kr=^^:ku=\034:kb=^H:kh=^Z:\ + :k1=^VA\r:k2=^VB\r:k3=^VC\r:k4=^VD\r:k5=^VE\r:\ + :k6=^VF\r:k7=^VG\r:k8=^VH\r:k9=^VI\r:k0=^VJ\r: +# # -------------------------------- +# +# a: ADDS +# +# Regent: lowest common denominator, works on all regents. +a0|regent|Adds Regent Series:li#24:co#80:am:cl=^L:ll=^A:up=^Z:\ + :bs:bc=^U:nd=^F:do=^J:ho=\EY : +# Regent 100 has a bug where if computer sends escape when user is holding +# down shift key it gets confused, so we avoid escape. +a1|regent100|Adds Regent 100:k0=^B1^M:k1=^B2^M:k2=^B3^M:k3=^B4^M:\ + :k4=^B5^M:k5=^B6^M:k6=^B7^M:k7=^B8^M:\ + :l0=F1:l1=F2:l2=F3:l3=F4:l4=F5:l5=F6:l6=F7:l7=F8:\ + :so=\E0P:ue=\E0@:us=\E0`:se=\E0@:\ + :cm=^K%+ %B^P%.:ug#1:sg#1:tc=regent: +a2|regent20|Adds Regent 20:cd=\Ek:ce=\EK:cm=\EY%+ %+ :tc=regent: +a3|regent25|Adds Regent 25:kh=^A:kl=^U:kr=^F:ku=^Z:kd=^J:tc=regent20: +a4|regent40|Adds Regent 40:k0=^B1^M:k1=^B2^M:k2=^B3^M:k3=^B4^M:\ + :k4=^B5^M:k5=^B6^M:k6=^B7^M:k7=^B8^M:\ + :l0=F1:l1=F2:l2=F3:l3=F4:l4=F5:l5=F6:l6=F7:l7=F8:\ + :al=2*\EM:dl=2*\El:\ + :so=\E0P:ue=\E0@:us=\E0`:se=\E0@:ug#1:sg#1:tc=regent25: +a5|regent40+|Adds Regent 40+:is=\EB:tc=regent40: +a6|regent60|regent200|Adds Regent 60:se=\ER\E0@\EV:so=\ER\E0P\EV:dc=\EE:ei=\EF:\ + :im=\EF:is=\EV\EB:ko=dc,im,ei:tc=regent40+: +a7|regent60na|regent 60 w/no arrow keys:\ + kl@:kr@:ku@:kd@:tc=regent60: +# +# adds viewpoint 90 - from cornell +# Note: emacs sends ei occasionally to insure the terminal is out of +# insert mode. This unfortunately puts the viewpoint90 IN insert +# mode. A hack to get around this is: ic=\EF \EF^U. (Also, +# - ei=:im=: must be present.) +# - xs indicates glich that attributes stick to location +# - bs save to move in standout mode +# - cl=\EG\Ek clears screen and visual attributes without affecting +# the status line +a9|vp90|viewpoint90|adds viewpoint 90:\ + :bs:bw:cd=\Ek:ce=\EK:cl=\EG\Ek:cm=\EY%+ %+ :co#80:\ + :dc=\EE:dl=\El:dm=:do=^J:ed=:ei=:im=:ic=\EF \EF^U:ho=\EY :\ + :nd=^F:up=^Z:\ + :kb=^H:kd=^J:kh=^A:kl=^U:kr=^F:ku=^Z:li#24:ll=^A:\ + :so=\ER\E0Q\EV:se=\ER\E0@\EV:\ + :us=\ER\E0`\EV:ue=\ER\E0@\EV:\ + :xs:ms: +# Note: if return acts weird on a980, check internal switch #2 +# on the top chip on the CONTROL pc board. +ac|a980|adds consul 980:\ + :do=^J:al=13\E^N:am:le=^H:bs:cl=^L\200^K@:cm=^K%+@\E^E%2:co#80:\ + :dl=13\E^O:k0=\E0:k1=\E1:k2=\E2:k3=\E3:k4=\E4:k5=\E5:k6=\E6:k7=\E7:\ + :k8=\E8:k9=\E9:li#24:nd=\E^E01:so=^Y^^^N:se=^O:up=9: +as|viewpt60|viewpoint60|addsviewpoint60|adds viewpoint60:\ + :tc=regent40: +# From Onyx:edward Thu Jul 9 09:27:33 1981 +av|viewpoint|addsviewpoint|adds viewpoint:\ + :do=^J:am:le=^H:bs:li#24:co#80:cm=\EY%+ %+ :cd=\Ek:ce=\EK:\ + :up=^Z:cl=^L:ll=^A:kl=^U:kd=^J:ku=^Z:kh=^A:\ + :so=^N:se=^O:us=^N:ue=^O:is=^O\E0`:vs=^O\E0P:ve=^O\E0`: +# # -------------------------------- +# +# b: BEEHIVE +# +# Reports are that most of these Beehive entries (except superbee) have not been +# tested and do not work right. se is a trouble spot. Be warned. +b2|sb2|sb3|fixed superbee:\ + :xb@:tc=superbee: +# set tab is ^F, clear (one) tab is ^V, no way to clear all tabs. +# good grief - does this entry make sg/ug when it doesn't have to? +# look at those spaces in se/so. Seems strange to me... +bh|bh3m|beehiveIIIm:\ + :if=/usr/share/tabset/beehive:do=^J:\ + :al=160^S:am:le=^H:bs:cd=^R:ce=^P:cl=^E^R:\ + :co#80:dl=350^Q:ho=^E:li#20:ll=^E^K:\ + :nd=^L:pt:se= ^_:so=^] :up=^K: +# This loses on lines > 80 chars long, use at your own risk +bi|superbeeic|super bee with insert char:\ + :ic=:im=\EQ:ei=\ER:tc=superbee: +bm|microb|microbee|micro bee series:\ + :do=^J:am:le=^H:bs:cd=\EJ:ce=\EK:cl=\EE:co#80:cm=\EF%+ %+ :\ + :k1=\Ep:k2=\Eq:k3=\Er:k4=\Es:k5=\Et:k6=\Eu:k7=\Ev:k8=\Ew:k9=\Ex:\ + :kd=\EB:kh=\EH:kl=\ED:kr=\EC:ku=\EA:\ + :li#24:nd=\EC:pt:se=\Ed@ :so= \EdP:ue=\Ed@:up=\EA:us=\Ed`: +# Superbee - f1=escape, f2=^C. +# Note: there are at least 3 kinds of superbees in the world. The sb1 +# holds onto escapes and botches ^C's. The sb2 is the best of the 3. +# The sb3 puts garbage on the bottom of the screen when you scroll with +# the switch in the back set to CRLF instead of AEP. This description +# is tested on the sb2 but should work on all with either switch setting. +# The f1/f2 business is for the sb1 and the :xb: can be taken out for +# the other two if you want to try to hit that tiny escape key. +# This description is tricky: being able to use cm depends on there being +# 2048 bytes of memory and the hairy nl string. +bs|sb1|superbee|superb|beehive super bee:\ + :ct=\E3:st=\E1:is=\EH\EJ:do=^J:\ + :sf=\n\200\200\200\n\200\200\200\EA\EK\200\200\200\ET\ET:\ + :am:le=^H:bs:cd=3\EJ:ce=3\EK:cl=3\EH\EJ:co#80:cm=\EF%r%3%3:cr=1000\r:\ + :dC#10:da:db:xb:dc=3\EP:dl=100\EM:so=\E_1:se=\E_3:\ + :li#25:nl=\n\200\200\200\n\200\200\200\EA\EK\200\200\200\ET\ET:\ + :nd=\EC:pt:up=\EA:ho=\EH:ve=\n:\ + :k1=\Ep:k2=\Eq:k3=\Er:k4=\Es:k5=\Et:k6=\Eu:k7=\Ev:k8=\Ew:\ + :kd=\EB:kh=\EH:kl=\ED:kr=\EC:ku=\EA: +# 8675, 8686, and bee from Cyrus Rahman +b7|8675|harris 8675:\ + :k1=^F:k2=^P:k3=^N:k4=^V:k5=^J:k6=^T:k7=^H:k8=\177:k9=\Ee:k10=\Ed:\ + :k11=^W:k12=\ER:k13=\EE:k14=\EI:k15=\Ei:k16=\Eg:\ + :is=\ES\E#\E*\Eh\Em\E?\E1\E9\E@\EX\EU:\ + :tc=bee: +b8|8686|harris 8686:\ + :k1=^B^[p^C:k2=^B^[q^C:k3=^B^[r^C:k4=^B^[s^C:k5=\E3:\ + :k6=\EI:k7=\ER:k8=\EJ:k9=\E(:k10=\Ej:k11=\EW:\ + :k12=^B^[{^C:k13=^B^[|^C:k14=^B^[}^C:k15=^B^[~^C:k16=^B^[\177^C:\ + :is=\ES\E#\E*\Eh\Em\E?\E1\E9\E@\EX\EU\E"*Z01\ + \E"8F35021B7C83#\E"8F45021B7D83#\E"8F55021B7E83#\E"8F65021B7F83#\ + \E"8F75021B7383#\E"8F851BD7#\E"8F95021B7083#\E"8FA5021B7183#\ + \E"8FB5021B7283#:\ + :tc=bee: +be|bee|harris beehive:\ + :co#80:li#24:am:bs:cd=\EJ:ce=\EK:cl=\EE:nd=\EC:\ + :cm=\EF%+ %+ :up=\EA:do=\EB:ho=\EH:bt=\E>:\ + :al=\EL:dc=\EP:dl=\EM:ei=\E@:im=\EQ:ic=:mi:\ + :kl=\ED:kr=\EC:ku=\EA:kd=\EB:kh=\EH:kb=^H:\ + :us=\Ed`:ue=\Ed@:so=\EdP:se=\Ed@:\ + :ko=al,bt,ce,cl,dc,dl,ei,ho,ic,im: +# # -------------------------------- +# +# c: CONCEPT (HUMAN DESIGNED SYSTEMS) +# +# From vax135!hpk Sat Jun 27 07:41:20 1981 +# Extensive changes to c108 by arpavax:eric Feb 1982 +# +# There seem to be a number of different versions of the C108 PROMS +# (with bug fixes in its Z-80 program). +# The first one that we had would lock out the keyboard of you +# sent lots of short lines (like /usr/dict/words) at 9600 baud. +# Try that on your C108 and see if it sends a ^S when you type it. +# If so, you have an old version of the PROMs. +# The old one also messed up running vi with a 132-character line-length. +# You should configure the C108 to send ^S/^Q before running this. +# It is much faster (at 9600 baud) than the c100 because the delays +# are not fixed. +# new status line display entries for c108: +# hs - has status capability +# es - escape sequences are OK on status line +# i2 - second init str - setup term for status display - set programmer mode, +# select window 2, define window at last line of memory, +# set bkgnd stat mesg there, select window 0. +# ts - to status line - select window 2, home cursor, erase to end-of-window, +# 1/2 bright on, goto(line#0, col#?) +# fs - from status line - 1/2 bright off, select window 0 +# ds - disable status display - set bkgnd status mesg with illegal window # +# +# the following two entries are for emacs -- they are just like the regular +# entries except that they have buffer overflow control OFF +c0|e108-8p:\ + :i2=\EU\E z"\Ev^A\177 !p\E ;"\E z \Ev ^A\177p\Ep\n:\ + :te=\Ev ^A\177p\Ep\r\n:tc=e108-4p: +c1|e108-4p:\ + :is=\EU\E f\Ef\E7\E5\E8\El\ENH\EK\E\200\Eo&\200\Eo\47\E\E!\E^G!\E^HA@ :\ + :tc=c108-4p: +c2|c108|c108-8p|concept108-8p|concept 108 w/8 pages:\ + :i2=\EU\E z"\Ev^A\177 !p\E ;"\E z \Ev ^A\177p\Ep\n:\ + :te=\Ev ^A\177p\Ep\r\n:tc=c108-4p: +c3|c108-4p|concept108-4p|concept 108 w/4 pages:\ + :es:hs:ts=\E z"\E?\E^C\Ea %+ :fs=\E z :ds=\E ;\177:\ + :i2=\EU\E z"\Ev\177 !p\E ;"\E z \Ev \177p\Ep\n:do=^J:pt:\ + :is=\EU\E F\Ef\E7\E5\E8\El\ENH\EK\E\200\Eo&\200\Eo\47\E\E!\E^G!\E^HA@ :\ + :ti=\EU\Ev 8p\Ep\r:te=\Ev \177p\Ep\r\n:\ + :al=\E^R:le=^H:bs:cd=\E^C:ce=\E^S:cl=\E?\E^E:cm=\Ea%+ %+ :co#80:\ + :dc=\E^Q:dl=\E^B:ei=\E\200:eo:im=\E^P:li#24:mi:nd=\E=:\ + :kb=^h:up=\E;:db:us=\EG:ue=\Eg:vs=\EW:ve=\Ew:am:xn:\ + :vb=\Ek\200\200\200\200\200\200\200\200\200\200\200\200\200\200\EK:\ + :ks=\EX:ke=\Ex:ku=\E;:kd=\E<:kl=\E>:kr=\E=:kh=\E?:\ + :k1=\E5:k2=\E6:k3=\E7:k4=\E8:k5=\E9:k6=\E\72:\ + :so=\ED:se=\Ed:mh=\EE:md=\ED:mr=\ED:me=\Ee\Ed\Eg\Ec: +c4|c108-rv-8p|concept108-rv-8p|concept 108 w/8 pages, in reverse video:\ + :vb=\EK\200\200\200\200\200\200\200\200\200\200\200\200\200\200\Ek:\ + :is=\EU\E F\Ef\E7\E5\E8\El\ENH\Ek\E\200\Eo&\200\Eo\47\E\E!\E^G!\E^HA@ :\ + :ts=\E z"\E?\E^C\EE\Ea %+ :fs=\Ee\E z :tc=c108-8p: +c5|c108-rv-4p|concept108-rv-4p|concept 108 w/4 pages, in reverse video:\ + :vb=\EK\200\200\200\200\200\200\200\200\200\200\200\200\200\200\Ek:\ + :is=\EU\E F\Ef\E7\E5\E8\El\ENH\Ek\E\200\Eo&\200\Eo\47\E\E!\E^G!\E^HA@ :\ + :ts=\E z"\E?\E^C\EE\Ea %+ :fs=\Ee\E z :tc=c108-4p: +c6|c108-na|c108-na-8p|concept108-na-8p|concept 108 w/8 pages, no arrows:\ + :ks@:ke@:k7=\E;:k8=\E<:k9=\E=:tc=c108-8p +c7|c108-rv-na|c108-rv-na-8p|concept 108 w/8 pages, no arrows in rev video:\ + :ts=\E z"\E?\E^C\EE\Ea %+ :fs=\Ee\E z :\ + :ks@:ke@:k7=\E;:k8=\E<:k9=\E=:tc=c108-rv-8p +# this needs new frotz in the cm capability for 2-char addrs when > 95.... +c8|c108-w|c108-w-8p|concept108-w-8p|concept 108 w/8 pages in wide mode:\ + :is=\EU\E F\Ef\E7\E5\E8\El\ENH\EK\E\200\Eo&\200\Eo\47\E\E"\E^G!\E^HA@ :\ + :ti=\EU\Ev 8^AD\Ep\r:te=\Ev ^A0^AD\Ep\r\n:pt@:cm@:\ + :co#132:tc=c108-8p +cA|avt-w|avtw|HDS concept avt w/4 or 8 pages; 132 columns:\ + :is=\E[1*q\E[2!t\E[7!t\E[=4;101;119l\E[=103;107;118;207h\E)1\E[1Q\EW\E[7!y\E[0\0720\07232!r\E[w\E2\r\n:\ + :ch=\E[%i%3G:cm=\E[%i%2;%3H:co#132:tc=avt: +cB|avt-8p-s|concept avt w/8 pages & 80 cols running sysline:\ + :is=\E[1*q\E[2!t\E[7!t\E[=4;101;103;119l\E[=107;118;207h\E)1\E[1Q\EW\E[0!y\E[0\0720\07232!r\E[2!w\E[192w\E[2*w\E[!w\E[1;191w\E2\r\n:\ + :hs:es:ts=\E[2!w\E[H\E[J\E[%i%dG:fs=\E[!w:\ + :ds=\E[2!w\E[2J\E[!w\E[*w:te=\E[1;191w\E2\n:tc=avt: +cC|avt-4p-s|concept avt w/4 pages & 80 cols running sysline:\ + :is=\E[1*q\E[2!t\E[7!t\E[=4;101;103;119l\E[=107;118;207h\E)1\E[1Q\EW\E[0!y\E[0\0720\07232!r\E[2!w\E[96w\E[2*w\E[!w\E[1;95w\E2\r\n:\ + :hs:es:ts=\E[2!w\E[H\E[J\E[%i%dG:fs=\E[!w:\ + :ds=\E[2!w\E[2J\E[!w\E[*w:te=\E[1;95w\E2\n:tc=avt: +cD|avt-rv|HDS concept avt w/4 or 8 pages, 80 columns, reverse video:\ + :is=\E[1*q\E[2!t\E[7!t\E[=4;101;103;119l\E[=107;118;205;207h\E)1\E[1Q\EW\E[0!y\E[0\0720\07232!r\E[w\E2\r\n:\ + :ve=\E[4l:vs=\E[4l:tc=avt +cE|avt|HDS concept avt w/4 or 8 pages, 80 columns:\ + :is=\E[1*q\E[2!t\E[7!t\E[=4;101;103;119;205l\E[=107;118;207h\E)1\E[1Q\EW\E[0!y\E[0\0720\07232!r\E[w\E2\r\n\E[*w:\ + :ae=^O:al=\E[L:am:as=^N:bs:bt=\E[Z:cd=\E[J:ce=\E[K:\ + :ch=\E[%i%2G:cl=\E[H\E[J:cm=\E[%i%2;%2H:co#80:cv=\E[%i%2d:\ + :dc=\E[P:dl=\E[M:do=\E[B:ei=\E1:eo:ho=\E[H:im=\E1:kb=^H:kd=\E[B:\ + :kh=\E[H:kl=\E[D:ko=do,ho,nd,up:kr=\E[C:\ + :ks=\E[1;4!z\E[1;8!z\E[1;10!z\E[1;11!z\E[1;12!z\E[1;14!z\E[3;7!z\E[3;9!z:\ + :ke=\E[;4!z\E[;8!z\E[;10!z\E[;11!z\E[;12!z\E[3;14!z\E[;7!z\E[;9!z:\ + :ku=\E[A:li#24:mi:nd=\E[C:pt:se=\E[7!{:so=\E[7m:\ + :te=\E[w\E2\n:ti=\E[1;24w\E2\n:ue=\E[4!{:\ + :up=\E[A:us=\E[4m:ve=\E[=4;119l:vs=\E[4l\E[=119h:xn: +# +# Concepts have only window relative cursor addressing, not screen relative. +# To get it to work right here, ti/te (which were invented for the concept) +# lock you into a one page window for screen style programs. To get out of +# the one page window, we use a clever trick: we set the window size to zero +# ("\Ev " in te) which the terminal recognizes as an error and resets the +# window to all of memory. +# +# Some tty drivers use cr3 for concept, others use nl3, hence dN/dC below. +# This padding is only needed at 9600 baud. +# 2 nulls padding on te isn't always enough. 6 works fine. Maybe less +# than 6 but more than 2 will work. +ca|c100|concept|c1004p|c100-4p|concept100|concept 100:\ + :is=\EU\Ef\E7\200\200\E5\E8\200\200\El\ENH\EK\E\200\Eo&\200\Eo\47\E\E^G\041\E^HA@ :\ + :ti=\EU\Ev 8p\Ep\r:te=\Ev \200\200\200\200\200\200\Ep\r\n:\ + :al=3*\E^R:am:le=^H:bs:cd=16*\E^C:ce=16\E^U:cl=2*^L:cm=\Ea%+ %+ :co#80:\ + :dc=16\E^Q:dl=3*\E^B:ei=\E\200:eo:im=\E^P:ip=16*:li#24:mi:nd=\E=:\ + :pt:kb=^h:ta=8\t:up=\E;:db:us=\EG:ue=\Eg:xn:\ + :vb=\Ek\200\200\200\200\200\200\200\200\200\200\200\200\200\200\EK:\ + :.dN#9:dC#9:pb#9600:vt#8:us=\EG:ue=\Eg:so=\EE\ED:se=\Ed\Ee:\ + :mh=\EE:mr=\ED:mb=\EC:mp=\EI:mk=\EH:me=\EN\200:do=^J:\ + :ks=\EX:ke=\Ex:ku=\E;:kd=\E<:kl=\E>:kr=\E=:kh=\E?:k1=\E5:k2=\E6:k3=\E7: +cb|c100-rv-pp|c100-rv-4p-pp|concept100-rv-pp|c100rv4ppp|w/ printer port:\ + :is=\EU\Ef\E7\200\200\E5\E8\200\200\El\ENH\Ek\E\200\Eo&\200\Eo\041\200\EQ"\EY(^W\Eo\47\E\E^G\041\E^HA@ :\ + :tc=c100-rv: +cc|c100-rv-na|c100-rv-4p-na|concept100-rv-na|c100rv4pna|c100 with no arrows:\ + :ks@:ke@:tc=c100-rv: +cd|c100-rv|c100-rv-4p|concept100-rv|c100rv4p|c100rv|c100 rev video:\ + :is=\EU\Ef\E7\200\200\E5\E8\200\200\El\ENH\Ek\E\200\Eo&\200\Eo\47\E\E^G\041\E^HA@ :\ + :vb=\EK\200\200\200\200\200\200\200\200\200\200\200\200\200\200\Ek:\ + :so=\EE:se=\Ee:tc=c100: +# This is useful at 1200 baud. +ce|c100-s|concept-s|concept100-s|slow concept 100:\ + :vb=\Ek\200\EK:pt:dC@:dN@:tc=c100: +cf|c100-rv-s|concept-rv-s|concept100-rv-s|c100rvs|slow reverse concept 100:\ + :vb=\EK\200\Ek:pt:dC@:dN@:tc=c100-rv: +# # -------------------------------- +# +# d: DEC (DIGITAL EQUIPMENT CORPORATION) +# +# Note that xn glitch in vt100 is not quite the same as concept, since +# the cursor is left in a different position while in the weird state +# (concept at beginning of next line, vt100 at end of this line) so +# all versions of vi before 3.7 don't handle xn right on vt100. +# I assume you have smooth scroll off or are at a slow enough baud +# rate that it doesn't matter (1200? or less). Also this assumes +# that you set auto-nl to "on", if you set it off use vt100-nam below. +# +# Since there are two things here called vt100, the installer can make +# a local decision to make either one standard "vt100" by including +# it in the list of terminals in reorder, since the first vt100 in +# /etc/termcap is the one that it will find. The choice is between +# nam (no automatic margins) and am (automatic margins), as determined +# by the wrapline switch (group 3 #2). I presonally recommend turning +# on the bit and using vt100-am, since having stuff hammer on the right +# margin is sort of hard to read. However, the xn glitch does not occur +# if you turn the bit off. +# +# I am unsure about the padding requirements listed here. I have heard +# a claim that the vt100 needs no padding. It's possible that it needs +# padding only if the xon/xoff switch is off. For UNIX, this switch +# should probably be on. +# +# The vt100 uses rs and rf rather than is/ct/st because the tab settings +# are in non-volatile memory and don't need to be reset upon login. +# You can type "reset" to get them set. +dp|vt100-np|vt100 with no padding (for psl games):\ + :cl=\E[H\E[2J:sr=\EM:cm=\E[%i%d;%dH:nd=\E[C:up=\E[A:\ + :ce=\E[K:cd=\E[J:so=\E[7m:se=\E[m:us=\E[4m:ue=\E[m:\ + :md=\E[1m:mr=\E[7m:mb=\E[5m:me=\E[m:tc=vt100: +d0|vt100|vt100-am|vt100am|dec vt100:\ + :do=^J:co#80:li#24:cl=50\E[;H\E[2J:sf=2*\ED:\ + :le=^H:bs:am:cm=5\E[%i%d;%dH:nd=2\E[C:up=2\E[A:\ + :ce=3\E[K:cd=50\E[J:so=2\E[7m:se=2\E[m:us=2\E[4m:ue=2\E[m:\ + :md=2\E[1m:mr=2\E[7m:mb=2\E[5m:me=2\E[m:is=\E[1;24r\E[24;1H:\ + :rf=/usr/share/tabset/vt100:\ + :rs=\E>\E[?3l\E[?4l\E[?5l\E[?7h\E[?8h:ks=\E[?1h\E=:ke=\E[?1l\E>:\ + :ku=\EOA:kd=\EOB:kr=\EOC:kl=\EOD:kb=^H:\ + :ho=\E[H:k1=\EOP:k2=\EOQ:k3=\EOR:k4=\EOS:pt:sr=2*\EM:vt#3:xn:\ + :sc=\E7:rc=\E8:cs=\E[%i%d;%dr: +d1|vt100-nam|vt100nam|vt100 w/no am:\ + :am@:xn@:\ + :is=\E>\E[?3l\E[?4l\E[?5l\E[?7l\E[?8h:ks=\E[?1h\E=:ke=\E[?1l\E>:\ + :tc=vt100-am: +d2|gt42|dec gt42:\ + :do=^J:le=^H:bs:co#72:ns:li#40:os: +d3|vt132|vt132:\ + :al=99\E[L:dl=99\E[M:ip=7:dc=7\E[P:ei=\E[4l:im=\E[4h:xn:dN#30:tc=vt100: +d4|gt40|dec gt40:\ + :do=^J:le=^H:bs:co#72:ns:li#30:os: +d5|vt50|dec vt50:\ + :do=^J:le=^H:bs:cd=\EJ:ce=\EK:cl=\EH\EJ:co#80:li#12:nd=\EC:pt:up=\EA: +d6|vt125|vt125-am|DEC vt125:\ + :xn:do=^J:co#80:li#24:cl=50\E[H\E[2J:dC=10:dN=10:\ + :le=^H:am:bs:cm=5\E[%i%d;%dH:nd=2\E[C:up=2\E[A:ce=3\E[K:cd=50\E[J:\ + :so=2\E[7m:se=2\E[m:us=2\E[4m:ue=2\E[m:md=2\E[1m:mr=2\E[7m:mb=2\E[5m:\ + :me=2\E[m:is=\E[1;24r\E[24;1H\E>\E[?3l\E[?4l\E[?5l\E[?7h\E[?8h:\ + :ks=\E[?1h\E=:ke=\E[?1l\E>:if=/usr/share/tabset/vt100:ku=\EOA:kd=\EOB:\ + :kr=\EOC:kl=\EOD:kb=^H:ho=\E[H:k1=\EOP:k2=\EOQ:k3=\EOR:k4=\EOS:\ + :pt:sr=5\EM:vt#3:sc=\E7:rc=\E8:cs=\E[%i%d;%dr: +d9|vt125-nam|DEC vt125 no automatic margin:\ + :am@:tc=vt125-am: +# DEC gigi color graphic terminal, same as vt52 +d7|gigi|dec gigi terminal:\ + :co#80:is=200\E>\E[?4l\E[?5l\E[?7h\E[?8h:\ + :li#24:cl=100\E[;H\E[2J:bs:cm=50\E[%i%2;%2H:nd=200\E[C:up=100\E[A:\ + :ce=120\E[K:cd=100\E[J:so=20\E[7m:se=20\E[m:us=20\E[4m:ue=20\E[m:\ + :ks=200\E[?1h\E=:ke=200\E[?1l\E>:\ + :ku=\EOA:kd=\EOB:kr=\EOC:kl=\EOD:\ + :kh=\E[H:k1=\EOP:k2=\EOQ:k3=\EOR:k4=\EOS:pt:sr=200\EM:\ + :dC=50:dF=200:dN=50:dT=50: +dI|dw1|decwriter I:\ + :do=^J:le=^H:bs:co#72:hc:os: +# From tut@Topaz.CC Thu May 12 14:49:02 1983 +dJ|dw3|la120|decwriter III:\ + :bs:kb=^H:co#132:hc:os:pt:\ + :is=\E(B\E[20l\E[w\E[1;132s\E[2g\E[9;17;25;33;41;49;57;65;73;81;89;97;105;113;121;129u\E[z\E[66t\E[1;66r\E[4g\E>\r: +# From tut@topaz.CC Thu Sep 24 22:10:46 1981 +df|dw4|decwriter IV:\ + :do=^J:le=^H:bs:co#132:hc:os:am:\ + :pt:is=\Ec:k0=\EOP:k1=\EOQ:k2=\EOR:k3=\EOS:kb=^H: +dh|vt50h|dec vt50h:\ + :do=^J:le=^H:bs:cd=\EJ:ce=\EK:cl=\EH\EJ:cm=\EY%+ %+ :\ + :co#80:li#12:nd=\EC:pt:sr=\EI:up=\EA: +di|vt100-s|vt100 with status line at top:\ + :li#23:i2=\E[2;24r\E[24;1H:cm@:ho=\E[H^J:cl=50\E[;H^J\E[0J:\ + :hs:es:ts=\E7\E[1;%dH\E[1K:fs=\E8:tc=vt100-am: +dj|vt100-s-bot|vt100 with status line at bottom:\ + :li#23:i2=\E[1;23r\E[23;1H:\ + :hs:es:ts=\E7\E[24;%dH\E[1K:fs=\E8:tc=vt100-am: +ds|vt100-nav|dec vt100 132 cols 14 lines (w/o advanced video option):\ + :li#14:tc=vt100-w: +dt|vt100-w|dec vt100 132 cols (w/advanced video):\ + :co#132:li#24:rs=\E>\E[?3h\E[?4l\E[?5l\E[?8h:tc=vt100-am: +dv|vt100-w-nam|dec vt100 132 cols (w/advanced video), no am:\ + :co#132:li#24:rs=\E>\E[?3h\E[?4l\E[?5l\E[?8h:vt@:tc=vt100-nam: +d8|vt102|vt100 w/adv. video:\ + :al=\E[1L:dl=\E[1M:im=\E[4h:ei=\E[4l:mi:dc=\E[1P:ku=\EOA:kd=\EOB:\ + :kr=\EOC:kl=\EOD:k0=\EOp:k1=\EOq:k2=\EOr:k3=\EOs:k4=\EOt:k5=\EOu:\ + :k6=\EOv:k7=\EOw:k8=\EOx:k9=\EOy:as=\E(0:ae=\E(B:am@:xn@:tc=vt100am: +# (from lai@decwrl) should be a vt102, but have heard enough +# unsubstantiated complaints to make it an alternate (obsolete) version +dy|vt102-obs|dec vt102:\ + :do=^J:co#80:li#24:cl=50\E[;H\E[2J:\ + :le=^H:bs:cm=5\E[%i%d;%dH:nd=2\E[C:up=2\E[A:\ + :ce=3\E[K:cd=50\E[J:so=2\E[7m:se=2\E[m:us=2\E[4m:ue=2\E[m:\ + :md=2\E[1m:mr=2\E[7m:mb=2\E[5m:me=2\E[m:is=\E[1;24r\E[24;1H:\ + :rs=\E>\E[?3l\E[?4l\E[?5l\E[?7h\E[?8h:ks=\E[?1h\E=:ke=\E[?1l\E>:\ + :ku=\EOA:kd=\EOB:kr=\EOC:kl=\EOD:kb=^H:\ + :ho=\E[H:k1=\EOP:k2=\EOQ:k3=\EOR:k4=\EOS:pt:sr=5\EM:vt#3:\ + :sc=\E7:rc=\E8:cs=\E[%i%d;%dr:vs=\E[?7l:ve=\E[?7h: +dw|vt52|dec vt52:\ + :do=^J:le=^H:bs:cd=\EJ:ce=\EK:cl=\EH\EJ:cm=\EY%+ %+ :co#80:li#24:\ + :nd=\EC:pt:sr=\EI:up=\EA:ku=\EA:kd=\EB:kr=\EC:kl=\ED:kb=^H: +# vt61 created by Roger Sacilotto Massachusetts Computer Associates, Inc +# Similar to vt52 but add al and dl +# +dq|vt61|dec vt61:\ + :al=\EPf:dl=\EPd:tc=vt52: +dx|dw2|decwriter II:\ + :do=^J:kb=^h:le=^H:bs:co#132:hc:os: +# DEC PRO-350 console (VT220-style) +dP|pro350|decpro|dec pro console:\ + :bs:cd=\EJ:ce=\EK:cl=\EH\EJ:\ + :cm=\EY%+ %+ :co#80:ho=\EH:\ + :kl=\ED:kr=\EC:ku=\EA:kd=\EB:kh=\EH:\ + :k0=\EE:k1=\EF:k2=\EG:k3=\EH:k4=\EI:k5=\EJ:k6=\Ei:k7=\Ej:\ + :li#24:nd=\EC:pt:sr=\EI:up=\EA:do=\EB:\ + :se=\E^N:so=\E^H:us=\E^D:ue=\E^C:\ + :ae=\EG:as=\EF: +# +# From: Bracy H. Elton +dl|vt200|vt220|vt200-js|vt220-js|dec vt200 series with jump scroll:\ + :im=\E[4h:ei=\E[4l:mi:dc=\E[P:dm=:ed=:al=\E[L:dl=\E[M:\ + :cs=\E[%i%d;%dr:sf=\ED:sr=\EM:sb=\EM:\ + :ce=\E[K:cl=\E[H\E[J:cd=\E[J:cm=\E[%i%d;%dH:nd=\E[C:up=\E[A:\ + :so=\E[7m:se=\E[27m:us=\E[4m:ue=\E[24m:\ + :md=\E[1m:mr=\E[7m:mb=\E[5m:me=\E[m:\ + :is=\E>\E[?3l\E[?4l\E[?5l\E[?7h\E[?8h\E[1;24r\E[24;1H:\ + :rs=\E>\E[?3l\E[?4l\E[?5l\E[?7h\E[?8h:\ + :tc=vt100: +dm|vt200-ss|vt220-ss|dec vt200 series with smooth scroll:\ + :is=\E>\E[?3l\E[?4h\E[?5l\E[?7h\E[?8h\E[1;24r\E[24;1H:\ + :rs=\E>\E[?3l\E[?4h\E[?5l\E[?7h\E[?8h:\ + :tc=vt200: +dn|vt200-w|vt220-w|vt200-wj|vt220-wj|dec vt200 series; 132 col.; jump scroll:\ + :is=\E>\E[?3h\E[?4l\E[?5l\E[?7h\E[?8h\E[1;24r\E[24;1H:\ + :rs=\E>\E[?3h\E[?4l\E[?5l\E[?7h\E[?8h:\ + :co#132:tc=vt200: +do|vt200-ws|vt220-ws|dec vt200 series; 132 col.; smooth scroll:\ + :is=\E>\E[?3h\E[?4h\E[?5l\E[?7h\E[?8h\E[1;24r\E[24;1H:\ + :rs=\E>\E[?3h\E[?4h\E[?5l\E[?7h\E[?8h:\ + :co#132:tc=vt200: +dl|vt300|vt320|vt340|dec vt300 series with jump scroll:\ + :im=\E[4h:ei=\E[4l:mi:dc=\E[P:dm=:ed=:al=\E[L:\ + :cs=\E[%i%d;%dr:sf=\ED:sr=\EM:sb=\EM:\ + :ce=\E[K:cl=\E[H\E[J:cd=\E[J:cm=\E[%i%d;%dH:nd=\E[C:up=\E[A:\ + :so=\E[7m:se=\E[27m:us=\E[4m:ue=\E[24m:\ + :md=\E[1m:mr=\E[7m:mb=\E[5m:me=\E[m:\ + :is=\E>\E[?3l\E[?4l\E[?5l\E[?7h\E[?8h\E[1;24r\E[24;1H:\ + :rs=\E>\E[?3l\E[?4l\E[?5l\E[?7h\E[?8h:\ + :tc=vt100: +# @(#)termcap X10/6.6 11/7/86, minus alternate screen, plus :cs +vs|xterm|vs100|xterm terminal emulator (X window system):\ + :do=^J:le=^H:ho=\E[H:\ + :co#80:li#65:cl=\E[H\E[2J:bs:am:cm=\E[%i%d;%dH:nd=\E[C:up=\E[A:\ + :ce=\E[K:cd=\E[J:so=\E[7m:se=\E[m:us=\E[4m:ue=\E[m:\ + :md=\E[1m:mr=\E[7m:me=\E[m:\ + :ku=\EOA:kd=\EOB:kr=\EOC:kl=\EOD:kb=^H:\ + :k1=\EOP:k2=\EOQ:k3=\EOR:k4=\EOS:pt:sf=\n:sr=\EM:\ + :al=\E[L:dl=\E[M:im=\E[4h:ei=\E[4l:mi:dc=\E[P:\ + :MT:ks=\E[?1h\E=:ke=\E[?1l\E>:xn:\ + :AL=\E[%dL:DL=\E[%dM:IC=\E[%d@:DC=\E[%dP:\ + :hs:ts=\E[?E\E[?%i%dT:fs=\E[?F:es:ds=\E[?E:\ + :is=\E\E[m\E[?7h\E[?1;4l:cs=\E[%i%d;%dr:\ + :rs=\E[r\E<\E[m\E[H\E[2J\E[?7h\E[?1;3;4;6l: +v2|xterms|vs100s|xterm terminal emulator (small)(X window system):\ + :co#80:li#24:tc=xterm: +# vs100 emulator using tsim (from lai@decwrl) +vt|vs100t|tsim|vs100-tsim:\ + :bs:cm=\EM%+ %+ :ho=\EH:do=^J:up=^K:cl=\EE:ce=\EL:cs=\ES%+ %+ :\ + :so=\Eh:se=\Er:us=\Eu:ue=\Ev:al=\EI:Al=\E+%+ :dl=\ED:Dl=\E-%+ :\ + :ic=\Ei:dc=\Ed:is=\ER:rs=\ER:am:cd=\EQ:pt:nd=\En:li#24:co#80: +# # -------------------------------- +# +# h: HEWLETT PACKARD +# +# Note: no "ho" on HP's since that homes to top of memory, not screen. +# Due to severe 2621 braindamage, the only way to get the arrow keys to +# transmit anything at all is to turn on the function key labels +# (f1-f8) with ks, and even then the poor user has to hold down shift! +# The default 2621 turns off the labels except when it has to to enable +# the function keys. If your installation prefers labels on all the time, +# or off all the time (at the "expense" of the function keys) move the +# 2621-nl or 2621-wl labels to the front using reorder. +# Note: there are newer ROM's for 2621's that allow you to set strap A +# so the regular arrow keys xmit \EA, etc, as with the 2645. However, +# even with this strap set, the terminal stops xmitting if you reset it, +# until you unset and reset the strap! Since there is no way to set/unset +# the strap with an escape sequence, we don't use it in the default. +# If you like, you can use 2621-ba (braindamaged arrow keys). +h1|2621-ba|2621 w/new rom, strap A set:\ + :ks@:ke@:ku=\EA:kd=\EB:kl=\ED:kr=\EC:kh=\Eh:tc=hp2621: +# 2621 with function labels. Most of the time they are off, +# but inside vi, the function key labels appear. You have to +# hold down shift to get them to xmit. +h2|2621|hp2621|hp2621a|hp2621p|2621a|2621p|2621-pb|hp2621-fl|hp 2621:\ + :is=\E&j@\r:bt=\Ei:cm=\E&a%r%dc%dY:dc=2\EP:ip=2:pb#19200:\ + :so=\E&dD:se=\E&d@:us=\E&dD:ue=\E&d@:me=\E&d@:\ + :kh=\Ep\r:ku=\Et\r:kl=\Eu\r:kr=\Ev\r:kd=\Ew\r:\ + :kn#8:k1=\Ep\r:k2=\Eq\r:k3=\Er\r:k4=\Es\r:k5=\Et\r:k6=\Eu\r:k7=\Ev\r:\ + :k8=\Ew\r:ks=\E&jB:ke=\E&j@:ta=2^I:tc=hp: +# 2621k45: untested +# 2622: unsure if this is quite it, have only heard about the terminal. +h3|2621k45|hp2621k45|k45|2622|hp2622|hp 2621 with 45 keyboard:\ + :kb=^H:ku=\EA:kd=\EB:kl=\ED:kr=\EC:kh=\Eh:ks=\E&s1A:ke=\E&s0A:tc=2621: +h4|hp2645|2645|hp45:\ + :mh=\E&dH:mr=\E&dB:us=\E&dD:mb=\E&dA:me=\E&d@:\ + :ku=\EA:kd=\EB:kl=\ED:kr=\EC:kh=\Eh:ks=\E&s1A:ke=\E&s0A:tc=hp: +h5|hp|hewlett-packard:\ + :ct=\E3:st=\E1:do=^J:al=\EL:am:le=^H:bs:\ + :cd=\EJ:ce=\EK:ch=\E&a%dC:cl=\EH\EJ:cm=6\E&a%r%dc%dY:\ + :co#80:cv=\E&a%dY:da:db:dc=\EP:dl=\EM:ei=\ER:im=\EQ:\ + :kb=^H:li#24:mi:nd=\EC:pt:se=\E&d@:so=\E&dJ:\ + :us=\E&dD:ue=\E&d@:up=\EA:xs:vt#6:pb#9600: +# This entry does not use any of the fancy windowing stuff of the 2621. +# Indeed, termcap does not yet handle such stuff. We are looking at it. +h6|hp2626|hp2626a|hp2626p|2626|2626a|2626p|hp 2626:\ + :dc=2\EP:ip=2:se=\E&d@:so=\E&dB:cd=500\EJ:\ + :mr=\E&dB:us=\E&dD:mb=\E&dA:mk=\E&dS:me=\E&d@:ue=\E&d@:\ + :kh=\Eh:ku=\EA:kl=\ED:kr=\EC:kd=\EB:ks=\E&s1A:ke=\E&s0A:\ + :sf=\ES:ta=2^I:xs:tc=2621: +# cD is a pain - but it only screws up at 9600 baud. +# You should use this terminal at 4800 baud or less. +h8|hp2648|hp2648a|2648a|2648|HP 2648a graphics terminal:\ + :cl=50\EH\EJ:cm=20\E&a%r%dc%dY:dc=7\EP:ip=5:tc=2645: +# This terminal should be used at 4800 baud or less. +h9|hp2645-np|2645 w/no padding:cm=\E&a%r%dc%dY:tc=hp2645: +# 2640a doesn't have the Y cursor addressing feature, and C is memory relative +# instead of screen relative, as we need. +ha|2640|hp2640a|2640a|hp 2640a:\ + :cm@:ks@:ke@:tc=2645: +hb|2640b|hp2640b|2644a|hp2644a|hp 264x series:\ + :ks@:ke@:tc=2645: +# 2621 using all 48 lines of memory, only 24 visible at any time. Untested. +hl|2621-48|48 line 2621:\ + :li#48:ho=\EH:cm=\E&a%r%dc%dR:tc=2621: +# Hp 110 computer is the same as 2621 except has 16 lines +hm|hp110|110|hp 110 computer:\ + :li#16:tc=2621: +# 2621 with no labels ever. Also prevents vi delays on escape. +hn|2621-nl|hp2621nl|2621nl|hp2621-nl|hp 2621 with no labels:\ + :ks@:ke@:kh@:ku@:kl@:kr@:kd@:tc=hp2621-fl: +# Needed for UCB ARPAVAX console, since lsi-11 expands tabs (wrong). +ht|hp2621-nt|2621nt|2621-nt|hp2621nt|hp 2621 w/no tabs:\ + :pt@:tc=hp2621: +# 2621 with labels on all the time - normal outside vi, function inside vi. +hw|hp2621wl|2621wl|2621-wl|hp2621-wl|hp 2621 w/labels:\ + :is=\E&jA\r:ke=\E&jA:tc=hp2621-fl: +# 2392 (from haddix@arpa?) +hz|2392|hp2392|hp2392a:\ + :bt=\Ei:ip=2:is=\E&j@\E3\r:if=/usr/share/tabset/stdcrt:\ + :ml=\El:MT:mu=\Em:km:\ + :mh=\E&dH:mr=\E&dB:us=\E&dD:mb=\E&dA:me=\E&d@:\ + :ku=\EA:kd=\EB:kl=\ED:kr=\EC:kh=\Eh:ks=\E&s1A:ke=\E&s0A:tc=hp: +#HP 236 console +#from ddavis@ic.berkeley.edu +h7|236|hp236|HP236 internal terminal emulator:\ + :am:bs:li#24:co#80:cl=\EF:cm=\EE%+ %+ :\ + :dc=\EJ:dl=\EH:ic=\EI:al=\EG:up=^K:im=:ei=:\ + :so=\EBI:se=\ECI:vs=\EDB:ve=\EDE: +# hp150 from ddavis@ic.berkeley.edu +h0|150|hp150|hp150a|150a:\ + :is=\E&s1A\E&f0a1k2L\Ep\r\E&k0K\E&f0a2k2L\Eq\r\E&f0a3k2L\Er\r\E&f0a4k2L\Es\r\E&f0a5k2L\Et\r\E&f0a6k2L\Eu\r\E&f0a7k2L\Ev\r\E&f0a8k2L\Ew\r\E&k0D\E&s0A:\ + :bt=\Ei:li#24:cm=\E&a%r%dc%dY:dc=2\EP:ip=2:pb#19200:so=\E&dJ:\ + :se=\E&d@:us=\E&dD:ue=\E&d@:me=\E&d@:kh=\Eh:ku=\EA:kl=\ED:kr=\EC:\ + :kd=\EB:kn#8:k1=\Ep:k2=\Eq:k3=\Er:k4=\Es:k5=\Et:k6=\Eu:k7=\Ev:\ + :k8=\Ew:ta=2^I:ct=\E3:st=\E1:do=^J:al=\EL:am:le=^H:\ + :bs:cd=\EJ:ce=\EK:ch=\E&a%dC:cl=\Eh\EJ:co#80:cv=\E&a%dY:da:db:dl=\EM:\ + :ei=\ER:im=\EQ:kb=^H:mi:nd=\EC:pt:up=\EA:xs:vt#6:sf=\ES:sr=\ET:\ + :vs=\E&s1A:ve=\E&s0A:ks=\E&jB\E&j@:ke=\E&j@: +# # -------------------------------- +# +# i: INFOTON (GENERAL TERMINAL) +# +# Infoton is now called General Terminal Corp. or some such thing. +# gt100 sounds like something DEC would come out with. Lets hope they don't. +i1|i100|gt100|gt100a|General Terminal 100A (formerly Infoton 100):\ + :do=^J:cl=^L:cd=\EJ:ce=\EK:li#24:co#80:\ + :al=\EL:dl=\EM:up=\EA:nd=\EC:ho=\EH:cm=\Ef%r%+ %+ :vb=\Eb\Ea:\ + :am:le=^H:bs:so=\Eb:se=\Ea: +i4|i400|400|infoton 400:\ + :do=^J:al=\E[L:am:le=^H:bs:ce=\E[N:cl=\E[2J:cm=%i\E[%3;%3H:co#80:\ + :dl=\E[M:li#25:nd=\E[C:up=\E[A:im=\E[4h\E[2Q:ei=\E[4l\E[0Q:\ + :dc=\E[4h\E[2Q\E[P\E[4l\E[0Q: +ia|addrinfo:\ + :do=^J:li#24:co#80:cl=^L:ho=^H:nd=^Y:cd=^K:\ + :up=^\:am:le=^Z:bc=^Z:cm=\037%+\377%+\377:ll=^H^\: +ik|infotonKAS:\ + :do=^J:am:le=^Z:bc=^Z:cd=^K:cl=^L:co#80:li#24:nd=^Y:up=^\:ll=^H^\: +# # -------------------------------- +# +# k: HEATHKIT (ZENITH) +# +kA|h19-a|h19a|heath-ansi|heathkit-a|heathkit h19 ansi mode:\ + :\ + :al=1*\E[1L:am:le=^H:bs:cd=\E[J:ce=\E[K:cl=\E[2J:cm=\E[%i%2;%2H:co#80:\ + :dc=\E[1P:dl=1*\E[1M:do=\E[1B:ei=\E[4l:ho=\E[H:im=\E[4h:li#24:mi:\ + :nd=\E[1C:as=\E[10m:ae=\E[11m:ms:pt:se=\E[0m:so=\E[7m:up=\E[1A:\ + :vs=\E[>4h:ve=\E[>4l:kb=^h:ku=\E[1A:kd=\E[1B:kl=\E[1D:kr=\E[1C:\ + :kh=\E[H:kn#8:k1=\EOS:k2=\EOT:k3=\EOU:k4=\EOV:k5=\EOW:l6=blue:\ + :l7=red:l8=white:k6=\EOP:k7=\EOQ:k8=\EOR:\ + :sr=\EM:is=\E<\E[>1;2;3;4;5;6;7;8;9l\E[0m\E[11m\E[?7h: +kB|h19-bs|h19bs|heathkit w/keypad shifted:\ + :ks=\Et:ke=\Eu:tc=h19-b: +#written by David Shewmake, UCSF Medical Information Science +#ucbvax!ucsfmis!shewmake +kC|h29|heath-29|z29|zenith-29:\ + :am:bc=\ED:bt=\E-:do=^J:\ + :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: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=\E0I:\ + :es:hs:ts=\Ej\Ex5\Ex1\EY8%+ \Eo:fs=\Ek\Ey5:ds=\Ey1:us=\Es8:ue=\Es0: +#the z29-e entry sucks...but it works with emacs +kD|z29-e|zenith 29 hacked for emacs:\ + :ip=1.5:ks=\Et:ke=\Eu:vs@:ve@:al=1*\EL:am:le=^H:\ + :bs:cd=\EJ:ce=\EK:cl=\EE:cm=\EY%+ %+ :co#80:dc=\EN:dl=1*\EM:\ + :do=\EB:ho=\EH:li#24:nd=\EC:as=\EF:ae=\EG:ms:\ + :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: +# z29 in ansi mode. Assumes that the cursor is in the correct state, and that +# the world is stable. `rs' causes the terminal to be reset to the state +# indicated by the name. kc -> key click, nkc -> no key click, uc -> underscore +# cursor, bc -> block cursor. +# from Mike Meyers +kF|z29a|z29a-kc-bc|h29a-kc-bc|heath/zenith 29 in ansi mode:\ + :do=^J:co#80:li#24:cl=\E[2J:pt:ho=\E[H:\ + :le=^H:bs:cm=\E[%i%d;%dH:nd=\E[C:up=\E[A:mb=\E[5m:mr=\E7m:\ + :ce=\E[K:cd=\E[J:so=\E[7;2m:se=\E[m:us=\E[4m:ue=\E[m:mh=\E[2m:\ + :md=\E[2m:mr=\E[7m:mb=\E[5m:me=\E[m:\ + :rs=\E<\E[1;24r\E[24;1H\E[?7h\E[>4h\E[>1;2;3;5;6;7;8;9l\E[m\E[11m:\ + :ku=\EOA:kd=\EOB:kr=\EOC:kl=\EOD:kb=^H:\ + :k1=\EOS:k2=\EOT:k3=\EOU:k4=\EOV:k5=\EOW:k6=\EOP:k7=\EOQ:k8=\EOR:\ + :k9=\EOX:k0=\E[~:l0=help:kn#2:ko=ho,cd:if=/usr/share/tabset/zenith29:\ + :es:hs:ts=\E[s\E[>5;1h\E[25;%i%dH\E[1K:fs=\E[u\E[>5l:ds=\E[>1l:\ + :cs=\E[%i%d;%dr:sr=\EM:sf=\ED:DO=\E[%dB:UP=\E[%dA:LE=\E[%dD:\ + :RI=\E[%dC:AL=\E[%dL:DL=\E[%dM:sc=\E[s:rc=\E[r:dc=\E[1P:DC=\E[%dP:\ + :kC=\E[J:ct=\E[3g:st=\EH:ti=\E[?7l:te=\E[?7h:ps=\E#7: +kG|z29a-kc-uc|h29a-kc-uc|heath/zenith 29 in ansi mode:\ + :rs=\E<\E[1;24r\E[24;1H\E[?7h\E[>1;2;3;4;5;6;7;8;9l\E[m\E[11m:\ + :tc=z29a: +kH|z29a-nkc-bc|h29a-nkc-bc|heath/zenith 29 in ansi mode:\ + :rs=\E<\E[1;24r\E[24;1H\E[?7h\E[>2;4h\E[>1;3;5;6;7;8;9l\E[m\E[11m:\ + :tc=z29a: +kI|z29a-nkc-uc|h29a-nkc-uc|heath/zenith 29 in ansi mode:\ + :rs=\E<\E[1;24r\E[24;1H\E[?7h\E[>2h\E[>1;3;4;5;6;7;8;9l\E[m\E[11m:\ + :tc=z29a: +#z100 entry from Brad Brahms at TRW (Brahms@USC-ECLC) +# usenet: {decvax,ucbvax}!trwrb!trwspp!brahms +kc|z100|h100|z110|z-100|h-100|heath/zenith z-100 pc with color monitor:\ + :vs=\Ex4\Em71:ve=\Ey4\Em70:tc=z100bw: +kY|z100bw|h100bw|z110bw|z-100bw|h-100bw|heath/zenith z-100 pc:\ + :al=5*\EL:bs:cd=\EJ:ce=\EK:cl=5*\EE:cm=1*\EY%+ %+ :co#80:dc=1*\EN:\ + :dl=5*\EM:do=\EB:ei=\EO:ho=\EH:im=\E@:li#24:mi:nd=\EC:as=\EF:ae=\EG:\ + :ms: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#10:\ + :k0=\EJ:k1=\ES:k2=\ET:k3=\EU:k4=\EV:k5=\EW:\k6=\EP:k7=\EQ:\ + :k8=\ER:k9=\EOI: +kp|p19:\ + :al=2*\EL:dl=2*\EM:tc=h19-b: +kU|h19-us|h19us|heathkit w/keypad shifted/underscore cursor:\ + :ks=\Et:ke=\Eu:tc=h19-u: +kb|h19|heath|h19-b|h19b|heathkit|heath-19|z19|zenith|heathkit h19:\ + :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: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:ke=\E>:ks=\E=:\ + :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: +ke|h19-e|h19e|h19 for emacs:ip=1.5:tc=h19-us: +ku|h19-u|h19u|heathkit with underscore cursor:\ + :vs@:ve@:tc=h19-b: +kg|h19-g|h19g|heathkit w/block cursor:\ + :ve=\Ex4:tc=h19-b: +# from ucscc!B.fiatlux@ucbvax.berkeley.edu +zx|ztx|ztx11|zt-1|htx11|ztx-1-a|ztx-10/11:\ + :al=\EL:am:bs:cd=\EJ:ce=\EK:cl=\EE:cm=\EY%+ %+ :co#80:\ + :dl=\EM:do=^J:ho=\EH:is=\Ej\EH\Eq\Ek\Ev\Ey1\Ey5\EG\Ey8\Ey9\Ey>:\ + :k0=\ES:k1=\EB:k2=\EU:k3=\EV:k4=\EW:k5=\EP:k6=\EQ:k7=\ER:kb=^H:kd=\EB:\ + :kl=\ED:kr=\EC:ku=\EA:le=^H:li#24:nd=\EC:pt:se=\Eq:so=\Es5:\ + :sr=\EI:sr=\EI:ue=\Eq:up=\EA:us=\Es2:\ + :es:hs:ts=\Ej\Ex5\Ex1\EY8%+ \Eo:fs=\Ek\Ey5:ds=\Ey1: +# # -------------------------------- +# +# l: LEAR SIEGLER (ADM) +# +# If the adm31 gives you trouble with standout mode, check the DIP switch +# in position 6, bank @c11, 25% from back end of pc. Should be OFF. +# If there is no such switch, you have an old adm31 and must use oadm31 +l1|adm31|31|lsi adm31:\ + :is=\Eu\E0:do=^J:al=\EE:am:le=^H:bs:ce=\ET:cm=\E=%+ %+ :\ + :cl=\E*:cd=\EY:co#80:dc=\EW:dl=\ER:ei=\Er:ho=^^:im=\Eq:\ + :k0=^A0\r:k1=^A1\r:k2=^A2\r:k3=^A3\r:k4=^A4\r:\ + :k5=^A5\r:k6=^A6\r:k7=^A7\r:k8=^A8\r:k9=^A9\r:kd=^J:kl=^H:kr=^L:ku=^K:\ + :li#24:ma=j^Jk^P^K^Pl ^R^L^L :mi:nd=^L:\ + :se=\EG0:so=\EG1:up=^K:us=\EG1:ue=\EG0: +l2|adm2|lsi adm2:\ + :do=^J:al=\EE:am:le=^H:bs:cd=\EY:ce=\ET:cl=\E;:\ + :cm=\E=%+ %+ :co#80:dc=\EW:dl=\ER:\ + :ei=:ho=^^:ic=\EQ:im=:kd=^J:kh=^^:kl=^H:kr=^L:ku=^K:li#24:nd=^L:up=^K: +l3|adm3|3|lsi adm3:\ + :do=^J:am:le=^H:bs:cl=^Z:li#24:ma=^K^P:co#80: +l4|adm42|42|lsi adm42:\ + :vs=\EC\E3 \E3(:do=^J:al=270\EE:am:le=^H:bs:cd=\EY:ce=\ET:cl=\E;:\ + :cm=\E=%+ %+ :co#80:dc=\EW:dl=\ER:ei=\Er:im=\Eq:ip=6*:li#24:\ + :bt=\EI:nd=^L:se=\EG0:so=\EG4:up=^k:ma=^K^P:pc=\177: +l5|adm5|5|lsi adm5:\ + :do=^J:cd=\EY:ce=\ET:do=^J:kb=^H:kh=^^:\ + :ma=^Hh^Jj^Kk^Ll^^H:se=\EG:sg#1:so=\EG:tc=adm3aplus: +l7|adm20|lear siegler adm20:\ + :am:li#24:co#80:bs:cl=^Z:cm=\E=%i%r%+^_%+^_:nd=^L:up=^K:ho=^^:ce=\ET:\ + :cd=\EY:al=\EE:dl=\ER:im=:ei=:ic=\EQ:dm=:ed=:dc=\EW:so=\E):se=\E(:\ + :bt=\EI:pt:kn#7:k1=^A:k2=^B:k3=^W:k4=^D:k5=^E:k6:^X:k7=^Z: +# From Andrew Scott Beals +l8|adm12|12|lsi adm12:\ + :is=\Eq:do=^J:al=\EE:am:le=^H:bs:ce=\ET:cm=\E=%+ %+ :cl=^Z:cd=\EY:\ + :co#80:dc=\EW:dl=\ER:ei=\Er:ho=^^:im=\Eq:\ + :k0=^A0\r:k1=^A1\r:k2=^A2\r:k3=^A3\r:k4=^A4\r:\ + :k5=^A5\r:k6=^A6\r:k7=^A7\r:k8=^A8\r:k9=^A9\r:kd=^J:kl=^H:kr=^L:ku=^K:\ + :li#24:ma=j^Jk^P^K^Pl ^R^L^L :mi:nd=^L:\ + :se=\EG0:so=\EG4:up=^K:us=\EG1:ue=\EG0: +la|adm3a|3a|lsi adm3a:\ + :am:do=^J:le=^H:bs:cm=\E=%+ %+ :cl=1^Z:co#80:ho=^^:\ + :li#24:ma=^K^P:nd=^L:up=^K: +lb|adm3a+|3a+|adm3aplus:\ + :kl=^H:kd=^J:ku=^K:kr=^L:tc=adm3a: +lc|adm22|22|lsi adm22:\ + :is=\E%\014\014\014\016\003\000\003\002\003\002\000\000\000\000\000\000\000\000\000\000\000:\ + :al=\EE:am:bs:bt=\EI:cd=\Ey:ce=\Et:cl=\E+:cm=\000\E=%+ %+ :co#80:\ + :dc=\EW:dl=\ER:do=^J:em=:ho=^^:ic=\EQ:im=:\ + :k1=\001@\015:k2=\001A\015:k3=\001B\015:k4=\001C\015:\ + :k5=\001D\015:k6=\001E\015:k7=\001F\015:kn#7:\ + :ko=ho:l1=F1:l2=F2:l3=F3:l4=F4:l5=F5:l6=F6:l7=F7:\ + :kb=^H:kd=^J:kh=^^:kl=^H:kr=^L:ku=^K:li#24:\ + :ma=j^Jk^P^K^Pl ^R^L^L :nd=^L:se=\E(:so=\E):ta=\Ei:up=^K: +#From: stephen%comp.lancs.ac.uk@ucl-cs.arpa +le|adm11|lsi adm11:\ + :do=^J:bs:\ + :cd=\EY:ce=\ET:kb=^H:kh=^^:\ + :ma=^Hh^Jj^Kk^Ll^^H:so=\E):se=\E(:\ + :kl=^H:kd=^J:ku=^K:kr=^L:\ + :am:cm=\E=%+ %+ :cl=^Z:co#80:li#24:nd=^L:up=^K:\ + :hs:ts=\EF\E):fs=\E(^M:ds=\Eh: +# # -------------------------------- +# +# m: MICROTERM +# +# These mime1 entries refer to the Microterm Mime I or Mime II. +# The default mime is assumed to be in enhanced act iv mode. +m3|mime3a|mime1 emulating 3a:\ + :am@:ma=^X ^K^J^Z^P:ku=^Z:kd=^K:kl=^H:kr=^X:tc=adm3a: +m4|microterm|act4|microterm act iv:\ + :am:do=^J:le=^H:bs:cd=^_:ce=^^:cl=^L:cm=^T%.%.:\ + :co#80:li#24:nd=^X:up=^Z:ho=^]: +# The padding on sr and ta for act5 and mime is a guess and not final. +# The act 5 has hardware tabs, but they are in columns 8, 16, 24, 32, 41 (!)... +m5|microterm5|act5|microterm act v:\ + :uc=^H\EA:sr=3\EH:ku=^Z:kd=^K:kl=^H:kr=^X:ma=^Z^P^Xl^Kj:tc=act4: +# Act V in split screen mode. act5s is not tested and said not to work. +mS|act5s|skinny act5:\ + :ti=\EP:te=\EQ:li#48:co#39:tc=act5: +# Mimes using brightness for standout. Half bright is really dim unless +# you turn up the brightness so far that lines show up on the screen. +# uc is disabled to get around a curses bug, should be put back in someday. +mf|mime-fb|full bright mime1:\ + :so=^Y:se=^S:is=^S\E:tc=mime: +mh|mime-hb|half bright mime1:\ + :so=^S:se=^Y:is=^Y\E:tc=mime: +mm|mime|mime1|mime2|mimei|mimeii|microterm mime1:\ + :do=^J:al=80^A:am:le=^H:bs:cd=^_:ce=^^:cl=\035^C:cm=^T%+^X%> 0%+P:\ + :co#80:dl=80^W:ta=2^I:li#24:nd=^X:pt:uc=^U:up=^z:ho=\035:do=^K:\ + :is=^S\E^Q:ma=^X ^K^J^Z^P:ku=^Z:kd=^K:kl=^H:kr=^X:sr=3^R:vt#9: +# These termcaps (for mime 2a) put the terminal in low intensity mode +# since high intensity mode is so obnoxious. +ms|mime2a-s|microterm mime2a (emulating an enhanced soroc iq120):\ + :do=^J:\ + :al=20*^A:am:le=^H:bs:cd=20*\EJ:ce=\EK:cl=\EL:cm=\E=%+ %+ :co#80:dc=\ED:\ + :dl=20*^W:kl=^H:kr=^L:ku=^K:kd=^J:ho=^^:is=\E):sr=\EI\ + :im=\EE:ei=^Z:ip=2:li#24:nd=^L:so=\E\072:se=\E;:up=\EI:\ + :us=\E6:ue=\E7: +# This is the preferred mode (but ^X can't be used as a kill character) +mv|mime2a|mime2a-v|microterm mime2a (emulating an enhanced vt52):\ + :do=^J:al=20*^A:le=^H:bs:cd=20*\EQ:co#80:ce=\EP:cl=\EL:cm=\EY%+ %+ :\ + :is=^Ydc=^N:dl=20*^W:ip=2:ei=^Z:ho=\EH:im=^O:kd=\EB:kl=\ED:kr=\EC:\ + :ku=\EA:li#24:nd=\EC:pt:se=\E9:so=\E8:up=\EA:sr=\EA:us=\E4:ue=\E5: +mx|mime3ax|mime-3ax|mime1 emulating enhanced 3a:\ + :al=80^A:dl=80^W:pt:ce=^X:cd=^_:tc=mime3a: +# # -------------------------------- +# +# p: PERKIN ELMER +# +pe|pe550|bantam|perkin elmer 550:\ + :do=^J:le=^H:bs:co#80:ce=20\EI:cl=20\EK:cm=\EX%+ \EY%+ :\ + :ho=\EH:li#24:ll=\EH\EA:nd=\EC:up=\EA:ma=^Z^P:cd=6^N@^V: +pf|fox|perkin elmer 1100:\ + :ct=\E3:st=\E1:do=^J:\ + :am:le=^H:bs:cd=5.5*\EJ:ce=\EI:cl=132\EH\EJ:co#80:ho=\EH:li#24:\ + :ll=\EH\EA:nd=\EC:cm=\EX%+ \EY%+ :up=\EA:vb=^P^B^P^C: +po|owl|perkin elmer 1200:\ + :ct=\E3:st=\E1:do=^J:al=5.5*\EL:am:le=^H:\ + :bs:cd=5.5*\EJ:ce=5.5\EI:cl=132\EH\EJ:ho=\EH:ll=\EH\EA:\ + :cm=\EX%+ \EY%+ :co#80:dc=5.5*\EO:dl=5.5*\EM:ei=:ic=\EN:im=:ip=5.5*:\ + :kb=^h:in:li#24:nd=\EC:up=\EA:se?=\E!\200:so?=\E!^H:vb=^P^B^P^C:\ + :k1=\ERA:k2=\ERB:k3=\ERC:k4=\ERD:k5=\ERE:k6=\ERF:\ + :k7=\ERG:k8=\ERH:k9=\ERI:k0=\ERJ: +# # -------------------------------- +# +# q: HOME MADE TERMINALS +# +qB|bc|bill croft homebrew:\ + :do=^J:am:le=^H:bs:cm=\E=%+ %+ :cl=^Z:co#96:ho=^^:li#72:\ + :nd=^L:up=^K:vb=: +qN|nucterm|rayterm|NUC homebrew:\ + :do=^J:am:le=^H:bs:cl=1^L:li#24:co#80:nd=^C:\ + :up=^N:ho=^B:ll=^K:ce=^A:cd=^E: +qb|ex3000:\ + :do=^J:li#24:co#80:ho=^Q: +qc|carlock|klc:\ + :do=^J:al=^E:am:bs:ce=^U:cl=100^Z:cm=\E=%+ %+ :co#80:dc=\177:dl=^D:\ + :dm=:ed=:ei=^T:ho=^^:im=^T:li#24:nd=^L:se=^V:so=^V:up=^K:vb=\EV\EV: +# uVAX +qd|qdss|qdcons|qdss glass tty:\ + :am:do=^J:le=^H:bs:cm=\E=%.%.:cl=1^Z:co#128:li#57::nd=^L:up=^K: +qe|exidy|exidy2500|exidy sorcerer as dm2500:\ + :do=^J:al=^P^J^X:am:le=^H:bs:ce=^W:cl=^^:cm=^L%r%n%.%.:co#64:\ + :dc=\b:dl=^P^Z^X:dm=^P:ed=^X:ei=^X:ho=^B:ic=^\:\ + :im=^P:li#30:nd=^\:pt:so=^N:se=^X:up=^Z: +qn|netx|netronics:\ + :do=^J:le=^H:bs:cd=2000^F^E:ce=1600^E:cl=466^L:cm=\E=%+@%+@:\ + :co#64:ho=^D:li#16:ma=j^Jk^Pl :nd=\E+@A:pc=\200:sr=\E=@@^K:up=^K: +# This came from the comp ctr who got it from some user. Smart indeed! +qs|sexidy|exidy smart:\ + :do=^J:li#24:co#64:cl=^l:ho=^q:nd=^s:\ + :up=^w:le=^H:bs:le=^a:bc=^a:ma=^x^J:kd=^S: +qu|ubell|ubellchar:\ + :if=/usr/share/tabset/ubell:do=^J:am:le=^H:bs:pt:ce=\Ed:cl=^Z:\ + :cm=\E=%+ %+ :co#80:li#24:nd=^L:up=^K:ma=j^Jk^P^K^Pl :ho=^^: +qw|ttyWilliams:\ + :do=^J:co#80:li#12:le=^Y:bc=^Y:do=^K:up=^Z:cl=^^:ce=^_:am:ho=^]:nd=^X: +qx|xitex|xitex sct-100:\ + :do=^J:le=^H:bs:cd=2000^F^E:ce=1600^E:cl=400^L:cm=\E=%+@%+@:co#64:\ + :ho=^D:li#16:ma=j^Jk^Pl :nd=\E+@A:pc=\200:sr=\E=@@^K:up=^K: +# # -------------------------------- +# +# s: SPECIALS +# +# Special "terminals". These are used to label tty lines when you don't +# know what kind of terminal is on it. The characteristics of an unknown +# terminal are the lowest common denominator - they look about like a ti 700. +sa|network:\ + :tc=unknown: +sb|arpanet:\ + :tc=unknown: +sc|bussiplexer:\ + :tc=unknown: +sd|du|dialup:\ + :tc=unknown: +se|ethernet:\ + :tc=unknown: +sl|lpr|printer|print|printing|line printer:\ + :do=^J:le=^H:bs:co#132:hc:os: +sp|plugboard|patch|patchboard:\ + :tc=unknown: +su|dumb|un|unknown:\ + :am:co#80:do=^J: +sw|switch|intelligent switch:\ + :tc=unknown: +sx|ansi|any ansi terminal with pessimistic assumptions:\ + :co#80:li#24:cl=50\E[;H\E[2J:bs:am:cm=\E[%i%d;%dH:\ + :nd=\E[C:up=\E[A:ce=\E[K:ho=\E[H:pt: +# # -------------------------------- +# +# t: TEXAS INSTRUMENTS +# +t3|ti|ti700|ti733|735|ti735|ti silent 700:\ + :do=^J:le=^H:bs:co#80:hc:os:dC#162: +t4|ti745|745|743|ti silent 745:\ + :do=^J:le=^H:bs:co#80:hc:os: +t8|ti800|ti omni 800:\ + :do=^J:le=^H:bs:co#132:hc:os: +# From lesleymw@topaz.berkeley.edu +t9|ti931|ti 931:\ + al=\EN:am:bs:cd=\EJ:ce=\EI:cl=\EL:cm=\EY%+ %+ :co=#80:dl=\EO:do=\EB:\ + eo:ho=\EH:li=#24:ku=\EA:kd=\EB:kr=\EC:kl=\ED:mi:nd:sf=\Eb:sr=\Ea:up=\EA: +# # -------------------------------- +# +# v: TELEVIDEO +# +# There are some tvi's that require incredible amounts of padding and +# some that don't. I'm assuming 912 and 920 are the old slow ones, +# and 912b, 912c, 920b, 920c are the new ones that don't need padding. +v1|tvi912|912|920|tvi920|old televideo:\ + :ct=\E3:st=\E1:do=^J:\ + :al=33*\EE:le=^H:ce=\ET:cm=\E=%+ %+ :cl=^Z:co#80:dc=\EW:dl=33*\ER:ei=:\ + :kb=^H:ku=^K:kd=^J:kl=^H:kr=^L:k0=^AI\r:k1=^A@\r:k2=^AA\r:k3=^AB\r:\ + :bs:am:k4=^AC\r:k5=^AD\r:k6=^AE\r:k7=^AF\r:k8=^AG\r:k9=^AH\r:\ + :ho=^^:im=:ic=\EQ:li#24:nd=^L:pt:se=\Ek:so=\Ej:up=^K:us=\El:ue=\Em:\ + :ma=^K^P^L :sg#1:ug#1:if=/usr/share/tabset/stdcrt +# the 912 has a key that's like shift: 8 xmits "^A8\r". +# The 920 has this plus real function keys that xmit different things. +# Termcap makes you use the funct key on the 912 but the real keys on the 920. +v2|912b|912c|tvi912b|tvi912c|tvi|new televideo 912:\ + :al=5*\EE:dl=5*\ER:tc=tvi912: +v3|920b|920c|tvi920b|tvi920c|new televideo 920:\ + :k0=^AI\r:k1=^A@\r:k2=^AA\r:k3=^AB\r:k4=^AC\r:k5=^AD\r:\ + :k6=^AE\r:k7=^AF\r:k8=^AG\r:k9=^AH\r:al=5*\EE:dl=5*\ER:tc=tvi912: +# set to page 1 when entering ex (\E-17 ) +# reset to page 0 when exiting ex (\E-07 ) +v4|tvi912-2p|tvi920-2p|912-2p|920-2p|tvi-2p|televideo w/2 pages:\ + :ti=\E-17 :te=\E-07 :tc=tvi912: +v5|tvi950-ap|tvi 950 w/alt pages:\ + :is=\E\\1:ti=\E-06 :te=\E-16 :tc=tvi950: +v6|tvi950-b|bare tvi950 no is:\ + :is@:tc=tvi950: +v7|tvi950-ns|tvi950 w/no standout:\ + :so@:se@:us@:ue@:tc=tvi950: +vi|tvi925|925|televideo model 925:\ + :hs:xn:am:bs:co#80:li#24:cm=\E=%+ %+ :cl=\E*:cd=\Ey:ce=\Et:is=\El\E":\ + :al=\EE:dl=\ER:im=:ei=:ic=\EQ:dc=\EW:if=/usr/share/tabset/stdcrt:\ + :ho=^^:nd=^L:bt=\EI:pt:so=\EG4:se=\EG0:sg#1:us=\EG8:ue=\EG0:ug#1:\ + :up=^K:do=^V:kb=^H:ku=^K:kd=^V:kl=^H:kr=^L:kh=^^:ma=^V^J^L :\ + :k1=^A@\r:k2=^AA\r:k3=^AB\r:k4=^AC\r:k5=^AD\r:k6=^AE\r:k7=^AF\r:\ + :k8=^AG\r:k9=^AH\r:k0=^AI\r:ko=ic,dc,al,dl,cl,ce,cd,bt:\ + :ts=\Ef:fs=^M\Eg:ds=\Eh:sr=\Ej: +vj|tvi925vb|925vb|televideo model 925 visual bells:\ + :vb=\Eb\200\200\200\200\200\200\200\200\200\200\200\200\200\200\200\Ed:\ + :tc=tvi925: +# Since the 925's uses a character position to store the escape sequences to go +# in and out of both stand out and underline modes, screen positioning is +# difficult. The following 925 entries don't use these modes. +vn|tvi925n|925n|televideo model 925 no standout or underline:\ + :so@:se@:us@:ue@:tc=tvi925: +vk|tvi925vbn|925vbn|televideo model 925 visual bells no so or ul:\ + :vb=\Eb\200\200\200\200\200\200\200\200\200\200\200\200\200\200\200\Ed:\ + :tc=tvi925n: +# entry by Tim Curry 5/21/82 Univ. of Central Fla. duke!ucf-cs!tim +v9|925a|tvi925a|TeleVideo Model 925:\ + :al=\EE:am:bs:bt=\EI:bw:cd=\EY:ce=\ET:cl=^Z:cm=\E=%+ %+ :co#80:dc=\EW:\ + :dl=\ER:do=^V:ei=:ic=\EQ:if=/usr/share/tabset/std:im=:kb=^H:kd=^V:\ + :kh=^^:kl=^H:kn#12:kr=^L:ku=^K:li#24:nd=^L:pt:se=\EG0:sg=#1:so=\EG4:\ + :ue=\EG0:ug#1:up=^K:us=\EG8:is=\El\ + :vb=\Eb\200\200\200\200\200\200\200\200\200\200\200\200\200\200\Ed:\ + :ve=\E.4:vs=\E.2: +# The following tvi descriptions from B:pjphar and virus!mike +# is for all 950's. It sets the following attributes: +# full duplex (\EDF) write protect off (\E() +# conversation mode (\EC) graphics mode off (\E%) +# white on black (\Ed) auto page flip off (\Ew) +# turn off status line (\Eg) clear status line (\Ef\r) +# normal video (\E0) monitor mode off (\EX or \Eu) +# edit mode (\Er) load blank char to space (\Ee\040) +# line edit mode (\EO) enable buffer control (^O) +# protect mode off (\E\047) duplex edit keys (\El) +# program unshifted send key to send line all (\E016) +# program shifted send key to send line unprotected (\E004) +# set the following to nulls: +# field delimiter (\Ex0\200\200) +# line delimiter (\Ex1\200\200) +# start-protected field delimiter (\Ex2\200\200) +# end-protected field delimiter (\Ex3\200\200) +# set end of text delimiter to carriage return/null (\Ex4\r\200) +# CHANGED 4-29-87 to set tabs and keep status line --John Kunze (jak@opal) +va|tvi950|950|televideo950:\ + :ct=\E3:st=\E1:do=^J:\ + :is=\EDF\EC\Ed\EG0\Er\EO\E\047\E(\E%\Ew\EX\Ee ^O\ + \El\E016\E004\Ex0\200\200\Ex1\200\200\Ex2\200\200\ + \Ex3\200\200\Ex4\r\200\Ef\r:if=/usr/share/tabset/stdcrt:\ + :al=\EE:am:le=^H:bs:bt=\EI:cd=\Ey:ce=\Et:cl=\E*:cm=\E=%+ %+ :\ + :co#80:dc=\EW:dl=\ER:do=^V:ei=\Er:ho=^^:im=\Eq:k0=^A0\r:\ + :k1=^A@\r:k2=^AA\r:k3=^AB\r:k4=^AC\r:k5=^AD\r:k6=^AE\r:\ + :k7=^AF\r:k8=^AG\r:k9=^AH\r:kb=^H:kd=^V:kh=^^:kl=^H:\ + :ko=ic\054dc\054al\054dl\054cl\054bt\054ce\054cd:kr=^L:\ + :ku=^K:li#24:ma=^Vj^Kk^Hh^Ll^^H:mi:ms:nd=^L:pt:se=\EG0:\ + :sg#1:so=\EG4:sr=\Ej:ue=\EG0:ug#1:up=^K:us=\EG8:\ + :vb=\Eb\200\200\200\200\200\200\200\200\200\200\200\200\200\200\200\Ed:\ + :xn:hs:ts=\Eg\Ef:fs=\r:ds=\Eg\Ef\r: +# +# is for 950 with two pages adds the following: +# set 48 line page (\E\\2) +# place cursor at page 0, line 24, column 1 (\E-07 ) +# set local (no send) edit keys (\Ek) +# +# two page 950 adds the following: +# when entering ex, set 24 line page (\E\\1) +# when exiting ex, reset 48 line page (\E\\2) +# place cursor at 0,24,1 (\E-07 ) +# set duplex (send) edit keys (\El) when entering vi +# set local (no send) edit keys (\Ek) when exiting vi +# +vb|tvi950-2p|950-2p|televideo950 w/2 pages:\ + :is=\EDF\EC\Ed\EG0\Eg\Er\EO\E\047\E(\E%\Ew\EX\Ee ^O\ + \Ek\E016\E004\Ex0\200\200\Ex1\200\200\Ex2\200\200\ + \Ex3\200\200\Ex4\r\200\E\\2\E-07 \ + :te=\E\\2\E-07 :ti=\E\\1\E-07 :ks=\El:ke=\Ek:tc=tvi950: +# +# is for 950 with four pages adds the following: +# set 96 line page (\E\\3) +# place cursor at page 0, line 24, column 1 (\E-07 ) +# +# four page 950 adds the following: +# when entering ex, set 24 line page (\E\\1) +# when exiting ex, reset 96 line page (\E\\3) +# place cursor at 0,24,1 (\E-07 ) +# +vc|tvi950-4p|950-4p|televideo950 w/4 pages:\ + :is=\EDF\EC\Ed\EG0\Eg\Er\EO\E\047\E(\E%\Ew\EX\Ee ^O\ + \Ek\E016\E004\Ex0\200\200\Ex1\200\200\Ex2\200\200\ + \Ex3\200\200\Ex4\r\200\E\\3\E-07 \ + :te=\E\\3\E-07 :ti=\E\\1\E-07 :ks=\El:ke=\Ek:tc=tvi950: +# +# is for reverse video 950 changes the following: +# set reverse video (\Ed) +# +# set vb accordingly (\Ed ...nulls... \Eb) +# +vd|tvi950-rv|950-rv|televideo950 rev video:\ + :is=\EDF\EC\Eb\EG0\Eg\Er\EO\E\047\E(\E%\Ew\EX\Ee ^O\ + \El\E016\E004\Ex0\200\200\Ex1\200\200\Ex2\200\200\ + \Ex3\200\200\Ex4\r\200:\ + :vb=\Ed\200\200\200\200\200\200\200\200\200\200\200\200\200\200\200\Eb:\ + :tc=tvi950: +# +# uses the appropriate entries from 950-2p and 950-rv +# +ve|tvi950-rv-2p|950-rv-2p|televideo950 rev video w/2 pages:\ + :is=\EDF\EC\Eb\EG0\Eg\Er\EO\E\047\E(\E%\Ew\EX\Ee ^O\ + \Ek\E016\E004\Ex0\200\200\Ex1\200\200\Ex2\200\200\ + \Ex3\200\200\Ex4\r\200\E\\2\E-07 :\ + :vb=\Ed\200\200\200\200\200\200\200\200\200\200\200\200\200\200\200\Eb:\ + :te=\E\\2\E-07 :ti=\E\\1\E-07 :ks=\El:ke=\Ek:tc=tvi950: +# +# uses the appropriate entries from 950-4p and 950-rv +# +vf|tvi950-rv-4p|950-rv-4p|televideo950 rev video w/4 pages:\ + :is=\EDF\EC\Eb\EG0\Er\EO\E\047\E(\E%\Ew\EX\Ee ^O\ + \Ek\E016\E004\Ex0\200\200\Ex1\200\200\Ex2\200\200\ + \Ex3\200\200\Ex4\r\200\E\\3\E-07 :\ + :vb=\Ed\200\200\200\200\200\200\200\200\200\200\200\200\200\200\200\Eb:\ + :te=\E\\3\E-07 :ti=\E\\1\E-07 :ks=\El:ke=\Ek:tc=tvi950: +vg|tvi924|924|televideo model 924:\ + :am:bs:xn:co#80:li#24:cm=\E=%+ %+ :cl=\E*0:cd=\Ey:ce=\Et:is=\Ek0\E"^O:\ + :al=\EE:dl=\ER:im=:ei=:ic=\EQ:dc=\EW:if=/usr/share/tabset/stdcrt:ho=^^:\ + :nd=^L:bt=\EI:pt:so=\EG4:se=\EG0:us=\EG8:ue=\EG0:up=^K:do=^V:kb=^H:\ + :ku=^K:kd=^V:kl=^H:kr=^L:kh=^^:ma=^Vj^Kk^Ll^^H^R^L:k1=^A@\r:k2=^AA\r:\ + :k3=^AB\r:k4=^AC\r:k5=^AD\r:k6=^AE\r:k7=^AF\r:k8=^AG\r:k9=^AH\r:\ + :k0=^AI\r:ko=ic,dc,al,dl,cl,ce,cd,bt:sr=\Ej:\ + :hs:fs=^Y\Es1:ts=\Ef:ds=\Es0\Ef^Y: +vo|tvi924vb|924vb|televideo model 924 visual bells:\ + :vb=\Eb\200\200\200\200\200\200\200\200\200\200\200\200\200\200\200\Ed:\ + :tc=tvi924: +# tvipt termcap from armsis@amber (Gene Rochlin), 9/19/84. Works with vi and +# rogue. NOTE: Esc v sets autowrap on, Esc u sets 80 char/line (rather than +# 40), Esc K chooses the normal character set. Not sure padding is needed, but +# adapted from the tvi920c termcap. so and us are klutzy, but at least use no +# screen space. +vp|tvipt|televideopt:if=/usr/share/tabset/stdcrt:\ + :is=\Ev\Eu\EK:al=5*\EE:am:bs:bt=\EI:ce=\ET:cm=\E=%+ %+ :cl=^Z:co#80:\ + :dl=5*\ER:kb=^H:ku=^K:kd=^J:kl=^H:kr=^L:ho=^^:li#24:nd=^L:se=\EF:\ + :so=\EG1@A\EH:ue=\EF:us=\EG1B@\EH:up=^K:ma=^Kk^Ll^R^L: +# Vanilla tvi910 -- W. Gish (cswarren@violet) 10/29/86 +vm|tvi910|910|televideo model 910:if=/usr/share/tabset/stdcrt:\ + :bs:bt=\EI:cd=\EY:ce=\ET:cm=\E=%+ %+ :cl=^Z:co#80:\ + :kb=^H:ku=^K:kd=^J:kl=^H:kr=^L:k1=^A@\r:k2=^AA\r:k3=^AB\r:k4=^AC\r:\ + :k5=^AD\r:k6=^AE\r:k7=^AF\r:k8=^AG\r:k9=^AH\r:k0=^AI\r:\ + :li#24:nd=^L:pt:se=\EG0:so=\EG4:up=^K:us=\EG8:ue=\EG0:\ + :ho=\E=\001\001:ma=^Kk^Ll^R^L:sg#1: +# from Alan R. Rogers (rogers%albany@csnet-relay) +vh|tvi910+|910+|televideo 910+:\ + :al=5*\EE:am:bs:bt=\EI:cd=\EY:ce=\ET:cl=^Z:cm=\E=%+\040%+\040:\ + :co#80:dc=\EW:dl=\ER:do=^J:ei=:ho=^^:ic=\EQ:\ + :if=/usr/share/tabset/stdcrt:im=:k0=^A@\r:k1=^AA\r:k2=^AB\r:k3=^AC\r:\ + :k4=^AD\r:k5=^AE\r:k6=^AF\r:k7=^AG\r:k8=^AH\r:k9=^AI\r:kb=^H:\ + :kd=^J:kh=^^:kl=^H:kr=^L:ku=^K:li#24:ll=\E=7\040:ma=^K^P^L\040:\ + :nd=^L:pt:se=\EG0:sg#1:so=\EG4:ue=\EG0:up=^K:us=\EG8:xn: +# From fair@ucbarpa Sun Oct 27 07:21:05 1985 +v6|ims950-b|bare ims950 no is:\ + :is@:tc=ims950: +v7|ims950-ns|ims950 w/no standout:\ + :so@:se@:us@:ue@:tc=ims950: +va|ims950|ims televideo 950 emulation:\ + :k0@:k1@:k2@:k3@:k4@:k5@:k6@:k7@:k8@:k9@:kb@:kd@:kh@:kl@:ko@:kr@:ku@:\ + :vb@:xn@:tc=tvi950: +vd|ims950-rv|ims tvi950 rev video:\ + :k0@:k1@:k2@:k3@:k4@:k5@:k6@:k7@:k8@:k9@:kb@:kd@:kh@:kl@:ko@:kr@:ku@:\ + :vb@:xn@:tc=tvi950-rv: +vx|ims-ansi|ultima2|ultimaII|IMS Ultima II:\ + :pt:am:bs:co#80:li#24:\ + :is=\E[0m\E[>14l\E[?1;?5;20l\E>\E[1m^M:if=/usr/share/tabset/vt100:\ + :cl=\E[;H\E[2J:cd=\E[0J:ce=\E[0K:cm=\E[%i%2;%2H:up=\EM:do=\ED:\ + :ku=\E[A:kd=\E[B:kr=\E[C:kl=\E[D:kh=\E[H:\ + :so=\E[7m:se=\E[0m\E[1m:us=\E[4m:ue=\E[0m\E[1m:sr=\EM: +# # -------------------------------- +# +# y: TELERAY +# +# Note two things called "teleray". Reorder should move the common one +# to the front if you have either. A dumb teleray with the cursor stuck +# on the bottom and no obvious model number is probably a 3700. +y1|t3700|teleray|dumb teleray 3700:\ + :do=^J:le=^H:bs:cl=^L:co#80:li#24: +y3|t3800|teleray 3800 series:\ + :do=^J:le=^H:bs:cd=\EJ:ce=\EK:cl=^L:cm=\EY%+ %+ :co#80: \ + :do=\n:ho=\EH:li#24:ll=\EY7 :nd=\EC:pt:up=^K: +y6|t1061|teleray 1061:\ + :if=/usr/share/tabset/teleray:\ + :ct=\EG:st=\EF:do=^J:\ + :al=2*\EL:am:le=^H:bs:cd=1\EJ:ce=\EK:cl=1^L:cm=\EY%+ %+ :co#80:\ + :dc=\EQ:dl=2*\EM:ei=:ho=\EH:ic=\EP:im=:ip=0.4*:\ + :k1=^Z1:k2=^Z2:k3=^Z3:k4=^Z4:k5=^Z5:k6=^Z6:k7=^Z7:k8=^Z8:\ + :li#24:nd=\EC:pt:se=\ER@:so= \ERD:\ + :is=\Ee\EU01^Z1\EV\EU02^Z2\EV\EU03^Z3\EV\EU04^Z4\EV\EU05^Z5\EV\EU06^Z6\EV\EU07^Z7\EV\EU08^Z8\EV\Ef:\ + :up=\EA:us=\ERH:ue=\ER@:xs:xt:sg#2:ug#1: +# "Teleray Arpa Special", offically designated as +# "Teleray Arpa network model 10" with "Special feature 720". +# This is the new (1981) fast microcode updating the older "arpa" proms +# (which gave meta-key and pgmmable-fxn keys). 720 is much much faster, +# converts the keypad to programmable function keys, and has other goodies. +# Standout mode is still broken (magic cookie, etc) so is suppressed as no +# programs handle such lossage properly. +# Note: this is NOT the old termcap's "t1061f with fast proms." +# From Univ of Utah, J.Lepreau Tue Feb 1 06:39:37 1983 +# lepreau@utah-cs, harpo!utah-cs!lepreau +# +y7|t10|teleray 10 special:\ + :so@:se@:us@:ue@:\ + :al=\EL:bs:cd=\EJ:ce=\EK:cl=30\Ej:cm=\EY%+ %+ :co#80:\ + :dc=\EQ:dl=\EM:ei=:ho=\EH:ic=\EP:im=:km:li#24:nd=\EC:pc=\200:pt:\ + :se=\ER@:so=\ERD:sf=\Eq:sg#2:sr=\Ep:up=\EA:ug#1:ue=\ER@:us=\ERH:\ + :xs:xt: +yf|t1061f|teleray 1061 with fast PROMs:\ + :al=\EL:ip@:dl=\EM:tc=t1061: +# Wyse 50 entry by Toni Guttman extended by Jeff Anton +ye|w50|wyse50|Wyse 50:\ + :al=\EE:am:bs:bt=\EI:cd=\EY:ce=\ET:cl=^Z:cm=\E=%+ %+ :co#80:\ + :dc=\EW:dl=\ER:do=^J:ei=\Er:im=\Eq:is=\E`\072\200\EC\EDF\E0\E'\E(\EA21:\ + :kd=^J:kl=^H:kr=^L:ku=^K:li#24:nd=^L:up=^K:us=\EG8:ue=\EG0:\ + :so=\EG4:se=\EG0:sg#1:sr=\Ej:ho=^^:ug#1: +# it is not known if the status line works with sysline +yh|w50-s|wyse50-s|Wyse 50 for sysline:\ + :hs:ts=\Ef:fs=\r:ds=\Ef\r:es:tc=w50: +yg|w50-w|w50-132|wyse50-132|Wyse 50-132:\ + :cm=\Ea%i%dR%dC:co#132:is=\E`;\200\EC\EDF\E0\E'\E(\EA21:tc=w50: +w6|w60|wyse60|Wyse 60 in native mode:\ + :ae=\EcD:al=\EE:am:as=\EcE:bs:bt=\EI:bw:cd=\Ey:ce=\Et:\ + :cl=^Z:cm=\E=%+\040%+\040:co#80:ct=\E0:dc=\EW:dl=\ER:do=^J:\ + :ei=\Er:im=\Eq:is=:kb=^?:kd=^N:ke=\E~2:kl=^B:kr=^F:ks=\E~3:ku=^P:\ + :le=^H:li#43:ll=^^^K:mb=\EG2:me=\EG0:mh=\EGp:mi:mr=\EG4:ms:\ + :nd=^L:pt:se=\EG0:sf=\n:so=\EG4:sr=\Ej:ue=\EG0:up=^K:us=\EG8: +# from John Gillmore hoptoad!gnu@lll-crg.arpa +wv|wyse-vp|wyse|Wyse 50 in ADDS Viewpoint emulation mode with "enhance" on:\ + :am:do=^J:if=/usr/share/tabset/wyse-adds:\ + :le=^H:bs:li#24:co#80:cm=\EY%+ %+ :cd=\Ek:ce=\EK:nd=^F:\ + :up=^Z:cl=^L:ho=^A:ll=^A^Z:kl=^U:kr=^F:kd=^J:ku=^Z:kh=^A:\ + :pt:so=^N:se=^O:us=^N:ue=^O:dl=\El:al=\EM:im=\Eq:ei=\Er:dc=\EW:\ + :is=\E`\072\E`9^O\Er:rs=\E`\072\E`9^O\Er: +wk|wyse-vp-nk|Wyse 50 in ADDS Viewpoint enhanced mode with cursor keys gone:\ + :kl@:kr@:kd@:ku@:kh@:tc=wyse-vp: +vw|wyse925|Wyse-50 emulating tvi925:\ + :xn@:tc=tvi925: +# wyse 75 series from JLarson.pa@xerox.arpa +wx|wyse75|wy75|wyse 75 terminal :\ + :co#80:li#24:cl=50\E[H\E[2J:bs:cm=5\E[%i%d;%dH:nd=\E[C:up=\E[A:\ + :al=3\E[L:dl=3\E[M:ku=\E[A:kd=\E[B:kr=\E[C:kl=\E[D:do=\E[B:\ + :ic=\E[@:ei=:im=:pt:bw:dc=\E[P:ce=3\E[K:ho=10\E[H:pt:\ + :mi:nd=\E[C:bt=\E[Z:us=\E[8p:ue=\E[p:so=\E[5m:se=\E[m:\ + :md=\E[1p:mr=\E[16p:mb=\E[2p:mk=\E[4p:me=\E[0p:hs:ll=\E[24;1H:\ + :cd=50\E[J:cs=9\E[%i%d;%dr:ae=\E(B:as=\E(0:kh=\E[H:kb=^H:\ + :k0=\EOP:k1=\EOQ:k2=\EOR:k3=\EOS:k4=\E[M:\ + :k5=\E[17~:k6=\E[31~:k7=\E[18~:k8=\E[19~:k9=\E[20~:kn#10:\ + :l0=PF1:l1=PF2:l2=PF3:l3=PF4:l4=F5:\ + :l5=F6:l6=F7:l7=F8:l8=F9:l9=F10:\ + :is=\E[1;24r\E[24;1H\E[35;?25h\E[4;?10;3;1l\E[m\E(B\E>:\ + :ds=\E7\E[>,//\E8:ts=\E7\E[>,^A:fs=^A\E8: +wx|wyse75-80|wy75-80|wyse 75 terminal with 80-column initialization:\ + :is=\E[?3l:tc=wy75: +wl|wyse75-132|wy75-132|wyse 75 terminal with 132 columns :\ + :is=\E[?3h:co#132:tc=wy75: +# +# Wyse WY75 utilizing keypad +# +w5|wy75ap|wyse75ap|wy-75ap|wyse-75ap|Wyse WY-75 Applications and Cursor keypad:\ + :is=\E[1;24r\E[?10;3l\E[?1;25h\E[4l\E[m\E(B\E=:\ + :kd=\EOB:ke=10\E[?1l\E>:kh=\EOH:kl=\EOD:kr=\EOC:\ + :ks=10\E[?1h\E=:ku=\EOA:\ + :tc=wyse75: +# from ucbvax!ucsfmis!shewmake +Wc|wy85|wyse85|wyse-85:\ + :do=^J:co#80:li#24:cl=\E[;H\E[2J:\ + :le=^H:bs:cm=\E[%i%d;%dH:nd=\E[C:up=\E[A:\ + :ce=\E[0K:cd=\E[0J:so=\E[7m:se=\E[27m:\ + :us=\E[4m:ue=\E[24m:\ + :is=\E[1;24r\E[24;1H\E[0m:\ + :ks=\E[?1h\E=:ke=\E[?1l\E>:\ + :ku=\EOA:kd=\EOB:kr=\EOC:kl=\EOD:kb=^H:\ + :ho=\E[H:k1=\EOP:k2=\EOQ:k3=\EOR:k4=\EOS:kh=\E[H"ta=^I:pt:sr=\EM:\ + :sc=\E7:rc=\E8:cs=\E[%i%d;%dr:as=^N:ae=^O:bt=\E[Z:\ + :dc=\E[P:dl=\E[M:al=\E[L:ei=\E[4l:im=\E[4h:\ + :vb=\E[?5h\E[?5l:\ + :hs:es:ts=\E7\E[?25l\E[40h\E[25;%dH\E[2K:fs=\E[1;24r\E8\E[?25h: +# # -------------------------------- +# +# z: Miscellaneous +# +z0|wind:\ + :bs:cm=\Ep%r%.%.:cl=\En\120\030\Eo:co#80:\ + :ho=\Ep\200\200:li#24:nd=^L:up=^K:nl=\035:\ + :kl=\E3:kr=\E4:ku=\E1:kd=\E2:k1=\E5:k2=\E6:k3=\E7:k4=\E8:\ + :so=\Em\014:se=\Em\003: +z1|wind16:\ + :bs:cm=\Ep%r%.%.:cl=\En\120\020\Eo:co#80:\ + :ho=\Ep\200\200:li#16:nd=^L:up=^K:nl=\035:\ + :so=\Em\014:se=\Em\003: +z2|wind40:\ + :bs:cm=\Ep%r%.%.:cl=\En\120\050\Eo:co#80:\ + :ho=\Ep\200\200:li#40:nd=^L:up=^K:nl=\035:\ + :so=\Em\014:se=\Em\003: +z3|wind50:\ + :bs:cm=\Ep%r%.%.:cl=\En\128\062\Eo:co#88:\ + :ho=\Ep\200\200:li#50:nd=^L:up=^K:nl=\035:\ + :kl=\E3:kr=\E4:ku=\E1:kd=\E2:k1=\E5:k2=\E6:k3=\E7:k4=\E8:\ + :so=\Em\014:se=\Em\003: +z4|cad68-3|cgc3|cad68 basic monitor transparent mode size 3 chars:\ + :am:bs:cl=^Z:co#73:ho=\036:li#36:nd=^L:up=^K: +z5|cad68-2|cgc2|cad68 basic monitor transparent mode size 2 chars:\ + :am:bs:cl=^Z:co#85:ho=\036:li#39:nd=^L:up=^K:\ + :kl=\E3:kr=\E4:ku=\E1:kd=\E2:k1=\E5:k2=\E6:k3=\E7:k4=\E8:\ + :so=\Em\014:se=\Em\003: +z6|v50|visual 50:\ + :am:bs:al=\EL:dl=\EM:\ + :cd=\Ek:ce=\EK:cl=^Z:cm=\E=%+\040%+\040:co#80:do=^J:ho=\EH:\ + :kb=^H:kd=\EB:kh=\EH:kl=\ED:kr=\EC:ku=\EA:li#24:ms:nd=^L:pt:\ + :so=\EU:se=\ET:up=^K: +z7|trs2|trsII|trs80II|Radio Shack Model II using P&T CP/M:\ + :nl=^_:al=^D:am:bs:cd=^B:ce=^A:cl=^L:cm=\EY%+ %+ :co#80:\ + :dl=^K:do=^_:ho=^F:li#24:nd=^]:ms:pt:se=^O:so=^N:up:=^^:\ + :kb=^H:kd=^_:kl=^\:kr=^]:ku=^^: +z9|ps300|Picture System 300:us@:ue@:so@:se@:xt:pt@:tc=vt100: +za|masscomp2:co#64:li#21:tc=masscomp: +zb|masscomp1:co#104:li#36:tc=masscomp: +zc|masscomp:\ + :al=\E[L:bs:cd=\E[J:ce=\E[K:co#80:dc=\E[P:dl=\E[M:do=\E[B:\ + :ei=\E[4l:im=\E[4h:is=\EGc\EGb\EGw:li#24:mi:MT:nd=\E[C:pt:se=\E[0m:\ + :sg#0:so=\E[7m:cm=\E[%i%d;%dH:ue=\EGau:us=\EGu:up=\E[A:\ + :ku=\EOA:kd=\EOB:kr=\EOC:kl=\EOD:kb=^h:cl=\E[2J: +# Kimtron TC entries include (undocumented) codes for: enter dim mode (mh), +# enter bold mode (md), enter reverse mode (mr), turn off all attributes (me) +# Kimtron ABM 85 added by Dual Systems +zd|abm85|Kimtron ABM 85:\ + :is=\EC\EX\Eg\En\E%\Er\E(\Ek\Em\Eq:if=/usr/share/tabset/stdcrt:\ + :li#24:co#80:am:bs:bw:ms:pt:\ + :cl=\E*:cd=\Ey:dl=\ER:al=\EE:ce=\Et:dc=\EW:im=\EQ:ei=\Er:\ + :cm=\E=%+ %+ :do=^J:nd=^L:up=^K:bt=\EI:\ + :kh=^^:kb=^H:kd=^J:ku=^K:kd=^J:kl=^H:kr=^L:\ + :so=\Ej:se=\Ek:sg#1:us=\El:ue=\Em:ug#1: +# Kimtron ABM 85H added by Dual Systems. +# Some notes about the 85h entries: +# 1) there are several firmware revs of 85H in the world. Use o85h for +# firmware revs prior to SP51 +# 2) Make sure to use 85h entry if the terminal is in 85H mode and the +# 85e entry if it is in 920 emulation mode. They are incompatible in +# some places and NOT software settable i.e., `is' can't fix change it) +# 3) In 85h mode, the arrow keys and special functions transmit when +# the terminal is in dup-edit, and work only locally in local-edit. +# Vi won't swallow `del char' for instance, but `vs' turns on +# dup-edit anyway so that the arrow keys will work right. If the +# arrow keys don't work the way you like, change `vs', `ve', and `is'. +# 920E mode does not have software commands to toggle between dup +# and local edit, so you get whatever was set last on the terminal. +# 4) vb attribute is nice, but seems too slow to work correctly (\Eb\Ed) +# 5) Make sure `hidden' attributes are selected. If `embedded' attributes +# are selected, the entries :sg@: and :ug@: should be removed. +# 6) auto new-line should be on (selectable from setup mode only) +# +# From fair@ucbarpa Sun Oct 27 07:21:05 1985 +ze|85h|85H|abm85h|Kimtron ABM 85H, 85H mode:\ + :is=\EC\EN\EX^T^N\EA\Ea\E%\E9\Ee\Er\En\E"\E}\E'\E(\Ef^M\EG0\Ed\E.4\El:\ + :im=\EZ:kd=^V:so=\EG4:se=\EG0:us=\EG8:ue=\EG0:vb@:vs=\E.2:ve=\E.4:\ + :mh=\E):mr=\EG4:me=\E(\EG0:sg@:ug@:ds=\Ee:fs=^M:hs:ts=\Eg\Ef:tc=abm85: +zf|85e|85E|abm85e|Kimtron ABM 85H, 920E mode:\ + :is=\EC\EX\EA\E%\E9\Ee\Er\En\E"\E}\E'\E(\Ef^M\Ek\Eq\Em:\ + :mh=\E):mr=\Ej:me=\E(\Ek:im=\EZ:sg@:ug@:vb@:tc=abm85: +zg|o85h|oabm85h|Kimtron ABM 85H, old firmware rev.:\ + :is=\E}\EC\EX\Ee\En\E%\Er\E(\Ek\Em\Eq\Ed\ET\EC\E9\EF:\ + :im=\EZ:sg@:ug@:vb=\200\200\200^G\200\200\200:\ + :mh=\E):mr=\Ej:me=\E(\Ek:tc=abm85: +#from malman@bbn-vax.arpa +zE|kt7|kimtron model kt-7:\ + :am:bs:co#80:li#24:cm=\E=%+ %+ :cl=^Z:cd=\EY:ce=\ET:is=\El\E":\ + :al=\EE:dl=\ER:im=:ei=:ic=\EQ:dc=\EW:if=/usr/share/tabset/stdcrt:\ + :ho=^^:nd=^L:bt=\EI:pt:so=\EG4:se=\EG0:sg#0:us=\EG8:ue=\EG0:ug#0:\ + :up=^K:do=^V:kb=^H:ku=^K:kd=^V:kl=^H:kr=^L:kh=^^:ma=^V^J^L :\ + :k1=^A@\r:k2=^AA\r:k3=^AB\r:k4=^AC\r:k5=^AD\r:k6=^AE\r:k7=^AF\r:\ + :k8=^AG\r:k9=^AH\r:k0=^AI\r:ko=ic,dc,al,dl,cl,ce,cd,bt:\ + :ts=\Ef:fs=\Eg: +zh|appleII|apple ii plus:vs=\024\103\066:ve=\024\103\062:\ + :am:co#80:ce=\035:li#24:cl=\014:bs:nd=\034:up=\037:ho=\E\031:pt:\ + :cd=\013:so=\017:se=\016:cm=\036%r%+ %+ :is=\024T1\016:do=^J:kd=^J:\ + :vb=\024G1\024T1:kr=: +# Gary Ford 21NOV83 +# New version from ee178aci%sdcc7@SDCSVAX.ARPA Fri Oct 11 21:27:00 1985 +zi|apple-80|apple II with smarterm 80 col:\ + :am:bs:bt=^R:bw:cd=10*^K:ce=10^]:cl=10*^L:cm=^^%r%+ %+ :\ + :co#80:cr=10*^M:do=^J:ho=^Y:le=^H:li#24:nd=^\\:up=^_: +# +zj|lisa|apple lisa xenix console display (white on black):\ + :al=\E[L:am:bs:cd=\E[J:ce=\E[K:cl=^L:cm=\E[%i%d;%dH:co#88:\ + :dc=\E[P:dl=\E[M:dn=\E[B:ei=:ho=\E[H:ic=\E[@:im=:li#32:\ + :nd=\E[C:ms:pt:so=\E[m:se=\E[7m:us=\E[4m:ue=\E[7m:up=\E[A:\ + :kb=^h:ku=\E[A:kd=\E[B:kl=\E[D:kr=\E[C:eo:\ + :is=\E[7m^L:GS=\E[11m:GE=\E[10m:GV=\140:GH=a:G1=c:\ + :G2=f:G3=e:G4=d:GU=u:GD=s:GC=b:GL=v:GR=t: +# The following is a version of the ibm-pc entry distributed with PC/IX, +# (Interactive Systems' System 3 for the Big Blue), modified by Richard +# McIntosh at UCB/CSM. The :pt: and :uc: have been removed from the original, +# (the former is untrue, and the latter failed under UCB/man); standout and +# underline modes have been added. Note: this entry describes the "native" +# capabilities of the PC monochrome display, without ANY emulation; most +# communications packages (but NOT PC/IX connect) do some kind of emulation. +pc|ibmpc|ibm pc PC/IX:\ + :li#24:co#80:am:bs:bw:eo:\ + :cd=\E[J:ce=\E[K:cl=\Ec:cm=\E[%i%2;%2H:do=\E[B:ho=\E[;H:\ + :nd=\E[C:up=\E[A:so=\E[7m:se=\E[0m:us=\E[4m:ue=\E[0m: +pc3-bold|ibmpc3|IBM PC BSD/386 Console with bold instead of underline:\ + :us=\E[=15F:ue=\E[=R:tc=pc3:\ +pc3|ibmpc3|IBM PC BSD/386 Console:\ + :li#25:al=\E[L:dl=\E[M:md=\E[=15F:me=\E[=R:mh=\E[=8F:\ + :kh=\E[H:kH=\E[F:kP=\E[I:kN=\E[G:kI=\E[L:\ + :ku=\E[A:kd=\E[B:kl=\E[D:kr=\E[C:tc=pc: +zk|ibmx|ibmpcx|IBM PC xenix console display:\ + :al=\E[L:am:bs:cd=\E[J:ce=\E[K:cl=^L:cm=\E[%d;%dH:co#80:\ + :dc=\E[P:dl=\E[M:dn=\E[B:ei=:ho=\E[H:ic=\E[@:im=:li#25:\ + :nd=\E[C:ms:se=\E[0m:so=\E[7m:us=\E[4m:\ + :ue=\E[m:up=\E[A:MR=\E[0m:\ + :kb=^h:kh=\E[Y:ku=\E[A:kd=\E[B:kl=\E[D:kr=\E[C:eo:\ + :GS=\E[11m:GE=\E[10m:\ + :GC=b:GL=v:GR=t:RT=^J:\ + :GH=\E[196g:GV=\E[179g:\ + :GU=\E[193g:GD=\E[194g:\ + :G1=\E[191g:G2=\E[218g:G3=\E[192g:G4=\E[217g:\ + :CW=\E[E:NU=\E[F:RF=\E[G:RC=\E[H:\ + :WL=\E[K:WR=\E[L:CL=\E[M:CR=\E[N:\ + :HM=\E[Y:EN=\E[d:PU=\E[Z:PD=\E[e: +zl|ibmc|ibmcpc|IBM PC xenix color console display:\ + :tc=ibm: +zl|ibmcx|ibmcpcx|IBM PC xenix color console display:\ + :tc=ibmx: +zm|kaypro|kaypro2|kaypro II:\ + :am:bs:cm=\E=%+ %+ :cl=1^Z:co#80:ho=^^:li#24:ma=^K^P:nd=^L:up=^K:\ + :kr= :kl=^H:ku= :kd=^J: +# From Suk Lee ..!{decvax,linus,allegra,ihnp4}!utcsrgv!spoo +zn|trs100|Radio Shack Model 100:\ + :am:bs:le=^H:li#8:co#40:ku=^^:kd=^_:kl=^]:kr=^\:up=\EA:\ + :nd=\EC:ho=\EH:ce=\EK:cd=\EJ:cl=\EE:xt:cm=\EY%+ %+ :\ + :so=\Ep:se=\Eq:al=\EL:dl=\EM: +zt|mac|macintosh|Macintosh with MacTerminal:\ + :al=20\E[L:dl=20\E[M:ip=7:dc=7\E[P:ic=9\E[@:xn:dN#30:tc=vt100: +zs|zen50|z50:zephyr:\ + :cm=\E=%+ %+ :cd=\EY:co#80:li#24:\ + :am:al=\EE:ce=\ET:dc=\EW:dl=\ER:ic=\EQ:im=:ei=:\ + :cl=\E+:bs:ma=^Hh^Ll^Jj^Kk:sg#1:se=\EGO:so=\EG4:\ + :kl=^H:kr=^L:ku=^K:kd=^J:kh=\036:up=^K:\ + :BS=^U:CL=^V:CR=^B:RK=^L:UK=^K:LK=^H:DK=^J:HM=\036: +zu|go140|graphon go-140:\ + :co#80:li#24:cl=10\E[;H\E[2J:bs:cm=\E[%i%2;%2H:nd=\E[C:up=\E[A:\ + :ce=\E[K:cd=10\E[J:so=\E[7m:se=\E[m:us=\E[4m:ue=\E[m:\ + :is=\E<\E=\E[?3l\E[?7l\E(B\E[J\E7\E[;r\E8\E[m\E[q:\ + :dl=\E[M:al=\E[L:dc=\E[P:im=\E[4h:ei=\E[4l:\ + :ks=\E[?1h\E=:ke=\E[?1l\E>:\ + :if=/usr/share/tabset/vt100:ku=\EOA:kd=\EOB:kr=\EOC:kl=\EOD:\ + :kh=\E[H:k1=\EOP:k2=\EOQ:k3=\EOR:k4=\EOS:pt:sr=\EM: +zv|go140w|graphon go-140 in 132 column mode:\ + :co#132:is=\E<\E=\E[?3h\E[?7h\E(B\E[J\E7\E[;r\E8\E[m\E[q:\ + :tc=go140: +zw|sanyo55|sanyo|sanyo mbc-55x pc compatible:\ + :co#80:li#25:am:cl=\E[H\E[J:bs:cm=\E[%i%d;%dH:nd=\E[C:up=\E[A:\ + :ce=\E[K:cd=\E[J:so=\E[7m:se=\E[m:us=\E[4m:ue=\E[m: +#From: Simson L. Garfinkel +zC|ST|atari st:\ + :bs:cd=\EJ:ce=\EK:cl=\EH\EJ:cm=\EY%+ %+ :co#80:li#25:nd=\EC:\ + :pt:sr=\EI:up=\EA:ku=\EA:kd=\EB:kr=\EC:kl=\ED:\ + :do=\EB:\ + :so=\Ep:se=\Eq:dl=\EM:al=\EL:am: +# UniTerm terminal program for the Atari ST: 49-line VT220 emulation mode +# From Paul M. Aoki, aoki@ucbvax.Berkeley.EDU +zD|uniterm|uniterm49|UniTerm VT200 emulator, 49 lines:\ + :li#49:is=\E>\E[?3l\E[?4l\E[?5l\E[?7h\E[?8h\E[1;49r\E[49;1H:\ + :tc=vt200: +# YTERM standard version 1.0. (gts 9-25-84) +# Straight old ascii keyboard except function keys are Yale (e.g.,ASCII.KBD). +# Only 80 tab columns (else yterm 1.1 bug). No :xn: in 1.0. +# Cannot use termcap :sr=\EM: because vi will not work, too bad. +# vi string is given so that yterm is reset each vi startup. +Y0|yterm10|yterm 1.0 UCB ascii.kbd:\ + :am:bs:cd=^K:ce=^]:cl=^L:cm=^^%r%+ %+ :co#80:EP:ho=^Y:li#24:nd=^\:pt:\ + :rc=\E8:sc=\E7:so=\E[7m:se=\E[m:up=^_:us=\E[4m:ue=\E[m:\ + :is=^O\E[7i\E[m\E[?7h\E[?3g\r\EHY0 for \EHYTERM 1.\EH0 with A\EHSCII.KBD\EH 9-13-84\EH \EH \EH \EH \EH\n:\ + :ku=^K:kd=^J:kl=^H:kr=^L:kh=^^:ma=h\012j k lH:\ + :k0=\E0:k1=\E1:k2=\E2:k3=\E3:k4=\E4:k5=\E5:k6=\E6:k7=\E7:k8=\E8:k9=\E9:\ + :vs=^O\E[7i\E[m\E[?7h\E[?3g\r\EHY0 \EH \EH \EH \EH \EH \EH \EH \EH \EH\r: +# YTERM varient version 1.1. (gts 9-13-84) Version 1.1 has :xn:. +Y1|yterm11|yterm 1.1 UCB ascii.kbd:\ + :xn:is=^O\E[7i\E[m\E[?7h\E[?3g\r\EHY1 for \EHYTERM 1.\EH1 with A\EHSCII.KBD\EH 9-13-84\EH \EH \EH \EH \EH\n:\ + :tc=yterm10 +# YTERM 1.0 varient no autowrap or tabs +# X does not remember autowrap or tabs when T is deleted and restarted. +Y2|yterm10nat|yterm 1.0 UCB ascii.kbd no autowrap or tabs:\ + :am@:pt@:vs=^O\E[7i\E[m\E[?7l\E[?3g\rY2\r:\ + :is=^O\E[7i\E[m\E[?7l\E[?3g\rY2 for YTERM 1.0 with ASCII.KBD 9-20-84 no autowrap or tabs\n:\ + :tc=yterm10 +# KERMIT standard all versions. (gts 9-25-84) +# Straight ascii keyboard. :sr=\EI: not avail. many versions + bug prone in vi. +K0|kermit|standard kermit:\ + :bs:cd=\EJ:ce=\EK:cl=\EE:cm=\EY%+ %+ :co#80:ho=\EH:li#24:nd=\EC:up=\EA:\ + :ku=^K:kd=^J:kl=^H:kr=^L:kh=^^:ma=^Hh\012j^Kk^Ll^^H:\ + :is=K0 Standard Kermit 9-25-84\n: +K1|kermitam|standard kermit plus am:\ + :am:is=K1 Standard Kermit plus Automatic Margins\n:tc=kermit: +# IBMPC Kermit 1.2. (gts 8-30-84) +# Bugs :cd:ce: do not work except at beginning of line! :cl: does not work, +# but fake with :cl=\EH\EJ (since :cd=\EJ: works at beginning of line). +K2|pckermit|pckermit12|UCB IBMPC Kermit 1.2:\ + :am:li#25:cd@:ce@:cl=\EH\EJ:\ + :is=K2 UCB IBMPC Kermit 1.2 8-30-84\n:tc=kermit: +# IBMPC Kermit 1.20 (gts 12-19-84) +# Cannot use line 25, now acts funny like ansi special scrolling region. +# Initialization must escape from that region by cursor position to line 24. +# Cannot use character insert because 1.20 goes crazy if insert at col 80. +# Does not use am: because autowrap mode lost when kermit dropped and restarted. +K3|pckermit120|UCB IBMPC Kermit 1.20:\ + :al=\EL:am@:dc=\EN:dl=\EM:do=\EB:ei@:im@:li#24:pt:se=\Eq:so=\Ep:\ + :is=\EO\Eq\EJ\EY7 K3 UCB IBMPC Kermit 1.20 12-19-84\n:\ + :vs=\EO\Eq\EEK3:tc=kermit: +# MS-DOS Kermit 2.27 for the IBMPC (UCB gts 3-17-85) +# Straight ascii keyboard. :sr=\EI: not avail. many versions + bug prone in vi. +# Cannot use line 25, now acts funny like ansi special scrolling region. +# Initialization must escape from that region by cursor position to line 24. +# Does not use am: because autowrap mode lost when kermit dropped and restarted. +# Reverse video for standout like H19. +K4|msk227|mskermit227|MS-DOS Kermit 2.27 for the IBMPC:\ + :al=\EL:am@:bs:cd=\EJ:ce=\EK:cl=\EE:cm=\EY%+ %+ :co#80:\ + :dc=\EN:dl=\EM:do=\EB:ei=\EO:im=\E@:\ + :ho=\EH:li#24:nd=\EC:up=\EA:pt:rc=\Ek:sc=\Ej:se=\Eq:so=\Ep:\ + :ku=^K:kd=^J:kl=^H:kr=^L:kh=^^:ma=^Hh\012j^Kk^Ll^^H:\ + :is=\EO\Eq\EG\Ew\EJ\EY7 K4 MS Kermit 2.27 for the IBMPC 3-17-85\n:\ + :vs=\EO\Eq\EG\EwK4: +# MS-DOS Kermit 2.27 with automatic margins (UCB gts 3-17-85) +K5|msk227am|mskermit227am|UCB MS-DOS Kermit 2.27 with automatic margins:\ + :am:\ + :is=\EO\Eq\EG\Ev\EJ\EY7 K5 MS Kermit 2.27 +automatic margins 3-17-85\n:\ + :vs=\EO\Eq\EG\EvK5:tc=mskermit227: +# MS-DOS Kermit 2.27 UCB 227.14 for the IBM PC (UCB gts 3-17-85) +# Automatic margins now default. Use ansi set graphic rendition for standout, +# underline and ul codes (md,me,mr). Define function keys. +K6|msk22714|mskermit22714|UCB MS-DOS Kermit 2.27 UCB 227.14 IBM PC:\ + :am:kn#10:\ + :k0=\E0:k1=\E1:k2=\E2:k3=\E3:k4=\E4:k5=\E5:k6=\E6:k7=\E7:k8=\E8:k9=\E9:\ + :md=\E[1m:me=\E[m:mr=\E[7m:se=\E[m:so=\E[1m:ue=\E[m:us=\E[4m:\ + :is=\EO\Eq\EG\Ev\EJ\EY7 K6 MS Kermit 2.27 UCB 227.14 IBM PC 3-17-85\n:\ + :vs=\EO\Eq\EG\EvK6:tc=mskermit227: +# From earle@smeagol.UUCP 29 Oct 85 05:40:18 GMT +# MS-Kermit with Heath-19 emulation mode enabled +Kh|h19k|h19kermit|heathkit emulation provided by Kermit (no auto margin):\ + :am@:ta@:pt@:xt:da:db:tc=h19-u: +# rough draft of Amiga termcap by Mike Meyer +AA|amiga|Amiga ANSI:\ + :co#80:li#25:am:do=\E[B:ce=\E[K:cd=\E[J:\ + :cl=\E[H\E[J:ku=\E[A:kd=\E[B:kl=\E[C:kr=\E[D:kb=^H:\ + :al=\E[L:dl=\E[M:le=^H:cm=\E[%i%d;%dH:nd=\E[C:up=\E[A:\ + :ce=\E[K:ho=\E[H:dc=\E[P:ic=\E[@:\ + :so=\E[2m:se=\E[m:us=\E[4m:ue=\E[m:mr=\E[7m:mb=\E[7;2m:me=\E[m: +# The pcplot IBM-PC terminal emulation program is really messed up. It is +# supposed to emulate a vt-100, but emulates the wraparound bug incorrectly, +# doesn't support scrolling regions, ignores add line commands, and ignores +# delete line commands. Consequently, the resulting behavior looks like a +# crude adm3a-type terminal. +# Steve Jacobson 8/85 +pp|pcplot:\ + :cs@:sc@:rc@:xn@:tc=vt100: +# From Joel Rubin, jmrubin@coral, a preliminary TERMCAP for VIDTEX, +# a terminal program sold by Compuserve. Line and column numbers are +# computer-dependent (I have a Commodore '64); you should use the meta-B +# option to shut off clean-breaking of lines. No key codes included +# since some of them are programmable and most are machine-specific. +# Works on vi if you don't use clean-breaking. Very similar to the IBM 3101 +# termcap. Escape-D used for backspace because control-H is destructive +# backspace. There seem to be a few weirdnesses (especially at the beginning +# of a wrapped line), and the cursor does not, unfortunately, flash. +zQ|vid|vidtex|Compuserve vidtex program:\ + :am:bc=\ED:cl=^L:li#25:co#40:nd=\EC:up=\EA:cd=\EJ:ce=\EK:\ + :ho=\EH:cm=\EY%+\40%+\40:pt: +# Fortune from c160-3bp@Coral (Robert Nathanson) via tut Wed Oct 5, 1983 +zK|fos|fortune|Fortune system:\ + :is=^_..:li#25:co#80:am:bs:bw:cl=20^L:cd=3*^\Y:\ + :ic=5^\Q:dc=5^\W:dl=15^\R:al=15^\E:cm=^\C%+ %+ :ta=^Z:ho=10^^:do=3^J:\ + :up=3^K:bs=^H:kb=^H:kd=^Ay\r:kh=^A?\r:kl=^Aw\r:kr=^Az\r:ku=^Ax\r:\ + :nl=5^J:so=^\H`:se=^\I`:sg=0:us=^\HP:ue=^\IP:ug=0:ce=^\Z:rv=\EH:re=\EI:\ + :rg=0:GS=\Eo:GE=^O:GG=0:GV=-:GH=&:GU=%:GD=#:G1=(:G2= :G3=":G4=*:CF=\E]:\ + :CO=\E\\:WL=^Aa\r:WR=^Ab\r:CL=^Ac\r:CR=^Ad\r:DL=^Ae\r:RF=^Af\r:\ + :RC=^Ag\r:CW=^Ah\r:NU=^Aj\r:EN=^Ak\r:HM=^Al:PL=^Am\r:PU=^An\r:PD=^Ao\r:\ + :PR=^Ap\r:HP=^A@\r:RT=^Aq\r:TB=\r:CN=\177:MP=\E+F: +# basis from Peter Harrison, Computer Graphics Lab, San Francisco +# ucbvax!ucsfmis!harrison ...uucp / ucbvax!ucsfmis!harrison@BERKELEY ...ARPA +ba|basis|BASIS108 computer with terminal translation table active:\ + :do=5000^J:nl=5000*^J:\ + :cd=\EY:ce=\ET:cl=300\E*:ma=^K^P^R^L^L :\ + :kb=^H:kl=^H:ku=^K:kr=^L:kd=^J:so=\E(:se=\E):tc=adm3a: +# From Peter Harrison, Computer Graphics Lab, San Francisco +# ucbvax!ucsfmis!harrison .....uucp +# ucbvax!ucsfmis!harrison@BERKELEY .......ARPA +# "These two work. If you don't have the inverse video chip for the +# Apple with videx then remove the so and se fields." +zO|DaleApple|Apple with videx videoterm 80 column board with inverse video:\ + :do=^J:am:le=^H:bs:cd=^K:ce=^]:cl=300^L:cm=^^%r%+ %+ :co#80:ho=^Y:\ + :kd=^J:kl=^H:kr=^U:kh=^Y:\ + :li#24:nd=^\:pt:so=^Z3:se=^Z2:up=^_:xn: +zJ|ibmaed|IBM Experimental display:\ + :al=\EN:am:bs:cd=\EJ:ce=\EI:cl=\EH\EK:cm=\EY%+\40%+\40:co#80:\ + :dc=\EQ:dl=\EO:do=\EB:ei=:ho=\EH:ic=\EP:im=:li#52:\ + :nd=\EC:ms:so=\E0:se=\E0:us=:ue=:up=\EA:\ + :kb=^h:ku=\EA:kd=\EB:kl=\ED:kr=\EC:eo:vb=\EG:pt: +# funny terminal that the TANDEM uses. +zA|653|t653x|Tandem 653x multipage terminal:\ + :li#24:co#80:ho=\EH:cm=\023%+ %+ :cl=\EI:cd=\EJ:ce=\EK:am:bs:\ + :if=/usr/share/tabset/tandem653:sb=\ES:sr=\ET:da:db:so=\E6$:se=\E6 :\ + :us=\E60:ue=\E6 :sg#1:ug#1:up=\EA:do=\012:le=\010:nd=\EC:\ + :hs:ts=\Eo:fs=\r:ds=\Eo\r:ws#64: +# From Paul Leondis, unllab@amber.berkeley.edu +zB|ifmr|Informer D304:\ + :am:bs:cd=\E/:ce=\EQ:cl=\EZ:cm=\EY%r%+ %+ :co#80:dc=\E\\:\ + :do=^J:im=:ei=:ic=\E[:li#24:nd=\EC:so=\EJ:se=\EK:up=\EA:\ + :sr=\En:ho=\EH: +# +# END OF TERMCAP +# ------------------------ diff --git a/src/libtermlib/tgoto.c b/src/libtermlib/tgoto.c new file mode 100644 index 0000000..f8ad1a4 --- /dev/null +++ b/src/libtermlib/tgoto.c @@ -0,0 +1,176 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +#include +#define CTRL(c) ('c' & 037) + +#define MAXRETURNSIZE 64 + +char *UP; +char *BC; + +/* + * Routine to perform cursor addressing. + * CM is a string containing printf type escapes to allow + * cursor addressing. We start out ready to print the destination + * line, and switch each time we print row or column. + * The following escapes are defined for substituting row/column: + * + * %d as in printf + * %2 like %2d + * %3 like %3d + * %. gives %c hacking special case characters + * %+x like %c but adding x first + * + * The codes below affect the state but don't use up a value. + * + * %>xy if value > x add y + * %r reverses row/column + * %i increments row/column (for one origin indexing) + * %% gives % + * %B BCD (2 decimal digits encoded in one byte) + * %D Delta Data (backwards bcd) + * + * all other characters are ``self-inserting''. + */ +char * +tgoto(CM, destcol, destline) + char *CM; + int destcol, destline; +{ + static char result[MAXRETURNSIZE]; + static char added[10]; + char *cp = CM; + register char *dp = result; + register int c; + int oncol = 0; + register int which = destline; + + if (cp == 0) { +toohard: + /* + * ``We don't do that under BOZO's big top'' + */ + return ("OOPS"); + } + added[0] = 0; + while ((c = *cp++)) { + if (c != '%') { + *dp++ = c; + continue; + } + switch (c = *cp++) { + +#ifdef CM_N + case 'n': + destcol ^= 0140; + destline ^= 0140; + goto setwhich; +#endif + + case 'd': + if (which < 10) + goto one; + if (which < 100) + goto two; + /* fall into... */ + + case '3': + *dp++ = (which / 100) | '0'; + which %= 100; + /* fall into... */ + + case '2': +two: + *dp++ = which / 10 | '0'; +one: + *dp++ = which % 10 | '0'; +swap: + oncol = 1 - oncol; +setwhich: + which = oncol ? destcol : destline; + continue; + +#ifdef CM_GT + case '>': + if (which > *cp++) + which += *cp++; + else + cp++; + continue; +#endif + + case '+': + which += *cp++; + /* fall into... */ + + case '.': + /* + * This code is worth scratching your head at for a + * while. The idea is that various weird things can + * happen to nulls, EOT's, tabs, and newlines by the + * tty driver, arpanet, and so on, so we don't send + * them if we can help it. + * + * Tab is taken out to get Ann Arbors to work, otherwise + * when they go to column 9 we increment which is wrong + * because bcd isn't continuous. We should take out + * the rest too, or run the thing through more than + * once until it doesn't make any of these, but that + * would make termlib (and hence pdp-11 ex) bigger, + * and also somewhat slower. This requires all + * programs which use termlib to stty tabs so they + * don't get expanded. They should do this anyway + * because some terminals use ^I for other things, + * like nondestructive space. + */ + if (which == 0 || which == CTRL(d) || /* which == '\t' || */ which == '\n') { + if (oncol || UP) /* Assumption: backspace works */ + /* + * Loop needed because newline happens + * to be the successor of tab. + */ + do { + strcat(added, oncol ? (BC ? BC : "\b") : UP); + which++; + } while (which == '\n'); + } + *dp++ = which; + goto swap; + + case 'r': + oncol = 1; + goto setwhich; + + case 'i': + destcol++; + destline++; + which++; + continue; + + case '%': + *dp++ = c; + continue; + +#ifdef CM_B + case 'B': + which = (which/10 << 4) + which%10; + continue; +#endif + +#ifdef CM_D + case 'D': + which = which - 2 * (which%16); + continue; +#endif + + default: + goto toohard; + } + } + strcpy(dp, added); + return (result); +} diff --git a/src/libtermlib/tputs.c b/src/libtermlib/tputs.c new file mode 100644 index 0000000..cdbddde --- /dev/null +++ b/src/libtermlib/tputs.c @@ -0,0 +1,92 @@ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +#include +#include + +/* + * The following array gives the number of tens of milliseconds per + * character for each speed as returned by gtty. Thus since 300 + * baud returns a 7, there are 33.3 milliseconds per char at 300 baud. + */ +static short tmspc10[] = { + 0, 2000, 1333, 909, 743, 666, 500, 333, 166, 83, 55, 41, 20, 10, 5 +}; + +short ospeed; +char PC; + +/* + * Put the character string cp out, with padding. + * The number of affected lines is affcnt, and the routine + * used to output one character is outc. + */ +void +tputs(cp, affcnt, outc) + register char *cp; + int affcnt; + int (*outc)(); +{ + register int i = 0; + register int mspc10; + + if (cp == 0) + return; + + /* + * Convert the number representing the delay. + */ + if (isdigit(*cp)) { + do + i = i * 10 + *cp++ - '0'; + while (isdigit(*cp)); + } + i *= 10; + if (*cp == '.') { + cp++; + if (isdigit(*cp)) + i += *cp - '0'; + /* + * Only one digit to the right of the decimal point. + */ + while (isdigit(*cp)) + cp++; + } + + /* + * If the delay is followed by a `*', then + * multiply by the affected lines count. + */ + if (*cp == '*') + cp++, i *= affcnt; + + /* + * The guts of the string. + */ + while (*cp) + (*outc)(*cp++); + + /* + * If no delay needed, or output speed is + * not comprehensible, then don't try to delay. + */ + if (i == 0) + return; + if (ospeed <= 0 || ospeed >= (sizeof tmspc10 / sizeof tmspc10[0])) + return; + + /* + * Round up by a half a character frame, + * and then do the delay. + * Too bad there are no user program accessible programmed delays. + * Transmitting pad characters slows many + * terminals down and also loads the system. + */ + mspc10 = tmspc10[ospeed]; + i += mspc10 / 2; + for (i /= mspc10; i > 0; i--) + (*outc)(PC); +} diff --git a/src/libutil/Makefile b/src/libutil/Makefile new file mode 100644 index 0000000..a2cc517 --- /dev/null +++ b/src/libutil/Makefile @@ -0,0 +1,47 @@ +# +# 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 redistribution 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. +# +TOPSRC = $(shell cd ../..; pwd) +include $(TOPSRC)/target.mk + +CFLAGS += ${DEFS} + +SRCS = login.c logout.c logwtmp.c +OBJS = login.o logout.o logwtmp.o + +all: ../libutil.a + +../libutil.a: ${OBJS} + $(AR) cru $@ ${OBJS} + $(RANLIB) $@ + +clean: + rm -f *.a *.o *~ profiled/*.o tags + +cleandir: clean + rm -f .depend + +depend: + mkdep ${CFLAGS} ${SRCS} + +install: all +# cp ../libutil.a ${DESTDIR}/lib/ +# $(RANLIB) -t ${DESTDIR}/lib/libutil.a +# cp libutil_p.a ${DESTDIR}/lib/ +# $(RANLIB) -t ${DESTDIR}/lib/libutil_p.a + +tags: + ctags ${SRCS} diff --git a/src/libutil/login.c b/src/libutil/login.c new file mode 100644 index 0000000..c48e6bc --- /dev/null +++ b/src/libutil/login.c @@ -0,0 +1,41 @@ +/* + * Copyright (c) 1988 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ +#include +#include +#include +#include +#include + +void +login(ut) + struct utmp *ut; +{ + register int fd; + int tty; + off_t lseek(); + + tty = ttyslot(); + if (tty > 0 && (fd = open(_PATH_UTMP, O_WRONLY, 0)) >= 0) { + (void)lseek(fd, (long)(tty * sizeof(struct utmp)), L_SET); + (void)write(fd, (char *)ut, sizeof(struct utmp)); + (void)close(fd); + } + if ((fd = open(_PATH_WTMP, O_WRONLY|O_APPEND, 0)) >= 0) { + (void)write(fd, (char *)ut, sizeof(struct utmp)); + (void)close(fd); + } +} diff --git a/src/libutil/logout.c b/src/libutil/logout.c new file mode 100644 index 0000000..85361be --- /dev/null +++ b/src/libutil/logout.c @@ -0,0 +1,50 @@ +/* + * Copyright (c) 1988 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ +#include +#include +#include +#include +#include +#include + +typedef struct utmp UTMP; + +logout(line) + register char *line; +{ + register int fd; + UTMP ut; + int rval; + off_t lseek(); + time_t time(); + + if ((fd = open(_PATH_UTMP, O_RDWR)) < 0) + return(0); + rval = 0; + while (read(fd, (char *)&ut, sizeof(UTMP)) == sizeof(UTMP)) { + if (!ut.ut_name[0] || strncmp(ut.ut_line, line, UT_LINESIZE)) + continue; + bzero(ut.ut_name, UT_NAMESIZE); + bzero(ut.ut_host, UT_HOSTSIZE); + (void)time(&ut.ut_time); + (void)lseek(fd, -(long)sizeof(UTMP), L_INCR); + (void)write(fd, (char *)&ut, sizeof(UTMP)); + rval = 1; + } + (void)close(fd); + return(rval); +} diff --git a/src/libutil/logwtmp.c b/src/libutil/logwtmp.c new file mode 100644 index 0000000..dd979d3 --- /dev/null +++ b/src/libutil/logwtmp.c @@ -0,0 +1,45 @@ +/* + * Copyright (c) 1988 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ +#include +#include +#include +#include +#include +#include + +logwtmp(line, name, host) + char *line, *name, *host; +{ + struct utmp ut; + struct stat buf; + int fd; + time_t time(); + char *strncpy(); + + if ((fd = open(_PATH_WTMP, O_WRONLY|O_APPEND, 0)) < 0) + return; + if (!fstat(fd, &buf)) { + (void)strncpy(ut.ut_line, line, sizeof(ut.ut_line)); + (void)strncpy(ut.ut_name, name, sizeof(ut.ut_name)); + (void)strncpy(ut.ut_host, host, sizeof(ut.ut_host)); + (void)time(&ut.ut_time); + if (write(fd, (char *)&ut, sizeof(struct utmp)) != + sizeof(struct utmp)) + (void)ftruncate(fd, buf.st_size); + } + (void)close(fd); +} diff --git a/src/libvmf/Makefile b/src/libvmf/Makefile new file mode 100644 index 0000000..19aabd2 --- /dev/null +++ b/src/libvmf/Makefile @@ -0,0 +1,44 @@ +# Copyright (c) 1980 Regents of the University of California. +# All rights reserved. The Berkeley software License Agreement +# specifies the terms and conditions for redistribution. +# +# vmf package +# +TOPSRC = $(shell cd ../..; pwd) +include $(TOPSRC)/target.mk + +CFILES = vmf.c +OBJS = vmf.o +POBJS = ../vmf.o +MAN = vmf.0 +MANSRC = vmf.3 + +CTAGS = ctags +#DEFS = -DNOSCCS +#CFLAGS = -O $(DEFS) +TAGSFILE = tags + +all: ../libvmf.a $(MAN) + +../libvmf.a: ${OBJS} + @echo building normal ../libvmf.a + @$(AR) ru ../libvmf.a ${OBJS} + $(RANLIB) ../libvmf.a + +../libvmf_p.a: ${OBJS} + @echo building profiled ../libvmf.a + @cd profiled; $(AR) ru ../../libvmf_p.a ${POBJS} + $(RANLIB) ../libvmf_p.a + +$(MAN): $(MANSRC) + ${MANROFF} $< > $@ + +install: all + cp $(MAN) $(DESTDIR)/share/man/cat3/ +# cp ../libvmf.a ${DESTDIR}/lib/libvmf.a +# $(RANLIB) ${DESTDIR}/lib/libvmf.a +# cp ../libvmf_p.a ${DESTDIR}/lib/libvmf_p.a +# $(RANLIB) ${DESTDIR}/lib/libvmf_p.a + +clean: + rm -f *.o profiled/*.o a.out core test errs ../libvmf*.a vmf.0 diff --git a/src/libvmf/vmf.3 b/src/libvmf/vmf.3 new file mode 100644 index 0000000..1acab7f --- /dev/null +++ b/src/libvmf/vmf.3 @@ -0,0 +1,142 @@ +.\" No copyright (1993) - Steven M. Schultz (sms@wlv.iipo.gtegsc.com) +.\" @(#)vmf.3 3.0 (2.11BSD) 9/24/93 +.\" +.TH VMF 3 "September 24, 1993" +.UC 6 +.SH NAME +vminit, vmopen, vmclose, vmmapseg, vmmodify, vmlock, vmunlock, vmclrseg, vmflush, \- disk based virtual memory routines +.SH SYNOPSIS +.nf +.PP +.ft B +#include +.PP +.ft B +struct vspace { + int v_fd; /* file for swapping */ + off_t v_foffset; /* offset for computing file addresses */ + int v_maxsegno; /* number of segments in this space */ + }; +.PP +.ft B +struct vseg { /* structure of a segment in memory */ + struct dlink s_link; /* for linking into lru list */ + int s_segno; /* segment number */ + struct vspace *s_vspace; /* which virtual space */ + int s_lock_count; + int s_flags; + union + { + int _winfo[WORDSPERSEG]; /* the actual segment */ + char _cinfo[BYTESPERSEG]; + } v_un; + }; +#define s_winfo v_un._winfo +#define s_cinfo v_un._cinfo +.PP +.ft B +int vminit(nseg); + int nseg; +.PP +.ft B +int vmopen(space, filename); + struct vspace *space; + char *filename; +.PP +.ft B +struct vseg *vmmapseg(space, segno); + struct vspace *space; + int segno; +.PP +.ft B +void vmlock(seg); + struct vseg *seg; +.PP +.ft B +void vmunlock(seg); + struct vseg *seg; +.PP +.ft B +void vmclrseg(seg); + struct vseg *seg; +.PP +.ft B +void vmmodify(seg); +.PP +.ft B +void vmflush(); +.PP +.ft B +void vmclose(space); + struct vspace *space; +.fi +.bp +.SH DESCRIPTION +This library provides a standard set +of routines for managing large virtual memory spaces. It supports +creation of multiple concurrent virtual spaces, mapping of virtual +pages into real memory, a lock/unlock mechanism, and a capability to +clear specified virtual pages. +.PP +.IR vminit\ - +This routine initializes the virtual memory system by setting up the +pool of in-memory segment buffers. The argument to this function is +the number of memory segments to allocate (typically 4 to 8 but can be +higher as long as memory can be malloc'd). +It must be called before any +other "libvmf" routine is called. +.PP +.IR vmopen\ - +For each virtual space that a program uses, the program must +allocate an instance of the space structure ('struct vspace'). +This routine is used to initialize +a virtual space structure using the specified address of a +space structure and the name of the file that will serve as +swap file for the space. If the second argument is \fBNULL\fP +an invisible temporary file is used rather than a named (permanent) +file. +.PP +.IR vmclose\ - +This routine is used to close the UNIX file descriptor associated +with the swap file for a virtual space. Any modified in-memory segments +belonging to the specified address space are flushed to the paging file. +.PP +.IR vmmapseg\ - +This routine is the primary interface to the virtual memory mechanism. +It is executed with a specified virtual space address and a segment +number (between 0 and 511), and returns a pointer to an in-memory +page containing the specified segment. +.PP +.IR vmmodify\ - +Whenever a program modifies the data of a segment, it is the program's +responsibility to inform the virtual memory system of the modification. +This function is also available as a macro +(\fBVMMODIFY\fP) for use in-line. +.PP +.IR vmlock\ - +This routine increments the lock count of the specified segment buffer. +A buffer with a nonzero lock count is +.I locked +and cannot be swapped out. +.PP +.IR vmunlock\ - +This routine decrements the lock count of the specified buffer. It is +a serious error to decrement the count below zero (lock underflow). +.PP +.IR vmclrseg\ - +This routine clears the user data area (page) of the specified segment buffer. +.IR vmflush\ - +This routine simply swaps out all segments that are marked as +modified. +.SH BUGS +Not as transparent (or as fast) as a larger hardware address space. +.PP +There is no automatic segment crossing capability, the application must +check if a +.I virtual address +crosses page/segment boundaries and perform a +.I vmmapseg +call. +.SH SEE ALSO +There is a nroff document (using the \-ms macros) in the \fIlibvmf\fP source +directory which goes into more details about the \fBvm\fP functions. diff --git a/src/libvmf/vmf.c b/src/libvmf/vmf.c new file mode 100644 index 0000000..55bbaea --- /dev/null +++ b/src/libvmf/vmf.c @@ -0,0 +1,375 @@ +/* Program Name: vmf.c + * Author: S.M. Schultz + * + * ----------- Modification History ------------ + * Version Date Reason For Modification + * 1.0 1JAN80 1. Initial release. + * 2.0 31Mar83 2. Cleanup. + * 2.1 19Oct87 3. Experiment increasing number of segments. + * 2.2 03Dec90 4. Merged error.c into this because it had + * been reduced to two write() statements. + * 3.0 08Sep93 5. Polish it up for use in 'ld.c' (2.11BSD). + * Release into the Public Domain. + * -------------------------------------------------- +*/ + +#include +#include +#include +#include +#include +#include +#include + +/* + * Choose ONE and only one of the following swap policies + */ +/* #define LRU /* Least Recently Used */ +/* #define PERC 3 /* Percolation */ +#define LRS /* Least Recently Swapped */ + +#ifndef DEBUG +#define debugseg(s,m) /* do nothing */ +#else +static void debugseg(); +#endif + +/* + * This is vfm.c, the file of virtual memory management primitives. + * Call vminit first to get the in memory segments set up. + * Then call vmopen for each virtual space to be used. + * Normal transactions against segments are handled via vmmapseg. + * At wrapup time, call vmflush if any modified segments are + * assigned to permanent files. + */ + +#define NOSEGNO (-1) /* can never match a segment number */ + + static struct dlink seghead[1]; + long nswaps, nmapsegs; /* statistics */ + extern int read(), write(), errno; + static int swap(); + static void promote(), vmerror(); + +/* + * vminit --- initialize virtual memory system with 'n' in-memory segments + */ + +int +vminit(n) + int n; + { + register struct vseg *s; + static struct vseg *segs; + + segs = (struct vseg *)calloc(n, sizeof (struct vseg)); + if (!segs) + { + errno = ENOMEM; + return(-1); + } + seghead[0].fwd = seghead[0].back = seghead; /* selfpoint */ + + for (s = segs; s < &segs[n] ; s++) + { + s->s_link.fwd = seghead; + s->s_link.back = seghead[0].back; + s->s_link.back->fwd = s->s_link.fwd->back = (struct dlink *)s; + s->s_segno = NOSEGNO; + s->s_vspace = NULL; + s->s_lock_count = 0; /* vmunlocked */ + s->s_flags = 0; /* not DIRTY */ + } + return(0); + } + +/* + * vmmapseg --- convert segment number to real memory address + */ + +struct vseg * +vmmapseg(vspace, segno) + struct vspace *vspace; + u_short segno; + { + register struct vseg *s; + + nmapsegs++; + + if (segno >= vspace->v_maxsegno || segno < 0) + { +#ifdef DEBUG + fprintf(stderr,"vmmapseg vspace0%o segno%d\n", vspace, segno); +#endif + vmerror("vmmapseg: bad segno"); + } + + /* look for segment in memory */ + for (s = (struct vseg *)seghead[0].fwd; + s->s_segno != segno || s->s_vspace != vspace; + s = (struct vseg *)s->s_link.fwd) + { + if (s == (struct vseg *)seghead) + { /* not in memory */ + int status; + + for (s = (struct vseg *)s->s_link.back; s->s_lock_count != 0; + s = (struct vseg *)s->s_link.back) + { + if (s == (struct vseg *)seghead) + vmerror("Too many locked segs!"); + debugseg(s, "back skip"); + } + debugseg(s, "dump on"); + if (s->s_flags & S_DIRTY) + if (swap(s, write) != 0) + { + fprintf(stderr, + "write swap, v=%d fd=%d\n", + s->s_vspace,s->s_vspace->v_fd); + exit(-2); + } + s->s_vspace = vspace; + s->s_segno = segno; + s->s_flags &= ~S_DIRTY; + status = swap(s, read); + if (status == -2) + { + fprintf(stderr, "can't read swap file"); + exit(-2); + } + else if (status == -1) + (void)vmclrseg(s); +#ifdef LRS /* Least Recently Swapped */ + promote(s); +#endif + break; + } + debugseg(s, "forward skip"); + } +#ifdef PERC + { /* percolate just-referenced segment up list */ + register struct dlink *neighbor, *target; + int count; + + s->fwd->back = s->back; /* delete */ + s->back->fwd = s->fwd; + + count = PERC; /* upward mobility */ + for (target = s; target != seghead && count-- > 0; ) + target = target->back; + neighbor = target->fwd; + s->back = target; /* reinsert */ + s->fwd = neighbor; + target->fwd = neighbor->back = s; + } +#endif +#ifdef LRU /* Least Recently Used */ + promote(s); +#endif + debugseg(s, "vmmapseg returns"); + return(s); + } + +/* + * swap --- swap a segment in or out + * (called only from this file) + */ + +static int +swap(seg, iofunc) /* used only from this file */ + register struct vseg *seg; + int (*iofunc)(); + { + off_t file_address; + register struct vspace *v; + + v = seg->s_vspace; + nswaps++; + file_address = seg->s_segno; + file_address *= (BYTESPERSEG); + file_address += v->v_foffset; +#ifdef SWAPTRACE + printf("fd%d blk%d\tswap %s\n", v->v_fd, file_address, + iofunc == read ? "in" : "out"); +#endif + if (lseek(v->v_fd, file_address, L_SET) == -1L) + return(-2); + + switch ((*iofunc)(v->v_fd, seg->s_cinfo, BYTESPERSEG)) + { + case BYTESPERSEG: + return(0); + case 0: + return(-1); + default: + return(-2); + } + } + +void +vmclrseg(seg) + register struct vseg *seg; + { + + (void)bzero(seg->s_cinfo, BYTESPERSEG); + vmmodify(seg); + } + +/* + * vmlock --- vmlock a segment into real memory + */ + +void +vmlock(seg) + register struct vseg *seg; + { + + seg->s_lock_count++; + if (seg->s_lock_count < 0) + vmerror("vmlock: overflow"); + } + +/* + * vmunlock --- unlock a segment + */ + +void +vmunlock(seg) + register struct vseg *seg; + { + + --seg->s_lock_count; + if (seg->s_lock_count < 0) + vmerror("vmlock: underflow"); + } + +/* + * vmmodify --- declare a segment to have been modified + */ + +void +vmmodify(seg) +register struct vseg *seg; + { + + VMMODIFY(seg); + debugseg(seg, "vmmodify"); + } + +/* + * vmflush --- flush out virtual space buffers + */ + +void +vmflush() + { + register struct vseg *s; + + for (s = (struct vseg *)seghead[0].fwd; s != (struct vseg *)seghead; + s = (struct vseg *)s->s_link.fwd) + if (s->s_flags & S_DIRTY) + swap(s, write); + } + +/* + * debugseg --- output debugging information about a seg in mem + */ +#ifdef DEBUG +static void +debugseg(s, msg) + char *msg; + register struct vseg *s; + { + fprintf(stderr, "seg%o vspace%o segno%d flags%o vmlock%d %s\r\n", + s, s->s_vspace, s->s_segno, s->s_flags, s->s_lock_count, msg); + } +#endif + +/* + * vmopen --- open a virtual space associated with a file + */ + +int +vmopen(vs, filename) + register struct vspace *vs; + char *filename; + { + register int fd; + char junk[32]; + + if (!filename) + { + strcpy(junk, "/tmp/vmXXXXXX"); + fd = mkstemp(junk); + unlink(junk); + } + else + fd = open(filename, O_RDWR|O_CREAT, 0664); + + if (fd != -1) + { + vs->v_fd = fd; + vs->v_foffset = 0; + vs->v_maxsegno = MAXSEGNO; + } + return(fd); + } + +/* + * vmclose --- closes a virtual space associated with a file + * invalidates all segments associated with that file + */ + +void +vmclose(vs) + register struct vspace *vs; + { + register struct vseg *s; + + vmflush(); + /* invalidate all segments associated with that file */ + for (s = (struct vseg *)seghead[0].fwd; s != (struct vseg *)seghead; + s = (struct vseg *)s->s_link.fwd) + { + if (s->s_vspace == vs) + { + s->s_segno = NOSEGNO; + s->s_vspace = NULL; + s->s_lock_count = 0; /* vmunlocked */ + s->s_flags &= ~S_DIRTY; + } + } + close(vs->v_fd); + } + +/* + * promote --- put a segment at the top of the list + */ + +static void +promote(s) + register struct vseg *s; + { + + s->s_link.fwd->back = s->s_link.back; /* delete */ + s->s_link.back->fwd = s->s_link.fwd; + + s->s_link.fwd = seghead[0].fwd; /* insert at top of totem pole */ + s->s_link.back = seghead; + seghead[0].fwd = s->s_link.fwd->back = (struct dlink *)s; + } + +/* + * vmerror --- print error message and commit suicide + * Message should always make clear where called from. + * Example: vmerror("In floogle: can't happen!"); + */ + +static void +vmerror(msg) + char *msg; + { + fprintf(stderr, "%s\n", msg); + abort(); /* terminate process with core dump */ + } diff --git a/src/libvmf/vmlib.ms b/src/libvmf/vmlib.ms new file mode 100644 index 0000000..be7a68d --- /dev/null +++ b/src/libvmf/vmlib.ms @@ -0,0 +1,406 @@ +.NH 1 +VMF -- Virtual Memory Facility +.NH 2 +Introduction +.PP +Since 2.11BSD is not a virtual memory operating system, a user level +"virtual memory" system can be of great utility to programs with +large address space requirements. This library provides a standard set +of routines for managing large virtual memory spaces. It supports +creation of multiple concurrent virtual spaces, mapping of virtual +pages into real memory, a lock/unlock mechanism, and a capability to +clear specified virtual pages. +.NH 3 +Concepts +.PP +The virtual memory scheme supports any number (subject to open file +limitations) of virtual +.I spaces, +each of which is made up of up to 512 +.I segments +(pages), each of which is 512 words (16 bit shorts) long. +The 512 ints (1024 chars) of a segment can be used for any purpose. +.PP +Each space may be temporary or permanent, in the sense that it is or +is not forgotten when the program ends. Between program invocations, +each permanent space resides in a named file. The most common (by +far) type is temporary using a file which is unlinked immediately +after opening the virtual address space. +.PP +At any time during the lifetime of a process that uses the virtual +memory facility, some number of segments will be in real memory, but +typically most will be "swapped out" to a file. +When the calling program knows +the real memory address of a segment, the segment may be viewed +and accessed as an array of 512 integers or as an array of 1024 +characters. +.NH 3 +Data Structures +.PP +Two structures are associated with the virtual memory scheme: the +space structure and the segment buffer structure. +.IP Space\ Structure 4 +.sp +One instance of the space structure must be allocated by the user for +each space to be used. Spaces are identified by the address of their +space structures. Included in the structure is the UNIX file descriptor +of the "swap" file to be used for the space, the offset (in bytes) +into the file at which the room allocated for the virtual space begins +(currently this is always zero and is reserved for future use), +and the number of segments in the space (currently always 512). The +user must never be concerned with any element of the space structure. +.IP Segment\ Buffer\ Structure 4 +.sp +The virtual memory system includes a pool of buffers for holding +segments while they reside in real memory. +.sp +The segment buffer structure (see 'struct seg' definition below) +includes: a double link, the segment number (in range [0, 511]), +the address of the virtual space structure instance for the virtual +space of which the segment is a member, a lock count, a "modified" +flag, and an array of 512 shorts (1024 bytes) for the segment itself. This +array represents the virtual page which is accessed directly by +the user. +.NH 2 +Defined Constants and Global Variables +.PP +The following defined symbolic constants are specified as either +calling parameters or returned values of the routines in the "dtlib" +facility. +.IP MAXSEGNO 18 +Specifies the maximum number of segments (pages) in a virtual space. +.IP WORDSPERSEG 18 +Specifies the number of words in a segment. +.IP BYTESPERSEG 18 +Specifies the number of bytes in a segment. This is always a power of 2. +.IP LOG2BPS 18 +The base 2 logarithm of BYTESPERSEG. +.PP +There are several global variables defined by the "vmlib" facility that an +applications programmer may examine. +.IP nswaps 18 +This is a 32 bit value which gives the number of pages swapped to or from +the paging file. +.IP nmapsegs 18 +This 32 bit value holds the number of calls made to map a segment into +memory via \fIvmmapseg\fP. +.PP +The following +defined "C" Language structures are specified as calling parameters +and/or returned values of the routines in the "vmlib" facility. +.PP +.nf +struct vspace { + int v_fd; /* file for swapping */ + off_t v_foffset; /* offset for computing file addresses */ + int v_maxsegno; /* number of segments in this space */ + }; + +struct dlink { /* general double link structure */ + struct dlink *fwd; /* forward link */ + struct dlink *back; /* back link */ + }; + +struct vseg { /* structure of a segment in memory */ + struct dlink s_link; /* for linking into lru list */ + int s_segno; /* segment number */ + struct vspace *s_vspace; /* which virtual space */ + int s_lock_count; + int s_flags; + union + { + int _winfo[WORDSPERSEG]; /* the actual segment */ + char _cinfo[BYTESPERSEG]; + } v_un; + }; + +#define s_winfo v_un._winfo +#define s_cinfo v_un._cinfo +.fi +.NH 2 +Routine Synopsis +.PP +Below are listed the names of each function +in the "vmlib" facility along with a brief synopsis +of what each routine does. +.IP vminit 14 +This routine initializes the virtual memory system by setting up the +pool of in-memory segment buffers. The argument to this function is +the number (typically 4 to 8 but can be higher as long as memory +can be malloc'd). +It must be called before any +other "vmlib" facility routine is called. +.IP vmopen 14 +For each virtual space that a program uses, the program must +allocate an instance of the space structure (see definition +of 'struct vspace' above). This routine is used to initialize +a virtual space structure using the specified address of a +space structure and the name of the file that will serve as +swap file for the space. If the second argument is \fBNULL\fP +an invisible temporary file is used rather than a named (permanent) +file. +.IP vmclose 14 +This routine is used to close the UNIX file descriptor associated +with the swap file for a virtual space. Any modified in-memory segments +belonging to the specified address space are flushed to the paging file. +.IP vmmapseg 14 +This routine is the primary interface to the virtual memory mechanism. +It is executed with a specified virtual space address and a segment +number ( in range [0, 511]), and returns a pointer to an in-memory +page containing the specified segment. +.IP vmmodify 14 +Whenever a program modifies the data of a segment, it is the program's +responsibility to inform the virtual memory system of the modification. +This routine flags the specified segment as modified and should be +executed before any future execution of 'vmmapseg' that could overlay +the modified buffer. This function is also available as a macro +(\fBVMMODIFY\fP) for use in-line. The macro form is actually preferred +since only a single bit is being set in a word. +.IP vmlock 14 +This routine increments the lock count of the specified segment buffer. +A buffer with a nonzero lock count is +.I locked +and cannot be overlayed. The utility of this feature to the user is +that a locked segment buffer will stay at the same real memory address +until unlocked, hence real memory pointers into or to it can remain +valid. Overuse of this feature will result in not being able to page +any new segments into memory from the paging file. +.IP vmunlock 14 +This routine decrements the lock count of the specified buffer. It is +a serious error to decrement the count below zero (lock underflow). +.IP vmclrseg 14 +This routine clears the user data area (page) of the specified segment buffer. +.IP vmflush 14 +This routine simply swaps out all segments that are marked as +"modified". It may be called at any time and is always called when +\fIvmclose\fP is called. +.bp +.NH 2 +Detailed Description of Virtual Memory Functions +.NH 3 +vminit -- Initialize Virtual Memory Interface +.NH 4 +.PP +The "vminit" routine initializes the virtual memory system by setting up the +pool of in-memory segment buffers. It must be called before any +other "vmlib" facility routine is called. +.NH 4 +CALLING SEQUENCE +.PP +.in +8 +.nf +status = vminit(nseg) + +int nseg; +int status; +.fi +.in -8 +.IP status +The return value will be \-1 and \fIerrno\fP will be set to ENOMEM +if memory for +the specified number of segments can not be allocated. +.IP nseg +This is the number of in-memory segments to allocate. These are shared +between all virtual spaces opened. Each segment is 1kb plus overhead, +so the number of segments should be chosen with care (if all data could +be held in memory we wouldn't need a virtual memory system after all). +Typical number of segments is between 4 and 8 although some applications +such as \fBld\fP(1) use 12 or more. +.NH 3 +vmopen -- Open a Virtual Space +.NH 4 +.PP +For each virtual space that a program uses, the program must +allocate an instance of the space structure (see definition +of 'struct vspace' above). The "vmopen" routine is used to initialize +a virtual space structure using the specified address of a +space structure and the name of the file that will serve as +swap file for the space. If the filename is NULL then an invisible +temporary file created in /tmp will be used and the address space +will be vanish when the program exits or calls \fIvmclose\fP. +.NH 4 +CALLING SEQUENCE +.PP +.in +8 +.nf +status = vmopen(vsptr,filename) + +struct vspace *vsptr; +char *filename; +int status; +.fi +.in -8 +.IP status +Indicates success if 0, an error if \-1. An error is caused by failure +to create (or open for update) the specified file. The global \fBerrno\fP +will be set if \-1 is returned by \fIvmopen\fP. +.NH 3 +vmclose -- Close a Virtual Space +.NH 4 +.PP +Close the UNIX file descriptor associated with the swap +file for a virtual space. Modified segments belonging to the specified +virtual space are flushed. +.NH 4 +CALLING SEQUENCE +.PP +.in +8 +.nf +void vmclose(vsptr) + +struct vspace *vsptr; +.fi +.in -8 +.IP vsptr +The address of the virtual space structure to be closed. No status is +returned. +.NH 3 +vmmapseg -- Map a Virtual Segment into Real Memory +.NH 4 +.PP +The "vmmapseg" routine is the primary interface to the virtual memory mechanism. +It is executed with a specified virtual space address and a segment +number ( in range [0, 511]), and returns the real memory address +of a buffer guaranteed to contain the segment requested. The address +returned is that of the 'struct vseg' not that of the data portion. It +is up to the program to refer to the 's_cinfo' or 's_winfo' member +to refer to the byte or word oriented data respectively. +.NH 4 +CALLING SEQUENCE +.PP +.in +8 +.nf +segptr = vmmapseg(vsptr,segno) + +struct vspace *vsptr; +int segno; +struct vseg *segptr; +.fi +.in -8 +.NH 4 +.IP vsptr +Specifies the address of a virtual space structure allocated by +the calling program. A previous vmopen call using this structure +must have been performed before calling \fIvmmapseg\fP. +.IP segno +Specifies the segment i.e., virtual page, number to be mapped into +real physical memory. The value must be in the range [0 to MAXSEGNO-1]. +There are two macros (defined in \fIvmf.h\fP) which are useful in +calculating segment numbers: \fBVSEG\fP and \fBVOFF\fP. +.IP segptr +The address of a virtual seg structure which contains the virtual +space segment associated with segno. The data is referred to with +the 's_cinfo' or 's_winfo' structure members: segptr->s_cinfo +or segptr->s_winfo respectively. +.PP +Currently this routine aborts the program on an error condition. +.NH 3 +vmmodify -- Mark a Segment as Modified +.NH 4 +.PP +Whenever the user program modifies any segment, it is the program's +responsibility to inform the virtual memory system of the modification. +The "vmmodify" routine flags the specified segment as modified and should be +executed before any future execution of 'vmmapseg' that could reuse +the modified buffer. Note that a locked segment buffer cannot be reused, +until it is unlocked. A macro form of this routine exists, \fBVMMODIFY\fP +may be used to mark a segment as modified. +.NH 4 +CALLING SEQUENCE +.PP +.in +8 +.nf +void vmmodify(segptr) + +struct vseg *segptr; +.fi +.in -8 +.IP segptr +Specifies the address of a seg structure associated with a current +incore virtual memory segment which has been modified. +.NH 3 +vmlock -- Lock a Virtual Segment into Real Memory +.NH 4 +.PP +Increment the lock count of the specified segment buffer. +A buffer with a nonzero lock count is +.I locked +and cannot be reused/swapped-out. The utility of this feature to the user is +that a locked segment buffer will stay at the same real memory address +until unlocked, hence real memory pointers into or to it can remain +valid. Overuse of \fIvmlock\fP will cause errors in \fIvmmapseg\fP +when no segments are available to satisfy swap in/out requests. +.NH 4 +CALLING SEQUENCE +.PP +.in +8 +.nf +void vmlock(segptr1) + +struct vseg *segptr; +.fi +.in -8 +.NH 4 +.IP segptr +Specifies the address of a seg structure associated with a current +incore virtual memory segment. No information is returned. +.NH 3 +vmunlock -- Unlock a Previously Locked Virtual Memory Segment +.NH 4 +.PP +Decrement the lock count of the specified buffer. It is a serious error +to decrement the count below zero, this typically means that the segment +was never locked in the first place. +.NH 4 +CALLING SEQUENCE +.PP +.in +8 +.nf +void vmunlock(segptr) + +struct vseg *segptr; +.fi +.in -8 +.NH 4 +.IP segptr1 +Specifies the address of a seg structure associated with a current +incore virtual memory segment. No information is returned from this +routine. +.NH 3 +vmclrseg -- Clear a Virtual Memory Segment to Zeros +.NH 4 +.PP +Clear the data area of the specified segement buffer. No information is +returned by this function. +.NH 4 +CALLING SEQUENCE +.PP +.in +8 +.nf +void vmclrseg(segptr) + +struct vseg *segptr +.fi +.in -8 +.NH 4 +.IP segptr +Specifies the address of a seg structure associated with a current +incore virtual memory segment. The data portion (segptr->s_cinfo) +is cleared by a call to \fIbzero\fP(3). +.NH 3 +vmflush -- Flush Virtual Memory Cache to Swap File +.NH 4 +.PP +Swap out all segments that are marked as +"modified". It may be called just prior to program termination +if there are any permanent spaces that have been modified but +normally a program will simply call \fIvmclose\fP which takes care +of flushing modified pages as part of its normal duties. +.NH 4 +CALLING SEQUENCE +.PP +.in +8 +.nf +void vmflush() +.fi +.in -8 diff --git a/src/libwiznet/Makefile b/src/libwiznet/Makefile new file mode 100644 index 0000000..0fadb8c --- /dev/null +++ b/src/libwiznet/Makefile @@ -0,0 +1,17 @@ +TOPSRC = $(shell cd ../..; pwd) +include $(TOPSRC)/target.mk + +CFLAGS += -O -Wall -Werror + +OBJS = w5100.o socket.o ethernet.o client.o server.o udp.o + +all: ../libwiznet.a + +../libwiznet.a: ${OBJS} + @$(AR) ru $@ ${OBJS} + $(RANLIB) $@ + +install: all + +clean: + rm -f *.o a.out core test errs ../libwiznet*.a diff --git a/src/libwiznet/client.c b/src/libwiznet/client.c new file mode 100644 index 0000000..fa40123 --- /dev/null +++ b/src/libwiznet/client.c @@ -0,0 +1,157 @@ +#include +#include +#include +#include + +unsigned _client_srcport = 1024; + +void client_init (client_t *c, uint8_t *ip, unsigned port) +{ + c->ip = ip; + c->port = port; + c->sock = MAX_SOCK_NUM; +} + +void client_init_sock (client_t *c, unsigned sock) +{ + c->sock = sock; +} + +int client_connect (client_t *c) +{ + int i; + + if (c->sock != MAX_SOCK_NUM) + return 0; + + for (i = 0; i < MAX_SOCK_NUM; i++) { + unsigned s = w5100_readSnSR (i); + if (s == SnSR_CLOSED || s == SnSR_FIN_WAIT) { + c->sock = i; + break; + } + } + + if (c->sock == MAX_SOCK_NUM) + return 0; + + _client_srcport++; + if (_client_srcport == 0) + _client_srcport = 1024; + socket_init (c->sock, SnMR_TCP, _client_srcport, 0); + + if (! socket_connect (c->sock, c->ip, c->port)) { + c->sock = MAX_SOCK_NUM; + return 0; + } + + while (client_status(c) != SnSR_ESTABLISHED) { + usleep (10000); + if (client_status(c) == SnSR_CLOSED) { + c->sock = MAX_SOCK_NUM; + return 0; + } + } + return 1; +} + +void client_putc (client_t *c, uint8_t b) +{ + if (c->sock != MAX_SOCK_NUM) + socket_send (c->sock, &b, 1); +} + +void client_puts (client_t *c, const char *str) +{ + if (c->sock != MAX_SOCK_NUM) + socket_send (c->sock, (const uint8_t *)str, strlen(str)); +} + +void client_write (client_t *c, const uint8_t *buf, size_t size) +{ + if (c->sock != MAX_SOCK_NUM) + socket_send (c->sock, buf, size); +} + +int client_available (client_t *c) +{ + if (c->sock != MAX_SOCK_NUM) + return w5100_getRXReceivedSize (c->sock); + return 0; +} + +int client_getc (client_t *c) +{ + uint8_t b; + + if (socket_recv (c->sock, &b, 1) <= 0) { + // No data available + return -1; + } + return b; +} + +int client_read (client_t *c, uint8_t *buf, size_t size) +{ + return socket_recv (c->sock, buf, size); +} + +int client_peek (client_t *c) +{ + uint8_t b; + + // Unlike recv, peek doesn't check to see if there's any data available, so we must + if (! client_available (c)) + return -1; + + b = socket_peek (c->sock); + return b; +} + +void client_flush (client_t *c) +{ + while (client_available (c)) + client_getc (c); +} + +void client_stop (client_t *c) +{ + int i; + + if (c->sock == MAX_SOCK_NUM) + return; + + // attempt to close the connection gracefully (send a FIN to other side) + socket_disconnect (c->sock); + + // wait a second for the connection to close + for (i=0; i<100; i++) { + if (client_status (c) == SnSR_CLOSED) + break; + usleep (10000); + } + + // if it hasn't closed, close it forcefully + if (client_status(c) != SnSR_CLOSED) + socket_close (c->sock); + + _socket_port[c->sock] = 0; + c->sock = MAX_SOCK_NUM; +} + +int client_connected (client_t *c) +{ + if (c->sock == MAX_SOCK_NUM) + return 0; + + unsigned s = client_status (c); + return ! (s == SnSR_LISTEN || s == SnSR_CLOSED || s == SnSR_FIN_WAIT || + (s == SnSR_CLOSE_WAIT && ! client_available (c))); +} + +unsigned client_status (client_t *c) +{ + if (c->sock == MAX_SOCK_NUM) + return SnSR_CLOSED; + return w5100_readSnSR (c->sock); +} diff --git a/src/libwiznet/ethernet.c b/src/libwiznet/ethernet.c new file mode 100644 index 0000000..ce1f9cc --- /dev/null +++ b/src/libwiznet/ethernet.c @@ -0,0 +1,131 @@ +#include +#include +#include +#include +#include + +unsigned char ethernet_mac [6]; +unsigned char ethernet_ip [4]; +unsigned char ethernet_gateway [4]; +unsigned char ethernet_netmask [4]; + +/* + * Get MAC address from string to byte array. + */ +static void parse_mac (unsigned char *macp, char *str) +{ + unsigned char *limit = macp + 6; + register unsigned c, val; + + do { + /* Collect number up to ":". */ + val = 0; + while ((c = (unsigned char) *str)) { + if (c >= '0' && c <= '9') + val = (val << 4) + (c - '0'); + else if (c >= 'a' && c <= 'f') + val = (val << 4) + (c - 'a' + 10); + else if (c >= 'A' && c <= 'F') + val = (val << 4) + (c - 'A' + 10); + else + break; + str++; + } + *macp++ = val; + } while (*str++ == ':' && macp < limit); +} + +/* + * Get IP address from string to byte array. + */ +static void parse_ip (unsigned char *val, char *str) +{ + unsigned long addr; + + if (! str) + return; + addr = inet_addr (str); + val[0] = addr >> 0; + val[1] = addr >> 8; + val[2] = addr >> 16; + val[3] = addr >> 24; +} + +/* + * Initialize Ethernet controller. + * Get parameters from environment: + * MAC=aa:bb:cc:dd:ee:ff - unique MAC address + * IP=12.34.56.78 - IP address + * GATEWAY=12.34.56.1 - gateway to Internet (optional) + * NETMASK=255.255.255.0 - netmask of local Ethernet network (optional) + */ +void ethernet_init () +{ + char *mac, *ip, *gateway, *netmask; + + mac = getenv("MAC"); + if (! mac) { + fprintf (stderr, "Please set MAC environment variable\n"); + exit (-1); + } + parse_mac (ethernet_mac, mac); + + ip = getenv("IP"); + if (! ip) { + fprintf (stderr, "Please set IP environment variable\n"); + exit (-1); + } + parse_ip (ethernet_ip, ip); + + gateway = getenv("GATEWAY"); + if (gateway != 0) { + parse_ip (ethernet_gateway, gateway); + } else { + ethernet_gateway[0] = ethernet_ip[0]; + ethernet_gateway[1] = ethernet_ip[1]; + ethernet_gateway[2] = ethernet_ip[2]; + ethernet_gateway[3] = 1; + } + + netmask = getenv("NETMASK"); + if (netmask != 0) { + parse_ip (ethernet_netmask, netmask); + } else { + ethernet_netmask[0] = 255; + ethernet_netmask[1] = 255; + ethernet_netmask[2] = 255; + ethernet_netmask[3] = 0; + } + printf("local MAC address %02x:%02x:%02x:%02x:%02x:%02x\n", + ethernet_mac[0], ethernet_mac[1], ethernet_mac[2], + ethernet_mac[3], ethernet_mac[4], ethernet_mac[5]); + printf("local IP address %u.%u.%u.%u\n", + ethernet_ip[0], ethernet_ip[1], + ethernet_ip[2], ethernet_ip[3]); + printf("gateway %u.%u.%u.%u\n", + ethernet_gateway[0], ethernet_gateway[1], + ethernet_gateway[2], ethernet_gateway[3]); + printf("netmask %u.%u.%u.%u\n", + ethernet_netmask[0], ethernet_netmask[1], + ethernet_netmask[2], ethernet_netmask[3]); + + w5100_init(); + + /* Set Ethernet MAC address. */ + w5100_writeSHAR (ethernet_mac); + + /* Set local IP address. */ + w5100_writeSIPR (ethernet_ip); + + /* Set gateway IP address. */ + w5100_writeGAR (ethernet_gateway); + + /* Set subnet mask. */ + w5100_writeSUBR (ethernet_netmask); + + /* Set retransmission timeout to 200 msec. */ + w5100_writeRTR (200*10); + + /* Set retransmission count. */ + //w5100_writeRCR (3); +} diff --git a/src/libwiznet/server.c b/src/libwiznet/server.c new file mode 100644 index 0000000..b9dd766 --- /dev/null +++ b/src/libwiznet/server.c @@ -0,0 +1,96 @@ +#include +#include +#include + +unsigned _server_port; + +void server_init (unsigned port) +{ + unsigned sock; + client_t client; + + _server_port = port; + for (sock = 0; sock < MAX_SOCK_NUM; sock++) { + client_init_sock (&client, sock); + + if (client_status (&client) == SnSR_CLOSED) { + socket_init (sock, SnMR_TCP, port, 0); + socket_listen (sock); + _socket_port[sock] = port; + break; + } + } +} + +void server_accept() +{ + unsigned sock; + client_t client; + int listening = 0; + + for (sock = 0; sock < MAX_SOCK_NUM; sock++) { + client_init_sock (&client, sock); + + if (_socket_port[sock] == _server_port) { + if (client_status (&client) == SnSR_LISTEN) { + listening = 1; + } + else if (client_status (&client) == SnSR_CLOSE_WAIT && + ! client_available (&client)) { + client_stop (&client); + } + } + } + + if (! listening) { + server_init (_server_port); + } +} + +int server_available (client_t *client) +{ + unsigned sock; + + server_accept(); + + for (sock = 0; sock < MAX_SOCK_NUM; sock++) { + client_init_sock (client, sock); + + if (_socket_port[sock] == _server_port && + (client_status (client) == SnSR_ESTABLISHED || + client_status (client) == SnSR_CLOSE_WAIT)) { + if (client_available (client)) { + // XXX: don't always pick the lowest numbered socket. + return 1; + } + } + } + return 0; +} + +void server_putc (uint8_t b) +{ + server_write (&b, 1); +} + +void server_puts (const char *str) +{ + server_write ((const uint8_t *)str, strlen(str)); +} + +void server_write (const uint8_t *buffer, size_t size) +{ + unsigned sock; + client_t client; + + server_accept(); + + for (sock = 0; sock < MAX_SOCK_NUM; sock++) { + client_init_sock (&client, sock); + + if (_socket_port[sock] == _server_port && + client_status (&client) == SnSR_ESTABLISHED) { + client_write (&client, buffer, size); + } + } +} diff --git a/src/libwiznet/socket.c b/src/libwiznet/socket.c new file mode 100644 index 0000000..53c6abd --- /dev/null +++ b/src/libwiznet/socket.c @@ -0,0 +1,329 @@ +#include +#include +#include + +unsigned _socket_port [MAX_SOCK_NUM] = { 0 }; + +static unsigned local_port; + +/* + * This Socket function initialize the channel in perticular mode, + * and set the port and wait for W5100 done it. + * Return 1 for success else 0. + */ +unsigned socket_init (unsigned sock, unsigned protocol, unsigned port, unsigned flag) +{ + if ((protocol == SnMR_TCP) || (protocol == SnMR_UDP) || + (protocol == SnMR_IPRAW) || (protocol == SnMR_MACRAW) || + (protocol == SnMR_PPPOE)) + { + socket_close (sock); + w5100_writeSnMR (sock, protocol | flag); + if (port != 0) { + w5100_writeSnPORT (sock, port); + } else { + /* if don't set the source port, set local_port number. */ + local_port++; + w5100_writeSnPORT (sock, local_port); + } + + w5100_socket_cmd (sock, Sock_OPEN); + return 1; + } + return 0; +} + +/* + * This function close the socket and parameter is "sock" which represent + * the socket number. + */ +void socket_close (unsigned sock) +{ + w5100_socket_cmd (sock, Sock_CLOSE); + w5100_writeSnIR (sock, 0xFF); +} + +/* + * This function established the connection for the channel in passive + * (server) mode. This function waits for the request from the peer. + * Return 1 for success else 0. + */ +unsigned socket_listen (unsigned sock) +{ + if (w5100_readSnSR (sock) != SnSR_INIT) + return 0; + w5100_socket_cmd (sock, Sock_LISTEN); + return 1; +} + +/* + * This function established the connection for the channel in Active + * (client) mode. This function waits for the untill the connection + * is established. + * Return 1 for success else 0. + */ +unsigned socket_connect (unsigned sock, uint8_t * addr, unsigned port) +{ + if (((addr[0] == 0xFF) && (addr[1] == 0xFF) && + (addr[2] == 0xFF) && (addr[3] == 0xFF)) || + ((addr[0] == 0x00) && (addr[1] == 0x00) && + (addr[2] == 0x00) && (addr[3] == 0x00)) || + (port == 0)) + return 0; + + /* set destination IP */ + w5100_writeSnDIPR (sock, addr); + w5100_writeSnDPORT (sock, port); + w5100_socket_cmd (sock, Sock_CONNECT); + return 1; +} + +/* + * This function used for disconnect the socket and parameter is "sock" + * which represent the socket number + * Return 1 for success else 0. + */ +void socket_disconnect (unsigned sock) +{ + w5100_socket_cmd (sock, Sock_DISCON); +} + +/* + * This function used to send the data in TCP mode + * Return 1 for success else 0. + */ +unsigned socket_send (unsigned sock, const uint8_t * buf, unsigned nbytes) +{ + unsigned status = 0; + unsigned freesize = 0; + + /* check size not to exceed MAX size. */ + if (nbytes > TXBUF_SIZE) + nbytes = TXBUF_SIZE; + + /* if freebuf is available, start. */ + do { + freesize = w5100_getTXFreeSize (sock); + status = w5100_readSnSR (sock); + if ((status != SnSR_ESTABLISHED) && + (status != SnSR_CLOSE_WAIT)) { + return 0; + } + } while (freesize < nbytes); + + /* copy data */ + w5100_send_chunk (sock, buf, nbytes); + w5100_socket_cmd (sock, Sock_SEND); + + /* +2008.01 bj */ + while ((w5100_readSnIR (sock) & SnIR_SEND_OK) != SnIR_SEND_OK) { + /* m2008.01 [bj] : reduce code */ + if (w5100_readSnSR (sock) == SnSR_CLOSED) { + socket_close (sock); + return 0; + } + } + /* +2008.01 bj */ + w5100_writeSnIR (sock, SnIR_SEND_OK); + return nbytes; +} + +/* + * This function is an application I/F function which is used to receive + * the data in TCP mode. It continues to wait for data as much as + * the application wants to receive. + * Return received data size for success else -1. + */ +unsigned socket_recv (unsigned sock, uint8_t *buf, unsigned len) +{ + /* Check how much data is available */ + unsigned navail = w5100_getRXReceivedSize (sock); + if (navail == 0) { + /* No data available. */ + w5100_readSnSR (sock); + + if (sock == SnSR_LISTEN || + sock == SnSR_CLOSED || + sock == SnSR_CLOSE_WAIT) + { + /* The remote end has closed its side of the connection, + * so this is the eof state */ + return 0; + } + /* The connection is still up, but there's no data waiting + * to be read */ + return -1; + } + + if (navail > len) { + navail = len; + } + + w5100_recv_chunk (sock, buf, navail); + w5100_socket_cmd (sock, Sock_RECV); + return navail; +} + +/* + * Returns the first byte in the receive queue (no checking) + */ +unsigned socket_peek (unsigned sock) +{ + return w5100_recv_peek (sock); +} + +/* + * This function is an application I/F function which is used to send + * the data for other then TCP mode. Unlike TCP transmission, the peer's + * destination address and the port is needed. + * + * This function return send data size for success else -1. + */ +unsigned socket_sendto (unsigned sock, const uint8_t *buf, unsigned len, uint8_t *addr, unsigned port) +{ + unsigned ret = 0; + + /* check size not to exceed MAX size. */ + if (len > TXBUF_SIZE) + ret = TXBUF_SIZE; + else + ret = len; + + if (((addr[0] == 0x00) && (addr[1] == 0x00) && + (addr[2] == 0x00) && (addr[3] == 0x00)) || + (port == 0) || (ret == 0)) { + /* +2008.01 [bj] : added return value */ + ret = 0; + } else { + w5100_writeSnDIPR (sock, addr); + w5100_writeSnDPORT (sock, port); + + /* copy data */ + w5100_send_chunk (sock, buf, ret); + w5100_socket_cmd (sock, Sock_SEND); + + /* +2008.01 bj */ + while ((w5100_readSnIR (sock) & SnIR_SEND_OK) != SnIR_SEND_OK) { + if (w5100_readSnIR (sock) & SnIR_TIMEOUT) { + /* +2008.01 [bj]: clear interrupt */ + /* clear SEND_OK & TIMEOUT */ + w5100_writeSnIR (sock, SnIR_SEND_OK | SnIR_TIMEOUT); + return 0; + } + } + + /* +2008.01 bj */ + w5100_writeSnIR (sock, SnIR_SEND_OK); + } + return ret; +} + +/* + * This function is an application I/F function which is used to receive + * the data in other then TCP mode. This function is used to receive UDP, + * IP_RAW and MAC_RAW mode, and handle the header as well. + * + * This function return received data size for success else -1. + */ +unsigned socket_recvfrom (unsigned sock, uint8_t *buf, unsigned len, + uint8_t *addr, unsigned *port) +{ + uint8_t head[8]; + unsigned nreceived = 0; + unsigned ptr, mode; + + if (len <= 0) + return 0; + + ptr = w5100_readSnRX_RD (sock); + mode = w5100_readSnMR (sock); + W5100_DEBUG ("socket_recvfrom: mode %02x, RX pointer = %04x\n", mode, ptr); + + switch (mode & 0x07) { + case SnMR_UDP: + w5100_read_data (sock, ptr, head, 8); + ptr += 8; + + /* read peer's IP address, port number. */ + W5100_DEBUG ("UDP peer %u.%u.%u.%u, port %u\n", + head[0], head[1], head[2], head[3], (head[4] << 8) | head[5]); + if (addr) { + addr[0] = head[0]; + addr[1] = head[1]; + addr[2] = head[2]; + addr[3] = head[3]; + } + if (port) + *port = (head[4] << 8) | head[5]; + + nreceived = (head[6] << 8) + head[7]; + break; + + case SnMR_IPRAW: + w5100_read_data (sock, ptr, head, 6); + ptr += 6; + + /* read peer's IP address. */ + W5100_DEBUG ("IPRAW peer %u.%u.%u.%u\n", + head[0], head[1], head[2], head[3]); + if (addr) { + addr[0] = head[0]; + addr[1] = head[1]; + addr[2] = head[2]; + addr[3] = head[3]; + } + nreceived = (head[4] << 8) + head[5]; + break; + + case SnMR_MACRAW: + w5100_read_data (sock, ptr, head, 2); + ptr += 2; + + nreceived = (head[0] << 8) + head[1] - 2; + break; + + default: + W5100_DEBUG ("unknown mode %02x\n", mode); + return 0; + } + W5100_DEBUG ("received %u bytes\n", nreceived); + + /* data copy. */ + w5100_read_data (sock, ptr, buf, nreceived); + ptr += nreceived; + + w5100_writeSnRX_RD (sock, ptr); + W5100_DEBUG ("set RX pointer = %04x\n", ptr); + + w5100_socket_cmd (sock, Sock_RECV); + return nreceived; +} + +unsigned socket_igmpsend (unsigned sock, const uint8_t * buf, unsigned len) +{ + unsigned ret = 0; + + if (len > TXBUF_SIZE) + ret = TXBUF_SIZE; /* check size not to exceed MAX size. */ + else + ret = len; + + if (ret == 0) + return 0; + + w5100_send_chunk (sock, buf, ret); + w5100_socket_cmd (sock, Sock_SEND); + + while ((w5100_readSnIR (sock) & SnIR_SEND_OK) != SnIR_SEND_OK) { + w5100_readSnSR (sock); + if (w5100_readSnIR (sock) & SnIR_TIMEOUT) { + /* in case of igmp, if send fails, then socket closed */ + /* if you want change, remove this code. */ + socket_close (sock); + return 0; + } + } + + w5100_writeSnIR (sock, SnIR_SEND_OK); + return ret; +} diff --git a/src/libwiznet/udp.c b/src/libwiznet/udp.c new file mode 100644 index 0000000..0c98adf --- /dev/null +++ b/src/libwiznet/udp.c @@ -0,0 +1,150 @@ +/* + * Udp.cpp: Library to send/receive UDP packets with the Arduino ethernet shield. + * This version only offers minimal wrapping of socket.c/socket.h + * + * MIT License: + * Copyright (c) 2008 Bjoern Hartmann + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * bjoern@cs.stanford.edu 12/30/2008 + */ +#include +#include +#include +#include + +/* + * Start UDP socket, listening at local port PORT + */ +int udp_init (udp_t *u, unsigned port) +{ + int i; + + for (i = 0; i < MAX_SOCK_NUM; i++) { + uint8_t s = w5100_readSnSR(i); + if (s == SnSR_CLOSED || s == SnSR_FIN_WAIT) { + u->sock = i; + break; + } + } + + if (u->sock == MAX_SOCK_NUM) + return 0; + + u->port = port; + socket_init (u->sock, SnMR_UDP, u->port, 0); + return 1; +} + +/* + * Is data available in rx buffer? + * Returns 0 if no, number of available bytes if yes. + * returned value includes 8 byte UDP header! + */ +unsigned udp_available (udp_t *u) +{ + return w5100_getRXReceivedSize (u->sock); +} + +/* + * Release any resources being used by this UDP instance. + */ +void udp_stop (udp_t *u) +{ + if (u->sock == MAX_SOCK_NUM) + return; + + socket_close (u->sock); + + _socket_port[u->sock] = 0; + u->sock = MAX_SOCK_NUM; +} + +/* + * Send packet contained in buf of length len to peer at specified ip, and port. + * Use this function to transmit binary data that might contain 0x00 bytes. + * This function returns sent data size for success else -1. + */ +unsigned udp_send_packet (udp_t *u, const uint8_t *buf, unsigned len, + uint8_t *ip, unsigned port) +{ + return socket_sendto (u->sock, buf, len, ip, port); +} + +/* + * Send zero-terminated string str as packet to peer at specified ip, and port. + * This function returns sent data size for success else -1. + */ +unsigned udp_send_string (udp_t *u, const char *str, + uint8_t *ip, unsigned port) +{ + unsigned len = strlen (str); + + return socket_sendto (u->sock, (const uint8_t *) str, len, ip, port); +} + +/* + * Read a received packet into buffer buf (which is of maximum length len); + * store calling ip and port as well. Call available() to make sure data is + * ready first. + * NOTE: I don't believe len is ever checked in implementation of recvfrom(), + * so it's easy to overflow buffer. so we check and truncate. + * Returns number of bytes read, or negative number of bytes we would have + * needed if we truncated. + */ +int udp_read_packet (udp_t *u, uint8_t *buf, unsigned len, + uint8_t *ip, unsigned *port) +{ + int nbytes = udp_available (u) - 8; /* skip UDP header */ + if (nbytes < 0) { + /* No real data here. */ + return 0; + } + + if (nbytes > (int)len) { + /* Packet is too large - truncate. + * HACK: hand-parse the UDP packet using TCP recv method. */ + uint8_t tmpBuf[8]; + int i; + + /* Read 8 header bytes and get IP and port from it. */ + socket_recv (u->sock, tmpBuf, 8); + if (ip != 0) { + ip[0] = tmpBuf[0]; + ip[1] = tmpBuf[1]; + ip[2] = tmpBuf[2]; + ip[3] = tmpBuf[3]; + } + if (port != 0) + *port = (tmpBuf[4] << 8) + tmpBuf[5]; + + /* Now copy first (len) bytes into buf. */ + for (i=0; i<(int)len; i++) { + socket_recv (u->sock, tmpBuf, 1); + buf[i] = tmpBuf[0]; + } + + /* And just read the rest byte by byte and throw it away. */ + while (udp_available (u)) { + socket_recv (u->sock, tmpBuf, 1); + } + return -nbytes; + } + return socket_recvfrom (u->sock, buf, len, ip, port); +} diff --git a/src/libwiznet/w5100.c b/src/libwiznet/w5100.c new file mode 100644 index 0000000..9d29615 --- /dev/null +++ b/src/libwiznet/w5100.c @@ -0,0 +1,246 @@ +/* + * Copyright (c) 2010 by Cristian Maglie + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of either the GNU General Public License version 2 + * or the GNU Lesser General Public License version 2.1, both as + * published by the Free Software Foundation. + * + * Edit History + * Aug 3, 2011 ported toh chipKIT boards + * Sept 13, 2011 change SPI clock divider from DIV8 to DIV32 + * Apr 16, 2012 ported to RetroBSD + */ +#include +#include +#include +#include +#include +#include + +#define SPI_DEVNAME "/dev/spi2" // W5100 chip is connected to SPI2 +#define SPI_KHZ 5000 // Clock speed 5 MHz +#define SPI_SELPIN 0x0404 // chipKIT board: select pin D4 + +#define TXBUF_BASE 0x4000 +#define RXBUF_BASE 0x6000 + +#define RST 7 // Reset BIT + +#define TXBUF_MASK (TXBUF_SIZE-1) // Tx buffer MASK +#define RXBUF_MASK (RXBUF_SIZE-1) // Rx buffer MASK + +static uint16_t SBASE [MAX_SOCK_NUM]; // Tx buffer base address +static uint16_t RBASE [MAX_SOCK_NUM]; // Rx buffer base address + +static int spi; // SPI driver descriptor + +void w5100_init() +{ + int i, failed; + + spi = open (SPI_DEVNAME, O_RDWR); + if (spi < 0) { + perror (SPI_DEVNAME); + exit (-1); + } + + ioctl (spi, SPICTL_SETRATE, SPI_KHZ); + ioctl (spi, SPICTL_SETSELPIN, SPI_SELPIN); + + /* Reset the chip. */ + w5100_writeMR (MR_RST); + + /* Assign 2 kbytes of memory to RX and TX of each socket. */ + w5100_writeTMSR (0x55); + w5100_writeRMSR (0x55); + + for (i=0; i TXBUF_SIZE) { + // Wrap around circular buffer + unsigned size = TXBUF_SIZE - offset; + w5100_write (dstAddr, data, size); + w5100_write (SBASE[sock], data + size, len - size); + W5100_DEBUG ("TX %04x-%04x, %04x-%04x\n", dstAddr, dstAddr+size-1, SBASE[sock], SBASE[sock]+len-size-1); + } else { + w5100_write (dstAddr, data, len); + W5100_DEBUG ("TX %04x-%04x\n", dstAddr, dstAddr+len-1); + } + + ptr += len; + w5100_writeSnTX_WR (sock, ptr); + W5100_DEBUG ("set TX write pointer = %04x\n", ptr); +} + +void w5100_recv_chunk (unsigned sock, uint8_t *data, unsigned len) +{ + unsigned ptr = w5100_readSnRX_RD (sock); + + W5100_DEBUG ("recv chunk: RX pointer = %04x\n", ptr); + w5100_read_data (sock, ptr, data, len); + + ptr += len; + w5100_writeSnRX_RD (sock, ptr); + W5100_DEBUG ("set RX pointer = %04x\n", ptr); +} + +unsigned w5100_recv_peek (unsigned sock) +{ + unsigned ptr = w5100_readSnRX_RD (sock); + unsigned char byte; + + w5100_read_data (sock, ptr, &byte, 1); + return byte; +} + +void w5100_socket_cmd (unsigned sock, int cmd) +{ + // Send command to socket + w5100_writeSnCR (sock, cmd); + + // Wait for command to complete + while (w5100_readSnCR (sock)) + ; +} + +void w5100_read_data (unsigned sock, unsigned ptr, uint8_t *dst, unsigned len) +{ + unsigned offset = ptr & RXBUF_MASK; + unsigned srcAddr = offset + RBASE[sock]; + + if (offset + len > RXBUF_SIZE) + { + unsigned size = RXBUF_SIZE - offset; + w5100_read (srcAddr, dst, size); + w5100_read (RBASE[sock], dst + size, len - size); + W5100_DEBUG ("RX %04x-%04x, %04x-%04x\n", srcAddr, srcAddr+size-1, SBASE[sock], SBASE[sock]+len-size-1); + } else { + w5100_read (srcAddr, dst, len); + W5100_DEBUG ("RX %04x-%04x\n", srcAddr, srcAddr+len-1); + } +} + +unsigned w5100_write_byte (unsigned addr, int byte) +{ + uint8_t data[4]; + + data[0] = 0xF0; + data[1] = addr >> 8; + data[2] = addr; + data[3] = byte; + ioctl (spi, SPICTL_IO8(4), data); + return 1; +} + +unsigned w5100_write (unsigned addr, const uint8_t *buf, unsigned len) +{ + uint8_t data[4]; + unsigned i; + + for (i=0; i> 8; + data[2] = addr; + data[3] = buf[i]; + ioctl (spi, SPICTL_IO8(4), data); + addr++; + } + return len; +} + +unsigned w5100_read_byte (unsigned addr) +{ + uint8_t data[4]; + + data[0] = 0x0F; + data[1] = addr >> 8; + data[2] = addr; + data[3] = 0xFF; + ioctl (spi, SPICTL_IO8(4), data); + + return data[3]; +} + +unsigned w5100_read (unsigned addr, uint8_t *buf, unsigned len) +{ + uint8_t data[4]; + unsigned i; + + for (i=0; i> 8; + data[2] = addr; + data[3] = 0xFF; + ioctl (spi, SPICTL_IO8(4), data); + addr++; + buf[i] = data[3]; + } + return len; +} diff --git a/src/share/Makefile b/src/share/Makefile new file mode 100644 index 0000000..bd0a113 --- /dev/null +++ b/src/share/Makefile @@ -0,0 +1,24 @@ +# +# Public domain - 1996/10/21 - sms +# +# @(#)Makefile 1.1 (2.11BSD) 1996/11/29 +# +TOPSRC = $(shell cd ../..; pwd) +include $(TOPSRC)/target.mk + +SUBDIR = misc + +all: ${SUBDIR} + +${SUBDIR}: FRC + cd $@; make ${MFLAGS} + +FRC: + +install: FRC + -for i in ${SUBDIR}; do \ + (cd $$i; make ${MFLAGS} DESTDIR=${DESTDIR} install); done + +clean: + rm -f *~ + for i in ${SUBDIR}; do (cd $$i; make ${MFLAGS} clean); done diff --git a/src/share/misc/Makefile b/src/share/misc/Makefile new file mode 100644 index 0000000..c32bac9 --- /dev/null +++ b/src/share/misc/Makefile @@ -0,0 +1,21 @@ +# +# Public domain - 1996/10/21 - sms +# +# Makefile for misc data files (lib.b from 'bc', usw.) +# +TOPSRC = $(shell cd ../../..; pwd) +include $(TOPSRC)/target.mk + +SRCS = +# eign lib.b Mail.help Mail.tildehelp units gprof.callg gprof.flat \ +# vlpmacs mkproto.data + +all: ${SRCS} + +install: ${SRCS} + -mkdir -p ${DESTDIR}/share/misc + -chmod a+r,a+x ${DESTDIR}/share/misc +# install -c -m 444 ${SRCS} ${DESTDIR}/share/misc + +clean: + rm -f *~ diff --git a/src/startup-mips/Makefile b/src/startup-mips/Makefile new file mode 100644 index 0000000..c90ec84 --- /dev/null +++ b/src/startup-mips/Makefile @@ -0,0 +1,56 @@ +# +# Copyright (c) 1987 Regents of the University of California. +# All rights reserved. The Berkeley software License Agreement +# specifies the terms and conditions for redistribution. +# +# crt0 Normal C run time startoff +# +TOPSRC = $(shell cd ../..; pwd) +include $(TOPSRC)/target.mk + +CFLAGS = -O ${DEFS} + +SRCS = crt0.c +OBJS = crt0.o + +TAGSFILE = tags + +all: ${OBJS} + cp crt0.o ../ + +install: ${OBJS} +# $(INSTALLDIR) ${DESTDIR}/lib +# $(INSTALL) crt0.o ${DESTDIR}/lib/crt0.o +# $(INSTALL) mcrt0.o ${DESTDIR}/lib/mcrt0.o +# $(INSTALL) gcrt0.o ${DESTDIR}/usr/lib/gcrt0.o + +crt0.o: crt0.c + $(CC) ${DEFS} ${CFLAGS} -c $< -o $@ + +tags: + cwd=`pwd`; \ + for i in *.c; do \ + ctags -a -f ${TAGSFILE} $$cwd/$$i; \ + done + +clean: + rm -f *.o *~ core errs tags Makefile.bak + +depend: + for i in ${SRCS}; do \ + cc -M ${DEFS} ${DFLAGS} $$i | 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 } ' >> makedep; done + echo '/^# DO NOT DELETE THIS LINE/+2,$$d' >eddep + echo '$$r makedep' >>eddep + echo 'w' >>eddep + cp Makefile Makefile.bak + ed - Makefile < eddep + rm eddep makedep + echo '# DEPENDENCIES MUST END AT END OF FILE' >> Makefile + echo '# IF YOU PUT STUFF HERE IT WILL GO AWAY' >> Makefile + echo '# see make depend above' >> Makefile + +# DO NOT DELETE THIS LINE -- make depend uses it diff --git a/src/startup-mips/crt0.c b/src/startup-mips/crt0.c new file mode 100644 index 0000000..7b08019 --- /dev/null +++ b/src/startup-mips/crt0.c @@ -0,0 +1,81 @@ +/* + * Copyright (c) 1987 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include +#include + +/* + * C runtime startoff. When an a.out is loaded by the kernel, the kernel + * sets up the stack as follows: + * + * _________________________________ + * | (NULL) | top of memory + * |-------------------------------| + * | | + * | environment strings | + * | | + * |-------------------------------| + * | | + * | argument strings | + * | | + * |-------------------------------| + * | envv[envc] (NULL) | end of environment vector tag, a 0 + * |-------------------------------| + * | envv[envc-1] | pointer to last environment string + * |-------------------------------| + * | ... | + * |-------------------------------| + * | envv[0] | pointer to first environment string + * |-------------------------------| + * | argv[argc] (NULL) | end of argument vector tag, a 0 + * |-------------------------------| + * | argv[argc-1] | pointer to last argument string + * |-------------------------------| + * | ... | + * |-------------------------------| + * | argv[0] | pointer to first argument string + * |-------------------------------| + * | | space for fourth argument + * |-------------------------------| + * | | space for third argument + * |-------------------------------| + * | | space for second argument + * |-------------------------------| + * sp-> | | space for first + * --------------------------------- + * + * Arguments are passed in registers $a0, $a1 and $a2. + * Register $gp is set to the start of data section. + * + * Crt0 simply moves the env to environ variable, calculates + * the __progname and then calls main. + */ +extern int main (int, char **, char **); + +char **environ; +const char *__progname = ""; + +void _start (int, char **, char **); + +/* The entry function. */ +void +_start (argc, argv, env) + int argc; + char **argv; + char **env; +{ + asm volatile ("la $gp, _gp"); + + environ = env; + if (argc > 0 && argv[0] != 0) { + const char *s; + + __progname = argv[0]; + for (s = __progname; *s != '\0'; s++) + if (*s == '/') + __progname = s + 1; + } + exit (main (argc, argv, env)); +} diff --git a/src/startup-mips/mcount.S b/src/startup-mips/mcount.S new file mode 100644 index 0000000..9fe23d3 --- /dev/null +++ b/src/startup-mips/mcount.S @@ -0,0 +1,90 @@ +/* + * Copyright (c) 1987 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +#ifdef LIBC_SCCS + <@(#)mcount.s 1.1 (Berkeley) 5/2/87\0> + .even +#endif LIBC_SCCS + +/* + * Count subroutine calls during simple (non-gprof) profiling. This file is + * appended to the compiled assembly output of mon.c. + * + * struct cnt { + * int (*pc)(); / address of function + * long ncall; / number of times _foo entered + * } + * + * mcount(cntp::r0) + * long **cntp; + * + * Mcount is called with a pointer to a function's local call count pointer in + * r0. On first entry, mcount allocates a (struct cnt) and initializes it with + * the function's base segment address and points the functions local call + * counter pointer just past the structure's ncall field. (we do this so we + * can do long increments slightly faster) + * + * The C compiler generates the following preamble for every function + * compiled with profiling: + * + * .data + * 1: _foo+1 + * .text + * + * _foo: / unique name of foo (always in base) + * ~foo: / real address of foo + * +0 jsr r5,csv / perform standard C entry + * +4 mov $1b,r0 / point to local call counter pointer + * +8 jsr pc,mcount / and have mcount do its thing + * +12 ... / first `real' word of ~foo + * + * Function and ncall field addresses are always even so the "_foo+1" doesn't + * destroy information and can be used to determine a first call to mcount. + * + * Note that because we now use functions' base segment address rather than + * our own return address (as was done in the past) and because the call to + * mcount is after that to csv, profiling now works for overlaid objects. + * Only static routines in overlays which are assigned the same address by + * the loader may be counted incorrectly. + */ +#include "../sys/SYS.h" +#undef PROF + + .text +ASENTRY(mcount) + tst _countbase / buffer set up yet? + beq 2f / nope, just exit + mov (r0),r1 / cnt struct allocated yet? + bit $1,r1 + bne 3f / nope, grab one +1: + add $1,-(r1) / increment *(*cnt-1) + adc -(r1) +2: + rts pc / and return +3: + mov _countbase,r1 + cmp r1,_countend / no, out of cnt structs? + bhis 3f / yes, output error message + mov (r0),(r1) / save _foo + bic $1,(r1)+ + cmp (r1)+,(r1)+ / move on to next cnt struct and + mov r1,_countbase / save in _countbase + mov r1,(r0) / save pointer to &ncall+1 in *cntp + br 1b / increment ncall (to 1) +3: + mov $9f-8f,-(sp) / ran out cnt structs, output an + mov $8f,-(sp) / error message + mov $2,-(sp) + tst -(sp) / simulate return address stack + SYS(write) / spacing and perform write (we + add $8.,sp / have to do the syscall because + rts pc / _write calls mcount) + +.data +8: +9: +.text diff --git a/src/startup-mips/mon.c b/src/startup-mips/mon.c new file mode 100644 index 0000000..22981a0 --- /dev/null +++ b/src/startup-mips/mon.c @@ -0,0 +1,124 @@ +/* + * Copyright (c) 1987 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)mon.c 5.5 (GTE) 3/23/92"; +#endif LIBC_SCCS and not lint + +#define ARCDENSITY 1 /* density of routines per 100 bytes */ +#define MINARCS 50 /* minimum number of counters */ +#define HISTFRACTION 8 /* fraction of text space for histograms */ + + +struct phdr { /* mon.out header */ + int *lpc; /* low pc of histogramed text space */ + int *hpc; /* high pc */ + int ncnt; /* number of functions counted */ +}; + +struct cnt { /* function entry count structure */ + int (*pc)(); /* address of profiled function */ + long ncall; /* number of time function called */ +}; + +static struct cnt *countbase; /* next free cnt struct */ +static struct cnt *countend; /* first address past cnt structs */ + +static short *s_sbuf; /* start of histogram buffer */ +static unsigned s_bufsize; /* size of histogram buffer (in chars) */ +static char *s_lowpc; /* low pc for histgram recording */ +static unsigned s_scale; /* histogram scale */ + +#define PERROR(s) write(2, s, sizeof(s)-1) + +monstartup(lowpc, highpc) + char *lowpc; + char *highpc; +{ + unsigned int cntsize, monsize; + char *buffer; + extern char *sbrk(); + extern char *minbrk; + + cntsize = (unsigned)(highpc - lowpc) * ARCDENSITY / 100; + if (cntsize < MINARCS) + cntsize = MINARCS; + monsize = (unsigned)(highpc - lowpc + HISTFRACTION - 1) / HISTFRACTION + + sizeof(struct phdr) + cntsize * sizeof(struct cnt); + monsize = (monsize + 1) & ~1; + buffer = sbrk(monsize); + if (buffer == (char *)-1) { + PERROR("monstartup: no space for monitor buffer(s)\n"); + return; + } + minbrk = sbrk(0); + monitor(lowpc, highpc, buffer, monsize>>1, cntsize); +} + +monitor(lowpc, highpc, buf, bufsize, cntsize) + char *lowpc, *highpc; + char *buf; /* really (short *) but easier this way */ + unsigned bufsize, cntsize; +{ + register unsigned o; + register struct phdr *php; + static char *sbuf; /* saved base of profiling buffer */ + static unsigned ssize; /* saved buffer size */ + + if (lowpc == 0) { + moncontrol(0); + o = creat("mon.out", 0666); + write(o, sbuf, ssize); + close(o); + return; + } + bufsize *= sizeof(short); + if (bufsize < sizeof(struct phdr)+sizeof(struct cnt)+sizeof(short)) { + PERROR("monitor: buffer too small"); + return; + } + sbuf = buf; + ssize = bufsize; + + countbase = (struct cnt *)(buf + sizeof(struct phdr)); + o = sizeof(struct phdr) + cntsize * sizeof(struct cnt); + if (o > bufsize) { + cntsize = (bufsize - sizeof(struct phdr))/sizeof(struct cnt); + o = sizeof(struct phdr) + cntsize * sizeof(struct cnt); + } + countend = (struct cnt *)(buf + o); + + php = (struct phdr *)buf; + php->lpc = (int *)lowpc; + php->hpc = (int *)highpc; + php->ncnt = cntsize; + + s_sbuf = (short *)countend; + s_bufsize = bufsize - o; + s_lowpc = lowpc; + o = highpc - lowpc; + if(s_bufsize < o) + o = ((long)s_bufsize << 16) / o; + else + o = 0xffff; + s_scale = o; + moncontrol(1); +} + +/* + * Control profiling + */ +moncontrol(mode) + int mode; +{ + if (mode) { + /* start */ + profil(s_sbuf, s_bufsize, s_lowpc, s_scale); + } else { + /* stop */ + profil((char *)0, 0, 0, 0); + } +} diff --git a/src/startup-mips/mon.ex b/src/startup-mips/mon.ex new file mode 100644 index 0000000..b6c3116 --- /dev/null +++ b/src/startup-mips/mon.ex @@ -0,0 +1,5 @@ +" @(#)mon.ex 4.4 (Berkeley) 7/26/83" +" fix funny name for minbrk used by monstartup() to limit brk()" +g/_minbrk/s//minbrk/g +w +q diff --git a/sys/include/adc.h b/sys/include/adc.h new file mode 100644 index 0000000..bfa2923 --- /dev/null +++ b/sys/include/adc.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + * + * @(#)adc.h 1.4 (2.11BSD GTE) 1997/3/28 + */ + +#ifndef _ADC_H +#define _ADC_H + +#include +#include + +#define ADCMAX 15 + +#ifdef KERNEL +#include "conf.h" + +extern const struct devspec adcdevs[]; + +int adc_open (dev_t dev, int flag, int mode); +int adc_close (dev_t dev, int flag, int mode); +int adc_read (dev_t dev, struct uio *uio, int flag); +int adc_write (dev_t dev, struct uio *uio, int flag); +int adc_ioctl (dev_t dev, u_int cmd, caddr_t addr, int flag); +#endif + +#endif diff --git a/sys/include/buf.h b/sys/include/buf.h new file mode 100644 index 0000000..9265b12 --- /dev/null +++ b/sys/include/buf.h @@ -0,0 +1,227 @@ +/* + * Copyright (c) 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +/* + * The header for buffers in the buffer pool and otherwise used + * to describe a block i/o request is given here. + * + * Each buffer in the pool is usually doubly linked into 2 lists: + * hashed into a chain by so it can be located in the cache, + * and (usually) on (one of several) queues. These lists are circular and + * doubly linked for easy removal. + * + * There are currently two queues for buffers: + * one for buffers containing ``useful'' information (the cache) + * one for buffers containing ``non-useful'' information + * (and empty buffers, pushed onto the front) + * These queues contain the buffers which are available for + * reallocation, are kept in lru order. When not on one of these queues, + * the buffers are ``checked out'' to drivers which use the available list + * pointers to keep track of them in their i/o active queues. + */ + +/* + * Bufhd structures used at the head of the hashed buffer queues. + * We only need three words for these, so this abbreviated + * definition saves some space. + */ +struct bufhd +{ + int b_flags; /* see defines below */ + struct buf *b_forw, *b_back; /* fwd/bkwd pointer in chain */ +}; + +struct buf +{ + int b_flags; /* see defines below */ + struct buf *b_forw, *b_back; /* hash chain (2 way street) */ + struct buf *av_forw, *av_back; /* position on free list if not BUSY */ +#define b_actf av_forw /* alternate names for driver queue */ +#define b_actl av_back /* head - isn't history wonderful */ + u_int b_bcount; /* transfer count */ +#define b_active b_bcount /* driver queue head: drive active */ + int b_error; /* returned after I/O */ + dev_t b_dev; /* major+minor device name */ + caddr_t b_addr; /* core address */ + daddr_t b_blkno; /* block # on device */ + u_int b_resid; /* words not transferred after error */ +#define b_cylin b_resid /* disksort */ +#define b_errcnt b_resid /* while i/o in progress: # retries */ +}; + +/* + * We never use BQ_LOCKED or BQ_EMPTY, but if you want the 4.X block I/O + * code to drop in, you have to have BQ_AGE and BQ_LRU *after* the first + * queue, and it only costs 6 bytes of data space. + */ +#define BQUEUES 3 /* number of free buffer queues */ + +#define BQ_LOCKED 0 /* super-blocks &c */ +#define BQ_LRU 1 /* lru, useful buffers */ +#define BQ_AGE 2 /* rubbish */ +#define BQ_EMPTY 3 /* buffer headers with no memory */ + +/* Flags to low-level allocation routines. */ +#define B_CLRBUF 0x01 /* Request allocated buffer be cleared. */ +#define B_SYNC 0x02 /* Do all allocations synchronously. */ + +#define bawrite(bp) { (bp)->b_flags |= B_ASYNC; bwrite(bp); } +#define bfree(bp) (bp)->b_bcount = 0 + +#ifdef KERNEL +struct inode; + +#define BUFHSZ 16 /* must be power of 2 */ +#define BUFHASH(dev,bn) ((struct buf*) &bufhash [((dev) + bn) & (BUFHSZ - 1)]) + +extern struct buf buf[]; /* the buffer pool itself */ +extern char bufdata[]; /* core data */ +extern struct bufhd bufhash[]; /* heads of hash lists */ +extern struct buf bfreelist[]; /* heads of available lists */ + +/* + * Assign a buffer for the given block. If the appropriate + */ +struct buf *getblk (dev_t dev, daddr_t blkno); + +/* + * Allocate a block in the file system. + */ +struct buf *balloc (struct inode *ip, int flags); + +/* + * Get an empty block. + */ +struct buf *geteblk (void); + +/* + * Read in (if necessary) the block and return a buffer pointer. + */ +struct buf *bread (dev_t dev, daddr_t blkno); + +/* + * Read in the block, like bread, but also start I/O on the + * read-ahead block. + */ +struct buf *breada (dev_t dev, daddr_t blkno, daddr_t rablkno); + +/* + * Write the buffer, waiting for completion. Then release the buffer. + */ +void bwrite (struct buf *bp); + +/* + * Release the buffer, with delayed write. + */ +void bdwrite (struct buf *bp); + +/* + * Mark I/O complete on a buffer. + */ +void biodone (struct buf *bp); + +/* + * Release the buffer, with no I/O implied. + */ +void brelse (struct buf *bp); + +/* + * Wait for I/O completion on the buffer. + */ +void biowait (struct buf *bp); + +/* + * See if the block is associated with some buffer. + */ +int incore (dev_t dev, daddr_t blkno); + +/* + * Make sure all write-behind blocks on dev are flushed out. + */ +void bflush (dev_t dev); + +/* + * Insure that no part of a specified block is in an incore buffer. + */ +void blkflush (dev_t dev, daddr_t blkno); + +/* + * Invalidate in core blocks belonging to closed or umounted filesystem. + */ +void binval (dev_t dev); + +/* + * Pick up the device's error number and pass it to the user. + */ +int geterror (struct buf *bp); + +#endif /* KERNEL */ + +/* + * These flags are kept in b_flags. + */ +#define B_WRITE 0x00000 /* non-read pseudo-flag */ +#define B_READ 0x00001 /* read when I/O occurs */ +#define B_DONE 0x00002 /* transaction finished */ +#define B_ERROR 0x00004 /* transaction aborted */ +#define B_BUSY 0x00008 /* not on av_forw/back list */ +#define B_PHYS 0x00010 /* physical IO */ +#define B_MAP 0x00020 /* alloc UNIBUS */ +#define B_WANTED 0x00040 /* issue wakeup when BUSY goes off */ +#define B_AGE 0x00080 /* delayed write for correct aging */ +#define B_ASYNC 0x00100 /* don't wait for I/O completion */ +#define B_DELWRI 0x00200 /* write at exit of avail list */ +#define B_TAPE 0x00400 /* this is a magtape (no bdwrite) */ +#define B_INVAL 0x00800 /* does not contain valid info */ +#define B_BAD 0x01000 /* bad block revectoring in progress */ +#define B_LOCKED 0x02000 /* locked in core (not reusable) */ +#define B_UBAREMAP 0x04000 /* addr UNIBUS virtual, not physical */ +#define B_RAMREMAP 0x08000 /* remapped into ramdisk */ + +/* + * Insq/Remq for the buffer hash lists. + */ +#define bremhash(bp) { \ + (bp)->b_back->b_forw = (bp)->b_forw; \ + (bp)->b_forw->b_back = (bp)->b_back; \ +} +#define binshash(bp, dp) { \ + (bp)->b_forw = (dp)->b_forw; \ + (bp)->b_back = (dp); \ + (dp)->b_forw->b_back = (bp); \ + (dp)->b_forw = (bp); \ +} + +/* + * Insq/Remq for the buffer free lists. + */ +#define bremfree(bp) { \ + (bp)->av_back->av_forw = (bp)->av_forw; \ + (bp)->av_forw->av_back = (bp)->av_back; \ +} +#define binsheadfree(bp, dp) { \ + (dp)->av_forw->av_back = (bp); \ + (bp)->av_forw = (dp)->av_forw; \ + (dp)->av_forw = (bp); \ + (bp)->av_back = (dp); \ +} +#define binstailfree(bp, dp) { \ + (dp)->av_back->av_forw = (bp); \ + (bp)->av_back = (dp)->av_back; \ + (dp)->av_back = (bp); \ + (bp)->av_forw = (dp); \ +} + +/* + * Take a buffer off the free list it's on and + * mark it as being use (B_BUSY) by a device. + */ +#define notavail(bp) { \ + register int x = splbio(); \ + bremfree(bp); \ + (bp)->b_flags |= B_BUSY; \ + splx(x); \ +} diff --git a/sys/include/callout.h b/sys/include/callout.h new file mode 100644 index 0000000..a2a0ebb --- /dev/null +++ b/sys/include/callout.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +/* + * The callout structure is for + * a routine arranging + * to be called by the clock interrupt + * (clock.c) with a specified argument, + * in a specified amount of time. + * Used, for example, to time tab + * delays on typewriters. + * + * The c_time field is stored in terms of ticks. Therefore, no callout + * may be scheduled past around 8 minutes on a 60 HZ machine. This is + * good as it avoids long operations on clock ticks. If you are ever + * forced to use a long, you might as well start doing the real-time + * timer as a timeout like 4.3BSD. + */ +struct callout { + int c_time; /* incremental time */ + caddr_t c_arg; /* argument to routine */ + void (*c_func) (caddr_t); /* routine */ + struct callout *c_next; +}; + +#ifdef KERNEL +extern struct callout *callfree, callout[], calltodo; +#endif diff --git a/sys/include/clist.h b/sys/include/clist.h new file mode 100644 index 0000000..ca0dd7b --- /dev/null +++ b/sys/include/clist.h @@ -0,0 +1,17 @@ +/* + * Raw structures for the character list routines. + * + * Copyright (c) 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +struct cblock { + struct cblock *c_next; + char c_info [CBSIZE]; +}; + +#ifdef KERNEL +extern struct cblock cfree[]; +struct cblock *cfreelist; +int cfreecount; +#endif diff --git a/sys/include/conf.h b/sys/include/conf.h new file mode 100644 index 0000000..362cd52 --- /dev/null +++ b/sys/include/conf.h @@ -0,0 +1,69 @@ +#ifndef _CONF_H +#define _CONF_H +/* + * Copyright (c) 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +struct uio; +struct buf; +struct tty; + +struct devspec { + int unit; + char *devname; +}; + +/* + * Declaration of block device + * switch. Each entry (row) is + * the only link between the + * main unix code and the driver. + * The initialization of the + * device switches is in the + * file conf.c. + */ +struct bdevsw +{ + int (*d_open) (dev_t, int, int); + int (*d_close) (dev_t, int, int); + void (*d_strategy) (struct buf*); + void (*d_root) (caddr_t); /* root attach routine */ + daddr_t (*d_psize) (dev_t); /* query partition size */ + int (*d_ioctl) (dev_t, u_int, caddr_t, int); + int d_flags; /* tape flag */ + const struct devspec *devs; +}; + +/* + * Character device switch. + */ +struct cdevsw +{ + int (*d_open) (dev_t, int, int); + int (*d_close) (dev_t, int, int); + int (*d_read) (dev_t, struct uio*, int); + int (*d_write) (dev_t, struct uio*, int); + int (*d_ioctl) (dev_t, u_int, caddr_t, int); + int (*d_stop) (struct tty*, int); + struct tty *d_ttys; + int (*d_select) (dev_t, int); + void (*d_strategy) (struct buf*); + char (*r_read) (dev_t); + void (*r_write) (dev_t, char); + const struct devspec *devs; +}; + +#ifdef KERNEL +extern const struct bdevsw bdevsw[]; +extern const struct cdevsw cdevsw[]; + +extern int nulldev(); +extern int norw(dev_t dev, struct uio *uio, int flag); +extern int noioctl(dev_t dev, u_int cmd, caddr_t data, int flag); +extern void noroot(caddr_t csr); + +int rawrw (dev_t dev, struct uio *uio, int flag); +#endif + +#endif diff --git a/sys/include/debug.h b/sys/include/debug.h new file mode 100644 index 0000000..bcc89b4 --- /dev/null +++ b/sys/include/debug.h @@ -0,0 +1,84 @@ +#ifndef _DEBUG_H +#define _DEBUG_H + +#define DEBUG(...) +#define DEBUG1(...) +#define DEBUG2(...) +#define DEBUG3(...) +#define DEBUG4(...) +#define DEBUG5(...) +#define DEBUG6(...) +#define DEBUG7(...) +#define DEBUG8(...) +#define DEBUG9(...) + +#ifdef GLOBAL_DEBUG +#undef DEBUG +#define DEBUG(...) printf(__VA_ARGS__) + +#if (GLOBAL_DEBUG>=1) +#undef DEBUG1 +#define DEBUG1(...) printf(__VA_ARGS__) +#endif + +#if (GLOBAL_DEBUG>=2) +#undef DEBUG2 +#define DEBUG2(...) printf(__VA_ARGS__) +#endif + +#if (GLOBAL_DEBUG>=3) +#undef DEBUG3 +#define DEBUG3(...) printf(__VA_ARGS__) +#endif + +#if (GLOBAL_DEBUG>=4) +#undef DEBUG4 +#define DEBUG4(...) printf(__VA_ARGS__) +#endif + +#if (GLOBAL_DEBUG>=5) +#undef DEBUG5 +#define DEBUG5(...) printf(__VA_ARGS__) +#endif + +#if (GLOBAL_DEBUG>=6) +#undef DEBUG6 +#define DEBUG6(...) printf(__VA_ARGS__) +#endif + +#if (GLOBAL_DEBUG>=7) +#undef DEBUG7 +#define DEBUG7(...) printf(__VA_ARGS__) +#endif + +#if (GLOBAL_DEBUG>=8) +#undef DEBUG8 +#define DEBUG8(...) printf(__VA_ARGS__) +#endif + +#if (GLOBAL_DEBUG>=9) +#undef DEBUG9 +#define DEBUG9(...) printf(__VA_ARGS__) +#endif + +#endif + +#define SETVAL(X) \ + TRISECLR = 0b0000000011111111; \ + LATECLR = 0b0000000011111111; \ + LATESET = (X & 0xFF) +/* + TRISFCLR = 0b0000000000110000; \ + LATFCLR = 0b0000000000110000; \ + TRISBCLR = 0b1111111000000000; \ + LATBCLR = 0b1111111000000000; \ + LATBCLR = 0b0000001000000000; \ + LATFSET = ((X & 0x01) << 5) | ((X & 0x02) << 3); \ + LATBSET = ((X & 0x04) << 13) | ((X & 0x08) << 11) | ((X & 0x10) << 9) | ((X & 0x20) << 7) | ((X & 0x40) << 5) | ((X & 0x80) << 3); \ + LATBSET = 0b0000001000000000; +*/ + +#define LED_ON(X,Y) TRIS_CLR(X) = 1<<(Y); LAT_SET(X) = 1<<(Y); +#define LED_OFF(X,Y) TRIS_CLR(X) = 1<<(Y); LAT_CLR(X) = 1<<(Y); + +#endif diff --git a/sys/include/dir.h b/sys/include/dir.h new file mode 100644 index 0000000..b645a7e --- /dev/null +++ b/sys/include/dir.h @@ -0,0 +1,105 @@ +/* + * Copyright (c) 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#ifndef _DIR_ +#define _DIR_ + +#ifndef MAXNAMLEN +#define MAXNAMLEN 63 +#endif + +#define DIRBLKSIZ 1024 + +/* + * inode numbers are ino_t rather than u_long now. before, when v7direct + * was used for the kernel, inode numbers were u_short/ino_t anyways, and since + * everything had to be recompiled when the fs structure was changed it seemed + * like a good idea to change the "real direct structure". SMS +*/ + +struct direct { + ino_t d_ino; /* inode number of entry */ + u_short d_reclen; /* length of this record */ + u_short d_namlen; /* length of string in d_name */ + char d_name[MAXNAMLEN+1]; /* name must be no longer than this */ +}; + +/* + * A directory consists of some number of blocks of DIRBLKSIZ + * bytes, where DIRBLKSIZ is chosen such that it can be transferred + * to disk in a single atomic operation (e.g. 512 bytes on most machines). + * + * Each DIRBLKSIZ byte block contains some number of directory entry + * structures, which are of variable length. Each directory entry has + * a struct direct at the front of it, containing its inode number, + * the length of the entry, and the length of the name contained in + * the entry. These are followed by the name padded to a 4 byte boundary + * with null bytes. All names are guaranteed null terminated. + * The maximum length of a name in a directory is MAXNAMLEN. + * + * The macro DIRSIZ(dp) gives the amount of space required to represent + * a directory entry. Free space in a directory is represented by + * entries which have dp->d_reclen > DIRSIZ(dp). All DIRBLKSIZ bytes + * in a directory block are claimed by the directory entries. This + * usually results in the last entry in a directory having a large + * dp->d_reclen. When entries are deleted from a directory, the + * space is returned to the previous entry in the same directory + * block by increasing its dp->d_reclen. If the first entry of + * a directory block is free, then its dp->d_ino is set to 0. + * Entries other than the first in a directory do not normally have + * dp->d_ino set to 0. + */ + +#undef DIRSIZ +#define DIRSIZ(dp) \ + ((((sizeof (struct direct) - (MAXNAMLEN+1)) + (dp)->d_namlen+1) + 3) &~ 3) + +/* + * Definitions for library routines operating on directories. + */ +typedef struct _dirdesc { + int dd_fd; + long dd_loc; + long dd_size; + char dd_buf[DIRBLKSIZ]; + struct direct dd_cur; +} DIR; + +#ifndef NULL +#define NULL 0 +#endif + +#ifndef KERNEL + +extern DIR *opendir (const char *); +extern struct direct *readdir (DIR *); +extern long telldir (DIR *); +extern void seekdir (DIR *, long); +extern void closedir (DIR *); + +#define rewinddir(dirp) seekdir ((dirp), (long)0) +#define dirfd(dirp) ((dirp)->dd_fd) + +#endif /* !KERNEL */ + +/* + * Template for manipulating directories. + * Should use struct direct's, but the name field + * is MAXNAMLEN - 1, and this just won't do. + */ +#define dotdot_ino dtdt_ino +#define dotdot_reclen dtdt_rec +#define dotdot_name dtdt_name +struct dirtemplate { + ino_t dot_ino; + u_short dot_reclen; + u_short dot_namlen; + char dot_name[4]; /* must be multiple of 4 */ + ino_t dotdot_ino; + u_short dotdot_reclen; + u_short dotdot_namlen; + char dotdot_name[4]; /* ditto */ +}; +#endif /* _DIR_ */ diff --git a/sys/include/disk.h b/sys/include/disk.h new file mode 100644 index 0000000..d96a9ab --- /dev/null +++ b/sys/include/disk.h @@ -0,0 +1,113 @@ +/* + * 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. + * + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, 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 _SYS_DISK_H_ +#define _SYS_DISK_H_ +#include + +/* + * Disk device structures. + * + * Note that this is only a preliminary outline. The final disk structures + * may be somewhat different. + * + * Note: the 2.11BSD version is very different. The 4.4 version served + * as the inspiration. I needed something similar but for slightly + * different purposes. + */ + +/* + * Disk device structures. Rather than replicate driver specific variations + * of the following in each driver it was made common here. + * + * Some of the flags are specific to various drivers. For example ALIVE and + * ONLINE apply to MSCP devices more than to SMD devices while the SEEK flag + * applies to the SMD (xp) driver but not to the MSCP driver. The rest + * of the flags as well as the open partition bitmaps are usable by any disk + * driver. One 'dkdevice' structure is needed for each disk drive supported + * by a driver. + * + * The entire disklabel is not resident in the kernel address space. Only + * the partition table is directly accessible by the kernel. The MSCP driver + * does not care (or know) about the geometry of the disk. Not holding + * the entire label in the kernel saved quite a bit of D space. Other drivers + * which need geometry information from the label will have to map in the + * label and copy out the geometry data they require. This is unlikely to + * cause much overhead since labels are read and written infrequently - when + * mounting a drive, assigning a label, running newfs, etc. + */ + +struct dkdevice { + int dk_bopenmask; /* block devices open */ + int dk_copenmask; /* character devices open */ + int dk_openmask; /* composite (bopen|copen) */ + int dk_flags; /* label state see below */ + size_t dk_label; /* sector containing label */ + struct partition dk_parts[MAXPARTITIONS]; /* inkernel portion */ +}; + +#define DKF_OPENING 0x0001 /* drive is being opened */ +#define DKF_CLOSING 0x0002 /* drive is being closed */ +#define DKF_WANTED 0x0004 /* drive is being waited for */ +#define DKF_ALIVE 0x0008 /* drive is alive */ +#define DKF_ONLINE 0x0010 /* drive is online */ +#define DKF_WLABEL 0x0020 /* label area is being written */ +#define DKF_SEEK 0x0040 /* drive is seeking */ +#define DKF_SWAIT 0x0080 /* waiting for seek to complete */ + +/* encoding of disk minor numbers, should be elsewhere... but better + * here than in ufs_disksubr.c + * + * Note: the controller number in bits 6 and 7 of the minor device are NOT + * removed. It is the responsibility of the driver to extract or mask + * these bits. +*/ + +#define dkunit(dev) (minor(dev) >> 3) +#define dkpart(dev) (minor(dev) & 07) +#define dkminor(unit, part) (((unit) << 3) | (part)) + +#ifdef KERNEL +//char *readdisklabel(); +//int setdisklabel(); +//int writedisklabel(); +#endif +#endif /* _SYS_DISK_H_ */ diff --git a/sys/include/dk.h b/sys/include/dk.h new file mode 100644 index 0000000..ec6723d --- /dev/null +++ b/sys/include/dk.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 1982, 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +/* + * Instrumentation + */ +#define CPUSTATES 4 + +#define CP_USER 0 +#define CP_NICE 1 +#define CP_SYS 2 +#define CP_IDLE 3 + +#define DK_NDRIVE 4 + +#if defined(KERNEL) && defined(UCB_METER) +long cp_time[CPUSTATES]; /* number of ticks spent in each cpu state */ +int dk_ndrive; /* number of drives being monitored */ +int dk_busy; /* bit array of drive busy flags */ +long dk_xfer[DK_NDRIVE]; /* number of transfers */ +long dk_bytes[DK_NDRIVE]; /* number of bytes transfered */ +char *dk_name[DK_NDRIVE]; /* names of monitored drives */ +int dk_unit[DK_NDRIVE]; /* unit numbers of monitored drives */ +int dk_n; /* number of dk numbers assigned so far */ + +long tk_nin; /* number of tty characters input */ +long tk_nout; /* number of tty characters output */ +#endif diff --git a/sys/include/dkbad.h b/sys/include/dkbad.h new file mode 100644 index 0000000..0707260 --- /dev/null +++ b/sys/include/dkbad.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + * + * @(#)dkbad.h 1.1 (2.10BSD Berkeley) 12/1/86 + */ + +/* + * Definitions needed to perform bad sector + * revectoring ala DEC STD 144. + * + * The bad sector information is located in the + * first 5 even numbered sectors of the last + * track of the disk pack. There are five + * identical copies of the information, described + * by the dkbad structure. + * + * Replacement sectors are allocated starting with + * the first sector before the bad sector information + * and working backwards towards the beginning of + * the disk. A maximum of 126 bad sectors are supported. + * The position of the bad sector in the bad sector table + * determines which replacement sector it corresponds to. + * + * The bad sector information and replacement sectors + * are conventionally only accessible through the + * 'c' file system partition of the disk. If that + * partition is used for a file system, the user is + * responsible for making sure that it does not overlap + * the bad sector information or any replacement sector.s + */ + +/* + * The 2.10BSD system defines MAXBAD as 32, not 126, although there + * should be no problem with increasing that value. It's your basic + * space tradeoff. Also, 2.10 drivers tend to have the bad sector + * information available through the 'h' file system partition, although + * there are exceptions to this rule. Note, this value is also present + * in the bad144 program. + */ +#define MAXBAD 32 /* Maximum bad sectors supported */ + +struct dkbad { + long bt_csn; /* cartridge serial number */ + u_short bt_mbz; /* unused; should be 0 */ + u_short bt_flag; /* -1 => alignment cartridge */ + struct bt_bad { + u_short bt_cyl; /* cylinder number of bad sector */ + u_short bt_trksec; /* track and sector number */ + } bt_bad[MAXBAD]; +}; + +#define ECC 0 +#define SSE 1 +#define BSE 2 +#define CONT 3 diff --git a/sys/include/errno.h b/sys/include/errno.h new file mode 100644 index 0000000..0f8c998 --- /dev/null +++ b/sys/include/errno.h @@ -0,0 +1,121 @@ +/* + * Copyright (c) 1982, 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + * + * @(#)errno.h 7.1.3 (2.11BSD) 1999/9/6 + */ + +#ifndef KERNEL +extern int errno; /* global error number */ +#endif + +#define EPERM 1 /* Not owner */ +#define ENOENT 2 /* No such file or directory */ +#define ESRCH 3 /* No such process */ +#define EINTR 4 /* Interrupted system call */ +#define EIO 5 /* I/O error */ +#define ENXIO 6 /* No such device or address */ +#define E2BIG 7 /* Arg list too long */ +#define ENOEXEC 8 /* Exec format error */ +#define EBADF 9 /* Bad file number */ +#define ECHILD 10 /* No children */ +#define EAGAIN 11 /* No more processes */ +#define ENOMEM 12 /* Not enough core */ +#define EACCES 13 /* Permission denied */ +#define EFAULT 14 /* Bad address */ +#define ENOTBLK 15 /* Block device required */ +#define EBUSY 16 /* Mount device busy */ +#define EEXIST 17 /* File exists */ +#define EXDEV 18 /* Cross-device link */ +#define ENODEV 19 /* No such device */ +#define ENOTDIR 20 /* Not a directory*/ +#define EISDIR 21 /* Is a directory */ +#define EINVAL 22 /* Invalid argument */ +#define ENFILE 23 /* File table overflow */ +#define EMFILE 24 /* Too many open files */ +#define ENOTTY 25 /* Not a typewriter */ +#define ETXTBSY 26 /* Text file busy */ +#define EFBIG 27 /* File too large */ +#define ENOSPC 28 /* No space left on device */ +#define ESPIPE 29 /* Illegal seek */ +#define EROFS 30 /* Read-only file system */ +#define EMLINK 31 /* Too many links */ +#define EPIPE 32 /* Broken pipe */ + +/* math software */ +#define EDOM 33 /* Argument too large */ +#define ERANGE 34 /* Result too large */ + +/* non-blocking and interrupt i/o */ +#define EWOULDBLOCK 35 /* Operation would block */ +#define EDEADLK EWOULDBLOCK /* ditto */ +#define EINPROGRESS 36 /* Operation now in progress */ +#define EALREADY 37 /* Operation already in progress */ + +/* ipc/network software */ + + /* argument errors */ +#define ENOTSOCK 38 /* Socket operation on non-socket */ +#define EDESTADDRREQ 39 /* Destination address required */ +#define EMSGSIZE 40 /* Message too long */ +#define EPROTOTYPE 41 /* Protocol wrong type for socket */ +#define ENOPROTOOPT 42 /* Protocol not available */ +#define EPROTONOSUPPORT 43 /* Protocol not supported */ +#define ESOCKTNOSUPPORT 44 /* Socket type not supported */ +#define EOPNOTSUPP 45 /* Operation not supported on socket */ +#define EPFNOSUPPORT 46 /* Protocol family not supported */ +#define EAFNOSUPPORT 47 /* Address family not supported by protocol family */ +#define EADDRINUSE 48 /* Address already in use */ +#define EADDRNOTAVAIL 49 /* Can't assign requested address */ + + /* operational errors */ +#define ENETDOWN 50 /* Network is down */ +#define ENETUNREACH 51 /* Network is unreachable */ +#define ENETRESET 52 /* Network dropped connection on reset */ +#define ECONNABORTED 53 /* Software caused connection abort */ +#define ECONNRESET 54 /* Connection reset by peer */ +#define ENOBUFS 55 /* No buffer space available */ +#define EISCONN 56 /* Socket is already connected */ +#define ENOTCONN 57 /* Socket is not connected */ +#define ESHUTDOWN 58 /* Can't send after socket shutdown */ +#define ETOOMANYREFS 59 /* Too many references: can't splice */ +#define ETIMEDOUT 60 /* Connection timed out */ +#define ECONNREFUSED 61 /* Connection refused */ + + /* */ +#define ELOOP 62 /* Too many levels of symbolic links */ +#define ENAMETOOLONG 63 /* File name too long */ + +/* should be rearranged */ +#define EHOSTDOWN 64 /* Host is down */ +#define EHOSTUNREACH 65 /* No route to host */ +#define ENOTEMPTY 66 /* Directory not empty */ + +/* quotas & mush */ +#define EPROCLIM 67 /* Too many processes */ +#define EUSERS 68 /* Too many users */ +#define EDQUOT 69 /* Disc quota exceeded */ + +/* Network File System */ +#define ESTALE 70 /* Stale NFS file handle */ +#define EREMOTE 71 /* Too many levels of remote in path */ +#define EBADRPC 72 /* RPC struct is bad */ +#define ERPCMISMATCH 73 /* RPC version wrong */ +#define EPROGUNAVAIL 74 /* RPC prog. not avail */ +#define EPROGMISMATCH 75 /* Program version wrong */ +#define EPROCUNAVAIL 76 /* Bad procedure for program */ + +#define ENOLCK 77 /* No locks available */ +#define ENOSYS 78 /* Function not implemented */ + +#define EFTYPE 79 /* Inappropriate file type or format */ +#define EAUTH 80 /* Authentication error */ +#define ENEEDAUTH 81 /* Need authenticator */ +#define ELAST 81 /* Must be equal largest errno */ + +#ifdef KERNEL +/* pseudo-errors returned inside kernel to modify return back to user mode */ +#define ERESTART -1 /* restart syscall */ +#define EJUSTRETURN -2 /* don't modify regs, just return */ +#endif diff --git a/sys/include/exec.h b/sys/include/exec.h new file mode 100644 index 0000000..1d11579 --- /dev/null +++ b/sys/include/exec.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +#ifndef _EXEC_ +#define _EXEC_ +/* + * Header prepended to each a.out file. + */ +struct exec { + int a_magic; /* magic number */ +unsigned int a_text; /* size of text segment */ +unsigned int a_data; /* size of initialized data */ +unsigned int a_bss; /* size of uninitialized data */ +unsigned int a_reltext; /* size of text relocation info */ +unsigned int a_reldata; /* size of data relocation info */ +unsigned int a_syms; /* size of symbol table */ +unsigned int a_entry; /* entry point */ +}; + +/* a_magic */ +#define RMAGIC 0406 /* relocatable object file */ +#define OMAGIC 0407 /* old impure format */ +#define NMAGIC 0410 /* read-only text */ + +#endif diff --git a/sys/include/fcntl.h b/sys/include/fcntl.h new file mode 100644 index 0000000..b66ec7c --- /dev/null +++ b/sys/include/fcntl.h @@ -0,0 +1,149 @@ +/*- + * Copyright (c) 1983, 1990, 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. + * + * @(#)fcntl.h 8.3.1 (2.11BSD GTE) 11/25/94 + * + * Copied from 4.4-Lite and modified for 2.11BSD. The modifications consisted + * of removing: function prototypes (I don't like them, the compiler does not + * support them, and it would mean dragging in cdefs.h to leave them in here), + * #ifndef _POSIX_SOURCE lines (silly) and record locking related definitions + * If anyone adds any of the above it will be easy enough to modify this file. + * In the meantime why bog down (or blow up) cpp any further? + */ + +#ifndef _FCNTL_H_ +#define _FCNTL_H_ + +/* + * This file includes the definitions for open and fcntl + * described by POSIX for ; it also includes + * related kernel definitions. + */ + +#ifndef KERNEL +#include +#endif + +/* + * File status flags: these are used by open(2), fcntl(2). + * They are also used (indirectly) in the kernel file structure f_flags, + * which is a superset of the open/fcntl flags. Open flags and f_flags + * are inter-convertible using OFLAGS(fflags) and FFLAGS(oflags). + * Open/fcntl flags begin with O_; kernel-internal flags begin with F. + */ +/* open-only flags */ +#define O_RDONLY 0x0000 /* open for reading only */ +#define O_WRONLY 0x0001 /* open for writing only */ +#define O_RDWR 0x0002 /* open for reading and writing */ +#define O_ACCMODE 0x0003 /* mask for above modes */ + +/* + * Kernel encoding of open mode; separate read and write bits that are + * independently testable: 1 greater than the above. + * + * XXX + * FREAD and FWRITE are excluded from the #ifdef KERNEL so that TIOCFLUSH, + * which was documented to use FREAD/FWRITE, continues to work. + */ +#define FREAD 0x0001 +#define FWRITE 0x0002 +#define O_NONBLOCK 0x0004 /* no delay */ +#define O_APPEND 0x0008 /* set append mode */ +#define O_SHLOCK 0x0010 /* open with shared file lock */ +#define O_EXLOCK 0x0020 /* open with exclusive file lock */ +#define O_ASYNC 0x0040 /* signal pgrp when data ready */ +#define O_FSYNC 0x0080 /* synchronous writes */ +#define O_CREAT 0x0200 /* create if nonexistant */ +#define O_TRUNC 0x0400 /* truncate to zero length */ +#define O_EXCL 0x0800 /* error if already exists */ +#ifdef KERNEL +#define FMARK 0x1000 /* mark during gc() */ +#define FDEFER 0x2000 /* defer for next gc pass */ +#endif + +/* defined by POSIX 1003.1; not 2.11BSD default, so bit is required */ +/* Not currently implemented but it may be placed on the TODO list shortly */ +#define O_NOCTTY 0x4000 /* don't assign controlling terminal */ + +#ifdef KERNEL +/* convert from open() flags to/from fflags; convert O_RD/WR to FREAD/FWRITE */ +#define FFLAGS(oflags) ((oflags) + 1) +#define OFLAGS(fflags) ((fflags) - 1) + +/* bits to save after open */ +#define FMASK (FREAD|FWRITE|FAPPEND|FASYNC|FFSYNC|FNONBLOCK) +/* bits settable by fcntl(F_SETFL, ...) */ +#define FCNTLFLAGS (FAPPEND|FASYNC|FFSYNC|FNONBLOCK) +#endif + +/* + * The O_* flags used to have only F* names, which were used in the kernel + * and by fcntl. We retain the F* names for the kernel f_flags field + * and for backward compatibility for fcntl. + */ +#define FAPPEND O_APPEND /* kernel/compat */ +#define FASYNC O_ASYNC /* kernel/compat */ +#define FFSYNC O_FSYNC /* kernel */ +#define FEXLOCK O_EXLOCK /* kernel */ +#define FSHLOCK O_SHLOCK /* kernel */ +#define FNONBLOCK O_NONBLOCK /* kernel */ +#define FNDELAY O_NONBLOCK /* compat */ +#define O_NDELAY O_NONBLOCK /* compat */ + +/* + * Constants used for fcntl(2) + */ + +/* command values */ +#define F_DUPFD 0 /* duplicate file descriptor */ +#define F_GETFD 1 /* get file descriptor flags */ +#define F_SETFD 2 /* set file descriptor flags */ +#define F_GETFL 3 /* get file status flags */ +#define F_SETFL 4 /* set file status flags */ +#define F_GETOWN 5 /* get SIGIO/SIGURG proc/pgrp */ +#define F_SETOWN 6 /* set SIGIO/SIGURG proc/pgrp */ + +/* file descriptor flags (F_GETFD, F_SETFD) */ +#define FD_CLOEXEC 1 /* close-on-exec flag */ + +/* lock operations for flock(2) */ +#define LOCK_SH 0x01 /* shared file lock */ +#define LOCK_EX 0x02 /* exclusive file lock */ +#define LOCK_NB 0x04 /* don't block when locking */ +#define LOCK_UN 0x08 /* unlock file */ + +#endif /* !_FCNTL_H_ */ diff --git a/sys/include/file.h b/sys/include/file.h new file mode 100644 index 0000000..faaf052 --- /dev/null +++ b/sys/include/file.h @@ -0,0 +1,120 @@ +/* + * Copyright (c) 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include + +#ifndef _SYS_FILE_H_ +#define _SYS_FILE_H_ + +/* + * Descriptor table entry. + * One for each kernel object. + */ +struct file { + int f_flag; /* see below */ + int f_type; /* descriptor type */ + u_int f_count; /* reference count */ + int f_msgcount; /* references from message queue */ + union { + caddr_t f_Data; + struct socket *f_Socket; + } f_un; + off_t f_offset; +}; + +#ifdef KERNEL +struct uio; + +struct fileops { + int (*fo_rw) (struct file *fp, struct uio *uio); + int (*fo_ioctl) (struct file *fp, u_int com, char *data); + int (*fo_select) (struct file *fp, int flag); + int (*fo_close) (struct file *fp); +}; + +#define f_data f_un.f_Data +#define f_socket f_un.f_Socket + +extern struct file file[]; +extern const struct fileops *const Fops[]; +extern const struct fileops inodeops; +extern const struct fileops pipeops; + +/* + * Convert a user supplied file descriptor into a pointer to a file structure. + */ +struct file *getf (int f); + +/* + * Allocate a user file descriptor and a file structure. + */ +struct file *falloc (void); + +/* + * Internal form of close. + */ +int closef (struct file *fp); + +/* + * Set/clear file flags: nonblock and async. + */ +int fset (struct file *fp, int bit, int value); + +/* + * Get/set process group id for a file. + */ +int fgetown (struct file *fp, int *valuep); +int fsetown (struct file *fp, int value); + +/* + * File table inode close routine. + */ +int vn_closefile (struct file *fp); + +/* + * Place an advisory lock on an inode. + */ +int ino_lock (struct file *fp, int cmd); + +/* + * Unlock a file. + */ +void ino_unlock (struct file *fp, int kind); + +int ino_ioctl (struct file *fp, u_int com, caddr_t data); + +#else /* KERNEL */ + +int flock(int fd, int operation); + +#endif /* KERNEL */ + +/* + * Access call. + */ +#define F_OK 0 /* does file exist */ +#define X_OK 1 /* is it executable by caller */ +#define W_OK 2 /* writable by caller */ +#define R_OK 4 /* readable by caller */ + +/* + * Lseek call. + */ +#define L_SET 0 /* absolute offset */ +#define L_INCR 1 /* relative to current offset */ +#define L_XTND 2 /* relative to end of file */ + +#ifdef KERNEL +#define GETF(fp, fd) { \ + if ((unsigned)(fd) >= NOFILE || ((fp) = u.u_ofile[fd]) == NULL) { \ + u.u_error = EBADF; \ + return; \ + } \ +} +#define DTYPE_INODE 1 /* file */ +#define DTYPE_SOCKET 2 /* communications endpoint */ +#define DTYPE_PIPE 3 /* I don't want to hear it, okay? */ +#endif +#endif /* _SYS_FILE_H_ */ diff --git a/sys/include/fs.h b/sys/include/fs.h new file mode 100644 index 0000000..d634cbf --- /dev/null +++ b/sys/include/fs.h @@ -0,0 +1,163 @@ +/* + * Copyright (c) 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#ifndef _SYS_FS_H_ +#define _SYS_FS_H_ + +/* + * The root inode is the root of the file system. + * Inode 0 can't be used for normal purposes and + * historically bad blocks were linked to inode 1, + * thus the root inode is 2. (inode 1 is no longer used for + * this purpose, however numerous dump tapes make this + * assumption, so we are stuck with it) + * The lost+found directory is given the next available + * inode when it is created by ``mkfs''. + */ +#define SBSIZE DEV_BSIZE +#define SUPERB ((daddr_t)0) /* block number of the super block */ + +#define ROOTINO ((ino_t)2) /* i number of all roots */ +#define LOSTFOUNDINO (ROOTINO + 1) + +#define NICINOD 32 /* number of superblock inodes */ +#define NICFREE 200 /* number of superblock free blocks */ + +/* + * The path name on which the file system is mounted is maintained + * in fs_fsmnt. MAXMNTLEN defines the amount of space allocated in + * the super block for this name. + */ +#define MAXMNTLEN 28 + +/* + * Super block for a file system. NOTE: The 'fs_flock' and 'fs_ilock' + * fields MUST be on an even byte boundary because they are used as sleep() + * channels and odd values specify a network sleep(). + */ +struct fs +{ + u_int fs_magic1; /* magic word */ + u_int fs_isize; /* first block after i-list */ + u_int fs_fsize; /* size in blocks of entire volume */ + u_int fs_swapsz; /* size in blocks of swap area */ + int fs_nfree; /* number of addresses in fs_free */ + daddr_t fs_free [NICFREE]; /* free block list */ + int fs_ninode; /* number of inodes in fs_inode */ + ino_t fs_inode [NICINOD]; /* free inode list */ + int fs_flock; /* lock during free list manipulation */ + int fs_fmod; /* super block modified flag */ + int fs_ilock; /* lock during i-list manipulation */ + int fs_ronly; /* mounted read-only flag */ + time_t fs_time; /* last super block update */ + u_int fs_tfree; /* total free blocks */ + ino_t fs_tinode; /* total free inodes */ + char fs_fsmnt [MAXMNTLEN]; /* ordinary file mounted on */ + ino_t fs_lasti; /* start place for circular search */ + ino_t fs_nbehind; /* est # free inodes before s_lasti */ + u_int fs_flags; /* mount time flags */ + u_int fs_magic2; /* magic word */ +/* actually longer */ +}; + +struct fblk { + int df_nfree; /* number of addresses in df_free */ + daddr_t df_free [NICFREE]; /* free block list */ +}; + +#define FSMAGIC1 ('F' | 'S'<<8 | '<'<<16 | '<'<<24) +#define FSMAGIC2 ('>' | '>'<<8 | 'F'<<16 | 'S'<<24) + +/* + * Turn file system block numbers into disk block addresses. + * This maps file system blocks to device size blocks. + */ +#define fsbtodb(b) ((daddr_t) (b)) +#define dbtofsb(b) ((daddr_t) (b)) + +/* + * Macros for handling inode numbers: + * inode number to file system block offset. + * inode number to file system block address. + */ +#define itoo(x) ((int)(((x) + INOPB - 1) % INOPB)) +#define itod(x) ((daddr_t)((((u_int)(x) + INOPB - 1) / INOPB))) + +/* + * The following macros optimize certain frequently calculated + * quantities by using shifts and masks in place of divisions + * modulos and multiplications. + */ +#define blkoff(loc) /* calculates (loc % fs->fs_bsize) */ \ + ((loc) & DEV_BMASK) +#define lblkno(loc) /* calculates (loc / fs->fs_bsize) */ \ + ((unsigned) (loc) >> DEV_BSHIFT) + +/* + * Determine the number of available blocks given a + * percentage to hold in reserve + */ +#define freespace(fs, percentreserved) \ + ((fs)->fs_tfree - ((fs)->fs_fsize - \ + (fs)->fs_isize) * (percentreserved) / 100) + +/* + * INOPB is the number of inodes in a secondary storage block. + */ +#define INOPB 16 /* MAXBSIZE / sizeof(dinode) */ + +/* + * NINDIR is the number of indirects in a file system block. + */ +#define NINDIR (DEV_BSIZE / sizeof(daddr_t)) +#define NSHIFT 8 /* log2(NINDIR) */ +#define NMASK 0377L /* NINDIR - 1 */ + +/* + * We continue to implement pipes within the file system because it would + * be pretty tough for us to handle 10 4K blocked pipes on a 1M machine. + * + * 4K is the allowable buffering per write on a pipe. This is also roughly + * the max size of the file created to implement the pipe. If this size is + * bigger than 4096, pipes will be implemented with large files, which is + * probably not good. + */ +#define MAXPIPSIZ (NDADDR * MAXBSIZE) + +#ifdef KERNEL +struct inode; + +/* + * Map a device number into a pointer to the incore super block. + */ +struct fs *getfs (dev_t dev); + +/* + * Mount a filesystem on the given directory inode. + */ +struct fs *mountfs (dev_t dev, int flags, struct inode *ip); + +void mount_updname (struct fs *fs, char *on, char *from, + int lenon, int lenfrom); + +/* + * Sync a single filesystem. + */ +struct mount; +int ufs_sync (struct mount *mp); + +/* + * Check that a specified block number is in range. + */ +int badblock (struct fs *fp, daddr_t bn); + +/* + * Print the name of a file system with an error diagnostic. + */ +void fserr (struct fs *fp, char *message); + +#endif /* KERNEL */ + +#endif /* _SYS_FS_H_ */ diff --git a/sys/include/glcd.h b/sys/include/glcd.h new file mode 100644 index 0000000..7721d3c --- /dev/null +++ b/sys/include/glcd.h @@ -0,0 +1,149 @@ +#ifndef _GLCD_H +#define _GLCD_H + +#include +#include + +//G13 +#define TRIS_DI TRISG +#define LAT_DI LATG +#define PORT_DI PORTG +#define PIN_DI 13 + +//G12 +#define TRIS_RW TRISG +#define LAT_RW LATG +#define PORT_RW PORTG +#define PIN_RW 12 + +//G14 +#define TRIS_E TRISG +#define LAT_E LATG +#define PORT_E PORTG +#define PIN_E 14 + +//E1 +#define TRIS_DB0 TRISE +#define LAT_DB0 LATE +#define PORT_DB0 PORTE +#define PIN_DB0 1 + +//E0 +#define TRIS_DB1 TRISE +#define LAT_DB1 LATE +#define PORT_DB1 PORTE +#define PIN_DB1 0 + +//A7 +#define TRIS_DB2 TRISA +#define LAT_DB2 LATA +#define PORT_DB2 PORTA +#define PIN_DB2 7 + +//A6 +#define TRIS_DB3 TRISA +#define LAT_DB3 LATA +#define PORT_DB3 PORTA +#define PIN_DB3 6 + +//G0 +#define TRIS_DB4 TRISG +#define LAT_DB4 LATG +#define PORT_DB4 PORTG +#define PIN_DB4 0 + +//G1 +#define TRIS_DB5 TRISG +#define LAT_DB5 LATG +#define PORT_DB5 PORTG +#define PIN_DB5 1 + +//F1 +#define TRIS_DB6 TRISF +#define LAT_DB6 LATF +#define PORT_DB6 PORTF +#define PIN_DB6 1 + +//F0 +#define TRIS_DB7 TRISF +#define LAT_DB7 LATF +#define PORT_DB7 PORTF +#define PIN_DB7 0 + +//D7 +#define TRIS_CS1 TRISD +#define LAT_CS1 LATD +#define PORT_CS1 PORTD +#define PIN_CS1 7 + +//D6 +#define TRIS_CS2 TRISD +#define LAT_CS2 LATD +#define PORT_CS2 PORTD +#define PIN_CS2 6 + +//D5 +#define TRIS_RES TRISD +#define LAT_RES LATD +#define PORT_RES PORTD +#define PIN_RES 5 + +#define GLCD_CMD_OFF 0b00111110 +#define GLCD_CMD_ON 0b00111111 +#define GLCD_CMD_SET_Y 0b01000000 +#define GLCD_CMD_SET_PAGE 0b10111000 +#define GLCD_CMD_START 0b11000000 + +#define INPUT 1 +#define OUTPUT 0 + +#define HIGH 1 +#define LOW 0 + +#define DATA 1 +#define INSTRUCTION 0 + +#define READ 1 +#define WRITE 0 + +#define ENABLE 1 +#define DISABLE 0 + +#define GLCD_STAT_BUSY 0b10000000 +#define GLCD_STAT_ONOFF 0b00100000 +#define GLCD_STAT_RESET 0b00010000 + +/* glcd interface */ + +struct glcd_command { + unsigned char x1; + unsigned char y1; + unsigned char x2; + unsigned char y2; + unsigned char ink; +}; + +#define GLCD_RESET _IOW('i', 1, struct glcd_command) +#define GLCD_CLS _IOW('i', 2, struct glcd_command) +#define GLCD_LOAD_PAGE _IOW('i', 3, struct glcd_command) +#define GLCD_UPDATE _IOW('i', 4, struct glcd_command) +#define GLCD_SET_PIXEL _IOW('i', 5, struct glcd_command) +#define GLCD_CLEAR_PIXEL _IOW('i', 6, struct glcd_command) +#define GLCD_LINE _IOW('i', 7, struct glcd_command) +#define GLCD_BOX _IOW('i', 8, struct glcd_command) +#define GLCD_FILLED_BOX _IOW('i', 9, struct glcd_command) +#define GLCD_GOTO_XY _IOW('i', 10, struct glcd_command) + +#ifdef KERNEL +#include "conf.h" + +extern const struct devspec glcddevs[]; + +extern int glcd_open (dev_t dev, int flag, int mode); +extern int glcd_close (dev_t dev, int flag, int mode); +extern int glcd_read (dev_t dev, struct uio *uio, int flag); +extern int glcd_write (dev_t dev, struct uio *uio, int flag); +extern int glcd_ioctl (dev_t dev, u_int cmd, caddr_t addr, int flag); +#endif + +#endif diff --git a/sys/include/glob.h b/sys/include/glob.h new file mode 100644 index 0000000..1c72cfe --- /dev/null +++ b/sys/include/glob.h @@ -0,0 +1,12 @@ +#ifndef _GLOB_H +#define _GLOB_H + +#ifdef KERNEL +extern void rdglob(); +extern void wrglob(); +#else +extern int rdglob(int); +extern int wrglob(int,int); +#endif + +#endif diff --git a/sys/include/gpio.h b/sys/include/gpio.h new file mode 100644 index 0000000..af3e83a --- /dev/null +++ b/sys/include/gpio.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + * + * @(#)gpio.h 1.4 (2.11BSD GTE) 1997/3/28 + */ + +/* + * Ioctl definitions + */ +#ifndef _GPIO_H +#define _GPIO_H + +#include +#include + +/* control general-purpose i/o pins */ +#define GPIO_PORT(n) ((n) & 0xff) /* port number */ +#define GPIO_PORTA GPIO_PORT(0) +#define GPIO_PORTB GPIO_PORT(1) +#define GPIO_PORTC GPIO_PORT(2) +#define GPIO_PORTD GPIO_PORT(3) +#define GPIO_PORTE GPIO_PORT(4) +#define GPIO_PORTF GPIO_PORT(5) +#define GPIO_PORTG GPIO_PORT(6) +#define GPIO_COMMAND 0x1fff0000 /* command mask */ +#define GPIO_CONFIN (IOC_VOID | 1 << 16 | 'g'<<8) /* configure as input */ +#define GPIO_CONFOUT (IOC_VOID | 1 << 17 | 'g'<<8) /* configure as output */ +#define GPIO_CONFOD (IOC_VOID | 1 << 18 | 'g'<<8) /* configure as open drain */ +#define GPIO_DECONF (IOC_VOID | 1 << 19 | 'g'<<8) /* deconfigure */ +#define GPIO_STORE (IOC_VOID | 1 << 20 | 'g'<<8) /* store all outputs */ +#define GPIO_SET (IOC_VOID | 1 << 21 | 'g'<<8) /* set to 1 by mask */ +#define GPIO_CLEAR (IOC_VOID | 1 << 22 | 'g'<<8) /* set to 0 by mask */ +#define GPIO_INVERT (IOC_VOID | 1 << 23 | 'g'<<8) /* invert by mask */ +#define GPIO_POLL (IOC_VOID | 1 << 24 | 'g'<<8) /* poll */ +#define GPIO_LOL (IOC_IN | 1 << 25 | 'g'<<8) /* display lol picture */ + +#ifdef KERNEL + +#include "conf.h" + +extern const struct devspec gpiodevs[]; + +int gpioopen (dev_t dev, int flag, int mode); +int gpioclose (dev_t dev, int flag, int mode); +int gpioread (dev_t dev, struct uio *uio, int flag); +int gpiowrite (dev_t dev, struct uio *uio, int flag); +int gpioioctl (dev_t dev, u_int cmd, caddr_t addr, int flag); +#endif + +#endif diff --git a/sys/include/inode.h b/sys/include/inode.h new file mode 100644 index 0000000..0d03342 --- /dev/null +++ b/sys/include/inode.h @@ -0,0 +1,430 @@ +/* + * Copyright (c) 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +/* + * The I node is the focus of all file activity in UNIX. + * There is a unique inode allocated for each active file, + * each current directory, each mounted-on file, text file, and the root. + * An inode is 'named' by its dev/inumber pair. (iget/iget.c) + * Data in icommon1 and icommon2 is read in from permanent inode on volume. + */ + +/* + * 28 of the di_addr address bytes are used; 7 addresses of 4 + * bytes each: 4 direct (4Kb directly accessible) and 3 indirect. + */ +#define NDADDR 4 /* direct addresses in inode */ +#define NIADDR 3 /* indirect addresses in inode */ +#define NADDR (NDADDR + NIADDR) /* total addresses in inode */ + +struct icommon1 { + u_short ic_mode; /* mode and type of file */ + u_short ic_nlink; /* number of links to file */ + uid_t ic_uid; /* owner's user id */ + gid_t ic_gid; /* owner's group id */ + off_t ic_size; /* number of bytes in file */ +}; + +struct icommon2 { + time_t ic_atime; /* time last accessed */ + time_t ic_mtime; /* time last modified */ + time_t ic_ctime; /* time created */ +}; + +struct inode { + struct inode *i_chain[2]; /* must be first */ + u_int i_flag; + u_int i_count; /* reference count */ + dev_t i_dev; /* device where inode resides */ + ino_t i_number; /* i number, 1-to-1 with device address */ + u_int i_id; /* unique identifier */ + struct fs *i_fs; /* file sys associated with this inode */ + union { + struct { + u_short I_shlockc; /* count of shared locks */ + u_short I_exlockc; /* count of exclusive locks */ + } i_l; + struct proc *I_rsel; /* pipe read select */ + } i_un0; + union { + struct proc *I_wsel; /* pipe write select */ + } i_un1; + union { + daddr_t I_addr[NADDR]; /* normal file/directory */ + struct { + daddr_t I_db[NDADDR]; /* normal file/directory */ + daddr_t I_ib[NIADDR]; + } i_f; + struct { + /* + * the dummy field is here so that the de/compression + * part of the iget/iput routines works for special + * files. + */ + u_int I_dummy; + dev_t I_rdev; /* dev type */ + } i_d; + } i_un2; + union { + daddr_t if_lastr; /* last read (read-ahead) */ + struct { + struct inode *if_freef; /* free list forward */ + struct inode **if_freeb; /* free list back */ + } i_fr; + } i_un3; + struct icommon1 i_ic1; + u_int i_flags; /* user changeable flags */ + struct icommon2 i_ic2; +}; + +/* + * Inode structure as it appears on + * a disk block. + */ +struct dinode { + struct icommon1 di_icom1; + daddr_t di_addr[NADDR]; /* 7 block addresses 4 bytes each */ + u_int di_reserved[1]; /* pad of 4 to make total size 64 */ + u_int di_flags; + struct icommon2 di_icom2; +}; + +#define i_mode i_ic1.ic_mode +#define i_nlink i_ic1.ic_nlink +#define i_uid i_ic1.ic_uid +#define i_gid i_ic1.ic_gid +#define i_size i_ic1.ic_size +#define i_shlockc i_un0.i_l.I_shlockc +#define i_exlockc i_un0.i_l.I_exlockc +#define i_rsel i_un0.I_rsel +#define i_wsel i_un1.I_wsel +#define i_db i_un2.i_f.I_db +#define i_ib i_un2.i_f.I_ib +#define i_atime i_ic2.ic_atime +#define i_mtime i_ic2.ic_mtime +#define i_ctime i_ic2.ic_ctime +#define i_rdev i_un2.i_d.I_rdev +#define i_addr i_un2.I_addr +#define i_dummy i_un2.i_d.I_dummy +#define i_lastr i_un3.if_lastr +#define i_forw i_chain[0] +#define i_back i_chain[1] +#define i_freef i_un3.i_fr.if_freef +#define i_freeb i_un3.i_fr.if_freeb + +#define di_ic1 di_icom1 +#define di_ic2 di_icom2 +#define di_mode di_ic1.ic_mode +#define di_nlink di_ic1.ic_nlink +#define di_uid di_ic1.ic_uid +#define di_gid di_ic1.ic_gid +#define di_size di_ic1.ic_size +#define di_atime di_ic2.ic_atime +#define di_mtime di_ic2.ic_mtime +#define di_ctime di_ic2.ic_ctime + +#ifdef KERNEL +struct stat; + +/* + * Invalidate an inode. Used by the namei cache to detect stale + * information. In order to save space and also reduce somewhat the + * overhead - the i_id field is made into a u_short. If a pdp-11 can + * invalidate 100 inodes per second, the cache will have to be invalidated + * in about 11 minutes. Ha! + * Assumes the cacheinvalall routine will map the namei cache. + */ +void cinvalall (void); + +#define cacheinval(ip) \ + (ip)->i_id = ++nextinodeid; \ + if (nextinodeid == 0) \ + cinvalall(); + +u_int nextinodeid; /* unique id generator */ + +extern struct inode inode[]; /* the inode table itself */ +struct inode *rootdir; /* pointer to inode of root directory */ + +/* + * Initialize hash links for inodes and build inode free list. + */ +void ihinit (void); + +/* + * Get an inode pointer of a file descriptor. + */ +struct inode *getinode (int fdes); + +/* + * Allocate an inode in the file system. + */ +struct inode *ialloc (struct inode *pip); + +/* + * Look up an inode by device, inumber. + */ +struct inode *iget (dev_t dev, struct fs *fs, ino_t ino); + +/* + * Dereference an inode structure. On the last reference, + * write the inode out and deallocate the file. + */ +void iput (struct inode *ip); + +/* + * Make a new file. + */ +struct nameidata; +struct inode *maknode (int mode, struct nameidata *ndp); + +/* + * Open inode: initialize and validate special files. + */ +int openi (struct inode *ip, int mode); + +/* + * Close inode: call the device driver for special (IBLK, ICHR) files. +*/ +int closei (struct inode *ip, int flag); + +/* + * Convert a pathname into a pointer to a locked inode. + */ +struct inode *namei (struct nameidata *ndp); + +enum uio_rw; +int rdwri (enum uio_rw rw, struct inode *ip, caddr_t base, int len, + off_t offset, int ioflg, int *aresid); + +struct uio; +int rwip (struct inode *ip, struct uio *uio, int ioflag); + +/* + * Check mode permission on inode pointer. + */ +int access (struct inode *ip, int mode); + +/* + * Change the mode on a file. + */ +int chmod1 (struct inode *ip, int mode); + +/* + * Change an owner of a file. + */ +int chown1 (struct inode *ip, int uid, int gid); + +/* + * Lock/unlock an inode. + */ +void ilock (struct inode *ip); +void iunlock (struct inode *ip); + +/* + * Get inode statistics. + */ +int ino_stat (struct inode *ip, struct stat *sb); + +/* + * Truncate the inode ip to at most length size. + */ +void itrunc (struct inode *oip, u_long length, int ioflags); + +/* + * Update the inode with the current time. + */ +struct timeval; +void iupdat (struct inode *ip, struct timeval *ta, struct timeval *tm, + int waitfor); + +void irele (struct inode *ip); + +/* + * Free an inode. + */ +void ifree (struct inode *ip, ino_t ino); + +/* + * Free a block or fragment. + */ +void free (struct inode *ip, daddr_t bno); + +/* + * Flush all the blocks associated with an inode. + */ +void syncip (struct inode *ip); + +/* + * Remove any inodes in the inode cache belonging to dev. + */ +int iflush (dev_t dev); + +/* + * Convert a pointer to an inode into a reference to an inode. + */ +void igrab (struct inode *ip); + +/* + * Check if source directory is in the path of the target directory. + */ +int checkpath (struct inode *source, struct inode *target); + +/* + * Check if a directory is empty or not. + */ +int dirempty (struct inode *ip, ino_t parentino); + +/* + * Rewrite an existing directory entry to point at the inode supplied. + */ +void dirrewrite (struct inode *dp, struct inode *ip, struct nameidata *ndp); + +/* + * Check that device is mounted somewhere. + */ +int ufs_mountedon (dev_t dev); + +/* + * Set the attributes on a file. This was placed here because ufs_syscalls + * is too large already (it will probably be split into two files eventually). + */ +struct vattr; +int ufs_setattr (struct inode *ip, struct vattr *vap); + +/* + * Cache flush, called when filesys is umounted. + */ +void nchinval (dev_t dev); + +#endif /* KERNEL */ + +/* i_flag */ +#define ILOCKED 0x1 /* inode is locked */ +#define IUPD 0x2 /* file has been modified */ +#define IACC 0x4 /* inode access time to be updated */ +#define IMOUNT 0x8 /* inode is mounted on */ +#define IWANT 0x10 /* some process waiting on lock */ +#define ITEXT 0x20 /* inode is pure text prototype */ +#define ICHG 0x40 /* inode has been changed */ +#define ISHLOCK 0x80 /* file has shared lock */ +#define IEXLOCK 0x100 /* file has exclusive lock */ +#define ILWAIT 0x200 /* someone waiting on file lock */ +#define IMOD 0x400 /* inode has been modified */ +#define IRENAME 0x800 /* inode is being renamed */ +#define IPIPE 0x1000 /* inode is a pipe */ +#define IRCOLL 0x2000 /* read select collision on pipe */ +#define IWCOLL 0x4000 /* write select collision on pipe */ +#define IXMOD 0x8000 /* inode is text, but impure (XXX) */ + +/* i_mode */ +#define IFMT 0170000 /* type of file */ +#define IFCHR 0020000 /* character special */ +#define IFDIR 0040000 /* directory */ +#define IFBLK 0060000 /* block special */ +#define IFREG 0100000 /* regular */ +#define IFLNK 0120000 /* symbolic link */ +#define IFSOCK 0140000 /* socket */ +#define ISUID 04000 /* set user id on execution */ +#define ISGID 02000 /* set group id on execution */ +#define ISVTX 01000 /* save swapped text even after use */ +#define IREAD 0400 /* read, write, execute permissions */ +#define IWRITE 0200 +#define IEXEC 0100 + +#ifdef KERNEL +/* + * Flags for va_cflags. + */ +#define VA_UTIMES_NULL 0x01 /* utimes argument was NULL */ + +/* + * Flags for ioflag. + */ +#define IO_UNIT 0x01 /* do I/O as atomic unit */ +#define IO_APPEND 0x02 /* append write to end */ +#define IO_SYNC 0x04 /* do I/O synchronously */ +/*#define IO_NODELOCKED 0x08 not implemented */ +#define IO_NDELAY 0x10 /* FNDELAY flag set in file table */ + + +/* + * This is a bit of a misnomer. 2.11BSD does not have 'vnodes' but it was + * easier/simpler to keep the name 'vattr' than changing the name to something + * like 'iattr'. + * + * This structure is a _subset_ of 4.4BSD's vnode attribute structure. ONLY + * those attributes which can be *changed by the user* are present. Since we + * do not have vnodes why initialize (and carry around) un-used members. + */ +struct vattr { + mode_t va_mode; + uid_t va_uid; + gid_t va_gid; + off_t va_size; + time_t va_atime; + time_t va_mtime; + u_int va_flags; + u_int va_vaflags; +}; + +/* + * Token indicating no attribute value yet assigned. + */ +#define VNOVAL (-1) + +/* + * Initialize a inode attribute structure. + */ +#define VATTR_NULL(vp) { \ + (vp)->va_mode = VNOVAL; \ + (vp)->va_uid = VNOVAL; \ + (vp)->va_gid = VNOVAL; \ + (vp)->va_size = VNOVAL; \ + (vp)->va_atime = VNOVAL; \ + (vp)->va_mtime = VNOVAL; \ + (vp)->va_flags = VNOVAL; \ + (vp)->va_vaflags = VNOVAL; } + +/* + * N.B: If the above structure changes be sure to modify the function + * vattr_null in pdp/mch_xxx.s! + */ +#endif + +#define ILOCK(ip) { \ + while ((ip)->i_flag & ILOCKED) { \ + (ip)->i_flag |= IWANT; \ + sleep((caddr_t)(ip), PINOD); \ + } \ + (ip)->i_flag |= ILOCKED; \ +} + +#define IUNLOCK(ip) { \ + (ip)->i_flag &= ~ILOCKED; \ + if ((ip)->i_flag&IWANT) { \ + (ip)->i_flag &= ~IWANT; \ + wakeup((caddr_t)(ip)); \ + } \ +} + +#define IUPDAT(ip, t1, t2, waitfor) { \ + if (ip->i_flag&(IUPD|IACC|ICHG|IMOD)) \ + iupdat(ip, t1, t2, waitfor); \ +} + +#define ITIMES(ip, t1, t2) { \ + if ((ip)->i_flag&(IUPD|IACC|ICHG)) { \ + (ip)->i_flag |= IMOD; \ + if ((ip)->i_flag&IACC) \ + (ip)->i_atime = (t1)->tv_sec; \ + if ((ip)->i_flag&IUPD) \ + (ip)->i_mtime = (t2)->tv_sec; \ + if ((ip)->i_flag&ICHG) \ + (ip)->i_ctime = time.tv_sec; \ + (ip)->i_flag &= ~(IACC|IUPD|ICHG); \ + } \ +} diff --git a/sys/include/ioctl.h b/sys/include/ioctl.h new file mode 100644 index 0000000..7db0f14 --- /dev/null +++ b/sys/include/ioctl.h @@ -0,0 +1,259 @@ +/* + * Copyright (c) 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + * + * @(#)ioctl.h 1.4 (2.11BSD GTE) 1997/3/28 + */ + +/* + * Ioctl definitions + */ +#ifndef _IOCTL_ +#define _IOCTL_ +#ifdef KERNEL +#include "ttychars.h" +#include "ttydev.h" +#else +#include +#include + +int ioctl (int d, int request, ...); + +#endif + +struct tchars { + char t_intrc; /* interrupt */ + char t_quitc; /* quit */ + char t_startc; /* start output */ + char t_stopc; /* stop output */ + char t_eofc; /* end-of-file */ + char t_brkc; /* input delimiter (like nl) */ +}; +struct ltchars { + char t_suspc; /* stop process signal */ + char t_dsuspc; /* delayed stop process signal */ + char t_rprntc; /* reprint line */ + char t_flushc; /* flush output (toggles) */ + char t_werasc; /* word erase */ + char t_lnextc; /* literal next character */ +}; + +/* + * Structure for TIOCGETP and TIOCSETP ioctls. + */ + +#ifndef _SGTTYB_ +#define _SGTTYB_ +struct sgttyb { + char sg_ispeed; /* input speed */ + char sg_ospeed; /* output speed */ + char sg_erase; /* erase character */ + char sg_kill; /* kill character */ + short sg_flags; /* mode flags */ +}; +#endif + +/* + * Window/terminal size structure. + * This information is stored by the kernel + * in order to provide a consistent interface, + * but is not used by the kernel. + * + * Type must be "unsigned short" so that types.h not required. + */ +struct winsize { + unsigned short ws_row; /* rows, in characters */ + unsigned short ws_col; /* columns, in characters */ + unsigned short ws_xpixel; /* horizontal size, pixels */ + unsigned short ws_ypixel; /* vertical size, pixels */ +}; + +/* + * Pun for SUN. + */ +struct ttysize { + unsigned short ts_lines; + unsigned short ts_cols; + unsigned short ts_xxx; + unsigned short ts_yyy; +}; +#define TIOCGSIZE TIOCGWINSZ +#define TIOCSSIZE TIOCSWINSZ + +#ifndef _IO +/* + * Ioctl's have the command encoded in the lower word, + * and the size of any in or out parameters in the upper + * word. The high 2 bits of the upper word are used + * to encode the in/out status of the parameter; for now + * we restrict parameters to at most 256 bytes (disklabels are 216 bytes). + */ +#define IOCPARM_MASK 0xff /* parameters must be < 256 bytes */ +#define IOC_VOID 0x20000000 /* no parameters */ +#define IOC_OUT 0x40000000 /* copy out parameters */ +#define IOC_IN 0x80000000 /* copy in parameters */ +#define IOC_INOUT (IOC_IN|IOC_OUT) + +#define _IO(x,y) (IOC_VOID | ((x)<<8)|y) +#define _IOR(x,y,t) (IOC_OUT |((sizeof(t)&IOCPARM_MASK)<<16)|((x)<<8)|y) +#define _IOW(x,y,t) (IOC_IN |((sizeof(t)&IOCPARM_MASK)<<16)|((x)<<8)|y) +/* this should be _IORW, but stdio got there first */ +#define _IOWR(x,y,t) (IOC_INOUT|((sizeof(t)&IOCPARM_MASK)<<16)|((x)<<8)|y) +#define _ION(x,y,n) (IOC_INOUT| (((n)&IOCPARM_MASK)<<16)|((x)<<8)|y) +#endif + +/* + * tty ioctl commands + */ +#define TIOCGETD _IOR('t', 0, int) /* get line discipline */ +#define TIOCSETD _IOW('t', 1, int) /* set line discipline */ +#define TIOCHPCL _IO ('t', 2) /* hang up on last close */ +#define TIOCMODG _IOR('t', 3, int) /* get modem control state */ +#define TIOCMODS _IOW('t', 4, int) /* set modem control state */ +#define TIOCM_LE 0001 /* line enable */ +#define TIOCM_DTR 0002 /* data terminal ready */ +#define TIOCM_RTS 0004 /* request to send */ +#define TIOCM_ST 0010 /* secondary transmit */ +#define TIOCM_SR 0020 /* secondary receive */ +#define TIOCM_CTS 0040 /* clear to send */ +#define TIOCM_CAR 0100 /* carrier detect */ +#define TIOCM_CD TIOCM_CAR +#define TIOCM_RNG 0200 /* ring */ +#define TIOCM_RI TIOCM_RNG +#define TIOCM_DSR 0400 /* data set ready */ +#define TIOCGETP _IOR('t', 8,struct sgttyb)/* get parameters -- gtty */ +#define TIOCSETP _IOW('t', 9,struct sgttyb)/* set parameters -- stty */ +#define TIOCSETN _IOW('t', 10,struct sgttyb)/* as above, but no flushtty */ +#define TIOCEXCL _IO ('t', 13) /* set exclusive use of tty */ +#define TIOCNXCL _IO ('t', 14) /* reset exclusive use of tty */ +#define TIOCFLUSH _IOW('t', 16, int) /* flush buffers */ +#define TIOCSETC _IOW('t', 17,struct tchars)/* set special characters */ +#define TIOCGETC _IOR('t', 18,struct tchars)/* get special characters */ +#define TANDEM 0x00000001 /* send stopc on out q full */ +#define CBREAK 0x00000002 /* half-cooked mode */ + /* 0x4 (old LCASE) */ +#define ECHO 0x00000008 /* echo input */ +#define CRMOD 0x00000010 /* map \r to \r\n on output */ +#define RAW 0x00000020 /* no i/o processing */ +#define ODDP 0x00000040 /* get/send odd parity */ +#define EVENP 0x00000080 /* get/send even parity */ +#define ANYP 0x000000c0 /* get any parity/send none */ + /* 0x100 (old NLDELAY) */ + /* 0x200 */ +#define XTABS 0x00000400 /* expand tabs on output */ + /* 0x0800 (part of old XTABS) */ + /* 0x1000 (old CRDELAY) */ + /* 0x2000 */ + /* 0x4000 (old VTDELAY) */ + /* 0x8000 (old BSDELAY) */ +#define CRTBS 0x00010000 /* do backspacing for crt */ +#define PRTERA 0x00020000 /* \ ... / erase */ +#define CRTERA 0x00040000 /* " \b " to wipe out char */ + /* 0x00080000 (old TILDE) */ +#define MDMBUF 0x00100000 /* start/stop output on carrier intr */ +#define LITOUT 0x00200000 /* literal output */ +#define TOSTOP 0x00400000 /* SIGSTOP on background output */ +#define FLUSHO 0x00800000 /* flush output to terminal */ +#define NOHANG 0x01000000 /* no SIGHUP on carrier drop */ +#define RTSCTS 0x02000000 /* use RTS/CTS flow control */ +#define CRTKIL 0x04000000 /* kill line with " \b " */ +#define PASS8 0x08000000 +#define CTLECH 0x10000000 /* echo control chars as ^X */ +#define PENDIN 0x20000000 /* tp->t_rawq needs reread */ +#define DECCTQ 0x40000000 /* only ^Q starts after ^S */ +#define NOFLSH 0x80000000 /* no output flush on signal */ +/* locals, from 127 down */ +#define TIOCLBIS _IOW('t', 127, int) /* bis local mode bits */ +#define TIOCLBIC _IOW('t', 126, int) /* bic local mode bits */ +#define TIOCLSET _IOW('t', 125, int) /* set entire local mode word */ +#define TIOCLGET _IOR('t', 124, int) /* get local modes */ +#define LCRTBS ((int)(CRTBS>>16)) +#define LPRTERA ((int)(PRTERA>>16)) +#define LCRTERA ((int)(CRTERA>>16)) +#define LMDMBUF ((int)(MDMBUF>>16)) +#define LLITOUT ((int)(LITOUT>>16)) +#define LTOSTOP ((int)(TOSTOP>>16)) +#define LFLUSHO ((int)(FLUSHO>>16)) +#define LNOHANG ((int)(NOHANG>>16)) +#define LRTSCTS ((int)(RTSCTS>>16)) +#define LCRTKIL ((int)(CRTKIL>>16)) +#define LPASS8 ((int)(PASS8>>16)) +#define LCTLECH ((int)(CTLECH>>16)) +#define LPENDIN ((int)(PENDIN>>16)) +#define LDECCTQ ((int)(DECCTQ>>16)) +#define LNOFLSH ((int)(NOFLSH>>16)) +#define TIOCSBRK _IO ('t', 123) /* set break bit */ +#define TIOCCBRK _IO ('t', 122) /* clear break bit */ +#define TIOCSDTR _IO ('t', 121) /* set data terminal ready */ +#define TIOCCDTR _IO ('t', 120) /* clear data terminal ready */ +#define TIOCGPGRP _IOR('t', 119, int) /* get pgrp of tty */ +#define TIOCSPGRP _IOW('t', 118, int) /* set pgrp of tty */ +#define TIOCSLTC _IOW('t', 117,struct ltchars)/* set local special chars */ +#define TIOCGLTC _IOR('t', 116,struct ltchars)/* get local special chars */ +#define TIOCOUTQ _IOR('t', 115, int) /* output queue size */ +#define TIOCSTI _IOW('t', 114, char) /* simulate terminal input */ +#define TIOCNOTTY _IO ('t', 113) /* void tty association */ +#define TIOCPKT _IOW('t', 112, int) /* pty: set/clear packet mode */ +#define TIOCPKT_DATA 0x00 /* data packet */ +#define TIOCPKT_FLUSHREAD 0x01 /* flush packet */ +#define TIOCPKT_FLUSHWRITE 0x02 /* flush packet */ +#define TIOCPKT_STOP 0x04 /* stop output */ +#define TIOCPKT_START 0x08 /* start output */ +#define TIOCPKT_NOSTOP 0x10 /* no more ^S, ^Q */ +#define TIOCPKT_DOSTOP 0x20 /* now do ^S ^Q */ +#define TIOCSTOP _IO ('t', 111) /* stop output, like ^S */ +#define TIOCSTART _IO ('t', 110) /* start output, like ^Q */ +#define TIOCMSET _IOW('t', 109, int) /* set all modem bits */ +#define TIOCMBIS _IOW('t', 108, int) /* bis modem bits */ +#define TIOCMBIC _IOW('t', 107, int) /* bic modem bits */ +#define TIOCMGET _IOR('t', 106, int) /* get all modem bits */ +#define TIOCREMOTE _IOW('t', 105, int) /* remote input editing */ +#define TIOCGWINSZ _IOR('t', 104, struct winsize) /* get window size */ +#define TIOCSWINSZ _IOW('t', 103, struct winsize) /* set window size */ +#define TIOCUCNTL _IOW('t', 102, int) /* pty: set/clr usr cntl mode */ +#define UIOCCMD(n) _IO ('u', n) /* usr cntl op "n" */ + +#define NTTYDISC 0 /* new tty discipline */ + +#define FIOCLEX _IO('f', 1) /* set exclusive use on fd */ +#define FIONCLEX _IO('f', 2) /* remove exclusive use */ +/* another local */ +/* should use off_t for FIONREAD but that would require types.h */ +#define FIONREAD _IOR('f', 97, long) /* get # bytes to read */ +#define FIONBIO _IOW('f', 96, int) /* set/clear non-blocking i/o */ +#define FIOASYNC _IOW('f', 95, int) /* set/clear async i/o */ +#define FIOSETOWN _IOW('f', 94, int) /* set owner */ +#define FIOGETOWN _IOR('f', 93, int) /* get owner */ + +/* socket i/o controls */ +#define SIOCSHIWAT _IOW('s', 0, int) /* set high watermark */ +#define SIOCGHIWAT _IOR('s', 1, int) /* get high watermark */ +#define SIOCSLOWAT _IOW('s', 2, int) /* set low watermark */ +#define SIOCGLOWAT _IOR('s', 3, int) /* get low watermark */ +#define SIOCATMARK _IOR('s', 7, int) /* at oob mark? */ +#define SIOCSPGRP _IOW('s', 8, int) /* set process group */ +#define SIOCGPGRP _IOR('s', 9, int) /* get process group */ + +#define SIOCADDRT _IOW('r', 10, struct rtentry) /* add route */ +#define SIOCDELRT _IOW('r', 11, struct rtentry) /* delete route */ + +#define SIOCSIFADDR _IOW ('i',12, struct ifreq) /* set ifnet address */ +#define SIOCGIFADDR _IOWR('i',13, struct ifreq) /* get ifnet address */ +#define SIOCSIFDSTADDR _IOW ('i',14, struct ifreq) /* set p-p address */ +#define SIOCGIFDSTADDR _IOWR('i',15, struct ifreq) /* get p-p address */ +#define SIOCSIFFLAGS _IOW ('i',16, struct ifreq) /* set ifnet flags */ +#define SIOCGIFFLAGS _IOWR('i',17, struct ifreq) /* get ifnet flags */ +#define SIOCGIFBRDADDR _IOWR('i',18, struct ifreq) /* get broadcast addr */ +#define SIOCSIFBRDADDR _IOW ('i',19, struct ifreq) /* set broadcast addr */ +#define SIOCGIFCONF _IOWR('i',20, struct ifconf) /* get ifnet list */ +#define SIOCGIFNETMASK _IOWR('i',21, struct ifreq) /* get net addr mask */ +#define SIOCSIFNETMASK _IOW ('i',22, struct ifreq) /* set net addr mask */ +#define SIOCGIFMETRIC _IOWR('i',23, struct ifreq) /* get IF metric */ +#define SIOCSIFMETRIC _IOW ('i',24, struct ifreq) /* set IF metric */ + +#define SIOCSARP _IOW ('i',30, struct arpreq) /* set arp entry */ +#define SIOCGARP _IOWR('i',31, struct arpreq) /* get arp entry */ +#define SIOCDARP _IOW ('i',32, struct arpreq) /* delete arp entry */ + +#endif diff --git a/sys/include/kernel.h b/sys/include/kernel.h new file mode 100644 index 0000000..e766599 --- /dev/null +++ b/sys/include/kernel.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +/* + * Global variables for the kernel + */ + +/* 1.1 */ +long hostid; +char hostname[MAXHOSTNAMELEN]; +int hostnamelen; + +/* 1.2 */ +#include + +struct timeval boottime; +struct timeval time; +struct timezone tz; /* XXX */ +int adjdelta; +int hz; +int usechz; /* # microseconds per hz */ +int lbolt; /* awoken once a second */ + +short avenrun[3]; diff --git a/sys/include/map.h b/sys/include/map.h new file mode 100644 index 0000000..4b4531b --- /dev/null +++ b/sys/include/map.h @@ -0,0 +1,53 @@ +/* + * Resource Allocation Maps. + * + * Copyright (c) 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +/* + * Associated routines manage allocation of an address space using + * an array of segment descriptors. + * + * Malloc and mfree allocate and free the resource described + * by the resource map. If the resource map becomes too fragmented + * to be described in the available space, then some of the resource + * is discarded. This may lead to critical shortages, + * but is better than not checking (as the previous versions of + * these routines did) or giving up and calling panic(). + * + * N.B.: The address 0 in the resource address space is not available + * as it is used internally by the resource map routines. + */ +struct map { + struct mapent *m_map; /* start of the map */ + struct mapent *m_limit; /* address of last slot in map */ + char *m_name; /* name of resource */ +/* we use m_name when the map overflows, in warning messages */ +}; + +struct mapent { + size_t m_size; /* size of this segment of the map */ + size_t m_addr; /* resource-space addr of start of segment */ +}; + +#ifdef KERNEL +extern struct map swapmap[]; /* space for swap allocation */ + +/* + * Allocate units from the given map. + */ +size_t malloc (struct map *mp, size_t nbytes); + +/* + * Free the previously allocated units at addr into the specified map. + */ +void mfree (struct map *mp, size_t nbytes, size_t addr); + +/* + * Allocate resources for the three segments of a process. + */ +size_t malloc3 (struct map *mp, size_t d_size, size_t s_size, size_t u_size, size_t a[3]); + +#endif diff --git a/sys/include/mount.h b/sys/include/mount.h new file mode 100644 index 0000000..9841bc8 --- /dev/null +++ b/sys/include/mount.h @@ -0,0 +1,101 @@ +/* + * Copyright (c) 1982, 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +/* + * file system statistics + */ +#include + +#define MNAMELEN 90 /* length of buffer for returned name */ + +struct statfs { + short f_type; /* type of filesystem (see below) */ + u_short f_flags; /* copy of mount flags */ + short f_bsize; /* fundamental file system block size */ + short f_iosize; /* optimal transfer block size */ + daddr_t f_blocks; /* total data blocks in file system */ + daddr_t f_bfree; /* free blocks in fs */ + daddr_t f_bavail; /* free blocks avail to non-superuser */ + ino_t f_files; /* total file nodes in file system */ + ino_t f_ffree; /* free file nodes in fs */ + long f_fsid[2]; /* file system id */ + long f_spare[5]; /* spare for later */ + char f_mntonname[MNAMELEN]; /* directory on which mounted */ + char f_mntfromname[MNAMELEN];/* mounted filesystem */ +}; + +/* + * File system types. Since only UFS is supported the others are not + * specified at this time. + */ +#define MOUNT_NONE 0 +#define MOUNT_UFS 1 /* Fast Filesystem */ +#define MOUNT_MAXTYPE 1 + +#define INITMOUNTNAMES { \ + "none", /* 0 MOUNT_NONE */ \ + "ufs", /* 1 MOUNT_UFS */ \ + 0, \ +} + +/* + * Mount structure. + * One allocated on every mount. + * Used to find the super block. + */ +struct mount +{ + dev_t m_dev; /* device mounted */ + struct fs m_filsys; /* superblock data */ +#define m_flags m_filsys.fs_flags + struct inode *m_inodp; /* pointer to mounted on inode */ + struct inode *m_qinod; /* QUOTA: pointer to quota file */ + char m_mntfrom [MNAMELEN]; /* /dev/xxxx mounted from */ + char m_mnton [MNAMELEN]; /* directory mounted on - this is the + * full(er) version of fs_fsmnt. */ +}; + +/* + * Mount flags. + */ +#define MNT_RDONLY 0x0001 /* read only filesystem */ +#define MNT_SYNCHRONOUS 0x0002 /* file system written synchronously */ +#define MNT_NOEXEC 0x0004 /* can't exec from filesystem */ +#define MNT_NOSUID 0x0008 /* don't honor setuid bits on fs */ +#define MNT_NODEV 0x0010 /* don't interpret special files */ +#define MNT_QUOTA 0x0020 /* quotas are enabled on filesystem */ +#define MNT_ASYNC 0x0040 /* file system written asynchronously */ +#define MNT_NOATIME 0x0080 /* don't update access times */ + +/* + * Mask of flags that are visible to statfs(). +*/ +#define MNT_VISFLAGMASK 0x0fff + +/* + * filesystem control flags. The high 4 bits are used for this. Since NFS + * support will never be a problem we can avoid making the flags into a 'long. +*/ +#define MNT_UPDATE 0x1000 /* not a real mount, just an update */ + +/* + * Flags for various system call interfaces. + * + * These aren't used for anything in the system and are present only + * for source code compatibility reasons. +*/ +#define MNT_WAIT 1 +#define MNT_NOWAIT 2 + +#ifdef KERNEL + +struct mount mount[NMOUNT]; + +#else + +int getfsstat (struct statfs *buf, int bufsize, unsigned flags); + +#endif diff --git a/sys/include/msgbuf.h b/sys/include/msgbuf.h new file mode 100644 index 0000000..aeabd54 --- /dev/null +++ b/sys/include/msgbuf.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#define MSG_MAGIC 0x063061 +#define MSG_BSIZE 2048 + +struct msgbuf { + long msg_magic; + int msg_bufx; + int msg_bufr; + char msg_bufc [MSG_BSIZE]; +}; + +#define logMSG 0 /* /dev/klog */ + +#ifdef KERNEL +/* + * Check that log is open by a user program. + */ +int logisopen (int unit); +#endif diff --git a/sys/include/mtio.h b/sys/include/mtio.h new file mode 100644 index 0000000..3848a24 --- /dev/null +++ b/sys/include/mtio.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 1982, 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + * + * @(#)mtio.h 7.1.2 (2.11BSD) 1998/3/7 + */ + +/* + * Structures and definitions for mag tape io control commands + */ + +/* structure for MTIOCTOP - mag tape op command */ +struct mtop { + short mt_op; /* operations defined below */ + daddr_t mt_count; /* how many of them */ +}; + +/* operations */ +#define MTWEOF 0 /* write an end-of-file record */ +#define MTFSF 1 /* forward space file */ +#define MTBSF 2 /* backward space file */ +#define MTFSR 3 /* forward space record */ +#define MTBSR 4 /* backward space record */ +#define MTREW 5 /* rewind */ +#define MTOFFL 6 /* rewind and put the drive offline */ +#define MTNOP 7 /* no operation, sets status only */ +#define MTCACHE 8 /* enable controller cache */ +#define MTNOCACHE 9 /* disable controller cache */ +#define MTFLUSH 10 /* flush cache */ + +/* structure for MTIOCGET - mag tape get status command */ + +struct mtget { + short mt_type; /* type of magtape device */ +/* the following two registers are grossly device dependent */ + short mt_dsreg; /* ``drive status'' register */ + short mt_erreg; /* ``error'' register */ +/* end device-dependent registers */ + short mt_resid; /* residual count */ +/* the following two are not yet implemented */ + daddr_t mt_fileno; /* file number of current position */ + daddr_t mt_blkno; /* block number of current position */ +/* end not yet implemented */ +}; + +/* + * Constants for mt_type byte. These are the same + * for other controllers compatible with the types listed. + */ +#define MT_ISTS 0x01 /* TS-11 */ +#define MT_ISHT 0x02 /* TM03 Massbus: TE16, TU45, TU77 */ +#define MT_ISTM 0x03 /* TM11/TE10 Unibus */ +#define MT_ISMT 0x04 /* TM78/TU78 Massbus */ +#define MT_ISUT 0x05 /* SI TU-45 emulation on Unibus */ +#define MT_ISCPC 0x06 /* SUN */ +#define MT_ISAR 0x07 /* SUN */ +#define MT_ISTMSCP 0x08 /* DEC TMSCP protocol (TU81, TK50) */ + +/* + * At present only the TMSCP driver reports this information in the + * high byte of the 'drive status' word. Other drives will (hopefully) + * be updated in the future. +*/ +#define MTF_BOM 0x01 /* At beginning of media */ +#define MTF_EOM 0x02 /* At the end of media */ +#define MTF_OFFLINE 0x04 /* Drive is offline */ +#define MTF_WRTLCK 0x08 /* Drive is write protected */ +#define MTF_WRITTEN 0x10 /* Tape has been written */ + +/* mag tape io control commands */ +#define MTIOCTOP _IOW('m', 1, struct mtop) /* do a mag tape op */ +#define MTIOCGET _IOR('m', 2, struct mtget) /* get tape status */ +#define MTIOCIEOT _IO ('m', 3) /* ignore EOT error */ +#define MTIOCEEOT _IO ('m', 4) /* enable EOT error */ + +#ifndef KERNEL +#define DEFTAPE "/dev/rmt8" +#define MT_DEF "/dev/nrmt8" +#endif diff --git a/sys/include/namei.h b/sys/include/namei.h new file mode 100644 index 0000000..f5c6228 --- /dev/null +++ b/sys/include/namei.h @@ -0,0 +1,104 @@ +/* + * Copyright (c) 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#ifndef _NAMEI_ +#define _NAMEI_ + +#ifdef KERNEL +#include "uio.h" +#else +#include +#endif + +/* + * Encapsulation of namei parameters. + * One of these is located in the u. area to + * minimize space allocated on the kernel stack. + */ +struct nameidata { + caddr_t ni_dirp; /* pathname pointer */ + short ni_nameiop; /* see below */ + short ni_error; /* error return if any */ + off_t ni_endoff; /* end of useful stuff in directory */ + struct inode *ni_pdir; /* inode of parent directory of dirp */ + struct inode *ni_ip; /* inode of dirp */ + off_t ni_offset; /* offset in directory */ + u_short ni_count; /* offset of open slot (off_t?) */ + struct direct ni_dent; /* current directory entry */ +}; + +/* + * namei operations and modifiers + */ +#define LOOKUP 0 /* perform name lookup only */ +#define CREATE 1 /* setup for file creation */ +#define DELETE 2 /* setup for file deletion */ +#define LOCKPARENT 0x10 /* see the top of namei */ +#define NOCACHE 0x20 /* name must not be left in cache */ +#define FOLLOW 0x40 /* follow symbolic links */ +#define NOFOLLOW 0x0 /* don't follow symbolic links (pseudo) */ + +#define NDINIT(ndp,op,flags,namep) {\ + (ndp)->ni_nameiop = op | flags; \ + (ndp)->ni_dirp = namep; } + +/* + * This structure describes the elements in the cache of recent + * names looked up by namei. + */ +struct namecache { + struct namecache *nc_forw; /* hash chain, MUST BE FIRST */ + struct namecache *nc_back; /* hash chain, MUST BE FIRST */ + struct namecache *nc_nxt; /* LRU chain */ + struct namecache **nc_prev; /* LRU chain */ + struct inode *nc_ip; /* inode the name refers to */ + ino_t nc_ino; /* ino of parent of name */ + dev_t nc_dev; /* dev of parent of name */ + dev_t nc_idev; /* dev of the name ref'd */ + u_short nc_id; /* referenced inode's id */ + char nc_nlen; /* length of name */ +#define NCHNAMLEN 15 /* maximum name segment length we bother with */ + char nc_name[NCHNAMLEN]; /* segment name */ +}; + +#ifdef KERNEL +extern struct namecache namecache []; +struct nchstats nchstats; /* cache effectiveness statistics */ + +/* + * Name cache initialization. + */ +void nchinit (void); + +/* + * Common code for vnode open operations. + */ +int vn_open (struct nameidata *ndp, int fmode, int cmode); + +/* + * Write a directory entry after a call to namei. + */ +int direnter (struct inode *ip, struct nameidata *ndp); + +/* + * Remove a directory entry after a call to namei. + */ +int dirremove (struct nameidata *ndp); + +#endif /* KERNEL */ + +/* + * Stats on usefulness of namei caches. + */ +struct nchstats { + long ncs_goodhits; /* hits that we can reall use */ + long ncs_badhits; /* hits we must drop */ + long ncs_falsehits; /* hits with id mismatch */ + long ncs_miss; /* misses */ + long ncs_long; /* long names that ignore cache */ + long ncs_pass2; /* names found with passes == 2 */ + long ncs_2passes; /* number of times we attempt it */ +}; +#endif diff --git a/sys/include/oc.h b/sys/include/oc.h new file mode 100644 index 0000000..38b748b --- /dev/null +++ b/sys/include/oc.h @@ -0,0 +1,38 @@ +#ifndef _OC_H +#define _OC_H + +#include + +struct oc_state { + int mode; + int pwm_duty; +}; + +#define OC_MAX_DEV 5 + +#define OC_MODE_PWM 0x0001 + +#define OC_SET_MODE _IOW('i',1,int) +#define OC_PWM_DUTY _IOW('i',2,int) + +#ifdef KERNEL +#include "conf.h" + +extern const struct devspec ocdevs[]; + +extern int oc_open (dev_t dev, int flag, int mode); +extern int oc_close (dev_t dev, int flag, int mode); +extern int oc_read (dev_t dev, struct uio *uio, int flag); +extern int oc_write (dev_t dev, struct uio *uio, int flag); +extern int oc_ioctl (dev_t dev, u_int cmd, caddr_t addr, int flag); +#endif + +#define OC2CON PIC32_R (0x03200) +#define OC3CON PIC32_R (0x03400) +#define OC5CON PIC32_R (0x03800) + +#define OC2RS PIC32_R (0x03220) +#define OC3RS PIC32_R (0x03420) +#define OC5RS PIC32_R (0x03820) + +#endif diff --git a/sys/include/param.h b/sys/include/param.h new file mode 100644 index 0000000..76dd9f1 --- /dev/null +++ b/sys/include/param.h @@ -0,0 +1,123 @@ +/* + * Copyright (c) 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#define BSD 211 /* 2.11 * 100, as cpp doesn't do floats */ + +#define offsetof(type, member) ((size_t)(&((type *)0)->member)) + +/* + * Machine type dependent parameters. + */ +#include + +/* + * Machine-independent constants + */ +#ifndef NMOUNT +#define NMOUNT 2 /* number of mountable file systems */ +#endif + +#define MAXUPRC 20 /* max processes per user */ +#define NOFILE 30 /* max open files per process */ +#define NCARGS 5120 /* # characters in exec arglist */ +#define NGROUPS 16 /* max number groups */ + +#define NOGROUP 65535 /* marker for empty group set member */ + +/* + * Priorities + */ +#define PSWP 0 +#define PINOD 10 +#define PRIBIO 20 +#define PRIUBA 24 +#define PZERO 25 +#define PPIPE 26 +#define PSOCK 26 +#define PWAIT 30 +#define PLOCK 35 +#define PPAUSE 40 +#define PUSER 50 + +#define NZERO 0 + +#define PRIMASK 0xff +#define PCATCH 0x100 + +/* + * Signals + */ +#include + +#define NBPW sizeof(int) /* number of bytes in an integer */ + +#ifndef NULL +#define NULL 0 +#endif +#define CMASK 026 /* default mask for file creation */ +#define NODEV (dev_t)(-1) + +/* CBLOCK is the size of a clist block, must be power of 2 */ +#define CBLOCK 32 +#define CBSIZE (CBLOCK - sizeof(struct cblock *)) /* data chars/clist */ +#define CROUND (CBLOCK - 1) /* clist rounding */ + +#include + +/* + * File system parameters and macros. + * + * The file system is made out of blocks of most MAXBSIZE units. + */ +#define MAXBSIZE 1024 + +/* + * MAXPATHLEN defines the longest permissable path length + * after expanding symbolic links. It is used to allocate + * a temporary buffer from the buffer pool in which to do the + * name expansion, hence should be a power of two, and must + * be less than or equal to MAXBSIZE. + * MAXSYMLINKS defines the maximum number of symbolic links + * that may be expanded in a path name. It should be set high + * enough to allow all legitimate uses, but halt infinite loops + * reasonably quickly. + */ +#define MAXPATHLEN 256 +#define MAXSYMLINKS 8 + +/* + * Macros for fast min/max. + */ +#define MIN(a,b) (((a)<(b))?(a):(b)) +#ifndef MAX +#define MAX(a,b) (((a)>(b))?(a):(b)) +#endif + +/* + * Macros for counting and rounding. + */ +#ifndef howmany +# define howmany(x,y) (((x)+((y)-1))/(y)) +#endif +#define roundup(x,y) ((((x)+((y)-1))/(y))*(y)) + +/* + * Maximum size of hostname recognized and stored in the kernel. + */ +#define MAXHOSTNAMELEN 64 + +#if defined(KERNEL) && defined(INET) +# include "machine/net_mac.h" +#endif + +/* + * MAXMEM is the maximum core per process is allowed. First number is Kb. +*/ +#define MAXMEM (96*1024) + +/* + * Max length of a user login name. + */ +#define MAXLOGNAME 16 diff --git a/sys/include/picga.h b/sys/include/picga.h new file mode 100644 index 0000000..dae8da5 --- /dev/null +++ b/sys/include/picga.h @@ -0,0 +1,100 @@ +#ifndef _PICGA_H +#define _PICGA_H + +#define SPI_IDLE 0x00 + +// System control +#define SPI_CLS 0x01 +#define SPI_CLUT 0x02 +#define SPI_ENCOPPER 0x03 +#define SPI_DISCOPPER 0x04 +#define SPI_COPPERFILL 0x05 +#define SPI_SCROLL 0x06 +#define SPI_COPY 0x07 + +// Basic drawing +#define SPI_PLOT 0x11 +#define SPI_DRAW 0x12 +#define SPI_COLOR 0x13 +#define SPI_RECTANGLE 0x14 +#define SPI_CIRCLE 0x15 + +// Text commands +#define SPI_LOCATE 0x80 +#define SPI_FONT 0x81 +#define SPI_PRINT 0x82 +#define SPI_PRINTAT 0x83 +#define SPI_PUTCH 0x84 +#define SPI_PUTCHAR 0x85 +#define SPI_FGCOLOR 0x86 +#define SPI_BGCOLOR 0x87 + +#define FONT_SINCLAIR 0x00 +#define FONT_TOPAZ 0x01 + +#define UP 0 +#define DOWN 1 +#define LEFT 2 +#define RIGHT 3 + +struct coord2 { + unsigned short x; + unsigned short y; +}__attribute__((packed)); + +struct coord4 { + unsigned short x1; + unsigned short y1; + unsigned short x2; + unsigned short y2; +}__attribute__((packed)); + +struct coord6 { + unsigned short x1; + unsigned short y1; + unsigned short x2; + unsigned short y2; + unsigned short x3; + unsigned short y3; +}__attribute__((packed)); + +struct intval { + unsigned short value; +}__attribute__((packed)); + +struct rectangle { + unsigned short x1; + unsigned short y1; + unsigned short x2; + unsigned short y2; + unsigned fill:1; + unsigned char dither; +}__attribute__((packed)); + +struct circle { + unsigned short x; + unsigned short y; + unsigned short radius; + unsigned fill:1; +}__attribute__((packed)); + +struct charval { + unsigned char value; +}__attribute__((packed)); + +#ifdef KERNEL +#include "conf.h" + +extern const struct devspec picgadevs[]; + +extern void picga_command(unsigned char cmd, unsigned char len, void *data); +extern int picga_open(dev_t dev, int flag, int mode); +extern int picga_close(dev_t dev, int flag, int mode); +extern int picga_read(dev_t dev, struct uio *uio, int flag); +extern int picga_write(dev_t dev, struct uio *uio, int flag); +extern int picga_ioctl(dev_t dev, register u_int cmd, caddr_t addr, int flag); +#endif + +#define PICGA_CLS _IO('g', 1) + +#endif diff --git a/sys/include/proc.h b/sys/include/proc.h new file mode 100644 index 0000000..f06c010 --- /dev/null +++ b/sys/include/proc.h @@ -0,0 +1,305 @@ +/* + * Copyright (c) 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#ifndef _SYS_PROC_H_ +#define _SYS_PROC_H_ + +/* + * One structure allocated per active + * process. It contains all data needed + * about the process while the + * process may be swapped out. + * Other per process data (user.h) + * is swapped with the process. + */ +struct proc { + struct proc *p_nxt; /* linked list of allocated proc slots */ + struct proc **p_prev; /* also zombies, and free proc's */ + struct proc *p_pptr; /* pointer to process structure of parent */ + short p_flag; + short p_uid; /* user id, used to direct tty signals */ + short p_pid; /* unique process id */ + short p_ppid; /* process id of parent */ + long p_sig; /* signals pending to this process */ + int p_stat; + + /* + * Union to overwrite information no longer needed by ZOMBIED + * process with exit information for the parent process. The + * two structures have been carefully set up to use the same + * amount of memory. Must be very careful that any values in + * p_alive are not used for zombies (zombproc). + */ + union { + struct { + char P_pri; /* priority, negative is high */ + char P_cpu; /* cpu usage for scheduling */ + char P_time; /* resident time for scheduling */ + char P_nice; /* nice for cpu usage */ + char P_slptime; /* secs sleeping */ + char P_ptracesig; /* used between parent & traced child */ + struct proc *P_hash; /* hashed based on p_pid */ + long P_sigmask; /* current signal mask */ + long P_sigignore; /* signals being ignored */ + long P_sigcatch; /* signals being caught by user */ + short P_pgrp; /* name of process group leader */ + struct proc *P_link; /* linked list of running processes */ + size_t P_addr; /* address of u. area */ + size_t P_daddr; /* address of data area */ + size_t P_saddr; /* address of stack area */ + size_t P_dsize; /* size of data area (clicks) */ + size_t P_ssize; /* size of stack segment (clicks) */ + caddr_t P_wchan; /* event process is awaiting */ + struct k_itimerval P_realtimer; + } p_alive; + struct { + int P_xstat; /* exit status for wait */ + struct k_rusage P_ru; /* exit information */ + } p_dead; + } p_un; +}; +#define p_pri p_un.p_alive.P_pri +#define p_cpu p_un.p_alive.P_cpu +#define p_time p_un.p_alive.P_time +#define p_nice p_un.p_alive.P_nice +#define p_slptime p_un.p_alive.P_slptime +#define p_hash p_un.p_alive.P_hash +#define p_ptracesig p_un.p_alive.P_ptracesig +#define p_sigmask p_un.p_alive.P_sigmask +#define p_sigignore p_un.p_alive.P_sigignore +#define p_sigcatch p_un.p_alive.P_sigcatch +#define p_pgrp p_un.p_alive.P_pgrp +#define p_link p_un.p_alive.P_link +#define p_addr p_un.p_alive.P_addr +#define p_daddr p_un.p_alive.P_daddr +#define p_saddr p_un.p_alive.P_saddr +#define p_dsize p_un.p_alive.P_dsize +#define p_ssize p_un.p_alive.P_ssize +#define p_wchan p_un.p_alive.P_wchan +#define p_realtimer p_un.p_alive.P_realtimer +#define p_clktim p_realtimer.it_value + +#define p_xstat p_un.p_dead.P_xstat +#define p_ru p_un.p_dead.P_ru + +#define PIDHSZ 16 +#define PIDHASH(pid) ((pid) & (PIDHSZ - 1)) + +/* arguments to swapout: */ +#define X_OLDSIZE (-1) /* the old size is the same as current */ +#define X_DONTFREE 0 /* save core image (for parent in newproc) */ +#define X_FREECORE 1 /* free core space after swap */ + +#ifdef KERNEL +struct proc *pidhash [PIDHSZ]; +extern struct proc proc[]; /* the proc table itself */ +struct proc *freeproc, *zombproc, *allproc, *qs; + /* lists of procs in various states */ +int nproc; + +/* + * Init the process queues. + */ +void pqinit (void); + +/* + * Find a process by pid. + */ +struct proc *pfind (int pid); + +/* + * Set user priority. + */ +int setpri (struct proc *pp); + +/* + * Send the specified signal to the specified process. + */ +void psignal (struct proc *p, int sig); + +/* + * Send the specified signal to a process group. + */ +void gsignal (int pgrp, int sig); + +/* + * Take the action for the specified signal. + */ +void postsig (int sig); + +/* + * If the current process has received a signal, return the signal number. + */ +int issignal (struct proc *p); + +/* + * Initialize signal state for process 0; + * set to ignore signals that are ignored by default. + */ +void siginit (struct proc *p); + +/* + * Remove a process from its wait queue + */ +void unsleep (struct proc *p); + +void selwakeup (struct proc *p, long coll); + +/* + * Set the process running; + * arrange for it to be swapped in if necessary. + */ +void setrun (struct proc *p); + +/* + * Reschedule the CPU. + */ +void swtch (void); + +/* + * Recompute process priorities, once a second. + */ +void schedcpu (caddr_t arg); + +/* + * The main loop of the scheduling process. No return. + */ +void sched (void); + +/* + * Create a new process -- the internal version of system call fork. + */ +int newproc (int isvfork); + +/* + * Notify parent that vfork child is finished with parent's data. + */ +void endvfork (void); + +/* + * Put the process into the run queue. + */ +void setrq (struct proc *p); + +/* + * Remove runnable job from run queue. + */ +void remrq (struct proc *p); + +/* + * Exit the process. + */ +void exit (int rv); + +/* + * Swap I/O. + */ +void swap (size_t blkno, size_t coreaddr, int count, int rdflg); + +/* + * Kill a process when ran out of swap space. + */ +void swkill (struct proc *p, char *name); + +/* + * Give up the processor till a wakeup occurs on chan, at which time the + * process enters the scheduling queue at priority pri. + */ +void sleep (caddr_t chan, int pri); + +/* + * Give up the processor till a wakeup occurs on ident or a timeout expires. + * Then the process enters the scheduling queue at given priority. + */ +int tsleep (caddr_t ident, int priority, u_int timo); + +/* + * Arrange that given function is called in t/hz seconds. + */ +void timeout (void (*fun) (caddr_t), caddr_t arg, int t); + +/* + * Remove a function timeout call from the callout structure. + */ +void untimeout (void (*fun) (caddr_t), caddr_t arg); + +/* + * Handler for hardware clock interrupt. + */ +void hardclock (caddr_t pc, int ps); + +/* + * Swap out a process. + */ +void swapout (struct proc *p, int freecore, u_int odata, u_int ostack); + +/* + * Swap a process in. + */ +void swapin (struct proc *p); + +/* + * Is p an inferior of the current process? + */ +int inferior (struct proc *p); + +/* + * Test if the current user is the super user. + */ +int suser (void); + +/* + * Load from user area (probably swapped out): real uid, + * controlling terminal device, and controlling terminal pointer. + */ +struct tty; +void fill_from_u (struct proc *p, uid_t *rup, struct tty **ttp, dev_t *tdp); + +/* + * Grow the stack to include the SP. + */ +int grow (unsigned sp); + +/* + * Kill current process with the specified signal in an uncatchable manner. + */ +void fatalsig (int signum); + +/* + * Parent controlled tracing. + */ +int procxmt (void); + +#endif /* KERMEL */ + +/* stat codes */ +#define SSLEEP 1 /* awaiting an event */ +#define SWAIT 2 /* (abandoned state) */ +#define SRUN 3 /* running */ +#define SIDL 4 /* intermediate state in process creation */ +#define SZOMB 5 /* intermediate state in process termination */ +#define SSTOP 6 /* process being traced */ + +/* flag codes */ +#define SLOAD 0x0001 /* in core */ +#define SSYS 0x0002 /* swapper or pager process */ +#define SLOCK 0x0004 /* process being swapped out */ +#define SSWAP 0x0008 /* save area flag */ +#define P_TRACED 0x0010 /* process is being traced */ +#define P_WAITED 0x0020 /* another tracing flag */ +#define P_SINTR 0x0080 /* sleeping interruptibly */ +#define SVFORK 0x0100 /* process resulted from vfork() */ +#define SVFPRNT 0x0200 /* parent in vfork, waiting for child */ +#define SVFDONE 0x0400 /* parent has released child in vfork */ + /* 0x0800 unused */ +#define P_TIMEOUT 0x1000 /* tsleep timeout expired */ +#define P_NOCLDSTOP 0x2000 /* no SIGCHLD signal to parent */ +#define P_SELECT 0x4000 /* selecting; wakeup/waiting danger */ + /* 0x8000 unused */ + +#define S_DATA 0 /* specified segment */ +#define S_STACK 1 + +#endif /* !_SYS_PROC_H_ */ diff --git a/sys/include/ptrace.h b/sys/include/ptrace.h new file mode 100644 index 0000000..49cd4ac --- /dev/null +++ b/sys/include/ptrace.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 1980, 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +#ifndef _PTRACE_ +#define _PTRACE_ + +#define PT_TRACE_ME 0 /* child declares it's being traced */ +#define PT_READ_I 1 /* read word in child's I space */ +#define PT_READ_D 2 /* read word in child's D space */ +#define PT_READ_U 3 /* read word in child's user structure */ +#define PT_WRITE_I 4 /* write word in child's I space */ +#define PT_WRITE_D 5 /* write word in child's D space */ +#define PT_WRITE_U 6 /* write word in child's user structure */ +#define PT_CONTINUE 7 /* continue the child */ +#define PT_KILL 8 /* kill the child process */ +#define PT_STEP 9 /* single step the child */ + +/* + * Tracing variables. + * Used to pass trace command from + * parent to child being traced. + * This data base cannot be + * shared and is locked + * per user. + */ +struct ipc { + int ip_lock; + int ip_req; + int *ip_addr; + int ip_data; +}; + +#ifdef KERNEL + +struct ipc ipc; + +#else + +int ptrace (int request, pid_t pid, void *addr, int data); + +#endif + +#endif diff --git a/sys/include/pty.h b/sys/include/pty.h new file mode 100644 index 0000000..5825227 --- /dev/null +++ b/sys/include/pty.h @@ -0,0 +1,49 @@ +#ifndef _PTY_H +#define _PTY_H + +#define PF_RCOLL 0x01 +#define PF_WCOLL 0x02 +#define PF_PKT 0x08 /* packet mode */ +#define PF_STOPPED 0x10 /* user told stopped */ +#define PF_REMOTE 0x20 /* remote and flow controlled input */ +#define PF_NOSTOP 0x40 +#define PF_UCNTL 0x80 /* user control mode */ + +#ifdef KERNEL + +#include "uio.h" +#include "tty.h" +#include "conf.h" + +extern const struct devspec ptsdevs[]; +extern const struct devspec ptcdevs[]; + + +#ifndef NPTY +#define NPTY 4 +#endif + +#if NPTY == 1 +#undef NPTY +#define NPTY 16 /* crude XXX */ +#endif + +extern struct tty pt_tty[NPTY]; + +extern int ptsopen(dev_t dev, int flag, int mode); +extern int ptsclose(dev_t dev, int flag, int mode); +extern int ptsread(dev_t dev, register struct uio *uio, int flag); +extern int ptswrite(dev_t dev, register struct uio *uio, int flag); +extern void ptsstart(struct tty *tp); +extern void ptcwakeup(struct tty *tp, int flag); +extern int ptcopen(dev_t dev, int flag, int mode); +extern int ptcclose(dev_t dev, int flag, int mode); +extern int ptcread(dev_t dev, register struct uio *uio, int flag); +extern void ptsstop(register struct tty *tp, int flush); +extern int ptcselect(dev_t dev, int rw); +extern int ptcwrite(dev_t dev, register struct uio *uio, int flag); +extern int ptyioctl(dev_t dev, u_int cmd, caddr_t data, int flag); + +#endif + +#endif diff --git a/sys/include/rd_flash.h b/sys/include/rd_flash.h new file mode 100644 index 0000000..f75e972 --- /dev/null +++ b/sys/include/rd_flash.h @@ -0,0 +1,14 @@ +#ifndef _RD_FLASH_H +#define _RD_FLASH_H + +#ifdef KERNEL + +extern int flash_read(int unit, unsigned int offset, char *data, unsigned int bcount); +extern int flash_write(int unit, unsigned int offset, char *data, unsigned int bcount); +extern int flash_open(int unit, int flag, int mode); +extern int flash_size(int unit); +extern void flash_init(int unit, int flag); + +#endif + +#endif diff --git a/sys/include/rd_mrams.h b/sys/include/rd_mrams.h new file mode 100644 index 0000000..4530f20 --- /dev/null +++ b/sys/include/rd_mrams.h @@ -0,0 +1,9 @@ +#ifndef _MRAMS_H +#define _MRAMS_H + +extern int mrams_size(int unit); +extern int mrams_read(int unit, unsigned int offset, char *data, unsigned int bcount); +extern int mrams_write (int unit, unsigned offset, char *data, unsigned bcount); +extern void mrams_preinit (int unit); + +#endif diff --git a/sys/include/rd_sdramp.h b/sys/include/rd_sdramp.h new file mode 100644 index 0000000..61a9196 --- /dev/null +++ b/sys/include/rd_sdramp.h @@ -0,0 +1,14 @@ +#ifndef _SDRAMP_H +#define _SDRAMP_H + +#ifdef KERNEL + +extern int sdramp_write(int unit, unsigned blockno, char* data, unsigned nbytes); +extern int sdramp_read (int unit, unsigned blockno, char *data, unsigned nbytes); +extern void sdramp_preinit(int unit); +extern int sdramp_size(int unit); +extern int sdramp_open(int unit, int a, int b); + +#endif + +#endif diff --git a/sys/include/rd_sramc.h b/sys/include/rd_sramc.h new file mode 100644 index 0000000..2c68f19 --- /dev/null +++ b/sys/include/rd_sramc.h @@ -0,0 +1,14 @@ +#ifndef _SRAMC_H +#define _SRAMC_H + +#ifdef KERNEL + +extern int sramc_read(int unit, unsigned int offset, char *data, unsigned int bcount); +extern int sramc_write(int unit, unsigned int offset, char *data, unsigned int bcount); +extern int sramc_open(int unit, int flag, int mode); +extern void sramc_init(int unit); +extern int sramc_size(int unit); + +#endif + +#endif diff --git a/sys/include/rdisk.h b/sys/include/rdisk.h new file mode 100644 index 0000000..4760979 --- /dev/null +++ b/sys/include/rdisk.h @@ -0,0 +1,97 @@ +#ifndef _RDISK_H +#define _RDISK_H + +#include "conf.h" + +#define RDISK_FS 0xB7 +#define RDISK_SWAP 0xB8 + +#define RD_DEFAULT 0x00000000UL +#define RD_READONLY 0x00000001UL +#define RD_PREPART 0x00000002UL + +#define S_SILENT 0x8000 + +#define RAMDISK_PARTSPEC(n,t,s,l) \ +m->partitions[n].type=t; \ +m->partitions[n].lbastart=s; \ +m->partitions[n].lbalength=l; + +struct diskentry { + void (*pre_init)(int unit); + int (*init)(int unit,int flag); + int (*deinit)(int unit); + int (*open)(int unit, int mode, int flags); + int (*size)(int unit); + int (*read)(int unit, unsigned int offset, char *data, unsigned int bcount); + int (*write)(int unit, unsigned int offset, char *data, unsigned int bcount); + unsigned char unit; + unsigned int settings; +}; + +struct diskflags { + unsigned char opens; + unsigned int start[4]; + unsigned int len[4]; + unsigned int blocks; +} __attribute__((packed)); + +struct chs { + unsigned char head; + struct { + unsigned cylhigh:2; + unsigned sector:6; + } __attribute__((packed)); + unsigned char cyllow; +}__attribute__((packed)); + +struct partition { +#define P_ACTIVE 0x80 + unsigned char status; + struct chs start; + unsigned char type; + struct chs end; + unsigned long lbastart; + unsigned long lbalength; +}; + +struct mbr { + unsigned char bootstrap1[218]; + unsigned short pad0000; + unsigned char biosdrive; + unsigned char secs; + unsigned char mins; + unsigned char hours; + unsigned char bootstrap2[216]; + unsigned int sig; + unsigned short pad0001; + struct partition partitions[4]; + unsigned short bootsig; +}__attribute__((packed)); + +#ifdef KERNEL +extern int rdopen(dev_t dev, int flag, int mode); +extern int rdclose(dev_t dev, int flag, int mode); +extern daddr_t rdsize(dev_t dev); +extern void rdstrategy(register struct buf *bp); +extern int partition_size(dev_t dev); +extern int rdioctl (dev_t dev, register u_int cmd, caddr_t addr, int flag); +extern void rdisk_init(); +extern void rdisk_list_partitions(unsigned char type); +extern int rdisk_num_disks(); + +extern dev_t get_boot_device(); +extern dev_t get_swap_device(); +extern unsigned char partition_type(dev_t dev); +extern struct buf *prepartition_device(char *devname); + +extern const struct devspec rd0devs[]; +extern const struct devspec rd1devs[]; +extern const struct devspec rd2devs[]; +extern const struct devspec rd3devs[]; +#endif + +#define RDGETMEDIASIZE _IOR('r',1,int) +#define RDREINIT _IO('r',2) + +#endif diff --git a/sys/include/reboot.h b/sys/include/reboot.h new file mode 100644 index 0000000..91b65ea --- /dev/null +++ b/sys/include/reboot.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + * + * @(#)reboot.h 1.2 (2.11BSD GTE) 1996/5/9 + */ + +/* + * Arguments to reboot system call. + * These are passed to boot program in r4, + * and on to init. + */ +#define RB_AUTOBOOT 0 /* flags for system auto-booting itself */ + +#define RB_ASKNAME 0x001 /* ask for file name to reboot from */ +#define RB_SINGLE 0x002 /* reboot to single user only */ +#define RB_NOSYNC 0x004 /* dont sync before reboot */ +#define RB_HALT 0x008 /* don't reboot, just halt */ +#define RB_INITNAME 0x010 /* name given for /etc/init */ +#define RB_DFLTROOT 0x020 /* use compiled-in rootdev */ +#define RB_DUMP 0x040 /* take a dump before rebooting */ +#define RB_NOFSCK 0x080 /* don't perform fsck's on reboot */ +#define RB_POWRFAIL 0x100 /* reboot caused by power failure */ +#define RB_RDONLY 0x200 /* mount root fs read-only */ +#define RB_AUTODEBUG 0x400 /* init runs autoconfig with "-d" (debug) */ +#define RB_POWEROFF 0x800 /* signal PSU to switch off power */ +#define RB_BOOTLOADER 0x1000 /* reboot into the bootloader */ + +#define RB_PANIC 0 /* reboot due to panic */ +#define RB_BOOT 1 /* reboot due to boot() */ diff --git a/sys/include/resource.h b/sys/include/resource.h new file mode 100644 index 0000000..9b50aa9 --- /dev/null +++ b/sys/include/resource.h @@ -0,0 +1,107 @@ +/* + * Copyright (c) 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + * + * @(#)resource.h 1.3 (2.11BSD GTE) 1997/2/14 + */ + +#ifndef _SYS_RESOURCE_H_ +#define _SYS_RESOURCE_H_ + +/* + * Process priority specifications to get/setpriority. + */ +#define PRIO_MIN -20 +#define PRIO_MAX 20 + +#define PRIO_PROCESS 0 +#define PRIO_PGRP 1 +#define PRIO_USER 2 + +/* + * Resource utilization information. + */ + +#define RUSAGE_SELF 0 +#define RUSAGE_CHILDREN -1 + +struct rusage { + struct timeval ru_utime; /* user time used */ + struct timeval ru_stime; /* system time used */ + long ru_maxrss; +#define ru_first ru_ixrss + long ru_ixrss; /* integral shared memory size */ + long ru_idrss; /* integral unshared data " */ + long ru_isrss; /* integral unshared stack " */ + long ru_minflt; /* page reclaims */ + long ru_majflt; /* page faults */ + long ru_nswap; /* swaps */ + long ru_inblock; /* block input operations */ + long ru_oublock; /* block output operations */ + long ru_msgsnd; /* messages sent */ + long ru_msgrcv; /* messages received */ + long ru_nsignals; /* signals received */ + long ru_nvcsw; /* voluntary context switches */ + long ru_nivcsw; /* involuntary " */ +#define ru_last ru_nivcsw +}; + +struct k_rusage { /* KERNEL RUSAGE STRUCTURE */ +#define k_ru_first ru_utime + long ru_utime; /* user time used ('hz' ticks) */ + long ru_stime; /* system time used ('hz' ticks) */ + long ru_nswap; /* swaps */ + long ru_inblock; /* block input operations */ + long ru_oublock; /* block output operations */ + long ru_msgsnd; /* messages sent */ + long ru_msgrcv; /* messages received */ + long ru_nsignals; /* signals received */ + long ru_nvcsw; /* voluntary context switches */ + long ru_nivcsw; /* involuntary " */ +#define k_ru_last ru_nivcsw +}; + +/* + * Resource limits + */ +#define RLIMIT_CPU 0 /* cpu time in milliseconds */ +#define RLIMIT_FSIZE 1 /* maximum file size */ +#define RLIMIT_DATA 2 /* data size */ +#define RLIMIT_STACK 3 /* stack size */ +#define RLIMIT_CORE 4 /* core file size */ +#define RLIMIT_RSS 5 /* resident set size */ + +#define RLIM_NLIMITS 6 /* number of resource limits */ + +#define RLIM_INFINITY 0x7fffffff + +struct rlimit { + long rlim_cur; /* current (soft) limit */ + long rlim_max; /* maximum value for rlim_cur */ +}; + +/* Load average structure. */ +struct loadavg { + short ldavg[3]; + int fscale; +}; + +#ifdef KERNEL +/* + * Convert an internal kernel rusage structure into a `real' rusage structure. + */ +void rucvt (struct rusage *rup, struct k_rusage *krup); + +/* + * Add resource usage data. + */ +void ruadd (struct k_rusage *ru, struct k_rusage *ru2); + +#else + +int getrusage (int who, struct rusage *usage); + +#endif + +#endif /* !_SYS_RESOURCE_H_ */ diff --git a/sys/include/select.h b/sys/include/select.h new file mode 100644 index 0000000..9828fb6 --- /dev/null +++ b/sys/include/select.h @@ -0,0 +1,75 @@ +/*- + * 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. + * + * @(#)select.h 8.2.1 (2.11BSD) 2000/2/28 + */ + +#ifndef _SYS_SELECT_H_ +#define _SYS_SELECT_H_ + +#include + +/* + * Select uses bit masks of file descriptors in longs. + * These macros manipulate such bit fields (the filesystem macros use chars). + * FD_SETSIZE may be defined by the user, but the default here + * should be >= NOFILE (param.h). + */ +#ifndef FD_SETSIZE +#define FD_SETSIZE 32 +#endif + +typedef long fd_mask; +#define NFDBITS (sizeof(fd_mask) * NBBY) /* bits per mask */ + +typedef struct fd_set { + fd_mask fds_bits[1]; +} fd_set; + +#define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1L << ((n) % NFDBITS))) +#define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1L << ((n) % NFDBITS))) +#define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1L << ((n) % NFDBITS))) +#define FD_ZERO(p) bzero((char *)(p), sizeof(*(p))) + +#ifndef KERNEL +#ifndef CROSS +void bzero(void *, unsigned long); +#endif + +/* According to POSIX.1-2001 */ +struct timeval; +int select (int nfds, fd_set *readfds, fd_set *writefds, + fd_set *exceptfds, struct timeval *timeout); + +#endif /* !KERNEL */ + +#endif /* !_SYS_SELECT_H_ */ diff --git a/sys/include/signal.h b/sys/include/signal.h new file mode 100644 index 0000000..475dd43 --- /dev/null +++ b/sys/include/signal.h @@ -0,0 +1,189 @@ +/* + * Copyright (c) 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#ifndef NSIG +#include + +#define NSIG 32 + +#define SIGHUP 1 /* hangup */ +#define SIGINT 2 /* interrupt */ +#define SIGQUIT 3 /* quit */ +#define SIGILL 4 /* illegal instruction (not reset when caught) */ +#define SIGTRAP 5 /* trace trap (not reset when caught) */ +#define SIGIOT 6 /* IOT instruction */ +#define SIGABRT SIGIOT /* compatibility */ +#define SIGEMT 7 /* EMT instruction */ +#define SIGFPE 8 /* floating point exception */ +#define SIGKILL 9 /* kill (cannot be caught or ignored) */ +#define SIGBUS 10 /* bus error */ +#define SIGSEGV 11 /* segmentation violation */ +#define SIGSYS 12 /* bad argument to system call */ +#define SIGPIPE 13 /* write on a pipe with no one to read it */ +#define SIGALRM 14 /* alarm clock */ +#define SIGTERM 15 /* software termination signal from kill */ +#define SIGURG 16 /* urgent condition on IO channel */ +#define SIGSTOP 17 /* sendable stop signal not from tty */ +#define SIGTSTP 18 /* stop signal from tty */ +#define SIGCONT 19 /* continue a stopped process */ +#define SIGCHLD 20 /* to parent on child stop or exit */ +#define SIGCLD SIGCHLD /* compatibility */ +#define SIGTTIN 21 /* to readers pgrp upon background tty read */ +#define SIGTTOU 22 /* like TTIN for output if (tp->t_local<OSTOP) */ +#define SIGIO 23 /* input/output possible signal */ +#define SIGXCPU 24 /* exceeded CPU time limit */ +#define SIGXFSZ 25 /* exceeded file size limit */ +#define SIGVTALRM 26 /* virtual time alarm */ +#define SIGPROF 27 /* profiling time alarm */ +#define SIGWINCH 28 /* window size changes */ +#define SIGUSR1 30 /* user defined signal 1 */ +#define SIGUSR2 31 /* user defined signal 2 */ + +typedef void (*sig_t) (int); /* type of signal function */ + +#define SIG_ERR (sig_t) -1 +#define SIG_DFL (sig_t) 0 +#define SIG_IGN (sig_t) 1 + +typedef unsigned long sigset_t; + +/* + * Signal vector "template" used in sigaction call. + */ +struct sigaction { + sig_t sa_handler; /* signal handler */ + sigset_t sa_mask; /* signal mask to apply */ + int sa_flags; /* see signal options below */ +}; + +#define SA_ONSTACK 0x0001 /* take signal on signal stack */ +#define SA_RESTART 0x0002 /* restart system on signal return */ +#define SA_DISABLE 0x0004 /* disable taking signals on alternate stack */ +#define SA_NOCLDSTOP 0x0008 /* do not generate SIGCHLD on child stop */ + +/* + * Flags for sigprocmask: + */ +#define SIG_BLOCK 1 /* block specified signal set */ +#define SIG_UNBLOCK 2 /* unblock specified signal set */ +#define SIG_SETMASK 3 /* set specified signal set */ + +/* + * Structure used in sigaltstack call. + */ +struct sigaltstack { + char *ss_base; /* signal stack base */ + int ss_size; /* signal stack length */ + int ss_flags; /* SA_DISABLE and/or SA_ONSTACK */ +}; +#define MINSIGSTKSZ 128 /* minimum allowable stack */ +#define SIGSTKSZ (MINSIGSTKSZ + 384) /* recommended stack size */ + +/* + * 4.3 compatibility: + * Signal vector "template" used in sigvec call. + */ +struct sigvec { + sig_t sv_handler; /* signal handler */ + long sv_mask; /* signal mask to apply */ + int sv_flags; /* see signal options below */ +}; +#define SV_ONSTACK SA_ONSTACK /* take signal on signal stack */ +#define SV_INTERRUPT SA_RESTART /* same bit, opposite sense */ +#define sv_onstack sv_flags /* isn't compatibility wonderful! */ + +/* + * 4.3 compatibility: + * Structure used in sigstack call. + */ +struct sigstack { + char *ss_sp; /* signal stack pointer */ + int ss_onstack; /* current status */ +}; + +/* + * Information pushed on stack when a signal is delivered. + * This is used by the kernel to restore state following + * execution of the signal handler. It is also made available + * to the handler to allow it to properly restore state if + * a non-standard exit is performed. + */ +struct sigcontext { + int sc_onstack; /* sigstack state to restore */ + long sc_mask; /* signal mask to restore */ + int sc_r1; /* r1 to restore */ + int sc_r2; /* and other registers */ + int sc_r3; + int sc_r4; + int sc_r5; + int sc_r6; + int sc_r7; + int sc_r8; + int sc_r9; + int sc_r10; + int sc_r11; + int sc_r12; + int sc_r13; + int sc_r14; + int sc_r15; + int sc_r16; + int sc_r17; + int sc_r18; + int sc_r19; + int sc_r20; + int sc_r21; + int sc_r22; + int sc_r23; + int sc_r24; + int sc_r25; + int sc_gp; + int sc_sp; /* sp to restore */ + int sc_fp; + int sc_ra; + int sc_lo; + int sc_hi; + int sc_pc; /* pc to restore */ +}; + +/* + * Macro for converting signal number to a mask suitable for + * sigblock(). + */ +#define sigmask(m) (1L << ((m)-1)) +#define sigaddset(set, signo) (*(set) |= 1L << ((signo) - 1), 0) +#define sigdelset(set, signo) (*(set) &= ~(1L << ((signo) - 1)), 0) +#define sigemptyset(set) (*(set) = (sigset_t)0, (int)0) +#define sigfillset(set) (*(set) = ~(sigset_t)0, (int)0) +#define sigismember(set, signo) ((*(set) & (1L << ((signo) - 1))) != 0) + +#ifdef KERNEL + +/* Table of signal properties. */ +extern const char sigprop [NSIG + 1]; + +/* + * Send an interrupt to process. + */ +void sendsig (sig_t p, int sig, long mask); + +#else /* KERNEL */ + +sig_t signal (int, sig_t); +int sigaction (int signum, const struct sigaction *act, + struct sigaction *oldact); +int sigvec (int sig, struct sigvec *vec, struct sigvec *ovec); +int kill (pid_t pid, int sig); +int sigpause (int mask); +int sigblock (int mask); +int sigsetmask (int mask); +int sigprocmask (int how, const sigset_t *set, sigset_t *oldset); +int siginterrupt (int sig, int flag); +int sigsuspend (const sigset_t *mask); + +#define BADSIG SIG_ERR + +#endif /* KERNEL */ + +#endif /* NSIG */ diff --git a/sys/include/signalvar.h b/sys/include/signalvar.h new file mode 100644 index 0000000..537d600 --- /dev/null +++ b/sys/include/signalvar.h @@ -0,0 +1,120 @@ +/* + * 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 _SYS_SIGNALVAR_H_ /* tmp for user.h */ +#define _SYS_SIGNALVAR_H_ + +/* + * Kernel signal definitions and data structures, + * not exported to user programs. + * + * For 2BSD the parts that did not apply were cut out. + */ + +/* signal flags */ +#define SAS_OLDMASK 0x01 /* need to restore mask before pause */ +#define SAS_ALTSTACK 0x02 /* have alternate signal stack */ + +/* additional signal action values, used only temporarily/internally */ +#define SIG_CATCH (sig_t) 2 +#define SIG_HOLD (sig_t) 3 + +/* + * Determine signal that should be delivered to process p, the current + * process, 0 if none. If there is a pending stop signal with default + * action, the process stops in issignal(). + * + * This probably should be a routine (assembly) instead of a macro due + * to the voluminous code generated by all of the 'long' operations. + */ +#define CURSIG(p) \ + (((p)->p_sig == 0 || \ + (((p)->p_flag & P_TRACED) == 0 && \ + ((p)->p_sig & ~(p)->p_sigmask) == 0)) ? \ + 0 : issignal(p)) + +/* + * Signal properties and actions. + * The array below categorizes the signals and their default actions + * according to the following properties: + */ +#define SA_KILL 0x01 /* terminates process by default */ +#define SA_CORE 0x02 /* ditto and coredumps */ +#define SA_STOP 0x04 /* suspend process */ +#define SA_TTYSTOP 0x08 /* ditto, from tty */ +#define SA_IGNORE 0x10 /* ignore by default */ +#define SA_CONT 0x20 /* continue if suspended */ + +#ifdef SIGPROP +const char sigprop [NSIG + 1] = { + 0, /* unused */ + SA_KILL, /* SIGHUP */ + SA_KILL, /* SIGINT */ + SA_KILL | SA_CORE, /* SIGQUIT */ + SA_KILL | SA_CORE, /* SIGILL */ + SA_KILL | SA_CORE, /* SIGTRAP */ + SA_KILL | SA_CORE, /* SIGABRT */ + SA_KILL | SA_CORE, /* SIGEMT */ + SA_KILL | SA_CORE, /* SIGFPE */ + SA_KILL, /* SIGKILL */ + SA_KILL | SA_CORE, /* SIGBUS */ + SA_KILL | SA_CORE, /* SIGSEGV */ + SA_KILL | SA_CORE, /* SIGSYS */ + SA_KILL, /* SIGPIPE */ + SA_KILL, /* SIGALRM */ + SA_KILL, /* SIGTERM */ + SA_IGNORE, /* SIGURG */ + SA_STOP, /* SIGSTOP */ + SA_STOP | SA_TTYSTOP, /* SIGTSTP */ + SA_IGNORE | SA_CONT, /* SIGCONT */ + SA_IGNORE, /* SIGCHLD */ + SA_STOP | SA_TTYSTOP, /* SIGTTIN */ + SA_STOP | SA_TTYSTOP, /* SIGTTOU */ + SA_IGNORE, /* SIGIO */ + SA_KILL, /* SIGXCPU */ + SA_KILL, /* SIGXFSZ */ + SA_KILL, /* SIGVTALRM */ + SA_KILL, /* SIGPROF */ + SA_IGNORE, /* SIGWINCH */ + SA_IGNORE, /* SIGINFO */ + SA_KILL, /* SIGUSR1 */ + SA_KILL, /* SIGUSR2 */ +}; +#endif /* SIGPROP */ + +#ifdef KERNEL +#define contsigmask (sigmask(SIGCONT)) +#define stopsigmask (sigmask(SIGSTOP) | sigmask(SIGTSTP) | \ + sigmask(SIGTTIN) | sigmask(SIGTTOU)) +#define sigcantmask (sigmask(SIGKILL) | sigmask(SIGSTOP)) +#endif +#endif /* !_SYS_SIGNALVAR_H_ */ diff --git a/sys/include/spi.h b/sys/include/spi.h new file mode 100644 index 0000000..ef8f114 --- /dev/null +++ b/sys/include/spi.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +/* + * Ioctl definitions for SPI driver. + */ +#ifndef _SPI_H +#define _SPI_H + +#include + +#define SPICTL_SETMODE _IO ('p', 0) /* set SPI mode */ +#define SPICTL_SETRATE _IO ('p', 1) /* set clock rate, kHz */ +#define SPICTL_SETSELPIN _IO ('p', 2) /* set select pin */ +#define SPICTL_IO8(n) _ION('p', 3, n) /* transfer n*8 bits */ +#define SPICTL_IO16(n) _ION('p', 4, n) /* transfer n*16 bits */ +#define SPICTL_IO32(n) _ION('p', 5, n) /* transfer n*32 bits */ + +#ifdef KERNEL +#include "conf.h" + +extern const struct devspec spidevs[]; + +int spidev_open (dev_t dev, int flag, int mode); +int spidev_close (dev_t dev, int flag, int mode); +int spidev_read (dev_t dev, struct uio *uio, int flag); +int spidev_write (dev_t dev, struct uio *uio, int flag); +int spidev_ioctl (dev_t dev, u_int cmd, caddr_t addr, int flag); +#endif + +#endif diff --git a/sys/include/spi_bus.h b/sys/include/spi_bus.h new file mode 100644 index 0000000..7c806ec --- /dev/null +++ b/sys/include/spi_bus.h @@ -0,0 +1,62 @@ +#ifndef _SPI_BUS_H +#define _SPI_BUS_H + +#ifdef KERNEL + +struct spireg { + volatile unsigned con; /* Control */ + volatile unsigned conclr; + volatile unsigned conset; + volatile unsigned coninv; + volatile unsigned stat; /* Status */ + volatile unsigned statclr; + volatile unsigned statset; + volatile unsigned statinv; + volatile unsigned buf; /* Transmit and receive buffer */ + volatile unsigned unused1; + volatile unsigned unused2; + volatile unsigned unused3; + volatile unsigned brg; /* Baud rate generator */ + volatile unsigned brgclr; + volatile unsigned brgset; + volatile unsigned brginv; +}; + +struct spi_dev { + struct spireg *bus; + unsigned int *cs_tris; + unsigned int cs_pin; + unsigned int baud; + unsigned int mode; +}; + +extern int spi_open(unsigned int bus, unsigned int *tris, unsigned int pin); +extern void spi_close(int dno); +extern void spi_set_cspin(int dno, unsigned int *tris, unsigned int pin); +extern void spi_select(int dno); +extern void spi_deselect(int dno); +extern void spi_set(int dno, unsigned int set); +extern void spi_clr(int dno, unsigned int set); +extern unsigned int spi_status(int dno); +extern unsigned char spi_transfer(int dno, unsigned char data); +extern void spi_bulk_write_32_be(int dno, unsigned int len, char *data); +extern void spi_bulk_write_32(int dno, unsigned int len, char *data); +extern void spi_bulk_write_16(int dno, unsigned int len, char *data); +extern void spi_bulk_write(int dno, unsigned int len, unsigned char *data); +extern void spi_bulk_read_32_be(int dno, unsigned int len, char *data); +extern void spi_bulk_read_32(int dno, unsigned int len, char *data); +extern void spi_bulk_read_16(int dno, unsigned int len, char *data); +extern void spi_bulk_read(int dno, unsigned int len, unsigned char *data); +extern void spi_bulk_rw_32_be(int dno, unsigned int len, char *data); +extern void spi_bulk_rw_32(int dno, unsigned int len, char *data); +extern void spi_bulk_rw_16(int dno, unsigned int len, char *data); +extern void spi_bulk_rw(int dno, unsigned int len, unsigned char *data); +extern void spi_brg(int dno, unsigned int baud); +extern char *spi_name(int dno); +extern char spi_csname(int dno); +extern int spi_cspin(int dno); +extern unsigned int spi_get_brg(int dno); + +#endif + +#endif diff --git a/sys/include/stat.h b/sys/include/stat.h new file mode 100644 index 0000000..81fa367 --- /dev/null +++ b/sys/include/stat.h @@ -0,0 +1,103 @@ +/* + * Copyright (c) 1982, 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#ifndef _STAT_H_ +#define _STAT_H_ + +struct stat +{ + dev_t st_dev; + ino_t st_ino; + u_int st_mode; + int st_nlink; + uid_t st_uid; + gid_t st_gid; + dev_t st_rdev; + off_t st_size; + time_t st_atime; + time_t st_mtime; + time_t st_ctime; + long st_blksize; + long st_blocks; + u_int st_flags; +}; + +#define S_IFMT 0170000 /* type of file */ +#define S_IFDIR 0040000 /* directory */ +#define S_IFCHR 0020000 /* character special */ +#define S_IFBLK 0060000 /* block special */ +#define S_IFREG 0100000 /* regular */ +#define S_IFLNK 0120000 /* symbolic link */ +#define S_IFSOCK 0140000/* socket */ +#define S_ISUID 0004000 /* set user id on execution */ +#define S_ISGID 0002000 /* set group id on execution */ +#define S_ISVTX 0001000 /* save swapped text even after use */ +#define S_IREAD 0000400 /* read permission, owner */ +#define S_IWRITE 0000200 /* write permission, owner */ +#define S_IEXEC 0000100 /* execute/search permission, owner */ + +/* + * Definitions of flags in mode that are 4.4 compatible. + */ + +#define S_IFIFO 0010000 /* named pipe (fifo) - Not used by 2.11BSD */ + +#define S_IRWXU 0000700 /* RWX mask for owner */ +#define S_IRUSR 0000400 /* R for owner */ +#define S_IWUSR 0000200 /* W for owner */ +#define S_IXUSR 0000100 /* X for owner */ + +#define S_IRWXG 0000070 /* RWX mask for group */ +#define S_IRGRP 0000040 /* R for group */ +#define S_IWGRP 0000020 /* W for group */ +#define S_IXGRP 0000010 /* X for group */ + +#define S_IRWXO 0000007 /* RWX mask for other */ +#define S_IROTH 0000004 /* R for other */ +#define S_IWOTH 0000002 /* W for other */ +#define S_IXOTH 0000001 /* X for other */ + +#define S_ISDIR(m) ((m & S_IFMT) == S_IFDIR) /* directory */ +#define S_ISCHR(m) ((m & S_IFMT) == S_IFCHR) /* character special */ +#define S_ISBLK(m) ((m & S_IFMT) == S_IFBLK) /* block special */ +#define S_ISREG(m) ((m & S_IFMT) == S_IFREG) /* regular */ +#define S_ISLNK(m) ((m & S_IFMT) == S_IFLNK) /* symbolic link */ +#define S_ISSOCK(m) ((m & S_IFMT) == S_IFSOCK) /* socket */ + +/* + * Definitions of flags stored in file flags word. Different from 4.4 because + * 2.11BSD only could afford a u_short for the flags. It is not a great + * inconvenience since there are still 5 bits in each byte available for + * future use. + * + * Super-user and owner changeable flags. + */ +#define UF_SETTABLE 0x00ff /* mask of owner changeable flags */ +#define UF_NODUMP 0x0001 /* do not dump file */ +#define UF_IMMUTABLE 0x0002 /* file may not be changed */ +#define UF_APPEND 0x0004 /* writes to file may only append */ +/* + * Super-user changeable flags. + */ +#define SF_SETTABLE 0xff00 /* mask of superuser changeable flags */ +#define SF_ARCHIVED 0x0100 /* file is archived */ +#define SF_IMMUTABLE 0x0200 /* file may not be changed */ +#define SF_APPEND 0x0400 /* writes to file may only append */ + +#ifdef KERNEL +/* + * Shorthand abbreviations of above. + */ +#define APPEND (UF_APPEND | SF_APPEND) +#define IMMUTABLE (UF_IMMUTABLE | SF_IMMUTABLE) +#else + +int chmod (const char *path, mode_t mode); +int fchmod (int fd, mode_t mode); +mode_t umask (mode_t cmask); + +#endif + +#endif /* !_STAT_H_ */ diff --git a/sys/include/swap.h b/sys/include/swap.h new file mode 100644 index 0000000..6fe9485 --- /dev/null +++ b/sys/include/swap.h @@ -0,0 +1,29 @@ +#ifndef _SWAP_H +#define _SWAP_H + +#ifdef KERNEL +#include "ioctl.h" +#else +#include +#endif + +#define TFALLOC _IOWR('s',1,off_t) + +#ifdef KERNEL + +extern int swopen(dev_t dev, int mode, int flag); +extern int swclose(dev_t dev, int mode, int flag); +extern void swstrategy(register struct buf *bp); +extern daddr_t swsize(dev_t dev); +extern int swcread(dev_t dev, register struct uio *uio, int flag); +extern int swcwrite(dev_t dev, register struct uio *uio, int flag); +extern int swcioctl (dev_t dev, register u_int cmd, caddr_t addr, int flag); +extern int swcopen(dev_t dev, int mode, int flag); +extern int swcclose(dev_t dev, int mode, int flag); + +extern const struct devspec swapbdevs[]; +extern const struct devspec swapcdevs[]; + +#endif + +#endif diff --git a/sys/include/sysctl.h b/sys/include/sysctl.h new file mode 100644 index 0000000..53c7228 --- /dev/null +++ b/sys/include/sysctl.h @@ -0,0 +1,393 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Mike Karels at Berkeley Software Design, 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 _SYS_SYSCTL_H_ +#define _SYS_SYSCTL_H_ + +/* + * These are for the eproc, etext, einode, efile and map structures. + */ +#ifndef KERNEL +#include +#include +#include +#include +#include +#include +#include +#endif + +/* + * Definitions for sysctl call. The sysctl call uses a hierarchical name + * for objects that can be examined or modified. The name is expressed as + * a sequence of integers. Like a file path name, the meaning of each + * component depends on its place in the hierarchy. The top-level and kern + * identifiers are defined here, and other identifiers are defined in the + * respective subsystem header files. + */ + +#define CTL_MAXNAME 12 /* largest number of components supported */ + +/* + * Each subsystem defined by sysctl defines a list of variables + * for that subsystem. Each name is either a node with further + * levels defined below it, or it is a leaf of some particular + * type given below. Each sysctl level defines a set of name/type + * pairs to be used by sysctl(1) in manipulating the subsystem. + */ +struct ctlname { + char *ctl_name; /* subsystem name */ + int ctl_type; /* type of name */ +}; +#define CTLTYPE_NODE 1 /* name is a node */ +#define CTLTYPE_INT 2 /* name describes a 16-bit integer */ +#define CTLTYPE_STRING 3 /* name describes a string */ +#define CTLTYPE_LONG 4 /* name describes a 32-bit number */ +#define CTLTYPE_STRUCT 5 /* name describes a structure */ + +/* + * Top-level identifiers + */ +#define CTL_UNSPEC 0 /* unused */ +#define CTL_KERN 1 /* "high kernel": proc, limits */ +#define CTL_VM 2 /* virtual memory */ +#define CTL_FS 3 /* file system, mount type is next */ +#define CTL_NET 4 /* network, see socket.h */ +#define CTL_DEBUG 5 /* debugging parameters */ +#define CTL_HW 6 /* generic cpu/io */ +#define CTL_MACHDEP 7 /* machine dependent */ +#define CTL_USER 8 /* user-level */ +#define CTL_MAXID 9 /* number of valid top-level ids */ + +#ifndef KERNEL +#define CTL_NAMES { \ + { 0, 0 }, \ + { "kern", CTLTYPE_NODE }, \ + { "vm", CTLTYPE_NODE }, \ + { "fs", CTLTYPE_NODE }, \ + { "net", CTLTYPE_NODE }, \ + { "debug", CTLTYPE_NODE }, \ + { "hw", CTLTYPE_NODE }, \ + { "machdep", CTLTYPE_NODE }, \ + { "user", CTLTYPE_NODE }, \ +} +#endif + +/* + * CTL_KERN identifiers + */ +#define KERN_OSTYPE 1 /* string: system version */ +#define KERN_OSRELEASE 2 /* string: system release */ +#define KERN_OSREV 3 /* int: system revision */ +#define KERN_VERSION 4 /* string: compile time info */ +#define KERN_MAXINODES 5 /* int: max inodes */ +#define KERN_MAXPROC 6 /* int: max processes */ +#define KERN_MAXFILES 7 /* int: max open files */ +#define KERN_ARGMAX 8 /* int: max arguments to exec */ +#define KERN_SECURELVL 9 /* int: system security level */ +#define KERN_HOSTNAME 10 /* string: hostname */ +#define KERN_HOSTID 11 /* int: host identifier */ +#define KERN_CLOCKRATE 12 /* struct: struct clockrate */ +#define KERN_INODE 13 /* struct: inode structures */ +#define KERN_PROC 14 /* struct: process entries */ +#define KERN_FILE 15 /* struct: file entries */ +#define KERN_PROF 16 /* node: kernel profiling info */ +#define KERN_POSIX1 17 /* int: POSIX.1 version */ +#define KERN_NGROUPS 18 /* int: # of supplemental group ids */ +#define KERN_JOB_CONTROL 19 /* int: is job control available */ +#define KERN_SAVED_IDS 20 /* int: saved set-user/group-ID */ +#define KERN_BOOTTIME 21 /* struct: time kernel was booted */ +#define KERN_MAXTEXTS 22 /* int: # of text entries */ +#define KERN_TEXT 23 /* struct: text entries */ +#define KERN_ACCTTHRESH 24 /* int: accounting daemon threshold */ +#define KERN_MAXID 25 /* number of valid kern ids */ + +#ifndef KERNEL +#define CTL_KERN_NAMES { \ + { 0, 0 }, \ + { "ostype", CTLTYPE_STRING }, \ + { "osrelease", CTLTYPE_STRING }, \ + { "osrevision", CTLTYPE_LONG }, \ + { "version", CTLTYPE_STRING }, \ + { "maxinodes", CTLTYPE_INT }, \ + { "maxproc", CTLTYPE_INT }, \ + { "maxfiles", CTLTYPE_INT }, \ + { "argmax", CTLTYPE_INT }, \ + { "securelevel", CTLTYPE_INT }, \ + { "hostname", CTLTYPE_STRING }, \ + { "hostid", CTLTYPE_LONG }, \ + { "clockrate", CTLTYPE_STRUCT }, \ + { "inode", CTLTYPE_STRUCT }, \ + { "proc", CTLTYPE_STRUCT }, \ + { "file", CTLTYPE_STRUCT }, \ + { "profiling", CTLTYPE_NODE }, \ + { "posix1version", CTLTYPE_INT }, \ + { "ngroups", CTLTYPE_INT }, \ + { "job_control", CTLTYPE_INT }, \ + { "saved_ids", CTLTYPE_INT }, \ + { "boottime", CTLTYPE_STRUCT }, \ + { "maxtexts", CTLTYPE_INT }, \ + { "text", CTLTYPE_STRUCT }, \ + { "acctthresh", CTLTYPE_INT }, \ +} +#endif + +/* + * KERN_PROC subtypes + */ +#define KERN_PROC_ALL 0 /* everything */ +#define KERN_PROC_PID 1 /* by process id */ +#define KERN_PROC_PGRP 2 /* by process group id */ +#define KERN_PROC_SESSION 3 /* by session of pid - NOT IN 2.11 */ +#define KERN_PROC_TTY 4 /* by controlling tty */ +#define KERN_PROC_UID 5 /* by effective uid */ +#define KERN_PROC_RUID 6 /* by real uid */ + +/* + * KERN_PROC subtype ops return arrays of augmented proc structures: + */ +struct kinfo_proc { + struct proc kp_proc; /* proc structure */ + struct eproc { + struct proc *e_paddr; /* address of proc */ + dev_t e_tdev; /* controlling tty dev */ + pid_t e_tpgid; /* tty process group id */ + uid_t e_ruid; /* real uid */ + } kp_eproc; +}; + +/* + * KERN_INODE returns an array of augmented inode structures: +*/ +struct kinfo_inode { + struct inode *kp_inodep; /* address of inode */ + struct inode kp_inode; /* inode structure */ +}; + +/* + * KERN_FILE returns an array of augmented file structures: +*/ +struct kinfo_file { + struct file *kp_filep; /* address of file */ + struct file kp_file; /* file structure */ +}; + +/* + * CTL_HW identifiers + */ +#define HW_MACHINE 1 /* string: machine class */ +#define HW_MODEL 2 /* string: specific machine model */ +#define HW_NCPU 3 /* int: number of cpus */ +#define HW_BYTEORDER 4 /* int: machine byte order */ +#define HW_PHYSMEM 5 /* int: total memory */ +#define HW_USERMEM 6 /* int: non-kernel memory */ +#define HW_PAGESIZE 7 /* int: software page size */ +#define HW_DISKNAMES 8 /* strings: disk drive names */ +#define HW_DISKSTATS 9 /* struct: diskstats[] */ +#define HW_MAXID 10 /* number of valid hw ids */ + +#ifndef KERNEL +#define CTL_HW_NAMES { \ + { 0, 0 }, \ + { "machine", CTLTYPE_STRING }, \ + { "model", CTLTYPE_STRING }, \ + { "ncpu", CTLTYPE_INT }, \ + { "byteorder", CTLTYPE_INT }, \ + { "physmem", CTLTYPE_LONG }, \ + { "usermem", CTLTYPE_LONG }, \ + { "pagesize", CTLTYPE_INT }, \ + { "disknames", CTLTYPE_STRUCT }, \ + { "diskstats", CTLTYPE_STRUCT }, \ +} +#endif + +#ifndef KERNEL +/* + * CTL_USER definitions + */ +#define USER_CS_PATH 1 /* string: _CS_PATH */ +#define USER_BC_BASE_MAX 2 /* int: BC_BASE_MAX */ +#define USER_BC_DIM_MAX 3 /* int: BC_DIM_MAX */ +#define USER_BC_SCALE_MAX 4 /* int: BC_SCALE_MAX */ +#define USER_BC_STRING_MAX 5 /* int: BC_STRING_MAX */ +#define USER_COLL_WEIGHTS_MAX 6 /* int: COLL_WEIGHTS_MAX */ +#define USER_EXPR_NEST_MAX 7 /* int: EXPR_NEST_MAX */ +#define USER_LINE_MAX 8 /* int: LINE_MAX */ +#define USER_RE_DUP_MAX 9 /* int: RE_DUP_MAX */ +#define USER_POSIX2_VERSION 10 /* int: POSIX2_VERSION */ +#define USER_POSIX2_C_BIND 11 /* int: POSIX2_C_BIND */ +#define USER_POSIX2_C_DEV 12 /* int: POSIX2_C_DEV */ +#define USER_POSIX2_CHAR_TERM 13 /* int: POSIX2_CHAR_TERM */ +#define USER_POSIX2_FORT_DEV 14 /* int: POSIX2_FORT_DEV */ +#define USER_POSIX2_FORT_RUN 15 /* int: POSIX2_FORT_RUN */ +#define USER_POSIX2_LOCALEDEF 16 /* int: POSIX2_LOCALEDEF */ +#define USER_POSIX2_SW_DEV 17 /* int: POSIX2_SW_DEV */ +#define USER_POSIX2_UPE 18 /* int: POSIX2_UPE */ +#define USER_STREAM_MAX 19 /* int: POSIX2_STREAM_MAX */ +#define USER_TZNAME_MAX 20 /* int: POSIX2_TZNAME_MAX */ +#define USER_MAXID 21 /* number of valid user ids */ + +#define CTL_USER_NAMES { \ + { 0, 0 }, \ + { "cs_path", CTLTYPE_STRING }, \ + { "bc_base_max", CTLTYPE_INT }, \ + { "bc_dim_max", CTLTYPE_INT }, \ + { "bc_scale_max", CTLTYPE_INT }, \ + { "bc_string_max", CTLTYPE_INT }, \ + { "coll_weights_max", CTLTYPE_INT }, \ + { "expr_nest_max", CTLTYPE_INT }, \ + { "line_max", CTLTYPE_INT }, \ + { "re_dup_max", CTLTYPE_INT }, \ + { "posix2_version", CTLTYPE_INT }, \ + { "posix2_c_bind", CTLTYPE_INT }, \ + { "posix2_c_dev", CTLTYPE_INT }, \ + { "posix2_char_term", CTLTYPE_INT }, \ + { "posix2_fort_dev", CTLTYPE_INT }, \ + { "posix2_fort_run", CTLTYPE_INT }, \ + { "posix2_localedef", CTLTYPE_INT }, \ + { "posix2_sw_dev", CTLTYPE_INT }, \ + { "posix2_upe", CTLTYPE_INT }, \ + { "stream_max", CTLTYPE_INT }, \ + { "tzname_max", CTLTYPE_INT }, \ +} +#endif + +/* + * CTL_DEBUG definitions + * + * Second level identifier specifies which debug variable. + * Third level identifier specifies which stucture component. + */ +#define CTL_DEBUG_NAME 0 /* string: variable name */ +#define CTL_DEBUG_VALUE 1 /* int: variable value */ +#define CTL_DEBUG_MAXID 20 + +/* + * Locking and stats + */ +struct sysctl_lock { + int sl_lock; + int sl_want; + int sl_locked; +}; + +#ifdef KERNEL + +#ifdef DEBUG +/* + * CTL_DEBUG variables. + * + * These are declared as separate variables so that they can be + * individually initialized at the location of their associated + * variable. The loader prevents multiple use by issuing errors + * if a variable is initialized in more than one place. They are + * aggregated into an array in debug_sysctl(), so that it can + * conveniently locate them when querried. If more debugging + * variables are added, they must also be declared here and also + * entered into the array. + */ +struct ctldebug { + char *debugname; /* name of debugging variable */ + int *debugvar; /* pointer to debugging variable */ +}; +extern struct ctldebug debug0, debug1, debug2, debug3, debug4; +extern struct ctldebug debug5, debug6, debug7, debug8, debug9; +extern struct ctldebug debug10, debug11, debug12, debug13, debug14; +extern struct ctldebug debug15, debug16, debug17, debug18, debug19; +#endif /* DEBUG */ + +struct sysctl_lock memlock; + +/* + * Internal sysctl function calling convention: + * + * (*sysctlfn)(name, namelen, oldval, oldlenp, newval, newlen); + * + * The name parameter points at the next component of the name to be + * interpreted. The namelen parameter is the number of integers in + * the name. + */ +typedef int (sysctlfn) (int *name, u_int namelen, + void *oldp, size_t *oldlenp, void *newp, size_t newlen); + +/* + * Get old / set new parameters for an integer value. + */ +int sysctl_int (void *oldp, size_t *oldlenp, + void *newp, size_t newlen, int *valp); + +/* + * As above, but read-only. + */ +int sysctl_rdint (void *oldp, size_t *oldlenp, void *newp, int val); + +/* + * Get old / set new parameters for an long value. + */ +int sysctl_long (void *oldp, size_t *oldlenp, + void *newp, size_t newlen, long *valp); + +/* + * As above, but read-only. + */ +int sysctl_rdlong (void *oldp, size_t *oldlenp, void *newp, long val); + +/* + * Get old / set new parameters for a string value. + */ +int sysctl_string (void *oldp, size_t *oldlenp, + void *newp, size_t newlen, char *str, int maxlen); + +/* + * As above, but read-only. + */ +int sysctl_rdstring (void *oldp, size_t *oldlenp, void *newp, const char *str); + +/* + * Get old parameters for a structure. + */ +int sysctl_rdstruct (void *oldp, size_t *oldlenp, + void *newp, void *sp, int len); + +#else /* !KERNEL */ + +int sysctl (int *name, u_int namelen, void *oldp, size_t *oldlenp, + void *newp, size_t newlen); + +int __sysctl (int *name, u_int namelen, void *oldp, size_t *oldlenp, + void *newp, size_t newlen); + +#endif /* KERNEL */ +#endif /* !_SYS_SYSCTL_H_ */ diff --git a/sys/include/syslog.h b/sys/include/syslog.h new file mode 100644 index 0000000..62229e1 --- /dev/null +++ b/sys/include/syslog.h @@ -0,0 +1,171 @@ +/* + * Copyright (c) 1982, 1986, 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. + * + * @(#)syslog.h 8.1.2 (2.11BSD) 1999/06/18 + * $Id: syslog.h,v 1.4 1994/08/21 04:42:00 paul Exp $ + */ + +#ifndef _SYS_SYSLOG_H_ +#define _SYS_SYSLOG_H_ + +#define _PATH_LOG "/dev/log" + +/* + * priorities/facilities are encoded into a single 16-bit quantity, where the + * bottom 3 bits are the priority (0-7) and the top 13 bits are the facility + * (0-big number). Both the priorities and the facilities map roughly + * one-to-one to strings in the syslogd(8) source code. This mapping is + * included in this file. + * + * priorities (these are ordered) + */ +#define LOG_EMERG 0 /* system is unusable */ +#define LOG_ALERT 1 /* action must be taken immediately */ +#define LOG_CRIT 2 /* critical conditions */ +#define LOG_ERR 3 /* error conditions */ +#define LOG_WARNING 4 /* warning conditions */ +#define LOG_NOTICE 5 /* normal but significant condition */ +#define LOG_INFO 6 /* informational */ +#define LOG_DEBUG 7 /* debug-level messages */ + +#define LOG_PRIMASK 0x07 /* mask to extract priority part (internal) */ + /* extract priority */ +#define LOG_PRI(p) ((p) & LOG_PRIMASK) +#define LOG_MAKEPRI(fac, pri) (((fac) << 3) | (pri)) + +#ifdef SYSLOG_NAMES +#define INTERNAL_NOPRI 0x10 /* the "no priority" priority */ + /* mark "facility" */ +#define INTERNAL_MARK LOG_MAKEPRI(LOG_NFACILITIES, 0) +typedef struct _code { + char *c_name; + int c_val; +} CODE; + +CODE prioritynames[] = { + "alert", LOG_ALERT, + "crit", LOG_CRIT, + "debug", LOG_DEBUG, + "emerg", LOG_EMERG, + "err", LOG_ERR, + "info", LOG_INFO, + "none", INTERNAL_NOPRI, /* INTERNAL */ + "notice", LOG_NOTICE, + "warning", LOG_WARNING, + NULL, -1, +}; +#endif + +/* facility codes */ +#define LOG_KERN (0<<3) /* kernel messages */ +#define LOG_USER (1<<3) /* random user-level messages */ +#define LOG_MAIL (2<<3) /* mail system */ +#define LOG_DAEMON (3<<3) /* system daemons */ +#define LOG_AUTH (4<<3) /* security/authorization messages */ +#define LOG_SYSLOG (5<<3) /* messages generated internally by syslogd */ +#define LOG_LPR (6<<3) /* line printer subsystem */ +#define LOG_NEWS (7<<3) /* network news subsystem */ +#define LOG_UUCP (8<<3) /* UUCP subsystem */ +#define LOG_CRON (9<<3) /* clock daemon */ +#define LOG_AUTHPRIV (10<<3) /* security/authorization messages (private) */ +#define LOG_FTP (11<<3) /* ftp daemon */ + + /* other codes through 15 reserved for system use */ +#define LOG_LOCAL0 (16<<3) /* reserved for local use */ +#define LOG_LOCAL1 (17<<3) /* reserved for local use */ +#define LOG_LOCAL2 (18<<3) /* reserved for local use */ +#define LOG_LOCAL3 (19<<3) /* reserved for local use */ +#define LOG_LOCAL4 (20<<3) /* reserved for local use */ +#define LOG_LOCAL5 (21<<3) /* reserved for local use */ +#define LOG_LOCAL6 (22<<3) /* reserved for local use */ +#define LOG_LOCAL7 (23<<3) /* reserved for local use */ + +#define LOG_NFACILITIES 24 /* current number of facilities */ +#define LOG_FACMASK 0x03f8 /* mask to extract facility part */ + /* facility of pri */ +#define LOG_FAC(p) (((p) & LOG_FACMASK) >> 3) + +#ifdef SYSLOG_NAMES +CODE facilitynames[] = { + "auth", LOG_AUTH, + "authpriv", LOG_AUTHPRIV, + "cron", LOG_CRON, + "daemon", LOG_DAEMON, + "ftp", LOG_FTP, + "kern", LOG_KERN, + "lpr", LOG_LPR, + "mail", LOG_MAIL, + "mark", INTERNAL_MARK, /* INTERNAL */ + "news", LOG_NEWS, + "syslog", LOG_SYSLOG, + "user", LOG_USER, + "uucp", LOG_UUCP, + "local0", LOG_LOCAL0, + "local1", LOG_LOCAL1, + "local2", LOG_LOCAL2, + "local3", LOG_LOCAL3, + "local4", LOG_LOCAL4, + "local5", LOG_LOCAL5, + "local6", LOG_LOCAL6, + "local7", LOG_LOCAL7, + NULL, -1, +}; +#endif + +#ifdef KERNEL +#define LOG_PRINTF -1 /* pseudo-priority to indicate use of printf */ +#else +void syslog (int pri, const char *fmt, ...); +void openlog (const char *ident, int logstat, int logfac); +void closelog (void); +#endif + +/* + * arguments to setlogmask. + */ +#define LOG_MASK(pri) (1 << (pri)) /* mask for one priority */ +#define LOG_UPTO(pri) ((1 << ((pri)+1)) - 1) /* all priorities through pri */ + +/* + * Option flags for openlog. + * + * LOG_ODELAY no longer does anything. + * LOG_NDELAY is the inverse of what it used to be. + */ +#define LOG_PID 0x01 /* log the pid with each message */ +#define LOG_CONS 0x02 /* log on the console if errors in sending */ +#define LOG_ODELAY 0x04 /* delay open until first syslog() (default) */ +#define LOG_NDELAY 0x08 /* don't delay open */ +#define LOG_NOWAIT 0x10 /* don't wait for console forks: DEPRECATED */ +#define LOG_PERROR 0x20 /* log to stderr as well */ + +#endif diff --git a/sys/include/systm.h b/sys/include/systm.h new file mode 100644 index 0000000..a00885e --- /dev/null +++ b/sys/include/systm.h @@ -0,0 +1,275 @@ +/* + * Copyright (c) 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +/* + * The `securelevel' variable controls the security level of the system. + * It can only be decreased by process 1 (/sbin/init). + * + * Security levels are as follows: + * -1 permannently insecure mode - always run system in level 0 mode. + * 0 insecure mode - immutable and append-only flags make be turned off. + * All devices may be read or written subject to permission modes. + * 1 secure mode - immutable and append-only flags may not be changed; + * raw disks of mounted filesystems, /dev/mem, and /dev/kmem are + * read-only. + * 2 highly secure mode - same as (1) plus raw disks are always + * read-only whether mounted or not. This level precludes tampering + * with filesystems by unmounting them, but also inhibits running + * newfs while the system is secured. + * + * In normal operation, the system runs in level 0 mode while single user + * and in level 1 mode while multiuser. If level 2 mode is desired while + * running multiuser, it can be set in the multiuser startup script + * (/etc/rc.local) using sysctl(8). If it is desired to run the system + * in level 0 mode while multiuser, initialize the variable securelevel + * in /sys/kern/kern_sysctl.c to -1. Note that it is NOT initialized to + * zero as that would allow the vmunix binary to be patched to -1. + * Without initialization, securelevel loads in the BSS area which only + * comes into existence when the kernel is loaded and hence cannot be + * patched by a stalking hacker. + */ +#include "conf.h" +extern int securelevel; /* system security level */ + +extern const char version[]; /* system version */ + +/* + * Nblkdev is the number of entries (rows) in the block switch. + * Used in bounds checking on major device numbers. + */ +extern const int nblkdev; + +/* + * Number of character switch entries. + */ +extern const int nchrdev; + +/* + * Number of system call entries. + */ +extern const int nsysent; + +extern int mpid; /* generic for unique process id's */ +extern char runin; /* scheduling flag */ +extern char runout; /* scheduling flag */ +extern int runrun; /* scheduling flag */ +extern char curpri; /* more scheduling */ + +extern u_int swapstart, nswap; /* start and size of swap space */ +extern int updlock; /* lock for sync */ +extern daddr_t rablock; /* block to be read ahead */ +extern dev_t rootdev; /* device of the root */ +extern dev_t dumpdev; /* device to take dumps on */ +extern long dumplo; /* offset into dumpdev */ +extern dev_t swapdev; /* swapping device */ +extern dev_t pipedev; /* pipe device */ + +extern const char icode[]; /* user init code */ +extern const char icodeend[]; /* its end */ + +struct inode; +daddr_t bmap (struct inode *ip, daddr_t bn, int rwflg, int flags); + +extern void kmemdev(); + +/* + * Structure of the system-entry table + */ +extern const struct sysent +{ + int sy_narg; /* total number of arguments */ + void (*sy_call) (void); /* handler */ +} sysent[]; + +extern const char *syscallnames[]; + +extern int noproc; /* no one is running just now */ +extern char *panicstr; +extern int boothowto; /* reboot flags, from boot */ +extern int selwait; +extern size_t physmem; /* total amount of physical memory */ + +extern dev_t get_cdev_by_name(char *); +extern char *cdevname(dev_t dev); + +void panic (char *msg); +void printf (char *fmt, ...); +void uprintf (char *fmt, ...); /* print to the current user's terminal */ +struct tty; +void tprintf (struct tty *tp, char *fmt, ...); /* print to the specified terminal */ +int loginit (void); +void log (int level, char *fmt, ...); +int logwrt (char *buf, int len, int log); +void logwakeup (int unit); +void cpuidentify (void); +void cninit (void); +void cnidentify (void); +void cnputc (char c); +int cngetc (void); +int baduaddr (caddr_t addr); /* detect bad user address */ +int badkaddr (caddr_t addr); /* detect bad kernel address */ + +int strncmp (const char *s1, const char *s2, size_t n); +void bzero (void *s, size_t nbytes); +void bcopy (const void *src, void *dest, size_t nbytes); +int bcmp (const void *a, const void *b, size_t nbytes); +int copystr (caddr_t src, caddr_t dest, u_int maxlen, u_int *copied); +size_t strlen (const char *s); +int ffs (u_long i); /* find the index of the lsb set bit */ +void insque (void *element, void *pred); +void remque (void *element); + +void startup (void); /* machine-dependent startup code */ +int chrtoblk (dev_t dev); /* convert from character to block device number */ +int blktochr (dev_t dev); /* convert from block to character device number */ +int isdisk (dev_t dev, int type); /* determine if a device is a disk */ +int iskmemdev (dev_t dev); /* identify /dev/mem and /dev/kmem */ +void boot (dev_t dev, int howto); + +/* + * Copy data from kernel space fromaddr to user space address toaddr. + * Fromaddr and toaddr must be word aligned. Returns zero on success, + * EFAULT on failure. + */ +int copyout (const caddr_t from, caddr_t to, u_int nbytes); + +/* + * Copy data from user space fromaddr to kernel space address toaddr. + * Fromaddr and toaddr must be word aligned. Returns zero on success, + * EFAULT on failure. + */ +int copyin (const caddr_t from, caddr_t to, u_int nbytes); + +/* + * Check if gid is a member of the group set. + */ +int groupmember (gid_t gid); + +/* + * Wake up all processes sleeping on chan. + */ +void wakeup (caddr_t chan); + +/* + * Allocate iostat disk monitoring slots for a driver. + */ +void dk_alloc (int *dkn, int slots, char *name); + +/* + * Initialize callouts. + */ +void coutinit (void); + +/* + * Syscalls. + */ +void nosys (void); + +/* 1.1 processes and protection */ +void getpid (void); +void getppid (void), fork (void), rexit (void), execv (void), execve (void); +void wait4 (void), getuid (void), getgid (void), getgroups (void), setgroups (void); +void geteuid (void), getegid (void); +void getpgrp (void), setpgrp (void); +void setgid (void), setegid (void), setuid (void), seteuid (void); +void ucall (void); /* 2BSD calls */ + +/* 1.2 memory management */ +void brk (void); +void ustore (void); /* 2BSD calls */ +void ufetch (void); /* 2BSD calls */ + +/* 1.3 signals */ +void sigstack (void), sigreturn (void); +void sigaction (void), sigprocmask (void), sigpending (void), sigaltstack (void), sigsuspend (void); +void sigwait (void), kill (void), killpg (void); + +/* 1.4 timing and statistics */ +void gettimeofday (void), settimeofday (void); +void getitimer (void), setitimer (void); +void adjtime (void); + +/* 1.5 descriptors */ +void getdtablesize (void), dup (void), dup2 (void), close (void); +void pselect (void), select (void), fcntl (void), flock (void); + +/* 1.6 resource controls */ +void getpriority (void), setpriority (void), getrusage (void), getrlimit (void), setrlimit (void); + +/* 1.7 system operation support */ +void umount (void), smount (void); +void sync (void), reboot (void), __sysctl (void); + +/* 2.1 generic operations */ +void read (void), write (void), readv (void), writev (void), ioctl (void); + +/* 2.2 file system */ +void chdir (void), fchdir (void), chroot (void); +void mkdir (void), rmdir (void), chflags (void), fchflags (void); +void open (void), mknod (void), unlink (void), stat (void), fstat (void), lstat (void); +void chown (void), fchown (void), chmod (void), fchmod (void), utimes (void); +void link (void), symlink (void), readlink (void), rename (void); +void lseek (void), truncate (void), ftruncate (void), saccess (void), fsync (void); +void statfs (void), fstatfs (void), getfsstat (void); + +/* 2.3 communications */ +void socket (void), bind (void), listen (void), accept (void), connect (void); +void socketpair (void), sendto (void), send (void), recvfrom (void), recv (void); +void sendmsg (void), recvmsg (void), shutdown (void), setsockopt (void), getsockopt (void); +void getsockname (void), getpeername (void), pipe (void); + +void umask (void); /* XXX */ + +/* 2.4 processes */ +void ptrace (void); + +void profil (void); /* 'cuz sys calls are interruptible */ +void vhangup (void); /* should just do in exit (void) */ +void vfork (void); /* awaiting fork w/ copy on write */ + +/* + * Drivers. + */ +struct buf; +struct uio; + +void cninit(); +int cnopen (dev_t dev, int flag, int mode); +int cnclose (dev_t dev, int flag, int mode); +int cnread (dev_t dev, struct uio *uio, int flag); +int cnwrite (dev_t dev, struct uio *uio, int flag); +int cnioctl (dev_t dev, u_int cmd, caddr_t addr, int flag); +int cnselect (dev_t dev, int rw); + +extern const struct devspec cndevs[]; +extern const struct devspec mmdevs[]; +extern const struct devspec sydevs[]; +extern const struct devspec logdevs[]; +extern const struct devspec fddevs[]; + +#ifdef TS_ISOPEN +extern struct tty cnttys[]; +#endif + +int mmrw (dev_t dev, struct uio *uio, int flag); +int seltrue (dev_t dev, int rw); +void nostrategy (struct buf *bp); +void nonet (void); + +int syopen (dev_t dev, int flag, int mode); +int syread (dev_t dev, struct uio *uio, int flag); +int sywrite (dev_t dev, struct uio *uio, int flag); +int syioctl (dev_t dev, u_int cmd, caddr_t addr, int flag); +int syselect (dev_t dev, int rw); + +int logopen (dev_t dev, int flag, int mode); +int logclose (dev_t dev, int flag, int mode); +int logread (dev_t dev, struct uio *uio, int flag); +int logioctl (dev_t dev, u_int cmd, caddr_t addr, int flag); +int logselect (dev_t dev, int rw); + +int fdopen (dev_t dev, int flag, int mode); +int dupfdopen (int indx, int dfd, int mode, int error); diff --git a/sys/include/time.h b/sys/include/time.h new file mode 100644 index 0000000..35d6254 --- /dev/null +++ b/sys/include/time.h @@ -0,0 +1,114 @@ +/* + * Copyright (c) 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +#ifndef _SYS_TIME_H_ +#define _SYS_TIME_H_ + +#include + +/* + * Structure returned by gettimeofday(2) system call, + * and used in other calls. + */ +struct timeval { + long tv_sec; /* seconds */ + long tv_usec; /* and microseconds */ +}; + +/* + * Structure defined by POSIX.4 to be like a timeval but with nanoseconds + * instead of microseconds. Silly on a PDP-11 but keeping the names the + * same makes life simpler than changing the names. +*/ +struct timespec { + time_t tv_sec; /* seconds */ + long tv_nsec; /* and nanoseconds */ +}; + +struct timezone { + int tz_minuteswest; /* minutes west of Greenwich */ + int tz_dsttime; /* type of dst correction */ +}; +#define DST_NONE 0 /* not on dst */ +#define DST_USA 1 /* USA style dst */ +#define DST_AUST 2 /* Australian style dst */ +#define DST_WET 3 /* Western European dst */ +#define DST_MET 4 /* Middle European dst */ +#define DST_EET 5 /* Eastern European dst */ +#define DST_CAN 6 /* Canada */ + +/* + * Operations on timevals. + * + * NB: timercmp does not work for >= or <=. + */ +#define timerisset(tvp) ((tvp)->tv_sec || (tvp)->tv_usec) +#define timercmp(tvp, uvp, cmp) \ + ((tvp)->tv_sec cmp (uvp)->tv_sec || \ + (tvp)->tv_sec == (uvp)->tv_sec && (tvp)->tv_usec cmp (uvp)->tv_usec) +#define timerclear(tvp) (tvp)->tv_sec = (tvp)->tv_usec = 0 + +/* + * Names of the interval timers, and structure + * defining a timer setting. + */ +#define ITIMER_REAL 0 +#define ITIMER_VIRTUAL 1 +#define ITIMER_PROF 2 + +struct k_itimerval { + long it_interval; /* timer interval */ + long it_value; /* current value */ +}; + +struct itimerval { + struct timeval it_interval; /* timer interval */ + struct timeval it_value; /* current value */ +}; + +#ifdef KERNEL +/* + * Round up a proposed time value to a minimal resolution of the clock. + */ +int itimerfix (struct timeval *tv); + +/* + * Add and subtract routines for timevals. + */ +void timevaladd (struct timeval *t1, struct timeval *t2); +void timevalsub (struct timeval *t1, struct timeval *t2); + +/* + * Compute number of hz until specified time. + */ +int hzto (struct timeval *tv); + +#else +#include + +int gettimeofday (struct timeval *tv, struct timezone *tz); +int utimes (const char *filename, const struct timeval times[2]); +int getitimer (int which, struct itimerval *curr_value); +int setitimer (int which, const struct itimerval *new_value, + struct itimerval *old_value); +int getpriority (int which, int who); +int setpriority (int which, int who, int prio); +char *tztab (int zone, int dst); + +#endif + +/* + * Getkerninfo clock information structure + */ +struct clockinfo { + int hz; /* clock frequency */ + int tick; /* micro-seconds per hz tick */ + int stathz; /* statistics clock frequency */ + int profhz; /* profiling clock frequency */ +}; + +extern unsigned int msec(); +#endif /* !_SYS_TIME_H_ */ diff --git a/sys/include/times.h b/sys/include/times.h new file mode 100644 index 0000000..546e7d1 --- /dev/null +++ b/sys/include/times.h @@ -0,0 +1,17 @@ +/* + * Copyright (c) 1982, 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + * + * @(#)times.h 7.1 (Berkeley) 6/4/86 + */ + +/* + * Structure returned by times() + */ +struct tms { + time_t tms_utime; /* user time */ + time_t tms_stime; /* system time */ + time_t tms_cutime; /* user time, children */ + time_t tms_cstime; /* system time, children */ +}; diff --git a/sys/include/trace.h b/sys/include/trace.h new file mode 100644 index 0000000..87bfa3c --- /dev/null +++ b/sys/include/trace.h @@ -0,0 +1,85 @@ +/* + * Copyright (c) 1982, 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +/* + * File system buffer tracing points; all trace + * + * Slipped into 2.10 in about 15 minutes. Bears only a casual + * relationship to the 4.X code, we just used the same names so + * someone could do it right if they felt like it. Note that + * the #defines aren't even sequentially numbered. + */ +#define TR_BREADHIT 0 /* buffer read found in cache */ +#define TR_BREADMISS 1 /* buffer read not in cache */ +#define TR_BWRITE 2 /* buffer written */ +#define TR_BREADHITRA 3 /* buffer read-ahead found in cache */ +#define TR_BREADMISSRA 4 /* buffer read-ahead not in cache */ +#define TR_BRELSE 5 /* brelse */ +#define TR_SWAPIO 6 /* swap i/o request arrives */ +#define TR_NUM_210 7 /* size of array for 2.10BSD */ + +#define TR_XFODMISS 5 /* exe fod read */ +#define TR_XFODHIT 6 /* exe fod read */ +#define TR_BREALLOC 8 /* expand/contract a buffer */ + +/* + * Memory allocator trace points; all trace the amount of memory involved + */ +#define TR_MALL 10 /* memory allocated */ + +/* + * Paging trace points: all are + */ +#define TR_INTRANS 20 /* page intransit block */ +#define TR_EINTRANS 21 /* page intransit wait done */ +#define TR_FRECLAIM 22 /* reclaim from free list */ +#define TR_RECLAIM 23 /* reclaim from loop */ +#define TR_XSFREC 24 /* reclaim from free list instead of drum */ +#define TR_XIFREC 25 /* reclaim from free list instead of fsys */ +#define TR_WAITMEM 26 /* wait for memory in pagein */ +#define TR_EWAITMEM 27 /* end memory wait in pagein */ +#define TR_ZFOD 28 /* zfod page fault */ +#define TR_EXFOD 29 /* exec fod page fault */ +#define TR_VRFOD 30 /* vread fod page fault */ +#define TR_CACHEFOD 31 /* fod in file system cache */ +#define TR_SWAPIN 32 /* drum page fault */ +#define TR_PGINDONE 33 /* page in done */ + +/* + * System call trace points. + */ +#define TR_VADVISE 40 /* vadvise occurred with */ + +/* + * Miscellaneous + */ +#define TR_STAMP 45 /* user said vtrace(VTR_STAMP, value); */ + +/* + * This defines the size of the trace flags array. + */ +#define TR_NFLAGS 100 /* generous */ + +#define TRCSIZ 4096 + +/* + * Specifications of the vtrace() system call, which takes one argument. + */ +#define VTRACE 64+51 + +#define VTR_DISABLE 0 /* set a trace flag to 0 */ +#define VTR_ENABLE 1 /* set a trace flag to 1 */ +#define VTR_VALUE 2 /* return value of a trace flag */ +#define VTR_UALARM 3 /* set alarm to go off (sig 16) */ + /* in specified number of hz */ +#define VTR_STAMP 4 /* user specified stamp */ + +#if defined(KERNEL) && defined(UCB_METER) +u_long tracebuf[TR_NUM_210]; +#define trace(a) tracebuf[a]++; +#else +#define trace(a) ; +#endif diff --git a/sys/include/tty.h b/sys/include/tty.h new file mode 100644 index 0000000..918e161 --- /dev/null +++ b/sys/include/tty.h @@ -0,0 +1,247 @@ +#ifndef _TTY_H +#define _TTY_H +/* + * Copyright (c) 1982, 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#ifdef KERNEL +#include "types.h" +#include "ttychars.h" +#include "ttydev.h" +#include "ioctl.h" +#else +#include +#include +#include +#include +#endif + +/* + * A clist structure is the head of a linked list queue + * of characters. The characters are stored in blocks + * containing a link and CBSIZE (param.h) characters. + * The routines in tty_subr.c manipulate these structures. + */ +struct clist { + int c_cc; /* character count */ + char *c_cf; /* pointer to first char */ + char *c_cl; /* pointer to last char */ +}; + +/* + * Per-tty structure. + * + * Should be split in two, into device and tty drivers. + * Glue could be masks of what to echo and circular buffer + * (low, high, timeout). + */ +struct tty { + union { + struct { + struct clist T_rawq; + struct clist T_canq; + } t_t; +#define t_rawq t_nu.t_t.T_rawq /* raw characters or partial line */ +#define t_canq t_nu.t_t.T_canq /* raw characters or partial line */ + struct { + struct buf *T_bufp; + char *T_cp; + int T_inbuf; + int T_rec; + } t_n; +#define t_bufp t_nu.t_n.T_bufp /* buffer allocated to protocol */ +#define t_cp t_nu.t_n.T_cp /* pointer into the ripped off buffer */ +#define t_inbuf t_nu.t_n.T_inbuf /* number chars in the buffer */ +#define t_rec t_nu.t_n.T_rec /* have a complete record */ + } t_nu; + struct clist t_outq; /* device */ + void (*t_oproc) (struct tty*); + struct proc *t_rsel; /* tty */ + struct proc *t_wsel; + caddr_t T_LINEP; /* ### */ + caddr_t t_addr; /* ??? */ + dev_t t_dev; /* device */ + long t_flags; /* some of both */ + long t_state; /* some of both */ + int t_pgrp; /* tty */ + int t_delct; /* tty */ + int t_col; /* tty */ + int t_ispeed, t_ospeed; /* device */ + int t_rocount, t_rocol; /* tty */ + struct ttychars t_chars; /* tty */ + struct winsize t_winsize; /* window size */ +/* be careful of tchars & co. */ +#define t_erase t_chars.tc_erase +#define t_kill t_chars.tc_kill +#define t_intrc t_chars.tc_intrc +#define t_quitc t_chars.tc_quitc +#define t_startc t_chars.tc_startc +#define t_stopc t_chars.tc_stopc +#define t_eofc t_chars.tc_eofc +#define t_brkc t_chars.tc_brkc +#define t_suspc t_chars.tc_suspc +#define t_dsuspc t_chars.tc_dsuspc +#define t_rprntc t_chars.tc_rprntc +#define t_flushc t_chars.tc_flushc +#define t_werasc t_chars.tc_werasc +#define t_lnextc t_chars.tc_lnextc +}; + +#define TTIPRI 28 +#define TTOPRI 29 + +/* limits */ +#define NSPEEDS 29 +#define TTMASK 15 +#define OBUFSIZ 100 + +#ifdef KERNEL + +extern const int tthiwat[NSPEEDS], ttlowat[NSPEEDS]; +extern int q_to_b(register struct clist *q, char *cp, int cc); + +#define TTHIWAT(tp) tthiwat[(tp)->t_ospeed&TTMASK] +#define TTLOWAT(tp) ttlowat[(tp)->t_ospeed&TTMASK] + +extern int nldisp; /* number of line disciplines */ + +/* + * Set t_chars to default values. + */ +void ttychars (struct tty *tp); + +/* + * Clean terminal on last close. + */ +void ttyclose (struct tty *tp); + +/* + * Wakeup processes waiting on output flow control. + */ +void ttyowake (struct tty *tp); + +/* + * Get a symbol from a character list. + */ +int getc (struct clist *p); + +/* + * Get the pointer to the next character in the list. + */ +char *nextc (struct clist *p, char *cp); + +/* + * Put a symbol to a character list. + */ +int putc (int c, struct clist *p); + +/* + * Remove the last character in the list and return it. + */ +int unputc (struct clist *p); + +/* + * Put the chars in the from que on the end of the to que. + */ +void catq (struct clist *from, struct clist *to); + +/* + * Copy buffer to clist. + */ +int b_to_q (char *cp, int nbytes, struct clist *q); + +/* + * Common code for tty ioctls. + */ +int ttioctl (struct tty *tp, u_int com, caddr_t data, int flag); + +/* + * Start output on the typewriter. + */ +void ttstart (struct tty *tp); + +void ttwakeup (struct tty *tp); + +/* + * Place a character on raw TTY input queue, + */ +void ttyinput (int c, struct tty *tp); + +/* + * Put character on TTY output queue. + */ +int ttyoutput (int c, struct tty *tp); + +/* + * Initial open of tty, or (re)entry to line discipline. + */ +int ttyopen (dev_t dev, struct tty *tp); + +/* + * Close a line discipline. + */ +int ttylclose (struct tty *tp, int flag); + +/* + * Check the output queue for space. + */ +int ttycheckoutq (struct tty *tp, int wait); + +/* + * Called from device's read routine after it has + * calculated the tty-structure given as argument. + */ +struct uio; +int ttread (struct tty *tp, struct uio *uio, int flag); +int ttwrite (struct tty *tp, struct uio *uio, int flag); + +/* + * Handle modem control transition on a tty. + */ +int ttymodem (struct tty *tp, int flag); + +/* + * Check that input or output is possible on a terminal. + */ +int ttyselect (struct tty *tp, int rw); + +/* + * Flush all TTY queues. + */ +void ttyflush (struct tty *tp, int rw); + +#endif /* KERNEL */ + +/* internal state bits */ +#define TS_TIMEOUT 0x000001L /* delay timeout in progress */ +#define TS_WOPEN 0x000002L /* waiting for open to complete */ +#define TS_ISOPEN 0x000004L /* device is open */ +#define TS_FLUSH 0x000008L /* outq has been flushed during DMA */ +#define TS_CARR_ON 0x000010L /* software copy of carrier-present */ +#define TS_BUSY 0x000020L /* output in progress */ +#define TS_ASLEEP 0x000040L /* wakeup when output done */ +#define TS_XCLUDE 0x000080L /* exclusive-use flag against open */ +#define TS_TTSTOP 0x000100L /* output stopped by ctl-s */ +#define TS_HUPCLS 0x000200L /* hang up upon last close */ +#define TS_TBLOCK 0x000400L /* tandem queue blocked */ +#define TS_RCOLL 0x000800L /* collision in read select */ +#define TS_WCOLL 0x001000L /* collision in write select */ +#define TS_ASYNC 0x004000L /* tty in async i/o mode */ +/* state for intra-line fancy editing work */ +#define TS_ERASE 0x040000L /* within a \.../ for PRTRUB */ +#define TS_LNCH 0x080000L /* next character is literal */ +#define TS_TYPEN 0x100000L /* retyping suspended input (PENDIN) */ +#define TS_CNTTB 0x200000L /* counting tab width; leave FLUSHO alone */ + +#define TS_LOCAL (TS_ERASE|TS_LNCH|TS_TYPEN|TS_CNTTB) + +/* define partab character types */ +#define ORDINARY 0 +#define CONTROL 1 +#define BACKSPACE 2 +#define NEWLINE 3 +#define TAB 4 +#define VTAB 5 +#define RETURN 6 +#endif diff --git a/sys/include/ttychars.h b/sys/include/ttychars.h new file mode 100644 index 0000000..c2f09d3 --- /dev/null +++ b/sys/include/ttychars.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 1982, 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + * + * @(#)ttychars.h 7.2 (2.11BSD) 1997/4/15 + */ + +/* + * User visible structures and constants + * related to terminal handling. + */ +#ifndef _TTYCHARS_ +#define _TTYCHARS_ +struct ttychars { + char tc_erase; /* erase last character */ + char tc_kill; /* erase entire line */ + char tc_intrc; /* interrupt */ + char tc_quitc; /* quit */ + char tc_startc; /* start output */ + char tc_stopc; /* stop output */ + char tc_eofc; /* end-of-file */ + char tc_brkc; /* input delimiter (like nl) */ + char tc_suspc; /* stop process signal */ + char tc_dsuspc; /* delayed stop process signal */ + char tc_rprntc; /* reprint line */ + char tc_flushc; /* flush output (toggles) */ + char tc_werasc; /* word erase */ + char tc_lnextc; /* literal next character */ +}; + +#define CTRL(c) (c & 037) +#define _POSIX_VDISABLE ((unsigned char)'\377') +#define CCEQ(val,c) (c == val ? val != _POSIX_VDISABLE : 0) + +/* default special characters */ +#define CERASE 0177 +#define CKILL CTRL('u') +#define CINTR CTRL('c') +#define CQUIT CTRL('\\') +#define CSTART CTRL('q') +#define CSTOP CTRL('s') +#define CEOF CTRL('d') +#define CEOT CEOF +#define CBRK _POSIX_VDISABLE +#define CSUSP CTRL('z') +#define CDSUSP CTRL('y') +#define CRPRNT CTRL('r') +#define CFLUSH CTRL('o') +#define CWERASE CTRL('w') +#define CLNEXT CTRL('v') +#endif /* _TTYCHARS_ */ diff --git a/sys/include/ttydev.h b/sys/include/ttydev.h new file mode 100644 index 0000000..34455ba --- /dev/null +++ b/sys/include/ttydev.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 1982, 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + * + * @(#)ttydev.h 7.1 (Berkeley) 6/4/86 + */ + +/* + * Terminal definitions related to underlying hardware. + */ +#ifndef _TTYDEV_ +#define _TTYDEV_ + +/* + * Speeds + */ +#define B0 0 +#define B50 1 +#define B75 2 +#define B150 3 +#define B200 4 +#define B300 5 +#define B600 6 +#define B1200 7 +#define B1800 8 +#define B2400 9 +#define B4800 10 +#define B9600 11 +#define B19200 12 +#define B38400 13 +#define B57600 14 +#define B115200 15 +#define B230400 16 +#define B460800 17 +#define B500000 18 +#define B576000 19 +#define B921600 20 +#define B1000000 21 +#define B1152000 22 +#define B1500000 23 +#define B2000000 24 +#define B2500000 25 +#define B3000000 26 +#define B3500000 27 +#define B4000000 28 + +#ifdef KERNEL +/* + * Modem control commands. + */ +#define DMSET 0 +#define DMBIS 1 +#define DMBIC 2 +#define DMGET 3 +#endif +#endif diff --git a/sys/include/types.h b/sys/include/types.h new file mode 100644 index 0000000..6baef8c --- /dev/null +++ b/sys/include/types.h @@ -0,0 +1,93 @@ +/* + * Copyright (c) 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +#ifndef _SYS_TYPES_H_ +#define _SYS_TYPES_H_ + +/* + * Basic system types and major/minor device constructing/busting macros. + */ + +/* major part of a device */ +#define major(x) ((int)(((int)(x)>>8)&0377)) + +/* minor part of a device */ +#define minor(x) ((int)((x)&0377)) + +/* make a device number */ +#define makedev(x,y) ((dev_t)(((x)<<8) | (y))) + +typedef unsigned char u_char; +typedef unsigned short u_short; +typedef unsigned int u_int; +typedef unsigned long u_long; /* see this! unsigned longs at last! */ +typedef unsigned short ushort; /* sys III compat */ + +#ifdef pdp11 +typedef struct label_t { + int val[7]; /* regs 2-7 and super SP */ +} label_t; +#endif +#ifdef __mips__ +typedef struct label_t { + unsigned val[12]; /* regs S0-S8, RA, GP and SP */ +} label_t; +#endif +typedef long daddr_t; +typedef char * caddr_t; +typedef u_int ino_t; +#ifndef _SIZE_T +#define _SIZE_T +typedef u_int size_t; +#endif +#ifndef __ssize_t_defined +#ifndef _SSIZE_T +typedef int ssize_t; +#define __ssize_t_defined +#define _SSIZE_T +#endif +#endif +typedef long time_t; +typedef int dev_t; +#ifndef _OFF_T +#define _OFF_T +typedef long off_t; +#endif +typedef u_int uid_t; +typedef u_int gid_t; +typedef int pid_t; +typedef u_int mode_t; +typedef int bool_t; /* boolean */ +#define _PID_T +#define _UID_T +#define _GID_T +#define _INO_T +#define _DEV_T +#define _TIME_T +#define _MODE_T + +#define NBBY 8 /* number of bits in a byte */ + +#ifndef howmany +#define howmany(x, y) (((x)+((y)-1))/(y)) +#endif + +#include + +#ifdef KERNEL +/* + * Save the process' current register context. + */ +int setjmp (label_t *env); + +/* + * Map in a user structure and jump to a saved context. + */ +void longjmp (size_t unew, label_t *env); + +#endif /* KERNEL */ + +#endif diff --git a/sys/include/uart.h b/sys/include/uart.h new file mode 100644 index 0000000..205f982 --- /dev/null +++ b/sys/include/uart.h @@ -0,0 +1,65 @@ +#ifndef _UART_H +#define _UART_H + +#include "tty.h" + +#define NUART 6 +#define UART_MAJOR 12 + +#ifdef KERNEL +#include "conf.h" + +struct uart_irq { + int er; + int rx; + int tx; +}; + +extern const struct uart_irq uirq[NUART]; + +/* + * PIC32 UART registers. + */ +struct uartreg { + volatile unsigned mode; /* Mode */ + volatile unsigned modeclr; + volatile unsigned modeset; + volatile unsigned modeinv; + volatile unsigned sta; /* Status and control */ + volatile unsigned staclr; + volatile unsigned staset; + volatile unsigned stainv; + volatile unsigned txreg; /* Transmit */ + volatile unsigned unused1; + volatile unsigned unused2; + volatile unsigned unused3; + volatile unsigned rxreg; /* Receive */ + volatile unsigned unused4; + volatile unsigned unused5; + volatile unsigned unused6; + volatile unsigned brg; /* Baud rate */ + volatile unsigned brgclr; + volatile unsigned brgset; + volatile unsigned brginv; +}; + +extern struct tty uartttys[NUART]; +extern struct uartreg *uart[NUART]; +extern void uartinit(); +extern int uartopen (dev_t dev, int flag, int mode); +extern int uartclose (dev_t dev, int flag, int mode); +extern int uartread (dev_t dev, struct uio * uio, int flag); +extern int uartwrite (dev_t dev, struct uio *uio, int flag); +extern int uartselect (register dev_t dev, int rw); +extern int uartioctl (dev_t dev, register u_int cmd, caddr_t addr, int flag); +extern void uartintr(dev_t dev); +extern void uartstart (register struct tty *tp); +extern void uartputc(dev_t dev, char c); +extern char uartgetc(dev_t dev); + +extern const struct devspec uartdevs[]; +extern unsigned int uart_major; + +#endif + +#endif diff --git a/sys/include/uio.h b/sys/include/uio.h new file mode 100644 index 0000000..09e79ed --- /dev/null +++ b/sys/include/uio.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 1982, 1986, 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. + * + * Copied from 4.4-Lite and modified for 2.11BSD. Modifications were removal + * of prototypes, limits for dynamic allocation of iovec structs and changing + * uio_resid to u_int from int. + */ + +#ifndef _SYS_UIO_H_ +#define _SYS_UIO_H_ + +#include "types.h" + +/* + * XXX + * iov_base should be a void *. + */ +struct iovec { + char *iov_base; /* Base address. */ + size_t iov_len; /* Length. */ +}; + +enum uio_rw { UIO_READ, UIO_WRITE }; + +struct uio { + struct iovec *uio_iov; + int uio_iovcnt; + off_t uio_offset; + u_int uio_resid; + enum uio_rw uio_rw; +}; + +#ifdef KERNEL +/* + * Move data to/from user space. + */ +int uiomove (caddr_t cp, u_int n, struct uio *uio); + +/* + * Give next character to user as result of read. + */ +int ureadc (int c, struct uio *uio); + +#else /* !KERNEL */ + +ssize_t readv (int fd, const struct iovec *iov, int iovcnt); + +ssize_t writev (int fd, const struct iovec *iov, int iovcnt); + +#endif /* KERNEL */ +#endif /* !_SYS_UIO_H_ */ diff --git a/sys/include/usb_uart.h b/sys/include/usb_uart.h new file mode 100644 index 0000000..6b42caa --- /dev/null +++ b/sys/include/usb_uart.h @@ -0,0 +1,47 @@ +/* + * Console driver via USB. + * + * Copyright (C) 2011 Serge Vakulenko, + * + * 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 the copyright notice and this + * permission notice and warranty disclaimer appear in supporting + * documentation, and that the name of the author not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * + * The author disclaim all warranties with regard to this + * software, including all implied warranties of merchantability + * and fitness. In no event shall the author 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. + */ +#ifndef _USB_UART_H +#define _USB_UART_H + +#include "conf.h" + +extern const struct devspec usbdevs[]; +extern unsigned int usb_major; + +#define USB_MAJOR 13 + +extern struct tty usbttys[1]; +extern void usbinit(); +extern int usbopen(dev_t dev, int flag, int mode); +extern int usbclose(dev_t dev, int flag, int mode); +extern int usbread(dev_t dev, struct uio *uio, int flag); +extern int usbwrite(dev_t dev, struct uio *uio, int flag); +extern int usbioctl(dev_t dev, register u_int cmd, caddr_t addr, int flag); +extern int usbselect(dev_t dev, int rw); +extern void usbstart (register struct tty *tp); +extern void usbputc(dev_t dev, char c); +extern char usbgetc(dev_t dev); +extern void usbintr(int chan); + +#endif diff --git a/sys/include/user.h b/sys/include/user.h new file mode 100644 index 0000000..0128556 --- /dev/null +++ b/sys/include/user.h @@ -0,0 +1,113 @@ +/* + * Copyright (c) 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#ifdef KERNEL +#include "dir.h" +#include "exec.h" +#include "time.h" +#include "resource.h" +#else +#include +#include +#include +#include +#endif + +/* + * data that doesn't need to be referenced while the process is swapped. + * For PIC32, the user block is USIZE bytes long; resides at virtual kernel loc + * 0x80007400; contains the system stack (and possibly network stack) per + * user; is cross referenced with the proc structure for the same process. + */ +#define MAXCOMLEN MAXNAMLEN /* <= MAXNAMLEN, >= sizeof(ac_comm) */ + +struct user { + struct proc *u_procp; /* pointer to proc structure */ + int *u_frame; /* address of users saved frame */ + char u_comm[MAXCOMLEN + 1]; /* command file name */ + label_t u_qsave; /* for non-local gotos on interrupts */ + label_t u_rsave; /* save info when exchanging stacks */ + label_t u_ssave; /* label variable for swapping */ + +/* syscall parameters and results */ + int u_arg[6]; /* arguments to current system call */ + int u_rval; /* return value */ + int u_error; /* return error code */ + +/* 1.1 - processes and protection */ + uid_t u_uid; /* effective user id */ + uid_t u_svuid; /* saved user id */ + uid_t u_ruid; /* real user id */ + gid_t u_svgid; /* saved group id */ + gid_t u_rgid; /* real group id */ + gid_t u_groups[NGROUPS]; /* groups, 0 terminated */ + +/* 1.2 - memory management */ + size_t u_tsize; /* text size (clicks) */ + size_t u_dsize; /* data size (clicks) */ + size_t u_ssize; /* stack size (clicks) */ + +/* 1.3 - signal management */ + sig_t u_signal[NSIG]; /* disposition of signals */ + long u_sigmask[NSIG]; /* signals to be blocked */ + long u_sigonstack; /* signals to take on sigstack */ + long u_sigintr; /* signals that interrupt syscalls */ + long u_oldmask; /* saved mask from before sigpause */ + int u_code; /* ``code'' to trap */ + int u_psflags; /* Process Signal flags */ + struct sigaltstack u_sigstk; /* signal stack info */ + u_int u_sigtramp; /* pointer to trampoline code in user space */ + +/* 1.4 - descriptor management */ + struct file *u_ofile[NOFILE]; /* file structures for open files */ + char u_pofile[NOFILE]; /* per-process flags of open files */ + int u_lastfile; /* high-water mark of u_ofile */ +#define UF_EXCLOSE 0x1 /* auto-close on exec */ +#define UF_MAPPED 0x2 /* mapped from device */ + struct inode *u_cdir; /* current directory */ + struct inode *u_rdir; /* root directory of current process */ + struct tty *u_ttyp; /* controlling tty pointer */ + dev_t u_ttyd; /* controlling tty dev */ + int u_cmask; /* mask for file creation */ + +/* 1.5 - timing and statistics */ + struct k_rusage u_ru; /* stats for this proc */ + struct k_rusage u_cru; /* sum of stats for reaped children */ + struct k_itimerval u_timer[2]; /* profile/virtual timers */ + long u_start; + int u_dupfd; /* XXX - see kern_descrip.c/fdopen */ + + struct uprof { /* profile arguments */ + unsigned *pr_base; /* buffer base */ + unsigned pr_size; /* buffer size */ + unsigned pr_off; /* pc offset */ + unsigned pr_scale; /* pc scaling */ + } u_prof; + +/* 1.6 - resource controls */ + struct rlimit u_rlimit[RLIM_NLIMITS]; + +/* namei & co. */ + struct nameicache { /* last successful directory search */ + off_t nc_prevoffset; /* offset at which last entry found */ + ino_t nc_inumber; /* inum of cached directory */ + dev_t nc_dev; /* dev of cached directory */ + } u_ncache; + int u_stack[1]; /* kernel stack per user + * extends from u + USIZE + * backward not to reach here */ +}; + +#include + +#ifdef KERNEL +extern struct user u, u0; + +/* + * Increment user profiling counters. + */ +void addupc (caddr_t pc, struct uprof *pbuf, int ticks); + +#endif diff --git a/sys/include/utsname.h b/sys/include/utsname.h new file mode 100644 index 0000000..947462d --- /dev/null +++ b/sys/include/utsname.h @@ -0,0 +1,49 @@ +/*- + * Copyright (c) 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Chuck Karish of Mindcraft, 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 _SYS_UTSNAME_H +#define _SYS_UTSNAME_H + +struct utsname { + char sysname[128]; /* Name of this OS. */ + char nodename[128]; /* Name of this network node. */ + char release[128]; /* Release level. */ + char version[128]; /* Version level. */ + char machine[128]; /* Hardware type. */ +}; + +int uname (struct utsname *name); + +#endif /* !_SYS_UTSNAME_H */ diff --git a/sys/include/vm.h b/sys/include/vm.h new file mode 100644 index 0000000..d343b45 --- /dev/null +++ b/sys/include/vm.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) 1982, 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#ifdef KERNEL +#include "vmparam.h" +#include "vmmac.h" +#include "vmmeter.h" +#include "vmsystm.h" +#else +#include +#include +#include +#include +#endif diff --git a/sys/include/vmmac.h b/sys/include/vmmac.h new file mode 100644 index 0000000..8151d66 --- /dev/null +++ b/sys/include/vmmac.h @@ -0,0 +1,11 @@ +/* + * Copyright (c) 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + * + * @(#)vmmac.h 1.1 (2.10 Berkeley) 12/1/86 + */ + +/* Average new into old with aging factor time */ +#define ave(smooth, cnt, time) \ + smooth = ((time - 1) * (smooth) + (cnt)) / (time) diff --git a/sys/include/vmmeter.h b/sys/include/vmmeter.h new file mode 100644 index 0000000..24d3e6c --- /dev/null +++ b/sys/include/vmmeter.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 1982, 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +/* + * Virtual memory related instrumentation + */ +struct vmrate +{ +#define v_first v_swtch + u_short v_swtch; /* context switches */ + u_short v_trap; /* calls to trap */ + u_short v_syscall; /* calls to syscall() */ + u_short v_intr; /* device interrupts */ + u_short v_soft; /* software interrupts */ + u_short v_fpsim; /* floating point simulator faults */ + u_short v_kbin; /* kbytes swapped in */ + u_short v_kbout; /* kbytes swapped out */ + u_short v_swpin; /* swapins */ + u_short v_swpout; /* swapouts */ +#define v_last v_swpout +}; + +struct vmsum +{ + long v_swtch; /* context switches */ + long v_trap; /* calls to trap */ + long v_syscall; /* calls to syscall() */ + long v_intr; /* device interrupts */ + long v_soft; /* software interrupts */ + long v_fpsim; /* floating point simulator faults */ + long v_kbin; /* kbytes swapped in */ + long v_kbout; /* kbytes swapped out */ + long v_swpin; /* swapins */ + long v_swpout; /* swapouts */ +}; +#if defined(KERNEL) && defined(UCB_METER) +struct vmrate cnt, rate; +struct vmsum sum; +#endif + +/* systemwide totals computed every five seconds */ +struct vmtotal +{ + short t_rq; /* length of the run queue */ + short t_dw; /* jobs in ``disk wait'' (neg priority) */ + short t_sl; /* jobs sleeping in core */ + short t_sw; /* swapped out runnable/short block jobs */ + long t_vm; /* total virtual memory, clicks */ + long t_avm; /* active virtual memory, clicks */ + size_t t_rm; /* total real memory, clicks */ + size_t t_arm; /* active real memory, clicks */ + long t_vmtxt; /* virtual memory used by text, clicks */ + long t_avmtxt; /* active virtual memory used by text, clicks */ + size_t t_rmtxt; /* real memory used by text, clicks */ + size_t t_armtxt; /* active real memory used by text, clicks */ + size_t t_free; /* free memory, kb */ +}; +#ifdef KERNEL +struct vmtotal total; + +/* + * Count up various things once a second + */ +void vmmeter (void); + +void vmtotal (void); + +#endif diff --git a/sys/include/vmparam.h b/sys/include/vmparam.h new file mode 100644 index 0000000..684e583 --- /dev/null +++ b/sys/include/vmparam.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 1982, 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +/* + * CTL_VM identifiers + */ +#define VM_METER 1 /* struct vmmeter */ +#define VM_LOADAVG 2 /* struct loadavg */ +#define VM_SWAPMAP 3 /* struct mapent _swapmap[] */ +#define VM_MAXID 5 /* number of valid vm ids */ + +#ifndef KERNEL +#define CTL_VM_NAMES { \ + { 0, 0 }, \ + { "vmmeter", CTLTYPE_STRUCT }, \ + { "loadavg", CTLTYPE_STRUCT }, \ + { "swapmap", CTLTYPE_STRUCT }, \ +} +#endif diff --git a/sys/include/vmsystm.h b/sys/include/vmsystm.h new file mode 100644 index 0000000..3312681 --- /dev/null +++ b/sys/include/vmsystm.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 1982, 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + * + * @(#)vmsystm.h 7.2.1 (2.11BSD GTE) 1/15/95 + */ + +/* + * Miscellaneous virtual memory subsystem variables and structures. + */ + +#if defined(KERNEL) && defined(UCB_METER) && !defined(SUPERVISOR) +size_t freemem; /* remaining clicks of free memory */ + +u_short avefree; /* moving average of remaining free clicks */ +u_short avefree30; /* 30 sec (avefree is 5 sec) moving average */ + +/* writable copies of tunables */ +int maxslp; /* max sleep time before very swappable */ +#endif + +/* + * Fork/vfork accounting. + */ +struct forkstat +{ + long cntfork; + long cntvfork; + long sizfork; + long sizvfork; +}; +#if defined(KERNEL) && defined(UCB_METER) && !defined(SUPERVISOR) +struct forkstat forkstat; +#endif diff --git a/sys/include/wait.h b/sys/include/wait.h new file mode 100644 index 0000000..587b0b1 --- /dev/null +++ b/sys/include/wait.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) 1982, 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + * + * @(#)wait.h 7.2.1 (2.11BSD GTE) 1995/06/23 + */ + +/* + * This file holds definitions relevent to the wait system call. + * Some of the options here are available only through the ``wait3'' + * entry point; the old entry point with one argument has more fixed + * semantics, never returning status of unstopped children, hanging until + * a process terminates if any are outstanding, and never returns + * detailed information about process resource utilization (). + */ + +/* + * Structure of the information in the first word returned by both + * wait and wait3. If w_stopval==WSTOPPED, then the second structure + * describes the information returned, else the first. See WUNTRACED below. + */ +union wait { + int w_status; /* used in syscall */ + /* + * Terminated process status. + */ + struct { + unsigned w_Termsig :7; /* termination signal */ + unsigned w_Coredump :1; /* core dump indicator */ + unsigned w_Retcode :8; /* exit code if w_termsig==0 */ + } w_T; + /* + * Stopped process status. Returned + * only for traced children unless requested + * with the WUNTRACED option bit. + */ + struct { + unsigned w_Stopval :8; /* == W_STOPPED if stopped */ + unsigned w_Stopsig :8; /* signal that stopped us */ + } w_S; +}; +#define w_termsig w_T.w_Termsig +#define w_coredump w_T.w_Coredump +#define w_retcode w_T.w_Retcode +#define w_stopval w_S.w_Stopval +#define w_stopsig w_S.w_Stopsig + +#define WSTOPPED 0177 /* value of s.stopval if process is stopped */ + +/* + * Option bits for the second argument of wait3. WNOHANG causes the + * wait to not hang if there are no stopped or terminated processes, rather + * returning an error indication in this case (pid==0). WUNTRACED + * indicates that the caller should receive status about untraced children + * which stop due to signals. If children are stopped and a wait without + * this option is done, it is as though they were still running... nothing + * about them is returned. + */ +#define WNOHANG 1 /* dont hang in wait */ +#define WUNTRACED 2 /* tell about stopped, untraced children */ + +#define WIFSTOPPED(x) (((union wait*)&(x))->w_stopval == WSTOPPED) +#define WIFSIGNALED(x) (((union wait*)&(x))->w_stopval != WSTOPPED &&\ + (((union wait*)&(x))->w_termsig != 0)) +#define WIFEXITED(x) (((union wait*)&(x))->w_stopval != WSTOPPED &&\ + (((union wait*)&(x))->w_termsig == 0)) +#define WEXITSTATUS(x) (((union wait*)&(x))->w_retcode) +#define WTERMSIG(x) (((union wait*)&(x))->w_termsig) +#define WCOREDUMP(x) (((union wait*)&(x))->w_coredump) +#define WSTOPSIG(x) (((union wait*)&(x))->w_stopsig) + +#define W_STOPCODE(sig) ((sig << 8) | WSTOPPED) +#define W_EXITCODE(ret,sig) ((ret << 8) | (sig)) + +#define WAIT_ANY (-1) +#define WAIT_MYPGRP 0 + +#ifndef KERNEL +#include +#include + +int wait (int *istat); +int wait3 (int *istat, int options, struct rusage *rup); +int waitpid (int pid, int *istat, int options); +int wait4 (int pid, int *istat, int options, struct rusage *rup); +#endif diff --git a/sys/kernel/init_main.c b/sys/kernel/init_main.c new file mode 100644 index 0000000..2610d7c --- /dev/null +++ b/sys/kernel/init_main.c @@ -0,0 +1,341 @@ +/* + * Copyright (c) 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "param.h" +#include "user.h" +#include "fs.h" +#include "mount.h" +#include "map.h" +#include "proc.h" +#include "ioctl.h" +#include "inode.h" +#include "conf.h" +#include "buf.h" +#include "fcntl.h" +#include "vm.h" +#include "clist.h" +#include "reboot.h" +#include "systm.h" +#include "kernel.h" +#include "namei.h" +#include "stat.h" +#include "rdisk.h" + +u_int swapstart, nswap; /* start and size of swap space */ +size_t physmem; /* total amount of physical memory */ +int boothowto; /* reboot flags, from boot */ + +/* + * Initialize hash links for buffers. + */ +static void +bhinit() +{ + register int i; + register struct bufhd *bp; + + for (bp = bufhash, i = 0; i < BUFHSZ; i++, bp++) + bp->b_forw = bp->b_back = (struct buf *)bp; +} + +/* + * Initialize the buffer I/O system by freeing + * all buffers and setting all device buffer lists to empty. + */ +static void +binit() +{ + register struct buf *bp; + register int i; + caddr_t paddr; + + for (bp = bfreelist; bp < &bfreelist[BQUEUES]; bp++) + bp->b_forw = bp->b_back = bp->av_forw = bp->av_back = bp; + paddr = bufdata; + for (i = 0; i < NBUF; i++, paddr += MAXBSIZE) { + bp = &buf[i]; + bp->b_dev = NODEV; + bp->b_bcount = 0; + bp->b_addr = paddr; + binshash(bp, &bfreelist[BQ_AGE]); + bp->b_flags = B_BUSY|B_INVAL; + brelse(bp); + } +} + +/* + * Initialize clist by freeing all character blocks, then count + * number of character devices. (Once-only routine) + */ +static void +cinit() +{ + register int ccp; + register struct cblock *cp; + + ccp = (int)cfree; + ccp = (ccp + CROUND) & ~CROUND; + for (cp = (struct cblock *)ccp; cp <= &cfree[NCLIST - 1]; cp++) { + cp->c_next = cfreelist; + cfreelist = cp; + cfreecount += CBSIZE; + } +} + +/* + * Initialization code. + * Called from cold start routine as + * soon as a stack and segmentation + * have been established. + * Functions: + * clear and free user core + * turn on clock + * hand craft 0th process + * call all initialization routines + * fork - process 0 to schedule + * - process 1 execute bootstrap + */ +int +main() +{ + register struct proc *p; + register int i; + register struct fs *fs = NULL; + char inbuf[4]; + char inch; + int s __attribute__((unused)); + + startup(); + printf ("\n%s", version); + cpuidentify(); + cnidentify(); + + /* + * Set up system process 0 (swapper). + */ + p = &proc[0]; + p->p_addr = (size_t) &u; + p->p_stat = SRUN; + p->p_flag |= SLOAD | SSYS; + p->p_nice = NZERO; + + u.u_procp = p; /* init user structure */ + u.u_cmask = CMASK; + u.u_lastfile = -1; + for (i = 1; i < NGROUPS; i++) + u.u_groups[i] = NOGROUP; + for (i = 0; i < sizeof(u.u_rlimit)/sizeof(u.u_rlimit[0]); i++) + u.u_rlimit[i].rlim_cur = u.u_rlimit[i].rlim_max = + RLIM_INFINITY; + + /* Initialize signal state for process 0 */ + siginit (p); + + /* + * Initialize tables, protocols, and set up well-known inodes. + */ +#ifdef LOG_ENABLED + loginit(); +#endif + coutinit(); + cinit(); + pqinit(); + ihinit(); + bhinit(); + binit(); + nchinit(); + clkstart(); + s = spl0(); + rdisk_init(); + + pipedev = rootdev = get_boot_device(); + swapdev = get_swap_device(); + + /* Mount a root filesystem. */ + for (;;) { + if(rootdev!=-1) + { + fs = mountfs (rootdev, (boothowto & RB_RDONLY) ? MNT_RDONLY : 0, + (struct inode*) 0); + } + if (fs) + break; + printf ("No root filesystem available!\n"); +// rdisk_list_partitions(RDISK_FS); +retry: + printf ("Please enter device to boot from (press ? to list): "); + inch=0; + inbuf[0] = inbuf[1] = inbuf[2] = inbuf[3] = 0; + while((inch=cngetc()) != '\r') + { + switch(inch) + { + case '?': + printf("?\n"); + rdisk_list_partitions(RDISK_FS); + printf ("Please enter device to boot from (press ? to list): "); + break; + default: + printf("%c",inch); + inbuf[0] = inbuf[1]; + inbuf[1] = inbuf[2]; + inbuf[2] = inbuf[3]; + inbuf[3] = inch; + break; + } + } + + inch = 0; + if(inbuf[0]=='r' && inbuf[1]=='d') + { + if(inbuf[2]>='0' && inbuf[2] < '0'+rdisk_num_disks()) + { + if(inbuf[3]>='a' && inbuf[3]<='d') + { + rootdev=makedev(inbuf[2]-'0',inbuf[3]-'a'+1); + inch = 1; + } + } + } else if(inbuf[1]=='r' && inbuf[2]=='d') { + if(inbuf[3]>='0' && inbuf[3] < '0'+rdisk_num_disks()) + { + rootdev=makedev(inbuf[3]-'0',0); + inch = 1; + } + } else if(inbuf[3] == 0) { + inch = 1; + } + if(inch==0) + { + printf("\nUnknown device.\n\n"); + goto retry; + } + printf ("\n\n"); + } + printf ("phys mem = %u kbytes\n", physmem / 1024); + printf ("user mem = %u kbytes\n", MAXMEM / 1024); + if(minor(rootdev)==0) + { + printf ("root dev = rd%d (%d,%d)\n", + major(rootdev), + major(rootdev), minor(rootdev) + ); + } else { + printf ("root dev = rd%d%c (%d,%d)\n", + major(rootdev), 'a'+minor(rootdev)-1, + major(rootdev), minor(rootdev) + ); + } + + printf ("root size = %u kbytes\n", fs->fs_fsize * DEV_BSIZE / 1024); + mount[0].m_inodp = (struct inode*) 1; /* XXX */ + mount_updname (fs, "/", "root", 1, 4); + time.tv_sec = fs->fs_time; + boottime = time; + + /* Find a swap file. */ + swapstart = 1; + while(swapdev == -1) + { + printf("Please enter swap device (press ? to list): "); + inbuf[0] = inbuf[1] = inbuf[2] = inbuf[3] = 0; + while((inch = cngetc())!='\r') + { + switch(inch) + { + case '?': + printf("?\n"); + rdisk_list_partitions(RDISK_SWAP); + printf("Please enter swap device (press ? to list): "); + break; + default: + printf("%c",inch); + inbuf[0] = inbuf[1]; + inbuf[1] = inbuf[2]; + inbuf[2] = inbuf[3]; + inbuf[3] = inch; + break; + } + } + inch = 0; + if(inbuf[0]=='r' && inbuf[1]=='d') + { + if(inbuf[2]>='0' && inbuf[2] < '0'+rdisk_num_disks()) + { + if(inbuf[3]>='a' && inbuf[3]<='d') + { + swapdev=makedev(inbuf[2]-'0',inbuf[3]-'a'+1); + inch = 1; + } + } + } else if(inbuf[1]=='r' && inbuf[2]=='d') { + if(inbuf[3]>='0' && inbuf[3] < '0'+rdisk_num_disks()) + { + swapdev=makedev(inbuf[3]-'0',0); + inch = 1; + } + } + + if(minor(swapdev)!=0) + { + if(partition_type(swapdev)!=RDISK_SWAP) + { + printf("\nNot a swap partition!\n\n"); + swapdev=-1; + } + } + } + nswap = rdsize(swapdev); + + if(minor(swapdev)==0) + { + printf ("swap dev = rd%d (%d,%d)\n", + major(swapdev), + major(swapdev), minor(swapdev) + ); + } else { + printf ("swap dev = rd%d%c (%d,%d)\n", + major(swapdev), 'a'+minor(swapdev)-1, + major(swapdev), minor(swapdev) + ); + } + (*bdevsw[major(swapdev)].d_open)(swapdev, FREAD|FWRITE, S_IFBLK); + printf ("swap size = %u kbytes\n", nswap * DEV_BSIZE / 1024); + if (nswap <= 0) + panic ("zero swap size"); /* don't want to panic, but what ? */ + mfree (swapmap, nswap, swapstart); + + /* Kick off timeout driven events by calling first time. */ + schedcpu (0); + + /* Set up the root file system. */ + rootdir = iget (rootdev, &mount[0].m_filsys, (ino_t) ROOTINO); + iunlock (rootdir); + u.u_cdir = iget (rootdev, &mount[0].m_filsys, (ino_t) ROOTINO); + iunlock (u.u_cdir); + u.u_rdir = NULL; + + /* + * Make init process. + */ + if (newproc (0) == 0) { + /* Parent process with pid 0: swapper. + * No return from sched. */ + sched(); + } + /* Child process with pid 1: init. */ + s = splhigh(); + p = u.u_procp; + p->p_dsize = icodeend - icode; + p->p_daddr = USER_DATA_START; + p->p_ssize = 1024; /* one kbyte of stack */ + p->p_saddr = USER_DATA_END - 1024; + bcopy ((caddr_t) icode, (caddr_t) USER_DATA_START, icodeend - icode); + /* + * return goes to location 0 of user init code + * just copied out. + */ + return 0; +} diff --git a/sys/kernel/init_sysent.c b/sys/kernel/init_sysent.c new file mode 100644 index 0000000..9570403 --- /dev/null +++ b/sys/kernel/init_sysent.c @@ -0,0 +1,211 @@ +/* + * System call switch table. + * + * Copyright (c) 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "param.h" +#include "systm.h" +#include "glob.h" + +#ifdef INET +# define ifnet(narg, name) narg, name +# define errnet(narg, name) narg, name +#else +# define ifnet(narg, name) 0, nosys +# define errnet(narg, name) 0, nonet +#endif + +extern void sc_msec(); + +/* + * Reserved/unimplemented system calls in the range 0-150 inclusive + * are reserved for use in future Berkeley releases. + * Additional system calls implemented in vendor and other + * redistributions should be placed in the reserved range at the end + * of the current calls. + */ +/* + * This table is the switch used to transfer to the appropriate routine for + * processing a system call. Each row contains the number of words of + * arguments expected in registers, how many on the stack, and a pointer to + * the routine. + * + * The maximum number of direct system calls is 255 since system call numbers + * are encoded in the lower byte of the trap instruction -- see trap.c. + */ +const struct sysent sysent[] = { + { 1, nosys }, /* 0 = out-of-range */ + { 1, rexit }, /* 1 = exit */ + { 0, fork }, /* 2 = fork */ + { 3, read }, /* 3 = read */ + { 3, write }, /* 4 = write */ + { 3, open }, /* 5 = open */ + { 1, close }, /* 6 = close */ + { 4, wait4 }, /* 7 = wait4 */ + { 0, nosys }, /* 8 = (old creat) */ + { 2, link }, /* 9 = link */ + { 1, unlink }, /* 10 = unlink */ + { 2, execv }, /* 11 = execv */ + { 1, chdir }, /* 12 = chdir */ + { 1, fchdir }, /* 13 = fchdir */ + { 3, mknod }, /* 14 = mknod */ + { 2, chmod }, /* 15 = chmod */ + { 3, chown }, /* 16 = chown; now 3 args */ + { 2, chflags }, /* 17 = chflags */ + { 2, fchflags }, /* 18 = fchflags */ + { 4, lseek }, /* 19 = lseek */ + { 0, getpid }, /* 20 = getpid */ + { 3, smount }, /* 21 = mount */ + { 1, umount }, /* 22 = umount */ + { 6, __sysctl }, /* 23 = __sysctl */ + { 0, getuid }, /* 24 = getuid */ + { 0, geteuid }, /* 25 = geteuid */ + { 4, ptrace }, /* 26 = ptrace */ + { 0, getppid }, /* 27 = getppid */ + { 2, statfs }, /* 28 = statfs */ + { 2, fstatfs }, /* 29 = fstatfs */ + { 3, getfsstat }, /* 30 = getfsstat */ + { 4, sigaction }, /* 31 = sigaction */ + { 3, sigprocmask }, /* 32 = sigprocmask */ + { 2, saccess }, /* 33 = access */ + { 1, sigpending }, /* 34 = sigpending */ + { 2, sigaltstack }, /* 35 = sigaltstack */ + { 0, sync }, /* 36 = sync */ + { 2, kill }, /* 37 = kill */ + { 2, stat }, /* 38 = stat */ + { 2, nosys }, /* 39 = getlogin */ + { 2, lstat }, /* 40 = lstat */ + { 1, dup }, /* 41 = dup */ + { 0, pipe }, /* 42 = pipe */ + { 1, nosys }, /* 43 = setlogin */ + { 4, profil }, /* 44 = profil */ + { 1, setuid }, /* 45 = setuid */ + { 1, seteuid }, /* 46 = seteuid */ + { 0, getgid }, /* 47 = getgid */ + { 0, getegid }, /* 48 = getegid */ + { 1, setgid }, /* 49 = setgid */ + { 1, setegid }, /* 50 = setegid */ + { 0, kmemdev }, /* 51 = kmemdev */ + { 3, nosys }, /* 52 = (2.9) set phys addr */ + { 1, nosys }, /* 53 = (2.9) lock in core */ + { 4, ioctl }, /* 54 = ioctl */ + { 1, reboot }, /* 55 = reboot */ + { 2, sigwait }, /* 56 = sigwait */ + { 2, symlink }, /* 57 = symlink */ + { 3, readlink }, /* 58 = readlink */ + { 3, execve }, /* 59 = execve */ + { 1, umask }, /* 60 = umask */ + { 1, chroot }, /* 61 = chroot */ + { 2, fstat }, /* 62 = fstat */ + { 0, nosys }, /* 63 = reserved */ + { 0, nosys }, /* 64 = (old getpagesize) */ + { 6, pselect }, /* 65 = pselect */ + { 0, vfork }, /* 66 = vfork */ + { 0, nosys }, /* 67 = unused */ + { 0, nosys }, /* 68 = unused */ + { 1, brk }, /* 69 = brk */ +#ifdef GLOB_ENABLED + { 1, rdglob }, /* 70 = read from global */ + { 2, wrglob }, /* 71 = write to global */ +#else + { 1, nosys }, + { 2, nosys }, +#endif + { 0, sc_msec }, /* 72 = msec */ + { 0, nosys }, /* 73 = unused */ + { 0, nosys }, /* 74 = unused */ + { 0, nosys }, /* 75 = unused */ + { 0, vhangup }, /* 76 = vhangup */ + { 0, nosys }, /* 77 = unused */ + { 0, nosys }, /* 78 = unused */ + { 2, getgroups }, /* 79 = getgroups */ + { 2, setgroups }, /* 80 = setgroups */ + { 1, getpgrp }, /* 81 = getpgrp */ + { 2, setpgrp }, /* 82 = setpgrp */ + { 3, setitimer }, /* 83 = setitimer */ + { 0, nosys }, /* 84 = (old wait,wait3) */ + { 0, nosys }, /* 85 = unused */ + { 2, getitimer }, /* 86 = getitimer */ + { 0, nosys }, /* 87 = (old gethostname) */ + { 0, nosys }, /* 88 = (old sethostname) */ + { 0, getdtablesize }, /* 89 = getdtablesize */ + { 2, dup2 }, /* 90 = dup2 */ + { 0, nosys }, /* 91 = unused */ + { 3, fcntl }, /* 92 = fcntl */ + { 5, select }, /* 93 = select */ + { 0, nosys }, /* 94 = unused */ + { 1, fsync }, /* 95 = fsync */ + { 3, setpriority }, /* 96 = setpriority */ + { errnet(3, socket) }, /* 97 = socket */ + { ifnet(3, connect) }, /* 98 = connect */ + { ifnet(3, accept) }, /* 99 = accept */ + { 2, getpriority }, /* 100 = getpriority */ + { ifnet(4, send) }, /* 101 = send */ + { ifnet(4, recv) }, /* 102 = recv */ + { 1, sigreturn }, /* 103 = sigreturn */ + { ifnet(3, bind) }, /* 104 = bind */ + { ifnet(5, setsockopt) }, /* 105 = setsockopt */ + { ifnet(2, listen) }, /* 106 = listen */ + { 1, sigsuspend }, /* 107 = sigsuspend */ + { 0, nosys }, /* 108 = (old sigvec) */ + { 0, nosys }, /* 109 = (old sigblock) */ + { 0, nosys }, /* 110 = (old sigsetmask) */ + { 0, nosys }, /* 111 = (old sigpause) */ + { 2, sigstack }, /* 112 = sigstack COMPAT-43 */ + { ifnet(3, recvmsg) }, /* 113 = recvmsg */ + { ifnet(3, sendmsg) }, /* 114 = sendmsg */ + { 0, nosys }, /* 115 = unused */ + { 2, gettimeofday }, /* 116 = gettimeofday */ + { 2, getrusage }, /* 117 = getrusage */ + { ifnet(5, getsockopt) }, /* 118 = getsockopt */ + { 0, nosys }, /* 119 = unused */ + { 3, readv }, /* 120 = readv */ + { 3, writev }, /* 121 = writev */ + { 2, settimeofday }, /* 122 = settimeofday */ + { 3, fchown }, /* 123 = fchown */ + { 2, fchmod }, /* 124 = fchmod */ + { ifnet(6, recvfrom) }, /* 125 = recvfrom */ + { 0, nosys }, /* 126 = (old setreuid) */ + { 0, nosys }, /* 127 = (old setregid) */ + { 2, rename }, /* 128 = rename */ + { 3, truncate }, /* 129 = truncate */ + { 3, ftruncate }, /* 130 = ftruncate */ + { 2, flock }, /* 131 = flock */ + { 0, nosys }, /* 132 = nosys */ + { ifnet(6, sendto) }, /* 133 = sendto */ + { ifnet(2, shutdown) }, /* 134 = shutdown */ + { errnet(4, socketpair) }, /* 135 = socketpair */ + { 2, mkdir }, /* 136 = mkdir */ + { 1, rmdir }, /* 137 = rmdir */ + { 2, utimes }, /* 138 = utimes */ + { 0, nosys }, /* 139 = unused */ + { 2, adjtime }, /* 140 = adjtime */ + { ifnet(3, getpeername) }, /* 141 = getpeername */ + { 0, nosys }, /* 142 = (old gethostid) */ + { 0, nosys }, /* 143 = (old sethostid) */ + { 2, getrlimit }, /* 144 = getrlimit */ + { 2, setrlimit }, /* 145 = setrlimit */ + { 2, killpg }, /* 146 = killpg */ + { 0, nosys }, /* 147 = nosys */ + { 2, nosys }, /* 148 = quota */ + { 4, nosys }, /* 149 = qquota */ + { ifnet(3, getsockname) }, /* 150 = getsockname */ + /* + * Syscalls 151-180 inclusive are reserved for vendor-specific + * system calls. (This includes various calls added for compatibity + * with other Unix variants.) + */ + + /* + * 2BSD special calls + */ + { 0, nosys }, /* 151 = unused */ + { 2, ustore }, /* 152 = ustore */ + { 1, ufetch }, /* 153 = ufetch */ + { 4, ucall }, /* 154 = ucall */ + { 0, nosys }, /* 155 = fperr */ +}; + +const int nsysent = sizeof (sysent) / sizeof (sysent[0]); diff --git a/sys/kernel/kern_clock.c b/sys/kernel/kern_clock.c new file mode 100644 index 0000000..87f0de4 --- /dev/null +++ b/sys/kernel/kern_clock.c @@ -0,0 +1,373 @@ +/* + * Copyright (c) 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "param.h" +#include "user.h" +#include "proc.h" +#include "callout.h" +#include "dk.h" +#include "kernel.h" +#include "systm.h" + +int noproc; /* no one is running just now */ + +struct callout *callfree, calltodo; + +#ifdef UCB_METER +int dk_ndrive = DK_NDRIVE; + +/* + * Gather statistics on resource utilization. + * + * We make a gross assumption: that the system has been in the + * state it is in (user state, kernel state, interrupt state, + * or idle state) for the entire last time interval, and + * update statistics accordingly. + */ +/*ARGSUSED*/ +void +gatherstats(pc, ps) + caddr_t pc; + int ps; +{ + register int cpstate; + + /* + * Determine what state the cpu is in. + */ + if (USERMODE(ps)) { + /* + * CPU was in user state. + */ + if (u.u_procp->p_nice > NZERO) + cpstate = CP_NICE; + else + cpstate = CP_USER; + } else { + /* + * CPU was in system state. If profiling kernel + * increment a counter. If no process is running + * then this is a system tick if we were running + * at a non-zero IPL (in a driver). If a process is running, + * then we charge it with system time even if we were + * at a non-zero IPL, since the system often runs + * this way during processing of system calls. + * This is approximate, but the lack of true interval + * timers makes doing anything else difficult. + */ + cpstate = CP_SYS; + if (noproc && BASEPRI(ps)) + cpstate = CP_IDLE; + } + /* + * We maintain statistics shown by user-level statistics + * programs: the amount of time in each cpu state, and + * the amount of time each of DK_NDRIVE ``drives'' is busy. + */ + cp_time[cpstate]++; +} +#endif /* UCB_METER */ + +/* + * Software priority level clock interrupt. + * Run periodic events from timeout queue. + */ +void +softclock(pc, ps) + caddr_t pc; + int ps; +{ + for (;;) { + register struct callout *p1; + register caddr_t arg; + register void (*func) (caddr_t); + register int s; + + s = splhigh(); + if ((p1 = calltodo.c_next) == 0 || p1->c_time > 0) { + splx(s); + break; + } + arg = p1->c_arg; + func = p1->c_func; + calltodo.c_next = p1->c_next; + p1->c_next = callfree; + callfree = p1; + splx(s); + (*func) (arg); + } + /* + * If trapped user-mode and profiling, give it + * a profiling tick. + */ + if (USERMODE(ps)) { + register struct proc *p = u.u_procp; + + if (u.u_prof.pr_scale) + addupc(pc, &u.u_prof, 1); + /* + * Check to see if process has accumulated + * more than 10 minutes of user time. If so + * reduce priority to give others a chance. + */ + + if (p->p_uid && p->p_nice == NZERO && + u.u_ru.ru_utime > 10L * 60L * hz) { + p->p_nice = NZERO+4; + (void) setpri(p); + } + } +} + +/* + * The hz hardware interval timer. + * We update the events relating to real time. + * Also gather statistics. + * + * reprime clock + * implement callouts + * maintain user/system times + * maintain date + * profile + */ +void +hardclock(pc, ps) + caddr_t pc; + int ps; +{ + register struct callout *p1; + register struct proc *p; + register int needsoft = 0; + + /* + * Update real-time timeout queue. + * At front of queue are some number of events which are ``due''. + * The time to these is <= 0 and if negative represents the + * number of ticks which have passed since it was supposed to happen. + * The rest of the q elements (times > 0) are events yet to happen, + * where the time for each is given as a delta from the previous. + * Decrementing just the first of these serves to decrement the time + * to all events. + */ + p1 = calltodo.c_next; + while (p1) { + if (--p1->c_time > 0) + break; + needsoft = 1; + if (p1->c_time == 0) + break; + p1 = p1->c_next; + } + + /* + * Charge the time out based on the mode the cpu is in. + * Here again we fudge for the lack of proper interval timers + * assuming that the current state has been around at least + * one tick. + */ + if (USERMODE(ps)) { + if (u.u_prof.pr_scale) + needsoft = 1; + /* + * CPU was in user state. Increment + * user time counter, and process process-virtual time + * interval timer. + */ + u.u_ru.ru_utime++; + if (u.u_timer[ITIMER_VIRTUAL - 1].it_value && + !--u.u_timer[ITIMER_VIRTUAL - 1].it_value) { + psignal(u.u_procp, SIGVTALRM); + u.u_timer[ITIMER_VIRTUAL - 1].it_value = + u.u_timer[ITIMER_VIRTUAL - 1].it_interval; + } + } else { + /* + * CPU was in system state. + */ + if (!noproc) + u.u_ru.ru_stime++; + } + + /* + * If the cpu is currently scheduled to a process, then + * charge it with resource utilization for a tick, updating + * statistics which run in (user+system) virtual time, + * such as the cpu time limit and profiling timers. + * This assumes that the current process has been running + * the entire last tick. + */ + if (noproc == 0) { + p = u.u_procp; + if (++p->p_cpu == 0) + p->p_cpu--; + if ((u.u_ru.ru_utime+u.u_ru.ru_stime+1) > + u.u_rlimit[RLIMIT_CPU].rlim_cur) { + psignal(p, SIGXCPU); + if (u.u_rlimit[RLIMIT_CPU].rlim_cur < + u.u_rlimit[RLIMIT_CPU].rlim_max) + u.u_rlimit[RLIMIT_CPU].rlim_cur += 5 * hz; + } + if (u.u_timer[ITIMER_PROF - 1].it_value && + !--u.u_timer[ITIMER_PROF - 1].it_value) { + psignal(p, SIGPROF); + u.u_timer[ITIMER_PROF - 1].it_value = + u.u_timer[ITIMER_PROF - 1].it_interval; + } + } + +#ifdef UCB_METER + gatherstats (pc, ps); +#endif + + /* + * Increment the time-of-day, process callouts at a very + * low cpu priority, so we don't keep the relatively high + * clock interrupt priority any longer than necessary. + */ + if (adjdelta) { + if (adjdelta > 0) { + ++lbolt; + --adjdelta; + } else { + --lbolt; + ++adjdelta; + } + } + if (++lbolt >= hz) { + lbolt -= hz; + ++time.tv_sec; + } + + if (needsoft && BASEPRI(ps)) { /* if ps is high, just return */ +// (void) splsoftclock(); + softclock (pc, ps); + } +} + +/* + * Arrange that (*fun)(arg) is called in t/hz seconds. + */ +void +timeout (fun, arg, t) + void (*fun) (caddr_t); + caddr_t arg; + register int t; +{ + register struct callout *p1, *p2, *pnew; + register int s = splclock(); + + if (t <= 0) + t = 1; + pnew = callfree; + if (pnew == NULL) + panic("timeout table overflow"); + callfree = pnew->c_next; + pnew->c_arg = arg; + pnew->c_func = fun; + for (p1 = &calltodo; (p2 = p1->c_next) && p2->c_time < t; p1 = p2) + if (p2->c_time > 0) + t -= p2->c_time; + p1->c_next = pnew; + pnew->c_next = p2; + pnew->c_time = t; + if (p2) + p2->c_time -= t; + splx(s); +} + +/* + * untimeout is called to remove a function timeout call + * from the callout structure. + */ +void +untimeout (fun, arg) + void (*fun) (caddr_t); + caddr_t arg; +{ + register struct callout *p1, *p2; + register int s; + + s = splclock(); + for (p1 = &calltodo; (p2 = p1->c_next) != 0; p1 = p2) { + if (p2->c_func == fun && p2->c_arg == arg) { + if (p2->c_next && p2->c_time > 0) + p2->c_next->c_time += p2->c_time; + p1->c_next = p2->c_next; + p2->c_next = callfree; + callfree = p2; + break; + } + } + splx(s); +} + +void +profil() +{ + register struct a { + unsigned *bufbase; + unsigned bufsize; + unsigned pcoffset; + unsigned pcscale; + } *uap = (struct a*) u.u_arg; + register struct uprof *upp = &u.u_prof; + + upp->pr_base = uap->bufbase; + upp->pr_size = uap->bufsize; + upp->pr_off = uap->pcoffset; + upp->pr_scale = uap->pcscale; +} + +/* + * Compute number of hz until specified time. + * Used to compute third argument to timeout() from an + * absolute time. + */ +int +hzto(tv) + register struct timeval *tv; +{ + register long ticks; + register long sec; + register int s = splhigh(); + + /* + * If number of milliseconds will fit in 32 bit arithmetic, + * then compute number of milliseconds to time and scale to + * ticks. Otherwise just compute number of hz in time, rounding + * times greater than representible to maximum value. + * + * Delta times less than 25 days can be computed ``exactly''. + * Maximum value for any timeout in 10ms ticks is 250 days. + */ + sec = tv->tv_sec - time.tv_sec; + if (sec <= 0x7fffffff / 1000 - 1000) + ticks = ((tv->tv_sec - time.tv_sec) * 1000 + + (tv->tv_usec - time.tv_usec) / 1000) / (1000/hz); + else if (sec <= 0x7fffffff / hz) + ticks = sec * hz; + else + ticks = 0x7fffffff; + splx(s); +#ifdef pdp11 + /* stored in an "int", so 16-bit max */ + if (ticks > 0x7fff) + ticks = 0x7fff; +#endif + return ((int)ticks); +} + +/* + * Initialize callouts. + */ +void +coutinit() +{ + int i; + + callfree = callout; + for (i=1; i + +const struct devspec fddevs[] = { + { 0, "stdin" }, + { 1, "stdout" }, + { 2, "stderr" }, + { 0, 0 } +}; + +/* + * Descriptor management. + */ + +/* + * Allocate a user file descriptor. + */ +static int +ufalloc(i) + register int i; +{ + for (; i < NOFILE; i++) + if (u.u_ofile[i] == NULL) { + u.u_rval = i; + u.u_pofile[i] = 0; + if (i > u.u_lastfile) + u.u_lastfile = i; + return (i); + } + u.u_error = EMFILE; + return (-1); +} + +/* + * System calls on descriptors. + */ +void +getdtablesize() +{ + u.u_rval = NOFILE; +} + +static void +dupit(fd, fp, flags) + register int fd; + register struct file *fp; + int flags; +{ + u.u_ofile[fd] = fp; + u.u_pofile[fd] = flags; + fp->f_count++; + if (fd > u.u_lastfile) + u.u_lastfile = fd; +} + +void +dup() +{ + register struct a { + int i; + } *uap = (struct a *) u.u_arg; + register struct file *fp; + register int j; + + if (uap->i &~ 077) { uap->i &= 077; dup2(); return; } /* XXX */ + + GETF(fp, uap->i); + j = ufalloc(0); + if (j < 0) + return; + dupit(j, fp, u.u_pofile[uap->i] &~ UF_EXCLOSE); +} + +void +dup2() +{ + register struct a { + int i, j; + } *uap = (struct a *) u.u_arg; + register struct file *fp; + + GETF(fp, uap->i); + if (uap->j < 0 || uap->j >= NOFILE) { + u.u_error = EBADF; + return; + } + u.u_rval = uap->j; + if (uap->i == uap->j) + return; + if (u.u_ofile[uap->j]) + /* + * dup2 must succeed even if the close has an error. + */ + (void) closef(u.u_ofile[uap->j]); + dupit(uap->j, fp, u.u_pofile[uap->i] &~ UF_EXCLOSE); +} + +/* + * The file control system call. + */ +void +fcntl() +{ + register struct file *fp; + register struct a { + int fdes; + int cmd; + int arg; + } *uap; + register int i; + register char *pop; + + uap = (struct a *)u.u_arg; + fp = getf(uap->fdes); + if (fp == NULL) + return; + pop = &u.u_pofile[uap->fdes]; + switch(uap->cmd) { + case F_DUPFD: + i = uap->arg; + if (i < 0 || i >= NOFILE) { + u.u_error = EINVAL; + return; + } + if ((i = ufalloc(i)) < 0) + return; + dupit(i, fp, *pop &~ UF_EXCLOSE); + break; + + case F_GETFD: + u.u_rval = *pop & 1; + break; + + case F_SETFD: + *pop = (*pop &~ 1) | (uap->arg & 1); + break; + + case F_GETFL: + u.u_rval = OFLAGS(fp->f_flag); + break; + + case F_SETFL: + fp->f_flag &= ~FCNTLFLAGS; + fp->f_flag |= (FFLAGS(uap->arg)) & FCNTLFLAGS; + u.u_error = fset (fp, FNONBLOCK, fp->f_flag & FNONBLOCK); + if (u.u_error) + break; + u.u_error = fset (fp, FASYNC, fp->f_flag & FASYNC); + if (u.u_error) + (void) fset (fp, FNONBLOCK, 0); + break; + + case F_GETOWN: + u.u_error = fgetown (fp, &u.u_rval); + break; + + case F_SETOWN: + u.u_error = fsetown (fp, uap->arg); + break; + + default: + u.u_error = EINVAL; + } +} + +int +fioctl(fp, cmd, value) + register struct file *fp; + u_int cmd; + caddr_t value; +{ + return ((*Fops[fp->f_type]->fo_ioctl)(fp, cmd, value)); +} + +/* + * Set/clear file flags: nonblock and async. + */ +int +fset (fp, bit, value) + register struct file *fp; + int bit, value; +{ + if (value) + fp->f_flag |= bit; + else + fp->f_flag &= ~bit; + return (fioctl(fp, (u_int)(bit == FNONBLOCK ? FIONBIO : FIOASYNC), + (caddr_t)&value)); +} + +/* + * Get process group id for a file. + */ +int +fgetown(fp, valuep) + register struct file *fp; + register int *valuep; +{ + register int error; + +#ifdef INET + if (fp->f_type == DTYPE_SOCKET) { + *valuep = mfsd(&fp->f_socket->so_pgrp); + return (0); + } +#endif + error = fioctl(fp, (u_int)TIOCGPGRP, (caddr_t)valuep); + *valuep = -*valuep; + return (error); +} + +/* + * Set process group id for a file. + */ +int +fsetown(fp, value) + register struct file *fp; + int value; +{ +#ifdef INET + if (fp->f_type == DTYPE_SOCKET) { + mtsd(&fp->f_socket->so_pgrp, value); + return (0); + } +#endif + if (value > 0) { + register struct proc *p = pfind(value); + if (p == 0) + return (ESRCH); + value = p->p_pgrp; + } else + value = -value; + return (fioctl(fp, (u_int)TIOCSPGRP, (caddr_t)&value)); +} + +void +close() +{ + register struct a { + int i; + } *uap = (struct a *)u.u_arg; + register struct file *fp; + + GETF(fp, uap->i); + u.u_ofile[uap->i] = NULL; + while (u.u_lastfile >= 0 && u.u_ofile[u.u_lastfile] == NULL) + u.u_lastfile--; + u.u_error = closef(fp); + /* WHAT IF u.u_error ? */ +} + +void +fstat() +{ + register struct file *fp; + register struct a { + int fdes; + struct stat *sb; + } *uap; + struct stat ub; + + uap = (struct a *)u.u_arg; + fp = getf(uap->fdes); + if (fp == NULL) + return; + switch (fp->f_type) { + + case DTYPE_PIPE: + case DTYPE_INODE: + u.u_error = ino_stat((struct inode *)fp->f_data, &ub); + if (fp->f_type == DTYPE_PIPE) + ub.st_size -= fp->f_offset; + break; + +#ifdef INET + case DTYPE_SOCKET: + u.u_error = SOO_STAT(fp->f_socket, &ub); + break; +#endif + default: + u.u_error = EINVAL; + break; + } + if (u.u_error == 0) + u.u_error = copyout((caddr_t)&ub, (caddr_t)uap->sb, + sizeof (ub)); +} + +struct file *lastf; + +/* + * Allocate a user file descriptor + * and a file structure. + * Initialize the descriptor + * to point at the file structure. + */ +struct file * +falloc() +{ + register struct file *fp; + register int i; + + i = ufalloc(0); + if (i < 0) + return (NULL); + if (lastf == 0) + lastf = file; + for (fp = lastf; fp < file+NFILE; fp++) + if (fp->f_count == 0) + goto slot; + for (fp = file; fp < lastf; fp++) + if (fp->f_count == 0) + goto slot; + log(LOG_ERR, "file: table full\n"); + u.u_error = ENFILE; + return (NULL); +slot: + u.u_ofile[i] = fp; + fp->f_count = 1; + fp->f_data = 0; + fp->f_offset = 0; + lastf = fp + 1; + return (fp); +} + +/* + * Convert a user supplied file descriptor into a pointer + * to a file structure. Only task is to check range of the descriptor. + * Critical paths should use the GETF macro unless code size is a + * consideration. + */ +struct file * +getf(f) + register int f; +{ + register struct file *fp; + + if ((unsigned)f >= NOFILE || (fp = u.u_ofile[f]) == NULL) { + u.u_error = EBADF; + return (NULL); + } + return (fp); +} + +/* + * Internal form of close. + * Decrement reference count on file structure. + */ +int +closef(fp) + register struct file *fp; +{ + int error; + + if (fp == NULL) + return(0); + if (fp->f_count > 1) { + fp->f_count--; + return(0); + } + + if ((fp->f_flag & (FSHLOCK|FEXLOCK)) && fp->f_type == DTYPE_INODE) + ino_unlock(fp, FSHLOCK|FEXLOCK); + + error = (*Fops[fp->f_type]->fo_close)(fp); + fp->f_count = 0; + return(error); +} + +/* + * Apply an advisory lock on a file descriptor. + */ +void +flock() +{ + register struct a { + int fd; + int how; + } *uap = (struct a *)u.u_arg; + register struct file *fp; + int error; + + if ((fp = getf(uap->fd)) == NULL) + return; + if (fp->f_type != DTYPE_INODE) { + u.u_error = EOPNOTSUPP; + return; + } + if (uap->how & LOCK_UN) { + ino_unlock(fp, FSHLOCK | FEXLOCK); + return; + } + if ((uap->how & (LOCK_SH | LOCK_EX)) == 0) + return; /* error? */ + if (uap->how & LOCK_EX) + uap->how &= ~LOCK_SH; + /* avoid work... */ + if ((fp->f_flag & FEXLOCK) && (uap->how & LOCK_EX)) + return; + if ((fp->f_flag & FSHLOCK) && (uap->how & LOCK_SH)) + return; + error = ino_lock(fp, uap->how); + u.u_error = error; +} + +/* + * File Descriptor pseudo-device driver (/dev/fd/). + * + * Opening minor device N dup()s the file (if any) connected to file + * descriptor N belonging to the calling process. Note that this driver + * consists of only the ``open()'' routine, because all subsequent + * references to this file will be direct to the other driver. + */ +/* ARGSUSED */ +int +fdopen(dev, mode, type) + dev_t dev; + int mode, type; +{ + /* + * XXX Kludge: set u.u_dupfd to contain the value of the + * the file descriptor being sought for duplication. The error + * return ensures that the vnode for this device will be released + * by vn_open. Open will detect this special error and take the + * actions in dupfdopen below. Other callers of vn_open will + * simply report the error. + */ + u.u_dupfd = minor(dev); + return(ENODEV); +} + +/* + * Duplicate the specified descriptor to a free descriptor. + */ +int +dupfdopen (indx, dfd, mode, error) + register int indx, dfd; + int mode; + int error; +{ + register struct file *wfp; + struct file *fp; + + /* + * If the to-be-dup'd fd number is greater than the allowed number + * of file descriptors, or the fd to be dup'd has already been + * closed, reject. Note, check for new == old is necessary as + * falloc could allocate an already closed to-be-dup'd descriptor + * as the new descriptor. + */ + fp = u.u_ofile[indx]; + if (dfd >= NOFILE || (wfp = u.u_ofile[dfd]) == NULL || fp == wfp) + return(EBADF); + + /* + * There are two cases of interest here. + * + * For ENODEV simply dup (dfd) to file descriptor + * (indx) and return. + * + * For ENXIO steal away the file structure from (dfd) and + * store it in (indx). (dfd) is effectively closed by + * this operation. + * + * NOTE: ENXIO only comes out of the 'portal fs' code of 4.4 - since + * 2.11BSD does not implement the portal fs the code is ifdef'd out + * and a short message output. + * + * Any other error code is just returned. + */ + switch (error) { + case ENODEV: + /* + * Check that the mode the file is being opened for is a + * subset of the mode of the existing descriptor. + */ + if (((mode & (FREAD|FWRITE)) | wfp->f_flag) != wfp->f_flag) + return(EACCES); + u.u_ofile[indx] = wfp; + u.u_pofile[indx] = u.u_pofile[dfd]; + wfp->f_count++; + if (indx > u.u_lastfile) + u.u_lastfile = indx; + return(0); +#ifdef haveportalfs + case ENXIO: + /* + * Steal away the file pointer from dfd, and stuff it into indx. + */ + fdp->fd_ofiles[indx] = fdp->fd_ofiles[dfd]; + fdp->fd_ofiles[dfd] = NULL; + fdp->fd_ofileflags[indx] = fdp->fd_ofileflags[dfd]; + fdp->fd_ofileflags[dfd] = 0; + /* + * Complete the clean up of the filedesc structure by + * recomputing the various hints. + */ + if (indx > fdp->fd_lastfile) + fdp->fd_lastfile = indx; + else + while (fdp->fd_lastfile > 0 && + fdp->fd_ofiles[fdp->fd_lastfile] == NULL) + fdp->fd_lastfile--; + if (dfd < fdp->fd_freefile) + fdp->fd_freefile = dfd; + return (0); +#else + log(LOG_NOTICE, "dupfdopen"); + /* FALLTHROUGH */ +#endif + default: + return(error); + } + /* NOTREACHED */ +} diff --git a/sys/kernel/kern_exec.c b/sys/kernel/kern_exec.c new file mode 100644 index 0000000..18cfbbf --- /dev/null +++ b/sys/kernel/kern_exec.c @@ -0,0 +1,539 @@ +/* + * Copyright (c) 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "param.h" +#include "systm.h" +#include "map.h" +#include "user.h" +#include "proc.h" +#include "buf.h" +#include "inode.h" +#include "namei.h" +#include "fs.h" +#include "mount.h" +#include "file.h" +#include "signalvar.h" + +/* + * exec system call, with and without environments. + */ +struct execa { + char *fname; + char **argp; + char **envp; +}; + +/* + * Reset signals for an exec of the specified process. In 4.4 this function + * was in kern_sig.c but since in 2.11 kern_sig and kern_exec will likely be + * in different overlays placing this here potentially saves a kernel overlay + * switch. + */ +static void +execsigs(p) + register struct proc *p; +{ + register int nc; + unsigned long mask; + + /* + * Reset caught signals. Held signals remain held + * through p_sigmask (unless they were caught, + * and are now ignored by default). + */ + while (p->p_sigcatch) { + nc = ffs(p->p_sigcatch); + mask = sigmask(nc); + p->p_sigcatch &= ~mask; + if (sigprop[nc] & SA_IGNORE) { + if (nc != SIGCONT) + p->p_sigignore |= mask; + p->p_sig &= ~mask; + } + u.u_signal[nc] = SIG_DFL; + } + /* + * Reset stack state to the user stack (disable the alternate stack). + */ + u.u_sigstk.ss_flags = SA_DISABLE; + u.u_sigstk.ss_size = 0; + u.u_sigstk.ss_base = 0; + u.u_psflags = 0; +} + +/* + * Read in and set up memory for executed file. + * u.u_error set on error + */ +static void +getxfile (ip, ep, nargc, uid, gid) + struct inode *ip; + register struct exec *ep; + int nargc, uid, gid; +{ + u_int ds, ts, ss; + + if (ep->a_magic == OMAGIC) { + ep->a_data += ep->a_text; + ep->a_text = 0; + } + + if (ep->a_text != 0 && (ip->i_flag & ITEXT) == 0 && + ip->i_count != 1) { + register struct file *fp; + + for (fp = file; fp < file+NFILE; fp++) { + if (fp->f_type == DTYPE_INODE && + fp->f_count > 0 && + (struct inode*)fp->f_data == ip && + (fp->f_flag & FWRITE)) { + u.u_error = ETXTBSY; + return; + } + } + } + + /* + * find text and data sizes try; them out for possible + * overflow of max sizes + */ + ts = ep->a_text; + ds = ep->a_data + ep->a_bss; + ss = SSIZE + nargc; + +//printf ("getxfile: size t/d/s = %u/%u/%u\n", ts, ds, ss); + if (ts + ds + ss > MAXMEM) { + u.u_error = ENOMEM; + return; + } + + /* + * Allocate core at this point, committed to the new image. + */ + u.u_prof.pr_scale = 0; + if (u.u_procp->p_flag & SVFORK) + endvfork(); + u.u_procp->p_dsize = ds; + u.u_procp->p_daddr = USER_DATA_START; + u.u_procp->p_ssize = ss; + u.u_procp->p_saddr = USER_DATA_END - ss; + + /* read in text and data */ +//printf ("getxfile: read %u bytes at %08x\n", ep->a_data, USER_DATA_START); + rdwri (UIO_READ, ip, (caddr_t) USER_DATA_START, ep->a_data, + sizeof(struct exec) + ep->a_text, IO_UNIT, (int*) 0); + + /* clear BSS and stack */ +//printf ("getxfile: clear %u bytes at %08x\n", USER_DATA_END - USER_DATA_START - ep->a_data, USER_DATA_START + ep->a_data); + bzero ((void*) (USER_DATA_START + ep->a_data), + USER_DATA_END - USER_DATA_START - ep->a_data); + + /* + * set SUID/SGID protections, if no tracing + */ + if ((u.u_procp->p_flag & P_TRACED) == 0) { + u.u_uid = uid; + u.u_procp->p_uid = uid; + u.u_groups[0] = gid; + } else + psignal (u.u_procp, SIGTRAP); + u.u_svuid = u.u_uid; + u.u_svgid = u.u_groups[0]; + + u.u_tsize = ts; + u.u_dsize = ds; + u.u_ssize = ss; +} + +void printmem (unsigned addr, int nbytes) +{ + for (; nbytes>0; addr+=16, nbytes-=16) { + unsigned char *p = (unsigned char*) addr; + printf ("%08x: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", + addr, p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], + p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]); + } +} + +void +execv() +{ + struct execa *arg = (struct execa *)u.u_arg; + + arg->envp = NULL; + execve(); +} + +void +execve() +{ + register char *cp; + register struct buf *bp; + struct execa *uap = (struct execa *)u.u_arg; + int nc, na, ne, ucp, ap, indir, uid, gid, resid, error; + register int cc; + unsigned len; + char *sharg; + struct inode *ip; + size_t bno; + char cfname [MAXCOMLEN + 1]; +#define SHSIZE 32 + char cfarg [SHSIZE]; + union { + char ex_shell [SHSIZE]; /* #! and name of interpreter */ + struct exec ex_exec; + } exdata; + struct nameidata nd; + register struct nameidata *ndp = &nd; + +//printf ("execve ('%s', ['%s', '%s', ...])\n", uap->fname, uap->argp[0], uap->argp[1]); + NDINIT (ndp, LOOKUP, FOLLOW, uap->fname); + ip = namei (ndp); + if (ip == NULL) { +//printf ("execve: file not found\n"); + return; + } + bno = 0; + bp = 0; + indir = 0; + uid = u.u_uid; + gid = u.u_groups[0]; + if (ip->i_fs->fs_flags & MNT_NOEXEC) { +//printf ("execve: NOEXEC, flags=%o\n", ip->i_fs->fs_flags); + u.u_error = EACCES; + goto done; + } + if ((ip->i_fs->fs_flags & MNT_NOSUID) == 0) { + if (ip->i_mode & ISUID) + uid = ip->i_uid; + if (ip->i_mode & ISGID) + gid = ip->i_gid; + } +again: + if (access (ip, IEXEC)) { +//printf ("execve: no IEXEC\n"); + goto done; + } + if ((u.u_procp->p_flag & P_TRACED) && access (ip, IREAD)) { +//printf ("execve: traced, but no IREAD\n"); + goto done; + } + if ((ip->i_mode & IFMT) != IFREG || + (ip->i_mode & (IEXEC | (IEXEC>>3) | (IEXEC>>6))) == 0) { +//printf ("execve: no IEXEC, mode=%o\n", ip->i_mode); + u.u_error = EACCES; + goto done; + } + + /* + * Read in first few bytes of file for segment sizes, magic number: + * 407 = plain executable + * Also an ASCII line beginning with #! is + * the file name of a ``shell'' and arguments may be prepended + * to the argument list if given here. + * + * SHELL NAMES ARE LIMITED IN LENGTH. + * + * ONLY ONE ARGUMENT MAY BE PASSED TO THE SHELL FROM + * THE ASCII LINE. + */ + exdata.ex_shell[0] = '\0'; /* for zero length files */ + u.u_error = rdwri (UIO_READ, ip, (caddr_t) &exdata, sizeof(exdata), + (off_t) 0, IO_UNIT, &resid); + if (u.u_error) { +//printf ("execve: rdwri error %d\n", u.u_error); + goto done; + } + if (resid > sizeof(exdata) - sizeof(exdata.ex_exec) && + exdata.ex_shell[0] != '#') { +//printf ("execve: short read, resid = %d, shell=%.32s\n", resid, exdata.ex_shell); + u.u_error = ENOEXEC; + goto done; + } +//printf ("execve: text=%u, data=%u, bss=%u\n", exdata.ex_exec.a_text, exdata.ex_exec.a_data, exdata.ex_exec.a_bss); + + switch ((int) exdata.ex_exec.a_magic) { + case OMAGIC: + case NMAGIC: + break; + default: + if (exdata.ex_shell[0] != '#' || + exdata.ex_shell[1] != '!' || + indir) { +//printf ("execve: bad shell=%.32s\n", exdata.ex_shell); + u.u_error = ENOEXEC; + goto done; + } + /* + * If setuid/gid scripts were to be disallowed this is where it would + * have to be done. + * u.u_uid = uid; + * u.u_gid = u_groups[0]; + */ + cp = &exdata.ex_shell[2]; /* skip "#!" */ + while (cp < &exdata.ex_shell[SHSIZE]) { + if (*cp == '\t') + *cp = ' '; + else if (*cp == '\n') { + *cp = '\0'; + break; + } + cp++; + } + if (*cp != '\0') { + u.u_error = ENOEXEC; + goto done; + } + cp = &exdata.ex_shell[2]; + while (*cp == ' ') + cp++; + ndp->ni_dirp = cp; + while (*cp && *cp != ' ') + cp++; + cfarg[0] = '\0'; + if (*cp) { + *cp++ = '\0'; + while (*cp == ' ') + cp++; + if (*cp) + bcopy ((caddr_t) cp, (caddr_t) cfarg, SHSIZE); + } + indir = 1; + iput (ip); + ndp->ni_nameiop = LOOKUP | FOLLOW; + ip = namei (ndp); + if (ip == NULL) + return; + bcopy ((caddr_t) ndp->ni_dent.d_name, (caddr_t) cfname, MAXCOMLEN); + cfname [MAXCOMLEN] = '\0'; + goto again; + } + + /* + * Collect arguments on "file" in swap space. + */ + na = 0; + ne = 0; + nc = 0; + cc = 0; + cp = 0; + bno = malloc (swapmap, btod (NCARGS + MAXBSIZE)); + if (bno == 0) { + u.u_error = ENOMEM; + goto done; + } + /* + * Copy arguments into file in argdev area. + */ + if (uap->argp) for (;;) { + ap = NULL; + sharg = NULL; + if (indir && na == 0) { + sharg = cfname; + ap = (int) sharg; + uap->argp++; /* ignore argv[0] */ + } else if (indir && (na == 1 && cfarg[0])) { + sharg = cfarg; + ap = (int) sharg; + } else if (indir && (na == 1 || (na == 2 && cfarg[0]))) + ap = (int) uap->fname; + else if (uap->argp) { + ap = *(int*) uap->argp; + uap->argp++; + } + if (ap == NULL && uap->envp) { + uap->argp = NULL; + ap = *(int*) uap->envp; + if (ap != NULL) + uap->envp++, ne++; + } + if (ap == NULL) + break; + na++; + if (ap == -1) { + u.u_error = EFAULT; + break; + } + do { + if (cc <= 0) { + /* + * We depend on NCARGS being a multiple of + * DEV_BSIZE. This way we need only check + * overflow before each buffer allocation. + */ + if (nc >= NCARGS-1) { +//printf ("execve: too many args = %d\n", nc); + error = E2BIG; + break; + } + if (bp) { + bdwrite(bp); + } + cc = DEV_BSIZE; + bp = getblk (swapdev, dbtofsb(bno) + lblkno(nc)); + cp = bp->b_addr; + } + if (sharg) { + error = copystr (sharg, cp, (unsigned) cc, &len); +//printf ("execve arg%d=%s: %u bytes from %08x to %08x\n", na-1, sharg, len, sharg, cp); + sharg += len; + } else { + error = copystr ((caddr_t) ap, cp, (unsigned) cc, &len); +//printf ("execve arg%d=%s: %u bytes from %08x to %08x\n", na-1, ap, len, ap, cp); + ap += len; + } + cp += len; + nc += len; + cc -= len; + } while (error == ENOENT); + if (error) { +//printf ("execve: copy arg error = %d\n", error); + u.u_error = error; + if (bp) { + bp->b_flags |= B_AGE; + bp->b_flags &= ~B_DELWRI; + brelse(bp); + } + bp = 0; + goto badarg; + } + } +//printf ("execve: argc=%d, envc=%d, total %d bytes\n", na, ne, nc); + if (bp) { + bdwrite (bp); + } + bp = 0; + nc = (nc + NBPW-1) & ~(NBPW-1); + getxfile (ip, &exdata.ex_exec, nc + (na+4)*NBPW, uid, gid); + if (u.u_error) { +//printf ("execve: getxfile error = %d\n", u.u_error); +badarg: + for (cc = 0; cc < nc; cc += DEV_BSIZE) { + daddr_t blkno; + + blkno = dbtofsb(bno) + lblkno(cc); + if (incore (swapdev, blkno)) { + bp = bread (swapdev, blkno); + bp->b_flags |= B_AGE; /* throw away */ + bp->b_flags &= ~B_DELWRI; /* cancel io */ + brelse(bp); + bp = 0; + } + } + goto done; + } + iput(ip); + ip = NULL; + + /* + * Copy back arglist. + */ + ucp = USER_DATA_END - nc - NBPW; + ap = ucp - na*NBPW - 2*NBPW; + u.u_frame [FRAME_SP] = ap - 16; + u.u_frame [FRAME_R4] = na - ne; /* $a0 := argc */ + u.u_frame [FRAME_R5] = ap; /* $a1 := argv */ + u.u_frame [FRAME_R6] = ap + (na-ne+1)*NBPW; /* $a2 := env */ + *(int*) (USER_DATA_END - NBPW) = ap; /* for /bin/ps */ + nc = 0; + cc = 0; + for (;;) { + if (na == ne) { + *(int*) ap = 0; + ap += NBPW; + } + if (--na < 0) + break; + *(int*) ap = ucp; + do { + if (cc <= 0) { + if (bp) { + brelse(bp); + } + cc = DEV_BSIZE; + bp = bread (swapdev, dbtofsb(bno) + lblkno(nc)); + bp->b_flags |= B_AGE; /* throw away */ + bp->b_flags &= ~B_DELWRI; /* cancel io */ + cp = bp->b_addr; + } + error = copystr (cp, (caddr_t) ucp, (unsigned) cc, + &len); +//printf ("execve copy '%s' %u bytes from %08x to %08x\n", cp, len, cp, ucp); + ucp += len; + cp += len; + nc += len; + cc -= len; + } while (error == ENOENT); + if (error == EFAULT) + panic ("exec: EFAULT"); + ap += NBPW; + } + *(int*) ap = 0; + if (bp) { + bp->b_flags |= B_AGE; + brelse (bp); + bp = NULL; + } + execsigs (u.u_procp); + for (cp = u.u_pofile, cc = 0; cc <= u.u_lastfile; cc++, cp++) { + if (*cp & UF_EXCLOSE) { + (void) closef (u.u_ofile [cc]); + u.u_ofile [cc] = NULL; + *cp = 0; + } + } + while (u.u_lastfile >= 0 && u.u_ofile [u.u_lastfile] == NULL) + u.u_lastfile--; + + /* + * Clear registers. + */ + u.u_frame [FRAME_R1] = 0; /* $at */ + u.u_frame [FRAME_R2] = 0; /* $v0 */ + u.u_frame [FRAME_R3] = 0; /* $v1 */ + u.u_frame [FRAME_R7] = 0; /* $a3 */ + u.u_frame [FRAME_R8] = 0; /* $t0 */ + u.u_frame [FRAME_R9] = 0; /* $t1 */ + u.u_frame [FRAME_R10] = 0; /* $t2 */ + u.u_frame [FRAME_R11] = 0; /* $t3 */ + u.u_frame [FRAME_R12] = 0; /* $t4 */ + u.u_frame [FRAME_R13] = 0; /* $t5 */ + u.u_frame [FRAME_R14] = 0; /* $t6 */ + u.u_frame [FRAME_R15] = 0; /* $t7 */ + u.u_frame [FRAME_R16] = 0; /* $s0 */ + u.u_frame [FRAME_R17] = 0; /* $s1 */ + u.u_frame [FRAME_R18] = 0; /* $s2 */ + u.u_frame [FRAME_R19] = 0; /* $s3 */ + u.u_frame [FRAME_R20] = 0; /* $s4 */ + u.u_frame [FRAME_R21] = 0; /* $s5 */ + u.u_frame [FRAME_R22] = 0; /* $s6 */ + u.u_frame [FRAME_R23] = 0; /* $s7 */ + u.u_frame [FRAME_R24] = 0; /* $t8 */ + u.u_frame [FRAME_R25] = 0; /* $t9 */ + u.u_frame [FRAME_FP] = 0; + u.u_frame [FRAME_RA] = 0; + u.u_frame [FRAME_LO] = 0; + u.u_frame [FRAME_HI] = 0; + u.u_frame [FRAME_GP] = 0; + u.u_frame [FRAME_PC] = exdata.ex_exec.a_entry; + + /* + * Remember file name for accounting. + */ + bcopy ((caddr_t) (indir ? cfname : ndp->ni_dent.d_name), + (caddr_t) u.u_comm, MAXCOMLEN); +done: +//printf ("execve done: PC=%08x, SP=%08x, R4=%08x, R5=%08x, R6=%08x\n", +// u.u_frame [FRAME_PC], u.u_frame [FRAME_SP], +// u.u_frame [FRAME_R4], u.u_frame [FRAME_R5], u.u_frame [FRAME_R6]); + if (bp) { + bp->b_flags |= B_AGE; + brelse (bp); + } + if (bno) + mfree (swapmap, btod (NCARGS + MAXBSIZE), bno); + if (ip) + iput(ip); +} diff --git a/sys/kernel/kern_exit.c b/sys/kernel/kern_exit.c new file mode 100644 index 0000000..b665add --- /dev/null +++ b/sys/kernel/kern_exit.c @@ -0,0 +1,280 @@ +/* + * Copyright (c) 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "param.h" +#include "systm.h" +#include "map.h" +#include "user.h" +#include "proc.h" +#include "inode.h" +#include "vm.h" +#include "file.h" +#include "wait.h" +#include "kernel.h" + +/* + * Notify parent that vfork child is finished with parent's data. Called + * during exit/exec(getxfile). The child + * must be locked in core so it will be in core when the parent runs. + */ +void +endvfork() +{ + register struct proc *rip, *rpp; + + rpp = u.u_procp; + rip = rpp->p_pptr; + rpp->p_flag &= ~SVFORK; + rpp->p_flag |= SLOCK; + wakeup ((caddr_t) rpp); + while (! (rpp->p_flag & SVFDONE)) + sleep ((caddr_t) rip, PZERO-1); + /* + * The parent has taken back our data+stack, set our sizes to 0. + */ + u.u_dsize = rpp->p_dsize = 0; + u.u_ssize = rpp->p_ssize = 0; + rpp->p_flag &= ~(SVFDONE | SLOCK); +} + +/* + * Exit: deallocate address space and other resources, + * change proc state to zombie, and unlink proc from allproc + * list. Save exit status and rusage for wait4(). + * Check for child processes and orphan them. + */ +void +exit (rv) + int rv; +{ + register int i; + register struct proc *p; + struct proc **pp; + + p = u.u_procp; + p->p_flag &= ~P_TRACED; + p->p_sigignore = ~0; + p->p_sig = 0; + /* + * 2.11 doesn't need to do this and it gets overwritten anyway. + * p->p_realtimer.it_value = 0; + */ + for (i = 0; i <= u.u_lastfile; i++) { + register struct file *f; + + f = u.u_ofile[i]; + u.u_ofile[i] = NULL; + u.u_pofile[i] = 0; + (void) closef(f); + } + ilock(u.u_cdir); + iput(u.u_cdir); + if (u.u_rdir) { + ilock(u.u_rdir); + iput(u.u_rdir); + } + u.u_rlimit[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY; + + if (p->p_flag & SVFORK) + endvfork(); + + if (p->p_pid == 1) + panic("init died"); + if ((*p->p_prev = p->p_nxt) != NULL) /* off allproc queue */ + p->p_nxt->p_prev = p->p_prev; + p->p_nxt = zombproc; /* onto zombproc */ + if (p->p_nxt != NULL) + p->p_nxt->p_prev = &p->p_nxt; + p->p_prev = &zombproc; + zombproc = p; + p->p_stat = SZOMB; + + noproc = 1; + for (pp = &pidhash[PIDHASH(p->p_pid)]; *pp; pp = &(*pp)->p_hash) + if (*pp == p) { + *pp = p->p_hash; + goto done; + } + panic("exit"); +done: + /* + * Overwrite p_alive substructure of proc - better not be anything + * important left! + */ + p->p_xstat = rv; + p->p_ru = u.u_ru; + ruadd(&p->p_ru, &u.u_cru); + { + register struct proc *q; + int doingzomb = 0; + + q = allproc; +again: + for(; q; q = q->p_nxt) + if (q->p_pptr == p) { + q->p_pptr = &proc[1]; + q->p_ppid = 1; + wakeup((caddr_t)&proc[1]); + if (q->p_flag& P_TRACED) { + q->p_flag &= ~P_TRACED; + psignal(q, SIGKILL); + } else if (q->p_stat == SSTOP) { + psignal(q, SIGHUP); + psignal(q, SIGCONT); + } + } + if (!doingzomb) { + doingzomb = 1; + q = zombproc; + goto again; + } + } + psignal(p->p_pptr, SIGCHLD); + wakeup((caddr_t) p->p_pptr); + wakeup((caddr_t) &runin); + swtch(); + /* NOTREACHED */ +} + +/* + * exit system call: pass back caller's arg + */ +void +rexit() +{ + register struct a { + int rval; + } *uap = (struct a*) u.u_arg; + + exit (W_EXITCODE (uap->rval, 0)); + /* NOTREACHED */ +} + +struct args { + int pid; + int *status; + int options; + struct rusage *rusage; +}; + +/* + * Wait: check child processes to see if any have exited, + * stopped under trace or (optionally) stopped by a signal. + * Pass back status and make available for reuse the exited + * child's proc structure. + */ +static int +wait1 (q, uap, retval) + struct proc *q; + register struct args *uap; + int retval[]; +{ + int nfound, status; + struct rusage ru; /* used for local conversion */ + register struct proc *p; + register int error; + + if (uap->pid == WAIT_MYPGRP) /* == 0 */ + uap->pid = -q->p_pgrp; +loop: + nfound = 0; + /* + * 4.X has child links in the proc structure, so they consolidate + * these two tests into one loop. We only have the zombie chain + * and the allproc chain, so we check for ZOMBIES first, then for + * children that have changed state. We check for ZOMBIES first + * because they are more common, and, as the list is typically small, + * a faster check. + */ + for (p = zombproc; p; p = p->p_nxt) { + if (p->p_pptr != q) /* are we the parent of this process? */ + continue; + if (uap->pid != WAIT_ANY && + p->p_pid != uap->pid && p->p_pgrp != -uap->pid) + continue; + retval[0] = p->p_pid; + retval[1] = p->p_xstat; + if (uap->status && (error = copyout ((caddr_t) &p->p_xstat, + (caddr_t) uap->status, sizeof (uap->status)))) + return(error); + if (uap->rusage) { + rucvt(&ru, &p->p_ru); + error = copyout ((caddr_t) &ru, (caddr_t) uap->rusage, sizeof (ru)); + if (error) + return(error); + } + ruadd(&u.u_cru, &p->p_ru); + p->p_xstat = 0; + p->p_stat = NULL; + p->p_pid = 0; + p->p_ppid = 0; + if ((*p->p_prev = p->p_nxt) != NULL) /* off zombproc */ + p->p_nxt->p_prev = p->p_prev; + p->p_nxt = freeproc; /* onto freeproc */ + freeproc = p; + p->p_pptr = 0; + p->p_sig = 0; + p->p_sigcatch = 0; + p->p_sigignore = 0; + p->p_sigmask = 0; + p->p_pgrp = 0; + p->p_flag = 0; + p->p_wchan = 0; + return (0); + } + for (p = allproc; p;p = p->p_nxt) { + if (p->p_pptr != q) + continue; + if (uap->pid != WAIT_ANY && + p->p_pid != uap->pid && p->p_pgrp != -uap->pid) + continue; + ++nfound; + if (p->p_stat == SSTOP && ! (p->p_flag & P_WAITED) && + (p->p_flag & P_TRACED || uap->options & WUNTRACED)) { + p->p_flag |= P_WAITED; + retval[0] = p->p_pid; + error = 0; + if (uap->status) { + status = W_STOPCODE(p->p_ptracesig); + error = copyout ((caddr_t) &status, + (caddr_t) uap->status, sizeof (status)); + } + return (error); + } + } + if (nfound == 0) + return (ECHILD); + if (uap->options&WNOHANG) { + retval[0] = 0; + return (0); + } + error = tsleep ((caddr_t) q, PWAIT|PCATCH, 0); + if (error == 0) + goto loop; + return(error); +} + +void +wait4() +{ + int retval[2]; + register struct args *uap = (struct args*) u.u_arg; + + retval[0] = 0; + u.u_error = wait1 (u.u_procp, uap, retval); + if (! u.u_error) + u.u_rval = retval[0]; +} + +void +reboot() +{ + struct a { + int opt; + }; + + if (suser ()) + boot (rootdev, ((struct a*)u.u_arg)->opt); +} diff --git a/sys/kernel/kern_fork.c b/sys/kernel/kern_fork.c new file mode 100644 index 0000000..603812a --- /dev/null +++ b/sys/kernel/kern_fork.c @@ -0,0 +1,254 @@ +/* + * Copyright (c) 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "param.h" +#include "systm.h" +#include "map.h" +#include "user.h" +#include "proc.h" +#include "inode.h" +#include "file.h" +#include "vm.h" +#include "kernel.h" +#include "syslog.h" + +int mpid; /* generic for unique process id's */ + +/* + * Create a new process -- the internal version of system call fork. + * It returns 1 in the new process, 0 in the old. + */ +int +newproc (isvfork) + int isvfork; +{ + register struct proc *child, *parent; + register int n; + static int pidchecked = 0; + struct file *fp; + + /* + * First, just locate a slot for a process + * and copy the useful info from this process into it. + * The panic "cannot happen" because fork has already + * checked for the existence of a slot. + */ + mpid++; +retry: + if (mpid >= 30000) { + mpid = 100; + pidchecked = 0; + } + if (mpid >= pidchecked) { + int doingzomb = 0; + + pidchecked = 30000; + /* + * Scan the proc table to check whether this pid + * is in use. Remember the lowest pid that's greater + * than mpid, so we can avoid checking for a while. + */ + child = allproc; +again: + for (; child != NULL; child = child->p_nxt) { + if (child->p_pid == mpid || child->p_pgrp == mpid) { + mpid++; + if (mpid >= pidchecked) + goto retry; + } + if (child->p_pid > mpid && pidchecked > child->p_pid) + pidchecked = child->p_pid; + if (child->p_pgrp > mpid && pidchecked > child->p_pgrp) + pidchecked = child->p_pgrp; + } + if (!doingzomb) { + doingzomb = 1; + child = zombproc; + goto again; + } + } + child = freeproc; + if (child == NULL) + panic("no procs"); + + freeproc = child->p_nxt; /* off freeproc */ + + /* + * Make a proc table entry for the new process. + */ + parent = u.u_procp; + child->p_stat = SIDL; + child->p_realtimer.it_value = 0; + child->p_flag = SLOAD; + child->p_uid = parent->p_uid; + child->p_pgrp = parent->p_pgrp; + child->p_nice = parent->p_nice; + child->p_pid = mpid; + child->p_ppid = parent->p_pid; + child->p_pptr = parent; + child->p_time = 0; + child->p_cpu = 0; + child->p_sigmask = parent->p_sigmask; + child->p_sigcatch = parent->p_sigcatch; + child->p_sigignore = parent->p_sigignore; + /* take along any pending signals like stops? */ +#ifdef UCB_METER + if (isvfork) { + forkstat.cntvfork++; + forkstat.sizvfork += (parent->p_dsize + parent->p_ssize) >> 10; + } else { + forkstat.cntfork++; + forkstat.sizfork += (parent->p_dsize + parent->p_ssize) >> 10; + } +#endif + child->p_wchan = 0; + child->p_slptime = 0; + { + struct proc **hash = &pidhash [PIDHASH (child->p_pid)]; + + child->p_hash = *hash; + *hash = child; + } + /* + * some shuffling here -- in most UNIX kernels, the allproc assign + * is done after grabbing the struct off of the freeproc list. We + * wait so that if the clock interrupts us and vmtotal walks allproc + * the text pointer isn't garbage. + */ + child->p_nxt = allproc; /* onto allproc */ + child->p_nxt->p_prev = &child->p_nxt; /* (allproc is never NULL) */ + child->p_prev = &allproc; + allproc = child; + + /* + * Increase reference counts on shared objects. + */ + for (n = 0; n <= u.u_lastfile; n++) { + fp = u.u_ofile[n]; + if (fp == NULL) + continue; + fp->f_count++; + } + u.u_cdir->i_count++; + if (u.u_rdir) + u.u_rdir->i_count++; + + /* + * When the longjmp is executed for the new process, + * here's where it will resume. + */ + if (setjmp (&u.u_ssave)) { + return(1); + } + + child->p_dsize = parent->p_dsize; + child->p_ssize = parent->p_ssize; + child->p_daddr = parent->p_daddr; + child->p_saddr = parent->p_saddr; + + /* + * Partially simulate the environment of the new process so that + * when it is actually created (by copying) it will look right. + */ + u.u_procp = child; + + /* + * Swap out the current process to generate the copy. + */ + parent->p_stat = SIDL; + child->p_addr = parent->p_addr; + child->p_stat = SRUN; + swapout (child, X_DONTFREE, X_OLDSIZE, X_OLDSIZE); + child->p_flag |= SSWAP; + parent->p_stat = SRUN; + u.u_procp = parent; + + if (isvfork) { + /* + * Wait for the child to finish with it. + * RetroBSD: to make this work, significant + * changes in scheduler are required. + */ + parent->p_dsize = 0; + parent->p_ssize = 0; + child->p_flag |= SVFORK; + parent->p_flag |= SVFPRNT; + while (child->p_flag & SVFORK) + sleep ((caddr_t)child, PSWP+1); + if ((child->p_flag & SLOAD) == 0) + panic ("newproc vfork"); + u.u_dsize = parent->p_dsize = child->p_dsize; + parent->p_daddr = child->p_daddr; + child->p_dsize = 0; + u.u_ssize = parent->p_ssize = child->p_ssize; + parent->p_saddr = child->p_saddr; + child->p_ssize = 0; + child->p_flag |= SVFDONE; + wakeup ((caddr_t) parent); + parent->p_flag &= ~SVFPRNT; + } + return(0); +} + +static void +fork1 (isvfork) + int isvfork; +{ + register int a; + register struct proc *p1, *p2; + + a = 0; + if (u.u_uid != 0) { + for (p1 = allproc; p1; p1 = p1->p_nxt) + if (p1->p_uid == u.u_uid) + a++; + for (p1 = zombproc; p1; p1 = p1->p_nxt) + if (p1->p_uid == u.u_uid) + a++; + } + /* + * Disallow if + * No processes at all; + * not su and too many procs owned; or + * not su and would take last slot. + */ + p2 = freeproc; + if (p2==NULL) + log(LOG_ERR, "proc: table full\n"); + + if (p2==NULL || (u.u_uid!=0 && (p2->p_nxt == NULL || a>MAXUPRC))) { + u.u_error = EAGAIN; + return; + } + p1 = u.u_procp; + if (newproc (isvfork)) { + /* Child */ + u.u_rval = 0; + u.u_start = time.tv_sec; + bzero(&u.u_ru, sizeof(u.u_ru)); + bzero(&u.u_cru, sizeof(u.u_cru)); + return; + } + /* Parent */ + u.u_rval = p2->p_pid; +} + +/* + * fork system call + */ +void +fork() +{ + fork1 (0); +} + +/* + * vfork system call, fast version of fork + */ +void +vfork() +{ + fork1 (1); +} diff --git a/sys/kernel/kern_glob.c b/sys/kernel/kern_glob.c new file mode 100644 index 0000000..34203d1 --- /dev/null +++ b/sys/kernel/kern_glob.c @@ -0,0 +1,61 @@ +/* + * Global memory area system. + * + * Works with two system calls: + * + * byte = rdglob(addr); + * success = wrglob(addr,byte); + */ +#include "param.h" +#include "systm.h" +#include "user.h" + +#ifndef GLOBSZ +#define GLOBSZ 256 +#endif + +unsigned char global_segment[GLOBSZ]; + +void rdglob() +{ + struct a { + int addr; + } *uap = (struct a *)u.u_arg; + + // Only root should have access to the shared memory block + if(u.u_uid!=0) + { + u.u_rval = -1; + return; + } + + if(uap->addr>=GLOBSZ) + { + u.u_rval = -1; + return; + } + u.u_rval = global_segment[uap->addr]; +} + +void wrglob() +{ + struct a { + int addr; + unsigned char value; + } *uap = (struct a *)u.u_arg; + + // Only root should have access to the shared memory block + if(u.u_uid!=0) + { + u.u_rval = -1; + return; + } + + if(uap->addr>=GLOBSZ) + { + u.u_rval = -1; + return; + } + u.u_rval = 0; + global_segment[uap->addr] = uap->value; +} diff --git a/sys/kernel/kern_mman.c b/sys/kernel/kern_mman.c new file mode 100644 index 0000000..839b7f3 --- /dev/null +++ b/sys/kernel/kern_mman.c @@ -0,0 +1,38 @@ +/* + * Copyright (c) 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "param.h" +#include "user.h" +#include "proc.h" +#include "vm.h" +#include "systm.h" + +void +brk() +{ + struct a { + int naddr; + }; + register int newsize, d; + + /* set newsize to new data size */ + newsize = ((struct a*)u.u_arg)->naddr - u.u_procp->p_daddr; + if (newsize < 0) + newsize = 0; + if (u.u_tsize + newsize + u.u_ssize > MAXMEM) { + u.u_error = ENOMEM; + return; + } + + u.u_procp->p_dsize = newsize; + + /* set d to (new - old) */ + d = newsize - u.u_dsize; +//printf ("brk: new size %u bytes, incremented by %d\n", newsize, d); + if (d > 0) + bzero ((void*) (u.u_procp->p_daddr + u.u_dsize), d); + u.u_dsize = newsize; + u.u_rval = u.u_procp->p_daddr + u.u_dsize; +} diff --git a/sys/kernel/kern_proc.c b/sys/kernel/kern_proc.c new file mode 100644 index 0000000..1df38e8 --- /dev/null +++ b/sys/kernel/kern_proc.c @@ -0,0 +1,65 @@ +/* + * Copyright (c) 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "param.h" +#include "user.h" +#include "proc.h" +#include "systm.h" + +/* + * Is p an inferior of the current process? + */ +int +inferior(p) + register struct proc *p; +{ + for (; p != u.u_procp; p = p->p_pptr) + if (p->p_ppid == 0) + return (0); + return (1); +} + +/* + * Find a process by pid. + */ +struct proc * +pfind (pid) + register int pid; +{ + register struct proc *p = pidhash [PIDHASH(pid)]; + + for (; p; p = p->p_hash) + if (p->p_pid == pid) + return (p); + return ((struct proc *)0); +} + +/* + * init the process queues + */ +void +pqinit() +{ + register struct proc *p; + + /* + * most procs are initially on freequeue + * nb: we place them there in their "natural" order. + */ + + freeproc = NULL; + for (p = proc+NPROC; --p > proc; freeproc = p) + p->p_nxt = freeproc; + + /* + * but proc[0] is special ... + */ + + allproc = p; + p->p_nxt = NULL; + p->p_prev = &allproc; + + zombproc = NULL; +} diff --git a/sys/kernel/kern_prot.c b/sys/kernel/kern_prot.c new file mode 100644 index 0000000..0f37df7 --- /dev/null +++ b/sys/kernel/kern_prot.c @@ -0,0 +1,155 @@ +/* + * System calls related to processes and protection. + * + * Copyright (c) 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "param.h" +#include "user.h" +#include "proc.h" +#include "systm.h" + +void +getpid() +{ + u.u_rval = u.u_procp->p_pid; +} + +void +getppid() +{ + u.u_rval = u.u_procp->p_ppid; +} + +void +getpgrp() +{ + register struct a { + int pid; + } *uap = (struct a *)u.u_arg; + register struct proc *p; + + if (uap->pid == 0) /* silly... */ + uap->pid = u.u_procp->p_pid; + p = pfind(uap->pid); + if (p == 0) { + u.u_error = ESRCH; + return; + } + u.u_rval = p->p_pgrp; +} + +void +getuid() +{ + u.u_rval = u.u_ruid; +} + +void +geteuid() +{ + u.u_rval = u.u_uid; +} + +void +getgid() +{ + u.u_rval = u.u_rgid; +} + +void +getegid() +{ + u.u_rval = u.u_groups[0]; +} + +/* + * getgroups and setgroups differ from 4.X because the VAX stores group + * entries in the user structure as shorts and has to convert them to ints. + */ +void +getgroups() +{ + register struct a { + u_int gidsetsize; + int *gidset; + } *uap = (struct a *)u.u_arg; + register gid_t *gp; + + for (gp = &u.u_groups[NGROUPS]; gp > u.u_groups; gp--) + if (gp[-1] != NOGROUP) + break; + if (uap->gidsetsize < gp - u.u_groups) { + u.u_error = EINVAL; + return; + } + uap->gidsetsize = gp - u.u_groups; + u.u_error = copyout((caddr_t)u.u_groups, (caddr_t)uap->gidset, + uap->gidsetsize * sizeof(u.u_groups[0])); + if (u.u_error) + return; + u.u_rval = uap->gidsetsize; +} + +void +setpgrp() +{ + register struct proc *p; + register struct a { + int pid; + int pgrp; + } *uap = (struct a *)u.u_arg; + + if (uap->pid == 0) /* silly... */ + uap->pid = u.u_procp->p_pid; + p = pfind(uap->pid); + if (p == 0) { + u.u_error = ESRCH; + return; + } + /* need better control mechanisms for process groups */ + if (p->p_uid != u.u_uid && u.u_uid && !inferior(p)) { + u.u_error = EPERM; + return; + } + p->p_pgrp = uap->pgrp; +} + +void +setgroups() +{ + register struct a { + u_int gidsetsize; + int *gidset; + } *uap = (struct a *)u.u_arg; + register gid_t *gp; + + if (!suser()) + return; + if (uap->gidsetsize > sizeof (u.u_groups) / sizeof (u.u_groups[0])) { + u.u_error = EINVAL; + return; + } + u.u_error = copyin((caddr_t)uap->gidset, (caddr_t)u.u_groups, + uap->gidsetsize * sizeof (u.u_groups[0])); + if (u.u_error) + return; + for (gp = &u.u_groups[uap->gidsetsize]; gp < &u.u_groups[NGROUPS]; gp++) + *gp = NOGROUP; +} + +/* + * Check if gid is a member of the group set. + */ +int +groupmember(gid) + gid_t gid; +{ + register gid_t *gp; + + for (gp = u.u_groups; gp < &u.u_groups[NGROUPS] && *gp != NOGROUP; gp++) + if (*gp == gid) + return (1); + return (0); +} diff --git a/sys/kernel/kern_prot2.c b/sys/kernel/kern_prot2.c new file mode 100644 index 0000000..fa4c66f --- /dev/null +++ b/sys/kernel/kern_prot2.c @@ -0,0 +1,114 @@ +/* + * Copyright (c) 1982, 1986, 1989, 1990, 1991, 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. + */ +#include "param.h" +#include "user.h" +#include "proc.h" +#include "systm.h" + +void +setuid() +{ + struct a { + uid_t uid; + } *uap = (struct a*) u.u_arg; + register uid_t uid; + + uid = uap->uid; + if (uid != u.u_ruid && ! suser()) + return; + /* + * Everything's okay, do it. + */ + u.u_procp->p_uid = uid; + u.u_uid = uid; + u.u_ruid = uid; + u.u_svuid = uid; + u.u_error = 0; +} + +void +seteuid() +{ + struct a { + uid_t euid; + } *uap = (struct a *)u.u_arg; + register uid_t euid; + + euid = uap->euid; + if (euid != u.u_ruid && euid != u.u_svuid && ! suser()) + return; + /* + * Everything's okay, do it. + */ + u.u_uid = euid; + u.u_error = 0; +} + +void +setgid() +{ + struct a { + gid_t gid; + } *uap = (struct a *)u.u_arg; + register gid_t gid; + + gid = uap->gid; + if (gid != u.u_rgid && ! suser()) + return; + + u.u_groups[0] = gid; /* effective gid is u_groups[0] */ + u.u_rgid = gid; + u.u_svgid = gid; + u.u_error = 0; +} + +void +setegid() +{ + struct a { + gid_t egid; + } *uap = (struct a *)u.u_arg; + register gid_t egid; + + egid = uap->egid; + if (egid != u.u_rgid && egid != u.u_svgid && ! suser()) + return; + + u.u_groups[0] = egid; + u.u_error = 0; +} diff --git a/sys/kernel/kern_resource.c b/sys/kernel/kern_resource.c new file mode 100644 index 0000000..200af6d --- /dev/null +++ b/sys/kernel/kern_resource.c @@ -0,0 +1,270 @@ +/* + * Copyright (c) 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "param.h" +#include "user.h" +#include "proc.h" +#include "systm.h" +#include "vm.h" +#include "kernel.h" + +/* + * Resource controls and accounting. + */ +void +getpriority() +{ + register struct a { + int which; + int who; + } *uap = (struct a *)u.u_arg; + register struct proc *p; + register int low = PRIO_MAX + 1; + + switch (uap->which) { + case PRIO_PROCESS: + if (uap->who == 0) + p = u.u_procp; + else + p = pfind(uap->who); + if (p == 0) + break; + low = p->p_nice; + break; + case PRIO_PGRP: + if (uap->who == 0) + uap->who = u.u_procp->p_pgrp; + for (p = allproc; p != NULL; p = p->p_nxt) { + if (p->p_pgrp == uap->who && + p->p_nice < low) + low = p->p_nice; + } + break; + case PRIO_USER: + if (uap->who == 0) + uap->who = u.u_uid; + for (p = allproc; p != NULL; p = p->p_nxt) { + if (p->p_uid == uap->who && + p->p_nice < low) + low = p->p_nice; + } + break; + default: + u.u_error = EINVAL; + return; + } + if (low == PRIO_MAX + 1) { + u.u_error = ESRCH; + return; + } + u.u_rval = low; +} + +static void +donice(p, n) + register struct proc *p; + register int n; +{ + if (u.u_uid && u.u_ruid && + u.u_uid != p->p_uid && u.u_ruid != p->p_uid) { + u.u_error = EPERM; + return; + } + if (n > PRIO_MAX) + n = PRIO_MAX; + if (n < PRIO_MIN) + n = PRIO_MIN; + if (n < p->p_nice && !suser()) { + u.u_error = EACCES; + return; + } + p->p_nice = n; +} + +void +setpriority() +{ + register struct a { + int which; + int who; + int prio; + } *uap = (struct a *)u.u_arg; + register struct proc *p; + register int found = 0; + + switch (uap->which) { + case PRIO_PROCESS: + if (uap->who == 0) + p = u.u_procp; + else + p = pfind(uap->who); + if (p == 0) + break; + donice(p, uap->prio); + found++; + break; + case PRIO_PGRP: + if (uap->who == 0) + uap->who = u.u_procp->p_pgrp; + for (p = allproc; p != NULL; p = p->p_nxt) + if (p->p_pgrp == uap->who) { + donice(p, uap->prio); + found++; + } + break; + case PRIO_USER: + if (uap->who == 0) + uap->who = u.u_uid; + for (p = allproc; p != NULL; p = p->p_nxt) + if (p->p_uid == uap->who) { + donice(p, uap->prio); + found++; + } + break; + default: + u.u_error = EINVAL; + return; + } + if (found == 0) + u.u_error = ESRCH; +} + +void +setrlimit() +{ + register struct a { + u_int which; + struct rlimit *lim; + } *uap = (struct a *)u.u_arg; + struct rlimit alim; + register struct rlimit *alimp; + + if (uap->which >= RLIM_NLIMITS) { + u.u_error = EINVAL; + return; + } + alimp = &u.u_rlimit[uap->which]; + u.u_error = copyin((caddr_t)uap->lim, (caddr_t)&alim, + sizeof (struct rlimit)); + if (u.u_error) + return; + if (uap->which == RLIMIT_CPU) { + /* + * 2.11 stores RLIMIT_CPU as ticks to keep from making + * hardclock() do long multiplication/division. + */ + if (alim.rlim_cur >= RLIM_INFINITY / hz) + alim.rlim_cur = RLIM_INFINITY; + else + alim.rlim_cur = alim.rlim_cur * hz; + if (alim.rlim_max >= RLIM_INFINITY / hz) + alim.rlim_max = RLIM_INFINITY; + else + alim.rlim_max = alim.rlim_max * hz; + } + if (alim.rlim_cur > alimp->rlim_max || alim.rlim_max > alimp->rlim_max) + if (!suser()) + return; + *alimp = alim; +} + +void +getrlimit() +{ + register struct a { + u_int which; + struct rlimit *rlp; + } *uap = (struct a *)u.u_arg; + + if (uap->which >= RLIM_NLIMITS) { + u.u_error = EINVAL; + return; + } + if (uap->which == RLIMIT_CPU) { + struct rlimit alim; + + alim = u.u_rlimit[uap->which]; + if (alim.rlim_cur != RLIM_INFINITY) + alim.rlim_cur = alim.rlim_cur / hz; + if (alim.rlim_max != RLIM_INFINITY) + alim.rlim_max = alim.rlim_max / hz; + u.u_error = copyout((caddr_t)&alim, + (caddr_t)uap->rlp,sizeof (struct rlimit)); + } + else u.u_error = copyout((caddr_t)&u.u_rlimit[uap->which], + (caddr_t)uap->rlp,sizeof (struct rlimit)); +} + +void +getrusage() +{ + register struct a { + int who; + struct rusage *rusage; + } *uap = (struct a *)u.u_arg; + register struct k_rusage *rup; + struct rusage ru; + + switch (uap->who) { + + case RUSAGE_SELF: + rup = &u.u_ru; + break; + + case RUSAGE_CHILDREN: + rup = &u.u_cru; + break; + + default: + u.u_error = EINVAL; + return; + } + rucvt(&ru,rup); + u.u_error = copyout((caddr_t)&ru, (caddr_t)uap->rusage, + sizeof (struct rusage)); +} + +/* + * Add resource usage data. + */ +void +ruadd(ru, ru2) + struct k_rusage *ru, *ru2; +{ + register long *ip, *ip2; + register int i; + + /* + * since the kernel timeval structures are single longs, + * fold them into the loop. + */ + ip = &ru->k_ru_first; + ip2 = &ru2->k_ru_first; + for (i = &ru->k_ru_last - &ru->k_ru_first; i >= 0; i--) + *ip++ += *ip2++; +} + +/* + * Convert an internal kernel rusage structure into a `real' rusage structure. + */ +void +rucvt (rup, krup) + register struct rusage *rup; + register struct k_rusage *krup; +{ + bzero((caddr_t)rup, sizeof(*rup)); + rup->ru_utime.tv_sec = krup->ru_utime / hz; + rup->ru_utime.tv_usec = (krup->ru_utime % hz) * usechz; + rup->ru_stime.tv_sec = krup->ru_stime / hz; + rup->ru_stime.tv_usec = (krup->ru_stime % hz) * usechz; + rup->ru_nswap = krup->ru_nswap; + rup->ru_inblock = krup->ru_inblock; + rup->ru_oublock = krup->ru_oublock; + rup->ru_msgsnd = krup->ru_msgsnd; + rup->ru_msgrcv = krup->ru_msgrcv; + rup->ru_nsignals = krup->ru_nsignals; + rup->ru_nvcsw = krup->ru_nvcsw; + rup->ru_nivcsw = krup->ru_nivcsw; +} diff --git a/sys/kernel/kern_sig.c b/sys/kernel/kern_sig.c new file mode 100644 index 0000000..a30e66e --- /dev/null +++ b/sys/kernel/kern_sig.c @@ -0,0 +1,664 @@ +/* + * Copyright (c) 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "param.h" +#include "systm.h" +#include "user.h" +#include "inode.h" +#include "proc.h" +#include "namei.h" +#include "signalvar.h" + +/* + * Can the current process send the signal `signum' to process `q'? + * This is complicated by the need to access the `real uid' of `q'. + * The 'real uid' is in the u area and `q' may be (but usually is not) swapped + * out. Use the routine `fill_from_u' which the sysctl() call uses. See the + * notes in kern_sysctl.c + * + * The previous checks for a process to post a signal to another process + * checked _only_ the effective userid. With the implementation of the + * 'saved id' feature and the ability of a setuid program to assume either + * uid that check was inadequate. + * + * The 'c'urrent process is allowed to send a signal to a 't'arget process if + * 1) either the real or effective user ids match OR 2) if the signal is + * SIGCONT and the target process is a descendant of the current process + */ +static int +cansignal (q, signum) + register struct proc *q; + int signum; +{ + register struct proc *curp = u.u_procp; + uid_t ruid; + + fill_from_u(q, &ruid, NULL, NULL); /* XXX */ + if (curp->p_uid == 0 || /* c effective root */ + u.u_ruid == ruid || /* c real = t real */ + curp->p_uid == ruid || /* c effective = t real */ + u.u_ruid == q->p_uid || /* c real = t effective */ + curp->p_uid == q->p_uid || /* c effective = t effective */ + (signum == SIGCONT && inferior(q))) + return(1); + return(0); +} + +/* + * 4.3 Compatibility + */ +void +sigstack() +{ + register struct a { + struct sigstack *nss; + struct sigstack *oss; + } *uap = (struct a*) u.u_arg; + struct sigstack ss; + register int error = 0; + + ss.ss_sp = u.u_sigstk.ss_base; + ss.ss_onstack = u.u_sigstk.ss_flags & SA_ONSTACK; + if(uap->oss && (error = copyout ((caddr_t) &ss, + (caddr_t) uap->oss, sizeof (ss)))) + goto out; + if (uap->nss && (error = copyin ((caddr_t) uap->nss, + (caddr_t) &ss, sizeof (ss))) == 0) { + u.u_sigstk.ss_base = ss.ss_sp; + u.u_sigstk.ss_size = 0; + u.u_sigstk.ss_flags |= (ss.ss_onstack & SA_ONSTACK); + u.u_psflags |= SAS_ALTSTACK; + } +out: + u.u_error = error; +} + +static int +killpg1 (signo, pgrp, all) + int signo, pgrp, all; +{ + register struct proc *p; + int f, error = 0; + + if (! all && pgrp == 0) { + /* + * Zero process id means send to my process group. + */ + pgrp = u.u_procp->p_pgrp; + if (pgrp == 0) + return (ESRCH); + } + for (f = 0, p = allproc; p != NULL; p = p->p_nxt) { + if ((p->p_pgrp != pgrp && !all) || p->p_ppid == 0 || + (p->p_flag&SSYS) || (all && p == u.u_procp)) + continue; + if (! cansignal (p, signo)) { + if (!all) + error = EPERM; + continue; + } + f++; + if (signo) + psignal(p, signo); + } + return (error ? error : (f == 0 ? ESRCH : 0)); +} + +void +kill() +{ + register struct a { + int pid; + int signo; + } *uap = (struct a *)u.u_arg; + register struct proc *p; + register int error = 0; + + /* + * BSD4.3 botches the comparison against NSIG - it's a good thing for + * them psignal catches the error - however, since psignal is the + * kernel's internel signal mechanism and *should be getting correct + * parameters from the rest of the kernel, psignal shouldn't *have* + * to check it's parameters for validity. If you feel differently, + * feel free to clutter up the entire inner kernel with parameter + * checks - start with postsig ... + */ + if (uap->signo < 0 || uap->signo >= NSIG) { + error = EINVAL; + goto out; + } + if (uap->pid > 0) { + /* kill single process */ + p = pfind(uap->pid); + if (p == 0) { + error = ESRCH; + goto out; + } + if (! cansignal (p, uap->signo)) + error = EPERM; + else if (uap->signo) + psignal (p, uap->signo); + goto out; + } + switch (uap->pid) { + case -1: /* broadcast signal */ + error = killpg1 (uap->signo, 0, 1); + break; + case 0: /* signal own process group */ + error = killpg1 (uap->signo, 0, 0); + break; + default: /* negative explicit process group */ + error = killpg1 (uap->signo, -uap->pid, 0); + break; + } +out: + u.u_error = error; +} + +void +killpg() +{ + register struct a { + int pgrp; + int signo; + } *uap = (struct a *)u.u_arg; + register int error = 0; + + if (uap->signo < 0 || uap->signo >= NSIG) { + error = EINVAL; + goto out; + } + error = killpg1 (uap->signo, uap->pgrp, 0); +out: + u.u_error = error; +} + +/* + * Put the argument process into the stopped + * state and notify the parent via wakeup. + * Signals are handled elsewhere. + */ +void +stop(p) + register struct proc *p; +{ + p->p_stat = SSTOP; + p->p_flag &= ~P_WAITED; + wakeup((caddr_t)p->p_pptr); +} + +/* + * Send the specified signal to + * all processes with 'pgrp' as + * process group. + */ +void +gsignal (pgrp, sig) + register int pgrp; +{ + register struct proc *p; + + if (pgrp == 0) + return; + + for (p = allproc; p != NULL; p = p->p_nxt) + if (p->p_pgrp == pgrp) + psignal(p, sig); +} + +/* + * Send the specified signal to + * the specified process. + */ +void +psignal(p, sig) + register struct proc *p; + register int sig; +{ + register int s; + sig_t action; + int prop; + long mask; + + mask = sigmask(sig); + prop = sigprop[sig]; + + /* + * If proc is traced, always give parent a chance. + */ + if (p->p_flag & P_TRACED) + action = SIG_DFL; + else { + /* + * If the signal is being ignored, + * then we forget about it immediately. + */ + if (p->p_sigignore & mask) + return; + if (p->p_sigmask & mask) + action = SIG_HOLD; + else if (p->p_sigcatch & mask) + action = SIG_CATCH; + else + action = SIG_DFL; + } + + if (p->p_nice > NZERO && action == SIG_DFL && (prop & SA_KILL) && + (p->p_flag & P_TRACED) == 0) + p->p_nice = NZERO; + + if (prop & SA_CONT) + p->p_sig &= ~stopsigmask; + + if (prop & SA_STOP) { + /* + * If sending a tty stop signal to a member of an orphaned + * process group (i.e. a child of init), discard the signal + * here if the action is default; don't stop the process + * below if sleeping, and don't clear any pending SIGCONT. + */ + if ((prop & SA_TTYSTOP) && (p->p_pptr == &proc[1]) && + action == SIG_DFL) + return; + p->p_sig &= ~contsigmask; + } + p->p_sig |= mask; + + /* + * Defer further processing for signals which are held. + */ + if (action == SIG_HOLD && ((prop & SA_CONT) == 0 || p->p_stat != SSTOP)) + return; + s = splhigh(); + switch (p->p_stat) { + + case SSLEEP: + /* + * If process is sleeping uninterruptibly we can not + * interrupt the sleep... the signal will be noticed + * when the process returns through trap() or syscall(). + */ + if ((p->p_flag & P_SINTR) == 0) + goto out; + /* + * Process is sleeping and traced... make it runnable + * so it can discover the signal in issignal() and stop + * for the parent. + */ + if (p->p_flag & P_TRACED) + goto run; + + /* + * If SIGCONT is default (or ignored) and process is + * asleep, we are finished; the process should not + * be awakened. + */ + if ((prop & SA_CONT) && action == SIG_DFL) { + p->p_sig &= ~mask; + goto out; + } + /* + * When a sleeping process receives a stop + * signal, process immediately if possible. + * All other (caught or default) signals + * cause the process to run. + */ + if (prop & SA_STOP) { + if (action != SIG_DFL) + goto run; + /* + * If a child holding parent blocked, + * stopping could cause deadlock. + */ + if (p->p_flag & SVFORK) + goto out; + p->p_sig &= ~mask; + p->p_ptracesig = sig; + if ((p->p_pptr->p_flag & P_NOCLDSTOP) == 0) + psignal(p->p_pptr, SIGCHLD); + stop(p); + goto out; + } else + goto run; + /*NOTREACHED*/ + case SSTOP: + /* + * If traced process is already stopped, + * then no further action is necessary. + */ + if (p->p_flag & P_TRACED) + goto out; + if (sig == SIGKILL) + goto run; + if (prop & SA_CONT) { + /* + * If SIGCONT is default (or ignored), we continue the + * process but don't leave the signal in p_sig, as + * it has no further action. If SIGCONT is held, we + * continue the process and leave the signal in + * p_sig. If the process catches SIGCONT, let it + * handle the signal itself. If it isn't waiting on + * an event, then it goes back to run state. + * Otherwise, process goes back to sleep state. + */ + if (action == SIG_DFL) + p->p_sig &= ~mask; + if (action == SIG_CATCH || p->p_wchan == 0) + goto run; + p->p_stat = SSLEEP; + goto out; + } + + if (prop & SA_STOP) { + /* + * Already stopped, don't need to stop again. + * (If we did the shell could get confused.) + */ + p->p_sig &= ~mask; /* take it away */ + goto out; + } + + /* + * If process is sleeping interruptibly, then simulate a + * wakeup so that when it is continued, it will be made + * runnable and can look at the signal. But don't make + * the process runnable, leave it stopped. + */ + if (p->p_wchan && (p->p_flag & P_SINTR)) + unsleep(p); + goto out; + /*NOTREACHED*/ + + default: + /* + * SRUN, SIDL, SZOMB do nothing with the signal, + * other than kicking ourselves if we are running. + * It will either never be noticed, or noticed very soon. + */ + goto out; + } + /*NOTREACHED*/ +run: + /* + * Raise priority to at least PUSER. + */ + if (p->p_pri > PUSER) + p->p_pri = PUSER; + setrun(p); +out: + splx(s); +} + +/* + * If the current process has received a signal (should be caught + * or cause termination, should interrupt current syscall) return the + * signal number. Stop signals with default action are processed + * immediately then cleared; they are not returned. This is checked + * after each entry into the kernel for a syscall of trap (though this + * can usually be done without calling issignal by checking the pending + * signals masks in CURSIG)/ The normal sequence is: + * + * while (signum = CURSIG(u.u_procp)) + * postsig(signum); + */ +int +issignal (p) + register struct proc *p; +{ + register int sig; + long mask; + int prop; + + for (;;) { + mask = p->p_sig & ~p->p_sigmask; + if (p->p_flag&SVFORK) + mask &= ~stopsigmask; + if (mask == 0) + return(0); /* No signals to send */ + sig = ffs(mask); + mask = sigmask(sig); + prop = sigprop[sig]; + /* + * We should see pending but ignored signals + * only if P_TRACED was on when they were posted. + */ + if ((mask & p->p_sigignore) && ! (p->p_flag & P_TRACED)) { + p->p_sig &= ~mask; + continue; + } + if ((p->p_flag & P_TRACED) && ! (p->p_flag & SVFORK)) { + /* + * If traced, always stop, and stay + * stopped until released by the parent. + * + * Note that we must clear the pending signal + * before we call procxmt since that routine + * might cause a fault, calling sleep and + * leading us back here again with the same signal. + * Then we would be deadlocked because the tracer + * would still be blocked on the ipc struct from + * the initial request. + */ + p->p_sig &= ~mask; + p->p_ptracesig = sig; + psignal(p->p_pptr, SIGCHLD); + do { + stop(p); + swtch(); + } while (! procxmt() && (p->p_flag & P_TRACED)); + + /* + * If parent wants us to take the signal, + * then it will leave it in p->p_ptracesig; + * otherwise we just look for signals again. + */ + sig = p->p_ptracesig; + if (sig == 0) + continue; + + /* + * Put the new signal into p_sig. If the + * signal is being masked, look for other signals. + */ + mask = sigmask(sig); + p->p_sig |= mask; + if (p->p_sigmask & mask) + continue; + + /* + * If the traced bit got turned off, go back up + * to the top to rescan signals. This ensures + * that p_sig* and u_signal are consistent. + */ + if ((p->p_flag& P_TRACED) == 0) + continue; + prop = sigprop[sig]; + } + + switch ((int)u.u_signal[sig]) { + + case (int)SIG_DFL: + /* + * Don't take default actions on system processes. + */ + if (p->p_pid <= 1) { +#ifdef DIAGNOSTIC + /* + * Are you sure you want to ignore SIGSEGV + * in init? XXX + */ + printf("Process (pid %d) got signal %d\n", + p->p_pid, sig); +#endif + break; + } + /* + * If there is a pending stop signal to process + * with default action, stop here, + * then clear the signal. However, + * if process is member of an orphaned + * process group, ignore tty stop signals. + */ + if (prop & SA_STOP) { + if (p->p_flag & P_TRACED || + (p->p_pptr == &proc[1] && + prop & SA_TTYSTOP)) + break; /* == ignore */ + p->p_ptracesig = sig; + if ((p->p_pptr->p_flag & P_NOCLDSTOP) == 0) + psignal(p->p_pptr, SIGCHLD); + stop(p); + swtch(); + break; + } else if (prop & SA_IGNORE) { + /* + * Except for SIGCONT, shouldn't get here. + * Default action is to ignore; drop it. + */ + break; /* == ignore */ + } else + return(sig); + /*NOTREACHED*/ + + case (int)SIG_IGN: + /* + * Masking above should prevent us + * ever trying to take action on a held + * or ignored signal, unless process is traced. + */ + if ((prop & SA_CONT) == 0 && + (p->p_flag & P_TRACED) == 0) + printf("issig\n"); + break; /* == ignore */ + + default: + /* + * This signal has an action, let postsig process it. + */ + return(sig); + } + p->p_sig &= ~mask; /* take the signal away! */ + } + /* NOTREACHED */ +} + +/* + * Create a core image on the file "core" + * If you are looking for protection glitches, + * there are probably a wealth of them here + * when this occurs to a suid command. + * + * It writes UPAGES (USIZE for pdp11) block of the + * user.h area followed by the entire + * data+stack segments. + */ +static int +core() +{ + register struct inode *ip; + struct nameidata nd; + register struct nameidata *ndp = &nd; + register char *np; + char *cp, name[MAXCOMLEN + 6]; + + /* + * Don't dump if not root. + */ + if (! suser()) + return(0); + if (USIZE + u.u_dsize + u.u_ssize >= u.u_rlimit[RLIMIT_CORE].rlim_cur) + return (0); + cp = u.u_comm; + np = name; + while ((*np++ = *cp++)) + ; + cp = ".core"; + np--; + while ((*np++ = *cp++)) + ; + u.u_error = 0; + NDINIT (ndp, CREATE, FOLLOW, name); + ip = namei(ndp); + if (ip == NULL) { + if (u.u_error) + return (0); + ip = maknode (0644, ndp); + if (ip==NULL) + return (0); + } + if (access(ip, IWRITE) || + (ip->i_mode&IFMT) != IFREG || + ip->i_nlink != 1) { + u.u_error = EFAULT; + goto out; + } + itrunc(ip, (u_long)0, 0); + u.u_error = rdwri (UIO_WRITE, ip, (caddr_t) &u, + USIZE, (off_t) 0, IO_UNIT, (int*) 0); + if (u.u_error) + goto out; + + u.u_error = rdwri (UIO_WRITE, ip, (caddr_t) USER_DATA_START, + u.u_dsize, (off_t) USIZE, IO_UNIT, (int*) 0); + if (u.u_error) + goto out; + + u.u_error = rdwri (UIO_WRITE, ip, (caddr_t) USER_DATA_END - u.u_ssize, + u.u_ssize, (off_t) USIZE + u.u_dsize, + IO_UNIT, (int*) 0); +out: + iput(ip); + return (u.u_error == 0); +} + +/* + * Take the action for the specified signal + * from the current set of pending signals. + */ +void +postsig(sig) + int sig; +{ + register struct proc *p = u.u_procp; + long mask = sigmask(sig), returnmask; + register sig_t action; + + p->p_sig &= ~mask; + action = u.u_signal[sig]; + + if (action != SIG_DFL) { +#ifdef DIAGNOSTIC + if (action == SIG_IGN || (p->p_sigmask & mask)) + panic("postsig action"); +#endif + u.u_error = 0; /* XXX - why? */ + /* + * Set the new mask value and also defer further + * occurences of this signal. + * + * Special case: user has done a sigsuspend. Here the + * current mask is not of interest, but rather the + * mask from before the sigsuspend is what we want restored + * after the signal processing is completed. + */ + (void) splhigh(); + if (u.u_psflags & SAS_OLDMASK) { + returnmask = u.u_oldmask; + u.u_psflags &= ~SAS_OLDMASK; + } else + returnmask = p->p_sigmask; + p->p_sigmask |= u.u_sigmask[sig] | mask; + (void) spl0(); + u.u_ru.ru_nsignals++; + sendsig(action, sig, returnmask); + return; + } + if (sigprop[sig] & SA_CORE) { + u.u_arg[0] = sig; + if (core()) + sig |= 0200; + } + exit(sig); +} diff --git a/sys/kernel/kern_sig2.c b/sys/kernel/kern_sig2.c new file mode 100644 index 0000000..a4801f8 --- /dev/null +++ b/sys/kernel/kern_sig2.c @@ -0,0 +1,371 @@ +/* + * Copyright (c) 1982, 1986, 1989, 1991, 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. + */ + +/* + * This module is a hacked down version of kern_sig.c from 4.4BSD. The + * original signal handling code is still present in 2.11's kern_sig.c. This + * was done because large modules are very hard to fit into the kernel's + * overlay structure. A smaller kern_sig2.c fits more easily into an overlaid + * kernel. + */ +#define SIGPROP /* include signal properties table */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* for coredump */ + +static void +setsigvec(signum, sa) + int signum; + register struct sigaction *sa; +{ + unsigned long bit; + register struct proc *p = u.u_procp; + + bit = sigmask(signum); + /* + * Change setting atomically. + */ + (void) splhigh(); + u.u_signal[signum] = sa->sa_handler; + u.u_sigmask[signum] = sa->sa_mask &~ sigcantmask; + if ((sa->sa_flags & SA_RESTART) == 0) + u.u_sigintr |= bit; + else + u.u_sigintr &= ~bit; + if (sa->sa_flags & SA_ONSTACK) + u.u_sigonstack |= bit; + else + u.u_sigonstack &= ~bit; + if (signum == SIGCHLD) { + if (sa->sa_flags & SA_NOCLDSTOP) + p->p_flag |= P_NOCLDSTOP; + else + p->p_flag &= ~P_NOCLDSTOP; + } + /* + * Set bit in p_sigignore for signals that are set to SIG_IGN, + * and for signals set to SIG_DFL where the default is to ignore. + * However, don't put SIGCONT in p_sigignore, + * as we have to restart the process. + */ + if (sa->sa_handler == SIG_IGN || + (sigprop[signum] & SA_IGNORE && sa->sa_handler == SIG_DFL)) { + p->p_sig &= ~bit; /* never to be seen again */ + if (signum != SIGCONT) + p->p_sigignore |= bit; /* easier in psignal */ + p->p_sigcatch &= ~bit; + } else { + p->p_sigignore &= ~bit; + if (sa->sa_handler == SIG_DFL) + p->p_sigcatch &= ~bit; + else + p->p_sigcatch |= bit; + } + (void) spl0(); +} + +void +sigaction() +{ + register struct a { + int signum; + struct sigaction *nsa; + struct sigaction *osa; + u_int sigtramp; + } *uap = (struct a *)u.u_arg; + struct sigaction vec; + register struct sigaction *sa; + register int signum; + u_long bit; + int error = 0; + + u.u_sigtramp = uap->sigtramp; /* save trampoline address */ + + signum = uap->signum; + if (signum <= 0 || signum >= NSIG) { + error = EINVAL; + goto out; + } + if (uap->nsa && (signum == SIGKILL || signum == SIGSTOP)) { + error = EINVAL; + goto out; + } + sa = &vec; + if (uap->osa) { + sa->sa_handler = u.u_signal[signum]; + sa->sa_mask = u.u_sigmask[signum]; + bit = sigmask(signum); + sa->sa_flags = 0; + if ((u.u_sigonstack & bit) != 0) + sa->sa_flags |= SA_ONSTACK; + if ((u.u_sigintr & bit) == 0) + sa->sa_flags |= SA_RESTART; + if (u.u_procp->p_flag & P_NOCLDSTOP) + sa->sa_flags |= SA_NOCLDSTOP; + error = copyout ((caddr_t) sa, (caddr_t) uap->osa, sizeof(vec)); + if (error != 0) + goto out; + } + if (uap->nsa) { + error = copyin ((caddr_t) uap->nsa, (caddr_t) sa, sizeof(vec)); + if (error != 0) + goto out; + setsigvec(signum, sa); + } +out: + u.u_error = error; +} + +/* + * Kill current process with the specified signal in an uncatchable manner; + * used when process is too confused to continue, or we are unable to + * reconstruct the process state safely. + */ +void +fatalsig(signum) + int signum; +{ + unsigned long mask; + register struct proc *p = u.u_procp; + + u.u_signal[signum] = SIG_DFL; + mask = sigmask(signum); + p->p_sigignore &= ~mask; + p->p_sigcatch &= ~mask; + p->p_sigmask &= ~mask; + psignal(p, signum); +} + +/* + * Initialize signal state for process 0; + * set to ignore signals that are ignored by default. + */ +void +siginit(p) + register struct proc *p; +{ + register int i; + + for (i = 0; i < NSIG; i++) + if (sigprop[i] & SA_IGNORE && i != SIGCONT) + p->p_sigignore |= sigmask(i); +} + +/* + * Manipulate signal mask. + * Unlike 4.4BSD we do not receive a pointer to the new and old mask areas and + * do a copyin/copyout instead of storing indirectly thru a 'retval' parameter. + * This is because we have to return both an error indication (which is 16 bits) + * _AND_ the new mask (which is 32 bits). Can't do both at the same time with + * the 2BSD syscall return mechanism. + */ +void +sigprocmask() +{ + register struct a { + int how; + sigset_t *set; + sigset_t *oset; + } *uap = (struct a *)u.u_arg; + int error = 0; + sigset_t oldmask, newmask; + register struct proc *p = u.u_procp; + + oldmask = p->p_sigmask; + if (! uap->set) /* No new mask, go possibly return old mask */ + goto out; + error = copyin ((caddr_t) uap->set, (caddr_t) &newmask, sizeof (newmask)); + if (error) + goto out; + (void) splhigh(); + + switch (uap->how) { + case SIG_BLOCK: + p->p_sigmask |= (newmask &~ sigcantmask); + break; + case SIG_UNBLOCK: + p->p_sigmask &= ~newmask; + break; + case SIG_SETMASK: + p->p_sigmask = newmask &~ sigcantmask; + break; + default: + error = EINVAL; + break; + } + (void) spl0(); +out: + if (error == 0 && uap->oset) + error = copyout ((caddr_t) &oldmask, (caddr_t) uap->oset, sizeof (oldmask)); + u.u_error = error; +} + +/* + * sigpending and sigsuspend use the standard calling sequence unlike 4.4 which + * used a nonstandard (mask instead of pointer) calling convention. + */ +void +sigpending() +{ + register struct a { + struct sigset_t *set; + } *uap = (struct a *)u.u_arg; + register int error = 0; + struct proc *p = u.u_procp; + + if (uap->set) + error = copyout((caddr_t)&p->p_sig, (caddr_t)uap->set, + sizeof (p->p_sig)); + else + error = EINVAL; + u.u_error = error; +} + +/* + * sigsuspend is supposed to always return EINTR so we ignore errors on the + * copyin by assuming a mask of 0. + */ +void +sigsuspend() +{ + register struct a { + struct sigset_t *set; + } *uap = (struct a *)u.u_arg; + sigset_t nmask = 0; + struct proc *p = u.u_procp; + int error; + + if (uap->set && (error = copyin ((caddr_t) uap->set, (caddr_t) &nmask, sizeof (nmask)))) + nmask = 0; + /* + * When returning from sigsuspend, we want the old mask to be restored + * after the signal handler has finished. Thus, we save it here and set + * a flag to indicate this. + */ + u.u_oldmask = p->p_sigmask; + u.u_psflags |= SAS_OLDMASK; + p->p_sigmask = nmask &~ sigcantmask; + while (tsleep((caddr_t)&u, PPAUSE|PCATCH, 0) == 0) + ; + /* always return EINTR rather than ERESTART */ + u.u_error = EINTR; +} + +void +sigaltstack() +{ + register struct a { + struct sigaltstack * nss; + struct sigaltstack * oss; + } *uap = (struct a *)u.u_arg; + struct sigaltstack ss; + int error = 0; + + if ((u.u_psflags & SAS_ALTSTACK) == 0) + u.u_sigstk.ss_flags |= SA_DISABLE; + if (uap->oss && (error = copyout((caddr_t)&u.u_sigstk, + (caddr_t)uap->oss, sizeof (struct sigaltstack)))) + goto out; + if (uap->nss == 0) + goto out; + error = copyin ((caddr_t) uap->nss, (caddr_t) &ss, sizeof(ss)); + if (error != 0) + goto out; + if (ss.ss_flags & SA_DISABLE) { + if (u.u_sigstk.ss_flags & SA_ONSTACK) + { + error = EINVAL; + goto out; + } + u.u_psflags &= ~SAS_ALTSTACK; + u.u_sigstk.ss_flags = ss.ss_flags; + goto out; + } + if (ss.ss_size < MINSIGSTKSZ) + { + error = ENOMEM; + goto out; + } + u.u_psflags |= SAS_ALTSTACK; + u.u_sigstk = ss; +out: + u.u_error = error; +} + +void +sigwait() +{ + register struct a { + sigset_t *set; + int *sig; + } *uap = (struct a *)u.u_arg; + sigset_t wanted, sigsavail; + register struct proc *p = u.u_procp; + int signo, error; + + if (uap->set == 0 || uap->sig == 0) { + error = EINVAL; + goto out; + } + error = copyin ((caddr_t) uap->set, (caddr_t) &wanted, sizeof (sigset_t)); + if (error) + goto out; + + wanted |= sigcantmask; + while ((sigsavail = (wanted & p->p_sig)) == 0) + tsleep ((caddr_t) &u.u_signal[0], PPAUSE | PCATCH, 0); + + if (sigsavail & sigcantmask) { + error = EINTR; + goto out; + } + + signo = ffs(sigsavail); + p->p_sig &= ~sigmask(signo); + error = copyout ((caddr_t) &signo, (caddr_t) uap->sig, sizeof (int)); +out: + u.u_error = error; +} diff --git a/sys/kernel/kern_subr.c b/sys/kernel/kern_subr.c new file mode 100644 index 0000000..a818bbb --- /dev/null +++ b/sys/kernel/kern_subr.c @@ -0,0 +1,126 @@ +/* + * Copyright (c) 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "param.h" +#include "systm.h" +#include "user.h" +#include "buf.h" +#include "uio.h" + +/* + * Move data to/from user space. + */ +int +uiomove (cp, n, uio) + caddr_t cp; + u_int n; + register struct uio *uio; +{ + register struct iovec *iov; + int error = 0; + register u_int cnt; + + while (n > 0 && uio->uio_resid) { + iov = uio->uio_iov; + cnt = iov->iov_len; + if (cnt == 0) { + uio->uio_iov++; + uio->uio_iovcnt--; + continue; + } + if (cnt > n) + cnt = n; + if (uio->uio_rw == UIO_READ) + bcopy ((caddr_t) cp, iov->iov_base, cnt); + else + bcopy (iov->iov_base, (caddr_t) cp, cnt); + iov->iov_base += cnt; + iov->iov_len -= cnt; + uio->uio_resid -= cnt; + uio->uio_offset += cnt; + cp += cnt; + n -= cnt; + } + return (error); +} + +/* + * Give next character to user as result of read. + */ +int +ureadc (c, uio) + register int c; + register struct uio *uio; +{ + register struct iovec *iov; + +again: + if (uio->uio_iovcnt == 0) + panic("ureadc"); + iov = uio->uio_iov; + if (iov->iov_len == 0 || uio->uio_resid == 0) { + uio->uio_iovcnt--; + uio->uio_iov++; + goto again; + } + *iov->iov_base = c; + + iov->iov_base++; + iov->iov_len--; + uio->uio_resid--; + uio->uio_offset++; + return (0); +} + +/* + * Get next character written in by user from uio. + */ +int +uwritec(uio) + register struct uio *uio; +{ + register struct iovec *iov; + register int c; + + if (uio->uio_resid == 0) + return (-1); +again: + if (uio->uio_iovcnt <= 0) + panic("uwritec"); + iov = uio->uio_iov; + if (iov->iov_len == 0) { + uio->uio_iov++; + if (--uio->uio_iovcnt == 0) + return (-1); + goto again; + } + c = (u_char) *iov->iov_base; + + iov->iov_base++; + iov->iov_len--; + uio->uio_resid--; + uio->uio_offset++; + return (c & 0377); +} + +/* + * Copy bytes to/from the kernel and the user. + */ +int +uiofmove(cp, n, uio, iov) + caddr_t cp; + register int n; + struct uio *uio; + struct iovec *iov; +{ + if (uio->uio_rw == UIO_READ) { + /* From kernel to user. */ + bcopy(cp, iov->iov_base, n); + } else { + /* From user to kernel. */ + bcopy(iov->iov_base, cp, n); + } + return(0); +} diff --git a/sys/kernel/kern_synch.c b/sys/kernel/kern_synch.c new file mode 100644 index 0000000..d1176f5 --- /dev/null +++ b/sys/kernel/kern_synch.c @@ -0,0 +1,538 @@ +/* + * Copyright (c) 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "param.h" +#include "user.h" +#include "proc.h" +#include "buf.h" +#include "signal.h" +#include "signalvar.h" +#include "vm.h" +#include "kernel.h" +#include "systm.h" + +#define SQSIZE 16 /* Must be power of 2 */ + +#define HASH(x) (((int)x >> 5) & (SQSIZE - 1)) +#define SCHMAG 8/10 + +struct proc *slpque[SQSIZE]; + +int runrun; /* scheduling flag */ +char curpri; /* more scheduling */ + +/* + * Recompute process priorities, once a second + */ +void +schedcpu (caddr_t arg) +{ + register struct proc *p; + register int a; + + wakeup((caddr_t)&lbolt); + for (p = allproc; p != NULL; p = p->p_nxt) { + if (p->p_time != 127) + p->p_time++; + /* + * this is where 2.11 does its real time alarms. 4.X uses + * timeouts, since it offers better than second resolution. + * Putting it here allows us to continue using use an int + * to store the number of ticks in the callout structure, + * since the kernel never has a timeout of greater than + * around 9 minutes. + */ + if (p->p_realtimer.it_value && !--p->p_realtimer.it_value) { + psignal(p, SIGALRM); + p->p_realtimer.it_value = p->p_realtimer.it_interval; + } + if (p->p_stat == SSLEEP || p->p_stat == SSTOP) + if (p->p_slptime != 127) + p->p_slptime++; + if (p->p_slptime > 1) + continue; + a = (p->p_cpu & 0377) * SCHMAG + p->p_nice; + if (a < 0) + a = 0; + if (a > 255) + a = 255; + p->p_cpu = a; + if (p->p_pri >= PUSER) + setpri(p); + } + vmmeter(); + if (runin != 0) { + runin = 0; + wakeup((caddr_t)&runin); + } + ++runrun; /* swtch at least once a second */ + timeout (schedcpu, (caddr_t) 0, hz); +} + +/* + * Recalculate the priority of a process after it has slept for a while. + */ +void +updatepri(p) + register struct proc *p; +{ + register int a = p->p_cpu & 0377; + + p->p_slptime--; /* the first time was done in schedcpu */ + while (a && --p->p_slptime) + a = (SCHMAG * a) /* + p->p_nice */; + if (a < 0) + a = 0; + if (a > 255) + a = 255; + p->p_cpu = a; + (void) setpri(p); +} + +/* + * Implement timeout for tsleep above. If process hasn't been awakened + * (p_wchan non zero) then set timeout flag and undo the sleep. If proc + * is stopped just unsleep so it will remain stopped. + */ +static void +endtsleep (p) + register struct proc *p; +{ + register int s; + + s = splhigh(); + if (p->p_wchan) { + if (p->p_stat == SSLEEP) + setrun(p); + else + unsleep(p); + p->p_flag |= P_TIMEOUT; + } + splx(s); +} + +/* + * General sleep call "borrowed" from 4.4BSD - the 'wmesg' parameter was + * removed due to data space concerns. Sleeps at most timo/hz seconds + * 0 means no timeout). NOTE: timeouts in 2.11BSD use a signed int and + * thus can be at most 32767 'ticks' or about 540 seconds in the US with + * 60hz power (~650 seconds if 50hz power is being used). + * + * If 'pri' includes the PCATCH flag signals are checked before and after + * sleeping otherwise signals are not checked. Returns 0 if a wakeup was + * done, EWOULDBLOCK if the timeout expired, ERESTART if the current system + * call should be restarted, and EINTR if the system call should be + * interrupted and EINTR returned to the user process. + */ +int +tsleep (ident, priority, timo) + caddr_t ident; + int priority; + u_int timo; +{ + register struct proc *p = u.u_procp; + register struct proc **qp; + int s; + int sig, catch = priority & PCATCH; + + s = splhigh(); + if (panicstr) { + /* + * After a panic just give interrupts a chance then just return. Don't + * run any other procs (or panic again below) in case this is the idle + * process and already asleep. The splnet should be spl0 if the network + * was being used but for now avoid network interrupts that might cause + * another panic. + */ + (void) splnet(); + noop(); + splx(s); + return(0); + } +#ifdef DIAGNOSTIC + if (ident == NULL || p->p_stat != SRUN) + panic("tsleep"); +#endif + p->p_wchan = ident; + p->p_slptime = 0; + p->p_pri = priority & PRIMASK; + qp = &slpque[HASH(ident)]; + p->p_link = *qp; + *qp = p; + if (timo) + timeout (endtsleep, (caddr_t)p, timo); + /* + * We put outselves on the sleep queue and start the timeout before calling + * CURSIG as we could stop there and a wakeup or a SIGCONT (or both) could + * occur while we were stopped. A SIGCONT would cause us to be marked SSLEEP + * without resuming us thus we must be ready for sleep when CURSIG is called. + * If the wakeup happens while we're stopped p->p_wchan will be 0 upon + * return from CURSIG. + */ + if (catch) { + p->p_flag |= P_SINTR; + sig = CURSIG(p); + if (sig) { + if (p->p_wchan) + unsleep(p); + p->p_stat = SRUN; + goto resume; + } + if (p->p_wchan == 0) { + catch = 0; + goto resume; + } + } else + sig = 0; + + p->p_stat = SSLEEP; + if (p != &proc[0]) + wakeup((caddr_t) &runin); + u.u_ru.ru_nvcsw++; + swtch(); +resume: + splx(s); + p->p_flag &= ~P_SINTR; + if (p->p_flag & P_TIMEOUT) { + p->p_flag &= ~P_TIMEOUT; + if (sig == 0) + return(EWOULDBLOCK); + } else if (timo) + untimeout (endtsleep, (caddr_t)p); + if (catch && (sig != 0 || (sig = CURSIG(p)))) { + if (u.u_sigintr & sigmask(sig)) + return(EINTR); + return(ERESTART); + } + return(0); +} + +/* + * Give up the processor till a wakeup occurs on chan, at which time the + * process enters the scheduling queue at priority pri. + * + * This routine was rewritten to use 'tsleep'. The old behaviour of sleep + * being interruptible (if 'pri>PZERO') is emulated by setting PCATCH and + * then performing the 'longjmp' if the return value of 'tsleep' is + * ERESTART. + * + * Callers of this routine must be prepared for premature return, and check + * that the reason for sleeping has gone away. + */ +void +sleep (chan, pri) + caddr_t chan; + int pri; +{ + register int priority = pri; + + if (pri > PZERO) + priority |= PCATCH; + + u.u_error = tsleep (chan, priority, 0); + /* + * sleep does not return anything. If it was a non-interruptible sleep _or_ + * a successful/normal sleep (one for which a wakeup was done) then return. + */ + if ((priority & PCATCH) == 0 || (u.u_error == 0)) + return; + /* + * XXX - compatibility uglyness. + * + * The tsleep() above will leave one of the following in u_error: + * + * 0 - a wakeup was done, this is handled above + * EWOULDBLOCK - since no timeout was passed to tsleep we will not see this + * EINTR - put into u_error for trap.c to find (interrupted syscall) + * ERESTART - system call to be restared + */ + longjmp (u.u_procp->p_addr, &u.u_qsave); + /*NOTREACHED*/ +} + +/* + * Remove a process from its wait queue + */ +void +unsleep (p) + register struct proc *p; +{ + register struct proc **hp; + register int s; + + s = splhigh(); + if (p->p_wchan) { + hp = &slpque[HASH(p->p_wchan)]; + while (*hp != p) + hp = &(*hp)->p_link; + *hp = p->p_link; + p->p_wchan = 0; + } + splx(s); +} + +/* + * Wake up all processes sleeping on chan. + */ +void +wakeup (chan) + register caddr_t chan; +{ + register struct proc *p, **q; + struct proc **qp; + int s; + + /* + * Since we are called at interrupt time, must insure normal + * kernel mapping to access proc. + */ + s = splclock(); + qp = &slpque[HASH(chan)]; +restart: + for (q = qp; (p = *q); ) { + if (p->p_stat != SSLEEP && p->p_stat != SSTOP) + panic("wakeup"); + if (p->p_wchan==chan) { + p->p_wchan = 0; + *q = p->p_link; + if (p->p_stat == SSLEEP) { + /* OPTIMIZED INLINE EXPANSION OF setrun(p) */ + if (p->p_slptime > 1) + updatepri(p); + p->p_slptime = 0; + p->p_stat = SRUN; + if (p->p_flag & SLOAD) + setrq(p); + /* + * Since curpri is a usrpri, + * p->p_pri is always better than curpri. + */ + runrun++; + if (! (p->p_flag & SLOAD)) { + if (runout != 0) { + runout = 0; + wakeup((caddr_t)&runout); + } + } + /* END INLINE EXPANSION */ + goto restart; + } + p->p_slptime = 0; + } else + q = &p->p_link; + } + splx(s); +} + +/* + * Set the process running; + * arrange for it to be swapped in if necessary. + */ +void +setrun (p) + register struct proc *p; +{ + register int s; + + s = splhigh(); + switch (p->p_stat) { + case 0: + case SWAIT: + case SRUN: + case SZOMB: + default: + panic("setrun"); + + case SSTOP: + case SSLEEP: + unsleep(p); /* e.g. when sending signals */ + break; + + case SIDL: + break; + } + if (p->p_slptime > 1) + updatepri(p); + p->p_stat = SRUN; + if (p->p_flag & SLOAD) + setrq(p); + splx(s); + if (p->p_pri < curpri) + runrun++; + if (! (p->p_flag & SLOAD)) { + if (runout != 0) { + runout = 0; + wakeup((caddr_t)&runout); + } + } +} + +/* + * Set user priority. + * The rescheduling flag (runrun) + * is set if the priority is better + * than the currently running process. + */ +int +setpri (pp) + register struct proc *pp; +{ + register int p; + + p = (pp->p_cpu & 0377)/16; + p += PUSER + pp->p_nice; + if (p > 127) + p = 127; + if (p < curpri) + runrun++; + pp->p_pri = p; + return (p); +} + +/* + * This routine is called to reschedule the CPU. If the calling process is + * not in RUN state, arrangements for it to restart must have been made + * elsewhere, usually by calling via sleep. There is a race here. A process + * may become ready after it has been examined. In this case, idle() will be + * called and will return in at most 1hz time, e.g. it's not worth putting an + * spl() in. + */ +void +swtch() +{ + register struct proc *p, *q; + register int n; + struct proc *pp, *pq; + int s; + +#ifdef UCB_METER + cnt.v_swtch++; +#endif + /* If not the idle process, resume the idle process. */ + if (u.u_procp != &proc[0]) { + if (setjmp (&u.u_rsave)) { + /* Returned from swapper to user process. */ + return; + } + /* Switch from user process to swapper. */ + longjmp (proc[0].p_addr, &u.u_qsave); + } + /* + * The first save returns nonzero when proc 0 is resumed + * by another process (above); then the second is not done + * and the process-search loop is entered. + */ + if (setjmp (&u.u_qsave)) { + /* Returned from user process. */ + goto loop; + } + /* + * The first save returns 0 when swtch is called in proc 0 + * from sched(). The second save returns 0 immediately, so + * in this case too the process-search loop is entered. + * Thus when proc 0 is awakened by being made runnable, it will + * find itself and resume itself at rsave, and return to sched(). + */ + if (setjmp (&u.u_rsave)) { + /* Swapper resumed by itself. */ + return; + } +loop: + s = splhigh(); + noproc = 0; + runrun = 0; +#ifdef DIAGNOSTIC + for (p = qs; p; p = p->p_link) + if (p->p_stat != SRUN) + panic ("swtch SRUN"); +#endif + pp = NULL; + q = NULL; + n = 128; + /* + * search for highest-priority runnable process + */ + pq = 0; + for (p = qs; p; p = p->p_link) { + if (p->p_flag & SLOAD && p->p_pri < n) { + pp = p; + pq = q; + n = p->p_pri; + } + q = p; + } + /* + * if no process is runnable, idle. + */ + p = pp; + if (p == NULL) { + idle(); + goto loop; + } + if (pq) + pq->p_link = p->p_link; + else + qs = p->p_link; + curpri = n; + splx(s); + /* + * the rsave (ssave) contents are interpreted + * in the new address space + */ + n = p->p_flag & SSWAP; + p->p_flag &= ~SSWAP; + longjmp (p->p_addr, n ? &u.u_ssave : &u.u_rsave); +} + +/* + * Put the process into the run queue. + */ +void +setrq (p) + register struct proc *p; +{ + register int s; + + s = splhigh(); +#ifdef DIAGNOSTIC + { /* see if already on the run queue */ + register struct proc *q; + + for (q = qs;q != NULL;q = q->p_link) + if (q == p) + panic("setrq"); + } +#endif + p->p_link = qs; + qs = p; + splx(s); +} + +/* + * Remove runnable job from run queue. This is done when a runnable job + * is swapped out so that it won't be selected in swtch(). It will be + * reinserted in the qs with setrq when it is swapped back in. + */ +void +remrq (p) + register struct proc *p; +{ + register struct proc *q; + register int s; + + s = splhigh(); + if (p == qs) + qs = p->p_link; + else { + for (q = qs; q; q = q->p_link) + if (q->p_link == p) { + q->p_link = p->p_link; + goto done; + } + panic("remrq"); + } +done: + splx(s); +} diff --git a/sys/kernel/kern_sysctl.c b/sys/kernel/kern_sysctl.c new file mode 100644 index 0000000..5005e6e --- /dev/null +++ b/sys/kernel/kern_sysctl.c @@ -0,0 +1,909 @@ +/* + * sysctl system call. + * + * Copyright (c) 1982, 1986, 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Mike Karels at Berkeley Software Design, 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. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +sysctlfn kern_sysctl; +sysctlfn hw_sysctl; +#ifdef DEBUG +sysctlfn debug_sysctl; +#endif +sysctlfn vm_sysctl; +sysctlfn fs_sysctl; +#ifdef INET +sysctlfn net_sysctl; +#endif +sysctlfn cpu_sysctl; + +struct sysctl_args { + int *name; + u_int namelen; + void *old; + size_t *oldlenp; + void *new; + size_t newlen; +}; + +static int sysctl_clockrate (char *where, size_t *sizep); +static int sysctl_inode (char *where, size_t *sizep); +static int sysctl_file (char *where, size_t *sizep); +static int sysctl_doproc (int *name, u_int namelen, char *where, size_t *sizep); + +void +__sysctl() +{ + register struct sysctl_args *uap = (struct sysctl_args*) u.u_arg; + int error; + u_int oldlen = 0; + sysctlfn *fn; + int name [CTL_MAXNAME]; + + if (uap->new != NULL && ! suser()) + return; + /* + * all top-level sysctl names are non-terminal + */ + if (uap->namelen > CTL_MAXNAME || uap->namelen < 2) { + u.u_error = EINVAL; + return; + } + error = copyin ((caddr_t) uap->name, (caddr_t) &name, uap->namelen * sizeof(int)); + if (error) { + u.u_error = error; + return; + } + + switch (name[0]) { + case CTL_KERN: + fn = kern_sysctl; + break; + case CTL_HW: + fn = hw_sysctl; + break; + case CTL_VM: + fn = vm_sysctl; + break; +#ifdef INET + case CTL_NET: + fn = net_sysctl; + break; +#endif +#ifdef notyet + case CTL_FS: + fn = fs_sysctl; + break; +#endif + case CTL_MACHDEP: + fn = cpu_sysctl; + break; +#ifdef DEBUG + case CTL_DEBUG: + fn = debug_sysctl; + break; +#endif + default: + u.u_error = EOPNOTSUPP; + return; + } + + if (uap->oldlenp && (error = copyin ((caddr_t) uap->oldlenp, + (caddr_t) &oldlen, sizeof(oldlen)))) { + u.u_error = error; + return; + } + if (uap->old != NULL) { + while (memlock.sl_lock) { + memlock.sl_want = 1; + sleep((caddr_t)&memlock, PRIBIO+1); + memlock.sl_locked++; + } + memlock.sl_lock = 1; + } + error = (*fn) (name + 1, uap->namelen - 1, uap->old, &oldlen, + uap->new, uap->newlen); + if (uap->old != NULL) { + memlock.sl_lock = 0; + if (memlock.sl_want) { + memlock.sl_want = 0; + wakeup((caddr_t)&memlock); + } + } + if (error) { + u.u_error = error; + return; + } + if (uap->oldlenp) { + error = copyout ((caddr_t) &oldlen, (caddr_t) uap->oldlenp, sizeof(oldlen)); + if (error) { + u.u_error = error; + return; + } + } + u.u_rval = oldlen; +} + +/* + * kernel related system variables. + */ +int +kern_sysctl(name, namelen, oldp, oldlenp, newp, newlen) + int *name; + u_int namelen; + void *oldp; + size_t *oldlenp; + void *newp; + size_t newlen; +{ + int error, level; + u_long longhostid; + char bsd[10]; + + /* all sysctl names at this level are terminal */ + if (namelen != 1 && !(name[0] == KERN_PROC || name[0] == KERN_PROF)) + return (ENOTDIR); /* overloaded */ + + switch (name[0]) { + case KERN_OSTYPE: + case KERN_OSRELEASE: + /* code is cheaper than D space */ + bsd[0]='2';bsd[1]='.';bsd[2]='1';bsd[3]='1';bsd[4]='B'; + bsd[5]='S';bsd[6]='D';bsd[7]='\0'; + return (sysctl_rdstring(oldp, oldlenp, newp, bsd)); + case KERN_OSREV: + return (sysctl_rdlong(oldp, oldlenp, newp, (long)BSD)); + case KERN_VERSION: + return (sysctl_rdstring(oldp, oldlenp, newp, version)); + case KERN_MAXINODES: + return(sysctl_rdint(oldp, oldlenp, newp, NINODE)); + case KERN_MAXPROC: + return (sysctl_rdint(oldp, oldlenp, newp, NPROC)); + case KERN_MAXFILES: + return (sysctl_rdint(oldp, oldlenp, newp, NFILE)); + case KERN_ARGMAX: + return (sysctl_rdint(oldp, oldlenp, newp, NCARGS)); + case KERN_SECURELVL: + level = securelevel; + if ((error = sysctl_int(oldp, oldlenp, newp, newlen, &level)) || + newp == NULL) + return (error); + if (level < securelevel && u.u_procp->p_pid != 1) + return (EPERM); + securelevel = level; + return (0); + case KERN_HOSTNAME: + error = sysctl_string(oldp, oldlenp, newp, newlen, + hostname, sizeof(hostname)); + if (newp && !error) + hostnamelen = newlen; + return (error); + case KERN_HOSTID: + longhostid = hostid; + error = sysctl_long(oldp, oldlenp, newp, newlen, (long*) &longhostid); + hostid = longhostid; + return (error); + case KERN_CLOCKRATE: + return (sysctl_clockrate(oldp, oldlenp)); + case KERN_BOOTTIME: + return (sysctl_rdstruct(oldp, oldlenp, newp, &boottime, + sizeof(struct timeval))); + case KERN_INODE: + return (sysctl_inode(oldp, oldlenp)); + case KERN_PROC: + return (sysctl_doproc(name + 1, namelen - 1, oldp, oldlenp)); + case KERN_FILE: + return (sysctl_file(oldp, oldlenp)); +#ifdef GPROF + case KERN_PROF: + return (sysctl_doprof(name + 1, namelen - 1, oldp, oldlenp, + newp, newlen)); +#endif + case KERN_NGROUPS: + return (sysctl_rdint(oldp, oldlenp, newp, NGROUPS)); + case KERN_JOB_CONTROL: + return (sysctl_rdint(oldp, oldlenp, newp, 1)); + case KERN_POSIX1: + case KERN_SAVED_IDS: + return (sysctl_rdint(oldp, oldlenp, newp, 0)); + default: + return (EOPNOTSUPP); + } + /* NOTREACHED */ +} + +/* + * hardware related system variables. + */ +int +hw_sysctl(name, namelen, oldp, oldlenp, newp, newlen) + int *name; + u_int namelen; + void *oldp; + size_t *oldlenp; + void *newp; + size_t newlen; +{ + /* all sysctl names at this level are terminal */ + if (namelen != 1) + return (ENOTDIR); /* overloaded */ + + switch (name[0]) { + case HW_MACHINE: + return (sysctl_rdstring(oldp, oldlenp, newp, "pic32")); + case HW_MODEL: + return (sysctl_rdstring(oldp, oldlenp, newp, "mips")); + case HW_NCPU: + return (sysctl_rdint(oldp, oldlenp, newp, 1)); /* XXX */ + case HW_BYTEORDER: + return (sysctl_rdint(oldp, oldlenp, newp, ENDIAN)); + case HW_PHYSMEM: + return (sysctl_rdlong(oldp, oldlenp, newp, physmem)); +#ifdef UCB_METER + case HW_USERMEM: + return (sysctl_rdlong(oldp, oldlenp, newp, freemem)); +#endif + case HW_PAGESIZE: + return (sysctl_rdint(oldp, oldlenp, newp, DEV_BSIZE)); + default: + return (EOPNOTSUPP); + } + /* NOTREACHED */ +} + +#ifdef DEBUG +/* + * Debugging related system variables. + */ +struct ctldebug debug0, debug1, debug2, debug3, debug4; +struct ctldebug debug5, debug6, debug7, debug8, debug9; +struct ctldebug debug10, debug11, debug12, debug13, debug14; +struct ctldebug debug15, debug16, debug17, debug18, debug19; +static struct ctldebug *debugvars[CTL_DEBUG_MAXID] = { + &debug0, &debug1, &debug2, &debug3, &debug4, + &debug5, &debug6, &debug7, &debug8, &debug9, + &debug10, &debug11, &debug12, &debug13, &debug14, + &debug15, &debug16, &debug17, &debug18, &debug19, +}; + +int +debug_sysctl(name, namelen, oldp, oldlenp, newp, newlen) + int *name; + u_int namelen; + void *oldp; + size_t *oldlenp; + void *newp; + size_t newlen; +{ + struct ctldebug *cdp; + + /* all sysctl names at this level are name and field */ + if (namelen != 2) + return (ENOTDIR); /* overloaded */ + cdp = debugvars[name[0]]; + if (cdp->debugname == 0) + return (EOPNOTSUPP); + switch (name[1]) { + case CTL_DEBUG_NAME: + return (sysctl_rdstring(oldp, oldlenp, newp, cdp->debugname)); + case CTL_DEBUG_VALUE: + return (sysctl_int(oldp, oldlenp, newp, newlen, cdp->debugvar)); + default: + return (EOPNOTSUPP); + } + /* NOTREACHED */ +} +#endif /* DEBUG */ + +/* + * Bit of a hack. 2.11 currently uses 'short avenrun[3]' and a fixed scale + * of 256. In order not to break all the applications which nlist() for + * 'avenrun' we build a local 'averunnable' structure here to return to the + * user. Eventually (after all applications which look up the load average + * the old way) have been converted we can change things. + * + * We do not call vmtotal(), that could get rather expensive, rather we rely + * on the 5 second update. + * + * The swapmap case is 2.11BSD extension. + */ +int +vm_sysctl(name, namelen, oldp, oldlenp, newp, newlen) + int *name; + u_int namelen; + void *oldp; + size_t *oldlenp; + void *newp; + size_t newlen; +{ + struct loadavg averunnable; /* loadavg in resource.h */ + + /* all sysctl names at this level are terminal */ + if (namelen != 1) + return (ENOTDIR); /* overloaded */ + + switch (name[0]) { + case VM_LOADAVG: + averunnable.fscale = 256; + averunnable.ldavg[0] = avenrun[0]; + averunnable.ldavg[1] = avenrun[1]; + averunnable.ldavg[2] = avenrun[2]; + return (sysctl_rdstruct(oldp, oldlenp, newp, &averunnable, + sizeof(averunnable))); + case VM_METER: +#ifdef notsure + vmtotal(); /* could be expensive to do this every time */ +#endif + return (sysctl_rdstruct(oldp, oldlenp, newp, &total, + sizeof(total))); + case VM_SWAPMAP: + if (oldp == NULL) { + *oldlenp = (char *)swapmap[0].m_limit - + (char *)swapmap[0].m_map; + return(0); + } + return (sysctl_rdstruct(oldp, oldlenp, newp, swapmap, + (int)swapmap[0].m_limit - (int)swapmap[0].m_map)); + default: + return (EOPNOTSUPP); + } + /* NOTREACHED */ +} + +/* + * Validate parameters and get old / set new parameters + * for an integer-valued sysctl function. + */ +int +sysctl_int(oldp, oldlenp, newp, newlen, valp) + void *oldp; + size_t *oldlenp; + void *newp; + size_t newlen; + int *valp; +{ + int error = 0; + + if (oldp && *oldlenp < sizeof(int)) + return (ENOMEM); + if (newp && newlen != sizeof(int)) + return (EINVAL); + *oldlenp = sizeof(int); + if (oldp) + error = copyout ((caddr_t) valp, (caddr_t) oldp, sizeof(int)); + if (error == 0 && newp) + error = copyin ((caddr_t) newp, (caddr_t) valp, sizeof(int)); + return (error); +} + +/* + * As above, but read-only. + */ +int +sysctl_rdint(oldp, oldlenp, newp, val) + void *oldp; + size_t *oldlenp; + void *newp; + int val; +{ + int error = 0; + + if (oldp && *oldlenp < sizeof(int)) + return (ENOMEM); + if (newp) + return (EPERM); + *oldlenp = sizeof(int); + if (oldp) + error = copyout((caddr_t)&val, oldp, sizeof(int)); + return (error); +} + +/* + * Validate parameters and get old / set new parameters + * for an long-valued sysctl function. + */ +int +sysctl_long(oldp, oldlenp, newp, newlen, valp) + void *oldp; + size_t *oldlenp; + void *newp; + size_t newlen; + long *valp; +{ + int error = 0; + + if (oldp && *oldlenp < sizeof(long)) + return (ENOMEM); + if (newp && newlen != sizeof(long)) + return (EINVAL); + *oldlenp = sizeof(long); + if (oldp) + error = copyout ((caddr_t) valp, (caddr_t) oldp, sizeof(long)); + if (error == 0 && newp) + error = copyin ((caddr_t) newp, (caddr_t) valp, sizeof(long)); + return (error); +} + +/* + * As above, but read-only. + */ +int +sysctl_rdlong(oldp, oldlenp, newp, val) + void *oldp; + size_t *oldlenp; + void *newp; + long val; +{ + int error = 0; + + if (oldp && *oldlenp < sizeof(long)) + return (ENOMEM); + if (newp) + return (EPERM); + *oldlenp = sizeof(long); + if (oldp) + error = copyout((caddr_t)&val, oldp, sizeof(long)); + return (error); +} + +/* + * Validate parameters and get old / set new parameters + * for a string-valued sysctl function. + */ +int +sysctl_string(oldp, oldlenp, newp, newlen, str, maxlen) + void *oldp; + size_t *oldlenp; + void *newp; + size_t newlen; + char *str; + int maxlen; +{ + int len, error = 0; + + len = strlen(str) + 1; + if (oldp && *oldlenp < len) + return (ENOMEM); + if (newp && newlen >= maxlen) + return (EINVAL); + if (oldp) { + *oldlenp = len; + error = copyout (str, oldp, len); + } + if (error == 0 && newp) { + error = copyin (newp, str, newlen); + str[newlen] = 0; + } + return (error); +} + +/* + * As above, but read-only. + */ +int +sysctl_rdstring(oldp, oldlenp, newp, str) + void *oldp; + size_t *oldlenp; + void *newp; + const char *str; +{ + int len, error = 0; + + len = strlen(str) + 1; + if (oldp && *oldlenp < len) + return (ENOMEM); + if (newp) + return (EPERM); + *oldlenp = len; + if (oldp) + error = copyout ((caddr_t) str, oldp, len); + return (error); +} + +/* + * Validate parameters and get old / set new parameters + * for a structure oriented sysctl function. + */ +int +sysctl_struct(oldp, oldlenp, newp, newlen, sp, len) + void *oldp; + size_t *oldlenp; + void *newp; + size_t newlen; + void *sp; + int len; +{ + int error = 0; + + if (oldp && *oldlenp < len) + return (ENOMEM); + if (newp && newlen > len) + return (EINVAL); + if (oldp) { + *oldlenp = len; + error = copyout(sp, oldp, len); + } + if (error == 0 && newp) + error = copyin(newp, sp, len); + return (error); +} + +/* + * Validate parameters and get old parameters + * for a structure oriented sysctl function. + */ +int +sysctl_rdstruct(oldp, oldlenp, newp, sp, len) + void *oldp; + size_t *oldlenp; + void *newp, *sp; + int len; +{ + int error = 0; + + if (oldp && *oldlenp < len) + return (ENOMEM); + if (newp) + return (EPERM); + *oldlenp = len; + if (oldp) + error = copyout(sp, oldp, len); + return (error); +} + +/* + * Get file structures. + */ +int +sysctl_file(where, sizep) + char *where; + size_t *sizep; +{ + int buflen, error; + register struct file *fp; + struct file *fpp; + char *start = where; + register int i; + + buflen = *sizep; + if (where == NULL) { + for (i = 0, fp = file; fp < file+NFILE; fp++) + if (fp->f_count) i++; + +#define FPTRSZ sizeof (struct file *) +#define FILESZ sizeof (struct file) + /* + * overestimate by 5 files + */ + *sizep = (i + 5) * (FILESZ + FPTRSZ); + return (0); + } + + /* + * array of extended file structures: first the address then the + * file structure. + */ + for (fp = file; fp < file+NFILE; fp++) { + if (fp->f_count == 0) + continue; + if (buflen < (FPTRSZ + FILESZ)) { + *sizep = where - start; + return (ENOMEM); + } + fpp = fp; + if ((error = copyout ((caddr_t) &fpp, (caddr_t) where, FPTRSZ)) || + (error = copyout ((caddr_t) fp, (caddr_t) (where + FPTRSZ), FILESZ))) + return (error); + buflen -= (FPTRSZ + FILESZ); + where += (FPTRSZ + FILESZ); + } + *sizep = where - start; + return (0); +} + +/* + * This one is in kern_clock.c in 4.4 but placed here for the reasons + * given earlier (back around line 367). + */ +int +sysctl_clockrate (where, sizep) + char *where; + size_t *sizep; +{ + struct clockinfo clkinfo; + + /* + * Construct clockinfo structure. + */ + clkinfo.hz = hz; + clkinfo.tick = usechz; + clkinfo.profhz = 0; + clkinfo.stathz = hz; + return(sysctl_rdstruct(where, sizep, NULL, &clkinfo, sizeof (clkinfo))); +} + +/* + * Dump inode list (via sysctl). + * Copyout address of inode followed by inode. + */ +/* ARGSUSED */ +int +sysctl_inode (where, sizep) + char *where; + size_t *sizep; +{ + register struct inode *ip; + register char *bp = where; + struct inode *ipp; + char *ewhere; + int error, numi; + + for (numi = 0, ip = inode; ip < inode+NINODE; ip++) + if (ip->i_count) numi++; + +#define IPTRSZ sizeof (struct inode *) +#define INODESZ sizeof (struct inode) + if (where == NULL) { + *sizep = (numi + 5) * (IPTRSZ + INODESZ); + return (0); + } + ewhere = where + *sizep; + + for (ip = inode; ip < inode+NINODE; ip++) { + if (ip->i_count == 0) + continue; + if (bp + IPTRSZ + INODESZ > ewhere) { + *sizep = bp - where; + return (ENOMEM); + } + ipp = ip; + if ((error = copyout ((caddr_t)&ipp, bp, IPTRSZ)) || + (error = copyout ((caddr_t)ip, bp + IPTRSZ, INODESZ))) + return (error); + bp += IPTRSZ + INODESZ; + } + + *sizep = bp - where; + return (0); +} + +/* + * Three pieces of information we need about a process are not kept in + * the proc table: real uid, controlling terminal device, and controlling + * terminal tty struct pointer. For these we must look in either the u + * area or the swap area. If the process is still in memory this is + * easy but if the process has been swapped out we have to read in the + * u area. + * + * XXX - We rely on the fact that u_ttyp, u_ttyd, and u_ruid are all within + * XXX - the first 1kb of the u area. If this ever changes the logic below + * XXX - will break (and badly). At the present time (97/9/2) the u area + * XXX - is 856 bytes long. + */ +void +fill_from_u (p, rup, ttp, tdp) + struct proc *p; + uid_t *rup; + struct tty **ttp; + dev_t *tdp; +{ + register struct buf *bp; + dev_t ttyd; + uid_t ruid; + struct tty *ttyp; + struct user *up; + + if (p->p_stat == SZOMB) { + ruid = (uid_t)-2; + ttyp = NULL; + ttyd = NODEV; + goto out; + } + if (p->p_flag & SLOAD) { + ttyd = ((struct user *)p->p_addr)->u_ttyd; + ttyp = ((struct user *)p->p_addr)->u_ttyp; + ruid = ((struct user *)p->p_addr)->u_ruid; + } else { + bp = geteblk(); + bp->b_dev = swapdev; + bp->b_blkno = (daddr_t)p->p_addr; + bp->b_bcount = DEV_BSIZE; /* XXX */ + bp->b_flags = B_READ; + + (*bdevsw[major(swapdev)].d_strategy)(bp); + biowait(bp); + + if (u.u_error) { + ttyd = NODEV; + ttyp = NULL; + ruid = (uid_t)-2; + } else { + up = (struct user*) bp->b_addr; + ruid = up->u_ruid; /* u_ruid = offset 164 */ + ttyd = up->u_ttyd; /* u_ttyd = offset 654 */ + ttyp = up->u_ttyp; /* u_ttyp = offset 652 */ + } + bp->b_flags |= B_AGE; + brelse(bp); + u.u_error = 0; /* XXX */ + } +out: + if (rup) + *rup = ruid; + if (ttp) + *ttp = ttyp; + if (tdp) + *tdp = ttyd; +} + +/* + * Fill in an eproc structure for the specified process. Slightly + * inefficient because we have to access the u area again for the + * information not kept in the proc structure itself. Can't afford + * to expand the proc struct so we take a slight speed hit here. + */ +static void +fill_eproc(p, ep) + register struct proc *p; + register struct eproc *ep; +{ + struct tty *ttyp; + + ep->e_paddr = p; + fill_from_u(p, &ep->e_ruid, &ttyp, &ep->e_tdev); + if (ttyp) + ep->e_tpgid = ttyp->t_pgrp; + else + ep->e_tpgid = 0; +} + +/* + * try over estimating by 5 procs + */ +#define KERN_PROCSLOP (5 * sizeof (struct kinfo_proc)) + +int +sysctl_doproc(name, namelen, where, sizep) + int *name; + u_int namelen; + char *where; + size_t *sizep; +{ + register struct proc *p; + register struct kinfo_proc *dp = (struct kinfo_proc *)where; + int needed = 0; + int buflen = where != NULL ? *sizep : 0; + int doingzomb; + struct eproc eproc; + int error = 0; + dev_t ttyd; + uid_t ruid; + struct tty *ttyp; + + if (namelen != 2 && !(namelen == 1 && name[0] == KERN_PROC_ALL)) + return (EINVAL); + p = (struct proc *)allproc; + doingzomb = 0; +again: + for (; p != NULL; p = p->p_nxt) { + /* + * Skip embryonic processes. + */ + if (p->p_stat == SIDL) + continue; + /* + * TODO: sysctl_oproc - make more efficient (see notes below). + * do by session. + */ + switch (name[0]) { + + case KERN_PROC_PID: + /* could do this with just a lookup */ + if (p->p_pid != (pid_t)name[1]) + continue; + break; + + case KERN_PROC_PGRP: + /* could do this by traversing pgrp */ + if (p->p_pgrp != (pid_t)name[1]) + continue; + break; + + case KERN_PROC_TTY: + fill_from_u(p, &ruid, &ttyp, &ttyd); + if (!ttyp || ttyd != (dev_t)name[1]) + continue; + break; + + case KERN_PROC_UID: + if (p->p_uid != (uid_t)name[1]) + continue; + break; + + case KERN_PROC_RUID: + fill_from_u(p, &ruid, &ttyp, &ttyd); + if (ruid != (uid_t)name[1]) + continue; + break; + + case KERN_PROC_ALL: + break; + default: + return(EINVAL); + } + if (buflen >= sizeof(struct kinfo_proc)) { + fill_eproc(p, &eproc); + error = copyout ((caddr_t) p, (caddr_t) &dp->kp_proc, + sizeof(struct proc)); + if (error) + return (error); + error = copyout ((caddr_t)&eproc, (caddr_t) &dp->kp_eproc, + sizeof(eproc)); + if (error) + return (error); + dp++; + buflen -= sizeof(struct kinfo_proc); + } + needed += sizeof(struct kinfo_proc); + } + if (doingzomb == 0) { + p = zombproc; + doingzomb++; + goto again; + } + if (where != NULL) { + *sizep = (caddr_t)dp - where; + if (needed > *sizep) + return (ENOMEM); + } else { + needed += KERN_PROCSLOP; + *sizep = needed; + } + return (0); +} diff --git a/sys/kernel/kern_time.c b/sys/kernel/kern_time.c new file mode 100644 index 0000000..452c0c4 --- /dev/null +++ b/sys/kernel/kern_time.c @@ -0,0 +1,342 @@ +/* + * Copyright (c) 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "param.h" +#include "user.h" +#include "proc.h" +#include "kernel.h" +#include "systm.h" + +static void +setthetime (tv) + register struct timeval *tv; +{ + int s; + + if (! suser()) + return; +#ifdef NOTNOW +/* + * If the system is secure, we do not allow the time to be set to an + * earlier value. The time may be slowed (using adjtime) but not set back. + * + * NOTE: Can not do this until ntpd is updated to deal with the coarse (50, 60 + * hz) clocks. Ntpd wants to adjust time system clock a few microseconds + * at a time (which gets rounded to 0 in adjtime below). If that fails + * ntpd uses settimeofday to step the time backwards which obviously + * will fail if the next 'if' is enabled - all that does is fill up the + * logfiles with "can't set time" messages and the time keeps drifting. +*/ + if (securelevel > 0 && timercmp(tv, &time, <)) { + u.u_error = EPERM; /* XXX */ + return; + } +#endif +/* WHAT DO WE DO ABOUT PENDING REAL-TIME TIMEOUTS??? */ + boottime.tv_sec += tv->tv_sec - time.tv_sec; + s = splhigh(); + time = *tv; + lbolt = time.tv_usec / usechz; + splx(s); +#ifdef notyet + /* + * if you have a time of day board, use it here + */ + resettodr(); +#endif +} + +/* + * Time of day and interval timer support. + * + * These routines provide the kernel entry points to get and set + * the time-of-day. + */ +void +gettimeofday() +{ + register struct a { + struct timeval *tp; + struct timezone *tzp; + } *uap = (struct a *)u.u_arg; + struct timeval atv; + int s; + register u_int ms; + + if (uap->tp) { + /* + * We don't resolve the milliseconds on every clock tick; it's + * easier to do it here. Long casts are out of paranoia. + */ + s = splhigh(); + atv = time; + ms = lbolt; + splx(s); + atv.tv_usec = (long)ms * usechz; + u.u_error = copyout ((caddr_t) &atv, (caddr_t) uap->tp, + sizeof(atv)); + if (u.u_error) + return; + } + if (uap->tzp) + u.u_error = copyout ((caddr_t) &tz, (caddr_t) uap->tzp, + sizeof (tz)); +} + +void +settimeofday() +{ + register struct a { + struct timeval *tv; + struct timezone *tzp; + } *uap = (struct a *)u.u_arg; + struct timeval atv; + struct timezone atz; + + if (uap->tv) { + u.u_error = copyin((caddr_t)uap->tv, (caddr_t)&atv, + sizeof (struct timeval)); + if (u.u_error) + return; + setthetime(&atv); + if (u.u_error) + return; + } + if (uap->tzp && suser()) { + u.u_error = copyin((caddr_t)uap->tzp, (caddr_t)&atz, + sizeof (atz)); + if (u.u_error == 0) + tz = atz; + } +} + +void +adjtime() +{ + register struct a { + struct timeval *delta; + struct timeval *olddelta; + } *uap = (struct a *)u.u_arg; + struct timeval atv; + register int s; + long adjust; + + if (!suser()) + return; + u.u_error = copyin((caddr_t)uap->delta, (caddr_t)&atv, + sizeof (struct timeval)); + if (u.u_error) + return; + adjust = (atv.tv_sec * hz) + (atv.tv_usec / usechz); + /* if unstoreable values, just set the clock */ + if (adjust > 0x7fff || adjust < 0x8000) { + s = splclock(); + time.tv_sec += atv.tv_sec; + lbolt += atv.tv_usec / usechz; + while (lbolt >= hz) { + lbolt -= hz; + ++time.tv_sec; + } + splx(s); + if (!uap->olddelta) + return; + atv.tv_sec = atv.tv_usec = 0; + } else { + if (!uap->olddelta) { + adjdelta = adjust; + return; + } + atv.tv_sec = adjdelta / hz; + atv.tv_usec = (adjdelta % hz) * usechz; + adjdelta = adjust; + } + u.u_error = copyout ((caddr_t) &atv, (caddr_t) uap->olddelta, + sizeof (struct timeval)); +} + +void +getitimer() +{ + register struct a { + u_int which; + struct itimerval *itv; + } *uap = (struct a *)u.u_arg; + struct itimerval aitv; + register int s; + + if (uap->which > ITIMER_PROF) { + u.u_error = EINVAL; + return; + } + aitv.it_interval.tv_usec = 0; + aitv.it_value.tv_usec = 0; + s = splclock(); + if (uap->which == ITIMER_REAL) { + register struct proc *p = u.u_procp; + + aitv.it_interval.tv_sec = p->p_realtimer.it_interval; + aitv.it_value.tv_sec = p->p_realtimer.it_value; + } else { + register struct k_itimerval *t = &u.u_timer[uap->which - 1]; + + aitv.it_interval.tv_sec = t->it_interval / hz; + aitv.it_value.tv_sec = t->it_value / hz; + } + splx(s); + u.u_error = copyout ((caddr_t)&aitv, (caddr_t)uap->itv, + sizeof (struct itimerval)); +} + +void +setitimer() +{ + register struct a { + u_int which; + struct itimerval *itv, *oitv; + } *uap = (struct a *)u.u_arg; + struct itimerval aitv; + register struct itimerval *aitvp; + int s; + + if (uap->which > ITIMER_PROF) { + u.u_error = EINVAL; + return; + } + aitvp = uap->itv; + if (uap->oitv) { + uap->itv = uap->oitv; + getitimer(); + } + if (aitvp == 0) + return; + u.u_error = copyin((caddr_t)aitvp, (caddr_t)&aitv, + sizeof (struct itimerval)); + if (u.u_error) + return; + s = splclock(); + if (uap->which == ITIMER_REAL) { + register struct proc *p = u.u_procp; + + p->p_realtimer.it_value = aitv.it_value.tv_sec; + if (aitv.it_value.tv_usec) + ++p->p_realtimer.it_value; + p->p_realtimer.it_interval = aitv.it_interval.tv_sec; + if (aitv.it_interval.tv_usec) + ++p->p_realtimer.it_interval; + } else { + register struct k_itimerval *t = &u.u_timer[uap->which - 1]; + + t->it_value = aitv.it_value.tv_sec * hz; + if (aitv.it_value.tv_usec) + t->it_value += hz; + t->it_interval = aitv.it_interval.tv_sec * hz; + if (aitv.it_interval.tv_usec) + t->it_interval += hz; + } + splx(s); +} + +/* + * Check that a proposed value to load into the .it_value or + * .it_interval part of an interval timer is acceptable, and + * fix it to have at least minimal value (i.e. if it is less + * than the resolution of the clock, round it up.) + */ +int +itimerfix(tv) + struct timeval *tv; +{ + if (tv->tv_sec < 0 || tv->tv_sec > 100000000L || + tv->tv_usec < 0 || tv->tv_usec >= 1000000L) + return (EINVAL); + if (tv->tv_sec == 0 && tv->tv_usec != 0 && tv->tv_usec < (1000/hz)) + tv->tv_usec = 1000/hz; + return (0); +} + +#ifdef NOT_CURRENTLY_IN_USE +/* + * Decrement an interval timer by a specified number + * of microseconds, which must be less than a second, + * i.e. < 1000000. If the timer expires, then reload + * it. In this case, carry over (usec - old value) to + * reducint the value reloaded into the timer so that + * the timer does not drift. This routine assumes + * that it is called in a context where the timers + * on which it is operating cannot change in value. + */ +itimerdecr(itp, usec) + register struct itimerval *itp; + int usec; +{ + + if (itp->it_value.tv_usec < usec) { + if (itp->it_value.tv_sec == 0) { + /* expired, and already in next interval */ + usec -= itp->it_value.tv_usec; + goto expire; + } + itp->it_value.tv_usec += 1000000L; + itp->it_value.tv_sec--; + } + itp->it_value.tv_usec -= usec; + usec = 0; + if (timerisset(&itp->it_value)) + return (1); + /* expired, exactly at end of interval */ +expire: + if (timerisset(&itp->it_interval)) { + itp->it_value = itp->it_interval; + itp->it_value.tv_usec -= usec; + if (itp->it_value.tv_usec < 0) { + itp->it_value.tv_usec += 1000000L; + itp->it_value.tv_sec--; + } + } else + itp->it_value.tv_usec = 0; /* sec is already 0 */ + return (0); +} +#endif /* NOT_CURRENTLY_IN_USE */ + +static void +tvfix(t1) + struct timeval *t1; +{ + if (t1->tv_usec < 0) { + t1->tv_sec--; + t1->tv_usec += 1000000L; + } + if (t1->tv_usec >= 1000000L) { + t1->tv_sec++; + t1->tv_usec -= 1000000L; + } +} + +/* + * Add and subtract routines for timevals. + * N.B.: subtract routine doesn't deal with + * results which are before the beginning, + * it just gets very confused in this case. + * Caveat emptor. + */ +void +timevaladd(t1, t2) + struct timeval *t1, *t2; +{ + t1->tv_sec += t2->tv_sec; + t1->tv_usec += t2->tv_usec; + tvfix(t1); +} + +#ifdef NOT_CURRENTLY_IN_USE +void +timevalsub(t1, t2) + struct timeval *t1, *t2; +{ + t1->tv_sec -= t2->tv_sec; + t1->tv_usec -= t2->tv_usec; + tvfix(t1); +} +#endif diff --git a/sys/kernel/subr_log.c b/sys/kernel/subr_log.c new file mode 100644 index 0000000..d7251d6 --- /dev/null +++ b/sys/kernel/subr_log.c @@ -0,0 +1,336 @@ +/* + * Copyright (c) 1982, 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +/* + * logioctl() had the wrong number of arguments. Argh! Apparently this + * driver was overlooked when 'dev' was added to ioctl entry points. + * + * logclose() returned garbage. this went unnoticed because most programs + * don't check status when doing a close. + + * Add support for multiple log devices. Minor device 0 is the traditional + * kernel logger (/dev/klog), minor device 1 is reserved for the future device + * error logging daemon. + */ + +#define NLOG 1 +int nlog = 1; + +#include "param.h" +#include "user.h" +#include "proc.h" +#include "ioctl.h" +#include "msgbuf.h" +#include "file.h" +#include "inode.h" +#include "errno.h" +#include "uio.h" +#include "map.h" +#include "systm.h" +#include "conf.h" + +const struct devspec logdevs[] = { + { 0, "klog" }, + { 0, 0 } +}; + +#define LOG_RDPRI (PZERO + 1) + +#define LOG_OPEN 0x01 +#define LOG_ASYNC 0x04 +#define LOG_RDWAIT 0x08 + +struct msgbuf msgbuf[NLOG]; + +static struct logsoftc { + int sc_state; /* see above for possibilities */ + struct proc *sc_selp; /* process waiting on select call */ + int sc_pgid; /* process/group for async I/O */ + int sc_overrun; /* full buffer count */ +} logsoftc[NLOG]; + +/*ARGSUSED*/ +int +logopen(dev, mode, unused) + dev_t dev; + int mode; +{ + register int unit = minor(dev); + + if (unit >= NLOG) + return(ENODEV); + if (logisopen(unit)) + return(EBUSY); + if (msgbuf[unit].msg_bufc == 0) /* no buffer allocated */ + return(ENOMEM); + logsoftc[unit].sc_state |= LOG_OPEN; + logsoftc[unit].sc_pgid = u.u_procp->p_pid; /* signal process only */ + logsoftc[unit].sc_overrun = 0; + return(0); +} + +/*ARGSUSED*/ +int +logclose(dev, flag, unused) + dev_t dev; + int flag; +{ + register int unit = minor(dev); + + logsoftc[unit].sc_state = 0; + return(0); +} + +/* + * This is a helper function to keep knowledge of this driver's data + * structures away from the rest of the kernel. + */ +int +logisopen(unit) + int unit; +{ + if (logsoftc[unit].sc_state & LOG_OPEN) + return(1); + return(0); +} + +/*ARGSUSED*/ +int +logread(dev, uio, flag) + dev_t dev; + struct uio *uio; + int flag; +{ + register int l; + register struct logsoftc *lp; + register struct msgbuf *mp; + int s, error = 0; + char buf [128]; + + l = minor(dev); + lp = &logsoftc[l]; + mp = &msgbuf[l]; + s = splhigh(); + while (mp->msg_bufr == mp->msg_bufx) { + if (flag & IO_NDELAY) { + splx(s); + return(EWOULDBLOCK); + } + lp->sc_state |= LOG_RDWAIT; + sleep((caddr_t)mp, LOG_RDPRI); + } + lp->sc_state &= ~LOG_RDWAIT; + + while (uio->uio_resid) { + l = mp->msg_bufx - mp->msg_bufr; + /* + * If the reader and writer are equal then we have caught up and there + * is nothing more to transfer. + */ + if (l == 0) + break; + /* + * If the write pointer is behind the reader then only consider as + * available for now the bytes from the read pointer thru the end of + * the buffer. + */ + if (l < 0) { + l = MSG_BSIZE - mp->msg_bufr; + /* + * If the reader is exactly at the end of the buffer it is + * time to wrap it around to the beginning and recalculate the + * amount of data to transfer. + */ + if (l == 0) { + mp->msg_bufr = 0; + continue; + } + } + l = MIN (l, uio->uio_resid); + l = MIN (l, sizeof buf); + bcopy (&mp->msg_bufc[mp->msg_bufr], buf, l); + error = uiomove (buf, l, uio); + if (error) + break; + mp->msg_bufr += l; + } + splx(s); + return(error); +} + +/*ARGSUSED*/ +int +logselect(dev, rw) + dev_t dev; + int rw; +{ + register int s = splhigh(); + int unit = minor(dev); + + switch (rw) { + case FREAD: + if (msgbuf[unit].msg_bufr != msgbuf[unit].msg_bufx) { + splx(s); + return(1); + } + logsoftc[unit].sc_selp = u.u_procp; + break; + } + splx(s); + return(0); +} + +void +logwakeup(unit) + int unit; +{ + register struct proc *p; + register struct logsoftc *lp; + register struct msgbuf *mp; + + if (! logisopen(unit)) + return; + lp = &logsoftc[unit]; + mp = &msgbuf[unit]; + if (lp->sc_selp) { + selwakeup(lp->sc_selp, (long) 0); + lp->sc_selp = 0; + } + if (lp->sc_state & LOG_ASYNC && (mp->msg_bufx != mp->msg_bufr)) { + if (lp->sc_pgid < 0) + gsignal(-lp->sc_pgid, SIGIO); + else if ((p = pfind(lp->sc_pgid))) + psignal(p, SIGIO); + } + if (lp->sc_state & LOG_RDWAIT) { + wakeup((caddr_t)mp); + lp->sc_state &= ~LOG_RDWAIT; + } +} + +/*ARGSUSED*/ +int +logioctl(dev, com, data, flag) + dev_t dev; + u_int com; + caddr_t data; + int flag; +{ + long l; + register int s; + int unit; + register struct logsoftc *lp; + register struct msgbuf *mp; + + unit = minor(dev); + lp = &logsoftc[unit]; + mp = &msgbuf[unit]; + + switch (com) { + case FIONREAD: + s = splhigh(); + l = mp->msg_bufx - mp->msg_bufr; + splx(s); + if (l < 0) + l += MSG_BSIZE; + *(off_t *)data = l; + break; + case FIONBIO: + break; + case FIOASYNC: + if (*(int *)data) + lp->sc_state |= LOG_ASYNC; + else + lp->sc_state &= ~LOG_ASYNC; + break; + case TIOCSPGRP: + lp->sc_pgid = *(int *)data; + break; + case TIOCGPGRP: + *(int *)data = lp->sc_pgid; + break; + default: + return(-1); + } + return(0); +} + +/* + * This is inefficient for single character writes. Alas, changing this + * to be buffered would affect the networking code's use of printf. +*/ +int +logwrt (buf, len, log) + char *buf; + int len; + int log; +{ + register struct msgbuf *mp = &msgbuf[log]; + struct logsoftc *lp = &logsoftc[log]; + register int infront; + int s, n, writer, err = 0; + + if (mp->msg_magic != MSG_MAGIC || (len > MSG_BSIZE)) + return(-1); + /* + * Hate to do this but since this can be called from anywhere in the kernel + * we have to hold off any interrupt service routines so they don't change + * things. This looks like a lot of code but it isn't really. + */ + s = splhigh(); + while (len) { +again: infront = MSG_BSIZE - mp->msg_bufx; + if (infront <= 0) { + mp->msg_bufx = 0; + infront = MSG_BSIZE - mp->msg_bufr; + } + n = mp->msg_bufr - mp->msg_bufx; + if (n < 0) /* bufr < bufx */ + writer = (MSG_BSIZE - mp->msg_bufx) + mp->msg_bufr; + else if (n == 0) + writer = MSG_BSIZE; + else { + writer = n; + infront = n; + } + if (len > writer) { + /* + * won't fit. the total number of bytes to be written is + * greater than the number available. the buffer is full. + * throw away the old data and keep the current data by resetting + * the 'writer' pointer to the current 'reader' position. Bump the + * overrun counter in case anyone wants to look at it for debugging. + */ + lp->sc_overrun++; + mp->msg_bufx = mp->msg_bufr; + goto again; + } + if (infront > len) + infront = len; + bcopy(buf, &mp->msg_bufc[mp->msg_bufx], infront); + mp->msg_bufx += infront; + len -= infront; + buf += infront; + } + splx(s); + return(err); +} + +/* + * Initialize the log driver. Called from the system startup code (machdep2.c). + * All buffers are the same (MSG_BSIZE) size. + */ +int +loginit() +{ + register struct msgbuf *mp; + + for (mp = &msgbuf[0]; mp < &msgbuf[NLOG]; mp++) { + mp->msg_magic = MSG_MAGIC; + mp->msg_bufx = mp->msg_bufr = 0; + } + return(0); +} diff --git a/sys/kernel/subr_prf.c b/sys/kernel/subr_prf.c new file mode 100644 index 0000000..7d720c0 --- /dev/null +++ b/sys/kernel/subr_prf.c @@ -0,0 +1,565 @@ +/* + * Copyright (c) 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "param.h" +#include "user.h" +#include "buf.h" +#include "msgbuf.h" +#include "conf.h" +#include "ioctl.h" +#include "tty.h" +#include "reboot.h" +#include "systm.h" +#include "syslog.h" + +#define TOCONS 0x1 +#define TOTTY 0x2 +#define TOLOG 0x4 + +/* + * In case console is off, + * panicstr contains argument to last + * call to panic. + */ +char *panicstr; + +/* + * Print a character on console or users terminal. + * If destination is console then the last MSGBUFS characters + * are saved in msgbuf for inspection later. + */ +static void +putchar (c, flags, tp) + int c, flags; + register struct tty *tp; +{ + if (flags & TOTTY) { + register int s = spltty(); + + if (tp && (tp->t_state & (TS_CARR_ON | TS_ISOPEN)) == + (TS_CARR_ON | TS_ISOPEN)) { + if (c == '\n') + (void) ttyoutput('\r', tp); + (void) ttyoutput(c, tp); + ttstart(tp); + } + splx(s); + } +#ifdef LOG_ENABLED + if ((flags & TOLOG) && c != '\0' && c != '\r' && c != 0177) { + char sym = c; + logwrt (&sym, 1, logMSG); + } +#endif + if ((flags & TOCONS) && c != '\0') + cnputc(c); +} + +static unsigned +mkhex (unsigned ch) +{ + ch &= 15; + if (ch > 9) + return ch + 'a' - 10; + return ch + '0'; +} + +/* + * Put a NUL-terminated ASCII number (base <= 16) in a buffer in reverse + * order; return an optional length and a pointer to the last character + * written in the buffer (i.e., the first character of the string). + * The buffer pointed to by `nbuf' must have length >= MAXNBUF. + */ +static char * +ksprintn (char *nbuf, unsigned long ul, int base, int width, int *lenp) +{ + char *p; + + p = nbuf; + *p = 0; + for (;;) { + *++p = mkhex (ul % base); + ul /= base; + if (--width > 0) + continue; + if (! ul) + break; + } + if (lenp) + *lenp = p - nbuf; + return (p); +} + +void puts(char *s, int flags, struct tty *ttyp) +{ + while(*s) + putchar(*(s++), flags, ttyp); +} + +/* + * Scaled down version of printf(3). + * Two additional formats: %b anf %D. + * Based on FreeBSD sources. + * Heavily rewritten by Serge Vakulenko. + * + * The format %b is supported to decode error registers. + * Its usage is: + * + * printf("reg=%b\n", regval, "*"); + * + * where is the output base expressed as a control character, e.g. + * \10 gives octal; \20 gives hex. Each arg is a sequence of characters, + * the first of which gives the bit number to be inspected (origin 1), and + * the next characters (up to a control character, i.e. a character <= 32), + * give the name of the register. Thus: + * + * kvprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n"); + * + * would produce output: + * + * reg=3 + * + * The format %D -- Hexdump, takes a pointer. Sharp flag - use `:' as + * a separator, instead of a space. For example: + * + * ("%6D", ptr) -> XX XX XX XX XX XX + * ("%#*D", len, ptr) -> XX:XX:XX:XX ... + */ + +#define PUTC(C) putchar(C,flags,ttyp) + +#define HION "\e[1m" +#define HIOFF "\e[0m" +static void +prf (fmt, ap, flags, ttyp) + register char *fmt; + register u_int *ap; + int flags; + struct tty *ttyp; +{ +#define va_arg(ap,type) *(type*) (void*) (ap++) + + char *q, nbuf [sizeof(long) * 8 + 1]; + const char *s; + int c, padding, base, lflag, ladjust, sharpflag, neg, dot, size; + int n, width, dwidth, uppercase, extrazeros, sign; + unsigned long ul; + +#ifdef KERNEL_HIGHLIGHT + puts(HION,flags,ttyp); +#endif + + if (! fmt) + fmt = "(null)\n"; + + for (;;) { + while ((c = *fmt++) != '%') { + if (! c) { +#ifdef KERNEL_HIGHLIGHT + puts(HIOFF,flags,ttyp); +#endif + return; + } + PUTC (c); + } + padding = ' '; + width = 0; extrazeros = 0; + lflag = 0; ladjust = 0; sharpflag = 0; neg = 0; + sign = 0; dot = 0; uppercase = 0; dwidth = -1; +reswitch: c = *fmt++; + switch (c) { + case '.': + dot = 1; + padding = ' '; + dwidth = 0; + goto reswitch; + + case '#': + sharpflag = 1; + goto reswitch; + + case '+': + sign = -1; + goto reswitch; + + case '-': + ladjust = 1; + goto reswitch; + + case '%': + PUTC (c); + break; + + case '*': + if (! dot) { + width = va_arg (ap, int); + if (width < 0) { + ladjust = !ladjust; + width = -width; + } + } else { + dwidth = va_arg (ap, int); + } + goto reswitch; + + case '0': + if (! dot) { + padding = '0'; + goto reswitch; + } + case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + for (n=0; ; ++fmt) { + n = n * 10 + c - '0'; + c = *fmt; + if (c < '0' || c > '9') + break; + } + if (dot) + dwidth = n; + else + width = n; + goto reswitch; + + case 'b': + ul = va_arg (ap, int); + s = va_arg (ap, const char*); + q = ksprintn (nbuf, ul, *s++, -1, 0); + while (*q) + PUTC (*q--); + + if (! ul) + break; + size = 0; + while (*s) { + n = *s++; + if ((char) (ul >> (n-1)) & 1) { + PUTC (size ? ',' : '<'); + for (; (n = *s) > ' '; ++s) + PUTC (n); + size = 1; + } else + while (*s > ' ') + ++s; + } + if (size) + PUTC ('>'); + break; + + case 'c': + if (! ladjust && width > 0) + while (width--) + PUTC (' '); + + PUTC (va_arg (ap, int)); + + if (ladjust && width > 0) + while (width--) + PUTC (' '); + break; + + case 'D': + s = va_arg (ap, const char*); + if (! width) + width = 16; + if (sharpflag) + padding = ':'; + while (width--) { + c = *s++; + PUTC (mkhex (c >> 4)); + PUTC (mkhex (c)); + if (width) + PUTC (padding); + } + break; + + case 'd': + ul = lflag ? va_arg (ap, long) : va_arg (ap, int); + if (! sign) sign = 1; + base = 10; + goto number; + + case 'l': + lflag = 1; + goto reswitch; + + case 'o': + ul = lflag ? va_arg (ap, unsigned long) : + va_arg (ap, unsigned int); + base = 8; + goto nosign; + + case 'p': + ul = (size_t) va_arg (ap, void*); + if (! ul) { + s = "(nil)"; + goto const_string; + } + base = 16; + sharpflag = (width == 0); + goto nosign; + + case 'n': + ul = lflag ? va_arg (ap, unsigned long) : + sign ? (unsigned long) va_arg (ap, int) : + va_arg (ap, unsigned int); + base = 10; + goto number; + + case 's': + s = va_arg (ap, char*); + if (! s) + s = (const char*) "(null)"; +const_string: + if (! dot) + n = strlen (s); + else + for (n=0; n 0) + while (width--) + PUTC (' '); + while (n--) + PUTC (*s++); + if (ladjust && width > 0) + while (width--) + PUTC (' '); + break; + + case 'u': + ul = lflag ? va_arg (ap, unsigned long) : + va_arg (ap, unsigned int); + base = 10; + goto nosign; + + case 'x': + case 'X': + ul = lflag ? va_arg (ap, unsigned long) : + va_arg (ap, unsigned int); + base = 16; + uppercase = (c == 'X'); + goto nosign; + case 'z': + case 'Z': + ul = lflag ? va_arg (ap, unsigned long) : + sign ? (unsigned long) va_arg (ap, int) : + va_arg (ap, unsigned int); + base = 16; + uppercase = (c == 'Z'); + goto number; + +nosign: sign = 0; +number: if (sign && ((long) ul != 0L)) { + if ((long) ul < 0L) { + neg = '-'; + ul = -(long) ul; + } else if (sign < 0) + neg = '+'; + } + if (dwidth >= (int) sizeof(nbuf)) { + extrazeros = dwidth - sizeof(nbuf) + 1; + dwidth = sizeof(nbuf) - 1; + } + s = ksprintn (nbuf, ul, base, dwidth, &size); + if (sharpflag && ul != 0) { + if (base == 8) + size++; + else if (base == 16) + size += 2; + } + if (neg) + size++; + + if (! ladjust && width && padding == ' ' && + (width -= size) > 0) + do { + PUTC (' '); + } while (--width > 0); + + if (neg) + PUTC (neg); + + if (sharpflag && ul != 0) { + if (base == 8) { + PUTC ('0'); + } else if (base == 16) { + PUTC ('0'); + PUTC (uppercase ? 'X' : 'x'); + } + } + + if (extrazeros) + do { + PUTC ('0'); + } while (--extrazeros > 0); + + if (! ladjust && width && (width -= size) > 0) + do { + PUTC (padding); + } while (--width > 0); + + for (; *s; --s) { + if (uppercase && *s>='a' && *s<='z') { + PUTC (*s + 'A' - 'a'); + } else { + PUTC (*s); + } + } + + if (ladjust && width && (width -= size) > 0) + do { + PUTC (' '); + } while (--width > 0); + break; + default: + PUTC ('%'); + if (lflag) + PUTC ('l'); + PUTC (c); + break; + } + } +#ifdef KERNEL_HIGHLIGHT + puts(HIOFF,flags,ttyp); +#endif +} + +static void +logpri (level) + int level; +{ + putchar ('<', TOLOG, (struct tty*) 0); + prf ("%u", &level, TOLOG, (struct tty*) 0); + putchar ('>', TOLOG, (struct tty*) 0); +} + +/* + * Scaled down version of C Library printf. + * Used to print diagnostic information directly on console tty. + * Since it is not interrupt driven, all system activities are + * suspended. Printf should not be used for chit-chat. + * + * One additional format: %b is supported to decode error registers. + * Usage is: + * printf("reg=%b\n", regval, "*"); + * Where is the output base expressed as a control character, + * e.g. \10 gives octal; \20 gives hex. Each arg is a sequence of + * characters, the first of which gives the bit number to be inspected + * (origin 1), and the next characters (up to a control character, i.e. + * a character <= 32), give the name of the register. Thus + * printf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n"); + * would produce output: + * reg=3 + */ +void +printf(char *fmt, ...) +{ + prf(fmt, &fmt + 1, TOCONS | TOLOG, (struct tty *)0); +} + +/* + * Microchip MPLABX C32 compiler generates calls to _printf_s() + * and other strange names. + */ +#ifdef __MPLABX__ +void _printf_s(char *fmt, ...) + __attribute__((alias ("printf"))); +void _printf_cdnopuxX(char *fmt, ...) + __attribute__((alias ("printf"))); +void _printf_cdnopsuxX(char *fmt, ...) + __attribute__((alias ("printf"))); +#endif + +/* + * Uprintf prints to the current user's terminal, + * guarantees not to sleep (so could be called by interrupt routines; + * but prints on the tty of the current process) + * and does no watermark checking - (so no verbose messages). + * NOTE: with current kernel mapping scheme, the user structure is + * not guaranteed to be accessible at interrupt level (see seg.h); + * a savemap/restormap would be needed here or in putchar if uprintf + * was to be used at interrupt time. + */ +void +uprintf (char *fmt, ...) +{ + register struct tty *tp; + + tp = u.u_ttyp; + if (tp == NULL) + return; + + if (ttycheckoutq (tp, 1)) + prf (fmt, &fmt+1, TOTTY, tp); +} + +/* + * tprintf prints on the specified terminal (console if none) + * and logs the message. It is designed for error messages from + * single-open devices, and may be called from interrupt level + * (does not sleep). + */ +void +tprintf (register struct tty *tp, char *fmt, ...) +{ + int flags = TOTTY | TOLOG; + + logpri (LOG_INFO); + if (tp == (struct tty*) NULL) + tp = &cnttys[0]; + if (ttycheckoutq (tp, 0) == 0) + flags = TOLOG; + prf (fmt, &fmt + 1, flags, tp); +#ifdef LOG_ENABLED + logwakeup (logMSG); +#endif +} + +/* + * Log writes to the log buffer, + * and guarantees not to sleep (so can be called by interrupt routines). + * If there is no process reading the log yet, it writes to the console also. + */ +/*VARARGS2*/ +void +log (int level, char *fmt, ...) +{ + register int s = splhigh(); + + logpri(level); + prf(fmt, &fmt + 1, TOLOG, (struct tty *)0); + splx(s); +#ifdef LOG_ENABLED + if (! logisopen(logMSG)) +#endif + prf(fmt, &fmt + 1, TOCONS, (struct tty *)0); +#ifdef LOG_ENABLED + logwakeup(logMSG); +#endif +} + +/* + * Panic is called on unresolvable fatal errors. + * It prints "panic: mesg", and then reboots. + * If we are called twice, then we avoid trying to + * sync the disks as this often leads to recursive panics. + */ +void +panic(s) + char *s; +{ + int bootopt = RB_HALT | RB_DUMP; + + if (panicstr) { + bootopt |= RB_NOSYNC; + } else { + panicstr = s; + } + printf ("panic: %s\n", s); + boot (rootdev, bootopt); +} diff --git a/sys/kernel/subr_rmap.c b/sys/kernel/subr_rmap.c new file mode 100644 index 0000000..01eddc5 --- /dev/null +++ b/sys/kernel/subr_rmap.c @@ -0,0 +1,230 @@ +/* + * Copyright (c) 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "param.h" +#include "systm.h" +#include "map.h" +#include "vm.h" + +/* + * Resource map handling routines. + * + * A resource map is an array of structures each of which describes a + * segment of the address space of an available resource. The segments + * are described by their base address and length, and sorted in address + * order. Each resource map has a fixed maximum number of segments + * allowed. Resources are allocated by taking part or all of one of the + * segments of the map. + * + * Returning of resources will require another segment if the returned + * resources are not adjacent in the address space to an existing segment. + * If the return of a segment would require a slot which is not available, + * then one of the resource map segments is discarded after a warning is + * printed. + * + * Returning of resources may also cause the map to collapse by coalescing + * two existing segments and the returned space into a single segment. In + * this case the resource map is made smaller by copying together to fill + * the resultant gap. + * + * N.B.: the current implementation uses a dense array and does not admit + * the value ``0'' as a legal address or size, since that is used as a + * delimiter. + */ + +/* + * Allocate 'size' units from the given map. Return the base of the + * allocated space. In a map, the addresses are increasing and the + * list is terminated by a 0 size. + * + * Algorithm is first-fit. + */ +size_t +malloc (mp, size) + struct map *mp; + register size_t size; +{ + register struct mapent *bp, *ep; + size_t addr; + + if (! size) + panic ("malloc: size = 0"); + /* + * Search for a piece of the resource map which has enough + * free space to accomodate the request. + */ + for (bp = mp->m_map; bp->m_size; ++bp) + if (bp->m_size >= size) { + /* + * Allocate from the map. If we allocated the entire + * piece, move the rest of the map to the left. + */ + addr = bp->m_addr; + bp->m_size -= size; + if (bp->m_size) + bp->m_addr += size; + else for (ep = bp;; ++ep) { + *ep = *++bp; + if (!bp->m_size) + break; + } + return(addr); + } + /* no entries big enough */ + return 0; +} + +/* + * Free the previously allocated size units at addr into the specified + * map. Sort addr into map and combine on one or both ends if possible. + */ +void +mfree (mp, size, addr) + struct map *mp; + size_t size; + register size_t addr; +{ + register struct mapent *bp, *ep; + struct mapent *start; + + if (! size) + return; + /* the address must not be 0, or the protocol has broken down. */ + if (! addr) + panic ("mfree: addr = 0"); + + /* + * locate the piece of the map which starts after the + * returned space (or the end of the map). + */ + bp = mp->m_map; + /* printf ("mfree (size=%u, addr=%u) m_map = %08x\n", size, addr, bp); */ + + while (bp->m_size && bp->m_addr <= addr) { + /*printf ("skip m_map[%d]: m_addr %u <= addr %u\n", bp - mp->m_map, bp->m_addr, addr);*/ + ++bp; + } + + /* if there is a piece on the left abutting us, combine with it. */ + ep = bp - 1; + if (bp != mp->m_map && ep->m_addr + ep->m_size >= addr) { +#ifdef DIAGNOSTIC + /* any overlap is an internal error */ + if (ep->m_addr + ep->m_size > addr) + panic("mfree overlap #1"); +#endif + /* add into piece on the left by increasing its size. */ + ep->m_size += size; + + /* + * if the combined piece abuts the piece on the right now, + * compress it in also, by shifting the remaining pieces + * of the map over. + */ + if (bp->m_size && addr + size >= bp->m_addr) { +#ifdef DIAGNOSTIC + if (addr + size > bp->m_addr) + panic("mfree overlap #2"); +#endif + ep->m_size += bp->m_size; + do { + *++ep = *++bp; + } while (bp->m_size); + } + return; + } + + /* if doesn't abut on the left, check for abutting on the right. */ + if (bp->m_size && addr + size >= bp->m_addr) { +#ifdef DIAGNOSTIC + if (addr + size > bp->m_addr) + panic("mfree overlap #3"); +#endif + bp->m_addr = addr; + bp->m_size += size; + return; + } + + /* doesn't abut. Make a new entry and check for map overflow. */ + for (start = bp; bp->m_size; ++bp); + if (++bp > mp->m_limit) + /* + * too many segments; if this happens, the correct fix + * is to make the map bigger; you can't afford to lose + * chunks of the map. If you need to implement recovery, + * use the above "for" loop to find the smallest entry + * and toss it. + */ + printf("%s: overflow, lost %u clicks at 0%o\n", + mp->m_name, size, addr); + else { + for (ep = bp - 1; ep >= start; *bp-- = *ep--); + start->m_addr = addr; + start->m_size = size; + } +} + +/* + * Allocate resources for the three segments of a process (data, stack + * and u.), attempting to minimize the cost of failure part-way through. + * Since the segments are located successively, it is best for the sizes + * to be in decreasing order; generally, data, stack, then u. will be + * best. Returns NULL on failure, address of u. on success. + */ +size_t +malloc3 (mp, d_size, s_size, u_size, a) + struct map *mp; + size_t d_size, s_size, u_size; + size_t a[3]; +{ + register struct mapent *bp, *remap; + register int next; + struct mapent *madd[3]; + size_t sizes[3]; + int found; + + sizes[0] = d_size; + sizes[1] = s_size; + sizes[2] = u_size; + /* + * note, this has to work for d_size and s_size of zero, + * since init() comes in that way. + */ + madd[0] = madd[1] = madd[2] = remap = NULL; + for (found = 0, bp = mp->m_map; bp->m_size; ++bp) + for (next = 0; next < 3; ++next) + if (!madd[next] && sizes[next] <= bp->m_size) { + madd[next] = bp; + bp->m_size -= sizes[next]; + if (!bp->m_size && !remap) + remap = bp; + if (++found == 3) + goto resolve; + } + + /* couldn't get it all; restore the old sizes, try again */ + for (next = 0; next < 3; ++next) + if (madd[next]) + madd[next]->m_size += sizes[next]; + return 0; + +resolve: + /* got it all, update the addresses. */ + for (next = 0; next < 3; ++next) { + bp = madd[next]; + a[next] = bp->m_addr; + bp->m_addr += sizes[next]; + } + + /* remove any entries of size 0; addr of 0 terminates */ + if (remap) + for (bp = remap + 1;; ++bp) + if (bp->m_size || !bp->m_addr) { + *remap++ = *bp; + if (!bp->m_addr) + break; + } + return(a[2]); +} diff --git a/sys/kernel/sys_generic.c b/sys/kernel/sys_generic.c new file mode 100644 index 0000000..d273d96 --- /dev/null +++ b/sys/kernel/sys_generic.c @@ -0,0 +1,544 @@ +/* + * Copyright (c) 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "param.h" +#include "user.h" +#include "proc.h" +#include "signalvar.h" +#include "inode.h" +#include "file.h" +#include "ioctl.h" +#include "conf.h" +#include "uio.h" +#include "kernel.h" +#include "systm.h" + +int selwait; + +static void +rwuio (uio) + register struct uio *uio; +{ + struct a { + int fdes; + }; + register struct file *fp; + register struct iovec *iov; + u_int i, count; + off_t total; + + GETF(fp, ((struct a *)u.u_arg)->fdes); + if ((fp->f_flag & (uio->uio_rw == UIO_READ ? FREAD : FWRITE)) == 0) { + u.u_error = EBADF; + return; + } + total = 0; + uio->uio_resid = 0; + for (iov = uio->uio_iov, i = 0; i < uio->uio_iovcnt; i++, iov++) + total += iov->iov_len; + + uio->uio_resid = total; + if (uio->uio_resid != total) { /* check wraparound */ + u.u_error = EINVAL; + return; + } + count = uio->uio_resid; + if (setjmp (&u.u_qsave)) { + /* + * The ONLY way we can get here is via the longjump in sleep. Thus signals + * have been checked and u_error set accordingly. If no bytes have been + * transferred then all that needs to be done now is 'return'; the system + * call will either be restarted or reported as interrupted. If bytes have + * been transferred then we need to calculate the number of bytes transferred. + */ + if (uio->uio_resid == count) + return; + u.u_error = 0; + } else + u.u_error = (*Fops[fp->f_type]->fo_rw) (fp, uio); + + u.u_rval = count - uio->uio_resid; +} + +/* + * Read system call. + */ +void +read() +{ + register struct a { + int fdes; + char *cbuf; + unsigned count; + } *uap = (struct a *)u.u_arg; + struct uio auio; + struct iovec aiov; + + aiov.iov_base = (caddr_t)uap->cbuf; + aiov.iov_len = uap->count; + auio.uio_iov = &aiov; + auio.uio_iovcnt = 1; + auio.uio_rw = UIO_READ; + rwuio (&auio); +} + +void +readv() +{ + register struct a { + int fdes; + struct iovec *iovp; + unsigned iovcnt; + } *uap = (struct a *)u.u_arg; + struct uio auio; + struct iovec aiov[16]; /* XXX */ + + if (uap->iovcnt > sizeof(aiov)/sizeof(aiov[0])) { + u.u_error = EINVAL; + return; + } + auio.uio_iov = aiov; + auio.uio_iovcnt = uap->iovcnt; + auio.uio_rw = UIO_READ; + u.u_error = copyin ((caddr_t)uap->iovp, (caddr_t)aiov, + uap->iovcnt * sizeof (struct iovec)); + if (u.u_error) + return; + rwuio (&auio); +} + +/* + * Write system call + */ +void +write() +{ + register struct a { + int fdes; + char *cbuf; + unsigned count; + } *uap = (struct a *)u.u_arg; + struct uio auio; + struct iovec aiov; + + auio.uio_iov = &aiov; + auio.uio_iovcnt = 1; + auio.uio_rw = UIO_WRITE; + aiov.iov_base = uap->cbuf; + aiov.iov_len = uap->count; + rwuio (&auio); +} + +void +writev() +{ + register struct a { + int fdes; + struct iovec *iovp; + unsigned iovcnt; + } *uap = (struct a *)u.u_arg; + struct uio auio; + struct iovec aiov[16]; /* XXX */ + + if (uap->iovcnt > sizeof(aiov)/sizeof(aiov[0])) { + u.u_error = EINVAL; + return; + } + auio.uio_iov = aiov; + auio.uio_iovcnt = uap->iovcnt; + auio.uio_rw = UIO_WRITE; + u.u_error = copyin ((caddr_t)uap->iovp, (caddr_t)aiov, + uap->iovcnt * sizeof (struct iovec)); + if (u.u_error) + return; + rwuio (&auio); +} + +/* + * Ioctl system call + */ +void +ioctl() +{ + register struct file *fp; + register struct a { + int fdes; + long cmd; + caddr_t cmarg; + } *uap; + u_int com; + + uap = (struct a *)u.u_arg; + fp = getf(uap->fdes); + if (! fp) + return; + if (! (fp->f_flag & (FREAD | FWRITE))) { + u.u_error = EBADF; + return; + } + com = (u_int) uap->cmd; + if (com & (IOC_IN | IOC_OUT)) { + /* Check user address. */ + u_int nbytes = (com & ~(IOC_INOUT | IOC_VOID)) >> 16; + if (baduaddr (uap->cmarg) || + baduaddr (uap->cmarg + nbytes - 1)) { + u.u_error = EFAULT; + return; + } + } + + switch (com) { + case FIOCLEX: + u.u_pofile[uap->fdes] |= UF_EXCLOSE; + return; + case FIONCLEX: + u.u_pofile[uap->fdes] &= ~UF_EXCLOSE; + return; + case FIONBIO: + u.u_error = fset (fp, FNONBLOCK, *(int*) uap->cmarg); + return; + case FIOASYNC: + u.u_error = fset (fp, FASYNC, *(int*) uap->cmarg); + return; + case FIOSETOWN: + u.u_error = fsetown (fp, *(int*) uap->cmarg); + return; + case FIOGETOWN: + u.u_error = fgetown (fp, (int*) uap->cmarg); + return; + } + u.u_error = (*Fops[fp->f_type]->fo_ioctl) (fp, com, uap->cmarg); +} + +int nselcoll; + +struct pselect_args { + int nd; + fd_set *in; + fd_set *ou; + fd_set *ex; + struct timespec *ts; + sigset_t *maskp; +}; + +int +selscan(ibits, obits, nfd, retval) + fd_set *ibits, *obits; + int nfd, *retval; +{ + register int i, j, flag; + fd_mask bits; + struct file *fp; + int which, n = 0; + + for (which = 0; which < 3; which++) { + switch (which) { + case 0: + flag = FREAD; break; + case 1: + flag = FWRITE; break; + case 2: + flag = 0; break; + } + for (i = 0; i < nfd; i += NFDBITS) { + bits = ibits[which].fds_bits[i/NFDBITS]; + while ((j = ffs(bits)) && i + --j < nfd) { + bits &= ~(1L << j); + fp = u.u_ofile[i + j]; + if (fp == NULL) + return(EBADF); + if ((*Fops[fp->f_type]->fo_select) (fp, flag)) { + FD_SET(i + j, &obits[which]); + n++; + } + } + } + } + *retval = n; + return(0); +} + +/* + * Select helper function common to both select() and pselect() + */ +static int +select1(uap, is_pselect) + register struct pselect_args *uap; + int is_pselect; +{ + fd_set ibits[3], obits[3]; + struct timeval atv; + sigset_t sigmsk; + unsigned int timo = 0; + register int error, ni; + int ncoll, s; + + bzero((caddr_t)ibits, sizeof(ibits)); + bzero((caddr_t)obits, sizeof(obits)); + if (uap->nd > NOFILE) + uap->nd = NOFILE; /* forgiving, if slightly wrong */ + ni = howmany(uap->nd, NFDBITS); + +#define getbits(name, x) \ + if (uap->name) { \ + error = copyin((caddr_t)uap->name, (caddr_t)&ibits[x], \ + (unsigned)(ni * sizeof(fd_mask))); \ + if (error) \ + goto done; \ + } + getbits(in, 0); + getbits(ou, 1); + getbits(ex, 2); +#undef getbits + + if (uap->maskp) { + error = copyin ((caddr_t) uap->maskp, (caddr_t) &sigmsk, sizeof(sigmsk)); + sigmsk &= ~sigcantmask; + if (error) + goto done; + } + if (uap->ts) { + error = copyin ((caddr_t) uap->ts, (caddr_t) &atv, sizeof (atv)); + if (error) + goto done; + /* + * nanoseconds ('struct timespec') on a PDP-11 are stupid since a 50 or 60 hz + * clock is all we have. Keeping the names and logic made porting easier + * though. + */ + if (is_pselect) { + struct timespec *ts = (struct timespec *)&atv; + + if (ts->tv_sec == 0 && ts->tv_nsec < 1000) + atv.tv_usec = 1; + else + atv.tv_usec = ts->tv_nsec / 1000; + } + if (itimerfix(&atv)) { + error = EINVAL; + goto done; + } + s = splhigh(); + time.tv_usec = lbolt * usechz; + timevaladd(&atv, &time); + splx(s); + } +retry: + ncoll = nselcoll; + u.u_procp->p_flag |= P_SELECT; + error = selscan(ibits, obits, uap->nd, &u.u_rval); + if (error || u.u_rval) + goto done; + s = splhigh(); + if (uap->ts) { + /* this should be timercmp(&time, &atv, >=) */ + if ((time.tv_sec > atv.tv_sec || (time.tv_sec == atv.tv_sec + && lbolt * usechz >= atv.tv_usec))) { + splx(s); + goto done; + } + timo = hzto(&atv); + if (timo == 0) + timo = 1; + } + if ((u.u_procp->p_flag & P_SELECT) == 0 || nselcoll != ncoll) { + u.u_procp->p_flag &= ~P_SELECT; + splx(s); + goto retry; + } + u.u_procp->p_flag &= ~P_SELECT; + /* + * If doing a pselect() need to set a temporary mask while in tsleep. + * Returning from pselect after catching a signal the old mask has to be + * restored. Save it here and set the appropriate flag. + */ + if (uap->maskp) { + u.u_oldmask = u.u_procp->p_sigmask; + u.u_psflags |= SAS_OLDMASK; + u.u_procp->p_sigmask = sigmsk; + } + error = tsleep ((caddr_t) &selwait, PSOCK | PCATCH, timo); + if (uap->maskp) + u.u_procp->p_sigmask = u.u_oldmask; + splx(s); + if (error == 0) + goto retry; +done: + u.u_procp->p_flag &= ~P_SELECT; + /* select is not restarted after signals... */ + if (error == ERESTART) + error = EINTR; + if (error == EWOULDBLOCK) + error = 0; +#define putbits(name, x) \ + if (uap->name && \ + (error2 = copyout ((caddr_t) &obits[x], (caddr_t) uap->name, ni*sizeof(fd_mask)))) \ + error = error2; + + if (error == 0) { + int error2; + + putbits(in, 0); + putbits(ou, 1); + putbits(ex, 2); +#undef putbits + } + return(error); +} + +/* + * Select system call. + */ +void +select() +{ + struct uap { + int nd; + fd_set *in, *ou, *ex; + struct timeval *tv; + } *uap = (struct uap *)u.u_arg; + register struct pselect_args *pselargs = (struct pselect_args *)uap; + + /* + * Fake the 6th parameter of pselect. See the comment below about the + * number of parameters! + */ + pselargs->maskp = 0; + u.u_error = select1 (pselargs, 0); +} + +/* + * pselect (posix select) + * + * N.B. There is only room for 6 arguments - see user.h - so pselect() is + * at the maximum! See user.h + */ +void +pselect() +{ + register struct pselect_args *uap = (struct pselect_args *)u.u_arg; + + u.u_error = select1(uap, 1); +} + +/*ARGSUSED*/ +int +seltrue(dev, flag) + dev_t dev; + int flag; +{ + return (1); +} + +void +selwakeup (p, coll) + register struct proc *p; + long coll; +{ + if (coll) { + nselcoll++; + wakeup ((caddr_t)&selwait); + } + if (p) { + register int s = splhigh(); + if (p->p_wchan == (caddr_t)&selwait) { + if (p->p_stat == SSLEEP) + setrun(p); + else + unsleep(p); + } else if (p->p_flag & P_SELECT) + p->p_flag &= ~P_SELECT; + splx(s); + } +} + +int +sorw(fp, uio) + register struct file *fp; + register struct uio *uio; +{ +#ifdef INET + if (uio->uio_rw == UIO_READ) + return(SORECEIVE((struct socket *)fp->f_socket, 0, uio, 0, 0)); + return(SOSEND((struct socket *)fp->f_socket, 0, uio, 0, 0)); +#else + return (EOPNOTSUPP); +#endif +} + +int +soctl(fp, com, data) + struct file *fp; + u_int com; + char *data; +{ +#ifdef INET + return (SOO_IOCTL(fp, com, data)); +#else + return (EOPNOTSUPP); +#endif +} + +int +sosel(fp, flag) + struct file *fp; + int flag; +{ +#ifdef INET + return (SOO_SELECT(fp, flag)); +#else + return (EOPNOTSUPP); +#endif +} + +int +socls(fp) + register struct file *fp; +{ + register int error = 0; + +#ifdef INET + if (fp->f_data) + error = SOCLOSE((struct socket *)fp->f_data); + fp->f_data = 0; +#else + error = EOPNOTSUPP; +#endif + return(error); +} + +/* + * this is consolidated here rather than being scattered all over the + * place. the socketops table has to be in kernel space, but since + * networking might not be defined an appropriate error has to be set + */ +const struct fileops socketops = { + sorw, soctl, sosel, socls +}; + +const struct fileops *const Fops[] = { + NULL, &inodeops, &socketops, &pipeops +}; + +/* + * Routine placed in illegal entries in the bdevsw and cdevsw tables. + */ +void +nostrategy (bp) + struct buf *bp; +{ + /* Empty. */ +} + +#ifndef INET +/* + * socket(2) and socketpair(2) if networking not available. + */ +void +nonet() +{ + u.u_error = EPROTONOSUPPORT; +} +#endif diff --git a/sys/kernel/sys_inode.c b/sys/kernel/sys_inode.c new file mode 100644 index 0000000..6fb9b6a --- /dev/null +++ b/sys/kernel/sys_inode.c @@ -0,0 +1,698 @@ +/* + * Copyright (c) 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "param.h" +#include "user.h" +#include "proc.h" +#include "signalvar.h" +#include "inode.h" +#include "buf.h" +#include "fs.h" +#include "file.h" +#include "stat.h" +#include "mount.h" +#include "conf.h" +#include "uio.h" +#include "ioctl.h" +#include "tty.h" +#include "kernel.h" +#include "systm.h" +#include "syslog.h" + +daddr_t rablock; /* block to be read ahead */ + +int +ino_rw(fp, uio) + struct file *fp; + register struct uio *uio; +{ + register struct inode *ip = (struct inode *)fp->f_data; + u_int count, error; + int ioflag; + + if ((ip->i_mode&IFMT) != IFCHR) + ILOCK(ip); + uio->uio_offset = fp->f_offset; + count = uio->uio_resid; + if (uio->uio_rw == UIO_READ) { + error = rwip(ip, uio, fp->f_flag & FNONBLOCK ? IO_NDELAY : 0); + fp->f_offset += (count - uio->uio_resid); + } else { + ioflag = 0; + if ((ip->i_mode&IFMT) == IFREG && (fp->f_flag & FAPPEND)) + ioflag |= IO_APPEND; + if (fp->f_flag & FNONBLOCK) + ioflag |= IO_NDELAY; + if (fp->f_flag & FFSYNC || + (ip->i_fs->fs_flags & MNT_SYNCHRONOUS)) + ioflag |= IO_SYNC; + error = rwip(ip, uio, ioflag); + if (ioflag & IO_APPEND) + fp->f_offset = uio->uio_offset; + else + fp->f_offset += (count - uio->uio_resid); + } + if ((ip->i_mode&IFMT) != IFCHR) + IUNLOCK(ip); + return (error); +} + +int +ino_ioctl(fp, com, data) + register struct file *fp; + register u_int com; + caddr_t data; +{ + register struct inode *ip = ((struct inode *)fp->f_data); + dev_t dev; + + switch (ip->i_mode & IFMT) { + + case IFREG: + case IFDIR: + if (com == FIONREAD) { + if (fp->f_type==DTYPE_PIPE && !(fp->f_flag&FREAD)) + *(off_t *)data = 0; + else + *(off_t *)data = ip->i_size - fp->f_offset; + return (0); + } + if (com == FIONBIO || com == FIOASYNC) /* XXX */ + return (0); /* XXX */ + /* fall into ... */ + + default: + return (ENOTTY); + + case IFCHR: + dev = ip->i_rdev; + u.u_rval = 0; + if (setjmp(&u.u_qsave)) { + /* + * The ONLY way we can get here is via the longjump in sleep. Signals have + * been checked for and u_error set accordingly. All that remains to do + * is 'return'. + */ + return(u.u_error); + } + return((*cdevsw[major(dev)].d_ioctl)(dev,com,data,fp->f_flag)); + case IFBLK: + dev = ip->i_rdev; + u.u_rval = 0; + if (setjmp(&u.u_qsave)) { + /* + * The ONLY way we can get here is via the longjump in sleep. Signals have + * been checked for and u_error set accordingly. All that remains to do + * is 'return'. + */ + return(u.u_error); + } + return((*bdevsw[major(dev)].d_ioctl)(dev,com,data,fp->f_flag)); + } +} + +int +ino_select(fp, which) + struct file *fp; + int which; +{ + register struct inode *ip = (struct inode *)fp->f_data; + register dev_t dev; + + switch (ip->i_mode & IFMT) { + + default: + return (1); /* XXX */ + + case IFCHR: + dev = ip->i_rdev; + return (*cdevsw[major(dev)].d_select)(dev, which); + } +} + +const struct fileops inodeops = { + ino_rw, ino_ioctl, ino_select, vn_closefile +}; + +int +rdwri (rw, ip, base, len, offset, ioflg, aresid) + enum uio_rw rw; + struct inode *ip; + caddr_t base; + int len; + off_t offset; + int ioflg; + register int *aresid; +{ + struct uio auio; + struct iovec aiov; + register int error; + + auio.uio_iov = &aiov; + auio.uio_iovcnt = 1; + aiov.iov_base = base; + aiov.iov_len = len; + auio.uio_rw = rw; + auio.uio_resid = len; + auio.uio_offset = offset; + error = rwip(ip, &auio, ioflg); + if (aresid) + *aresid = auio.uio_resid; + else + if (auio.uio_resid) + error = EIO; + return (error); +} + +int +rwip (ip, uio, ioflag) + register struct inode *ip; + register struct uio *uio; + int ioflag; +{ + dev_t dev = (dev_t)ip->i_rdev; + register struct buf *bp; + off_t osize; + daddr_t lbn, bn; + int n, on, type, resid; + int error = 0; + int flags; + + //if (uio->uio_offset < 0) + //return (EINVAL); + type = ip->i_mode & IFMT; + /* + * The write case below checks that i/o is done synchronously to directories + * and that i/o to append only files takes place at the end of file. + * We do not panic on non-sync directory i/o - the sync bit is forced on. + */ + if (uio->uio_rw == UIO_READ) { + if (! (ip->i_fs->fs_flags & MNT_NOATIME)) + ip->i_flag |= IACC; + } else { + switch (type) { + case IFREG: + if (ioflag & IO_APPEND) + uio->uio_offset = ip->i_size; + if (ip->i_flags & APPEND && uio->uio_offset != ip->i_size) + return(EPERM); + break; + case IFDIR: + if ((ioflag & IO_SYNC) == 0) + ioflag |= IO_SYNC; + break; + case IFLNK: + case IFBLK: + case IFCHR: + break; + default: + return (EFTYPE); + } + } + + /* + * The IO_SYNC flag is turned off here if the 'async' mount flag is on. + * Otherwise directory I/O (which is done by the kernel) would still + * synchronous (because the kernel carefully passes IO_SYNC for all directory + * I/O) even if the fs was mounted with "-o async". + * + * A side effect of this is that if the system administrator mounts a filesystem + * 'async' then the O_FSYNC flag to open() is ignored. + * + * This behaviour should probably be selectable via "sysctl fs.async.dirs" and + * "fs.async.ofsync". A project for a rainy day. + */ + if (type == IFREG || (type == IFDIR && (ip->i_fs->fs_flags & MNT_ASYNC))) + ioflag &= ~IO_SYNC; + + if (type == IFCHR) { + if (uio->uio_rw == UIO_READ) { + if (! (ip->i_fs->fs_flags & MNT_NOATIME)) + ip->i_flag |= IACC; + error = (*cdevsw[major(dev)].d_read)(dev, uio, ioflag); + } else { + ip->i_flag |= IUPD|ICHG; + error = (*cdevsw[major(dev)].d_write)(dev, uio, ioflag); + } + return (error); + } + if (uio->uio_resid == 0) + return (0); + if (uio->uio_rw == UIO_WRITE && type == IFREG && + uio->uio_offset + uio->uio_resid > + u.u_rlimit[RLIMIT_FSIZE].rlim_cur) { + psignal(u.u_procp, SIGXFSZ); + return (EFBIG); + } + if (type != IFBLK) + dev = ip->i_dev; + resid = uio->uio_resid; + osize = ip->i_size; + + flags = ioflag & IO_SYNC ? B_SYNC : 0; + + do { + lbn = lblkno(uio->uio_offset); + on = blkoff(uio->uio_offset); + n = MIN((u_int)(DEV_BSIZE - on), uio->uio_resid); + if (type != IFBLK) { + if (uio->uio_rw == UIO_READ) { + off_t diff = ip->i_size - uio->uio_offset; + if (diff <= 0) + return (0); + if (diff < n) + n = diff; + bn = bmap(ip, lbn, B_READ, flags); + } else + bn = bmap(ip,lbn,B_WRITE, + n == DEV_BSIZE ? flags : flags|B_CLRBUF); + if (u.u_error || (uio->uio_rw == UIO_WRITE && (long)bn < 0)) + return (u.u_error); + if (uio->uio_rw == UIO_WRITE && uio->uio_offset + n > ip->i_size && + (type == IFDIR || type == IFREG || type == IFLNK)) + ip->i_size = uio->uio_offset + n; + } else { + bn = lbn; + rablock = bn + 1; + } + if (uio->uio_rw == UIO_READ) { + if ((long)bn < 0) { + bp = geteblk(); + bzero (bp->b_addr, MAXBSIZE); + } else if (ip->i_lastr + 1 == lbn) + bp = breada (dev, bn, rablock); + else + bp = bread (dev, bn); + ip->i_lastr = lbn; + } else { + if (n == DEV_BSIZE) + bp = getblk (dev, bn); + else + bp = bread (dev, bn); + /* + * 4.3 didn't do this, but 2.10 did. not sure why. + * something about tape drivers don't clear buffers on end-of-tape + * any longer (clrbuf can't be called from interrupt). + */ + if (bp->b_resid == DEV_BSIZE) { + bp->b_resid = 0; + bzero (bp->b_addr, MAXBSIZE); + } + } + n = MIN(n, DEV_BSIZE - bp->b_resid); + if (bp->b_flags & B_ERROR) { + error = EIO; + brelse(bp); + break; + } + u.u_error = uiomove (bp->b_addr + on, n, uio); + if (uio->uio_rw == UIO_READ) { + if (n + on == DEV_BSIZE || uio->uio_offset == ip->i_size) { + bp->b_flags |= B_AGE; + if (ip->i_flag & IPIPE) + bp->b_flags &= ~B_DELWRI; + } + brelse(bp); + } else { + if (ioflag & IO_SYNC) + bwrite(bp); + /* + * The check below interacts _very_ badly with virtual memory tmp files + * such as those used by 'ld'. These files tend to be small and repeatedly + * rewritten in 1kb chunks. The check below causes the device driver to be + * called (and I/O initiated) constantly. Not sure what to do about this yet + * but this comment is being placed here as a reminder. + */ + else if (n + on == DEV_BSIZE && !(ip->i_flag & IPIPE)) { + bp->b_flags |= B_AGE; + bawrite(bp); + } else + bdwrite(bp); + ip->i_flag |= IUPD|ICHG; + if (u.u_ruid != 0) + ip->i_mode &= ~(ISUID|ISGID); + } + } while (u.u_error == 0 && uio->uio_resid && n != 0); + if (error == 0) /* XXX */ + error = u.u_error; /* XXX */ + if (error && (uio->uio_rw == UIO_WRITE) && (ioflag & IO_UNIT) && + (type != IFBLK)) { + itrunc(ip, osize, ioflag & IO_SYNC); + uio->uio_offset -= (resid - uio->uio_resid); + uio->uio_resid = resid; + /* + * Should back out the change to the quota here but that would be a lot + * of work for little benefit. Besides we've already made the assumption + * that the entire write would succeed and users can't turn on the IO_UNIT + * bit for their writes anyways. + */ + } +#ifdef whybother + if (! error && (ioflag & IO_SYNC)) + IUPDAT(ip, &time, &time, 1); +#endif + return (error); +} + +int +ino_stat(ip, sb) + register struct inode *ip; + register struct stat *sb; +{ + register struct icommon2 *ic2; + + ic2 = &ip->i_ic2; + + /* + * inlined ITIMES which takes advantage of the common times pointer. + */ + if (ip->i_flag & (IUPD|IACC|ICHG)) { + ip->i_flag |= IMOD; + if (ip->i_flag & IACC) + ic2->ic_atime = time.tv_sec; + if (ip->i_flag & IUPD) + ic2->ic_mtime = time.tv_sec; + if (ip->i_flag & ICHG) + ic2->ic_ctime = time.tv_sec; + ip->i_flag &= ~(IUPD|IACC|ICHG); + } + sb->st_dev = ip->i_dev; + sb->st_ino = ip->i_number; + sb->st_mode = ip->i_mode; + sb->st_nlink = ip->i_nlink; + sb->st_uid = ip->i_uid; + sb->st_gid = ip->i_gid; + sb->st_rdev = (dev_t)ip->i_rdev; + sb->st_size = ip->i_size; + sb->st_atime = ic2->ic_atime; + sb->st_mtime = ic2->ic_mtime; + sb->st_ctime = ic2->ic_ctime; + sb->st_blksize = MAXBSIZE; + /* + * blocks are too tough to do; it's not worth the effort. + */ + sb->st_blocks = btod (ip->i_size); + sb->st_flags = ip->i_flags; + return (0); +} + +/* + * This routine, like its counterpart openi(), calls the device driver for + * special (IBLK, ICHR) files. Normal files simply return early (the default + * case in the switch statement). Pipes and sockets do NOT come here because + * they have their own close routines. +*/ +int +closei (ip, flag) + register struct inode *ip; + int flag; +{ + register struct mount *mp; + register struct file *fp; + int mode, error; + dev_t dev; + int (*cfunc)(); + + mode = ip->i_mode & IFMT; + dev = ip->i_rdev; + + switch (mode) { + case IFCHR: + cfunc = cdevsw[major(dev)].d_close; + break; + case IFBLK: + /* + * We don't want to really close the device if it is mounted + */ + /* MOUNT TABLE SHOULD HOLD INODE */ + for (mp = mount; mp < &mount[NMOUNT]; mp++) + if (mp->m_inodp != NULL && mp->m_dev == dev) + return(0); + cfunc = bdevsw[major(dev)].d_close; + break; + default: + return(0); + } + /* + * Check that another inode for the same device isn't active. + * This is because the same device can be referenced by two + * different inodes. + */ + for (fp = file; fp < file+NFILE; fp++) { + if (fp->f_type != DTYPE_INODE) + continue; + if (fp->f_count && (ip = (struct inode *)fp->f_data) && + ip->i_rdev == dev && (ip->i_mode&IFMT) == mode) + return(0); + } + if (mode == IFBLK) { + /* + * On last close of a block device (that isn't mounted) + * we must invalidate any in core blocks, so that + * we can, for instance, change floppy disks. + */ + bflush(dev); + binval(dev); + } + /* + * NOTE: none of the device drivers appear to either set u_error OR return + * anything meaningful from their close routines. It's a good thing + * programs don't bother checking the error status on close() calls. + * Apparently the only time "errno" is meaningful after a "close" is + * when the process is interrupted. + */ + if (setjmp (&u.u_qsave)) { + /* + * If device close routine is interrupted, + * must return so closef can clean up. + */ + if ((error = u.u_error) == 0) + error = EINTR; + } else + error = (*cfunc)(dev, flag, mode); + return (error); +} + +/* + * Place an advisory lock on an inode. + * NOTE: callers of this routine must be prepared to deal with the pseudo + * error return ERESTART. + */ +int +ino_lock(fp, cmd) + register struct file *fp; + int cmd; +{ + register int priority = PLOCK; + register struct inode *ip = (struct inode *)fp->f_data; + int error; + + if ((cmd & LOCK_EX) == 0) + priority += 4; +/* + * If there's a exclusive lock currently applied to the file then we've + * gotta wait for the lock with everyone else. + * + * NOTE: We can NOT sleep on i_exlockc because it is on an odd byte boundary + * and the low (oddness) bit is reserved for networking/supervisor mode + * sleep channels. Thus we always sleep on i_shlockc and simply check + * the proper bits to see if the lock we want is granted. This may + * mean an extra wakeup/sleep event is done once in a while but + * everything will work correctly. +*/ +again: + while (ip->i_flag & IEXLOCK) { + /* + * If we're holding an exclusive + * lock, then release it. + */ + if (fp->f_flag & FEXLOCK) { + ino_unlock(fp, FEXLOCK); + continue; + } + if (cmd & LOCK_NB) + return (EWOULDBLOCK); + ip->i_flag |= ILWAIT; + error = tsleep((caddr_t)&ip->i_shlockc, priority | PCATCH, 0); + if (error) + return(error); + } + if ((cmd & LOCK_EX) && (ip->i_flag & ISHLOCK)) { + /* + * Must wait for any shared locks to finish + * before we try to apply a exclusive lock. + * + * If we're holding a shared + * lock, then release it. + */ + if (fp->f_flag & FSHLOCK) { + ino_unlock(fp, FSHLOCK); + goto again; + } + if (cmd & LOCK_NB) + return (EWOULDBLOCK); + ip->i_flag |= ILWAIT; + error = tsleep((caddr_t)&ip->i_shlockc, PLOCK | PCATCH, 0); + if (error) + return(error); + goto again; + } + if (cmd & LOCK_EX) { + cmd &= ~LOCK_SH; + ip->i_exlockc++; + ip->i_flag |= IEXLOCK; + fp->f_flag |= FEXLOCK; + } + if ((cmd & LOCK_SH) && (fp->f_flag & FSHLOCK) == 0) { + ip->i_shlockc++; + ip->i_flag |= ISHLOCK; + fp->f_flag |= FSHLOCK; + } + return (0); +} + +/* + * Unlock a file. + */ +void +ino_unlock(fp, kind) + register struct file *fp; + int kind; +{ + register struct inode *ip = (struct inode *)fp->f_data; + register int flags; + + kind &= fp->f_flag; + if (ip == NULL || kind == 0) + return; + flags = ip->i_flag; + if (kind & FSHLOCK) { + if (--ip->i_shlockc == 0) { + ip->i_flag &= ~ISHLOCK; + if (flags & ILWAIT) + wakeup((caddr_t)&ip->i_shlockc); + } + fp->f_flag &= ~FSHLOCK; + } + if (kind & FEXLOCK) { + if (--ip->i_exlockc == 0) { + ip->i_flag &= ~(IEXLOCK|ILWAIT); + if (flags & ILWAIT) + wakeup((caddr_t)&ip->i_shlockc); + } + fp->f_flag &= ~FEXLOCK; + } +} + +/* + * Openi called to allow handler of special files to initialize and + * validate before actual IO. + */ +int +openi (ip, mode) + register struct inode *ip; +{ + register dev_t dev = ip->i_rdev; + register int maj = major(dev); + dev_t bdev; + int error; + + switch (ip->i_mode&IFMT) { + + case IFCHR: + if (ip->i_fs->fs_flags & MNT_NODEV) + return(ENXIO); + if ((u_int)maj >= nchrdev) + return (ENXIO); + if (mode & FWRITE) { + /* + * When running in very secure mode, do not allow + * opens for writing of any disk character devices. + */ + if (securelevel >= 2 && isdisk(dev, IFCHR)) + return(EPERM); + /* + * When running in secure mode, do not allow opens + * for writing of /dev/mem, /dev/kmem, or character + * devices whose corresponding block devices are + * currently mounted. + */ + if (securelevel >= 1) { + if ((bdev = chrtoblk(dev)) != NODEV && + (error = ufs_mountedon(bdev))) + return(error); + if (iskmemdev(dev)) + return(EPERM); + } + } + return ((*cdevsw[maj].d_open)(dev, mode, S_IFCHR)); + + case IFBLK: + if (ip->i_fs->fs_flags & MNT_NODEV) + return(ENXIO); + if ((u_int)maj >= nblkdev) + return (ENXIO); + /* + * When running in very secure mode, do not allow + * opens for writing of any disk block devices. + */ + if (securelevel >= 2 && (mode & FWRITE) && isdisk(dev, IFBLK)) + return(EPERM); + /* + * Do not allow opens of block devices that are + * currently mounted. + * + * 2.11BSD must relax this restriction to allow 'fsck' to + * open the root filesystem (which is always mounted) during + * a reboot. Once in secure or very secure mode the + * above restriction is fully effective. On the otherhand + * fsck should 1) use the raw device, 2) not do sync calls... + */ + if (securelevel > 0 && (error = ufs_mountedon(dev))) + return(error); + return ((*bdevsw[maj].d_open)(dev, mode, S_IFBLK)); + } + return (0); +} + +static void +forceclose(dev) + register dev_t dev; +{ + register struct file *fp; + register struct inode *ip; + + for (fp = file; fp < file+NFILE; fp++) { + if (fp->f_count == 0) + continue; + if (fp->f_type != DTYPE_INODE) + continue; + ip = (struct inode *)fp->f_data; + if (ip == 0) + continue; + if ((ip->i_mode & IFMT) != IFCHR) + continue; + if (ip->i_rdev != dev) + continue; + fp->f_flag &= ~(FREAD | FWRITE); + } +} + +/* + * Revoke access the current tty by all processes. + * Used only by the super-user in init + * to give ``clean'' terminals at login. + */ +void +vhangup() +{ + if (! suser()) + return; + if (u.u_ttyp == NULL) + return; + forceclose(u.u_ttyd); + if ((u.u_ttyp->t_state) & TS_ISOPEN) + gsignal(u.u_ttyp->t_pgrp, SIGHUP); +} diff --git a/sys/kernel/sys_pipe.c b/sys/kernel/sys_pipe.c new file mode 100644 index 0000000..c0a19c1 --- /dev/null +++ b/sys/kernel/sys_pipe.c @@ -0,0 +1,307 @@ +/* + * Copyright (c) 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "param.h" +#include "systm.h" +#include "user.h" +#include "proc.h" +#include "inode.h" +#include "file.h" +#include "fs.h" +#include "mount.h" +#include "uio.h" + +int +readp (fp, uio, flag) + register struct file *fp; + register struct uio *uio; + int flag; +{ + register struct inode *ip; + int error; + + ip = (struct inode *)fp->f_data; +loop: + /* Very conservative locking. */ + ILOCK(ip); + + /* If nothing in the pipe, wait (unless FNONBLOCK is set). */ + if (ip->i_size == 0) { + /* + * If there are not both reader and writer active, + * return without satisfying read. + */ + IUNLOCK(ip); + if (ip->i_count != 2) + return (0); + if (fp->f_flag & FNONBLOCK) + return (EWOULDBLOCK); + ip->i_mode |= IREAD; + sleep((caddr_t)ip+4, PPIPE); + goto loop; + } + + uio->uio_offset = fp->f_offset; + error = rwip(ip, uio, flag); + fp->f_offset = uio->uio_offset; + + /* + * If reader has caught up with writer, reset + * offset and size to 0. + */ + if (fp->f_offset == ip->i_size) { + fp->f_offset = 0; + ip->i_size = 0; + if (ip->i_mode & IWRITE) { + ip->i_mode &= ~IWRITE; + wakeup((caddr_t)ip+2); + } + if (ip->i_wsel) { + selwakeup(ip->i_wsel, (long)(ip->i_flag & IWCOLL)); + ip->i_wsel = 0; + ip->i_flag &= ~IWCOLL; + } + } + IUNLOCK(ip); + return (error); +} + +int +writep (fp, uio, flag) + struct file *fp; + register struct uio *uio; + int flag; +{ + register struct inode *ip; + register int c; + int error = 0; + + ip = (struct inode *)fp->f_data; + c = uio->uio_resid; + ILOCK(ip); + if ((fp->f_flag & FNONBLOCK) && ip->i_size + c >= MAXPIPSIZ) { + error = EWOULDBLOCK; + goto done; + } +loop: + /* If all done, return. */ + if (c == 0) { + uio->uio_resid = 0; + goto done; + } + + /* + * If there are not both read and write sides of the pipe active, + * return error and signal too. + */ + if (ip->i_count != 2) { + psignal(u.u_procp, SIGPIPE); + error = EPIPE; +done: IUNLOCK(ip); + return (error); + } + + /* + * If the pipe is full, wait for reads to deplete + * and truncate it. + */ + if (ip->i_size >= MAXPIPSIZ) { + ip->i_mode |= IWRITE; + IUNLOCK(ip); + sleep((caddr_t)ip+2, PPIPE); + ILOCK(ip); + goto loop; + } + + /* + * Write what is possible and loop back. + * If writing less than MAXPIPSIZ, it always goes. + * One can therefore get a file > MAXPIPSIZ if write + * sizes do not divide MAXPIPSIZ. + */ + uio->uio_offset = ip->i_size; + uio->uio_resid = MIN((u_int)c, (u_int)MAXPIPSIZ); + c -= uio->uio_resid; + error = rwip(ip, uio, flag); + if (ip->i_mode&IREAD) { + ip->i_mode &= ~IREAD; + wakeup((caddr_t)ip+4); + } + if (ip->i_rsel) { + selwakeup(ip->i_rsel, (long)(ip->i_flag & IRCOLL)); + ip->i_rsel = 0; + ip->i_flag &= ~IRCOLL; + } + goto loop; +} + +int +pipe_rw (fp, uio, flag) + register struct file *fp; + register struct uio *uio; + int flag; +{ + if (uio->uio_rw == UIO_READ) + return (readp(fp, uio, flag)); + return (writep(fp, uio, flag)); +} + +int +pipe_select (fp, which) + struct file *fp; + int which; +{ + register struct inode *ip = (struct inode *)fp->f_data; + register struct proc *p; + register int retval = 0; + extern int selwait; + + ILOCK(ip); + if (ip->i_count != 2) + retval = 1; + + else switch (which) { + case FREAD: + if (ip->i_size) { + retval = 1; + break; + } + if ((p = ip->i_rsel) && p->p_wchan == (caddr_t)&selwait) + ip->i_flag |= IRCOLL; + else + ip->i_rsel = u.u_procp; + break; + + case FWRITE: + if (ip->i_size < MAXPIPSIZ) { + retval = 1; + break; + } + if ((p = ip->i_wsel) && p->p_wchan == (caddr_t)&selwait) + ip->i_flag |= IWCOLL; + else + ip->i_wsel = u.u_procp; + break; + } + IUNLOCK(ip); + return(retval); +} + +/* + * This routine was pulled out of what used to be called 'ino_close'. Doing + * so saved a test of the inode belonging to a pipe. We know this is a pipe + * because the inode type was DTYPE_PIPE. The dispatch in closef() can come + * directly here instead of the general inode close routine. + * + * This routine frees the inode by calling 'iput'. The inode must be + * unlocked prior to calling this routine because an 'ilock' is done prior + * to the select wakeup processing. + */ +int +pipe_close(fp) + struct file *fp; +{ + register struct inode *ip = (struct inode *)fp->f_data; + + ilock(ip); +#ifdef DIAGNOSTIC + if ((ip->i_flag & IPIPE) == 0) + panic("pipe_close !IPIPE"); +#endif + if (ip->i_rsel) { + selwakeup(ip->i_rsel, (long)(ip->i_flag & IRCOLL)); + ip->i_rsel = 0; + ip->i_flag &= ~IRCOLL; + } + if (ip->i_wsel) { + selwakeup(ip->i_wsel, (long)(ip->i_flag & IWCOLL)); + ip->i_wsel = 0; + ip->i_flag &= ~IWCOLL; + } + ip->i_mode &= ~(IREAD|IWRITE); + wakeup((caddr_t)ip+2); + wakeup((caddr_t)ip+4); + + /* + * And finally decrement the reference count and (likely) release the inode. + */ + iput(ip); + return(0); +} + +const struct fileops pipeops = { + pipe_rw, ino_ioctl, pipe_select, pipe_close +}; + +/* + * The sys-pipe entry. + * Allocate an inode on the root device. Allocate 2 + * file structures. Put it all together with flags. + */ +void +pipe() +{ + register struct inode *ip; + register struct file *rf, *wf; + static struct mount *mp; + struct inode itmp; + int r; + + /* + * if pipedev not yet found, or not available, get it; if can't + * find it, use rootdev. It would be cleaner to wander around + * and fix it so that this and getfs() only check m_dev OR + * m_inodp, but hopefully the mount table isn't scanned enough + * to make it a problem. Besides, 4.3's is just as bad. Basic + * fantasy is that if m_inodp is set, m_dev *will* be okay. + */ + if (! mp || ! mp->m_inodp || mp->m_dev != pipedev) { + for (mp = &mount[0]; ; ++mp) { + if (mp == &mount[NMOUNT]) { + mp = &mount[0]; /* use root */ + break; + } + if (mp->m_inodp == NULL || mp->m_dev != pipedev) + continue; + break; + } + if (mp->m_filsys.fs_ronly) { + u.u_error = EROFS; + return; + } + } + itmp.i_fs = &mp->m_filsys; + itmp.i_dev = mp->m_dev; + ip = ialloc (&itmp); + if (ip == NULL) + return; + rf = falloc(); + if (rf == NULL) { + iput (ip); + return; + } + r = u.u_rval; + wf = falloc(); + if (wf == NULL) { + rf->f_count = 0; + u.u_ofile[r] = NULL; + iput (ip); + return; + } +#ifdef __mips__ + /* Move a secondary return value to register $v1. */ + u.u_frame [FRAME_R3] = u.u_rval; +#else +#error "pipe return value for unknown architecture" +#endif + u.u_rval = r; + wf->f_flag = FWRITE; + rf->f_flag = FREAD; + rf->f_type = wf->f_type = DTYPE_PIPE; + rf->f_data = wf->f_data = (caddr_t) ip; + ip->i_count = 2; + ip->i_mode = IFREG; + ip->i_flag = IACC | IUPD | ICHG | IPIPE; +} diff --git a/sys/kernel/sys_process.c b/sys/kernel/sys_process.c new file mode 100644 index 0000000..e029675 --- /dev/null +++ b/sys/kernel/sys_process.c @@ -0,0 +1,137 @@ +/* + * Copyright (c) 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "param.h" +#include "systm.h" +#include "user.h" +#include "proc.h" +#include "inode.h" +#include "vm.h" +#include "ptrace.h" + +/* + * sys-trace system call. + */ +void +ptrace() +{ + register struct proc *p; + register struct a { + int req; + int pid; + int *addr; + int data; + } *uap; + + uap = (struct a *)u.u_arg; + if (uap->req <= 0) { + u.u_procp->p_flag |= P_TRACED; + return; + } + p = pfind(uap->pid); + if (p == 0 || p->p_stat != SSTOP || p->p_ppid != u.u_procp->p_pid || + !(p->p_flag & P_TRACED)) { + u.u_error = ESRCH; + return; + } + while (ipc.ip_lock) + sleep((caddr_t)&ipc, PZERO); + ipc.ip_lock = p->p_pid; + ipc.ip_data = uap->data; + ipc.ip_addr = uap->addr; + ipc.ip_req = uap->req; + p->p_flag &= ~P_WAITED; + setrun(p); + while (ipc.ip_req > 0) + sleep((caddr_t)&ipc, PZERO); + u.u_rval = ipc.ip_data; + if (ipc.ip_req < 0) + u.u_error = EIO; + ipc.ip_lock = 0; + wakeup((caddr_t)&ipc); +} + +/* + * Code that the child process + * executes to implement the command + * of the parent process in tracing. + */ +int +procxmt() +{ + register int i, *p; + + if (ipc.ip_lock != u.u_procp->p_pid) + return(0); + u.u_procp->p_slptime = 0; + i = ipc.ip_req; + ipc.ip_req = 0; + wakeup ((caddr_t)&ipc); + switch (i) { + + /* read user I */ + case PT_READ_I: + + /* read user D */ + case PT_READ_D: + if (baduaddr ((caddr_t) ipc.ip_addr)) + goto error; + ipc.ip_data = *(int*) ipc.ip_addr; + break; + + /* read u */ + case PT_READ_U: + i = (int) ipc.ip_addr; + if (i < 0 || i >= USIZE) + goto error; + ipc.ip_data = ((unsigned*)&u) [i/sizeof(int)]; + break; + + /* write user I */ + case PT_WRITE_I: + /* write user D */ + case PT_WRITE_D: + if (baduaddr ((caddr_t) ipc.ip_addr)) + goto error; + *(int*) ipc.ip_addr = ipc.ip_data; + break; + + /* write u */ + case PT_WRITE_U: + i = (int)ipc.ip_addr; + p = (int*)&u + i/sizeof(int); + for (i=0; i NSIG) + goto error; + u.u_procp->p_ptracesig = ipc.ip_data; + return(1); + + /* force exit */ + case PT_KILL: + exit(u.u_procp->p_ptracesig); + /*NOTREACHED*/ + + default: +error: + ipc.ip_req = -1; + } + return(0); +} diff --git a/sys/kernel/syscalls.c b/sys/kernel/syscalls.c new file mode 100644 index 0000000..b6ac2b3 --- /dev/null +++ b/sys/kernel/syscalls.c @@ -0,0 +1,169 @@ +/* + * Copyright (c) 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +/* + * System call names. + */ +#ifndef pdp11 +const char *const syscallnames[] = { + "indir", /* 0 = indir */ + "exit", /* 1 = exit */ + "fork", /* 2 = fork */ + "read", /* 3 = read */ + "write", /* 4 = write */ + "open", /* 5 = open */ + "close", /* 6 = close */ + "wait4", /* 7 = wait4 */ + "#8", /* 8 = (old creat) */ + "link", /* 9 = link */ + "unlink", /* 10 = unlink */ + "execv", /* 11 = execv */ + "chdir", /* 12 = chdir */ + "fchdir", /* 13 = fchdir */ + "mknod", /* 14 = mknod */ + "chmod", /* 15 = chmod */ + "chown", /* 16 = chown; now 3 args */ + "chflags", /* 17 = chflags */ + "fchflags", /* 18 = fchflags */ + "lseek", /* 19 = lseek */ + "getpid", /* 20 = getpid */ + "mount", /* 21 = mount */ + "umount", /* 22 = umount */ + "__sysctl", /* 23 = __sysctl */ + "getuid", /* 24 = getuid */ + "geteuid", /* 25 = geteuid */ + "ptrace", /* 26 = ptrace */ + "getppid", /* 27 = getppid */ + "statfs", /* 28 = statfs */ + "fstatfs", /* 29 = fstatfs */ + "getfsstat", /* 30 = getfsstat */ + "sigaction", /* 31 = sigaction */ + "sigprocmask", /* 32 = sigprocmask */ + "access", /* 33 = access */ + "sigpending", /* 34 = sigpending */ + "sigaltstack", /* 35 = sigaltstack */ + "sync", /* 36 = sync */ + "kill", /* 37 = kill */ + "stat", /* 38 = stat */ + "getlogin", /* 39 = getlogin */ + "lstat", /* 40 = lstat */ + "dup", /* 41 = dup */ + "pipe", /* 42 = pipe */ + "setlogin", /* 43 = setlogin */ + "profil", /* 44 = profil */ + "setuid", /* 45 = setuid */ + "seteuid", /* 46 = seteuid */ + "getgid", /* 47 = getgid */ + "getegid", /* 48 = getegid */ + "setgid", /* 49 = setgid */ + "setegid", /* 50 = setegid */ + "kmemdev", /* 51 = kmemdev */ + "phys", /* 52 = (2.9) set phys addr */ + "lock", /* 53 = (2.9) lock in core */ + "ioctl", /* 54 = ioctl */ + "reboot", /* 55 = reboot */ + "sigwait", /* 56 = sigwait */ + "symlink", /* 57 = symlink */ + "readlink", /* 58 = readlink */ + "execve", /* 59 = execve */ + "umask", /* 60 = umask */ + "chroot", /* 61 = chroot */ + "fstat", /* 62 = fstat */ + "#63", /* 63 = unused */ + "#64", /* 64 = (old getpagesize) */ + "pselect", /* 65 = pselect */ + "vfork", /* 66 = vfork */ + "#67", /* 67 = unused */ + "#68", /* 68 = unused */ + "brk", /* 69 = brk */ + "rdglob", /* 70 = read from global space */ + "wrglob", /* 71 = write to global space */ + "msec", /* 72 = kticks */ + "#73", /* 73 = unused */ + "#74", /* 74 = unused */ + "#75", /* 75 = unused */ + "vhangup", /* 76 = vhangup */ + "#77", /* 77 = unused */ + "#78", /* 78 = unused */ + "getgroups", /* 79 = getgroups */ + "setgroups", /* 80 = setgroups */ + "getpgrp", /* 81 = getpgrp */ + "setpgrp", /* 82 = setpgrp */ + "setitimer", /* 83 = setitimer */ + "old wait", /* 84 = wait,wait3 COMPAT*/ + "#85", /* 85 = unused */ + "getitimer", /* 86 = getitimer */ + "#87", /* 87 = (old gethostname) */ + "#88", /* 88 = (old sethostname) */ + "getdtablesize", /* 89 = getdtablesize */ + "dup2", /* 90 = dup2 */ + "#91", /* 91 = unused */ + "fcntl", /* 92 = fcntl */ + "select", /* 93 = select */ + "#94", /* 94 = unused */ + "fsync", /* 95 = fsync */ + "setpriority", /* 96 = setpriority */ + "socket", /* 97 = socket */ + "connect", /* 98 = connect */ + "accept", /* 99 = accept */ + "getpriority", /* 100 = getpriority */ + "send", /* 101 = send */ + "recv", /* 102 = recv */ + "sigreturn", /* 103 = sigreturn */ + "bind", /* 104 = bind */ + "setsockopt", /* 105 = setsockopt */ + "listen", /* 106 = listen */ + "sigsuspend", /* 107 = sigsuspend */ + "#108", /* 108 = (old sigvec) */ + "#109", /* 109 = (old sigblock) */ + "#110", /* 110 = (old sigsetmask) */ + "#111", /* 111 = (old sigpause) */ + "sigstack", /* 112 = sigstack COMPAT-43 */ + "recvmsg", /* 113 = recvmsg */ + "sendmsg", /* 114 = sendmsg */ + "#115", /* 115 = unused */ + "gettimeofday", /* 116 = gettimeofday */ + "getrusage", /* 117 = getrusage */ + "getsockopt", /* 118 = getsockopt */ + "#119", /* 119 = unused */ + "readv", /* 120 = readv */ + "writev", /* 121 = writev */ + "settimeofday", /* 122 = settimeofday */ + "fchown", /* 123 = fchown */ + "fchmod", /* 124 = fchmod */ + "recvfrom", /* 125 = recvfrom */ + "#126", /* 126 = (old setreuid) */ + "#127", /* 127 = (old setregid) */ + "rename", /* 128 = rename */ + "truncate", /* 129 = truncate */ + "ftruncate", /* 130 = ftruncate */ + "flock", /* 131 = flock */ + "#132", /* 132 = unused */ + "sendto", /* 133 = sendto */ + "shutdown", /* 134 = shutdown */ + "socketpair", /* 135 = socketpair */ + "mkdir", /* 136 = mkdir */ + "rmdir", /* 137 = rmdir */ + "utimes", /* 138 = utimes */ + "#139", /* 139 = unused */ + "adjtime", /* 140 = adjtime */ + "getpeername", /* 141 = getpeername */ + "#142", /* 142 = (old gethostid) */ + "#143", /* 143 = (old sethostid) */ + "getrlimit", /* 144 = getrlimit */ + "setrlimit", /* 145 = setrlimit */ + "killpg", /* 146 = killpg */ + "#147", /* 147 = unused */ + "setquota", /* 148 = setquota */ + "quota", /* 149 = quota */ + "getsockname", /* 150 = getsockname */ + "#151", /* 151 = unused */ + "ustore", /* 152 = ustore */ + "ufetch", /* 153 = ufetch */ + "ucall", /* 154 = ucall */ + "#155", /* 155 = unused */ +}; +#endif diff --git a/sys/kernel/tty.c b/sys/kernel/tty.c new file mode 100644 index 0000000..41ca2e6 --- /dev/null +++ b/sys/kernel/tty.c @@ -0,0 +1,1653 @@ +/* + * Copyright (c) 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "param.h" +#include "user.h" +#include "ioctl.h" +#include "tty.h" +#include "proc.h" +#include "file.h" +#include "conf.h" +#include "dk.h" +#include "uio.h" +#include "kernel.h" +#include "systm.h" +#include "inode.h" +#include "syslog.h" + +static int rts = TIOCM_RTS; + +/* + * These were moved here from tty.h so that they could be easily modified + * and/or patched instead of recompiling the kernel. There is only 1 other + * place which references these - see tty_pty.c + * + * The block and unblock numbers may look low but certain devices (the DHV-11 + * for example) have poor silo handling and at high data rates (19200) the + * raw queue overflows even though we've stopped the sending device. At 192 + * characters for the 'block' point c-kermit would regularily see dropped data + * during interactive mode at 19200. + * + * It would be nice to have a larger than 8kb clist area and raise these limits + * but that would require 2 mapping registers and/or a rewrite of the entire + * clist handling. + */ +int TTYHOG = 255; +int TTYBLOCK = 128; +int TTYUNBLOCK = 64; + +/* + * Table giving parity for characters and indicating + * character classes to tty driver. In particular, + * if the low 6 bits are 0, then the character needs + * no special processing on output. + */ +const char partab[] = { + 0001,0201,0201,0001,0201,0001,0001,0201, + 0202,0004,0003,0201,0005,0206,0201,0001, + 0201,0001,0001,0201,0001,0201,0201,0001, + 0001,0201,0201,0001,0201,0001,0001,0201, + 0200,0000,0000,0200,0000,0200,0200,0000, + 0000,0200,0200,0000,0200,0000,0000,0200, + 0000,0200,0200,0000,0200,0000,0000,0200, + 0200,0000,0000,0200,0000,0200,0200,0000, + 0200,0000,0000,0200,0000,0200,0200,0000, + 0000,0200,0200,0000,0200,0000,0000,0200, + 0000,0200,0200,0000,0200,0000,0000,0200, + 0200,0000,0000,0200,0000,0200,0200,0000, + 0000,0200,0200,0000,0200,0000,0000,0200, + 0200,0000,0000,0200,0000,0200,0200,0000, + 0200,0000,0000,0200,0000,0200,0200,0000, + 0000,0200,0200,0000,0200,0000,0000,0201, + + /* + * 7 bit ascii ends with the last character above, + * but we contine through all 256 codes for the sake + * of the tty output routines which use special vax + * instructions which need a 256 character trt table. + */ + + 0007,0007,0007,0007,0007,0007,0007,0007, + 0007,0007,0007,0007,0007,0007,0007,0007, + 0007,0007,0007,0007,0007,0007,0007,0007, + 0007,0007,0007,0007,0007,0007,0007,0007, + 0007,0007,0007,0007,0007,0007,0007,0007, + 0007,0007,0007,0007,0007,0007,0007,0007, + 0007,0007,0007,0007,0007,0007,0007,0007, + 0007,0007,0007,0007,0007,0007,0007,0007, + 0007,0007,0007,0007,0007,0007,0007,0007, + 0007,0007,0007,0007,0007,0007,0007,0007, + 0007,0007,0007,0007,0007,0007,0007,0007, + 0007,0007,0007,0007,0007,0007,0007,0007, + 0007,0007,0007,0007,0007,0007,0007,0007, + 0007,0007,0007,0007,0007,0007,0007,0007, + 0007,0007,0007,0007,0007,0007,0007,0007, + 0007,0007,0007,0007,0007,0007,0007,0007 +}; + +const int tthiwat[NSPEEDS] = + { 100,100,100,100,100,100,100,200,200,400,400,400,650,650,1300,2000,2000,2000,2000,2000,2000,2000,2000,2000,2000,2000,2000,2000,2000 }; + +const int ttlowat[NSPEEDS] = + { 30, 30, 30, 30, 30, 30, 30, 50, 50,120,120,120,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125 }; + +#define SET(t,f) (t) |= (f) +#define CLR(t,f) (t) &= ~(f) +#define ISSET(t,f) ((t) & (f)) + +/* + * Set t_chars to default values. + */ +void +ttychars(tp) + struct tty *tp; +{ + static const struct ttychars ttydefaults = { + CERASE, CKILL, CINTR, CQUIT, CSTART, CSTOP, CEOF, + CBRK, CSUSP, CDSUSP, CRPRNT, CFLUSH, CWERASE,CLNEXT + }; + + tp->t_chars = ttydefaults; +} + +/* + * Wakeup processes waiting on output flow control (TS_ASLEEP). Normally + * called from driver start routine (dhvstart, etc) after a transmit done + * interrupt. If t_outq.c_cc <= t_lowat then do the wakeup. + */ +void +ttyowake(tp) + register struct tty *tp; +{ + if (tp->t_outq.c_cc <= TTLOWAT(tp)) { + if (ISSET(tp->t_state,TS_ASLEEP)) { + CLR(tp->t_state,TS_ASLEEP); + wakeup ((caddr_t)&tp->t_outq); + } + if (tp->t_wsel) { + selwakeup (tp->t_wsel, tp->t_state & TS_WCOLL); + tp->t_wsel = 0; + CLR(tp->t_state,TS_WCOLL); + } + } +} + +static void +ttywait(tp) + register struct tty *tp; +{ + register int s = spltty(); + + while ((tp->t_outq.c_cc || tp->t_state & TS_BUSY) && + tp->t_state & TS_CARR_ON && tp->t_oproc) { + (*tp->t_oproc)(tp); + /* + * If the output routine drains the queue and the device is no longer busy + * then don't wait for something that's already happened. + */ + if (tp->t_outq.c_cc == 0 && !ISSET(tp->t_state,TS_BUSY)) + break; + tp->t_state |= TS_ASLEEP; + sleep((caddr_t)&tp->t_outq, TTOPRI); + splx(s); /* drop priority, give interrupts a chance */ + s = spltty(); + } + splx(s); +} + +/* + * Wait for output to drain, then flush input waiting. + */ +void +ttywflush(tp) + register struct tty *tp; +{ + ttywait(tp); + ttyflush(tp, FREAD); +} + +static void +ttyunblock (tp) + register struct tty *tp; +{ + if (ISSET(tp->t_flags,TANDEM) && + tp->t_startc != _POSIX_VDISABLE && + putc(tp->t_startc, &tp->t_outq) == 0) { + CLR(tp->t_state,TS_TBLOCK); + ttstart(tp); + } + if (ISSET(tp->t_flags, RTSCTS) && + (*cdevsw[major(tp->t_dev)].d_ioctl) (tp->t_dev, TIOCMBIS, + (caddr_t) &rts, 0) == 0) { + CLR(tp->t_state, TS_TBLOCK); + } +} + +/* + * Flush all TTY queues. + */ +void ttyflush (tp, rw) + register struct tty *tp; +{ + register int s; + + s = spltty(); + if (rw & FREAD) { + while (getc(&tp->t_canq) >= 0) + ; + while (getc(&tp->t_rawq) >= 0) + ; + tp->t_rocount = 0; + tp->t_rocol = 0; + tp->t_state &= ~TS_LOCAL; + ttwakeup (tp); + } + if (rw & FWRITE) { + tp->t_state &= ~TS_TTSTOP; + (*cdevsw[major(tp->t_dev)].d_stop)(tp, rw); + wakeup ((caddr_t)&tp->t_outq); + while (getc(&tp->t_outq) >= 0) + ; + selwakeup (tp->t_wsel, tp->t_state & TS_WCOLL); + CLR(tp->t_state, TS_WCOLL); + tp->t_wsel = 0; + } + if (rw & FREAD && ISSET(tp->t_state,TS_TBLOCK)) + ttyunblock(tp); + splx(s); +} + +/* + * Send stop character on input overflow. + */ +void +ttyblock(tp) + register struct tty *tp; +{ + register int total; + + total = tp->t_rawq.c_cc + tp->t_canq.c_cc; + /* + * Block further input iff: + * Current input > threshold AND input is available to user program + */ + if (total >= TTYBLOCK && + ((tp->t_flags & (RAW|CBREAK)) || (tp->t_canq.c_cc > 0)) && + (tp->t_state & TS_TBLOCK) == 0) { + /* + * TANDEM is the same as IXOFF for all intents and purposes. Since we could + * get called for either software or hardware flow control we need to check + * the IXOFF bit. + */ + if (ISSET(tp->t_flags,TANDEM) && + tp->t_stopc != _POSIX_VDISABLE && + putc(tp->t_stopc, &tp->t_outq) == 0) { + SET(tp->t_state, TS_TBLOCK); + ttstart(tp); + } + /* + * If queue is full, drop RTS to tell modem to stop sending us stuff + */ + if (ISSET(tp->t_flags, RTSCTS) && + (*cdevsw[major(tp->t_dev)].d_ioctl) (tp->t_dev, TIOCMBIC, + (caddr_t) &rts, 0) == 0) { + SET(tp->t_state, TS_TBLOCK); + } + } +} + +/* + * Restart typewriter output following a delay timeout. + * The name of the routine is passed to the timeout + * subroutine and it is called during a clock interrupt. + */ +void +ttrstrt(tp) + register struct tty *tp; +{ + tp->t_state &= ~TS_TIMEOUT; + ttstart(tp); +} + +/* + * Start output on the typewriter. It is used from the top half + * after some characters have been put on the output queue, + * from the interrupt routine to transmit the next + * character, and after a timeout has finished. + * + * The spl calls were removed because the priority should already be spltty. + */ +void +ttstart(tp) + register struct tty *tp; +{ + if (tp->t_oproc) /* kludge for pty */ + (*tp->t_oproc) (tp); +} + +/* + * reinput pending characters after state switch + * call at spltty(). + */ +static void +ttypend (tp) + register struct tty *tp; +{ + struct clist tq; + register int c; + + tp->t_flags &= ~PENDIN; + tp->t_state |= TS_TYPEN; + tq = tp->t_rawq; + tp->t_rawq.c_cc = 0; + tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0; + while ((c = getc(&tq)) >= 0) + ttyinput(c, tp); + tp->t_state &= ~TS_TYPEN; +} + +static int +ttnread (tp) + register struct tty *tp; +{ + register int nread = 0; + + if (tp->t_flags & PENDIN) + ttypend(tp); + nread = tp->t_canq.c_cc; + if (tp->t_flags & (RAW|CBREAK)) + nread += tp->t_rawq.c_cc; + return (nread); +} + +/* + * Common code for tty ioctls. + */ +/*ARGSUSED*/ +int +ttioctl(tp, com, data, flag) + register struct tty *tp; + u_int com; + caddr_t data; + int flag; +{ + int s; + long newflags; + +//printf ("ttioctl (com=%08x, data=%08x, flag=%d)\n", com, data, flag); + /* + * If the ioctl involves modification, + * hang if in the background. + */ + switch (com) { + + case TIOCSETD: + case TIOCSETP: + case TIOCSETN: + case TIOCFLUSH: + case TIOCSETC: + case TIOCSLTC: + case TIOCSPGRP: + case TIOCLBIS: + case TIOCLBIC: + case TIOCLSET: + case TIOCSTI: + case TIOCSWINSZ: + while (u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp && + (u.u_procp->p_flag & SVFORK) == 0 && + !(u.u_procp->p_sigignore & sigmask(SIGTTOU)) && + !(u.u_procp->p_sigmask & sigmask(SIGTTOU))) { + gsignal(u.u_procp->p_pgrp, SIGTTOU); + sleep((caddr_t)&lbolt, TTOPRI); + } + break; + } + + /* + * Process the ioctl. + */ + switch (com) { + + /* get discipline number */ + case TIOCGETD: + *(int *)data = 0; + break; + + /* set line discipline */ + case TIOCSETD: { + register int t = *(int *)data; + if (t != 0) + return (ENXIO); + break; + } + + /* prevent more opens on channel */ + case TIOCEXCL: + tp->t_state |= TS_XCLUDE; + break; + + case TIOCNXCL: + tp->t_state &= ~TS_XCLUDE; + break; + + /* hang up line on last close */ + case TIOCHPCL: + tp->t_state |= TS_HUPCLS; + break; + + case TIOCFLUSH: { + register int flags = *(int *)data; + + if (flags == 0) + flags = FREAD|FWRITE; + else + flags &= FREAD|FWRITE; + ttyflush(tp, flags); + break; + } + + /* return number of characters immediately available */ + case FIONREAD: + *(off_t *)data = ttnread(tp); + break; + + case TIOCOUTQ: + *(int *)data = tp->t_outq.c_cc; + break; + + case TIOCSTOP: + s = spltty(); + if ((tp->t_state & TS_TTSTOP) == 0) { + tp->t_state |= TS_TTSTOP; + (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); + } + splx(s); + break; + + case TIOCSTART: + s = spltty(); + if ((tp->t_state & TS_TTSTOP) || (tp->t_flags & FLUSHO)) { + tp->t_state &= ~TS_TTSTOP; + tp->t_flags &= ~FLUSHO; + ttstart(tp); + } + splx(s); + break; + + /* + * Simulate typing of a character at the terminal. + */ + case TIOCSTI: + if (u.u_uid && (flag & FREAD) == 0) + return (EPERM); + if (u.u_uid && u.u_ttyp != tp) + return (EACCES); + ttyinput (*(char *)data, tp); + break; + + case TIOCSETP: + case TIOCSETN: { + register struct sgttyb *sg = (struct sgttyb *)data; + + tp->t_erase = sg->sg_erase; + tp->t_kill = sg->sg_kill; + tp->t_ispeed = sg->sg_ispeed; + tp->t_ospeed = sg->sg_ospeed; + newflags = (tp->t_flags&0xffff0000) | (sg->sg_flags&0xffffL); + s = spltty(); + if (tp->t_flags & RAW || newflags & RAW || com == TIOCSETP) { + ttywait(tp); + ttyflush(tp, FREAD); + } else if ((tp->t_flags & CBREAK) != (newflags & CBREAK)) { + if (newflags & CBREAK) { + struct clist tq; + + catq(&tp->t_rawq, &tp->t_canq); + tq = tp->t_rawq; + tp->t_rawq = tp->t_canq; + tp->t_canq = tq; + } else { + tp->t_flags |= PENDIN; + newflags |= PENDIN; + ttwakeup (tp); + } + } + tp->t_flags = newflags; + if (tp->t_flags & RAW) { + tp->t_state &= ~TS_TTSTOP; + ttstart(tp); + } + splx(s); + break; + } + + /* send current parameters to user */ + case TIOCGETP: { + register struct sgttyb *sg = (struct sgttyb *)data; + + sg->sg_ispeed = tp->t_ispeed; + sg->sg_ospeed = tp->t_ospeed; + sg->sg_erase = tp->t_erase; + sg->sg_kill = tp->t_kill; + sg->sg_flags = tp->t_flags; + break; + } + + case FIONBIO: + break; /* XXX remove */ + + case FIOASYNC: + if (*(int *)data) + tp->t_state |= TS_ASYNC; + else + tp->t_state &= ~TS_ASYNC; + break; + + case TIOCGETC: + bcopy((caddr_t)&tp->t_intrc, data, sizeof (struct tchars)); + break; + + case TIOCSETC: + bcopy(data, (caddr_t)&tp->t_intrc, sizeof (struct tchars)); + break; + + /* set/get local special characters */ + case TIOCSLTC: + bcopy(data, (caddr_t)&tp->t_suspc, sizeof (struct ltchars)); + break; + + case TIOCGLTC: + bcopy((caddr_t)&tp->t_suspc, data, sizeof (struct ltchars)); + break; + + /* + * Modify local mode word. + */ + case TIOCLBIS: + tp->t_flags |= (long)*(u_int *)data << 16; + break; + + case TIOCLBIC: + tp->t_flags &= ~((long)*(u_int *)data << 16); + break; + + case TIOCLSET: + tp->t_flags &= 0xffffL; + tp->t_flags |= (long)*(u_int *)data << 16; + break; + + case TIOCLGET: + *(int *)data = tp->t_flags >> 16; + break; + + /* + * Allow SPGRP only if tty is open for reading. + * Quick check: if we can find a process in the new pgrp, + * this user must own that process. + * SHOULD VERIFY THAT PGRP IS IN USE AND IS THIS USER'S. + */ + case TIOCSPGRP: { + struct proc *p; + short pgrp = *(int *)data; + + if (u.u_uid && (flag & FREAD) == 0) + return (EPERM); + p = pfind(pgrp); + if (p && p->p_pgrp == pgrp && + p->p_uid != u.u_uid && u.u_uid && !inferior(p)) + return (EPERM); + tp->t_pgrp = pgrp; + break; + } + + case TIOCGPGRP: + *(int *)data = tp->t_pgrp; + break; + + case TIOCSWINSZ: + if (bcmp((caddr_t)&tp->t_winsize, data, + sizeof (struct winsize))) { + tp->t_winsize = *(struct winsize *)data; + gsignal(tp->t_pgrp, SIGWINCH); + } + break; + + case TIOCGWINSZ: + *(struct winsize *)data = tp->t_winsize; + break; + + default: + return (-1); + } + return (0); +} + +/* + * Check that input or output is possible on a terminal. + */ +int +ttyselect (tp, rw) + register struct tty *tp; + int rw; +{ + int nread; + register int s = spltty(); + + switch (rw) { + + case FREAD: + nread = ttnread(tp); + if ((nread > 0) || ((tp->t_state & TS_CARR_ON) == 0)) + goto win; + if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait) + tp->t_state |= TS_RCOLL; + else + tp->t_rsel = u.u_procp; + break; + + case FWRITE: + if (tp->t_outq.c_cc <= TTLOWAT(tp)) + goto win; + if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait) + tp->t_state |= TS_WCOLL; + else + tp->t_wsel = u.u_procp; + break; + } + splx(s); + return (0); +win: + splx(s); + return (1); +} + +/* + * Initial open of tty, or (re)entry to line discipline. + * Establish a process group for distribution of + * quits and interrupts from the tty. + */ +int +ttyopen(dev, tp) + dev_t dev; + register struct tty *tp; +{ + register struct proc *pp; + + pp = u.u_procp; + tp->t_dev = dev; + if (pp->p_pgrp == 0) { + u.u_ttyp = tp; + u.u_ttyd = dev; + if (tp->t_pgrp == 0) + tp->t_pgrp = pp->p_pid; + pp->p_pgrp = tp->t_pgrp; + } + tp->t_state &= ~TS_WOPEN; + if ((tp->t_state & TS_ISOPEN) == 0) { + tp->t_state |= TS_ISOPEN; + bzero((caddr_t)&tp->t_winsize, sizeof(tp->t_winsize)); + } + return (0); +} + +/* + * "close" a line discipline + */ +int +ttylclose (tp, flag) + register struct tty *tp; + int flag; +{ + /* + * 4.4 has IO_NDELAY but I think that is a mistake because the upper level + * 'close' routines all pass 'fp->f_flags' down. This was verified with a + * printf here - the F* flags are received rather than the IO_* flags! + */ + if (flag & FNDELAY) + ttyflush(tp, FREAD|FWRITE); + else + ttywflush(tp); + return (0); +} + +/* + * Clean terminal on last close. + */ +void +ttyclose(tp) + register struct tty *tp; +{ + ttyflush(tp, FREAD|FWRITE); + tp->t_pgrp = 0; + tp->t_state = 0; +} + +/* + * Handle modem control transition on a tty. + * Flag indicates new state of carrier. + * Returns 0 if the line should be turned off, otherwise 1. + */ +int +ttymodem(tp, flag) + register struct tty *tp; + int flag; +{ + if ((tp->t_state & TS_WOPEN) == 0 && (tp->t_flags & MDMBUF)) { + /* + * MDMBUF: do flow control according to carrier flag + */ + if (flag) { + tp->t_state &= ~TS_TTSTOP; + ttstart(tp); + } else if ((tp->t_state & TS_TTSTOP) == 0) { + tp->t_state |= TS_TTSTOP; + (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); + } + } else if (flag == 0) { + /* + * Lost carrier. + */ + tp->t_state &= ~TS_CARR_ON; + if (tp->t_state & TS_ISOPEN) { + if ((tp->t_flags & NOHANG) == 0) { + gsignal(tp->t_pgrp, SIGHUP); + gsignal(tp->t_pgrp, SIGCONT); + ttyflush(tp, FREAD|FWRITE); + return (0); + } + } + } else { + /* + * Carrier now on. + */ + tp->t_state |= TS_CARR_ON; + wakeup ((caddr_t) &tp->t_rawq); + } + return (1); +} + +/* + * Default modem control routine (for other line disciplines). + * Return argument flag, to turn off device on carrier drop. + */ +int +nullmodem(tp, flag) + register struct tty *tp; + int flag; +{ + if (flag) + tp->t_state |= TS_CARR_ON; + else + tp->t_state &= ~TS_CARR_ON; + return (flag); +} + +/* + * send string cp to tp + */ +static void +ttyout (cp, tp) + register char *cp; + register struct tty *tp; +{ + register int c; + + while ((c = *cp++)) + (void) ttyoutput (c, tp); +} + +/* + * Crt back over cnt chars perhaps + * erasing them. + */ +static void +ttyrubo(tp, cnt) + register struct tty *tp; + register int cnt; +{ + register char *rubostring = (tp->t_flags & CRTERA) ? "\b \b" : "\b"; + + while (--cnt >= 0) + ttyout(rubostring, tp); +} + +/* + * Echo a typed character to the terminal + */ +static void +ttyecho(c, tp) + register int c; + register struct tty *tp; +{ + register int c7; + + if ((tp->t_state & TS_CNTTB) == 0) + tp->t_flags &= ~FLUSHO; + if ((tp->t_flags & ECHO) == 0) + return; + c &= 0377; + + if (tp->t_flags & RAW) { + (void) ttyoutput(c, tp); + return; + } + if (c == '\r' && tp->t_flags & CRMOD) + c = '\n'; + c7 = c & 0177; + if (tp->t_flags & CTLECH) { + if ((c7 <= 037 && c != '\t' && c != '\n') || c7 == 0177) { + (void) ttyoutput('^', tp); + if (c7 == 0177) + c7 = '?'; + else + c7 += 'A' - 1; + } + } + (void) ttyoutput(c7, tp); +} + +/* + * Reprint the rawq line. + * We assume c_cc has already been checked. + */ +static void +ttyretype(tp) + register struct tty *tp; +{ + register char *cp; + int s; + + if (tp->t_rprntc != _POSIX_VDISABLE) + ttyecho(tp->t_rprntc, tp); + (void) ttyoutput('\n', tp); + s = spltty(); + for (cp = tp->t_canq.c_cf; cp; cp = nextc(&tp->t_canq, cp)) + ttyecho(*cp, tp); + for (cp = tp->t_rawq.c_cf; cp; cp = nextc(&tp->t_rawq, cp)) + ttyecho(*cp, tp); + tp->t_state &= ~TS_ERASE; + splx(s); + tp->t_rocount = tp->t_rawq.c_cc; + tp->t_rocol = 0; +} + +/* + * Rubout one character from the rawq of tp + * as cleanly as possible. + */ +static void +ttyrub(c, tp) + register int c; + register struct tty *tp; +{ + register char *cp; + int savecol; + int s; + + if ((tp->t_flags & ECHO) == 0) + return; + tp->t_flags &= ~FLUSHO; + c &= 0377; + if (tp->t_flags & CRTBS) { + if (tp->t_rocount == 0) { + /* + * Screwed by ttwrite; retype + */ + ttyretype(tp); + return; + } + /* + * Out of the ENTIRE tty subsystem would believe this is the ONLY place + * that the "9th" bit (quoted chars) is tested? + */ + if (c == ('\t' | 0200) || c == ('\n' | 0200)) + ttyrubo (tp, 2); + else switch (partab [c &= 0177] & 0177) { + + case ORDINARY: + ttyrubo(tp, 1); + break; + + case VTAB: + case BACKSPACE: + case CONTROL: + case RETURN: + if (tp->t_flags & CTLECH) + ttyrubo(tp, 2); + break; + + case TAB: + if (tp->t_rocount < tp->t_rawq.c_cc) { + ttyretype(tp); + return; + } + s = spltty(); + savecol = tp->t_col; + tp->t_state |= TS_CNTTB; + tp->t_flags |= FLUSHO; + tp->t_col = tp->t_rocol; + cp = tp->t_rawq.c_cf; + for (; cp; cp = nextc (&tp->t_rawq, cp)) + ttyecho(*cp, tp); + tp->t_flags &= ~FLUSHO; + tp->t_state &= ~TS_CNTTB; + splx(s); + /* + * savecol will now be length of the tab + */ + savecol -= tp->t_col; + tp->t_col += savecol; + if (savecol > 8) + savecol = 8; /* overflow screw */ + while (--savecol >= 0) + (void) ttyoutput('\b', tp); + break; + + default: + panic("ttyrub"); + } + } else if (tp->t_flags & PRTERA) { + if ((tp->t_state & TS_ERASE) == 0) { + (void) ttyoutput('\\', tp); + tp->t_state |= TS_ERASE; + } + ttyecho(c, tp); + } else + ttyecho(tp->t_erase, tp); + tp->t_rocount--; +} + +/* + * Is c a break char for tp? + */ +int +ttbreakc (c, tp) + register int c; + register struct tty *tp; +{ + return (c == '\n' || CCEQ (tp->t_eofc, c) || CCEQ (tp->t_brkc, c) || + (c == '\r' && (tp->t_flags & CRMOD))); +} + +/* + * Place a character on raw TTY input queue, + * putting in delimiters and waking up top + * half as needed. Also echo if required. + * The arguments are the character and the + * appropriate tty structure. + */ +void +ttyinput (c, tp) + register int c; + register struct tty *tp; +{ + long t_flags = tp->t_flags; + int i; + + /* + * If input is pending take it first. + */ + if (t_flags & PENDIN) + ttypend(tp); +#ifdef UCB_METER + tk_nin++; +#endif + c &= 0377; + + /* + * In tandem mode, check high water mark. + */ + if (t_flags & (TANDEM | RTSCTS)) + ttyblock(tp); + + if (t_flags & RAW) { + /* + * Raw mode, just put character + * in input q w/o interpretation. + */ + if (tp->t_rawq.c_cc > TTYHOG) + ttyflush(tp, FREAD | FWRITE); + else { + if (putc(c, &tp->t_rawq) == 0) + ttwakeup (tp); + ttyecho(c, tp); + } + goto endcase; + } + + /* + * Ignore any high bit added during + * previous ttyinput processing. + */ + if ((tp->t_state & TS_TYPEN) == 0 && (t_flags & PASS8) == 0) + c &= 0177; + + /* + * Check for literal nexting very first. This is the _ONLY_ place + * left which ORs in 0200. Handling literal nexting this way is + * what keeps the tty subsystem from being 8 bit clean. The fix is + * horrendous though and is put off for now. And to think that ALL + * of this is made necessary by ttyrubout() - it's the only place that + * actually _checks_ the 0200 bit and only for newline and tab chars + * at that! + * + * If we had 9 bit bytes life would be a lot simpler ;) + * + * The basic idea is to flag the character as "special" and also + * modify it so that the character does not match any of the special + * editing or control characters. We could just as simply jump directly + * to the test for 'cbreak' below. + */ + if (tp->t_state & TS_LNCH) { + c |= 0200; + tp->t_state &= ~TS_LNCH; + } + + /* + * Scan for special characters. This code + * is really just a big case statement with + * non-constant cases. The bottom of the + * case statement is labeled ``endcase'', so goto + * it after a case match, or similar. + */ + if (CCEQ(tp->t_lnextc, c)) { + if (t_flags & ECHO) + ttyout("^\b", tp); + tp->t_state |= TS_LNCH; + goto endcase; + } + if (CCEQ(tp->t_flushc, c)) { + if (t_flags & FLUSHO) + tp->t_flags &= ~FLUSHO; + else { + ttyflush(tp, FWRITE); + ttyecho(c, tp); + if (tp->t_rawq.c_cc + tp->t_canq.c_cc) + ttyretype(tp); + tp->t_flags |= FLUSHO; + } + goto startoutput; + } + if (CCEQ(tp->t_suspc, c)) { + if ((t_flags & NOFLSH) == 0) + ttyflush(tp, FREAD); + ttyecho(c, tp); + gsignal(tp->t_pgrp, SIGTSTP); + goto endcase; + } + + /* + * Handle start/stop characters. + */ + if (CCEQ(tp->t_stopc, c)) { + if ((tp->t_state & TS_TTSTOP) == 0) { + tp->t_state |= TS_TTSTOP; + (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); + return; + } + if (CCEQ(tp->t_startc, c)) + return; + goto endcase; + } + if (CCEQ(tp->t_startc, c)) + goto restartoutput; + + /* + * Look for interrupt/quit chars. + */ + if (CCEQ(tp->t_intrc, c) || CCEQ(tp->t_quitc, c)) { + if ((t_flags & NOFLSH) == 0) + ttyflush(tp, FREAD|FWRITE); + ttyecho(c, tp); + gsignal(tp->t_pgrp, CCEQ(tp->t_intrc, c) ? SIGINT : SIGQUIT); + goto endcase; + } + + /* + * Cbreak mode, don't process line editing + * characters; check high water mark for wakeup. + */ + if (t_flags & CBREAK) { + if (tp->t_rawq.c_cc > TTYHOG) { + if (tp->t_outq.c_cc < TTHIWAT(tp)) + (void) ttyoutput(CTRL('g'), tp); + } else if (putc(c, &tp->t_rawq) == 0) { + ttwakeup (tp); + ttyecho (c, tp); + } + goto endcase; + } + + /* + * From here on down cooked mode character + * processing takes place. + */ + if (CCEQ(tp->t_erase, c) || CCEQ(CTRL('h'), c)) { + if (tp->t_rawq.c_cc) + ttyrub(unputc(&tp->t_rawq), tp); + goto endcase; + } + if (CCEQ(tp->t_kill, c)) { + if (t_flags & CRTKIL && + tp->t_rawq.c_cc == tp->t_rocount) { + while (tp->t_rawq.c_cc) + ttyrub(unputc(&tp->t_rawq), tp); + } else { + ttyecho(c, tp); + ttyecho('\n', tp); + while (getc(&tp->t_rawq) > 0) + ; + tp->t_rocount = 0; + } + tp->t_state &= ~TS_LOCAL; + goto endcase; + } + + /* + * Check word erase/reprint line. + */ + if (CCEQ(tp->t_werasc, c)) { + if (tp->t_rawq.c_cc == 0) + goto endcase; + do { + c = unputc(&tp->t_rawq); + if (c != ' ' && c != '\t') + goto erasenb; + ttyrub(c, tp); + } while (tp->t_rawq.c_cc); + goto endcase; +erasenb: + do { + ttyrub(c, tp); + if (tp->t_rawq.c_cc == 0) + goto endcase; + c = unputc(&tp->t_rawq); + } while (c != ' ' && c != '\t'); + (void) putc(c, &tp->t_rawq); + goto endcase; + } + if (CCEQ(tp->t_rprntc, c)) { + ttyretype(tp); + goto endcase; + } + + /* + * Check for input buffer overflow + */ + if (tp->t_rawq.c_cc+tp->t_canq.c_cc >= TTYHOG) { + (void) ttyoutput(CTRL('g'), tp); + goto endcase; + } + + /* + * Put data char in q for user and + * wakeup on seeing a line delimiter. + */ + if (putc(c, &tp->t_rawq) == 0) { + if (ttbreakc (c, tp)) { + tp->t_rocount = 0; + catq(&tp->t_rawq, &tp->t_canq); + ttwakeup (tp); + } else if (tp->t_rocount++ == 0) + tp->t_rocol = tp->t_col; + if (tp->t_state & TS_ERASE) { + tp->t_state &= ~TS_ERASE; + (void) ttyoutput('/', tp); + } + i = tp->t_col; + ttyecho(c, tp); + if (CCEQ(tp->t_eofc, c) && t_flags & ECHO) { + i = MIN(2, tp->t_col - i); + while (i > 0) { + (void) ttyoutput('\b', tp); + i--; + } + } + } +endcase: + /* + * If DEC-style start/stop is enabled don't restart + * output until seeing the start character. + */ + if (t_flags & DECCTQ && tp->t_state & TS_TTSTOP && + tp->t_startc != tp->t_stopc) + return; +restartoutput: + tp->t_state &= ~TS_TTSTOP; + tp->t_flags &= ~FLUSHO; +startoutput: + ttstart(tp); +} + +/* + * Put character on TTY output queue, adding delays, + * expanding tabs, and handling the CR/NL bit. + * This is called both from the top half for output, + * and from interrupt level for echoing. + * The arguments are the character and the tty structure. + * Returns < 0 if putc succeeds, otherwise returns char to resend + */ +int +ttyoutput(c, tp) + register int c; + register struct tty *tp; +{ + register int col; + + if (tp->t_flags & (RAW|LITOUT)) { + if (tp->t_flags & FLUSHO) + return (-1); + if (putc(c, &tp->t_outq)) + return(c); +#ifdef UCB_METER + tk_nout++; +#endif + return(-1); + } + + c &= 0177; +#ifdef whybother + /* + * Ignore EOT in normal mode to avoid + * hanging up certain terminals. + */ + if (c == CEOT && (tp->t_flags & CBREAK) == 0) + return(-1); +#endif + /* + * Turn tabs to spaces as required + */ + if (c == '\t' && (tp->t_flags & XTABS)) { + register int s; + + c = 8 - (tp->t_col&7); + if ((tp->t_flags & FLUSHO) == 0) { + s = spltty(); /* don't interrupt tabs */ + c -= b_to_q(" ", c, &tp->t_outq); +#ifdef UCB_METER + tk_nout += c; +#endif + splx(s); + } + tp->t_col += c; + return (c ? -1 : '\t'); + } +#ifdef UCB_METER + tk_nout++; +#endif + /* + * turn to if desired. + */ + if (c == '\n' && tp->t_flags & CRMOD) { + if (putc('\r', &tp->t_outq)) + return(c); +#ifdef UCB_METER + tk_nout++; +#endif + } + if ((tp->t_flags & FLUSHO) == 0 && putc(c, &tp->t_outq)) + return (c); + + col = tp->t_col; + switch (partab[c] & 077) { + + case ORDINARY: + col++; + case CONTROL: + break; + case BACKSPACE: + if (col) + col--; + break; + case NEWLINE: + case RETURN: + col = 0; + break; + case TAB: + col = (col | 07) + 1; + break; + } + tp->t_col = col; + return(-1); +} + +/* + * Called from device's read routine after it has + * calculated the tty-structure given as argument. + */ +int +ttread (tp, uio, flag) + register struct tty *tp; + struct uio *uio; +{ + register struct clist *qp; + register int c; + long t_flags; + int s, first, error = 0, carrier; + +loop: + /* + * Take any pending input first. + */ + s = spltty(); + if (tp->t_flags & PENDIN) + ttypend(tp); + splx(s); + + /* + * Hang process if it's in the background. + */ + if (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) { + if ((u.u_procp->p_sigignore & sigmask(SIGTTIN)) || + (u.u_procp->p_sigmask & sigmask(SIGTTIN)) || + u.u_procp->p_flag & SVFORK) + return (EIO); + gsignal(u.u_procp->p_pgrp, SIGTTIN); + sleep((caddr_t)&lbolt, TTIPRI); + goto loop; + } + t_flags = tp->t_flags; + + /* + * In raw mode take characters directly from the + * raw queue w/o processing. Interlock against + * device interrupts when interrogating rawq. + */ + if (t_flags & RAW) { + s = spltty(); + if (tp->t_rawq.c_cc <= 0) { + carrier = ISSET(tp->t_state, TS_CARR_ON); + if (!carrier && ISSET(tp->t_state, TS_ISOPEN)) { + splx(s); + return(0); /* EOF */ + } + if (flag & IO_NDELAY) { + splx(s); + return(EWOULDBLOCK); + } + sleep((caddr_t)&tp->t_rawq, TTIPRI); + splx(s); + goto loop; + } + splx(s); + while (!error && tp->t_rawq.c_cc && uio->uio_resid) + error = ureadc(getc(&tp->t_rawq), uio); + goto checktandem; + } + + /* + * In cbreak mode use the rawq, otherwise + * take characters from the canonicalized q. + */ + qp = t_flags & CBREAK ? &tp->t_rawq : &tp->t_canq; + + /* + * No input, sleep on rawq awaiting hardware + * receipt and notification. + */ + s = spltty(); + if (qp->c_cc <= 0) { + carrier = ISSET(tp->t_state, TS_CARR_ON); + if (!carrier && ISSET(tp->t_state,TS_ISOPEN)) + { + splx(s); + return(0); /* EOF */ + } + if (flag & IO_NDELAY) + { + splx(s); + return(EWOULDBLOCK); + } + sleep((caddr_t)&tp->t_rawq, TTIPRI); + splx(s); + goto loop; + } + splx(s); + + /* + * Input present, perform input mapping + * and processing (we're not in raw mode). + */ + first = 1; + while ((c = getc(qp)) >= 0) { + if (t_flags & CRMOD && c == '\r') + c = '\n'; + /* + * Check for delayed suspend character. + */ + if (CCEQ(tp->t_dsuspc, c)) { + gsignal(tp->t_pgrp, SIGTSTP); + if (first) { + sleep((caddr_t)&lbolt, TTIPRI); + goto loop; + } + break; + } + /* + * Interpret EOF only in cooked mode. + */ + if (CCEQ(tp->t_eofc, c) && (t_flags & CBREAK) == 0) + break; + /* + * Give user character. + */ + error = ureadc(t_flags & PASS8 ? c : c & 0177, uio); + if (error) + break; + if (uio->uio_resid == 0) + break; + /* + * In cooked mode check for a "break character" + * marking the end of a "line of input". + */ + if ((t_flags & CBREAK) == 0 && ttbreakc (c, tp)) + break; + first = 0; + } + +checktandem: + /* + * Look to unblock output now that (presumably) + * the input queue has gone down. + */ + s = spltty(); + if (ISSET(tp->t_state,TS_TBLOCK) && tp->t_rawq.c_cc < TTYUNBLOCK) + ttyunblock(tp); + splx(s); + return(error); +} + +/* + * Check the output queue on tp for space for a kernel message + * (from uprintf/tprintf). Allow some space over the normal + * hiwater mark so we don't lose messages due to normal flow + * control, but don't let the tty run amok. + * Sleeps here are not interruptible, but we return prematurely + * if new signals come in. + */ +int +ttycheckoutq (tp, wait) + register struct tty *tp; + int wait; +{ + int hiwat, s, oldsig; + + hiwat = TTHIWAT(tp); + s = spltty(); + oldsig = u.u_procp->p_sig; + if (tp->t_outq.c_cc > hiwat + 200) + while (tp->t_outq.c_cc > hiwat) { + ttstart(tp); + if (wait == 0 || u.u_procp->p_sig != oldsig) { + splx(s); + return(0); + } + timeout (wakeup, (caddr_t)&tp->t_outq, hz); + tp->t_state |= TS_ASLEEP; + sleep ((caddr_t) &tp->t_outq, PZERO - 1); + } + splx(s); + return(1); +} + +/* + * Scan through str up to (but not including str[size]) stopping when a + * character who's entry in table has mask bits set. Return number of + * characters left in str. + */ +static int +scanc (size, str) + unsigned size; + const char *str; +{ + if (size == 0 || str == 0) + return 0; + do { + if (partab [(u_char) *str++] & 077) + return size; + } while (--size > 0); + return 0; +} + +/* + * Called from the device's write routine after it has + * calculated the tty-structure given as argument. + */ +int +ttwrite (tp, uio, flag) + register struct tty *tp; + register struct uio *uio; +{ + char *cp; + register int cc, ce; + int i, hiwat, cnt, error, s; + char obuf[OBUFSIZ]; + + hiwat = TTHIWAT(tp); + cnt = uio->uio_resid; + error = 0; + cc = 0; + cp = 0; +loop: + s = spltty(); + if (! (tp->t_state & TS_CARR_ON)) { + if (tp->t_state & TS_ISOPEN) { + splx(s); + return(EIO); + } else if (flag & IO_NDELAY) { + splx(s); + error = EWOULDBLOCK; + goto out; + } else { + /* Sleep awaiting carrier. */ + sleep((caddr_t)&tp->t_rawq, TTIPRI); + splx(s); + goto loop; + } + } + splx(s); + /* + * Hang the process if it's in the background. + */ + if (u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp && + (tp->t_flags & TOSTOP) && (u.u_procp->p_flag & SVFORK)==0 && + ! (u.u_procp->p_sigignore & sigmask(SIGTTOU)) && + ! (u.u_procp->p_sigmask & sigmask(SIGTTOU))) { + gsignal(u.u_procp->p_pgrp, SIGTTOU); + sleep((caddr_t)&lbolt, TTIPRI); + goto loop; + } + + /* + * Process the user's data in at most OBUFSIZ + * chunks. Perform lower case simulation and + * similar hacks. Keep track of high water + * mark, sleep on overflow awaiting device aid + * in acquiring new space. + */ + while (uio->uio_resid || cc > 0) { + if (tp->t_flags & FLUSHO) { + uio->uio_resid = 0; + return(0); + } + if (tp->t_outq.c_cc > hiwat) + goto ovhiwat; + /* + * Grab a hunk of data from the user, unless we have some + * leftover from last time. + */ + if (cc == 0) { + cc = MIN(uio->uio_resid, OBUFSIZ); + cp = obuf; + error = uiomove(cp, cc, uio); + if (error) { + cc = 0; + break; + } + } + /* + * If nothing fancy need be done, grab those characters we + * can handle without any of ttyoutput's processing and + * just transfer them to the output q. For those chars + * which require special processing (as indicated by the + * bits in partab), call ttyoutput. After processing + * a hunk of data, look for FLUSHO so ^O's will take effect + * immediately. + */ + while (cc > 0) { + if (tp->t_flags & (RAW|LITOUT)) + ce = cc; + else { + ce = cc - scanc((unsigned)cc, (caddr_t)cp); + /* + * If ce is zero, then we're processing + * a special character through ttyoutput. + */ + if (ce == 0) { + tp->t_rocount = 0; + if (ttyoutput(*cp, tp) >= 0) { + /* no c-lists, wait a bit */ + ttstart(tp); + sleep((caddr_t)&lbolt, TTOPRI); + goto loop; + } + cp++, cc--; + if (tp->t_flags & FLUSHO || + tp->t_outq.c_cc > hiwat) + goto ovhiwat; + continue; + } + } + /* + * A bunch of normal characters have been found, + * transfer them en masse to the output queue and + * continue processing at the top of the loop. + * If there are any further characters in this + * <= OBUFSIZ chunk, the first should be a character + * requiring special handling by ttyoutput. + */ + tp->t_rocount = 0; + i = b_to_q(cp, ce, &tp->t_outq); + ce -= i; + tp->t_col += ce; + cp += ce, cc -= ce; +#ifdef UCB_METER + tk_nout += ce; +#endif + if (i > 0) { + /* out of c-lists, wait a bit */ + ttstart(tp); + sleep((caddr_t)&lbolt, TTOPRI); + goto loop; + } + if (tp->t_flags & FLUSHO || tp->t_outq.c_cc > hiwat) + break; + } /* while (cc > 0) */ + ttstart(tp); + } /* while (uio->uio_resid || cc > 0) */ +out: + /* + * If cc is nonzero, we leave the uio structure inconsistent, as the + * offset and iov pointers have moved forward, but it doesn't matter + * (the call will either return short or restart with a new uio). + */ + uio->uio_resid += cc; + return (error); + +ovhiwat: + s = spltty(); + /* + * This can only occur if FLUSHO is also set in t_flags, + * or if ttstart/oproc is synchronous (or very fast). + */ + if (tp->t_outq.c_cc <= hiwat) { + splx(s); + goto loop; + } + ttstart(tp); + if (flag & IO_NDELAY) { + splx(s); + uio->uio_resid += cc; + return (uio->uio_resid == cnt ? EWOULDBLOCK : 0); + } + tp->t_state |= TS_ASLEEP; + sleep((caddr_t)&tp->t_outq, TTOPRI); + splx(s); + goto loop; +} + +void +ttwakeup (tp) + register struct tty *tp; +{ + if (tp->t_rsel) { + selwakeup (tp->t_rsel, tp->t_state & TS_RCOLL); + tp->t_state &= ~TS_RCOLL; + tp->t_rsel = 0; + } + if (tp->t_state & TS_ASYNC) + gsignal (tp->t_pgrp, SIGIO); + wakeup ((caddr_t) &tp->t_rawq); +} diff --git a/sys/kernel/tty_pty.c b/sys/kernel/tty_pty.c new file mode 100644 index 0000000..3c6f911 --- /dev/null +++ b/sys/kernel/tty_pty.c @@ -0,0 +1,520 @@ +/* + * Pseudo-teletype Driver + * (Actually two drivers, requiring two entries in 'cdevsw') + * + * Copyright (c) 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "pty.h" + +#if NPTY > 0 +#include "param.h" +#include "systm.h" +#include "ioctl.h" +#include "tty.h" +#include "user.h" +#include "conf.h" +#include "file.h" +#include "proc.h" +#include "uio.h" +#include "kernel.h" +#include "inode.h" +#include "types.h" +#include "ttydev.h" + +const struct devspec ptsdevs[] = { + { 0, "ttyp0" }, { 1, "ttyp1" }, { 2, "ttyp2" }, { 3, "ttyp3" }, + { 0, 0 } +}; + +const struct devspec ptcdevs[] = { + { 0, "ptyp0" }, { 1, "ptyp1" }, { 2, "ptyp2" }, { 3, "ptyp3" }, + { 0, 0 } +}; + +extern int TTYHOG; /* see tty.c */ + +#define BUFSIZ 100 /* Chunk size iomoved to/from user */ + +/* + * pts == /dev/tty[pqrs]? + * ptc == /dev/pty[pqrs]? + */ +struct tty pt_tty[NPTY]; +struct pt_ioctl { + int pt_flags; + struct proc *pt_selr, *pt_selw; + u_char pt_send; + u_char pt_ucntl; +} pt_ioctl[NPTY]; +int npty = NPTY; /* for pstat -t */ + +#define PF_RCOLL 0x01 +#define PF_WCOLL 0x02 +#define PF_PKT 0x08 /* packet mode */ +#define PF_STOPPED 0x10 /* user told stopped */ +#define PF_REMOTE 0x20 /* remote and flow controlled input */ +#define PF_NOSTOP 0x40 +#define PF_UCNTL 0x80 /* user control mode */ + +/*ARGSUSED*/ +int ptsopen(dev_t dev, int flag, int mode) +{ + register struct tty *tp; + int error; + +#ifdef lint + npty = npty; +#endif + if (minor(dev) >= NPTY) + return (ENXIO); + tp = &pt_tty[minor(dev)]; + if ((tp->t_state & TS_ISOPEN) == 0) { + ttychars(tp); /* Set up default chars */ + tp->t_ispeed = tp->t_ospeed = B115200; + tp->t_flags = 0; /* No features (nor raw mode) */ + } else if (tp->t_state&TS_XCLUDE && u.u_uid != 0) + return (EBUSY); + if (tp->t_oproc) /* Ctrlr still around. */ + tp->t_state |= TS_CARR_ON; + while ((tp->t_state & TS_CARR_ON) == 0) { + tp->t_state |= TS_WOPEN; + sleep((caddr_t)&tp->t_rawq, TTIPRI); + } + error = ttyopen(dev, tp); + ptcwakeup (tp, FREAD | FWRITE); + return (error); +} + +int ptsclose(dev_t dev, int flag, int mode) +{ + register struct tty *tp; + + tp = &pt_tty[minor(dev)]; + ttyclose(tp); + ptcwakeup(tp, FREAD|FWRITE); + return 0; +} + +int ptsread(dev_t dev, register struct uio *uio, int flag) +{ + register struct tty *tp = &pt_tty[minor(dev)]; + register struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; + int error = 0; + +again: + if (pti->pt_flags & PF_REMOTE) { + while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) { + if ((u.u_procp->p_sigignore & sigmask(SIGTTIN)) || + (u.u_procp->p_sigmask & sigmask(SIGTTIN)) || + u.u_procp->p_flag&SVFORK) + return (EIO); + gsignal(u.u_procp->p_pgrp, SIGTTIN); + sleep((caddr_t)&lbolt, TTIPRI); + } + if (tp->t_canq.c_cc == 0) { + if (flag & IO_NDELAY) + return (EWOULDBLOCK); + sleep((caddr_t)&tp->t_canq, TTIPRI); + goto again; + } + while (tp->t_canq.c_cc > 1 && uio->uio_resid) + if (ureadc(getc(&tp->t_canq), uio) < 0) { + error = EFAULT; + break; + } + if (tp->t_canq.c_cc == 1) + (void) getc(&tp->t_canq); + if (tp->t_canq.c_cc) + return (error); + } else + if (tp->t_oproc) + error = ttread(tp, uio, flag); + ptcwakeup(tp, FWRITE); + return (error); +} + +/* + * Write to pseudo-tty. + * Wakeups of controlling tty will happen + * indirectly, when tty driver calls ptsstart. + */ +int ptswrite(dev_t dev, register struct uio *uio, int flag) +{ + register struct tty *tp; + + tp = &pt_tty[minor(dev)]; + if (tp->t_oproc == 0) + return (EIO); + return ttwrite(tp, uio, flag); +} + +/* + * Start output on pseudo-tty. + * Wake up process selecting or sleeping for input from controlling tty. + */ +void ptsstart(struct tty *tp) +{ + register struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; + + if (tp->t_state & TS_TTSTOP) + return; + if (pti->pt_flags & PF_STOPPED) { + pti->pt_flags &= ~PF_STOPPED; + pti->pt_send = TIOCPKT_START; + } + ptcwakeup(tp, FREAD); +} + +void ptcwakeup(struct tty *tp, int flag) +{ + struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; + + if (flag & FREAD) { + if (pti->pt_selr) { + selwakeup(pti->pt_selr, (long)(pti->pt_flags & PF_RCOLL)); + pti->pt_selr = 0; + pti->pt_flags &= ~PF_RCOLL; + } + wakeup((caddr_t)&tp->t_outq.c_cf); + } + if (flag & FWRITE) { + if (pti->pt_selw) { + selwakeup(pti->pt_selw, (long)(pti->pt_flags & PF_WCOLL)); + pti->pt_selw = 0; + pti->pt_flags &= ~PF_WCOLL; + } + wakeup((caddr_t)&tp->t_rawq.c_cf); + } +} + +/*ARGSUSED*/ +int ptcopen(dev_t dev, int flag, int mode) +{ + register struct tty *tp; + struct pt_ioctl *pti; + + if (minor(dev) >= NPTY) + return (ENXIO); + tp = &pt_tty[minor(dev)]; + if (tp->t_oproc) + return (EIO); + tp->t_oproc = ptsstart; + ttymodem(tp, 1); + pti = &pt_ioctl[minor(dev)]; + pti->pt_flags = 0; + pti->pt_send = 0; + pti->pt_ucntl = 0; + return (0); +} + +int ptcclose(dev_t dev, int flag, int mode) +{ + register struct tty *tp; + + tp = &pt_tty[minor(dev)]; + ttymodem(tp, 0); + tp->t_state &= ~TS_CARR_ON; + tp->t_oproc = 0; /* mark closed */ + return 0; +} + +int ptcread(dev_t dev, register struct uio *uio, int flag) +{ + register struct tty *tp = &pt_tty[minor(dev)]; + struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; + char buf[BUFSIZ]; + int error = 0, cc; + + /* + * We want to block until the slave + * is open, and there's something to read; + * but if we lost the slave or we're NBIO, + * then return the appropriate error instead. + */ + for (;;) { + if (tp->t_state&TS_ISOPEN) { + if (pti->pt_flags&PF_PKT && pti->pt_send) { + error = ureadc((int)pti->pt_send, uio); + if (error) + return (error); + pti->pt_send = 0; + return (0); + } + if (pti->pt_flags&PF_UCNTL && pti->pt_ucntl) { + error = ureadc((int)pti->pt_ucntl, uio); + if (error) + return (error); + pti->pt_ucntl = 0; + return (0); + } + if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) + break; + } + if ((tp->t_state&TS_CARR_ON) == 0) + return (0); /* EOF */ + if (flag & IO_NDELAY) + return (EWOULDBLOCK); + sleep((caddr_t)&tp->t_outq.c_cf, TTIPRI); + } + if (pti->pt_flags & (PF_PKT|PF_UCNTL)) + error = ureadc(0, uio); + while (uio->uio_resid && error == 0) { + cc = q_to_b(&tp->t_outq, buf, MIN(uio->uio_resid, BUFSIZ)); + if (cc <= 0) + break; + error = uiomove(buf, cc, uio); + } + if (tp->t_outq.c_cc <= TTLOWAT(tp)) { + if (tp->t_state&TS_ASLEEP) { + tp->t_state &= ~TS_ASLEEP; + wakeup((caddr_t)&tp->t_outq); + } + if (tp->t_wsel) { + selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); + tp->t_wsel = 0; + tp->t_state &= ~TS_WCOLL; + } + } + return (error); +} + +void ptsstop(register struct tty *tp, int flush) +{ + struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; + int flag; + + /* note: FLUSHREAD and FLUSHWRITE already ok */ + if (flush == 0) { + flush = TIOCPKT_STOP; + pti->pt_flags |= PF_STOPPED; + } else + pti->pt_flags &= ~PF_STOPPED; + pti->pt_send |= flush; + /* change of perspective */ + flag = 0; + if (flush & FREAD) + flag |= FWRITE; + if (flush & FWRITE) + flag |= FREAD; + ptcwakeup(tp, flag); +} + +int ptcselect(dev_t dev, int rw) +{ + register struct tty *tp = &pt_tty[minor(dev)]; + struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; + struct proc *p; + int s; + + if ((tp->t_state&TS_CARR_ON) == 0) + return (1); + switch (rw) { + + case FREAD: + /* + * Need to block timeouts (ttrstart). + */ + s = spltty(); + if ((tp->t_state&TS_ISOPEN) && + tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) { + splx(s); + return (1); + } + splx(s); + /* FALLTHROUGH */ + + case 0: /* exceptional */ + if ((tp->t_state&TS_ISOPEN) && + ((pti->pt_flags&PF_PKT && pti->pt_send) || + (pti->pt_flags&PF_UCNTL && pti->pt_ucntl))) + return (1); + if ((p = pti->pt_selr) && p->p_wchan == (caddr_t)&selwait) + pti->pt_flags |= PF_RCOLL; + else + pti->pt_selr = u.u_procp; + break; + + + case FWRITE: + if (tp->t_state&TS_ISOPEN) { + if (pti->pt_flags & PF_REMOTE) { + if (tp->t_canq.c_cc == 0) + return (1); + } else { + if (tp->t_rawq.c_cc + tp->t_canq.c_cc < TTYHOG-2) + return (1); + if (tp->t_canq.c_cc == 0 && + (tp->t_flags & (RAW|CBREAK)) == 0) + return (1); + } + } + if ((p = pti->pt_selw) && p->p_wchan == (caddr_t)&selwait) + pti->pt_flags |= PF_WCOLL; + else + pti->pt_selw = u.u_procp; + break; + + } + return (0); +} + +int ptcwrite(dev_t dev, register struct uio *uio, int flag) +{ + register struct tty *tp = &pt_tty[minor(dev)]; + register char *cp = NULL; + register int cc = 0; + char locbuf[BUFSIZ]; + int cnt = 0; + struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; + int error = 0; + +again: + if ((tp->t_state&TS_ISOPEN) == 0) + goto block; + if (pti->pt_flags & PF_REMOTE) { + if (tp->t_canq.c_cc) + goto block; + while (uio->uio_resid && tp->t_canq.c_cc < TTYHOG - 1) { + if (cc == 0) { + cc = MIN(uio->uio_resid, BUFSIZ); + cc = MIN(cc, TTYHOG - 1 - tp->t_canq.c_cc); + cp = locbuf; + error = uiomove(cp, cc, uio); + if (error) + return (error); + /* check again for safety */ + if ((tp->t_state&TS_ISOPEN) == 0) + return (EIO); + } + if (cc) + (void) b_to_q(cp, cc, &tp->t_canq); + cc = 0; + } + (void) putc(0, &tp->t_canq); + ttwakeup(tp); + wakeup((caddr_t)&tp->t_canq); + return (0); + } + while (uio->uio_resid > 0) { + if (cc == 0) { + cc = MIN(uio->uio_resid, BUFSIZ); + cp = locbuf; + error = uiomove(cp, cc, uio); + if (error) + return (error); + /* check again for safety */ + if ((tp->t_state&TS_ISOPEN) == 0) + return (EIO); + } + while (cc > 0) { + if ((tp->t_rawq.c_cc + tp->t_canq.c_cc) >= TTYHOG - 2 && + (tp->t_canq.c_cc > 0 || + tp->t_flags & (RAW|CBREAK))) { + wakeup((caddr_t)&tp->t_rawq); + goto block; + } + ttyinput(*cp++, tp); + cnt++; + cc--; + } + cc = 0; + } + return (0); +block: + /* + * Come here to wait for slave to open, for space + * in outq, or space in rawq. + */ + if ((tp->t_state&TS_CARR_ON) == 0) + return (EIO); + if (flag & IO_NDELAY) { + /* adjust for data copied in but not written */ + uio->uio_resid += cc; + if (cnt == 0) + return (EWOULDBLOCK); + return (0); + } + sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI); + goto again; +} + +int ptyioctl(dev_t dev, u_int cmd, caddr_t data, int flag) +{ + register struct tty *tp = &pt_tty[minor(dev)]; + register struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; + int stop, error; + + /* + * IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG. + * ttywflush(tp) will hang if there are characters in the outq. + */ + if (cdevsw[major(dev)].d_open == ptcopen) + switch (cmd) { + + case TIOCPKT: + if (*(int *)data) { + if (pti->pt_flags & PF_UCNTL) + return (EINVAL); + pti->pt_flags |= PF_PKT; + } else + pti->pt_flags &= ~PF_PKT; + return (0); + + case TIOCUCNTL: + if (*(int *)data) { + if (pti->pt_flags & PF_PKT) + return (EINVAL); + pti->pt_flags |= PF_UCNTL; + } else + pti->pt_flags &= ~PF_UCNTL; + return (0); + + case TIOCREMOTE: + if (*(int *)data) + pti->pt_flags |= PF_REMOTE; + else + pti->pt_flags &= ~PF_REMOTE; + ttyflush(tp, FREAD|FWRITE); + return (0); + + case TIOCSETP: + case TIOCSETN: + case TIOCSETD: + while (getc(&tp->t_outq) >= 0) + ; + break; + } + error = ttioctl (tp, cmd, data, flag); + if (error < 0) { + if (pti->pt_flags & PF_UCNTL && + (cmd & ~0xff) == UIOCCMD(0)) { + if (cmd & 0xff) { + pti->pt_ucntl = (u_char)cmd; + ptcwakeup(tp, FREAD); + } + return (0); + } + error = ENOTTY; + } + stop = (tp->t_flags & RAW) == 0 && + tp->t_stopc == CTRL('s') && tp->t_startc == CTRL('q'); + if (pti->pt_flags & PF_NOSTOP) { + if (stop) { + pti->pt_send &= ~TIOCPKT_NOSTOP; + pti->pt_send |= TIOCPKT_DOSTOP; + pti->pt_flags &= ~PF_NOSTOP; + ptcwakeup(tp, FREAD); + } + } else { + if (!stop) { + pti->pt_send &= ~TIOCPKT_DOSTOP; + pti->pt_send |= TIOCPKT_NOSTOP; + pti->pt_flags |= PF_NOSTOP; + ptcwakeup(tp, FREAD); + } + } + return (error); +} +#endif diff --git a/sys/kernel/tty_subr.c b/sys/kernel/tty_subr.c new file mode 100644 index 0000000..4344544 --- /dev/null +++ b/sys/kernel/tty_subr.c @@ -0,0 +1,406 @@ +/* + * Copyright (c) 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "param.h" +#include "clist.h" +#include "ioctl.h" +#include "tty.h" +#include "systm.h" + +char cwaiting; + +/* + * Character list get/put + */ +int +getc(p) + register struct clist *p; +{ + register struct cblock *bp; + register int c, s; + + s = spltty(); + if (p->c_cc <= 0) { + c = -1; + p->c_cc = 0; + p->c_cf = p->c_cl = NULL; + } else { + c = *p->c_cf++ & 0377; + if (--p->c_cc<=0) { + bp = (struct cblock *)(p->c_cf-1); + bp = (struct cblock *)((int)bp & ~CROUND); + p->c_cf = NULL; + p->c_cl = NULL; + bp->c_next = cfreelist; + cfreelist = bp; + cfreecount += CBSIZE; + if (cwaiting) { + wakeup (&cwaiting); + cwaiting = 0; + } + } else if (((int)p->c_cf & CROUND) == 0){ + bp = (struct cblock *)(p->c_cf); + bp--; + p->c_cf = bp->c_next->c_info; + bp->c_next = cfreelist; + cfreelist = bp; + cfreecount += CBSIZE; + if (cwaiting) { + wakeup (&cwaiting); + cwaiting = 0; + } + } + } + splx(s); + return (c); +} + +/* + * Copy clist to buffer. + * Return number of bytes moved. + */ +int +q_to_b (q, cp, cc) + register struct clist *q; + char *cp; +{ + register struct cblock *bp; + register int nc; + int s; + char *acp; + + if (cc <= 0) + return (0); + s = spltty(); + if (q->c_cc <= 0) { + q->c_cc = 0; + q->c_cf = q->c_cl = NULL; + splx(s); + return (0); + } + acp = cp; + + while (cc) { + nc = sizeof (struct cblock) - ((int)q->c_cf & CROUND); + nc = MIN(nc, cc); + nc = MIN(nc, q->c_cc); + (void) bcopy(q->c_cf, cp, (unsigned)nc); + q->c_cf += nc; + q->c_cc -= nc; + cc -= nc; + cp += nc; + if (q->c_cc <= 0) { + bp = (struct cblock *)(q->c_cf - 1); + bp = (struct cblock *)((int)bp & ~CROUND); + q->c_cf = q->c_cl = NULL; + bp->c_next = cfreelist; + cfreelist = bp; + cfreecount += CBSIZE; + if (cwaiting) { + wakeup (&cwaiting); + cwaiting = 0; + } + break; + } + if (((int)q->c_cf & CROUND) == 0) { + bp = (struct cblock *)(q->c_cf); + bp--; + q->c_cf = bp->c_next->c_info; + bp->c_next = cfreelist; + cfreelist = bp; + cfreecount += CBSIZE; + if (cwaiting) { + wakeup (&cwaiting); + cwaiting = 0; + } + } + } + splx(s); + return (cp - acp); +} + +/* + * Return count of contiguous characters + * in clist starting at q->c_cf. + * Stop counting if flag&character is non-null. + */ +int ndqb (q, flag) + register struct clist *q; +{ + int cc; + int s; + + s = spltty(); + if (q->c_cc <= 0) { + cc = -q->c_cc; + goto out; + } + cc = ((int)q->c_cf + CBSIZE) & ~CROUND; + cc -= (int)q->c_cf; + if (q->c_cc < cc) + cc = q->c_cc; + if (flag) { + register char *p, *end; + + p = q->c_cf; + end = p; + end += cc; + while (p < end) { + if (*p & flag) { + cc = (int)p; + cc -= (int)q->c_cf; + break; + } + p++; + } + } +out: + splx(s); + return (cc); +} + +/* + * Flush cc bytes from q. + */ +void +ndflush (q, cc) + register struct clist *q; + register int cc; +{ + register struct cblock *bp; + char *end; + int rem, s; + + s = spltty(); + if (q->c_cc <= 0) + goto out; + while (cc>0 && q->c_cc) { + bp = (struct cblock *)((int)q->c_cf & ~CROUND); + if ((int)bp == (((int)q->c_cl-1) & ~CROUND)) { + end = q->c_cl; + } else { + end = (char *)((int)bp + sizeof (struct cblock)); + } + rem = end - q->c_cf; + if (cc >= rem) { + cc -= rem; + q->c_cc -= rem; + q->c_cf = bp->c_next->c_info; + bp->c_next = cfreelist; + cfreelist = bp; + cfreecount += CBSIZE; + if (cwaiting) { + wakeup (&cwaiting); + cwaiting = 0; + } + } else { + q->c_cc -= cc; + q->c_cf += cc; + if (q->c_cc <= 0) { + bp->c_next = cfreelist; + cfreelist = bp; + cfreecount += CBSIZE; + if (cwaiting) { + wakeup (&cwaiting); + cwaiting = 0; + } + } + break; + } + } + if (q->c_cc <= 0) { + q->c_cf = q->c_cl = NULL; + q->c_cc = 0; + } +out: + splx(s); +} + +/* + * Put a symbol to a character list. + */ +int +putc (c, p) + register struct clist *p; +{ + register struct cblock *bp; + register char *cp; + register int s; + + s = spltty(); + if ((cp = p->c_cl) == NULL || p->c_cc < 0 ) { + if ((bp = cfreelist) == NULL) { + splx(s); + return (-1); + } + cfreelist = bp->c_next; + cfreecount -= CBSIZE; + bp->c_next = NULL; + p->c_cf = cp = bp->c_info; + } else if (((int)cp & CROUND) == 0) { + bp = (struct cblock *)cp - 1; + if ((bp->c_next = cfreelist) == NULL) { + splx(s); + return (-1); + } + bp = bp->c_next; + cfreelist = bp->c_next; + cfreecount -= CBSIZE; + bp->c_next = NULL; + cp = bp->c_info; + } + *cp++ = c; + p->c_cc++; + p->c_cl = cp; + splx(s); + return (0); +} + +/* + * Copy buffer to clist. + * Return number of bytes not transfered. + */ +int +b_to_q (cp, cc, q) + register char *cp; + struct clist *q; + register int cc; +{ + register char *cq; + register struct cblock *bp; + register int s, nc; + int acc; + + if (cc <= 0) + return (0); + acc = cc; + s = spltty(); + if ((cq = q->c_cl) == NULL || q->c_cc < 0) { + if ((bp = cfreelist) == NULL) + goto out; + cfreelist = bp->c_next; + cfreecount -= CBSIZE; + bp->c_next = NULL; + q->c_cf = cq = bp->c_info; + } + + while (cc) { + if (((int)cq & CROUND) == 0) { + bp = (struct cblock *)cq - 1; + if ((bp->c_next = cfreelist) == NULL) + goto out; + bp = bp->c_next; + cfreelist = bp->c_next; + cfreecount -= CBSIZE; + bp->c_next = NULL; + cq = bp->c_info; + } + nc = MIN(cc, sizeof (struct cblock) - ((int)cq & CROUND)); + (void) bcopy(cp, cq, (unsigned)nc); + cp += nc; + cq += nc; + cc -= nc; + } +out: + q->c_cl = cq; + q->c_cc += acc - cc; + splx(s); + return (cc); +} + +/* + * Given a non-NULL pointter into the list (like c_cf which + * always points to a real character if non-NULL) return the pointer + * to the next character in the list or return NULL if no more chars. + * + * Callers must not allow getc's to happen between nextc's so that the + * pointer becomes invalid. Note that interrupts are NOT masked. + */ +char * +nextc (p, cp) + register struct clist *p; + register char *cp; +{ + register char *rcp; + + if (p->c_cc && ++cp != p->c_cl) { + if (((int)cp & CROUND) == 0) + rcp = ((struct cblock *)cp)[-1].c_next->c_info; + else + rcp = cp; + } else + rcp = (char *)NULL; + return (rcp); +} + +/* + * Remove the last character in the list and return it. + */ +int +unputc (p) + register struct clist *p; +{ + register struct cblock *bp; + register int c, s; + struct cblock *obp; + + s = spltty(); + if (p->c_cc <= 0) + c = -1; + else { + c = *--p->c_cl; + if (--p->c_cc <= 0) { + bp = (struct cblock *)p->c_cl; + bp = (struct cblock *)((int)bp & ~CROUND); + p->c_cl = p->c_cf = NULL; + bp->c_next = cfreelist; + cfreelist = bp; + cfreecount += CBSIZE; + } else if (((int)p->c_cl & CROUND) == sizeof(bp->c_next)) { + p->c_cl = (char *)((int)p->c_cl & ~CROUND); + bp = (struct cblock *)p->c_cf; + bp = (struct cblock *)((int)bp & ~CROUND); + while (bp->c_next != (struct cblock *)p->c_cl) + bp = bp->c_next; + obp = bp; + p->c_cl = (char *)(bp + 1); + bp = bp->c_next; + bp->c_next = cfreelist; + cfreelist = bp; + cfreecount += CBSIZE; + obp->c_next = NULL; + } + } + splx(s); + return (c); +} + +/* + * Put the chars in the from que + * on the end of the to que. + */ +void +catq (from, to) + register struct clist *from, *to; +{ + char bbuf [CBSIZE*4]; + register int c; + int s; + + s = spltty(); + if (to->c_cc == 0) { + *to = *from; + from->c_cc = 0; + from->c_cf = NULL; + from->c_cl = NULL; + splx(s); + return; + } + splx(s); + while (from->c_cc > 0) { + c = q_to_b(from, bbuf, sizeof bbuf); + (void) b_to_q(bbuf, c, to); + } +} diff --git a/sys/kernel/tty_tty.c b/sys/kernel/tty_tty.c new file mode 100644 index 0000000..9951ac2 --- /dev/null +++ b/sys/kernel/tty_tty.c @@ -0,0 +1,90 @@ +/* + * Copyright (c) 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + * + * @(#)tty_tty.c 1.2 (2.11BSD GTE) 11/29/94 + */ + +/* + * Indirect driver for controlling tty. + * + */ +#include "param.h" +#include "user.h" +#include "proc.h" +#include "ioctl.h" +#include "tty.h" +#include "conf.h" + +const struct devspec sydevs[] = { + { 0, "tty" }, + { 0, 0 } +}; + +/*ARGSUSED*/ +int +syopen (dev, flag) + dev_t dev; + int flag; +{ + if (u.u_ttyp == NULL) + return (ENXIO); + return((*cdevsw[major(u.u_ttyd)].d_open)(u.u_ttyd, flag, 0)); +} + +/*ARGSUSED*/ +int +syread (dev, uio, flag) + dev_t dev; + struct uio *uio; + int flag; +{ + if (u.u_ttyp == NULL) + return (ENXIO); + return ((*cdevsw[major(u.u_ttyd)].d_read)(u.u_ttyd, uio, flag)); +} + +/*ARGSUSED*/ +int +sywrite (dev, uio, flag) + dev_t dev; + struct uio *uio; +{ + if (u.u_ttyp == NULL) + return (ENXIO); + return ((*cdevsw[major(u.u_ttyd)].d_write)(u.u_ttyd, uio, flag)); +} + +/*ARGSUSED*/ +int +syioctl (dev, cmd, addr, flag) + dev_t dev; + u_int cmd; + caddr_t addr; + int flag; +{ + if (cmd == TIOCNOTTY) { + u.u_ttyp = 0; + u.u_ttyd = 0; + u.u_procp->p_pgrp = 0; + return (0); + } + if (u.u_ttyp == NULL) + return (ENXIO); + return ((*cdevsw[major(u.u_ttyd)].d_ioctl)(u.u_ttyd, cmd, addr, flag)); +} + +/*ARGSUSED*/ +int +syselect (dev, flag) + dev_t dev; + int flag; +{ + + if (u.u_ttyp == NULL) { + u.u_error = ENXIO; + return (0); + } + return ((*cdevsw[major(u.u_ttyd)].d_select)(u.u_ttyd, flag)); +} diff --git a/sys/kernel/ufs_alloc.c b/sys/kernel/ufs_alloc.c new file mode 100644 index 0000000..439d9c3 --- /dev/null +++ b/sys/kernel/ufs_alloc.c @@ -0,0 +1,302 @@ +/* + * Copyright (c) 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "param.h" +#include "fs.h" +#include "dir.h" +#include "inode.h" +#include "buf.h" +#include "user.h" +#include "kernel.h" +#include "mount.h" +#include "proc.h" +#include "systm.h" + +typedef struct fblk *FBLKP; + +/* + * Allocate a block in the file system. + * + * alloc will obtain the next available free disk block from the + * free list of the specified device. The super block has up to + * NICFREE remembered free blocks; the last of these is read to + * obtain NICFREE more... + */ +struct buf * +balloc(ip, flags) + struct inode *ip; + int flags; +{ + register struct fs *fs; + register struct buf *bp; + int async; + daddr_t bno; + + fs = ip->i_fs; + async = fs->fs_flags & MNT_ASYNC; + + while (fs->fs_flock) + sleep((caddr_t)&fs->fs_flock, PINOD); + do { + if (fs->fs_nfree <= 0) + goto nospace; + if (fs->fs_nfree > NICFREE) { + fserr (fs, "bad free count"); + goto nospace; + } + bno = fs->fs_free[--fs->fs_nfree]; + if (bno == 0) + goto nospace; + } while (badblock(fs, bno)); + if (fs->fs_nfree <= 0) { + fs->fs_flock++; + bp = bread(ip->i_dev, bno); + if (((bp->b_flags&B_ERROR) == 0) && (bp->b_resid==0)) { + register struct fblk *fbp; + + fbp = (FBLKP) bp->b_addr; + *((FBLKP)&fs->fs_nfree) = *fbp; + } + brelse(bp); + /* + * Write the superblock back, synchronously if requested, + * so that the free list pointer won't point at garbage. + * We can still end up with dups in free if we then + * use some of the blocks in this freeblock, then crash + * without a sync. + */ + bp = getblk(ip->i_dev, SUPERB); + fs->fs_fmod = 0; + fs->fs_time = time.tv_sec; + { + register struct fs *fps; + + fps = (struct fs*) bp->b_addr; + *fps = *fs; + } + if (!async) + bwrite(bp); + else + bdwrite(bp); + fs->fs_flock = 0; + wakeup((caddr_t)&fs->fs_flock); + if (fs->fs_nfree <=0) + goto nospace; + } + bp = getblk(ip->i_dev, bno); + bp->b_resid = 0; + if (flags & B_CLRBUF) + bzero (bp->b_addr, MAXBSIZE); + fs->fs_fmod = 1; + fs->fs_tfree--; + return(bp); + +nospace: + fs->fs_nfree = 0; + fs->fs_tfree = 0; + fserr (fs, "file system full"); + /* + * THIS IS A KLUDGE... + * SHOULD RATHER SEND A SIGNAL AND SUSPEND THE PROCESS IN A + * STATE FROM WHICH THE SYSTEM CALL WILL RESTART + */ + uprintf("\n%s: write failed, file system full\n", fs->fs_fsmnt); + { + register int i; + + for (i = 0; i < 5; i++) + sleep((caddr_t)&lbolt, PRIBIO); + } + u.u_error = ENOSPC; + return(NULL); +} + +/* + * Allocate an inode in the file system. + * + * Allocate an unused I node on the specified device. Used with file + * creation. The algorithm keeps up to NICINOD spare I nodes in the + * super block. When this runs out, a linear search through the I list + * is instituted to pick up NICINOD more. + */ +struct inode * +ialloc (pip) + struct inode *pip; +{ + register struct fs *fs; + register struct buf *bp; + register struct inode *ip; + int i; + struct dinode *dp; + ino_t ino; + daddr_t adr; + ino_t inobas; + int first; + struct inode *ifind(); + char *emsg = "no inodes free"; + + fs = pip->i_fs; + while (fs->fs_ilock) + sleep((caddr_t)&fs->fs_ilock, PINOD); +loop: + if (fs->fs_ninode > 0) { + ino = fs->fs_inode[--fs->fs_ninode]; + if (ino <= ROOTINO) + goto loop; + ip = iget(pip->i_dev, fs, ino); + if (ip == NULL) + return(NULL); + if (ip->i_mode == 0) { + bzero((caddr_t)ip->i_addr,sizeof(ip->i_addr)); + ip->i_flags = 0; + fs->fs_fmod = 1; + fs->fs_tinode--; + return(ip); + } + /* + * Inode was allocated after all. + * Look some more. + */ + iput(ip); + goto loop; + } + fs->fs_ilock++; + if (fs->fs_nbehind < 4 * NICINOD) { + first = 1; + ino = fs->fs_lasti; +#ifdef DIAGNOSTIC + if (itoo(ino)) + panic("ialloc"); +#endif + adr = itod(ino); + } else { +fromtop: + first = 0; + ino = 1; + adr = SUPERB+1; + fs->fs_nbehind = 0; + } + inobas = 0; + for (; adr < fs->fs_isize; adr++) { + inobas = ino; + bp = bread(pip->i_dev, adr); + if ((bp->b_flags & B_ERROR) || bp->b_resid) { + brelse(bp); + ino += INOPB; + continue; + } + dp = (struct dinode*) bp->b_addr; + for (i = 0;i < INOPB;i++) { + if (dp->di_mode != 0) + goto cont; + if (ifind(pip->i_dev, ino)) + goto cont; + fs->fs_inode[fs->fs_ninode++] = ino; + if (fs->fs_ninode >= NICINOD) + break; + cont: + ino++; + dp++; + } + brelse(bp); + if (fs->fs_ninode >= NICINOD) + break; + } + if (fs->fs_ninode < NICINOD && first) + goto fromtop; + fs->fs_lasti = inobas; + fs->fs_ilock = 0; + wakeup((caddr_t)&fs->fs_ilock); + if (fs->fs_ninode > 0) + goto loop; + fserr (fs, emsg); + uprintf("\n%s: %s\n", fs->fs_fsmnt, emsg); + u.u_error = ENOSPC; + return(NULL); +} + +/* + * Free a block or fragment. + * + * Place the specified disk block back on the free list of the + * specified device. + */ +void +free (ip, bno) + struct inode *ip; + daddr_t bno; +{ + register struct fs *fs; + register struct buf *bp; + struct fblk *fbp; + + fs = ip->i_fs; + if (badblock (fs, bno)) { + printf("bad block %D, ino %d\n", bno, ip->i_number); + return; + } + while (fs->fs_flock) + sleep((caddr_t)&fs->fs_flock, PINOD); + if (fs->fs_nfree <= 0) { + fs->fs_nfree = 1; + fs->fs_free[0] = 0; + } + if (fs->fs_nfree >= NICFREE) { + fs->fs_flock++; + bp = getblk(ip->i_dev, bno); + fbp = (FBLKP) bp->b_addr; + *fbp = *((FBLKP)&fs->fs_nfree); + fs->fs_nfree = 0; + if (fs->fs_flags & MNT_ASYNC) + bdwrite(bp); + else + bwrite(bp); + fs->fs_flock = 0; + wakeup((caddr_t)&fs->fs_flock); + } + fs->fs_free[fs->fs_nfree++] = bno; + fs->fs_tfree++; + fs->fs_fmod = 1; +} + +/* + * Free an inode. + * + * Free the specified I node on the specified device. The algorithm + * stores up to NICINOD I nodes in the super block and throws away any more. + */ +void +ifree (ip, ino) + struct inode *ip; + ino_t ino; +{ + register struct fs *fs; + + fs = ip->i_fs; + fs->fs_tinode++; + if (fs->fs_ilock) + return; + if (fs->fs_ninode >= NICINOD) { + if (fs->fs_lasti > ino) + fs->fs_nbehind++; + return; + } + fs->fs_inode[fs->fs_ninode++] = ino; + fs->fs_fmod = 1; +} + +/* + * Fserr prints the name of a file system with an error diagnostic. + * + * The form of the error message is: + * fs: error message + */ +void +fserr (fp, cp) + struct fs *fp; + char *cp; +{ + printf ("%s: %s\n", fp->fs_fsmnt, cp); +} diff --git a/sys/kernel/ufs_bio.c b/sys/kernel/ufs_bio.c new file mode 100644 index 0000000..53b54c9 --- /dev/null +++ b/sys/kernel/ufs_bio.c @@ -0,0 +1,485 @@ +/* + * Copyright (c) 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "param.h" +#include "buf.h" +#include "user.h" +#include "conf.h" +#include "fs.h" +#include "dk.h" +#include "systm.h" +#include "map.h" +#include "trace.h" +#include "proc.h" + +/* + * Read in (if necessary) the block and return a buffer pointer. + */ +struct buf * +bread (dev, blkno) + dev_t dev; + daddr_t blkno; +{ + register struct buf *bp; + + bp = getblk(dev, blkno); + if (bp->b_flags&(B_DONE|B_DELWRI)) { + trace(TR_BREADHIT); + return (bp); + } + bp->b_flags |= B_READ; + bp->b_bcount = DEV_BSIZE; /* XXX? KB */ + (*bdevsw[major(dev)].d_strategy)(bp); + trace(TR_BREADMISS); + u.u_ru.ru_inblock++; /* pay for read */ + biowait(bp); + return(bp); +} + +/* + * Read in the block, like bread, but also start I/O on the + * read-ahead block (which is not allocated to the caller) + */ +struct buf * +breada(dev, blkno, rablkno) + register dev_t dev; + daddr_t blkno; + daddr_t rablkno; +{ + register struct buf *bp, *rabp; + + bp = NULL; + /* + * If the block isn't in core, then allocate + * a buffer and initiate i/o (getblk checks + * for a cache hit). + */ + if (! incore (dev, blkno)) { + bp = getblk(dev, blkno); + if ((bp->b_flags&(B_DONE|B_DELWRI)) == 0) { + bp->b_flags |= B_READ; + bp->b_bcount = DEV_BSIZE; /* XXX? KB */ + (*bdevsw[major(dev)].d_strategy)(bp); + trace(TR_BREADMISS); + u.u_ru.ru_inblock++; /* pay for read */ + } + else + trace(TR_BREADHIT); + } + + /* + * If there's a read-ahead block, start i/o + * on it also (as above). + */ + if (rablkno) { + if (! incore (dev, rablkno)) { + rabp = getblk(dev, rablkno); + if (rabp->b_flags & (B_DONE|B_DELWRI)) { + brelse(rabp); + trace(TR_BREADHITRA); + } else { + rabp->b_flags |= B_READ|B_ASYNC; + rabp->b_bcount = DEV_BSIZE; /* XXX? KB */ + (*bdevsw[major(dev)].d_strategy)(rabp); + trace(TR_BREADMISSRA); + u.u_ru.ru_inblock++; /* pay in advance */ + } + } else + trace(TR_BREADHITRA); + } + + /* + * If block was in core, let bread get it. + * If block wasn't in core, then the read was started + * above, and just wait for it. + */ + if (bp == NULL) + return (bread(dev, blkno)); + biowait(bp); + return (bp); +} + +/* + * Write the buffer, waiting for completion. + * Then release the buffer. + */ +void +bwrite(bp) + register struct buf *bp; +{ + register int flag; + + flag = bp->b_flags; + bp->b_flags &= ~(B_READ | B_DONE | B_ERROR | B_DELWRI); + if ((flag&B_DELWRI) == 0) + u.u_ru.ru_oublock++; /* noone paid yet */ + trace(TR_BWRITE); + bp->b_bcount = DEV_BSIZE; /* XXX? KB */ + (*bdevsw[major(bp->b_dev)].d_strategy)(bp); + + /* + * If the write was synchronous, then await i/o completion. + * If the write was "delayed", then we put the buffer on + * the q of blocks awaiting i/o completion status. + */ + if ((flag&B_ASYNC) == 0) { + biowait(bp); + brelse(bp); + } else if (flag & B_DELWRI) + bp->b_flags |= B_AGE; +} + +/* + * Release the buffer, marking it so that if it is grabbed + * for another purpose it will be written out before being + * given up (e.g. when writing a partial block where it is + * assumed that another write for the same block will soon follow). + * This can't be done for magtape, since writes must be done + * in the same order as requested. + */ +void +bdwrite (bp) + register struct buf *bp; +{ + + if ((bp->b_flags&B_DELWRI) == 0) + u.u_ru.ru_oublock++; /* noone paid yet */ + if (bdevsw[major(bp->b_dev)].d_flags & B_TAPE) { + bawrite(bp); + } + else { + bp->b_flags |= B_DELWRI | B_DONE; + brelse(bp); + } +} + +/* + * Release the buffer, with no I/O implied. + */ +void +brelse (bp) + register struct buf *bp; +{ + register struct buf *flist; + register int s; + + trace(TR_BRELSE); + /* + * If someone's waiting for the buffer, or + * is waiting for a buffer, wake 'em up. + */ + if (bp->b_flags&B_WANTED) + wakeup((caddr_t)bp); + if (bfreelist[0].b_flags&B_WANTED) { + bfreelist[0].b_flags &= ~B_WANTED; + wakeup((caddr_t)bfreelist); + } + if (bp->b_flags&B_ERROR) { + if (bp->b_flags & B_LOCKED) + bp->b_flags &= ~B_ERROR; /* try again later */ + else + bp->b_dev = NODEV; /* no assoc */ + } + /* + * Stick the buffer back on a free list. + */ + s = splbio(); + if (bp->b_flags & (B_ERROR|B_INVAL)) { + /* block has no info ... put at front of most free list */ + flist = &bfreelist[BQ_AGE]; + binsheadfree(bp, flist); + } else { + if (bp->b_flags & B_LOCKED) + flist = &bfreelist[BQ_LOCKED]; + else if (bp->b_flags & B_AGE) + flist = &bfreelist[BQ_AGE]; + else + flist = &bfreelist[BQ_LRU]; + binstailfree(bp, flist); + } + bp->b_flags &= ~(B_WANTED|B_BUSY|B_ASYNC|B_AGE); + splx(s); +} + +/* + * See if the block is associated with some buffer + * (mainly to avoid getting hung up on a wait in breada) + */ +int +incore (dev, blkno) + register dev_t dev; + daddr_t blkno; +{ + register struct buf *bp; + register struct buf *dp; + + dp = BUFHASH(dev, blkno); + blkno = fsbtodb(blkno); + for (bp = dp->b_forw; bp != dp; bp = bp->b_forw) + if (bp->b_blkno == blkno && bp->b_dev == dev && + (bp->b_flags & B_INVAL) == 0) + return (1); + return (0); +} + +/* + * Find a buffer which is available for use. + * Select something from a free list. + * Preference is to AGE list, then LRU list. + */ +struct buf * +getnewbuf() +{ + register struct buf *bp, *dp; + int s; + +loop: + s = splbio(); + for (dp = &bfreelist[BQ_AGE]; dp > bfreelist; dp--) + if (dp->av_forw != dp) + break; + if (dp == bfreelist) { /* no free blocks */ + dp->b_flags |= B_WANTED; + sleep((caddr_t)dp, PRIBIO+1); + splx(s); + goto loop; + } + splx(s); + bp = dp->av_forw; + notavail(bp); + if (bp->b_flags & B_DELWRI) { + bawrite(bp); + goto loop; + } + if(bp->b_flags & (B_RAMREMAP|B_PHYS)) { +#ifdef DIAGNOSTIC + if ((bp < &buf[0]) || (bp >= &buf[NBUF])) + panic("getnewbuf: RAMREMAP bp addr"); +#endif + bp->b_addr = bufdata + DEV_BSIZE * (bp - buf); + } + trace(TR_BRELSE); + bp->b_flags = B_BUSY; + return (bp); +} + +/* + * Assign a buffer for the given block. If the appropriate + * block is already associated, return it; otherwise search + * for the oldest non-busy buffer and reassign it. + * + * We use splx here because this routine may be called + * on the interrupt stack during a dump, and we don't + * want to lower the ipl back to 0. + */ +struct buf * +getblk(dev, blkno) + register dev_t dev; + daddr_t blkno; +{ + register struct buf *bp, *dp; + daddr_t dblkno; + int s; + +#ifdef DIAGNOSTIC + if (major(dev) >= nblkdev) + panic("blkdev"); +#endif + /* + * Search the cache for the block. If we hit, but + * the buffer is in use for i/o, then we wait until + * the i/o has completed. + */ + dp = BUFHASH(dev, blkno); + dblkno = fsbtodb(blkno); +loop: + for (bp = dp->b_forw; bp != dp; bp = bp->b_forw) { + if (bp->b_blkno != dblkno || bp->b_dev != dev || + bp->b_flags&B_INVAL) + continue; + s = splbio(); + if (bp->b_flags&B_BUSY) { + bp->b_flags |= B_WANTED; + sleep((caddr_t)bp, PRIBIO+1); + splx(s); + goto loop; + } + splx(s); + notavail(bp); + return (bp); + } + bp = getnewbuf(); + bfree(bp); + bremhash(bp); + binshash(bp, dp); + bp->b_dev = dev; + bp->b_blkno = dblkno; + bp->b_error = 0; + return (bp); +} + +/* + * get an empty block, + * not assigned to any particular device + */ +struct buf * +geteblk() +{ + register struct buf *bp, *flist; + + bp = getnewbuf(); + bp->b_flags |= B_INVAL; + bfree(bp); + bremhash(bp); + flist = &bfreelist[BQ_AGE]; + binshash(bp, flist); + bp->b_dev = (dev_t)NODEV; + bp->b_error = 0; + return (bp); +} + +/* + * Wait for I/O completion on the buffer; return errors + * to the user. + */ +void +biowait(bp) + register struct buf *bp; +{ + register int s; + + s = splbio(); + while ((bp->b_flags & B_DONE) == 0) + sleep((caddr_t)bp, PRIBIO); + splx(s); + if (! u.u_error) /* XXX */ + u.u_error = geterror(bp); +} + +/* + * Mark I/O complete on a buffer. + * Wake up anyone waiting for it. + */ +void +biodone(bp) + register struct buf *bp; +{ + if (bp->b_flags & B_DONE) + panic("dup biodone"); + bp->b_flags |= B_DONE; + if (bp->b_flags & B_ASYNC) + brelse(bp); + else { + bp->b_flags &= ~B_WANTED; + wakeup((caddr_t)bp); + } +} + +/* + * Insure that no part of a specified block is in an incore buffer. + */ +void +blkflush (dev, blkno) + register dev_t dev; + daddr_t blkno; +{ + register struct buf *ep; + struct buf *dp; + register int s; + + dp = BUFHASH(dev, blkno); + blkno = fsbtodb(blkno); +loop: + for (ep = dp->b_forw; ep != dp; ep = ep->b_forw) { + if (ep->b_blkno != blkno || ep->b_dev != dev || + (ep->b_flags&B_INVAL)) + continue; + s = splbio(); + if (ep->b_flags&B_BUSY) { + ep->b_flags |= B_WANTED; + sleep((caddr_t)ep, PRIBIO+1); + splx(s); + goto loop; + } + if (ep->b_flags & B_DELWRI) { + splx(s); + notavail(ep); + bwrite(ep); + goto loop; + } + splx(s); + } +} + +/* + * Make sure all write-behind blocks on dev are flushed out. + * (from umount and sync) + */ +void +bflush(dev) + register dev_t dev; +{ + register struct buf *bp; + register struct buf *flist; + int s; + +loop: + s = splbio(); + for (flist = bfreelist; flist < &bfreelist[BQ_EMPTY]; flist++) { + for (bp = flist->av_forw; bp != flist; bp = bp->av_forw) { + if ((bp->b_flags & B_DELWRI) == 0) + continue; + if (dev == bp->b_dev) { + bp->b_flags |= B_ASYNC; + notavail(bp); + bwrite(bp); + splx(s); + goto loop; + } + } + } + splx(s); +} + +/* + * Pick up the device's error number and pass it to the user; + * if there is an error but the number is 0 set a generalized code. + */ +int +geterror (bp) + register struct buf *bp; +{ + register int error = 0; + + if (bp->b_flags&B_ERROR) + if ((error = bp->b_error)==0) + return(EIO); + return (error); +} + +/* + * Invalidate in core blocks belonging to closed or umounted filesystem + * + * This is not nicely done at all - the buffer ought to be removed from the + * hash chains & have its dev/blkno fields clobbered, but unfortunately we + * can't do that here, as it is quite possible that the block is still + * being used for i/o. Eventually, all disc drivers should be forced to + * have a close routine, which ought ensure that the queue is empty, then + * properly flush the queues. Until that happy day, this suffices for + * correctness. ... kre + */ +void +binval(dev) + register dev_t dev; +{ + register struct buf *bp; + register struct bufhd *hp; +#define dp ((struct buf *)hp) + + for (hp = bufhash; hp < &bufhash[BUFHSZ]; hp++) + for (bp = dp->b_forw; bp != dp; bp = bp->b_forw) + if (bp->b_dev == dev) + bp->b_flags |= B_INVAL; +} diff --git a/sys/kernel/ufs_bmap.c b/sys/kernel/ufs_bmap.c new file mode 100644 index 0000000..d56d21c --- /dev/null +++ b/sys/kernel/ufs_bmap.c @@ -0,0 +1,154 @@ +/* + * Copyright (c) 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "param.h" +#include "systm.h" +#include "conf.h" +#include "dir.h" +#include "inode.h" +#include "user.h" +#include "buf.h" +#include "fs.h" +#include "mount.h" +#include "uio.h" + +/* + * Bmap defines the structure of file system storage + * by returning the physical block number on a device given the + * inode and the logical block number in a file. + * When convenient, it also leaves the physical + * block number of the next block of the file in rablock + * for use in read-ahead. + */ +daddr_t +bmap(ip, bn, rwflg, flags) + register struct inode *ip; + daddr_t bn; + int rwflg, flags; +{ + register int i; + register struct buf *bp; + struct buf *nbp; + int j, sh; + daddr_t nb, *bap, ra; + int async = ip->i_fs->fs_flags & MNT_ASYNC; + + if (bn < 0) { + u.u_error = EFBIG; + return((daddr_t)0); + } + ra = rablock = 0; + + /* + * blocks 0..NADDR-4 are direct blocks + */ + if (bn < NADDR-3) { + i = bn; + nb = ip->i_addr[i]; + if (nb == 0) { + if (rwflg == B_READ || (bp = balloc(ip, flags)) == NULL) + return((daddr_t)-1); + nb = dbtofsb(bp->b_blkno); +/* + * directory blocks are usually the only thing written synchronously at this + * point (so they never appear with garbage in them on the disk). This is + * overridden if the filesystem was mounted 'async'. +*/ + if (flags & B_SYNC) + bwrite(bp); + else + bdwrite(bp); + ip->i_addr[i] = nb; + ip->i_flag |= IUPD|ICHG; + } + if (i < NADDR-4) + rablock = ip->i_addr[i+1]; + return(nb); + } + + /* + * addresses NADDR-3, NADDR-2, and NADDR-1 + * have single, double, triple indirect blocks. + * the first step is to determine + * how many levels of indirection. + */ + sh = 0; + nb = 1; + bn -= NADDR-3; + for (j = 3;j > 0;j--) { + sh += NSHIFT; + nb <<= NSHIFT; + if (bn < nb) + break; + bn -= nb; + } + if (j == 0) { + u.u_error = EFBIG; + return((daddr_t)0); + } + + /* + * fetch the first indirect block + */ + nb = ip->i_addr[NADDR-j]; + if (nb == 0) { + if (rwflg == B_READ || (bp = balloc(ip, flags | B_CLRBUF)) == NULL) + return((daddr_t) -1); + nb = dbtofsb(bp->b_blkno); + /* + * Write synchronously if requested so that indirect blocks + * never point at garbage. + */ + if (async) + bdwrite(bp); + else + bwrite(bp); + ip->i_addr[NADDR-j] = nb; + ip->i_flag |= IUPD|ICHG; + } + + /* + * fetch through the indirect blocks + */ + for(;j <= 3;j++) { + bp = bread(ip->i_dev, nb); + if ((bp->b_flags & B_ERROR) || bp->b_resid) { + brelse(bp); + return((daddr_t)0); + } + bap = (daddr_t*) bp->b_addr; + sh -= NSHIFT; + i = (bn>>sh) & NMASK; + nb = bap[i]; + /* + * calculate read-ahead + */ + if (i < NINDIR-1) + ra = bap[i+1]; + if (nb == 0) { + if (rwflg == B_READ || (nbp = balloc(ip, flags | B_CLRBUF)) == NULL) { + brelse(bp); + return((daddr_t) -1); + } + nb = dbtofsb(nbp->b_blkno); +/* + * Write synchronously so indirect blocks never point at garbage and blocks + * in directories never contain garbage. This check used to be based on the + * type of inode, if it was a directory then 'sync' writes were done. See the + * comments earlier about filesystems being mounted 'async'. +*/ + if (!async && (j < 3 || (flags & B_SYNC))) + bwrite(nbp); + else + bdwrite(nbp); + bap = (daddr_t*) bp->b_addr; + bap[i] = nb; + bdwrite(bp); + } else + brelse(bp); + } + rablock = ra; + return(nb); +} diff --git a/sys/kernel/ufs_dsort.c b/sys/kernel/ufs_dsort.c new file mode 100644 index 0000000..3f6b7f9 --- /dev/null +++ b/sys/kernel/ufs_dsort.c @@ -0,0 +1,84 @@ +/* + * Copyright (c) 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + * + * @(#)ufs_dsort.c 1.1 (2.10BSD Berkeley) 12/1/86 + */ + +/* + * generalized seek sort for disk + */ + +#include "param.h" +#include "systm.h" +#include "buf.h" +#include "dk.h" + +void +disksort (dp, bp) + register struct buf *dp, *bp; +{ + register struct buf *ap; + struct buf *tp; + + ap = dp->b_actf; + if (ap == NULL) { + dp->b_actf = bp; + dp->b_actl = bp; + bp->av_forw = NULL; + return; + } + tp = NULL; + for (; ap != NULL; ap = ap->av_forw) { + if ((bp->b_flags&B_READ) && (ap->b_flags&B_READ) == 0) { + if (tp == NULL) + tp = ap; + break; + } + if ((bp->b_flags&B_READ) == 0 && (ap->b_flags&B_READ)) + continue; + if (ap->b_cylin <= bp->b_cylin) + if (tp == NULL || ap->b_cylin >= tp->b_cylin) + tp = ap; + } + if (tp == NULL) + tp = dp->b_actl; + bp->av_forw = tp->av_forw; + tp->av_forw = bp; + if (tp == dp->b_actl) + dp->b_actl = bp; +} + +#ifdef UCB_METER +/* + * Allocate iostat disk monitoring slots for a driver. If slots already + * allocated (*dkn >= 0) or not enough slots left to satisfy request simply + * ignore it. + */ +void +dk_alloc (dkn, slots, name) + int *dkn; /* pointer to number for iostat */ + int slots; /* number of iostat slots requested */ + char *name; /* name of device */ +{ + int i; + register char **np; + register int *up; + + if (*dkn < 0 && dk_n + slots <= DK_NDRIVE) { + /* + * Allocate and initialize the slots + */ + *dkn = dk_n; + np = &dk_name[dk_n]; + up = &dk_unit[dk_n]; + dk_n += slots; + + for (i = 0; i < slots; i++) { + *np++ = name; + *up++ = i; + } + } +} +#endif /* UCB_METER */ diff --git a/sys/kernel/ufs_fio.c b/sys/kernel/ufs_fio.c new file mode 100644 index 0000000..556485b --- /dev/null +++ b/sys/kernel/ufs_fio.c @@ -0,0 +1,186 @@ +/* + * Copyright (c) 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "param.h" +#include "user.h" +#include "fs.h" +#include "inode.h" +#include "mount.h" +#include "namei.h" +#include "systm.h" +#include "stat.h" + +/* + * Check mode permission on inode pointer. + * Mode is READ, WRITE or EXEC. + * In the case of WRITE, the + * read-only status of the file + * system is checked. + * Also in WRITE, prototype text + * segments cannot be written. + * The mode is shifted to select + * the owner/group/other fields. + * The super user is granted all + * permissions. + */ +int +access (ip, mode) + register struct inode *ip; + int mode; +{ + register int m; + register gid_t *gp; + + m = mode; + if (m == IWRITE) { + if (ip->i_flags & IMMUTABLE) { + u.u_error = EPERM; + return(1); + } + /* + * Disallow write attempts on read-only + * file systems; unless the file is a block + * or character device resident on the + * file system. + */ + if (ip->i_fs->fs_ronly != 0) { + if ((ip->i_mode & IFMT) != IFCHR && + (ip->i_mode & IFMT) != IFBLK) { + u.u_error = EROFS; + return (1); + } + } + } + /* + * If you're the super-user, + * you always get access. + */ + if (u.u_uid == 0) + return (0); + /* + * Access check is based on only + * one of owner, group, public. + * If not owner, then check group. + * If not a member of the group, then + * check public access. + */ + if (u.u_uid != ip->i_uid) { + m >>= 3; + gp = u.u_groups; + for (; gp < &u.u_groups[NGROUPS] && *gp != NOGROUP; gp++) + if (ip->i_gid == *gp) + goto found; + m >>= 3; +found: + ; + } + if ((ip->i_mode&m) != 0) + return (0); + u.u_error = EACCES; + return (1); +} + +/* copied, for supervisory networking, to sys_net.c */ +/* + * Test if the current user is the + * super user. + */ +int +suser() +{ + if (u.u_uid == 0) { + return (1); + } + u.u_error = EPERM; + return (0); +} + +/* + * Set the attributes on a file. This was placed here because ufs_syscalls + * is too large already (it will probably be split into two files eventually). + */ +int +ufs_setattr (ip, vap) + register struct inode *ip; + register struct vattr *vap; +{ + int error; + struct timeval atimeval, mtimeval; + + if (ip->i_fs->fs_ronly) /* can't change anything on a RO fs */ + return(EROFS); + if (vap->va_flags != VNOVAL) { + if (u.u_uid != ip->i_uid && !suser()) + return(u.u_error); + if (u.u_uid == 0) { + if ((ip->i_flags & + (SF_IMMUTABLE|SF_APPEND)) && securelevel > 0) + return(EPERM); + ip->i_flags = vap->va_flags; + } else { + if (ip->i_flags & (SF_IMMUTABLE|SF_APPEND)) + return(EPERM); + ip->i_flags &= SF_SETTABLE; + ip->i_flags |= (vap->va_flags & UF_SETTABLE); + } + ip->i_flag |= ICHG; + if (vap->va_flags & (IMMUTABLE|APPEND)) + return(0); + } + if (ip->i_flags & (IMMUTABLE|APPEND)) + return(EPERM); + /* + * Go thru the fields (other than 'flags') and update iff not VNOVAL. + */ + if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) { + error = chown1 (ip, vap->va_uid, vap->va_gid); + if (error) + return(error); + } + if (vap->va_size != (off_t)VNOVAL) { + if ((ip->i_mode & IFMT) == IFDIR) + return(EISDIR); + itrunc(ip, vap->va_size, 0); + if (u.u_error) + return(u.u_error); + } + if (vap->va_atime != (time_t)VNOVAL || + vap->va_mtime != (time_t)VNOVAL) { + if (u.u_uid != ip->i_uid && !suser() && + ((vap->va_vaflags & VA_UTIMES_NULL) == 0 || + access(ip, IWRITE))) + return(u.u_error); + if (vap->va_atime != (time_t)VNOVAL && + ! (ip->i_fs->fs_flags & MNT_NOATIME)) + ip->i_flag |= IACC; + if (vap->va_mtime != (time_t)VNOVAL) + ip->i_flag |= (IUPD|ICHG); + atimeval.tv_sec = vap->va_atime; + mtimeval.tv_sec = vap->va_mtime; + iupdat(ip, &atimeval, &mtimeval, 1); + } + if (vap->va_mode != (mode_t)VNOVAL) + return(chmod1(ip, vap->va_mode)); + return(0); +} + +/* + * Check that device is mounted somewhere. + * Return EBUSY if mounted, 0 otherwise. + */ +int +ufs_mountedon (dev) + dev_t dev; +{ + register struct mount *mp; + + for (mp = mount; mp < &mount[NMOUNT]; mp++) { + if (mp->m_inodp == NULL) + continue; + if (mp->m_dev == dev) + return(EBUSY); + } + return(0); +} diff --git a/sys/kernel/ufs_inode.c b/sys/kernel/ufs_inode.c new file mode 100644 index 0000000..abc4a5b --- /dev/null +++ b/sys/kernel/ufs_inode.c @@ -0,0 +1,695 @@ +/* + * Copyright (c) 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "param.h" +#include "user.h" +#include "proc.h" +#include "inode.h" +#include "fs.h" +#include "mount.h" +#include "kernel.h" +#include "buf.h" +#include "systm.h" +#include "syslog.h" + +#define INOHSZ 16 /* must be power of two */ +#define INOHASH(dev,ino) (((dev)+(ino))&(INOHSZ-1)) + +union ihead { /* inode LRU cache, stolen */ + union ihead *ih_head[2]; + struct inode *ih_chain[2]; +} ihead[INOHSZ]; + +struct inode *ifreeh, **ifreet; + +/* + * Initialize hash links for inodes + * and build inode free list. + */ +void +ihinit() +{ + register int i; + register struct inode *ip = inode; + register union ihead *ih = ihead; + + for (i = INOHSZ; --i >= 0; ih++) { + ih->ih_head[0] = ih; + ih->ih_head[1] = ih; + } + ifreeh = ip; + ifreet = &ip->i_freef; + ip->i_freeb = &ifreeh; + ip->i_forw = ip; + ip->i_back = ip; + for (i = NINODE; --i > 0; ) { + ++ip; + ip->i_forw = ip; + ip->i_back = ip; + *ifreet = ip; + ip->i_freeb = ifreet; + ifreet = &ip->i_freef; + } + ip->i_freef = NULL; +} + +/* + * Find an inode if it is incore. + */ +struct inode * +ifind(dev, ino) + register dev_t dev; + register ino_t ino; +{ + register struct inode *ip; + union ihead *ih; + + ih = &ihead[INOHASH(dev, ino)]; + for (ip = ih->ih_chain[0]; ip != (struct inode *)ih; ip = ip->i_forw) + if (ino == ip->i_number && dev == ip->i_dev) + return(ip); + return((struct inode *)NULL); +} + +/* + * Look up an inode by device,inumber. + * If it is in core (in the inode structure), + * honor the locking protocol. + * If it is not in core, read it in from the + * specified device. + * If the inode is mounted on, perform + * the indicated indirection. + * In all cases, a pointer to a locked + * inode structure is returned. + * + * panic: no imt -- if the mounted file + * system is not in the mount table. + * "cannot happen" + */ +struct inode * +iget(dev, fs, ino) + dev_t dev; + register struct fs *fs; + ino_t ino; +{ + register struct inode *ip; + union ihead *ih; + struct buf *bp; + struct dinode *dp; +loop: + ih = &ihead[INOHASH(dev, ino)]; + for (ip = ih->ih_chain[0]; ip != (struct inode *)ih; ip = ip->i_forw) + if (ino == ip->i_number && dev == ip->i_dev) { + /* + * Following is essentially an inline expanded + * copy of igrab(), expanded inline for speed, + * and so that the test for a mounted on inode + * can be deferred until after we are sure that + * the inode isn't busy. + */ + if ((ip->i_flag&ILOCKED) != 0) { + ip->i_flag |= IWANT; + sleep((caddr_t)ip, PINOD); + goto loop; + } + if ((ip->i_flag&IMOUNT) != 0) { + register struct mount *mp; + + for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) + if(mp->m_inodp == ip) { + dev = mp->m_dev; + fs = &mp->m_filsys; + ino = ROOTINO; + goto loop; + } + panic("no imt"); + } + if (ip->i_count == 0) { /* ino on free list */ + register struct inode *iq; + + iq = ip->i_freef; + if (iq) + iq->i_freeb = ip->i_freeb; + else + ifreet = ip->i_freeb; + *ip->i_freeb = iq; + ip->i_freef = NULL; + ip->i_freeb = NULL; + } + ip->i_count++; + ip->i_flag |= ILOCKED; + return(ip); + } + + ip = ifreeh; + if (ip == NULL) { + log(LOG_ERR, "inode: table full\n"); + u.u_error = ENFILE; + return(NULL); + } + if (ip->i_count) + panic("free inode isn't"); + { + register struct inode *iq; + + iq = ip->i_freef; + if (iq) + iq->i_freeb = &ifreeh; + ifreeh = iq; + } + ip->i_freef = NULL; + ip->i_freeb = NULL; + /* + * Now to take inode off the hash chain it was on + * (initially, or after an iflush, it is on a "hash chain" + * consisting entirely of itself, and pointed to by no-one, + * but that doesn't matter), and put it on the chain for + * its new (ino, dev) pair + */ + remque(ip); + insque(ip, ih); + ip->i_dev = dev; + ip->i_fs = fs; + ip->i_number = ino; + cacheinval(ip); + ip->i_flag = ILOCKED; + ip->i_count++; + ip->i_lastr = 0; + bp = bread(dev, itod(ino)); + /* + * Check I/O errors + */ + if ((bp->b_flags&B_ERROR) != 0) { + brelse(bp); + /* + * the inode doesn't contain anything useful, so it would + * be misleading to leave it on its hash chain. + * 'iput' will take care of putting it back on the free list. + */ + remque(ip); + ip->i_forw = ip; + ip->i_back = ip; + /* + * we also loose its inumber, just in case (as iput + * doesn't do that any more) - but as it isn't on its + * hash chain, I doubt if this is really necessary .. kre + * (probably the two methods are interchangable) + */ + ip->i_number = 0; + iput(ip); + return(NULL); + } + dp = (struct dinode*) bp->b_addr; + dp += itoo(ino); + ip->i_ic1 = dp->di_ic1; + ip->i_flags = dp->di_flags; + ip->i_ic2 = dp->di_ic2; + bcopy(dp->di_addr, ip->i_addr, NADDR * sizeof (daddr_t)); + brelse(bp); + return (ip); +} + +/* + * Convert a pointer to an inode into a reference to an inode. + * + * This is basically the internal piece of iget (after the + * inode pointer is located) but without the test for mounted + * filesystems. It is caller's responsibility to check that + * the inode pointer is valid. + */ +void +igrab (ip) + register struct inode *ip; +{ + while ((ip->i_flag&ILOCKED) != 0) { + ip->i_flag |= IWANT; + sleep((caddr_t)ip, PINOD); + } + if (ip->i_count == 0) { /* ino on free list */ + register struct inode *iq; + + iq = ip->i_freef; + if (iq) + iq->i_freeb = ip->i_freeb; + else + ifreet = ip->i_freeb; + *ip->i_freeb = iq; + ip->i_freef = NULL; + ip->i_freeb = NULL; + } + ip->i_count++; + ip->i_flag |= ILOCKED; +} + +/* + * Decrement reference count of + * an inode structure. + * On the last reference, + * write the inode out and if necessary, + * truncate and deallocate the file. + */ +void +iput (ip) + register struct inode *ip; +{ +#ifdef notnow + /* + * This code requires a lot of workarounds, you have to change + * lots of places to gratuitously lock just so we can unlock it. + * Not worth it. -- KB + */ + if ((ip->i_flag & ILOCKED) == 0) + panic("iput"); +#endif + IUNLOCK(ip); + irele(ip); +} + +void +irele (ip) + register struct inode *ip; +{ + if (ip->i_count == 1) { + ip->i_flag |= ILOCKED; + if (ip->i_nlink <= 0 && ip->i_fs->fs_ronly == 0) { + itrunc (ip, (u_long) 0, 0); + ip->i_mode = 0; + ip->i_rdev = 0; + ip->i_flag |= IUPD|ICHG; + ifree(ip, ip->i_number); + } + IUPDAT(ip, &time, &time, 0); + IUNLOCK(ip); + ip->i_flag = 0; + /* + * Put the inode on the end of the free list. + * Possibly in some cases it would be better to + * put the inode at the head of the free list, + * (eg: where i_mode == 0 || i_number == 0) + * but I will think about that later .. kre + * (i_number is rarely 0 - only after an i/o error in iget, + * where i_mode == 0, the inode will probably be wanted + * again soon for an ialloc, so possibly we should keep it) + */ + if (ifreeh) { + *ifreet = ip; + ip->i_freeb = ifreet; + } else { + ifreeh = ip; + ip->i_freeb = &ifreeh; + } + ip->i_freef = NULL; + ifreet = &ip->i_freef; + } else if (!(ip->i_flag & ILOCKED)) + ITIMES(ip, &time, &time); + ip->i_count--; +} + +/* + * Check accessed and update flags on + * an inode structure. + * If any are on, update the inode + * with the current time. + * If waitfor set, then must insure + * i/o order so wait for the write to complete. + */ +void +iupdat (ip, ta, tm, waitfor) + struct inode *ip; + struct timeval *ta, *tm; + int waitfor; +{ + register struct buf *bp; + register struct dinode *dp; + register struct inode *tip = ip; + + if ((tip->i_flag & (IUPD|IACC|ICHG|IMOD)) == 0) + return; + if (tip->i_fs->fs_ronly) + return; + bp = bread(tip->i_dev, itod(tip->i_number)); + if (bp->b_flags & B_ERROR) { + brelse(bp); + return; + } + if (tip->i_flag&IACC) + tip->i_atime = ta->tv_sec; + if (tip->i_flag&IUPD) + tip->i_mtime = tm->tv_sec; + if (tip->i_flag&ICHG) + tip->i_ctime = time.tv_sec; + tip->i_flag &= ~(IUPD|IACC|ICHG|IMOD); + dp = (struct dinode*) bp->b_addr + itoo (tip->i_number); + dp->di_ic1 = tip->i_ic1; + dp->di_flags = tip->i_flags; + dp->di_ic2 = tip->i_ic2; + bcopy(ip->i_addr, dp->di_addr, NADDR * sizeof (daddr_t)); + if (waitfor && ((ip->i_fs->fs_flags & MNT_ASYNC) == 0)) + bwrite(bp); + else + bdwrite(bp); +} + +#define SINGLE 0 /* index of single indirect block */ +#define DOUBLE 1 /* index of double indirect block */ +#define TRIPLE 2 /* index of triple indirect block */ + +static void +trsingle (ip, bp, last, aflags) + register struct inode *ip; + struct buf *bp; + daddr_t last; + int aflags; +{ + register const daddr_t *bstart, *bstop; + const daddr_t *blarray = (const daddr_t*) bp->b_addr; + + bstart = &blarray[NINDIR - 1]; + bstop = &blarray[last]; + for (; bstart > bstop; --bstart) + if (*bstart) + free (ip, *bstart); +} + +/* + * Release blocks associated with the inode ip and + * stored in the indirect block bn. Blocks are free'd + * in LIFO order up to (but not including) lastbn. If + * level is greater than SINGLE, the block is an indirect + * block and recursive calls to indirtrunc must be used to + * cleanse other indirect blocks. + * + * NB: triple indirect blocks are untested. + */ +void +indirtrunc (ip, bn, lastbn, level, aflags) + struct inode *ip; + daddr_t bn, lastbn; + int level; + int aflags; +{ + register struct buf *bp; + daddr_t nb, last; + long factor; + + /* + * Calculate index in current block of last + * block to be kept. -1 indicates the entire + * block so we need not calculate the index. + */ + switch (level) { + default: + case SINGLE: + factor = 1; + break; + case DOUBLE: + factor = NINDIR; + break; + case TRIPLE: + factor = NINDIR * NINDIR; + break; + } + last = lastbn; + if (lastbn > 0) + last = last / factor; + /* + * Get buffer of block pointers, zero those + * entries corresponding to blocks to be free'd, + * and update on disk copy first. + */ + { + register daddr_t *bap; + register struct buf *cpy; + + bp = bread(ip->i_dev, bn); + if (bp->b_flags&B_ERROR) { + brelse(bp); + return; + } + cpy = geteblk(); + bcopy (bp->b_addr, cpy->b_addr, DEV_BSIZE); + bap = (daddr_t*) bp->b_addr; + bzero((caddr_t)&bap[last + 1], + (u_int)(NINDIR - (last + 1)) * sizeof(daddr_t)); + if (aflags & B_SYNC) + bwrite(bp); + else + bawrite(bp); + bp = cpy; + } + + /* + * Optimized for single indirect blocks, i.e. until a file is + * greater than 4K + 256K you don't have to do a mapin/mapout + * for every entry. The mapin/mapout is required since free() + * may have to map an item in. Have to use another routine + * since it requires 1K of kernel stack to get around the problem + * and that doesn't work well with recursion. + */ + if (level == SINGLE) + trsingle (ip, bp, last, aflags); + else { + register daddr_t *bstart, *bstop; + + bstart = (daddr_t*) bp->b_addr; + bstop = &bstart[last]; + bstart += NINDIR - 1; + /* + * Recursively free totally unused blocks. + */ + for (;bstart > bstop;--bstart) { + nb = *bstart; + if (nb) { + indirtrunc(ip,nb,(daddr_t)-1, level-1, aflags); + free(ip, nb); + } + } + + /* + * Recursively free last partial block. + */ + if (lastbn >= 0) { + nb = *bstop; + last = lastbn % factor; + if (nb != 0) + indirtrunc(ip, nb, last, level - 1, aflags); + } + } + brelse(bp); +} + +/* + * Truncate the inode ip to at most + * length size. Free affected disk + * blocks -- the blocks of the file + * are removed in reverse order. + * + * NB: triple indirect blocks are untested. + */ +void +itrunc (oip, length, ioflags) + register struct inode *oip; + u_long length; + int ioflags; +{ + daddr_t lastblock; + register int i; + register struct inode *ip; + daddr_t bn, lastiblock[NIADDR]; + struct buf *bp; + int offset, level; + struct inode tip; + int aflags; + + aflags = B_CLRBUF; + if (ioflags & IO_SYNC) + aflags |= B_SYNC; + + /* + * special hack for pipes, since size for them isn't the size of + * the file, it's the amount currently waiting for transfer. It's + * unclear that this will work, though, because pipes can (although + * rarely do) get bigger than MAXPIPSIZ. Don't think it worked + * in V7 either, I don't really understand what's going on. + */ + if (oip->i_flag & IPIPE) + oip->i_size = MAXPIPSIZ; + else if (oip->i_size == length) + goto updret; + + /* + * Lengthen the size of the file. We must ensure that the + * last byte of the file is allocated. Since the smallest + * value of osize is 0, length will be at least 1. + */ + if (oip->i_size < length) { + bn = bmap(oip, lblkno(length - 1), B_WRITE, aflags); + if (u.u_error || bn < 0) + return; + oip->i_size = length; + goto doquotaupd; + } + + /* + * Calculate index into inode's block list of + * last direct and indirect blocks (if any) + * which we want to keep. Lastblock is -1 when + * the file is truncated to 0. + */ + lastblock = lblkno(length + DEV_BSIZE - 1) - 1; + lastiblock[SINGLE] = lastblock - NDADDR; + lastiblock[DOUBLE] = lastiblock[SINGLE] - NINDIR; + lastiblock[TRIPLE] = lastiblock[DOUBLE] - NINDIR * NINDIR; + /* + * Update the size of the file. If the file is not being + * truncated to a block boundry, the contents of the + * partial block following the end of the file must be + * zero'ed in case it ever become accessable again because + * of subsequent file growth. + */ + offset = blkoff(length); + if (offset) { + bn = bmap(oip, lblkno(length), B_WRITE, aflags); + if (u.u_error || bn < 0) + return; + bp = bread(oip->i_dev, bn); + if (bp->b_flags & B_ERROR) { + u.u_error = EIO; + brelse(bp); + return; + } + bzero (bp->b_addr + offset, (u_int) (DEV_BSIZE - offset)); + bdwrite(bp); + } + /* + * Update file and block pointers + * on disk before we start freeing blocks. + * If we crash before free'ing blocks below, + * the blocks will be returned to the free list. + * lastiblock values are also normalized to -1 + * for calls to indirtrunc below. + */ + tip = *oip; + oip->i_size = length; + for (level = TRIPLE; level >= SINGLE; level--) + if (lastiblock[level] < 0) { + oip->i_ib[level] = 0; + lastiblock[level] = -1; + } + for (i = NDADDR - 1; i > lastblock; i--) + oip->i_db[i] = 0; + + /* + * Indirect blocks first. + */ + ip = &tip; + for (level = TRIPLE; level >= SINGLE; level--) { + bn = ip->i_ib[level]; + if (bn != 0) { + indirtrunc(ip, bn, lastiblock[level], level, aflags); + if (lastiblock[level] < 0) { + ip->i_ib[level] = 0; + free(ip, bn); + } + } + if (lastiblock[level] >= 0) + goto done; + } + + /* + * All whole direct blocks. + */ + for (i = NDADDR - 1; i > lastblock; i--) { + bn = ip->i_db[i]; + if (bn == 0) + continue; + ip->i_db[i] = 0; + free(ip, bn); + } + if (lastblock < 0) + goto done; + +done: +#ifdef DIAGNOSTIC +/* BEGIN PARANOIA */ + for (level = SINGLE; level <= TRIPLE; level++) + if (ip->i_ib[level] != oip->i_ib[level]) + panic("itrunc1"); + for (i = 0; i < NDADDR; i++) + if (ip->i_db[i] != oip->i_db[i]) + panic("itrunc2"); +/* END PARANOIA */ +#endif + +doquotaupd: +updret: + oip->i_flag |= ICHG|IUPD; + iupdat(oip, &time, &time, 1); +} + +/* + * Remove any inodes in the inode cache belonging to dev. + * + * There should not be any active ones, return error if any are found + * (nb: this is a user error, not a system err) + * + * Also, count the references to dev by block devices - this really + * has nothing to do with the object of the procedure, but as we have + * to scan the inode table here anyway, we might as well get the + * extra benefit. + * + * this is called from sumount() when dev is being unmounted + */ +int +iflush (dev) + dev_t dev; +{ + register struct inode *ip; + register int open = 0; + + for (ip = inode; ip < inode+NINODE; ip++) { + if (ip->i_dev == dev) + if (ip->i_count) + return(-1); + else { + remque(ip); + ip->i_forw = ip; + ip->i_back = ip; + /* + * as i_count == 0, the inode was on the free + * list already, just leave it there, it will + * fall off the bottom eventually. We could + * perhaps move it to the head of the free + * list, but as umounts are done so + * infrequently, we would gain very little, + * while making the code bigger. + */ + } + else if (ip->i_count && (ip->i_mode&IFMT)==IFBLK && + ip->i_rdev == dev) + open++; + } + return (open); +} + +/* + * Lock an inode. If its already locked, set the WANT bit and sleep. + */ +void +ilock(ip) + register struct inode *ip; +{ + ILOCK(ip); +} + +/* + * Unlock an inode. If WANT bit is on, wakeup. + */ +void +iunlock(ip) + register struct inode *ip; +{ + IUNLOCK(ip); +} diff --git a/sys/kernel/ufs_mount.c b/sys/kernel/ufs_mount.c new file mode 100644 index 0000000..c87cde5 --- /dev/null +++ b/sys/kernel/ufs_mount.c @@ -0,0 +1,301 @@ +/* + * Copyright (c) 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "param.h" +#include "systm.h" +#include "user.h" +#include "inode.h" +#include "fs.h" +#include "buf.h" +#include "mount.h" +#include "file.h" +#include "namei.h" +#include "conf.h" +#include "stat.h" +#include "ioctl.h" +#include "proc.h" + +/* + * Common code for mount and umount. + * Check that the user's argument is a reasonable + * thing on which to mount, otherwise return error. + */ +static int +getmdev (pdev, fname) + caddr_t fname; + dev_t *pdev; +{ + register dev_t dev; + register struct inode *ip; + struct nameidata nd; + register struct nameidata *ndp = &nd; + + if (!suser()) + return (u.u_error); + NDINIT (ndp, LOOKUP, FOLLOW, fname); + ip = namei(ndp); + if (ip == NULL) { + if (u.u_error == ENOENT) + return (ENODEV); /* needs translation */ + return (u.u_error); + } + if ((ip->i_mode&IFMT) != IFBLK) { + iput(ip); + return (ENOTBLK); + } + dev = (dev_t)ip->i_rdev; + iput(ip); + if (major(dev) >= nblkdev) + return (ENXIO); + *pdev = dev; + return (0); +} + +void +mount_updname (fs, on, from, lenon, lenfrom) + struct fs *fs; + char *on, *from; + int lenon, lenfrom; +{ + struct mount *mp; + + bzero (fs->fs_fsmnt, sizeof (fs->fs_fsmnt)); + bcopy (on, fs->fs_fsmnt, sizeof (fs->fs_fsmnt) - 1); + mp = (struct mount*) ((int) fs - offsetof (struct mount, m_filsys)); + bzero (mp->m_mnton, sizeof (mp->m_mnton)); + bzero (mp->m_mntfrom, sizeof (mp->m_mntfrom)); + bcopy (on, mp->m_mnton, lenon); + bcopy (from, mp->m_mntfrom, lenfrom); +} + +void +smount() +{ + register struct a { + char *fspec; + char *freg; + int flags; + } *uap = (struct a *)u.u_arg; + dev_t dev = 0; + register struct inode *ip; + register struct fs *fs; + struct nameidata nd; + struct nameidata *ndp = &nd; + struct mount *mp; + u_int lenon, lenfrom; + int error = 0; + char mnton[MNAMELEN], mntfrom[MNAMELEN]; + + u.u_error = getmdev (&dev, uap->fspec); + if (u.u_error) + return; + NDINIT (ndp, LOOKUP, FOLLOW, uap->freg); + if ((ip = namei(ndp)) == NULL) + return; + if ((ip->i_mode&IFMT) != IFDIR) { + error = ENOTDIR; + goto cmnout; + } + copystr (uap->freg, mnton, sizeof (mnton) - 1, &lenon); + copystr (uap->fspec, mntfrom, sizeof (mntfrom) - 1, &lenfrom); + + if (uap->flags & MNT_UPDATE) { + fs = ip->i_fs; + mp = (struct mount *) + ((int)fs - offsetof(struct mount, m_filsys)); + if (ip->i_number != ROOTINO) { + error = EINVAL; /* Not a mount point */ + goto cmnout; + } + /* + * Check that the device passed in is the same one that is in the mount + * table entry for this mount point. + */ + if (dev != mp->m_dev) { + error = EINVAL; /* not right mount point */ + goto cmnout; + } + /* + * This is where the RW to RO transformation would be done. It is, for now, + * too much work to port pages of code to do (besides which most + * programs get very upset at having access yanked out from under them). + */ + if (fs->fs_ronly == 0 && (uap->flags & MNT_RDONLY)) { + error = EPERM; /* ! RW to RO updates */ + goto cmnout; + } + /* + * However, going from RO to RW is easy. Then merge in the new + * flags (async, sync, nodev, etc) passed in from the program. + */ + if (fs->fs_ronly && ((uap->flags & MNT_RDONLY) == 0)) { + fs->fs_ronly = 0; + mp->m_flags &= ~MNT_RDONLY; + } +#define _MF (MNT_NOSUID | MNT_NODEV | MNT_NOEXEC | MNT_ASYNC | MNT_SYNCHRONOUS | MNT_NOATIME) + mp->m_flags &= ~_MF; + mp->m_flags |= (uap->flags & _MF); +#undef _MF + iput(ip); + u.u_error = 0; + goto updname; + } else { + /* + * This is where a new mount (not an update of an existing mount point) is + * done. + * + * The directory being mounted on can have no other references AND can not + * currently be a mount point. Mount points have an inode number of (you + * guessed it) ROOTINO which is 2. + */ + if (ip->i_count != 1 || (ip->i_number == ROOTINO)) { + error = EBUSY; + goto cmnout; + } + fs = mountfs (dev, uap->flags, ip); + if (fs == 0) + return; + } + /* + * Lastly, both for new mounts and updates of existing mounts, update the + * mounted-on and mounted-from fields. + */ +updname: + mount_updname(fs, mnton, mntfrom, lenon, lenfrom); + return; +cmnout: + iput(ip); + u.u_error = error; +} + +/* + * Mount a filesystem on the given directory inode. + * + * this routine has races if running twice + */ +struct fs * +mountfs (dev, flags, ip) + dev_t dev; + int flags; + struct inode *ip; +{ + register struct mount *mp = 0; + struct buf *tp = 0; + register struct fs *fs; + register int error; + int ronly = flags & MNT_RDONLY; + int needclose = 0; + + error = (*bdevsw[major(dev)].d_open) (dev, + ronly ? FREAD : (FREAD | FWRITE), S_IFBLK); + if (error) + goto out; + + needclose = 1; + tp = bread (dev, SUPERB); + if (tp->b_flags & B_ERROR) + goto out; + for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) + if (mp->m_inodp != 0 && dev == mp->m_dev) { + mp = 0; + error = EBUSY; + needclose = 0; + goto out; + } + for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) + if (mp->m_inodp == 0) + goto found; + mp = 0; + error = EMFILE; /* needs translation */ + goto out; +found: + mp->m_inodp = ip; /* reserve slot */ + mp->m_dev = dev; + fs = &mp->m_filsys; + bcopy (tp->b_addr, (caddr_t)fs, sizeof(struct fs)); + brelse (tp); + tp = 0; + if (fs->fs_magic1 != FSMAGIC1 || fs->fs_magic2 != FSMAGIC2) { + error = EINVAL; + goto out; + } + fs->fs_ronly = (ronly != 0); + if (ronly == 0) + fs->fs_fmod = 1; + fs->fs_ilock = 0; + fs->fs_flock = 0; + fs->fs_nbehind = 0; + fs->fs_lasti = 1; + fs->fs_flags = flags; + if (ip) { + ip->i_flag |= IMOUNT; + cacheinval(ip); + IUNLOCK(ip); + } + return (fs); +out: + if (error == 0) + error = EIO; + if (ip) + iput(ip); + if (mp) + mp->m_inodp = 0; + if (tp) + brelse(tp); + if (needclose) { + (*bdevsw[major(dev)].d_close)(dev, + ronly? FREAD : FREAD|FWRITE, S_IFBLK); + binval(dev); + } + u.u_error = error; + return (0); +} + +static int +unmount1 (fname) + caddr_t fname; +{ + dev_t dev = 0; + register struct mount *mp; + register struct inode *ip; + register int error; + int aflag; + + error = getmdev(&dev, fname); + if (error) + return (error); + for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) + if (mp->m_inodp != NULL && dev == mp->m_dev) + goto found; + return (EINVAL); +found: + nchinval (dev); /* flush the name cache */ + aflag = mp->m_flags & MNT_ASYNC; + mp->m_flags &= ~MNT_ASYNC; /* Don't want async when unmounting */ + ufs_sync(mp); + + if (iflush(dev) < 0) { + mp->m_flags |= aflag; + return (EBUSY); + } + ip = mp->m_inodp; + ip->i_flag &= ~IMOUNT; + irele(ip); + mp->m_inodp = 0; + mp->m_dev = 0; + (*bdevsw[major(dev)].d_close)(dev, 0, S_IFBLK); + binval(dev); + return (0); +} + +void +umount() +{ + struct a { + char *fspec; + } *uap = (struct a *)u.u_arg; + + u.u_error = unmount1 (uap->fspec); +} diff --git a/sys/kernel/ufs_namei.c b/sys/kernel/ufs_namei.c new file mode 100644 index 0000000..f881ed5 --- /dev/null +++ b/sys/kernel/ufs_namei.c @@ -0,0 +1,1258 @@ +/* + * Copyright (c) 1982 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "param.h" +#include "systm.h" +#include "dir.h" +#include "inode.h" +#include "fs.h" +#include "mount.h" +#include "user.h" +#include "buf.h" +#include "namei.h" +#include "proc.h" + +int dirchk = 0; + +/* + * Structures associated with name cacheing. + */ +#define NCHHASH 16 /* size of hash table */ + +#if ((NCHHASH)&((NCHHASH)-1)) != 0 +#define NHASH(h, i, d) ((unsigned)((h) + (i) + 13 * (int)(d)) % (NCHHASH)) +#else +#define NHASH(h, i, d) ((unsigned)((h) + (i) + 13 * (int)(d)) & ((NCHHASH)-1)) +#endif + +union nchash { + union nchash *nch_head[2]; + struct namecache *nch_chain[2]; +} nchash[NCHHASH]; +#define nch_forw nch_chain[0] +#define nch_back nch_chain[1] + +struct namecache *nchhead, **nchtail; /* LRU chain pointers */ + +static void +dirbad (ip, offset, how) + struct inode *ip; + off_t offset; + char *how; +{ + printf ("%s: bad dir I=%u off %ld: %s\n", + ip->i_fs->fs_fsmnt, ip->i_number, offset, how); +} + +/* + * Return buffer with contents of block "offset" + * from the beginning of directory "ip". If "res" + * is non-zero, fill it in with a pointer to the + * remaining space in the directory. + */ +static struct buf * +blkatoff(ip, offset, res) + struct inode *ip; + off_t offset; + char **res; +{ + daddr_t lbn = lblkno(offset); + register struct buf *bp; + daddr_t bn; + char *junk; + + bn = bmap(ip, lbn, B_READ, 0); + if (u.u_error) + return (0); + if (bn == (daddr_t)-1) { + dirbad(ip, offset, "hole in dir"); + return (0); + } + bp = bread(ip->i_dev, bn); + if (bp->b_flags & B_ERROR) { + brelse(bp); + return (0); + } + junk = (caddr_t) bp->b_addr; + if (res) + *res = junk + (u_int)blkoff(offset); + return (bp); +} + +/* + * Do consistency checking on a directory entry: + * record length must be multiple of 4 + * entry must fit in rest of its DIRBLKSIZ block + * record must be large enough to contain entry + * name is not longer than MAXNAMLEN + * name must be as long as advertised, and null terminated + */ +static int +dirbadentry (ep, entryoffsetinblock) + register struct direct *ep; + int entryoffsetinblock; +{ + register int i; + + if ((ep->d_reclen & 0x3) != 0 || + ep->d_reclen > DIRBLKSIZ - (entryoffsetinblock & (DIRBLKSIZ - 1)) || + ep->d_reclen < DIRSIZ(ep) || ep->d_namlen > MAXNAMLEN) + return (1); + for (i = 0; i < ep->d_namlen; i++) + if (ep->d_name[i] == '\0') + return (1); + return (ep->d_name[i]); +} + +/* + * Convert a pathname into a pointer to a locked inode. + * This is a very central and rather complicated routine. + * If the file system is not maintained in a strict tree hierarchy, + * this can result in a deadlock situation (see comments in code below). + * + * The flag argument is LOOKUP, CREATE, or DELETE depending on whether + * the name is to be looked up, created, or deleted. When CREATE or + * DELETE is specified, information usable in creating or deleteing a + * directory entry is also calculated. If flag has LOCKPARENT or'ed + * into it and the target of the pathname exists, namei returns both + * the target and its parent directory locked. When creating and + * LOCKPARENT is specified, the target may not be ".". When deleting + * and LOCKPARENT is specified, the target may be ".", but the caller + * must check to insure it does an irele and iput instead of two iputs. + * + * The FOLLOW flag is set when symbolic links are to be followed + * when they occur at the end of the name translation process. + * Symbolic links are always followed for all other pathname + * components other than the last. + * + * Name caching works as follows: + * + * Names found by directory scans are retained in a cache + * for future reference. It is managed LRU, so frequently + * used names will hang around. Cache is indexed by hash value + * obtained from (ino,dev,name) where ino & dev refer to the + * directory containing name. + * + * For simplicity (and economy of storage), names longer than + * a maximum length of NCHNAMLEN are not cached; they occur + * infrequently in any case, and are almost never of interest. + * + * Upon reaching the last segment of a path, if the reference + * is for DELETE, or NOCACHE is set (rewrite), and the + * name is located in the cache, it will be dropped. + * + * Overall outline of namei: + * + * copy in name + * get starting directory + * dirloop: + * check accessibility of directory + * dirloop2: + * copy next component of name to ndp->ni_dent + * handle degenerate case where name is null string + * look for name in cache, if found, then if at end of path + * and deleting or creating, drop it, else to haveino + * search for name in directory, to found or notfound + * notfound: + * if creating, return locked directory, leaving info on avail. slots + * else return error + * found: + * if at end of path and deleting, return information to allow delete + * if at end of path and rewriting (CREATE and LOCKPARENT), lock target + * inode and return info to allow rewrite + * if .. and on mounted filesys, look in mount table for parent + * if not at end, add name to cache; if at end and neither creating + * nor deleting, add name to cache + * haveino: + * if symbolic link, massage name in buffer and continue at dirloop + * if more components of name, do next level at dirloop + * return the answer as locked inode + * + * NOTE: (LOOKUP | LOCKPARENT) currently returns the parent inode, + * but unlocked. + */ +struct inode * +namei (ndp) + register struct nameidata *ndp; +{ + register char *cp; /* pointer into pathname argument */ +/* these variables refer to things which must be freed or unlocked */ + struct inode *dp = 0; /* the directory we are searching */ + struct namecache *ncp = 0; /* cache slot for entry */ + struct fs *fs; /* file system that directory is in */ + struct buf *bp = 0; /* a buffer of directory entries */ + struct direct *ep; /* the current directory entry */ + int entryoffsetinblock = 0; /* offset of ep in bp's buffer */ +/* these variables hold information about the search for a slot */ + enum {NONE, COMPACT, FOUND} slotstatus; + off_t slotoffset = -1; /* offset of area with free space */ + int slotsize = 0; /* size of area at slotoffset */ + int slotfreespace = 0; /* amount of space free in slot */ + int slotneeded = 0; /* size of the entry we're seeking */ +/* */ + int numdirpasses; /* strategy for directory search */ + off_t endsearch; /* offset to end directory search */ + off_t prevoff = 0; /* ndp->ni_offset of previous entry */ + int nlink = 0; /* number of symbolic links taken */ + struct inode *pdp; /* saved dp during symlink work */ + register int i; + int error; + int lockparent; + int docache; /* == 0 do not cache last component */ + int makeentry; /* != 0 if name to be added to cache */ + unsigned hash; /* value of name hash for entry */ + union nchash *nhp = 0; /* cache chain head for entry */ + int isdotdot; /* != 0 if current name is ".." */ + int flag; /* op ie, LOOKUP, CREATE, or DELETE */ + off_t enduseful; /* pointer past last used dir slot */ + char path[MAXPATHLEN]; /* current path */ + + lockparent = ndp->ni_nameiop & LOCKPARENT; + docache = (ndp->ni_nameiop & NOCACHE) ^ NOCACHE; + flag = ndp->ni_nameiop &~ (LOCKPARENT|NOCACHE|FOLLOW); + if (flag == DELETE || lockparent) + docache = 0; + /* + * Copy the name into the buffer. + */ + error = copystr (ndp->ni_dirp, path, MAXPATHLEN, (u_int*) 0); + if (error) { + u.u_error = error; + goto retNULL; + } + + /* + * Get starting directory. + */ + cp = path; + if (*cp == '/') { + while (*cp == '/') + cp++; + if ((dp = u.u_rdir) == NULL) + dp = rootdir; + } else + dp = u.u_cdir; + fs = dp->i_fs; + ILOCK(dp); + dp->i_count++; + ndp->ni_endoff = 0; + + /* + * We come to dirloop to search a new directory. + * The directory must be locked so that it can be + * iput, and fs must be already set to dp->i_fs. + */ +dirloop: + /* + * Check accessibility of directory. + */ + if ((dp->i_mode&IFMT) != IFDIR) { + u.u_error = ENOTDIR; + goto bad; + } + if (access(dp, IEXEC)) + goto bad; + +dirloop2: + /* + * Copy next component of name to ndp->ni_dent. + */ + hash = 0; + for (i = 0; *cp != 0 && *cp != '/'; cp++) { + if (i >= MAXNAMLEN) { + u.u_error = ENAMETOOLONG; + goto bad; + } + if (*cp & 0200) + if ((*cp&0377) == ('/'|0200) || flag != DELETE) { + u.u_error = EINVAL; + goto bad; + } + ndp->ni_dent.d_name[i++] = *cp; + hash += (unsigned char)*cp * i; + } + ndp->ni_dent.d_namlen = i; + ndp->ni_dent.d_name[i] = '\0'; + isdotdot = (i == 2 && + ndp->ni_dent.d_name[0] == '.' && ndp->ni_dent.d_name[1] == '.'); + makeentry = 1; + if (*cp == '\0' && docache == 0) + makeentry = 0; + + /* + * Check for degenerate name (e.g. / or "") + * which is a way of talking about a directory, + * e.g. like "/." or ".". + */ + if (ndp->ni_dent.d_name[0] == '\0') { + if (flag != LOOKUP || lockparent) { + u.u_error = EISDIR; + goto bad; + } + goto retDP; + } + + /* + * We now have a segment name to search for, and a directory to search. + * + * Before tediously performing a linear scan of the directory, + * check the name cache to see if the directory/name pair + * we are looking for is known already. We don't do this + * if the segment name is long, simply so the cache can avoid + * holding long names (which would either waste space, or + * add greatly to the complexity). + */ + if (ndp->ni_dent.d_namlen > NCHNAMLEN) { + nchstats.ncs_long++; + makeentry = 0; + } else { + nhp = &nchash[NHASH(hash, dp->i_number, dp->i_dev)]; + for (ncp = nhp->nch_forw; ncp != (struct namecache *)nhp; + ncp = ncp->nc_forw) { + if (ncp->nc_ino == dp->i_number && + ncp->nc_dev == dp->i_dev && + ncp->nc_nlen == ndp->ni_dent.d_namlen && + !bcmp(ncp->nc_name, ndp->ni_dent.d_name, + (unsigned)ncp->nc_nlen)) + break; + } + if (ncp == (struct namecache *)nhp) { + nchstats.ncs_miss++; + ncp = NULL; + } else { + if (ncp->nc_id != ncp->nc_ip->i_id) + nchstats.ncs_falsehits++; + else if (!makeentry) + nchstats.ncs_badhits++; + else { + /* + * move this slot to end of LRU + * chain, if not already there + */ + if (ncp->nc_nxt) { + /* remove from LRU chain */ + *ncp->nc_prev = ncp->nc_nxt; + ncp->nc_nxt->nc_prev = ncp->nc_prev; + + /* and replace at end of it */ + ncp->nc_nxt = NULL; + ncp->nc_prev = nchtail; + *nchtail = ncp; + nchtail = &ncp->nc_nxt; + } + + /* + * Get the next inode in the path. + * See comment above other `IUNLOCK' code for + * an explaination of the locking protocol. + */ + pdp = dp; + if (!isdotdot || dp != u.u_rdir) + dp = ncp->nc_ip; + if (dp == NULL) + panic("namei: null cache ino"); + if (pdp == dp) + dp->i_count++; + else if (isdotdot) { + IUNLOCK(pdp); + igrab(dp); + } else { + igrab(dp); + IUNLOCK(pdp); + } + + /* + * Verify that the inode that we got + * did not change while we were waiting + * for it to be locked. + */ + if (ncp->nc_id != ncp->nc_ip->i_id) { + iput(dp); + ILOCK(pdp); + dp = pdp; + nchstats.ncs_falsehits++; + } else { + ndp->ni_dent.d_ino = dp->i_number; + /* ni_dent.d_reclen is garbage ... */ + nchstats.ncs_goodhits++; + goto haveino; + } + } + + /* + * Last component and we are renaming or deleting, + * the cache entry is invalid, or otherwise don't + * want cache entry to exist. + */ + /* remove from LRU chain */ + *ncp->nc_prev = ncp->nc_nxt; + if (ncp->nc_nxt) + ncp->nc_nxt->nc_prev = ncp->nc_prev; + else + nchtail = ncp->nc_prev; + remque(ncp); /* remove from hash chain */ + /* insert at head of LRU list (first to grab) */ + ncp->nc_nxt = nchhead; + ncp->nc_prev = &nchhead; + nchhead->nc_prev = &ncp->nc_nxt; + nchhead = ncp; + /* and make a dummy hash chain */ + ncp->nc_forw = ncp; + ncp->nc_back = ncp; + ncp = NULL; + } + } + + /* + * Suppress search for slots unless creating + * file and at end of pathname, in which case + * we watch for a place to put the new file in + * case it doesn't already exist. + */ + slotstatus = FOUND; + if (flag == CREATE && *cp == 0) { + slotstatus = NONE; + slotfreespace = 0; + slotneeded = DIRSIZ(&ndp->ni_dent); + } + /* + * If this is the same directory that this process + * previously searched, pick up where we last left off. + * We cache only lookups as these are the most common + * and have the greatest payoff. Caching CREATE has little + * benefit as it usually must search the entire directory + * to determine that the entry does not exist. Caching the + * location of the last DELETE has not reduced profiling time + * and hence has been removed in the interest of simplicity. + */ + if (flag != LOOKUP || dp->i_number != u.u_ncache.nc_inumber || + dp->i_dev != u.u_ncache.nc_dev) { + ndp->ni_offset = 0; + numdirpasses = 1; + } else { + if (u.u_ncache.nc_prevoffset > dp->i_size) + u.u_ncache.nc_prevoffset = 0; + ndp->ni_offset = u.u_ncache.nc_prevoffset; + entryoffsetinblock = blkoff(ndp->ni_offset); + if (entryoffsetinblock != 0) { + bp = blkatoff(dp, ndp->ni_offset, (char **)0); + if (bp == 0) + goto bad; + } + numdirpasses = 2; + nchstats.ncs_2passes++; + } + endsearch = roundup(dp->i_size, DIRBLKSIZ); + enduseful = 0; + +searchloop: + while (ndp->ni_offset < endsearch) { + /* + * If offset is on a block boundary, + * read the next directory block. + * Release previous if it exists. + */ + if (blkoff(ndp->ni_offset) == 0) { + if (bp != NULL) { + brelse(bp); + } + bp = blkatoff(dp, ndp->ni_offset, (char **)0); + if (bp == 0) + goto bad; + entryoffsetinblock = 0; + } + /* + * If still looking for a slot, and at a DIRBLKSIZE + * boundary, have to start looking for free space again. + */ + if (slotstatus == NONE && + (entryoffsetinblock&(DIRBLKSIZ-1)) == 0) { + slotoffset = -1; + slotfreespace = 0; + } + /* + * Get pointer to next entry. + * Full validation checks are slow, so we only check + * enough to insure forward progress through the + * directory. Complete checks can be run by patching + * "dirchk" to be true. + */ + ep = (struct direct*) ((caddr_t) bp->b_addr + entryoffsetinblock); + if (ep->d_reclen == 0 || + (dirchk && dirbadentry (ep, entryoffsetinblock))) { + dirbad(dp, ndp->ni_offset, "mangled entry"); + i = DIRBLKSIZ - (entryoffsetinblock & (DIRBLKSIZ - 1)); + ndp->ni_offset += i; + entryoffsetinblock += i; + continue; + } + + /* + * If an appropriate sized slot has not yet been found, + * check to see if one is available. Also accumulate space + * in the current block so that we can determine if + * compaction is viable. + */ + if (slotstatus != FOUND) { + int size = ep->d_reclen; + + if (ep->d_ino != 0) + size -= DIRSIZ(ep); + if (size > 0) { + if (size >= slotneeded) { + slotstatus = FOUND; + slotoffset = ndp->ni_offset; + slotsize = ep->d_reclen; + } else if (slotstatus == NONE) { + slotfreespace += size; + if (slotoffset == -1) + slotoffset = ndp->ni_offset; + if (slotfreespace >= slotneeded) { + slotstatus = COMPACT; + slotsize = ndp->ni_offset + + ep->d_reclen - slotoffset; + } + } + } + } + + /* + * Check for a name match. + */ + if (ep->d_ino) { + if (ep->d_namlen == ndp->ni_dent.d_namlen && + !bcmp(ndp->ni_dent.d_name, ep->d_name, + (unsigned)ep->d_namlen)) + goto found; + } + prevoff = ndp->ni_offset; + ndp->ni_offset += ep->d_reclen; + entryoffsetinblock += ep->d_reclen; + if (ep->d_ino) + enduseful = ndp->ni_offset; + } +/* notfound: */ + /* + * If we started in the middle of the directory and failed + * to find our target, we must check the beginning as well. + */ + if (numdirpasses == 2) { + numdirpasses--; + ndp->ni_offset = 0; + endsearch = u.u_ncache.nc_prevoffset; + goto searchloop; + } + /* + * If creating, and at end of pathname and current + * directory has not been removed, then can consider + * allowing file to be created. + */ + if (flag == CREATE && *cp == 0 && dp->i_nlink != 0) { + /* + * Access for write is interpreted as allowing + * creation of files in the directory. + */ + if (access(dp, IWRITE)) + goto bad; + /* + * Return an indication of where the new directory + * entry should be put. If we didn't find a slot, + * then set ndp->ni_count to 0 indicating that the new + * slot belongs at the end of the directory. If we found + * a slot, then the new entry can be put in the range + * [ndp->ni_offset .. ndp->ni_offset + ndp->ni_count) + */ + if (slotstatus == NONE) { + ndp->ni_offset = roundup(dp->i_size, DIRBLKSIZ); + ndp->ni_count = 0; + enduseful = ndp->ni_offset; + } else { + ndp->ni_offset = slotoffset; + ndp->ni_count = slotsize; + if (enduseful < slotoffset + slotsize) + enduseful = slotoffset + slotsize; + } + ndp->ni_endoff = roundup(enduseful, DIRBLKSIZ); + dp->i_flag |= IUPD|ICHG; + if (bp) { + brelse(bp); + } + /* + * We return with the directory locked, so that + * the parameters we set up above will still be + * valid if we actually decide to do a direnter(). + * We return NULL to indicate that the entry doesn't + * currently exist, leaving a pointer to the (locked) + * directory inode in ndp->ni_pdir. + */ + ndp->ni_pdir = dp; + goto retNULL; + } + u.u_error = ENOENT; + goto bad; +found: + if (numdirpasses == 2) + nchstats.ncs_pass2++; + /* + * Check that directory length properly reflects presence + * of this entry. + */ + if (entryoffsetinblock + DIRSIZ(ep) > dp->i_size) { + dirbad(dp, ndp->ni_offset, "i_size too small"); + dp->i_size = entryoffsetinblock + DIRSIZ(ep); + dp->i_flag |= IUPD|ICHG; + } + + /* + * Found component in pathname. + * If the final component of path name, save information + * in the cache as to where the entry was found. + */ + if (*cp == '\0' && flag == LOOKUP) { + u.u_ncache.nc_prevoffset = ndp->ni_offset &~ (DIRBLKSIZ - 1); + u.u_ncache.nc_inumber = dp->i_number; + u.u_ncache.nc_dev = dp->i_dev; + } + /* + * Save directory entry's inode number and reclen in ndp->ni_dent, + * and release directory buffer. + */ + ndp->ni_dent.d_ino = ep->d_ino; + ndp->ni_dent.d_reclen = ep->d_reclen; + brelse(bp); + bp = NULL; + + /* + * If deleting, and at end of pathname, return + * parameters which can be used to remove file. + * If the lockparent flag isn't set, we return only + * the directory (in ndp->ni_pdir), otherwise we go + * on and lock the inode, being careful with ".". + */ + if (flag == DELETE && *cp == 0) { + /* + * Write access to directory required to delete files. + */ + if (access(dp, IWRITE)) + goto bad; + ndp->ni_pdir = dp; /* for dirremove() */ + /* + * Return pointer to current entry in ndp->ni_offset, + * and distance past previous entry (if there + * is a previous entry in this block) in ndp->ni_count. + * Save directory inode pointer in ndp->ni_pdir for dirremove(). + */ + if ((ndp->ni_offset&(DIRBLKSIZ-1)) == 0) + ndp->ni_count = 0; + else + ndp->ni_count = ndp->ni_offset - prevoff; + if (lockparent) { + if (dp->i_number == ndp->ni_dent.d_ino) + dp->i_count++; + else { + dp = iget(dp->i_dev, fs, ndp->ni_dent.d_ino); + if (dp == NULL) { + iput(ndp->ni_pdir); + goto bad; + } + /* + * If directory is "sticky", then user must own + * the directory, or the file in it, else he + * may not delete it (unless he's root). This + * implements append-only directories. + */ + if ((ndp->ni_pdir->i_mode & ISVTX) && + u.u_uid != 0 && + u.u_uid != ndp->ni_pdir->i_uid && + dp->i_uid != u.u_uid) { + iput(ndp->ni_pdir); + u.u_error = EPERM; + goto bad; + } + } + } + goto retDP; + } + + /* + * Special handling for ".." allowing chdir out of mounted + * file system: indirect .. in root inode to reevaluate + * in directory file system was mounted on. + */ + if (isdotdot) { + if (dp == u.u_rdir) { + ndp->ni_dent.d_ino = dp->i_number; + makeentry = 0; + } else if (ndp->ni_dent.d_ino == ROOTINO && + dp->i_number == ROOTINO) { + register struct mount *mp; + register dev_t d; + + d = dp->i_dev; + for (mp = &mount[1]; mp < &mount[NMOUNT]; mp++) + if (mp->m_inodp && mp->m_dev == d) { + iput(dp); + dp = mp->m_inodp; + ILOCK(dp); + dp->i_count++; + fs = dp->i_fs; + cp -= 2; /* back over .. */ + goto dirloop2; + } + } + } + + /* + * If rewriting (rename), return the inode and the + * information required to rewrite the present directory + * Must get inode of directory entry to verify it's a + * regular file, or empty directory. + */ + if ((flag == CREATE && lockparent) && *cp == 0) { + if (access(dp, IWRITE)) + goto bad; + ndp->ni_pdir = dp; /* for dirrewrite() */ + /* + * Careful about locking second inode. + * This can only occur if the target is ".". + */ + if (dp->i_number == ndp->ni_dent.d_ino) { + u.u_error = EISDIR; /* XXX */ + goto bad; + } + dp = iget(dp->i_dev, fs, ndp->ni_dent.d_ino); + if (dp == NULL) { + iput(ndp->ni_pdir); + goto bad; + } + goto retDP; + } + + /* + * Check for symbolic link, which may require us to massage the + * name before we continue translation. We do not `iput' the + * directory because we may need it again if the symbolic link + * is relative to the current directory. Instead we save it + * unlocked as "pdp". We must get the target inode before unlocking + * the directory to insure that the inode will not be removed + * before we get it. We prevent deadlock by always fetching + * inodes from the root, moving down the directory tree. Thus + * when following backward pointers ".." we must unlock the + * parent directory before getting the requested directory. + * There is a potential race condition here if both the current + * and parent directories are removed before the `iget' for the + * inode associated with ".." returns. We hope that this occurs + * infrequently since we cannot avoid this race condition without + * implementing a sophisticated deadlock detection algorithm. + * Note also that this simple deadlock detection scheme will not + * work if the file system has any hard links other than ".." + * that point backwards in the directory structure. + */ + pdp = dp; + if (isdotdot) { + IUNLOCK(pdp); /* race to get the inode */ + dp = iget(dp->i_dev, fs, ndp->ni_dent.d_ino); + if (dp == NULL) + goto bad2; + } else if (dp->i_number == ndp->ni_dent.d_ino) { + dp->i_count++; /* we want ourself, ie "." */ + } else { + dp = iget(dp->i_dev, fs, ndp->ni_dent.d_ino); + IUNLOCK(pdp); + if (dp == NULL) + goto bad2; + } + + /* + * Insert name into cache if appropriate. + */ + if (makeentry) { + if (ncp != NULL) + panic("namei: duplicating cache"); + /* + * Free the cache slot at head of lru chain. + */ + ncp = nchhead; + if (ncp) { + /* remove from lru chain */ + *ncp->nc_prev = ncp->nc_nxt; + if (ncp->nc_nxt) + ncp->nc_nxt->nc_prev = ncp->nc_prev; + else + nchtail = ncp->nc_prev; + remque(ncp); /* remove from old hash chain */ + /* grab the inode we just found */ + ncp->nc_ip = dp; + /* fill in cache info */ + ncp->nc_ino = pdp->i_number; /* parents inum */ + ncp->nc_dev = pdp->i_dev; /* & device */ + ncp->nc_idev = dp->i_dev; /* our device */ + ncp->nc_id = dp->i_id; /* identifier */ + ncp->nc_nlen = ndp->ni_dent.d_namlen; + bcopy(ndp->ni_dent.d_name, ncp->nc_name, + (unsigned)ncp->nc_nlen); + /* link at end of lru chain */ + ncp->nc_nxt = NULL; + ncp->nc_prev = nchtail; + *nchtail = ncp; + nchtail = &ncp->nc_nxt; + /* and insert on hash chain */ + insque(ncp, nhp); + } + } + +haveino: + fs = dp->i_fs; + + /* + * Check for symbolic link + */ + if ((dp->i_mode & IFMT) == IFLNK && + ((ndp->ni_nameiop & FOLLOW) || *cp == '/')) { + u_int pathlen = strlen(cp) + 1; + + if (dp->i_size + pathlen >= MAXPATHLEN - 1) { + u.u_error = ENAMETOOLONG; + goto bad2; + } + if (++nlink > MAXSYMLINKS) { + u.u_error = ELOOP; + goto bad2; + } + + bp = bread(dp->i_dev, bmap(dp, (daddr_t)0, B_READ, 0)); + if (bp->b_flags & B_ERROR) { + brelse(bp); + bp = NULL; + goto bad2; + } + /* + * Shift the rest of path further down the buffer, then + * copy link path into the first part of the buffer. + */ + bcopy(cp, path + (u_int)dp->i_size, pathlen); + bcopy(bp->b_addr, path, (u_int)dp->i_size); + brelse(bp); + bp = NULL; + cp = path; + iput(dp); + if (*cp == '/') { + irele(pdp); + while (*cp == '/') + cp++; + if ((dp = u.u_rdir) == NULL) + dp = rootdir; + ILOCK(dp); + dp->i_count++; + } else { + dp = pdp; + ILOCK(dp); + } + fs = dp->i_fs; + goto dirloop; + } + + /* + * Not a symbolic link. If more pathname, + * continue at next component, else return. + */ + if (*cp == '/') { + while (*cp == '/') + cp++; + irele(pdp); + goto dirloop; + } + if (lockparent) + ndp->ni_pdir = pdp; + else + irele(pdp); +retDP: + ndp->ni_ip = dp; + return (dp); + +bad2: + irele(pdp); +bad: + if (bp) { + brelse(bp); + } + if (dp) + iput(dp); +retNULL: + ndp->ni_ip = NULL; + return (NULL); +} + +/* + * Write a directory entry after a call to namei, using the parameters + * which it left in the u. area. The argument ip is the inode which + * the new directory entry will refer to. The u. area field ndp->ni_pdir is + * a pointer to the directory to be written, which was left locked by + * namei. Remaining parameters (ndp->ni_offset, ndp->ni_count) indicate + * how the space for the new entry is to be gotten. + */ +int +direnter(ip, ndp) + struct inode *ip; + register struct nameidata *ndp; +{ + register struct direct *ep, *nep; + register struct inode *dp = ndp->ni_pdir; + struct buf *bp; + int loc, spacefree, error = 0; + u_int dsize; + int newentrysize; + char *dirbuf; + + ndp->ni_dent.d_ino = ip->i_number; + newentrysize = DIRSIZ(&ndp->ni_dent); + if (ndp->ni_count == 0) { + /* + * If ndp->ni_count is 0, then namei could find no space in the + * directory. In this case ndp->ni_offset will be on a directory + * block boundary and we will write the new entry into a fresh + * block. + */ + if (ndp->ni_offset&(DIRBLKSIZ-1)) + panic("wdir: newblk"); + ndp->ni_dent.d_reclen = DIRBLKSIZ; + error = rdwri (UIO_WRITE, dp, (caddr_t)&ndp->ni_dent, + newentrysize, ndp->ni_offset, + IO_UNIT|IO_SYNC, (int *)0); + dp->i_size = roundup(dp->i_size, DIRBLKSIZ); + iput(dp); + return (error); + } + + /* + * If ndp->ni_count is non-zero, then namei found space for the new + * entry in the range ndp->ni_offset to ndp->ni_offset + ndp->ni_count. + * in the directory. To use this space, we may have to compact + * the entries located there, by copying them together towards + * the beginning of the block, leaving the free space in + * one usable chunk at the end. + */ + + /* + * Increase size of directory if entry eats into new space. + * This should never push the size past a new multiple of + * DIRBLKSIZE. + * + * N.B. - THIS IS AN ARTIFACT OF 4.2 AND SHOULD NEVER HAPPEN. + */ + if (ndp->ni_offset + ndp->ni_count > dp->i_size) + dp->i_size = ndp->ni_offset + ndp->ni_count; + /* + * Get the block containing the space for the new directory + * entry. Should return error by result instead of u.u_error. + */ + bp = blkatoff(dp, ndp->ni_offset, (char **)&dirbuf); + if (bp == 0) { + iput(dp); + return (u.u_error); + } + /* + * Find space for the new entry. In the simple case, the + * entry at offset base will have the space. If it does + * not, then namei arranged that compacting the region + * ndp->ni_offset to ndp->ni_offset+ndp->ni_count would yield the space. + */ + ep = (struct direct *)dirbuf; + dsize = DIRSIZ(ep); + spacefree = ep->d_reclen - dsize; + for (loc = ep->d_reclen; loc < ndp->ni_count; ) { + nep = (struct direct *)(dirbuf + loc); + if (ep->d_ino) { + /* trim the existing slot */ + ep->d_reclen = dsize; + ep = (struct direct *)((char *)ep + dsize); + } else { + /* overwrite; nothing there; header is ours */ + spacefree += dsize; + } + dsize = DIRSIZ(nep); + spacefree += nep->d_reclen - dsize; + loc += nep->d_reclen; + bcopy((caddr_t)nep, (caddr_t)ep, dsize); + } + /* + * Update the pointer fields in the previous entry (if any), + * copy in the new entry, and write out the block. + */ + if (ep->d_ino == 0) { + if (spacefree + dsize < newentrysize) + panic("wdir: compact1"); + ndp->ni_dent.d_reclen = spacefree + dsize; + } else { + if (spacefree < newentrysize) + panic("wdir: compact2"); + ndp->ni_dent.d_reclen = spacefree; + ep->d_reclen = dsize; + ep = (struct direct *)((char *)ep + dsize); + } + bcopy((caddr_t)&ndp->ni_dent, (caddr_t)ep, (u_int)newentrysize); + bwrite(bp); + dp->i_flag |= IUPD|ICHG; + if (ndp->ni_endoff && ndp->ni_endoff < dp->i_size) + itrunc(dp, (u_long)ndp->ni_endoff, 0); + iput(dp); + return (error); +} + +/* + * Remove a directory entry after a call to namei, using the + * parameters which it left in the u. area. The u. entry + * ni_offset contains the offset into the directory of the + * entry to be eliminated. The ni_count field contains the + * size of the previous record in the directory. If this + * is 0, the first entry is being deleted, so we need only + * zero the inode number to mark the entry as free. If the + * entry isn't the first in the directory, we must reclaim + * the space of the now empty record by adding the record size + * to the size of the previous entry. + */ +int +dirremove (ndp) + register struct nameidata *ndp; +{ + register struct inode *dp = ndp->ni_pdir; + register struct buf *bp; + struct direct *ep; + + if (ndp->ni_count == 0) { + /* + * First entry in block: set d_ino to zero. + */ + ndp->ni_dent.d_ino = 0; + (void) rdwri (UIO_WRITE, dp, (caddr_t) &ndp->ni_dent, + (int) DIRSIZ(&ndp->ni_dent), ndp->ni_offset, + IO_UNIT | IO_SYNC, (int*) 0); + } else { + /* + * Collapse new free space into previous entry. + */ + bp = blkatoff(dp, ndp->ni_offset - ndp->ni_count, (char **)&ep); + if (bp == 0) + return (0); + ep->d_reclen += ndp->ni_dent.d_reclen; + bwrite(bp); + dp->i_flag |= IUPD|ICHG; + } + return (1); +} + +/* + * Rewrite an existing directory entry to point at the inode + * supplied. The parameters describing the directory entry are + * set up by a call to namei. + */ +void +dirrewrite(dp, ip, ndp) + register struct inode *dp; + struct inode *ip; + register struct nameidata *ndp; +{ + + ndp->ni_dent.d_ino = ip->i_number; + u.u_error = rdwri (UIO_WRITE, dp, (caddr_t) &ndp->ni_dent, + (int) DIRSIZ(&ndp->ni_dent), ndp->ni_offset, + IO_UNIT | IO_SYNC, (int*) 0); + iput(dp); +} + +/* + * Check if a directory is empty or not. + * Inode supplied must be locked. + * + * Using a struct dirtemplate here is not precisely + * what we want, but better than using a struct direct. + * + * NB: does not handle corrupted directories. + */ +int +dirempty (ip, parentino) + register struct inode *ip; + ino_t parentino; +{ + register off_t off; + struct dirtemplate dbuf; + register struct direct *dp = (struct direct *)&dbuf; + int error, count; +#define MINDIRSIZ (sizeof (struct dirtemplate) / 2) + + for (off = 0; off < ip->i_size; off += dp->d_reclen) { + error = rdwri (UIO_READ, ip, (caddr_t) dp, MINDIRSIZ, + off, IO_UNIT, &count); + /* + * Since we read MINDIRSIZ, residual must + * be 0 unless we're at end of file. + */ + if (error || count != 0) + return (0); + /* avoid infinite loops */ + if (dp->d_reclen == 0) + return (0); + /* skip empty entries */ + if (dp->d_ino == 0) + continue; + /* accept only "." and ".." */ + if (dp->d_namlen > 2) + return (0); + if (dp->d_name[0] != '.') + return (0); + /* + * At this point d_namlen must be 1 or 2. + * 1 implies ".", 2 implies ".." if second + * char is also "." + */ + if (dp->d_namlen == 1) + continue; + if (dp->d_name[1] == '.' && dp->d_ino == parentino) + continue; + return (0); + } + return (1); +} + +/* + * Check if source directory is in the path of the target directory. + * Target is supplied locked, source is unlocked. + * The target is always iput() before returning. + */ +int +checkpath (source, target) + struct inode *source, *target; +{ + struct dirtemplate dirbuf; + register struct inode *ip; + register int error = 0; + + ip = target; + if (ip->i_number == source->i_number) { + error = EEXIST; + goto out; + } + if (ip->i_number == ROOTINO) + goto out; + + for (;;) { + if ((ip->i_mode&IFMT) != IFDIR) { + error = ENOTDIR; + break; + } + error = rdwri (UIO_READ, ip, (caddr_t) &dirbuf, + sizeof(struct dirtemplate), (off_t) 0, + IO_UNIT, (int*) 0); + if (error != 0) + break; + if (dirbuf.dotdot_namlen != 2 || + dirbuf.dotdot_name[0] != '.' || + dirbuf.dotdot_name[1] != '.') { + error = ENOTDIR; + break; + } + if (dirbuf.dotdot_ino == source->i_number) { + error = EINVAL; + break; + } + if (dirbuf.dotdot_ino == ROOTINO) + break; + iput(ip); + ip = iget(ip->i_dev, ip->i_fs, dirbuf.dotdot_ino); + if (ip == NULL) { + error = u.u_error; + break; + } + } + +out: + if (error == ENOTDIR) + printf("checkpath: .. !dir\n"); + if (ip != NULL) + iput(ip); + return (error); +} + +/* + * Name cache initialization, from main() when we are booting + */ +void +nchinit() +{ + register union nchash *nchp; + register struct namecache *ncp; + + nchhead = 0; + nchtail = &nchhead; + for (ncp = namecache; ncp < &namecache[NNAMECACHE]; ncp++) { + ncp->nc_forw = ncp; /* hash chain */ + ncp->nc_back = ncp; + ncp->nc_nxt = NULL; /* lru chain */ + *nchtail = ncp; + ncp->nc_prev = nchtail; + nchtail = &ncp->nc_nxt; + /* all else is zero already */ + } + for (nchp = nchash; nchp < &nchash[NCHHASH]; nchp++) { + nchp->nch_head[0] = nchp; + nchp->nch_head[1] = nchp; + } +} + +/* + * Cache flush, called when filesys is umounted to + * remove entries that would now be invalid + * + * The line "nxtcp = nchhead" near the end is to avoid potential problems + * if the cache lru chain is modified while we are dumping the + * inode. This makes the algorithm O(n^2), but do you think I care? + */ +void +nchinval (dev) + register dev_t dev; +{ + register struct namecache *ncp, *nxtcp; + + for (ncp = nchhead; ncp; ncp = nxtcp) { + nxtcp = ncp->nc_nxt; + if (ncp->nc_ip == NULL || + (ncp->nc_idev != dev && ncp->nc_dev != dev)) + continue; + /* free the resources we had */ + ncp->nc_idev = NODEV; + ncp->nc_dev = NODEV; + ncp->nc_id = NULL; + ncp->nc_ino = 0; + ncp->nc_ip = NULL; + remque(ncp); /* remove entry from its hash chain */ + ncp->nc_forw = ncp; /* and make a dummy one */ + ncp->nc_back = ncp; + /* delete this entry from LRU chain */ + *ncp->nc_prev = nxtcp; + if (nxtcp) + nxtcp->nc_prev = ncp->nc_prev; + else + nchtail = ncp->nc_prev; + /* cause rescan of list, it may have altered */ + nxtcp = nchhead; + /* put the now-free entry at head of LRU */ + ncp->nc_nxt = nxtcp; + ncp->nc_prev = &nchhead; + nxtcp->nc_prev = &ncp->nc_nxt; + nchhead = ncp; + } +} + +/* + * Name cache invalidation of all entries. + */ +void +cinvalall() +{ + register struct namecache *ncp, *encp = &namecache[NNAMECACHE]; + + for (ncp = namecache; ncp < encp; ncp++) + ncp->nc_id = 0; +} diff --git a/sys/kernel/ufs_subr.c b/sys/kernel/ufs_subr.c new file mode 100644 index 0000000..c9300f6 --- /dev/null +++ b/sys/kernel/ufs_subr.c @@ -0,0 +1,145 @@ +/* + * Copyright (c) 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "param.h" +#include "user.h" +#include "proc.h" +#include "fs.h" +#include "inode.h" +#include "buf.h" +#include "mount.h" +#include "kernel.h" +#include "systm.h" + +int updlock; /* lock for sync */ + +/* + * Go through the mount table looking for filesystems which have been modified. + * For each "dirty" filesystem call 'ufs_sync' to flush changed inodes, data + * blocks and the superblock to disc. + */ +void +sync() +{ + register struct mount *mp; + register struct fs *fs; + int async; + + if (updlock) + return; + updlock++; + for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) { + if (mp->m_inodp == NULL || mp->m_dev == NODEV) + continue; + fs = &mp->m_filsys; + if (fs->fs_fmod == 0 || fs->fs_ilock || fs->fs_flock) + continue; + async = mp->m_flags & MNT_ASYNC; + mp->m_flags &= ~MNT_ASYNC; + ufs_sync(mp); + mp->m_flags |= async; + } + updlock = 0; +} + +/* + * Flush all the blocks associated with an inode. + * There are two strategies based on the size of the file; + * large files are those with more than NBUF/2 blocks. + * Large files + * Walk through the buffer pool and push any dirty pages + * associated with the device on which the file resides. + * Small files + * Look up each block in the file to see if it is in the + * buffer pool writing any that are found to disk. + * Note that we make a more stringent check of + * writing out any block in the buffer pool that may + * overlap the inode. This brings the inode up to + * date with recent mods to the cooked device. + */ +void +syncip(ip) + struct inode *ip; +{ + register struct buf *bp; + register struct buf *lastbufp; + long lbn, lastlbn; + register int s; + daddr_t blkno; + + lastlbn = howmany(ip->i_size, DEV_BSIZE); + if (lastlbn < NBUF / 2) { + for (lbn = 0; lbn < lastlbn; lbn++) { + blkno = fsbtodb(bmap(ip, lbn, B_READ, 0)); + blkflush(ip->i_dev, blkno); + } + } else { + lastbufp = &buf[NBUF]; + for (bp = buf; bp < lastbufp; bp++) { + if (bp->b_dev != ip->i_dev || + (bp->b_flags & B_DELWRI) == 0) + continue; + s = splbio(); + if (bp->b_flags & B_BUSY) { + bp->b_flags |= B_WANTED; + sleep((caddr_t)bp, PRIBIO+1); + splx(s); + bp--; + continue; + } + splx(s); + notavail(bp); + bwrite(bp); + } + } + ip->i_flag |= ICHG; + iupdat(ip, &time, &time, 1); +} + +/* + * Check that a specified block number is in range. + */ +int +badblock (fp, bn) + register struct fs *fp; + daddr_t bn; +{ + if (bn < fp->fs_isize || bn >= fp->fs_fsize) { + printf("bad block %D, ",bn); + fserr(fp, "bad block"); + return (1); + } + return (0); +} + +/* + * Getfs maps a device number into a pointer to the incore super block. + * + * The algorithm is a linear search through the mount table. A + * consistency check of the super block magic number is performed. + * + * panic: no fs -- the device is not mounted. + * this "cannot happen" + */ +struct fs * +getfs(dev) + dev_t dev; +{ + register struct mount *mp; + register struct fs *fs; + + for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) { + if (mp->m_inodp == NULL || mp->m_dev != dev) + continue; + fs = &mp->m_filsys; + if (fs->fs_nfree > NICFREE || fs->fs_ninode > NICINOD) { + fserr(fs, "bad count"); + fs->fs_nfree = fs->fs_ninode = 0; + } + return(fs); + } + printf("no fs on dev %u/%u\n",major(dev), minor(dev)); + return((struct fs *) NULL); +} diff --git a/sys/kernel/ufs_syscalls.c b/sys/kernel/ufs_syscalls.c new file mode 100644 index 0000000..6b4362e --- /dev/null +++ b/sys/kernel/ufs_syscalls.c @@ -0,0 +1,1338 @@ +/* + * Copyright (c) 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "param.h" +#include "systm.h" +#include "user.h" +#include "inode.h" +#include "namei.h" +#include "fs.h" +#include "file.h" +#include "stat.h" +#include "kernel.h" +#include "proc.h" + +/* + * Common routine for chroot and chdir. + */ +static void +chdirec(ipp) + register struct inode **ipp; +{ + register struct inode *ip; + struct a { + char *fname; + } *uap = (struct a *)u.u_arg; + struct nameidata nd; + register struct nameidata *ndp = &nd; + + NDINIT (ndp, LOOKUP, FOLLOW, uap->fname); + ip = namei(ndp); + if (ip == NULL) + return; + if ((ip->i_mode&IFMT) != IFDIR) { + u.u_error = ENOTDIR; + goto bad; + } + if (access(ip, IEXEC)) + goto bad; + iunlock(ip); + if (*ipp) + irele(*ipp); + *ipp = ip; + return; + +bad: + iput(ip); +} + +/* + * Change current working directory (``.''). + */ +void +chdir() +{ + chdirec (&u.u_cdir); +} + +void +fchdir() +{ + register struct a { + int fd; + } *uap = (struct a *)u.u_arg; + register struct inode *ip; + + ip = getinode (uap->fd); + if (ip == NULL) + return; + ilock(ip); + if ((ip->i_mode & IFMT) != IFDIR) { + u.u_error = ENOTDIR; + goto bad; + } + if (access (ip, IEXEC)) + goto bad; + iunlock(ip); + ip->i_count++; + irele(u.u_cdir); + u.u_cdir = ip; + return; +bad: + iunlock(ip); + return; +} + +/* + * Change notion of root (``/'') directory. + */ +void +chroot() +{ + if (suser()) + chdirec (&u.u_rdir); +} + +/* + * Check permissions, allocate an open file structure, + * and call the device open routine if any. + */ +static int +copen (mode, cmode, fname) + int mode; + int cmode; + caddr_t fname; +{ + register struct inode *ip; + register struct file *fp; + struct nameidata nd; + register struct nameidata *ndp = &nd; + int indx, type, flags, error; + + if (! fname) + fname = ""; +//printf ("copen (mode=%#o, cmode=%#o, fname=%#x '%s')\n", mode, cmode, fname, fname); + fp = falloc(); + if (fp == NULL) { +//printf ("copen: falloc failed, errno=%d\n", u.u_error); + return(u.u_error); /* XXX */ + } + flags = FFLAGS(mode); /* convert from open to kernel flags */ + fp->f_flag = flags & FMASK; + fp->f_type = DTYPE_INODE; + cmode &= 077777 & ~ISVTX; + indx = u.u_rval; + u.u_dupfd = -indx - 1; + NDINIT (ndp, LOOKUP, FOLLOW, fname); + + /* + * ENODEV is returned by the 'fdopen()' routine - see the comments in that + * routine for details about the hack being used. + * + * ENXIO only comes out of the 'portal fs' code (which 2.11BSD does not have). + * It probably should have been removed during the port of the 'file descriptor + * driver' since it's a "can not happen" event. + * + * u.u_dupfd is used because there the space in the proc structure is at a + * premium in 2.11 while space in the u structure is relatively free. Also + * there were more unused (pad) fields available in 'u' as compared to 'proc'. + */ + error = vn_open(ndp, flags, cmode); + if (error) { +//printf ("copen: vn_open failed, errno=%d\n", error); + fp->f_count = 0; + if ((error == ENODEV || error == ENXIO) && + u.u_dupfd >= 0 && + (error = dupfdopen(indx,u.u_dupfd,flags,error) == 0)) { + u.u_rval = indx; + return(0); + } + u.u_ofile[indx] = NULL; + return(error); + } + ip = ndp->ni_ip; + u.u_dupfd = 0; + + fp->f_data = (caddr_t)ip; + + if (flags & (O_EXLOCK | O_SHLOCK)) { + if (flags & O_EXLOCK) + type = LOCK_EX; + else + type = LOCK_SH; + if (flags & FNONBLOCK) + type |= LOCK_NB; + error = ino_lock(fp, type); + if (error) { +//printf ("copen: ino_lock failed, errno=%d\n", error); + closef(fp); + u.u_ofile[indx] = NULL; + } + } +//printf ("copen returned errno=%d\n", error); + return(error); +} + +/* + * Open system call. + */ +void +open() +{ + register struct a { + char *fname; + int mode; + int crtmode; + } *uap = (struct a *) u.u_arg; + + u.u_error = copen (uap->mode, uap->crtmode, uap->fname); +} + +/* + * Mknod system call + */ +void +mknod() +{ + register struct inode *ip; + register struct a { + char *fname; + int fmode; + int dev; + } *uap = (struct a *)u.u_arg; + struct nameidata nd; + register struct nameidata *ndp = &nd; + + if (! suser()) + return; + NDINIT (ndp, CREATE, NOFOLLOW, uap->fname); + ip = namei(ndp); + if (ip != NULL) { + u.u_error = EEXIST; + goto out; + } + if (u.u_error) + return; + ip = maknode (uap->fmode, ndp); + if (ip == NULL) + return; + switch (ip->i_mode & IFMT) { + + case IFMT: /* used by badsect to flag bad sectors */ + case IFCHR: + case IFBLK: + if (uap->dev) { + /* + * Want to be able to use this to make badblock + * inodes, so don't truncate the dev number. + */ + ip->i_rdev = uap->dev; + ip->i_dummy = 0; + ip->i_flag |= IACC|IUPD|ICHG; + } + } +out: + iput(ip); +} + +/* + * link system call + */ +void +link() +{ + register struct inode *ip, *xp; + register struct a { + char *target; + char *linkname; + } *uap = (struct a *)u.u_arg; + struct nameidata nd; + register struct nameidata *ndp = &nd; + + NDINIT (ndp, LOOKUP, FOLLOW, uap->target); + ip = namei(ndp); /* well, this routine is doomed anyhow */ + if (ip == NULL) + return; + if ((ip->i_mode&IFMT) == IFDIR && !suser()) { + iput(ip); + return; + } + if (ip->i_flags & (IMMUTABLE|APPEND)) { + u.u_error = EPERM; + iput(ip); + return; + } + ip->i_nlink++; + ip->i_flag |= ICHG; + iupdat(ip, &time, &time, 1); + iunlock(ip); + ndp->ni_nameiop = CREATE; + ndp->ni_dirp = (caddr_t)uap->linkname; + xp = namei(ndp); + if (xp != NULL) { + u.u_error = EEXIST; + iput(xp); + goto out; + } + if (u.u_error) + goto out; + if (ndp->ni_pdir->i_dev != ip->i_dev) { + iput(ndp->ni_pdir); + u.u_error = EXDEV; + goto out; + } + u.u_error = direnter(ip, ndp); +out: + if (u.u_error) { + ip->i_nlink--; + ip->i_flag |= ICHG; + } + irele(ip); +} + +/* + * symlink -- make a symbolic link + */ +void +symlink() +{ + register struct a { + char *target; + char *linkname; + } *uap = (struct a *)u.u_arg; + register struct inode *ip; + char *tp; + int c, nc; + struct nameidata nd; + register struct nameidata *ndp = &nd; + + tp = uap->target; + nc = 0; + for (;;) { + if (baduaddr (tp)) { + u.u_error = EFAULT; + return; + } + c = (u_char) *tp; + if (c == 0) + break; + tp++; + nc++; + } + NDINIT (ndp, CREATE, NOFOLLOW, uap->linkname); + ip = namei(ndp); + if (ip) { + iput(ip); + u.u_error = EEXIST; + return; + } + if (u.u_error) + return; + ip = maknode (IFLNK | 0777, ndp); + if (ip == NULL) + return; + u.u_error = rdwri (UIO_WRITE, ip, uap->target, nc, (off_t) 0, + IO_UNIT, (int*) 0); + /* handle u.u_error != 0 */ + iput(ip); +} + +/* + * Unlink system call. + * Hard to avoid races here, especially + * in unlinking directories. + */ +void +unlink() +{ + register struct a { + char *fname; + } *uap = (struct a *)u.u_arg; + register struct inode *ip, *dp; + struct nameidata nd; + register struct nameidata *ndp = &nd; + + NDINIT (ndp, DELETE, LOCKPARENT, uap->fname); + ip = namei(ndp); + if (ip == NULL) + return; + dp = ndp->ni_pdir; + if ((ip->i_mode&IFMT) == IFDIR && !suser()) + goto out; + /* + * Don't unlink a mounted file. + */ + if (ip->i_dev != dp->i_dev) { + u.u_error = EBUSY; + goto out; + } + if ((ip->i_flags & (IMMUTABLE|APPEND)) || (dp->i_flags & APPEND)) { + u.u_error = EPERM; + goto out; + } + if (dirremove(ndp)) { + ip->i_nlink--; + ip->i_flag |= ICHG; + } +out: + if (dp == ip) + irele(ip); + else + iput(ip); + iput(dp); +} + +/* + * Access system call + */ +void +saccess() +{ + uid_t t_uid; + gid_t t_gid; + register struct inode *ip; + register struct a { + char *fname; + int fmode; + } *uap = (struct a *)u.u_arg; + struct nameidata nd; + register struct nameidata *ndp = &nd; + + t_uid = u.u_uid; + t_gid = u.u_groups[0]; + u.u_uid = u.u_ruid; + u.u_groups[0] = u.u_rgid; + NDINIT (ndp, LOOKUP, FOLLOW, uap->fname); + ip = namei(ndp); + if (ip != NULL) { + if ((uap->fmode&R_OK) && access(ip, IREAD)) + goto done; + if ((uap->fmode&W_OK) && access(ip, IWRITE)) + goto done; + if ((uap->fmode&X_OK) && access(ip, IEXEC)) + goto done; +done: + iput(ip); + } + u.u_uid = t_uid; + u.u_groups[0] = t_gid; +} + +static void +stat1 (follow) + int follow; +{ + register struct inode *ip; + register struct a { + char *fname; + struct stat *ub; + } *uap = (struct a *)u.u_arg; + struct stat sb; + struct nameidata nd; + register struct nameidata *ndp = &nd; + + NDINIT (ndp, LOOKUP, follow, uap->fname); + ip = namei(ndp); + if (ip == NULL) + return; + (void) ino_stat(ip, &sb); + iput(ip); + u.u_error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); +} + +/* + * Stat system call. This version follows links. + */ +void +stat() +{ + stat1 (FOLLOW); +} + +/* + * Lstat system call. This version does not follow links. + */ +void +lstat() +{ + stat1 (NOFOLLOW); +} + +/* + * Return target name of a symbolic link + */ +void +readlink() +{ + register struct inode *ip; + register struct a { + char *name; + char *buf; + int count; + } *uap = (struct a *)u.u_arg; + struct nameidata nd; + register struct nameidata *ndp = &nd; + int resid; + + NDINIT (ndp, LOOKUP, NOFOLLOW, uap->name); + ip = namei(ndp); + if (ip == NULL) + return; + if ((ip->i_mode&IFMT) != IFLNK) { + u.u_error = EINVAL; + goto out; + } + u.u_error = rdwri (UIO_READ, ip, uap->buf, uap->count, (off_t) 0, + IO_UNIT, &resid); +out: + iput(ip); + u.u_rval = uap->count - resid; +} + +static int +chflags1 (ip, flags) + register struct inode *ip; + u_short flags; +{ + struct vattr vattr; + + VATTR_NULL(&vattr); + vattr.va_flags = flags; + return(ufs_setattr(ip, &vattr)); +} + +/* + * change flags of a file given pathname. + */ +void +chflags() +{ + register struct inode *ip; + register struct a { + char *fname; + u_int flags; + } *uap = (struct a *)u.u_arg; + struct nameidata nd; + register struct nameidata *ndp = &nd; + + NDINIT (ndp, LOOKUP, FOLLOW, uap->fname); + if ((ip = namei(ndp)) == NULL) + return; + u.u_error = chflags1 (ip, uap->flags); + iput(ip); +} + +/* + * change flags of a file given file descriptor. + */ +void +fchflags() +{ + register struct a { + int fd; + u_int flags; + } *uap = (struct a *)u.u_arg; + register struct inode *ip; + + ip = getinode (uap->fd); + if (ip == NULL) + return; + ilock(ip); + u.u_error = chflags1 (ip, uap->flags); + iunlock(ip); +} + +/* + * Change mode of a file given path name. + */ +void +chmod() +{ + register struct inode *ip; + register struct a { + char *fname; + int fmode; + } *uap = (struct a *)u.u_arg; + struct vattr vattr; + struct nameidata nd; + register struct nameidata *ndp = &nd; + + NDINIT (ndp, LOOKUP, FOLLOW, uap->fname); + ip = namei(ndp); + if (!ip) + return; + VATTR_NULL(&vattr); + vattr.va_mode = uap->fmode & 07777; + u.u_error = ufs_setattr(ip, &vattr); + iput(ip); +} + +/* + * Change mode of a file given a file descriptor. + */ +void +fchmod() +{ + register struct a { + int fd; + int fmode; + } *uap = (struct a *)u.u_arg; + register struct inode *ip; + struct vattr vattr; + + if ((ip = getinode(uap->fd)) == NULL) + return; + ilock(ip); + VATTR_NULL(&vattr); + vattr.va_mode = uap->fmode & 07777; + u.u_error = ufs_setattr(ip, &vattr); + iunlock(ip); +} + +/* + * Change the mode on a file. This routine is called from ufs_setattr. + * Inode must be locked before calling. + */ +int +chmod1(ip, mode) + register struct inode *ip; + register int mode; +{ + + if (u.u_uid != ip->i_uid && !suser()) + return(u.u_error); + if (u.u_uid) { + if ((ip->i_mode & IFMT) != IFDIR && (mode & ISVTX)) + return(EFTYPE); + if (!groupmember(ip->i_gid) && (mode & ISGID)) + return(EPERM); + } + ip->i_mode &= ~07777; /* why? */ + ip->i_mode |= mode&07777; + ip->i_flag |= ICHG; + return (0); +} + +/* + * Set ownership given a path name. + */ +void +chown() +{ + register struct inode *ip; + register struct a { + char *fname; + int uid; + int gid; + } *uap = (struct a *)u.u_arg; + struct nameidata nd; + register struct nameidata *ndp = &nd; + struct vattr vattr; + + NDINIT (ndp, LOOKUP, NOFOLLOW, uap->fname); + ip = namei(ndp); + if (ip == NULL) + return; + VATTR_NULL(&vattr); + vattr.va_uid = uap->uid; + vattr.va_gid = uap->gid; + u.u_error = ufs_setattr(ip, &vattr); + iput(ip); +} + +/* + * Set ownership given a file descriptor. + */ +void +fchown() +{ + register struct a { + int fd; + int uid; + int gid; + } *uap = (struct a *)u.u_arg; + register struct inode *ip; + struct vattr vattr; + + if ((ip = getinode(uap->fd)) == NULL) + return; + ilock(ip); + VATTR_NULL(&vattr); + vattr.va_uid = uap->uid; + vattr.va_gid = uap->gid; + u.u_error = ufs_setattr(ip, &vattr); + iunlock(ip); +} + +/* + * Perform chown operation on inode ip. This routine called from ufs_setattr. + * inode must be locked prior to call. + */ +int +chown1 (ip, uid, gid) + register struct inode *ip; + register int uid, gid; +{ + int ouid, ogid; + + if (uid == -1) + uid = ip->i_uid; + if (gid == -1) + gid = ip->i_gid; + /* + * If we don't own the file, are trying to change the owner + * of the file, or are not a member of the target group, + * the caller must be superuser or the call fails. + */ + if ((u.u_uid != ip->i_uid || uid != ip->i_uid || + !groupmember((gid_t)gid)) && !suser()) + return (u.u_error); + ouid = ip->i_uid; + ogid = ip->i_gid; + ip->i_uid = uid; + ip->i_gid = gid; + if (ouid != uid || ogid != gid) + ip->i_flag |= ICHG; + if (ouid != uid && u.u_uid != 0) + ip->i_mode &= ~ISUID; + if (ogid != gid && u.u_uid != 0) + ip->i_mode &= ~ISGID; + return (0); +} + +/* + * Truncate a file given its path name. + */ +void +truncate() +{ + register struct a { + char *fname; + off_t length; + } *uap = (struct a *)u.u_arg; + register struct inode *ip; + struct nameidata nd; + register struct nameidata *ndp = &nd; + struct vattr vattr; + + NDINIT (ndp, LOOKUP, FOLLOW, uap->fname); + ip = namei(ndp); + if (ip == NULL) + return; + if (access(ip, IWRITE)) + goto bad; + VATTR_NULL(&vattr); + vattr.va_size = uap->length; + u.u_error = ufs_setattr(ip, &vattr); +bad: + iput(ip); +} + +/* + * Truncate a file given a file descriptor. + */ +void +ftruncate() +{ + register struct a { + int fd; + off_t length; + } *uap = (struct a *)u.u_arg; + register struct inode *ip; + register struct file *fp; + struct vattr vattr; + + if ((fp = getf(uap->fd)) == NULL) + return; + if (!(fp->f_flag&FWRITE) || (fp->f_type != DTYPE_INODE)) { + u.u_error = EINVAL; + return; + } + ip = (struct inode *)fp->f_data; + ilock(ip); + VATTR_NULL(&vattr); + vattr.va_size = uap->length; + u.u_error = ufs_setattr(ip, &vattr); + iunlock(ip); +} + +/* + * Rename system call. + * rename("foo", "bar"); + * is essentially + * unlink("bar"); + * link("foo", "bar"); + * unlink("foo"); + * but ``atomically''. Can't do full commit without saving state in the + * inode on disk which isn't feasible at this time. Best we can do is + * always guarantee the target exists. + * + * Basic algorithm is: + * + * 1) Bump link count on source while we're linking it to the + * target. This also insure the inode won't be deleted out + * from underneath us while we work (it may be truncated by + * a concurrent `trunc' or `open' for creation). + * 2) Link source to destination. If destination already exists, + * delete it first. + * 3) Unlink source reference to inode if still around. If a + * directory was moved and the parent of the destination + * is different from the source, patch the ".." entry in the + * directory. + * + * Source and destination must either both be directories, or both + * not be directories. If target is a directory, it must be empty. + */ +void +rename() +{ + struct a { + char *from; + char *to; + } *uap = (struct a *)u.u_arg; + register struct inode *ip, *xp, *dp; + struct dirtemplate dirbuf; + int doingdirectory = 0, oldparent = 0, newparent = 0; + struct nameidata nd; + register struct nameidata *ndp = &nd; + int error = 0; + + NDINIT (ndp, DELETE, LOCKPARENT, uap->from); + ip = namei(ndp); + if (ip == NULL) + return; + dp = ndp->ni_pdir; + /* + * 'from' file can not be renamed if it is immutable/appendonly or if its + * parent directory is append only. + */ + if ((ip->i_flags & (IMMUTABLE|APPEND)) || (dp->i_flags & APPEND)) { + iput(dp); + if (dp == ip) + irele(ip); + else + iput(ip); + u.u_error = EPERM; + return; + } + + if ((ip->i_mode&IFMT) == IFDIR) { + register struct direct *d; + + d = &ndp->ni_dent; + /* + * Avoid ".", "..", and aliases of "." for obvious reasons. + */ + if ((d->d_namlen == 1 && d->d_name[0] == '.') || + (d->d_namlen == 2 && bcmp(d->d_name, "..", 2) == 0) || + (dp == ip) || (ip->i_flag & IRENAME)) { + iput(dp); + if (dp == ip) + irele(ip); + else + iput(ip); + u.u_error = EINVAL; + return; + } + ip->i_flag |= IRENAME; + oldparent = dp->i_number; + doingdirectory++; + } + iput(dp); + + /* + * 1) Bump link count while we're moving stuff + * around. If we crash somewhere before + * completing our work, the link count + * may be wrong, but correctable. + */ + ip->i_nlink++; + ip->i_flag |= ICHG; + iupdat(ip, &time, &time, 1); + iunlock(ip); + + /* + * When the target exists, both the directory + * and target inodes are returned locked. + */ + ndp->ni_nameiop = CREATE | LOCKPARENT | NOCACHE; + ndp->ni_dirp = (caddr_t)uap->to; + xp = namei(ndp); + if (u.u_error) { + error = u.u_error; + goto out; + } + dp = ndp->ni_pdir; + /* + * rename can not be done if 'to' file exists and is immutable/appendonly + * or if the directory is append only (this is because an existing 'to' + * has to be deleted first and that is illegal in an appendonly directory). + */ + if (xp && ((xp->i_flags & (IMMUTABLE|APPEND)) || (dp->i_flags & APPEND))) { + error = EPERM; + goto bad; + } + + /* + * If ".." must be changed (ie the directory gets a new + * parent) then the source directory must not be in the + * directory heirarchy above the target, as this would + * orphan everything below the source directory. Also + * the user must have write permission in the source so + * as to be able to change "..". We must repeat the call + * to namei, as the parent directory is unlocked by the + * call to checkpath(). + */ + if (oldparent != dp->i_number) + newparent = dp->i_number; + if (doingdirectory && newparent) { + if (access(ip, IWRITE)) + goto bad; + do { + dp = ndp->ni_pdir; + if (xp != NULL) + iput(xp); + u.u_error = checkpath(ip, dp); + if (u.u_error) + goto out; + xp = namei(ndp); + if (u.u_error) { + error = u.u_error; + goto out; + } + } while (dp != ndp->ni_pdir); + } + /* + * 2) If target doesn't exist, link the target + * to the source and unlink the source. + * Otherwise, rewrite the target directory + * entry to reference the source inode and + * expunge the original entry's existence. + */ + if (xp == NULL) { + if (dp->i_dev != ip->i_dev) { + error = EXDEV; + goto bad; + } + /* + * Account for ".." in new directory. + * When source and destination have the same + * parent we don't fool with the link count. + */ + if (doingdirectory && newparent) { + dp->i_nlink++; + dp->i_flag |= ICHG; + iupdat(dp, &time, &time, 1); + } + error = direnter(ip, ndp); + if (error) + goto out; + } else { + if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev) { + error = EXDEV; + goto bad; + } + /* + * Short circuit rename(foo, foo). + */ + if (xp->i_number == ip->i_number) + goto bad; + /* + * If the parent directory is "sticky", then the user must + * own the parent directory, or the destination of the rename, + * otherwise the destination may not be changed (except by + * root). This implements append-only directories. + */ + if ((dp->i_mode & ISVTX) && u.u_uid != 0 && + u.u_uid != dp->i_uid && xp->i_uid != u.u_uid) { + error = EPERM; + goto bad; + } + /* + * Target must be empty if a directory + * and have no links to it. + * Also, insure source and target are + * compatible (both directories, or both + * not directories). + */ + if ((xp->i_mode&IFMT) == IFDIR) { + if (!dirempty(xp, dp->i_number) || xp->i_nlink > 2) { + error = ENOTEMPTY; + goto bad; + } + if (!doingdirectory) { + error = ENOTDIR; + goto bad; + } + cacheinval(dp); + } else if (doingdirectory) { + error = EISDIR; + goto bad; + } + dirrewrite(dp, ip, ndp); + if (u.u_error) { + error = u.u_error; + goto bad1; + } + /* + * Adjust the link count of the target to + * reflect the dirrewrite above. If this is + * a directory it is empty and there are + * no links to it, so we can squash the inode and + * any space associated with it. We disallowed + * renaming over top of a directory with links to + * it above, as the remaining link would point to + * a directory without "." or ".." entries. + */ + xp->i_nlink--; + if (doingdirectory) { + if (--xp->i_nlink != 0) + panic("rename: lnk dir"); + itrunc(xp, (u_long)0, 0); /* IO_SYNC? */ + } + xp->i_flag |= ICHG; + iput(xp); + xp = NULL; + } + + /* + * 3) Unlink the source. + */ + NDINIT (ndp, DELETE, LOCKPARENT, uap->from); + xp = namei(ndp); + if (xp != NULL) + dp = ndp->ni_pdir; + else + dp = NULL; + /* + * Insure that the directory entry still exists and has not + * changed while the new name has been entered. If the source is + * a file then the entry may have been unlinked or renamed. In + * either case there is no further work to be done. If the source + * is a directory then it cannot have been rmdir'ed; its link + * count of three would cause a rmdir to fail with ENOTEMPTY. + * The IRENAME flag insures that it cannot be moved by another + * rename. + */ + if (xp != ip) { + if (doingdirectory) + panic("rename: lost dir entry"); + } else { + /* + * If the source is a directory with a + * new parent, the link count of the old + * parent directory must be decremented + * and ".." set to point to the new parent. + */ + if (doingdirectory && newparent) { + dp->i_nlink--; + dp->i_flag |= ICHG; + error = rdwri (UIO_READ, xp, (caddr_t) &dirbuf, + sizeof(struct dirtemplate), (off_t) 0, + IO_UNIT, (int*) 0); + + if (error == 0) { + if (dirbuf.dotdot_namlen != 2 || + dirbuf.dotdot_name[0] != '.' || + dirbuf.dotdot_name[1] != '.') { + printf("rename: mangled dir\n"); + } else { + dirbuf.dotdot_ino = newparent; + (void) rdwri (UIO_WRITE, xp, + (caddr_t) &dirbuf, + sizeof(struct dirtemplate), + (off_t) 0, + IO_UNIT | IO_SYNC, (int*) 0); + cacheinval(dp); + } + } + } + if (dirremove(ndp)) { + xp->i_nlink--; + xp->i_flag |= ICHG; + } + xp->i_flag &= ~IRENAME; + if (error == 0) /* XXX conservative */ + error = u.u_error; + } + if (dp) + iput(dp); + if (xp) + iput(xp); + irele(ip); + if (error) + u.u_error = error; + return; + +bad: + iput(dp); +bad1: + if (xp) + iput(xp); +out: + ip->i_nlink--; + ip->i_flag |= ICHG; + irele(ip); + if (error) + u.u_error = error; +} + +/* + * Make a new file. + */ +struct inode * +maknode (mode, ndp) + int mode; + register struct nameidata *ndp; +{ + register struct inode *ip; + register struct inode *pdir = ndp->ni_pdir; + + ip = ialloc(pdir); + if (ip == NULL) { + iput(pdir); + return (NULL); + } + ip->i_flag |= IACC|IUPD|ICHG; + if ((mode & IFMT) == 0) + mode |= IFREG; + ip->i_mode = mode & ~u.u_cmask; + ip->i_nlink = 1; + ip->i_uid = u.u_uid; + ip->i_gid = pdir->i_gid; + if (ip->i_mode & ISGID && !groupmember(ip->i_gid)) + ip->i_mode &= ~ISGID; + /* + * Make sure inode goes to disk before directory entry. + */ + iupdat(ip, &time, &time, 1); + u.u_error = direnter(ip, ndp); + if (u.u_error) { + /* + * Write error occurred trying to update directory + * so must deallocate the inode. + */ + ip->i_nlink = 0; + ip->i_flag |= ICHG; + iput(ip); + return (NULL); + } + ndp->ni_ip = ip; + return (ip); +} + +/* + * A virgin directory (no blushing please). + */ +const struct dirtemplate mastertemplate = { + 0, 12, 1, ".", + 0, DIRBLKSIZ - 12, 2, "..", +}; + +/* + * Mkdir system call + */ +void +mkdir() +{ + register struct a { + char *name; + int dmode; + } *uap = (struct a *)u.u_arg; + register struct inode *ip, *dp; + struct dirtemplate dirtemplate; + struct nameidata nd; + register struct nameidata *ndp = &nd; + + NDINIT (ndp, CREATE, NOFOLLOW, uap->name); + ip = namei(ndp); + if (u.u_error) + return; + if (ip != NULL) { + iput(ip); + u.u_error = EEXIST; + return; + } + dp = ndp->ni_pdir; + uap->dmode &= 0777; + uap->dmode |= IFDIR; + /* + * Must simulate part of maknode here + * in order to acquire the inode, but + * not have it entered in the parent + * directory. The entry is made later + * after writing "." and ".." entries out. + */ + ip = ialloc(dp); + if (ip == NULL) { + iput(dp); + return; + } + ip->i_flag |= IACC|IUPD|ICHG; + ip->i_mode = uap->dmode & ~u.u_cmask; + ip->i_nlink = 2; + ip->i_uid = u.u_uid; + ip->i_gid = dp->i_gid; + iupdat(ip, &time, &time, 1); + + /* + * Bump link count in parent directory + * to reflect work done below. Should + * be done before reference is created + * so reparation is possible if we crash. + */ + dp->i_nlink++; + dp->i_flag |= ICHG; + iupdat(dp, &time, &time, 1); + + /* + * Initialize directory with "." + * and ".." from static template. + */ + dirtemplate = mastertemplate; + dirtemplate.dot_ino = ip->i_number; + dirtemplate.dotdot_ino = dp->i_number; + u.u_error = rdwri (UIO_WRITE, ip, (caddr_t) &dirtemplate, + sizeof (dirtemplate), (off_t) 0, IO_UNIT | IO_SYNC, (int*) 0); + if (u.u_error) { + dp->i_nlink--; + dp->i_flag |= ICHG; + goto bad; + } + ip->i_size = DIRBLKSIZ; + /* + * Directory all set up, now + * install the entry for it in + * the parent directory. + */ + u.u_error = direnter(ip, ndp); + dp = NULL; + if (u.u_error) { + NDINIT (ndp, LOOKUP, NOCACHE, uap->name); + dp = namei(ndp); + if (dp) { + dp->i_nlink--; + dp->i_flag |= ICHG; + } + } +bad: + /* + * No need to do an explicit itrunc here, + * irele will do this for us because we set + * the link count to 0. + */ + if (u.u_error) { + ip->i_nlink = 0; + ip->i_flag |= ICHG; + } + if (dp) + iput(dp); + iput(ip); +} + +/* + * Rmdir system call. + */ +void +rmdir() +{ + struct a { + char *name; + } *uap = (struct a *)u.u_arg; + register struct inode *ip, *dp; + struct nameidata nd; + register struct nameidata *ndp = &nd; + + NDINIT (ndp, DELETE, LOCKPARENT, uap->name); + ip = namei(ndp); + if (ip == NULL) + return; + dp = ndp->ni_pdir; + /* + * No rmdir "." please. + */ + if (dp == ip) { + irele(dp); + iput(ip); + u.u_error = EINVAL; + return; + } + if ((ip->i_mode&IFMT) != IFDIR) { + u.u_error = ENOTDIR; + goto out; + } + /* + * Don't remove a mounted on directory. + */ + if (ip->i_dev != dp->i_dev) { + u.u_error = EBUSY; + goto out; + } + /* + * Verify the directory is empty (and valid). + * (Rmdir ".." won't be valid since + * ".." will contain a reference to + * the current directory and thus be + * non-empty.) + */ + if (ip->i_nlink != 2 || !dirempty(ip, dp->i_number)) { + u.u_error = ENOTEMPTY; + goto out; + } + if ((dp->i_flags & APPEND) || (ip->i_flags & (IMMUTABLE|APPEND))) { + u.u_error = EPERM; + goto out; + } + /* + * Delete reference to directory before purging + * inode. If we crash in between, the directory + * will be reattached to lost+found, + */ + if (dirremove(ndp) == 0) + goto out; + dp->i_nlink--; + dp->i_flag |= ICHG; + cacheinval(dp); + iput(dp); + dp = NULL; + /* + * Truncate inode. The only stuff left + * in the directory is "." and "..". The + * "." reference is inconsequential since + * we're quashing it. The ".." reference + * has already been adjusted above. We've + * removed the "." reference and the reference + * in the parent directory, but there may be + * other hard links so decrement by 2 and + * worry about them later. + */ + ip->i_nlink -= 2; + itrunc(ip, (u_long)0, 0); /* IO_SYNC? */ + cacheinval(ip); +out: + if (dp) + iput(dp); + iput(ip); +} + +/* + * Get an inode pointer of a file descriptor. + */ +struct inode * +getinode(fdes) + int fdes; +{ + register struct file *fp; + + if ((unsigned)fdes >= NOFILE || (fp = u.u_ofile[fdes]) == NULL) { + u.u_error = EBADF; + return ((struct inode *)0); + } + if (fp->f_type != DTYPE_INODE) { + u.u_error = EINVAL; + return ((struct inode *)0); + } + return((struct inode *)fp->f_data); +} diff --git a/sys/kernel/ufs_syscalls2.c b/sys/kernel/ufs_syscalls2.c new file mode 100644 index 0000000..6124cfb --- /dev/null +++ b/sys/kernel/ufs_syscalls2.c @@ -0,0 +1,279 @@ +/* + * ufs_syscalls was getting too large. Various UFS related system calls were + * relocated to this file. + */ +#include "param.h" +#include "sys/file.h" +#include "user.h" +#include "inode.h" +#include "buf.h" +#include "fs.h" +#include "namei.h" +#include "mount.h" +#include "kernel.h" +#include "systm.h" +#include "proc.h" + +static int +statfs1 (mp, sbp) + struct mount *mp; + struct statfs *sbp; +{ + struct statfs sfs; + register struct statfs *sfsp; + struct fs *fs = &mp->m_filsys; + + sfsp = &sfs; + sfsp->f_type = MOUNT_UFS; + sfsp->f_bsize = MAXBSIZE; + sfsp->f_iosize = MAXBSIZE; + sfsp->f_blocks = fs->fs_fsize - fs->fs_isize; + sfsp->f_bfree = fs->fs_tfree; + sfsp->f_bavail = fs->fs_tfree; + sfsp->f_files = (fs->fs_isize - 1) * INOPB; + sfsp->f_ffree = fs->fs_tinode; + + bcopy (mp->m_mnton, sfsp->f_mntonname, MNAMELEN); + bcopy (mp->m_mntfrom, sfsp->f_mntfromname, MNAMELEN); + sfsp->f_flags = mp->m_flags & MNT_VISFLAGMASK; + return copyout ((caddr_t) sfsp, (caddr_t) sbp, sizeof (struct statfs)); +} + +void +statfs() +{ + register struct a { + char *path; + struct statfs *buf; + } *uap = (struct a *)u.u_arg; + register struct inode *ip; + struct nameidata nd; + register struct nameidata *ndp = &nd; + struct mount *mp; + + NDINIT (ndp, LOOKUP, FOLLOW, uap->path); + ip = namei(ndp); + if (! ip) + return; + mp = (struct mount *)((int)ip->i_fs - offsetof(struct mount, m_filsys)); + iput(ip); + u.u_error = statfs1 (mp, uap->buf); +} + +void +fstatfs() +{ + register struct a { + int fd; + struct statfs *buf; + } *uap = (struct a *)u.u_arg; + register struct inode *ip; + struct mount *mp; + + ip = getinode(uap->fd); + if (! ip) + return; + mp = (struct mount *)((int)ip->i_fs - offsetof(struct mount, m_filsys)); + u.u_error = statfs1 (mp, uap->buf); +} + +void +getfsstat() +{ + register struct a { + struct statfs *buf; + int bufsize; + u_int flags; + } *uap = (struct a *)u.u_arg; + register struct mount *mp; + caddr_t sfsp; + int count, maxcount, error; + + maxcount = uap->bufsize / sizeof (struct statfs); + sfsp = (caddr_t)uap->buf; + count = 0; + for (mp = mount; mp < &mount[NMOUNT]; mp++) { + if (mp->m_inodp == NULL) + continue; + if (count < maxcount) { + error = statfs1 (mp, sfsp); + if (error) { + u.u_error = error; + return; + } + sfsp += sizeof (struct statfs); + } + count++; + } + if (sfsp && count > maxcount) + u.u_rval = maxcount; + else + u.u_rval = count; +} + +/* + * This is somewhat inefficient in that the inode table is scanned for each + * filesystem but it didn't seem worth a page or two of code on something + * which only happens every 30 seconds. + */ +static void +syncinodes(fs) + struct fs *fs; +{ + register struct inode *ip; + + /* + * Write back each (modified) inode. + */ + for (ip = inode; ip < inode+NINODE; ip++) { + /* + * Attempt to reduce the overhead by short circuiting the scan if the + * inode is not for the filesystem being processed. + */ + if (ip->i_fs != fs) + continue; + if ((ip->i_flag & ILOCKED) != 0 || ip->i_count == 0 || + (ip->i_flag & (IMOD|IACC|IUPD|ICHG)) == 0) + continue; + ip->i_flag |= ILOCKED; + ip->i_count++; + iupdat(ip, &time, &time, 0); + iput(ip); + } +} + +/* + * 'ufs_sync' is the routine which syncs a single filesystem. This was + * created to replace 'update' which 'unmount' called. It seemed silly to + * sync _every_ filesystem when unmounting just one filesystem. + */ +int +ufs_sync(mp) + register struct mount *mp; +{ + register struct fs *fs; + struct buf *bp; + int error = 0; + + fs = &mp->m_filsys; + if (fs->fs_fmod && (mp->m_flags & MNT_RDONLY)) { + printf("fs = %s\n", fs->fs_fsmnt); + panic("sync: rofs"); + } + syncinodes(fs); /* sync the inodes for this filesystem */ + bflush(mp->m_dev); /* flush dirty data blocks */ + /* + * And lastly the superblock, if the filesystem was modified. + * Write back modified superblocks. Consistency check that the superblock + * of each file system is still in the buffer cache. + */ + if (fs->fs_fmod) { + bp = getblk(mp->m_dev, SUPERB); + fs->fs_fmod = 0; + fs->fs_time = time.tv_sec; + bcopy(fs, bp->b_addr, sizeof (struct fs)); + bwrite(bp); + error = geterror(bp); + } + return(error); +} + +/* + * mode mask for creation of files + */ +void +umask() +{ + register struct a { + int mask; + } *uap = (struct a *)u.u_arg; + + u.u_rval = u.u_cmask; + u.u_cmask = uap->mask & 07777; +} + +/* + * Seek system call + */ +void +lseek() +{ + register struct file *fp; + register struct a { + int fd; + off_t off; + int sbase; + } *uap = (struct a *)u.u_arg; + + if ((fp = getf(uap->fd)) == NULL) + return; + if (fp->f_type != DTYPE_INODE) { + u.u_error = ESPIPE; + return; + } + switch (uap->sbase) { + + case L_INCR: + fp->f_offset += uap->off; + break; + case L_XTND: + fp->f_offset = uap->off + ((struct inode *)fp->f_data)->i_size; + break; + case L_SET: + fp->f_offset = uap->off; + break; + default: + u.u_error = EINVAL; + return; + } + u.u_rval = fp->f_offset; +} + +/* + * Synch an open file. + */ +void +fsync() +{ + register struct a { + int fd; + } *uap = (struct a *)u.u_arg; + register struct inode *ip; + + if ((ip = getinode(uap->fd)) == NULL) + return; + ilock(ip); + syncip(ip); + iunlock(ip); +} + +void +utimes() +{ + register struct a { + char *fname; + struct timeval *tptr; + } *uap = (struct a *)u.u_arg; + register struct inode *ip; + struct nameidata nd; + register struct nameidata *ndp = &nd; + struct timeval tv[2]; + struct vattr vattr; + + VATTR_NULL(&vattr); + if (uap->tptr == NULL) { + tv[0].tv_sec = tv[1].tv_sec = time.tv_sec; + vattr.va_vaflags |= VA_UTIMES_NULL; + } else { + u.u_error = copyin ((caddr_t)uap->tptr,(caddr_t)tv,sizeof(tv)); + if (u.u_error) + return; + } + NDINIT (ndp, LOOKUP, FOLLOW, uap->fname); + if ((ip = namei(ndp)) == NULL) + return; + vattr.va_atime = tv[0].tv_sec; + vattr.va_mtime = tv[1].tv_sec; + u.u_error = ufs_setattr(ip, &vattr); + iput(ip); +} diff --git a/sys/kernel/vfs_vnops.c b/sys/kernel/vfs_vnops.c new file mode 100644 index 0000000..8ddd0a9 --- /dev/null +++ b/sys/kernel/vfs_vnops.c @@ -0,0 +1,212 @@ +/* + * Copyright (c) 1982, 1986, 1989, 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. + */ +#include +#include +#include +#include +#include +#include + +#include "systm.h" + +/* + * 2.11BSD does not have "vnodes", having instead only old fashioned "inodes". + * The routine names (i.e. vn_open) were retained since the functions them- + * selves were ported over with minimal change. Retaining the 4.4 function + * names also makes it easier to follow the logic flow when reading the 4.4 + * sources. Also, changing the names from vn_* to in_* could have caused + * confusion with the networking routines since 'in_' and 'ip_' are frequently + * used in the networking code. + * + * The tab spacing has been altered to be (to me) more readable. +*/ + +/* + * Common code for vnode open operations. + * Check permissions, and call the VOP_OPEN (openi for 2.11) or VOP_CREATE + * (maknode) routine. + */ +int +vn_open (ndp, fmode, cmode) + register struct nameidata *ndp; + int fmode, cmode; +{ + register struct inode *ip; + register int error; + + if (fmode & O_CREAT) { + if ((fmode & O_EXCL) == 0) + ndp->ni_nameiop |= (CREATE|FOLLOW); + else + ndp->ni_nameiop = CREATE; + ip = namei(ndp); + if (ip == NULL) { + if (u.u_error) { + goto retuerr; + } + ip = maknode(cmode, ndp); + if (ip == NULL) { + goto retuerr; + } + fmode &= ~O_TRUNC; + } else { + if (fmode & O_EXCL) { + error = EEXIST; + goto bad; + } + fmode &= ~O_CREAT; + } + } else { + ndp->ni_nameiop = LOOKUP | FOLLOW; + ip = namei(ndp); + if (ip == NULL) { + goto retuerr; + } + } + if ((ip->i_mode & IFMT) == IFSOCK) { + error = EOPNOTSUPP; + goto bad; + } + if ((ip->i_flags & APPEND) && (fmode&(FWRITE|O_APPEND)) == FWRITE) { + error = EPERM; + goto bad; + } + if ((fmode & O_CREAT) == 0) { + if (fmode & FREAD) { + if (access(ip, IREAD)) { + error = u.u_error; /* XXX */ + goto bad; + } + } + if (fmode & (FWRITE | O_TRUNC)) { + if ((ip->i_mode & IFMT) == IFDIR) { + error = EISDIR; + goto bad; + } + if (access(ip, IWRITE)) { + error = u.u_error; + goto bad; + } + } + } + if (fmode & O_TRUNC) + itrunc(ip, (off_t)0, fmode & O_FSYNC ? IO_SYNC : 0); + /* + * 4.4 returns the vnode locked from vn_open which means that each caller + * has to go and unlock it. + * + * 2.11 returns the inode unlocked (for now). + */ + iunlock(ip); /* because namei returns a locked inode */ + if (setjmp(&u.u_qsave)) { + error = EINTR; /* opens are not restarted after signals */ + goto lbad; + } + error = openi (ip, fmode); + if (error) { + goto lbad; + } + return(0); + + /* + * Gratuitous lock but it does (correctly) implement the earlier behaviour of + * copen (it also avoids a panic in iput). + */ +lbad: + ilock(ip); + +bad: + /* + * Do NOT do an 'ilock' here - this tag is to be used only when the inode is + * locked (i.e. from namei). + */ + iput(ip); + return(error); + +retuerr: + return(u.u_error); /* XXX - Bletch */ +} + +/* + * Inode close call. Pipes and sockets do NOT enter here. This routine is + * used by the kernel to close files it opened for itself. + * The kernel does not create sockets or pipes on its own behalf. + * + * The difference between this routine and vn_closefile below is that vn_close + * takes an "inode *" as a first argument and is passed the flags by the caller + * while vn_closefile (called from the closef routine for DTYPE_INODE inodes) + * takes a "file *" and extracts the flags from the file structure. + */ +int +vn_close(ip, flags) + register struct inode *ip; + int flags; +{ + register int error; + + error = closei(ip, flags); + irele(ip); /* assumes inode is unlocked */ + return(error); +} + +/* + * File table inode close routine. This is called from 'closef()' via the + * "Fops" table (the 'inodeops' entry). + * + * NOTE: pipes are a special case of inode and have their own 'pipe_close' + * entry in the 'pipeops' table. See sys_pipe.c for pipe_close(). + * + * In 4.4BSD this routine called vn_close() but since 2.11 does not do the + * writecheck counting we can skip the overhead of nesting another level down + * and call closei() and irele() ourself. + */ +int +vn_closefile(fp) + register struct file *fp; +{ + register struct inode *ip = (struct inode *)fp->f_data; + + /* + * Need to clear the inode pointer in the file structure so that the + * inode is not seen during the scan for aliases of character or block + * devices in closei(). + */ + fp->f_data = (caddr_t)0; /* XXX */ + irele(ip); + return (closei(ip, fp->f_flag)); +} diff --git a/sys/kernel/vm_sched.c b/sys/kernel/vm_sched.c new file mode 100644 index 0000000..8a92e76 --- /dev/null +++ b/sys/kernel/vm_sched.c @@ -0,0 +1,262 @@ +/* + * Copyright (c) 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "param.h" +#include "user.h" +#include "proc.h" +#include "vm.h" +#include "kernel.h" +#include "systm.h" +#include "debug.h" + +#define MINFINITY -32767 /* minus infinity */ + +int maxslp = MAXSLP; +char runin; /* scheduling flag */ +char runout; /* scheduling flag */ + +/* + * The main loop of the scheduling (swapping) process. + * The basic idea is: + * see if anyone wants to be swapped in + * swap out processes until there is room + * swap him in + * repeat + * The runout flag is set whenever someone is swapped out. Sched sleeps on + * it awaiting work. Sched sleeps on runin whenever it cannot find enough + * core (by swapping out or otherwise) to fit the selected swapped process. + * It is awakened when the core situation changes and in any case once per + * second. + */ +void +sched() +{ + register struct proc *rp; + struct proc *swapped_out = 0, *in_core = 0; + register int out_time, rptime; + int s __attribute__((unused)); + + for (;;) { + /* Perform swap-out/swap-in action. */ + s=spl0(); + if (in_core) + swapout (in_core, X_FREECORE, X_OLDSIZE, X_OLDSIZE); + if (swapped_out) + swapin (swapped_out); + s=splhigh(); + in_core = 0; + swapped_out = 0; + + /* Find user to swap in; of users ready, + * select one out longest. */ + out_time = -20000; + for (rp = allproc; rp; rp = rp->p_nxt) { + if (rp->p_stat != SRUN || (rp->p_flag & SLOAD)) + continue; + rptime = rp->p_time - rp->p_nice * 8; + + /* + * Always bring in parents ending a vfork, + * to avoid deadlock + */ + if (rptime > out_time || (rp->p_flag & SVFPRNT)) { + swapped_out = rp; + out_time = rptime; + if (rp->p_flag & SVFPRNT) + break; + } + } + + /* If there is no one there, wait. */ + if (! swapped_out) { + ++runout; + //SETVAL(0); + sleep ((caddr_t) &runout, PSWP); + continue; + } + + //SETVAL(swapped_out->p_pid); + + /* + * Look around for somebody to swap out. + * There may be only one non-system loaded process. + */ + for (rp = allproc; rp != NULL; rp = rp->p_nxt) { + if (rp->p_stat != SZOMB && + (rp->p_flag & (SSYS | SLOAD)) == SLOAD) { + in_core = rp; + break; + } + } + if (! in_core) { + /* In-core memory is empty. */ + continue; + } + + /* + * Swap found user out if sleeping interruptibly, or if he has spent at + * least 1 second in core and the swapped-out process has spent at + * least 2 seconds out. Otherwise wait a bit and try again. + */ + if (! (in_core->p_flag & SLOCK) && + (in_core->p_stat == SSTOP || + (in_core->p_stat == SSLEEP && (in_core->p_flag & P_SINTR)) || + ((in_core->p_stat == SRUN || in_core->p_stat == SSLEEP) && + out_time >= 2 && + in_core->p_time + in_core->p_nice >= 1))) + { + /* Swap out in-core process. */ + in_core->p_flag &= ~SLOAD; + if (in_core->p_stat == SRUN) + remrq (in_core); + } else { + /* Nothing to swap in/out. */ + in_core = 0; + swapped_out = 0; + ++runin; + sleep ((caddr_t) &runin, PSWP); + } + } +} + +/* + * Count up various things once a second + */ +void +vmmeter() +{ +#ifdef UCB_METER + register u_short *cp, *rp; + register long *sp; + + ave(avefree, freemem, 5); + ave(avefree30, freemem, 30); + cp = &cnt.v_first; + rp = &rate.v_first; + sp = &sum.v_first; + while (cp <= &cnt.v_last) { + ave(*rp, *cp, 5); + *sp += *cp; + *cp = 0; + rp++, cp++, sp++; + } +#endif + + if (time.tv_sec % 5 == 0) { + vmtotal(); +#ifdef UCB_METER + rate.v_swpin = cnt.v_swpin; + sum.v_swpin += cnt.v_swpin; + cnt.v_swpin = 0; + rate.v_swpout = cnt.v_swpout; + sum.v_swpout += cnt.v_swpout; + cnt.v_swpout = 0; +#endif + } +} + +/* + * Compute Tenex style load average. This code is adapted from similar code + * by Bill Joy on the Vax system. The major change is that we avoid floating + * point since not all pdp-11's have it. This makes the code quite hard to + * read - it was derived with some algebra. + * + * "floating point" numbers here are stored in a 16 bit short, with 8 bits on + * each side of the decimal point. Some partial products will have 16 bits to + * the right. + */ +static void +loadav (avg, n) + register short *avg; + register int n; +{ + register int i; + static const long cexp[3] = { + 0353, /* 256 * exp(-1/12) */ + 0373, /* 256 * exp(-1/60) */ + 0376, /* 256 * exp(-1/180) */ + }; + + for (i = 0; i < 3; i++) + avg[i] = (cexp[i] * (avg[i]-(n<<8)) + (((long)n)<<16)) >> 8; +} + +void +vmtotal() +{ + register struct proc *p; + register int nrun = 0; +#ifdef UCB_METER + total.t_vmtxt = 0; + total.t_avmtxt = 0; + total.t_rmtxt = 0; + total.t_armtxt = 0; + total.t_vm = 0; + total.t_avm = 0; + total.t_rm = 0; + total.t_arm = 0; + total.t_rq = 0; + total.t_dw = 0; + total.t_sl = 0; + total.t_sw = 0; +#endif + for (p = allproc; p != NULL; p = p->p_nxt) { + if (p->p_flag & SSYS) + continue; + if (p->p_stat) { +#ifdef UCB_METER + if (p->p_stat != SZOMB) { + total.t_vm += p->p_dsize + p->p_ssize + USIZE; + if (p->p_flag & SLOAD) + total.t_rm += p->p_dsize + p->p_ssize + + USIZE; + } +#endif + switch (p->p_stat) { + + case SSLEEP: + case SSTOP: + if (!(p->p_flag & P_SINTR) && p->p_stat == SSLEEP) + nrun++; +#ifdef UCB_METER + if (p->p_flag & SLOAD) { + if (!(p->p_flag & P_SINTR)) + total.t_dw++; + else if (p->p_slptime < maxslp) + total.t_sl++; + } else if (p->p_slptime < maxslp) + total.t_sw++; + if (p->p_slptime < maxslp) + goto active; +#endif + break; + + case SRUN: + case SIDL: + nrun++; +#ifdef UCB_METER + if (p->p_flag & SLOAD) + total.t_rq++; + else + total.t_sw++; +active: + total.t_avm += p->p_dsize + p->p_ssize + USIZE; + if (p->p_flag & SLOAD) + total.t_arm += p->p_dsize + p->p_ssize + + USIZE; +#endif + break; + } + } + } +#ifdef UCB_METER + total.t_vm += total.t_vmtxt; + total.t_avm += total.t_avmtxt; + total.t_rm += total.t_rmtxt; + total.t_arm += total.t_armtxt; + total.t_free = avefree; +#endif + loadav (avenrun, nrun); +} diff --git a/sys/kernel/vm_swap.c b/sys/kernel/vm_swap.c new file mode 100644 index 0000000..3402e99 --- /dev/null +++ b/sys/kernel/vm_swap.c @@ -0,0 +1,115 @@ +/* + * Copyright (c) 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "param.h" +#include "user.h" +#include "proc.h" +#include "map.h" +#include "buf.h" +#include "systm.h" +#include "vm.h" + +/* + * Swap a process in. + * Allocate data and possible text separately. It would be better + * to do largest first. Text, data, and stack are allocated in + * that order, as that is likely to be in order of size. + * U area goes into u0 buffer. + */ +void +swapin (p) + register struct proc *p; +{ + size_t daddr = USER_DATA_START; + size_t saddr = USER_DATA_END - p->p_ssize; + size_t uaddr = (size_t) &u0; + + if (p->p_dsize) { + swap (p->p_daddr, daddr, p->p_dsize, B_READ); + mfree (swapmap, btod (p->p_dsize), p->p_daddr); + } + if (p->p_ssize) { + swap (p->p_saddr, saddr, p->p_ssize, B_READ); + mfree (swapmap, btod (p->p_ssize), p->p_saddr); + } + swap (p->p_addr, uaddr, USIZE, B_READ); + mfree (swapmap, btod (USIZE), p->p_addr); + + p->p_daddr = daddr; + p->p_saddr = saddr; + p->p_addr = uaddr; + if (p->p_stat == SRUN) + setrq (p); + p->p_flag |= SLOAD; + p->p_time = 0; +#ifdef UCB_METER + cnt.v_swpin++; +#endif +} + +/* + * Swap out process p. + * odata and ostack are the old data size and the stack size + * of the process, and are supplied during core expansion swaps. + * The freecore flag causes its core to be freed -- it may be + * off when called to create an image for a child process + * in newproc. + * + * panic: out of swap space + */ +void +swapout (p, freecore, odata, ostack) + register struct proc *p; + int freecore; + register u_int odata, ostack; +{ + size_t a[3]; + + if (odata == (u_int) X_OLDSIZE) + odata = p->p_dsize; + if (ostack == (u_int) X_OLDSIZE) + ostack = p->p_ssize; + if (malloc3 (swapmap, btod (p->p_dsize), btod (p->p_ssize), + btod (USIZE), a) == NULL) + panic ("out of swap space"); + p->p_flag |= SLOCK; + if (odata) { + swap (a[0], p->p_daddr, odata, B_WRITE); + } + if (ostack) { + swap (a[1], p->p_saddr, ostack, B_WRITE); + } + /* + * Increment u_ru.ru_nswap for process being tossed out of core. + * We can be called to swap out a process other than the current + * process, so we have to map in the victim's u structure briefly. + * Note, savekdsa6 *must* be a static, because we remove the stack + * in the next instruction. The splclock is to prevent the clock + * from coming in and doing accounting for the wrong process, plus + * we don't want to come through here twice. Why are we doing + * this, anyway? + */ + { + int s; + + s = splclock(); + u.u_ru.ru_nswap++; + splx (s); + } + swap (a[2], p->p_addr, USIZE, B_WRITE); + p->p_daddr = a[0]; + p->p_saddr = a[1]; + p->p_addr = a[2]; + p->p_flag &= ~(SLOAD|SLOCK); + p->p_time = 0; + +#ifdef UCB_METER + cnt.v_swpout++; +#endif + if (runout) { + runout = 0; + wakeup ((caddr_t)&runout); + } +} diff --git a/sys/kernel/vm_swp.c b/sys/kernel/vm_swp.c new file mode 100644 index 0000000..f19f6d3 --- /dev/null +++ b/sys/kernel/vm_swp.c @@ -0,0 +1,177 @@ +/* + * Copyright (c) 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "param.h" +#include "user.h" +#include "proc.h" +#include "buf.h" +#include "conf.h" +#include "systm.h" +#include "vm.h" +#include "trace.h" +#include "uio.h" + +/* + * swap I/O + */ +void +swap (blkno, coreaddr, count, rdflg) + size_t blkno, coreaddr; + register int count; + int rdflg; +{ + register struct buf *bp; + int s; + +//printf ("swap (%u, %08x, %d, %s)\n", blkno, coreaddr, count, rdflg ? "R" : "W"); +#ifdef UCB_METER + if (rdflg) { + cnt.v_kbin += (count + 1023) / 1024; + } else { + cnt.v_kbout += (count + 1023) / 1024; + } +#endif + bp = geteblk(); /* allocate a buffer header */ + + while (count) { + bp->b_flags = B_BUSY | B_PHYS | B_INVAL | rdflg; + bp->b_dev = swapdev; + bp->b_bcount = count; + bp->b_blkno = blkno; + bp->b_addr = (caddr_t) coreaddr; + trace (TR_SWAPIO); + (*bdevsw[major(swapdev)].d_strategy) (bp); + s = splbio(); + while ((bp->b_flags & B_DONE) == 0) + sleep ((caddr_t)bp, PSWP); + splx (s); + if ((bp->b_flags & B_ERROR) || bp->b_resid) + panic ("hard err: swap"); + count -= count; + coreaddr += count; + blkno += btod (count); + } + brelse(bp); +} + +/* + * Raw I/O. The arguments are + * The strategy routine for the device + * A buffer, which may be a special buffer header + * owned exclusively by the device for this purpose or + * NULL if one is to be allocated. + * The device number + * Read/write flag + * Essentially all the work is computing physical addresses and + * validating them. + * + * rewritten to use the iov/uio mechanism from 4.3bsd. the physbuf routine + * was inlined. essentially the chkphys routine performs the same task + * as the useracc routine on a 4.3 system. 3/90 sms + * + * If the buffer pointer is NULL then one is allocated "dynamically" from + * the system cache. the 'invalid' flag is turned on so that the brelse() + * done later doesn't place the buffer back in the cache. the 'phys' flag + * is left on so that the address of the buffer is recalcuated in getnewbuf(). + * The BYTE/WORD stuff began to be removed after testing proved that either + * 1) the underlying hardware gives an error or 2) nothing bad happens. + * besides, 4.3BSD doesn't do the byte/word check and noone could remember + * why the byte/word check was added in the first place - likely historical + * paranoia. chkphys() inlined. 5/91 sms + * + * Refined (and streamlined) the flow by using a 'for' construct + * (a la 4.3Reno). Avoid allocating/freeing the buffer for each iovec + * element (i must have been confused at the time). 6/91-sms + * + * Finished removing the BYTE/WORD code as part of implementing the common + * raw read&write routines , systems had been running fine for several + * months with it ifdef'd out. 9/91-sms + */ +int +physio(strat, bp, dev, rw, uio) + void (*strat) (struct buf*); + register struct buf *bp; + dev_t dev; + int rw; + register struct uio *uio; +{ + int error = 0, s, c, allocbuf = 0; + register struct iovec *iov; + + if (! bp) { + allocbuf++; + bp = geteblk(); + } + u.u_procp->p_flag |= SLOCK; + for ( ; uio->uio_iovcnt; uio->uio_iov++, uio->uio_iovcnt--) { + iov = uio->uio_iov; + if (iov->iov_base >= iov->iov_base + iov->iov_len) { + error = EFAULT; + break; + } + /* + * Check that transfer is either entirely in the + * data or in the stack: that is, either + * the end is in the data or the start is in the stack + * (remember wraparound was already checked). + */ + if (baduaddr (iov->iov_base) || + baduaddr (iov->iov_base + iov->iov_len - 1)) { + error = EFAULT; + break; + } + if (! allocbuf) { + s = splbio(); + while (bp->b_flags & B_BUSY) { + bp->b_flags |= B_WANTED; + sleep((caddr_t)bp, PRIBIO+1); + } + splx(s); + } + bp->b_error = 0; + while (iov->iov_len) { + bp->b_flags = B_BUSY | B_PHYS | B_INVAL | rw; + bp->b_dev = dev; + bp->b_addr = iov->iov_base; + bp->b_blkno = (unsigned) uio->uio_offset >> DEV_BSHIFT; + bp->b_bcount = iov->iov_len; + c = bp->b_bcount; + (*strat)(bp); + s = splbio(); + while ((bp->b_flags & B_DONE) == 0) + sleep((caddr_t)bp, PRIBIO); + if (bp->b_flags & B_WANTED) /* rare */ + wakeup((caddr_t)bp); + splx(s); + c -= bp->b_resid; + iov->iov_base += c; + iov->iov_len -= c; + uio->uio_resid -= c; + uio->uio_offset += c; + /* temp kludge for tape drives */ + if (bp->b_resid || (bp->b_flags & B_ERROR)) + break; + } + bp->b_flags &= ~(B_BUSY | B_WANTED); + error = geterror(bp); + /* temp kludge for tape drives */ + if (bp->b_resid || error) + break; + } + if (allocbuf) + brelse(bp); + u.u_procp->p_flag &= ~SLOCK; + return(error); +} + +int +rawrw (dev, uio, flag) + dev_t dev; + register struct uio *uio; + int flag; +{ + return (physio(cdevsw[major(dev)].d_strategy, (struct buf *)NULL, dev, + uio->uio_rw == UIO_READ ? B_READ : B_WRITE, uio)); +} diff --git a/sys/pic32/MAKEDEV.sh b/sys/pic32/MAKEDEV.sh new file mode 100644 index 0000000..0d4e40c --- /dev/null +++ b/sys/pic32/MAKEDEV.sh @@ -0,0 +1,63 @@ +#!/bin/sh - +# +# Copyright (c) 1980 Regents of the University of California. +# All rights reserved. The Berkeley software License Agreement +# specifies the terms and conditions for redistribution. +# +# Device "make" file. Valid arguments: +# std standard devices +# local configuration specific devices +# fd file descriptor driver +# Disks: +# sd* flash cards SecureDigital +# Pseudo terminals: +# pty* set of 16 master and slave pseudo terminals + +PATH=/etc:/sbin:/usr/sbin:/bin:/usr/bin +umask 77 +for i +do +case $i in + +std) + mknod console c 0 0 + mknod mem c 1 0 ; chmod 640 mem ; chgrp kmem mem + mknod kmem c 1 1 ; chmod 640 kmem ; chgrp kmem kmem + mknod null c 1 2 ; chmod 666 null + mknod zero c 1 3 ; chmod 444 zero + mknod tty c 2 0 ; chmod 666 tty + mknod klog c 4 0 ; chmod 600 klog + mknod errlog c 4 1 ; chmod 600 errlog + mknod acctlog c 4 2 ; chmod 600 acctlog + ;; + +fd) + umask 0 + rm -rf fd + rm -f stdin stdout stderr + mkdir fd + chmod 755 fd + mknod stdin c 5 0 + mknod stdout c 5 1 + mknod stderr c 5 2 + eval `echo "" | awk '{ for (i = 0; i < 32; i++) + printf("mknod fd/%d c 5 %d; ",i,i); }'` + ;; + +sd*) + # The 2.11BSD sd driver doesn't support partitions. We create + # a single block and character inode pair for each unit and + # call it sdNh. + umask 2 + unit=`expr $i : '..\(.*\)'` + mknod sd${unit}h b 0 ${unit} + mknod rsd${unit}h c 3 ${unit} + chgrp operator sd${unit}h rsd${unit}h + chmod 640 sd${unit}h rsd${unit}h + ;; + +local) + sh MAKEDEV.local + ;; +esac +done diff --git a/sys/pic32/Makefile b/sys/pic32/Makefile new file mode 100644 index 0000000..33de1cf --- /dev/null +++ b/sys/pic32/Makefile @@ -0,0 +1,22 @@ + +# Programs that live in subdirectories, and have makefiles of their own. +# +SUBDIR = baremetal dip duinomite duinomite-uart duinomite-e \ + duinomite-e-uart explorer16 max32 max32-eth maximite \ + meb pinguino-micro starter-kit ubw32 ubw32-uart \ + ubw32-uart-sdram baremetal fubarino fubarino-uart \ + fubarino-uart-sramc mmb-mx7 maximite-color + +default: + +all: + -for i in $(SUBDIR); do make -C $$i all; done + +install: + +clean: + -for i in $(SUBDIR); do make -C $$i clean; done + find .. -name \*~ | xargs rm -f + +reconfig: + -for i in $(SUBDIR); do echo $$i; I=`echo $$i | awk '{print toupper($$0)}'`; (cd $$i; ../../../tools/configsys/config $$I); done diff --git a/sys/pic32/README b/sys/pic32/README new file mode 100644 index 0000000..e8b9cf3 --- /dev/null +++ b/sys/pic32/README @@ -0,0 +1,22 @@ +Build directories: + +max32 - chipKIT Max32 board. + +ubw32 - Sparkfun UBW32 board, USB console. + +ubw32-uart - Sparkfun UBW32 board, UART console. + +maximite - Maximite computer. + +explorer16 - Microchip Explorer 16 board, with + PIC32 CAN-USB plug-in module and SD & MMC pictail. + +starter-kit - Microchip PIC32 USB or Ethernet Starter Kit, + with I/O Expansion board and SD & MMC pictail. + +dip - eflightworks.net PIC32-on-DIP board. + (work in progress) + +meb - Microchip Multimedia Expansion board with + Microchip PIC32 USB or Ethernet Starter Kit. + (work in progress) diff --git a/sys/pic32/_startup.S b/sys/pic32/_startup.S new file mode 120000 index 0000000..cac3df3 --- /dev/null +++ b/sys/pic32/_startup.S @@ -0,0 +1 @@ +startup.S \ No newline at end of file diff --git a/sys/pic32/adc.c b/sys/pic32/adc.c new file mode 100644 index 0000000..eb442e7 --- /dev/null +++ b/sys/pic32/adc.c @@ -0,0 +1,149 @@ +/* + * ADC driver for PIC32. + * + * Copyright (C) 2012 Majenko Technologies + * + * 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 the copyright notice and this + * permission notice and warranty disclaimer appear in supporting + * documentation, and that the name of the author not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * + * The author disclaim all warranties with regard to this + * software, including all implied warranties of merchantability + * and fitness. In no event shall the author 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. + */ + +#include "param.h" +#include "conf.h" +#include "user.h" +#include "ioctl.h" +#include "systm.h" +#include "uio.h" +#include "adc.h" +#include "debug.h" + +const struct devspec adcdevs[] = { + { 0, "adc0" }, { 1, "adc1" }, { 2, "adc2" }, { 3, "adc3" }, + { 4, "adc4" }, { 5, "adc5" }, { 6, "adc6" }, { 7, "adc7" }, + { 8, "adc8" }, { 9, "adc9" }, { 10, "adc10" }, { 11, "adc11" }, + { 12, "adc12" }, { 13, "adc13" }, { 14, "adc14" }, { 15, "adc15" }, + { 0, 0 } +}; + +extern int uwritec(struct uio *); + +unsigned short adcactive = 0; + +int adc_open(dev_t dev, int flag, int mode) +{ + int channel; + + channel = minor(dev); + if(channel>ADCMAX) + return ENODEV; + + DEBUG1("adc%2: opened\n",channel); + + AD1PCFG &= ~(1<ADCMAX) + return ENODEV; + + AD1PCFG |= (1<ADCMAX) + return ENODEV; + + lr = *(&ADC1BUF0+(channel<<2)); + + c=0; + if(lr >= 1000) + { + tv = lr/1000; + temp[c++] = '0' + tv; + lr = lr - (tv*1000); + } + if((lr >= 100) || (c>0)) + { + tv = lr/100; + temp[c++] = '0' + tv; + lr = lr - (tv*100); + } + if((lr >= 10) || (c>0)) + { + tv = lr/10; + temp[c++] = '0' + tv; + lr = lr - (tv*10); + } + temp[c++] = '0' + lr; + temp[c++] = '\n'; + temp[c] = 0; + + uiomove(temp,strlen(temp), uio); + + return 0; +} + +int adc_write(dev_t dev, struct uio *uio, int flag) +{ + return EINVAL; +} + +int adc_ioctl(dev_t dev, register u_int cmd, caddr_t addr, int flag) +{ + switch(cmd) + { + default: + return EINVAL; + } + + return 0; +} diff --git a/sys/pic32/baremetal/BAREMETAL b/sys/pic32/baremetal/BAREMETAL new file mode 100644 index 0000000..6ba3d39 --- /dev/null +++ b/sys/pic32/baremetal/BAREMETAL @@ -0,0 +1,13 @@ +core pic32mx7 +mapping generic +linker bare + +device kernel led=D3 cpu_khz=80000 bus_khz=80000 +device rdisk led=D2 +device uart1 baud=115200 +device console led=D12 device=tty0 + +device sd0 port=2 mhz=16 cs=D1 + +device devcfg + diff --git a/sys/pic32/baremetal/Makefile b/sys/pic32/baremetal/Makefile new file mode 100644 index 0000000..3c92ffd --- /dev/null +++ b/sys/pic32/baremetal/Makefile @@ -0,0 +1,66 @@ +BUILDPATH = ../../../tools/configsys/../../sys/pic32 +H = ../../../tools/configsys/../../sys/include +M = ../../../tools/configsys/../../sys/pic32 +S = ../../../tools/configsys/../../sys/kernel + +vpath %.c $(M):$(S) +vpath %.S $(M):$(S) + +KERNOBJ += _startup.o clock.o cons.o devcfg.o devsw.o exception.o init_main.o init_sysent.o kern_clock.o kern_descrip.o kern_exec.o kern_exit.o kern_fork.o kern_mman.o kern_proc.o kern_prot.o kern_prot2.o kern_resource.o kern_sig.o kern_sig2.o kern_subr.o kern_synch.o kern_sysctl.o kern_time.o machdep.o mem.o rd_sd.o rdisk.o signal.o spi_bus.o subr_prf.o subr_rmap.o swap.o sys_generic.o sys_inode.o sys_pipe.o sys_process.o syscalls.o sysctl.o tty.o tty_subr.o tty_tty.o uart.o ufs_alloc.o ufs_bio.o ufs_bmap.o ufs_dsort.o ufs_fio.o ufs_inode.o ufs_mount.o ufs_namei.o ufs_subr.o ufs_syscalls.o ufs_syscalls2.o vers.o vfs_vnops.o vm_sched.o vm_swap.o vm_swp.o +EXTRA_TARGETS = + +DEFS += -DBUS_DIV=1 +DEFS += -DBUS_KHZ=80000 +DEFS += -DCONSOLE_DEVICE=tty0 +DEFS += -DCPU_IDIV=2 +DEFS += -DCPU_KHZ=80000 +DEFS += -DCPU_MUL=20 +DEFS += -DCPU_ODIV=1 +DEFS += -DCRYSTAL=8 +DEFS += -DDC0_DEBUG=DEVCFG0_DEBUG_DISABLED +DEFS += -DDC0_ICE=0 +DEFS += -DDC1_CKM=0 +DEFS += -DDC1_CKS=0 +DEFS += -DDC1_FNOSC=DEVCFG1_FNOSC_PRIPLL +DEFS += -DDC1_IESO=DEVCFG1_IESO +DEFS += -DDC1_OSCIOFNC=0 +DEFS += -DDC1_PBDIV=DEVCFG1_FPBDIV_1 +DEFS += -DDC1_POSCMOD=DEVCFG1_POSCMOD_HS +DEFS += -DDC1_SOSC=0 +DEFS += -DDC1_WDTEN=0 +DEFS += -DDC1_WDTPS=DEVCFG1_WDTPS_1 +DEFS += -DDC2_PLLIDIV=DEVCFG2_FPLLIDIV_2 +DEFS += -DDC2_PLLMUL=DEVCFG2_FPLLMUL_20 +DEFS += -DDC2_PLLODIV=DEVCFG2_FPLLODIV_1 +DEFS += -DDC2_UPLL=0 +DEFS += -DDC2_UPLLIDIV=DEVCFG2_UPLLIDIV_2 +DEFS += -DDC3_CAN=DEVCFG3_FCANIO +DEFS += -DDC3_ETH=DEVCFG3_FETHIO +DEFS += -DDC3_MII=DEVCFG3_FMIIEN +DEFS += -DDC3_SRS=DEVCFG3_FSRSSEL_7 +DEFS += -DDC3_USBID=DEVCFG3_FUSBIDIO +DEFS += -DDC3_USERID=0xffff +DEFS += -DDC3_VBUSON=DEVCFG3_FVBUSONIO +DEFS += -DKERNEL +DEFS += -DLED_DISK_PIN=2 +DEFS += -DLED_DISK_PORT=TRISD +DEFS += -DLED_KERNEL_PIN=3 +DEFS += -DLED_KERNEL_PORT=TRISD +DEFS += -DLED_TTY_PIN=12 +DEFS += -DLED_TTY_PORT=TRISD +DEFS += -DPIC32MX7 +DEFS += -DSD0_CS_PIN=1 +DEFS += -DSD0_CS_PORT=TRISD +DEFS += -DSD0_MHZ=16 +DEFS += -DSD0_PORT=2 +DEFS += -DUART1_BAUD=115200 +DEFS += -DUART1_ENABLED=YES +DEFS += -DUCB_METER + + +LDSCRIPT = ../../../tools/configsys/../../sys/pic32/cfg/bare.ld + +CONFIG = BAREMETAL +CONFIGPATH = ../../../tools/configsys + +include ../../../tools/configsys/../../sys/pic32/kernel-post.mk diff --git a/sys/pic32/baremetal/bare-metal.ld b/sys/pic32/baremetal/bare-metal.ld new file mode 100644 index 0000000..d663b49 --- /dev/null +++ b/sys/pic32/baremetal/bare-metal.ld @@ -0,0 +1,186 @@ +/* + * Linker script for PIC32 firmware. + */ +OUTPUT_FORMAT("elf32-littlemips", "elf32-bigmips", + "elf32-littlemips") +OUTPUT_ARCH(mips) +ENTRY(_reset_vector_) +MEMORY +{ + ram (rw!x): ORIGIN = 0x80000000, LENGTH = 26K + u0area (rw!x): ORIGIN = 0x80006800, LENGTH = 3K + uarea (rw!x): ORIGIN = 0x80007400, LENGTH = 3K + devcfg (r) : ORIGIN = 0x9fc02ff0, LENGTH = 16 + +/* flash (rx) : ORIGIN = 0x9d005000, LENGTH = 492K + ram (rw!x): ORIGIN = 0x80000000, LENGTH = 24K + u0area (rw!x): ORIGIN = 0x80006000, LENGTH = 3K + uarea (rw!x): ORIGIN = 0x80006C00, LENGTH = 3K + keram (rwx) : ORIGIN = 0x80007800, LENGTH = 2K*/ + + + /* Required by Microchip C32 linker */ + kseg0_program_mem (rx) : ORIGIN = 0x9D000000, LENGTH = 512K + exception_mem (rx) : ORIGIN = 0x9D000000, LENGTH = 0x1000 + kseg0_boot_mem (rx) : ORIGIN = 0x9FC00000, LENGTH = 12K-16 + kseg1_boot_mem (rx) : ORIGIN = 0xBFC00000, LENGTH = 0x490 + kseg1_data_mem (w!x) : ORIGIN = 0xA0000000, LENGTH = 0x20000 +} + +/* higher address of the user mode stack */ +u0 = ORIGIN(u0area); +u = ORIGIN(uarea); +u_end = ORIGIN(uarea) + LENGTH(uarea); + +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = 0x0000; + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rel.init : { *(.rel.init) } + .rela.init : { *(.rela.init) } + .rel.text : { *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) } + .rela.text : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) } + .rel.fini : { *(.rel.fini) } + .rela.fini : { *(.rela.fini) } + .rel.rodata : { *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) } + .rela.rodata : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) } + .rel.data : { *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) } + .rela.data : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.sdata : { *(.rel.sdata .rel.sdata.* .rel.gnu.linkonce.s.*) } + .rela.sdata : { *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*) } + .rel.sbss : { *(.rel.sbss .rel.sbss.* .rel.gnu.linkonce.sb.*) } + .rela.sbss : { *(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*) } + .rel.sdata2 : { *(.rel.sdata2 .rel.sdata2.* .rel.gnu.linkonce.s2.*) } + .rela.sdata2 : { *(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*) } + .rel.sbss2 : { *(.rel.sbss2 .rel.sbss2.* .rel.gnu.linkonce.sb2.*) } + .rela.sbss2 : { *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*) } + .rel.bss : { *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) } + .rela.bss : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .plt : { *(.plt) } + + .boot : + { + /* Execution starts here. */ + *(.startup) + } > kseg0_boot_mem + + .text : + { + /* Exception handlers. */ + *(.exception) + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.glue_7t) *(.glue_7) + __rodata_start = . ; + *(.rodata .rodata.* .gnu.linkonce.r.* .rel.dyn) + /* Align here to ensure that the .text section ends on word boundary. */ + . = ALIGN (32 / 8); + _etext = .; + } > kseg0_program_mem + + /* Start data (internal SRAM). */ + .data : AT (ADDR (.text) + SIZEOF (.text)) + { + __data_start = . ; + _gp = .; /* We have only 32k RAM on MC-24, so no need for 0x8000 offset. */ + *(.data .data.* .gnu.linkonce.d.*) + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + *(.sdata .sdata.* .gnu.linkonce.s.*) + *(.eh_frame) + _edata = .; + } > ram + + /* Device configuration. */ + .config : + { + *(.config3) + *(.config2) + *(.config1) + *(.config0) + } > devcfg + + .bss ADDR (.data) + SIZEOF (.data) (NOLOAD) : + { + __bss_start = .; + *(.dynbss) + *(.sbss .sbss.*) + *(.scommon) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. */ + . = ALIGN (32 / 8); + } > ram + __bss_end = . ; + _end = .; + +/* + * RAM functions go at the end of our stack and heap allocation. + * Alignment of 2K required by the boundary register (BMXDKPBA). + */ +/* + .ramfunc : AT (LOADADDR (.data) + SIZEOF (.data)) + { + _ramfunc_begin = . ; + *(.ramfunc .ramfunc.*) + . = ALIGN(4) ; + _ramfunc_end = . ; + } >keram + _ramfunc_image_begin = LOADADDR(.ramfunc) ; + _ramfunc_length = SIZEOF(.ramfunc) ; +*/ + + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } +} diff --git a/sys/pic32/baremetal/devcfg.c b/sys/pic32/baremetal/devcfg.c new file mode 100644 index 0000000..38790ea --- /dev/null +++ b/sys/pic32/baremetal/devcfg.c @@ -0,0 +1,25 @@ +/* + * Chip configuration. + */ +#include "machine/pic32mx.h" + +PIC32_DEVCFG ( + DEVCFG0_DEBUG_DISABLED, /* ICE debugger enabled */ + + DEVCFG1_FNOSC_FRCDIVPLL | /* Internal FRC oscillator with PLL */ + DEVCFG1_POSCMOD_DISABLE | /* No crystal */ + DEVCFG1_OSCIOFNC | /* CLKO output active */ + DEVCFG1_FPBDIV_1 | /* Peripheral bus clock = SYSCLK/1 */ + DEVCFG1_FCKM_DISABLE | /* Fail-safe clock monitor disable */ + DEVCFG1_FCKS_DISABLE | /* Clock switching disable */ + DEVCFG1_WDTPS_1024, /* Watchdog postscale = 1/1024 */ + + DEVCFG2_FPLLIDIV_2 | /* PLL divider = 1/2 */ + DEVCFG2_FPLLMUL_20 | /* PLL multiplier = 20x */ + DEVCFG2_UPLLIDIV_2 | /* USB PLL divider = 1/2 */ + DEVCFG2_UPLLDIS | /* Disable USB PLL */ + DEVCFG2_FPLLODIV_1, /* PLL postscaler = 1/1 */ + + DEVCFG3_USERID(0xffff) | /* User-defined ID */ + DEVCFG3_FSRSSEL_7 | /* Assign irq priority 7 to shadow set */ + DEVCFG3_FETHIO); /* Default Ethernet i/o pins */ diff --git a/sys/pic32/cfg/adc.dev b/sys/pic32/cfg/adc.dev new file mode 100644 index 0000000..f0c0897 --- /dev/null +++ b/sys/pic32/cfg/adc.dev @@ -0,0 +1,4 @@ +always + file adc.o + define ADC_ENABLED YES +end always diff --git a/sys/pic32/cfg/bare.ld b/sys/pic32/cfg/bare.ld new file mode 100644 index 0000000..adc7434 --- /dev/null +++ b/sys/pic32/cfg/bare.ld @@ -0,0 +1,179 @@ +/* + * Linker script for PIC32 firmware. + */ +OUTPUT_FORMAT("elf32-littlemips", "elf32-bigmips", + "elf32-littlemips") +OUTPUT_ARCH(mips) +ENTRY(_reset_vector_) +MEMORY +{ + ram (rw!x): ORIGIN = 0x80000000, LENGTH = 26K + u0area (rw!x): ORIGIN = 0x80006800, LENGTH = 3K + uarea (rw!x): ORIGIN = 0x80007400, LENGTH = 3K + devcfg (r) : ORIGIN = 0x9fc02ff0, LENGTH = 16 + + /* Required by Microchip C32 linker */ + kseg0_program_mem (rx) : ORIGIN = 0x9D000000, LENGTH = 512K + exception_mem (rx) : ORIGIN = 0x9D000000, LENGTH = 0x1000 + kseg0_boot_mem (rx) : ORIGIN = 0x9FC00000, LENGTH = 12K-16 + kseg1_boot_mem (rx) : ORIGIN = 0xBFC00000, LENGTH = 0x490 + kseg1_data_mem (w!x) : ORIGIN = 0xA0000000, LENGTH = 0x20000 +} + +/* higher address of the user mode stack */ +u0 = ORIGIN(u0area); +u = ORIGIN(uarea); +u_end = ORIGIN(uarea) + LENGTH(uarea); + +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = 0x0000; + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rel.init : { *(.rel.init) } + .rela.init : { *(.rela.init) } + .rel.text : { *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) } + .rela.text : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) } + .rel.fini : { *(.rel.fini) } + .rela.fini : { *(.rela.fini) } + .rel.rodata : { *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) } + .rela.rodata : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) } + .rel.data : { *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) } + .rela.data : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.sdata : { *(.rel.sdata .rel.sdata.* .rel.gnu.linkonce.s.*) } + .rela.sdata : { *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*) } + .rel.sbss : { *(.rel.sbss .rel.sbss.* .rel.gnu.linkonce.sb.*) } + .rela.sbss : { *(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*) } + .rel.sdata2 : { *(.rel.sdata2 .rel.sdata2.* .rel.gnu.linkonce.s2.*) } + .rela.sdata2 : { *(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*) } + .rel.sbss2 : { *(.rel.sbss2 .rel.sbss2.* .rel.gnu.linkonce.sb2.*) } + .rela.sbss2 : { *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*) } + .rel.bss : { *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) } + .rela.bss : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .plt : { *(.plt) } + + .boot : + { + /* Execution starts here. */ + *(.startup) + } > kseg0_boot_mem + + .text : + { + /* Exception handlers. */ + *(.exception) + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.glue_7t) *(.glue_7) + __rodata_start = . ; + *(.rodata .rodata.* .gnu.linkonce.r.* .rel.dyn) + /* Align here to ensure that the .text section ends on word boundary. */ + . = ALIGN (32 / 8); + _etext = .; + } > kseg0_program_mem + + /* Start data (internal SRAM). */ + .data : AT (ADDR (.text) + SIZEOF (.text)) + { + __data_start = . ; + _gp = .; /* We have only 32k RAM on MC-24, so no need for 0x8000 offset. */ + *(.data .data.* .gnu.linkonce.d.*) + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + *(.sdata .sdata.* .gnu.linkonce.s.*) + *(.eh_frame) + _edata = .; + } > ram + + /* Device configuration. */ + .config : + { + *(.config3) + *(.config2) + *(.config1) + *(.config0) + } > devcfg + + .bss ADDR (.data) + SIZEOF (.data) (NOLOAD) : + { + __bss_start = .; + *(.dynbss) + *(.sbss .sbss.*) + *(.scommon) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. */ + . = ALIGN (32 / 8); + } > ram + __bss_end = . ; + _end = .; + +/* + * RAM functions go at the end of our stack and heap allocation. + * Alignment of 2K required by the boundary register (BMXDKPBA). + */ +/* + .ramfunc : AT (LOADADDR (.data) + SIZEOF (.data)) + { + _ramfunc_begin = . ; + *(.ramfunc .ramfunc.*) + . = ALIGN(4) ; + _ramfunc_end = . ; + } >keram + _ramfunc_image_begin = LOADADDR(.ramfunc) ; + _ramfunc_length = SIZEOF(.ramfunc) ; +*/ + + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } +} diff --git a/sys/pic32/cfg/boot.ld b/sys/pic32/cfg/boot.ld new file mode 100644 index 0000000..056d86c --- /dev/null +++ b/sys/pic32/cfg/boot.ld @@ -0,0 +1,151 @@ +/* + * Linker script for PIC32 bootloader. + */ +OUTPUT_FORMAT("elf32-tradlittlemips") +OUTPUT_ARCH(mips) +ENTRY(_start) +MEMORY +{ + ram (rw!x): ORIGIN = 0x80000000, LENGTH = 32K + devcfg (r) : ORIGIN = 0x9fc02ff0, LENGTH = 16 + + /* Required by Microchip C32 linker */ + kseg0_boot_mem (rx) : ORIGIN = 0x9fc00000, LENGTH = 0 + kseg0_program_mem (rx) : ORIGIN = 0x9fc00000, LENGTH = 12K + exception_mem (rx) : ORIGIN = 0x9fc00000, LENGTH = 0x400 + kseg1_boot_mem (rx) : ORIGIN = 0xbfc00000, LENGTH = 1K + kseg1_data_mem (w!x) : ORIGIN = 0xa0000000, LENGTH = 128K +} + +/* higher address of the user mode stack */ +_estack = ORIGIN(ram) + LENGTH(ram); + +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = 0x0000; + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rel.init : { *(.rel.init) } + .rela.init : { *(.rela.init) } + .rel.text : { *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) } + .rela.text : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) } + .rel.fini : { *(.rel.fini) } + .rela.fini : { *(.rela.fini) } + .rel.rodata : { *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) } + .rela.rodata : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) } + .rel.data : { *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) } + .rela.data : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.sdata : { *(.rel.sdata .rel.sdata.* .rel.gnu.linkonce.s.*) } + .rela.sdata : { *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*) } + .rel.sbss : { *(.rel.sbss .rel.sbss.* .rel.gnu.linkonce.sb.*) } + .rela.sbss : { *(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*) } + .rel.sdata2 : { *(.rel.sdata2 .rel.sdata2.* .rel.gnu.linkonce.s2.*) } + .rela.sdata2 : { *(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*) } + .rel.sbss2 : { *(.rel.sbss2 .rel.sbss2.* .rel.gnu.linkonce.sb2.*) } + .rela.sbss2 : { *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*) } + .rel.bss : { *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) } + .rela.bss : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .plt : { *(.plt) } + + .text : + { + /* Execution starts here. */ + *(.startup) + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.glue_7t) *(.glue_7) + __rodata_start = . ; + *(.rodata .rodata.* .gnu.linkonce.r.* .rel.dyn) + /* Align here to ensure that the .text section ends on word boundary. */ + . = ALIGN (32 / 8); + _etext = .; + } > kseg0_program_mem + + /* Device configuration. */ + .config : + { + *(.config3) + *(.config2) + *(.config1) + *(.config0) + } > devcfg + + /* Start data (internal SRAM). */ + .data : AT (ADDR (.text) + SIZEOF (.text)) + { + __data_start = . ; + _gp = .; + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + *(.sdata .sdata.* .gnu.linkonce.s.*) + *(.data .data.* .gnu.linkonce.d.*) + *(.eh_frame) + _edata = .; + } > ram + + .bss ADDR (.data) + SIZEOF (.data) (NOLOAD) : + { + __bss_start = .; + *(.dynbss) + *(.sbss .sbss.*) + *(.scommon) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. */ + . = ALIGN (32 / 8); + } > ram + __bss_end = . ; + _end = .; + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } +} diff --git a/sys/pic32/cfg/bootloader-max32.ld b/sys/pic32/cfg/bootloader-max32.ld new file mode 100644 index 0000000..54bc462 --- /dev/null +++ b/sys/pic32/cfg/bootloader-max32.ld @@ -0,0 +1,117 @@ +/* + * Linker script for PIC32 firmware using HID bootloader. + * Flash area for user starts at 9d000000. + * Start address for user program is 9d001000. + */ +OUTPUT_FORMAT("elf32-littlemips", "elf32-bigmips", + "elf32-littlemips") +OUTPUT_ARCH(mips) +ENTRY(_reset_vector_) +MEMORY +{ + flash (rx) : ORIGIN = 0x9d000000, LENGTH = 512K + ram (rw!x): ORIGIN = 0x80000000, LENGTH = 26K + u0area (rw!x): ORIGIN = 0x80006800, LENGTH = 3K + uarea (rw!x): ORIGIN = 0x80007400, LENGTH = 3K + + /* Required by Microchip C32 linker */ + kseg0_program_mem (rx) : ORIGIN = 0x9D000000, LENGTH = 0x80000 + kseg0_boot_mem : ORIGIN = 0x9FC00000, LENGTH = 0x1000 + exception_mem : ORIGIN = 0x9FC01000, LENGTH = 0x1000 + kseg1_boot_mem : ORIGIN = 0xBFC00000, LENGTH = 0 + kseg1_data_mem (w!x) : ORIGIN = 0xA0000000, LENGTH = 0x20000 +} + +/* higher address of the user mode stack */ +u0 = ORIGIN(u0area); +u = ORIGIN(uarea); +u_end = ORIGIN(uarea) + LENGTH(uarea); + +SECTIONS +{ + .text ORIGIN(flash) : + { + /* Exception handlers. */ + *(.exception) + . = 0x1000; + /* Execution starts here. */ + *(.startup) + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.glue_7t) *(.glue_7) + __rodata_start = . ; + *(.rodata .rodata.* .gnu.linkonce.r.* .rel.dyn) + *(.dinit) + /* Align here to ensure that the .text section ends on word boundary. */ + . = ALIGN (32 / 8); + _etext = .; + } > flash + + /* Start data (internal SRAM). */ + .data : AT (ADDR (.text) + SIZEOF (.text)) + { + __data_start = . ; + _gp = .; /* We use only 32k RAM for kernel, so no need for 0x8000 offset. */ + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + *(.sdata .sdata.* .gnu.linkonce.s.*) + *(.data .data.* .gnu.linkonce.d.*) + *(.eh_frame) + _edata = .; + } > ram + + .bss ADDR (.data) + SIZEOF (.data) (NOLOAD) : + { + __bss_start = .; + *(.dynbss) + *(.sbss .sbss.*) + *(.scommon) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. */ + . = ALIGN (32 / 8); + } > ram + __bss_end = . ; + _end = .; + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + .debug_pubtypes 0 : { *(.debug_pubtypes) } + .debug_ranges 0 : { *(.debug_ranges) } + .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) } +} diff --git a/sys/pic32/cfg/bootloader-maxcolor.ld b/sys/pic32/cfg/bootloader-maxcolor.ld new file mode 100644 index 0000000..84af529 --- /dev/null +++ b/sys/pic32/cfg/bootloader-maxcolor.ld @@ -0,0 +1,117 @@ +/* + * Linker script for PIC32 firmware using HID bootloader. + * Flash area for user starts at 9d005000. + * Start address for user program is 9d006000. + */ +OUTPUT_FORMAT("elf32-littlemips", "elf32-bigmips", + "elf32-littlemips") +OUTPUT_ARCH(mips) +ENTRY(_reset_vector_) +MEMORY +{ + flash (rx) : ORIGIN = 0x9d005000, LENGTH = 512K-20K + ram (rw!x): ORIGIN = 0x80000000, LENGTH = 26K + u0area (rw!x): ORIGIN = 0x80006800, LENGTH = 3K + uarea (rw!x): ORIGIN = 0x80007400, LENGTH = 3K + + /* Required by Microchip C32 linker */ + kseg0_program_mem (rx) : ORIGIN = 0x9D000000, LENGTH = 0x80000 + kseg0_boot_mem : ORIGIN = 0x9FC00000, LENGTH = 0x1000 + exception_mem : ORIGIN = 0x9FC04000, LENGTH = 0x1000 + kseg1_boot_mem : ORIGIN = 0xBFC00000, LENGTH = 0 + kseg1_data_mem (w!x) : ORIGIN = 0xA0000000, LENGTH = 0x20000 +} + +/* higher address of the user mode stack */ +u0 = ORIGIN(u0area); +u = ORIGIN(uarea); +u_end = ORIGIN(uarea) + LENGTH(uarea); + +SECTIONS +{ + .text ORIGIN(flash) : + { + /* Exception handlers. */ + *(.exception) + . = 0x1000; + /* Execution starts here. */ + *(.startup) + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.glue_7t) *(.glue_7) + __rodata_start = . ; + *(.rodata .rodata.* .gnu.linkonce.r.* .rel.dyn) + *(.dinit) + /* Align here to ensure that the .text section ends on word boundary. */ + . = ALIGN (32 / 8); + _etext = .; + } > flash + + /* Start data (internal SRAM). */ + .data : AT (ADDR (.text) + SIZEOF (.text)) + { + __data_start = . ; + _gp = .; /* We use only 32k RAM for kernel, so no need for 0x8000 offset. */ + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + *(.sdata .sdata.* .gnu.linkonce.s.*) + *(.data .data.* .gnu.linkonce.d.*) + *(.eh_frame) + _edata = .; + } > ram + + .bss ADDR (.data) + SIZEOF (.data) (NOLOAD) : + { + __bss_start = .; + *(.dynbss) + *(.sbss .sbss.*) + *(.scommon) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. */ + . = ALIGN (32 / 8); + } > ram + __bss_end = . ; + _end = .; + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + .debug_pubtypes 0 : { *(.debug_pubtypes) } + .debug_ranges 0 : { *(.debug_ranges) } + .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) } +} diff --git a/sys/pic32/cfg/bootloader-maximite.ld b/sys/pic32/cfg/bootloader-maximite.ld new file mode 100644 index 0000000..8ec7152 --- /dev/null +++ b/sys/pic32/cfg/bootloader-maximite.ld @@ -0,0 +1,117 @@ +/* + * Linker script for PIC32 firmware using HID bootloader. + * Flash area for user starts at 9d003000. + * Start address for user program is 9d004000. + */ +OUTPUT_FORMAT("elf32-littlemips", "elf32-bigmips", + "elf32-littlemips") +OUTPUT_ARCH(mips) +ENTRY(_reset_vector_) +MEMORY +{ + flash (rx) : ORIGIN = 0x9d003000, LENGTH = 512K-12K + ram (rw!x): ORIGIN = 0x80000000, LENGTH = 26K + u0area (rw!x): ORIGIN = 0x80006800, LENGTH = 3K + uarea (rw!x): ORIGIN = 0x80007400, LENGTH = 3K + + /* Required by Microchip C32 linker */ + kseg0_program_mem (rx) : ORIGIN = 0x9D000000, LENGTH = 0x80000 + kseg0_boot_mem : ORIGIN = 0x9FC00000, LENGTH = 0x1000 + exception_mem : ORIGIN = 0x9FC04000, LENGTH = 0x1000 + kseg1_boot_mem : ORIGIN = 0xBFC00000, LENGTH = 0 + kseg1_data_mem (w!x) : ORIGIN = 0xA0000000, LENGTH = 0x20000 +} + +/* higher address of the user mode stack */ +u0 = ORIGIN(u0area); +u = ORIGIN(uarea); +u_end = ORIGIN(uarea) + LENGTH(uarea); + +SECTIONS +{ + .text ORIGIN(flash) : + { + /* Exception handlers. */ + *(.exception) + . = 0x1000; + /* Execution starts here. */ + *(.startup) + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.glue_7t) *(.glue_7) + __rodata_start = . ; + *(.rodata .rodata.* .gnu.linkonce.r.* .rel.dyn) + *(.dinit) + /* Align here to ensure that the .text section ends on word boundary. */ + . = ALIGN (32 / 8); + _etext = .; + } > flash + + /* Start data (internal SRAM). */ + .data : AT (ADDR (.text) + SIZEOF (.text)) + { + __data_start = . ; + _gp = .; /* We use only 32k RAM for kernel, so no need for 0x8000 offset. */ + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + *(.sdata .sdata.* .gnu.linkonce.s.*) + *(.data .data.* .gnu.linkonce.d.*) + *(.eh_frame) + _edata = .; + } > ram + + .bss ADDR (.data) + SIZEOF (.data) (NOLOAD) : + { + __bss_start = .; + *(.dynbss) + *(.sbss .sbss.*) + *(.scommon) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. */ + . = ALIGN (32 / 8); + } > ram + __bss_end = . ; + _end = .; + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + .debug_pubtypes 0 : { *(.debug_pubtypes) } + .debug_ranges 0 : { *(.debug_ranges) } + .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) } +} diff --git a/sys/pic32/cfg/bootloader-sdram.ld b/sys/pic32/cfg/bootloader-sdram.ld new file mode 100644 index 0000000..ba65550 --- /dev/null +++ b/sys/pic32/cfg/bootloader-sdram.ld @@ -0,0 +1,136 @@ +/* + * Linker script for PIC32 firmware using HID bootloader. + * Flash area for user starts at 9d005000. + * Start address for user program is 9d006000. + */ +OUTPUT_FORMAT("elf32-littlemips", "elf32-bigmips", + "elf32-littlemips") +OUTPUT_ARCH(mips) +ENTRY(_reset_vector_) +MEMORY +{ + flash (rx) : ORIGIN = 0x9d005000, LENGTH = 512K-20K + ram (rw!x): ORIGIN = 0x80000000, LENGTH = 0x62C0 + u0area (rw!x): ORIGIN = 0x800062C0, LENGTH = 3K + uarea (rw!x): ORIGIN = 0x80006EC0, LENGTH = 3K + keram (rwx) : ORIGIN = 0x80007AC0, LENGTH = 0x540 + + /* Required by Microchip C32 linker */ + kseg0_program_mem (rx) : ORIGIN = 0x9D000000, LENGTH = 0x80000 + kseg0_boot_mem : ORIGIN = 0x9FC00000, LENGTH = 0x1000 + exception_mem : ORIGIN = 0x9FC06000, LENGTH = 0x1000 + kseg1_boot_mem : ORIGIN = 0xBFC00000, LENGTH = 0 + kseg1_data_mem (w!x) : ORIGIN = 0xA0000000, LENGTH = 0x20000 +} + +/* higher address of the user mode stack */ +u0 = ORIGIN(u0area); +u = ORIGIN(uarea); +u_end = ORIGIN(uarea) + LENGTH(uarea); + +_keram_start = ORIGIN(keram); +_keram_end = ORIGIN(keram) + LENGTH(keram); + +SECTIONS +{ + .text ORIGIN(flash) : + { + /* Exception handlers. */ + *(.exception) + . = 0x1000; + /* Execution starts here. */ + *(.startup) + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.glue_7t) *(.glue_7) + __rodata_start = . ; + *(.rodata .rodata.* .gnu.linkonce.r.* .rel.dyn) + *(.dinit) + /* Align here to ensure that the .text section ends on word boundary. */ + . = ALIGN (32 / 8); + _etext = .; + } > flash + + /* Start data (internal SRAM). */ + .data : AT (ADDR (.text) + SIZEOF (.text)) + { + __data_start = . ; + _gp = .; /* We use only 32k RAM for kernel, so no need for 0x8000 offset. */ + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + *(.sdata .sdata.* .gnu.linkonce.s.*) + *(.data .data.* .gnu.linkonce.d.*) + *(.eh_frame) + _edata = .; + } > ram + + .bss ADDR (.data) + SIZEOF (.data) (NOLOAD) : + { + __bss_start = .; + *(.dynbss) + *(.sbss .sbss.*) + *(.scommon) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. */ + . = ALIGN (32 / 8); + } > ram + __bss_end = . ; + _end = .; + +/* + * RAM functions go at the end of our stack and heap allocation. + * Alignment of 2K required by the boundary register (BMXDKPBA). + */ + .ramfunc : AT (LOADADDR (.data) + SIZEOF (.data)) + { + _ramfunc_begin = . ; + *(.ramfunc .ramfunc.*) + . = ALIGN(4) ; + _ramfunc_end = . ; + } >keram + _ramfunc_image_begin = LOADADDR(.ramfunc) ; + _ramfunc_length = SIZEOF(.ramfunc) ; + + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + .debug_pubtypes 0 : { *(.debug_pubtypes) } + .debug_ranges 0 : { *(.debug_ranges) } + .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) } +} diff --git a/sys/pic32/cfg/bootloader-ubw32.ld b/sys/pic32/cfg/bootloader-ubw32.ld new file mode 100644 index 0000000..ac39fe0 --- /dev/null +++ b/sys/pic32/cfg/bootloader-ubw32.ld @@ -0,0 +1,117 @@ +/* + * Linker script for PIC32 firmware using HID bootloader. + * Flash area for user starts at 9d005000. + * Start address for user program is 9d006000. + */ +OUTPUT_FORMAT("elf32-littlemips", "elf32-bigmips", + "elf32-littlemips") +OUTPUT_ARCH(mips) +ENTRY(_reset_vector_) +MEMORY +{ + flash (rx) : ORIGIN = 0x9d005000, LENGTH = 512K-20K + ram (rw!x): ORIGIN = 0x80000000, LENGTH = 26K + u0area (rw!x): ORIGIN = 0x80006800, LENGTH = 3K + uarea (rw!x): ORIGIN = 0x80007400, LENGTH = 3K + + /* Required by Microchip C32 linker */ + kseg0_program_mem (rx) : ORIGIN = 0x9D000000, LENGTH = 0x80000 + kseg0_boot_mem : ORIGIN = 0x9FC00000, LENGTH = 0x1000 + exception_mem : ORIGIN = 0x9FC06000, LENGTH = 0x1000 + kseg1_boot_mem : ORIGIN = 0xBFC00000, LENGTH = 0 + kseg1_data_mem (w!x) : ORIGIN = 0xA0000000, LENGTH = 0x20000 +} + +/* higher address of the user mode stack */ +u0 = ORIGIN(u0area); +u = ORIGIN(uarea); +u_end = ORIGIN(uarea) + LENGTH(uarea); + +SECTIONS +{ + .text ORIGIN(flash) : + { + /* Exception handlers. */ + *(.exception) + . = 0x1000; + /* Execution starts here. */ + *(.startup) + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.glue_7t) *(.glue_7) + __rodata_start = . ; + *(.rodata .rodata.* .gnu.linkonce.r.* .rel.dyn) + *(.dinit) + /* Align here to ensure that the .text section ends on word boundary. */ + . = ALIGN (32 / 8); + _etext = .; + } > flash + + /* Start data (internal SRAM). */ + .data : AT (ADDR (.text) + SIZEOF (.text)) + { + __data_start = . ; + _gp = .; /* We use only 32k RAM for kernel, so no need for 0x8000 offset. */ + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + *(.sdata .sdata.* .gnu.linkonce.s.*) + *(.data .data.* .gnu.linkonce.d.*) + *(.eh_frame) + _edata = .; + } > ram + + .bss ADDR (.data) + SIZEOF (.data) (NOLOAD) : + { + __bss_start = .; + *(.dynbss) + *(.sbss .sbss.*) + *(.scommon) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. */ + . = ALIGN (32 / 8); + } > ram + __bss_end = . ; + _end = .; + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + .debug_pubtypes 0 : { *(.debug_pubtypes) } + .debug_ranges 0 : { *(.debug_ranges) } + .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) } +} diff --git a/sys/pic32/cfg/bootloader.dev b/sys/pic32/cfg/bootloader.dev new file mode 100644 index 0000000..acd618f --- /dev/null +++ b/sys/pic32/cfg/bootloader.dev @@ -0,0 +1,83 @@ +always + target bootloader + define USB_NUM_STRING_DESCRIPTORS 3 + define USB_MAX_EP_NUMBER 1 + define USB_EP0_BUFF_SIZE 8 + define HID_INPUT_REPORT_BYTES 2 + define HID_OUTPUT_REPORT_BYTES 2 + define HID_FEATURE_REPORT_BYTES 2 + define HID_INT_OUT_EP_SIZE 64 + define HID_INT_IN_EP_SIZE 64 + define HID_RPT01_SIZE 29 + nofile devcfg.o +end always + +option button + define BL_BUTTON_PORT $TRIS(%1) + define BL_BUTTON_PIN $PIN(%1) +end option + +option crystal + define BL_CRYSTAL %1 +end option + +option jump + define FLASH_JUMP %1 +end option + +option user + define FLASH_USER %1 +end option + +option led + define BL_LED_PORT $TRIS(%1) + define BL_LED_PIN $PIN(%1) +end option + +option invled + define BL_LED_PORT $TRIS(%1) + define BL_LED_PIN $PIN(%1) + define BL_LED_INVERT +end option + +option led2 + define BL_LED2_PORT $TRIS(%1) + define BL_LED2_PIN $PIN(%1) +end option + +option invled2 + define BL_LED2_PORT $TRIS(%1) + define BL_LED2_PIN $PIN(%1) + define BL_LED2_INVERT +end option + +option led3 + define BL_LED3_PORT $TRIS(%1) + define BL_LED3_PIN $PIN(%1) +end option + +option invled3 + define BL_LED3_PORT $TRIS(%1) + define BL_LED3_PIN $PIN(%1) + define BL_LED3_INVERT +end option + +option set + define BL_SET_PORT $TRIS(%1) + define BL_SET_PIN $PIN(%1) +end option + +option set2 + define BL_SET2_PORT $TRIS(%1) + define BL_SET2_PIN $PIN(%1) +end option + +option clear + define BL_CLEAR_PORT $TRIS(%1) + define BL_CLEAR_PIN $PIN(%1) +end option + +option clear2 + define BL_CLEAR2_PORT $TRIS(%1) + define BL_CLEAR2_PIN $PIN(%1) +end option diff --git a/sys/pic32/cfg/bootloader.ld b/sys/pic32/cfg/bootloader.ld new file mode 100644 index 0000000..e21057f --- /dev/null +++ b/sys/pic32/cfg/bootloader.ld @@ -0,0 +1,116 @@ +/* + * Linker script for PIC32 firmware using HID bootloader. + * Flash area for user starts at 9d000000. + * Start address for user program is 9d000000. + */ +OUTPUT_FORMAT("elf32-littlemips", "elf32-bigmips", + "elf32-littlemips") +OUTPUT_ARCH(mips) +ENTRY(_reset_vector_) +MEMORY +{ + flash (rx) : ORIGIN = 0x9d000000, LENGTH = 512K + ram (rw!x): ORIGIN = 0x80000000, LENGTH = 26K + u0area (rw!x): ORIGIN = 0x80006800, LENGTH = 3K + uarea (rw!x): ORIGIN = 0x80007400, LENGTH = 3K + + /* Required by Microchip C32 linker */ + kseg0_program_mem (rx) : ORIGIN = 0x9D000000, LENGTH = 0x80000 + kseg0_boot_mem : ORIGIN = 0x9FC00000, LENGTH = 0x1000 + exception_mem : ORIGIN = 0x9FC00000, LENGTH = 0x1000 + kseg1_boot_mem : ORIGIN = 0xBFC00000, LENGTH = 0 + kseg1_data_mem (w!x) : ORIGIN = 0xA0000000, LENGTH = 0x20000 +} + +/* higher address of the user mode stack */ +u0 = ORIGIN(u0area); +u = ORIGIN(uarea); +u_end = ORIGIN(uarea) + LENGTH(uarea); + +SECTIONS +{ + .text ORIGIN(flash) : + { + /* Exception handlers. */ + *(.exception) + /* Execution starts here. */ + *(.startup) + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.glue_7t) *(.glue_7) + __rodata_start = . ; + *(.rodata .rodata.* .gnu.linkonce.r.* .rel.dyn) + *(.dinit) + /* Align here to ensure that the .text section ends on word boundary. */ + . = ALIGN (32 / 8); + _etext = .; + } > flash + + /* Start data (internal SRAM). */ + .data : AT (ADDR (.text) + SIZEOF (.text)) + { + __data_start = . ; + _gp = .; /* We use only 32k RAM for kernel, so no need for 0x8000 offset. */ + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + *(.sdata .sdata.* .gnu.linkonce.s.*) + *(.data .data.* .gnu.linkonce.d.*) + *(.eh_frame) + _edata = .; + } > ram + + .bss ADDR (.data) + SIZEOF (.data) (NOLOAD) : + { + __bss_start = .; + *(.dynbss) + *(.sbss .sbss.*) + *(.scommon) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. */ + . = ALIGN (32 / 8); + } > ram + __bss_end = . ; + _end = .; + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + .debug_pubtypes 0 : { *(.debug_pubtypes) } + .debug_ranges 0 : { *(.debug_ranges) } + .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) } +} diff --git a/sys/pic32/cfg/console.dev b/sys/pic32/cfg/console.dev new file mode 100644 index 0000000..8c39586 --- /dev/null +++ b/sys/pic32/cfg/console.dev @@ -0,0 +1,18 @@ +always + file cons.o +end always + +option led + define LED_TTY_PORT $TRIS(%1) + define LED_TTY_PIN $PIN(%1) +end option + +option invled + define LED_TTY_PORT $TRIS(%1) + define LED_TTY_PIN $PIN(%1) + define LED_TTY_INVERT YES +end option + +option device + define CONSOLE_DEVICE %1 +end option diff --git a/sys/pic32/cfg/devcfg.dev b/sys/pic32/cfg/devcfg.dev new file mode 100644 index 0000000..9c83c88 --- /dev/null +++ b/sys/pic32/cfg/devcfg.dev @@ -0,0 +1,3 @@ +always + file devcfg.o +end always diff --git a/sys/pic32/cfg/foreignbootloader.dev b/sys/pic32/cfg/foreignbootloader.dev new file mode 100644 index 0000000..fcbeefd --- /dev/null +++ b/sys/pic32/cfg/foreignbootloader.dev @@ -0,0 +1,3 @@ +always + nofile devcfg.o +end always diff --git a/sys/pic32/cfg/fubarino.map b/sys/pic32/cfg/fubarino.map new file mode 100644 index 0000000..4d63bd8 --- /dev/null +++ b/sys/pic32/cfg/fubarino.map @@ -0,0 +1,53 @@ +# Format is: silk port pin +# silk is the name of the pin, port and pin is what it maps to. +0 D 8 +1 D 9 +2 D 10 +3 D 11 +4 D 0 +5 C 13 +6 C 14 +7 D 1 +8 D 2 +9 D 3 +10 D 4 +11 D 5 +12 D 6 +13 D 7 +14 F 0 +15 F 1 +16 E 0 +17 E 1 +18 E 2 +19 E 3 +20 E 4 +21 E 5 +22 E 6 +23 E 7 +SCK G 6 +24 G 6 +SDI G 7 +25 G 7 +SDO G 8 +26 G 8 +SS G 9 +27 G 9 +A14 B 4 +A13 B 3 +A12 B 2 +A11 B 1 +A10 B 0 +A9 B 7 +A8 B 6 +A7 B 8 +A6 B 9 +A5 B 10 +A4 B 11 +A3 B 12 +A2 B 13 +A1 B 14 +A0 B 15 +RX F 4 +28 F 4 +TX F 5 +29 F 5 diff --git a/sys/pic32/cfg/generic.map b/sys/pic32/cfg/generic.map new file mode 100644 index 0000000..869d343 --- /dev/null +++ b/sys/pic32/cfg/generic.map @@ -0,0 +1,113 @@ +A0 A 0 +A1 A 1 +A2 A 2 +A3 A 3 +A4 A 4 +A5 A 5 +A6 A 6 +A7 A 7 +A8 A 8 +A9 A 9 +A10 A 10 +A11 A 11 +A12 A 12 +A13 A 13 +A14 A 14 +A15 A 15 +B0 B 0 +B1 B 1 +B2 B 2 +B3 B 3 +B4 B 4 +B5 B 5 +B6 B 6 +B7 B 7 +B8 B 8 +B9 B 9 +B10 B 10 +B11 B 11 +B12 B 12 +B13 B 13 +B14 B 14 +B15 B 15 +C0 C 0 +C1 C 1 +C2 C 2 +C3 C 3 +C4 C 4 +C5 C 5 +C6 C 6 +C7 C 7 +C8 C 8 +C9 C 9 +C10 C 10 +C11 C 11 +C12 C 12 +C13 C 13 +C14 C 14 +C15 C 15 +D0 D 0 +D1 D 1 +D2 D 2 +D3 D 3 +D4 D 4 +D5 D 5 +D6 D 6 +D7 D 7 +D8 D 8 +D9 D 9 +D10 D 10 +D11 D 11 +D12 D 12 +D13 D 13 +D14 D 14 +D15 D 15 +E0 E 0 +E1 E 1 +E2 E 2 +E3 E 3 +E4 E 4 +E5 E 5 +E6 E 6 +E7 E 7 +E8 E 8 +E9 E 9 +E10 E 10 +E11 E 11 +E12 E 12 +E13 E 13 +E14 E 14 +E15 E 15 +F0 F 0 +F1 F 1 +F2 F 2 +F3 F 3 +F4 F 4 +F5 F 5 +F6 F 6 +F7 F 7 +F8 F 8 +F9 F 9 +F10 F 10 +F11 F 11 +F12 F 12 +F13 F 13 +F14 F 14 +F15 F 15 +G0 G 0 +G1 G 1 +G2 G 2 +G3 G 3 +G4 G 4 +G5 G 5 +G6 G 6 +G7 G 7 +G8 G 8 +G9 G 9 +G10 G 10 +G11 G 11 +G12 G 12 +G13 G 13 +G14 G 14 +G15 G 15 + diff --git a/sys/pic32/cfg/glcd.dev b/sys/pic32/cfg/glcd.dev new file mode 100644 index 0000000..ec2090b --- /dev/null +++ b/sys/pic32/cfg/glcd.dev @@ -0,0 +1,4 @@ +always + file glcd.o + define GLCD_ENABLED YES +end always diff --git a/sys/pic32/cfg/glob.dev b/sys/pic32/cfg/glob.dev new file mode 100644 index 0000000..bca2936 --- /dev/null +++ b/sys/pic32/cfg/glob.dev @@ -0,0 +1,8 @@ +always + file kern_glob.o + define GLOB_ENABLED YES +end always + +option globsz + define GLOBSZ %1 +end option diff --git a/sys/pic32/cfg/global.dev b/sys/pic32/cfg/global.dev new file mode 100644 index 0000000..4c57a92 --- /dev/null +++ b/sys/pic32/cfg/global.dev @@ -0,0 +1,456 @@ +# Special device for global options + +always + file devcfg.o + define DC0_DEBUG DEVCFG0_DEBUG_DISABLED + define DC0_ICE 0 + + define DC1_FNOSC DEVCFG1_FNOSC_PRIPLL + define DC1_SOSC 0 + define DC1_IESO DEVCFG1_IESO + define DC1_POSCMOD DEVCFG1_POSCMOD_HS + define DC1_OSCIOFNC 0 + define DC1_PBDIV DEVCFG1_FPBDIV_1 + define DC1_CKM 0 + define DC1_CKS 0 + define DC1_WDTPS DEVCFG1_WDTPS_1 + define DC1_WDTEN 0 + + define DC2_PLLIDIV DEVCFG2_FPLLIDIV_2 + define DC2_PLLMUL DEVCFG2_FPLLMUL_20 + define DC2_UPLLIDIV DEVCFG2_UPLLIDIV_2 + define DC2_UPLL 0 + define DC2_PLLODIV DEVCFG2_FPLLODIV_1 + + define DC3_USERID 0xffff + define DC3_SRS DEVCFG3_FSRSSEL_7 + define DC3_MII DEVCFG3_FMIIEN + define DC3_ETH DEVCFG3_FETHIO + define DC3_CAN DEVCFG3_FCANIO + define DC3_USBID DEVCFG3_FUSBIDIO + define DC3_VBUSON DEVCFG3_FVBUSONIO + + define BUS_DIV 1 + define CPU_IDIV 2 + define CPU_ODIV 1 + define CPU_MUL 20 + define CRYSTAL 8 +end always + +option nproc + define NPROC %1 +end option + +option nbuf + define NBUF %1 +end option + +option nfile + define NFILE %1 +end option + +option ninode + define NINODE %1 +end option + +option smapsiz + define SMAPSIZ %1 +end option + +option hz + define HZ %1 +end option + +option haltreboot + define HALTREBOOT YES +end option + +option blreboot + set BLREBOOT -p +end option + +option partition + define PARTITION "%1" +end option + +option nmount + define NMOUNT %1 +end option + +# Now for the device config options: + +option crystal + define CRYSTAL %1 +end option + +# DC0 + +option debug=disabled + define DC0_DEBUG DEVCFG0_DEBUG_DISABLED +end option + +option debug=enabled + define DC0_DEBUG DEVCFG0_DEBUG_ENABLED +end option + +option debug=ice + define DC0_ICE DEVCFG0_ICESEL +end option + +# DC1 +option fnosc=frc + define DC1_FNOSC DEVCFG1_FNOSC_FRC +end option +option fnosc=frcdivpll + define DC1_FNOSC DEVCFG1_FNOSC_FRCDIVPLL +end option +option fnosc=pri + define DC1_FNOSC DEVCFG1_FNOSC_PRI +end option +option fnosc=pripll + define DC1_FNOSC DEVCFG1_FNOSC_PRIPLL +end option +option fnosc=sec + define DC1_FNOSC DEVCFG1_FNOSC_SEC +end option +option fnosc=lprc + define DC1_FNOSC DEVCFG1_FNOSC_LPRC +end option +option fnosc=frcdiv + define DC1_FNOSC DEVCFG1_FNOSC_FRCDIV +end option + +option secondary=on + define DC1_SOSC DEVCFG1_FSOSCEN +end option +option secondary=off + define DC1_SOSC 0 +end option + +option switchover=on + define DC1_IESO DEVCFG1_IESO +option +option switchover=off + define DC1_IESO 0 +option + +option osc=ext + define DC1_POSCMOD DEVCFG1_POSCMOD_EXT +end option +option osc=xt + define DC1_POSCMOD DEVCFG1_POSCMOD_XT +end option +option osc=hs + define DC1_POSCMOD DEVCFG1_POSCMOD_HS +end option +option osc=off + define DC1_POSCMOD DEVCFG1_POSCMOD_DISABLE +end option + +option oscio=io + define DC1_OSCIOFNC 0 +end option +option oscio=clock + define DC1_OSCIOFNC DEVCFG1_OSCIOFNC +end option + +option busdiv=1 + define DC1_PBDIV DEVCFG1_FPBDIV_1 + define BUS_DIV 1 +end option +option busdiv=2 + define DC1_PBDIV DEVCFG1_FPBDIV_2 + define BUS_DIV 2 +end option +option busdiv=4 + define DC1_PBDIV DEVCFG1_FPBDIV_4 + define BUS_DIV 4 +end option +option busdiv=8 + define DC1_PBDIV DEVCFG1_FPBDIV_8 + define BUS_DIV 8 +end option + +option fsmonitor=on + define DC1_CKM 0 +end option +option fsmonitor=off + define DC1_CKM DEVCFG1_FCKM_DISABLE +end option + +option fsswitch=on + define DC1_CKS 0 +end option +option fsswitch=off + define DC1_CKS DEVCFG1_FCKS_DISABLE +end option + +option wdtps=1 + define DC1_WDTPS DEVCFG1_WDTPS_1 +end option +option wdtps=2 + define DC1_WDTPS DEVCFG1_WDTPS_2 +end option +option wdtps=4 + define DC1_WDTPS DEVCFG1_WDTPS_4 +end option +option wdtps=8 + define DC1_WDTPS DEVCFG1_WDTPS_8 +end option +option wdtps=16 + define DC1_WDTPS DEVCFG1_WDTPS_16 +end option +option wdtps=32 + define DC1_WDTPS DEVCFG1_WDTPS_32 +end option +option wdtps=64 + define DC1_WDTPS DEVCFG1_WDTPS_64 +end option +option wdtps=128 + define DC1_WDTPS DEVCFG1_WDTPS_128 +end option +option wdtps=256 + define DC1_WDTPS DEVCFG1_WDTPS_256 +end option +option wdtps=512 + define DC1_WDTPS DEVCFG1_WDTPS_512 +end option +option wdtps=1024 + define DC1_WDTPS DEVCFG1_WDTPS_1024 +end option +option wdtps=2048 + define DC1_WDTPS DEVCFG1_WDTPS_2048 +end option +option wdtps=4096 + define DC1_WDTPS DEVCFG1_WDTPS_4096 +end option +option wdtps=8192 + define DC1_WDTPS DEVCFG1_WDTPS_8192 +end option +option wdtps=16384 + define DC1_WDTPS DEVCFG1_WDTPS_16384 +end option +option wdtps=32768 + define DC1_WDTPS DEVCFG1_WDTPS_32768 +end option +option wdtps=65536 + define DC1_WDTPS DEVCFG1_WDTPS_65536 +end option +option wdtps=131072 + define DC1_WDTPS DEVCFG1_WDTPS_131072 +end option +option wdtps=262144 + define DC1_WDTPS DEVCFG1_WDTPS_262144 +end option +option wdtps=524288 + define DC1_WDTPS DEVCFG1_WDTPS_524288 +end option +option wdtps=1048576 + define DC1_WDTPS DEVCFG1_WDTPS_1048576 +end option + +option watchdog=on + define DC1_WDTEN DEVCFG1_FWDTEN +end option +option watchdog=off + define DC1_WDTEN 0 +end option + +# DC2 + +option pllidiv=1 + define DC2_PLLIDIV DEVCFG2_FPLLIDIV_1 + define CPU_IDIV 1 +end option +option pllidiv=2 + define DC2_PLLIDIV DEVCFG2_FPLLIDIV_2 + define CPU_IDIV 2 +end option +option pllidiv=3 + define DC2_PLLIDIV DEVCFG2_FPLLIDIV_3 + define CPU_IDIV 3 +end option +option pllidiv=4 + define DC2_PLLIDIV DEVCFG2_FPLLIDIV_4 + define CPU_IDIV 4 +end option +option pllidiv=5 + define DC2_PLLIDIV DEVCFG2_FPLLIDIV_5 + define CPU_IDIV 5 +end option +option pllidiv=6 + define DC2_PLLIDIV DEVCFG2_FPLLIDIV_6 + define CPU_IDIV 6 +end option +option pllidiv=10 + define DC2_PLLIDIV DEVCFG2_FPLLIDIV_10 + define CPU_IDIV 10 +end option +option pllidiv=12 + define DC2_PLLIDIV DEVCFG2_FPLLIDIV_12 + define CPU_IDIV 12 +end option + +option pllmul=15 + define DC2_PLLMUL DEVCFG2_FPLLMUL_15 + define CPU_MUL 15 +end option +option pllmul=16 + define DC2_PLLMUL DEVCFG2_FPLLMUL_16 + define CPU_MUL 16 +end option +option pllmul=17 + define DC2_PLLMUL DEVCFG2_FPLLMUL_17 + define CPU_MUL 17 +end option +option pllmul=18 + define DC2_PLLMUL DEVCFG2_FPLLMUL_18 + define CPU_MUL 18 +end option +option pllmul=19 + define DC2_PLLMUL DEVCFG2_FPLLMUL_19 + define CPU_MUL 19 +end option +option pllmul=20 + define DC2_PLLMUL DEVCFG2_FPLLMUL_20 + define CPU_MUL 20 +end option +option pllmul=21 + define DC2_PLLMUL DEVCFG2_FPLLMUL_21 + define CPU_MUL 21 +end option +option pllmul=24 + define DC2_PLLMUL DEVCFG2_FPLLMUL_24 + define CPU_MUL 24 +end option + +option upllidiv=1 + define DC2_UPLLIDIV DEVCFG2_UPLLIDIV_1 +end option +option upllidiv=2 + define DC2_UPLLIDIV DEVCFG2_UPLLIDIV_2 +end option +option upllidiv=3 + define DC2_UPLLIDIV DEVCFG2_UPLLIDIV_3 +end option +option upllidiv=4 + define DC2_UPLLIDIV DEVCFG2_UPLLIDIV_4 +end option +option upllidiv=5 + define DC2_UPLLIDIV DEVCFG2_UPLLIDIV_5 +end option +option upllidiv=6 + define DC2_UPLLIDIV DEVCFG2_UPLLIDIV_6 +end option +option upllidiv=10 + define DC2_UPLLIDIV DEVCFG2_UPLLIDIV_10 +end option +option upllidiv=12 + define DC2_UPLLIDIV DEVCFG2_UPLLIDIV_12 +end option + +option upll=on + define DC2_UPLL 0 +end option +option upll=off + define DC2_UPLL DEVCFG2_UPLLDIS +end option + +option pllodiv=1 + define DC2_PLLODIV DEVCFG2_FPLLODIV_1 + define CPU_ODIV 1 +end option +option pllodiv=2 + define DC2_PLLODIV DEVCFG2_FPLLODIV_2 + define CPU_ODIV 2 +end option +option pllodiv=4 + define DC2_PLLODIV DEVCFG2_FPLLODIV_4 + define CPU_ODIV 4 +end option +option pllodiv=8 + define DC2_PLLODIV DEVCFG2_FPLLODIV_8 + define CPU_ODIV 8 +end option +option pllodiv=16 + define DC2_PLLODIV DEVCFG2_FPLLODIV_16 + define CPU_ODIV 16 +end option +option pllodiv=32 + define DC2_PLLODIV DEVCFG2_FPLLODIV_32 + define CPU_ODIV 32 +end option +option pllodiv=64 + define DC2_PLLODIV DEVCFG2_FPLLODIV_64 + define CPU_ODIV 64 +end option +option pllodiv=256 + define DC2_PLLODIV DEVCFG2_FPLLODIV_256 + define CPU_ODIV 256 +end option + +# DC3 +option userid + define DC3_USERID %1 +end option + +option srs=all + define DC3_SRS DEVCFG3_FSRSSEL_ALL +end option +option srs=1 + define DC3_SRS DEVCFG3_FSRSSEL_1 +end option +option srs=2 + define DC3_SRS DEVCFG3_FSRSSEL_2 +end option +option srs=3 + define DC3_SRS DEVCFG3_FSRSSEL_3 +end option +option srs=4 + define DC3_SRS DEVCFG3_FSRSSEL_4 +end option +option srs=5 + define DC3_SRS DEVCFG3_FSRSSEL_5 +end option +option srs=6 + define DC3_SRS DEVCFG3_FSRSSEL_6 +end option +option srs=7 + define DC3_SRS DEVCFG3_FSRSSEL_7 +end option + +option mii=on + define DC3_MII DEVCFG3_FMIIEN +end option +option mii=off + define DC3_MII 0 +end option + +option eth=default + define DC3_ETH DEVCFG3_FETHIO +end option +option eth=alternate + define DC3_ETH 0 +end option + +option can=default + define DC3_CAN DEVCFG3_FCANIO +end option +option can=alternate + define DC3_CAN 0 +end option + +option usbid=usb + define DC3_USBID DEVCFG3_FUSBIDIO +end option +option usbid=io + define DC3_USBID 0 +end option + +option vbuson=usb + define DC3_VBUSON DEVCFG3_FVBUSONIO +end option +option vbuson=io + define DC3_VBUSON 0 +end option + diff --git a/sys/pic32/cfg/gpio.dev b/sys/pic32/cfg/gpio.dev new file mode 100644 index 0000000..6849ac2 --- /dev/null +++ b/sys/pic32/cfg/gpio.dev @@ -0,0 +1,4 @@ +always + file gpio.o + define GPIO_ENABLED YES +end always diff --git a/sys/pic32/cfg/kernel.dev b/sys/pic32/cfg/kernel.dev new file mode 100644 index 0000000..88e32a2 --- /dev/null +++ b/sys/pic32/cfg/kernel.dev @@ -0,0 +1,78 @@ +always + define KERNEL + define UCB_METER + file _startup.o + file clock.o + file devsw.o + file sysctl.o + file signal.o + file machdep.o + file mem.o + file exception.o + file init_main.o + file init_sysent.o + file kern_clock.o + file kern_descrip.o + file kern_exec.o + file kern_exit.o + file kern_fork.o + file kern_mman.o + file kern_proc.o + file kern_prot.o + file kern_prot2.o + file kern_resource.o + file kern_sig.o + file kern_sig2.o + file kern_subr.o + file kern_synch.o + file kern_sysctl.o + file kern_time.o + file subr_prf.o + file subr_rmap.o + file sys_generic.o + file sys_inode.o + file syscalls.o + file sys_pipe.o + file sys_process.o + file vfs_vnops.o + file vm_sched.o + file vm_swap.o + file vm_swp.o + file swap.o + file vers.o + require ufs + require tty + require global + + define CPU_KHZ '((CRYSTAL*1000)/CPU_IDIV*CPU_MUL/CPU_ODIV)' + define BUS_KHZ 'CPU_KHZ/BUS_DIV' + +end always + +option cpu_khz + define CPU_KHZ %1 +end option + +option bus_khz + define BUS_KHZ %1 +end option + +option led + define LED_KERNEL_PORT $TRIS(%1) + define LED_KERNEL_PIN $PIN(%1) +end option + +option invled + define LED_KERNEL_PORT $TRIS(%1) + define LED_KERNEL_PIN $PIN(%1) + define LED_KERNEL_INVERT YES +end option + +option highlight + define KERNEL_HIGHLIGHT YES +end option + +option clear_pin + define GPIO_CLEAR_PORT $TRIS(%1) + define GPIO_CLEAR_PIN $PIN(%1) +end option diff --git a/sys/pic32/cfg/log.dev b/sys/pic32/cfg/log.dev new file mode 100644 index 0000000..31df5b4 --- /dev/null +++ b/sys/pic32/cfg/log.dev @@ -0,0 +1,4 @@ +always + file subr_log.o + define LOG_ENABLED YES +end always diff --git a/sys/pic32/cfg/max32.map b/sys/pic32/cfg/max32.map new file mode 100644 index 0000000..029d9b9 --- /dev/null +++ b/sys/pic32/cfg/max32.map @@ -0,0 +1,105 @@ +RX F 2 +0 F 2 +TX F 8 +1 F 8 +2 E 8 +3 D 0 +4 C 14 +5 D 1 +6 D 2 +7 E 9 +8 D 12 +9 D 3 +10 D 4 +11 C 4 +12 A 2 +LED A 3 +13 A 3 +14 F 13 +15 F 12 +16 F 5 +17 F 4 +18 D 15 +19 D 14 +20 A 15 +21 A 14 +22 C 2 +23 C 3 +24 C 0 +25 F 3 +26 G 3 +27 G 2 +28 G 15 +29 G 7 +30 E 7 +31 E 6 +32 E 5 +33 E 4 +34 E 3 +35 E 2 +36 E 1 +37 E 0 +38 D 10 +39 D 5 +40 B 11 +41 B 13 +42 B 12 +43 G 8 +44 A 10 +45 F 0 +46 F 1 +47 D 6 +48 D 8 +49 D 11 +50 G 7 +51 G 8 +52 G 6 +53 G 9 +A0 B 0 +54 B 0 +A1 B 1 +55 B 1 +A2 B 2 +56 B 2 +A3 B 3 +57 B 3 +A4 B 4 +58 B 4 +A5 B 5 +59 B 5 +A6 B 6 +60 B 6 +A7 B 7 +61 B 7 +A8 B 8 +62 B 8 +A9 B 9 +63 B 9 +A10 B 10 +64 B 10 +A11 B 11 +65 B 11 +A12 B 12 +66 B 12 +A13 B 13 +67 B 13 +A14 B 14 +68 B 14 +A15 B 15 +69 B 15 +70 A 0 +71 A 1 +72 A 4 +73 A 5 +74 D 9 +75 C 13 +76 D 13 +77 D 7 +78 G 1 +79 G 0 +80 A 6 +81 A 7 +82 G 14 +83 G 12 +84 G 13 +85 A 9 diff --git a/sys/pic32/cfg/mrams.dev b/sys/pic32/cfg/mrams.dev new file mode 100644 index 0000000..cd34903 --- /dev/null +++ b/sys/pic32/cfg/mrams.dev @@ -0,0 +1,84 @@ +always + define MRAMS_ENABLED + file rd_mrams.o + require rdisk + require spibus + define MRAMS_CHIPSIZE 512 +end always + +option chips + define MRAMS_CHIPS %1 +end option + +option port + define MRAMS_PORT %1 +end option + +option chipsize + define MRAMS_CHIPSIZE %1 +end option + +option mhz + define MRAMS_MHZ %1 +end option + +option cs0 + define MRAMS_CS0_PORT $TRIS(%1) + define MRAMS_CS0_PIN $PIN(%1) +end option + +option cs1 + define MRAMS_CS1_PORT $TRIS(%1) + define MRAMS_CS1_PIN $PIN(%1) +end option + +option cs2 + define MRAMS_CS2_PORT $TRIS(%1) + define MRAMS_CS2_PIN $PIN(%1) +end option + +option cs3 + define MRAMS_CS3_PORT $TRIS(%1) + define MRAMS_CS3_PIN $PIN(%1) +end option + +option cs4 + define MRAMS_CS4_PORT $TRIS(%1) + define MRAMS_CS4_PIN $PIN(%1) +end option + +option cs5 + define MRAMS_CS5_PORT $TRIS(%1) + define MRAMS_CS5_PIN $PIN(%1) +end option + +option led0 + define MRAMS_LED0_PORT $TRIS(%1) + define MRAMS_LED0_PIN $PIN(%1) +end option + +option led1 + define MRAMS_LED1_PORT $TRIS(%1) + define MRAMS_LED1_PIN $PIN(%1) +end option + +option led2 + define MRAMS_LED2_PORT $TRIS(%1) + define MRAMS_LED2_PIN $PIN(%1) +end option + +option led3 + define MRAMS_LED3_PORT $TRIS(%1) + define MRAMS_LED3_PIN $PIN(%1) +end option + +option led4 + define MRAMS_LED4_PORT $TRIS(%1) + define MRAMS_LED4_PIN $PIN(%1) +end option + +option led5 + define MRAMS_LED5_PORT $TRIS(%1) + define MRAMS_LED5_PIN $PIN(%1) +end option + diff --git a/sys/pic32/cfg/oc.dev b/sys/pic32/cfg/oc.dev new file mode 100644 index 0000000..e6f408e --- /dev/null +++ b/sys/pic32/cfg/oc.dev @@ -0,0 +1,4 @@ +always + file oc.o + define OC_ENABLED YES +end always diff --git a/sys/pic32/cfg/picga.dev b/sys/pic32/cfg/picga.dev new file mode 100644 index 0000000..cfec1c6 --- /dev/null +++ b/sys/pic32/cfg/picga.dev @@ -0,0 +1,14 @@ +always + file picga.o + require spibus + define PICGA_ENABLED YES +end always + +option bus + define PICGA_BUS %1 +end option + +option cs + define PICGA_CS_PORT $TRIS(%1) + define PICGA_CS_PIN $PIN(%1) +end option diff --git a/sys/pic32/cfg/power.dev b/sys/pic32/cfg/power.dev new file mode 100644 index 0000000..678edf0 --- /dev/null +++ b/sys/pic32/cfg/power.dev @@ -0,0 +1,19 @@ +always + file power_control.o +end always + +option led + define POWER_LED_PORT $PORT(%1) + define POWER_LED_PIN $PIN(%1) +end option + +option switch + define POWER_SWITCH_PORT $PORT(%1) + define POWER_SWITCH_PIN $PIN(%1) +end option + +option control + define POWER_CONTROL_PORT $PORT(%1) + define POWER_CONTROL_PIN $PIN(%1) +end option + diff --git a/sys/pic32/cfg/pty.dev b/sys/pic32/cfg/pty.dev new file mode 100644 index 0000000..597a842 --- /dev/null +++ b/sys/pic32/cfg/pty.dev @@ -0,0 +1,4 @@ +always + file tty_pty.o + define PTY_ENABLED YES +end always diff --git a/sys/pic32/cfg/rdisk.dev b/sys/pic32/cfg/rdisk.dev new file mode 100644 index 0000000..009348f --- /dev/null +++ b/sys/pic32/cfg/rdisk.dev @@ -0,0 +1,25 @@ +always + file rdisk.o +end always + +option led + define LED_DISK_PORT $TRIS(%1) + define LED_DISK_PIN $PIN(%1) +end option + +option invled + define LED_DISK_PORT $TRIS(%1) + define LED_DISK_PIN $PIN(%1) + define LED_DISK_INVERT YES +end option + +option swap + define LED_SWAP_PORT $TRIS(%1) + define LED_SWAP_PIN $PIN(%1) +end option + +option invswap + define LED_SWAP_PORT $TRIS(%1) + define LED_SWAP_PIN $PIN(%1) + define LED_SWAP_INVERT YES +end option diff --git a/sys/pic32/cfg/sd.dev b/sys/pic32/cfg/sd.dev new file mode 100644 index 0000000..9b2a9b9 --- /dev/null +++ b/sys/pic32/cfg/sd.dev @@ -0,0 +1,23 @@ +always + file rd_sd.o + require spibus + require rdisk +end always + +option port + define SD%0_PORT %1 +end option + +option cs + define SD%0_CS_PORT $TRIS(%1) + define SD%0_CS_PIN $PIN(%1) +end option + +option mhz + define SD%0_MHZ %1 +end option + +option power + define SD%0_ENA_PORT $TRIS(%1) + define SD%0_ENA_PIN $PIN(%1) +end option diff --git a/sys/pic32/cfg/sdramp.dev b/sys/pic32/cfg/sdramp.dev new file mode 100644 index 0000000..b187280 --- /dev/null +++ b/sys/pic32/cfg/sdramp.dev @@ -0,0 +1,7 @@ +always + file sdram.o + file rd_sdramp.o + require rdisk + define KERNEL_EXECUTABLE_RAM + define SDRAMP_ENABLED YES +end always diff --git a/sys/pic32/cfg/spi.dev b/sys/pic32/cfg/spi.dev new file mode 100644 index 0000000..537ea5b --- /dev/null +++ b/sys/pic32/cfg/spi.dev @@ -0,0 +1,5 @@ +always + file spi.o + require spibus + define SPI_ENABLED YES +end always diff --git a/sys/pic32/cfg/spibus.dev b/sys/pic32/cfg/spibus.dev new file mode 100644 index 0000000..cb215f0 --- /dev/null +++ b/sys/pic32/cfg/spibus.dev @@ -0,0 +1,3 @@ +always + file spi_bus.o +end always diff --git a/sys/pic32/cfg/sramc.dev b/sys/pic32/cfg/sramc.dev new file mode 100644 index 0000000..e5f754d --- /dev/null +++ b/sys/pic32/cfg/sramc.dev @@ -0,0 +1,26 @@ +always + file rd_sramc.o + require rdisk + define SRAMC_ENABLED YES +end always + +option data + define SW_DATA_PORT $TRIS(%1) + define SW_DATA_PIN $PIN(%1) +end option + +option lda + define SW_LDA_PORT $TRIS(%1) + define SW_LDA_PIN $PIN(%1) +end option + +option rd + define SW_RD_PORT $TRIS(%1) + define SW_RD_PIN $PIN(%1) +end option + +option wr + define SW_WR_PORT $TRIS(%1) + define SW_WR_PIN $PIN(%1) +end option + diff --git a/sys/pic32/cfg/tty.dev b/sys/pic32/cfg/tty.dev new file mode 100644 index 0000000..0d11fb3 --- /dev/null +++ b/sys/pic32/cfg/tty.dev @@ -0,0 +1,5 @@ +always + file tty.o + file tty_subr.o + file tty_tty.o +end always diff --git a/sys/pic32/cfg/uart.dev b/sys/pic32/cfg/uart.dev new file mode 100644 index 0000000..a6cca05 --- /dev/null +++ b/sys/pic32/cfg/uart.dev @@ -0,0 +1,13 @@ +always + file uart.o + define UART%0_ENABLED YES +end always + +option baud + define UART%0_BAUD %1 +end option + +option power + define UART%0_ENA_PORT $TRIS(%1) + define UART%0_ENA_PIN $PIN(%1) +end option diff --git a/sys/pic32/cfg/uartconsole.dev b/sys/pic32/cfg/uartconsole.dev new file mode 100644 index 0000000..e69de29 diff --git a/sys/pic32/cfg/uartusb.dev b/sys/pic32/cfg/uartusb.dev new file mode 100644 index 0000000..013f27e --- /dev/null +++ b/sys/pic32/cfg/uartusb.dev @@ -0,0 +1,16 @@ +always + file usb_device.o + file usb_function_cdc.o + file usb_uart.o + define USB_NUM_STRING_DESCRIPTORS 3 + define USB_MAX_EP_NUMBER 3 + define UARTUSB_ENABLED YES +end always + +option autoboot + define USB_AUTOBOOT YES +end option + +option baud + define UARTUSB_BAUD %1 +end option diff --git a/sys/pic32/cfg/ufs.dev b/sys/pic32/cfg/ufs.dev new file mode 100644 index 0000000..64405b2 --- /dev/null +++ b/sys/pic32/cfg/ufs.dev @@ -0,0 +1,13 @@ +always + file ufs_alloc.o + file ufs_bio.o + file ufs_bmap.o + file ufs_dsort.o + file ufs_fio.o + file ufs_inode.o + file ufs_mount.o + file ufs_namei.o + file ufs_subr.o + file ufs_syscalls.o + file ufs_syscalls2.o +end always diff --git a/sys/pic32/cfg/usbconsole.dev b/sys/pic32/cfg/usbconsole.dev new file mode 100644 index 0000000..e69de29 diff --git a/sys/pic32/clock.c b/sys/pic32/clock.c new file mode 100644 index 0000000..c86e858 --- /dev/null +++ b/sys/pic32/clock.c @@ -0,0 +1,21 @@ +/* + * Copyright (c) 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "param.h" +#include "machine/pic32mx.h" + +/* + * Setup core timer for `hz' timer interrupts per second. + */ +void +clkstart() +{ + unsigned count = mips_read_c0_register (C0_COUNT, 0); + + mips_write_c0_register (C0_COMPARE, 0, + count + (CPU_KHZ * 1000 / HZ + 1) / 2); + + IECSET(0) = 1 << PIC32_IRQ_CT; +} diff --git a/sys/pic32/cons.c b/sys/pic32/cons.c new file mode 100644 index 0000000..b5568be --- /dev/null +++ b/sys/pic32/cons.c @@ -0,0 +1,109 @@ +/* + * UART driver for PIC32. + * + * Copyright (c) 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "param.h" +#include "conf.h" +#include "user.h" +#include "ioctl.h" +#include "tty.h" +#include "systm.h" + +#include "uart.h" +#include "usb_uart.h" + +#define CONCAT(x,y) x ## y +#define BBAUD(x) CONCAT(B,x) + +#ifndef CONSOLE_BAUD +#define CONSOLE_BAUD 115200 +#endif + +const struct devspec cndevs[] = { + { 0, "console" }, + { 0, 0 } +}; + +dev_t console_device = -1; + +#define NKL 1 /* Only one console device */ + +#define Q2(X) #X +#define QUOTE(X) Q2(X) + +struct tty cnttys [1]; + +void cnstart (struct tty *tp); + +void cninit() +{ + console_device = get_cdev_by_name(QUOTE(CONSOLE_DEVICE)); +} + +void cnidentify() +{ + printf ("console: %s (%d,%d)\n", + cdevname(console_device), major(console_device), minor(console_device)); +} + +int cnopen(dev_t dev, int flag, int mode) +{ + return cdevsw[major(console_device)].d_open(console_device, flag, mode); +} + +int cnclose (dev_t dev, int flag, int mode) +{ + return cdevsw[major(console_device)].d_close(console_device, flag, mode); +} + +int cnread(dev_t dev,register struct uio *uio, int flag) +{ + return cdevsw[major(console_device)].d_read(console_device, uio, flag); +} + +int cnwrite(dev_t dev,register struct uio *uio, int flag) +{ + return cdevsw[major(console_device)].d_write(console_device, uio, flag); +} + +int cnselect(dev_t dev, int rw) +{ + return cdevsw[major(console_device)].d_select(console_device, rw); +} + +int cnioctl(dev_t dev, register u_int cmd, caddr_t addr, int flag) +{ + return cdevsw[major(console_device)].d_ioctl(console_device, cmd, addr, flag); +} + +/* + * Put a symbol on console terminal. + */ +void cnputc(char c) +{ + if (cdevsw[major(console_device)].r_write) { + cdevsw[major(console_device)].r_write(console_device, c); + } else { + putc(c, &cdevsw[major(console_device)].d_ttys[minor(console_device)].t_outq); + ttstart(&cdevsw[major(console_device)].d_ttys[minor(console_device)]); + ttyflush(&cdevsw[major(console_device)].d_ttys[minor(console_device)],0); + } + if(c=='\n') + cnputc('\r'); +} + +/* + * Receive a symbol from console terminal. + */ +int +cngetc () +{ + if (cdevsw[major(console_device)].r_read) { + return cdevsw[major(console_device)].r_read(console_device); + } else { + return getc(&cdevsw[major(console_device)].d_ttys[minor(console_device)].t_rawq); + } +} diff --git a/sys/pic32/cpu.h b/sys/pic32/cpu.h new file mode 100644 index 0000000..e81d045 --- /dev/null +++ b/sys/pic32/cpu.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +/* + * CTL_MACHDEP definitions. + */ +#define CPU_CONSDEV 1 /* dev_t: console terminal device */ +#define CPU_ERRMSG 2 /* get error message by errno */ +#define CPU_NLIST 3 /* get name address */ +#define CPU_TIMO_CMD 4 +#define CPU_TIMO_SEND_OP 5 +#define CPU_TIMO_SEND_CSD 6 +#define CPU_TIMO_READ 7 +#define CPU_TIMO_WAIT_CMD 8 +#define CPU_TIMO_WAIT_WDATA 9 +#define CPU_TIMO_WAIT_WDONE 10 +#define CPU_TIMO_WAIT_WSTOP 11 +#define CPU_TIMO_WAIT_WIDLE 12 +#define CPU_MAXID 13 /* number of valid machdep ids */ + +#ifndef KERNEL +#define CTL_MACHDEP_NAMES { \ + { 0, 0 }, \ + { "console_device", CTLTYPE_STRUCT }, \ + { 0, 0 }, \ + { 0, 0 }, \ + { "sd_timeout_cmd", CTLTYPE_INT }, \ + { "sd_timeout_send_op", CTLTYPE_INT }, \ + { "sd_timeout_send_csd", CTLTYPE_INT }, \ + { "sd_timeout_read", CTLTYPE_INT }, \ + { "sd_timeout_wait_cmd", CTLTYPE_INT }, \ + { "sd_timeout_wait_wdata", CTLTYPE_INT }, \ + { "sd_timeout_wait_wdone", CTLTYPE_INT }, \ + { "sd_timeout_wait_wstop", CTLTYPE_INT }, \ + { "sd_timeout_wait_widle", CTLTYPE_INT }, \ +} +#endif diff --git a/sys/pic32/devcfg.c b/sys/pic32/devcfg.c new file mode 100644 index 0000000..5418445 --- /dev/null +++ b/sys/pic32/devcfg.c @@ -0,0 +1,20 @@ +/* + * Chip configuration. + */ +#include "machine/pic32mx.h" + +PIC32_DEVCFG ( + 0| DC0_DEBUG | DC0_ICE, + + 0| DC1_FNOSC | DC1_SOSC | DC1_IESO | DC1_POSCMOD | + DC1_OSCIOFNC | DC1_PBDIV | DC1_CKM | DC1_CKS | + DC1_WDTPS | DC1_WDTEN, + + 0| DC2_PLLIDIV | DC2_PLLMUL | DC2_UPLLIDIV | DC2_UPLL | + DC2_PLLODIV, + + 0| DEVCFG3_USERID(DC3_USERID) | DC3_SRS | DC3_MII | + DC3_ETH | DC3_CAN | DC3_USBID | DC3_VBUSON +); + + diff --git a/sys/pic32/devsw.c b/sys/pic32/devsw.c new file mode 100644 index 0000000..45a511e --- /dev/null +++ b/sys/pic32/devsw.c @@ -0,0 +1,372 @@ +/* + * Copyright (c) 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "param.h" +#include "conf.h" +#include "buf.h" +#include "time.h" +#include "ioctl.h" +#include "resource.h" +#include "inode.h" +#include "proc.h" +#include "clist.h" +#include "tty.h" +#include "systm.h" +#include "rdisk.h" +#include "errno.h" +#include "uart.h" + +#include "swap.h" + +extern int strcmp(char *s1, char *s2); + +#ifdef UARTUSB_ENABLED +#include "usb_uart.h" +#endif + +#ifdef GPIO_ENABLED +#include "gpio.h" +#endif + +#ifdef ADC_ENABLED +#include "adc.h" +#endif + +#ifdef SPI_ENABLED +#include "spi.h" +#endif + +#ifdef GLCD_ENABLED +#include "glcd.h" +#endif + +#ifdef OC_ENABLED +#include "oc.h" +#endif + +#ifdef PICGA_ENABLED +#include "picga.h" +#endif + +#ifdef PTY_ENABLED +#include "pty.h" +#endif + +/* + * Null routine; placed in insignificant entries + * in the bdevsw and cdevsw tables. + */ +int nulldev () +{ + return (0); +} + +int norw (dev, uio, flag) + dev_t dev; + struct uio *uio; + int flag; +{ + return (0); +} + +int noioctl (dev, cmd, data, flag) + dev_t dev; + u_int cmd; + caddr_t data; + int flag; +{ + return EIO; +; +} + +/* + * root attach routine + */ +void noroot (csr) + caddr_t csr; +{ + /* Empty. */ +} + +const struct bdevsw bdevsw[] = { +{ + rdopen, rdclose, rdstrategy, + noroot, rdsize, rdioctl, 0, rd0devs }, +{ + rdopen, rdclose, rdstrategy, + noroot, rdsize, rdioctl, 0, rd1devs }, +{ + rdopen, rdclose, rdstrategy, + noroot, rdsize, rdioctl, 0, rd2devs }, +{ + rdopen, rdclose, rdstrategy, + noroot, rdsize, rdioctl, 0, rd3devs }, +{ + swopen, swclose, swstrategy, + noroot, swsize, swcioctl, 0, swapbdevs }, +{ + 0, 0, 0, + 0, 0, 0, 0, 0 }, +}; + +const int nblkdev = sizeof(bdevsw) / sizeof(bdevsw[0]) - 1; + +// The RetroDisks require the same master number as the disk entry in the +// rdisk.c file. A bit of a bind, but it means that the RetroDisk +// devices must be numbered from master 0 upwards. + +const struct cdevsw cdevsw[] = { + +// Static drivers - every system has these: + +{ /* cn = 0 */ + cnopen, cnclose, cnread, cnwrite, + cnioctl, nulldev, cnttys, cnselect, + nostrategy, 0, 0, cndevs +}, + +{ /* mem = 1 */ + nulldev, nulldev, mmrw, mmrw, + noioctl, nulldev, 0, seltrue, + nostrategy, 0, 0, mmdevs +}, + +{ /* tty = 2 */ + syopen, nulldev, syread, sywrite, + syioctl, nulldev, 0, syselect, + nostrategy, 0, 0, sydevs +}, + +{ /* fd = 3 */ + fdopen, nulldev, norw, norw, + noioctl, nulldev, 0, seltrue, + nostrategy, 0, 0, fddevs +}, + +{ /* swap = 4 */ + swcopen, swcclose, swcread, swcwrite, + swcioctl, nulldev, 0, seltrue, + nostrategy, 0, 0, swapcdevs +}, + + +// Optional drivers from here on: + +#ifdef LOG_ENABLED +{ /* log = 3 */ + logopen, logclose, logread, norw, + logioctl, nulldev, 0, logselect, + nostrategy, 0, 0, logdevs +}, +#endif + +#if defined(UART1_ENABLED) || defined(UART2_ENABLED) || defined(UART3_ENABLED) || defined(UART4_ENABLED) || defined(UART5_ENABLED) || defined(UART6_ENABLED) +{ + uartopen, uartclose, uartread, uartwrite, + uartioctl, nulldev, uartttys, uartselect, + nostrategy, uartgetc, uartputc, uartdevs +}, +#endif + +#ifdef UARTUSB_ENABLED +{ + usbopen, usbclose, usbread, usbwrite, + usbioctl, nulldev, usbttys, usbselect, + nostrategy, usbgetc, usbputc, usbdevs +}, +#endif + +#ifdef PTY_ENABLED +{ + ptsopen, ptsclose, ptsread, ptswrite, + ptyioctl, nulldev, pt_tty, ptcselect, + nostrategy, 0, 0, ptsdevs +}, { + ptcopen, ptcclose, ptcread, ptcwrite, + ptyioctl, nulldev, pt_tty, ptcselect, + nostrategy, 0, 0, ptcdevs +}, +#endif + +#ifdef GPIO_ENABLED +{ + gpioopen, gpioclose, gpioread, gpiowrite, + gpioioctl, nulldev, 0, seltrue, + nostrategy, 0, 0, gpiodevs +}, +#endif + +#ifdef ADC_ENABLED +{ + adc_open, adc_close, adc_read, adc_write, + adc_ioctl, nulldev, 0, seltrue, + nostrategy, 0, 0, adcdevs +}, +#endif + +#ifdef SPI_ENABLED +{ + spidev_open, spidev_close, spidev_read, spidev_write, + spidev_ioctl, nulldev, 0, seltrue, + nostrategy, 0, 0, spidevs +}, +#endif + +#ifdef GLCD_ENABLED +{ + glcd_open, glcd_close, glcd_read, glcd_write, + glcd_ioctl, nulldev, 0, seltrue, + nostrategy, 0, 0, glcddevs +}, +#endif + +#ifdef OC_ENABLED +{ + oc_open, oc_close, oc_read, oc_write, + oc_ioctl, nulldev, 0, seltrue, + nostrategy, 0, 0, ocdevs +}, +#endif + +// Ignore this for now - it's WIP. +#ifdef PICGA_ENABLED +{ + picga_open, picga_close, picga_read, picga_write, + picga_ioctl, nulldev, 0, seltrue, + nostrategy, 0, 0, picgadevs +}, +#endif + +// End the list with a blank entry +{ + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0 +}, +}; +const int nchrdev = sizeof(cdevsw) / sizeof(cdevsw[0]) - 1; + +/* + * Routine that identifies /dev/mem and /dev/kmem. + * + * A minimal stub routine can always return 0. + */ +int +iskmemdev(dev) + register dev_t dev; +{ + if (major(dev) == 1 && (minor(dev) == 0 || minor(dev) == 1)) + return (1); + return (0); +} + +/* + * Routine to determine if a device is a disk. + * + * A minimal stub routine can always return 0. + */ +int +isdisk(dev, type) + dev_t dev; + register int type; +{ + switch (major(dev)) { + case 0: /* sd */ + case 1: /* sw */ + case 2: + case 3: + case 4: + if (type == IFBLK) + return (1); + return (0); + default: + return (0); + } + /* NOTREACHED */ +} + +#define MAXDEV 7 +static const char chrtoblktbl[MAXDEV] = { + /* CHR */ /* BLK */ + /* 0 */ NODEV, + /* 1 */ NODEV, + /* 2 */ NODEV, + /* 3 */ 0, /* sd */ + /* 4 */ NODEV, + /* 5 */ NODEV, + /* 6 */ 1, +}; + +/* + * Routine to convert from character to block device number. + * + * A minimal stub routine can always return NODEV. + */ +int +chrtoblk(dev) + register dev_t dev; +{ + register int blkmaj; + + if (major(dev) >= MAXDEV || (blkmaj = chrtoblktbl[major(dev)]) == NODEV) + return (NODEV); + return (makedev(blkmaj, minor(dev))); +} + +/* + * This routine returns the cdevsw[] index of the block device + * specified by the input parameter. Used by init_main and ufs_mount to + * find the diskdriver's ioctl entry point so that the label and partition + * information can be obtained for 'block' (instead of 'character') disks. + * + * Rather than create a whole separate table 'chrtoblktbl' is scanned + * looking for a match. This routine is only called a half dozen times during + * a system's life so efficiency isn't a big concern. + */ +int +blktochr(dev) + register dev_t dev; +{ + register int maj = major(dev); + register int i; + + for (i = 0; i < MAXDEV; i++) { + if (maj == chrtoblktbl[i]) + return(i); + } + return(NODEV); +} + +/* + * Search through the devspec entries in the cdevsw + * table looking for a device name match. + */ + +dev_t get_cdev_by_name(char *name) +{ + int maj, i; + + for (maj = 0; maj < nchrdev; maj++) { + for (i = 0; cdevsw[maj].devs[i].devname != 0; i++) { + if (!strcmp(cdevsw[maj].devs[i].devname, name)) { + return makedev(maj, cdevsw[maj].devs[i].unit); + } + } + } + return -1; +} + +char *cdevname(dev_t dev) +{ + int maj = major(dev); + int i; + + for (i=0; cdevsw[maj].devs[i].devname != 0; i++) { + if (cdevsw[maj].devs[i].unit == minor(dev)) { + return cdevsw[maj].devs[i].devname; + } + } + return NULL; +} diff --git a/sys/pic32/diag/Makefile b/sys/pic32/diag/Makefile new file mode 100644 index 0000000..dc4cd3d --- /dev/null +++ b/sys/pic32/diag/Makefile @@ -0,0 +1,145 @@ +H = ../../include +M = .. +S = ../../kernel + +vpath %.c $(M):$(S) +vpath %.S $(M):$(S) + +include ../gcc-config.mk + +# Kernel options. +DEFS += -I. -I$(H) -DKERNEL -DPIC32MX7 + +# CPU frequency 80 MHz. +DEFS += -DCPU_KHZ=80000 +DEFS += -DBUS_KHZ=80000 + +# +# Ethernet/USB Starter Kit with I/O Expansion board +# ================================================= +# +#LDSCRIPT = ../strater-kit/using-bootloader.ld + +# Console on USB +# For Windows, use the driver: http://www.schmalzhaus.com/UBW32/FW/UBW32inf.zip +DEFS += -DCONSOLE_USB +DEFS += -DUSB_NUM_STRING_DESCRIPTORS=3 -DUSB_MAX_EP_NUMBER=3 + +# SD/MMC card driver on SPI1 +# /CS0 at pin B1 +#DEFS += -DSD0_PORT=1 -DSD0_MHZ=10 +#DEFS += -DSD0_CS_PORT=TRISB -DSD0_CS_PIN=1 + +# LEDs at pins D0 (red), D1 (yellow), D2 (green) +#DEFS += -DLED_TTY_PORT=TRISD -DLED_TTY_PIN=0 +#DEFS += -DLED_DISK_PORT=TRISD -DLED_DISK_PIN=1 +#DEFS += -DLED_KERNEL_PORT=TRISD -DLED_KERNEL_PIN=2 + +# +# UBW32 board +# =========== +# +LDSCRIPT = ../ubw32/using-bootloader.ld + +# SD/MMC card driver on SPI1 +# /CS0 at pin A9 (and optional /CS1 at pin A10) +DEFS += -DSD0_PORT=1 +DEFS += -DSD0_CS_PORT=TRISA -DSD0_CS_PIN=9 +DEFS += -DSD1_PORT=1 +DEFS += -DSD1_CS_PORT=TRISA -DSD1_CS_PIN=10 + +# LEDs at pins E0, E1, E2, E3 +DEFS += -DLED_AUX_PORT=TRISE -DLED_AUX_PIN=0 -DLED_AUX_INVERT +DEFS += -DLED_DISK_PORT=TRISE -DLED_DISK_PIN=1 -DLED_DISK_INVERT +DEFS += -DLED_KERNEL_PORT=TRISE -DLED_KERNEL_PIN=2 -DLED_KERNEL_INVERT +DEFS += -DLED_TTY_PORT=TRISE -DLED_TTY_PIN=3 -DLED_TTY_INVERT + +# +# Include or exclude drivers +# + +# General Purpose I/O +DRIVER_GPIO = no + +# Basic ADC interface +DRIVER_ADC = no + +# Power control (power LED, and soft power-off by button) +# requires supported PSU (ATX) +DRIVER_POWER = no + +POWER_LED_PORT = TRISG +POWER_LED_PIN = 12 +POWER_SWITCH_PORT = TRISG +POWER_SWITCH_PIN = 0 +POWER_CONTROL_PORT = TRISE +POWER_CONTROL_PIN = 9 + +DEPFLAGS = -MT $@ -MD -MP -MF .deps/$*.dep +CFLAGS = -O $(DEFS) $(DEPFLAGS) +ASFLAGS = $(DEFS) $(DEPFLAGS) + +CC = $(GCCPREFIX)gcc -EL -g -mips32r2 +CC += -nostdinc -fno-builtin -Werror -Wall -fno-dwarf2-cfi-asm +LDFLAGS += -nostdlib -T$(LDSCRIPT) -Wl,-Map=diag.map +SIZE = $(GCCPREFIX)size +OBJDUMP = $(GCCPREFIX)objdump +OBJCOPY = $(GCCPREFIX)objcopy + +# Machine-dependent files: +# startup.o MUST be loaded first. +KERNOBJ = startup.o machdep.o usb_device.o usb_function_cdc.o +KERNOBJ += usb_console.o +#KERNOBJ += cons.o + +# Kernel. +KERNOBJ += main.o subr_prf.o + +# Drivers. +KERNOBJ += rdisk.o rd_sd.o spi_bus.o + +# Include any local specific configuration overrides +-include Makefile.local + +# This makefile does the work including the right files and options for the drivers +include ../drivers.mk + +all: .deps sys machine diag.elf + $(SIZE) diag.elf + +clean: + rm -rf .deps *.o *.elf *.bin *.dis *.map *.srec core \ + mklog assym.h vers.c genassym sys machine + +.deps: + mkdir .deps + +sys: + ln -s ../../include $@ + +machine: + ln -s .. $@ + +diag.elf: $(KERNOBJ) $(LDSCRIPT) + $(CC) $(LDFLAGS) $(KERNOBJ) -o $@ + chmod -x $@ + $(OBJDUMP) -d -S $@ > diag.dis + $(OBJCOPY) -O binary $@ diag.bin + $(OBJCOPY) -O ihex --change-addresses=0x80000000 $@ diag.hex + chmod -x $@ diag.bin + +load: diag.elf + pic32prog diag.hex + +vers.o: ../newvers.sh $(H)/*.h $(M)/*.[ch] $(S)/*.c + sh ../newvers.sh > vers.c + $(CC) -c vers.c + +.SUFFIXES: .i .srec .hex .dis .cpp .cxx .bin .elf + +.o.dis: + $(OBJDUMP) -d -z -S $< > $@ + +ifeq (.deps, $(wildcard .deps)) +-include .deps/*.dep +endif diff --git a/sys/pic32/diag/main.c b/sys/pic32/diag/main.c new file mode 100644 index 0000000..d29bcc4 --- /dev/null +++ b/sys/pic32/diag/main.c @@ -0,0 +1,550 @@ +#include "param.h" +#include "conf.h" +#include "systm.h" +#include "buf.h" +#include "reboot.h" + +#define SECTSIZE 512 /* size of SD card sector */ + +size_t physmem; /* total amount of physical memory */ +u_int swapstart, nswap; /* start and size of swap space */ + +const struct linesw linesw[] = { { 0 } }; +int nldisp = 1; + +char data [SECTSIZE * 2]; + +extern int card_size (int unit, unsigned *nsectors); +extern int card_read (int unit, unsigned offset, char *data, unsigned bcount); +extern int card_write (int unit, unsigned offset, char *data, unsigned bcount); + +static void +fill_sector (p, byte0, byte1) + char *p; + unsigned byte0, byte1; +{ + unsigned i; + + for (i=0; i> 2 & 31); + + switch (cause & CA_EXC_CODE) { + case CA_AdEL: + case CA_AdES: + printf ("*** badvaddr = 0x%08x\n", + mips_read_c0_register (C0_BADVADDR, 0)); + } + printf (" t0 = %8x s0 = %8x t8 = %8x lo = %8x\n", + frame [FRAME_R8], frame [FRAME_R16], + frame [FRAME_R24], frame [FRAME_LO]); + printf ("at = %8x t1 = %8x s1 = %8x t9 = %8x hi = %8x\n", + frame [FRAME_R1], frame [FRAME_R9], frame [FRAME_R17], + frame [FRAME_R25], frame [FRAME_HI]); + printf ("v0 = %8x t2 = %8x s2 = %8x status = %8x\n", + frame [FRAME_R2], frame [FRAME_R10], + frame [FRAME_R18], frame [FRAME_STATUS]); + printf ("v1 = %8x t3 = %8x s3 = %8x cause = %8x\n", + frame [FRAME_R3], frame [FRAME_R11], + frame [FRAME_R19], cause); + printf ("a0 = %8x t4 = %8x s4 = %8x gp = %8x epc = %8x\n", + frame [FRAME_R4], frame [FRAME_R12], + frame [FRAME_R20], frame [FRAME_GP], frame [FRAME_PC]); + printf ("a1 = %8x t5 = %8x s5 = %8x sp = %8x\n", + frame [FRAME_R5], frame [FRAME_R13], + frame [FRAME_R21], frame [FRAME_SP]); + printf ("a2 = %8x t6 = %8x s6 = %8x fp = %8x\n", + frame [FRAME_R6], frame [FRAME_R14], + frame [FRAME_R22], frame [FRAME_FP]); + printf ("a3 = %8x t7 = %8x s7 = %8x ra = %8x\n", + frame [FRAME_R7], frame [FRAME_R15], + frame [FRAME_R23], frame [FRAME_RA]); +} + +void +exception (frame) /* exception.c */ + int *frame; +{ + unsigned c, irq, status, cause; + + led_control (LED_KERNEL, 1); + status = frame [FRAME_STATUS]; + cause = mips_read_c0_register (C0_CAUSE, 0); + + if ((cause & CA_EXC_CODE) != CA_Int) { + /* Exception. */ + dumpregs (frame); + panic ("unexpected exception"); + } + + /* + * Hardware interrupt. + */ + /* Get the current irq number */ + c = INTSTAT; + if ((c & PIC32_INTSTAT_SRIPL_MASK) == 0) { + printf ("*** unexpected interrupt: INTSTAT %08x\n", c); + goto ret; + } + irq = PIC32_INTSTAT_VEC (c); + + /* Handle the interrupt. */ + switch (irq) { + case PIC32_VECT_CT: /* Core Timer */ +#if 0 + /* Increment COMPARE register. */ + c = mips_read_c0_register (C0_COMPARE, 0); + do { + c += (CPU_KHZ * 1000 / HZ + 1) / 2; + mips_write_c0_register (C0_COMPARE, 0, c); + } while ((int) (c - mips_read_c0_register (C0_COUNT, 0)) < 0); + + IFSCLR(0) = 1 << PIC32_IRQ_CT; + hardclock ((caddr_t) frame [FRAME_PC], status); +#endif +#ifdef CONSOLE_USB + /* Poll USB on every timer tick. */ + cnintr (0); +#endif + break; +#if defined(CONSOLE_UART1) || defined(CONSOLE_UART2) || \ +defined(CONSOLE_UART3) || defined(CONSOLE_UART4) || \ +defined(CONSOLE_UART5) || defined(CONSOLE_UART6) +#if CONSOLE_UART1 + case PIC32_VECT_U1: /* UART1 */ +#endif +#if CONSOLE_UART2 + case PIC32_VECT_U2: /* UART2 */ +#endif +#if CONSOLE_UART3 + case PIC32_VECT_U3: /* UART3 */ +#endif +#if CONSOLE_UART4 + case PIC32_VECT_U4: /* UART4 */ +#endif +#if CONSOLE_UART5 + case PIC32_VECT_U5: /* UART5 */ +#endif +#if CONSOLE_UART6 + case PIC32_VECT_U6: /* UART6 */ +#endif + cnintr (0); + break; +#endif +#ifdef CONSOLE_USB + case PIC32_VECT_USB: /* USB */ + IFSCLR(1) = 1 << (PIC32_IRQ_USB - 32); + cnintr (0); + break; +#endif + default: + /* Disable the irq, to avoid loops */ + printf ("*** irq %u\n", irq); + if (irq < PIC32_VECT_CN) { + IECCLR(0) = mask_by_vector [irq]; + IFSCLR(0) = mask_by_vector [irq]; + } else { + IECCLR(1) = mask_by_vector [irq]; + IFSCLR(1) = mask_by_vector [irq]; + } + break; + } +ret: led_control (LED_KERNEL, 0); +} + +void +biodone(bp) + register struct buf *bp; +{ + bp->b_flags |= B_DONE; +} + +/* + * Stubs. + */ +int noproc; /* kern_clock.c */ + +struct fs * +getfs(dev) /* ufs_subr.c */ + dev_t dev; +{ + return 0; +} + +void +sync() /* ufs_subr.c */ +{ + /* empty */ +} + +void +ttyowake(tp) /* tty.c */ + struct tty *tp; +{ + /* empty */ +} + +void +ttychars(tp) /* tty.c */ + struct tty *tp; +{ + /* empty */ +} + +void +ttyclose(tp) /* tty.c */ + struct tty *tp; +{ + /* empty */ +} + +int +ttyselect (tp, rw) /* tty.c */ + struct tty *tp; + int rw; +{ + return 0; +} + +int +ttioctl(tp, com, data, flag) /* tty.c */ + struct tty *tp; + u_int com; + caddr_t data; + int flag; +{ + return 0; +} + +int +ttyoutput(c, tp) /* tty.c */ + int c; + struct tty *tp; +{ + return 0; +} + +void +ttstart(tp) /* tty.c */ + struct tty *tp; +{ + /* empty */ +} + +int +ttycheckoutq (tp, wait) /* tty.c */ + struct tty *tp; + int wait; +{ + return 0; +} + +int +logwrt (buf, len, log) /* subr_log.c */ + char *buf; + int len; + int log; +{ + return 0; +} + +void +logwakeup(unit) /* subr_log.c */ + int unit; +{ + /* empty */ +} + +int +logisopen(unit) /* subr_log.c */ + int unit; +{ + return 0; +} + +int +getc(p) /* tty_subr.c */ + struct clist *p; +{ + return '*'; +} diff --git a/sys/pic32/dip/DIP b/sys/pic32/dip/DIP new file mode 100644 index 0000000..143f1b7 --- /dev/null +++ b/sys/pic32/dip/DIP @@ -0,0 +1,22 @@ +# +# eflightworks DIP board +# ====================== +# +# Console on USB +# For Windows, use the driver: http://www.schmalzhaus.com/UBW32/FW/UBW32inf.zip + +core pic32mx7 +mapping generic +linker bare + +device kernel led=E5 + +device console device=ttyUSB0 led=E6 +device uartusb + +device rdisk led=E4 swap=E7 +device sd0 port=3 cs=D4 + +device gpio + +device bootloader button=D6 jump=0x9d000000 led=E7 invled2=E6 clear=E4 clear2=E5 diff --git a/sys/pic32/dip/Makefile b/sys/pic32/dip/Makefile new file mode 100644 index 0000000..a3de049 --- /dev/null +++ b/sys/pic32/dip/Makefile @@ -0,0 +1,88 @@ +BUILDPATH = ../../../tools/configsys/../../sys/pic32 +H = ../../../tools/configsys/../../sys/include +M = ../../../tools/configsys/../../sys/pic32 +S = ../../../tools/configsys/../../sys/kernel + +vpath %.c $(M):$(S) +vpath %.S $(M):$(S) + +KERNOBJ += _startup.o clock.o cons.o devsw.o exception.o gpio.o init_main.o init_sysent.o kern_clock.o kern_descrip.o kern_exec.o kern_exit.o kern_fork.o kern_mman.o kern_proc.o kern_prot.o kern_prot2.o kern_resource.o kern_sig.o kern_sig2.o kern_subr.o kern_synch.o kern_sysctl.o kern_time.o machdep.o mem.o rd_sd.o rdisk.o signal.o spi_bus.o subr_prf.o subr_rmap.o swap.o sys_generic.o sys_inode.o sys_pipe.o sys_process.o syscalls.o sysctl.o tty.o tty_subr.o tty_tty.o ufs_alloc.o ufs_bio.o ufs_bmap.o ufs_dsort.o ufs_fio.o ufs_inode.o ufs_mount.o ufs_namei.o ufs_subr.o ufs_syscalls.o ufs_syscalls2.o usb_device.o usb_function_cdc.o usb_uart.o vers.o vfs_vnops.o vm_sched.o vm_swap.o vm_swp.o +EXTRA_TARGETS = bootloader + +DEFS += -DBL_BUTTON_PIN=6 +DEFS += -DBL_BUTTON_PORT=TRISD +DEFS += -DBL_CLEAR2_PIN=5 +DEFS += -DBL_CLEAR2_PORT=TRISE +DEFS += -DBL_CLEAR_PIN=4 +DEFS += -DBL_CLEAR_PORT=TRISE +DEFS += -DBL_LED2_INVERT +DEFS += -DBL_LED2_PIN=6 +DEFS += -DBL_LED2_PORT=TRISE +DEFS += -DBL_LED_PIN=7 +DEFS += -DBL_LED_PORT=TRISE +DEFS += -DBUS_DIV=1 +DEFS += -DBUS_KHZ='CPU_KHZ/BUS_DIV' +DEFS += -DCONSOLE_DEVICE=ttyUSB0 +DEFS += -DCPU_IDIV=2 +DEFS += -DCPU_KHZ='((CRYSTAL*1000)/CPU_IDIV*CPU_MUL/CPU_ODIV)' +DEFS += -DCPU_MUL=20 +DEFS += -DCPU_ODIV=1 +DEFS += -DCRYSTAL=8 +DEFS += -DDC0_DEBUG=DEVCFG0_DEBUG_DISABLED +DEFS += -DDC0_ICE=0 +DEFS += -DDC1_CKM=0 +DEFS += -DDC1_CKS=0 +DEFS += -DDC1_FNOSC=DEVCFG1_FNOSC_PRIPLL +DEFS += -DDC1_IESO=DEVCFG1_IESO +DEFS += -DDC1_OSCIOFNC=0 +DEFS += -DDC1_PBDIV=DEVCFG1_FPBDIV_1 +DEFS += -DDC1_POSCMOD=DEVCFG1_POSCMOD_HS +DEFS += -DDC1_SOSC=0 +DEFS += -DDC1_WDTEN=0 +DEFS += -DDC1_WDTPS=DEVCFG1_WDTPS_1 +DEFS += -DDC2_PLLIDIV=DEVCFG2_FPLLIDIV_2 +DEFS += -DDC2_PLLMUL=DEVCFG2_FPLLMUL_20 +DEFS += -DDC2_PLLODIV=DEVCFG2_FPLLODIV_1 +DEFS += -DDC2_UPLL=0 +DEFS += -DDC2_UPLLIDIV=DEVCFG2_UPLLIDIV_2 +DEFS += -DDC3_CAN=DEVCFG3_FCANIO +DEFS += -DDC3_ETH=DEVCFG3_FETHIO +DEFS += -DDC3_MII=DEVCFG3_FMIIEN +DEFS += -DDC3_SRS=DEVCFG3_FSRSSEL_7 +DEFS += -DDC3_USBID=DEVCFG3_FUSBIDIO +DEFS += -DDC3_USERID=0xffff +DEFS += -DDC3_VBUSON=DEVCFG3_FVBUSONIO +DEFS += -DFLASH_JUMP=0x9d000000 +DEFS += -DGPIO_ENABLED=YES +DEFS += -DHID_FEATURE_REPORT_BYTES=2 +DEFS += -DHID_INPUT_REPORT_BYTES=2 +DEFS += -DHID_INT_IN_EP_SIZE=64 +DEFS += -DHID_INT_OUT_EP_SIZE=64 +DEFS += -DHID_OUTPUT_REPORT_BYTES=2 +DEFS += -DHID_RPT01_SIZE=29 +DEFS += -DKERNEL +DEFS += -DLED_DISK_PIN=4 +DEFS += -DLED_DISK_PORT=TRISE +DEFS += -DLED_KERNEL_PIN=5 +DEFS += -DLED_KERNEL_PORT=TRISE +DEFS += -DLED_SWAP_PIN=7 +DEFS += -DLED_SWAP_PORT=TRISE +DEFS += -DLED_TTY_PIN=6 +DEFS += -DLED_TTY_PORT=TRISE +DEFS += -DPIC32MX7 +DEFS += -DSD0_CS_PIN=4 +DEFS += -DSD0_CS_PORT=TRISD +DEFS += -DSD0_PORT=3 +DEFS += -DUARTUSB_ENABLED=YES +DEFS += -DUCB_METER +DEFS += -DUSB_EP0_BUFF_SIZE=8 +DEFS += -DUSB_MAX_EP_NUMBER=3 +DEFS += -DUSB_NUM_STRING_DESCRIPTORS=3 + + +LDSCRIPT = ../../../tools/configsys/../../sys/pic32/cfg/bare.ld + +CONFIG = DIP +CONFIGPATH = ../../../tools/configsys + +include ../../../tools/configsys/../../sys/pic32/kernel-post.mk diff --git a/sys/pic32/dip/bare-metal.ld b/sys/pic32/dip/bare-metal.ld new file mode 100644 index 0000000..5c45bea --- /dev/null +++ b/sys/pic32/dip/bare-metal.ld @@ -0,0 +1,162 @@ +/* + * Linker script for PIC32 firmware. + */ +OUTPUT_FORMAT("elf32-littlemips", "elf32-bigmips", + "elf32-littlemips") +OUTPUT_ARCH(mips) +ENTRY(_reset_vector_) +MEMORY +{ + ram (rw!x): ORIGIN = 0x80000000, LENGTH = 26K + u0area (rw!x): ORIGIN = 0x80006800, LENGTH = 3K + uarea (rw!x): ORIGIN = 0x80007400, LENGTH = 3K + devcfg (r) : ORIGIN = 0x9fc02ff0, LENGTH = 16 + + /* Required by Microchip C32 linker */ + kseg0_program_mem (rx) : ORIGIN = 0x9D000000, LENGTH = 512K + exception_mem (rx) : ORIGIN = 0x9D000000, LENGTH = 0x1000 + kseg0_boot_mem (rx) : ORIGIN = 0x9FC00000, LENGTH = 12K-16 + kseg1_boot_mem (rx) : ORIGIN = 0xBFC00000, LENGTH = 0x490 + kseg1_data_mem (w!x) : ORIGIN = 0xA0000000, LENGTH = 0x20000 +} + +/* higher address of the user mode stack */ +u0 = ORIGIN(u0area); +u = ORIGIN(uarea); +u_end = ORIGIN(uarea) + LENGTH(uarea); + +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = 0x0000; + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rel.init : { *(.rel.init) } + .rela.init : { *(.rela.init) } + .rel.text : { *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) } + .rela.text : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) } + .rel.fini : { *(.rel.fini) } + .rela.fini : { *(.rela.fini) } + .rel.rodata : { *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) } + .rela.rodata : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) } + .rel.data : { *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) } + .rela.data : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.sdata : { *(.rel.sdata .rel.sdata.* .rel.gnu.linkonce.s.*) } + .rela.sdata : { *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*) } + .rel.sbss : { *(.rel.sbss .rel.sbss.* .rel.gnu.linkonce.sb.*) } + .rela.sbss : { *(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*) } + .rel.sdata2 : { *(.rel.sdata2 .rel.sdata2.* .rel.gnu.linkonce.s2.*) } + .rela.sdata2 : { *(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*) } + .rel.sbss2 : { *(.rel.sbss2 .rel.sbss2.* .rel.gnu.linkonce.sb2.*) } + .rela.sbss2 : { *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*) } + .rel.bss : { *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) } + .rela.bss : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .plt : { *(.plt) } + + .boot : + { + /* Execution starts here. */ + *(.startup) + } > kseg0_boot_mem + + .text : + { + /* Exception handlers. */ + *(.exception) + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.glue_7t) *(.glue_7) + __rodata_start = . ; + *(.rodata .rodata.* .gnu.linkonce.r.* .rel.dyn) + /* Align here to ensure that the .text section ends on word boundary. */ + . = ALIGN (32 / 8); + _etext = .; + } > kseg0_program_mem + + /* Start data (internal SRAM). */ + .data : AT (ADDR (.text) + SIZEOF (.text)) + { + __data_start = . ; + _gp = .; /* We have only 32k RAM on MC-24, so no need for 0x8000 offset. */ + *(.data .data.* .gnu.linkonce.d.*) + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + *(.sdata .sdata.* .gnu.linkonce.s.*) + *(.eh_frame) + _edata = .; + } > ram + + /* Device configuration. */ + .config : + { + *(.config3) + *(.config2) + *(.config1) + *(.config0) + } > devcfg + + .bss ADDR (.data) + SIZEOF (.data) (NOLOAD) : + { + __bss_start = .; + *(.dynbss) + *(.sbss .sbss.*) + *(.scommon) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. */ + . = ALIGN (32 / 8); + } > ram + __bss_end = . ; + _end = .; + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } +} diff --git a/sys/pic32/dip/devcfg.c b/sys/pic32/dip/devcfg.c new file mode 100644 index 0000000..8603f7b --- /dev/null +++ b/sys/pic32/dip/devcfg.c @@ -0,0 +1,25 @@ +/* + * Chip configuration. + */ +#include "machine/pic32mx.h" + +PIC32_DEVCFG ( + DEVCFG0_DEBUG_ENABLED | /* ICE debugger disabled */ + DEVCFG0_ICESEL, /* Use PGC1/PGD1 */ + + DEVCFG1_FNOSC_PRIPLL | /* Primary oscillator with PLL */ + DEVCFG1_POSCMOD_HS | /* HS oscillator */ + DEVCFG1_OSCIOFNC | /* CLKO output active */ + DEVCFG1_FPBDIV_1 | /* Peripheral bus clock = SYSCLK/1 */ + DEVCFG1_FCKM_DISABLE | /* Fail-safe clock monitor disable */ + DEVCFG1_FCKS_DISABLE | /* Clock switching disable */ + DEVCFG1_WDTPS_1024, /* Watchdog postscale = 1/1024 */ + + DEVCFG2_FPLLIDIV_2 | /* PLL divider = 1/2 */ + DEVCFG2_FPLLMUL_20 | /* PLL multiplier = 20x */ + DEVCFG2_UPLLIDIV_2 | /* USB PLL divider = 1/2 */ + DEVCFG2_FPLLODIV_1, /* PLL postscaler = 1/1 */ + + DEVCFG3_USERID(0xffff) | /* User-defined ID */ + DEVCFG3_FSRSSEL_7 | /* Assign irq priority 7 to shadow set */ + DEVCFG3_FETHIO); /* Default Ethernet i/o pins */ diff --git a/sys/pic32/dip/using-bootloader.ld b/sys/pic32/dip/using-bootloader.ld new file mode 100644 index 0000000..773de13 --- /dev/null +++ b/sys/pic32/dip/using-bootloader.ld @@ -0,0 +1,114 @@ +/* + * Linker script for PIC32 firmware using HID bootloader. + */ +OUTPUT_FORMAT("elf32-littlemips", "elf32-bigmips", + "elf32-littlemips") +OUTPUT_ARCH(mips) +ENTRY(_reset_vector_) +MEMORY +{ + flash (rx) : ORIGIN = 0x9d000000, LENGTH = 512K + ram (rw!x): ORIGIN = 0x80000000, LENGTH = 26K + u0area (rw!x): ORIGIN = 0x80006800, LENGTH = 3K + uarea (rw!x): ORIGIN = 0x80007400, LENGTH = 3K + + /* Required by Microchip C32 linker */ + kseg0_program_mem (rx) : ORIGIN = 0x9D000000, LENGTH = 0x80000 + kseg0_boot_mem : ORIGIN = 0x9FC00000, LENGTH = 0 + exception_mem : ORIGIN = 0x9FC01000, LENGTH = 0x1000 + kseg1_boot_mem : ORIGIN = 0xBFC00000, LENGTH = 0x1000 + kseg1_data_mem (w!x) : ORIGIN = 0xA0000000, LENGTH = 0x20000 +} + +/* higher address of the user mode stack */ +u0 = ORIGIN(u0area); +u = ORIGIN(uarea); +u_end = ORIGIN(uarea) + LENGTH(uarea); + +SECTIONS +{ + .text ORIGIN(flash) : + { + /* Exception handlers. */ + *(.exception) + /* Execution starts here. */ + *(.startup) + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.glue_7t) *(.glue_7) + __rodata_start = . ; + *(.rodata .rodata.* .gnu.linkonce.r.* .rel.dyn) + *(.dinit) + /* Align here to ensure that the .text section ends on word boundary. */ + . = ALIGN (32 / 8); + _etext = .; + } > flash + + /* Start data (internal SRAM). */ + .data : AT (ADDR (.text) + SIZEOF (.text)) + { + __data_start = . ; + _gp = .; /* We use only 32k RAM for kernel, so no need for 0x8000 offset. */ + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + *(.sdata .sdata.* .gnu.linkonce.s.*) + *(.data .data.* .gnu.linkonce.d.*) + *(.eh_frame) + _edata = .; + } > ram + + .bss ADDR (.data) + SIZEOF (.data) (NOLOAD) : + { + __bss_start = .; + *(.dynbss) + *(.sbss .sbss.*) + *(.scommon) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. */ + . = ALIGN (32 / 8); + } > ram + __bss_end = . ; + _end = .; + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + .debug_pubtypes 0 : { *(.debug_pubtypes) } + .debug_ranges 0 : { *(.debug_ranges) } + .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) } +} diff --git a/sys/pic32/drivers.mk b/sys/pic32/drivers.mk new file mode 100644 index 0000000..26a24f1 --- /dev/null +++ b/sys/pic32/drivers.mk @@ -0,0 +1,43 @@ +ifeq ($(DRIVER_GPIO),yes) + KERNOBJ += gpio.o + DEFS += -DGPIO_ENABLED +endif + +ifeq ($(DRIVER_POWER),yes) + KERNOBJ += power_control.o + POWER_LED_PORT ?= TRISG + POWER_LED_PIN ?= 14 + POWER_SWITCH_PORT ?= TRISE + POWER_SWITCH_PIN ?= 9 + POWER_CONTROL_PORT ?= TRISE + POWER_CONTROL_PIN ?= 9 + DEFS += -DPOWER_ENABLED -DPOWER_LED_PORT=$(POWER_LED_PORT) -DPOWER_LED_PIN=$(POWER_LED_PIN) + DEFS += -DPOWER_SWITCH_PORT=$(POWER_SWITCH_PORT) -DPOWER_SWITCH_PIN=$(POWER_SWITCH_PIN) + DEFS += -DPOWER_CONTROL_PORT=$(POWER_CONTROL_PORT) -DPOWER_CONTROL_PIN=$(POWER_CONTROL_PIN) +endif + +ifeq ($(DRIVER_ADC),yes) + KERNOBJ += adc.o + DEFS += -DADC_ENABLED +endif + +ifeq ($(DRIVER_SPI),yes) + KERNOBJ += spi.o + DEFS += -DSPI_ENABLED +endif + +ifeq ($(DRIVER_GLCD),yes) + KERNOBJ += glcd.o + DEFS += -DGLCD_ENABLED +endif + +ifeq ($(DRIVER_OC),yes) + KERNOBJ += oc.o + DEFS += -DOC_ENABLED +endif + +ifeq ($(DRIVER_SDRAMP),yes) + NEEDS_FEATURE_KERNEL_EXECUTABLE_RAM = yes + KERNOBJ += sdram.o rd_sdramp.o + DEFS += -DSDRAMP_ENABLED +endif \ No newline at end of file diff --git a/sys/pic32/duinomite-e-uart/DUINOMITE-E-UART b/sys/pic32/duinomite-e-uart/DUINOMITE-E-UART new file mode 100644 index 0000000..525a055 --- /dev/null +++ b/sys/pic32/duinomite-e-uart/DUINOMITE-E-UART @@ -0,0 +1,19 @@ +# +# Duinomite-eMega board +# ===================== +# +# Console on UART5 + +core pic32mx7 +mapping generic +linker bootloader-maximite + +device kernel cpu_khz=80000 bus_khz=40000 led=B15 + +device console port=UART5 +device uart5 baud=115200 power=G13 + +device rdisk led=C1 +device sd0 port=3 cs=G12 power=G13 + +device gpio diff --git a/sys/pic32/duinomite-e-uart/Makefile b/sys/pic32/duinomite-e-uart/Makefile new file mode 100644 index 0000000..b23e0d0 --- /dev/null +++ b/sys/pic32/duinomite-e-uart/Makefile @@ -0,0 +1,35 @@ +BUILDPATH = ../../../tools/configsys/../../sys/pic32 +H = ../../../tools/configsys/../../sys/include +M = ../../../tools/configsys/../../sys/pic32 +S = ../../../tools/configsys/../../sys/kernel + +vpath %.c $(M):$(S) +vpath %.S $(M):$(S) + +KERNOBJ += _startup.o clock.o cons.o devsw.o exception.o gpio.o init_main.o init_sysent.o kern_clock.o kern_descrip.o kern_exec.o kern_exit.o kern_fork.o kern_glob.o kern_mman.o kern_proc.o kern_prot.o kern_prot2.o kern_resource.o kern_sig.o kern_sig2.o kern_subr.o kern_synch.o kern_sysctl.o kern_time.o machdep.o mem.o rd_sd.o rdisk.o signal.o spi_bus.o subr_log.o subr_prf.o subr_rmap.o swap.o sys_generic.o sys_inode.o sys_pipe.o sys_process.o syscalls.o sysctl.o tty.o tty_conf.o tty_subr.o tty_tty.o uart.o ufs_alloc.o ufs_bio.o ufs_bmap.o ufs_dsort.o ufs_fio.o ufs_inode.o ufs_mount.o ufs_namei.o ufs_subr.o ufs_syscalls.o ufs_syscalls2.o vers.o vfs_vnops.o vm_sched.o vm_swap.o vm_swp.o + +DEFS += -DBUS_KHZ=40000 +DEFS += -DCONSOLE_UART5=YES +DEFS += -DCPU_KHZ=80000 +DEFS += -DGPIO_ENABLED=YES +DEFS += -DKERNEL +DEFS += -DLED_DISK_PIN=1 +DEFS += -DLED_DISK_PORT=TRISC +DEFS += -DLED_KERNEL_PIN=15 +DEFS += -DLED_KERNEL_PORT=TRISB +DEFS += -DPIC32MX7 +DEFS += -DSD0_CS_PIN=12 +DEFS += -DSD0_CS_PORT=TRISG +DEFS += -DSD0_ENA_PIN=13 +DEFS += -DSD0_ENA_PORT=TRISG +DEFS += -DSD0_PORT=3 +DEFS += -DUART5_BAUD=115200 +DEFS += -DUART5_ENABLED=YES +DEFS += -DUART5_ENA_PIN=13 +DEFS += -DUART5_ENA_PORT=TRISG +DEFS += -DUCB_METER + + +LDSCRIPT = ../../../tools/configsys/../../sys/pic32/lds/bootloader-maximite.ld + +include ../../../tools/configsys/../../sys/pic32/kernel-post.mk diff --git a/sys/pic32/duinomite-e/DUINOMITE-E b/sys/pic32/duinomite-e/DUINOMITE-E new file mode 100644 index 0000000..ed4577e --- /dev/null +++ b/sys/pic32/duinomite-e/DUINOMITE-E @@ -0,0 +1,21 @@ +# +# Duinomite-eMega board +# ===================== +# +# Console on USB +# For Windows, use the driver: http://www.schmalzhaus.com/UBW32/FW/UBW32inf.zip + +core pic32mx7 +mapping generic +linker bootloader-maximite + +device kernel cpu_khz=80000 bus_khz=40000 led=B15 + +device console port=USB +device uartusb + +device rdisk led=C1 +device sd0 port=3 cs=G12 power=G13 + +device gpio + diff --git a/sys/pic32/duinomite-e/Makefile b/sys/pic32/duinomite-e/Makefile new file mode 100644 index 0000000..aab6603 --- /dev/null +++ b/sys/pic32/duinomite-e/Makefile @@ -0,0 +1,34 @@ +BUILDPATH = ../../../tools/configsys/../../sys/pic32 +H = ../../../tools/configsys/../../sys/include +M = ../../../tools/configsys/../../sys/pic32 +S = ../../../tools/configsys/../../sys/kernel + +vpath %.c $(M):$(S) +vpath %.S $(M):$(S) + +KERNOBJ += _startup.o clock.o cons.o devsw.o exception.o gpio.o init_main.o init_sysent.o kern_clock.o kern_descrip.o kern_exec.o kern_exit.o kern_fork.o kern_glob.o kern_mman.o kern_proc.o kern_prot.o kern_prot2.o kern_resource.o kern_sig.o kern_sig2.o kern_subr.o kern_synch.o kern_sysctl.o kern_time.o machdep.o mem.o rd_sd.o rdisk.o signal.o spi_bus.o subr_log.o subr_prf.o subr_rmap.o swap.o sys_generic.o sys_inode.o sys_pipe.o sys_process.o syscalls.o sysctl.o tty.o tty_conf.o tty_subr.o tty_tty.o ufs_alloc.o ufs_bio.o ufs_bmap.o ufs_dsort.o ufs_fio.o ufs_inode.o ufs_mount.o ufs_namei.o ufs_subr.o ufs_syscalls.o ufs_syscalls2.o usb_device.o usb_function_cdc.o usb_uart.o vers.o vfs_vnops.o vm_sched.o vm_swap.o vm_swp.o + +DEFS += -DBUS_KHZ=40000 +DEFS += -DCONSOLE_USB=YES +DEFS += -DCPU_KHZ=80000 +DEFS += -DGPIO_ENABLED=YES +DEFS += -DKERNEL +DEFS += -DLED_DISK_PIN=1 +DEFS += -DLED_DISK_PORT=TRISC +DEFS += -DLED_KERNEL_PIN=15 +DEFS += -DLED_KERNEL_PORT=TRISB +DEFS += -DPIC32MX7 +DEFS += -DSD0_CS_PIN=12 +DEFS += -DSD0_CS_PORT=TRISG +DEFS += -DSD0_ENA_PIN=13 +DEFS += -DSD0_ENA_PORT=TRISG +DEFS += -DSD0_PORT=3 +DEFS += -DUARTUSB_ENABLED=YES +DEFS += -DUCB_METER +DEFS += -DUSB_MAX_EP_NUMBER=3 +DEFS += -DUSB_NUM_STRING_DESCRIPTORS=3 + + +LDSCRIPT = ../../../tools/configsys/../../sys/pic32/lds/bootloader-maximite.ld + +include ../../../tools/configsys/../../sys/pic32/kernel-post.mk diff --git a/sys/pic32/duinomite-uart/DUINOMITE-UART b/sys/pic32/duinomite-uart/DUINOMITE-UART new file mode 100644 index 0000000..2c865dc --- /dev/null +++ b/sys/pic32/duinomite-uart/DUINOMITE-UART @@ -0,0 +1,20 @@ +# +# Duinomite and Duinomite-Mega boards +# =================================== +# +# Console on UART5 + +core pic32mx7 +mapping generic +linker bootloader-maximite + +device kernel cpu_khz=80000 bus_khz=80000 led=B15 + +device console device=tty4 +device uart5 baud=115200 power=B13 + +device rdisk led=B12 +device sd0 port=3 cs=D5 power=B13 + +device gpio +device foreignbootloader diff --git a/sys/pic32/duinomite-uart/Makefile b/sys/pic32/duinomite-uart/Makefile new file mode 100644 index 0000000..2883e97 --- /dev/null +++ b/sys/pic32/duinomite-uart/Makefile @@ -0,0 +1,68 @@ +BUILDPATH = ../../../tools/configsys/../../sys/pic32 +H = ../../../tools/configsys/../../sys/include +M = ../../../tools/configsys/../../sys/pic32 +S = ../../../tools/configsys/../../sys/kernel + +vpath %.c $(M):$(S) +vpath %.S $(M):$(S) + +KERNOBJ += _startup.o clock.o cons.o devsw.o exception.o gpio.o init_main.o init_sysent.o kern_clock.o kern_descrip.o kern_exec.o kern_exit.o kern_fork.o kern_mman.o kern_proc.o kern_prot.o kern_prot2.o kern_resource.o kern_sig.o kern_sig2.o kern_subr.o kern_synch.o kern_sysctl.o kern_time.o machdep.o mem.o rd_sd.o rdisk.o signal.o spi_bus.o subr_prf.o subr_rmap.o swap.o sys_generic.o sys_inode.o sys_pipe.o sys_process.o syscalls.o sysctl.o tty.o tty_subr.o tty_tty.o uart.o ufs_alloc.o ufs_bio.o ufs_bmap.o ufs_dsort.o ufs_fio.o ufs_inode.o ufs_mount.o ufs_namei.o ufs_subr.o ufs_syscalls.o ufs_syscalls2.o vers.o vfs_vnops.o vm_sched.o vm_swap.o vm_swp.o +EXTRA_TARGETS = + +DEFS += -DBUS_DIV=1 +DEFS += -DBUS_KHZ=80000 +DEFS += -DCONSOLE_DEVICE=tty4 +DEFS += -DCPU_IDIV=2 +DEFS += -DCPU_KHZ=80000 +DEFS += -DCPU_MUL=20 +DEFS += -DCPU_ODIV=1 +DEFS += -DCRYSTAL=8 +DEFS += -DDC0_DEBUG=DEVCFG0_DEBUG_DISABLED +DEFS += -DDC0_ICE=0 +DEFS += -DDC1_CKM=0 +DEFS += -DDC1_CKS=0 +DEFS += -DDC1_FNOSC=DEVCFG1_FNOSC_PRIPLL +DEFS += -DDC1_IESO=DEVCFG1_IESO +DEFS += -DDC1_OSCIOFNC=0 +DEFS += -DDC1_PBDIV=DEVCFG1_FPBDIV_1 +DEFS += -DDC1_POSCMOD=DEVCFG1_POSCMOD_HS +DEFS += -DDC1_SOSC=0 +DEFS += -DDC1_WDTEN=0 +DEFS += -DDC1_WDTPS=DEVCFG1_WDTPS_1 +DEFS += -DDC2_PLLIDIV=DEVCFG2_FPLLIDIV_2 +DEFS += -DDC2_PLLMUL=DEVCFG2_FPLLMUL_20 +DEFS += -DDC2_PLLODIV=DEVCFG2_FPLLODIV_1 +DEFS += -DDC2_UPLL=0 +DEFS += -DDC2_UPLLIDIV=DEVCFG2_UPLLIDIV_2 +DEFS += -DDC3_CAN=DEVCFG3_FCANIO +DEFS += -DDC3_ETH=DEVCFG3_FETHIO +DEFS += -DDC3_MII=DEVCFG3_FMIIEN +DEFS += -DDC3_SRS=DEVCFG3_FSRSSEL_7 +DEFS += -DDC3_USBID=DEVCFG3_FUSBIDIO +DEFS += -DDC3_USERID=0xffff +DEFS += -DDC3_VBUSON=DEVCFG3_FVBUSONIO +DEFS += -DGPIO_ENABLED=YES +DEFS += -DKERNEL +DEFS += -DLED_DISK_PIN=12 +DEFS += -DLED_DISK_PORT=TRISB +DEFS += -DLED_KERNEL_PIN=15 +DEFS += -DLED_KERNEL_PORT=TRISB +DEFS += -DPIC32MX7 +DEFS += -DSD0_CS_PIN=5 +DEFS += -DSD0_CS_PORT=TRISD +DEFS += -DSD0_ENA_PIN=13 +DEFS += -DSD0_ENA_PORT=TRISB +DEFS += -DSD0_PORT=3 +DEFS += -DUART5_BAUD=115200 +DEFS += -DUART5_ENABLED=YES +DEFS += -DUART5_ENA_PIN=13 +DEFS += -DUART5_ENA_PORT=TRISB +DEFS += -DUCB_METER + + +LDSCRIPT = ../../../tools/configsys/../../sys/pic32/cfg/bootloader-maximite.ld + +CONFIG = DUINOMITE-UART +CONFIGPATH = ../../../tools/configsys + +include ../../../tools/configsys/../../sys/pic32/kernel-post.mk diff --git a/sys/pic32/duinomite-uart/using-bootloader.ld b/sys/pic32/duinomite-uart/using-bootloader.ld new file mode 100644 index 0000000..499a9a9 --- /dev/null +++ b/sys/pic32/duinomite-uart/using-bootloader.ld @@ -0,0 +1,115 @@ +/* + * Linker script for PIC32 firmware using HID bootloader. + */ +OUTPUT_FORMAT("elf32-littlemips", "elf32-bigmips", + "elf32-littlemips") +OUTPUT_ARCH(mips) +ENTRY(_reset_vector_) +MEMORY +{ + flash (rx) : ORIGIN = 0x9d003000, LENGTH = 492K + ram (rw!x): ORIGIN = 0x80000000, LENGTH = 26K + u0area (rw!x): ORIGIN = 0x80006800, LENGTH = 3K + uarea (rw!x): ORIGIN = 0x80007400, LENGTH = 3K + + /* Required by Microchip C32 linker */ + kseg0_program_mem (rx) : ORIGIN = 0x9D000000, LENGTH = 0x80000 + kseg0_boot_mem : ORIGIN = 0x9FC00490, LENGTH = 0x970 + exception_mem : ORIGIN = 0x9FC01000, LENGTH = 0x1000 + kseg1_boot_mem : ORIGIN = 0xBFC00000, LENGTH = 0x490 + kseg1_data_mem (w!x) : ORIGIN = 0xA0000000, LENGTH = 0x20000 +} + +/* higher address of the user mode stack */ +u0 = ORIGIN(u0area); +u = ORIGIN(uarea); +u_end = ORIGIN(uarea) + LENGTH(uarea); + +SECTIONS +{ + .text ORIGIN(flash) : + { + /* Exception handlers. */ + *(.exception) + . = 0x1000; + /* Execution starts here. */ + *(.startup) + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.glue_7t) *(.glue_7) + __rodata_start = . ; + *(.rodata .rodata.* .gnu.linkonce.r.* .rel.dyn) + *(.dinit) + /* Align here to ensure that the .text section ends on word boundary. */ + . = ALIGN (32 / 8); + _etext = .; + } > flash + + /* Start data (internal SRAM). */ + .data : AT (ADDR (.text) + SIZEOF (.text)) + { + __data_start = . ; + _gp = .; /* We use only 32k RAM for kernel, so no need for 0x8000 offset. */ + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + *(.sdata .sdata.* .gnu.linkonce.s.*) + *(.data .data.* .gnu.linkonce.d.*) + *(.eh_frame) + _edata = .; + } > ram + + .bss ADDR (.data) + SIZEOF (.data) (NOLOAD) : + { + __bss_start = .; + *(.dynbss) + *(.sbss .sbss.*) + *(.scommon) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. */ + . = ALIGN (32 / 8); + } > ram + __bss_end = . ; + _end = .; + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + .debug_pubtypes 0 : { *(.debug_pubtypes) } + .debug_ranges 0 : { *(.debug_ranges) } + .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) } +} diff --git a/sys/pic32/duinomite/DUINOMITE b/sys/pic32/duinomite/DUINOMITE new file mode 100644 index 0000000..bdde407 --- /dev/null +++ b/sys/pic32/duinomite/DUINOMITE @@ -0,0 +1,21 @@ +# +# Duinomite and Duinomite-Mega boards +# =================================== +# +# Console on USB +# For Windows, use the driver: http://www.schmalzhaus.com/UBW32/FW/UBW32inf.zip + +core pic32mx7 +mapping generic +linker bootloader-maximite + +device kernel cpu_khz=80000 bus_khz=80000 led=B15 + +device console device=ttyUSB0 +device uartusb + +device rdisk led=B12 +device sd0 port=3 cs=D5 power=B13 + +device gpio +device foreignbootloader diff --git a/sys/pic32/duinomite/Makefile b/sys/pic32/duinomite/Makefile new file mode 100644 index 0000000..687441c --- /dev/null +++ b/sys/pic32/duinomite/Makefile @@ -0,0 +1,67 @@ +BUILDPATH = ../../../tools/configsys/../../sys/pic32 +H = ../../../tools/configsys/../../sys/include +M = ../../../tools/configsys/../../sys/pic32 +S = ../../../tools/configsys/../../sys/kernel + +vpath %.c $(M):$(S) +vpath %.S $(M):$(S) + +KERNOBJ += _startup.o clock.o cons.o devsw.o exception.o gpio.o init_main.o init_sysent.o kern_clock.o kern_descrip.o kern_exec.o kern_exit.o kern_fork.o kern_mman.o kern_proc.o kern_prot.o kern_prot2.o kern_resource.o kern_sig.o kern_sig2.o kern_subr.o kern_synch.o kern_sysctl.o kern_time.o machdep.o mem.o rd_sd.o rdisk.o signal.o spi_bus.o subr_prf.o subr_rmap.o swap.o sys_generic.o sys_inode.o sys_pipe.o sys_process.o syscalls.o sysctl.o tty.o tty_subr.o tty_tty.o ufs_alloc.o ufs_bio.o ufs_bmap.o ufs_dsort.o ufs_fio.o ufs_inode.o ufs_mount.o ufs_namei.o ufs_subr.o ufs_syscalls.o ufs_syscalls2.o usb_device.o usb_function_cdc.o usb_uart.o vers.o vfs_vnops.o vm_sched.o vm_swap.o vm_swp.o +EXTRA_TARGETS = + +DEFS += -DBUS_DIV=1 +DEFS += -DBUS_KHZ=80000 +DEFS += -DCONSOLE_DEVICE=ttyUSB0 +DEFS += -DCPU_IDIV=2 +DEFS += -DCPU_KHZ=80000 +DEFS += -DCPU_MUL=20 +DEFS += -DCPU_ODIV=1 +DEFS += -DCRYSTAL=8 +DEFS += -DDC0_DEBUG=DEVCFG0_DEBUG_DISABLED +DEFS += -DDC0_ICE=0 +DEFS += -DDC1_CKM=0 +DEFS += -DDC1_CKS=0 +DEFS += -DDC1_FNOSC=DEVCFG1_FNOSC_PRIPLL +DEFS += -DDC1_IESO=DEVCFG1_IESO +DEFS += -DDC1_OSCIOFNC=0 +DEFS += -DDC1_PBDIV=DEVCFG1_FPBDIV_1 +DEFS += -DDC1_POSCMOD=DEVCFG1_POSCMOD_HS +DEFS += -DDC1_SOSC=0 +DEFS += -DDC1_WDTEN=0 +DEFS += -DDC1_WDTPS=DEVCFG1_WDTPS_1 +DEFS += -DDC2_PLLIDIV=DEVCFG2_FPLLIDIV_2 +DEFS += -DDC2_PLLMUL=DEVCFG2_FPLLMUL_20 +DEFS += -DDC2_PLLODIV=DEVCFG2_FPLLODIV_1 +DEFS += -DDC2_UPLL=0 +DEFS += -DDC2_UPLLIDIV=DEVCFG2_UPLLIDIV_2 +DEFS += -DDC3_CAN=DEVCFG3_FCANIO +DEFS += -DDC3_ETH=DEVCFG3_FETHIO +DEFS += -DDC3_MII=DEVCFG3_FMIIEN +DEFS += -DDC3_SRS=DEVCFG3_FSRSSEL_7 +DEFS += -DDC3_USBID=DEVCFG3_FUSBIDIO +DEFS += -DDC3_USERID=0xffff +DEFS += -DDC3_VBUSON=DEVCFG3_FVBUSONIO +DEFS += -DGPIO_ENABLED=YES +DEFS += -DKERNEL +DEFS += -DLED_DISK_PIN=12 +DEFS += -DLED_DISK_PORT=TRISB +DEFS += -DLED_KERNEL_PIN=15 +DEFS += -DLED_KERNEL_PORT=TRISB +DEFS += -DPIC32MX7 +DEFS += -DSD0_CS_PIN=5 +DEFS += -DSD0_CS_PORT=TRISD +DEFS += -DSD0_ENA_PIN=13 +DEFS += -DSD0_ENA_PORT=TRISB +DEFS += -DSD0_PORT=3 +DEFS += -DUARTUSB_ENABLED=YES +DEFS += -DUCB_METER +DEFS += -DUSB_MAX_EP_NUMBER=3 +DEFS += -DUSB_NUM_STRING_DESCRIPTORS=3 + + +LDSCRIPT = ../../../tools/configsys/../../sys/pic32/cfg/bootloader-maximite.ld + +CONFIG = DUINOMITE +CONFIGPATH = ../../../tools/configsys + +include ../../../tools/configsys/../../sys/pic32/kernel-post.mk diff --git a/sys/pic32/duinomite/using-bootloader.ld b/sys/pic32/duinomite/using-bootloader.ld new file mode 100644 index 0000000..499a9a9 --- /dev/null +++ b/sys/pic32/duinomite/using-bootloader.ld @@ -0,0 +1,115 @@ +/* + * Linker script for PIC32 firmware using HID bootloader. + */ +OUTPUT_FORMAT("elf32-littlemips", "elf32-bigmips", + "elf32-littlemips") +OUTPUT_ARCH(mips) +ENTRY(_reset_vector_) +MEMORY +{ + flash (rx) : ORIGIN = 0x9d003000, LENGTH = 492K + ram (rw!x): ORIGIN = 0x80000000, LENGTH = 26K + u0area (rw!x): ORIGIN = 0x80006800, LENGTH = 3K + uarea (rw!x): ORIGIN = 0x80007400, LENGTH = 3K + + /* Required by Microchip C32 linker */ + kseg0_program_mem (rx) : ORIGIN = 0x9D000000, LENGTH = 0x80000 + kseg0_boot_mem : ORIGIN = 0x9FC00490, LENGTH = 0x970 + exception_mem : ORIGIN = 0x9FC01000, LENGTH = 0x1000 + kseg1_boot_mem : ORIGIN = 0xBFC00000, LENGTH = 0x490 + kseg1_data_mem (w!x) : ORIGIN = 0xA0000000, LENGTH = 0x20000 +} + +/* higher address of the user mode stack */ +u0 = ORIGIN(u0area); +u = ORIGIN(uarea); +u_end = ORIGIN(uarea) + LENGTH(uarea); + +SECTIONS +{ + .text ORIGIN(flash) : + { + /* Exception handlers. */ + *(.exception) + . = 0x1000; + /* Execution starts here. */ + *(.startup) + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.glue_7t) *(.glue_7) + __rodata_start = . ; + *(.rodata .rodata.* .gnu.linkonce.r.* .rel.dyn) + *(.dinit) + /* Align here to ensure that the .text section ends on word boundary. */ + . = ALIGN (32 / 8); + _etext = .; + } > flash + + /* Start data (internal SRAM). */ + .data : AT (ADDR (.text) + SIZEOF (.text)) + { + __data_start = . ; + _gp = .; /* We use only 32k RAM for kernel, so no need for 0x8000 offset. */ + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + *(.sdata .sdata.* .gnu.linkonce.s.*) + *(.data .data.* .gnu.linkonce.d.*) + *(.eh_frame) + _edata = .; + } > ram + + .bss ADDR (.data) + SIZEOF (.data) (NOLOAD) : + { + __bss_start = .; + *(.dynbss) + *(.sbss .sbss.*) + *(.scommon) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. */ + . = ALIGN (32 / 8); + } > ram + __bss_end = . ; + _end = .; + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + .debug_pubtypes 0 : { *(.debug_pubtypes) } + .debug_ranges 0 : { *(.debug_ranges) } + .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) } +} diff --git a/sys/pic32/exception.c b/sys/pic32/exception.c new file mode 100644 index 0000000..2d70c7d --- /dev/null +++ b/sys/pic32/exception.c @@ -0,0 +1,575 @@ +/* + * Copyright (c) 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "param.h" +#include "signalvar.h" +#include "systm.h" +#include "user.h" +#include "proc.h" +#include "vm.h" +#include "uart.h" +#include "usb_uart.h" +#include "debug.h" + +//#define TRACE_EXCEPTIONS + +#ifdef POWER_ENABLED +extern void power_switch_check(); +#endif + +/* + * Copy of COP0 Debug register, saved by exception handler (in startup.S). + */ +int c0_debug; + +volatile unsigned int ct_ticks = 0; + +#ifdef TRACE_EXCEPTIONS +static void +print_args (narg, arg0, arg1, arg2, arg3, arg4, arg5) +{ + void print_arg (val) { + if (val & 0xff000000) + printf ("%08x", val); + else + printf ("%u", val); + } + + print_arg (arg0); + if (narg > 1) { printf (", "); print_arg (arg1); } + if (narg > 2) { printf (", "); print_arg (arg2); } + if (narg > 3) { printf (", "); print_arg (arg3); } + if (narg > 4) { printf (", "); print_arg (arg4); } + if (narg > 5) { printf (", "); print_arg (arg5); } +} +#endif + +/* + * Translate interrupt vector number to IRQ mask. + */ +static const unsigned mask_by_vector[] = { + (1 << PIC32_IRQ_CT), /* 0 - Core Timer Interrupt */ + (1 << PIC32_IRQ_CS0), /* 1 - Core Software Interrupt 0 */ + (1 << PIC32_IRQ_CS1), /* 2 - Core Software Interrupt 1 */ + (1 << PIC32_IRQ_INT0), /* 3 - External Interrupt 0 */ + (1 << PIC32_IRQ_T1), /* 4 - Timer1 */ + (1 << PIC32_IRQ_IC1), /* 5 - Input Capture 1 */ + (1 << PIC32_IRQ_OC1), /* 6 - Output Compare 1 */ + (1 << PIC32_IRQ_INT1), /* 7 - External Interrupt 1 */ + (1 << PIC32_IRQ_T2), /* 8 - Timer2 */ + (1 << PIC32_IRQ_IC2), /* 9 - Input Capture 2 */ + (1 << PIC32_IRQ_OC2), /* 10 - Output Compare 2 */ + (1 << PIC32_IRQ_INT2), /* 11 - External Interrupt 2 */ + (1 << PIC32_IRQ_T3), /* 12 - Timer3 */ + (1 << PIC32_IRQ_IC3), /* 13 - Input Capture 3 */ + (1 << PIC32_IRQ_OC3), /* 14 - Output Compare 3 */ + (1 << PIC32_IRQ_INT3), /* 15 - External Interrupt 3 */ + (1 << PIC32_IRQ_T4), /* 16 - Timer4 */ + (1 << PIC32_IRQ_IC4), /* 17 - Input Capture 4 */ + (1 << PIC32_IRQ_OC4), /* 18 - Output Compare 4 */ + (1 << PIC32_IRQ_INT4), /* 19 - External Interrupt 4 */ + (1 << PIC32_IRQ_T5), /* 20 - Timer5 */ + (1 << PIC32_IRQ_IC5), /* 21 - Input Capture 5 */ + (1 << PIC32_IRQ_OC5), /* 22 - Output Compare 5 */ + (1 << PIC32_IRQ_SPI1E) | /* 23 - SPI1 */ + (1 << PIC32_IRQ_SPI1TX) | + (1 << PIC32_IRQ_SPI1RX), + + (1 << PIC32_IRQ_U1E) | /* 24 - UART1 */ + (1 << PIC32_IRQ_U1RX) | + (1 << PIC32_IRQ_U1TX) | + (1 << PIC32_IRQ_SPI3E) | /* 24 - SPI3 */ + (1 << PIC32_IRQ_SPI3TX) | + (1 << PIC32_IRQ_SPI3RX) | + (1 << PIC32_IRQ_I2C3B) | /* 24 - I2C3 */ + (1 << PIC32_IRQ_I2C3S) | + (1 << PIC32_IRQ_I2C3M), + + (1 << PIC32_IRQ_I2C1B) | /* 25 - I2C1 */ + (1 << PIC32_IRQ_I2C1S) | + (1 << PIC32_IRQ_I2C1M), + (1 << (PIC32_IRQ_CN-32)), /* 26 - Input Change Interrupt */ + (1 << (PIC32_IRQ_AD1-32)), /* 27 - ADC1 Convert Done */ + (1 << (PIC32_IRQ_PMP-32)), /* 28 - Parallel Master Port */ + (1 << (PIC32_IRQ_CMP1-32)), /* 29 - Comparator Interrupt */ + (1 << (PIC32_IRQ_CMP2-32)), /* 30 - Comparator Interrupt */ + + (1 << (PIC32_IRQ_U3E-32)) | /* 31 - UART3 */ + (1 << (PIC32_IRQ_U3E-32)) | + (1 << (PIC32_IRQ_U3E-32)) | + (1 << (PIC32_IRQ_SPI2E-32)) | /* 31 - SPI2 */ + (1 << (PIC32_IRQ_SPI2TX-32)) | + (1 << (PIC32_IRQ_SPI2RX-32)) | + (1 << (PIC32_IRQ_I2C4B-32)) | /* 31 - I2C4 */ + (1 << (PIC32_IRQ_I2C4S-32)) | + (1 << (PIC32_IRQ_I2C4M-32)), + + (1 << (PIC32_IRQ_U2E-32)) | /* 32 - UART2 */ + (1 << (PIC32_IRQ_U2RX-32)) | + (1 << (PIC32_IRQ_U2TX-32)) | + (1 << (PIC32_IRQ_SPI4E-32)) | /* 32 - SPI4 */ + (1 << (PIC32_IRQ_SPI4TX-32)) | + (1 << (PIC32_IRQ_SPI4RX-32)) | + (1 << (PIC32_IRQ_I2C5B-32)) | /* 32 - I2C5 */ + (1 << (PIC32_IRQ_I2C5S-32)) | + (1 << (PIC32_IRQ_I2C5M-32)), + + (1 << (PIC32_IRQ_I2C2B-32)) | /* 33 - I2C2 */ + (1 << (PIC32_IRQ_I2C2S-32)) | + (1 << (PIC32_IRQ_I2C2M-32)), + (1 << (PIC32_IRQ_FSCM-32)), /* 34 - Fail-Safe Clock Monitor */ + (1 << (PIC32_IRQ_RTCC-32)), /* 35 - Real-Time Clock and Calendar */ + (1 << (PIC32_IRQ_DMA0-32)), /* 36 - DMA Channel 0 */ + (1 << (PIC32_IRQ_DMA1-32)), /* 37 - DMA Channel 1 */ + (1 << (PIC32_IRQ_DMA2-32)), /* 38 - DMA Channel 2 */ + (1 << (PIC32_IRQ_DMA3-32)), /* 39 - DMA Channel 3 */ + (1 << (PIC32_IRQ_DMA4-32)), /* 40 - DMA Channel 4 */ + (1 << (PIC32_IRQ_DMA5-32)), /* 41 - DMA Channel 5 */ + (1 << (PIC32_IRQ_DMA6-32)), /* 42 - DMA Channel 6 */ + (1 << (PIC32_IRQ_DMA7-32)), /* 43 - DMA Channel 7 */ + (1 << (PIC32_IRQ_FCE-32)), /* 44 - Flash Control Event */ + (1 << (PIC32_IRQ_USB-32)), /* 45 - USB */ + (1 << (PIC32_IRQ_CAN1-32)), /* 46 - Control Area Network 1 */ + (1 << (PIC32_IRQ_CAN2-32)), /* 47 - Control Area Network 2 */ + (1 << (PIC32_IRQ_ETH-32)), /* 48 - Ethernet Controller */ + (1 << (PIC32_IRQ_U4E-64)) | /* 49 - UART4 */ + (1 << (PIC32_IRQ_U4RX-64)) | + (1 << (PIC32_IRQ_U4TX-64)), + (1 << (PIC32_IRQ_U6E-64)) | /* 50 - UART6 */ + (1 << (PIC32_IRQ_U6RX-64)) | + (1 << (PIC32_IRQ_U6TX-64)), + (1 << (PIC32_IRQ_U5E-64)) | /* 51 - UART5 */ + (1 << (PIC32_IRQ_U5RX-64)) | + (1 << (PIC32_IRQ_U5TX-64)) +}; + +static void +dumpregs (frame) + int *frame; +{ + unsigned int cause; + const char *code = 0; + + unsigned * stacktop = (unsigned *)0x80007ffc; + unsigned * p = (unsigned*)frame; + printf( "************************************\n"); + printf( "*******STACK DUMP START*************\n"); + printf( "frame = %8x\n", frame ); + printf( "stack data\n" ); + while( p <= stacktop ) + { + printf( " %8x", *p++ ); + if( p <= stacktop ) printf( " %8x", *p++ ); + if( p <= stacktop ) printf( " %8x", *p++ ); + if( p <= stacktop ) printf( " %8x", *p++ ); + printf("\n"); + } + printf( "*******STACK DUMP END***************\n"); + printf( "************************************\n"); + + + printf ("\n*** 0x%08x: exception ", frame [FRAME_PC]); + + cause = mips_read_c0_register (C0_CAUSE, 0); + switch (cause & CA_EXC_CODE) { + case CA_Int: code = "Interrupt"; break; + case CA_AdEL: code = "Address Load"; break; + case CA_AdES: code = "Address Save"; break; + case CA_IBE: code = "Bus fetch"; break; + case CA_DBE: code = "Bus load/store"; break; + case CA_Sys: code = "Syscall"; break; + case CA_Bp: code = "Breakpoint"; break; + case CA_RI: code = "Reserved Instruction"; break; + case CA_CPU: code = "Coprocessor Unusable"; break; + case CA_Ov: code = "Arithmetic Overflow"; break; + case CA_Tr: code = "Trap"; break; + } + if (code) + printf ("'%s'\n", code); + else + printf ("%d\n", cause >> 2 & 31); + + switch (cause & CA_EXC_CODE) { + case CA_AdEL: + case CA_AdES: + printf ("*** badvaddr = 0x%08x\n", + mips_read_c0_register (C0_BADVADDR, 0)); + } + printf (" t0 = %8x s0 = %8x t8 = %8x lo = %8x\n", + frame [FRAME_R8], frame [FRAME_R16], + frame [FRAME_R24], frame [FRAME_LO]); + printf ("at = %8x t1 = %8x s1 = %8x t9 = %8x hi = %8x\n", + frame [FRAME_R1], frame [FRAME_R9], frame [FRAME_R17], + frame [FRAME_R25], frame [FRAME_HI]); + printf ("v0 = %8x t2 = %8x s2 = %8x status = %8x\n", + frame [FRAME_R2], frame [FRAME_R10], + frame [FRAME_R18], frame [FRAME_STATUS]); + printf ("v1 = %8x t3 = %8x s3 = %8x cause = %8x\n", + frame [FRAME_R3], frame [FRAME_R11], + frame [FRAME_R19], cause); + printf ("a0 = %8x t4 = %8x s4 = %8x gp = %8x epc = %8x\n", + frame [FRAME_R4], frame [FRAME_R12], + frame [FRAME_R20], frame [FRAME_GP], frame [FRAME_PC]); + printf ("a1 = %8x t5 = %8x s5 = %8x sp = %8x\n", + frame [FRAME_R5], frame [FRAME_R13], + frame [FRAME_R21], frame [FRAME_SP]); + printf ("a2 = %8x t6 = %8x s6 = %8x fp = %8x\n", + frame [FRAME_R6], frame [FRAME_R14], + frame [FRAME_R22], frame [FRAME_FP]); + printf ("a3 = %8x t7 = %8x s7 = %8x ra = %8x\n", + frame [FRAME_R7], frame [FRAME_R15], + frame [FRAME_R23], frame [FRAME_RA]); + + + +} + +/* + * User mode flag added to cause code if exception is from user space. + */ +#define USER 1 + +/* + * Called from startup.S when a processor exception occurs. + * The argument is the array of registers saved on the system stack + * by the hardware and software during the exception processing. + */ +void +exception (frame) + int *frame; +{ + register int psig; + time_t syst; + unsigned c, irq, status, cause, sp; + + led_control (LED_KERNEL, 1); + if ((unsigned) frame < (unsigned) &u + sizeof(u)) { + dumpregs (frame); + panic ("stack overflow"); + /*NOTREACHED*/ + } + /* Switch to kernel mode, keep interrupts disabled. */ + status = frame [FRAME_STATUS]; + mips_write_c0_register (C0_STATUS, 0, + status & ~(ST_UM | ST_EXL | ST_IE)); + + if (c0_debug & DB_DM) { + cause = CA_Bp; + c0_debug = 0; + // TODO: save DBD bit + } else { + cause = mips_read_c0_register (C0_CAUSE, 0); + cause &= CA_EXC_CODE; + } + if (USERMODE (status)) + cause |= USER; + + syst = u.u_ru.ru_stime; + + switch (cause) { + + /* + * Exception. + */ + default: +#ifdef UCB_METER + cnt.v_trap++; +#endif + switch (cause) { + default: /* Unknown exception: fatal kernel error */ + dumpregs (frame); + panic ("unexpected exception"); + /*NOTREACHED*/ + case CA_IBE + USER: /* Bus error, instruction fetch */ + case CA_DBE + USER: /* Bus error, load or store */ + printf ("*** 0x%08x: bus error\n", frame [FRAME_PC]); + psig = SIGBUS; + break; + case CA_RI + USER: /* Reserved instruction */ + psig = SIGILL; + break; + case CA_Bp + USER: /* Breakpoint */ + psig = SIGTRAP; + break; + case CA_Tr + USER: /* Trap */ + psig = SIGIOT; + break; + case CA_CPU + USER: /* Coprocessor unusable */ + psig = SIGEMT; + break; + case CA_Ov: /* Arithmetic overflow */ + case CA_Ov + USER: + psig = SIGFPE; + break; + case CA_AdEL + USER: /* Address error, load or instruction fetch */ + case CA_AdES + USER: /* Address error, store */ + printf ("*** 0x%08x: bad address 0x%08x\n", + frame [FRAME_PC], mips_read_c0_register (C0_BADVADDR, 0)); + psig = SIGSEGV; + break; + } + /* Enable interrupts. */ + mips_intr_enable(); + break; + + /* + * Hardware interrupt. + */ + case CA_Int: /* Interrupt */ + case CA_Int + USER: +#ifdef UCB_METER + cnt.v_intr++; +#endif + /* Get the current irq number */ + c = INTSTAT; + if ((c & PIC32_INTSTAT_SRIPL_MASK) == 0) { + //printf ("*** unexpected interrupt: INTSTAT %08x\n", c); + goto ret; + } + irq = PIC32_INTSTAT_VEC (c); + + + /* Handle the interrupt. */ + switch (irq) { + case PIC32_VECT_CT: /* Core Timer */ + ct_ticks++; + /* Increment COMPARE register. */ + IFSCLR(0) = 1 << PIC32_IRQ_CT; + c = mips_read_c0_register (C0_COMPARE, 0); + do { + c += (CPU_KHZ * 1000 / HZ + 1) / 2; + mips_write_c0_register (C0_COMPARE, 0, c); + } while ((int) (c - (unsigned)mips_read_c0_register (C0_COUNT, 0)) < 0); + hardclock ((caddr_t) frame [FRAME_PC], status); + +#ifdef POWER_ENABLED + power_switch_check(); +#endif + +#ifdef UARTUSB_ENABLED + /* Poll USB on every timer tick. */ + usbintr(0); +#endif + break; +#ifdef UART1_ENABLED + case PIC32_VECT_U1: /* UART1 */ + uartintr(makedev(UART_MAJOR,0)); + break; +#endif +#ifdef UART2_ENABLED + case PIC32_VECT_U2: /* UART2 */ + uartintr(makedev(UART_MAJOR,1)); + break; +#endif +#ifdef UART3_ENABLED + case PIC32_VECT_U3: /* UART3 */ + uartintr(makedev(UART_MAJOR,2)); + break; +#endif +#ifdef UART4_ENABLED + case PIC32_VECT_U4: /* UART4 */ + uartintr(makedev(UART_MAJOR,3)); + break; +#endif +#ifdef UART5_ENABLED + case PIC32_VECT_U5: /* UART5 */ + uartintr(makedev(UART_MAJOR,4)); + break; +#endif +#ifdef UART6_ENABLED + case PIC32_VECT_U6: /* UART6 */ + if(!(SD0_PORT == 2)) + { + uartintr(makedev(UART_MAJOR,5)); + } + break; +#endif +#ifdef UARTUSB_ENABLED + case PIC32_VECT_USB: /* USB */ + IFSCLR(1) = 1 << (PIC32_IRQ_USB - 32); + usbintr(0); + break; +#endif + + default: + /* Disable the irq, to avoid loops */ + printf ("*** irq %u\n", irq); + if (irq < PIC32_VECT_CN) { + IECCLR(0) = mask_by_vector [irq]; + IFSCLR(0) = mask_by_vector [irq]; + } else { + IECCLR(1) = mask_by_vector [irq]; + IFSCLR(1) = mask_by_vector [irq]; + } + break; + } + if ((cause & USER) && runrun) { + /* Need to switch processes: in user mode only. + * Enable interrupts first. */ +// MADSCIFI start new code + //u.u_error = 0; + u.u_frame = frame; + u.u_code = frame [FRAME_PC]; /* For signal handler */ + + /* Check stack. */ + sp = frame [FRAME_SP]; + if (sp < u.u_procp->p_daddr + u.u_dsize) { + /* Process has trashed its stack; give it an illegal + * instruction violation to halt it in its tracks. */ + panic ("unexpected exception 2"); + psig = SIGSEGV; + break; + } + if (u.u_procp->p_ssize < USER_DATA_END - sp) { + /* Expand stack. */ + u.u_procp->p_ssize = USER_DATA_END - sp; + u.u_procp->p_saddr = sp; + u.u_ssize = u.u_procp->p_ssize; + } +// MADSCIFI end new code + + mips_intr_enable(); + goto out; + } + goto ret; + + /* + * System call. + */ + case CA_Sys + USER: /* Syscall */ +#ifdef UCB_METER + cnt.v_syscall++; +#endif + /* Enable interrupts. */ + mips_intr_enable(); + u.u_error = 0; + u.u_frame = frame; + u.u_code = frame [FRAME_PC]; /* For signal handler */ + + /* Check stack. */ + sp = frame [FRAME_SP]; + if (sp < u.u_procp->p_daddr + u.u_dsize) { + /* Process has trashed its stack; give it an illegal + * instruction violation to halt it in its tracks. */ + psig = SIGSEGV; + break; + } + if (u.u_procp->p_ssize < USER_DATA_END - sp) { + /* Expand stack. */ + u.u_procp->p_ssize = USER_DATA_END - sp; + u.u_procp->p_saddr = sp; + u.u_ssize = u.u_procp->p_ssize; + } + + /* Original pc for restarting syscalls */ + int opc = frame [FRAME_PC]; /* opc points at syscall */ + frame [FRAME_PC] = opc + 3*NBPW; /* no errors - skip 2 next instructions */ + + const struct sysent *callp = &sysent[0]; + int code = (*(u_int*) opc >> 6) & 0377; /* bottom 8 bits are index */ + if (code < nsysent) + callp += code; + + if (callp->sy_narg) { + u.u_arg[0] = frame [FRAME_R4]; /* $a0 */ + u.u_arg[1] = frame [FRAME_R5]; /* $a1 */ + u.u_arg[2] = frame [FRAME_R6]; /* $a2 */ + u.u_arg[3] = frame [FRAME_R7]; /* $a3 */ + if (callp->sy_narg > 4) { + unsigned addr = (frame [FRAME_SP] + 16) & ~3; + if (! baduaddr ((caddr_t) addr)) + u.u_arg[4] = *(unsigned*) addr; + } + if (callp->sy_narg > 5) { + unsigned addr = (frame [FRAME_SP] + 20) & ~3; + if (! baduaddr ((caddr_t) addr)) + u.u_arg[5] = *(unsigned*) addr; + } + } +#ifdef TRACE_EXCEPTIONS + printf ("--- (%u)syscall: %s (", u.u_procp->p_pid, + syscallnames [code >= nsysent ? 0 : code]); + if (callp->sy_narg > 0) + print_args (callp->sy_narg, u.u_arg[0], u.u_arg[1], + u.u_arg[2], u.u_arg[3], u.u_arg[4], u.u_arg[5]); + printf (") at %08x\n", opc); +#endif + u.u_rval = 0; + if (setjmp (&u.u_qsave) == 0) { + (*callp->sy_call) (); + } + switch (u.u_error) { + case 0: +#ifdef TRACE_EXCEPTIONS + printf (" (%u)syscall returned %u\n", u.u_procp->p_pid, u.u_rval); +#endif + frame [FRAME_R2] = u.u_rval; /* $v0 - result */ + break; + case ERESTART: +#ifdef TRACE_EXCEPTIONS + printf (" (%u)syscall restarted at %#x\n", u.u_procp->p_pid, opc); +#endif + frame [FRAME_PC] = opc; /* return to syscall */ + break; + case EJUSTRETURN: /* return from signal handler */ +#ifdef TRACE_EXCEPTIONS + printf (" (%u)jump to %#x, stack %#x\n", u.u_procp->p_pid, frame [FRAME_PC], frame [FRAME_SP]); +#endif + break; + default: +#ifdef TRACE_EXCEPTIONS + printf (" (%u)syscall failed, errno %d\n", u.u_procp->p_pid, u.u_error); +#endif + frame [FRAME_PC] = opc + NBPW; /* return to next instruction */ + frame [FRAME_R2] = -1; /* $v0 - result */ + frame [FRAME_R8] = u.u_error; /* $t0 - errno */ + break; + } + goto out; + } + /* From this point and further the interrupts must be enabled. */ + psignal (u.u_procp, psig); +out: + /* Process all received signals. */ + for (;;) { + psig = CURSIG (u.u_procp); + if (psig <= 0) + break; + postsig (psig); + } + curpri = setpri (u.u_procp); + + /* Switch to another process. */ + if (runrun) { + setrq (u.u_procp); + u.u_ru.ru_nivcsw++; + swtch(); + } + + /* Update profiling information. */ + if (u.u_prof.pr_scale) + addupc ((caddr_t) frame [FRAME_PC], + &u.u_prof, (int) (u.u_ru.ru_stime - syst)); +ret: + led_control (LED_KERNEL, 0); +} + +/* + * nonexistent system call-- signal process (may want to handle it) + * flag error if process won't see signal immediately + * Q: should we do that all the time ?? + */ +void +nosys() +{ + if (u.u_signal[SIGSYS] == SIG_IGN || u.u_signal[SIGSYS] == SIG_HOLD) + u.u_error = EINVAL; + psignal (u.u_procp, SIGSYS); +} + +void sc_msec() +{ + u.u_rval = ct_ticks * (1000 / HZ); +} diff --git a/sys/pic32/explorer16/EXPLORER16 b/sys/pic32/explorer16/EXPLORER16 new file mode 100644 index 0000000..5f433d5 --- /dev/null +++ b/sys/pic32/explorer16/EXPLORER16 @@ -0,0 +1,18 @@ +# +# Explorer16 board +# ================ +# + +core pic32mx7 +linker bare +mapping generic + +device kernel cpu_khz=80000 bus_khz=80000 led=A1 + +device console led=A2 device=tty1 +device uart2 baud=115200 + +device rdisk led=A0 swap=A3 +device sd0 port=1 cs=B1 mhz=10 + +device gpio diff --git a/sys/pic32/explorer16/Makefile b/sys/pic32/explorer16/Makefile new file mode 100644 index 0000000..e494508 --- /dev/null +++ b/sys/pic32/explorer16/Makefile @@ -0,0 +1,69 @@ +BUILDPATH = ../../../tools/configsys/../../sys/pic32 +H = ../../../tools/configsys/../../sys/include +M = ../../../tools/configsys/../../sys/pic32 +S = ../../../tools/configsys/../../sys/kernel + +vpath %.c $(M):$(S) +vpath %.S $(M):$(S) + +KERNOBJ += _startup.o clock.o cons.o devcfg.o devsw.o exception.o gpio.o init_main.o init_sysent.o kern_clock.o kern_descrip.o kern_exec.o kern_exit.o kern_fork.o kern_mman.o kern_proc.o kern_prot.o kern_prot2.o kern_resource.o kern_sig.o kern_sig2.o kern_subr.o kern_synch.o kern_sysctl.o kern_time.o machdep.o mem.o rd_sd.o rdisk.o signal.o spi_bus.o subr_prf.o subr_rmap.o swap.o sys_generic.o sys_inode.o sys_pipe.o sys_process.o syscalls.o sysctl.o tty.o tty_subr.o tty_tty.o uart.o ufs_alloc.o ufs_bio.o ufs_bmap.o ufs_dsort.o ufs_fio.o ufs_inode.o ufs_mount.o ufs_namei.o ufs_subr.o ufs_syscalls.o ufs_syscalls2.o vers.o vfs_vnops.o vm_sched.o vm_swap.o vm_swp.o +EXTRA_TARGETS = + +DEFS += -DBUS_DIV=1 +DEFS += -DBUS_KHZ=80000 +DEFS += -DCONSOLE_DEVICE=tty1 +DEFS += -DCPU_IDIV=2 +DEFS += -DCPU_KHZ=80000 +DEFS += -DCPU_MUL=20 +DEFS += -DCPU_ODIV=1 +DEFS += -DCRYSTAL=8 +DEFS += -DDC0_DEBUG=DEVCFG0_DEBUG_DISABLED +DEFS += -DDC0_ICE=0 +DEFS += -DDC1_CKM=0 +DEFS += -DDC1_CKS=0 +DEFS += -DDC1_FNOSC=DEVCFG1_FNOSC_PRIPLL +DEFS += -DDC1_IESO=DEVCFG1_IESO +DEFS += -DDC1_OSCIOFNC=0 +DEFS += -DDC1_PBDIV=DEVCFG1_FPBDIV_1 +DEFS += -DDC1_POSCMOD=DEVCFG1_POSCMOD_HS +DEFS += -DDC1_SOSC=0 +DEFS += -DDC1_WDTEN=0 +DEFS += -DDC1_WDTPS=DEVCFG1_WDTPS_1 +DEFS += -DDC2_PLLIDIV=DEVCFG2_FPLLIDIV_2 +DEFS += -DDC2_PLLMUL=DEVCFG2_FPLLMUL_20 +DEFS += -DDC2_PLLODIV=DEVCFG2_FPLLODIV_1 +DEFS += -DDC2_UPLL=0 +DEFS += -DDC2_UPLLIDIV=DEVCFG2_UPLLIDIV_2 +DEFS += -DDC3_CAN=DEVCFG3_FCANIO +DEFS += -DDC3_ETH=DEVCFG3_FETHIO +DEFS += -DDC3_MII=DEVCFG3_FMIIEN +DEFS += -DDC3_SRS=DEVCFG3_FSRSSEL_7 +DEFS += -DDC3_USBID=DEVCFG3_FUSBIDIO +DEFS += -DDC3_USERID=0xffff +DEFS += -DDC3_VBUSON=DEVCFG3_FVBUSONIO +DEFS += -DGPIO_ENABLED=YES +DEFS += -DKERNEL +DEFS += -DLED_DISK_PIN=0 +DEFS += -DLED_DISK_PORT=TRISA +DEFS += -DLED_KERNEL_PIN=1 +DEFS += -DLED_KERNEL_PORT=TRISA +DEFS += -DLED_SWAP_PIN=3 +DEFS += -DLED_SWAP_PORT=TRISA +DEFS += -DLED_TTY_PIN=2 +DEFS += -DLED_TTY_PORT=TRISA +DEFS += -DPIC32MX7 +DEFS += -DSD0_CS_PIN=1 +DEFS += -DSD0_CS_PORT=TRISB +DEFS += -DSD0_MHZ=10 +DEFS += -DSD0_PORT=1 +DEFS += -DUART2_BAUD=115200 +DEFS += -DUART2_ENABLED=YES +DEFS += -DUCB_METER + + +LDSCRIPT = ../../../tools/configsys/../../sys/pic32/cfg/bare.ld + +CONFIG = EXPLORER16 +CONFIGPATH = ../../../tools/configsys + +include ../../../tools/configsys/../../sys/pic32/kernel-post.mk diff --git a/sys/pic32/explorer16/bare-metal.ld b/sys/pic32/explorer16/bare-metal.ld new file mode 100644 index 0000000..5c45bea --- /dev/null +++ b/sys/pic32/explorer16/bare-metal.ld @@ -0,0 +1,162 @@ +/* + * Linker script for PIC32 firmware. + */ +OUTPUT_FORMAT("elf32-littlemips", "elf32-bigmips", + "elf32-littlemips") +OUTPUT_ARCH(mips) +ENTRY(_reset_vector_) +MEMORY +{ + ram (rw!x): ORIGIN = 0x80000000, LENGTH = 26K + u0area (rw!x): ORIGIN = 0x80006800, LENGTH = 3K + uarea (rw!x): ORIGIN = 0x80007400, LENGTH = 3K + devcfg (r) : ORIGIN = 0x9fc02ff0, LENGTH = 16 + + /* Required by Microchip C32 linker */ + kseg0_program_mem (rx) : ORIGIN = 0x9D000000, LENGTH = 512K + exception_mem (rx) : ORIGIN = 0x9D000000, LENGTH = 0x1000 + kseg0_boot_mem (rx) : ORIGIN = 0x9FC00000, LENGTH = 12K-16 + kseg1_boot_mem (rx) : ORIGIN = 0xBFC00000, LENGTH = 0x490 + kseg1_data_mem (w!x) : ORIGIN = 0xA0000000, LENGTH = 0x20000 +} + +/* higher address of the user mode stack */ +u0 = ORIGIN(u0area); +u = ORIGIN(uarea); +u_end = ORIGIN(uarea) + LENGTH(uarea); + +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = 0x0000; + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rel.init : { *(.rel.init) } + .rela.init : { *(.rela.init) } + .rel.text : { *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) } + .rela.text : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) } + .rel.fini : { *(.rel.fini) } + .rela.fini : { *(.rela.fini) } + .rel.rodata : { *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) } + .rela.rodata : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) } + .rel.data : { *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) } + .rela.data : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.sdata : { *(.rel.sdata .rel.sdata.* .rel.gnu.linkonce.s.*) } + .rela.sdata : { *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*) } + .rel.sbss : { *(.rel.sbss .rel.sbss.* .rel.gnu.linkonce.sb.*) } + .rela.sbss : { *(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*) } + .rel.sdata2 : { *(.rel.sdata2 .rel.sdata2.* .rel.gnu.linkonce.s2.*) } + .rela.sdata2 : { *(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*) } + .rel.sbss2 : { *(.rel.sbss2 .rel.sbss2.* .rel.gnu.linkonce.sb2.*) } + .rela.sbss2 : { *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*) } + .rel.bss : { *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) } + .rela.bss : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .plt : { *(.plt) } + + .boot : + { + /* Execution starts here. */ + *(.startup) + } > kseg0_boot_mem + + .text : + { + /* Exception handlers. */ + *(.exception) + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.glue_7t) *(.glue_7) + __rodata_start = . ; + *(.rodata .rodata.* .gnu.linkonce.r.* .rel.dyn) + /* Align here to ensure that the .text section ends on word boundary. */ + . = ALIGN (32 / 8); + _etext = .; + } > kseg0_program_mem + + /* Start data (internal SRAM). */ + .data : AT (ADDR (.text) + SIZEOF (.text)) + { + __data_start = . ; + _gp = .; /* We have only 32k RAM on MC-24, so no need for 0x8000 offset. */ + *(.data .data.* .gnu.linkonce.d.*) + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + *(.sdata .sdata.* .gnu.linkonce.s.*) + *(.eh_frame) + _edata = .; + } > ram + + /* Device configuration. */ + .config : + { + *(.config3) + *(.config2) + *(.config1) + *(.config0) + } > devcfg + + .bss ADDR (.data) + SIZEOF (.data) (NOLOAD) : + { + __bss_start = .; + *(.dynbss) + *(.sbss .sbss.*) + *(.scommon) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. */ + . = ALIGN (32 / 8); + } > ram + __bss_end = . ; + _end = .; + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } +} diff --git a/sys/pic32/explorer16/devcfg.c b/sys/pic32/explorer16/devcfg.c new file mode 100644 index 0000000..29b9d63 --- /dev/null +++ b/sys/pic32/explorer16/devcfg.c @@ -0,0 +1,25 @@ +/* + * Chip configuration. + */ +#include "machine/pic32mx.h" + +PIC32_DEVCFG ( + DEVCFG0_DEBUG_ENABLED, /* ICE debugger enabled */ + + DEVCFG1_FNOSC_PRIPLL | /* Primary oscillator with PLL */ + DEVCFG1_POSCMOD_HS | /* HS oscillator */ + DEVCFG1_OSCIOFNC | /* CLKO output active */ + DEVCFG1_FPBDIV_1 | /* Peripheral bus clock = SYSCLK/1 */ + DEVCFG1_FCKM_DISABLE | /* Fail-safe clock monitor disable */ + DEVCFG1_FCKS_DISABLE | /* Clock switching disable */ + DEVCFG1_WDTPS_1024, /* Watchdog postscale = 1/1024 */ + + DEVCFG2_FPLLIDIV_2 | /* PLL divider = 1/2 */ + DEVCFG2_FPLLMUL_20 | /* PLL multiplier = 20x */ + DEVCFG2_UPLLIDIV_2 | /* USB PLL divider = 1/2 */ + DEVCFG2_UPLLDIS | /* Disable USB PLL */ + DEVCFG2_FPLLODIV_1, /* PLL postscaler = 1/1 */ + + DEVCFG3_USERID(0xffff) | /* User-defined ID */ + DEVCFG3_FSRSSEL_7 | /* Assign irq priority 7 to shadow set */ + DEVCFG3_FETHIO); /* Default Ethernet i/o pins */ diff --git a/sys/pic32/float.h b/sys/pic32/float.h new file mode 100644 index 0000000..3888d80 --- /dev/null +++ b/sys/pic32/float.h @@ -0,0 +1,50 @@ +#ifndef _MACHINE_FLOAT_H_ +#define _MACHINE_FLOAT_H_ + +/* Characteristics of IEEE floating types */ + +#define FLT_RADIX 2 +#define FLT_ROUNDS 1 + +/* + * These values provide information pertaining to the float type. + */ +#define FLT_EPSILON 1.19209290E-07F /* b**(1-p) */ +#define FLT_MAX 3.40282347E+38F /* (1-b**(-p))*b**emax */ +#define FLT_MIN 1.17549435E-38F /* b**(emin-1) */ +#define FLT_DIG 6 /* floor((p-1)*log10(b))+(b == 10) */ +#define FLT_MANT_DIG 24 /* p */ +#define FLT_MAX_10_EXP 38 /* floor(log10((1-b**(-p))*b**emax)) */ +#define FLT_MAX_EXP 128 /* emax */ +#define FLT_MIN_10_EXP (-37) /* ceil(log10(b**(emin-1))) */ +#define FLT_MIN_EXP (-125) /* emin */ + +/* + * These values provide information pertaining to the double type + * The values are dependant upon the presence of the -fno-short-double + * compiler option. + */ +#define DBL_EPSILON FLT_EPSILON +#define DBL_MAX FLT_MAX +#define DBL_MIN FLT_MIN +#define DBL_DIG FLT_DIG +#define DBL_MANT_DIG FLT_MANT_DIG +#define DBL_MAX_10_EXP FLT_MAX_10_EXP +#define DBL_MAX_EXP FLT_MAX_EXP +#define DBL_MIN_10_EXP FLT_MIN_10_EXP +#define DBL_MIN_EXP FLT_MIN_EXP + +/* + * These values provide information pertaining to the long double type. + */ +#define LDBL_EPSILON 2.2204460492503131E-16 +#define LDBL_MAX 1.7976931348623157E+308 +#define LDBL_MIN 2.2250738585072014E-308 +#define LDBL_DIG 15 +#define LDBL_MANT_DIG 53 +#define LDBL_MAX_10_EXP 308 +#define LDBL_MAX_EXP 1024 +#define LDBL_MIN_10_EXP (-307) +#define LDBL_MIN_EXP (-1021) + +#endif /* _MACHINE_FLOAT_H_ */ diff --git a/sys/pic32/fubarino-uart-sramc/FUBARINO-UART-SRAMC b/sys/pic32/fubarino-uart-sramc/FUBARINO-UART-SRAMC new file mode 100644 index 0000000..b5eb177 --- /dev/null +++ b/sys/pic32/fubarino-uart-sramc/FUBARINO-UART-SRAMC @@ -0,0 +1,17 @@ +# Fubarino SD with UART 2 enabled, USB console and SRAMC + +core pic32mx7 +mapping fubarino +linker bootloader + +option PARTITION=sramc0:sa@1500,fs@2572 + +device kernel cpu_khz=80000 bus_khz=80000 invled=6 +device console device=tty1 +device uart2 baud=115200 +device sd0 port=2 cs=SS +device adc +device glcd +device oc +device gpio +device sramc data=16 lda=5 rd=15 wr=14 diff --git a/sys/pic32/fubarino-uart-sramc/Makefile b/sys/pic32/fubarino-uart-sramc/Makefile new file mode 100644 index 0000000..78842df --- /dev/null +++ b/sys/pic32/fubarino-uart-sramc/Makefile @@ -0,0 +1,76 @@ +BUILDPATH = ../../../tools/configsys/../../sys/pic32 +H = ../../../tools/configsys/../../sys/include +M = ../../../tools/configsys/../../sys/pic32 +S = ../../../tools/configsys/../../sys/kernel + +vpath %.c $(M):$(S) +vpath %.S $(M):$(S) + +KERNOBJ += _startup.o adc.o clock.o cons.o devcfg.o devsw.o exception.o glcd.o gpio.o init_main.o init_sysent.o kern_clock.o kern_descrip.o kern_exec.o kern_exit.o kern_fork.o kern_mman.o kern_proc.o kern_prot.o kern_prot2.o kern_resource.o kern_sig.o kern_sig2.o kern_subr.o kern_synch.o kern_sysctl.o kern_time.o machdep.o mem.o oc.o rd_sd.o rd_sramc.o rdisk.o signal.o spi_bus.o subr_prf.o subr_rmap.o swap.o sys_generic.o sys_inode.o sys_pipe.o sys_process.o syscalls.o sysctl.o tty.o tty_subr.o tty_tty.o uart.o ufs_alloc.o ufs_bio.o ufs_bmap.o ufs_dsort.o ufs_fio.o ufs_inode.o ufs_mount.o ufs_namei.o ufs_subr.o ufs_syscalls.o ufs_syscalls2.o vers.o vfs_vnops.o vm_sched.o vm_swap.o vm_swp.o +EXTRA_TARGETS = + +DEFS += -DADC_ENABLED=YES +DEFS += -DBUS_DIV=1 +DEFS += -DBUS_KHZ=80000 +DEFS += -DCONSOLE_DEVICE=tty1 +DEFS += -DCPU_IDIV=2 +DEFS += -DCPU_KHZ=80000 +DEFS += -DCPU_MUL=20 +DEFS += -DCPU_ODIV=1 +DEFS += -DCRYSTAL=8 +DEFS += -DDC0_DEBUG=DEVCFG0_DEBUG_DISABLED +DEFS += -DDC0_ICE=0 +DEFS += -DDC1_CKM=0 +DEFS += -DDC1_CKS=0 +DEFS += -DDC1_FNOSC=DEVCFG1_FNOSC_PRIPLL +DEFS += -DDC1_IESO=DEVCFG1_IESO +DEFS += -DDC1_OSCIOFNC=0 +DEFS += -DDC1_PBDIV=DEVCFG1_FPBDIV_1 +DEFS += -DDC1_POSCMOD=DEVCFG1_POSCMOD_HS +DEFS += -DDC1_SOSC=0 +DEFS += -DDC1_WDTEN=0 +DEFS += -DDC1_WDTPS=DEVCFG1_WDTPS_1 +DEFS += -DDC2_PLLIDIV=DEVCFG2_FPLLIDIV_2 +DEFS += -DDC2_PLLMUL=DEVCFG2_FPLLMUL_20 +DEFS += -DDC2_PLLODIV=DEVCFG2_FPLLODIV_1 +DEFS += -DDC2_UPLL=0 +DEFS += -DDC2_UPLLIDIV=DEVCFG2_UPLLIDIV_2 +DEFS += -DDC3_CAN=DEVCFG3_FCANIO +DEFS += -DDC3_ETH=DEVCFG3_FETHIO +DEFS += -DDC3_MII=DEVCFG3_FMIIEN +DEFS += -DDC3_SRS=DEVCFG3_FSRSSEL_7 +DEFS += -DDC3_USBID=DEVCFG3_FUSBIDIO +DEFS += -DDC3_USERID=0xffff +DEFS += -DDC3_VBUSON=DEVCFG3_FVBUSONIO +DEFS += -DGLCD_ENABLED=YES +DEFS += -DGPIO_ENABLED=YES +DEFS += -DKERNEL +DEFS += -DLED_KERNEL_INVERT=YES +DEFS += -DLED_KERNEL_PIN=14 +DEFS += -DLED_KERNEL_PORT=TRISC +DEFS += -DOC_ENABLED=YES +DEFS += -DPARTITION="sramc0:sa@1500,fs@2572" +DEFS += -DPIC32MX7 +DEFS += -DSD0_CS_PIN=9 +DEFS += -DSD0_CS_PORT=TRISG +DEFS += -DSD0_PORT=2 +DEFS += -DSRAMC_ENABLED=YES +DEFS += -DSW_DATA_PIN=0 +DEFS += -DSW_DATA_PORT=TRISE +DEFS += -DSW_LDA_PIN=13 +DEFS += -DSW_LDA_PORT=TRISC +DEFS += -DSW_RD_PIN=1 +DEFS += -DSW_RD_PORT=TRISF +DEFS += -DSW_WR_PIN=0 +DEFS += -DSW_WR_PORT=TRISF +DEFS += -DUART2_BAUD=115200 +DEFS += -DUART2_ENABLED=YES +DEFS += -DUCB_METER + + +LDSCRIPT = ../../../tools/configsys/../../sys/pic32/cfg/bootloader.ld + +CONFIG = FUBARINO-UART-SRAMC +CONFIGPATH = ../../../tools/configsys + +include ../../../tools/configsys/../../sys/pic32/kernel-post.mk diff --git a/sys/pic32/fubarino-uart-sramc/Makefile.local b/sys/pic32/fubarino-uart-sramc/Makefile.local new file mode 100644 index 0000000..b41e48b --- /dev/null +++ b/sys/pic32/fubarino-uart-sramc/Makefile.local @@ -0,0 +1,50 @@ + + +# CPU frequency 80 MHz. +DEFS += -DCPU_KHZ=80000 +DEFS += -DBUS_KHZ=80000 + +DEFS += -DSRAMC_ENABLED + +DEFS += -DPARTITION="sramc0:sa@1500,fs@2572" + +#DEFS += -DROOT='makedev(0,1)' +#DEFS += -DSWAP='makedev(0,2)' + +# +# Fubarino SD board +# ================= +# +# Console on UART2 +DEFS += -DCONSOLE_UART2 -DCONSOLE_BAUD=115200 + +# SD/MMC card driver on SPI2 +# /CS0 at pin G9 +DEFS += -DSD0_PORT=2 +DEFS += -DSD0_CS_PORT=TRISG -DSD0_CS_PIN=9 + +# LED at pin C14 +DEFS += -DLED_KERNEL_PORT=TRISC -DLED_KERNEL_PIN=14 -DLED_KERNEL_INVERT + +# Swap on external device, 2 Mbytes +# data at E0-E7 +# rd at F1 +# wr at F0 +# ldaddr at C13 +DEFS += -DSWAPDEV=0x0100 -DSWAPSZ=2048 +DEFS += -DSW_DATA_PORT=TRISE -DSW_DATA_PIN=0 +DEFS += -DSW_RD_PORT=TRISF -DSW_RD_PIN=1 +DEFS += -DSW_WR_PORT=TRISF -DSW_WR_PIN=0 +DEFS += -DSW_LDA_PORT=TRISC -DSW_LDA_PIN=13 + +# Include or exclude drivers +DRIVER_GPIO = yes +# General Purpose I/O +DRIVER_ADC = yes +# Basic ADC interface +DRIVER_SPI = yes +# Generic SPI interface +DRIVER_OC = yes +# Output Compare driver + + diff --git a/sys/pic32/fubarino-uart-sramc/Makefile_old b/sys/pic32/fubarino-uart-sramc/Makefile_old new file mode 100644 index 0000000..66503f0 --- /dev/null +++ b/sys/pic32/fubarino-uart-sramc/Makefile_old @@ -0,0 +1,144 @@ +H = ../../include +M = .. +S = ../../kernel + +vpath %.c $(M):$(S) +vpath %.S $(M):$(S) + +# Kernel options. +DEFS += -I. -I$(H) -DKERNEL -DUCB_METER -DPIC32MX7 + +# CPU frequency 80 MHz. +DEFS += -DCPU_KHZ=80000 +DEFS += -DBUS_KHZ=80000 + +DEFS += -DSRAMC_ENABLED + +DEFS += -DPARTITION="sramc0:sa@1500,fs@2572" + +#DEFS += -DROOT='makedev(0,1)' +#DEFS += -DSWAP='makedev(0,2)' + +# +# Fubarino SD board +# ================= +# +# Console on UART2 +DEFS += -DCONSOLE_UART2 -DCONSOLE_BAUD=115200 + +# SD/MMC card driver on SPI2 +# /CS0 at pin G9 +DEFS += -DSD0_PORT=2 +DEFS += -DSD0_CS_PORT=TRISG -DSD0_CS_PIN=9 + +# LED at pin E5 +DEFS += -DLED_KERNEL_PORT=TRISC -DLED_KERNEL_PIN=14 -DLED_KERNEL_INVERT + +# Swap on external device, 2 Mbytes +# data at E0-E7 +# rd at F0 +# wr at F1 +# ldaddr at G9 +DEFS += -DSWAPDEV=0x0100 -DSWAPSZ=2048 +DEFS += -DSW_DATA_PORT=TRISE -DSW_DATA_PIN=0 +DEFS += -DSW_RD_PORT=TRISF -DSW_RD_PIN=1 +DEFS += -DSW_WR_PORT=TRISF -DSW_WR_PIN=0 +DEFS += -DSW_LDA_PORT=TRISC -DSW_LDA_PIN=13 + +# Include or exclude drivers +DRIVER_GPIO = yes +# General Purpose I/O +DRIVER_ADC = yes +# Basic ADC interface +DRIVER_SPI = yes +# Generic SPI interface +DRIVER_OC = yes +# Output Compare driver + +DEPFLAGS = -MT $@ -MD -MP -MF .deps/$*.dep +CFLAGS = -O $(DEFS) $(DEPFLAGS) +ASFLAGS = $(DEFS) $(DEPFLAGS) + +include ../gcc-config.mk + +CC = $(GCCPREFIX)gcc -EL -g -mips32r2 +CC += -nostdinc -fno-builtin -Werror -Wall -fno-dwarf2-cfi-asm +LDFLAGS += -nostdlib -T using-bootloader.ld -Wl,-Map=unix.map +SIZE = $(GCCPREFIX)size +OBJDUMP = $(GCCPREFIX)objdump +OBJCOPY = $(GCCPREFIX)objcopy +PROGTOOL = $(AVRDUDE) -c stk500v2 -p pic32 -b 115200 + +# Machine-dependent files: +# startup.o MUST be loaded first. +KERNOBJ = startup.o clock.o devsw.o sysctl.o \ + signal.o machdep.o mem.o exception.o + +KERNOBJ += cons.o rd_sramc.o + +# Kernel. +KERNOBJ += init_main.o init_sysent.o kern_clock.o \ + kern_descrip.o kern_exec.o kern_exit.o kern_fork.o \ + kern_mman.o kern_proc.o kern_prot.o \ + kern_prot2.o kern_resource.o kern_sig.o kern_sig2.o \ + kern_subr.o kern_synch.o kern_sysctl.o kern_time.o \ + subr_log.o subr_prf.o subr_rmap.o \ + sys_generic.o sys_inode.o syscalls.o \ + sys_pipe.o sys_process.o tty.o tty_conf.o \ + tty_subr.o tty_tty.o ufs_alloc.o ufs_bio.o \ + ufs_bmap.o ufs_dsort.o ufs_fio.o \ + ufs_inode.o ufs_mount.o ufs_namei.o ufs_subr.o \ + ufs_syscalls.o ufs_syscalls2.o vfs_vnops.o \ + vm_sched.o vm_swap.o vm_swp.o kern_glob.o swap.o spi_bus.o + +# Drivers. +KERNOBJ += rdisk.o rd_sd.o + +# Configuration-dependent files. +KERNOBJ += vers.o + +# Include any local specific configuration overrides +-include Makefile.local + +# This makefile does the work including the right files and options for the drivers +include ../drivers.mk + +all: .deps sys machine unix.elf + $(SIZE) unix.elf + +clean: + rm -rf .deps *.o *.elf *.bin *.dis *.map *.srec core \ + mklog assym.h vers.c genassym sys machine + +.deps: + mkdir .deps + +sys: + ln -s ../../include $@ + +machine: + ln -s .. $@ + +unix.elf: $(KERNOBJ) using-bootloader.ld + $(CC) $(LDFLAGS) $(KERNOBJ) -o $@ + chmod -x $@ + $(OBJDUMP) -d -S $@ > unix.dis + $(OBJCOPY) -O binary $@ unix.bin + $(OBJCOPY) -O ihex --change-addresses=0x80000000 $@ unix.hex + chmod -x $@ unix.bin + +load: unix.hex + pic32prog unix.hex + +vers.o: ../newvers.sh $(H)/*.h $(M)/*.[ch] $(S)/*.c + sh ../newvers.sh > vers.c + $(CC) -c vers.c + +.SUFFIXES: .i .srec .hex .dis .cpp .cxx .bin .elf + +.o.dis: + $(OBJDUMP) -d -z -S $< > $@ + +ifeq (.deps, $(wildcard .deps)) +-include .deps/*.dep +endif diff --git a/sys/pic32/fubarino-uart-sramc/using-bootloader.ld b/sys/pic32/fubarino-uart-sramc/using-bootloader.ld new file mode 100644 index 0000000..0401b09 --- /dev/null +++ b/sys/pic32/fubarino-uart-sramc/using-bootloader.ld @@ -0,0 +1,114 @@ +/* + * Linker script for PIC32 firmware using RetroBSD bootloader. + */ +OUTPUT_FORMAT("elf32-littlemips", "elf32-bigmips", + "elf32-littlemips") +OUTPUT_ARCH(mips) +ENTRY(_reset_vector_) +MEMORY +{ + flash (rx) : ORIGIN = 0x9d000000, LENGTH = 512K + ram (rw!x): ORIGIN = 0x80000000, LENGTH = 26K + u0area (rw!x): ORIGIN = 0x80006800, LENGTH = 3K + uarea (rw!x): ORIGIN = 0x80007400, LENGTH = 3K + + /* Required by Microchip C32 linker */ + kseg0_program_mem (rx) : ORIGIN = 0x9D000000, LENGTH = 0x80000 + kseg0_boot_mem : ORIGIN = 0x9FC00000, LENGTH = 0x1000 + exception_mem : ORIGIN = 0x9FC00000, LENGTH = 0x1000 + kseg1_boot_mem : ORIGIN = 0xBFC00000, LENGTH = 0 + kseg1_data_mem (w!x) : ORIGIN = 0xA0000000, LENGTH = 0x20000 +} + +/* higher address of the user mode stack */ +u0 = ORIGIN(u0area); +u = ORIGIN(uarea); +u_end = ORIGIN(uarea) + LENGTH(uarea); + +SECTIONS +{ + .text ORIGIN(flash) : + { + /* Exception handlers. */ + *(.exception) + /* Execution starts here. */ + *(.startup) + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.glue_7t) *(.glue_7) + __rodata_start = . ; + *(.rodata .rodata.* .gnu.linkonce.r.* .rel.dyn) + *(.dinit) + /* Align here to ensure that the .text section ends on word boundary. */ + . = ALIGN (32 / 8); + _etext = .; + } > flash + + /* Start data (internal SRAM). */ + .data : AT (ADDR (.text) + SIZEOF (.text)) + { + __data_start = . ; + _gp = .; /* We use only 32k RAM for kernel, so no need for 0x8000 offset. */ + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + *(.sdata .sdata.* .gnu.linkonce.s.*) + *(.data .data.* .gnu.linkonce.d.*) + *(.eh_frame) + _edata = .; + } > ram + + .bss ADDR (.data) + SIZEOF (.data) (NOLOAD) : + { + __bss_start = .; + *(.dynbss) + *(.sbss) + *(.scommon) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. */ + . = ALIGN (32 / 8); + } > ram + __bss_end = . ; + _end = .; + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + .debug_pubtypes 0 : { *(.debug_pubtypes) } + .debug_ranges 0 : { *(.debug_ranges) } + .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) } +} diff --git a/sys/pic32/fubarino-uart/FUBARINO-UART b/sys/pic32/fubarino-uart/FUBARINO-UART new file mode 100644 index 0000000..3e495c2 --- /dev/null +++ b/sys/pic32/fubarino-uart/FUBARINO-UART @@ -0,0 +1,14 @@ +# Fubarino configuration file + +core pic32mx7 +mapping fubarino +linker bootloader + +device kernel led=21 cpu_khz=80000 bus_khz=80000 +device console device=tty1 +device uart2 baud=115200 +device sd0 port=2 cs=SS +device adc +device glcd +device oc +device gpio diff --git a/sys/pic32/fubarino-uart/Makefile b/sys/pic32/fubarino-uart/Makefile new file mode 100644 index 0000000..de08001 --- /dev/null +++ b/sys/pic32/fubarino-uart/Makefile @@ -0,0 +1,65 @@ +BUILDPATH = ../../../tools/configsys/../../sys/pic32 +H = ../../../tools/configsys/../../sys/include +M = ../../../tools/configsys/../../sys/pic32 +S = ../../../tools/configsys/../../sys/kernel + +vpath %.c $(M):$(S) +vpath %.S $(M):$(S) + +KERNOBJ += _startup.o adc.o clock.o cons.o devcfg.o devsw.o exception.o glcd.o gpio.o init_main.o init_sysent.o kern_clock.o kern_descrip.o kern_exec.o kern_exit.o kern_fork.o kern_mman.o kern_proc.o kern_prot.o kern_prot2.o kern_resource.o kern_sig.o kern_sig2.o kern_subr.o kern_synch.o kern_sysctl.o kern_time.o machdep.o mem.o oc.o rd_sd.o rdisk.o signal.o spi_bus.o subr_prf.o subr_rmap.o swap.o sys_generic.o sys_inode.o sys_pipe.o sys_process.o syscalls.o sysctl.o tty.o tty_subr.o tty_tty.o uart.o ufs_alloc.o ufs_bio.o ufs_bmap.o ufs_dsort.o ufs_fio.o ufs_inode.o ufs_mount.o ufs_namei.o ufs_subr.o ufs_syscalls.o ufs_syscalls2.o vers.o vfs_vnops.o vm_sched.o vm_swap.o vm_swp.o +EXTRA_TARGETS = + +DEFS += -DADC_ENABLED=YES +DEFS += -DBUS_DIV=1 +DEFS += -DBUS_KHZ=80000 +DEFS += -DCONSOLE_DEVICE=tty1 +DEFS += -DCPU_IDIV=2 +DEFS += -DCPU_KHZ=80000 +DEFS += -DCPU_MUL=20 +DEFS += -DCPU_ODIV=1 +DEFS += -DCRYSTAL=8 +DEFS += -DDC0_DEBUG=DEVCFG0_DEBUG_DISABLED +DEFS += -DDC0_ICE=0 +DEFS += -DDC1_CKM=0 +DEFS += -DDC1_CKS=0 +DEFS += -DDC1_FNOSC=DEVCFG1_FNOSC_PRIPLL +DEFS += -DDC1_IESO=DEVCFG1_IESO +DEFS += -DDC1_OSCIOFNC=0 +DEFS += -DDC1_PBDIV=DEVCFG1_FPBDIV_1 +DEFS += -DDC1_POSCMOD=DEVCFG1_POSCMOD_HS +DEFS += -DDC1_SOSC=0 +DEFS += -DDC1_WDTEN=0 +DEFS += -DDC1_WDTPS=DEVCFG1_WDTPS_1 +DEFS += -DDC2_PLLIDIV=DEVCFG2_FPLLIDIV_2 +DEFS += -DDC2_PLLMUL=DEVCFG2_FPLLMUL_20 +DEFS += -DDC2_PLLODIV=DEVCFG2_FPLLODIV_1 +DEFS += -DDC2_UPLL=0 +DEFS += -DDC2_UPLLIDIV=DEVCFG2_UPLLIDIV_2 +DEFS += -DDC3_CAN=DEVCFG3_FCANIO +DEFS += -DDC3_ETH=DEVCFG3_FETHIO +DEFS += -DDC3_MII=DEVCFG3_FMIIEN +DEFS += -DDC3_SRS=DEVCFG3_FSRSSEL_7 +DEFS += -DDC3_USBID=DEVCFG3_FUSBIDIO +DEFS += -DDC3_USERID=0xffff +DEFS += -DDC3_VBUSON=DEVCFG3_FVBUSONIO +DEFS += -DGLCD_ENABLED=YES +DEFS += -DGPIO_ENABLED=YES +DEFS += -DKERNEL +DEFS += -DLED_KERNEL_PIN=5 +DEFS += -DLED_KERNEL_PORT=TRISE +DEFS += -DOC_ENABLED=YES +DEFS += -DPIC32MX7 +DEFS += -DSD0_CS_PIN=9 +DEFS += -DSD0_CS_PORT=TRISG +DEFS += -DSD0_PORT=2 +DEFS += -DUART2_BAUD=115200 +DEFS += -DUART2_ENABLED=YES +DEFS += -DUCB_METER + + +LDSCRIPT = ../../../tools/configsys/../../sys/pic32/cfg/bootloader.ld + +CONFIG = FUBARINO-UART +CONFIGPATH = ../../../tools/configsys + +include ../../../tools/configsys/../../sys/pic32/kernel-post.mk diff --git a/sys/pic32/fubarino-uart/using-bootloader.ld b/sys/pic32/fubarino-uart/using-bootloader.ld new file mode 100644 index 0000000..0401b09 --- /dev/null +++ b/sys/pic32/fubarino-uart/using-bootloader.ld @@ -0,0 +1,114 @@ +/* + * Linker script for PIC32 firmware using RetroBSD bootloader. + */ +OUTPUT_FORMAT("elf32-littlemips", "elf32-bigmips", + "elf32-littlemips") +OUTPUT_ARCH(mips) +ENTRY(_reset_vector_) +MEMORY +{ + flash (rx) : ORIGIN = 0x9d000000, LENGTH = 512K + ram (rw!x): ORIGIN = 0x80000000, LENGTH = 26K + u0area (rw!x): ORIGIN = 0x80006800, LENGTH = 3K + uarea (rw!x): ORIGIN = 0x80007400, LENGTH = 3K + + /* Required by Microchip C32 linker */ + kseg0_program_mem (rx) : ORIGIN = 0x9D000000, LENGTH = 0x80000 + kseg0_boot_mem : ORIGIN = 0x9FC00000, LENGTH = 0x1000 + exception_mem : ORIGIN = 0x9FC00000, LENGTH = 0x1000 + kseg1_boot_mem : ORIGIN = 0xBFC00000, LENGTH = 0 + kseg1_data_mem (w!x) : ORIGIN = 0xA0000000, LENGTH = 0x20000 +} + +/* higher address of the user mode stack */ +u0 = ORIGIN(u0area); +u = ORIGIN(uarea); +u_end = ORIGIN(uarea) + LENGTH(uarea); + +SECTIONS +{ + .text ORIGIN(flash) : + { + /* Exception handlers. */ + *(.exception) + /* Execution starts here. */ + *(.startup) + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.glue_7t) *(.glue_7) + __rodata_start = . ; + *(.rodata .rodata.* .gnu.linkonce.r.* .rel.dyn) + *(.dinit) + /* Align here to ensure that the .text section ends on word boundary. */ + . = ALIGN (32 / 8); + _etext = .; + } > flash + + /* Start data (internal SRAM). */ + .data : AT (ADDR (.text) + SIZEOF (.text)) + { + __data_start = . ; + _gp = .; /* We use only 32k RAM for kernel, so no need for 0x8000 offset. */ + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + *(.sdata .sdata.* .gnu.linkonce.s.*) + *(.data .data.* .gnu.linkonce.d.*) + *(.eh_frame) + _edata = .; + } > ram + + .bss ADDR (.data) + SIZEOF (.data) (NOLOAD) : + { + __bss_start = .; + *(.dynbss) + *(.sbss) + *(.scommon) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. */ + . = ALIGN (32 / 8); + } > ram + __bss_end = . ; + _end = .; + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + .debug_pubtypes 0 : { *(.debug_pubtypes) } + .debug_ranges 0 : { *(.debug_ranges) } + .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) } +} diff --git a/sys/pic32/fubarino/FUBARINO b/sys/pic32/fubarino/FUBARINO new file mode 100644 index 0000000..bb6bb88 --- /dev/null +++ b/sys/pic32/fubarino/FUBARINO @@ -0,0 +1,16 @@ +# Fubarino configuration file + +core pic32mx7 +mapping fubarino +linker bootloader + +device kernel led=21 cpu_khz=80000 bus_khz=80000 +device console device=ttyUSB0 +device uartusb +device sd0 port=2 cs=SS +device adc +device glcd +device oc +device gpio + +device bootloader led=21 button=23 crystal=8 jump=0x9d000000 diff --git a/sys/pic32/fubarino/Makefile b/sys/pic32/fubarino/Makefile new file mode 100644 index 0000000..53cc266 --- /dev/null +++ b/sys/pic32/fubarino/Makefile @@ -0,0 +1,79 @@ +BUILDPATH = ../../../tools/configsys/../../sys/pic32 +H = ../../../tools/configsys/../../sys/include +M = ../../../tools/configsys/../../sys/pic32 +S = ../../../tools/configsys/../../sys/kernel + +vpath %.c $(M):$(S) +vpath %.S $(M):$(S) + +KERNOBJ += _startup.o adc.o clock.o cons.o devsw.o exception.o glcd.o gpio.o init_main.o init_sysent.o kern_clock.o kern_descrip.o kern_exec.o kern_exit.o kern_fork.o kern_mman.o kern_proc.o kern_prot.o kern_prot2.o kern_resource.o kern_sig.o kern_sig2.o kern_subr.o kern_synch.o kern_sysctl.o kern_time.o machdep.o mem.o oc.o rd_sd.o rdisk.o signal.o spi_bus.o subr_prf.o subr_rmap.o swap.o sys_generic.o sys_inode.o sys_pipe.o sys_process.o syscalls.o sysctl.o tty.o tty_subr.o tty_tty.o ufs_alloc.o ufs_bio.o ufs_bmap.o ufs_dsort.o ufs_fio.o ufs_inode.o ufs_mount.o ufs_namei.o ufs_subr.o ufs_syscalls.o ufs_syscalls2.o usb_device.o usb_function_cdc.o usb_uart.o vers.o vfs_vnops.o vm_sched.o vm_swap.o vm_swp.o +EXTRA_TARGETS = bootloader + +DEFS += -DADC_ENABLED=YES +DEFS += -DBL_BUTTON_PIN=7 +DEFS += -DBL_BUTTON_PORT=TRISE +DEFS += -DBL_CRYSTAL=8 +DEFS += -DBL_LED_PIN=5 +DEFS += -DBL_LED_PORT=TRISE +DEFS += -DBUS_DIV=1 +DEFS += -DBUS_KHZ=80000 +DEFS += -DCONSOLE_DEVICE=ttyUSB0 +DEFS += -DCPU_IDIV=2 +DEFS += -DCPU_KHZ=80000 +DEFS += -DCPU_MUL=20 +DEFS += -DCPU_ODIV=1 +DEFS += -DCRYSTAL=8 +DEFS += -DDC0_DEBUG=DEVCFG0_DEBUG_DISABLED +DEFS += -DDC0_ICE=0 +DEFS += -DDC1_CKM=0 +DEFS += -DDC1_CKS=0 +DEFS += -DDC1_FNOSC=DEVCFG1_FNOSC_PRIPLL +DEFS += -DDC1_IESO=DEVCFG1_IESO +DEFS += -DDC1_OSCIOFNC=0 +DEFS += -DDC1_PBDIV=DEVCFG1_FPBDIV_1 +DEFS += -DDC1_POSCMOD=DEVCFG1_POSCMOD_HS +DEFS += -DDC1_SOSC=0 +DEFS += -DDC1_WDTEN=0 +DEFS += -DDC1_WDTPS=DEVCFG1_WDTPS_1 +DEFS += -DDC2_PLLIDIV=DEVCFG2_FPLLIDIV_2 +DEFS += -DDC2_PLLMUL=DEVCFG2_FPLLMUL_20 +DEFS += -DDC2_PLLODIV=DEVCFG2_FPLLODIV_1 +DEFS += -DDC2_UPLL=0 +DEFS += -DDC2_UPLLIDIV=DEVCFG2_UPLLIDIV_2 +DEFS += -DDC3_CAN=DEVCFG3_FCANIO +DEFS += -DDC3_ETH=DEVCFG3_FETHIO +DEFS += -DDC3_MII=DEVCFG3_FMIIEN +DEFS += -DDC3_SRS=DEVCFG3_FSRSSEL_7 +DEFS += -DDC3_USBID=DEVCFG3_FUSBIDIO +DEFS += -DDC3_USERID=0xffff +DEFS += -DDC3_VBUSON=DEVCFG3_FVBUSONIO +DEFS += -DFLASH_JUMP=0x9d000000 +DEFS += -DGLCD_ENABLED=YES +DEFS += -DGPIO_ENABLED=YES +DEFS += -DHID_FEATURE_REPORT_BYTES=2 +DEFS += -DHID_INPUT_REPORT_BYTES=2 +DEFS += -DHID_INT_IN_EP_SIZE=64 +DEFS += -DHID_INT_OUT_EP_SIZE=64 +DEFS += -DHID_OUTPUT_REPORT_BYTES=2 +DEFS += -DHID_RPT01_SIZE=29 +DEFS += -DKERNEL +DEFS += -DLED_KERNEL_PIN=5 +DEFS += -DLED_KERNEL_PORT=TRISE +DEFS += -DOC_ENABLED=YES +DEFS += -DPIC32MX7 +DEFS += -DSD0_CS_PIN=9 +DEFS += -DSD0_CS_PORT=TRISG +DEFS += -DSD0_PORT=2 +DEFS += -DUARTUSB_ENABLED=YES +DEFS += -DUCB_METER +DEFS += -DUSB_EP0_BUFF_SIZE=8 +DEFS += -DUSB_MAX_EP_NUMBER=3 +DEFS += -DUSB_NUM_STRING_DESCRIPTORS=3 + + +LDSCRIPT = ../../../tools/configsys/../../sys/pic32/cfg/bootloader.ld + +CONFIG = FUBARINO +CONFIGPATH = ../../../tools/configsys + +include ../../../tools/configsys/../../sys/pic32/kernel-post.mk diff --git a/sys/pic32/fubarino/using-bootloader.ld b/sys/pic32/fubarino/using-bootloader.ld new file mode 100644 index 0000000..8d2d334 --- /dev/null +++ b/sys/pic32/fubarino/using-bootloader.ld @@ -0,0 +1,114 @@ +/* + * Linker script for PIC32 firmware using RetroBSD bootloader. + */ +OUTPUT_FORMAT("elf32-littlemips", "elf32-bigmips", + "elf32-littlemips") +OUTPUT_ARCH(mips) +ENTRY(_reset_vector_) +MEMORY +{ + flash (rx) : ORIGIN = 0x9d000000, LENGTH = 512K + ram (rw!x): ORIGIN = 0x80000000, LENGTH = 26K + u0area (rw!x): ORIGIN = 0x80006800, LENGTH = 3K + uarea (rw!x): ORIGIN = 0x80007400, LENGTH = 3K + + /* Required by Microchip C32 linker */ + kseg0_program_mem (rx) : ORIGIN = 0x9D000000, LENGTH = 0x80000 + kseg0_boot_mem : ORIGIN = 0x9FC00000, LENGTH = 0x1000 + exception_mem : ORIGIN = 0x9FC00000, LENGTH = 0x1000 + kseg1_boot_mem : ORIGIN = 0xBFC00000, LENGTH = 0 + kseg1_data_mem (w!x) : ORIGIN = 0xA0000000, LENGTH = 0x20000 +} + +/* higher address of the user mode stack */ +u0 = ORIGIN(u0area); +u = ORIGIN(uarea); +u_end = ORIGIN(uarea) + LENGTH(uarea); + +SECTIONS +{ + .text ORIGIN(flash) : + { + /* Exception handlers. */ + *(.exception) + /* Execution starts here. */ + *(.startup) + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.glue_7t) *(.glue_7) + __rodata_start = . ; + *(.rodata .rodata.* .gnu.linkonce.r.* .rel.dyn) + *(.dinit) + /* Align here to ensure that the .text section ends on word boundary. */ + . = ALIGN (32 / 8); + _etext = .; + } > flash + + /* Start data (internal SRAM). */ + .data : AT (ADDR (.text) + SIZEOF (.text)) + { + __data_start = . ; + _gp = .; /* We use only 32k RAM for kernel, so no need for 0x8000 offset. */ + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + *(.sdata .sdata.* .gnu.linkonce.s.*) + *(.data .data.* .gnu.linkonce.d.*) + *(.eh_frame) + _edata = .; + } > ram + + .bss ADDR (.data) + SIZEOF (.data) (NOLOAD) : + { + __bss_start = .; + *(.dynbss) + *(.sbss .sbss.*) + *(.scommon) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. */ + . = ALIGN (32 / 8); + } > ram + __bss_end = . ; + _end = .; + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + .debug_pubtypes 0 : { *(.debug_pubtypes) } + .debug_ranges 0 : { *(.debug_ranges) } + .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) } +} diff --git a/sys/pic32/gcc-config.mk b/sys/pic32/gcc-config.mk new file mode 100644 index 0000000..aae0bcb --- /dev/null +++ b/sys/pic32/gcc-config.mk @@ -0,0 +1,35 @@ +# chipKIT PIC32 compiler on Linux +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Download from https://github.com/jasonkajita/chipKIT-cxx/downloads +# and unzip to /usr/local. +# Need to copy pic32-tools/pic32mx/include/stdarg.h +# to pic32-tools/lib/gcc/pic32mx/4.5.1/include. +# MPLABX C32 compiler doesn't support some functionality +# we need, so use chipKIT compiler by default. +ifndef GCCPREFIX + GCCPREFIX = /usr/local/pic32-tools/bin/pic32- + LDFLAGS = -Wl,--oformat=elf32-tradlittlemips +endif + +# Generic MIPS toolchain +# ~~~~~~~~~~~~~~~~~~~~~~ +# You can build it from sources, as described on page +# http://retrobsd.org/wiki/doku.php/doc/toolchain-mips +ifndef GCCPREFIX + GCCPREFIX = /usr/local/mips-gcc-4.7.2/bin/mips-elf- + LDFLAGS = +endif + +# chipKIT MPIDE on Mac OS X +ifneq (,$(wildcard /Applications/Mpide.app/Contents/Resources/Java/hardware/tools/avr)) + AVRDUDE = /Applications/Mpide.app/Contents/Resources/Java/hardware/tools/avr/bin/avrdude \ + -C /Applications/Mpide.app/Contents/Resources/Java/hardware/tools/avr/etc/avrdude.conf \ + -P /dev/tty.usbserial-* +endif + +# chipKIT MPIDE on Linux +ifneq (,$(wildcard /opt/mpide-0023-linux-20120903/hardware/tools/avrdude)) + AVRDUDE = /opt/mpide-0023-linux-20120903/hardware/tools/avrdude \ + -C /opt/mpide-0023-linux-20120903/hardware/tools/avrdude.conf \ + -P /dev/ttyUSB0 +endif diff --git a/sys/pic32/glcd.c b/sys/pic32/glcd.c new file mode 100644 index 0000000..57007ca --- /dev/null +++ b/sys/pic32/glcd.c @@ -0,0 +1,683 @@ +/* + * Graphical GLCD driver for PIC32. + * + * Copyright (C) 2012 Majenko Technologies + * + * 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 the copyright notice and this + * permission notice and warranty disclaimer appear in supporting + * documentation, and that the name of the author not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * + * The author disclaim all warranties with regard to this + * software, including all implied warranties of merchantability + * and fitness. In no event shall the author 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. + */ +#include "param.h" +#include "conf.h" +#include "user.h" +#include "ioctl.h" +#include "systm.h" +#include "sys/uio.h" +#include "glcd.h" +#include "debug.h" + +const struct devspec glcddevs[] = { + { 0, "glcd0" }, + { 0, 0 } +}; + +#define _BC(R,B) (R &= ~(1< + 0x02, 0x01, 0x51, 0x09, 0x06,// ? + 0x32, 0x49, 0x79, 0x41, 0x3E,// @ + 0x7E, 0x11, 0x11, 0x11, 0x7E,// A + 0x7F, 0x49, 0x49, 0x49, 0x36,// B + 0x3E, 0x41, 0x41, 0x41, 0x22,// C + 0x7F, 0x41, 0x41, 0x22, 0x1C,// D + 0x7F, 0x49, 0x49, 0x49, 0x41,// E + 0x7F, 0x09, 0x09, 0x01, 0x01,// F + 0x3E, 0x41, 0x41, 0x51, 0x32,// G + 0x7F, 0x08, 0x08, 0x08, 0x7F,// H + 0x00, 0x41, 0x7F, 0x41, 0x00,// I + 0x20, 0x40, 0x41, 0x3F, 0x01,// J + 0x7F, 0x08, 0x14, 0x22, 0x41,// K + 0x7F, 0x40, 0x40, 0x40, 0x40,// L + 0x7F, 0x02, 0x04, 0x02, 0x7F,// M + 0x7F, 0x04, 0x08, 0x10, 0x7F,// N + 0x3E, 0x41, 0x41, 0x41, 0x3E,// O + 0x7F, 0x09, 0x09, 0x09, 0x06,// P + 0x3E, 0x41, 0x51, 0x21, 0x5E,// Q + 0x7F, 0x09, 0x19, 0x29, 0x46,// R + 0x46, 0x49, 0x49, 0x49, 0x31,// S + 0x01, 0x01, 0x7F, 0x01, 0x01,// T + 0x3F, 0x40, 0x40, 0x40, 0x3F,// U + 0x1F, 0x20, 0x40, 0x20, 0x1F,// V + 0x7F, 0x20, 0x18, 0x20, 0x7F,// W + 0x63, 0x14, 0x08, 0x14, 0x63,// X + 0x03, 0x04, 0x78, 0x04, 0x03,// Y + 0x61, 0x51, 0x49, 0x45, 0x43,// Z + 0x00, 0x00, 0x7F, 0x41, 0x41,// [ + 0x02, 0x04, 0x08, 0x10, 0x20,// "\" + 0x41, 0x41, 0x7F, 0x00, 0x00,// ] + 0x04, 0x02, 0x01, 0x02, 0x04,// ^ + 0x40, 0x40, 0x40, 0x40, 0x40,// _ + 0x00, 0x01, 0x02, 0x04, 0x00,// ` + 0x20, 0x54, 0x54, 0x54, 0x78,// a + 0x7F, 0x48, 0x44, 0x44, 0x38,// b + 0x38, 0x44, 0x44, 0x44, 0x20,// c + 0x38, 0x44, 0x44, 0x48, 0x7F,// d + 0x38, 0x54, 0x54, 0x54, 0x18,// e + 0x08, 0x7E, 0x09, 0x01, 0x02,// f + 0x08, 0x14, 0x54, 0x54, 0x3C,// g + 0x7F, 0x08, 0x04, 0x04, 0x78,// h + 0x00, 0x44, 0x7D, 0x40, 0x00,// i + 0x20, 0x40, 0x44, 0x3D, 0x00,// j + 0x00, 0x7F, 0x10, 0x28, 0x44,// k + 0x00, 0x41, 0x7F, 0x40, 0x00,// l + 0x7C, 0x04, 0x18, 0x04, 0x78,// m + 0x7C, 0x08, 0x04, 0x04, 0x78,// n + 0x38, 0x44, 0x44, 0x44, 0x38,// o + 0x7C, 0x14, 0x14, 0x14, 0x08,// p + 0x08, 0x14, 0x14, 0x18, 0x7C,// q + 0x7C, 0x08, 0x04, 0x04, 0x08,// r + 0x48, 0x54, 0x54, 0x54, 0x20,// s + 0x04, 0x3F, 0x44, 0x40, 0x20,// t + 0x3C, 0x40, 0x40, 0x20, 0x7C,// u + 0x1C, 0x20, 0x40, 0x20, 0x1C,// v + 0x3C, 0x40, 0x30, 0x40, 0x3C,// w + 0x44, 0x28, 0x10, 0x28, 0x44,// x + 0x0C, 0x50, 0x50, 0x50, 0x3C,// y + 0x44, 0x64, 0x54, 0x4C, 0x44,// z + 0x00, 0x08, 0x36, 0x41, 0x00,// { + 0x00, 0x00, 0x7F, 0x00, 0x00,// | + 0x00, 0x41, 0x36, 0x08, 0x00,// } + 0x08, 0x08, 0x2A, 0x1C, 0x08,// -> + 0x08, 0x1C, 0x2A, 0x08, 0x08 // <- +}; + +/* + * Devices: + * /dev/glcd + * + * Write to the device outputs to GLCD memory as data. Use ioctl() to send + * comands: + * + * ioctl(fd, GLCD_RESET, 0) - reset the GLCD + * ioctl(fd, GLCD_SET_PAGE, page) - set the page address + * ioctl(fd, GLCD_SET_Y, y) - set the page offset + * + */ + +int abs(int x) +{ + if(x>0) + return x; + return 0-x; +} + +void glcd_delay() +{ + unsigned long c; + for(c=0; c<200; c++) + asm("nop"); +} + +void glcd_write_value(int chip, unsigned char data) +{ + _BC(LAT_RW, PIN_RW); + _BC(TRIS_DB0, PIN_DB0); + _BC(TRIS_DB1, PIN_DB1); + _BC(TRIS_DB2, PIN_DB2); + _BC(TRIS_DB3, PIN_DB3); + _BC(TRIS_DB4, PIN_DB4); + _BC(TRIS_DB5, PIN_DB5); + _BC(TRIS_DB6, PIN_DB6); + _BC(TRIS_DB7, PIN_DB7); + + if(chip==0) + _BS(LAT_CS1, PIN_CS1); + if(chip==1) + _BS(LAT_CS2, PIN_CS2); + + if(data & 0b00000001) + _BS(LAT_DB0, PIN_DB0); + else + _BC(LAT_DB0, PIN_DB0); + + if(data & 0b00000010) + _BS(LAT_DB1, PIN_DB1); + else + _BC(LAT_DB1, PIN_DB1); + + if(data & 0b00000100) + _BS(LAT_DB2, PIN_DB2); + else + _BC(LAT_DB2, PIN_DB2); + + if(data & 0b00001000) + _BS(LAT_DB3, PIN_DB3); + else + _BC(LAT_DB3, PIN_DB3); + + if(data & 0b00010000) + _BS(LAT_DB4, PIN_DB4); + else + _BC(LAT_DB4, PIN_DB4); + + if(data & 0b00100000) + _BS(LAT_DB5, PIN_DB5); + else + _BC(LAT_DB5, PIN_DB5); + + if(data & 0b01000000) + _BS(LAT_DB6, PIN_DB6); + else + _BC(LAT_DB6, PIN_DB6); + + if(data & 0b10000000) + _BS(LAT_DB7, PIN_DB7); + else + _BC(LAT_DB7, PIN_DB7); + + _BS(LAT_E, PIN_E); + glcd_delay(); + _BC(LAT_E, PIN_E); + glcd_delay(); + + if(chip==0) + _BC(LAT_CS1, PIN_CS1); + if(chip==1) + _BC(LAT_CS2, PIN_CS2); +} + +void glcd_write_data(int chip, unsigned char value) +{ + _BS(LAT_DI, PIN_DI); + glcd_write_value(chip,value); +} + +void glcd_write_command(int chip, unsigned char value) +{ + _BC(LAT_DI, PIN_DI); + glcd_write_value(chip,value); +} + +void glcd_init() +{ + _BC(TRIS_DI, PIN_DI); + _BC(TRIS_RW, PIN_RW); + _BC(TRIS_E, PIN_E); + _BC(TRIS_DB0, PIN_DB0); + _BC(TRIS_DB1, PIN_DB1); + _BC(TRIS_DB2, PIN_DB2); + _BC(TRIS_DB3, PIN_DB3); + _BC(TRIS_DB4, PIN_DB4); + _BC(TRIS_DB5, PIN_DB5); + _BC(TRIS_DB6, PIN_DB6); + _BC(TRIS_DB7, PIN_DB7); + _BC(TRIS_CS1, PIN_CS1); + _BC(TRIS_CS2, PIN_CS2); + _BC(TRIS_RES, PIN_RES); + + _BC(LAT_E, PIN_E); + _BC(LAT_CS1, PIN_CS1); + _BC(LAT_CS2, PIN_CS2); + _BS(LAT_RES, PIN_RES); + + glcd_write_command(0,GLCD_CMD_ON); + glcd_write_command(1,GLCD_CMD_ON); + glcd_write_command(0,GLCD_CMD_START); + glcd_write_command(1,GLCD_CMD_START); + +} + +void glcd_reset() +{ + _BC(LAT_RES, PIN_RES); + glcd_delay(); + _BS(LAT_RES, PIN_RES); + glcd_init(); +} + +void glcd_set_page(int chip, int page) +{ + glcd_write_command(chip, GLCD_CMD_SET_PAGE | (page & 0x07)); +} + +void glcd_set_y(int chip, int y) +{ + glcd_write_command(chip, GLCD_CMD_SET_Y | (y & 0x63)); +} + +void glcd_update() +{ + unsigned char x,y; + for(y=0; y<8; y++) + { + glcd_set_page(0,y); + glcd_set_page(1,y); + glcd_set_y(0,0); + glcd_set_y(1,0); + for(x=0; x<64; x++) + { + glcd_write_data(0,screen[y][x]); + glcd_write_data(1,screen[y][x+64]); + } + } +} + +void glcd_cls() +{ + unsigned char x,y; + for(y=0; y<8; y++) + { + for(x=0; x<128; x++) + { + screen[y][x] = 0; + } + } + screen_x = 0; + screen_y = 0; +} + +void glcd_load_page() +{ + screen_x = 0; + screen_y = 0; + mode = MODE_LOAD; +} + +int +glcd_open (dev, flag, mode) + dev_t dev; +{ + int unit = minor(dev); + + if (unit >= 2) + return ENXIO; + if (u.u_uid != 0) + return EPERM; + + glcd_init(); + mode = MODE_TEXT; + DEBUG("glcd%d: Openend\n",unit); + //screen_x = 0; + //screen_y = 0; + return 0; +} + +int glcd_close (dev_t dev, int flag, int mode) +{ + return 0; +} + +int glcd_read (dev_t dev, struct uio *uio, int flag) +{ + // TODO + return ENODEV; +} + +void glcd_scrollUp(void) +{ + unsigned char x,y; + for(y=0; y<9; y++) + { + for(x=0; x<128; x++) + { + screen[y][x] = screen[y][x]>>1; + if(y<8) + screen[y][x] |= (screen[y+1][x]<<7); + } + } +} + +void glcd_putc(char c) +{ + unsigned int cpos; + if(c=='\r') + { + screen_x = 0; + return; + } + + if(c=='\n') + { + screen_y++; + screen_x=0; + if(screen_y>7) + { + screen_y--; + for(cpos=0; cpos<8; cpos++) + glcd_scrollUp(); + } + return; + } + + if(c==0x08) + { + if(screen_x>0) + { + screen_x-=6; + } else { + if(screen_y>0) + { + screen_x = 127-7; + screen_y--; + } + } + return; + } + if(c==0x07) + { + return; + } + if(c==0x0C) + { + glcd_cls(); + glcd_update(); + return; + } + if(screen_x > 127-6) + { + screen_x=0; + screen_y++; + if(screen_y>7) + { + screen_y--; + for(cpos=0; cpos<8; cpos++) + glcd_scrollUp(); + } + } + cpos = (c - ' ') * 5; + screen[screen_y][screen_x++] = font[cpos++]; + screen[screen_y][screen_x++] = font[cpos++]; + screen[screen_y][screen_x++] = font[cpos++]; + screen[screen_y][screen_x++] = font[cpos++]; + screen[screen_y][screen_x++] = font[cpos++]; + screen[screen_y][screen_x++] = 0; +} + +void glcd_setPixel(int x, int y) +{ + unsigned char row; + unsigned char pixel; + unsigned char mask; + + if(x>127) + return; + if(y>63) + return; + if(x<0) + return; + if(y<0) + return; + + row = y>>3; + pixel = y & 0x07; + + mask = 1 << pixel; + + screen[row][x] |= mask; +} + +void glcd_clearPixel(int x, int y) +{ + unsigned char row; + unsigned char pixel; + unsigned char mask; + + if(x>127) + return; + if(y>63) + return; + if(x<0) + return; + if(y<0) + return; + + row = y>>3; + pixel = y & 0x07; + + mask = 1 << pixel; + + screen[row][x] &= ~mask; +} + +void glcd_drawLine(int x, int y, int x2, int y2, unsigned char ink) +{ + int w, h; + int dx1=0, dy1=0, dx2=0, dy2=0; + int longest, shortest; + int numerator; + int i; + + w = x2 - x; + h = y2 - y; + + if(w<0) + { + dx1 = -1; + dx2 = -1; + } + else if(w>0) + { + dx1 = 1; + dx2 = 1; + } + + if(h<0) + dy1 = -1; + else if(h>0) + dy1 = 1; + + longest = abs(w); + shortest = abs(h); + if(!(longest>shortest)) + { + longest = abs(h); + shortest = abs(w); + if(h<0) + dy2 = -1; + else if(h>0) + dy2 = 1; + dx2=0; + } + + numerator = longest >> 1; + for(i=0; i<=longest; i++) + { + if(ink==1) + glcd_setPixel(x,y); + else + glcd_clearPixel(x,y); + numerator += shortest; + if(!(numeratorx1, c->y1); +} + +void glcd_clear_pixel(struct glcd_command *c) +{ + glcd_clearPixel(c->x1, c->y1); +} + +void glcd_draw_line(struct glcd_command *c) +{ + glcd_drawLine(c->x1, c->y1, c->x2, c->y2, c->ink); +} + +void glcd_draw_box(struct glcd_command *c) +{ + glcd_drawLine(c->x1, c->y1, c->x1, c->y2, c->ink); + glcd_drawLine(c->x1, c->y1, c->x2, c->y1, c->ink); + glcd_drawLine(c->x2, c->y2, c->x1, c->y2, c->ink); + glcd_drawLine(c->x2, c->y2, c->x2, c->y1, c->ink); +} + +void glcd_draw_filled_box(struct glcd_command *c) +{ + unsigned char y; + int y1,y2; + if(c->y1 > c->y2) + { + y1 = c->y2; + y2 = c->y1; + } else { + y1 = c->y1; + y2 = c->y2; + } + for(y=y1; y<=y2; y++) + { + glcd_drawLine(c->x1, y, c->x2, y, c->ink); + } +} + +void glcd_goto_xy(struct glcd_command *c) +{ + screen_x = c->x1; + screen_y = c->y1; +} + +int glcd_write (dev_t dev, struct uio *uio, int flag) +{ + struct iovec *iov; + int i; + + iov = uio->uio_iov; + + switch(mode) + { + case MODE_LOAD: + for(i=0; iiov_len; i++) + { + screen[screen_y][screen_x] = *(iov->iov_base+i); + screen_x++; + if(screen_x==128) + { + screen_y++; + if(screen_y==8) + { + mode=MODE_TEXT; + glcd_update(); + } + } + } + break; + case MODE_TEXT: + for(i=0; iiov_len; i++) + { + glcd_putc(*(iov->iov_base+i)); + } + glcd_update(); + break; + } + return 0; +} + +int glcd_ioctl (dev_t dev, register u_int cmd, caddr_t addr, int flag) +{ + if(cmd == GLCD_RESET) { + glcd_reset(); + } + + if(cmd == GLCD_UPDATE) { + glcd_update(); + } + + if(cmd == GLCD_CLS) { + glcd_cls(); + } + + if (cmd == GLCD_LOAD_PAGE) { + glcd_load_page(); + } + + if (cmd == GLCD_SET_PIXEL) { + glcd_set_pixel((struct glcd_command *)addr); + } + + if (cmd == GLCD_CLEAR_PIXEL) { + glcd_clear_pixel((struct glcd_command *)addr); + } + + if (cmd == GLCD_LINE) { + glcd_draw_line((struct glcd_command *)addr); + } + + if (cmd == GLCD_BOX) { + glcd_draw_box((struct glcd_command *)addr); + } + + if (cmd == GLCD_FILLED_BOX) { + glcd_draw_filled_box((struct glcd_command *)addr); + } + + if (cmd == GLCD_GOTO_XY) { + glcd_goto_xy((struct glcd_command *)addr); + } + + return 0; +} diff --git a/sys/pic32/gpio.c b/sys/pic32/gpio.c new file mode 100644 index 0000000..0fe7dd3 --- /dev/null +++ b/sys/pic32/gpio.c @@ -0,0 +1,621 @@ +/* + * GPIO driver for PIC32. + * + * Copyright (C) 2012 Serge Vakulenko, + * + * 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 the copyright notice and this + * permission notice and warranty disclaimer appear in supporting + * documentation, and that the name of the author not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * + * The author disclaim all warranties with regard to this + * software, including all implied warranties of merchantability + * and fitness. In no event shall the author 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. + */ +#include "param.h" +#include "conf.h" +#include "user.h" +#include "ioctl.h" +#include "gpio.h" +#include "systm.h" +#include "uio.h" + +const struct devspec gpiodevs[] = { + { 0, "porta" }, { 1, "portb" }, { 2, "portc" }, { 3, "portd" }, + { 4, "porte" }, { 5, "portf" }, { 6, "portg" }, + + { 64, "confa" }, { 65, "confb" }, { 66, "confc" }, { 67, "confd" }, + { 68, "confe" }, { 69, "conff" }, { 70, "confg" }, + + { 0, 0 } +}; + + +/* + * Devices: + * /dev/porta ... /dev/portg + * /dev/confa ... /dev/confg + * + * Example: + * echo ....oiiid....iiii > /dev/confa + * echo ....1...0........ > /dev/porta + * + * Write to /dev/confX: + * 'i' - configure the corresponding port pin as an input; + * 'o' - configure the corresponding port pin as an output; + * 'd' - configure the corresponding port pin as an open-drain output; + * 'x' - deconfigure the corresponding port pin; + * '.' - no action. + * + * Write to /dev/portX: + * '0' - set output pin low; + * '1' - set output pin high; + * '+' - invert the value of output pin; + * '.' - no action. + * + * Use ioctl() on any of devices to control pins from the user program. + * ioctl(fd, GPIO_PORTA | GPIO_CONFIN, mask) - configure as input + * ioctl(fd, GPIO_PORTB | GPIO_CONFOUT,mask) - configure as output + * ioctl(fd, GPIO_PORTC | GPIO_CONFOD, mask) - configure as open drain + * ioctl(fd, GPIO_PORTD | GPIO_DECONF, mask) - deconfigure + * ioctl(fd, GPIO_PORTE | GPIO_STORE, val) - set values of all pins + * ioctl(fd, GPIO_PORTF | GPIO_SET, mask) - set to 1 by mask + * ioctl(fd, GPIO_PORTG | GPIO_CLEAR, mask) - set to 0 by mask + * ioctl(fd, GPIO_PORT(0)| GPIO_INVERT, mask) - invert by mask + * val= ioctl(fd, GPIO_PORT(1)| GPIO_POLL, 0) - get input values + * + * Several operations can be combined in one call. + * For example, to toggle pin A2 high thew low, and get value + * of all PORTA pins: + * val = ioctl(fd, GPIO_PORTA | GPIO_SET | GPIO_CLEAR | GPIO_POLL, 1<<3); + */ +#define NGPIO 7 /* Ports A, B, C, D, E, F, G */ +#define NPINS 16 /* Number of pins per port */ + +#define MINOR_CONF 0x40 /* Minor mask: /dev/confX */ +#define MINOR_UNIT 0x07 /* Minor mask: unit number */ + +/* + * Some pins are actually not available in hardware. + * Here are masks of real pins. + */ +#define MASK(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p) \ + (a<<15 | b<<14 | c<<13 | d<<12 | e<<11 | f<<10 | g<<9 | h<<8 | \ + i<<7 | j<<6 | k<<5 | l<<4 | m<<3 | n<<2 | o<<1 | p) + +static const u_int gpio_pins_mx7 [NGPIO] = +{ /* Missing pins: */ + MASK (1,1,0,0,0,1,1,0,1,1,1,1,1,1,1,1), /* A8, A11-A13 */ + MASK (1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1), + MASK (1,1,1,1,0,0,0,0,0,0,0,1,1,1,1,0), /* C0, C5-C11 */ + MASK (1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1), + MASK (0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1), /* E10-E15 */ + MASK (0,0,1,1,0,0,0,1,0,0,1,1,1,1,1,1), /* F6-F7, F9-F11, F14-F15 */ + MASK (1,1,1,1,0,0,1,1,1,1,0,0,0,0,1,1), /* G2-G5, G10-G11 */ +}; + +/* + * Mask of configured pins, default empty. + */ +u_int gpio_confmask [NGPIO]; + +/* + * To enable debug output, comment out the first line, + * and uncomment the second line. + */ +#define PRINTDBG(...) /*empty*/ +//#define PRINTDBG printf + +/* + * PIC32 port i/o registers. + */ +struct gpioreg { + volatile unsigned tris; /* Mask of inputs */ + volatile unsigned trisclr; + volatile unsigned trisset; + volatile unsigned trisinv; + volatile unsigned port; /* Read inputs, write outputs */ + volatile unsigned portclr; + volatile unsigned portset; + volatile unsigned portinv; + volatile unsigned lat; /* Read/write outputs */ + volatile unsigned latclr; + volatile unsigned latset; + volatile unsigned latinv; + volatile unsigned odc; /* Open drain configuration */ + volatile unsigned odcclr; + volatile unsigned odcset; + volatile unsigned odcinv; +}; + +/* + * If a port address matches a port number, + * clear a given bit in pin mask. + */ +static u_int +filter_out (mask, portnum, portaddr, pin) + register u_int mask; + u_int portnum; + volatile unsigned *portaddr; +{ + register struct gpioreg *reg = portnum + (struct gpioreg*) &TRISA; + + if ((unsigned) reg == (unsigned) portaddr) + mask &= ~(1 << pin); + return mask; +} + +/* + * Some pins are not available in harsware or used by other drivers. + * Remove them from the mask. + */ +static u_int +gpio_filter (mask, portnum) + u_int mask; + u_int portnum; +{ + mask &= gpio_pins_mx7 [portnum]; + +#ifdef LED_SWAP_PORT + mask = filter_out (mask, portnum, &LED_SWAP_PORT, LED_SWAP_PIN); +#endif +#ifdef LED_DISK_PORT + mask = filter_out (mask, portnum, &LED_DISK_PORT, LED_DISK_PIN); +#endif +#ifdef LED_KERNEL_PORT + mask = filter_out (mask, portnum, &LED_KERNEL_PORT, LED_KERNEL_PIN); +#endif +#ifdef LED_TTY_PORT + mask = filter_out (mask, portnum, &LED_TTY_PORT, LED_TTY_PIN); +#endif +#ifdef SD0_CS_PORT + mask = filter_out (mask, portnum, &SD0_CS_PORT, SD0_CS_PIN); +#endif +#ifdef SD1_CS_PORT + mask = filter_out (mask, portnum, &SD1_CS_PORT, SD1_CS_PIN); +#endif +#ifdef SD0_ENA_PORT + mask = filter_out (mask, portnum, &SD0_ENA_PORT, SD0_ENA_PIN); +#endif +#ifdef SD1_ENA_PORT + mask = filter_out (mask, portnum, &SD1_ENA_PORT, SD1_ENA_PIN); +#endif +#ifdef UART1_ENA_PORT + mask = filter_out (mask, portnum, &UART1_ENA_PORT, UART1_ENA_PIN); +#endif +#ifdef UART2_ENA_PORT + mask = filter_out (mask, portnum, &UART2_ENA_PORT, UART2_ENA_PIN); +#endif +#ifdef UART3_ENA_PORT + mask = filter_out (mask, portnum, &UART3_ENA_PORT, UART3_ENA_PIN); +#endif +#ifdef UART4_ENA_PORT + mask = filter_out (mask, portnum, &UART4_ENA_PORT, UART4_ENA_PIN); +#endif +#ifdef UART5_ENA_PORT + mask = filter_out (mask, portnum, &UART5_ENA_PORT, UART5_ENA_PIN); +#endif +#ifdef UART6_ENA_PORT + mask = filter_out (mask, portnum, &UART6_ENA_PORT, UART6_ENA_PIN); +#endif +#ifdef SW_DATA_PORT + mask = filter_out (mask, portnum, &SW_DATA_PORT, SW_DATA_PIN); +#endif +#ifdef SW_LDA_PORT + mask = filter_out (mask, portnum, &SW_LDA_PORT, SW_LDA_PIN); +#endif +#ifdef SW_RD_PORT + mask = filter_out (mask, portnum, &SW_RD_PORT, SW_RD_PIN); +#endif +#ifdef SW_WR_PORT + mask = filter_out (mask, portnum, &SW_WR_PORT, SW_WR_PIN); +#endif + +#ifdef POWER_ENABLED +#ifdef POWER_SWITCH_PORT + mask = filter_out (mask, portnum, &POWER_SWITCH_PORT, POWER_SWITCH_PIN); +#endif +#ifdef POWER_LED_PORT + mask = filter_out (mask, portnum, &POWER_LED_PORT, POWER_LED_PIN); +#endif +#ifdef POWER_CONTROL_PORT + mask = filter_out (mask, portnum, &POWER_CONTROL_PORT, POWER_CONTROL_PIN); +#endif +#endif + + return mask; +} + +static void +gpio_print (dev, buf) + dev_t dev; + char *buf; +{ + u_int unit = minor(dev) & MINOR_UNIT; + register struct gpioreg *reg = unit + (struct gpioreg*) &TRISA; + register u_int mask, conf, tris; + register char c; + + conf = gpio_confmask [unit]; + tris = reg->tris; + if (minor(dev) & MINOR_CONF) { + /* /dev/confX device: port configuration mask */ + u_int odc = reg->odc; + for (mask=1<<(NPINS-1); mask; mask>>=1) { + if (! (conf & mask)) + c = '-'; + else if (tris & mask) + c = 'i'; + else + c = (odc & mask) ? 'd' : 'o'; + *buf++ = c; + } + } else { + /* /dev/portX device: port value mask */ + u_int lat = reg->lat; + u_int port = reg->port; + for (mask=1<<(NPINS-1); mask; mask>>=1) { + if (! (conf & mask)) + c = '-'; + else if (tris & mask) + c = (port & mask) ? '1' : '0'; + else + c = (lat & mask) ? '1' : '0'; + *buf++ = c; + } + } + *buf++ = '\n'; + *buf = 0; +} + +static void +gpio_parse (dev, buf) + dev_t dev; + char *buf; +{ + u_int unit = minor(dev) & MINOR_UNIT; + register struct gpioreg *reg = unit + (struct gpioreg*) &TRISA; + register u_int mask; + register char c; + + if (minor(dev) & MINOR_CONF) { + /* /dev/confX device: port configuration mask */ + for (mask=1<<(NPINS-1); mask; mask>>=1) { + c = *buf++; + if (c <= ' ' || c > '~') + break; + if (c == 'x' || c == 'X') + gpio_confmask [unit] &= ~mask; + else if (c == 'i' || c == 'I') + reg->trisset = mask; + else if (c == 'o' || c == 'O') { + reg->odcclr = mask; + reg->trisclr = mask; + } else if (c == 'd' || c == 'D') { + reg->odcset = mask; + reg->trisclr = mask; + } + } + } else { + /* /dev/portX device: port value mask */ + u_int conf = gpio_confmask [unit]; + u_int tris = reg->tris; + for (mask=1<<(NPINS-1); mask; mask>>=1) { + c = *buf++; + if (c <= ' ' || c > '~') + break; + if (! (conf & mask) || (tris & mask)) + continue; + if (c == '0') + reg->latclr = mask; + else + reg->latset = mask; + } + } +} + +int +gpioopen (dev, flag, mode) + dev_t dev; +{ + register u_int unit = minor(dev) & MINOR_UNIT; + + if (unit >= NGPIO) + return ENXIO; + if (u.u_uid != 0) + return EPERM; + return 0; +} + +int +gpioclose (dev, flag, mode) + dev_t dev; +{ + return 0; +} + +int +gpioread (dev, uio, flag) + dev_t dev; + struct uio *uio; + int flag; +{ + register struct iovec *iov; + register u_int cnt = NPINS + 1; + char buf [20]; + + /* I/o size should be large enough. */ + iov = uio->uio_iov; + if (iov->iov_len < cnt) + return EIO; + + /* Read only cnt bytes. */ + if (uio->uio_offset >= cnt) + return 0; + cnt -= uio->uio_offset; + + /* Print port status to buffer. */ + gpio_print (dev, buf); + //PRINTDBG ("gpioread -> %s", buf); + + bcopy (buf + uio->uio_offset, iov->iov_base, cnt); + iov->iov_base += cnt; + iov->iov_len -= cnt; + uio->uio_resid -= cnt; + uio->uio_offset += cnt; + return 0; +} + +int +gpiowrite (dev, uio, flag) + dev_t dev; + struct uio *uio; + int flag; +{ + register struct iovec *iov = uio->uio_iov; + register u_int cnt = NPINS; + char buf [20]; + + /* I/o size should be large enough. */ + if (iov->iov_len < cnt) + return EIO; + + bcopy (iov->iov_base, buf, cnt); + iov->iov_base += cnt; + iov->iov_len -= cnt; + uio->uio_resid -= cnt; + uio->uio_offset += cnt; + + PRINTDBG ("gpiowrite ('%s')\n", buf); + gpio_parse (dev, buf); + return 0; +} + +/* + * Display a picture on LoL shield. + * Duration in milliseconds is specified. + */ +static void +gpio_lol (msec, data) + u_int msec; + const short *data; +{ + /* Number of control pins for LoL Shield. */ + #define LOL_NPINS 12 + + /* Number of rows on LoL Shield. */ + #define LOL_NROW 9 + + /* Number of columns on LoL Shield. */ + #define LOL_NCOL 14 + + /* Sequence of pins to set high during refresh cycle. */ + static const unsigned high [LOL_NPINS] = { + 1 << 10, /* PB10 - labeled D13 on board (connect to A5) */ + 1 << 9, /* PB9 - D12 (connect to A4) */ + 1 << 7, /* PB7 - D11 (connect to A3) */ + 1 << 6, /* PB6 - D10 (connect to A2) */ + 1 << 4, /* PB4 - D9 (connect to A1) */ + 1 << 11, /* PB11 - D8 */ + 0x10000 << 7, /* PE7 - D7 */ + 0x10000 << 6, /* PE6 - D6 */ + 0x10000 << 5, /* PE5 - D5 */ + 0x10000 << 4, /* PE4 - D4 */ + 0x10000 << 3, /* PE3 - D3 */ + 0x10000 << 2, /* PE2 - D2 */ + }; + + /* Remap pixels to pin indexes. */ + static const unsigned char lol_map [LOL_NROW*LOL_NCOL*2] = + { + 0,8,0,7,0,6,0,5,0,4,0,3,0,2,0,1,0,9,9,0,0,10,10,0,0,11,11,0, + 1,8,1,7,1,6,1,5,1,4,1,3,1,2,1,0,1,9,9,1,1,10,10,1,1,11,11,1, + 2,8,2,7,2,6,2,5,2,4,2,3,2,1,2,0,2,9,9,2,2,10,10,2,2,11,11,2, + 3,8,3,7,3,6,3,5,3,4,3,2,3,1,3,0,3,9,9,3,3,10,10,3,3,11,11,3, + 4,8,4,7,4,6,4,5,4,3,4,2,4,1,4,0,4,9,9,4,4,10,10,4,4,11,11,4, + 5,8,5,7,5,6,5,4,5,3,5,2,5,1,5,0,5,9,9,5,5,10,10,5,5,11,11,5, + 6,8,6,7,6,5,6,4,6,3,6,2,6,1,6,0,6,9,9,6,6,10,10,6,6,11,11,6, + 7,8,7,6,7,5,7,4,7,3,7,2,7,1,7,0,7,9,9,7,7,10,10,7,7,11,11,7, + 8,7,8,6,8,5,8,4,8,3,8,2,8,1,8,0,8,9,9,8,8,10,10,8,8,11,11,8, + }; + + unsigned row, mask, bmask, emask; + const unsigned char *map; + unsigned low [LOL_NPINS]; + + /* Clear pin masks. */ + for (row = 0; row < LOL_NPINS; row++) + low [row] = 0; + + /* Convert image to array of pin masks. */ + for (row = 0; row < LOL_NROW; row++) { + mask = *data++ & ((1 << LOL_NCOL) - 1); + map = &lol_map [row * LOL_NCOL * 2]; + while (mask != 0) { + if (mask & 1) { + low [map[0]] |= high [map[1]]; + } + map += 2; + mask >>= 1; + } + } + bmask = high[0] | high[1] | high[2] | high[3] | high[4] | high[5]; + emask = (high[6] | high[7] | high[8] | high[9] | high[10] | + high[11]) >> 16; + + /* Display the image. */ + if (msec < 1) + msec = 20; + while (msec-- > 0) { + for (row = 0; row < LOL_NPINS; row++) { + /* Set all pins to tristate. */ + TRISBSET = bmask; + TRISESET = emask; + + /* Set one pin to high. */ + mask = high [row]; + if (row < 6) { + TRISBCLR = mask; + LATBSET = mask; + } else { + mask >>= 16; + TRISECLR = mask; + LATESET = mask; + } + + /* Set other pins to low. */ + mask = low [row]; + TRISBCLR = mask; + LATBCLR = mask; + mask >>= 16; + TRISECLR = mask; + LATECLR = mask; + + /* Pause to make it visible. */ + udelay (1000 / LOL_NPINS); + } + } + + /* Turn display off. */ + TRISBSET = bmask; + TRISESET = emask; +} + +/* + * Commands: + * GPIO_CONFIN - configure as input + * GPIO_CONFOUT - configure as output + * GPIO_CONFOD - configure as open drain + * GPIO_DECONF - deconfigure + * GPIO_STORE - store all outputs + * GPIO_SET - set to 1 by mask + * GPIO_CLEAR - set to 0 by mask + * GPIO_INVERT - invert by mask + * GPIO_POLL - poll + * + * Use GPIO_PORT(n) to set port number. + */ +int +gpioioctl (dev, cmd, addr, flag) + dev_t dev; + register u_int cmd; + caddr_t addr; +{ + register u_int unit, mask, value; + register struct gpioreg *reg; + + PRINTDBG ("gpioioctl (cmd=%08x, addr=%08x, flag=%d)\n", cmd, addr, flag); + unit = cmd & 0xff; + cmd &= ~0xff; + if (cmd == GPIO_LOL) { + /* display 9x14 image on a lol shield */ + if (baduaddr (addr) || baduaddr (addr + LOL_NROW*2 - 1)) + return EFAULT; + gpio_lol (unit, (const short*) addr); + return 0; + } + + if ((cmd & (IOC_INOUT | IOC_VOID)) != IOC_VOID || + ((cmd >> 8) & 0xff) != 'g') + return EINVAL; + if (unit >= NGPIO) + return ENXIO; + + reg = unit + (struct gpioreg*) &TRISA; + mask = (u_int) addr & 0xffff; + if (cmd & GPIO_COMMAND & (GPIO_CONFIN | GPIO_CONFOUT | GPIO_CONFOD)) + mask = gpio_filter (mask, unit); + else + mask &= gpio_confmask [unit]; + + if (cmd & GPIO_COMMAND & GPIO_CONFIN) { + /* configure as input */ + PRINTDBG ("TRIS%cSET %p := %04x\n", unit+'A', ®->trisset, mask); + reg->trisset = mask; + gpio_confmask [unit] |= mask; + + /* skip output-only bits */ + gpio_confmask [unit] ^= mask & ~reg->tris; + } + if (cmd & GPIO_COMMAND & (GPIO_CONFOUT | GPIO_CONFOD)) { + if (cmd & GPIO_COMMAND & GPIO_CONFOUT) { + /* configure as output */ + PRINTDBG ("ODC%cCLR %p := %04x\n", unit+'A', ®->odcclr, mask); + reg->odcclr = mask; + } else { + /* configure as open drain */ + PRINTDBG ("ODC%cSET %p := %04x\n", unit+'A', ®->odcset, mask); + reg->odcset = mask; + } + PRINTDBG ("TRIS%cCLR %p := %04x\n", unit+'A', ®->trisclr, mask); + reg->trisclr = mask; + gpio_confmask [unit] |= mask; + + /* skip input-only bits */ + gpio_confmask [unit] ^= mask & reg->tris; + } + if (cmd & GPIO_COMMAND & GPIO_DECONF) { + /* deconfigure */ + gpio_confmask [unit] &= ~mask; + } + if (cmd & GPIO_COMMAND & GPIO_STORE) { + /* store all outputs */ + value = reg->lat; + PRINTDBG ("LAT%c %p -> %04x\n", unit+'A', ®->lat, value); + value &= ~gpio_confmask [unit]; + value |= mask; + PRINTDBG ("LAT%c %p := %04x\n", unit+'A', ®->lat, value); + reg->lat = value; + } + if (cmd & GPIO_COMMAND & GPIO_SET) { + /* set to 1 by mask */ + PRINTDBG ("LAT%cSET %p := %04x\n", unit+'A', ®->latset, mask); + reg->latset = mask; + } + if (cmd & GPIO_COMMAND & GPIO_CLEAR) { + /* set to 0 by mask */ + PRINTDBG ("LAT%cCLR %p := %04x\n", unit+'A', ®->latclr, mask); + reg->latclr = mask; + } + if (cmd & GPIO_COMMAND & GPIO_INVERT) { + /* invert by mask */ + PRINTDBG ("LAT%cINV %p := %04x\n", unit+'A', ®->latinv, mask); + reg->latinv = mask; + } + if (cmd & GPIO_COMMAND & GPIO_POLL) { + /* send current pin values to user */ + value = reg->port; + PRINTDBG ("PORT%c %p -> %04x\n", unit+'A', ®->port, value); + u.u_rval = value; + } + return 0; +} diff --git a/sys/pic32/io.h b/sys/pic32/io.h new file mode 100644 index 0000000..491d994 --- /dev/null +++ b/sys/pic32/io.h @@ -0,0 +1,209 @@ +/* + * Hardware register defines for MIPS32 architecture. + * + * Copyright (C) 2008-2010 Serge Vakulenko, + * + * 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 the copyright notice and this + * permission notice and warranty disclaimer appear in supporting + * documentation, and that the name of the author not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * + * The author disclaim all warranties with regard to this + * software, including all implied warranties of merchantability + * and fitness. In no event shall the author 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. + */ +#ifdef PIC32MX4 +# include "machine/pic32mx.h" +#endif +#ifdef PIC32MX7 +# include "machine/pic32mx.h" +#endif + +/* + * Offsets of register values in saved context. + */ +#define FRAME_R1 0 +#define FRAME_R2 1 +#define FRAME_R3 2 +#define FRAME_R4 3 +#define FRAME_R5 4 +#define FRAME_R6 5 +#define FRAME_R7 6 +#define FRAME_R8 7 +#define FRAME_R9 8 +#define FRAME_R10 9 +#define FRAME_R11 10 +#define FRAME_R12 11 +#define FRAME_R13 12 +#define FRAME_R14 13 +#define FRAME_R15 14 +#define FRAME_R16 15 +#define FRAME_R17 16 +#define FRAME_R18 17 +#define FRAME_R19 18 +#define FRAME_R20 19 +#define FRAME_R21 20 +#define FRAME_R22 21 +#define FRAME_R23 22 +#define FRAME_R24 23 +#define FRAME_R25 24 +#define FRAME_GP 25 +#define FRAME_SP 26 +#define FRAME_FP 27 +#define FRAME_RA 28 +#define FRAME_LO 29 +#define FRAME_HI 30 +#define FRAME_STATUS 31 +#define FRAME_PC 32 + +#define FRAME_WORDS 33 + +#ifndef __ASSEMBLER__ + +#ifndef KERNEL +/* + * 2BSD system call extensions: use with care. + */ + +/* + * Read peripheral register. + */ +unsigned ufetch (unsigned addr); + +/* + * Write peripheral register. + */ +unsigned ustore (unsigned addr, unsigned value); + +/* + * Call a kernel function. + */ +unsigned ucall (int priority, void *address, int arg1, int arg2); + +#endif /* KERNEL */ + +/* + * Set value of stack pointer register. + */ +static void inline __attribute__ ((always_inline)) +mips_set_stack_pointer (void *x) +{ + asm volatile ( + "move $sp, %0" + : : "r" (x) : "sp"); +} + +/* + * Get value of stack pointer register. + */ +static inline __attribute__ ((always_inline)) +void *mips_get_stack_pointer () +{ + void *x; + + asm volatile ( + "move %0, $sp" + : "=r" (x)); + return x; +} + +/* + * Read C0 coprocessor register. + */ +#define mips_read_c0_register(reg,sel) \ + ({ int __value; \ + asm volatile ( \ + "mfc0 %0, $%1, %2" \ + : "=r" (__value) : "K" (reg), "K" (sel)); \ + __value; \ +}) + +/* + * Write C0 coprocessor register. + */ +#define mips_write_c0_register(reg, sel, value) \ +do { \ + asm volatile ( \ + "mtc0 %z0, $%1, %2 \n ehb" \ + : : "r" ((unsigned int) (value)), "K" (reg), "K" (sel));\ +} while (0) + +/* + * Disable the hardware interrupts, + * saving the interrupt state into the supplied variable. + */ +static int inline __attribute__ ((always_inline)) +mips_intr_disable () +{ + int status; + asm volatile ("di %0" : "=r" (status)); + return status; +} + +/* + * Restore the hardware interrupt mode using the saved interrupt state. + */ +static void inline __attribute__ ((always_inline)) +mips_intr_restore (int x) +{ + /* C0_STATUS */ + mips_write_c0_register (12, 0, x); +} + +/* + * Explicit hazard barrier. + */ +static void inline __attribute__ ((always_inline)) +mips_ehb() +{ + asm volatile ("ehb"); +} + +/* + * Enable hardware interrupts. + */ +static int inline __attribute__ ((always_inline)) +mips_intr_enable () +{ + int status; + asm volatile ("ei %0" : "=r" (status)); + return status; +} + +/* + * Count a number of leading (most significant) zero bits in a word. + */ +static int inline __attribute__ ((always_inline)) +mips_clz (unsigned x) +{ + int n; + + asm volatile ("clz %0, %1" + : "=r" (n) : "r" (x)); + return n; +} + +/* + * Swap bytes in a word: ABCD to DCBA. + */ +static unsigned inline __attribute__ ((always_inline)) +mips_bswap (unsigned x) +{ + int n; + + asm volatile ( + "wsbh %0, %1 \n" + "rotr %0, 16" + : "=r" (n) : "r" (x)); + return n; +} +#endif /* __ASSEMBLER__ */ diff --git a/sys/pic32/kernel-post.mk b/sys/pic32/kernel-post.mk new file mode 100644 index 0000000..b73fd0e --- /dev/null +++ b/sys/pic32/kernel-post.mk @@ -0,0 +1,85 @@ + +DEPFLAGS = -MT $@ -MP -MD -MF .deps/$*.dep +CFLAGS = -I. -I$(H) -O $(DEFS) $(DEPFLAGS) +ASFLAGS = -I. -I$(H) $(DEFS) $(DEPFLAGS) + +include $(BUILDPATH)/gcc-config.mk + +CC = $(GCCPREFIX)gcc -EL -g -mips32r2 +CC += -nostdinc -fno-builtin -Werror -Wall -fno-dwarf2-cfi-asm +LDFLAGS += -nostdlib -T $(LDSCRIPT) -Wl,-Map=unix.map +SIZE = $(GCCPREFIX)size +OBJDUMP = $(GCCPREFIX)objdump +OBJCOPY = $(GCCPREFIX)objcopy +PROGTOOL = $(AVRDUDE) -c stk500v2 -p pic32 -b 115200 +BLLDFLAGS = -nostdlib -T$(BUILDPATH)/cfg/boot.ld -Wl,-Map=usbboot.map +BLCC = $(CC) #$(GCCPREFIX)gcc -EL -g -mips32r2 -Werror -Wall -fno-dwarf2-cfi-asm +BLCFLAGS = -Os -I. -I$(H) $(DEFS) $(DEPFLAGS) + +DEFS += -DCONFIG=$(CONFIG) + +all: .deps sys machine unix.elf $(EXTRA_TARGETS) + $(SIZE) unix.elf + +bootloader: .deps sys machine bootloader.elf + +clean: + rm -rf .deps *.o *.elf *.bin *.dis *.map *.srec core \ + mklog assym.h vers.c genassym sys machine + +.deps: + mkdir .deps + +sys: + ln -s $(BUILDPATH)/../include $@ + +machine: + ln -s $(BUILDPATH) $@ + +unix.elf: $(KERNOBJ) $(LDSCRIPT) + $(CC) $(LDFLAGS) $(KERNOBJ) -o $@ + chmod -x $@ + $(OBJDUMP) -d -S $@ > unix.dis + $(OBJCOPY) -O binary $@ unix.bin + $(OBJCOPY) -O ihex --change-addresses=0x80000000 $@ unix.hex + chmod -x $@ unix.bin + +bootloader.elf: bl_usb_boot.o bl_usb_device.o bl_usb_function_hid.o bl_devcfg.o + $(BLCC) $(BLLDFLAGS) bl_usb_boot.o bl_usb_device.o bl_usb_function_hid.o bl_devcfg.o -o bootloader.elf + chmod -x bootloader.elf + $(OBJDUMP) -d -S bootloader.elf > bootloader.dis + $(OBJCOPY) -O ihex --change-addresses=0x80000000 bootloader.elf bootloader.hex + +bl_usb_boot.o: $(BUILDPATH)/usb_boot.c + $(BLCC) $(BLCFLAGS) -o $@ -c $(BUILDPATH)/usb_boot.c + +bl_usb_device.o: $(BUILDPATH)/usb_device.c + $(BLCC) $(BLCFLAGS) -o $@ -c $(BUILDPATH)/usb_device.c + +bl_usb_function_hid.o: $(BUILDPATH)/usb_function_hid.c + $(BLCC) $(BLCFLAGS) -o $@ -c $(BUILDPATH)/usb_function_hid.c + +bl_devcfg.o: $(BUILDPATH)/devcfg.c + $(BLCC) $(BLCFLAGS) -o $@ -c $(BUILDPATH)/devcfg.c + +load: unix.hex + pic32prog $(BLREBOOT) unix.hex + +loadboot: bootloader.hex + pic32prog $(BLREBOOT) bootloader.hex + +vers.o: $(BUILDPATH)/newvers.sh $(H)/*.h $(M)/*.[ch] $(S)/*.c + sh $(BUILDPATH)/newvers.sh > vers.c + $(CC) -c vers.c + +reconfig: + ../../../tools/configsys/config $(CONFIG) + +.SUFFIXES: .i .srec .hex .dis .cpp .cxx .bin .elf + +.o.dis: + $(OBJDUMP) -d -z -S $< > $@ + +ifeq (.deps, $(wildcard .deps)) +-include .deps/*.dep +endif diff --git a/sys/pic32/limits.h b/sys/pic32/limits.h new file mode 100644 index 0000000..6198023 --- /dev/null +++ b/sys/pic32/limits.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. + */ + +#define CHAR_BIT 8 /* number of bits in a char */ + +/* + * According to ANSI (section 2.2.4.2), the values below must be usable by + * #if preprocessing directives. Additionally, the expression must have the + * same type as would an expression that is an object of the corresponding + * type converted according to the integral promotions. The subtraction for + * INT_MIN and LONG_MIN is so the value is not unsigned; 2147483648 is an + * unsigned int for 32-bit two's complement ANSI compilers (section 3.1.3.2). + * These numbers work for pcc as well. The UINT_MAX and ULONG_MAX values + * are written as hex so that GCC will be quiet about large integer constants. + */ +#define SCHAR_MAX 127 /* min value for a signed char */ +#define SCHAR_MIN (-128) /* max value for a signed char */ + +#define UCHAR_MAX 255 /* max value for an unsigned char */ +#define CHAR_MAX 127 /* max value for a char */ +#define CHAR_MIN (-128) /* min value for a char */ + +#define USHRT_MAX 65535 /* max value for an unsigned short */ +#define SHRT_MAX 32767 /* max value for a short */ +#define SHRT_MIN (-32768) /* min value for a short */ + +#define UINT_MAX 0xffffffff /* max value for an unsigned int */ +#define INT_MAX 2147483647 /* max value for an int */ +#define INT_MIN (-2147483647-1) /* min value for an int */ + +#define ULONG_MAX 0xffffffff /* max value for an unsigned long */ +#define LONG_MAX 2147483647L /* max value for a long */ +#define LONG_MIN (-2147483647L-1L) /* min value for a long */ + +#define SSIZE_MAX INT_MAX /* max value for a ssize_t */ +#define SIZE_T_MAX UINT_MAX /* max value for a size_t */ diff --git a/sys/pic32/machdep.c b/sys/pic32/machdep.c new file mode 100644 index 0000000..6ae6c9b --- /dev/null +++ b/sys/pic32/machdep.c @@ -0,0 +1,888 @@ +/* + * Copyright (c) 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "param.h" +#include "dir.h" +#include "inode.h" +#include "user.h" +#include "proc.h" +#include "fs.h" +#include "map.h" +#include "buf.h" +#include "file.h" +#include "clist.h" +#include "callout.h" +#include "reboot.h" +#include "msgbuf.h" +#include "namei.h" +#include "mount.h" +#include "systm.h" +#include "debug.h" +#include "uart.h" +#include "usb_uart.h" +#ifdef UARTUSB_ENABLED +# include +# include +#endif + +#ifdef POWER_ENABLED +extern void power_init(); +extern void power_off(); +#endif + +#ifdef LED_TTY_INVERT +#define LED_TTY_ON() LAT_CLR(LED_TTY_PORT) = 1 << LED_TTY_PIN +#define LED_TTY_OFF() LAT_SET(LED_TTY_PORT) = 1 << LED_TTY_PIN +#else +#define LED_TTY_ON() LAT_SET(LED_TTY_PORT) = 1 << LED_TTY_PIN +#define LED_TTY_OFF() LAT_CLR(LED_TTY_PORT) = 1 << LED_TTY_PIN +#endif + +#ifdef LED_DISK_INVERT +#define LED_DISK_ON() LAT_CLR(LED_DISK_PORT) = 1 << LED_DISK_PIN +#define LED_DISK_OFF() LAT_SET(LED_DISK_PORT) = 1 << LED_DISK_PIN +#else +#define LED_DISK_ON() LAT_SET(LED_DISK_PORT) = 1 << LED_DISK_PIN +#define LED_DISK_OFF() LAT_CLR(LED_DISK_PORT) = 1 << LED_DISK_PIN +#endif + +#ifdef LED_KERNEL_INVERT +#define LED_KERNEL_ON() LAT_CLR(LED_KERNEL_PORT) = 1 << LED_KERNEL_PIN +#define LED_KERNEL_OFF() LAT_SET(LED_KERNEL_PORT) = 1 << LED_KERNEL_PIN +#else +#define LED_KERNEL_ON() LAT_SET(LED_KERNEL_PORT) = 1 << LED_KERNEL_PIN +#define LED_KERNEL_OFF() LAT_CLR(LED_KERNEL_PORT) = 1 << LED_KERNEL_PIN +#endif + +#ifdef LED_SWAP_INVERT +#define LED_SWAP_ON() LAT_CLR(LED_SWAP_PORT) = 1 << LED_SWAP_PIN +#define LED_SWAP_OFF() LAT_SET(LED_SWAP_PORT) = 1 << LED_SWAP_PIN +#else +#define LED_SWAP_ON() LAT_SET(LED_SWAP_PORT) = 1 << LED_SWAP_PIN +#define LED_SWAP_OFF() LAT_CLR(LED_SWAP_PORT) = 1 << LED_SWAP_PIN +#endif + +#ifdef LED_MISC1_INVERT +#define LED_MISC1_ON() LAT_CLR(LED_MISC1_PORT) = 1 << LED_MISC1_PIN +#define LED_MISC1_OFF() LAT_SET(LED_MISC1_PORT) = 1 << LED_MISC1_PIN +#else +#define LED_MISC1_ON() LAT_SET(LED_MISC1_PORT) = 1 << LED_MISC1_PIN +#define LED_MISC1_OFF() LAT_CLR(LED_MISC1_PORT) = 1 << LED_MISC1_PIN +#endif + +#ifdef LED_MISC2_INVERT +#define LED_MISC2_ON() LAT_CLR(LED_MISC2_PORT) = 1 << LED_MISC2_PIN +#define LED_MISC2_OFF() LAT_SET(LED_MISC2_PORT) = 1 << LED_MISC2_PIN +#else +#define LED_MISC2_ON() LAT_SET(LED_MISC2_PORT) = 1 << LED_MISC2_PIN +#define LED_MISC2_OFF() LAT_CLR(LED_MISC2_PORT) = 1 << LED_MISC2_PIN +#endif + +#ifdef LED_MISC3_INVERT +#define LED_MISC3_ON() LAT_CLR(LED_MISC3_PORT) = 1 << LED_MISC3_PIN +#define LED_MISC3_OFF() LAT_SET(LED_MISC3_PORT) = 1 << LED_MISC3_PIN +#else +#define LED_MISC3_ON() LAT_SET(LED_MISC3_PORT) = 1 << LED_MISC3_PIN +#define LED_MISC3_OFF() LAT_CLR(LED_MISC3_PORT) = 1 << LED_MISC3_PIN +#endif + +#ifdef LED_MISC4_INVERT +#define LED_MISC4_ON() LAT_CLR(LED_MISC4_PORT) = 1 << LED_MISC4_PIN +#define LED_MISC4_OFF() LAT_SET(LED_MISC4_PORT) = 1 << LED_MISC4_PIN +#else +#define LED_MISC4_ON() LAT_SET(LED_MISC4_PORT) = 1 << LED_MISC4_PIN +#define LED_MISC4_OFF() LAT_CLR(LED_MISC4_PORT) = 1 << LED_MISC4_PIN +#endif + +int hz = HZ; +int usechz = (1000000L + HZ - 1) / HZ; +struct timezone tz = { 8*60, 1 }; +int nproc = NPROC; + +struct namecache namecache [NNAMECACHE]; +char bufdata [NBUF * MAXBSIZE]; +struct inode inode [NINODE]; +struct callout callout [NCALL]; +struct mount mount [NMOUNT]; +struct buf buf [NBUF], bfreelist [BQUEUES]; +struct bufhd bufhash [BUFHSZ]; +struct cblock cfree [NCLIST]; +struct proc proc [NPROC]; +struct file file [NFILE]; + +/* + * Remove the ifdef/endif to run the kernel in unsecure mode even when in + * a multiuser state. Normally 'init' raises the security level to 1 + * upon transitioning to multiuser. Setting the securelevel to -1 prevents + * the secure level from being raised by init. + */ +#ifdef PERMANENTLY_INSECURE +int securelevel = -1; +#else +int securelevel = 0; +#endif + +struct mapent swapent[SMAPSIZ]; +struct map swapmap[1] = { + { swapent, + &swapent[SMAPSIZ], + "swapmap" }, +}; + +int waittime = -1; + +static int +nodump (dev) + dev_t dev; +{ + printf ("\ndumping to dev %o off %D: not implemented\n", dumpdev, dumplo); + return (0); +} + +int (*dump) (dev_t) = nodump; + +dev_t rootdev, swapdev, pipedev; + +dev_t dumpdev = NODEV; +daddr_t dumplo = (daddr_t) 1024; + +/* + * Machine dependent startup code + */ +void +startup() +{ + extern void _etext(), _exception_base_(); + extern unsigned __data_start; + + /* Initialize STATUS register: master interrupt disable. + * Setup interrupt vector base. */ + mips_write_c0_register (C0_STATUS, 0, ST_CU0 | ST_BEV); + mips_write_c0_register (C0_EBASE, 1, _exception_base_); + mips_write_c0_register (C0_STATUS, 0, ST_CU0); + + /* Set vector spacing: not used really, but must be nonzero. */ + mips_write_c0_register (C0_INTCTL, 1, 32); + + /* Clear CAUSE register: use special interrupt vector 0x200. */ + mips_write_c0_register (C0_CAUSE, 0, CA_IV); + + /* Setup memory. */ + BMXPUPBA = 512 << 10; /* Kernel Flash memory size */ +#ifdef KERNEL_EXECUTABLE_RAM + /* + * Set boundry for kernel executable ram on smallest + * 2k boundry required to allow the keram segement to fit. + * This means that there is possibly some u0area ramspace that + * is executable, but as it is isolated from userspace this + * should be ok, given the apparent goals of this project. + */ + extern void _keram_start(), _keram_end(); + unsigned keram_size = (((char*)&_keram_end-(char*)&_keram_start+(2<<10))/(2<<10)*(2<<10)); + BMXDKPBA = ((32<<10)-keram_size); /* Kernel RAM size */ + BMXDUDBA = BMXDKPBA+(keram_size); /* Executable RAM in kernel */ +#else + BMXDKPBA = 32 << 10; /* Kernel RAM size */ + BMXDUDBA = BMXDKPBA; /* Zero executable RAM in kernel */ +#endif + BMXDUPBA = BMXDUDBA; /* All user RAM is executable */ + + /* + * Setup interrupt controller. + */ + INTCON = 0; /* Interrupt Control */ + IPTMR = 0; /* Temporal Proximity Timer */ + IFS(0) = + PIC32_IPC_IP0(2) | PIC32_IPC_IP1(1) | + PIC32_IPC_IP2(1) | PIC32_IPC_IP3(1) | + PIC32_IPC_IS0(0) | PIC32_IPC_IS1(0) | + PIC32_IPC_IS2(0) | PIC32_IPC_IS3(0) ; + + IFS(1) = IFS(2) = 0; /* Interrupt Flag Status */ + IEC(0) = IEC(1) = IEC(2) = 0; /* Interrupt Enable Control */ + IPC(0) = IPC(1) = IPC(2) = IPC(3) = /* Interrupt Priority Control */ + IPC(4) = IPC(5) = IPC(6) = IPC(7) = + IPC(8) = IPC(9) = IPC(10) = IPC(11) = + IPC(12) = + PIC32_IPC_IP0(1) | PIC32_IPC_IP1(1) | + PIC32_IPC_IP2(1) | PIC32_IPC_IP3(1) | + PIC32_IPC_IS0(0) | PIC32_IPC_IS1(0) | + PIC32_IPC_IS2(0) | PIC32_IPC_IS3(0) ; + + /* + * Setup wait states. + */ + CHECON = 2; + BMXCONCLR = 0x40; + CHECONSET = 0x30; + + /* Disable JTAG port, to use it for i/o. */ + DDPCON = 0; + + /* Use all B ports as digital. */ + AD1PCFG = ~0; + + /* Config register: enable kseg0 caching. */ + mips_write_c0_register (C0_CONFIG, 0, + mips_read_c0_register (C0_CONFIG, 0) | 3); + + /* Kernel mode, interrupts disabled. */ + mips_write_c0_register (C0_STATUS, 0, ST_CU0); + mips_ehb(); + + /* + * Configure LED pins. + */ +#ifdef LED_TTY_PORT /* Terminal i/o */ + LED_TTY_OFF(); + TRIS_CLR(LED_TTY_PORT) = 1 << LED_TTY_PIN; +#endif +#ifdef LED_DISK_PORT /* Disk i/o */ + LED_DISK_OFF(); + TRIS_CLR(LED_DISK_PORT) = 1 << LED_DISK_PIN; +#endif +#ifdef LED_KERNEL_PORT /* Kernel activity */ + LED_KERNEL_OFF(); + TRIS_CLR(LED_KERNEL_PORT) = 1 << LED_KERNEL_PIN; +#endif +#ifdef LED_SWAP_PORT /* Auxiliary */ + LED_SWAP_OFF(); + TRIS_CLR(LED_SWAP_PORT) = 1 << LED_SWAP_PIN; +#endif +#ifdef GPIO_CLEAR_PORT /* Clear pin */ + LAT_CLR(GPIO_CLEAR_PORT) = 1 << GPIO_CLEAR_PIN; + TRIS_CLR(GPIO_CLEAR_PORT) = 1 << GPIO_CLEAR_PIN; +#endif +#ifdef POWER_ENABLED + power_init(); +#endif + + //SETVAL(0); + + /* Initialize .data + .bss segments by zeroes. */ + bzero (&__data_start, KERNEL_DATA_SIZE - 96); + +#if __MPLABX__ + /* Microchip C32 compiler generates a .dinit table with + * initialization values for .data segment. */ + extern const unsigned _dinit_addr[]; + unsigned const *dinit = &_dinit_addr[0]; + for (;;) { + char *dst = (char*) (*dinit++); + if (dst == 0) + break; + + unsigned nbytes = *dinit++; + unsigned fmt = *dinit++; + if (fmt == 0) { /* Clear */ + do { + *dst++ = 0; + } while (--nbytes > 0); + } else { /* Copy */ + char *src = (char*) dinit; + do { + *dst++ = *src++; + } while (--nbytes > 0); + dinit = (unsigned*) ((unsigned) (src + 3) & ~3); + } + } +#else + /* Copy the .data image from flash to ram. + * Linker places it at the end of .text segment. */ + extern unsigned _edata; + unsigned *src = (unsigned*) &_etext; + unsigned *dest = &__data_start; + unsigned *limit = &_edata; + while (dest < limit) { + /*printf ("copy %08x from (%08x) to (%08x)\n", *src, src, dest);*/ + *dest++ = *src++; + } + +#ifdef KERNEL_EXECUTABLE_RAM + /* Copy code that must run out of ram (due to timing restrictions) + * from flash to the executable section of kernel ram. + * This was added to support swap on sdram */ + + extern void _ramfunc_image_begin(); + extern void _ramfunc_begin(); + extern void _ramfunc_end(); + + unsigned *src1 = (unsigned*) &_ramfunc_image_begin; + unsigned *dest1 = (unsigned*)&_ramfunc_begin; + unsigned *limit1 = (unsigned*)&_ramfunc_end; + /*printf ("copy from (%08x) to (%08x)\n", src1, dest1);*/ + while (dest1 < limit1) { + *dest1++ = *src1++; + } +#endif + +#endif + /* + * Setup UART registers. + * Compute the divisor for 115.2 kbaud. + */ +#if defined(UART1_ENABLED) || defined(UART2_ENABLED) || defined UART3_ENABLED || defined(UART4_ENABLED) || defined(UART5_ENABLED) || defined(UART6_ENABLED) + uartinit(); +#endif +#ifdef UARTUSB_ENABLED + usbinit(); +#endif + cninit(); + + + /* Get total RAM size. */ + physmem = BMXDRMSZ; +} + +void cpuidentify() +{ + unsigned devid = DEVID, osccon = OSCCON; + static const char pllmult[] = { 15, 16, 17, 18, 19, 20, 21, 24 }; + static const char plldiv[] = { 1, 2, 3, 4, 5, 6, 10, 12 }; + static const char *poscmod[] = { "external", "XT crystal", + "HS crystal", "(disabled)" }; + + printf ("cpu: "); + switch (devid & 0x0fffffff) { + case 0x04307053: printf ("795F512L"); break; + case 0x0430E053: printf ("795F512H"); break; + case 0x04341053: printf ("695F512L"); break; + case 0x04325053: printf ("695F512H"); break; + default: printf ("DevID %08x", devid); + } + printf (" %u MHz, bus %u MHz\n", CPU_KHZ/1000, BUS_KHZ/1000); + + /* COSC: current oscillator selection bits */ + printf ("oscillator: "); + switch (osccon >> 12 & 7) { + case 0: + printf ("internal Fast RC\n"); + break; + case 1: + printf ("internal Fast RC, PLL div 1:%d mult x%d\n", + plldiv [DEVCFG2 & 7], pllmult [osccon >> 16 & 7]); + break; + case 2: + printf ("%s\n", poscmod [DEVCFG1 >> 8 & 3]); + break; + case 3: + printf ("%s, PLL div 1:%d mult x%d\n", + poscmod [DEVCFG1 >> 8 & 3], + plldiv [DEVCFG2 & 7], pllmult [osccon >> 16 & 7]); + break; + case 4: + printf ("secondary\n"); + break; + case 5: + printf ("internal Low-Power RC\n"); + break; + case 6: + printf ("internal Fast RC, divided 1:16\n"); + break; + case 7: + printf ("internal Fast RC, divided\n"); + break; + } +} + +/* + * Sit and wait for something to happen... + */ +void +idle () +{ + /* Indicate that no process is running. */ + noproc = 1; + + /* Set SPL low so we can be interrupted. */ + int x = spl0(); + + /* Wait for something to happen. */ + asm volatile ("wait"); + + /* Restore previous SPL. */ + splx(x); +} + +void +boot (dev, howto) + register dev_t dev; + register int howto; +{ + if ((howto & RB_NOSYNC) == 0 && waittime < 0 && bfreelist[0].b_forw) { + register struct fs *fp; + register struct buf *bp; + int iter, nbusy; + + /* + * Force the root filesystem's superblock to be updated, + * so the date will be as current as possible after + * rebooting. + */ + fp = getfs (rootdev); + if (fp) + fp->fs_fmod = 1; + waittime = 0; + printf("syncing disks... "); + (void) splnet(); + sync(); + for (iter = 0; iter < 20; iter++) { + nbusy = 0; + for (bp = &buf[NBUF]; --bp >= buf; ) + if (bp->b_flags & B_BUSY) + nbusy++; + if (nbusy == 0) + break; + printf ("%d ", nbusy); + udelay (40000L * iter); + } + printf("done\n"); + } + (void) splhigh(); + if (! (howto & RB_HALT)) { + if ((howto & RB_DUMP) && dumpdev != NODEV) { + /* + * Take a dump of memory by calling (*dump)(), + * which must correspond to dumpdev. + * It should dump from dumplo blocks to the end + * of memory or to the end of the logical device. + */ + (*dump) (dumpdev); + } + /* Restart from dev, howto */ +#ifdef USB_NUM_STRING_DESCRIPTORS + /* Disable USB module, and wait awhile for the USB cable + * capacitance to discharge down to disconnected (SE0) state. + */ + U1CON = 0x0000; + udelay (1000); + + /* Stop DMA */ + if (! (DMACON & 0x1000)) { + DMACONSET = 0x1000; + while (DMACON & 0x800) + continue; + } +#endif + /* Unlock access to reset register */ + SYSKEY = 0; + SYSKEY = 0xaa996655; + SYSKEY = 0x556699aa; + + /* Reset microcontroller */ + RSWRSTSET = 1; + (void) RSWRST; + } + printf ("halted\n"); + + if(howto & RB_BOOTLOADER) + { + printf("entering bootloader\n"); + BLRKEY=0x12345678; + /* Unlock access to reset register */ + SYSKEY = 0; + SYSKEY = 0xaa996655; + SYSKEY = 0x556699aa; + + /* Reset microcontroller */ + RSWRSTSET = 1; + (void) RSWRST; + } + +#ifdef HALTREBOOT + printf("press any key to reboot..."); + cngetc(); + /* Unlock access to reset register */ + SYSKEY = 0; + SYSKEY = 0xaa996655; + SYSKEY = 0x556699aa; + + /* Reset microcontroller */ + RSWRSTSET = 1; + (void) RSWRST; + +#endif + + for (;;) { +#ifdef UARTUSB_ENABLED + usb_device_tasks(); + cdc_consume (0); + cdc_tx_service(); +#else +#ifdef POWER_ENABLED + if(howto & RB_POWEROFF) + power_off(); +#endif + asm volatile ("wait"); +#endif + } + /*NOTREACHED*/ +} + +/* + * Microsecond delay routine for MIPS processor. + */ +void +udelay (usec) + u_int usec; +{ + unsigned now = mips_read_c0_register (C0_COUNT, 0); + unsigned final = now + usec * (CPU_KHZ / 1000); + + for (;;) { + now = mips_read_c0_register (C0_COUNT, 0); + + /* This comparison is valid only when using a signed type. */ + if ((int) (now - final) >= 0) + break; + } +} + +/* + * Control LEDs, installed on the board. + */ +void led_control (int mask, int on) +{ +#ifdef LED_SWAP_PORT + if (mask & LED_SWAP) { /* Auxiliary */ + if (on) LED_SWAP_ON(); + else LED_SWAP_OFF(); + } +#endif +#ifdef LED_DISK_PORT + if (mask & LED_DISK) { /* Disk i/o */ + if (on) LED_DISK_ON(); + else LED_DISK_OFF(); + } +#endif +#ifdef LED_KERNEL_PORT + if (mask & LED_KERNEL) { /* Kernel activity */ + if (on) LED_KERNEL_ON(); + else LED_KERNEL_OFF(); + } +#endif +#ifdef LED_TTY_PORT + if (mask & LED_TTY) { /* Terminal i/o */ + if (on) LED_TTY_ON(); + else LED_TTY_OFF(); + } +#endif +} + +/* + * Increment user profiling counters. + */ +void addupc (caddr_t pc, struct uprof *pbuf, int ticks) +{ + unsigned indx; + + if (pc < (caddr_t) pbuf->pr_off) + return; + + indx = pc - (caddr_t) pbuf->pr_off; + indx = (indx * pbuf->pr_scale) >> 16; + if (indx >= pbuf->pr_size) + return; + + pbuf->pr_base[indx] += ticks; +} + +/* + * Find the index of the least significant set bit in the 32-bit word. + * If LSB bit is set - return 1. + * If only MSB bit is set - return 32. + * Return 0 when no bit is set. + */ +int +ffs (i) + u_long i; +{ + if (i != 0) + i = 32 - mips_clz (i & -i); + return i; +} + +/* + * Copy a null terminated string from one point to another. + * Returns zero on success, ENOENT if maxlength exceeded. + * If lencopied is non-zero, *lencopied gets the length of the copy + * (including the null terminating byte). + */ +int +copystr (src, dest, maxlength, lencopied) + register caddr_t src, dest; + register u_int maxlength, *lencopied; +{ + caddr_t dest0 = dest; + int error = ENOENT; + + if (maxlength != 0) { + while ((*dest++ = *src++) != '\0') { + if (--maxlength == 0) { + /* Failed. */ + goto done; + } + } + /* Succeeded. */ + error = 0; + } +done: if (lencopied != 0) + *lencopied = dest - dest0; + return error; +} + +/* + * Calculate the length of a string. + */ +size_t +strlen (s) + register const char *s; +{ + const char *s0 = s; + + while (*s++ != '\0') + ; + return s - s0 - 1; +} + +/* + * Return 0 if a user address is valid. + * There are two memory regions allowed for user: flash and RAM. + */ +int +baduaddr (addr) + register caddr_t addr; +{ + if (addr >= (caddr_t) USER_FLASH_START && + addr < (caddr_t) USER_FLASH_END) + return 0; + if (addr >= (caddr_t) USER_DATA_START && + addr < (caddr_t) USER_DATA_END) + return 0; + return 1; +} + +/* + * Return 0 if a kernel address is valid. + * There is only one memory region allowed for kernel: RAM. + */ +int +badkaddr (addr) + register caddr_t addr; +{ + if (addr >= (caddr_t) KERNEL_DATA_START && + addr < (caddr_t) KERNEL_DATA_END) + return 0; + if (addr >= (caddr_t) KERNEL_FLASH_START && + addr < (caddr_t) KERNEL_FLASH_START + FLASH_SIZE) + return 0; + return 1; +} + +/* + * Insert the specified element into a queue immediately after + * the specified predecessor element. + */ +void insque (void *element, void *predecessor) +{ + struct que { + struct que *q_next; + struct que *q_prev; + }; + register struct que *e = (struct que *) element; + register struct que *prev = (struct que *) predecessor; + + e->q_prev = prev; + e->q_next = prev->q_next; + prev->q_next->q_prev = e; + prev->q_next = e; +} + +/* + * Remove the specified element from the queue. + */ +void remque (void *element) +{ + struct que { + struct que *q_next; + struct que *q_prev; + }; + register struct que *e = (struct que *) element; + + e->q_prev->q_next = e->q_next; + e->q_next->q_prev = e->q_prev; +} + +/* + * Compare strings. + */ +int strncmp (const char *s1, const char *s2, size_t n) +{ + register int ret, tmp; + + if (n == 0) + return 0; + do { + ret = *s1++ - (tmp = *s2++); + } while ((ret == 0) && (tmp != 0) && --n); + return ret; +} + +/* Nonzero if pointer is not aligned on a "sz" boundary. */ +#define UNALIGNED(p, sz) ((unsigned) (p) & ((sz) - 1)) + +/* + * Copy data from the memory region pointed to by src0 to the memory + * region pointed to by dst0. + * If the regions overlap, the behavior is undefined. + */ +void +bcopy (const void *src0, void *dst0, size_t nbytes) +{ + unsigned char *dst = dst0; + const unsigned char *src = src0; + unsigned *aligned_dst; + const unsigned *aligned_src; + +//printf ("bcopy (%08x, %08x, %d)\n", src0, dst0, nbytes); + /* If the size is small, or either SRC or DST is unaligned, + * then punt into the byte copy loop. This should be rare. */ + if (nbytes >= 4*sizeof(unsigned) && + ! UNALIGNED (src, sizeof(unsigned)) && + ! UNALIGNED (dst, sizeof(unsigned))) { + aligned_dst = (unsigned*) dst; + aligned_src = (const unsigned*) src; + + /* Copy 4X unsigned words at a time if possible. */ + while (nbytes >= 4*sizeof(unsigned)) { + *aligned_dst++ = *aligned_src++; + *aligned_dst++ = *aligned_src++; + *aligned_dst++ = *aligned_src++; + *aligned_dst++ = *aligned_src++; + nbytes -= 4*sizeof(unsigned); + } + + /* Copy one unsigned word at a time if possible. */ + while (nbytes >= sizeof(unsigned)) { + *aligned_dst++ = *aligned_src++; + nbytes -= sizeof(unsigned); + } + + /* Pick up any residual with a byte copier. */ + dst = (unsigned char*) aligned_dst; + src = (const unsigned char*) aligned_src; + } + + while (nbytes--) + *dst++ = *src++; +} + +void * +memcpy (void *dst, const void *src, size_t nbytes) +{ + bcopy (src, dst, nbytes); + return dst; +} + +/* + * Fill the array with zeroes. + */ +void +bzero (void *dst0, size_t nbytes) +{ + unsigned char *dst; + unsigned *aligned_dst; + + dst = (unsigned char*) dst0; + while (UNALIGNED (dst, sizeof(unsigned))) { + *dst++ = 0; + if (--nbytes == 0) + return; + } + if (nbytes >= sizeof(unsigned)) { + /* If we get this far, we know that nbytes is large and dst is word-aligned. */ + aligned_dst = (unsigned*) dst; + + while (nbytes >= 4*sizeof(unsigned)) { + *aligned_dst++ = 0; + *aligned_dst++ = 0; + *aligned_dst++ = 0; + *aligned_dst++ = 0; + nbytes -= 4*sizeof(unsigned); + } + while (nbytes >= sizeof(unsigned)) { + *aligned_dst++ = 0; + nbytes -= sizeof(unsigned); + } + dst = (unsigned char*) aligned_dst; + } + + /* Pick up the remainder with a bytewise loop. */ + while (nbytes--) + *dst++ = 0; +} + +/* + * Compare not more than nbytes of data pointed to by m1 with + * the data pointed to by m2. Return an integer greater than, equal to or + * less than zero according to whether the object pointed to by + * m1 is greater than, equal to or less than the object + * pointed to by m2. + */ +int +bcmp (const void *m1, const void *m2, size_t nbytes) +{ + const unsigned char *s1 = (const unsigned char*) m1; + const unsigned char *s2 = (const unsigned char*) m2; + const unsigned *aligned1, *aligned2; + + /* If the size is too small, or either pointer is unaligned, + * then we punt to the byte compare loop. Hopefully this will + * not turn up in inner loops. */ + if (nbytes >= 4*sizeof(unsigned) && + ! UNALIGNED (s1, sizeof(unsigned)) && + ! UNALIGNED (s2, sizeof(unsigned))) { + /* Otherwise, load and compare the blocks of memory one + word at a time. */ + aligned1 = (const unsigned*) s1; + aligned2 = (const unsigned*) s2; + while (nbytes >= sizeof(unsigned)) { + if (*aligned1 != *aligned2) + break; + aligned1++; + aligned2++; + nbytes -= sizeof(unsigned); + } + + /* check remaining characters */ + s1 = (const unsigned char*) aligned1; + s2 = (const unsigned char*) aligned2; + } + while (nbytes--) { + if (*s1 != *s2) + return *s1 - *s2; + s1++; + s2++; + } + return 0; +} + +int +copyout (caddr_t from, caddr_t to, u_int nbytes) +{ + //printf ("copyout (from=%p, to=%p, nbytes=%u)\n", from, to, nbytes); + if (baduaddr (to) || baduaddr (to + nbytes - 1)) + return EFAULT; + bcopy (from, to, nbytes); + return 0; +} + +int copyin (caddr_t from, caddr_t to, u_int nbytes) +{ + if (baduaddr (from) || baduaddr (from + nbytes - 1)) + return EFAULT; + bcopy (from, to, nbytes); + return 0; +} diff --git a/sys/pic32/machparam.h b/sys/pic32/machparam.h new file mode 100644 index 0000000..6a4b3ca --- /dev/null +++ b/sys/pic32/machparam.h @@ -0,0 +1,199 @@ +/* + * Machine dependent constants for MIPS32. + * + * Copyright (c) 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#ifndef ENDIAN + +/* + * Definitions for byte order, + * according to byte significance from low address to high. + */ +#define LITTLE 1234 /* least-significant byte first (vax) */ +#define BIG 4321 /* most-significant byte first */ +#define PDP 3412 /* LSB first in word, MSW first in long (pdp) */ +#define ENDIAN LITTLE /* byte order on pic32 */ + +/* + * The time for a process to be blocked before being very swappable. + * This is a number of seconds which the system takes as being a non-trivial + * amount of real time. You probably shouldn't change this; + * it is used in subtle ways (fractions and multiples of it are, that is, like + * half of a ``long time'', almost a long time, etc.) + * It is related to human patience and other factors which don't really + * change over time. + */ +#define MAXSLP 20 + +/* + * Clock ticks per second. The HZ value must be an integer factor of 1000. + */ +#ifndef HZ +#define HZ 200 +#endif + +/* + * System parameter formulae. + */ +#ifndef NBUF +#define NBUF 10 /* number of i/o buffers */ +#endif +#define MAXUSERS 1 /* number of user logins */ +#ifndef NPROC +#define NPROC 10 /* number of processes */ +#endif +#ifndef NINODE +#define NINODE 24 +#endif +#ifndef NFILE +#define NFILE 24 +#endif +#define NNAMECACHE (NINODE * 11/10) +#define NCALL (16 + 2 * MAXUSERS) +#define NCLIST 32 /* number or CBSIZE blocks */ +#ifndef SMAPSIZ +#define SMAPSIZ NPROC /* size of swap allocation map */ +#endif + +/* + * Disk blocks. + */ +#define DEV_BSIZE 1024 /* the same as MAXBSIZE */ +#define DEV_BSHIFT 10 /* log2(DEV_BSIZE) */ +#define DEV_BMASK (DEV_BSIZE-1) + +/* Bytes to disk blocks */ +#define btod(x) (((x) + DEV_BSIZE-1) >> DEV_BSHIFT) + +/* + * On PIC32, there are total 512 kbytes of flash and 128 kbytes of RAM. + * We reserve for kernel 192 kbytes of flash and 32 kbytes of RAM. + */ +#define FLASH_SIZE (512*1024) +#define DATA_SIZE (128*1024) + +#define KERNEL_FLASH_SIZE (192*1024) + +#ifdef KERNEL_EXECUTABLE_RAM +extern void _keram_start(), _keram_end(); +#define KERAM_SIZE ((unsigned)((char*)&_keram_end-(char*)&_keram_start)) +#define KERNEL_DATA_SIZE (32*1024-KERAM_SIZE) +#else +#define KERNEL_DATA_SIZE (32*1024) +#endif + +#define KERNEL_FLASH_START 0x9d000000 +#define USER_FLASH_START (KERNEL_FLASH_START + KERNEL_FLASH_SIZE) +#define USER_FLASH_END (KERNEL_FLASH_START + FLASH_SIZE) + +#define KERNEL_DATA_START 0x80000000 +#define KERNEL_DATA_END (KERNEL_DATA_START + KERNEL_DATA_SIZE) + +#ifdef KERNEL_EXECUTABLE_RAM +#define USER_DATA_START (0x7f000000 + KERNEL_DATA_SIZE+KERAM_SIZE) +#else +#define USER_DATA_START (0x7f000000 + KERNEL_DATA_SIZE) +#endif + +#define USER_DATA_END (0x7f000000 + DATA_SIZE) + +#define stacktop(siz) (USER_DATA_END) +#define stackbas(siz) (USER_DATA_END-(siz)) + +/* + * User area: a user structure, followed by the kernel + * stack. The number for USIZE is determined empirically. + * + * Note that the SBASE and STOP constants are only used by the assembly code, + * but are defined here to localize information about the user area's + * layout (see pdp/genassym.c). Note also that a networking stack is always + * allocated even for non-networking systems. This prevents problems with + * applications having to be recompiled for networking versus non-networking + * systems. + */ +#define USIZE 3072 +#define SSIZE 2048 /* initial stack size (bytes) */ + +#ifdef KERNEL +#include "machine/io.h" + +/* + * Macros to decode processor status word. + */ +#define USERMODE(ps) (((ps) & ST_UM) != 0) +#define BASEPRI(ps) (CA_RIPL(ps) == 0) + +#define splbio() mips_intr_disable () +#define spltty() mips_intr_disable () +#define splclock() mips_intr_disable () +#define splhigh() mips_intr_disable () +#define splnet() mips_intr_enable () +#define splsoftclock() mips_intr_enable () +#define spl0() mips_intr_enable () +#define splx(s) mips_intr_restore (s) + +#define noop() asm volatile ("nop") + +/* + * Wait for something to happen. + */ +void idle (void); + +/* + * Microsecond delay routine. + */ +void udelay (unsigned usec); + +/* + * Setup system timer for `hz' timer interrupts per second. + */ +void clkstart (void); + +/* + * Control LEDs, installed on the board. + */ +#define LED_MISC4 0x80 +#define LED_MISC3 0x40 +#define LED_MISC2 0x20 +#define LED_MISC1 0x10 +#define LED_TTY 0x08 +#define LED_SWAP 0x04 +#define LED_DISK 0x02 +#define LED_KERNEL 0x01 + +void led_control (int mask, int on); + +/* + * Port i/o access, relative to TRIS base. + */ +#define TRIS_VAL(p) (&p)[0] +#define TRIS_CLR(p) (&p)[1] +#define TRIS_SET(p) (&p)[2] +#define TRIS_INV(p) (&p)[3] +#define PORT_VAL(p) (&p)[4] +#define PORT_CLR(p) (&p)[5] +#define PORT_SET(p) (&p)[6] +#define PORT_INV(p) (&p)[7] +#define LAT_VAL(p) (&p)[8] +#define LAT_CLR(p) (&p)[9] +#define LAT_SET(p) (&p)[10] +#define LAT_INV(p) (&p)[11] + +/* + * SD timeouts, for sysctl. + */ +extern int sd_timo_cmd; +extern int sd_timo_send_op; +extern int sd_timo_send_csd; +extern int sd_timo_read; +extern int sd_timo_wait_cmd; +extern int sd_timo_wait_wdata; +extern int sd_timo_wait_wdone; +extern int sd_timo_wait_wstop; +extern int sd_timo_wait_widle; + +#endif /* KERNEL */ + +#endif /* ENDIAN */ diff --git a/sys/pic32/max32-eth/MAX32-ETH b/sys/pic32/max32-eth/MAX32-ETH new file mode 100644 index 0000000..5f293b5 --- /dev/null +++ b/sys/pic32/max32-eth/MAX32-ETH @@ -0,0 +1,25 @@ +# +# Max32 board with Arduino Ethernet shield +# ======================================== +# +# Console on UART1 +# SD/MMC card driver on SPI2 + +core pic32mx7 +mapping max32 +linker bootloader-max32 + +device kernel led=LED cpu_khz=80000 bus_khz=80000 + +device console device=tty0 +device uart1 baud=115200 +device uart2 baud=115200 +device uart3 baud=115200 +device uart4 baud=115200 + +device sd0 port=2 cs=4 +device gpio +device spi +device adc + +device foreignbootloader diff --git a/sys/pic32/max32-eth/Makefile b/sys/pic32/max32-eth/Makefile new file mode 100644 index 0000000..47e7b66 --- /dev/null +++ b/sys/pic32/max32-eth/Makefile @@ -0,0 +1,70 @@ +BUILDPATH = ../../../tools/configsys/../../sys/pic32 +H = ../../../tools/configsys/../../sys/include +M = ../../../tools/configsys/../../sys/pic32 +S = ../../../tools/configsys/../../sys/kernel + +vpath %.c $(M):$(S) +vpath %.S $(M):$(S) + +KERNOBJ += _startup.o adc.o clock.o cons.o devsw.o exception.o gpio.o init_main.o init_sysent.o kern_clock.o kern_descrip.o kern_exec.o kern_exit.o kern_fork.o kern_mman.o kern_proc.o kern_prot.o kern_prot2.o kern_resource.o kern_sig.o kern_sig2.o kern_subr.o kern_synch.o kern_sysctl.o kern_time.o machdep.o mem.o rd_sd.o rdisk.o signal.o spi.o spi_bus.o subr_prf.o subr_rmap.o swap.o sys_generic.o sys_inode.o sys_pipe.o sys_process.o syscalls.o sysctl.o tty.o tty_subr.o tty_tty.o uart.o ufs_alloc.o ufs_bio.o ufs_bmap.o ufs_dsort.o ufs_fio.o ufs_inode.o ufs_mount.o ufs_namei.o ufs_subr.o ufs_syscalls.o ufs_syscalls2.o vers.o vfs_vnops.o vm_sched.o vm_swap.o vm_swp.o +EXTRA_TARGETS = + +DEFS += -DADC_ENABLED=YES +DEFS += -DBUS_DIV=1 +DEFS += -DBUS_KHZ=80000 +DEFS += -DCONSOLE_DEVICE=tty0 +DEFS += -DCPU_IDIV=2 +DEFS += -DCPU_KHZ=80000 +DEFS += -DCPU_MUL=20 +DEFS += -DCPU_ODIV=1 +DEFS += -DCRYSTAL=8 +DEFS += -DDC0_DEBUG=DEVCFG0_DEBUG_DISABLED +DEFS += -DDC0_ICE=0 +DEFS += -DDC1_CKM=0 +DEFS += -DDC1_CKS=0 +DEFS += -DDC1_FNOSC=DEVCFG1_FNOSC_PRIPLL +DEFS += -DDC1_IESO=DEVCFG1_IESO +DEFS += -DDC1_OSCIOFNC=0 +DEFS += -DDC1_PBDIV=DEVCFG1_FPBDIV_1 +DEFS += -DDC1_POSCMOD=DEVCFG1_POSCMOD_HS +DEFS += -DDC1_SOSC=0 +DEFS += -DDC1_WDTEN=0 +DEFS += -DDC1_WDTPS=DEVCFG1_WDTPS_1 +DEFS += -DDC2_PLLIDIV=DEVCFG2_FPLLIDIV_2 +DEFS += -DDC2_PLLMUL=DEVCFG2_FPLLMUL_20 +DEFS += -DDC2_PLLODIV=DEVCFG2_FPLLODIV_1 +DEFS += -DDC2_UPLL=0 +DEFS += -DDC2_UPLLIDIV=DEVCFG2_UPLLIDIV_2 +DEFS += -DDC3_CAN=DEVCFG3_FCANIO +DEFS += -DDC3_ETH=DEVCFG3_FETHIO +DEFS += -DDC3_MII=DEVCFG3_FMIIEN +DEFS += -DDC3_SRS=DEVCFG3_FSRSSEL_7 +DEFS += -DDC3_USBID=DEVCFG3_FUSBIDIO +DEFS += -DDC3_USERID=0xffff +DEFS += -DDC3_VBUSON=DEVCFG3_FVBUSONIO +DEFS += -DGPIO_ENABLED=YES +DEFS += -DKERNEL +DEFS += -DLED_KERNEL_PIN=3 +DEFS += -DLED_KERNEL_PORT=TRISA +DEFS += -DPIC32MX7 +DEFS += -DSD0_CS_PIN=14 +DEFS += -DSD0_CS_PORT=TRISC +DEFS += -DSD0_PORT=2 +DEFS += -DSPI_ENABLED=YES +DEFS += -DUART1_BAUD=115200 +DEFS += -DUART1_ENABLED=YES +DEFS += -DUART2_BAUD=115200 +DEFS += -DUART2_ENABLED=YES +DEFS += -DUART3_BAUD=115200 +DEFS += -DUART3_ENABLED=YES +DEFS += -DUART4_BAUD=115200 +DEFS += -DUART4_ENABLED=YES +DEFS += -DUCB_METER + + +LDSCRIPT = ../../../tools/configsys/../../sys/pic32/cfg/bootloader-max32.ld + +CONFIG = MAX32-ETH +CONFIGPATH = ../../../tools/configsys + +include ../../../tools/configsys/../../sys/pic32/kernel-post.mk diff --git a/sys/pic32/max32-eth/using-bootloader.ld b/sys/pic32/max32-eth/using-bootloader.ld new file mode 100644 index 0000000..189e51b --- /dev/null +++ b/sys/pic32/max32-eth/using-bootloader.ld @@ -0,0 +1,115 @@ +/* + * Linker script for PIC32 firmware using HID bootloader. + */ +OUTPUT_FORMAT("elf32-littlemips", "elf32-bigmips", + "elf32-littlemips") +OUTPUT_ARCH(mips) +ENTRY(_reset_vector_) +MEMORY +{ + flash (rx) : ORIGIN = 0x9d000000, LENGTH = 512K + ram (rw!x): ORIGIN = 0x80000000, LENGTH = 26K + u0area (rw!x): ORIGIN = 0x80006800, LENGTH = 3K + uarea (rw!x): ORIGIN = 0x80007400, LENGTH = 3K + + /* Required by Microchip C32 linker */ + kseg0_program_mem (rx) : ORIGIN = 0x9D000000, LENGTH = 0x80000 + kseg0_boot_mem : ORIGIN = 0x9FC00490, LENGTH = 0x970 + exception_mem : ORIGIN = 0x9FC01000, LENGTH = 0x1000 + kseg1_boot_mem : ORIGIN = 0xBFC00000, LENGTH = 0x490 + kseg1_data_mem (w!x) : ORIGIN = 0xA0000000, LENGTH = 0x20000 +} + +/* higher address of the user mode stack */ +u0 = ORIGIN(u0area); +u = ORIGIN(uarea); +u_end = ORIGIN(uarea) + LENGTH(uarea); + +SECTIONS +{ + .text ORIGIN(flash) : + { + /* Exception handlers. */ + *(.exception) + . = 0x1000; + /* Execution starts here. */ + *(.startup) + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.glue_7t) *(.glue_7) + __rodata_start = . ; + *(.rodata .rodata.* .gnu.linkonce.r.* .rel.dyn) + *(.dinit) + /* Align here to ensure that the .text section ends on word boundary. */ + . = ALIGN (32 / 8); + _etext = .; + } > flash + + /* Start data (internal SRAM). */ + .data : AT (ADDR (.text) + SIZEOF (.text)) + { + __data_start = . ; + _gp = .; /* We use only 32k RAM for kernel, so no need for 0x8000 offset. */ + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + *(.sdata .sdata.* .gnu.linkonce.s.*) + *(.data .data.* .gnu.linkonce.d.*) + *(.eh_frame) + _edata = .; + } > ram + + .bss ADDR (.data) + SIZEOF (.data) (NOLOAD) : + { + __bss_start = .; + *(.dynbss) + *(.sbss .sbss.*) + *(.scommon) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. */ + . = ALIGN (32 / 8); + } > ram + __bss_end = . ; + _end = .; + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + .debug_pubtypes 0 : { *(.debug_pubtypes) } + .debug_ranges 0 : { *(.debug_ranges) } + .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) } +} diff --git a/sys/pic32/max32/MAX32 b/sys/pic32/max32/MAX32 new file mode 100644 index 0000000..668bf9d --- /dev/null +++ b/sys/pic32/max32/MAX32 @@ -0,0 +1,21 @@ +# MAX32 board + +core pic32mx7 +linker bootloader-max32 +mapping max32 +device kernel led=12 cpu_khz=80000 bus_khz=80000 + +device console device=tty0 led=LED +device uart1 baud=115200 +#device uart2 baud=115200 +#device uart3 baud=115200 +#device uart4 baud=115200 + +device rdisk led=44 +device sd0 port=4 cs=9 +device sd1 port=4 cs=10 + +device gpio +device adc + +device foreignbootloader diff --git a/sys/pic32/max32/MAX32-ETH b/sys/pic32/max32/MAX32-ETH new file mode 100644 index 0000000..e69de29 diff --git a/sys/pic32/max32/Makefile b/sys/pic32/max32/Makefile new file mode 100644 index 0000000..6875356 --- /dev/null +++ b/sys/pic32/max32/Makefile @@ -0,0 +1,70 @@ +BUILDPATH = ../../../tools/configsys/../../sys/pic32 +H = ../../../tools/configsys/../../sys/include +M = ../../../tools/configsys/../../sys/pic32 +S = ../../../tools/configsys/../../sys/kernel + +vpath %.c $(M):$(S) +vpath %.S $(M):$(S) + +KERNOBJ += _startup.o adc.o clock.o cons.o devsw.o exception.o gpio.o init_main.o init_sysent.o kern_clock.o kern_descrip.o kern_exec.o kern_exit.o kern_fork.o kern_mman.o kern_proc.o kern_prot.o kern_prot2.o kern_resource.o kern_sig.o kern_sig2.o kern_subr.o kern_synch.o kern_sysctl.o kern_time.o machdep.o mem.o rd_sd.o rdisk.o signal.o spi_bus.o subr_prf.o subr_rmap.o swap.o sys_generic.o sys_inode.o sys_pipe.o sys_process.o syscalls.o sysctl.o tty.o tty_subr.o tty_tty.o uart.o ufs_alloc.o ufs_bio.o ufs_bmap.o ufs_dsort.o ufs_fio.o ufs_inode.o ufs_mount.o ufs_namei.o ufs_subr.o ufs_syscalls.o ufs_syscalls2.o vers.o vfs_vnops.o vm_sched.o vm_swap.o vm_swp.o +EXTRA_TARGETS = + +DEFS += -DADC_ENABLED=YES +DEFS += -DBUS_DIV=1 +DEFS += -DBUS_KHZ=80000 +DEFS += -DCONSOLE_DEVICE=tty0 +DEFS += -DCPU_IDIV=2 +DEFS += -DCPU_KHZ=80000 +DEFS += -DCPU_MUL=20 +DEFS += -DCPU_ODIV=1 +DEFS += -DCRYSTAL=8 +DEFS += -DDC0_DEBUG=DEVCFG0_DEBUG_DISABLED +DEFS += -DDC0_ICE=0 +DEFS += -DDC1_CKM=0 +DEFS += -DDC1_CKS=0 +DEFS += -DDC1_FNOSC=DEVCFG1_FNOSC_PRIPLL +DEFS += -DDC1_IESO=DEVCFG1_IESO +DEFS += -DDC1_OSCIOFNC=0 +DEFS += -DDC1_PBDIV=DEVCFG1_FPBDIV_1 +DEFS += -DDC1_POSCMOD=DEVCFG1_POSCMOD_HS +DEFS += -DDC1_SOSC=0 +DEFS += -DDC1_WDTEN=0 +DEFS += -DDC1_WDTPS=DEVCFG1_WDTPS_1 +DEFS += -DDC2_PLLIDIV=DEVCFG2_FPLLIDIV_2 +DEFS += -DDC2_PLLMUL=DEVCFG2_FPLLMUL_20 +DEFS += -DDC2_PLLODIV=DEVCFG2_FPLLODIV_1 +DEFS += -DDC2_UPLL=0 +DEFS += -DDC2_UPLLIDIV=DEVCFG2_UPLLIDIV_2 +DEFS += -DDC3_CAN=DEVCFG3_FCANIO +DEFS += -DDC3_ETH=DEVCFG3_FETHIO +DEFS += -DDC3_MII=DEVCFG3_FMIIEN +DEFS += -DDC3_SRS=DEVCFG3_FSRSSEL_7 +DEFS += -DDC3_USBID=DEVCFG3_FUSBIDIO +DEFS += -DDC3_USERID=0xffff +DEFS += -DDC3_VBUSON=DEVCFG3_FVBUSONIO +DEFS += -DGPIO_ENABLED=YES +DEFS += -DKERNEL +DEFS += -DLED_DISK_PIN=10 +DEFS += -DLED_DISK_PORT=TRISA +DEFS += -DLED_KERNEL_PIN=2 +DEFS += -DLED_KERNEL_PORT=TRISA +DEFS += -DLED_TTY_PIN=3 +DEFS += -DLED_TTY_PORT=TRISA +DEFS += -DPIC32MX7 +DEFS += -DSD0_CS_PIN=3 +DEFS += -DSD0_CS_PORT=TRISD +DEFS += -DSD0_PORT=4 +DEFS += -DSD1_CS_PIN=4 +DEFS += -DSD1_CS_PORT=TRISD +DEFS += -DSD1_PORT=4 +DEFS += -DUART1_BAUD=115200 +DEFS += -DUART1_ENABLED=YES +DEFS += -DUCB_METER + + +LDSCRIPT = ../../../tools/configsys/../../sys/pic32/cfg/bootloader-max32.ld + +CONFIG = MAX32 +CONFIGPATH = ../../../tools/configsys + +include ../../../tools/configsys/../../sys/pic32/kernel-post.mk diff --git a/sys/pic32/max32/using-bootloader.ld b/sys/pic32/max32/using-bootloader.ld new file mode 100644 index 0000000..189e51b --- /dev/null +++ b/sys/pic32/max32/using-bootloader.ld @@ -0,0 +1,115 @@ +/* + * Linker script for PIC32 firmware using HID bootloader. + */ +OUTPUT_FORMAT("elf32-littlemips", "elf32-bigmips", + "elf32-littlemips") +OUTPUT_ARCH(mips) +ENTRY(_reset_vector_) +MEMORY +{ + flash (rx) : ORIGIN = 0x9d000000, LENGTH = 512K + ram (rw!x): ORIGIN = 0x80000000, LENGTH = 26K + u0area (rw!x): ORIGIN = 0x80006800, LENGTH = 3K + uarea (rw!x): ORIGIN = 0x80007400, LENGTH = 3K + + /* Required by Microchip C32 linker */ + kseg0_program_mem (rx) : ORIGIN = 0x9D000000, LENGTH = 0x80000 + kseg0_boot_mem : ORIGIN = 0x9FC00490, LENGTH = 0x970 + exception_mem : ORIGIN = 0x9FC01000, LENGTH = 0x1000 + kseg1_boot_mem : ORIGIN = 0xBFC00000, LENGTH = 0x490 + kseg1_data_mem (w!x) : ORIGIN = 0xA0000000, LENGTH = 0x20000 +} + +/* higher address of the user mode stack */ +u0 = ORIGIN(u0area); +u = ORIGIN(uarea); +u_end = ORIGIN(uarea) + LENGTH(uarea); + +SECTIONS +{ + .text ORIGIN(flash) : + { + /* Exception handlers. */ + *(.exception) + . = 0x1000; + /* Execution starts here. */ + *(.startup) + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.glue_7t) *(.glue_7) + __rodata_start = . ; + *(.rodata .rodata.* .gnu.linkonce.r.* .rel.dyn) + *(.dinit) + /* Align here to ensure that the .text section ends on word boundary. */ + . = ALIGN (32 / 8); + _etext = .; + } > flash + + /* Start data (internal SRAM). */ + .data : AT (ADDR (.text) + SIZEOF (.text)) + { + __data_start = . ; + _gp = .; /* We use only 32k RAM for kernel, so no need for 0x8000 offset. */ + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + *(.sdata .sdata.* .gnu.linkonce.s.*) + *(.data .data.* .gnu.linkonce.d.*) + *(.eh_frame) + _edata = .; + } > ram + + .bss ADDR (.data) + SIZEOF (.data) (NOLOAD) : + { + __bss_start = .; + *(.dynbss) + *(.sbss .sbss.*) + *(.scommon) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. */ + . = ALIGN (32 / 8); + } > ram + __bss_end = . ; + _end = .; + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + .debug_pubtypes 0 : { *(.debug_pubtypes) } + .debug_ranges 0 : { *(.debug_ranges) } + .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) } +} diff --git a/sys/pic32/maximite-color/MAXCOLOR b/sys/pic32/maximite-color/MAXCOLOR new file mode 100644 index 0000000..8d29d77 --- /dev/null +++ b/sys/pic32/maximite-color/MAXCOLOR @@ -0,0 +1,23 @@ +# +# Maximite board +# ============== +# +# Console on USB +# For Windows, use the driver: +# http://geoffg.net/Downloads/BoatComputer/Silicon_Chip_USB_Serial_Port_Driver.zip + +core pic32mx7 +mapping generic +linker bootloader-maxcolor + +device kernel invled=E0 + +device console device=ttyUSB0 +device uartusb + +device rdisk led=E1 +device sd0 port=4 cs=A1 + +device gpio + +device bootloader button=C13 user=0x1d005000 led=E1 diff --git a/sys/pic32/maximite-color/Makefile b/sys/pic32/maximite-color/Makefile new file mode 100644 index 0000000..2629593 --- /dev/null +++ b/sys/pic32/maximite-color/Makefile @@ -0,0 +1,78 @@ +BUILDPATH = ../../../tools/configsys/../../sys/pic32 +H = ../../../tools/configsys/../../sys/include +M = ../../../tools/configsys/../../sys/pic32 +S = ../../../tools/configsys/../../sys/kernel + +vpath %.c $(M):$(S) +vpath %.S $(M):$(S) + +KERNOBJ += _startup.o clock.o cons.o devsw.o exception.o gpio.o init_main.o init_sysent.o kern_clock.o kern_descrip.o kern_exec.o kern_exit.o kern_fork.o kern_mman.o kern_proc.o kern_prot.o kern_prot2.o kern_resource.o kern_sig.o kern_sig2.o kern_subr.o kern_synch.o kern_sysctl.o kern_time.o machdep.o mem.o rd_sd.o rdisk.o signal.o spi_bus.o subr_prf.o subr_rmap.o swap.o sys_generic.o sys_inode.o sys_pipe.o sys_process.o syscalls.o sysctl.o tty.o tty_subr.o tty_tty.o ufs_alloc.o ufs_bio.o ufs_bmap.o ufs_dsort.o ufs_fio.o ufs_inode.o ufs_mount.o ufs_namei.o ufs_subr.o ufs_syscalls.o ufs_syscalls2.o usb_device.o usb_function_cdc.o usb_uart.o vers.o vfs_vnops.o vm_sched.o vm_swap.o vm_swp.o +EXTRA_TARGETS = bootloader + +DEFS += -DBL_BUTTON_PIN=13 +DEFS += -DBL_BUTTON_PORT=TRISC +DEFS += -DBL_LED_PIN=1 +DEFS += -DBL_LED_PORT=TRISE +DEFS += -DBUS_DIV=1 +DEFS += -DBUS_KHZ='CPU_KHZ/BUS_DIV' +DEFS += -DCONSOLE_DEVICE=ttyUSB0 +DEFS += -DCPU_IDIV=2 +DEFS += -DCPU_KHZ='((CRYSTAL*1000)/CPU_IDIV*CPU_MUL/CPU_ODIV)' +DEFS += -DCPU_MUL=20 +DEFS += -DCPU_ODIV=1 +DEFS += -DCRYSTAL=8 +DEFS += -DDC0_DEBUG=DEVCFG0_DEBUG_DISABLED +DEFS += -DDC0_ICE=0 +DEFS += -DDC1_CKM=0 +DEFS += -DDC1_CKS=0 +DEFS += -DDC1_FNOSC=DEVCFG1_FNOSC_PRIPLL +DEFS += -DDC1_IESO=DEVCFG1_IESO +DEFS += -DDC1_OSCIOFNC=0 +DEFS += -DDC1_PBDIV=DEVCFG1_FPBDIV_1 +DEFS += -DDC1_POSCMOD=DEVCFG1_POSCMOD_HS +DEFS += -DDC1_SOSC=0 +DEFS += -DDC1_WDTEN=0 +DEFS += -DDC1_WDTPS=DEVCFG1_WDTPS_1 +DEFS += -DDC2_PLLIDIV=DEVCFG2_FPLLIDIV_2 +DEFS += -DDC2_PLLMUL=DEVCFG2_FPLLMUL_20 +DEFS += -DDC2_PLLODIV=DEVCFG2_FPLLODIV_1 +DEFS += -DDC2_UPLL=0 +DEFS += -DDC2_UPLLIDIV=DEVCFG2_UPLLIDIV_2 +DEFS += -DDC3_CAN=DEVCFG3_FCANIO +DEFS += -DDC3_ETH=DEVCFG3_FETHIO +DEFS += -DDC3_MII=DEVCFG3_FMIIEN +DEFS += -DDC3_SRS=DEVCFG3_FSRSSEL_7 +DEFS += -DDC3_USBID=DEVCFG3_FUSBIDIO +DEFS += -DDC3_USERID=0xffff +DEFS += -DDC3_VBUSON=DEVCFG3_FVBUSONIO +DEFS += -DFLASH_USER=0x1d005000 +DEFS += -DGPIO_ENABLED=YES +DEFS += -DHID_FEATURE_REPORT_BYTES=2 +DEFS += -DHID_INPUT_REPORT_BYTES=2 +DEFS += -DHID_INT_IN_EP_SIZE=64 +DEFS += -DHID_INT_OUT_EP_SIZE=64 +DEFS += -DHID_OUTPUT_REPORT_BYTES=2 +DEFS += -DHID_RPT01_SIZE=29 +DEFS += -DKERNEL +DEFS += -DLED_DISK_PIN=1 +DEFS += -DLED_DISK_PORT=TRISE +DEFS += -DLED_KERNEL_INVERT=YES +DEFS += -DLED_KERNEL_PIN=0 +DEFS += -DLED_KERNEL_PORT=TRISE +DEFS += -DPIC32MX7 +DEFS += -DSD0_CS_PIN=1 +DEFS += -DSD0_CS_PORT=TRISA +DEFS += -DSD0_PORT=4 +DEFS += -DUARTUSB_ENABLED=YES +DEFS += -DUCB_METER +DEFS += -DUSB_EP0_BUFF_SIZE=8 +DEFS += -DUSB_MAX_EP_NUMBER=3 +DEFS += -DUSB_NUM_STRING_DESCRIPTORS=3 + + +LDSCRIPT = ../../../tools/configsys/../../sys/pic32/cfg/bootloader-maxcolor.ld + +CONFIG = MAXCOLOR +CONFIGPATH = ../../../tools/configsys + +include ../../../tools/configsys/../../sys/pic32/kernel-post.mk diff --git a/sys/pic32/maximite/MAXIMITE b/sys/pic32/maximite/MAXIMITE new file mode 100644 index 0000000..46d6731 --- /dev/null +++ b/sys/pic32/maximite/MAXIMITE @@ -0,0 +1,23 @@ +# +# Maximite board +# ============== +# +# Console on USB +# For Windows, use the driver: +# http://geoffg.net/Downloads/BoatComputer/Silicon_Chip_USB_Serial_Port_Driver.zip + +core pic32mx7 +mapping generic +linker bootloader-maximite + +device kernel invled=F0 + +device console device=ttyUSB0 +device uartusb + +device rdisk led=E1 +device sd0 port=4 cs=E0 + +device gpio + +device bootloader button=C13 user=0x1d003000 led=E1 clear=F0 diff --git a/sys/pic32/maximite/Makefile b/sys/pic32/maximite/Makefile new file mode 100644 index 0000000..bdf7c81 --- /dev/null +++ b/sys/pic32/maximite/Makefile @@ -0,0 +1,80 @@ +BUILDPATH = ../../../tools/configsys/../../sys/pic32 +H = ../../../tools/configsys/../../sys/include +M = ../../../tools/configsys/../../sys/pic32 +S = ../../../tools/configsys/../../sys/kernel + +vpath %.c $(M):$(S) +vpath %.S $(M):$(S) + +KERNOBJ += _startup.o clock.o cons.o devsw.o exception.o gpio.o init_main.o init_sysent.o kern_clock.o kern_descrip.o kern_exec.o kern_exit.o kern_fork.o kern_mman.o kern_proc.o kern_prot.o kern_prot2.o kern_resource.o kern_sig.o kern_sig2.o kern_subr.o kern_synch.o kern_sysctl.o kern_time.o machdep.o mem.o rd_sd.o rdisk.o signal.o spi_bus.o subr_prf.o subr_rmap.o swap.o sys_generic.o sys_inode.o sys_pipe.o sys_process.o syscalls.o sysctl.o tty.o tty_subr.o tty_tty.o ufs_alloc.o ufs_bio.o ufs_bmap.o ufs_dsort.o ufs_fio.o ufs_inode.o ufs_mount.o ufs_namei.o ufs_subr.o ufs_syscalls.o ufs_syscalls2.o usb_device.o usb_function_cdc.o usb_uart.o vers.o vfs_vnops.o vm_sched.o vm_swap.o vm_swp.o +EXTRA_TARGETS = bootloader + +DEFS += -DBL_BUTTON_PIN=13 +DEFS += -DBL_BUTTON_PORT=TRISC +DEFS += -DBL_CLEAR_PIN=0 +DEFS += -DBL_CLEAR_PORT=TRISF +DEFS += -DBL_LED_PIN=1 +DEFS += -DBL_LED_PORT=TRISE +DEFS += -DBUS_DIV=1 +DEFS += -DBUS_KHZ='CPU_KHZ/BUS_DIV' +DEFS += -DCONSOLE_DEVICE=ttyUSB0 +DEFS += -DCPU_IDIV=2 +DEFS += -DCPU_KHZ='((CRYSTAL*1000)/CPU_IDIV*CPU_MUL/CPU_ODIV)' +DEFS += -DCPU_MUL=20 +DEFS += -DCPU_ODIV=1 +DEFS += -DCRYSTAL=8 +DEFS += -DDC0_DEBUG=DEVCFG0_DEBUG_DISABLED +DEFS += -DDC0_ICE=0 +DEFS += -DDC1_CKM=0 +DEFS += -DDC1_CKS=0 +DEFS += -DDC1_FNOSC=DEVCFG1_FNOSC_PRIPLL +DEFS += -DDC1_IESO=DEVCFG1_IESO +DEFS += -DDC1_OSCIOFNC=0 +DEFS += -DDC1_PBDIV=DEVCFG1_FPBDIV_1 +DEFS += -DDC1_POSCMOD=DEVCFG1_POSCMOD_HS +DEFS += -DDC1_SOSC=0 +DEFS += -DDC1_WDTEN=0 +DEFS += -DDC1_WDTPS=DEVCFG1_WDTPS_1 +DEFS += -DDC2_PLLIDIV=DEVCFG2_FPLLIDIV_2 +DEFS += -DDC2_PLLMUL=DEVCFG2_FPLLMUL_20 +DEFS += -DDC2_PLLODIV=DEVCFG2_FPLLODIV_1 +DEFS += -DDC2_UPLL=0 +DEFS += -DDC2_UPLLIDIV=DEVCFG2_UPLLIDIV_2 +DEFS += -DDC3_CAN=DEVCFG3_FCANIO +DEFS += -DDC3_ETH=DEVCFG3_FETHIO +DEFS += -DDC3_MII=DEVCFG3_FMIIEN +DEFS += -DDC3_SRS=DEVCFG3_FSRSSEL_7 +DEFS += -DDC3_USBID=DEVCFG3_FUSBIDIO +DEFS += -DDC3_USERID=0xffff +DEFS += -DDC3_VBUSON=DEVCFG3_FVBUSONIO +DEFS += -DFLASH_USER=0x1d003000 +DEFS += -DGPIO_ENABLED=YES +DEFS += -DHID_FEATURE_REPORT_BYTES=2 +DEFS += -DHID_INPUT_REPORT_BYTES=2 +DEFS += -DHID_INT_IN_EP_SIZE=64 +DEFS += -DHID_INT_OUT_EP_SIZE=64 +DEFS += -DHID_OUTPUT_REPORT_BYTES=2 +DEFS += -DHID_RPT01_SIZE=29 +DEFS += -DKERNEL +DEFS += -DLED_DISK_PIN=1 +DEFS += -DLED_DISK_PORT=TRISE +DEFS += -DLED_KERNEL_INVERT=YES +DEFS += -DLED_KERNEL_PIN=0 +DEFS += -DLED_KERNEL_PORT=TRISF +DEFS += -DPIC32MX7 +DEFS += -DSD0_CS_PIN=0 +DEFS += -DSD0_CS_PORT=TRISE +DEFS += -DSD0_PORT=4 +DEFS += -DUARTUSB_ENABLED=YES +DEFS += -DUCB_METER +DEFS += -DUSB_EP0_BUFF_SIZE=8 +DEFS += -DUSB_MAX_EP_NUMBER=3 +DEFS += -DUSB_NUM_STRING_DESCRIPTORS=3 + + +LDSCRIPT = ../../../tools/configsys/../../sys/pic32/cfg/bootloader-maximite.ld + +CONFIG = MAXIMITE +CONFIGPATH = ../../../tools/configsys + +include ../../../tools/configsys/../../sys/pic32/kernel-post.mk diff --git a/sys/pic32/maximite/kbd.c b/sys/pic32/maximite/kbd.c new file mode 100644 index 0000000..2d57e3c --- /dev/null +++ b/sys/pic32/maximite/kbd.c @@ -0,0 +1,263 @@ +/* + * + * RetroBSD - PS2 keyboard driver for the Maximite PIC32 board + * + * Copyright (C) 2011 Rob Judd + * All rights reserved. The three clause ("New" or "Modified") + * Berkeley software License Agreement specifies the terms and + * conditions for redistribution. + * + */ + +/* +../kbd.c: In function 'initKBD': +../kbd.c:155:8: error: request for member 'ON' in something not a structure or union +../kbd.c:156:8: error: request for member 'CNPUE15' in something not a structure or union +../kbd.c:157:8: error: request for member 'CNPUE16' in something not a structure or union +../kbd.c: In function 'readKBD': +../kbd.c:173:9: error: request for member 'RD7' in something not a structure or union +../kbd.c:174:9: error: request for member 'RD6' in something not a structure or union + * + * This driver uses a 20uS timer, probably too fast + */ + +#include "sys/types.h" +#include "machine/io.h" +#include "kbd.h" + +//#define TRACE printf +#ifndef TRACE +#define TRACE(...) +#endif + +// I2C registers +struct kbdreg { + // +}; + +#define USASCII 1 +//#define RUSSIAN 1 + +#define true 1 +#define false 0 +#define PS2CLOCK 1//PORTD.RD6 +#define PS2DATA 2//PORTD.RD7 +#define QUEUE_SIZE 256 + +extern volatile char in_queue[QUEUE_SIZE]; +extern volatile int in_queue_head, in_queue_tail; +volatile int abort; + +#define POLL 20*(CPU_KHZ/1000) // # clock cycles for 20uS between keyboard reads +#define TIMEOUT 500*(CPU_KHZ/1000) // # clock cycles for 500uS timeout + +enum {PS2START, PS2BIT, PS2PARITY, PS2STOP}; + +// Keyboard state machine and buffer +int state; +unsigned char key_buff; +int key_state, key_count, key_parity, key_timer; + +// IBM keyboard scancode set 2 - Special Keys +#define F1 0x0e +#define F2 0x0f +#define F3 0x10 +#define F4 0x11 +#define F5 0x12 +#define F6 0x13 +#define F7 0x14 // maps to F5 +#define F8 0x15 +#define F9 0x16 +#define F10 0x17 +#define F11 0x18 +#define F12 0x19 + +#define NUM 0x00 +#define BKSP 0x08 +#define TAB 0x09 +#define L_ALT 0x11 +#define L_SHF 0x12 +#define L_CTL 0x14 +#define CAPS 0x58 +#define R_SHF 0x59 +#define ENTER 0x0d +#define ESC 0x1b +#define SCRL 0x7e + +#ifdef USASCII +#include "usascii.inc" +#elif defined RUSSIAN +#include "russian.inc" +#endif + +/* + Standard PC init sequence: + + Keyboard: AA Self-test passed ;Keyboard controller init + Host: ED Set/Reset Status Indicators + Keyboard: FA Acknowledge + Host: 00 Turn off all LEDs + Keyboard: FA Acknowledge + Host: F2 Read ID + Keyboard: FA Acknowledge + Keyboard: AB First byte of ID + Host: ED Set/Reset Status Indicators ;BIOS init + Keyboard: FA Acknowledge + Host: 02 Turn on Num Lock LED + Keyboard: FA Acknowledge + Host: F3 Set Typematic Rate/Delay ;Windows init + Keyboard: FA Acknowledge + Host: 20 500 ms / 30.0 reports/sec + Keyboard: FA Acknowledge + Host: F4 Enable + Keyboard: FA Acknowledge + Host: F3 Set Typematic Rate/delay + Keyboard: FA Acknowledge + Host: 00 250 ms / 30.0 reports/sec + Keyboard: FA Acknowledge +*/ + +char init_kbd(void) +{ + // enable pullups on the clock and data lines. + // This stops them from floating and generating random chars when no keyboard is attached +// CNCON.ON = 1; // turn on Change Notice for interrupt +// CNPUE.CNPUE15 = 1; // turn on the pullup for pin D6 also called CN15 +// CNPUE.CNPUE16 = 1; // turn on the pullup for pin D7 also called CN16 + + return false; +} + +void read_kbd(void) +{ + int data = PS2DATA; + int clock = PS2CLOCK; + static char key_up = false; + static unsigned char code = 0; + static unsigned then = 0; + unsigned now = mips_read_c0_register (C0_COUNT, 0); + + // Is it time to poll the keyboard yet? + if ((int) (now - then) < POLL) + return; + else + then = now; + + if (key_state) { // if clock was high, key_state = 1 + if (!clock) { // PS2CLOCK == 0, falling edge detected + key_state = 0; // transition to state 0 + key_timer = TIMEOUT; // restart the counter + + switch(state){ + default: + case PS2START: + if(!data) { // PS2DATA == 0 + key_count = 8; // init bit counter + key_parity = 0; // init parity check + code = 0; + state = PS2BIT; + } + break; + + case PS2BIT: + code >>= 1; // shift in data bit + if(data) // PS2DATA == 1 + code |= 0x80; + key_parity ^= code; + if (--key_count == 0) + state = PS2PARITY; // all bits read + break; + + case PS2PARITY: + if(data) + key_parity ^= 0x80; + if(key_parity & 0x80) // parity odd, continue + state = PS2STOP; + else + state = PS2START; + break; + + case PS2STOP: + if(data) { + if(code == 0xf0) + key_up = true; + else { + + char chr; + static char LShift = 0; + static char RShift = 0; + static char LCtrl = 0; + static char LAlt = 0; + static char CapsLock = 0; + + if(key_up) { // check for special key release + key_up = false; + switch(code) { + case L_SHF: LShift = 0; + case R_SHF: RShift = 0; + case L_CTL: LCtrl = 0; + case L_ALT: LAlt = 0; + } + goto exit; + } else { // check for special key press + switch(code) { + case L_SHF: LShift = 1; + case R_SHF: RShift = 1; + case L_CTL: LCtrl = 1; + case L_ALT: LAlt = 1; + case CAPS: CapsLock = !CapsLock; + default: break; + goto exit; + } + } + + if(LShift || RShift) // get the ASCII code + chr = lowerKey[code%128]; + else + chr = upperKey[code%128]; + + if(!chr) // it was an unmapped key + break; + + if(CapsLock && chr >= 'a' && chr <= 'z') // check for altered keys + chr -= 32; + if(LCtrl) + chr &= 0x1F; + + in_queue[in_queue_head] = chr; + in_queue_head = (in_queue_head + 1) % QUEUE_SIZE; + + if(chr == 3) { // check for CTL-C + in_queue_head = in_queue_tail = 0; + abort = true; + } + +// PrintSignonToUSB = false; // show that the keyboard is in use + + LAlt = LAlt; // not used yet + } // if key_up +exit: + code = 0; + } // if(data) + state = PS2START; + + } // switch(state) + + } // if(!clock) + + } else // if(key_state) + key_state = 1; // PS2CLOCK == 1, rising edge detected + + if ((key_timer -= POLL) <= 0) + state = PS2START; // timeout, reset state machine + + return; +} + +char write_kbd(u_char data) +{ + + // do something here + + return false; +} diff --git a/sys/pic32/maximite/kbd.h b/sys/pic32/maximite/kbd.h new file mode 100644 index 0000000..ae49092 --- /dev/null +++ b/sys/pic32/maximite/kbd.h @@ -0,0 +1,20 @@ +/* + * + * RetroBSD - PS2 keyboard driver for the Maximite PIC32 board + * + * Copyright (C) 2011 Rob Judd + * All rights reserved. The three clause ("New" or "Modified") + * Berkeley software License Agreement specifies the terms and + * conditions for redistribution. + * + */ + +#ifndef __KBD_H__ +#define __KBD_H__ + + +extern char init_kbd(void); +extern void read_kbd(void); +extern char write_kbd(u_char data); + +#endif // __KBD_H__ diff --git a/sys/pic32/maximite/russian.inc b/sys/pic32/maximite/russian.inc new file mode 100644 index 0000000..17f6a51 --- /dev/null +++ b/sys/pic32/maximite/russian.inc @@ -0,0 +1,50 @@ +/* + * + * RetroBSD - PS2 keyboard driver for the Maximite PIC32 board + * + * Copyright (C) 2011 Rob Judd + * All rights reserved. The three clause ("New" or "Modified") + * Berkeley software License Agreement specifies the terms and + * conditions for redistribution. + * + */ + +// Map of standard keyboard, Russian Windows layout +const char lowerKey[128]={ + 0, F9, 0, F5, F3, F1, F2, F12, //00 + 0, F10, F8, F6, F4, TAB, 'Ñ‘', 0, //08 + 0, 0, L_SHF, 0, L_CTL, 'й', '1', 0, //10 + 0, 0, 'Ñ', 'Ñ‹', 'Ñ„', 'ц', '2', 0, //18 + 0, 'Ñ', 'ч', 'в', 'у', '4', '3', 0, //20 + 0, ' ', 'м', 'а', 'е', 'к', '5', 0, //28 + 0, 'Ñ‚', 'и', 'Ñ€', 'п', 'н', '6', 0, //30 + 0, 0, 'ÑŒ', 'о', 'г', '7', '8', 0, //38 + 0, 'б', 'л', 'ш', 'щ', '0', '9', 0, //40 + 0, 'ÑŽ', '.', 'д', 'ж', 'з', '-', 0, //48 + 0, 0, 'Ñ', 0, 'Ñ…', '=', 0, 0, //50 + CAPS, R_SHF, ENTER, 'ÑŠ', 0, '\\', 0, 0, //58 + 0, 0, 0, 0, 0, 0, BKSP, 0, //60 + 0, '1', 0, '4', '7', 0, 0, 0, //68 + '0', ',', '2', '5', '6', '8', ESC, NUM, //70 + F11, '+', '3', '-', '*', '9', 0, 0 //78 + }; + +const char upperKey[128] = { + 0, F9, 0, F5, F3, F1, F2, F12, //00 + 0, F10, F8, F6, F4, TAB, 'Ð', 0, //08 + 0, 0, L_SHF, 0, L_CTL, 'Й', '!', 0, //10 + 0, 0, 'Я', 'Ы', 'Ф', 'Ц', '\"', 0, //18 + 0, 'С', 'Ч', 'Ð’', 'У', ';', 'â„–', 0, //20 + 0, ' ', 'М', 'Ð', 'Е', 'К', '%', 0, //28 + 0, 'Т', 'И', 'Р', 'П', 'Ð', ':', 0, //30 + 0, 0, 'Ь', 'О', 'Г', '?', '*', 0, //38 + 0, 'Б', 'Л', 'Ш', 'Щ', ')', '(', 0, //40 + 0, 'Ю', ',', 'Д', 'Ж', 'З', '_', 0, //48 + 0, 0, 'Э', 0, 'Ð¥', '+', 0, 0, //50 + CAPS, R_SHF, ENTER, 'Ъ', 0, '/', 0, 0, //58 + 0, 0, 0, 0, 0, 0, BKSP, 0, //60 + 0, '1', 0, '4', '7', 0, 0, 0, //68 + '0', ',', '2', '5', '6', '8', ESC, NUM, //70 + F11, '+', '3', '-', '*', '9', 0, 0 //78 + }; + diff --git a/sys/pic32/maximite/usascii.inc b/sys/pic32/maximite/usascii.inc new file mode 100644 index 0000000..9bfaece --- /dev/null +++ b/sys/pic32/maximite/usascii.inc @@ -0,0 +1,50 @@ +/* + * + * RetroBSD - PS2 keyboard driver for the Maximite PIC32 board + * + * Copyright (C) 2011 Rob Judd + * All rights reserved. The three clause ("New" or "Modified") + * Berkeley software License Agreement specifies the terms and + * conditions for redistribution. + * + */ + +// Map of standard keyboard, US ASCII layout +const char lowerKey[128]={ + 0, F9, 0, F5, F3, F1, F2, F12, //00 + 0, F10, F8, F6, F4, TAB, '`', 0, //08 + 0, 0, L_SHF, 0, L_CTL, 'q', '1', 0, //10 + 0, 0, 'z', 's', 'a', 'w', '2', 0, //18 + 0, 'c', 'x', 'd', 'e', '4', '3', 0, //20 + 0, ' ', 'v', 'f', 't', 'r', '5', 0, //28 + 0, 'n', 'b', 'h', 'g', 'y', '6', 0, //30 + 0, 0, 'm', 'j', 'u', '7', '8', 0, //38 + 0, ',', 'k', 'i', 'o', '0', '9', 0, //40 + 0, '.', '/', 'l', ';', 'p', '-', 0, //48 + 0, 0, '\'', 0, '[', '=', 0, 0, //50 + CAPS, R_SHF, ENTER, ']', 0, '\\', 0, 0, //58 + 0, 0, 0, 0, 0, 0, BKSP, 0, //60 + 0, '1', 0, '4', '7', 0, 0, 0, //68 + '0', '.', '2', '5', '6', '8', ESC, NUM, //70 + F11, '+', '3', '-', '*', '9', 0, 0 //78 + }; + +const char upperKey[128] = { + 0, F9, 0, F5, F3, F1, F2, F12, //00 + 0, F10, F8, F6, F4, TAB, '~', 0, //08 + 0, 0, L_SHF, 0, L_CTL, 'Q', '!', 0, //10 + 0, 0, 'Z', 'S', 'A', 'W', '@', 0, //18 + 0, 'C', 'X', 'D', 'E', '$', '#', 0, //20 + 0, ' ', 'V', 'F', 'T', 'R', '%', 0, //28 + 0, 'N', 'B', 'H', 'G', 'Y', '^', 0, //30 + 0, 0, 'M', 'J', 'U', '&', '*', 0, //38 + 0, '<', 'K', 'I', 'O', ')', '(', 0, //40 + 0, '>', '?', 'L', ':', 'P', '_', 0, //48 + 0, 0, '\"', 0, '{', '+', 0, 0, //50 + CAPS, R_SHF, ENTER, '}', 0, '|', 0, 0, //58 + 0, 0, 0, 0, 0, 0, BKSP, 0, //60 + 0, '1', 0, '4', '7', 0, 0, 0, //68 + '0', '.', '2', '5', '6', '8', ESC, NUM, //70 + F11, '+', '3', '-', '*', '9', 0, 0 //78 + }; + diff --git a/sys/pic32/maximite/using-bootloader.ld b/sys/pic32/maximite/using-bootloader.ld new file mode 100644 index 0000000..e715de5 --- /dev/null +++ b/sys/pic32/maximite/using-bootloader.ld @@ -0,0 +1,115 @@ +/* + * Linker script for PIC32 firmware using HID bootloader. + */ +OUTPUT_FORMAT("elf32-littlemips", "elf32-bigmips", + "elf32-littlemips") +OUTPUT_ARCH(mips) +ENTRY(_reset_vector_) +MEMORY +{ + flash (rx) : ORIGIN = 0x9d003000, LENGTH = 512K-12K + ram (rw!x): ORIGIN = 0x80000000, LENGTH = 26K + u0area (rw!x): ORIGIN = 0x80006800, LENGTH = 3K + uarea (rw!x): ORIGIN = 0x80007400, LENGTH = 3K + + /* Required by Microchip C32 linker */ + kseg0_program_mem (rx) : ORIGIN = 0x9D000000, LENGTH = 0x80000 + kseg0_boot_mem : ORIGIN = 0x9FC00490, LENGTH = 0x970 + exception_mem : ORIGIN = 0x9FC01000, LENGTH = 0x1000 + kseg1_boot_mem : ORIGIN = 0xBFC00000, LENGTH = 0x490 + kseg1_data_mem (w!x) : ORIGIN = 0xA0000000, LENGTH = 0x20000 +} + +/* higher address of the user mode stack */ +u0 = ORIGIN(u0area); +u = ORIGIN(uarea); +u_end = ORIGIN(uarea) + LENGTH(uarea); + +SECTIONS +{ + .text ORIGIN(flash) : + { + /* Exception handlers. */ + *(.exception) + . = 0x1000; + /* Execution starts here. */ + *(.startup) + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.glue_7t) *(.glue_7) + __rodata_start = . ; + *(.rodata .rodata.* .gnu.linkonce.r.* .rel.dyn) + *(.dinit) + /* Align here to ensure that the .text section ends on word boundary. */ + . = ALIGN (32 / 8); + _etext = .; + } > flash + + /* Start data (internal SRAM). */ + .data : AT (ADDR (.text) + SIZEOF (.text)) + { + __data_start = . ; + _gp = .; /* We use only 32k RAM for kernel, so no need for 0x8000 offset. */ + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + *(.sdata .sdata.* .gnu.linkonce.s.*) + *(.data .data.* .gnu.linkonce.d.*) + *(.eh_frame) + _edata = .; + } > ram + + .bss ADDR (.data) + SIZEOF (.data) (NOLOAD) : + { + __bss_start = .; + *(.dynbss) + *(.sbss .sbss.*) + *(.scommon) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. */ + . = ALIGN (32 / 8); + } > ram + __bss_end = . ; + _end = .; + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + .debug_pubtypes 0 : { *(.debug_pubtypes) } + .debug_ranges 0 : { *(.debug_ranges) } + .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) } +} diff --git a/sys/pic32/meb/MEB b/sys/pic32/meb/MEB new file mode 100644 index 0000000..77cb050 --- /dev/null +++ b/sys/pic32/meb/MEB @@ -0,0 +1,18 @@ + + +core pic32mx7 +linker bootloader +mapping generic + +device kernel cpu_khz=80000 bus_khz=80000 led=D2 + +device console device=ttyUSB0 led=D0 +device uartusb + +device rdisk led=D1 +device sd0 port=1 cs=A9 + +device gpio + +#device adc +#device bootloader button=A10 crystal=8 jump=0x9d000000 invled=A0 invled2=A1 invled3=D9 clear=D2 diff --git a/sys/pic32/meb/Makefile b/sys/pic32/meb/Makefile new file mode 100644 index 0000000..8fe1470 --- /dev/null +++ b/sys/pic32/meb/Makefile @@ -0,0 +1,67 @@ +BUILDPATH = ../../../tools/configsys/../../sys/pic32 +H = ../../../tools/configsys/../../sys/include +M = ../../../tools/configsys/../../sys/pic32 +S = ../../../tools/configsys/../../sys/kernel + +vpath %.c $(M):$(S) +vpath %.S $(M):$(S) + +KERNOBJ += _startup.o clock.o cons.o devcfg.o devsw.o exception.o gpio.o init_main.o init_sysent.o kern_clock.o kern_descrip.o kern_exec.o kern_exit.o kern_fork.o kern_mman.o kern_proc.o kern_prot.o kern_prot2.o kern_resource.o kern_sig.o kern_sig2.o kern_subr.o kern_synch.o kern_sysctl.o kern_time.o machdep.o mem.o rd_sd.o rdisk.o signal.o spi_bus.o subr_prf.o subr_rmap.o swap.o sys_generic.o sys_inode.o sys_pipe.o sys_process.o syscalls.o sysctl.o tty.o tty_subr.o tty_tty.o ufs_alloc.o ufs_bio.o ufs_bmap.o ufs_dsort.o ufs_fio.o ufs_inode.o ufs_mount.o ufs_namei.o ufs_subr.o ufs_syscalls.o ufs_syscalls2.o usb_device.o usb_function_cdc.o usb_uart.o vers.o vfs_vnops.o vm_sched.o vm_swap.o vm_swp.o +EXTRA_TARGETS = + +DEFS += -DBUS_DIV=1 +DEFS += -DBUS_KHZ=80000 +DEFS += -DCONSOLE_DEVICE=ttyUSB0 +DEFS += -DCPU_IDIV=2 +DEFS += -DCPU_KHZ=80000 +DEFS += -DCPU_MUL=20 +DEFS += -DCPU_ODIV=1 +DEFS += -DCRYSTAL=8 +DEFS += -DDC0_DEBUG=DEVCFG0_DEBUG_DISABLED +DEFS += -DDC0_ICE=0 +DEFS += -DDC1_CKM=0 +DEFS += -DDC1_CKS=0 +DEFS += -DDC1_FNOSC=DEVCFG1_FNOSC_PRIPLL +DEFS += -DDC1_IESO=DEVCFG1_IESO +DEFS += -DDC1_OSCIOFNC=0 +DEFS += -DDC1_PBDIV=DEVCFG1_FPBDIV_1 +DEFS += -DDC1_POSCMOD=DEVCFG1_POSCMOD_HS +DEFS += -DDC1_SOSC=0 +DEFS += -DDC1_WDTEN=0 +DEFS += -DDC1_WDTPS=DEVCFG1_WDTPS_1 +DEFS += -DDC2_PLLIDIV=DEVCFG2_FPLLIDIV_2 +DEFS += -DDC2_PLLMUL=DEVCFG2_FPLLMUL_20 +DEFS += -DDC2_PLLODIV=DEVCFG2_FPLLODIV_1 +DEFS += -DDC2_UPLL=0 +DEFS += -DDC2_UPLLIDIV=DEVCFG2_UPLLIDIV_2 +DEFS += -DDC3_CAN=DEVCFG3_FCANIO +DEFS += -DDC3_ETH=DEVCFG3_FETHIO +DEFS += -DDC3_MII=DEVCFG3_FMIIEN +DEFS += -DDC3_SRS=DEVCFG3_FSRSSEL_7 +DEFS += -DDC3_USBID=DEVCFG3_FUSBIDIO +DEFS += -DDC3_USERID=0xffff +DEFS += -DDC3_VBUSON=DEVCFG3_FVBUSONIO +DEFS += -DGPIO_ENABLED=YES +DEFS += -DKERNEL +DEFS += -DLED_DISK_PIN=1 +DEFS += -DLED_DISK_PORT=TRISD +DEFS += -DLED_KERNEL_PIN=2 +DEFS += -DLED_KERNEL_PORT=TRISD +DEFS += -DLED_TTY_PIN=0 +DEFS += -DLED_TTY_PORT=TRISD +DEFS += -DPIC32MX7 +DEFS += -DSD0_CS_PIN=9 +DEFS += -DSD0_CS_PORT=TRISA +DEFS += -DSD0_PORT=1 +DEFS += -DUARTUSB_ENABLED=YES +DEFS += -DUCB_METER +DEFS += -DUSB_MAX_EP_NUMBER=3 +DEFS += -DUSB_NUM_STRING_DESCRIPTORS=3 + + +LDSCRIPT = ../../../tools/configsys/../../sys/pic32/cfg/bootloader.ld + +CONFIG = MEB +CONFIGPATH = ../../../tools/configsys + +include ../../../tools/configsys/../../sys/pic32/kernel-post.mk diff --git a/sys/pic32/meb/README b/sys/pic32/meb/README new file mode 100644 index 0000000..aebbad0 --- /dev/null +++ b/sys/pic32/meb/README @@ -0,0 +1,5 @@ +NOTE +==== + +This device configuration is not currently supported by the +rdisk system. A new driver is needed for the SD card chip. diff --git a/sys/pic32/meb/using-bootloader.ld b/sys/pic32/meb/using-bootloader.ld new file mode 100644 index 0000000..8d2d334 --- /dev/null +++ b/sys/pic32/meb/using-bootloader.ld @@ -0,0 +1,114 @@ +/* + * Linker script for PIC32 firmware using RetroBSD bootloader. + */ +OUTPUT_FORMAT("elf32-littlemips", "elf32-bigmips", + "elf32-littlemips") +OUTPUT_ARCH(mips) +ENTRY(_reset_vector_) +MEMORY +{ + flash (rx) : ORIGIN = 0x9d000000, LENGTH = 512K + ram (rw!x): ORIGIN = 0x80000000, LENGTH = 26K + u0area (rw!x): ORIGIN = 0x80006800, LENGTH = 3K + uarea (rw!x): ORIGIN = 0x80007400, LENGTH = 3K + + /* Required by Microchip C32 linker */ + kseg0_program_mem (rx) : ORIGIN = 0x9D000000, LENGTH = 0x80000 + kseg0_boot_mem : ORIGIN = 0x9FC00000, LENGTH = 0x1000 + exception_mem : ORIGIN = 0x9FC00000, LENGTH = 0x1000 + kseg1_boot_mem : ORIGIN = 0xBFC00000, LENGTH = 0 + kseg1_data_mem (w!x) : ORIGIN = 0xA0000000, LENGTH = 0x20000 +} + +/* higher address of the user mode stack */ +u0 = ORIGIN(u0area); +u = ORIGIN(uarea); +u_end = ORIGIN(uarea) + LENGTH(uarea); + +SECTIONS +{ + .text ORIGIN(flash) : + { + /* Exception handlers. */ + *(.exception) + /* Execution starts here. */ + *(.startup) + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.glue_7t) *(.glue_7) + __rodata_start = . ; + *(.rodata .rodata.* .gnu.linkonce.r.* .rel.dyn) + *(.dinit) + /* Align here to ensure that the .text section ends on word boundary. */ + . = ALIGN (32 / 8); + _etext = .; + } > flash + + /* Start data (internal SRAM). */ + .data : AT (ADDR (.text) + SIZEOF (.text)) + { + __data_start = . ; + _gp = .; /* We use only 32k RAM for kernel, so no need for 0x8000 offset. */ + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + *(.sdata .sdata.* .gnu.linkonce.s.*) + *(.data .data.* .gnu.linkonce.d.*) + *(.eh_frame) + _edata = .; + } > ram + + .bss ADDR (.data) + SIZEOF (.data) (NOLOAD) : + { + __bss_start = .; + *(.dynbss) + *(.sbss .sbss.*) + *(.scommon) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. */ + . = ALIGN (32 / 8); + } > ram + __bss_end = . ; + _end = .; + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + .debug_pubtypes 0 : { *(.debug_pubtypes) } + .debug_ranges 0 : { *(.debug_ranges) } + .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) } +} diff --git a/sys/pic32/mem.c b/sys/pic32/mem.c new file mode 100644 index 0000000..f0bc531 --- /dev/null +++ b/sys/pic32/mem.c @@ -0,0 +1,85 @@ +/* + * Copyright (c) 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "param.h" +#include "user.h" +#include "conf.h" +#include "systm.h" +#include "uio.h" + +const struct devspec mmdevs[] = { + { 0, "mem" }, + { 1, "kmem" }, + { 2, "null" }, + { 3, "zero" }, + { 0, 0 } +}; + +void kmemdev() +{ + u.u_rval = get_cdev_by_name("kmem"); +} + +/* + * Read/write routine for /dev/mem family. + */ +int +mmrw (dev, uio, flag) + dev_t dev; + register struct uio *uio; + int flag; +{ + register struct iovec *iov; + int error = 0; + register u_int c; + caddr_t addr; + + //printf ("mmrw (dev=%u, len=%u, flag=%d)\n", dev, uio->uio_iov->iov_len, flag); + while (uio->uio_resid && error == 0) { + iov = uio->uio_iov; + if (iov->iov_len == 0) { + uio->uio_iov++; + uio->uio_iovcnt--; + if (uio->uio_iovcnt < 0) + panic("mmrw"); + continue; + } + switch (minor(dev)) { + case 0: /* minor device 0 is physical memory (/dev/mem) */ + case 1: /* minor device 1 is kernel memory (/dev/kmem) */ + addr = (caddr_t) uio->uio_offset; + if ((badkaddr (addr) && baduaddr (addr)) || + (badkaddr (addr + iov->iov_len - 1) && + baduaddr (addr + iov->iov_len - 1))) { + error = EFAULT; + break; + } + error = uiomove(addr, iov->iov_len, uio); + break; + case 2: /* minor device 2 is EOF/RATHOLE (/dev/null) */ + if (uio->uio_rw == UIO_READ) + return(0); + c = iov->iov_len; + iov->iov_base += c; + iov->iov_len -= c; + uio->uio_offset += c; + uio->uio_resid -= c; + break; + case 3: /* minor device 3 is ZERO (/dev/zero) */ + if (uio->uio_rw == UIO_WRITE) + return(EIO); + c = iov->iov_len; + bzero (iov->iov_base, c); + iov->iov_base += c; + iov->iov_len -= c; + uio->uio_offset += c; + uio->uio_resid -= c; + break; + default: + return(EINVAL); + } + } + return(error); +} diff --git a/sys/pic32/mmb-mx7/MMB-MX7 b/sys/pic32/mmb-mx7/MMB-MX7 new file mode 100644 index 0000000..e403e71 --- /dev/null +++ b/sys/pic32/mmb-mx7/MMB-MX7 @@ -0,0 +1,21 @@ +# +# MikroElektronika MMB for PIC32MX7 board +# ======================================= +# +# Console on USB +# For Windows, use the driver: http://www.schmalzhaus.com/UBW32/FW/UBW32inf.zip + +core pic32mx7 +linker bootloader +mapping generic + +device kernel invled=A0 clear_pin=D2 +device console invled=A1 device=ttyUSB0 +device uartusb +device rdisk invswap=D9 +device sd0 port=1 cs=A9 mhz=8 +device gpio +device adc +device uart1 + +device bootloader button=A10 crystal=8 jump=0x9d000000 invled=A0 invled2=A1 invled3=D9 clear=D2 diff --git a/sys/pic32/mmb-mx7/Makefile b/sys/pic32/mmb-mx7/Makefile new file mode 100644 index 0000000..c9aa575 --- /dev/null +++ b/sys/pic32/mmb-mx7/Makefile @@ -0,0 +1,97 @@ +BUILDPATH = ../../../tools/configsys/../../sys/pic32 +H = ../../../tools/configsys/../../sys/include +M = ../../../tools/configsys/../../sys/pic32 +S = ../../../tools/configsys/../../sys/kernel + +vpath %.c $(M):$(S) +vpath %.S $(M):$(S) + +KERNOBJ += _startup.o adc.o clock.o cons.o devsw.o exception.o gpio.o init_main.o init_sysent.o kern_clock.o kern_descrip.o kern_exec.o kern_exit.o kern_fork.o kern_mman.o kern_proc.o kern_prot.o kern_prot2.o kern_resource.o kern_sig.o kern_sig2.o kern_subr.o kern_synch.o kern_sysctl.o kern_time.o machdep.o mem.o rd_sd.o rdisk.o signal.o spi_bus.o subr_prf.o subr_rmap.o swap.o sys_generic.o sys_inode.o sys_pipe.o sys_process.o syscalls.o sysctl.o tty.o tty_subr.o tty_tty.o uart.o ufs_alloc.o ufs_bio.o ufs_bmap.o ufs_dsort.o ufs_fio.o ufs_inode.o ufs_mount.o ufs_namei.o ufs_subr.o ufs_syscalls.o ufs_syscalls2.o usb_device.o usb_function_cdc.o usb_uart.o vers.o vfs_vnops.o vm_sched.o vm_swap.o vm_swp.o +EXTRA_TARGETS = bootloader + +DEFS += -DADC_ENABLED=YES +DEFS += -DBL_BUTTON_PIN=10 +DEFS += -DBL_BUTTON_PORT=TRISA +DEFS += -DBL_CLEAR_PIN=2 +DEFS += -DBL_CLEAR_PORT=TRISD +DEFS += -DBL_CRYSTAL=8 +DEFS += -DBL_LED2_INVERT +DEFS += -DBL_LED2_PIN=1 +DEFS += -DBL_LED2_PORT=TRISA +DEFS += -DBL_LED3_INVERT +DEFS += -DBL_LED3_PIN=9 +DEFS += -DBL_LED3_PORT=TRISD +DEFS += -DBL_LED_INVERT +DEFS += -DBL_LED_PIN=0 +DEFS += -DBL_LED_PORT=TRISA +DEFS += -DBUS_DIV=1 +DEFS += -DBUS_KHZ='CPU_KHZ/BUS_DIV' +DEFS += -DCONSOLE_DEVICE=ttyUSB0 +DEFS += -DCPU_IDIV=2 +DEFS += -DCPU_KHZ='((CRYSTAL*1000)/CPU_IDIV*CPU_MUL/CPU_ODIV)' +DEFS += -DCPU_MUL=20 +DEFS += -DCPU_ODIV=1 +DEFS += -DCRYSTAL=8 +DEFS += -DDC0_DEBUG=DEVCFG0_DEBUG_DISABLED +DEFS += -DDC0_ICE=0 +DEFS += -DDC1_CKM=0 +DEFS += -DDC1_CKS=0 +DEFS += -DDC1_FNOSC=DEVCFG1_FNOSC_PRIPLL +DEFS += -DDC1_IESO=DEVCFG1_IESO +DEFS += -DDC1_OSCIOFNC=0 +DEFS += -DDC1_PBDIV=DEVCFG1_FPBDIV_1 +DEFS += -DDC1_POSCMOD=DEVCFG1_POSCMOD_HS +DEFS += -DDC1_SOSC=0 +DEFS += -DDC1_WDTEN=0 +DEFS += -DDC1_WDTPS=DEVCFG1_WDTPS_1 +DEFS += -DDC2_PLLIDIV=DEVCFG2_FPLLIDIV_2 +DEFS += -DDC2_PLLMUL=DEVCFG2_FPLLMUL_20 +DEFS += -DDC2_PLLODIV=DEVCFG2_FPLLODIV_1 +DEFS += -DDC2_UPLL=0 +DEFS += -DDC2_UPLLIDIV=DEVCFG2_UPLLIDIV_2 +DEFS += -DDC3_CAN=DEVCFG3_FCANIO +DEFS += -DDC3_ETH=DEVCFG3_FETHIO +DEFS += -DDC3_MII=DEVCFG3_FMIIEN +DEFS += -DDC3_SRS=DEVCFG3_FSRSSEL_7 +DEFS += -DDC3_USBID=DEVCFG3_FUSBIDIO +DEFS += -DDC3_USERID=0xffff +DEFS += -DDC3_VBUSON=DEVCFG3_FVBUSONIO +DEFS += -DFLASH_JUMP=0x9d000000 +DEFS += -DGPIO_CLEAR_PIN=2 +DEFS += -DGPIO_CLEAR_PORT=TRISD +DEFS += -DGPIO_ENABLED=YES +DEFS += -DHID_FEATURE_REPORT_BYTES=2 +DEFS += -DHID_INPUT_REPORT_BYTES=2 +DEFS += -DHID_INT_IN_EP_SIZE=64 +DEFS += -DHID_INT_OUT_EP_SIZE=64 +DEFS += -DHID_OUTPUT_REPORT_BYTES=2 +DEFS += -DHID_RPT01_SIZE=29 +DEFS += -DKERNEL +DEFS += -DLED_KERNEL_INVERT=YES +DEFS += -DLED_KERNEL_PIN=0 +DEFS += -DLED_KERNEL_PORT=TRISA +DEFS += -DLED_SWAP_INVERT=YES +DEFS += -DLED_SWAP_PIN=9 +DEFS += -DLED_SWAP_PORT=TRISD +DEFS += -DLED_TTY_INVERT=YES +DEFS += -DLED_TTY_PIN=1 +DEFS += -DLED_TTY_PORT=TRISA +DEFS += -DPIC32MX7 +DEFS += -DSD0_CS_PIN=9 +DEFS += -DSD0_CS_PORT=TRISA +DEFS += -DSD0_MHZ=8 +DEFS += -DSD0_PORT=1 +DEFS += -DUART1_ENABLED=YES +DEFS += -DUARTUSB_ENABLED=YES +DEFS += -DUCB_METER +DEFS += -DUSB_EP0_BUFF_SIZE=8 +DEFS += -DUSB_MAX_EP_NUMBER=3 +DEFS += -DUSB_NUM_STRING_DESCRIPTORS=3 + + +LDSCRIPT = ../../../tools/configsys/../../sys/pic32/cfg/bootloader.ld + +CONFIG = MMB-MX7 +CONFIGPATH = ../../../tools/configsys + +include ../../../tools/configsys/../../sys/pic32/kernel-post.mk diff --git a/sys/pic32/newvers.sh b/sys/pic32/newvers.sh new file mode 100644 index 0000000..6713d67 --- /dev/null +++ b/sys/pic32/newvers.sh @@ -0,0 +1,38 @@ +#!/bin/sh - +# +# Copyright (c) 1980 Regents of the University of California. +# All rights reserved. The Berkeley software License Agreement +# specifies the terms and conditions for redistribution. +# +CV=`cat .compileversion` +CV=`expr $CV + 1` +OV=`cat .oldversion` +SVN=`svnversion` + +if [ "x$SVN" = "xexported" ] +then + PWD=`pwd` + cd .. + SVN=`svnversion` + cd $PWD +fi + +if [ "x$SVN" != "x$OV" ] +then + CV=1 +fi +echo $CV >.compileversion +echo $SVN >.oldversion + +echo $SVN ${USER-root} `pwd` `date +'%Y-%m-%d'` `hostname` $CV| \ +awk ' { + version = $1; + user = $2; + dir = $3; + date = $4; + host = $5; + cv = $6; + printf "const char version[] = \"2.11 BSD Unix for PIC32, revision %s build %d:\\n", version, cv; + printf " Compiled %s by %s@%s:\\n", date, user, host; + printf " %s\\n\";\n", dir; +}' diff --git a/sys/pic32/oc.c b/sys/pic32/oc.c new file mode 100644 index 0000000..4b1406f --- /dev/null +++ b/sys/pic32/oc.c @@ -0,0 +1,219 @@ +/* + * Output Compare driver for PIC32. + * + * Copyright (C) 2012 Majenko Technologies + * + * 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 the copyright notice and this + * permission notice and warranty disclaimer appear in supporting + * documentation, and that the name of the author not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * + * The author disclaim all warranties with regard to this + * software, including all implied warranties of merchantability + * and fitness. In no event shall the author 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. + */ +#include "param.h" +#include "conf.h" +#include "user.h" +#include "ioctl.h" +#include "systm.h" +#include "sys/uio.h" +#include "oc.h" +#include "debug.h" + +const struct devspec ocdevs[] = { + { 0, "oc1" }, + { 1, "oc2" }, + { 2, "oc3" }, + { 3, "oc4" }, + { 4, "oc5" }, + { 0, 0 } +}; + +#define _BC(R,B) (R &= ~(1<- 1:1 prescale + _BC(T2CON,4); + _BC(T2CON,3); // 16 bit timer + _BC(T2CON,1); // Internal clock source + PR2 = 0xFFFF; + switch(unit) + { + case 0: + _BS(OC1CON,15); // ON + _BC(OC1CON,5); // 16 bit + _BC(OC1CON,3); // TMR2 + _BS(OC1CON,2); // + _BS(OC1CON,1); // >- PWM Mode, no fault pin + _BC(OC1CON,0); // + state[0].mode = OC_MODE_PWM; + break; + case 1: + _BS(OC2CON,15); // ON + _BC(OC2CON,5); // 16 bit + _BC(OC2CON,3); // TMR2 + _BS(OC2CON,2); // + _BS(OC2CON,1); // >- PWM Mode, no fault pin + _BC(OC2CON,0); // + state[1].mode = OC_MODE_PWM; + break; + case 2: + _BS(OC3CON,15); // ON + _BC(OC3CON,5); // 16 bit + _BC(OC3CON,3); // TMR2 + _BS(OC3CON,2); // + _BS(OC3CON,1); // >- PWM Mode, no fault pin + _BC(OC3CON,0); // + state[2].mode = OC_MODE_PWM; + break; + case 3: + _BS(OC4CON,15); // ON + _BC(OC4CON,5); // 16 bit + _BC(OC4CON,3); // TMR2 + _BS(OC4CON,2); // + _BS(OC4CON,1); // >- PWM Mode, no fault pin + _BC(OC4CON,0); // + state[3].mode = OC_MODE_PWM; + break; + case 4: + _BS(OC5CON,15); // ON + _BC(OC5CON,5); // 16 bit + _BC(OC5CON,3); // TMR2 + _BS(OC5CON,2); // + _BS(OC5CON,1); // >- PWM Mode, no fault pin + _BC(OC5CON,0); // + state[4].mode = OC_MODE_PWM; + break; + default: + return EINVAL; + } + DEBUG("oc%d: Mode set to PWM\n",unit); + break; + default: + return EINVAL; + } + return 0; +} + +int oc_pwm_duty(int unit, unsigned int duty) +{ + if(state[unit].mode!=OC_MODE_PWM) + return EINVAL; + + switch(unit) + { + case 0: + OC1RS = duty; + break; + case 1: + OC2RS = duty; + break; + case 2: + OC3RS = duty; + break; + case 3: + OC4RS = duty; + break; + case 4: + OC5RS = duty; + break; + default: + return EINVAL; + } + DEBUG("oc%d: Duty set to %d\n",unit,duty); + return 0; +} + +int +oc_open (dev, flag, mode) + dev_t dev; +{ + int unit = minor(dev); + + if (unit >= OC_MAX_DEV) + return ENXIO; + if (u.u_uid != 0) + return EPERM; + DEBUG("oc%d: Opened\n",unit); + return 0; +} + +int +oc_close (dev, flag, mode) + dev_t dev; +{ + return 0; +} + +int +oc_read (dev, uio, flag) + dev_t dev; + struct uio *uio; + int flag; +{ + // TODO + return ENODEV; +} + +int oc_write (dev_t dev, struct uio *uio, int flag) +{ + return ENODEV; +} + +int +oc_ioctl (dev, cmd, addr, flag) + dev_t dev; + register u_int cmd; + caddr_t addr; +{ + int unit; + int *val; + val = (int *)addr; + + unit = minor(dev); + + if(unit >= OC_MAX_DEV) + return ENODEV; + + if (cmd == OC_SET_MODE) { + return oc_set_mode(unit, *val); + } + + if (cmd == OC_PWM_DUTY) { + return oc_pwm_duty(unit, (unsigned int) *val); + } + + return 0; +} diff --git a/sys/pic32/pic32mx.h b/sys/pic32/pic32mx.h new file mode 100644 index 0000000..e287281 --- /dev/null +++ b/sys/pic32/pic32mx.h @@ -0,0 +1,1320 @@ +/* + * Hardware register defines for all Microchip PIC32MX microcontrollers. + * + * Copyright (C) 2010 Serge Vakulenko, + * + * 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 the copyright notice and this + * permission notice and warranty disclaimer appear in supporting + * documentation, and that the name of the author not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * + * The author disclaim all warranties with regard to this + * software, including all implied warranties of merchantability + * and fitness. In no event shall the author 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. + */ +#ifndef _IO_PIC32MX_H +#define _IO_PIC32MX_H + +/*-------------------------------------- + * Coprocessor 0 registers. + */ +#define C0_HWRENA 7 /* Enable RDHWR in non-privileged mode */ +#define C0_BADVADDR 8 /* Virtual address of last exception */ +#define C0_COUNT 9 /* Processor cycle count */ +#define C0_COMPARE 11 /* Timer interrupt control */ +#define C0_STATUS 12 /* Processor status and control */ +#define C0_INTCTL 12 /* Select 1: interrupt control */ +#define C0_SRSCTL 12 /* Select 2: GPR shadow set control */ +#define C0_SRSMAP 12 /* Select 3: vector to shadow set mapping */ +#define C0_CAUSE 13 /* Cause of last exception */ +#define C0_EPC 14 /* Program counter at last exception */ +#define C0_PRID 15 /* Processor identification (read only) */ +#define C0_EBASE 15 /* Select 1: exception base address */ +#define C0_CONFIG 16 /* Configuration */ +#define C0_CONFIG1 16 /* Select 1: configuration 1 */ +#define C0_CONFIG2 16 /* Select 2: configuration 2 */ +#define C0_CONFIG3 16 /* Select 3: configuration 3 */ +#define C0_DEBUG 23 /* Debug control and status */ +#define C0_DEPC 24 /* Program counter at last debug exception */ +#define C0_ERROREPC 30 /* Program counter at last error */ +#define C0_DESAVE 31 /* Debug handler scratchpad register */ + +/* + * Status register. + */ +#define ST_CU0 0x10000000 /* Access to coprocessor 0 allowed (in user mode) */ +#define ST_RP 0x08000000 /* Enable reduced power mode */ +#define ST_RE 0x02000000 /* Reverse endianness (in user mode) */ +#define ST_BEV 0x00400000 /* Exception vectors: bootstrap */ +#define ST_SR 0x00100000 /* Soft reset */ +#define ST_NMI 0x00080000 /* NMI reset */ +#define ST_IPL(x) ((x) << 10) /* Current interrupt priority level */ +#define ST_UM 0x00000010 /* User mode */ +#define ST_ERL 0x00000004 /* Error level */ +#define ST_EXL 0x00000002 /* Exception level */ +#define ST_IE 0x00000001 /* Interrupt enable */ + +/* + * Сause register. + */ +#define CA_BD 0x80000000 /* Exception occured in delay slot */ +#define CA_TI 0x40000000 /* Timer interrupt is pending */ +#define CA_CE 0x30000000 /* Coprocessor exception */ +#define CA_DC 0x08000000 /* Disable COUNT register */ +#define CA_IV 0x00800000 /* Use special interrupt vector 0x200 */ +#define CA_RIPL(r) ((r)>>10 & 63) /* Requested interrupt priority level */ +#define CA_IP1 0x00020000 /* Request software interrupt 1 */ +#define CA_IP0 0x00010000 /* Request software interrupt 0 */ +#define CA_EXC_CODE 0x0000007c /* Exception code */ + +#define CA_Int 0 /* Interrupt */ +#define CA_AdEL (4 << 2) /* Address error, load or instruction fetch */ +#define CA_AdES (5 << 2) /* Address error, store */ +#define CA_IBE (6 << 2) /* Bus error, instruction fetch */ +#define CA_DBE (7 << 2) /* Bus error, load or store */ +#define CA_Sys (8 << 2) /* Syscall */ +#define CA_Bp (9 << 2) /* Breakpoint */ +#define CA_RI (10 << 2) /* Reserved instruction */ +#define CA_CPU (11 << 2) /* Coprocessor unusable */ +#define CA_Ov (12 << 2) /* Arithmetic overflow */ +#define CA_Tr (13 << 2) /* Trap */ + +#define DB_DBD (1 << 31) /* Debug exception in a branch delay slot */ +#define DB_DM (1 << 30) /* Debug mode */ +#define DB_NODCR (1 << 29) /* No dseg present */ +#define DB_LSNM (1 << 28) /* Load/stores in dseg go to main memory */ +#define DB_DOZE (1 << 27) /* Processor was in low-power mode */ +#define DB_HALT (1 << 26) /* Internal system bus clock was running */ +#define DB_COUNTDM (1 << 25) /* Count register is running in Debug mode */ +#define DB_IBUSEP (1 << 24) /* Instruction fetch bus error exception */ +#define DB_DBUSEP (1 << 21) /* Data access bus error exception */ +#define DB_IEXI (1 << 20) /* Imprecise error exception */ +#define DB_VER (7 << 15) /* EJTAG version number */ +#define DB_DEXCCODE (0x1f << 10) /* Cause of exception in Debug mode */ +#define DB_SST (1 << 8) /* Single step exception enabled */ +#define DB_DIBImpr (1 << 6) /* Imprecise debug instruction break */ +#define DB_DINT (1 << 5) /* Debug interrupt exception */ +#define DB_DIB (1 << 4) /* Debug instruction break exception */ +#define DB_DDBS (1 << 3) /* Debug data break exception on store */ +#define DB_DDBL (1 << 2) /* Debug data break exception on load */ +#define DB_DBP (1 << 1) /* Debug software breakpoint exception */ +#define DB_DSS (1 << 0) /* Debug single-step exception */ + +/*-------------------------------------- + * Peripheral registers. + */ +#ifdef __ASSEMBLER__ +#define PIC32_R(a) (0xBF800000 + (a)) +#else +#define PIC32_R(a) *(volatile unsigned*)(0xBF800000 + (a)) +#endif +/*-------------------------------------- + * UART registers. + */ +#define U1MODE PIC32_R (0x6000) /* Mode */ +#define U1MODECLR PIC32_R (0x6004) +#define U1MODESET PIC32_R (0x6008) +#define U1MODEINV PIC32_R (0x600C) +#define U1STA PIC32_R (0x6010) /* Status and control */ +#define U1STACLR PIC32_R (0x6014) +#define U1STASET PIC32_R (0x6018) +#define U1STAINV PIC32_R (0x601C) +#define U1TXREG PIC32_R (0x6020) /* Transmit */ +#define U1RXREG PIC32_R (0x6030) /* Receive */ +#define U1BRG PIC32_R (0x6040) /* Baud rate */ +#define U1BRGCLR PIC32_R (0x6044) +#define U1BRGSET PIC32_R (0x6048) +#define U1BRGINV PIC32_R (0x604C) + +#ifdef PIC32MX4 +#define U2MODE PIC32_R (0x6200) /* Mode */ +#define U2MODECLR PIC32_R (0x6204) +#define U2MODESET PIC32_R (0x6208) +#define U2MODEINV PIC32_R (0x620C) +#define U2STA PIC32_R (0x6210) /* Status and control */ +#define U2STACLR PIC32_R (0x6214) +#define U2STASET PIC32_R (0x6218) +#define U2STAINV PIC32_R (0x621C) +#define U2TXREG PIC32_R (0x6220) /* Transmit */ +#define U2RXREG PIC32_R (0x6230) /* Receive */ +#define U2BRG PIC32_R (0x6240) /* Baud rate */ +#define U2BRGCLR PIC32_R (0x6244) +#define U2BRGSET PIC32_R (0x6248) +#define U2BRGINV PIC32_R (0x624C) +#endif +#ifdef PIC32MX7 +#define U4MODE PIC32_R (0x6200) /* Mode */ +#define U4MODECLR PIC32_R (0x6204) +#define U4MODESET PIC32_R (0x6208) +#define U4MODEINV PIC32_R (0x620C) +#define U4STA PIC32_R (0x6210) /* Status and control */ +#define U4STACLR PIC32_R (0x6214) +#define U4STASET PIC32_R (0x6218) +#define U4STAINV PIC32_R (0x621C) +#define U4TXREG PIC32_R (0x6220) /* Transmit */ +#define U4RXREG PIC32_R (0x6230) /* Receive */ +#define U4BRG PIC32_R (0x6240) /* Baud rate */ +#define U4BRGCLR PIC32_R (0x6244) +#define U4BRGSET PIC32_R (0x6248) +#define U4BRGINV PIC32_R (0x624C) + +#define U3MODE PIC32_R (0x6400) /* Mode */ +#define U3MODECLR PIC32_R (0x6404) +#define U3MODESET PIC32_R (0x6408) +#define U3MODEINV PIC32_R (0x640C) +#define U3STA PIC32_R (0x6410) /* Status and control */ +#define U3STACLR PIC32_R (0x6414) +#define U3STASET PIC32_R (0x6418) +#define U3STAINV PIC32_R (0x641C) +#define U3TXREG PIC32_R (0x6420) /* Transmit */ +#define U3RXREG PIC32_R (0x6430) /* Receive */ +#define U3BRG PIC32_R (0x6440) /* Baud rate */ +#define U3BRGCLR PIC32_R (0x6444) +#define U3BRGSET PIC32_R (0x6448) +#define U3BRGINV PIC32_R (0x644C) + +#define U6MODE PIC32_R (0x6600) /* Mode */ +#define U6MODECLR PIC32_R (0x6604) +#define U6MODESET PIC32_R (0x6608) +#define U6MODEINV PIC32_R (0x660C) +#define U6STA PIC32_R (0x6610) /* Status and control */ +#define U6STACLR PIC32_R (0x6614) +#define U6STASET PIC32_R (0x6618) +#define U6STAINV PIC32_R (0x661C) +#define U6TXREG PIC32_R (0x6620) /* Transmit */ +#define U6RXREG PIC32_R (0x6630) /* Receive */ +#define U6BRG PIC32_R (0x6640) /* Baud rate */ +#define U6BRGCLR PIC32_R (0x6644) +#define U6BRGSET PIC32_R (0x6648) +#define U6BRGINV PIC32_R (0x664C) + +#define U2MODE PIC32_R (0x6800) /* Mode */ +#define U2MODECLR PIC32_R (0x6804) +#define U2MODESET PIC32_R (0x6808) +#define U2MODEINV PIC32_R (0x680C) +#define U2STA PIC32_R (0x6810) /* Status and control */ +#define U2STACLR PIC32_R (0x6814) +#define U2STASET PIC32_R (0x6818) +#define U2STAINV PIC32_R (0x681C) +#define U2TXREG PIC32_R (0x6820) /* Transmit */ +#define U2RXREG PIC32_R (0x6830) /* Receive */ +#define U2BRG PIC32_R (0x6840) /* Baud rate */ +#define U2BRGCLR PIC32_R (0x6844) +#define U2BRGSET PIC32_R (0x6848) +#define U2BRGINV PIC32_R (0x684C) + +#define U5MODE PIC32_R (0x6A00) /* Mode */ +#define U5MODECLR PIC32_R (0x6A04) +#define U5MODESET PIC32_R (0x6A08) +#define U5MODEINV PIC32_R (0x6A0C) +#define U5STA PIC32_R (0x6A10) /* Status and control */ +#define U5STACLR PIC32_R (0x6A14) +#define U5STASET PIC32_R (0x6A18) +#define U5STAINV PIC32_R (0x6A1C) +#define U5TXREG PIC32_R (0x6A20) /* Transmit */ +#define U5RXREG PIC32_R (0x6A30) /* Receive */ +#define U5BRG PIC32_R (0x6A40) /* Baud rate */ +#define U5BRGCLR PIC32_R (0x6A44) +#define U5BRGSET PIC32_R (0x6A48) +#define U5BRGINV PIC32_R (0x6A4C) +#endif + +/* + * UART Mode register. + */ +#define PIC32_UMODE_STSEL 0x0001 /* 2 Stop bits */ +#define PIC32_UMODE_PDSEL 0x0006 /* Bitmask: */ +#define PIC32_UMODE_PDSEL_8NPAR 0x0000 /* 8-bit data, no parity */ +#define PIC32_UMODE_PDSEL_8EVEN 0x0002 /* 8-bit data, even parity */ +#define PIC32_UMODE_PDSEL_8ODD 0x0004 /* 8-bit data, odd parity */ +#define PIC32_UMODE_PDSEL_9NPAR 0x0006 /* 9-bit data, no parity */ +#define PIC32_UMODE_BRGH 0x0008 /* High Baud Rate Enable */ +#define PIC32_UMODE_RXINV 0x0010 /* Receive Polarity Inversion */ +#define PIC32_UMODE_ABAUD 0x0020 /* Auto-Baud Enable */ +#define PIC32_UMODE_LPBACK 0x0040 /* UARTx Loopback Mode */ +#define PIC32_UMODE_WAKE 0x0080 /* Wake-up on start bit during Sleep Mode */ +#define PIC32_UMODE_UEN 0x0300 /* Bitmask: */ +#define PIC32_UMODE_UEN_RTS 0x0100 /* Using UxRTS pin */ +#define PIC32_UMODE_UEN_RTSCTS 0x0200 /* Using UxCTS and UxRTS pins */ +#define PIC32_UMODE_UEN_BCLK 0x0300 /* Using UxBCLK pin */ +#define PIC32_UMODE_RTSMD 0x0800 /* UxRTS Pin Simplex mode */ +#define PIC32_UMODE_IREN 0x1000 /* IrDA Encoder and Decoder Enable bit */ +#define PIC32_UMODE_SIDL 0x2000 /* Stop in Idle Mode */ +#define PIC32_UMODE_FRZ 0x4000 /* Freeze in Debug Exception Mode */ +#define PIC32_UMODE_ON 0x8000 /* UART Enable */ + +/* + * UART Control and status register. + */ +#define PIC32_USTA_URXDA 0x00000001 /* Receive Data Available (read-only) */ +#define PIC32_USTA_OERR 0x00000002 /* Receive Buffer Overrun */ +#define PIC32_USTA_FERR 0x00000004 /* Framing error detected (read-only) */ +#define PIC32_USTA_PERR 0x00000008 /* Parity error detected (read-only) */ +#define PIC32_USTA_RIDLE 0x00000010 /* Receiver is idle (read-only) */ +#define PIC32_USTA_ADDEN 0x00000020 /* Address Detect mode */ +#define PIC32_USTA_URXISEL 0x000000C0 /* Bitmask: receive interrupt is set when... */ +#define PIC32_USTA_URXISEL_NEMP 0x00000000 /* ...receive buffer is not empty */ +#define PIC32_USTA_URXISEL_HALF 0x00000040 /* ...receive buffer becomes 1/2 full */ +#define PIC32_USTA_URXISEL_3_4 0x00000080 /* ...receive buffer becomes 3/4 full */ +#define PIC32_USTA_TRMT 0x00000100 /* Transmit shift register is empty (read-only) */ +#define PIC32_USTA_UTXBF 0x00000200 /* Transmit buffer is full (read-only) */ +#define PIC32_USTA_UTXEN 0x00000400 /* Transmit Enable */ +#define PIC32_USTA_UTXBRK 0x00000800 /* Transmit Break */ +#define PIC32_USTA_URXEN 0x00001000 /* Receiver Enable */ +#define PIC32_USTA_UTXINV 0x00002000 /* Transmit Polarity Inversion */ +#define PIC32_USTA_UTXISEL 0x0000C000 /* Bitmask: TX interrupt is generated when... */ +#define PIC32_USTA_UTXISEL_1 0x00000000 /* ...the transmit buffer contains at least one empty space */ +#define PIC32_USTA_UTXISEL_ALL 0x00004000 /* ...all characters have been transmitted */ +#define PIC32_USTA_UTXISEL_EMP 0x00008000 /* ...the transmit buffer becomes empty */ +#define PIC32_USTA_ADDR 0x00FF0000 /* Automatic Address Mask */ +#define PIC32_USTA_ADM_EN 0x01000000 /* Automatic Address Detect */ + +/* + * Compute the 16-bit baud rate divisor, given + * the bus frequency and baud rate. + * Round to the nearest integer. + */ +#define PIC32_BRG_BAUD(fr,bd) ((((fr)/8 + (bd)) / (bd) / 2) - 1) + +/*-------------------------------------- + * Port A-G registers. + */ +#define TRISA PIC32_R (0x86000) /* Port A: mask of inputs */ +#define TRISACLR PIC32_R (0x86004) +#define TRISASET PIC32_R (0x86008) +#define TRISAINV PIC32_R (0x8600C) +#define PORTA PIC32_R (0x86010) /* Port A: read inputs, write outputs */ +#define PORTACLR PIC32_R (0x86014) +#define PORTASET PIC32_R (0x86018) +#define PORTAINV PIC32_R (0x8601C) +#define LATA PIC32_R (0x86020) /* Port A: read/write outputs */ +#define LATACLR PIC32_R (0x86024) +#define LATASET PIC32_R (0x86028) +#define LATAINV PIC32_R (0x8602C) +#define ODCA PIC32_R (0x86030) /* Port A: open drain configuration */ +#define ODCACLR PIC32_R (0x86034) +#define ODCASET PIC32_R (0x86038) +#define ODCAINV PIC32_R (0x8603C) + +#define TRISB PIC32_R (0x86040) /* Port B: mask of inputs */ +#define TRISBCLR PIC32_R (0x86044) +#define TRISBSET PIC32_R (0x86048) +#define TRISBINV PIC32_R (0x8604C) +#define PORTB PIC32_R (0x86050) /* Port B: read inputs, write outputs */ +#define PORTBCLR PIC32_R (0x86054) +#define PORTBSET PIC32_R (0x86058) +#define PORTBINV PIC32_R (0x8605C) +#define LATB PIC32_R (0x86060) /* Port B: read/write outputs */ +#define LATBCLR PIC32_R (0x86064) +#define LATBSET PIC32_R (0x86068) +#define LATBINV PIC32_R (0x8606C) +#define ODCB PIC32_R (0x86070) /* Port B: open drain configuration */ +#define ODCBCLR PIC32_R (0x86074) +#define ODCBSET PIC32_R (0x86078) +#define ODCBINV PIC32_R (0x8607C) + +#define TRISC PIC32_R (0x86080) /* Port C: mask of inputs */ +#define TRISCCLR PIC32_R (0x86084) +#define TRISCSET PIC32_R (0x86088) +#define TRISCINV PIC32_R (0x8608C) +#define PORTC PIC32_R (0x86090) /* Port C: read inputs, write outputs */ +#define PORTCCLR PIC32_R (0x86094) +#define PORTCSET PIC32_R (0x86098) +#define PORTCINV PIC32_R (0x8609C) +#define LATC PIC32_R (0x860A0) /* Port C: read/write outputs */ +#define LATCCLR PIC32_R (0x860A4) +#define LATCSET PIC32_R (0x860A8) +#define LATCINV PIC32_R (0x860AC) +#define ODCC PIC32_R (0x860B0) /* Port C: open drain configuration */ +#define ODCCCLR PIC32_R (0x860B4) +#define ODCCSET PIC32_R (0x860B8) +#define ODCCINV PIC32_R (0x860BC) + +#define TRISD PIC32_R (0x860C0) /* Port D: mask of inputs */ +#define TRISDCLR PIC32_R (0x860C4) +#define TRISDSET PIC32_R (0x860C8) +#define TRISDINV PIC32_R (0x860CC) +#define PORTD PIC32_R (0x860D0) /* Port D: read inputs, write outputs */ +#define PORTDCLR PIC32_R (0x860D4) +#define PORTDSET PIC32_R (0x860D8) +#define PORTDINV PIC32_R (0x860DC) +#define LATD PIC32_R (0x860E0) /* Port D: read/write outputs */ +#define LATDCLR PIC32_R (0x860E4) +#define LATDSET PIC32_R (0x860E8) +#define LATDINV PIC32_R (0x860EC) +#define ODCD PIC32_R (0x860F0) /* Port D: open drain configuration */ +#define ODCDCLR PIC32_R (0x860F4) +#define ODCDSET PIC32_R (0x860F8) +#define ODCDINV PIC32_R (0x860FC) + +#define TRISE PIC32_R (0x86100) /* Port E: mask of inputs */ +#define TRISECLR PIC32_R (0x86104) +#define TRISESET PIC32_R (0x86108) +#define TRISEINV PIC32_R (0x8610C) +#define PORTE PIC32_R (0x86110) /* Port E: read inputs, write outputs */ +#define PORTECLR PIC32_R (0x86114) +#define PORTESET PIC32_R (0x86118) +#define PORTEINV PIC32_R (0x8611C) +#define LATE PIC32_R (0x86120) /* Port E: read/write outputs */ +#define LATECLR PIC32_R (0x86124) +#define LATESET PIC32_R (0x86128) +#define LATEINV PIC32_R (0x8612C) +#define ODCE PIC32_R (0x86130) /* Port E: open drain configuration */ +#define ODCECLR PIC32_R (0x86134) +#define ODCESET PIC32_R (0x86138) +#define ODCEINV PIC32_R (0x8613C) + +#define TRISF PIC32_R (0x86140) /* Port F: mask of inputs */ +#define TRISFCLR PIC32_R (0x86144) +#define TRISFSET PIC32_R (0x86148) +#define TRISFINV PIC32_R (0x8614C) +#define PORTF PIC32_R (0x86150) /* Port F: read inputs, write outputs */ +#define PORTFCLR PIC32_R (0x86154) +#define PORTFSET PIC32_R (0x86158) +#define PORTFINV PIC32_R (0x8615C) +#define LATF PIC32_R (0x86160) /* Port F: read/write outputs */ +#define LATFCLR PIC32_R (0x86164) +#define LATFSET PIC32_R (0x86168) +#define LATFINV PIC32_R (0x8616C) +#define ODCF PIC32_R (0x86170) /* Port F: open drain configuration */ +#define ODCFCLR PIC32_R (0x86174) +#define ODCFSET PIC32_R (0x86178) +#define ODCFINV PIC32_R (0x8617C) + +#define TRISG PIC32_R (0x86180) /* Port G: mask of inputs */ +#define TRISGCLR PIC32_R (0x86184) +#define TRISGSET PIC32_R (0x86188) +#define TRISGINV PIC32_R (0x8618C) +#define PORTG PIC32_R (0x86190) /* Port G: read inputs, write outputs */ +#define PORTGCLR PIC32_R (0x86194) +#define PORTGSET PIC32_R (0x86198) +#define PORTGINV PIC32_R (0x8619C) +#define LATG PIC32_R (0x861A0) /* Port G: read/write outputs */ +#define LATGCLR PIC32_R (0x861A4) +#define LATGSET PIC32_R (0x861A8) +#define LATGINV PIC32_R (0x861AC) +#define ODCG PIC32_R (0x861B0) /* Port G: open drain configuration */ +#define ODCGCLR PIC32_R (0x861B4) +#define ODCGSET PIC32_R (0x861B8) +#define ODCGINV PIC32_R (0x861BC) + +#define CNCON PIC32_R (0x861C0) /* Interrupt-on-change control */ +#define CNCONCLR PIC32_R (0x861C4) +#define CNCONSET PIC32_R (0x861C8) +#define CNCONINV PIC32_R (0x861CC) +#define CNEN PIC32_R (0x861D0) /* Input change interrupt enable */ +#define CNENCLR PIC32_R (0x861D4) +#define CNENSET PIC32_R (0x861D8) +#define CNENINV PIC32_R (0x861DC) +#define CNPUE PIC32_R (0x861E0) /* Input pin pull-up enable */ +#define CNPUECLR PIC32_R (0x861E4) +#define CNPUESET PIC32_R (0x861E8) +#define CNPUEINV PIC32_R (0x861EC) + +/*-------------------------------------- + * A/D Converter registers. + */ +#define AD1CON1 PIC32_R (0x9000) /* Control register 1 */ +#define AD1CON1CLR PIC32_R (0x9004) +#define AD1CON1SET PIC32_R (0x9008) +#define AD1CON1INV PIC32_R (0x900C) +#define AD1CON2 PIC32_R (0x9010) /* Control register 2 */ +#define AD1CON2CLR PIC32_R (0x9014) +#define AD1CON2SET PIC32_R (0x9018) +#define AD1CON2INV PIC32_R (0x901C) +#define AD1CON3 PIC32_R (0x9020) /* Control register 3 */ +#define AD1CON3CLR PIC32_R (0x9024) +#define AD1CON3SET PIC32_R (0x9028) +#define AD1CON3INV PIC32_R (0x902C) +#define AD1CHS PIC32_R (0x9040) /* Channel select */ +#define AD1CHSCLR PIC32_R (0x9044) +#define AD1CHSSET PIC32_R (0x9048) +#define AD1CHSINV PIC32_R (0x904C) +#define AD1CSSL PIC32_R (0x9050) /* Input scan selection */ +#define AD1CSSLCLR PIC32_R (0x9054) +#define AD1CSSLSET PIC32_R (0x9058) +#define AD1CSSLINV PIC32_R (0x905C) +#define AD1PCFG PIC32_R (0x9060) /* Port configuration */ +#define AD1PCFGCLR PIC32_R (0x9064) +#define AD1PCFGSET PIC32_R (0x9068) +#define AD1PCFGINV PIC32_R (0x906C) +#define ADC1BUF0 PIC32_R (0x9070) /* Result words */ +#define ADC1BUF1 PIC32_R (0x9080) +#define ADC1BUF2 PIC32_R (0x9090) +#define ADC1BUF3 PIC32_R (0x90A0) +#define ADC1BUF4 PIC32_R (0x90B0) +#define ADC1BUF5 PIC32_R (0x90C0) +#define ADC1BUF6 PIC32_R (0x90D0) +#define ADC1BUF7 PIC32_R (0x90E0) +#define ADC1BUF8 PIC32_R (0x90F0) +#define ADC1BUF9 PIC32_R (0x9100) +#define ADC1BUFA PIC32_R (0x9110) +#define ADC1BUFB PIC32_R (0x9120) +#define ADC1BUFC PIC32_R (0x9130) +#define ADC1BUFD PIC32_R (0x9140) +#define ADC1BUFE PIC32_R (0x9150) +#define ADC1BUFF PIC32_R (0x9160) + +/*-------------------------------------- + * Parallel master port registers. + */ +#define PMCON PIC32_R (0x7000) /* Control */ +#define PMCONCLR PIC32_R (0x7004) +#define PMCONSET PIC32_R (0x7008) +#define PMCONINV PIC32_R (0x700C) +#define PMMODE PIC32_R (0x7010) /* Mode */ +#define PMMODECLR PIC32_R (0x7014) +#define PMMODESET PIC32_R (0x7018) +#define PMMODEINV PIC32_R (0x701C) +#define PMADDR PIC32_R (0x7020) /* Address */ +#define PMADDRCLR PIC32_R (0x7024) +#define PMADDRSET PIC32_R (0x7028) +#define PMADDRINV PIC32_R (0x702C) +#define PMDOUT PIC32_R (0x7030) /* Data output */ +#define PMDOUTCLR PIC32_R (0x7034) +#define PMDOUTSET PIC32_R (0x7038) +#define PMDOUTINV PIC32_R (0x703C) +#define PMDIN PIC32_R (0x7040) /* Data input */ +#define PMDINCLR PIC32_R (0x7044) +#define PMDINSET PIC32_R (0x7048) +#define PMDININV PIC32_R (0x704C) +#define PMAEN PIC32_R (0x7050) /* Pin enable */ +#define PMAENCLR PIC32_R (0x7054) +#define PMAENSET PIC32_R (0x7058) +#define PMAENINV PIC32_R (0x705C) +#define PMSTAT PIC32_R (0x7060) /* Status (slave only) */ +#define PMSTATCLR PIC32_R (0x7064) +#define PMSTATSET PIC32_R (0x7068) +#define PMSTATINV PIC32_R (0x706C) + +/* + * PMP Control register. + */ +#define PIC32_PMCON_RDSP 0x0001 /* Read strobe polarity active-high */ +#define PIC32_PMCON_WRSP 0x0002 /* Write strobe polarity active-high */ +#define PIC32_PMCON_CS1P 0x0008 /* Chip select 0 polarity active-high */ +#define PIC32_PMCON_CS2P 0x0010 /* Chip select 1 polarity active-high */ +#define PIC32_PMCON_ALP 0x0020 /* Address latch polarity active-high */ +#define PIC32_PMCON_CSF 0x00C0 /* Chip select function bitmask: */ +#define PIC32_PMCON_CSF_NONE 0x0000 /* PMCS2 and PMCS1 as A[15:14] */ +#define PIC32_PMCON_CSF_CS2 0x0040 /* PMCS2 as chip select */ +#define PIC32_PMCON_CSF_CS21 0x0080 /* PMCS2 and PMCS1 as chip select */ +#define PIC32_PMCON_PTRDEN 0x0100 /* Read/write strobe port enable */ +#define PIC32_PMCON_PTWREN 0x0200 /* Write enable strobe port enable */ +#define PIC32_PMCON_PMPTTL 0x0400 /* TTL input buffer select */ +#define PIC32_PMCON_ADRMUX 0x1800 /* Address/data mux selection bitmask: */ +#define PIC32_PMCON_ADRMUX_NONE 0x0000 /* Address and data separate */ +#define PIC32_PMCON_ADRMUX_AD 0x0800 /* Lower address on PMD[7:0], high on PMA[15:8] */ +#define PIC32_PMCON_ADRMUX_D8 0x1000 /* All address on PMD[7:0] */ +#define PIC32_PMCON_ADRMUX_D16 0x1800 /* All address on PMD[15:0] */ +#define PIC32_PMCON_SIDL 0x2000 /* Stop in idle */ +#define PIC32_PMCON_FRZ 0x4000 /* Freeze in debug exception */ +#define PIC32_PMCON_ON 0x8000 /* Parallel master port enable */ + +/* + * PMP Mode register. + */ +#define PIC32_PMMODE_WAITE(x) ((x)<<0) /* Wait states: data hold after RW strobe */ +#define PIC32_PMMODE_WAITM(x) ((x)<<2) /* Wait states: data RW strobe */ +#define PIC32_PMMODE_WAITB(x) ((x)<<6) /* Wait states: data setup to RW strobe */ +#define PIC32_PMMODE_MODE 0x0300 /* Mode select bitmask: */ +#define PIC32_PMMODE_MODE_SLAVE 0x0000 /* Legacy slave */ +#define PIC32_PMMODE_MODE_SLENH 0x0100 /* Enhanced slave */ +#define PIC32_PMMODE_MODE_MAST2 0x0200 /* Master mode 2 */ +#define PIC32_PMMODE_MODE_MAST1 0x0300 /* Master mode 1 */ +#define PIC32_PMMODE_MODE16 0x0400 /* 16-bit mode */ +#define PIC32_PMMODE_INCM 0x1800 /* Address increment mode bitmask: */ +#define PIC32_PMMODE_INCM_NONE 0x0000 /* No increment/decrement */ +#define PIC32_PMMODE_INCM_INC 0x0800 /* Increment address */ +#define PIC32_PMMODE_INCM_DEC 0x1000 /* Decrement address */ +#define PIC32_PMMODE_INCM_SLAVE 0x1800 /* Slave auto-increment */ +#define PIC32_PMMODE_IRQM 0x6000 /* Interrupt request bitmask: */ +#define PIC32_PMMODE_IRQM_DIS 0x0000 /* No interrupt generated */ +#define PIC32_PMMODE_IRQM_END 0x2000 /* Interrupt at end of read/write cycle */ +#define PIC32_PMMODE_IRQM_A3 0x4000 /* Interrupt on address 3 */ +#define PIC32_PMMODE_BUSY 0x8000 /* Port is busy */ + +/* + * PMP Address register. + */ +#define PIC32_PMADDR_PADDR 0x3FFF /* Destination address */ +#define PIC32_PMADDR_CS1 0x4000 /* Chip select 1 is active */ +#define PIC32_PMADDR_CS2 0x8000 /* Chip select 2 is active */ + +/* + * PMP status register (slave only). + */ +#define PIC32_PMSTAT_OB0E 0x0001 /* Output buffer 0 empty */ +#define PIC32_PMSTAT_OB1E 0x0002 /* Output buffer 1 empty */ +#define PIC32_PMSTAT_OB2E 0x0004 /* Output buffer 2 empty */ +#define PIC32_PMSTAT_OB3E 0x0008 /* Output buffer 3 empty */ +#define PIC32_PMSTAT_OBUF 0x0040 /* Output buffer underflow */ +#define PIC32_PMSTAT_OBE 0x0080 /* Output buffer empty */ +#define PIC32_PMSTAT_IB0F 0x0100 /* Input buffer 0 full */ +#define PIC32_PMSTAT_IB1F 0x0200 /* Input buffer 1 full */ +#define PIC32_PMSTAT_IB2F 0x0400 /* Input buffer 2 full */ +#define PIC32_PMSTAT_IB3F 0x0800 /* Input buffer 3 full */ +#define PIC32_PMSTAT_IBOV 0x4000 /* Input buffer overflow */ +#define PIC32_PMSTAT_IBF 0x8000 /* Input buffer full */ + +/*-------------------------------------- + * USB registers. + */ +#define U1OTGIR PIC32_R (0x85040) /* OTG interrupt flags */ +#define U1OTGIE PIC32_R (0x85050) /* OTG interrupt enable */ +#define U1OTGSTAT PIC32_R (0x85060) /* Comparator and pin status */ +#define U1OTGCON PIC32_R (0x85070) /* Resistor and pin control */ +#define U1PWRC PIC32_R (0x85080) /* Power control */ +#define U1IR PIC32_R (0x85200) /* Pending interrupt */ +#define U1IE PIC32_R (0x85210) /* Interrupt enable */ +#define U1EIR PIC32_R (0x85220) /* Pending error interrupt */ +#define U1EIE PIC32_R (0x85230) /* Error interrupt enable */ +#define U1STAT PIC32_R (0x85240) /* Status FIFO */ +#define U1CON PIC32_R (0x85250) /* Control */ +#define U1ADDR PIC32_R (0x85260) /* Address */ +#define U1BDTP1 PIC32_R (0x85270) /* Buffer descriptor table pointer 1 */ +#define U1FRML PIC32_R (0x85280) /* Frame counter low */ +#define U1FRMH PIC32_R (0x85290) /* Frame counter high */ +#define U1TOK PIC32_R (0x852A0) /* Host control */ +#define U1SOF PIC32_R (0x852B0) /* SOF counter */ +#define U1BDTP2 PIC32_R (0x852C0) /* Buffer descriptor table pointer 2 */ +#define U1BDTP3 PIC32_R (0x852D0) /* Buffer descriptor table pointer 3 */ +#define U1CNFG1 PIC32_R (0x852E0) /* Debug and idle */ +#define U1EP(n) PIC32_R (0x85300 + (n << 4)) /* Endpoint control */ + +/* + * USB Control register. + */ +#define PIC32_U1CON_USBEN 0x0001 /* USB module enable (device mode) */ +#define PIC32_U1CON_SOFEN 0x0001 /* SOF sent every 1 ms (host mode) */ +#define PIC32_U1CON_PPBRST 0x0002 /* Ping-pong buffers reset */ +#define PIC32_U1CON_RESUME 0x0004 /* Resume signaling enable */ +#define PIC32_U1CON_HOSTEN 0x0008 /* Host mode enable */ +#define PIC32_U1CON_USBRST 0x0010 /* USB reset */ +#define PIC32_U1CON_PKTDIS 0x0020 /* Packet transfer disable */ +#define PIC32_U1CON_TOKBUSY 0x0020 /* Token busy indicator */ +#define PIC32_U1CON_SE0 0x0040 /* Single ended zero detected */ +#define PIC32_U1CON_JSTATE 0x0080 /* Live differential receiver JSTATE flag */ + +/* + * USB Power control register. + */ +#define PIC32_U1PWRC_USBPWR 0x0001 /* USB operation enable */ +#define PIC32_U1PWRC_USUSPEND 0x0002 /* USB suspend mode */ +#define PIC32_U1PWRC_USLPGRD 0x0010 /* USB sleep entry guard */ +#define PIC32_U1PWRC_UACTPND 0x0080 /* UAB activity pending */ + +/* + * USB Pending interrupt register. + * USB Interrupt enable register. + */ +#define PIC32_U1I_DETACH 0x0001 /* Detach (host mode) */ +#define PIC32_U1I_URST 0x0001 /* USB reset (device mode) */ +#define PIC32_U1I_UERR 0x0002 /* USB error condition */ +#define PIC32_U1I_SOF 0x0004 /* SOF token */ +#define PIC32_U1I_TRN 0x0008 /* Token processing complete */ +#define PIC32_U1I_IDLE 0x0010 /* Idle detect */ +#define PIC32_U1I_RESUME 0x0020 /* Resume */ +#define PIC32_U1I_ATTACH 0x0040 /* Peripheral attach */ +#define PIC32_U1I_STALL 0x0080 /* STALL handshake */ + +/* + * USB OTG interrupt flags register. + * USB OTG interrupt enable register. + */ +#define PIC32_U1OTGI_VBUSVD 0x0001 /* A-device Vbus change */ +#define PIC32_U1OTGI_SESEND 0x0004 /* B-device Vbus change */ +#define PIC32_U1OTGI_SESVD 0x0008 /* Session valid change */ +#define PIC32_U1OTGI_ACTV 0x0010 /* Bus activity indicator */ +#define PIC32_U1OTGI_LSTATE 0x0020 /* Line state stable */ +#define PIC32_U1OTGI_T1MSEC 0x0040 /* 1 millisecond timer expired */ +#define PIC32_U1OTGI_ID 0x0080 /* ID state change */ + +#define PIC32_U1OTGSTAT_VBUSVD 0x0001 /* */ +#define PIC32_U1OTGSTAT_SESEND 0x0004 /* */ +#define PIC32_U1OTGSTAT_SESVD 0x0008 /* */ +#define PIC32_U1OTGSTAT_LSTATE 0x0020 /* */ +#define PIC32_U1OTGSTAT_ID 0x0080 /* */ + +#define PIC32_U1OTGCON_VBUSDIS 0x0001 /* */ +#define PIC32_U1OTGCON_VBUSCHG 0x0002 /* */ +#define PIC32_U1OTGCON_OTGEN 0x0004 /* */ +#define PIC32_U1OTGCON_VBUSON 0x0008 /* */ +#define PIC32_U1OTGCON_DMPULDWN 0x0010 /* */ +#define PIC32_U1OTGCON_DPPULDWN 0x0020 /* */ +#define PIC32_U1OTGCON_DMPULUP 0x0040 /* */ +#define PIC32_U1OTGCON_DPPULUP 0x0080 /* */ + +#define PIC32_U1EI_PID 0x0001 /* */ +#define PIC32_U1EI_CRC5 0x0002 /* */ +#define PIC32_U1EI_EOF 0x0002 /* */ +#define PIC32_U1EI_CRC16 0x0004 /* */ +#define PIC32_U1EI_DFN8 0x0008 /* */ +#define PIC32_U1EI_BTO 0x0010 /* */ +#define PIC32_U1EI_DMA 0x0020 /* */ +#define PIC32_U1EI_BMX 0x0040 /* */ +#define PIC32_U1EI_BTS 0x0080 /* */ + +#define PIC32_U1STAT_PPBI 0x0004 /* */ +#define PIC32_U1STAT_DIR 0x0008 /* */ +#define PIC32_U1STAT_ENDPT(x) (((x) >> 4) & 0xF) /* */ + +#define PIC32_U1ADDR_DEVADDR 0x007F /* */ +#define PIC32_U1ADDR_USBADDR0 0x0001 /* */ +#define PIC32_U1ADDR_DEVADDR1 0x0002 /* */ +#define PIC32_U1ADDR_DEVADDR2 0x0004 /* */ +#define PIC32_U1ADDR_DEVADDR3 0x0008 /* */ +#define PIC32_U1ADDR_DEVADDR4 0x0010 /* */ +#define PIC32_U1ADDR_DEVADDR5 0x0020 /* */ +#define PIC32_U1ADDR_DEVADDR6 0x0040 /* */ +#define PIC32_U1ADDR_LSPDEN 0x0080 /* */ + +#define PIC32_U1FRML_FRM0 0x0001 /* */ +#define PIC32_U1FRML_FRM1 0x0002 /* */ +#define PIC32_U1FRML_FRM2 0x0004 /* */ +#define PIC32_U1FRML_FRM3 0x0008 /* */ +#define PIC32_U1FRML_FRM4 0x0010 /* */ +#define PIC32_U1FRML_FRM5 0x0020 /* */ +#define PIC32_U1FRML_FRM6 0x0040 /* */ +#define PIC32_U1FRML_FRM7 0x0080 /* */ + +#define PIC32_U1FRMH_FRM8 0x0001 /* */ +#define PIC32_U1FRMH_FRM9 0x0002 /* */ +#define PIC32_U1FRMH_FRM10 0x0004 /* */ + +#define PIC32_U1TOK_EP0 0x0001 /* */ +#define PIC32_U1TOK_EP 0x000F /* */ +#define PIC32_U1TOK_EP1 0x0002 /* */ +#define PIC32_U1TOK_EP2 0x0004 /* */ +#define PIC32_U1TOK_EP3 0x0008 /* */ +#define PIC32_U1TOK_PID0 0x0010 /* */ +#define PIC32_U1TOK_PID 0x00F0 /* */ +#define PIC32_U1TOK_PID1 0x0020 /* */ +#define PIC32_U1TOK_PID2 0x0040 /* */ +#define PIC32_U1TOK_PID3 0x0080 /* */ + +#define PIC32_U1CNFG1_USBSIDL 0x0010 /* */ +#define PIC32_U1CNFG1_USBFRZ 0x0020 /* */ +#define PIC32_U1CNFG1_UOEMON 0x0040 /* */ +#define PIC32_U1CNFG1_UTEYE 0x0080 /* */ + +#define PIC32_U1EP_EPHSHK 0x0001 /* */ +#define PIC32_U1EP_EPSTALL 0x0002 /* */ +#define PIC32_U1EP_EPTXEN 0x0004 /* */ +#define PIC32_U1EP_EPRXEN 0x0008 /* */ +#define PIC32_U1EP_EPCONDIS 0x0010 /* */ +#define PIC32_U1EP_RETRYDIS 0x0040 /* */ +#define PIC32_U1EP_LSPD 0x0080 /* */ + +/* DB status field values */ +#define PIC32_DB_BSTALL (1 << 2) +#define PIC32_DB_DTS (1 << 3) +#define PIC32_DB_NINC (1 << 4) +#define PIC32_DB_KEEP (1 << 5) +#define PIC32_DB_DATA1 (1 << 6) +#define PIC32_DB_UOWN (1 << 7) +#define PIC32_DB_GET_PID(x) (((x) >> 2) & 0xF) +#define PIC32_DB_SET_PID(x) (((x) & 0xF) << 2) +#define PIC32_DB_GET_COUNT(x) (((x) >> 16) & 0x3FF) +#define PIC32_DB_SET_COUNT(x) (((x) & 0x3FF) << 16) + +/*-------------------------------------- + * SPI registers. + */ +#ifdef PIC32MX4 +#define SPI1CON PIC32_R (0x5800) /* Control */ +#define SPI1CONCLR PIC32_R (0x5804) +#define SPI1CONSET PIC32_R (0x5808) +#define SPI1CONINV PIC32_R (0x580C) +#define SPI1STAT PIC32_R (0x5810) /* Status */ +#define SPI1STATCLR PIC32_R (0x5814) +#define SPI1STATSET PIC32_R (0x5818) +#define SPI1STATINV PIC32_R (0x581C) +#define SPI1BUF PIC32_R (0x5820) /* Transmit and receive buffer */ +#define SPI1BRG PIC32_R (0x5830) /* Baud rate generator */ +#define SPI1BRGCLR PIC32_R (0x5834) +#define SPI1BRGSET PIC32_R (0x5838) +#define SPI1BRGINV PIC32_R (0x583C) +#endif +#ifdef PIC32MX7 +#define SPI3CON PIC32_R (0x5800) /* Control */ +#define SPI3CONCLR PIC32_R (0x5804) +#define SPI3CONSET PIC32_R (0x5808) +#define SPI3CONINV PIC32_R (0x580C) +#define SPI3STAT PIC32_R (0x5810) /* Status */ +#define SPI3STATCLR PIC32_R (0x5814) +#define SPI3STATSET PIC32_R (0x5818) +#define SPI3STATINV PIC32_R (0x581C) +#define SPI3BUF PIC32_R (0x5820) /* Transmit and receive buffer */ +#define SPI3BRG PIC32_R (0x5830) /* Baud rate generator */ +#define SPI3BRGCLR PIC32_R (0x5834) +#define SPI3BRGSET PIC32_R (0x5838) +#define SPI3BRGINV PIC32_R (0x583C) + +#define SPI4CON PIC32_R (0x5C00) /* Control */ +#define SPI4CONCLR PIC32_R (0x5C04) +#define SPI4CONSET PIC32_R (0x5C08) +#define SPI4CONINV PIC32_R (0x5C0C) +#define SPI4STAT PIC32_R (0x5C10) /* Status */ +#define SPI4STATCLR PIC32_R (0x5C14) +#define SPI4STATSET PIC32_R (0x5C18) +#define SPI4STATINV PIC32_R (0x5C1C) +#define SPI4BUF PIC32_R (0x5C20) /* Transmit and receive buffer */ +#define SPI4BRG PIC32_R (0x5C30) /* Baud rate generator */ +#define SPI4BRGCLR PIC32_R (0x5C34) +#define SPI4BRGSET PIC32_R (0x5C38) +#define SPI4BRGINV PIC32_R (0x5C3C) + +#define SPI1CON PIC32_R (0x5E00) /* Control */ +#define SPI1CONCLR PIC32_R (0x5E04) +#define SPI1CONSET PIC32_R (0x5E08) +#define SPI1CONINV PIC32_R (0x5E0C) +#define SPI1STAT PIC32_R (0x5E10) /* Status */ +#define SPI1STATCLR PIC32_R (0x5E14) +#define SPI1STATSET PIC32_R (0x5E18) +#define SPI1STATINV PIC32_R (0x5E1C) +#define SPI1BUF PIC32_R (0x5E20) /* Transmit and receive buffer */ +#define SPI1BRG PIC32_R (0x5E30) /* Baud rate generator */ +#define SPI1BRGCLR PIC32_R (0x5E34) +#define SPI1BRGSET PIC32_R (0x5E38) +#define SPI1BRGINV PIC32_R (0x5E3C) +#endif + +#define SPI2CON PIC32_R (0x5A00) /* Control */ +#define SPI2CONCLR PIC32_R (0x5A04) +#define SPI2CONSET PIC32_R (0x5A08) +#define SPI2CONINV PIC32_R (0x5A0C) +#define SPI2STAT PIC32_R (0x5A10) /* Status */ +#define SPI2STATCLR PIC32_R (0x5A14) +#define SPI2STATSET PIC32_R (0x5A18) +#define SPI2STATINV PIC32_R (0x5A1C) +#define SPI2BUF PIC32_R (0x5A20) /* Transmit and receive buffer */ +#define SPI2BRG PIC32_R (0x5A30) /* Baud rate generator */ +#define SPI2BRGCLR PIC32_R (0x5A34) +#define SPI2BRGSET PIC32_R (0x5A38) +#define SPI2BRGINV PIC32_R (0x5A3C) + +/* + * SPI Control register. + */ +#define PIC32_SPICON_MSTEN 0x00000020 /* Master mode */ +#define PIC32_SPICON_CKP 0x00000040 /* Idle clock is high level */ +#define PIC32_SPICON_SSEN 0x00000080 /* Slave mode: SSx pin enable */ +#define PIC32_SPICON_CKE 0x00000100 /* Output data changes on + * transition from active clock + * state to Idle clock state */ +#define PIC32_SPICON_SMP 0x00000200 /* Master mode: input data sampled + * at end of data output time. */ +#define PIC32_SPICON_MODE16 0x00000400 /* 16-bit data width */ +#define PIC32_SPICON_MODE32 0x00000800 /* 32-bit data width */ +#define PIC32_SPICON_DISSDO 0x00001000 /* SDOx pin is not used */ +#define PIC32_SPICON_SIDL 0x00002000 /* Stop in Idle mode */ +#define PIC32_SPICON_FRZ 0x00004000 /* Freeze in Debug mode */ +#define PIC32_SPICON_ON 0x00008000 /* SPI Peripheral is enabled */ +#define PIC32_SPICON_ENHBUF 0x00010000 /* Enhanced buffer enable */ +#define PIC32_SPICON_SPIFE 0x00020000 /* Frame synchronization pulse + * coincides with the first bit clock */ +#define PIC32_SPICON_FRMPOL 0x20000000 /* Frame pulse is active-high */ +#define PIC32_SPICON_FRMSYNC 0x40000000 /* Frame sync pulse input (Slave mode) */ +#define PIC32_SPICON_FRMEN 0x80000000 /* Framed SPI support */ + +/* + * SPI Status register. + */ +#define PIC32_SPISTAT_SPIRBF 0x00000001 /* Receive buffer is full */ +#define PIC32_SPISTAT_SPITBF 0x00000002 /* Transmit buffer is full */ +#define PIC32_SPISTAT_SPITBE 0x00000008 /* Transmit buffer is empty */ +#define PIC32_SPISTAT_SPIRBE 0x00000020 /* Receive buffer is empty */ +#define PIC32_SPISTAT_SPIROV 0x00000040 /* Receive overflow flag */ +#define PIC32_SPISTAT_SPIBUSY 0x00000800 /* SPI is busy */ + +/*-------------------------------------- + * DMA controller registers. + */ +#define DMACON PIC32_R (0x83000) /* DMA Control */ +#define DMACONCLR PIC32_R (0x83004) +#define DMACONSET PIC32_R (0x83008) +#define DMACONINV PIC32_R (0x8300C) +#define DMASTAT PIC32_R (0x83010) /* DMA Status */ +#define DMAADDR PIC32_R (0x83020) /* DMA Address */ +// TODO: other DMA registers. + +/*-------------------------------------- + * System controller registers. + */ +#define OSCCON PIC32_R (0xf000) +#define OSCTUN PIC32_R (0xf010) +#define DDPCON PIC32_R (0xf200) /* Debug Data Port Control */ +#define DEVID PIC32_R (0xf220) +#define SYSKEY PIC32_R (0xf230) +#define RCON PIC32_R (0xf600) +#define RCONCLR PIC32_R (0xf604) +#define RCONSET PIC32_R (0xf608) +#define RCONINV PIC32_R (0xf60C) +#define RSWRST PIC32_R (0xf610) +#define RSWRSTCLR PIC32_R (0xf614) +#define RSWRSTSET PIC32_R (0xf618) +#define RSWRSTINV PIC32_R (0xf61C) + +/* + * Reset control register. + */ +#define PIC32_RCON_POR 0x00000001 +#define PIC32_RCON_BOR 0x00000002 +#define PIC32_RCON_IDLE 0x00000004 +#define PIC32_RCON_SLEEP 0x00000008 +#define PIC32_RCON_WDTO 0x00000010 +#define PIC32_RCON_SWR 0x00000040 +#define PIC32_RCON_EXTR 0x00000080 +#define PIC32_RCON_VREGS 0x00000100 +#define PIC32_RCON_CMR 0x00000200 + +/*-------------------------------------- + * Prefetch cache controller registers. + */ +#define CHECON PIC32_R (0x84000) /* Prefetch cache control */ +#define CHECONCLR PIC32_R (0x84004) +#define CHECONSET PIC32_R (0x84008) +#define CHECONINV PIC32_R (0x8400C) +// TODO: other prefetech registers + +/*-------------------------------------- + * Bus matrix control registers. + */ +#define BMXCON PIC32_R (0x82000) /* Memory configuration */ +#define BMXCONCLR PIC32_R (0x82004) +#define BMXCONSET PIC32_R (0x82008) +#define BMXCONINV PIC32_R (0x8200C) +#define BMXDKPBA PIC32_R (0x82010) /* Data RAM kernel program base address */ +#define BMXDUDBA PIC32_R (0x82020) /* Data RAM user data base address */ +#define BMXDUPBA PIC32_R (0x82030) /* Data RAM user program base address */ +#define BMXDRMSZ PIC32_R (0x82040) /* Data RAM size */ +#define BMXPUPBA PIC32_R (0x82050) /* Program Flash user program base address */ +#define BMXPFMSZ PIC32_R (0x82060) /* Program Flash size */ +#define BMXBOOTSZ PIC32_R (0x82070) /* Boot Flash size */ + +/*-------------------------------------- + * Non-volatile memory control registers. + */ +#define NVMCON PIC32_R (0x0F400) +#define NVMCONCLR PIC32_R (0x0F404) +#define NVMCONSET PIC32_R (0x0F408) +#define NVMCONINV PIC32_R (0x0F40C) +#define NVMKEY PIC32_R (0x0F410) +#define NVMADDR PIC32_R (0x0F420) +#define NVMADDRCLR PIC32_R (0x0F424) +#define NVMADDRSET PIC32_R (0x0F428) +#define NVMADDRINV PIC32_R (0x0F42C) +#define NVMDATA PIC32_R (0x0F430) +#define NVMSRCADDR PIC32_R (0x0F440) + +#define PIC32_NVMCON_NVMOP 0x0000000F +#define PIC32_NVMCON_NOP 0 /* No operation */ +#define PIC32_NVMCON_WORD_PGM 1 /* Word program */ +#define PIC32_NVMCON_ROW_PGM 3 /* Row program */ +#define PIC32_NVMCON_PAGE_ERASE 4 /* Page erase */ + +#define PIC32_NVMCON_LVDSTAT 0x00000800 +#define PIC32_NVMCON_LVDERR 0x00001000 +#define PIC32_NVMCON_WRERR 0x00002000 +#define PIC32_NVMCON_WREN 0x00004000 +#define PIC32_NVMCON_WR 0x00008000 + + +/* + * Timer2 registers + */ +#define T2CON PIC32_R (0x0800) +#define T2CONSET PIC32_R (0x0808) +#define TMR2 PIC32_R (0x0810) +#define PR2 PIC32_R (0x0820) + +/* + * Output compare registers + */ +#define OC1CON PIC32_R (0x3000) +#define OC1R PIC32_R (0x3010) +#define OC1RS PIC32_R (0x3020) +#define OC4CON PIC32_R (0x3600) +#define OC4R PIC32_R (0x3610) +#define OC4RS PIC32_R (0x3620) + +#define BLRKEY *(volatile unsigned*)(0x80000000) + +/*-------------------------------------- + * Configuration registers. + */ +#define DEVCFG0 *(volatile unsigned*)0x9fc02ffc +#define DEVCFG1 *(volatile unsigned*)0x9fc02ff8 +#define DEVCFG2 *(volatile unsigned*)0x9fc02ff4 +#define DEVCFG3 *(volatile unsigned*)0x9fc02ff0 + +#define PIC32_DEVCFG(cfg0, cfg1, cfg2, cfg3) \ + asm (".section .config"); \ + unsigned __DEVCFG0 __attribute__ ((section (".config0"))) = (cfg0) ^ 0x7fffffff; \ + unsigned __DEVCFG1 __attribute__ ((section (".config1"))) = (cfg1) | DEVCFG1_UNUSED; \ + unsigned __DEVCFG2 __attribute__ ((section (".config2"))) = (cfg2) | DEVCFG2_UNUSED; \ + unsigned __DEVCFG3 __attribute__ ((section (".config3"))) = (cfg3) | DEVCFG3_UNUSED + +/* + * Config0 register at 1fc02ffc, inverted. + */ +#define DEVCFG0_DEBUG_MASK 0x00000003 /* Debugger enable bits */ +#define DEVCFG0_DEBUG_DISABLED 0x00000000 /* Debugger disabled */ +#define DEVCFG0_DEBUG_ENABLED 0x00000002 /* Debugger enabled */ +#define DEVCFG0_ICESEL 0x00000008 /* Use PGC1/PGD1 (default PGC2/PGD2) */ +#define DEVCFG0_PWP_MASK 0x000ff000 /* Program flash write protect */ +#define DEVCFG0_BWP 0x01000000 /* Boot flash write protect */ +#define DEVCFG0_CP 0x10000000 /* Code protect */ + +/* + * Config1 register at 1fc02ff8. + */ +#define DEVCFG1_UNUSED 0xff600858 +#define DEVCFG1_FNOSC_MASK 0x00000007 /* Oscillator selection */ +#define DEVCFG1_FNOSC_FRC 0x00000000 /* Fast RC */ +#define DEVCFG1_FNOSC_FRCDIVPLL 0x00000001 /* Fast RC with divide-by-N and PLL */ +#define DEVCFG1_FNOSC_PRI 0x00000002 /* Primary oscillator XT, HS, EC */ +#define DEVCFG1_FNOSC_PRIPLL 0x00000003 /* Primary with PLL */ +#define DEVCFG1_FNOSC_SEC 0x00000004 /* Secondary oscillator */ +#define DEVCFG1_FNOSC_LPRC 0x00000005 /* Low-power RC */ +#define DEVCFG1_FNOSC_FRCDIV 0x00000007 /* Fast RC with divide-by-N */ +#define DEVCFG1_FSOSCEN 0x00000020 /* Secondary oscillator enable */ +#define DEVCFG1_IESO 0x00000080 /* Internal-external switch over */ +#define DEVCFG1_POSCMOD_MASK 0x00000300 /* Primary oscillator config */ +#define DEVCFG1_POSCMOD_EXT 0x00000000 /* External mode */ +#define DEVCFG1_POSCMOD_XT 0x00000100 /* XT oscillator */ +#define DEVCFG1_POSCMOD_HS 0x00000200 /* HS oscillator */ +#define DEVCFG1_POSCMOD_DISABLE 0x00000300 /* Disabled */ +#define DEVCFG1_OSCIOFNC 0x00000400 /* CLKO output active */ +#define DEVCFG1_FPBDIV_MASK 0x00003000 /* Peripheral bus clock divisor */ +#define DEVCFG1_FPBDIV_1 0x00000000 /* SYSCLK / 1 */ +#define DEVCFG1_FPBDIV_2 0x00001000 /* SYSCLK / 2 */ +#define DEVCFG1_FPBDIV_4 0x00002000 /* SYSCLK / 4 */ +#define DEVCFG1_FPBDIV_8 0x00003000 /* SYSCLK / 8 */ +#define DEVCFG1_FCKM_DISABLE 0x00004000 /* Fail-safe clock monitor disable */ +#define DEVCFG1_FCKS_DISABLE 0x00008000 /* Clock switching disable */ +#define DEVCFG1_WDTPS_MASK 0x001f0000 /* Watchdog postscale */ +#define DEVCFG1_WDTPS_1 0x00000000 /* 1:1 */ +#define DEVCFG1_WDTPS_2 0x00010000 /* 1:2 */ +#define DEVCFG1_WDTPS_4 0x00020000 /* 1:4 */ +#define DEVCFG1_WDTPS_8 0x00030000 /* 1:8 */ +#define DEVCFG1_WDTPS_16 0x00040000 /* 1:16 */ +#define DEVCFG1_WDTPS_32 0x00050000 /* 1:32 */ +#define DEVCFG1_WDTPS_64 0x00060000 /* 1:64 */ +#define DEVCFG1_WDTPS_128 0x00070000 /* 1:128 */ +#define DEVCFG1_WDTPS_256 0x00080000 /* 1:256 */ +#define DEVCFG1_WDTPS_512 0x00090000 /* 1:512 */ +#define DEVCFG1_WDTPS_1024 0x000a0000 /* 1:1024 */ +#define DEVCFG1_WDTPS_2048 0x000b0000 /* 1:2048 */ +#define DEVCFG1_WDTPS_4096 0x000c0000 /* 1:4096 */ +#define DEVCFG1_WDTPS_8192 0x000d0000 /* 1:8192 */ +#define DEVCFG1_WDTPS_16384 0x000e0000 /* 1:16384 */ +#define DEVCFG1_WDTPS_32768 0x000f0000 /* 1:32768 */ +#define DEVCFG1_WDTPS_65536 0x00100000 /* 1:65536 */ +#define DEVCFG1_WDTPS_131072 0x00110000 /* 1:131072 */ +#define DEVCFG1_WDTPS_262144 0x00120000 /* 1:262144 */ +#define DEVCFG1_WDTPS_524288 0x00130000 /* 1:524288 */ +#define DEVCFG1_WDTPS_1048576 0x00140000 /* 1:1048576 */ +#define DEVCFG1_FWDTEN 0x00800000 /* Watchdog enable */ + +/* + * Config2 register at 1fc02ff4. + */ +#define DEVCFG2_UNUSED 0xfff87888 +#define DEVCFG2_FPLLIDIV_MASK 0x00000007 /* PLL input divider */ +#define DEVCFG2_FPLLIDIV_1 0x00000000 /* 1x */ +#define DEVCFG2_FPLLIDIV_2 0x00000001 /* 2x */ +#define DEVCFG2_FPLLIDIV_3 0x00000002 /* 3x */ +#define DEVCFG2_FPLLIDIV_4 0x00000003 /* 4x */ +#define DEVCFG2_FPLLIDIV_5 0x00000004 /* 5x */ +#define DEVCFG2_FPLLIDIV_6 0x00000005 /* 6x */ +#define DEVCFG2_FPLLIDIV_10 0x00000006 /* 10x */ +#define DEVCFG2_FPLLIDIV_12 0x00000007 /* 12x */ +#define DEVCFG2_FPLLMUL_MASK 0x00000070 /* PLL multiplier */ +#define DEVCFG2_FPLLMUL_15 0x00000000 /* 15x */ +#define DEVCFG2_FPLLMUL_16 0x00000010 /* 16x */ +#define DEVCFG2_FPLLMUL_17 0x00000020 /* 17x */ +#define DEVCFG2_FPLLMUL_18 0x00000030 /* 18x */ +#define DEVCFG2_FPLLMUL_19 0x00000040 /* 19x */ +#define DEVCFG2_FPLLMUL_20 0x00000050 /* 20x */ +#define DEVCFG2_FPLLMUL_21 0x00000060 /* 21x */ +#define DEVCFG2_FPLLMUL_24 0x00000070 /* 24x */ +#define DEVCFG2_UPLLIDIV_MASK 0x00000700 /* USB PLL input divider */ +#define DEVCFG2_UPLLIDIV_1 0x00000000 /* 1x */ +#define DEVCFG2_UPLLIDIV_2 0x00000100 /* 2x */ +#define DEVCFG2_UPLLIDIV_3 0x00000200 /* 3x */ +#define DEVCFG2_UPLLIDIV_4 0x00000300 /* 4x */ +#define DEVCFG2_UPLLIDIV_5 0x00000400 /* 5x */ +#define DEVCFG2_UPLLIDIV_6 0x00000500 /* 6x */ +#define DEVCFG2_UPLLIDIV_10 0x00000600 /* 10x */ +#define DEVCFG2_UPLLIDIV_12 0x00000700 /* 12x */ +#define DEVCFG2_UPLLDIS 0x00008000 /* Disable USB PLL */ +#define DEVCFG2_FPLLODIV_MASK 0x00070000 /* Default postscaler for PLL */ +#define DEVCFG2_FPLLODIV_1 0x00000000 /* 1x */ +#define DEVCFG2_FPLLODIV_2 0x00010000 /* 2x */ +#define DEVCFG2_FPLLODIV_4 0x00020000 /* 4x */ +#define DEVCFG2_FPLLODIV_8 0x00030000 /* 8x */ +#define DEVCFG2_FPLLODIV_16 0x00040000 /* 16x */ +#define DEVCFG2_FPLLODIV_32 0x00050000 /* 32x */ +#define DEVCFG2_FPLLODIV_64 0x00060000 /* 64x */ +#define DEVCFG2_FPLLODIV_256 0x00070000 /* 256x */ + +/* + * Config3 register at 1fc02ff0. + */ +#define DEVCFG3_UNUSED 0x38f80000 +#define DEVCFG3_USERID_MASK 0x0000ffff /* User-defined ID */ +#define DEVCFG3_USERID(x) ((x) & 0xffff) +#define DEVCFG3_FSRSSEL_MASK 0x00070000 /* SRS select */ +#define DEVCFG3_FSRSSEL_ALL 0x00000000 /* All irqs assigned to shadow set */ +#define DEVCFG3_FSRSSEL_1 0x00010000 /* Assign irq priority 1 to shadow set */ +#define DEVCFG3_FSRSSEL_2 0x00020000 /* Assign irq priority 2 to shadow set */ +#define DEVCFG3_FSRSSEL_3 0x00030000 /* Assign irq priority 3 to shadow set */ +#define DEVCFG3_FSRSSEL_4 0x00040000 /* Assign irq priority 4 to shadow set */ +#define DEVCFG3_FSRSSEL_5 0x00050000 /* Assign irq priority 5 to shadow set */ +#define DEVCFG3_FSRSSEL_6 0x00060000 /* Assign irq priority 6 to shadow set */ +#define DEVCFG3_FSRSSEL_7 0x00070000 /* Assign irq priority 7 to shadow set */ +#define DEVCFG3_FMIIEN 0x01000000 /* Ethernet MII enable */ +#define DEVCFG3_FETHIO 0x02000000 /* Ethernet pins default */ +#define DEVCFG3_FCANIO 0x04000000 /* CAN pins default */ +#define DEVCFG3_FUSBIDIO 0x40000000 /* USBID pin: controlled by USB */ +#define DEVCFG3_FVBUSONIO 0x80000000 /* VBuson pin: controlled by USB */ + +/*-------------------------------------- + * Interrupt controller registers. + */ +#define INTCON PIC32_R (0x81000) /* Interrupt Control */ +#define INTCONCLR PIC32_R (0x81004) +#define INTCONSET PIC32_R (0x81008) +#define INTCONINV PIC32_R (0x8100C) +#define INTSTAT PIC32_R (0x81010) /* Interrupt Status */ +#define IPTMR PIC32_R (0x81020) /* Temporal Proximity Timer */ +#define IPTMRCLR PIC32_R (0x81024) +#define IPTMRSET PIC32_R (0x81028) +#define IPTMRINV PIC32_R (0x8102C) +#define IFS(n) PIC32_R (0x81030+((n)<<4)) /* IFS(0..2) - Interrupt Flag Status */ +#define IFSCLR(n) PIC32_R (0x81034+((n)<<4)) +#define IFSSET(n) PIC32_R (0x81038+((n)<<4)) +#define IFSINV(n) PIC32_R (0x8103C+((n)<<4)) +#define IEC(n) PIC32_R (0x81060+((n)<<4)) /* IEC(0..2) - Interrupt Enable Control */ +#define IECCLR(n) PIC32_R (0x81064+((n)<<4)) +#define IECSET(n) PIC32_R (0x81068+((n)<<4)) +#define IECINV(n) PIC32_R (0x8106C+((n)<<4)) +#define IPC(n) PIC32_R (0x81090+((n)<<4)) /* IPC(0..12) - Interrupt Priority Control */ +#define IPCCLR(n) PIC32_R (0x81094+((n)<<4)) +#define IPCSET(n) PIC32_R (0x81098+((n)<<4)) +#define IPCINV(n) PIC32_R (0x8109C+((n)<<4)) + +/* + * Interrupt Control register. + */ +#define PIC32_INTCON_INT0EP 0x0001 /* External interrupt 0 polarity rising edge */ +#define PIC32_INTCON_INT1EP 0x0002 /* External interrupt 1 polarity rising edge */ +#define PIC32_INTCON_INT2EP 0x0004 /* External interrupt 2 polarity rising edge */ +#define PIC32_INTCON_INT3EP 0x0008 /* External interrupt 3 polarity rising edge */ +#define PIC32_INTCON_INT4EP 0x0010 /* External interrupt 4 polarity rising edge */ +#define PIC32_INTCON_TPC(x) ((x)<<8) /* Temporal proximity group priority */ +#define PIC32_INTCON_MVEC 0x1000 /* Multi-vectored mode */ +#define PIC32_INTCON_FRZ 0x4000 /* Freeze in debug mode */ +#define PIC32_INTCON_SS0 0x8000 /* Single vector has a shadow register set */ + +/* + * Interrupt Status register. + */ +#define PIC32_INTSTAT_VEC(s) ((s) & 0xFF) /* Interrupt vector */ +#define PIC32_INTSTAT_SRIPL(s) ((s) >> 8 & 7) /* Requested priority level */ +#define PIC32_INTSTAT_SRIPL_MASK 0x0700 + +/* + * Interrupt Prority Control register. + */ +#define PIC32_IPC_IS0(x) (x) /* Interrupt 0 subpriority */ +#define PIC32_IPC_IP0(x) ((x)<<2) /* Interrupt 0 priority */ +#define PIC32_IPC_IS1(x) ((x)<<8) /* Interrupt 1 subpriority */ +#define PIC32_IPC_IP1(x) ((x)<<10) /* Interrupt 1 priority */ +#define PIC32_IPC_IS2(x) ((x)<<16) /* Interrupt 2 subpriority */ +#define PIC32_IPC_IP2(x) ((x)<<18) /* Interrupt 2 priority */ +#define PIC32_IPC_IS3(x) ((x)<<24) /* Interrupt 3 subpriority */ +#define PIC32_IPC_IP3(x) ((x)<<26) /* Interrupt 3 priority */ + +/* + * IRQ numbers for PIC32MX3xx/4xx/5xx/6xx/7xx + */ +#define PIC32_IRQ_CT 0 /* Core Timer Interrupt */ +#define PIC32_IRQ_CS0 1 /* Core Software Interrupt 0 */ +#define PIC32_IRQ_CS1 2 /* Core Software Interrupt 1 */ +#define PIC32_IRQ_INT0 3 /* External Interrupt 0 */ +#define PIC32_IRQ_T1 4 /* Timer1 */ +#define PIC32_IRQ_IC1 5 /* Input Capture 1 */ +#define PIC32_IRQ_OC1 6 /* Output Compare 1 */ +#define PIC32_IRQ_INT1 7 /* External Interrupt 1 */ +#define PIC32_IRQ_T2 8 /* Timer2 */ +#define PIC32_IRQ_IC2 9 /* Input Capture 2 */ +#define PIC32_IRQ_OC2 10 /* Output Compare 2 */ +#define PIC32_IRQ_INT2 11 /* External Interrupt 2 */ +#define PIC32_IRQ_T3 12 /* Timer3 */ +#define PIC32_IRQ_IC3 13 /* Input Capture 3 */ +#define PIC32_IRQ_OC3 14 /* Output Compare 3 */ +#define PIC32_IRQ_INT3 15 /* External Interrupt 3 */ +#define PIC32_IRQ_T4 16 /* Timer4 */ +#define PIC32_IRQ_IC4 17 /* Input Capture 4 */ +#define PIC32_IRQ_OC4 18 /* Output Compare 4 */ +#define PIC32_IRQ_INT4 19 /* External Interrupt 4 */ +#define PIC32_IRQ_T5 20 /* Timer5 */ +#define PIC32_IRQ_IC5 21 /* Input Capture 5 */ +#define PIC32_IRQ_OC5 22 /* Output Compare 5 */ +#define PIC32_IRQ_SPI1E 23 /* SPI1 Fault */ +#define PIC32_IRQ_SPI1TX 24 /* SPI1 Transfer Done */ +#define PIC32_IRQ_SPI1RX 25 /* SPI1 Receive Done */ + +#define PIC32_IRQ_SPI3E 26 /* SPI3 Fault */ +#define PIC32_IRQ_SPI3TX 27 /* SPI3 Transfer Done */ +#define PIC32_IRQ_SPI3RX 28 /* SPI3 Receive Done */ +#define PIC32_IRQ_U1E 26 /* UART1 Error */ +#define PIC32_IRQ_U1RX 27 /* UART1 Receiver */ +#define PIC32_IRQ_U1TX 28 /* UART1 Transmitter */ +#define PIC32_IRQ_I2C3B 26 /* I2C3 Bus Collision Event */ +#define PIC32_IRQ_I2C3S 27 /* I2C3 Slave Event */ +#define PIC32_IRQ_I2C3M 28 /* I2C3 Master Event */ + +#define PIC32_IRQ_I2C1B 29 /* I2C1 Bus Collision Event */ +#define PIC32_IRQ_I2C1S 30 /* I2C1 Slave Event */ +#define PIC32_IRQ_I2C1M 31 /* I2C1 Master Event */ +#define PIC32_IRQ_CN 32 /* Input Change Interrupt */ +#define PIC32_IRQ_AD1 33 /* ADC1 Convert Done */ +#define PIC32_IRQ_PMP 34 /* Parallel Master Port */ +#define PIC32_IRQ_CMP1 35 /* Comparator Interrupt */ +#define PIC32_IRQ_CMP2 36 /* Comparator Interrupt */ + +#define PIC32_IRQ_SPI2E 37 /* SPI2 Fault */ +#define PIC32_IRQ_SPI2TX 38 /* SPI2 Transfer Done */ +#define PIC32_IRQ_SPI2RX 39 /* SPI2 Receive Done */ +#define PIC32_IRQ_U3E 37 /* UART3 Error */ +#define PIC32_IRQ_U3RX 38 /* UART3 Receiver */ +#define PIC32_IRQ_U3TX 39 /* UART3 Transmitter */ +#define PIC32_IRQ_I2C4B 37 /* I2C4 Bus Collision Event */ +#define PIC32_IRQ_I2C4S 38 /* I2C4 Slave Event */ +#define PIC32_IRQ_I2C4M 39 /* I2C4 Master Event */ + +#define PIC32_IRQ_SPI4E 40 /* SPI4 Fault */ +#define PIC32_IRQ_SPI4TX 41 /* SPI4 Transfer Done */ +#define PIC32_IRQ_SPI4RX 42 /* SPI4 Receive Done */ +#define PIC32_IRQ_U2E 40 /* UART2 Error */ +#define PIC32_IRQ_U2RX 41 /* UART2 Receiver */ +#define PIC32_IRQ_U2TX 42 /* UART2 Transmitter */ +#define PIC32_IRQ_I2C5B 40 /* I2C5 Bus Collision Event */ +#define PIC32_IRQ_I2C5S 41 /* I2C5 Slave Event */ +#define PIC32_IRQ_I2C5M 42 /* I2C5 Master Event */ + +#define PIC32_IRQ_I2C2B 43 /* I2C2 Bus Collision Event */ +#define PIC32_IRQ_I2C2S 44 /* I2C2 Slave Event */ +#define PIC32_IRQ_I2C2M 45 /* I2C2 Master Event */ +#define PIC32_IRQ_FSCM 46 /* Fail-Safe Clock Monitor */ +#define PIC32_IRQ_RTCC 47 /* Real-Time Clock and Calendar */ +#define PIC32_IRQ_DMA0 48 /* DMA Channel 0 */ +#define PIC32_IRQ_DMA1 49 /* DMA Channel 1 */ +#define PIC32_IRQ_DMA2 50 /* DMA Channel 2 */ +#define PIC32_IRQ_DMA3 51 /* DMA Channel 3 */ +#define PIC32_IRQ_DMA4 52 /* DMA Channel 4 */ +#define PIC32_IRQ_DMA5 53 /* DMA Channel 5 */ +#define PIC32_IRQ_DMA6 54 /* DMA Channel 6 */ +#define PIC32_IRQ_DMA7 55 /* DMA Channel 7 */ +#define PIC32_IRQ_FCE 56 /* Flash Control Event */ +#define PIC32_IRQ_USB 57 /* USB */ +#define PIC32_IRQ_CAN1 58 /* Control Area Network 1 */ +#define PIC32_IRQ_CAN2 59 /* Control Area Network 2 */ +#define PIC32_IRQ_ETH 60 /* Ethernet Interrupt */ +#define PIC32_IRQ_IC1E 61 /* Input Capture 1 Error */ +#define PIC32_IRQ_IC2E 62 /* Input Capture 2 Error */ +#define PIC32_IRQ_IC3E 63 /* Input Capture 3 Error */ +#define PIC32_IRQ_IC4E 64 /* Input Capture 4 Error */ +#define PIC32_IRQ_IC5E 65 /* Input Capture 5 Error */ +#define PIC32_IRQ_PMPE 66 /* Parallel Master Port Error */ +#define PIC32_IRQ_U4E 67 /* UART4 Error */ +#define PIC32_IRQ_U4RX 68 /* UART4 Receiver */ +#define PIC32_IRQ_U4TX 69 /* UART4 Transmitter */ +#define PIC32_IRQ_U6E 70 /* UART6 Error */ +#define PIC32_IRQ_U6RX 71 /* UART6 Receiver */ +#define PIC32_IRQ_U6TX 72 /* UART6 Transmitter */ +#define PIC32_IRQ_U5E 73 /* UART5 Error */ +#define PIC32_IRQ_U5RX 74 /* UART5 Receiver */ +#define PIC32_IRQ_U5TX 75 /* UART5 Transmitter */ + +/* + * Interrupt vector numbers for PIC32MX3xx/4xx/5xx/6xx/7xx + */ +#define PIC32_VECT_CT 0 /* Core Timer Interrupt */ +#define PIC32_VECT_CS0 1 /* Core Software Interrupt 0 */ +#define PIC32_VECT_CS1 2 /* Core Software Interrupt 1 */ +#define PIC32_VECT_INT0 3 /* External Interrupt 0 */ +#define PIC32_VECT_T1 4 /* Timer1 */ +#define PIC32_VECT_IC1 5 /* Input Capture 1 */ +#define PIC32_VECT_OC1 6 /* Output Compare 1 */ +#define PIC32_VECT_INT1 7 /* External Interrupt 1 */ +#define PIC32_VECT_T2 8 /* Timer2 */ +#define PIC32_VECT_IC2 9 /* Input Capture 2 */ +#define PIC32_VECT_OC2 10 /* Output Compare 2 */ +#define PIC32_VECT_INT2 11 /* External Interrupt 2 */ +#define PIC32_VECT_T3 12 /* Timer3 */ +#define PIC32_VECT_IC3 13 /* Input Capture 3 */ +#define PIC32_VECT_OC3 14 /* Output Compare 3 */ +#define PIC32_VECT_INT3 15 /* External Interrupt 3 */ +#define PIC32_VECT_T4 16 /* Timer4 */ +#define PIC32_VECT_IC4 17 /* Input Capture 4 */ +#define PIC32_VECT_OC4 18 /* Output Compare 4 */ +#define PIC32_VECT_INT4 19 /* External Interrupt 4 */ +#define PIC32_VECT_T5 20 /* Timer5 */ +#define PIC32_VECT_IC5 21 /* Input Capture 5 */ +#define PIC32_VECT_OC5 22 /* Output Compare 5 */ +#define PIC32_VECT_SPI1 23 /* SPI1 */ + +#define PIC32_VECT_SPI3 24 /* SPI3 */ +#define PIC32_VECT_U1 24 /* UART1 */ +#define PIC32_VECT_I2C3 24 /* I2C3 */ + +#define PIC32_VECT_I2C1 25 /* I2C1 */ +#define PIC32_VECT_CN 26 /* Input Change Interrupt */ +#define PIC32_VECT_AD1 27 /* ADC1 Convert Done */ +#define PIC32_VECT_PMP 28 /* Parallel Master Port */ +#define PIC32_VECT_CMP1 29 /* Comparator Interrupt */ +#define PIC32_VECT_CMP2 30 /* Comparator Interrupt */ + +#define PIC32_VECT_SPI2 31 /* SPI2 */ +#define PIC32_VECT_U3 31 /* UART3 */ +#define PIC32_VECT_I2C4 31 /* I2C4 */ + +#define PIC32_VECT_SPI4 32 /* SPI4 */ +#define PIC32_VECT_U2 32 /* UART2 */ +#define PIC32_VECT_I2C5 32 /* I2C5 */ + +#define PIC32_VECT_I2C2 33 /* I2C2 */ +#define PIC32_VECT_FSCM 34 /* Fail-Safe Clock Monitor */ +#define PIC32_VECT_RTCC 35 /* Real-Time Clock and Calendar */ +#define PIC32_VECT_DMA0 36 /* DMA Channel 0 */ +#define PIC32_VECT_DMA1 37 /* DMA Channel 1 */ +#define PIC32_VECT_DMA2 38 /* DMA Channel 2 */ +#define PIC32_VECT_DMA3 39 /* DMA Channel 3 */ +#define PIC32_VECT_DMA4 40 /* DMA Channel 4 */ +#define PIC32_VECT_DMA5 41 /* DMA Channel 5 */ +#define PIC32_VECT_DMA6 42 /* DMA Channel 6 */ +#define PIC32_VECT_DMA7 43 /* DMA Channel 7 */ +#define PIC32_VECT_FCE 44 /* Flash Control Event */ +#define PIC32_VECT_USB 45 /* USB */ +#define PIC32_VECT_CAN1 46 /* Control Area Network 1 */ +#define PIC32_VECT_CAN2 47 /* Control Area Network 2 */ +#define PIC32_VECT_ETH 48 /* Ethernet Interrupt */ +#define PIC32_VECT_U4 49 /* UART4 */ +#define PIC32_VECT_U6 50 /* UART6 */ +#define PIC32_VECT_U5 51 /* UART5 */ + +#endif /* _IO_PIC32MX_H */ diff --git a/sys/pic32/picga.c b/sys/pic32/picga.c new file mode 100644 index 0000000..c6aec3f --- /dev/null +++ b/sys/pic32/picga.c @@ -0,0 +1,166 @@ +/* + * PICGA driver for PIC32. + * + * Copyright (C) 2012 Majenko Technologies + * + * 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 the copyright notice and this + * permission notice and warranty disclaimer appear in supporting + * documentation, and that the name of the author not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * + * The author disclaim all warranties with regard to this + * software, including all implied warranties of merchantability + * and fitness. In no event shall the author 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. + */ + +#include "param.h" +#include "conf.h" +#include "user.h" +#include "ioctl.h" +#include "systm.h" +#include "uio.h" +#include "picga.h" +#include "spi_bus.h" +#include "debug.h" + +const struct devspec picgadevs[] = { + { 0, "picga" }, + { 0, 0 } +}; + +extern int uwritec(struct uio *); + +int fd; + +void blockdelay(unsigned int v) +{ + for( ; v>0 ; v--) + asm volatile ("nop"); +} + +void picga_command(unsigned char cmd, unsigned char len, void *data) +{ + char *p = (char *)data; + spi_select(fd); + blockdelay(3000); + spi_transfer(fd,cmd); + blockdelay(3000); + spi_transfer(fd,len); + blockdelay(3000); + spi_transfer(fd,0); + blockdelay(3000); + while(len>0) + { + spi_transfer(fd,*p++); + blockdelay(3000); + len--; + } + blockdelay(3000); + spi_deselect(fd); + blockdelay(3000); +} + +int picga_open(dev_t dev, int flag, int mode) +{ + int channel; + struct intval i; + struct coord2 j; + + channel = minor(dev); + if(channel>0) + return ENODEV; + + fd = spi_open(PICGA_BUS,(unsigned int *)&PICGA_CS_PORT,PICGA_CS_PIN); + if(fd==-1) + return ENODEV; + + spi_brg(fd,500); + + i.value = 0x01; + picga_command(SPI_FGCOLOR,sizeof(struct intval),&i); + i.value = 0x00; + picga_command(SPI_BGCOLOR,sizeof(struct intval),&i); + i.value = FONT_TOPAZ; + picga_command(SPI_FONT,sizeof(struct intval),&i); + j.x = 0; + j.y = 0; + picga_command(SPI_CLUT,sizeof(struct coord2),&j); + j.x = 1; + j.y = 0xFFFF; + picga_command(SPI_CLUT,sizeof(struct coord2),&j); + + return 0; +} + +int picga_close(dev_t dev, int flag, int mode) +{ + int channel; + + channel = minor(dev); + if(channel>0) + return ENODEV; + + spi_close(fd); + return 0; +} + +// Return the most recent ADC value +int picga_read(dev_t dev, struct uio *uio, int flag) +{ + return EPERM; +} + +// Trigger an ADC conversion +int picga_write(dev_t dev, struct uio *uio, int flag) +{ + int channel; + char t[100]; + int p = 0; + char c; + + channel = minor(dev); + if(channel>0) + return ENODEV; + + while(uio->uio_iov->iov_len>0) + { + p=0; + while((p<90) && (uio->uio_iov->iov_len>0)) + { + c = uwritec(uio); + t[p++] = c; + t[p] = 0; + if(c == '\n') + break; + } + picga_command(SPI_PRINT,p,t); + blockdelay(50000); + } + return 0; +} + +int picga_ioctl(dev_t dev, register u_int cmd, caddr_t addr, int flag) +{ + printf("IOCTL %08X\n",cmd); + + switch(cmd) + { + case PICGA_CLS: + printf("CLS command\n"); + picga_command(SPI_CLS,0,NULL); + break; + default: + return EINVAL; + } + + return 0; +} diff --git a/sys/pic32/pinguino-micro/Makefile b/sys/pic32/pinguino-micro/Makefile new file mode 100644 index 0000000..bffac60 --- /dev/null +++ b/sys/pic32/pinguino-micro/Makefile @@ -0,0 +1,77 @@ +BUILDPATH = ../../../tools/configsys/../../sys/pic32 +H = ../../../tools/configsys/../../sys/include +M = ../../../tools/configsys/../../sys/pic32 +S = ../../../tools/configsys/../../sys/kernel + +vpath %.c $(M):$(S) +vpath %.S $(M):$(S) + +KERNOBJ += _startup.o adc.o clock.o cons.o devsw.o exception.o gpio.o init_main.o init_sysent.o kern_clock.o kern_descrip.o kern_exec.o kern_exit.o kern_fork.o kern_mman.o kern_proc.o kern_prot.o kern_prot2.o kern_resource.o kern_sig.o kern_sig2.o kern_subr.o kern_synch.o kern_sysctl.o kern_time.o machdep.o mem.o rd_sd.o rdisk.o signal.o spi_bus.o subr_prf.o subr_rmap.o swap.o sys_generic.o sys_inode.o sys_pipe.o sys_process.o syscalls.o sysctl.o tty.o tty_subr.o tty_tty.o ufs_alloc.o ufs_bio.o ufs_bmap.o ufs_dsort.o ufs_fio.o ufs_inode.o ufs_mount.o ufs_namei.o ufs_subr.o ufs_syscalls.o ufs_syscalls2.o usb_device.o usb_function_cdc.o usb_uart.o vers.o vfs_vnops.o vm_sched.o vm_swap.o vm_swp.o +EXTRA_TARGETS = bootloader + +DEFS += -DADC_ENABLED=YES +DEFS += -DBL_BUTTON_PIN=7 +DEFS += -DBL_BUTTON_PORT=TRISE +DEFS += -DBL_LED_PIN=3 +DEFS += -DBL_LED_PORT=TRISE +DEFS += -DBUS_DIV=1 +DEFS += -DBUS_KHZ='CPU_KHZ/BUS_DIV' +DEFS += -DCONSOLE_DEVICE=ttyUSB0 +DEFS += -DCPU_IDIV=2 +DEFS += -DCPU_KHZ='((CRYSTAL*1000)/CPU_IDIV*CPU_MUL/CPU_ODIV)' +DEFS += -DCPU_MUL=20 +DEFS += -DCPU_ODIV=1 +DEFS += -DCRYSTAL=8 +DEFS += -DDC0_DEBUG=DEVCFG0_DEBUG_DISABLED +DEFS += -DDC0_ICE=0 +DEFS += -DDC1_CKM=0 +DEFS += -DDC1_CKS=0 +DEFS += -DDC1_FNOSC=DEVCFG1_FNOSC_PRIPLL +DEFS += -DDC1_IESO=DEVCFG1_IESO +DEFS += -DDC1_OSCIOFNC=0 +DEFS += -DDC1_PBDIV=DEVCFG1_FPBDIV_1 +DEFS += -DDC1_POSCMOD=DEVCFG1_POSCMOD_HS +DEFS += -DDC1_SOSC=0 +DEFS += -DDC1_WDTEN=0 +DEFS += -DDC1_WDTPS=DEVCFG1_WDTPS_1 +DEFS += -DDC2_PLLIDIV=DEVCFG2_FPLLIDIV_2 +DEFS += -DDC2_PLLMUL=DEVCFG2_FPLLMUL_20 +DEFS += -DDC2_PLLODIV=DEVCFG2_FPLLODIV_1 +DEFS += -DDC2_UPLL=0 +DEFS += -DDC2_UPLLIDIV=DEVCFG2_UPLLIDIV_2 +DEFS += -DDC3_CAN=DEVCFG3_FCANIO +DEFS += -DDC3_ETH=DEVCFG3_FETHIO +DEFS += -DDC3_MII=DEVCFG3_FMIIEN +DEFS += -DDC3_SRS=DEVCFG3_FSRSSEL_7 +DEFS += -DDC3_USBID=DEVCFG3_FUSBIDIO +DEFS += -DDC3_USERID=0xffff +DEFS += -DDC3_VBUSON=DEVCFG3_FVBUSONIO +DEFS += -DFLASH_USER=0x1d005000 +DEFS += -DGPIO_ENABLED=YES +DEFS += -DHID_FEATURE_REPORT_BYTES=2 +DEFS += -DHID_INPUT_REPORT_BYTES=2 +DEFS += -DHID_INT_IN_EP_SIZE=64 +DEFS += -DHID_INT_OUT_EP_SIZE=64 +DEFS += -DHID_OUTPUT_REPORT_BYTES=2 +DEFS += -DHID_RPT01_SIZE=29 +DEFS += -DKERNEL +DEFS += -DLED_KERNEL_INVERT=YES +DEFS += -DLED_KERNEL_PIN=1 +DEFS += -DLED_KERNEL_PORT=TRISD +DEFS += -DPIC32MX7 +DEFS += -DSD0_CS_PIN=13 +DEFS += -DSD0_CS_PORT=TRISB +DEFS += -DSD0_PORT=2 +DEFS += -DUARTUSB_ENABLED=YES +DEFS += -DUCB_METER +DEFS += -DUSB_EP0_BUFF_SIZE=8 +DEFS += -DUSB_MAX_EP_NUMBER=3 +DEFS += -DUSB_NUM_STRING_DESCRIPTORS=3 + + +LDSCRIPT = ../../../tools/configsys/../../sys/pic32/cfg/bootloader-ubw32.ld + +CONFIG = PINGUINO-MICRO +CONFIGPATH = ../../../tools/configsys + +include ../../../tools/configsys/../../sys/pic32/kernel-post.mk diff --git a/sys/pic32/pinguino-micro/PINGUINO-MICRO b/sys/pic32/pinguino-micro/PINGUINO-MICRO new file mode 100644 index 0000000..3e59100 --- /dev/null +++ b/sys/pic32/pinguino-micro/PINGUINO-MICRO @@ -0,0 +1,22 @@ +# +# Pinguino-micro board +# ==================== +# +# Console on USB +# For Windows, use the driver: http://www.schmalzhaus.com/UBW32/FW/UBW32inf.zip + +core pic32mx7 +linker bootloader-ubw32 +mapping generic + +device kernel invled=D1 + +device console device=ttyUSB0 +device uartusb + +device sd0 port=2 cs=B13 +device gpio +device adc + +device bootloader button=E7 led=E3 user=0x1d005000 + diff --git a/sys/pic32/pinguino-micro/using-bootloader.ld b/sys/pic32/pinguino-micro/using-bootloader.ld new file mode 100644 index 0000000..6b0b5f5 --- /dev/null +++ b/sys/pic32/pinguino-micro/using-bootloader.ld @@ -0,0 +1,115 @@ +/* + * Linker script for PIC32 firmware using HID bootloader. + */ +OUTPUT_FORMAT("elf32-littlemips", "elf32-bigmips", + "elf32-littlemips") +OUTPUT_ARCH(mips) +ENTRY(_reset_vector_) +MEMORY +{ + flash (rx) : ORIGIN = 0x9d005000, LENGTH = 492K + ram (rw!x): ORIGIN = 0x80000000, LENGTH = 26K + u0area (rw!x): ORIGIN = 0x80006800, LENGTH = 3K + uarea (rw!x): ORIGIN = 0x80007400, LENGTH = 3K + + /* Required by Microchip C32 linker */ + kseg0_program_mem (rx) : ORIGIN = 0x9D000000, LENGTH = 0x80000 + kseg0_boot_mem : ORIGIN = 0x9FC00490, LENGTH = 0x970 + exception_mem : ORIGIN = 0x9FC01000, LENGTH = 0x1000 + kseg1_boot_mem : ORIGIN = 0xBFC00000, LENGTH = 0x490 + kseg1_data_mem (w!x) : ORIGIN = 0xA0000000, LENGTH = 0x20000 +} + +/* higher address of the user mode stack */ +u0 = ORIGIN(u0area); +u = ORIGIN(uarea); +u_end = ORIGIN(uarea) + LENGTH(uarea); + +SECTIONS +{ + .text ORIGIN(flash) : + { + /* Exception handlers. */ + *(.exception) + . = 0x1000; + /* Execution starts here. */ + *(.startup) + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.glue_7t) *(.glue_7) + __rodata_start = . ; + *(.rodata .rodata.* .gnu.linkonce.r.* .rel.dyn) + *(.dinit) + /* Align here to ensure that the .text section ends on word boundary. */ + . = ALIGN (32 / 8); + _etext = .; + } > flash + + /* Start data (internal SRAM). */ + .data : AT (ADDR (.text) + SIZEOF (.text)) + { + __data_start = . ; + _gp = .; /* We use only 32k RAM for kernel, so no need for 0x8000 offset. */ + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + *(.sdata .sdata.* .gnu.linkonce.s.*) + *(.data .data.* .gnu.linkonce.d.*) + *(.eh_frame) + _edata = .; + } > ram + + .bss ADDR (.data) + SIZEOF (.data) (NOLOAD) : + { + __bss_start = .; + *(.dynbss) + *(.sbss .sbss.*) + *(.scommon) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. */ + . = ALIGN (32 / 8); + } > ram + __bss_end = . ; + _end = .; + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + .debug_pubtypes 0 : { *(.debug_pubtypes) } + .debug_ranges 0 : { *(.debug_ranges) } + .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) } +} diff --git a/sys/pic32/power_control.c b/sys/pic32/power_control.c new file mode 100644 index 0000000..d956e31 --- /dev/null +++ b/sys/pic32/power_control.c @@ -0,0 +1,74 @@ +#include "param.h" +#include "conf.h" +#include "user.h" +#include "systm.h" +#include "machparam.h" +#include "reboot.h" + +volatile unsigned int psCounter; +int countdown; + +#define COUNTDOWN 5 + +void power_off() +{ + TRIS_CLR(POWER_CONTROL_PORT) = 1<0) + { + LAT_SET(POWER_LED_PORT) = 1<>10; + + + DEBUG3("flash%d: %u kbytes\n", unit, fsize); + return fsize; +} + +int flash_open (int unit, int flag, int mode) +{ + if (unit > 0) + return ENXIO; + return 0; +} + +int flash_read(int unit, unsigned int offset, char *buf, unsigned int bcount) +{ + unsigned int i; + if(unit>0) + return ENXIO; + + offset = offset<<10; + if(!buf) + return 0; + + for(i=0; i>16); + spi_transfer(fd[chip], address>>8); + spi_transfer(fd[chip], address); + + // If the length is a multiple of 32 bits, then do a 32 bit transfer +/* + if((length & 0x03) == 0) + spi_bulk_read_32(fd[chip],length,data); + else if((length & 0x01) == 0) + spi_bulk_read_16(fd[chip],length,data); + else +*/ + spi_bulk_read(fd[chip],length,(unsigned char *)data); + + spi_deselect(fd[chip]); + + switch(chip) + { + case 0: + #ifdef MRAMS_LED0_PORT + LAT_CLR(MRAMS_LED0_PORT) = 1< 0) + { + pass++; + toread = bcount; + if(toread > MRBSIZE) + toread = MRBSIZE; + + chip = offset / MRAMS_CHIPSIZE; + + address = (offset<<10) - (chip * (MRAMS_CHIPSIZE*1024)); + + + if(chip>=MRAMS_CHIPS) + { + printf("!!!EIO\n"); + return EIO; + } + mr_read_block(chip, address, toread, data); + bcount -= toread; + offset += (toread>>MRBLOG2); + data += toread; + } + return 1; +} + +unsigned int mr_write_block(unsigned int chip, unsigned int address, unsigned int length, char *data) +{ + register unsigned int cs = 0; + char blank __attribute__((unused)); + + switch(chip) + { + case 0: + #ifdef MRAMS_LED0_PORT + TRIS_CLR(MRAMS_LED0_PORT) = 1<>16); + spi_transfer(fd[chip], address>>8); + spi_transfer(fd[chip], address); + +/* + if((length & 0x03) == 0) + spi_bulk_write_32(fd[chip],length,data); + else if((length & 0x01) == 0) + spi_bulk_write_16(fd[chip],length,data); + else +*/ + spi_bulk_write(fd[chip],length,(unsigned char *)data); + + spi_deselect(fd[chip]); + + switch(chip) + { + case 0: + #ifdef MRAMS_LED0_PORT + LAT_CLR(MRAMS_LED0_PORT) = 1< 0) + { + pass++; + towrite = bcount; + if(towrite > MRBSIZE) + towrite = MRBSIZE; + + chip = offset / MRAMS_CHIPSIZE; + address = (offset<<10) - (chip * (MRAMS_CHIPSIZE*MRBSIZE)); + + + if(chip>=MRAMS_CHIPS) + { + printf("!!!EIO\n"); + return EIO; + } + + mr_write_block(chip, address, towrite, data); + bcount -= towrite; + offset += (towrite>>MRBLOG2); + data += towrite; + } + return 1; +} + +void mrams_preinit (int unit) +{ + struct buf *bp; + + if (unit >= 1) + return; + + /* Initialize hardware. */ + + + fd[0] = spi_open(MRAMS_PORT,(unsigned int *)&MRAMS_CS0_PORT,MRAMS_CS0_PIN); + if(fd[0]==-1) return; + + spi_brg(fd[0],MRAMS_MHZ * 1000); + spi_set(fd[0],PIC32_SPICON_CKE); + spi_select(fd[0]); + spi_transfer(fd[0],MRAM_WREN); + spi_deselect(fd[0]); + +#ifdef MRAMS_CS1_PORT + fd[1] = spi_open(MRAMS_PORT,(unsigned int *)&MRAMS_CS1_PORT,MRAMS_CS1_PIN); + + spi_brg(fd[1],MRAMS_MHZ * 1000); + spi_set(fd[1],PIC32_SPICON_CKE); + spi_select(fd[1]); + spi_transfer(fd[1],MRAM_WREN); + spi_deselect(fd[1]); +#endif +#ifdef MRAMS_CS2_PORT + fd[2] = spi_open(MRAMS_PORT,(unsigned int *)&MRAMS_CS2_PORT,MRAMS_CS2_PIN); + + spi_brg(fd[2],MRAMS_MHZ * 1000); + spi_set(fd[2],PIC32_SPICON_CKE); + spi_select(fd[2]); + spi_transfer(fd[2],MRAM_WREN); + spi_deselect(fd[2]); +#endif +#ifdef MRAMS_CS3_PORT + fd[3] = spi_open(MRAMS_PORT,(unsigned int *)&MRAMS_CS3_PORT,MRAMS_CS3_PIN); + + spi_brg(fd[3],MRAMS_MHZ * 1000); + spi_set(fd[3],PIC32_SPICON_CKE); + spi_select(fd[3]); + spi_transfer(fd[3],MRAM_WREN); + spi_deselect(fd[3]); +#endif + + printf("mrams0: port %s, size %dKB, speed %d Mbit/sec\n", + spi_name(MRAMS_PORT),MRAMS_CHIPS * MRAMS_CHIPSIZE, + spi_get_brg(fd[0]) / 1000); + bp = prepartition_device("mrams0"); + if(bp) + { + mrams_write (0, 0, bp->b_addr, 512); + brelse(bp); + } +} diff --git a/sys/pic32/rd_sd.c b/sys/pic32/rd_sd.c new file mode 100644 index 0000000..2634f37 --- /dev/null +++ b/sys/pic32/rd_sd.c @@ -0,0 +1,647 @@ +/* + * SecureDigital flash drive on SPI port. + * + * These cards are known to work: + * 1) NCP SD 256Mb - type 1, 249856 kbytes, 244 Mbytes + * 2) Patriot SD 2Gb - type 2, 1902592 kbytes, 1858 Mbytes + * 3) Wintec microSD 2Gb - type 2, 1969152 kbytes, 1923 Mbytes + * 4) Transcend SDHC 4Gb - type 3, 3905536 kbytes, 3814 Mbytes + * 5) Verbatim SD 2Gb - type 2, 1927168 kbytes, 1882 Mbytes + * 6) SanDisk SDHC 4Gb - type 3, 3931136 kbytes, 3833 Mbytes + * + * Copyright (C) 2010 Serge Vakulenko, + * + * 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 the copyright notice and this + * permission notice and warranty disclaimer appear in supporting + * documentation, and that the name of the author not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * + * The author disclaim all warranties with regard to this + * software, including all implied warranties of merchantability + * and fitness. In no event shall the author 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. + */ +#include "param.h" +#include "systm.h" +#include "buf.h" +#include "errno.h" +#include "dk.h" +#include "rdisk.h" +#include "spi_bus.h" + +#include "debug.h" + +/* + * Two SD/MMC disks on SPI. + * Signals for SPI1: + * D0 - SDO1 + * D10 - SCK1 + * C4 - SDI1 + */ +#define NSD 2 +#define SECTSIZE 512 +#define SPI_ENHANCED /* use SPI fifo */ +#ifndef SD0_MHZ +#define SD0_MHZ 13 /* speed 13.33 MHz */ +#endif +#ifndef SD1_MHZ +#define SD1_MHZ 13 /* speed 13.33 MHz */ +#endif + +#define TIMO_WAIT_WDONE 400000 +#define TIMO_WAIT_WIDLE 200000 +#define TIMO_WAIT_CMD 100000 +#define TIMO_WAIT_WDATA 30000 +#define TIMO_READ 90000 +#define TIMO_SEND_OP 8000 +#define TIMO_CMD 7000 +#define TIMO_SEND_CSD 6000 +#define TIMO_WAIT_WSTOP 5000 + +int sd_type[NSD]; /* Card type */ +int sd_dkn = -1; /* Statistics slot number */ + +int sd_timo_cmd; /* Max timeouts, for sysctl */ +int sd_timo_send_op; +int sd_timo_send_csd; +int sd_timo_read; +int sd_timo_wait_cmd; +int sd_timo_wait_wdata; +int sd_timo_wait_wdone; +int sd_timo_wait_wstop; +int sd_timo_wait_widle; + +/* + * Definitions for MMC/SDC commands. + */ +#define CMD_GO_IDLE 0 /* CMD0 */ +#define CMD_SEND_OP_MMC 1 /* CMD1 (MMC) */ +#define CMD_SEND_IF_COND 8 +#define CMD_SEND_CSD 9 +#define CMD_SEND_CID 10 +#define CMD_STOP 12 +#define CMD_SEND_STATUS 13 /* CMD13 */ +#define CMD_SET_BLEN 16 +#define CMD_READ_SINGLE 17 +#define CMD_READ_MULTIPLE 18 +#define CMD_SET_BCOUNT 23 /* (MMC) */ +#define CMD_SET_WBECNT 23 /* ACMD23 (SDC) */ +#define CMD_WRITE_SINGLE 24 +#define CMD_WRITE_MULTIPLE 25 +#define CMD_SEND_OP_SDC 41 /* ACMD41 (SDC) */ +#define CMD_APP 55 /* CMD55 */ +#define CMD_READ_OCR 58 + +#define DATA_START_BLOCK 0xFE /* start data for single block */ +#define STOP_TRAN_TOKEN 0xFD /* stop token for write multiple */ +#define WRITE_MULTIPLE_TOKEN 0xFC /* start data for write multiple */ + +int sd_fd[NSD]; + +// Add extra clocks after a deselect +void sd_deselect(unsigned int fd) +{ + spi_deselect(fd); + spi_transfer(fd,0xFF); +} + +/* + * Wait while busy, up to 300 msec. + */ + +static void spi_wait_ready (int unit, int limit, int *maxcount) +{ + int i; + + spi_transfer(sd_fd[unit],0xFF); + for (i=0; i> 24); + spi_transfer(sd_fd[unit],addr >> 16); + spi_transfer(sd_fd[unit],addr >> 8); + spi_transfer(sd_fd[unit],addr); + + /* Send cmd checksum for CMD_GO_IDLE. + * For all other commands, CRC is ignored. */ + if (cmd == CMD_GO_IDLE) + spi_transfer(sd_fd[unit],0x95); + else if (cmd == CMD_SEND_IF_COND) + spi_transfer(sd_fd[unit],0x87); + else + spi_transfer(sd_fd[unit],0xFF); + + /* Wait for a response. */ + for (i=0; i= TIMO_SEND_OP) + { + /* Init timed out. */ + printf ("card_init: SEND_OP timed out, reply = %d\n", reply); + return 0; + } + } + if (sd_timo_send_op < i) + sd_timo_send_op = i; + + /* If SD2 read OCR register to check for SDHC card. */ + if (sd_type[unit] == 2) + { + spi_select(sd_fd[unit]); + reply = card_cmd(unit, CMD_READ_OCR, 0); + if (reply != 0) + { + sd_deselect(sd_fd[unit]); + printf ("sd%d: READ_OCR failed, reply=%02x\n", unit, reply); + return 0; + } + response[0] = spi_transfer(sd_fd[unit],0xFF); + response[1] = spi_transfer(sd_fd[unit],0xFF); + response[2] = spi_transfer(sd_fd[unit],0xFF); + response[3] = spi_transfer(sd_fd[unit],0xFF); + sd_deselect(sd_fd[unit]); + if ((response[0] & 0xC0) == 0xC0) + { + sd_type[unit] = 3; + } + } + /* Fast speed. */ + if(unit == 0) + spi_brg(sd_fd[unit],SD0_MHZ * 1000); +#ifdef SD1_PORT + if(unit == 1) + spi_brg(sd_fd[unit],SD1_MHZ * 1000); +#endif + return 1; +} + +/* + * Get number of sectors on the disk. + * Return nonzero if successful. + */ +int sdsize(int unit) +{ + unsigned char csd [16]; + unsigned csize, n; + int reply, i; + int nsectors; + + spi_select(sd_fd[unit]); + reply = card_cmd(unit,CMD_SEND_CSD, 0); + if (reply != 0) + { + /* Command rejected. */ + sd_deselect(sd_fd[unit]); + return 0; + } + /* Wait for a response. */ + for (i=0; ; i++) + { + reply = spi_transfer(sd_fd[unit],0xFF); + if (reply == DATA_START_BLOCK) + break; + if (i >= TIMO_SEND_CSD) + { + /* Command timed out. */ + sd_deselect(sd_fd[unit]); + printf ("sd%d: card_size: SEND_CSD timed out, reply = %d\n", + unit, reply); + return 0; + } + } + if (sd_timo_send_csd < i) + sd_timo_send_csd = i; + + /* Read data. */ + for (i=0; i> 6) + { + case 1: /* SDC ver 2.00 */ + csize = csd[9] + (csd[8] << 8) + 1; + nsectors = csize << 10; + break; + case 0: /* SDC ver 1.XX or MMC. */ + n = (csd[5] & 15) + ((csd[10] & 128) >> 7) + ((csd[9] & 3) << 1) + 2; + csize = (csd[8] >> 6) + (csd[7] << 2) + ((csd[6] & 3) << 10) + 1; + nsectors = csize << (n - 9); + break; + default: /* Unknown version. */ + return 0; + } + return nsectors>>1; +} + +/* + * Read a block of data. + * Return nonzero if successful. + */ +int card_read(int unit, unsigned int offset, char *data, unsigned int bcount) +{ + int reply, i; + + /* Send read-multiple command. */ + spi_select(sd_fd[unit]); + if (sd_type[unit] != 3) offset <<= 9; + reply = card_cmd(unit, CMD_READ_MULTIPLE, offset<<1); + if (reply != 0) + { + /* Command rejected. */ + printf ("sd%d: card_read: bad READ_MULTIPLE reply = %d, offset = %08x\n", + unit, reply, offset<<1); + sd_deselect(sd_fd[unit]); + return 0; + } + +again: + /* Wait for a response. */ + for (i=0; ; i++) + { + int x = spl0(); + reply = spi_transfer(sd_fd[unit],0xFF); + splx(x); + if (reply == DATA_START_BLOCK) + break; + if (i >= TIMO_READ) + { + /* Command timed out. */ + printf ("sd%d: card_read: READ_MULTIPLE timed out, reply = %d\n", + unit, reply); + sd_deselect(sd_fd[unit]); + return 0; + } + } + if (sd_timo_read < i) + sd_timo_read = i; + + /* Read data. */ + if (bcount >= SECTSIZE) + { + spi_bulk_read_32_be(sd_fd[unit],SECTSIZE,data); + data += SECTSIZE; + } else { + spi_bulk_read(sd_fd[unit],bcount,(unsigned char *)data); + data += bcount; + for (i=bcount; i SECTSIZE) + { + /* Next sector. */ + bcount -= SECTSIZE; + goto again; + } + + /* Stop a read-multiple sequence. */ + card_cmd(unit, CMD_STOP, 0); + sd_deselect(sd_fd[unit]); + return 1; +} + +/* + * Write a block of data. + * Return nonzero if successful. + */ +int +card_write (int unit, unsigned offset, char *data, unsigned bcount) +{ + unsigned reply, i; + + /* Send pre-erase count. */ + spi_select(sd_fd[unit]); + card_cmd(unit, CMD_APP, 0); + reply = card_cmd(unit, CMD_SET_WBECNT, (bcount + SECTSIZE - 1) / SECTSIZE); + if (reply != 0) + { + /* Command rejected. */ + sd_deselect(sd_fd[unit]); + printf("sd%d: card_write: bad SET_WBECNT reply = %02x, count = %u\n", + unit, reply, (bcount + SECTSIZE - 1) / SECTSIZE); + return 0; + } + + /* Send write-multiple command. */ + if (sd_type[unit] != 3) offset <<= 9; + reply = card_cmd(unit, CMD_WRITE_MULTIPLE, offset<<1); + if (reply != 0) + { + /* Command rejected. */ + sd_deselect(sd_fd[unit]); + printf("sd%d: card_write: bad WRITE_MULTIPLE reply = %02x\n", unit, reply); + return 0; + } + sd_deselect(sd_fd[unit]); +again: + /* Select, wait while busy. */ + spi_select(sd_fd[unit]); + spi_wait_ready(unit, TIMO_WAIT_WDATA, &sd_timo_wait_wdata); + + /* Send data. */ + spi_transfer(sd_fd[unit],WRITE_MULTIPLE_TOKEN); + if (bcount >= SECTSIZE) + { + spi_bulk_write_32_be(sd_fd[unit],SECTSIZE,data); + data += SECTSIZE; + } else { + spi_bulk_write(sd_fd[unit],bcount,(unsigned char *)data); + data += bcount; + for (i=bcount; i SECTSIZE) + { + /* Next sector. */ + bcount -= SECTSIZE; + goto again; + } + + /* Stop a write-multiple sequence. */ + spi_select(sd_fd[unit]); + spi_wait_ready(unit, TIMO_WAIT_WSTOP, &sd_timo_wait_wstop); + spi_transfer(sd_fd[unit],STOP_TRAN_TOKEN); + spi_wait_ready(unit, TIMO_WAIT_WIDLE, &sd_timo_wait_widle); + sd_deselect(sd_fd[unit]); + return 1; +} + +void sd_preinit (int unit) +{ + if (unit >= NSD) + return; + + int fd = -1; + if(unit==0) + fd = spi_open(SD0_PORT,(unsigned int *)&SD0_CS_PORT,SD0_CS_PIN); + +#ifdef SD1_PORT + if(unit==1) + fd = spi_open(SD1_PORT,(unsigned int *)&SD1_CS_PORT,SD1_CS_PIN); +#endif + + if(fd==-1) + { + printf("sd%d: Cannot open port\n",unit); + return; + } + + sd_fd[unit] = fd; + +#ifdef SD0_ENA_PORT + /* Enable SD0 phy - pin is assumed to be active low */ + TRIS_CLR(SD0_ENA_PORT) = 1 << SD0_ENA_PIN; + LAT_CLR(SD0_ENA_PORT) = 1 << SD0_ENA_PIN; + udelay (1000); +#endif + +#ifdef SD1_ENA_PORT + /* Enable SD1 phy - pin is assumed to be active low */ + TRIS_CLR(SD1_ENA_PORT) = 1 << SD1_ENA_PIN; + LAT_CLR(SD1_ENA_PORT) = 1 << SD1_ENA_PIN; + udelay (1000); +#endif + + spi_brg(fd, SD0_MHZ * 1000); + spi_set(fd, PIC32_SPICON_CKE); + + printf ("sd%d: port %s, select pin %c%d\n", unit, + spi_name(fd), spi_csname(fd), spi_cspin(fd)); +} + +int sdinit (int unit, int flag) +{ + unsigned nsectors; + /* Detect a card. */ + +#ifdef SD0_ENA_PORT + /* On Duinomite Mega board, pin B13 set low + * enables a +3.3V power to SD card. */ + if (unit == 0) { + LAT_CLR(SD0_ENA_PORT) = 1 << SD0_ENA_PIN; + udelay (1000); + } +#endif + +#ifdef SD1_ENA_PORT + /* On Duinomite Mega board, pin B13 set low + * enables a +3.3V power to SD card. */ + if (unit == 1) { + LAT_CLR(SD1_ENA_PORT) = 1 << SD1_ENA_PIN; + udelay (1000); + } +#endif + + if (!card_init(unit)) + { + printf ("sd%d: no SD/MMC card detected\n", unit); + return ENODEV; + } + if ((nsectors=sdsize(unit))==0) + { + printf ("sd%d: cannot get card size\n", unit); + return ENODEV; + } + if(!(flag & S_SILENT)) + { + printf ("sd%d: type %s, size %u kbytes, speed %u Mbit/sec\n", unit, + sd_type[unit]==3 ? "SDHC" : + sd_type[unit]==2 ? "II" : "I", + nsectors, + spi_get_brg(sd_fd[unit]) / 1000); + } + DEBUG("sd%d: init done\n",unit); + return 0; +} + +int sddeinit(int unit) +{ +#ifdef SD0_ENA_PORT + /* On Duinomite Mega board, pin B13 set low + * enables a +3.3V power to SD card. */ + if (unit == 0) { + LAT_SET(SD0_ENA_PORT) = 1 << SD0_ENA_PIN; + udelay (1000); + } +#endif + +#ifdef SD1_ENA_PORT + /* On Duinomite Mega board, pin B13 set low + * enables a +3.3V power to SD card. */ + if (unit == 1) { + LAT_SET(SD1_ENA_PORT) = 1 << SD1_ENA_PIN; + udelay (1000); + } +#endif + return 0; +} + +int sdopen(int unit, int flags, int mode) +{ + DEBUG("sd%d: open\n",unit); + return 0; +} diff --git a/sys/pic32/rd_sdramp.c b/sys/pic32/rd_sdramp.c new file mode 100644 index 0000000..1746202 --- /dev/null +++ b/sys/pic32/rd_sdramp.c @@ -0,0 +1,425 @@ +/* + * Driver for external SDRAM-based swap device. + * + * See sdram.S for information on interface to sdram + * + * This code could use a bit of optimization. + */ + +#include "param.h" +#include "systm.h" +#include "buf.h" +#include "errno.h" +#include "dk.h" +#include "sdram.h" +#include "rd_sdramp.h" +#include "rdisk.h" + +/* + * See rd_sdramp_config.h for sdramp port/pin configuration + */ +#include "rd_sdramp_config.h" + +int sw_dkn = -1; /* Statistics slot number */ + +/* + * physical specs of SDRAM chip + */ +#define RAM_COLS 512 + +#if SDR_ADDRESS_LINES == 13 +#define RAM_ROWS (4096*2) +#elif SDR_ADDRESS_LINES == 12 +#define RAM_ROWS 4096 +#elif SDR_ADDRESS_LINES == 11 +#define RAM_ROWS 2048 +#else +#error Invalid Configuration - SDR_ADDRESS_LINES +#endif + +#define RAM_BANKS 4 + + +/* + * RAM_BURST_COUNT MUST be match the number of bytes + * read/written by each call to sdram_read/sdram_write + */ +#define RAM_BURST_COUNT 8 + +/* + * CHUNK_SIZE number of bytes in each "chunk" + */ +#define CHUNK_SIZE 32 + +#define RAM_BURST_GROUP_COUNT 4 + +#define BLOCKS_PER_ROW ( RAM_COLS / CHUNK_SIZE ) + +static char swaptemp[CHUNK_SIZE]; + +/* + * Used to specify partition table for ramdisk from Makefile + */ +#define RAMDISK_PARTSPEC(n,t,s,l) \ +m->partitions[n].type=t; \ +m->partitions[n].lbastart=s; \ +m->partitions[n].lbalength=l; + +//void build_ramdisk_mbr( struct mbr* m ); + +// FIXME - FOLLOWING shared with gpio.c - needs to be made common + +/* + * PIC32 port i/o registers. + */ +struct gpioreg { + volatile unsigned tris; /* Mask of inputs */ + volatile unsigned trisclr; + volatile unsigned trisset; + volatile unsigned trisinv; + volatile unsigned port; /* Read inputs, write outputs */ + volatile unsigned portclr; + volatile unsigned portset; + volatile unsigned portinv; + volatile unsigned lat; /* Read/write outputs */ + volatile unsigned latclr; + volatile unsigned latset; + volatile unsigned latinv; + volatile unsigned odc; /* Open drain configuration */ + volatile unsigned odcclr; + volatile unsigned odcset; + volatile unsigned odcinv; +}; + +struct ocreg { + volatile unsigned con; /* ? */ + volatile unsigned conclr; + volatile unsigned conset; + volatile unsigned coninv; + volatile unsigned r; /* ? */ + volatile unsigned rclr; + volatile unsigned rset; + volatile unsigned rinv; + volatile unsigned rs; /* ? */ + volatile unsigned rsclr; + volatile unsigned rsset; + volatile unsigned rsinv; +}; + +static void sdram_bank_c(unsigned bank) +{ + // In order to keep unnecessary noise from occuring on the + // address lines, don't use the hardware set/clear functions. + // Rather, read the latch value, change it, and write it back. + + struct gpioreg * bankport = (struct gpioreg *)&SDR_BANK_PORT; + unsigned v = bankport->lat; + v &= ~(BANK_BITMASK << SDR_BANK_0_BIT); + v |= (bank & BANK_BITMASK) << SDR_BANK_0_BIT; + bankport->lat = v; +} + +static void sdram_upperlowerbyte( unsigned bit ) +{ + struct gpioreg * dqm_port = (struct gpioreg *)&SDR_DQM_PORT; +#ifdef SDR_DQM_UDQM_BIT + + if( bit == 0 ) + { + dqm_port->latset = (1<latclr = (1<latset = (1<latclr = (1<latset = (1<latclr = (1<latclr = (1<latclr = (1<<13)|(1<<8); +address_lb_port->trisclr = (1<<13)|(1<<8); + + address_lb_port->trisclr = ADDRESS_LB_MASK; + address_port->trisclr = ADDRESS_MASK; + + /* AD1PCFGSET = 0xFFFF; */ + bank_port->trisclr = BANK_ALL_MASK; + +#ifdef SDR_DQM_UDQM_BIT + dqm_port->latset = (1<latclr = (1<trisclr = SDR_DQM_MASK; + + /* All address lines low */ + address_lb_port->latclr = ADDRESS_LB_MASK; + address_port->latclr = ADDRESS_MASK; + + bank_port->latclr = BANK_ALL_MASK; + + /* Initialize data lines */ + data_port->trisset = 0xff; + + /* Initialize SDRAM control lines */ + control_port->trisclr = CONTROL_ALL_MASK; + + /* Command Inhibit */ + control_port->latset = CONTROL_ALL_MASK; + + /* Initialize CKE line */ + cke_port->trisclr = (1<latclr = (1<latset = (1<trisclr = (1<con = 0; + ocr_reg->rs = 1; + ocr_reg->r = 3; + ocr_reg->con = 0x8005; + + /* Clock output starts here */ + + /* SD-RAM initialization delay */ + unsigned cc_start, cc_now; + asm volatile("mfc0 %0, $9" : "=r" (cc_start)); + do + { + asm volatile("mfc0 %0, $9" : "=r" (cc_now)); + } while( cc_now - cc_start < 500 ); + + /* CKE high */ + cke_port->latset = (1<lat = (address_lb_port->lat & ~ADDRESS_LB_MASK) | ((addr & 0x7) << SDR_ADDRESS_LB_A0_BIT); + address_port->lat = (address_port->lat & ~ADDRESS_MASK) + | ((addr & (ADDRESS_MASK<<(3-SDR_ADDRESS_A3_BIT))) >> (3-SDR_ADDRESS_A3_BIT)); +} + +static void sdram_active_c( unsigned row_address ) +{ + sdram_output_addr( row_address ); + sdram_active(); +} + +static void sdram_write_c(uint16_t coladdr, uint64_t val) +{ + sdram_output_addr( coladdr ); + sdram_write( val ); +} + +static uint64_t sdram_read_c(uint16_t coladdr) +{ + sdram_output_addr( coladdr ); + return sdram_read(); +} + +static void +read_chunk_from_sdram( uint64_t* dest, unsigned int blockNumber ) +{ + int startColumn = ( ( blockNumber & ( BLOCKS_PER_ROW - 1 ) ) * CHUNK_SIZE ); // / RAM_BURST_COUNT; + int rowAndBank = blockNumber / BLOCKS_PER_ROW; + int row = rowAndBank & ( RAM_ROWS - 1 ); + int bank = rowAndBank / RAM_ROWS; + int sbank = bank / 4; + bank = bank & 0b011; + int col = startColumn; + + sdram_upperlowerbyte( sbank ); + + while( col < startColumn + CHUNK_SIZE/*/RAM_BURST_COUNT*/ ) { + int x = mips_intr_disable(); + sdram_wake(); + sdram_bank_c(bank); + sdram_active_c(row); + int i; + for( i = 0; i < RAM_BURST_GROUP_COUNT; i++ ) { + *dest++ = sdram_read_c( col ); + col += RAM_BURST_COUNT; + } + sdram_precharge(); + sdram_precharge_all(); + sdram_sleep(); + + mips_intr_restore (x); + + asm volatile ("nop"); + } +} + +static void +write_chunk_to_sdram( uint64_t* src, unsigned int blockNumber ) +{ + int startColumn = ( ( blockNumber & ( BLOCKS_PER_ROW - 1 ) ) * CHUNK_SIZE ); /// RAM_BURST_COUNT; + int rowAndBank = blockNumber / BLOCKS_PER_ROW; + int row = rowAndBank & ( RAM_ROWS - 1 ); + int bank = rowAndBank / RAM_ROWS; + int sbank = bank / 4; + bank = bank & 0b011; + + sdram_upperlowerbyte( sbank ); + + int col = startColumn; + while( col < startColumn + CHUNK_SIZE /*/RAM_BURST_COUNT*/ ) { + int x = mips_intr_disable(); + + sdram_wake(); + sdram_bank_c(bank); + sdram_active_c(row); + int i; + for( i = 0; i < RAM_BURST_GROUP_COUNT; i++ ) { + sdram_write_c( col, *src++ ); + col += RAM_BURST_COUNT; + } + sdram_precharge(); + sdram_precharge_all(); + sdram_sleep(); + + mips_intr_restore (x); + + asm volatile ("nop"); + } +} + + +/* + * Read a block of data. + */ +int +sdramp_read(int unit, unsigned blockno, char* data, unsigned nbytes) +{ + blockno = blockno * (DEV_BSIZE/CHUNK_SIZE); + + while( nbytes >= CHUNK_SIZE ) { + read_chunk_from_sdram( (uint64_t*) swaptemp, blockno ); + bcopy( swaptemp, data, CHUNK_SIZE ); + data += CHUNK_SIZE; + blockno += 1; + nbytes -= CHUNK_SIZE; + } + + if( nbytes ) { + read_chunk_from_sdram( (uint64_t*) swaptemp, blockno ); + bcopy( swaptemp, data, nbytes ); + } + + return 1; +} + +/* + * Write a block of data. + */ +int +sdramp_write (int unit, unsigned blockno, char *data, unsigned nbytes) +{ + blockno = blockno * (DEV_BSIZE/CHUNK_SIZE); + + while( nbytes >= CHUNK_SIZE ) { + bcopy( data, swaptemp, CHUNK_SIZE ); + int x = mips_intr_disable(); + write_chunk_to_sdram( (uint64_t*) swaptemp, blockno ); + mips_intr_restore(x); + data += CHUNK_SIZE; + blockno += 1; + nbytes -= CHUNK_SIZE; + } + if( nbytes ) { + read_chunk_from_sdram( (uint64_t*) swaptemp, blockno ); + bcopy( data, swaptemp, nbytes ); + int x = mips_intr_disable(); + write_chunk_to_sdram( (uint64_t*) swaptemp, blockno ); + mips_intr_restore(x); + } + return 1; +} + +void sdramp_preinit (int unit) +{ + printf("sdramp_preinit\n"); + + int x = mips_intr_disable(); + struct buf *bp; + sdram_init_c(); + mips_intr_restore(x); + + bp = prepartition_device("sdramp0"/*,sdramp_size(0)*/); + if(bp) + { + sdramp_write (0, 0, bp->b_addr, 512); + brelse(bp); + } + +} + +int sdramp_open(int unit, int flag, int mode) +{ + return 0; +} + +int sdramp_size(int unit) +{ + return (1<= 11 +#define SDR_ADDRESS_A10_BIT 8 +#endif + +#if SDR_ADDRESS_LINES >= 12 +#define SDR_ADDRESS_A11_BIT 9 +#endif + +#if SDR_ADDRESS_LINES >= 13 +#define SDR_ADDRESS_A12_BIT 10 +#endif + +/***** END WARNING *****/ + +/* + * Data Lines + * + * The low 8 bits (bits 0-7) must be used + * and connected to the data lines on the sdram. + * The specific order in which the 8 pins are + * connected to the data pins of the sdram is + * not significant, unless you wish for a neat + * and tidy design that is easy connect to a + * logic analyzer for debugging purposes. + */ + +#define SDR_DATA_PORT TRISE + +/* + * Output Compare + * + * Currently supporting OC1CON or OC4CON + * Timer2 is used in all cases. + * The appropriate pin should be connected to CLK on the sdram. + * OC1CON - RD0 + * OC4CON - RD3 + */ + +#define SDR_OCR OC1CON + +/* + * Additional sdram connections + * + * Power and ground as appropriate. + */ + + +/***************************************************************/ + +/* + * Anthing following should not normally need to be modified. + * There are here in order to share definitions between C and ASM. + */ + +#ifdef SDR_ADDRESS_A10_BIT +#define SDR_ADDRESS_A10_BITMASK (1<> SW_DATA_PIN; +} + +/* + * Send LDA pulse: high-low-high. + */ +static inline void lda_pulse () +{ + LAT_CLR(SW_LDA_PORT) = 1 << SW_LDA_PIN; + asm volatile ("nop"); + asm volatile ("nop"); + LAT_SET(SW_LDA_PORT) = 1 << SW_LDA_PIN; +} + +/* + * Set RD low. + * Minimal time between falling edge of RD to data valid is 50ns. + */ +static inline void rd_low () +{ + LAT_CLR(SW_RD_PORT) = 1 << SW_RD_PIN; + +#if BUS_KHZ > 33000 + asm volatile ("nop"); // 55ns + asm volatile ("nop"); // 55ns +#endif +#if BUS_KHZ > 66000 + asm volatile ("nop"); // 55ns + asm volatile ("nop"); // 55ns +#endif +} + +/* + * Set RD high. + */ +static inline void rd_high () +{ + LAT_SET(SW_RD_PORT) = 1 << SW_RD_PIN; +} + +/* + * Send WR pulse: high-low-high. + * It shall be minimally 40ns. + */ +static inline void wr_pulse () +{ + LAT_CLR(SW_WR_PORT) = 1 << SW_WR_PIN; + +#if BUS_KHZ > 33000 + asm volatile ("nop"); // 55ns + asm volatile ("nop"); // 55ns +#endif +#if BUS_KHZ > 66000 + asm volatile ("nop"); // 55ns +#endif + LAT_SET(SW_WR_PORT) = 1 << SW_WR_PIN; +} + +/* + * Load the 24 bit address to ramdisk. + * Leave data bus in input mode. + */ +static void +dev_load_address (addr) + unsigned addr; +{ + /* Toggle rd: make one dummy read - this clears cpld's addr pointer */ + rd_low (); + rd_high (); + + data_switch_output(); /* switch data bus to output */ + + data_set (addr); /* send lowest 4 bits */ + lda_pulse(); /* pulse ldaddr */ + + data_set (addr >> 4); /* send 4 bits */ + lda_pulse(); /* pulse ldaddr */ + + data_set (addr >> 8); /* send 4 bits */ + lda_pulse(); /* pulse ldaddr */ + + data_set (addr >> 12); /* send 4 bits */ + lda_pulse(); /* pulse ldaddr */ + + data_set (addr >> 16); /* send 4 bits */ + lda_pulse(); /* pulse ldaddr */ + + data_set (addr >> 20); /* send highest 4 bits */ + lda_pulse(); /* pulse ldaddr */ + + data_switch_input(); +} + +/* + * Get number of kBytes on the disk. + * Return nonzero if successful. + */ +int sramc_size ( int unit ) +{ + return 4096; +} + +/* + * Read a block of data. + */ +int sramc_read (int unit, unsigned int blockno, char *data, unsigned int nbytes) +{ + int i; + + //DEBUG9("sramc%d: read block %u, length %u bytes, addr %p\n", + // major(dev), blockno, nbytes, data); + + dev_load_address (blockno * DEV_BSIZE); + + data_switch_input(); /* switch data bus to input */ + + /* Read data. */ + for (i=0; ib_addr, 512); + brelse(bp); + } + + return; +} + +/* + * Open the disk. + */ +int sramc_open (int unit) +{ + DEBUG3("sramc%d: open\n",unit); + return 0; +} diff --git a/sys/pic32/rdisk.c b/sys/pic32/rdisk.c new file mode 100644 index 0000000..dea62b0 --- /dev/null +++ b/sys/pic32/rdisk.c @@ -0,0 +1,684 @@ +#include "param.h" +#include "systm.h" +#include "buf.h" +#include "errno.h" +#include "dk.h" +#include "debug.h" +#include "ioctl.h" +#include "rdisk.h" +#include "conf.h" + +#define Q2(X) #X +#define QUOTE(X) Q2((X)) + +extern struct buf *getnewbuf(); + +/* + * Variable naming conventions + * + * root - this is the number of the device entry in the disks[] array + * part - the minor number of a device entry, which represents the partition + * number, or 0 for the whole disk + * unit - the physical device number of a specific device type. Equates + * to the .unit entry in the diskentry structure for a device. + */ + +extern int card_read(int unit, unsigned int offset, char *data, unsigned int bcount); +extern int card_write(int unit, unsigned int offset, char *data, unsigned int bcount); +extern int sdinit(int unit, int flag); +extern int sddeinit(int unit); +extern void sd_preinit(int unit); +extern int sdopen(int unit, int flags, int mode); +extern int sdsize(int unit); + +#ifdef SRAMC_ENABLED +#include +#endif +#ifdef SDRAMP_ENABLED +#include +#endif +#ifdef FLASH_ENABLED +#include +#endif +#ifdef MRAMS_ENABLED +#include +#endif + +int no_deinit(int u) { return 0; } +void no_preinit(int u) { return; } +int no_init(int u, int v) { return 0; } +int no_open(int u, int a, int b) { return 0; } +int no_size(int u) { return 0; } +int no_read(int u, unsigned int o, char *dat, unsigned int bs) { return 0; } +int no_write(int u, unsigned int o, char *dat, unsigned int bs) { return 0; } + +const struct devspec rd0devs[] = { { 0, "rd0" }, { 1, "rd0a" }, { 2, "rd0b" }, { 3, "rd0c" }, { 4, "rd0d" }, { 0, 0 } }; +const struct devspec rd1devs[] = { { 0, "rd1" }, { 1, "rd1a" }, { 2, "rd1b" }, { 3, "rd1c" }, { 4, "rd1d" }, { 0, 0 } }; +const struct devspec rd2devs[] = { { 0, "rd2" }, { 1, "rd2a" }, { 2, "rd2b" }, { 3, "rd2c" }, { 4, "rd2d" }, { 0, 0 } }; +const struct devspec rd3devs[] = { { 0, "rd3" }, { 1, "rd3a" }, { 2, "rd3b" }, { 3, "rd3c" }, { 4, "rd3d" }, { 0, 0 } }; + +// This is the list of physical storage devices on the system. +// Uncomment the ones you want below. Maximum 4 at the moment. +// They number, in the order of this list, rd0, rd1, rd2 and rd3. + +const struct diskentry disks[] = { + + {sd_preinit, sdinit, sddeinit, sdopen, sdsize, card_read, card_write, 0, RD_DEFAULT}, + +#ifdef SD1_PORT + {sd_preinit, sdinit, sddeinit, sdopen, sdsize, card_read, card_write, 1, RD_DEFAULT}, +#endif + +#ifdef SRAMC_ENABLED + {sramc_init, no_init, no_deinit, sramc_open, sramc_size, sramc_read, sramc_write, 0, RD_PREPART}, +#endif + +#ifdef SDRAMP_ENABLED + {sdramp_preinit, no_init, no_deinit, sdramp_open, sdramp_size, sdramp_read, sdramp_write, 0, RD_PREPART}, +#endif + +#ifdef FLASH_ENABLED + {flash_init, no_init, no_deinit, flash_open, flash_size, flash_read, flash_write, 0, RD_READONLY}, +#endif + +#ifdef MRAMS_ENABLED + {mrams_preinit, no_init, no_deinit, no_open, mrams_size, mrams_read, mrams_write, 0, RD_DEFAULT}, +#endif + +}; + +#define NRDSK sizeof(disks)/sizeof(struct diskentry) +#define MAXDEV NRDSK-1 + +#ifdef UCB_METER +int rddk = -1; +#endif + +struct diskflags dflags[NRDSK]; + +static inline struct buf *read_mbr(int root) +{ + if(root>MAXDEV) return NULL; + + int rv; + int unit = disks[root].unit; + + struct buf *bp = getnewbuf(); + + DEBUG8("rd%d: read mbr from device %d\n",root,unit); + rv = disks[root].read(unit,0,bp->b_addr,512); + if(rv==0) + { + DEBUG8("rd%d: mbr read FAIL\n",root); + brelse(buf); + return NULL; + } + DEBUG8("rd%d: mbr read OK\n",root); + + return bp; +} + + +static inline int init_device(int root,int flag) +{ + int i; + int e; + if(root>MAXDEV) return ENODEV; + + struct buf *bp; + struct mbr *mbr; + + int unit = disks[root].unit; + + e = disks[root].init(unit,flag); + + if(e!=0) + return e; + + DEBUG8("rd%d: about to read mbr\n",root); + bp = read_mbr(root); + if(!bp) + return ENXIO; + DEBUG8("rd%d: mbr read\n",root); + + mbr = (struct mbr *)bp->b_addr; + + DEBUG5("rd%d: partition types: %02X %02X %02X %02X\n",root, + mbr->partitions[0].type, + mbr->partitions[1].type, + mbr->partitions[2].type, + mbr->partitions[3].type + ); + DEBUG8("rd%d: partition 1 start: %p length: %p\n",root, + mbr->partitions[0].lbastart, mbr->partitions[0].lbalength + ); + DEBUG8("rd%d: partition 2 start: %p length: %p\n",root, + mbr->partitions[1].lbastart, mbr->partitions[1].lbalength + ); + DEBUG8("rd%d: partition 3 start: %p length: %p\n",root, + mbr->partitions[2].lbastart, mbr->partitions[2].lbalength + ); + DEBUG8("rd%d: partition 4 start: %p length: %p\n",root, + mbr->partitions[3].lbastart, mbr->partitions[3].lbalength + ); + + for(i=0; i<4; i++) + { + dflags[root].start[i] = mbr->partitions[i].lbastart>>1; + dflags[root].len[i] = mbr->partitions[i].lbalength>>1; + } + dflags[root].blocks = disks[root].size(unit); + brelse(bp); + return 0; +} + +static inline int deinit_device(int root) +{ + if(root>MAXDEV) return ENODEV; + return disks[root].deinit(disks[root].unit); +} + +static inline int open_device(int root, int flag) +{ + int e; + if(root>MAXDEV) return ENODEV; + + DEBUG3("rd%d: opening\n",root); + if(dflags[root].opens==0) + { + DEBUG3("rd%d: init device\n",root); + e = init_device(root, flag); + if(e!=0) + return e; + } + dflags[root].opens++; + + DEBUG3("rd%d: opened: %d\n",root,dflags[root].opens); + return 0; +} + +static inline int close_device(int root) +{ + if(root>MAXDEV) return ENODEV; + if(dflags[root].opens==0) + return ENXIO; + dflags[root].opens--; + if(dflags[root].opens==0) + { + deinit_device(root); + } + DEBUG3("rd%d: closed: %d\n",root,dflags[root].opens); + return 0; +} + +int rdopen(dev_t dev, int mode, int flag) +{ + int e; + int root = major(dev); + if(root>MAXDEV) return ENODEV; + + int unit = disks[root].unit; + + e=open_device(root,flag); + if(e!=0) + return e; + e=disks[root].open(unit,mode,flag); + if(e!=0) + return e; + + return 0; +} + +int rdclose(dev_t dev, int mode, int flag) +{ + int root = major(dev); + if(root>MAXDEV) return ENODEV; + close_device(root); + return 0; +} + +daddr_t rdsize(dev_t dev) +{ + int root = major(dev); + if(root>MAXDEV) return ENODEV; + + int part = minor(dev); + int unit = disks[root].unit; + unsigned int blocks; + + if(part==0) + { + return disks[root].size(unit); + } else { + if(rdopen(dev,0,S_SILENT)!=0) + return 0; + blocks=dflags[root].len[part-1]; + rdclose(dev,0,0); + DEBUG3("rd%d%c: get partition size: %d\n",root,part+'a'-1,blocks); + return blocks; + } +} + +void rdstrategy(register struct buf *bp) +{ + int root = major(bp->b_dev); + static int mutex = 0; + if(root>MAXDEV) return; + + mutex++; + if(mutex>1) + { + led_control(LED_SWAP,1); + } else { + led_control(LED_DISK,0); + } + + int part = minor(bp->b_dev); + int unit = disks[root].unit; + + int offset=0; + int s; + + if(part>0) + offset = dflags[root].start[part-1]; + + offset += (bp->b_blkno); + + if (bp->b_dev == swapdev) { + led_control(LED_SWAP,1); + } else { + led_control(LED_DISK,1); + } + + s = splbio(); + +#ifdef UCB_METER + if (rddk >= 0) { + dk_busy |= 1 << (rddk + root); + dk_xfer[rddk + root]++; + dk_bytes[rddk + root] += bp->b_bcount; + } +#endif + + + if (bp->b_flags & B_READ) { + disks[root].read(unit, offset, bp->b_addr, bp->b_bcount); + } else { + if(!(disks[root].settings & RD_READONLY)) + disks[root].write(unit, offset, bp->b_addr, bp->b_bcount); + } + + biodone(bp); + if (bp->b_dev == swapdev) { + led_control(LED_SWAP,0); + } else { + led_control(LED_DISK,0); + } + splx(s); + mutex--; +} + +void update_mbr(int unit) +{ + +} + +int rdioctl (dev_t dev, register u_int cmd, caddr_t addr, int flag) +{ + int *val; + + val = (int *)addr; + + if(cmd == RDGETMEDIASIZE) + { + *val = rdsize(dev); + } + if(cmd == RDREINIT) + { + bflush(major(dev)); + init_device(major(dev),S_SILENT); + + } + return 0; +} + +void rdisk_init() +{ + int i; + + //printf("Prepartition Schema: %s\n",prepartition_schema); + +#ifdef UCB_METER + dk_alloc(&rddk,NRDSK,"rd"); +#endif + + for(i=0; ib_addr; + for(j=1; j<5; j++) + { + if(mbr->partitions[j-1].type==type) + { + printf(" rd%d%c: %d KB\n",i,'a'+j-1,rdsize(makedev(i,j))); + } + } + brelse(bp); + } +} + +int rdisk_num_disks() +{ + return NRDSK; +} + +dev_t get_boot_device() +{ +// If a root device has been specified, then we can short cut all this and just +// use that device. +#ifdef ROOT + return ROOT; +#else + dev_t bd = -1; + int i,j,e; + struct buf *bp; + struct mbr *mbr; + + for(i=0; ib_addr; + + for(j=0; j<4; j++) + { + if(mbr->partitions[j].type==RDISK_FS) + { + if(mbr->partitions[j].status & P_ACTIVE) + { + brelse(bp); + rdclose(makedev(i,0),0,0); + return makedev(i,j+1); + } + } + } + brelse(bp); + } + rdclose(makedev(i,0),0,0); + } + } + + return bd; +#endif +} + +dev_t get_swap_device() +{ +// If a swap device has been specified, then we can short cut all this and just +// use that device. +#ifdef SWAP + return SWAP; +#else + + dev_t bd = -1; + int i,j,e; + unsigned int max_size = 0; + struct buf *bp; + struct mbr *mbr; + + // First we look for the first active swap device + + for(i=0; ib_addr; + + for(j=0; j<4; j++) + { + if(mbr->partitions[j].type==RDISK_SWAP) + { + // If this partition is the biggest so far + // then store it. We'll use this if + // there is no active partition. + if(mbr->partitions[j].lbalength>max_size) + { + max_size = mbr->partitions[j].lbalength; + bd = makedev(i,j+1); + } + + // If it is active, then use it. + if(mbr->partitions[j].status & P_ACTIVE) + { + brelse(bp); + rdclose(makedev(i,0),0,0); + return makedev(i,j+1); + } + } + } + brelse(bp); + } + rdclose(makedev(i,0),0,0); + } + } + + // There is no active partition, so we'll use the biggest one we found. + return bd; +#endif +} + +unsigned char partition_type(dev_t dev) +{ + struct buf *bp; + struct mbr *mbr; + unsigned char pt; + + if(minor(dev)<1 || minor(dev)>4) + return 0; + if(rdopen(dev,0,S_SILENT)==0) + { + bp = read_mbr(major(dev)); + rdclose(dev,0,0); + if(!bp) + { + brelse(bp); + return 0; + } + mbr = (struct mbr *)bp->b_addr; + pt = mbr->partitions[minor(dev)-1].type; + brelse(bp); + return pt; + } + return 0; +} + +int atoi(char *s) +{ + int i = 0; + char *q; + for(q=s; *q; q++) + { + if(*q < '0' || *q > '9') + { + return i; + } + i = i * 10; + i += *q - '0'; + } + return i; +} + +int strcmp(char *s1, char *s2) +{ + char *p1,*p2; + p1 = s1; + p2 = s2; + while(*p1 && *p2) + { + if(*p1 < *p2) return -1; + if(*p1 > *p2) return 1; + p1++; + p2++; + } + if(*p1 < *p2) return -1; + if(*p1 > *p2) return 1; + return 0; +} + +/* + +Prepartition format: + +mrams0:fs@1024,swap@2048,fs@1022 sdramp0:... + +*/ + +struct buf *prepartition_device(char *devname) +{ + +#ifndef PARTITION + char *prepartition_schema = ""; +#else + char *prepartition_schema = (char *)QUOTE(PARTITION); +#endif + char *p,*q; + struct buf *bp; + struct mbr *mbr; + int pnum = 0; + int start = 2; + char dev[9]; + char size[9]; + char type[5]; + int pos = 0; + + p = prepartition_schema+1; + q = p; + + printf("PP Schema: %s\n",prepartition_schema); + + bp = getnewbuf(); + if(!bp) + { + return NULL; + } + + mbr = (struct mbr *)bp->b_addr; + + while(*p) + { + while(*q && *q != ' ') + q++; + if(*q == ' ') + { + *q = 0; + q++; + } + + pos = 0; + while((*p) && (*p != ':')) + { + dev[pos++] = *p; + dev[pos] = 0; + p++; + } + + if((*p) == ':') + { + p++; + } else { + printf("Device Format Error (%c)\n",*p); + brelse(bp); + return NULL; + } + + while((*p) && (*p != ' ')) + { + pos = 0; + while((*p) && (*p != '@')) + { + type[pos++] = *p; + type[pos] = 0; + p++; + } + + if((*p) == '@') + { + p++; + } else { + printf("Type Format Error\n"); + brelse(bp); + return NULL; + } + + pos = 0; + while((*p) && (*p != ',') && (*p != ' ') && (*p != ')')) + { + size[pos++] = *p; + size[pos] = 0; + p++; + } + + printf("Found partition on %s of type %s and size %s\n", + dev,type,size); + + if(!strcmp(dev,devname)) + { + if(!strcmp("sw",type)) + mbr->partitions[pnum].type=RDISK_SWAP; + if(!strcmp("sa",type)) + { + mbr->partitions[pnum].type=RDISK_SWAP; + mbr->partitions[pnum].status = 0x80; + } + if(!strcmp("fs",type)) + mbr->partitions[pnum].type=RDISK_FS; + + mbr->partitions[pnum].lbastart = start; + mbr->partitions[pnum].lbalength = atoi(size)<<1; + start += mbr->partitions[pnum].lbalength; + pnum++; + } + p++; + } + } + + if(pnum > 0) + { + mbr->bootsig = 0xAA55; + mbr->biosdrive = 0x80; + mbr->sig = 'R'<<24 | 'T'<<16 | 'E'<<8 | 'R'; + return bp; + } + + brelse(bp); + return NULL; +} diff --git a/sys/pic32/retroone/Makefile b/sys/pic32/retroone/Makefile new file mode 100644 index 0000000..110b24d --- /dev/null +++ b/sys/pic32/retroone/Makefile @@ -0,0 +1,142 @@ +# +# Build RetroBSD kernel for PIC32 platform. +# +H = ../../include +M = .. +S = ../../kernel + +vpath %.c $(M):$(S) +vpath %.S $(M):$(S) + +# Kernel options. +DEFS += -I. -I$(H) -DKERNEL -DUCB_METER -DPIC32MX7 +DEFS += -DGLOBAL_DEBUG + +# CPU frequency 80 MHz. +DEFS += -DCPU_KHZ=80000 +DEFS += -DBUS_KHZ=80000 + +# +# Basic pic32mx795f512l chip with internal oscillator +# =================================================== +# +# Console on UART1 with hardware handshaking +DEFS += -DCONSOLE_UART1 #-DCONSOLE_RTSCTS +# SD/MMC card driver on SPI1 +DEFS += -DSD0_PORT=1 -DSD0_MHZ=20 +# /CS0 at pin B1 +DEFS += -DSD0_CS_PORT=TRISD -DSD0_CS_PIN=9 +# LEDs at pins A0, A1, A2, A3 +DEFS += -DLED_DISK_PORT=TRISA -DLED_DISK_PIN=14 +DEFS += -DLED_KERNEL_PORT=TRISB -DLED_KERNEL_PIN=8 +DEFS += -DLED_TTY_PORT=TRISB -DLED_TTY_PIN=9 +DEFS += -DLED_AUX_PORT=TRISA -DLED_AUX_PIN=9 + +# Include or exclude drivers + +# General Purpose I/O +DRIVER_GPIO = yes + +# Basic ADC interface +DRIVER_ADC = yes + +# Power control (power LED, and soft power-off by button) +# requires supported PSU (ATX) +DRIVER_POWER = no + +DRIVER_GLCD = yes +DRIVER_OC = yes + +POWER_LED_PORT = TRISG +POWER_LED_PIN = 12 +POWER_SWITCH_PORT = TRISG +POWER_SWITCH_PIN = 0 +POWER_CONTROL_PORT = TRISE +POWER_CONTROL_PIN = 9 + +DEPFLAGS = -MT $@ -MD -MP -MF .deps/$*.dep +CFLAGS = -O $(DEFS) $(DEPFLAGS) +ASFLAGS = $(DEFS) $(DEPFLAGS) + +include ../gcc-config.mk + +CC = $(GCCPREFIX)gcc -EL -g -mips32r2 +CC += -nostdinc -fno-builtin -Werror -Wall -fno-dwarf2-cfi-asm +LDFLAGS += -nostdlib -T bare-metal.ld -Wl,-Map=unix.map +SIZE = $(GCCPREFIX)size +OBJDUMP = $(GCCPREFIX)objdump +OBJCOPY = $(GCCPREFIX)objcopy +MPIDE = /Applications/Mpide.app/Contents/Resources/Java/ + +# Machine-dependent files: +# startup.o MUST be loaded first. +KERNOBJ = startup.o clock.o devsw.o cons.o sysctl.o \ + signal.o machdep.o mem.o exception.o + +# Kernel. +KERNOBJ += init_main.o init_sysent.o kern_clock.o \ + kern_descrip.o kern_exec.o kern_exit.o kern_fork.o \ + kern_mman.o kern_proc.o kern_prot.o \ + kern_prot2.o kern_resource.o kern_sig.o kern_sig2.o \ + kern_subr.o kern_synch.o kern_sysctl.o kern_time.o \ + subr_log.o subr_prf.o subr_rmap.o \ + sys_generic.o sys_inode.o syscalls.o \ + sys_pipe.o sys_process.o tty.o \ + tty_subr.o tty_tty.o ufs_alloc.o ufs_bio.o \ + ufs_bmap.o ufs_dsort.o ufs_fio.o \ + ufs_inode.o ufs_mount.o ufs_namei.o ufs_subr.o \ + ufs_syscalls.o ufs_syscalls2.o vfs_vnops.o \ + vm_sched.o vm_swap.o vm_swp.o kern_glob.o swap.o spi_bus.o + +# Drivers. +KERNOBJ += sd.o + +# Configuration-dependent files. +KERNOBJ += vers.o devcfg.o + +# Include any local specific configuration overrides +-include Makefile.local + +# This makefile does the work including the right files and options for the drivers +include ../drivers.mk + +all: .deps sys machine unix.elf + $(SIZE) unix.elf + +clean: + rm -rf .deps *.o *.elf *.bin *.dis *.map *.srec core \ + mklog assym.h vers.c genassym sys machine + +cleanest: clean + rm -f unix.hex + +.deps: + mkdir .deps + +sys: + ln -s ../../include $@ + +machine: + ln -s .. $@ + +unix.elf: $(KERNOBJ) bare-metal.ld + $(CC) $(LDFLAGS) $(KERNOBJ) -o $@ + chmod -x $@ + $(OBJDUMP) -d -S $@ > unix.dis + $(OBJCOPY) -O ihex --change-addresses=0x80000000 $@ unix.hex + +load: unix.elf + pic32prog unix.hex + +vers.o: ../newvers.sh $(H)/*.h $(M)/*.[ch] $(S)/*.c + sh ../newvers.sh > vers.c + $(CC) -c vers.c + +.SUFFIXES: .i .srec .hex .dis .cpp .cxx .bin .elf + +.o.dis: + $(OBJDUMP) -d -z -S $< > $@ + +ifeq (.deps, $(wildcard .deps)) +-include .deps/*.dep +endif diff --git a/sys/pic32/retroone/bare-metal.ld b/sys/pic32/retroone/bare-metal.ld new file mode 100644 index 0000000..5c45bea --- /dev/null +++ b/sys/pic32/retroone/bare-metal.ld @@ -0,0 +1,162 @@ +/* + * Linker script for PIC32 firmware. + */ +OUTPUT_FORMAT("elf32-littlemips", "elf32-bigmips", + "elf32-littlemips") +OUTPUT_ARCH(mips) +ENTRY(_reset_vector_) +MEMORY +{ + ram (rw!x): ORIGIN = 0x80000000, LENGTH = 26K + u0area (rw!x): ORIGIN = 0x80006800, LENGTH = 3K + uarea (rw!x): ORIGIN = 0x80007400, LENGTH = 3K + devcfg (r) : ORIGIN = 0x9fc02ff0, LENGTH = 16 + + /* Required by Microchip C32 linker */ + kseg0_program_mem (rx) : ORIGIN = 0x9D000000, LENGTH = 512K + exception_mem (rx) : ORIGIN = 0x9D000000, LENGTH = 0x1000 + kseg0_boot_mem (rx) : ORIGIN = 0x9FC00000, LENGTH = 12K-16 + kseg1_boot_mem (rx) : ORIGIN = 0xBFC00000, LENGTH = 0x490 + kseg1_data_mem (w!x) : ORIGIN = 0xA0000000, LENGTH = 0x20000 +} + +/* higher address of the user mode stack */ +u0 = ORIGIN(u0area); +u = ORIGIN(uarea); +u_end = ORIGIN(uarea) + LENGTH(uarea); + +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = 0x0000; + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rel.init : { *(.rel.init) } + .rela.init : { *(.rela.init) } + .rel.text : { *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) } + .rela.text : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) } + .rel.fini : { *(.rel.fini) } + .rela.fini : { *(.rela.fini) } + .rel.rodata : { *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) } + .rela.rodata : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) } + .rel.data : { *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) } + .rela.data : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.sdata : { *(.rel.sdata .rel.sdata.* .rel.gnu.linkonce.s.*) } + .rela.sdata : { *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*) } + .rel.sbss : { *(.rel.sbss .rel.sbss.* .rel.gnu.linkonce.sb.*) } + .rela.sbss : { *(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*) } + .rel.sdata2 : { *(.rel.sdata2 .rel.sdata2.* .rel.gnu.linkonce.s2.*) } + .rela.sdata2 : { *(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*) } + .rel.sbss2 : { *(.rel.sbss2 .rel.sbss2.* .rel.gnu.linkonce.sb2.*) } + .rela.sbss2 : { *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*) } + .rel.bss : { *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) } + .rela.bss : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .plt : { *(.plt) } + + .boot : + { + /* Execution starts here. */ + *(.startup) + } > kseg0_boot_mem + + .text : + { + /* Exception handlers. */ + *(.exception) + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.glue_7t) *(.glue_7) + __rodata_start = . ; + *(.rodata .rodata.* .gnu.linkonce.r.* .rel.dyn) + /* Align here to ensure that the .text section ends on word boundary. */ + . = ALIGN (32 / 8); + _etext = .; + } > kseg0_program_mem + + /* Start data (internal SRAM). */ + .data : AT (ADDR (.text) + SIZEOF (.text)) + { + __data_start = . ; + _gp = .; /* We have only 32k RAM on MC-24, so no need for 0x8000 offset. */ + *(.data .data.* .gnu.linkonce.d.*) + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + *(.sdata .sdata.* .gnu.linkonce.s.*) + *(.eh_frame) + _edata = .; + } > ram + + /* Device configuration. */ + .config : + { + *(.config3) + *(.config2) + *(.config1) + *(.config0) + } > devcfg + + .bss ADDR (.data) + SIZEOF (.data) (NOLOAD) : + { + __bss_start = .; + *(.dynbss) + *(.sbss .sbss.*) + *(.scommon) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. */ + . = ALIGN (32 / 8); + } > ram + __bss_end = . ; + _end = .; + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } +} diff --git a/sys/pic32/retroone/devcfg.c b/sys/pic32/retroone/devcfg.c new file mode 100644 index 0000000..e17d102 --- /dev/null +++ b/sys/pic32/retroone/devcfg.c @@ -0,0 +1,25 @@ +/* + * Chip configuration. + */ +#include "machine/pic32mx.h" + +PIC32_DEVCFG ( + DEVCFG0_DEBUG_ENABLED, /* ICE debugger enabled */ + + DEVCFG1_FNOSC_FRCDIVPLL | /* Primary oscillator with PLL */ + DEVCFG1_POSCMOD_DISABLE | /* HS oscillator */ + DEVCFG1_OSCIOFNC | /* CLKO output active */ + DEVCFG1_FPBDIV_1 | /* Peripheral bus clock = SYSCLK/1 */ + DEVCFG1_FCKM_DISABLE | /* Fail-safe clock monitor disable */ + DEVCFG1_FCKS_DISABLE | /* Clock switching disable */ + DEVCFG1_WDTPS_1024, /* Watchdog postscale = 1/1024 */ + + DEVCFG2_FPLLIDIV_2 | /* PLL divider = 1/2 */ + DEVCFG2_FPLLMUL_20 | /* PLL multiplier = 20x */ + DEVCFG2_UPLLIDIV_2 | /* USB PLL divider = 1/2 */ + DEVCFG2_UPLLDIS | /* Disable USB PLL */ + DEVCFG2_FPLLODIV_1, /* PLL postscaler = 1/1 */ + + DEVCFG3_USERID(0xffff) | /* User-defined ID */ + DEVCFG3_FSRSSEL_7 | /* Assign irq priority 7 to shadow set */ + DEVCFG3_FETHIO); /* Default Ethernet i/o pins */ diff --git a/sys/pic32/sdram.S b/sys/pic32/sdram.S new file mode 100644 index 0000000..ee9d2a0 --- /dev/null +++ b/sys/pic32/sdram.S @@ -0,0 +1,538 @@ +/* + * SDRAM Access Routines for PIC32. + * + * Retromaster - 10.05.2010 + * + * This file is in the public domain. You can use, modify, and distribute the source code + * and executable programs based on the source code. This file is provided "as is" and + * without any express or implied warranties whatsoever. Use at your own risk! + * + * Changes by jmcgee for inclusion in the retrobsd project. + */ + +/* SDRAM Used: HY57V281620 */ + +/* + * See rd_sdramp_config.h for sdramp port/pin configuration + */ +#include "rd_sdramp_config.h" + +/* Offsets (from TRISA) for the various port control registers */ +#define TRIS_OFFSET 0x0 +#define PORT_OFFSET (PORTA-TRISA) +#define LAT_OFFSET (LATA-TRISA) +#define ODCF_OFFSET (ODCA-TRISA) + +/* Offsets (from TRISA) for the various io port bit manipulator registers */ +#define NOP_OP_OFFSET 0x0 +#define CLR_OP_OFFSET (TRISACLR-TRISA) +#define SET_OP_OFFSET (TRISASET-TRISA) +#define INV_OP_OFFSET (TRISAINV-TRISA) + + /* Global Symbols */ + .globl sdram_init + .globl sdram_read + .globl sdram_write + .globl sdram_active + .globl sdram_auto_refresh + .globl sdram_precharge + .globl sdram_precharge_all + .globl sdram_sleep + .globl sdram_wake + .globl sdram_bank + + .type sdram_init, @function + .type sdram_read, @function + .type sdram_write, @function + .type sdram_active, @function + .type sdram_auto_refresh, @function + .type sdram_precharge, @function + .type sdram_precharge_all, @function + .type sdram_sleep, @function + .type sdram_wake, @function + .type sdram_bank, @function + + /* + * This code MUST execute from ram and the ram MUST be configured + * for zero wait states. Interrupts MUST disabled before + * calling any of these functions, and any DMA MUST also be + * disabled. + * + * Also, the peripheral bus divisor must be set to 1. + */ + + .section .ramfunc,"ax",@progbits + + /* No instruction reordering */ + + .set noreorder + +#define clock4 \ + nop;nop;nop;nop + +#define clock3 \ + nop;nop;nop + +#define clock2 \ + nop;nop + +#define clock1 \ + nop + +/* + * The SDRAM clock is output from the output compare unit. + * This macro synchronizes with that clock so that we are + * sure to have at least two clock cycles to issue control + * line changes and access the data bus before the rising + * edge. + */ + + +#define sync_clock \ + la $t8, TMR2; \ + li $v0, 2; \ + lw $v1, ($t8); \ + bge $v1, $v0, 1f; \ + nop; \ + nop; \ + nop; \ + 1: \ + nop; + +/* + * Initializes the SDRAM. + * Should be called once sometime after startup + * C Prototype: + * extern __attribute__((far)) void sdram_init(); + * This should only be called from sdram_init_c, + * which does all of the preliminary setup. + */ + +sdram_init: + + /* Initialize address lines */ + la $t0, TRISA /* base of io addresses */ + + /* Get ready for the commands we are about to issue. */ + li $t4, (1< +typedef unsigned short uint16_t; +typedef unsigned char uint8_t; +typedef unsigned long long uint64_t; + +extern __attribute__((far)) void sdram_init(); +extern __attribute__((far)) void sdram_active(); +extern __attribute__((far)) void sdram_write(uint64_t val); +extern __attribute__((far)) uint64_t sdram_read(); +extern __attribute__((far)) void sdram_auto_refresh(void); +extern __attribute__((far)) void sdram_precharge(void); +extern __attribute__((far)) void sdram_precharge_all(void); +extern __attribute__((far)) void sdram_sleep(void); +extern __attribute__((far)) void sdram_wake(void); + +#endif + +#endif diff --git a/sys/pic32/signal.c b/sys/pic32/signal.c new file mode 100644 index 0000000..2fdcd04 --- /dev/null +++ b/sys/pic32/signal.c @@ -0,0 +1,197 @@ +/* + * Copyright (c) 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "param.h" +#include "systm.h" +#include "signalvar.h" +#include "user.h" +#include "proc.h" +#include "buf.h" +#include "map.h" +#include "syslog.h" + +//#define DIAGNOSTIC + +/* + * Send an interrupt to process. + * + * Stack is set up to allow trampoline code stored at u.u_sigtramp (as + * specified by the user process) to call the user's real signal catch + * routine, followed by sys sigreturn to the sigreturn routine below + * (see lib/libc/mips/sys/sigaction.S). After sigreturn resets the signal + * mask, the stack, and the frame pointer, it returns to the user specified + * pc and regs. + */ +void +sendsig (p, sig, mask) + sig_t p; + int sig; + long mask; +{ + struct sigframe { + int sf_space [4]; + struct sigcontext sf_sc; + }; + register int *regs = u.u_frame; + register struct sigframe *sfp; + int oonstack; + +#ifdef DIAGNOSTIC + printf("(%u)sendsig %d, mask=%#x, handler=%#x, tramp=%#x\n", + u.u_procp->p_pid, sig, mask, p, u.u_sigtramp); +#endif + oonstack = u.u_sigstk.ss_flags & SA_ONSTACK; + + /* + * Allocate and validate space for the signal frame. + */ + if ((u.u_psflags & SAS_ALTSTACK) && + ! (u.u_sigstk.ss_flags & SA_ONSTACK) && + (u.u_sigonstack & sigmask(sig))) { + sfp = (struct sigframe*) (u.u_sigstk.ss_base + + u.u_sigstk.ss_size); + u.u_sigstk.ss_flags |= SA_ONSTACK; + } else + sfp = (struct sigframe*) regs [FRAME_SP]; + + sfp--; + if (! (u.u_sigstk.ss_flags & SA_ONSTACK)) { + if ((caddr_t) sfp < (caddr_t) u.u_procp->p_daddr + u.u_dsize) { + /* + * Process has trashed its stack; give it an illegal + * instruction violation to halt it in its tracks. + */ + fatalsig(SIGILL); + return; + } + if (u.u_procp->p_ssize < USER_DATA_END - (unsigned) sfp) { + u.u_procp->p_ssize = USER_DATA_END - (unsigned) sfp; + u.u_procp->p_saddr = (unsigned) sfp; + u.u_ssize = u.u_procp->p_ssize; + } + } + + /* + * Build the signal context to be used by sigreturn. + */ + sfp->sf_sc.sc_onstack = oonstack; + sfp->sf_sc.sc_mask = mask; + sfp->sf_sc.sc_r1 = regs [FRAME_R1]; + sfp->sf_sc.sc_r2 = regs [FRAME_R2]; + sfp->sf_sc.sc_r3 = regs [FRAME_R3]; + sfp->sf_sc.sc_r4 = regs [FRAME_R4]; + sfp->sf_sc.sc_r5 = regs [FRAME_R5]; + sfp->sf_sc.sc_r6 = regs [FRAME_R6]; + sfp->sf_sc.sc_r7 = regs [FRAME_R7]; + sfp->sf_sc.sc_r8 = regs [FRAME_R8]; + sfp->sf_sc.sc_r9 = regs [FRAME_R9]; + sfp->sf_sc.sc_r10 = regs [FRAME_R10]; + sfp->sf_sc.sc_r11 = regs [FRAME_R11]; + sfp->sf_sc.sc_r12 = regs [FRAME_R12]; + sfp->sf_sc.sc_r13 = regs [FRAME_R13]; + sfp->sf_sc.sc_r14 = regs [FRAME_R14]; + sfp->sf_sc.sc_r15 = regs [FRAME_R15]; + sfp->sf_sc.sc_r16 = regs [FRAME_R16]; + sfp->sf_sc.sc_r17 = regs [FRAME_R17]; + sfp->sf_sc.sc_r18 = regs [FRAME_R18]; + sfp->sf_sc.sc_r19 = regs [FRAME_R19]; + sfp->sf_sc.sc_r20 = regs [FRAME_R20]; + sfp->sf_sc.sc_r21 = regs [FRAME_R21]; + sfp->sf_sc.sc_r22 = regs [FRAME_R22]; + sfp->sf_sc.sc_r23 = regs [FRAME_R23]; + sfp->sf_sc.sc_r24 = regs [FRAME_R24]; + sfp->sf_sc.sc_r25 = regs [FRAME_R25]; + sfp->sf_sc.sc_gp = regs [FRAME_GP]; + sfp->sf_sc.sc_sp = regs [FRAME_SP]; + sfp->sf_sc.sc_fp = regs [FRAME_FP]; + sfp->sf_sc.sc_ra = regs [FRAME_RA]; + sfp->sf_sc.sc_lo = regs [FRAME_LO]; + sfp->sf_sc.sc_hi = regs [FRAME_HI]; + sfp->sf_sc.sc_pc = regs [FRAME_PC]; + + /* Call signal handler */ + regs [FRAME_R4] = sig; /* $a0 - signal number */ + regs [FRAME_R5] = u.u_code; /* $a1 - code */ + regs [FRAME_R6] = (int) &sfp->sf_sc; /* $a2 - address of sigcontext */ + regs [FRAME_RA] = (int) u.u_sigtramp; /* $ra - sigtramp */ + regs [FRAME_SP] = (int) sfp; + regs [FRAME_PC] = (int) p; +#ifdef DIAGNOSTIC + printf(" ...call handler %p (sig=%d, code=%#x, context=%p)\n", + p, sig, u.u_code, &sfp->sf_sc); + printf(" ...stack=%p, return to %p\n", sfp, u.u_sigtramp); +#endif +} + +/* + * System call to cleanup state after a signal + * has been taken. Reset signal mask and + * stack state from context left by sendsig (above). + * Return to previous pc and ps as specified by + * context left by sendsig. Check carefully to + * make sure that the user has not modified the + * ps to gain improper priviledges or to cause + * a machine fault. + */ +void +sigreturn() +{ + register int *regs = u.u_frame; + register struct sigcontext *scp = + (struct sigcontext*) (regs [FRAME_SP] + 16); + +#ifdef DIAGNOSTIC + printf("(%u)sigreturn stack=%#x, context=%p\n", + u.u_procp->p_pid, regs [FRAME_SP], scp); +#endif + if (baduaddr ((caddr_t) scp) || + baduaddr ((caddr_t) scp + sizeof(*scp))) { + u.u_error = EFAULT; + return; + } + u.u_error = EJUSTRETURN; + if (scp->sc_onstack & SA_ONSTACK) + u.u_sigstk.ss_flags |= SA_ONSTACK; + else + u.u_sigstk.ss_flags &= ~SA_ONSTACK; + u.u_procp->p_sigmask = scp->sc_mask & ~sigcantmask; + + /* Return from signal handler */ + regs [FRAME_R1] = scp->sc_r1; + regs [FRAME_R2] = scp->sc_r2; + regs [FRAME_R3] = scp->sc_r3; + regs [FRAME_R4] = scp->sc_r4; + regs [FRAME_R5] = scp->sc_r5; + regs [FRAME_R6] = scp->sc_r6; + regs [FRAME_R7] = scp->sc_r7; + regs [FRAME_R8] = scp->sc_r8; + regs [FRAME_R9] = scp->sc_r9; + regs [FRAME_R10] = scp->sc_r10; + regs [FRAME_R11] = scp->sc_r11; + regs [FRAME_R12] = scp->sc_r12; + regs [FRAME_R13] = scp->sc_r13; + regs [FRAME_R14] = scp->sc_r14; + regs [FRAME_R15] = scp->sc_r15; + regs [FRAME_R16] = scp->sc_r16; + regs [FRAME_R17] = scp->sc_r17; + regs [FRAME_R18] = scp->sc_r18; + regs [FRAME_R19] = scp->sc_r19; + regs [FRAME_R20] = scp->sc_r20; + regs [FRAME_R21] = scp->sc_r21; + regs [FRAME_R22] = scp->sc_r22; + regs [FRAME_R23] = scp->sc_r23; + regs [FRAME_R24] = scp->sc_r24; + regs [FRAME_R25] = scp->sc_r25; + regs [FRAME_GP] = scp->sc_gp; + regs [FRAME_SP] = scp->sc_sp; + regs [FRAME_FP] = scp->sc_fp; + regs [FRAME_RA] = scp->sc_ra; + regs [FRAME_LO] = scp->sc_lo; + regs [FRAME_HI] = scp->sc_hi; + regs [FRAME_PC] = scp->sc_pc; +#ifdef DIAGNOSTIC + printf(" ...to %#x, stack %#x\n", regs[FRAME_PC], regs[FRAME_SP]); +#endif +} diff --git a/sys/pic32/spi.c b/sys/pic32/spi.c new file mode 100644 index 0000000..caf60c3 --- /dev/null +++ b/sys/pic32/spi.c @@ -0,0 +1,178 @@ +/* + * Generic SPI driver for PIC32. + * + * Copyright (C) 2012 Serge Vakulenko, + * + * 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 the copyright notice and this + * permission notice and warranty disclaimer appear in supporting + * documentation, and that the name of the author not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * + * The author disclaim all warranties with regard to this + * software, including all implied warranties of merchantability + * and fitness. In no event shall the author 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. + */ +#include "param.h" +#include "conf.h" +#include "user.h" +#include "ioctl.h" +#include "systm.h" +#include "uio.h" +#include "spi.h" +#include "spi_bus.h" + +const struct devspec spidevs[] = { + { 0, "spi1" }, + { 1, "spi2" }, + { 2, "spi3" }, + { 3, "spi4" }, + { 0, 0 } +}; + +#define NSPI 4 /* Ports SPI1...SPI4 */ + +/* + * To enable debug output, uncomment the first line. + */ +//#define PRINTDBG printf +#ifndef PRINTDBG +# define PRINTDBG(...) /*empty*/ +#endif + +int spi_fd[NSPI]; + +/* + * Open /dev/spi# device. + * Use default SPI parameters: + * - rate 250 kHz; + * - no sleect pin. + */ +int spidev_open (dev_t dev, int flag, int mode) +{ + int channel = minor (dev); + + if (channel >= NSPI) + return ENXIO; + + if (u.u_uid != 0) + return EPERM; + + spi_fd[channel] = spi_open(channel+1,NULL,NULL); + if(spi_fd[channel]==-1) + return ENODEV; + return 0; +} + +int spidev_close (dev_t dev, int flag, int mode) +{ + int channel = minor (dev); + + if (channel >= NSPI) + return ENXIO; + + if (u.u_uid != 0) + return EPERM; + + spi_close(spi_fd[channel]); + return 0; +} + +int spidev_read (dev_t dev, struct uio *uio, int flag) +{ + return 0; +} + +int spidev_write (dev_t dev, struct uio *uio, int flag) +{ + return 0; +} + +/* + * SPI control operations: + * - SPICTL_SETMODE - set clock polarity and phase + * - SPICTL_SETRATE - set data rate in kHz + * - SPICTL_SETSELPIN - set select pin + * - SPICTL_IO8(n) - n*8 bit transaction + * - SPICTL_IO16(n) - n*16 bit transaction + * - SPICTL_IO32(n) - n*32 bit transaction + */ +int spidev_ioctl (dev_t dev, u_int cmd, caddr_t addr, int flag) +{ + int channel = minor (dev); + unsigned char *cval = (unsigned char *)addr; + int nelem; + static unsigned volatile *const tris[8] = { + 0, &TRISA,&TRISB,&TRISC,&TRISD,&TRISE,&TRISF,&TRISG, + }; + int mask, portnum; + + //PRINTDBG ("spi%d: ioctl (cmd=%08x, addr=%08x)\n", channel+1, cmd, addr); + if (channel >= NSPI) + return ENXIO; + + switch (cmd & ~(IOCPARM_MASK << 16)) { + default: + return ENODEV; + + case SPICTL_SETMODE: /* set SPI mode */ + /* --- Clock ---- + * Mode Polarity Phase + * 0 0 0 + * 1 0 1 + * 2 1 0 + * 3 1 1 + */ + if((unsigned int) addr & 0x01) + spi_set(spi_fd[channel], PIC32_SPICON_CKE); + if((unsigned int) addr & 0x02) + spi_set(spi_fd[channel], PIC32_SPICON_CKP); + return 0; + + case SPICTL_SETRATE: /* set clock rate, kHz */ + spi_brg(spi_fd[channel], (unsigned int) addr); + return 0; + + case SPICTL_SETSELPIN: /* set select pin */ + mask = 1 << ((unsigned int) addr & 15); + portnum = ((unsigned int) addr >> 8) & 7; + if (! portnum) + return 0; + spi_set_cspin(spi_fd[channel], (unsigned int *)tris[((unsigned int) addr >> 8) & 7], (unsigned int) addr & 15); + return 0; + + case SPICTL_IO8(0): /* transfer n*8 bits */ + spi_select(spi_fd[channel]); + nelem = (cmd >> 16) & IOCPARM_MASK; + if (baduaddr (addr) || baduaddr (addr + nelem - 1)) + return EFAULT; + spi_bulk_rw(spi_fd[channel], nelem, cval); + spi_deselect(spi_fd[channel]); + break; + + case SPICTL_IO16(0): /* transfer n*16 bits */ + nelem = (cmd >> 16) & IOCPARM_MASK; + if (((unsigned) addr & 1) || + baduaddr (addr) || baduaddr (addr + nelem*2 - 1)) + return EFAULT; + spi_bulk_rw_16(spi_fd[channel], nelem<<1, (char *)addr); + break; + + case SPICTL_IO32(0): /* transfer n*32 bits */ + nelem = (cmd >> 16) & IOCPARM_MASK; + if (((unsigned) addr & 3) || + baduaddr (addr) || baduaddr (addr + nelem*4 - 1)) + return EFAULT; + spi_bulk_rw_32(spi_fd[channel], nelem<<2, (char *)addr); + break; + } + return 0; +} diff --git a/sys/pic32/spi_bus.c b/sys/pic32/spi_bus.c new file mode 100644 index 0000000..3966197 --- /dev/null +++ b/sys/pic32/spi_bus.c @@ -0,0 +1,678 @@ +#include "param.h" +#include "conf.h" +#include "user.h" +#include "ioctl.h" +#include "systm.h" +#include "uio.h" +#include "spi_bus.h" + +#define NSPI 4 /* Ports SPI1...SPI4 */ + +#define MAXSPIDEV 10 + +struct spi_dev spi_devices[MAXSPIDEV]; + +// Default SPI bus speed + +#ifndef SPI_MHZ +#define SPI_MHZ 10 +#endif + + +// Open an SPI device in default mode. Use further function calls to +// set baud rate, clock phase, etc. +// Returns an integer for the number of the device (ala fd). +// Returns -1 if no devices are available. + +int spi_open(unsigned int bus, unsigned int *tris, unsigned int pin) +{ + int dno; + + // Find a free device + for(dno=0; dno= MAXSPIDEV) + return; + + if(spi_devices[dno].bus==NULL) + return; + + // Revert the old CS pin to an input (release it) + if(spi_devices[dno].cs_tris) + { + // Configure the CS pin + TRIS_SET(*spi_devices[dno].cs_tris) = 1<= MAXSPIDEV) + return; + + if(spi_devices[dno].bus==NULL) + return; + + if (spi_devices[dno].cs_tris != NULL) { + // Revert the CS pin to input. + TRIS_CLR(*spi_devices[dno].cs_tris) = 1<= MAXSPIDEV) + return; + + if(spi_devices[dno].bus==NULL) + return; + + if (spi_devices[dno].cs_tris == NULL) + return; + + spi_devices[dno].bus->brg = spi_devices[dno].baud; + spi_devices[dno].bus->con = spi_devices[dno].mode; + + LAT_CLR(*spi_devices[dno].cs_tris) = 1<= MAXSPIDEV) + return; + + if(spi_devices[dno].bus==NULL) + return; + + if (spi_devices[dno].cs_tris == NULL) + return; + + LAT_SET(*spi_devices[dno].cs_tris) = 1<= MAXSPIDEV) + return; + + if(spi_devices[dno].bus==NULL) + return; + + spi_devices[dno].mode |= set; +} + +// Clear a mode setting or two - just updates the internal records, the +// actual mode is changed next time the CS is asserted +void spi_clr(int dno, unsigned int set) +{ + if(dno >= MAXSPIDEV) + return; + + if(spi_devices[dno].bus==NULL) + return; + + spi_devices[dno].mode &= ~set; +} + +// Return the current status of the SPI bus for the device in question +// Just returns the ->stat entry in the register set. +unsigned int spi_status(int dno) +{ + if(dno >= MAXSPIDEV) + return 0; + + if(spi_devices[dno].bus==NULL) + return 0; + + return spi_devices[dno].bus->stat; +} + +// Transfer one word of data, and return the read word of +// data. The actual number of bits sent depends on the +// mode of the transfer. +// This is blocking, and waits for the transfer to complete +// before returning. Times out after a certain period. +unsigned char spi_transfer(int dno, unsigned char data) +{ + unsigned int to = 100000; + + if(dno >= MAXSPIDEV) + return 0xF0; + + if(spi_devices[dno].bus==NULL) + return 0xF1; + + spi_devices[dno].bus->con = spi_devices[dno].mode; + spi_devices[dno].bus->brg = spi_devices[dno].baud; + + spi_devices[dno].bus->buf = data; + while ((--to > 0) && (!(spi_devices[dno].bus->stat & PIC32_SPISTAT_SPIRBF))) + asm volatile ("nop"); + + if(to == 0) + return 0xF2; + + return spi_devices[dno].bus->buf; +} + +// Write a huge chunk of data as fast and as efficiently as +// possible. Switches in to 32-bit mode regardless, and uses +// the enhanced buffer mode. +// Data should be a multiple of 32 bits. +void spi_bulk_write_32_be(int dno, unsigned int len, char *data) +{ + int *data32 = (int *)data; + unsigned int words = len >> 2; + unsigned int nread; + unsigned int nwritten; + + if(dno >= MAXSPIDEV) + return; + + if(spi_devices[dno].bus==NULL) + return; + + nread = 0; + nwritten = words; + + spi_devices[dno].bus->conset = PIC32_SPICON_MODE32 | PIC32_SPICON_ENHBUF; + while(nread < words) + { + if(nwritten > 0 && !(spi_devices[dno].bus->stat & PIC32_SPISTAT_SPITBF)) + { + spi_devices[dno].bus->buf = mips_bswap(*data32++); + nwritten--; + } + + if(!(spi_devices[dno].bus->stat & PIC32_SPISTAT_SPIRBE)) + { + (void) spi_devices[dno].bus->buf; + nread++; + } + } + spi_devices[dno].bus->con = spi_devices[dno].mode; +} + +void spi_bulk_write_32(int dno, unsigned int len, char *data) +{ + int *data32 = (int *)data; + unsigned int words = len >> 2; + unsigned int nread; + unsigned int nwritten; + + if(dno >= MAXSPIDEV) + return; + + if(spi_devices[dno].bus==NULL) + return; + + nread = 0; + nwritten = words; + + spi_devices[dno].bus->conset = PIC32_SPICON_MODE32 | PIC32_SPICON_ENHBUF; + while(nread < words) + { + if(nwritten > 0 && !(spi_devices[dno].bus->stat & PIC32_SPISTAT_SPITBF)) + { + spi_devices[dno].bus->buf = *data32++; + nwritten--; + } + + if(!(spi_devices[dno].bus->stat & PIC32_SPISTAT_SPIRBE)) + { + (void) spi_devices[dno].bus->buf; + nread++; + } + } + spi_devices[dno].bus->con = spi_devices[dno].mode; +} + +void spi_bulk_write_16(int dno, unsigned int len, char *data) +{ + short *data16 = (short *)data; + unsigned int words = len >> 1; + unsigned int nread; + unsigned int nwritten; + + if(dno >= MAXSPIDEV) + return; + + if(spi_devices[dno].bus==NULL) + return; + + nread = 0; + nwritten = words; + + spi_devices[dno].bus->conset = PIC32_SPICON_MODE16 | PIC32_SPICON_ENHBUF; + while(nread < words) + { + if(nwritten > 0 && !(spi_devices[dno].bus->stat & PIC32_SPISTAT_SPITBF)) + { + spi_devices[dno].bus->buf = *data16++; + nwritten--; + } + + if(!(spi_devices[dno].bus->stat & PIC32_SPISTAT_SPIRBE)) + { + (void) spi_devices[dno].bus->buf; + nread++; + } + } + spi_devices[dno].bus->con = spi_devices[dno].mode; +} + +void spi_bulk_write(int dno, unsigned int len, unsigned char *data) +{ + unsigned char *data8 = data; + unsigned int i; + unsigned char in,out; + + if(dno >= MAXSPIDEV) + return; + + if(spi_devices[dno].bus==NULL) + return; + + for(i=0; i> 2; + unsigned int nread; + unsigned int nwritten; + + if(dno >= MAXSPIDEV) + return; + + if(spi_devices[dno].bus==NULL) + return; + + nread = 0; + nwritten = words; + + spi_devices[dno].bus->conset = PIC32_SPICON_MODE32 | PIC32_SPICON_ENHBUF; + while(nread < words) + { + if(nwritten > 0 && !(spi_devices[dno].bus->stat & PIC32_SPISTAT_SPITBF)) + { + spi_devices[dno].bus->buf = ~0; + nwritten--; + } + + if(!(spi_devices[dno].bus->stat & PIC32_SPISTAT_SPIRBE)) + { + *data32++ = mips_bswap(spi_devices[dno].bus->buf); + nread++; + } + } + spi_devices[dno].bus->con = spi_devices[dno].mode; +} + +void spi_bulk_read_32(int dno, unsigned int len, char *data) +{ + int *data32 = (int *)data; + unsigned int words = len >> 2; + unsigned int nread; + unsigned int nwritten; + + if(dno >= MAXSPIDEV) + return; + + if(spi_devices[dno].bus==NULL) + return; + + nread = 0; + nwritten = words; + + spi_devices[dno].bus->conset = PIC32_SPICON_MODE32 | PIC32_SPICON_ENHBUF; + while(nread < words) + { + if(nwritten > 0 && !(spi_devices[dno].bus->stat & PIC32_SPISTAT_SPITBF)) + { + spi_devices[dno].bus->buf = ~0; + nwritten--; + } + + if(!(spi_devices[dno].bus->stat & PIC32_SPISTAT_SPIRBE)) + { + *data32++ = spi_devices[dno].bus->buf; + nread++; + } + } + spi_devices[dno].bus->con = spi_devices[dno].mode; +} + +void spi_bulk_read_16(int dno, unsigned int len, char *data) +{ + short *data16 = (short *)data; + unsigned int words = len >> 1; + unsigned int nread; + unsigned int nwritten; + + if(dno >= MAXSPIDEV) + return; + + if(spi_devices[dno].bus==NULL) + return; + + nread = 0; + nwritten = words; + + spi_devices[dno].bus->conset = PIC32_SPICON_MODE16 | PIC32_SPICON_ENHBUF; + while(nread < words) + { + if(nwritten > 0 && !(spi_devices[dno].bus->stat & PIC32_SPISTAT_SPITBF)) + { + spi_devices[dno].bus->buf = ~0; + nwritten--; + } + + if(!(spi_devices[dno].bus->stat & PIC32_SPISTAT_SPIRBE)) + { + *data16++ = mips_bswap(spi_devices[dno].bus->buf); + nread++; + } + } + spi_devices[dno].bus->con = spi_devices[dno].mode; +} + +void spi_bulk_read(int dno, unsigned int len, unsigned char *data) +{ + unsigned char *data8 = data; + unsigned int i; + unsigned char in,out; + + if(dno >= MAXSPIDEV) + return; + + if(spi_devices[dno].bus==NULL) + return; + + for(i=0; i> 2; + unsigned int nread; + unsigned int nwritten; + + if(dno >= MAXSPIDEV) + return; + + if(spi_devices[dno].bus==NULL) + return; + + nread = 0; + nwritten = words; + + spi_devices[dno].bus->conset = PIC32_SPICON_MODE32 | PIC32_SPICON_ENHBUF; + while(nread < words) + { + if(nwritten > 0 && !(spi_devices[dno].bus->stat & PIC32_SPISTAT_SPITBF)) + { + spi_devices[dno].bus->buf = *write32++; + nwritten--; + } + + if(!(spi_devices[dno].bus->stat & PIC32_SPISTAT_SPIRBE)) + { + *read32++ = mips_bswap(spi_devices[dno].bus->buf); + nread++; + } + } + spi_devices[dno].bus->con = spi_devices[dno].mode; +} + +void spi_bulk_rw_32(int dno, unsigned int len, char *data) +{ + int *read32 = (int *)data; + int *write32 = (int *)data; + unsigned int words = len >> 2; + unsigned int nread; + unsigned int nwritten; + + if(dno >= MAXSPIDEV) + return; + + if(spi_devices[dno].bus==NULL) + return; + + nread = 0; + nwritten = words; + + spi_devices[dno].bus->conset = PIC32_SPICON_MODE32 | PIC32_SPICON_ENHBUF; + while(nread < words) + { + if(nwritten > 0 && !(spi_devices[dno].bus->stat & PIC32_SPISTAT_SPITBF)) + { + spi_devices[dno].bus->buf = *write32++; + nwritten--; + } + + if(!(spi_devices[dno].bus->stat & PIC32_SPISTAT_SPIRBE)) + { + *read32++ = spi_devices[dno].bus->buf; + nread++; + } + } + spi_devices[dno].bus->con = spi_devices[dno].mode; +} + +void spi_bulk_rw_16(int dno, unsigned int len, char *data) +{ + short *read16 = (short *)data; + short *write16 = (short *)data; + unsigned int words = len >> 1; + unsigned int nread; + unsigned int nwritten; + + if(dno >= MAXSPIDEV) + return; + + if(spi_devices[dno].bus==NULL) + return; + + nread = 0; + nwritten = words; + + spi_devices[dno].bus->conset = PIC32_SPICON_MODE16 | PIC32_SPICON_ENHBUF; + while(nread < words) + { + if(nwritten > 0 && !(spi_devices[dno].bus->stat & PIC32_SPISTAT_SPITBF)) + { + spi_devices[dno].bus->buf = *write16++; + nwritten--; + } + + if(!(spi_devices[dno].bus->stat & PIC32_SPISTAT_SPIRBE)) + { + *read16++ = mips_bswap(spi_devices[dno].bus->buf); + nread++; + } + } + spi_devices[dno].bus->con = spi_devices[dno].mode; +} + +void spi_bulk_rw(int dno, unsigned int len, unsigned char *data) +{ + unsigned char *data8 = data; + unsigned int i; + unsigned char in,out; + + if(dno >= MAXSPIDEV) + return; + + if(spi_devices[dno].bus==NULL) + return; + + for(i=0; i= MAXSPIDEV) + return; + + if(spi_devices[dno].bus==NULL) + return; + + spi_devices[dno].baud = (BUS_KHZ / baud + 1) / 2 - 1; +} + +// Return the name of the SPI bus for a device + +char *spi_name(int dno) +{ + if(dno >= MAXSPIDEV) + return "SPI?"; + + if(spi_devices[dno].bus==NULL) + return "SPI?"; + + if(spi_devices[dno].bus == (struct spireg *)&SPI1CON) + return "SPI1"; + + if(spi_devices[dno].bus == (struct spireg *)&SPI2CON) + return "SPI2"; + + if(spi_devices[dno].bus == (struct spireg *)&SPI3CON) + return "SPI3"; + + if(spi_devices[dno].bus == (struct spireg *)&SPI4CON) + return "SPI4"; + + return "SPI?"; +} + +// Return the port name of the CS pin for a device +char spi_csname(int dno) +{ + if(dno >= MAXSPIDEV) + return '?'; + + if(spi_devices[dno].bus==NULL) + return '?'; + + switch((unsigned int)spi_devices[dno].cs_tris) + { + case (unsigned int)&TRISA: return 'A'; + case (unsigned int)&TRISB: return 'B'; + case (unsigned int)&TRISC: return 'C'; + case (unsigned int)&TRISD: return 'D'; + case (unsigned int)&TRISE: return 'E'; + case (unsigned int)&TRISF: return 'F'; + case (unsigned int)&TRISG: return 'G'; + } + return '?'; +} + +int spi_cspin(int dno) +{ + if(dno >= MAXSPIDEV) + return '?'; + + if(spi_devices[dno].bus==NULL) + return '?'; + + return spi_devices[dno].cs_pin; +} + +unsigned int spi_get_brg(int dno) +{ + if(dno >= MAXSPIDEV) + return 0; + + if(spi_devices[dno].bus==NULL) + return 0; + + return BUS_KHZ / (spi_devices[dno].baud + 1) / 2; +} diff --git a/sys/pic32/ssd1926-sdcard.c b/sys/pic32/ssd1926-sdcard.c new file mode 100644 index 0000000..3bc2260 --- /dev/null +++ b/sys/pic32/ssd1926-sdcard.c @@ -0,0 +1,854 @@ +/* + * SSD1926 hardware SD card driver + * + * Copyright (C) 2008 Microchip Technology Inc. All rights reserved. + * Microchip licenses to you the right to use, modify, copy and distribute + * Software only when embedded on a Microchip microcontroller or digital + * signal controller, which is integrated into your product or third party + * product (pursuant to the sublicense terms in the accompanying license + * agreement). + * + * You should refer to the license agreement accompanying this Software + * for additional information regarding your rights and obligations. + * + * SOFTWARE AND DOCUMENTATION ARE PROVIDED 'AS IS' WITHOUT WARRANTY OF ANY + * KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION, ANY WARRANTY + * OF MERCHANTABILITY, TITLE, NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR + * PURPOSE. IN NO EVENT SHALL MICROCHIP OR ITS LICENSORS BE LIABLE OR + * OBLIGATED UNDER CONTRACT, NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, + * BREACH OF WARRANTY, OR OTHER LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT + * DAMAGES OR EXPENSES INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, + * INDIRECT, PUNITIVE OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, + * COST OF PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY + * CLAIMS BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), + * OR OTHER SIMILAR COSTS. + * + * Author Date Comments + * ----------------------------------------------------- + * Sean Justice 15_Sept-2008 First release + * Anton Alkhimenok 06_Jun-2009 Ported to PIC24 + */ +#include "ssd1926.h" + +/* + * Helper Macros + */ +#define CheckDataInhibit() while(GetReg(0x1124) & 0x02) +#define CheckCommandInhibit() while(GetReg(0x1124) & 0x01) +#define GetDataPortReg0() GetReg(0x1120) +#define SetDataPortReg0(data) SetReg(0x1120, data) +#define SetTransferMode(mode) SetReg(0x110C, mode) + +/* + * Set graphics controller register (byte access) + */ +void SetReg(WORD index, BYTE value) +{ + DisplaySetCommand(); // set RS line to low for command + DisplayEnable(); // enable SSD1926 + + DeviceWrite(((WORD_VAL) index).v[1]); + DeviceWrite(index << 8); + + DisplaySetData(); // set RS line to high for data + + if(index & 0x0001) + DeviceWrite(value); + else + DeviceWrite(value << 8); + + DisplayDisable(); // disable SSD1926 +} + +/* + * Read graphics controller register value (byte access) + */ +BYTE GetReg(WORD index) +{ + WORD value; + + DisplaySetCommand(); // set RS line to low for command + DisplayEnable(); // enable SSD1926 + + DeviceWrite(((WORD_VAL) index).v[1]); + DeviceWrite(index << 8); + + DisplaySetData(); // set RS line to high for data + + value = DeviceRead(); + value = DeviceRead(); + + DisplayDisable(); // disable SSD1926 + + if(index & 0x0001) + value &= 0x00ff; + else + value = (value >> 8) & 0x00ff; + + return (value); +} + +/* + * Helper Functions + */ +inline void __attribute__ ((always_inline)) +SetCommandArgument(DWORD arg) +{ + SetReg(0x110B, ((DWORD_VAL) arg).v[3]); + SetReg(0x110A, ((DWORD_VAL) arg).v[2]); + SetReg(0x1109, ((DWORD_VAL) arg).v[1]); + SetReg(0x1108, ((DWORD_VAL) arg).v[0]); +} + +inline void __attribute__ ((always_inline)) +SetCommand(BYTE idx, BYTE flags) +{ + SetReg(0x110E, flags); //set response type + SetReg(0x110F, idx); //command index +} + +inline volatile DWORD __attribute__ ((always_inline)) +GetCommandResponse(BYTE idx) +{ + DWORD_VAL rsp; + + idx <<= 2; + + rsp.v[0] = GetReg(0x1110 + idx); + rsp.v[1] = GetReg(0x1111 + idx); + rsp.v[2] = GetReg(0x1112 + idx); + rsp.v[3] = GetReg(0x1113 + idx); + + return (rsp.Val); +} + +void ReadCmdResponse(DWORD *rsp, UINT size) +{ + DWORD idx; + for(idx = 0; idx < size; idx++) + { + *rsp = GetCommandResponse(idx); + rsp++; + } +} + +/* + * Global Variables + */ +DWORD finalLBA; +WORD sectorSize; +DWORD maxBusClock; +BYTE hcMode; +MEDIA_INFORMATION mediaInformation; + +/* + * Local Prototypes + */ +BYTE SDInit(void); +BYTE SDSetClock(DWORD clockMax); +BYTE SDSendCommand(BYTE cmd_idx, BYTE flags, DWORD arg); +BYTE SDSendAppCommand(BYTE cmd_idx, BYTE flags, DWORD arg1, DWORD arg2); +void SDReset(BYTE type); + +/* + * Function: + * BYTE SDSetClock(DWORD clockMax) + * Input: + * clockMax - SD card maximum frequency, + * Output: + * returns non-zero if the operation is successfull. + * Overview: + * Sets the SD card clock frequency close to clockMax + */ +BYTE SDSetClock(DWORD clockMax) +{ + DWORD mclk; + BYTE reg; + BYTE div; + + mclk = SSD_SYS_CLOCK * GetReg(SSD_REG_PLL_CONFIG1); + mclk /= (GetReg(SSD_REG_PLL_CONFIG0) & 0x1F); + mclk /= ((GetReg(SSD_REG_MCLK_CONIG) & 0x1F) + 1); + + if(GetReg(SSD_REG_MCLK_CONIG) & 0x01) + mclk /= 2; + + reg = GetReg(SSD_SDCARD_REG_CLK_CNTL); + + reg = reg &~((BYTE) SSD_SD_CLK_ENABLE); + SetReg(SSD_SDCARD_REG_CLK_CNTL, reg); + + reg |= SSD_SD_INT_CLK_ENABLE; + SetReg(SSD_SDCARD_REG_CLK_CNTL, reg); + + DelayMs(1); + if(!(GetReg(SSD_SDCARD_REG_CLK_CNTL) & SSD_SD_INT_CLK_STABLE)) + return (FALSE); + + div = 0; + while(mclk > clockMax) + { + mclk >>= 1; + div++; + } + + div = 1 << (div - 1); + + SetReg(SSD_SDCARD_REG_CLK_DIV, div); + + reg |= SSD_SD_CLK_ENABLE; + SetReg(SSD_SDCARD_REG_CLK_CNTL, reg); + + return (TRUE); +} + +/* + * Function: + * BYTE SDSendCommand(BYTE cmd_idx, BYTE flags, DWORD arg) + * Input: + * cmd_idx - command start index, + * flags - command flags, + * arg - command arguments. + * Output: + * Returns non-zero if the operation is successful + * Overview: + * Send SD card command. + */ +BYTE SDSendCommand(BYTE cmd_idx, BYTE flags, DWORD arg) +{ + DWORD timeout; + + SetReg(0x112E, 0x0E); // Data Timeout Counter Value = MCLK x 2^27 + CheckCommandInhibit(); + + // Clear interrupt flags + SetReg(0x1130, 0xff); + + // Enable command complete interrupt + SetReg(0x1134, GetReg(0x1134) | 0x01); + + // Clear error interrupt flags + SetReg(0x1132, 0xff); + SetReg(0x1133, 0xff); + + // Enable all interrupts + SetReg(0x1136, 0xff); + SetReg(0x1137, 0xff); + + SetCommandArgument(arg); + SetCommand(cmd_idx, flags); + + timeout = SD_TIMEOUT; + while(1) + { + if(GetReg(0x1130) & 0x01) + { + break; + } + + if(!timeout--) + { + return (FALSE); + } + } + + return (TRUE); +} + +/* + * Function: + * BYTE SDSendAppCommand(BYTE cmd_idx, BYTE flags, DWORD arg1, DWORD arg2) + * Input: + * cmd_idx - command start index, + * flags - command flags, + * arg1 - application command arguments 1 + * arg2 - application command arguments 2 + * Output: + * Returns non-zero if the operation is successful + * Overview: + * Send SD card application command. + */ +BYTE SDSendAppCommand(BYTE cmd_idx, BYTE flags, DWORD arg1, DWORD arg2) +{ + if(!SDSendCommand(CMD_APP_CMD, SSD_RESPONSE_48, arg1)) + return (FALSE); + + if(!SDSendCommand(cmd_idx, flags, arg2)) + return (FALSE); + + return (TRUE); +} + +/* + * Function: + * void SDReset(BYTE type) + * Input: + * type - type of reset. + * Overview: + * Resets the SD card module + */ +void SDReset(BYTE type) +{ + DWORD timeout; + + SetReg(SSD_SDCARD_REG_SW_RESET, type); + + timeout = SD_TIMEOUT; + while(1) + { + if(!timeout--) + return; + if(!(GetReg(SSD_SDCARD_REG_SW_RESET) & type)) + return; + } +} + +/* + * Function: + * void SDPower(BYTE on) + * Input: + * on - '0' means off, '1' means on. + * Overview: + * Powers on the SD card. + */ +void SDPower(BYTE on) +{ + if(on) + SetReg(SSD_SDCARD_REG_PWR_CNTL, 0x0F); + else + SetReg(SSD_SDCARD_REG_PWR_CNTL, 0x0E); +} + +/* + * Function: + * BYTE SDDetect(void) + * Output: + * TRUE - card detected, + * FALSE - no card detected. + * Overview: + * Detects if the SD card is inserted. + */ +BYTE SDDetect(void) +{ + BYTE reg; + + reg = GetReg(SSD_SDCARD_REG_PRSNT_STATE_2); + + if(!(reg & SSD_CARD_DETECT)) + return (FALSE); + + if(reg & SSD_CARD_INSERTED) + { + DWORD timeout; + + timeout = SD_TIMEOUT; + while(1) + { + if(!timeout--) + return (FALSE); + if(GetReg(SSD_SDCARD_REG_PRSNT_STATE_2) & SSD_CARD_STABLE) + break; + } + } + else + return (FALSE); + + return (TRUE); +} + +/* + * Function: + * BYTE SDWriteProtectState(void) + * Output: + * Returns the status of the "write enabled" pin. + * Overview: + * Determines if the card is write-protected. + */ +BYTE SDWriteProtectState(void) +{ + return (GetReg(SSD_SDCARD_REG_PRSNT_STATE_2) & SSD_WRITE_PROTECT); +} + +/* + * Function: + * BYTE SDInit(void) + * Output: + * Returns TRUE if media is initialized, FALSE otherwise. + * Overview: + * MediaInitialize initializes the media card and supporting variables. + */ +BYTE SDInit(void) +{ + DWORD timeout; + DWORD response; + DWORD voltage; + DWORD CSD_C_SIZE; + DWORD CSD_C_SIZE_MULT; + DWORD CSD_RD_BL_LEN; + DWORD RCA; + DWORD CSD[4]; + + if(!SDSendCommand(CMD_RESET, SSD_NO_RESPONSE, 0xFFFFFFFF)) + return (FALSE); + + + if(!SDSendCommand(CMD_SEND_IF_COND, SSD_RESPONSE_48 | SSD_CMD_CRC_CHK | SSD_CMD_IDX_CHK, 0x000001AA)) + return (FALSE); + + response = GetCommandResponse(0); + + if(response == 0x000001AA) + { + voltage = 0x40200000; + hcMode = 1; + }else{ + voltage = 0x00200000; + hcMode = 0; + } + + timeout = 10; + do + { + if(!timeout--) + { + return (FALSE); + } + + SDReset(SSD_RESET_DATA|SSD_RESET_CMD); + if(!SDSendAppCommand(ACMD_SEND_OCR, SSD_RESPONSE_48, 0, voltage)) + return (FALSE); // ask card send OCR back + DelayMs(150); + response = GetCommandResponse(0); + } while((response&0x80000000) == 0); + + if((response&0x40000000L) == 0){ + hcMode = 0; + } + + if(!SDSendCommand(CMD_SEND_ALL_CID, SSD_RESPONSE_136 | SSD_CMD_CRC_CHK, 0xFFFFFFFF)) + return (FALSE); + + DelayMs(150); + + if(!SDSendCommand(CMD_SEND_RCA, SSD_RESPONSE_48 | SSD_CMD_CRC_CHK | SSD_CMD_IDX_CHK, 0xFFFFFFFF)) + return (FALSE); + + RCA = GetCommandResponse(0); + RCA |= 0x0000ffff; + + //CMD9 - Request CSD from SD Card + if(!SDSendCommand(CMD_SEND_CSD, SSD_CMD_IDX_CHK | SSD_CMD_CRC_CHK | SSD_RESPONSE_136, RCA)) + return (FALSE); + + ReadCmdResponse(CSD, 4); + + CSD_C_SIZE = ((CSD[2] & 0x00000003) << 10) | ((CSD[1] & 0xFFC00000) >> 22); //CSD Bit[73:62] => Bit[65:54] (Deduct CRC-7 as CRC-7 is not stored in response register) + CSD_C_SIZE_MULT = ((CSD[1] & 0x00000380) >> 7); //CSD Bit[49:47] =? Bit[41:39] + CSD_RD_BL_LEN = (CSD[2] & 0x00000F00) >> 8; //CSD Bit[83:80] -> Bit[75:72] + finalLBA = (CSD_C_SIZE + 1) * (1 << (CSD_C_SIZE_MULT + 2)); + sectorSize = (1 << CSD_RD_BL_LEN); + if((CSD[3] & 0x000000FF) == 0x32) + maxBusClock = 25000000; // 25MHz + else + maxBusClock = 25000000; // 50MHz + SDReset(SSD_RESET_CMD); + + //CMD7 Select Card + if(!SDSendCommand(CMD_SELECT_CARD, SSD_RESPONSE_48_BUSY | SSD_CMD_CRC_CHK | SSD_CMD_IDX_CHK, RCA)) + return (FALSE); + + sectorSize = 512L; + + //CMD16 Set the block size. + if(!SDSendCommand(CMD_SET_BLKLEN, SSD_RESPONSE_48 | SSD_CMD_CRC_CHK | SSD_CMD_IDX_CHK, sectorSize)) + return (FALSE); + + //CMD55 + ACMD6 Set bus width = 4 Bit + if(!SDSendAppCommand(ACMD_SET_BUS_WIDTH, SSD_RESPONSE_48 | SSD_CMD_CRC_CHK | SSD_CMD_IDX_CHK, RCA, 0xFFFFFFFE)) + return (FALSE); + + //Data width 4bits + SetReg(0x1128, 0x02); + + return (TRUE); +} + +/* + * Function: + * INT32 SDGetStatus(void) + * Output: + * SD card status. + * Overview: + * Returns SD card status. If the returned value is -1 the there's an error. + */ +INT32 SDGetStatus(void) +{ + DWORD status; + DWORD RCA; + + SDReset(SSD_RESET_CMD); + + //Normal interrupt handling + SetReg(0x1134, GetReg(0x1134) | 0x01); //enable read interrupt + SetReg(0x1130, 0x01); //clear previous interrupt + + //Error interrupt handling + SetReg(0x1136, GetReg(0x1136) | 0x8F); //enable error interrupt + SetReg(0x1137, GetReg(0x1137) | 0x71); //enable error interrupt + SetReg(0x1132, 0x8F); //enable error interrupt + SetReg(0x1133, 0x71); //enable error interrupt + if(!SDSendCommand(CMD_SEND_RCA, SSD_RESPONSE_48 | SSD_CMD_CRC_CHK | SSD_CMD_IDX_CHK, 0xFFFFFFFF)) + return (DWORD) (-1); + + RCA = GetCommandResponse(0); + RCA |= 0x0000ffff; + + if(!SDSendCommand(CMD_SEND_STATUS, SSD_RESPONSE_48 | SSD_CMD_CRC_CHK | SSD_CMD_IDX_CHK, RCA)) + return (DWORD) (-1); + + while(!(GetReg(0x1130) & 0x01)); + + //check cmd complt int + SetReg(0x1130, 0x01); //clear previous int + while((GetReg(0x1132) & 0x8F) || (GetReg(0x1133) & 0x71)); + SetReg(0x1132, 0x8F); //enable error interrupt + SetReg(0x1133, 0x71); //enable error interrupt + ReadCmdResponse(&status, 1); + + return (status); +} + +/* + * Function: + * MEDIA_INFORMATION* SDInitialize(void) + * Output: + * Returns a pointer to the media inforamtion structure. + * Overview: + * SDInitialize initializes the media card and supporting variables. + * Sets maximum clock frequency for the SD card. + */ +MEDIA_INFORMATION *SDInitialize(void) +{ + DWORD timeout; + + SDReset(SSD_RESET_DATA | SSD_RESET_CMD | SSD_RESET_ALL); + + SDPower(TRUE); + + mediaInformation.errorCode = MEDIA_NO_ERROR; + mediaInformation.validityFlags.value = 0; + + if(!SDSetClock(SSD_SD_CLK_INIT)) + { + mediaInformation.errorCode = MEDIA_DEVICE_NOT_PRESENT; + return (&mediaInformation); + } + + timeout = 10; + while(!SDInit()) + { + if(!timeout--) + { + mediaInformation.errorCode = MEDIA_DEVICE_NOT_PRESENT; + return (&mediaInformation); + } + } + + mediaInformation.validityFlags.bits.sectorSize = 1; + mediaInformation.sectorSize = sectorSize; + + if(!SDSetClock(maxBusClock>>1)) + mediaInformation.errorCode = MEDIA_DEVICE_NOT_PRESENT; + + return (&mediaInformation); +} + +/* + * Function: BYTE SDSectorRead(DWORD sector_addr, BYTE *buffer) + * + * Input: sector_addr - Sector address + * buffer - Buffer where data will be stored, see + * 'ram_acs.h' for 'block' definition. + * 'Block' is dependent on whether internal or + * external memory is used + * + * Output: Returns TRUE if read successful, false otherwise + * + * Overview: SectorRead reads data from the card starting + * at the sector address specified by sector_addr and stores + * them in the location pointed to by 'buffer'. + * + * Note: The device expects the address field in the command packet + * to be byte address. Therefore the sector_addr must first + * be converted to byte address. + */ +BYTE SDSectorRead(DWORD sector_addr, BYTE *buffer) +{ + if(!hcMode) + { + sector_addr *= sectorSize; + } + + CheckDataInhibit(); + + SDReset(SSD_RESET_DATA); + + SetTransferMode(0x10); + + // Block size is one sector + SetReg(0x1104, ((WORD_VAL) sectorSize).v[0]); // write block size + SetReg(0x1105, ((WORD_VAL) sectorSize).v[1]); // write block size + + //Clear error interrupt flags + SetReg(0x1136, 0xff); + SetReg(0x1137, 0xff); + SetReg(0x1132, 0xff); + SetReg(0x1133, 0xff); + + // Buffer Read Ready, Transfer Complete, Command Complete interrupts enable + SetReg(0x1134, 0x23); + + // Clear previous interrupt flags + SetReg(0x1130, 0x23); + + // Send command + if + ( + !SDSendCommand + ( + CMD_RD_SINGLE, + SSD_RESPONSE_48 | SSD_DATA_PRESENT | SSD_CMD_CRC_CHK | SSD_CMD_IDX_CHK, + sector_addr + ) + ) return (FALSE); + + // Wait for transfer complete + while(!(GetReg(0x1130) & 0x20)); + + // Clear transfer complete flag + SetReg(0x1130, 0x20); + + // Read data + WORD counter = 0; + while(GetReg(0x1125) & 0x08) + { + if(counter < sectorSize) + *buffer++ = GetDataPortReg0(); + counter++; + } + + if(counter > sectorSize) + return (FALSE); + + return (TRUE); +} + +/* + * Function: + * BYTE SDSectorDMARead(DWORD sector_addr, DWORD dma_addr, UINT16 num_blk) + * Input: + * sector_addr - Sector address + * buffer - Buffer where data will be stored, see + * 'ram_acs.h' for 'block' definition. + * 'Block' is dependent on whether internal or + * external memory is used + * + * Output: + * Returns TRUE if read successful, false otherwise. + * Overview: SectorRead reads data from the card starting + * at the sector address specified by sector_addr and stores + * them in the location pointed to by 'buffer'. + * + * Note: The device expects the address field in the command packet + * to be byte address. Therefore the sector_addr must first + * be converted to byte address. + */ +BYTE SDSectorDMARead(DWORD sector_addr, DWORD dma_addr, UINT16 num_blk) +{ + DWORD dma_size; + BYTE boundary; + + if(!hcMode) + { + sector_addr *= sectorSize; + } + + CheckDataInhibit(); + SDReset(SSD_RESET_DATA); + + // set up the DMA address + SetReg(0x1100, ((DWORD_VAL) dma_addr).v[0]); + SetReg(0x1101, ((DWORD_VAL) dma_addr).v[1]); + SetReg(0x1102, ((DWORD_VAL) dma_addr).v[2]); + SetReg(0x1103, ((DWORD_VAL) dma_addr).v[3]); + + // set up the transefer mode (Multi-Blk, Read, Blk Cnt, DMA) + SetTransferMode(0x33); + + // set up the DMA buffer size (4k) and sector block size + dma_size = (DWORD) num_blk * sectorSize; + + dma_size >>= 12; + boundary = 0; + while(dma_size) + { + dma_size >>= 1; + boundary++; + } + + boundary <<= 4; + boundary |= ((WORD_VAL) sectorSize).v[1] & 0x0F; + + SetReg(0x1104, ((WORD_VAL) sectorSize).v[0]); // write block size + SetReg(0x1105, boundary); // write block size + + // Set the number of blocks to read + SetReg(0x1106, (BYTE) (num_blk & 0xFF)); // write block size + SetReg(0x1107, (BYTE) (num_blk >> 8)); // write block size + + // set up the normal status register 0 + SetReg(0x1134, 0x0B); // enable read interrupt + SetReg(0x1130, GetReg(0x1130) | 0x0B); // clear previous interrupt + + // set up the error status register + SetReg(0x1136, 0xFF); // clear previous interrupt + SetReg(0x1132, 0xFF); // clear previous interrupt + SetReg(0x1133, 0x01); // clear previous interrupt + SetReg(0x1130, 0x08); // clear previous interrupt + + // set the command to read multiple blocks + if + ( + !SDSendCommand + ( + CMD_RD_MULTIPLE, + SSD_RESPONSE_48 | SSD_DATA_PRESENT | SSD_CMD_CRC_CHK | SSD_CMD_IDX_CHK, + sector_addr + ) + ) return (FALSE); + + // wait until the dma transfer is done + while(!(GetReg(0x1130) & 0x08) && (GetReg(0x1125) & 0x02)); + SetReg(0x1130, 0x08); + + // stop the transmission + if + ( + !SDSendCommand + ( + CMD_STOP_TRANSMISSION, + SSD_CMD_TYPE_ABORT | SSD_RESPONSE_48_BUSY | SSD_CMD_CRC_CHK | SSD_CMD_IDX_CHK, + 0xFFFFFFFF + ) + ) return (FALSE); + SetReg(0x1130, 0x01); //clear previous interrupt + SetReg(0x1106, 0); // write block size + SetReg(0x1107, 0); // write block size + + // disable the transfer mode + SetTransferMode(0); + + return (TRUE); +} + +/* + * Function: BYTE SDSectorWrite(DWORD sector_addr, BYTE *buffer, BYTE allowWriteToZero) + * + * Input: sector_addr - Sector address + * buffer - Buffer where data will be read + * allowWriteToZero - If true, writes to the MBR will be valid + * + * Output: Returns TRUE if write successful, FALSE otherwise + * + * Overview: SectorWrite sends data from the location + * pointed to by 'buffer' to the card starting + * at the sector address specified by sector_addr. + * + * Note: The sample device expects the address field in the command packet + * to be byte address. Therefore the sector_addr must first + * be converted to byte address. + */ +BYTE SDSectorWrite(DWORD sector_addr, BYTE *buffer, BYTE allowWriteToZero) +{ + UINT16 i; + + if(!hcMode) + { + sector_addr *= sectorSize; + } + + CheckDataInhibit(); + SDReset(SSD_RESET_DATA); + SetTransferMode(0); + + SetReg(0x1104, ((WORD_VAL) sectorSize).v[0]); // write block size + SetReg(0x1105, ((WORD_VAL) sectorSize).v[1]); // write block size + + //Clear error interrupt flags + SetReg(0x1136, 0xff); + SetReg(0x1137, 0xff); + SetReg(0x1132, 0xff); + SetReg(0x1133, 0xff); + + //Normal interrupt handling + SetReg(0x1134, 0x13); //enable write interrupt + SetReg(0x1130, 0x13); //clear all type of normal interrupt + + if + ( + !SDSendCommand + ( + CMD_WR_SINGLE, + SSD_RESPONSE_48 | SSD_DATA_PRESENT | SSD_CMD_CRC_CHK | SSD_CMD_IDX_CHK, + sector_addr + ) + ) return (FALSE); + + SetReg(0x1130, 0x01); //clear previous interrupt + while(!(GetReg(0x1130)&0x10) && !(GetReg(0x1125) & 0x04)); //check Buffer write int + SetReg(0x1130, 0x10); //clear previous interrupt + + for(i = 0; i < sectorSize; i++) + { + //check if Write Enable bit set, which mean buffer is free for new data + while(!(GetReg(0x1125) & 0x04)); + //put data that need be written into SSD1928 buffers + SetDataPortReg0(*buffer++); + } + + SetReg(0x1130, 0x10); //clear previous interrupt + while(!(GetReg(0x1130)&0x02)); //check Transfer complt int + SetReg(0x1130, 0x02); // clear previous interrupt + + return (TRUE); +} + +/* + * Function: + * WORD SDReadSectorSize(void) + * PreCondition: + * MediaInitialize() is complete + * Output: + * Size of the sectors for this physical media. + * Overview: + * Returns size of the sectors for this physical media. + */ +WORD SDReadSectorSize(void) +{ + return (sectorSize); +} + +/* + * Function: + * DWORD SDReadCapacity(void) + * PreCondition: + * MediaInitialize() is complete + * Output: + * Number of sectors. + * Overview: + * Returns number of sectors. + */ +DWORD SDReadCapacity(void) +{ + return (finalLBA); +} diff --git a/sys/pic32/ssd1926.h b/sys/pic32/ssd1926.h new file mode 100644 index 0000000..2dadea2 --- /dev/null +++ b/sys/pic32/ssd1926.h @@ -0,0 +1,157 @@ +/* + * SSD1926 hardware definitions + * + * Copyright (C) 2008 Microchip Technology Inc. All rights reserved. + * Microchip licenses to you the right to use, modify, copy and distribute + * Software only when embedded on a Microchip microcontroller or digital + * signal controller, which is integrated into your product or third party + * product (pursuant to the sublicense terms in the accompanying license + * agreement). + * + * You should refer to the license agreement accompanying this Software + * for additional information regarding your rights and obligations. + * + * SOFTWARE AND DOCUMENTATION ARE PROVIDED 'AS IS' WITHOUT WARRANTY OF ANY + * KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION, ANY WARRANTY + * OF MERCHANTABILITY, TITLE, NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR + * PURPOSE. IN NO EVENT SHALL MICROCHIP OR ITS LICENSORS BE LIABLE OR + * OBLIGATED UNDER CONTRACT, NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, + * BREACH OF WARRANTY, OR OTHER LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT + * DAMAGES OR EXPENSES INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, + * INDIRECT, PUNITIVE OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, + * COST OF PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY + * CLAIMS BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), + * OR OTHER SIMILAR COSTS. + * + * Author Date Comments + * ----------------------------------------------------- + * Sean Justice 15_Sept-2008 First release + * Anton Alkhimenok 06_Jun-2009 Ported to PIC24 + */ +#ifndef _SSD1926_H + +#define _SSD1926_H + +/* + * User Defines + */ +#define SSD_SYS_CLOCK (DWORD) (4000000) /* SSD1926 crystal frequncy */ +#define SSD_SD_CLK_INIT (DWORD) (400000) +#define SD_TIMEOUT (DWORD) (3000000) + +/* + * Registers + */ +#define SSD_REG_PLL_CONFIG0 0x0126 +#define SSD_REG_PLL_CONFIG1 0x0127 +#define SSD_REG_MCLK_CONIG 0x0004 +#define SSD_SDCARD_SD_CLK 0x1001 +#define SSD_SDCARD_REG_DMA_ADDR 0x1100 +#define SSD_SDCARD_REG_BLK_SIZE 0x1104 +#define SSD_SDCARD_REG_BLK_CNT 0x1106 +#define SSD_SDCARD_REG_ARG_32BIT 0x1108 +#define SSD_SDCARD_REG_XFR_MODE 0x110c +#define SSD_SDCARD_REG_CMD 0x110e +#define SSD_SDCARD_REG_RSP 0x1110 +#define SSD_SDCARD_REG_DATA_PORT 0x1120 +#define SSD_SDCARD_REG_RSVD1 0x1121 +#define SSD_SDCARD_REG_PRSNT_STATE_0 0x1124 +#define SSD_SDCARD_REG_PRSNT_STATE_1 0x1125 +#define SSD_SDCARD_REG_PRSNT_STATE_2 0x1126 +#define SSD_SDCARD_REG_PRSNT_STATE_3 0x1127 +#define SSD_SDCARD_REG_HST_CNTL 0x1128 +#define SSD_SDCARD_REG_PWR_CNTL 0x1129 +#define SSD_SDCARD_REG_BLK_GAP_CNTL 0x112a +#define SSD_SDCARD_REG_WKUP_CNTL 0x112b +#define SSD_SDCARD_REG_CLK_CNTL 0x112c +#define SSD_SDCARD_REG_CLK_DIV 0x112d +#define SSD_SDCARD_REG_TOUT_CNTL 0x112e +#define SSD_SDCARD_REG_SW_RESET 0x112f +#define SSD_SDCARD_REG_NRM_INTR_STATUS 0x1130 +#define SSD_SDCARD_REG_ERR_INTR_STATUS 0x1132 +#define SSD_SDCARD_REG_NRM_INTR_STATUS_EN 0x1134 +#define SSD_SDCARD_REG_ERR_INTR_STATUS_EN 0x1136 +#define SSD_SDCARD_REG_NRM_INTR_SIG_EN 0x1138 +#define SSD_SDCARD_REG_ERR_INTR_SIG_EN 0x113a +#define SSD_SDCARD_REG_ACMD12_ERR_STATUS 0x113c +#define SSD_SDCARD_REG_RSVD2 0x113e +#define SSD_SDCARD_REG_CAPABILITIES 0x1140 +#define SSD_SDCARD_REG_CAP_RSVD 0x1144 +#define SSD_SDCARD_REG_MAX_CURR_CAP 0x1148 +#define SSD_SDCARD_REG_MAX_CURR_CAP_RSVD 0x114c +#define SSD_SDCARD_REG_RSVD3 0x1150 +#define SSD_SDCARD_REG_SLOT_INTR_STATUS 0x11fc +#define SSD_SDCARD_REG_HCVER 0x11fe + +/* + * SD Commands + */ +#define CMD_RESET 0 +#define CMD_SEND_OCR 1 // used exclusively in MMC +#define CMD_SEND_ALL_CID 2 // R2: R136 +#define CMD_SEND_RCA 3 // R1 (MMC) or R6(SDMEM) +#define CMD_SET_DSR 4 +#define CMD_IO_SEND_OCR 5 // R4, unique to IO cards +#define CMD_SELECT_CARD 7 // R1, arg=rca[31..16] or 0 +#define CMD_SEND_IF_COND 8 +#define CMD_SEND_CSD 9 // R2: R136 +#define CMD_SEND_CID 10 // R2: R136 +#define CMD_STOP_TRANSMISSION 12 // R1b: arg=stuff bits +#define CMD_SEND_STATUS 13 // R1 +#define CMD_GO_INACTIVE 15 // None, arg=rca[31..16], stuff[15..0] +#define CMD_SET_BLKLEN 16 // R1, arg=block len[31..0] +#define CMD_RD_SINGLE 17 // R1, arg=block address[31..0] +#define CMD_RD_MULTIPLE 18 // R1, arg=block address[31..0] +#define CMD_WR_SINGLE 24 // R1, arg=block address[31..0] +#define CMD_WR_MULTIPLE 25 // R1, arg=block address[31..0] +#define CMD_SET_WP 28 // R1b, arg=wp address[31..0] +#define CMD_CLR_WP 29 // R1b, arg=wp address[31..0] +#define CMD_SEND_WP 30 // R1, DATA, arg=wp address[31..0] +#define CMD_ERASE_SADDR 32 // R1, arg=block address[31..0] +#define CMD_ERASE_EADDR 33 // R1, arg=block address[31..0] +#define CMD_ERASE_GRP_SADDR 35 // R1, arg=block address[31..0] +#define CMD_ERASE_GRP_EADDR 36 // R1, arg=block address[31..0] +#define CMD_ERASE 38 // R1b, arg=stuff bits[31..0] +#define CMD_IO_RW_DIRECT 52 // R5 +#define CMD_IO_RW_EXTENDED 53 // R1, data transfer +#define CMD_APP_CMD 55 // R1, arg=rca[31..16], stuff[15..0] +#define CMD_GEN_CMD 56 // R1, data, arg=stuff[31..1], RD/WR[0] +#define ACMD_SET_BUS_WIDTH 6 // R1, arg=[1..0] = bus width, [31:2] stuff bits +#define ACMD_SEND_STATUS 13 // R1, DATA, arg=stuff bits [31..0] +#define ACMD_SEND_NUM_WR_BLK 22 // R1, DATA, arg=stuff bits [31..0] +#define ACMD_SEND_OCR 41 +#define ACMD_SEND_SCR 51 // R1, arg=stuff bits[31..0] + +/* + * Flags + */ +#define SSD_SD_CLK_CTRL_ON (DWORD) 0x80000000 +#define SSD_SD_CLK_ENABLE (DWORD) 0x00000004 +#define SSD_SD_INT_CLK_STABLE (DWORD) 0x00000002 +#define SSD_SD_INT_CLK_ENABLE (DWORD) 0x00000001 +#define SSD_SD_CLK_FLAGS (SSD_SD_CLK_CTRL_ON | SSD_SD_CLK_ENABLE | SSD_SD_INT_CLK_ENABLE) +#define SSD_CMD_TYPE_ABORT 0xC0 +#define SDD_CMD_TYPE_RESUME 0x80 +#define SDD_CMD_TYPE_SUSPEND 0x40 +#define SDD_CMD_TYPE_NORMAL 0x00 +#define SSD_DATA_PRESENT 0x20 +#define SSD_CMD_IDX_CHK 0x10 +#define SSD_CMD_CRC_CHK 0x08 +#define SSD_NO_RESPONSE 0x00 +#define SSD_RESPONSE_136 0x01 +#define SSD_RESPONSE_48 0x02 +#define SSD_RESPONSE_48_BUSY 0x03 + +#define SSD_CARD_DETECT 0x04 +#define SSD_CARD_STABLE 0x02 +#define SSD_CARD_INSERTED 0x01 + +#define SSD_WRITE_PROTECT 0x08 + +#define SSD_RESET_ALL 0x01 +#define SSD_RESET_CMD 0x02 +#define SSD_RESET_DATA 0x04 + +#define WAIT_CNT (DWORD) 10000000l + +#endif /* _SSD1926_H */ diff --git a/sys/pic32/starter-kit/Makefile b/sys/pic32/starter-kit/Makefile new file mode 100644 index 0000000..c49714c --- /dev/null +++ b/sys/pic32/starter-kit/Makefile @@ -0,0 +1,84 @@ +BUILDPATH = ../../../tools/configsys/../../sys/pic32 +H = ../../../tools/configsys/../../sys/include +M = ../../../tools/configsys/../../sys/pic32 +S = ../../../tools/configsys/../../sys/kernel + +vpath %.c $(M):$(S) +vpath %.S $(M):$(S) + +KERNOBJ += _startup.o adc.o clock.o cons.o devsw.o exception.o gpio.o init_main.o init_sysent.o kern_clock.o kern_descrip.o kern_exec.o kern_exit.o kern_fork.o kern_mman.o kern_proc.o kern_prot.o kern_prot2.o kern_resource.o kern_sig.o kern_sig2.o kern_subr.o kern_synch.o kern_sysctl.o kern_time.o machdep.o mem.o rd_sd.o rdisk.o signal.o spi_bus.o subr_prf.o subr_rmap.o swap.o sys_generic.o sys_inode.o sys_pipe.o sys_process.o syscalls.o sysctl.o tty.o tty_subr.o tty_tty.o ufs_alloc.o ufs_bio.o ufs_bmap.o ufs_dsort.o ufs_fio.o ufs_inode.o ufs_mount.o ufs_namei.o ufs_subr.o ufs_syscalls.o ufs_syscalls2.o usb_device.o usb_function_cdc.o usb_uart.o vers.o vfs_vnops.o vm_sched.o vm_swap.o vm_swp.o +EXTRA_TARGETS = bootloader + +DEFS += -DADC_ENABLED=YES +DEFS += -DBL_BUTTON_PIN=6 +DEFS += -DBL_BUTTON_PORT=TRISD +DEFS += -DBL_LED2_INVERT +DEFS += -DBL_LED2_PIN=1 +DEFS += -DBL_LED2_PORT=TRISD +DEFS += -DBL_LED3_INVERT +DEFS += -DBL_LED3_PIN=2 +DEFS += -DBL_LED3_PORT=TRISD +DEFS += -DBL_LED_PIN=0 +DEFS += -DBL_LED_PORT=TRISD +DEFS += -DBUS_DIV=1 +DEFS += -DBUS_KHZ='CPU_KHZ/BUS_DIV' +DEFS += -DCONSOLE_DEVICE=ttyUSB0 +DEFS += -DCPU_IDIV=2 +DEFS += -DCPU_KHZ='((CRYSTAL*1000)/CPU_IDIV*CPU_MUL/CPU_ODIV)' +DEFS += -DCPU_MUL=20 +DEFS += -DCPU_ODIV=1 +DEFS += -DCRYSTAL=8 +DEFS += -DDC0_DEBUG=DEVCFG0_DEBUG_DISABLED +DEFS += -DDC0_ICE=0 +DEFS += -DDC1_CKM=0 +DEFS += -DDC1_CKS=0 +DEFS += -DDC1_FNOSC=DEVCFG1_FNOSC_PRIPLL +DEFS += -DDC1_IESO=DEVCFG1_IESO +DEFS += -DDC1_OSCIOFNC=0 +DEFS += -DDC1_PBDIV=DEVCFG1_FPBDIV_1 +DEFS += -DDC1_POSCMOD=DEVCFG1_POSCMOD_HS +DEFS += -DDC1_SOSC=0 +DEFS += -DDC1_WDTEN=0 +DEFS += -DDC1_WDTPS=DEVCFG1_WDTPS_1 +DEFS += -DDC2_PLLIDIV=DEVCFG2_FPLLIDIV_2 +DEFS += -DDC2_PLLMUL=DEVCFG2_FPLLMUL_20 +DEFS += -DDC2_PLLODIV=DEVCFG2_FPLLODIV_1 +DEFS += -DDC2_UPLL=0 +DEFS += -DDC2_UPLLIDIV=DEVCFG2_UPLLIDIV_2 +DEFS += -DDC3_CAN=DEVCFG3_FCANIO +DEFS += -DDC3_ETH=DEVCFG3_FETHIO +DEFS += -DDC3_MII=DEVCFG3_FMIIEN +DEFS += -DDC3_SRS=DEVCFG3_FSRSSEL_7 +DEFS += -DDC3_USBID=DEVCFG3_FUSBIDIO +DEFS += -DDC3_USERID=0xffff +DEFS += -DDC3_VBUSON=DEVCFG3_FVBUSONIO +DEFS += -DFLASH_JUMP=0x9d000000 +DEFS += -DGPIO_ENABLED=YES +DEFS += -DHID_FEATURE_REPORT_BYTES=2 +DEFS += -DHID_INPUT_REPORT_BYTES=2 +DEFS += -DHID_INT_IN_EP_SIZE=64 +DEFS += -DHID_INT_OUT_EP_SIZE=64 +DEFS += -DHID_OUTPUT_REPORT_BYTES=2 +DEFS += -DHID_RPT01_SIZE=29 +DEFS += -DKERNEL +DEFS += -DLED_DISK_PIN=1 +DEFS += -DLED_DISK_PORT=TRISD +DEFS += -DLED_KERNEL_PIN=2 +DEFS += -DLED_KERNEL_PORT=TRISD +DEFS += -DPIC32MX7 +DEFS += -DSD0_CS_PIN=1 +DEFS += -DSD0_CS_PORT=TRISB +DEFS += -DSD0_PORT=1 +DEFS += -DUARTUSB_ENABLED=YES +DEFS += -DUCB_METER +DEFS += -DUSB_EP0_BUFF_SIZE=8 +DEFS += -DUSB_MAX_EP_NUMBER=3 +DEFS += -DUSB_NUM_STRING_DESCRIPTORS=3 + + +LDSCRIPT = ../../../tools/configsys/../../sys/pic32/cfg/bootloader.ld + +CONFIG = STARTER-KIT +CONFIGPATH = ../../../tools/configsys + +include ../../../tools/configsys/../../sys/pic32/kernel-post.mk diff --git a/sys/pic32/starter-kit/STARTER-KIT b/sys/pic32/starter-kit/STARTER-KIT new file mode 100644 index 0000000..3100146 --- /dev/null +++ b/sys/pic32/starter-kit/STARTER-KIT @@ -0,0 +1,23 @@ +# +# Ethernet/USB Starter Kit with I/O Expansion board +# ================================================= +# +# Console on USB +# For Windows, use the driver: http://www.schmalzhaus.com/UBW32/FW/UBW32inf.zip + +core pic32mx7 +linker bootloader +mapping generic + +device kernel led=D2 + +device console device=ttyUSB0 +device uartusb + +device rdisk led=D1 +device sd0 port=1 cs=B1 + +device gpio +device adc + +device bootloader button=D6 jump=0x9d000000 led=D0 invled2=D1 invled3=D2 diff --git a/sys/pic32/starter-kit/using-bootloader.ld b/sys/pic32/starter-kit/using-bootloader.ld new file mode 100644 index 0000000..8d2d334 --- /dev/null +++ b/sys/pic32/starter-kit/using-bootloader.ld @@ -0,0 +1,114 @@ +/* + * Linker script for PIC32 firmware using RetroBSD bootloader. + */ +OUTPUT_FORMAT("elf32-littlemips", "elf32-bigmips", + "elf32-littlemips") +OUTPUT_ARCH(mips) +ENTRY(_reset_vector_) +MEMORY +{ + flash (rx) : ORIGIN = 0x9d000000, LENGTH = 512K + ram (rw!x): ORIGIN = 0x80000000, LENGTH = 26K + u0area (rw!x): ORIGIN = 0x80006800, LENGTH = 3K + uarea (rw!x): ORIGIN = 0x80007400, LENGTH = 3K + + /* Required by Microchip C32 linker */ + kseg0_program_mem (rx) : ORIGIN = 0x9D000000, LENGTH = 0x80000 + kseg0_boot_mem : ORIGIN = 0x9FC00000, LENGTH = 0x1000 + exception_mem : ORIGIN = 0x9FC00000, LENGTH = 0x1000 + kseg1_boot_mem : ORIGIN = 0xBFC00000, LENGTH = 0 + kseg1_data_mem (w!x) : ORIGIN = 0xA0000000, LENGTH = 0x20000 +} + +/* higher address of the user mode stack */ +u0 = ORIGIN(u0area); +u = ORIGIN(uarea); +u_end = ORIGIN(uarea) + LENGTH(uarea); + +SECTIONS +{ + .text ORIGIN(flash) : + { + /* Exception handlers. */ + *(.exception) + /* Execution starts here. */ + *(.startup) + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.glue_7t) *(.glue_7) + __rodata_start = . ; + *(.rodata .rodata.* .gnu.linkonce.r.* .rel.dyn) + *(.dinit) + /* Align here to ensure that the .text section ends on word boundary. */ + . = ALIGN (32 / 8); + _etext = .; + } > flash + + /* Start data (internal SRAM). */ + .data : AT (ADDR (.text) + SIZEOF (.text)) + { + __data_start = . ; + _gp = .; /* We use only 32k RAM for kernel, so no need for 0x8000 offset. */ + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + *(.sdata .sdata.* .gnu.linkonce.s.*) + *(.data .data.* .gnu.linkonce.d.*) + *(.eh_frame) + _edata = .; + } > ram + + .bss ADDR (.data) + SIZEOF (.data) (NOLOAD) : + { + __bss_start = .; + *(.dynbss) + *(.sbss .sbss.*) + *(.scommon) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. */ + . = ALIGN (32 / 8); + } > ram + __bss_end = . ; + _end = .; + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + .debug_pubtypes 0 : { *(.debug_pubtypes) } + .debug_ranges 0 : { *(.debug_ranges) } + .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) } +} diff --git a/sys/pic32/startup.S b/sys/pic32/startup.S new file mode 100644 index 0000000..dddbdee --- /dev/null +++ b/sys/pic32/startup.S @@ -0,0 +1,405 @@ +# +# Startup code for Microchip PIC32 microcontrollers. +# Using HID bootloader. +# +# Copyright (C) 2010 Serge Vakulenko, +# +# 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 the copyright notice and this +# permission notice and warranty disclaimer appear in supporting +# documentation, and that the name of the author not be used in +# advertising or publicity pertaining to distribution of the +# software without specific, written prior permission. +# +# The author disclaim all warranties with regard to this +# software, including all implied warranties of merchantability +# and fitness. In no event shall the author 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. +# +#include "machine/io.h" + +#define UBASE 0x7f008000 /* User space base address */ + + .set noreorder + .set mips32r2 + .set nomips16 + + .extern u + .extern u_end + .extern u0 + .extern main + .extern exception + +#--------------------------------------- +# Reset vector: main entry point +# + .section .startup,"ax",@progbits + .org 0 + .type _reset_vector_, @function +_reset_vector_: .globl _reset_vector_ + + .set noat + move $1, $zero # Clear all regs + move $2, $zero + move $3, $zero + move $4, $zero + move $5, $zero + move $6, $zero + move $7, $zero + move $8, $zero + move $9, $zero + move $10, $zero + move $11, $zero + move $12, $zero + move $13, $zero + move $14, $zero + move $15, $zero + move $16, $zero + move $17, $zero + move $18, $zero + move $19, $zero + move $20, $zero + move $21, $zero + move $22, $zero + move $23, $zero + move $24, $zero + move $25, $zero + move $26, $zero + move $27, $zero + move $28, $zero + move $29, $zero + move $30, $zero + move $31, $zero + mtlo $zero + mthi $zero + .set at + + la $sp, u_end - 16 # Stack at end of U area + la $a0, main + jalr $a0 # Jump to main() + lui $gp, 0x8000 # Set global pointer (delay slot) + + la $k0, UBASE + mtc0 $k0, $C0_EPC # Entry to user code. + + mfc0 $k0, $C0_STATUS + ori $k0, $k0, ST_UM | ST_EXL | ST_IE # Set user mode and enable interrupts + mtc0 $k0, $C0_STATUS # Put SR back + ehb + eret # PC <= EPC; EXL <= 0 + nop # just to be safe + + +#--------------------------------------- +# Secondary entry point for RetroBSD bootloader. +# + .section .exception,"ax",@progbits +_exception_base_: .globl _exception_base_ + + .org 0 + .type _entry_vector_, @function +_entry_vector_: .globl _entry_vector_ + la $k0, _reset_vector_ + jr $k0 + nop + +#--------------------------------------- +# Exception vector: handle interrupts and exceptions +# + .org 0x200 + .type _exception_vector_, @function +_exception_vector_: .globl _exception_vector_ + + mfc0 $k0, $C0_STATUS + andi $k1, $k0, ST_UM # Check user mode + beqz $k1, kernel_exception + move $k1, $sp + + # + # Exception in user mode: switch stack. + # +user_exception: + la $sp, u_end # Stack at end of U area +kernel_exception: + addi $sp, -16-FRAME_WORDS*4 # Allocate space for registers +save_regs: + sw $k0, (16+FRAME_STATUS*4) ($sp) + sw $k1, (16+FRAME_SP*4) ($sp) + + .set noat + sw $1, (16+FRAME_R1*4) ($sp) # Save general registers + sw $2, (16+FRAME_R2*4) ($sp) + sw $3, (16+FRAME_R3*4) ($sp) + sw $4, (16+FRAME_R4*4) ($sp) + sw $5, (16+FRAME_R5*4) ($sp) + sw $6, (16+FRAME_R6*4) ($sp) + sw $7, (16+FRAME_R7*4) ($sp) + sw $8, (16+FRAME_R8*4) ($sp) + sw $9, (16+FRAME_R9*4) ($sp) + sw $10, (16+FRAME_R10*4) ($sp) + sw $11, (16+FRAME_R11*4) ($sp) + sw $12, (16+FRAME_R12*4) ($sp) + sw $13, (16+FRAME_R13*4) ($sp) + sw $14, (16+FRAME_R14*4) ($sp) + sw $15, (16+FRAME_R15*4) ($sp) + sw $16, (16+FRAME_R16*4) ($sp) + sw $17, (16+FRAME_R17*4) ($sp) + sw $18, (16+FRAME_R18*4) ($sp) + sw $19, (16+FRAME_R19*4) ($sp) + sw $20, (16+FRAME_R20*4) ($sp) + sw $21, (16+FRAME_R21*4) ($sp) + sw $22, (16+FRAME_R22*4) ($sp) + sw $23, (16+FRAME_R23*4) ($sp) + sw $24, (16+FRAME_R24*4) ($sp) + sw $25, (16+FRAME_R25*4) ($sp) + # Skip $26 - K0 + # Skip $27 - K1 + sw $28, (16+FRAME_GP*4) ($sp) + # Skip $29 - SP + sw $30, (16+FRAME_FP*4) ($sp) + sw $31, (16+FRAME_RA*4) ($sp) + .set at + + mfhi $k0 # Save special registers + sw $k0, (16+FRAME_HI*4) ($sp) + + mflo $k0 + sw $k0, (16+FRAME_LO*4) ($sp) + + mfc0 $k0, $C0_EPC + sw $k0, (16+FRAME_PC*4) ($sp) + + move $a0, $sp + addi $a0, 16 # Arg 0: saved regs. + jal exception # Call C code. + lui $gp, 0x8000 # Set global pointer (delay slot) + + # + # Restore CPU state and return from interrupt. + # +restore_regs: + lw $a0, (16+FRAME_LO*4) ($sp) # Load HI, LO registers + mtlo $a0 + lw $a0, (16+FRAME_HI*4) ($sp) + mthi $a0 + + .set noat + lw $1, (16+FRAME_R1*4) ($sp) # Load general registers + lw $2, (16+FRAME_R2*4) ($sp) + lw $3, (16+FRAME_R3*4) ($sp) + lw $4, (16+FRAME_R4*4) ($sp) + lw $5, (16+FRAME_R5*4) ($sp) + lw $6, (16+FRAME_R6*4) ($sp) + lw $7, (16+FRAME_R7*4) ($sp) + lw $8, (16+FRAME_R8*4) ($sp) + lw $9, (16+FRAME_R9*4) ($sp) + lw $10, (16+FRAME_R10*4) ($sp) + lw $11, (16+FRAME_R11*4) ($sp) + lw $12, (16+FRAME_R12*4) ($sp) + lw $13, (16+FRAME_R13*4) ($sp) + lw $14, (16+FRAME_R14*4) ($sp) + lw $15, (16+FRAME_R15*4) ($sp) + lw $16, (16+FRAME_R16*4) ($sp) + lw $17, (16+FRAME_R17*4) ($sp) + lw $18, (16+FRAME_R18*4) ($sp) + lw $19, (16+FRAME_R19*4) ($sp) + lw $20, (16+FRAME_R20*4) ($sp) + lw $21, (16+FRAME_R21*4) ($sp) + lw $22, (16+FRAME_R22*4) ($sp) + lw $23, (16+FRAME_R23*4) ($sp) + lw $24, (16+FRAME_R24*4) ($sp) + lw $25, (16+FRAME_R25*4) ($sp) + # Skip $26 - K0 + # Skip $27 - K1 + lw $28, (16+FRAME_GP*4) ($sp) + # Skip $29 - SP + lw $30, (16+FRAME_FP*4) ($sp) + .set at + + # Do not use k0/k1 here, as interrupts are still enabled + lw $31, (16+FRAME_STATUS*4) ($sp) # K0 = saved status + ori $31, ST_EXL # Set EXL + mtc0 $31, $C0_STATUS # put SR back: disable interrupts + ehb + + lw $k0, (16+FRAME_PC*4) ($sp) # K0 = EPC + mtc0 $k0, $C0_EPC # put PC in EPC + ext $k1, $31, 27, 1 # get RP bit: single-step request + + lw $31, (16+FRAME_RA*4) ($sp) + lw $sp, (16+FRAME_SP*4) ($sp) # Restore stack + + # Return from exception + bnez $k1, debug_request # single-step request + ehb + eret # PC <= EPC; EXL <= 0 +debug_request: + sdbbp # enter debug mode + +#--------------------------------------- +# Debug exception processing. +# + .org 0x480 + .type _debug_vector_, @function +_debug_vector_: .globl _debug_vector_ + + mfc0 $k0, $C0_DEPC + la $k1, debug_request + bne $k0, $k1, single_step_done + nop + + # single step request + mfc0 $k0, $C0_DEBUG + ori $k0, DB_SST # set SST bit + mtc0 $k0, $C0_DEBUG + + mfc0 $k1, $C0_EPC + mtc0 $k1, $C0_DEPC # DEPC <= EPC + mfc0 $k0, $C0_STATUS + xori $k0, ST_EXL # Clear EXL + mtc0 $k0, $C0_STATUS + ehb + deret # PC <= DEPC; DM <= 0 + +single_step_done: + mtc0 $k0, $C0_EPC # EPC <= DEPC + + la $k1, _exception_vector_ + mtc0 $k1, $C0_DEPC # DEPC <= exception handler + + mfc0 $k0, $C0_DEBUG + sw $k0, c0_debug # save Debug register + ori $k0, DB_SST + xori $k0, DB_SST # clear SST bit + mtc0 $k0, $C0_DEBUG + + mfc0 $k1, $C0_STATUS + ori $k1, ST_EXL # Set EXL + mtc0 $k1, $C0_STATUS + ehb + deret # PC <= DEPC; DM <= 0 + +#--------------------------------------- +# Icode is copied out to process 1 to exec /sbin/init. +# If the exec fails, process 1 exits. +# + .globl icode, icodeend + .type icode, @function + .type icodeend, @function +icode: + la $a0, UBASE + move $a1, $a0 + addi $a0, etcinit - icode + addi $a1, argv - icode + syscall 11 # SYS_execv + move $a0, $v0 + syscall 1 # SYS_exit +etcinit: + .ascii "/sbin/init\0" +initflags: + .ascii "-\0" # ASCII initflags +argv: + .word etcinit + 6 - icode + UBASE # address of "init\0" + .word initflags - icode + UBASE # init options + .word 0 + +icodeend: nop + +#--------------------------------------- +# int setjmp (label_t *env); +# +# Setjmp(env) will save the process' current register variables, stack +# and program counter context and return a zero. +# + .type setjmp, @function +setjmp: .globl setjmp + sw $s0, (0 * 4) ($a0) # save register variables s0-s8 + sw $s1, (1 * 4) ($a0) + sw $s2, (2 * 4) ($a0) + sw $s3, (3 * 4) ($a0) + sw $s4, (4 * 4) ($a0) + sw $s5, (5 * 4) ($a0) + sw $s6, (6 * 4) ($a0) + sw $s7, (7 * 4) ($a0) + sw $s8, (8 * 4) ($a0) # frame pointer + sw $ra, (9 * 4) ($a0) # return address + sw $gp, (10 * 4) ($a0) # global data pointer + sw $sp, (11 * 4) ($a0) # stack pointer + j $ra + move $v0, $zero # return a zero for the setjmp call + +#--------------------------------------- +# void longjmp (memaddr uaddr, label_t *env); +# +# Longjmp(uaddr, env) will generate a "return(1)" from the last +# call to setjmp(env) by mapping in the user structure pointed to by uaddr, +# restoring the context saved by setjmp in env and returning a "1". +# Note that registers are recovered statically from the env buffer. +# Stack is not used. +# +# This longjmp differs from the longjmp found in the standard library - +# it's actually closer to the resume routine of the 4.3BSD kernel. +# + .type longjmp, @function +longjmp: .globl longjmp + + di # can't let anything in till we get a valid stack... + + la $v0, u # pointer to &u + beq $v0, $a0, 2f # if uaddr == &u... + nop # ...no need to remap U area + + la $a3, u_end # pointer to &u + USIZE + la $a0, u0 # pointer to &u0 + + lw $v1, 0($v0) # u.u_procp + sw $a0, 60($v1) # u.u_procp->p_addr = &u0 + + # exchange contents of u and u0 + move $v1, $v0 +1: + lw $t1, 0($v1) + lw $t0, 0($a0) + sw $t0, 0($v1) + sw $t1, 0($a0) + lw $t1, 4($v1) + lw $t0, 4($a0) + sw $t0, 4($v1) + sw $t1, 4($a0) + lw $t1, 8($v1) + lw $t0, 8($a0) + sw $t0, 8($v1) + sw $t1, 8($a0) + lw $t1, 12($v1) + lw $t0, 12($a0) + sw $t0, 12($v1) + sw $t1, 12($a0) + addiu $v1, $v1, 16 + bne $a3, $v1, 1b + addiu $a0, $a0, 16 + + lw $v1, 0($v0) # u.u_procp + sw $v0, 60($v1) # u.u_procp->p_addr = &u +2: + lw $s0, (0 * 4) ($a1) # restore register variables s0-s8 + lw $s1, (1 * 4) ($a1) + lw $s2, (2 * 4) ($a1) + lw $s3, (3 * 4) ($a1) + lw $s4, (4 * 4) ($a1) + lw $s5, (5 * 4) ($a1) + lw $s6, (6 * 4) ($a1) + lw $s7, (7 * 4) ($a1) + lw $s8, (8 * 4) ($a1) # frame pointer + lw $ra, (9 * 4) ($a1) # return address + lw $gp, (10 * 4) ($a1) # global data pointer + lw $sp, (11 * 4) ($a1) # stack pointer + + ei # release interrupts + j $ra # transfer back to setjmp() + li $v0, 1 # return value of 1 diff --git a/sys/pic32/swap.c b/sys/pic32/swap.c new file mode 100644 index 0000000..5ad63a2 --- /dev/null +++ b/sys/pic32/swap.c @@ -0,0 +1,258 @@ +/* + * Simple proxy for swap partition. Forwards requests for /dev/swap on to the + * device specified by swapdev + */ + +#include "param.h" +#include "systm.h" +#include "buf.h" +#include "errno.h" +#include "dk.h" +#include "uio.h" +#include "conf.h" +#include "fcntl.h" +#include "map.h" +#include "swap.h" +#include "rdisk.h" + +#ifndef NTMP +#define NTMP 3 +#endif + +const struct devspec swapbdevs[] = { { 0, "swap0" }, { 1, "swap1" }, { 2, "swap2" }, { 64, "swap" }, { 0, 0 } }; +const struct devspec swapcdevs[] = { { 0, "temp0" }, { 1, "temp1" }, { 2, "temp2" }, { 0, 0 } }; + +extern struct buf *getnewbuf(); + +static unsigned int tdsize[NTMP]; // Number of blocks allocated +static unsigned int tdstart[NTMP]; // Starting location in map + +extern dev_t swapdev; +extern int physio(void (*strat) (struct buf*), + register struct buf *bp, + dev_t dev, + int rw, + register struct uio *uio); + +extern void swap(size_t blkno, size_t coreaddr, register int count, int rdflg); + +int swopen(dev_t dev, int mode, int flag) +{ + int unit = minor(dev); + + if (unit == 64) + return bdevsw[major(swapdev)].d_open(swapdev, mode, flag); + + if (unit >= NTMP) + return ENODEV; + return 0; +} + +int swclose(dev_t dev, int mode, int flag) +{ + int unit = minor(dev); + + if (unit == 64) + return bdevsw[major(swapdev)].d_close(swapdev, mode, flag); + + if (unit >= NTMP) + return ENODEV; + return 0; +} + +daddr_t swsize(dev_t dev) +{ + int unit = minor(dev); + + if (unit == 64) + return bdevsw[major(dev)].d_psize(dev); + + if (unit >= NTMP) + return ENODEV; + + return tdsize[unit]; +} + +int swcopen(dev_t dev, int mode, int flag) +{ + int unit = minor(dev); + + if (unit >= NTMP) { + printf("temp%d: Device number out of range\n", minor(dev)); + return ENODEV; + } + return 0; +} + +int swcclose(dev_t dev, int mode, int flag) +{ + int unit = minor(dev); + + if (unit >= NTMP) + return ENODEV; + + return 0; +} + +int swcread(dev_t dev, register struct uio *uio, int flag) +{ + unsigned int block; + unsigned int boff; + struct buf *bp; + unsigned int rsize; + unsigned int rlen; + int unit = minor(dev); + + if (unit >= NTMP) { + printf("temp%d: Device number out of range\n", minor(dev)); + return ENODEV; + } + + if (tdstart[unit] == 0) + return EIO; + + if (uio->uio_offset >= tdsize[unit] << 10) + return EIO; + + bp = getnewbuf(); + + block = uio->uio_offset >> 10; + boff = uio->uio_offset - (block << 10); + + rsize = DEV_BSIZE - boff; + rlen = uio->uio_iov->iov_len; + + while((rlen > 0) && (block < tdsize[unit])) { + swap(tdstart[unit] + block, (size_t)bp->b_addr, DEV_BSIZE, B_READ); + uiomove(bp->b_addr+boff, rsize, uio); + boff = 0; + block++; + rlen -= rsize; + rsize = rlen >= DEV_BSIZE ? DEV_BSIZE : rlen; + } + + brelse(bp); + return 0; +} + +int swcwrite(dev_t dev, register struct uio *uio, int flag) +{ + unsigned int block; + unsigned int boff; + struct buf *bp; + unsigned int rsize; + unsigned int rlen; + int unit = minor(dev); + + if (unit >= NTMP) { + printf("temp%d: Device number out of range\n", minor(dev)); + return ENODEV; + } + + if (tdstart[unit] == 0) { + printf("temp%d: attempt to write with no allocation\n", unit); + return EIO; + } + + if (uio->uio_offset >= tdsize[unit] << 10) { + printf("temp%d: attempt to write past end of allocation\n", unit); + return EIO; + } + + bp = getnewbuf(); + + block = uio->uio_offset >> 10; + boff = uio->uio_offset - (block << 10); + + rsize = DEV_BSIZE - boff; + rlen = uio->uio_iov->iov_len; + + while((rlen > 0) && (block < tdsize[unit])) { + uiomove(bp->b_addr+boff, rsize, uio); + swap(tdstart[unit] + block, (size_t)bp->b_addr, DEV_BSIZE, B_WRITE); + boff = 0; + block++; + rlen -= rsize; + rsize = rlen >= DEV_BSIZE ? DEV_BSIZE : rlen; + } + + brelse(bp); + return 0; +} + +int swcioctl (dev_t dev, register u_int cmd, caddr_t addr, int flag) +{ + unsigned int *uival; + off_t *offtval; + int unit = minor(dev); + + if (unit >= NTMP) { + printf("temp%d: Device number out of range\n", minor(dev)); + return ENODEV; + } + + uival = (unsigned int *)addr; + offtval = (off_t *)addr; + + switch(cmd) + { + case TFALLOC: + if (tdstart[unit] > 0) + mfree(swapmap, tdsize[unit], tdstart[unit]); + + if (*offtval > 0) { + tdstart[unit] = malloc(swapmap, *offtval); + if (tdstart[unit] > 0) { + tdsize[unit] = *offtval; + //printf("temp%d: allocated %lu blocks\n", unit, tdsize[unit]); + return 0; + } + *offtval = 0; + printf("temp%d: failed to allocate %lu blocks\n", tdsize[unit]); + return 0; + } else { + //printf("temp%d: released allocation\n", unit); + } + break; + + case RDGETMEDIASIZE: + *uival = swsize(dev); + break; + } + return EINVAL; +} + +void swstrategy(register struct buf *bp) +{ + int unit = minor(bp->b_dev); + + if (unit == 64) { + + dev_t od = bp->b_dev; + bp->b_dev = swapdev; + bdevsw[major(swapdev)].d_strategy(bp); + bp->b_dev = od; + + } else { + + if (unit >= NTMP) + return; + + if (tdstart[unit] == 0) { + printf("swap%d: attempt to access unallocated device\n", unit); + return; + } + + if (bp->b_blkno > tdsize[unit]) { + printf("swap%d: attempt to access past end of allocation\n", unit); + return; + } + + if (bp->b_flags & B_READ) { + swap(tdstart[unit] + bp->b_blkno, (size_t)bp->b_addr, bp->b_bcount , B_READ); + } else { + swap(tdstart[unit] + bp->b_blkno, (size_t)bp->b_addr, bp->b_bcount , B_WRITE); + } + biodone(bp); + } +} diff --git a/sys/pic32/sysctl.c b/sys/pic32/sysctl.c new file mode 100644 index 0000000..e0a0b05 --- /dev/null +++ b/sys/pic32/sysctl.c @@ -0,0 +1,358 @@ +/* + * Copyright (c) 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "param.h" +#include "user.h" +#include "ioctl.h" +#include "proc.h" +#include "kernel.h" +#include "file.h" +#include "inode.h" +#include "sysctl.h" +#include "cpu.h" +#include "tty.h" +#include "systm.h" +#include "dk.h" +#include "vmsystm.h" +#include "ptrace.h" +#include "namei.h" +#include "vmmeter.h" +#include "map.h" +#include "conf.h" + +/* + * Errno messages. + */ +static const char *errlist[] = { + "Undefined error: 0", /* 0 - ENOERROR */ + "Operation not permitted", /* 1 - EPERM */ + "No such file or directory", /* 2 - ENOENT */ + "No such process", /* 3 - ESRCH */ + "Interrupted system call", /* 4 - EINTR */ + "Input/output error", /* 5 - EIO */ + "Device not configured", /* 6 - ENXIO */ + "Argument list too long", /* 7 - E2BIG */ + "Exec format error", /* 8 - ENOEXEC */ + "Bad file descriptor", /* 9 - EBADF */ + "No child processes", /* 10 - ECHILD */ + "No more processes", /* 11 - EAGAIN */ + "Cannot allocate memory", /* 12 - ENOMEM */ + "Permission denied", /* 13 - EACCES */ + "Bad address", /* 14 - EFAULT */ + "Block device required", /* 15 - ENOTBLK */ + "Device busy", /* 16 - EBUSY */ + "File exists", /* 17 - EEXIST */ + "Cross-device link", /* 18 - EXDEV */ + "Operation not supported by device", /* 19 - ENODEV */ + "Not a directory", /* 20 - ENOTDIR */ + "Is a directory", /* 21 - EISDIR */ + "Invalid argument", /* 22 - EINVAL */ + "Too many open files in system", /* 23 - ENFILE */ + "Too many open files", /* 24 - EMFILE */ + "Inappropriate ioctl for device", /* 25 - ENOTTY */ + "Text file busy", /* 26 - ETXTBSY */ + "File too large", /* 27 - EFBIG */ + "No space left on device", /* 28 - ENOSPC */ + "Illegal seek", /* 29 - ESPIPE */ + "Read-only file system", /* 30 - EROFS */ + "Too many links", /* 31 - EMLINK */ + "Broken pipe", /* 32 - EPIPE */ + +/* math software */ + "Numerical argument out of domain", /* 33 - EDOM */ + "Result too large", /* 34 - ERANGE */ + +/* non-blocking and interrupt i/o */ + "Resource temporarily unavailable", /* 35 - EWOULDBLOCK */ + "Operation now in progress", /* 36 - EINPROGRESS */ + "Operation already in progress", /* 37 - EALREADY */ + +/* ipc/network software -- argument errors */ + "Socket operation on non-socket", /* 38 - ENOTSOCK */ + "Destination address required", /* 39 - EDESTADDRREQ */ + "Message too long", /* 40 - EMSGSIZE */ + "Protocol wrong type for socket", /* 41 - EPROTOTYPE */ + "Protocol not available", /* 42 - ENOPROTOOPT */ + "Protocol not supported", /* 43 - EPROTONOSUPPORT */ + "Socket type not supported", /* 44 - ESOCKTNOSUPPORT */ + "Operation not supported", /* 45 - EOPNOTSUPP */ + "Protocol family not supported", /* 46 - EPFNOSUPPORT */ + /* 47 - EAFNOSUPPORT */ + "Address family not supported by protocol family", + "Address already in use", /* 48 - EADDRINUSE */ + "Can't assign requested address", /* 49 - EADDRNOTAVAIL */ + +/* ipc/network software -- operational errors */ + "Network is down", /* 50 - ENETDOWN */ + "Network is unreachable", /* 51 - ENETUNREACH */ + "Network dropped connection on reset", /* 52 - ENETRESET */ + "Software caused connection abort", /* 53 - ECONNABORTED */ + "Connection reset by peer", /* 54 - ECONNRESET */ + "No buffer space available", /* 55 - ENOBUFS */ + "Socket is already connected", /* 56 - EISCONN */ + "Socket is not connected", /* 57 - ENOTCONN */ + "Can't send after socket shutdown", /* 58 - ESHUTDOWN */ + "Too many references: can't splice", /* 59 - ETOOMANYREFS */ + "Operation timed out", /* 60 - ETIMEDOUT */ + "Connection refused", /* 61 - ECONNREFUSED */ + + "Too many levels of symbolic links", /* 62 - ELOOP */ + "File name too long", /* 63 - ENAMETOOLONG */ + +/* should be rearranged */ + "Host is down", /* 64 - EHOSTDOWN */ + "No route to host", /* 65 - EHOSTUNREACH */ + "Directory not empty", /* 66 - ENOTEMPTY */ + +/* quotas & mush */ + "Too many processes", /* 67 - EPROCLIM */ + "Too many users", /* 68 - EUSERS */ + "Disc quota exceeded", /* 69 - EDQUOT */ + +/* Network File System */ + "Stale NFS file handle", /* 70 - ESTALE */ + "Too many levels of remote in path", /* 71 - EREMOTE */ + "RPC struct is bad", /* 72 - EBADRPC */ + "RPC version wrong", /* 73 - ERPCMISMATCH */ + "RPC prog. not avail", /* 74 - EPROGUNAVAIL */ + "Program version wrong", /* 75 - EPROGMISMATCH */ + "Bad procedure for program", /* 76 - EPROCUNAVAIL */ + + "No locks available", /* 77 - ENOLCK */ + "Function not implemented", /* 78 - ENOSYS */ + "Inappropriate file type or format", /* 79 - EFTYPE */ + "Authentication error", /* 80 - EAUTH */ + "Need authenticator", /* 81 - ENEEDAUTH */ +}; + +/* + * Kernel symbol name list. + */ +static const struct { + const char *name; + int addr; +} nlist[] = { + { "_boottime", (int) &boottime }, /* vmstat */ + { "_cnttys", (int) &cnttys }, /* pstat */ + { "_cp_time", (int) &cp_time }, /* iostat vmstat */ + { "_dk_busy", (int) &dk_busy }, /* iostat */ + { "_dk_name", (int) &dk_name }, /* iostat vmstat */ + { "_dk_ndrive", (int) &dk_ndrive }, /* iostat vmstat */ + { "_dk_unit", (int) &dk_unit }, /* iostat vmstat */ + { "_dk_bytes", (int) &dk_bytes }, /* iostat */ + { "_dk_xfer", (int) &dk_xfer }, /* iostat vmstat */ + { "_file", (int) &file }, /* pstat */ + { "_forkstat", (int) &forkstat }, /* vmstat */ +#ifdef UCB_METER + { "_freemem", (int) &freemem }, /* vmstat */ +#endif + { "_hz", (int) &hz }, /* ps */ + { "_inode", (int) &inode }, /* pstat */ + { "_ipc", (int) &ipc }, /* ps */ + { "_lbolt", (int) &lbolt }, /* ps */ + { "_memlock", (int) &memlock }, /* ps */ + { "_nchstats", (int) &nchstats }, /* vmstat */ + { "_nproc", (int) &nproc }, /* ps pstat */ + { "_nswap", (int) &nswap }, /* pstat */ + { "_proc", (int) &proc }, /* ps pstat */ + { "_runin", (int) &runin }, /* ps */ + { "_runout", (int) &runout }, /* ps */ + { "_selwait", (int) &selwait }, /* ps */ + { "_swapmap", (int) &swapmap }, /* pstat */ + { "_tk_nin", (int) &tk_nin }, /* iostat */ + { "_tk_nout", (int) &tk_nout }, /* iostat */ + { "_total", (int) &total }, /* vmstat */ + { "_u", (int) &u }, /* ps */ +#if NPTY > 0 + { "_npty", (int) &npty }, /* pstat */ + { "_pt_tty", (int) &pt_tty }, /* pstat */ +#endif +#ifdef UCB_METER + { "_rate", (int) &rate }, /* vmstat */ + { "_sum", (int) &sum }, /* vmstat */ +#endif + { "_bdevsw", (int) &bdevsw }, + { "_cdevsw", (int) &cdevsw }, + { 0, 0 }, +}; + +/* + * ucall allows user level code to call various kernel functions. + * Autoconfig uses it to call the probe and attach routines of the + * various device drivers. + */ +void +ucall() +{ + register struct a { + int priority; + int (*routine)(); + int arg1; + int arg2; + } *uap = (struct a *)u.u_arg; + int s; + + if (!suser()) + return; + switch (uap->priority) { + case 0: + s = spl0(); + break; + default: + s = splhigh(); + break; + } + u.u_rval = (*uap->routine) (uap->arg1, uap->arg2); + splx(s); +} + +/* + * Fetch the word at addr from flash memory or i/o port. + * This system call is required on PIC32 because in user mode + * the access to flash memory region is not allowed. + */ +void +ufetch() +{ + unsigned addr = *(unsigned*) u.u_arg & ~3; + + /* Check root privileges */ + if (! suser()) + return; + + /* Low memory address - assume peripheral i/o space. */ + if (addr < 0x90000) + addr += 0xbf800000; + + /* Check address */ + if (! (addr >= 0x9d000000 && addr < 0x9d000000 + FLASH_SIZE) && + ! (addr >= 0xbd000000 && addr < 0xbd000000 + FLASH_SIZE) && + + /* Boot flash memory */ + ! (addr >= 0x9fc00000 && addr < 0x9fc00000 + 12*1024) && + ! (addr >= 0xbfc00000 && addr < 0xbfc00000 + 12*1024) && + + /* Peripheral registers */ + ! (addr >= 0xbf800000 && addr < 0xbf810000) && + ! (addr >= 0xbf880000 && addr < 0xbf890000)) { + u.u_error = EFAULT; + return; + } + u.u_rval = *(unsigned*) addr; +} + +/* + * Store the word at addr of i/o port. + */ +void +ustore() +{ + register struct a { + unsigned addr; + unsigned value; + } *uap = (struct a *)u.u_arg; + unsigned addr = uap->addr & ~3; + + /* Check root privileges */ + if (! suser()) + return; + + /* Low memory address - assume peripheral i/o space. */ + if (addr < 0x90000) + addr += 0xbf800000; + + /* Check address */ + if (! (addr >= 0xbf800000 && addr < 0xbf810000) && + ! (addr >= 0xbf880000 && addr < 0xbf890000)) { + u.u_error = EFAULT; + return; + } + *(unsigned*) addr = uap->value; +} + +/* + * This was moved here when the TMSCP portion was added. At that time it + * became (even more) system specific and didn't belong in kern_sysctl.c + */ +int +cpu_sysctl (name, namelen, oldp, oldlenp, newp, newlen) + int *name; + u_int namelen; + void *oldp; + size_t *oldlenp; + void *newp; + size_t newlen; +{ + int i; + + switch (name[0]) { + case CPU_CONSDEV: + if (namelen != 1) + return ENOTDIR; + return sysctl_rdstruct (oldp, oldlenp, newp, + &cnttys[0].t_dev, sizeof &cnttys[0].t_dev); +#if NTMSCP > 0 + case CPU_TMSCP: + /* All sysctl names at this level are terminal */ + if (namelen != 2) + return ENOTDIR; + switch (name[1]) { + case TMSCP_CACHE: + return sysctl_int (oldp, oldlenp, newp, + newlen, &tmscpcache); + case TMSCP_PRINTF: + return sysctl_int (oldp, oldlenp, newp, + newlen, &tmscpprintf); + default: + } +#endif + case CPU_ERRMSG: + if (namelen != 2) + return ENOTDIR; + if (name[1] < 1 || + name[1] >= sizeof(errlist) / sizeof(errlist[0])) + return EOPNOTSUPP; + return sysctl_string(oldp, oldlenp, 0, 0, + (char*) errlist[name[1]], + 1 + strlen(errlist[name[1]])); + + case CPU_NLIST: + for (i=0; nlist[i].name; i++) { + if (strncmp (newp, nlist[i].name, newlen) == 0) { + int addr = nlist[i].addr; + if (! oldp) + return 0; + if (*oldlenp < sizeof(int)) + return ENOMEM; + *oldlenp = sizeof(int); + return copyout ((caddr_t) &addr, (caddr_t) oldp, sizeof(int)); + } + } + return EOPNOTSUPP; + + case CPU_TIMO_CMD: + return sysctl_int(oldp, oldlenp, newp, newlen, &sd_timo_cmd); + case CPU_TIMO_SEND_OP: + return sysctl_int(oldp, oldlenp, newp, newlen, &sd_timo_send_op); + case CPU_TIMO_SEND_CSD: + return sysctl_int(oldp, oldlenp, newp, newlen, &sd_timo_send_csd); + case CPU_TIMO_READ: + return sysctl_int(oldp, oldlenp, newp, newlen, &sd_timo_read); + case CPU_TIMO_WAIT_CMD: + return sysctl_int(oldp, oldlenp, newp, newlen, &sd_timo_wait_cmd); + case CPU_TIMO_WAIT_WDATA: + return sysctl_int(oldp, oldlenp, newp, newlen, &sd_timo_wait_wdata); + case CPU_TIMO_WAIT_WDONE: + return sysctl_int(oldp, oldlenp, newp, newlen, &sd_timo_wait_wdone); + case CPU_TIMO_WAIT_WSTOP: + return sysctl_int(oldp, oldlenp, newp, newlen, &sd_timo_wait_wstop); + case CPU_TIMO_WAIT_WIDLE: + return sysctl_int(oldp, oldlenp, newp, newlen, &sd_timo_wait_widle); + + default: + return EOPNOTSUPP; + } + /* NOTREACHED */ +} diff --git a/sys/pic32/uart.c b/sys/pic32/uart.c new file mode 100644 index 0000000..d2093e7 --- /dev/null +++ b/sys/pic32/uart.c @@ -0,0 +1,779 @@ +/* + * UART driver for PIC32. + * + * Copyright (c) 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ +#include "param.h" +#include "conf.h" +#include "user.h" +#include "ioctl.h" +#include "tty.h" +#include "systm.h" +#include "uart.h" + +#define CONCAT(x,y) x ## y +#define BBAUD(x) CONCAT(B,x) + +unsigned int uart_major = 0; + +#ifndef UART1_BAUD +#define UART1_BAUD 115200 +#endif +#ifndef UART2_BAUD +#define UART2_BAUD 115200 +#endif +#ifndef UART3_BAUD +#define UART3_BAUD 115200 +#endif +#ifndef UART4_BAUD +#define UART4_BAUD 115200 +#endif +#ifndef UART5_BAUD +#define UART5_BAUD 115200 +#endif +#ifndef UART6_BAUD +#define UART6_BAUD 115200 +#endif + +const struct uart_irq uirq[NUART] = { + { PIC32_IRQ_U1E, PIC32_IRQ_U1RX, PIC32_IRQ_U1TX }, + { PIC32_IRQ_U2E, PIC32_IRQ_U2RX, PIC32_IRQ_U2TX }, + { PIC32_IRQ_U3E, PIC32_IRQ_U3RX, PIC32_IRQ_U3TX }, + { PIC32_IRQ_U4E, PIC32_IRQ_U4RX, PIC32_IRQ_U4TX }, + { PIC32_IRQ_U5E, PIC32_IRQ_U5RX, PIC32_IRQ_U5TX }, + { PIC32_IRQ_U6E, PIC32_IRQ_U6RX, PIC32_IRQ_U6TX }, +}; + +struct tty uartttys[NUART]; + +static unsigned speed_bps [NSPEEDS] = { + 0, 50, 75, 150, 200, 300, 600, 1200, + 1800, 2400, 4800, 9600, 19200, 38400, 57600, 115200, + 230400, 460800, 500000, 576000, 921600, 1000000, 1152000, 1500000, + 2000000, 2500000, 3000000, 3500000, 4000000 +}; + +const struct devspec uartdevs[] = { + { 0, "tty0" }, + { 1, "tty1" }, + { 2, "tty2" }, + { 3, "tty3" }, + { 4, "tty4" }, + { 5, "tty5" }, + { 0, 0 }, +}; + +void cnstart (struct tty *tp); +struct uartreg *uart[NUART] = { + (struct uartreg*) &U1MODE, + (struct uartreg*) &U2MODE, + (struct uartreg*) &U3MODE, + (struct uartreg*) &U4MODE, + (struct uartreg*) &U5MODE, + (struct uartreg*) &U6MODE +}; + +void uartinit() +{ + unsigned char unit; + int i; + + // Our first task is to find out what our major + // number is, so that the console can continue to work. + + for (i=0; ibrg = PIC32_BRG_BAUD (BUS_KHZ * 1000, UART1_BAUD); + break; + case 1: +#ifdef UART2_ENA_PORT + /* Enable UART2 phy - pin is assumed to be active low */ + TRIS_CLR(UART2_ENA_PORT) = 1 << UART2_ENA_PIN; + LAT_CLR(UART2_ENA_PORT) = 1 << UART2_ENA_PIN; + udelay(2500); +#endif + uart[unit]->brg = PIC32_BRG_BAUD (BUS_KHZ * 1000, UART2_BAUD); + break; + case 2: +#ifdef UART3_ENA_PORT + /* Enable UART3 phy - pin is assumed to be active low */ + TRIS_CLR(UART3_ENA_PORT) = 1 << UART3_ENA_PIN; + LAT_CLR(UART3_ENA_PORT) = 1 << UART3_ENA_PIN; + udelay(2500); +#endif + uart[unit]->brg = PIC32_BRG_BAUD (BUS_KHZ * 1000, UART3_BAUD); + break; + case 3: +#ifdef UART4_ENA_PORT + /* Enable UART4 phy - pin is assumed to be active low */ + TRIS_CLR(UART4_ENA_PORT) = 1 << UART4_ENA_PIN; + LAT_CLR(UART4_ENA_PORT) = 1 << UART4_ENA_PIN; + udelay(2500); +#endif + uart[unit]->brg = PIC32_BRG_BAUD (BUS_KHZ * 1000, UART4_BAUD); + break; + case 4: +#ifdef UART5_ENA_PORT + /* Enable UART5 phy - pin is assumed to be active low */ + TRIS_CLR(UART5_ENA_PORT) = 1 << UART5_ENA_PIN; + LAT_CLR(UART5_ENA_PORT) = 1 << UART5_ENA_PIN; + udelay(2500); +#endif + uart[unit]->brg = PIC32_BRG_BAUD (BUS_KHZ * 1000, UART5_BAUD); + break; + case 5: +#ifdef UART6_ENA_PORT + /* Enable UART6 phy - pin is assumed to be active low */ + TRIS_CLR(UART6_ENA_PORT) = 1 << UART6_ENA_PIN; + LAT_CLR(UART6_ENA_PORT) = 1 << UART6_ENA_PIN; + udelay(2500); +#endif + uart[unit]->brg = PIC32_BRG_BAUD (BUS_KHZ * 1000, UART6_BAUD); + break; + } + + uart[unit]->sta = 0; + uart[unit]->mode = PIC32_UMODE_PDSEL_8NPAR | /* 8-bit data, no parity */ + PIC32_UMODE_ON; /* UART Enable */ + uart[unit]->staset = PIC32_USTA_URXEN | /* Receiver Enable */ + PIC32_USTA_UTXEN; /* Transmit Enable */ + } +} + +int uartopen(dev_t dev, int flag, int mode) +{ + register struct uartreg *reg; + register struct tty *tp; + register int unit = minor(dev); + + if (unit >= NUART) + return (ENXIO); + +#ifndef UART1_ENABLED + if (unit==0) + return ENODEV; +#endif +#ifndef UART2_ENABLED + if (unit==1) + return ENODEV; +#endif +#ifndef UART3_ENABLED + if (unit==2) + return ENODEV; +#endif +#ifndef UART4_ENABLED + if (unit==3) + return ENODEV; +#endif +#ifndef UART5_ENABLED + if (unit==4) + return ENODEV; +#endif +#ifndef UART6_ENABLED + if (unit==5) + return ENODEV; +#endif + + if ((SD0_PORT == 2) && (unit==2 || unit==5)) + return (ENODEV); + if ((SD0_PORT == 3) && (unit==0 || unit==3)) + return (ENODEV); + if ((SD0_PORT == 4) && (unit==1 || unit==4)) + return (ENODEV); + + tp = &uartttys[unit]; + if (! tp->t_addr) { + switch (unit) { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + tp->t_addr = (caddr_t) uart[unit]; + break; + default: + return (ENXIO); + } + } + reg = (struct uartreg*) tp->t_addr; + tp->t_oproc = uartstart; + if ((tp->t_state & TS_ISOPEN) == 0) { + if (tp->t_ispeed == 0) { + switch(unit) + { + case 0: + tp->t_ispeed = BBAUD(UART1_BAUD); + tp->t_ospeed = BBAUD(UART1_BAUD); + break; + case 1: + tp->t_ispeed = BBAUD(UART2_BAUD); + tp->t_ospeed = BBAUD(UART2_BAUD); + break; + case 2: + tp->t_ispeed = BBAUD(UART3_BAUD); + tp->t_ospeed = BBAUD(UART3_BAUD); + break; + case 3: + tp->t_ispeed = BBAUD(UART4_BAUD); + tp->t_ospeed = BBAUD(UART4_BAUD); + break; + case 4: + tp->t_ispeed = BBAUD(UART5_BAUD); + tp->t_ospeed = BBAUD(UART5_BAUD); + break; + case 5: + tp->t_ispeed = BBAUD(UART6_BAUD); + tp->t_ospeed = BBAUD(UART6_BAUD); + break; + } + } + ttychars(tp); + tp->t_state = TS_ISOPEN | TS_CARR_ON; + tp->t_flags = ECHO | XTABS | CRMOD | CRTBS | CRTERA | CTLECH | CRTKIL; + } + if ((tp->t_state & TS_XCLUDE) && u.u_uid != 0) + return (EBUSY); + + reg->sta = 0; + reg->brg = PIC32_BRG_BAUD (BUS_KHZ * 1000, speed_bps [tp->t_ospeed]); + reg->mode = PIC32_UMODE_PDSEL_8NPAR | + PIC32_UMODE_ON; + reg->staset = PIC32_USTA_URXEN | PIC32_USTA_UTXEN; + + /* Enable receive interrupt. */ + if (uirq[unit].rx < 32) + { + IECSET(0) = 1 << uirq[unit].rx; + } else if (uirq[unit].rx < 64) + { + IECSET(1) = 1 << (uirq[unit].rx-32); + } else { + IECSET(2) = 1 << (uirq[unit].rx-64); + } + return ttyopen(dev, tp); +} + +/*ARGSUSED*/ +int +uartclose (dev, flag, mode) + dev_t dev; +{ + register int unit = minor(dev); + register struct tty *tp = &uartttys[unit]; +#ifndef UART1_ENABLED + if (unit==0) + return ENODEV; +#endif +#ifndef UART2_ENABLED + if (unit==1) + return ENODEV; +#endif +#ifndef UART3_ENABLED + if (unit==2) + return ENODEV; +#endif +#ifndef UART4_ENABLED + if (unit==3) + return ENODEV; +#endif +#ifndef UART5_ENABLED + if (unit==4) + return ENODEV; +#endif +#ifndef UART6_ENABLED + if (unit==5) + return ENODEV; +#endif + + if ((SD0_PORT == 2) && (unit==2 || unit==5)) + return (ENODEV); + if ((SD0_PORT == 3) && (unit==0 || unit==3)) + return (ENODEV); + if ((SD0_PORT == 4) && (unit==1 || unit==4)) + return (ENODEV); + + ttyclose(tp); + return(0); +} + +/*ARGSUSED*/ +int +uartread (dev, uio, flag) + dev_t dev; + struct uio *uio; + int flag; +{ + register int unit = minor(dev); + register struct tty *tp = &uartttys[unit]; +#ifndef UART1_ENABLED + if (unit==0) + return ENODEV; +#endif +#ifndef UART2_ENABLED + if (unit==1) + return ENODEV; +#endif +#ifndef UART3_ENABLED + if (unit==2) + return ENODEV; +#endif +#ifndef UART4_ENABLED + if (unit==3) + return ENODEV; +#endif +#ifndef UART5_ENABLED + if (unit==4) + return ENODEV; +#endif +#ifndef UART6_ENABLED + if (unit==5) + return ENODEV; +#endif + + if ((SD0_PORT == 2) && (unit==2 || unit==5)) + return (ENODEV); + if ((SD0_PORT == 3) && (unit==0 || unit==3)) + return (ENODEV); + if ((SD0_PORT == 4) && (unit==1 || unit==4)) + return (ENODEV); + + return ttread(tp, uio, flag); +} + +/*ARGSUSED*/ +int +uartwrite (dev, uio, flag) + dev_t dev; + struct uio *uio; + int flag; +{ + register int unit = minor(dev); + register struct tty *tp = &uartttys[unit]; + +#ifndef UART1_ENABLED + if (unit==0) + return ENODEV; +#endif +#ifndef UART2_ENABLED + if (unit==1) + return ENODEV; +#endif +#ifndef UART3_ENABLED + if (unit==2) + return ENODEV; +#endif +#ifndef UART4_ENABLED + if (unit==3) + return ENODEV; +#endif +#ifndef UART5_ENABLED + if (unit==4) + return ENODEV; +#endif +#ifndef UART6_ENABLED + if (unit==5) + return ENODEV; +#endif + if ((SD0_PORT == 2) && (unit==2 || unit==5)) + return (ENODEV); + if ((SD0_PORT == 3) && (unit==0 || unit==3)) + return (ENODEV); + if ((SD0_PORT == 4) && (unit==1 || unit==4)) + return (ENODEV); + + return ttwrite(tp, uio, flag); +} + +int +uartselect (dev, rw) + register dev_t dev; + int rw; +{ + register int unit = minor(dev); + register struct tty *tp = &uartttys[unit]; + +#ifndef UART1_ENABLED + if (unit==0) + return ENODEV; +#endif +#ifndef UART2_ENABLED + if (unit==1) + return ENODEV; +#endif +#ifndef UART3_ENABLED + if (unit==2) + return ENODEV; +#endif +#ifndef UART4_ENABLED + if (unit==3) + return ENODEV; +#endif +#ifndef UART5_ENABLED + if (unit==4) + return ENODEV; +#endif +#ifndef UART6_ENABLED + if (unit==5) + return ENODEV; +#endif + if ((SD0_PORT == 2) && (unit==2 || unit==5)) + return (ENODEV); + if ((SD0_PORT == 3) && (unit==0 || unit==3)) + return (ENODEV); + if ((SD0_PORT == 4) && (unit==1 || unit==4)) + return (ENODEV); + + return (ttyselect (tp, rw)); +} + +/*ARGSUSED*/ +int +uartioctl (dev, cmd, addr, flag) + dev_t dev; + register u_int cmd; + caddr_t addr; +{ + register int unit = minor(dev); + register struct tty *tp = &uartttys[unit]; + register int error; + +#ifndef UART1_ENABLED + if (unit==0) + return ENODEV; +#endif +#ifndef UART2_ENABLED + if (unit==1) + return ENODEV; +#endif +#ifndef UART3_ENABLED + if (unit==2) + return ENODEV; +#endif +#ifndef UART4_ENABLED + if (unit==3) + return ENODEV; +#endif +#ifndef UART5_ENABLED + if (unit==4) + return ENODEV; +#endif +#ifndef UART6_ENABLED + if (unit==5) + return ENODEV; +#endif + if ((SD0_PORT == 2) && (unit==2 || unit==5)) + return (ENODEV); + if ((SD0_PORT == 3) && (unit==0 || unit==3)) + return (ENODEV); + if ((SD0_PORT == 4) && (unit==1 || unit==4)) + return (ENODEV); + + error = ttioctl(tp, cmd, addr, flag); + if (error < 0) + error = ENOTTY; + return (error); +} + +void +uartintr (dev) + dev_t dev; +{ + register int c; + register int unit = minor(dev); + register struct tty *tp = &uartttys[unit]; + register struct uartreg *reg = (struct uartreg *)tp->t_addr; + +#ifndef UART1_ENABLED + if (unit==0) + return; +#endif +#ifndef UART2_ENABLED + if (unit==1) + return; +#endif +#ifndef UART3_ENABLED + if (unit==2) + return; +#endif +#ifndef UART4_ENABLED + if (unit==3) + return; +#endif +#ifndef UART5_ENABLED + if (unit==4) + return; +#endif +#ifndef UART6_ENABLED + if (unit==5) + return; +#endif + /* Receive */ + while (reg->sta & PIC32_USTA_URXDA) { + c = reg->rxreg; + ttyinput(c, tp); + } + if (reg->sta & PIC32_USTA_OERR) + reg->staclr = PIC32_USTA_OERR; + + if (uirq[unit].rx < 32) + { + IFSCLR(0) = (1 << uirq[unit].rx) | (1 << uirq[unit].er); + } else if (uirq[unit].rx < 64) + { + IFSCLR(1) = (1 << (uirq[unit].rx-32)) | (1 << (uirq[unit].er-32)); + } else { + IFSCLR(2) = (1 << (uirq[unit].rx-64)) | (1 << (uirq[unit].er-64)); + } + + /* Transmit */ + if (reg->sta & PIC32_USTA_TRMT) { + led_control (LED_TTY, 0); + + if (uirq[unit].tx < 32) + { + IECCLR(0) = 1 << uirq[unit].tx; + IFSCLR(0) = 1 << uirq[unit].tx; + } else if (uirq[unit].tx < 64) { + IECCLR(1) = 1 << (uirq[unit].tx - 32); + IFSCLR(1) = 1 << (uirq[unit].tx - 32); + } else { + IECCLR(2) = 1 << (uirq[unit].tx - 64); + IFSCLR(2) = 1 << (uirq[unit].tx - 64); + } + if (tp->t_state & TS_BUSY) { + tp->t_state &= ~TS_BUSY; + ttstart(tp); + } + } +} + +void uartstart (register struct tty *tp) +{ + register struct uartreg *reg = (struct uartreg*) tp->t_addr; + register int c, s; + register int unit = minor(tp->t_dev); + +#ifndef UART1_ENABLED + if (unit==0) + return; +#endif +#ifndef UART2_ENABLED + if (unit==1) + return; +#endif +#ifndef UART3_ENABLED + if (unit==2) + return; +#endif +#ifndef UART4_ENABLED + if (unit==3) + return; +#endif +#ifndef UART5_ENABLED + if (unit==4) + return; +#endif +#ifndef UART6_ENABLED + if (unit==5) + return; +#endif + s = spltty(); + if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP)) { +out: /* Disable transmit_interrupt. */ + led_control (LED_TTY, 0); + splx (s); + return; + } + ttyowake(tp); + if (tp->t_outq.c_cc == 0) + goto out; + if (reg->sta & PIC32_USTA_TRMT) { + c = getc(&tp->t_outq); + reg->txreg = c & 0xff; + tp->t_state |= TS_BUSY; + } + /* Enable transmit interrupt. */ + if (uirq[unit].tx < 32) { + IECSET(0) = 1 << uirq[unit].tx; + } else if (uirq[unit].tx < 64) { + IECSET(1) = 1 << (uirq[unit].tx - 32); + } else { + IECSET(2) = 1 << (uirq[unit].tx - 64); + } + led_control (LED_TTY, 1); + splx (s); +} + +void uartputc(dev_t dev, char c) +{ + int unit = minor(dev); + struct tty *tp = &uartttys[unit]; + register struct uartreg *reg = uart[unit]; + register int s, timo; + +#ifndef UART1_ENABLED + if (unit==0) + return; +#endif +#ifndef UART2_ENABLED + if (unit==1) + return; +#endif +#ifndef UART3_ENABLED + if (unit==2) + return; +#endif +#ifndef UART4_ENABLED + if (unit==3) + return; +#endif +#ifndef UART5_ENABLED + if (unit==4) + return; +#endif +#ifndef UART6_ENABLED + if (unit==5) + return; +#endif + s = spltty(); +again: + /* + * Try waiting for the console tty to come ready, + * otherwise give up after a reasonable time. + */ + timo = 30000; + while ((reg->sta & PIC32_USTA_TRMT) == 0) + if (--timo == 0) + break; + if (tp->t_state & TS_BUSY) { + uartintr (0); + goto again; + } + led_control (LED_TTY, 1); + reg->txreg = c; + + timo = 30000; + while ((reg->sta & PIC32_USTA_TRMT) == 0) + if (--timo == 0) + break; + + /* Clear TX interrupt. */ + if (uirq[unit].tx < 32) { + IECCLR(0) = 1 << uirq[unit].tx; + } else if (uirq[unit].tx < 64) { + IECCLR(1) = 1 << (uirq[unit].tx - 32); + } else { + IECCLR(2) = 1 << (uirq[unit].tx - 64); + } + led_control(LED_TTY, 0); + splx(s); +} + + +char uartgetc(dev_t dev) +{ + int unit = minor(dev); + register struct uartreg *reg = uart[unit]; + int s, c; + +#ifndef UART1_ENABLED + if (unit == 0) + return ENODEV; +#endif +#ifndef UART2_ENABLED + if (unit == 1) + return ENODEV; +#endif +#ifndef UART3_ENABLED + if (unit == 2) + return ENODEV; +#endif +#ifndef UART4_ENABLED + if (unit == 3) + return ENODEV; +#endif +#ifndef UART5_ENABLED + if (unit == 4) + return ENODEV; +#endif +#ifndef UART6_ENABLED + if (unit == 5) + return ENODEV; +#endif + s = spltty(); + for (;;) { + /* Wait for key pressed. */ + if (reg->sta & PIC32_USTA_URXDA) { + c = reg->rxreg; + break; + } + } + if (uirq[unit].rx < 32) { + IFSCLR(0) = (1 << uirq[unit].rx) | (1 << uirq[unit].er); + } else if (uirq[unit].rx < 64) { + IFSCLR(1) = (1 << (uirq[unit].rx-32)) | (1 << (uirq[unit].er-32)); + } else { + IFSCLR(2) = (1 << (uirq[unit].rx-64)) | (1 << (uirq[unit].er-64)); + } + splx(s); + return (unsigned char) c; +} diff --git a/sys/pic32/ubw32-uart-sdram/Makefile b/sys/pic32/ubw32-uart-sdram/Makefile new file mode 100644 index 0000000..55f67a2 --- /dev/null +++ b/sys/pic32/ubw32-uart-sdram/Makefile @@ -0,0 +1,94 @@ +BUILDPATH = ../../../tools/configsys/../../sys/pic32 +H = ../../../tools/configsys/../../sys/include +M = ../../../tools/configsys/../../sys/pic32 +S = ../../../tools/configsys/../../sys/kernel + +vpath %.c $(M):$(S) +vpath %.S $(M):$(S) + +KERNOBJ += _startup.o clock.o cons.o devsw.o exception.o init_main.o init_sysent.o kern_clock.o kern_descrip.o kern_exec.o kern_exit.o kern_fork.o kern_mman.o kern_proc.o kern_prot.o kern_prot2.o kern_resource.o kern_sig.o kern_sig2.o kern_subr.o kern_synch.o kern_sysctl.o kern_time.o machdep.o mem.o rd_sd.o rd_sdramp.o rdisk.o sdram.o signal.o spi_bus.o subr_prf.o subr_rmap.o swap.o sys_generic.o sys_inode.o sys_pipe.o sys_process.o syscalls.o sysctl.o tty.o tty_subr.o tty_tty.o uart.o ufs_alloc.o ufs_bio.o ufs_bmap.o ufs_dsort.o ufs_fio.o ufs_inode.o ufs_mount.o ufs_namei.o ufs_subr.o ufs_syscalls.o ufs_syscalls2.o vers.o vfs_vnops.o vm_sched.o vm_swap.o vm_swp.o +EXTRA_TARGETS = bootloader + +DEFS += -DBL_BUTTON_PIN=7 +DEFS += -DBL_BUTTON_PORT=TRISE +DEFS += -DBL_LED2_INVERT +DEFS += -DBL_LED2_PIN=2 +DEFS += -DBL_LED2_PORT=TRISE +DEFS += -DBL_LED_PIN=3 +DEFS += -DBL_LED_PORT=TRISE +DEFS += -DBL_SET2_PIN=1 +DEFS += -DBL_SET2_PORT=TRISE +DEFS += -DBL_SET_PIN=0 +DEFS += -DBL_SET_PORT=TRISE +DEFS += -DBUS_DIV=1 +DEFS += -DBUS_KHZ='CPU_KHZ/BUS_DIV' +DEFS += -DCONSOLE_DEVICE=tty1 +DEFS += -DCPU_IDIV=2 +DEFS += -DCPU_KHZ='((CRYSTAL*1000)/CPU_IDIV*CPU_MUL/CPU_ODIV)' +DEFS += -DCPU_MUL=20 +DEFS += -DCPU_ODIV=1 +DEFS += -DCRYSTAL=8 +DEFS += -DDC0_DEBUG=DEVCFG0_DEBUG_DISABLED +DEFS += -DDC0_ICE=0 +DEFS += -DDC1_CKM=0 +DEFS += -DDC1_CKS=0 +DEFS += -DDC1_FNOSC=DEVCFG1_FNOSC_PRIPLL +DEFS += -DDC1_IESO=DEVCFG1_IESO +DEFS += -DDC1_OSCIOFNC=0 +DEFS += -DDC1_PBDIV=DEVCFG1_FPBDIV_1 +DEFS += -DDC1_POSCMOD=DEVCFG1_POSCMOD_HS +DEFS += -DDC1_SOSC=0 +DEFS += -DDC1_WDTEN=0 +DEFS += -DDC1_WDTPS=DEVCFG1_WDTPS_1 +DEFS += -DDC2_PLLIDIV=DEVCFG2_FPLLIDIV_2 +DEFS += -DDC2_PLLMUL=DEVCFG2_FPLLMUL_20 +DEFS += -DDC2_PLLODIV=DEVCFG2_FPLLODIV_1 +DEFS += -DDC2_UPLL=0 +DEFS += -DDC2_UPLLIDIV=DEVCFG2_UPLLIDIV_2 +DEFS += -DDC3_CAN=DEVCFG3_FCANIO +DEFS += -DDC3_ETH=DEVCFG3_FETHIO +DEFS += -DDC3_MII=DEVCFG3_FMIIEN +DEFS += -DDC3_SRS=DEVCFG3_FSRSSEL_7 +DEFS += -DDC3_USBID=DEVCFG3_FUSBIDIO +DEFS += -DDC3_USERID=0xffff +DEFS += -DDC3_VBUSON=DEVCFG3_FVBUSONIO +DEFS += -DFLASH_USER=0x1d005000 +DEFS += -DHID_FEATURE_REPORT_BYTES=2 +DEFS += -DHID_INPUT_REPORT_BYTES=2 +DEFS += -DHID_INT_IN_EP_SIZE=64 +DEFS += -DHID_INT_OUT_EP_SIZE=64 +DEFS += -DHID_OUTPUT_REPORT_BYTES=2 +DEFS += -DHID_RPT01_SIZE=29 +DEFS += -DKERNEL +DEFS += -DKERNEL_EXECUTABLE_RAM +DEFS += -DLED_DISK_INVERT=YES +DEFS += -DLED_DISK_PIN=9 +DEFS += -DLED_DISK_PORT=TRISB +DEFS += -DLED_KERNEL_INVERT=YES +DEFS += -DLED_KERNEL_PIN=10 +DEFS += -DLED_KERNEL_PORT=TRISB +DEFS += -DLED_SWAP_INVERT=YES +DEFS += -DLED_SWAP_PIN=8 +DEFS += -DLED_SWAP_PORT=TRISB +DEFS += -DLED_TTY_INVERT=YES +DEFS += -DLED_TTY_PIN=11 +DEFS += -DLED_TTY_PORT=TRISB +DEFS += -DPARTITION="sdramp0:sa@2048,fs@14000" +DEFS += -DPIC32MX7 +DEFS += -DSD0_CS_PIN=9 +DEFS += -DSD0_CS_PORT=TRISA +DEFS += -DSD0_PORT=2 +DEFS += -DSDRAMP_ENABLED=YES +DEFS += -DUART2_ENABLED=YES +DEFS += -DUCB_METER +DEFS += -DUSB_EP0_BUFF_SIZE=8 +DEFS += -DUSB_MAX_EP_NUMBER=1 +DEFS += -DUSB_NUM_STRING_DESCRIPTORS=3 + + +LDSCRIPT = ../../../tools/configsys/../../sys/pic32/cfg/bootloader-sdram.ld + +CONFIG = UBW32-UART-SDRAM +CONFIGPATH = ../../../tools/configsys + +include ../../../tools/configsys/../../sys/pic32/kernel-post.mk diff --git a/sys/pic32/ubw32-uart-sdram/UBW32-UART-SDRAM b/sys/pic32/ubw32-uart-sdram/UBW32-UART-SDRAM new file mode 100644 index 0000000..5335dc8 --- /dev/null +++ b/sys/pic32/ubw32-uart-sdram/UBW32-UART-SDRAM @@ -0,0 +1,20 @@ +# +# UBW32 board +# =========== +# +# Console on UART2 + +core pic32mx7 +linker bootloader-sdram +mapping generic + +device kernel invled=B10 +device console invled=B11 device=tty1 +device uart2 +device rdisk invled=B9 invswap=B8 +device sd0 port=2 cs=A9 +device sdramp + +option PARTITION=sdramp0:sa@2048,fs@14000 + +device bootloader button=E7 user=0x1d005000 led=E3 invled2=E2 set=E0 set2=E1 diff --git a/sys/pic32/ubw32-uart-sdram/using-bootloader-ker.ld b/sys/pic32/ubw32-uart-sdram/using-bootloader-ker.ld new file mode 100644 index 0000000..4790af9 --- /dev/null +++ b/sys/pic32/ubw32-uart-sdram/using-bootloader-ker.ld @@ -0,0 +1,134 @@ +/* + * Linker script for PIC32 firmware using HID bootloader. + */ +OUTPUT_FORMAT("elf32-littlemips", "elf32-bigmips", + "elf32-littlemips") +OUTPUT_ARCH(mips) +ENTRY(_reset_vector_) +MEMORY +{ + flash (rx) : ORIGIN = 0x9d005000, LENGTH = 492K + ram (rw!x): ORIGIN = 0x80000000, LENGTH = 0x62C0 + u0area (rw!x): ORIGIN = 0x800062C0, LENGTH = 3K + uarea (rw!x): ORIGIN = 0x80006EC0, LENGTH = 3K + keram (rwx) : ORIGIN = 0x80007AC0, LENGTH = 0x540 + + /* Required by Microchip C32 linker */ + kseg0_program_mem (rx) : ORIGIN = 0x9D000000, LENGTH = 0x80000 + kseg0_boot_mem : ORIGIN = 0x9FC00490, LENGTH = 0x970 + exception_mem : ORIGIN = 0x9FC01000, LENGTH = 0x1000 + kseg1_boot_mem : ORIGIN = 0xBFC00000, LENGTH = 0x490 + kseg1_data_mem (w!x) : ORIGIN = 0xA0000000, LENGTH = 0x20000 +} + +/* higher address of the user mode stack */ +u0 = ORIGIN(u0area); +u = ORIGIN(uarea); +u_end = ORIGIN(uarea) + LENGTH(uarea); + +_keram_start = ORIGIN(keram); +_keram_end = ORIGIN(keram) + LENGTH(keram); + +SECTIONS +{ + .text ORIGIN(flash) : + { + /* Exception handlers. */ + *(.exception) + . = 0x1000; + /* Execution starts here. */ + *(.startup) + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.glue_7t) *(.glue_7) + __rodata_start = . ; + *(.rodata .rodata.* .gnu.linkonce.r.* .rel.dyn) + *(.dinit) + /* Align here to ensure that the .text section ends on word boundary. */ + . = ALIGN (32 / 8); + _etext = .; + } > flash + + /* Start data (internal SRAM). */ + .data : AT (ADDR (.text) + SIZEOF (.text)) + { + __data_start = . ; + _gp = .; /* We use only 32k RAM for kernel, so no need for 0x8000 offset. */ + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + *(.sdata .sdata.* .gnu.linkonce.s.*) + *(.data .data.* .gnu.linkonce.d.*) + *(.eh_frame) + _edata = .; + } > ram + + .bss ADDR (.data) + SIZEOF (.data) (NOLOAD) : + { + __bss_start = .; + *(.dynbss) + *(.sbss .sbss.*) + *(.scommon) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. */ + . = ALIGN (32 / 8); + } > ram + __bss_end = . ; + _end = .; + +/* + * RAM functions go at the end of our stack and heap allocation. + * Alignment of 2K required by the boundary register (BMXDKPBA). + */ + .ramfunc : AT (LOADADDR (.data) + SIZEOF (.data)) + { + _ramfunc_begin = . ; + *(.ramfunc .ramfunc.*) + . = ALIGN(4) ; + _ramfunc_end = . ; + } >keram + _ramfunc_image_begin = LOADADDR(.ramfunc) ; + _ramfunc_length = SIZEOF(.ramfunc) ; + + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + .debug_pubtypes 0 : { *(.debug_pubtypes) } + .debug_ranges 0 : { *(.debug_ranges) } + .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) } +} diff --git a/sys/pic32/ubw32-uart-sdram/using-bootloader.ld b/sys/pic32/ubw32-uart-sdram/using-bootloader.ld new file mode 100644 index 0000000..81ba7d2 --- /dev/null +++ b/sys/pic32/ubw32-uart-sdram/using-bootloader.ld @@ -0,0 +1,115 @@ +/* + * Linker script for PIC32 firmware using HID bootloader. + */ +OUTPUT_FORMAT("elf32-littlemips", "elf32-bigmips", + "elf32-littlemips") +OUTPUT_ARCH(mips) +ENTRY(_reset_vector_) +MEMORY +{ + flash (rx) : ORIGIN = 0x9d005000, LENGTH = 492K + ram (rw!x): ORIGIN = 0x80000000, LENGTH = 26K + u0area (rw!x): ORIGIN = 0x80006800, LENGTH = 3K + uarea (rw!x): ORIGIN = 0x80007400, LENGTH = 3K + + /* Required by Microchip C32 linker */ + kseg0_program_mem (rx) : ORIGIN = 0x9D000000, LENGTH = 0x80000 + kseg0_boot_mem : ORIGIN = 0x9FC00490, LENGTH = 0x970 + exception_mem : ORIGIN = 0x9FC01000, LENGTH = 0x1000 + kseg1_boot_mem : ORIGIN = 0xBFC00000, LENGTH = 0x490 + kseg1_data_mem (w!x) : ORIGIN = 0xA0000000, LENGTH = 0x20000 +} + +/* higher address of the user mode stack */ +u0 = ORIGIN(u0area); +u = ORIGIN(uarea); +u_end = ORIGIN(uarea) + LENGTH(uarea); + +SECTIONS +{ + .text ORIGIN(flash) : + { + /* Exception handlers. */ + *(.exception) + . = 0x1000; + /* Execution starts here. */ + *(.startup) + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.glue_7t) *(.glue_7) + __rodata_start = . ; + *(.rodata .rodata.* .gnu.linkonce.r.* .rel.dyn) + *(.dinit) + /* Align here to ensure that the .text section ends on word boundary. */ + . = ALIGN (32 / 8); + _etext = .; + } > flash + + /* Start data (internal SRAM). */ + .data : AT (ADDR (.text) + SIZEOF (.text)) + { + __data_start = . ; + _gp = .; /* We use only 32k RAM for kernel, so no need for 0x8000 offset. */ + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + *(.sdata .sdata.* .gnu.linkonce.s.*) + *(.data .data.* .gnu.linkonce.d.*) + *(.eh_frame) + _edata = .; + } > ram + + .bss ADDR (.data) + SIZEOF (.data) (NOLOAD) : + { + __bss_start = .; + *(.dynbss) + *(.sbss) + *(.scommon) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. */ + . = ALIGN (32 / 8); + } > ram + __bss_end = . ; + _end = .; + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + .debug_pubtypes 0 : { *(.debug_pubtypes) } + .debug_ranges 0 : { *(.debug_ranges) } + .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) } +} diff --git a/sys/pic32/ubw32-uart/Makefile b/sys/pic32/ubw32-uart/Makefile new file mode 100644 index 0000000..b8d8588 --- /dev/null +++ b/sys/pic32/ubw32-uart/Makefile @@ -0,0 +1,95 @@ +BUILDPATH = ../../../tools/configsys/../../sys/pic32 +H = ../../../tools/configsys/../../sys/include +M = ../../../tools/configsys/../../sys/pic32 +S = ../../../tools/configsys/../../sys/kernel + +vpath %.c $(M):$(S) +vpath %.S $(M):$(S) + +KERNOBJ += _startup.o clock.o cons.o devsw.o exception.o gpio.o init_main.o init_sysent.o kern_clock.o kern_descrip.o kern_exec.o kern_exit.o kern_fork.o kern_mman.o kern_proc.o kern_prot.o kern_prot2.o kern_resource.o kern_sig.o kern_sig2.o kern_subr.o kern_synch.o kern_sysctl.o kern_time.o machdep.o mem.o rd_sd.o rdisk.o signal.o spi_bus.o subr_prf.o subr_rmap.o swap.o sys_generic.o sys_inode.o sys_pipe.o sys_process.o syscalls.o sysctl.o tty.o tty_subr.o tty_tty.o uart.o ufs_alloc.o ufs_bio.o ufs_bmap.o ufs_dsort.o ufs_fio.o ufs_inode.o ufs_mount.o ufs_namei.o ufs_subr.o ufs_syscalls.o ufs_syscalls2.o vers.o vfs_vnops.o vm_sched.o vm_swap.o vm_swp.o +EXTRA_TARGETS = bootloader + +DEFS += -DBL_BUTTON_PIN=7 +DEFS += -DBL_BUTTON_PORT=TRISE +DEFS += -DBL_LED2_INVERT +DEFS += -DBL_LED2_PIN=2 +DEFS += -DBL_LED2_PORT=TRISE +DEFS += -DBL_LED_PIN=3 +DEFS += -DBL_LED_PORT=TRISE +DEFS += -DBL_SET2_PIN=1 +DEFS += -DBL_SET2_PORT=TRISE +DEFS += -DBL_SET_PIN=0 +DEFS += -DBL_SET_PORT=TRISE +DEFS += -DBUS_DIV=1 +DEFS += -DBUS_KHZ='CPU_KHZ/BUS_DIV' +DEFS += -DCONSOLE_DEVICE=tty1 +DEFS += -DCPU_IDIV=2 +DEFS += -DCPU_KHZ='((CRYSTAL*1000)/CPU_IDIV*CPU_MUL/CPU_ODIV)' +DEFS += -DCPU_MUL=20 +DEFS += -DCPU_ODIV=1 +DEFS += -DCRYSTAL=8 +DEFS += -DDC0_DEBUG=DEVCFG0_DEBUG_DISABLED +DEFS += -DDC0_ICE=0 +DEFS += -DDC1_CKM=0 +DEFS += -DDC1_CKS=0 +DEFS += -DDC1_FNOSC=DEVCFG1_FNOSC_PRIPLL +DEFS += -DDC1_IESO=DEVCFG1_IESO +DEFS += -DDC1_OSCIOFNC=0 +DEFS += -DDC1_PBDIV=DEVCFG1_FPBDIV_1 +DEFS += -DDC1_POSCMOD=DEVCFG1_POSCMOD_HS +DEFS += -DDC1_SOSC=0 +DEFS += -DDC1_WDTEN=0 +DEFS += -DDC1_WDTPS=DEVCFG1_WDTPS_1 +DEFS += -DDC2_PLLIDIV=DEVCFG2_FPLLIDIV_2 +DEFS += -DDC2_PLLMUL=DEVCFG2_FPLLMUL_20 +DEFS += -DDC2_PLLODIV=DEVCFG2_FPLLODIV_1 +DEFS += -DDC2_UPLL=0 +DEFS += -DDC2_UPLLIDIV=DEVCFG2_UPLLIDIV_2 +DEFS += -DDC3_CAN=DEVCFG3_FCANIO +DEFS += -DDC3_ETH=DEVCFG3_FETHIO +DEFS += -DDC3_MII=DEVCFG3_FMIIEN +DEFS += -DDC3_SRS=DEVCFG3_FSRSSEL_7 +DEFS += -DDC3_USBID=DEVCFG3_FUSBIDIO +DEFS += -DDC3_USERID=0xffff +DEFS += -DDC3_VBUSON=DEVCFG3_FVBUSONIO +DEFS += -DFLASH_USER=0x1d005000 +DEFS += -DGPIO_ENABLED=YES +DEFS += -DHID_FEATURE_REPORT_BYTES=2 +DEFS += -DHID_INPUT_REPORT_BYTES=2 +DEFS += -DHID_INT_IN_EP_SIZE=64 +DEFS += -DHID_INT_OUT_EP_SIZE=64 +DEFS += -DHID_OUTPUT_REPORT_BYTES=2 +DEFS += -DHID_RPT01_SIZE=29 +DEFS += -DKERNEL +DEFS += -DLED_DISK_INVERT=YES +DEFS += -DLED_DISK_PIN=1 +DEFS += -DLED_DISK_PORT=TRISE +DEFS += -DLED_KERNEL_INVERT=YES +DEFS += -DLED_KERNEL_PIN=2 +DEFS += -DLED_KERNEL_PORT=TRISE +DEFS += -DLED_SWAP_INVERT=YES +DEFS += -DLED_SWAP_PIN=0 +DEFS += -DLED_SWAP_PORT=TRISE +DEFS += -DLED_TTY_INVERT=YES +DEFS += -DLED_TTY_PIN=3 +DEFS += -DLED_TTY_PORT=TRISE +DEFS += -DPIC32MX7 +DEFS += -DSD0_CS_PIN=9 +DEFS += -DSD0_CS_PORT=TRISA +DEFS += -DSD0_PORT=1 +DEFS += -DSD1_CS_PIN=10 +DEFS += -DSD1_CS_PORT=TRISA +DEFS += -DSD1_PORT=1 +DEFS += -DUART2_ENABLED=YES +DEFS += -DUCB_METER +DEFS += -DUSB_EP0_BUFF_SIZE=8 +DEFS += -DUSB_MAX_EP_NUMBER=1 +DEFS += -DUSB_NUM_STRING_DESCRIPTORS=3 + + +LDSCRIPT = ../../../tools/configsys/../../sys/pic32/cfg/bootloader-ubw32.ld + +CONFIG = UBW32-UART +CONFIGPATH = ../../../tools/configsys + +include ../../../tools/configsys/../../sys/pic32/kernel-post.mk diff --git a/sys/pic32/ubw32-uart/UBW32-UART b/sys/pic32/ubw32-uart/UBW32-UART new file mode 100644 index 0000000..320f5ff --- /dev/null +++ b/sys/pic32/ubw32-uart/UBW32-UART @@ -0,0 +1,21 @@ +# +# UBW32 board +# =========== +# +# Console on UART2 + +core pic32mx7 +linker bootloader-ubw32 +mapping generic + +device kernel invled=E2 + +device console invled=E3 device=tty1 +device uart2 + +device rdisk invled=E1 invswap=E0 +device sd0 port=1 cs=A9 +device sd1 port=1 cs=A10 + +device gpio +device bootloader button=E7 user=0x1d005000 led=E3 invled2=E2 set=E0 set2=E1 diff --git a/sys/pic32/ubw32-uart/using-bootloader.ld b/sys/pic32/ubw32-uart/using-bootloader.ld new file mode 100644 index 0000000..6b0b5f5 --- /dev/null +++ b/sys/pic32/ubw32-uart/using-bootloader.ld @@ -0,0 +1,115 @@ +/* + * Linker script for PIC32 firmware using HID bootloader. + */ +OUTPUT_FORMAT("elf32-littlemips", "elf32-bigmips", + "elf32-littlemips") +OUTPUT_ARCH(mips) +ENTRY(_reset_vector_) +MEMORY +{ + flash (rx) : ORIGIN = 0x9d005000, LENGTH = 492K + ram (rw!x): ORIGIN = 0x80000000, LENGTH = 26K + u0area (rw!x): ORIGIN = 0x80006800, LENGTH = 3K + uarea (rw!x): ORIGIN = 0x80007400, LENGTH = 3K + + /* Required by Microchip C32 linker */ + kseg0_program_mem (rx) : ORIGIN = 0x9D000000, LENGTH = 0x80000 + kseg0_boot_mem : ORIGIN = 0x9FC00490, LENGTH = 0x970 + exception_mem : ORIGIN = 0x9FC01000, LENGTH = 0x1000 + kseg1_boot_mem : ORIGIN = 0xBFC00000, LENGTH = 0x490 + kseg1_data_mem (w!x) : ORIGIN = 0xA0000000, LENGTH = 0x20000 +} + +/* higher address of the user mode stack */ +u0 = ORIGIN(u0area); +u = ORIGIN(uarea); +u_end = ORIGIN(uarea) + LENGTH(uarea); + +SECTIONS +{ + .text ORIGIN(flash) : + { + /* Exception handlers. */ + *(.exception) + . = 0x1000; + /* Execution starts here. */ + *(.startup) + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.glue_7t) *(.glue_7) + __rodata_start = . ; + *(.rodata .rodata.* .gnu.linkonce.r.* .rel.dyn) + *(.dinit) + /* Align here to ensure that the .text section ends on word boundary. */ + . = ALIGN (32 / 8); + _etext = .; + } > flash + + /* Start data (internal SRAM). */ + .data : AT (ADDR (.text) + SIZEOF (.text)) + { + __data_start = . ; + _gp = .; /* We use only 32k RAM for kernel, so no need for 0x8000 offset. */ + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + *(.sdata .sdata.* .gnu.linkonce.s.*) + *(.data .data.* .gnu.linkonce.d.*) + *(.eh_frame) + _edata = .; + } > ram + + .bss ADDR (.data) + SIZEOF (.data) (NOLOAD) : + { + __bss_start = .; + *(.dynbss) + *(.sbss .sbss.*) + *(.scommon) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. */ + . = ALIGN (32 / 8); + } > ram + __bss_end = . ; + _end = .; + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + .debug_pubtypes 0 : { *(.debug_pubtypes) } + .debug_ranges 0 : { *(.debug_ranges) } + .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) } +} diff --git a/sys/pic32/ubw32/Makefile b/sys/pic32/ubw32/Makefile new file mode 100644 index 0000000..8801812 --- /dev/null +++ b/sys/pic32/ubw32/Makefile @@ -0,0 +1,95 @@ +BUILDPATH = ../../../tools/configsys/../../sys/pic32 +H = ../../../tools/configsys/../../sys/include +M = ../../../tools/configsys/../../sys/pic32 +S = ../../../tools/configsys/../../sys/kernel + +vpath %.c $(M):$(S) +vpath %.S $(M):$(S) + +KERNOBJ += _startup.o clock.o cons.o devsw.o exception.o gpio.o init_main.o init_sysent.o kern_clock.o kern_descrip.o kern_exec.o kern_exit.o kern_fork.o kern_mman.o kern_proc.o kern_prot.o kern_prot2.o kern_resource.o kern_sig.o kern_sig2.o kern_subr.o kern_synch.o kern_sysctl.o kern_time.o machdep.o mem.o rd_sd.o rdisk.o signal.o spi_bus.o subr_prf.o subr_rmap.o swap.o sys_generic.o sys_inode.o sys_pipe.o sys_process.o syscalls.o sysctl.o tty.o tty_subr.o tty_tty.o ufs_alloc.o ufs_bio.o ufs_bmap.o ufs_dsort.o ufs_fio.o ufs_inode.o ufs_mount.o ufs_namei.o ufs_subr.o ufs_syscalls.o ufs_syscalls2.o usb_device.o usb_function_cdc.o usb_uart.o vers.o vfs_vnops.o vm_sched.o vm_swap.o vm_swp.o +EXTRA_TARGETS = bootloader + +DEFS += -DBL_BUTTON_PIN=7 +DEFS += -DBL_BUTTON_PORT=TRISE +DEFS += -DBL_LED2_INVERT +DEFS += -DBL_LED2_PIN=2 +DEFS += -DBL_LED2_PORT=TRISE +DEFS += -DBL_LED_PIN=3 +DEFS += -DBL_LED_PORT=TRISE +DEFS += -DBL_SET2_PIN=1 +DEFS += -DBL_SET2_PORT=TRISE +DEFS += -DBL_SET_PIN=0 +DEFS += -DBL_SET_PORT=TRISE +DEFS += -DBUS_DIV=1 +DEFS += -DBUS_KHZ='CPU_KHZ/BUS_DIV' +DEFS += -DCONSOLE_DEVICE=ttyUSB0 +DEFS += -DCPU_IDIV=2 +DEFS += -DCPU_KHZ='((CRYSTAL*1000)/CPU_IDIV*CPU_MUL/CPU_ODIV)' +DEFS += -DCPU_MUL=20 +DEFS += -DCPU_ODIV=1 +DEFS += -DCRYSTAL=8 +DEFS += -DDC0_DEBUG=DEVCFG0_DEBUG_DISABLED +DEFS += -DDC0_ICE=0 +DEFS += -DDC1_CKM=0 +DEFS += -DDC1_CKS=0 +DEFS += -DDC1_FNOSC=DEVCFG1_FNOSC_PRIPLL +DEFS += -DDC1_IESO=DEVCFG1_IESO +DEFS += -DDC1_OSCIOFNC=0 +DEFS += -DDC1_PBDIV=DEVCFG1_FPBDIV_1 +DEFS += -DDC1_POSCMOD=DEVCFG1_POSCMOD_HS +DEFS += -DDC1_SOSC=0 +DEFS += -DDC1_WDTEN=0 +DEFS += -DDC1_WDTPS=DEVCFG1_WDTPS_1 +DEFS += -DDC2_PLLIDIV=DEVCFG2_FPLLIDIV_2 +DEFS += -DDC2_PLLMUL=DEVCFG2_FPLLMUL_20 +DEFS += -DDC2_PLLODIV=DEVCFG2_FPLLODIV_1 +DEFS += -DDC2_UPLL=0 +DEFS += -DDC2_UPLLIDIV=DEVCFG2_UPLLIDIV_2 +DEFS += -DDC3_CAN=DEVCFG3_FCANIO +DEFS += -DDC3_ETH=DEVCFG3_FETHIO +DEFS += -DDC3_MII=DEVCFG3_FMIIEN +DEFS += -DDC3_SRS=DEVCFG3_FSRSSEL_7 +DEFS += -DDC3_USBID=DEVCFG3_FUSBIDIO +DEFS += -DDC3_USERID=0xffff +DEFS += -DDC3_VBUSON=DEVCFG3_FVBUSONIO +DEFS += -DFLASH_USER=0x1d005000 +DEFS += -DGPIO_ENABLED=YES +DEFS += -DHID_FEATURE_REPORT_BYTES=2 +DEFS += -DHID_INPUT_REPORT_BYTES=2 +DEFS += -DHID_INT_IN_EP_SIZE=64 +DEFS += -DHID_INT_OUT_EP_SIZE=64 +DEFS += -DHID_OUTPUT_REPORT_BYTES=2 +DEFS += -DHID_RPT01_SIZE=29 +DEFS += -DKERNEL +DEFS += -DLED_DISK_INVERT=YES +DEFS += -DLED_DISK_PIN=1 +DEFS += -DLED_DISK_PORT=TRISE +DEFS += -DLED_KERNEL_INVERT=YES +DEFS += -DLED_KERNEL_PIN=2 +DEFS += -DLED_KERNEL_PORT=TRISE +DEFS += -DLED_SWAP_INVERT=YES +DEFS += -DLED_SWAP_PIN=0 +DEFS += -DLED_SWAP_PORT=TRISE +DEFS += -DLED_TTY_INVERT=YES +DEFS += -DLED_TTY_PIN=3 +DEFS += -DLED_TTY_PORT=TRISE +DEFS += -DPIC32MX7 +DEFS += -DSD0_CS_PIN=9 +DEFS += -DSD0_CS_PORT=TRISA +DEFS += -DSD0_PORT=1 +DEFS += -DSD1_CS_PIN=10 +DEFS += -DSD1_CS_PORT=TRISA +DEFS += -DSD1_PORT=1 +DEFS += -DUARTUSB_ENABLED=YES +DEFS += -DUCB_METER +DEFS += -DUSB_EP0_BUFF_SIZE=8 +DEFS += -DUSB_MAX_EP_NUMBER=3 +DEFS += -DUSB_NUM_STRING_DESCRIPTORS=3 + + +LDSCRIPT = ../../../tools/configsys/../../sys/pic32/cfg/bootloader-ubw32.ld + +CONFIG = UBW32 +CONFIGPATH = ../../../tools/configsys + +include ../../../tools/configsys/../../sys/pic32/kernel-post.mk diff --git a/sys/pic32/ubw32/UBW32 b/sys/pic32/ubw32/UBW32 new file mode 100644 index 0000000..0dfa0af --- /dev/null +++ b/sys/pic32/ubw32/UBW32 @@ -0,0 +1,23 @@ +# +# UBW32 board +# =========== +# +# Console on USB +# For Windows, use the driver: http://www.schmalzhaus.com/UBW32/FW/UBW32inf.zip + +core pic32mx7 +linker bootloader-ubw32 +mapping generic + +device kernel invled=E2 + +device console invled=E3 device=ttyUSB0 +device uartusb + +device rdisk invled=E1 invswap=E0 +device sd0 port=1 cs=A9 +device sd1 port=1 cs=A10 + +device gpio + +device bootloader button=E7 user=0x1d005000 led=E3 invled2=E2 set=E0 set2=E1 diff --git a/sys/pic32/ubw32/using-bootloader.ld b/sys/pic32/ubw32/using-bootloader.ld new file mode 100644 index 0000000..6b0b5f5 --- /dev/null +++ b/sys/pic32/ubw32/using-bootloader.ld @@ -0,0 +1,115 @@ +/* + * Linker script for PIC32 firmware using HID bootloader. + */ +OUTPUT_FORMAT("elf32-littlemips", "elf32-bigmips", + "elf32-littlemips") +OUTPUT_ARCH(mips) +ENTRY(_reset_vector_) +MEMORY +{ + flash (rx) : ORIGIN = 0x9d005000, LENGTH = 492K + ram (rw!x): ORIGIN = 0x80000000, LENGTH = 26K + u0area (rw!x): ORIGIN = 0x80006800, LENGTH = 3K + uarea (rw!x): ORIGIN = 0x80007400, LENGTH = 3K + + /* Required by Microchip C32 linker */ + kseg0_program_mem (rx) : ORIGIN = 0x9D000000, LENGTH = 0x80000 + kseg0_boot_mem : ORIGIN = 0x9FC00490, LENGTH = 0x970 + exception_mem : ORIGIN = 0x9FC01000, LENGTH = 0x1000 + kseg1_boot_mem : ORIGIN = 0xBFC00000, LENGTH = 0x490 + kseg1_data_mem (w!x) : ORIGIN = 0xA0000000, LENGTH = 0x20000 +} + +/* higher address of the user mode stack */ +u0 = ORIGIN(u0area); +u = ORIGIN(uarea); +u_end = ORIGIN(uarea) + LENGTH(uarea); + +SECTIONS +{ + .text ORIGIN(flash) : + { + /* Exception handlers. */ + *(.exception) + . = 0x1000; + /* Execution starts here. */ + *(.startup) + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.glue_7t) *(.glue_7) + __rodata_start = . ; + *(.rodata .rodata.* .gnu.linkonce.r.* .rel.dyn) + *(.dinit) + /* Align here to ensure that the .text section ends on word boundary. */ + . = ALIGN (32 / 8); + _etext = .; + } > flash + + /* Start data (internal SRAM). */ + .data : AT (ADDR (.text) + SIZEOF (.text)) + { + __data_start = . ; + _gp = .; /* We use only 32k RAM for kernel, so no need for 0x8000 offset. */ + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + *(.sdata .sdata.* .gnu.linkonce.s.*) + *(.data .data.* .gnu.linkonce.d.*) + *(.eh_frame) + _edata = .; + } > ram + + .bss ADDR (.data) + SIZEOF (.data) (NOLOAD) : + { + __bss_start = .; + *(.dynbss) + *(.sbss .sbss.*) + *(.scommon) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. */ + . = ALIGN (32 / 8); + } > ram + __bss_end = . ; + _end = .; + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + .debug_pubtypes 0 : { *(.debug_pubtypes) } + .debug_ranges 0 : { *(.debug_ranges) } + .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) } +} diff --git a/sys/pic32/usb_boot.c b/sys/pic32/usb_boot.c new file mode 100644 index 0000000..645b039 --- /dev/null +++ b/sys/pic32/usb_boot.c @@ -0,0 +1,837 @@ +/* + * USB HID bootloader for PIC32 microcontroller. + * + * Based on Microchip sources. + * Heavily rewritten by Serge Vakulenko, . + * + * The software supplied herewith by Microchip Technology Incorporated + * (the 'Company') for its PIC(R) Microcontroller is intended and + * supplied to you, the Company's customer, for use solely and + * exclusively on Microchip PIC Microcontroller products. The + * software is owned by the Company and/or its supplier, and is + * protected under applicable copyright laws. All rights are reserved. + * Any use in violation of the foregoing restrictions may subject the + * user to criminal sanctions under applicable laws, as well as to + * civil liability for the breach of the terms and conditions of this license. + * + * THIS SOFTWARE IS PROVIDED IN AN 'AS IS' CONDITION. NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED + * TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE COMPANY SHALL NOT, + * IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR + * CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER. + */ +#include +#include +#include +#include + +/* + * Flash memory. + */ +#define FLASH_BASE 0x1D000000 /* physical */ + +#ifndef FLASH_USER +# define FLASH_USER FLASH_BASE /* physical: beginning of user application */ +#endif + +#ifndef FLASH_JUMP /* virtual: start of application */ +# define FLASH_JUMP (FLASH_USER + 0x80001000) +#endif + +#define FLASH_PAGESZ 4096 /* bytes per page, for erasing */ + +/* + * Commands of bootloader protocol. + */ +#define QUERY_DEVICE 0x02 // Command that the host uses to learn + // about the device (what regions can be + // programmed, and what type of memory + // is the region) +#define UNLOCK_CONFIG 0x03 // Note, this command is used for both + // locking and unlocking the config bits +#define ERASE_DEVICE 0x04 // Host sends this command to start + // an erase operation. Firmware controls + // which pages should be erased. +#define PROGRAM_DEVICE 0x05 // If host is going to send a full + // REQUEST_SIZE to be programmed, it + // uses this command. +#define PROGRAM_COMPLETE 0x06 // If host send less than a REQUEST_SIZE + // to be programmed, or if it wished + // to program whatever was left in + // the buffer, it uses this command. +#define GET_DATA 0x07 // The host sends this command in order + // to read out memory from the device. + // Used during verify (and read/export + // hex operations) +#define RESET_DEVICE 0x08 // Resets the microcontroller, so it can + // update the config bits (if they were + // programmed, and so as to leave + // the bootloader (and potentially go back + // into the main application) + +/* + * HID packet structure. + */ +#define PACKET_SIZE 64 // HID packet size +#define REQUEST_SIZE 56 // Number of bytes of a standard request + +typedef union __attribute__ ((packed)) +{ + unsigned char Contents [PACKET_SIZE]; + + struct __attribute__ ((packed)) { + unsigned char Command; + unsigned Address; + unsigned char Size; + unsigned char PadBytes [PACKET_SIZE - 6 - REQUEST_SIZE]; + unsigned int Data [REQUEST_SIZE / sizeof(unsigned)]; + }; + + struct __attribute__ ((packed)) { + unsigned char Command; + unsigned char PacketDataFieldSize; + unsigned char DeviceFamily; + unsigned char Type1; + unsigned long Address1; + unsigned long Length1; + unsigned char Type2; + unsigned long Address2; + unsigned long Length2; + unsigned char Type3; + unsigned long Address3; + unsigned long Length3; + unsigned char Type4; // End of sections list indicator goes here, fill with 0xFF. + unsigned char ExtraPadBytes[33]; + }; +} packet_t; + +static packet_t send; // 64-byte send buffer (EP1 IN to the PC) +static packet_t receive_buffer; // 64-byte receive buffer (EP1 OUT from the PC) +static packet_t receive; // copy of receive buffer, for processing + +static USB_HANDLE request_handle; + +/* + * Placed at fixed address 0x80000000 by linker. + * To enter boot mode from user program, set this value + * to 0x12345678 and perform a software reset. + */ +unsigned int reset_key + __attribute__((section(".sdata"))); + +static unsigned int buf [32]; +static unsigned int buf_index; +static unsigned int base_address; + +/* + * GPIO pin control. + */ +#define TRIS_VAL(p) (&p)[0] +#define TRIS_CLR(p) (&p)[1] +#define TRIS_SET(p) (&p)[2] +#define TRIS_INV(p) (&p)[3] +#define PORT_VAL(p) (&p)[4] +#define PORT_CLR(p) (&p)[5] +#define PORT_SET(p) (&p)[6] +#define PORT_INV(p) (&p)[7] +#define LAT_VAL(p) (&p)[8] +#define LAT_CLR(p) (&p)[9] +#define LAT_SET(p) (&p)[10] +#define LAT_INV(p) (&p)[11] + +/* + * Boot code. + */ +asm (" .section .startup,\"ax\",@progbits"); +asm (" .globl _start"); +asm (" .type _start, function"); +asm ("_start: la $sp, _estack"); +asm (" la $ra, main"); +asm (" la $gp, _gp"); +asm (" jr $ra"); +asm (" .text"); + +/* + * A single button is used to control the bootloader mode. + * Configured by parameters: + * BL_BUTTON_PORT = TRISA ... TRISG + * BL_BUTTON_PIN = 0 ... 15 + */ +static inline void button_init() +{ + TRIS_SET(BL_BUTTON_PORT) = 1 << BL_BUTTON_PIN; +} + +static inline int button_pressed() +{ + return ! (PORT_VAL(BL_BUTTON_PORT) & (1 << BL_BUTTON_PIN)); +} + +/* + * Up to three LEDs can be used to indicate a bootloader mode. + * Configured by parameters: + * - first LED: BL_LED_PORT, BL_LED_PIN, BL_LED_INVERT + * - second LED: BL_LED2_PORT, BL_LED2_PIN, BL_LED2_INVERT + * - third LED: BL_LED3_PORT, BL_LED3_PIN, BL_LED3_INVERT + * + * Additionally, up to two output signals can be set or cleared at startup. + * Configured by parameters: + * BL_SET_PORT, BL_SET_PIN + * BL_SET2_PORT, BL_SET2_PIN + * BL_CLEAR_PORT, BL_CLEAR_PIN + * BL_CLEAR2_PORT, BL_CLEAR2_PIN + * + * Settings for UBW32 board: + * - first LED is E2, inverted + * - second LED is E3 + * - set signals E0 and E1 + * + * For Maximite board: + * - LED is E1, inverted + * - clear signal F0 + * + * For eflightworks DIP board: + * - first LED is E6, inverted + * - second LED is E7 + * - clear signals E4 and E5 + * + * For PIC32 Starter Kit board: + * - first LED is D0 + * - second LED is D1, inverted + * - third LED is D2, inverted + */ +static inline void led_init() +{ + /* First LED. */ +#ifdef BL_LED_INVERT + LAT_SET(BL_LED_PORT) = 1 << BL_LED_PIN; +#else + LAT_CLR(BL_LED_PORT) = 1 << BL_LED_PIN; +#endif + TRIS_CLR(BL_LED_PORT) = 1 << BL_LED_PIN; + + /* Optional second LED. */ +#ifdef BL_LED2_PORT +#ifdef BL_LED2_INVERT + LAT_SET(BL_LED2_PORT) = 1 << BL_LED2_PIN; +#else + LAT_CLR(BL_LED2_PORT) = 1 << BL_LED2_PIN; +#endif + TRIS_CLR(BL_LED2_PORT) = 1 << BL_LED2_PIN; +#endif + + /* Optional third LED. */ +#ifdef BL_LED3_PORT +#ifdef BL_LED3_INVERT + LAT_SET(BL_LED3_PORT) = 1 << BL_LED3_PIN; +#else + LAT_CLR(BL_LED3_PORT) = 1 << BL_LED3_PIN; +#endif + TRIS_CLR(BL_LED3_PORT) = 1 << BL_LED3_PIN; +#endif + + /* Additional signals. */ +#ifdef BL_SET_PORT + LAT_SET(BL_SET_PORT) = 1 << BL_SET_PIN; + TRIS_CLR(BL_SET_PORT) = 1 << BL_SET_PIN; +#endif +#ifdef BL_SET2_PORT + LAT_SET(BL_SET2_PORT) = 1 << BL_SET2_PIN; + TRIS_CLR(BL_SET2_PORT) = 1 << BL_SET2_PIN; +#endif +#ifdef BL_CLEAR_PORT + LAT_CLR(BL_CLEAR_PORT) = 1 << BL_CLEAR_PIN; + TRIS_CLR(BL_CLEAR_PORT) = 1 << BL_CLEAR_PIN; +#endif +#ifdef BL_CLEAR2_PORT + LAT_CLR(BL_CLEAR2_PORT) = 1 << BL_CLEAR2_PIN; + TRIS_CLR(BL_CLEAR2_PORT) = 1 << BL_CLEAR2_PIN; +#endif +} + +static inline void led_toggle() +{ + /* First LED. */ + LAT_INV(BL_LED_PORT) = 1 << BL_LED_PIN; + + /* Optional second LED. */ +#ifdef BL_LED2_PORT + LAT_INV(BL_LED2_PORT) = 1 << BL_LED2_PIN; +#endif + + /* Optional third LED. */ +#ifdef BL_LED3_PORT + LAT_INV(BL_LED3_PORT) = 1 << BL_LED3_PIN; +#endif +} + +#if 0 +/* + * Printing to UART. + * These functions are useful for debugging a bootloader. + */ +static inline void cinit() +{ + /* + * Setup UART registers. + * Compute the divisor for 115.2 kbaud. + */ + U1BRG = PIC32_BRG_BAUD (CPU_KHZ * 1000, 115200); + U1STA = 0; + U1MODE = PIC32_UMODE_PDSEL_8NPAR | /* 8-bit data, no parity */ + PIC32_UMODE_ON; /* UART Enable */ + U1STASET = PIC32_USTA_URXEN | /* Receiver Enable */ + PIC32_USTA_UTXEN; /* Transmit Enable */ +} + +/* + * Send a byte to the UART transmitter. + */ +static void cputc (int c) +{ + /* Wait for transmitter shift register empty. */ + while (! (U1STA & PIC32_USTA_TRMT)) + continue; +again: + /* Send byte. */ + U1TXREG = c; + + /* Wait for transmitter shift register empty. */ + while (! (U1STA & PIC32_USTA_TRMT)) + continue; + + if (c == '\n') { + c = '\r'; + goto again; + } +} + +static void cputs (const char *p) +{ + for (; *p; ++p) + cputc (*p); +} +#endif + +/* + * Reset the microrontroller. + */ +static void soft_reset() +{ + mips_intr_disable(); + + if (! (DMACON & 0x1000)) { + DMACONSET = 0x1000; + while (DMACON & 0x800) + continue; + } + SYSKEY = 0; + SYSKEY = 0xaa996655; + SYSKEY = 0x556699aa; + + RSWRSTSET = 1; + (void) RSWRST; + + for (;;) + continue; +} + +/* + * Microsecond delay routine for MIPS processor. + */ +static void udelay (unsigned usec) +{ + unsigned now = mips_read_c0_register (C0_COUNT, 0); + unsigned final = now + usec * (CPU_KHZ / 1000); + + for (;;) { + now = mips_read_c0_register (C0_COUNT, 0); + + /* This comparison is valid only when using a signed type. */ + if ((int) (now - final) >= 0) + break; + } +} + +/* + * Clear an array. + */ +void memzero (void *data, unsigned nbytes) +{ + unsigned *wordp = (unsigned*) data; + unsigned nwords = nbytes / sizeof(int); + + while (nwords-- > 0) + *wordp++ = 0; +} + +/* + * Copy an array. + */ +void memcopy (void *from, void *to, unsigned nbytes) +{ + unsigned *src = (unsigned*) from; + unsigned *dst = (unsigned*) to; + unsigned nwords = nbytes / sizeof(int); + + while (nwords-- > 0) + *dst++ = *src++; +} + +/* + * BlinkUSBStatus turns on and off LEDs + * corresponding to the USB device state. + */ +static void led_blink() +{ + static unsigned led_count; + + if (led_count == 0) + led_count = 100000; + led_count--; + + if (! usb_is_device_suspended() && + usb_device_state == CONFIGURED_STATE && + led_count == 0) + { + led_toggle(); + } +} + +/* + * Perform non-volatile memory operation. + */ +static void nvm_operation (unsigned op, unsigned address, unsigned data) +{ + int x; + + // Convert virtual address to physical + NVMADDR = address & 0x1fffffff; + NVMDATA = data; + + // Disable interrupts + x = mips_intr_disable(); + + // Enable Flash Write/Erase Operations + NVMCON = PIC32_NVMCON_WREN | op; + + // Data sheet prescribes 6us delay for LVD to become stable. + // To be on the safer side, we shall set 7us delay. + udelay (7); + + NVMKEY = 0xAA996655; + NVMKEY = 0x556699AA; + NVMCONSET = PIC32_NVMCON_WR; + + // Wait for WR bit to clear + while (NVMCON & PIC32_NVMCON_WR) + continue; + + // Disable Flash Write/Erase operations + NVMCONCLR = PIC32_NVMCON_WREN; + + // Enable interrupts + mips_intr_restore (x); +#if 0 + // Check error status + if (NVMCON & (PIC32_NVMCON_WRERR | PIC32_NVMCON_LVDERR)) { + TODO; + } +#endif +} + +/* + * Use word writes to write code chunks less than a full 64 byte block size. + */ +static void write_flash_block() +{ + unsigned int i; + + for (i = 0; buf_index > 0; buf_index--) { + // Write word to flash memory. + nvm_operation (PIC32_NVMCON_WORD_PGM, + base_address - buf_index * sizeof(unsigned), + buf [i++]); + } +} + +/* + * A command packet was received from PC. + * Process it and return 1 when a reply is ready. + */ +static int handle_packet() +{ + int i; + + switch (receive.Command) { + case QUERY_DEVICE: + // Prepare a response packet, which lets the PC software know + // about the memory ranges of this device. + memzero (&send, PACKET_SIZE); + send.Command = QUERY_DEVICE; + send.PacketDataFieldSize = REQUEST_SIZE; + send.DeviceFamily = 3; /* PIC32 */ + send.Type1 = 1; /* 'program' memory type */ + send.Address1 = FLASH_USER; + send.Length1 = FLASH_BASE + BMXPFMSZ - FLASH_USER; + send.Type2 = 0xFF; /* end of list */ + return 1; + + case UNLOCK_CONFIG: + return 0; + + case ERASE_DEVICE: + for (i = 0; i < BMXPFMSZ/FLASH_PAGESZ; i++) { + /* Erase flash page */ + nvm_operation (PIC32_NVMCON_PAGE_ERASE, + FLASH_USER + i * FLASH_PAGESZ, 0); + + // Call this function periodically to prevent falling + // off the bus if any SETUP packets should happen to arrive. + usb_device_tasks(); + } + // Good practice to clear WREN bit anytime we are + // not expecting to do erase/write operations, + // further reducing probability of accidental activation. + NVMCONCLR = PIC32_NVMCON_WREN; + return 0; + + case PROGRAM_DEVICE: + if (base_address == 0) + base_address = receive.Address; + + if (base_address == receive.Address) { + for (i = 0; i < receive.Size/sizeof(unsigned); i++) { + unsigned int index; + + index = (REQUEST_SIZE - receive.Size) / sizeof(unsigned) + i; + + // Data field is right justified. + // Need to put it in the buffer left justified. + buf [buf_index++] = + receive.Data [(REQUEST_SIZE - receive.Size) / sizeof(unsigned) + i]; + base_address += sizeof(unsigned); + if (buf_index == REQUEST_SIZE / sizeof(unsigned)) { + write_flash_block(); + } + } + } + // else host sent us a non-contiguous packet address... + // to make this firmware simpler, host should not do this without + // sending a PROGRAM_COMPLETE command in between program sections. + return 0; + + case PROGRAM_COMPLETE: + write_flash_block(); + + // Reinitialize pointer to an invalid range, so we know the next + // PROGRAM_DEVICE will be the start address of a contiguous section. + base_address = 0; + return 0; + + case GET_DATA: + memzero (&send, PACKET_SIZE); + send.Command = GET_DATA; + send.Address = receive.Address; + send.Size = receive.Size; + memcopy ((void*) (receive.Address | 0x80000000), + send.Data + (REQUEST_SIZE - receive.Size)/sizeof(unsigned), + receive.Size); + return 1; + + case RESET_DEVICE: + // Disable USB module + U1CON = 0x0000; + + // And wait awhile for the USB cable capacitance to discharge + // down to disconnected (SE0) state. Otherwise host might not + // realize we disconnected/reconnected when we do the reset. + udelay (1000); + + soft_reset(); + return 0; + } + return 0; +} + +/* + * Main program entry point. + */ +int main() +{ + /* Initialize STATUS register: master interrupt disable. */ + mips_write_c0_register (C0_STATUS, 0, ST_CU0 | ST_BEV); + + /* Clear CAUSE register: use special interrupt vector 0x200. */ + mips_write_c0_register (C0_CAUSE, 0, CA_IV); + + /* + * Setup wait states. + */ + CHECON = 2; + BMXCONCLR = 0x40; + CHECONSET = 0x30; + + /* Disable JTAG port, to use it for i/o. */ + DDPCON = 0; + + /* Config register: enable kseg0 caching. */ + mips_write_c0_register (C0_CONFIG, 0, + mips_read_c0_register (C0_CONFIG, 0) | 3); + mips_ehb(); + + /* Initialize all .bss variables by zeros. */ + extern unsigned char __bss_start, __bss_end; + memzero (&__bss_start, &__bss_end - &__bss_start); + + //cinit(); + //cputs("=0=\n"); + + // Initialize all of the push buttons + button_init(); + + /* + * To call the normal application (i.e. don't go into the bootloader) + * we need to make sure that the PRG button is not pressed, and that we + * don't have a software reset. + */ + if (! button_pressed() && + (! (RCON & PIC32_RCON_SWR) || reset_key != 0x12345678)) + { + // Must clear out software key + reset_key = 0; + + // If there is NO real program to execute, then fall through to the bootloader + if (*(int*) FLASH_JUMP != 0xFFFFFFFF) { + void (*fptr)(void) = (void (*)(void)) FLASH_JUMP; + + fptr(); + for (;;) + continue; + } + } + // Must clear out software key. + reset_key = 0; + RCONCLR = PIC32_RCON_SWR; + + // Initialize all of the LED pins + led_init(); + + // Initialize USB module SFRs and firmware variables to known states. + usb_device_init(); + + USB_HANDLE reply_handle = 0; + int packet_received = 0; + for (;;) { + // Check bus status and service USB interrupts. + usb_device_tasks(); + + // Blink the LEDs according to the USB device status + led_blink(); + + // User Application USB tasks + if (usb_device_state < CONFIGURED_STATE || usb_is_device_suspended()) + continue; + + // Are we done sending the last response. We need to be before we + // receive the next command because we clear the send buffer + // once we receive a command + if (reply_handle != 0) { + if (usb_handle_busy (reply_handle)) + continue; + reply_handle = 0; + } + + if (packet_received) { + if (handle_packet()) + reply_handle = usb_transfer_one_packet (HID_EP, + IN_TO_HOST, &send.Contents[0], PACKET_SIZE); + packet_received = 0; + continue; + } + + // Did we receive a command? + if (usb_handle_busy (request_handle)) + continue; + + // Make a copy of received data. + memcopy (&receive_buffer, &receive, PACKET_SIZE); + packet_received = 1; + + // Restart receiver, to be ready for a next packet. + request_handle = usb_transfer_one_packet (HID_EP, OUT_FROM_HOST, + (unsigned char*) &receive_buffer, PACKET_SIZE); + } +} + +/* + * USB Callback Functions + */ +/* + * Process device-specific SETUP requests. + */ +void usbcb_check_other_req() +{ + hid_check_request(); +} + +/* + * This function is called when the device becomes initialized. + * It should initialize the endpoints for the device's usage + * according to the current configuration. + */ +void usbcb_init_ep() +{ + // Enable the HID endpoint + usb_enable_endpoint (HID_EP, USB_IN_ENABLED | USB_OUT_ENABLED | + USB_HANDSHAKE_ENABLED | USB_DISALLOW_SETUP); + + // Arm the OUT endpoint for the first packet + request_handle = usb_rx_one_packet (HID_EP, + &receive_buffer.Contents[0], PACKET_SIZE); +} + +/* + * The device descriptor. + */ +const USB_DEVICE_DESCRIPTOR usb_device = { + sizeof (usb_device), // Size of this descriptor in bytes + USB_DESCRIPTOR_DEVICE, // DEVICE descriptor type + 0x0200, // USB Spec Release Number in BCD format + 0x00, // Class Code + 0x00, // Subclass code + 0x00, // Protocol code + USB_EP0_BUFF_SIZE, // Max packet size for EP0 + 0x04D8, // Vendor ID + 0x003C, // Product ID: USB HID Bootloader + 0x0002, // Device release number in BCD format + 1, // Manufacturer string index + 2, // Product string index + 0, // Device serial number string index + 1, // Number of possible configurations +}; + +/* + * Configuration 1 descriptor + */ +const unsigned char usb_config1_descriptor[] = { + /* + * Configuration descriptor + */ + sizeof (USB_CONFIGURATION_DESCRIPTOR), + USB_DESCRIPTOR_CONFIGURATION, + 0x29, 0x00, // Total length of data for this cfg + 1, // Number of interfaces in this cfg + 1, // Index value of this configuration + 0, // Configuration string index + _DEFAULT | _SELF, // Attributes + 50, // Max power consumption (2X mA) + + /* + * Interface descriptor + */ + sizeof (USB_INTERFACE_DESCRIPTOR), + USB_DESCRIPTOR_INTERFACE, + 0, // Interface Number + 0, // Alternate Setting Number + 2, // Number of endpoints in this intf + HID_INTF, // Class code + 0, // Subclass code + 0, // Protocol code + 0, // Interface string index + + /* + * HID Class-Specific descriptor + */ + sizeof (USB_HID_DSC) + 3, + DSC_HID, + 0x11, 0x01, // HID Spec Release Number in BCD format (1.11) + 0x00, // Country Code (0x00 for Not supported) + HID_NUM_OF_DSC, // Number of class descriptors + DSC_RPT, // Report descriptor type + HID_RPT01_SIZE, 0x00, // Size of the report descriptor + + /* + * Endpoint descriptor + */ + sizeof (USB_ENDPOINT_DESCRIPTOR), + USB_DESCRIPTOR_ENDPOINT, + HID_EP | _EP_IN, // EndpointAddress + _INTERRUPT, // Attributes + PACKET_SIZE, 0, // Size + 1, // Interval + + /* + * Endpoint descriptor + */ + sizeof (USB_ENDPOINT_DESCRIPTOR), + USB_DESCRIPTOR_ENDPOINT, + HID_EP | _EP_OUT, // EndpointAddress + _INTERRUPT, // Attributes + PACKET_SIZE, 0, // Size + 1, // Interval +}; + +/* + * Class specific descriptor - HID + */ +const unsigned char hid_rpt01 [HID_RPT01_SIZE] = { + 0x06, 0x00, 0xFF, // Usage Page = 0xFF00 (Vendor Defined Page 1) + 0x09, 0x01, // Usage (Vendor Usage 1) + 0xA1, 0x01, // Collection (Application) + + 0x19, 0x01, // Usage Minimum + 0x29, 0x40, // Usage Maximum 64 input usages total (0x01 to 0x40) + 0x15, 0x00, // Logical Minimum (data bytes in the report may have minimum value = 0x00) + 0x26, 0xFF, 0x00, // Logical Maximum (data bytes in the report may have maximum value = 0x00FF = unsigned 255) + 0x75, 0x08, // Report Size: 8-bit field size + 0x95, 0x40, // Report Count: Make sixty-four 8-bit fields (the next time the parser hits an "Input", "Output", or "Feature" item) + 0x81, 0x00, // Input (Data, Array, Abs): Instantiates input packet fields based on the above report size, count, logical min/max, and usage. + + 0x19, 0x01, // Usage Minimum + 0x29, 0x40, // Usage Maximum 64 output usages total (0x01 to 0x40) + 0x91, 0x00, // Output (Data, Array, Abs): Instantiates output packet fields. Uses same report size and count as "Input" fields, since nothing new/different was specified to the parser since the "Input" item. + + 0xC0, // End Collection +}; + +/* + * USB Strings + */ +static const USB_STRING_INIT(1) string0_descriptor = { + sizeof(string0_descriptor), + USB_DESCRIPTOR_STRING, /* Language code */ + { 0x0409 }, +}; + +static const USB_STRING_INIT(25) string1_descriptor = { + sizeof(string1_descriptor), + USB_DESCRIPTOR_STRING, /* Manufacturer */ + { 'M','i','c','r','o','c','h','i','p',' ', + 'T','e','c','h','n','o','l','o','g','y', + ' ','I','n','c','.' }, +}; + +static const USB_STRING_INIT(18) string2_descriptor = { + sizeof(string2_descriptor), + USB_DESCRIPTOR_STRING, /* Product */ + { 'U','S','B',' ','H','I','D',' ','B','o', + 'o','t','l','o','a','d','e','r' }, +}; + +/* + * Array of configuration descriptors + */ +const unsigned char *const usb_config[] = { + (const unsigned char *const) &usb_config1_descriptor, +}; + +/* + * Array of string descriptors + */ +const unsigned char *const usb_string[USB_NUM_STRING_DESCRIPTORS] = { + (const unsigned char *const) &string0_descriptor, + (const unsigned char *const) &string1_descriptor, + (const unsigned char *const) &string2_descriptor, +}; diff --git a/sys/pic32/usb_ch9.h b/sys/pic32/usb_ch9.h new file mode 100644 index 0000000..d9fbef5 --- /dev/null +++ b/sys/pic32/usb_ch9.h @@ -0,0 +1,365 @@ +/* + * USB Chapter 9 Protocol (Header File) + * + * This file defines data structures, constants, and macros that are used to + * to support the USB Device Framework protocol described in Chapter 9 of the + * USB 2.0 specification. + * + * The software supplied herewith by Microchip Technology Incorporated + * (the “Company”) for its PICmicro® Microcontroller is intended and + * supplied to you, the Company’s customer, for use solely and + * exclusively on Microchip PICmicro Microcontroller products. The + * software is owned by the Company and/or its supplier, and is + * protected under applicable copyright laws. All rights are reserved. + * Any use in violation of the foregoing restrictions may subject the + * user to criminal sanctions under applicable laws, as well as to + * civil liability for the breach of the terms and conditions of this + * license. + * + * THIS SOFTWARE IS PROVIDED IN AN “AS IS” CONDITION. NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED + * TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE COMPANY SHALL NOT, + * IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR + * CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER. + */ +#ifndef _USB_CH9_H_ +#define _USB_CH9_H_ + +// +// Section: USB Descriptors +// +#define USB_DESCRIPTOR_DEVICE 0x01 // bDescriptorType for a Device Descriptor. +#define USB_DESCRIPTOR_CONFIGURATION 0x02 // bDescriptorType for a Configuration Descriptor. +#define USB_DESCRIPTOR_STRING 0x03 // bDescriptorType for a String Descriptor. +#define USB_DESCRIPTOR_INTERFACE 0x04 // bDescriptorType for an Interface Descriptor. +#define USB_DESCRIPTOR_ENDPOINT 0x05 // bDescriptorType for an Endpoint Descriptor. +#define USB_DESCRIPTOR_DEVICE_QUALIFIER 0x06 // bDescriptorType for a Device Qualifier. +#define USB_DESCRIPTOR_OTHER_SPEED 0x07 // bDescriptorType for a Other Speed Configuration. +#define USB_DESCRIPTOR_INTERFACE_POWER 0x08 // bDescriptorType for Interface Power. +#define USB_DESCRIPTOR_OTG 0x09 // bDescriptorType for an OTG Descriptor. + +/* + * USB Device Descriptor Structure + * + * This struct defines the structure of a USB Device Descriptor. Note that this + * structure may need to be packed, or even accessed as bytes, to properly access + * the correct fields when used on some device architectures. + */ +typedef struct __attribute__ ((packed)) _USB_DEVICE_DESCRIPTOR +{ + unsigned char bLength; // Length of this descriptor. + unsigned char bDescriptorType; // DEVICE descriptor type (USB_DESCRIPTOR_DEVICE). + unsigned short bcdUSB; // USB Spec Release Number (BCD). + unsigned char bDeviceClass; // Class code (assigned by the USB-IF). 0xFF-Vendor specific. + unsigned char bDeviceSubClass; // Subclass code (assigned by the USB-IF). + unsigned char bDeviceProtocol; // Protocol code (assigned by the USB-IF). 0xFF-Vendor specific. + unsigned char bMaxPacketSize0; // Maximum packet size for endpoint 0. + unsigned short idVendor; // Vendor ID (assigned by the USB-IF). + unsigned short idProduct; // Product ID (assigned by the manufacturer). + unsigned short bcdDevice; // Device release number (BCD). + unsigned char iManufacturer; // Index of String Descriptor describing the manufacturer. + unsigned char iProduct; // Index of String Descriptor describing the product. + unsigned char iSerialNumber; // Index of String Descriptor with the device's serial number. + unsigned char bNumConfigurations; // Number of possible configurations. +} USB_DEVICE_DESCRIPTOR; + + +/* + * USB Configuration Descriptor Structure + * + * This struct defines the structure of a USB Configuration Descriptor. Note that this + * structure may need to be packed, or even accessed as bytes, to properly access + * the correct fields when used on some device architectures. + */ +typedef struct __attribute__ ((packed)) _USB_CONFIGURATION_DESCRIPTOR +{ + unsigned char bLength; // Length of this descriptor. + unsigned char bDescriptorType; // CONFIGURATION descriptor type (USB_DESCRIPTOR_CONFIGURATION). + unsigned short wTotalLength; // Total length of all descriptors for this configuration. + unsigned char bNumInterfaces; // Number of interfaces in this configuration. + unsigned char bConfigurationValue; // Value of this configuration (1 based). + unsigned char iConfiguration; // Index of String Descriptor describing the configuration. + unsigned char bmAttributes; // Configuration characteristics. + unsigned char bMaxPower; // Maximum power consumed by this configuration. +} USB_CONFIGURATION_DESCRIPTOR; + +// Attributes bits +#define USB_CFG_DSC_REQUIRED 0x80 // Required attribute +#define USB_CFG_DSC_SELF_PWR (0x40 | USB_CFG_DSC_REQUIRED) // Device is self powered. +#define USB_CFG_DSC_REM_WAKE (0x20 | USB_CFG_DSC_REQUIRED) // Device can request remote wakup + + +/* + * USB Interface Descriptor Structure + * + * This struct defines the structure of a USB Interface Descriptor. Note that this + * structure may need to be packed, or even accessed as bytes, to properly access + * the correct fields when used on some device architectures. + */ +typedef struct __attribute__ ((packed)) _USB_INTERFACE_DESCRIPTOR +{ + unsigned char bLength; // Length of this descriptor. + unsigned char bDescriptorType; // INTERFACE descriptor type (USB_DESCRIPTOR_INTERFACE). + unsigned char bInterfaceNumber; // Number of this interface (0 based). + unsigned char bAlternateSetting; // Value of this alternate interface setting. + unsigned char bNumEndpoints; // Number of endpoints in this interface. + unsigned char bInterfaceClass; // Class code (assigned by the USB-IF). 0xFF-Vendor specific. + unsigned char bInterfaceSubClass; // Subclass code (assigned by the USB-IF). + unsigned char bInterfaceProtocol; // Protocol code (assigned by the USB-IF). 0xFF-Vendor specific. + unsigned char iInterface; // Index of String Descriptor describing the interface. +} USB_INTERFACE_DESCRIPTOR; + + +// ***************************************************************************** +/* USB Endpoint Descriptor Structure + +This struct defines the structure of a USB Endpoint Descriptor. Note that this +structure may need to be packed, or even accessed as bytes, to properly access +the correct fields when used on some device architectures. +*/ +typedef struct __attribute__ ((packed)) _USB_ENDPOINT_DESCRIPTOR +{ + unsigned char bLength; // Length of this descriptor. + unsigned char bDescriptorType; // ENDPOINT descriptor type (USB_DESCRIPTOR_ENDPOINT). + unsigned char bEndpointAddress; // Endpoint address. Bit 7 indicates direction (0=OUT, 1=IN). + unsigned char bmAttributes; // Endpoint transfer type. + unsigned short wMaxPacketSize; // Maximum packet size. + unsigned char bInterval; // Polling interval in frames. +} USB_ENDPOINT_DESCRIPTOR; + + +// Endpoint Direction +#define EP_DIR_IN 0x80 // Data flows from device to host +#define EP_DIR_OUT 0x00 // Data flows from host to device + + +// ****************************************************************** +// USB Endpoint Attributes +// ****************************************************************** + +// Section: Transfer Types +#define EP_ATTR_CONTROL (0<<0) // Endoint used for control transfers +#define EP_ATTR_ISOCH (1<<0) // Endpoint used for isochronous transfers +#define EP_ATTR_BULK (2<<0) // Endpoint used for bulk transfers +#define EP_ATTR_INTR (3<<0) // Endpoint used for interrupt transfers + +// Section: Synchronization Types (for isochronous enpoints) +#define EP_ATTR_NO_SYNC (0<<2) // No Synchronization +#define EP_ATTR_ASYNC (1<<2) // Asynchronous +#define EP_ATTR_ADAPT (2<<2) // Adaptive synchronization +#define EP_ATTR_SYNC (3<<2) // Synchronous + +// Section: Usage Types (for isochronous endpoints) +#define EP_ATTR_DATA (0<<4) // Data Endpoint +#define EP_ATTR_FEEDBACK (1<<4) // Feedback endpoint +#define EP_ATTR_IMP_FB (2<<4) // Implicit Feedback data EP + +// Section: Max Packet Sizes +#define EP_MAX_PKT_INTR_LS 8 // Max low-speed interrupt packet +#define EP_MAX_PKT_INTR_FS 64 // Max full-speed interrupt packet +#define EP_MAX_PKT_ISOCH_FS 1023 // Max full-speed isochronous packet +#define EP_MAX_PKT_BULK_FS 64 // Max full-speed bulk packet +#define EP_LG_PKT_BULK_FS 32 // Large full-speed bulk packet +#define EP_MED_PKT_BULK_FS 16 // Medium full-speed bulk packet +#define EP_SM_PKT_BULK_FS 8 // Small full-speed bulk packet + + +// ***************************************************************************** +/* USB OTG Descriptor Structure + +This struct defines the structure of a USB OTG Descriptor. Note that this +structure may need to be packed, or even accessed as bytes, to properly access +the correct fields when used on some device architectures. +*/ +typedef struct __attribute__ ((packed)) _USB_OTG_DESCRIPTOR +{ + unsigned char bLength; // Length of this descriptor. + unsigned char bDescriptorType; // OTG descriptor type (USB_DESCRIPTOR_OTG). + unsigned char bmAttributes; // OTG attributes. +} USB_OTG_DESCRIPTOR; + + +// ****************************************************************** +// Section: USB String Descriptor Structure +// ****************************************************************** +// This structure describes the USB string descriptor. The string +// descriptor provides user-readable information about various aspects of +// the device. The first string desriptor (string descriptor zero (0)), +// provides a list of the number of languages supported by the set of +// string descriptors for this device instead of an actual string. +// +// Note: The strings are in 2-byte-per-character unicode, not ASCII. +// +// Note: This structure only describes the "header" of the string +// descriptor. The actual data (either the language ID array or the +// array of unicode characters making up the string, must be allocated +// immediately following this header with no padding between them. + +typedef struct __attribute__ ((packed)) _USB_STRING_DSC +{ + unsigned char bLength; // Size of this descriptor + unsigned char bDescriptorType; // Type, USB_DSC_STRING + +} USB_STRING_DESCRIPTOR; + +#define USB_STRING_INIT(nchars) struct {\ + unsigned char bLength; \ + unsigned char bDescriptorType; \ + unsigned short string[nchars]; \ +} + + +// ****************************************************************** +// Section: USB Device Qualifier Descriptor Structure +// ****************************************************************** +// This structure describes the device qualifier descriptor. The device +// qualifier descriptor provides overall device information if the device +// supports "other" speeds. +// +// Note: A high-speed device may support "other" speeds (ie. full or low). +// If so, it may need to implement the the device qualifier and other +// speed descriptors. + +typedef struct __attribute__ ((packed)) _USB_DEVICE_QUALIFIER_DESCRIPTOR +{ + unsigned char bLength; // Size of this descriptor + unsigned char bType; // Type, always USB_DESCRIPTOR_DEVICE_QUALIFIER + unsigned short bcdUSB; // USB spec version, in BCD + unsigned char bDeviceClass; // Device class code + unsigned char bDeviceSubClass; // Device sub-class code + unsigned char bDeviceProtocol; // Device protocol + unsigned char bMaxPacketSize0; // EP0, max packet size + unsigned char bNumConfigurations; // Number of "other-speed" configurations + unsigned char bReserved; // Always zero (0) + +} USB_DEVICE_QUALIFIER_DESCRIPTOR; + + +// ****************************************************************** +// Section: USB Setup Packet Structure +// ****************************************************************** +// This structure describes the data contained in a USB standard device +// request's setup packet. It is the data packet sent from the host to +// the device to control and configure the device. +// +// Note: Refer to the USB 2.0 specification for additional details on the +// usage of the setup packet and standard device requests. + +typedef struct __attribute__ ((packed)) +{ + union // offset description + { // ------ ------------------------ + unsigned char bmRequestType; // 0 Bit-map of request type + struct { + unsigned recipient: 5; // Recipient of the request + unsigned type: 2; // Type of request + unsigned direction: 1; // Direction of data X-fer + }; + } requestInfo; + + unsigned char bRequest; // 1 Request type + unsigned short wValue; // 2 Depends on bRequest + unsigned short wIndex; // 4 Depends on bRequest + unsigned short wLength; // 6 Depends on bRequest + +} SETUP_PKT, *PSETUP_PKT; + + +// +// Section: USB Specification Constants +// + +// Section: Valid PID Values +//DOM-IGNORE-BEGIN +#define PID_OUT 0x1 // PID for an OUT token +#define PID_ACK 0x2 // PID for an ACK handshake +#define PID_DATA0 0x3 // PID for DATA0 data +#define PID_PING 0x4 // Special PID PING +#define PID_SOF 0x5 // PID for a SOF token +#define PID_NYET 0x6 // PID for a NYET handshake +#define PID_DATA2 0x7 // PID for DATA2 data +#define PID_SPLIT 0x8 // Special PID SPLIT +#define PID_IN 0x9 // PID for a IN token +#define PID_NAK 0xA // PID for a NAK handshake +#define PID_DATA1 0xB // PID for DATA1 data +#define PID_PRE 0xC // Special PID PRE (Same as PID_ERR) +#define PID_ERR 0xC // Special PID ERR (Same as PID_PRE) +#define PID_SETUP 0xD // PID for a SETUP token +#define PID_STALL 0xE // PID for a STALL handshake +#define PID_MDATA 0xF // PID for MDATA data + +#define PID_MASK_DATA 0x03 // Data PID mask +#define PID_MASK_DATA_SHIFTED (PID_MASK_DATA << 2) // Data PID shift to proper position +//DOM-IGNORE-END + +// Section: USB Token Types +//DOM-IGNORE-BEGIN +#define USB_TOKEN_OUT 0x01 // U1TOK - OUT token +#define USB_TOKEN_IN 0x09 // U1TOK - IN token +#define USB_TOKEN_SETUP 0x0D // U1TOK - SETUP token +//DOM-IGNORE-END + +// Section: OTG Descriptor Constants + +#define OTG_HNP_SUPPORT 0x02 // OTG Descriptor bmAttributes - HNP support flag +#define OTG_SRP_SUPPORT 0x01 // OTG Descriptor bmAttributes - SRP support flag + +// Section: Endpoint Directions + +#define USB_IN_EP 0x80 // IN endpoint mask +#define USB_OUT_EP 0x00 // OUT endpoint mask + +// Section: Standard Device Requests + +#define USB_REQUEST_GET_STATUS 0 // Standard Device Request - GET STATUS +#define USB_REQUEST_CLEAR_FEATURE 1 // Standard Device Request - CLEAR FEATURE +#define USB_REQUEST_SET_FEATURE 3 // Standard Device Request - SET FEATURE +#define USB_REQUEST_SET_ADDRESS 5 // Standard Device Request - SET ADDRESS +#define USB_REQUEST_GET_DESCRIPTOR 6 // Standard Device Request - GET DESCRIPTOR +#define USB_REQUEST_SET_DESCRIPTOR 7 // Standard Device Request - SET DESCRIPTOR +#define USB_REQUEST_GET_CONFIGURATION 8 // Standard Device Request - GET CONFIGURATION +#define USB_REQUEST_SET_CONFIGURATION 9 // Standard Device Request - SET CONFIGURATION +#define USB_REQUEST_GET_INTERFACE 10 // Standard Device Request - GET INTERFACE +#define USB_REQUEST_SET_INTERFACE 11 // Standard Device Request - SET INTERFACE +#define USB_REQUEST_SYNCH_FRAME 12 // Standard Device Request - SYNCH FRAME + +#define USB_FEATURE_ENDPOINT_HALT 0 // CLEAR/SET FEATURE - Endpoint Halt +#define USB_FEATURE_DEVICE_REMOTE_WAKEUP 1 // CLEAR/SET FEATURE - Device remote wake-up +#define USB_FEATURE_TEST_MODE 2 // CLEAR/SET FEATURE - Test mode + +// Section: Setup Data Constants + +#define USB_SETUP_HOST_TO_DEVICE 0x00 // Device Request bmRequestType transfer direction - host to device transfer +#define USB_SETUP_DEVICE_TO_HOST 0x80 // Device Request bmRequestType transfer direction - device to host transfer +#define USB_SETUP_TYPE_STANDARD 0x00 // Device Request bmRequestType type - standard +#define USB_SETUP_TYPE_CLASS 0x20 // Device Request bmRequestType type - class +#define USB_SETUP_TYPE_VENDOR 0x40 // Device Request bmRequestType type - vendor +#define USB_SETUP_RECIPIENT_DEVICE 0x00 // Device Request bmRequestType recipient - device +#define USB_SETUP_RECIPIENT_INTERFACE 0x01 // Device Request bmRequestType recipient - interface +#define USB_SETUP_RECIPIENT_ENDPOINT 0x02 // Device Request bmRequestType recipient - endpoint +#define USB_SETUP_RECIPIENT_OTHER 0x03 // Device Request bmRequestType recipient - other + +// Section: OTG SET FEATURE Constants + +#define OTG_FEATURE_B_HNP_ENABLE 3 // SET FEATURE OTG - Enable B device to perform HNP +#define OTG_FEATURE_A_HNP_SUPPORT 4 // SET FEATURE OTG - A device supports HNP +#define OTG_FEATURE_A_ALT_HNP_SUPPORT 5 // SET FEATURE OTG - Another port on the A device supports HNP + +// Section: USB Endpoint Transfer Types + +#define USB_TRANSFER_TYPE_CONTROL 0x00 // Endpoint is a control endpoint. +#define USB_TRANSFER_TYPE_ISOCHRONOUS 0x01 // Endpoint is an isochronous endpoint. +#define USB_TRANSFER_TYPE_BULK 0x02 // Endpoint is a bulk endpoint. +#define USB_TRANSFER_TYPE_INTERRUPT 0x03 // Endpoint is an interrupt endpoint. + +// Section: Standard Feature Selectors for CLEAR_FEATURE Requests +#define USB_FEATURE_ENDPOINT_STALL 0 // Endpoint recipient +#define USB_FEATURE_DEVICE_REMOTE_WAKEUP 1 // Device recipient +#define USB_FEATURE_TEST_MODE 2 // Device recipient + + +// Section: USB Class Code Definitions +#define USB_HUB_CLASSCODE 0x09 // Class code for a hub. + +#endif // _USB_CH9_H_ diff --git a/sys/pic32/usb_console.c b/sys/pic32/usb_console.c new file mode 100644 index 0000000..d43d58e --- /dev/null +++ b/sys/pic32/usb_console.c @@ -0,0 +1,452 @@ +/* + * Console driver via USB. + * + * Copyright (C) 2011 Serge Vakulenko, + * + * 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 the copyright notice and this + * permission notice and warranty disclaimer appear in supporting + * documentation, and that the name of the author not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * + * The author disclaim all warranties with regard to this + * software, including all implied warranties of merchantability + * and fitness. In no event shall the author 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. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct tty cnttys [1]; + +void cnstart (struct tty *tp); + +/* + * Initialize USB module SFRs and firmware variables to known state. + * Enable interrupts. + */ +void cninit() +{ + usb_device_init(); + IECSET(1) = 1 << (PIC32_IRQ_USB - 32); + + /* Wait for any user input. */ + while (! cdc_consume(0)) + usb_device_tasks(); +} + +void cnidentify() +{ + printf ("console: USB\n"); +} + +int cnopen (dev, flag, mode) + dev_t dev; +{ + register struct tty *tp = &cnttys[0]; + + tp->t_oproc = cnstart; + if ((tp->t_state & TS_ISOPEN) == 0) { + ttychars(tp); + tp->t_state = TS_ISOPEN | TS_CARR_ON; + tp->t_flags = ECHO | XTABS | CRMOD | CRTBS | CRTERA | CTLECH | CRTKIL; + } + if ((tp->t_state & TS_XCLUDE) && u.u_uid != 0) + return (EBUSY); + + return ttyopen (dev, tp); +} + +int cnclose (dev, flag, mode) + dev_t dev; +{ + register struct tty *tp = &cnttys[0]; + + ttyclose (tp); + return 0; +} + +int cnread (dev, uio, flag) + dev_t dev; + struct uio *uio; + int flag; +{ + register struct tty *tp = &cnttys[0]; + + return ttread (tp, uio, flag); +} + +int cnwrite (dev, uio, flag) + dev_t dev; + struct uio *uio; + int flag; +{ + register struct tty *tp = &cnttys[0]; + + return ttwrite (tp, uio, flag); +} + +int cnioctl (dev, cmd, addr, flag) + dev_t dev; + register u_int cmd; + caddr_t addr; +{ + register struct tty *tp = &cnttys[0]; + register int error; + + error = ttioctl (tp, cmd, addr, flag); + if (error < 0) + error = ENOTTY; + return error; +} + +int cnselect (dev, rw) + register dev_t dev; + int rw; +{ + register struct tty *tp = &cnttys[0]; + + return ttyselect (tp, rw); +} + +void cnstart (tp) + register struct tty *tp; +{ + register int s; + + s = spltty(); + if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP)) { +out: /* Disable transmit_interrupt. */ + led_control (LED_TTY, 0); + splx (s); + return; + } + ttyowake(tp); + if (tp->t_outq.c_cc == 0) + goto out; + if (cdc_is_tx_ready()) { + while (tp->t_outq.c_cc != 0) { + int c = getc (&tp->t_outq); + if (cdc_putc (c) == 0) + break; + } + cdc_tx_service(); + tp->t_state |= TS_BUSY; + } + led_control (LED_TTY, 1); + splx (s); +} + +/* + * Put a symbol on console terminal. + */ +void cnputc (c) + char c; +{ + register int s; + + s = spltty(); + while (! cdc_is_tx_ready()) { + usb_device_tasks(); + cdc_tx_service(); + } + led_control (LED_TTY, 1); +again: + cdc_putc (c); + cdc_tx_service(); + + while (! cdc_is_tx_ready()) { + cdc_tx_service(); + usb_device_tasks(); + } + if (c == '\n') { + c = '\r'; + goto again; + } + + led_control (LED_TTY, 0); + splx (s); +} + +static int getc_data; + +/* + * Receive a character for getc. + */ +static void store_char (int c) +{ + getc_data = (unsigned char) c; +} + +/* + * Receive a symbol from console terminal. + */ +int +cngetc () +{ + register int s; + + s = spltty(); + for (getc_data = -1; getc_data < 0; ) { + usb_device_tasks(); + cdc_consume (store_char); + cdc_tx_service(); + } + splx (s); + return getc_data; +} + +/* + * Receive a character from CDC. + */ +static void cn_rx (int c) +{ + register struct tty *tp = &cnttys[0]; + + if ((tp->t_state & TS_ISOPEN) == 0) + return; + ttinput (c, tp); +} + +/* + * Check bus status and service USB interrupts. + */ +void cnintr (int chan) +{ + register struct tty *tp = &cnttys[0]; + + // Must call this function from interrupt or periodically. + usb_device_tasks(); + + // Check that USB connection is established. + if (usb_device_state < CONFIGURED_STATE || + (U1PWRC & PIC32_U1PWRC_USUSPEND)) + return; + + // Receive data from user. + cdc_consume (cn_rx); + + if (cdc_is_tx_ready()) { + // Transmitter empty. + led_control (LED_TTY, 0); + + if (tp->t_state & TS_BUSY) { + tp->t_state &= ~TS_BUSY; + ttstart (tp); + } + } + + // Transmit data to user. + cdc_tx_service(); +} + +/* + * USB Callback Functions + */ + +/* + * This function is called when the device becomes initialized. + * It should initialize the endpoints for the device's usage + * according to the current configuration. + */ +void usbcb_init_ep() +{ + cdc_init_ep(); +} + +/* + * Process device-specific SETUP requests. + */ +void usbcb_check_other_req() +{ + cdc_check_request(); +} + +#if 0 +/* + * Wake up a host PC. + */ +void usb_send_resume (void) +{ + /* Start RESUME signaling. */ + U1CON |= PIC32_U1CON_RESUME; + + /* Set RESUME line for 1-13 ms. */ + udelay (5000); + + U1CON &= ~PIC32_U1CON_RESUME; +} +#endif + +#ifndef CONSOLE_VID +# define CONSOLE_VID 0x04D8 // Vendor ID: Microchip +#endif +#ifndef CONSOLE_PID +# define CONSOLE_PID 0x000A // Product ID: CDC RS-232 Emulation Demo +#endif + +/* + * Device Descriptor + */ +const USB_DEVICE_DESCRIPTOR usb_device = { + sizeof(usb_device), // Size of this descriptor in bytes + USB_DESCRIPTOR_DEVICE, // DEVICE descriptor type + 0x0200, // USB Spec Release Number in BCD format + CDC_DEVICE, // Class Code + 0x00, // Subclass code + 0x00, // Protocol code + USB_EP0_BUFF_SIZE, // Max packet size for EP0, see usb_config.h + CONSOLE_VID, // Vendor ID + CONSOLE_PID, // Product ID + 0x0100, // Device release number in BCD format + 0x01, // Manufacturer string index + 0x02, // Product string index + 0x00, // Device serial number string index + 0x01 // Number of possible configurations +}; + +/* + * Configuration 1 Descriptor + */ +const unsigned char usb_config1_descriptor[] = +{ + /* Configuration Descriptor */ + 9, // sizeof(USB_CFG_DSC) + USB_DESCRIPTOR_CONFIGURATION, // CONFIGURATION descriptor type + 67, 0, // Total length of data for this cfg + 2, // Number of interfaces in this cfg + 1, // Index value of this configuration + 0, // Configuration string index + _DEFAULT | _SELF, // Attributes, see usb_device.h + 150, // Max power consumption (2X mA) + + /* Interface Descriptor */ + 9, // sizeof(USB_INTF_DSC) + USB_DESCRIPTOR_INTERFACE, // INTERFACE descriptor type + 0, // Interface Number + 0, // Alternate Setting Number + 1, // Number of endpoints in this intf + COMM_INTF, // Class code + ABSTRACT_CONTROL_MODEL, // Subclass code + V25TER, // Protocol code + 0, // Interface string index + + /* CDC Class-Specific Descriptors */ + sizeof(USB_CDC_HEADER_FN_DSC), + CS_INTERFACE, + DSC_FN_HEADER, + 0x10,0x01, + + sizeof(USB_CDC_ACM_FN_DSC), + CS_INTERFACE, + DSC_FN_ACM, + USB_CDC_ACM_FN_DSC_VAL, + + sizeof(USB_CDC_UNION_FN_DSC), + CS_INTERFACE, + DSC_FN_UNION, + CDC_COMM_INTF_ID, + CDC_DATA_INTF_ID, + + sizeof(USB_CDC_CALL_MGT_FN_DSC), + CS_INTERFACE, + DSC_FN_CALL_MGT, + 0x00, + CDC_DATA_INTF_ID, + + /* Endpoint Descriptor */ + 7, // sizeof(USB_EP_DSC) + USB_DESCRIPTOR_ENDPOINT, // Endpoint Descriptor + _EP02_IN, // EndpointAddress + _INTERRUPT, // Attributes + 0x08, 0x00, // size + 0x02, // Interval + + /* Interface Descriptor */ + 9, // sizeof(USB_INTF_DSC) + USB_DESCRIPTOR_INTERFACE, // INTERFACE descriptor type + 1, // Interface Number + 0, // Alternate Setting Number + 2, // Number of endpoints in this intf + DATA_INTF, // Class code + 0, // Subclass code + NO_PROTOCOL, // Protocol code + 0, // Interface string index + + /* Endpoint Descriptor */ + 7, // sizeof(USB_EP_DSC) + USB_DESCRIPTOR_ENDPOINT, // Endpoint Descriptor + _EP03_OUT, // EndpointAddress + _BULK, // Attributes + 0x40, 0x00, // size + 0x00, // Interval + + /* Endpoint Descriptor */ + 7, // sizeof(USB_EP_DSC) + USB_DESCRIPTOR_ENDPOINT, // Endpoint Descriptor + _EP03_IN, // EndpointAddress + _BULK, // Attributes + 0x40, 0x00, // size + 0x00, // Interval +}; + + +/* + * Language code string descriptor. + */ +static const USB_STRING_INIT(1) string0_descriptor = { + sizeof(string0_descriptor), + USB_DESCRIPTOR_STRING, + { 0x0409 } /* US English */ +}; + +/* + * Manufacturer string descriptor + */ +static const USB_STRING_INIT(25) string1_descriptor = { + sizeof(string1_descriptor), + USB_DESCRIPTOR_STRING, + { 'M','i','c','r','o','c','h','i','p',' ', + 'T','e','c','h','n','o','l','o','g','y', + ' ','I','n','c','.', }, +}; + +/* + * Product string descriptor + */ +static const USB_STRING_INIT(16) string2_descriptor = { + sizeof(string2_descriptor), + USB_DESCRIPTOR_STRING, + { 'R','e','t','r','o','B','S','D',' ','C', + 'o','n','s','o','l','e', }, +}; + +/* + * Array of configuration descriptors + */ +const unsigned char *const usb_config[] = { + (const unsigned char *const) &usb_config1_descriptor, +}; + +/* + * Array of string descriptors + */ +const unsigned char *const usb_string[USB_NUM_STRING_DESCRIPTORS] = { + (const unsigned char *const) &string0_descriptor, + (const unsigned char *const) &string1_descriptor, + (const unsigned char *const) &string2_descriptor, +}; diff --git a/sys/pic32/usb_device.c b/sys/pic32/usb_device.c new file mode 100644 index 0000000..f8f5bac --- /dev/null +++ b/sys/pic32/usb_device.c @@ -0,0 +1,1534 @@ +/* + * This file contains functions, macros, definitions, variables, + * datatypes, etc. that are required for usage with the MCHPFSUSB device + * stack. This file should be included in projects that use the device stack. + * + * The software supplied herewith by Microchip Technology Incorporated + * (the 'Company') for its PIC® Microcontroller is intended and + * supplied to you, the Company's customer, for use solely and + * exclusively on Microchip PIC Microcontroller products. The + * software is owned by the Company and/or its supplier, and is + * protected under applicable copyright laws. All rights are reserved. + * Any use in violation of the foregoing restrictions may subject the + * user to criminal sanctions under applicable laws, as well as to + * civil liability for the breach of the terms and conditions of this license. + * + * THIS SOFTWARE IS PROVIDED IN AN 'AS IS' CONDITION. NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED + * TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE COMPANY SHALL NOT, + * IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR + * CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER. + */ +#include +#include + +#if (USB_PING_PONG_MODE != USB_PING_PONG__FULL_PING_PONG) + #error "PIC32 only supports full ping pong mode." +#endif + +unsigned usb_device_state; +unsigned usb_active_configuration; +static unsigned char usb_alternate_interface[USB_MAX_NUM_INT]; +static volatile BDT_ENTRY *pBDTEntryEP0OutCurrent; +static volatile BDT_ENTRY *pBDTEntryEP0OutNext; +static volatile BDT_ENTRY *pBDTEntryOut[USB_MAX_EP_NUMBER+1]; +static volatile BDT_ENTRY *pBDTEntryIn[USB_MAX_EP_NUMBER+1]; +static unsigned short_packet_status; +static unsigned control_transfer_state; +static unsigned ustat_saved; +IN_PIPE usb_in_pipe[1]; +OUT_PIPE usb_out_pipe[1]; +int usb_remote_wakeup; + +/* + * Section A: Buffer Descriptor Table + * - 0x400 - 0x4FF(max) + * - USB_MAX_EP_NUMBER is defined in target.cfg + */ +volatile BDT_ENTRY usb_buffer [(USB_MAX_EP_NUMBER + 1) * 4] __attribute__ ((aligned (512))); + +/* + * Section B: EP0 Buffer Space + */ +volatile CTRL_TRF_SETUP usb_setup_pkt; // 8-byte only + +// Buffer for control transfer data +static volatile unsigned char ctrl_trf_data [USB_EP0_BUFF_SIZE]; + +/* + * This function initializes the device stack + * it in the default state + * + * The USB module will be completely reset including + * all of the internal variables, registers, and + * interrupt flags. + */ +void usb_device_init(void) +{ + unsigned i; + + // Clear all USB error flags + U1EIR = 0xFF; + + // Clears all USB interrupts + U1IR = 0xFF; + + U1EIE = 0x9F; // Unmask all USB error interrupts + U1IE = PIC32_U1I_URST | // Unmask Reset interrupt + PIC32_U1I_IDLE | // Unmask Idle interrupt + PIC32_U1I_UERR | // Unmask Error interrupt + PIC32_U1I_TRN; // Transaction Complete Interrupt + + // Power up the module + U1PWRC |= PIC32_U1PWRC_USBPWR; + + // Set the address of the BDT (if applicable) + U1BDTP1 = (unsigned) usb_buffer >> 8; + + // Reset all of the Ping Pong buffers + U1CON |= PIC32_U1CON_PPBRST; + U1CON &= ~PIC32_U1CON_PPBRST; + + // Reset to default address + U1ADDR = 0x00; + + // Clear all of the endpoint control registers + for (i=1; iSTAT.Val == _USIE && + pBDTEntryIn[0]->STAT.Val == (_USIE | _BSTALL)) + { + // Set ep0Bo to stall also + pBDTEntryEP0OutCurrent->STAT.Val = _USIE|_DAT0|_DTSEN|_BSTALL; + } + // Clear stall status + U1EP(0) &= ~PIC32_U1EP_EPSTALL; + } + + U1IR = PIC32_U1I_STALL; +} + +/* + * This function handles if the host tries to suspend the device + */ +void usb_suspend(void) +{ + /* + * NOTE: Do not clear UIR_ACTVIF here! + * Reason: + * ACTVIF is only generated once an IDLEIF has been generated. + * This is a 1:1 ratio interrupt generation. + * For every IDLEIF, there will be only one ACTVIF regardless of + * the number of subsequent bus transitions. + * + * If the ACTIF is cleared here, a problem could occur when: + * [ IDLE ][bus activity -> + * <--- 3 ms -----> ^ + * ^ ACTVIF=1 + * IDLEIF=1 + * # # # # (#=Program polling flags) + * ^ + * This polling loop will see both + * IDLEIF=1 and ACTVIF=1. + * However, the program services IDLEIF first + * because ACTIVIE=0. + * If this routine clears the only ACTIVIF, + * then it can never get out of the suspend + * mode. + */ + + U1OTGIE |= PIC32_U1OTGI_ACTV; // Enable bus activity interrupt + U1IR = PIC32_U1I_IDLE; + + /* + * At this point the PIC can go into sleep,idle, or + * switch to a slower clock, etc. This should be done in the + * usbcb_suspend() if necessary. + */ + usbcb_suspend(); // Required callback, see usbcallbacks.c +} + +/* + * Wake up the USB module from suspend. + */ +void usb_wake_from_suspend(void) +{ + /* + * If using clock switching, the place to restore the original + * microcontroller core clock frequency is in the usbcb_wake_from_suspend() callback + */ + usbcb_wake_from_suspend(); // Required callback, see usbcallbacks.c + + U1OTGIE &= ~PIC32_U1OTGI_ACTV; + + /* + Bug Fix: Feb 26, 2007 v2.1 + ********************************************************************* + The ACTVIF bit cannot be cleared immediately after the USB module wakes + up from Suspend or while the USB module is suspended. A few clock cycles + are required to synchronize the internal hardware state machine before + the ACTIVIF bit can be cleared by firmware. Clearing the ACTVIF bit + before the internal hardware is synchronized may not have an effect on + the value of ACTVIF. Additonally, if the USB module uses the clock from + the 96 MHz PLL source, then after clearing the SUSPND bit, the USB + module may not be immediately operational while waiting for the 96 MHz + PLL to lock. + */ + U1OTGIR = PIC32_U1OTGI_ACTV; +} + +/* + * usb_ctrl_ep_service checks for three transaction + * types that it knows how to service and services them: + * 1. EP0 SETUP + * 2. EP0 OUT + * 3. EP0 IN + * It ignores all other types (i.e. EP1, EP2, etc.) + * + * PreCondition: USTAT is loaded with a valid endpoint address. + */ +void usb_ctrl_ep_service(void) +{ + // If the last packet was a EP0 OUT packet + if ((ustat_saved & USTAT_EP0_PP_MASK) == USTAT_EP0_OUT_EVEN) + { + // Point to the EP0 OUT buffer of the buffer that arrived + pBDTEntryEP0OutCurrent = (volatile BDT_ENTRY*) + &usb_buffer [(ustat_saved & USTAT_EP_MASK) >> 2]; + + // Set the next out to the current out packet + pBDTEntryEP0OutNext = pBDTEntryEP0OutCurrent; + + // Toggle it to the next ping pong buffer (if applicable) + *(unsigned char*)&pBDTEntryEP0OutNext ^= USB_NEXT_EP0_OUT_PING_PONG; + + // If the current EP0 OUT buffer has a SETUP token + if (pBDTEntryEP0OutCurrent->STAT.PID == SETUP_TOKEN) + { + // Handle the control transfer + usb_ctrl_trf_setup_handler(); + } else { + // Handle the DATA transfer + usb_ctrl_trf_out_handler(); + } + } else if ((ustat_saved & USTAT_EP0_PP_MASK) == USTAT_EP0_IN) + { + // Otherwise the transmission was and EP0 IN + // so take care of the IN transfer + usb_ctrl_trf_in_handler(); + } +} + +/* + * This routine is a task dispatcher and has 3 stages. + * 1. It initializes the control transfer state machine. + * 2. It calls on each of the module that may know how to + * service the Setup Request from the host. + * Module Example: USBD, HID, CDC, MSD, ... + * A callback function, usbcb_check_other_req(), + * is required to call other module handlers. + * 3. Once each of the modules has had a chance to check if + * it is responsible for servicing the request, stage 3 + * then checks direction of the transfer to determine how + * to prepare EP0 for the control transfer. + * Refer to usb_ctrl_ep_service_complete() for more details. + * + * PreCondition: usb_setup_pkt buffer is loaded with valid USB Setup Data + * + * Microchip USB Firmware has three different states for + * the control transfer state machine: + * 1. WAIT_SETUP + * 2. CTRL_TRF_TX + * 3. CTRL_TRF_RX + * Refer to firmware manual to find out how one state + * is transitioned to another. + * + * A Control Transfer is composed of many USB transactions. + * When transferring data over multiple transactions, + * it is important to keep track of data source, data + * destination, and data count. These three parameters are + * stored in pSrc, pDst, and wCount. A flag is used to + * note if the data source is from ROM or RAM. + */ +void usb_ctrl_trf_setup_handler(void) +{ + //if the SIE currently owns the buffer + if (pBDTEntryIn[0]->STAT.UOWN != 0) + { + // give control back to the CPU + // Compensate for after a STALL + pBDTEntryIn[0]->STAT.Val = _UCPU; + } + + // Keep track of if a short packet has been sent yet or not + short_packet_status = SHORT_PKT_NOT_USED; + + /* Stage 1 */ + control_transfer_state = WAIT_SETUP; + + usb_in_pipe[0].wCount = 0; + usb_in_pipe[0].info.Val = 0; + + /* Stage 2 */ + usb_check_std_request(); + usbcb_check_other_req(); // Required callback, see usbcallbacks.c + + /* Stage 3 */ + usb_ctrl_ep_service_complete(); +} + +/* + * This routine handles an OUT transaction according to + * which control transfer state is currently active. + * + * Note that if the the control transfer was from + * host to device, the session owner should be notified + * at the end of each OUT transaction to service the + * received data. + */ +void usb_ctrl_trf_out_handler(void) +{ + if (control_transfer_state == CTRL_TRF_RX) + { + usb_ctrl_trf_rx_service(); + } + else // CTRL_TRF_TX + { + usb_prepare_for_next_setup_trf(); + } +} + +/* + * This routine handles an IN transaction according to + * which control transfer state is currently active. + * + * A Set Address Request must not change the acutal address + * of the device until the completion of the control + * transfer. The end of the control transfer for Set Address + * Request is an IN transaction. Therefore it is necessary + * to service this unique situation when the condition is + * right. Macro mUSBCheckAdrPendingState is defined in + * usb9.h and its function is to specifically service this event. + */ +void usb_ctrl_trf_in_handler(void) +{ + unsigned lastDTS; + + lastDTS = pBDTEntryIn[0]->STAT.DTS; + + //switch to the next ping pong buffer + *(unsigned char*)&pBDTEntryIn[0] ^= USB_NEXT_EP0_IN_PING_PONG; + + //mUSBCheckAdrPendingState(); // Must check if in ADR_PENDING_STATE + if (usb_device_state == ADR_PENDING_STATE) + { + U1ADDR = usb_setup_pkt.bDevADR; + if (U1ADDR > 0) + { + usb_device_state = ADDRESS_STATE; + } + else + { + usb_device_state = DEFAULT_STATE; + } + }//end if + + + if (control_transfer_state == CTRL_TRF_TX) + { + pBDTEntryIn[0]->ADR = ConvertToPhysicalAddress (ctrl_trf_data); + usb_ctrl_trf_tx_service(); + + /* v2b fix */ + if (short_packet_status == SHORT_PKT_SENT) + { + // If a short packet has been sent, don't want to send any more, + // stall next time if host is still trying to read. + pBDTEntryIn[0]->STAT.Val = _USIE|_BSTALL; + } else { + if (lastDTS == 0) { + pBDTEntryIn[0]->STAT.Val = _USIE|_DAT1|_DTSEN; + } else { + pBDTEntryIn[0]->STAT.Val = _USIE|_DAT0|_DTSEN; + } + } + } else { + // CTRL_TRF_RX + usb_prepare_for_next_setup_trf(); + } +} + +/* + * The routine forces EP0 OUT to be ready for a new + * Setup transaction, and forces EP0 IN to be owned by CPU. + */ +void usb_prepare_for_next_setup_trf(void) +{ + /* + Bug Fix: Feb 26, 2007 v2.1 + ********************************************************************* + Facts: + A Setup Packet should never be stalled. (USB 2.0 Section 8.5.3) + If a Setup PID is detected by the SIE, the DTSEN setting is ignored. + This causes a problem at the end of a control write transaction. + In usb_ctrl_ep_service_complete(), during a control write (Host to Device), + the EP0_OUT is setup to write any data to the ctrl_trf_data buffer. + If is completed and usb_ctrl_trf_in_handler() is not + called before the next is received, then the latest Setup + data will be written to the ctrl_trf_data buffer instead of the usb_setup_pkt + buffer. + + If usb_ctrl_trf_in_handler() was called before the latest is + received, then there would be no problem, + because usb_prepare_for_next_setup_trf() would have been called and updated + ep0Bo.ADR to point to the usb_setup_pkt buffer. + + Work around: + Check for the problem as described above and copy the Setup data from + ctrl_trf_data to usb_setup_pkt. + */ + if ((control_transfer_state == CTRL_TRF_RX) && + (U1CON & PIC32_U1CON_PKTDIS) && + (pBDTEntryEP0OutCurrent->CNT == sizeof(CTRL_TRF_SETUP)) && + (pBDTEntryEP0OutCurrent->STAT.PID == SETUP_TOKEN) && + (pBDTEntryEP0OutNext->STAT.UOWN == 0)) + { + unsigned setup_cnt; + + pBDTEntryEP0OutNext->ADR = ConvertToPhysicalAddress(&usb_setup_pkt); + + // The Setup data was written to the ctrl_trf_data buffer, must copy + // it back to the usb_setup_pkt buffer so that it can be processed correctly + // by usb_ctrl_trf_setup_handler(). + for(setup_cnt = 0; setup_cnt < sizeof(CTRL_TRF_SETUP); setup_cnt++) + { + *(((unsigned char*) &usb_setup_pkt) + setup_cnt) = + *(((unsigned char*) &ctrl_trf_data) + setup_cnt); + } + /* End v3b fix */ + } else { + control_transfer_state = WAIT_SETUP; + pBDTEntryEP0OutNext->CNT = USB_EP0_BUFF_SIZE; // Defined in target.cfg + pBDTEntryEP0OutNext->ADR = ConvertToPhysicalAddress(&usb_setup_pkt); + + /* + Bug Fix: Feb 26, 2007 v2.1 (#F1) + ********************************************************************* + In the original firmware, if an OUT token is sent by the host + before a SETUP token is sent, the firmware would respond with an ACK. + This is not a correct response, the firmware should have sent a STALL. + This is a minor non-compliance since a compliant host should not + send an OUT before sending a SETUP token. The fix allows a SETUP + transaction to be accepted while stalling OUT transactions. + */ + //ep0Bo.Stat.Val = _USIE|_DAT0|_DTSEN; // Removed + pBDTEntryEP0OutNext->STAT.Val = _USIE|_DAT0|_DTSEN|_BSTALL; //Added #F1 + + /* + Bug Fix: Feb 26, 2007 v2.1 (#F3) + ********************************************************************* + In the original firmware, if an IN token is sent by the host + before a SETUP token is sent, the firmware would respond with an ACK. + This is not a correct response, the firmware should have sent a STALL. + This is a minor non-compliance since a compliant host should not + send an IN before sending a SETUP token. + + Comment why this fix (#F3) is interfering with fix (#AF1). + */ + pBDTEntryIn[0]->STAT.Val = _UCPU; // Should be removed + + { + BDT_ENTRY* p; + + p = (BDT_ENTRY*)(((unsigned int)pBDTEntryIn[0])^USB_NEXT_EP0_IN_PING_PONG); + p->STAT.Val = _UCPU; + } + + //ep0Bi.Stat.Val = _USIE|_BSTALL; // Should be added #F3 + } + + //if someone is still expecting data from the control transfer + // then make sure to terminate that request and let them know that + // they are done + if (usb_out_pipe[0].info.bits.busy == 1) { + if (usb_out_pipe[0].pFunc != 0) { + usb_out_pipe[0].pFunc(); + } + usb_out_pipe[0].info.bits.busy = 0; + } + +}//end usb_prepare_for_next_setup_trf + +/* + * This routine checks the setup data packet to see + * if it knows how to handle it + */ +void usb_check_std_request(void) +{ + if (usb_setup_pkt.RequestType != STANDARD) return; + + switch (usb_setup_pkt.bRequest) { + case SET_ADR: + usb_in_pipe[0].info.bits.busy = 1; // This will generate a zero length packet + usb_device_state = ADR_PENDING_STATE; // Update state only + /* See usb_ctrl_trf_in_handler() for the next step */ + break; + case GET_DSC: + usb_std_get_dsc_handler(); + break; + case SET_CFG: + usb_std_set_cfg_handler(); + break; + case GET_CFG: + usb_in_pipe[0].pSrc.bRam = (unsigned char*)&usb_active_configuration; // Set Source + usb_in_pipe[0].info.bits.ctrl_trf_mem = _RAM; // Set memory type + usb_in_pipe[0].wCount |= 0xff; // Set data count + usb_in_pipe[0].info.bits.busy = 1; + break; + case GET_STATUS: + usb_std_get_status_handler(); + break; + case CLR_FEATURE: + case SET_FEATURE: + usb_std_feature_req_handler(); + break; + case GET_INTF: + usb_in_pipe[0].pSrc.bRam = (unsigned char*)&usb_alternate_interface + + usb_setup_pkt.bIntfID; // Set source + usb_in_pipe[0].info.bits.ctrl_trf_mem = _RAM; // Set memory type + usb_in_pipe[0].wCount |= 0xff; // Set data count + usb_in_pipe[0].info.bits.busy = 1; + break; + case SET_INTF: + usb_in_pipe[0].info.bits.busy = 1; + usb_alternate_interface[usb_setup_pkt.bIntfID] = usb_setup_pkt.bAltID; + break; + case SET_DSC: + usbcb_std_set_dsc_handler(); + break; + case SYNCH_FRAME: + default: + break; + } +} + +/* + * This routine handles the standard SET & CLEAR + * FEATURES requests + */ +void usb_std_feature_req_handler(void) +{ + BDT_ENTRY *p; + unsigned int *pUEP; + +#ifdef USB_SUPPORT_OTG + if ((usb_setup_pkt.bFeature == OTG_FEATURE_B_HNP_ENABLE)&& + (usb_setup_pkt.Recipient == RCPT_DEV)) + { + usb_in_pipe[0].info.bits.busy = 1; + if (usb_setup_pkt.bRequest == SET_FEATURE) + USBOTGEnableHnp(); + else + USBOTGDisableHnp(); + } + + if ((usb_setup_pkt.bFeature == OTG_FEATURE_A_HNP_SUPPORT)&& + (usb_setup_pkt.Recipient == RCPT_DEV)) + { + usb_in_pipe[0].info.bits.busy = 1; + if (usb_setup_pkt.bRequest == SET_FEATURE) + USBOTGEnableSupportHnp(); + else + USBOTGDisableSupportHnp(); + } + + + if ((usb_setup_pkt.bFeature == OTG_FEATURE_A_ALT_HNP_SUPPORT)&& + (usb_setup_pkt.Recipient == RCPT_DEV)) + { + usb_in_pipe[0].info.bits.busy = 1; + if (usb_setup_pkt.bRequest == SET_FEATURE) + USBOTGEnableAltHnp(); + else + USBOTGDisableAltHnp(); + } +#endif + if ((usb_setup_pkt.bFeature == DEVICE_REMOTE_WAKEUP)&& + (usb_setup_pkt.Recipient == RCPT_DEV)) + { + usb_in_pipe[0].info.bits.busy = 1; + if (usb_setup_pkt.bRequest == SET_FEATURE) + usb_remote_wakeup = 1; + else + usb_remote_wakeup = 0; + } + + if ((usb_setup_pkt.bFeature == ENDPOINT_HALT)&& + (usb_setup_pkt.Recipient == RCPT_EP)&& + (usb_setup_pkt.EPNum != 0)) + { + usb_in_pipe[0].info.bits.busy = 1; + /* Must do address calculation here */ + + if (usb_setup_pkt.EPDir == 0) + { + p = (BDT_ENTRY*)pBDTEntryOut[usb_setup_pkt.EPNum]; + } else { + p = (BDT_ENTRY*)pBDTEntryIn[usb_setup_pkt.EPNum]; + } + + //if it was a SET_FEATURE request + if (usb_setup_pkt.bRequest == SET_FEATURE) + { + // Then STALL the endpoint + p->STAT.Val = _USIE|_BSTALL; + } else { + // If it was not a SET_FEATURE + // point to the appropriate UEP register + pUEP = (unsigned int*) &U1EP(0); + pUEP += usb_setup_pkt.EPNum * 4; + + //Clear the STALL bit in the UEP register + *pUEP &= ~UEP_STALL; + + if (usb_setup_pkt.EPDir == 1) // IN + { + // If the endpoint is an IN endpoint then we + // need to return it to the CPU and reset the + // DTS bit so that the next transfer is correct +#if (USB_PING_PONG_MODE == USB_PING_PONG__ALL_BUT_EP0) || \ + (USB_PING_PONG_MODE == USB_PING_PONG__FULL_PING_PONG) + p->STAT.Val = _UCPU | _DAT0; + // toggle over the to the next buffer + *(unsigned char*)&p ^= USB_NEXT_PING_PONG; + p->STAT.Val = _UCPU | _DAT1; +#else + p->STAT.Val = _UCPU | _DAT1; +#endif + } else { + // If the endpoint was an OUT endpoint then we + // need to give control of the endpoint back to + // the SIE so that the function driver can + // receive the data as they expected. Also need + // to set the DTS bit so the next packet will be + // correct +#if (USB_PING_PONG_MODE == USB_PING_PONG__ALL_BUT_EP0) || \ + (USB_PING_PONG_MODE == USB_PING_PONG__FULL_PING_PONG) + p->STAT.Val = _USIE|_DAT0|_DTSEN; + //toggle over the to the next buffer + *(unsigned char*)&p ^= USB_NEXT_PING_PONG; + p->STAT.Val = _USIE|_DAT1|_DTSEN; +#else + p->STAT.Val = _USIE|_DAT1|_DTSEN; +#endif + } + } + } +} + +/* + * This routine handles the standard GET_DESCRIPTOR request. + */ +void usb_std_get_dsc_handler(void) +{ + if (usb_setup_pkt.bmRequestType == 0x80) + { + usb_in_pipe[0].info.Val = USB_INPIPES_ROM | USB_INPIPES_BUSY | USB_INPIPES_INCLUDE_ZERO; + + switch(usb_setup_pkt.bDescriptorType) + { + case USB_DESCRIPTOR_DEVICE: + usb_in_pipe[0].pSrc.bRom = (const unsigned char*) &usb_device; + usb_in_pipe[0].wCount = sizeof(usb_device); + break; + case USB_DESCRIPTOR_CONFIGURATION: + usb_in_pipe[0].pSrc.bRom = usb_config [usb_setup_pkt.bDscIndex]; + usb_in_pipe[0].wCount = *(usb_in_pipe[0].pSrc.wRom+1); // Set data count + break; + case USB_DESCRIPTOR_STRING: +#if defined(USB_NUM_STRING_DESCRIPTORS) + if (usb_setup_pkt.bDscIndex < USB_NUM_STRING_DESCRIPTORS) +#else + if (1) +#endif + { + //Get a pointer to the String descriptor requested + usb_in_pipe[0].pSrc.bRom = usb_string [usb_setup_pkt.bDscIndex]; + // Set data count + usb_in_pipe[0].wCount = *usb_in_pipe[0].pSrc.bRom; + } + else + { + usb_in_pipe[0].info.Val = 0; + } + break; + default: + usb_in_pipe[0].info.Val = 0; + break; + }//end switch + }//end if +}//end usb_std_get_dsc_handler + +/* + * This routine handles the standard GET_STATUS request + */ +void usb_std_get_status_handler(void) +{ + ctrl_trf_data[0] = 0; // Initialize content + ctrl_trf_data[1] = 0; + + switch(usb_setup_pkt.Recipient) + { + case RCPT_DEV: + usb_in_pipe[0].info.bits.busy = 1; + /* + * [0]: bit0: Self-Powered Status [0] Bus-Powered [1] Self-Powered + * bit1: RemoteWakeup [0] Disabled [1] Enabled + */ + ctrl_trf_data[0] |= 1; // self powered + + if (usb_remote_wakeup == 1) { + ctrl_trf_data[0] |= 2; + } + break; + case RCPT_INTF: + usb_in_pipe[0].info.bits.busy = 1; // No data to update + break; + case RCPT_EP: + usb_in_pipe[0].info.bits.busy = 1; + /* + * [0]: bit0: Halt Status [0] Not Halted [1] Halted + */ + { + BDT_ENTRY *p; + + if (usb_setup_pkt.EPDir == 0) + { + p = (BDT_ENTRY*)pBDTEntryOut[usb_setup_pkt.EPNum]; + } else { + p = (BDT_ENTRY*)pBDTEntryIn[usb_setup_pkt.EPNum]; + } + + if (p->STAT.Val & _BSTALL) // Use _BSTALL as a bit mask + ctrl_trf_data[0] = 1; // Set bit0 + break; + } + }//end switch + + if (usb_in_pipe[0].info.bits.busy == 1) + { + usb_in_pipe[0].pSrc.bRam = (unsigned char*) &ctrl_trf_data; // Set Source + usb_in_pipe[0].info.bits.ctrl_trf_mem = _RAM; // Set memory type + usb_in_pipe[0].wCount &= ~0xff; + usb_in_pipe[0].wCount |= 2; // Set data count + } +} + +/* + * This routine wrap up the ramaining tasks in servicing + * a Setup Request. Its main task is to set the endpoint + * controls appropriately for a given situation. See code + * below. + * There are three main scenarios: + * a) There was no handler for the Request, in this case + * a STALL should be sent out. + * b) The host has requested a read control transfer, + * endpoints are required to be setup in a specific way. + * c) The host has requested a write control transfer, or + * a control data stage is not required, endpoints are + * required to be setup in a specific way. + * + * Packet processing is resumed by clearing PKTDIS bit. + */ +void usb_ctrl_ep_service_complete(void) +{ + /* + * PKTDIS bit is set when a Setup Transaction is received. + * Clear to resume packet processing. + */ + U1CON &= ~PIC32_U1CON_PKTDIS; + + if (usb_in_pipe[0].info.bits.busy == 0) + { + if (usb_out_pipe[0].info.bits.busy == 1) + { + control_transfer_state = CTRL_TRF_RX; + /* + * Control Write: + * ... | + * + * 1. Prepare IN EP to respond to early termination + * + * This is the same as a Zero Length Packet Response + * for control transfer without a data stage + */ + pBDTEntryIn[0]->CNT = 0; + pBDTEntryIn[0]->STAT.Val = _USIE|_DAT1|_DTSEN; + + /* + * 2. Prepare OUT EP to receive data. + */ + pBDTEntryEP0OutNext->CNT = USB_EP0_BUFF_SIZE; + pBDTEntryEP0OutNext->ADR = ConvertToPhysicalAddress (&ctrl_trf_data); + pBDTEntryEP0OutNext->STAT.Val = _USIE|_DAT1|_DTSEN; + } else { + /* + * If no one knows how to service this request then stall. + * Must also prepare EP0 to receive the next SETUP transaction. + */ + pBDTEntryEP0OutNext->CNT = USB_EP0_BUFF_SIZE; + pBDTEntryEP0OutNext->ADR = ConvertToPhysicalAddress(&usb_setup_pkt); + + /* v2b fix */ + pBDTEntryEP0OutNext->STAT.Val = _USIE|_DAT0|_DTSEN|_BSTALL; + pBDTEntryIn[0]->STAT.Val = _USIE|_BSTALL; + } + } else { + // A module has claimed ownership of the control transfer session. + if (usb_out_pipe[0].info.bits.busy == 0) + { + if (usb_setup_pkt.DataDir == DEV_TO_HOST) + { + if (usb_setup_pkt.wLength < usb_in_pipe[0].wCount) + { + usb_in_pipe[0].wCount = usb_setup_pkt.wLength; + } + usb_ctrl_trf_tx_service(); + control_transfer_state = CTRL_TRF_TX; + /* + * Control Read: + * ... | + * 1. Prepare OUT EP to respond to early termination + * + * NOTE: + * If something went wrong during the control transfer, + * the last status stage may not be sent by the host. + * When this happens, two different things could happen + * depending on the host. + * a) The host could send out a RESET. + * b) The host could send out a new SETUP transaction + * without sending a RESET first. + * To properly handle case (b), the OUT EP must be setup + * to receive either a zero length OUT transaction, or a + * new SETUP transaction. + * + * Furthermore, the Cnt byte should be set to prepare for + * the SETUP data (8-byte or more), and the buffer address + * should be pointed to usb_setup_pkt. + */ + pBDTEntryEP0OutNext->CNT = USB_EP0_BUFF_SIZE; + pBDTEntryEP0OutNext->ADR = ConvertToPhysicalAddress(&usb_setup_pkt); + pBDTEntryEP0OutNext->STAT.Val = _USIE; // Note: DTSEN is 0! + + pBDTEntryEP0OutCurrent->CNT = USB_EP0_BUFF_SIZE; + pBDTEntryEP0OutCurrent->ADR = (unsigned char*)&usb_setup_pkt; + pBDTEntryEP0OutCurrent->STAT.Val = _USIE; // Note: DTSEN is 0! + + /* + * 2. Prepare IN EP to transfer data, Cnt should have + * been initialized by responsible request owner. + */ + pBDTEntryIn[0]->ADR = ConvertToPhysicalAddress (&ctrl_trf_data); + pBDTEntryIn[0]->STAT.Val = _USIE|_DAT1|_DTSEN; + + } else { // (usb_setup_pkt.DataDir == HOST_TO_DEVICE) + + control_transfer_state = CTRL_TRF_RX; + /* + * Control Write: + * ... | + * + * 1. Prepare IN EP to respond to early termination + * + * This is the same as a Zero Length Packet Response + * for control transfer without a data stage + */ + pBDTEntryIn[0]->CNT = 0; + pBDTEntryIn[0]->STAT.Val = _USIE|_DAT1|_DTSEN; + + /* + * 2. Prepare OUT EP to receive data. + */ + pBDTEntryEP0OutNext->CNT = USB_EP0_BUFF_SIZE; + pBDTEntryEP0OutNext->ADR = ConvertToPhysicalAddress (&ctrl_trf_data); + pBDTEntryEP0OutNext->STAT.Val = _USIE|_DAT1|_DTSEN; + } + } + } +} + + +/* + * This routine should be called from only two places. + * One from usb_ctrl_ep_service_complete() and one from + * usb_ctrl_trf_in_handler(). It takes care of managing a + * transfer over multiple USB transactions. + * + * This routine works with isochronous endpoint larger than + * 256 bytes and is shown here as an example of how to deal + * with BC9 and BC8. In reality, a control endpoint can never + * be larger than 64 bytes. + * + * PreCondition: pSrc, wCount, and usb_stat.ctrl_trf_mem are setup properly. + */ +void usb_ctrl_trf_tx_service(void) +{ + unsigned byteToSend; + unsigned char *dst; + + /* + * First, have to figure out how many byte of data to send. + */ + if (usb_in_pipe[0].wCount < USB_EP0_BUFF_SIZE) + { + byteToSend = usb_in_pipe[0].wCount; + + /* v2b fix */ + if (short_packet_status == SHORT_PKT_NOT_USED) { + short_packet_status = SHORT_PKT_PENDING; + + } else if (short_packet_status == SHORT_PKT_PENDING) { + short_packet_status = SHORT_PKT_SENT; + } + /* end v2b fix for this section */ + } + else + { + byteToSend = USB_EP0_BUFF_SIZE; + } + + /* + * Next, load the number of bytes to send to BC9..0 in buffer descriptor + */ + pBDTEntryIn[0]->CNT = byteToSend; + + /* + * Subtract the number of bytes just about to be sent from the total. + */ + usb_in_pipe[0].wCount = usb_in_pipe[0].wCount - byteToSend; + + // Set destination pointer + dst = (unsigned char*) ctrl_trf_data; + + // Determine type of memory source + if (usb_in_pipe[0].info.bits.ctrl_trf_mem == USB_INPIPES_ROM) + { + while (byteToSend) + { + *dst++ = *usb_in_pipe[0].pSrc.bRom++; + byteToSend--; + } + } else { // RAM + while (byteToSend) + { + *dst++ = *usb_in_pipe[0].pSrc.bRam++; + byteToSend--; + } + } +} + +/* + * *** This routine is only partially complete. Check for + * new version of the firmware. + * + * PreCondition: pDst and wCount are setup properly. + * pSrc is always &ctrl_trf_data + * usb_stat.ctrl_trf_mem is always _RAM. + * wCount should be set to 0 at the start of each control transfer. + */ +void usb_ctrl_trf_rx_service(void) +{ + unsigned byteToRead, i; + + byteToRead = pBDTEntryEP0OutCurrent->CNT; + + /* + * Accumulate total number of bytes read + */ + if (byteToRead > usb_out_pipe[0].wCount) + { + byteToRead = usb_out_pipe[0].wCount; + } else { + usb_out_pipe[0].wCount = usb_out_pipe[0].wCount - byteToRead; + } + + for(i=0;i 0) + { + /* + * Don't have to worry about overwriting _KEEP bit + * because if _KEEP was set, TRNIF would not have been + * generated in the first place. + */ + pBDTEntryEP0OutNext->CNT = USB_EP0_BUFF_SIZE; + pBDTEntryEP0OutNext->ADR = ConvertToPhysicalAddress (&ctrl_trf_data); + if (pBDTEntryEP0OutCurrent->STAT.DTS == 0) + { + pBDTEntryEP0OutNext->STAT.Val = _USIE|_DAT1|_DTSEN; + } else { + pBDTEntryEP0OutNext->STAT.Val = _USIE|_DAT0|_DTSEN; + } + } else { + pBDTEntryEP0OutNext->ADR = ConvertToPhysicalAddress(&usb_setup_pkt); + if (usb_out_pipe[0].pFunc != 0) { + usb_out_pipe[0].pFunc(); + } + usb_out_pipe[0].info.bits.busy = 0; + } + + // reset ep0Bo.Cnt to USB_EP0_BUFF_SIZE + +}//end usb_ctrl_trf_rx_service + +/* + * This routine first disables all endpoints by + * clearing UEP registers. It then configures + * (initializes) endpoints by calling the callback + * function usbcb_init_ep(). + */ +void usb_std_set_cfg_handler(void) +{ + unsigned i; + + // This will generate a zero length packet + usb_in_pipe[0].info.bits.busy = 1; + + // disable all endpoints except endpoint 0 + for (i=1; iSTAT.UOWN = 0; + + if (direction == 0) { + pBDTEntryOut[epnum] = handle; + } else { + pBDTEntryIn[epnum] = handle; + } + +#if (USB_PING_PONG_MODE == USB_PING_PONG__FULL_PING_PONG) + handle->STAT.DTS = 0; + (handle+1)->STAT.DTS = 1; +#elif (USB_PING_PONG_MODE == USB_PING_PONG__NO_PING_PONG) + //Set DTS to one because the first thing we will do + //when transmitting is toggle the bit + handle->STAT.DTS = 1; +#elif (USB_PING_PONG_MODE == USB_PING_PONG__EP0_OUT_ONLY) + if (epnum != 0) + { + handle->STAT.DTS = 1; + } +#elif (USB_PING_PONG_MODE == USB_PING_PONG__ALL_BUT_EP0) + if (epnum != 0) + { + handle->STAT.DTS = 0; + (handle+1)->STAT.DTS = 1; + } +#endif +} + +/* + * This function will enable the specified endpoint with the specified + * options. + * + * Typical Usage: + * + * void usbcb_init_ep(void) + * { + * usb_enable_endpoint(MSD_DATA_IN_EP,USB_IN_ENABLED|USB_OUT_ENABLED|USB_HANDSHAKE_ENABLED|USB_DISALLOW_SETUP); + * USBMSDInit(); + * } + * + * + * In the above example endpoint number MSD_DATA_IN_EP is being configured + * for both IN and OUT traffic with handshaking enabled. Also since + * MSD_DATA_IN_EP is not endpoint 0 (MSD does not allow this), then we can + * explicitly disable SETUP packets on this endpoint. + * + * Input: + * unsigned ep - the endpoint to be configured + * unsigned options - optional settings for the endpoint. The options should + * be ORed together to form a single options string. The + * available optional settings for the endpoint. The + * options should be ORed together to form a single options + * string. The available options are the following\: + * * USB_HANDSHAKE_ENABLED enables USB handshaking (ACK, + * NAK) + * * USB_HANDSHAKE_DISABLED disables USB handshaking (ACK, + * NAK) + * * USB_OUT_ENABLED enables the out direction + * * USB_OUT_DISABLED disables the out direction + * * USB_IN_ENABLED enables the in direction + * * USB_IN_DISABLED disables the in direction + * * USB_ALLOW_SETUP enables control transfers + * * USB_DISALLOW_SETUP disables control transfers + * * USB_STALL_ENDPOINT STALLs this endpoint + */ +void usb_enable_endpoint (unsigned ep, unsigned options) +{ + // Set the options to the appropriate endpoint control register + unsigned int *p = (unsigned int*) (&U1EP(0) + (4 * ep)); + + *p = options; + + if (options & USB_OUT_ENABLED) { + usb_configure_endpoint(ep, 0); + } + if (options & USB_IN_ENABLED) { + usb_configure_endpoint(ep, 1); + } +} + +/* + * STALLs the specified endpoint + * + * Input: + * unsigned ep - the endpoint the data will be transmitted on + * unsigned dir - the direction of the transfer + */ +void usb_stall_endpoint (unsigned ep, unsigned dir) +{ + BDT_ENTRY *p; + + if (ep == 0) { + /* + * If no one knows how to service this request then stall. + * Must also prepare EP0 to receive the next SETUP transaction. + */ + pBDTEntryEP0OutNext->CNT = USB_EP0_BUFF_SIZE; + pBDTEntryEP0OutNext->ADR = ConvertToPhysicalAddress(&usb_setup_pkt); + + /* v2b fix */ + pBDTEntryEP0OutNext->STAT.Val = _USIE|_DAT0|_DTSEN|_BSTALL; + pBDTEntryIn[0]->STAT.Val = _USIE|_BSTALL; + } else { + p = (BDT_ENTRY*) &usb_buffer[EP(ep, dir, 0)]; + p->STAT.Val |= _BSTALL | _USIE; + + //If the device is in FULL or ALL_BUT_EP0 ping pong modes + //then stall that entry as well +#if (USB_PING_PONG_MODE == USB_PING_PONG__FULL_PING_PONG) || \ + (USB_PING_PONG_MODE == USB_PING_PONG__ALL_BUT_EP0) + + p = (BDT_ENTRY*) &usb_buffer[EP(ep, dir, 1)]; + p->STAT.Val |= _BSTALL | _USIE; +#endif + } +} + +/* + * Transfers one packet over the USB. + * + * Input: + * unsigned ep - the endpoint the data will be transmitted on + * unsigned dir - the direction of the transfer + * This value is either OUT_FROM_HOST or IN_TO_HOST + * unsigned char* data - pointer to the data to be sent + * unsigned len - length of the data needing to be sent + */ +USB_HANDLE usb_transfer_one_packet (unsigned ep, unsigned dir, + unsigned char* data, unsigned len) +{ + USB_HANDLE handle; + + // If the direction is IN + if (dir != 0) { + // point to the IN BDT of the specified endpoint + handle = pBDTEntryIn[ep]; + } else { + // else point to the OUT BDT of the specified endpoint + handle = pBDTEntryOut[ep]; + } + + //Toggle the DTS bit if required +#if (USB_PING_PONG_MODE == USB_PING_PONG__NO_PING_PONG) + handle->STAT.Val ^= _DTSMASK; +#elif (USB_PING_PONG_MODE == USB_PING_PONG__EP0_OUT_ONLY) + if (ep != 0) { + handle->STAT.Val ^= _DTSMASK; + } +#endif + + //Set the data pointer, data length, and enable the endpoint + handle->ADR = ConvertToPhysicalAddress(data); + handle->CNT = len; + handle->STAT.Val &= _DTSMASK; + handle->STAT.Val |= _USIE | _DTSEN; + + // Point to the next buffer for ping pong purposes. + if (dir != 0) { + // toggle over the to the next buffer for an IN endpoint + *(unsigned char*)&pBDTEntryIn[ep] ^= USB_NEXT_PING_PONG; + } else { + // toggle over the to the next buffer for an OUT endpoint + *(unsigned char*)&pBDTEntryOut[ep] ^= USB_NEXT_PING_PONG; + } + return handle; +} + +/* + * USB Callback Functions + */ +/* + * Call back that is invoked when a USB suspend is detected. + */ +void __attribute__((weak)) +usbcb_suspend() +{ + /* Empty. */ +} + +/* + * This call back is invoked when a wakeup from USB suspend is detected. + */ +void __attribute__((weak)) +usbcb_wake_from_suspend() +{ + /* Empty. */ +} + +/* + * Called when start-of-frame packet arrives, every 1 ms. + */ +void __attribute__((weak)) +usbcb_sof_handler() +{ + /* Empty. */ +} + +/* + * Called on any USB error interrupt, for debugging purposes. + */ +void __attribute__((weak)) +usbcb_error_handler() +{ + /* Empty. */ +} + +/* + * Handle a SETUP SET_DESCRIPTOR request (optional). + */ +void __attribute__((weak)) +usbcb_std_set_dsc_handler() +{ + /* Empty. */ +} diff --git a/sys/pic32/usb_device.h b/sys/pic32/usb_device.h new file mode 100644 index 0000000..c5cde64 --- /dev/null +++ b/sys/pic32/usb_device.h @@ -0,0 +1,1740 @@ +/* + * USB Device header file + * + * This file, with its associated C source file, provides the main substance of + * the USB device side stack. These files will receive, transmit, and process + * various USB commands as well as take action when required for various events + * that occur on the bus. + * + * The software supplied herewith by Microchip Technology Incorporated + * (the 'Company') for its PIC® Microcontroller is intended and + * supplied to you, the Company's customer, for use solely and + * exclusively on Microchip PIC Microcontroller products. The + * software is owned by the Company and/or its supplier, and is + * protected under applicable copyright laws. All rights are reserved. + * Any use in violation of the foregoing restrictions may subject the + * user to criminal sanctions under applicable laws, as well as to + * civil liability for the breach of the terms and conditions of this + * license. + * + * THIS SOFTWARE IS PROVIDED IN AN 'AS IS' CONDITION. NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED + * TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE COMPANY SHALL NOT, + * IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR + * CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER. + */ +#ifndef USBDEVICE_H +#define USBDEVICE_H + +#include +#include + +/* + * USB Endpoint Definitions + * USB Standard EP Address Format: DIR:X:X:X:EP3:EP2:EP1:EP0 + * This is used in the descriptors. See usbcfg.c + * + * NOTE: Do not use these values for checking against USTAT. + * To check against USTAT, use values defined in usbd.h. + */ +#define _EP_IN 0x80 +#define _EP_OUT 0x00 +#define _EP01_OUT 0x01 +#define _EP01_IN 0x81 +#define _EP02_OUT 0x02 +#define _EP02_IN 0x82 +#define _EP03_OUT 0x03 +#define _EP03_IN 0x83 +#define _EP04_OUT 0x04 +#define _EP04_IN 0x84 +#define _EP05_OUT 0x05 +#define _EP05_IN 0x85 +#define _EP06_OUT 0x06 +#define _EP06_IN 0x86 +#define _EP07_OUT 0x07 +#define _EP07_IN 0x87 +#define _EP08_OUT 0x08 +#define _EP08_IN 0x88 +#define _EP09_OUT 0x09 +#define _EP09_IN 0x89 +#define _EP10_OUT 0x0A +#define _EP10_IN 0x8A +#define _EP11_OUT 0x0B +#define _EP11_IN 0x8B +#define _EP12_OUT 0x0C +#define _EP12_IN 0x8C +#define _EP13_OUT 0x0D +#define _EP13_IN 0x8D +#define _EP14_OUT 0x0E +#define _EP14_IN 0x8E +#define _EP15_OUT 0x0F +#define _EP15_IN 0x8F + +/* Configuration Attributes */ +#define _DEFAULT (0x01 << 7) // Default Value (Bit 7 is set) +#define _SELF (0x01 << 6) // Self-powered (Supports if set) +#define _RWU (0x01 << 5) // Remote Wakeup (Supports if set) +#define _HNP (0x01 << 1) // HNP (Supports if set) +#define _SRP (0x01) // SRP (Supports if set) + +/* Endpoint Transfer Type */ +#define _CTRL 0x00 // Control Transfer +#define _ISO 0x01 // Isochronous Transfer +#define _BULK 0x02 // Bulk Transfer +#define _INTERRUPT 0x03 // Interrupt Transfer + +/* Isochronous Endpoint Synchronization Type */ +#define _NS (0x00 << 2) // No Synchronization +#define _AS (0x01 << 2) // Asynchronous +#define _AD (0x02 << 2) // Adaptive +#define _SY (0x03 << 2) // Synchronous + +/* Isochronous Endpoint Usage Type */ +#define _DE (0x00 << 4) // Data endpoint +#define _FE (0x01 << 4) // Feedback endpoint +#define _IE (0x02 << 4) // Implicit feedback Data endpoint + +#define _ROM USB_INPIPES_ROM +#define _RAM USB_INPIPES_RAM + +//These are the directional indicators used for the usb_transfer_one_packet() +// function. +#define OUT_FROM_HOST 0 +#define IN_TO_HOST 1 + +/* + * CTRL_TRF_SETUP: Every setup packet has 8 bytes. This structure + * allows direct access to the various members of the control + * transfer. + */ +typedef union __attribute__ ((packed)) _CTRL_TRF_SETUP +{ + /* Standard Device Requests */ + struct __attribute__ ((packed)) + { + unsigned char bmRequestType; //from table 9-2 of USB2.0 spec + unsigned char bRequest; //from table 9-2 of USB2.0 spec + unsigned short wValue; //from table 9-2 of USB2.0 spec + unsigned short wIndex; //from table 9-2 of USB2.0 spec + unsigned short wLength; //from table 9-2 of USB2.0 spec + }; + struct __attribute__ ((packed)) + { + unsigned :8; + unsigned :8; + unsigned short W_Value; //from table 9-2 of USB2.0 spec, allows byte/bitwise access + unsigned short W_Index; //from table 9-2 of USB2.0 spec, allows byte/bitwise access + unsigned short W_Length; //from table 9-2 of USB2.0 spec, allows byte/bitwise access + }; + struct __attribute__ ((packed)) + { + unsigned Recipient:5; //Device,Interface,Endpoint,Other + unsigned RequestType:2; //Standard,Class,Vendor,Reserved + unsigned DataDir:1; //Host-to-device,Device-to-host + unsigned :8; + unsigned char bFeature; //DEVICE_REMOTE_WAKEUP,ENDPOINT_HALT + unsigned :8; + unsigned :8; + unsigned :8; + unsigned :8; + unsigned :8; + }; + struct __attribute__ ((packed)) + { + unsigned :8; + unsigned :8; + unsigned char bDscIndex; //For Configuration and String DSC Only + unsigned char bDescriptorType; //Device,Configuration,String + unsigned short wLangID; //Language ID + unsigned :8; + unsigned :8; + }; + struct __attribute__ ((packed)) + { + unsigned :8; + unsigned :8; + unsigned char bDevADR; //Device Address 0-127 + unsigned char bDevADRH; //Must equal zero + unsigned :8; + unsigned :8; + unsigned :8; + unsigned :8; + }; + struct __attribute__ ((packed)) + { + unsigned :8; + unsigned :8; + unsigned char bConfigurationValue; //Configuration Value 0-255 + unsigned char bCfgRSD; //Must equal zero (Reserved) + unsigned :8; + unsigned :8; + unsigned :8; + unsigned :8; + }; + struct __attribute__ ((packed)) + { + unsigned :8; + unsigned :8; + unsigned char bAltID; //Alternate Setting Value 0-255 + unsigned char bAltID_H; //Must equal zero + unsigned char bIntfID; //Interface Number Value 0-255 + unsigned char bIntfID_H; //Must equal zero + unsigned :8; + unsigned :8; + }; + struct __attribute__ ((packed)) + { + unsigned :8; + unsigned :8; + unsigned :8; + unsigned :8; + unsigned char bEPID; //Endpoint ID (Number & Direction) + unsigned char bEPID_H; //Must equal zero + unsigned :8; + unsigned :8; + }; + struct __attribute__ ((packed)) + { + unsigned :8; + unsigned :8; + unsigned :8; + unsigned :8; + unsigned EPNum:4; //Endpoint Number 0-15 + unsigned :3; + unsigned EPDir:1; //Endpoint Direction: 0-OUT, 1-IN + unsigned :8; + unsigned :8; + unsigned :8; + }; + + /* End: Standard Device Requests */ + +} CTRL_TRF_SETUP; + +// Defintion of the PIPE structure +// This structure is used to keep track of data that is sent out +// of the stack automatically. +typedef struct __attribute__ ((packed)) +{ + union __attribute__ ((packed)) + { + //Various options of pointers that are available to + // get the data from + unsigned char *bRam; + const unsigned char *bRom; + unsigned short *wRam; + const unsigned short *wRom; + } pSrc; + union __attribute__ ((packed)) + { + struct __attribute__ ((packed)) + { + //is this transfer from RAM or ROM? + unsigned ctrl_trf_mem :1; + unsigned reserved :5; + //include a zero length packet after + //data is done if data_size%ep_size = 0? + unsigned includeZero :1; + //is this PIPE currently in use + unsigned busy :1; + } bits; + unsigned char Val; + } info; + unsigned short wCount; +} IN_PIPE; + +#define CTRL_TRF_RETURN void +#define CTRL_TRF_PARAMS void +typedef struct __attribute__ ((packed)) +{ + union __attribute__ ((packed)) + { + //Various options of pointers that are available to + // get the data from + unsigned char *bRam; + unsigned short *wRam; + } pDst; + union __attribute__ ((packed)) + { + struct __attribute__ ((packed)) + { + unsigned reserved :7; + //is this PIPE currently in use + unsigned busy :1; + } bits; + unsigned char Val; + } info; + unsigned short wCount; + CTRL_TRF_RETURN (*pFunc)(CTRL_TRF_PARAMS); +} OUT_PIPE; + +//Various options for setting the PIPES +#define USB_INPIPES_ROM 0x00 //Data comes from RAM +#define USB_INPIPES_RAM 0x01 //Data comes from ROM +#define USB_INPIPES_BUSY 0x80 //The PIPE is busy +#define USB_INPIPES_INCLUDE_ZERO 0x40 //include a trailing zero packet +#define USB_INPIPES_NO_DATA 0x00 //no data to send +#define USB_INPIPES_NO_OPTIONS 0x00 //no options set + +#define USB_EP0_ROM USB_INPIPES_ROM +#define USB_EP0_RAM USB_INPIPES_RAM +#define USB_EP0_BUSY USB_INPIPES_BUSY +#define USB_EP0_INCLUDE_ZERO USB_INPIPES_INCLUDE_ZERO +#define USB_EP0_NO_DATA USB_INPIPES_NO_DATA +#define USB_EP0_NO_OPTIONS USB_INPIPES_NO_OPTIONS + +/* + * Standard Request Codes + * USB 2.0 Spec Ref Table 9-4 + */ +#define GET_STATUS 0 +#define CLR_FEATURE 1 +#define SET_FEATURE 3 +#define SET_ADR 5 +#define GET_DSC 6 +#define SET_DSC 7 +#define GET_CFG 8 +#define SET_CFG 9 +#define GET_INTF 10 +#define SET_INTF 11 +#define SYNCH_FRAME 12 + +/* Section: Standard Feature Selectors */ +#define DEVICE_REMOTE_WAKEUP 0x01 +#define ENDPOINT_HALT 0x00 + +/* Section: USB Device States - To be used with [BYTE usb_device_state] */ + +/* Detached is the state in which the device is not attached to the bus. When + * in the detached state a device should not have any pull-ups attached to either + * the D+ or D- line. This defintions is a return value of the + * function usb_get_device_state() + */ +#define DETACHED_STATE 0x00 + +/* Attached is the state in which the device is attached ot the bus but the + * hub/port that it is attached to is not yet configured. This defintions is a + * return value of the function usb_get_device_state() + */ +#define ATTACHED_STATE 0x01 + +/* Powered is the state in which the device is attached to the bus and the + * hub/port that it is attached to is configured. This defintions is a return + * value of the function usb_get_device_state() + */ +#define POWERED_STATE 0x02 + +/* Default state is the state after the device receives a RESET command from + * the host. This defintions is a return value of the function usb_get_device_state() + */ +#define DEFAULT_STATE 0x04 + +/* Address pending state is not an official state of the USB defined states. + * This state is internally used to indicate that the device has received a + * SET_ADDRESS command but has not received the STATUS stage of the transfer yet. + * The device is should not switch addresses until after the STATUS stage is + * complete. This defintions is a return value of the function + * usb_get_device_state() + */ +#define ADR_PENDING_STATE 0x08 + +/* Address is the state in which the device has its own specific address on the + * bus. This defintions is a return value of the function usb_get_device_state(). + */ +#define ADDRESS_STATE 0x10 + +/* Configured is the state where the device has been fully enumerated and is + * operating on the bus. The device is now allowed to excute its application + * specific tasks. It is also allowed to increase its current consumption to the + * value specified in the configuration descriptor of the current configuration. + * This defintions is a return value of the function usb_get_device_state(). + */ +#define CONFIGURED_STATE 0x20 + +/* UCFG Initialization Parameters */ +#define SetConfigurationOptions() {U1CNFG1 = 0;} + +/* UEPn Initialization Parameters */ +#define EP_CTRL 0x0C // Cfg Control pipe for this ep +#define EP_OUT 0x18 // Cfg OUT only pipe for this ep +#define EP_IN 0x14 // Cfg IN only pipe for this ep +#define EP_OUT_IN 0x1C // Cfg both OUT & IN pipes for this ep +#define HSHK_EN 0x01 // Enable handshake packet + // Handshake should be disable for isoch + +#define USB_HANDSHAKE_ENABLED 0x01 +#define USB_HANDSHAKE_DISABLED 0x00 + +#define USB_OUT_ENABLED 0x08 +#define USB_OUT_DISABLED 0x00 + +#define USB_IN_ENABLED 0x04 +#define USB_IN_DISABLED 0x00 + +#define USB_ALLOW_SETUP 0x00 +#define USB_DISALLOW_SETUP 0x10 + +#define USB_STALL_ENDPOINT 0x02 + +// USB_HANDLE is a pointer to an entry in the BDT. This pointer can be used +// to read the length of the last transfer, the status of the last transfer, +// and various other information. Insure to initialize USB_HANDLE objects +// to NULL so that they are in a known state during their first usage. +#define USB_HANDLE volatile BDT_ENTRY* + +// PIC32 supports only full ping-pong mode. +#define USB_PING_PONG_MODE USB_PING_PONG__FULL_PING_PONG + +/* Size of buffer for end-point EP0. + * Valid Options: 8, 16, 32, or 64 bytes. + * Using larger options take more SRAM, but + * does not provide much advantage in most types + * of applications. Exceptions to this, are applications + * that use EP0 IN or OUT for sending large amounts of + * application related data. + */ +#ifndef USB_EP0_BUFF_SIZE +# define USB_EP0_BUFF_SIZE 8 +#endif + +/* + * Only one interface by default. + */ +#ifndef USB_MAX_NUM_INT +# define USB_MAX_NUM_INT 1 +#endif + +// Definitions for the BDT +extern volatile BDT_ENTRY usb_buffer[(USB_MAX_EP_NUMBER + 1) * 4]; + +// Device descriptor +extern const USB_DEVICE_DESCRIPTOR usb_device; + +// Array of configuration descriptors +extern const unsigned char *const usb_config[]; +extern const unsigned char usb_config1_descriptor[]; + +// Array of string descriptors +extern const unsigned char *const usb_string[]; + +// Buffer for control transfers +extern volatile CTRL_TRF_SETUP usb_setup_pkt; // 8-byte only + +/* Control Transfer States */ +#define WAIT_SETUP 0 +#define CTRL_TRF_TX 1 +#define CTRL_TRF_RX 2 + +/* v2.1 fix - Short Packet States - Used by Control Transfer Read - CTRL_TRF_TX */ +#define SHORT_PKT_NOT_USED 0 +#define SHORT_PKT_PENDING 1 +#define SHORT_PKT_SENT 2 + +/* USB PID: Token Types - See chapter 8 in the USB specification */ +#define SETUP_TOKEN 0x0D // 0b00001101 +#define OUT_TOKEN 0x01 // 0b00000001 +#define IN_TOKEN 0x09 // 0b00001001 + +/* bmRequestType Definitions */ +#define HOST_TO_DEV 0 +#define DEV_TO_HOST 1 + +#define STANDARD 0x00 +#define CLASS 0x01 +#define VENDOR 0x02 + +#define RCPT_DEV 0 +#define RCPT_INTF 1 +#define RCPT_EP 2 +#define RCPT_OTH 3 + +extern unsigned usb_device_state; +extern unsigned usb_active_configuration; +extern IN_PIPE usb_in_pipe[1]; +extern OUT_PIPE usb_out_pipe[1]; + +/* + Function: + void usb_device_tasks(void) + + Summary: + This function is the main state machine of the USB device side stack. + This function should be called periodically to receive and transmit + packets through the stack. This function should be called preferably + once every 100us during the enumeration process. After the enumeration + process this function still needs to be called periodically to respond + to various situations on the bus but is more relaxed in its time + requirements. This function should also be called at least as fast as + the OUT data expected from the PC. + + Description: + This function is the main state machine of the USB device side stack. + This function should be called periodically to receive and transmit + packets through the stack. This function should be called preferably + once every 100us during the enumeration process. After the enumeration + process this function still needs to be called periodically to respond + to various situations on the bus but is more relaxed in its time + requirements. This function should also be called at least as fast as + the OUT data expected from the PC. + + Typical usage: + + void main(void) + { + usb_device_init(); + while (1) + { + usb_device_tasks(); + if ((usb_get_device_state() \< CONFIGURED_STATE) || usb_is_device_suspended()) + { + // Either the device is not configured or we are suspended + // so we don't want to do execute any application code + continue; //go back to the top of the while loop + } else { + // Otherwise we are free to run user application code. + UserApplication(); + } + } + } + + + Conditions: + None + Remarks: + This function should be called preferably once every 100us during the + enumeration process. After the enumeration process this function still + needs to be called periodically to respond to various situations on the + bus but is more relaxed in its time requirements. + */ +void usb_device_tasks(void); + +/* + Function: + void usb_device_init(void) + + Description: + This function initializes the device stack it in the default state. The + USB module will be completely reset including all of the internal + variables, registers, and interrupt flags. + + Precondition: + This function must be called before any of the other USB Device + functions can be called, including usb_device_tasks(). + + Parameters: + None + + Return Values: + None + + Remarks: + None + + */ +void usb_device_init(void); + +/* + Function: + int usb_get_remote_wakeup_status(void) + + Summary: + This function indicates if remote wakeup has been enabled by the host. + Devices that support remote wakeup should use this function to + determine if it should send a remote wakeup. + + Description: + This function indicates if remote wakeup has been enabled by the host. + Devices that support remote wakeup should use this function to + determine if it should send a remote wakeup. + + If a device does not support remote wakeup (the Remote wakeup bit, bit + 5, of the bmAttributes field of the Configuration descriptor is set to + 1), then it should not send a remote wakeup command to the PC and this + function is not of any use to the device. If a device does support + remote wakeup then it should use this function as described below. + + If this function returns FALSE and the device is suspended, it should + not issue a remote wakeup (resume). + + If this function returns TRUE and the device is suspended, it should + issue a remote wakeup (resume). + + A device can add remote wakeup support by having the _RWU symbol added + in the configuration descriptor (located in the usb_descriptors.c file + in the project). This done in the 8th byte of the configuration + descriptor. For example: + + + const unsigned char configDescriptor1[]={ + 0x09, // Size + USB_DESCRIPTOR_CONFIGURATION, // descriptor type + DESC_CONFIG_WORD(0x0022), // Total length + 1, // Number of interfaces + 1, // Index value of this cfg + 0, // Configuration string index + _DEFAULT | _SELF | _RWU, // Attributes, see usb_device.h + 50, // Max power consumption in 2X mA(100mA) + + //The rest of the configuration descriptor should follow + + + For more information about remote wakeup, see the following section of + the USB v2.0 specification available at www.usb.org: + * Section 9.2.5.2 + * Table 9-10 + * Section 7.1.7.7 + * Section 9.4.5 + + Conditions: + None + + Return Values: + TRUE - Remote Wakeup has been enabled by the host + FALSE - Remote Wakeup is not currently enabled + + Remarks: + None + + */ +#define usb_get_remote_wakeup_status() usb_remote_wakeup + +/* + Function: + unsigned usb_get_device_state(void) + + Summary: + This function will return the current state of the device on the USB. + This function should return CONFIGURED_STATE before an application + tries to send information on the bus. + Description: + This function returns the current state of the device on the USB. This + \function is used to determine when the device is ready to communicate + on the bus. Applications should not try to send or receive data until + this function returns CONFIGURED_STATE. + + It is also important that applications yield as much time as possible + to the usb_device_tasks() function as possible while the this function + \returns any value between ATTACHED_STATE through CONFIGURED_STATE. + + For more information about the various device states, please refer to + the USB specification section 9.1 available from www.usb.org. + + Typical usage: + + void main(void) + { + usb_device_init(); + while(1) + { + usb_device_tasks(); + if ((usb_get_device_state() \< CONFIGURED_STATE) || usb_is_device_suspended()) + { + //Either the device is not configured or we are suspended + // so we don't want to do execute any application code + continue; //go back to the top of the while loop + } + else + { + //Otherwise we are free to run user application code. + UserApplication(); + } + } + } + + Conditions: + None + Return Values: + DETACHED_STATE - The device is not attached to the bus + ATTACHED_STATE - The device is attached to the bus but + POWERED_STATE - The device is not officially in the powered state + DEFAULT_STATE - The device has received a RESET from the host + ADR_PENDING_STATE - The device has received the SET_ADDRESS command but + hasn't received the STATUS stage of the command so + it is still operating on address 0. + ADDRESS_STATE - The device has an address assigned but has not + received a SET_CONFIGURATION command yet or has + received a SET_CONFIGURATION with a configuration + number of 0 (deconfigured) + CONFIGURED_STATE - the device has received a non\-zero + SET_CONFIGURATION command is now ready for + communication on the bus. + Remarks: + None + */ +#define usb_get_device_state() usb_device_state + +/* + Function: + int usb_is_device_suspended(void) + + Summary: + This function indicates if this device is currently suspended. When a + device is suspended it will not be able to transfer data over the bus. + Description: + This function indicates if this device is currently suspended. When a + device is suspended it will not be able to transfer data over the bus. + This function can be used by the application to skip over section of + code that do not need to exectute if the device is unable to send data + over the bus. + + Typical usage: + + void main(void) + { + usb_device_init(); + while(1) + { + usb_device_tasks(); + if ((usb_get_device_state() \< CONFIGURED_STATE) || usb_is_device_suspended()) + { + //Either the device is not configured or we are suspended + // so we don't want to do execute any application code + continue; //go back to the top of the while loop + } + else + { + //Otherwise we are free to run user application code. + UserApplication(); + } + } + } + + Conditions: + None + Return Values: + TRUE - this device is suspended. + FALSE - this device is not suspended. + Remarks: + None + */ +#define usb_is_device_suspended() (U1PWRC & PIC32_U1PWRC_USUSPEND) + +void usb_ctrl_ep_service (void); +void usb_ctrl_trf_setup_handler (void); +void usb_ctrl_trf_in_handler (void); +void usb_check_std_request (void); +void usb_std_get_dsc_handler (void); +void usb_ctrl_ep_service_complete (void); +void usb_ctrl_trf_tx_service (void); +void usb_prepare_for_next_setup_trf (void); +void usb_ctrl_trf_rx_service (void); +void usb_std_set_cfg_handler (void); +void usb_std_get_status_handler (void); +void usb_std_feature_req_handler (void); +void usb_ctrl_trf_out_handler (void); + +void usb_wake_from_suspend (void); +void usb_suspend (void); +void usb_stall_handler (void); +volatile USB_HANDLE usb_transfer_one_packet (unsigned ep, unsigned dir, unsigned char* data, unsigned len); +void usb_enable_endpoint (unsigned ep, unsigned options); +void usb_configure_endpoint (unsigned EPNum, unsigned direction); + +#if defined(USB_DYNAMIC_EP_CONFIG) + void usb_init_ep(unsigned char const* pConfig); +#else + #define usb_init_ep(a) +#endif + +/* Section: CALLBACKS */ + +/* + Function: + void usbcb_suspend(void) + + Summary: + Call back that is invoked when a USB suspend is detected. + Description: + Call back that is invoked when a USB suspend is detected. + + \Example power saving code. Insert appropriate code here for the + desired application behavior. If the microcontroller will be put to + sleep, a process similar to that shown below may be used: + + \Example Psuedo Code: + + ConfigureIOPinsForLowPower(); + SaveStateOfAllInterruptEnableBits(); + DisableAllInterruptEnableBits(); + + //should enable at least USBActivityIF as a wake source + EnableOnlyTheInterruptsWhichWillBeUsedToWakeTheMicro(); + + Sleep(); + + //Preferrably, this should be done in the + // usbcb_wake_from_suspend() function instead. + RestoreStateOfAllPreviouslySavedInterruptEnableBits(); + + //Preferrably, this should be done in the + // usbcb_wake_from_suspend() function instead. + RestoreIOPinsToNormal(); + + + IMPORTANT NOTE: Do not clear the USBActivityIF (ACTVIF) bit here. This + bit is cleared inside the usb_device.c file. Clearing USBActivityIF + here will cause things to not work as intended. + Conditions: + None + + Paramters: None + Side Effects: + None + + Remark: None + */ +void usbcb_suspend (void); + +/* + Function: + void usbcb_wake_from_suspend (void) + + Summary: + This call back is invoked when a wakeup from USB suspend + is detected. + + Description: + The host may put USB peripheral devices in low power + suspend mode (by "sending" 3+ms of idle). Once in suspend + mode, the host may wake the device back up by sending non- + idle state signalling. + + This call back is invoked when a wakeup from USB suspend + is detected. + + If clock switching or other power savings measures were taken when + executing the usbcb_suspend() function, now would be a good time to + switch back to normal full power run mode conditions. The host allows + a few milliseconds of wakeup time, after which the device must be + fully back to normal, and capable of receiving and processing USB + packets. In order to do this, the USB module must receive proper + clocking (IE: 48MHz clock must be available to SIE for full speed USB + operation). + + PreCondition: None + + Parameters: None + + Return Values: None + + Remarks: None + */ +void usbcb_wake_from_suspend (void); + +/* + Function: + void usbcb_sof_handler (void) + + Summary: + This callback is called when a SOF packet is received by the host. + (optional) + + Description: + This callback is called when a SOF packet is received by the host. + (optional) + + The USB host sends out a SOF packet to full-speed + devices every 1 ms. This interrupt may be useful + for isochronous pipes. End designers should + implement callback routine as necessary. + + PreCondition: + None + + Parameters: + None + + Return Values: + None + + Remarks: + None + */ +void usbcb_sof_handler (void); + +/* + Function: + void usbcb_error_handler (void) + + Summary: + This callback is called whenever a USB error occurs. (optional) + + Description: + This callback is called whenever a USB error occurs. (optional) + + The purpose of this callback is mainly for + debugging during development. Check UEIR to see + which error causes the interrupt. + + PreCondition: + None + + Parameters: + None + + Return Values: + None + + Remarks: + No need to clear UEIR to 0 here. + Callback caller is already doing that. + + Typically, user firmware does not need to do anything special + if a USB error occurs. For example, if the host sends an OUT + packet to your device, but the packet gets corrupted (ex: + because of a bad connection, or the user unplugs the + USB cable during the transmission) this will typically set + one or more USB error interrupt flags. Nothing specific + needs to be done however, since the SIE will automatically + send a "NAK" packet to the host. In response to this, the + host will normally retry to send the packet again, and no + data loss occurs. The system will typically recover + automatically, without the need for application firmware + intervention. + + Nevertheless, this callback function is provided, such as + for debugging purposes. + */ +void usbcb_error_handler (void); + +/* + Function: + void usbcb_check_other_req (void) + + Summary: + This function is called whenever a request comes over endpoint 0 (the + control endpoint) that the stack does not know how to handle. + Description: + When SETUP packets arrive from the host, some firmware must process the + request and respond appropriately to fulfill the request. Some of the + SETUP packets will be for standard USB "chapter 9" (as in, fulfilling + chapter 9 of the official USB specifications) requests, while others + may be specific to the USB device class that is being implemented. For + \example, a HID class device needs to be able to respond to "GET + REPORT" type of requests. This is not a standard USB chapter 9 request, + and therefore not handled by usb_device.c. Instead this request should + be handled by class specific firmware, such as that contained in + usb_function_hid.c. + + Typical Usage: + + void usbcb_check_other_req (void) + { + //Since the stack didn't handle the request I need to check + // my class drivers to see if it is for them + USBCheckMSDRequest(); + } + + Conditions: + None + Remarks: + None + */ +void usbcb_check_other_req (void); + +/* + Function: + void usbcb_std_set_dsc_handler (void) + + Summary: + This callback is called when a SET_DESCRIPTOR request is received (optional) + + Description: + The usbcb_std_set_dsc_handler() callback function is + called when a SETUP, bRequest: SET_DESCRIPTOR request + arrives. Typically SET_DESCRIPTOR requests are + not used in most applications, and it is + optional to support this type of request. + + PreCondition: + None + + Parameters: + None + + Return Values: + None + + Remark: None + */ +void usbcb_std_set_dsc_handler (void); + +/* + Function: + void usbcb_init_ep (void) + + Summary: + This function is called whenever the device receives a + SET_CONFIGURATION request. + Description: + This function is called when the device becomes initialized, which + occurs after the host sends a SET_CONFIGURATION (wValue not = 0) + request. This callback function should initialize the endpoints for the + device's usage according to the current configuration. + + Typical Usage: + + void usbcb_init_ep (void) + { + usb_enable_endpoint(MSD_DATA_IN_EP,USB_IN_ENABLED|USB_OUT_ENABLED|USB_HANDSHAKE_ENABLED|USB_DISALLOW_SETUP); + USBMSDInit(); + } + + Conditions: + None + Remarks: + None + */ +void usbcb_init_ep (void); + +/* + Function: + void usbcb_send_resume (void) + + Summary: + This function should be called to initiate a remote wakeup. (optional) + Description: + The USB specifications allow some types of USB peripheral devices to + wake up a host PC (such as if it is in a low power suspend to RAM + state). This can be a very useful feature in some USB applications, + such as an Infrared remote control receiver. If a user presses the + "power" button on a remote control, it is nice that the IR receiver can + detect this signalling, and then send a USB "command" to the PC to wake + up. + + The usbcb_send_resume() "callback" function is used to send this special + USB signalling which wakes up the PC. This function may be called by + application firmware to wake up the PC. This function should only be + called when: + + 1. The USB driver used on the host PC supports the remote wakeup + capability. + 2. The USB configuration descriptor indicates the device is remote + wakeup capable in the bmAttributes field. (see usb_descriptors.c and + _RWU) + 3. The USB host PC is currently sleeping, and has previously sent + your device a SET FEATURE setup packet which "armed" the remote wakeup + capability. (see usb_get_remote_wakeup_status()) + + This callback should send a RESUME signal that has the period of + 1-15ms. + + Typical Usage: + + if ((usb_device_state == CONFIGURED_STATE) + && usb_is_device_suspended() + && (usb_get_remote_wakeup_status() == TRUE)) + { + if (ButtonPressed) + { + // Wake up the USB module from suspend + usb_wake_from_suspend(); + + // Issue a remote wakeup command on the bus + usbcb_send_resume(); + } + } + + Conditions: + None + Remarks: + A user can switch to primary first by calling usbcb_wake_from_suspend() if + required/desired. + + The modifiable section in this routine should be changed to meet the + application needs. Current implementation temporary blocks other + functions from executing for a period of 1-13 ms depending on the core + frequency. + + According to USB 2.0 specification section 7.1.7.7, "The remote wakeup + device must hold the resume signaling for at lest 1 ms but for no more + than 15 ms." The idea here is to use a delay counter loop, using a + common value that would work over a wide range of core frequencies. + That value selected is 1800. See table below: + + Core Freq(MHz) MIP (for PIC18) RESUME Signal Period (ms) + --------------- ---------------- -------------------------- + 48 12 1.05 + 4 1 12.6 +
    + * These timing could be incorrect when using code optimization or + extended instruction mode, or when having other interrupts enabled. + Make sure to verify using the MPLAB SIM's Stopwatch and verify the + actual signal on an oscilloscope. + * These timing numbers should be recalculated when using PIC24 or + PIC32 as they have different clocking structures. + * A timer can be used in place of the blocking loop if desired. + +*/ +void usbcb_send_resume (void); + +/* + Function: + void usbcb_ep0_data_received(void) + + Summary: + This function is called whenever a EP0 data + packet is received. (optional) + + Description: + This function is called whenever a EP0 data + packet is received. This gives the user (and + thus the various class examples a way to get + data that is received via the control endpoint. + This function needs to be used in conjunction + with the usbcb_check_other_req() function since + the usbcb_check_other_req() function is the apps + method for getting the initial control transfer + before the data arrives. + + PreCondition: + ENABLE_EP0_DATA_RECEIVED_CALLBACK must be + defined already (in target.cfg) + + Parameters: + None + + Return Values: + None + + Remarks: + None +*/ +void usbcb_ep0_data_received (void); + + + + +/* Section: MACROS */ + +#define DESC_CONFIG_BYTE(a) (a) +#define DESC_CONFIG_WORD(a) (a&0xFF),((a>>8)&0xFF) +#define DESC_CONFIG_DWORD(a) (a&0xFF),((a>>8)&0xFF),((a>>16)&0xFF),((a>>24)&0xFF) + +/* + Function: + int usb_handle_busy(USB_HANDLE handle) + + Summary: + Checks to see if the input handle is busy + + Description: + Checks to see if the input handle is busy + + Typical Usage + + //make sure that the last transfer isn't busy by checking the handle + if (! usb_handle_busy(handle)) + { + //Send the data contained in the INPacket[] array out on + // endpoint USBGEN_EP_NUM + handle = USBGenWrite (USBGEN_EP_NUM, (unsigned char*) &INPacket[0], sizeof(INPacket)); + } + + + Conditions: + None + Input: + USB_HANDLE handle - handle of the transfer that you want to check the + status of + Return Values: + TRUE - The specified handle is busy + FALSE - The specified handle is free and available for a transfer + Remarks: + None + */ +#define usb_handle_busy(handle) (handle != 0 && handle->STAT.UOWN) + +/* + Function: + unsigned short usb_handle_get_length(USB_HANDLE handle) + + Summary: + Retrieves the length of the destination buffer of the input + handle + + Description: + Retrieves the length of the destination buffer of the input + handle + + PreCondition: + None + + Parameters: + USB_HANDLE handle - the handle to the transfer you want the + address for. + + Return Values: + unsigned short - length of the current buffer that the input handle + points to. If the transfer is complete then this is the + length of the data transmitted or the length of data + actually received. + + Remarks: + None + + */ +#define usb_handle_get_length(handle) (handle->CNT) + +/* + Function: + unsigned short usb_handle_get_addr(USB_HANDLE) + + Summary: + Retrieves the address of the destination buffer of the input + handle + + Description: + Retrieves the address of the destination buffer of the input + handle + + PreCondition: + None + + Parameters: + USB_HANDLE handle - the handle to the transfer you want the + address for. + + Return Values: + unsigned short - address of the current buffer that the input handle + points to. + + Remarks: + None + + */ +#define usb_handle_get_addr(handle) (handle->ADR) + +/* + Function: + void usb_ep0_set_source_ram(unsigned char* src) + + Summary: + Sets the address of the data to send over the + control endpoint + + PreCondition: + None + + Paramters: + src - address of the data to send + + Return Values: + None + + Remarks: + None + + */ +#define usb_ep0_set_source_ram(src) usb_in_pipe[0].pSrc.bRam = src + +/* + Function: + void usb_ep0_set_source_rom(unsigned char* src) + + Summary: + Sets the address of the data to send over the + control endpoint + + PreCondition: + None + + Parameters: + src - address of the data to send + + Return Values: + None + + Remarks: + None + + */ +#define usb_ep0_set_source_rom(src) usb_in_pipe[0].pSrc.bRom = src + +/* + Function: + void usb_ep0_transmit(unsigned char options) + + Summary: + Sets the address of the data to send over the + control endpoint + + PreCondition: + None + + Paramters: + options - the various options that you want + when sending the control data. Options are: + USB_INPIPES_ROM + USB_INPIPES_RAM + USB_INPIPES_BUSY + USB_INPIPES_INCLUDE_ZERO + USB_INPIPES_NO_DATA + USB_INPIPES_NO_OPTIONS + + Return Values: + None + + Remarks: + None + + */ +#define usb_ep0_transmit(options) usb_in_pipe[0].info.Val = options | USB_INPIPES_BUSY + +/* + Function: + void usb_ep0_set_size(unsigned short size) + + Summary: + Sets the size of the data to send over the + control endpoint + + PreCondition: + None + + Parameters: + size - the size of the data needing to be transmitted + + Return Values: + None + + Remarks: + None + + */ +#define usb_ep0_set_size(size) usb_in_pipe[0].wCount = size + +/* + Function: + void usb_ep0_send_ram_ptr(unsigned char* src, unsigned short size, unsigned char Options) + + Summary: + Sets the source, size, and options of the data + you wish to send from a RAM source + + PreCondition: + None + + Parameters: + src - address of the data to send + size - the size of the data needing to be transmitted + options - the various options that you want + when sending the control data. Options are: + USB_INPIPES_ROM + USB_INPIPES_RAM + USB_INPIPES_BUSY + USB_INPIPES_INCLUDE_ZERO + USB_INPIPES_NO_DATA + USB_INPIPES_NO_OPTIONS + + Return Values: + None + + Remarks: + None + + */ +#define usb_ep0_send_ram_ptr(src,size,options) {usb_ep0_set_source_ram(src);usb_ep0_set_size(size);usb_ep0_transmit(options | USB_EP0_RAM);} + +/* + Function: + void usb_ep0_send_rom_ptr(unsigned char* src, unsigned short size, unsigned char Options) + + Summary: + Sets the source, size, and options of the data + you wish to send from a ROM source + + PreCondition: + None + + Parameters: + src - address of the data to send + size - the size of the data needing to be transmitted + options - the various options that you want + when sending the control data. Options are: + USB_INPIPES_ROM + USB_INPIPES_RAM + USB_INPIPES_BUSY + USB_INPIPES_INCLUDE_ZERO + USB_INPIPES_NO_DATA + USB_INPIPES_NO_OPTIONS + + Return Values: + None + + Remarks: + None + + */ +#define usb_ep0_send_rom_ptr(src,size,options) {usb_ep0_set_source_rom(src);usb_ep0_set_size(size);usb_ep0_transmit(options | USB_EP0_ROM);} + +/* + Function: + USB_HANDLE usb_tx_one_packet(unsigned char ep, unsigned char* data, unsigned short len) + + Summary: + Sends the specified data out the specified endpoint + + PreCondition: + None + + Parameters: + ep - the endpoint you want to send the data out of + data - the data that you wish to send + len - the length of the data that you wish to send + + Return Values: + USB_HANDLE - a handle for the transfer. This information + should be kept to track the status of the transfer + + Remarks: + None + + */ +#define usb_tx_one_packet(ep, data, len) usb_transfer_one_packet(ep, IN_TO_HOST, data, len) + +/* + Function: + void usb_rx_one_packet(unsigned char ep, unsigned char* data, unsigned short len) + + Summary: + Receives the specified data out the specified endpoint + + PreCondition: + None + + Parameters: + ep - the endpoint you want to receive the data into + data - where the data will go when it arrives + len - the length of the data that you wish to receive + + Return Values: + None + + Remarks: + None + + */ +#define usb_rx_one_packet(ep, data, len) usb_transfer_one_packet(ep, OUT_FROM_HOST, data, len) + +/* + Function: + void usb_stall_endpoint(unsigned ep, unsigned dir) + + Summary: + STALLs the specified endpoint + + PreCondition: + None + + Parameters: + unsigned char ep - the endpoint the data will be transmitted on + unsigned char dir - the direction of the transfer + + Return Values: + None + + Remarks: + None + */ +void usb_stall_endpoint(unsigned ep, unsigned dir); + +#if (USB_PING_PONG_MODE == USB_PING_PONG__NO_PING_PONG) + #define USB_NEXT_EP0_OUT_PING_PONG 0x0000 // Used in USB Device Mode only + #define USB_NEXT_EP0_IN_PING_PONG 0x0000 // Used in USB Device Mode only + #define USB_NEXT_PING_PONG 0x0000 // Used in USB Device Mode only + #define EP0_OUT_EVEN 0 // Used in USB Device Mode only + #define EP0_OUT_ODD 0 // Used in USB Device Mode only + #define EP0_IN_EVEN 1 // Used in USB Device Mode only + #define EP0_IN_ODD 1 // Used in USB Device Mode only + #define EP1_OUT_EVEN 2 // Used in USB Device Mode only + #define EP1_OUT_ODD 2 // Used in USB Device Mode only + #define EP1_IN_EVEN 3 // Used in USB Device Mode only + #define EP1_IN_ODD 3 // Used in USB Device Mode only + #define EP2_OUT_EVEN 4 // Used in USB Device Mode only + #define EP2_OUT_ODD 4 // Used in USB Device Mode only + #define EP2_IN_EVEN 5 // Used in USB Device Mode only + #define EP2_IN_ODD 5 // Used in USB Device Mode only + #define EP3_OUT_EVEN 6 // Used in USB Device Mode only + #define EP3_OUT_ODD 6 // Used in USB Device Mode only + #define EP3_IN_EVEN 7 // Used in USB Device Mode only + #define EP3_IN_ODD 7 // Used in USB Device Mode only + #define EP4_OUT_EVEN 8 // Used in USB Device Mode only + #define EP4_OUT_ODD 8 // Used in USB Device Mode only + #define EP4_IN_EVEN 9 // Used in USB Device Mode only + #define EP4_IN_ODD 9 // Used in USB Device Mode only + #define EP5_OUT_EVEN 10 // Used in USB Device Mode only + #define EP5_OUT_ODD 10 // Used in USB Device Mode only + #define EP5_IN_EVEN 11 // Used in USB Device Mode only + #define EP5_IN_ODD 11 // Used in USB Device Mode only + #define EP6_OUT_EVEN 12 // Used in USB Device Mode only + #define EP6_OUT_ODD 12 // Used in USB Device Mode only + #define EP6_IN_EVEN 13 // Used in USB Device Mode only + #define EP6_IN_ODD 13 // Used in USB Device Mode only + #define EP7_OUT_EVEN 14 // Used in USB Device Mode only + #define EP7_OUT_ODD 14 // Used in USB Device Mode only + #define EP7_IN_EVEN 15 // Used in USB Device Mode only + #define EP7_IN_ODD 15 // Used in USB Device Mode only + #define EP8_OUT_EVEN 16 // Used in USB Device Mode only + #define EP8_OUT_ODD 16 // Used in USB Device Mode only + #define EP8_IN_EVEN 17 // Used in USB Device Mode only + #define EP8_IN_ODD 17 // Used in USB Device Mode only + #define EP9_OUT_EVEN 18 // Used in USB Device Mode only + #define EP9_OUT_ODD 18 // Used in USB Device Mode only + #define EP9_IN_EVEN 19 // Used in USB Device Mode only + #define EP9_IN_ODD 19 // Used in USB Device Mode only + #define EP10_OUT_EVEN 20 // Used in USB Device Mode only + #define EP10_OUT_ODD 20 // Used in USB Device Mode only + #define EP10_IN_EVEN 21 // Used in USB Device Mode only + #define EP10_IN_ODD 21 // Used in USB Device Mode only + #define EP11_OUT_EVEN 22 // Used in USB Device Mode only + #define EP11_OUT_ODD 22 // Used in USB Device Mode only + #define EP11_IN_EVEN 23 // Used in USB Device Mode only + #define EP11_IN_ODD 23 // Used in USB Device Mode only + #define EP12_OUT_EVEN 24 // Used in USB Device Mode only + #define EP12_OUT_ODD 24 // Used in USB Device Mode only + #define EP12_IN_EVEN 25 // Used in USB Device Mode only + #define EP12_IN_ODD 25 // Used in USB Device Mode only + #define EP13_OUT_EVEN 26 // Used in USB Device Mode only + #define EP13_OUT_ODD 26 // Used in USB Device Mode only + #define EP13_IN_EVEN 27 // Used in USB Device Mode only + #define EP13_IN_ODD 27 // Used in USB Device Mode only + #define EP14_OUT_EVEN 28 // Used in USB Device Mode only + #define EP14_OUT_ODD 28 // Used in USB Device Mode only + #define EP14_IN_EVEN 29 // Used in USB Device Mode only + #define EP14_IN_ODD 29 // Used in USB Device Mode only + #define EP15_OUT_EVEN 30 // Used in USB Device Mode only + #define EP15_OUT_ODD 30 // Used in USB Device Mode only + #define EP15_IN_EVEN 31 // Used in USB Device Mode only + #define EP15_IN_ODD 31 // Used in USB Device Mode only + + #define EP(ep,dir,pp) (2*ep+dir) // Used in USB Device Mode only + + #define BD(ep,dir,pp) ((8 * ep) + (4 * dir)) // Used in USB Device Mode only + +#elif (USB_PING_PONG_MODE == USB_PING_PONG__EP0_OUT_ONLY) + #define USB_NEXT_EP0_OUT_PING_PONG 0x0004 + #define USB_NEXT_EP0_IN_PING_PONG 0x0000 + #define USB_NEXT_PING_PONG 0x0000 + #define EP0_OUT_EVEN 0 + #define EP0_OUT_ODD 1 + #define EP0_IN_EVEN 2 + #define EP0_IN_ODD 2 + #define EP1_OUT_EVEN 3 + #define EP1_OUT_ODD 3 + #define EP1_IN_EVEN 4 + #define EP1_IN_ODD 4 + #define EP2_OUT_EVEN 5 + #define EP2_OUT_ODD 5 + #define EP2_IN_EVEN 6 + #define EP2_IN_ODD 6 + #define EP3_OUT_EVEN 7 + #define EP3_OUT_ODD 7 + #define EP3_IN_EVEN 8 + #define EP3_IN_ODD 8 + #define EP4_OUT_EVEN 9 + #define EP4_OUT_ODD 9 + #define EP4_IN_EVEN 10 + #define EP4_IN_ODD 10 + #define EP5_OUT_EVEN 11 + #define EP5_OUT_ODD 11 + #define EP5_IN_EVEN 12 + #define EP5_IN_ODD 12 + #define EP6_OUT_EVEN 13 + #define EP6_OUT_ODD 13 + #define EP6_IN_EVEN 14 + #define EP6_IN_ODD 14 + #define EP7_OUT_EVEN 15 + #define EP7_OUT_ODD 15 + #define EP7_IN_EVEN 16 + #define EP7_IN_ODD 16 + #define EP8_OUT_EVEN 17 + #define EP8_OUT_ODD 17 + #define EP8_IN_EVEN 18 + #define EP8_IN_ODD 18 + #define EP9_OUT_EVEN 19 + #define EP9_OUT_ODD 19 + #define EP9_IN_EVEN 20 + #define EP9_IN_ODD 20 + #define EP10_OUT_EVEN 21 + #define EP10_OUT_ODD 21 + #define EP10_IN_EVEN 22 + #define EP10_IN_ODD 22 + #define EP11_OUT_EVEN 23 + #define EP11_OUT_ODD 23 + #define EP11_IN_EVEN 24 + #define EP11_IN_ODD 24 + #define EP12_OUT_EVEN 25 + #define EP12_OUT_ODD 25 + #define EP12_IN_EVEN 26 + #define EP12_IN_ODD 26 + #define EP13_OUT_EVEN 27 + #define EP13_OUT_ODD 27 + #define EP13_IN_EVEN 28 + #define EP13_IN_ODD 28 + #define EP14_OUT_EVEN 29 + #define EP14_OUT_ODD 29 + #define EP14_IN_EVEN 30 + #define EP14_IN_ODD 30 + #define EP15_OUT_EVEN 31 + #define EP15_OUT_ODD 31 + #define EP15_IN_EVEN 32 + #define EP15_IN_ODD 32 + + #define EP(ep,dir,pp) (2*ep+dir+(((ep==0)&&(dir==0))?pp:2)) + #define BD(ep,dir,pp) (4*(ep+dir+(((ep==0)&&(dir==0))?pp:2))) + +#elif (USB_PING_PONG_MODE == USB_PING_PONG__FULL_PING_PONG) + #define USB_NEXT_EP0_OUT_PING_PONG 0x0008 + #define USB_NEXT_EP0_IN_PING_PONG 0x0008 + #define USB_NEXT_PING_PONG 0x0008 + + #define EP0_OUT_EVEN 0 + #define EP0_OUT_ODD 1 + #define EP0_IN_EVEN 2 + #define EP0_IN_ODD 3 + #define EP1_OUT_EVEN 4 + #define EP1_OUT_ODD 5 + #define EP1_IN_EVEN 6 + #define EP1_IN_ODD 7 + #define EP2_OUT_EVEN 8 + #define EP2_OUT_ODD 9 + #define EP2_IN_EVEN 10 + #define EP2_IN_ODD 11 + #define EP3_OUT_EVEN 12 + #define EP3_OUT_ODD 13 + #define EP3_IN_EVEN 14 + #define EP3_IN_ODD 15 + #define EP4_OUT_EVEN 16 + #define EP4_OUT_ODD 17 + #define EP4_IN_EVEN 18 + #define EP4_IN_ODD 19 + #define EP5_OUT_EVEN 20 + #define EP5_OUT_ODD 21 + #define EP5_IN_EVEN 22 + #define EP5_IN_ODD 23 + #define EP6_OUT_EVEN 24 + #define EP6_OUT_ODD 25 + #define EP6_IN_EVEN 26 + #define EP6_IN_ODD 27 + #define EP7_OUT_EVEN 28 + #define EP7_OUT_ODD 29 + #define EP7_IN_EVEN 30 + #define EP7_IN_ODD 31 + #define EP8_OUT_EVEN 32 + #define EP8_OUT_ODD 33 + #define EP8_IN_EVEN 34 + #define EP8_IN_ODD 35 + #define EP9_OUT_EVEN 36 + #define EP9_OUT_ODD 37 + #define EP9_IN_EVEN 38 + #define EP9_IN_ODD 39 + #define EP10_OUT_EVEN 40 + #define EP10_OUT_ODD 41 + #define EP10_IN_EVEN 42 + #define EP10_IN_ODD 43 + #define EP11_OUT_EVEN 44 + #define EP11_OUT_ODD 45 + #define EP11_IN_EVEN 46 + #define EP11_IN_ODD 47 + #define EP12_OUT_EVEN 48 + #define EP12_OUT_ODD 49 + #define EP12_IN_EVEN 50 + #define EP12_IN_ODD 51 + #define EP13_OUT_EVEN 52 + #define EP13_OUT_ODD 53 + #define EP13_IN_EVEN 54 + #define EP13_IN_ODD 55 + #define EP14_OUT_EVEN 56 + #define EP14_OUT_ODD 57 + #define EP14_IN_EVEN 58 + #define EP14_IN_ODD 59 + #define EP15_OUT_EVEN 60 + #define EP15_OUT_ODD 61 + #define EP15_IN_EVEN 62 + #define EP15_IN_ODD 63 + + #define EP(ep,dir,pp) (4*ep+2*dir+pp) + + #define BD(ep,dir,pp) (8*(4*ep+2*dir+pp)) + +#elif (USB_PING_PONG_MODE == USB_PING_PONG__ALL_BUT_EP0) + #define USB_NEXT_EP0_OUT_PING_PONG 0x0000 + #define USB_NEXT_EP0_IN_PING_PONG 0x0000 + #define USB_NEXT_PING_PONG 0x0004 + #define EP0_OUT_EVEN 0 + #define EP0_OUT_ODD 0 + #define EP0_IN_EVEN 1 + #define EP0_IN_ODD 1 + #define EP1_OUT_EVEN 2 + #define EP1_OUT_ODD 3 + #define EP1_IN_EVEN 4 + #define EP1_IN_ODD 5 + #define EP2_OUT_EVEN 6 + #define EP2_OUT_ODD 7 + #define EP2_IN_EVEN 8 + #define EP2_IN_ODD 9 + #define EP3_OUT_EVEN 10 + #define EP3_OUT_ODD 11 + #define EP3_IN_EVEN 12 + #define EP3_IN_ODD 13 + #define EP4_OUT_EVEN 14 + #define EP4_OUT_ODD 15 + #define EP4_IN_EVEN 16 + #define EP4_IN_ODD 17 + #define EP5_OUT_EVEN 18 + #define EP5_OUT_ODD 19 + #define EP5_IN_EVEN 20 + #define EP5_IN_ODD 21 + #define EP6_OUT_EVEN 22 + #define EP6_OUT_ODD 23 + #define EP6_IN_EVEN 24 + #define EP6_IN_ODD 25 + #define EP7_OUT_EVEN 26 + #define EP7_OUT_ODD 27 + #define EP7_IN_EVEN 28 + #define EP7_IN_ODD 29 + #define EP8_OUT_EVEN 30 + #define EP8_OUT_ODD 31 + #define EP8_IN_EVEN 32 + #define EP8_IN_ODD 33 + #define EP9_OUT_EVEN 34 + #define EP9_OUT_ODD 35 + #define EP9_IN_EVEN 36 + #define EP9_IN_ODD 37 + #define EP10_OUT_EVEN 38 + #define EP10_OUT_ODD 39 + #define EP10_IN_EVEN 40 + #define EP10_IN_ODD 41 + #define EP11_OUT_EVEN 42 + #define EP11_OUT_ODD 43 + #define EP11_IN_EVEN 44 + #define EP11_IN_ODD 45 + #define EP12_OUT_EVEN 46 + #define EP12_OUT_ODD 47 + #define EP12_IN_EVEN 48 + #define EP12_IN_ODD 49 + #define EP13_OUT_EVEN 50 + #define EP13_OUT_ODD 51 + #define EP13_IN_EVEN 52 + #define EP13_IN_ODD 53 + #define EP14_OUT_EVEN 54 + #define EP14_OUT_ODD 55 + #define EP14_IN_EVEN 56 + #define EP14_IN_ODD 57 + #define EP15_OUT_EVEN 58 + #define EP15_OUT_ODD 59 + #define EP15_IN_EVEN 60 + #define EP15_IN_ODD 61 + + #define EP(ep,dir,pp) (4*ep+2*dir+((ep==0)?0:(pp-2))) + #define BD(ep,dir,pp) (4*(4*ep+2*dir+((ep==0)?0:(pp-2)))) + +#else + #error "No ping pong mode defined." +#endif + +extern int usb_remote_wakeup; + +#endif //USBD_H diff --git a/sys/pic32/usb_function_cdc.c b/sys/pic32/usb_function_cdc.c new file mode 100644 index 0000000..fa4a6e1 --- /dev/null +++ b/sys/pic32/usb_function_cdc.c @@ -0,0 +1,284 @@ +/* + * This file contains all of functions, macros, definitions, variables, + * datatypes, etc. that are required for usage with the CDC function + * driver. This file should be included in projects that use the CDC + * \function driver. + * + * The software supplied herewith by Microchip Technology Incorporated + * (the 'Company') for its PIC® Microcontroller is intended and + * supplied to you, the Company's customer, for use solely and + * exclusively on Microchip PIC Microcontroller products. The + * software is owned by the Company and/or its supplier, and is + * protected under applicable copyright laws. All rights are reserved. + * Any use in violation of the foregoing restrictions may subject the + * user to criminal sanctions under applicable laws, as well as to + * civil liability for the breach of the terms and conditions of this license. + * + * THIS SOFTWARE IS PROVIDED IN AN 'AS IS' CONDITION. NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED + * TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE COMPANY SHALL NOT, + * IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR + * CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER. + */ +#include +#include +#include + +unsigned cdc_trf_state; // States are defined cdc.h +unsigned cdc_tx_len; // total tx length + +LINE_CODING cdc_line_coding; // Buffer to store line coding information + +static USB_HANDLE data_out; +static USB_HANDLE data_in; + +static CONTROL_SIGNAL_BITMAP control_signal_bitmap; + +static volatile unsigned char cdc_data_rx [CDC_DATA_OUT_EP_SIZE]; +static volatile unsigned char cdc_data_tx [CDC_DATA_IN_EP_SIZE]; + +/* + * SEND_ENCAPSULATED_COMMAND and GET_ENCAPSULATED_RESPONSE are required + * requests according to the CDC specification. + * However, it is not really being used here, therefore a dummy buffer is + * used for conformance. + */ +#define DUMMY_LENGTH 0x08 + +static unsigned char dummy_encapsulated_cmd_response [DUMMY_LENGTH]; + +/* + * This routine checks the setup data packet to see if it + * knows how to handle it. + */ +void cdc_check_request() +{ + /* + * If request recipient is not an interface then return + */ + if (usb_setup_pkt.Recipient != RCPT_INTF) + return; + + /* + * If request type is not class-specific then return + */ + if (usb_setup_pkt.RequestType != CLASS) + return; + + /* + * Interface ID must match interface numbers associated with + * CDC class, else return + */ + if (usb_setup_pkt.bIntfID != CDC_COMM_INTF_ID && + usb_setup_pkt.bIntfID != CDC_DATA_INTF_ID) + return; + + switch (usb_setup_pkt.bRequest) + { + case SEND_ENCAPSULATED_COMMAND: + // send the packet + usb_in_pipe[0].pSrc.bRam = (unsigned char*) &dummy_encapsulated_cmd_response; + usb_in_pipe[0].wCount = DUMMY_LENGTH; + usb_in_pipe[0].info.bits.ctrl_trf_mem = USB_INPIPES_RAM; + usb_in_pipe[0].info.bits.busy = 1; + break; + + case GET_ENCAPSULATED_RESPONSE: + // Populate dummy_encapsulated_cmd_response first. + usb_in_pipe[0].pSrc.bRam = (unsigned char*) &dummy_encapsulated_cmd_response; + usb_in_pipe[0].info.bits.busy = 1; + break; + + case SET_LINE_CODING: + usb_out_pipe[0].wCount = usb_setup_pkt.wLength; + usb_out_pipe[0].pDst.bRam = (unsigned char*) &cdc_line_coding._byte[0]; + usb_out_pipe[0].pFunc = 0; + usb_out_pipe[0].info.bits.busy = 1; + break; + + case GET_LINE_CODING: + usb_ep0_send_ram_ptr ((unsigned char*) &cdc_line_coding, + LINE_CODING_LENGTH, USB_EP0_INCLUDE_ZERO); + break; + + case SET_CONTROL_LINE_STATE: + control_signal_bitmap._byte = (unsigned char)usb_setup_pkt.W_Value; + CONFIGURE_RTS(control_signal_bitmap.CARRIER_CONTROL); + CONFIGURE_DTR(control_signal_bitmap.DTE_PRESENT); + usb_in_pipe[0].info.bits.busy = 1; + break; + } +} + +/* + * This function initializes the CDC function driver. This function sets + * the default line coding (baud rate, bit parity, number of data bits, + * and format). This function also enables the endpoints and prepares for + * the first transfer from the host. + * + * This function should be called after the SET_CONFIGURATION command. + * This is most simply done by calling this function from the + * usbcb_init_ep() function. + * + * Usage: + * void usbcb_init_ep() + * { + * cdc_init_ep(); + * } + */ +void cdc_init_ep() +{ + // Abstract line coding information + cdc_line_coding.dwDTERate = 115200; // baud rate + cdc_line_coding.bCharFormat = 0; // 1 stop bit + cdc_line_coding.bParityType = 0; // None + cdc_line_coding.bDataBits = 8; // 5,6,7,8, or 16 + + cdc_trf_state = CDC_TX_READY; + cdc_tx_len = 0; + + /* + * Do not have to init Cnt of IN pipes here. + * Reason: Number of BYTEs to send to the host + * varies from one transaction to + * another. Cnt should equal the exact + * number of BYTEs to transmit for + * a given IN transaction. + * This number of BYTEs will only + * be known right before the data is + * sent. + */ + usb_enable_endpoint (CDC_COMM_EP, USB_IN_ENABLED | + USB_HANDSHAKE_ENABLED | USB_DISALLOW_SETUP); + usb_enable_endpoint (CDC_DATA_EP, USB_IN_ENABLED | USB_OUT_ENABLED | + USB_HANDSHAKE_ENABLED | USB_DISALLOW_SETUP); + + data_out = usb_rx_one_packet (CDC_DATA_EP, + (unsigned char*) &cdc_data_rx, sizeof(cdc_data_rx)); + data_in = 0; +} + +/* + * Get received data. + */ +int cdc_consume (void (*func) (int)) +{ + unsigned len; + + if (! data_out || usb_handle_busy (data_out)) + return 0; + + /* + * Pass received data to user function. + */ + len = usb_handle_get_length (data_out); + if (func != 0) { + unsigned n; + for (n=0; n 0); + * } + * Conditions: + * cdc_is_tx_ready() must return TRUE. This indicates that the last + * transfer is complete and is ready to receive a new block of data. + */ +int cdc_putc (int c) +{ + if (cdc_trf_state != CDC_TX_READY || cdc_tx_len >= sizeof(cdc_data_tx)) + return 0; + + cdc_data_tx [cdc_tx_len++] = c; + return sizeof(cdc_data_tx) - cdc_tx_len; +} + +/* + * cdc_tx_service handles device-to-host transaction(s). This function + * should be called once per Main Program loop after the device reaches + * the configured state. + * + * Usage: + * void main() + * { + * usb_device_init(); + * while (1) + * { + * usb_device_tasks(); + * if (USBGetDeviceState() < CONFIGURED_STATE || USBIsDeviceSuspended()) + * { + * // Either the device is not configured or we are suspended + * // so we don't want to do execute any application code + * continue; // go back to the top of the while loop + * } else { + * // Keep trying to send data to the PC as required + * cdc_tx_service(); + * + * // Run application code. + * UserApplication(); + * } + * } + * } + */ +void cdc_tx_service() +{ + // Check that USB connection is established. + if (usb_device_state < CONFIGURED_STATE || + (U1PWRC & PIC32_U1PWRC_USUSPEND)) + return; + + if (usb_handle_busy(data_in)) + return; + /* + * Completing stage is necessary while [ mCDCUSartTxIsBusy()==1 ]. + * By having this stage, user can always check cdc_trf_state, + * and not having to call mCDCUsartTxIsBusy() directly. + */ + if (cdc_trf_state == CDC_TX_COMPLETING) { + cdc_trf_state = CDC_TX_READY; + cdc_tx_len = 0; + } + + /* + * If CDC_TX_BUSY_ZLP state, send zero length packet + */ + if (cdc_trf_state == CDC_TX_BUSY_ZLP) + { + data_in = usb_tx_one_packet (CDC_DATA_EP, 0, 0); + cdc_trf_state = CDC_TX_COMPLETING; + return; + } + + /* + * Send a next packet. + */ + if (cdc_trf_state == CDC_TX_READY && cdc_tx_len > 0) { + /* + * Determine if a zero length packet state is necessary. + * See explanation in USB Specification 2.0: Section 5.8.3 + */ + if (cdc_tx_len == CDC_DATA_IN_EP_SIZE) + cdc_trf_state = CDC_TX_BUSY_ZLP; + else + cdc_trf_state = CDC_TX_COMPLETING; + + data_in = usb_tx_one_packet (CDC_DATA_EP, (unsigned char*)&cdc_data_tx, cdc_tx_len); + } +} diff --git a/sys/pic32/usb_function_cdc.h b/sys/pic32/usb_function_cdc.h new file mode 100644 index 0000000..37f632d --- /dev/null +++ b/sys/pic32/usb_function_cdc.h @@ -0,0 +1,409 @@ +/* + * USB CDC Function Driver File + * + * This file contains all of functions, macros, definitions, variables, + * datatypes, etc. that are required for usage with the CDC function + * driver. This file should be included in projects that use the CDC + * \function driver. This file should also be included into the + * usb_descriptors.c file and any other user file that requires access to the + * CDC interface. + * + * The software supplied herewith by Microchip Technology Incorporated + * (the 'Company') for its PIC® Microcontroller is intended and + * supplied to you, the Company's customer, for use solely and + * exclusively on Microchip PIC Microcontroller products. The + * software is owned by the Company and/or its supplier, and is + * protected under applicable copyright laws. All rights are reserved. + * Any use in violation of the foregoing restrictions may subject the + * user to criminal sanctions under applicable laws, as well as to + * civil liability for the breach of the terms and conditions of this license. + * + * THIS SOFTWARE IS PROVIDED IN AN 'AS IS' CONDITION. NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED + * TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE COMPANY SHALL NOT, + * IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR + * CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER. + */ +#ifndef CDC_H +#define CDC_H + +/* + * Default CDC configuration. + */ +#ifndef CDC_COMM_INTF_ID +# define CDC_COMM_INTF_ID 0x0 +#endif +#ifndef CDC_COMM_EP +# define CDC_COMM_EP 2 +#endif +#ifndef CDC_COMM_IN_EP_SIZE +# define CDC_COMM_IN_EP_SIZE 8 +#endif +#ifndef CDC_DATA_INTF_ID +# define CDC_DATA_INTF_ID 0x01 +#endif +#ifndef CDC_DATA_EP +# define CDC_DATA_EP 3 +#endif +#ifndef CDC_DATA_OUT_EP_SIZE +# define CDC_DATA_OUT_EP_SIZE 64 +#endif +#ifndef CDC_DATA_IN_EP_SIZE +# define CDC_DATA_IN_EP_SIZE 64 +#endif + +/* Class-Specific Requests */ +#define SEND_ENCAPSULATED_COMMAND 0x00 +#define GET_ENCAPSULATED_RESPONSE 0x01 +#define SET_COMM_FEATURE 0x02 +#define GET_COMM_FEATURE 0x03 +#define CLEAR_COMM_FEATURE 0x04 +#define SET_LINE_CODING 0x20 +#define GET_LINE_CODING 0x21 +#define SET_CONTROL_LINE_STATE 0x22 +#define SEND_BREAK 0x23 + +/* Notifications * + * Note: Notifications are polled over + * Communication Interface (Interrupt Endpoint) + */ +#define NETWORK_CONNECTION 0x00 +#define RESPONSE_AVAILABLE 0x01 +#define SERIAL_STATE 0x20 + + +/* Device Class Code */ +#define CDC_DEVICE 0x02 + +/* Communication Interface Class Code */ +#define COMM_INTF 0x02 + +/* Communication Interface Class SubClass Codes */ +#define ABSTRACT_CONTROL_MODEL 0x02 + +/* Communication Interface Class Control Protocol Codes */ +#define V25TER 0x01 // Common AT commands ("Hayes(TM)") + + +/* Data Interface Class Codes */ +#define DATA_INTF 0x0A + +/* Data Interface Class Protocol Codes */ +#define NO_PROTOCOL 0x00 // No class specific protocol required + +/* Communication Feature Selector Codes */ +#define ABSTRACT_STATE 0x01 +#define COUNTRY_SETTING 0x02 + +/* Functional Descriptors */ +/* Type Values for the bDscType Field */ +#define CS_INTERFACE 0x24 +#define CS_ENDPOINT 0x25 + +/* bDscSubType in Functional Descriptors */ +#define DSC_FN_HEADER 0x00 +#define DSC_FN_CALL_MGT 0x01 +#define DSC_FN_ACM 0x02 // ACM - Abstract Control Management +#define DSC_FN_DLM 0x03 // DLM - Direct Line Managment +#define DSC_FN_TELEPHONE_RINGER 0x04 +#define DSC_FN_RPT_CAPABILITIES 0x05 +#define DSC_FN_UNION 0x06 +#define DSC_FN_COUNTRY_SELECTION 0x07 +#define DSC_FN_TEL_OP_MODES 0x08 +#define DSC_FN_USB_TERMINAL 0x09 +/* more.... see Table 25 in USB CDC Specification 1.1 */ + +/* CDC Bulk IN transfer states */ +#define CDC_TX_READY 0 +#define CDC_TX_BUSY_ZLP 2 // ZLP: Zero Length Packet +#define CDC_TX_COMPLETING 3 + +#if defined(USB_CDC_SUPPORT_HARDWARE_FLOW_CONTROL) + #define CONFIGURE_RTS(a) UART_RTS = a; + #define CONFIGURE_DTR(a) UART_DTR = a; +#else + #define CONFIGURE_RTS(a) + #define CONFIGURE_DTR(a) +#endif + +#define USB_CDC_ACM_FN_DSC_VAL 0x02 + +/* + * Function: + * void cdc_set_baud_rate(unsigned int baudRate) + * + * Summary: + * This macro is used set the baud rate reported back to the host during + * a get line coding request. (optional) + * + * Description: + * This macro is used set the baud rate reported back to the host during + * a get line coding request. + * + * Typical Usage: + * + * cdc_set_baud_rate(19200); + * + * + * This function is optional for CDC devices that do not actually convert + * the USB traffic to a hardware UART. + * + * Parameters: + * unsigned int baudRate - The desired baudrate + */ +#define cdc_set_baud_rate(baudRate) { cdc_line_coding.dwDTERate = baudRate; } + +/* + * Function: + * void cdc_set_character_format (unsigned charFormat) + * + * Summary: + * This macro is used manually set the character format reported back to + * the host during a get line coding request. (optional) + * + * Description: + * This macro is used manually set the character format reported back to + * the host during a get line coding request. + * + * Typical Usage: + * + * cdc_set_character_format(NUM_STOP_BITS_1); + * + * + * This function is optional for CDC devices that do not actually convert + * the USB traffic to a hardware UART. + * + * Parameters: + * unsigned charFormat - number of stop bits. Available options are: + * * NUM_STOP_BITS_1 - 1 Stop bit + * * NUM_STOP_BITS_1_5 - 1.5 Stop bits + * * NUM_STOP_BITS_2 - 2 Stop bits + */ +#define cdc_set_character_format(charFormat) { cdc_line_coding.bCharFormat = charFormat; } +#define NUM_STOP_BITS_1 0 // 1 stop bit +#define NUM_STOP_BITS_1_5 1 // 1.5 stop bit +#define NUM_STOP_BITS_2 2 // 2 stop bit + +/* + * Function: + * void cdc_set_parity (unsigned parityType) + * + * Summary: + * This function is used manually set the parity format reported back to + * the host during a get line coding request. (optional) + * + * Description: + * This macro is used manually set the parity format reported back to + * the host during a get line coding request. + * + * Typical Usage: + * + * cdc_set_parity(PARITY_NONE); + * + * + * This function is optional for CDC devices that do not actually convert + * the USB traffic to a hardware UART. + * + * Parameters: + * unsigned parityType - Type of parity. The options are the following: + * * PARITY_NONE + * * PARITY_ODD + * * PARITY_EVEN + * * PARITY_MARK + * * PARITY_SPACE + */ +#define cdc_set_parity(parityType) { cdc_line_coding.bParityType = parityType; } +#define PARITY_NONE 0 // no parity +#define PARITY_ODD 1 // odd parity +#define PARITY_EVEN 2 // even parity +#define PARITY_MARK 3 // mark parity +#define PARITY_SPACE 4 // space parity + +/* + * Function: + * void cdc_set_data_size (unsigned dataBits) + * + * Summary: + * This function is used manually set the number of data bits reported back + * to the host during a get line coding request. (optional) + * + * Description: + * This function is used manually set the number of data bits reported back + * to the host during a get line coding request. + * + * Typical Usage: + * + * cdc_set_data_size(8); + * + * + * This function is optional for CDC devices that do not actually convert + * the USB traffic to a hardware UART. + * + * Parameters: + * unsigned dataBits - number of data bits. The options are 5, 6, 7, 8, or 16. + */ +#define cdc_set_data_size(dataBits) { cdc_line_coding.bDataBits = dataBits; } + +/* + * Function: + * void cdc_set_line_coding(unsigned int baud, unsigned format, unsigned parity, unsigned dataSize) + * + * Summary: + * This function is used to manually set the data reported back + * to the host during a get line coding request. (optional) + * + * Description: + * This function is used to manually set the data reported back + * to the host during a get line coding request. + * + * Typical Usage: + * + * cdc_set_line_coding(19200, NUM_STOP_BITS_1, PARITY_NONE, 8); + * + * + * This function is optional for CDC devices that do not actually convert + * the USB traffic to a hardware UART. + * + * Parameters: + * unsigned baud - The desired baudrate + * unsigned format - number of stop bits. Available options are: + * * NUM_STOP_BITS_1 - 1 Stop bit + * * NUM_STOP_BITS_1_5 - 1.5 Stop bits + * * NUM_STOP_BITS_2 - 2 Stop bits + * unsigned parity - Type of parity. The options are the following: + * * PARITY_NONE + * * PARITY_ODD + * * PARITY_EVEN + * * PARITY_MARK + * * PARITY_SPACE + * unsigned dataSize - number of data bits. The options are 5, 6, 7, 8, or 16. + */ +#define cdc_set_line_coding(baud, format, parity, dataSize) {\ + cdc_set_baud_rate(baud);\ + cdc_set_character_format(format);\ + cdc_set_parity(parity);\ + cdc_set_data_size(dataSize);\ + } + +/* + * Function: + * bool_t cdc_is_tx_ready(void) + * + * Summary: + * This macro is used to check if the CDC class is ready + * to send more data. + * + * Description: + * This macro is used to check if the CDC class is ready + * to send more data. + * + * Typical Usage: + * + * if (cdc_is_tx_ready()) + * { + * cdc_putrs ("Hello World"); + * } + * + */ +#define cdc_is_tx_ready() (cdc_trf_state == CDC_TX_READY) + +/* + * S T R U C T U R E S + */ + +/* Line Coding Structure */ +#define LINE_CODING_LENGTH 0x07 + +typedef union _LINE_CODING +{ + struct + { + unsigned char _byte[LINE_CODING_LENGTH]; + }; + struct + { + unsigned long dwDTERate; // Complex data structure + unsigned char bCharFormat; + unsigned char bParityType; + unsigned char bDataBits; + }; +} LINE_CODING; + +typedef union _CONTROL_SIGNAL_BITMAP +{ + unsigned char _byte; + struct + { + unsigned DTE_PRESENT:1; // [0] Not Present [1] Present + unsigned CARRIER_CONTROL:1; // [0] Deactivate [1] Activate + }; +} CONTROL_SIGNAL_BITMAP; + + +/* Functional Descriptor Structure - See CDC Specification 1.1 for details */ + +/* Header Functional Descriptor */ +typedef struct __attribute__((packed)) _USB_CDC_HEADER_FN_DSC +{ + unsigned char bFNLength; + unsigned char bDscType; + unsigned char bDscSubType; + unsigned short bcdCDC; +} USB_CDC_HEADER_FN_DSC; + +/* Abstract Control Management Functional Descriptor */ +typedef struct __attribute__((packed)) _USB_CDC_ACM_FN_DSC +{ + unsigned char bFNLength; + unsigned char bDscType; + unsigned char bDscSubType; + unsigned char bmCapabilities; +} USB_CDC_ACM_FN_DSC; + +/* Union Functional Descriptor */ +typedef struct __attribute__((packed)) _USB_CDC_UNION_FN_DSC +{ + unsigned char bFNLength; + unsigned char bDscType; + unsigned char bDscSubType; + unsigned char bMasterIntf; + unsigned char bSaveIntf0; +} USB_CDC_UNION_FN_DSC; + +/* Call Management Functional Descriptor */ +typedef struct __attribute__((packed)) _USB_CDC_CALL_MGT_FN_DSC +{ + unsigned char bFNLength; + unsigned char bDscType; + unsigned char bDscSubType; + unsigned char bmCapabilities; + unsigned char bDataInterface; +} USB_CDC_CALL_MGT_FN_DSC; + +typedef union __attribute__((packed)) _CDC_NOTICE +{ + LINE_CODING GetLineCoding; + LINE_CODING SetLineCoding; + unsigned char packet[CDC_COMM_IN_EP_SIZE]; +} CDC_NOTICE, *PCDC_NOTICE; + +/* + * E X T E R N S + */ +extern unsigned cdc_rx_len; +extern unsigned cdc_tx_len; +extern unsigned cdc_trf_state; + +extern LINE_CODING cdc_line_coding; + +/* + * Public Prototypes + */ +void cdc_check_request (void); +void cdc_init_ep (void); +void cdc_tx_service (void); +int cdc_putc (int c); +int cdc_consume (void (*func) (int)); + +#endif //CDC_H diff --git a/sys/pic32/usb_function_hid.c b/sys/pic32/usb_function_hid.c new file mode 100644 index 0000000..0b844f9 --- /dev/null +++ b/sys/pic32/usb_function_hid.c @@ -0,0 +1,221 @@ +/* + * USB HID Function Driver File + * + * This file contains all of functions, macros, definitions, variables, + * datatypes, etc. that are required for usage with the HID function + * driver. This file should be included in projects that use the HID + * function driver. + * + * The software supplied herewith by Microchip Technology Incorporated + * (the 'Company') for its PIC(R) Microcontroller is intended and + * supplied to you, the Company's customer, for use solely and + * exclusively on Microchip PIC Microcontroller products. The + * software is owned by the Company and/or its supplier, and is + * protected under applicable copyright laws. All rights are reserved. + * Any use in violation of the foregoing restrictions may subject the + * user to criminal sanctions under applicable laws, as well as to + * civil liability for the breach of the terms and conditions of this license. + * + * THIS SOFTWARE IS PROVIDED IN AN 'AS IS' CONDITION. NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED + * TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE COMPANY SHALL NOT, + * IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR + * CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER. + */ +#include +#include + +unsigned char hid_idle_rate; +unsigned char hid_active_protocol; // [0] Boot Protocol [1] Report Protocol + +/* + * Section C: non-EP0 Buffer Space + */ +volatile unsigned char hid_report_out[HID_INT_OUT_EP_SIZE]; +volatile unsigned char hid_report_in[HID_INT_IN_EP_SIZE]; +volatile unsigned char hid_report_feature [HID_FEATURE_REPORT_BYTES]; + +/* + * Check to see if the HID supports a specific Output or Feature report. + * + * Return: 1 if it's a supported Input report + * 2 if it's a supported Output report + * 3 if it's a supported Feature report + * 0 for all other cases + */ +static unsigned char report_supported (void) +{ + // Find out if an Output or Feature report has arrived on the control pipe. + usb_device_tasks(); + + switch (usb_setup_pkt.W_Value >> 8) { + case 0x01: // Input report + switch (usb_setup_pkt.W_Value & 0xff) { + case 0x00: return 1; // Report ID 0 + default: return 0; // Other report IDs not supported. + } + case 0x02: // Output report + switch (usb_setup_pkt.W_Value & 0xff) { + case 0x00: return 2; // Report ID 0 + default: return 0; // Other report IDs not supported. + } + case 0x03: // Feature report + switch (usb_setup_pkt.W_Value & 0xff) { + case 0x00: return 3; // Report ID 0 + default: return 0; // Other report IDs not supported. + } + default: + return 0; + } +} + +/* + * Check to see if an Output or Feature report has arrived + * on the control pipe. If yes, extract and use the data. + */ +static void report_handler (void) +{ + unsigned char count = 0; + + // Find out if an Output or Feature report has arrived on the control pipe. + // Get the report type from the Setup packet. + + switch (usb_setup_pkt.W_Value >> 8) { + case 0x02: // Output report + switch (usb_setup_pkt.W_Value & 0xff) { + case 0: // Report ID 0 + // This example application copies the Output report data + // to hid_report_in. + // (Assumes Input and Output reports are the same length.) + // A "real" application would do something more useful with the data. + // wCount holds the number of bytes read in the Data stage. + // This example assumes the report fits in one transaction. + + for (count=0; count <= HID_OUTPUT_REPORT_BYTES - 1; count++) { + hid_report_in[count] = hid_report_out[count]; + } + break; + } + break; + + case 0x03: // Feature report + // Get the report ID from the Setup packet. + switch (usb_setup_pkt.W_Value & 0xff) { + case 0: // Report ID 0 + // The Feature report data is in hid_report_feature. + // This example application just sends the data back in the next + // Get_Report request for a Feature report. + // wCount holds the number of bytes read in the Data stage. + // This example assumes the report fits in one transaction. + // The Feature report uses a single buffer so to send the same data back + // in the next IN Feature report, there is nothing to copy. + // The data is in hid_report_feature[HID_FEATURE_REPORT_BYTES] + break; + } + break; + } +} + +/* + * This routine handles HID specific request that happen on EP0. These + * include, but are not limited to, requests for the HID report + * descriptors. This function should be called from the + * USBCBCheckOtherReq() call back function whenever using an HID device. + * + * Typical Usage: + * void USBCBCheckOtherReq(void) + * { + * // Since the stack didn't handle the request I need + * // to check my class drivers to see if it is for them + * hid_check_request(); + * } + */ +void hid_check_request (void) +{ + if (usb_setup_pkt.Recipient != RCPT_INTF) + return; + if (usb_setup_pkt.bIntfID != HID_INTF_ID) + return; + + /* + * There are two standard requests that hid.c may support. + * 1. GET_DSC(DSC_HID,DSC_RPT,DSC_PHY); + * 2. SET_DSC(DSC_HID,DSC_RPT,DSC_PHY); + */ + if (usb_setup_pkt.bRequest == GET_DSC) { + switch (usb_setup_pkt.bDescriptorType) { + case DSC_HID: + if (usb_active_configuration == 1) { + usb_ep0_send_rom_ptr ((const unsigned char*) + &usb_config1_descriptor + 18, + sizeof(USB_HID_DSC)+3, + USB_EP0_INCLUDE_ZERO); + } + break; + case DSC_RPT: + if (usb_active_configuration == 1) { + usb_ep0_send_rom_ptr ((const unsigned char*) + &hid_rpt01[0], + HID_RPT01_SIZE, // See target.cfg + USB_EP0_INCLUDE_ZERO); + } + break; + case DSC_PHY: + usb_ep0_transmit (USB_EP0_NO_DATA); + break; + } + } + + if (usb_setup_pkt.RequestType != CLASS) + return; + + switch (usb_setup_pkt.bRequest) { + case GET_REPORT: + switch (report_supported()) { + case 1: // Input Report + usb_in_pipe[0].pSrc.bRam = (unsigned char*) &hid_report_in[0]; + usb_in_pipe[0].info.bits.ctrl_trf_mem = _RAM; // Set memory type + usb_in_pipe[0].wCount = HID_INPUT_REPORT_BYTES; // Set data count + usb_in_pipe[0].info.bits.busy = 1; + break; + case 3: // Feature Report + usb_in_pipe[0].pSrc.bRam = (unsigned char*) &hid_report_feature[0]; + usb_in_pipe[0].info.bits.ctrl_trf_mem = _RAM; // Set memory type + usb_in_pipe[0].wCount = HID_FEATURE_REPORT_BYTES; // Set data count + usb_in_pipe[0].info.bits.busy = 1; + break; + } + break; + case SET_REPORT: + switch (report_supported()) { + case 2: // Output Report + usb_out_pipe[0].wCount = usb_setup_pkt.wLength; + usb_out_pipe[0].pFunc = report_handler; + usb_out_pipe[0].pDst.bRam = (unsigned char*) &hid_report_out[0]; + usb_out_pipe[0].info.bits.busy = 1; + break; + case 3: // Feature Report + usb_out_pipe[0].wCount = usb_setup_pkt.wLength; + usb_out_pipe[0].pFunc = report_handler; + usb_out_pipe[0].pDst.bRam = (unsigned char*) &hid_report_feature[0]; + usb_out_pipe[0].info.bits.busy = 1; + break; + } + break; + case GET_IDLE: + usb_ep0_send_ram_ptr (&hid_idle_rate, 1, USB_EP0_INCLUDE_ZERO); + break; + case SET_IDLE: + usb_ep0_transmit (USB_EP0_NO_DATA); + hid_idle_rate = usb_setup_pkt.W_Value >> 8; + break; + case GET_PROTOCOL: + usb_ep0_send_ram_ptr (&hid_active_protocol, 1, USB_EP0_NO_OPTIONS); + break; + case SET_PROTOCOL: + usb_ep0_transmit (USB_EP0_NO_DATA); + hid_active_protocol = usb_setup_pkt.W_Value & 0xff; + break; + } +} diff --git a/sys/pic32/usb_function_hid.h b/sys/pic32/usb_function_hid.h new file mode 100644 index 0000000..a961059 --- /dev/null +++ b/sys/pic32/usb_function_hid.h @@ -0,0 +1,119 @@ +/* + * USB HID Function Driver File + * + * This file contains all of functions, macros, definitions, variables, + * datatypes, etc. that are required for usage with the HID function + * driver. This file should be included in projects that use the HID + * function driver. This file should also be included into the + * usb_descriptors.c file and any other user file that requires access to the + * HID interface. + * + * The software supplied herewith by Microchip Technology Incorporated + * (the 'Company') for its PIC(R) Microcontroller is intended and + * supplied to you, the Company's customer, for use solely and + * exclusively on Microchip PIC Microcontroller products. The + * software is owned by the Company and/or its supplier, and is + * protected under applicable copyright laws. All rights are reserved. + * Any use in violation of the foregoing restrictions may subject the + * user to criminal sanctions under applicable laws, as well as to + * civil liability for the breach of the terms and conditions of this license. + * + * THIS SOFTWARE IS PROVIDED IN AN 'AS IS' CONDITION. NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED + * TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE COMPANY SHALL NOT, + * IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR + * CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER. + */ +#ifndef HID_H +#define HID_H + +/* + * Default HID configuration. + */ +#ifndef HID_EP +# define HID_EP 1 +#endif +#ifndef HID_INTF_ID +# define HID_INTF_ID 0x00 +#endif +#ifndef HID_BD_OUT +# define HID_BD_OUT USB_EP_1_OUT +#endif +#ifndef HID_INT_OUT_EP_SIZE +# define HID_INT_OUT_EP_SIZE 3 +#endif +#ifndef HID_BD_IN +# define HID_BD_IN USB_EP_1_IN +#endif +#ifndef HID_INT_IN_EP_SIZE +# define HID_INT_IN_EP_SIZE 3 +#endif +#ifndef HID_NUM_OF_DSC +# define HID_NUM_OF_DSC 1 +#endif +#ifndef HID_RPT01_SIZE +# define HID_RPT01_SIZE 47 +#endif + +/* Class-Specific Requests */ +#define GET_REPORT 0x01 +#define GET_IDLE 0x02 +#define GET_PROTOCOL 0x03 +#define SET_REPORT 0x09 +#define SET_IDLE 0x0A +#define SET_PROTOCOL 0x0B + +/* Class Descriptor Types */ +#define DSC_HID 0x21 +#define DSC_RPT 0x22 +#define DSC_PHY 0x23 + +/* Protocol Selection */ +#define BOOT_PROTOCOL 0x00 +#define RPT_PROTOCOL 0x01 + +/* HID Interface Class Code */ +#define HID_INTF 0x03 + +/* HID Interface Class SubClass Codes */ +#define BOOT_INTF_SUBCLASS 0x01 + +/* HID Interface Class Protocol Codes */ +#define HID_PROTOCOL_NONE 0x00 +#define HID_PROTOCOL_KEYBOARD 0x01 +#define HID_PROTOCOL_MOUSE 0x02 + +extern const unsigned char hid_rpt01 [HID_RPT01_SIZE]; +extern volatile unsigned char hid_report_out[HID_INT_OUT_EP_SIZE]; +extern volatile unsigned char hid_report_in[HID_INT_IN_EP_SIZE]; +extern volatile unsigned char hid_report_feature[HID_FEATURE_REPORT_BYTES]; + +// +// USB HID Descriptor header as detailed in section +// "6.2.1 HID Descriptor" of the HID class definition specification +// +typedef struct _USB_HID_DSC_HEADER +{ + unsigned char bDescriptorType; // offset 9 + unsigned short wDscLength; // offset 10 + +} USB_HID_DSC_HEADER; + +// +// USB HID Descriptor header as detailed in section +// "6.2.1 HID Descriptor" of the HID class definition specification +// +typedef struct _USB_HID_DSC +{ + unsigned char bLength; // offset 0 + unsigned char bDescriptorType; // offset 1 + unsigned short bcdHID; // offset 2 + unsigned char bCountryCode; // offset 4 + unsigned char bNumDsc; // offset 5 + +} USB_HID_DSC; + +void hid_check_request(void); + +#endif // HID_H diff --git a/sys/pic32/usb_hal_pic32.h b/sys/pic32/usb_hal_pic32.h new file mode 100644 index 0000000..8af3aba --- /dev/null +++ b/sys/pic32/usb_hal_pic32.h @@ -0,0 +1,149 @@ +/* + * USB Hardware Abstraction Layer (HAL) (Header File) + * + * This file abstracts the hardware interface. The USB stack firmware can be + * compiled to work on different USB microcontrollers, such as PIC18 and PIC24. + * The USB related special function registers and bit names are generally very + * similar between the device families, but small differences in naming exist. + * + * In order to make the same set of firmware work accross the device families, + * when modifying SFR contents, a slightly abstracted name is used, which is + * then "mapped" to the appropriate real name in the usb_hal_picxx.h header. + * + * Make sure to include the correct version of the usb_hal_picxx.h file for + * the microcontroller family which will be used. + * + * The software supplied herewith by Microchip Technology Incorporated + * (the 'Company') for its PICmicro® Microcontroller is intended and + * supplied to you, the Company's customer, for use solely and + * exclusively on Microchip PICmicro Microcontroller products. The + * software is owned by the Company and/or its supplier, and is + * protected under applicable copyright laws. All rights are reserved. + * Any use in violation of the foregoing restrictions may subject the + * user to criminal sanctions under applicable laws, as well as to + * civil liability for the breach of the terms and conditions of this + * license. + * + * THIS SOFTWARE IS PROVIDED IN AN 'AS IS' CONDITION. NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED + * TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE COMPANY SHALL NOT, + * IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR + * CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER. + */ +#ifndef USB_HAL_PIC32_H +#define USB_HAL_PIC32_H + +/* Buffer Descriptor Status Register Initialization Parameters */ + +//The _BSTALL definition is changed from 0x04 to 0x00 to +// fix a difference in the PIC18 and PIC24 definitions of this +// bit. This should be changed back once the definitions are +// synced. +#define _BSTALL 0x04 //Buffer Stall enable +#define _DTSEN 0x08 //Data Toggle Synch enable +#define _DAT0 0x00 //DATA0 packet expected next +#define _DAT1 0x40 //DATA1 packet expected next +#define _DTSMASK 0x40 //DTS Mask +#define _USIE 0x80 //SIE owns buffer +#define _UCPU 0x00 //CPU owns buffer + +#define _STAT_MASK 0xFC + +// Buffer Descriptor Status Register layout. +typedef union __attribute__ ((packed)) _BD_STAT +{ + struct __attribute__ ((packed)){ + unsigned :2; + unsigned BSTALL :1; //Buffer Stall Enable + unsigned DTSEN :1; //Data Toggle Synch Enable + unsigned :2; //Reserved - write as 00 + unsigned DTS :1; //Data Toggle Synch Value + unsigned UOWN :1; //USB Ownership + }; + struct __attribute__ ((packed)){ + unsigned :2; + unsigned PID0 :1; + unsigned PID1 :1; + unsigned PID2 :1; + unsigned PID3 :1; + + }; + struct __attribute__ ((packed)){ + unsigned :2; + unsigned PID :4; //Packet Identifier + }; + unsigned short Val; +} BD_STAT; + +// BDT Entry Layout +typedef union __attribute__ ((packed))__BDT +{ + struct __attribute__ ((packed)) + { + BD_STAT STAT; + unsigned CNT:10; + unsigned char *ADR; //Buffer Address + }; + struct __attribute__ ((packed)) + { + unsigned res :16; + unsigned count:10; + }; + unsigned int w[2]; + unsigned short v[4]; + unsigned long long Val; +} BDT_ENTRY; + +#define USTAT_EP0_PP_MASK ~0x04 +#define USTAT_EP_MASK 0xFC +#define USTAT_EP0_OUT 0x00 +#define USTAT_EP0_OUT_EVEN 0x00 +#define USTAT_EP0_OUT_ODD 0x04 + +#define USTAT_EP0_IN 0x08 +#define USTAT_EP0_IN_EVEN 0x08 +#define USTAT_EP0_IN_ODD 0x0C + +#define UEP_STALL 0x0002 + +//#define USB_PING_PONG__NO_PING_PONG 0x00 +//#define USB_PING_PONG__EP0_OUT_ONLY 0x01 +#define USB_PING_PONG__FULL_PING_PONG 0x02 +//#define USB_PING_PONG__ALL_BUT_EP0 0x03 + +/* + * Translate virtual address to physical one. + * Only for fixed mapping. + */ +static inline void *ConvertToPhysicalAddress (volatile void *addr) +{ + unsigned virt = (unsigned) addr; + unsigned phys; + + if (virt & 0x80000000) { + if (virt & 0x40000000) { + // kseg2 or kseg3 - no mapping + phys = virt; + } else { + // kseg0 или kseg1, cut bits A[31:29] + phys = virt & 0x1fffffff; + } + } else { + // kuseg + phys = virt + 0x40000000; + } + return (void*) phys; +} + +/* + * This macro is used to disable the USB module + */ +#define usb_module_disable() {\ + U1CON = 0;\ + U1IE = 0;\ + U1OTGIE = 0;\ + U1PWR |= PIC32_U1PWR_USBPWR;\ + usb_device_state = DETACHED_STATE;\ +} +#endif diff --git a/sys/pic32/usb_uart.c b/sys/pic32/usb_uart.c new file mode 100644 index 0000000..7a683a6 --- /dev/null +++ b/sys/pic32/usb_uart.c @@ -0,0 +1,479 @@ +/* + * Console driver via USB. + * + * Copyright (C) 2011 Serge Vakulenko, + * + * 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 the copyright notice and this + * permission notice and warranty disclaimer appear in supporting + * documentation, and that the name of the author not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * + * The author disclaim all warranties with regard to this + * software, including all implied warranties of merchantability + * and fitness. In no event shall the author 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. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +unsigned int usb_major = 0; + +const struct devspec usbdevs[] = { + { 0, "ttyUSB0" }, + { 0, 0 } +}; + +#define CONCAT(x,y) x ## y +#define BBAUD(x) CONCAT(B,x) + +#ifndef UARTUSB_BAUD +#define UARTUSB_BAUD 115200 +#endif + +static unsigned speed_bps [NSPEEDS] = { + 0, 50, 75, 150, 200, 300, 600, 1200, + 1800, 2400, 4800, 9600, 19200, 38400, 57600, 115200, + 230400, 460800, 500000, 576000, 921600, 1000000, 1152000, 1500000, + 2000000, 2500000, 3000000, 3500000, 4000000 +}; + + +struct tty usbttys [1]; + +void usbstart (struct tty *tp); +int usbopen (dev_t dev, int flag, int mode); +/* + * Initialize USB module SFRs and firmware variables to known state. + * Enable interrupts. + */ +void usbinit() +{ + int i; + for (i=0; it_oproc = usbstart; + + if ((tp->t_state & TS_ISOPEN) == 0) + { + tp->t_ispeed = BBAUD(UARTUSB_BAUD); + tp->t_ospeed = BBAUD(UARTUSB_BAUD); + ttychars(tp); + tp->t_state = TS_ISOPEN | TS_CARR_ON; + tp->t_flags = ECHO | XTABS | CRMOD | CRTBS | CRTERA | CTLECH | CRTKIL; + } + if ((tp->t_state & TS_XCLUDE) && u.u_uid != 0) + return (EBUSY); + + if(tp->t_ispeed == 0) + { + tp->t_ispeed = BBAUD(UARTUSB_BAUD); + tp->t_ospeed = BBAUD(UARTUSB_BAUD); + } + cdc_set_line_coding(speed_bps[tp->t_ospeed], NUM_STOP_BITS_1, PARITY_NONE, 8); + return ttyopen (dev, tp); +} + +int usbclose (dev, flag, mode) + dev_t dev; +{ + register struct tty *tp = &usbttys[0]; + + ttyclose (tp); + return 0; +} + +int usbread (dev, uio, flag) + dev_t dev; + struct uio *uio; + int flag; +{ + register struct tty *tp = &usbttys[0]; + + return ttread (tp, uio, flag); +} + +int usbwrite (dev, uio, flag) + dev_t dev; + struct uio *uio; + int flag; +{ + register struct tty *tp = &usbttys[0]; + + return ttwrite (tp, uio, flag); +} + +int usbioctl (dev, cmd, addr, flag) + dev_t dev; + register u_int cmd; + caddr_t addr; +{ + register struct tty *tp = &usbttys[0]; + register int error; + + error = ttioctl (tp, cmd, addr, flag); + if (error < 0) + error = ENOTTY; + return error; +} + +int usbselect (dev, rw) + register dev_t dev; + int rw; +{ + register struct tty *tp = &usbttys[0]; + + return ttyselect (tp, rw); +} + +void usbstart (tp) + register struct tty *tp; +{ + register int s; + + s = spltty(); + if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP)) { +out: /* Disable transmit_interrupt. */ + led_control (LED_TTY, 0); + splx (s); + return; + } + ttyowake(tp); + if (tp->t_outq.c_cc == 0) + goto out; + if (cdc_is_tx_ready()) { + while (tp->t_outq.c_cc != 0) { + int c = getc (&tp->t_outq); + if (cdc_putc (c) == 0) + break; + } + cdc_tx_service(); + tp->t_state |= TS_BUSY; + } + led_control (LED_TTY, 1); + splx (s); +} + +/* + * Put a symbol on console terminal. + */ +void usbputc(dev_t dev, char c) +{ + register int s; + + s = spltty(); + while (! cdc_is_tx_ready()) { + usb_device_tasks(); + cdc_tx_service(); + } + led_control (LED_TTY, 1); + cdc_putc (c); + cdc_tx_service(); + + while (! cdc_is_tx_ready()) { + cdc_tx_service(); + usb_device_tasks(); + } + + led_control (LED_TTY, 0); + splx (s); +} + +static int getc_data; + +/* + * Receive a character for getc. + */ +static void store_char (int c) +{ + getc_data = (unsigned char) c; +} + +/* + * Receive a symbol from console terminal. + */ +char usbgetc(dev_t dev) +{ + register int s; + + s = spltty(); + for (getc_data = -1; getc_data < 0; ) { + usb_device_tasks(); + cdc_consume (store_char); + cdc_tx_service(); + } + splx (s); + return getc_data; +} + +/* + * Receive a character from CDC. + */ +static void usb_rx (int c) +{ + register struct tty *tp = &usbttys[0]; + + if ((tp->t_state & TS_ISOPEN) == 0) + return; + ttyinput (c, tp); +} + +/* + * Check bus status and service USB interrupts. + */ +void usbintr (int chan) +{ + register struct tty *tp = &usbttys[0]; + + // Must call this function from interrupt or periodically. + usb_device_tasks(); + + // Check that USB connection is established. + if (usb_device_state < CONFIGURED_STATE || + (U1PWRC & PIC32_U1PWRC_USUSPEND)) + return; + + // Receive data from user. + cdc_consume (usb_rx); + + if (cdc_is_tx_ready()) { + // Transmitter empty. + led_control (LED_TTY, 0); + + if (tp->t_state & TS_BUSY) { + tp->t_state &= ~TS_BUSY; + ttstart (tp); + } + } + + // Transmit data to user. + cdc_tx_service(); +} + +/* + * USB Callback Functions + */ + +/* + * This function is called when the device becomes initialized. + * It should initialize the endpoints for the device's usage + * according to the current configuration. + */ +void usbcb_init_ep() +{ + cdc_init_ep(); +} + +/* + * Process device-specific SETUP requests. + */ +void usbcb_check_other_req() +{ + cdc_check_request(); +} + +#if 0 +/* + * Wake up a host PC. + */ +void usb_send_resume (void) +{ + /* Start RESUME signaling. */ + U1CON |= PIC32_U1CON_RESUME; + + /* Set RESUME line for 1-13 ms. */ + udelay (5000); + + U1CON &= ~PIC32_U1CON_RESUME; +} +#endif + +#ifndef CONSOLE_VID +# define CONSOLE_VID 0x04D8 // Vendor ID: Microchip +#endif +#ifndef CONSOLE_PID +# define CONSOLE_PID 0x000A // Product ID: CDC RS-232 Emulation Demo +#endif + +/* + * Device Descriptor + */ +const USB_DEVICE_DESCRIPTOR usb_device = { + sizeof(usb_device), // Size of this descriptor in bytes + USB_DESCRIPTOR_DEVICE, // DEVICE descriptor type + 0x0200, // USB Spec Release Number in BCD format + CDC_DEVICE, // Class Code + 0x00, // Subclass code + 0x00, // Protocol code + USB_EP0_BUFF_SIZE, // Max packet size for EP0, see usb_config.h + CONSOLE_VID, // Vendor ID + CONSOLE_PID, // Product ID + 0x0100, // Device release number in BCD format + 0x01, // Manufacturer string index + 0x02, // Product string index + 0x00, // Device serial number string index + 0x01 // Number of possible configurations +}; + +/* + * Configuration 1 Descriptor + */ +const unsigned char usb_config1_descriptor[] = +{ + /* Configuration Descriptor */ + 9, // sizeof(USB_CFG_DSC) + USB_DESCRIPTOR_CONFIGURATION, // CONFIGURATION descriptor type + 67, 0, // Total length of data for this cfg + 2, // Number of interfaces in this cfg + 1, // Index value of this configuration + 0, // Configuration string index + _DEFAULT | _SELF, // Attributes, see usb_device.h + 150, // Max power consumption (2X mA) + + /* Interface Descriptor */ + 9, // sizeof(USB_INTF_DSC) + USB_DESCRIPTOR_INTERFACE, // INTERFACE descriptor type + 0, // Interface Number + 0, // Alternate Setting Number + 1, // Number of endpoints in this intf + COMM_INTF, // Class code + ABSTRACT_CONTROL_MODEL, // Subclass code + V25TER, // Protocol code + 0, // Interface string index + + /* CDC Class-Specific Descriptors */ + sizeof(USB_CDC_HEADER_FN_DSC), + CS_INTERFACE, + DSC_FN_HEADER, + 0x10,0x01, + + sizeof(USB_CDC_ACM_FN_DSC), + CS_INTERFACE, + DSC_FN_ACM, + USB_CDC_ACM_FN_DSC_VAL, + + sizeof(USB_CDC_UNION_FN_DSC), + CS_INTERFACE, + DSC_FN_UNION, + CDC_COMM_INTF_ID, + CDC_DATA_INTF_ID, + + sizeof(USB_CDC_CALL_MGT_FN_DSC), + CS_INTERFACE, + DSC_FN_CALL_MGT, + 0x00, + CDC_DATA_INTF_ID, + + /* Endpoint Descriptor */ + 7, // sizeof(USB_EP_DSC) + USB_DESCRIPTOR_ENDPOINT, // Endpoint Descriptor + _EP02_IN, // EndpointAddress + _INTERRUPT, // Attributes + 0x08, 0x00, // size + 0x02, // Interval + + /* Interface Descriptor */ + 9, // sizeof(USB_INTF_DSC) + USB_DESCRIPTOR_INTERFACE, // INTERFACE descriptor type + 1, // Interface Number + 0, // Alternate Setting Number + 2, // Number of endpoints in this intf + DATA_INTF, // Class code + 0, // Subclass code + NO_PROTOCOL, // Protocol code + 0, // Interface string index + + /* Endpoint Descriptor */ + 7, // sizeof(USB_EP_DSC) + USB_DESCRIPTOR_ENDPOINT, // Endpoint Descriptor + _EP03_OUT, // EndpointAddress + _BULK, // Attributes + 0x40, 0x00, // size + 0x00, // Interval + + /* Endpoint Descriptor */ + 7, // sizeof(USB_EP_DSC) + USB_DESCRIPTOR_ENDPOINT, // Endpoint Descriptor + _EP03_IN, // EndpointAddress + _BULK, // Attributes + 0x40, 0x00, // size + 0x00, // Interval +}; + + +/* + * Language code string descriptor. + */ +static const USB_STRING_INIT(1) string0_descriptor = { + sizeof(string0_descriptor), + USB_DESCRIPTOR_STRING, + { 0x0409 } /* US English */ +}; + +/* + * Manufacturer string descriptor + */ +static const USB_STRING_INIT(25) string1_descriptor = { + sizeof(string1_descriptor), + USB_DESCRIPTOR_STRING, + { 'M','i','c','r','o','c','h','i','p',' ', + 'T','e','c','h','n','o','l','o','g','y', + ' ','I','n','c','.', }, +}; + +/* + * Product string descriptor + */ +static const USB_STRING_INIT(16) string2_descriptor = { + sizeof(string2_descriptor), + USB_DESCRIPTOR_STRING, + { 'R','e','t','r','o','B','S','D',' ','C', + 'o','n','s','o','l','e', }, +}; + +/* + * Array of configuration descriptors + */ +const unsigned char *const usb_config[] = { + (const unsigned char *const) &usb_config1_descriptor, +}; + +/* + * Array of string descriptors + */ +const unsigned char *const usb_string[USB_NUM_STRING_DESCRIPTORS] = { + (const unsigned char *const) &string0_descriptor, + (const unsigned char *const) &string1_descriptor, + (const unsigned char *const) &string2_descriptor, +}; diff --git a/target.mk b/target.mk new file mode 100644 index 0000000..0128b30 --- /dev/null +++ b/target.mk @@ -0,0 +1,48 @@ +MACHINE = mips +DESTDIR ?= $(TOPSRC) + +# chipKIT PIC32 compiler on Linux +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Download from https://github.com/jasonkajita/chipKIT-cxx/downloads +# and unzip to /usr/local. +# Need to copy pic32-tools/pic32mx/include/stdarg.h +# to pic32-tools/lib/gcc/pic32mx/4.5.1/include. +# MPLABX C32 compiler doesn't support some functionality +# we need, so use chipKIT compiler by default. +ifndef GCCPREFIX + GCCPREFIX = /usr/local/pic32-tools/bin/pic32- + LDFLAGS = -Wl,--oformat=elf32-tradlittlemips + INCLUDES = -I/usr/local/pic32-tools/lib/gcc/pic32mx/4.5.1/include +endif + +# Generic MIPS toolchain +# ~~~~~~~~~~~~~~~~~~~~~~ +# You can build it from sources, as described on page +# http://retrobsd.org/wiki/doku.php/doc/toolchain-mips +ifndef GCCPREFIX + GCCPREFIX = /usr/local/mips-gcc-4.7.2/bin/mips-elf- + LDFLAGS = + INCLUDES = +endif + +CC = $(GCCPREFIX)gcc -mips32r2 -EL -msoft-float -nostdinc -fshort-double -I$(TOPSRC)/include $(INCLUDES) +CXX = $(GCCPREFIX)g++ -mips32r2 -EL -msoft-float -nostdinc -fshort-double -I$(TOPSRC)/include $(INCLUDES) +LD = $(GCCPREFIX)ld +AR = $(GCCPREFIX)ar +RANLIB = $(GCCPREFIX)ranlib +SIZE = $(GCCPREFIX)size +OBJDUMP = $(GCCPREFIX)objdump -mmips:isa32r2 +AS = $(CC) -x assembler-with-cpp -c +YACC = byacc +LEX = flex +INSTALL = install -m 644 +INSTALLDIR = install -m 755 -d +TAGSFILE = tags +MANROFF = nroff -man -h -Tascii +ELF2AOUT = $(TOPSRC)/tools/elf2aout/elf2aout + +CFLAGS = -O + +LDFLAGS += -N -nostartfiles -fno-dwarf2-cfi-asm -T$(TOPSRC)/src/elf32-mips.ld \ + $(TOPSRC)/src/crt0.o -L$(TOPSRC)/src +LIBS = -lc diff --git a/tools/Makefile b/tools/Makefile new file mode 100644 index 0000000..ae7452a --- /dev/null +++ b/tools/Makefile @@ -0,0 +1,8 @@ +SUBDIR = elf2aout fsutil virtualmips mkrd configsys icache + +all install depend: ${SUBDIR} + -for i in ${SUBDIR}; do ${MAKE} -C $$i ${MFLAGS} DESTDIR=${DESTDIR} $@; done + +clean: + rm -f *~ + for i in ${SUBDIR}; do ${MAKE} -C $$i ${MFLAGS} clean; done diff --git a/tools/configsys/Makefile b/tools/configsys/Makefile new file mode 100644 index 0000000..d51e972 --- /dev/null +++ b/tools/configsys/Makefile @@ -0,0 +1,18 @@ + +BIN = config +SRCS = main.cpp config.cpp mapping.cpp device.cpp cluster.cpp util.cpp core.cpp gstore.cpp +OBJS = main.o config.o mapping.o device.o cluster.o util.o core.o gstore.o +CXXFLAGS = -Wall -O + +all: .depend $(BIN) + +$(BIN): $(OBJS) + g++ -o $@ $(OBJS) $(CXXFLAGS) + +clean: + -rm -f $(OBJS) $(BIN) + +.depend: $(SRCS) Makefile + g++ -MM $(CXXFLAGS) $(SRCS) > $@ + +-include .depend diff --git a/tools/configsys/Makefile.test b/tools/configsys/Makefile.test new file mode 100644 index 0000000..f314d99 --- /dev/null +++ b/tools/configsys/Makefile.test @@ -0,0 +1,40 @@ +BUILDPATH = ./../../sys/pic32 +H = ./../../sys/include +M = ./../../sys/pic32 +S = ./../../sys/kernel + +vpath %.c $(M):$(S) +vpath %.S $(M):$(S) + +KERNOBJ += _startup.o adc.o clock.o devsw.o exception.o gpio.o init_main.o init_sysent.o kern_clock.o kern_descrip.o kern_exec.o kern_exit.o kern_fork.o kern_glob.o kern_mman.o kern_proc.o kern_prot.o kern_prot2.o kern_resource.o kern_sig.o kern_sig2.o kern_subr.o kern_synch.o kern_sysctl.o kern_time.o machdep.o mem.o picga.o rd_sd.o rdisk.o signal.o spi_bus.o subr_log.o subr_prf.o subr_rmap.o swap.o sys_generic.o sys_inode.o sys_pipe.o sys_process.o syscalls.o sysctl.o tty.o tty_conf.o tty_subr.o tty_tty.o ufs_alloc.o ufs_bio.o ufs_bmap.o ufs_dsort.o ufs_fio.o ufs_inode.o ufs_mount.o ufs_namei.o ufs_subr.o ufs_syscalls.o ufs_syscalls2.o usb_console.o usb_device.o usb_function_cdc.o vers.o vfs_vnops.o vm_sched.o vm_swap.o vm_swp.o + +DEFS += -DADC_ENABLED=YES +DEFS += -DBUS_KHZ=80000 +DEFS += -DCONSOLE_USB +DEFS += -DCPU_KHZ=80000 +DEFS += -DGPIO_ENABLED=YES +DEFS += -DHALTREBOOT=YES +DEFS += -DHZ=500 +DEFS += -DKERNEL +DEFS += -DLED_DISK_PIN=4 +DEFS += -DLED_DISK_PORT=TRISE +DEFS += -DLED_KERNEL_PIN=5 +DEFS += -DLED_KERNEL_PORT=TRISE +DEFS += -DNPROC=10 +DEFS += -DPICGA_BUS=3 +DEFS += -DPICGA_CS_PIN=4 +DEFS += -DPICGA_CS_PORT=TRISD +DEFS += -DPICGA_ENABLED=YES +DEFS += -DSD0_CS_PIN=9 +DEFS += -DSD0_CS_PORT=TRISG +DEFS += -DSD0_PORT=2 +DEFS += -DSD1_CS_PIN=4 +DEFS += -DSD1_CS_PORT=TRISB +DEFS += -DSD1_PORT=2 +DEFS += -DUCB_METER +DEFS += -DUSB_AUTOBOOT=YES +DEFS += -DUSB_MAX_EP_NUMBER=3 +DEFS += -DUSB_NUM_STRING_DESCRIPTORS=3 + +BLREBOOT = -p +include ./../../sys/pic32/kernel-post.mk diff --git a/tools/configsys/cluster.cpp b/tools/configsys/cluster.cpp new file mode 100644 index 0000000..c7d0fda --- /dev/null +++ b/tools/configsys/cluster.cpp @@ -0,0 +1,55 @@ +#include +#include +#include +#include +#include +#include + +#include "util.h" +#include "cluster.h" + +using namespace std; + +void cluster::read(ifstream& f) +{ + char line[1024]; + string in; + + while (f.getline(line,1023)) { + stringstream temp(line); + temp >> in; + uc(in); + if (in.substr(0,1) == "#") + continue; + if (in == "END") { + return; + } + if (in == "DEFINE") { + temp >> in; + temp >> this->defines[in]; + } + if (in == "SET") { + temp >> in; + temp >> this->sets[in]; + } + if (in == "REQUIRE") { + temp >> in; + uc(in); + this->requires.push_back(in); + } + if (in == "FILE") { + temp >> in; + this->files.push_back(in); + } + if (in == "NOFILE") { + temp >> in; + this->nofiles.push_back(in); + } + if (in == "TARGET") { + temp >> in; + this->targets.push_back(in); + } + } + return; +} + diff --git a/tools/configsys/cluster.h b/tools/configsys/cluster.h new file mode 100644 index 0000000..7bae772 --- /dev/null +++ b/tools/configsys/cluster.h @@ -0,0 +1,24 @@ +#ifndef _CLUSTER_H +#define _CLUSTER_H + +#include +#include +#include +#include + +using namespace std; + +class cluster { + public: + map defines; + vector files; + vector nofiles; + map sets; + vector requires; + vector targets; + + public: + void read(ifstream&); +}; + +#endif diff --git a/tools/configsys/config.cpp b/tools/configsys/config.cpp new file mode 100644 index 0000000..c089475 --- /dev/null +++ b/tools/configsys/config.cpp @@ -0,0 +1,177 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "util.h" +#include "mapping.h" +#include "device.h" +#include "instance.h" +#include "config.h" + +using namespace std; + +extern map devices; +extern map cores; +extern map mappings; + +config::config(string path) +{ + this->configpath = path; +} + +string get_parsed_line(ifstream &f) +{ + stringstream line; + char in[1024]; + string token; + stringstream s; + + s.str(""); + + if(f.getline(in,1023)) + { + line.str(in); + while(line >> token) + { + if(token == "\\") + { + f.getline(in,1023); + line.str(in); + continue; + } + s << token << " "; + } + } + return s.str(); +} + +bool config::load(const char *filename) +{ + ifstream f; + string temp; + size_t pos; + string devid = ""; + + map ::iterator it; + + f.open(filename,ios::in); + if(!f.is_open()) + { + cout << "Unable to open " << filename << endl; + return false; + } + while(!f.eof()) + { + string command; + + temp = get_parsed_line(f); + stringstream in(temp); + + in >> command; + uc(command); + + if(command.substr(0,1)=="#") + { + continue; + } + + if(command == "MAPPING") + { + in >> this->pinmapping; + uc(this->pinmapping); + continue; + } + + if(command == "DEVICE") + { + string devname; + int devnum; + string devid; + in >> devid; + uc(devid); + pos = devid.find_first_not_of("ABCDEFGHIJKLMNOPQRSTUFWXYZ"); + if(pos == devid.npos) + { + devname = devid; + devnum = 0; + } else { + devname = devid.substr(0,pos); + devnum = atoi(devid.substr(pos,devid.size()).c_str()); + } + + this->instances[devid].unit = devnum; + this->instances[devid].device = devname; + + while(in >> temp) + { + pos = temp.find("="); + if(pos>0) + { + string l,r; + l = temp.substr(0,pos); + uc(l); + r = temp.substr(pos+1,temp.size()); + this->instances[devid].settings[l] = r; + } + } + continue; + } + + if(command == "CORE") + { + string devname; + in >> devname; + uc(devname); + + if(cores.find(devname) == cores.end()) + { + cout << "Unknown core: " << devname << endl; + f.close(); + return false; + } + + this->core.device = devname; + this->core.unit = 0; + + while(in >> temp) + { + pos = temp.find("="); + if(pos>0) + { + this->core.settings[temp.substr(0,pos)] = temp.substr(pos,temp.size()); + } + } + continue; + } + + if(command == "LINKER") + { + in >> this->linker; + continue; + } + + if(command == "OPTION") + { + in >> temp; + pos = temp.find("="); + if(pos>0) + { + string l,r; + l = temp.substr(0,pos); + uc(l); + r = temp.substr(pos+1,temp.size()); + this->instances["GLOBAL"].settings[l] = r; + this->instances["GLOBAL"].device="GLOBAL"; + this->instances["GLOBAL"].unit=0; + } + continue; + } + } + f.close(); + return true; +} + diff --git a/tools/configsys/config.h b/tools/configsys/config.h new file mode 100644 index 0000000..40bc383 --- /dev/null +++ b/tools/configsys/config.h @@ -0,0 +1,25 @@ +#ifndef _CONFIG_H +#define _CONFIG_H + +#include +#include +#include "mapping.h" +#include "instance.h" + +using namespace std; + +class config { + public: + string pinmapping; + instance core; + map instances; + string configpath; + string linker; + map options; + + public: + bool load(const char *); + config(string); +}; + +#endif diff --git a/tools/configsys/core.cpp b/tools/configsys/core.cpp new file mode 100644 index 0000000..703c9f1 --- /dev/null +++ b/tools/configsys/core.cpp @@ -0,0 +1,55 @@ +#include +#include +#include +#include +#include +#include + +#include "util.h" +#include "core.h" +#include "cluster.h" + +using namespace std; + +bool core::load(const char *filename) +{ + ifstream f; + char line[1024]; + + f.open(filename,ios::in); + if(!f.is_open()) + { + cout << "Unable to open core " << filename << endl; + return false; + } + + while(f.getline(line,1023)) + { + stringstream temp(line); + string in; + temp >> in; + uc(in); + if(in.substr(0,1) == "#") + continue; + + if(in == "MACHINE") + { + this->data.read(f); + } + + if(in == "ALWAYS") + { + this->always.read(f); + } + if(in == "OPTION") + { + temp >> in; + uc(in); + this->options[in].read(f); + } + } + + f.close(); + return true; +} + diff --git a/tools/configsys/core.h b/tools/configsys/core.h new file mode 100644 index 0000000..88f04ff --- /dev/null +++ b/tools/configsys/core.h @@ -0,0 +1,21 @@ +#ifndef _CORE_H +#define _CORE_H + +#include +#include +#include "cluster.h" +#include "gstore.h" + +using namespace std; + +class core { + public: + map options; // Option clusters + cluster always; // Always cluster + gstore data; // data store + + public: + bool load(const char *); +}; + +#endif diff --git a/tools/configsys/cores/pic32mx7.cor b/tools/configsys/cores/pic32mx7.cor new file mode 100644 index 0000000..4c0eac0 --- /dev/null +++ b/tools/configsys/cores/pic32mx7.cor @@ -0,0 +1,16 @@ +machine + root pic32 +end machine + +always + define PIC32MX7 + require kernel +end always + +option cpu_khz + define CPU_KHZ %1 +end option + +option bus_khz + define BUS_KHZ %1 +end option diff --git a/tools/configsys/device.cpp b/tools/configsys/device.cpp new file mode 100644 index 0000000..3a4c613 --- /dev/null +++ b/tools/configsys/device.cpp @@ -0,0 +1,50 @@ +#include +#include +#include +#include +#include +#include + +#include "util.h" +#include "device.h" +#include "cluster.h" + +using namespace std; + +bool device::load(const char *filename) +{ + ifstream f; + char line[1024]; + + f.open(filename,ios::in); + if(!f.is_open()) + { + cout << "Unable to open device " << filename << endl; + return false; + } + + while(f.getline(line,1023)) + { + stringstream temp(line); + string in; + temp >> in; + uc(in); + if(in.substr(0,1) == "#") + continue; + + if(in == "ALWAYS") + { + this->always.read(f); + } + if(in == "OPTION") + { + temp >> in; + uc(in); + this->options[in].read(f); + } + } + + f.close(); + return true; +} + diff --git a/tools/configsys/device.h b/tools/configsys/device.h new file mode 100644 index 0000000..308594f --- /dev/null +++ b/tools/configsys/device.h @@ -0,0 +1,19 @@ +#ifndef _DEVICE_H +#define _DEVICE_H + +#include +#include +#include "cluster.h" + +using namespace std; + +class device { + public: + map options; // Option clusters + cluster always; // Always cluster + + public: + bool load(const char *); +}; + +#endif diff --git a/tools/configsys/gstore.cpp b/tools/configsys/gstore.cpp new file mode 100644 index 0000000..a12e611 --- /dev/null +++ b/tools/configsys/gstore.cpp @@ -0,0 +1,34 @@ +#include +#include +#include +#include +#include +#include + +#include "util.h" +#include "gstore.h" + +using namespace std; + +void gstore::read(ifstream& f) +{ + char line[1024]; + string in; + + while(f.getline(line,1023)) + { + stringstream temp(line); + temp >> in; + uc(in); + if(in.substr(0,1) == "#") + continue; + if(in == "END") + { + return; + } + + temp >> this->values[in]; + } + return; +} + diff --git a/tools/configsys/gstore.h b/tools/configsys/gstore.h new file mode 100644 index 0000000..a32db38 --- /dev/null +++ b/tools/configsys/gstore.h @@ -0,0 +1,19 @@ +#ifndef _GSTORE_H +#define _GSTORE_H + +#include +#include +#include +#include + +using namespace std; + +class gstore { + public: + map values; + + public: + void read(ifstream&); +}; + +#endif diff --git a/tools/configsys/instance.h b/tools/configsys/instance.h new file mode 100644 index 0000000..ec4999b --- /dev/null +++ b/tools/configsys/instance.h @@ -0,0 +1,17 @@ +#ifndef _INSTANCE_H +#define _INSTANCE_H + +#include +#include +#include "cluster.h" + +using namespace std; + +class instance { + public: + map settings; // Settings from config + int unit; + string device; +}; + +#endif diff --git a/tools/configsys/main.cpp b/tools/configsys/main.cpp new file mode 100644 index 0000000..0fd4ba0 --- /dev/null +++ b/tools/configsys/main.cpp @@ -0,0 +1,652 @@ +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + + +#include "util.h" +#include "config.h" +#include "device.h" +#include "core.h" + +using namespace std; + +map devices; +map cores; +map mappings; + +void substitute(string &out, string source, string param, int devnum, string pinmap) +{ + size_t pos; + stringstream dnum; + dnum << devnum; + + out = source; + + replace_all(out, "%0", dnum.str()); + replace_all(out, "%1", param); + + pos = out.find("$TRIS("); + while(pos != out.npos) + { + int end; + string content; + end = out.find(")",pos); + content = out.substr(pos+6,(end-pos)-6); + out.replace(pos,pos-end,"TRIS"+mappings[pinmap].ports[content]); + pos = out.find("$TRIS("); + } + + pos = out.find("$PIN("); + while(pos != out.npos) + { + int end; + string content; + stringstream pno; + end = out.find(")",pos); + content = out.substr(pos+5,(end-pos)-5); + pno << mappings[pinmap].pins[content]; + out.replace(pos,pos-end,pno.str()); + pos = out.find("$PIN("); + } +} + +int main(int argc, char *argv[]) +{ + string path(argv[0]); + string root,machine,cfg; + string corep; + DIR *d; + struct dirent *dent; + map ::iterator dit; + map ::iterator sit; + map ::iterator cit; + int q __attribute__((unused)); + + if(argc!=2) + { + cout << "Usage: " << argv[0] << " " << endl; + return 10; + } + + path = path.substr(0,path.rfind("/")); + root = path + "/../.."; + corep = path + "/cores"; + + d = opendir(corep.c_str()); + if(!d) + { + cout << "Unable to locate cores directory!" << endl; + return 10; + } + + while((dent = readdir(d))) + { + string filepath(corep + "/" + dent->d_name); + string filename(dent->d_name); + + if(filepath.substr(filepath.size()-4,4) == ".cor") + { + string devname = filename.substr(0,filename.size()-4); + uc(devname); + if(!cores[devname].load(filepath.c_str())) + { + cout << "Unable to parse core " << devname << endl; + return 10; + } + } + } + closedir(d); + + + config config(cfg); + + if(!config.load(argv[1])) + { + cout << "Config load failed" << endl; + return 10; + } + + machine = root + "/sys/" + cores[config.core.device].data.values["ROOT"]; + cfg = machine + "/cfg"; + + cout << "Machine: " << machine << endl; + cout << "Config: " << cfg << endl; + + d = opendir(cfg.c_str()); + if(!d) + { + cout << "Unable to locate config directory!" << endl; + return 10; + } + + while((dent = readdir(d))) + { + string filepath(cfg + "/" + dent->d_name); + string filename(dent->d_name); + + if(filepath.substr(filepath.size()-4,4) == ".dev") + { + string devname = filename.substr(0,filename.size()-4); + uc(devname); + if(!devices[devname].load(filepath.c_str())) + { + cout << "Unable to parse device " << devname << endl; + return 10; + } + } + + if(filepath.substr(filepath.size()-4,4) == ".map") + { + string devname = filename.substr(0,filename.size()-4); + uc(devname); + if(!mappings[devname].load(filepath.c_str())) + { + cout << "Unable to parse mapping " << devname << endl; + return 10; + } + } + } + closedir(d); + + + // At this point we should now have the configuration loaded in the config object, and all the + // device descriptors etc loaded into their respective maps. + // Now to link the two together to create an output. + + // First we will iterate the device instances and collate any requred sub-devices. + // From that we will add new device instances, and repeat until there are no more changes. + + bool repeat = true; + map ::iterator it; + vector ::iterator rit; + + if(cores.find(config.core.device)==cores.end()) + { + cout << "Unknown core: " << config.core.device << endl; + return 10; + } + + for(rit = cores[config.core.device].always.requires.begin(); + rit != cores[config.core.device].always.requires.end(); + rit++) + { + map ::iterator iit; + bool exist = false; + for(iit = config.instances.begin(); iit != config.instances.end(); iit++) + { + if((*iit).second.device == *rit) + { + exist = true; + } + } + if(!exist) + { + config.instances[*rit].device=*rit; + config.instances[*rit].unit=0; + } + } + + while(repeat) + { + repeat = false; + for(it = config.instances.begin(); it != config.instances.end(); it++) + { + for( + rit = devices[(*it).second.device].always.requires.begin(); + rit != devices[(*it).second.device].always.requires.end(); + rit++) + { + map ::iterator iit; + bool exist = false; + for(iit = config.instances.begin(); iit != config.instances.end(); iit++) + { + if((*iit).second.device == *rit) + { + exist = true; + } + } + if(!exist) + { + config.instances[*rit].device=*rit; + config.instances[*rit].unit=0; + repeat=true; + } + } + } + } + + // Ok, we now have instances for all devices, and all their dependencies, and all + // their dependencies dependencies ... etc ... + + // Now we need to generate our lists. + // Let's start with files. Work through the list of instances, and get the files + // from their devices. Compile them all into one big vector in + // alphabetical order. + + vector files; + + // First the core: + + vector ::iterator fit; + vector ::iterator eit; + vector ::iterator vit; + + for( + fit = cores[config.core.device].always.files.begin(); + fit != cores[config.core.device].always.files.end(); + fit++ + ) + { + bool exist = false; + for(eit = files.begin(); eit != files.end(); eit++) + { + if(*eit == *fit) + exist = true; + } + if(!exist) + { + files.push_back(*fit); + } + } + + + // Then the instances: + + for(it = config.instances.begin(); it != config.instances.end(); it++) + { + for( + fit = devices[(*it).second.device].always.files.begin(); + fit != devices[(*it).second.device].always.files.end(); + fit++ + ) + { + bool exist = false; + for(eit = files.begin(); eit != files.end(); eit++) + { + if(*eit == *fit) + exist = true; + } + if(!exist) + { + files.push_back(*fit); + } + } + } + + vector nofiles; + + // First the core: + + + for( + fit = cores[config.core.device].always.nofiles.begin(); + fit != cores[config.core.device].always.nofiles.end(); + fit++ + ) + { + bool exist = false; + for(eit = nofiles.begin(); eit != nofiles.end(); eit++) + { + if(*eit == *fit) + exist = true; + } + if(!exist) + { + nofiles.push_back(*fit); + } + } + + + // Then the instances: + + for(it = config.instances.begin(); it != config.instances.end(); it++) + { + for( + fit = devices[(*it).second.device].always.nofiles.begin(); + fit != devices[(*it).second.device].always.nofiles.end(); + fit++ + ) + { + bool exist = false; + for(eit = nofiles.begin(); eit != nofiles.end(); eit++) + { + if(*eit == *fit) + exist = true; + } + if(!exist) + { + nofiles.push_back(*fit); + } + } + } + + // We have the files, now to sort them alphabetically. A good old + // bubble sort is what we will do. We could have done this while + // adding the files to the vector, but this is simpler to manage. + + unsigned int outer,inner; + + for(outer = 0; outer < files.size(); outer++) + { + for(inner = outer; inner < files.size(); inner++) + { + if(files[outer] > files[inner]) + { + string t = files[outer]; + files[outer] = files[inner]; + files[inner] = t; + } + } + } + + // Now we should filter out the files to remove any nofiles. Again, this + // could have been integrated with the previous stages, but meh... + + for (fit = files.begin(); fit != files.end(); fit++) { + bool exist = false; + for (eit = nofiles.begin(); eit != nofiles.end(); eit++) { + if(*eit == *fit) + exist = true; + } + if (exist) { + files.erase(fit); + } + } + + // Now to collate the extra targets that should be built. + + vector targets; + + // First the core: + + for ( + fit = cores[config.core.device].always.targets.begin(); + fit != cores[config.core.device].always.targets.end(); + fit++ + ) { + bool exist = false; + for (eit = targets.begin(); eit != targets.end(); eit++) { + if(*eit == *fit) + exist = true; + } + if (!exist) { + targets.push_back(*fit); + } + } + + // Then the instances: + + for (it = config.instances.begin(); it != config.instances.end(); it++) { + for ( + fit = devices[(*it).second.device].always.targets.begin(); + fit != devices[(*it).second.device].always.targets.end(); + fit++ + ) { + bool exist = false; + for (eit = targets.begin(); eit != targets.end(); eit++) { + if(*eit == *fit) + exist = true; + } + if (!exist) { + targets.push_back(*fit); + } + } + } + + // Next let's do the defines. We need to do this for the "always" + // and also for every instance. We also need to do string replacements + // using the data from the instances. + + map defines; + + // Again, core first: + + for( + dit = cores[config.core.device].always.defines.begin(); + dit != cores[config.core.device].always.defines.end(); + dit++ + ) + { + string f,s; + substitute(f, (*dit).first, "", 0, config.pinmapping); + substitute(s, (*dit).second, "", 0, config.pinmapping); + defines[f] = s; + } + for( + sit = config.core.settings.begin(); + sit != config.core.settings.end(); + sit++ + ) + { + string testopt = (*sit).first + "=" + (*sit).second; + uc(testopt); + if(cores[config.core.device].options.find(testopt) == cores[config.core.device].options.end()) + { + testopt = (*sit).first; + uc(testopt); + if(cores[config.core.device].options.find(testopt) == cores[config.core.device].options.end()) + { + cout << "Unknown option: " << testopt << endl; + return 10; + } + } + for( + dit = cores[config.core.device].options[testopt].defines.begin(); + dit != cores[config.core.device].options[testopt].defines.end(); + dit++ + ) + { + string f,s; + substitute(f, (*dit).first, (*sit).second, 0, config.pinmapping); + substitute(s, (*dit).second, (*sit).second, 0, config.pinmapping); + defines[f] = s; + } + } + + // followed by the instances: + + for(it = config.instances.begin(); it != config.instances.end(); it++) + { + for( + dit = devices[(*it).second.device].always.defines.begin(); + dit != devices[(*it).second.device].always.defines.end(); + dit++ + ) + { + string f,s; + substitute(f, (*dit).first, "", (*it).second.unit, config.pinmapping); + substitute(s, (*dit).second, "", (*it).second.unit, config.pinmapping); + defines[f] = s; + } + for( + sit = (*it).second.settings.begin(); + sit != (*it).second.settings.end(); + sit++ + ) + { + string testopt = (*sit).first + "=" + (*sit).second; + uc(testopt); + if(devices[(*it).second.device].options.find(testopt) == devices[(*it).second.device].options.end()) + { + testopt = (*sit).first; + uc(testopt); + if(devices[(*it).second.device].options.find(testopt) == devices[(*it).second.device].options.end()) + { + cout << "Unknown option: " << testopt << "=" << (*sit).second<< endl; + return 10; + } + } + for( + dit = devices[(*it).second.device].options[testopt].defines.begin(); + dit != devices[(*it).second.device].options[testopt].defines.end(); + dit++ + ) + { + string f,s; + substitute(f, (*dit).first, (*sit).second, (*it).second.unit, config.pinmapping); + substitute(s, (*dit).second, (*sit).second, (*it).second.unit, config.pinmapping); + defines[f] = s; + } + } + } + + // Wow... that was fun. Now we need to do it all again for the SETs. + + map sets; + + for( + dit = cores[config.core.device].always.sets.begin(); + dit != cores[config.core.device].always.sets.end(); + dit++ + ) + { + string f,s; + substitute(f, (*dit).first, "", 0, config.pinmapping); + substitute(s, (*dit).second, "", 0, config.pinmapping); + sets[f] = s; + } + for( + sit = config.core.settings.begin(); + sit != config.core.settings.end(); + sit++ + ) + { + if(cores[config.core.device].options.find((*sit).first) == cores[config.core.device].options.end()) + { + cout << "Unknown option: " << (*sit).first << endl; + return 10; + } + for( + dit = cores[config.core.device].options[(*sit).first].sets.begin(); + dit != cores[config.core.device].options[(*sit).first].sets.end(); + dit++ + ) + { + string f,s; + substitute(f, (*dit).first, (*sit).second, 0, config.pinmapping); + substitute(s, (*dit).second, (*sit).second, 0, config.pinmapping); + sets[f] = s; + } + } + + + for(it = config.instances.begin(); it != config.instances.end(); it++) + { + for( + dit = devices[(*it).second.device].always.sets.begin(); + dit != devices[(*it).second.device].always.sets.end(); + dit++ + ) + { + string f,s; + substitute(f, (*dit).first, "", (*it).second.unit, config.pinmapping); + substitute(s, (*dit).second, "", (*it).second.unit, config.pinmapping); + sets[f] = s; + } + for( + sit = (*it).second.settings.begin(); + sit != (*it).second.settings.end(); + sit++ + ) + { + string testopt = (*sit).first + "=" + (*sit).second; + uc(testopt); + if(devices[(*it).second.device].options.find(testopt) == devices[(*it).second.device].options.end()) + { + testopt = (*sit).first; + uc(testopt); + if(devices[(*it).second.device].options.find(testopt) == devices[(*it).second.device].options.end()) + { + cout << "Unknown option " << testopt << endl; + return 10; + } + } + for( + dit = devices[(*it).second.device].options[testopt].sets.begin(); + dit != devices[(*it).second.device].options[testopt].sets.end(); + dit++ + ) + { + string f,s; + substitute(f, (*dit).first, (*sit).second, (*it).second.unit, config.pinmapping); + substitute(s, (*dit).second, (*sit).second, (*it).second.unit, config.pinmapping); + sets[f] = s; + } + } + } + + // Right, we might have it all ready for outputting now. Let's give it a go... + + ofstream out; + + out.open("Makefile",ios::out); + + out << "BUILDPATH = " << machine << endl; + out << "H = " << root << "/sys/include" << endl; + out << "M = " << machine << endl; + out << "S = " << root << "/sys/kernel" << endl; + out << endl; + out << "vpath %.c $(M):$(S)" << endl; + out << "vpath %.S $(M):$(S)" << endl; + out << endl; + out << "KERNOBJ += "; + + + for(vit = files.begin(); vit != files.end(); vit++) + { + out << (*vit) << " "; + } + out << endl; + out << "EXTRA_TARGETS = "; + + for(vit = targets.begin(); vit != targets.end(); vit++) + { + out << (*vit) << " "; + } + + out << endl; + out << endl; + + for(sit = defines.begin(); sit != defines.end(); sit++) + { + if((*sit).second != "") + { + out << "DEFS += -D" << (*sit).first << "=" << (*sit).second << endl; + } else { + out << "DEFS += -D" << (*sit).first << endl; + } + } + + out << endl; + + for(sit = sets.begin(); sit != sets.end(); sit++) + { + out << (*sit).first << " = " << (*sit).second << endl; + } + + out << endl; + + out << "LDSCRIPT = " << machine << "/cfg/"<< config.linker << ".ld" << endl; + + out << endl; + out << "CONFIG = " << argv[1] << endl; + out << "CONFIGPATH = " << path << endl; + + out << endl; + + out << "include " << machine << "/kernel-post.mk" << endl; + out.close(); + + q = system("make clean"); + + return 0; +} diff --git a/tools/configsys/mapping.cpp b/tools/configsys/mapping.cpp new file mode 100644 index 0000000..0dbb8f1 --- /dev/null +++ b/tools/configsys/mapping.cpp @@ -0,0 +1,40 @@ +#include +#include +#include +#include +#include +#include +#include "mapping.h" + +using namespace std; + +bool mapping::load(const char *filename) +{ + ifstream f; + string in; + char line[1024]; + + f.open(filename); + if(!f.is_open()) + { + cout << "Unable to open mapping " << filename << endl; + return false; + } + + while(f.getline(line,1023)) + { + stringstream temp(line); + string silk; + + temp << line; + temp >> silk; + if(silk.substr(0,1)=="#") + continue; + + temp >> this->ports[silk]; + temp >> this->pins[silk]; + + } + f.close(); + return true; +} diff --git a/tools/configsys/mapping.h b/tools/configsys/mapping.h new file mode 100644 index 0000000..794c1fc --- /dev/null +++ b/tools/configsys/mapping.h @@ -0,0 +1,17 @@ +#ifndef _MAPPING_H +#define _MAPPING_H + +#include + +using namespace std; + +class mapping { + public: + map ports; + map pins; + + public: + bool load(const char *); +}; + +#endif diff --git a/tools/configsys/util.cpp b/tools/configsys/util.cpp new file mode 100644 index 0000000..56b34de --- /dev/null +++ b/tools/configsys/util.cpp @@ -0,0 +1,27 @@ +#include +#include +#include +#include +#include +#include + +using namespace std; + +void replace_all(string &haystack, string from, string to) +{ + size_t pos; + pos = haystack.find(from); + while(pos != haystack.npos) + { + haystack.replace(pos, from.size(), to); + pos = haystack.find(from); + } +} + +void uc(string &s) +{ + for(unsigned int l = 0; l < s.length(); l++) + { + s[l] = toupper(s[l]); + } +} diff --git a/tools/configsys/util.h b/tools/configsys/util.h new file mode 100644 index 0000000..7269bbd --- /dev/null +++ b/tools/configsys/util.h @@ -0,0 +1,11 @@ +#ifndef _UTIL_H +#define _UTIL_H + +#include + +using namespace std; + +extern void replace_all(string &haystack, string from, string to); +extern void uc(string &s); + +#endif diff --git a/tools/elf2aout/Makefile b/tools/elf2aout/Makefile new file mode 100644 index 0000000..8224766 --- /dev/null +++ b/tools/elf2aout/Makefile @@ -0,0 +1,18 @@ +CC = gcc -g +CFLAGS = -O -Wall +DESTDIR = /usr/local +OBJS = elf2aout.o +PROG = elf2aout + +# For Mac OS X +#LIBS = -largp + +all: $(PROG) + +install: $(PROG) + install -s $(PROG) ${DESTDIR}/bin/$(PROG) +clean: + rm -f *~ *.o *.lst *.dis $(PROG) + +$(PROG): $(OBJS) + $(CC) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) diff --git a/tools/elf2aout/elf2aout.c b/tools/elf2aout/elf2aout.c new file mode 100644 index 0000000..453254e --- /dev/null +++ b/tools/elf2aout/elf2aout.c @@ -0,0 +1,723 @@ +/* + * This program converts an elf executable to a BSD a.out executable. + * The minimal symbol table is copied, but the debugging symbols and + * other informational sections are not. + * + * Copyright (c) 1995 Ted Lemon (hereinafter referred to as the author) + * Copyright (c) 2011 Serge Vakulenko + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Header prepended to each a.out file. + */ +struct exec { + unsigned a_magic; /* magic number */ +#define OMAGIC 0407 /* old impure format */ + + unsigned a_text; /* size of text segment */ + unsigned a_data; /* size of initialized data */ + unsigned a_bss; /* size of uninitialized data */ + unsigned a_reltext; /* size of text relocation info */ + unsigned a_reldata; /* size of data relocation info */ + unsigned a_syms; /* size of symbol table */ + unsigned a_entry; /* entry point */ +}; + +struct nlist { + union { + char *n_name; /* In memory address of symbol name */ + unsigned n_strx; /* String table offset (file) */ + } n_un; + u_char n_type; /* Type of symbol - see below */ + char n_ovly; /* Overlay number */ + u_int n_value; /* Symbol value */ +}; + +/* + * Simple values for n_type. + */ +#define N_UNDF 0x00 /* undefined */ +#define N_ABS 0x01 /* absolute */ +#define N_TEXT 0x02 /* text segment */ +#define N_DATA 0x03 /* data segment */ +#define N_BSS 0x04 /* bss segment */ +#define N_REG 0x14 /* register symbol */ +#define N_FN 0x1f /* file name */ + +#define N_EXT 0x20 /* external (global) bit, OR'ed in */ +#define N_TYPE 0x1f /* mask for all the type bits */ + +struct sect { + /* should be unsigned long, but assume no a.out binaries on LP64 */ + uint32_t vaddr; + uint32_t len; +}; + +/* + * Standard ELF types, structures, and macros. + */ + +/* The ELF file header. This appears at the start of every ELF file. */ + +#define EI_NIDENT (16) + +typedef struct +{ + unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ + uint16_t e_type; /* Object file type */ + uint16_t e_machine; /* Architecture */ + uint32_t e_version; /* Object file version */ + uint32_t e_entry; /* Entry point virtual address */ + uint32_t e_phoff; /* Program header table file offset */ + uint32_t e_shoff; /* Section header table file offset */ + uint32_t e_flags; /* Processor-specific flags */ + uint16_t e_ehsize; /* ELF header size in bytes */ + uint16_t e_phentsize; /* Program header table entry size */ + uint16_t e_phnum; /* Program header table entry count */ + uint16_t e_shentsize; /* Section header table entry size */ + uint16_t e_shnum; /* Section header table entry count */ + uint16_t e_shstrndx; /* Section header string table index */ +} Elf32_Ehdr; + +/* Program segment header. */ + +typedef struct +{ + uint32_t p_type; /* Segment type */ + uint32_t p_offset; /* Segment file offset */ + uint32_t p_vaddr; /* Segment virtual address */ + uint32_t p_paddr; /* Segment physical address */ + uint32_t p_filesz; /* Segment size in file */ + uint32_t p_memsz; /* Segment size in memory */ + uint32_t p_flags; /* Segment flags */ + uint32_t p_align; /* Segment alignment */ +} Elf32_Phdr; + +/* Section header. */ + +typedef struct +{ + uint32_t sh_name; /* Section name (string tbl index) */ + uint32_t sh_type; /* Section type */ + uint32_t sh_flags; /* Section flags */ + uint32_t sh_addr; /* Section virtual addr at execution */ + uint32_t sh_offset; /* Section file offset */ + uint32_t sh_size; /* Section size in bytes */ + uint32_t sh_link; /* Link to another section */ + uint32_t sh_info; /* Additional section information */ + uint32_t sh_addralign; /* Section alignment */ + uint32_t sh_entsize; /* Entry size if section holds table */ +} Elf32_Shdr; + +/* Symbol table entry. */ + +typedef struct +{ + uint32_t st_name; /* Symbol name (string tbl index) */ + uint32_t st_value; /* Symbol value */ + uint32_t st_size; /* Symbol size */ + unsigned char st_info; /* Symbol type and binding */ + unsigned char st_other; /* Symbol visibility */ + uint16_t st_shndx; /* Section index */ +} Elf32_Sym; + +/* Legal values for p_type (segment type). */ + +#define PT_NULL 0 /* Program header table entry unused */ +#define PT_LOAD 1 /* Loadable program segment */ +#define PT_DYNAMIC 2 /* Dynamic linking information */ +#define PT_INTERP 3 /* Program interpreter */ +#define PT_NOTE 4 /* Auxiliary information */ +#define PT_SHLIB 5 /* Reserved */ +#define PT_PHDR 6 /* Entry for header table itself */ +#define PT_TLS 7 /* Thread-local storage segment */ +#define PT_NUM 8 /* Number of defined types */ +#define PT_LOOS 0x60000000 /* Start of OS-specific */ +#define PT_GNU_EH_FRAME 0x6474e550 /* GCC .eh_frame_hdr segment */ +#define PT_GNU_STACK 0x6474e551 /* Indicates stack executability */ +#define PT_GNU_RELRO 0x6474e552 /* Read-only after relocation */ +#define PT_LOSUNW 0x6ffffffa +#define PT_SUNWBSS 0x6ffffffa /* Sun Specific segment */ +#define PT_SUNWSTACK 0x6ffffffb /* Stack segment */ +#define PT_HISUNW 0x6fffffff +#define PT_HIOS 0x6fffffff /* End of OS-specific */ +#define PT_LOPROC 0x70000000 /* Start of processor-specific */ +#define PT_HIPROC 0x7fffffff /* End of processor-specific */ + +/* Legal values for p_type field of Elf32_Phdr. */ + +#define PT_MIPS_REGINFO 0x70000000 /* Register usage information */ +#define PT_MIPS_RTPROC 0x70000001 /* Runtime procedure table. */ +#define PT_MIPS_OPTIONS 0x70000002 + +/* Legal values for p_flags (segment flags). */ + +#define PF_X (1 << 0) /* Segment is executable */ +#define PF_W (1 << 1) /* Segment is writable */ +#define PF_R (1 << 2) /* Segment is readable */ +#define PF_MASKOS 0x0ff00000 /* OS-specific */ +#define PF_MASKPROC 0xf0000000 /* Processor-specific */ + +/* How to extract and insert information held in the st_info field. */ + +#define ELF32_ST_BIND(val) (((unsigned char) (val)) >> 4) +#define ELF32_ST_TYPE(val) ((val) & 0xf) +#define ELF32_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf)) + +/* Legal values for ST_TYPE subfield of st_info (symbol type). */ + +#define STT_NOTYPE 0 /* Symbol type is unspecified */ +#define STT_OBJECT 1 /* Symbol is a data object */ +#define STT_FUNC 2 /* Symbol is a code object */ +#define STT_SECTION 3 /* Symbol associated with a section */ +#define STT_FILE 4 /* Symbol's name is file name */ +#define STT_COMMON 5 /* Symbol is a common data object */ +#define STT_TLS 6 /* Symbol is thread-local data object*/ +#define STT_NUM 7 /* Number of defined types. */ +#define STT_LOOS 10 /* Start of OS-specific */ +#define STT_GNU_IFUNC 10 /* Symbol is indirect code object */ +#define STT_HIOS 12 /* End of OS-specific */ +#define STT_LOPROC 13 /* Start of processor-specific */ +#define STT_HIPROC 15 /* End of processor-specific */ + +/* Special section indices. */ + +#define SHN_UNDEF 0 /* Undefined section */ +#define SHN_LORESERVE 0xff00 /* Start of reserved indices */ +#define SHN_LOPROC 0xff00 /* Start of processor-specific */ +#define SHN_BEFORE 0xff00 /* Order section before all others + (Solaris). */ +#define SHN_AFTER 0xff01 /* Order section after all others + (Solaris). */ +#define SHN_HIPROC 0xff1f /* End of processor-specific */ +#define SHN_LOOS 0xff20 /* Start of OS-specific */ +#define SHN_HIOS 0xff3f /* End of OS-specific */ +#define SHN_ABS 0xfff1 /* Associated symbol is absolute */ +#define SHN_COMMON 0xfff2 /* Associated symbol is common */ +#define SHN_XINDEX 0xffff /* Index is in extra table. */ +#define SHN_HIRESERVE 0xffff /* End of reserved indices */ + +/* Legal values for ST_BIND subfield of st_info (symbol binding). */ + +#define STB_LOCAL 0 /* Local symbol */ +#define STB_GLOBAL 1 /* Global symbol */ +#define STB_WEAK 2 /* Weak symbol */ +#define STB_NUM 3 /* Number of defined types. */ +#define STB_LOOS 10 /* Start of OS-specific */ +#define STB_GNU_UNIQUE 10 /* Unique symbol. */ +#define STB_HIOS 12 /* End of OS-specific */ +#define STB_LOPROC 13 /* Start of processor-specific */ +#define STB_HIPROC 15 /* End of processor-specific */ + +void combine (struct sect *, struct sect *, int); +int phcmp (const void *, const void *); +char *save_read (int file, off_t offset, off_t len, const char *name); +void copy (int, int, off_t, off_t); +void translate_syms (int, int, off_t, off_t, off_t, off_t); + +int *symTypeTable; + +int +main(int argc, char **argv) +{ + Elf32_Ehdr ex; + Elf32_Phdr *ph; + Elf32_Shdr *sh; + char *shstrtab; + int strtabix, symtabix; + int i; + struct sect text, data, bss; + struct exec aex; + int infile, outfile; + uint32_t cur_vma = UINT32_MAX; + int verbose = 0; + int symflag = 0; + + strtabix = symtabix = 0; + text.len = data.len = bss.len = 0; + text.vaddr = data.vaddr = bss.vaddr = 0; + + /* Check args... */ + for (;;) { + switch (getopt (argc, argv, "sv")) { + case EOF: + break; + case 'v': + ++verbose; + continue; + case 's': + ++symflag; + continue; + default: +usage: fprintf(stderr, + "usage: elf2aout [-v] [-s] \n"); + exit(1); + } + break; + } + argc -= optind; + argv += optind; + if (argc != 2) + goto usage; + + /* Try the input file... */ + if ((infile = open(argv[0], O_RDONLY)) < 0) { + fprintf(stderr, "Can't open %s for read: %s\n", + argv[0], strerror(errno)); + exit(1); + } + /* Read the header, which is at the beginning of the file... */ + i = read(infile, &ex, sizeof ex); + if (i != sizeof ex) { + fprintf(stderr, "ex: %s: %s.\n", + argv[0], i ? strerror(errno) : "End of file reached"); + exit(1); + } + /* Read the program headers... */ + ph = (Elf32_Phdr *) save_read(infile, ex.e_phoff, + ex.e_phnum * sizeof(Elf32_Phdr), "ph"); + + /* Read the section headers... */ + sh = (Elf32_Shdr *) save_read(infile, ex.e_shoff, + ex.e_shnum * sizeof(Elf32_Shdr), "sh"); + + /* Read in the section string table. */ + shstrtab = save_read(infile, sh[ex.e_shstrndx].sh_offset, + sh[ex.e_shstrndx].sh_size, "shstrtab"); + + /* Find space for a table matching ELF section indices to a.out symbol + * types. */ + symTypeTable = malloc(ex.e_shnum * sizeof(int)); + if (symTypeTable == NULL) { + fprintf(stderr, "symTypeTable: can't allocate.\n"); + exit(1); + } + memset(symTypeTable, 0, ex.e_shnum * sizeof(int)); + + /* Look for the symbol table and string table... Also map section + * indices to symbol types for a.out */ + for (i = 0; i < ex.e_shnum; i++) { + char *name = shstrtab + sh[i].sh_name; + if (!strcmp(name, ".symtab")) + symtabix = i; + + else if (!strcmp(name, ".strtab")) + strtabix = i; + + else if (!strcmp(name, ".text") || !strcmp(name, ".rodata")) + symTypeTable[i] = N_TEXT; + + else if (!strcmp(name, ".data") || !strcmp(name, ".sdata") || + !strcmp(name, ".lit4") || !strcmp(name, ".lit8")) + symTypeTable[i] = N_DATA; + + else if (!strcmp(name, ".bss") || !strcmp(name, ".sbss")) + symTypeTable[i] = N_BSS; + } + + /* Figure out if we can cram the program header into an a.out + * header... Basically, we can't handle anything but loadable + * segments, but we can ignore some kinds of segments. We can't + * handle holes in the address space, and we handle start addresses + * other than 0x1000 by hoping that the loader will know where to load + * - a.out doesn't have an explicit load address. Segments may be + * out of order, so we sort them first. */ + qsort(ph, ex.e_phnum, sizeof(Elf32_Phdr), phcmp); + for (i = 0; i < ex.e_phnum; i++) { + /* Section types we can ignore... */ + if (ph[i].p_type == PT_NULL || ph[i].p_type == PT_NOTE || + ph[i].p_type == PT_PHDR || ph[i].p_type == PT_MIPS_REGINFO) + continue; + + /* Section types we can't handle... */ + if (ph[i].p_type != PT_LOAD) + errx(1, "Program header %d type %d can't be converted.", i, ph[i].p_type); + if (verbose) + printf ("Section type=%x flags=%x vaddr=%x filesz=%x\n", + ph[i].p_type, ph[i].p_flags, ph[i].p_vaddr, ph[i].p_filesz); + + /* Writable (data) segment? */ + if (ph[i].p_flags & PF_W) { + struct sect ndata, nbss; + + ndata.vaddr = ph[i].p_vaddr; + ndata.len = ph[i].p_filesz; + nbss.vaddr = ph[i].p_vaddr + ph[i].p_filesz; + nbss.len = ph[i].p_memsz - ph[i].p_filesz; + + combine(&data, &ndata, 0); + combine(&bss, &nbss, 1); + } else { + struct sect ntxt; + + ntxt.vaddr = ph[i].p_vaddr; + ntxt.len = ph[i].p_filesz; + + combine(&text, &ntxt, 0); + } + /* Remember the lowest segment start address. */ + if (ph[i].p_vaddr < cur_vma) + cur_vma = ph[i].p_vaddr; + } + if (! symflag) { + /* Sections must be in order to be converted... */ + if (text.vaddr > data.vaddr || data.vaddr > bss.vaddr || + text.vaddr + text.len > data.vaddr || data.vaddr + data.len > bss.vaddr) { + fprintf(stderr, "Sections ordering prevents a.out conversion.\n"); + exit(1); + } + } + + /* If there's a data section but no text section, then the loader + * combined everything into one section. That needs to be the text + * section, so just make the data section zero length following text. */ + if (data.len && text.len == 0) { + text = data; + data.vaddr = text.vaddr + text.len; + data.len = 0; + } + if (verbose) + printf ("Text vaddr = %x, data vaddr = %x\n", text.vaddr, data.vaddr); + + /* If there is a gap between text and data, we'll fill it when we copy + * the data, so update the length of the text segment as represented + * in a.out to reflect that, since a.out doesn't allow gaps in the + * program address space. */ + if (text.vaddr + text.len < data.vaddr) { + if (verbose) + printf ("Update text len = %x (was %x)\n", + data.vaddr - text.vaddr, text.len); + text.len = data.vaddr - text.vaddr; + } + + /* We now have enough information to cons up an a.out header... */ + aex.a_magic = OMAGIC; + if (! symflag) { + aex.a_text = text.len; + aex.a_data = data.len; + aex.a_bss = bss.len; + aex.a_entry = ex.e_entry; + aex.a_syms = 0; + } else { + aex.a_text = 0; + aex.a_data = 0; + aex.a_bss = 0; + aex.a_entry = 0; + aex.a_syms = (sizeof(struct nlist) * (symtabix != -1 ? + sh[symtabix].sh_size / sizeof(Elf32_Sym) : 0)); + } + aex.a_reltext = 0; + aex.a_reldata = 0; + if (verbose) { + printf (" magic: %#o\n", aex.a_magic); + printf (" text: %#x\n", aex.a_text); + printf (" data: %#x\n", aex.a_data); + printf (" bss: %#x\n", aex.a_bss); + printf ("reltext: %#x\n", aex.a_reltext); + printf ("reldata: %#x\n", aex.a_reldata); + printf (" entry: %#x\n", aex.a_entry); + printf (" syms: %u\n", aex.a_syms); + } + + /* Make the output file... */ + if ((outfile = open(argv[1], O_WRONLY | O_CREAT, 0777)) < 0) { + fprintf(stderr, "Unable to create %s: %s\n", argv[1], strerror(errno)); + exit(1); + } + /* Truncate file... */ + if (ftruncate(outfile, 0)) { + warn("ftruncate %s", argv[1]); + } + /* Write the header... */ + i = write(outfile, &aex, sizeof aex); + if (i != sizeof aex) { + perror("aex: write"); + exit(1); + } + if (! symflag) { + /* Copy the loadable sections. Zero-fill any gaps less than 64k; + * complain about any zero-filling, and die if we're asked to + * zero-fill more than 64k. */ + for (i = 0; i < ex.e_phnum; i++) { + /* Unprocessable sections were handled above, so just verify + * that the section can be loaded before copying. */ + if (ph[i].p_type == PT_LOAD && ph[i].p_filesz) { + if (cur_vma != ph[i].p_vaddr) { + uint32_t gap = ph[i].p_vaddr - cur_vma; + char obuf[1024]; + if (gap > 65536) + errx(1, "Intersegment gap (%ld bytes) too large.", (long) gap); +#ifdef DEBUG + warnx("Warning: %ld byte intersegment gap.", + (long)gap); +#endif + memset(obuf, 0, sizeof obuf); + while (gap) { + int count = write(outfile, obuf, (gap > sizeof obuf + ? sizeof obuf : gap)); + if (count < 0) { + fprintf(stderr, "Error writing gap: %s\n", + strerror(errno)); + exit(1); + } + gap -= count; + } + } + copy(outfile, infile, ph[i].p_offset, ph[i].p_filesz); + cur_vma = ph[i].p_vaddr + ph[i].p_filesz; + } + } + } else { + /* Copy and translate the symbol table... */ + translate_syms(outfile, infile, + sh[symtabix].sh_offset, sh[symtabix].sh_size, + sh[strtabix].sh_offset, sh[strtabix].sh_size); + } + /* Looks like we won... */ + return 0; +} + +/* + * translate_syms (out, in, offset, size) + * + * Read the ELF symbol table from in at offset; translate it into a.out + * nlist format and write it to out. + */ +void +translate_syms(int out, int in, off_t symoff, off_t symsize, + off_t stroff, off_t strsize) +{ +#define SYMS_PER_PASS 64 + Elf32_Sym inbuf[64]; + struct nlist outbuf[64]; + int i, remaining, cur; + char *oldstrings; + char *newstrings, *nsp; + int newstringsize, stringsizebuf; + + /* Zero the unused fields in the output buffer.. */ + memset(outbuf, 0, sizeof outbuf); + + /* Find number of symbols to process... */ + remaining = symsize / sizeof(Elf32_Sym); + + /* Suck in the old string table... */ + oldstrings = save_read(in, stroff, strsize, "string table"); + + /* Allocate space for the new one. XXX We make the wild assumption + * that no two symbol table entries will point at the same place in + * the string table - if that assumption is bad, this could easily + * blow up. */ + newstringsize = strsize + remaining; + newstrings = malloc(newstringsize); + if (newstrings == NULL) { + fprintf(stderr, "No memory for new string table!\n"); + exit(1); + } + /* Initialize the table pointer... */ + nsp = newstrings; + + /* Go the start of the ELF symbol table... */ + if (lseek(in, symoff, SEEK_SET) < 0) { + perror("translate_syms: lseek"); + exit(1); + } + /* Translate and copy symbols... */ + while (remaining) { + cur = remaining; + if (cur > SYMS_PER_PASS) + cur = SYMS_PER_PASS; + remaining -= cur; + if ((i = read(in, inbuf, cur * sizeof(Elf32_Sym))) + != cur * (ssize_t)sizeof(Elf32_Sym)) { + if (i < 0) + perror("translate_syms"); + else + fprintf(stderr, "translate_syms: premature end of file.\n"); + exit(1); + } + /* Do the translation... */ + for (i = 0; i < cur; i++) { + int binding, type; + + /* Copy the symbol into the new table, but prepend an + * underscore. */ + *nsp = '_'; + strcpy(nsp + 1, oldstrings + inbuf[i].st_name); + outbuf[i].n_un.n_strx = nsp - newstrings + 4; + nsp += strlen(nsp) + 1; + + type = ELF32_ST_TYPE(inbuf[i].st_info); + binding = ELF32_ST_BIND(inbuf[i].st_info); + + /* Convert ELF symbol type/section/etc info into a.out + * type info. */ + if (type == STT_FILE) + outbuf[i].n_type = N_FN; + + else if (inbuf[i].st_shndx == SHN_UNDEF) + outbuf[i].n_type = N_UNDF; + + else if (inbuf[i].st_shndx == SHN_ABS) + outbuf[i].n_type = N_ABS; + + else if (inbuf[i].st_shndx == SHN_COMMON) + outbuf[i].n_type = N_ABS /*N_COMM*/; + + else + outbuf[i].n_type = symTypeTable[inbuf[i].st_shndx]; + + if (binding == STB_GLOBAL) + outbuf[i].n_type |= N_EXT; + + /* Symbol values in executables should be compatible. */ + outbuf[i].n_value = inbuf[i].st_value; + } + /* Write out the symbols... */ + if ((i = write(out, outbuf, cur * sizeof(struct nlist))) + != cur * (ssize_t)sizeof(struct nlist)) { + fprintf(stderr, "translate_syms: write: %s\n", strerror(errno)); + exit(1); + } + } + /* Write out the string table length... */ + stringsizebuf = newstringsize; + if (write(out, &stringsizebuf, sizeof stringsizebuf) + != sizeof stringsizebuf) { + fprintf(stderr, + "translate_syms: newstringsize: %s\n", strerror(errno)); + exit(1); + } + /* Write out the string table... */ + if (write(out, newstrings, newstringsize) != newstringsize) { + fprintf(stderr, "translate_syms: newstrings: %s\n", strerror(errno)); + exit(1); + } +} + +void +copy(int out, int in, off_t offset, off_t size) +{ + char ibuf[4096]; + int remaining, cur, count; + + /* Go to the start of the ELF symbol table... */ + if (lseek(in, offset, SEEK_SET) < 0) { + perror("copy: lseek"); + exit(1); + } + remaining = size; + while (remaining) { + cur = remaining; + if (cur > (int)sizeof ibuf) + cur = sizeof ibuf; + remaining -= cur; + if ((count = read(in, ibuf, cur)) != cur) { + fprintf(stderr, "copy: read: %s\n", + count ? strerror(errno) : "premature end of file"); + exit(1); + } + if ((count = write(out, ibuf, cur)) != cur) { + perror("copy: write"); + exit(1); + } + } +} + +/* + * Combine two segments, which must be contiguous. + * If pad is true, it's okay for there to be padding between. + */ +void +combine(struct sect *base, struct sect *new, int pad) +{ + + if (base->len == 0) + *base = *new; + else + if (new->len) { + if (base->vaddr + base->len != new->vaddr) { + if (pad) + base->len = new->vaddr - base->vaddr; + else { + fprintf(stderr, + "Non-contiguous data can't be converted.\n"); + exit(1); + } + } + base->len += new->len; + } +} + +int +phcmp(const void *vh1, const void *vh2) +{ + const Elf32_Phdr *h1, *h2; + + h1 = (const Elf32_Phdr *)vh1; + h2 = (const Elf32_Phdr *)vh2; + + if (h1->p_vaddr > h2->p_vaddr) + return 1; + else + if (h1->p_vaddr < h2->p_vaddr) + return -1; + else + return 0; +} + +char * +save_read(int file, off_t offset, off_t len, const char *name) +{ + char *tmp; + int count; + off_t off; + if ((off = lseek(file, offset, SEEK_SET)) < 0) { + fprintf(stderr, "%s: fseek: %s\n", name, strerror(errno)); + exit(1); + } + if ((tmp = malloc(len)) == NULL) + errx(1, "%s: Can't allocate %ld bytes.", name, (long)len); + count = read(file, tmp, len); + if (count != len) { + fprintf(stderr, "%s: read: %s.\n", + name, count ? strerror(errno) : "End of file reached"); + exit(1); + } + return tmp; +} diff --git a/tools/fsutil/Makefile b/tools/fsutil/Makefile new file mode 100644 index 0000000..02c4297 --- /dev/null +++ b/tools/fsutil/Makefile @@ -0,0 +1,34 @@ +CC = gcc -g +CFLAGS = -O -Wall +DESTDIR = /usr/local +OBJS = fsutil.o superblock.o block.c inode.o create.o check.o file.o +PROG = fsutil + +# For Mac OS X +#LIBS = -largp + +all: $(PROG) + +install: $(PROG) + install -s $(PROG) ${DESTDIR}/bin/$(PROG) +clean: + rm -f *~ *.o *.lst *.dis $(PROG) + +$(PROG): $(OBJS) + $(CC) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) + +root.bin: $(PROG) + ./$(PROG) -n16384 -s2048 $@ + ./$(PROG) -v $@ + ./$(PROG) -c $@ + +swap.bin: + dd bs=1k count=2048 < /dev/zero > $@ + +block.o: block.c bsdfs.h +check.o: check.c bsdfs.h +create.o: create.c bsdfs.h +file.o: file.c bsdfs.h +fsutil.o: fsutil.c bsdfs.h +inode.o: inode.c bsdfs.h +superblock.o: superblock.c bsdfs.h diff --git a/tools/fsutil/block.c b/tools/fsutil/block.c new file mode 100644 index 0000000..d178e66 --- /dev/null +++ b/tools/fsutil/block.c @@ -0,0 +1,163 @@ +/* + * Block handling for 2.xBSD filesystem. + * + * Copyright (C) 2006-2011 Serge Vakulenko, + * + * This file is part of RetroBSD project, which is distributed + * under the terms of the GNU General Public License (GPL). + * See the accompanying file "COPYING" for more details. + */ +#include +#include "bsdfs.h" + +extern int verbose; + +int fs_read_block (fs_t *fs, unsigned bnum, unsigned char *data) +{ + if (verbose > 3) + printf ("read block %d\n", bnum); + if (bnum < fs->isize) + return 0; + if (! fs_seek (fs, bnum * BSDFS_BSIZE)) + return 0; + if (! fs_read (fs, data, BSDFS_BSIZE)) + return 0; + return 1; +} + +int fs_write_block (fs_t *fs, unsigned bnum, unsigned char *data) +{ + if (verbose > 3) + printf ("write block %d\n", bnum); + if (! fs->writable || bnum < fs->isize) + return 0; + if (! fs_seek (fs, bnum * BSDFS_BSIZE)) + return 0; + if (! fs_write (fs, data, BSDFS_BSIZE)) + return 0; + fs->modified = 1; + return 1; +} + +/* + * Add a block to free list. + */ +int fs_block_free (fs_t *fs, unsigned int bno) +{ + int i; + unsigned buf [BSDFS_BSIZE / 4]; + + if (verbose > 1) + printf ("free block %d, total %d\n", bno, fs->nfree); + if (fs->nfree >= NICFREE) { + buf[0] = fs->nfree; + for (i=0; ifree[i]; + if (! fs_write_block (fs, bno, (unsigned char*) buf)) { + fprintf (stderr, "block_free: write error at block %d\n", bno); + return 0; + } + fs->nfree = 0; + } + fs->free [fs->nfree] = bno; + fs->nfree++; + fs->dirty = 1; + if (bno) /* Count total free blocks. */ + ++fs->tfree; + return 1; +} + +/* + * Free an indirect block. + */ +int fs_indirect_block_free (fs_t *fs, unsigned int bno) +{ + unsigned nb; + unsigned char data [BSDFS_BSIZE]; + int i; + + if (! fs_read_block (fs, bno, data)) { + fprintf (stderr, "inode_clear: read error at block %d\n", bno); + return 0; + } + for (i=BSDFS_BSIZE-2; i>=0; i-=2) { + nb = data [i+1] << 8 | data [i]; + if (nb) + fs_block_free (fs, nb); + } + fs_block_free (fs, bno); + return 1; +} + +/* + * Free a double indirect block. + */ +int fs_double_indirect_block_free (fs_t *fs, unsigned int bno) +{ + unsigned nb; + unsigned char data [BSDFS_BSIZE]; + int i; + + if (! fs_read_block (fs, bno, data)) { + fprintf (stderr, "inode_clear: read error at block %d\n", bno); + return 0; + } + for (i=BSDFS_BSIZE-2; i>=0; i-=2) { + nb = data [i+1] << 8 | data [i]; + if (nb) + fs_indirect_block_free (fs, nb); + } + fs_block_free (fs, bno); + return 1; +} + +/* + * Free a triple indirect block. + */ +int fs_triple_indirect_block_free (fs_t *fs, unsigned int bno) +{ + unsigned nb; + unsigned char data [BSDFS_BSIZE]; + int i; + + if (! fs_read_block (fs, bno, data)) { + fprintf (stderr, "inode_clear: read error at block %d\n", bno); + return 0; + } + for (i=BSDFS_BSIZE-2; i>=0; i-=2) { + nb = data [i+1] << 8 | data [i]; + if (nb) + fs_double_indirect_block_free (fs, nb); + } + fs_block_free (fs, bno); + return 1; +} + +/* + * Get a block from free list. + */ +int fs_block_alloc (fs_t *fs, unsigned int *bno) +{ + int i; + unsigned buf [BSDFS_BSIZE / 4]; +again: + if (fs->nfree == 0) + return 0; + fs->nfree--; + --fs->tfree; /* Count total free blocks. */ + *bno = fs->free [fs->nfree]; + if (verbose) + printf ("allocate new block %d from slot %d\n", *bno, fs->nfree); + fs->free [fs->nfree] = 0; + fs->dirty = 1; + if (fs->nfree <= 0) { + if (! fs_read_block (fs, *bno, (unsigned char*) buf)) + return 0; + fs->nfree = buf[0]; + for (i=0; ifree[i] = buf[i+1]; + } + if (*bno == 0) + goto again; + return 1; +} diff --git a/tools/fsutil/bsdfs.h b/tools/fsutil/bsdfs.h new file mode 100644 index 0000000..4dc8ff9 --- /dev/null +++ b/tools/fsutil/bsdfs.h @@ -0,0 +1,188 @@ +/* + * Data structures for 2.xBSD filesystem. + * + * Copyright (C) 2006-2011 Serge Vakulenko, + * + * This file is part of RetroBSD project, which is distributed + * under the terms of the GNU General Public License (GPL). + * See the accompanying file "COPYING" for more details. + */ +#define BSDFS_BSIZE 1024 /* block size */ +#define BSDFS_ROOT_INODE 2 /* root directory in inode 2 */ +#define BSDFS_LOSTFOUND_INODE 3 /* lost+found directory in inode 3 */ +#define BSDFS_SWAP_INODE 4 /* swap file in inode 4 */ +#define BSDFS_INODES_PER_BLOCK 16 /* inodes per block */ + +#define NICINOD 32 /* number of superblock inodes */ +#define NICFREE 200 /* number of superblock free blocks */ + +/* + * 28 of the di_addr address bytes are used; 7 addresses of 4 + * bytes each: 4 direct (4Kb directly accessible) and 3 indirect. + */ +#define NDADDR 4 /* direct addresses in inode */ +#define NIADDR 3 /* indirect addresses in inode */ +#define NADDR (NDADDR + NIADDR) /* total addresses in inode */ + +/* + * NINDIR is the number of indirects in a file system block. + */ +#define NINDIR (DEV_BSIZE / sizeof(daddr_t)) +#define NSHIFT 8 /* log2(NINDIR) */ +#define NMASK 0377L /* NINDIR - 1 */ + +/* + * The path name on which the file system is mounted is maintained + * in fs_fsmnt. MAXMNTLEN defines the amount of space allocated in + * the super block for this name. + */ +#define MAXMNTLEN 28 + +#define MAXNAMLEN 63 + +#define FSMAGIC1 ('F' | 'S'<<8 | '<'<<16 | '<'<<24) +#define FSMAGIC2 ('>' | '>'<<8 | 'F'<<16 | 'S'<<24) + +typedef struct { + const char *filename; + int fd; + unsigned long seek; + int writable; + int dirty; /* sync needed */ + int modified; /* write_block was called */ + + unsigned isize; /* size in blocks of superblock + I list */ + unsigned fsize; /* size in blocks of entire volume */ + unsigned swapsz; /* size in blocks of swap area */ + unsigned nfree; /* number of in core free blocks (0-100) */ + unsigned free [NICFREE]; /* in core free blocks */ + unsigned ninode; /* number of in core I nodes (0-100) */ + unsigned inode [NICINOD]; /* in core free I nodes */ + unsigned flock; /* lock during free list manipulation */ + unsigned ilock; /* lock during I list manipulation */ + unsigned fmod; /* super block modified flag */ + unsigned ronly; /* mounted read-only flag */ + long utime; /* current date of last update */ + unsigned tfree; /* total free blocks */ + unsigned tinode; /* total free inodes */ + char fsmnt [MAXMNTLEN]; /* ordinary file mounted on */ + unsigned lasti; /* start place for circular search */ + unsigned nbehind; /* est # free inodes before s_lasti */ + unsigned flags; /* mount time flags */ +} fs_t; + +typedef struct { + fs_t *fs; + unsigned number; + int dirty; /* save needed */ + + unsigned short mode; /* file type and access mode */ +#define INODE_MODE_FMT 0170000 /* type of file */ +#define INODE_MODE_FCHR 020000 /* character special */ +#define INODE_MODE_FDIR 040000 /* directory */ +#define INODE_MODE_FBLK 060000 /* block special */ +#define INODE_MODE_FREG 0100000 /* regular */ +#define INODE_MODE_FLNK 0120000 /* symbolic link */ +#define INODE_MODE_FSOCK 0140000 /* socket */ +#define INODE_MODE_SUID 04000 /* set user id on execution */ +#define INODE_MODE_SGID 02000 /* set group id on execution */ +#define INODE_MODE_SVTX 01000 /* save swapped text even after use */ +#define INODE_MODE_READ 0400 /* read, write, execute permissions */ +#define INODE_MODE_WRITE 0200 +#define INODE_MODE_EXEC 0100 + + unsigned short nlink; /* directory entries */ + unsigned uid; /* owner */ + unsigned gid; /* group */ + unsigned long size; /* size */ + unsigned addr [7]; /* device addresses constituting file */ + unsigned flags; /* user defined flags */ +/* + * Super-user and owner changeable flags. + */ +#define USER_SETTABLE 0x00ff /* mask of owner changeable flags */ +#define USER_NODUMP 0x0001 /* do not dump file */ +#define USER_IMMUTABLE 0x0002 /* file may not be changed */ +#define USER_APPEND 0x0004 /* writes to file may only append */ +/* + * Super-user changeable flags. + */ +#define SYS_SETTABLE 0xff00 /* mask of superuser changeable flags */ +#define SYS_ARCHIVED 0x0100 /* file is archived */ +#define SYS_IMMUTABLE 0x0200 /* file may not be changed */ +#define SYS_APPEND 0x0400 /* writes to file may only append */ + + long atime; /* time last accessed */ + long mtime; /* time last modified */ + long ctime; /* time created */ +} fs_inode_t; + +typedef struct { + unsigned ino; + unsigned reclen; + unsigned namlen; + char name [MAXNAMLEN+1]; +} fs_dirent_t; + +typedef void (*fs_directory_scanner_t) (fs_inode_t *dir, + fs_inode_t *file, char *dirname, char *filename, void *arg); + +typedef struct { + fs_inode_t inode; + int writable; /* write allowed */ + unsigned long offset; /* current i/o offset */ +} fs_file_t; + +int fs_seek (fs_t *fs, unsigned long offset); +int fs_read8 (fs_t *fs, unsigned char *val); +int fs_read16 (fs_t *fs, unsigned short *val); +int fs_read32 (fs_t *fs, unsigned *val); +int fs_write8 (fs_t *fs, unsigned char val); +int fs_write16 (fs_t *fs, unsigned short val); +int fs_write32 (fs_t *fs, unsigned val); + +int fs_read (fs_t *fs, unsigned char *data, int bytes); +int fs_write (fs_t *fs, unsigned char *data, int bytes); + +int fs_open (fs_t *fs, const char *filename, int writable); +void fs_close (fs_t *fs); +int fs_sync (fs_t *fs, int force); +int fs_create (fs_t *fs, const char *filename, unsigned kbytes, + unsigned swap_kbytes); +int fs_check (fs_t *fs); +void fs_print (fs_t *fs, FILE *out); + +int fs_inode_get (fs_t *fs, fs_inode_t *inode, unsigned inum); +int fs_inode_save (fs_inode_t *inode, int force); +void fs_inode_clear (fs_inode_t *inode); +void fs_inode_truncate (fs_inode_t *inode); +void fs_inode_print (fs_inode_t *inode, FILE *out); +int fs_inode_read (fs_inode_t *inode, unsigned long offset, + unsigned char *data, unsigned long bytes); +int fs_inode_write (fs_inode_t *inode, unsigned long offset, + unsigned char *data, unsigned long bytes); +int fs_inode_alloc (fs_t *fs, fs_inode_t *inode); +int fs_inode_by_name (fs_t *fs, fs_inode_t *inode, char *name, + int op, int mode); +int inode_build_list (fs_t *fs); + +int fs_write_block (fs_t *fs, unsigned bnum, unsigned char *data); +int fs_read_block (fs_t *fs, unsigned bnum, unsigned char *data); +int fs_block_free (fs_t *fs, unsigned int bno); +int fs_block_alloc (fs_t *fs, unsigned int *bno); +int fs_indirect_block_free (fs_t *fs, unsigned int bno); +int fs_double_indirect_block_free (fs_t *fs, unsigned int bno); +int fs_triple_indirect_block_free (fs_t *fs, unsigned int bno); + +void fs_directory_scan (fs_inode_t *inode, char *dirname, + fs_directory_scanner_t scanner, void *arg); +void fs_dirent_pack (unsigned char *data, fs_dirent_t *dirent); +void fs_dirent_unpack (fs_dirent_t *dirent, unsigned char *data); + +int fs_file_create (fs_t *fs, fs_file_t *file, char *name, int mode); +int fs_file_open (fs_t *fs, fs_file_t *file, char *name, int wflag); +int fs_file_read (fs_file_t *file, unsigned char *data, + unsigned long bytes); +int fs_file_write (fs_file_t *file, unsigned char *data, + unsigned long bytes); +int fs_file_close (fs_file_t *file); diff --git a/tools/fsutil/check.c b/tools/fsutil/check.c new file mode 100644 index 0000000..cae91b7 --- /dev/null +++ b/tools/fsutil/check.c @@ -0,0 +1,1004 @@ +/* + * Check 2.xBSD filesystem. + * + * Copyright (C) 2006-2011 Serge Vakulenko, + * + * This file is part of RetroBSD project, which is distributed + * under the terms of the GNU General Public License (GPL). + * See the accompanying file "COPYING" for more details. + */ +#include +#include +#include +#include +#include +#include +#include "bsdfs.h" + +extern int verbose; + +#define MAXDUP 10 /* limit on dup blks (per inode) */ +#define MAXBAD 10 /* limit on bad blks (per inode) */ +#define DUP_LIST_SIZE 100 /* num of dup blocks to remember */ +#define LINK_LIST_SIZE 20 /* num zero link cnts to remember */ + +#define STATE_BITS 2 /* bits per inode state */ +#define STATE_MASK 3 /* mask for inode state */ +#define STATES_PER_BYTE 4 /* inode states per byte */ +#define USTATE 0 /* inode not allocated */ +#define FSTATE 1 /* inode is file */ +#define DSTATE 2 /* inode is directory */ +#define CLEAR 3 /* inode is to be cleared */ + +#define DATA 1 /* flags for scan_inode() */ +#define ADDR 0 + +#define ALTERD 010 /* values returned by scan functions */ +#define KEEPON 004 +#define SKIP 002 +#define STOP 001 + +#define outrange(fs,x) ((x) < (fs)->isize || (x) >= (fs)->fsize) + +/* block scan function, called by scan_inode for every file block */ +typedef int scanner_t (fs_inode_t *inode, unsigned blk, void *arg); + +static unsigned char buf_data [BSDFS_BSIZE]; /* buffer data for scan_directory */ +static unsigned buf_bno; /* buffer block number */ +static int buf_dirty; /* buffer data modified */ + +static unsigned dup_list [DUP_LIST_SIZE]; /* dup block table */ +static unsigned *dup_end; /* next entry in dup table */ +static unsigned *dup_multi; /* multiple dups part of table */ + +static unsigned bad_link_list [LINK_LIST_SIZE]; /* inos with zero link cnts */ +static unsigned *bad_link_end; /* next entry in table */ + +static char *block_map; /* primary blk allocation map */ +static char *free_map; /* secondary blk allocation map */ +static char *state_map; /* inode state table */ +static int *link_count; /* link count table */ + +static char pathname [256]; /* file path name for pass2 */ +static char *pathp; /* pointer to pathname position */ +static char *thisname; /* ptr to current pathname component */ + +static char *lost_found_name = "lost+found"; +static unsigned lost_found_inode; /* lost & found directory */ + +static int free_list_corrupted; /* corrupted free list */ +static int bad_blocks; /* num of bad blks seen (per inode) */ +static int dup_blocks; /* num of dup blks seen (per inode) */ + +static char *find_inode_name; /* searching for this name */ +static unsigned find_inode_result; /* result of inode search */ +static unsigned lost_inode; /* lost file to reconnect */ + +static unsigned long scan_filesize; /* file size, decremented during scan */ +static unsigned total_files; /* number of files seen */ + +static void set_inode_state (unsigned inum, int s) +{ + unsigned int byte, shift; + + byte = inum / STATES_PER_BYTE; + shift = inum % STATES_PER_BYTE * STATE_BITS; + state_map [byte] &= ~(STATE_MASK << shift); + state_map [byte] |= s << shift; +} + +static int inode_state (unsigned inum) +{ + unsigned int byte, shift; + + byte = inum / STATES_PER_BYTE; + shift = inum % STATES_PER_BYTE * STATE_BITS; + return (state_map [byte] >> shift) & STATE_MASK; +} + +static int block_is_busy (unsigned blk) +{ + return block_map [blk >> 3] & (1 << (blk & 7)); +} + +static void mark_block_busy (unsigned blk) +{ + block_map [blk >> 3] |= 1 << (blk & 7); +} + +static void mark_block_free (unsigned blk) +{ + block_map [blk >> 3] &= ~(1 << (blk & 7)); +} + +static void mark_free_list (unsigned blk) +{ + free_map [blk >> 3] |= 1 << (blk & 7); +} + +static int in_free_list (unsigned blk) +{ + return free_map [blk >> 3] & (1 << (blk & 7)); +} + +static void print_io_error (char *s, unsigned blk) +{ + printf ("\nCAN NOT %s: BLK %d\n", s, blk); +} + +static void buf_flush (fs_t *fs) +{ + if (buf_dirty && fs->writable) { +/*printf ("WRITE blk %d\n", buf_bno);*/ + if (! fs_write_block (fs, buf_bno, buf_data)) + print_io_error ("WRITE", buf_bno); + } + buf_dirty = 0; +} + +static int buf_get (fs_t *fs, unsigned blk) +{ + if (buf_bno == blk) + return 1; + buf_flush (fs); +/*printf ("read blk %d\n", blk);*/ + if (! fs_read_block (fs, blk, buf_data)) { + print_io_error ("READ", blk); + buf_bno = (unsigned)-1; + return 0; + } + buf_bno = blk; + return 1; +} + +/* + * Scan recursively the indirect block of the inode, + * and for every block call the given function. + */ +static int scan_indirect_block (fs_inode_t *inode, unsigned blk, + int double_indirect, int flg, scanner_t *func, void *arg) +{ + unsigned nb; + int ret, i; + unsigned char data [BSDFS_BSIZE]; + +/*printf ("check %siblock %d: \n", double_indirect > 1 ? "triple " : double_indirect ? "double " : "", blk);*/ + if (flg == ADDR) { + ret = (*func) (inode, blk, arg); + if (! (ret & KEEPON)) + return ret; + } + if (outrange (inode->fs, blk)) /* protect thyself */ + return SKIP; + + if (! fs_read_block (inode->fs, blk, data)) { + print_io_error ("READ", blk); + return SKIP; + } + for (i = 0; i < BSDFS_BSIZE; i+=2) { + nb = data [i+1] << 8 | data [i]; + if (nb) { + if (double_indirect) + ret = scan_indirect_block (inode, nb, + double_indirect - 1, flg, func, arg); + else + ret = (*func) (inode, nb, arg); + + if (ret & STOP) + return ret; + } + } + return KEEPON; +} + +/* + * Scan recursively the block list of the inode, + * and for every block call the given function. + * Option flg: + * - when ADDR - call func for both data and indirect blocks + * - when DATA - only data blocks are processed + */ +static int scan_inode (fs_inode_t *inode, int flg, scanner_t *func, void *arg) +{ + unsigned *ap; + int ret; + +/*printf ("check inode %d: %#o\n", inode->number, inode->mode);*/ + if (((inode->mode & INODE_MODE_FMT) == INODE_MODE_FBLK) || + ((inode->mode & INODE_MODE_FMT) == INODE_MODE_FCHR)) + return KEEPON; + scan_filesize = inode->size; + + /* Check direct blocks. */ + for (ap = inode->addr; ap < &inode->addr[NDADDR]; ap++) { + if (*ap) { + ret = (*func) (inode, *ap, arg); + if (ret & STOP) + return ret; + } + } + if (inode->addr[NADDR-3]) { + /* Check the indirect block. */ + ret = scan_indirect_block (inode, inode->addr[NADDR-3], 0, + flg, func, arg); + if (ret & STOP) + return (ret); + } + if (inode->addr[NADDR-2]) { + /* Check the double indirect block. */ + ret = scan_indirect_block (inode, inode->addr[NADDR-2], 1, + flg, func, arg); + if (ret & STOP) + return (ret); + } + if (inode->addr[NADDR-1]) { + /* Check the last (triple indirect) block. */ + ret = scan_indirect_block (inode, inode->addr[NADDR-1], 2, + flg, func, arg); + if (ret & STOP) + return (ret); + } + return KEEPON; +} + +static void print_block_error (char *s, unsigned blk, unsigned inum) +{ + printf ("%u %s I=%u\n", blk, s, inum); +} + +/* + * Called once for every block of every file. + * Mark blocks as busy on block map. + * If duplicates are found, put them into dup_list. + */ +static int pass1 (fs_inode_t *inode, unsigned blk, void *arg) +{ + unsigned *dlp; + unsigned *blocks = arg; + +/*printf ("pass1 inode %d block %d: \n", inode->number, blk);*/ + if (outrange (inode->fs, blk)) { + print_block_error ("BAD", blk, inode->number); + set_inode_state (inode->number, CLEAR); /* mark for possible clearing */ + if (++bad_blocks >= MAXBAD) { + printf ("EXCESSIVE BAD BLKS I=%u\n", inode->number); + return STOP; + } + return SKIP; + } + if (block_is_busy (blk)) { + print_block_error ("DUP", blk, inode->number); + set_inode_state (inode->number, CLEAR); /* mark for possible clearing */ + if (++dup_blocks >= MAXDUP) { + printf ("EXCESSIVE DUP BLKS I=%u\n", inode->number); + return STOP; + } + if (dup_end >= &dup_list[DUP_LIST_SIZE]) { + printf ("DUP TABLE OVERFLOW.\n"); + return STOP; + } + for (dlp = dup_list; dlp < dup_multi; dlp++) { + if (*dlp == blk) { + *dup_end++ = blk; + break; + } + } + if (dlp >= dup_multi) { + *dup_end++ = *dup_multi; + *dup_multi++ = blk; + } + } else { + if (blocks) + ++*blocks; + mark_block_busy (blk); + } + return KEEPON; +} + +static int pass1b (fs_inode_t *inode, unsigned blk, void *arg) +{ + unsigned *dlp; + + if (outrange (inode->fs, blk)) + return SKIP; + for (dlp = dup_list; dlp < dup_multi; dlp++) { + if (*dlp == blk) { + print_block_error ("DUP", blk, inode->number); + set_inode_state (inode->number, CLEAR); /* mark for possible clearing */ + *dlp = *--dup_multi; + *dup_multi = blk; + return (dup_multi == dup_list ? STOP : KEEPON); + } + } + return KEEPON; +} + +/* + * Read directory, and for every entry call given function. + * If function altered the contents of entry, then write it back. + */ +static int scan_directory (fs_inode_t *inode, unsigned blk, void *arg) +{ + fs_dirent_t direntry; + unsigned char *dirp; + int (*func) () = arg; + int n; + +/*printf ("scan_directory: I=%d, blk=%d\n", inode->number, blk);*/ + if (outrange (inode->fs, blk)) { + scan_filesize -= BSDFS_BSIZE; + return SKIP; + } + dirp = buf_data; + while (dirp < &buf_data[BSDFS_BSIZE] && scan_filesize > 0) { + if (! buf_get (inode->fs, blk)) { + scan_filesize -= (&buf_data[BSDFS_BSIZE] - dirp); + return SKIP; + } + fs_dirent_unpack (&direntry, dirp); + if (direntry.reclen == 0) + break; + + /* For every directory entry, call handler. */ + n = (*func) (inode->fs, &direntry); + + if (n & ALTERD) { + if (buf_get (inode->fs, blk)) { + fs_dirent_pack (dirp, &direntry); + buf_dirty = 1; + } else + n &= ~ALTERD; + } + if (n & STOP) + return n; + dirp += direntry.reclen; + scan_filesize -= direntry.reclen; + } + return (scan_filesize > 0) ? KEEPON : STOP; +} + +static void print_inode (fs_inode_t *inode) +{ + char *p; + + printf (" I=%u ", inode->number); + printf (" OWNER=%d ", inode->uid); + printf ("MODE=%o\n", inode->mode); + printf ("SIZE=%ld ", inode->size); + p = ctime (&inode->mtime); + printf ("MTIME=%12.12s %4.4s\n", p+4, p+20); +} + +static void print_dir_error (fs_t *fs, unsigned inum, char *s) +{ + fs_inode_t inode; + + if (! fs_inode_get (fs, &inode, inum)) { + printf ("%s I=%u\nNAME=%s\n", s, inum, pathname); + return; + } + printf ("%s ", s); + print_inode (&inode); + printf ("%s=%s\n", ((inode.mode & INODE_MODE_FMT) == + INODE_MODE_FDIR) ? "DIR" : "FILE", pathname); +} + +static void scan_pass2 (fs_t *fs, unsigned inum); + +/* + * Clear directory entries which refer to duplicated or unallocated inodes. + * Decrement link counters. + */ +static int pass2 (fs_t *fs, fs_dirent_t *dirp) +{ + int inum, ret = KEEPON; + fs_inode_t inode; + + inum = dirp->ino; + if (inum == 0) + return KEEPON; + + /* Copy file name from dirp to pathp */ + thisname = pathp; + strcpy (pathp, dirp->name); + pathp += strlen (pathp); +/*printf ("%s %d\n", pathname, inum);*/ + if (inum > (fs->isize - 1) * BSDFS_INODES_PER_BLOCK || + inum < BSDFS_ROOT_INODE) + print_dir_error (fs, inum, "I OUT OF RANGE"); + else { +again: switch (inode_state (inum)) { + case USTATE: + print_dir_error (fs, inum, "UNALLOCATED"); + if (fs->writable) { + dirp->ino = 0; + ret |= ALTERD; + break; + } + break; + case CLEAR: + print_dir_error (fs, inum, "DUP/BAD"); + if (fs->writable) { + dirp->ino = 0; + ret |= ALTERD; + break; + } + if (! fs_inode_get (fs, &inode, inum)) + break; + set_inode_state (inum, ((inode.mode & INODE_MODE_FMT) == + INODE_MODE_FDIR) ? DSTATE : FSTATE); + goto again; + case FSTATE: + --link_count [inum]; + break; + case DSTATE: + --link_count [inum]; + scan_pass2 (fs, inum); + } + } + pathp = thisname; + return ret; +} + +/* + * Traverse directory tree. Call pass2 for every directory entry. + * Keep current file name in 'pathname'. + */ +static void scan_pass2 (fs_t *fs, unsigned inum) +{ + fs_inode_t inode; + char *savname; + unsigned long savsize; + + set_inode_state (inum, FSTATE); + if (! fs_inode_get (fs, &inode, inum)) + return; + *pathp++ = '/'; + savname = thisname; + savsize = scan_filesize; + scan_inode (&inode, DATA, scan_directory, pass2); + scan_filesize = savsize; + thisname = savname; + *--pathp = 0; +} + +/* + * Find inode number by name. + * The name is in 'find_inode_name'. + * Put resulting inode number into 'find_inode_result'. + */ +static int find_inode (fs_t *fs, fs_dirent_t *dirp) +{ + if (dirp->ino == 0) + return KEEPON; + if (strcmp (find_inode_name, dirp->name) == 0) { + if (dirp->ino >= BSDFS_ROOT_INODE && + dirp->ino < (fs->isize-1) * BSDFS_INODES_PER_BLOCK) + find_inode_result = dirp->ino; + return STOP; + } + return KEEPON; +} + +/* + * Find a free slot and make link to 'lost_inode'. + * Create filename of a kind "#01234". + */ +static int make_lost_entry (fs_t *fs, fs_dirent_t *dirp) +{ + if (dirp->ino) + return KEEPON; + dirp->ino = lost_inode; + sprintf (dirp->name, "#%05d", dirp->ino); + return ALTERD | STOP; +} + +/* + * For entry ".." set inode number to 'lost_found_inode'. + */ +static int dotdot_to_lost_found (fs_t *fs, fs_dirent_t *dirp) +{ + if (dirp->name[0] == '.' && dirp->name[1] == '.' && + dirp->name[2] == 0) { + dirp->ino = lost_found_inode; + return ALTERD | STOP; + } + return KEEPON; +} + +/* + * Return lost+found inode number. + * TODO: create /lost+found when not available. + */ +static unsigned find_lost_found (fs_t *fs) +{ + fs_inode_t root; + + /* Find lost_found directory inode number. */ + if (! fs_inode_get (fs, &root, BSDFS_ROOT_INODE)) + return 0; + find_inode_name = lost_found_name; + find_inode_result = 0; + scan_inode (&root, DATA, scan_directory, find_inode); + return find_inode_result; +} + +/* + * Restore a link to parent directory - "..". + */ +static int move_to_lost_found (fs_inode_t *inode) +{ + fs_inode_t lost_found; + + printf ("UNREF %s ", ((inode->mode & INODE_MODE_FMT) == + INODE_MODE_FDIR) ? "DIR" : "FILE"); + print_inode (inode); + if (! inode->fs->writable) + return 0; + + /* Get lost+found inode. */ + if (lost_found_inode == 0) { + /* Find lost_found directory inode number. */ + lost_found_inode = find_lost_found (inode->fs); + if (! lost_found_inode) { + printf ("SORRY. NO lost+found DIRECTORY\n\n"); + return 0; + } + } + if (! fs_inode_get (inode->fs, &lost_found, lost_found_inode) || + ((lost_found.mode & INODE_MODE_FMT) != INODE_MODE_FDIR) || + inode_state (lost_found_inode) != FSTATE) { + printf ("SORRY. NO lost+found DIRECTORY\n\n"); + return 0; + } + if (lost_found.size % BSDFS_BSIZE) { + lost_found.size = (lost_found.size + BSDFS_BSIZE - 1) / + BSDFS_BSIZE * BSDFS_BSIZE; + if (! fs_inode_save (&lost_found, 1)) { + printf ("SORRY. ERROR WRITING lost+found I-NODE\n\n"); + return 0; + } + } + + /* Put a file to lost+found. */ + lost_inode = inode->number; + if ((scan_inode (&lost_found, DATA, scan_directory, make_lost_entry) & + ALTERD) == 0) { + printf ("SORRY. NO SPACE IN lost+found DIRECTORY\n\n"); + return 0; + } + --link_count [inode->number]; + + if ((inode->mode & INODE_MODE_FMT) == INODE_MODE_FDIR) { + /* For ".." set inode number to lost_found_inode. */ + scan_inode (inode, DATA, scan_directory, dotdot_to_lost_found); + if (fs_inode_get (inode->fs, &lost_found, lost_found_inode)) { + lost_found.nlink++; + ++link_count [lost_found.number]; + if (! fs_inode_save (&lost_found, 1)) { + printf ("SORRY. ERROR WRITING lost+found I-NODE\n\n"); + return 0; + } + } + printf ("DIR I=%u CONNECTED.\n\n", inode->number); + } + return 1; +} + +/* + * Mark the block as free. Remove it from dup list. + */ +static int pass4 (fs_inode_t *inode, unsigned blk, void *arg) +{ + unsigned *dlp; + unsigned *blocks = arg; + + if (outrange (inode->fs, blk)) + return SKIP; + if (block_is_busy (blk)) { + /* Free block. */ + for (dlp = dup_list; dlp < dup_end; dlp++) + if (*dlp == blk) { + *dlp = *--dup_end; + return KEEPON; + } + mark_block_free (blk); + if (blocks) + --*blocks; + } + return KEEPON; +} + +/* + * Clear the inode, mark it's blocks as free. + */ +static void clear_inode (fs_t *fs, unsigned inum, char *msg) +{ + fs_inode_t inode; + + if (! fs_inode_get (fs, &inode, inum)) + return; + if (msg) { + printf ("%s %s", msg, ((inode.mode & INODE_MODE_FMT) == + INODE_MODE_FDIR) ? "DIR" : "FILE"); + print_inode (&inode); + } + if (fs->writable) { + total_files--; + scan_inode (&inode, ADDR, pass4, 0); + fs_inode_clear (&inode); + fs_inode_save (&inode, 1); + } +} + +/* + * Fix the link count of the inode. + * If no links - move it to lost+found. + */ +static void adjust_link_count (fs_t *fs, unsigned inum, unsigned lcnt) +{ + fs_inode_t inode; + + if (! fs_inode_get (fs, &inode, inum)) + return; + if (inode.nlink == lcnt) { + /* No links to file - move to lost+found. */ + if (! move_to_lost_found (&inode)) + clear_inode (fs, inum, 0); + } else { + printf ("LINK COUNT %s", (lost_found_inode==inum) ? lost_found_name : + (((inode.mode & INODE_MODE_FMT) == INODE_MODE_FDIR) ? + "DIR" : "FILE")); + print_inode (&inode); + printf ("COUNT %d SHOULD BE %d\n", + inode.nlink, inode.nlink - lcnt); + if (fs->writable) { + inode.nlink -= lcnt; + fs_inode_save (&inode, 1); + } + } +} + +/* + * Called from check_free_list() for every block in free list. + * Count free blocks, detect duplicates. + */ +static int pass5 (fs_t *fs, unsigned blk, unsigned *free_blocks) +{ + if (outrange (fs, blk)) { + free_list_corrupted = 1; + if (++bad_blocks >= MAXBAD) { + printf ("EXCESSIVE BAD BLKS IN FREE LIST.\n"); + return STOP; + } + return SKIP; + } + if (in_free_list (blk)) { + free_list_corrupted = 1; + if (++dup_blocks >= DUP_LIST_SIZE) { + printf ("EXCESSIVE DUP BLKS IN FREE LIST.\n"); + return STOP; + } + } else { + ++*free_blocks; + mark_free_list (blk); + } + return KEEPON; +} + +/* + * Scan a free block list and return a number of free blocks. + * If the list is corrupted, set 'free_list_corrupted' flag. + */ +static unsigned check_free_list (fs_t *fs) +{ + unsigned *ap, *base; + unsigned free_blocks, nfree; + unsigned data [BSDFS_BSIZE / 4]; + unsigned list [NICFREE]; + int i; + + if (fs->nfree == 0) + return 0; + free_blocks = 0; + nfree = fs->nfree; + base = fs->free; + for (;;) { + if (nfree <= 0 || nfree > NICFREE) { + printf ("BAD FREEBLK COUNT\n"); + free_list_corrupted = 1; + break; + } + ap = base + nfree; + while (--ap > base) { + if (pass5 (fs, *ap, &free_blocks) == STOP) + return free_blocks; + } + if (*ap == 0 || pass5 (fs, *ap, &free_blocks) != KEEPON) + break; + if (! fs_read_block (fs, *ap, (unsigned char*) data)) { + print_io_error ("READ", *ap); + break; + } + nfree = data[0]; + for (i=0; ininode; i++) { + inum = fs->inode[i]; + if (inode_state (inum) != USTATE) { + printf ("ALLOCATED INODE(S) IN IFREE LIST\n"); + if (fs->writable) { + fs->ninode = i - 1; + while (i < NICINOD) + fs->inode [i++] = 0; + fs->dirty = 1; + } + return; + } + } +} + +/* + * Build a free block list from scratch. + */ +static unsigned make_free_list (fs_t *fs) +{ + unsigned free_blocks, n; + + fs->nfree = 0; + fs->flock = 0; + fs->fmod = 0; + fs->ilock = 0; + fs->ronly = 0; + fs->dirty = 1; + free_blocks = 0; + + /* Build a list of free blocks */ + fs_block_free (fs, 0); + for (n = fs->fsize - 1; n >= fs->isize; n--) { + if (block_is_busy (n)) + continue; + ++free_blocks; + if (! fs_block_free (fs, n)) + return 0; + } + return free_blocks; +} + +/* + * Check filesystem for errors. + * When readonly - just check and print errors. + * If the system is open on read/write - fix errors. + */ +int fs_check (fs_t *fs) +{ + fs_inode_t inode; + int n; + unsigned inum; + unsigned block_map_size; /* number of free blocks */ + unsigned free_blocks; /* number of free blocks */ + unsigned used_blocks; /* number of blocks used */ + unsigned last_allocated_inode; /* hiwater mark of inodes */ + + if (fs->isize >= fs->fsize) { + printf ("Bad filesystem size: total %d blocks with %d inode blocks\n", + fs->fsize, fs->isize); + return 0; + } + free_list_corrupted = 0; + total_files = 0; + used_blocks = 0; + dup_multi = dup_end = &dup_list[0]; + bad_link_end = &bad_link_list[0]; + lost_found_inode = 0; + buf_dirty = 0; + buf_bno = (unsigned) -1; + + /* Allocate memory. */ + block_map_size = (fs->fsize + 7) / 8; + block_map = calloc (block_map_size, sizeof (*block_map)); + state_map = calloc (((fs->isize-1) * BSDFS_INODES_PER_BLOCK + + STATES_PER_BYTE) / STATES_PER_BYTE, sizeof (*state_map)); + link_count = calloc ((fs->isize-1) * BSDFS_INODES_PER_BLOCK + 1, + sizeof (*link_count)); + if (! block_map || ! state_map || ! link_count) { + printf ("Cannot allocate memory\n"); +fatal: if (block_map) + free (block_map); + if (state_map) + free (state_map); + if (link_count) + free (link_count); + return 0; + } + + printf ("** Phase 1 - Check Blocks and Sizes\n"); + last_allocated_inode = 0; + for (inum = 1; inum <= (fs->isize-1) * BSDFS_INODES_PER_BLOCK; inum++) { + if (! fs_inode_get (fs, &inode, inum)) + continue; + if (inode.mode & INODE_MODE_FMT) { +/*printf ("inode %d: %#o\n", inode.number, inode.mode);*/ + last_allocated_inode = inum; + total_files++; + link_count[inum] = inode.nlink; + if (link_count[inum] <= 0) { + if (bad_link_end < &bad_link_list[LINK_LIST_SIZE]) + *bad_link_end++ = inum; + else { + printf ("LINK COUNT TABLE OVERFLOW\n"); + } + } + set_inode_state (inum, ((inode.mode & INODE_MODE_FMT) == + INODE_MODE_FDIR) ? DSTATE : FSTATE); + bad_blocks = dup_blocks = 0; + scan_inode (&inode, ADDR, pass1, &used_blocks); + n = inode_state (inum); + if (n == DSTATE || n == FSTATE) { + if ((inode.mode & INODE_MODE_FMT) == INODE_MODE_FDIR && + (inode.size % 4) != 0) { + printf ("DIRECTORY MISALIGNED I=%u\n\n", + inode.number); + } + } + } + else if (inode.mode != 0) { + printf ("PARTIALLY ALLOCATED INODE I=%u\n", inum); + if (fs->writable) + fs_inode_clear (&inode); + } + fs_inode_save (&inode, 0); + } + if (dup_end != &dup_list[0]) { + printf ("** Phase 1b - Rescan For More DUPS\n"); + for (inum = 1; inum <= last_allocated_inode; inum++) { + if (inode_state (inum) == USTATE) + continue; + if (! fs_inode_get (fs, &inode, inum)) + continue; + if (scan_inode (&inode, ADDR, pass1b, 0) & STOP) + break; + } + } + + printf ("** Phase 2 - Check Pathnames\n"); + thisname = pathp = pathname; + switch (inode_state (BSDFS_ROOT_INODE)) { + case USTATE: + printf ("ROOT INODE UNALLOCATED. TERMINATING.\n"); + goto fatal; + case FSTATE: + printf ("ROOT INODE NOT DIRECTORY\n"); + if (! fs->writable) + goto fatal; + if (! fs_inode_get (fs, &inode, BSDFS_ROOT_INODE)) + goto fatal; + inode.mode &= ~INODE_MODE_FMT; + inode.mode |= INODE_MODE_FDIR; + fs_inode_save (&inode, 1); + set_inode_state (BSDFS_ROOT_INODE, DSTATE); + case DSTATE: + scan_pass2 (fs, BSDFS_ROOT_INODE); + break; + case CLEAR: + printf ("DUPS/BAD IN ROOT INODE\n"); + set_inode_state (BSDFS_ROOT_INODE, DSTATE); + scan_pass2 (fs, BSDFS_ROOT_INODE); + } + + printf ("** Phase 3 - Check Connectivity\n"); + for (inum = BSDFS_ROOT_INODE; inum <= last_allocated_inode; inum++) { + if (inode_state (inum) == DSTATE) { + unsigned ino; + + find_inode_name = ".."; + ino = inum; + do { + if (! fs_inode_get (fs, &inode, ino)) + break; + find_inode_result = 0; + scan_inode (&inode, DATA, scan_directory, find_inode); + if (find_inode_result == 0) { + /* Parent link lost. */ + if (move_to_lost_found (&inode)) { + thisname = pathp = pathname; + *pathp++ = '?'; + scan_pass2 (fs, ino); + } + break; + } + ino = find_inode_result; + } while (inode_state (ino) == DSTATE); + } + } + + printf ("** Phase 4 - Check Reference Counts\n"); + for (inum = BSDFS_ROOT_INODE; inum <= last_allocated_inode; inum++) { + switch (inode_state (inum)) { + case FSTATE: + n = link_count [inum]; + if (n) + adjust_link_count (fs, inum, n); + else { + unsigned *blp; + + for (blp = bad_link_list; blp < bad_link_end; blp++) + if (*blp == inum) { + clear_inode (fs, inum, "UNREF"); + break; + } + } + break; + case DSTATE: + clear_inode (fs, inum, "UNREF"); + break; + case CLEAR: + clear_inode (fs, inum, "BAD/DUP"); + } + } + buf_flush (fs); + + printf ("** Phase 5 - Check Free List\n"); + free (link_count); + check_free_inode_list (fs); + free (state_map); + bad_blocks = dup_blocks = 0; + free_map = calloc (block_map_size, sizeof (*free_map)); + if (! free_map) { + printf ("NO MEMORY TO CHECK FREE LIST\n"); + free_list_corrupted = 1; + free_blocks = 0; + } else { + memcpy (free_map, block_map, block_map_size); + free_blocks = check_free_list (fs); + free (free_map); + } + if (bad_blocks) + printf ("%d BAD BLKS IN FREE LIST\n", bad_blocks); + if (dup_blocks) + printf ("%d DUP BLKS IN FREE LIST\n", dup_blocks); + if (free_list_corrupted == 0) { + if (used_blocks + free_blocks != fs->fsize - fs->isize) { + printf ("%d BLK(S) MISSING\n", fs->fsize - + fs->isize - used_blocks - free_blocks); + free_list_corrupted = 1; + } + } + if (free_list_corrupted) { + printf ("BAD FREE LIST\n"); + if (! fs->writable) + free_list_corrupted = 0; + } + + if (free_list_corrupted) { + printf ("** Phase 6 - Salvage Free List\n"); + free_blocks = make_free_list (fs); + } + + printf ("%d files %d blocks %d free\n", + total_files, used_blocks, free_blocks); + if (fs->modified) { + time (&fs->utime); + fs->dirty = 1; + } + buf_flush (fs); + fs_sync (fs, 0); + if (fs->modified) + printf ("\n***** FILE SYSTEM WAS MODIFIED *****\n"); + + free (block_map); + return 1; +} diff --git a/tools/fsutil/create.c b/tools/fsutil/create.c new file mode 100644 index 0000000..ad3eea9 --- /dev/null +++ b/tools/fsutil/create.c @@ -0,0 +1,386 @@ +/* + * Create new 2.xBSD filesystem. + * + * Copyright (C) 2006-2011 Serge Vakulenko, + * + * This file is part of RetroBSD project, which is distributed + * under the terms of the GNU General Public License (GPL). + * See the accompanying file "COPYING" for more details. + */ +#include +#include +#include +#include +#include +#include +#include "bsdfs.h" + +extern int verbose; + +int inode_build_list (fs_t *fs) +{ + fs_inode_t inode; + unsigned int inum, total_inodes; + + total_inodes = (fs->isize - 1) * BSDFS_INODES_PER_BLOCK; + for (inum = 1; inum <= total_inodes; inum++) { + if (! fs_inode_get (fs, &inode, inum)) + return 0; + if (inode.mode == 0) { + fs->inode [fs->ninode++] = inum; + if (fs->ninode >= NICINOD) + break; + } + } + return 1; +} + +static int create_inode1 (fs_t *fs) +{ + fs_inode_t inode; + + memset (&inode, 0, sizeof(inode)); + inode.mode = INODE_MODE_FREG; + inode.fs = fs; + inode.number = 1; + if (! fs_inode_save (&inode, 1)) + return 0; + fs->tinode--; + return 1; +} + +static int create_root_directory (fs_t *fs) +{ + fs_inode_t inode; + unsigned char buf [BSDFS_BSIZE]; + unsigned int bno; + + memset (&inode, 0, sizeof(inode)); + inode.mode = INODE_MODE_FDIR | 0777; + inode.fs = fs; + inode.number = BSDFS_ROOT_INODE; + inode.size = BSDFS_BSIZE; + inode.flags = 0; + + time (&inode.ctime); + time (&inode.atime); + time (&inode.mtime); + + /* directory - put in extra links */ + memset (buf, 0, sizeof(buf)); + buf[0] = inode.number; + buf[1] = inode.number >> 8; + buf[2] = inode.number >> 16; + buf[3] = inode.number >> 24; + buf[4] = 12; + buf[5] = 12 >> 8; + buf[6] = 1; + buf[7] = 1 >> 8; + buf[8] = '.'; + buf[9] = 0; + buf[10] = 0; + buf[11] = 0; + + buf[12+0] = BSDFS_ROOT_INODE; + buf[12+1] = BSDFS_ROOT_INODE >> 8; + buf[12+2] = BSDFS_ROOT_INODE >> 16; + buf[12+3] = BSDFS_ROOT_INODE >> 24; + buf[12+4] = 12; + buf[12+5] = 12 >> 8; + buf[12+6] = 2; + buf[12+7] = 2 >> 8; + buf[12+8] = '.'; + buf[12+9] = '.'; + buf[12+10] = 0; + buf[12+11] = 0; + + buf[24+0] = BSDFS_LOSTFOUND_INODE; + buf[24+1] = BSDFS_LOSTFOUND_INODE >> 8; + buf[24+2] = BSDFS_LOSTFOUND_INODE >> 16; + buf[24+3] = BSDFS_LOSTFOUND_INODE >> 24; + buf[24+4] = (unsigned char) (BSDFS_BSIZE - 12 - 12); + buf[24+5] = (BSDFS_BSIZE - 12 - 12) >> 8; + buf[24+6] = 10; + buf[24+7] = 10 >> 8; + memcpy (&buf[24+8], "lost+found\0\0", 12); + + if (fs->swapsz != 0) { + buf[24+4] = 20; + buf[24+5] = 20 >> 8; + buf[44+0] = BSDFS_SWAP_INODE; + buf[44+1] = BSDFS_SWAP_INODE >> 8; + buf[44+2] = BSDFS_SWAP_INODE >> 16; + buf[44+3] = BSDFS_SWAP_INODE >> 24; + buf[44+4] = (unsigned char) (BSDFS_BSIZE - 12 - 12 - 20); + buf[44+5] = (BSDFS_BSIZE - 12 - 12 - 20) >> 8; + buf[44+6] = 4; + buf[44+7] = 4 >> 8; + memcpy (&buf[44+8], "swap\0\0\0\0", 8); + } + inode.nlink = 3; + + if (! fs_block_alloc (fs, &bno)) + return 0; + if (! fs_write_block (fs, bno, buf)) + return 0; + inode.addr[0] = bno; + + if (! fs_inode_save (&inode, 1)) + return 0; + fs->tinode--; + return 1; +} + +static int create_lost_found_directory (fs_t *fs) +{ + fs_inode_t inode; + unsigned char buf [BSDFS_BSIZE]; + unsigned int bno; + + memset (&inode, 0, sizeof(inode)); + inode.mode = INODE_MODE_FDIR | 0777; + inode.fs = fs; + inode.number = BSDFS_LOSTFOUND_INODE; + inode.size = BSDFS_BSIZE; + inode.flags = 0; + + time (&inode.ctime); + time (&inode.atime); + time (&inode.mtime); + + /* directory - put in extra links */ + memset (buf, 0, sizeof(buf)); + buf[0] = inode.number; + buf[1] = inode.number >> 8; + buf[2] = inode.number >> 16; + buf[3] = inode.number >> 24; + buf[4] = 12; + buf[5] = 12 >> 8; + buf[6] = 1; + buf[7] = 1 >> 8; + buf[8] = '.'; + buf[9] = 0; + buf[10] = 0; + buf[11] = 0; + + buf[12+0] = BSDFS_ROOT_INODE; + buf[12+1] = BSDFS_ROOT_INODE >> 8; + buf[12+2] = BSDFS_ROOT_INODE >> 16; + buf[12+3] = BSDFS_ROOT_INODE >> 24; + buf[12+4] = (unsigned char) (BSDFS_BSIZE - 12); + buf[12+5] = (BSDFS_BSIZE - 12) >> 8; + buf[12+6] = 2; + buf[12+7] = 2 >> 8; + buf[12+8] = '.'; + buf[12+9] = '.'; + buf[12+10] = 0; + buf[12+11] = 0; + + inode.nlink = 2; + + if (! fs_block_alloc (fs, &bno)) + return 0; + if (! fs_write_block (fs, bno, buf)) + return 0; + inode.addr[0] = bno; + + if (! fs_inode_save (&inode, 1)) + return 0; + fs->tinode--; + return 1; +} + +static void map_block_swap (fs_inode_t *inode, unsigned lbn) +{ + unsigned block [BSDFS_BSIZE / 4]; + unsigned int bn, indir, newb, shift, i, j; + + /* + * Blocks 0..NADDR-3 are direct blocks. + */ + if (lbn < NADDR-3) { + /* small file algorithm */ + inode->addr[lbn] = inode->fs->isize + lbn; + return; + } + + /* + * Addresses NADDR-3, NADDR-2, and NADDR-1 + * have single, double, triple indirect blocks. + * The first step is to determine + * how many levels of indirection. + */ + shift = 0; + i = 1; + bn = lbn - (NADDR-3); + for (j=3; ; j--) { + if (j == 0) { + fprintf (stderr, "swap: too large size\n"); + exit (-1); + } + shift += NSHIFT; + i <<= NSHIFT; + if (bn < i) + break; + bn -= i; + } + + /* + * Fetch the first indirect block. + */ + indir = inode->addr [NADDR-j]; + if (indir == 0) { + if (! fs_block_alloc (inode->fs, &indir)) { +alloc_error: fprintf (stderr, "swap: cannot allocate indirect block\n"); + exit (-1); + } + if (verbose) + printf ("swap: allocate indirect block %d (j=%d)\n", indir, j); + memset (block, 0, BSDFS_BSIZE); + if (! fs_write_block (inode->fs, indir, (unsigned char*) block)) { +write_error: fprintf (stderr, "swap: cannot write indirect block %d\n", indir); + exit (-1); + } + inode->addr [NADDR-j] = indir; + } + + /* + * Fetch through the indirect blocks + */ + for (; ; j++) { + if (! fs_read_block (inode->fs, indir, (unsigned char*) block)) { + fprintf (stderr, "swap: cannot read indirect block %d\n", indir); + exit (-1); + } + shift -= NSHIFT; + i = (bn >> shift) & NMASK; + if (j == 3) { + block[i] = inode->fs->isize + lbn; + if (! fs_write_block (inode->fs, indir, (unsigned char*) block)) + goto write_error; + return; + } + if (block[i] != 0) { + indir = block [i]; + continue; + } + /* Allocate new indirect block. */ + if (! fs_block_alloc (inode->fs, &newb)) + goto alloc_error; + if (verbose) + printf ("swap: allocate new block %d (j=%d)\n", newb, j); + block[i] = newb; + if (! fs_write_block (inode->fs, indir, (unsigned char*) block)) + goto write_error; + memset (block, 0, BSDFS_BSIZE); + if (! fs_write_block (inode->fs, newb, (unsigned char*) block)) { + fprintf (stderr, "swap: cannot write block %d\n", newb); + exit (-1); + } + indir = newb; + } +} + +static int create_swap_file (fs_t *fs) +{ + fs_inode_t inode; + unsigned lbn; + + memset (&inode, 0, sizeof(inode)); + inode.mode = INODE_MODE_FREG | 0400; + inode.fs = fs; + inode.number = BSDFS_SWAP_INODE; + inode.size = fs->swapsz * BSDFS_BSIZE; + inode.flags = /*SYS_IMMUTABLE |*/ USER_IMMUTABLE | USER_NODUMP; + inode.nlink = 1; + inode.dirty = 1; + + time (&inode.ctime); + time (&inode.atime); + time (&inode.mtime); + + for (lbn=0; lbnswapsz; lbn++) + map_block_swap (&inode, lbn); + + if (! fs_inode_save (&inode, 0)) { + fprintf (stderr, "swap: cannot save file inode\n"); + return 0; + } + return 1; +} + +int fs_create (fs_t *fs, const char *filename, unsigned kbytes, + unsigned swap_kbytes) +{ + int n; + unsigned char buf [BSDFS_BSIZE]; + off_t bytes, offset; + + memset (fs, 0, sizeof (*fs)); + fs->filename = filename; + fs->seek = 0; + + fs->fd = open (fs->filename, O_CREAT | O_RDWR, 0666); + if (fs->fd < 0) + return 0; + fs->writable = 1; + + /* get total disk size + * and inode block size */ + bytes = (off_t) kbytes * 1024ULL; + fs->fsize = bytes / BSDFS_BSIZE; + fs->isize = 1 + (fs->fsize / 16 + BSDFS_INODES_PER_BLOCK - 1) / + BSDFS_INODES_PER_BLOCK; + if (fs->isize < 2) + return 0; + + /* make sure the file is of proper size */ + offset = lseek (fs->fd, bytes-1, SEEK_SET); + if (offset != bytes-1) + return 0; + if (write (fs->fd, "", 1) != 1) { + perror ("write"); + return 0; + } + lseek (fs->fd, 0, SEEK_SET); + + /* build a list of free blocks */ + fs->swapsz = swap_kbytes * 1024 / BSDFS_BSIZE; + fs_block_free (fs, 0); + for (n = fs->fsize - 1; n >= fs->isize + fs->swapsz; n--) + if (! fs_block_free (fs, n)) + return 0; + + /* initialize inodes */ + memset (buf, 0, BSDFS_BSIZE); + if (! fs_seek (fs, BSDFS_BSIZE)) + return 0; + for (n=1; n < fs->isize; n++) { + if (! fs_write (fs, buf, BSDFS_BSIZE)) + return 0; + fs->tinode += BSDFS_INODES_PER_BLOCK; + } + + /* legacy empty inode 1 */ + if (! create_inode1 (fs)) + return 0; + + /* lost+found directory */ + if (! create_lost_found_directory (fs)) + return 0; + + /* root directory */ + if (! create_root_directory (fs)) + return 0; + + /* swap file */ + if (fs->swapsz != 0 && ! create_swap_file (fs)) + return 0; + + /* build a list of free inodes */ + if (! inode_build_list (fs)) + return 0; + + /* write out super block */ + return fs_sync (fs, 1); +} diff --git a/tools/fsutil/file.c b/tools/fsutil/file.c new file mode 100644 index 0000000..aed769b --- /dev/null +++ b/tools/fsutil/file.c @@ -0,0 +1,82 @@ +/* + * File i/o routines for 2.xBSD filesystem. + * + * Copyright (C) 2006-2011 Serge Vakulenko, + * + * This file is part of RetroBSD project, which is distributed + * under the terms of the GNU General Public License (GPL). + * See the accompanying file "COPYING" for more details. + */ +#include +#include +#include "bsdfs.h" + +extern int verbose; + +int fs_file_create (fs_t *fs, fs_file_t *file, char *name, int mode) +{ + if (! fs_inode_by_name (fs, &file->inode, name, 1, mode)) { + fprintf (stderr, "%s: inode open failed\n", name); + return 0; + } + if ((file->inode.mode & INODE_MODE_FMT) == INODE_MODE_FDIR) { + /* Cannot open directory on write. */ + return 0; + } + fs_inode_truncate (&file->inode); + fs_inode_save (&file->inode, 0); + file->writable = 1; + file->offset = 0; + return 1; +} + +int fs_file_open (fs_t *fs, fs_file_t *file, char *name, int wflag) +{ + if (! fs_inode_by_name (fs, &file->inode, name, 0, 0)) { + fprintf (stderr, "%s: inode open failed\n", name); + return 0; + } + if (wflag && (file->inode.mode & INODE_MODE_FMT) == INODE_MODE_FDIR) { + /* Cannot open directory on write. */ + return 0; + } + file->writable = wflag; + file->offset = 0; + return 1; +} + +int fs_file_read (fs_file_t *file, unsigned char *data, unsigned long bytes) +{ + if (! fs_inode_read (&file->inode, file->offset, data, bytes)) { + fprintf (stderr, "inode %d: file write failed\n", + file->inode.number); + return 0; + } + file->offset += bytes; + return 1; +} + +int fs_file_write (fs_file_t *file, unsigned char *data, unsigned long bytes) +{ + if (! file->writable) + return 0; + if (! fs_inode_write (&file->inode, file->offset, data, bytes)) { + fprintf (stderr, "inode %d: error writing %lu bytes at offset %lu\n", + file->inode.number, bytes, file->offset); + return 0; + } + file->offset += bytes; + return 1; +} + +int fs_file_close (fs_file_t *file) +{ + if (file->writable) { + if (! fs_inode_save (&file->inode, 0)) { + fprintf (stderr, "inode %d: file close failed\n", + file->inode.number); + return 0; + } + } + return 1; +} diff --git a/tools/fsutil/fsutil.c b/tools/fsutil/fsutil.c new file mode 100644 index 0000000..8f7eca1 --- /dev/null +++ b/tools/fsutil/fsutil.c @@ -0,0 +1,519 @@ +/* + * Utility for dealing with 2.xBSD filesystem images. + * + * Copyright (C) 2006-2011 Serge Vakulenko, + * + * This file is part of RetroBSD project, which is distributed + * under the terms of the GNU General Public License (GPL). + * See the accompanying file "COPYING" for more details. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include "bsdfs.h" + +int verbose; +int extract; +int add; +int newfs; +int check; +int fix; +unsigned kbytes; +unsigned swap_kbytes; + +static const char *program_version = + "BSD 2.x file system utility, version 1.0\n" + "Copyright (C) 2011 Serge Vakulenko"; + +static const char *program_bug_address = ""; + +static struct option program_options[] = { + { "help", no_argument, 0, 'h' }, + { "version", no_argument, 0, 'V' }, + { "verbose", no_argument, 0, 'v' }, + { "add", no_argument, 0, 'a' }, + { "extract", no_argument, 0, 'x' }, + { "check", no_argument, 0, 'c' }, + { "fix", no_argument, 0, 'f' }, + { "new", required_argument, 0, 'n' }, + { "swap", required_argument, 0, 's' }, + { 0 } +}; + +static void print_help (char *progname) +{ + char *p = strrchr (progname, '/'); + if (p) + progname = p+1; + + printf ("%s\n", program_version); + printf ("This program is free software; it comes with ABSOLUTELY NO WARRANTY;\n" + "see the GNU General Public License for more details.\n"); + printf ("\n"); + printf ("Usage:\n"); + printf (" %s [--verbose] filesys.bin\n", progname); + printf (" %s --add filesys.bin files...\n", progname); + printf (" %s --extract filesys.bin\n", progname); + printf (" %s --check [--fix] filesys.bin\n", progname); + printf (" %s --new=kbytes [--swap=kbytes] filesys.bin\n", progname); + printf ("\n"); + printf ("Options:\n"); + printf (" -a, --add Add files to filesystem.\n"); + printf (" -x, --extract Extract all files.\n"); + printf (" -c, --check Check filesystem, use -c -f to fix.\n"); + printf (" -f, --fix Fix bugs in filesystem.\n"); + printf (" -n NUM, --new=NUM Create new filesystem, size in kbytes.\n"); + printf (" -s NUM, --swap=NUM Size of swap area in kbytes.\n"); + printf (" -v, --verbose Print verbose information.\n"); + printf (" -V, --version Print version information and then exit.\n"); + printf (" -h, --help Print this message.\n"); + printf ("\n"); + printf ("Report bugs to \"%s\".\n", program_bug_address); +} + +void print_inode (fs_inode_t *inode, + char *dirname, char *filename, FILE *out) +{ + fprintf (out, "%s/%s", dirname, filename); + switch (inode->mode & INODE_MODE_FMT) { + case INODE_MODE_FDIR: + if (filename[0] != 0) + fprintf (out, "/"); + break; + case INODE_MODE_FCHR: + fprintf (out, " - char %d %d", + inode->addr[1] >> 8, inode->addr[1] & 0xff); + break; + case INODE_MODE_FBLK: + fprintf (out, " - block %d %d", + inode->addr[1] >> 8, inode->addr[1] & 0xff); + break; + default: + fprintf (out, " - %lu bytes", inode->size); + break; + } + fprintf (out, "\n"); +} + +void print_indirect_block (fs_t *fs, unsigned int bno, FILE *out) +{ + unsigned short nb; + unsigned char data [BSDFS_BSIZE]; + int i; + + fprintf (out, " [%d]", bno); + if (! fs_read_block (fs, bno, data)) { + fprintf (stderr, "read error at block %d\n", bno); + return; + } + for (i=0; imode & INODE_MODE_FMT) == INODE_MODE_FCHR || + (inode->mode & INODE_MODE_FMT) == INODE_MODE_FBLK) + return; + + fprintf (out, " "); + for (i=0; iaddr[i] == 0) + continue; + fprintf (out, " %d", inode->addr[i]); + } + if (inode->addr[NDADDR] != 0) + print_indirect_block (inode->fs, inode->addr[NDADDR], out); + if (inode->addr[NDADDR+1] != 0) + print_double_indirect_block (inode->fs, + inode->addr[NDADDR+1], out); + if (inode->addr[NDADDR+2] != 0) + print_triple_indirect_block (inode->fs, + inode->addr[NDADDR+2], out); + fprintf (out, "\n"); +} + +void extract_inode (fs_inode_t *inode, char *path) +{ + int fd, n, mode; + unsigned long offset; + unsigned char data [BSDFS_BSIZE]; + + /* Allow read/write for user. */ + mode = (inode->mode & 0777) | 0600; + fd = open (path, O_CREAT | O_RDWR, mode); + if (fd < 0) { + perror (path); + return; + } + for (offset = 0; offset < inode->size; offset += BSDFS_BSIZE) { + n = inode->size - offset; + if (n > BSDFS_BSIZE) + n = BSDFS_BSIZE; + if (! fs_inode_read (inode, offset, data, n)) { + fprintf (stderr, "%s: read error at offset %ld\n", + path, offset); + break; + } + if (write (fd, data, n) != n) { + fprintf (stderr, "%s: write error\n", path); + break; + } + } + close (fd); +} + +void extractor (fs_inode_t *dir, fs_inode_t *inode, + char *dirname, char *filename, void *arg) +{ + FILE *out = arg; + char *path, *relpath; + + if (verbose) + print_inode (inode, dirname, filename, out); + + if ((inode->mode & INODE_MODE_FMT) != INODE_MODE_FDIR && + (inode->mode & INODE_MODE_FMT) != INODE_MODE_FREG) + return; + + path = alloca (strlen (dirname) + strlen (filename) + 2); + strcpy (path, dirname); + strcat (path, "/"); + strcat (path, filename); + for (relpath=path; *relpath == '/'; relpath++) + continue; + + if ((inode->mode & INODE_MODE_FMT) == INODE_MODE_FDIR) { + if (mkdir (relpath, 0775) < 0 && errno != EEXIST) + perror (relpath); + /* Scan subdirectory. */ + fs_directory_scan (inode, path, extractor, arg); + } else { + extract_inode (inode, relpath); + } +} + +void scanner (fs_inode_t *dir, fs_inode_t *inode, + char *dirname, char *filename, void *arg) +{ + FILE *out = arg; + char *path; + + print_inode (inode, dirname, filename, out); + + if (verbose > 1) { + /* Print a list of blocks. */ + print_inode_blocks (inode, out); + if (verbose > 2) { + fs_inode_print (inode, out); + printf ("--------\n"); + } + } + if ((inode->mode & INODE_MODE_FMT) == INODE_MODE_FDIR && + inode->number != BSDFS_ROOT_INODE) { + /* Scan subdirectory. */ + path = alloca (strlen (dirname) + strlen (filename) + 2); + strcpy (path, dirname); + strcat (path, "/"); + strcat (path, filename); + fs_directory_scan (inode, path, scanner, arg); + } +} + +/* + * Create a directory. + */ +void add_directory (fs_t *fs, char *name) +{ + fs_inode_t dir, parent; + char buf [BSDFS_BSIZE], *p; + + /* Open parent directory. */ + strcpy (buf, name); + p = strrchr (buf, '/'); + if (p) + *p = 0; + else + *buf = 0; + if (! fs_inode_by_name (fs, &parent, buf, 0, 0)) { + fprintf (stderr, "%s: cannot open directory\n", buf); + return; + } + + /* Create directory. */ + int done = fs_inode_by_name (fs, &dir, name, 1, INODE_MODE_FDIR | 0777); + if (! done) { + fprintf (stderr, "%s: directory inode create failed\n", name); + return; + } + if (done == 1) { + /* The directory already existed. */ + return; + } + fs_inode_save (&dir, 0); + + /* Make parent link '..' */ + strcpy (buf, name); + strcat (buf, "/.."); + if (! fs_inode_by_name (fs, &dir, buf, 3, parent.number)) { + fprintf (stderr, "%s: dotdot link failed\n", name); + return; + } + if (! fs_inode_get (fs, &parent, parent.number)) { + fprintf (stderr, "inode %d: cannot open parent\n", parent.number); + return; + } + ++parent.nlink; + fs_inode_save (&parent, 1); +/*printf ("*** inode %d: increment link counter to %d\n", parent.number, parent.nlink);*/ +} + +/* + * Create a device node. + */ +void add_device (fs_t *fs, char *name, char *spec) +{ + fs_inode_t dev; + int majr, minr; + char type; + + if (sscanf (spec, "%c%d:%d", &type, &majr, &minr) != 3 || + (type != 'c' && type != 'b') || + majr < 0 || majr > 255 || minr < 0 || minr > 255) { + fprintf (stderr, "%s: invalid device specification\n", spec); + fprintf (stderr, "expected c: or b:\n"); + return; + } + if (! fs_inode_by_name (fs, &dev, name, 1, 0666 | + ((type == 'b') ? INODE_MODE_FBLK : INODE_MODE_FCHR))) { + fprintf (stderr, "%s: device inode create failed\n", name); + return; + } + dev.addr[1] = majr << 8 | minr; + fs_inode_save (&dev, 1); +} + +/* + * Copy file to filesystem. + * When name is ended by slash as "name/", directory is created. + */ +void add_file (fs_t *fs, char *name) +{ + fs_file_t file; + FILE *fd; + unsigned char data [BSDFS_BSIZE]; + struct stat st; + char *p; + int len; + + if (verbose) { + printf ("%s\n", name); + } + p = strrchr (name, '/'); + if (p && p[1] == 0) { + *p = 0; + add_directory (fs, name); + return; + } + p = strrchr (name, '!'); + if (p) { + *p++ = 0; + add_device (fs, name, p); + return; + } + fd = fopen (name, "r"); + if (! fd) { + perror (name); + return; + } + stat (name, &st); + if (! fs_file_create (fs, &file, name, st.st_mode)) { + fprintf (stderr, "%s: cannot create\n", name); + return; + } + for (;;) { + len = fread (data, 1, sizeof (data), fd); +/* printf ("read %d bytes from %s\n", len, name);*/ + if (len < 0) + perror (name); + if (len <= 0) + break; + if (! fs_file_write (&file, data, len)) { + fprintf (stderr, "%s: write error\n", name); + break; + } + } + file.inode.mtime = st.st_mtime; + fs_file_close (&file); + fclose (fd); +} + +int main (int argc, char **argv) +{ + int i, key; + fs_t fs; + fs_inode_t inode; + + for (;;) { + key = getopt_long (argc, argv, "vaxn:cfs:", + program_options, 0); + if (key == -1) + break; + switch (key) { + case 'v': + ++verbose; + break; + case 'a': + ++add; + break; + case 'x': + ++extract; + break; + case 'n': + ++newfs; + kbytes = strtol (optarg, 0, 0); + break; + case 'c': + ++check; + break; + case 'f': + ++fix; + break; + case 's': + swap_kbytes = strtol (optarg, 0, 0); + break; + case 'V': + printf ("%s\n", program_version); + return 0; + case 'h': + print_help (argv[0]); + return 0; + default: + print_help (argv[0]); + return -1; + } + } + i = optind; + if ((! add && i != argc-1) || (add && i >= argc) || + (extract + newfs + check + add > 1) || + (newfs && kbytes < BSDFS_BSIZE * 10 / 1024)) { + print_help (argv[0]); + return -1; + } + + if (newfs) { + /* Create new filesystem. */ + if (! fs_create (&fs, argv[i], kbytes, swap_kbytes)) { + fprintf (stderr, "%s: cannot create filesystem\n", argv[i]); + return -1; + } + printf ("Created filesystem %s - %u kbytes\n", argv[i], kbytes); + fs_close (&fs); + return 0; + } + + if (check) { + /* Check filesystem for errors, and optionally fix them. */ + if (! fs_open (&fs, argv[i], fix)) { + fprintf (stderr, "%s: cannot open\n", argv[i]); + return -1; + } + fs_check (&fs); + fs_close (&fs); + return 0; + } + + /* Add or extract or info. */ + if (! fs_open (&fs, argv[i], (add != 0))) { + fprintf (stderr, "%s: cannot open\n", argv[i]); + return -1; + } + + if (extract) { + /* Extract all files to current directory. */ + if (! fs_inode_get (&fs, &inode, BSDFS_ROOT_INODE)) { + fprintf (stderr, "%s: cannot get inode 1\n", argv[i]); + return -1; + } + fs_directory_scan (&inode, "", extractor, (void*) stdout); + fs_close (&fs); + return 0; + } + + if (add) { + /* Add files i+1..argc-1 to filesystem. */ + while (++i < argc) + add_file (&fs, argv[i]); + fs_sync (&fs, 0); + fs_close (&fs); + return 0; + } + + /* Print the structure of flesystem. */ + fs_print (&fs, stdout); + if (verbose) { + printf ("--------\n"); + if (! fs_inode_get (&fs, &inode, BSDFS_ROOT_INODE)) { + fprintf (stderr, "%s: cannot get inode 1\n", argv[i]); + return -1; + } + printf ("/\n"); + if (verbose > 1) { + /* Print a list of blocks. */ + print_inode_blocks (&inode, stdout); + if (verbose > 2) { + fs_inode_print (&inode, stdout); + printf ("--------\n"); + } + } + fs_directory_scan (&inode, "", scanner, (void*) stdout); + } + fs_close (&fs); + return 0; +} diff --git a/tools/fsutil/inode.c b/tools/fsutil/inode.c new file mode 100644 index 0000000..da70cf5 --- /dev/null +++ b/tools/fsutil/inode.c @@ -0,0 +1,832 @@ +/* + * Inode routines for 2.xBSD filesystem. + * + * Copyright (C) 2006-2011 Serge Vakulenko, + * + * This file is part of RetroBSD project, which is distributed + * under the terms of the GNU General Public License (GPL). + * See the accompanying file "COPYING" for more details. + */ +#include +#include +#include +#include +#include +#include "bsdfs.h" + +extern int verbose; + +int fs_inode_get (fs_t *fs, fs_inode_t *inode, unsigned inum) +{ + unsigned long offset; + int i, reserved; + + memset (inode, 0, sizeof (*inode)); + inode->fs = fs; + inode->number = inum; + + /* Inodes are numbered starting from 1. + * 64 bytes per inode, 16 inodes per block. + * Skip first block. */ + if (inum == 0 || inum > (fs->isize-1) * BSDFS_INODES_PER_BLOCK) + return 0; + offset = (inode->number + BSDFS_INODES_PER_BLOCK - 1) * + BSDFS_BSIZE / BSDFS_INODES_PER_BLOCK; + + if (! fs_seek (fs, offset)) + return 0; + + if (! fs_read16 (fs, &inode->mode)) /* file type and access mode */ + return 0; + if (! fs_read16 (fs, &inode->nlink)) /* directory entries */ + return 0; + if (! fs_read32 (fs, &inode->uid)) /* owner */ + return 0; + if (! fs_read32 (fs, &inode->gid)) /* group */ + return 0; + if (! fs_read32 (fs, (unsigned*) &inode->size)) /* size */ + return 0; + + for (i=0; iaddr[i])) + return 0; + } + if (! fs_read32 (fs, (unsigned*) &reserved)) + return 0; + if (! fs_read32 (fs, (unsigned*) &inode->flags)) + return 0; + if (! fs_read32 (fs, (unsigned*) &inode->atime)) + return 0; /* last access time */ + if (! fs_read32 (fs, (unsigned*) &inode->mtime)) + return 0; /* last modification time */ + if (! fs_read32 (fs, (unsigned*) &inode->ctime)) + return 0; /* creation time */ +/*if (inode->mode) { fs_inode_print (inode, stdout); printf ("---\n"); }*/ + if (verbose > 3) + printf ("get inode %u\n", inode->number); + return 1; +} + +/* + * Free all the disk blocks associated + * with the specified inode structure. + * The blocks of the file are removed + * in reverse order. This FILO + * algorithm will tend to maintain + * a contiguous free list much longer + * than FIFO. + */ +void fs_inode_truncate (fs_inode_t *inode) +{ + unsigned *blk; + + if ((inode->mode & INODE_MODE_FMT) == INODE_MODE_FCHR || + (inode->mode & INODE_MODE_FMT) == INODE_MODE_FBLK) + return; + +#define SINGLE 4 /* index of single indirect block */ +#define DOUBLE 5 /* index of double indirect block */ +#define TRIPLE 6 /* index of triple indirect block */ + + for (blk = &inode->addr[TRIPLE]; blk >= &inode->addr[0]; --blk) { + if (*blk == 0) + continue; + + if (blk == &inode->addr [TRIPLE]) + fs_triple_indirect_block_free (inode->fs, *blk); + else if (blk == &inode->addr [DOUBLE]) + fs_double_indirect_block_free (inode->fs, *blk); + else if (blk == &inode->addr [SINGLE]) + fs_indirect_block_free (inode->fs, *blk); + else + fs_block_free (inode->fs, *blk); + + *blk = 0; + } + + inode->size = 0; + inode->dirty = 1; +} + +void fs_inode_clear (fs_inode_t *inode) +{ + inode->dirty = 1; + inode->mode = 0; + inode->nlink = 0; + inode->uid = 0; + inode->size = 0; + memset (inode->addr, 0, sizeof(inode->addr)); + inode->atime = 0; + inode->mtime = 0; +} + +int fs_inode_save (fs_inode_t *inode, int force) +{ + unsigned long offset; + int i; + + if (! inode->fs->writable) + return 0; + if (! force && ! inode->dirty) + return 1; + if (inode->number == 0 || + inode->number > (inode->fs->isize-1) * BSDFS_INODES_PER_BLOCK) + return 0; + offset = (inode->number + BSDFS_INODES_PER_BLOCK - 1) * + BSDFS_BSIZE / BSDFS_INODES_PER_BLOCK; + + time (&inode->atime); + //time (&inode->mtime); + + if (! fs_seek (inode->fs, offset)) + return 0; + + if (! fs_write16 (inode->fs, inode->mode)) /* file type and access mode */ + return 0; + if (! fs_write16 (inode->fs, inode->nlink)) /* directory entries */ + return 0; + if (! fs_write32 (inode->fs, inode->uid)) /* owner */ + return 0; + if (! fs_write32 (inode->fs, inode->gid)) /* group */ + return 0; + if (! fs_write32 (inode->fs, inode->size)) /* size */ + return 0; + + for (i=0; ifs, inode->addr[i])) + return 0; + } + if (! fs_write32 (inode->fs, 0)) /* reserved */ + return 0; + if (! fs_write32 (inode->fs, inode->flags)) /* flags */ + return 0; + if (! fs_write32 (inode->fs, inode->atime)) /* last access time */ + return 0; + if (! fs_write32 (inode->fs, inode->mtime)) /* last modification time */ + return 0; + if (! fs_write32 (inode->fs, inode->ctime)) /* creation time */ + return 0; + + inode->dirty = 0; + if (verbose > 3) + printf ("save inode %u\n", inode->number); + return 1; +} + +void fs_inode_print (fs_inode_t *inode, FILE *out) +{ + int i; + + fprintf (out, " I-node: %u\n", inode->number); + fprintf (out, " Type: %s\n", + (inode->mode & INODE_MODE_FMT) == INODE_MODE_FDIR ? "Directory" : + (inode->mode & INODE_MODE_FMT) == INODE_MODE_FCHR ? "Character device" : + (inode->mode & INODE_MODE_FMT) == INODE_MODE_FBLK ? "Block device" : + (inode->mode & INODE_MODE_FMT) == INODE_MODE_FREG ? "File" : + (inode->mode & INODE_MODE_FMT) == INODE_MODE_FLNK ? "Symbolic link" : + (inode->mode & INODE_MODE_FMT) == INODE_MODE_FSOCK? "Socket" : + "Unknown"); + fprintf (out, " Size: %lu bytes\n", inode->size); + fprintf (out, " Mode: %#o\n", inode->mode); + + fprintf (out, " "); + if (inode->mode & INODE_MODE_SUID) fprintf (out, " SUID"); + if (inode->mode & INODE_MODE_SGID) fprintf (out, " SGID"); + if (inode->mode & INODE_MODE_SVTX) fprintf (out, " SVTX"); + if (inode->mode & INODE_MODE_READ) fprintf (out, " READ"); + if (inode->mode & INODE_MODE_WRITE) fprintf (out, " WRITE"); + if (inode->mode & INODE_MODE_EXEC) fprintf (out, " EXEC"); + fprintf (out, "\n"); + + fprintf (out, " Links: %u\n", inode->nlink); + fprintf (out, " Owner id: %u\n", inode->uid); + + fprintf (out, " Blocks:"); + for (i=0; iaddr[i]); + } + fprintf (out, "\n"); + + fprintf (out, " Created: %s", ctime (&inode->ctime)); + fprintf (out, " Modified: %s", ctime (&inode->mtime)); + fprintf (out, "Last access: %s", ctime (&inode->atime)); +} + +void fs_directory_scan (fs_inode_t *dir, char *dirname, + fs_directory_scanner_t scanner, void *arg) +{ + fs_inode_t file; + unsigned long offset; + unsigned char name [BSDFS_BSIZE - 12]; + struct { + unsigned int inum; + unsigned short reclen; + unsigned short namlen; + } dirent; + + /* Variable record per file */ + for (offset = 0; offset < dir->size; offset += dirent.reclen) { + if (! fs_inode_read (dir, offset, (unsigned char*) &dirent, sizeof(dirent))) { + fprintf (stderr, "%s: read error at offset %ld\n", + dirname[0] ? dirname : "/", offset); + return; + } +/*printf ("scan offset %lu: inum=%u, reclen=%u, namlen=%u\n", offset, dirent.inum, dirent.reclen, dirent.namlen);*/ + if (! fs_inode_read (dir, offset+sizeof(dirent), name, (dirent.namlen + 4) / 4 * 4)) { + fprintf (stderr, "%s: name read error at offset %ld\n", + dirname[0] ? dirname : "/", offset); + return; + } +/*printf ("scan offset %lu: name='%s'\n", offset, name);*/ + + if (dirent.inum == 0 || (name[0]=='.' && name[1]==0) || + (name[0]=='.' && name[1]=='.' && name[2]==0)) + continue; + + if (! fs_inode_get (dir->fs, &file, dirent.inum)) { + fprintf (stderr, "cannot scan inode %d\n", dirent.inum); + continue; + } + scanner (dir, &file, dirname, (char*) name, arg); + } +} + +/* + * Return the physical block number on a device given the + * inode and the logical block number in a file. + */ +static unsigned map_block (fs_inode_t *inode, unsigned lbn) +{ + unsigned block [BSDFS_BSIZE / 4]; + unsigned int nb, i, j, sh; + + /* + * Blocks 0..NADDR-4 are direct blocks. + */ + if (lbn < NADDR-3) { + /* small file algorithm */ + return inode->addr [lbn]; + } + + /* + * Addresses NADDR-3, NADDR-2, and NADDR-1 + * have single, double, triple indirect blocks. + * The first step is to determine + * how many levels of indirection. + */ + sh = 0; + nb = 1; + lbn -= NADDR-3; + for (j=3; ; j--) { + if (j == 0) + return 0; + sh += NSHIFT; + nb <<= NSHIFT; + if (lbn < nb) + break; + lbn -= nb; + } + + /* + * Fetch the first indirect block. + */ + nb = inode->addr [NADDR-j]; + if (nb == 0) + return 0; + + /* + * Fetch through the indirect blocks. + */ + for(; j <= 3; j++) { + if (! fs_read_block (inode->fs, nb, (unsigned char*) block)) + return 0; + + sh -= NSHIFT; + i = (lbn >> sh) & NMASK; + nb = block [i]; + if (nb == 0) + return 0; + } + return nb; +} + +/* + * Bmap defines the structure of file system storage + * by returning the physical block number on a device given the + * inode and the logical block number in a file. + */ +static unsigned map_block_write (fs_inode_t *inode, unsigned lbn) +{ + unsigned block [BSDFS_BSIZE / 4]; + unsigned int nb, newb, sh, i, j; + + /* + * Blocks 0..NADDR-3 are direct blocks. + */ + if (lbn < NADDR-3) { + /* small file algorithm */ + nb = inode->addr [lbn]; + if (nb != 0) { + if (verbose) + printf ("map logical block %d to physical %d\n", lbn, nb); + return nb; + } + + /* allocate new block */ + if (! fs_block_alloc (inode->fs, &nb)) + return 0; + inode->addr[lbn] = nb; + inode->dirty = 1; + return nb; + } + + /* + * Addresses NADDR-3, NADDR-2, and NADDR-1 + * have single, double, triple indirect blocks. + * The first step is to determine + * how many levels of indirection. + */ + sh = 0; + nb = 1; + lbn -= NADDR-3; + for (j=3; ; j--) { + if (j == 0) + return 0; + sh += NSHIFT; + nb <<= NSHIFT; + if (lbn < nb) + break; + lbn -= nb; + } + + /* + * Fetch the first indirect block. + */ + nb = inode->addr [NADDR-j]; + if (nb == 0) { + if (! fs_block_alloc (inode->fs, &nb)) + return 0; + if (verbose) + printf ("inode %d: allocate new block %d\n", inode->number, nb); + memset (block, 0, BSDFS_BSIZE); + if (! fs_write_block (inode->fs, nb, (unsigned char*) block)) + return 0; + inode->addr [NADDR-j] = nb; + inode->dirty = 1; + } + + /* + * Fetch through the indirect blocks + */ + for(; j <= 3; j++) { + if (! fs_read_block (inode->fs, nb, (unsigned char*) block)) + return 0; + + sh -= NSHIFT; + i = (lbn >> sh) & NMASK; + if (block [i] != 0) + nb = block [i]; + else { + /* Allocate new block. */ + if (! fs_block_alloc (inode->fs, &newb)) + return 0; + if (verbose) + printf ("inode %d: allocate new block %d\n", inode->number, newb); + block[i] = newb; + if (! fs_write_block (inode->fs, nb, (unsigned char*) block)) + return 0; + memset (block, 0, BSDFS_BSIZE); + if (! fs_write_block (inode->fs, newb, (unsigned char*) block)) + return 0; + nb = newb; + } + } + return nb; +} + +int fs_inode_read (fs_inode_t *inode, unsigned long offset, + unsigned char *data, unsigned long bytes) +{ + unsigned char block [BSDFS_BSIZE]; + unsigned long n; + unsigned int bn, inblock_offset; + + if (bytes + offset > inode->size) + return 0; + while (bytes != 0) { + inblock_offset = offset % BSDFS_BSIZE; + n = BSDFS_BSIZE - inblock_offset; + if (n > bytes) + n = bytes; + + bn = map_block (inode, offset / BSDFS_BSIZE); + if (bn == 0) + return 0; + + if (! fs_read_block (inode->fs, bn, block)) + return 0; + memcpy (data, block + inblock_offset, n); + offset += n; + bytes -= n; + } + return 1; +} + +int fs_inode_write (fs_inode_t *inode, unsigned long offset, + unsigned char *data, unsigned long bytes) +{ + unsigned char block [BSDFS_BSIZE]; + unsigned long n; + unsigned int bn, inblock_offset; + + time (&inode->mtime); + while (bytes != 0) { + inblock_offset = offset % BSDFS_BSIZE; + n = BSDFS_BSIZE - inblock_offset; + if (n > bytes) + n = bytes; + + bn = map_block_write (inode, offset / BSDFS_BSIZE); + if (bn == 0) + return 0; + if (inode->size < offset + n) { + /* Increase file size. */ + inode->size = offset + n; + inode->dirty = 1; + } + if (verbose) + printf ("inode %d offset %ld: write %ld bytes to block %d\n", + inode->number, offset, n, bn); + + if (n == BSDFS_BSIZE) { + if (! fs_write_block (inode->fs, bn, data)) + return 0; + } else { + if (! fs_read_block (inode->fs, bn, block)) + return 0; + memcpy (block + inblock_offset, data, n); + if (! fs_write_block (inode->fs, bn, block)) + return 0; + } + offset += n; + bytes -= n; + } + return 1; +} + +/* + * Convert from dirent to raw data. + */ +void fs_dirent_pack (unsigned char *data, fs_dirent_t *dirent) +{ + int i; + + *data++ = dirent->ino; + *data++ = dirent->ino >> 8; + *data++ = dirent->ino >> 16; + *data++ = dirent->ino >> 24; + *data++ = dirent->reclen; + *data++ = dirent->reclen >> 8; + *data++ = dirent->namlen; + *data++ = dirent->namlen >> 8; + for (i=0; dirent->name[i]; ++i) + *data++ = dirent->name[i]; + for (; i & 3; ++i) + *data++ = 0; +} + +/* + * Read dirent from raw data. + */ +void fs_dirent_unpack (fs_dirent_t *dirent, unsigned char *data) +{ + dirent->ino = *data++; + dirent->ino |= *data++ << 8; + dirent->ino |= *data++ << 16; + dirent->ino |= *data++ << 24; + dirent->reclen = *data++; + dirent->reclen |= *data++ << 8; + dirent->namlen = *data++; + dirent->namlen |= *data++ << 8; + memset (dirent->name, 0, sizeof (dirent->name)); + memcpy (dirent->name, data, dirent->namlen); +} + +/* + * Convert a pathname into a pointer to + * an inode. Note that the inode is locked. + * + * op = 0 if name is saught + * 1 if name is to be created, mode is given + * 2 if name is to be deleted + * 3 if name is to be linked, mode contains inode number + * + * Return 0 on any error. + * Return 1 when the inode was found. + * Return 2 when the inode was created/deleted/linked. + */ +#define LOOKUP 0 /* perform name lookup only */ +#define CREATE 1 /* setup for file creation */ +#define DELETE 2 /* setup for file deletion */ +#define LINK 3 /* setup for link */ + +int fs_inode_by_name (fs_t *fs, fs_inode_t *inode, char *name, + int op, int mode) +{ + fs_inode_t dir; + int c, namlen, reclen; + char *namptr; + unsigned long offset, last_offset; + struct { + unsigned int inum; + unsigned short reclen; + unsigned short namlen; + } dirent; + + /* Start from root. */ + if (! fs_inode_get (fs, &dir, BSDFS_ROOT_INODE)) { + fprintf (stderr, "inode_open(): cannot get root\n"); + return 0; + } + c = *name++; + while (c == '/') + c = *name++; + if (! c && op != LOOKUP) { + /* Cannot write or delete root directory. */ + return 0; + } +cloop: + /* Here inode contains pointer + * to last component matched. */ + if (! c) { + *inode = dir; + return 1; + } + + /* If there is another component, + * inode must be a directory. */ + if ((dir.mode & INODE_MODE_FMT) != INODE_MODE_FDIR) { + return 0; + } + + /* Gather up dir name into buffer. */ + namptr = name - 1; + while (c && c != '/') { + c = *name++; + } + namlen = name - namptr - 1; + while (c == '/') + c = *name++; + + /* Search a directory, variable record per file */ + if (verbose > 2) + printf ("scan for '%.*s', %d bytes\n", namlen, namptr, namlen); + last_offset = 0; + for (offset = 0; offset < dir.size; last_offset = offset, offset += dirent.reclen) { + unsigned char fname [BSDFS_BSIZE - 12]; + + if (! fs_inode_read (&dir, offset, (unsigned char*) &dirent, sizeof(dirent))) { + fprintf (stderr, "inode %d: read error at offset %ld\n", + dir.number, offset); + return 0; + } + if (verbose > 2) + printf ("scan offset %lu: inum=%u, reclen=%u, namlen=%u\n", offset, dirent.inum, dirent.reclen, dirent.namlen); + if (dirent.inum == 0 || dirent.namlen != namlen) + continue; + if (! fs_inode_read (&dir, offset+sizeof(dirent), fname, namlen)) { + fprintf (stderr, "inode %d: name read error at offset %ld\n", + dir.number, offset); + return 0; + } + if (verbose > 2) + printf ("scan offset %lu: name='%.*s'\n", offset, namlen, fname); + if (strncmp (namptr, (char*) fname, namlen) == 0) { + /* Here a component matched in a directory. + * If there is more pathname, go back to + * cloop, otherwise return. */ + if (op == DELETE && ! c) { + goto delete_file; + } + if (! fs_inode_get (fs, &dir, dirent.inum)) { + fprintf (stderr, "inode_open(): cannot get inode %d\n", dirent.inum); + return 0; + } + goto cloop; + } + } + /* If at the end of the directory, the search failed. + * Report what is appropriate as per flag. */ + if (op == CREATE && ! c) + goto create_file; + if (op == LINK && ! c) + goto create_link; + return 0; + + /* + * Make a new file, and return it's inode. + */ +create_file: + if (! fs_inode_alloc (fs, inode)) { + fprintf (stderr, "%s: cannot allocate inode\n", name); + return 0; + } + inode->dirty = 1; + inode->mode = mode & (07777 | INODE_MODE_FMT); + if ((inode->mode & INODE_MODE_FMT) == 0) + inode->mode |= INODE_MODE_FREG; + inode->nlink = 1; + inode->uid = 0; + inode->flags = 0; + time (&inode->ctime); + if ((inode->mode & INODE_MODE_FMT) == INODE_MODE_FDIR) { + /* Make link '.' */ + struct { + unsigned int inum; + unsigned short reclen; + unsigned short namlen; + char name [4]; + } dotent; + dotent.inum = inode->number; + dotent.reclen = BSDFS_BSIZE; + dotent.namlen = 1; + memcpy (dotent.name, ".\0\0\0", 4); + if (! fs_inode_write (inode, 0, (unsigned char*) &dotent, sizeof(dotent))) { + fprintf (stderr, "inode %d: write error at offset %ld\n", + inode->number, 0L); + return 0; + } + /* Increase file size. */ + inode->size = BSDFS_BSIZE; + ++inode->nlink; + } + if (! fs_inode_save (inode, 0)) { + fprintf (stderr, "%s: cannot save file inode\n", name); + return 0; + } + + /* Write a directory entry. */ + if (verbose > 2) + printf ("*** create file '%.*s', inode %d\n", namlen, namptr, inode->number); + reclen = dirent.reclen - 8 - (dirent.namlen + 4) / 4 * 4; + c = 8 + (namlen + 4) / 4 * 4; + if (reclen >= c) { + /* Enough space */ + dirent.reclen -= reclen; + if (verbose > 2) + printf ("*** previous entry %u-%u-%u at offset %lu\n", + dirent.inum, dirent.reclen, dirent.namlen, last_offset); + if (! fs_inode_write (&dir, last_offset, (unsigned char*) &dirent, sizeof(dirent))) { + fprintf (stderr, "inode %d: write error at offset %ld\n", + dir.number, last_offset); + return 0; + } + } else { + /* No space, extend directory. */ + if (verbose > 2) + printf ("*** extend dir, previous entry %u-%u-%u at offset %lu\n", + dirent.inum, dirent.reclen, dirent.namlen, last_offset); + reclen = BSDFS_BSIZE; + } + offset = last_offset + dirent.reclen; + dirent.inum = inode->number; + dirent.reclen = reclen; + dirent.namlen = namlen; + if (verbose > 2) + printf ("*** new entry %u-%u-%u at offset %lu\n", dirent.inum, dirent.reclen, dirent.namlen, offset); + if (! fs_inode_write (&dir, offset, (unsigned char*) &dirent, sizeof(dirent))) { + fprintf (stderr, "inode %d: write error at offset %ld\n", + dir.number, offset); + return 0; + } + if (verbose > 2) + printf ("*** name '%.*s' at offset %lu\n", namlen, namptr, offset+sizeof(dirent)); + if (! fs_inode_write (&dir, offset+sizeof(dirent), (unsigned char*) namptr, namlen)) { + fprintf (stderr, "inode %d: write error at offset %ld\n", + dir.number, offset+sizeof(dirent)); + return 0; + } + /* Align directory size. */ + dir.size = (dir.size + BSDFS_BSIZE - 1) / BSDFS_BSIZE * BSDFS_BSIZE; + if (! fs_inode_save (&dir, 0)) { + fprintf (stderr, "%s: cannot save directory inode\n", name); + return 0; + } + return 2; + + /* + * Delete file. Return inode of deleted file. + */ +delete_file: + if (verbose > 2) + printf ("*** delete inode %d\n", dirent.inum); + if (! fs_inode_get (fs, inode, dirent.inum)) { + fprintf (stderr, "%s: cannot get inode %d\n", name, dirent.inum); + return 0; + } + inode->dirty = 1; + inode->nlink--; + if (inode->nlink <= 0) { + fs_inode_truncate (inode); + fs_inode_clear (inode); + if (inode->fs->ninode < NICINOD) { + inode->fs->inode [inode->fs->ninode++] = dirent.inum; + inode->fs->dirty = 1; + } + } + /* Extend previous entry to cover the empty space. */ + reclen = dirent.reclen; + if (! fs_inode_read (&dir, last_offset, (unsigned char*) &dirent, sizeof(dirent))) { + fprintf (stderr, "inode %d: read error at offset %ld\n", + dir.number, last_offset); + return 0; + } + dirent.reclen += reclen; + if (! fs_inode_write (&dir, last_offset, (unsigned char*) &dirent, sizeof(dirent))) { + fprintf (stderr, "inode %d: write error at offset %ld\n", + dir.number, last_offset); + return 0; + } + if (! fs_inode_save (&dir, 0)) { + fprintf (stderr, "%s: cannot save directory inode\n", name); + return 0; + } + return 2; + + /* + * Make a link. Return a directory inode. + */ +create_link: + if (verbose > 2) + printf ("*** link inode %d to '%.*s', directory %d\n", mode, namlen, namptr, dir.number); + reclen = dirent.reclen - 8 - (dirent.namlen + 4) / 4 * 4; + dirent.reclen -= reclen; + if (verbose > 2) + printf ("*** previous entry %u-%u-%u at offset %lu\n", dirent.inum, dirent.reclen, dirent.namlen, last_offset); + if (! fs_inode_write (&dir, last_offset, (unsigned char*) &dirent, sizeof(dirent))) { + fprintf (stderr, "inode %d: write error at offset %ld\n", + dir.number, last_offset); + return 0; + } + offset = last_offset + dirent.reclen; + dirent.inum = mode; + dirent.reclen = reclen; + dirent.namlen = namlen; + if (verbose > 2) + printf ("*** new entry %u-%u-%u at offset %lu\n", dirent.inum, dirent.reclen, dirent.namlen, offset); + if (! fs_inode_write (&dir, offset, (unsigned char*) &dirent, sizeof(dirent))) { + fprintf (stderr, "inode %d: write error at offset %ld\n", + dir.number, offset); + return 0; + } + if (verbose > 2) + printf ("*** name '%.*s' at offset %lu\n", namlen, namptr, offset+sizeof(dirent)); + if (! fs_inode_write (&dir, offset+sizeof(dirent), (unsigned char*) namptr, namlen)) { + fprintf (stderr, "inode %d: write error at offset %ld\n", + dir.number, offset+sizeof(dirent)); + return 0; + } + if (! fs_inode_save (&dir, 0)) { + fprintf (stderr, "%s: cannot save directory inode\n", name); + return 0; + } + *inode = dir; + return 2; +} + +/* + * Allocate an unused I node on the specified device. + * Used with file creation. The algorithm keeps up to + * NICINOD spare I nodes in the super block. + * When this runs out, a linear search through the + * I list is instituted to pick up NICINOD more. + */ +int fs_inode_alloc (fs_t *fs, fs_inode_t *inode) +{ + int ino; + + for (;;) { + if (fs->ninode <= 0) { + /* Build a list of free inodes. */ + if (! inode_build_list (fs)) { + fprintf (stderr, "inode_alloc: cannot build inode list\n"); + return 0; + } + if (fs->ninode <= 0) { + fprintf (stderr, "inode_alloc: out of in-core inodes\n"); + return 0; + } + } + ino = fs->inode[--fs->ninode]; + fs->dirty = 1; + fs->tinode--; + if (! fs_inode_get (fs, inode, ino)) { + fprintf (stderr, "inode_alloc: cannot get inode %d\n", ino); + return 0; + } + if (inode->mode == 0) { + fs_inode_clear (inode); + return 1; + } + } +} diff --git a/tools/fsutil/superblock.c b/tools/fsutil/superblock.c new file mode 100644 index 0000000..e8c02aa --- /dev/null +++ b/tools/fsutil/superblock.c @@ -0,0 +1,315 @@ +/* + * Superblock routines for 2.xBSD filesystem. + * + * Copyright (C) 2006-2011 Serge Vakulenko, + * + * This file is part of RetroBSD project, which is distributed + * under the terms of the GNU General Public License (GPL). + * See the accompanying file "COPYING" for more details. + */ +#include +#include +#include +#include +#include +#include "bsdfs.h" + +extern int verbose; + +int fs_seek (fs_t *fs, unsigned long offset) +{ +/* printf ("seek %ld, block %ld\n", offset, offset / BSDFS_BSIZE);*/ + if (lseek (fs->fd, offset, 0) < 0) { + if (verbose) + printf ("error seeking %ld, block %ld\n", + offset, offset / BSDFS_BSIZE); + return 0; + } + fs->seek = offset; + return 1; +} + +int fs_read8 (fs_t *fs, unsigned char *val) +{ + if (read (fs->fd, val, 1) != 1) { + if (verbose) + printf ("error read8, seek %ld block %ld\n", fs->seek, fs->seek / BSDFS_BSIZE); + return 0; + } + return 1; +} + +int fs_read16 (fs_t *fs, unsigned short *val) +{ + unsigned char data [2]; + + if (read (fs->fd, data, 2) != 2) { + if (verbose) + printf ("error read16, seek %ld block %ld\n", fs->seek, fs->seek / BSDFS_BSIZE); + return 0; + } + *val = data[1] << 8 | data[0]; + return 1; +} + +int fs_read32 (fs_t *fs, unsigned *val) +{ + unsigned char data [4]; + + if (read (fs->fd, data, 4) != 4) { + if (verbose) + printf ("error read32, seek %ld block %ld\n", fs->seek, fs->seek / BSDFS_BSIZE); + return 0; + } + *val = (unsigned long) data[0] | (unsigned long) data[1] << 8 | + data[2] << 16 | data[3] << 24; + return 1; +} + +int fs_write8 (fs_t *fs, unsigned char val) +{ + if (write (fs->fd, &val, 1) != 1) + return 0; + return 1; +} + +int fs_write16 (fs_t *fs, unsigned short val) +{ + unsigned char data [2]; + + data[0] = val; + data[1] = val >> 8; + if (write (fs->fd, data, 2) != 2) + return 0; + return 1; +} + +int fs_write32 (fs_t *fs, unsigned val) +{ + unsigned char data [4]; + + data[0] = val; + data[1] = val >> 8; + data[2] = val >> 16; + data[3] = val >> 24; + if (write (fs->fd, data, 4) != 4) + return 0; + return 1; +} + +int fs_read (fs_t *fs, unsigned char *data, int bytes) +{ + int len; + + while (bytes > 0) { + len = bytes; + if (len > 16*BSDFS_BSIZE) + len = 16*BSDFS_BSIZE; + if (read (fs->fd, data, len) != len) + return 0; + data += len; + bytes -= len; + } + return 1; +} + +int fs_write (fs_t *fs, unsigned char *data, int bytes) +{ + int len; + + if (! fs->writable) + return 0; + while (bytes > 0) { + len = bytes; + if (len > 16*BSDFS_BSIZE) + len = 16*BSDFS_BSIZE; + if (write (fs->fd, data, len) != len) + return 0; + data += len; + bytes -= len; + } + return 1; +} + +int fs_open (fs_t *fs, const char *filename, int writable) +{ + int i; + unsigned magic; + + memset (fs, 0, sizeof (*fs)); + fs->filename = filename; + fs->seek = 0; + + fs->fd = open (fs->filename, writable ? O_RDWR : O_RDONLY); + if (fs->fd < 0) + return 0; + fs->writable = writable; + + if (! fs_read32 (fs, &magic) || /* magic word */ + magic != FSMAGIC1) { + if (verbose) + printf ("fs_open: bad magic1 = %08x, expected %08x\n", + magic, FSMAGIC1); + return 0; + } + if (! fs_read32 (fs, &fs->isize)) /* size in blocks of I list */ + return 0; + if (! fs_read32 (fs, &fs->fsize)) /* size in blocks of entire volume */ + return 0; + if (! fs_read32 (fs, &fs->swapsz)) /* size in blocks of swap area */ + return 0; + if (! fs_read32 (fs, &fs->nfree)) /* number of in core free blocks */ + return 0; + for (i=0; ifree[i])) + return 0; + } + if (! fs_read32 (fs, &fs->ninode)) /* number of in core I nodes */ + return 0; + for (i=0; iinode[i])) + return 0; + } + if (! fs_read32 (fs, &fs->flock)) + return 0; + if (! fs_read32 (fs, &fs->fmod)) + return 0; + if (! fs_read32 (fs, &fs->ilock)) + return 0; + if (! fs_read32 (fs, &fs->ronly)) + return 0; + if (! fs_read32 (fs, (unsigned*) &fs->utime)) + return 0; /* current date of last update */ + if (! fs_read32 (fs, &fs->tfree)) /* total free blocks */ + return 0; + if (! fs_read32 (fs, &fs->tinode)) /* total free inodes */ + return 0; + if (! fs_read (fs, (unsigned char*) fs->fsmnt, MAXMNTLEN)) + return 0; /* ordinary file mounted on */ + if (! fs_read32 (fs, &fs->lasti)) /* start place for circular search */ + return 0; + if (! fs_read32 (fs, &fs->nbehind)) /* est # free inodes before s_lasti */ + return 0; + if (! fs_read32 (fs, &fs->flags)) /* mount time flags */ + return 0; + if (! fs_read32 (fs, &magic) || /* magic word */ + magic != FSMAGIC2) { + if (verbose) + printf ("fs_open: bad magic2 = %08x, expected %08x\n", + magic, FSMAGIC2); + return 0; + } + return 1; +} + +int fs_sync (fs_t *fs, int force) +{ + int i; + + if (! fs->writable) + return 0; + if (! force && ! fs->dirty) + return 1; + + time (&fs->utime); + if (! fs_seek (fs, 0)) + return 0; + + if (! fs_write32 (fs, FSMAGIC1)) /* magic word */ + return 0; + if (! fs_write32 (fs, fs->isize)) /* size in blocks of I list */ + return 0; + if (! fs_write32 (fs, fs->fsize)) /* size in blocks of entire volume */ + return 0; + if (! fs_write32 (fs, fs->swapsz)) /* size in blocks of swap area */ + return 0; + if (! fs_write32 (fs, fs->nfree)) /* number of in core free blocks */ + return 0; + for (i=0; ifree[i])) + return 0; + } + if (! fs_write32 (fs, fs->ninode)) /* number of in core I nodes */ + return 0; + for (i=0; iinode[i])) + return 0; + } + if (! fs_write32 (fs, fs->flock)) + return 0; + if (! fs_write32 (fs, fs->fmod)) + return 0; + if (! fs_write32 (fs, fs->ilock)) + return 0; + if (! fs_write32 (fs, fs->ronly)) + return 0; + if (! fs_write32 (fs, fs->utime)) /* current date of last update */ + return 0; + if (! fs_write32 (fs, fs->tfree)) /* total free blocks */ + return 0; + if (! fs_write32 (fs, fs->tinode)) /* total free inodes */ + return 0; + if (! fs_write (fs, (unsigned char*) fs->fsmnt, MAXMNTLEN)) + return 0; /* ordinary file mounted on */ + if (! fs_write32 (fs, 0)) /* lasti*/ + return 0; + if (! fs_write32 (fs, 0)) /* nbehind */ + return 0; + if (! fs_write32 (fs, 0)) /* flags */ + return 0; + if (! fs_write32 (fs, FSMAGIC2)) /* magic word */ + return 0; + fs->dirty = 0; + return 1; +} + +void fs_print (fs_t *fs, FILE *out) +{ + int i; + + fprintf (out, " File: %s\n", fs->filename); + fprintf (out, " Volume size: %u blocks\n", fs->fsize); + fprintf (out, " Inode list size: %u blocks\n", fs->isize); + fprintf (out, " Swap size: %u blocks\n", fs->swapsz); + fprintf (out, " Total free blocks: %u blocks\n", fs->tfree); + fprintf (out, " Total free inodes: %u inodes\n", fs->tinode); + fprintf (out, " Last mounted on: %.*s\n", MAXMNTLEN, + fs->fsmnt[0] ? fs->fsmnt : "(none)"); + fprintf (out, " In-core free list: %u blocks", fs->nfree); + if (verbose) + for (i=0; i < NICFREE && i < fs->nfree; ++i) { + if (i % 10 == 0) + fprintf (out, "\n "); + fprintf (out, " %u", fs->free[i]); + } + fprintf (out, "\n"); + + fprintf (out, " In-core free inodes: %u inodes", fs->ninode); + if (verbose) + for (i=0; i < NICINOD && i < fs->ninode; ++i) { + if (i % 10 == 0) + fprintf (out, "\n "); + fprintf (out, " %u", fs->inode[i]); + } + fprintf (out, "\n"); + if (verbose) { +// fprintf (out, " Free list lock: %u\n", fs->flock); +// fprintf (out, " Inode list lock: %u\n", fs->ilock); +// fprintf (out, "Super block modified: %u\n", fs->fmod); +// fprintf (out, " Mounted read-only: %u\n", fs->ronly); +// fprintf (out, " Circ.search start: %u\n", fs->lasti); +// fprintf (out, " Circ.search behind: %u\n", fs->nbehind); +// fprintf (out, " Mount flags: 0x%x\n", fs->flags); + } + + fprintf (out, " Last update time: %s", ctime (&fs->utime)); +} + +void fs_close (fs_t *fs) +{ + if (fs->fd < 0) + return; + + close (fs->fd); + fs->fd = -1; +} diff --git a/tools/icache/Makefile b/tools/icache/Makefile new file mode 100644 index 0000000..531a077 --- /dev/null +++ b/tools/icache/Makefile @@ -0,0 +1,18 @@ +CC = gcc -g +CFLAGS = -O -Wall +DESTDIR = /usr/local +OBJS = ice2aout.o +PROG = ice2aout + +# For Mac OS X +#LIBS = -largp + +all: $(PROG) + +install: $(PROG) + install -s $(PROG) ${DESTDIR}/bin/$(PROG) +clean: + rm -f *~ *.o *.lst *.dis $(PROG) + +$(PROG): $(OBJS) + $(CC) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) diff --git a/tools/icache/ice2aout.c b/tools/icache/ice2aout.c new file mode 100644 index 0000000..ce3ab28 --- /dev/null +++ b/tools/icache/ice2aout.c @@ -0,0 +1,521 @@ +/* +Copyright (c) 2013, Alexey Frunze +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +The views and conclusions contained in the software and documentation are those +of the authors and should not be interpreted as representing official policies, +either expressed or implied, of the FreeBSD Project. +*/ + +/*****************************************************************************/ +/* */ +/* MIPS ELF to RetroBSD a.out convertor with support for MIPS icache */ +/* */ +/*****************************************************************************/ + +#include +#include +#include +#include +#include +#include + +typedef unsigned char uchar, uint8; +typedef signed char schar, int8; +typedef unsigned short ushort, uint16; +typedef short int16; +#if UINT_MAX >= 0xFFFFFFFF +typedef unsigned uint32; +typedef int int32; +#else +typedef unsigned long uint32; +typedef long int32; +#endif +typedef unsigned uint; +typedef unsigned long ulong; +typedef long long longlong; +typedef unsigned long long ulonglong; +#if ULONG_MAX >= 0xFFFFFFFFFFFFFFFFULL +typedef unsigned long uint64; +typedef long int64; +#else +typedef unsigned long long uint64; +typedef long long int64; +#endif + +#define C_ASSERT(expr) extern char CAssertExtern[(expr)?1:-1] + +C_ASSERT(CHAR_BIT == 8); +C_ASSERT(sizeof(uint16) == 2); +C_ASSERT(sizeof(uint32) == 4); +C_ASSERT(sizeof(uint64) == 8); +C_ASSERT(sizeof(size_t) >= 4); + +#pragma pack(push,1) + +typedef struct +{ + uint8 e_ident[16]; + uint16 e_type; + uint16 e_machine; + uint32 e_version; + uint32 e_entry; + uint32 e_phoff; + uint32 e_shoff; + uint32 e_flags; + uint16 e_ehsize; + uint16 e_phentsize; + uint16 e_phnum; + uint16 e_shentsize; + uint16 e_shnum; + uint16 e_shstrndx; +} Elf32Hdr; + +typedef struct +{ + uint32 sh_name; + uint32 sh_type; + uint32 sh_flags; + uint32 sh_addr; + uint32 sh_offset; + uint32 sh_size; + uint32 sh_link; + uint32 sh_info; + uint32 sh_addralign; + uint32 sh_entsize; +} Elf32SectHdr; + +typedef struct +{ + uint32 a_magic; /* magic number */ +#define OMAGIC 0407 /* old impure format */ + + uint32 a_text; /* size of text segment */ + uint32 a_data; /* size of initialized data */ + uint32 a_bss; /* size of uninitialized data */ + uint32 a_reltext; /* size of text relocation info */ + uint32 a_reldata; /* size of data relocation info */ + uint32 a_syms; /* size of symbol table */ + uint32 a_entry; /* entry point */ +} AoutHdr; + +#pragma pack(pop) + +C_ASSERT(sizeof(Elf32Hdr) == 52); +C_ASSERT(sizeof(Elf32SectHdr) == 40); +C_ASSERT(sizeof(AoutHdr) == 32); + +typedef struct +{ + const char* Name; + uint32 FileOffs; + uint32 Addr; + uint32 Size; + uint32 Flags; + uint32 Flags2; +} tSection; + +tSection* Sections = NULL; +uint SectionCnt = 0; +char* SectNames = NULL; +uint32 EntryPointAddr = 0; + +FILE* ElfFile = NULL; +FILE* AoutFile = NULL; +const char* AoutName = NULL; + +void error(char* format, ...) +{ + va_list vl; + va_start(vl, format); + + if (ElfFile) + fclose(ElfFile); + if (AoutFile) + fclose(AoutFile); + if (AoutName != NULL) + remove(AoutName); + + puts(""); + vprintf(format, vl); + + va_end(vl); + exit(-1); +} + +int SectAddrCompare(const void* pa, const void* pb) +{ + const tSection *p1 = pa, *p2 = pb; + if (p1->Addr < p2->Addr) + return -1; + else if (p1->Addr > p2->Addr) + return +1; + return 0; +} + +void WriteZeroes(FILE* f, uint32 size) +{ + static const char zeroes[1024]; + while (size) + { + uint32 sz; + + if (size > sizeof zeroes) + sz = sizeof zeroes; + else + sz = size; + + if (fwrite(zeroes, 1, sz, f) != sz) + error("Can't write file\n"); + + size -= sz; + } +} + +void CopyFileData(FILE* fto, FILE* ffrom, uint32 size) +{ + char buf[1024]; + while (size) + { + uint32 sz; + + if (size > sizeof buf) + sz = sizeof buf; + else + sz = size; + + if (fread(buf, 1, sz, ffrom) != sz) + error("Can't read file\n"); + + if (fwrite(buf, 1, sz, fto) != sz) + error("Can't write file\n"); + + size -= sz; + } +} + +int main(int argc, char** argv) +{ + Elf32Hdr elfHdr; + Elf32SectHdr sectHdr; + uint idx; + int unsupported = 0; + int verbose = 0; + AoutHdr aoutHdr; + uint32 addr; + uint32 endAddr = 0, codeEndAddr, bssStartAddr; + + if (argc > 1 && !strcmp(argv[1], "-v")) + { + verbose = 1; + argc--; + argv++; + } + + if (argc != 3 || + !(ElfFile = fopen(argv[1], "rb")) || + !(AoutFile = fopen(AoutName = argv[2], "wb"))) + error("Usage:\n ice2aout [-v] \n"); + + if (fread(&elfHdr, 1, sizeof elfHdr, ElfFile) != sizeof elfHdr) + error("Can't read file\n"); + + if (memcmp(elfHdr.e_ident, "\x7F""ELF", 4)) + error("Not an ELF file\n"); + if (elfHdr.e_ident[6] != 1) + error("Not a v1 ELF file\n"); + if (elfHdr.e_ehsize != sizeof elfHdr) + error("Unexpected ELF header size\n"); + if (elfHdr.e_shentsize != sizeof sectHdr) + error("Unexpected ELF section size\n"); + + if (elfHdr.e_ident[4] != 1) + error("Not a 32-bit file\n"); + if (elfHdr.e_ident[5] != 1) + error("Not a little-endian file\n"); + if (elfHdr.e_type != 2) + error("Not an executable file\n"); + if (elfHdr.e_machine != 8) + error("Not a MIPS executable\n"); + + if (fseek(ElfFile, elfHdr.e_shoff + elfHdr.e_shstrndx * sizeof sectHdr, SEEK_SET)) + error("Can't read file\n"); + if (fread(§Hdr, 1, sizeof sectHdr, ElfFile) != sizeof sectHdr) + error("Can't read file\n"); + + if ((SectNames = malloc(sectHdr.sh_size)) == NULL) + error("Out of memory\n"); + + if (fseek(ElfFile, sectHdr.sh_offset, SEEK_SET)) + error("Can't read file\n"); + if (fread(SectNames, 1, sectHdr.sh_size, ElfFile) != sectHdr.sh_size) + error("Can't read file\n"); + + if ((Sections = calloc(1, (elfHdr.e_shnum + 1) * sizeof(tSection))) == NULL) + error("Out of memory\n"); + + for (idx = 0; idx < elfHdr.e_shnum; idx++) + { + const char* name = ""; + + if (fseek(ElfFile, elfHdr.e_shoff + idx * sizeof sectHdr, SEEK_SET)) + error("Can't read file\n"); + if (fread(§Hdr, 1, sizeof sectHdr, ElfFile) != sizeof sectHdr) + error("Can't read file\n"); + if (sectHdr.sh_type == 0) + memset(§Hdr, 0, sizeof sectHdr); + + if (sectHdr.sh_name) + name = SectNames + sectHdr.sh_name; + + unsupported |= + (!strcmp(name, ".dynsym") || + !strcmp(name, ".dynstr") || + !strcmp(name, ".dynamic") || + !strcmp(name, ".hash") || + !strcmp(name, ".got") || + !strcmp(name, ".plt") || + sectHdr.sh_type == 5 || // SHT_HASH + sectHdr.sh_type == 6 || // SHT_DYNAMIC + sectHdr.sh_type == 11); // SHT_DYNSYM + + // Keep only allocatable sections of non-zero size + if ((sectHdr.sh_flags & 2) && sectHdr.sh_size) // SHF_ALLOC and size > 0 + { + Sections[SectionCnt].FileOffs = 0; + Sections[SectionCnt].Name = name; + Sections[SectionCnt].Addr = sectHdr.sh_addr; + Sections[SectionCnt].Size = sectHdr.sh_size; + Sections[SectionCnt].Flags = (sectHdr.sh_flags & 1) | ((sectHdr.sh_flags & 4) >> 1); // bit0=Writable,bit1=eXecutable + + if (sectHdr.sh_type == 1) // SHT_PROGBITS + { + Sections[SectionCnt].FileOffs = sectHdr.sh_offset; + } + + SectionCnt++; + } + } + + EntryPointAddr = elfHdr.e_entry; + + // Sort sections by address as we'll need them in order + // and without gaps inbetween + qsort(Sections, SectionCnt, sizeof Sections[0], &SectAddrCompare); + + if (verbose) + { + printf(" # XAW VirtAddr FileOffs Size Name\n"); + for (idx = 0; idx < SectionCnt; idx++) + { + tSection* p = &Sections[idx]; + printf("%2u %c%c%c 0x%08lX 0x%08lX %10lu %s\n", + idx, + "-X"[(p->Flags / 2) & 1], + "-A"[1], + "-W"[(p->Flags / 1) & 1], + (ulong)p->Addr, + (ulong)p->FileOffs, + (ulong)p->Size, + p->Name); + } + printf("Entry: 0x%08lX\n", (ulong)EntryPointAddr); + puts(""); + } + + if (unsupported) + error("Dynamically linked or unsupported type of executable\n"); + + // Write an empty a.out header at first, it will be updated later + memset(&aoutHdr, 0, sizeof aoutHdr); + if (fwrite(&aoutHdr, 1, sizeof aoutHdr, AoutFile) != sizeof aoutHdr) + error("Can't write file\n"); + +#define USER_DATA_START 0x7F008000 +#define MAXMEM (96*1024) +#define USER_DATA_END (USER_DATA_START + MAXMEM) + + if (verbose) + printf("Phase 1: Processing sections in the range 0x%08lX ... 0x%08lX ...\n", + (ulong)USER_DATA_START, (ulong)USER_DATA_END - 1); + + addr = USER_DATA_START; + + // Copy non-cached sections + for (idx = 0; idx < SectionCnt; idx++) + { + tSection* p = &Sections[idx]; + + if (p->Addr + p->Size >= p->Addr && + p->Addr >= USER_DATA_START && + p->Addr + p->Size <= USER_DATA_END) + { + if (verbose) + printf("Copying %s ...\n", p->Name); + + if (idx && (Sections[idx - 1].Flags2 & 1)) + { + if (p->Addr < Sections[idx - 1].Addr + Sections[idx - 1].Size) + error("Sections must not intersect in memory\n"); + if ((p->Flags & 2) && !(Sections[idx - 1].Flags & 2)) // executable after non-executable + error("Code sections must precede data sections in memory\n"); + } + if ((p->Flags & 2) && !p->FileOffs) // executable and initialized to all zeroes + error("Code sections must not be initialized to all zeroes\n"); + + // If this section has code/data in it, if it's not initialized to all zeroes... + if (p->FileOffs) + { + // Fill inter-section gaps (and .bss-like sections that aren't at the end) + // with zeroes. This lets me order sections more flexibly and yet make + // sure they all are properly initialized. + if (addr < p->Addr) + { + WriteZeroes(AoutFile, p->Addr - addr); + addr = p->Addr; + } + + // Copy section + if (fseek(ElfFile, p->FileOffs, SEEK_SET)) + error("Can't read file\n"); + CopyFileData(AoutFile, ElfFile, p->Size); + addr += p->Size; + } + + p->Flags2 |= 1; // section has been processed + + endAddr = p->Addr + p->Size; + } + else + { + if (verbose) + printf("Skipping %s ...\n", p->Name); + } + } + + if (endAddr == 0) + error("There are no copiable sections in this range\n"); + + if (verbose) + printf("Phase 2: Processing sections outside the range 0x%08lX ... 0x%08lX ...\n", + (ulong)USER_DATA_START, (ulong)USER_DATA_END - 1); + + // Append cached section(s) + for (idx = 0; idx < SectionCnt; idx++) + { + tSection* p = &Sections[idx]; + + if (p->Addr + p->Size >= p->Addr && + (p->Addr >= USER_DATA_END || + p->Addr + p->Size <= USER_DATA_START)) + { + if (verbose) + printf("Copying %s ...\n", p->Name); + + // Copy section + if (p->FileOffs) + { + if (fseek(ElfFile, p->FileOffs, SEEK_SET)) + error("Can't read file\n"); + CopyFileData(AoutFile, ElfFile, p->Size); + } + + p->Flags2 |= 1; // section has been processed + } + } + + // Make sure no section has been left unprocessed + for (idx = 0; idx < SectionCnt; idx++) + { + tSection* p = &Sections[idx]; + if (!(p->Flags2 & 1)) + error("Not all sections have been processed, e.g. %s hasn't\n", p->Name); + } + + // Update a.out header + aoutHdr.a_magic = OMAGIC; + aoutHdr.a_entry = EntryPointAddr; + + codeEndAddr = endAddr; + + for (idx = SectionCnt - 1; idx != (uint)-1; idx--) + { + tSection* p = &Sections[idx]; + + if (p->Addr + p->Size >= p->Addr && + p->Addr >= USER_DATA_START && + p->Addr + p->Size <= USER_DATA_END) + { + // While not executable, keep going, executable sections are first + if (!(p->Flags & 2)) + codeEndAddr = p->Addr; + else + break; + } + } + + bssStartAddr = endAddr; + + for (idx = SectionCnt - 1; idx != (uint)-1; idx--) + { + tSection* p = &Sections[idx]; + + if (p->Addr + p->Size >= p->Addr && + p->Addr >= USER_DATA_START && + p->Addr + p->Size <= USER_DATA_END) + { + // While initialized to all zeroes, keep going + if (!p->FileOffs) + bssStartAddr = p->Addr; + else + break; + } + } + + aoutHdr.a_text = codeEndAddr - USER_DATA_START; + aoutHdr.a_data = bssStartAddr - codeEndAddr; + aoutHdr.a_bss = endAddr - bssStartAddr; + + if (fseek(AoutFile, 0, SEEK_SET)) + error("Can't write file\n"); + if (fwrite(&aoutHdr, 1, sizeof aoutHdr, AoutFile) != sizeof aoutHdr) + error("Can't write file\n"); + + if (fclose(AoutFile)) + error("Can't write file\n"); + fclose(ElfFile); + + if (verbose) + { + printf("a.out header:\n" + " text size: %lu\n" + " data size: %lu\n" + " bss size: %lu\n", + (ulong)aoutHdr.a_text, + (ulong)aoutHdr.a_data, + (ulong)aoutHdr.a_bss); + printf("Done\n"); + } + + return 0; +} diff --git a/tools/icache/license.txt b/tools/icache/license.txt new file mode 100644 index 0000000..449e8ed --- /dev/null +++ b/tools/icache/license.txt @@ -0,0 +1,26 @@ +Copyright (c) 2013, Alexey Frunze +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +The views and conclusions contained in the software and documentation are those +of the authors and should not be interpreted as representing official policies, +either expressed or implied, of the FreeBSD Project. diff --git a/tools/icache/readme.txt b/tools/icache/readme.txt new file mode 100644 index 0000000..8cdb63b --- /dev/null +++ b/tools/icache/readme.txt @@ -0,0 +1,10 @@ +icache is a MIPS emulator + software instruction cache. + +With it one may be able to run large programs on MIPS32 processors +that would otherwise not fit into small on-chip RAMs of ~128KB. + +Supported platform: RetroBSD. +http://www.retrobsd.org/ + +See the Wiki for more up-to-date details: +http://github.com/alexfru/icacheMips/wiki diff --git a/tools/libufs/Makefile b/tools/libufs/Makefile new file mode 100644 index 0000000..582ca3d --- /dev/null +++ b/tools/libufs/Makefile @@ -0,0 +1,20 @@ +LOBJS=fs.o util.o fops.o set.o +CFLAGS=-Wall -Werror -ggdb3 +PROGS=umkfs umkdir uls uchmod uchown uchgrp ulogin ucd ucat +POBJS=umkfs.o umkdir.o uls.o uchmod.o uchown.o uchgrp.o ulogin.o ucd.o ucat.o +LDFLAGS=-L. -lufs -ggdb3 +CC=gcc +ARFLAGS=-cr + +LIB=libufs.a + +all: $(LIB) $(PROGS) + +$(LIB): $(LOBJS) + $(AR) $(ARFLAGS) $(LIB) $(LOBJS) + +$(PROGS): $(POBJS) $(LIB) + $(CC) -o $@ $@.o $(LDFLAGS) + +clean: + rm -f $(LIB) $(LOBJS) $(PROGS) $(POBJS) diff --git a/tools/libufs/fops.c b/tools/libufs/fops.c new file mode 100644 index 0000000..dcd8420 --- /dev/null +++ b/tools/libufs/fops.c @@ -0,0 +1,665 @@ +#include +#include +#include +#include +#include +#include +#include +#include "libufs.h" + +// Split a path into an array of char pointers, each +// one containing an element of the path, +char **splitpath(char *path, int *ndir) +{ + char *p,*q; + int dn = 0; + char **dirs; + *ndir = 0; + + p = path; + while (*p == '/') + p++; + + while (*(p+strlen(p)-1) == '/') { + *(p+strlen(p)-1) = '\0'; + } + + // First count the number of entries we have + q = p; + for ( ; *p; p++) { + if (*p == '/') { + (*ndir)++; + } + } + + if(*q) + (*ndir)++; + p = q; + + // Then allocate enough space for them + dirs = malloc(*ndir * sizeof(char *)); + + // Now do the actual splitting. + for ( ; *p; p++) { + if ((*p) == '/') { + *p = 0; + dirs[dn] = q; + p++; + dn++; + q = p; + } + } + + if (*q) { + dirs[dn] = q; + dn++; + } + if (dn != *ndir) { + printf("Something odd happened to the path\n"); + } + + return dirs; +} + +unsigned int getfileinode(struct filesystem *f, struct inode *in, char *fn) +{ + unsigned int ino = 0; + char *buf; + char *d; + struct direct *de; + + buf = fsreadblock(f, in->i_db[0]); + if (!buf) { + printf("Bad read\n"); + return 0; + } + + d = buf; + de = (struct direct *)d; + while ((de < (struct direct *)(buf+DEV_BSIZE)) && (de->d_ino != 0)) { + if (!strcmp(de->d_name, fn)) { + ino = de->d_ino; + break; + } + d += de->d_reclen; + de = (struct direct *)d; + } + + free(buf); + + return ino; +} + +struct inode *inodebypath(struct filesystem *f, char *path) +{ + char **dirs = NULL; + int ndir = 0; + int i; + struct inode *in = f->root; + char *p = strdup(path); + int ino __attribute__((unused)); + + dirs = splitpath(p, &ndir); + + if (ndir == 0) { + free(dirs); + free(p); + return f->root; + } + + for (i = 0; i < ndir; i++) { + ino = getfileinode(f, in, dirs[i]); + if (ino != 0) { + if (in != f->root) { + free(in); + } + in = fsreadinode(f, ino); + } else { + free(p); + free(dirs); + if (in != f->root) { + free(in); + } + return 0; + } + } + free(p); + free(dirs); + return in; +} + +struct inode *inodebypartpath(struct filesystem *f, char *path, int *depth) +{ + char **dirs = NULL; + int ndir = 0; + int i; + struct inode *in = f->root; + char *p = strdup(path); + int ino __attribute__((unused)); + + if(depth) + *depth = 0; + + dirs = splitpath(p, &ndir); + + for (i = 0; i < ndir; i++) { + ino = getfileinode(f, in, dirs[i]); + if (ino != 0) { + if (in != f->root) { + free(in); + } + in = fsreadinode(f, ino); + if(depth) + (*depth)++; + } else { + printf("Not found\n"); + free(p); + free(dirs); + return in; + } + } + free(p); + free(dirs); + return in; +} + +void listdir(struct filesystem *f, ino_t ino) +{ + struct inode *in; + struct inode *ip; + char *buf; + int i; + char c; + char *d; + struct direct *dp; + struct tm *tmp; + char tbuf[22]; + + in = fsreadinode(f, ino); + + for (i = 0; i < NADDR; i++) { + if (in->i_db[i] > 0) { + buf = fsreadblock(f, in->i_db[i]); + + d = buf; + while ((d - buf) < DEV_BSIZE) { + dp = (struct direct *)d; + ip = fsreadinode(f, dp->d_ino); + + switch (ip->i_mode & IFMT) { + case IFBLK: + printf("b"); + break; + case IFCHR: + printf("c"); + break; + case IFDIR: + printf("d"); + break; + case IFLNK: + printf("l"); + break; + default: + printf("-"); + break; + } + + c = '-'; + if (ip->i_mode & 0400) + c = 'r'; + printf("%c", c); + + c = '-'; + if (ip->i_mode & 0200) + c = 'w'; + printf("%c", c); + + c = '-'; + if (ip->i_mode & 0100) + c = 'x'; + if (ip->i_mode & 04000) + c = 's'; + printf("%c", c); + + c = '-'; + if (ip->i_mode & 0040) + c = 'r'; + printf("%c", c); + + c = '-'; + if (ip->i_mode & 0020) + c = 'w'; + printf("%c", c); + + c = '-'; + if (ip->i_mode & 0010) + c = 'x'; + if (ip->i_mode & 02000) + c = 's'; + printf("%c", c); + + c = '-'; + if (ip->i_mode & 0004) + c = 'r'; + printf("%c", c); + + c = '-'; + if (ip->i_mode & 0002) + c = 'w'; + printf("%c", c); + + c = '-'; + if (ip->i_mode & 0001) + c = 'x'; + if (ip->i_mode & 01000) + c = 't'; + printf("%c", c); + + printf(" %5u", ip->i_number); + printf(" %8lu", ip->i_size); + + tmp = localtime(&ip->i_mtime); + strftime(tbuf, 20, "%Y-%m-%d %H:%M", tmp); + + printf(" %s", tbuf); + printf(" %s", dp->d_name); +#if 0 + printf("\n "); + + for (i=0; ii_addr[i]); + } +#endif + printf("\n"); + + + d += dp->d_reclen; + free(ip); + } + free(buf); + } + } + free(in); +} + +struct inode *adddirectory(struct filesystem *f, struct inode *in, char *name) +{ + char *buf; + char *d; + struct direct *dp; + int bno; + struct inode *ip; + ino_t ino = fsinodealloc(f); + int rem; + + int i = 0; + + if (!(in->i_mode & IFDIR)) { + errno = ENOTDIR; + return NULL; + } + + if (ino == 0) { + printf("Could not allocate inode\n"); + errno = ENOSPC; + return NULL; + } + + // Create the new directory + + bno = fsblockalloc(f); + + if (bno == 0) { + errno = ENOSPC; + return NULL; + } + + rem = DEV_BSIZE; + buf = malloc(DEV_BSIZE); + d = buf; + + dp = (struct direct *)d; + dp->d_ino = ino; + dp->d_namlen = 1; + dp->d_name[0] = '.'; dp->d_name[1] = '\0'; + dp->d_reclen = DIRSIZ(dp); + rem -= dp->d_reclen; + d += dp->d_reclen; + dp = (struct direct *)d; + dp->d_ino = in->i_number; + dp->d_namlen = 2; + dp->d_name[0] = '.'; dp->d_name[1] = '.'; dp->d_name[2] = '\0'; + dp->d_reclen = rem; + + fswriteblock(f, bno, buf); + free(buf); + + ip = malloc(sizeof(struct inode)); + + for (i = 0; i < NADDR; i++) + ip->i_db[i] = 0; + + ip->i_number = ino; + ip->i_db[0] = bno; + ip->i_mode = IFDIR | 0755; + ip->i_uid = 0; + ip->i_gid = 0; + ip->i_nlink = 2; + ip->i_size = DEV_BSIZE; + ip->i_atime = time(NULL); + ip->i_ctime = time(NULL); + ip->i_mtime = time(NULL); + fswriteinode(f, ip); + + // insert the new directory into the parent + + buf = fsreadblock(f, in->i_db[0]); + if (!buf) { + printf("Bad read\n"); + errno = EIO; + return NULL; + } + + d = buf; + rem = DEV_BSIZE; + while ((d - buf) < DEV_BSIZE) { + dp = (struct direct *)d; + printf("inode %d (%d %d)\n", (int)dp->d_ino, (int)dp->d_reclen, sizeof(struct direct)); + if (dp->d_reclen != DIRSIZ(dp)) { + if (dp->d_ino != 0) { + dp->d_reclen = DIRSIZ(dp); + rem -= dp->d_reclen; + d += dp->d_reclen; + dp = (struct direct *)d; + } + dp->d_ino = ino; + dp->d_namlen = strlen(name); + bcopy(name, dp->d_name, strlen(name)); + dp->d_reclen = rem; + if (!fswriteblock(f, in->i_db[0], buf)) { + errno = EIO; + free(ip); + free(buf); + return NULL; + } + in->i_nlink++; + fswriteinode(f, in); + free(buf); + return ip; + } + i++; + rem -= dp->d_reclen; + d += dp->d_reclen; + } + free(ip); + free(buf); + errno = ENOSPC; + return NULL; +} + +int umkdir(struct filesystem *f, char *path) +{ + struct inode *in; + struct inode *ip; + int sd; + int i; + char *p = strdup(path); + int ndir; + char **dirs = splitpath(p, &ndir); + + in = inodebypartpath(f, path, &sd); + + if (sd == ndir) { + if (in != f->root) { + free(in); + } + free(p); + free(dirs); + errno = EEXIST; + return 0; + } + + for (i = sd; i < ndir; i++) + { + ip = adddirectory(f, in, dirs[i]); + if (in != f->root) { + free(in); + } + if (!ip) { + free(p); + free(dirs); + return 0; + } + in = ip; + } + if (in != f->root) { + free(in); + } + free(p); + free(dirs); + + return 1; +} + +int uls(struct filesystem *f, char *path) +{ + struct inode *in; + + in = inodebypath(f, path); + if (!in) { + errno = ENOENT; + return 0; + } + listdir(f, in->i_number); + if (in != f->root) + free(in); + return 1; +} + +int uchmod(struct filesystem *f, char *path, int mode) +{ + struct inode *in; + char *p = strdup(path); + int ndir; + char **dirs = splitpath(p, &ndir); + free(p); + free(dirs); + + in = inodebypath(f, path); + + if (!in) { + errno = ENOENT; + return 0; + } + + in->i_mode &= ~07777; + in->i_mode |= (mode & 07777); + fswriteinode(f, in); + free(in); + return 1; +} + +int uchown(struct filesystem *f, char *path, int uid) +{ + struct inode *in; + char *p = strdup(path); + int ndir; + char **dirs = splitpath(p, &ndir); + free(p); + free(dirs); + + in = inodebypath(f, path); + + if (!in) { + errno = ENOENT; + return 0; + } + + in->i_uid = uid; + fswriteinode(f, in); + free(in); + return 1; +} + +int uchgrp(struct filesystem *f, char *path, int gid) +{ + struct inode *in; + char *p = strdup(path); + int ndir; + char **dirs = splitpath(p, &ndir); + free(p); + free(dirs); + + in = inodebypath(f, path); + + if (!in) { + errno = ENOENT; + return 0; + } + + in->i_mode = gid; + fswriteinode(f, in); + free(in); + return 1; +} + +int uftruncate(UFILE *file) +{ + return 1; +} + +struct inode *fscreatefile(struct filesystem *f, char *path) +{ + return NULL; +} + +UFILE *ufopen(struct filesystem *f, char *path, char *mode) +{ + UFILE *file = malloc(sizeof(UFILE)); + file->f = f; + file->in = inodebypath(f, path); + file->readoffset = 0; + file->writeoffset = 0; + file->perm = 0; + + if (!strcmp(mode, "r")) { + if (!file->in) { + return 0; + } + file->readoffset = 0; + file->writeoffset = 0; + file->perm = O_RDONLY; + } + + if (!strcmp(mode, "r+")) { + if (!file->in) { + return 0; + } + file->readoffset = 0; + file->writeoffset = 0; + file->perm = O_RDWR; + } + + if (!strcmp(mode, "w")) { + if (!file->in) { + return 0; + } + uftruncate(file); + file->readoffset = 0; + file->writeoffset = 0; + file->perm = O_WRONLY; + } + + if (!strcmp(mode, "w+")) { + if (!file->in) { + file->in = fscreatefile(f, path); + } else { + uftruncate(file); + } + file->readoffset = 0; + file->writeoffset = 0; + file->perm = O_RDWR; + } + + if (!strcmp(mode, "a")) { + if (!file->in) { + file->in = fscreatefile(f, path); + } + file->readoffset = file->in->i_size; + file->writeoffset = file->in->i_size; + file->perm = O_WRONLY; + } + + if (!strcmp(mode, "a+")) { + if (!file->in) { + file->in = fscreatefile(f, path); + } + file->readoffset = 0; + file->writeoffset = file->in->i_size; + file->perm = O_RDWR; + } + + return file; +} + +void ufclose(UFILE *f) +{ + if (f->in) { + free(f->in); + } + free(f); +} + +int ufgetc(UFILE *f) +{ + unsigned char *buf; + int bno; + int offset; + unsigned int addr; + int c; + int *ib; + + if (f->readoffset >= f->in->i_size) { + return EOF; + } + bno = f->readoffset / DEV_BSIZE; + offset = f->readoffset - (bno * DEV_BSIZE); + + + if (bno < NADDR-3) { + addr = f->in->i_db[bno]; + } else { + bno -= NADDR-3; + // First level indirect + if (bno < DEV_BSIZE / 4) { + buf = fsreadblock(f->f, f->in->i_db[NADDR-3]); + ib = (daddr_t *)buf; + addr = ib[bno]; + free(buf); + } else { + bno -= (DEV_BSIZE / 4); + // Double indirect + if (bno < ((DEV_BSIZE / 4) * (DEV_BSIZE / 4))) { + buf = fsreadblock(f->f, f->in->i_db[NADDR-2]); + ib = (daddr_t *)buf; + addr = ib[bno / (DEV_BSIZE / 4)]; + free(buf); + buf = fsreadblock(f->f, addr); + ib = (daddr_t *)buf; + addr = ib[bno - ((bno / (DEV_BSIZE / 4)) * (DEV_BSIZE / 4))]; + free(buf); + } else { + // It gets horrible now - triple indirect. + } + } + } + + buf = fsreadblock(f->f, addr); + if (!buf) { + return -EIO; + } + f->readoffset++; + c = buf[offset]; + free(buf); + return c; +} diff --git a/tools/libufs/fs.c b/tools/libufs/fs.c new file mode 100644 index 0000000..f638be1 --- /dev/null +++ b/tools/libufs/fs.c @@ -0,0 +1,464 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "libufs.h" + +void inodemap(void *buf) +{ + int i; + struct inode *in; + + for (i = 0; i < INOPB; i++) { + in = (struct inode *)(buf + (i * sizeof(struct inode))); + printf("%lu\n", (unsigned long)in->i_number); + } +} + +// Convert an array of direct structures into a filesysem block +// representing a directory structure containing those direct +// structures as the content +int32_t makedir(struct direct *protodir, int entries, void *buf) +{ + char *cp; + int i, spcleft; + + spcleft = DIRBLKSIZ; + for (cp = buf, i = 0; i < entries - 1; i++) { + protodir[i].d_reclen = DIRSIZ(&protodir[i]); + bcopy(&protodir[i], cp, protodir[i].d_reclen); + cp += protodir[i].d_reclen; + spcleft -= protodir[i].d_reclen; + } + protodir[i].d_reclen = spcleft; + bcopy(&protodir[i], cp, DIRSIZ(&protodir[i])); + for (i=0; ifs); +} + +u_int32_t fsinodealloc(struct filesystem *f) +{ + u_int32_t ino; + // are there any known free inodes? + struct inode *in; + u_int32_t ninode = 0; + +badino: + if (f->fs->fs_ninode > 0) { + ino = f->fs->fs_inode[--f->fs->fs_ninode]; + // An inode number below ROOTINO is not valid. + if (ino <= ROOTINO) { + goto badino; + } + + in = malloc(sizeof(struct inode)); + bzero(in, sizeof(struct inode)); + in->i_number = ino; + fswriteinode(f, in); + free(in); + f->fs->fs_tinode--; + fssync(f); + return ino; + } + // We couldn't get an inode, so we need to scrape the filesystem + // for more. + + printf("Not able to get an inode - scraping\n"); + + + // First, let's find a good inode for ourselves... + for (ino = ROOTINO+1; itod(ino) < f->fs->fs_isize; ino++) { + in = fsreadinode(f, ino); + if (in->i_mode == 0) { + bzero(in, sizeof(struct inode)); + in->i_number = ino; + fswriteinode(f, in); + ninode = ino; + f->fs->fs_tinode--; + fssync(f); + free(in); + break; + } + free(in); + } + + printf("Got inode %lu\n", (unsigned long)ninode); + + // Did it work? + if (ninode == 0) { + printf("Error: out of inodes\n"); + return 0; + } + + // Now to find a free one. + for (ino = ninode+1; itod(ino) < f->fs->fs_isize; ino++) { + in = fsreadinode(f, ino); + if (in->i_mode == 0) { + f->fs->fs_inode[f->fs->fs_ninode++] = ino; + if (f->fs->fs_ninode == NICINOD) + break; + } + } + + fssync(f); + + return ninode; +} + +int64_t fsblockalloc(struct filesystem *f) +{ + int64_t bno; + + if (f->fs->fs_tfree == 0) { + printf("disk full\n"); + return 0; + } + + if (f->fs->fs_nfree == 0) { + printf("no free space and no scraping yet\n"); + return 0; + } + + f->fs->fs_tfree--; + bno = f->fs->fs_free[--f->fs->fs_nfree]; + fssync(f); + return (bno); +} + +void *fsreadblock(struct filesystem *f, int64_t bno) +{ + int n; + int64_t offset; + + char *buf = malloc(DEV_BSIZE); + if (!buf) { + printf("Unable to allocate buffer!!!!!\n"); + return NULL; + } + + offset = (int64_t) bno*DEV_BSIZE; + if (lseek(f->fd, offset, 0) != offset) { + printf("lseek read error: %lu\n", (unsigned long)bno); + free(buf); + return NULL; + } + n = read(f->fd, buf, DEV_BSIZE); + if (n != DEV_BSIZE) { + printf("read error: %ld\n", (long)bno); + free(buf); + return NULL; + } + return buf; +} + +int fswriteblock(struct filesystem *f, int64_t bno, void *buf) +{ + int n; + int64_t offset; + + offset = (int64_t) bno*DEV_BSIZE; + if (lseek(f->fd, offset, 0) != offset) { + printf ("lseek failed on block number %lu, offset=%lu\n", (unsigned long)bno, (unsigned long)offset); + return 0; + } + n = write(f->fd, buf, DEV_BSIZE); + if (n != DEV_BSIZE) { + printf("write error: %ld\n", (long)bno); + return 0; + } + return 1; +} + +struct inode *fsreadinode(struct filesystem *f, int64_t ino) +{ + char *buf; + struct inode *i; + int64_t off; + struct dinode *dp; + int n; + + buf = fsreadblock(f, itod(ino)); + if (!buf) { + printf("Failed reading inode block\n"); + return NULL; + } + + i = malloc(sizeof(struct inode)); + off = itoo(ino); + + dp = (struct dinode *)(buf + (sizeof(struct dinode) * off)); + i->i_number = ino; + i->i_ic1 = dp->di_icom1; + i->i_flags = dp->di_flags; + i->i_ic2 = dp->di_icom2; + for (n = 0; n < NADDR; n++) + i->i_addr[n] = dp->di_addr[n]; + + free(buf); + + return i; +} + +int fswriteinode(struct filesystem *f, struct inode *ip) +{ + char *buf; + struct dinode *dp; + int64_t d; + int n; + + d = itod(ip->i_number); + if (d >= f->fs->fs_isize) { + printf("ilist too small\n"); + return 0; + } + buf = fsreadblock(f, d); + if (!buf) { + return 0; + } + + dp = (struct dinode *)(buf + (itoo(ip->i_number) * sizeof(struct dinode))); + + dp->di_icom1 = ip->i_ic1; + dp->di_flags = ip->i_flags; + dp->di_icom2 = ip->i_ic2; + for (n = 0; n < NADDR; n++) + dp->di_addr[n] = ip->i_addr[n]; + + if (!fswriteblock(f, d, buf)) { + free(buf); + return 0; + } + free(buf); + return 1; +} + + +void fsfreeblock(struct filesystem *f, int64_t bno) +{ + if (bno != 0) + f->fs->fs_tfree++; + if (f->fs->fs_nfree < NICFREE) { + f->fs->fs_free[f->fs->fs_nfree++] = bno; + } + fssync(f); +} + +struct filesystem *fsopen(char *filename) +{ + struct filesystem *f; + f = malloc(sizeof(struct filesystem)); + + f->fd = open(filename, O_RDWR); + if (!f->fd) { + free(f); + return NULL; + } + + f->fs = (struct fs *)fsreadblock(f, SUPERB); + if (!f->fs) { + printf("%s: Bad superblock\n", filename); + free(f); + return NULL; + } + + f->root = fsreadinode(f, ROOTINO); + if (!f->root) { + printf("%s: Bad root directory\n", filename); + free(f->fs); + free(f); + return NULL; + } + return f; +} + +void fsclose(struct filesystem *f) +{ + if (!f) + return; + + if (f->fd) { + if (f->fs) { + fswriteblock(f, SUPERB, f->fs); + } + close(f->fd); + } + + if (f->root) + free(f->root); + + if (f->fs) + free(f->fs); + free(f); +} + +void bfree(struct filesystem *f, int64_t bno) +{ + register int i; + struct fblk *fb = malloc(DEV_BSIZE); + + if (bno != 0) + f->fs->fs_tfree++; + if (f->fs->fs_nfree >= NICFREE) { + fb->df_nfree = f->fs->fs_nfree; + for (i=0; idf_free[i] = f->fs->fs_free[i]; + fswriteblock(f, bno, fb); + printf("Writing free list to %d\n", (int)bno); + f->fs->fs_nfree = 0; + } + f->fs->fs_free[f->fs->fs_nfree++] = bno; +} + +void bflist(struct filesystem *f) +{ + struct inode in; + int64_t d; + + bzero(&in, sizeof (in)); + in.i_number = 1; /* inode 1 is a historical hack */ + in.i_mode = IFREG; + fswriteinode(f, &in); + + bfree(f, (int64_t)0); + d = f->fs->fs_fsize; + while (--d >= f->fs->fs_isize + f->fs->fs_swapsz) { + bfree(f, d); + } + printf("Resultant free list size %d\n", f->fs->fs_nfree); +} + +struct filesystem *fsnew(char *filename, unsigned int blocks, unsigned int bpi) +{ + struct filesystem *f; + unsigned int i; + char *buffer; + + f = malloc(sizeof(DEV_BSIZE)); + + f->fd = open(filename, O_RDWR | O_TRUNC | O_CREAT, 0644); + if (!f->fd) { + free(f); + return NULL; + } + + buffer = malloc(DEV_BSIZE); + bzero(buffer, DEV_BSIZE); + + for (i=0; ifs = malloc(DEV_BSIZE); + f->fs->fs_fsize = blocks; + + fsformat(f, bpi); + return f; +} + +int fsformat(struct filesystem *f, int bpi) +{ + unsigned int nino; + char *buffer = malloc(DEV_BSIZE); + unsigned int i; + + nino = (f->fs->fs_fsize * DEV_BSIZE / bpi) / INOPB; + if (nino <= 0) { + nino = 1; + } + + f->fs->fs_isize = nino+1; + f->fs->fs_swapsz = 0; + f->fs->fs_time = time(NULL); + f->fs->fs_magic1 = FSMAGIC1; + f->fs->fs_magic2 = FSMAGIC2; + f->fs->fs_tfree = 0; + f->fs->fs_tinode = 0; + f->fs->fs_ninode = 0; + f->fs->fs_nfree = 0; + + bzero(buffer, DEV_BSIZE); + + for (i = SUPERB+1; i != f->fs->fs_isize; i++) { + if (!fswriteblock(f, i, buffer)) { + close(f->fd); + free(f->fs); + free(buffer); + return 0; + } + f->fs->fs_tinode += INOPB; + } + + bflist(f); + + fsinit(f); + + free(buffer); + return 1; +} + +void fsinit(struct filesystem *f) +{ + int i; + struct inode node; + char *buf = malloc(DEV_BSIZE); + time_t utime; + + struct direct lost_found_dir[] = { + { LOSTFOUNDINO, sizeof(struct direct), 1, "." }, + { ROOTINO, sizeof(struct direct), 2, ".." }, + { 0, DIRBLKSIZ, 0, "" }, + }; + + struct direct root_dir[] = { + { ROOTINO, sizeof(struct direct), 1, "." }, + { ROOTINO, sizeof(struct direct), 2, ".." }, + { LOSTFOUNDINO, sizeof(struct direct), 10, "lost+found" }, + { 0, DIRBLKSIZ, 0, "" }, + }; + + utime = time(NULL); + + node.i_atime = utime; + node.i_mtime = utime; + node.i_ctime = utime; + + makedir(lost_found_dir, 2, buf); + for (i = DIRBLKSIZ; i < DEV_BSIZE; i += DIRBLKSIZ) + bcopy(&lost_found_dir[2], &buf[i], DIRSIZ(&lost_found_dir[2])); + + node.i_number = LOSTFOUNDINO; + node.i_mode = IFDIR | 0755; + node.i_nlink = 2; + node.i_size = DEV_BSIZE; + node.i_db[0] = fsblockalloc(f); + + fswriteblock(f, node.i_db[0], buf); + fswriteinode(f, &node); + + node.i_number = ROOTINO; + node.i_mode = IFDIR | 0755; + node.i_nlink = 3; + node.i_size = makedir(root_dir, 3, buf); + node.i_db[0] = fsblockalloc(f); + + fswriteblock(f, node.i_db[0], buf); + fswriteinode(f, &node); + + free(buf); +} + diff --git a/tools/libufs/libufs.h b/tools/libufs/libufs.h new file mode 100644 index 0000000..fb08b98 --- /dev/null +++ b/tools/libufs/libufs.h @@ -0,0 +1,350 @@ +#ifndef _LIBUFS_H +#define _LIBUFS_H + +#include + +#define dev_t int +#define ino_t u_int +#define time_t long + +#define DEV_BSIZE 1024 // Block size +#define BPI (16 * DEV_BSIZE) // Bytes per inode +#define ROOTINO ((u_int)2) // i number of all roots +#define LOSTFOUNDINO (ROOTINO + 1) // i number of lost+found +#define NICINOD 32 // number of superblock inodes +#define NICFREE 200 // number of superblock free blocks +#define MAXMNTLEN 28 +#define NSHIFT 8 +#define NMASK 0377L +#define MAXNAMLEN 63 +#define MAXSYMLINKS 8 +#define DEV_BMASK (DEV_BSIZE-1) +#define B_CLRBUF 0x01 +#define DEV_BSHIFT 10 +#define DIRBLKSIZ 1024 +#define NINDIR (DEV_BSIZE / sizeof(long)) +#define INOPB 16 +#define MAXPATHLEN 256 +#define FSMAGIC1 ('F' | 'S'<<8 | '<'<<16 | '<'<<24) +#define FSMAGIC2 ('>' | '>'<<8 | 'F'<<16 | 'S'<<24) +#define SUPERB ((long)0) /* block number of the super block */ +#define PINOD 10 + +#define dbtofsb(b) ((long) (b)) +#define itod(x) ((long)((((u_int)(x) + INOPB - 1) / INOPB))) +#define itoo(x) ((int)(((x) + INOPB - 1) % INOPB)) +#define DIRSIZ(dp) \ + ((((sizeof (struct direct) - (MAXNAMLEN+1)) + (dp)->d_namlen+1) + 3) &~ 3) +#define blkoff(loc) /* calculates (loc % fs->fs_bsize) */ \ + ((loc) & DEV_BMASK) +#define lblkno(loc) /* calculates (loc / fs->fs_bsize) */ \ + ((unsigned) (loc) >> DEV_BSHIFT) + +#define NDINIT(ndp,op,flags,namep) {\ + (ndp)->ni_nameiop = op | flags; \ + (ndp)->ni_dirp = namep; } + + +#define roundup(x,y) ((((x)+((y)-1))/(y))*(y)) +#define LOOKUP 0 /* perform name lookup only */ +#define CREATE 1 /* setup for file creation */ +#define DELETE 2 /* setup for file deletion */ +#define LOCKPARENT 0x10 /* see the top of namei */ +#define NOCACHE 0x20 /* name must not be left in cache */ +#define FOLLOW 0x40 /* follow symbolic links */ +#define NOFOLLOW 0x0 /* don't follow symbolic links (pseudo) */ + +#define B_READ 0x00001 /* read when I/O occurs */ +#define B_ERROR 0x00004 /* transaction aborted */ + + +struct fs +{ + u_int fs_magic1; /* magic word */ + u_int fs_isize; /* first block after i-list */ + u_int fs_fsize; /* size in blocks of entire volume */ + u_int fs_swapsz; /* size in blocks of swap area */ + int fs_nfree; /* number of addresses in fs_free */ + daddr_t fs_free [NICFREE]; /* free block list */ + int fs_ninode; /* number of inodes in fs_inode */ + ino_t fs_inode [NICINOD]; /* free inode list */ + int fs_flock; /* lock during free list manipulation */ + int fs_fmod; /* super block modified flag */ + int fs_ilock; /* lock during i-list manipulation */ + int fs_ronly; /* mounted read-only flag */ + time_t fs_time; /* last super block update */ + u_int fs_tfree; /* total free blocks */ + ino_t fs_tinode; /* total free inodes */ + char fs_fsmnt [MAXMNTLEN]; /* ordinary file mounted on */ + ino_t fs_lasti; /* start place for circular search */ + ino_t fs_nbehind; /* est # free inodes before s_lasti */ + u_int fs_flags; /* mount time flags */ + u_int fs_magic2; /* magic word */ +/* actually longer */ +}; + + +struct fblk { + int df_nfree; /* number of addresses in df_free */ + daddr_t df_free [NICFREE]; /* free block list */ +}; + +struct direct { + ino_t d_ino; /* inode number of entry */ + u_short d_reclen; /* length of this record */ + u_short d_namlen; /* length of string in d_name */ + char d_name[MAXNAMLEN+1]; /* name must be no longer than this */ +}; + +#define NDADDR 4 /* direct addresses in inode */ +#define NIADDR 3 /* indirect addresses in inode */ +#define NADDR (NDADDR + NIADDR) /* total addresses in inode */ + +struct icommon1 { + u_short ic_mode; /* mode and type of file */ + u_short ic_nlink; /* number of links to file */ + uid_t ic_uid; /* owner's user id */ + gid_t ic_gid; /* owner's group id */ + off_t ic_size; /* number of bytes in file */ +}; + +struct icommon2 { + time_t ic_atime; /* time last accessed */ + time_t ic_mtime; /* time last modified */ + time_t ic_ctime; /* time created */ +}; + +struct inode { + struct inode *i_chain[2]; /* must be first */ + u_int i_flag; + u_int i_count; /* reference count */ + dev_t i_dev; /* device where inode resides */ + ino_t i_number; /* i number, 1-to-1 with device address */ + u_int i_id; /* unique identifier */ + struct fs *i_fs; /* file sys associated with this inode */ + union { + struct { + u_short I_shlockc; /* count of shared locks */ + u_short I_exlockc; /* count of exclusive locks */ + } i_l; + struct proc *I_rsel; /* pipe read select */ + } i_un0; + union { + struct proc *I_wsel; /* pipe write select */ + } i_un1; + union { + daddr_t I_addr[NADDR]; /* normal file/directory */ + struct { + daddr_t I_db[NDADDR]; /* normal file/directory */ + daddr_t I_ib[NIADDR]; + } i_f; + struct { + /* + * the dummy field is here so that the de/compression + * part of the iget/iput routines works for special + * files. + */ + u_int I_dummy; + dev_t I_rdev; /* dev type */ + } i_d; + } i_un2; + union { + daddr_t if_lastr; /* last read (read-ahead) */ + struct { + struct inode *if_freef; /* free list forward */ + struct inode **if_freeb; /* free list back */ + } i_fr; + } i_un3; + struct icommon1 i_ic1; + u_int i_flags; /* user changeable flags */ + struct icommon2 i_ic2; +}; + +struct dinode { + struct icommon1 di_icom1; + daddr_t di_addr[NADDR]; /* 7 block addresses 4 bytes each */ + u_int di_reserved[1]; /* pad of 4 to make total size 64 */ + u_int di_flags; + struct icommon2 di_icom2; +}; + +struct nameidata { + caddr_t ni_dirp; /* pathname pointer */ + short ni_nameiop; /* see below */ + short ni_error; /* error return if any */ + off_t ni_endoff; /* end of useful stuff in directory */ + struct inode *ni_pdir; /* inode of parent directory of dirp */ + struct inode *ni_ip; /* inode of dirp */ + off_t ni_offset; /* offset in directory */ + u_short ni_count; /* offset of open slot (off_t?) */ + struct direct ni_dent; /* current directory entry */ +}; + +#define i_mode i_ic1.ic_mode +#define i_nlink i_ic1.ic_nlink +#define i_uid i_ic1.ic_uid +#define i_gid i_ic1.ic_gid +#define i_size i_ic1.ic_size +#define i_shlockc i_un0.i_l.I_shlockc +#define i_exlockc i_un0.i_l.I_exlockc +#define i_rsel i_un0.I_rsel +#define i_wsel i_un1.I_wsel +#define i_db i_un2.i_f.I_db +#define i_ib i_un2.i_f.I_ib +#define i_atime i_ic2.ic_atime +#define i_mtime i_ic2.ic_mtime +#define i_ctime i_ic2.ic_ctime +#define i_rdev i_un2.i_d.I_rdev +#define i_addr i_un2.I_addr +#define i_dummy i_un2.i_d.I_dummy +#define i_lastr i_un3.if_lastr +#define i_forw i_chain[0] +#define i_back i_chain[1] +#define i_freef i_un3.i_fr.if_freef +#define i_freeb i_un3.i_fr.if_freeb + +#define di_ic1 di_icom1 +#define di_ic2 di_icom2 +#define di_mode di_ic1.ic_mode +#define di_nlink di_ic1.ic_nlink +#define di_uid di_ic1.ic_uid +#define di_gid di_ic1.ic_gid +#define di_size di_ic1.ic_size +#define di_atime di_ic2.ic_atime +#define di_mtime di_ic2.ic_mtime +#define di_ctime di_ic2.ic_ctime +/* i_flag */ +#define ILOCKED 0x1 /* inode is locked */ +#define IUPD 0x2 /* file has been modified */ +#define IACC 0x4 /* inode access time to be updated */ +#define IMOUNT 0x8 /* inode is mounted on */ +#define IWANT 0x10 /* some process waiting on lock */ +#define ITEXT 0x20 /* inode is pure text prototype */ +#define ICHG 0x40 /* inode has been changed */ +#define ISHLOCK 0x80 /* file has shared lock */ +#define IEXLOCK 0x100 /* file has exclusive lock */ +#define ILWAIT 0x200 /* someone waiting on file lock */ +#define IMOD 0x400 /* inode has been modified */ +#define IRENAME 0x800 /* inode is being renamed */ +#define IPIPE 0x1000 /* inode is a pipe */ +#define IRCOLL 0x2000 /* read select collision on pipe */ +#define IWCOLL 0x4000 /* write select collision on pipe */ +#define IXMOD 0x8000 /* inode is text, but impure (XXX) */ + +/* i_mode */ +#define IFMT 0170000 /* type of file */ +#define IFCHR 0020000 /* character special */ +#define IFDIR 0040000 /* directory */ +#define IFBLK 0060000 /* block special */ +#define IFREG 0100000 /* regular */ +#define IFLNK 0120000 /* symbolic link */ +#define IFSOCK 0140000 /* socket */ +#define ISUID 04000 /* set user id on execution */ +#define ISGID 02000 /* set group id on execution */ +#define ISVTX 01000 /* save swapped text even after use */ +#define IREAD 0400 /* read, write, execute permissions */ +#define IWRITE 0200 +#define IEXEC 0100 + +#define IUPDAT(ip, t1, t2, waitfor) { \ + if (ip->i_flag&(IUPD|IACC|ICHG|IMOD)) \ + iupdat(ip, t1, t2, waitfor); \ +} + +#define ITIMES(ip, t1, t2) { \ + if ((ip)->i_flag&(IUPD|IACC|ICHG)) { \ + (ip)->i_flag |= IMOD; \ + if ((ip)->i_flag&IACC) \ + (ip)->i_atime = (t1)->tv_sec; \ + if ((ip)->i_flag&IUPD) \ + (ip)->i_mtime = (t2)->tv_sec; \ + if ((ip)->i_flag&ICHG) \ + (ip)->i_ctime = time.tv_sec; \ + (ip)->i_flag &= ~(IACC|IUPD|ICHG); \ + } \ +} + +struct bufhd +{ + int32_t b_flags; /* see defines below */ + struct buf *b_forw, *b_back; /* fwd/bkwd pointer in chain */ +}; + +struct buf +{ + int32_t b_flags; /* see defines below */ + struct buf *b_forw, *b_back; /* hash chain (2 way street) */ + struct buf *av_forw, *av_back; /* position on free list if not BUSY */ +#define b_actf av_forw /* alternate names for driver queue */ +#define b_actl av_back /* head - isn't history wonderful */ + u_int32_t b_bcount; /* transfer count */ +#define b_active b_bcount /* driver queue head: drive active */ + int32_t b_error; /* returned after I/O */ + dev_t b_dev; /* major+minor device name */ + caddr_t b_addr; /* core address */ + long b_blkno; /* block # on device */ + u_int32_t b_resid; /* words not transferred after error */ +#define b_cylin b_resid /* disksort */ +#define b_errcnt b_resid /* while i/o in progress: # retries */ +}; + +#define dotdot_ino dtdt_ino +#define dotdot_reclen dtdt_rec +#define dotdot_name dtdt_name +struct dirtemplate { + u_int dot_ino; + u_short dot_reclen; + u_short dot_namlen; + char dot_name[4]; /* must be multiple of 4 */ + u_int dotdot_ino; + u_short dotdot_reclen; + u_short dotdot_namlen; + char dotdot_name[4]; /* ditto */ +}; + +struct filesystem { + int32_t fd; + struct fs *fs; + struct inode *root; +}; + + +extern int32_t makedir(struct direct *protodir, int32_t entries, void *buf); +extern void *fsreadblock(struct filesystem *f, int64_t bno); +extern int32_t fsformat(struct filesystem *f, int32_t bpi); +extern void fsinit(struct filesystem *f); +extern struct filesystem *fsopen(char *filename); +extern void fsclose(struct filesystem *f); +extern struct filesystem *fsnew(char *filename, u_int32_t blocks, u_int32_t bpi); +extern int32_t fsformat(struct filesystem *f, int32_t bpi); +extern struct inode *fsreadinode(struct filesystem *f, int64_t ino); +extern int32_t fswriteblock(struct filesystem *f, int64_t bno, void *buf); +extern int32_t fswriteinode(struct filesystem *f, struct inode *ip); +extern u_int32_t fsinodealloc(struct filesystem *f); +extern int64_t fsblockalloc(struct filesystem *f); +extern int32_t umkdir(struct filesystem *f, char *path); +extern int uls(struct filesystem *f, char *path); +extern int uchmod(struct filesystem *f, char *path, int mode); +extern int uchown(struct filesystem *f, char *path, int uid); +extern int uchgrp(struct filesystem *f, char *path, int gid); +extern struct inode *inodebypath(struct filesystem *f, char *path); + + +typedef struct { + struct filesystem *f; + struct inode *in; + off_t readoffset; + off_t writeoffset; + int perm; +} UFILE; + +extern char *getsetting(char *setting); +extern void storesetting(char *setting, char *value); +extern char **splitpath(char *path, int *ndir); +extern void compresspath(char *path); + +extern UFILE *ufopen(struct filesystem *f, char *path, char *mode); +extern void ufclose(UFILE *f); +extern int ufgetc(UFILE *f); + +#endif diff --git a/tools/libufs/set.c b/tools/libufs/set.c new file mode 100644 index 0000000..c94af85 --- /dev/null +++ b/tools/libufs/set.c @@ -0,0 +1,84 @@ +#include +#include +#include +#include + +#include "libufs.h" + +char *getsetting(char *setting) +{ + FILE *f; + char *s = NULL; + char *home; + char temp[1024]; + char sub[1024]; + char fmt[1024]; + + home = getenv("HOME"); + + sprintf(temp, "%s/.libufs", home); + + f = fopen(temp, "r"); + if (!f) { + return s; + } + + sprintf(fmt, "%s=%%s", setting); + + while (fgets(temp, 1024, f)) { + bzero(sub, 800); + if (sscanf(temp, fmt, sub)) { + s = strdup(sub); + } + } + + fclose(f); + return s; +} + +void storesetting(char *setting, char *value) +{ + FILE *f1; + FILE *f2; + char *home; + char temp1[1024]; + char temp2[1024]; + + if (!setting) { + return; + } + + home = getenv("HOME"); + + sprintf(temp1, "%s/.libufs.bak", home); + sprintf(temp2, "%s/.libufs", home); + + rename(temp2, temp1); + + f1 = fopen(temp1, "r"); + if (!f1) { + return; + } + f2 = fopen(temp2, "w"); + if (!f2) { + fclose(f2); + return; + } + + sprintf(temp2, "%s=", setting); + + while (fgets(temp1, 1024, f1)) { + if (strncmp(temp1, temp2, strlen(temp2)) != 0) { + if (strlen(temp1) > 2) { + fprintf(f2, "%s", temp1); + } + } + } + + if (value) { + fprintf(f2, "%s=%s\n", setting, value); + } + fclose(f1); + fclose(f2); +} + diff --git a/tools/libufs/ucat.c b/tools/libufs/ucat.c new file mode 100644 index 0000000..59644d9 --- /dev/null +++ b/tools/libufs/ucat.c @@ -0,0 +1,56 @@ +#include +#include + +#include "libufs.h" + +int main(int argc, char *argv[]) +{ + struct filesystem *f; + char path[1024]; + char *image = getsetting("imagefile"); + UFILE *file; + int c; + + if (!image) { + printf("Have you run ulogin?\n"); + return 10; + } + + char *cwd = getsetting("cwd"); + if (argc == 2) { + if (argv[1][0] == '/') { + sprintf(path, "%s", argv[1]); + } else { + sprintf(path, "%s/%s", cwd, argv[1]); + } + } else { + sprintf(path, "%s", cwd); + } + free(cwd); + + f = fsopen(image); + if (!f) { + printf("Unable to open %s\n", image); + fsclose(f); + free(image); + return(10); + } + + file = ufopen(f, path, "r"); + if (!file) { + printf("%s: not found\n", path); + fsclose(f); + free(image); + return(10); + } + + while ((c = ufgetc(file)) != EOF) { + printf("%c", c); + } + + ufclose(file); + + fsclose(f); + free(image); + return 0; +} diff --git a/tools/libufs/ucd.c b/tools/libufs/ucd.c new file mode 100644 index 0000000..8887a55 --- /dev/null +++ b/tools/libufs/ucd.c @@ -0,0 +1,60 @@ +#include +#include +#include + +#include "libufs.h" + +int main(int argc, char *argv[]) +{ + struct filesystem *f; + char *temp = malloc(1024); + char *image; + + image = getsetting("imagefile"); + + if (!image) { + printf("Have you run ulogin?\n"); + return 10; + } + + if (argc != 2) { + printf("Usage: %s \n", argv[0]); + free(image); + return 10; + } + + f = fsopen(image); + if (!f) { + if(image) free(image); + return 10; + } + + if (argv[1][0] == '/') { + if (!inodebypath(f, argv[1])) { + printf("%s not found\n", argv[1]); + } else { + storesetting("cwd", argv[1]); + } + fsclose(f); + free(image); + return 0; + } else { + char *cwd = getsetting("cwd"); + if (!cwd) { + sprintf(temp, "/%s", argv[1]); + } else { + sprintf(temp, "%s/%s", cwd, argv[1]); + compresspath(temp); + free(cwd); + } + if (!inodebypath(f, temp)) { + printf("%s not found\n", temp); + } else { + storesetting("cwd", temp); + } + free(image); + fsclose(f); + return 0; + } + return 0; +} diff --git a/tools/libufs/uchgrp.c b/tools/libufs/uchgrp.c new file mode 100644 index 0000000..ed0e392 --- /dev/null +++ b/tools/libufs/uchgrp.c @@ -0,0 +1,51 @@ +#include +#include + +#include "libufs.h" + +int main(int argc, char *argv[]) +{ + struct filesystem *f; + int i; + int mode; + char temp[1024]; + char *cwd; + char *fsname = getsetting("imagefile");; + + if (!fsname) { + printf("Have you run ulogin?\n"); + return 10; + } + + if (argc < 3) { + printf("Usage: %s ...\n", argv[0]); + return 10; + } + + sscanf(argv[1], "%o", &mode); + + f = fsopen(fsname); + if (!f) { + printf("Unable to open %s\n", fsname); + return 10; + } + cwd = getsetting("cwd"); + for (i = 2; i < argc; i++) { + if (argv[i][0] == '/') { + uchgrp(f, argv[i], mode); + } else { + if (!cwd) { + sprintf(temp, "/%s", argv[i]); + } else { + sprintf(temp, "%s/%s", cwd, argv[i]); + } + compresspath(temp); + uchgrp(f, temp, mode); + } + } + fsclose(f); + if (cwd) + free(cwd); + free(fsname); + return 0; +} diff --git a/tools/libufs/uchmod.c b/tools/libufs/uchmod.c new file mode 100644 index 0000000..7f7abca --- /dev/null +++ b/tools/libufs/uchmod.c @@ -0,0 +1,51 @@ +#include +#include + +#include "libufs.h" + +int main(int argc, char *argv[]) +{ + struct filesystem *f; + int i; + int mode; + char temp[1024]; + char *cwd; + char *fsname = getsetting("imagefile");; + + if (!fsname) { + printf("Have you run ulogin?\n"); + return 10; + } + + if (argc < 3) { + printf("Usage: %s ...\n", argv[0]); + return 10; + } + + sscanf(argv[1], "%o", &mode); + + f = fsopen(fsname); + if (!f) { + printf("Unable to open %s\n", fsname); + return 10; + } + cwd = getsetting("cwd"); + for (i = 2; i < argc; i++) { + if (argv[i][0] == '/') { + uchmod(f, argv[i], mode); + } else { + if (!cwd) { + sprintf(temp, "/%s", argv[i]); + } else { + sprintf(temp, "%s/%s", cwd, argv[i]); + } + compresspath(temp); + uchmod(f, temp, mode); + } + } + fsclose(f); + if (cwd) + free(cwd); + free(fsname); + return 0; +} diff --git a/tools/libufs/uchown.c b/tools/libufs/uchown.c new file mode 100644 index 0000000..546b1e3 --- /dev/null +++ b/tools/libufs/uchown.c @@ -0,0 +1,51 @@ +#include +#include + +#include "libufs.h" + +int main(int argc, char *argv[]) +{ + struct filesystem *f; + int i; + int mode; + char temp[1024]; + char *cwd; + char *fsname = getsetting("imagefile");; + + if (!fsname) { + printf("Have you run ulogin?\n"); + return 10; + } + + if (argc < 3) { + printf("Usage: %s ...\n", argv[0]); + return 10; + } + + sscanf(argv[1], "%o", &mode); + + f = fsopen(fsname); + if (!f) { + printf("Unable to open %s\n", fsname); + return 10; + } + cwd = getsetting("cwd"); + for (i = 2; i < argc; i++) { + if (argv[i][0] == '/') { + uchown(f, argv[i], mode); + } else { + if (!cwd) { + sprintf(temp, "/%s", argv[i]); + } else { + sprintf(temp, "%s/%s", cwd, argv[i]); + } + compresspath(temp); + uchown(f, temp, mode); + } + } + fsclose(f); + if (cwd) + free(cwd); + free(fsname); + return 0; +} diff --git a/tools/libufs/ulogin.c b/tools/libufs/ulogin.c new file mode 100644 index 0000000..3d73ef0 --- /dev/null +++ b/tools/libufs/ulogin.c @@ -0,0 +1,37 @@ +#include +#include +#include +#include "libufs.h" + +int main(int argc, char *argv[]) +{ + char *filename; + struct filesystem *f; + char fullpath[1024]; + char cwd[800]; + + if (argc != 2) { + printf("Usage: %s \n", argv[0]); + return 10; + } + + filename = argv[1]; + + f = fsopen(filename); + if (!f) { + printf("Unable to open %s\n", filename); + return 10; + } + + if (filename[0] == '/') { + storesetting("imagefile", filename); + } else { + getcwd(cwd,800); + sprintf(fullpath, "%s/%s", cwd, filename); + storesetting("imagefile", fullpath); + } + + storesetting("cwd","/"); + + return 0; +} diff --git a/tools/libufs/uls.c b/tools/libufs/uls.c new file mode 100644 index 0000000..ba5a2b6 --- /dev/null +++ b/tools/libufs/uls.c @@ -0,0 +1,40 @@ +#include +#include + +#include "libufs.h" + +int main(int argc, char *argv[]) +{ + struct filesystem *f; + char path[1024]; + char *image = getsetting("imagefile"); + + if (!image) { + printf("Have you run ulogin?\n"); + return 10; + } + + char *cwd = getsetting("cwd"); + if (argc == 2) { + if (argv[1][0] == '/') { + sprintf(path, "%s", argv[1]); + } else { + sprintf(path, "%s/%s", cwd, argv[1]); + } + } else { + sprintf(path, "%s", cwd); + } + free(cwd); + + f = fsopen(image); + if (!f) { + printf("Unable to open %s\n", image); + } else { + if (!uls(f, path)) { + printf("%s not found\n", path); + } + } + fsclose(f); + free(image); + return 0; +} diff --git a/tools/libufs/umkdir.c b/tools/libufs/umkdir.c new file mode 100644 index 0000000..12a81b9 --- /dev/null +++ b/tools/libufs/umkdir.c @@ -0,0 +1,42 @@ +#include +#include + +#include "libufs.h" + +int main(int argc, char *argv[]) +{ + struct filesystem *f; + int i; + char *image = getsetting("imagefile"); + char temp[1024]; + char *cwd; + + if (argc < 2) { + printf("Usage: %s ...\n", argv[0]); + return 10; + } + + f = fsopen(image); + if (!f) { + return 10; + } + cwd = getsetting("cwd"); + for (i = 1; i < argc; i++) { + if (argv[i][0] == '/') { + umkdir(f, argv[i]); + } else { + if (!cwd) { + sprintf(temp, "/%s", argv[i]); + } else { + sprintf(temp, "%s/%s", cwd, argv[i]); + } + compresspath(temp); + umkdir(f, temp); + } + } + if (cwd) + free(cwd); + free(image); + fsclose(f); + return 0; +} diff --git a/tools/libufs/umkfs.c b/tools/libufs/umkfs.c new file mode 100644 index 0000000..a3612b2 --- /dev/null +++ b/tools/libufs/umkfs.c @@ -0,0 +1,48 @@ +#include +#include +#include +#include + +#include "libufs.h" + +int main(int argc, char *argv[]) +{ + struct stat sb; + int opt; + int blocks = 0; + int bpi = BPI; + struct filesystem *f; + + while ((opt = getopt(argc, argv, "i:b:")) != -1) { + switch (opt) { + case 'i': + bpi = atoi(optarg); + break; + case 'b': + blocks = atoi(optarg); + break; + } + } + + if (argc <= optind) { + printf("Usage: %s [-i bpi] [-b blocks] file\n", argv[0]); + printf(" Format an file image with a UFS filesystem\n"); + return 10; + } + + if (stat(argv[optind], &sb) != -1) { + f = fsopen(argv[optind]); + if (!f) { + printf("Error opening image file\n"); + return 10; + } + f->fs->fs_fsize = sb.st_size / DEV_BSIZE; + fsformat(f, bpi); + } else { + f = fsnew(argv[optind], blocks, bpi); + } + + fsclose(f); + + return 0; +} diff --git a/tools/libufs/util.c b/tools/libufs/util.c new file mode 100644 index 0000000..a2fe2d8 --- /dev/null +++ b/tools/libufs/util.c @@ -0,0 +1,62 @@ +#include +#include +#include +#include +#include "libufs.h" + +void compresspath(char *path) +{ + char *work; + char *p, *q; + char **dirs; + int ndir; + int i,j; + + // First, remove any double slashes + + for (p = path; *(p+1); p++) { + while ((*p == '/') && (*(p+1) == '/')) { + for (q = p+1; *q; q++) { + *q = *(q+1); + } + } + } + + // Now we need to split it all up and remove any single dots, and + // cd up any double dots. + + work = strdup(path); + + dirs = splitpath(work, &ndir); + + for (i = 0; i < ndir; i++) { + if (!strcmp(dirs[i], ".")) { + for (j = i; j < ndir-1; j++) { + dirs[j] = dirs[j+1]; + } + ndir--; + } + if (!strcmp(dirs[i], "..")) { + for (j = i-1; j < ndir-1; j++) { + dirs[j] = dirs[j+1]; + } + ndir--; + for (j = i-1; j < ndir-1; j++) { + dirs[j] = dirs[j+1]; + } + ndir--; + } + } + + sprintf(path, "%s", ""); + for (i=0; i +#include +#include +#include +#include +#include + +#include "rdisk.h" + +#define BUFSZ 512 + +#define BOOT 1 +#define SWAP 2 +#define FS 3 + +void usage() +{ + printf("Usage: mkrd -out [-boot ] [-swap ] [-fs ]\n"); + exit(10); +} + +int main(int argc, char *argv[]) +{ + struct mbr mbr; + int i; + struct stat sb; + int pno = 0; + unsigned int start = 2; + int fd,fin; + unsigned int r; + char buf[BUFSZ]; + unsigned int tl; + unsigned char ok = 0; + int q __attribute__((unused)); + + char *output = NULL; + char *files[4] = {NULL,NULL,NULL,NULL}; + char types[4] = {0,0,0,0}; + + int argnum = 1; + + bzero(&mbr,sizeof(struct mbr)); + + mbr.biosdrive=0x80; + mbr.sig = 'R'<<24 | 'T'<<16 | 'E'<<8 | 'R'; + mbr.bootsig = 0xAA55; + + for(argnum=1; argnumargc) usage(); + output = argv[argnum]; + printf("Output: %s\n",output); + ok = 1; + } + + if(!strcmp(argv[argnum],"-boot")) + { + argnum++; + if(argnum>argc) usage(); + files[pno] = argv[argnum]; + types[pno] = BOOT; + ok = 1; + printf("Boot: %s\n",files[pno]); + pno++; + } + + if(!strcmp(argv[argnum],"-swap")) + { + argnum++; + if(argnum>argc) usage(); + files[pno] = argv[argnum]; + types[pno] = SWAP; + ok = 1; + printf("Swap: %s\n",files[pno]); + pno++; + } + + if(!strcmp(argv[argnum],"-fs")) + { + argnum++; + if(argnum>argc) usage(); + files[pno] = argv[argnum]; + types[pno] = FS; + ok = 1; + printf("Fs: %s\n",files[pno]); + pno++; + } + + if(ok==0) + { + printf("Unknown option %s\n",argv[argnum]); + usage(); + } + } + + if(!output) usage(); + + for(i=0; i<4; i++) + { + if(types[i]!=0) + { + if(stat(files[i],&sb)==-1) + { + printf("Error: unable to stat %s\n",argv[i]); + exit(10); + } + tl = sb.st_size; + if(tl%BUFSZ != 0) + { + tl = (tl >> 9) + 1; + } else { + tl = tl >> 9; + } + + mbr.partitions[i].lbastart = start; + mbr.partitions[i].lbalength = tl; + switch(types[i]) + { + case BOOT: + mbr.partitions[i].type = RDISK_FS; + mbr.partitions[i].status = 0x80; + break; + case SWAP: + mbr.partitions[i].type = RDISK_SWAP; + mbr.partitions[i].status = 0x00; + break; + case FS: + mbr.partitions[i].type = RDISK_FS; + mbr.partitions[i].status = 0x00; + break; + } + + printf("Partition %d, start %u, length %u\n", + i, + mbr.partitions[i].lbastart, + mbr.partitions[i].lbalength + ); + + start += tl; + } + } + fd = open(output,O_WRONLY|O_CREAT|O_TRUNC,0666); + if(!fd) + { + printf("Error: cannot open %s for writing\n",argv[1]); + exit(10); + } + + q = write(fd,&mbr,BUFSZ); + + for(i=0; i<4; i++) + { + if(types[i]!=0) + { + lseek(fd,mbr.partitions[i].lbastart<<9,SEEK_SET); + printf("Loading data from %s...\n",files[i]); + fin = open(files[i],O_RDONLY); + bzero(buf,BUFSZ); + while((r=read(fin,buf,BUFSZ))>0) + { + q = write(fd,buf,BUFSZ); + bzero(buf,BUFSZ); + } + close(fin); + } + } + + close(fd); + return 0; +} diff --git a/tools/mkrd/rdisk.h b/tools/mkrd/rdisk.h new file mode 100644 index 0000000..139c3ab --- /dev/null +++ b/tools/mkrd/rdisk.h @@ -0,0 +1,39 @@ +#ifndef _RDISK_H +#define _RDISK_H + +#define RDISK_FS 0xB7 +#define RDISK_SWAP 0xB8 + +struct chs { + unsigned char head; + struct { + unsigned cylhigh:2; + unsigned sector:6; + } __attribute__((packed)); + unsigned char cyllow; +}__attribute__((packed)); + +struct partition { + unsigned char status; + struct chs start; + unsigned char type; + struct chs end; + unsigned lbastart; + unsigned lbalength; +}; + +struct mbr { + unsigned char bootstrap1[218]; + unsigned short pad0000; + unsigned char biosdrive; + unsigned char secs; + unsigned char mins; + unsigned char hours; + unsigned char bootstrap2[216]; + unsigned int sig; + unsigned short pad0001; + struct partition partitions[4]; + unsigned short bootsig; +}__attribute__((packed)); + +#endif diff --git a/tools/virtualmips/.indent.pro b/tools/virtualmips/.indent.pro new file mode 100644 index 0000000..ccb7d61 --- /dev/null +++ b/tools/virtualmips/.indent.pro @@ -0,0 +1,24 @@ +-nbad +-bap +-nbc +-blf +-br +-brs +-c33 +-ci4 +-cbi4 +-cd33 +-ce +-ci4 +-cli0 +-di0 +-nfc1 +-i4 +-ip0 +-l78 +-nlp +-pcs +-npsl +-sc +-sob +-nut diff --git a/tools/virtualmips/.le.ini b/tools/virtualmips/.le.ini new file mode 100644 index 0000000..312135c --- /dev/null +++ b/tools/virtualmips/.le.ini @@ -0,0 +1,39 @@ +tabsize=4 +indentsize=4 +autoindent=1 +bsunindents=1 +insert=1 +inputmode=0 +editmode=1 +makebak=1 +bakpath= +make=exec make +shell=exec $SHELL +run=exec make run +compile=exec make "$NAME.o" +scroll=1 +hscroll=8 +rblock=0 +savepos=1 +savehst=1 +noreg=0 +linelen=63 +leftmrg=0 +flnmarg=0 +leftadj=1 +rightadj=0 +helpcmd=exec man "$WORD" +usecolor=1 +usetabs=0 +scrollbar=1 +statusline=0 +backupext=~ +backupnum=9 +preferpagetop=0 +wordwrap=0 +syntaxhl=1 +undo_enable=1 +undo_min_levels=4 +undo_max_memory=128 +undo_glue=1 +usemouse=1 diff --git a/tools/virtualmips/LICENSE b/tools/virtualmips/LICENSE new file mode 100644 index 0000000..c474417 --- /dev/null +++ b/tools/virtualmips/LICENSE @@ -0,0 +1,4 @@ +The following points clarify the virtualmips license: + +virtualmips as a whole is released under the GNU General Public License + diff --git a/tools/virtualmips/Makefile b/tools/virtualmips/Makefile new file mode 100644 index 0000000..ad1f9db --- /dev/null +++ b/tools/virtualmips/Makefile @@ -0,0 +1,78 @@ +# +# Build VirtualMIPS simulator. +# + +# Select target board: +# chipKIT Max32 +CFLAGS = -DSIM_PIC32 -DPIC32MX7 -DMAX32 + +# Microchip Explorer 16 +#CFLAGS = -DSIM_PIC32 -DPIC32MX7 -DEXPLORER16 + +# UBW32 with UART console +#CFLAGS = -DSIM_PIC32 -DPIC32MX7 -DUBW32 + +CC = gcc -g +CFLAGS += -Wall -MT $@ -MD -MP -MF .deps/$*.dep -I/opt/local/include -I/opt/local/include/libelf +LIBS = -lpthread -lelf + +ifneq ($(wildcard /usr/lib/librt.a),) +LIBS += -lrt # Linux +endif +ifneq ($(wildcard /usr/lib/i386-linux-gnu/librt.a),) +LIBS += -lrt # Linux +endif +ifneq ($(wildcard /opt/local/lib/libintl.a),) +LIBS += -L/opt/local/lib -lintl # Mac OS X +endif + +# Optimization. +CFLAGS += -O +#CFLAGS += -O3 -fomit-frame-pointer + +PROG = pic32 +OBJS = pic32.o pic32_dev_flash.o pic32_dev_uart.o pic32_dev_intcon.o \ + pic32_dev_spi.o pic32_dev_gpio.o dev_sdcard.o dev_swap.o \ + pic32_dev_bmxcon.o pic32_dev_dmacon.o pic32_dev_syscon.o \ + pic32_dev_prefetch.o pic32_dev_adc.o pic32_dev_devcfg.o \ + pic32_dev_rtcc.o pic32_dev_timer.o + +# Ingenic JZ4740. +#CFLAGS += -DSIM_PAVO -D_USE_FDD_ +#PROG = pavo +#OBJS = pavo.o jz4740.o jz4740_dev_cpm.o jz4740_dev_dma.o \ +# jz4740_dev_emc.o jz4740_dev_gpio.o jz4740_dev_int.o \ +# jz4740_dev_rtc.o jz4740_dev_ts.o \ +# jz4740_dev_uart.o jz4740_dev_wdt_tcu.o + +# Implement LCD. +#CFLAGS += -DSIM_LCD +#LIBS += -lSDL +#OBJS += jz4740_dev_lcd.o vp_sdl.o + +# Use JIT compiler. +#CFLAGS += -D_USE_JIT_ +#OBJS += mips_jit.o x86_trans.o + +# Common files. +OBJS += dev_cs8900.o dev_nand_flash_1g.o dev_ram.o \ + dev_vtty.o device.o vm.o cpu.o mips.o mips_cp0.o \ + mips_exec.o mips_fdd.o crc.o mips_hostalarm.o \ + mempool.o sbox.o utils.o vp_clock.o vp_timer.o net_io.o \ + mips_memory.o debug.o gdb_interface.o main.o \ + mips-dis.o config.o + +all: .deps $(PROG) + +$(PROG): $(OBJS) + $(CC) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) + +.deps: + @mkdir .deps + +clean: + rm -rf *.o *~ *_log.txt .deps pavo pic32 pic32-log.txt + +ifeq (.deps, $(wildcard .deps)) +-include .deps/*.dep +endif diff --git a/tools/virtualmips/README b/tools/virtualmips/README new file mode 100644 index 0000000..54b2f61 --- /dev/null +++ b/tools/virtualmips/README @@ -0,0 +1 @@ +Please visit http://code.google.com/p/virtualmips/ to get the information of how to use VirtualMIPS. \ No newline at end of file diff --git a/tools/virtualmips/SConstruct b/tools/virtualmips/SConstruct new file mode 100644 index 0000000..567997c --- /dev/null +++ b/tools/virtualmips/SConstruct @@ -0,0 +1,122 @@ +#Build script of virtualmips. +#Scons is really an excellent tool to build software! + +import os,platform,SCons,glob,re,sys + +######################### +# Global Environment # +######################### +baseEnv=Environment() + +if ARGUMENTS.get('debug',0): + baseEnv.Append(CCFLAGS = "-g") + + +helpString = """ +Usage: + scons [target] [compile options] +Targets: + pavo: Build VirtualMIPS for pavo emulation + mknandflash: Build mknandflash tool + +Compile Options: + jit: Set to 0 to compile VirtualMIPS *without* JIT support(pavo only). Default 1. + lcd: Set to 0 to compile VirtualMIPS *without* LCD support(pavo only). Default 1. + mhz: Set to 1 to test emulator's speed. Default 0. + debug: Set to 1 to compile with -g. Default 0. + o: Set optimization level.Default 3. + cc: Set compiler.Default "gcc". You can set cc=gcc-3.4 to use gcc 3.4. + +""" + + +######################### +# Project Environment # +######################### + + +baseEnv.Append(INCDIR = [os.path.join(os.path.abspath('.'),'../emulator')]) +baseEnv.Append(INCDIR = [os.path.join(os.path.abspath('.'),'../emulator','device')]) +baseEnv.Append(INCDIR = [os.path.join(os.path.abspath('.'),'../emulator','system')]) +baseEnv.Append(INCDIR = [os.path.join(os.path.abspath('.'),'../emulator','mips')]) +baseEnv.Append(INCDIR = [os.path.join(os.path.abspath('.'),'../emulator','utils')]) +baseEnv.Append(INCDIR = [os.path.join(os.path.abspath('.'),'../emulator','utils','net')]) +baseEnv.Append(INCDIR = [os.path.join(os.path.abspath('.'),'../emulator','memory')]) +baseEnv.Append(INCDIR = [os.path.join(os.path.abspath('.'),'../emulator','gdb')]) + + +baseEnv.Append(CPPPATH = baseEnv['INCDIR']) +baseEnv.Append(LIBS = ['confuse','pthread','rt','elf'] ) +baseEnv.Append(LIBPATH = ['/usr/lib', '/usr/local/lib'] ) + +baseEnv.Append(CCFLAGS= "-Wall -fomit-frame-pointer" ) + +mhz = ARGUMENTS.get('mhz', 0) +if int(mhz): + #test emulator's MHZ + baseEnv.Append(CCFLAGS = "-DDEBUG_MHZ") + + +o = ARGUMENTS.get('o', 3) +if int(o)==3: + baseEnv.Append(CCFLAGS= "-O3" ) + baseEnv.Append(LINKFLAGS = "-O3" ) +elif int(o)==2: + baseEnv.Append(CCFLAGS= "-O2" ) + baseEnv.Append(LINKFLAGS = "-O2" ) +elif int(o)==1: + baseEnv.Append(CCFLAGS= "-O1" ) + baseEnv.Append(LINKFLAGS = "-O1" ) + +cc1 = ARGUMENTS.get('cc', "gcc") +if (cc1): + baseEnv.Replace(CC = cc1) + + + +Help(helpString) + +def listFiles(dirs,srcexts): + allFiles = [] + for dir in (dirs): + path= os.path.join(os.path.abspath(dir),srcexts) + newFiles = glob.glob(path) + for newFile in newFiles: + allFiles.append(newFile) + return allFiles + + + + +if 'pavo' in COMMAND_LINE_TARGETS: + pavo = baseEnv.Clone() + pavo.Append(CPPPATH = [os.path.join(os.path.abspath('.'),'../emulator','system','jz','soc')]) + pavo.Append(CPPPATH = [os.path.join(os.path.abspath('.'),'../emulator','system','jz','pavo')]) + pavo.Append(CPPPATH = [os.path.join(os.path.abspath('.'),'../emulator','utils','sdl')]) + pavo.Append(CCFLAGS = "-DSIM_PAVO") + lcd = ARGUMENTS.get('lcd', 1) + if int(lcd): + #check libsdl + conf = Configure(pavo) + if not conf.CheckLib('SDL'): + print 'Did not find libSDL, exiting!' + Exit(1) + if not conf.CheckCHeader('SDL/SDL.h'): + print 'SDL/SDL.h must be installed!' + Exit(1) + pavo = conf.Finish() + pavo.Append(CCFLAGS = "-DSIM_LCD") + pavo.Append(LINKFLAGS = "-lSDL") + + pavo.Program('pavo',listFiles(pavo['CPPPATH'],'*.c')) + + +if 'mknandflash' in COMMAND_LINE_TARGETS: + mknandflash=Environment() + mknandflash.Program('mknandflash','../tool/mknandflash.c',LIBS = ['confuse'] ) + + + + + + diff --git a/tools/virtualmips/adm5120/adm5120.c b/tools/virtualmips/adm5120/adm5120.c new file mode 100644 index 0000000..fee0a0f --- /dev/null +++ b/tools/virtualmips/adm5120/adm5120.c @@ -0,0 +1,366 @@ + /* + * Copyright (C) yajin 2008 + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + * + */ + +#define _GNU_SOURCE +#include +#include +#include +#include + +#include "utils.h" +#include "adm5120.h" +#include "mips.h" +#include "vm.h" +#include "cpu.h" +#include "mips_exec.h" +#include "debug.h" +#include "vp_lock.h" + +int dev_sw_init (vm_instance_t * vm, char *name, m_pa_t paddr, + m_uint32_t len); +int dev_rom_init (vm_instance_t * vm, char *name); +int dev_nor_flash_4m_init (vm_instance_t * vm, char *name); +int dev_mpmc_init (vm_instance_t * vm, char *name, m_pa_t paddr, + m_uint32_t len); +int dev_intctrl_init (vm_instance_t * vm, char *name, m_pa_t paddr, + m_uint32_t len); +int dev_uart_init (vm_instance_t * vm, char *name, m_pa_t paddr, + m_uint32_t len, vtty_t * vtty, int uart_index); +int dev_pci_init (vm_instance_t * vm, char *name, m_pa_t paddr, + m_uint32_t len); + +/* Initialize default parameters for a adm5120 */ +static void adm5120_init_defaults (adm5120_t * adm5120) +{ + vm_instance_t *vm = adm5120->vm; + + if (vm->configure_filename == NULL) + vm->configure_filename = strdup (ADM5120_DEFAULT_CONFIG_FILE); + vm->ram_size = ADM5120_DEFAULT_RAM_SIZE; + vm->boot_method = ADM5120_DEFAULT_BOOT_METHOD; + vm->kernel_filename = strdup (ADM5120_DEFAULT_KERNEL_FILENAME); +} + +/* Initialize the adm5120 Platform (MIPS) */ +static int adm5120_init_platform (adm5120_t * adm5120) +{ + struct vm_instance *vm = adm5120->vm; + cpu_mips_t *cpu0; + void *(*cpu_run_fn) (void *); + + vm_init_vtty (vm); + + /* Create a CPU group */ + vm->cpu_group = cpu_group_create ("System CPU"); + + /* Initialize the virtual MIPS processor */ + if (!(cpu0 = cpu_create (vm, CPU_TYPE_MIPS32, 0))) { + vm_error (vm, "unable to create CPU0!\n"); + return (-1); + } + /* Add this CPU to the system CPU group */ + cpu_group_add (vm->cpu_group, cpu0); + vm->boot_cpu = cpu0; + + cpu_run_fn = (void *) mips_exec_run_cpu; + /* create the CPU thread execution */ + if (pthread_create (&cpu0->cpu_thread, NULL, cpu_run_fn, cpu0) != 0) { + fprintf (stderr, "cpu_create: unable to create thread for CPU%u\n", + 0); + free (cpu0); + return (-1); + } + cpu0->addr_bus_mask = ADM5120_ADDR_BUS_MASK; + + /* Initialize RAM */ + vm_ram_init (vm, 0x00000000ULL); + + /* Initialize ROM */ + /*if (vm->rom_size!=0) + * { + * if (dev_rom_init(vm, "ROM")==-1) + * return (-1); + * } */ + + /* Initialize FLASH */ + if ((vm->flash_size != 0) && (vm->flash_type == FLASH_TYPE_NOR_FLASH)) + if (dev_nor_flash_4m_init (vm, "NORFLASH4M") == -1) + return (-1); + + if (dev_sw_init (vm, "SW", ADM5120_SWCTRL_BASE, SW_INDEX_MAX * 4) == -1) + return (-1); + if (dev_mpmc_init (vm, "MPMC", ADM5120_MPMC_BASE, + MPMC_INDEX_MAX * 4) == -1) + return (-1); + if (dev_intctrl_init (vm, "INT CTRL", ADM5120_INTC_BASE, + INTCTRL_INDEX_MAX * 4) == -1) + return (-1); + if (dev_uart_init (vm, "UART 0", ADM5120_UART0_BASE, 0x24, vm->vtty_con1, + 0) == -1) + return (-1); + if (dev_uart_init (vm, "UART 1", ADM5120_UART1_BASE, 0x24, vm->vtty_con2, + 0) == -1) + return (-1); + if (dev_pci_init (vm, "PCI", ADM5120_PCI_BASE, PCI_INDEX_MAX * 4) == -1) + return (-1); + + return (0); +} + +extern m_uint32_t sw_table[SW_INDEX_MAX]; +/*set adm5120 reg default value. Only needed if boot from linux elf image. +Linux will query sw_table[0x7] to get sdram size. + */ +static void adm5120_reg_default_value (adm5120_t * adm5120) +{ + if (adm5120->vm->ram_size == 128) + sw_table[0x7] = 0x50405; // 128M + else if (adm5120->vm->ram_size == 64) + sw_table[0x7] = 0x50404; // 64m + else if (adm5120->vm->ram_size == 32) + sw_table[0x7] = 0x50423; //16M *2 + else if (adm5120->vm->ram_size == 16) + sw_table[0x7] = 0x50403; //16M + else if (adm5120->vm->ram_size == 8) + sw_table[0x7] = 0x50402; // 8M + else if (adm5120->vm->ram_size == 4) + sw_table[0x7] = 0x50401; // 4M + else + ASSERT (0, "Invalid ram_size.\n Valid value:4,8,16,32,64,128\n"); +} + +static int adm5120_boot (adm5120_t * adm5120) +{ + vm_instance_t *vm = adm5120->vm; + cpu_mips_t *cpu; + m_va_t kernel_entry_point; + + if (!vm->boot_cpu) + return (-1); + + vm_suspend (vm); + + /* Check that CPU activity is really suspended */ + if (cpu_group_sync_state (vm->cpu_group) == -1) { + vm_error (vm, "unable to sync with system CPUs.\n"); + return (-1); + } + + /* Reset the boot CPU */ + cpu = (vm->boot_cpu); + mips_reset (cpu); + + /*set configure register */ + cpu->cp0.config_usable = 0x3; /*only configure sel 0 and 1 is valid */ + cpu->cp0.config_reg[0] = ADM5120_CONFIG0; + cpu->cp0.config_reg[1] = ADM5120_CONFIG1; + + /*set PC and PRID */ + cpu->cp0.reg[MIPS_CP0_PRID] = ADM5120_PRID; + cpu->cp0.tlb_entries = ADM5120_DEFAULT_TLB_ENTRYNO; + cpu->pc = ADM5120_ROM_PC; + /*If we boot from elf kernel image, load the image and set pc to elf entry */ + if (vm->boot_method == BOOT_ELF) { + if (mips_load_elf_image (cpu, vm->kernel_filename, + &kernel_entry_point) == -1) + return (-1); + adm5120_reg_default_value (adm5120); + cpu->pc = kernel_entry_point; + } + + /* Launch the simulation */ + printf ("\nADM5120 '%s': starting simulation (CPU0 PC=0x%" LL "x), " + "JIT %sabled.\n", vm->name, cpu->pc, vm->jit_use ? "en" : "dis"); + + vm->status = VM_STATUS_RUNNING; + cpu_start (vm->boot_cpu); + return (0); + +} + +extern m_uint32_t intctrl_table[INTCTRL_INDEX_MAX]; + +/* +Mapping adm irq to mips irq. + +So why we need a mapping of interrupts? + +IN ADM5120,there are 10 interrupts +0 Timer +1 Uart 0 +2 Uart 1 +3 USB Host +4 External I/O 0 +5 External I/O 1 +6 PCI 0 +7 PCI 1 +8 PCI 2 +9 Switch + +ADM5120 will triger INTERRUPT 2 and 3 to MIPS. +INT_M(0X14) register control the interrupt releation of ADM5120 and iqr/firq. + + */ +int adm_irq2mips_irq (vm_instance_t * vm, u_int irq) +{ + m_uint32_t int_bit_mask = 0; + + int_bit_mask = 1 << irq; + if ((intctrl_table[IRQ_MODE_REG / 4] & int_bit_mask) == int_bit_mask) { + return ADM5120_MIPSINT_FIQ; + } else + return ADM5120_MIPSINT_IRQ; + +} + +int whether_irq_enable (vm_instance_t * vm, u_int irq) +{ + m_uint32_t int_bit_mask = 0; + + int_bit_mask = 1 << irq; + if ((intctrl_table[IRQ_ENABLE_REG / 4] & int_bit_mask) == int_bit_mask) { + return TRUE; + } else + return FALSE; + +} + +void adm5120_clear_irq (vm_instance_t * vm, u_int irq) +{ + assert (irq <= INT_LVL_MAX); + int mips_irq_no; + m_uint32_t int_bit_mask = 0; + + int_bit_mask = 1 << irq; + + /*clear raw status */ + intctrl_table[IRQ_RAW_STATUS_REG / 4] &= ~int_bit_mask; + + mips_irq_no = adm_irq2mips_irq (vm, irq); + + if (ADM5120_MIPSINT_FIQ == mips_irq_no) { + intctrl_table[FIQ_STATUS_REG / 4] &= ~int_bit_mask; + } else { + intctrl_table[IRQ_STATUS_REG / 4] &= ~int_bit_mask; + } + irq = mips_irq_no; + mips_clear_irq (vm->boot_cpu, irq); + +} + +/*We must map adm irq to mips irq before setting irq*/ +void adm5120_set_irq (vm_instance_t * vm, u_int irq) +{ + assert (irq <= INT_LVL_MAX); + + int mips_irq_no; + m_uint32_t int_bit_mask = 0; + + int_bit_mask = 1 << irq; + + /*set raw status */ + intctrl_table[IRQ_RAW_STATUS_REG / 4] |= int_bit_mask; + + /*check whether irq is enabled */ + if (whether_irq_enable (vm, irq) == FALSE) + return; + + mips_irq_no = adm_irq2mips_irq (vm, irq); + + if (ADM5120_MIPSINT_FIQ == mips_irq_no) { + intctrl_table[FIQ_STATUS_REG / 4] |= int_bit_mask; + } else { + intctrl_table[IRQ_STATUS_REG / 4] |= int_bit_mask; + } + + irq = mips_irq_no; + mips_set_irq (vm->boot_cpu, irq); + mips_update_irq_flag (vm->boot_cpu); + +} + +COMMON_CONFIG_INFO_ARRAY static void printf_configure (adm5120_t * adm5120) +{ + vm_instance_t *vm = adm5120->vm; + PRINT_COMMON_CONFIG_OPTION; +} + +static void adm5120_parse_configure (adm5120_t * adm5120) +{ + vm_instance_t *vm = adm5120->vm; + cfg_opt_t opts[] = { + COMMON_CONFIG_OPTION CFG_END () + }; + cfg_t *cfg; + + cfg = cfg_init (opts, 0); + cfg_parse (cfg, vm->configure_filename); + cfg_free (cfg); + + VALID_COMMON_CONFIG_OPTION; + + if (vm->boot_method == BOOT_BINARY) { + ASSERT (vm->boot_from == 1, + "boot_from must be 1(NOR Flash)\n ADM5120 only can boot from NOR Flash.\n"); + } + + /*Print the configure information */ + printf_configure (adm5120); + +} + +/* Create a router instance */ +vm_instance_t *create_instance (char *configure_filename) +{ + adm5120_t *adm5120; + char *name; + if (!(adm5120 = malloc (sizeof (*adm5120)))) { + fprintf (stderr, "ADM5120': Unable to create new instance!\n"); + return NULL; + } + + memset (adm5120, 0, sizeof (*adm5120)); + name = strdup ("adm5120"); + + if (!(adm5120->vm = vm_create (name, VM_TYPE_ADM5120))) { + fprintf (stderr, "ADM5120 : unable to create VM instance!\n"); + goto err_vm; + } + free (name); + if (configure_filename != NULL) + adm5120->vm->configure_filename = strdup (configure_filename); + adm5120_init_defaults (adm5120); + adm5120_parse_configure (adm5120); + /*init gdb debug */ + vm_debug_init (adm5120->vm); + + adm5120->vm->hw_data = adm5120; + + return (adm5120->vm); + + err_vm: + free (adm5120); + return NULL; + +} + +int init_instance (vm_instance_t * vm) +{ + adm5120_t *adm5120 = VM_ADM5120 (vm); + + if (adm5120_init_platform (adm5120) == -1) { + vm_error (vm, "unable to initialize the platform hardware.\n"); + return (-1); + } + /* IRQ routing */ + vm->set_irq = adm5120_set_irq; + vm->clear_irq = adm5120_clear_irq; + + return (adm5120_boot (adm5120)); + +} diff --git a/tools/virtualmips/adm5120/adm5120.conf b/tools/virtualmips/adm5120/adm5120.conf new file mode 100644 index 0000000..a5508e8 --- /dev/null +++ b/tools/virtualmips/adm5120/adm5120.conf @@ -0,0 +1,34 @@ +#configure file for adm5120 + +# RAM size in kbytes. If not set, default value is 16384. +ram_size = 16384 + +#There are two methods for virtualmips to boot the image. +#Binary. It means virtualmips direct boots the image from ROM or flash. The entry pc is 0x1fc00000. The image contains bootloader and kernel/rootfs. +#ELF. It means virtualmips reads an elf image(setten by kernel_file_name) into sdram and then boots from elf entry point. The elf image contains kernel and rootfs. +#Default boot method is ELF. +#1:Binary 2:elf +boot_method = 2 + + +#boot_from MUST be set if boot_method=1. +#1:NOR_FLASH 2 NAND FLASH +boot_from = 1 + +#If boot_method is elf, that means boot the elf image.kernel_file_name gives the elf image path. +#kernel_file_name MUST be set if boot_method=2. +kernel_file_name = "vmlinux-adm5120" + +#1 NOR 2 NAND +flash_type = 1 +#Flash size. 4 and 0 is valid for NOR type flash. 0 means no flash emulation. 4 means 4M bytes flash(device id=22F9h) emulation. +flash_size = 4 +#Flash file path. If this file does not exist, virtualmips will create it. +flash_file_name = "run.bin" +#flash physical address. for nor flash only +flash_phy_address = 0x1fc00000 + +#set to 1 to enable gdb debug +gdb_debug = 0 +#the port for remote gdb connection +gdb_port = 5555 diff --git a/tools/virtualmips/adm5120/adm5120.h b/tools/virtualmips/adm5120/adm5120.h new file mode 100644 index 0000000..09bc3cb --- /dev/null +++ b/tools/virtualmips/adm5120/adm5120.h @@ -0,0 +1,425 @@ + /* + * Copyright (C) yajin 2008 + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + * + */ + +#ifndef __ADM5120_H__ +#define __ADM5120_H__ + +#include "types.h" + +/*virtual address and physical address*/ +typedef m_uint32_t m_va_t; +typedef m_uint32_t m_pa_t; +typedef m_uint32_t m_reg_t; +typedef m_int32_t m_ireg_t; +typedef m_uint32_t m_cp0_reg_t; + +#define DATA_WIDTH 32 /*64 */ +#define LL + +/*ADM5120 use soft fpu*/ +#define SOFT_FPU 1 + +/*Guest endian*/ +#define GUEST_BYTE_ORDER ARCH_LITTLE_ENDIAN +#ifndef GUEST_BYTE_ORDER +#error Please define guest architecture in utils.h! +#endif + +/* Host to VM conversion functions */ +#if HOST_BYTE_ORDER == GUEST_BYTE_ORDER +#define htovm16(x) (x) +#define htovm32(x) (x) +#define htovm64(x) (x) + +#define vmtoh16(x) (x) +#define vmtoh32(x) (x) +#define vmtoh64(x) (x) +#elif HOST_BYTE_ORDER==ARCH_LITTLE_ENDIAN //host:little guest:big +#define htovm16(x) (htons(x)) +#define htovm32(x) (htonl(x)) +#define htovm64(x) (swap64(x)) + +#define vmtoh16(x) (ntohs(x)) +#define vmtoh32(x) (ntohl(x)) +#define vmtoh64(x) (swap64(x)) +#else //host:big guest:little + +#define htovm16(x) (ntohs(x)) +#define htovm32(x) (ntohl(x)) +#define htovm64(x) (swap64(x)) + +#define vmtoh16(x) (htons(x)) +#define vmtoh32(x) (htonl(x)) +#define vmtoh64(x) (swap64(x)) +#endif + +#define ADM5120_DEFAULT_CONFIG_FILE "adm5120.conf" +#define ADM5120_DEFAULT_RAM_SIZE 16 +#define ADM5120_DEFAULT_BOOT_METHOD BOOT_ELF +#define ADM5120_DEFAULT_KERNEL_FILENAME "vmlinux" +#define ADM5120_ADDR_BUS_MASK 0xffffffff /*32bit phy address */ + +#define ADM5120_CONFIG0 0x80000082 +#define ADM5120_CONFIG1 0x3E613080 /*CACHE (128SET*32 BYTES*2 WAY)= 8K */ +//#define ADM5120_CONFIG7 0x0 + +//#define SOC_CONFIG0 ADM5120_CONFIG0 +//#define SOC_CONFIG1 ADM5120_CONFIG1 +//#define SOC_CONFIG7 ADM5120_CONFIG7 + +#define ADM5120_ROM_PC 0xbfc00000UL +#define ADM5120_PRID 0x0001800b +#define ADM5120_DEFAULT_TLB_ENTRYNO 16 + +struct adm5120_system { + /* Associated VM instance */ + vm_instance_t *vm; +}; + +typedef struct adm5120_system adm5120_t; + +#define VM_ADM5120(vm) ((adm5120_t *)vm->hw_data) + +vm_instance_t *create_instance (char *conf); +int init_instance (vm_instance_t * vm); + +//void virtual_timer(cpu_mips_t *cpu); + +/*---------ADM5120 SOC releated--------------------*/ + +/*========================= Physical Memory Map ============================*/ +#define ADM5120_SDRAM_BASE 0 +#define ADM5120_SMEM1_BASE 0x10000000 + +#define ADM5120_EXTIO0_BASE 0x10C00000 +#define ADM5120_EXTIO1_BASE 0x10E00000 +#define ADM5120_MPMC_BASE 0x11000000 +#define ADM5120_USBHOST_BASE 0x11200000 +#define ADM5120_PCIMEM_BASE 0x11400000 +#define ADM5120_PCIIO_BASE 0x11500000 +#define ADM5120_PCICFG_BASE 0x115FFFF0 +#define ADM5120_MIPS_BASE 0x11A00000 +#define ADM5120_SWCTRL_BASE 0x12000000 + +#define ADM5120_INTC_BASE 0x12200000 +#define ADM5120_SYSC_BASE 0x12400000 + +#define ADM5120_UART0_BASE 0x12600000 +#define ADM5120_UART1_BASE 0x12800000 + +#define ADM5120_SMEM0_BASE 0x1FC00000 + +/*========================= Switch Control Register ========================*/ +/* Control Register */ +#define CODE_REG 0x0000 +#define SftRest_REG 0x0004 +#define Boot_done_REG 0x0008 +#define SWReset_REG 0x000C +#define Global_St_REG 0x0010 +#define PHY_st_REG 0x0014 +#define Port_st_REG 0x0018 +#define Mem_control_REG 0x001C +#define SW_conf_REG 0x0020 +#define CPUp_conf_REG 0x0024 +#define Port_conf0_REG 0x0028 +#define Port_conf1_REG 0x002C +#define Port_conf2_REG 0x0030 + +#define VLAN_G1_REG 0x0040 +#define VLAN_G2_REG 0x0044 +#define Send_trig_REG 0x0048 +#define Srch_cmd_REG 0x004C +#define ADDR_st0_REG 0x0050 +#define ADDR_st1_REG 0x0054 +#define MAC_wt0_REG 0x0058 +#define MAC_wt1_REG 0x005C +#define BW_cntl0_REG 0x0060 +#define BW_cntl1_REG 0x0064 +#define PHY_cntl0_REG 0x0068 +#define PHY_cntl1_REG 0x006C +#define FC_th_REG 0x0070 +#define Adj_port_th_REG 0x0074 +#define Port_th_REG 0x0078 +#define PHY_cntl2_REG 0x007C +#define PHY_cntl3_REG 0x0080 +#define Pri_cntl_REG 0x0084 +#define VLAN_pri_REG 0x0088 +#define TOS_en_REG 0x008C +#define TOS_map0_REG 0x0090 +#define TOS_map1_REG 0x0094 +#define Custom_pri1_REG 0x0098 +#define Custom_pri2_REG 0x009C +#define PHY_cntl4_REG 0x00A0 +#define Empty_cnt_REG 0x00A4 +#define Port_cnt_sel_REG 0x00A8 +#define Port_cnt_REG 0x00AC +#define SW_Int_st_REG 0x00B0 +#define SW_Int_mask_REG 0x00B4 + +// GPIO config +#define GPIO_conf0_REG 0x00B8 +#define GPIO_conf2_REG 0x00BC + +// Watch dog +#define Watchdog0_REG 0x00C0 +#define Watchdog1_REG 0x00C4 + +#define Swap_in_REG 0x00C8 +#define Swap_out_REG 0x00CC + +// Tx/Rx Descriptors +#define Send_HBaddr_REG 0x00D0 +#define Send_LBaddr_REG 0x00D4 +#define Recv_HBaddr_REG 0x00D8 +#define Recv_LBaddr_REG 0x00DC +#define Send_HWaddr_REG 0x00E0 +#define Send_LWaddr_REG 0x00E4 +#define Recv_HWaddr_REG 0x00E8 +#define Recv_LWaddr_REG 0x00EC + +// Timer Control +#define Timer_int_REG 0x00F0 +#define Timer_REG 0x00F4 + +// LED control +#define Port0_LED_REG 0x0100 +#define Port1_LED_REG 0x0104 +#define Port2_LED_REG 0x0108 +#define Port3_LED_REG 0x010c +#define Port4_LED_REG 0x0110 + +#define SW_INDEX_MAX 0x45 //0x0114/4 + +/* Timer_int_REG */ +#define SW_TIMER_INT_DISABLE 0x10000 +#define SW_TIMER_INT 0x1 + +/* Timer_REG */ +#define SW_TIMER_EN 0x10000 +#define SW_TIMER_MASK 0xffff +#define SW_TIMER_10MS_TICKS 0x3D09 +#define SW_TIMER_1MS_TICKS 0x61A +#define SW_TIMER_100US_TICKS 0x9D + +/*==================== MultiPort Memory Controller (MPMC) ==================*/ +/* registers offset */ +#define MPMC_CONTROL_REG 0x0000 +#define MPMC_STATUS_REG 0x0004 +#define MPMC_CONFIG_REG 0x0008 + +#define MPMC_DM_CONTROL_REG 0x0020 +#define MPMC_DM_REFRESH_REG 0x0024 + +#define MPMC_DM_TRP_REG 0x0030 +#define MPMC_DM_TRAS_REG 0x0034 +#define MPMC_DM_TSREX_REG 0x0038 +#define MPMC_DM_TAPR_REG 0x003C +#define MPMC_DM_TDAL_REG 0x0040 +#define MPMC_DM_TWR_REG 0x0044 +#define MPMC_DM_TRC_REG 0x0048 +#define MPMC_DM_TRFC_REG 0x004C +#define MPMC_DM_TXSR_REG 0x0050 +#define MPMC_DM_TRRD_REG 0x0054 +#define MPMC_DM_TMRD_REG 0x0058 + +#define MPMC_SM_EXTWAIT_REG 0x0080 + +#define MPMC_DM_CONFIG0_REG 0x0100 +#define MPMC_DM_RASCAS0_REG 0x0104 + +#define MPMC_DM_CONFIG1_REG 0x0120 +#define MPMC_DM_RASCAS1_REG 0x0124 + +#define MPMC_SM_CONFIG0_REG 0x0200 +#define MPMC_SM_WAITWEN0_REG 0x0204 +#define MPMC_SM_WAITOEN0_REG 0x0208 +#define MPMC_SM_WAITRD0_REG 0x020C +#define MPMC_SM_WAITPAGE0_REG 0x0210 +#define MPMC_SM_WAITWR0_REG 0x0214 +#define MPMC_SM_WAITTURN0_REG 0x0218 + +#define MPMC_SM_CONFIG1_REG 0x0220 +#define MPMC_SM_WAITWEN1_REG 0x0224 +#define MPMC_SM_WAITOEN1_REG 0x0228 +#define MPMC_SM_WAITRD1_REG 0x022C +#define MPMC_SM_WAITPAGE1_REG 0x0230 +#define MPMC_SM_WAITWR1_REG 0x0234 +#define MPMC_SM_WAITTURN1_REG 0x0238 + +#define MPMC_SM_CONFIG2_REG 0x0240 +#define MPMC_SM_WAITWEN2_REG 0x0244 +#define MPMC_SM_WAITOEN2_REG 0x0248 +#define MPMC_SM_WAITRD2_REG 0x024C +#define MPMC_SM_WAITPAGE2_REG 0x0250 +#define MPMC_SM_WAITWR2_REG 0x0254 +#define MPMC_SM_WAITTURN2_REG 0x0258 + +#define MPMC_SM_CONFIG3_REG 0x0260 +#define MPMC_SM_WAITWEN3_REG 0x0264 +#define MPMC_SM_WAITOEN3_REG 0x0268 +#define MPMC_SM_WAITRD3_REG 0x026C +#define MPMC_SM_WAITPAGE3_REG 0x0270 +#define MPMC_SM_WAITWR3_REG 0x0274 +#define MPMC_SM_WAITTURN3_REG 0x0278 + +#define MPMC_INDEX_MAX 0x9f //0x027C/4 + +/*=========================== UART Control Register +========================*/ +#define UART_DR_REG 0x00 +#define UART_RSR_REG 0x04 +#define UART_ECR_REG 0x04 +#define UART_LCR_H_REG 0x08 +#define UART_LCR_M_REG 0x0c +#define UART_LCR_L_REG 0x10 +#define UART_CR_REG 0x14 +#define UART_FR_REG 0x18 +#define UART_IIR_REG 0x1c +#define UART_ICR_REG 0x1C +#define UART_ILPR_REG 0x20 + +/* rsr/ecr reg */ +#define UART_OVERRUN_ERR 0x08 +#define UART_BREAK_ERR 0x04 +#define UART_PARITY_ERR 0x02 +#define UART_FRAMING_ERR 0x01 +#define UART_RX_STATUS_MASK 0x0f +#define UART_RX_ERROR ( UART_BREAK_ERR \ + | UART_PARITY_ERR \ + | UART_FRAMING_ERR) + +/* lcr_h reg */ +#define UART_SEND_BREAK 0x01 +#define UART_PARITY_EN 0x02 +#define UART_EVEN_PARITY 0x04 +#define UART_TWO_STOP_BITS 0x08 +#define UART_ENABLE_FIFO 0x10 + +#define UART_WLEN_5BITS 0x00 +#define UART_WLEN_6BITS 0x20 +#define UART_WLEN_7BITS 0x40 +#define UART_WLEN_8BITS 0x60 +#define UART_WLEN_MASK 0x60 + +/* cr reg */ +#define UART_PORT_EN 0x01 +#define UART_SIREN 0x02 +#define UART_SIRLP 0x04 +#define UART_MODEM_STATUS_INT_EN 0x08 +#define UART_RX_INT_EN 0x10 +#define UART_TX_INT_EN 0x20 +#define UART_RX_TIMEOUT_INT_EN 0x40 +#define UART_LOOPBACK_EN 0x80 + +/* fr reg */ +#define UART_CTS 0x01 +#define UART_DSR 0x02 +#define UART_DCD 0x04 +#define UART_BUSY 0x08 +#define UART_RX_FIFO_EMPTY 0x10 +#define UART_TX_FIFO_FULL 0x20 +#define UART_RX_FIFO_FULL 0x40 +#define UART_TX_FIFO_EMPTY 0x80 + +/* iir/icr reg */ +#define UART_MODEM_STATUS_INT 0x01 +#define UART_RX_INT 0x02 +#define UART_TX_INT 0x04 +#define UART_RX_TIMEOUT_INT 0x08 + +#define UART_INT_MASK 0x0f + +#define ADM5120_UARTCLK_FREQ 62500000 + +/* uart_baudrate */ +#define UART_230400bps_DIVISOR UART_BAUDDIV(230400) +// #define UART_115200bps_DIVISOR UART_BAUDDIV(115200) +#define UART_115200bps_DIVISOR 33 +// #define UART_76800bps_DIVISOR UART_BAUDDIV(76800) +#define UART_76800bps_DIVISOR 50 +// #define UART_57600bps_DIVISOR UART_BAUDDIV(57600) +#define UART_57600bps_DIVISOR 67 +//#define UART_38400bps_DIVISOR UART_BAUDDIV(38400) +#define UART_38400bps_DIVISOR 102 +//#define UART_19200bps_DIVISOR UART_BAUDDIV(19200) +#define UART_19200bps_DIVISOR 202 +//#define UART_14400bps_DIVISOR UART_BAUDDIV(14400) +#define UART_14400bps_DIVISOR 270 +//#define UART_9600bps_DIVISOR UART_BAUDDIV(9600) +#define UART_9600bps_DIVISOR 406 +//#define UART_2400bps_DIVISOR UART_BAUDDIV(2400) +#define UART_2400bps_DIVISOR 1627 +//#define UART_1200bps_DIVISOR UART_BAUDDIV(1200) + +#define UART_INDEX_MAX 0x9 //0x024/4 + +/* pci space +pci memory 0x1140 0000- 0x114f ffff +pci io 0x1150 0000 - 0x 115f ffef +pci configuration address port 0x115ffff0 +pci configuration data port 0x115ffff8 + +*/ +#define ADM5120_PCI_BASE 0x11400000 +#define PCI_INDEX_MAX 0X80000 //0X200000/4 + +/*========================== Interrupt Controller ==========================*/ +/* registers offset */ +#define IRQ_STATUS_REG 0x00 /* Read */ +#define IRQ_RAW_STATUS_REG 0x04 /* Read */ +#define IRQ_ENABLE_REG 0x08 /* Read/Write */ +#define IRQ_DISABLE_REG 0x0C /* Write */ +#define IRQ_SOFT_REG 0x10 /* Write */ + +#define IRQ_MODE_REG 0x14 /* Read/Write */ +#define FIQ_STATUS_REG 0x18 /* Read */ + +/* test registers */ +#define IRQ_TESTSRC_REG 0x1c /* Read/Write */ +#define IRQ_SRCSEL_REG 0x20 /* Read/Write */ +#define IRQ_LEVEL_REG 0x24 /* Read/Write */ + +#define INTCTRL_INDEX_MAX 0xa //0x028/4 + +/* interrupt levels */ +#define INT_LVL_TIMER 0 /* Timer */ +#define INT_LVL_UART0 1 /* Uart 0 */ +#define INT_LVL_UART1 2 /* Uart 1 */ +#define INT_LVL_USBHOST 3 /* USB Host */ +#define INT_LVL_EXTIO_0 4 /* External I/O 0 */ +#define INT_LVL_EXTIO_1 5 /* External I/O 1 */ +#define INT_LVL_PCI_0 6 /* PCI 0 */ +#define INT_LVL_PCI_1 7 /* PCI 1 */ +#define INT_LVL_PCI_2 8 /* PCI 2 */ +#define INT_LVL_SWITCH 9 /* Switch */ +#define INT_LVL_MAX INT_LVL_SWITCH + +/* interrupts */ +#define IRQ_TIMER (0x1 << INT_LVL_TIMER) +#define IRQ_UART0 (0x1 << INT_LVL_UART0) +#define IRQ_UART1 (0x1 << INT_LVL_UART1) +#define IRQ_USBHOST (0x1 << INT_LVL_USBHOST) +#define IRQ_EXTIO_0 (0x1 << INT_LVL_EXTIO_0) +#define IRQ_EXTIO_1 (0x1 << INT_LVL_EXTIO_1) +#define IRQ_PCI_INT0 (0x1 << INT_LVL_PCI_0) +#define IRQ_PCI_INT1 (0x1 << INT_LVL_PCI_1) +#define IRQ_PCI_INT2 (0x1 << INT_LVL_PCI_2) +#define IRQ_SWITCH (0x1 << INT_LVL_SWITCH) + +#define IRQ_MASK 0x3ff + +#define ADM5120_MIPSINT_SOFT0 0 +#define ADM5120_MIPSINT_SOFT1 1 +#define ADM5120_MIPSINT_IRQ 2 +#define ADM5120_MIPSINT_FIQ 3 +#define ADM5120_MIPSINT_REV0 4 +#define ADM5120_MIPSINT_REV1 5 +#define ADM5120_MIPSINT_REV2 6 +#define ADM5120_MIPSINT_TIMER 7 + +#endif diff --git a/tools/virtualmips/adm5120/adm5120_dev_intctrl.c b/tools/virtualmips/adm5120/adm5120_dev_intctrl.c new file mode 100644 index 0000000..bc8bfbe --- /dev/null +++ b/tools/virtualmips/adm5120/adm5120_dev_intctrl.c @@ -0,0 +1,89 @@ + /* + * Copyright (C) yajin 2008 + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + * + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include + +#include "device.h" +#include "mips_memory.h" +#include "adm5120.h" +#include "cpu.h" + +m_uint32_t intctrl_table[INTCTRL_INDEX_MAX]; + +struct intctrl_data { + struct vdevice *dev; + m_uint8_t *intctrl_ptr; + m_uint32_t intctrl_size; +}; + +void *dev_intctrl_access (cpu_mips_t * cpu, struct vdevice *dev, + m_uint32_t offset, u_int op_size, u_int op_type, m_reg_t * data, + m_uint8_t * has_set_value) +{ + + struct intctrl_data *d = dev->priv_data; + + if (offset >= d->intctrl_size) { + *data = 0; + return NULL; + } + + switch (offset) { + case IRQ_DISABLE_REG: + if (MTS_WRITE == op_type) { + intctrl_table[IRQ_ENABLE_REG / 4] = *data & 0x3ff; + *has_set_value = TRUE; + return NULL; + } + break; + } + + return ((void *) (d->intctrl_ptr + offset)); +} + +void dev_intctrl_init_defaultvalue () +{ + +} + +int dev_intctrl_init (vm_instance_t * vm, char *name, m_pa_t paddr, + m_uint32_t len) +{ + struct intctrl_data *d; + + /* allocate the private data structure */ + if (!(d = malloc (sizeof (*d)))) { + fprintf (stderr, "INTCTRL: unable to create device.\n"); + return (-1); + } + + memset (d, 0, sizeof (*d)); + if (!(d->dev = dev_create (name))) + goto err_dev_create; + d->dev->priv_data = d; + d->dev->phys_addr = paddr; + d->dev->phys_len = len; + d->intctrl_ptr = (m_uint8_t *) (m_iptr_t) (&intctrl_table[0]); + d->intctrl_size = len; + d->dev->handler = dev_intctrl_access; + d->dev->flags = VDEVICE_FLAG_NO_MTS_MMAP; + + vm_bind_device (vm, d->dev); + dev_intctrl_init_defaultvalue (); + return (0); + + err_dev_create: + free (d); + return (-1); +} diff --git a/tools/virtualmips/adm5120/adm5120_dev_mpmc.c b/tools/virtualmips/adm5120/adm5120_dev_mpmc.c new file mode 100644 index 0000000..03529bd --- /dev/null +++ b/tools/virtualmips/adm5120/adm5120_dev_mpmc.c @@ -0,0 +1,76 @@ + /* + * Copyright (C) yajin 2008 + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + * + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include + +#include "device.h" +#include "memory.h" +#include "adm5120.h" +#include "cpu.h" + +m_uint32_t mpmc_table[MPMC_INDEX_MAX]; + +struct mpmc_data { + struct vdevice *dev; + m_uint8_t *mpmc_ptr; + m_uint32_t mpmc_size; +}; + +void *dev_mpmc_access (cpu_mips_t * cpu, struct vdevice *dev, + m_uint32_t offset, u_int op_size, u_int op_type, m_reg_t * data, + m_uint8_t * has_set_value) +{ + struct mpmc_data *d = dev->priv_data; + + if (offset >= d->mpmc_size) { + *data = 0; + return NULL; + } + return ((void *) (d->mpmc_ptr + offset)); +} + +void dev_mpmc_init_defaultvalue () +{ + +} + +int dev_mpmc_init (vm_instance_t * vm, char *name, m_pa_t paddr, + m_uint32_t len) +{ + struct mpmc_data *d; + + /* allocate the private data structure */ + if (!(d = malloc (sizeof (*d)))) { + fprintf (stderr, "MPMC: unable to create device.\n"); + return (-1); + } + + memset (d, 0, sizeof (*d)); + if (!(d->dev = dev_create (name))) + goto err_dev_create; + d->dev->priv_data = d; + d->dev->phys_addr = paddr; + d->dev->phys_len = len; + d->mpmc_ptr = (m_uint8_t *) (m_iptr_t) (&mpmc_table[0]); + d->mpmc_size = len; + d->dev->handler = dev_mpmc_access; + d->dev->flags = VDEVICE_FLAG_NO_MTS_MMAP; + vm_bind_device (vm, d->dev); + dev_mpmc_init_defaultvalue (); + return (0); + + err_dev_create: + free (d); + return (-1); +} diff --git a/tools/virtualmips/adm5120/adm5120_dev_pci.c b/tools/virtualmips/adm5120/adm5120_dev_pci.c new file mode 100644 index 0000000..10eca42 --- /dev/null +++ b/tools/virtualmips/adm5120/adm5120_dev_pci.c @@ -0,0 +1,79 @@ + /* + * Copyright (C) yajin 2008 + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + * + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include + +#include "device.h" +#include "memory.h" +#include "adm5120.h" +#include "cpu.h" + +m_uint32_t pci_table[PCI_INDEX_MAX]; + +struct pci_data { + struct vdevice *dev; + m_uint8_t *pci_ptr; + m_uint32_t pci_size; +}; + +void *dev_pci_access (cpu_mips_t * cpu, struct vdevice *dev, + m_uint32_t offset, u_int op_size, u_int op_type, m_reg_t * data, + m_uint8_t * has_set_value) +{ + + struct pci_data *d = dev->priv_data; + + if (offset >= d->pci_size) { + *data = 0; + return NULL; + } + + return ((void *) (d->pci_ptr + offset)); +} + +void dev_pci_init_defaultvalue () +{ + +} + +int dev_pci_init (vm_instance_t * vm, char *name, m_pa_t paddr, + m_uint32_t len) +{ + struct pci_data *d; + + /* allocate the private data structure */ + if (!(d = malloc (sizeof (*d)))) { + fprintf (stderr, "PCI: unable to create device.\n"); + return (-1); + } + + memset (d, 0, sizeof (*d)); + if (!(d->dev = dev_create (name))) + goto err_dev_create; + d->dev->priv_data = d; + d->dev->phys_addr = paddr; + d->dev->phys_len = len; + d->pci_ptr = (m_uint8_t *) (m_iptr_t) (&pci_table[0]); + d->pci_size = len; + d->dev->handler = dev_pci_access; + d->dev->flags = VDEVICE_FLAG_NO_MTS_MMAP; + + vm_bind_device (vm, d->dev); + dev_pci_init_defaultvalue (); + return (0); + + err_dev_create: + free (d); + return (-1); +} diff --git a/tools/virtualmips/adm5120/adm5120_dev_sw.c b/tools/virtualmips/adm5120/adm5120_dev_sw.c new file mode 100644 index 0000000..d4df165 --- /dev/null +++ b/tools/virtualmips/adm5120/adm5120_dev_sw.c @@ -0,0 +1,101 @@ + /* + * Copyright (C) yajin 2008 + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + * + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include + +#include "device.h" +#include "mips_memory.h" +#include "adm5120.h" +#include "cpu.h" + +m_uint32_t sw_table[SW_INDEX_MAX]; + +struct sw_data { + struct vdevice *dev; + m_uint8_t *sw_ptr; + m_uint32_t sw_size; +}; +extern int timeout; +extern m_uint32_t time_reload; +void *dev_sw_access (cpu_mips_t * cpu, struct vdevice *dev, + m_uint32_t offset, u_int op_size, u_int op_type, m_reg_t * data, + m_uint8_t * has_set_value) +{ + struct sw_data *d = dev->priv_data; + if (offset >= d->sw_size) { + *data = 0; + return NULL; + } + + switch (offset) { + case Timer_int_REG: + if (op_type == MTS_WRITE) { + if (*data & SW_TIMER_INT) { + timeout = 0; + } + } else if (op_type == MTS_READ) { + + *data = sw_table[Timer_int_REG / 4] & (~SW_TIMER_INT); + *data |= timeout; + *has_set_value = TRUE; + return NULL; + } else + assert (0); + break; + case Timer_REG: + if (op_type == MTS_WRITE) { + + time_reload = *data & SW_TIMER_MASK; + } + break; + } + return ((void *) (d->sw_ptr + offset)); +} + +void dev_sw_init_defaultvalue () +{ + sw_table[CODE_REG / 4] = 0x34085120; + sw_table[Timer_int_REG / 4] = 0x10000; + sw_table[Timer_REG / 4] = 0xffff; +} + +int dev_sw_init (vm_instance_t * vm, char *name, m_pa_t paddr, m_uint32_t len) +{ + struct sw_data *d; + + /* allocate the private data structure */ + if (!(d = malloc (sizeof (*d)))) { + fprintf (stderr, "SW: unable to create device.\n"); + return (-1); + } + + memset (d, 0, sizeof (*d)); + if (!(d->dev = dev_create (name))) + goto err_dev_create; + d->dev->priv_data = d; + d->dev->phys_addr = paddr; + d->dev->phys_len = len; + d->sw_ptr = (m_uint8_t *) (m_iptr_t) (&sw_table[0]); + d->sw_size = len; + d->dev->handler = dev_sw_access; + d->dev->flags = VDEVICE_FLAG_NO_MTS_MMAP; + + vm_bind_device (vm, d->dev); + dev_sw_init_defaultvalue (); + return (0); + + err_dev_create: + free (d); + return (-1); +} diff --git a/tools/virtualmips/adm5120/adm5120_dev_uart.c b/tools/virtualmips/adm5120/adm5120_dev_uart.c new file mode 100644 index 0000000..b406401 --- /dev/null +++ b/tools/virtualmips/adm5120/adm5120_dev_uart.c @@ -0,0 +1,257 @@ + /* + * Copyright (C) yajin 2008 + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + * + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include + +#include "device.h" +#include "mips_memory.h" +#include "adm5120.h" +#include "cpu.h" + +m_uint32_t uart_table[2][UART_INDEX_MAX]; + +struct uart_data { + struct vdevice *dev; + m_uint8_t *uart_ptr; + m_uint32_t uart_size; + vtty_t *vtty[2]; + +}; +#define ADM5120_UART_IRQ0 1 +#define ADM5120_UART_IRQ1 2 + +void uart_set_interrupt (cpu_mips_t * cpu, int channel) +{ + if (channel == 0) + cpu->vm->set_irq (cpu->vm, INT_LVL_UART0); + else if (channel == 1) + cpu->vm->set_irq (cpu->vm, INT_LVL_UART1); + return; + assert (0); +} + +void uart_clear_interrupt (cpu_mips_t * cpu, int channel) +{ + if (channel == 0) + cpu->vm->clear_irq (cpu->vm, INT_LVL_UART0); + else if (channel == 1) + cpu->vm->clear_irq (cpu->vm, INT_LVL_UART1); + return; + assert (0); +} + +/* Console port input */ +static void tty_con0_input (vtty_t * vtty) +{ + + uart_table[0][UART_FR_REG / 4] &= ~UART_RX_FIFO_EMPTY; + if (vtty_is_full (vtty)) + uart_table[0][UART_FR_REG / 4] |= UART_RX_FIFO_FULL; + if ((uart_table[0][UART_CR_REG / 4] & UART_RX_INT_EN) + && (uart_table[0][UART_CR_REG / 4] & UART_PORT_EN)) { + uart_table[0][UART_ICR_REG / 4] |= UART_RX_INT; + uart_set_interrupt (vtty->vm->boot_cpu, 0); + } + +} + +/* Console port input */ +static void tty_con1_input (vtty_t * vtty) +{ + + uart_table[1][UART_FR_REG / 4] &= ~UART_RX_FIFO_EMPTY; + if (vtty_is_full (vtty)) + uart_table[1][UART_FR_REG / 4] |= UART_RX_FIFO_FULL; + if ((uart_table[1][UART_CR_REG / 4] & UART_RX_INT_EN) + && (uart_table[1][UART_CR_REG / 4] & UART_PORT_EN)) { + uart_set_interrupt (vtty->vm->boot_cpu, 1); + uart_table[1][UART_ICR_REG / 4] |= UART_RX_INT; + } + +} + +void *dev_uart_access (cpu_mips_t * cpu, struct vdevice *dev, + m_uint32_t offset, u_int op_size, u_int op_type, + m_reg_t * data, m_uint8_t * has_set_value, m_uint8_t channel) +{ + + struct uart_data *d = dev->priv_data; + + if (offset >= d->uart_size) { + *data = 0; + return NULL; + } + switch (offset) { + case (UART_DR_REG): + if (!(uart_table[channel][UART_CR_REG / 4] & UART_PORT_EN)) { + //uart port is disabled. + if (op_type == MTS_READ) { + *data = vmtoh32 (0xffffffff); + } + *has_set_value = TRUE; + return NULL; + } + + if (op_type == MTS_READ) { + + if (vtty_is_char_avail (d->vtty[channel])) { + *data = vtty_get_char (d->vtty[channel]); + + uart_table[channel][UART_RSR_REG / 4] = 0; + + } else + *data = vmtoh32 (0xffffffff); + if (vtty_is_char_avail (d->vtty[channel])) { + uart_table[channel][UART_FR_REG / 4] &= ~UART_RX_FIFO_EMPTY; + uart_table[channel][UART_FR_REG / 4] |= UART_RX_FIFO_FULL; + if ((uart_table[channel][UART_CR_REG / 4] & UART_RX_INT_EN) + && (uart_table[channel][UART_CR_REG / 4] & UART_PORT_EN)) { + uart_table[channel][UART_ICR_REG / 4] |= UART_RX_INT; + uart_set_interrupt (cpu, channel); + } + + } else { + uart_table[channel][UART_FR_REG / 4] |= UART_RX_FIFO_EMPTY; + uart_table[channel][UART_FR_REG / 4] &= ~UART_RX_FIFO_FULL; + if ((uart_table[channel][UART_CR_REG / 4] & UART_RX_INT_EN) + && (uart_table[channel][UART_CR_REG / 4] & UART_PORT_EN)) { + uart_table[channel][UART_ICR_REG / 4] &= ~UART_RX_INT; + uart_clear_interrupt (cpu, channel); + } + + } + + *has_set_value = TRUE; + + } else if (op_type == MTS_WRITE) { + + vtty_put_char (d->vtty[channel], (char) *data); + *has_set_value = TRUE; + } else { + assert (0); + } + return NULL; + break; + case UART_RSR_REG: + if (op_type == MTS_WRITE) { + uart_table[channel][UART_RSR_REG / 4] = 0; + *has_set_value = TRUE; + } + break; + case UART_CR_REG: + if (op_type == MTS_WRITE) { + //enable UART + if ((*data) & UART_PORT_EN) { + + if (*data & UART_TX_INT_EN) { + //START TX + uart_table[channel][UART_ICR_REG / 4] |= UART_TX_INT; + uart_set_interrupt (cpu, channel); + + } else { + //TX interrupt dissabled + uart_table[channel][UART_ICR_REG / 4] &= ~UART_TX_INT; + uart_clear_interrupt (cpu, channel); + } + if (*data & UART_RX_INT_EN) { + if (vtty_is_char_avail (d->vtty[channel])) { + //set RX interrupt + uart_table[channel][UART_ICR_REG / 4] |= UART_RX_INT; + uart_set_interrupt (cpu, channel); + } + + } else { + //disable RX interrupt + uart_table[channel][UART_ICR_REG / 4] &= ~UART_RX_INT; + uart_clear_interrupt (cpu, channel); + } + } else { + //disable UART + //clear rx and tx interrupt + uart_table[channel][UART_ICR_REG / 4] &= ~UART_TX_INT; + uart_clear_interrupt (cpu, channel); + uart_table[channel][UART_ICR_REG / 4] &= ~UART_RX_INT; + uart_clear_interrupt (cpu, channel); + } + } + + break; + + } + return ((void *) (d->uart_ptr + offset)); + +} + +void dev_uart_init_defaultvalue (int uart_index) +{ + uart_table[uart_index][UART_FR_REG / 4] = 0x90; + uart_table[uart_index][UART_RSR_REG / 4] = 0; + +} + +void *dev_uart_access0 (cpu_mips_t * cpu, struct vdevice *dev, + m_uint32_t offset, u_int op_size, u_int op_type, m_reg_t * data, + m_uint8_t * has_set_value) +{ + return dev_uart_access (cpu, dev, offset, op_size, op_type, data, + has_set_value, 0); +} + +void *dev_uart_access1 (cpu_mips_t * cpu, struct vdevice *dev, + m_uint32_t offset, u_int op_size, u_int op_type, m_reg_t * data, + m_uint8_t * has_set_value) +{ + return dev_uart_access (cpu, dev, offset, op_size, op_type, data, + has_set_value, 1); +} + +int dev_uart_init (vm_instance_t * vm, char *name, m_pa_t paddr, + m_uint32_t len, vtty_t * vtty, int uart_index) +{ + struct uart_data *d; + + /* allocate the private data structure */ + if (!(d = malloc (sizeof (*d)))) { + fprintf (stderr, "UART: unable to create device.\n"); + return (-1); + } + memset (d, 0, sizeof (*d)); + if (!(d->dev = dev_create (name))) + goto err_dev_create; + d->dev->priv_data = d; + d->dev->phys_addr = paddr; + d->dev->phys_len = len; + d->dev->flags = VDEVICE_FLAG_NO_MTS_MMAP; + + (*d).vtty[uart_index] = vtty; + d->uart_size = len; + if (uart_index == 0) { + d->dev->handler = dev_uart_access0; + (*d).vtty[uart_index]->read_notifier = tty_con0_input; + + } else { + d->dev->handler = dev_uart_access1; + (*d).vtty[uart_index]->read_notifier = tty_con1_input; + } + + d->uart_ptr = (m_uint8_t *) (m_iptr_t) (&uart_table[uart_index]); + + vm_bind_device (vm, d->dev); + dev_uart_init_defaultvalue (uart_index); + return (0); + + err_dev_create: + free (d); + return (-1); +} diff --git a/tools/virtualmips/adm5120/adm5120_host_alarm.c b/tools/virtualmips/adm5120/adm5120_host_alarm.c new file mode 100644 index 0000000..be89a7e --- /dev/null +++ b/tools/virtualmips/adm5120/adm5120_host_alarm.c @@ -0,0 +1,92 @@ + /* + * Copyright (C) yajin 2008 + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + * + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include + +#include "device.h" +#include "adm5120.h" +#include "mips.h" + +#define ADM_FREQ 175000000 /*175MHZ */ + +int instructions = 0; +extern m_uint32_t sw_table[SW_INDEX_MAX]; +#define MAX_INSTRUCTIONS 1 +int timeout = 0; +m_uint32_t time_reload; +extern m_uint32_t uart_table[2][UART_INDEX_MAX]; +extern cpu_mips_t *current_cpu; + +void uart_set_interrupt (cpu_mips_t * cpu, int channel); +/*ADM5120 use host_alarm_handler to process all the things, +This method is deprecated. +JZ4740 uses a timer method, which is more flexible. +See jz4740_host_alam.c */ + +void host_alarm_handler (int host_signum) +{ + + m_uint32_t tim; + if (unlikely (current_cpu->state != CPU_STATE_RUNNING)) + return; + if ((uart_table[0][UART_CR_REG / 4] & UART_RX_INT_EN) + && (uart_table[0][UART_CR_REG / 4] & UART_PORT_EN)) { + if (vtty_is_char_avail (current_cpu->vm->vtty_con1)) { + uart_set_interrupt (current_cpu, 0); + uart_table[0][UART_ICR_REG / 4] |= UART_RX_INT; + return; + } + + } + + if (uart_table[0][UART_CR_REG / 4] & UART_PORT_EN) { + + if (uart_table[0][UART_CR_REG / 4] & UART_TX_INT_EN) { + uart_table[0][UART_ICR_REG / 4] |= UART_TX_INT; + uart_set_interrupt (current_cpu, 0); + return; + } + + } + + /*check count and compare */ + /*Why 2*1000? CPU is 175MHZ, we assume CPI(cycle per instruction)=2 + * see arch/mips/adm5120/setup.c for more information + * 49 void __init mips_time_init(void) + */ + current_cpu->cp0.reg[MIPS_CP0_COUNT] += ADM_FREQ / (2 * 1000); + if (current_cpu->cp0.reg[MIPS_CP0_COMPARE] != 0) { + if (current_cpu->cp0.reg[MIPS_CP0_COUNT] >= + current_cpu->cp0.reg[MIPS_CP0_COMPARE]) { + mips_set_irq (current_cpu, MIPS_TIMER_INTERRUPT); + mips_update_irq_flag (current_cpu); + } + } + + /*Linux kernel does not use this timer. It use mips count */ + if (sw_table[Timer_REG / 4] & SW_TIMER_EN) { + tim = sw_table[Timer_REG / 4] & SW_TIMER_MASK; + if (tim == 0) { + tim = time_reload; + timeout = 1; + } else + tim -= 0x2000; /*1ms=2000*640ns.but 2000 is too slow. I set it to 0x2000 */ + if ((m_int32_t) tim < 0x2000) + tim = 0; + sw_table[Timer_REG / 4] &= ~SW_TIMER_MASK; + sw_table[Timer_REG / 4] += tim; + + } + +} diff --git a/tools/virtualmips/bsd_syscalls.h b/tools/virtualmips/bsd_syscalls.h new file mode 100644 index 0000000..0bd0ae8 --- /dev/null +++ b/tools/virtualmips/bsd_syscalls.h @@ -0,0 +1,164 @@ +/* + * System call switch table. + */ +static const struct { + int narg; + const char *name; +} bsd_syscalls[] = { + { 0, "#0" }, /* 0 = out-of-range */ + { 1, "exit", }, /* 1 = exit */ + { 0, "fork", }, /* 2 = fork */ + { 3, "read", }, /* 3 = read */ + { 3, "write", }, /* 4 = write */ + { 3, "open", }, /* 5 = open */ + { 1, "close", }, /* 6 = close */ + { 4, "wait4", }, /* 7 = wait4 */ + { 0, "#8", }, /* 8 = (old creat) */ + { 2, "link", }, /* 9 = link */ + { 1, "unlink", }, /* 10 = unlink */ + { 2, "execv", }, /* 11 = execv */ + { 1, "chdir", }, /* 12 = chdir */ + { 1, "fchdir", }, /* 13 = fchdir */ + { 3, "mknod", }, /* 14 = mknod */ + { 2, "chmod", }, /* 15 = chmod */ + { 3, "chown", }, /* 16 = chown; now 3 args */ + { 2, "chflags", }, /* 17 = chflags */ + { 2, "fchflags", }, /* 18 = fchflags */ + { 4, "lseek", }, /* 19 = lseek */ + { 0, "getpid", }, /* 20 = getpid */ + { 3, "mount", }, /* 21 = mount */ + { 1, "umount", }, /* 22 = umount */ + { 6, "__sysctl", }, /* 23 = __sysctl */ + { 0, "getuid", }, /* 24 = getuid */ + { 0, "geteuid", }, /* 25 = geteuid */ + { 4, "ptrace", }, /* 26 = ptrace */ + { 0, "getppid", }, /* 27 = getppid */ + { 2, "statfs", }, /* 28 = statfs */ + { 2, "fstatfs", }, /* 29 = fstatfs */ + { 3, "getfsstat", }, /* 30 = getfsstat */ + { 4, "sigaction", }, /* 31 = sigaction */ + { 3, "sigprocmask", }, /* 32 = sigprocmask */ + { 2, "access", }, /* 33 = access */ + { 1, "sigpending", }, /* 34 = sigpending */ + { 2, "sigaltstack", }, /* 35 = sigaltstack */ + { 0, "sync", }, /* 36 = sync */ + { 2, "kill", }, /* 37 = kill */ + { 2, "stat", }, /* 38 = stat */ + { 2, "getlogin", }, /* 39 = getlogin */ + { 2, "lstat", }, /* 40 = lstat */ + { 1, "dup", }, /* 41 = dup */ + { 0, "pipe", }, /* 42 = pipe */ + { 1, "setlogin", }, /* 43 = setlogin */ + { 4, "profil", }, /* 44 = profil */ + { 1, "setuid", }, /* 45 = setuid */ + { 1, "seteuid", }, /* 46 = seteuid */ + { 0, "getgid", }, /* 47 = getgid */ + { 0, "getegid", }, /* 48 = getegid */ + { 1, "setgid", }, /* 49 = setgid */ + { 1, "setegid", }, /* 50 = setegid */ + { 0, "#51", }, /* 51 = unused */ + { 3, "phys", }, /* 52 = (2.9) set phys addr */ + { 1, "lock", }, /* 53 = (2.9) lock in core */ + { 4, "ioctl", }, /* 54 = ioctl */ + { 1, "reboot", }, /* 55 = reboot */ + { 2, "sigwait", }, /* 56 = sigwait */ + { 2, "symlink", }, /* 57 = symlink */ + { 3, "readlink", }, /* 58 = readlink */ + { 3, "execve", }, /* 59 = execve */ + { 1, "umask", }, /* 60 = umask */ + { 1, "chroot", }, /* 61 = chroot */ + { 2, "fstat", }, /* 62 = fstat */ + { 0, "#63", }, /* 63 = reserved */ + { 0, "#64", }, /* 64 = (old getpagesize) */ + { 6, "pselect", }, /* 65 = pselect */ + { 0, "vfork", }, /* 66 = vfork */ + { 0, "#67", }, /* 67 = unused */ + { 0, "#68", }, /* 68 = unused */ + { 1, "brk", }, /* 69 = brk */ + { 0, "#70", }, /* 70 = unused */ + { 0, "#71", }, /* 71 = unused */ + { 0, "#72", }, /* 72 = unused */ + { 0, "#73", }, /* 73 = unused */ + { 0, "#74", }, /* 74 = unused */ + { 0, "#75", }, /* 75 = unused */ + { 0, "vhangup", }, /* 76 = vhangup */ + { 0, "#77", }, /* 77 = unused */ + { 0, "#78", }, /* 78 = unused */ + { 2, "getgroups", }, /* 79 = getgroups */ + { 2, "setgroups", }, /* 80 = setgroups */ + { 1, "getpgrp", }, /* 81 = getpgrp */ + { 2, "setpgrp", }, /* 82 = setpgrp */ + { 3, "setitimer", }, /* 83 = setitimer */ + { 0, "old wait", }, /* 84 = (old wait,wait3) */ + { 0, "#85", }, /* 85 = unused */ + { 2, "getitimer", }, /* 86 = getitimer */ + { 0, "#87", }, /* 87 = (old gethostname) */ + { 0, "#88", }, /* 88 = (old sethostname) */ + { 0, "getdtablesize",}, /* 89 = getdtablesize */ + { 2, "dup2", }, /* 90 = dup2 */ + { 0, "#91", }, /* 91 = unused */ + { 3, "fcntl", }, /* 92 = fcntl */ + { 5, "select", }, /* 93 = select */ + { 0, "#94", }, /* 94 = unused */ + { 1, "fsync", }, /* 95 = fsync */ + { 3, "setpriority", }, /* 96 = setpriority */ + { 3, "socket", }, /* 97 = socket */ + { 3, "connect", }, /* 98 = connect */ + { 3, "accept", }, /* 99 = accept */ + { 2, "getpriority", }, /* 100 = getpriority */ + { 4, "send", }, /* 101 = send */ + { 4, "recv", }, /* 102 = recv */ + { 1, "sigreturn", }, /* 103 = sigreturn */ + { 3, "bind", }, /* 104 = bind */ + { 5, "setsockopt", }, /* 105 = setsockopt */ + { 2, "listen", }, /* 106 = listen */ + { 1, "sigsuspend", }, /* 107 = sigsuspend */ + { 0, "#108", }, /* 108 = (old sigvec) */ + { 0, "#109", }, /* 109 = (old sigblock) */ + { 0, "#110", }, /* 110 = (old sigsetmask) */ + { 0, "#111", }, /* 111 = (old sigpause) */ + { 2, "sigstack", }, /* 112 = sigstack COMPAT-43 */ + { 3, "recvmsg", }, /* 113 = recvmsg */ + { 3, "sendmsg", }, /* 114 = sendmsg */ + { 0, "#115", }, /* 115 = unused */ + { 2, "gettimeofday", }, /* 116 = gettimeofday */ + { 2, "getrusage", }, /* 117 = getrusage */ + { 5, "getsockopt", }, /* 118 = getsockopt */ + { 0, "#119", }, /* 119 = unused */ + { 3, "readv", }, /* 120 = readv */ + { 3, "writev", }, /* 121 = writev */ + { 2, "settimeofday", }, /* 122 = settimeofday */ + { 3, "fchown", }, /* 123 = fchown */ + { 2, "fchmod", }, /* 124 = fchmod */ + { 6, "recvfrom", }, /* 125 = recvfrom */ + { 0, "#126", }, /* 126 = (old setreuid) */ + { 0, "#127", }, /* 127 = (old setregid) */ + { 2, "rename", }, /* 128 = rename */ + { 3, "truncate", }, /* 129 = truncate */ + { 3, "ftruncate", }, /* 130 = ftruncate */ + { 2, "flock", }, /* 131 = flock */ + { 0, "#132", }, /* 132 = nosys */ + { 6, "sendto", }, /* 133 = sendto */ + { 2, "shutdown", }, /* 134 = shutdown */ + { 4, "socketpair", }, /* 135 = socketpair */ + { 2, "mkdir", }, /* 136 = mkdir */ + { 1, "rmdir", }, /* 137 = rmdir */ + { 2, "utimes", }, /* 138 = utimes */ + { 0, "#139", }, /* 139 = unused */ + { 2, "adjtime", }, /* 140 = adjtime */ + { 3, "getpeername", }, /* 141 = getpeername */ + { 0, "#142", }, /* 142 = (old gethostid) */ + { 0, "#143", }, /* 143 = (old sethostid) */ + { 2, "getrlimit", }, /* 144 = getrlimit */ + { 2, "setrlimit", }, /* 145 = setrlimit */ + { 2, "killpg", }, /* 146 = killpg */ + { 0, "#147", }, /* 147 = nosys */ + { 2, "setquota", }, /* 148 = quota */ + { 4, "quota", }, /* 149 = qquota */ + { 3, "getsockname", }, /* 150 = getsockname */ + { 0, "#151", }, /* 151 = unused */ + { 0, "nostk", }, /* 152 = nostk */ + { 1, "fetchi", }, /* 153 = fetchi */ + { 4, "ucall", }, /* 154 = ucall */ + { 0, "fperr", }, /* 155 = fperr */ +}; diff --git a/tools/virtualmips/config.c b/tools/virtualmips/config.c new file mode 100644 index 0000000..001535a --- /dev/null +++ b/tools/virtualmips/config.c @@ -0,0 +1,315 @@ +/* + * Parsing INI-style configuration files. The routines are taken and + * modified from SMB source code (http://samba.anu.edu.au/cifs). + * + * Copyright (C) 2009-2012 Serge Vakulenko + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#include +#include +#include "config.h" + +static const char *confname; +static char *bufr; +static int bsize; +static char *cursec; + +/* + * Scan to the end of a comment. + */ +static int eat_comment (FILE *fp) +{ + int c; + + c = getc (fp); + while (c > 0 && c != '\n') + c = getc (fp); + return c; +} + +/* + * Skip whitespaces to end of line. + */ +static int eat_whitespace (FILE *fp) +{ + int c; + + c = getc (fp); + while (isspace(c) && c != '\n') + c = getc (fp); + return c; +} + +/* + * Search for continuation backshash, starting from line end, + * When found, return it's index. + * When no continuation, return -1. + */ +static int find_continuation (char *line, int pos) +{ + pos--; + while (pos >= 0 && isspace (line [pos])) + pos--; + if (pos >= 0 && line[pos] == '\\') + return pos; + /* No continuation. */ + return -1; +} + +/* + * Scan a parameter name (or name and value pair) and pass the value (or + * values) to function pfunc(). + */ +static void parse_parameter (FILE *fp, + void (*pfunc) (void*, char*, char*, char*), + void *arg, + int c) +{ + int i = 0; /* position withing bufr */ + int end = 0; /* bufr[end] is current end-of-string */ + int vstart = 0; /* starting position of the parameter */ + + /* Loop until we found the start of the value */ + while (vstart == 0) { + /* Ensure there's space for next char */ + if (i > (bsize-2)) { + bsize += 1024; + bufr = realloc (bufr, bsize); + if (! bufr) { + fprintf (stderr, "%s: malloc failed\n", confname); + exit (-1); + } + } + switch (c) { + case '=': + if (end == 0) { + fprintf (stderr, "%s: invalid parameter name\n", confname); + exit (-1); + } + bufr[end++] = '\0'; + i = end; + vstart = end; + bufr[i] = '\0'; + break; + + case ';': /* comment line */ + case '#': + c = eat_comment (fp); + case '\n': + i = find_continuation (bufr, i); + if (i < 0) { + /* End of line, but no assignment symbol. */ + bufr[end]='\0'; + fprintf (stderr, "%s: bad line, ignored: `%s'\n", + confname, bufr); + return; + } + end = ((i > 0) && (bufr[i-1] == ' ')) ? (i-1) : (i); + c = getc (fp); + break; + + case '\0': + case EOF: + bufr[i] = '\0'; + fprintf (stderr, "%s: unexpected end-of-file at %s: func\n", + confname, bufr); + exit (-1); + + default: + if (isspace (c)) { + bufr[end] = ' '; + i = end + 1; + c = eat_whitespace (fp); + } else { + bufr[i++] = c; + end = i; + c = getc (fp); + } + break; + } + } + + /* Now parse the value */ + c = eat_whitespace (fp); + while (c > 0) { + if (i > (bsize-2)) { + bsize += 1024; + bufr = realloc (bufr, bsize); + if (! bufr) { + fprintf (stderr, "%s: malloc failed\n", confname); + exit (-1); + } + } + switch(c) { + case '\r': + c = getc (fp); + break; + + case ';': /* comment line */ + case '#': + c = eat_comment (fp); + case '\n': + i = find_continuation (bufr, i); + if (i < 0) + c = 0; + else { + for (end=i; (end >= 0) && isspace (bufr[end]); end--) + ; + c = getc (fp); + } + break; + + default: + bufr[i++] = c; + if (! isspace (c)) + end = i; + c = getc (fp); + break; + } + } + bufr[end] = '\0'; + pfunc (arg, cursec, bufr, &bufr [vstart]); +} + +/* + * Scan a section name and remember it in `cursec'. + */ +static void parse_section (FILE *fp) +{ + int c, i, end; + + /* We've already got the '['. Scan past initial white space. */ + c = eat_whitespace (fp); + i = 0; + end = 0; + while (c > 0) { + if (i > (bsize-2)) { + bsize += 1024; + bufr = realloc (bufr, bsize); + if (! bufr) { + fprintf (stderr, "%s: malloc failed\n", confname); + exit (-1); + } + } + switch (c) { + case ']': /* found the closing bracked */ + bufr[end] = '\0'; + if (end == 0) { + fprintf (stderr, "%s: empty section name\n", confname); + exit (-1); + } + /* Register a section. */ + if (cursec) + free (cursec); + cursec = strdup (bufr); + + eat_comment (fp); + return; + + case '\n': + i = find_continuation (bufr, i); + if (i < 0) { + bufr [end] = 0; + fprintf (stderr, "%s: invalid line: '%s'\n", + confname, bufr); + exit (-1); + } + end = ((i > 0) && (bufr[i-1] == ' ')) ? (i-1) : (i); + c = getc (fp); + break; + + default: + if (isspace (c)) { + bufr[end] = ' '; + i = end + 1; + c = eat_whitespace (fp); + } else { + bufr[i++] = c; + end = i; + c = getc (fp); + } + break; + } + } +} + +/* + * Process the named parameter file + */ +void conf_parse (const char *filename, + void (*pfunc) (void*, char*, char*, char*), + void *arg) +{ + FILE *fp; + int c; + + confname = filename; + fp = fopen (filename, "r"); + if (! fp) { + fprintf (stderr, "%s: unable to open config file\n", filename); + exit (-1); + } + bsize = 1024; + bufr = (char*) malloc (bsize); + if (! bufr) { + fprintf (stderr, "%s: malloc failed\n", confname); + fclose (fp); + exit (-1); + } + + /* Parse file. */ + c = eat_whitespace (fp); + while (c > 0) { + switch (c) { + case '\n': /* blank line */ + c = eat_whitespace (fp); + break; + case ';': /* comment line */ + case '#': + c = eat_comment (fp); + break; + case '[': /* section header */ + parse_section (fp); + c = eat_whitespace (fp); + break; + case '\\': /* bogus backslash */ + c = eat_whitespace (fp); + break; + default: /* parameter line */ + parse_parameter (fp, pfunc, arg, c); + c = eat_whitespace (fp); + break; + } + } + fclose (fp); + if (cursec) { + free (cursec); + cursec = 0; + } + free (bufr); + bufr = 0; + bsize = 0; +} diff --git a/tools/virtualmips/config.h b/tools/virtualmips/config.h new file mode 100644 index 0000000..75ff6ac --- /dev/null +++ b/tools/virtualmips/config.h @@ -0,0 +1,31 @@ +/* + * Parsing INI-style configuration files. The routines are taken and + * modified from SMB source code (http://samba.anu.edu.au/cifs). + * + * Copyright (C) 2009-2012 Serge Vakulenko + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +void conf_parse (const char *filename, + void (*pfunc) (void*, char*, char*, char*), + void *arg); diff --git a/tools/virtualmips/cpu.c b/tools/virtualmips/cpu.c new file mode 100644 index 0000000..32541a7 --- /dev/null +++ b/tools/virtualmips/cpu.c @@ -0,0 +1,304 @@ + /* + * Copyright (C) yajin 2008 + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + */ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cpu.h" +#include "mips_memory.h" +#include "device.h" +#include "mips.h" +#include "mips_cp0.h" +#include "mips_exec.h" +#include "vm.h" + +#define LOG_ENABLE 0 + +/* + * Log a message for a CPU + */ +void cpu_log (cpu_mips_t * cpu, char *module, char *format, ...) +{ +#if LOG_ENABLE + char buffer[256]; + va_list ap; + + va_start (ap, format); + snprintf (buffer, sizeof (buffer), "CPU%u: %s", cpu->id, module); + vm_flog (cpu->vm, buffer, format, ap); + va_end (ap); +#endif +} + +/* + * Start a CPU + */ +void cpu_start (cpu_mips_t * cpu) +{ + if (cpu) { + cpu->state = CPU_STATE_RUNNING; + } +} + +/* + * Stop a CPU + */ +void cpu_stop (cpu_mips_t * cpu) +{ + if (cpu) { + cpu_log (cpu, "CPU_STATE", "Halting CPU (old state=%u)...\n", + cpu->state); + cpu->state = CPU_STATE_HALTED; + } +} + +void cpu_restart (cpu_mips_t * cpu) +{ + if (cpu) { + cpu_log (cpu, "CPU_STATE", "Restartting CPU (old state=%u)...\n", + cpu->state); + cpu->state = CPU_STATE_RESTARTING; + } +} + +/* + * Create a new CPU + */ +cpu_mips_t *cpu_create (vm_instance_t * vm, u_int type, u_int id) +{ + cpu_mips_t *cpu; + + cpu = malloc (sizeof (*cpu)); + if (!cpu) + return NULL; + + memset (cpu, 0, sizeof (*cpu)); + cpu->vm = vm; + cpu->id = id; + cpu->type = type; + cpu->state = CPU_STATE_SUSPENDED; + cpu->vm = vm; + mips_init (cpu); + return cpu; +} + +/* + * Delete a CPU + */ +void cpu_delete (cpu_mips_t * cpu) +{ + if (cpu) { + /* Stop activity of this CPU */ + cpu_stop (cpu); + pthread_join (cpu->cpu_thread, NULL); + mips_delete (cpu); + free (cpu); + } +} + +/* + * Find a CPU in a group given its ID + */ +cpu_mips_t *cpu_group_find_id (cpu_group_t * group, u_int id) +{ + cpu_mips_t *cpu; + + if (!group) + return NULL; + + for (cpu = group->cpu_list; cpu; cpu = cpu->next) + if (cpu->id == id) + return cpu; + + return NULL; +} + +/* + * Find the highest CPU ID in a CPU group + */ +int cpu_group_find_highest_id (cpu_group_t * group, u_int * highest_id) +{ + cpu_mips_t *cpu; + u_int max_id = 0; + + if (!group || group->cpu_list) + return (-1); + + for (cpu = group->cpu_list; cpu; cpu = cpu->next) + if (cpu->id >= max_id) + max_id = cpu->id; + + *highest_id = max_id; + return (0); +} + +/* + * Add a CPU in a CPU group + */ +int cpu_group_add (cpu_group_t * group, cpu_mips_t * cpu) +{ + if (!group) + return (-1); + + /* check that we don't already have a CPU with this id */ + if (cpu_group_find_id (group, cpu->id) != NULL) { + fprintf (stderr, "cpu_group_add: CPU%u already present in group.\n", + cpu->id); + return (-1); + } + cpu->next = group->cpu_list; + group->cpu_list = cpu; + return (0); +} + +/* + * Create a new CPU group + */ +cpu_group_t *cpu_group_create (char *name) +{ + cpu_group_t *group; + + if (!(group = malloc (sizeof (*group)))) + return NULL; + + group->name = name; + group->cpu_list = NULL; + return group; +} + +/* + * Delete a CPU group + */ +void cpu_group_delete (cpu_group_t * group) +{ + cpu_mips_t *cpu, *next; + + if (group != NULL) { + for (cpu = group->cpu_list; cpu; cpu = next) { + next = cpu->next; + cpu_delete (cpu); + } + free (group); + } +} + +/* + * Rebuild the MTS subsystem for a CPU group + */ +int cpu_group_rebuild_mts (cpu_group_t * group) +{ + cpu_mips_t *cpu; + + for (cpu = group->cpu_list; cpu; cpu = cpu->next) + cpu->mts_rebuild (cpu); + + return (0); +} + +/* + * Start all CPUs of a CPU group + */ +void cpu_group_start_all_cpu (cpu_group_t * group) +{ + cpu_mips_t *cpu; + + for (cpu = group->cpu_list; cpu; cpu = cpu->next) + cpu_start (cpu); +} + +/* + * Stop all CPUs of a CPU group + */ +void cpu_group_stop_all_cpu (cpu_group_t * group) +{ + cpu_mips_t *cpu; + + for (cpu = group->cpu_list; cpu; cpu = cpu->next) + cpu_stop (cpu); +} + +/* + * Set a state of all CPUs of a CPU group + */ +void cpu_group_set_state (cpu_group_t * group, u_int state) +{ + cpu_mips_t *cpu; + + for (cpu = group->cpu_list; cpu; cpu = cpu->next) + cpu->state = state; +} + +/* + * Returns TRUE if all CPUs in a CPU group are inactive + */ +static int cpu_group_check_activity (cpu_group_t * group) +{ + cpu_mips_t *cpu; + + for (cpu = group->cpu_list; cpu; cpu = cpu->next) { + if (!cpu->cpu_thread_running) + continue; + if (cpu->state == CPU_STATE_RUNNING) + return (FALSE); + } + return (TRUE); +} + +/* + * Synchronize on CPUs (all CPUs must be inactive) + */ +int cpu_group_sync_state (cpu_group_t * group) +{ + m_tmcnt_t t1, t2; + + /* Check that CPU activity is really suspended */ + t1 = m_gettime (); + + while (!cpu_group_check_activity (group)) { + t2 = m_gettime (); + + if (t2 > (t1 + 10000)) + return (-1); + + usleep (50000); + } + return (0); +} + +/* + * Save state of all CPUs + */ +int cpu_group_save_state (cpu_group_t * group) +{ + cpu_mips_t *cpu; + + for (cpu = group->cpu_list; cpu; cpu = cpu->next) + cpu->prev_state = cpu->state; + + return (TRUE); +} + +/* + * Restore state of all CPUs + */ +int cpu_group_restore_state (cpu_group_t * group) +{ + cpu_mips_t *cpu; + + for (cpu = group->cpu_list; cpu; cpu = cpu->next) + cpu->state = cpu->prev_state; + + return (TRUE); +} diff --git a/tools/virtualmips/cpu.h b/tools/virtualmips/cpu.h new file mode 100644 index 0000000..b394639 --- /dev/null +++ b/tools/virtualmips/cpu.h @@ -0,0 +1,60 @@ + /* + * Copyright (C) yajin 2008 + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + * + */ + +#ifndef __CPU_H__ +#define __CPU_H__ + +#include + +#include "utils.h" +#include "mips.h" +#include "system.h" + +/* Possible CPU types */ +enum { + CPU_TYPE_MIPS64 = 1, + CPU_TYPE_MIPS32, +}; + +/* Virtual CPU states */ +enum { + CPU_STATE_RUNNING = 0, /*cpu is running */ + CPU_STATE_HALTED, + CPU_STATE_SUSPENDED, /*CPU is SUSPENDED */ + CPU_STATE_RESTARTING, /*cpu is restarting */ + CPU_STATE_PAUSING, /*cpu is pausing for timer */ +}; + +/* CPU group definition */ +typedef struct cpu_group cpu_group_t; +struct cpu_group { + char *name; + cpu_mips_t *cpu_list; + void *priv_data; +}; + +void cpu_log (cpu_mips_t * cpu, char *module, char *format, ...); +void cpu_start (cpu_mips_t * cpu); +void cpu_stop (cpu_mips_t * cpu); +void cpu_restart (cpu_mips_t * cpu); +cpu_mips_t *cpu_create (vm_instance_t * vm, u_int type, u_int id); +void cpu_delete (cpu_mips_t * cpu); +cpu_mips_t *cpu_group_find_id (cpu_group_t * group, u_int id); +int cpu_group_find_highest_id (cpu_group_t * group, u_int * highest_id); +int cpu_group_add (cpu_group_t * group, cpu_mips_t * cpu); +cpu_group_t *cpu_group_create (char *name); +void cpu_group_delete (cpu_group_t * group); +int cpu_group_rebuild_mts (cpu_group_t * group); +void cpu_group_start_all_cpu (cpu_group_t * group); +void cpu_group_stop_all_cpu (cpu_group_t * group); +void cpu_group_set_state (cpu_group_t * group, u_int state); +int cpu_group_sync_state (cpu_group_t * group); +int cpu_group_save_state (cpu_group_t * group); +int cpu_group_restore_state (cpu_group_t * group); + +#endif diff --git a/tools/virtualmips/crc.c b/tools/virtualmips/crc.c new file mode 100644 index 0000000..1144589 --- /dev/null +++ b/tools/virtualmips/crc.c @@ -0,0 +1,100 @@ +/* + * Cisco router simulation platform. + * Copyright (c) 2006 Christophe Fillot (cf@utc.fr) + * + * CRC functions. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "utils.h" +#include "crc.h" + +#define CRC12_POLY 0x0f01 +#define CRC16_POLY 0xa001 +#define CRC32_POLY 0xedb88320L + +/* CRC tables */ +m_uint16_t crc12_array[256], crc16_array[256]; +m_uint32_t crc32_array[256]; + +/* Initialize CRC-12 algorithm */ +static void crc12_init (void) +{ + m_uint16_t crc, c; + int i, j; + + for (i = 0; i < 256; i++) { + crc = 0; + c = (m_uint16_t) i; + + for (j = 0; j < 8; j++) { + if ((crc ^ c) & 0x0001) + crc = (crc >> 1) ^ CRC12_POLY; + else + crc = crc >> 1; + + c = c >> 1; + } + + crc12_array[i] = crc; + } +} + +/* Initialize CRC-16 algorithm */ +static void crc16_init (void) +{ + m_uint16_t crc, c; + int i, j; + + for (i = 0; i < 256; i++) { + crc = 0; + c = (m_uint16_t) i; + + for (j = 0; j < 8; j++) { + if ((crc ^ c) & 0x0001) + crc = (crc >> 1) ^ CRC16_POLY; + else + crc = crc >> 1; + + c = c >> 1; + } + + crc16_array[i] = crc; + } +} + +/* Initialize CRC-32 algorithm */ +static void crc32_init (void) +{ + unsigned long c; + int n, k; + + for (n = 0; n < 256; n++) { + c = (unsigned long) n; + for (k = 0; k < 8; k++) { + if (c & 1) + c = CRC32_POLY ^ (c >> 1); + else + c = c >> 1; + } + crc32_array[n] = c; + } +} + +/* Initialize CRC algorithms */ +void crc_init (void) +{ + crc12_init (); + crc16_init (); + crc32_init (); +} diff --git a/tools/virtualmips/crc.h b/tools/virtualmips/crc.h new file mode 100644 index 0000000..01d451b --- /dev/null +++ b/tools/virtualmips/crc.h @@ -0,0 +1,62 @@ +/* + * Cisco router simulation platform. + * Copyright (c) 2006 Christophe Fillot (cf@utc.fr) + * + * CRC functions. + */ + +#ifndef __CRC_H__ +#define __CRC_H__ + +#include +#include "utils.h" + +extern m_uint16_t crc12_array[], crc16_array[]; +extern m_uint32_t crc32_array[]; + +/* Compute a CRC-12 hash on a 32-bit integer */ +static forced_inline m_uint32_t crc12_hash_u32 (m_uint32_t val) +{ + register m_uint32_t crc = 0; + register int i; + + for (i = 0; i < 4; i++) { + crc = (crc >> 8) ^ crc12_array[(crc ^ val) & 0xff]; + val >>= 8; + } + + return (crc); +} + +/* Compute a CRC-16 hash on a 32-bit integer */ +static forced_inline m_uint32_t crc16_hash_u32 (m_uint32_t val) +{ + register m_uint32_t crc = 0; + register int i; + + for (i = 0; i < 4; i++) { + crc = (crc >> 8) ^ crc16_array[(crc ^ val) & 0xff]; + val >>= 8; + } + + return (crc); +} + +/* Compute a CRC-32 on the specified block */ +static forced_inline m_uint32_t crc32_compute (m_uint32_t crc_accum, + m_uint8_t * ptr, int len) +{ + unsigned long c = crc_accum; + int n; + + for (n = 0; n < len; n++) { + c = crc32_array[(c ^ ptr[n]) & 0xff] ^ (c >> 8); + } + + return (~c); +} + +/* Initialize CRC algorithms */ +void crc_init (void); + +#endif diff --git a/tools/virtualmips/debug.c b/tools/virtualmips/debug.c new file mode 100644 index 0000000..472bd29 --- /dev/null +++ b/tools/virtualmips/debug.c @@ -0,0 +1,89 @@ + /* + * Copyright (C) yajin 2008 + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + * + */ + +/* + A simple interface for GDB. + Based on SimOS. + */ + +#define _GNU_SOURCE +#include +#include + +#include "vm.h" +#include "mips.h" +#include "utils.h" +#include "debug.h" + +int forced_inline mips_debug (vm_instance_t * vm, int is_break) +{ + Simdebug_result res; + + res = Simdebug_run (vm, is_break ? SIGTRAP : SIGUSR2); + + switch (res) { + case SD_CONTINUE: + vm->mipsy_break_nexti = MIPS_NOBREAK; + vm->mipsy_debug_mode = 1; + break; + case SD_NEXTI_ANYCPU: + vm->mipsy_break_nexti = MIPS_BREAKANYCPU; + vm->mipsy_debug_mode = 1; + break; + default: + vm->mipsy_break_nexti = res; + vm->mipsy_debug_mode = 1; + break; + } + + return 0; + +} + +void vm_debug_init (vm_instance_t * vm) +{ + struct sockaddr_in sockaddr; + int tmp; + + if (vm->gdb_debug != 1) + return; + vm->mipsy_debug_mode = 1; + vm->mipsy_break_nexti = -1; + vm->gdb_interact_sock = -1; + vm->gdb_debug_from_poll = 0; + + vm->gdb_listen_sock = socket (PF_INET, SOCK_STREAM, 0); + if (vm->gdb_listen_sock < 0) { + fprintf (stderr, "Can't open debug socket. Run without gdb debug\n"); + vm->gdb_debug = 0; + return; + } + + /* Allow rapid reuse of this port. */ + tmp = 1; + if (setsockopt (vm->gdb_listen_sock, SOL_SOCKET, SO_REUSEADDR, + (char *) &tmp, sizeof (tmp)) < 0) { + printf ("simdebug setsockopt SO_REUSEADDR"); + /* Not fatal */ + } + bzero ((char *) &sockaddr, sizeof (struct sockaddr_in)); + + sockaddr.sin_family = PF_INET; + sockaddr.sin_port = htons (vm->gdb_port); + sockaddr.sin_addr.s_addr = INADDR_ANY; + + while (bind (vm->gdb_listen_sock, (struct sockaddr *) &sockaddr, + sizeof (sockaddr)) || listen (vm->gdb_listen_sock, 1)) { + vm->gdb_port++; + sockaddr.sin_port = htons (vm->gdb_port); + } + + vm->breakpoint_head = 0; + vm->breakpoint_tail = 0; + +} diff --git a/tools/virtualmips/debug.h b/tools/virtualmips/debug.h new file mode 100644 index 0000000..ab929bc --- /dev/null +++ b/tools/virtualmips/debug.h @@ -0,0 +1,20 @@ + /* + * Copyright (C) yajin 2008 + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + * + */ + +#ifndef __DEBUG_H__ +#define __DEBUG_H__ + +#include "vm.h" + +#define MIPS_NOBREAK (-2) +#define MIPS_BREAKANYCPU (-1) + +void vm_debug_init (vm_instance_t * vm); +int mips_debug (vm_instance_t * vm, int is_break); + +#endif diff --git a/tools/virtualmips/dev_cs8900.c b/tools/virtualmips/dev_cs8900.c new file mode 100644 index 0000000..5ee1f8f --- /dev/null +++ b/tools/virtualmips/dev_cs8900.c @@ -0,0 +1,917 @@ + /* + * Copyright (C) yajin 2008 + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + * + */ + + /* + * cs8900 net card emulation. + * (jz4740 driver). + * Only works in linux 2.6.24/2.6.22/2.4.20 + * uboot can not use it. + * + * Please use TCP instead of UDP when using NFS. + * Throughput is about 50k-100k bytes per second when downloading a file from host using http. + * Maybe improved when JIT is implemented in the future. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "crc.h" +#include "utils.h" +#include "cpu.h" +#include "vm.h" +#include "mips_memory.h" +#include "device.h" +#include "net.h" +#include "net_io.h" +#include "dev_cs8900.h" + +/*#define QUEUE_SIZE 128 +#define PACKET_LEN 1600 +m_uint8_t recv_buffer[QUEUE_SIZE][PACKET_LEN]; +m_uint8_t packet_len[QUEUE_SIZE]; + +m_uint8_t read_index=0; +m_uint8_t write_index=0; +*/ + +/*00:62:9c:61:cf:16*/ +static uint8_t cs8900a_default_mac[6] = + { 0x00, 0x62, 0x9c, 0x61, 0xcf, 0x16 }; + +#define CS8900_DEFAULT_RX_TIMEOUT 40 +#define CS8900_MIN_RX_TIMEOUT 20 +#define CS8900_MAX_RX_TIMEOUT 100 +#define CS8900_RX_TIMEOUT_STEP 5 + +static m_uint32_t cs8900a_rx_timeout = CS8900_DEFAULT_RX_TIMEOUT; + +/* Maximum packet size */ +#define CS8900_MAX_PKT_SIZE 1518 +#define CS8900_MIN_PKT_SIZE 8 +#define CS8900_RUN_PKT_SIZE 64 + +#define CS8900A_PRODUCT_ID 0x630e /*little endian */ + +#define PP_RT_DATA0 0x00 +#define PP_RT_DATA1 0x02 +#define PP_TX_CMD 0X04 +#define PP_TX_LEN 0X06 +#define PP_IO_ISQ 0X08 +#define PP_ADDRESS 0x0a /* PacketPage Pointer Port (Section 4.10.10) */ +#define PP_DATA0 0x0c /* PacketPage Data Port (Section 4.10.10) */ +#define PP_DATA1 0X0e + +#define PP_ProductID 0x0000 /* Section 4.3.1 Product Identification Code */ +#define PP_ISAIOB 0x0020 /* IO base address */ +#define PP_IntNum 0x0022 /* Section 3.2.3 Interrupt Number */ +#define PP_ISASOF 0x0026 /* ISA DMA offset */ +#define PP_DmaFrameCnt 0x0028 /* ISA DMA Frame count */ +#define PP_DmaByteCnt 0x002A /* ISA DMA Byte count */ +#define PP_MemBase 0x002c /* Section 4.9.2 Memory Base Address Register */ +#define PP_EEPROMCommand 0x0040 /* Section 4.3.11 EEPROM Command */ +#define PP_EEPROMData 0x0042 /* Section 4.3.12 EEPROM Data */ + +#define PP_RxCFG 0x0102 /* Section 4.4.6 Receiver Configuration */ +#define PP_RxCTL 0x0104 /* Section 4.4.8 Receiver Control */ +#define PP_TxCFG 0x0106 /* Section 4.4.9 Transmit Configuration */ +#define PP_BufCFG 0x010a /* Section 4.4.12 Buffer Configuration */ +#define PP_LineCTL 0x0112 /* Section 4.4.16 Line Control */ +#define PP_SelfCTL 0x0114 /* Section 4.4.18 Self Control */ +#define PP_BusCTL 0x0116 /* Section 4.4.20 Bus Control */ +#define PP_TestCTL 0x0118 /* Section 4.4.22 Test Control */ +#define PP_AutoNegCTL 0x011C /* Auto Negotiation Ctrl */ +#define PP_ISQ 0x0120 /* Section 4.4.5 Interrupt Status Queue */ +#define PP_RxEvent 0x0124 /* Rx Event Register */ +#define PP_TxEvent 0x0128 /* Section 4.4.10 Transmitter Event */ +#define PP_BufEvent 0x012c /* Section 4.4.13 Buffer Event */ +#define PP_RxMISS 0x0130 /* Section 4.4.14 Receiver Miss Counter */ +#define PP_TxCOL 0x0132 /* Section 4.4.15 Transmit Collision Counter */ +#define PP_LineST 0x0134 /* Line State Register */ +#define PP_SelfST 0x0136 /* Section 4.4.19 Self Status */ +#define PP_BusST 0x0138 /* Section 4.4.21 Bus Status */ +#define PP_TDR 0x013C /* Time Domain Reflectometry */ +#define PP_AutoNegST 0x013E /* Auto Neg Status */ +#define PP_TxCMD 0x0144 /* Section 4.4.11 Transmit Command */ +#define PP_TxLength 0x0146 /* Section 4.5.2 Transmit Length */ +#define PP_LAF 0x0150 /* Hash Table */ +#define PP_IA 0x0158 /* Section 4.6.2 Individual Address (IEEE Address) */ + +#define PP_RxStatus 0x0400 /* Section 4.7.1 Receive Status */ +#define PP_RxLength 0x0402 /* Section 4.7.1 Receive Length (in bytes) */ +#define PP_RxFrame 0x0404 /* Section 4.7.2 Receive Frame Location */ +#define PP_TxFrame 0x0a00 /* Section 4.7.2 Transmit Frame Location */ + +/* PP_RxCFG */ +#define Skip_1 0x0040 +#define StreamE 0x0080 +#define RxOKiE 0x0100 +#define RxDMAonly 0x0200 +#define AutoRxDMAE 0x0400 +#define BufferCRC 0x0800 +#define CRCerroriE 0x1000 +#define RuntiE 0x2000 +#define ExtradataiE 0x4000 + + /* PP_TxCFG */ +#define Loss_of_CRSiE 0x0040 +#define SQErroriE 0x0080 +#define TxOKiE 0x0100 +#define Out_of_windowiE 0x0200 +#define JabberiE 0x0400 +#define AnycolliE 0x0800 +#define T16colliE 0x8000 + +/* PP_BufCFG */ +#define SWint_X 0x0040 +#define RxDMAiE 0x0080 +#define Rdy4TxiE 0x0100 +#define TxUnderruniE 0x0200 +#define RxMissiE 0x0400 +#define Rx128iE 0x0800 +#define TxColOvfiE 0x1000 +#define MissOvfloiE 0x2000 +#define RxDestiE 0x8000 + + /* PP_RxCTL */ +#define IAHashA 0x0040 +#define PromiscuousA 0x0080 +#define RxOKA 0x0100 +#define MulticastA 0x0200 +#define IndividualA 0x0400 +#define BroadcastA 0x0800 +#define CRCerrorA 0x1000 +#define RuntA 0x2000 +#define ExtradataA 0x4000 + + /* PP_SelfCTL */ +#define RESET 0x0040 +#define SWSuspend 0x0100 +#define HWSleepE 0x0200 +#define HWStandbyE 0x0400 +#define HC0E 0x1000 +#define HC1E 0x2000 +#define HCB0 0x4000 +#define HCB1 0x8000 + +/* PP_LineCTL */ +#define SerRxON 0x0040 +#define SerTxON 0x0080 +#define AUIonly 0x0100 +#define AutoAUI_10BT 0x0200 +#define ModBackoffE 0x0800 +#define PolarityDis 0x1000 +#define L2_partDefDis 0x2000 +#define LoRxSquelch 0x4000 + +/* PP_TxEvent */ +#define Loss_of_CRS 0x0040 +#define SQEerror 0x0080 +#define TxOK 0x0100 +#define Out_of_window 0x0200 +#define Jabber 0x0400 +#define T16coll 0x8000 + +#define RxEvent 0x0004 +#define TxEvent 0x0008 +#define BufEvent 0x000c +#define RxMISS 0x0010 +#define TxCOL 0x0012 + +/* PP_BufEvent */ +#define SWint 0x0040 +#define RxDMAFrame 0x0080 +#define Rdy4Tx 0x0100 +#define TxUnderrun 0x0200 +#define RxMiss 0x0400 +#define Rx128 0x0800 +#define RxDest 0x8000 + + /* PP_TxCMD */ +#define After5 0 +#define After381 1 +#define After1021 2 +#define AfterAll 3 +#define TxStart(x) ((x) << 6) + +#define Force 0x0100 +#define Onecoll 0x0200 +#define InhibitCRC 0x1000 +#define TxPadDis 0x2000 + + /* PP_BusST */ +#define TxBidErr 0x0080 +#define Rdy4TxNOW 0x0100 + +extern cpu_mips_t *current_cpu; +static void dev_cs8900_gen_interrupt (struct cs8900_data *d) +{ + vm_instance_t *vm; + vm = d->vm; + + /*must check RQ bit in 0x116 */ + m_uint8_t *ram_base; + ram_base = (m_uint8_t *) (&(d->internal_ram[0])); + if ((*(m_uint16_t *) (ram_base + PP_BusCTL)) & (0x8000)) { + /*generate IRQ */ + vm->set_irq (vm, d->irq_no); + } +} + +static void dev_cs8900_init_defaultvalue (struct cs8900_data *d) +{ + m_uint8_t *ram_base; + + ram_base = (m_uint8_t *) (&(d->internal_ram[0])); + + *(m_uint32_t *) (ram_base + PP_ProductID) = CS8900A_PRODUCT_ID; + *(m_uint16_t *) (ram_base + PP_ISAIOB) = 0x300; + *(m_uint16_t *) (ram_base + PP_IntNum) = 0x4; + *(m_uint16_t *) (ram_base + PP_IntNum) = 0x4; + + *(m_uint16_t *) (ram_base + PP_RxCFG) = 0x3; + *(m_uint16_t *) (ram_base + PP_RxEvent) = 0x4; + + *(m_uint16_t *) (ram_base + PP_RxCTL) = 0x5; + *(m_uint16_t *) (ram_base + PP_TxCFG) = 0x7; + *(m_uint16_t *) (ram_base + PP_TxEvent) = 0x8; + *(m_uint16_t *) (ram_base + 0x108) = 0x9; + + *(m_uint16_t *) (ram_base + PP_BufCFG) = 0xb; + *(m_uint16_t *) (ram_base + PP_BufEvent) = 0xc; + + *(m_uint16_t *) (ram_base + PP_RxMISS) = 0x10; + + *(m_uint16_t *) (ram_base + PP_TxCOL) = 0x12; + *(m_uint16_t *) (ram_base + PP_LineCTL) = 0x13; + *(m_uint16_t *) (ram_base + PP_LineST) = 0x14; + *(m_uint16_t *) (ram_base + PP_SelfCTL) = 0x15; + + *(m_uint16_t *) (ram_base + PP_SelfST) = 0x16; + *(m_uint16_t *) (ram_base + PP_BusCTL) = 0x17; + + *(m_uint16_t *) (ram_base + PP_BusST) = 0x18; + *(m_uint16_t *) (ram_base + PP_TestCTL) = 0x19; + + *(m_uint16_t *) (ram_base + PP_TDR) = 0x1c; + + *(m_uint16_t *) (ram_base + PP_TxCMD) = 0x9; + + *(ram_base + PP_IA) = cs8900a_default_mac[0]; + *(ram_base + PP_IA + 1) = cs8900a_default_mac[1]; + *(ram_base + PP_IA + 2) = cs8900a_default_mac[2]; + *(ram_base + PP_IA + 3) = cs8900a_default_mac[3]; + *(ram_base + PP_IA + 4) = cs8900a_default_mac[4]; + *(ram_base + PP_IA + 5) = cs8900a_default_mac[5]; + +} + +static void dev_cs8900_reset (cpu_mips_t * cpu, struct vdevice *dev) +{ + struct cs8900_data *d = dev->priv_data; + memset (d->internal_ram, 0, sizeof (d->internal_ram)); + dev_cs8900_init_defaultvalue (d); +} + +/* Check if a packet must be delivered to the emulated chip based on length*/ +static inline int cs8900_handle_len (struct cs8900_data *d, m_uint8_t * pkt, + ssize_t pkt_len) +{ + /*we do not check CRC !!!! */ + if (pkt_len < CS8900_MIN_PKT_SIZE) + return FALSE; + + ASSERT ((pkt_len >= CS8900_RUN_PKT_SIZE) + && (pkt_len <= CS8900_MAX_PKT_SIZE), "not valid pktlen 0x%x\n", + (unsigned) pkt_len); + /*64internal_ram[0])); + + if ((*(m_uint16_t *) (ram_base + PP_RxCTL)) & PromiscuousA) { + goto rx_dest_int; + } + if (eth_addr_is_bcast (&hdr->daddr)) { + if ((*(m_uint16_t *) (ram_base + PP_RxCTL)) & BroadcastA) { + *(m_uint16_t *) (ram_base + PP_RxEvent) |= BroadcastA; + *(m_uint16_t *) (ram_base + PP_RxStatus) |= BroadcastA; + goto rx_dest_int; + } else + return FALSE; + } + if (eth_addr_is_mcast (&hdr->daddr)) { + if ((*(m_uint16_t *) (ram_base + PP_RxCTL)) & MulticastA) { + *(m_uint16_t *) (ram_base + PP_RxEvent) |= MulticastA; + *(m_uint16_t *) (ram_base + PP_RxStatus) |= MulticastA; + goto rx_dest_int; + } else + return FALSE; + } + + if ((*(m_uint16_t *) (ram_base + PP_RxCTL)) & IndividualA) { + /* Accept frames directly for us, discard others */ + if (!memcmp ((ram_base + PP_IA), &hdr->daddr, N_ETH_ALEN)) { + *(m_uint16_t *) (ram_base + PP_RxEvent) |= IndividualA; + *(m_uint16_t *) (ram_base + PP_RxStatus) |= IndividualA; + goto rx_dest_int; + } else + return FALSE; + + } + + rx_dest_int: + return (TRUE); +} + +static int dev_cs8900_receive_pkt (struct cs8900_data *d, u_char * pkt, + ssize_t pkt_len) +{ + m_uint8_t *ram_base; + ram_base = (m_uint8_t *) (&(d->internal_ram[0])); + + /* Truncate the packet if it is too big */ + pkt_len = m_min (pkt_len, CS8900_MAX_PKT_SIZE); + /*set RX len */ + *(m_uint16_t *) (ram_base + PP_RxLength) = pkt_len; + /*Rx status has been set */ + /*just copy frame to internal ram */ + memcpy (ram_base + PP_RxFrame, pkt, pkt_len); + /*generate interrupt */ + + *(m_uint16_t *) (ram_base + PP_RxEvent) |= RxOKA; + *(m_uint16_t *) (ram_base + PP_RxStatus) |= RxOKA; + if ((*(m_uint16_t *) (ram_base + PP_RxCFG)) & RxOKiE) { + //*(m_uint16_t*)(ram_base+PP_ISQ) &= ~0x3f; + *(m_uint16_t *) (ram_base + PP_ISQ) |= RxEvent; + dev_cs8900_gen_interrupt (d); + } + + return TRUE; + +} + +static int dev_cs8900_rx (netio_desc_t * nio, u_char * pkt, ssize_t pkt_len, + struct cs8900_data *d) +{ + m_uint8_t *ram_base; + m_uint16_t real_len; + int i; + m_uint32_t ifcs; + + ram_base = (m_uint8_t *) (&(d->internal_ram[0])); + + if (!((*(m_uint16_t *) (ram_base + PP_LineCTL)) & SerRxON)) + return FALSE; + real_len = pkt_len; + + /*FIXME: yajin + * jzdriver discard <64 bytes packet. But arp packet has 40 bytes. Pad it to 64 bytes to meet jz driver's requirement + */ + if (unlikely (pkt_len < 64)) { + /*pad to 60 bytes */ + for (i = pkt_len; i < 60; i++) { + *(pkt + i) = 0x0; + } + /*add crc */ + ifcs = crc32_compute (0xFFFFFFFF, pkt, 60); + *(pkt + 60) = ifcs & 0xff; + *(pkt + 61) = (ifcs >> 8) & 0xff; + *(pkt + 62) = (ifcs >> 16) & 0xff; + *(pkt + 63) = ifcs >> 24; + real_len = 64; + } + + /*check MAC address */ + if (!(cs8900_handle_mac_addr (d, pkt))) + return FALSE; + + /*check frame len */ + if (!(cs8900_handle_len (d, pkt, real_len))) + return FALSE; + + return (dev_cs8900_receive_pkt (d, pkt, real_len)); + +} + +static int dev_cs8900_tx (struct cs8900_data *d) +{ + + m_uint8_t *ram_base; + ram_base = (m_uint8_t *) (&(d->internal_ram[0])); + m_uint16_t send_len; + int i; + m_uint32_t ifcs; + + send_len = *(m_uint16_t *) (ram_base + PP_TxLength); + /*check if tx is enabled */ + if ((*(m_uint16_t *) (ram_base + PP_LineCTL)) & SerTxON) { + /*pad if len<60 */ + if (send_len <= (CS8900_RUN_PKT_SIZE - 4)) { + if (!((*(m_uint16_t *) (ram_base + PP_TxCMD)) & TxPadDis)) { + /*pad to 60 bytes */ + for (i = send_len; i < 60; i++) { + *(ram_base + PP_TxFrame + i) = 0x0; + } + send_len = 60; + if (!((*(m_uint16_t *) (ram_base + PP_TxCMD)) & InhibitCRC)) { + /*append crc */ + ifcs = + crc32_compute (0xFFFFFFFF, ram_base + PP_TxFrame, + send_len); + *(ram_base + PP_TxFrame + send_len) = ifcs & 0xff; + *(ram_base + PP_TxFrame + send_len + 1) = + (ifcs >> 8) & 0xff; + *(ram_base + PP_TxFrame + send_len + 2) = + (ifcs >> 16) & 0xff; + *(ram_base + PP_TxFrame + send_len + 3) = ifcs >> 24; + send_len += 4; + + } + } + } + *(m_uint16_t *) (ram_base + PP_TxLength) = send_len; + netio_send (d->nio, ram_base + PP_TxFrame, send_len); + *(m_uint16_t *) (ram_base + PP_TxEvent) = TxOK | 0x8; /*is = not |. all other bits must be cleared */ + if ((*(m_uint16_t *) (ram_base + PP_TxCFG)) & TxOKiE) { + /*if TXOKIE, generate an interrupt */ + /*set ISQ (regno=TX Event) */ + //*(m_uint16_t*)(ram_base+PP_ISQ) &= ~0x3f; + *(m_uint16_t *) (ram_base + PP_ISQ) |= TxEvent; + dev_cs8900_gen_interrupt (d); + } + + } + + return TRUE; +} + +/* +how to determinte the timeout value??? +*/ +void dev_cs8900_active_timer (struct cs8900_data *d) +{ + vp_mod_timer (d->cs8900_timer, + vp_get_clock (rt_clock) + cs8900a_rx_timeout); +} + +void dev_cs8900_unactive_timer (struct cs8900_data *d) +{ + vp_del_timer (d->cs8900_timer); +} + +void dev_cs8900_cb (void *opaque) +{ + struct cs8900_data *d = opaque; + + int fd; + ssize_t pkt_len; + + static m_uint8_t status = 0; + + ASSERT (d->nio != NULL, "set nio first\n"); + + if ((fd = netio_get_fd (d->nio)) == -1) { + ASSERT (0, "can not get nio fd. init cs8900 nio first.\n"); + } + + pkt_len = netio_recv (d->nio, d->nio->rx_pkt, sizeof (d->nio->rx_pkt)); + + if (pkt_len > 0) { + /*rx packet */ + dev_cs8900_rx (d->nio, d->nio->rx_pkt, pkt_len, d); + + /*Why we need to adjust CS8900_MAX_RX_TIMEOUT? yajin + * If CS8900_MAX_RX_TIMEOUT is small, that means rx packets quickly. Tx can not get enough time to tell cpu + * that tx ok. + * If CS8900_MAX_RX_TIMEOUT is big, that means rx packets slow. This will decrease network throughtput and + * some applications will complain about rx timeout. + * So I adjut the CS8900_MAX_RX_TIMEOUT dynamicly when receiving a packet . + * + * Please use TCP protocol instead of UDP when mounting directory using nfs. + * + */ + if (cs8900a_rx_timeout >= CS8900_MAX_RX_TIMEOUT) + status = 1; + else if (cs8900a_rx_timeout <= CS8900_MIN_RX_TIMEOUT) + status = 2; + + if (status == 0) + cs8900a_rx_timeout -= CS8900_RX_TIMEOUT_STEP; + if (status == 1) + cs8900a_rx_timeout -= CS8900_RX_TIMEOUT_STEP; + else if (status == 2) + cs8900a_rx_timeout += CS8900_RX_TIMEOUT_STEP; + + } + + cs8900a_rx_timeout = CS8900_DEFAULT_RX_TIMEOUT; + dev_cs8900_active_timer (d); + +} + +static void *dev_cs8900_access (cpu_mips_t * cpu, struct vdevice *dev, + m_uint32_t offset, u_int op_size, u_int op_type, + m_uint32_t * data, m_uint8_t * has_set_value) +{ + struct cs8900_data *d = dev->priv_data; + void *ret; + m_uint8_t *ram_base; + m_uint16_t io_address; + m_uint16_t isq; + + ram_base = (m_uint8_t *) (&(d->internal_ram[0])); + + if (offset >= d->cs8900_size) { + *data = 0; + return NULL; + } +#if VALIDE_CS8900_OPERATION + if (op_type == MTS_WRITE) { + ASSERT (offset != PP_IO_ISQ, + "Write to read only register in CS8900. offset %x\n", offset); + } else if (op_type == MTS_READ) { + ASSERT (offset != PP_TX_CMD, + "Read write only register in CS8900. offset %x\n", offset); + ASSERT (offset != PP_TX_LEN, + "Read write only register in CS8900. offset %x\n", offset); + } +#endif + + switch (offset) { + case PP_RT_DATA0: + case PP_RT_DATA0 + 1: + case PP_RT_DATA1: + case PP_RT_DATA1 + 1: + if (op_type == MTS_READ) { + ASSERT (d->rx_read_index < + (*(m_uint16_t *) (ram_base + PP_RxLength)), + "read out of data rx_read_index %x data len %x \n", + d->rx_read_index, (*(m_uint16_t *) (ram_base + PP_RxLength))); + ret = (void *) (ram_base + PP_RxFrame + d->rx_read_index); + d->rx_read_index += op_size; + /****if read all data,set d->rx_read_index=0*/ + if (d->rx_read_index >= *(m_uint16_t *) (ram_base + PP_RxLength)) + d->rx_read_index = 0; + return ret; + } else if (op_type == MTS_WRITE) { + ret = (void *) (ram_base + PP_TxFrame + d->tx_send_index); + if (op_size == MTS_BYTE) + *(m_uint8_t *) ret = *data; + if (op_size == MTS_HALF_WORD) + *(m_uint16_t *) ret = *data; + else + *(m_uint32_t *) ret = *data; + *has_set_value = TRUE; + d->tx_send_index += op_size; + /*if write all data into tx buffer, set d->tx_send_index=0 */ + if (d->tx_send_index >= *(m_uint16_t *) (ram_base + PP_TxLength)) { + d->tx_send_index = 0; + /*start tx a frame */ + dev_cs8900_tx (d); + } + return NULL; + } + break; + case PP_TX_CMD: + + ret = (void *) (ram_base + PP_TxCMD); + return ret; + case PP_TX_LEN: + ret = (void *) (ram_base + PP_TxLength); + return ret; + case PP_IO_ISQ: + ASSERT (0, "not support PP_IO_ISQ \n"); + case PP_ADDRESS: + return (void *) (ram_base + PP_ADDRESS); + case PP_DATA0: + case PP_DATA1: + if (offset == PP_DATA0) + ASSERT (op_size == MTS_HALF_WORD, + "op_size must be 2. op_size %x\n", op_size); + else if (offset == PP_DATA1) + ASSERT (0, "cs8900 only support 16 bit IO operation"); + io_address = *(m_uint16_t *) (ram_base + PP_ADDRESS); + switch (io_address) { + case PP_ProductID: + ASSERT (op_type == MTS_READ, "write to read only register %x\n", + *(m_uint16_t *) (ram_base + PP_ADDRESS)); + *data = CS8900A_PRODUCT_ID; + *has_set_value = TRUE; + return NULL; + case PP_ProductID + 2: /*16 bit */ + *data = 0; + *has_set_value = TRUE; + return NULL; + case PP_ISAIOB: + case PP_IntNum: + return (void *) (ram_base + io_address); + case PP_ISASOF: + case PP_DmaFrameCnt: + case PP_DmaByteCnt: + case PP_MemBase: + case PP_EEPROMCommand: + case PP_EEPROMData: + ASSERT (0, "Not support yet offset %x \n", io_address); + break; + case PP_RxCFG: + if (op_type == MTS_WRITE) { + if (*data & Skip_1) { + memset (ram_base + PP_RxFrame, 0x0, + PP_TxFrame - 1 - PP_RxFrame); + } + *(m_uint16_t *) (ram_base + PP_RxCFG) = *data | 0x3; + *has_set_value = TRUE; + return NULL; + } else /*read */ + return (void *) (ram_base + io_address); + case PP_RxCTL: + if (op_type == MTS_WRITE) { + *(m_uint16_t *) (ram_base + PP_RxCTL) = *data | 0x5; + *has_set_value = TRUE; + if (*data & IAHashA) + ASSERT (0, "Hash dest address is not support yet \n"); + return NULL; + } else + return (void *) (ram_base + io_address); + + case PP_TxCFG: + if (op_type == MTS_WRITE) { + *(m_uint16_t *) (ram_base + PP_TxCFG) = *data | 0x7; + *has_set_value = TRUE; + return NULL; + } else + return (void *) (ram_base + io_address); + case 0x108: + /*read 0x108 actually read 0x144 TXcmd */ + ASSERT (op_type == MTS_READ, + "CS8900 write to read only register. IO address 0x108 \n"); + return (void *) (ram_base + 0x144); + case PP_BufCFG: + if (op_type == MTS_WRITE) { + if (*data & SWint_X) { + *(m_uint16_t *) (ram_base + PP_BufEvent) |= SWint; + //*(m_uint16_t*)(ram_base+PP_ISQ) &= ~0x3f; + *(m_uint16_t *) (ram_base + PP_ISQ) |= BufEvent; + dev_cs8900_gen_interrupt (d); + } + if (*data & Rdy4TxiE) { + /*if host set rdy4tx, we are always ready for tx */ + *(m_uint16_t *) (ram_base + PP_BufEvent) |= Rdy4Tx; + //*(m_uint16_t*)(ram_base+PP_ISQ) &= ~0x3f; + *(m_uint16_t *) (ram_base + PP_ISQ) |= BufEvent; + dev_cs8900_gen_interrupt (d); + } + *(m_uint16_t *) (ram_base + PP_BufCFG) = *data | 0xb; + *has_set_value = TRUE; + return NULL; + } else + return (void *) (ram_base + io_address); + + case PP_LineCTL: + if (op_type == MTS_WRITE) { + *(m_uint16_t *) (ram_base + PP_LineCTL) = *data | 0x13; + if ((*data & SerRxON) || (*data & SerTxON)) + dev_cs8900_active_timer (d); + *has_set_value = TRUE; + return NULL; + } else + return (void *) (ram_base + io_address); + case PP_SelfCTL: + if (op_type == MTS_WRITE) { + if (*data & RESET) { + dev_cs8900_reset (cpu, dev); + } + *(m_uint16_t *) (ram_base + PP_SelfCTL) = *data | 0x15; + *has_set_value = TRUE; + return NULL; + } else + return (void *) (ram_base + io_address); + case PP_BusCTL: + if (op_type == MTS_WRITE) { + *(m_uint16_t *) (ram_base + PP_BusCTL) = *data | 0x17; + *has_set_value = TRUE; + return NULL; + } else + return (void *) (ram_base + io_address); + + case PP_TestCTL: + if (op_type == MTS_WRITE) { + *(m_uint16_t *) (ram_base + PP_TestCTL) = *data | 0x19; + *has_set_value = TRUE; + return NULL; + } else + return (void *) (ram_base + io_address); + + case PP_ISQ: + isq = *(m_uint16_t *) (ram_base + PP_ISQ); + if (op_type == MTS_WRITE) { + *(m_uint16_t *) (ram_base + PP_ISQ) = 0; + *has_set_value = TRUE; + return NULL; + } + /*Readonly? But sometimes, kernel will write to this register. */ + //ASSERT(op_type == MTS_READ, "wirte to read only register io_address %x.", io_address); + /*SHOULD be read */ + if (isq & TxEvent) { + *(m_uint16_t *) (ram_base + PP_ISQ) &= ~TxEvent; + *(m_uint16_t *) data = + *(m_uint16_t *) (ram_base + PP_TxEvent); + *(m_uint16_t *) (ram_base + PP_TxEvent) = 0X8; + //return (void*)(ram_base+PP_TxEvent); + } else if (isq & RxEvent) { + *(m_uint16_t *) (ram_base + PP_ISQ) &= ~RxEvent; + *(m_uint16_t *) data = + *(m_uint16_t *) (ram_base + PP_RxEvent); + *(m_uint16_t *) (ram_base + PP_RxEvent) = 0X4; + + //return (void*)(ram_base+PP_RxEvent); + } else if (isq & BufEvent) { + *(m_uint16_t *) (ram_base + PP_ISQ) &= ~BufEvent; + *(m_uint16_t *) data = + *(m_uint16_t *) (ram_base + PP_BufEvent); + *(m_uint16_t *) (ram_base + PP_BufEvent) = 0Xc; + + //return (void*)(ram_base+PP_BufEvent); + } + + else if (isq & RxMISS) { + *(m_uint16_t *) (ram_base + PP_ISQ) &= ~RxMISS; + *(m_uint16_t *) data = *(m_uint16_t *) (ram_base + PP_RxMISS); + *(m_uint16_t *) (ram_base + PP_RxMISS) = 0x10; + //return (void*)(ram_base+PP_RxMISS); + } else if (isq & TxCOL) { + *(m_uint16_t *) (ram_base + PP_ISQ) &= ~TxCOL; + *(m_uint16_t *) data = *(m_uint16_t *) (ram_base + PP_TxCOL); + *(m_uint16_t *) (ram_base + PP_TxCOL) = 0x12; + //return (void*)(ram_base+PP_TxCOL); + } else { + return (void *) (ram_base + PP_ISQ); + } + *has_set_value = TRUE; + return NULL; + break; + case PP_RxEvent: + /*read rx event will clear it */ + ASSERT (op_type == MTS_READ, + "CS8900 write to read only register. IO address %x \n", + io_address); + *(m_uint16_t *) data = *(m_uint16_t *) (ram_base + PP_RxEvent); + *has_set_value = TRUE; + *(m_uint16_t *) (ram_base + PP_RxEvent) = 0X4; + return NULL; + case PP_TxEvent: + /*read tx event will clear it */ + ASSERT (op_type == MTS_READ, + "CS8900 write to read only register. IO address %x \n", + io_address); + *(m_uint16_t *) data = *(m_uint16_t *) (ram_base + PP_TxEvent); + *has_set_value = TRUE; + *(m_uint16_t *) (ram_base + PP_TxEvent) = 0X8; + return NULL; + case PP_BufEvent: + /*read BufEvent event will clear it */ + ASSERT (op_type == MTS_READ, + "CS8900 write to read only register. IO address %x \n", + io_address); + *(m_uint16_t *) data = *(m_uint16_t *) (ram_base + PP_BufEvent); + *has_set_value = TRUE; + *(m_uint16_t *) (ram_base + PP_BufEvent) = 0Xc; + return NULL; + + case PP_RxMISS: + case PP_TxCOL: + case PP_LineST: + case PP_SelfST: + case PP_TDR: + ASSERT (op_type == MTS_READ, + "CS8900 write to read only register. IO address %x \n", + io_address); + return (void *) (ram_base + io_address); + case PP_BusST: + *(m_uint16_t *) (ram_base + PP_BusST) |= Rdy4TxNOW; + //else + //{ + // *(m_uint16_t*)(ram_base+PP_BusST) &= ~Rdy4TxNOW; + //} + return (void *) (ram_base + io_address); + case PP_TxCMD: + ASSERT (op_type == MTS_WRITE, + "CS8900 read write only register. IO address %x \n", + PP_TxCMD); + *(m_uint16_t *) (ram_base + PP_TxCMD) = *data | 0x9; + *has_set_value = TRUE; + return NULL; + + case PP_TxLength: + ASSERT (op_type == MTS_WRITE, + "CS8900 read write only register. IO address %x \n", + PP_TxLength); + *(m_uint16_t *) (ram_base + PP_TxLength) = *data; + *has_set_value = TRUE; + if (*(m_uint16_t *) (ram_base + PP_TxLength) > 1518) { + *(m_uint16_t *) (ram_base + PP_BusST) |= TxBidErr; + } else if (*(m_uint16_t *) (ram_base + PP_TxLength) > 1514) { + if (!((*(m_uint16_t *) (ram_base + PP_TxCMD)) & InhibitCRC)) + *(m_uint16_t *) (ram_base + PP_BusST) |= TxBidErr; + else + *(m_uint16_t *) (ram_base + PP_BusST) &= ~TxBidErr; + } else + *(m_uint16_t *) (ram_base + PP_BusST) &= ~TxBidErr; + return NULL; + case PP_LAF: + case PP_LAF + 1: + case PP_LAF + 2: + case PP_LAF + 3: + case PP_LAF + 4: + case PP_LAF + 5: + case PP_LAF + 6: + case PP_LAF + 7: + case PP_IA: + case PP_IA + 1: + case PP_IA + 2: + case PP_IA + 3: + case PP_IA + 4: + case PP_IA + 5: + case PP_RxStatus: + case PP_RxLength: + return (void *) (ram_base + io_address); + + default: + ASSERT (0, "error io address %x\n", io_address); + + } + + } + + return NULL; +} + +struct cs8900_data *dev_cs8900_init (vm_instance_t * vm, char *name, + m_pa_t phys_addr, m_uint32_t phys_len, int irq) +{ + struct cs8900_data *d; + + /* Allocate the private data structure for DEC21140 */ + if (!(d = malloc (sizeof (*d)))) { + fprintf (stderr, "%s (cs8900_data): out of memory\n", name); + return NULL; + } + memset (d, 0, sizeof (*d)); + + /* Create the device itself */ + if (!(d->dev = dev_create (name))) { + fprintf (stderr, "%s (DEC21140): unable to create device.\n", name); + goto err_dev; + } + d->irq_no = irq; + d->vm = vm; + d->dev->priv_data = d; + d->dev->phys_addr = phys_addr; + d->dev->phys_len = phys_len; + d->cs8900_size = phys_len; + + d->dev->handler = dev_cs8900_access; + d->dev->reset_handler = dev_cs8900_reset; + + d->dev->flags = VDEVICE_FLAG_NO_MTS_MMAP; + d->cs8900_timer = vp_new_timer (rt_clock, dev_cs8900_cb, d); + vm_bind_device (vm, d->dev); + return (d); + + err_dev: + free (d); + return NULL; +} + +int dev_cs8900_set_nio (struct cs8900_data *d, netio_desc_t * nio) +{ + + /* check that a NIO is not already bound */ + if (d->nio != NULL) + return (-1); + + d->nio = nio; + + return (0); +} diff --git a/tools/virtualmips/dev_cs8900.h b/tools/virtualmips/dev_cs8900.h new file mode 100644 index 0000000..48ac581 --- /dev/null +++ b/tools/virtualmips/dev_cs8900.h @@ -0,0 +1,54 @@ + /* + * Copyright (C) yajin 2008 + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + * + */ + +#ifndef __DEV_CS8900_H__ +#define __DEV_CS8900_H__ + +#include "utils.h" +#include "cpu.h" +#include "vm.h" +#include "mips_memory.h" +#include "device.h" +#include "net.h" +#include "net_io.h" +#include "vp_timer.h" + +#define CS8900_INTERNAL_RAM_SIZE 0x1000 /*4K */ +/* CS8900 Data */ +struct cs8900_data { + char *name; + m_uint32_t cs8900_size; + + /* Device information */ + struct vdevice *dev; + + /* Virtual machine */ + vm_instance_t *vm; + + /* NetIO descriptor */ + netio_desc_t *nio; /*one nio can have multi listener */ + + /*internal RAM 4K bytes */ + m_uint32_t internal_ram[CS8900_INTERNAL_RAM_SIZE / 4]; + m_uint32_t irq_no; + + m_uint16_t rx_read_index; + m_uint16_t tx_send_index; + + vp_timer_t *cs8900_timer; + + // m_uint8_t want_tx; +// m_uint8_t want_rx; + +}; + +int dev_cs8900_set_nio (struct cs8900_data *d, netio_desc_t * nio); +struct cs8900_data *dev_cs8900_init (vm_instance_t * vm, char *name, + m_pa_t phys_addr, m_uint32_t phys_len, int irq); + +#endif diff --git a/tools/virtualmips/dev_nand_flash_1g.c b/tools/virtualmips/dev_nand_flash_1g.c new file mode 100644 index 0000000..784367a --- /dev/null +++ b/tools/virtualmips/dev_nand_flash_1g.c @@ -0,0 +1,494 @@ + /* + * Copyright (C) yajin 2008 + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + * + */ + +/* +1G bytes nand flash emulation. Samsung K9F8G08 1GB +1G bytes nand flash are stored in file nandflash8g.0-nandflash8g.8191 (8192 blocks). +The flash file only be created when writing to block (copy on write). +Please use tool/mknandflash to create init nand file of u-boot image. +*/ + +/* + +supported operation: + READ + Read for copy back + Read ID + Reset + Page program + Copy-back + Block erase + Random data input + Random data output + +*/ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "device.h" +#include "mips_memory.h" +#include "dev_nand_flash_1g.h" + +m_uint8_t id_info[5] = { 0xec, 0xd3, 0x51, 0x95, 0x58 }; + +#define NAND_STATUS_READY 0x40 +#define NAND_STATUS_WP 0x80 + +/*status ready & not write protected*/ +/*I am always ready. haha. Better than real nand flash :)*/ +m_uint8_t nand_status = NAND_STATUS_READY | NAND_STATUS_WP; + +#ifdef CPU_LOG +#undef CPU_LOG +#endif + +//#define DEBUG_FLASH_ACCESS +#ifdef DEBUG_FLASH_ACCESS +#define CPU_LOG(arg1) cpu_log arg1 +#else +#define CPU_LOG(arg1) +#endif + +/*Create nand flash file. 1 block 1 file.*/ +static unsigned char *create_nand_flash_file (m_uint32_t block_no) +{ + char file_path[64]; + char page[NAND_FLASH_1G_PAGE_SIZE]; + int i, n; + int fd; + unsigned char *ret; + + /*create nand flash file when writing */ + snprintf (file_path, sizeof (file_path), "%s/%s.%d", + NAND_FLASH_1G_FILE_DIR, NAND_FLASH_1G_FILE_PREFIX, block_no); + fd = open (file_path, O_RDWR | O_CREAT, + S_IREAD | S_IWRITE | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); + assert (fd >= 0); + + for (i = 0; i < NAND_FLASH_1G_PAGES_PER_BLOCK; i++) { + memset (page, 0xff, NAND_FLASH_1G_PAGE_SIZE); + n = write (fd, page, NAND_FLASH_1G_PAGE_SIZE); + assert (n == NAND_FLASH_1G_PAGE_SIZE); + } + ret = memzone_map_file (fd, NAND_FLASH_1G_BLOCK_SIZE); + assert (ret != NULL); + return ret; +} + +/*get the page pointer given row addr and block start address*/ +unsigned char *get_nand_flash_page_ptr (m_uint32_t row_addr, + unsigned char *block_start) +{ + + m_uint32_t block_no = row_addr >> NAND_FLASH_1G_BLOCK_PAGE_OFFSET; + m_uint32_t page_no = row_addr & NAND_FLASH_1G_BLOCK_PAGE_MASK; + assert (block_no < NAND_FLASH_1G_TOTAL_BLOCKS); + assert (block_start != NULL); + return (block_start + page_no * NAND_FLASH_1G_PAGE_SIZE); + +} + +static void nand_flash_erase_block (unsigned char *block_start) +{ + memset (block_start, 0xff, NAND_FLASH_1G_BLOCK_SIZE); +} + +/*write data to nand file (1 page)*/ +static void write_nand_fiash_page_file (m_uint32_t row_addr, + unsigned char *block_start, unsigned char *write_data) +{ + unsigned char *page_ptr; + int i; + + page_ptr = get_nand_flash_page_ptr (row_addr, block_start); + /*we only copy different data into page */ + for (i = 0; i < NAND_FLASH_1G_PAGE_SIZE; i++) { + if (*(write_data + i) == 0XFF) + continue; + if ((*(page_ptr + i)) != (*(write_data + i))) { + *(page_ptr + i) = *(write_data + i); + } + } + +} + +char *state_string[8] = { "STATE_INIT", + "STATE_READ_START", + "STATE_RANDOM_READ_START", + "STATE_WRITE_START", + "STATE_RANDOM_WRITE_START", + "STATE_READ_PAGE_FOR_COPY_WRITE", + "STATE_COPY_START", + "STATE_ERASE_START", +}; + +void *dev_nand_flash_1g_access (cpu_mips_t * cpu, struct vdevice *dev, + m_uint32_t offset, u_int op_size, u_int op_type, + m_uint32_t * data, m_uint8_t * has_set_value) +{ + nand_flash_1g_data_t *d = dev->priv_data; + m_uint32_t block_no; + void *ret; + /*COMMAND PORT */ + if (offset == NAND_COMMPORT_OFFSET) { + /*clear addr offset */ + d->addr_offset = 0; + switch (d->state) { + case STATE_INIT: + if (((*data) & 0xff) == 0x00) + d->state = STATE_READ_START; + else if (((*data) & 0xff) == 0x80) { + memset (d->write_buffer, 0xff, NAND_FLASH_1G_PAGE_SIZE); + d->state = STATE_WRITE_START; + } else if (((*data) & 0xff) == 0x05) { + assert (d->has_issue_30h == 1); + d->state = STATE_RANDOM_READ_START; + d->has_issue_30h = 0; + } else if (((*data) & 0xff) == 0xFF) { + /*reset */ + d->state = STATE_INIT; + } else if (((*data) & 0xff) == 0x90) { + /*read ID */ + d->data_port_ipr = id_info; + d->state = STATE_INIT; + d->read_offset = 0; + } else if (((*data) & 0xff) == 0x60) { + /*ERASE */ + d->state = STATE_ERASE_START; + /*erase only need row address. adjust addr_offset */ + d->addr_offset = 2; + } else if (((*data) & 0xff) == 0x70) { + /*READ STATUS */ + d->state = STATE_INIT; + d->read_offset = 0; + d->data_port_ipr = &nand_status; + } else + ASSERT (0, "*data %x\n", *data); + break; + + case STATE_ERASE_START: + if (((*data) & 0xff) == 0xd0) { + //erase blcok + block_no = (d->row_addr) >> NAND_FLASH_1G_BLOCK_PAGE_OFFSET; + if (d->flash_map[block_no] == NULL) + d->flash_map[block_no] = + create_nand_flash_file (block_no); + nand_flash_erase_block (d->flash_map[block_no]); + d->state = STATE_INIT; + } else + assert (0); + break; + case STATE_READ_START: + if (((*data) & 0xff) == 0x30) { + d->has_issue_30h = 1; + d->state = STATE_INIT; + block_no = (d->row_addr) >> NAND_FLASH_1G_BLOCK_PAGE_OFFSET; + if (d->flash_map[block_no] == NULL) { + CPU_LOG ((cpu, "", + "block_no %x is null. redirect to fake page.", + block_no)); + d->data_port_ipr = + get_nand_flash_page_ptr (d->row_addr, d->fake_block); + } else + d->data_port_ipr = + get_nand_flash_page_ptr (d->row_addr, + d->flash_map[block_no]); + + d->read_offset = d->col_addr; + CPU_LOG ((cpu, "", "d->read_offset %x d->col_addr %x.", + d->read_offset, d->col_addr)); + } else if (((*data) & 0xff) == 0x35) { + d->state = STATE_READ_PAGE_FOR_COPY_WRITE; + block_no = (d->row_addr) >> NAND_FLASH_1G_BLOCK_PAGE_OFFSET; + memset (d->write_buffer, 0xff, NAND_FLASH_1G_PAGE_SIZE); + } else if (((*data) & 0xff) == 0xFF) { + /*reset */ + d->state = STATE_INIT; + + } else + assert (0); + break; + + case STATE_RANDOM_READ_START: + if (((*data) & 0xff) == 0xe0) { + d->state = STATE_INIT; + block_no = (d->row_addr) >> NAND_FLASH_1G_BLOCK_PAGE_OFFSET; + if (d->flash_map[block_no] == NULL) { + CPU_LOG ((cpu, "", + "block_no %x is null. redirect to fake page.", + block_no)); + d->data_port_ipr = + get_nand_flash_page_ptr (d->row_addr, d->fake_block); + } else + d->data_port_ipr = + get_nand_flash_page_ptr (d->row_addr, + d->flash_map[block_no]); + d->read_offset = d->col_addr; + } else if (((*data) & 0xff) == 0x05) { + d->state = STATE_RANDOM_READ_START; + } else + assert (0); + break; + + case STATE_WRITE_START: + if (((*data) & 0xff) == 0x10) { + d->state = STATE_INIT; + block_no = (d->row_addr) >> NAND_FLASH_1G_BLOCK_PAGE_OFFSET; + if (d->flash_map[block_no] == NULL) + d->flash_map[block_no] = + create_nand_flash_file (block_no); + + write_nand_fiash_page_file (d->row_addr, + d->flash_map[block_no], d->write_buffer); + d->write_offset = 0; + } else if (((*data) & 0xff) == 0x85) { + d->write_offset = 0; + d->state = STATE_RANDOM_WRITE_START; + } else + assert (0); + break; + + case STATE_RANDOM_WRITE_START: + if (((*data) & 0xff) == 0x10) { + d->state = STATE_INIT; + block_no = (d->row_addr) >> NAND_FLASH_1G_BLOCK_PAGE_OFFSET; + if (d->flash_map[block_no] == NULL) + d->flash_map[block_no] = + create_nand_flash_file (block_no); + write_nand_fiash_page_file (d->row_addr, + d->flash_map[block_no], d->write_buffer); + d->write_offset = 0; + } else if (((*data) & 0xff) == 0x85) { + d->write_offset = 0; + d->state = STATE_RANDOM_WRITE_START; + } else + assert (0); + break; + + case STATE_READ_PAGE_FOR_COPY_WRITE: + if (((*data) & 0xff) == 0x85) { + d->write_offset = 0; + + d->state = STATE_COPY_START; + } else + assert (0); + break; + + case STATE_COPY_START: + if (((*data) & 0xff) == 0x10) { + d->state = STATE_INIT; + block_no = (d->row_addr) >> NAND_FLASH_1G_BLOCK_PAGE_OFFSET; + if (d->flash_map[block_no] == NULL) + d->flash_map[block_no] = + create_nand_flash_file (block_no); + write_nand_fiash_page_file (d->row_addr, + d->flash_map[block_no], d->write_buffer); + d->write_offset = 0; + } else if (((*data) & 0xff) == 0x85) { + d->write_offset = 0; + d->state = STATE_RANDOM_WRITE_START; + } else + assert (0); + break; + + default: + assert (0); + } + + CPU_LOG ((cpu, "", " state %s\n", state_string[d->state])); + + } else if (offset == NAND_DATAPORT_OFFSET) { + *has_set_value = FALSE; + if (op_type == MTS_READ) { + /*data port */ + CPU_LOG ((cpu, "", + "pc %x data %x d->read_offset %x d->data_port_ipr %x \n", + cpu->pc, *(d->data_port_ipr + d->read_offset), + d->read_offset, d->data_port_ipr)); + ret = (void *) (d->data_port_ipr + d->read_offset); + d->read_offset++; + return ret; + + } else if (op_type == MTS_WRITE) { + ret = (void *) (d->write_buffer + d->col_addr + d->write_offset); + d->write_offset++; + + return ret; + } + assert (0); + + } else if (offset == NAND_ADDRPORT_OFFSET) { + CPU_LOG ((cpu, "", "ADDRESS pc %x d->addr_offset %x *data %x \n", + cpu->pc, d->addr_offset, *data)); + /*ADDRESS PORT */ + assert (op_type == MTS_WRITE); + *has_set_value = TRUE; + switch (d->addr_offset) { + case 0x0: + d->col_addr = (*data) & 0xff; + break; + case 0x01: + d->col_addr += ((*data) & 0xff) << 8; + break; + case 0x2: + d->row_addr = (*data) & 0xff; + break; + case 0x03: + d->row_addr += ((*data) & 0xff) << 8; + break; + case 0x04: + d->row_addr += ((*data) & 0xff) << 16; + break; + default: + assert (0); + } + CPU_LOG ((cpu, "", "col_addr %x row_addr %x\n", d->col_addr, + d->row_addr)); + d->addr_offset++; + } + + *has_set_value = TRUE; + return NULL; + +} + +static int load_nand_flash_file (nand_flash_1g_data_t * d) +{ + int i, j = 0; + struct dirent *ent = NULL; + DIR *p_dir; + char file_path[64]; + char *file_name; + char block_number[16]; + int fd; + //nand_flash_1g_data_t *d=*nand_flash; + + memset (d->flash_map, 0x0, + NAND_FLASH_1G_TOTAL_BLOCKS * sizeof (d->flash_map[0])); + p_dir = opendir (NAND_FLASH_1G_FILE_DIR); + if (NULL == p_dir) { + fprintf (stderr, + "NAND FLASH: Can not open nand flash file directory \"%s\".\n", + NAND_FLASH_1G_FILE_DIR); + goto err_flash_map_create; + } + while (NULL != (ent = readdir (p_dir))) { + //we only take care file + if (ent->d_type == DT_DIR) + continue; + snprintf (file_path, sizeof (file_path), "%s/%s", + NAND_FLASH_1G_FILE_DIR, ent->d_name); + if (get_file_size (file_path) != NAND_FLASH_1G_BLOCK_SIZE) + continue; + file_name = strdup (ent->d_name); + for (i = strlen (file_name) - 1; i >= 0; i--) { + if (file_name[i] == '.') + break; + } + if (i == -1) { + //not a valid flash file + continue; + } + file_name[i] = '\0'; + if (strcmp (file_name, NAND_FLASH_1G_FILE_PREFIX) != 0) { + continue; + } + free (file_name); + file_name = strdup (ent->d_name); + //get the block number + strncpy (block_number, file_name + i + 1, strlen (file_name) - i - 1); + block_number[strlen (file_name) - i - 1] = '\0'; + i = atoi (block_number); + fd = open (file_path, O_RDWR); + if (fd < 0) + goto err_open_flash_file; + d->flash_map[i] = memzone_map_file (fd, NAND_FLASH_1G_BLOCK_SIZE); + if (d->flash_map[i] == NULL) + goto err_map_flash_file; + close (fd); + free (file_name); + j++; + + } + closedir (p_dir); + printf ("\nloaded %d nand flash file from directory \"%s\". \n", j, + NAND_FLASH_1G_FILE_DIR); + return (0); + err_map_flash_file: + close (fd); + err_open_flash_file: + free (file_name); + err_flash_map_create: + return (-1); + +} + +void dev_nand_flash_1g_reset (cpu_mips_t * cpu, struct vdevice *dev) +{ + nand_flash_1g_data_t *d = dev->priv_data; + memset (d->fake_block, 0xff, NAND_FLASH_1G_BLOCK_SIZE); + d->state = STATE_INIT; + memset (d->write_buffer, 0xff, NAND_FLASH_1G_PAGE_SIZE); + +} + +int dev_nand_flash_1g_init (vm_instance_t * vm, char *name, m_pa_t phys_addr, + m_uint32_t phys_len, nand_flash_1g_data_t ** nand_flash) +{ + + nand_flash_1g_data_t *d; + + /* allocate the private data structure */ + if (!(d = malloc (sizeof (*d)))) { + fprintf (stderr, "NAND FLASH: unable to create device.\n"); + return (-1); + } + memset (d, 0, sizeof (*d)); + + /*load all flash data to d->flash_map */ + if (load_nand_flash_file (d) == -1) + return (-1); + /*set fake_page + * We only create nand flash file when writing to a blcok. + * When reading from a block which has not been written, give it the fake_page. + */ + memset (d->fake_block, 0xff, NAND_FLASH_1G_BLOCK_SIZE); + + d->state = STATE_INIT; + memset (d->write_buffer, 0xff, NAND_FLASH_1G_PAGE_SIZE); + + if (!(d->dev = dev_create (name))) + goto err_dev_create; + d->dev->priv_data = d; + d->dev->handler = dev_nand_flash_1g_access; + d->dev->reset_handler = dev_nand_flash_1g_reset; + /*NAND COMMPORT AND DATA PORT ADDRESS */ + d->dev->phys_addr = phys_addr; + d->dev->phys_len = phys_len; + d->dev->flags = VDEVICE_FLAG_NO_MTS_MMAP; + /* Map this device to the VM */ + vm_bind_device (vm, d->dev); + + *nand_flash = d; + + return (0); + err_dev_create: + free (d); + return (-1); +} diff --git a/tools/virtualmips/dev_nand_flash_1g.h b/tools/virtualmips/dev_nand_flash_1g.h new file mode 100644 index 0000000..dfc21c7 --- /dev/null +++ b/tools/virtualmips/dev_nand_flash_1g.h @@ -0,0 +1,78 @@ + /* + * Copyright (C) yajin 2008 + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + * + */ + +#ifndef __DEV_NAND_FLASH_1G_H__ +#define __DEV_NAND_FLASH_1G_H__ + +#include "utils.h" + +#define NAND_FLASH_1G_BLOCK_PAGE_OFFSET 0x6 /*64 page in a blcok */ +#define NAND_FLASH_1G_BLOCK_PAGE_MASK 0x3f +#define NAND_FLASH_1G_TOTAL_SIZE 0x42000000 /*1G data BYTES +32M bytes SPARE BYTES */ +#define NAND_FLASH_1G_TOTAL_PLANE 4 +#define NAND_FLASH_1G_TOTAL_PAGES 0x80000 +#define NAND_FLASH_1G_TOTAL_BLOCKS 0x2000 +#define NAND_FLASH_1G_PAGES_PER_BLOCK 0x40 + +#define NAND_FLASH_1G_PAGE_SIZE 0x840 /*2k bytes date size+64 bytes spare size */ +#define NAND_FLASH_1G_SPARE_SIZE 0x40 /*64 bytes */ +#define NAND_FLASH_1G_BLOCK_SIZE 0x21000 /*132k bytes */ +#define NAND_FLASH_1G_PAGE_DATA_SIZE 0x800 /*2k bytes */ +#define NAND_FLASH_1G_BLOCK_DATA_SIZE 0x20000 /*128k bytes */ + +#define NAND_FLASH_1G_BLOCK_OFFSET(x) (NAND_FLASH_1G_BLOCK_SIZE*x) +#define NAND_FLASH_1G_PAGE_OFFSET(x) (NAND_FLASH_1G_PAGE_SIZE*x) + +#define NAND_FLASH_1G_FILE_PREFIX "nandflash1GB" +#define NAND_FLASH_1G_FILE_DIR "nandflash1GB" + +/*NAND_FLASH_STATE*/ + +#define STATE_INIT 0x0 +#define STATE_READ_START 0x1 +#define STATE_RANDOM_READ_START 0x2 +#define STATE_WRITE_START 0x3 +#define STATE_RANDOM_WRITE_START 0x4 + +#define STATE_READ_PAGE_FOR_COPY_WRITE 0x5 +#define STATE_COPY_START 0x6 + +#define STATE_ERASE_START 0x7 + +#define NAND_DATAPORT_OFFSET 0x00000000 +#define NAND_ADDRPORT_OFFSET 0x00010000 +#define NAND_COMMPORT_OFFSET 0x00008000 + +/* nand flash private data */ +struct nand_flash_1g_data { + struct vdevice *dev; + int state; + unsigned char *flash_map[NAND_FLASH_1G_TOTAL_BLOCKS]; + + unsigned char fake_block[NAND_FLASH_1G_BLOCK_SIZE]; + + m_uint32_t row_addr; + m_uint32_t col_addr; + + unsigned char write_buffer[NAND_FLASH_1G_PAGE_SIZE]; //for copy back + m_uint32_t read_offset; + m_uint32_t write_offset; + m_uint32_t addr_offset; + m_uint8_t has_issue_30h; + /*for nand flash read */ + unsigned char *data_port_ipr; + +}; +typedef struct nand_flash_1g_data nand_flash_1g_data_t; + +unsigned char *get_nand_flash_page_ptr (m_uint32_t row_addr, + unsigned char *block_start); +int dev_nand_flash_1g_init (vm_instance_t * vm, char *name, m_pa_t phys_addr, + m_uint32_t phys_len, nand_flash_1g_data_t ** nand_flash); + +#endif diff --git a/tools/virtualmips/dev_nor_flash_4m.c b/tools/virtualmips/dev_nor_flash_4m.c new file mode 100644 index 0000000..03df5e5 --- /dev/null +++ b/tools/virtualmips/dev_nor_flash_4m.c @@ -0,0 +1,326 @@ + /* + * Copyright (C) yajin 2008 + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + */ + +/* +4M *byte* FLASH device simulation (device id=22F9h). +Most important part of flash simulation is CFI interface. +See flash datasheet for details. + */ +#define _GNU_SOURCE +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "device.h" +#include "mips_memory.h" + +#define ROM_INIT_STATE 0 + +/* flash private data */ +struct flash_data { + struct vdevice *dev; + m_uint8_t *flash_ptr; + m_uint32_t flash_size; + m_uint8_t *flash_file_name; + m_uint32_t state; + int flash_fd; +}; +typedef struct flash_data flash_data_t; + +#define BPTR(d,offset) (((char *)d->flash_ptr) + offset) + +m_uint16_t vendorID = 0x01; // target is little end 0x0001 +m_uint16_t deviceID = 0x22f9; // target is little end 0x22F9 +m_uint16_t earse_ready = 0x80; // target is little end 0X0080 +m_uint32_t last_offset = 0; + +m_uint32_t dump_data; +m_uint32_t cfi_data[] = + { 0x51, 0x52, 0x59, 0x2, 0x0, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x27, 0x36, + 0x0, 0x0, 0x4, + 0x0, 0xa, 0x0, 0x5, 0x0, 0x4, 0x0, 0x16, 0x2, 0x0, 0x0, 0x0, 0x2, 0x7, + 0x0, 0x20, + 0x0, 0x3e, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, + 0x50, 0x52, 0x49, 0x31, 0x31, 0x0, 0x2, 0x4, 0x1, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xc5, 0x2, //02 BOTTOM +}; + +static void secotor_info (m_uint32_t offset, m_uint32_t * sector_start, + m_uint32_t * sector_size) +{ + if (offset <= 0x00FFF) { + *sector_start = offset & 0xFFFFFE00; + *sector_size = 0x2000; + return; + } + *sector_start = offset & (0xffff0000); + *sector_size = 0x10000; +} + +void *dev_flash_access (cpu_mips_t * cpu, struct vdevice *dev, + m_uint32_t offset, u_int op_size, u_int op_type, m_uint32_t * data, + m_uint8_t * has_set_value) +{ + flash_data_t *d = dev->priv_data; + m_uint32_t r_offset, sector_size, sector_start; + m_uint32_t last_sector_start, last_sector_size; + + if (offset >= d->flash_size) { + *data = 0; + return NULL; + } + if (op_type == MTS_READ) { + switch (d->state) { + case 0: + return (BPTR (d, offset)); + case 99: /*cfi query */ + if ((offset >= 0x20) && (offset <= 0x9e)) { + *data = (cfi_data[(offset - 0x20) / 2]); //always littleend + *has_set_value = TRUE; + } else { + d->state = 0; + return (BPTR (d, offset)); + } + + break; + case 0x6: + d->state = 0; + if (offset == 0X0) + return &vendorID; + if (offset == 0X2) + return &deviceID; + break; + case 10: + //last cycle is chip erase or sector erase + secotor_info (offset, §or_start, §or_size); + secotor_info (last_offset, &last_sector_start, &last_sector_size); + d->state = 0; + if (last_sector_start == sector_start) + return &earse_ready; + else + return (BPTR (d, offset)); + break; + + default: + cpu_log (cpu, dev->name, "read: unhandled state %d\n", d->state); + } + return NULL; + } + if (op_type == MTS_WRITE) { + r_offset = offset; + if ((op_size == MTS_HALF_WORD) && (offset == 0X554)) + offset = 0X555; + + switch (d->state) { + case ROM_INIT_STATE: + switch (offset) { + case 0xAAA: + if (((*data) & 0xff) == 0xAA) + d->state = 1; + break; + case 0XAA: + if (((*data) & 0xff) == 0x98) { + d->state = 99; //CFI QUERY + } + break; + default: + switch ((*data) & 0xff) { + case 0xB0: + /* Erase/Program Suspend */ + d->state = 0; + break; + case 0x30: + /* Erase/Program Resume */ + d->state = 0; + break; + case 0xF0: + case 0xFF: + /*Read/Reset */ + d->state = 0; + break; + default: + return ((void *) (d->flash_ptr + r_offset)); + } + + } + break; + + case 99: + if (((*data & 0xff) == 0xff) || ((*data & 0xff) == 0xf0)) + d->state = 0; + else + return ((void *) (d->flash_ptr + r_offset)); + break; + case 1: + if ((offset != 0x555) && ((*data & 0xff) != 0x55)) + d->state = 0; + else + d->state = 2; + break; + + case 2: + d->state = 0; + + if (offset == 0xAAA) { + switch ((*data) & 0xff) { + case 0x80: + d->state = 3; + break; + case 0xA0: + /* Byte/Word program */ + d->state = 4; + break; + case 0x90: + /* Product ID Entry / Status of Block B protection */ + d->state = 6; + break; + } + } + break; + + case 3: + if ((offset != 0xAAA) && (*data != 0xAA)) + d->state = 0; + else + d->state = 8; + break; + + case 8: + if ((offset != 0x555) && (*data != 0x55)) + d->state = 0; + else + d->state = 9; + break; + + case 9: + d->state = 10; + last_offset = r_offset; + + switch ((*data) & 0xff) { + case 0x10: + /* Chip Erase */ + memset (BPTR (d, 0), 0, d->dev->phys_len); + break; + + case 0x30: + /* Sector Erase */ + secotor_info (r_offset, §or_start, §or_size); + break; + + } + break; + + /* Byte/Word Program */ + case 4: + d->state = 0; + return ((void *) (d->flash_ptr + r_offset)); + break; + + default: + cpu_log (cpu, dev->name, "write: unhandled state %d\n", d->state); + } + return &dump_data; + } + assert (0); +} + +static int dev_flash_load (char *flash_file_name, m_uint32_t flash_len, + unsigned char **flash_data_hp, u_int create) +{ + int fd; + struct stat sb; + unsigned char *temp; + + fd = open (flash_file_name, O_RDWR); + if ((fd < 0) && (create == 1)) { + fprintf (stderr, "Can not open flash file. name %s\n", + flash_file_name); + fprintf (stderr, "creating flash file. name %s\n", flash_file_name); + fd = open (flash_file_name, O_RDWR | O_CREAT, + S_IREAD | S_IWRITE | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); + if (fd < 0) { + fprintf (stderr, "Can not create flash file. name %s\n", + flash_file_name); + return (-1); + } + temp = malloc (flash_len); + assert (temp != NULL); + memset (temp, 0xff, flash_len); + lseek (fd, 0, SEEK_SET); + write (fd, (void *) temp, flash_len); + free (temp); + fprintf (stderr, "create flash file success. name %s\n", + flash_file_name); + lseek (fd, 0, SEEK_SET); + } else if (fd < 0) { + fprintf (stderr, "%s does not exist and not allowed to create.\n", + flash_file_name); + return (-1); + } + assert (fd >= 0); + fstat (fd, &sb); + if (flash_len < sb.st_size) { + fprintf (stderr, + "Too large flash file. flash len:%d M, flash file name %s," + "flash file legth: %d bytes.\n", flash_len, flash_file_name, + (int) sb.st_size); + return (-1); + } + *flash_data_hp = + mmap (NULL, sb.st_size, PROT_WRITE | PROT_READ, MAP_SHARED, fd, 0); + if (*flash_data_hp == MAP_FAILED) { + fprintf (stderr, "errno %d\n", errno); + fprintf (stderr, "failed\n"); + return (-1); + } + return 0; +} + +/* Initialize a NOR Flash zone */ +int dev_nor_flash_4m_init (vm_instance_t * vm, char *name) +{ + flash_data_t *d; + unsigned char *flash_data_hp; + + /*load rom data */ + if (dev_flash_load (vm->flash_filename, vm->flash_size * 1048576, + &flash_data_hp, 1) < 0) + return (-1); + + /* allocate the private data structure */ + if (!(d = malloc (sizeof (*d)))) { + fprintf (stderr, "FLASH: unable to create device.\n"); + return (-1); + } + + memset (d, 0, sizeof (*d)); + d->flash_ptr = flash_data_hp; + d->flash_size = vm->flash_size * 1048576; + d->state = ROM_INIT_STATE; + + if (!(d->dev = dev_create (name))) + goto err_dev_create; + d->dev->priv_data = d; + d->dev->phys_addr = vm->flash_address; + d->dev->phys_len = vm->flash_size * 1048576; + d->dev->handler = dev_flash_access; + d->dev->flags = VDEVICE_FLAG_NO_MTS_MMAP; + /* Map this device to the VM */ + vm_bind_device (vm, d->dev); + return (0); + err_dev_create: + free (d); + return (-1); +} diff --git a/tools/virtualmips/dev_ram.c b/tools/virtualmips/dev_ram.c new file mode 100644 index 0000000..c2aa6a4 --- /dev/null +++ b/tools/virtualmips/dev_ram.c @@ -0,0 +1,59 @@ + /* + * Copyright (C) yajin 2008 + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + * + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include + +#include "vm.h" +#include "mips_memory.h" +#include "device.h" + +/* RAM private data */ +struct ram_data { + struct vdevice *dev; +}; + +void dev_ram_reset (cpu_mips_t * cpu, struct vdevice *dev) +{ + assert (dev->host_addr != 0); + /*reset ram */ + memset ((unsigned char *) dev->host_addr, 0x0, dev->phys_len); + +} + +/* Initialize a RAM zone */ +int dev_ram_init (vm_instance_t * vm, char *name, m_pa_t paddr, + m_uint32_t len) +{ + struct ram_data *d; + + /* allocate the private data structure */ + if (!(d = malloc (sizeof (*d)))) { + fprintf (stderr, "RAM: unable to create device.\n"); + return (-1); + } + + memset (d, 0, sizeof (*d)); + + if (!(d->dev = dev_create_ram (vm, name, paddr, len))) { + fprintf (stderr, "RAM: unable to create device.\n"); + goto err_dev_create; + } + d->dev->priv_data = d; + d->dev->reset_handler = dev_ram_reset; + return (0); + +err_dev_create: + free (d); + return (-1); +} diff --git a/tools/virtualmips/dev_sdcard.c b/tools/virtualmips/dev_sdcard.c new file mode 100644 index 0000000..38fd9b0 --- /dev/null +++ b/tools/virtualmips/dev_sdcard.c @@ -0,0 +1,352 @@ +/* + * SD/MMC card emulation. + * + * Copyright (C) 2011 Serge Vakulenko + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + * + */ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include + +#include "vm.h" +#include "mips_memory.h" +#include "device.h" +#include "dev_sdcard.h" + +//#define TRACE printf +#ifndef TRACE +#define TRACE(...) /*empty*/ +#endif + +/* + * Definitions for MMC/SDC commands. + */ +#define CMD_GO_IDLE (0x40+0) /* CMD0 */ +#define CMD_SEND_OP_SDC (0x40+41) /* ACMD41 (SDC) */ +#define CMD_SET_BLEN (0x40+16) +#define CMD_SEND_CSD (0x40+9) +#define CMD_STOP (0x40+12) +#define CMD_READ_SINGLE (0x40+17) +#define CMD_READ_MULTIPLE (0x40+18) +#define CMD_SET_WBECNT (0x40+23) /* ACMD23 */ +#define CMD_WRITE_SINGLE (0x40+24) +#define CMD_WRITE_MULTIPLE (0x40+25) +#define CMD_APP (0x40+55) /* CMD55 */ + +#define DATA_START_BLOCK 0xFE /* start data for single block */ +#define STOP_TRAN_TOKEN 0xFD /* stop token for write multiple */ +#define WRITE_MULTIPLE_TOKEN 0xFC /* start data for write multiple */ + +static void sdcard_read_data (int fd, unsigned offset, + unsigned char *buf, unsigned blen) +{ + /* Fill uninitialized blocks by FF: simulate real flash media. */ + memset (buf, 0xFF, blen); + + if (lseek (fd, offset, 0) != offset) { + printf ("sdcard: seek failed, offset %#x\n", offset); + return; + } + if (read (fd, buf, blen) < 0) { + printf ("sdcard: read failed, offset %#x\n", offset); + return; + } +} + +static void sdcard_write_data (int fd, unsigned offset, + unsigned char *buf, unsigned blen) +{ + if (lseek (fd, offset, 0) != offset) { + printf ("sdcard: seek failed, offset %#x\n", offset); + return; + } + if (write (fd, buf, blen) != blen) { + printf ("sdcard: write failed, offset %#x\n", offset); + return; + } +} + +static void sdcard_reset (sdcard_t *d) +{ + d->select = 0; + d->blen = 512; + d->count = 0; +} + +/* + * Reset sdcard. + */ +void dev_sdcard_reset (cpu_mips_t *cpu) +{ + pic32_t *pic32 = (pic32_t*) cpu->vm->hw_data; + + sdcard_reset (&pic32->sdcard[0]); + sdcard_reset (&pic32->sdcard[1]); +} + +/* + * Initialize SD card. + */ +int dev_sdcard_init (sdcard_t *d, char *name, unsigned mbytes, char *filename) +{ + memset (d, 0, sizeof (*d)); + d->name = name; + if (mbytes == 0 || ! filename) { + /* No SD card installed. */ + return (0); + } + d->kbytes = mbytes * 1024; + d->fd = open (filename, O_RDWR); + if (d->fd < 0) { + /* Fatal: no image available. */ + perror (filename); + return (-1); + } + return (0); +} + +void dev_sdcard_select (cpu_mips_t *cpu, int unit, int on) +{ + pic32_t *pic32 = (pic32_t*) cpu->vm->hw_data; + sdcard_t *d = &pic32->sdcard[unit]; + + if (on) { + TRACE ("sdcard%d: (((\n", unit); + d->select = 1; + d->count = 0; + } else { + TRACE ("sdcard%d: )))\n", unit); + d->select = 0; + } +} + +/* + * Data i/o: send byte to device. + * Return received byte. + */ +unsigned dev_sdcard_io (cpu_mips_t *cpu, unsigned data) +{ + pic32_t *pic32 = (pic32_t*) cpu->vm->hw_data; + sdcard_t *d = pic32->sdcard[0].select ? &pic32->sdcard[0] : + pic32->sdcard[1].select ? &pic32->sdcard[1] : 0; + unsigned reply; + + if (! d) { + TRACE ("sdcard: unselected i/o\n"); + return 0xFF; + } + data = (unsigned char) data; + reply = 0xFF; + if (d->count == 0) { + d->buf[0] = data; + if (data != 0xFF) + d->count++; + } else { + switch (d->buf[0]) { + case CMD_GO_IDLE: /* CMD0: reset */ + if (d->count >= 7) + break; + d->buf [d->count++] = data; + if (d->count == 7) + reply = 0x01; + break; + case CMD_APP: /* CMD55: application prefix */ + if (d->count >= 7) + break; + d->buf [d->count++] = data; + if (d->count == 7) { + reply = 0; + d->count = 0; + } + break; + case CMD_SEND_OP_SDC: /* ACMD41: initialization */ + if (d->count >= 7) + break; + d->buf [d->count++] = data; + if (d->count == 7) + reply = 0; + break; + case CMD_SET_BLEN: /* Set block length */ + if (d->count >= 7) + break; + d->buf [d->count++] = data; + if (d->count == 7) { + d->blen = d->buf[1] << 24 | d->buf[2] << 16 | + d->buf[3] << 8 | d->buf[4]; + TRACE ("sdcard%d: set block length %u bytes\n", d->unit, d->blen); + reply = (d->blen > 0 && d->blen <= 1024) ? 0 : 4; + } + break; + case CMD_SET_WBECNT: /* Set write block erase count */ + if (d->count >= 7) + break; + d->buf [d->count++] = data; + if (d->count == 7) { + d->wbecnt = d->buf[1] << 24 | d->buf[2] << 16 | + d->buf[3] << 8 | d->buf[4]; + TRACE ("sdcard%d: set write block erase count %u\n", d->unit, d->wbecnt); + reply = 0; + d->count = 0; + } + break; + case CMD_SEND_CSD: /* Get card data */ + if (d->count >= 7) + break; + d->buf [d->count++] = data; + if (d->count == 7) { + /* Send reply */ + TRACE ("sdcard%d: send media size %u sectors\n", + d->unit, d->kbytes * 2); + reply = 0; + d->limit = 16 + 3; + d->count = 1; + d->buf[0] = 0; + d->buf[1] = DATA_START_BLOCK; + d->buf[2+0] = 1 << 6; /* SDC ver 2.00 */ + d->buf[2+1] = 0; + d->buf[2+2] = 0; + d->buf[2+3] = 0; + d->buf[2+4] = 0; + d->buf[2+5] = 0; + d->buf[2+6] = 0; + d->buf[2+7] = 0; + d->buf[2+8] = (d->kbytes / 512 - 1) >> 8; + d->buf[2+9] = d->kbytes / 512 - 1; + d->buf[2+10] = 0; + d->buf[2+11] = 0; + d->buf[2+12] = 0; + d->buf[2+13] = 0; + d->buf[2+14] = 0; + d->buf[2+15] = 0; + d->buf[d->limit - 1] = 0xFF; + d->buf[d->limit] = 0xFF; + } + break; + case CMD_READ_SINGLE: /* Read block */ + if (d->count >= 7) + break; + d->buf [d->count++] = data; + if (d->count == 7) { + /* Send reply */ + reply = 0; + d->offset = d->buf[1] << 24 | d->buf[2] << 16 | + d->buf[3] << 8 | d->buf[4]; + TRACE ("sdcard%d: read offset %#x, length %u kbytes\n", + d->unit, d->offset, d->blen); + d->limit = d->blen + 3; + d->count = 1; + d->buf[0] = 0; + d->buf[1] = DATA_START_BLOCK; + sdcard_read_data (d->fd, d->offset, &d->buf[2], d->blen); + d->buf[d->limit - 1] = 0xFF; + d->buf[d->limit] = 0xFF; + } + break; + case CMD_READ_MULTIPLE: /* Read multiple blocks */ + if (d->count >= 7) + break; + d->buf [d->count++] = data; + if (d->count == 7) { + /* Send reply */ + reply = 0; + d->read_multiple = 1; + d->offset = d->buf[1] << 24 | d->buf[2] << 16 | + d->buf[3] << 8 | d->buf[4]; + TRACE ("sdcard%d: read offset %#x, length %u kbytes\n", + d->unit, d->offset, d->blen); + d->limit = d->blen + 3; + d->count = 1; + d->buf[0] = 0; + d->buf[1] = DATA_START_BLOCK; + sdcard_read_data (d->fd, d->offset, &d->buf[2], d->blen); + d->buf[d->limit - 1] = 0xFF; + d->buf[d->limit] = 0xFF; + } + break; + case CMD_WRITE_SINGLE: /* Write block */ + if (d->count >= sizeof (d->buf)) + break; + d->buf [d->count++] = data; + if (d->count == 7) { + /* Accept command */ + reply = 0; + d->offset = d->buf[1] << 24 | d->buf[2] << 16 | + d->buf[3] << 8 | d->buf[4]; + TRACE ("sdcard%d: write offset %#x\n", d->unit, d->offset); + } else if (d->count == 7 + d->blen + 2 + 2) { + if (d->buf[7] == DATA_START_BLOCK) { + /* Accept data */ + reply = 0x05; + d->offset = d->buf[1] << 24 | d->buf[2] << 16 | + d->buf[3] << 8 | d->buf[4]; + sdcard_write_data (d->fd, d->offset, &d->buf[8], d->blen); + TRACE ("sdcard%d: write data, length %u kbytes\n", d->unit, d->blen); + } else { + /* Reject data */ + reply = 4; + TRACE ("sdcard%d: reject write data, tag=%02x\n", d->unit, d->buf[7]); + } + } + break; + case CMD_WRITE_MULTIPLE: /* Write multiple blocks */ + if (d->count >= 7) + break; + d->buf [d->count++] = data; + if (d->count == 7) { + /* Accept command */ + reply = 0; + d->offset = d->buf[1] << 24 | d->buf[2] << 16 | + d->buf[3] << 8 | d->buf[4]; + TRACE ("sdcard%d: write multiple offset %#x\n", d->unit, d->offset); + d->count = 0; + } + break; + case WRITE_MULTIPLE_TOKEN: /* Data for write-miltiple */ + if (d->count >= sizeof (d->buf)) + break; + d->buf [d->count++] = data; + if (d->count == 2 + d->blen + 2) { + /* Accept data */ + reply = 0x05; + sdcard_write_data (d->fd, d->offset, &d->buf[1], d->blen); + TRACE ("sdcard%d: write sector %u, length %u kbytes\n", + d->unit, d->offset / 512, d->blen); + d->offset += 512; + d->count = 0; + } + break; + case CMD_STOP: /* Stop read-multiple sequence */ + if (d->count > 1) + break; + d->read_multiple = 0; + reply = 0; + break; + case 0: /* Reply */ + if (d->count <= d->limit) { + reply = d->buf [d->count++]; + break; + } + if (d->read_multiple) { + /* Next read-multiple block. */ + d->offset += d->blen; + d->count = 1; + sdcard_read_data (d->fd, d->offset, &d->buf[2], d->blen); + reply = 0; + } + break; + default: /* Ignore */ + break; + } + } + TRACE ("sdcard%d: send %02x, reply %02x\n", d->unit, data, reply); + return reply; +} diff --git a/tools/virtualmips/dev_sdcard.h b/tools/virtualmips/dev_sdcard.h new file mode 100644 index 0000000..f98eca0 --- /dev/null +++ b/tools/virtualmips/dev_sdcard.h @@ -0,0 +1,34 @@ +/* + * SecureDigital flash card. + * + * Copyright (C) 2011 Serge Vakulenko + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + */ +#ifndef __DEV_SD__ +#define __DEV_SD__ + +/* SD card private data */ +struct sdcard { + char *name; /* Device name */ + unsigned kbytes; /* Disk size */ + int unit; /* Index (sd0 or sd1) */ + int fd; /* Image file */ + int select; /* Selected */ + int read_multiple; /* Read-multiple mode */ + unsigned blen; /* Block length */ + unsigned wbecnt; /* Write block erase count */ + unsigned offset; /* Read/write offset */ + unsigned count; /* Byte count */ + unsigned limit; /* Reply length */ + unsigned char buf [1024 + 16]; +}; +typedef struct sdcard sdcard_t; + +int dev_sdcard_init (sdcard_t *d, char *devname, unsigned mbytes, char *filename); +void dev_sdcard_reset (cpu_mips_t *cpu); +void dev_sdcard_select (cpu_mips_t *cpu, int unit, int on); +unsigned dev_sdcard_io (cpu_mips_t *cpu, unsigned data); + +#endif diff --git a/tools/virtualmips/dev_swap.c b/tools/virtualmips/dev_swap.c new file mode 100644 index 0000000..9e2f796 --- /dev/null +++ b/tools/virtualmips/dev_swap.c @@ -0,0 +1,123 @@ +/* + * RAM-based disk for swap. + * + * Copyright (C) 2011 Igor Mokos + * Copyright (C) 2011 Serge Vakulenko + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + * + */ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include + +#include "vm.h" +#include "mips_memory.h" +#include "device.h" +#include "dev_swap.h" + +//#define TRACE printf +#ifndef TRACE +#define TRACE(...) /*empty*/ +#endif + +/* + * Reset swap. + */ +void dev_swap_reset (cpu_mips_t *cpu) +{ + pic32_t *pic32 = (pic32_t*) cpu->vm->hw_data; + + pic32->swap.rd = 0; + pic32->swap.wr = 0; + pic32->swap.ldaddr = 0; + pic32->swap.offset = 0; +} + +/* + * Initialize SD card. + */ +int dev_swap_init (swap_t *d, char *name) +{ + memset (d, 0, sizeof (*d)); + d->name = name; + return (0); +} + +void dev_swap_rd (cpu_mips_t *cpu, int on) +{ + pic32_t *pic32 = (pic32_t*) cpu->vm->hw_data; + swap_t *d = &pic32->swap; + + if (on && ! d->rd) { + d->rd = 1; + d->offset %= SWAP_BYTES; + d->data = d->buf [d->offset]; + TRACE ("swap: RD on, %06X -> %02X\n", d->offset, d->data); + } else if (! on && d->rd) { + d->rd = 0; + d->offset++; + TRACE ("swap: RD off, offset = %06X\n", d->offset); + } +} + +void dev_swap_wr (cpu_mips_t *cpu, int on) +{ + pic32_t *pic32 = (pic32_t*) cpu->vm->hw_data; + swap_t *d = &pic32->swap; + + if (on && ! d->wr) { + d->wr = 1; + d->offset %= SWAP_BYTES; + d->buf [d->offset] = d->data; + TRACE ("swap: WR on, %06X := %02X\n", d->offset, d->data); + } else if (! on && d->wr) { + d->wr = 0; + d->offset++; + TRACE ("swap: WR off, offset = %06X\n", d->offset); + } +} + +void dev_swap_ldaddr (cpu_mips_t *cpu, int on) +{ + pic32_t *pic32 = (pic32_t*) cpu->vm->hw_data; + swap_t *d = &pic32->swap; + + if (on && ! d->ldaddr) { + d->ldaddr = 1; + d->offset >>= 4; + d->offset |= d->data << 20; + TRACE ("swap: LDADDR on, offset = %06X\n", d->offset); + } else if (! on && d->ldaddr) { + TRACE ("swap: LDADDR off\n"); + d->ldaddr = 0; + } +} + +/* + * Data i/o: send byte to device. + * Return received byte. + */ +unsigned dev_swap_io (cpu_mips_t *cpu, unsigned char newval, unsigned char rmask) +{ + pic32_t *pic32 = (pic32_t*) cpu->vm->hw_data; + swap_t *d = &pic32->swap; + + if (rmask == 0) { + /* Write mode. */ + //TRACE ("swap: send %02x\n", newval); + d->data = newval; + } else { + //TRACE ("swap: receive %02x\n", d->data); + } + + /* Read mode. */ + return d->data; +} diff --git a/tools/virtualmips/dev_swap.h b/tools/virtualmips/dev_swap.h new file mode 100644 index 0000000..96fe561 --- /dev/null +++ b/tools/virtualmips/dev_swap.h @@ -0,0 +1,34 @@ +/* + * RAM-based disk for swap. + * + * Copyright (C) 2011 Igor Mokos + * Copyright (C) 2011 Serge Vakulenko + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + */ +#ifndef __DEV_SWAP__ +#define __DEV_SWAP__ + +#define SWAP_BYTES (2*1024*1024) /* Disk size */ + +/* Swap device private data */ +struct swap { + char *name; /* Device name */ + int rd; /* RD signal */ + int wr; /* WR signal */ + int ldaddr; /* LDADDR signal */ + unsigned char data; /* Latched byte */ + unsigned offset; /* Read/write offset */ + unsigned char buf [SWAP_BYTES]; /* Stored data */ +}; +typedef struct swap swap_t; + +int dev_swap_init (swap_t *d, char *devname); +void dev_swap_reset (cpu_mips_t *cpu); +void dev_swap_rd (cpu_mips_t *cpu, int on); +void dev_swap_wr (cpu_mips_t *cpu, int on); +void dev_swap_ldaddr (cpu_mips_t *cpu, int on); +unsigned dev_swap_io (cpu_mips_t *cpu, unsigned char data, unsigned char mask); + +#endif diff --git a/tools/virtualmips/dev_vtty.c b/tools/virtualmips/dev_vtty.c new file mode 100644 index 0000000..0d62486 --- /dev/null +++ b/tools/virtualmips/dev_vtty.c @@ -0,0 +1,1037 @@ +/* + * Cisco router simulation platform. + * Copyright (c) 2005,2006 Christophe Fillot (cf@utc.fr) + * + * Virtual console TTY. + * + * "Interactive" part idea by Mtve. + * TCP console added by Mtve. + * Serial console by Peter Ross (suxen_drol@hotmail.com) + */ + +/* By default, Cygwin supports only 64 FDs with select()! */ + + /* + * Copyright (C) yajin 2008 + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + * + */ + +#ifdef __CYGWIN__ +#define FD_SETSIZE 1024 +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "utils.h" +#include "mips.h" +#include "vm.h" + +#include "mips_exec.h" + +#include "device.h" +#include "mips_memory.h" +#include "dev_vtty.h" + +/* VTTY list */ +static pthread_mutex_t vtty_list_mutex = PTHREAD_MUTEX_INITIALIZER; +static vtty_t *vtty_list = NULL; +static pthread_t vtty_thread; + +#define VTTY_LIST_LOCK() pthread_mutex_lock(&vtty_list_mutex); +#define VTTY_LIST_UNLOCK() pthread_mutex_unlock(&vtty_list_mutex); + +static struct termios tios, tios_orig; + +/* Send Telnet command: WILL TELOPT_ECHO */ +static void vtty_telnet_will_echo (vtty_t * vtty) +{ + u_char cmd[] = { IAC, WILL, TELOPT_ECHO }; + if (write (vtty->fd, cmd, sizeof (cmd)) < 0) + perror ("vtty_telnet_will_echo"); +} + +/* Send Telnet command: Suppress Go-Ahead */ +static void vtty_telnet_will_suppress_go_ahead (vtty_t * vtty) +{ + u_char cmd[] = { IAC, WILL, TELOPT_SGA }; + if (write (vtty->fd, cmd, sizeof (cmd)) < 0) + perror ("vtty_telnet_will_suppress_go_ahead"); +} + +/* Send Telnet command: Don't use linemode */ +static void vtty_telnet_dont_linemode (vtty_t * vtty) +{ + u_char cmd[] = { IAC, DONT, TELOPT_LINEMODE }; + if (write (vtty->fd, cmd, sizeof (cmd)) < 0) + perror ("vtty_telnet_dont_linemode"); +} + +/* Send Telnet command: does the client support terminal type message? */ +static void vtty_telnet_do_ttype (vtty_t * vtty) +{ + u_char cmd[] = { IAC, DO, TELOPT_TTYPE }; + if (write (vtty->fd, cmd, sizeof (cmd)) < 0) + perror ("vtty_telnet_do_ttype"); +} + +/* Restore TTY original settings */ +static void vtty_term_reset (void) +{ + tcsetattr (STDIN_FILENO, TCSANOW, &tios_orig); +} + +/* Initialize real TTY */ +static void vtty_term_init (void) +{ + tcgetattr (STDIN_FILENO, &tios); + + memcpy (&tios_orig, &tios, sizeof (struct termios)); + atexit (vtty_term_reset); + + tios.c_cc[VTIME] = 0; + tios.c_cc[VMIN] = 1; + + /* Disable Ctrl-C, Ctrl-S, Ctrl-Q and Ctrl-Z */ + tios.c_cc[VINTR] = 0; + tios.c_cc[VSTART] = 0; + tios.c_cc[VSTOP] = 0; + tios.c_cc[VSUSP] = 0; + + tios.c_lflag &= ~(ICANON | ECHO); + tios.c_iflag &= ~ICRNL; + tcsetattr (STDIN_FILENO, TCSANOW, &tios); + tcflush (STDIN_FILENO, TCIFLUSH); +} + +/* Wait for a TCP connection */ +static int vtty_tcp_conn_wait (vtty_t * vtty) +{ + struct sockaddr_in serv; + int one = 1; + + vtty->state = VTTY_STATE_TCP_INVALID; + + if ((vtty->accept_fd = socket (PF_INET, SOCK_STREAM, 0)) < 0) { + perror ("vtty_tcp_waitcon: socket"); + return (-1); + } + + if (setsockopt (vtty->accept_fd, SOL_SOCKET, SO_REUSEADDR, &one, + sizeof (one)) < 0) { + perror ("vtty_tcp_waitcon: setsockopt(SO_REUSEADDR)"); + goto error; + } + + memset (&serv, 0, sizeof (serv)); + serv.sin_family = AF_INET; + serv.sin_addr.s_addr = htonl (INADDR_ANY); + serv.sin_port = htons (vtty->tcp_port); + + if (bind (vtty->accept_fd, (struct sockaddr *) &serv, sizeof (serv)) < 0) { + perror ("vtty_tcp_waitcon: bind"); + goto error; + } + + if (listen (vtty->accept_fd, 1) < 0) { + perror ("vtty_tcp_waitcon: listen"); + goto error; + } + + vm_log (vtty->vm, "VTTY", + "%s: waiting connection on tcp port %d (FD %d)\n", vtty->name, + vtty->tcp_port, vtty->accept_fd); + + vtty->select_fd = &vtty->accept_fd; + vtty->state = VTTY_STATE_TCP_WAITING; + return (0); + + error: + close (vtty->accept_fd); + vtty->accept_fd = -1; + vtty->select_fd = NULL; + return (-1); +} + +/* Accept a TCP connection */ +static int vtty_tcp_conn_accept (vtty_t * vtty) +{ + if ((vtty->fd = accept (vtty->accept_fd, NULL, NULL)) < 0) { + fprintf (stderr, + "vtty_tcp_conn_accept: accept on port %d failed %s\n", + vtty->tcp_port, strerror (errno)); + return (-1); + } + + vm_log (vtty->vm, "VTTY", + "%s is now connected (accept_fd=%d,conn_fd=%d)\n", vtty->name, + vtty->accept_fd, vtty->fd); + + /* Adapt Telnet settings */ + if (vtty->terminal_support) { + vtty_telnet_do_ttype (vtty); + vtty_telnet_will_echo (vtty); + vtty_telnet_will_suppress_go_ahead (vtty); + vtty_telnet_dont_linemode (vtty); + vtty->input_state = VTTY_INPUT_TELNET; + } + + if (!(vtty->fstream = fdopen (vtty->fd, "wb"))) { + close (vtty->fd); + vtty->fd = -1; + return (-1); + } + + fprintf (vtty->fstream, + "Connected to Dynamips VM \"%s\" ( type %s) - %s\r\n\r\n", + vtty->vm->name, vm_get_type (vtty->vm), vtty->name); + + vtty->select_fd = &vtty->fd; + vtty->state = VTTY_STATE_TCP_RUNNING; + return (0); +} + +/* + * Parse serial interface descriptor string, return 0 if success + * string takes the form "device:baudrate:databits:parity:stopbits:hwflow" + * device is mandatory, other options are optional (default=9600,8,N,1,0). + */ +int vtty_parse_serial_option (vtty_serial_option_t * option, char *optarg) +{ + char *array[6]; + int count; + + if ((count = m_strtok (optarg, ':', array, 6)) < 1) { + fprintf (stderr, "vtty_parse_serial_option: invalid string\n"); + return (-1); + } + + if (!(option->device = strdup (array[0]))) { + fprintf (stderr, "vtty_parse_serial_option: unable to copy string\n"); + return (-1); + } + + option->baudrate = (count > 1) ? atoi (array[1]) : 9600; + option->databits = (count > 2) ? atoi (array[2]) : 8; + + if (count > 3) { + switch (*array[3]) { + case 'o': + case 'O': + option->parity = 1; /* odd */ + case 'e': + case 'E': + option->parity = 2; /* even */ + default: + option->parity = 0; /* none */ + } + } else { + option->parity = 0; + } + + option->stopbits = (count > 4) ? atoi (array[4]) : 1; + option->hwflow = (count > 5) ? atoi (array[5]) : 0; + return (0); +} + +#if defined(__CYGWIN__) || defined(SUNOS) +void cfmakeraw (struct termios *termios_p) +{ + termios_p->c_iflag &= + ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON); + termios_p->c_oflag &= ~OPOST; + termios_p->c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); + termios_p->c_cflag &= ~(CSIZE | PARENB); + termios_p->c_cflag |= CS8; +} +#endif + +/* + * Setup serial port, return 0 if success. + */ +static int vtty_serial_setup (vtty_t * vtty, + const vtty_serial_option_t * option) +{ + struct termios tio; + int tio_baudrate; + + if (tcgetattr (vtty->fd, &tio) != 0) { + fprintf (stderr, "error: tcgetattr failed\n"); + return (-1); + } + + cfmakeraw (&tio); + + tio.c_cflag = 0 | CLOCAL // ignore modem control lines + ; + + tio.c_cflag &= ~CREAD; + tio.c_cflag |= CREAD; + + switch (option->baudrate) { + case 50: + tio_baudrate = B50; + break; + case 75: + tio_baudrate = B75; + break; + case 110: + tio_baudrate = B110; + break; + case 134: + tio_baudrate = B134; + break; + case 150: + tio_baudrate = B150; + break; + case 200: + tio_baudrate = B200; + break; + case 300: + tio_baudrate = B300; + break; + case 600: + tio_baudrate = B600; + break; + case 1200: + tio_baudrate = B1200; + break; + case 1800: + tio_baudrate = B1800; + break; + case 2400: + tio_baudrate = B2400; + break; + case 4800: + tio_baudrate = B4800; + break; + case 9600: + tio_baudrate = B9600; + break; + case 19200: + tio_baudrate = B19200; + break; + case 38400: + tio_baudrate = B38400; + break; + case 57600: + tio_baudrate = B57600; + break; +#if defined(B76800) + case 76800: + tio_baudrate = B76800; + break; +#endif + case 115200: + tio_baudrate = B115200; + break; +#if defined(B230400) + case 230400: + tio_baudrate = B230400; + break; +#endif + default: + fprintf (stderr, "error: unsupported baudrate\n"); + return (-1); + } + + cfsetospeed (&tio, tio_baudrate); + cfsetispeed (&tio, tio_baudrate); + + tio.c_cflag &= ~CSIZE; /* clear size flag */ + switch (option->databits) { + case 5: + tio.c_cflag |= CS5; + break; + case 6: + tio.c_cflag |= CS6; + break; + case 7: + tio.c_cflag |= CS7; + break; + case 8: + tio.c_cflag |= CS8; + break; + default: + fprintf (stderr, "error: unsupported databits\n"); + return (-1); + } + + tio.c_iflag &= ~INPCK; /* clear parity flag */ + tio.c_cflag &= ~(PARENB | PARODD); + switch (option->parity) { + case 0: + break; + case 2: + tio.c_iflag |= INPCK; + tio.c_cflag |= PARENB; + break; /* even */ + case 1: + tio.c_iflag |= INPCK; + tio.c_cflag |= PARENB | PARODD; + break; /* odd */ + default: + fprintf (stderr, "error: unsupported parity\n"); + return (-1); + } + + tio.c_cflag &= ~CSTOPB; /* clear stop flag */ + switch (option->stopbits) { + case 1: + break; + case 2: + tio.c_cflag |= CSTOPB; + break; + default: + fprintf (stderr, "error: unsupported stopbits\n"); + return (-1); + } + +#if defined(CRTSCTS) + tio.c_cflag &= ~CRTSCTS; +#endif +#if defined(CNEW_RTSCTS) + tio.c_cflag &= ~CNEW_RTSCTS; +#endif + if (option->hwflow) { +#if defined(CRTSCTS) + tio.c_cflag |= CRTSCTS; +#else + tio.c_cflag |= CNEW_RTSCTS; +#endif + } + + tio.c_cc[VTIME] = 0; + tio.c_cc[VMIN] = 1; /* block read() until one character is available */ + +#if 0 + /* not neccessary unless O_NONBLOCK used */ + if (fcntl (vtty->fd, F_SETFL, 0) != 0) { /* enable blocking mode */ + fprintf (stderr, "error: fnctl F_SETFL failed\n"); + return (-1); + } +#endif + + if (tcflush (vtty->fd, TCIOFLUSH) != 0) { + fprintf (stderr, "error: tcflush failed\n"); + return (-1); + } + + if (tcsetattr (vtty->fd, TCSANOW, &tio) != 0) { + fprintf (stderr, "error: tcsetattr failed\n"); + return (-1); + } + + return (0); +} + +/* Create a virtual tty */ +vtty_t *vtty_create (vm_instance_t * vm, char *name, int type, int tcp_port, + const vtty_serial_option_t * option) +{ + vtty_t *vtty; + + if (!(vtty = malloc (sizeof (*vtty)))) { + fprintf (stderr, "VTTY: unable to create new virtual tty.\n"); + return NULL; + } + + memset (vtty, 0, sizeof (*vtty)); + vtty->name = name; + vtty->type = type; + vtty->vm = vm; + vtty->fd = -1; + vtty->fstream = NULL; + vtty->accept_fd = -1; + pthread_mutex_init (&vtty->lock, NULL); + vtty->terminal_support = 0; // was 1 (vak) + vtty->input_state = VTTY_INPUT_TEXT; + + switch (vtty->type) { + case VTTY_TYPE_NONE: + vtty->select_fd = NULL; + break; + + case VTTY_TYPE_TERM: + vtty_term_init (); + vtty->fd = STDIN_FILENO; + vtty->select_fd = &vtty->fd; + vtty->fstream = stdout; + break; + + case VTTY_TYPE_TCP: + vtty->tcp_port = tcp_port; + vtty_tcp_conn_wait (vtty); + break; + + case VTTY_TYPE_SERIAL: + vtty->fd = open (option->device, O_RDWR); + if (vtty->fd < 0) { + fprintf (stderr, "VTTY: open failed\n"); + free (vtty); + return NULL; + } + if (vtty_serial_setup (vtty, option)) { + fprintf (stderr, "VTTY: setup failed\n"); + close (vtty->fd); + free (vtty); + return NULL; + } + vtty->select_fd = &vtty->fd; + vtty->terminal_support = 0; + break; + + default: + fprintf (stderr, "tty_create: bad vtty type %d\n", vtty->type); + return NULL; + } + + /* Add this new VTTY to the list */ + VTTY_LIST_LOCK (); + vtty->next = vtty_list; + vtty->pprev = &vtty_list; + + if (vtty_list != NULL) + vtty_list->pprev = &vtty->next; + + vtty_list = vtty; + VTTY_LIST_UNLOCK (); + return vtty; +} + +/* Delete a virtual tty */ +void vtty_delete (vtty_t * vtty) +{ + if (vtty != NULL) { + if (vtty->pprev != NULL) { + VTTY_LIST_LOCK (); + if (vtty->next) + vtty->next->pprev = vtty->pprev; + *(vtty->pprev) = vtty->next; + VTTY_LIST_UNLOCK (); + } + + if ((vtty->fstream) && (vtty->fstream != stdout)) + fclose (vtty->fstream); + + /* We don't close FD 0 since it is stdin */ + if (vtty->fd > 0) { + vm_log (vtty->vm, "VTTY", "%s: closing FD %d\n", vtty->name, + vtty->fd); + close (vtty->fd); + } + + if (vtty->accept_fd != -1) { + vm_log (vtty->vm, "VTTY", "%s: closing accept FD %d\n", + vtty->name, vtty->accept_fd); + close (vtty->accept_fd); + } + + free (vtty); + } +} + +/* Store a character in the FIFO buffer */ +static int vtty_store (vtty_t * vtty, u_char c) +{ + u_int nwptr; + + VTTY_LOCK (vtty); + nwptr = vtty->write_ptr + 1; + if (nwptr == VTTY_BUFFER_SIZE) + nwptr = 0; + + if (nwptr == vtty->read_ptr) { + VTTY_UNLOCK (vtty); + return (-1); + } + + vtty->buffer[vtty->write_ptr] = c; + vtty->write_ptr = nwptr; + VTTY_UNLOCK (vtty); + return (0); +} + +/* Store a string in the FIFO buffer */ +int vtty_store_str (vtty_t * vtty, char *str) +{ + if (!vtty) + return (0); + + while (*str != 0) { + if (vtty_store (vtty, *str) == -1) + return (-1); + + str++; + } + + vtty->input_pending = TRUE; + return (0); +} + +/* Store CTRL+C in buffer */ +int vtty_store_ctrlc (vtty_t * vtty) +{ + if (vtty) + vtty_store (vtty, 0x03); + return (0); +} + +/* + * Read a character from the terminal. + */ +static int vtty_term_read (vtty_t * vtty) +{ + u_char c; + + if (read (vtty->fd, &c, 1) == 1) + return (c); + + perror ("read from vtty failed"); + return (-1); +} + +/* + * Read a character from the TCP connection. + */ +static int vtty_tcp_read (vtty_t * vtty) +{ + u_char c; + + switch (vtty->state) { + case VTTY_STATE_TCP_RUNNING: + if (read (vtty->fd, &c, 1) == 1) + return (c); + + /* Problem with the connection: Re-enter wait mode */ + shutdown (vtty->fd, 2); + fclose (vtty->fstream); + close (vtty->fd); + vtty->fstream = NULL; + vtty->fd = -1; + vtty->select_fd = &vtty->accept_fd; + vtty->state = VTTY_STATE_TCP_WAITING; + return (-1); + + case VTTY_STATE_TCP_WAITING: + /* A new connection has arrived */ + vtty_tcp_conn_accept (vtty); + return (-1); + } + + /* Shouldn't happen... */ + return (-1); +} + +/* + * Read a character from the USB connection. + */ +static int vtty_usb_read (vtty_t * vtty) +{ + // stub + perror("VTTY not yet implemented on USB\n"); + return (-1); +} + +/* + * Read a character from the virtual TTY. + * + * If the VTTY is a TCP connection, restart it in case of error. + */ +static int vtty_read (vtty_t * vtty) +{ + switch (vtty->type) { + case VTTY_TYPE_TERM: + case VTTY_TYPE_SERIAL: + return (vtty_term_read (vtty)); + case VTTY_TYPE_TCP: + return (vtty_tcp_read (vtty)); + case VTTY_TYPE_USB: + return (vtty_usb_read (vtty)); + default: + fprintf (stderr, "vtty_read: bad vtty type %d\n", vtty->type); + return (-1); + } + + /* NOTREACHED */ + return (-1); +} + +#if 0 +/* Remote control for MIPS64 processors */ +static int remote_control_mips (vtty_t * vtty, char c, cpu_mips_t * cpu) +{ + switch (c) { + /* Show information about JIT compiled pages */ + case 'b': + // printf("\nCPU0: %u JIT compiled pages [Exec Area Pages: %lu/%lu]\n", + // cpu->compiled_pages, + // (u_long)cpu->exec_page_alloc, + // (u_long)cpu->exec_page_count); + break; + + /* Non-JIT mode statistics */ + case 'j': + // mips_dump_stats(cpu); + break; + + default: + return (FALSE); + } + + return (TRUE); +} +#endif + +/* Read a character (until one is available) and store it in buffer */ +static void vtty_read_and_store (vtty_t * vtty) +{ + int c; + + /* wait until we get a character input */ + c = vtty_read (vtty); + + /* if read error, do nothing */ + if (c < 0) + return; + + if (!vtty->terminal_support) { + vtty_store (vtty, c); + return; + } + + switch (vtty->input_state) { + case VTTY_INPUT_TEXT: + switch (c) { + case 0x1b: + vtty->input_state = VTTY_INPUT_VT1; + return; + + /* Ctrl + ']' (0x1d, 29), or Alt-Gr + '*' (0xb3, 179) */ + case 0x1d: + case 0xb3: + vtty->input_state = VTTY_INPUT_REMOTE; + return; + case IAC: + vtty->input_state = VTTY_INPUT_TELNET; + return; + case 0: /* NULL - Must be ignored - generated by Linux telnet */ + case 10: /* LF (Line Feed) - Must be ignored on Windows platform */ + return; + default: + /* Store a standard character */ + vtty_store (vtty, c); + return; + } + + case VTTY_INPUT_VT1: + switch (c) { + case 0x5b: + vtty->input_state = VTTY_INPUT_VT2; + return; + default: + vtty_store (vtty, 0x1b); + vtty_store (vtty, c); + } + vtty->input_state = VTTY_INPUT_TEXT; + return; + + case VTTY_INPUT_VT2: + switch (c) { + case 0x41: /* Up Arrow */ + vtty_store (vtty, 16); + break; + case 0x42: /* Down Arrow */ + vtty_store (vtty, 14); + break; + case 0x43: /* Right Arrow */ + vtty_store (vtty, 6); + break; + case 0x44: /* Left Arrow */ + vtty_store (vtty, 2); + break; + default: + vtty_store (vtty, 0x5b); + vtty_store (vtty, 0x1b); + vtty_store (vtty, c); + break; + } + vtty->input_state = VTTY_INPUT_TEXT; + return; + + case VTTY_INPUT_REMOTE: + //remote_control(vtty, c); + vtty->input_state = VTTY_INPUT_TEXT; + return; + + case VTTY_INPUT_TELNET: + vtty->telnet_cmd = c; + switch (c) { + case WILL: + case WONT: + case DO: + case DONT: + vtty->input_state = VTTY_INPUT_TELNET_IYOU; + return; + case SB: + vtty->telnet_cmd = c; + vtty->input_state = VTTY_INPUT_TELNET_SB1; + return; + case SE: + break; + case IAC: + vtty_store (vtty, IAC); + break; + } + vtty->input_state = VTTY_INPUT_TEXT; + return; + + case VTTY_INPUT_TELNET_IYOU: + vtty->telnet_opt = c; + /* if telnet client can support ttype, ask it to send ttype string */ + if ((vtty->telnet_cmd == WILL) && (vtty->telnet_opt == TELOPT_TTYPE)) { + vtty_put_char (vtty, IAC); + vtty_put_char (vtty, SB); + vtty_put_char (vtty, TELOPT_TTYPE); + vtty_put_char (vtty, TELQUAL_SEND); + vtty_put_char (vtty, IAC); + vtty_put_char (vtty, SE); + } + vtty->input_state = VTTY_INPUT_TEXT; + return; + + case VTTY_INPUT_TELNET_SB1: + vtty->telnet_opt = c; + vtty->input_state = VTTY_INPUT_TELNET_SB2; + return; + + case VTTY_INPUT_TELNET_SB2: + vtty->telnet_qual = c; + if ((vtty->telnet_opt == TELOPT_TTYPE) + && (vtty->telnet_qual == TELQUAL_IS)) + vtty->input_state = VTTY_INPUT_TELNET_SB_TTYPE; + else + vtty->input_state = VTTY_INPUT_TELNET_NEXT; + return; + + case VTTY_INPUT_TELNET_SB_TTYPE: + /* parse ttype string: first char is sufficient */ + /* if client is xterm or vt, set the title bar */ + if ((c == 'x') || (c == 'X') || (c == 'v') || (c == 'V')) { + // fprintf(vtty->fstream, "\033]0;Dynamips(%i): %s, %s\07", + // vtty->vm->instance_id, vtty->vm->name, vtty->name); + } + vtty->input_state = VTTY_INPUT_TELNET_NEXT; + return; + + case VTTY_INPUT_TELNET_NEXT: + /* ignore all chars until next IAC */ + if (c == IAC) + vtty->input_state = VTTY_INPUT_TELNET; + return; + } +} + +int vtty_bytes (vtty_t * vtty) +{ + if (vtty->read_ptr < vtty->write_ptr) + return vtty->write_ptr - vtty->read_ptr; + else if (vtty->read_ptr == vtty->write_ptr) { + return VTTY_BUFFER_SIZE; + } else + return VTTY_BUFFER_SIZE - (vtty->read_ptr - vtty->write_ptr); +} + +int vtty_is_full (vtty_t * vtty) +{ + return (vtty->read_ptr == vtty->write_ptr); +} + +/* Read a character from the buffer (-1 if the buffer is empty) */ +int vtty_get_char (vtty_t * vtty) +{ + u_char c; + + VTTY_LOCK (vtty); + + if (vtty->read_ptr == vtty->write_ptr) { + VTTY_UNLOCK (vtty); + return (-1); + } + + c = vtty->buffer[vtty->read_ptr++]; + + if (vtty->read_ptr == VTTY_BUFFER_SIZE) + vtty->read_ptr = 0; + + VTTY_UNLOCK (vtty); + return (c); +} + +/* Returns TRUE if a character is available in buffer */ +int vtty_is_char_avail (vtty_t * vtty) +{ + int res; + + VTTY_LOCK (vtty); + res = (vtty->read_ptr != vtty->write_ptr); + VTTY_UNLOCK (vtty); + return (res); +} + +/* Put char to vtty */ +void vtty_put_char (vtty_t * vtty, char ch) +{ + switch (vtty->type) { + case VTTY_TYPE_NONE: + break; + + case VTTY_TYPE_TERM: + //printf("put char %c\n",ch); + fwrite (&ch, 1, 1, vtty->fstream); + break; + + case VTTY_TYPE_TCP: + if ((vtty->state == VTTY_STATE_TCP_RUNNING) + && (fwrite (&ch, 1, 1, vtty->fstream) != 1)) { + vm_log (vtty->vm, "VTTY", "%s: put char %d failed (%s)\n", + vtty->name, (int) ch, strerror (errno)); + } + break; + + case VTTY_TYPE_SERIAL: + if (write (vtty->fd, &ch, 1) != 1) { + vm_log (vtty->vm, "VTTY", "%s: put char 0x%x failed (%s)\n", + vtty->name, (int) ch, strerror (errno)); + } + break; + + default: + fprintf (stderr, "vtty_put_char: bad vtty type %d\n", vtty->type); + exit (1); + } +} + +/* Put a buffer to vtty */ +void vtty_put_buffer (vtty_t * vtty, char *buf, size_t len) +{ + size_t i; + + for (i = 0; i < len; i++) + vtty_put_char (vtty, buf[i]); +} + +/* Flush VTTY output */ +void vtty_flush (vtty_t * vtty) +{ + switch (vtty->type) { + case VTTY_TYPE_TERM: + case VTTY_TYPE_TCP: + if (vtty->fstream) + fflush (vtty->fstream); + break; + + case VTTY_TYPE_SERIAL: + fsync (vtty->fd); + break; + } +} + +/* VTTY thread */ +static void *vtty_thread_main (void *arg) +{ + vtty_t *vtty; + struct timeval tv; + int fd, fd_max, res; + fd_set rfds; + + for (;;) { + VTTY_LIST_LOCK (); + + /* Build the FD set */ + FD_ZERO (&rfds); + fd_max = -1; + for (vtty = vtty_list; vtty; vtty = vtty->next) { + if (!vtty->select_fd) + continue; + + if ((fd = *vtty->select_fd) < 0) + continue; + + if (fd > fd_max) + fd_max = fd; + FD_SET (fd, &rfds); + } + VTTY_LIST_UNLOCK (); + + /* Wait for incoming data */ + tv.tv_sec = 0; + tv.tv_usec = 50 * 1000; /* 50 ms */ + res = select (fd_max + 1, &rfds, NULL, NULL, &tv); + + if (res == -1) { + if (errno != EINTR) { + perror ("vtty_thread: select"); + + for (vtty = vtty_list; vtty; vtty = vtty->next) { + fprintf (stderr, " %-15s: %s, FD %d\n", vtty->vm->name, + vtty->name, vtty->fd); + } + } + continue; + } + + /* Examine active FDs and call user handlers */ + VTTY_LIST_LOCK (); + for (vtty = vtty_list; vtty; vtty = vtty->next) { + if (!vtty->select_fd) + continue; + + if ((fd = *vtty->select_fd) < 0) + continue; + + if (FD_ISSET (fd, &rfds)) { + vtty_read_and_store (vtty); + vtty->input_pending = TRUE; + } + + if (vtty->input_pending) { + if (vtty->read_notifier != NULL) + vtty->read_notifier (vtty); + + vtty->input_pending = FALSE; + } + + /* Flush any pending output */ + if (!vtty->managed_flush) + vtty_flush (vtty); + } + VTTY_LIST_UNLOCK (); + } + + return NULL; +} + +/* Initialize the VTTY thread */ +int vtty_init (void) +{ + if (pthread_create (&vtty_thread, NULL, vtty_thread_main, NULL)) { + perror ("vtty: pthread_create"); + return (-1); + } + + return (0); +} diff --git a/tools/virtualmips/dev_vtty.h b/tools/virtualmips/dev_vtty.h new file mode 100644 index 0000000..c6bd574 --- /dev/null +++ b/tools/virtualmips/dev_vtty.h @@ -0,0 +1,128 @@ +/* + * Cisco router simulation platform. + * Copyright (c) 2005,2006 Christophe Fillot (cf@utc.fr) + * + * Virtual console TTY. + */ + + /* + * Copyright (C) yajin 2008 + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + * + */ + +#ifndef __DEV_VTTY_H__ +#define __DEV_VTTY_H__ + +#include +#include + +#include "vm.h" +#include + +/* 4 Kb should be enough for a keyboard buffer */ +#define VTTY_BUFFER_SIZE 4096 + +/* VTTY connection types */ +enum { + VTTY_TYPE_NONE = 0, + VTTY_TYPE_TERM, + VTTY_TYPE_TCP, + VTTY_TYPE_SERIAL, + VTTY_TYPE_USB, +}; + +/* VTTY connection states (for TCP) */ +enum { + VTTY_STATE_TCP_INVALID, /* connection is not working */ + VTTY_STATE_TCP_WAITING, /* waiting for incoming connection */ + VTTY_STATE_TCP_RUNNING, /* character reading/writing ok */ +}; + +/* VTTY input states */ +enum { + VTTY_INPUT_TEXT, + VTTY_INPUT_VT1, + VTTY_INPUT_VT2, + VTTY_INPUT_REMOTE, + VTTY_INPUT_TELNET, + VTTY_INPUT_TELNET_IYOU, + VTTY_INPUT_TELNET_SB1, + VTTY_INPUT_TELNET_SB2, + VTTY_INPUT_TELNET_SB_TTYPE, + VTTY_INPUT_TELNET_NEXT +}; + +/* Commmand line support utility */ +typedef struct vtty_serial_option vtty_serial_option_t; +struct vtty_serial_option { + char *device; + int baudrate, databits, parity, stopbits, hwflow; +}; + +int vtty_parse_serial_option (vtty_serial_option_t * params, char *optarg); + +/* Virtual TTY structure */ +typedef struct virtual_tty vtty_t; +struct virtual_tty { + vm_instance_t *vm; + char *name; + int type, state; + int tcp_port; + int terminal_support; + int input_state; + int input_pending; + int telnet_cmd, telnet_opt, telnet_qual; + int fd, accept_fd, *select_fd; + int managed_flush; + FILE *fstream; + u_char buffer[VTTY_BUFFER_SIZE]; + u_int read_ptr, write_ptr; + pthread_mutex_t lock; + vtty_t *next, **pprev; + void *priv_data; + + /* Read notification */ + void (*read_notifier) (vtty_t *); +}; + +#define VTTY_LOCK(tty) pthread_mutex_lock(&(tty)->lock); +#define VTTY_UNLOCK(tty) pthread_mutex_unlock(&(tty)->lock); + +/* create a virtual tty */ +vtty_t *vtty_create (vm_instance_t * vm, char *name, int type, int tcp_port, + const vtty_serial_option_t * option); + +/* delete a virtual tty */ +void vtty_delete (vtty_t * vtty); + +/* Store a string in the FIFO buffer */ +int vtty_store_str (vtty_t * vtty, char *str); + +/* read a character from the buffer (-1 if the buffer is empty) */ +int vtty_get_char (vtty_t * vtty); + +/* print a character to vtty */ +void vtty_put_char (vtty_t * vtty, char ch); + +/* Put a buffer to vtty */ +void vtty_put_buffer (vtty_t * vtty, char *buf, size_t len); + +/* Flush VTTY output */ +void vtty_flush (vtty_t * vtty); + +/* returns TRUE if a character is available in buffer */ +int vtty_is_char_avail (vtty_t * vtty); + +/* write CTRL+C to buffer */ +int vtty_store_ctrlc (vtty_t *); + +/* Initialize the VTTY thread */ +int vtty_init (void); + +int vtty_is_full (vtty_t * vtty); + +int vtty_bytes (vtty_t * vtty); +#endif diff --git a/tools/virtualmips/device.c b/tools/virtualmips/device.c new file mode 100644 index 0000000..4f7399b --- /dev/null +++ b/tools/virtualmips/device.c @@ -0,0 +1,237 @@ +/* + * Cisco router simulation platform. + * Copyright (c) 2005,2006 Christophe Fillot (cf@utc.fr) + */ + + /* + * Copyright (C) yajin 2008 + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + * + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cpu.h" +#include "vm.h" +#include "mips_memory.h" +#include "device.h" + +#define DEBUG_DEV_ACCESS 0 + +/* Get device by ID */ +struct vdevice *dev_get_by_id (vm_instance_t * vm, u_int dev_id) +{ + if (!vm || (dev_id >= VM_DEVICE_MAX)) + return NULL; + + return (vm->dev_array[dev_id]); +} + +/* Get device by name */ +struct vdevice *dev_get_by_name (vm_instance_t * vm, char *name) +{ + struct vdevice *dev; + + if (!vm) + return NULL; + + for (dev = vm->dev_list; dev; dev = dev->next) + if (!strcmp (dev->name, name)) + return dev; + + return NULL; +} + +/* Device lookup by physical address */ +//struct vdevice *dev_lookup(vm_instance_t *vm,m_pa_t phys_addr,int cached) +struct vdevice *dev_lookup (vm_instance_t * vm, m_pa_t phys_addr) +{ + struct vdevice *dev; + + if (!vm) + return NULL; + + for (dev = vm->dev_list; dev; dev = dev->next) { + // if (cached && !(dev->flags & VDEVICE_FLAG_CACHING)) + // continue; + + if ((phys_addr >= dev->phys_addr) + && ((phys_addr - dev->phys_addr) < dev->phys_len)) + return dev; + } + + return NULL; +} + +/* Find the next device after the specified address */ +//struct vdevice *dev_lookup_next(vm_instance_t *vm,m_pa_t phys_addr, +// struct vdevice *dev_start,int cached) +struct vdevice *dev_lookup_next (vm_instance_t * vm, m_pa_t phys_addr, + struct vdevice *dev_start) +{ + struct vdevice *dev; + + if (!vm) + return NULL; + + dev = (dev_start != NULL) ? dev_start : vm->dev_list; + for (; dev; dev = dev->next) { + //if (cached && !(dev->flags & VDEVICE_FLAG_CACHING)) + // continue; + + if (dev->phys_addr > phys_addr) + return dev; + } + + return NULL; +} + +/* Initialize a device */ +void dev_init (struct vdevice *dev) +{ + memset (dev, 0, sizeof (*dev)); + dev->fd = -1; +} + +/* reset all devices */ +void dev_reset_all (vm_instance_t * vm) +{ + struct vdevice *dev; + for (dev = vm->dev_list; dev; dev = dev->next) { + ASSERT (dev->reset_handler != NULL, + "reset_handler is NULL. name %s\n", dev->name); + dev->reset_handler (vm->boot_cpu, dev); + } +} + +/* Allocate a device */ +struct vdevice *dev_create (char *name) +{ + struct vdevice *dev; + + if (!(dev = malloc (sizeof (*dev)))) { + fprintf (stderr, + "dev_create: insufficient memory to " "create device '%s'.\n", + name); + return NULL; + } + + dev_init (dev); + dev->name = name; + return dev; +} + +/* Remove a device */ +void dev_remove (vm_instance_t * vm, struct vdevice *dev) +{ + if (dev == NULL) + return; + + vm_unbind_device (vm, dev); + + vm_log (vm, "DEVICE", + "Removal of device %s, fd=%d, host_addr=0x%" LL "x, flags=%d\n", + dev->name, dev->fd, (m_uint64_t) dev->host_addr, dev->flags); + + if (dev->flags & VDEVICE_FLAG_REMAP) { + dev_init (dev); + return; + } + + if (dev->fd != -1) { + /* Unmap memory mapped file */ + if (dev->host_addr) { + + vm_log (vm, "MMAP", "unmapping of device '%s', " + "fd=%d, host_addr=0x%" LL "x, len=0x%x\n", + dev->name, dev->fd, (m_uint64_t) dev->host_addr, + dev->phys_len); + munmap ((void *) dev->host_addr, dev->phys_len); + } + + close (dev->fd); + } else { + /* Use of malloc'ed host memory: free it */ + if (dev->host_addr) + free ((void *) dev->host_addr); + } + + /* reinitialize the device to a clean state */ + dev_init (dev); +} + +/* Show properties of a device */ +void dev_show (struct vdevice *dev) +{ + if (!dev) + return; + + printf (" %-18s: 0x%12.12" LL "x (0x%8.8x)\n", dev->name, + dev->phys_addr, dev->phys_len); +} + +/* Show the device list */ +void dev_show_list (vm_instance_t * vm) +{ + struct vdevice *dev; + + printf ("\nVM \"%s\" () Device list:\n", vm->name); + + for (dev = vm->dev_list; dev; dev = dev->next) + dev_show (dev); + + printf ("\n"); +} + +/* Remap a device at specified physical address */ +struct vdevice *dev_remap (char *name, struct vdevice *orig, m_pa_t paddr, + m_uint32_t len) +{ + struct vdevice *dev; + + if (!(dev = dev_create (name))) + return NULL; + + dev->phys_addr = paddr; + dev->phys_len = len; + dev->flags = orig->flags | VDEVICE_FLAG_REMAP; + dev->fd = orig->fd; + dev->host_addr = orig->host_addr; + dev->handler = orig->handler; + //dev->sparse_map = orig->sparse_map; + return dev; +} + +/* Create a RAM device */ +struct vdevice *dev_create_ram (vm_instance_t * vm, char *name, m_pa_t paddr, + m_uint32_t len) +{ + struct vdevice *dev; + + if (!(dev = dev_create (name))) + return NULL; + + dev->phys_addr = paddr; + dev->phys_len = len; + //dev->flags = VDEVICE_FLAG_CACHING; + dev->host_addr = (m_iptr_t) m_memalign (4096, dev->phys_len); + + if (!dev->host_addr) { + free (dev); + return NULL; + } + + vm_bind_device (vm, dev); + return dev; +} diff --git a/tools/virtualmips/device.h b/tools/virtualmips/device.h new file mode 100644 index 0000000..4fe58b6 --- /dev/null +++ b/tools/virtualmips/device.h @@ -0,0 +1,76 @@ +/* + * Cisco router simulation platform. + * Copyright (c) 2005,2006 Christophe Fillot (cf@utc.fr) + */ + + /* + * Copyright (C) yajin 2008 + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + * + */ + +#ifndef __DEVICE_H__ +#define __DEVICE_H__ + +#include + +#include "utils.h" +#include "mips.h" +#include "vm.h" +#include "cpu.h" +/* Device Flags */ +#define VDEVICE_FLAG_NO_MTS_MMAP 0x01 /* Prevent MMAPed access by MTS */ +#define VDEVICE_FLAG_CACHING 0x02 /* Device does support caching */ +#define VDEVICE_FLAG_REMAP 0x04 /* Physical address remapping */ +//#define VDEVICE_FLAG_COW 0x08 /* Copy on write device */ + +#define VDEVICE_PTE_DIRTY 0x01 + +/*device handler */ +typedef void *(*dev_handler_t) (cpu_mips_t * cpu, vdevice_t * dev, + m_uint32_t offset, u_int op_size, u_int op_type, + m_reg_t * data, m_uint8_t * has_set_value); + +typedef void (*dev_reset_handler_t) (cpu_mips_t * cpu, vdevice_t * dev); + +/* Virtual Device */ +struct vdevice { + char *name; + u_int id; + m_pa_t phys_addr; + m_uint32_t phys_len; + m_iptr_t host_addr; + void *priv_data; + int flags; + int fd; + dev_handler_t handler; + dev_reset_handler_t reset_handler; + struct vdevice *next, **pprev; +}; + +/* device access function */ +static forced_inline + void *dev_access_fast (cpu_mips_t * cpu, u_int dev_id, m_uint32_t offset, + u_int op_size, u_int op_type, m_reg_t * data, m_uint8_t * has_set_value) +{ + struct vdevice *dev = cpu->vm->dev_array[dev_id]; + + if (unlikely (!dev)) { + cpu_log (cpu, "dev_access_fast", + "null handler (dev_id=%u,offset=0x%x)\n", dev_id, offset); + return NULL; + } + return (dev->handler (cpu, dev, offset, op_size, op_type, data, + has_set_value)); +} + +struct vdevice *dev_lookup (vm_instance_t * vm, m_pa_t phys_addr); +void dev_init (struct vdevice *dev); +struct vdevice *dev_create (char *name); +struct vdevice *dev_create_ram (vm_instance_t * vm, char *name, m_pa_t paddr, + m_uint32_t len); +void dev_reset_all (vm_instance_t * vm); + +#endif diff --git a/tools/virtualmips/gdb_interface.c b/tools/virtualmips/gdb_interface.c new file mode 100644 index 0000000..27919e6 --- /dev/null +++ b/tools/virtualmips/gdb_interface.c @@ -0,0 +1,723 @@ +/* + * Copyright (C) 1996-1998 by the Board of Trustees + * of Leland Stanford Junior University. + * + * This file is part of the SimOS distribution. + * See LICENSE file for terms of the license. + * + */ + + /* + * Copyright (C) yajin 2008 + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + * + */ + +/*GDB interface for virtualmips based on simos*/ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "vm.h" +#include "mips.h" +#include "gdb_interface.h" +#include "utils.h" +#include "debug.h" + +#define GDB_NUM_REGS 72 //general cpu register and cp0 reegister +#define VCONT "vCont" +#define QSYMBOL "qSymbol" +#define QC "qC" +#define QOFFSETS "qOffsets" + +int delete_breakpoint (vm_instance_t * vm, m_uint32_t addr, int len) +{ + virtual_breakpoint_t *tmp, *prev = 0; + + tmp = vm->breakpoint_head; + + // addr = SIGN_EXTEND(32,addr); + while (tmp) { + if (tmp->addr == addr) { + /*find it */ + if (prev) + prev->next = tmp->next; + + if (vm->breakpoint_head == tmp) + vm->breakpoint_head = tmp->next; + + if (vm->breakpoint_tail == tmp) + vm->breakpoint_tail = prev; + + if (tmp->save) + free (tmp->save); + free (tmp); + + goto exit; + } + + prev = tmp; + tmp = tmp->next; + } + + exit: + return SUCCESS; +} + +virtual_breakpoint_t *alloc_breakpoint (vm_instance_t * vm, m_uint32_t addr, + char *save, int len) +{ + virtual_breakpoint_t *tmp; + + tmp = malloc (sizeof (virtual_breakpoint_t)); + if (!tmp) + return NULL; + + memset (tmp, 0, sizeof (*tmp)); + tmp->addr = (addr); + + if (save) { + tmp->save = malloc (strlen (save) + 1); + strcpy (tmp->save, save); + } + //tmp->cpuno = cpuno; + tmp->len = len; + tmp->next = 0; + + return tmp; +} + +int insert_breakpoint (vm_instance_t * vm, virtual_breakpoint_t * new) +{ + virtual_breakpoint_t *tmp; + + if (vm->breakpoint_head == 0) { + vm->breakpoint_tail = vm->breakpoint_head = new; + } else { + tmp = vm->breakpoint_head; + + while (tmp) { + if (tmp->addr == new->addr) { + /*the same one */ + if (new->save) + free (new->save); + free (new); + goto exit; + } + + tmp = tmp->next; + } + + vm->breakpoint_tail->next = new; + vm->breakpoint_tail = new; + } + + exit: + return SUCCESS; +} + +static int fromhex (int a) +{ + if (a >= '0' && a <= '9') + return a - '0'; + else if (a >= 'a' && a <= 'f') + return a - 'a' + 10; + else { + fprintf (stderr, "Request contains invalid hex digit : %s %d\n", + __FILE__, __LINE__); + return 0; + } +} + +/* Convert number NIB to a hex digit. */ + +static int tohex (int nib) +{ + if (nib < 10) + return '0' + nib; + else + return 'a' + nib - 10; +} + +#if 0 +static int bin2hex (const char *bin, char *hex, int count) +{ + int i; + /* May use a length, or a nul-terminated string as input. */ + if (count == 0) + count = strlen (bin); + + for (i = 0; i < count; i++) { + *hex++ = tohex ((*bin >> 4) & 0xf); + *hex++ = tohex (*bin++ & 0xf); + } + *hex = 0; + return i; +} + +#endif + +static void convert_int_to_ascii (char *from, char *to, int n) +{ + int nib; + char ch; + while (n--) { + ch = *from++; + nib = ((ch & 0xf0) >> 4) & 0x0f; + *to++ = tohex (nib); + nib = ch & 0x0f; + *to++ = tohex (nib); + } + *to++ = 0; +} + +/***************************************************************** + * readchar + * Returns next char from remote GDB. -1 if error. + *****************************************************************/ +static int readchar (int fd) +{ + static char buf[BUFSIZ]; + static int bufcnt = 0; + static char *bufp; + + if (bufcnt-- > 0) + return *bufp++ & 0x7f; + + bufcnt = read (fd, buf, BUFSIZ); + if (bufcnt <= 0) { + printf ("Simdebug readchar"); + return -1; + } + + bufp = buf; + bufcnt--; + return *bufp++ & 0x7f; +} + +/***************************************************************** + * getpkt + * + * Read a packet from the remote machine, with error checking, + * and store it in BUF. Returns length of packet, or negative if error. + *****************************************************************/ +static int getpkt (int fd, char *buf) +{ + char *bp; + unsigned char csum, c1, c2; + int c; + + bp = buf; + while (1) { + csum = 0; + + while (1) { + c = readchar (fd); + if (c == '$') + break; + if (c < 0) + goto errout; + } + + bp = buf; + while (1) { + c = readchar (fd); + if (c < 0) + goto errout; + + if (c == '#') + break; + + *bp++ = c; + csum += c; + } + *bp = 0; + + c = readchar (fd); + if (c < 0) + goto errout; + c1 = fromhex (c); + + c = readchar (fd); + if (c < 0) + goto errout; + c2 = fromhex (c); + + if (csum == (c1 << 4) + c2) + break; + + if (write (fd, "-", 1) < 0) + return -1; + } + + if (write (fd, "+", 1) < 0) + return -1; + return bp - buf; + + errout: + return -1; +} + +static void write_ok (char *buf) +{ + buf[0] = 'O'; + buf[1] = 'K'; + buf[2] = '\0'; +} + +static void write_enn (char *buf) +{ + buf[0] = 'E'; +#if 0 + buf[1] = 'N'; + buf[2] = 'N'; +#endif + + buf[1] = '0'; + buf[2] = '1'; + buf[3] = '\0'; +} + +/* Send a packet to the remote machine, with error checking. + The data of the packet is in BUF. Returns >= 0 on success, -1 otherwise. */ + +static int putpkt (int fd, char *buf) +{ + //printf("putpkt\n"); + int i; + unsigned char csum = 0; + char buf2[2000]; + char buf3[1]; + int cnt = strlen (buf); + char *p; + + /* Copy the packet into buffer BUF2, encapsulating it + * and giving it a checksum. */ + + p = buf2; + *p++ = '$'; + + for (i = 0; i < cnt; i++) { + csum += buf[i]; + *p++ = buf[i]; + } + + *p++ = '#'; + *p++ = tohex ((csum >> 4) & 0xf); + *p++ = tohex (csum & 0xf); + + /* Send it over and over until we get a positive ack. */ + + do { + int cc; + + if (write (fd, buf2, p - buf2) != p - buf2) { + printf ("putpkt(write)\n"); + goto errout; + } + + cc = read (fd, buf3, 1); + if (cc <= 0) { + printf ("putpkt(read)\n"); + goto errout; + } + } + while (buf3[0] != '+'); + + return 1; /* Success! */ + + errout: + return -1; +} + +static void attach_gdb (vm_instance_t * vm) +{ + struct sockaddr_in sockaddr1; + unsigned int tmp; + int gdb_fd; + + if (!vm->gdb_debug_from_poll) + printf ("Waiting for gdb on port %d.\n", vm->gdb_port); + + tmp = sizeof (sockaddr1); + gdb_fd = + accept (vm->gdb_listen_sock, (struct sockaddr *) &sockaddr1, &tmp); + vm->gdb_interact_sock = gdb_fd; + if (gdb_fd == -1) { + printf ("Debugger accept failed\n"); + return; + } + + if (!vm->gdb_debug_from_poll) + printf ("GDB attached. Enjoy yourself!\n"); + + /* Tell TCP not to delay small packets. This greatly speeds up + * interactive response. */ + + tmp = 1; + setsockopt (gdb_fd, SOL_SOCKET, SO_KEEPALIVE, (char *) &tmp, + sizeof (tmp)); + + tmp = 1; + setsockopt (gdb_fd, IPPROTO_TCP, TCP_NODELAY, (char *) &tmp, + sizeof (tmp)); + + // int save_fcntl_flags; +#if defined(F_SETFL) && defined (FASYNC) + save_fcntl_flags = fcntl (gdb_fd, F_GETFL, 0); + fcntl (gdb_fd, F_SETFL, save_fcntl_flags | FASYNC); +#if defined (F_SETOWN) + fcntl (gdb_fd, F_SETOWN, getpid ()); +#endif +#endif + + signal (SIGIO, SIG_IGN); + + // return gdb_fd; +} + +#define MAX_XFER (8*1024) +#define WORD_SZ 4 +#define BYTE_SZ 1 + +int debug_read_memory (cpu_mips_t * cpu, m_uint32_t vaddr, unsigned int len, + char *buf) +{ + //void *haddr=NULL; + //m_uint32_t exc; + //m_uint32_t data; + //m_uint8_t has_set_value=FALSE; + + char readout_buf[MAX_XFER]; + if (len > MAX_XFER) { + fprintf (stderr, "read_memory: too many bytes requested"); + } + assert (len <= MAX_XFER); + + int reallen = len; + char *cur = readout_buf; + int i = 0; + + //We read one byte once to avoid align problem + for (i = 0; i < (reallen / BYTE_SZ); i++) { + cpu->mips_mts_gdb_lb (cpu, vaddr, cur); + + cur += BYTE_SZ; + vaddr += BYTE_SZ; + } + + convert_int_to_ascii (readout_buf, buf, len); + return SUCCESS; + +} + +int forced_inline cpu_hit_breakpoint (vm_instance_t * vm, m_uint32_t vaddr) +{ + virtual_breakpoint_t *tmp = vm->breakpoint_head; + static char cmd_buf[BUFSIZ + 1]; + + while (tmp) { + if (tmp->addr == vaddr) { + sprintf (cmd_buf, "S%02x", SIGTRAP); + if (putpkt (vm->gdb_interact_sock, cmd_buf) < 0) { + /* the connection was terminated prematurely. Reset */ + close (vm->gdb_interact_sock); + vm->gdb_interact_sock = -1; + vm->mipsy_debug_mode = 0; //we do not debug anymore + printf ("Remote debugger connection lost, continuing...\n"); + return FAILURE; + } + return SUCCESS; + } + tmp = tmp->next; + } + return FAILURE; +} + +/* Convert hex digit A to a number. */ + +Simdebug_result Simdebug_run (vm_instance_t * vm, int sig) +{ + static char cmd_buf[BUFSIZ + 1]; + char *b; + int i = 0; + Simdebug_result ret = SD_CONTINUE; + + if (vm->gdb_interact_sock <= 0) { + attach_gdb (vm); + if (vm->gdb_interact_sock < 0) { + return SD_CONTINUE; /* could not get debugger */ + } + vm->gdb_debug_from_poll = 0; /* whether or not we entered from poll doesn't + * matter this time, but we'd better reset it + * before next time this function runs + */ + } else { + /* reestablish an old connection. We might get here either + * for internal reasons (hitting a breakpoint) or for external + * reasons (gdb sent us a ^C). If external, we need to swallow + * the break packet. Then in either case, let GDB know why + * we stopped. + */ + + if (vm->gdb_debug_from_poll) { + vm->gdb_debug_from_poll = 0; + int cc; + char c; + + cc = read (vm->gdb_interact_sock, &c, 1); + + if (cc != 1 || c != '\003') { + fprintf (stderr, "input_interrupt, cc = %d c = %d\n", cc, c); + goto errout; + } + + sig = SIGINT; + /* Inform the remote debugger we have entered debugging mode. */ + // sprintf (cmd_buf, "S%02x%02x", sig, debug_cpuno); + sprintf (cmd_buf, "S%02x", sig); + if (putpkt (vm->gdb_interact_sock, cmd_buf) < 0) + goto errout; + + } + } + + while (1) { + char ch; + i = 0; + int pkg_len = 0; + + if ((pkg_len = getpkt (vm->gdb_interact_sock, cmd_buf)) <= 0) + goto errout; + ch = cmd_buf[i++]; + SIM_DEBUG (('g', "gdb command %c \n", ch)); + //printf("---\n gdb command %s\n",cmd_buf); + + switch (ch) { + case 'c': + ret = SD_CONTINUE; + goto out; + case 'g': //read register + { + m_uint32_t r = 0; + b = cmd_buf; + for (i = 0; i < GDB_NUM_REGS; i++) { + //FIXME: find the mapping from register index to register of cpu and cpu0 of gdb + if (vm->boot_cpu->reg_get (vm->boot_cpu, i, + &r) == FAILURE) + r = 0; + /* + * flip the bytes around + */ + r = htovm32 (r); //gdb likes the data of target machine format + convert_int_to_ascii ((char *) &r, b, 4); + + b += 8; + } + *b = 0; + break; + } + + case 'H': + write_ok (cmd_buf); + break; + case 'm': + { + m_uint32_t memaddr; + unsigned int len; + + if (sscanf (cmd_buf + 1, "%x,%x", &memaddr, &len) != 2) { + write_enn (cmd_buf); + } else { + + if (debug_read_memory (vm->boot_cpu, memaddr, len, + cmd_buf) != SUCCESS) + write_enn (cmd_buf); + } + break; + } + + case 'p': + { + m_uint32_t r, index = 0; + b = cmd_buf; + if (sscanf (cmd_buf + 1, "%x", &index) != 1) + write_enn (cmd_buf); + else { + // index=vmtoh32(index); + if (vm->boot_cpu->reg_get (vm->boot_cpu, index, + &r) == FAILURE) + r = 0; + /* + * flip the bytes around + */ + r = htovm32 (r); //gdb likes the data of target machine format + convert_int_to_ascii ((char *) &r, b, 4); + //*(r+4)=0; + //*(r+5)=0; + //*(r+6)=0; + //*(r+7)=0; + + } + + } + break; + + case 'v': + { + char *cmd_tmp; + + cmd_tmp = cmd_buf; + + if (strncmp (cmd_buf, VCONT, strlen (VCONT)) != 0) + write_enn (cmd_buf); + else { + cmd_tmp += strlen (VCONT); + if (';' == cmd_tmp[0]) { + cmd_tmp++; + if ('c' == cmd_tmp[0]) { + ret = SD_CONTINUE; + goto out; + } else if ('s' == cmd_tmp[0]) { + /*single step */ + int cpuno; + cpuno = 0; + + ret = cpuno; + + goto out; + } else + write_enn (cmd_buf); + } else if ('?' == (cmd_tmp)[0]) { + /*query */ + strcpy (cmd_buf, VCONT ";c"); + } else + write_enn (cmd_buf); + } + } + break; + + case 'q': + { + if (strncmp (cmd_buf, QSYMBOL, strlen (QSYMBOL)) == 0) + write_ok (cmd_buf); + else if (strncmp (cmd_buf, QC, strlen (QC)) == 0) { + strcpy (cmd_buf, "QC0"); + } else if (strncmp (cmd_buf, QOFFSETS, + strlen (QOFFSETS)) == 0) { + strcpy (cmd_buf, "Text=0;Data=0;Bss=0"); + } else { + write_enn (cmd_buf); + } + + } + break; + + case 's': + case 'S': + ret = SD_NEXTI_ANYCPU; + goto out; + + case 'z': + { + m_uint32_t addr; + int len; + if ('0' == (cmd_buf + 1)[0]) { + //memory breakpoint + if (sscanf (cmd_buf + 3, "%x,%x", &addr, &len) != 2) { + + write_enn (cmd_buf); + } + + else { + if (delete_breakpoint (vm, addr, len) != SUCCESS) + write_enn (cmd_buf); + else { + + write_ok (cmd_buf); + } + + } + + } + + else + write_enn (cmd_buf); + + } + break; + + case 'Z': + { + m_uint32_t addr; + int len; + if ('0' == (cmd_buf + 1)[0]) { + //memory breakpoint + if (sscanf (cmd_buf + 3, "%x,%x", &addr, &len) != 2) { + + write_enn (cmd_buf); + + } + + else { + + virtual_breakpoint_t *tmp = + alloc_breakpoint (vm, addr, 0, len); + insert_breakpoint (vm, tmp); + write_ok (cmd_buf); + + } + } else + write_enn (cmd_buf); + + } + break; + case '?': + sprintf (cmd_buf, "S%02x", sig); + break; + default: + write_enn (cmd_buf); + break; + + } + //printf("send %s\n",cmd_buf); + if (putpkt (vm->gdb_interact_sock, cmd_buf) < 0) + goto errout; + + } +out: + return ret; +errout: + /* the connection was terminated prematurely. Reset */ + close (vm->gdb_interact_sock); + vm->gdb_interact_sock = -1; + printf ("Remote debugger connection lost, continuing...\n"); + return SD_CONTINUE; +} + +void bad_memory_access_gdb (vm_instance_t * vm) +{ + static char cmd_buf[BUFSIZ + 1]; + + vm->mipsy_break_nexti = MIPS_BREAKANYCPU; + sprintf (cmd_buf, "S%02x", SIGTRAP); + if (putpkt (vm->gdb_interact_sock, cmd_buf) < 0) { + /* the connection was terminated prematurely. Reset */ + close (vm->gdb_interact_sock); + vm->gdb_interact_sock = -1; + vm->mipsy_debug_mode = 0; //we do not debug anymore + printf ("Remote debugger connection lost, continuing...\n"); + } +} diff --git a/tools/virtualmips/gdb_interface.h b/tools/virtualmips/gdb_interface.h new file mode 100644 index 0000000..897b236 --- /dev/null +++ b/tools/virtualmips/gdb_interface.h @@ -0,0 +1,31 @@ + /* + * Copyright (C) yajin 2008 + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + * + */ + +#ifndef __GDB_INTERFACE_H__ +#define __GDB_INTERFACE_H__ +#include "utils.h" +#include "mips.h" + +typedef enum Simdebug_result { + SD_CONTINUE = -2, + SD_NEXTI_ANYCPU = -1 +} Simdebug_result; + +typedef struct virtualBreakpoint { + m_uint32_t addr; + char *save; + //int cpuno; + int len; /*break point instruction len */ + struct virtualBreakpoint *next; +} virtual_breakpoint_t; + +int cpu_hit_breakpoint (vm_instance_t * vm, m_uint32_t vaddr); + +Simdebug_result Simdebug_run (vm_instance_t * vm, int sig); +void bad_memory_access_gdb (vm_instance_t * vm); +#endif diff --git a/tools/virtualmips/jz4740/jz4740.c b/tools/virtualmips/jz4740/jz4740.c new file mode 100644 index 0000000..2e0a6ce --- /dev/null +++ b/tools/virtualmips/jz4740/jz4740.c @@ -0,0 +1,105 @@ + /* + * Copyright (C) yajin 2008 + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + * + */ + +#include +#include +#include +#include + +#include "utils.h" +#include "mips.h" +#include "vm.h" +#include "cpu.h" +#include "mips_exec.h" +#include "debug.h" + +#include "jz4740.h" +#include "pavo.h" +#include "device.h" + +int jz4740_boot_from_nandflash (vm_instance_t * vm) +{ + struct vdevice *dev; + unsigned char *page_addr; + int i; + + pavo_t *pavo; + if (vm->type == VM_TYPE_PAVO) { + pavo = VM_PAVO (vm); + } else + ASSERT (0, "Error vm type\n"); + + /*get ram device */ + dev = dev_lookup (vm, 0x0); + assert (dev != NULL); + assert (dev->host_addr != 0); + /*copy 8K nand flash data to 8K RAM */ + for (i = 0; i < (0x2000 / NAND_FLASH_1G_PAGE_DATA_SIZE); i++) { + page_addr = + get_nand_flash_page_ptr (i, pavo->nand_flash->flash_map[0]); + memcpy ((unsigned char *) dev->host_addr + + NAND_FLASH_1G_PAGE_DATA_SIZE * i, page_addr, + NAND_FLASH_1G_PAGE_DATA_SIZE); + } + + return (0); + +} + +int jz4740_reset (vm_instance_t * vm) +{ + cpu_mips_t *cpu; + m_va_t kernel_entry_point; + vm_suspend (vm); + /* Check that CPU activity is really suspended */ + if (cpu_group_sync_state (vm->cpu_group) == -1) { + vm_error (vm, "unable to sync with system CPUs.\n"); + return (-1); + } + + /* Reset the boot CPU */ + cpu = (vm->boot_cpu); + mips_reset (cpu); + + /*set configure register */ + cpu->cp0.config_usable = 0x83; /* configure sel 0 1 7 is valid */ + cpu->cp0.config_reg[0] = JZ4740_CONFIG0; + cpu->cp0.config_reg[1] = JZ4740_CONFIG1; + cpu->cp0.config_reg[7] = JZ4740_CONFIG7; + + /*set PC and PRID */ + cpu->cp0.reg[MIPS_CP0_PRID] = JZ4740_PRID; + cpu->cp0.tlb_entries = JZ4740_DEFAULT_TLB_ENTRYNO; + cpu->pc = JZ4740_ROM_PC; + /*reset all devices */ + dev_reset_all (vm); + +#ifdef _USE_JIT_ + /*if jit is used. flush all jit buffer */ + if (vm->jit_use) + mips_jit_flush (cpu, 0); +#endif + /*If we boot from elf kernel image, load the image and set pc to elf entry */ + if (vm->boot_method == BOOT_ELF) { + if (mips_load_elf_image (cpu, vm->kernel_filename, + &kernel_entry_point) == -1) + return (-1); + cpu->pc = kernel_entry_point; + } else if (vm->boot_method == BOOT_BINARY) { + if (jz4740_boot_from_nandflash (vm) == -1) + return (-1); + } + +/* Launch the simulation */ + printf ("VM '%s': starting simulation (CPU0 PC=0x%" LL + "x), JIT %sabled.\n", vm->name, cpu->pc, vm->jit_use ? "en" : "dis"); + vm->status = VM_STATUS_RUNNING; + cpu_start (vm->boot_cpu); + return (0); + +} diff --git a/tools/virtualmips/jz4740/jz4740.h b/tools/virtualmips/jz4740/jz4740.h new file mode 100644 index 0000000..4c9ee19 --- /dev/null +++ b/tools/virtualmips/jz4740/jz4740.h @@ -0,0 +1,760 @@ + /* + * Copyright (C) yajin 2008 + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + * + */ + + /*JZ4740 Header file */ + +#ifndef __JZ4740_H__ +#define __JZ4740_H__ + +#include "types.h" + +/*virtual address and physical address*/ +typedef m_uint32_t m_va_t; +typedef m_uint32_t m_pa_t; +typedef m_uint32_t m_reg_t; +typedef m_int32_t m_ireg_t; +typedef m_uint32_t m_cp0_reg_t; + +#define DATA_WIDTH 32 /*64 */ +#define LL + +/*JZ4740 use soft fpu*/ +#define SOFT_FPU 1 + +/*Guest endian*/ +#define GUEST_BYTE_ORDER ARCH_LITTLE_ENDIAN +#ifndef GUEST_BYTE_ORDER +#error Please define guest architecture in utils.h! +#endif + +/* Host to VM conversion functions */ +#if HOST_BYTE_ORDER == GUEST_BYTE_ORDER +#define htovm16(x) (x) +#define htovm32(x) (x) +#define htovm64(x) (x) + +#define vmtoh16(x) (x) +#define vmtoh32(x) (x) +#define vmtoh64(x) (x) +#elif HOST_BYTE_ORDER==ARCH_LITTLE_ENDIAN //host:little guest:big +#define htovm16(x) (htons(x)) +#define htovm32(x) (htonl(x)) +#define htovm64(x) (swap64(x)) + +#define vmtoh16(x) (ntohs(x)) +#define vmtoh32(x) (ntohl(x)) +#define vmtoh64(x) (swap64(x)) +#else //host:big guest:little + +#define htovm16(x) (ntohs(x)) +#define htovm32(x) (ntohl(x)) +#define htovm64(x) (swap64(x)) + +#define vmtoh16(x) (htons(x)) +#define vmtoh32(x) (htonl(x)) +#define vmtoh64(x) (swap64(x)) +#endif + +#define JZ4740_CONFIG0 0x80000082 +#define JZ4740_CONFIG1 0x3E613080 /*CACHE (128SET*32 BYTES*2 WAY)= 8K */ +#define JZ4740_CONFIG7 0x0 + +#define JZ4740_ROM_PC 0x80000004 +#define JZ4740_PRID 0x0ad0024f /*jz4740 prid */ +#define JZ4740_DEFAULT_TLB_ENTRYNO 32 /*32 pairs */ + +/*------------------------REG DEFINE---------------------------------*/ +#define NAND_DATAPORT 0x18000000 +#define NAND_ADDRPORT 0x18010000 +#define NAND_COMMPORT 0x18008000 + +/*FOR CS8900*/ +#define CS8900_IO_BASE 0x8000000 +#define CS8900_SIZE 0x10 +#define CS8900_DEFAULT_IRQ 107 +#define CS8900_GPIO_GROUP 1 +/* GPIO is in 4 groups. 32 per group*/ +/* + +48-79 0 +80-111 1 +112-143 2 +144-175 3 + +so irq 107 is in gpio group 1 +*/ + +/*---------------------GPIO----------------------------------*/ +#define JZ4740_GPIO_BASE 0x10010000 +#define JZ4740_GPIO_SIZE 0x388 +//n = 0,1,2,3 +#define GPIO_PXPIN(n) ( (0x00 + (n)*0x100)) /* PIN Level Register */ +#define GPIO_PXDAT(n) ((0x10 + (n)*0x100)) /* Port Data Register */ +#define GPIO_PXDATS(n) ( (0x14 + (n)*0x100)) /* Port Data Set Register */ +#define GPIO_PXDATC(n) ( (0x18 + (n)*0x100)) /* Port Data Clear Register */ +#define GPIO_PXIM(n) ( (0x20 + (n)*0x100)) /* Interrupt Mask Register */ +#define GPIO_PXIMS(n) ( (0x24 + (n)*0x100)) /* Interrupt Mask Set Reg */ +#define GPIO_PXIMC(n) ( (0x28 + (n)*0x100)) /* Interrupt Mask Clear Reg */ +#define GPIO_PXPE(n) ((0x30 + (n)*0x100)) /* Pull Enable Register */ +#define GPIO_PXPES(n) ( (0x34 + (n)*0x100)) /* Pull Enable Set Reg. */ +#define GPIO_PXPEC(n) ( (0x38 + (n)*0x100)) /* Pull Enable Clear Reg. */ +#define GPIO_PXFUN(n) ( (0x40 + (n)*0x100)) /* Function Register */ +#define GPIO_PXFUNS(n) ( (0x44 + (n)*0x100)) /* Function Set Register */ +#define GPIO_PXFUNC(n) ( (0x48 + (n)*0x100)) /* Function Clear Register */ +#define GPIO_PXSEL(n) ( (0x50 + (n)*0x100)) /* Select Register */ +#define GPIO_PXSELS(n) ( (0x54 + (n)*0x100)) /* Select Set Register */ +#define GPIO_PXSELC(n) ( (0x58 + (n)*0x100)) /* Select Clear Register */ +#define GPIO_PXDIR(n) ( (0x60 + (n)*0x100)) /* Direction Register */ +#define GPIO_PXDIRS(n) ( (0x64 + (n)*0x100)) /* Direction Set Register */ +#define GPIO_PXDIRC(n) ( (0x68 + (n)*0x100)) /* Direction Clear Register */ +#define GPIO_PXTRG(n) ( (0x70 + (n)*0x100)) /* Trigger Register */ +#define GPIO_PXTRGS(n) ( (0x74 + (n)*0x100)) /* Trigger Set Register */ +#define GPIO_PXTRGC(n) ( (0x78 + (n)*0x100)) /* Trigger Set Register */ +#define GPIO_PXFLG(n) ( (0x80 + (n)*0x100)) /* Port Flag Register */ +/* According to datasheet, it is 0x14. I think it shoud be 0x84*/ +#define GPIO_PXFLGC(n) ( (0x84 + (n)*0x100)) /* Port Flag clear Register */ + +#define JZ4740_GPIO_INDEX_MAX 0xe2 /*0x388/4 */ + +/*---------------------UART----------------------------------*/ + +#define JZ4740_UART_SIZE 0x302c + +#define JZ4740_UART0_BASE 0x10030000 +#define JZ4740_UART0_SIZE 0x2c + +#define JZ4740_UART1_BASE 0x10031000 +#define JZ4740_UART1_SIZE 0x2c +#define JZ4740_UART2_BASE 0x10032000 +#define JZ4740_UART2_SIZE 0x2c +#define JZ4740_UART3_BASE 0x10033000 +#define JZ4740_UART3_SIZE 0x2c + +#define JZ4740_UART_BASE JZ4740_UART0_BASE + +#define UART_RBR (0x00) +#define UART_THR (0x00) +#define UART_DLLR (0x00) +#define UART_DLHR (0x04) +#define UART_IER (0x04) +#define UART_IIR (0x08) +#define UART_FCR (0x08) +#define UART_LCR (0x0C) +#define UART_MCR (0x10) +#define UART_LSR (0x14) +#define UART_MSR (0x18) +#define UART_SPR (0x1C) +#define UART_ISR (0x20) +#define UART_UMR (0x24) +#define UART_UACR (0x28) + +#define JZ4740_UART_INDEX_MAX 0xb //0x02c/4 +#define JZ4740_UART_NUMBER 2 //we emulates two uarts + +#define UART_IER_RDRIE 0x01 +#define UART_IER_TDRIE 0x02 +#define UART_IER_RLSIE 0x04 +#define UART_IER_MSIE 0x08 +#define UART_IER_RTOIE 0x10 + +#define UART_FCR_FME 0x1 +#define UART_FCR_RFRT 0x2 +#define UART_FCR_TFRT 0x4 +#define UART_FCR_DME 0x8 +#define UART_FCR_UME 0x10 +#define UART_FCR_RDTR 0xC0 +#define UART_FCR_RDTR_SHIFT 0x6 + +#define UART_LSR_DRY 0x1 +#define UART_LSR_OVER 0x2 +#define UART_LSR_PARER 0x4 +#define UART_LSR_FMER 0x8 +#define UART_LSR_BI 0x10 +#define UART_LSR_TDRQ 0x20 +#define UART_LSR_TEMP 0x40 +#define UART_LSR_FIFOE 0x80 + +/*-------------------PLL----------------------*/ + +#define JZ4740_CPM_BASE 0x10000000 +#define JZ4740_CPM_SIZE 0X70 + +#define CPM_CPCCR (0x00) +#define CPM_CPPCR (0x10) +#define CPM_I2SCDR (0x60) +#define CPM_LPCDR (0x64) +#define CPM_MSCCDR (0x68) +#define CPM_UHCCDR (0x6C) + +#define CPM_LCR (0x04) +#define CPM_CLKGR (0x20) +#define CPM_SCR (0x24) + +#define CPM_HCR (0x30) +#define CPM_HWFCR (0x34) +#define CPM_HRCR (0x38) +#define CPM_HWCR (0x3c) +#define CPM_HWSR (0x40) +#define CPM_HSPR (0x44) + +#define JZ4740_CPM_INDEX_MAX 0X1c /*0X70/4 */ + +/*-------------------EMC----------------------*/ +#define JZ4740_EMC_BASE 0x13010000 +#define JZ4740_EMC_SIZE 0xa400 /*FROM A000-A3FF is mode register */ + +#define EMC_BCR ( 0x0) /* BCR */ +#define EMC_SMCR0 ( 0x10) /* Static Memory Control Register 0 */ +#define EMC_SMCR1 ( 0x14) /* Static Memory Control Register 1 */ +#define EMC_SMCR2 ( 0x18) /* Static Memory Control Register 2 */ +#define EMC_SMCR3 ( 0x1c) /* Static Memory Control Register 3 */ +#define EMC_SMCR4 ( 0x20) /* Static Memory Control Register 4 */ +#define EMC_SACR0 ( 0x30) /* Static Memory Bank 0 Addr Config Reg */ +#define EMC_SACR1 ( 0x34) /* Static Memory Bank 1 Addr Config Reg */ +#define EMC_SACR2 ( 0x38) /* Static Memory Bank 2 Addr Config Reg */ +#define EMC_SACR3 ( 0x3c) /* Static Memory Bank 3 Addr Config Reg */ +#define EMC_SACR4 ( 0x40) /* Static Memory Bank 4 Addr Config Reg */ + +#define EMC_NFCSR ( 0x050) /* NAND Flash Control/Status Register */ +#define EMC_NFECR ( 0x100) /* NAND Flash ECC Control Register */ +#define EMC_NFECC ( 0x104) /* NAND Flash ECC Data Register */ +#define EMC_NFPAR0 ( 0x108) /* NAND Flash RS Parity 0 Register */ +#define EMC_NFPAR1 ( 0x10c) /* NAND Flash RS Parity 1 Register */ +#define EMC_NFPAR2 ( 0x110) /* NAND Flash RS Parity 2 Register */ +#define EMC_NFINTS ( 0x114) /* NAND Flash Interrupt Status Register */ +#define EMC_NFINTE ( 0x118) /* NAND Flash Interrupt Enable Register */ +#define EMC_NFERR0 ( 0x11c) /* NAND Flash RS Error Report 0 Register */ +#define EMC_NFERR1 ( 0x120) /* NAND Flash RS Error Report 1 Register */ +#define EMC_NFERR2 ( 0x124) /* NAND Flash RS Error Report 2 Register */ +#define EMC_NFERR3 ( 0x128) /* NAND Flash RS Error Report 3 Register */ + +#define EMC_DMCR ( 0x80) /* DRAM Control Register */ +#define EMC_RTCSR ( 0x84) /* Refresh Time Control/Status Register */ +#define EMC_RTCNT ( 0x88) /* Refresh Timer Counter */ +#define EMC_RTCOR ( 0x8c) /* Refresh Time Constant Register */ +#define EMC_DMAR0 ( 0x90) /* SDRAM Bank 0 Addr Config Register */ + +#define EMC_SDMR0 ( 0xa000) /* Mode Register of SDRAM bank 0 */ +/*has other register*/ + +#define JZ4740_EMC_INDEX_MAX 0x4b /*0x12c/4 */ + +/*-----------------------RTC-------------------------------------*/ + +#define JZ4740_RTC_BASE 0x10003000 +#define JZ4740_RTC_SIZE 0x38 +#define RTC_RCR ( 0x00) /* RTC Control Register */ +#define RTC_RSR ( 0x04) /* RTC Second Register */ +#define RTC_RSAR ( 0x08) /* RTC Second Alarm Register */ +#define RTC_RGR ( 0x0c) /* RTC Regulator Register */ + +#define RTC_HCR ( 0x20) /* Hibernate Control Register */ +#define RTC_HWFCR ( 0x24) /* Hibernate Wakeup Filter Counter Reg */ +#define RTC_HRCR ( 0x28) /* Hibernate Reset Counter Register */ +#define RTC_HWCR ( 0x2c) /* Hibernate Wakeup Control Register */ +#define RTC_HWRSR ( 0x30) /* Hibernate Wakeup Status Register */ +#define RTC_HSPR ( 0x34) /* Hibernate Scratch Pattern Register */ + +#define RTC_RCR_WRDY_BIT 7 +#define RTC_RCR_WRDY (1 << 7) /* Write Ready Flag */ +#define RTC_RCR_1HZ_BIT 6 +#define RTC_RCR_1HZ (1 << RTC_RCR_1HZ_BIT) /* 1Hz Flag */ +#define RTC_RCR_1HZIE (1 << 5) /* 1Hz Interrupt Enable */ +#define RTC_RCR_AF_BIT 4 +#define RTC_RCR_AF (1 << RTC_RCR_AF_BIT) /* Alarm Flag */ +#define RTC_RCR_AIE (1 << 3) /* Alarm Interrupt Enable */ +#define RTC_RCR_AE (1 << 2) /* Alarm Enable */ +#define RTC_RCR_RTCE (1 << 0) /* RTC Enable */ + + /* RTC Regulator Register */ +#define RTC_RGR_LOCK (1 << 31) /* Lock Bit */ +#define RTC_RGR_ADJC_BIT 16 +#define RTC_RGR_ADJC_MASK (0x3ff << RTC_RGR_ADJC_BIT) +#define RTC_RGR_NC1HZ_BIT 0 +#define RTC_RGR_NC1HZ_MASK (0xffff << RTC_RGR_NC1HZ_BIT) + + /* Hibernate Control Register */ +#define RTC_HCR_PD (1 << 0) /* Power Down */ + + /* Hibernate Wakeup Filter Counter Register */ +#define RTC_HWFCR_BIT 5 +#define RTC_HWFCR_MASK (0x7ff << RTC_HWFCR_BIT) + + /* Hibernate Reset Counter Register */ +#define RTC_HRCR_BIT 5 +#define RTC_HRCR_MASK (0x7f << RTC_HRCR_BIT) + + /* Hibernate Wakeup Control Register */ +#define RTC_HWCR_EALM (1 << 0) /* RTC alarm wakeup enable */ + + /* Hibernate Wakeup Status Register */ +#define RTC_HWRSR_HR (1 << 5) /* Hibernate reset */ +#define RTC_HWRSR_PPR (1 << 4) /* PPR reset */ +#define RTC_HWRSR_PIN (1 << 1) /* Wakeup pin status bit */ +#define RTC_HWRSR_ALM (1 << 0) /* RTC alarm status bit */ + +#define JZ4740_RTC_INDEX_MAX 0xe /*0x38/4 */ + +/*----------------------WDT&TCU--------------------------------*/ +#define JZ4740_WDT_TCU_BASE 0x10002000 +#define JZ4740_WDT_TCU_SIZE 0xa0 + +#define WDT_TDR ( 0x00) +#define WDT_TCER ( 0x04) +#define WDT_TCNT ( 0x08) +#define WDT_TCSR ( 0x0C) + +#define TCU_CLOCK_EXT 0x4 +#define TCU_CLOCK_RTC 0x2 +#define TCU_CLOCK_PCK 0x0 +#define TCU_CLOCK_SOUCE_MASK 0x7 + +#define TCU_CLOCK_PRESCALE_MASK 0x38 +#define TCU_CLOCK_PRESCALE_OFFSET 0x3 + +#define WDT_CLOCK_EXT 0x4 +#define WDT_CLOCK_RTC 0x2 +#define WDT_CLOCK_PCK 0x0 +#define WDT_CLOCK_SOUCE_MASK 0x7 + +#define WDT_CLOCK_PRESCALE_MASK 0x38 +#define WDT_CLOCK_PRESCALE_OFFSET 0x3 + +#define EXT_CLOCK 12000000 /*12M */ +#define RTC_CLOCK 32768 + +/************************************************************************* + * TCU (Timer Counter Unit) + *************************************************************************/ +#define TCU_TSR ( 0x1C) /* Timer Stop Register */ +#define TCU_TSSR ( 0x2C) /* Timer Stop Set Register */ +#define TCU_TSCR ( 0x3C) /* Timer Stop Clear Register */ +#define TCU_TER ( 0x10) /* Timer Counter Enable Register */ +#define TCU_TESR ( 0x14) /* Timer Counter Enable Set Register */ +#define TCU_TECR ( 0x18) /* Timer Counter Enable Clear Register */ +#define TCU_TFR ( 0x20) /* Timer Flag Register */ +#define TCU_TFSR ( 0x24) /* Timer Flag Set Register */ +#define TCU_TFCR ( 0x28) /* Timer Flag Clear Register */ +#define TCU_TMR ( 0x30) /* Timer Mask Register */ +#define TCU_TMSR ( 0x34) /* Timer Mask Set Register */ +#define TCU_TMCR ( 0x38) /* Timer Mask Clear Register */ +#define TCU_TDFR0 ( 0x40) /* Timer Data Full Register */ +#define TCU_TDHR0 ( 0x44) /* Timer Data Half Register */ +#define TCU_TCNT0 ( 0x48) /* Timer Counter Register */ +#define TCU_TCSR0 ( 0x4C) /* Timer Control Register */ +#define TCU_TDFR1 ( 0x50) +#define TCU_TDHR1 ( 0x54) +#define TCU_TCNT1 ( 0x58) +#define TCU_TCSR1 ( 0x5C) +#define TCU_TDFR2 (0x60) +#define TCU_TDHR2 ( 0x64) +#define TCU_TCNT2 ( 0x68) +#define TCU_TCSR2 ( 0x6C) +#define TCU_TDFR3 ( 0x70) +#define TCU_TDHR3 ( 0x74) +#define TCU_TCNT3 ( 0x78) +#define TCU_TCSR3 ( 0x7C) +#define TCU_TDFR4 ( 0x80) +#define TCU_TDHR4 ( 0x84) +#define TCU_TCNT4 ( 0x88) +#define TCU_TCSR4 ( 0x8C) +#define TCU_TDFR5 ( 0x90) +#define TCU_TDHR5 ( 0x94) +#define TCU_TCNT5 ( 0x98) +#define TCU_TCSR5 ( 0x9C) + +#define TCU_TDFR(n) (TCU_TDFR0+n*0x10) +#define TCU_TDHR(n) (TCU_TDHR0+n*0x10) +#define TCU_TCNT(n) (TCU_TCNT0+n*0x10) +#define TCU_TCSR(n) (TCU_TCSR0+n*0x10) + +#define WDT_TIMER_STOP 0x10000 +#define JZ4740_WDT_INDEX_MAX 0x28 /*0xa0/4 */ + +/*-------------------LCD---------------------*/ +#define JZ4740_LCD_BASE 0x13050000 +#define JZ4740_LCD_SIZE 0x60 + +#define LCD_CFG ( 0x00) /* LCD Configure Register */ +#define LCD_VSYNC ( 0x04) /* Vertical Synchronize Register */ +#define LCD_HSYNC ( 0x08) /* Horizontal Synchronize Register */ +#define LCD_VAT ( 0x0c) /* Virtual Area Setting Register */ +#define LCD_DAH ( 0x10) /* Display Area Horizontal Start/End Point */ +#define LCD_DAV ( 0x14) /* Display Area Vertical Start/End Point */ +#define LCD_PS ( 0x18) /* PS Signal Setting */ +#define LCD_CLS ( 0x1c) /* CLS Signal Setting */ +#define LCD_SPL ( 0x20) /* SPL Signal Setting */ +#define LCD_REV ( 0x24) /* REV Signal Setting */ +#define LCD_CTRL ( 0x30) /* LCD Control Register */ +#define LCD_STATE ( 0x34) /* LCD Status Register */ +#define LCD_IID ( 0x38) /* Interrupt ID Register */ +#define LCD_DA0 ( 0x40) /* Descriptor Address Register 0 */ +#define LCD_SA0 ( 0x44) /* Source Address Register 0 */ +#define LCD_FID0 ( 0x48) /* Frame ID Register 0 */ +#define LCD_CMD0 ( 0x4c) /* DMA Command Register 0 */ +#define LCD_DA1 ( 0x50) /* Descriptor Address Register 1 */ +#define LCD_SA1 ( 0x54) /* Source Address Register 1 */ +#define LCD_FID1 ( 0x58) /* Frame ID Register 1 */ +#define LCD_CMD1 ( 0x5c) /* DMA Command Register 1 */ + +#define LCD_CTRL_BST_BIT 28 /* Burst Length Selection */ +#define LCD_CTRL_BST_MASK (0x03 << LCD_CTRL_BST_BIT) +#define LCD_CTRL_BST_4 (0 << LCD_CTRL_BST_BIT) /* 4-word */ +#define LCD_CTRL_BST_8 (1 << LCD_CTRL_BST_BIT) /* 8-word */ +#define LCD_CTRL_BST_16 (2 << LCD_CTRL_BST_BIT) /* 16-word */ +#define LCD_CTRL_RGB565 (0 << 27) /* RGB565 mode */ +#define LCD_CTRL_RGB555 (1 << 27) /* RGB555 mode */ +#define LCD_CTRL_OFUP (1 << 26) /* Output FIFO underrun protection enable */ +#define LCD_CTRL_FRC_BIT 24 /* STN FRC Algorithm Selection */ +#define LCD_CTRL_FRC_MASK (0x03 << LCD_CTRL_FRC_BIT) +#define LCD_CTRL_FRC_16 (0 << LCD_CTRL_FRC_BIT) /* 16 grayscale */ +#define LCD_CTRL_FRC_4 (1 << LCD_CTRL_FRC_BIT) /* 4 grayscale */ +#define LCD_CTRL_FRC_2 (2 << LCD_CTRL_FRC_BIT) /* 2 grayscale */ +#define LCD_CTRL_PDD_BIT 16 /* Load Palette Delay Counter */ +#define LCD_CTRL_PDD_MASK (0xff << LCD_CTRL_PDD_BIT) +#define LCD_CTRL_EOFM (1 << 13) /* EOF interrupt mask */ +#define LCD_CTRL_SOFM (1 << 12) /* SOF interrupt mask */ +#define LCD_CTRL_OFUM (1 << 11) /* Output FIFO underrun interrupt mask */ +#define LCD_CTRL_IFUM0 (1 << 10) /* Input FIFO 0 underrun interrupt mask */ +#define LCD_CTRL_IFUM1 (1 << 9) /* Input FIFO 1 underrun interrupt mask */ +#define LCD_CTRL_LDDM (1 << 8) /* LCD disable done interrupt mask */ +#define LCD_CTRL_QDM (1 << 7) /* LCD quick disable done interrupt mask */ +#define LCD_CTRL_BEDN (1 << 6) /* Endian selection */ +#define LCD_CTRL_PEDN (1 << 5) /* Endian in byte:0-msb first, 1-lsb first */ +#define LCD_CTRL_DIS (1 << 4) /* Disable indicate bit */ +#define LCD_CTRL_ENA (1 << 3) /* LCD enable bit */ +#define LCD_CTRL_BPP_BIT 0 /* Bits Per Pixel */ +#define LCD_CTRL_BPP_MASK (0x07 << LCD_CTRL_BPP_BIT) +#define LCD_CTRL_BPP_1 (0 << LCD_CTRL_BPP_BIT) /* 1 bpp */ +#define LCD_CTRL_BPP_2 (1 << LCD_CTRL_BPP_BIT) /* 2 bpp */ +#define LCD_CTRL_BPP_4 (2 << LCD_CTRL_BPP_BIT) /* 4 bpp */ +#define LCD_CTRL_BPP_8 (3 << LCD_CTRL_BPP_BIT) /* 8 bpp */ +#define LCD_CTRL_BPP_16 (4 << LCD_CTRL_BPP_BIT) /* 15/16 bpp */ +#define LCD_CTRL_BPP_18_24 (5 << LCD_CTRL_BPP_BIT) /* 18/24/32 bpp */ + + /* Display Area Horizontal Start/End Point Register */ +#define LCD_DAH_HDS_BIT 16 /* Horizontal display area start in dot clock */ +#define LCD_DAH_HDS_MASK (0xffff << LCD_DAH_HDS_BIT) +#define LCD_DAH_HDE_BIT 0 /* Horizontal display area end in dot clock */ +#define LCD_DAH_HDE_MASK (0xffff << LCD_DAH_HDE_BIT) + + /* Display Area Vertical Start/End Point Register */ +#define LCD_DAV_VDS_BIT 16 /* Vertical display area start in line clock */ +#define LCD_DAV_VDS_MASK (0xffff << LCD_DAV_VDS_BIT) +#define LCD_DAV_VDE_BIT 0 /* Vertical display area end in line clock */ +#define LCD_DAV_VDE_MASK (0xffff << LCD_DAV_VDE_BIT) + +#define LCD_STATE_QD (1 << 7) /* Quick Disable Done */ +#define LCD_STATE_EOF (1 << 5) /* EOF Flag */ +#define LCD_STATE_SOF (1 << 4) /* SOF Flag */ +#define LCD_STATE_OFU (1 << 3) /* Output FIFO Underrun */ +#define LCD_STATE_IFU0 (1 << 2) /* Input FIFO 0 Underrun */ +#define LCD_STATE_IFU1 (1 << 1) /* Input FIFO 1 Underrun */ +#define LCD_STATE_LDD (1 << 0) /* LCD Disabled */ + +#define LCD_CMD_SOFINT (1 << 31) +#define LCD_CMD_EOFINT (1 << 30) +#define LCD_CMD_PAL (1 << 28) +#define LCD_CMD_LEN_BIT 0 +#define LCD_CMD_LEN_MASK (0xffffff << LCD_CMD_LEN_BIT) + +#define JZ4740_LCD_INDEX_MAX 0x18 /*0x60/4 */ + +/*---------------------touch screen------------------*/ +#define JZ4740_TS_BASE 0x10070000 +#define JZ4740_TS_SIZE 0x28 + +#define SADC_ENA ( 0x00) /* ADC Enable Register */ +#define SADC_CFG ( 0x04) /* ADC Configure Register */ +#define SADC_CTRL ( 0x08) /* ADC Control Register */ +#define SADC_STATE ( 0x0C) /* ADC Status Register */ +#define SADC_SAMETIME ( 0x10) /* ADC Same Point Time Register */ +#define SADC_WAITTIME ( 0x14) /* ADC Wait Time Register */ +#define SADC_TSDAT ( 0x18) /* ADC Touch Screen Data Register */ +#define SADC_BATDAT ( 0x1C) /* ADC PBAT Data Register */ +#define SADC_SADDAT ( 0x20) /* ADC SADCIN Data Register */ + + /* ADC Enable Register */ +#define SADC_ENA_ADEN (1 << 7) /* Touch Screen Enable */ +#define SADC_ENA_TSEN (1 << 2) /* Touch Screen Enable */ +#define SADC_ENA_PBATEN (1 << 1) /* PBAT Enable */ +#define SADC_ENA_SADCINEN (1 << 0) /* SADCIN Enable */ + + /* ADC Configure Register */ +#define SADC_CFG_EXIN (1 << 30) +#define SADC_CFG_CLKOUT_NUM_BIT 16 +#define SADC_CFG_CLKOUT_NUM_MASK (0x7 << SADC_CFG_CLKOUT_NUM_BIT) +#define SADC_CFG_TS_DMA (1 << 15) /* Touch Screen DMA Enable */ +#define SADC_CFG_XYZ_BIT 13 /* XYZ selection */ +#define SADC_CFG_XYZ_MASK (0x3 << SADC_CFG_XYZ_BIT) +#define SADC_CFG_XY (0 << SADC_CFG_XYZ_BIT) +#define SADC_CFG_XYZ (1 << SADC_CFG_XYZ_BIT) +#define SADC_CFG_XYZ1Z2 (2 << SADC_CFG_XYZ_BIT) +#define SADC_CFG_SNUM_BIT 10 /* Sample Number */ +#define SADC_CFG_SNUM_MASK (0x7 << SADC_CFG_SNUM_BIT) +#define SADC_CFG_SNUM_1 (0x0 << SADC_CFG_SNUM_BIT) +#define SADC_CFG_SNUM_2 (0x1 << SADC_CFG_SNUM_BIT) +#define SADC_CFG_SNUM_3 (0x2 << SADC_CFG_SNUM_BIT) +#define SADC_CFG_SNUM_4 (0x3 << SADC_CFG_SNUM_BIT) +#define SADC_CFG_SNUM_5 (0x4 << SADC_CFG_SNUM_BIT) +#define SADC_CFG_SNUM_6 (0x5 << SADC_CFG_SNUM_BIT) +#define SADC_CFG_SNUM_8 (0x6 << SADC_CFG_SNUM_BIT) +#define SADC_CFG_SNUM_9 (0x7 << SADC_CFG_SNUM_BIT) +#define SADC_CFG_CLKDIV_BIT 5 /* AD Converter frequency clock divider */ +#define SADC_CFG_CLKDIV_MASK (0x1f << SADC_CFG_CLKDIV_BIT) +#define SADC_CFG_PBAT_HIGH (0 << 4) /* PBAT >= 2.5V */ +#define SADC_CFG_PBAT_LOW (1 << 4) /* PBAT < 2.5V */ +#define SADC_CFG_CMD_BIT 0 /* ADC Command */ +#define SADC_CFG_CMD_MASK (0xf << SADC_CFG_CMD_BIT) +#define SADC_CFG_CMD_X_SE (0x0 << SADC_CFG_CMD_BIT) /* X Single-End */ +#define SADC_CFG_CMD_Y_SE (0x1 << SADC_CFG_CMD_BIT) /* Y Single-End */ +#define SADC_CFG_CMD_X_DIFF (0x2 << SADC_CFG_CMD_BIT) /* X Differential */ +#define SADC_CFG_CMD_Y_DIFF (0x3 << SADC_CFG_CMD_BIT) /* Y Differential */ +#define SADC_CFG_CMD_Z1_DIFF (0x4 << SADC_CFG_CMD_BIT) /* Z1 Differential */ +#define SADC_CFG_CMD_Z2_DIFF (0x5 << SADC_CFG_CMD_BIT) /* Z2 Differential */ +#define SADC_CFG_CMD_Z3_DIFF (0x6 << SADC_CFG_CMD_BIT) /* Z3 Differential */ +#define SADC_CFG_CMD_Z4_DIFF (0x7 << SADC_CFG_CMD_BIT) /* Z4 Differential */ +#define SADC_CFG_CMD_TP_SE (0x8 << SADC_CFG_CMD_BIT) /* Touch Pressure */ +#define SADC_CFG_CMD_PBATH_SE (0x9 << SADC_CFG_CMD_BIT) /* PBAT >= 2.5V */ +#define SADC_CFG_CMD_PBATL_SE (0xa << SADC_CFG_CMD_BIT) /* PBAT < 2.5V */ +#define SADC_CFG_CMD_SADCIN_SE (0xb << SADC_CFG_CMD_BIT) /* Measure SADCIN */ +#define SADC_CFG_CMD_INT_PEN (0xc << SADC_CFG_CMD_BIT) /* INT_PEN Enable */ + + /* ADC Control Register */ +#define SADC_CTRL_PENDM (1 << 4) /* Pen Down Interrupt Mask */ +#define SADC_CTRL_PENUM (1 << 3) /* Pen Up Interrupt Mask */ +#define SADC_CTRL_TSRDYM (1 << 2) /* Touch Screen Data Ready Interrupt Mask */ +#define SADC_CTRL_PBATRDYM (1 << 1) /* PBAT Data Ready Interrupt Mask */ +#define SADC_CTRL_SRDYM (1 << 0) /* SADCIN Data Ready Interrupt Mask */ + + /* ADC Status Register */ +#define SADC_STATE_TSBUSY (1 << 7) /* TS A/D is working */ +#define SADC_STATE_PBATBUSY (1 << 6) /* PBAT A/D is working */ +#define SADC_STATE_SBUSY (1 << 5) /* SADCIN A/D is working */ +#define SADC_STATE_PEND (1 << 4) /* Pen Down Interrupt Flag */ +#define SADC_STATE_PENU (1 << 3) /* Pen Up Interrupt Flag */ +#define SADC_STATE_TSRDY (1 << 2) /* Touch Screen Data Ready Interrupt Flag */ +#define SADC_STATE_PBATRDY (1 << 1) /* PBAT Data Ready Interrupt Flag */ +#define SADC_STATE_SRDY (1 << 0) /* SADCIN Data Ready Interrupt Flag */ + + /* ADC Touch Screen Data Register */ +#define SADC_TSDAT_DATA0_BIT 0 +#define SADC_TSDAT_DATA0_MASK (0xfff << SADC_TSDAT_DATA0_BIT) +#define SADC_TSDAT_TYPE0 (1 << 15) +#define SADC_TSDAT_DATA1_BIT 16 +#define SADC_TSDAT_DATA1_MASK (0xfff << SADC_TSDAT_DATA1_BIT) +#define SADC_TSDAT_TYPE1 (1 << 31) + +#define JZ4740_TS_INDEX_MAX 0xA /*0x28/4 */ + +/*--------------DMA--------------------*/ +#define JZ4740_DMA_BASE 0x13020000 +#define JZ4740_DMA_SIZE 0x310 +#define MAX_DMA_NUM 6 /* max 6 channels */ + +#define DMAC_DSAR(n) ( (0x00 + (n) * 0x20)) /* DMA source address */ +#define DMAC_DTAR(n) ( (0x04 + (n) * 0x20)) /* DMA target address */ +#define DMAC_DTCR(n) ( (0x08 + (n) * 0x20)) /* DMA transfer count */ +#define DMAC_DRSR(n) ( (0x0c + (n) * 0x20)) /* DMA request source */ +#define DMAC_DCCSR(n) ( (0x10 + (n) * 0x20)) /* DMA control/status */ +#define DMAC_DCMD(n) ( (0x14 + (n) * 0x20)) /* DMA command */ +#define DMAC_DDA(n) ( (0x18 + (n) * 0x20)) /* DMA descriptor address */ +#define DMAC_DMACR ( 0x0300) /* DMA control register */ +#define DMAC_DMAIPR ( 0x0304) /* DMA interrupt pending */ +#define DMAC_DMADBR ( 0x0308) /* DMA doorbell */ +#define DMAC_DMADBSR ( 0x030C) /* DMA doorbell set */ + +// channel 0 +#define DMAC_DSAR0 DMAC_DSAR(0) +#define DMAC_DTAR0 DMAC_DTAR(0) +#define DMAC_DTCR0 DMAC_DTCR(0) +#define DMAC_DRSR0 DMAC_DRSR(0) +#define DMAC_DCCSR0 DMAC_DCCSR(0) +#define DMAC_DCMD0 DMAC_DCMD(0) +#define DMAC_DDA0 DMAC_DDA(0) + +// channel 1 +#define DMAC_DSAR1 DMAC_DSAR(1) +#define DMAC_DTAR1 DMAC_DTAR(1) +#define DMAC_DTCR1 DMAC_DTCR(1) +#define DMAC_DRSR1 DMAC_DRSR(1) +#define DMAC_DCCSR1 DMAC_DCCSR(1) +#define DMAC_DCMD1 DMAC_DCMD(1) +#define DMAC_DDA1 DMAC_DDA(1) + +// channel 2 +#define DMAC_DSAR2 DMAC_DSAR(2) +#define DMAC_DTAR2 DMAC_DTAR(2) +#define DMAC_DTCR2 DMAC_DTCR(2) +#define DMAC_DRSR2 DMAC_DRSR(2) +#define DMAC_DCCSR2 DMAC_DCCSR(2) +#define DMAC_DCMD2 DMAC_DCMD(2) +#define DMAC_DDA2 DMAC_DDA(2) + +// channel 3 +#define DMAC_DSAR3 DMAC_DSAR(3) +#define DMAC_DTAR3 DMAC_DTAR(3) +#define DMAC_DTCR3 DMAC_DTCR(3) +#define DMAC_DRSR3 DMAC_DRSR(3) +#define DMAC_DCCSR3 DMAC_DCCSR(3) +#define DMAC_DCMD3 DMAC_DCMD(3) +#define DMAC_DDA3 DMAC_DDA(3) + +// channel 4 +#define DMAC_DSAR4 DMAC_DSAR(4) +#define DMAC_DTAR4 DMAC_DTAR(4) +#define DMAC_DTCR4 DMAC_DTCR(4) +#define DMAC_DRSR4 DMAC_DRSR(4) +#define DMAC_DCCSR4 DMAC_DCCSR(4) +#define DMAC_DCMD4 DMAC_DCMD(4) +#define DMAC_DDA4 DMAC_DDA(4) + +// channel 5 +#define DMAC_DSAR5 DMAC_DSAR(5) +#define DMAC_DTAR5 DMAC_DTAR(5) +#define DMAC_DTCR5 DMAC_DTCR(5) +#define DMAC_DRSR5 DMAC_DRSR(5) +#define DMAC_DCCSR5 DMAC_DCCSR(5) +#define DMAC_DCMD5 DMAC_DCMD(5) +#define DMAC_DDA5 DMAC_DDA(5) + +#define JZ4740_DMA_INDEX_MAX 0xC4 /*0x310/4 */ + +// DMA request source register +#define DMAC_DRSR_RS_BIT 0 +#define DMAC_DRSR_RS_MASK (0x1f << DMAC_DRSR_RS_BIT) +#define DMAC_DRSR_RS_AUTO (8 << DMAC_DRSR_RS_BIT) +#define DMAC_DRSR_RS_UART0OUT (20 << DMAC_DRSR_RS_BIT) +#define DMAC_DRSR_RS_UART0IN (21 << DMAC_DRSR_RS_BIT) +#define DMAC_DRSR_RS_SSIOUT (22 << DMAC_DRSR_RS_BIT) +#define DMAC_DRSR_RS_SSIIN (23 << DMAC_DRSR_RS_BIT) +#define DMAC_DRSR_RS_AICOUT (24 << DMAC_DRSR_RS_BIT) +#define DMAC_DRSR_RS_AICIN (25 << DMAC_DRSR_RS_BIT) +#define DMAC_DRSR_RS_MSCOUT (26 << DMAC_DRSR_RS_BIT) +#define DMAC_DRSR_RS_MSCIN (27 << DMAC_DRSR_RS_BIT) +#define DMAC_DRSR_RS_TCU (28 << DMAC_DRSR_RS_BIT) +#define DMAC_DRSR_RS_SADC (29 << DMAC_DRSR_RS_BIT) +#define DMAC_DRSR_RS_SLCD (30 << DMAC_DRSR_RS_BIT) + +// DMA channel control/status register +#define DMAC_DCCSR_NDES (1 << 31) /* descriptor (0) or not (1) ? */ +#define DMAC_DCCSR_CDOA_BIT 16 /* copy of DMA offset address */ +#define DMAC_DCCSR_CDOA_MASK (0xff << DMAC_DCCSR_CDOA_BIT) +#define DMAC_DCCSR_INV (1 << 6) /* descriptor invalid */ +#define DMAC_DCCSR_AR (1 << 4) /* address error */ +#define DMAC_DCCSR_TT (1 << 3) /* transfer terminated */ +#define DMAC_DCCSR_HLT (1 << 2) /* DMA halted */ +#define DMAC_DCCSR_CT (1 << 1) /* count terminated */ +#define DMAC_DCCSR_EN (1 << 0) /* channel enable bit */ + +// DMA channel command register +#define DMAC_DCMD_SAI (1 << 23) /* source address increment */ +#define DMAC_DCMD_DAI (1 << 22) /* dest address increment */ +#define DMAC_DCMD_RDIL_BIT 16 /* request detection interval length */ +#define DMAC_DCMD_RDIL_MASK (0x0f << DMAC_DCMD_RDIL_BIT) +#define DMAC_DCMD_RDIL_IGN (0 << DMAC_DCMD_RDIL_BIT) +#define DMAC_DCMD_RDIL_2 (1 << DMAC_DCMD_RDIL_BIT) +#define DMAC_DCMD_RDIL_4 (2 << DMAC_DCMD_RDIL_BIT) +#define DMAC_DCMD_RDIL_8 (3 << DMAC_DCMD_RDIL_BIT) +#define DMAC_DCMD_RDIL_12 (4 << DMAC_DCMD_RDIL_BIT) +#define DMAC_DCMD_RDIL_16 (5 << DMAC_DCMD_RDIL_BIT) +#define DMAC_DCMD_RDIL_20 (6 << DMAC_DCMD_RDIL_BIT) +#define DMAC_DCMD_RDIL_24 (7 << DMAC_DCMD_RDIL_BIT) +#define DMAC_DCMD_RDIL_28 (8 << DMAC_DCMD_RDIL_BIT) +#define DMAC_DCMD_RDIL_32 (9 << DMAC_DCMD_RDIL_BIT) +#define DMAC_DCMD_RDIL_48 (10 << DMAC_DCMD_RDIL_BIT) +#define DMAC_DCMD_RDIL_60 (11 << DMAC_DCMD_RDIL_BIT) +#define DMAC_DCMD_RDIL_64 (12 << DMAC_DCMD_RDIL_BIT) +#define DMAC_DCMD_RDIL_124 (13 << DMAC_DCMD_RDIL_BIT) +#define DMAC_DCMD_RDIL_128 (14 << DMAC_DCMD_RDIL_BIT) +#define DMAC_DCMD_RDIL_200 (15 << DMAC_DCMD_RDIL_BIT) +#define DMAC_DCMD_SWDH_BIT 14 /* source port width */ +#define DMAC_DCMD_SWDH_MASK (0x03 << DMAC_DCMD_SWDH_BIT) +#define DMAC_DCMD_SWDH_32 (0 << DMAC_DCMD_SWDH_BIT) +#define DMAC_DCMD_SWDH_8 (1 << DMAC_DCMD_SWDH_BIT) +#define DMAC_DCMD_SWDH_16 (2 << DMAC_DCMD_SWDH_BIT) +#define DMAC_DCMD_DWDH_BIT 12 /* dest port width */ +#define DMAC_DCMD_DWDH_MASK (0x03 << DMAC_DCMD_DWDH_BIT) +#define DMAC_DCMD_DWDH_32 (0 << DMAC_DCMD_DWDH_BIT) +#define DMAC_DCMD_DWDH_8 (1 << DMAC_DCMD_DWDH_BIT) +#define DMAC_DCMD_DWDH_16 (2 << DMAC_DCMD_DWDH_BIT) +#define DMAC_DCMD_DS_BIT 8 /* transfer data size of a data unit */ +#define DMAC_DCMD_DS_MASK (0x07 << DMAC_DCMD_DS_BIT) +#define DMAC_DCMD_DS_32BIT (0 << DMAC_DCMD_DS_BIT) +#define DMAC_DCMD_DS_8BIT (1 << DMAC_DCMD_DS_BIT) +#define DMAC_DCMD_DS_16BIT (2 << DMAC_DCMD_DS_BIT) +#define DMAC_DCMD_DS_16BYTE (3 << DMAC_DCMD_DS_BIT) +#define DMAC_DCMD_DS_32BYTE (4 << DMAC_DCMD_DS_BIT) +#define DMAC_DCMD_TM (1 << 7) /* transfer mode: 0-single 1-block */ +#define DMAC_DCMD_DES_V (1 << 4) /* descriptor valid flag */ +#define DMAC_DCMD_DES_VM (1 << 3) /* descriptor valid mask: 1:support V-bit */ +#define DMAC_DCMD_DES_VIE (1 << 2) /* DMA valid error interrupt enable */ +#define DMAC_DCMD_TIE (1 << 1) /* DMA transfer interrupt enable */ +#define DMAC_DCMD_LINK (1 << 0) /* descriptor link enable */ + +// DMA descriptor address register +#define DMAC_DDA_BASE_BIT 12 /* descriptor base address */ +#define DMAC_DDA_BASE_MASK (0x0fffff << DMAC_DDA_BASE_BIT) +#define DMAC_DDA_OFFSET_BIT 4 /* descriptor offset address */ +#define DMAC_DDA_OFFSET_MASK (0x0ff << DMAC_DDA_OFFSET_BIT) + +// DMA control register +#define DMAC_DMACR_PR_BIT 8 /* channel priority mode */ +#define DMAC_DMACR_PR_MASK (0x03 << DMAC_DMACR_PR_BIT) +#define DMAC_DMACR_PR_012345 (0 << DMAC_DMACR_PR_BIT) +#define DMAC_DMACR_PR_023145 (1 << DMAC_DMACR_PR_BIT) +#define DMAC_DMACR_PR_201345 (2 << DMAC_DMACR_PR_BIT) +#define DMAC_DMACR_PR_RR (3 << DMAC_DMACR_PR_BIT) /* round robin */ +#define DMAC_DMACR_HLT (1 << 3) /* DMA halt flag */ +#define DMAC_DMACR_AR (1 << 2) /* address error flag */ +#define DMAC_DMACR_DMAE (1 << 0) /* DMA enable bit */ + +/*------------INT CONTROLLER------------------------*/ +#define JZ4740_INT_BASE 0x10001000 +#define JZ4740_INT_SIZE 0x1C + +#define INTC_ISR ( 0x00) +#define INTC_IMR ( 0x04) +#define INTC_IMSR ( 0x08) +#define INTC_IMCR ( 0x0c) +#define INTC_IPR ( 0x10) + +// 1st-level interrupts +#define IRQ_I2C 1 +#define IRQ_UHC 3 +#define IRQ_UART0 9 +#define IRQ_SADC 12 +#define IRQ_MSC 14 +#define IRQ_RTC 15 +#define IRQ_SSI 16 +#define IRQ_CIM 17 +#define IRQ_AIC 18 +#define IRQ_ETH 19 +#define IRQ_DMAC 20 +#define IRQ_TCU2 21 +#define IRQ_TCU1 22 +#define IRQ_TCU0 23 +#define IRQ_UDC 24 +#define IRQ_GPIO3 25 +#define IRQ_GPIO2 26 +#define IRQ_GPIO1 27 +#define IRQ_GPIO0 28 +#define IRQ_IPU 29 +#define IRQ_LCD 30 + +// 2nd-level interrupts +#define IRQ_DMA_0 32 /* 32 to 37 for DMAC channel 0 to 5 */ +#define IRQ_GPIO_0 48 /* 48 to 175 for GPIO pin 0 to 127 */ + +#define JZ4740_INT_INDEX_MAX 0x7 /*0x1C/4 */ +#define JZ4740_INT_TO_MIPS 0x2 /*jz4740 intc will issue int 2 to mips cpu */ + +int jz4740_boot_from_nandflash (vm_instance_t * vm); +int jz4740_reset (vm_instance_t * vm); + +#endif diff --git a/tools/virtualmips/jz4740/jz4740_dev_cpm.c b/tools/virtualmips/jz4740/jz4740_dev_cpm.c new file mode 100644 index 0000000..a17da23 --- /dev/null +++ b/tools/virtualmips/jz4740/jz4740_dev_cpm.c @@ -0,0 +1,91 @@ + /* + * Copyright (C) yajin 2008 + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + * + */ + +/*Just a dummy cpm for JZ4740 +I need document!!! +*/ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include + +#include "device.h" +#include "mips_memory.h" +#include "cpu.h" +#include "jz4740.h" + +m_uint32_t jz4740_cpm_table[JZ4740_CPM_INDEX_MAX]; + +struct jz4740_cpm_data { + struct vdevice *dev; + m_uint8_t *jz4740_cpm_ptr; + m_uint32_t jz4740_cpm_size; +}; + +void *dev_jz4740_cpm_access (cpu_mips_t * cpu, struct vdevice *dev, + m_uint32_t offset, u_int op_size, u_int op_type, m_reg_t * data, + m_uint8_t * has_set_value) +{ + + struct jz4740_cpm_data *d = dev->priv_data; + + if (offset >= d->jz4740_cpm_size) { + *data = 0; + return NULL; + } + return ((void *) (d->jz4740_cpm_ptr + offset)); + +} + +void dev_jz4740_cpm_init_defaultvalue () +{ + memset (jz4740_cpm_table, 0x0, sizeof (jz4740_cpm_table)); +} + +void dev_jz4740_cpm_reset (cpu_mips_t * cpu, struct vdevice *dev) +{ + dev_jz4740_cpm_init_defaultvalue (); +} + +int dev_jz4740_cpm_init (vm_instance_t * vm, char *name, m_pa_t paddr, + m_uint32_t len) +{ + struct jz4740_cpm_data *d; + + /* allocate the private data structure */ + if (!(d = malloc (sizeof (*d)))) { + fprintf (stderr, "jz4740_cpm: unable to create device.\n"); + return (-1); + } + + memset (d, 0, sizeof (*d)); + if (!(d->dev = dev_create (name))) + goto err_dev_create; + d->dev->priv_data = d; + d->dev->phys_addr = paddr; + d->dev->phys_len = len; + d->jz4740_cpm_ptr = (m_uint8_t *) (&jz4740_cpm_table[0]); + d->jz4740_cpm_size = len; + d->dev->handler = dev_jz4740_cpm_access; + d->dev->reset_handler = dev_jz4740_cpm_reset; + + d->dev->flags = VDEVICE_FLAG_NO_MTS_MMAP; + + vm_bind_device (vm, d->dev); + //dev_jz4740_cpm_init_defaultvalue(); + + return (0); + + err_dev_create: + free (d); + return (-1); +} diff --git a/tools/virtualmips/jz4740/jz4740_dev_dma.c b/tools/virtualmips/jz4740/jz4740_dev_dma.c new file mode 100644 index 0000000..7792f6f --- /dev/null +++ b/tools/virtualmips/jz4740/jz4740_dev_dma.c @@ -0,0 +1,294 @@ + /* + * Copyright (C) yajin 2008 + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + * + */ + +/*DMA Controller +Only support AUTO Request. + +TODO: +*/ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include + +#include "device.h" +#include "mips_memory.h" +#include "cpu.h" +#include "jz4740.h" + +m_uint32_t jz4740_dma_table[JZ4740_DMA_INDEX_MAX]; + +struct jz4740_dma_data { + struct vdevice *dev; + m_uint8_t *jz4740_dma_ptr; + m_uint32_t jz4740_dma_size; +}; + +typedef struct { + m_uint32_t dcmd; /* DCMD value for the current transfer */ + m_uint32_t dsadr; /* DSAR value for the current transfer */ + m_uint32_t dtadr; /* DTAR value for the current transfer */ + m_uint32_t ddadr; /* Points to the next descriptor + transfer count */ +} jz_dma_desc; + +static int get_dma_unit_size (int channel, m_uint32_t cmd_value) +{ + //switch (jz4740_dma_table[DMAC_DCMD(channel)/4]&DMAC_DCMD_DS_MASK) + switch (cmd_value & DMAC_DCMD_DS_MASK) { + case DMAC_DCMD_DS_32BIT: + return 4; + case DMAC_DCMD_DS_16BIT: + return 2; + case DMAC_DCMD_DS_8BIT: + return 1; + case DMAC_DCMD_DS_16BYTE: + return 16; + case DMAC_DCMD_DS_32BYTE: + return 32; + default: + assert (0); + } + +} + +void dma_non_descriptor_trans (cpu_mips_t * cpu, struct jz4740_dma_data *d, + int channel) +{ + + physmem_dma_transfer (cpu->vm, jz4740_dma_table[DMAC_DSAR (channel) / 4], + jz4740_dma_table[DMAC_DTAR (channel) / 4], + get_dma_unit_size (channel, + jz4740_dma_table[DMAC_DCMD (channel) / 4]) * + jz4740_dma_table[DMAC_DTCR (channel) / 4]); + /*we have finished dma */ + jz4740_dma_table[DMAC_DTCR (channel) / 4] = 0; + + /*set DIR QP */ + jz4740_dma_table[DMAC_DMAIPR / 4] |= 1 << channel; + /*some cleanup work */ + /*clean AR TT GLOBAL AR */ + jz4740_dma_table[DMAC_DCCSR (channel) / 4] |= ~DMAC_DCCSR_AR; + jz4740_dma_table[DMAC_DCCSR (channel) / 4] |= ~DMAC_DCCSR_TT; + jz4740_dma_table[DMAC_DMACR / 4] |= ~DMAC_DMACR_AR; + + if (jz4740_dma_table[DMAC_DCMD (channel) / 4] & DMAC_DCMD_TIE) { + cpu->vm->set_irq (cpu->vm, IRQ_DMAC); + } + +} + +void dma_descriptor_trans (cpu_mips_t * cpu, struct jz4740_dma_data *d, + int channel) +{ + jz_dma_desc *desc; + m_pa_t desc_phy; + m_uint32_t dummy_data; + + /*fetch the first descritpor */ + desc_phy = jz4740_dma_table[DMAC_DDA (channel) / 4]; + ASSERT ((desc_phy & 0xf) == 0, "DDA%d should be 16 bytes aligned\n", + channel); + desc = physmem_get_hptr (cpu->vm, desc_phy, 4, MTS_READ, &dummy_data); + ASSERT (desc != NULL, "error descriptor phyaddress %x\n", desc_phy); + while (1) { + if (((desc->dcmd) & DMAC_DCMD_DES_VM) + && (!((desc->dcmd) & DMAC_DCMD_DES_V))) { + /*STOP DMA SET DCSN.INV=1 */ + jz4740_dma_table[DMAC_DCCSR (channel) / 4] |= DMAC_DCCSR_INV; + return; + } + physmem_dma_transfer (cpu->vm, desc->dsadr, + desc->dtadr, + (desc->ddadr & 0xffffff) * get_dma_unit_size (channel, + desc->dcmd)); + + if ((desc->dcmd) & DMAC_DCMD_DES_VM) { + /*clear v */ + desc->dcmd |= ~DMAC_DCMD_DES_V; + } + if ((desc->dcmd) & DMAC_DCMD_LINK) { + /*set DCSN.CT=1 */ + jz4740_dma_table[DMAC_DCCSR (channel) / 4] |= DMAC_DCCSR_CT; + } else { + /*set DCSN.TT=1 */ + jz4740_dma_table[DMAC_DCCSR (channel) / 4] |= DMAC_DCCSR_TT; + } + + if (desc->dcmd & DMAC_DCMD_TIE) { + cpu->vm->set_irq (cpu->vm, IRQ_DMAC); + } + + if ((desc->dcmd) & DMAC_DCMD_LINK) { + /*fetch next descriptor */ + desc_phy = jz4740_dma_table[DMAC_DDA (channel) / 4] & 0xfffff000; + desc_phy += (desc->dtadr & 0xff000000) >> 24; + desc = + physmem_get_hptr (cpu->vm, desc_phy, 4, MTS_READ, + &dummy_data); + ASSERT (desc != NULL, "error descriptor phyaddress %x\n", + desc_phy); + } else + break; + + } + +} + +void enable_dma_channel (cpu_mips_t * cpu, struct jz4740_dma_data *d, + int channel) +{ + if (jz4740_dma_table[DMAC_DMACR / 4] & DMAC_DMACR_DMAE) { + if ((jz4740_dma_table[DMAC_DCCSR (channel) / 4] & DMAC_DCCSR_NDES)) { + /*NON DESCRIPTOR */ + dma_non_descriptor_trans (cpu, d, channel); + } + } +} + +void enable_global_dma (cpu_mips_t * cpu, struct jz4740_dma_data *d) +{ + int channel; + for (channel = 0; channel < MAX_DMA_NUM; channel++) { + if ((jz4740_dma_table[DMAC_DCCSR (channel) / 4] & DMAC_DCCSR_NDES)) { + if ((jz4740_dma_table[DMAC_DCCSR (channel) / + 4] & DMAC_DCCSR_NDES)) + dma_non_descriptor_trans (cpu, d, channel); /*NON DESCRIPTOR */ + } + } + +} + +void enable_dma_dbn (cpu_mips_t * cpu, struct jz4740_dma_data *d, int channel) +{ + /*DESCRIPTOR trans */ + if ((jz4740_dma_table[DMAC_DMACR / 4] & DMAC_DMACR_DMAE) + && (jz4740_dma_table[DMAC_DCCSR (channel) / 4] & DMAC_DCCSR_NDES)) { + dma_descriptor_trans (cpu, d, channel); + } +} + +void *dev_jz4740_dma_access (cpu_mips_t * cpu, struct vdevice *dev, + m_uint32_t offset, u_int op_size, u_int op_type, m_reg_t * data, + m_uint8_t * has_set_value) +{ + + struct jz4740_dma_data *d = dev->priv_data; + int channel; + + if (offset >= d->jz4740_dma_size) { + *data = 0; + return NULL; + } + + if (op_type == MTS_WRITE) { + switch (offset) { + case DMAC_DRSR0: + case DMAC_DRSR1: + case DMAC_DRSR2: + case DMAC_DRSR3: + case DMAC_DRSR4: + case DMAC_DRSR5: + /*only support AUTO request */ + ASSERT (((*data) & DMAC_DRSR_RS_MASK) == DMAC_DRSR_RS_AUTO, + "only support AUTO request\n"); + return ((void *) (d->jz4740_dma_ptr + offset)); + + case DMAC_DCCSR0: + case DMAC_DCCSR1: + case DMAC_DCCSR2: + case DMAC_DCCSR3: + case DMAC_DCCSR4: + case DMAC_DCCSR5: + channel = (offset - 0x10) / 0x20; + jz4740_dma_table[DMAC_DCCSR (channel) / 4] = *data; + *has_set_value = TRUE; + if ((*data) & DMAC_DCCSR_EN) { + enable_dma_channel (cpu, d, channel); + } + return NULL; + + case DMAC_DMACR: + /*DMA Control register */ + jz4740_dma_table[DMAC_DMACR / 4] = *data; + *has_set_value = TRUE; + if ((*data) & DMAC_DMACR_DMAE) { + enable_global_dma (cpu, d); + } + return NULL; + + case DMAC_DMADBR: + case DMAC_DMADBSR: + jz4740_dma_table[DMAC_DMADBR / 4] = *data; + *has_set_value = TRUE; + for (channel = 0; channel < 6; channel++) { + if ((*data) & (1 << channel)) { + enable_dma_dbn (cpu, d, channel); + break; + } + + } + return NULL; + default: + return ((void *) (d->jz4740_dma_ptr + offset)); + } + + } else if (op_type == MTS_READ) + return ((void *) (d->jz4740_dma_ptr + offset)); + else + assert (0); + + return NULL; + +} + +void dev_jz4740_dma_init_defaultvalue () +{ + memset (jz4740_dma_table, 0x0, sizeof (jz4740_dma_table)); +} + +void dev_jz4740_dma_reset (cpu_mips_t * cpu, struct vdevice *dev) +{ + dev_jz4740_dma_init_defaultvalue (); +} + +int dev_jz4740_dma_init (vm_instance_t * vm, char *name, m_pa_t paddr, + m_uint32_t len) +{ + struct jz4740_dma_data *d; + + /* allocate the private data structure */ + if (!(d = malloc (sizeof (*d)))) { + fprintf (stderr, "jz4740_dma: unable to create device.\n"); + return (-1); + } + + memset (d, 0, sizeof (*d)); + if (!(d->dev = dev_create (name))) + goto err_dev_create; + d->dev->priv_data = d; + d->dev->phys_addr = paddr; + d->dev->phys_len = len; + d->jz4740_dma_ptr = (m_uint8_t *) (&jz4740_dma_table[0]); + d->jz4740_dma_size = len; + d->dev->handler = dev_jz4740_dma_access; + d->dev->reset_handler = dev_jz4740_dma_reset; + + d->dev->flags = VDEVICE_FLAG_NO_MTS_MMAP; + + vm_bind_device (vm, d->dev); + + return (0); + + err_dev_create: + free (d); + return (-1); +} diff --git a/tools/virtualmips/jz4740/jz4740_dev_emc.c b/tools/virtualmips/jz4740/jz4740_dev_emc.c new file mode 100644 index 0000000..11a10b4 --- /dev/null +++ b/tools/virtualmips/jz4740/jz4740_dev_emc.c @@ -0,0 +1,111 @@ + /* + * Copyright (C) yajin 2008 + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + * + */ + +/*EMC. */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include + +#include "device.h" +#include "mips_memory.h" +#include "cpu.h" +#include "jz4740.h" + +m_uint32_t jz4740_emc_table[JZ4740_EMC_INDEX_MAX]; +m_uint32_t emc_sdram0[256]; +/*configure register for sdram0*/ +/*In order to save space, set emc sdram0 seperately.*/ + +struct jz4740_emc_data { + struct vdevice *dev; + m_uint8_t *jz4740_emc_ptr; + m_uint32_t jz4740_emc_size; +}; + +void *dev_jz4740_emc_access (cpu_mips_t * cpu, struct vdevice *dev, + m_uint32_t offset, u_int op_size, u_int op_type, + m_reg_t * data, m_uint8_t * has_set_value) +{ + + struct jz4740_emc_data *d = dev->priv_data; + /*TODO: SDRAM MODE. Now just set dummy value. */ + /*EMC SDRAM0 is in seperate space */ + if ((offset >= EMC_SDMR0) && (offset <= (EMC_SDMR0 + 0x3ff))) { + return (void *) (((m_uint8_t *) & emc_sdram0[0]) + offset - + EMC_SDMR0); + } + + if ((offset >= d->jz4740_emc_size)) { + *data = 0; + return NULL; + } + /*FIXME: + * currently we do not support nand flash rc check. just set + * EMC_NFINTS_DECF(bit 3) and EMC_NFINTS_ENCF(bit 2). to tell uboot and decoding and Encoding finished + * set EMC_NFINTS_ERR(bit 0)=0 : no error */ + if (offset == EMC_NFINTS) { + jz4740_emc_table[EMC_NFINTS / 4] |= 0xc; + } + + return ((void *) (d->jz4740_emc_ptr + offset)); + +} + +void dev_jz4740_emc_init_defaultvalue () +{ + memset (jz4740_emc_table, 0x0, sizeof (jz4740_emc_table)); +#ifdef SIM_PAVO + /*EMC BCR(31:30):Boot sel + * 11:2k page nand flash */ + jz4740_emc_table[EMC_BCR / 4] |= 0xc0000000; +#endif + +} + +void dev_jz4740_emc_reset (cpu_mips_t * cpu, struct vdevice *dev) +{ + dev_jz4740_emc_init_defaultvalue (); +} + +int dev_jz4740_emc_init (vm_instance_t * vm, char *name, m_pa_t paddr, + m_uint32_t len) +{ + struct jz4740_emc_data *d; + + /* allocate the private data structure */ + if (!(d = malloc (sizeof (*d)))) { + fprintf (stderr, "jz4740_emc: unable to create device.\n"); + return (-1); + } + + memset (d, 0, sizeof (*d)); + if (!(d->dev = dev_create (name))) + goto err_dev_create; + d->dev->priv_data = d; + d->dev->phys_addr = paddr; + d->dev->phys_len = len; + d->jz4740_emc_ptr = (m_uint8_t *) (&jz4740_emc_table[0]); + d->jz4740_emc_size = len; + d->dev->handler = dev_jz4740_emc_access; + d->dev->reset_handler = dev_jz4740_emc_reset; + d->dev->flags = VDEVICE_FLAG_NO_MTS_MMAP; + + vm_bind_device (vm, d->dev); + //dev_jz4740_emc_init_defaultvalue(); + + return (0); + + err_dev_create: + free (d); + return (-1); +} diff --git a/tools/virtualmips/jz4740/jz4740_dev_gpio.c b/tools/virtualmips/jz4740/jz4740_dev_gpio.c new file mode 100644 index 0000000..1c5cbe3 --- /dev/null +++ b/tools/virtualmips/jz4740/jz4740_dev_gpio.c @@ -0,0 +1,529 @@ + /* + * Copyright (C) yajin 2008 + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + * + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include + +#include "device.h" +#include "mips_memory.h" +#include "cpu.h" +#include "jz4740.h" + +/*set to 0 to improve performance. set to 1 to debug gpio*/ +#define VALIDE_GPIO_OPERATION 0 + +m_uint32_t jz4740_gpio_table[JZ4740_GPIO_INDEX_MAX]; + +struct jz4740_gpio_data { + struct vdevice *dev; + m_uint8_t *jz4740_gpio_ptr; + m_uint32_t jz4740_gpio_size; +}; + +/* GPIO is in 4 groups. 32 per group*/ +/* + +48-79 0 +80-111 1 +112-143 2 +144-175 3 + +#define IRQ_GPIO3 25 +#define IRQ_GPIO2 26 +#define IRQ_GPIO1 27 +#define IRQ_GPIO0 28 +#define IRQ_GPIO_0 48 48 to 175 for GPIO pin 0 to 127 */ + +void dev_jz4740_gpio_setirq (int irq) +{ + int group_no; + int pin_no; + + ASSERT ((irq >= IRQ_GPIO_0) + && (irq < IRQ_GPIO_0 + 128), "wrong gpio irq 0x%x\n", irq); + + group_no = (irq - IRQ_GPIO_0) / 32; + pin_no = (irq - IRQ_GPIO_0) % 32; + jz4740_gpio_table[GPIO_PXFLG (group_no) / 4] |= 1 << pin_no; +} + +void dev_jz4740_gpio_clearirq (int irq) +{ + int group_no; + int pin_no; + + ASSERT ((irq >= IRQ_GPIO_0) + && (irq < IRQ_GPIO_0 + 128), "wrong gpio irq 0x%x\n", irq); + + group_no = (irq - IRQ_GPIO_0) / 32; + pin_no = (irq - IRQ_GPIO_0) % 32; + jz4740_gpio_table[GPIO_PXFLG (group_no) / 4] &= ~(1 << pin_no); +} + +void *dev_jz4740_gpio_access (cpu_mips_t * cpu, struct vdevice *dev, + m_uint32_t offset, u_int op_size, u_int op_type, m_reg_t * data, + m_uint8_t * has_set_value) +{ + + struct jz4740_gpio_data *d = dev->priv_data; + + m_uint8_t group; + m_uint32_t mask, mask_data, temp; + + if (offset >= d->jz4740_gpio_size) { + *data = 0; + return NULL; + } +#if VALIDE_GPIO_OPERATION + if (op_type == MTS_WRITE) { + ASSERT (offset != GPIO_PXPIN (0), + "Write to read only register in GPIO. offset %x\n", offset); + ASSERT (offset != GPIO_PXPIN (1), + "Write to read only register in GPIO. offset %x\n", offset); + ASSERT (offset != GPIO_PXPIN (2), + "Write to read only register in GPIO. offset %x\n", offset); + ASSERT (offset != GPIO_PXPIN (3), + "Write to read only register in GPIO. offset %x\n", offset); + + ASSERT (offset != GPIO_PXDAT (0), + "Write to read only register in GPIO. offset %x\n", offset); + ASSERT (offset != GPIO_PXDAT (1), + "Write to read only register in GPIO. offset %x\n", offset); + ASSERT (offset != GPIO_PXDAT (2), + "Write to read only register in GPIO. offset %x\n", offset); + ASSERT (offset != GPIO_PXDAT (3), + "Write to read only register in GPIO. offset %x\n", offset); + + ASSERT (offset != GPIO_PXIM (0), + "Write to read only register in GPIO. offset %x\n", offset); + ASSERT (offset != GPIO_PXIM (1), + "Write to read only register in GPIO. offset %x\n", offset); + ASSERT (offset != GPIO_PXIM (2), + "Write to read only register in GPIO. offset %x\n", offset); + ASSERT (offset != GPIO_PXIM (3), + "Write to read only register in GPIO. offset %x\n", offset); + + ASSERT (offset != GPIO_PXPE (0), + "Write to read only register in GPIO. offset %x\n", offset); + ASSERT (offset != GPIO_PXPE (1), + "Write to read only register in GPIO. offset %x\n", offset); + ASSERT (offset != GPIO_PXPE (2), + "Write to read only register in GPIO. offset %x\n", offset); + ASSERT (offset != GPIO_PXPE (3), + "Write to read only register in GPIO. offset %x\n", offset); + + ASSERT (offset != GPIO_PXFUN (0), + "Write to read only register in GPIO. offset %x\n", offset); + ASSERT (offset != GPIO_PXFUN (1), + "Write to read only register in GPIO. offset %x\n", offset); + ASSERT (offset != GPIO_PXFUN (2), + "Write to read only register in GPIO. offset %x\n", offset); + ASSERT (offset != GPIO_PXFUN (3), + "Write to read only register in GPIO. offset %x\n", offset); + + ASSERT (offset != GPIO_PXSEL (0), + "Write to read only register in GPIO. offset %x\n", offset); + ASSERT (offset != GPIO_PXSEL (1), + "Write to read only register in GPIO. offset %x\n", offset); + ASSERT (offset != GPIO_PXSEL (2), + "Write to read only register in GPIO. offset %x\n", offset); + ASSERT (offset != GPIO_PXSEL (3), + "Write to read only register in GPIO. offset %x\n", offset); + + ASSERT (offset != GPIO_PXDIR (0), + "Write to read only register in GPIO. offset %x\n", offset); + ASSERT (offset != GPIO_PXDIR (1), + "Write to read only register in GPIO. offset %x\n", offset); + ASSERT (offset != GPIO_PXDIR (2), + "Write to read only register in GPIO. offset %x\n", offset); + ASSERT (offset != GPIO_PXDIR (3), + "Write to read only register in GPIO. offset %x\n", offset); + + ASSERT (offset != GPIO_PXTRG (0), + "Write to read only register in GPIO. offset %x\n", offset); + ASSERT (offset != GPIO_PXTRG (1), + "Write to read only register in GPIO. offset %x\n", offset); + ASSERT (offset != GPIO_PXTRG (2), + "Write to read only register in GPIO. offset %x\n", offset); + ASSERT (offset != GPIO_PXTRG (3), + "Write to read only register in GPIO. offset %x\n", offset); + + ASSERT (offset != GPIO_PXFLG (0), + "Write to read only register in GPIO. offset %x\n", offset); + ASSERT (offset != GPIO_PXFLG (1), + "Write to read only register in GPIO. offset %x\n", offset); + ASSERT (offset != GPIO_PXFLG (2), + "Write to read only register in GPIO. offset %x\n", offset); + ASSERT (offset != GPIO_PXFLG (3), + "Write to read only register in GPIO. offset %x\n", offset); + + } + if (op_type == MTS_READ) { + ASSERT (offset != GPIO_PXDATS (0), + "Read write only register in GPIO. offset %x\n", offset); + ASSERT (offset != GPIO_PXDATS (0), + "Read write only register in GPIO. offset %x\n", offset); + ASSERT (offset != GPIO_PXDATS (0), + "Read write only register in GPIO. offset %x\n", offset); + ASSERT (offset != GPIO_PXDATS (0), + "Read write only register in GPIO. offset %x\n", offset); + + ASSERT (offset != GPIO_PXDATC (0), + "Read write only register in GPIO. offset %x\n", offset); + ASSERT (offset != GPIO_PXDATC (0), + "Read write only register in GPIO. offset %x\n", offset); + ASSERT (offset != GPIO_PXDATC (0), + "Read write only register in GPIO. offset %x\n", offset); + ASSERT (offset != GPIO_PXDATC (0), + "Read write only register in GPIO. offset %x\n", offset); + + ASSERT (offset != GPIO_PXIMS (0), + "Read write only register in GPIO. offset %x\n", offset); + ASSERT (offset != GPIO_PXIMS (0), + "Read write only register in GPIO. offset %x\n", offset); + ASSERT (offset != GPIO_PXIMS (0), + "Read write only register in GPIO. offset %x\n", offset); + ASSERT (offset != GPIO_PXIMS (0), + "Read write only register in GPIO. offset %x\n", offset); + + ASSERT (offset != GPIO_PXIMC (0), + "Read write only register in GPIO. offset %x\n", offset); + ASSERT (offset != GPIO_PXIMC (0), + "Read write only register in GPIO. offset %x\n", offset); + ASSERT (offset != GPIO_PXIMC (0), + "Read write only register in GPIO. offset %x\n", offset); + ASSERT (offset != GPIO_PXIMC (0), + "Read write only register in GPIO. offset %x\n", offset); + + ASSERT (offset != GPIO_PXPES (0), + "Read write only register in GPIO. offset %x\n", offset); + ASSERT (offset != GPIO_PXPES (0), + "Read write only register in GPIO. offset %x\n", offset); + ASSERT (offset != GPIO_PXPES (0), + "Read write only register in GPIO. offset %x\n", offset); + ASSERT (offset != GPIO_PXPES (0), + "Read write only register in GPIO. offset %x\n", offset); + + ASSERT (offset != GPIO_PXPEC (0), + "Read write only register in GPIO. offset %x\n", offset); + ASSERT (offset != GPIO_PXPEC (0), + "Read write only register in GPIO. offset %x\n", offset); + ASSERT (offset != GPIO_PXPEC (0), + "Read write only register in GPIO. offset %x\n", offset); + ASSERT (offset != GPIO_PXPEC (0), + "Read write only register in GPIO. offset %x\n", offset); + + ASSERT (offset != GPIO_PXFUNS (0), + "Read write only register in GPIO. offset %x\n", offset); + ASSERT (offset != GPIO_PXFUNS (0), + "Read write only register in GPIO. offset %x\n", offset); + ASSERT (offset != GPIO_PXFUNS (0), + "Read write only register in GPIO. offset %x\n", offset); + ASSERT (offset != GPIO_PXFUNS (0), + "Read write only register in GPIO. offset %x\n", offset); + + ASSERT (offset != GPIO_PXFUNC (0), + "Read write only register in GPIO. offset %x\n", offset); + ASSERT (offset != GPIO_PXFUNC (0), + "Read write only register in GPIO. offset %x\n", offset); + ASSERT (offset != GPIO_PXFUNC (0), + "Read write only register in GPIO. offset %x\n", offset); + ASSERT (offset != GPIO_PXFUNC (0), + "Read write only register in GPIO. offset %x\n", offset); + + ASSERT (offset != GPIO_PXDIRS (0), + "Read write only register in GPIO. offset %x\n", offset); + ASSERT (offset != GPIO_PXDIRS (0), + "Read write only register in GPIO. offset %x\n", offset); + ASSERT (offset != GPIO_PXDIRS (0), + "Read write only register in GPIO. offset %x\n", offset); + ASSERT (offset != GPIO_PXDIRS (0), + "Read write only register in GPIO. offset %x\n", offset); + + ASSERT (offset != GPIO_PXDIRC (0), + "Read write only register in GPIO. offset %x\n", offset); + ASSERT (offset != GPIO_PXDIRC (0), + "Read write only register in GPIO. offset %x\n", offset); + ASSERT (offset != GPIO_PXDIRC (0), + "Read write only register in GPIO. offset %x\n", offset); + ASSERT (offset != GPIO_PXDIRC (0), + "Read write only register in GPIO. offset %x\n", offset); + + ASSERT (offset != GPIO_PXTRGS (0), + "Read write only register in GPIO. offset %x\n", offset); + ASSERT (offset != GPIO_PXTRGS (0), + "Read write only register in GPIO. offset %x\n", offset); + ASSERT (offset != GPIO_PXTRGS (0), + "Read write only register in GPIO. offset %x\n", offset); + ASSERT (offset != GPIO_PXTRGS (0), + "Read write only register in GPIO. offset %x\n", offset); + + ASSERT (offset != GPIO_PXTRGC (0), + "Read write only register in GPIO. offset %x\n", offset); + ASSERT (offset != GPIO_PXTRGC (0), + "Read write only register in GPIO. offset %x\n", offset); + ASSERT (offset != GPIO_PXTRGC (0), + "Read write only register in GPIO. offset %x\n", offset); + ASSERT (offset != GPIO_PXTRGC (0), + "Read write only register in GPIO. offset %x\n", offset); + + ASSERT (offset != GPIO_PXFLGC (0), + "Read write only register in GPIO. offset %x\n", offset); + ASSERT (offset != GPIO_PXFLGC (0), + "Read write only register in GPIO. offset %x\n", offset); + ASSERT (offset != GPIO_PXFLGC (0), + "Read write only register in GPIO. offset %x\n", offset); + ASSERT (offset != GPIO_PXFLGC (0), + "Read write only register in GPIO. offset %x\n", offset); + + } +#endif + + if (op_type == MTS_READ) { + +#ifdef SIM_PAVO +/*PAVO GPIO(C) PIN 30 -> NAND FLASH R/B. */ + if (offset == GPIO_PXPIN (2)) { + /*FOR NAND FLASH.PIN 30 ----|_____|------ */ + temp = jz4740_gpio_table[GPIO_PXPIN (2) / 4]; + temp &= 0x40000000; + if (temp) + temp &= ~0x40000000; + else + temp |= 0x40000000; + jz4740_gpio_table[GPIO_PXPIN (2) / 4] = temp; + } +#endif + + return ((void *) (d->jz4740_gpio_ptr + offset)); + } else if (op_type == MTS_WRITE) { + switch (op_size) { + case 1: + mask = 0xff; + break; + case 2: + mask = 0xffff; + break; + case 4: + mask = 0xffffffff; + break; + default: + assert (0); + } + + switch (offset) { + case GPIO_PXDATS (0): + case GPIO_PXDATS (1): + case GPIO_PXDATS (2): + case GPIO_PXDATS (3): + group = offset / 0x100; + mask_data = (*data) & mask; + jz4740_gpio_table[GPIO_PXDAT (group) / 4] |= mask_data; + break; + + case GPIO_PXDATC (0): + case GPIO_PXDATC (1): + case GPIO_PXDATC (2): + case GPIO_PXDATC (3): + group = offset / 0x100; + mask_data = (*data) & mask; + mask_data = ~(mask_data); + jz4740_gpio_table[GPIO_PXDAT (group) / 4] &= mask_data; + break; + + case GPIO_PXIMS (0): + case GPIO_PXIMS (1): + case GPIO_PXIMS (2): + case GPIO_PXIMS (3): + group = offset / 0x100; + mask_data = (*data) & mask; + jz4740_gpio_table[GPIO_PXIM (group) / 4] |= mask_data; + break; + + case GPIO_PXIMC (0): + case GPIO_PXIMC (1): + case GPIO_PXIMC (2): + case GPIO_PXIMC (3): + group = offset / 0x100; + mask_data = (*data) & mask; + mask_data = ~(mask_data); + jz4740_gpio_table[GPIO_PXIM (group) / 4] &= mask_data; + break; + + case GPIO_PXPES (0): + case GPIO_PXPES (1): + case GPIO_PXPES (2): + case GPIO_PXPES (3): + group = offset / 0x100; + mask_data = (*data) & mask; + jz4740_gpio_table[GPIO_PXPE (group) / 4] |= mask_data; + break; + + case GPIO_PXPEC (0): + case GPIO_PXPEC (1): + case GPIO_PXPEC (2): + case GPIO_PXPEC (3): + group = offset / 0x100; + mask_data = (*data) & mask; + mask_data = ~(mask_data); + jz4740_gpio_table[GPIO_PXPE (group) / 4] &= mask_data; + break; + + case GPIO_PXFUNS (0): + case GPIO_PXFUNS (1): + case GPIO_PXFUNS (2): + case GPIO_PXFUNS (3): + group = offset / 0x100; + mask_data = (*data) & mask; + jz4740_gpio_table[GPIO_PXFUN (group) / 4] |= mask_data; + break; + + case GPIO_PXFUNC (0): + case GPIO_PXFUNC (1): + case GPIO_PXFUNC (2): + case GPIO_PXFUNC (3): + group = offset / 0x100; + mask_data = (*data) & mask; + mask_data = ~(mask_data); + jz4740_gpio_table[GPIO_PXFUN (group) / 4] &= mask_data; + break; + + case GPIO_PXSELS (0): + case GPIO_PXSELS (1): + case GPIO_PXSELS (2): + case GPIO_PXSELS (3): + group = offset / 0x100; + mask_data = (*data) & mask; + jz4740_gpio_table[GPIO_PXSEL (group) / 4] |= mask_data; + break; + + case GPIO_PXSELC (0): + case GPIO_PXSELC (1): + case GPIO_PXSELC (2): + case GPIO_PXSELC (3): + group = offset / 0x100; + mask_data = (*data) & mask; + mask_data = ~(mask_data); + jz4740_gpio_table[GPIO_PXSEL (group) / 4] &= mask_data; + break; + + case GPIO_PXDIRS (0): + case GPIO_PXDIRS (1): + case GPIO_PXDIRS (2): + case GPIO_PXDIRS (3): + group = offset / 0x100; + mask_data = (*data) & mask; + jz4740_gpio_table[GPIO_PXDIR (group) / 4] |= mask_data; + break; + + case GPIO_PXDIRC (0): + case GPIO_PXDIRC (1): + case GPIO_PXDIRC (2): + case GPIO_PXDIRC (3): + group = offset / 0x100; + mask_data = (*data) & mask; + mask_data = ~(mask_data); + jz4740_gpio_table[GPIO_PXDIR (group) / 4] &= mask_data; + break; + + case GPIO_PXTRGS (0): + case GPIO_PXTRGS (1): + case GPIO_PXTRGS (2): + case GPIO_PXTRGS (3): + group = offset / 0x100; + mask_data = (*data) & mask; + jz4740_gpio_table[GPIO_PXTRG (group) / 4] |= mask_data; + break; + + case GPIO_PXTRGC (0): + case GPIO_PXTRGC (1): + case GPIO_PXTRGC (2): + case GPIO_PXTRGC (3): + group = offset / 0x100; + mask_data = (*data) & mask; + mask_data = ~(mask_data); + jz4740_gpio_table[GPIO_PXTRG (group) / 4] &= mask_data; + break; + + case GPIO_PXFLGC (0): + case GPIO_PXFLGC (1): + case GPIO_PXFLGC (2): + case GPIO_PXFLGC (3): + group = offset / 0x100; + mask_data = (*data) & mask; + mask_data = ~(mask_data); + jz4740_gpio_table[GPIO_PXFLG (group) / 4] &= mask_data; + break; + + default: + cpu_log (cpu, "", "invalid offset in GPIO. offset %x\n", offset); + return NULL; + + } + *has_set_value = TRUE; + return NULL; + } + + return NULL; +} + +void dev_jz4740_gpio_init_defaultvalue () +{ + memset (jz4740_gpio_table, 0x0, sizeof (jz4740_gpio_table)); + + jz4740_gpio_table[GPIO_PXIM (0) / 4] = 0xffffffff; + jz4740_gpio_table[GPIO_PXIM (1) / 4] = 0xffffffff; + jz4740_gpio_table[GPIO_PXIM (2) / 4] = 0xffffffff; + jz4740_gpio_table[GPIO_PXIM (3) / 4] = 0xffffffff; + + //jz4740_gpio_table[GPIO_PXPIN(2)/4]=0x40000000; + +} + +void dev_jz4740_gpio_reset (cpu_mips_t * cpu, struct vdevice *dev) +{ + dev_jz4740_gpio_init_defaultvalue (); +} + +int dev_jz4740_gpio_init (vm_instance_t * vm, char *name, m_pa_t paddr, + m_uint32_t len) +{ + struct jz4740_gpio_data *d; + + /* allocate the private data structure */ + if (!(d = malloc (sizeof (*d)))) { + fprintf (stderr, "jz4740_gpio: unable to create device.\n"); + return (-1); + } + + memset (d, 0, sizeof (*d)); + if (!(d->dev = dev_create (name))) + goto err_dev_create; + d->dev->priv_data = d; + d->dev->phys_addr = paddr; + d->dev->phys_len = len; + d->jz4740_gpio_ptr = (m_uint8_t *) (&jz4740_gpio_table[0]); + d->jz4740_gpio_size = len; + d->dev->handler = dev_jz4740_gpio_access; + d->dev->reset_handler = dev_jz4740_gpio_reset; + d->dev->flags = VDEVICE_FLAG_NO_MTS_MMAP; + + vm_bind_device (vm, d->dev); + //dev_jz4740_gpio_init_defaultvalue(); + + return (0); + + err_dev_create: + free (d); + return (-1); +} diff --git a/tools/virtualmips/jz4740/jz4740_dev_int.c b/tools/virtualmips/jz4740/jz4740_dev_int.c new file mode 100644 index 0000000..292f937 --- /dev/null +++ b/tools/virtualmips/jz4740/jz4740_dev_int.c @@ -0,0 +1,141 @@ + /* + * Copyright (C) yajin 2008 + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + * + */ + +/*jz4740 Interrupt controller*/ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include + +#include "device.h" +#include "mips_memory.h" +#include "cpu.h" +#include "jz4740.h" + +#define VALIDE_INT_OPERATION 0 + +extern cpu_mips_t *current_cpu; +m_uint32_t jz4740_int_table[JZ4740_INT_INDEX_MAX]; + +struct jz4740_int_data { + struct vdevice *dev; + m_uint8_t *jz4740_int_ptr; + m_uint32_t jz4740_int_size; +}; + +void *dev_jz4740_int_access (cpu_mips_t * cpu, struct vdevice *dev, + m_uint32_t offset, u_int op_size, u_int op_type, m_reg_t * data, + m_uint8_t * has_set_value) +{ + + struct jz4740_int_data *d = dev->priv_data; + m_uint32_t mask_data, mask; + + if (offset >= d->jz4740_int_size) { + *data = 0; + return NULL; + } +#if VALIDE_INT_OPERATION + if (op_type == MTS_WRITE) { + ASSERT (offset != INTC_ISR, + "Write to read only register in INT. offset %x\n", offset); + ASSERT (offset != INTC_IPR, + "Write to read only register in INT. offset %x\n", offset); + } else if (op_type == MTS_READ) { + ASSERT (offset != INTC_IMSR, + "Read write only register in INT. offset %x\n", offset); + ASSERT (offset != INTC_IMCR, + "Read write only register in INT. offset %x\n", offset); + + } +#endif + + switch (op_size) { + case 1: + mask = 0xff; + break; + case 2: + mask = 0xffff; + break; + case 4: + mask = 0xffffffff; + break; + default: + assert (0); + } + + switch (offset) { + case INTC_IMSR: /*set */ + assert (op_type == MTS_WRITE); + mask_data = (*data) & mask; + jz4740_int_table[INTC_IMR / 4] |= mask_data; + *has_set_value = TRUE; + break; + case INTC_IMCR: /*clear */ + assert (op_type == MTS_WRITE); + mask_data = (*data) & mask; + mask_data = ~(mask_data); + jz4740_int_table[INTC_IMR / 4] &= mask_data; + *has_set_value = TRUE; + break; + case INTC_IPR: /*clear */ + *data = jz4740_int_table[INTC_IPR / 4]; + jz4740_int_table[INTC_IPR / 4] = 0; + *has_set_value = TRUE; + return NULL; + default: + return ((void *) (d->jz4740_int_ptr + offset)); + } + return NULL; +} + +void dev_jz4740_int_init_defaultvalue () +{ + memset (jz4740_int_table, 0x0, sizeof (jz4740_int_table)); + jz4740_int_table[INTC_IMR / 4] = 0xffffffff; +} + +void dev_jz4740_int_reset (cpu_mips_t * cpu, struct vdevice *dev) +{ + dev_jz4740_int_init_defaultvalue (); +} + +int dev_jz4740_int_init (vm_instance_t * vm, char *name, m_pa_t paddr, + m_uint32_t len) +{ + struct jz4740_int_data *d; + + /* allocate the private data structure */ + if (!(d = malloc (sizeof (*d)))) { + fprintf (stderr, "jz4740_dma: unable to create device.\n"); + return (-1); + } + + memset (d, 0, sizeof (*d)); + if (!(d->dev = dev_create (name))) + goto err_dev_create; + d->dev->priv_data = d; + d->dev->phys_addr = paddr; + d->dev->phys_len = len; + d->jz4740_int_ptr = (m_uint8_t *) (&jz4740_int_table[0]); + d->jz4740_int_size = len; + d->dev->handler = dev_jz4740_int_access; + d->dev->reset_handler = dev_jz4740_int_reset; + d->dev->flags = VDEVICE_FLAG_NO_MTS_MMAP; + + vm_bind_device (vm, d->dev); + return (0); + + err_dev_create: + free (d); + return (-1); +} diff --git a/tools/virtualmips/jz4740/jz4740_dev_lcd.c b/tools/virtualmips/jz4740/jz4740_dev_lcd.c new file mode 100644 index 0000000..07d9f55 --- /dev/null +++ b/tools/virtualmips/jz4740/jz4740_dev_lcd.c @@ -0,0 +1,246 @@ + /* + * Copyright (C) yajin 2008 + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + * + */ + +#ifdef SIM_LCD +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include + +#include "device.h" +#include "mips_memory.h" +#include "cpu.h" +#include "jz4740.h" +#include "vp_sdl.h" +#include "vp_timer.h" +#include "utils.h" + +int dev_jz4740_ts_init (vm_instance_t * vm, char *name, m_pa_t paddr, + m_uint32_t len, struct DisplayState *ds); + +#define LCD_TIMEOUT 500 //MS + +#define LCD_WIDTH 480 +#define LCD_HEIGHT 272 +#define LCD_BPP 32 /*32 bit per pixel */ + +extern cpu_mips_t *current_cpu; + +m_uint32_t jz4740_lcd_table[JZ4740_LCD_INDEX_MAX]; +struct jz_fb_dma_descriptor { + m_uint32_t fdadr; /* Frame descriptor address register */ + m_uint32_t fsadr; /* Frame source address register */ + m_uint32_t fidr; /* Frame ID register */ + m_uint32_t ldcmd; /* Command register */ + +}; + +struct jz4740_lcd_data { + struct vdevice *dev; + m_uint8_t *jz4740_lcd_ptr; + m_uint32_t jz4740_lcd_size; + vp_timer_t *lcd_timer; + struct DisplayState *ds; + m_uint16_t vde, vds, hds, hde; +}; + +void dev_jz4740_lcd_init_defaultvalue () +{ + memset (jz4740_lcd_table, 0x0, sizeof (jz4740_lcd_table)); + +} + +void dev_jz4740_active_lcd (struct jz4740_lcd_data *d) +{ + vp_mod_timer (d->lcd_timer, vp_get_clock (rt_clock) + LCD_TIMEOUT); +} + +void dev_jz4740_unactive_lcd (struct jz4740_lcd_data *d) +{ + vp_del_timer (d->lcd_timer); +} + +void dev_jz4740_lcd_reset (cpu_mips_t * cpu, struct vdevice *dev) +{ + struct jz4740_lcd_data *d = dev->priv_data; + dev_jz4740_lcd_init_defaultvalue (); + dev_jz4740_unactive_lcd (d); +} + +void *dev_jz4740_lcd_access (cpu_mips_t * cpu, struct vdevice *dev, + m_uint32_t offset, u_int op_size, u_int op_type, m_reg_t * data, + m_uint8_t * has_set_value) +{ + + struct jz4740_lcd_data *d = dev->priv_data; + + if ((offset >= d->jz4740_lcd_size)) { + *data = 0; + return NULL; + } + + switch (offset) { + case LCD_CTRL: + if (op_type == MTS_WRITE) { + if (*data & LCD_CTRL_ENA) { + dev_jz4740_active_lcd (d); + } else { + dev_jz4740_unactive_lcd (d); + jz4740_lcd_table[LCD_STATE / 4] |= LCD_STATE_QD; + /*INTERRUPT*/ if ((jz4740_lcd_table[LCD_CTRL / + 4] & LCD_CTRL_QDM) == 0x0) { + current_cpu->vm->set_irq (current_cpu->vm, IRQ_LCD); + } + + } + + if (*data & LCD_CTRL_DIS) { + dev_jz4740_unactive_lcd (d); + jz4740_lcd_table[LCD_STATE / 4] |= LCD_STATE_LDD; + /*INTERRUPT*/ if ((jz4740_lcd_table[LCD_CTRL / + 4] & LCD_CTRL_LDDM) == 0x0) { + current_cpu->vm->set_irq (current_cpu->vm, IRQ_LCD); + } + + } + + if ((*data & LCD_CTRL_BPP_MASK) == LCD_CTRL_BPP_16) { + d->ds->depth = 16; + dpy_resize (d->ds, d->ds->width, d->ds->height); + + } else if ((*data & LCD_CTRL_BPP_MASK) == LCD_CTRL_BPP_18_24) { + d->ds->depth = 32; + dpy_resize (d->ds, d->ds->width, d->ds->height); + } else { + ASSERT (0, "errror bpp \n"); + } + + } + break; + case LCD_DAH: + if (op_type == MTS_WRITE) { + d->hde = (*data & LCD_DAH_HDE_MASK) >> LCD_DAH_HDE_BIT; + d->hds = (*data & LCD_DAH_HDS_MASK) >> LCD_DAH_HDS_BIT; + ASSERT (d->hde > d->hds, "hde < hds hde %x hds %x \n", d->hde, + d->hds); + d->ds->width = d->hde - d->hds; + ASSERT (d->ds->width > 0, "d->ds->width<=0 %x \n", + d->ds->width); + ASSERT (d->ds->height > 0, "d->ds->height<=0 %x \n", + d->ds->height); + dpy_resize (d->ds, d->ds->width, d->ds->height); + + } + break; + case LCD_DAV: + if (op_type == MTS_WRITE) { + d->vde = (*data & LCD_DAV_VDE_MASK) >> LCD_DAV_VDE_BIT; + d->vds = (*data & LCD_DAV_VDS_MASK) >> LCD_DAV_VDS_BIT; + ASSERT (d->vde > d->vds, "vde < vds vde %x vds %x \n", d->vde, + d->vds); + d->ds->height = d->vde - d->vds; + ASSERT (d->ds->width > 0, "d->ds->width<=0 %x \n", + d->ds->width); + ASSERT (d->ds->height > 0, "d->ds->height<=0 %x \n", + d->ds->height); + dpy_resize (d->ds, d->ds->width, d->ds->height); + } + break; + + } + + return ((void *) (d->jz4740_lcd_ptr + offset)); + +} + +void dev_jz4740_lcd_cb (void *opaque) +{ + struct jz4740_lcd_data *d = opaque; + struct jz_fb_dma_descriptor *lcda0_desc = NULL; + m_uint8_t *src_data; + m_uint32_t dummy; + + lcda0_desc = + (struct jz_fb_dma_descriptor *) physmem_get_hptr (current_cpu->vm, + jz4740_lcd_table[LCD_DA0 / 4], 0, MTS_READ, &dummy); + src_data = + physmem_get_hptr (current_cpu->vm, lcda0_desc->fsadr, 0, MTS_READ, + &dummy); + + ASSERT (src_data != NULL, + "dev_jz4740_lcd_cb can not get framebuffer src data\n"); + jz4740_lcd_table[LCD_SA0 / 4] = lcda0_desc->fsadr; + jz4740_lcd_table[LCD_FID0 / 4] = lcda0_desc->fidr; + jz4740_lcd_table[LCD_CMD0 / 4] = lcda0_desc->ldcmd; + + ASSERT ((((jz4740_lcd_table[LCD_CTRL / 4] & LCD_CTRL_BPP_MASK) == + LCD_CTRL_BPP_16) + || ((jz4740_lcd_table[LCD_CTRL / 4] & LCD_CTRL_BPP_MASK) == + LCD_CTRL_BPP_18_24)), "Only 15/16/18/24 bpp supproted\n"); + memcpy (d->ds->data, src_data, + d->ds->height * d->ds->width * d->ds->depth / 8); + dpy_update (d->ds, 0, 0, 0, 0); + jz4740_lcd_table[LCD_STATE / 4] |= LCD_STATE_EOF; + if ((jz4740_lcd_table[LCD_CMD0 / 4] & LCD_CMD_EOFINT) + && ((jz4740_lcd_table[LCD_CTRL / 4] & LCD_CTRL_EOFM) == 0x0)) { + current_cpu->vm->set_irq (current_cpu->vm, IRQ_LCD); + } + dev_jz4740_active_lcd (d); + +} + +int dev_jz4740_lcd_init (vm_instance_t * vm, char *name, m_pa_t paddr, + m_uint32_t len) +{ + struct jz4740_lcd_data *d; + + /* allocate the private data structure */ + if (!(d = malloc (sizeof (*d)))) { + fprintf (stderr, "jz4740_lcd: unable to create device.\n"); + return (-1); + } + + memset (d, 0, sizeof (*d)); + if (!(d->dev = dev_create (name))) + goto err_dev_create; + d->dev->priv_data = d; + d->dev->phys_addr = paddr; + d->dev->phys_len = len; + d->jz4740_lcd_ptr = (m_uint8_t *) (&jz4740_lcd_table[0]); + d->jz4740_lcd_size = len; + d->dev->handler = dev_jz4740_lcd_access; + d->dev->reset_handler = dev_jz4740_lcd_reset; + d->dev->flags = VDEVICE_FLAG_NO_MTS_MMAP; + d->lcd_timer = vp_new_timer (rt_clock, dev_jz4740_lcd_cb, d); + + d->ds = malloc (sizeof (*d->ds)); + if (d->ds == NULL) + goto err_dev_create; + d->ds->width = LCD_WIDTH; + d->ds->height = LCD_HEIGHT; + d->ds->depth = 32; + sdl_display_init (d->ds, 0); + + vm_bind_device (vm, d->dev); + + /*Init jz4740 internal TS */ + if (dev_jz4740_ts_init (vm, "JZ4740 TS", JZ4740_TS_BASE, JZ4740_TS_SIZE, + d->ds) == -1) + goto err_dev_create; + + return (0); + + err_dev_create: + free (d); + return (-1); +} + +#endif diff --git a/tools/virtualmips/jz4740/jz4740_dev_rtc.c b/tools/virtualmips/jz4740/jz4740_dev_rtc.c new file mode 100644 index 0000000..47cb8a0 --- /dev/null +++ b/tools/virtualmips/jz4740/jz4740_dev_rtc.c @@ -0,0 +1,207 @@ + /* + * Copyright (C) yajin 2008 + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + * + */ + +/*RTC. */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include + +#include "device.h" +#include "mips_memory.h" +#include "cpu.h" +#include "jz4740.h" +#include "vp_timer.h" + +#define RTC_TIMEOUT 1000 //1000MS=1S +extern cpu_mips_t *current_cpu; +m_uint32_t jz4740_rtc_table[JZ4740_RTC_INDEX_MAX]; + +struct jz4740_rtc_data { + struct vdevice *dev; + m_uint8_t *jz4740_rtc_ptr; + m_uint32_t jz4740_rtc_size; + vp_timer_t *rtc_timer; + +}; +static const unsigned int sum_monthday[13] = { + 0, + 31, + 31 + 28, + 31 + 28 + 31, + 31 + 28 + 31 + 30, + 31 + 28 + 31 + 30 + 31, + 31 + 28 + 31 + 30 + 31 + 30, + 31 + 28 + 31 + 30 + 31 + 30 + 31, + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31, + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30, + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31, + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30, + 365 +}; +static const unsigned int yearday[5] = + { 0, 366, 366 + 365, 366 + 365 * 2, 366 + 365 * 3 }; +static const unsigned int sweekday = 6; +unsigned int forced_inline jz_mktime (int year, int mon, int day, int hour, + int min, int sec) +{ + unsigned int seccounter; + + if (year < 2000) + year = 2000; + year -= 2000; + seccounter = (year / 4) * (365 * 3 + 366); + seccounter += yearday[year % 4]; + if (year % 4) + seccounter += sum_monthday[mon - 1]; + else if (mon >= 3) + seccounter += sum_monthday[mon - 1] + 1; /* Feb is 29 days. */ + else + seccounter += sum_monthday[mon - 1]; + seccounter += day - 1; + seccounter *= 24; + seccounter += hour; + seccounter *= 60; + seccounter += min; + seccounter *= 60; + seccounter += sec; + + return seccounter; +} + +/*Set RTC Time. From Year 2000.*/ +void dev_jz4740_rtc_init_defaultvalue () +{ + time_t timep; + struct tm *p; + + memset (jz4740_rtc_table, 0x0, sizeof (jz4740_rtc_table)); + /*Set RTC value to current time */ + time (&timep); + p = localtime (&timep); + jz4740_rtc_table[RTC_RSR / 4] = + jz_mktime ((1900 + p->tm_year), (1 + p->tm_mon), p->tm_mday, + p->tm_hour, p->tm_min, p->tm_sec); + +} + +void dev_jz4740_rtc_reset (cpu_mips_t * cpu, struct vdevice *dev) +{ + dev_jz4740_rtc_init_defaultvalue (); +} + +void dev_jz4740_active_rtc (struct jz4740_rtc_data *d) +{ + vp_mod_timer (d->rtc_timer, vp_get_clock (rt_clock) + RTC_TIMEOUT); +} + +void dev_jz4740_unactive_rtc (struct jz4740_rtc_data *d) +{ + vp_del_timer (d->rtc_timer); +} + +void *dev_jz4740_rtc_access (cpu_mips_t * cpu, struct vdevice *dev, + m_uint32_t offset, u_int op_size, u_int op_type, m_reg_t * data, + m_uint8_t * has_set_value) +{ + + struct jz4740_rtc_data *d = dev->priv_data; + if (offset >= d->jz4740_rtc_size) { + *data = 0; + return NULL; + } + + switch (offset) { + case RTC_RCR: + if (op_type == MTS_READ) { + /*RTC_RCR (RTC_RCR_WRDY )=1 bit 7 */ + jz4740_rtc_table[RTC_RCR / 4] |= RTC_RCR_WRDY; + } else if (op_type == MTS_WRITE) { + if (*data & RTC_RCR_RTCE) { + dev_jz4740_active_rtc (d); + } else { + dev_jz4740_unactive_rtc (d); + } + } + break; + + } + + return ((void *) (d->jz4740_rtc_ptr + offset)); + +} + +void dev_jz4740_rtc_cb (void *opaque) +{ + struct jz4740_rtc_data *d = opaque; + time_t timep; + struct tm *p; + + if (jz4740_rtc_table[RTC_RCR / 4] & RTC_RCR_RTCE) { + //rtc enable + jz4740_rtc_table[RTC_RCR / 4] |= RTC_RCR_1HZ; + if (jz4740_rtc_table[RTC_RCR / 4] & RTC_RCR_1HZIE) { + current_cpu->vm->set_irq (current_cpu->vm, IRQ_RTC); + } + + time (&timep); + p = localtime (&timep); + /*always get the current time from host */ + jz4740_rtc_table[RTC_RSR / 4] = + jz_mktime ((1900 + p->tm_year), (1 + p->tm_mon), p->tm_mday, + p->tm_hour, p->tm_min, p->tm_sec); + if (jz4740_rtc_table[RTC_RSR / 4] == jz4740_rtc_table[RTC_RSAR / 4]) { + if (jz4740_rtc_table[RTC_RCR / 4] & RTC_RCR_AE) { + jz4740_rtc_table[RTC_RCR / 4] |= RTC_RCR_AF; + if (jz4740_rtc_table[RTC_RCR / 4] & RTC_RCR_AIE) { + current_cpu->vm->set_irq (current_cpu->vm, IRQ_RTC); + } + } + } + } + dev_jz4740_active_rtc (d); + +} + +int dev_jz4740_rtc_init (vm_instance_t * vm, char *name, m_pa_t paddr, + m_uint32_t len) +{ + struct jz4740_rtc_data *d; + + /* allocate the private data structure */ + if (!(d = malloc (sizeof (*d)))) { + fprintf (stderr, "jz4740_rtc: unable to create device.\n"); + return (-1); + } + + memset (d, 0, sizeof (*d)); + if (!(d->dev = dev_create (name))) + goto err_dev_create; + d->dev->priv_data = d; + d->dev->phys_addr = paddr; + d->dev->phys_len = len; + d->jz4740_rtc_ptr = (m_uint8_t *) (&jz4740_rtc_table[0]); + d->jz4740_rtc_size = len; + d->dev->handler = dev_jz4740_rtc_access; + d->dev->reset_handler = dev_jz4740_rtc_reset; + d->dev->flags = VDEVICE_FLAG_NO_MTS_MMAP; + d->rtc_timer = vp_new_timer (rt_clock, dev_jz4740_rtc_cb, d); + + vm_bind_device (vm, d->dev); + dev_jz4740_rtc_init_defaultvalue (); + + return (0); + + err_dev_create: + free (d); + return (-1); +} diff --git a/tools/virtualmips/jz4740/jz4740_dev_ts.c b/tools/virtualmips/jz4740/jz4740_dev_ts.c new file mode 100644 index 0000000..bafea85 --- /dev/null +++ b/tools/virtualmips/jz4740/jz4740_dev_ts.c @@ -0,0 +1,235 @@ + /* + * Copyright (C) yajin 2008 + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + * + */ + +#ifdef SIM_LCD +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include + +#include "device.h" +#include "mips_memory.h" +#include "cpu.h" +#include "jz4740.h" +#include "vp_sdl.h" +#include "vp_timer.h" +#include "utils.h" + +extern cpu_mips_t *current_cpu; + +#define TSMAXX 4096 +#define TSMAXY 4096 +#define TSMINX 0 +#define TSMINY 0 + +#define TS_TIMEOUT 15 //MS +m_uint32_t jz4740_ts_table[JZ4740_TS_INDEX_MAX]; + +#define MOUSE_DOWN 1 +#define MOUSE_UP 2 +#define MOUSE_MOVE 3 +struct jz4740_ts_data { + struct vdevice *dev; + m_uint8_t *jz4740_ts_ptr; + m_uint32_t jz4740_ts_size; + vp_timer_t *ts_timer; + + m_uint8_t xyz; /*xyz of cfg */ + m_uint8_t snum; /*snum of cfg */ + + m_uint8_t read_index; + m_uint32_t x, y; + + /*mouse status */ + m_uint8_t mouse_status; + + struct DisplayState *ds; +}; + +void dev_jz4740_active_ts (struct jz4740_ts_data *d) +{ + vp_mod_timer (d->ts_timer, vp_get_clock (rt_clock) + TS_TIMEOUT); +} + +void dev_jz4740_unactive_ts (struct jz4740_ts_data *d) +{ + vp_del_timer (d->ts_timer); +} + +void dev_jz4740_ts_cb (void *opaque) +{ + struct jz4740_ts_data *d = opaque; + SDL_Event *ts_ev; + if ((jz4740_ts_table[SADC_ENA / 4] & SADC_ENA_TSEN)) { + if ((jz4740_ts_table[SADC_CTRL / 4] & SADC_CTRL_PENDM) == 0) { + ts_ev = sdl_getmouse_down (); + /*Pen down interrupt */ + if (ts_ev != NULL) { + d->x = + ((ts_ev->button.x) * (TSMAXX - TSMINX) / d->ds->width) + + TSMINX; + d->y = + ((ts_ev->button.y) * (TSMAXY - TSMINY) / d->ds->height) + + TSMINY; + if (d->x > TSMAXX) + d->x = TSMAXX; + if (d->y > TSMAXY) + d->y = TSMAXY; + + /*Interrupt */ + current_cpu->vm->set_irq (current_cpu->vm, IRQ_SADC); + jz4740_ts_table[SADC_STATE / 4] |= + (SADC_STATE_PEND | SADC_STATE_TSRDY); + } + } + + if ((jz4740_ts_table[SADC_CTRL / 4] & SADC_CTRL_PENUM) == 0) { + /*Pen UP interrupt */ + if (d->read_index == 0) { + /* + * TODO: Mouse up checking. + * We do not check whether mouse up. JUST assume when clicked, it is always mouseup. + * Can not use hand writing in qtopia. + */ + /*Interrupt */ + current_cpu->vm->set_irq (current_cpu->vm, IRQ_SADC); + jz4740_ts_table[SADC_STATE / 4] |= + (SADC_STATE_PENU | SADC_STATE_TSRDY); + + } + } + + } + + dev_jz4740_active_ts (d); + +} + +void dev_jz4740_ts_init_defaultvalue () +{ + memset (jz4740_ts_table, 0x0, sizeof (jz4740_ts_table)); + +} + +void dev_jz4740_ts_reset (cpu_mips_t * cpu, struct vdevice *dev) +{ + dev_jz4740_ts_init_defaultvalue (); +} + +void *dev_jz4740_ts_access (cpu_mips_t * cpu, struct vdevice *dev, + m_uint32_t offset, u_int op_size, u_int op_type, m_reg_t * data, + m_uint8_t * has_set_value) +{ + + struct jz4740_ts_data *d = dev->priv_data; + + if ((offset >= d->jz4740_ts_size)) { + *data = 0; + return NULL; + } + switch (offset) { + case SADC_ENA: + if (op_type == MTS_WRITE) { + ASSERT ((*data & SADC_ENA_TSEN), + "Only touche screen model is support in SADC \n"); + if (*data & SADC_ENA_TSEN) + dev_jz4740_active_ts (d); + else + dev_jz4740_unactive_ts (d); + } + break; + case SADC_CFG: + if (op_type == MTS_WRITE) { + ASSERT ((*data & SADC_CFG_TS_DMA) == 0x0, + "Only touche screen model is support in SADC \n"); + ASSERT ((*data & SADC_CFG_XYZ_MASK) != (3 << SADC_CFG_XYZ_BIT), + "XYZ =3 is not support \n"); + ASSERT ((*data & SADC_CFG_XYZ_MASK) != (2 << SADC_CFG_XYZ_BIT), + "XYZ =2 is not support \n"); + + d->xyz = (*data & SADC_CFG_XYZ_MASK) >> SADC_CFG_XYZ_BIT; + d->snum = ((*data & SADC_CFG_SNUM_MASK) >> SADC_CFG_SNUM_BIT) + 1; + /*need read twice */ + if (d->xyz == 0x1) + d->snum *= 2; + + d->read_index = 0; + + } + break; + case SADC_STATE: + if (op_type == MTS_WRITE) { + jz4740_ts_table[SADC_STATE / 4] = ~(*data); + *has_set_value = TRUE; + return NULL; + } else { + *data = jz4740_ts_table[SADC_STATE / 4] & 0x1f; + *data |= SADC_CTRL_TSRDYM; + *has_set_value = TRUE; + return NULL; + } + break; + + case SADC_TSDAT: + if (op_type == MTS_READ) { + + if ((d->read_index % 2) == 0) { + *data = ((d->x) & 0x7fff) | ((d->y & 0x7ffff) << 16); + } else { + *data = ((500) & 0x7fff); + } + *has_set_value = TRUE; + d->read_index++; + if (d->read_index == d->snum) + d->read_index = 0; + return NULL; + } + break; + + } + return ((void *) (d->jz4740_ts_ptr + offset)); +} + +int dev_jz4740_ts_init (vm_instance_t * vm, char *name, m_pa_t paddr, + m_uint32_t len, struct DisplayState *ds) +{ + struct jz4740_ts_data *d; + + /* allocate the private data structure */ + if (!(d = malloc (sizeof (*d)))) { + fprintf (stderr, "jz4740_lcd: unable to create device.\n"); + return (-1); + } + + memset (d, 0, sizeof (*d)); + if (!(d->dev = dev_create (name))) + goto err_dev_create; + d->dev->priv_data = d; + d->dev->phys_addr = paddr; + d->dev->phys_len = len; + d->jz4740_ts_ptr = (m_uint8_t *) (&jz4740_ts_table[0]); + d->jz4740_ts_size = len; + d->dev->handler = dev_jz4740_ts_access; + d->dev->reset_handler = dev_jz4740_ts_reset; + d->dev->flags = VDEVICE_FLAG_NO_MTS_MMAP; + d->ts_timer = vp_new_timer (rt_clock, dev_jz4740_ts_cb, d); + d->ds = ds; + + vm_bind_device (vm, d->dev); + + return (0); + + err_dev_create: + free (d); + return (-1); +} + +#endif diff --git a/tools/virtualmips/jz4740/jz4740_dev_uart.c b/tools/virtualmips/jz4740/jz4740_dev_uart.c new file mode 100644 index 0000000..1447a80 --- /dev/null +++ b/tools/virtualmips/jz4740/jz4740_dev_uart.c @@ -0,0 +1,293 @@ + /* + * Copyright (C) yajin 2008 + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + * + */ + + /*JZ4740 UART Emulation. + * + * JZ4740 UART is compatible with 16c550 . + * + * Linux use uart interrupt to receive and send data. + * + * For simulator, it is a bad idea for os to use interrupt to send data . + * Because simulator is always READY for sending, so interrupt is slow than polling. + * + * + * receive: + * 1.set IER + * 2. Wating interrupt (read IIR and LSR) + * 3. if IIR says an interrupt and LSR says that data ready. read RBR. + * + * send: + * 1. set IER to enable transmit request interrupt + * 2. if UART can send data, generate an interrupt and set IIR LSR + * 3. linux receives the interrupt ,read IIR and LSR + * 4. send data. + * + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include + +#include "device.h" +#include "mips_memory.h" +#include "jz4740.h" +#include "cpu.h" +#include "vp_timer.h" + +/* Interrupt Identification Register */ +#define IIR_NPENDING 0x01 /* 0: irq pending, 1: no irq pending */ +#define IIR_TXRDY 0x02 +#define IIR_RXRDY 0x04 + +struct jz4740_uart_data { + struct vdevice *dev; + + u_int irq, duart_irq_seq; + u_int output; + + vtty_t *vtty; + vm_instance_t *vm; + + m_uint32_t ier; /*0x04 */ + m_uint32_t iir; /*0x08 */ + m_uint32_t fcr; /*0x08 */ + m_uint32_t lcr; /*0x0c */ + m_uint32_t mcr; /*0x10 */ + m_uint32_t lsr; /*0x14 */ + m_uint32_t msr; /*0x18 */ + m_uint32_t spr; /*0x1c */ + m_uint32_t isr; /*0x20 */ + m_uint32_t umr; /*0x24 */ + m_uint32_t uacr; /*0x28 */ + + m_uint32_t jz4740_uart_size; + + vp_timer_t *uart_timer; + +}; + +static void jz4740_tty_con_input (vtty_t * vtty) +{ + struct jz4740_uart_data *d = vtty->priv_data; + + if (d->ier & UART_IER_RDRIE) { + d->vm->set_irq (d->vm, d->irq); + } + d->lsr |= UART_LSR_DRY; + +} + +void *dev_jz4740_uart_access (cpu_mips_t * cpu, struct vdevice *dev, + m_uint32_t offset, u_int op_size, u_int op_type, m_reg_t * data, + m_uint8_t * has_set_value) +{ + struct jz4740_uart_data *d = dev->priv_data; + + u_char odata; + + if (offset >= d->jz4740_uart_size) { + *data = 0; + return NULL; + } + + switch (offset) { + case UART_RBR: /*0x0 RBR THR */ + if (op_type == MTS_READ) { + + *data = vtty_get_char (d->vtty); + if (vtty_is_char_avail (d->vtty)) + d->lsr |= UART_LSR_DRY; + else + d->lsr &= ~UART_LSR_DRY; + } else { + vtty_put_char (d->vtty, (char) (*data)); + if ((d->ier & UART_IER_TDRIE) && (d->output == 0) + && (d->fcr & 0x10)) { + /*yajin. + * + * In order to put the next data more quickly, just set irq not waiting for host_alarm_handler to set irq. + * Sorry uart, too much work for you. + * + * Sometimes, linux kernel prints "serial8250: too much work for irq9" if we print large data on screen. + * Please patch the kernel. comment "printk(KERN_ERR "serial8250: too much work for " + * "irq%d\n", irq);" + * qemu has some question. + * http://lkml.org/lkml/2008/1/12/135 + * http://kerneltrap.org/mailarchive/linux-kernel/2008/2/7/769924 + * + * If jit is used in future, we may not need to set irq here because simulation is quick enough. Then we have + * no "too much work for irq9" problem. + * + * + */ + d->output = TRUE; + d->vm->set_irq (d->vm, d->irq); + } + + } + + *has_set_value = TRUE; + break; + + case UART_IER: /*0x4 */ + if (op_type == MTS_READ) { + *data = d->ier; + } else { + d->ier = *data & 0xFF; + } + + *has_set_value = TRUE; + break; + + case UART_IIR: /*0x08 */ + d->vm->clear_irq (d->vm, d->irq); + if (op_type == MTS_READ) { + odata = IIR_NPENDING; + + if (vtty_is_char_avail (d->vtty)) { + odata = IIR_RXRDY; + } else { + if (d->output) { + odata = IIR_TXRDY; + d->output = 0; + } + + } + *data = odata; + } else { + d->fcr = *data; + if (d->fcr & 0x20) + d->lsr &= ~UART_LSR_DRY; + } + + *has_set_value = TRUE; + break; + + case UART_LSR: /*0x14 */ + if (op_type == MTS_READ) { + d->lsr |= UART_LSR_TDRQ | UART_LSR_TEMP; + if (vtty_is_char_avail (d->vtty)) + d->lsr |= UART_LSR_DRY; + return &(d->lsr); + } else + ASSERT (0, "WRITE TO LSR\n"); + *has_set_value = TRUE; + break; + + case UART_LCR: + return &(d->lcr); + case UART_MCR: + return &(d->mcr); + case UART_MSR: + return &(d->msr); + case UART_SPR: + return &(d->spr); + case UART_ISR: + return &(d->isr); + case UART_UMR: + return &(d->umr); + case UART_UACR: + return &(d->uacr); + + default: + ASSERT (0, "invalid uart offset %x\n", offset); + + } + + return NULL; + +} + +void dev_jz4740_uart_reset (cpu_mips_t * cpu, struct vdevice *dev) +{ + + struct jz4740_uart_data *d = dev->priv_data; + d->fcr = 0x0; + d->lcr = 0x0; + d->mcr = 0x0; + d->lsr |= UART_LSR_TDRQ | UART_LSR_TEMP; + d->msr = 0x0; + d->spr = 0x0; + d->isr = 0x0; + d->umr = 0x0; + d->uacr = 0x0; + +} + +extern cpu_mips_t *current_cpu; + +#define UART_TIME_OUT 25 +void dev_jz4740_uart_cb (void *opaque) +{ + + struct jz4740_uart_data *d = (struct jz4740_uart_data *) opaque; + + d->output = 0; + if (vtty_is_char_avail (d->vtty)) { + d->lsr |= UART_LSR_DRY; + if (d->ier & UART_IER_RDRIE) { + d->vm->set_irq (d->vm, d->irq); + vp_mod_timer (d->uart_timer, + vp_get_clock (rt_clock) + UART_TIME_OUT); + return; + } + + } + if ((d->ier & UART_IER_TDRIE) && (d->output == 0) && (d->fcr & 0x10)) { + d->output = TRUE; + d->vm->set_irq (d->vm, d->irq); + vp_mod_timer (d->uart_timer, vp_get_clock (rt_clock) + UART_TIME_OUT); + return; + } + // d->uart_timer->set_time=vp_get_clock(rt_clock); + vp_mod_timer (d->uart_timer, vp_get_clock (rt_clock) + UART_TIME_OUT); + +} + +int dev_jz4740_uart_init (vm_instance_t * vm, char *name, m_pa_t paddr, + m_uint32_t len, u_int irq, vtty_t * vtty) +{ + struct jz4740_uart_data *d; + + /* allocate the private data structure */ + if (!(d = malloc (sizeof (*d)))) { + fprintf (stderr, "JZ4740 UART: unable to create device.\n"); + return (-1); + } + memset (d, 0, sizeof (*d)); + if (!(d->dev = dev_create (name))) + goto err_dev_create; + d->dev->priv_data = d; + d->dev->phys_addr = paddr; + d->dev->phys_len = len; + d->dev->flags = VDEVICE_FLAG_NO_MTS_MMAP; + d->vm = vm; + (*d).vtty = vtty; + d->irq = irq; + vtty->priv_data = d; + d->jz4740_uart_size = len; + d->dev->handler = dev_jz4740_uart_access; + d->dev->reset_handler = dev_jz4740_uart_reset; + (*d).vtty->read_notifier = jz4740_tty_con_input; + d->uart_timer = vp_new_timer (rt_clock, dev_jz4740_uart_cb, d); + + //d->uart_timer->set_time=vp_get_clock(rt_clock); + vp_mod_timer (d->uart_timer, vp_get_clock (rt_clock) + UART_TIME_OUT); + + vm_bind_device (vm, d->dev); + + return (0); + + err_dev_create: + free (d); + return (-1); +} diff --git a/tools/virtualmips/jz4740/jz4740_dev_wdt_tcu.c b/tools/virtualmips/jz4740/jz4740_dev_wdt_tcu.c new file mode 100644 index 0000000..6d139e2 --- /dev/null +++ b/tools/virtualmips/jz4740/jz4740_dev_wdt_tcu.c @@ -0,0 +1,515 @@ + /* + * Copyright (C) yajin 2008 + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + * + */ + + /* Watch dog and timer of JZ4740. + * TODO: + * 2. timer1-5 + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include + +#include "device.h" +#include "mips_memory.h" +#include "cpu.h" +#include "jz4740.h" +#include "vp_timer.h" +#include "vp_clock.h" + +#define VALIDE_WDT_TCU_OPERATION 0 +extern cpu_mips_t *current_cpu; +m_uint32_t jz4740_wdt_tcu_table[JZ4740_WDT_INDEX_MAX]; + +/*4:EXT 2:RTC 1:PCK*/ +//m_uint8_t jz4740_tcu_clock_source[JZ4740_WDT_INDEX_MAX]; +//m_uint32_t jz4740_tcu_clock_prescale[JZ4740_WDT_INDEX_MAX]; + +/*clocksource/prescale*/ +m_uint64_t jz4740_tcu_clock[JZ4740_WDT_INDEX_MAX]; +m_uint64_t jz4740_wdt_clock; + +struct jz4740_wdt_tcu_data { + struct vdevice *dev; + m_uint8_t *jz4740_wdt_tcu_ptr; + m_uint32_t jz4740_wdt_tcu_size; + vp_timer_t *tcu_timer[JZ4740_WDT_INDEX_MAX]; + vp_timer_t *wdt_timer; +}; + +/*fire timer0 every 10ms*/ +void dev_jz4740_tcu_active_timer0 (struct jz4740_wdt_tcu_data *d) +{ + d->tcu_timer[0]->set_time = vp_get_clock (rt_clock); + vp_mod_timer (d->tcu_timer[0], vp_get_clock (rt_clock) + 10); +} + +void dev_jz4740_tcu_unactive_timer0 (struct jz4740_wdt_tcu_data *d) +{ + vp_del_timer (d->tcu_timer[0]); +} + +void dev_jz4740_active_wdt (struct jz4740_wdt_tcu_data *d) +{ + d->wdt_timer->set_time = vp_get_clock (rt_clock); + vp_mod_timer (d->wdt_timer, vp_get_clock (rt_clock) + 10); +} + +void dev_jz4740_unactive_wdt (struct jz4740_wdt_tcu_data *d) +{ + vp_del_timer (d->wdt_timer); +} + +void *dev_jz4740_wdt_tcu_access (cpu_mips_t * cpu, struct vdevice *dev, + m_uint32_t offset, u_int op_size, u_int op_type, + m_reg_t * data, m_uint8_t * has_set_value) +{ + + struct jz4740_wdt_tcu_data *d = dev->priv_data; + m_uint32_t mask_data, mask; + int clock_index; + //m_uint64_t clock; + + if (offset >= d->jz4740_wdt_tcu_size) { + *data = 0; + return NULL; + } +#if VALIDE_WDT_TCU_OPERATION + if (op_type == MTS_WRITE) { + ASSERT (offset != TCU_TSR, + "Write to read only register in TCU. offset %x\n", offset); + ASSERT (offset != TCU_TER, + "Write to read only register in TCU. offset %x\n", offset); + ASSERT (offset != TCU_TFR, + "Write to read only register in TCU. offset %x\n", offset); + ASSERT (offset != TCU_TMR, + "Write to read only register in TCU. offset %x\n", offset); + } else if (op_type == MTS_READ) { + ASSERT (offset != TCU_TSSR, + "Read write only register in TCU. offset %x\n", offset); + ASSERT (offset != TCU_TSCR, + "Read write only register in TCU. offset %x\n", offset); + ASSERT (offset != TCU_TESR, + "Read write only register in TCU. offset %x\n", offset); + ASSERT (offset != TCU_TECR, + "Read write only register in TCU. offset %x\n", offset); + ASSERT (offset != TCU_TFSR, + "Read write only register in TCU. offset %x\n", offset); + ASSERT (offset != TCU_TFCR, + "Read write only register in TCU. offset %x\n", offset); + ASSERT (offset != TCU_TMSR, + "Read write only register in TCU. offset %x\n", offset); + ASSERT (offset != TCU_TMCR, + "Read write only register in TCU. offset %x\n", offset); + } else + assert (0); +#endif + switch (op_size) { + case 1: + mask = 0xff; + break; + case 2: + mask = 0xffff; + break; + case 4: + mask = 0xffffffff; + break; + default: + assert (0); + } + + switch (offset) { + case TCU_TSSR: /*set */ + + assert (op_type == MTS_WRITE); + mask_data = (*data) & mask; + jz4740_wdt_tcu_table[TCU_TSR / 4] |= mask_data; + *has_set_value = TRUE; + if (jz4740_wdt_tcu_table[TCU_TSR / 4] & 0x01) + dev_jz4740_tcu_unactive_timer0 (d); + if (jz4740_wdt_tcu_table[TCU_TSR / 4] & WDT_TIMER_STOP) + dev_jz4740_unactive_wdt (d); + + break; + case TCU_TSCR: /*clear */ + assert (op_type == MTS_WRITE); + mask_data = (*data) & mask; + mask_data = ~(mask_data); + jz4740_wdt_tcu_table[TCU_TSR / 4] &= mask_data; + *has_set_value = TRUE; + if ((!jz4740_wdt_tcu_table[TCU_TSR / 4] & 0x01) + && (jz4740_wdt_tcu_table[TCU_TER / 4] & 0x01)) + dev_jz4740_tcu_active_timer0 (d); + if (unlikely (jz4740_wdt_tcu_table[WDT_TCER / 4] & 0x01) + && (!(jz4740_wdt_tcu_table[TCU_TSR / 4] & WDT_TIMER_STOP))) + dev_jz4740_active_wdt (d); + break; + + case TCU_TESR: /*set */ + assert (op_type == MTS_WRITE); + mask_data = (*data) & mask; + jz4740_wdt_tcu_table[TCU_TER / 4] |= mask_data; + *has_set_value = TRUE; + if ((!jz4740_wdt_tcu_table[TCU_TSR / 4] & 0x01) + && (jz4740_wdt_tcu_table[TCU_TER / 4] & 0x01)) + dev_jz4740_tcu_active_timer0 (d); + break; + case TCU_TECR: /*clear */ + assert (op_type == MTS_WRITE); + mask_data = (*data) & mask; + mask_data = ~(mask_data); + jz4740_wdt_tcu_table[TCU_TER / 4] &= mask_data; + *has_set_value = TRUE; + if (!(jz4740_wdt_tcu_table[TCU_TER / 4] & 0x01)) + dev_jz4740_tcu_unactive_timer0 (d); + break; + + case TCU_TFSR: /*set */ + assert (op_type == MTS_WRITE); + mask_data = (*data) & mask; + jz4740_wdt_tcu_table[TCU_TFR / 4] |= mask_data; + *has_set_value = TRUE; + break; + case TCU_TFCR: /*clear */ + assert (op_type == MTS_WRITE); + mask_data = (*data) & mask; + mask_data = ~(mask_data); + jz4740_wdt_tcu_table[TCU_TFR / 4] &= mask_data; + *has_set_value = TRUE; + break; + + case TCU_TMSR: /*set */ + assert (op_type == MTS_WRITE); + mask_data = (*data) & mask; + jz4740_wdt_tcu_table[TCU_TMR / 4] |= mask_data; + *has_set_value = TRUE; + break; + case TCU_TMCR: /*clear */ + assert (op_type == MTS_WRITE); + mask_data = (*data) & mask; + mask_data = ~(mask_data); + jz4740_wdt_tcu_table[TCU_TMR / 4] &= mask_data; + *has_set_value = TRUE; + break; + case TCU_TCSR0: + case TCU_TCSR1: + case TCU_TCSR2: + case TCU_TCSR3: + case TCU_TCSR4: + case TCU_TCSR5: + if (op_type == MTS_WRITE) { + clock_index = (offset - TCU_TCSR0) / 0x10; + if (((*data) & TCU_CLOCK_SOUCE_MASK) == TCU_CLOCK_EXT) { + jz4740_tcu_clock[clock_index] = EXT_CLOCK; + + } else if (((*data) & TCU_CLOCK_SOUCE_MASK) == TCU_CLOCK_RTC) { + jz4740_tcu_clock[clock_index] = RTC_CLOCK; + } else + ASSERT (0, "RTC and EXT clock is supported \n"); + + if ((((*data) & TCU_CLOCK_PRESCALE_MASK) >> + TCU_CLOCK_PRESCALE_OFFSET) == 0x1) + jz4740_tcu_clock[clock_index] = + jz4740_tcu_clock[clock_index] / 4; + else if ((((*data) & TCU_CLOCK_PRESCALE_MASK) >> + TCU_CLOCK_PRESCALE_OFFSET) == 0x2) + jz4740_tcu_clock[clock_index] = + jz4740_tcu_clock[clock_index] / 16; + else if ((((*data) & TCU_CLOCK_PRESCALE_MASK) >> + TCU_CLOCK_PRESCALE_OFFSET) == 0x3) + jz4740_tcu_clock[clock_index] = + jz4740_tcu_clock[clock_index] / 64; + else if ((((*data) & TCU_CLOCK_PRESCALE_MASK) >> + TCU_CLOCK_PRESCALE_OFFSET) == 0x4) + jz4740_tcu_clock[clock_index] = + jz4740_tcu_clock[clock_index] / 256; + else if ((((*data) & TCU_CLOCK_PRESCALE_MASK) >> + TCU_CLOCK_PRESCALE_OFFSET) == 0x5) + jz4740_tcu_clock[clock_index] = + jz4740_tcu_clock[clock_index] / 1024; + else if ((((*data) & TCU_CLOCK_PRESCALE_MASK) >> + TCU_CLOCK_PRESCALE_OFFSET) != 0x0) + ASSERT (0, "INVALID PRESCALE\n"); + + } + return ((void *) (d->jz4740_wdt_tcu_ptr + offset)); + + case WDT_TCSR: + if (op_type == MTS_WRITE) { + if (((*data) & WDT_CLOCK_SOUCE_MASK) == WDT_CLOCK_EXT) { + jz4740_wdt_clock = EXT_CLOCK; + } else if (((*data) & WDT_CLOCK_SOUCE_MASK) == WDT_CLOCK_RTC) + jz4740_wdt_clock = RTC_CLOCK; + else + ASSERT (0, "RTC and EXT clock is supported \n"); + + if ((((*data) & WDT_CLOCK_PRESCALE_MASK) >> + WDT_CLOCK_PRESCALE_OFFSET) == 0x1) + jz4740_wdt_clock = jz4740_wdt_clock / 4; + else if ((((*data) & WDT_CLOCK_PRESCALE_MASK) >> + WDT_CLOCK_PRESCALE_OFFSET) == 0x2) + jz4740_wdt_clock = jz4740_wdt_clock / 16; + else if ((((*data) & WDT_CLOCK_PRESCALE_MASK) >> + WDT_CLOCK_PRESCALE_OFFSET) == 0x3) + jz4740_wdt_clock = jz4740_wdt_clock / 64; + else if ((((*data) & WDT_CLOCK_PRESCALE_MASK) >> + WDT_CLOCK_PRESCALE_OFFSET) == 0x4) + jz4740_wdt_clock = jz4740_wdt_clock / 256; + else if ((((*data) & WDT_CLOCK_PRESCALE_MASK) >> + WDT_CLOCK_PRESCALE_OFFSET) == 0x5) + jz4740_wdt_clock = jz4740_wdt_clock / 1024; + else if ((((*data) & WDT_CLOCK_PRESCALE_MASK) >> + WDT_CLOCK_PRESCALE_OFFSET) != 0x0) + ASSERT (0, "INVALID PRESCALE %x \n", *data); + + } + return ((void *) (d->jz4740_wdt_tcu_ptr + offset)); + + case WDT_TCER: + if (op_type == MTS_WRITE) { + jz4740_wdt_tcu_table[WDT_TCER / 4] = (*data) & 0x1; + *has_set_value = TRUE; + if (unlikely (jz4740_wdt_tcu_table[WDT_TCER / 4] & 0x01) + && (!(jz4740_wdt_tcu_table[TCU_TSR / 4] & WDT_TIMER_STOP))) + dev_jz4740_active_wdt (d); + else + dev_jz4740_unactive_wdt (d); + } else + return ((void *) (d->jz4740_wdt_tcu_ptr + offset)); + + default: + return ((void *) (d->jz4740_wdt_tcu_ptr + offset)); + + } + + return NULL; + +} + +void dev_jz4740_wdt_tcu_init_defaultvalue () +{ + + memset (jz4740_wdt_tcu_table, 0x0, sizeof (jz4740_wdt_tcu_table)); + + jz4740_wdt_tcu_table[TCU_TDFR0 / 4] = 0X7FF8; + jz4740_wdt_tcu_table[TCU_TDHR0 / 4] = 0X7FF7; + jz4740_wdt_tcu_table[TCU_TCNT0 / 4] = 0X7FF7; + + jz4740_wdt_tcu_table[TCU_TDFR1 / 4] = 0X7FF8; + jz4740_wdt_tcu_table[TCU_TDHR1 / 4] = 0X7FF7; + jz4740_wdt_tcu_table[TCU_TCNT1 / 4] = 0X7FF7; + + jz4740_wdt_tcu_table[TCU_TDFR2 / 4] = 0X7FF8; + jz4740_wdt_tcu_table[TCU_TDHR2 / 4] = 0X7FF7; + jz4740_wdt_tcu_table[TCU_TCNT2 / 4] = 0X7FF7; + + jz4740_wdt_tcu_table[TCU_TDFR3 / 4] = 0X7FF8; + jz4740_wdt_tcu_table[TCU_TDHR3 / 4] = 0X7FF7; + jz4740_wdt_tcu_table[TCU_TCNT3 / 4] = 0X7FF7; + + jz4740_wdt_tcu_table[TCU_TDFR4 / 4] = 0X7FF8; + jz4740_wdt_tcu_table[TCU_TDHR4 / 4] = 0X7FF7; + jz4740_wdt_tcu_table[TCU_TCNT4 / 4] = 0X7FF7; + + jz4740_wdt_tcu_table[TCU_TDFR5 / 4] = 0X7FF8; + jz4740_wdt_tcu_table[TCU_TDHR5 / 4] = 0X7FF7; + jz4740_wdt_tcu_table[TCU_TCNT5 / 4] = 0X7FF7; +} + +void dev_jz4740_wdt_tcu_reset (cpu_mips_t * cpu, struct vdevice *dev) +{ + dev_jz4740_wdt_tcu_init_defaultvalue (); +} + +int gasdf; +int reset_request = 0; + +/*10ms*/ +void dev_jz4740_wdt_cb (void *opaque) +{ + m_int64_t current; + m_uint32_t past_time; + + struct jz4740_wdt_tcu_data *d = (struct jz4740_wdt_tcu_data *) opaque; + if (unlikely (jz4740_wdt_tcu_table[WDT_TCER / 4] & 0x01) + && (!(jz4740_wdt_tcu_table[TCU_TSR / 4] & WDT_TIMER_STOP))) { + current = vp_get_clock (rt_clock); + past_time = current - d->tcu_timer[0]->set_time; + + { + jz4740_wdt_tcu_table[WDT_TCNT / 4] += (jz4740_wdt_clock) / 100; + + if (jz4740_wdt_tcu_table[WDT_TCNT / 4] >= + jz4740_wdt_tcu_table[WDT_TDR / 4]) { + /*RESET soc */ + cpu_restart (current_cpu); + jz4740_reset (current_cpu->vm); + } + } + } + dev_jz4740_active_wdt (d); + +} + +/*10ms +Linux uses 100HZ timer, so we fire tcu every 10 ms. +1ms -> jz4740_wdt_tcu_table[TCU_TCNT0/4]+= jz4740_tcu_clock[0])/1000; */ +void dev_jz4740_tcu_cb (void *opaque) +{ + struct jz4740_wdt_tcu_data *d = (struct jz4740_wdt_tcu_data *) opaque; + + m_int64_t current; + m_uint32_t past_time; + current = vp_get_clock (rt_clock); + past_time = current - d->tcu_timer[0]->set_time; + + jz4740_wdt_tcu_table[TCU_TCNT0 / 4] += + (past_time * jz4740_tcu_clock[0]) / 1000; + jz4740_wdt_tcu_table[TCU_TCNT0 / 4] &= 0xffff; + + if (jz4740_wdt_tcu_table[TCU_TCNT0 / 4] >= + jz4740_wdt_tcu_table[TCU_TDHR0 / 4]) { + /*set TFR */ + jz4740_wdt_tcu_table[TCU_TFR / 4] |= 1 << 16; + if (!(jz4740_wdt_tcu_table[TCU_TMR / 4] & (1 << 16))) + current_cpu->vm->set_irq (current_cpu->vm, IRQ_TCU0); + } + if (jz4740_wdt_tcu_table[TCU_TCNT0 / 4] >= + jz4740_wdt_tcu_table[TCU_TDFR0 / 4]) { + jz4740_wdt_tcu_table[TCU_TFR / 4] |= 1; + if (!(jz4740_wdt_tcu_table[TCU_TMR / 4] & (0x1))) { + current_cpu->vm->set_irq (current_cpu->vm, IRQ_TCU0); + } + jz4740_wdt_tcu_table[TCU_TCNT0 / 4] = 0; + } + + dev_jz4740_tcu_active_timer0 (d); + +} + +int dev_jz4740_wdt_tcu_init (vm_instance_t * vm, char *name, m_pa_t paddr, + m_uint32_t len) +{ + struct jz4740_wdt_tcu_data *d; + + /* allocate the private data structure */ + if (!(d = malloc (sizeof (*d)))) { + fprintf (stderr, "jz4740_wdt_tcu: unable to create device.\n"); + return (-1); + } + + memset (d, 0, sizeof (*d)); + if (!(d->dev = dev_create (name))) + goto err_dev_create; + d->dev->priv_data = d; + d->dev->phys_addr = paddr; + d->dev->phys_len = len; + d->jz4740_wdt_tcu_ptr = (m_uint8_t *) (&jz4740_wdt_tcu_table[0]); + d->jz4740_wdt_tcu_size = len; + d->dev->handler = dev_jz4740_wdt_tcu_access; + d->dev->reset_handler = dev_jz4740_wdt_tcu_reset; + d->dev->flags = VDEVICE_FLAG_NO_MTS_MMAP; + + /*only emulate timer0 */ + d->tcu_timer[0] = vp_new_timer (rt_clock, dev_jz4740_tcu_cb, d); + d->wdt_timer = vp_new_timer (rt_clock, dev_jz4740_wdt_cb, d); + + vm_bind_device (vm, d->dev); + + return (0); + + err_dev_create: + free (d); + return (-1); +} + +#if 0 + +/*-------------Virtual Timer and WDT Timer----------------------*/ +m_uint32_t past_instructions = 0; +//m_uint32_t past_instructions[6]; +/*TODO:need to adjust*/ +#define COUNT_PER_INSTRUCTION 0x80 //0X180 + +/*JUST TIMER 0*/ +void forced_inline virtual_jz4740_timer (cpu_mips_t * cpu) +{ + + if (unlikely (jz4740_wdt_tcu_table[TCU_TSR / 4] & 0x01)) { + return; + } + if (likely (jz4740_wdt_tcu_table[TCU_TER / 4] & 0x01)) { + //allow counter + past_instructions++; + if (past_instructions == COUNT_PER_INSTRUCTION) { + jz4740_wdt_tcu_table[TCU_TCNT0 / 4] += 1; + if (jz4740_wdt_tcu_table[TCU_TCNT0 / 4] == + jz4740_wdt_tcu_table[TCU_TDHR0 / 4]) { + /*set TFR */ + jz4740_wdt_tcu_table[TCU_TFR / 4] |= 1 << 16; + if (!(jz4740_wdt_tcu_table[TCU_TMR / 4] & (1 << 16))) + cpu->vm->set_irq (cpu->vm, IRQ_TCU0); + } + if (jz4740_wdt_tcu_table[TCU_TCNT0 / 4] == + jz4740_wdt_tcu_table[TCU_TDFR0 / 4]) { + jz4740_wdt_tcu_table[TCU_TFR / 4] |= 1; + if (!(jz4740_wdt_tcu_table[TCU_TMR / 4] & (0x1))) { + cpu->vm->set_irq (cpu->vm, IRQ_TCU0); + } + + jz4740_wdt_tcu_table[TCU_TCNT0 / 4] = 0; + } + past_instructions = 0; + + } + } + +} + +m_uint32_t wdt_past_instructions = 0; + +void forced_inline virtual_jz4740_wdt (cpu_mips_t * cpu) +{ + + if (likely (jz4740_wdt_tcu_table[TCU_TSR / 4] & WDT_TIMER_STOP)) { + return; + } + + if (unlikely (jz4740_wdt_tcu_table[WDT_TCER / 4] & 0x01)) { + + wdt_past_instructions++; + if (wdt_past_instructions >= COUNT_PER_INSTRUCTION) { + jz4740_wdt_tcu_table[WDT_TCNT / 4] += 1; + wdt_past_instructions = 0; + if (jz4740_wdt_tcu_table[WDT_TCNT / 4] & 0xffff0000) + jz4740_wdt_tcu_table[WDT_TCNT / 4] = 0; + + if (jz4740_wdt_tcu_table[WDT_TCNT / 4] >= + jz4740_wdt_tcu_table[WDT_TDR / 4]) { + /*RESET soc */ + cpu_stop (cpu); + cpu->cpu_thread_running = FALSE; + jz4740_reset (cpu->vm); + + } + } + + } + +} + +void forced_inline virtual_timer (cpu_mips_t * cpu) +{ + virtual_jz4740_timer (cpu); + virtual_jz4740_wdt (cpu); +} +#endif diff --git a/tools/virtualmips/main.c b/tools/virtualmips/main.c new file mode 100644 index 0000000..ce0648d --- /dev/null +++ b/tools/virtualmips/main.c @@ -0,0 +1,95 @@ +/* + * Copyright (C) yajin 2008 + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + */ +#define _GNU_SOURCE +#include +#include +#include +#include +#include + +#include "utils.h" +#include "mips.h" +#include "device.h" +#include "vm.h" +#include "mips_exec.h" +#include "vp_timer.h" +#include "crc.h" +#include "net_io.h" + +#define VERSION "0.06-retrobsd" + +void signal_gen_handler (int sig) +{ + switch (sig) { + case SIGHUP: + /* For future use */ + break; + + case SIGQUIT: + printf ("\n--- Stop simulation\n"); + /*do not worry, exit will release all resource */ + exit (EXIT_SUCCESS); + break; + + case SIGINT: + /* In theory, this shouldn't happen thanks to VTTY settings */ + break; + + default: + fprintf (stderr, "Unhandled signal %d\n", sig); + } +} + +/* Setups signals */ +static void setup_signals (void) +{ + struct sigaction act; + + memset (&act, 0, sizeof (act)); + act.sa_handler = signal_gen_handler; + act.sa_flags = SA_RESTART; + sigaction (SIGHUP, &act, NULL); + sigaction (SIGQUIT, &act, NULL); + sigaction (SIGINT, &act, NULL); +} + +int main (int argc, char *argv[]) +{ + vm_instance_t *vm; + char *configure_filename = NULL; + + printf ("VirtualMIPS (version %s)\n", VERSION); + printf ("Copyright (c) 2008 yajin, 2011 vak.\n"); + printf ("Build date: %s %s\n\n", __DATE__, __TIME__); + + /* Initialize CRC functions */ + crc_init (); + + /* Initialize VTTY code */ + vtty_init (); + + /* Create the default instance */ + vm = create_instance (configure_filename); + if (!vm) + return EXIT_FAILURE; + + /* Set seed for random value. */ + srand ((int) time (0)); + + setup_signals (); + init_timers (); + if (init_instance (vm) < 0) { + fprintf (stderr, "Unable to initialize instance.\n"); + return EXIT_FAILURE; + } + + /* We get here, because the cpu is not running now. */ + vm_monitor (vm); + + printf ("VM shut down\n"); + return (0); +} diff --git a/tools/virtualmips/mempool.c b/tools/virtualmips/mempool.c new file mode 100644 index 0000000..ddfcd28 --- /dev/null +++ b/tools/virtualmips/mempool.c @@ -0,0 +1,246 @@ +/* + * Copyright (c) 1999-2006 Christophe Fillot. + * E-mail: cf@utc.fr + * + * mempool.c: Simple Memory Pools. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "utils.h" +#include "mempool.h" + +/* + * Internal function used to allocate a memory block, and do basic operations + * on it. It does not manipulate pools, so no mutex is needed. + */ +static inline memblock_t *memblock_alloc (size_t size, int zeroed) +{ + memblock_t *block; + size_t total_size; + + total_size = size + sizeof (memblock_t); + if (!(block = malloc (total_size))) + return NULL; + + if (zeroed) + memset (block, 0, total_size); + + block->tag = MEMBLOCK_TAG; + block->block_size = size; + block->prev = block->next = NULL; + return block; +} + +/* Insert block in linked list */ +static inline void memblock_insert (mempool_t * pool, memblock_t * block) +{ + MEMPOOL_LOCK (pool); + + pool->nr_blocks++; + pool->total_size += block->block_size; + + block->prev = NULL; + block->next = pool->block_list; + + if (block->next) + block->next->prev = block; + + pool->block_list = block; + + MEMPOOL_UNLOCK (pool); +} + +/* Remove block from linked list */ +static inline void memblock_delete (mempool_t * pool, memblock_t * block) +{ + MEMPOOL_LOCK (pool); + + pool->nr_blocks--; + pool->total_size -= block->block_size; + + if (!block->prev) + pool->block_list = block->next; + else + block->prev->next = block->next; + + if (block->next) + block->next->prev = block->prev; + + block->next = block->prev = NULL; + MEMPOOL_UNLOCK (pool); +} + +/* Allocate a new block in specified pool (internal function) */ +static inline void *mp_alloc_inline (mempool_t * pool, size_t size, + int zeroed) +{ + memblock_t *block; + + if (!(block = memblock_alloc (size, zeroed))) + return NULL; + + block->pool = pool; + memblock_insert (pool, block); + return (block->data); +} + +/* Allocate a new block in specified pool */ +void *mp_alloc (mempool_t * pool, size_t size) +{ + return (mp_alloc_inline (pool, size, TRUE)); +} + +/* Allocate a new block which will not be zeroed */ +void *mp_alloc_n0 (mempool_t * pool, size_t size) +{ + return (mp_alloc_inline (pool, size, FALSE)); +} + +/* Reallocate a block */ +void *mp_realloc (void *addr, size_t new_size) +{ + memblock_t *ptr, *block = (memblock_t *) addr - 1; + mempool_t *pool; + size_t total_size; + + assert (block->tag == MEMBLOCK_TAG); + pool = block->pool; + + /* remove this block from list */ + memblock_delete (pool, block); + + /* reallocate block with specified size */ + total_size = new_size + sizeof (memblock_t); + + if (!(ptr = realloc (block, total_size))) { + memblock_insert (pool, block); + return NULL; + } + + ptr->block_size = new_size; + memblock_insert (pool, ptr); + return ptr->data; +} + +/* Allocate a new memory block and copy data into it */ +void *mp_dup (mempool_t * pool, void *data, size_t size) +{ + void *p; + + if ((p = mp_alloc_n0 (pool, size))) + memcpy (p, data, size); + + return p; +} + +/* Duplicate specified string and insert it in a memory pool */ +char *mp_strdup (mempool_t * pool, char *str) +{ + char *new_str; + + if ((new_str = mp_alloc (pool, strlen (str) + 1)) == NULL) + return NULL; + + strcpy (new_str, str); + return new_str; +} + +/* Free block at specified address */ +int mp_free (void *addr) +{ + memblock_t *block = (memblock_t *) addr - 1; + mempool_t *pool; + + if (addr != NULL) { + assert (block->tag == MEMBLOCK_TAG); + pool = block->pool; + + memblock_delete (pool, block); + memset (block, 0, sizeof (memblock_t)); + free (block); + } + + return (0); +} + +/* Free block at specified address and clean pointer */ +int mp_free_ptr (void *addr) +{ + void *p; + + assert (addr != NULL); + p = *(void **) addr; + *(void **) addr = NULL; + mp_free (p); + return (0); +} + +/* Free all blocks of specified pool */ +void mp_free_all_blocks (mempool_t * pool) +{ + memblock_t *block, *next; + + MEMPOOL_LOCK (pool); + + for (block = pool->block_list; block; block = next) { + next = block->next; + free (block); + } + + pool->block_list = NULL; + pool->nr_blocks = 0; + pool->total_size = 0; + + MEMPOOL_UNLOCK (pool); +} + +/* Free specified memory pool */ +void mp_free_pool (mempool_t * pool) +{ + mp_free_all_blocks (pool); + + if (!(pool->flags & MEMPOOL_FIXED)) + free (pool); +} + +/* Create a new pool in a fixed memory area */ +mempool_t *mp_create_fixed_pool (mempool_t * mp, char *name) +{ + memset (mp, 0, sizeof (*mp)); + + if (pthread_mutex_init (&mp->lock, NULL) != 0) + return NULL; + + mp->name = name; + mp->block_list = NULL; + mp->flags = MEMPOOL_FIXED; + return mp; +} + +/* Create a new pool */ +mempool_t *mp_create_pool (char *name) +{ + mempool_t *mp = malloc (sizeof (*mp)); + + if (!mp || !mp_create_fixed_pool (mp, name)) { + free (mp); + return NULL; + } + + mp->flags = 0; /* clear "FIXED" flag */ + return mp; +} diff --git a/tools/virtualmips/mempool.h b/tools/virtualmips/mempool.h new file mode 100644 index 0000000..8408453 --- /dev/null +++ b/tools/virtualmips/mempool.h @@ -0,0 +1,96 @@ +/* + * Copyright (c) 1999-2006 Christophe Fillot. + * E-mail: cf@utc.fr + * + * mempool.h: Simple Memory Pools. + */ + +#ifndef __MEMPOOL_H__ +#define __MEMPOOL_H__ 1 + +#include +#include +#include + +#include "utils.h" + +/* Memory Pool "Fixed" Flag */ +#define MEMPOOL_FIXED 1 + +/* Dummy value used to check if a memory block is invalid */ +#define MEMBLOCK_TAG 0xdeadbeef + +typedef struct memblock memblock_t; +typedef struct mempool mempool_t; + +/* Memory block */ +struct memblock { + int tag; /* MEMBLOCK_TAG if block is valid */ + size_t block_size; /* Block size (without header) */ + memblock_t *next, *prev; /* Double linked list pointers */ + mempool_t *pool; /* Pool which contains this block */ + m_uint64_t data[0]; /* Memory block itself */ +}; + +/* Memory Pool */ +struct mempool { + memblock_t *block_list; /* Double-linked block list */ + pthread_mutex_t lock; /* Mutex for managing pool */ + char *name; /* Name of this pool */ + int flags; /* Flags */ + int nr_blocks; /* Number of blocks in this pool */ + size_t total_size; /* Total bytes allocated */ + size_t max_size; /* Maximum memory */ +}; + +/* Lock and unlock access to a memory pool */ +#define MEMPOOL_LOCK(mp) pthread_mutex_lock(&(mp)->lock) +#define MEMPOOL_UNLOCK(mp) pthread_mutex_unlock(&(mp)->lock) + +/* Callback function for use with mp_foreach */ +typedef void (*mp_foreach_cbk) (memblock_t * block, void *user_arg); + +/* Execute an action for each block in specified pool */ +static inline void mp_foreach (mempool_t * pool, mp_foreach_cbk cbk, + void *arg) +{ + memblock_t *mb; + + for (mb = pool->block_list; mb; mb = mb->next) + cbk (mb, arg); +} + +/* Allocate a new block in specified pool */ +void *mp_alloc (mempool_t * pool, size_t size); + +/* Allocate a new block which will not be zeroed */ +void *mp_alloc_n0 (mempool_t * pool, size_t size); + +/* Reallocate a block */ +void *mp_realloc (void *addr, size_t new_size); + +/* Allocate a new memory block and copy data into it */ +void *mp_dup (mempool_t * pool, void *data, size_t size); + +/* Duplicate specified string and insert it in a memory pool */ +char *mp_strdup (mempool_t * pool, char *str); + +/* Free block at specified address */ +int mp_free (void *addr); + +/* Free block at specified address and clean pointer */ +int mp_free_ptr (void *addr); + +/* Free all blocks of specified pool */ +void mp_free_all_blocks (mempool_t * pool); + +/* Free specified memory pool */ +void mp_free_pool (mempool_t * pool); + +/* Create a new pool in a fixed memory area */ +mempool_t *mp_create_fixed_pool (mempool_t * mp, char *name); + +/* Create a new pool */ +mempool_t *mp_create_pool (char *name); + +#endif diff --git a/tools/virtualmips/mips-dis.c b/tools/virtualmips/mips-dis.c new file mode 100644 index 0000000..68319ac --- /dev/null +++ b/tools/virtualmips/mips-dis.c @@ -0,0 +1,1529 @@ +/* + * Print mips instructions. + * + * Copyright 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, + * 2000, 2001, 2002, 2003, 2005, 2006, 2007, 2008, 2009 + * Free Software Foundation, Inc. + * Contributed by Nobuyuki Hikichi (hikichi@sra.co.jp). + * Rewritten for VirtualMIPS by Serge Vakulenko. + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + */ +#include +#include +#include +#include "mips-opcode.h" +#include "mips-opc.c" +#include "mips16-opc.c" + +/* FIXME: These are needed to figure out if the code is mips16 or + not. The low bit of the address is often a good indicator. No + symbol table is available when this code runs out in an embedded + system as when it is used for disassembler support in a monitor. */ + +/* Mips instructions are at maximum this many bytes long. */ +#define INSNLEN 4 + +struct mips_cp0sel_name { + unsigned int cp0reg; + unsigned int sel; + const char *const name; +}; + +/* The mips16 registers. */ +static const unsigned int mips16_to_32_reg_map[] = { + 16, 17, 2, 3, 4, 5, 6, 7 +}; + +#define mips16_reg_names(rn) mips_gpr_names[mips16_to_32_reg_map[rn]] + +static const char *const mips_gpr_names[32] = { + "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3", + "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", + "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", + "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra" +}; + +static const char *const mips_fpr_names[32] = { + "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7", + "$f8", "$f9", "$f10", "$f11", "$f12", "$f13", "$f14", "$f15", + "$f16", "$f17", "$f18", "$f19", "$f20", "$f21", "$f22", "$f23", + "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "$f31" +}; + +static const char *const mips_cp0_names[32] = { + "c0_index", "c0_random", "c0_entrylo0", "c0_entrylo1", + "c0_context", "c0_pagemask", "c0_wired", "c0_hwrena", + "c0_badvaddr", "c0_count", "c0_entryhi", "c0_compare", + "c0_status", "c0_cause", "c0_epc", "c0_prid", + "c0_config", "c0_lladdr", "c0_watchlo", "c0_watchhi", + "c0_xcontext", "$21", "$22", "c0_debug", + "c0_depc", "c0_perfcnt", "c0_errctl", "c0_cacheerr", + "c0_taglo", "c0_taghi", "c0_errorepc", "c0_desave", +}; + +static const struct mips_cp0sel_name mips_cp0sel_names[] = { + {4, 1, "c0_contextconfig"}, + {0, 1, "c0_mvpcontrol"}, + {0, 2, "c0_mvpconf0"}, + {0, 3, "c0_mvpconf1"}, + {1, 1, "c0_vpecontrol"}, + {1, 2, "c0_vpeconf0"}, + {1, 3, "c0_vpeconf1"}, + {1, 4, "c0_yqmask"}, + {1, 5, "c0_vpeschedule"}, + {1, 6, "c0_vpeschefback"}, + {2, 1, "c0_tcstatus"}, + {2, 2, "c0_tcbind"}, + {2, 3, "c0_tcrestart"}, + {2, 4, "c0_tchalt"}, + {2, 5, "c0_tccontext"}, + {2, 6, "c0_tcschedule"}, + {2, 7, "c0_tcschefback"}, + {5, 1, "c0_pagegrain"}, + {6, 1, "c0_srsconf0"}, + {6, 2, "c0_srsconf1"}, + {6, 3, "c0_srsconf2"}, + {6, 4, "c0_srsconf3"}, + {6, 5, "c0_srsconf4"}, + {12, 1, "c0_intctl"}, + {12, 2, "c0_srsctl"}, + {12, 3, "c0_srsmap"}, + {15, 1, "c0_ebase"}, + {16, 1, "c0_config1"}, + {16, 2, "c0_config2"}, + {16, 3, "c0_config3"}, + {18, 1, "c0_watchlo,1"}, + {18, 2, "c0_watchlo,2"}, + {18, 3, "c0_watchlo,3"}, + {18, 4, "c0_watchlo,4"}, + {18, 5, "c0_watchlo,5"}, + {18, 6, "c0_watchlo,6"}, + {18, 7, "c0_watchlo,7"}, + {19, 1, "c0_watchhi,1"}, + {19, 2, "c0_watchhi,2"}, + {19, 3, "c0_watchhi,3"}, + {19, 4, "c0_watchhi,4"}, + {19, 5, "c0_watchhi,5"}, + {19, 6, "c0_watchhi,6"}, + {19, 7, "c0_watchhi,7"}, + {23, 1, "c0_tracecontrol"}, + {23, 2, "c0_tracecontrol2"}, + {23, 3, "c0_usertracedata"}, + {23, 4, "c0_tracebpc"}, + {25, 1, "c0_perfcnt,1"}, + {25, 2, "c0_perfcnt,2"}, + {25, 3, "c0_perfcnt,3"}, + {25, 4, "c0_perfcnt,4"}, + {25, 5, "c0_perfcnt,5"}, + {25, 6, "c0_perfcnt,6"}, + {25, 7, "c0_perfcnt,7"}, + {27, 1, "c0_cacheerr,1"}, + {27, 2, "c0_cacheerr,2"}, + {27, 3, "c0_cacheerr,3"}, + {28, 1, "c0_datalo"}, + {28, 2, "c0_taglo1"}, + {28, 3, "c0_datalo1"}, + {28, 4, "c0_taglo2"}, + {28, 5, "c0_datalo2"}, + {28, 6, "c0_taglo3"}, + {28, 7, "c0_datalo3"}, + {29, 1, "c0_datahi"}, + {29, 2, "c0_taghi1"}, + {29, 3, "c0_datahi1"}, + {29, 4, "c0_taghi2"}, + {29, 5, "c0_datahi2"}, + {29, 6, "c0_taghi3"}, + {29, 7, "c0_datahi3"}, +}; +static const int mips_cp0sel_names_len = sizeof (mips_cp0sel_names) / sizeof (*mips_cp0sel_names); + +static const char *const mips_hwr_names[32] = { + "$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" +}; + +/* + * If set disassemble as most general inst. + */ +static int no_aliases = 0; + +static int big_endian; +static int branch_delay_insns; +static int data_size; +static unsigned target; + +enum dis_insn_type { + dis_noninsn, /* Not a valid instruction. */ + dis_nonbranch, /* Not a branch instruction. */ + dis_branch, /* Unconditional branch. */ + dis_condbranch, /* Conditional branch. */ + dis_jsr, /* Jump to subroutine. */ + dis_condjsr, /* Conditional jump to subroutine. */ + dis_dref, /* Data reference instruction. */ + dis_dref2 /* Two data references in instruction. */ +}; + +static enum dis_insn_type insn_type; + +#if 0 +/* + * Get LENGTH bytes from info's buffer, at target address memaddr. + * Transfer them to myaddr. + */ +int +read_memory (unsigned memaddr, + unsigned char *myaddr, + unsigned int nbytes) +{ + //unsigned char *buffer; + //unsigned int buffer_length; + //unsigned int buffer_vma; + + if (memaddr < buffer_vma || + memaddr - buffer_vma > buffer_length || + memaddr - buffer_vma + nbytes > buffer_length) { + /* Out of bounds. Use EIO because GDB uses it. */ + return EIO; + } + memcpy (myaddr, info->buffer + memaddr - buffer_vma, nbytes); + return 0; +} +#endif + +static void +print_address (unsigned address, FILE *stream) +{ + if (address < 16) + fprintf (stream, "%d", address); + else + fprintf (stream, "0x%x", address); +} + +static void +memory_error (int status, unsigned memaddr, FILE *stream) +{ + fprintf (stream, "Error reading memory at 0x%08x: %s", memaddr, strerror (status)); +} + +static const struct mips_cp0sel_name * +lookup_mips_cp0sel_name (const struct + mips_cp0sel_name *names, unsigned int len, unsigned int cp0reg, + unsigned int sel) +{ + unsigned int i; + + for (i = 0; i < len; i++) + if (names[i].cp0reg == cp0reg && names[i].sel == sel) + return &names[i]; + return NULL; +} + +/* + * CP0 register including 'sel' code for mftc0, to be + * printed textually if known. If not known, print both + * CP0 register name and sel numerically since CP0 register + * with sel 0 may have a name unrelated to register being + * printed. + */ +const char *cp0reg_name (unsigned cp0reg, unsigned sel) +{ + const struct mips_cp0sel_name *n; + static char name [32]; + + if (sel == 0) + return mips_cp0_names[cp0reg]; + + n = lookup_mips_cp0sel_name (mips_cp0sel_names, + mips_cp0sel_names_len, cp0reg, sel); + if (n != NULL) + return n->name; + + sprintf (name, "CP0_R[%d,%d]", cp0reg, sel); + return name; +} + +/* Print insn arguments for 32/64-bit code. */ + +static void +print_insn_args (const char *d, + register unsigned long int l, + unsigned pc, FILE *stream, const struct mips_opcode *opp) +{ + int op, delta; + unsigned int lsb, msb, msbd; + + lsb = 0; + + for (; *d != '\0'; d++) { + switch (*d) { + case ',': + case '(': + case ')': + case '[': + case ']': + fprintf (stream, "%c", *d); + break; + + case '+': + /* Extension character; switch for second char. */ + d++; + switch (*d) { + case '\0': + /* xgettext:c-format */ + fprintf (stream, + "# internal error, incomplete extension sequence (+)"); + return; + + case 'A': + lsb = (l >> OP_SH_SHAMT) & OP_MASK_SHAMT; + fprintf (stream, "0x%x", lsb); + break; + + case 'B': + msb = (l >> OP_SH_INSMSB) & OP_MASK_INSMSB; + fprintf (stream, "0x%x", msb - lsb + 1); + break; + + case '1': + fprintf (stream, "0x%lx", + (l >> OP_SH_UDI1) & OP_MASK_UDI1); + break; + + case '2': + fprintf (stream, "0x%lx", + (l >> OP_SH_UDI2) & OP_MASK_UDI2); + break; + + case '3': + fprintf (stream, "0x%lx", + (l >> OP_SH_UDI3) & OP_MASK_UDI3); + break; + + case '4': + fprintf (stream, "0x%lx", + (l >> OP_SH_UDI4) & OP_MASK_UDI4); + break; + + case 'C': + case 'H': + msbd = (l >> OP_SH_EXTMSBD) & OP_MASK_EXTMSBD; + fprintf (stream, "0x%x", msbd + 1); + break; + + case 'D': + { + const struct mips_cp0sel_name *n; + unsigned int cp0reg, sel; + + cp0reg = (l >> OP_SH_RD) & OP_MASK_RD; + sel = (l >> OP_SH_SEL) & OP_MASK_SEL; + + /* CP0 register including 'sel' code for mtcN (et al.), to be + * printed textually if known. If not known, print both + * CP0 register name and sel numerically since CP0 register + * with sel 0 may have a name unrelated to register being + * printed. */ + n = lookup_mips_cp0sel_name (mips_cp0sel_names, + mips_cp0sel_names_len, cp0reg, sel); + if (n != NULL) + fprintf (stream, "%s", n->name); + else + fprintf (stream, "$%d,%d", cp0reg, + sel); + break; + } + + case 'E': + lsb = ((l >> OP_SH_SHAMT) & OP_MASK_SHAMT) + 32; + fprintf (stream, "0x%x", lsb); + break; + + case 'F': + msb = ((l >> OP_SH_INSMSB) & OP_MASK_INSMSB) + 32; + fprintf (stream, "0x%x", msb - lsb + 1); + break; + + case 'G': + msbd = ((l >> OP_SH_EXTMSBD) & OP_MASK_EXTMSBD) + 32; + fprintf (stream, "0x%x", msbd + 1); + break; + + case 't': /* Coprocessor 0 reg name */ + fprintf (stream, "%s", + mips_cp0_names[(l >> OP_SH_RT) & OP_MASK_RT]); + break; + + case 'T': /* Coprocessor 0 reg name */ + { + const struct mips_cp0sel_name *n; + unsigned int cp0reg, sel; + + cp0reg = (l >> OP_SH_RT) & OP_MASK_RT; + sel = (l >> OP_SH_SEL) & OP_MASK_SEL; + + /* CP0 register including 'sel' code for mftc0, to be + * printed textually if known. If not known, print both + * CP0 register name and sel numerically since CP0 register + * with sel 0 may have a name unrelated to register being + * printed. */ + n = lookup_mips_cp0sel_name (mips_cp0sel_names, + mips_cp0sel_names_len, cp0reg, sel); + if (n != NULL) + fprintf (stream, "%s", n->name); + else + fprintf (stream, "$%d,%d", cp0reg, + sel); + break; + } + + case 'x': /* bbit bit index */ + fprintf (stream, "0x%lx", + (l >> OP_SH_BBITIND) & OP_MASK_BBITIND); + break; + + case 'p': /* cins, cins32, exts and exts32 position */ + fprintf (stream, "0x%lx", + (l >> OP_SH_CINSPOS) & OP_MASK_CINSPOS); + break; + + case 's': /* cins and exts length-minus-one */ + fprintf (stream, "0x%lx", + (l >> OP_SH_CINSLM1) & OP_MASK_CINSLM1); + break; + + case 'S': /* cins32 and exts32 length-minus-one field */ + fprintf (stream, "0x%lx", + (l >> OP_SH_CINSLM1) & OP_MASK_CINSLM1); + break; + + case 'Q': /* seqi/snei immediate field */ + op = (l >> OP_SH_SEQI) & OP_MASK_SEQI; + /* Sign-extend it. */ + op = (op ^ 512) - 512; + fprintf (stream, "%d", op); + break; + + default: + /* xgettext:c-format */ + fprintf (stream, "# internal error, undefined extension sequence (+%c)", *d); + return; + } + break; + + case '2': + fprintf (stream, "0x%lx", + (l >> OP_SH_BP) & OP_MASK_BP); + break; + + case '3': + fprintf (stream, "0x%lx", + (l >> OP_SH_SA3) & OP_MASK_SA3); + break; + + case '4': + fprintf (stream, "0x%lx", + (l >> OP_SH_SA4) & OP_MASK_SA4); + break; + + case '5': + fprintf (stream, "0x%lx", + (l >> OP_SH_IMM8) & OP_MASK_IMM8); + break; + + case '6': + fprintf (stream, "0x%lx", + (l >> OP_SH_RS) & OP_MASK_RS); + break; + + case '7': + fprintf (stream, "$ac%ld", + (l >> OP_SH_DSPACC) & OP_MASK_DSPACC); + break; + + case '8': + fprintf (stream, "0x%lx", + (l >> OP_SH_WRDSP) & OP_MASK_WRDSP); + break; + + case '9': + fprintf (stream, "$ac%ld", + (l >> OP_SH_DSPACC_S) & OP_MASK_DSPACC_S); + break; + + case '0': /* dsp 6-bit signed immediate in bit 20 */ + delta = ((l >> OP_SH_DSPSFT) & OP_MASK_DSPSFT); + if (delta & 0x20) /* test sign bit */ + delta |= ~OP_MASK_DSPSFT; + fprintf (stream, "%d", delta); + break; + + case ':': /* dsp 7-bit signed immediate in bit 19 */ + delta = ((l >> OP_SH_DSPSFT_7) & OP_MASK_DSPSFT_7); + if (delta & 0x40) /* test sign bit */ + delta |= ~OP_MASK_DSPSFT_7; + fprintf (stream, "%d", delta); + break; + + case '\'': + fprintf (stream, "0x%lx", + (l >> OP_SH_RDDSP) & OP_MASK_RDDSP); + break; + + case '@': /* dsp 10-bit signed immediate in bit 16 */ + delta = ((l >> OP_SH_IMM10) & OP_MASK_IMM10); + if (delta & 0x200) /* test sign bit */ + delta |= ~OP_MASK_IMM10; + fprintf (stream, "%d", delta); + break; + + case '!': + fprintf (stream, "%ld", + (l >> OP_SH_MT_U) & OP_MASK_MT_U); + break; + + case '$': + fprintf (stream, "%ld", + (l >> OP_SH_MT_H) & OP_MASK_MT_H); + break; + + case '*': + fprintf (stream, "$ac%ld", + (l >> OP_SH_MTACC_T) & OP_MASK_MTACC_T); + break; + + case '&': + fprintf (stream, "$ac%ld", + (l >> OP_SH_MTACC_D) & OP_MASK_MTACC_D); + break; + + case 'g': + /* Coprocessor register for CTTC1, MTTC2, MTHC2, CTTC2. */ + fprintf (stream, "$%ld", + (l >> OP_SH_RD) & OP_MASK_RD); + break; + + case 's': + case 'b': + case 'r': + case 'v': + fprintf (stream, "%s", + mips_gpr_names[(l >> OP_SH_RS) & OP_MASK_RS]); + break; + + case 't': + case 'w': + fprintf (stream, "%s", + mips_gpr_names[(l >> OP_SH_RT) & OP_MASK_RT]); + break; + + case 'i': + case 'u': + fprintf (stream, "0x%lx", + (l >> OP_SH_IMMEDIATE) & OP_MASK_IMMEDIATE); + break; + + case 'j': /* Same as i, but sign-extended. */ + case 'o': + delta = (l >> OP_SH_DELTA) & OP_MASK_DELTA; + if (delta & 0x8000) + delta |= ~0xffff; + fprintf (stream, "%d", delta); + break; + + case 'h': + fprintf (stream, "0x%x", + (unsigned int) ((l >> OP_SH_PREFX) + & OP_MASK_PREFX)); + break; + + case 'k': + fprintf (stream, "0x%x", + (unsigned int) ((l >> OP_SH_CACHE) + & OP_MASK_CACHE)); + break; + + case 'a': + target = (((pc + 4) & ~(unsigned) 0x0fffffff) + | (((l >> OP_SH_TARGET) & OP_MASK_TARGET) << 2)); + /* For gdb disassembler, force odd address on jalx. */ + if (strcmp (opp->name, "jalx") == 0) + target |= 1; + print_address (target, stream); + break; + + case 'p': + /* Sign extend the displacement. */ + delta = (l >> OP_SH_DELTA) & OP_MASK_DELTA; + if (delta & 0x8000) + delta |= ~0xffff; + target = (delta << 2) + pc + INSNLEN; + print_address (target, stream); + break; + + case 'd': + fprintf (stream, "%s", + mips_gpr_names[(l >> OP_SH_RD) & OP_MASK_RD]); + break; + + case 'U': + { + /* First check for both rd and rt being equal. */ + unsigned int reg = (l >> OP_SH_RD) & OP_MASK_RD; + if (reg == ((l >> OP_SH_RT) & OP_MASK_RT)) + fprintf (stream, "%s", + mips_gpr_names[reg]); + else { + /* If one is zero use the other. */ + if (reg == 0) + fprintf (stream, "%s", + mips_gpr_names[(l >> OP_SH_RT) & OP_MASK_RT]); + else if (((l >> OP_SH_RT) & OP_MASK_RT) == 0) + fprintf (stream, "%s", + mips_gpr_names[reg]); + else /* Bogus, result depends on processor. */ + fprintf (stream, "%s or %s", + mips_gpr_names[reg], + mips_gpr_names[(l >> OP_SH_RT) & OP_MASK_RT]); + } + } + break; + + case 'z': + fprintf (stream, "%s", mips_gpr_names[0]); + break; + + case '<': + case '1': + fprintf (stream, "0x%lx", + (l >> OP_SH_SHAMT) & OP_MASK_SHAMT); + break; + + case 'c': + fprintf (stream, "0x%lx", + (l >> OP_SH_CODE) & OP_MASK_CODE); + break; + + case 'q': + fprintf (stream, "0x%lx", + (l >> OP_SH_CODE2) & OP_MASK_CODE2); + break; + + case 'C': + fprintf (stream, "0x%lx", + (l >> OP_SH_COPZ) & OP_MASK_COPZ); + break; + + case 'B': + fprintf (stream, "0x%lx", + (l >> OP_SH_CODE20) & OP_MASK_CODE20); + break; + + case 'J': + fprintf (stream, "0x%lx", + (l >> OP_SH_CODE19) & OP_MASK_CODE19); + break; + + case 'S': + case 'V': + fprintf (stream, "%s", + mips_fpr_names[(l >> OP_SH_FS) & OP_MASK_FS]); + break; + + case 'T': + case 'W': + fprintf (stream, "%s", + mips_fpr_names[(l >> OP_SH_FT) & OP_MASK_FT]); + break; + + case 'D': + fprintf (stream, "%s", + mips_fpr_names[(l >> OP_SH_FD) & OP_MASK_FD]); + break; + + case 'R': + fprintf (stream, "%s", + mips_fpr_names[(l >> OP_SH_FR) & OP_MASK_FR]); + break; + + case 'E': + /* Coprocessor register for lwcN instructions, et al. + * + * Note that there is no load/store cp0 instructions, and + * that FPU (cp1) instructions disassemble this field using + * 'T' format. Therefore, until we gain understanding of + * cp2 register names, we can simply print the register + * numbers. */ + fprintf (stream, "$%ld", + (l >> OP_SH_RT) & OP_MASK_RT); + break; + + case 'G': + /* Coprocessor register for mtcN instructions, et al. Note + * that FPU (cp1) instructions disassemble this field using + * 'S' format. Therefore, we only need to worry about cp0, + * cp2, and cp3. */ + op = (l >> OP_SH_OP) & OP_MASK_OP; + if (op == OP_OP_COP0) + fprintf (stream, "%s", + mips_cp0_names[(l >> OP_SH_RD) & OP_MASK_RD]); + else + fprintf (stream, "$%ld", + (l >> OP_SH_RD) & OP_MASK_RD); + break; + + case 'K': + fprintf (stream, "%s", + mips_hwr_names[(l >> OP_SH_RD) & OP_MASK_RD]); + break; + + case 'N': + fprintf (stream, + ((opp->pinfo & (FP_D | FP_S)) != 0 + ? "$fcc%ld" : "$cc%ld"), (l >> OP_SH_BCC) & OP_MASK_BCC); + break; + + case 'M': + fprintf (stream, "$fcc%ld", + (l >> OP_SH_CCC) & OP_MASK_CCC); + break; + + case 'P': + fprintf (stream, "%ld", + (l >> OP_SH_PERFREG) & OP_MASK_PERFREG); + break; + + case 'e': + fprintf (stream, "%ld", + (l >> OP_SH_VECBYTE) & OP_MASK_VECBYTE); + break; + + case '%': + fprintf (stream, "%ld", + (l >> OP_SH_VECALIGN) & OP_MASK_VECALIGN); + break; + + case 'H': + fprintf (stream, "%ld", + (l >> OP_SH_SEL) & OP_MASK_SEL); + break; + + case 'O': + fprintf (stream, "%ld", + (l >> OP_SH_ALN) & OP_MASK_ALN); + break; + + case 'Q': + { + unsigned int vsel = (l >> OP_SH_VSEL) & OP_MASK_VSEL; + + if ((vsel & 0x10) == 0) { + int fmt; + + vsel &= 0x0f; + for (fmt = 0; fmt < 3; fmt++, vsel >>= 1) + if ((vsel & 1) == 0) + break; + fprintf (stream, "$v%ld[%d]", + (l >> OP_SH_FT) & OP_MASK_FT, vsel >> 1); + } else if ((vsel & 0x08) == 0) { + fprintf (stream, "$v%ld", + (l >> OP_SH_FT) & OP_MASK_FT); + } else { + fprintf (stream, "0x%lx", + (l >> OP_SH_FT) & OP_MASK_FT); + } + } + break; + + case 'X': + fprintf (stream, "$v%ld", + (l >> OP_SH_FD) & OP_MASK_FD); + break; + + case 'Y': + fprintf (stream, "$v%ld", + (l >> OP_SH_FS) & OP_MASK_FS); + break; + + case 'Z': + fprintf (stream, "$v%ld", + (l >> OP_SH_FT) & OP_MASK_FT); + break; + + default: + /* xgettext:c-format */ + fprintf (stream, "# internal error, undefined modifier (%c)", *d); + return; + } + } +} + +/* + * Print the mips instruction at address MEMADDR in debugged memory. + * Returns length of the instruction, in bytes, which is + * always INSNLEN. + */ +int +print_insn_mips (unsigned memaddr, + unsigned long int word, FILE *stream) +{ + const struct mips_opcode *op; + static int init = 0; + static const struct mips_opcode *mips_hash[OP_MASK_OP + 1]; + + /* Build a hash table to shorten the search time. */ + if (! init) { + unsigned int i; + + for (i = 0; i <= OP_MASK_OP; i++) { + for (op = mips_opcodes; op < &mips_opcodes[mips_num_opcodes]; op++) { + if (op->pinfo == INSN_MACRO + || (no_aliases && (op->pinfo2 & INSN2_ALIAS))) + continue; + if (i == ((op->match >> OP_SH_OP) & OP_MASK_OP)) { + mips_hash[i] = op; + break; + } + } + } + + init = 1; + } + + branch_delay_insns = 0; + data_size = 0; + insn_type = dis_nonbranch; + target = 0; + + op = mips_hash[(word >> OP_SH_OP) & OP_MASK_OP]; + if (op != NULL) { + for (; op < &mips_opcodes[mips_num_opcodes]; op++) { + if (op->pinfo != INSN_MACRO + && !(no_aliases && (op->pinfo2 & INSN2_ALIAS)) + && (word & op->mask) == op->match) { + const char *d; + + /* Figure out instruction type and branch delay information. */ + if ((op->pinfo & INSN_UNCOND_BRANCH_DELAY) != 0) { + if ((op->pinfo & (INSN_WRITE_GPR_31 + | INSN_WRITE_GPR_D)) != 0) + insn_type = dis_jsr; + else + insn_type = dis_branch; + branch_delay_insns = 1; + } else if ((op->pinfo & (INSN_COND_BRANCH_DELAY + | INSN_COND_BRANCH_LIKELY)) != 0) { + if ((op->pinfo & INSN_WRITE_GPR_31) != 0) + insn_type = dis_condjsr; + else + insn_type = dis_condbranch; + branch_delay_insns = 1; + } else if ((op->pinfo & (INSN_STORE_MEMORY + | INSN_LOAD_MEMORY_DELAY)) != 0) + insn_type = dis_dref; + + fprintf (stream, "%s", op->name); + + d = op->args; + if (d != NULL && *d != '\0') { + fprintf (stream, "\t"); + print_insn_args (d, word, memaddr, stream, op); + } + + return INSNLEN; + } + } + } + + /* Handle undefined instructions. */ + insn_type = dis_noninsn; + fprintf (stream, "0x%lx", word); + return INSNLEN; +} + +static unsigned +getb16 (const unsigned char *buf) +{ + return (buf[0] << 8) | buf[1]; +} + +static unsigned +getl16 (const unsigned char *buf) +{ + return (buf[1] << 8) | buf[0]; +} + +static unsigned +getb32 (const unsigned char *buf) +{ + unsigned long v; + + v = (unsigned long) buf[0] << 24; + v |= (unsigned long) buf[1] << 16; + v |= (unsigned long) buf[2] << 8; + v |= (unsigned long) buf[3]; + return v; +} + +static unsigned +getl32 (const unsigned char *buf) +{ + unsigned long v; + + v = (unsigned long) buf[0]; + v |= (unsigned long) buf[1] << 8; + v |= (unsigned long) buf[2] << 16; + v |= (unsigned long) buf[3] << 24; + return v; +} + +/* + * Disassemble an operand for a mips16 instruction. + */ +static void +print_mips16_insn_arg (char type, + const struct mips_opcode *op, + int l, + int use_extend, + int extend, unsigned memaddr, FILE *stream, + int (*read_memory) (unsigned addr, unsigned char *buf, unsigned nbytes)) +{ + switch (type) { + case ',': + case '(': + case ')': + fprintf (stream, "%c", type); + break; + + case 'y': + case 'w': + fprintf (stream, "%s", + mips16_reg_names (((l >> MIPS16OP_SH_RY) + & MIPS16OP_MASK_RY))); + break; + + case 'x': + case 'v': + fprintf (stream, "%s", + mips16_reg_names (((l >> MIPS16OP_SH_RX) + & MIPS16OP_MASK_RX))); + break; + + case 'z': + fprintf (stream, "%s", + mips16_reg_names (((l >> MIPS16OP_SH_RZ) + & MIPS16OP_MASK_RZ))); + break; + + case 'Z': + fprintf (stream, "%s", + mips16_reg_names (((l >> MIPS16OP_SH_MOVE32Z) + & MIPS16OP_MASK_MOVE32Z))); + break; + + case '0': + fprintf (stream, "%s", mips_gpr_names[0]); + break; + + case 'S': + fprintf (stream, "%s", mips_gpr_names[29]); + break; + + case 'P': + fprintf (stream, "$pc"); + break; + + case 'R': + fprintf (stream, "%s", mips_gpr_names[31]); + break; + + case 'X': + fprintf (stream, "%s", + mips_gpr_names[((l >> MIPS16OP_SH_REGR32) + & MIPS16OP_MASK_REGR32)]); + break; + + case 'Y': + fprintf (stream, "%s", + mips_gpr_names[MIPS16OP_EXTRACT_REG32R (l)]); + break; + + case '<': + case '>': + case '[': + case ']': + case '4': + case '5': + case 'H': + case 'W': + case 'D': + case 'j': + case '6': + case '8': + case 'V': + case 'C': + case 'U': + case 'k': + case 'K': + case 'p': + case 'q': + case 'A': + case 'B': + case 'E': + { + int immed, nbits, shift, signedp, extbits, pcrel, extu, branch; + + shift = 0; + signedp = 0; + extbits = 16; + pcrel = 0; + extu = 0; + branch = 0; + switch (type) { + case '<': + nbits = 3; + immed = (l >> MIPS16OP_SH_RZ) & MIPS16OP_MASK_RZ; + extbits = 5; + extu = 1; + break; + case '>': + nbits = 3; + immed = (l >> MIPS16OP_SH_RX) & MIPS16OP_MASK_RX; + extbits = 5; + extu = 1; + break; + case '[': + nbits = 3; + immed = (l >> MIPS16OP_SH_RZ) & MIPS16OP_MASK_RZ; + extbits = 6; + extu = 1; + break; + case ']': + nbits = 3; + immed = (l >> MIPS16OP_SH_RX) & MIPS16OP_MASK_RX; + extbits = 6; + extu = 1; + break; + case '4': + nbits = 4; + immed = (l >> MIPS16OP_SH_IMM4) & MIPS16OP_MASK_IMM4; + signedp = 1; + extbits = 15; + break; + case '5': + nbits = 5; + immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5; + insn_type = dis_dref; + data_size = 1; + break; + case 'H': + nbits = 5; + shift = 1; + immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5; + insn_type = dis_dref; + data_size = 2; + break; + case 'W': + nbits = 5; + shift = 2; + immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5; + if ((op->pinfo & MIPS16_INSN_READ_PC) == 0 + && (op->pinfo & MIPS16_INSN_READ_SP) == 0) { + insn_type = dis_dref; + data_size = 4; + } + break; + case 'D': + nbits = 5; + shift = 3; + immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5; + insn_type = dis_dref; + data_size = 8; + break; + case 'j': + nbits = 5; + immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5; + signedp = 1; + break; + case '6': + nbits = 6; + immed = (l >> MIPS16OP_SH_IMM6) & MIPS16OP_MASK_IMM6; + break; + case '8': + nbits = 8; + immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8; + break; + case 'V': + nbits = 8; + shift = 2; + immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8; + /* FIXME: This might be lw, or it might be addiu to $sp or + * $pc. We assume it's load. */ + insn_type = dis_dref; + data_size = 4; + break; + case 'C': + nbits = 8; + shift = 3; + immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8; + insn_type = dis_dref; + data_size = 8; + break; + case 'U': + nbits = 8; + immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8; + extu = 1; + break; + case 'k': + nbits = 8; + immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8; + signedp = 1; + break; + case 'K': + nbits = 8; + shift = 3; + immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8; + signedp = 1; + break; + case 'p': + nbits = 8; + immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8; + signedp = 1; + pcrel = 1; + branch = 1; + break; + case 'q': + nbits = 11; + immed = (l >> MIPS16OP_SH_IMM11) & MIPS16OP_MASK_IMM11; + signedp = 1; + pcrel = 1; + branch = 1; + break; + case 'A': + nbits = 8; + shift = 2; + immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8; + pcrel = 1; + /* FIXME: This can be lw or la. We assume it is lw. */ + insn_type = dis_dref; + data_size = 4; + break; + case 'B': + nbits = 5; + shift = 3; + immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5; + pcrel = 1; + insn_type = dis_dref; + data_size = 8; + break; + case 'E': + nbits = 5; + shift = 2; + immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5; + pcrel = 1; + break; + default: + fprintf (stream, "# internal disassembler error, unrecognised mips16 type (%c)", type); + abort (); + } + + if (!use_extend) { + if (signedp && immed >= (1 << (nbits - 1))) + immed -= 1 << nbits; + immed <<= shift; + if ((type == '<' || type == '>' || type == '[' || type == ']') + && immed == 0) + immed = 8; + } else { + if (extbits == 16) + immed |= ((extend & 0x1f) << 11) | (extend & 0x7e0); + else if (extbits == 15) + immed |= ((extend & 0xf) << 11) | (extend & 0x7f0); + else + immed = ((extend >> 6) & 0x1f) | (extend & 0x20); + immed &= (1 << extbits) - 1; + if (!extu && immed >= (1 << (extbits - 1))) + immed -= 1 << extbits; + } + + if (!pcrel) + fprintf (stream, "%d", immed); + else { + unsigned baseaddr; + + if (branch) { + immed *= 2; + baseaddr = memaddr + 2; + } else if (use_extend) + baseaddr = memaddr - 2; + else { + int status; + unsigned char buffer[2]; + + baseaddr = memaddr; + + /* If this instruction is in the delay slot of a jr + * instruction, the base address is the address of the + * jr instruction. If it is in the delay slot of jalr + * instruction, the base address is the address of the + * jalr instruction. This test is unreliable: we have + * no way of knowing whether the previous word is + * instruction or data. */ + status = read_memory (memaddr - 4, buffer, 2); + if (status == 0 + && (((big_endian ? getb16 (buffer) + : getl16 (buffer)) + & 0xf800) == 0x1800)) + baseaddr = memaddr - 4; + else { + status = read_memory (memaddr - 2, buffer, 2); + if (status == 0 + && (((big_endian ? getb16 (buffer) + : getl16 (buffer)) + & 0xf81f) == 0xe800)) + baseaddr = memaddr - 2; + } + } + target = (baseaddr & ~((1 << shift) - 1)) + immed; + if (pcrel && branch) + /* For gdb disassembler, maintain odd address. */ + target |= 1; + print_address (target, stream); + } + } + break; + + case 'a': + { + int jalx = l & 0x400; + + if (!use_extend) + extend = 0; + l = ((l & 0x1f) << 23) | ((l & 0x3e0) << 13) | (extend << 2); + if (! jalx) + /* For gdb disassembler, maintain odd address. */ + l |= 1; + } + target = ((memaddr + 4) & ~(unsigned) 0x0fffffff) | l; + print_address (target, stream); + break; + + case 'l': + case 'L': + { + int need_comma, amask, smask; + + need_comma = 0; + + l = (l >> MIPS16OP_SH_IMM6) & MIPS16OP_MASK_IMM6; + + amask = (l >> 3) & 7; + + if (amask > 0 && amask < 5) { + fprintf (stream, "%s", mips_gpr_names[4]); + if (amask > 1) + fprintf (stream, "-%s", + mips_gpr_names[amask + 3]); + need_comma = 1; + } + + smask = (l >> 1) & 3; + if (smask == 3) { + fprintf (stream, "%s??", + need_comma ? "," : ""); + need_comma = 1; + } else if (smask > 0) { + fprintf (stream, "%s%s", + need_comma ? "," : "", mips_gpr_names[16]); + if (smask > 1) + fprintf (stream, "-%s", + mips_gpr_names[smask + 15]); + need_comma = 1; + } + + if (l & 1) { + fprintf (stream, "%s%s", + need_comma ? "," : "", mips_gpr_names[31]); + need_comma = 1; + } + + if (amask == 5 || amask == 6) { + fprintf (stream, "%s$f0", + need_comma ? "," : ""); + if (amask == 6) + fprintf (stream, "-$f1"); + } + } + break; + + case 'm': + case 'M': + /* MIPS16e save/restore. */ + { + int need_comma = 0; + int amask, args, statics; + int nsreg, smask; + int framesz; + int i, j; + + l = l & 0x7f; + if (use_extend) + l |= extend << 16; + + amask = (l >> 16) & 0xf; + if (amask == MIPS16_ALL_ARGS) { + args = 4; + statics = 0; + } else if (amask == MIPS16_ALL_STATICS) { + args = 0; + statics = 4; + } else { + args = amask >> 2; + statics = amask & 3; + } + + if (args > 0) { + fprintf (stream, "%s", mips_gpr_names[4]); + if (args > 1) + fprintf (stream, "-%s", + mips_gpr_names[4 + args - 1]); + need_comma = 1; + } + + framesz = (((l >> 16) & 0xf0) | (l & 0x0f)) * 8; + if (framesz == 0 && !use_extend) + framesz = 128; + + fprintf (stream, "%s%d", + need_comma ? "," : "", framesz); + + if (l & 0x40) /* $ra */ + fprintf (stream, ",%s", + mips_gpr_names[31]); + + nsreg = (l >> 24) & 0x7; + smask = 0; + if (l & 0x20) /* $s0 */ + smask |= 1 << 0; + if (l & 0x10) /* $s1 */ + smask |= 1 << 1; + if (nsreg > 0) /* $s2-$s8 */ + smask |= ((1 << nsreg) - 1) << 2; + + /* Find first set static reg bit. */ + for (i = 0; i < 9; i++) { + if (smask & (1 << i)) { + fprintf (stream, ",%s", + mips_gpr_names[i == 8 ? 30 : (16 + i)]); + /* Skip over string of set bits. */ + for (j = i; smask & (2 << j); j++) + continue; + if (j > i) + fprintf (stream, "-%s", + mips_gpr_names[j == 8 ? 30 : (16 + j)]); + i = j + 1; + } + } + + /* Statics $ax - $a3. */ + if (statics == 1) + fprintf (stream, ",%s", + mips_gpr_names[7]); + else if (statics > 0) + fprintf (stream, ",%s-%s", + mips_gpr_names[7 - statics + 1], mips_gpr_names[7]); + } + break; + + default: + /* xgettext:c-format */ + fprintf (stream, "# internal disassembler error, unrecognised modifier (%c)", type); + abort (); + } +} + +/* Disassemble mips16 instructions. */ + +static int print_insn_mips16 (unsigned memaddr, FILE *stream, + int (*read_memory) (unsigned addr, unsigned char *buf, unsigned nbytes)) +{ + int status; + unsigned char buffer[2]; + int length; + int insn; + int use_extend; + int extend = 0; + const struct mips_opcode *op, *opend; + + branch_delay_insns = 0; + data_size = 0; + insn_type = dis_nonbranch; + target = 0; + + status = read_memory (memaddr, buffer, 2); + if (status != 0) { + memory_error (status, memaddr, stream); + return -1; + } + + length = 2; + + if (big_endian) + insn = getb16 (buffer); + else + insn = getl16 (buffer); + + /* Handle the extend opcode specially. */ + use_extend = 0; + if ((insn & 0xf800) == 0xf000) { + use_extend = 1; + extend = insn & 0x7ff; + + memaddr += 2; + + status = read_memory (memaddr, buffer, 2); + if (status != 0) { + fprintf (stream, "extend 0x%x", + (unsigned int) extend); + memory_error (status, memaddr, stream); + return -1; + } + + if (big_endian) + insn = getb16 (buffer); + else + insn = getl16 (buffer); + + /* Check for an extend opcode followed by an extend opcode. */ + if ((insn & 0xf800) == 0xf000) { + fprintf (stream, "extend 0x%x", + (unsigned int) extend); + insn_type = dis_noninsn; + return length; + } + + length += 2; + } + + /* FIXME: Should probably use a hash table on the major opcode here. */ + + opend = mips16_opcodes + mips16_num_opcodes; + for (op = mips16_opcodes; op < opend; op++) { + if (op->pinfo != INSN_MACRO + && !(no_aliases && (op->pinfo2 & INSN2_ALIAS)) + && (insn & op->mask) == op->match) { + const char *s; + + if (strchr (op->args, 'a') != NULL) { + if (use_extend) { + fprintf (stream, "extend 0x%x", + (unsigned int) extend); + insn_type = dis_noninsn; + return length - 2; + } + + use_extend = 0; + + memaddr += 2; + + status = read_memory (memaddr, buffer, 2); + if (status == 0) { + use_extend = 1; + if (big_endian) + extend = getb16 (buffer); + else + extend = getl16 (buffer); + length += 2; + } + } + + fprintf (stream, "%s", op->name); + if (op->args[0] != '\0') + fprintf (stream, "\t"); + + for (s = op->args; *s != '\0'; s++) { + if (*s == ',' + && s[1] == 'w' + && (((insn >> MIPS16OP_SH_RX) & MIPS16OP_MASK_RX) + == ((insn >> MIPS16OP_SH_RY) & MIPS16OP_MASK_RY))) { + /* Skip the register and the comma. */ + ++s; + continue; + } + if (*s == ',' + && s[1] == 'v' + && (((insn >> MIPS16OP_SH_RZ) & MIPS16OP_MASK_RZ) + == ((insn >> MIPS16OP_SH_RX) & MIPS16OP_MASK_RX))) { + /* Skip the register and the comma. */ + ++s; + continue; + } + print_mips16_insn_arg (*s, op, insn, use_extend, extend, + memaddr, stream, read_memory); + } + + /* Figure out branch instruction type and delay slot information. */ + if ((op->pinfo & INSN_UNCOND_BRANCH_DELAY) != 0) + branch_delay_insns = 1; + if ((op->pinfo & (INSN_UNCOND_BRANCH_DELAY + | MIPS16_INSN_UNCOND_BRANCH)) != 0) { + if ((op->pinfo & INSN_WRITE_GPR_31) != 0) + insn_type = dis_jsr; + else + insn_type = dis_branch; + } else if ((op->pinfo & MIPS16_INSN_COND_BRANCH) != 0) + insn_type = dis_condbranch; + + return length; + } + } + + if (use_extend) + fprintf (stream, "0x%x", extend | 0xf000); + fprintf (stream, "0x%x", insn); + insn_type = dis_noninsn; + + return length; +} + +/* + * In an environment where we do not know the symbol type of the + * instruction we are forced to assume that the low order bit of the + * instructions' address may mark it as a mips16 instruction. If we + * are single stepping, or the pc is within the disassembled function, + * this works. Otherwise, we need a clue. Sometimes. + */ +int +print_mips (unsigned memaddr, FILE *stream, int bigendian_flag, + int (*read_memory) (unsigned addr, unsigned char *buf, unsigned nbytes)) +{ + unsigned char buffer[INSNLEN]; + int status; + + big_endian = bigendian_flag; +#if 1 + /* FIXME: If odd address, this is CLEARLY a mips 16 instruction. */ + /* Only a few tools will work this way. */ + if (memaddr & 0x01) + return print_insn_mips16 (memaddr, stream, read_memory); +#endif + + status = read_memory (memaddr, buffer, INSNLEN); + if (status == 0) { + unsigned long insn; + + if (big_endian) + insn = (unsigned long) getb32 (buffer); + else + insn = (unsigned long) getl32 (buffer); + + return print_insn_mips (memaddr, insn, stream); + } else { + memory_error (status, memaddr, stream); + return -1; + } +} diff --git a/tools/virtualmips/mips-opc.c b/tools/virtualmips/mips-opc.c new file mode 100644 index 0000000..8e906db --- /dev/null +++ b/tools/virtualmips/mips-opc.c @@ -0,0 +1,2068 @@ +/* + * MIPS opcode list. + * + * Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002 + * 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc. + * Contributed by Ralph Campbell and OSF + * Commented and modified by Ian Lance Taylor, Cygnus Support + * Extended for MIPS32 support by Anders Norlander, and by SiByte, Inc. + * MIPS-3D, MDMX, and MIPS32 Release 2 support added by Broadcom + * Corporation (SiByte). + * Adapted for VirtualMIPS by Serge Vakulenko. + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + */ + +/* Short hand so the lines aren't too long. */ + +#define LDD INSN_LOAD_MEMORY_DELAY +#define LCD INSN_LOAD_COPROC_DELAY +#define UBD INSN_UNCOND_BRANCH_DELAY +#define CBD INSN_COND_BRANCH_DELAY +#define COD INSN_COPROC_MOVE_DELAY +#define CLD INSN_COPROC_MEMORY_DELAY +#define CBL INSN_COND_BRANCH_LIKELY +#define TRAP INSN_TRAP +#define SM INSN_STORE_MEMORY + +#define WR_d INSN_WRITE_GPR_D +#define WR_t INSN_WRITE_GPR_T +#define WR_31 INSN_WRITE_GPR_31 +#define WR_D INSN_WRITE_FPR_D +#define WR_T INSN_WRITE_FPR_T +#define WR_S INSN_WRITE_FPR_S +#define RD_s INSN_READ_GPR_S +#define RD_b INSN_READ_GPR_S +#define RD_t INSN_READ_GPR_T +#define RD_S INSN_READ_FPR_S +#define RD_T INSN_READ_FPR_T +#define RD_R INSN_READ_FPR_R +#define WR_CC INSN_WRITE_COND_CODE +#define RD_CC INSN_READ_COND_CODE +#define RD_C0 INSN_COP +#define RD_C1 INSN_COP +#define RD_C2 INSN_COP +#define RD_C3 INSN_COP +#define WR_C0 INSN_COP +#define WR_C1 INSN_COP +#define WR_C2 INSN_COP +#define WR_C3 INSN_COP +#define CP INSN_COP + +#define WR_HI INSN_WRITE_HI +#define RD_HI INSN_READ_HI +#define MOD_HI WR_HI|RD_HI + +#define WR_LO INSN_WRITE_LO +#define RD_LO INSN_READ_LO +#define MOD_LO WR_LO|RD_LO + +#define WR_HILO WR_HI|WR_LO +#define RD_HILO RD_HI|RD_LO +#define MOD_HILO WR_HILO|RD_HILO + +#define IS_M INSN_MULT + +#define WR_MACC INSN2_WRITE_MDMX_ACC +#define RD_MACC INSN2_READ_MDMX_ACC + +#define I1 INSN_ISA1 +#define I2 INSN_ISA2 +#define I3 INSN_ISA3 +#define I4 INSN_ISA4 +#define I5 INSN_ISA5 +#define I32 INSN_ISA32 +#define I64 INSN_ISA64 +#define I33 INSN_ISA32R2 +#define I65 INSN_ISA64R2 +#define I3_32 INSN_ISA3_32 +#define I3_33 INSN_ISA3_32R2 +#define I4_32 INSN_ISA4_32 +#define I4_33 INSN_ISA4_32R2 +#define I5_33 INSN_ISA5_32R2 + +/* MIPS64 MIPS-3D ASE support. */ +#define M3D INSN_MIPS3D + +/* MIPS32 SmartMIPS ASE support. */ +#define SMT INSN_SMARTMIPS + +/* MIPS64 MDMX ASE support. */ +#define MX INSN_MDMX + +#define IL2E (INSN_LOONGSON_2E) +#define IL2F (INSN_LOONGSON_2F) + +#define P3 INSN_4650 +#define L1 INSN_4010 +#define V1 (INSN_4100 | INSN_4111 | INSN_4120) +#define T3 INSN_3900 +#define M1 INSN_10000 +#define SB1 INSN_SB1 +#define N411 INSN_4111 +#define N412 INSN_4120 +#define N5 (INSN_5400 | INSN_5500) +#define N54 INSN_5400 +#define N55 INSN_5500 +#define IOCT INSN_OCTEON +#define XLR INSN_XLR + +#define G1 (T3 \ + ) + +#define G2 (T3 \ + ) + +#define G3 (I4 \ + ) + +/* MIPS DSP ASE support. + NOTE: + 1. MIPS DSP ASE includes 4 accumulators ($ac0 - $ac3). $ac0 is the pair + of original HI and LO. $ac1, $ac2 and $ac3 are new registers, and have + the same structure as $ac0 (HI + LO). For DSP instructions that write or + read accumulators (that may be $ac0), we add WR_a (WR_HILO) or RD_a + (RD_HILO) attributes, such that HILO dependencies are maintained + conservatively. + + 2. For some mul. instructions that use integer registers as destinations + but destroy HI+LO as side-effect, we add WR_HILO to their attributes. + + 3. MIPS DSP ASE includes a new DSP control register, which has 6 fields + (ccond, outflag, EFI, c, scount, pos). Many DSP instructions read or write + certain fields of the DSP control register. For simplicity, we decide not + to track dependencies of these fields. + However, "bposge32" is a branch instruction that depends on the "pos" + field. In order to make sure that GAS does not reorder DSP instructions + that writes the "pos" field and "bposge32", we add DSP_VOLA (INSN_TRAP) + attribute to those instructions that write the "pos" field. */ + +#define WR_a WR_HILO /* Write dsp accumulators (reuse WR_HILO) */ +#define RD_a RD_HILO /* Read dsp accumulators (reuse RD_HILO) */ +#define MOD_a WR_a|RD_a +#define DSP_VOLA INSN_TRAP +#define D32 INSN_DSP +#define D33 INSN_DSPR2 +#define D64 INSN_DSP64 + +/* MIPS MT ASE support. */ +#define MT32 INSN_MT + +/* The order of overloaded instructions matters. Label arguments and + register arguments look the same. Instructions that can have either + for arguments must apear in the correct order in this table for the + assembler to pick the right one. In other words, entries with + immediate operands must apear after the same instruction with + registers. + + Because of the lookup algorithm used, entries with the same opcode + name must be contiguous. + + Many instructions are short hand for other instructions (i.e., The + jal instruction is short for jalr ). */ + +static const struct mips_opcode mips_opcodes[] = +{ +/* These instructions appear first so that the disassembler will find + them first. The assemblers uses a hash table based on the + instruction name anyhow. */ +/* name, args, match, mask, pinfo, pinfo2, membership */ +{"pref", "k,o(b)", 0xcc000000, 0xfc000000, RD_b, 0, I4_32|G3 }, +{"prefx", "h,t(b)", 0x4c00000f, 0xfc0007ff, RD_b|RD_t|FP_S, 0, I4_33 }, +{"nop", "", 0x00000000, 0xffffffff, 0, INSN2_ALIAS, I1 }, /* sll */ +{"ssnop", "", 0x00000040, 0xffffffff, 0, INSN2_ALIAS, I1 }, /* sll */ +{"ehb", "", 0x000000c0, 0xffffffff, 0, INSN2_ALIAS, I1 }, /* sll */ +{"li", "t,j", 0x24000000, 0xffe00000, WR_t, INSN2_ALIAS, I1 }, /* addiu */ +{"li", "t,i", 0x34000000, 0xffe00000, WR_t, INSN2_ALIAS, I1 }, /* ori */ +{"li", "t,I", 0, (int) M_LI, INSN_MACRO, 0, I1 }, +{"move", "d,s", 0, (int) M_MOVE, INSN_MACRO, 0, I1 }, +{"move", "d,s", 0x0000002d, 0xfc1f07ff, WR_d|RD_s, INSN2_ALIAS, I3 },/* daddu */ +{"move", "d,s", 0x00000021, 0xfc1f07ff, WR_d|RD_s, INSN2_ALIAS, I1 },/* addu */ +{"move", "d,s", 0x00000025, 0xfc1f07ff, WR_d|RD_s, INSN2_ALIAS, I1 },/* or */ +{"b", "p", 0x10000000, 0xffff0000, UBD, INSN2_ALIAS, I1 },/* beq 0,0 */ +{"b", "p", 0x04010000, 0xffff0000, UBD, INSN2_ALIAS, I1 },/* bgez 0 */ +{"bal", "p", 0x04110000, 0xffff0000, UBD|WR_31, INSN2_ALIAS, I1 },/* bgezal 0*/ + +{"abs", "d,v", 0, (int) M_ABS, INSN_MACRO, 0, I1 }, +{"abs.s", "D,V", 0x46000005, 0xffff003f, WR_D|RD_S|FP_S, 0, I1 }, +{"abs.d", "D,V", 0x46200005, 0xffff003f, WR_D|RD_S|FP_D, 0, I1 }, +{"abs.ps", "D,V", 0x46c00005, 0xffff003f, WR_D|RD_S|FP_D, 0, I5_33|IL2F }, +{"abs.ps", "D,V", 0x45600005, 0xffff003f, WR_D|RD_S|FP_D, 0, IL2E }, +{"add", "d,v,t", 0x00000020, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I1 }, +{"add", "t,r,I", 0, (int) M_ADD_I, INSN_MACRO, 0, I1 }, +{"add", "D,S,T", 0x45c00000, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, IL2E }, +{"add", "D,S,T", 0x4b40000c, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, IL2F }, +{"add.s", "D,V,T", 0x46000000, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, 0, I1 }, +{"add.d", "D,V,T", 0x46200000, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I1 }, +{"add.ob", "X,Y,Q", 0x7800000b, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX|SB1 }, +{"add.ob", "D,S,T", 0x4ac0000b, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"add.ob", "D,S,T[e]", 0x4800000b, 0xfe20003f, WR_D|RD_S|RD_T, 0, N54 }, +{"add.ob", "D,S,k", 0x4bc0000b, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"add.ps", "D,V,T", 0x46c00000, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I5_33|IL2F }, +{"add.ps", "D,V,T", 0x45600000, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, IL2E }, +{"add.qh", "X,Y,Q", 0x7820000b, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, +{"adda.ob", "Y,Q", 0x78000037, 0xfc2007ff, RD_S|RD_T|FP_D, WR_MACC, MX|SB1 }, +{"adda.qh", "Y,Q", 0x78200037, 0xfc2007ff, RD_S|RD_T|FP_D, WR_MACC, MX }, +{"addi", "t,r,j", 0x20000000, 0xfc000000, WR_t|RD_s, 0, I1 }, +{"addiu", "t,r,j", 0x24000000, 0xfc000000, WR_t|RD_s, 0, I1 }, +{"addl.ob", "Y,Q", 0x78000437, 0xfc2007ff, RD_S|RD_T|FP_D, WR_MACC, MX|SB1 }, +{"addl.qh", "Y,Q", 0x78200437, 0xfc2007ff, RD_S|RD_T|FP_D, WR_MACC, MX }, +{"addr.ps", "D,S,T", 0x46c00018, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, M3D }, +{"addu", "d,v,t", 0x00000021, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I1 }, +{"addu", "t,r,I", 0, (int) M_ADDU_I, INSN_MACRO, 0, I1 }, +{"addu", "D,S,T", 0x45800000, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, IL2E }, +{"addu", "D,S,T", 0x4b00000c, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, IL2F }, +{"alni.ob", "X,Y,Z,O", 0x78000018, 0xff00003f, WR_D|RD_S|RD_T|FP_D, 0, MX|SB1 }, +{"alni.ob", "D,S,T,%", 0x48000018, 0xff00003f, WR_D|RD_S|RD_T, 0, N54 }, +{"alni.qh", "X,Y,Z,O", 0x7800001a, 0xff00003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, +{"alnv.ps", "D,V,T,s", 0x4c00001e, 0xfc00003f, WR_D|RD_S|RD_T|FP_D, 0, I5_33 }, +{"alnv.ob", "X,Y,Z,s", 0x78000019, 0xfc00003f, WR_D|RD_S|RD_T|RD_s|FP_D, 0, MX|SB1 }, +{"alnv.qh", "X,Y,Z,s", 0x7800001b, 0xfc00003f, WR_D|RD_S|RD_T|RD_s|FP_D, 0, MX }, +{"and", "d,v,t", 0x00000024, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I1 }, +{"and", "t,r,I", 0, (int) M_AND_I, INSN_MACRO, 0, I1 }, +{"and", "D,S,T", 0x47c00002, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2E }, +{"and", "D,S,T", 0x4bc00002, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2F }, +{"and.ob", "X,Y,Q", 0x7800000c, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX|SB1 }, +{"and.ob", "D,S,T", 0x4ac0000c, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"and.ob", "D,S,T[e]", 0x4800000c, 0xfe20003f, WR_D|RD_S|RD_T, 0, N54 }, +{"and.ob", "D,S,k", 0x4bc0000c, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"and.qh", "X,Y,Q", 0x7820000c, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, +{"andi", "t,r,i", 0x30000000, 0xfc000000, WR_t|RD_s, 0, I1 }, +{"baddu", "d,v,t", 0x70000028, 0xfc0007ff, WR_d|RD_s|RD_t, 0, IOCT }, +/* b is at the top of the table. */ +/* bal is at the top of the table. */ +{"bbit032", "s,+x,p", 0xd8000000, 0xfc000000, RD_s|CBD, 0, IOCT }, +{"bbit0", "s,+X,p", 0xd8000000, 0xfc000000, RD_s|CBD, 0, IOCT }, /* bbit032 */ +{"bbit0", "s,+x,p", 0xc8000000, 0xfc000000, RD_s|CBD, 0, IOCT }, +{"bbit132", "s,+x,p", 0xf8000000, 0xfc000000, RD_s|CBD, 0, IOCT }, +{"bbit1", "s,+X,p", 0xf8000000, 0xfc000000, RD_s|CBD, 0, IOCT }, /* bbit132 */ +{"bbit1", "s,+x,p", 0xe8000000, 0xfc000000, RD_s|CBD, 0, IOCT }, +/* bc0[tf]l? are at the bottom of the table. */ +{"bc1any2f", "N,p", 0x45200000, 0xffe30000, CBD|RD_CC|FP_S, 0, M3D }, +{"bc1any2t", "N,p", 0x45210000, 0xffe30000, CBD|RD_CC|FP_S, 0, M3D }, +{"bc1any4f", "N,p", 0x45400000, 0xffe30000, CBD|RD_CC|FP_S, 0, M3D }, +{"bc1any4t", "N,p", 0x45410000, 0xffe30000, CBD|RD_CC|FP_S, 0, M3D }, +{"bc1f", "p", 0x45000000, 0xffff0000, CBD|RD_CC|FP_S, 0, I1 }, +{"bc1f", "N,p", 0x45000000, 0xffe30000, CBD|RD_CC|FP_S, 0, I4_32 }, +{"bc1fl", "p", 0x45020000, 0xffff0000, CBL|RD_CC|FP_S, 0, I2|T3 }, +{"bc1fl", "N,p", 0x45020000, 0xffe30000, CBL|RD_CC|FP_S, 0, I4_32 }, +{"bc1t", "p", 0x45010000, 0xffff0000, CBD|RD_CC|FP_S, 0, I1 }, +{"bc1t", "N,p", 0x45010000, 0xffe30000, CBD|RD_CC|FP_S, 0, I4_32 }, +{"bc1tl", "p", 0x45030000, 0xffff0000, CBL|RD_CC|FP_S, 0, I2|T3 }, +{"bc1tl", "N,p", 0x45030000, 0xffe30000, CBL|RD_CC|FP_S, 0, I4_32 }, +/* bc2* are at the bottom of the table. */ +/* bc3* are at the bottom of the table. */ +{"beqz", "s,p", 0x10000000, 0xfc1f0000, CBD|RD_s, 0, I1 }, +{"beqzl", "s,p", 0x50000000, 0xfc1f0000, CBL|RD_s, 0, I2|T3 }, +{"beq", "s,t,p", 0x10000000, 0xfc000000, CBD|RD_s|RD_t, 0, I1 }, +{"beq", "s,I,p", 0, (int) M_BEQ_I, INSN_MACRO, 0, I1 }, +{"beql", "s,t,p", 0x50000000, 0xfc000000, CBL|RD_s|RD_t, 0, I2|T3 }, +{"beql", "s,I,p", 0, (int) M_BEQL_I, INSN_MACRO, 0, I2|T3 }, +{"bge", "s,t,p", 0, (int) M_BGE, INSN_MACRO, 0, I1 }, +{"bge", "s,I,p", 0, (int) M_BGE_I, INSN_MACRO, 0, I1 }, +{"bgel", "s,t,p", 0, (int) M_BGEL, INSN_MACRO, 0, I2|T3 }, +{"bgel", "s,I,p", 0, (int) M_BGEL_I, INSN_MACRO, 0, I2|T3 }, +{"bgeu", "s,t,p", 0, (int) M_BGEU, INSN_MACRO, 0, I1 }, +{"bgeu", "s,I,p", 0, (int) M_BGEU_I, INSN_MACRO, 0, I1 }, +{"bgeul", "s,t,p", 0, (int) M_BGEUL, INSN_MACRO, 0, I2|T3 }, +{"bgeul", "s,I,p", 0, (int) M_BGEUL_I, INSN_MACRO, 0, I2|T3 }, +{"bgez", "s,p", 0x04010000, 0xfc1f0000, CBD|RD_s, 0, I1 }, +{"bgezl", "s,p", 0x04030000, 0xfc1f0000, CBL|RD_s, 0, I2|T3 }, +{"bgezal", "s,p", 0x04110000, 0xfc1f0000, CBD|RD_s|WR_31, 0, I1 }, +{"bgezall", "s,p", 0x04130000, 0xfc1f0000, CBL|RD_s|WR_31, 0, I2|T3 }, +{"bgt", "s,t,p", 0, (int) M_BGT, INSN_MACRO, 0, I1 }, +{"bgt", "s,I,p", 0, (int) M_BGT_I, INSN_MACRO, 0, I1 }, +{"bgtl", "s,t,p", 0, (int) M_BGTL, INSN_MACRO, 0, I2|T3 }, +{"bgtl", "s,I,p", 0, (int) M_BGTL_I, INSN_MACRO, 0, I2|T3 }, +{"bgtu", "s,t,p", 0, (int) M_BGTU, INSN_MACRO, 0, I1 }, +{"bgtu", "s,I,p", 0, (int) M_BGTU_I, INSN_MACRO, 0, I1 }, +{"bgtul", "s,t,p", 0, (int) M_BGTUL, INSN_MACRO, 0, I2|T3 }, +{"bgtul", "s,I,p", 0, (int) M_BGTUL_I, INSN_MACRO, 0, I2|T3 }, +{"bgtz", "s,p", 0x1c000000, 0xfc1f0000, CBD|RD_s, 0, I1 }, +{"bgtzl", "s,p", 0x5c000000, 0xfc1f0000, CBL|RD_s, 0, I2|T3 }, +{"ble", "s,t,p", 0, (int) M_BLE, INSN_MACRO, 0, I1 }, +{"ble", "s,I,p", 0, (int) M_BLE_I, INSN_MACRO, 0, I1 }, +{"blel", "s,t,p", 0, (int) M_BLEL, INSN_MACRO, 0, I2|T3 }, +{"blel", "s,I,p", 0, (int) M_BLEL_I, INSN_MACRO, 0, I2|T3 }, +{"bleu", "s,t,p", 0, (int) M_BLEU, INSN_MACRO, 0, I1 }, +{"bleu", "s,I,p", 0, (int) M_BLEU_I, INSN_MACRO, 0, I1 }, +{"bleul", "s,t,p", 0, (int) M_BLEUL, INSN_MACRO, 0, I2|T3 }, +{"bleul", "s,I,p", 0, (int) M_BLEUL_I, INSN_MACRO, 0, I2|T3 }, +{"blez", "s,p", 0x18000000, 0xfc1f0000, CBD|RD_s, 0, I1 }, +{"blezl", "s,p", 0x58000000, 0xfc1f0000, CBL|RD_s, 0, I2|T3 }, +{"blt", "s,t,p", 0, (int) M_BLT, INSN_MACRO, 0, I1 }, +{"blt", "s,I,p", 0, (int) M_BLT_I, INSN_MACRO, 0, I1 }, +{"bltl", "s,t,p", 0, (int) M_BLTL, INSN_MACRO, 0, I2|T3 }, +{"bltl", "s,I,p", 0, (int) M_BLTL_I, INSN_MACRO, 0, I2|T3 }, +{"bltu", "s,t,p", 0, (int) M_BLTU, INSN_MACRO, 0, I1 }, +{"bltu", "s,I,p", 0, (int) M_BLTU_I, INSN_MACRO, 0, I1 }, +{"bltul", "s,t,p", 0, (int) M_BLTUL, INSN_MACRO, 0, I2|T3 }, +{"bltul", "s,I,p", 0, (int) M_BLTUL_I, INSN_MACRO, 0, I2|T3 }, +{"bltz", "s,p", 0x04000000, 0xfc1f0000, CBD|RD_s, 0, I1 }, +{"bltzl", "s,p", 0x04020000, 0xfc1f0000, CBL|RD_s, 0, I2|T3 }, +{"bltzal", "s,p", 0x04100000, 0xfc1f0000, CBD|RD_s|WR_31, 0, I1 }, +{"bltzall", "s,p", 0x04120000, 0xfc1f0000, CBL|RD_s|WR_31, 0, I2|T3 }, +{"bnez", "s,p", 0x14000000, 0xfc1f0000, CBD|RD_s, 0, I1 }, +{"bnezl", "s,p", 0x54000000, 0xfc1f0000, CBL|RD_s, 0, I2|T3 }, +{"bne", "s,t,p", 0x14000000, 0xfc000000, CBD|RD_s|RD_t, 0, I1 }, +{"bne", "s,I,p", 0, (int) M_BNE_I, INSN_MACRO, 0, I1 }, +{"bnel", "s,t,p", 0x54000000, 0xfc000000, CBL|RD_s|RD_t, 0, I2|T3 }, +{"bnel", "s,I,p", 0, (int) M_BNEL_I, INSN_MACRO, 0, I2|T3 }, +{"break", "", 0x0000000d, 0xffffffff, TRAP, 0, I1 }, +{"break", "c", 0x0000000d, 0xfc00ffff, TRAP, 0, I1 }, +{"break", "c,q", 0x0000000d, 0xfc00003f, TRAP, 0, I1 }, +{"c.f.d", "S,T", 0x46200030, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I1 }, +{"c.f.d", "M,S,T", 0x46200030, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I4_32 }, +{"c.f.s", "S,T", 0x46000030, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, 0, I1 }, +{"c.f.s", "M,S,T", 0x46000030, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, I4_32 }, +{"c.f.ps", "S,T", 0x46c00030, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I5_33|IL2F }, +{"c.f.ps", "S,T", 0x45600030, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, IL2E }, +{"c.f.ps", "M,S,T", 0x46c00030, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I5_33 }, +{"c.un.d", "S,T", 0x46200031, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I1 }, +{"c.un.d", "M,S,T", 0x46200031, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I4_32 }, +{"c.un.s", "S,T", 0x46000031, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, 0, I1 }, +{"c.un.s", "M,S,T", 0x46000031, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, I4_32 }, +{"c.un.ps", "S,T", 0x46c00031, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I5_33|IL2F }, +{"c.un.ps", "S,T", 0x45600031, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, IL2E }, +{"c.un.ps", "M,S,T", 0x46c00031, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I5_33 }, +{"c.eq.d", "S,T", 0x46200032, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I1 }, +{"c.eq.d", "M,S,T", 0x46200032, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I4_32 }, +{"c.eq.s", "S,T", 0x46000032, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, 0, I1 }, +{"c.eq.s", "M,S,T", 0x46000032, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, I4_32 }, +{"c.eq.ob", "Y,Q", 0x78000001, 0xfc2007ff, WR_CC|RD_S|RD_T|FP_D, 0, MX|SB1 }, +{"c.eq.ob", "S,T", 0x4ac00001, 0xffe007ff, WR_CC|RD_S|RD_T, 0, N54 }, +{"c.eq.ob", "S,T[e]", 0x48000001, 0xfe2007ff, WR_CC|RD_S|RD_T, 0, N54 }, +{"c.eq.ob", "S,k", 0x4bc00001, 0xffe007ff, WR_CC|RD_S|RD_T, 0, N54 }, +{"c.eq.ps", "S,T", 0x46c00032, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I5_33|IL2F }, +{"c.eq.ps", "S,T", 0x45600032, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, IL2E }, +{"c.eq.ps", "M,S,T", 0x46c00032, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I5_33 }, +{"c.eq.qh", "Y,Q", 0x78200001, 0xfc2007ff, WR_CC|RD_S|RD_T|FP_D, 0, MX }, +{"c.ueq.d", "S,T", 0x46200033, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I1 }, +{"c.ueq.d", "M,S,T", 0x46200033, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I4_32 }, +{"c.ueq.s", "S,T", 0x46000033, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, 0, I1 }, +{"c.ueq.s", "M,S,T", 0x46000033, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, I4_32 }, +{"c.ueq.ps","S,T", 0x46c00033, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I5_33|IL2F }, +{"c.ueq.ps","S,T", 0x45600033, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, IL2E }, +{"c.ueq.ps","M,S,T", 0x46c00033, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I5_33 }, +{"c.olt.d", "S,T", 0x46200034, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I1 }, +{"c.olt.d", "M,S,T", 0x46200034, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I4_32 }, +{"c.olt.s", "S,T", 0x46000034, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, 0, I1 }, +{"c.olt.s", "M,S,T", 0x46000034, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, I4_32 }, +{"c.olt.ps","S,T", 0x46c00034, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I5_33|IL2F }, +{"c.olt.ps","S,T", 0x45600034, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, IL2E }, +{"c.olt.ps","M,S,T", 0x46c00034, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I5_33 }, +{"c.ult.d", "S,T", 0x46200035, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I1 }, +{"c.ult.d", "M,S,T", 0x46200035, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I4_32 }, +{"c.ult.s", "S,T", 0x46000035, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, 0, I1 }, +{"c.ult.s", "M,S,T", 0x46000035, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, I4_32 }, +{"c.ult.ps","S,T", 0x46c00035, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I5_33|IL2F }, +{"c.ult.ps","S,T", 0x45600035, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, IL2E }, +{"c.ult.ps","M,S,T", 0x46c00035, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I5_33 }, +{"c.ole.d", "S,T", 0x46200036, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I1 }, +{"c.ole.d", "M,S,T", 0x46200036, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I4_32 }, +{"c.ole.s", "S,T", 0x46000036, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, 0, I1 }, +{"c.ole.s", "M,S,T", 0x46000036, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, I4_32 }, +{"c.ole.ps","S,T", 0x46c00036, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I5_33|IL2F }, +{"c.ole.ps","S,T", 0x45600036, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, IL2E }, +{"c.ole.ps","M,S,T", 0x46c00036, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I5_33 }, +{"c.ule.d", "S,T", 0x46200037, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I1 }, +{"c.ule.d", "M,S,T", 0x46200037, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I4_32 }, +{"c.ule.s", "S,T", 0x46000037, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, 0, I1 }, +{"c.ule.s", "M,S,T", 0x46000037, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, I4_32 }, +{"c.ule.ps","S,T", 0x46c00037, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I5_33|IL2F }, +{"c.ule.ps","S,T", 0x45600037, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, IL2E }, +{"c.ule.ps","M,S,T", 0x46c00037, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I5_33 }, +{"c.sf.d", "S,T", 0x46200038, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I1 }, +{"c.sf.d", "M,S,T", 0x46200038, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I4_32 }, +{"c.sf.s", "S,T", 0x46000038, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, 0, I1 }, +{"c.sf.s", "M,S,T", 0x46000038, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, I4_32 }, +{"c.sf.ps", "S,T", 0x46c00038, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I5_33|IL2F }, +{"c.sf.ps", "S,T", 0x45600038, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, IL2E }, +{"c.sf.ps", "M,S,T", 0x46c00038, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I5_33 }, +{"c.ngle.d","S,T", 0x46200039, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I1 }, +{"c.ngle.d","M,S,T", 0x46200039, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I4_32 }, +{"c.ngle.s","S,T", 0x46000039, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, 0, I1 }, +{"c.ngle.s","M,S,T", 0x46000039, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, I4_32 }, +{"c.ngle.ps","S,T", 0x46c00039, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I5_33|IL2F }, +{"c.ngle.ps","S,T", 0x45600039, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, IL2E }, +{"c.ngle.ps","M,S,T", 0x46c00039, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I5_33 }, +{"c.seq.d", "S,T", 0x4620003a, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I1 }, +{"c.seq.d", "M,S,T", 0x4620003a, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I4_32 }, +{"c.seq.s", "S,T", 0x4600003a, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, 0, I1 }, +{"c.seq.s", "M,S,T", 0x4600003a, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, I4_32 }, +{"c.seq.ps","S,T", 0x46c0003a, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I5_33|IL2F }, +{"c.seq.ps","S,T", 0x4560003a, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, IL2E }, +{"c.seq.ps","M,S,T", 0x46c0003a, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I5_33 }, +{"c.ngl.d", "S,T", 0x4620003b, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I1 }, +{"c.ngl.d", "M,S,T", 0x4620003b, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I4_32 }, +{"c.ngl.s", "S,T", 0x4600003b, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, 0, I1 }, +{"c.ngl.s", "M,S,T", 0x4600003b, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, I4_32 }, +{"c.ngl.ps","S,T", 0x46c0003b, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I5_33|IL2F }, +{"c.ngl.ps","S,T", 0x4560003b, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, IL2E }, +{"c.ngl.ps","M,S,T", 0x46c0003b, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I5_33 }, +{"c.lt.d", "S,T", 0x4620003c, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I1 }, +{"c.lt.d", "M,S,T", 0x4620003c, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I4_32 }, +{"c.lt.s", "S,T", 0x4600003c, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, 0, I1 }, +{"c.lt.s", "M,S,T", 0x4600003c, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, I4_32 }, +{"c.lt.ob", "Y,Q", 0x78000004, 0xfc2007ff, WR_CC|RD_S|RD_T|FP_D, 0, MX|SB1 }, +{"c.lt.ob", "S,T", 0x4ac00004, 0xffe007ff, WR_CC|RD_S|RD_T, 0, N54 }, +{"c.lt.ob", "S,T[e]", 0x48000004, 0xfe2007ff, WR_CC|RD_S|RD_T, 0, N54 }, +{"c.lt.ob", "S,k", 0x4bc00004, 0xffe007ff, WR_CC|RD_S|RD_T, 0, N54 }, +{"c.lt.ps", "S,T", 0x46c0003c, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I5_33|IL2F }, +{"c.lt.ps", "S,T", 0x4560003c, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, IL2E }, +{"c.lt.ps", "M,S,T", 0x46c0003c, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I5_33 }, +{"c.lt.qh", "Y,Q", 0x78200004, 0xfc2007ff, WR_CC|RD_S|RD_T|FP_D, 0, MX }, +{"c.nge.d", "S,T", 0x4620003d, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I1 }, +{"c.nge.d", "M,S,T", 0x4620003d, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I4_32 }, +{"c.nge.s", "S,T", 0x4600003d, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, 0, I1 }, +{"c.nge.s", "M,S,T", 0x4600003d, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, I4_32 }, +{"c.nge.ps","S,T", 0x46c0003d, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I5_33|IL2F }, +{"c.nge.ps","S,T", 0x4560003d, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, IL2E }, +{"c.nge.ps","M,S,T", 0x46c0003d, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I5_33 }, +{"c.le.d", "S,T", 0x4620003e, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I1 }, +{"c.le.d", "M,S,T", 0x4620003e, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I4_32 }, +{"c.le.s", "S,T", 0x4600003e, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, 0, I1 }, +{"c.le.s", "M,S,T", 0x4600003e, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, I4_32 }, +{"c.le.ob", "Y,Q", 0x78000005, 0xfc2007ff, WR_CC|RD_S|RD_T|FP_D, 0, MX|SB1 }, +{"c.le.ob", "S,T", 0x4ac00005, 0xffe007ff, WR_CC|RD_S|RD_T, 0, N54 }, +{"c.le.ob", "S,T[e]", 0x48000005, 0xfe2007ff, WR_CC|RD_S|RD_T, 0, N54 }, +{"c.le.ob", "S,k", 0x4bc00005, 0xffe007ff, WR_CC|RD_S|RD_T, 0, N54 }, +{"c.le.ps", "S,T", 0x46c0003e, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I5_33|IL2F }, +{"c.le.ps", "S,T", 0x4560003e, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, IL2E }, +{"c.le.ps", "M,S,T", 0x46c0003e, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I5_33 }, +{"c.le.qh", "Y,Q", 0x78200005, 0xfc2007ff, WR_CC|RD_S|RD_T|FP_D, 0, MX }, +{"c.ngt.d", "S,T", 0x4620003f, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I1 }, +{"c.ngt.d", "M,S,T", 0x4620003f, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I4_32 }, +{"c.ngt.s", "S,T", 0x4600003f, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, 0, I1 }, +{"c.ngt.s", "M,S,T", 0x4600003f, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, I4_32 }, +{"c.ngt.ps","S,T", 0x46c0003f, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I5_33|IL2F }, +{"c.ngt.ps","S,T", 0x4560003f, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, IL2E }, +{"c.ngt.ps","M,S,T", 0x46c0003f, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I5_33 }, +{"cabs.eq.d", "M,S,T", 0x46200072, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.eq.ps", "M,S,T", 0x46c00072, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.eq.s", "M,S,T", 0x46000072, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, M3D }, +{"cabs.f.d", "M,S,T", 0x46200070, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.f.ps", "M,S,T", 0x46c00070, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.f.s", "M,S,T", 0x46000070, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, M3D }, +{"cabs.le.d", "M,S,T", 0x4620007e, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.le.ps", "M,S,T", 0x46c0007e, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.le.s", "M,S,T", 0x4600007e, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, M3D }, +{"cabs.lt.d", "M,S,T", 0x4620007c, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.lt.ps", "M,S,T", 0x46c0007c, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.lt.s", "M,S,T", 0x4600007c, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, M3D }, +{"cabs.nge.d", "M,S,T", 0x4620007d, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.nge.ps","M,S,T", 0x46c0007d, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.nge.s", "M,S,T", 0x4600007d, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, M3D }, +{"cabs.ngl.d", "M,S,T", 0x4620007b, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.ngl.ps","M,S,T", 0x46c0007b, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.ngl.s", "M,S,T", 0x4600007b, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, M3D }, +{"cabs.ngle.d","M,S,T", 0x46200079, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.ngle.ps","M,S,T",0x46c00079, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.ngle.s","M,S,T", 0x46000079, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, M3D }, +{"cabs.ngt.d", "M,S,T", 0x4620007f, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.ngt.ps","M,S,T", 0x46c0007f, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.ngt.s", "M,S,T", 0x4600007f, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, M3D }, +{"cabs.ole.d", "M,S,T", 0x46200076, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.ole.ps","M,S,T", 0x46c00076, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.ole.s", "M,S,T", 0x46000076, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, M3D }, +{"cabs.olt.d", "M,S,T", 0x46200074, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.olt.ps","M,S,T", 0x46c00074, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.olt.s", "M,S,T", 0x46000074, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, M3D }, +{"cabs.seq.d", "M,S,T", 0x4620007a, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.seq.ps","M,S,T", 0x46c0007a, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.seq.s", "M,S,T", 0x4600007a, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, M3D }, +{"cabs.sf.d", "M,S,T", 0x46200078, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.sf.ps", "M,S,T", 0x46c00078, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.sf.s", "M,S,T", 0x46000078, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, M3D }, +{"cabs.ueq.d", "M,S,T", 0x46200073, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.ueq.ps","M,S,T", 0x46c00073, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.ueq.s", "M,S,T", 0x46000073, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, M3D }, +{"cabs.ule.d", "M,S,T", 0x46200077, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.ule.ps","M,S,T", 0x46c00077, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.ule.s", "M,S,T", 0x46000077, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, M3D }, +{"cabs.ult.d", "M,S,T", 0x46200075, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.ult.ps","M,S,T", 0x46c00075, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.ult.s", "M,S,T", 0x46000075, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, M3D }, +{"cabs.un.d", "M,S,T", 0x46200071, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.un.ps", "M,S,T", 0x46c00071, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.un.s", "M,S,T", 0x46000071, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, M3D }, +/* CW4010 instructions which are aliases for the cache instruction. */ +{"flushi", "", 0xbc010000, 0xffffffff, 0, 0, L1 }, +{"flushd", "", 0xbc020000, 0xffffffff, 0, 0, L1 }, +{"flushid", "", 0xbc030000, 0xffffffff, 0, 0, L1 }, +{"wb", "o(b)", 0xbc040000, 0xfc1f0000, SM|RD_b, 0, L1 }, +{"cache", "k,o(b)", 0xbc000000, 0xfc000000, RD_b, 0, I3_32|T3}, +{"cache", "k,A(b)", 0, (int) M_CACHE_AB, INSN_MACRO, 0, I3_32|T3}, +{"ceil.l.d", "D,S", 0x4620000a, 0xffff003f, WR_D|RD_S|FP_D, 0, I3_33 }, +{"ceil.l.s", "D,S", 0x4600000a, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I3_33 }, +{"ceil.w.d", "D,S", 0x4620000e, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I2 }, +{"ceil.w.s", "D,S", 0x4600000e, 0xffff003f, WR_D|RD_S|FP_S, 0, I2 }, +{"cfc0", "t,G", 0x40400000, 0xffe007ff, LCD|WR_t|RD_C0, 0, I1 }, +{"cfc1", "t,G", 0x44400000, 0xffe007ff, LCD|WR_t|RD_C1|FP_S, 0, I1 }, +{"cfc1", "t,S", 0x44400000, 0xffe007ff, LCD|WR_t|RD_C1|FP_S, 0, I1 }, +/* cfc2 is at the bottom of the table. */ +/* cfc3 is at the bottom of the table. */ +{"cftc1", "d,E", 0x41000023, 0xffe007ff, TRAP|LCD|WR_d|RD_C1|FP_S, 0, MT32 }, +{"cftc1", "d,T", 0x41000023, 0xffe007ff, TRAP|LCD|WR_d|RD_C1|FP_S, 0, MT32 }, +{"cftc2", "d,E", 0x41000025, 0xffe007ff, TRAP|LCD|WR_d|RD_C2, 0, MT32 }, +{"cins32", "t,r,+p,+S",0x70000033, 0xfc00003f, WR_t|RD_s, 0, IOCT }, +{"cins", "t,r,+P,+S",0x70000033, 0xfc00003f, WR_t|RD_s, 0, IOCT }, /* cins32 */ +{"cins", "t,r,+p,+s",0x70000032, 0xfc00003f, WR_t|RD_s, 0, IOCT }, +{"clo", "U,s", 0x70000021, 0xfc0007ff, WR_d|WR_t|RD_s, 0, I32|N55 }, +{"clz", "U,s", 0x70000020, 0xfc0007ff, WR_d|WR_t|RD_s, 0, I32|N55 }, +{"ctc0", "t,G", 0x40c00000, 0xffe007ff, COD|RD_t|WR_CC, 0, I1 }, +{"ctc1", "t,G", 0x44c00000, 0xffe007ff, COD|RD_t|WR_CC|FP_S, 0, I1 }, +{"ctc1", "t,S", 0x44c00000, 0xffe007ff, COD|RD_t|WR_CC|FP_S, 0, I1 }, +/* ctc2 is at the bottom of the table. */ +/* ctc3 is at the bottom of the table. */ +{"cttc1", "t,g", 0x41800023, 0xffe007ff, TRAP|COD|RD_t|WR_CC|FP_S, 0, MT32 }, +{"cttc1", "t,S", 0x41800023, 0xffe007ff, TRAP|COD|RD_t|WR_CC|FP_S, 0, MT32 }, +{"cttc2", "t,g", 0x41800025, 0xffe007ff, TRAP|COD|RD_t|WR_CC, 0, MT32 }, +{"cvt.d.l", "D,S", 0x46a00021, 0xffff003f, WR_D|RD_S|FP_D, 0, I3_33 }, +{"cvt.d.s", "D,S", 0x46000021, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I1 }, +{"cvt.d.w", "D,S", 0x46800021, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I1 }, +{"cvt.l.d", "D,S", 0x46200025, 0xffff003f, WR_D|RD_S|FP_D, 0, I3_33 }, +{"cvt.l.s", "D,S", 0x46000025, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I3_33 }, +{"cvt.s.l", "D,S", 0x46a00020, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I3_33 }, +{"cvt.s.d", "D,S", 0x46200020, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I1 }, +{"cvt.s.w", "D,S", 0x46800020, 0xffff003f, WR_D|RD_S|FP_S, 0, I1 }, +{"cvt.s.pl","D,S", 0x46c00028, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I5_33 }, +{"cvt.s.pu","D,S", 0x46c00020, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I5_33 }, +{"cvt.w.d", "D,S", 0x46200024, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I1 }, +{"cvt.w.s", "D,S", 0x46000024, 0xffff003f, WR_D|RD_S|FP_S, 0, I1 }, +{"cvt.ps.pw", "D,S", 0x46800026, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, M3D }, +{"cvt.ps.s","D,V,T", 0x46000026, 0xffe0003f, WR_D|RD_S|RD_T|FP_S|FP_D, 0, I5_33 }, +{"cvt.pw.ps", "D,S", 0x46c00024, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, M3D }, +{"dabs", "d,v", 0, (int) M_DABS, INSN_MACRO, 0, I3 }, +{"dadd", "d,v,t", 0x0000002c, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I3 }, +{"dadd", "t,r,I", 0, (int) M_DADD_I, INSN_MACRO, 0, I3 }, +{"dadd", "D,S,T", 0x45e00000, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2E }, +{"dadd", "D,S,T", 0x4b60000c, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2F }, +{"daddi", "t,r,j", 0x60000000, 0xfc000000, WR_t|RD_s, 0, I3 }, +{"daddiu", "t,r,j", 0x64000000, 0xfc000000, WR_t|RD_s, 0, I3 }, +{"daddu", "d,v,t", 0x0000002d, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I3 }, +{"daddu", "t,r,I", 0, (int) M_DADDU_I, INSN_MACRO, 0, I3 }, +{"daddwc", "d,s,t", 0x70000038, 0xfc0007ff, WR_d|RD_s|RD_t|WR_C0|RD_C0, 0, XLR }, +{"dbreak", "", 0x7000003f, 0xffffffff, 0, 0, N5 }, +{"dclo", "U,s", 0x70000025, 0xfc0007ff, RD_s|WR_d|WR_t, 0, I64|N55 }, +{"dclz", "U,s", 0x70000024, 0xfc0007ff, RD_s|WR_d|WR_t, 0, I64|N55 }, +/* dctr and dctw are used on the r5000. */ +{"dctr", "o(b)", 0xbc050000, 0xfc1f0000, RD_b, 0, I3 }, +{"dctw", "o(b)", 0xbc090000, 0xfc1f0000, RD_b, 0, I3 }, +{"deret", "", 0x4200001f, 0xffffffff, 0, 0, I32|G2 }, +{"dext", "t,r,I,+I", 0, (int) M_DEXT, INSN_MACRO, 0, I65 }, +{"dext", "t,r,+A,+C", 0x7c000003, 0xfc00003f, WR_t|RD_s, 0, I65 }, +{"dextm", "t,r,+A,+G", 0x7c000001, 0xfc00003f, WR_t|RD_s, 0, I65 }, +{"dextu", "t,r,+E,+H", 0x7c000002, 0xfc00003f, WR_t|RD_s, 0, I65 }, +/* For ddiv, see the comments about div. */ +{"ddiv", "z,s,t", 0x0000001e, 0xfc00ffff, RD_s|RD_t|WR_HILO, 0, I3 }, +{"ddiv", "d,v,t", 0, (int) M_DDIV_3, INSN_MACRO, 0, I3 }, +{"ddiv", "d,v,I", 0, (int) M_DDIV_3I, INSN_MACRO, 0, I3 }, +/* For ddivu, see the comments about div. */ +{"ddivu", "z,s,t", 0x0000001f, 0xfc00ffff, RD_s|RD_t|WR_HILO, 0, I3 }, +{"ddivu", "d,v,t", 0, (int) M_DDIVU_3, INSN_MACRO, 0, I3 }, +{"ddivu", "d,v,I", 0, (int) M_DDIVU_3I, INSN_MACRO, 0, I3 }, +{"di", "", 0x41606000, 0xffffffff, WR_t|WR_C0, 0, I33|IOCT}, +{"di", "t", 0x41606000, 0xffe0ffff, WR_t|WR_C0, 0, I33|IOCT}, +{"dins", "t,r,I,+I", 0, (int) M_DINS, INSN_MACRO, 0, I65 }, +{"dins", "t,r,+A,+B", 0x7c000007, 0xfc00003f, WR_t|RD_s, 0, I65 }, +{"dinsm", "t,r,+A,+F", 0x7c000005, 0xfc00003f, WR_t|RD_s, 0, I65 }, +{"dinsu", "t,r,+E,+F", 0x7c000006, 0xfc00003f, WR_t|RD_s, 0, I65 }, +/* The MIPS assembler treats the div opcode with two operands as + though the first operand appeared twice (the first operand is both + a source and a destination). To get the div machine instruction, + you must use an explicit destination of $0. */ +{"div", "z,s,t", 0x0000001a, 0xfc00ffff, RD_s|RD_t|WR_HILO, 0, I1 }, +{"div", "z,t", 0x0000001a, 0xffe0ffff, RD_s|RD_t|WR_HILO, 0, I1 }, +{"div", "d,v,t", 0, (int) M_DIV_3, INSN_MACRO, 0, I1 }, +{"div", "d,v,I", 0, (int) M_DIV_3I, INSN_MACRO, 0, I1 }, +{"div.d", "D,V,T", 0x46200003, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I1 }, +{"div.s", "D,V,T", 0x46000003, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, 0, I1 }, +{"div.ps", "D,V,T", 0x46c00003, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, SB1 }, +/* For divu, see the comments about div. */ +{"divu", "z,s,t", 0x0000001b, 0xfc00ffff, RD_s|RD_t|WR_HILO, 0, I1 }, +{"divu", "z,t", 0x0000001b, 0xffe0ffff, RD_s|RD_t|WR_HILO, 0, I1 }, +{"divu", "d,v,t", 0, (int) M_DIVU_3, INSN_MACRO, 0, I1 }, +{"divu", "d,v,I", 0, (int) M_DIVU_3I, INSN_MACRO, 0, I1 }, +{"dla", "t,A(b)", 0, (int) M_DLA_AB, INSN_MACRO, 0, I3 }, +{"dlca", "t,A(b)", 0, (int) M_DLCA_AB, INSN_MACRO, 0, I3 }, +{"dli", "t,j", 0x24000000, 0xffe00000, WR_t, 0, I3 }, /* addiu */ +{"dli", "t,i", 0x34000000, 0xffe00000, WR_t, 0, I3 }, /* ori */ +{"dli", "t,I", 0, (int) M_DLI, INSN_MACRO, 0, I3 }, +{"dmacc", "d,s,t", 0x00000029, 0xfc0007ff, RD_s|RD_t|WR_LO|WR_d, 0, N412 }, +{"dmacchi", "d,s,t", 0x00000229, 0xfc0007ff, RD_s|RD_t|WR_LO|WR_d, 0, N412 }, +{"dmacchis", "d,s,t", 0x00000629, 0xfc0007ff, RD_s|RD_t|WR_LO|WR_d, 0, N412 }, +{"dmacchiu", "d,s,t", 0x00000269, 0xfc0007ff, RD_s|RD_t|WR_LO|WR_d, 0, N412 }, +{"dmacchius", "d,s,t", 0x00000669, 0xfc0007ff, RD_s|RD_t|WR_LO|WR_d, 0, N412 }, +{"dmaccs", "d,s,t", 0x00000429, 0xfc0007ff, RD_s|RD_t|WR_LO|WR_d, 0, N412 }, +{"dmaccu", "d,s,t", 0x00000069, 0xfc0007ff, RD_s|RD_t|WR_LO|WR_d, 0, N412 }, +{"dmaccus", "d,s,t", 0x00000469, 0xfc0007ff, RD_s|RD_t|WR_LO|WR_d, 0, N412 }, +{"dmadd16", "s,t", 0x00000029, 0xfc00ffff, RD_s|RD_t|MOD_LO, 0, N411 }, +{"dmfc0", "t,G", 0x40200000, 0xffe007ff, LCD|WR_t|RD_C0, 0, I3|IOCT }, +{"dmfc0", "t,+D", 0x40200000, 0xffe007f8, LCD|WR_t|RD_C0, 0, I64|IOCT}, +{"dmfc0", "t,G,H", 0x40200000, 0xffe007f8, LCD|WR_t|RD_C0, 0, I64|IOCT}, +{"dmt", "", 0x41600bc1, 0xffffffff, TRAP, 0, MT32 }, +{"dmt", "t", 0x41600bc1, 0xffe0ffff, TRAP|WR_t, 0, MT32 }, +{"dmtc0", "t,G", 0x40a00000, 0xffe007ff, COD|RD_t|WR_C0|WR_CC, 0, I3|IOCT }, +{"dmtc0", "t,+D", 0x40a00000, 0xffe007f8, COD|RD_t|WR_C0|WR_CC, 0, I64|IOCT}, +{"dmtc0", "t,G,H", 0x40a00000, 0xffe007f8, COD|RD_t|WR_C0|WR_CC, 0, I64|IOCT}, +{"dmfc1", "t,S", 0x44200000, 0xffe007ff, LCD|WR_t|RD_S|FP_D, 0, I3 }, +{"dmfc1", "t,G", 0x44200000, 0xffe007ff, LCD|WR_t|RD_S|FP_D, 0, I3 }, +{"dmtc1", "t,S", 0x44a00000, 0xffe007ff, COD|RD_t|WR_S|FP_D, 0, I3 }, +{"dmtc1", "t,G", 0x44a00000, 0xffe007ff, COD|RD_t|WR_S|FP_D, 0, I3 }, +/* dmfc2 is at the bottom of the table. */ +/* dmtc2 is at the bottom of the table. */ +/* dmfc3 is at the bottom of the table. */ +/* dmtc3 is at the bottom of the table. */ +{"dmul", "d,v,t", 0x70000003, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0, IOCT }, +{"dmul", "d,v,t", 0, (int) M_DMUL, INSN_MACRO, 0, I3 }, +{"dmul", "d,v,I", 0, (int) M_DMUL_I, INSN_MACRO, 0, I3 }, +{"dmulo", "d,v,t", 0, (int) M_DMULO, INSN_MACRO, 0, I3 }, +{"dmulo", "d,v,I", 0, (int) M_DMULO_I, INSN_MACRO, 0, I3 }, +{"dmulou", "d,v,t", 0, (int) M_DMULOU, INSN_MACRO, 0, I3 }, +{"dmulou", "d,v,I", 0, (int) M_DMULOU_I, INSN_MACRO, 0, I3 }, +{"dmult", "s,t", 0x0000001c, 0xfc00ffff, RD_s|RD_t|WR_HILO, 0, I3 }, +{"dmultu", "s,t", 0x0000001d, 0xfc00ffff, RD_s|RD_t|WR_HILO, 0, I3 }, +{"dneg", "d,w", 0x0000002e, 0xffe007ff, WR_d|RD_t, 0, I3 }, /* dsub 0 */ +{"dnegu", "d,w", 0x0000002f, 0xffe007ff, WR_d|RD_t, 0, I3 }, /* dsubu 0*/ +{"dpop", "d,v", 0x7000002d, 0xfc1f07ff, WR_d|RD_s, 0, IOCT }, +{"drem", "z,s,t", 0x0000001e, 0xfc00ffff, RD_s|RD_t|WR_HILO, 0, I3 }, +{"drem", "d,v,t", 0, (int) M_DREM_3, INSN_MACRO, 0, I3 }, +{"drem", "d,v,I", 0, (int) M_DREM_3I, INSN_MACRO, 0, I3 }, +{"dremu", "z,s,t", 0x0000001f, 0xfc00ffff, RD_s|RD_t|WR_HILO, 0, I3 }, +{"dremu", "d,v,t", 0, (int) M_DREMU_3, INSN_MACRO, 0, I3 }, +{"dremu", "d,v,I", 0, (int) M_DREMU_3I, INSN_MACRO, 0, I3 }, +{"dret", "", 0x7000003e, 0xffffffff, 0, 0, N5 }, +{"drol", "d,v,t", 0, (int) M_DROL, INSN_MACRO, 0, I3 }, +{"drol", "d,v,I", 0, (int) M_DROL_I, INSN_MACRO, 0, I3 }, +{"dror", "d,v,t", 0, (int) M_DROR, INSN_MACRO, 0, I3 }, +{"dror", "d,v,I", 0, (int) M_DROR_I, INSN_MACRO, 0, I3 }, +{"dror", "d,w,<", 0x0020003a, 0xffe0003f, WR_d|RD_t, 0, N5|I65 }, +{"drorv", "d,t,s", 0x00000056, 0xfc0007ff, RD_t|RD_s|WR_d, 0, N5|I65 }, +{"dror32", "d,w,<", 0x0020003e, 0xffe0003f, WR_d|RD_t, 0, N5|I65 }, +{"drotl", "d,v,t", 0, (int) M_DROL, INSN_MACRO, 0, I65 }, +{"drotl", "d,v,I", 0, (int) M_DROL_I, INSN_MACRO, 0, I65 }, +{"dror", "d,v,t", 0, (int) M_DROR, INSN_MACRO, 0, I65 }, +{"dror", "d,v,I", 0, (int) M_DROR_I, INSN_MACRO, 0, I65 }, +{"drorv", "d,t,s", 0x00000056, 0xfc0007ff, RD_t|RD_s|WR_d, 0, I65 }, +{"dror32", "d,w,<", 0x0020003e, 0xffe0003f, WR_d|RD_t, 0, I65 }, +{"dsbh", "d,w", 0x7c0000a4, 0xffe007ff, WR_d|RD_t, 0, I65 }, +{"dshd", "d,w", 0x7c000164, 0xffe007ff, WR_d|RD_t, 0, I65 }, +{"dsllv", "d,t,s", 0x00000014, 0xfc0007ff, WR_d|RD_t|RD_s, 0, I3 }, +{"dsll32", "d,w,<", 0x0000003c, 0xffe0003f, WR_d|RD_t, 0, I3 }, +{"dsll", "d,w,s", 0x00000014, 0xfc0007ff, WR_d|RD_t|RD_s, 0, I3 }, /* dsllv */ +{"dsll", "d,w,>", 0x0000003c, 0xffe0003f, WR_d|RD_t, 0, I3 }, /* dsll32 */ +{"dsll", "d,w,<", 0x00000038, 0xffe0003f, WR_d|RD_t, 0, I3 }, +{"dsll", "D,S,T", 0x45a00002, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2E }, +{"dsll", "D,S,T", 0x4b20000e, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2F }, +{"dsrav", "d,t,s", 0x00000017, 0xfc0007ff, WR_d|RD_t|RD_s, 0, I3 }, +{"dsra32", "d,w,<", 0x0000003f, 0xffe0003f, WR_d|RD_t, 0, I3 }, +{"dsra", "d,w,s", 0x00000017, 0xfc0007ff, WR_d|RD_t|RD_s, 0, I3 }, /* dsrav */ +{"dsra", "d,w,>", 0x0000003f, 0xffe0003f, WR_d|RD_t, 0, I3 }, /* dsra32 */ +{"dsra", "d,w,<", 0x0000003b, 0xffe0003f, WR_d|RD_t, 0, I3 }, +{"dsra", "D,S,T", 0x45e00003, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2E }, +{"dsra", "D,S,T", 0x4b60000f, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2F }, +{"dsrlv", "d,t,s", 0x00000016, 0xfc0007ff, WR_d|RD_t|RD_s, 0, I3 }, +{"dsrl32", "d,w,<", 0x0000003e, 0xffe0003f, WR_d|RD_t, 0, I3 }, +{"dsrl", "d,w,s", 0x00000016, 0xfc0007ff, WR_d|RD_t|RD_s, 0, I3 }, /* dsrlv */ +{"dsrl", "d,w,>", 0x0000003e, 0xffe0003f, WR_d|RD_t, 0, I3 }, /* dsrl32 */ +{"dsrl", "d,w,<", 0x0000003a, 0xffe0003f, WR_d|RD_t, 0, I3 }, +{"dsrl", "D,S,T", 0x45a00003, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2E }, +{"dsrl", "D,S,T", 0x4b20000f, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2F }, +{"dsub", "d,v,t", 0x0000002e, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I3 }, +{"dsub", "d,v,I", 0, (int) M_DSUB_I, INSN_MACRO, 0, I3 }, +{"dsub", "D,S,T", 0x45e00001, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2E }, +{"dsub", "D,S,T", 0x4b60000d, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2F }, +{"dsubu", "d,v,t", 0x0000002f, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I3 }, +{"dsubu", "d,v,I", 0, (int) M_DSUBU_I, INSN_MACRO, 0, I3 }, +{"dvpe", "", 0x41600001, 0xffffffff, TRAP, 0, MT32 }, +{"dvpe", "t", 0x41600001, 0xffe0ffff, TRAP|WR_t, 0, MT32 }, +{"ei", "", 0x41606020, 0xffffffff, WR_t|WR_C0, 0, I33|IOCT}, +{"ei", "t", 0x41606020, 0xffe0ffff, WR_t|WR_C0, 0, I33|IOCT}, +{"emt", "", 0x41600be1, 0xffffffff, TRAP, 0, MT32 }, +{"emt", "t", 0x41600be1, 0xffe0ffff, TRAP|WR_t, 0, MT32 }, +{"eret", "", 0x42000018, 0xffffffff, 0, 0, I3_32 }, +{"evpe", "", 0x41600021, 0xffffffff, TRAP, 0, MT32 }, +{"evpe", "t", 0x41600021, 0xffe0ffff, TRAP|WR_t, 0, MT32 }, +{"ext", "t,r,+A,+C", 0x7c000000, 0xfc00003f, WR_t|RD_s, 0, I33 }, +{"exts32", "t,r,+p,+S",0x7000003b, 0xfc00003f, WR_t|RD_s, 0, IOCT }, +{"exts", "t,r,+P,+S",0x7000003b, 0xfc00003f, WR_t|RD_s, 0, IOCT }, /* exts32 */ +{"exts", "t,r,+p,+s",0x7000003a, 0xfc00003f, WR_t|RD_s, 0, IOCT }, +{"floor.l.d", "D,S", 0x4620000b, 0xffff003f, WR_D|RD_S|FP_D, 0, I3_33 }, +{"floor.l.s", "D,S", 0x4600000b, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I3_33 }, +{"floor.w.d", "D,S", 0x4620000f, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I2 }, +{"floor.w.s", "D,S", 0x4600000f, 0xffff003f, WR_D|RD_S|FP_S, 0, I2 }, +{"hibernate","", 0x42000023, 0xffffffff, 0, 0, V1 }, +{"ins", "t,r,+A,+B", 0x7c000004, 0xfc00003f, WR_t|RD_s, 0, I33 }, +{"jr", "s", 0x00000008, 0xfc1fffff, UBD|RD_s, 0, I1 }, +/* jr.hb is officially MIPS{32,64}R2, but it works on R1 as jr with + the same hazard barrier effect. */ +{"jr.hb", "s", 0x00000408, 0xfc1fffff, UBD|RD_s, 0, I32 }, +{"j", "s", 0x00000008, 0xfc1fffff, UBD|RD_s, 0, I1 }, /* jr */ +/* SVR4 PIC code requires special handling for j, so it must be a + macro. */ +{"j", "a", 0, (int) M_J_A, INSN_MACRO, 0, I1 }, +/* This form of j is used by the disassembler and internally by the + assembler, but will never match user input (because the line above + will match first). */ +{"j", "a", 0x08000000, 0xfc000000, UBD, 0, I1 }, +{"jalr", "s", 0x0000f809, 0xfc1fffff, UBD|RD_s|WR_d, 0, I1 }, +{"jalr", "d,s", 0x00000009, 0xfc1f07ff, UBD|RD_s|WR_d, 0, I1 }, +/* jalr.hb is officially MIPS{32,64}R2, but it works on R1 as jalr + with the same hazard barrier effect. */ +{"jalr.hb", "s", 0x0000fc09, 0xfc1fffff, UBD|RD_s|WR_d, 0, I32 }, +{"jalr.hb", "d,s", 0x00000409, 0xfc1f07ff, UBD|RD_s|WR_d, 0, I32 }, +/* SVR4 PIC code requires special handling for jal, so it must be a + macro. */ +{"jal", "d,s", 0, (int) M_JAL_2, INSN_MACRO, 0, I1 }, +{"jal", "s", 0, (int) M_JAL_1, INSN_MACRO, 0, I1 }, +{"jal", "a", 0, (int) M_JAL_A, INSN_MACRO, 0, I1 }, +/* This form of jal is used by the disassembler and internally by the + assembler, but will never match user input (because the line above + will match first). */ +{"jal", "a", 0x0c000000, 0xfc000000, UBD|WR_31, 0, I1 }, +{"jalx", "a", 0x74000000, 0xfc000000, UBD|WR_31, 0, I1 }, +{"la", "t,A(b)", 0, (int) M_LA_AB, INSN_MACRO, 0, I1 }, +{"lb", "t,o(b)", 0x80000000, 0xfc000000, LDD|RD_b|WR_t, 0, I1 }, +{"lb", "t,A(b)", 0, (int) M_LB_AB, INSN_MACRO, 0, I1 }, +{"lbu", "t,o(b)", 0x90000000, 0xfc000000, LDD|RD_b|WR_t, 0, I1 }, +{"lbu", "t,A(b)", 0, (int) M_LBU_AB, INSN_MACRO, 0, I1 }, +{"lca", "t,A(b)", 0, (int) M_LCA_AB, INSN_MACRO, 0, I1 }, +/* The macro has to be first to handle o32 correctly. */ +{"ld", "t,o(b)", 0, (int) M_LD_OB, INSN_MACRO, 0, I1 }, +{"ld", "t,o(b)", 0xdc000000, 0xfc000000, WR_t|RD_b, 0, I3 }, +{"ld", "t,A(b)", 0, (int) M_LD_AB, INSN_MACRO, 0, I1 }, +{"ldaddw", "t,b", 0x70000010, 0xfc00ffff, SM|RD_t|WR_t|RD_b, 0, XLR }, +{"ldaddwu", "t,b", 0x70000011, 0xfc00ffff, SM|RD_t|WR_t|RD_b, 0, XLR }, +{"ldaddd", "t,b", 0x70000012, 0xfc00ffff, SM|RD_t|WR_t|RD_b, 0, XLR }, +{"ldc1", "T,o(b)", 0xd4000000, 0xfc000000, CLD|RD_b|WR_T|FP_D, 0, I2 }, +{"ldc1", "E,o(b)", 0xd4000000, 0xfc000000, CLD|RD_b|WR_T|FP_D, 0, I2 }, +{"ldc1", "T,A(b)", 0, (int) M_LDC1_AB, INSN_MACRO, INSN2_M_FP_D, I2 }, +{"ldc1", "E,A(b)", 0, (int) M_LDC1_AB, INSN_MACRO, INSN2_M_FP_D, I2 }, +{"l.d", "T,o(b)", 0xd4000000, 0xfc000000, CLD|RD_b|WR_T|FP_D, 0, I2 }, /* ldc1 */ +{"l.d", "T,o(b)", 0, (int) M_L_DOB, INSN_MACRO, INSN2_M_FP_D, I1 }, +{"l.d", "T,A(b)", 0, (int) M_L_DAB, INSN_MACRO, INSN2_M_FP_D, I1 }, +{"ldc2", "E,o(b)", 0xd8000000, 0xfc000000, CLD|RD_b|WR_CC, 0, I2 }, +{"ldc2", "E,A(b)", 0, (int) M_LDC2_AB, INSN_MACRO, 0, I2 }, +{"ldc3", "E,o(b)", 0xdc000000, 0xfc000000, CLD|RD_b|WR_CC, 0, I2 }, +{"ldc3", "E,A(b)", 0, (int) M_LDC3_AB, INSN_MACRO, 0, I2 }, +{"ldl", "t,o(b)", 0x68000000, 0xfc000000, LDD|WR_t|RD_b, 0, I3 }, +{"ldl", "t,A(b)", 0, (int) M_LDL_AB, INSN_MACRO, 0, I3 }, +{"ldr", "t,o(b)", 0x6c000000, 0xfc000000, LDD|WR_t|RD_b, 0, I3 }, +{"ldr", "t,A(b)", 0, (int) M_LDR_AB, INSN_MACRO, 0, I3 }, +{"ldxc1", "D,t(b)", 0x4c000001, 0xfc00f83f, LDD|WR_D|RD_t|RD_b|FP_D, 0, I4_33 }, +{"lh", "t,o(b)", 0x84000000, 0xfc000000, LDD|RD_b|WR_t, 0, I1 }, +{"lh", "t,A(b)", 0, (int) M_LH_AB, INSN_MACRO, 0, I1 }, +{"lhu", "t,o(b)", 0x94000000, 0xfc000000, LDD|RD_b|WR_t, 0, I1 }, +{"lhu", "t,A(b)", 0, (int) M_LHU_AB, INSN_MACRO, 0, I1 }, +/* li is at the start of the table. */ +{"li.d", "t,F", 0, (int) M_LI_D, INSN_MACRO, INSN2_M_FP_D, I1 }, +{"li.d", "T,L", 0, (int) M_LI_DD, INSN_MACRO, INSN2_M_FP_D, I1 }, +{"li.s", "t,f", 0, (int) M_LI_S, INSN_MACRO, INSN2_M_FP_S, I1 }, +{"li.s", "T,l", 0, (int) M_LI_SS, INSN_MACRO, INSN2_M_FP_S, I1 }, +{"ll", "t,o(b)", 0xc0000000, 0xfc000000, LDD|RD_b|WR_t, 0, I2 }, +{"ll", "t,A(b)", 0, (int) M_LL_AB, INSN_MACRO, 0, I2 }, +{"lld", "t,o(b)", 0xd0000000, 0xfc000000, LDD|RD_b|WR_t, 0, I3 }, +{"lld", "t,A(b)", 0, (int) M_LLD_AB, INSN_MACRO, 0, I3 }, +{"lui", "t,u", 0x3c000000, 0xffe00000, WR_t, 0, I1 }, +{"luxc1", "D,t(b)", 0x4c000005, 0xfc00f83f, LDD|WR_D|RD_t|RD_b|FP_D, 0, I5_33|N55}, +{"lw", "t,o(b)", 0x8c000000, 0xfc000000, LDD|RD_b|WR_t, 0, I1 }, +{"lw", "t,A(b)", 0, (int) M_LW_AB, INSN_MACRO, 0, I1 }, +{"lwc0", "E,o(b)", 0xc0000000, 0xfc000000, CLD|RD_b|WR_CC, 0, I1 }, +{"lwc0", "E,A(b)", 0, (int) M_LWC0_AB, INSN_MACRO, 0, I1 }, +{"lwc1", "T,o(b)", 0xc4000000, 0xfc000000, CLD|RD_b|WR_T|FP_S, 0, I1 }, +{"lwc1", "E,o(b)", 0xc4000000, 0xfc000000, CLD|RD_b|WR_T|FP_S, 0, I1 }, +{"lwc1", "T,A(b)", 0, (int) M_LWC1_AB, INSN_MACRO, INSN2_M_FP_S, I1 }, +{"lwc1", "E,A(b)", 0, (int) M_LWC1_AB, INSN_MACRO, INSN2_M_FP_S, I1 }, +{"l.s", "T,o(b)", 0xc4000000, 0xfc000000, CLD|RD_b|WR_T|FP_S, 0, I1 }, /* lwc1 */ +{"l.s", "T,A(b)", 0, (int) M_LWC1_AB, INSN_MACRO, INSN2_M_FP_S, I1 }, +{"lwc2", "E,o(b)", 0xc8000000, 0xfc000000, CLD|RD_b|WR_CC, 0, I1 }, +{"lwc2", "E,A(b)", 0, (int) M_LWC2_AB, INSN_MACRO, 0, I1 }, +{"lwc3", "E,o(b)", 0xcc000000, 0xfc000000, CLD|RD_b|WR_CC, 0, I1 }, +{"lwc3", "E,A(b)", 0, (int) M_LWC3_AB, INSN_MACRO, 0, I1 }, +{"lwl", "t,o(b)", 0x88000000, 0xfc000000, LDD|RD_b|WR_t, 0, I1 }, +{"lwl", "t,A(b)", 0, (int) M_LWL_AB, INSN_MACRO, 0, I1 }, +{"lcache", "t,o(b)", 0x88000000, 0xfc000000, LDD|RD_b|WR_t, 0, I2 }, /* same */ +{"lcache", "t,A(b)", 0, (int) M_LWL_AB, INSN_MACRO, 0, I2 }, /* as lwl */ +{"lwr", "t,o(b)", 0x98000000, 0xfc000000, LDD|RD_b|WR_t, 0, I1 }, +{"lwr", "t,A(b)", 0, (int) M_LWR_AB, INSN_MACRO, 0, I1 }, +{"flush", "t,o(b)", 0x98000000, 0xfc000000, LDD|RD_b|WR_t, 0, I2 }, /* same */ +{"flush", "t,A(b)", 0, (int) M_LWR_AB, INSN_MACRO, 0, I2 }, /* as lwr */ +{"fork", "d,s,t", 0x7c000008, 0xfc0007ff, TRAP|WR_d|RD_s|RD_t, 0, MT32 }, +{"lwu", "t,o(b)", 0x9c000000, 0xfc000000, LDD|RD_b|WR_t, 0, I3 }, +{"lwu", "t,A(b)", 0, (int) M_LWU_AB, INSN_MACRO, 0, I3 }, +{"lwxc1", "D,t(b)", 0x4c000000, 0xfc00f83f, LDD|WR_D|RD_t|RD_b|FP_S, 0, I4_33 }, +{"lwxs", "d,t(b)", 0x70000088, 0xfc0007ff, LDD|RD_b|RD_t|WR_d, 0, SMT }, +{"macc", "d,s,t", 0x00000028, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N412 }, +{"macc", "d,s,t", 0x00000158, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N5 }, +{"maccs", "d,s,t", 0x00000428, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N412 }, +{"macchi", "d,s,t", 0x00000228, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N412 }, +{"macchi", "d,s,t", 0x00000358, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N5 }, +{"macchis", "d,s,t", 0x00000628, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N412 }, +{"macchiu", "d,s,t", 0x00000268, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N412 }, +{"macchiu", "d,s,t", 0x00000359, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N5 }, +{"macchius","d,s,t", 0x00000668, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N412 }, +{"maccu", "d,s,t", 0x00000068, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N412 }, +{"maccu", "d,s,t", 0x00000159, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N5 }, +{"maccus", "d,s,t", 0x00000468, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N412 }, +{"mad", "s,t", 0x70000000, 0xfc00ffff, RD_s|RD_t|MOD_HILO, 0, P3 }, +{"madu", "s,t", 0x70000001, 0xfc00ffff, RD_s|RD_t|MOD_HILO, 0, P3 }, +{"madd.d", "D,R,S,T", 0x4c000021, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D, 0, I4_33 }, +{"madd.d", "D,S,T", 0x46200018, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2E }, +{"madd.d", "D,S,T", 0x72200018, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2F }, +{"madd.s", "D,R,S,T", 0x4c000020, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_S, 0, I4_33 }, +{"madd.s", "D,S,T", 0x46000018, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, IL2E }, +{"madd.s", "D,S,T", 0x72000018, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, IL2F }, +{"madd.ps", "D,R,S,T", 0x4c000026, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D, 0, I5_33 }, +{"madd.ps", "D,S,T", 0x45600018, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2E }, +{"madd.ps", "D,S,T", 0x71600018, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2F }, +{"madd", "s,t", 0x0000001c, 0xfc00ffff, RD_s|RD_t|WR_HILO, 0, L1 }, +{"madd", "s,t", 0x70000000, 0xfc00ffff, RD_s|RD_t|MOD_HILO, 0, I32|N55 }, +{"madd", "s,t", 0x70000000, 0xfc00ffff, RD_s|RD_t|WR_HILO|IS_M, 0, G1 }, +{"madd", "7,s,t", 0x70000000, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D32 }, +{"madd", "d,s,t", 0x70000000, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d|IS_M, 0, G1 }, +{"maddp", "s,t", 0x70000441, 0xfc00ffff, RD_s|RD_t|MOD_HILO, 0, SMT }, +{"maddu", "s,t", 0x0000001d, 0xfc00ffff, RD_s|RD_t|WR_HILO, 0, L1 }, +{"maddu", "s,t", 0x70000001, 0xfc00ffff, RD_s|RD_t|MOD_HILO, 0, I32|N55 }, +{"maddu", "s,t", 0x70000001, 0xfc00ffff, RD_s|RD_t|WR_HILO|IS_M, 0, G1 }, +{"maddu", "7,s,t", 0x70000001, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D32 }, +{"maddu", "d,s,t", 0x70000001, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d|IS_M, 0, G1 }, +{"madd16", "s,t", 0x00000028, 0xfc00ffff, RD_s|RD_t|MOD_HILO, 0, N411 }, +{"max.ob", "X,Y,Q", 0x78000007, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX|SB1 }, +{"max.ob", "D,S,T", 0x4ac00007, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"max.ob", "D,S,T[e]", 0x48000007, 0xfe20003f, WR_D|RD_S|RD_T, 0, N54 }, +{"max.ob", "D,S,k", 0x4bc00007, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"max.qh", "X,Y,Q", 0x78200007, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, +{"mfpc", "t,P", 0x4000c801, 0xffe0ffc1, LCD|WR_t|RD_C0, 0, M1|N5 }, +{"mfps", "t,P", 0x4000c800, 0xffe0ffc1, LCD|WR_t|RD_C0, 0, M1|N5 }, +{"mftacx", "d", 0x41020021, 0xffff07ff, TRAP|WR_d|RD_a, 0, MT32 }, +{"mftacx", "d,*", 0x41020021, 0xfff307ff, TRAP|WR_d|RD_a, 0, MT32 }, +{"mftc0", "d,+t", 0x41000000, 0xffe007ff, TRAP|LCD|WR_d|RD_C0, 0, MT32 }, +{"mftc0", "d,+T", 0x41000000, 0xffe007f8, TRAP|LCD|WR_d|RD_C0, 0, MT32 }, +{"mftc0", "d,E,H", 0x41000000, 0xffe007f8, TRAP|LCD|WR_d|RD_C0, 0, MT32 }, +{"mftc1", "d,T", 0x41000022, 0xffe007ff, TRAP|LCD|WR_d|RD_T|FP_S, 0, MT32 }, +{"mftc1", "d,E", 0x41000022, 0xffe007ff, TRAP|LCD|WR_d|RD_T|FP_S, 0, MT32 }, +{"mftc2", "d,E", 0x41000024, 0xffe007ff, TRAP|LCD|WR_d|RD_C2, 0, MT32 }, +{"mftdsp", "d", 0x41100021, 0xffff07ff, TRAP|WR_d, 0, MT32 }, +{"mftgpr", "d,t", 0x41000020, 0xffe007ff, TRAP|WR_d|RD_t, 0, MT32 }, +{"mfthc1", "d,T", 0x41000032, 0xffe007ff, TRAP|LCD|WR_d|RD_T|FP_D, 0, MT32 }, +{"mfthc1", "d,E", 0x41000032, 0xffe007ff, TRAP|LCD|WR_d|RD_T|FP_D, 0, MT32 }, +{"mfthc2", "d,E", 0x41000034, 0xffe007ff, TRAP|LCD|WR_d|RD_C2, 0, MT32 }, +{"mfthi", "d", 0x41010021, 0xffff07ff, TRAP|WR_d|RD_a, 0, MT32 }, +{"mfthi", "d,*", 0x41010021, 0xfff307ff, TRAP|WR_d|RD_a, 0, MT32 }, +{"mftlo", "d", 0x41000021, 0xffff07ff, TRAP|WR_d|RD_a, 0, MT32 }, +{"mftlo", "d,*", 0x41000021, 0xfff307ff, TRAP|WR_d|RD_a, 0, MT32 }, +{"mftr", "d,t,!,H,$", 0x41000000, 0xffe007c8, TRAP|WR_d, 0, MT32 }, +{"mfc0", "t,G", 0x40000000, 0xffe007ff, LCD|WR_t|RD_C0, 0, I1|IOCT }, +{"mfc0", "t,+D", 0x40000000, 0xffe007f8, LCD|WR_t|RD_C0, 0, I32|IOCT}, +{"mfc0", "t,G,H", 0x40000000, 0xffe007f8, LCD|WR_t|RD_C0, 0, I32|IOCT}, +{"mfc1", "t,S", 0x44000000, 0xffe007ff, LCD|WR_t|RD_S|FP_S, 0, I1 }, +{"mfc1", "t,G", 0x44000000, 0xffe007ff, LCD|WR_t|RD_S|FP_S, 0, I1 }, +{"mfhc1", "t,S", 0x44600000, 0xffe007ff, LCD|WR_t|RD_S|FP_D, 0, I33 }, +{"mfhc1", "t,G", 0x44600000, 0xffe007ff, LCD|WR_t|RD_S|FP_D, 0, I33 }, +/* mfc2 is at the bottom of the table. */ +/* mfhc2 is at the bottom of the table. */ +/* mfc3 is at the bottom of the table. */ +{"mfdr", "t,G", 0x7000003d, 0xffe007ff, LCD|WR_t|RD_C0, 0, N5 }, +{"mfhi", "d", 0x00000010, 0xffff07ff, WR_d|RD_HI, 0, I1 }, +{"mfhi", "d,9", 0x00000010, 0xff9f07ff, WR_d|RD_HI, 0, D32 }, +{"mflo", "d", 0x00000012, 0xffff07ff, WR_d|RD_LO, 0, I1 }, +{"mflo", "d,9", 0x00000012, 0xff9f07ff, WR_d|RD_LO, 0, D32 }, +{"mflhxu", "d", 0x00000052, 0xffff07ff, WR_d|MOD_HILO, 0, SMT }, +{"mfcr", "t,s", 0x70000018, 0xfc00ffff, WR_t, 0, XLR }, +{"min.ob", "X,Y,Q", 0x78000006, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX|SB1 }, +{"min.ob", "D,S,T", 0x4ac00006, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"min.ob", "D,S,T[e]", 0x48000006, 0xfe20003f, WR_D|RD_S|RD_T, 0, N54 }, +{"min.ob", "D,S,k", 0x4bc00006, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"min.qh", "X,Y,Q", 0x78200006, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, +{"mov.d", "D,S", 0x46200006, 0xffff003f, WR_D|RD_S|FP_D, 0, I1 }, +{"mov.s", "D,S", 0x46000006, 0xffff003f, WR_D|RD_S|FP_S, 0, I1 }, +{"mov.ps", "D,S", 0x46c00006, 0xffff003f, WR_D|RD_S|FP_D, 0, I5_33|IL2F }, +{"mov.ps", "D,S", 0x45600006, 0xffff003f, WR_D|RD_S|FP_D, 0, IL2E }, +{"movf", "d,s,N", 0x00000001, 0xfc0307ff, WR_d|RD_s|RD_CC|FP_S|FP_D, 0, I4_32 }, +{"movf.d", "D,S,N", 0x46200011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D, 0, I4_32 }, +{"movf.l", "D,S,N", 0x46a00011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D, 0, MX|SB1 }, +{"movf.l", "X,Y,N", 0x46a00011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D, 0, MX|SB1 }, +{"movf.s", "D,S,N", 0x46000011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_S, 0, I4_32 }, +{"movf.ps", "D,S,N", 0x46c00011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D, 0, I5_33 }, +{"movn", "d,v,t", 0x0000000b, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I4_32|IL2E|IL2F }, +{"movnz", "d,v,t", 0x0000000b, 0xfc0007ff, WR_d|RD_s|RD_t, 0, IL2E|IL2F }, +{"ffc", "d,v", 0x0000000b, 0xfc1f07ff, WR_d|RD_s, 0, L1 }, +{"movn.d", "D,S,t", 0x46200013, 0xffe0003f, WR_D|RD_S|RD_t|FP_D, 0, I4_32 }, +{"movn.l", "D,S,t", 0x46a00013, 0xffe0003f, WR_D|RD_S|RD_t|FP_D, 0, MX|SB1 }, +{"movn.l", "X,Y,t", 0x46a00013, 0xffe0003f, WR_D|RD_S|RD_t|FP_D, 0, MX|SB1 }, +{"movn.s", "D,S,t", 0x46000013, 0xffe0003f, WR_D|RD_S|RD_t|FP_S, 0, I4_32 }, +{"movn.ps", "D,S,t", 0x46c00013, 0xffe0003f, WR_D|RD_S|RD_t|FP_D, 0, I5_33 }, +{"movt", "d,s,N", 0x00010001, 0xfc0307ff, WR_d|RD_s|RD_CC|FP_S|FP_D, 0, I4_32 }, +{"movt.d", "D,S,N", 0x46210011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D, 0, I4_32 }, +{"movt.l", "D,S,N", 0x46a10011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D, 0, MX|SB1 }, +{"movt.l", "X,Y,N", 0x46a10011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D, 0, MX|SB1 }, +{"movt.s", "D,S,N", 0x46010011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_S, 0, I4_32 }, +{"movt.ps", "D,S,N", 0x46c10011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D, 0, I5_33 }, +{"movz", "d,v,t", 0x0000000a, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I4_32|IL2E|IL2F }, +{"ffs", "d,v", 0x0000000a, 0xfc1f07ff, WR_d|RD_s, 0, L1 }, +{"movz.d", "D,S,t", 0x46200012, 0xffe0003f, WR_D|RD_S|RD_t|FP_D, 0, I4_32 }, +{"movz.l", "D,S,t", 0x46a00012, 0xffe0003f, WR_D|RD_S|RD_t|FP_D, 0, MX|SB1 }, +{"movz.l", "X,Y,t", 0x46a00012, 0xffe0003f, WR_D|RD_S|RD_t|FP_D, 0, MX|SB1 }, +{"movz.s", "D,S,t", 0x46000012, 0xffe0003f, WR_D|RD_S|RD_t|FP_S, 0, I4_32 }, +{"movz.ps", "D,S,t", 0x46c00012, 0xffe0003f, WR_D|RD_S|RD_t|FP_D, 0, I5_33 }, +{"msac", "d,s,t", 0x000001d8, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N5 }, +{"msacu", "d,s,t", 0x000001d9, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N5 }, +{"msachi", "d,s,t", 0x000003d8, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N5 }, +{"msachiu", "d,s,t", 0x000003d9, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N5 }, +/* move is at the top of the table. */ +{"msgn.qh", "X,Y,Q", 0x78200000, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, +{"msgsnd", "t", 0, (int) M_MSGSND, INSN_MACRO, 0, XLR }, +{"msgld", "", 0, (int) M_MSGLD, INSN_MACRO, 0, XLR }, +{"msgld", "t", 0, (int) M_MSGLD_T, INSN_MACRO, 0, XLR }, +{"msgwait", "", 0, (int) M_MSGWAIT, INSN_MACRO, 0, XLR }, +{"msgwait", "t", 0, (int) M_MSGWAIT_T,INSN_MACRO, 0, XLR }, +{"msub.d", "D,R,S,T", 0x4c000029, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D, 0, I4_33 }, +{"msub.d", "D,S,T", 0x46200019, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2E }, +{"msub.d", "D,S,T", 0x72200019, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2F }, +{"msub.s", "D,R,S,T", 0x4c000028, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_S, 0, I4_33 }, +{"msub.s", "D,S,T", 0x46000019, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, IL2E }, +{"msub.s", "D,S,T", 0x72000019, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, IL2F }, +{"msub.ps", "D,R,S,T", 0x4c00002e, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D, 0, I5_33 }, +{"msub.ps", "D,S,T", 0x45600019, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2E }, +{"msub.ps", "D,S,T", 0x71600019, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2F }, +{"msub", "s,t", 0x0000001e, 0xfc00ffff, RD_s|RD_t|WR_HILO, 0, L1 }, +{"msub", "s,t", 0x70000004, 0xfc00ffff, RD_s|RD_t|MOD_HILO, 0, I32|N55 }, +{"msub", "7,s,t", 0x70000004, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D32 }, +{"msubu", "s,t", 0x0000001f, 0xfc00ffff, RD_s|RD_t|WR_HILO, 0, L1 }, +{"msubu", "s,t", 0x70000005, 0xfc00ffff, RD_s|RD_t|MOD_HILO, 0, I32|N55 }, +{"msubu", "7,s,t", 0x70000005, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D32 }, +{"mtpc", "t,P", 0x4080c801, 0xffe0ffc1, COD|RD_t|WR_C0, 0, M1|N5 }, +{"mtps", "t,P", 0x4080c800, 0xffe0ffc1, COD|RD_t|WR_C0, 0, M1|N5 }, +{"mtc0", "t,G", 0x40800000, 0xffe007ff, COD|RD_t|WR_C0|WR_CC, 0, I1|IOCT }, +{"mtc0", "t,+D", 0x40800000, 0xffe007f8, COD|RD_t|WR_C0|WR_CC, 0, I32|IOCT}, +{"mtc0", "t,G,H", 0x40800000, 0xffe007f8, COD|RD_t|WR_C0|WR_CC, 0, I32|IOCT}, +{"mtc1", "t,S", 0x44800000, 0xffe007ff, COD|RD_t|WR_S|FP_S, 0, I1 }, +{"mtc1", "t,G", 0x44800000, 0xffe007ff, COD|RD_t|WR_S|FP_S, 0, I1 }, +{"mthc1", "t,S", 0x44e00000, 0xffe007ff, COD|RD_t|WR_S|FP_D, 0, I33 }, +{"mthc1", "t,G", 0x44e00000, 0xffe007ff, COD|RD_t|WR_S|FP_D, 0, I33 }, +/* mtc2 is at the bottom of the table. */ +/* mthc2 is at the bottom of the table. */ +/* mtc3 is at the bottom of the table. */ +{"mtdr", "t,G", 0x7080003d, 0xffe007ff, COD|RD_t|WR_C0, 0, N5 }, +{"mthi", "s", 0x00000011, 0xfc1fffff, RD_s|WR_HI, 0, I1 }, +{"mthi", "s,7", 0x00000011, 0xfc1fe7ff, RD_s|WR_HI, 0, D32 }, +{"mtlo", "s", 0x00000013, 0xfc1fffff, RD_s|WR_LO, 0, I1 }, +{"mtlo", "s,7", 0x00000013, 0xfc1fe7ff, RD_s|WR_LO, 0, D32 }, +{"mtlhx", "s", 0x00000053, 0xfc1fffff, RD_s|MOD_HILO, 0, SMT }, +{"mtcr", "t,s", 0x70000019, 0xfc00ffff, RD_t, 0, XLR }, +{"mtm0", "s", 0x70000008, 0xfc1fffff, RD_s, 0, IOCT }, +{"mtm1", "s", 0x7000000c, 0xfc1fffff, RD_s, 0, IOCT }, +{"mtm2", "s", 0x7000000d, 0xfc1fffff, RD_s, 0, IOCT }, +{"mtp0", "s", 0x70000009, 0xfc1fffff, RD_s, 0, IOCT }, +{"mtp1", "s", 0x7000000a, 0xfc1fffff, RD_s, 0, IOCT }, +{"mtp2", "s", 0x7000000b, 0xfc1fffff, RD_s, 0, IOCT }, +{"mttc0", "t,G", 0x41800000, 0xffe007ff, TRAP|COD|RD_t|WR_C0|WR_CC, 0, MT32 }, +{"mttc0", "t,+D", 0x41800000, 0xffe007f8, TRAP|COD|RD_t|WR_C0|WR_CC, 0, MT32 }, +{"mttc0", "t,G,H", 0x41800000, 0xffe007f8, TRAP|COD|RD_t|WR_C0|WR_CC, 0, MT32 }, +{"mttc1", "t,S", 0x41800022, 0xffe007ff, TRAP|COD|RD_t|WR_S|FP_S, 0, MT32 }, +{"mttc1", "t,G", 0x41800022, 0xffe007ff, TRAP|COD|RD_t|WR_S|FP_S, 0, MT32 }, +{"mttc2", "t,g", 0x41800024, 0xffe007ff, TRAP|COD|RD_t|WR_C2|WR_CC, 0, MT32 }, +{"mttacx", "t", 0x41801021, 0xffe0ffff, TRAP|WR_a|RD_t, 0, MT32 }, +{"mttacx", "t,&", 0x41801021, 0xffe09fff, TRAP|WR_a|RD_t, 0, MT32 }, +{"mttdsp", "t", 0x41808021, 0xffe0ffff, TRAP|RD_t, 0, MT32 }, +{"mttgpr", "t,d", 0x41800020, 0xffe007ff, TRAP|WR_d|RD_t, 0, MT32 }, +{"mtthc1", "t,S", 0x41800032, 0xffe007ff, TRAP|COD|RD_t|WR_S|FP_D, 0, MT32 }, +{"mtthc1", "t,G", 0x41800032, 0xffe007ff, TRAP|COD|RD_t|WR_S|FP_D, 0, MT32 }, +{"mtthc2", "t,g", 0x41800034, 0xffe007ff, TRAP|COD|RD_t|WR_C2|WR_CC, 0, MT32 }, +{"mtthi", "t", 0x41800821, 0xffe0ffff, TRAP|WR_a|RD_t, 0, MT32 }, +{"mtthi", "t,&", 0x41800821, 0xffe09fff, TRAP|WR_a|RD_t, 0, MT32 }, +{"mttlo", "t", 0x41800021, 0xffe0ffff, TRAP|WR_a|RD_t, 0, MT32 }, +{"mttlo", "t,&", 0x41800021, 0xffe09fff, TRAP|WR_a|RD_t, 0, MT32 }, +{"mttr", "t,d,!,H,$", 0x41800000, 0xffe007c8, TRAP|RD_t, 0, MT32 }, +{"mul.d", "D,V,T", 0x46200002, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I1 }, +{"mul.s", "D,V,T", 0x46000002, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, 0, I1 }, +{"mul.ob", "X,Y,Q", 0x78000030, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX|SB1 }, +{"mul.ob", "D,S,T", 0x4ac00030, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"mul.ob", "D,S,T[e]", 0x48000030, 0xfe20003f, WR_D|RD_S|RD_T, 0, N54 }, +{"mul.ob", "D,S,k", 0x4bc00030, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"mul.ps", "D,V,T", 0x46c00002, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I5_33|IL2F }, +{"mul.ps", "D,V,T", 0x45600002, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, IL2E }, +{"mul.qh", "X,Y,Q", 0x78200030, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, +{"mul", "d,v,t", 0x70000002, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0, I32|P3|N55}, +{"mul", "d,s,t", 0x00000058, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N54 }, +{"mul", "d,v,t", 0, (int) M_MUL, INSN_MACRO, 0, I1 }, +{"mul", "d,v,I", 0, (int) M_MUL_I, INSN_MACRO, 0, I1 }, +{"mula.ob", "Y,Q", 0x78000033, 0xfc2007ff, RD_S|RD_T|FP_D, WR_MACC, MX|SB1 }, +{"mula.ob", "S,T", 0x4ac00033, 0xffe007ff, WR_CC|RD_S|RD_T, 0, N54 }, +{"mula.ob", "S,T[e]", 0x48000033, 0xfe2007ff, WR_CC|RD_S|RD_T, 0, N54 }, +{"mula.ob", "S,k", 0x4bc00033, 0xffe007ff, WR_CC|RD_S|RD_T, 0, N54 }, +{"mula.qh", "Y,Q", 0x78200033, 0xfc2007ff, RD_S|RD_T|FP_D, WR_MACC, MX }, +{"mulhi", "d,s,t", 0x00000258, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N5 }, +{"mulhiu", "d,s,t", 0x00000259, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N5 }, +{"mull.ob", "Y,Q", 0x78000433, 0xfc2007ff, RD_S|RD_T|FP_D, WR_MACC, MX|SB1 }, +{"mull.ob", "S,T", 0x4ac00433, 0xffe007ff, WR_CC|RD_S|RD_T, 0, N54 }, +{"mull.ob", "S,T[e]", 0x48000433, 0xfe2007ff, WR_CC|RD_S|RD_T, 0, N54 }, +{"mull.ob", "S,k", 0x4bc00433, 0xffe007ff, WR_CC|RD_S|RD_T, 0, N54 }, +{"mull.qh", "Y,Q", 0x78200433, 0xfc2007ff, RD_S|RD_T|FP_D, WR_MACC, MX }, +{"mulo", "d,v,t", 0, (int) M_MULO, INSN_MACRO, 0, I1 }, +{"mulo", "d,v,I", 0, (int) M_MULO_I, INSN_MACRO, 0, I1 }, +{"mulou", "d,v,t", 0, (int) M_MULOU, INSN_MACRO, 0, I1 }, +{"mulou", "d,v,I", 0, (int) M_MULOU_I, INSN_MACRO, 0, I1 }, +{"mulr.ps", "D,S,T", 0x46c0001a, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, M3D }, +{"muls", "d,s,t", 0x000000d8, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N5 }, +{"mulsu", "d,s,t", 0x000000d9, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N5 }, +{"mulshi", "d,s,t", 0x000002d8, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N5 }, +{"mulshiu", "d,s,t", 0x000002d9, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N5 }, +{"muls.ob", "Y,Q", 0x78000032, 0xfc2007ff, RD_S|RD_T|FP_D, WR_MACC, MX|SB1 }, +{"muls.ob", "S,T", 0x4ac00032, 0xffe007ff, WR_CC|RD_S|RD_T, 0, N54 }, +{"muls.ob", "S,T[e]", 0x48000032, 0xfe2007ff, WR_CC|RD_S|RD_T, 0, N54 }, +{"muls.ob", "S,k", 0x4bc00032, 0xffe007ff, WR_CC|RD_S|RD_T, 0, N54 }, +{"muls.qh", "Y,Q", 0x78200032, 0xfc2007ff, RD_S|RD_T|FP_D, WR_MACC, MX }, +{"mulsl.ob", "Y,Q", 0x78000432, 0xfc2007ff, RD_S|RD_T|FP_D, WR_MACC, MX|SB1 }, +{"mulsl.ob", "S,T", 0x4ac00432, 0xffe007ff, WR_CC|RD_S|RD_T, 0, N54 }, +{"mulsl.ob", "S,T[e]", 0x48000432, 0xfe2007ff, WR_CC|RD_S|RD_T, 0, N54 }, +{"mulsl.ob", "S,k", 0x4bc00432, 0xffe007ff, WR_CC|RD_S|RD_T, 0, N54 }, +{"mulsl.qh", "Y,Q", 0x78200432, 0xfc2007ff, RD_S|RD_T|FP_D, WR_MACC, MX }, +{"mult", "s,t", 0x00000018, 0xfc00ffff, RD_s|RD_t|WR_HILO|IS_M, 0, I1 }, +{"mult", "7,s,t", 0x00000018, 0xfc00e7ff, WR_a|RD_s|RD_t, 0, D32 }, +{"mult", "d,s,t", 0x00000018, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d|IS_M, 0, G1 }, +{"multp", "s,t", 0x00000459, 0xfc00ffff, RD_s|RD_t|MOD_HILO, 0, SMT }, +{"multu", "s,t", 0x00000019, 0xfc00ffff, RD_s|RD_t|WR_HILO|IS_M, 0, I1 }, +{"multu", "7,s,t", 0x00000019, 0xfc00e7ff, WR_a|RD_s|RD_t, 0, D32 }, +{"multu", "d,s,t", 0x00000019, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d|IS_M, 0, G1 }, +{"mulu", "d,s,t", 0x00000059, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N5 }, +{"neg", "d,w", 0x00000022, 0xffe007ff, WR_d|RD_t, 0, I1 }, /* sub 0 */ +{"negu", "d,w", 0x00000023, 0xffe007ff, WR_d|RD_t, 0, I1 }, /* subu 0 */ +{"neg.d", "D,V", 0x46200007, 0xffff003f, WR_D|RD_S|FP_D, 0, I1 }, +{"neg.s", "D,V", 0x46000007, 0xffff003f, WR_D|RD_S|FP_S, 0, I1 }, +{"neg.ps", "D,V", 0x46c00007, 0xffff003f, WR_D|RD_S|FP_D, 0, I5_33|IL2F }, +{"neg.ps", "D,V", 0x45600007, 0xffff003f, WR_D|RD_S|FP_D, 0, IL2E }, +{"nmadd.d", "D,R,S,T", 0x4c000031, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D, 0, I4_33 }, +{"nmadd.d", "D,S,T", 0x4620001a, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2E }, +{"nmadd.d", "D,S,T", 0x7220001a, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2F }, +{"nmadd.s", "D,R,S,T", 0x4c000030, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_S, 0, I4_33 }, +{"nmadd.s", "D,S,T", 0x4600001a, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, IL2E }, +{"nmadd.s", "D,S,T", 0x7200001a, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, IL2F }, +{"nmadd.ps","D,R,S,T", 0x4c000036, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D, 0, I5_33 }, +{"nmadd.ps", "D,S,T", 0x4560001a, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2E }, +{"nmadd.ps", "D,S,T", 0x7160001a, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2F }, +{"nmsub.d", "D,R,S,T", 0x4c000039, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D, 0, I4_33 }, +{"nmsub.d", "D,S,T", 0x4620001b, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2E }, +{"nmsub.d", "D,S,T", 0x7220001b, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2F }, +{"nmsub.s", "D,R,S,T", 0x4c000038, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_S, 0, I4_33 }, +{"nmsub.s", "D,S,T", 0x4600001b, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, IL2E }, +{"nmsub.s", "D,S,T", 0x7200001b, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, IL2F }, +{"nmsub.ps","D,R,S,T", 0x4c00003e, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D, 0, I5_33 }, +{"nmsub.ps", "D,S,T", 0x4560001b, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2E }, +{"nmsub.ps", "D,S,T", 0x7160001b, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2F }, +/* nop is at the start of the table. */ +{"nor", "d,v,t", 0x00000027, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I1 }, +{"nor", "t,r,I", 0, (int) M_NOR_I, INSN_MACRO, 0, I1 }, +{"nor", "D,S,T", 0x47a00002, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2E }, +{"nor", "D,S,T", 0x4ba00002, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2F }, +{"nor.ob", "X,Y,Q", 0x7800000f, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX|SB1 }, +{"nor.ob", "D,S,T", 0x4ac0000f, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"nor.ob", "D,S,T[e]", 0x4800000f, 0xfe20003f, WR_D|RD_S|RD_T, 0, N54 }, +{"nor.ob", "D,S,k", 0x4bc0000f, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"nor.qh", "X,Y,Q", 0x7820000f, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, +{"not", "d,v", 0x00000027, 0xfc1f07ff, WR_d|RD_s|RD_t, 0, I1 },/*nor d,s,0*/ +{"or", "d,v,t", 0x00000025, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I1 }, +{"or", "t,r,I", 0, (int) M_OR_I, INSN_MACRO, 0, I1 }, +{"or", "D,S,T", 0x45a00000, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2E }, +{"or", "D,S,T", 0x4b20000c, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2F }, +{"or.ob", "X,Y,Q", 0x7800000e, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX|SB1 }, +{"or.ob", "D,S,T", 0x4ac0000e, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"or.ob", "D,S,T[e]", 0x4800000e, 0xfe20003f, WR_D|RD_S|RD_T, 0, N54 }, +{"or.ob", "D,S,k", 0x4bc0000e, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"or.qh", "X,Y,Q", 0x7820000e, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, +{"ori", "t,r,i", 0x34000000, 0xfc000000, WR_t|RD_s, 0, I1 }, +{"pabsdiff.ob", "X,Y,Q",0x78000009, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, SB1 }, +{"pabsdiffc.ob", "Y,Q", 0x78000035, 0xfc2007ff, RD_S|RD_T|FP_D, WR_MACC, SB1 }, +{"pavg.ob", "X,Y,Q", 0x78000008, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, SB1 }, +{"pickf.ob", "X,Y,Q", 0x78000002, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX|SB1 }, +{"pickf.ob", "D,S,T", 0x4ac00002, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"pickf.ob", "D,S,T[e]",0x48000002, 0xfe20003f, WR_D|RD_S|RD_T, 0, N54 }, +{"pickf.ob", "D,S,k", 0x4bc00002, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"pickf.qh", "X,Y,Q", 0x78200002, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, +{"pickt.ob", "X,Y,Q", 0x78000003, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX|SB1 }, +{"pickt.ob", "D,S,T", 0x4ac00003, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"pickt.ob", "D,S,T[e]",0x48000003, 0xfe20003f, WR_D|RD_S|RD_T, 0, N54 }, +{"pickt.ob", "D,S,k", 0x4bc00003, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"pickt.qh", "X,Y,Q", 0x78200003, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, +{"pll.ps", "D,V,T", 0x46c0002c, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I5_33 }, +{"plu.ps", "D,V,T", 0x46c0002d, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I5_33 }, +{"pop", "d,v", 0x7000002c, 0xfc1f07ff, WR_d|RD_s, 0, IOCT }, + /* pref and prefx are at the start of the table. */ +{"pul.ps", "D,V,T", 0x46c0002e, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I5_33 }, +{"puu.ps", "D,V,T", 0x46c0002f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I5_33 }, +{"pperm", "s,t", 0x70000481, 0xfc00ffff, MOD_HILO|RD_s|RD_t, 0, SMT }, +{"rach.ob", "X", 0x7a00003f, 0xfffff83f, WR_D|FP_D, RD_MACC, MX|SB1 }, +{"rach.ob", "D", 0x4a00003f, 0xfffff83f, WR_D, 0, N54 }, +{"rach.qh", "X", 0x7a20003f, 0xfffff83f, WR_D|FP_D, RD_MACC, MX }, +{"racl.ob", "X", 0x7800003f, 0xfffff83f, WR_D|FP_D, RD_MACC, MX|SB1 }, +{"racl.ob", "D", 0x4800003f, 0xfffff83f, WR_D, 0, N54 }, +{"racl.qh", "X", 0x7820003f, 0xfffff83f, WR_D|FP_D, RD_MACC, MX }, +{"racm.ob", "X", 0x7900003f, 0xfffff83f, WR_D|FP_D, RD_MACC, MX|SB1 }, +{"racm.ob", "D", 0x4900003f, 0xfffff83f, WR_D, 0, N54 }, +{"racm.qh", "X", 0x7920003f, 0xfffff83f, WR_D|FP_D, RD_MACC, MX }, +{"recip.d", "D,S", 0x46200015, 0xffff003f, WR_D|RD_S|FP_D, 0, I4_33 }, +{"recip.ps","D,S", 0x46c00015, 0xffff003f, WR_D|RD_S|FP_D, 0, SB1 }, +{"recip.s", "D,S", 0x46000015, 0xffff003f, WR_D|RD_S|FP_S, 0, I4_33 }, +{"recip1.d", "D,S", 0x4620001d, 0xffff003f, WR_D|RD_S|FP_D, 0, M3D }, +{"recip1.ps", "D,S", 0x46c0001d, 0xffff003f, WR_D|RD_S|FP_S, 0, M3D }, +{"recip1.s", "D,S", 0x4600001d, 0xffff003f, WR_D|RD_S|FP_S, 0, M3D }, +{"recip2.d", "D,S,T", 0x4620001c, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, M3D }, +{"recip2.ps", "D,S,T", 0x46c0001c, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, 0, M3D }, +{"recip2.s", "D,S,T", 0x4600001c, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, 0, M3D }, +{"rem", "z,s,t", 0x0000001a, 0xfc00ffff, RD_s|RD_t|WR_HILO, 0, I1 }, +{"rem", "d,v,t", 0, (int) M_REM_3, INSN_MACRO, 0, I1 }, +{"rem", "d,v,I", 0, (int) M_REM_3I, INSN_MACRO, 0, I1 }, +{"remu", "z,s,t", 0x0000001b, 0xfc00ffff, RD_s|RD_t|WR_HILO, 0, I1 }, +{"remu", "d,v,t", 0, (int) M_REMU_3, INSN_MACRO, 0, I1 }, +{"remu", "d,v,I", 0, (int) M_REMU_3I, INSN_MACRO, 0, I1 }, +{"rdhwr", "t,K", 0x7c00003b, 0xffe007ff, WR_t, 0, I33 }, +{"rdpgpr", "d,w", 0x41400000, 0xffe007ff, WR_d, 0, I33 }, +{"rfe", "", 0x42000010, 0xffffffff, 0, 0, I1|T3 }, +{"rnas.qh", "X,Q", 0x78200025, 0xfc20f83f, WR_D|RD_T|FP_D, RD_MACC, MX }, +{"rnau.ob", "X,Q", 0x78000021, 0xfc20f83f, WR_D|RD_T|FP_D, RD_MACC, MX|SB1 }, +{"rnau.qh", "X,Q", 0x78200021, 0xfc20f83f, WR_D|RD_T|FP_D, RD_MACC, MX }, +{"rnes.qh", "X,Q", 0x78200026, 0xfc20f83f, WR_D|RD_T|FP_D, RD_MACC, MX }, +{"rneu.ob", "X,Q", 0x78000022, 0xfc20f83f, WR_D|RD_T|FP_D, RD_MACC, MX|SB1 }, +{"rneu.qh", "X,Q", 0x78200022, 0xfc20f83f, WR_D|RD_T|FP_D, RD_MACC, MX }, +{"rol", "d,v,t", 0, (int) M_ROL, INSN_MACRO, 0, I1 }, +{"rol", "d,v,I", 0, (int) M_ROL_I, INSN_MACRO, 0, I1 }, +{"ror", "d,v,t", 0, (int) M_ROR, INSN_MACRO, 0, I1 }, +{"ror", "d,v,I", 0, (int) M_ROR_I, INSN_MACRO, 0, I1 }, +{"ror", "d,w,<", 0x00200002, 0xffe0003f, WR_d|RD_t, 0, N5|I33|SMT }, +{"rorv", "d,t,s", 0x00000046, 0xfc0007ff, RD_t|RD_s|WR_d, 0, N5|I33|SMT }, +{"rotl", "d,v,t", 0, (int) M_ROL, INSN_MACRO, 0, I33|SMT }, +{"rotl", "d,v,I", 0, (int) M_ROL_I, INSN_MACRO, 0, I33|SMT }, +{"ror", "d,v,t", 0, (int) M_ROR, INSN_MACRO, 0, I33|SMT }, +{"ror", "d,v,I", 0, (int) M_ROR_I, INSN_MACRO, 0, I33|SMT }, +{"rorv", "d,t,s", 0x00000046, 0xfc0007ff, RD_t|RD_s|WR_d, 0, I33|SMT }, +{"round.l.d", "D,S", 0x46200008, 0xffff003f, WR_D|RD_S|FP_D, 0, I3_33 }, +{"round.l.s", "D,S", 0x46000008, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I3_33 }, +{"round.w.d", "D,S", 0x4620000c, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I2 }, +{"round.w.s", "D,S", 0x4600000c, 0xffff003f, WR_D|RD_S|FP_S, 0, I2 }, +{"rsqrt.d", "D,S", 0x46200016, 0xffff003f, WR_D|RD_S|FP_D, 0, I4_33 }, +{"rsqrt.ps","D,S", 0x46c00016, 0xffff003f, WR_D|RD_S|FP_D, 0, SB1 }, +{"rsqrt.s", "D,S", 0x46000016, 0xffff003f, WR_D|RD_S|FP_S, 0, I4_33 }, +{"rsqrt1.d", "D,S", 0x4620001e, 0xffff003f, WR_D|RD_S|FP_D, 0, M3D }, +{"rsqrt1.ps", "D,S", 0x46c0001e, 0xffff003f, WR_D|RD_S|FP_S, 0, M3D }, +{"rsqrt1.s", "D,S", 0x4600001e, 0xffff003f, WR_D|RD_S|FP_S, 0, M3D }, +{"rsqrt2.d", "D,S,T", 0x4620001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, M3D }, +{"rsqrt2.ps", "D,S,T", 0x46c0001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, 0, M3D }, +{"rsqrt2.s", "D,S,T", 0x4600001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, 0, M3D }, +{"rzs.qh", "X,Q", 0x78200024, 0xfc20f83f, WR_D|RD_T|FP_D, RD_MACC, MX }, +{"rzu.ob", "X,Q", 0x78000020, 0xfc20f83f, WR_D|RD_T|FP_D, RD_MACC, MX|SB1 }, +{"rzu.ob", "D,k", 0x4bc00020, 0xffe0f83f, WR_D|RD_S|RD_T, 0, N54 }, +{"rzu.qh", "X,Q", 0x78200020, 0xfc20f83f, WR_D|RD_T|FP_D, RD_MACC, MX }, +{"sb", "t,o(b)", 0xa0000000, 0xfc000000, SM|RD_t|RD_b, 0, I1 }, +{"sb", "t,A(b)", 0, (int) M_SB_AB, INSN_MACRO, 0, I1 }, +{"sc", "t,o(b)", 0xe0000000, 0xfc000000, SM|RD_t|WR_t|RD_b, 0, I2 }, +{"sc", "t,A(b)", 0, (int) M_SC_AB, INSN_MACRO, 0, I2 }, +{"scd", "t,o(b)", 0xf0000000, 0xfc000000, SM|RD_t|WR_t|RD_b, 0, I3 }, +{"scd", "t,A(b)", 0, (int) M_SCD_AB, INSN_MACRO, 0, I3 }, +/* The macro has to be first to handle o32 correctly. */ +{"sd", "t,o(b)", 0, (int) M_SD_OB, INSN_MACRO, 0, I1 }, +{"sd", "t,o(b)", 0xfc000000, 0xfc000000, SM|RD_t|RD_b, 0, I3 }, +{"sd", "t,A(b)", 0, (int) M_SD_AB, INSN_MACRO, 0, I1 }, +{"sdbbp", "", 0x0000000e, 0xffffffff, TRAP, 0, G2 }, +{"sdbbp", "c", 0x0000000e, 0xfc00ffff, TRAP, 0, G2 }, +{"sdbbp", "c,q", 0x0000000e, 0xfc00003f, TRAP, 0, G2 }, +{"sdbbp", "", 0x7000003f, 0xffffffff, TRAP, 0, I32 }, +{"sdbbp", "B", 0x7000003f, 0xfc00003f, TRAP, 0, I32 }, +{"sdc1", "T,o(b)", 0xf4000000, 0xfc000000, SM|RD_T|RD_b|FP_D, 0, I2 }, +{"sdc1", "E,o(b)", 0xf4000000, 0xfc000000, SM|RD_T|RD_b|FP_D, 0, I2 }, +{"sdc1", "T,A(b)", 0, (int) M_SDC1_AB, INSN_MACRO, INSN2_M_FP_D, I2 }, +{"sdc1", "E,A(b)", 0, (int) M_SDC1_AB, INSN_MACRO, INSN2_M_FP_D, I2 }, +{"sdc2", "E,o(b)", 0xf8000000, 0xfc000000, SM|RD_C2|RD_b, 0, I2 }, +{"sdc2", "E,A(b)", 0, (int) M_SDC2_AB, INSN_MACRO, 0, I2 }, +{"sdc3", "E,o(b)", 0xfc000000, 0xfc000000, SM|RD_C3|RD_b, 0, I2 }, +{"sdc3", "E,A(b)", 0, (int) M_SDC3_AB, INSN_MACRO, 0, I2 }, +{"s.d", "T,o(b)", 0xf4000000, 0xfc000000, SM|RD_T|RD_b|FP_D, 0, I2 }, +{"s.d", "T,o(b)", 0, (int) M_S_DOB, INSN_MACRO, INSN2_M_FP_D, I1 }, +{"s.d", "T,A(b)", 0, (int) M_S_DAB, INSN_MACRO, INSN2_M_FP_D, I1 }, +{"sdl", "t,o(b)", 0xb0000000, 0xfc000000, SM|RD_t|RD_b, 0, I3 }, +{"sdl", "t,A(b)", 0, (int) M_SDL_AB, INSN_MACRO, 0, I3 }, +{"sdr", "t,o(b)", 0xb4000000, 0xfc000000, SM|RD_t|RD_b, 0, I3 }, +{"sdr", "t,A(b)", 0, (int) M_SDR_AB, INSN_MACRO, 0, I3 }, +{"sdxc1", "S,t(b)", 0x4c000009, 0xfc0007ff, SM|RD_S|RD_t|RD_b|FP_D, 0, I4_33 }, +{"seb", "d,w", 0x7c000420, 0xffe007ff, WR_d|RD_t, 0, I33 }, +{"seh", "d,w", 0x7c000620, 0xffe007ff, WR_d|RD_t, 0, I33 }, +{"selsl", "d,v,t", 0x00000005, 0xfc0007ff, WR_d|RD_s|RD_t, 0, L1 }, +{"selsr", "d,v,t", 0x00000001, 0xfc0007ff, WR_d|RD_s|RD_t, 0, L1 }, +{"seq", "d,v,t", 0x7000002a, 0xfc0007ff, WR_d|RD_s|RD_t, 0, IOCT }, +{"seq", "d,v,t", 0, (int) M_SEQ, INSN_MACRO, 0, I1 }, +{"seq", "d,v,I", 0, (int) M_SEQ_I, INSN_MACRO, 0, I1 }, +{"seq", "S,T", 0x46a00032, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, IL2E }, +{"seq", "S,T", 0x4ba0000c, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, IL2F }, +{"seqi", "t,r,+Q", 0x7000002e, 0xfc00003f, WR_t|RD_s, 0, IOCT }, +{"sge", "d,v,t", 0, (int) M_SGE, INSN_MACRO, 0, I1 }, +{"sge", "d,v,I", 0, (int) M_SGE_I, INSN_MACRO, 0, I1 }, +{"sgeu", "d,v,t", 0, (int) M_SGEU, INSN_MACRO, 0, I1 }, +{"sgeu", "d,v,I", 0, (int) M_SGEU_I, INSN_MACRO, 0, I1 }, +{"sgt", "d,v,t", 0, (int) M_SGT, INSN_MACRO, 0, I1 }, +{"sgt", "d,v,I", 0, (int) M_SGT_I, INSN_MACRO, 0, I1 }, +{"sgtu", "d,v,t", 0, (int) M_SGTU, INSN_MACRO, 0, I1 }, +{"sgtu", "d,v,I", 0, (int) M_SGTU_I, INSN_MACRO, 0, I1 }, +{"sh", "t,o(b)", 0xa4000000, 0xfc000000, SM|RD_t|RD_b, 0, I1 }, +{"sh", "t,A(b)", 0, (int) M_SH_AB, INSN_MACRO, 0, I1 }, +{"shfl.bfla.qh", "X,Y,Z", 0x7a20001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, +{"shfl.mixh.ob", "X,Y,Z", 0x7980001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, MX|SB1 }, +{"shfl.mixh.ob", "D,S,T", 0x4980001f, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"shfl.mixh.qh", "X,Y,Z", 0x7820001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, +{"shfl.mixl.ob", "X,Y,Z", 0x79c0001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, MX|SB1 }, +{"shfl.mixl.ob", "D,S,T", 0x49c0001f, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"shfl.mixl.qh", "X,Y,Z", 0x78a0001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, +{"shfl.pach.ob", "X,Y,Z", 0x7900001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, MX|SB1 }, +{"shfl.pach.ob", "D,S,T", 0x4900001f, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"shfl.pach.qh", "X,Y,Z", 0x7920001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, +{"shfl.pacl.ob", "D,S,T", 0x4940001f, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"shfl.repa.qh", "X,Y,Z", 0x7b20001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, +{"shfl.repb.qh", "X,Y,Z", 0x7ba0001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, +{"shfl.upsl.ob", "X,Y,Z", 0x78c0001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, MX|SB1 }, +{"sle", "d,v,t", 0, (int) M_SLE, INSN_MACRO, 0, I1 }, +{"sle", "d,v,I", 0, (int) M_SLE_I, INSN_MACRO, 0, I1 }, +{"sle", "S,T", 0x46a0003e, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, IL2E }, +{"sle", "S,T", 0x4ba0000e, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, IL2F }, +{"sleu", "d,v,t", 0, (int) M_SLEU, INSN_MACRO, 0, I1 }, +{"sleu", "d,v,I", 0, (int) M_SLEU_I, INSN_MACRO, 0, I1 }, +{"sleu", "S,T", 0x4680003e, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, IL2E }, +{"sleu", "S,T", 0x4b80000e, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, IL2F }, +{"sllv", "d,t,s", 0x00000004, 0xfc0007ff, WR_d|RD_t|RD_s, 0, I1 }, +{"sll", "d,w,s", 0x00000004, 0xfc0007ff, WR_d|RD_t|RD_s, 0, I1 }, /* sllv */ +{"sll", "d,w,<", 0x00000000, 0xffe0003f, WR_d|RD_t, 0, I1 }, +{"sll", "D,S,T", 0x45800002, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2E }, +{"sll", "D,S,T", 0x4b00000e, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2F }, +{"sll.ob", "X,Y,Q", 0x78000010, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX|SB1 }, +{"sll.ob", "D,S,T[e]", 0x48000010, 0xfe20003f, WR_D|RD_S|RD_T, 0, N54 }, +{"sll.ob", "D,S,k", 0x4bc00010, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"sll.qh", "X,Y,Q", 0x78200010, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, +{"slt", "d,v,t", 0x0000002a, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I1 }, +{"slt", "d,v,I", 0, (int) M_SLT_I, INSN_MACRO, 0, I1 }, +{"slt", "S,T", 0x46a0003c, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, IL2E }, +{"slt", "S,T", 0x4ba0000d, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, IL2F }, +{"slti", "t,r,j", 0x28000000, 0xfc000000, WR_t|RD_s, 0, I1 }, +{"sltiu", "t,r,j", 0x2c000000, 0xfc000000, WR_t|RD_s, 0, I1 }, +{"sltu", "d,v,t", 0x0000002b, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I1 }, +{"sltu", "d,v,I", 0, (int) M_SLTU_I, INSN_MACRO, 0, I1 }, +{"sltu", "S,T", 0x4680003c, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, IL2E }, +{"sltu", "S,T", 0x4b80000d, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, IL2F }, +{"sne", "d,v,t", 0x7000002b, 0xfc0007ff, WR_d|RD_s|RD_t, 0, IOCT }, +{"sne", "d,v,t", 0, (int) M_SNE, INSN_MACRO, 0, I1 }, +{"sne", "d,v,I", 0, (int) M_SNE_I, INSN_MACRO, 0, I1 }, +{"snei", "t,r,+Q", 0x7000002f, 0xfc00003f, WR_t|RD_s, 0, IOCT }, +{"sqrt.d", "D,S", 0x46200004, 0xffff003f, WR_D|RD_S|FP_D, 0, I2 }, +{"sqrt.s", "D,S", 0x46000004, 0xffff003f, WR_D|RD_S|FP_S, 0, I2 }, +{"sqrt.ps", "D,S", 0x46c00004, 0xffff003f, WR_D|RD_S|FP_D, 0, SB1 }, +{"srav", "d,t,s", 0x00000007, 0xfc0007ff, WR_d|RD_t|RD_s, 0, I1 }, +{"sra", "d,w,s", 0x00000007, 0xfc0007ff, WR_d|RD_t|RD_s, 0, I1 }, /* srav */ +{"sra", "d,w,<", 0x00000003, 0xffe0003f, WR_d|RD_t, 0, I1 }, +{"sra", "D,S,T", 0x45c00003, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2E }, +{"sra", "D,S,T", 0x4b40000f, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2F }, +{"sra.qh", "X,Y,Q", 0x78200013, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, +{"srlv", "d,t,s", 0x00000006, 0xfc0007ff, WR_d|RD_t|RD_s, 0, I1 }, +{"srl", "d,w,s", 0x00000006, 0xfc0007ff, WR_d|RD_t|RD_s, 0, I1 }, /* srlv */ +{"srl", "d,w,<", 0x00000002, 0xffe0003f, WR_d|RD_t, 0, I1 }, +{"srl", "D,S,T", 0x45800003, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2E }, +{"srl", "D,S,T", 0x4b00000f, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2F }, +{"srl.ob", "X,Y,Q", 0x78000012, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX|SB1 }, +{"srl.ob", "D,S,T[e]", 0x48000012, 0xfe20003f, WR_D|RD_S|RD_T, 0, N54 }, +{"srl.ob", "D,S,k", 0x4bc00012, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"srl.qh", "X,Y,Q", 0x78200012, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, +/* ssnop is at the start of the table. */ +{"standby", "", 0x42000021, 0xffffffff, 0, 0, V1 }, +{"sub", "d,v,t", 0x00000022, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I1 }, +{"sub", "d,v,I", 0, (int) M_SUB_I, INSN_MACRO, 0, I1 }, +{"sub", "D,S,T", 0x45c00001, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, IL2E }, +{"sub", "D,S,T", 0x4b40000d, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, IL2F }, +{"sub.d", "D,V,T", 0x46200001, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I1 }, +{"sub.s", "D,V,T", 0x46000001, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, 0, I1 }, +{"sub.ob", "X,Y,Q", 0x7800000a, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX|SB1 }, +{"sub.ob", "D,S,T", 0x4ac0000a, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"sub.ob", "D,S,T[e]", 0x4800000a, 0xfe20003f, WR_D|RD_S|RD_T, 0, N54 }, +{"sub.ob", "D,S,k", 0x4bc0000a, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"sub.ps", "D,V,T", 0x46c00001, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I5_33|IL2F }, +{"sub.ps", "D,V,T", 0x45600001, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, IL2E }, +{"sub.qh", "X,Y,Q", 0x7820000a, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, +{"suba.ob", "Y,Q", 0x78000036, 0xfc2007ff, RD_S|RD_T|FP_D, WR_MACC, MX|SB1 }, +{"suba.qh", "Y,Q", 0x78200036, 0xfc2007ff, RD_S|RD_T|FP_D, WR_MACC, MX }, +{"subl.ob", "Y,Q", 0x78000436, 0xfc2007ff, RD_S|RD_T|FP_D, WR_MACC, MX|SB1 }, +{"subl.qh", "Y,Q", 0x78200436, 0xfc2007ff, RD_S|RD_T|FP_D, WR_MACC, MX }, +{"subu", "d,v,t", 0x00000023, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I1 }, +{"subu", "d,v,I", 0, (int) M_SUBU_I, INSN_MACRO, 0, I1 }, +{"subu", "D,S,T", 0x45800001, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, IL2E }, +{"subu", "D,S,T", 0x4b00000d, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, IL2F }, +{"suspend", "", 0x42000022, 0xffffffff, 0, 0, V1 }, +{"suxc1", "S,t(b)", 0x4c00000d, 0xfc0007ff, SM|RD_S|RD_t|RD_b|FP_D, 0, I5_33|N55}, +{"sw", "t,o(b)", 0xac000000, 0xfc000000, SM|RD_t|RD_b, 0, I1 }, +{"sw", "t,A(b)", 0, (int) M_SW_AB, INSN_MACRO, 0, I1 }, +{"swapw", "t,b", 0x70000014, 0xfc00ffff, SM|RD_t|WR_t|RD_b, 0, XLR }, +{"swapwu", "t,b", 0x70000015, 0xfc00ffff, SM|RD_t|WR_t|RD_b, 0, XLR }, +{"swapd", "t,b", 0x70000016, 0xfc00ffff, SM|RD_t|WR_t|RD_b, 0, XLR }, +{"swc0", "E,o(b)", 0xe0000000, 0xfc000000, SM|RD_C0|RD_b, 0, I1 }, +{"swc0", "E,A(b)", 0, (int) M_SWC0_AB, INSN_MACRO, 0, I1 }, +{"swc1", "T,o(b)", 0xe4000000, 0xfc000000, SM|RD_T|RD_b|FP_S, 0, I1 }, +{"swc1", "E,o(b)", 0xe4000000, 0xfc000000, SM|RD_T|RD_b|FP_S, 0, I1 }, +{"swc1", "T,A(b)", 0, (int) M_SWC1_AB, INSN_MACRO, INSN2_M_FP_S, I1 }, +{"swc1", "E,A(b)", 0, (int) M_SWC1_AB, INSN_MACRO, INSN2_M_FP_S, I1 }, +{"s.s", "T,o(b)", 0xe4000000, 0xfc000000, SM|RD_T|RD_b|FP_S, 0, I1 }, /* swc1 */ +{"s.s", "T,A(b)", 0, (int) M_SWC1_AB, INSN_MACRO, INSN2_M_FP_S, I1 }, +{"swc2", "E,o(b)", 0xe8000000, 0xfc000000, SM|RD_C2|RD_b, 0, I1 }, +{"swc2", "E,A(b)", 0, (int) M_SWC2_AB, INSN_MACRO, 0, I1 }, +{"swc3", "E,o(b)", 0xec000000, 0xfc000000, SM|RD_C3|RD_b, 0, I1 }, +{"swc3", "E,A(b)", 0, (int) M_SWC3_AB, INSN_MACRO, 0, I1 }, +{"swl", "t,o(b)", 0xa8000000, 0xfc000000, SM|RD_t|RD_b, 0, I1 }, +{"swl", "t,A(b)", 0, (int) M_SWL_AB, INSN_MACRO, 0, I1 }, +{"scache", "t,o(b)", 0xa8000000, 0xfc000000, RD_t|RD_b, 0, I2 }, /* same */ +{"scache", "t,A(b)", 0, (int) M_SWL_AB, INSN_MACRO, 0, I2 }, /* as swl */ +{"swr", "t,o(b)", 0xb8000000, 0xfc000000, SM|RD_t|RD_b, 0, I1 }, +{"swr", "t,A(b)", 0, (int) M_SWR_AB, INSN_MACRO, 0, I1 }, +{"invalidate", "t,o(b)",0xb8000000, 0xfc000000, RD_t|RD_b, 0, I2 }, /* same */ +{"invalidate", "t,A(b)",0, (int) M_SWR_AB, INSN_MACRO, 0, I2 }, /* as swr */ +{"swxc1", "S,t(b)", 0x4c000008, 0xfc0007ff, SM|RD_S|RD_t|RD_b|FP_S, 0, I4_33 }, +{"synciobdma", "", 0x0000008f, 0xffffffff, INSN_SYNC, 0, IOCT }, +{"syncs", "", 0x0000018f, 0xffffffff, INSN_SYNC, 0, IOCT }, +{"syncw", "", 0x0000010f, 0xffffffff, INSN_SYNC, 0, IOCT }, +{"syncws", "", 0x0000014f, 0xffffffff, INSN_SYNC, 0, IOCT }, +{"sync_acquire", "", 0x0000044f, 0xffffffff, INSN_SYNC, 0, I33 }, +{"sync_mb", "", 0x0000040f, 0xffffffff, INSN_SYNC, 0, I33 }, +{"sync_release", "", 0x0000048f, 0xffffffff, INSN_SYNC, 0, I33 }, +{"sync_rmb", "", 0x000004cf, 0xffffffff, INSN_SYNC, 0, I33 }, +{"sync_wmb", "", 0x0000010f, 0xffffffff, INSN_SYNC, 0, I33 }, +{"sync", "", 0x0000000f, 0xffffffff, INSN_SYNC, 0, I2|G1 }, +{"sync", "1", 0x0000000f, 0xfffff83f, INSN_SYNC, 0, I32 }, +{"sync.p", "", 0x0000040f, 0xffffffff, INSN_SYNC, 0, I2 }, +{"sync.l", "", 0x0000000f, 0xffffffff, INSN_SYNC, 0, I2 }, +{"synci", "o(b)", 0x041f0000, 0xfc1f0000, SM|RD_b, 0, I33 }, +{"syscall", "", 0x0000000c, 0xffffffff, TRAP, 0, I1 }, +{"syscall", "B", 0x0000000c, 0xfc00003f, TRAP, 0, I1 }, +{"teqi", "s,j", 0x040c0000, 0xfc1f0000, RD_s|TRAP, 0, I2 }, +{"teq", "s,t", 0x00000034, 0xfc00ffff, RD_s|RD_t|TRAP, 0, I2 }, +{"teq", "s,t,q", 0x00000034, 0xfc00003f, RD_s|RD_t|TRAP, 0, I2 }, +{"teq", "s,j", 0x040c0000, 0xfc1f0000, RD_s|TRAP, 0, I2 }, /* teqi */ +{"teq", "s,I", 0, (int) M_TEQ_I, INSN_MACRO, 0, I2 }, +{"tgei", "s,j", 0x04080000, 0xfc1f0000, RD_s|TRAP, 0, I2 }, +{"tge", "s,t", 0x00000030, 0xfc00ffff, RD_s|RD_t|TRAP, 0, I2 }, +{"tge", "s,t,q", 0x00000030, 0xfc00003f, RD_s|RD_t|TRAP, 0, I2 }, +{"tge", "s,j", 0x04080000, 0xfc1f0000, RD_s|TRAP, 0, I2 }, /* tgei */ +{"tge", "s,I", 0, (int) M_TGE_I, INSN_MACRO, 0, I2 }, +{"tgeiu", "s,j", 0x04090000, 0xfc1f0000, RD_s|TRAP, 0, I2 }, +{"tgeu", "s,t", 0x00000031, 0xfc00ffff, RD_s|RD_t|TRAP, 0, I2 }, +{"tgeu", "s,t,q", 0x00000031, 0xfc00003f, RD_s|RD_t|TRAP, 0, I2 }, +{"tgeu", "s,j", 0x04090000, 0xfc1f0000, RD_s|TRAP, 0, I2 }, /* tgeiu */ +{"tgeu", "s,I", 0, (int) M_TGEU_I, INSN_MACRO, 0, I2 }, +{"tlbp", "", 0x42000008, 0xffffffff, INSN_TLB, 0, I1 }, +{"tlbr", "", 0x42000001, 0xffffffff, INSN_TLB, 0, I1 }, +{"tlbwi", "", 0x42000002, 0xffffffff, INSN_TLB, 0, I1 }, +{"tlbwr", "", 0x42000006, 0xffffffff, INSN_TLB, 0, I1 }, +{"tlti", "s,j", 0x040a0000, 0xfc1f0000, RD_s|TRAP, 0, I2 }, +{"tlt", "s,t", 0x00000032, 0xfc00ffff, RD_s|RD_t|TRAP, 0, I2 }, +{"tlt", "s,t,q", 0x00000032, 0xfc00003f, RD_s|RD_t|TRAP, 0, I2 }, +{"tlt", "s,j", 0x040a0000, 0xfc1f0000, RD_s|TRAP, 0, I2 }, /* tlti */ +{"tlt", "s,I", 0, (int) M_TLT_I, INSN_MACRO, 0, I2 }, +{"tltiu", "s,j", 0x040b0000, 0xfc1f0000, RD_s|TRAP, 0, I2 }, +{"tltu", "s,t", 0x00000033, 0xfc00ffff, RD_s|RD_t|TRAP, 0, I2 }, +{"tltu", "s,t,q", 0x00000033, 0xfc00003f, RD_s|RD_t|TRAP, 0, I2 }, +{"tltu", "s,j", 0x040b0000, 0xfc1f0000, RD_s|TRAP, 0, I2 }, /* tltiu */ +{"tltu", "s,I", 0, (int) M_TLTU_I, INSN_MACRO, 0, I2 }, +{"tnei", "s,j", 0x040e0000, 0xfc1f0000, RD_s|TRAP, 0, I2 }, +{"tne", "s,t", 0x00000036, 0xfc00ffff, RD_s|RD_t|TRAP, 0, I2 }, +{"tne", "s,t,q", 0x00000036, 0xfc00003f, RD_s|RD_t|TRAP, 0, I2 }, +{"tne", "s,j", 0x040e0000, 0xfc1f0000, RD_s|TRAP, 0, I2 }, /* tnei */ +{"tne", "s,I", 0, (int) M_TNE_I, INSN_MACRO, 0, I2 }, +{"trunc.l.d", "D,S", 0x46200009, 0xffff003f, WR_D|RD_S|FP_D, 0, I3_33 }, +{"trunc.l.s", "D,S", 0x46000009, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I3_33 }, +{"trunc.w.d", "D,S", 0x4620000d, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I2 }, +{"trunc.w.d", "D,S,x", 0x4620000d, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I2 }, +{"trunc.w.d", "D,S,t", 0, (int) M_TRUNCWD, INSN_MACRO, INSN2_M_FP_S|INSN2_M_FP_D, I1 }, +{"trunc.w.s", "D,S", 0x4600000d, 0xffff003f, WR_D|RD_S|FP_S, 0, I2 }, +{"trunc.w.s", "D,S,x", 0x4600000d, 0xffff003f, WR_D|RD_S|FP_S, 0, I2 }, +{"trunc.w.s", "D,S,t", 0, (int) M_TRUNCWS, INSN_MACRO, INSN2_M_FP_S, I1 }, +{"uld", "t,o(b)", 0, (int) M_ULD, INSN_MACRO, 0, I3 }, +{"uld", "t,A(b)", 0, (int) M_ULD_A, INSN_MACRO, 0, I3 }, +{"ulh", "t,o(b)", 0, (int) M_ULH, INSN_MACRO, 0, I1 }, +{"ulh", "t,A(b)", 0, (int) M_ULH_A, INSN_MACRO, 0, I1 }, +{"ulhu", "t,o(b)", 0, (int) M_ULHU, INSN_MACRO, 0, I1 }, +{"ulhu", "t,A(b)", 0, (int) M_ULHU_A, INSN_MACRO, 0, I1 }, +{"ulw", "t,o(b)", 0, (int) M_ULW, INSN_MACRO, 0, I1 }, +{"ulw", "t,A(b)", 0, (int) M_ULW_A, INSN_MACRO, 0, I1 }, +{"usd", "t,o(b)", 0, (int) M_USD, INSN_MACRO, 0, I3 }, +{"usd", "t,A(b)", 0, (int) M_USD_A, INSN_MACRO, 0, I3 }, +{"ush", "t,o(b)", 0, (int) M_USH, INSN_MACRO, 0, I1 }, +{"ush", "t,A(b)", 0, (int) M_USH_A, INSN_MACRO, 0, I1 }, +{"usw", "t,o(b)", 0, (int) M_USW, INSN_MACRO, 0, I1 }, +{"usw", "t,A(b)", 0, (int) M_USW_A, INSN_MACRO, 0, I1 }, +{"v3mulu", "d,v,t", 0x70000011, 0xfc0007ff, WR_d|RD_s|RD_t, 0, IOCT }, +{"vmm0", "d,v,t", 0x70000010, 0xfc0007ff, WR_d|RD_s|RD_t, 0, IOCT }, +{"vmulu", "d,v,t", 0x7000000f, 0xfc0007ff, WR_d|RD_s|RD_t, 0, IOCT }, +{"wach.ob", "Y", 0x7a00003e, 0xffff07ff, RD_S|FP_D, WR_MACC, MX|SB1 }, +{"wach.ob", "S", 0x4a00003e, 0xffff07ff, RD_S, 0, N54 }, +{"wach.qh", "Y", 0x7a20003e, 0xffff07ff, RD_S|FP_D, WR_MACC, MX }, +{"wacl.ob", "Y,Z", 0x7800003e, 0xffe007ff, RD_S|RD_T|FP_D, WR_MACC, MX|SB1 }, +{"wacl.ob", "S,T", 0x4800003e, 0xffe007ff, RD_S|RD_T, 0, N54 }, +{"wacl.qh", "Y,Z", 0x7820003e, 0xffe007ff, RD_S|RD_T|FP_D, WR_MACC, MX }, +{"wait", "", 0x42000020, 0xffffffff, TRAP, 0, I3_32 }, +{"wait", "J", 0x42000020, 0xfe00003f, TRAP, 0, I32|N55 }, +{"waiti", "", 0x42000020, 0xffffffff, TRAP, 0, L1 }, +{"wrpgpr", "d,w", 0x41c00000, 0xffe007ff, RD_t, 0, I33 }, +{"wsbh", "d,w", 0x7c0000a0, 0xffe007ff, WR_d|RD_t, 0, I33 }, +{"xor", "d,v,t", 0x00000026, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I1 }, +{"xor", "t,r,I", 0, (int) M_XOR_I, INSN_MACRO, 0, I1 }, +{"xor", "D,S,T", 0x47800002, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2E }, +{"xor", "D,S,T", 0x4b800002, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2F }, +{"xor.ob", "X,Y,Q", 0x7800000d, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX|SB1 }, +{"xor.ob", "D,S,T", 0x4ac0000d, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"xor.ob", "D,S,T[e]", 0x4800000d, 0xfe20003f, WR_D|RD_S|RD_T, 0, N54 }, +{"xor.ob", "D,S,k", 0x4bc0000d, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"xor.qh", "X,Y,Q", 0x7820000d, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, +{"xori", "t,r,i", 0x38000000, 0xfc000000, WR_t|RD_s, 0, I1 }, +{"yield", "s", 0x7c000009, 0xfc1fffff, TRAP|RD_s, 0, MT32 }, +{"yield", "d,s", 0x7c000009, 0xfc1f07ff, TRAP|WR_d|RD_s, 0, MT32 }, + +/* User Defined Instruction. */ +{"udi0", "s,t,d,+1",0x70000010, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi0", "s,t,+2", 0x70000010, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi0", "s,+3", 0x70000010, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi0", "+4", 0x70000010, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi1", "s,t,d,+1",0x70000011, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi1", "s,t,+2", 0x70000011, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi1", "s,+3", 0x70000011, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi1", "+4", 0x70000011, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi2", "s,t,d,+1",0x70000012, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi2", "s,t,+2", 0x70000012, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi2", "s,+3", 0x70000012, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi2", "+4", 0x70000012, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi3", "s,t,d,+1",0x70000013, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi3", "s,t,+2", 0x70000013, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi3", "s,+3", 0x70000013, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi3", "+4", 0x70000013, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi4", "s,t,d,+1",0x70000014, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi4", "s,t,+2", 0x70000014, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi4", "s,+3", 0x70000014, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi4", "+4", 0x70000014, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi5", "s,t,d,+1",0x70000015, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi5", "s,t,+2", 0x70000015, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi5", "s,+3", 0x70000015, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi5", "+4", 0x70000015, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi6", "s,t,d,+1",0x70000016, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi6", "s,t,+2", 0x70000016, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi6", "s,+3", 0x70000016, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi6", "+4", 0x70000016, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi7", "s,t,d,+1",0x70000017, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi7", "s,t,+2", 0x70000017, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi7", "s,+3", 0x70000017, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi7", "+4", 0x70000017, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi8", "s,t,d,+1",0x70000018, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi8", "s,t,+2", 0x70000018, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi8", "s,+3", 0x70000018, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi8", "+4", 0x70000018, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi9", "s,t,d,+1",0x70000019, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi9", "s,t,+2", 0x70000019, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi9", "s,+3", 0x70000019, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi9", "+4", 0x70000019, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi10", "s,t,d,+1",0x7000001a, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi10", "s,t,+2", 0x7000001a, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi10", "s,+3", 0x7000001a, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi10", "+4", 0x7000001a, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi11", "s,t,d,+1",0x7000001b, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi11", "s,t,+2", 0x7000001b, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi11", "s,+3", 0x7000001b, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi11", "+4", 0x7000001b, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi12", "s,t,d,+1",0x7000001c, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi12", "s,t,+2", 0x7000001c, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi12", "s,+3", 0x7000001c, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi12", "+4", 0x7000001c, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi13", "s,t,d,+1",0x7000001d, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi13", "s,t,+2", 0x7000001d, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi13", "s,+3", 0x7000001d, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi13", "+4", 0x7000001d, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi14", "s,t,d,+1",0x7000001e, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi14", "s,t,+2", 0x7000001e, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi14", "s,+3", 0x7000001e, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi14", "+4", 0x7000001e, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi15", "s,t,d,+1",0x7000001f, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi15", "s,t,+2", 0x7000001f, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi15", "s,+3", 0x7000001f, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi15", "+4", 0x7000001f, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, + +/* Coprocessor 2 move/branch operations overlap with VR5400 .ob format + instructions so they are here for the latters to take precedence. */ +{"bc2f", "p", 0x49000000, 0xffff0000, CBD|RD_CC, 0, I1 }, +{"bc2f", "N,p", 0x49000000, 0xffe30000, CBD|RD_CC, 0, I32 }, +{"bc2fl", "p", 0x49020000, 0xffff0000, CBL|RD_CC, 0, I2|T3 }, +{"bc2fl", "N,p", 0x49020000, 0xffe30000, CBL|RD_CC, 0, I32 }, +{"bc2t", "p", 0x49010000, 0xffff0000, CBD|RD_CC, 0, I1 }, +{"bc2t", "N,p", 0x49010000, 0xffe30000, CBD|RD_CC, 0, I32 }, +{"bc2tl", "p", 0x49030000, 0xffff0000, CBL|RD_CC, 0, I2|T3 }, +{"bc2tl", "N,p", 0x49030000, 0xffe30000, CBL|RD_CC, 0, I32 }, +{"cfc2", "t,G", 0x48400000, 0xffe007ff, LCD|WR_t|RD_C2, 0, I1 }, +{"ctc2", "t,G", 0x48c00000, 0xffe007ff, COD|RD_t|WR_CC, 0, I1 }, +{"dmfc2", "t,i", 0x48200000, 0xffe00000, LCD|WR_t|RD_C2, 0, IOCT }, +{"dmfc2", "t,G", 0x48200000, 0xffe007ff, LCD|WR_t|RD_C2, 0, I3 }, +{"dmfc2", "t,G,H", 0x48200000, 0xffe007f8, LCD|WR_t|RD_C2, 0, I64 }, +{"dmtc2", "t,i", 0x48a00000, 0xffe00000, COD|RD_t|WR_C2|WR_CC, 0, IOCT }, +{"dmtc2", "t,G", 0x48a00000, 0xffe007ff, COD|RD_t|WR_C2|WR_CC, 0, I3 }, +{"dmtc2", "t,G,H", 0x48a00000, 0xffe007f8, COD|RD_t|WR_C2|WR_CC, 0, I64 }, +{"mfc2", "t,G", 0x48000000, 0xffe007ff, LCD|WR_t|RD_C2, 0, I1 }, +{"mfc2", "t,G,H", 0x48000000, 0xffe007f8, LCD|WR_t|RD_C2, 0, I32 }, +{"mfhc2", "t,G", 0x48600000, 0xffe007ff, LCD|WR_t|RD_C2, 0, I33 }, +{"mfhc2", "t,G,H", 0x48600000, 0xffe007f8, LCD|WR_t|RD_C2, 0, I33 }, +{"mfhc2", "t,i", 0x48600000, 0xffe00000, LCD|WR_t|RD_C2, 0, I33 }, +{"mtc2", "t,G", 0x48800000, 0xffe007ff, COD|RD_t|WR_C2|WR_CC, 0, I1 }, +{"mtc2", "t,G,H", 0x48800000, 0xffe007f8, COD|RD_t|WR_C2|WR_CC, 0, I32 }, +{"mthc2", "t,G", 0x48e00000, 0xffe007ff, COD|RD_t|WR_C2|WR_CC, 0, I33 }, +{"mthc2", "t,G,H", 0x48e00000, 0xffe007f8, COD|RD_t|WR_C2|WR_CC, 0, I33 }, +{"mthc2", "t,i", 0x48e00000, 0xffe00000, COD|RD_t|WR_C2|WR_CC, 0, I33 }, + +/* Coprocessor 3 move/branch operations overlap with MIPS IV COP1X + instructions, so they are here for the latters to take precedence. */ +{"bc3f", "p", 0x4d000000, 0xffff0000, CBD|RD_CC, 0, I1 }, +{"bc3fl", "p", 0x4d020000, 0xffff0000, CBL|RD_CC, 0, I2|T3 }, +{"bc3t", "p", 0x4d010000, 0xffff0000, CBD|RD_CC, 0, I1 }, +{"bc3tl", "p", 0x4d030000, 0xffff0000, CBL|RD_CC, 0, I2|T3 }, +{"cfc3", "t,G", 0x4c400000, 0xffe007ff, LCD|WR_t|RD_C3, 0, I1 }, +{"ctc3", "t,G", 0x4cc00000, 0xffe007ff, COD|RD_t|WR_CC, 0, I1 }, +{"dmfc3", "t,G", 0x4c200000, 0xffe007ff, LCD|WR_t|RD_C3, 0, I3 }, +{"dmtc3", "t,G", 0x4ca00000, 0xffe007ff, COD|RD_t|WR_C3|WR_CC, 0, I3 }, +{"mfc3", "t,G", 0x4c000000, 0xffe007ff, LCD|WR_t|RD_C3, 0, I1 }, +{"mfc3", "t,G,H", 0x4c000000, 0xffe007f8, LCD|WR_t|RD_C3, 0, I32 }, +{"mtc3", "t,G", 0x4c800000, 0xffe007ff, COD|RD_t|WR_C3|WR_CC, 0, I1 }, +{"mtc3", "t,G,H", 0x4c800000, 0xffe007f8, COD|RD_t|WR_C3|WR_CC, 0, I32 }, + + /* Conflicts with the 4650's "mul" instruction. Nobody's using the + 4010 any more, so move this insn out of the way. If the object + format gave us more info, we could do this right. */ +{"addciu", "t,r,j", 0x70000000, 0xfc000000, WR_t|RD_s, 0, L1 }, +/* MIPS DSP ASE */ +{"absq_s.ph", "d,t", 0x7c000252, 0xffe007ff, WR_d|RD_t, 0, D32 }, +{"absq_s.pw", "d,t", 0x7c000456, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"absq_s.qh", "d,t", 0x7c000256, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"absq_s.w", "d,t", 0x7c000452, 0xffe007ff, WR_d|RD_t, 0, D32 }, +{"addq.ph", "d,s,t", 0x7c000290, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"addq.pw", "d,s,t", 0x7c000494, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"addq.qh", "d,s,t", 0x7c000294, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"addq_s.ph", "d,s,t", 0x7c000390, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"addq_s.pw", "d,s,t", 0x7c000594, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"addq_s.qh", "d,s,t", 0x7c000394, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"addq_s.w", "d,s,t", 0x7c000590, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"addsc", "d,s,t", 0x7c000410, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"addu.ob", "d,s,t", 0x7c000014, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"addu.qb", "d,s,t", 0x7c000010, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"addu_s.ob", "d,s,t", 0x7c000114, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"addu_s.qb", "d,s,t", 0x7c000110, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"addwc", "d,s,t", 0x7c000450, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"bitrev", "d,t", 0x7c0006d2, 0xffe007ff, WR_d|RD_t, 0, D32 }, +{"bposge32", "p", 0x041c0000, 0xffff0000, CBD, 0, D32 }, +{"bposge64", "p", 0x041d0000, 0xffff0000, CBD, 0, D64 }, +{"cmp.eq.ph", "s,t", 0x7c000211, 0xfc00ffff, RD_s|RD_t, 0, D32 }, +{"cmp.eq.pw", "s,t", 0x7c000415, 0xfc00ffff, RD_s|RD_t, 0, D64 }, +{"cmp.eq.qh", "s,t", 0x7c000215, 0xfc00ffff, RD_s|RD_t, 0, D64 }, +{"cmpgu.eq.ob", "d,s,t", 0x7c000115, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"cmpgu.eq.qb", "d,s,t", 0x7c000111, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"cmpgu.le.ob", "d,s,t", 0x7c000195, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"cmpgu.le.qb", "d,s,t", 0x7c000191, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"cmpgu.lt.ob", "d,s,t", 0x7c000155, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"cmpgu.lt.qb", "d,s,t", 0x7c000151, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"cmp.le.ph", "s,t", 0x7c000291, 0xfc00ffff, RD_s|RD_t, 0, D32 }, +{"cmp.le.pw", "s,t", 0x7c000495, 0xfc00ffff, RD_s|RD_t, 0, D64 }, +{"cmp.le.qh", "s,t", 0x7c000295, 0xfc00ffff, RD_s|RD_t, 0, D64 }, +{"cmp.lt.ph", "s,t", 0x7c000251, 0xfc00ffff, RD_s|RD_t, 0, D32 }, +{"cmp.lt.pw", "s,t", 0x7c000455, 0xfc00ffff, RD_s|RD_t, 0, D64 }, +{"cmp.lt.qh", "s,t", 0x7c000255, 0xfc00ffff, RD_s|RD_t, 0, D64 }, +{"cmpu.eq.ob", "s,t", 0x7c000015, 0xfc00ffff, RD_s|RD_t, 0, D64 }, +{"cmpu.eq.qb", "s,t", 0x7c000011, 0xfc00ffff, RD_s|RD_t, 0, D32 }, +{"cmpu.le.ob", "s,t", 0x7c000095, 0xfc00ffff, RD_s|RD_t, 0, D64 }, +{"cmpu.le.qb", "s,t", 0x7c000091, 0xfc00ffff, RD_s|RD_t, 0, D32 }, +{"cmpu.lt.ob", "s,t", 0x7c000055, 0xfc00ffff, RD_s|RD_t, 0, D64 }, +{"cmpu.lt.qb", "s,t", 0x7c000051, 0xfc00ffff, RD_s|RD_t, 0, D32 }, +{"dextpdp", "t,7,6", 0x7c0002bc, 0xfc00e7ff, WR_t|RD_a|DSP_VOLA, 0, D64 }, +{"dextpdpv", "t,7,s", 0x7c0002fc, 0xfc00e7ff, WR_t|RD_a|RD_s|DSP_VOLA, 0, D64 }, +{"dextp", "t,7,6", 0x7c0000bc, 0xfc00e7ff, WR_t|RD_a, 0, D64 }, +{"dextpv", "t,7,s", 0x7c0000fc, 0xfc00e7ff, WR_t|RD_a|RD_s, 0, D64 }, +{"dextr.l", "t,7,6", 0x7c00043c, 0xfc00e7ff, WR_t|RD_a, 0, D64 }, +{"dextr_r.l", "t,7,6", 0x7c00053c, 0xfc00e7ff, WR_t|RD_a, 0, D64 }, +{"dextr_rs.l", "t,7,6", 0x7c0005bc, 0xfc00e7ff, WR_t|RD_a, 0, D64 }, +{"dextr_rs.w", "t,7,6", 0x7c0001bc, 0xfc00e7ff, WR_t|RD_a, 0, D64 }, +{"dextr_r.w", "t,7,6", 0x7c00013c, 0xfc00e7ff, WR_t|RD_a, 0, D64 }, +{"dextr_s.h", "t,7,6", 0x7c0003bc, 0xfc00e7ff, WR_t|RD_a, 0, D64 }, +{"dextrv.l", "t,7,s", 0x7c00047c, 0xfc00e7ff, WR_t|RD_a|RD_s, 0, D64 }, +{"dextrv_r.l", "t,7,s", 0x7c00057c, 0xfc00e7ff, WR_t|RD_a|RD_s, 0, D64 }, +{"dextrv_rs.l", "t,7,s", 0x7c0005fc, 0xfc00e7ff, WR_t|RD_a|RD_s, 0, D64 }, +{"dextrv_rs.w", "t,7,s", 0x7c0001fc, 0xfc00e7ff, WR_t|RD_a|RD_s, 0, D64 }, +{"dextrv_r.w", "t,7,s", 0x7c00017c, 0xfc00e7ff, WR_t|RD_a|RD_s, 0, D64 }, +{"dextrv_s.h", "t,7,s", 0x7c0003fc, 0xfc00e7ff, WR_t|RD_a|RD_s, 0, D64 }, +{"dextrv.w", "t,7,s", 0x7c00007c, 0xfc00e7ff, WR_t|RD_a|RD_s, 0, D64 }, +{"dextr.w", "t,7,6", 0x7c00003c, 0xfc00e7ff, WR_t|RD_a, 0, D64 }, +{"dinsv", "t,s", 0x7c00000d, 0xfc00ffff, WR_t|RD_s, 0, D64 }, +{"dmadd", "7,s,t", 0x7c000674, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"dmaddu", "7,s,t", 0x7c000774, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"dmsub", "7,s,t", 0x7c0006f4, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"dmsubu", "7,s,t", 0x7c0007f4, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"dmthlip", "s,7", 0x7c0007fc, 0xfc1fe7ff, RD_s|MOD_a|DSP_VOLA, 0, D64 }, +{"dpaq_sa.l.pw", "7,s,t", 0x7c000334, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"dpaq_sa.l.w", "7,s,t", 0x7c000330, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D32 }, +{"dpaq_s.w.ph", "7,s,t", 0x7c000130, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D32 }, +{"dpaq_s.w.qh", "7,s,t", 0x7c000134, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"dpau.h.obl", "7,s,t", 0x7c0000f4, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"dpau.h.obr", "7,s,t", 0x7c0001f4, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"dpau.h.qbl", "7,s,t", 0x7c0000f0, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D32 }, +{"dpau.h.qbr", "7,s,t", 0x7c0001f0, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D32 }, +{"dpsq_sa.l.pw", "7,s,t", 0x7c000374, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"dpsq_sa.l.w", "7,s,t", 0x7c000370, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D32 }, +{"dpsq_s.w.ph", "7,s,t", 0x7c000170, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D32 }, +{"dpsq_s.w.qh", "7,s,t", 0x7c000174, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"dpsu.h.obl", "7,s,t", 0x7c0002f4, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"dpsu.h.obr", "7,s,t", 0x7c0003f4, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"dpsu.h.qbl", "7,s,t", 0x7c0002f0, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D32 }, +{"dpsu.h.qbr", "7,s,t", 0x7c0003f0, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D32 }, +{"dshilo", "7,:", 0x7c0006bc, 0xfc07e7ff, MOD_a, 0, D64 }, +{"dshilov", "7,s", 0x7c0006fc, 0xfc1fe7ff, MOD_a|RD_s, 0, D64 }, +{"extpdp", "t,7,6", 0x7c0002b8, 0xfc00e7ff, WR_t|RD_a|DSP_VOLA, 0, D32 }, +{"extpdpv", "t,7,s", 0x7c0002f8, 0xfc00e7ff, WR_t|RD_a|RD_s|DSP_VOLA, 0, D32 }, +{"extp", "t,7,6", 0x7c0000b8, 0xfc00e7ff, WR_t|RD_a, 0, D32 }, +{"extpv", "t,7,s", 0x7c0000f8, 0xfc00e7ff, WR_t|RD_a|RD_s, 0, D32 }, +{"extr_rs.w", "t,7,6", 0x7c0001b8, 0xfc00e7ff, WR_t|RD_a, 0, D32 }, +{"extr_r.w", "t,7,6", 0x7c000138, 0xfc00e7ff, WR_t|RD_a, 0, D32 }, +{"extr_s.h", "t,7,6", 0x7c0003b8, 0xfc00e7ff, WR_t|RD_a, 0, D32 }, +{"extrv_rs.w", "t,7,s", 0x7c0001f8, 0xfc00e7ff, WR_t|RD_a|RD_s, 0, D32 }, +{"extrv_r.w", "t,7,s", 0x7c000178, 0xfc00e7ff, WR_t|RD_a|RD_s, 0, D32 }, +{"extrv_s.h", "t,7,s", 0x7c0003f8, 0xfc00e7ff, WR_t|RD_a|RD_s, 0, D32 }, +{"extrv.w", "t,7,s", 0x7c000078, 0xfc00e7ff, WR_t|RD_a|RD_s, 0, D32 }, +{"extr.w", "t,7,6", 0x7c000038, 0xfc00e7ff, WR_t|RD_a, 0, D32 }, +{"insv", "t,s", 0x7c00000c, 0xfc00ffff, WR_t|RD_s, 0, D32 }, +{"lbux", "d,t(b)", 0x7c00018a, 0xfc0007ff, LDD|WR_d|RD_t|RD_b, 0, D32 }, +{"ldx", "d,t(b)", 0x7c00020a, 0xfc0007ff, LDD|WR_d|RD_t|RD_b, 0, D64 }, +{"lhx", "d,t(b)", 0x7c00010a, 0xfc0007ff, LDD|WR_d|RD_t|RD_b, 0, D32 }, +{"lwx", "d,t(b)", 0x7c00000a, 0xfc0007ff, LDD|WR_d|RD_t|RD_b, 0, D32 }, +{"maq_sa.w.phl", "7,s,t", 0x7c000430, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D32 }, +{"maq_sa.w.phr", "7,s,t", 0x7c0004b0, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D32 }, +{"maq_sa.w.qhll", "7,s,t", 0x7c000434, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"maq_sa.w.qhlr", "7,s,t", 0x7c000474, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"maq_sa.w.qhrl", "7,s,t", 0x7c0004b4, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"maq_sa.w.qhrr", "7,s,t", 0x7c0004f4, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"maq_s.l.pwl", "7,s,t", 0x7c000734, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"maq_s.l.pwr", "7,s,t", 0x7c0007b4, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"maq_s.w.phl", "7,s,t", 0x7c000530, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D32 }, +{"maq_s.w.phr", "7,s,t", 0x7c0005b0, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D32 }, +{"maq_s.w.qhll", "7,s,t", 0x7c000534, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"maq_s.w.qhlr", "7,s,t", 0x7c000574, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"maq_s.w.qhrl", "7,s,t", 0x7c0005b4, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"maq_s.w.qhrr", "7,s,t", 0x7c0005f4, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"modsub", "d,s,t", 0x7c000490, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"mthlip", "s,7", 0x7c0007f8, 0xfc1fe7ff, RD_s|MOD_a|DSP_VOLA, 0, D32 }, +{"muleq_s.pw.qhl", "d,s,t", 0x7c000714, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0, D64 }, +{"muleq_s.pw.qhr", "d,s,t", 0x7c000754, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0, D64 }, +{"muleq_s.w.phl", "d,s,t", 0x7c000710, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0, D32 }, +{"muleq_s.w.phr", "d,s,t", 0x7c000750, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0, D32 }, +{"muleu_s.ph.qbl", "d,s,t", 0x7c000190, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0, D32 }, +{"muleu_s.ph.qbr", "d,s,t", 0x7c0001d0, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0, D32 }, +{"muleu_s.qh.obl", "d,s,t", 0x7c000194, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0, D64 }, +{"muleu_s.qh.obr", "d,s,t", 0x7c0001d4, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0, D64 }, +{"mulq_rs.ph", "d,s,t", 0x7c0007d0, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0, D32 }, +{"mulq_rs.qh", "d,s,t", 0x7c0007d4, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0, D64 }, +{"mulsaq_s.l.pw", "7,s,t", 0x7c0003b4, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"mulsaq_s.w.ph", "7,s,t", 0x7c0001b0, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D32 }, +{"mulsaq_s.w.qh", "7,s,t", 0x7c0001b4, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"packrl.ph", "d,s,t", 0x7c000391, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"packrl.pw", "d,s,t", 0x7c000395, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"pick.ob", "d,s,t", 0x7c0000d5, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"pick.ph", "d,s,t", 0x7c0002d1, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"pick.pw", "d,s,t", 0x7c0004d5, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"pick.qb", "d,s,t", 0x7c0000d1, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"pick.qh", "d,s,t", 0x7c0002d5, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"preceq.pw.qhla", "d,t", 0x7c000396, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"preceq.pw.qhl", "d,t", 0x7c000316, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"preceq.pw.qhra", "d,t", 0x7c0003d6, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"preceq.pw.qhr", "d,t", 0x7c000356, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"preceq.s.l.pwl", "d,t", 0x7c000516, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"preceq.s.l.pwr", "d,t", 0x7c000556, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"precequ.ph.qbla", "d,t", 0x7c000192, 0xffe007ff, WR_d|RD_t, 0, D32 }, +{"precequ.ph.qbl", "d,t", 0x7c000112, 0xffe007ff, WR_d|RD_t, 0, D32 }, +{"precequ.ph.qbra", "d,t", 0x7c0001d2, 0xffe007ff, WR_d|RD_t, 0, D32 }, +{"precequ.ph.qbr", "d,t", 0x7c000152, 0xffe007ff, WR_d|RD_t, 0, D32 }, +{"precequ.pw.qhla", "d,t", 0x7c000196, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"precequ.pw.qhl", "d,t", 0x7c000116, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"precequ.pw.qhra", "d,t", 0x7c0001d6, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"precequ.pw.qhr", "d,t", 0x7c000156, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"preceq.w.phl", "d,t", 0x7c000312, 0xffe007ff, WR_d|RD_t, 0, D32 }, +{"preceq.w.phr", "d,t", 0x7c000352, 0xffe007ff, WR_d|RD_t, 0, D32 }, +{"preceu.ph.qbla", "d,t", 0x7c000792, 0xffe007ff, WR_d|RD_t, 0, D32 }, +{"preceu.ph.qbl", "d,t", 0x7c000712, 0xffe007ff, WR_d|RD_t, 0, D32 }, +{"preceu.ph.qbra", "d,t", 0x7c0007d2, 0xffe007ff, WR_d|RD_t, 0, D32 }, +{"preceu.ph.qbr", "d,t", 0x7c000752, 0xffe007ff, WR_d|RD_t, 0, D32 }, +{"preceu.qh.obla", "d,t", 0x7c000796, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"preceu.qh.obl", "d,t", 0x7c000716, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"preceu.qh.obra", "d,t", 0x7c0007d6, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"preceu.qh.obr", "d,t", 0x7c000756, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"precrq.ob.qh", "d,s,t", 0x7c000315, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"precrq.ph.w", "d,s,t", 0x7c000511, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"precrq.pw.l", "d,s,t", 0x7c000715, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"precrq.qb.ph", "d,s,t", 0x7c000311, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"precrq.qh.pw", "d,s,t", 0x7c000515, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"precrq_rs.ph.w", "d,s,t", 0x7c000551, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"precrq_rs.qh.pw", "d,s,t", 0x7c000555, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"precrqu_s.ob.qh", "d,s,t", 0x7c0003d5, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"precrqu_s.qb.ph", "d,s,t", 0x7c0003d1, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"raddu.l.ob", "d,s", 0x7c000514, 0xfc1f07ff, WR_d|RD_s, 0, D64 }, +{"raddu.w.qb", "d,s", 0x7c000510, 0xfc1f07ff, WR_d|RD_s, 0, D32 }, +{"rddsp", "d", 0x7fff04b8, 0xffff07ff, WR_d, 0, D32 }, +{"rddsp", "d,'", 0x7c0004b8, 0xffc007ff, WR_d, 0, D32 }, +{"repl.ob", "d,5", 0x7c000096, 0xff0007ff, WR_d, 0, D64 }, +{"repl.ph", "d,@", 0x7c000292, 0xfc0007ff, WR_d, 0, D32 }, +{"repl.pw", "d,@", 0x7c000496, 0xfc0007ff, WR_d, 0, D64 }, +{"repl.qb", "d,5", 0x7c000092, 0xff0007ff, WR_d, 0, D32 }, +{"repl.qh", "d,@", 0x7c000296, 0xfc0007ff, WR_d, 0, D64 }, +{"replv.ob", "d,t", 0x7c0000d6, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"replv.ph", "d,t", 0x7c0002d2, 0xffe007ff, WR_d|RD_t, 0, D32 }, +{"replv.pw", "d,t", 0x7c0004d6, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"replv.qb", "d,t", 0x7c0000d2, 0xffe007ff, WR_d|RD_t, 0, D32 }, +{"replv.qh", "d,t", 0x7c0002d6, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"shilo", "7,0", 0x7c0006b8, 0xfc0fe7ff, MOD_a, 0, D32 }, +{"shilov", "7,s", 0x7c0006f8, 0xfc1fe7ff, MOD_a|RD_s, 0, D32 }, +{"shll.ob", "d,t,3", 0x7c000017, 0xff0007ff, WR_d|RD_t, 0, D64 }, +{"shll.ph", "d,t,4", 0x7c000213, 0xfe0007ff, WR_d|RD_t, 0, D32 }, +{"shll.pw", "d,t,6", 0x7c000417, 0xfc0007ff, WR_d|RD_t, 0, D64 }, +{"shll.qb", "d,t,3", 0x7c000013, 0xff0007ff, WR_d|RD_t, 0, D32 }, +{"shll.qh", "d,t,4", 0x7c000217, 0xfe0007ff, WR_d|RD_t, 0, D64 }, +{"shll_s.ph", "d,t,4", 0x7c000313, 0xfe0007ff, WR_d|RD_t, 0, D32 }, +{"shll_s.pw", "d,t,6", 0x7c000517, 0xfc0007ff, WR_d|RD_t, 0, D64 }, +{"shll_s.qh", "d,t,4", 0x7c000317, 0xfe0007ff, WR_d|RD_t, 0, D64 }, +{"shll_s.w", "d,t,6", 0x7c000513, 0xfc0007ff, WR_d|RD_t, 0, D32 }, +{"shllv.ob", "d,t,s", 0x7c000097, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"shllv.ph", "d,t,s", 0x7c000293, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"shllv.pw", "d,t,s", 0x7c000497, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"shllv.qb", "d,t,s", 0x7c000093, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"shllv.qh", "d,t,s", 0x7c000297, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"shllv_s.ph", "d,t,s", 0x7c000393, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"shllv_s.pw", "d,t,s", 0x7c000597, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"shllv_s.qh", "d,t,s", 0x7c000397, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"shllv_s.w", "d,t,s", 0x7c000593, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"shra.ph", "d,t,4", 0x7c000253, 0xfe0007ff, WR_d|RD_t, 0, D32 }, +{"shra.pw", "d,t,6", 0x7c000457, 0xfc0007ff, WR_d|RD_t, 0, D64 }, +{"shra.qh", "d,t,4", 0x7c000257, 0xfe0007ff, WR_d|RD_t, 0, D64 }, +{"shra_r.ph", "d,t,4", 0x7c000353, 0xfe0007ff, WR_d|RD_t, 0, D32 }, +{"shra_r.pw", "d,t,6", 0x7c000557, 0xfc0007ff, WR_d|RD_t, 0, D64 }, +{"shra_r.qh", "d,t,4", 0x7c000357, 0xfe0007ff, WR_d|RD_t, 0, D64 }, +{"shra_r.w", "d,t,6", 0x7c000553, 0xfc0007ff, WR_d|RD_t, 0, D32 }, +{"shrav.ph", "d,t,s", 0x7c0002d3, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"shrav.pw", "d,t,s", 0x7c0004d7, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"shrav.qh", "d,t,s", 0x7c0002d7, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"shrav_r.ph", "d,t,s", 0x7c0003d3, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"shrav_r.pw", "d,t,s", 0x7c0005d7, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"shrav_r.qh", "d,t,s", 0x7c0003d7, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"shrav_r.w", "d,t,s", 0x7c0005d3, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"shrl.ob", "d,t,3", 0x7c000057, 0xff0007ff, WR_d|RD_t, 0, D64 }, +{"shrl.qb", "d,t,3", 0x7c000053, 0xff0007ff, WR_d|RD_t, 0, D32 }, +{"shrlv.ob", "d,t,s", 0x7c0000d7, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"shrlv.qb", "d,t,s", 0x7c0000d3, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"subq.ph", "d,s,t", 0x7c0002d0, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"subq.pw", "d,s,t", 0x7c0004d4, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"subq.qh", "d,s,t", 0x7c0002d4, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"subq_s.ph", "d,s,t", 0x7c0003d0, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"subq_s.pw", "d,s,t", 0x7c0005d4, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"subq_s.qh", "d,s,t", 0x7c0003d4, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"subq_s.w", "d,s,t", 0x7c0005d0, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"subu.ob", "d,s,t", 0x7c000054, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"subu.qb", "d,s,t", 0x7c000050, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"subu_s.ob", "d,s,t", 0x7c000154, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"subu_s.qb", "d,s,t", 0x7c000150, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"wrdsp", "s", 0x7c1ffcf8, 0xfc1fffff, RD_s|DSP_VOLA, 0, D32 }, +{"wrdsp", "s,8", 0x7c0004f8, 0xfc1e07ff, RD_s|DSP_VOLA, 0, D32 }, +/* MIPS DSP ASE Rev2 */ +{"absq_s.qb", "d,t", 0x7c000052, 0xffe007ff, WR_d|RD_t, 0, D33 }, +{"addu.ph", "d,s,t", 0x7c000210, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"addu_s.ph", "d,s,t", 0x7c000310, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"adduh.qb", "d,s,t", 0x7c000018, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"adduh_r.qb", "d,s,t", 0x7c000098, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"append", "t,s,h", 0x7c000031, 0xfc0007ff, WR_t|RD_t|RD_s, 0, D33 }, +{"balign", "t,s,I", 0, (int) M_BALIGN, INSN_MACRO, 0, D33 }, +{"balign", "t,s,2", 0x7c000431, 0xfc00e7ff, WR_t|RD_t|RD_s, 0, D33 }, +{"cmpgdu.eq.qb", "d,s,t", 0x7c000611, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"cmpgdu.lt.qb", "d,s,t", 0x7c000651, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"cmpgdu.le.qb", "d,s,t", 0x7c000691, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"dpa.w.ph", "7,s,t", 0x7c000030, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D33 }, +{"dps.w.ph", "7,s,t", 0x7c000070, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D33 }, +{"mul.ph", "d,s,t", 0x7c000318, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0, D33 }, +{"mul_s.ph", "d,s,t", 0x7c000398, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0, D33 }, +{"mulq_rs.w", "d,s,t", 0x7c0005d8, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0, D33 }, +{"mulq_s.ph", "d,s,t", 0x7c000790, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0, D33 }, +{"mulq_s.w", "d,s,t", 0x7c000598, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0, D33 }, +{"mulsa.w.ph", "7,s,t", 0x7c0000b0, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D33 }, +{"precr.qb.ph", "d,s,t", 0x7c000351, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"precr_sra.ph.w", "t,s,h", 0x7c000791, 0xfc0007ff, WR_t|RD_t|RD_s, 0, D33 }, +{"precr_sra_r.ph.w", "t,s,h", 0x7c0007d1, 0xfc0007ff, WR_t|RD_t|RD_s, 0, D33 }, +{"prepend", "t,s,h", 0x7c000071, 0xfc0007ff, WR_t|RD_t|RD_s, 0, D33 }, +{"shra.qb", "d,t,3", 0x7c000113, 0xff0007ff, WR_d|RD_t, 0, D33 }, +{"shra_r.qb", "d,t,3", 0x7c000153, 0xff0007ff, WR_d|RD_t, 0, D33 }, +{"shrav.qb", "d,t,s", 0x7c000193, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"shrav_r.qb", "d,t,s", 0x7c0001d3, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"shrl.ph", "d,t,4", 0x7c000653, 0xfe0007ff, WR_d|RD_t, 0, D33 }, +{"shrlv.ph", "d,t,s", 0x7c0006d3, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"subu.ph", "d,s,t", 0x7c000250, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"subu_s.ph", "d,s,t", 0x7c000350, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"subuh.qb", "d,s,t", 0x7c000058, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"subuh_r.qb", "d,s,t", 0x7c0000d8, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"addqh.ph", "d,s,t", 0x7c000218, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"addqh_r.ph", "d,s,t", 0x7c000298, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"addqh.w", "d,s,t", 0x7c000418, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"addqh_r.w", "d,s,t", 0x7c000498, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"subqh.ph", "d,s,t", 0x7c000258, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"subqh_r.ph", "d,s,t", 0x7c0002d8, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"subqh.w", "d,s,t", 0x7c000458, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"subqh_r.w", "d,s,t", 0x7c0004d8, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"dpax.w.ph", "7,s,t", 0x7c000230, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D33 }, +{"dpsx.w.ph", "7,s,t", 0x7c000270, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D33 }, +{"dpaqx_s.w.ph", "7,s,t", 0x7c000630, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D33 }, +{"dpaqx_sa.w.ph", "7,s,t", 0x7c0006b0, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D33 }, +{"dpsqx_s.w.ph", "7,s,t", 0x7c000670, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D33 }, +{"dpsqx_sa.w.ph", "7,s,t", 0x7c0006f0, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D33 }, +/* Move bc0* after mftr and mttr to avoid opcode collision. */ +{"bc0f", "p", 0x41000000, 0xffff0000, CBD|RD_CC, 0, I1 }, +{"bc0fl", "p", 0x41020000, 0xffff0000, CBL|RD_CC, 0, I2|T3 }, +{"bc0t", "p", 0x41010000, 0xffff0000, CBD|RD_CC, 0, I1 }, +{"bc0tl", "p", 0x41030000, 0xffff0000, CBL|RD_CC, 0, I2|T3 }, +/* ST Microelectronics Loongson-2E and -2F. */ +{"mult.g", "d,s,t", 0x7c000018, 0xfc0007ff, RD_s|RD_t|WR_d, 0, IL2E }, +{"mult.g", "d,s,t", 0x70000010, 0xfc0007ff, RD_s|RD_t|WR_d, 0, IL2F }, +{"multu.g", "d,s,t", 0x7c000019, 0xfc0007ff, RD_s|RD_t|WR_d, 0, IL2E }, +{"multu.g", "d,s,t", 0x70000012, 0xfc0007ff, RD_s|RD_t|WR_d, 0, IL2F }, +{"dmult.g", "d,s,t", 0x7c00001c, 0xfc0007ff, RD_s|RD_t|WR_d, 0, IL2E }, +{"dmult.g", "d,s,t", 0x70000011, 0xfc0007ff, RD_s|RD_t|WR_d, 0, IL2F }, +{"dmultu.g", "d,s,t", 0x7c00001d, 0xfc0007ff, RD_s|RD_t|WR_d, 0, IL2E }, +{"dmultu.g", "d,s,t", 0x70000013, 0xfc0007ff, RD_s|RD_t|WR_d, 0, IL2F }, +{"div.g", "d,s,t", 0x7c00001a, 0xfc0007ff, RD_s|RD_t|WR_d, 0, IL2E }, +{"div.g", "d,s,t", 0x70000014, 0xfc0007ff, RD_s|RD_t|WR_d, 0, IL2F }, +{"divu.g", "d,s,t", 0x7c00001b, 0xfc0007ff, RD_s|RD_t|WR_d, 0, IL2E }, +{"divu.g", "d,s,t", 0x70000016, 0xfc0007ff, RD_s|RD_t|WR_d, 0, IL2F }, +{"ddiv.g", "d,s,t", 0x7c00001e, 0xfc0007ff, RD_s|RD_t|WR_d, 0, IL2E }, +{"ddiv.g", "d,s,t", 0x70000015, 0xfc0007ff, RD_s|RD_t|WR_d, 0, IL2F }, +{"ddivu.g", "d,s,t", 0x7c00001f, 0xfc0007ff, RD_s|RD_t|WR_d, 0, IL2E }, +{"ddivu.g", "d,s,t", 0x70000017, 0xfc0007ff, RD_s|RD_t|WR_d, 0, IL2F }, +{"mod.g", "d,s,t", 0x7c000022, 0xfc0007ff, RD_s|RD_t|WR_d, 0, IL2E }, +{"mod.g", "d,s,t", 0x7000001c, 0xfc0007ff, RD_s|RD_t|WR_d, 0, IL2F }, +{"modu.g", "d,s,t", 0x7c000023, 0xfc0007ff, RD_s|RD_t|WR_d, 0, IL2E }, +{"modu.g", "d,s,t", 0x7000001e, 0xfc0007ff, RD_s|RD_t|WR_d, 0, IL2F }, +{"dmod.g", "d,s,t", 0x7c000026, 0xfc0007ff, RD_s|RD_t|WR_d, 0, IL2E }, +{"dmod.g", "d,s,t", 0x7000001d, 0xfc0007ff, RD_s|RD_t|WR_d, 0, IL2F }, +{"dmodu.g", "d,s,t", 0x7c000027, 0xfc0007ff, RD_s|RD_t|WR_d, 0, IL2E }, +{"dmodu.g", "d,s,t", 0x7000001f, 0xfc0007ff, RD_s|RD_t|WR_d, 0, IL2F }, +{"packsshb", "D,S,T", 0x47400002, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2E }, +{"packsshb", "D,S,T", 0x4b400002, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2F }, +{"packsswh", "D,S,T", 0x47200002, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2E }, +{"packsswh", "D,S,T", 0x4b200002, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2F }, +{"packushb", "D,S,T", 0x47600002, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2E }, +{"packushb", "D,S,T", 0x4b600002, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2F }, +{"paddb", "D,S,T", 0x47c00000, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2E }, +{"paddb", "D,S,T", 0x4bc00000, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2F }, +{"paddh", "D,S,T", 0x47400000, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2E }, +{"paddh", "D,S,T", 0x4b400000, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2F }, +{"paddw", "D,S,T", 0x47600000, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2E }, +{"paddw", "D,S,T", 0x4b600000, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2F }, +{"paddd", "D,S,T", 0x47e00000, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2E }, +{"paddd", "D,S,T", 0x4be00000, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2F }, +{"paddsb", "D,S,T", 0x47800000, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2E }, +{"paddsb", "D,S,T", 0x4b800000, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2F }, +{"paddsh", "D,S,T", 0x47000000, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2E }, +{"paddsh", "D,S,T", 0x4b000000, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2F }, +{"paddusb", "D,S,T", 0x47a00000, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2E }, +{"paddusb", "D,S,T", 0x4ba00000, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2F }, +{"paddush", "D,S,T", 0x47200000, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2E }, +{"paddush", "D,S,T", 0x4b200000, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2F }, +{"pandn", "D,S,T", 0x47e00002, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2E }, +{"pandn", "D,S,T", 0x4be00002, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2F }, +{"pavgb", "D,S,T", 0x46600000, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2E }, +{"pavgb", "D,S,T", 0x4b200008, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2F }, +{"pavgh", "D,S,T", 0x46400000, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2E }, +{"pavgh", "D,S,T", 0x4b000008, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2F }, +{"pcmpeqb", "D,S,T", 0x46c00001, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2E }, +{"pcmpeqb", "D,S,T", 0x4b800009, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2F }, +{"pcmpeqh", "D,S,T", 0x46800001, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2E }, +{"pcmpeqh", "D,S,T", 0x4b400009, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2F }, +{"pcmpeqw", "D,S,T", 0x46400001, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2E }, +{"pcmpeqw", "D,S,T", 0x4b000009, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2F }, +{"pcmpgtb", "D,S,T", 0x46e00001, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2E }, +{"pcmpgtb", "D,S,T", 0x4ba00009, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2F }, +{"pcmpgth", "D,S,T", 0x46a00001, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2E }, +{"pcmpgth", "D,S,T", 0x4b600009, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2F }, +{"pcmpgtw", "D,S,T", 0x46600001, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2E }, +{"pcmpgtw", "D,S,T", 0x4b200009, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2F }, +{"pextrh", "D,S,T", 0x45c00002, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2E }, +{"pextrh", "D,S,T", 0x4b40000e, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2F }, +{"pinsrh_0", "D,S,T", 0x47800003, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2E }, +{"pinsrh_0", "D,S,T", 0x4b800003, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2F }, +{"pinsrh_1", "D,S,T", 0x47a00003, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2E }, +{"pinsrh_1", "D,S,T", 0x4ba00003, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2F }, +{"pinsrh_2", "D,S,T", 0x47c00003, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2E }, +{"pinsrh_2", "D,S,T", 0x4bc00003, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2F }, +{"pinsrh_3", "D,S,T", 0x47e00003, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2E }, +{"pinsrh_3", "D,S,T", 0x4be00003, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2F }, +{"pmaddhw", "D,S,T", 0x45e00002, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2E }, +{"pmaddhw", "D,S,T", 0x4b60000e, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2F }, +{"pmaxsh", "D,S,T", 0x46800000, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2E }, +{"pmaxsh", "D,S,T", 0x4b400008, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2F }, +{"pmaxub", "D,S,T", 0x46c00000, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2E }, +{"pmaxub", "D,S,T", 0x4b800008, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2F }, +{"pminsh", "D,S,T", 0x46a00000, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2E }, +{"pminsh", "D,S,T", 0x4b600008, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2F }, +{"pminub", "D,S,T", 0x46e00000, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2E }, +{"pminub", "D,S,T", 0x4ba00008, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2F }, +{"pmovmskb", "D,S", 0x46a00005, 0xffff003f, RD_S|WR_D|FP_D, 0, IL2E }, +{"pmovmskb", "D,S", 0x4ba0000f, 0xffff003f, RD_S|WR_D|FP_D, 0, IL2F }, +{"pmulhuh", "D,S,T", 0x46e00002, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2E }, +{"pmulhuh", "D,S,T", 0x4ba0000a, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2F }, +{"pmulhh", "D,S,T", 0x46a00002, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2E }, +{"pmulhh", "D,S,T", 0x4b60000a, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2F }, +{"pmullh", "D,S,T", 0x46800002, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2E }, +{"pmullh", "D,S,T", 0x4b40000a, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2F }, +{"pmuluw", "D,S,T", 0x46c00002, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2E }, +{"pmuluw", "D,S,T", 0x4b80000a, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2F }, +{"pasubub", "D,S,T", 0x45a00001, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2E }, +{"pasubub", "D,S,T", 0x4b20000d, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2F }, +{"biadd", "D,S", 0x46800005, 0xffff003f, RD_S|WR_D|FP_D, 0, IL2E }, +{"biadd", "D,S", 0x4b80000f, 0xffff003f, RD_S|WR_D|FP_D, 0, IL2F }, +{"pshufh", "D,S,T", 0x47000002, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2E }, +{"pshufh", "D,S,T", 0x4b000002, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2F }, +{"psllh", "D,S,T", 0x46600002, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2E }, +{"psllh", "D,S,T", 0x4b20000a, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2F }, +{"psllw", "D,S,T", 0x46400002, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2E }, +{"psllw", "D,S,T", 0x4b00000a, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2F }, +{"psrah", "D,S,T", 0x46a00003, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2E }, +{"psrah", "D,S,T", 0x4b60000b, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2F }, +{"psraw", "D,S,T", 0x46800003, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2E }, +{"psraw", "D,S,T", 0x4b40000b, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2F }, +{"psrlh", "D,S,T", 0x46600003, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2E }, +{"psrlh", "D,S,T", 0x4b20000b, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2F }, +{"psrlw", "D,S,T", 0x46400003, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2E }, +{"psrlw", "D,S,T", 0x4b00000b, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2F }, +{"psubb", "D,S,T", 0x47c00001, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2E }, +{"psubb", "D,S,T", 0x4bc00001, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2F }, +{"psubh", "D,S,T", 0x47400001, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2E }, +{"psubh", "D,S,T", 0x4b400001, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2F }, +{"psubw", "D,S,T", 0x47600001, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2E }, +{"psubw", "D,S,T", 0x4b600001, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2F }, +{"psubd", "D,S,T", 0x47e00001, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2E }, +{"psubd", "D,S,T", 0x4be00001, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2F }, +{"psubsb", "D,S,T", 0x47800001, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2E }, +{"psubsb", "D,S,T", 0x4b800001, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2F }, +{"psubsh", "D,S,T", 0x47000001, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2E }, +{"psubsh", "D,S,T", 0x4b000001, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2F }, +{"psubusb", "D,S,T", 0x47a00001, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2E }, +{"psubusb", "D,S,T", 0x4ba00001, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2F }, +{"psubush", "D,S,T", 0x47200001, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2E }, +{"psubush", "D,S,T", 0x4b200001, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2F }, +{"punpckhbh", "D,S,T", 0x47600003, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2E }, +{"punpckhbh", "D,S,T", 0x4b600003, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2F }, +{"punpckhhw", "D,S,T", 0x47200003, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2E }, +{"punpckhhw", "D,S,T", 0x4b200003, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2F }, +{"punpckhwd", "D,S,T", 0x46e00003, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2E }, +{"punpckhwd", "D,S,T", 0x4ba0000b, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2F }, +{"punpcklbh", "D,S,T", 0x47400003, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2E }, +{"punpcklbh", "D,S,T", 0x4b400003, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2F }, +{"punpcklhw", "D,S,T", 0x47000003, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2E }, +{"punpcklhw", "D,S,T", 0x4b000003, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2F }, +{"punpcklwd", "D,S,T", 0x46c00003, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2E }, +{"punpcklwd", "D,S,T", 0x4b80000b, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, IL2F }, +{"sequ", "S,T", 0x46800032, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, IL2E }, +{"sequ", "S,T", 0x4b80000c, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, IL2F }, +/* No hazard protection on coprocessor instructions--they shouldn't + change the state of the processor and if they do it's up to the + user to put in nops as necessary. These are at the end so that the + disassembler recognizes more specific versions first. */ +{"c0", "C", 0x42000000, 0xfe000000, CP, 0, I1 }, +{"c1", "C", 0x46000000, 0xfe000000, FP_S, 0, I1 }, +{"c2", "C", 0x4a000000, 0xfe000000, CP, 0, I1 }, +{"c3", "C", 0x4e000000, 0xfe000000, CP, 0, I1 }, +{"cop0", "C", 0, (int) M_COP0, INSN_MACRO, 0, I1 }, +{"cop1", "C", 0, (int) M_COP1, INSN_MACRO, INSN2_M_FP_S, I1 }, +{"cop2", "C", 0, (int) M_COP2, INSN_MACRO, 0, I1 }, +{"cop3", "C", 0, (int) M_COP3, INSN_MACRO, 0, I1 } +}; + +static const int mips_num_opcodes = sizeof (mips_opcodes) / sizeof (mips_opcodes[0]); + +#undef LDD +#undef LCD +#undef UBD +#undef CBD +#undef COD +#undef CLD +#undef CBL +#undef TRAP +#undef SM +#undef WR_d +#undef WR_t +#undef WR_31 +#undef WR_D +#undef WR_T +#undef WR_S +#undef RD_s +#undef RD_b +#undef RD_t +#undef RD_S +#undef RD_T +#undef RD_R +#undef WR_CC +#undef RD_CC +#undef RD_C0 +#undef RD_C1 +#undef RD_C2 +#undef RD_C3 +#undef WR_C0 +#undef WR_C1 +#undef WR_C2 +#undef WR_C3 +#undef CP +#undef WR_HI +#undef RD_HI +#undef MOD_HI +#undef WR_LO +#undef RD_LO +#undef MOD_LO +#undef WR_HILO +#undef RD_HILO +#undef MOD_HILO +#undef IS_M +#undef WR_MACC +#undef RD_MACC +#undef I1 +#undef I2 +#undef I3 +#undef I4 +#undef I5 +#undef I32 +#undef I64 +#undef I33 +#undef I65 +#undef I3_32 +#undef I3_33 +#undef I4_32 +#undef I4_33 +#undef I5_33 +#undef M3D +#undef SMT +#undef MX +#undef IL2E +#undef IL2F +#undef P3 +#undef L1 +#undef V1 +#undef T3 +#undef M1 +#undef SB1 +#undef N411 +#undef N412 +#undef N5 +#undef N54 +#undef N55 +#undef IOCT +#undef XLR +#undef G1 +#undef G2 +#undef G3 +#undef WR_a +#undef RD_a +#undef MOD_a +#undef DSP_VOLA +#undef D32 +#undef D33 +#undef D64 +#undef MT32 diff --git a/tools/virtualmips/mips-opcode.h b/tools/virtualmips/mips-opcode.h new file mode 100644 index 0000000..9ab9bbf --- /dev/null +++ b/tools/virtualmips/mips-opcode.h @@ -0,0 +1,1097 @@ +/* + * Mips opcode list. + * + * Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, + * 2003, 2004, 2005, 2008, 2009, 2010 + * Free Software Foundation, Inc. + * Contributed by Ralph Campbell and OSF + * Commented and modified by Ian Lance Taylor, Cygnus Support + * Adapted for VirtualMIPS by Serge Vakulenko. + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + */ + +#ifndef _MIPS_H_ +#define _MIPS_H_ + +/* These are bit masks and shift counts to use to access the various + fields of an instruction. To retrieve the X field of an + instruction, use the expression + (i >> OP_SH_X) & OP_MASK_X + To set the same field (to j), use + i = (i &~ (OP_MASK_X << OP_SH_X)) | (j << OP_SH_X) + + Make sure you use fields that are appropriate for the instruction, + of course. + + The 'i' format uses OP, RS, RT and IMMEDIATE. + + The 'j' format uses OP and TARGET. + + The 'r' format uses OP, RS, RT, RD, SHAMT and FUNCT. + + The 'b' format uses OP, RS, RT and DELTA. + + The floating point 'i' format uses OP, RS, RT and IMMEDIATE. + + The floating point 'r' format uses OP, FMT, FT, FS, FD and FUNCT. + + A breakpoint instruction uses OP, CODE and SPEC (10 bits of the + breakpoint instruction are not defined; Kane says the breakpoint + code field in BREAK is 20 bits; yet MIPS assemblers and debuggers + only use ten bits). An optional two-operand form of break/sdbbp + allows the lower ten bits to be set too, and MIPS32 and later + architectures allow 20 bits to be set with a signal operand + (using CODE20). + + The syscall instruction uses CODE20. + + The general coprocessor instructions use COPZ. */ + +#define OP_MASK_OP 0x3f +#define OP_SH_OP 26 +#define OP_MASK_RS 0x1f +#define OP_SH_RS 21 +#define OP_MASK_FR 0x1f +#define OP_SH_FR 21 +#define OP_MASK_FMT 0x1f +#define OP_SH_FMT 21 +#define OP_MASK_BCC 0x7 +#define OP_SH_BCC 18 +#define OP_MASK_CODE 0x3ff +#define OP_SH_CODE 16 +#define OP_MASK_CODE2 0x3ff +#define OP_SH_CODE2 6 +#define OP_MASK_RT 0x1f +#define OP_SH_RT 16 +#define OP_MASK_FT 0x1f +#define OP_SH_FT 16 +#define OP_MASK_CACHE 0x1f +#define OP_SH_CACHE 16 +#define OP_MASK_RD 0x1f +#define OP_SH_RD 11 +#define OP_MASK_FS 0x1f +#define OP_SH_FS 11 +#define OP_MASK_PREFX 0x1f +#define OP_SH_PREFX 11 +#define OP_MASK_CCC 0x7 +#define OP_SH_CCC 8 +#define OP_MASK_CODE20 0xfffff /* 20 bit syscall/breakpoint code. */ +#define OP_SH_CODE20 6 +#define OP_MASK_SHAMT 0x1f +#define OP_SH_SHAMT 6 +#define OP_MASK_FD 0x1f +#define OP_SH_FD 6 +#define OP_MASK_TARGET 0x3ffffff +#define OP_SH_TARGET 0 +#define OP_MASK_COPZ 0x1ffffff +#define OP_SH_COPZ 0 +#define OP_MASK_IMMEDIATE 0xffff +#define OP_SH_IMMEDIATE 0 +#define OP_MASK_DELTA 0xffff +#define OP_SH_DELTA 0 +#define OP_MASK_FUNCT 0x3f +#define OP_SH_FUNCT 0 +#define OP_MASK_SPEC 0x3f +#define OP_SH_SPEC 0 +#define OP_SH_LOCC 8 /* FP condition code. */ +#define OP_SH_HICC 18 /* FP condition code. */ +#define OP_MASK_CC 0x7 +#define OP_SH_COP1NORM 25 /* Normal COP1 encoding. */ +#define OP_MASK_COP1NORM 0x1 /* a single bit. */ +#define OP_SH_COP1SPEC 21 /* COP1 encodings. */ +#define OP_MASK_COP1SPEC 0xf +#define OP_MASK_COP1SCLR 0x4 +#define OP_MASK_COP1CMP 0x3 +#define OP_SH_COP1CMP 4 +#define OP_SH_FORMAT 21 /* FP short format field. */ +#define OP_MASK_FORMAT 0x7 +#define OP_SH_TRUE 16 +#define OP_MASK_TRUE 0x1 +#define OP_SH_GE 17 +#define OP_MASK_GE 0x01 +#define OP_SH_UNSIGNED 16 +#define OP_MASK_UNSIGNED 0x1 +#define OP_SH_HINT 16 +#define OP_MASK_HINT 0x1f +#define OP_SH_MMI 0 /* Multimedia (parallel) op. */ +#define OP_MASK_MMI 0x3f +#define OP_SH_MMISUB 6 +#define OP_MASK_MMISUB 0x1f +#define OP_MASK_PERFREG 0x1f /* Performance monitoring. */ +#define OP_SH_PERFREG 1 +#define OP_SH_SEL 0 /* Coprocessor select field. */ +#define OP_MASK_SEL 0x7 /* The sel field of mfcZ and mtcZ. */ +#define OP_SH_CODE19 6 /* 19 bit wait code. */ +#define OP_MASK_CODE19 0x7ffff +#define OP_SH_ALN 21 +#define OP_MASK_ALN 0x7 +#define OP_SH_VSEL 21 +#define OP_MASK_VSEL 0x1f +#define OP_MASK_VECBYTE 0x7 /* Selector field is really 4 bits, + but 0x8-0xf don't select bytes. */ +#define OP_SH_VECBYTE 22 +#define OP_MASK_VECALIGN 0x7 /* Vector byte-align (alni.ob) op. */ +#define OP_SH_VECALIGN 21 +#define OP_MASK_INSMSB 0x1f /* "ins" MSB. */ +#define OP_SH_INSMSB 11 +#define OP_MASK_EXTMSBD 0x1f /* "ext" MSBD. */ +#define OP_SH_EXTMSBD 11 + +/* MIPS DSP ASE */ +#define OP_SH_DSPACC 11 +#define OP_MASK_DSPACC 0x3 +#define OP_SH_DSPACC_S 21 +#define OP_MASK_DSPACC_S 0x3 +#define OP_SH_DSPSFT 20 +#define OP_MASK_DSPSFT 0x3f +#define OP_SH_DSPSFT_7 19 +#define OP_MASK_DSPSFT_7 0x7f +#define OP_SH_SA3 21 +#define OP_MASK_SA3 0x7 +#define OP_SH_SA4 21 +#define OP_MASK_SA4 0xf +#define OP_SH_IMM8 16 +#define OP_MASK_IMM8 0xff +#define OP_SH_IMM10 16 +#define OP_MASK_IMM10 0x3ff +#define OP_SH_WRDSP 11 +#define OP_MASK_WRDSP 0x3f +#define OP_SH_RDDSP 16 +#define OP_MASK_RDDSP 0x3f +#define OP_SH_BP 11 +#define OP_MASK_BP 0x3 + +/* MIPS MT ASE */ +#define OP_SH_MT_U 5 +#define OP_MASK_MT_U 0x1 +#define OP_SH_MT_H 4 +#define OP_MASK_MT_H 0x1 +#define OP_SH_MTACC_T 18 +#define OP_MASK_MTACC_T 0x3 +#define OP_SH_MTACC_D 13 +#define OP_MASK_MTACC_D 0x3 + +#define OP_OP_COP0 0x10 +#define OP_OP_COP1 0x11 +#define OP_OP_COP2 0x12 +#define OP_OP_COP3 0x13 +#define OP_OP_LWC1 0x31 +#define OP_OP_LWC2 0x32 +#define OP_OP_LWC3 0x33 /* a.k.a. pref */ +#define OP_OP_LDC1 0x35 +#define OP_OP_LDC2 0x36 +#define OP_OP_LDC3 0x37 /* a.k.a. ld */ +#define OP_OP_SWC1 0x39 +#define OP_OP_SWC2 0x3a +#define OP_OP_SWC3 0x3b +#define OP_OP_SDC1 0x3d +#define OP_OP_SDC2 0x3e +#define OP_OP_SDC3 0x3f /* a.k.a. sd */ + +/* Values in the 'VSEL' field. */ +#define MDMX_FMTSEL_IMM_QH 0x1d +#define MDMX_FMTSEL_IMM_OB 0x1e +#define MDMX_FMTSEL_VEC_QH 0x15 +#define MDMX_FMTSEL_VEC_OB 0x16 + +/* UDI */ +#define OP_SH_UDI1 6 +#define OP_MASK_UDI1 0x1f +#define OP_SH_UDI2 6 +#define OP_MASK_UDI2 0x3ff +#define OP_SH_UDI3 6 +#define OP_MASK_UDI3 0x7fff +#define OP_SH_UDI4 6 +#define OP_MASK_UDI4 0xfffff + +/* Octeon */ +#define OP_SH_BBITIND 16 +#define OP_MASK_BBITIND 0x1f +#define OP_SH_CINSPOS 6 +#define OP_MASK_CINSPOS 0x1f +#define OP_SH_CINSLM1 11 +#define OP_MASK_CINSLM1 0x1f +#define OP_SH_SEQI 6 +#define OP_MASK_SEQI 0x3ff + +/* This structure holds information for a particular instruction. */ + +struct mips_opcode +{ + /* The name of the instruction. */ + const char *name; + /* A string describing the arguments for this instruction. */ + const char *args; + /* The basic opcode for the instruction. When assembling, this + opcode is modified by the arguments to produce the actual opcode + that is used. If pinfo is INSN_MACRO, then this is 0. */ + unsigned long match; + /* If pinfo is not INSN_MACRO, then this is a bit mask for the + relevant portions of the opcode when disassembling. If the + actual opcode anded with the match field equals the opcode field, + then we have found the correct instruction. If pinfo is + INSN_MACRO, then this field is the macro identifier. */ + unsigned long mask; + /* For a macro, this is INSN_MACRO. Otherwise, it is a collection + of bits describing the instruction, notably any relevant hazard + information. */ + unsigned long pinfo; + /* A collection of additional bits describing the instruction. */ + unsigned long pinfo2; + /* A collection of bits describing the instruction sets of which this + instruction or macro is a member. */ + unsigned long membership; +}; + +/* These are the characters which may appear in the args field of an + instruction. They appear in the order in which the fields appear + when the instruction is used. Commas and parentheses in the args + string are ignored when assembling, and written into the output + when disassembling. + + Each of these characters corresponds to a mask field defined above. + + "1" 5 bit sync type (OP_*_SHAMT) + "<" 5 bit shift amount (OP_*_SHAMT) + ">" shift amount between 32 and 63, stored after subtracting 32 (OP_*_SHAMT) + "a" 26 bit target address (OP_*_TARGET) + "b" 5 bit base register (OP_*_RS) + "c" 10 bit breakpoint code (OP_*_CODE) + "d" 5 bit destination register specifier (OP_*_RD) + "h" 5 bit prefx hint (OP_*_PREFX) + "i" 16 bit unsigned immediate (OP_*_IMMEDIATE) + "j" 16 bit signed immediate (OP_*_DELTA) + "k" 5 bit cache opcode in target register position (OP_*_CACHE) + Also used for immediate operands in vr5400 vector insns. + "o" 16 bit signed offset (OP_*_DELTA) + "p" 16 bit PC relative branch target address (OP_*_DELTA) + "q" 10 bit extra breakpoint code (OP_*_CODE2) + "r" 5 bit same register used as both source and target (OP_*_RS) + "s" 5 bit source register specifier (OP_*_RS) + "t" 5 bit target register (OP_*_RT) + "u" 16 bit upper 16 bits of address (OP_*_IMMEDIATE) + "v" 5 bit same register used as both source and destination (OP_*_RS) + "w" 5 bit same register used as both target and destination (OP_*_RT) + "U" 5 bit same destination register in both OP_*_RD and OP_*_RT + (used by clo and clz) + "C" 25 bit coprocessor function code (OP_*_COPZ) + "B" 20 bit syscall/breakpoint function code (OP_*_CODE20) + "J" 19 bit wait function code (OP_*_CODE19) + "x" accept and ignore register name + "z" must be zero register + "K" 5 bit Hardware Register (rdhwr instruction) (OP_*_RD) + "+A" 5 bit ins/ext/dins/dext/dinsm/dextm position, which becomes + LSB (OP_*_SHAMT). + Enforces: 0 <= pos < 32. + "+B" 5 bit ins/dins size, which becomes MSB (OP_*_INSMSB). + Requires that "+A" or "+E" occur first to set position. + Enforces: 0 < (pos+size) <= 32. + "+C" 5 bit ext/dext size, which becomes MSBD (OP_*_EXTMSBD). + Requires that "+A" or "+E" occur first to set position. + Enforces: 0 < (pos+size) <= 32. + (Also used by "dext" w/ different limits, but limits for + that are checked by the M_DEXT macro.) + "+E" 5 bit dinsu/dextu position, which becomes LSB-32 (OP_*_SHAMT). + Enforces: 32 <= pos < 64. + "+F" 5 bit "dinsm/dinsu" size, which becomes MSB-32 (OP_*_INSMSB). + Requires that "+A" or "+E" occur first to set position. + Enforces: 32 < (pos+size) <= 64. + "+G" 5 bit "dextm" size, which becomes MSBD-32 (OP_*_EXTMSBD). + Requires that "+A" or "+E" occur first to set position. + Enforces: 32 < (pos+size) <= 64. + "+H" 5 bit "dextu" size, which becomes MSBD (OP_*_EXTMSBD). + Requires that "+A" or "+E" occur first to set position. + Enforces: 32 < (pos+size) <= 64. + + Floating point instructions: + "D" 5 bit destination register (OP_*_FD) + "M" 3 bit compare condition code (OP_*_CCC) (only used for mips4 and up) + "N" 3 bit branch condition code (OP_*_BCC) (only used for mips4 and up) + "S" 5 bit fs source 1 register (OP_*_FS) + "T" 5 bit ft source 2 register (OP_*_FT) + "R" 5 bit fr source 3 register (OP_*_FR) + "V" 5 bit same register used as floating source and destination (OP_*_FS) + "W" 5 bit same register used as floating target and destination (OP_*_FT) + + Coprocessor instructions: + "E" 5 bit target register (OP_*_RT) + "G" 5 bit destination register (OP_*_RD) + "H" 3 bit sel field for (d)mtc* and (d)mfc* (OP_*_SEL) + "P" 5 bit performance-monitor register (OP_*_PERFREG) + "e" 5 bit vector register byte specifier (OP_*_VECBYTE) + "%" 3 bit immediate vr5400 vector alignment operand (OP_*_VECALIGN) + see also "k" above + "+D" Combined destination register ("G") and sel ("H") for CP0 ops, + for pretty-printing in disassembly only. + + Macro instructions: + "A" General 32 bit expression + "I" 32 bit immediate (value placed in imm_expr). + "+I" 32 bit immediate (value placed in imm2_expr). + "F" 64 bit floating point constant in .rdata + "L" 64 bit floating point constant in .lit8 + "f" 32 bit floating point constant + "l" 32 bit floating point constant in .lit4 + + MDMX instruction operands (note that while these use the FP register + fields, they accept both $fN and $vN names for the registers): + "O" MDMX alignment offset (OP_*_ALN) + "Q" MDMX vector/scalar/immediate source (OP_*_VSEL and OP_*_FT) + "X" MDMX destination register (OP_*_FD) + "Y" MDMX source register (OP_*_FS) + "Z" MDMX source register (OP_*_FT) + + DSP ASE usage: + "2" 2 bit unsigned immediate for byte align (OP_*_BP) + "3" 3 bit unsigned immediate (OP_*_SA3) + "4" 4 bit unsigned immediate (OP_*_SA4) + "5" 8 bit unsigned immediate (OP_*_IMM8) + "6" 5 bit unsigned immediate (OP_*_RS) + "7" 2 bit dsp accumulator register (OP_*_DSPACC) + "8" 6 bit unsigned immediate (OP_*_WRDSP) + "9" 2 bit dsp accumulator register (OP_*_DSPACC_S) + "0" 6 bit signed immediate (OP_*_DSPSFT) + ":" 7 bit signed immediate (OP_*_DSPSFT_7) + "'" 6 bit unsigned immediate (OP_*_RDDSP) + "@" 10 bit signed immediate (OP_*_IMM10) + + MT ASE usage: + "!" 1 bit usermode flag (OP_*_MT_U) + "$" 1 bit load high flag (OP_*_MT_H) + "*" 2 bit dsp/smartmips accumulator register (OP_*_MTACC_T) + "&" 2 bit dsp/smartmips accumulator register (OP_*_MTACC_D) + "g" 5 bit coprocessor 1 and 2 destination register (OP_*_RD) + "+t" 5 bit coprocessor 0 destination register (OP_*_RT) + "+T" 5 bit coprocessor 0 destination register (OP_*_RT) - disassembly only + + UDI immediates: + "+1" UDI immediate bits 6-10 + "+2" UDI immediate bits 6-15 + "+3" UDI immediate bits 6-20 + "+4" UDI immediate bits 6-25 + + Octeon: + "+x" Bit index field of bbit. Enforces: 0 <= index < 32. + "+X" Bit index field of bbit aliasing bbit32. Matches if 32 <= index < 64, + otherwise skips to next candidate. + "+p" Position field of cins/cins32/exts/exts32. Enforces 0 <= pos < 32. + "+P" Position field of cins/exts aliasing cins32/exts32. Matches if + 32 <= pos < 64, otherwise skips to next candidate. + "+Q" Immediate field of seqi/snei. Enforces -512 <= imm < 512. + "+s" Length-minus-one field of cins/exts. Enforces: 0 <= lenm1 < 32. + "+S" Length-minus-one field of cins32/exts32 or cins/exts aliasing + cint32/exts32. Enforces non-negative value and that + pos + lenm1 < 32 or pos + lenm1 < 64 depending whether previous + position field is "+p" or "+P". + + Other: + "()" parens surrounding optional value + "," separates operands + "[]" brackets around index for vector-op scalar operand specifier (vr5400) + "+" Start of extension sequence. + + Characters used so far, for quick reference when adding more: + "1234567890" + "%[]<>(),+:'@!$*&" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklopqrstuvwxz" + + Extension character sequences used so far ("+" followed by the + following), for quick reference when adding more: + "1234" + "ABCDEFGHIPQSTX" + "pstx" +*/ + +/* These are the bits which may be set in the pinfo field of an + instructions, if it is not equal to INSN_MACRO. */ + +/* Modifies the general purpose register in OP_*_RD. */ +#define INSN_WRITE_GPR_D 0x00000001 +/* Modifies the general purpose register in OP_*_RT. */ +#define INSN_WRITE_GPR_T 0x00000002 +/* Modifies general purpose register 31. */ +#define INSN_WRITE_GPR_31 0x00000004 +/* Modifies the floating point register in OP_*_FD. */ +#define INSN_WRITE_FPR_D 0x00000008 +/* Modifies the floating point register in OP_*_FS. */ +#define INSN_WRITE_FPR_S 0x00000010 +/* Modifies the floating point register in OP_*_FT. */ +#define INSN_WRITE_FPR_T 0x00000020 +/* Reads the general purpose register in OP_*_RS. */ +#define INSN_READ_GPR_S 0x00000040 +/* Reads the general purpose register in OP_*_RT. */ +#define INSN_READ_GPR_T 0x00000080 +/* Reads the floating point register in OP_*_FS. */ +#define INSN_READ_FPR_S 0x00000100 +/* Reads the floating point register in OP_*_FT. */ +#define INSN_READ_FPR_T 0x00000200 +/* Reads the floating point register in OP_*_FR. */ +#define INSN_READ_FPR_R 0x00000400 +/* Modifies coprocessor condition code. */ +#define INSN_WRITE_COND_CODE 0x00000800 +/* Reads coprocessor condition code. */ +#define INSN_READ_COND_CODE 0x00001000 +/* TLB operation. */ +#define INSN_TLB 0x00002000 +/* Reads coprocessor register other than floating point register. */ +#define INSN_COP 0x00004000 +/* Instruction loads value from memory, requiring delay. */ +#define INSN_LOAD_MEMORY_DELAY 0x00008000 +/* Instruction loads value from coprocessor, requiring delay. */ +#define INSN_LOAD_COPROC_DELAY 0x00010000 +/* Instruction has unconditional branch delay slot. */ +#define INSN_UNCOND_BRANCH_DELAY 0x00020000 +/* Instruction has conditional branch delay slot. */ +#define INSN_COND_BRANCH_DELAY 0x00040000 +/* Conditional branch likely: if branch not taken, insn nullified. */ +#define INSN_COND_BRANCH_LIKELY 0x00080000 +/* Moves to coprocessor register, requiring delay. */ +#define INSN_COPROC_MOVE_DELAY 0x00100000 +/* Loads coprocessor register from memory, requiring delay. */ +#define INSN_COPROC_MEMORY_DELAY 0x00200000 +/* Reads the HI register. */ +#define INSN_READ_HI 0x00400000 +/* Reads the LO register. */ +#define INSN_READ_LO 0x00800000 +/* Modifies the HI register. */ +#define INSN_WRITE_HI 0x01000000 +/* Modifies the LO register. */ +#define INSN_WRITE_LO 0x02000000 +/* Takes a trap (easier to keep out of delay slot). */ +#define INSN_TRAP 0x04000000 +/* Instruction stores value into memory. */ +#define INSN_STORE_MEMORY 0x08000000 +/* Instruction uses single precision floating point. */ +#define FP_S 0x10000000 +/* Instruction uses double precision floating point. */ +#define FP_D 0x20000000 +/* Instruction is part of the tx39's integer multiply family. */ +#define INSN_MULT 0x40000000 +/* Instruction synchronize shared memory. */ +#define INSN_SYNC 0x80000000 +/* Instruction is actually a macro. It should be ignored by the + disassembler, and requires special treatment by the assembler. */ +#define INSN_MACRO 0xffffffff + +/* These are the bits which may be set in the pinfo2 field of an + instruction. */ + +/* Instruction is a simple alias (I.E. "move" for daddu/addu/or) */ +#define INSN2_ALIAS 0x00000001 +/* Instruction reads MDMX accumulator. */ +#define INSN2_READ_MDMX_ACC 0x00000002 +/* Instruction writes MDMX accumulator. */ +#define INSN2_WRITE_MDMX_ACC 0x00000004 +/* Macro uses single-precision floating-point instructions. This should + only be set for macros. For instructions, FP_S in pinfo carries the + same information. */ +#define INSN2_M_FP_S 0x00000008 +/* Macro uses double-precision floating-point instructions. This should + only be set for macros. For instructions, FP_D in pinfo carries the + same information. */ +#define INSN2_M_FP_D 0x00000010 + +/* Masks used to mark instructions to indicate which MIPS ISA level + they were introduced in. INSN_ISA_MASK masks an enumeration that + specifies the base ISA level(s). The remainder of a 32-bit + word constructed using these macros is a bitmask of the remaining + INSN_* values below. */ + +#define INSN_ISA_MASK 0x0000000ful + +/* We cannot start at zero due to ISA_UNKNOWN below. */ +#define INSN_ISA1 1 +#define INSN_ISA2 2 +#define INSN_ISA3 3 +#define INSN_ISA4 4 +#define INSN_ISA5 5 +#define INSN_ISA32 6 +#define INSN_ISA32R2 7 +#define INSN_ISA64 8 +#define INSN_ISA64R2 9 +/* Below this point the INSN_* values correspond to combinations of ISAs. + They are only for use in the opcodes table to indicate membership of + a combination of ISAs that cannot be expressed using the usual inclusion + ordering on the above INSN_* values. */ +#define INSN_ISA3_32 10 +#define INSN_ISA3_32R2 11 +#define INSN_ISA4_32 12 +#define INSN_ISA4_32R2 13 +#define INSN_ISA5_32R2 14 + +/* Given INSN_ISA* values X and Y, where X ranges over INSN_ISA1 through + INSN_ISA5_32R2 and Y ranges over INSN_ISA1 through INSN_ISA64R2, + this table describes whether at least one of the ISAs described by X + is/are implemented by ISA Y. (Think of Y as the ISA level supported by + a particular core and X as the ISA level(s) at which a certain instruction + is defined.) The ISA(s) described by X is/are implemented by Y iff + (mips_isa_table[(Y & INSN_ISA_MASK) - 1] >> ((X & INSN_ISA_MASK) - 1)) & 1 + is non-zero. */ +static const unsigned int mips_isa_table[] = + { 0x0001, 0x0003, 0x0607, 0x1e0f, 0x3e1f, 0x0a23, 0x3e63, 0x3ebf, 0x3fff }; + +/* Masks used for Chip specific instructions. */ +#define INSN_CHIP_MASK 0xc3ff0820 + +/* Cavium Networks Octeon instructions. */ +#define INSN_OCTEON 0x00000800 + +/* Masks used for MIPS-defined ASEs. */ +#define INSN_ASE_MASK 0x3c00f000 + +/* DSP ASE */ +#define INSN_DSP 0x00001000 +#define INSN_DSP64 0x00002000 + +/* 0x00004000 is unused. */ + +/* MIPS-3D ASE */ +#define INSN_MIPS3D 0x00008000 + +/* MIPS R4650 instruction. */ +#define INSN_4650 0x00010000 +/* LSI R4010 instruction. */ +#define INSN_4010 0x00020000 +/* NEC VR4100 instruction. */ +#define INSN_4100 0x00040000 +/* Toshiba R3900 instruction. */ +#define INSN_3900 0x00080000 +/* MIPS R10000 instruction. */ +#define INSN_10000 0x00100000 +/* Broadcom SB-1 instruction. */ +#define INSN_SB1 0x00200000 +/* NEC VR4111/VR4181 instruction. */ +#define INSN_4111 0x00400000 +/* NEC VR4120 instruction. */ +#define INSN_4120 0x00800000 +/* NEC VR5400 instruction. */ +#define INSN_5400 0x01000000 +/* NEC VR5500 instruction. */ +#define INSN_5500 0x02000000 + +/* MDMX ASE */ +#define INSN_MDMX 0x04000000 +/* MT ASE */ +#define INSN_MT 0x08000000 +/* SmartMIPS ASE */ +#define INSN_SMARTMIPS 0x10000000 +/* DSP R2 ASE */ +#define INSN_DSPR2 0x20000000 +/* ST Microelectronics Loongson 2E. */ +#define INSN_LOONGSON_2E 0x40000000 +/* ST Microelectronics Loongson 2F. */ +#define INSN_LOONGSON_2F 0x80000000 +/* RMI Xlr instruction */ +#define INSN_XLR 0x00000020 + +/* MIPS ISA defines, use instead of hardcoding ISA level. */ + +#define ISA_UNKNOWN 0 /* Gas internal use. */ +#define ISA_MIPS1 INSN_ISA1 +#define ISA_MIPS2 INSN_ISA2 +#define ISA_MIPS3 INSN_ISA3 +#define ISA_MIPS4 INSN_ISA4 +#define ISA_MIPS5 INSN_ISA5 + +#define ISA_MIPS32 INSN_ISA32 +#define ISA_MIPS64 INSN_ISA64 + +#define ISA_MIPS32R2 INSN_ISA32R2 +#define ISA_MIPS64R2 INSN_ISA64R2 + + +/* CPU defines, use instead of hardcoding processor number. Keep this + in sync with bfd/archures.c in order for machine selection to work. */ +#define CPU_UNKNOWN 0 /* Gas internal use. */ +#define CPU_R3000 3000 +#define CPU_R3900 3900 +#define CPU_R4000 4000 +#define CPU_R4010 4010 +#define CPU_VR4100 4100 +#define CPU_R4111 4111 +#define CPU_VR4120 4120 +#define CPU_R4300 4300 +#define CPU_R4400 4400 +#define CPU_R4600 4600 +#define CPU_R4650 4650 +#define CPU_R5000 5000 +#define CPU_VR5400 5400 +#define CPU_VR5500 5500 +#define CPU_R6000 6000 +#define CPU_RM7000 7000 +#define CPU_R8000 8000 +#define CPU_RM9000 9000 +#define CPU_R10000 10000 +#define CPU_R12000 12000 +#define CPU_R14000 14000 +#define CPU_R16000 16000 +#define CPU_MIPS16 16 +#define CPU_MIPS32 32 +#define CPU_MIPS32R2 33 +#define CPU_MIPS5 5 +#define CPU_MIPS64 64 +#define CPU_MIPS64R2 65 +#define CPU_SB1 12310201 /* octal 'SB', 01. */ +#define CPU_LOONGSON_2E 3001 +#define CPU_LOONGSON_2F 3002 +#define CPU_OCTEON 6501 +#define CPU_XLR 887682 /* decimal 'XLR' */ + +/* Test for membership in an ISA including chip specific ISAs. INSN + is pointer to an element of the opcode table; ISA is the specified + ISA/ASE bitmask to test against; and CPU is the CPU specific ISA to + test, or zero if no CPU specific ISA test is desired. */ + +#define OPCODE_IS_MEMBER(insn, isa, cpu) \ + (((isa & INSN_ISA_MASK) != 0 \ + && ((insn)->membership & INSN_ISA_MASK) != 0 \ + && ((mips_isa_table [(isa & INSN_ISA_MASK) - 1] >> \ + (((insn)->membership & INSN_ISA_MASK) - 1)) & 1) != 0) \ + || ((isa & ~INSN_ISA_MASK) \ + & ((insn)->membership & ~INSN_ISA_MASK)) != 0 \ + || (cpu == CPU_R4650 && ((insn)->membership & INSN_4650) != 0) \ + || (cpu == CPU_RM7000 && ((insn)->membership & INSN_4650) != 0) \ + || (cpu == CPU_RM9000 && ((insn)->membership & INSN_4650) != 0) \ + || (cpu == CPU_R4010 && ((insn)->membership & INSN_4010) != 0) \ + || (cpu == CPU_VR4100 && ((insn)->membership & INSN_4100) != 0) \ + || (cpu == CPU_R3900 && ((insn)->membership & INSN_3900) != 0) \ + || ((cpu == CPU_R10000 || cpu == CPU_R12000 || cpu == CPU_R14000 \ + || cpu == CPU_R16000) \ + && ((insn)->membership & INSN_10000) != 0) \ + || (cpu == CPU_SB1 && ((insn)->membership & INSN_SB1) != 0) \ + || (cpu == CPU_R4111 && ((insn)->membership & INSN_4111) != 0) \ + || (cpu == CPU_VR4120 && ((insn)->membership & INSN_4120) != 0) \ + || (cpu == CPU_VR5400 && ((insn)->membership & INSN_5400) != 0) \ + || (cpu == CPU_VR5500 && ((insn)->membership & INSN_5500) != 0) \ + || (cpu == CPU_LOONGSON_2E \ + && ((insn)->membership & INSN_LOONGSON_2E) != 0) \ + || (cpu == CPU_LOONGSON_2F \ + && ((insn)->membership & INSN_LOONGSON_2F) != 0) \ + || (cpu == CPU_OCTEON \ + && ((insn)->membership & INSN_OCTEON) != 0) \ + || (cpu == CPU_XLR && ((insn)->membership & INSN_XLR) != 0) \ + || 0) /* Please keep this term for easier source merging. */ + +/* This is a list of macro expanded instructions. + + _I appended means immediate + _A appended means address + _AB appended means address with base register + _D appended means 64 bit floating point constant + _S appended means 32 bit floating point constant. */ + +enum +{ + M_ABS, + M_ADD_I, + M_ADDU_I, + M_AND_I, + M_BALIGN, + M_BEQ, + M_BEQ_I, + M_BEQL_I, + M_BGE, + M_BGEL, + M_BGE_I, + M_BGEL_I, + M_BGEU, + M_BGEUL, + M_BGEU_I, + M_BGEUL_I, + M_BGT, + M_BGTL, + M_BGT_I, + M_BGTL_I, + M_BGTU, + M_BGTUL, + M_BGTU_I, + M_BGTUL_I, + M_BLE, + M_BLEL, + M_BLE_I, + M_BLEL_I, + M_BLEU, + M_BLEUL, + M_BLEU_I, + M_BLEUL_I, + M_BLT, + M_BLTL, + M_BLT_I, + M_BLTL_I, + M_BLTU, + M_BLTUL, + M_BLTU_I, + M_BLTUL_I, + M_BNE, + M_BNE_I, + M_BNEL_I, + M_CACHE_AB, + M_DABS, + M_DADD_I, + M_DADDU_I, + M_DDIV_3, + M_DDIV_3I, + M_DDIVU_3, + M_DDIVU_3I, + M_DEXT, + M_DINS, + M_DIV_3, + M_DIV_3I, + M_DIVU_3, + M_DIVU_3I, + M_DLA_AB, + M_DLCA_AB, + M_DLI, + M_DMUL, + M_DMUL_I, + M_DMULO, + M_DMULO_I, + M_DMULOU, + M_DMULOU_I, + M_DREM_3, + M_DREM_3I, + M_DREMU_3, + M_DREMU_3I, + M_DSUB_I, + M_DSUBU_I, + M_DSUBU_I_2, + M_J_A, + M_JAL_1, + M_JAL_2, + M_JAL_A, + M_L_DOB, + M_L_DAB, + M_LA_AB, + M_LB_A, + M_LB_AB, + M_LBU_A, + M_LBU_AB, + M_LCA_AB, + M_LD_A, + M_LD_OB, + M_LD_AB, + M_LDC1_AB, + M_LDC2_AB, + M_LDC3_AB, + M_LDL_AB, + M_LDR_AB, + M_LH_A, + M_LH_AB, + M_LHU_A, + M_LHU_AB, + M_LI, + M_LI_D, + M_LI_DD, + M_LI_S, + M_LI_SS, + M_LL_AB, + M_LLD_AB, + M_LS_A, + M_LW_A, + M_LW_AB, + M_LWC0_A, + M_LWC0_AB, + M_LWC1_A, + M_LWC1_AB, + M_LWC2_A, + M_LWC2_AB, + M_LWC3_A, + M_LWC3_AB, + M_LWL_A, + M_LWL_AB, + M_LWR_A, + M_LWR_AB, + M_LWU_AB, + M_MSGSND, + M_MSGLD, + M_MSGLD_T, + M_MSGWAIT, + M_MSGWAIT_T, + M_MOVE, + M_MUL, + M_MUL_I, + M_MULO, + M_MULO_I, + M_MULOU, + M_MULOU_I, + M_NOR_I, + M_OR_I, + M_REM_3, + M_REM_3I, + M_REMU_3, + M_REMU_3I, + M_DROL, + M_ROL, + M_DROL_I, + M_ROL_I, + M_DROR, + M_ROR, + M_DROR_I, + M_ROR_I, + M_S_DA, + M_S_DOB, + M_S_DAB, + M_S_S, + M_SC_AB, + M_SCD_AB, + M_SD_A, + M_SD_OB, + M_SD_AB, + M_SDC1_AB, + M_SDC2_AB, + M_SDC3_AB, + M_SDL_AB, + M_SDR_AB, + M_SEQ, + M_SEQ_I, + M_SGE, + M_SGE_I, + M_SGEU, + M_SGEU_I, + M_SGT, + M_SGT_I, + M_SGTU, + M_SGTU_I, + M_SLE, + M_SLE_I, + M_SLEU, + M_SLEU_I, + M_SLT_I, + M_SLTU_I, + M_SNE, + M_SNE_I, + M_SB_A, + M_SB_AB, + M_SH_A, + M_SH_AB, + M_SW_A, + M_SW_AB, + M_SWC0_A, + M_SWC0_AB, + M_SWC1_A, + M_SWC1_AB, + M_SWC2_A, + M_SWC2_AB, + M_SWC3_A, + M_SWC3_AB, + M_SWL_A, + M_SWL_AB, + M_SWR_A, + M_SWR_AB, + M_SUB_I, + M_SUBU_I, + M_SUBU_I_2, + M_TEQ_I, + M_TGE_I, + M_TGEU_I, + M_TLT_I, + M_TLTU_I, + M_TNE_I, + M_TRUNCWD, + M_TRUNCWS, + M_ULD, + M_ULD_A, + M_ULH, + M_ULH_A, + M_ULHU, + M_ULHU_A, + M_ULW, + M_ULW_A, + M_USH, + M_USH_A, + M_USW, + M_USW_A, + M_USD, + M_USD_A, + M_XOR_I, + M_COP0, + M_COP1, + M_COP2, + M_COP3, + M_NUM_MACROS +}; + + +/* The order of overloaded instructions matters. Label arguments and + register arguments look the same. Instructions that can have either + for arguments must apear in the correct order in this table for the + assembler to pick the right one. In other words, entries with + immediate operands must apear after the same instruction with + registers. + + Many instructions are short hand for other instructions (i.e., The + jal instruction is short for jalr ). */ + +/* The rest of this file adds definitions for the mips16 TinyRISC + processor. */ + +/* These are the bitmasks and shift counts used for the different + fields in the instruction formats. Other than OP, no masks are + provided for the fixed portions of an instruction, since they are + not needed. + + The I format uses IMM11. + + The RI format uses RX and IMM8. + + The RR format uses RX, and RY. + + The RRI format uses RX, RY, and IMM5. + + The RRR format uses RX, RY, and RZ. + + The RRI_A format uses RX, RY, and IMM4. + + The SHIFT format uses RX, RY, and SHAMT. + + The I8 format uses IMM8. + + The I8_MOVR32 format uses RY and REGR32. + + The IR_MOV32R format uses REG32R and MOV32Z. + + The I64 format uses IMM8. + + The RI64 format uses RY and IMM5. + */ + +#define MIPS16OP_MASK_OP 0x1f +#define MIPS16OP_SH_OP 11 +#define MIPS16OP_MASK_IMM11 0x7ff +#define MIPS16OP_SH_IMM11 0 +#define MIPS16OP_MASK_RX 0x7 +#define MIPS16OP_SH_RX 8 +#define MIPS16OP_MASK_IMM8 0xff +#define MIPS16OP_SH_IMM8 0 +#define MIPS16OP_MASK_RY 0x7 +#define MIPS16OP_SH_RY 5 +#define MIPS16OP_MASK_IMM5 0x1f +#define MIPS16OP_SH_IMM5 0 +#define MIPS16OP_MASK_RZ 0x7 +#define MIPS16OP_SH_RZ 2 +#define MIPS16OP_MASK_IMM4 0xf +#define MIPS16OP_SH_IMM4 0 +#define MIPS16OP_MASK_REGR32 0x1f +#define MIPS16OP_SH_REGR32 0 +#define MIPS16OP_MASK_REG32R 0x1f +#define MIPS16OP_SH_REG32R 3 +#define MIPS16OP_EXTRACT_REG32R(i) ((((i) >> 5) & 7) | ((i) & 0x18)) +#define MIPS16OP_MASK_MOVE32Z 0x7 +#define MIPS16OP_SH_MOVE32Z 0 +#define MIPS16OP_MASK_IMM6 0x3f +#define MIPS16OP_SH_IMM6 5 + +/* These are the characters which may appears in the args field of a MIPS16 + instruction. They appear in the order in which the fields appear when the + instruction is used. Commas and parentheses in the args string are ignored + when assembling, and written into the output when disassembling. + + "y" 3 bit register (MIPS16OP_*_RY) + "x" 3 bit register (MIPS16OP_*_RX) + "z" 3 bit register (MIPS16OP_*_RZ) + "Z" 3 bit register (MIPS16OP_*_MOVE32Z) + "v" 3 bit same register as source and destination (MIPS16OP_*_RX) + "w" 3 bit same register as source and destination (MIPS16OP_*_RY) + "0" zero register ($0) + "S" stack pointer ($sp or $29) + "P" program counter + "R" return address register ($ra or $31) + "X" 5 bit MIPS register (MIPS16OP_*_REGR32) + "Y" 5 bit MIPS register (MIPS16OP_*_REG32R) + "6" 6 bit unsigned break code (MIPS16OP_*_IMM6) + "a" 26 bit jump address + "e" 11 bit extension value + "l" register list for entry instruction + "L" register list for exit instruction + + The remaining codes may be extended. Except as otherwise noted, + the full extended operand is a 16 bit signed value. + "<" 3 bit unsigned shift count * 0 (MIPS16OP_*_RZ) (full 5 bit unsigned) + ">" 3 bit unsigned shift count * 0 (MIPS16OP_*_RX) (full 5 bit unsigned) + "[" 3 bit unsigned shift count * 0 (MIPS16OP_*_RZ) (full 6 bit unsigned) + "]" 3 bit unsigned shift count * 0 (MIPS16OP_*_RX) (full 6 bit unsigned) + "4" 4 bit signed immediate * 0 (MIPS16OP_*_IMM4) (full 15 bit signed) + "5" 5 bit unsigned immediate * 0 (MIPS16OP_*_IMM5) + "H" 5 bit unsigned immediate * 2 (MIPS16OP_*_IMM5) + "W" 5 bit unsigned immediate * 4 (MIPS16OP_*_IMM5) + "D" 5 bit unsigned immediate * 8 (MIPS16OP_*_IMM5) + "j" 5 bit signed immediate * 0 (MIPS16OP_*_IMM5) + "8" 8 bit unsigned immediate * 0 (MIPS16OP_*_IMM8) + "V" 8 bit unsigned immediate * 4 (MIPS16OP_*_IMM8) + "C" 8 bit unsigned immediate * 8 (MIPS16OP_*_IMM8) + "U" 8 bit unsigned immediate * 0 (MIPS16OP_*_IMM8) (full 16 bit unsigned) + "k" 8 bit signed immediate * 0 (MIPS16OP_*_IMM8) + "K" 8 bit signed immediate * 8 (MIPS16OP_*_IMM8) + "p" 8 bit conditional branch address (MIPS16OP_*_IMM8) + "q" 11 bit branch address (MIPS16OP_*_IMM11) + "A" 8 bit PC relative address * 4 (MIPS16OP_*_IMM8) + "B" 5 bit PC relative address * 8 (MIPS16OP_*_IMM5) + "E" 5 bit PC relative address * 4 (MIPS16OP_*_IMM5) + "m" 7 bit register list for save instruction (18 bit extended) + "M" 7 bit register list for restore instruction (18 bit extended) + */ + +/* Save/restore encoding for the args field when all 4 registers are + either saved as arguments or saved/restored as statics. */ +#define MIPS16_ALL_ARGS 0xe +#define MIPS16_ALL_STATICS 0xb + +/* For the mips16, we use the same opcode table format and a few of + the same flags. However, most of the flags are different. */ + +/* Modifies the register in MIPS16OP_*_RX. */ +#define MIPS16_INSN_WRITE_X 0x00000001 +/* Modifies the register in MIPS16OP_*_RY. */ +#define MIPS16_INSN_WRITE_Y 0x00000002 +/* Modifies the register in MIPS16OP_*_RZ. */ +#define MIPS16_INSN_WRITE_Z 0x00000004 +/* Modifies the T ($24) register. */ +#define MIPS16_INSN_WRITE_T 0x00000008 +/* Modifies the SP ($29) register. */ +#define MIPS16_INSN_WRITE_SP 0x00000010 +/* Modifies the RA ($31) register. */ +#define MIPS16_INSN_WRITE_31 0x00000020 +/* Modifies the general purpose register in MIPS16OP_*_REG32R. */ +#define MIPS16_INSN_WRITE_GPR_Y 0x00000040 +/* Reads the register in MIPS16OP_*_RX. */ +#define MIPS16_INSN_READ_X 0x00000080 +/* Reads the register in MIPS16OP_*_RY. */ +#define MIPS16_INSN_READ_Y 0x00000100 +/* Reads the register in MIPS16OP_*_MOVE32Z. */ +#define MIPS16_INSN_READ_Z 0x00000200 +/* Reads the T ($24) register. */ +#define MIPS16_INSN_READ_T 0x00000400 +/* Reads the SP ($29) register. */ +#define MIPS16_INSN_READ_SP 0x00000800 +/* Reads the RA ($31) register. */ +#define MIPS16_INSN_READ_31 0x00001000 +/* Reads the program counter. */ +#define MIPS16_INSN_READ_PC 0x00002000 +/* Reads the general purpose register in MIPS16OP_*_REGR32. */ +#define MIPS16_INSN_READ_GPR_X 0x00004000 +/* Is an unconditional branch insn. */ +#define MIPS16_INSN_UNCOND_BRANCH 0x00008000 +/* Is a conditional branch insn. */ +#define MIPS16_INSN_COND_BRANCH 0x00010000 + +/* The following flags have the same value for the mips16 opcode + table: + INSN_UNCOND_BRANCH_DELAY + INSN_COND_BRANCH_DELAY + INSN_COND_BRANCH_LIKELY (never used) + INSN_READ_HI + INSN_READ_LO + INSN_WRITE_HI + INSN_WRITE_LO + INSN_TRAP + INSN_ISA3 + */ + +/* A NOP insn impemented as "or at,at,zero". + Used to implement -mfix-loongson2f. */ +#define LOONGSON2F_NOP_INSN 0x00200825 + +#endif /* _MIPS_H_ */ diff --git a/tools/virtualmips/mips.c b/tools/virtualmips/mips.c new file mode 100644 index 0000000..bda5b34 --- /dev/null +++ b/tools/virtualmips/mips.c @@ -0,0 +1,603 @@ +/* + * Cisco router simulation platform. + * Copyright (c) 2005,2006 Christophe Fillot (cf@utc.fr) + * + */ + + /* + * Copyright (C) yajin 2008 + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + * + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include + +#include "mips_memory.h" +#include "mips_exec.h" +#include "mips.h" +#include "vm.h" +#include "utils.h" +#include "system.h" +#include "mips_cp0.h" +#include "mips_jit.h" + +#define GDB_SR 32 +#define GDB_LO 33 +#define GDB_HI 34 +#define GDB_BAD 35 +#define GDB_CAUSE 36 +#define GDB_PC 37 + +/* MIPS general purpose registers names */ +char *mips_gpr_reg_names[MIPS64_GPR_NR] = { + "zr", "at", "v0", "v1", "a0", "a1", "a2", "a3", + "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", + "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", + "t8", "t9", "k0", "k1", "gp", "sp", "fp", "ra", +}; + +/* Cacheability and Coherency Attribute */ +static int cca_cache_status[8] = { + 1, 1, 0, 1, 0, 1, 0, 0, +}; + +/* Get register index given its name */ +int mips_get_reg_index (char *name) +{ + int i; + + for (i = 0; i < MIPS64_GPR_NR; i++) + if (!strcmp (mips_gpr_reg_names[i], name)) + return (i); + + return (-1); +} + +/* Get cacheability info */ +int mips_cca_cached (m_uint8_t val) +{ + return (cca_cache_status[val & 0x03]); +} + +/* Set a register */ +void mips_reg_set (cpu_mips_t * cpu, u_int reg, m_reg_t val) +{ + if (reg == 0 || reg >= MIPS64_GPR_NR) + return; + cpu->gpr[reg] = val; + + if (cpu->vm->debug_level > 2 || (cpu->vm->debug_level > 1 && + (cpu->cp0.reg[MIPS_CP0_STATUS] & MIPS_CP0_STATUS_UM) && + ! (cpu->cp0.reg[MIPS_CP0_STATUS] & MIPS_CP0_STATUS_EXL))) + { + /* Print GPR values in user mode. */ + printf (" $%d := %08x \n", reg, val); + } +} + +/*get register value giving index. For GDB*/ +int mips_reg_get (cpu_mips_t * cpu, u_int reg, m_reg_t * val) +{ + if (reg < MIPS64_GPR_NR) { + *val = cpu->gpr[reg]; + return SUCCESS; + } else { + switch (reg) { + case GDB_SR: + *val = cpu->cp0.reg[MIPS_CP0_STATUS]; + break; + case GDB_LO: + *val = cpu->lo; + break; + case GDB_HI: + *val = cpu->hi; + break; + case GDB_BAD: + *val = cpu->cp0.reg[MIPS_CP0_BADVADDR]; + break; + case GDB_CAUSE: + *val = cpu->cp0.reg[MIPS_CP0_CAUSE]; + break; + case GDB_PC: + *val = cpu->pc; + break; + default: + return FAILURE; + } + + } + + return SUCCESS; + +} + +/* Delete a MIPS64 processor */ +void mips_delete (cpu_mips_t * cpu) +{ + if (cpu) { + mips_mem_shutdown (cpu); + } +} + +/* Reset a MIPS64 CPU */ +int mips_reset (cpu_mips_t * cpu) +{ + cpu->cp0.reg[MIPS_CP0_STATUS] = MIPS_CP0_STATUS_BEV; + cpu->cp0.reg[MIPS_CP0_CAUSE] = 0; + cpu->cp0.ebase_reg = 0x80000000; + + /* Clear the complete TLB */ + memset (&cpu->cp0.tlb, 0, MIPS64_TLB_MAX_ENTRIES * sizeof (tlb_entry_t)); + + /* Restart the MTS subsystem */ + mips_set_addr_mode (cpu, 32 /*64 */ ); /* zzz */ + cpu->mts_rebuild (cpu); + + /* Flush JIT structures */ + //mips_jit_flush(cpu,0); + return (0); +} + +/* Initialize a MIPS64 processor */ +int mips_init (cpu_mips_t * cpu) +{ + /* Set the CPU methods */ + cpu->reg_get = (void *) mips_reg_get; + cpu->reg_set = (void *) mips_reg_set; + + /* Set the startup parameters */ + mips_reset (cpu); + return (0); +} + +/* Load an ELF image into the simulated memory. Using libelf*/ +int mips_load_elf_image (cpu_mips_t * cpu, char *filename, + m_va_t * entry_point) +{ + m_va_t vaddr; + m_uint32_t remain; + void *haddr; + Elf32_Ehdr *ehdr; + Elf32_Shdr *shdr; + Elf_Scn *scn; + Elf *img_elf; + size_t len, clen; + int i, fd; + FILE *bfd; + + if (! filename) + return (-1); + +#ifdef __CYGWIN__ + fd = open (filename, O_RDONLY | O_BINARY); +#else + fd = open (filename, O_RDONLY); +#endif + printf ("Loading ELF file '%s'...\n", filename); + if (fd == -1) { + perror ("load_elf_image: open"); + return (-1); + } + + if (elf_version (EV_CURRENT) == EV_NONE) { + fprintf (stderr, "load_elf_image: library out of date\n"); + return (-1); + } + + if (!(img_elf = elf_begin (fd, ELF_C_READ, NULL))) { + fprintf (stderr, "load_elf_image: elf_begin: %s\n", + elf_errmsg (elf_errno ())); + return (-1); + } + + if (!(ehdr = elf32_getehdr (img_elf))) { + fprintf (stderr, "load_elf_image: invalid ELF file\n"); + return (-1); + } + + bfd = fdopen (fd, "rb"); + + if (!bfd) { + perror ("load_elf_image: fdopen"); + return (-1); + } +// if (!skip_load) { + for (i = 0; i < ehdr->e_shnum; i++) { + scn = elf_getscn (img_elf, i); + + shdr = elf32_getshdr (scn); + len = shdr->sh_size; + + if (!(shdr->sh_flags & SHF_ALLOC) || !len) + continue; + + fseek (bfd, shdr->sh_offset, SEEK_SET); + vaddr = sign_extend (shdr->sh_addr, 32); + + if (cpu->vm->debug_level > 0) { + printf (" * Adding section at virtual address 0x%8.8" LL "x " + "(len=0x%8.8lx)\n", vaddr & 0xFFFFFFFF, (u_long) len); + } + + while (len > 0) { + haddr = cpu->mem_op_lookup (cpu, vaddr); + + if (!haddr) { + fprintf (stderr, + "load_elf_image: invalid load address 0x%" LL "x\n", + vaddr); + return (-1); + } + + if (len > MIPS_MIN_PAGE_SIZE) + clen = MIPS_MIN_PAGE_SIZE; + else + clen = len; + + remain = MIPS_MIN_PAGE_SIZE; + remain -= (vaddr - (vaddr & MIPS_MIN_PAGE_SIZE)); + + clen = m_min (clen, remain); + + if (fread ((u_char *) haddr, clen, 1, bfd) < 1) + break; + + vaddr += clen; + len -= clen; + } + } + + printf ("ELF entry point: 0x%x\n", ehdr->e_entry); + + if (entry_point) + *entry_point = ehdr->e_entry; + + elf_end (img_elf); + fclose (bfd); + return (0); +} + +/* Update the IRQ flag (inline) */ +static forced_inline fastcall int mips_update_irq_flag_fast (cpu_mips_t * + cpu) +{ + mips_cp0_t *cp0 = &cpu->cp0; + m_uint32_t cause; + cpu->irq_pending = FALSE; + + cause = cp0->reg[MIPS_CP0_CAUSE] & ~MIPS_CP0_CAUSE_IMASK; + cp0->reg[MIPS_CP0_CAUSE] = cause | cpu->irq_cause; + +/*printf ("(%08x-%08x) ", cpu->pc, cp0->reg[MIPS_CP0_STATUS]); fflush (stdout);*/ + if ((cp0->reg[MIPS_CP0_STATUS] & (MIPS_CP0_STATUS_IE | + MIPS_CP0_STATUS_EXL | MIPS_CP0_STATUS_ERL)) == MIPS_CP0_STATUS_IE) { +#ifdef SIM_PIC32 + m_uint32_t current_ipl = cp0->reg[MIPS_CP0_STATUS] >> 10 & 63; + m_uint32_t requested_ipl = cp0->reg[MIPS_CP0_CAUSE] >> 10 & 63; +/*printf ("(%d-%d) ", requested_ipl, current_ipl); fflush (stdout);*/ + if (unlikely (requested_ipl > current_ipl)) { + cpu->irq_pending = TRUE; + return (TRUE); + } +#else + m_uint32_t imask = cp0->reg[MIPS_CP0_STATUS] & MIPS_CP0_STATUS_IMASK; + if (unlikely (cp0->reg[MIPS_CP0_CAUSE] & imask)) { + cpu->irq_pending = TRUE; + return (TRUE); + } +#endif + } + return (FALSE); +} + +/* Update the IRQ flag */ +int fastcall mips_update_irq_flag (cpu_mips_t * cpu) +{ + return mips_update_irq_flag_fast (cpu); +} + +#if SIM_PIC32 +static void print_arg (val) { + if (val & 0xff000000) + printf ("%08x", val); + else + printf ("%u", val); +} + +static void print_args (narg, arg0, arg1, arg2, arg3, arg4, arg5) +{ + print_arg (arg0); + if (narg > 1) { printf (", "); print_arg (arg1); } + if (narg > 2) { printf (", "); print_arg (arg2); } + if (narg > 3) { printf (", "); print_arg (arg3); } + if (narg > 4) { printf (", "); print_arg (arg4); } + if (narg > 5) { printf (", "); print_arg (arg5); } +} + +/* + * Print trace information for exception. + * For syscalls, display name and arguments. + */ +static void print_exception (cpu_mips_t * cpu, u_int exc_code) +{ + const char *code = 0; +#include "bsd_syscalls.h" + + if (exc_code == MIPS_CP0_CAUSE_SYSCALL) { + mips_insn_t code; + + if (mips_fetch_instruction (cpu, cpu->pc, &code) != 0) { + printf ("--- syscall at %08x: cannot fetch instruction opcode\n", cpu->pc); + return; + } + /* bottom 8 bits are index */ + code = (code >> 6) & 0377; +if (code == 97) cpu->vm->debug_level = 2; +if (code == 1) cpu->vm->debug_level = 1; + cpu->trace_syscall = code; + if (code >= sizeof (bsd_syscalls) / sizeof (bsd_syscalls[0])) { + printf ("--- syscall: #%d at %08x\n", (int)code, cpu->pc); + return; + } + printf ("--- syscall: %s (", bsd_syscalls[code].name); + if (bsd_syscalls[code].narg > 0) { + m_reg_t arg4 = 0, arg5 = 0; + void *haddr; + u_int exc; + m_uint8_t has_set_value; + + if (bsd_syscalls[code].narg >= 4) { + has_set_value = FALSE; + haddr = mips_mts32_access (cpu, cpu->gpr[MIPS_GPR_SP] + 16, + MIPS_MEMOP_LW, 4, MTS_READ, &arg4, &exc, &has_set_value, 0); + if (exc || (! haddr && ! has_set_value)) + arg4 = 0; + else if (! has_set_value) + arg4 = vmtoh32 (*(m_uint32_t *) haddr); + } + if (bsd_syscalls[code].narg >= 5) { + has_set_value = FALSE; + haddr = mips_mts32_access (cpu, cpu->gpr[MIPS_GPR_SP] + 20, + MIPS_MEMOP_LW, 4, MTS_READ, &arg5, &exc, &has_set_value, 0); + if (exc || (! haddr && ! has_set_value)) + arg5 = 0; + else if (! has_set_value) + arg5 = vmtoh32 (*(m_uint32_t *) haddr); + } + print_args (bsd_syscalls[code].narg, + cpu->gpr[MIPS_GPR_A0], cpu->gpr[MIPS_GPR_A1], + cpu->gpr[MIPS_GPR_A2], cpu->gpr[MIPS_GPR_A3], arg4, arg5); + } + printf (") at %08x\n", cpu->pc); + return; + } + printf ("\n*** 0x%08x: exception ", cpu->pc); + + switch (exc_code) { + case MIPS_CP0_CAUSE_INTERRUPT: code = "Interrupt"; break; + case MIPS_CP0_CAUSE_ADDR_LOAD: code = "Address Load"; break; + case MIPS_CP0_CAUSE_ADDR_SAVE: code = "Address Save"; break; + case MIPS_CP0_CAUSE_BUS_INSTR: code = "Bus fetch"; break; + case MIPS_CP0_CAUSE_BUS_DATA: code = "Bus load/store"; break; + case MIPS_CP0_CAUSE_SYSCALL: code = "Syscall"; break; + case MIPS_CP0_CAUSE_BP: code = "Breakpoint"; break; + case MIPS_CP0_CAUSE_ILLOP: code = "Reserved Instruction"; break; + case MIPS_CP0_CAUSE_CP_UNUSABLE:code = "Coprocessor Unusable"; break; + case MIPS_CP0_CAUSE_OVFLW: code = "Arithmetic Overflow"; break; + case MIPS_CP0_CAUSE_TRAP: code = "Trap"; break; + } + if (code) + printf ("'%s'\n", code); + else + printf ("%d\n", exc_code); + + switch (exc_code) { + case MIPS_CP0_CAUSE_ADDR_LOAD: + case MIPS_CP0_CAUSE_ADDR_SAVE: + printf ("*** badvaddr = 0x%08x\n", cpu->cp0.reg[MIPS_CP0_BADVADDR]); + break; + } + printf (" t0 = %8x s0 = %8x t8 = %8x lo = %8x\n", + cpu->gpr[8], cpu->gpr[16], cpu->gpr[24], cpu->lo); + printf ("at = %8x t1 = %8x s1 = %8x t9 = %8x hi = %8x\n", + cpu->gpr[1], cpu->gpr[9], cpu->gpr[17], cpu->gpr[25], cpu->hi); + printf ("v0 = %8x t2 = %8x s2 = %8x status = %8x\n", + cpu->gpr[2], cpu->gpr[10], cpu->gpr[18], cpu->cp0.reg[MIPS_CP0_STATUS]); + printf ("v1 = %8x t3 = %8x s3 = %8x cause = %8x\n", + cpu->gpr[3], cpu->gpr[11],cpu->gpr[19], cpu->cp0.reg[MIPS_CP0_CAUSE]); + printf ("a0 = %8x t4 = %8x s4 = %8x gp = %8x epc = %8x\n", + cpu->gpr[4], cpu->gpr[12], cpu->gpr[20], cpu->gpr[MIPS_GPR_GP], cpu->pc); + printf ("a1 = %8x t5 = %8x s5 = %8x sp = %8x\n", + cpu->gpr[5], cpu->gpr[13], cpu->gpr[21], cpu->gpr[MIPS_GPR_SP]); + printf ("a2 = %8x t6 = %8x s6 = %8x fp = %8x\n", + cpu->gpr[6], cpu->gpr[14], cpu->gpr[22], cpu->gpr[MIPS_GPR_FP]); + printf ("a3 = %8x t7 = %8x s7 = %8x ra = %8x\n", + cpu->gpr[7], cpu->gpr[15], cpu->gpr[23], cpu->gpr[MIPS_GPR_RA]); +} +#endif + +/* Generate an exception */ +void mips_trigger_exception (cpu_mips_t * cpu, u_int exc_code, int bd_slot) +{ + mips_cp0_t *cp0 = &cpu->cp0; + m_uint64_t new_pc; + m_reg_t cause; + + /* keep IM, set exception code and bd slot */ + cause = cp0->reg[MIPS_CP0_CAUSE]; + + /* we don't set EPC if EXL is set */ + if (!(cp0->reg[MIPS_CP0_STATUS] & MIPS_CP0_STATUS_EXL)) { + cp0->reg[MIPS_CP0_EPC] = cpu->pc; + /*Cause BD is not update. MIPS VOLUME V3 P65 */ + cause &= ~MIPS_CP0_CAUSE_BD_SLOT; //clear bd + if (bd_slot) + cause |= MIPS_CP0_CAUSE_BD_SLOT; + else + cause &= ~MIPS_CP0_CAUSE_BD_SLOT; + + } + + cause &= ~MIPS_CP0_CAUSE_EXC_MASK; //clear exec-code + cause |= (exc_code << 2); + cp0->reg[MIPS_CP0_CAUSE] = cause; + if (exc_code == MIPS_CP0_CAUSE_INTERRUPT) + cpu->irq_cause = 0; + + /* Set EXL bit in status register */ + /*TODO: RESET SOFT RESET AND NMI EXCEPTION */ + cp0->reg[MIPS_CP0_STATUS] |= MIPS_CP0_STATUS_EXL; + + /* clear ERL bit in status register */ + /*TODO: RESET SOFT RESET AND NMI EXCEPTION */ + cp0->reg[MIPS_CP0_STATUS] &= ~MIPS_CP0_STATUS_ERL; + + if (cpu->vm->debug_level > 2) { + printf (" exception %u at %08x\n", exc_code, cpu->pc); + } + if (cp0->reg[MIPS_CP0_STATUS] & MIPS_CP0_STATUS_BEV) { + if ((exc_code == MIPS_CP0_CAUSE_TLB_LOAD) + || (exc_code == MIPS_CP0_CAUSE_TLB_SAVE)) { + if (cp0->reg[MIPS_CP0_STATUS] & MIPS_CP0_STATUS_EXL) + new_pc = 0xffffffffbfc00380ULL; + else + new_pc = 0xffffffffbfc00200ULL; + } else if (exc_code == MIPS_CP0_CAUSE_INTERRUPT) { + if (cp0->reg[MIPS_CP0_CAUSE] & MIPS_CP0_CAUSE_IV) + new_pc = 0xffffffffbfc00400ULL; + else + new_pc = 0xffffffffbfc00380ULL; + + } else + new_pc = 0xffffffffbfc00380ULL; + + } else { +#if SIM_PIC32 + /* TODO */ + new_pc = cp0->ebase_reg + 0x200; + if (exc_code != MIPS_CP0_CAUSE_INTERRUPT && + (exc_code != MIPS_CP0_CAUSE_SYSCALL || cpu->vm->debug_level > 0)) + print_exception (cpu, exc_code); +#else + if ((exc_code == MIPS_CP0_CAUSE_TLB_LOAD) + || (exc_code == MIPS_CP0_CAUSE_TLB_SAVE)) { + if (cp0->reg[MIPS_CP0_STATUS] & MIPS_CP0_STATUS_EXL) + new_pc = 0xffffffff80000180ULL; + else + new_pc = 0xffffffff80000000ULL; + } else if (exc_code == MIPS_CP0_CAUSE_INTERRUPT) { + if (cp0->reg[MIPS_CP0_CAUSE] & MIPS_CP0_CAUSE_IV) + new_pc = 0xffffffff80000200ULL; + else + new_pc = 0xffffffff80000180ULL; + } else + new_pc = 0xffffffff80000180ULL; +#endif + } + + cpu->pc = (m_va_t) new_pc; + + /* Clear the pending IRQ flag */ + cpu->irq_pending = 0; +} + +/* Execute fpu instruction */ +void fastcall mips_exec_soft_fpu (cpu_mips_t * cpu) +{ + mips_cp0_t *cp0 = &cpu->cp0; + cp0->reg[MIPS_CP0_CAUSE] |= 0x10000000; //CE=1 + mips_trigger_exception (cpu, MIPS_CP0_CAUSE_CP_UNUSABLE, + cpu->is_in_bdslot); + +} + +/* Execute ERET instruction */ +void fastcall mips_exec_eret (cpu_mips_t * cpu) +{ + mips_cp0_t *cp0 = &cpu->cp0; + + if (cp0->reg[MIPS_CP0_STATUS] & MIPS_CP0_STATUS_ERL) { + cp0->reg[MIPS_CP0_STATUS] &= ~MIPS_CP0_STATUS_ERL; + cpu->pc = cp0->reg[MIPS_CP0_ERR_EPC]; + + } else { + cp0->reg[MIPS_CP0_STATUS] &= ~MIPS_CP0_STATUS_EXL; + cpu->pc = cp0->reg[MIPS_CP0_EPC]; + } + /* We have to clear the LLbit */ + cpu->ll_bit = 0; + +} + +/* Execute BREAK instruction */ +void fastcall mips_exec_break (cpu_mips_t * cpu, u_int code) +{ + //mips_dump_regs(cpu); + printf ("exec break cpu->pc %x\n", cpu->pc); + + /* XXX TODO: Branch Delay slot */ + mips_trigger_exception (cpu, MIPS_CP0_CAUSE_BP, 0); + +} + +/* Trigger a Trap Exception */ +void fastcall mips_trigger_trap_exception (cpu_mips_t * cpu) +{ + /* XXX TODO: Branch Delay slot */ + printf ("MIPS64: TRAP exception, CPU=%p\n", cpu); + mips_trigger_exception (cpu, MIPS_CP0_CAUSE_TRAP, 0); +} + +/* Execute SYSCALL instruction */ +void fastcall mips_exec_syscall (cpu_mips_t * cpu) +{ +#if DEBUG_SYSCALL + printf ("MIPS: SYSCALL at PC=0x%" LL "x (RA=0x%" LL "x)\n" + " a0=0x%" LL "x, a1=0x%" LL "x, a2=0x%" LL "x, a3=0x%" LL "x\n", + cpu->pc, cpu->gpr[MIPS_GPR_RA], + cpu->gpr[MIPS_GPR_A0], cpu->gpr[MIPS_GPR_A1], cpu->gpr[MIPS_GPR_A2], + cpu->gpr[MIPS_GPR_A3]); +#endif + + if (cpu->is_in_bdslot == 0) + mips_trigger_exception (cpu, MIPS_CP0_CAUSE_SYSCALL, 0); + else + mips_trigger_exception (cpu, MIPS_CP0_CAUSE_SYSCALL, 1); +} + +/* Trigger IRQs */ +void forced_inline fastcall mips_trigger_irq (cpu_mips_t * cpu) +{ + if (mips_update_irq_flag (cpu)) + mips_trigger_exception (cpu, MIPS_CP0_CAUSE_INTERRUPT, 0); +} + +/* Set an IRQ */ +void mips_set_irq (cpu_mips_t * cpu, m_uint8_t irq) +{ + m_uint32_t m; + m = (1 << (irq + MIPS_CP0_CAUSE_ISHIFT)) & MIPS_CP0_CAUSE_IMASK; + //atomic_or(&cpu->irq_cause,m); + cpu->irq_cause |= m; +} + +/* Clear an IRQ */ +void mips_clear_irq (cpu_mips_t * cpu, m_uint8_t irq) +{ + m_uint32_t m; + + m = (1 << (irq + MIPS_CP0_CAUSE_ISHIFT)) & MIPS_CP0_CAUSE_IMASK; + cpu->irq_cause &= ~m; + //atomic_and(&cpu->irq_cause,~m); + + if (! cpu->irq_cause) + cpu->irq_pending = 0; +} diff --git a/tools/virtualmips/mips.h b/tools/virtualmips/mips.h new file mode 100644 index 0000000..6397621 --- /dev/null +++ b/tools/virtualmips/mips.h @@ -0,0 +1,503 @@ +/* + * Cisco router simulation platform. + * Copyright (c) 2005,2006 Christophe Fillot (cf@utc.fr) + * + */ + /* + * Copyright (C) yajin 2008 + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + * + */ + +#ifndef __MIPS_H__ +#define __MIPS_H__ +#include "system.h" +#include "utils.h" + +/* + * MIPS General Purpose Registers + */ +#define MIPS_GPR_ZERO 0 /* zero */ +#define MIPS_GPR_AT 1 /* at */ +#define MIPS_GPR_V0 2 /* v0 */ +#define MIPS_GPR_V1 3 /* v1 */ +#define MIPS_GPR_A0 4 /* a0 */ +#define MIPS_GPR_A1 5 /* a1 */ +#define MIPS_GPR_A2 6 /* a2 */ +#define MIPS_GPR_A3 7 /* a3 */ +#define MIPS_GPR_T0 8 /* t0 */ +#define MIPS_GPR_T1 9 /* t1 */ +#define MIPS_GPR_T2 10 /* t2 */ +#define MIPS_GPR_T3 11 /* t3 */ +#define MIPS_GPR_T4 12 /* t4 */ +#define MIPS_GPR_T5 13 /* t5 */ +#define MIPS_GPR_T6 14 /* t6 */ +#define MIPS_GPR_T7 15 /* t7 */ +#define MIPS_GPR_S0 16 /* s0 */ +#define MIPS_GPR_S1 17 /* s1 */ +#define MIPS_GPR_S2 18 /* s2 */ +#define MIPS_GPR_S3 19 /* s3 */ +#define MIPS_GPR_S4 20 /* s4 */ +#define MIPS_GPR_S5 21 /* s5 */ +#define MIPS_GPR_S6 22 /* s6 */ +#define MIPS_GPR_S7 23 /* s7 */ +#define MIPS_GPR_T8 24 /* t8 */ +#define MIPS_GPR_T9 25 /* t9 */ +#define MIPS_GPR_K0 26 /* k0 */ +#define MIPS_GPR_K1 27 /* k1 */ +#define MIPS_GPR_GP 28 /* gp */ +#define MIPS_GPR_SP 29 /* sp */ +#define MIPS_GPR_FP 30 /* fp */ +#define MIPS_GPR_RA 31 /* ra */ + +/* + * Coprocessor 0 (System Coprocessor) Register definitions + */ +#define MIPS_CP0_INDEX 0 /* TLB Index */ +#define MIPS_CP0_RANDOM 1 /* TLB Random */ +#define MIPS_CP0_TLB_LO_0 2 /* TLB Entry Lo0 */ +#define MIPS_CP0_TLB_LO_1 3 /* TLB Entry Lo1 */ +#define MIPS_CP0_CONTEXT 4 /* Kernel PTE pointer */ +#define MIPS_CP0_PAGEMASK 5 /* TLB Page Mask */ +#define MIPS_CP0_WIRED 6 /* TLB Wired */ +#define MIPS_CP0_INFO 7 /* Info (RM7000) */ +#define MIPS_CP0_BADVADDR 8 /* Bad Virtual Address */ +#define MIPS_CP0_COUNT 9 /* Count */ +#define MIPS_CP0_TLB_HI 10 /* TLB Entry Hi */ +#define MIPS_CP0_COMPARE 11 /* Timer Compare */ +#define MIPS_CP0_STATUS 12 /* Status */ +#define MIPS_CP0_CAUSE 13 /* Cause */ +#define MIPS_CP0_EPC 14 /* Exception PC */ +#define MIPS_CP0_PRID 15 /* Proc Rev ID */ +#define MIPS_CP0_CONFIG 16 /* Configuration */ +#define MIPS_CP0_LLADDR 17 /* Load/Link address */ +#define MIPS_CP0_WATCHLO 18 /* Low Watch address */ +#define MIPS_CP0_WATCHHI 19 /* High Watch address */ +#define MIPS_CP0_XCONTEXT 20 /* Extended context */ +#define MIPS_CP0_ECC 26 /* ECC and parity */ +#define MIPS_CP0_CACHERR 27 /* Cache Err/Status */ +#define MIPS_CP0_TAGLO 28 /* Cache Tag Lo */ +#define MIPS_CP0_TAGHI 29 /* Cache Tag Hi */ +#define MIPS_CP0_ERR_EPC 30 /* Error exception PC */ + +/* + * CP0 Status Register + */ +#define MIPS_CP0_STATUS_CU0 0x10000000 +#define MIPS_CP0_STATUS_CU1 0x20000000 +#define MIPS_CP0_STATUS_BEV 0x00400000 +#define MIPS_CP0_STATUS_TS 0x00200000 +#define MIPS_CP0_STATUS_SR 0x00100000 +#define MIPS_CP0_STATUS_CH 0x00040000 +#define MIPS_CP0_STATUS_CE 0x00020000 +#define MIPS_CP0_STATUS_DE 0x00010000 +#define MIPS_CP0_STATUS_RP 0x08000000 +#define MIPS_CP0_STATUS_FR 0x04000000 +#define MIPS_CP0_STATUS_RE 0x02000000 +#define MIPS_CP0_STATUS_KX 0x00000080 +#define MIPS_CP0_STATUS_SX 0x00000040 +#define MIPS_CP0_STATUS_UX 0x00000020 +#define MIPS_CP0_STATUS_KSU 0x00000018 +#define MIPS_CP0_STATUS_ERL 0x00000004 +#define MIPS_CP0_STATUS_EXL 0x00000002 +#define MIPS_CP0_STATUS_IE 0x00000001 +#define MIPS_CP0_STATUS_IMASK7 0x00008000 +#define MIPS_CP0_STATUS_IMASK6 0x00004000 +#define MIPS_CP0_STATUS_IMASK5 0x00002000 +#define MIPS_CP0_STATUS_IMASK4 0x00001000 +#define MIPS_CP0_STATUS_IMASK3 0x00000800 +#define MIPS_CP0_STATUS_IMASK2 0x00000400 +#define MIPS_CP0_STATUS_IMASK1 0x00000200 +#define MIPS_CP0_STATUS_IMASK0 0x00000100 + +#define MIPS_CP0_STATUS_DS_MASK 0x00770000 +#define MIPS_CP0_STATUS_CU_MASK 0xF0000000 +#define MIPS_CP0_STATUS_IMASK 0x0000FF00 + +/* Addressing mode: Kernel, Supervisor and User */ +#define MIPS_CP0_STATUS_KSU_SHIFT 0x03 +#define MIPS_CP0_STATUS_KSU_MASK 0x03 + +#define MIPS_CP0_STATUS_KM 0x00 +#define MIPS_CP0_STATUS_SM 0x01 +#define MIPS_CP0_STATUS_UM 0x10 + +/* + * CP0 Cause register + */ + +#define MIPS_CP0_CAUSE_BD_SLOT 0x80000000 + +#define MIPS_CP0_CAUSE_MASK 0x0000007C +#define MIPS_CP0_CAUSE_CEMASK 0x30000000 +#ifdef SIM_PIC32 +#define MIPS_CP0_CAUSE_IMASK 0x0000FC00 /* mips r2 */ +#else +#define MIPS_CP0_CAUSE_IMASK 0x0000FF00 /* mips r1 */ +#endif +#define MIPS_CP0_CAUSE_IV 0x00800000 +#define MIPS_CP0_CAUSE_SHIFT 2 +#define MIPS_CP0_CAUSE_CESHIFT 28 +#define MIPS_CP0_CAUSE_ISHIFT 8 +#define MIPS_CP0_CAUSE_EXC_MASK 0x0000007C + +#define MIPS_CP0_CAUSE_INTERRUPT 0 +#define MIPS_CP0_CAUSE_TLB_MOD 1 +#define MIPS_CP0_CAUSE_TLB_LOAD 2 +#define MIPS_CP0_CAUSE_TLB_SAVE 3 +#define MIPS_CP0_CAUSE_ADDR_LOAD 4 /* ADEL */ +#define MIPS_CP0_CAUSE_ADDR_SAVE 5 /* ADES */ +#define MIPS_CP0_CAUSE_BUS_INSTR 6 +#define MIPS_CP0_CAUSE_BUS_DATA 7 +#define MIPS_CP0_CAUSE_SYSCALL 8 +#define MIPS_CP0_CAUSE_BP 9 +#define MIPS_CP0_CAUSE_ILLOP 10 +#define MIPS_CP0_CAUSE_CP_UNUSABLE 11 +#define MIPS_CP0_CAUSE_OVFLW 12 +#define MIPS_CP0_CAUSE_TRAP 13 +#define MIPS_CP0_CAUSE_VC_INSTR 14 /* Virtual Coherency */ +#define MIPS_CP0_CAUSE_FPE 15 +#define MIPS_CP0_CAUSE_WATCH 23 +#define MIPS_CP0_CAUSE_VC_DATA 31 /* Virtual Coherency */ + +#define MIPS_CP0_CAUSE_IBIT7 0x00008000 +#define MIPS_CP0_CAUSE_IBIT6 0x00004000 +#define MIPS_CP0_CAUSE_IBIT5 0x00002000 +#define MIPS_CP0_CAUSE_IBIT4 0x00001000 +#define MIPS_CP0_CAUSE_IBIT3 0x00000800 +#define MIPS_CP0_CAUSE_IBIT2 0x00000400 +#define MIPS_CP0_CAUSE_IBIT1 0x00000200 +#define MIPS_CP0_CAUSE_IBIT0 0x00000100 + +/* cp0 context */ +#define MIPS_CP0_CONTEXT_PTEBASE_MASK 0xff800000 +#define MIPS_CP0_CONTEXT_BADVPN2_MASK 0x0007ffff0 + +/* TLB masks and shifts */ +#define MIPS_TLB_PAGE_MASK 0x01ffe000 +#define MIPS_TLB_PAGE_SHIFT 13 +//#define MIPS_TLB_VPN2_MASK 0xffffe000 +#define MIPS_TLB_VPN2_MASK_32 0xffffe000 +#define MIPS_TLB_VPN2_MASK_64 0xc00000ffffffe000ULL +#define MIPS_TLB_PFN_MASK 0x3fffffc0 +#define MIPS_TLB_ASID_MASK 0x000000ff /* "asid" in EntryHi */ +#define MIPS_TLB_G_MASK 0x00001000 /* "Global" in EntryHi */ +#define MIPS_TLB_V_MASK 0x2 /* "Valid" in EntryLo */ +#define MIPS_TLB_D_MASK 0x4 /* "Dirty" in EntryLo */ +#define MIPS_TLB_C_MASK 0x38 /* Page Coherency Attribute */ +#define MIPS_TLB_C_SHIFT 3 +#define MIPS_TLB_V_SHIT 1 +#define MIPS_TLB_D_SHIT 2 + +#define MIPS_CP0_LO_G_MASK 0x00000001 /* "Global" in Lo0/1 reg */ +#define MIPS_CP0_HI_SAFE_MASK 0xffffe0ff /* Safety mask for Hi reg */ +#define MIPS_CP0_LO_SAFE_MASK 0x7fffffff /* Safety mask for Lo reg */ + +/* MIPS "jr ra" instruction */ +#define MIPS_INSN_JR_RA 0x03e00008 + +#ifdef SIM_PIC32 +#define MIPS_MIN_PAGE_SHIFT 8 +#define MIPS_MIN_PAGE_SIZE (1 << MIPS_MIN_PAGE_SHIFT) +#define MIPS_MIN_PAGE_IMASK (MIPS_MIN_PAGE_SIZE - 1) +#define MIPS_MIN_PAGE_MASK 0xffffffffffffff00ULL +#else +/* Minimum page size: 4 Kb */ +#define MIPS_MIN_PAGE_SHIFT 12 +#define MIPS_MIN_PAGE_SIZE (1 << MIPS_MIN_PAGE_SHIFT) +#define MIPS_MIN_PAGE_IMASK (MIPS_MIN_PAGE_SIZE - 1) +#define MIPS_MIN_PAGE_MASK 0xfffffffffffff000ULL +#endif + +/* Addressing mode: Kernel, Supervisor and User */ +#define MIPS_MODE_KERNEL 00 + +/* Segments in 32-bit User mode */ +#define MIPS_USEG_BASE 0x00000000 +#define MIPS_USEG_SIZE 0x80000000 + +/* Segments in 32-bit Supervisor mode */ +#define MIPS_SUSEG_BASE 0x00000000 +#define MIPS_SUSEG_SIZE 0x80000000 +#define MIPS_SSEG_BASE 0xc0000000 +#define MIPS_SSEG_SIZE 0x20000000 + +/* Segments in 32-bit Kernel mode */ +#define MIPS_KUSEG_BASE 0x00000000 +#define MIPS_KUSEG_SIZE 0x80000000 + +#define MIPS_KSEG0_BASE 0x80000000 +#define MIPS_KSEG0_SIZE 0x20000000 + +#define MIPS_KSEG1_BASE 0xa0000000 +#define MIPS_KSEG1_SIZE 0x20000000 + +#define MIPS_KSSEG_BASE 0xc0000000 +#define MIPS_KSSEG_SIZE 0x20000000 + +#define MIPS_KSEG3_BASE 0xe0000000 +#define MIPS_KSEG3_SIZE 0x20000000 + +/* xkphys mask (36-bit physical address) */ +#define MIPS64_XKPHYS_ZONE_MASK 0xF800000000000000ULL +#define MIPS64_XKPHYS_PHYS_SIZE (1ULL << 36) +#define MIPS64_XKPHYS_PHYS_MASK (MIPS64_XKPHYS_PHYS_SIZE - 1) +#define MIPS64_XKPHYS_CCA_SHIFT 59 + +/* Number of GPR (general purpose registers) */ +#define MIPS64_GPR_NR 32 + +/* Number of registers in CP0 */ +#define MIPS64_CP0_REG_NR 32 + +/*8 configure register in cp0. sel:0-7*/ +#define MIPS64_CP0_CONFIG_REG_NR 8 + +/* Number of registers in CP1 */ +#define MIPS64_CP1_REG_NR 32 + +/* Number of TLB entries */ +#define MIPS64_TLB_STD_ENTRIES 48 +#define MIPS64_TLB_MAX_ENTRIES 64 +#define MIPS64_TLB_IDX_MASK 0x3f /* 6 bits */ + +/* Enable the 64 TLB entries for R7000 CPU */ +#define MIPS64_R7000_TLB64_ENABLE 0x20000000 + +/* Number of instructions per page */ +#define MIPS_INSN_PER_PAGE (MIPS_MIN_PAGE_SIZE/sizeof(mips_insn_t)) + +/* MIPS CPU Identifiers */ +#define MIPS_PRID_R4600 0x00002012 +#define MIPS_PRID_R4700 0x00002112 +#define MIPS_PRID_R5000 0x00002312 +#define MIPS_PRID_R7000 0x00002721 +#define MIPS_PRID_R527x 0x00002812 +#define MIPS_PRID_BCM1250 0x00040102 + +enum { + MIPS_KUSEG = 0, + MIPS_KSEG0, + MIPS_KSEG1, + MIPS_KSEG2, +}; + +/* Memory operations */ +enum { + MIPS_MEMOP_LOOKUP = 0, + + MIPS_MEMOP_LB, + MIPS_MEMOP_LBU, + MIPS_MEMOP_LH, + MIPS_MEMOP_LHU, + MIPS_MEMOP_LW, + MIPS_MEMOP_LWU, + MIPS_MEMOP_LD, + MIPS_MEMOP_SB, + MIPS_MEMOP_SH, + MIPS_MEMOP_SW, + MIPS_MEMOP_SD, + + MIPS_MEMOP_LWL, + MIPS_MEMOP_LWR, + MIPS_MEMOP_LDL, + MIPS_MEMOP_LDR, + MIPS_MEMOP_SWL, + MIPS_MEMOP_SWR, + MIPS_MEMOP_SDL, + MIPS_MEMOP_SDR, + + MIPS_MEMOP_LL, + MIPS_MEMOP_SC, + + MIPS_MEMOP_LDC1, + MIPS_MEMOP_SDC1, + + MIPS_MEMOP_CACHE, + + MIPS_MEMOP_MAX, +}; + +/* Maximum number of breakpoints */ +#define MIPS64_MAX_BREAKPOINTS 8 + +#define CPU_INTERRUPT_EXIT 0x01 /* wants exit from main loop */ +#define CPU_INTERRUPT_HARD 0x02 /* hardware interrupt pending */ +#define CPU_INTERRUPT_EXITTB 0x04 /* exit the current TB (use for x86 a20 case) */ +#define CPU_INTERRUPT_TIMER 0x08 /* internal timer exception pending */ +#define CPU_INTERRUPT_FIQ 0x10 /* Fast interrupt pending. */ +#define CPU_INTERRUPT_HALT 0x20 /* CPU halt wanted */ +#define CPU_INTERRUPT_SMI 0x40 /* (x86 only) SMI interrupt pending */ + +/* MIPS CPU type */ +//typedef struct cpu_mips cpu_mips_t; + +/* Memory operation function prototype */ +typedef u_int fastcall (*mips_memop_fn) (cpu_mips_t * cpu, m_va_t vaddr, + u_int reg); + +/* TLB entry definition */ +typedef struct { + m_va_t mask; + m_va_t hi; + m_va_t lo0; + m_va_t lo1; +} tlb_entry_t; + +/* System Coprocessor (CP0) definition */ +typedef struct { + m_cp0_reg_t reg[MIPS64_CP0_REG_NR]; + /*because configure has sel 0-7, seperate it to reg */ + m_cp0_reg_t config_reg[MIPS64_CP0_CONFIG_REG_NR]; + m_cp0_reg_t intctl_reg; + m_cp0_reg_t ebase_reg; + m_uint8_t config_usable; /*if configure register sel N is useable, set the bit in config_usable to 1 */ + + tlb_entry_t tlb[MIPS64_TLB_MAX_ENTRIES]; + + /* Number of TLB entries */ + u_int tlb_entries; + +} mips_cp0_t; + +/* mips CPU definition */ +struct cpu_mips { + /* CPU identifier for MP systems */ + u_int id; + u_int type; + + m_va_t pc, ret_pc; + m_va_t jit_pc; + m_reg_t gpr[MIPS64_GPR_NR]; + m_reg_t lo, hi; + /* VM instance */ + vm_instance_t *vm; + /* Next CPU in group */ + cpu_mips_t *next; + /* System coprocessor (CP0) */ + mips_cp0_t cp0; + + /* CPU states */ + volatile m_uint32_t state, prev_state; + + /* Thread running this CPU */ + pthread_t cpu_thread; + int cpu_thread_running; + + /*pause request. INTERRUPT will pause cpu */ + m_uint32_t pause_request; + + /* Methods */ + int (*reg_get) (cpu_mips_t * cpu, u_int reg, m_reg_t * val); + void (*reg_set) (cpu_mips_t * cpu, u_int reg_index, m_reg_t val); + void (*mts_rebuild) (cpu_mips_t * cpu); + u_int (*mips_mts_gdb_lb) (cpu_mips_t * cpu, m_va_t vaddr, void *cur); + + /* MTS32/MTS64 caches */ + union { + mts32_entry_t *mts32_cache; + mts64_entry_t *mts64_cache; + } mts_u; + + /* General Purpose Registers, Pointer Counter, LO/HI, IRQ */ + m_uint32_t irq_pending, irq_cause, ll_bit; + + /* Virtual address to physical page translation */ + int (*translate) (cpu_mips_t * cpu, m_va_t vaddr, m_uint32_t * phys_page); + /* Memory access functions */ + mips_memop_fn mem_op_fn[MIPS_MEMOP_MAX]; + /* Memory lookup function (to load ELF image,...) */ + void *fastcall (*mem_op_lookup) (cpu_mips_t * cpu, m_va_t vaddr); + + /* Address bus mask for physical addresses */ + m_va_t addr_bus_mask; + + /* MTS map/unmap/rebuild operations */ + void (*mts_map) (cpu_mips_t * cpu, m_va_t vaddr, m_pa_t paddr, + m_uint32_t len, int cache_access, int tlb_index); + void (*mts_unmap) (cpu_mips_t * cpu, m_va_t vaddr, m_uint32_t len, + m_uint32_t val, int tlb_index); + void (*mts_shutdown) (cpu_mips_t * cpu); + /* MTS cache statistics */ + m_uint64_t mts_misses, mts_lookups; + + /* Address mode (32 or 64 bits) */ + u_int addr_mode; + + int is_in_bdslot; + int trace_syscall; + + /* Current exec page (non-JIT) info */ + m_va_t njm_exec_page; + mips_insn_t *njm_exec_ptr; + +#ifdef _USE_JIT_ + /* JIT flush method */ + u_int jit_flush_method; + + /* Number of compiled pages */ + u_int compiled_pages; + + /* Code page translation cache */ + mips_jit_tcb_t **exec_blk_map; + void *exec_page_area; + size_t exec_page_area_size; /*M bytes */ + size_t exec_page_count, exec_page_alloc; + insn_exec_page_t *exec_page_free_list; + insn_exec_page_t *exec_page_array; + /* Current and free lists of translated code blocks */ + mips_jit_tcb_t *tcb_list, *tcb_last, *tcb_free_list; + /* Direct block jump.Optimization */ + u_int exec_blk_direct_jump; + +#endif + +}; + +/* Register names */ +extern char *mips_gpr_reg_names[]; + +#define MAJOR_OP(_inst) (((uint)_inst >> 26) & 0x3f ) + +int mips_load_elf_image (cpu_mips_t * cpu, char *filename, + m_va_t * entry_point); + +int mips_get_reg_index (char *name); +int mips_cca_cached (m_uint8_t val); +void mips_dump_regs (cpu_mips_t * cpu); +void mips_delete (cpu_mips_t * cpu); +int mips_reset (cpu_mips_t * cpu); +int mips_init (cpu_mips_t * cpu); +int mips_load_elf_image (cpu_mips_t * cpu, char *filename, + m_va_t * entry_point); +void mips_delete (cpu_mips_t * cpu); +int fastcall mips_update_irq_flag (cpu_mips_t * cpu); +void mips_trigger_exception (cpu_mips_t * cpu, u_int exc_code, int bd_slot); +void fastcall mips_exec_soft_fpu (cpu_mips_t * cpu); +void fastcall mips_exec_eret (cpu_mips_t * cpu); +void fastcall mips_exec_break (cpu_mips_t * cpu, u_int code); +void fastcall mips_trigger_trap_exception (cpu_mips_t * cpu); +void fastcall mips_exec_syscall (cpu_mips_t * cpu); +void fastcall mips_trigger_irq (cpu_mips_t * cpu); +void mips_set_irq (cpu_mips_t * cpu, m_uint8_t irq); +void mips_clear_irq (cpu_mips_t * cpu, m_uint8_t irq); + +/* Control timer interrupt */ +void set_timer_irq (cpu_mips_t *cpu); +void clear_timer_irq (cpu_mips_t *cpu); + +/* Print the mips instruction at address MEMADDR in debugged memory. */ +int print_insn_mips (unsigned memaddr, unsigned long int word, FILE *stream); + +const char *cp0reg_name (unsigned cp0reg, unsigned sel); + +int mips_fetch_instruction (cpu_mips_t * cpu, + m_va_t pc, mips_insn_t * insn); +void *mips_mts32_access (cpu_mips_t * cpu, m_va_t vaddr, + u_int op_code, u_int op_size, + u_int op_type, m_reg_t * data, u_int * exc, m_uint8_t * has_set_value, + u_int is_fromgdb); + +#endif diff --git a/tools/virtualmips/mips16-opc.c b/tools/virtualmips/mips16-opc.c new file mode 100644 index 0000000..4457333 --- /dev/null +++ b/tools/virtualmips/mips16-opc.c @@ -0,0 +1,259 @@ +/* + * This is the opcodes table for the mips16 processor. The format of + * this table is intentionally identical to the one in mips-opc.c. + * However, the special letters that appear in the argument string are + * different, and the table uses some different flags. + * + * Copyright 1996, 1997, 1998, 2000, 2005, 2006, 2007 + * Free Software Foundation, Inc. + * Contributed by Ian Lance Taylor, Cygnus Support + * Adapted for VirtualMIPS by Serge Vakulenko. + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + */ + +/* Use some short hand macros to keep down the length of the lines in + the opcodes table. */ + +#define UBD INSN_UNCOND_BRANCH_DELAY +#define UBR MIPS16_INSN_UNCOND_BRANCH +#define CBR MIPS16_INSN_COND_BRANCH + +#define WR_x MIPS16_INSN_WRITE_X +#define WR_y MIPS16_INSN_WRITE_Y +#define WR_z MIPS16_INSN_WRITE_Z +#define WR_T MIPS16_INSN_WRITE_T +#define WR_SP MIPS16_INSN_WRITE_SP +#define WR_31 MIPS16_INSN_WRITE_31 +#define WR_Y MIPS16_INSN_WRITE_GPR_Y + +#define RD_x MIPS16_INSN_READ_X +#define RD_y MIPS16_INSN_READ_Y +#define RD_Z MIPS16_INSN_READ_Z +#define RD_T MIPS16_INSN_READ_T +#define RD_SP MIPS16_INSN_READ_SP +#define RD_31 MIPS16_INSN_READ_31 +#define RD_PC MIPS16_INSN_READ_PC +#define RD_X MIPS16_INSN_READ_GPR_X + +#define WR_HI INSN_WRITE_HI +#define WR_LO INSN_WRITE_LO +#define RD_HI INSN_READ_HI +#define RD_LO INSN_READ_LO + +#define TRAP INSN_TRAP + +#define I1 INSN_ISA1 +#define I3 INSN_ISA3 +#define I32 INSN_ISA32 +#define I64 INSN_ISA64 +#define T3 INSN_3900 + +static const struct mips_opcode mips16_opcodes[] = +{ +/* name, args, match, mask, pinfo, pinfo2, membership */ +{"nop", "", 0x6500, 0xffff, RD_Z, 0, I1 }, /* move $0,$Z */ +{"la", "x,A", 0x0800, 0xf800, WR_x|RD_PC, 0, I1 }, +{"abs", "x,w", 0, (int) M_ABS, INSN_MACRO, 0, I1 }, +{"addiu", "y,x,4", 0x4000, 0xf810, WR_y|RD_x, 0, I1 }, +{"addiu", "x,k", 0x4800, 0xf800, WR_x|RD_x, 0, I1 }, +{"addiu", "S,K", 0x6300, 0xff00, WR_SP|RD_SP, 0, I1 }, +{"addiu", "S,S,K", 0x6300, 0xff00, WR_SP|RD_SP, 0, I1 }, +{"addiu", "x,P,V", 0x0800, 0xf800, WR_x|RD_PC, 0, I1 }, +{"addiu", "x,S,V", 0x0000, 0xf800, WR_x|RD_SP, 0, I1 }, +{"addu", "z,v,y", 0xe001, 0xf803, WR_z|RD_x|RD_y, 0, I1 }, +{"addu", "y,x,4", 0x4000, 0xf810, WR_y|RD_x, 0, I1 }, +{"addu", "x,k", 0x4800, 0xf800, WR_x|RD_x, 0, I1 }, +{"addu", "S,K", 0x6300, 0xff00, WR_SP|RD_SP, 0, I1 }, +{"addu", "S,S,K", 0x6300, 0xff00, WR_SP|RD_SP, 0, I1 }, +{"addu", "x,P,V", 0x0800, 0xf800, WR_x|RD_PC, 0, I1 }, +{"addu", "x,S,V", 0x0000, 0xf800, WR_x|RD_SP, 0, I1 }, +{"and", "x,y", 0xe80c, 0xf81f, WR_x|RD_x|RD_y, 0, I1 }, +{"b", "q", 0x1000, 0xf800, UBR, 0, I1 }, +{"beq", "x,y,p", 0, (int) M_BEQ, INSN_MACRO, 0, I1 }, +{"beq", "x,U,p", 0, (int) M_BEQ_I, INSN_MACRO, 0, I1 }, +{"beqz", "x,p", 0x2000, 0xf800, CBR|RD_x, 0, I1 }, +{"bge", "x,y,p", 0, (int) M_BGE, INSN_MACRO, 0, I1 }, +{"bge", "x,8,p", 0, (int) M_BGE_I, INSN_MACRO, 0, I1 }, +{"bgeu", "x,y,p", 0, (int) M_BGEU, INSN_MACRO, 0, I1 }, +{"bgeu", "x,8,p", 0, (int) M_BGEU_I, INSN_MACRO, 0, I1 }, +{"bgt", "x,y,p", 0, (int) M_BGT, INSN_MACRO, 0, I1 }, +{"bgt", "x,8,p", 0, (int) M_BGT_I, INSN_MACRO, 0, I1 }, +{"bgtu", "x,y,p", 0, (int) M_BGTU, INSN_MACRO, 0, I1 }, +{"bgtu", "x,8,p", 0, (int) M_BGTU_I, INSN_MACRO, 0, I1 }, +{"ble", "x,y,p", 0, (int) M_BLE, INSN_MACRO, 0, I1 }, +{"ble", "x,8,p", 0, (int) M_BLE_I, INSN_MACRO, 0, I1 }, +{"bleu", "x,y,p", 0, (int) M_BLEU, INSN_MACRO, 0, I1 }, +{"bleu", "x,8,p", 0, (int) M_BLEU_I, INSN_MACRO, 0, I1 }, +{"blt", "x,y,p", 0, (int) M_BLT, INSN_MACRO, 0, I1 }, +{"blt", "x,8,p", 0, (int) M_BLT_I, INSN_MACRO, 0, I1 }, +{"bltu", "x,y,p", 0, (int) M_BLTU, INSN_MACRO, 0, I1 }, +{"bltu", "x,8,p", 0, (int) M_BLTU_I, INSN_MACRO, 0, I1 }, +{"bne", "x,y,p", 0, (int) M_BNE, INSN_MACRO, 0, I1 }, +{"bne", "x,U,p", 0, (int) M_BNE_I, INSN_MACRO, 0, I1 }, +{"bnez", "x,p", 0x2800, 0xf800, CBR|RD_x, 0, I1 }, +{"break", "6", 0xe805, 0xf81f, TRAP, 0, I1 }, +{"bteqz", "p", 0x6000, 0xff00, CBR|RD_T, 0, I1 }, +{"btnez", "p", 0x6100, 0xff00, CBR|RD_T, 0, I1 }, +{"cmpi", "x,U", 0x7000, 0xf800, WR_T|RD_x, 0, I1 }, +{"cmp", "x,y", 0xe80a, 0xf81f, WR_T|RD_x|RD_y, 0, I1 }, +{"cmp", "x,U", 0x7000, 0xf800, WR_T|RD_x, 0, I1 }, +{"dla", "y,E", 0xfe00, 0xff00, WR_y|RD_PC, 0, I3 }, +{"daddiu", "y,x,4", 0x4010, 0xf810, WR_y|RD_x, 0, I3 }, +{"daddiu", "y,j", 0xfd00, 0xff00, WR_y|RD_y, 0, I3 }, +{"daddiu", "S,K", 0xfb00, 0xff00, WR_SP|RD_SP, 0, I3 }, +{"daddiu", "S,S,K", 0xfb00, 0xff00, WR_SP|RD_SP, 0, I3 }, +{"daddiu", "y,P,W", 0xfe00, 0xff00, WR_y|RD_PC, 0, I3 }, +{"daddiu", "y,S,W", 0xff00, 0xff00, WR_y|RD_SP, 0, I3 }, +{"daddu", "z,v,y", 0xe000, 0xf803, WR_z|RD_x|RD_y, 0, I3 }, +{"daddu", "y,x,4", 0x4010, 0xf810, WR_y|RD_x, 0, I3 }, +{"daddu", "y,j", 0xfd00, 0xff00, WR_y|RD_y, 0, I3 }, +{"daddu", "S,K", 0xfb00, 0xff00, WR_SP|RD_SP, 0, I3 }, +{"daddu", "S,S,K", 0xfb00, 0xff00, WR_SP|RD_SP, 0, I3 }, +{"daddu", "y,P,W", 0xfe00, 0xff00, WR_y|RD_PC, 0, I3 }, +{"daddu", "y,S,W", 0xff00, 0xff00, WR_y|RD_SP, 0, I3 }, +{"ddiv", "0,x,y", 0xe81e, 0xf81f, RD_x|RD_y|WR_HI|WR_LO, 0, I3 }, +{"ddiv", "z,v,y", 0, (int) M_DDIV_3, INSN_MACRO, 0, I1 }, +{"ddivu", "0,x,y", 0xe81f, 0xf81f, RD_x|RD_y|WR_HI|WR_LO, 0, I3 }, +{"ddivu", "z,v,y", 0, (int) M_DDIVU_3, INSN_MACRO, 0, I1 }, +{"div", "0,x,y", 0xe81a, 0xf81f, RD_x|RD_y|WR_HI|WR_LO, 0, I1 }, +{"div", "z,v,y", 0, (int) M_DIV_3, INSN_MACRO, 0, I1 }, +{"divu", "0,x,y", 0xe81b, 0xf81f, RD_x|RD_y|WR_HI|WR_LO, 0, I1 }, +{"divu", "z,v,y", 0, (int) M_DIVU_3, INSN_MACRO, 0, I1 }, +{"dmul", "z,v,y", 0, (int) M_DMUL, INSN_MACRO, 0, I3 }, +{"dmult", "x,y", 0xe81c, 0xf81f, RD_x|RD_y|WR_HI|WR_LO, 0, I3 }, +{"dmultu", "x,y", 0xe81d, 0xf81f, RD_x|RD_y|WR_HI|WR_LO, 0, I3 }, +{"drem", "0,x,y", 0xe81e, 0xf81f, RD_x|RD_y|WR_HI|WR_LO, 0, I3 }, +{"drem", "z,v,y", 0, (int) M_DREM_3, INSN_MACRO, 0, I1 }, +{"dremu", "0,x,y", 0xe81f, 0xf81f, RD_x|RD_y|WR_HI|WR_LO, 0, I3 }, +{"dremu", "z,v,y", 0, (int) M_DREMU_3, INSN_MACRO, 0, I1 }, +{"dsllv", "y,x", 0xe814, 0xf81f, WR_y|RD_y|RD_x, 0, I3 }, +{"dsll", "x,w,[", 0x3001, 0xf803, WR_x|RD_y, 0, I3 }, +{"dsll", "y,x", 0xe814, 0xf81f, WR_y|RD_y|RD_x, 0, I3 }, +{"dsrav", "y,x", 0xe817, 0xf81f, WR_y|RD_y|RD_x, 0, I3 }, +{"dsra", "y,]", 0xe813, 0xf81f, WR_y|RD_y, 0, I3 }, +{"dsra", "y,x", 0xe817, 0xf81f, WR_y|RD_y|RD_x, 0, I3 }, +{"dsrlv", "y,x", 0xe816, 0xf81f, WR_y|RD_y|RD_x, 0, I3 }, +{"dsrl", "y,]", 0xe808, 0xf81f, WR_y|RD_y, 0, I3 }, +{"dsrl", "y,x", 0xe816, 0xf81f, WR_y|RD_y|RD_x, 0, I3 }, +{"dsubu", "z,v,y", 0xe002, 0xf803, WR_z|RD_x|RD_y, 0, I3 }, +{"dsubu", "y,x,4", 0, (int) M_DSUBU_I, INSN_MACRO, 0, I1 }, +{"dsubu", "y,j", 0, (int) M_DSUBU_I_2, INSN_MACRO, 0, I1 }, +{"exit", "L", 0xed09, 0xff1f, TRAP, 0, I1 }, +{"exit", "L", 0xee09, 0xff1f, TRAP, 0, I1 }, +{"exit", "L", 0xef09, 0xff1f, TRAP, 0, I1 }, +{"entry", "l", 0xe809, 0xf81f, TRAP, 0, I1 }, +{"extend", "e", 0xf000, 0xf800, 0, 0, I1 }, +{"jalr", "x", 0xe840, 0xf8ff, UBD|WR_31|RD_x, 0, I1 }, +{"jalr", "R,x", 0xe840, 0xf8ff, UBD|WR_31|RD_x, 0, I1 }, +{"jal", "x", 0xe840, 0xf8ff, UBD|WR_31|RD_x, 0, I1 }, +{"jal", "R,x", 0xe840, 0xf8ff, UBD|WR_31|RD_x, 0, I1 }, +{"jal", "a", 0x1800, 0xfc00, UBD|WR_31, 0, I1 }, +{"jalx", "a", 0x1c00, 0xfc00, UBD|WR_31, 0, I1 }, +{"jr", "x", 0xe800, 0xf8ff, UBD|RD_x, 0, I1 }, +{"jr", "R", 0xe820, 0xffff, UBD|RD_31, 0, I1 }, +{"j", "x", 0xe800, 0xf8ff, UBD|RD_x, 0, I1 }, +{"j", "R", 0xe820, 0xffff, UBD|RD_31, 0, I1 }, +{"lb", "y,5(x)", 0x8000, 0xf800, WR_y|RD_x, 0, I1 }, +{"lbu", "y,5(x)", 0xa000, 0xf800, WR_y|RD_x, 0, I1 }, +{"ld", "y,D(x)", 0x3800, 0xf800, WR_y|RD_x, 0, I3 }, +{"ld", "y,B", 0xfc00, 0xff00, WR_y|RD_PC, 0, I3 }, +{"ld", "y,D(P)", 0xfc00, 0xff00, WR_y|RD_PC, 0, I3 }, +{"ld", "y,D(S)", 0xf800, 0xff00, WR_y|RD_SP, 0, I3 }, +{"lh", "y,H(x)", 0x8800, 0xf800, WR_y|RD_x, 0, I1 }, +{"lhu", "y,H(x)", 0xa800, 0xf800, WR_y|RD_x, 0, I1 }, +{"li", "x,U", 0x6800, 0xf800, WR_x, 0, I1 }, +{"lw", "y,W(x)", 0x9800, 0xf800, WR_y|RD_x, 0, I1 }, +{"lw", "x,A", 0xb000, 0xf800, WR_x|RD_PC, 0, I1 }, +{"lw", "x,V(P)", 0xb000, 0xf800, WR_x|RD_PC, 0, I1 }, +{"lw", "x,V(S)", 0x9000, 0xf800, WR_x|RD_SP, 0, I1 }, +{"lwu", "y,W(x)", 0xb800, 0xf800, WR_y|RD_x, 0, I3 }, +{"mfhi", "x", 0xe810, 0xf8ff, WR_x|RD_HI, 0, I1 }, +{"mflo", "x", 0xe812, 0xf8ff, WR_x|RD_LO, 0, I1 }, +{"move", "y,X", 0x6700, 0xff00, WR_y|RD_X, 0, I1 }, +{"move", "Y,Z", 0x6500, 0xff00, WR_Y|RD_Z, 0, I1 }, +{"mul", "z,v,y", 0, (int) M_MUL, INSN_MACRO, 0, I1 }, +{"mult", "x,y", 0xe818, 0xf81f, RD_x|RD_y|WR_HI|WR_LO, 0, I1 }, +{"multu", "x,y", 0xe819, 0xf81f, RD_x|RD_y|WR_HI|WR_LO, 0, I1 }, +{"neg", "x,w", 0xe80b, 0xf81f, WR_x|RD_y, 0, I1 }, +{"not", "x,w", 0xe80f, 0xf81f, WR_x|RD_y, 0, I1 }, +{"or", "x,y", 0xe80d, 0xf81f, WR_x|RD_x|RD_y, 0, I1 }, +{"rem", "0,x,y", 0xe81a, 0xf81f, RD_x|RD_y|WR_HI|WR_LO, 0, I1 }, +{"rem", "z,v,y", 0, (int) M_REM_3, INSN_MACRO, 0, I1 }, +{"remu", "0,x,y", 0xe81b, 0xf81f, RD_x|RD_y|WR_HI|WR_LO, 0, I1 }, +{"remu", "z,v,y", 0, (int) M_REMU_3, INSN_MACRO, 0, I1 }, +{"sb", "y,5(x)", 0xc000, 0xf800, RD_y|RD_x, 0, I1 }, +{"sd", "y,D(x)", 0x7800, 0xf800, RD_y|RD_x, 0, I3 }, +{"sd", "y,D(S)", 0xf900, 0xff00, RD_y|RD_PC, 0, I3 }, +{"sd", "R,C(S)", 0xfa00, 0xff00, RD_31|RD_PC, 0, I1 }, +{"sh", "y,H(x)", 0xc800, 0xf800, RD_y|RD_x, 0, I1 }, +{"sllv", "y,x", 0xe804, 0xf81f, WR_y|RD_y|RD_x, 0, I1 }, +{"sll", "x,w,<", 0x3000, 0xf803, WR_x|RD_y, 0, I1 }, +{"sll", "y,x", 0xe804, 0xf81f, WR_y|RD_y|RD_x, 0, I1 }, +{"slti", "x,8", 0x5000, 0xf800, WR_T|RD_x, 0, I1 }, +{"slt", "x,y", 0xe802, 0xf81f, WR_T|RD_x|RD_y, 0, I1 }, +{"slt", "x,8", 0x5000, 0xf800, WR_T|RD_x, 0, I1 }, +{"sltiu", "x,8", 0x5800, 0xf800, WR_T|RD_x, 0, I1 }, +{"sltu", "x,y", 0xe803, 0xf81f, WR_T|RD_x|RD_y, 0, I1 }, +{"sltu", "x,8", 0x5800, 0xf800, WR_T|RD_x, 0, I1 }, +{"srav", "y,x", 0xe807, 0xf81f, WR_y|RD_y|RD_x, 0, I1 }, +{"sra", "x,w,<", 0x3003, 0xf803, WR_x|RD_y, 0, I1 }, +{"sra", "y,x", 0xe807, 0xf81f, WR_y|RD_y|RD_x, 0, I1 }, +{"srlv", "y,x", 0xe806, 0xf81f, WR_y|RD_y|RD_x, 0, I1 }, +{"srl", "x,w,<", 0x3002, 0xf803, WR_x|RD_y, 0, I1 }, +{"srl", "y,x", 0xe806, 0xf81f, WR_y|RD_y|RD_x, 0, I1 }, +{"subu", "z,v,y", 0xe003, 0xf803, WR_z|RD_x|RD_y, 0, I1 }, +{"subu", "y,x,4", 0, (int) M_SUBU_I, INSN_MACRO, 0, I1 }, +{"subu", "x,k", 0, (int) M_SUBU_I_2, INSN_MACRO,0, I1 }, +{"sw", "y,W(x)", 0xd800, 0xf800, RD_y|RD_x, 0, I1 }, +{"sw", "x,V(S)", 0xd000, 0xf800, RD_x|RD_SP, 0, I1 }, +{"sw", "R,V(S)", 0x6200, 0xff00, RD_31|RD_SP, 0, I1 }, +{"xor", "x,y", 0xe80e, 0xf81f, WR_x|RD_x|RD_y, 0, I1 }, + /* MIPS16e additions */ +{"jalrc", "x", 0xe8c0, 0xf8ff, UBR|WR_31|RD_x|TRAP, 0, I32 }, +{"jalrc", "R,x", 0xe8c0, 0xf8ff, UBR|WR_31|RD_x|TRAP, 0, I32 }, +{"jrc", "x", 0xe880, 0xf8ff, UBR|RD_x|TRAP, 0, I32 }, +{"jrc", "R", 0xe8a0, 0xffff, UBR|RD_31|TRAP, 0, I32 }, +{"restore", "M", 0x6400, 0xff80, WR_31|RD_SP|WR_SP|TRAP, 0, I32 }, +{"save", "m", 0x6480, 0xff80, RD_31|RD_SP|WR_SP|TRAP, 0, I32 }, +{"sdbbp", "6", 0xe801, 0xf81f, TRAP, 0, I32 }, +{"seb", "x", 0xe891, 0xf8ff, WR_x|RD_x, 0, I32 }, +{"seh", "x", 0xe8b1, 0xf8ff, WR_x|RD_x, 0, I32 }, +{"sew", "x", 0xe8d1, 0xf8ff, WR_x|RD_x, 0, I64 }, +{"zeb", "x", 0xe811, 0xf8ff, WR_x|RD_x, 0, I32 }, +{"zeh", "x", 0xe831, 0xf8ff, WR_x|RD_x, 0, I32 }, +{"zew", "x", 0xe851, 0xf8ff, WR_x|RD_x, 0, I64 }, +}; + +static const int mips16_num_opcodes = + ((sizeof mips16_opcodes) / (sizeof (mips16_opcodes[0]))); + +#undef UBD +#undef UBR +#undef CBR +#undef WR_x +#undef WR_y +#undef WR_z +#undef WR_T +#undef WR_SP +#undef WR_31 +#undef WR_Y +#undef RD_x +#undef RD_y +#undef RD_Z +#undef RD_T +#undef RD_SP +#undef RD_31 +#undef RD_PC +#undef RD_X +#undef WR_HI +#undef WR_LO +#undef RD_HI +#undef RD_LO +#undef TRAP +#undef I1 +#undef I3 +#undef I32 +#undef I64 +#undef T3 diff --git a/tools/virtualmips/mips_codetable.c b/tools/virtualmips/mips_codetable.c new file mode 100644 index 0000000..e3599af --- /dev/null +++ b/tools/virtualmips/mips_codetable.c @@ -0,0 +1,2169 @@ +/* + * Code dispatch table. + * + * Copyright (C) yajin 2008 + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + */ + +static int unknown_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + printf ("--- Unknown instruction:\n"); + printf ("%08x: %08x ", cpu->pc, insn); + print_insn_mips (cpu->pc, insn, stdout); + printf ("\n"); + exit (EXIT_FAILURE); +} + +static int add_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + int rs = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + int rd = bits (insn, 11, 15); + m_reg_t res; + + /* TODO: Exception handling */ + res = (m_uint32_t) cpu->gpr[rs] + (m_uint32_t) cpu->gpr[rt]; + cpu->reg_set (cpu, rd, sign_extend (res, 32)); + return (0); +} + +static int addi_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + int rs = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + int imm = bits (insn, 0, 15); + m_uint32_t res, val = sign_extend (imm, 16); + + /* TODO: Exception handling */ + res = (m_uint32_t) cpu->gpr[rs] + val; + cpu->reg_set (cpu, rt, sign_extend (res, 32)); + return (0); +} + +static int addiu_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + int rs = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + int imm = bits (insn, 0, 15); + m_uint32_t res, val = sign_extend (imm, 16); + + res = (m_uint32_t) cpu->gpr[rs] + val; + cpu->reg_set (cpu, rt, sign_extend (res, 32)); + return (0); +} + +static int addu_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + int rs = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + int rd = bits (insn, 11, 15); + m_uint32_t res; + + res = (m_uint32_t) cpu->gpr[rs] + (m_uint32_t) cpu->gpr[rt]; + cpu->reg_set (cpu, rd, sign_extend (res, 32)); + return (0); +} + +static int and_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + int rs = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + int rd = bits (insn, 11, 15); + + cpu->reg_set (cpu, rd, cpu->gpr[rs] & cpu->gpr[rt]); + return (0); +} + +static int andi_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + int rs = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + int imm = bits (insn, 0, 15); + + cpu->reg_set (cpu, rt, cpu->gpr[rs] & imm); + return (0); +} + +static int bcond_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + uint16_t special_func = bits (insn, 16, 20); + return mips_bcond_opcodes[special_func].func (cpu, insn); +} + +static int beq_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + int rs = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + int offset = bits (insn, 0, 15); + m_va_t new_pc; + int res; + + /* compute the new pc */ + new_pc = (cpu->pc + 4) + sign_extend (offset << 2, 18); + + /* take the branch if gpr[rs] == gpr[rt] */ + res = (cpu->gpr[rs] == cpu->gpr[rt]); + + /* exec the instruction in the delay slot */ + int ins_res = mips_exec_bdslot (cpu); + if (likely (!ins_res)) { + if (res) + cpu->pc = new_pc; + else + cpu->pc += 8; + } + + return (1); +} + +static int beql_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + int rs = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + int offset = bits (insn, 0, 15); + m_va_t new_pc; + int res; + + /* compute the new pc */ + new_pc = (cpu->pc + 4) + sign_extend (offset << 2, 18); + + /* take the branch if gpr[rs] == gpr[rt] */ + res = (cpu->gpr[rs] == cpu->gpr[rt]); + + /* take the branch if the test result is true */ + if (res) { + int ins_res = mips_exec_bdslot (cpu); + if (likely (!ins_res)) + cpu->pc = new_pc; + } else + cpu->pc += 8; + + return (1); +} + +static int bgez_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + int rs = bits (insn, 21, 25); + int offset = bits (insn, 0, 15); + m_va_t new_pc; + int res; + + /* compute the new pc */ + new_pc = (cpu->pc + 4) + sign_extend (offset << 2, 18); + + /* take the branch if gpr[rs] >= 0 */ + res = ((m_ireg_t) cpu->gpr[rs] >= 0); + + /* exec the instruction in the delay slot */ + /* exec the instruction in the delay slot */ + int ins_res = mips_exec_bdslot (cpu); + + if (likely (!ins_res)) { + /* take the branch if the test result is true */ + if (res) + cpu->pc = new_pc; + else + cpu->pc += 8; + } + return (1); +} + +static int bgezal_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + int rs = bits (insn, 21, 25); + int offset = bits (insn, 0, 15); + m_va_t new_pc; + int res; + + /* compute the new pc */ + new_pc = (cpu->pc + 4) + sign_extend (offset << 2, 18); + + /* set the return address (instruction after the delay slot) */ + cpu->reg_set (cpu, MIPS_GPR_RA, cpu->pc + 8); + + /* take the branch if gpr[rs] >= 0 */ + res = ((m_ireg_t) cpu->gpr[rs] >= 0); + + /* exec the instruction in the delay slot */ + int ins_res = mips_exec_bdslot (cpu); + + if (likely (!ins_res)) { + /* take the branch if the test result is true */ + if (res) + cpu->pc = new_pc; + else + cpu->pc += 8; + } + return (1); +} + +static int bgezall_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + int rs = bits (insn, 21, 25); + int offset = bits (insn, 0, 15); + m_va_t new_pc; + int res; + + /* compute the new pc */ + new_pc = (cpu->pc + 4) + sign_extend (offset << 2, 18); + + /* set the return address (instruction after the delay slot) */ + cpu->reg_set (cpu, MIPS_GPR_RA, cpu->pc + 8); + + /* take the branch if gpr[rs] >= 0 */ + res = ((m_ireg_t) cpu->gpr[rs] >= 0); + + /* take the branch if the test result is true */ + if (res) { + mips_exec_bdslot (cpu); + cpu->pc = new_pc; + } else + cpu->pc += 8; + + return (1); + +} + +static int bgezl_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + int rs = bits (insn, 21, 25); + int offset = bits (insn, 0, 15); + m_va_t new_pc; + int res; + + /* compute the new pc */ + new_pc = (cpu->pc + 4) + sign_extend (offset << 2, 18); + + /* take the branch if gpr[rs] >= 0 */ + res = ((m_ireg_t) cpu->gpr[rs] >= 0); + + /* take the branch if the test result is true */ + if (res) { + mips_exec_bdslot (cpu); + cpu->pc = new_pc; + } else + cpu->pc += 8; + + return (1); + +} + +static int bgtz_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + int rs = bits (insn, 21, 25); + int offset = bits (insn, 0, 15); + m_va_t new_pc; + int res; + + /* compute the new pc */ + new_pc = (cpu->pc + 4) + sign_extend (offset << 2, 18); + + /* take the branch if gpr[rs] > 0 */ + res = ((m_ireg_t) cpu->gpr[rs] > 0); + + /* exec the instruction in the delay slot */ + int ins_res = mips_exec_bdslot (cpu); + + if (likely (!ins_res)) { + /* take the branch if the test result is true */ + if (res) + cpu->pc = new_pc; + else + cpu->pc += 8; + } + return (1); +} + +static int bgtzl_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + int rs = bits (insn, 21, 25); + int offset = bits (insn, 0, 15); + m_va_t new_pc; + int res; + + /* compute the new pc */ + new_pc = (cpu->pc + 4) + sign_extend (offset << 2, 18); + + /* take the branch if gpr[rs] > 0 */ + res = ((m_ireg_t) cpu->gpr[rs] > 0); + + /* take the branch if the test result is true */ + if (res) { + mips_exec_bdslot (cpu); + cpu->pc = new_pc; + } else + cpu->pc += 8; + + return (1); +} + +static int blez_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + int rs = bits (insn, 21, 25); + int offset = bits (insn, 0, 15); + m_va_t new_pc; + int res; + + /* compute the new pc */ + new_pc = (cpu->pc + 4) + sign_extend (offset << 2, 18); + + /* take the branch if gpr[rs] <= 0 */ + res = ((m_ireg_t) cpu->gpr[rs] <= 0); + + /* exec the instruction in the delay slot */ + int ins_res = mips_exec_bdslot (cpu); + + if (likely (!ins_res)) { + /* take the branch if the test result is true */ + if (res) + cpu->pc = new_pc; + else + cpu->pc += 8; + } + return (1); +} + +static int blezl_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + int rs = bits (insn, 21, 25); + int offset = bits (insn, 0, 15); + m_va_t new_pc; + int res; + + /* compute the new pc */ + new_pc = (cpu->pc + 4) + sign_extend (offset << 2, 18); + + /* take the branch if gpr[rs] <= 0 */ + res = ((m_ireg_t) cpu->gpr[rs] <= 0); + + /* take the branch if the test result is true */ + if (res) { + mips_exec_bdslot (cpu); + cpu->pc = new_pc; + } else + cpu->pc += 8; + + return (1); +} + +static int bltz_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + int rs = bits (insn, 21, 25); + int offset = bits (insn, 0, 15); + m_va_t new_pc; + int res; + + /* compute the new pc */ + new_pc = (cpu->pc + 4) + sign_extend (offset << 2, 18); + + /* take the branch if gpr[rs] < 0 */ + res = ((m_ireg_t) cpu->gpr[rs] < 0); + + /* exec the instruction in the delay slot */ + int ins_res = mips_exec_bdslot (cpu); + + if (likely (!ins_res)) { + /* take the branch if the test result is true */ + if (res) + cpu->pc = new_pc; + else + cpu->pc += 8; + } + return (1); +} + +static int bltzal_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + int rs = bits (insn, 21, 25); + int offset = bits (insn, 0, 15); + m_va_t new_pc; + int res; + + /* compute the new pc */ + new_pc = (cpu->pc + 4) + sign_extend (offset << 2, 18); + + /* set the return address (instruction after the delay slot) */ + cpu->reg_set (cpu, MIPS_GPR_RA, cpu->pc + 8); + + /* take the branch if gpr[rs] < 0 */ + res = ((m_ireg_t) cpu->gpr[rs] < 0); + + /* exec the instruction in the delay slot */ + int ins_res = mips_exec_bdslot (cpu); + + if (likely (!ins_res)) { + /* take the branch if the test result is true */ + if (res) + cpu->pc = new_pc; + else + cpu->pc += 8; + } + return (1); +} + +static int bltzall_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + int rs = bits (insn, 21, 25); + int offset = bits (insn, 0, 15); + m_va_t new_pc; + int res; + + /* compute the new pc */ + new_pc = (cpu->pc + 4) + sign_extend (offset << 2, 18); + + /* set the return address (instruction after the delay slot) */ + cpu->reg_set (cpu, MIPS_GPR_RA, cpu->pc + 8); + + /* take the branch if gpr[rs] < 0 */ + res = ((m_ireg_t) cpu->gpr[rs] < 0); + + /* take the branch if the test result is true */ + if (res) { + mips_exec_bdslot (cpu); + cpu->pc = new_pc; + } else + cpu->pc += 8; + + return (1); +} + +static int bltzl_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + int rs = bits (insn, 21, 25); + int offset = bits (insn, 0, 15); + m_va_t new_pc; + int res; + + /* compute the new pc */ + new_pc = (cpu->pc + 4) + sign_extend (offset << 2, 18); + + /* take the branch if gpr[rs] < 0 */ + res = ((m_ireg_t) cpu->gpr[rs] < 0); + + /* take the branch if the test result is true */ + if (res) { + mips_exec_bdslot (cpu); + cpu->pc = new_pc; + } else + cpu->pc += 8; + + return (1); +} + +static int bne_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + int rs = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + int offset = bits (insn, 0, 15); + m_va_t new_pc; + int res; + + /* compute the new pc */ + new_pc = (cpu->pc + 4) + sign_extend (offset << 2, 18); + + /* take the branch if gpr[rs] != gpr[rt] */ + res = (cpu->gpr[rs] != cpu->gpr[rt]); + + /* exec the instruction in the delay slot */ + int ins_res = mips_exec_bdslot (cpu); + + if (likely (!ins_res)) { + /* take the branch if the test result is true */ + if (res) + cpu->pc = new_pc; + else + cpu->pc += 8; + } + + return (1); +} + +static int bnel_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + int rs = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + int offset = bits (insn, 0, 15); + m_va_t new_pc; + int res; + + /* compute the new pc */ + new_pc = (cpu->pc + 4) + sign_extend (offset << 2, 18); + + /* take the branch if gpr[rs] != gpr[rt] */ + res = (cpu->gpr[rs] != cpu->gpr[rt]); + + /* take the branch if the test result is true */ + if (res) { + mips_exec_bdslot (cpu); + cpu->pc = new_pc; + } else + cpu->pc += 8; + return (1); +} + +static int break_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + u_int code = bits (insn, 6, 25); + + mips_exec_break (cpu, code); + return (1); +} + +static int cache_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + int base = bits (insn, 21, 25); + int op = bits (insn, 16, 20); + int offset = bits (insn, 0, 15); + + return (mips_exec_memop2 (cpu, MIPS_MEMOP_CACHE, base, offset, op, + FALSE)); +} + +static int cfc0_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + return unknown_op (cpu, insn); +} + +static int clz_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + int rs = bits (insn, 21, 25); + int rd = bits (insn, 11, 15); + int i; + m_uint32_t val; + val = 32; + for (i = 31; i >= 0; i--) { + if (cpu->gpr[rs] & (1 << i)) { + val = 31 - i; + break; + } + } + cpu->reg_set (cpu, rd, val); + return (0); +} + +static int cop0_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + uint16_t special_func = bits (insn, 21, 25); +//printf ("cop0 instruction. func %x\n", special_func); + return mips_cop0_opcodes[special_func].func (cpu, insn); +} + +static int cop1_op (cpu_mips_t * cpu, mips_insn_t insn) +{ +#if SOFT_FPU + mips_exec_soft_fpu (cpu); + return (1); +#else + return unknown_op (cpu, insn); +#endif +} + +static int cop1x_op (cpu_mips_t * cpu, mips_insn_t insn) +{ +#if SOFT_FPU + mips_exec_soft_fpu (cpu); + return (1); +#else + return unknown_op (cpu, insn); +#endif +} + +static int cop2_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + return unknown_op (cpu, insn); +} + +static int dadd_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + return unknown_op (cpu, insn); +} + +static int daddi_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + return unknown_op (cpu, insn); +} + +static int daddiu_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + return unknown_op (cpu, insn); +} + +static int daddu_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + return unknown_op (cpu, insn); +} + +static int ddiv_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + return unknown_op (cpu, insn); +} + +static int ddivu_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + return unknown_op (cpu, insn); +} + +static int div_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + int rs = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + + cpu->lo = (m_int32_t) cpu->gpr[rs] / (m_int32_t) cpu->gpr[rt]; + cpu->hi = (m_int32_t) cpu->gpr[rs] % (m_int32_t) cpu->gpr[rt]; + + cpu->lo = sign_extend (cpu->lo, 32); + cpu->hi = sign_extend (cpu->hi, 32); + return (0); +} + +static int divu_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + int rs = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + + if (cpu->gpr[rt] == 0) + return (0); + + cpu->lo = (m_uint32_t) cpu->gpr[rs] / (m_uint32_t) cpu->gpr[rt]; + cpu->hi = (m_uint32_t) cpu->gpr[rs] % (m_uint32_t) cpu->gpr[rt]; + + cpu->lo = sign_extend (cpu->lo, 32); + cpu->hi = sign_extend (cpu->hi, 32); + return (0); + +} + +static int dmfc0_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + return unknown_op (cpu, insn); +} + +static int dmtc0_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + return unknown_op (cpu, insn); +} + +static int dmult_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + return unknown_op (cpu, insn); +} + +static int dmultu_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + return unknown_op (cpu, insn); +} + +static int dsll_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + return unknown_op (cpu, insn); +} + +static int dsllv_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + return unknown_op (cpu, insn); +} + +static int dsrlv_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + return unknown_op (cpu, insn); +} + +static int dsrav_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + return unknown_op (cpu, insn); +} + +static int dsub_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + return unknown_op (cpu, insn); +} + +static int dsubu_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + return unknown_op (cpu, insn); +} + +static int dsrl_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + return unknown_op (cpu, insn); +} + +static int dsra_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + return unknown_op (cpu, insn); +} + +static int dsll32_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + return unknown_op (cpu, insn); +} + +static int dsrl32_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + return unknown_op (cpu, insn); +} + +static int dsra32_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + return unknown_op (cpu, insn); +} + +static int eret_op (cpu_mips_t * cpu, mips_insn_t insn) +{ +#if 1 + if (cpu->trace_syscall && + (cpu->cp0.reg[MIPS_CP0_STATUS] & MIPS_CP0_STATUS_UM)) + { + if (cpu->gpr[2] == 0xffffffff) + printf (" syscall failed, errno %u\n", cpu->gpr[8]); + else { + if (cpu->gpr[2] & ~0xffff) + printf (" syscall returned %08x\n", cpu->gpr[2]); + else + printf (" syscall returned %u\n", cpu->gpr[2]); + } + cpu->trace_syscall = 0; + } +#endif + mips_exec_eret (cpu); + return (1); +} + +static int j_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + u_int instr_index = bits (insn, 0, 25); + m_va_t new_pc; + + /* compute the new pc */ + new_pc = cpu->pc & ~((1 << 28) - 1); + new_pc |= instr_index << 2; + + /* exec the instruction in the delay slot */ + int ins_res = mips_exec_bdslot (cpu); + if (likely (!ins_res)) + cpu->pc = new_pc; + return (1); +} + +static int jal_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + u_int instr_index = bits (insn, 0, 25); + m_va_t new_pc; + + /* compute the new pc */ + new_pc = cpu->pc & ~((1 << 28) - 1); + new_pc |= instr_index << 2; + + /* set the return address (instruction after the delay slot) */ + cpu->reg_set (cpu, MIPS_GPR_RA, cpu->pc + 8); + + int ins_res = mips_exec_bdslot (cpu); + if (likely (!ins_res)) + cpu->pc = new_pc; + + return (1); +} + +static int jalr_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + int rs = bits (insn, 21, 25); + int rd = bits (insn, 11, 15); + m_va_t new_pc; + + /* set the return pc (instruction after the delay slot) in GPR[rd] */ + cpu->reg_set (cpu, rd, cpu->pc + 8); + + /* get the new pc */ + new_pc = cpu->gpr[rs]; + + int ins_res = mips_exec_bdslot (cpu); + if (likely (!ins_res)) + cpu->pc = new_pc; + return (1); + +} + +static int jr_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + int rs = bits (insn, 21, 25); + m_va_t new_pc; + + /* get the new pc */ + new_pc = cpu->gpr[rs]; + + int ins_res = mips_exec_bdslot (cpu); + if (likely (!ins_res)) + cpu->pc = new_pc; + return (1); + +} + +static int lb_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + int base = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + int offset = bits (insn, 0, 15); + + return (mips_exec_memop2 (cpu, MIPS_MEMOP_LB, base, offset, rt, TRUE)); +} + +static int lbu_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + int base = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + int offset = bits (insn, 0, 15); + + return (mips_exec_memop2 (cpu, MIPS_MEMOP_LBU, base, offset, rt, TRUE)); +} + +static int ld_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + return unknown_op (cpu, insn); +} + +static int ldc1_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + return unknown_op (cpu, insn); +} + +static int ldc2_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + return unknown_op (cpu, insn); +} + +static int ldl_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + return unknown_op (cpu, insn); +} + +static int ldr_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + return unknown_op (cpu, insn); +} + +static int lh_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + int base = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + int offset = bits (insn, 0, 15); + + return (mips_exec_memop2 (cpu, MIPS_MEMOP_LH, base, offset, rt, TRUE)); +} + +static int lhu_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + int base = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + int offset = bits (insn, 0, 15); + + return (mips_exec_memop2 (cpu, MIPS_MEMOP_LHU, base, offset, rt, TRUE)); +} + +static int ll_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + int base = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + int offset = bits (insn, 0, 15); + + return (mips_exec_memop2 (cpu, MIPS_MEMOP_LL, base, offset, rt, TRUE)); +} + +static int lld_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + return unknown_op (cpu, insn); +} + +static int lui_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + int rt = bits (insn, 16, 20); + int imm = bits (insn, 0, 15); + + cpu->reg_set (cpu, rt, sign_extend (imm, 16) << 16); + return (0); +} + +static int lw_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + int base = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + int offset = bits (insn, 0, 15); + + return (mips_exec_memop2 (cpu, MIPS_MEMOP_LW, base, offset, rt, TRUE)); + +} + +static int lwc1_op (cpu_mips_t * cpu, mips_insn_t insn) +{ +#if SOFT_FPU + mips_exec_soft_fpu (cpu); + return (1); +#else + return unknown_op (cpu, insn); +#endif + +} + +static int lwc2_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + return unknown_op (cpu, insn); +} + +static int lwl_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + int base = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + int offset = bits (insn, 0, 15); + + return (mips_exec_memop2 (cpu, MIPS_MEMOP_LWL, base, offset, rt, TRUE)); + +} + +static int lwr_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + int base = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + int offset = bits (insn, 0, 15); + + return (mips_exec_memop2 (cpu, MIPS_MEMOP_LWR, base, offset, rt, TRUE)); +} + +static int lwu_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + int base = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + int offset = bits (insn, 0, 15); + + return (mips_exec_memop2 (cpu, MIPS_MEMOP_LWU, base, offset, rt, TRUE)); +} + +static int spec3_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + int index = bits (insn, 0, 5); + return mips_spec3_opcodes[index].func (cpu, insn); +} + +static int bshfl_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + int rt = bits (insn, 16, 20); + int rd = bits (insn, 11, 15); + int sa = bits (insn, 6, 10); +//printf ("seh rt=%d, rd=%d, sa=%x\n", rt, rd, sa); + switch (sa) { + case 0x02: + /* wsbh - word swap bytes within halfwords */ + cpu->reg_set (cpu, rd, bits (cpu->gpr[rt], 16, 23) << 24 | + bits (cpu->gpr[rt], 24, 31) << 16 | + bits (cpu->gpr[rt], 0, 7) << 8 | + bits (cpu->gpr[rt], 8, 15)); + return (0); + case 0x10: + /* seb - sign extend byte */ + cpu->reg_set (cpu, rd, sign_extend (cpu->gpr[rt], 8)); + return (0); + case 0x18: + /* seh - sign extend halfword */ + cpu->reg_set (cpu, rd, sign_extend (cpu->gpr[rt], 16)); + return (0); + } + return unknown_op (cpu, insn); +} + +static int ext_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + int rs = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + int msbd = bits (insn, 11, 15); + int lsb = bits (insn, 6, 10); + + /* Extract bit field */ + cpu->reg_set (cpu, rt, (cpu->gpr[rs] >> lsb) & (~0U >> (31 - msbd))); + return (0); +} + +static int ins_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + int rs = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + int msb = bits (insn, 11, 15); + int lsb = bits (insn, 6, 10); + + /* Insert bit field */ + int mask = ~0U >> (31-msb+lsb) << lsb; + cpu->gpr[rt] &= ~mask; + cpu->gpr[rt] |= (cpu->gpr[rs] << lsb) & mask; + return (0); +} + +static int spec2_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + int index = bits (insn, 0, 5); + return mips_spec2_opcodes[index].func (cpu, insn); +} + +static int madd_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + int rs = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + m_int64_t val, temp; + + val = (m_int32_t) (m_int32_t) cpu->gpr[rs]; + val *= (m_int32_t) (m_int32_t) cpu->gpr[rt]; + + temp = cpu->hi; + temp = temp << 32; + temp += cpu->lo; + val += temp; + + cpu->lo = sign_extend (val, 32); + cpu->hi = sign_extend (val >> 32, 32); + return (0); +} + +static int maddu_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + int rs = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + m_int64_t val, temp; + + val = (m_uint32_t) (m_uint32_t) cpu->gpr[rs]; + val *= (m_uint32_t) (m_uint32_t) cpu->gpr[rt]; + + temp = cpu->hi; + temp = temp << 32; + temp += cpu->lo; + val += temp; + + cpu->lo = sign_extend (val, 32); + cpu->hi = sign_extend (val >> 32, 32); + return (0); +} + +static int mfc0_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + int rt = bits (insn, 16, 20); + int rd = bits (insn, 11, 15); + int sel = bits (insn, 0, 2); + //mfc rt,rd + + mips_cp0_exec_mfc0 (cpu, rt, rd, sel); + return (0); +} + +static int mfhi_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + int rd = bits (insn, 11, 15); + + if (rd) + cpu->reg_set (cpu, rd, cpu->hi); + return (0); +} + +static int mflo_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + int rd = bits (insn, 11, 15); + + if (rd) + cpu->reg_set (cpu, rd, cpu->lo); + return (0); +} + +static int movc_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + return unknown_op (cpu, insn); +} + +static int movz_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + int rs = bits (insn, 21, 25); + int rd = bits (insn, 11, 15); + int rt = bits (insn, 16, 20); + + if ((cpu->gpr[rt]) == 0) + cpu->reg_set (cpu, rd, sign_extend (cpu->gpr[rs], 32)); + return (0); +} + +static int movn_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + int rs = bits (insn, 21, 25); + int rd = bits (insn, 11, 15); + int rt = bits (insn, 16, 20); + + // printf("pc %x rs %x rd %x rt %x\n",cpu->pc,rs,rd,rt); + if ((cpu->gpr[rt]) != 0) + cpu->reg_set (cpu, rd, sign_extend (cpu->gpr[rs], 32)); + return (0); +} + +static int msub_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + int rs = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + m_int64_t val, temp; + + val = (m_int32_t) (m_int32_t) cpu->gpr[rs]; + val *= (m_int32_t) (m_int32_t) cpu->gpr[rt]; + + temp = cpu->hi; + temp = temp << 32; + temp += cpu->lo; + + temp -= val; + //val += temp; + + cpu->lo = sign_extend (temp, 32); + cpu->hi = sign_extend (temp >> 32, 32); + return (0); +} + +static int msubu_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + int rs = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + m_int64_t val, temp; + + val = (m_uint32_t) (m_uint32_t) cpu->gpr[rs]; + val *= (m_uint32_t) (m_uint32_t) cpu->gpr[rt]; + + temp = cpu->hi; + temp = temp << 32; + temp += cpu->lo; + + temp -= val; + //val += temp; + + cpu->lo = sign_extend (temp, 32); + cpu->hi = sign_extend (temp >> 32, 32); + return (0); +} + +static int mtc0_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + int rt = bits (insn, 16, 20); + int rd = bits (insn, 11, 15); + int sel = bits (insn, 0, 2); + + //printf("cpu->pc %x insn %x\n",cpu->pc,insn); + mips_cp0_exec_mtc0 (cpu, rt, rd, sel); + return (0); +} + +static int mthi_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + int rs = bits (insn, 21, 25); + + cpu->hi = cpu->gpr[rs]; + return (0); +} + +static int mtlo_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + int rs = bits (insn, 21, 25); + + cpu->lo = cpu->gpr[rs]; + return (0); +} + +static int mul_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + int rs = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + int rd = bits (insn, 11, 15); + m_int32_t val; + + /* note: after this instruction, HI/LO regs are undefined */ + val = (m_int32_t) cpu->gpr[rs] * (m_int32_t) cpu->gpr[rt]; + cpu->reg_set (cpu, rd, sign_extend (val, 32)); + return (0); +} + +static int mult_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + int rs = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + m_int64_t val; + + val = (m_int64_t) (m_int32_t) cpu->gpr[rs]; + val *= (m_int64_t) (m_int32_t) cpu->gpr[rt]; + + cpu->lo = sign_extend (val, 32); + cpu->hi = sign_extend (val >> 32, 32); + return (0); +} + +static int multu_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + int rs = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + m_int64_t val; //must be 64 bit. not m_reg_t !!! + + val = (m_reg_t) (m_uint32_t) cpu->gpr[rs]; + val *= (m_reg_t) (m_uint32_t) cpu->gpr[rt]; + cpu->lo = sign_extend (val, 32); + cpu->hi = sign_extend (val >> 32, 32); + return (0); +} + +static int nor_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + int rs = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + int rd = bits (insn, 11, 15); + + cpu->reg_set (cpu, rd, ~(cpu->gpr[rs] | cpu->gpr[rt])); + return (0); +} + +static int or_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + int rs = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + int rd = bits (insn, 11, 15); + + cpu->reg_set (cpu, rd, cpu->gpr[rs] | cpu->gpr[rt]); + return (0); +} + +static int ori_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + int rs = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + int imm = bits (insn, 0, 15); + + cpu->reg_set (cpu, rt, cpu->gpr[rs] | imm); + return (0); +} + +static int pref_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + return (0); +} + +static int sb_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + int base = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + int offset = bits (insn, 0, 15); + return (mips_exec_memop2 (cpu, MIPS_MEMOP_SB, base, offset, rt, FALSE)); +} + +static int sc_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + int base = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + int offset = bits (insn, 0, 15); + + return (mips_exec_memop2 (cpu, MIPS_MEMOP_SC, base, offset, rt, TRUE)); +} + +static int scd_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + return unknown_op (cpu, insn); +} + +static int sd_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + return unknown_op (cpu, insn); +} + +static int sdc1_op (cpu_mips_t * cpu, mips_insn_t insn) +{ +#if SOFT_FPU + mips_exec_soft_fpu (cpu); + return (1); +#else + return unknown_op (cpu, insn); +#endif +} + +static int sdc2_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + return unknown_op (cpu, insn); +} + +static int sdl_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + return unknown_op (cpu, insn); +} + +static int sdr_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + return unknown_op (cpu, insn); +} + +static int sh_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + int base = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + int offset = bits (insn, 0, 15); + + return (mips_exec_memop2 (cpu, MIPS_MEMOP_SH, base, offset, rt, FALSE)); +} + +static int sll_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + int rt = bits (insn, 16, 20); + int rd = bits (insn, 11, 15); + int sa = bits (insn, 6, 10); + m_uint32_t res; + + res = (m_uint32_t) cpu->gpr[rt] << sa; + cpu->reg_set (cpu, rd, sign_extend (res, 32)); + return (0); +} + +static int sllv_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + int rs = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + int rd = bits (insn, 11, 15); + m_uint32_t res; + + res = (m_uint32_t) cpu->gpr[rt] << (cpu->gpr[rs] & 0x1f); + cpu->reg_set (cpu, rd, sign_extend (res, 32)); + return (0); +} + +static int slt_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + int rs = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + int rd = bits (insn, 11, 15); + + if ((m_ireg_t) cpu->gpr[rs] < (m_ireg_t) cpu->gpr[rt]) + cpu->reg_set (cpu, rd, 1); + else + cpu->reg_set (cpu, rd, 0); + return (0); +} + +static int slti_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + int rs = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + int imm = bits (insn, 0, 15); + m_ireg_t val = sign_extend (imm, 16); + + if ((m_ireg_t) cpu->gpr[rs] < val) + cpu->reg_set (cpu, rt, 1); + else + cpu->reg_set (cpu, rt, 0); + return (0); +} + +static int sltiu_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + int rs = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + int imm = bits (insn, 0, 15); + m_reg_t val = sign_extend (imm, 16); + + if (cpu->gpr[rs] < val) + cpu->reg_set (cpu, rt, 1); + else + cpu->reg_set (cpu, rt, 0); + return (0); +} + +static int sltu_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + int rs = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + int rd = bits (insn, 11, 15); + + if (cpu->gpr[rs] < cpu->gpr[rt]) + cpu->reg_set (cpu, rd, 1); + else + cpu->reg_set (cpu, rd, 0); + return (0); +} + +static int spec_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + uint16_t special_func = bits (insn, 0, 5); + return mips_spec_opcodes[special_func].func (cpu, insn); +} + +static int sra_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + int rt = bits (insn, 16, 20); + int rd = bits (insn, 11, 15); + int sa = bits (insn, 6, 10); + m_int32_t res; + + res = (m_int32_t) cpu->gpr[rt] >> sa; + cpu->reg_set (cpu, rd, sign_extend (res, 32)); + return (0); +} + +static int srav_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + int rs = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + int rd = bits (insn, 11, 15); + m_int32_t res; + + res = (m_int32_t) cpu->gpr[rt] >> (cpu->gpr[rs] & 0x1f); + cpu->reg_set (cpu, rd, sign_extend (res, 32)); + return (0); +} + +static int srl_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + int rt = bits (insn, 16, 20); + int rd = bits (insn, 11, 15); + int sa = bits (insn, 6, 10); + m_uint32_t res; + + /* srl */ + res = (m_uint32_t) cpu->gpr[rt] >> sa; + if ((insn >> 21) & 1) { + /* rotr */ + res |= (m_uint32_t) cpu->gpr[rt] << (32 - sa); + } + cpu->reg_set (cpu, rd, sign_extend (res, 32)); + return (0); +} + +static int srlv_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + int rs = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + int rd = bits (insn, 11, 15); + m_uint32_t res, sa; + + /* srlv */ + sa = cpu->gpr[rs] & 0x1f; + res = (m_uint32_t) cpu->gpr[rt] >> sa; + if ((insn >> 6) & 1) { + /* rotrv */ + res |= (m_uint32_t) cpu->gpr[rt] << (32 - sa); + } + cpu->reg_set (cpu, rd, sign_extend (res, 32)); + return (0); +} + +static int sub_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + int rs = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + int rd = bits (insn, 11, 15); + m_uint32_t res; + + /* TODO: Exception handling */ + res = (m_uint32_t) cpu->gpr[rs] - (m_uint32_t) cpu->gpr[rt]; + cpu->reg_set (cpu, rd, sign_extend (res, 32)); + return (0); +} + +static int subu_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + int rs = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + int rd = bits (insn, 11, 15); + m_uint32_t res; + res = (m_uint32_t) cpu->gpr[rs] - (m_uint32_t) cpu->gpr[rt]; + cpu->reg_set (cpu, rd, sign_extend (res, 32)); + return (0); +} + +static int sw_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + int base = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + int offset = bits (insn, 0, 15); + + return (mips_exec_memop2 (cpu, MIPS_MEMOP_SW, base, offset, rt, FALSE)); +} + +static int swc1_op (cpu_mips_t * cpu, mips_insn_t insn) +{ +#if SOFT_FPU + mips_exec_soft_fpu (cpu); + return (1); +#else + return unknown_op (cpu, insn); +#endif +} + +static int swc2_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + return unknown_op (cpu, insn); +} + +static int swl_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + int base = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + int offset = bits (insn, 0, 15); + + return (mips_exec_memop2 (cpu, MIPS_MEMOP_SWL, base, offset, rt, + FALSE)); +} + +static int swr_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + int base = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + int offset = bits (insn, 0, 15); + + return (mips_exec_memop2 (cpu, MIPS_MEMOP_SWR, base, offset, rt, + FALSE)); +} + +static int sync_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + return (0); +} + +static int syscall_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + mips_exec_syscall (cpu); + return (1); +} + +static int teq_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + int rs = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + + if (unlikely (cpu->gpr[rs] == cpu->gpr[rt])) { + mips_trigger_trap_exception (cpu); + return (1); + } + return (0); +} + +static int teqi_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + int rs = bits (insn, 21, 25); + int imm = bits (insn, 0, 15); + m_reg_t val = sign_extend (imm, 16); + + if (unlikely (cpu->gpr[rs] == val)) { + mips_trigger_trap_exception (cpu); + return (1); + } + return (0); +} + +static int mfmc0_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + int rt = bits (insn, 16, 20); + int rd = bits (insn, 11, 15); + int func = bits (insn, 0, 5); + + if (rd != 12) + return unknown_op (cpu, insn); + + cpu->reg_set (cpu, rt, cpu->cp0.reg [MIPS_CP0_STATUS]); + if (func & 0x20) { + /* ei - enable interrupts */ + cpu->cp0.reg [MIPS_CP0_STATUS] |= MIPS_CP0_STATUS_IE; + } else { + /* di - disable interrupts */ + cpu->cp0.reg [MIPS_CP0_STATUS] &= ~MIPS_CP0_STATUS_IE; + } + return 0; +} + +static int tlb_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + uint16_t func = bits (insn, 0, 5); + return mips_tlb_opcodes[func].func (cpu, insn); +} + +static int tlbp_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + mips_cp0_exec_tlbp (cpu); + return (0); +} + +static int tlbr_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + mips_cp0_exec_tlbr (cpu); + return (0); +} + +static int tlbwi_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + mips_cp0_exec_tlbwi (cpu); + return (0); +} + +static int tlbwr_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + mips_cp0_exec_tlbwr (cpu); + return (0); +} + +static int tge_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + return unknown_op (cpu, insn); +} + +static int tgei_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + return unknown_op (cpu, insn); +} + +static int tgeiu_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + return unknown_op (cpu, insn); +} + +static int tgeu_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + return unknown_op (cpu, insn); +} + +static int tlt_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + return unknown_op (cpu, insn); +} + +static int tlti_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + return unknown_op (cpu, insn); +} + +static int tltiu_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + return unknown_op (cpu, insn); +} + +static int tltu_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + return unknown_op (cpu, insn); +} + +static int tne_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + int rs = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + + if ((m_ireg_t) cpu->gpr[rs] != (m_ireg_t) cpu->gpr[rt]) { + /*take a trap */ + mips_trigger_trap_exception (cpu); + return (1); + } else + return (0); +} + +static int tnei_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + return unknown_op (cpu, insn); +} + +static int wait_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + if (! (cpu->cp0.reg [MIPS_CP0_STATUS] & MIPS_CP0_STATUS_IE)) { + /* Wait instruction with interrupts disabled - stop the simulator. */ + printf ("%08x: wait instruction with interrupts disabled - stop the simulator.\n", + cpu->pc); + kill (0, SIGQUIT); + } + usleep (1000); + return (0); +} + +static int xor_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + int rs = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + int rd = bits (insn, 11, 15); + + cpu->reg_set (cpu, rd, cpu->gpr[rs] ^ cpu->gpr[rt]); + return (0); +} + +static int rdpgpr_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + int rt = bits (insn, 16, 20); + int rd = bits (insn, 11, 15); + + printf ("%08x: unsupported RDPGPR $%u,$%u instruction.\n", cpu->pc, rd, rt); + return (0); +} + +static int wrpgpr_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + int rt = bits (insn, 16, 20); + int rd = bits (insn, 11, 15); + + printf ("%08x: unsupported WRPGPR $%u,$%u instruction.\n", cpu->pc, rd, rt); + return (0); +} + +static int xori_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + int rs = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + int imm = bits (insn, 0, 15); + + cpu->reg_set (cpu, rt, cpu->gpr[rs] ^ imm); + return (0); +} + +static int undef_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + return unknown_op (cpu, insn); +} + +static int undef_bcond (cpu_mips_t * cpu, mips_insn_t insn) +{ + return unknown_op (cpu, insn); +} + +static int undef_cop0 (cpu_mips_t * cpu, mips_insn_t insn) +{ + return unknown_op (cpu, insn); +} + +static int undef_spec2 (cpu_mips_t * cpu, mips_insn_t insn) +{ + return unknown_op (cpu, insn); +} + +static int undef_spec3 (cpu_mips_t * cpu, mips_insn_t insn) +{ + return unknown_op (cpu, insn); +} + +static int undef_spec (cpu_mips_t * cpu, mips_insn_t insn) +{ + return unknown_op (cpu, insn); +} + +static int undef_tlb (cpu_mips_t * cpu, mips_insn_t insn) +{ + return unknown_op (cpu, insn); +} + +/* + * Main instruction table. + */ +static const struct mips_op_desc mips_opcodes[] = { + {"spec", spec_op, 0x00}, /* indexed by FUNC field */ + {"bcond", bcond_op, 0x01}, /* indexed by RT field */ + {"j", j_op, 0x02}, + {"jal", jal_op, 0x03}, + {"beq", beq_op, 0x04}, + {"bne", bne_op, 0x05}, + {"blez", blez_op, 0x06}, + {"bgtz", bgtz_op, 0x07}, + {"addi", addi_op, 0x08}, + {"addiu", addiu_op, 0x09}, + {"slti", slti_op, 0x0A}, + {"sltiu", sltiu_op, 0x0B}, + {"andi", andi_op, 0x0C}, + {"ori", ori_op, 0x0D}, + {"xori", xori_op, 0x0E}, + {"lui", lui_op, 0x0F}, + {"cop0", cop0_op, 0x10}, /* indexed by RS field */ + {"cop1", cop1_op, 0x11}, + {"cop2", cop2_op, 0x12}, + {"cop1x", cop1x_op, 0x13}, + {"beql", beql_op, 0x14}, + {"bnel", bnel_op, 0x15}, + {"blezl", blezl_op, 0x16}, + {"bgtzl", bgtzl_op, 0x17}, + {"daddi", daddi_op, 0x18}, + {"daddiu", daddiu_op, 0x19}, + {"ldl", ldl_op, 0x1A}, + {"ldr", ldr_op, 0x1B}, + {"spec2", spec2_op, 0x1C}, /* indexed by FUNC field */ + {"undef", undef_op, 0x1D}, + {"undef", undef_op, 0x1E}, + {"spec3", spec3_op, 0x1F}, /* indexed by FUNC field */ + {"lb", lb_op, 0x20}, + {"lh", lh_op, 0x21}, + {"lwl", lwl_op, 0x22}, + {"lw", lw_op, 0x23}, + {"lbu", lbu_op, 0x24}, + {"lhu", lhu_op, 0x25}, + {"lwr", lwr_op, 0x26}, + {"lwu", lwu_op, 0x27}, + {"sb", sb_op, 0x28}, + {"sh", sh_op, 0x29}, + {"swl", swl_op, 0x2A}, + {"sw", sw_op, 0x2B}, + {"sdl", sdl_op, 0x2C}, + {"sdr", sdr_op, 0x2D}, + {"swr", swr_op, 0x2E}, + {"cache", cache_op, 0x2F}, + {"ll", ll_op, 0x30}, + {"lwc1", lwc1_op, 0x31}, + {"lwc2", lwc2_op, 0x32}, + {"pref", pref_op, 0x33}, + {"lld", lld_op, 0x34}, + {"ldc1", ldc1_op, 0x35}, + {"ldc2", ldc2_op, 0x36}, + {"ld", ld_op, 0x37}, + {"sc", sc_op, 0x38}, + {"swc1", swc1_op, 0x39}, + {"swc2", swc2_op, 0x3A}, + {"undef", undef_op, 0x3B}, + {"scd", scd_op, 0x3C}, + {"sdc1", sdc1_op, 0x3D}, + {"sdc2", sdc2_op, 0x3E}, + {"sd", sd_op, 0x3F}, +}; + +/* + * SPEC opcode: indexed by FUNC field. + */ +static const struct mips_op_desc mips_spec_opcodes[] = { + {"sll", sll_op, 0x00}, + {"movc", movc_op, 0x01}, + {"srl", srl_op, 0x02}, + {"sra", sra_op, 0x03}, + {"sllv", sllv_op, 0x04}, + {"?spec", undef_spec, 0x05}, + {"srlv", srlv_op, 0x06}, + {"srav", srav_op, 0x07}, + {"jr", jr_op, 0x08}, + {"jalr", jalr_op, 0x09}, + {"movz", movz_op, 0x0A}, + {"movn", movn_op, 0x0B}, + {"syscall", syscall_op, 0x0C}, + {"break", break_op, 0x0D}, + {"spim", undef_spec, 0x0E}, + {"sync", sync_op, 0x0F}, + {"mfhi", mfhi_op, 0x10}, + {"mthi", mthi_op, 0x11}, + {"mflo", mflo_op, 0x12}, + {"mtlo", mtlo_op, 0x13}, + {"dsllv", dsllv_op, 0x14}, + {"?spec", undef_spec, 0x15}, + {"dsrlv", dsrlv_op, 0x16}, + {"dsrav", dsrav_op, 0x17}, + {"mult", mult_op, 0x18}, + {"multu", multu_op, 0x19}, + {"div", div_op, 0x1A}, + {"divu", divu_op, 0x1B}, + {"dmult", dmult_op, 0x1C}, + {"dmultu", dmultu_op, 0x1D}, + {"ddiv", ddiv_op, 0x1E}, + {"ddivu", ddivu_op, 0x1F}, + {"add", add_op, 0x20}, + {"addu", addu_op, 0x21}, + {"sub", sub_op, 0x22}, + {"subu", subu_op, 0x23}, + {"and", and_op, 0x24}, + {"or", or_op, 0x25}, + {"xor", xor_op, 0x26}, + {"nor", nor_op, 0x27}, + {"?spec", undef_spec, 0x28}, + {"?spec", undef_spec, 0x29}, + {"slt", slt_op, 0x2A}, + {"sltu", sltu_op, 0x2B}, + {"dadd", dadd_op, 0x2C}, + {"daddu", daddu_op, 0x2D}, + {"dsub", dsub_op, 0x2E}, + {"dsubu", dsubu_op, 0x2F}, + {"tge", tge_op, 0x30}, + {"tgeu", tgeu_op, 0x31}, + {"tlt", tlt_op, 0x32}, + {"tltu", tltu_op, 0x33}, + {"teq", teq_op, 0x34}, + {"?spec", undef_spec, 0x35}, + {"tne", tne_op, 0x36}, + {"?spec", undef_spec, 0x37}, + {"dsll", dsll_op, 0x38}, + {"?spec", undef_spec, 0x39}, + {"dsrl", dsrl_op, 0x3A}, + {"dsra", dsra_op, 0x3B}, + {"dsll32", dsll32_op, 0x3C}, + {"?spec", undef_spec, 0x3D}, + {"dsrl32", dsrl32_op, 0x3E}, + {"dsra32", dsra32_op, 0x3F} +}; + +/* + * BCOND opcode: indexed by RT field. + */ +static const struct mips_op_desc mips_bcond_opcodes[] = { + {"bltz", bltz_op, 0x00}, + {"bgez", bgez_op, 0x01}, + {"bltzl", bltzl_op, 0x02}, + {"bgezl", bgezl_op, 0x03}, + {"spimi", undef_bcond,0x04}, + {"?bcond", undef_bcond,0x05}, + {"?bcond", undef_bcond,0x06}, + {"?bcond", undef_bcond,0x07}, + {"tgei", tgei_op, 0x08}, + {"tgeiu", tgeiu_op, 0x09}, + {"tlti", tlti_op, 0x0A}, + {"tltiu", tltiu_op, 0x0B}, + {"teqi", teqi_op, 0x0C}, + {"?bcond", undef_bcond,0x0D}, + {"tnei", tnei_op, 0x0E}, + {"?bcond", undef_bcond,0x0F}, + {"bltzal", bltzal_op, 0x10}, + {"bgezal", bgezal_op, 0x11}, + {"bltzall", bltzall_op, 0x12}, + {"bgezall", bgezall_op, 0x13}, + {"?bcond", undef_bcond,0x14}, + {"?bcond", undef_bcond,0x15}, + {"?bcond", undef_bcond,0x16}, + {"?bcond", undef_bcond,0x17}, + {"?bcond", undef_bcond,0x18}, + {"?bcond", undef_bcond,0x19}, + {"?bcond", undef_bcond,0x1A}, + {"?bcond", undef_bcond,0x1B}, + {"?bcond", undef_bcond,0x1C}, + {"?bcond", undef_bcond,0x1D}, + {"?bcond", undef_bcond,0x1E}, + {"?bcond", undef_bcond,0x1F} +}; + +/* + * COP0 opcode: indexed by RS field. + */ +static const struct mips_op_desc mips_cop0_opcodes[] = { + {"mfc0", mfc0_op, 0x0}, + {"dmfc0", dmfc0_op, 0x1}, + {"cfc0", cfc0_op, 0x2}, + {"?cop0", undef_cop0, 0x3}, + {"mtc0", mtc0_op, 0x4}, + {"dmtc0", dmtc0_op, 0x5}, + {"?cop0", undef_cop0, 0x6}, + {"?cop0", undef_cop0, 0x7}, + {"?cop0", undef_cop0, 0x8}, + {"?cop0", undef_cop0, 0x9}, + {"?cop0", rdpgpr_op, 0xa}, + {"?cop0", mfmc0_op, 0xb}, + {"?cop0", undef_cop0, 0xc}, + {"?cop0", undef_cop0, 0xd}, + {"wrpgpr", wrpgpr_op, 0xe}, + {"?cop0", undef_cop0, 0xf}, + {"tlb", tlb_op, 0x10}, /* indexed by FUNC field */ + {"?cop0", undef_cop0, 0x11}, + {"?cop0", undef_cop0, 0x12}, + {"?cop0", undef_cop0, 0x13}, + {"?cop0", undef_cop0, 0x14}, + {"?cop0", undef_cop0, 0x15}, + {"?cop0", undef_cop0, 0x16}, + {"?cop0", undef_cop0, 0x17}, + {"?cop0", undef_cop0, 0x18}, + {"?cop0", undef_cop0, 0x19}, + {"?cop0", undef_cop0, 0x1a}, + {"?cop0", undef_cop0, 0x1b}, + {"?cop0", undef_cop0, 0x1c}, + {"?cop0", undef_cop0, 0x1d}, + {"?cop0", undef_cop0, 0x1e}, + {"?cop0", undef_cop0, 0x1f}, +}; + +/* + * SPEC2 opcode: indexed by FUNC field. + */ +static const struct mips_op_desc mips_spec2_opcodes[] = { + {"madd", madd_op, 0x0}, + {"maddu", maddu_op, 0x1}, + {"mul", mul_op, 0x2}, + {"?spec2", undef_spec2,0x3}, + {"msub", msub_op, 0x4}, + {"msubu", msubu_op, 0x5}, + {"?spec2", undef_spec2,0x6}, + {"?spec2", undef_spec2,0x7}, + {"?spec2", undef_spec2,0x8}, + {"?spec2", undef_spec2,0x9}, + {"?spec2", undef_spec2,0xa}, + {"?spec2", undef_spec2,0xb}, + {"?spec2", undef_spec2,0xc}, + {"?spec2", undef_spec2,0xd}, + {"?spec2", undef_spec2,0xe}, + {"?spec2", undef_spec2,0xf}, + {"?spec2", undef_spec2,0x10}, + {"?spec2", undef_spec2,0x11}, + {"?spec2", undef_spec2,0x12}, + {"?spec2", undef_spec2,0x13}, + {"?spec2", undef_spec2,0x14}, + {"?spec2", undef_spec2,0x15}, + {"?spec2", undef_spec2,0x16}, + {"?spec2", undef_spec2,0x17}, + {"?spec2", undef_spec2,0x18}, + {"?spec2", undef_spec2,0x19}, + {"?spec2", undef_spec2,0x1a}, + {"?spec2", undef_spec2,0x1b}, + {"?spec2", undef_spec2,0x1c}, + {"?spec2", undef_spec2,0x1d}, + {"?spec2", undef_spec2,0x1e}, + {"?spec2", undef_spec2,0x1f}, + {"clz", clz_op, 0x20}, + {"?spec2", undef_spec2,0x21}, + {"?spec2", undef_spec2,0x22}, + {"?spec2", undef_spec2,0x23}, + {"?spec2", undef_spec2,0x24}, + {"?spec2", undef_spec2,0x25}, + {"?spec2", undef_spec2,0x26}, + {"?spec2", undef_spec2,0x27}, + {"?spec2", undef_spec2,0x28}, + {"?spec2", undef_spec2,0x29}, + {"?spec2", undef_spec2,0x2a}, + {"?spec2", undef_spec2,0x2b}, + {"?spec2", undef_spec2,0x2c}, + {"?spec2", undef_spec2,0x2d}, + {"?spec2", undef_spec2,0x2e}, + {"?spec2", undef_spec2,0x2f}, + {"?spec2", undef_spec2,0x30}, + {"?spec2", undef_spec2,0x31}, + {"?spec2", undef_spec2,0x32}, + {"?spec2", undef_spec2,0x33}, + {"?spec2", undef_spec2,0x34}, + {"?spec2", undef_spec2,0x35}, + {"?spec2", undef_spec2,0x36}, + {"?spec2", undef_spec2,0x37}, + {"?spec2", undef_spec2,0x38}, + {"?spec2", undef_spec2,0x39}, + {"?spec2", undef_spec2,0x3a}, + {"?spec2", undef_spec2,0x3b}, + {"?spec2", undef_spec2,0x3c}, + {"?spec2", undef_spec2,0x3d}, + {"?spec2", undef_spec2,0x3e}, + {"?spec2", undef_spec2,0x3f}, +}; + +/* + * SPEC3 opcode: indexed by FUNC field. + */ +static const struct mips_op_desc mips_spec3_opcodes[] = { + {"ext", ext_op, 0x0}, + {"?spec3", undef_spec3,0x1}, + {"?spec3", undef_spec3,0x2}, + {"?spec3", undef_spec3,0x3}, + {"ins", ins_op, 0x4}, + {"?spec3", undef_spec3,0x5}, + {"?spec3", undef_spec3,0x6}, + {"?spec3", undef_spec3,0x7}, + {"?spec3", undef_spec3,0x8}, + {"?spec3", undef_spec3,0x9}, + {"?spec3", undef_spec3,0xa}, + {"?spec3", undef_spec3,0xb}, + {"?spec3", undef_spec3,0xc}, + {"?spec3", undef_spec3,0xd}, + {"?spec3", undef_spec3,0xe}, + {"?spec3", undef_spec3,0xf}, + {"?spec3", undef_spec3,0x10}, + {"?spec3", undef_spec3,0x11}, + {"?spec3", undef_spec3,0x12}, + {"?spec3", undef_spec3,0x13}, + {"?spec3", undef_spec3,0x14}, + {"?spec3", undef_spec3,0x15}, + {"?spec3", undef_spec3,0x16}, + {"?spec3", undef_spec3,0x17}, + {"?spec3", undef_spec3,0x18}, + {"?spec3", undef_spec3,0x19}, + {"?spec3", undef_spec3,0x1a}, + {"?spec3", undef_spec3,0x1b}, + {"?spec3", undef_spec3,0x1c}, + {"?spec3", undef_spec3,0x1d}, + {"?spec3", undef_spec3,0x1e}, + {"?spec3", undef_spec3,0x1f}, + {"bshfl", bshfl_op, 0x20}, + {"?spec3", undef_spec3,0x21}, + {"?spec3", undef_spec3,0x22}, + {"?spec3", undef_spec3,0x23}, + {"?spec3", undef_spec3,0x24}, + {"?spec3", undef_spec3,0x25}, + {"?spec3", undef_spec3,0x26}, + {"?spec3", undef_spec3,0x27}, + {"?spec3", undef_spec3,0x28}, + {"?spec3", undef_spec3,0x29}, + {"?spec3", undef_spec3,0x2a}, + {"?spec3", undef_spec3,0x2b}, + {"?spec3", undef_spec3,0x2c}, + {"?spec3", undef_spec3,0x2d}, + {"?spec3", undef_spec3,0x2e}, + {"?spec3", undef_spec3,0x2f}, + {"?spec3", undef_spec3,0x30}, + {"?spec3", undef_spec3,0x31}, + {"?spec3", undef_spec3,0x32}, + {"?spec3", undef_spec3,0x33}, + {"?spec3", undef_spec3,0x34}, + {"?spec3", undef_spec3,0x35}, + {"?spec3", undef_spec3,0x36}, + {"?spec3", undef_spec3,0x37}, + {"?spec3", undef_spec3,0x38}, + {"?spec3", undef_spec3,0x39}, + {"?spec3", undef_spec3,0x3a}, + {"?spec3", undef_spec3,0x3b}, + {"?spec3", undef_spec3,0x3c}, + {"?spec3", undef_spec3,0x3d}, + {"?spec3", undef_spec3,0x3e}, + {"?spec3", undef_spec3,0x3f}, +}; + +/* + * TLB opcode: indexed by FUNC field. + */ +static const struct mips_op_desc mips_tlb_opcodes[] = { + {"?tlb", undef_tlb, 0x0}, + {"tlbr", tlbr_op, 0x1}, + {"tlbwi", tlbwi_op, 0x2}, + {"?tlb", undef_tlb, 0x3}, + {"?tlb", undef_tlb, 0x4}, + {"?tlb", undef_tlb, 0x5}, + {"tlbwi", tlbwr_op, 0x6}, + {"?tlb", undef_tlb, 0x7}, + {"tlbp", tlbp_op, 0x8}, + {"?tlb", undef_tlb, 0x9}, + {"?tlb", undef_tlb, 0xa}, + {"?tlb", undef_tlb, 0xb}, + {"?tlb", undef_tlb, 0xc}, + {"?tlb", undef_tlb, 0xd}, + {"?tlb", undef_tlb, 0xe}, + {"?tlb", undef_tlb, 0xf}, + {"?tlb", undef_tlb, 0x10}, + {"?tlb", undef_tlb, 0x11}, + {"?tlb", undef_tlb, 0x12}, + {"?tlb", undef_tlb, 0x13}, + {"?tlb", undef_tlb, 0x14}, + {"?tlb", undef_tlb, 0x15}, + {"?tlb", undef_tlb, 0x16}, + {"?tlb", undef_tlb, 0x17}, + {"eret", eret_op, 0x18}, + {"?tlb", undef_tlb, 0x19}, + {"?tlb", undef_tlb, 0x1a}, + {"?tlb", undef_tlb, 0x1b}, + {"?tlb", undef_tlb, 0x1c}, + {"?tlb", undef_tlb, 0x1d}, + {"?tlb", undef_tlb, 0x1e}, + {"?tlb", undef_tlb, 0x1f}, + {"wait", wait_op, 0x20}, + {"?tlb", undef_tlb, 0x21}, + {"?tlb", undef_tlb, 0x22}, + {"?tlb", undef_tlb, 0x23}, + {"?tlb", undef_tlb, 0x24}, + {"?tlb", undef_tlb, 0x25}, + {"?tlb", undef_tlb, 0x26}, + {"?tlb", undef_tlb, 0x27}, + {"?tlb", undef_tlb, 0x28}, + {"?tlb", undef_tlb, 0x29}, + {"?tlb", undef_tlb, 0x2a}, + {"?tlb", undef_tlb, 0x2b}, + {"?tlb", undef_tlb, 0x2c}, + {"?tlb", undef_tlb, 0x2d}, + {"?tlb", undef_tlb, 0x2e}, + {"?tlb", undef_tlb, 0x2f}, + {"?tlb", undef_tlb, 0x30}, + {"?tlb", undef_tlb, 0x31}, + {"?tlb", undef_tlb, 0x32}, + {"?tlb", undef_tlb, 0x33}, + {"?tlb", undef_tlb, 0x34}, + {"?tlb", undef_tlb, 0x35}, + {"?tlb", undef_tlb, 0x36}, + {"?tlb", undef_tlb, 0x37}, + {"?tlb", undef_tlb, 0x38}, + {"?tlb", undef_tlb, 0x39}, + {"?tlb", undef_tlb, 0x3a}, + {"?tlb", undef_tlb, 0x3b}, + {"?tlb", undef_tlb, 0x3c}, + {"?tlb", undef_tlb, 0x3d}, + {"?tlb", undef_tlb, 0x3e}, + {"?tlb", undef_tlb, 0x3f}, +}; diff --git a/tools/virtualmips/mips_cp0.c b/tools/virtualmips/mips_cp0.c new file mode 100644 index 0000000..4b0f1c5 --- /dev/null +++ b/tools/virtualmips/mips_cp0.c @@ -0,0 +1,550 @@ +/* + * Cisco router simulation platform. + * Copyright (c) 2005,2006 Christophe Fillot (cf@utc.fr) + * + * MIPS Coprocessor 0 (System Coprocessor) implementation. + * We don't use the JIT here, since there is no high performance needed. + */ + + /* + * Copyright (C) yajin 2008 + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + * + */ + +#define _GNU_SOURCE +#include +#include + +#include "mips.h" +#include "mips_memory.h" +#include "mips_cp0.h" +#include "cpu.h" +#include "vm.h" + +/* MIPS cp0 registers names */ +char *mips_cp0_reg_names[MIPS64_CP0_REG_NR] = { + "index", + "random", + "entry_lo", + "cp0_r3", + "context", + "cp0_r5", + "wired", + "cp0_r7", + "badvaddr", + "cp0_r9", + "entry_hi", + "cp0_r11", + "status", + "cause", + "epc", + "prid", + "dreg", + "depc", + "cp0_r18", + "cp0_r19", + "cctl", + "cp0_r21", + "cp0_r22", + "cp0_r23", + "cp0_r24", + "cp0_r25", + "cp0_r26", + "cp0_r27", + "cp0_r28", + "cp0_r29", + "cp0_r30", + "desave", +}; + +/* Get value of random register */ +static inline u_int mips_cp0_get_random_reg (cpu_mips_t * cpu) +{ + int random_value; + random_value = + (int) ((double) (cpu->cp0.tlb_entries) * rand () / (RAND_MAX + 1.0)); + return random_value; +} + +/* Get a cp0 register (fast version) */ +static inline m_cp0_reg_t mips_cp0_get_reg_fast (cpu_mips_t * cpu, + u_int cp0_reg, u_int sel) +{ + mips_cp0_t *cp0 = &cpu->cp0; + switch (cp0_reg) { + + case MIPS_CP0_RANDOM: + return (mips_cp0_get_random_reg (cpu)); + case MIPS_CP0_CONFIG: + if (! ((1 << sel) & cp0->config_usable)) { +unimpl: fprintf (stderr, + "Reading unimplemented CP0 register %s\n", + cp0reg_name (cp0_reg, sel)); + return 0; + } + return cp0->config_reg[sel]; + + case MIPS_CP0_STATUS: + switch (sel) { + case 0: /* Status */ + return cp0->reg[cp0_reg]; + case 1: /* IntCtl */ + return cp0->intctl_reg; + } + goto unimpl; + + case MIPS_CP0_PRID: + switch (sel) { + case 0: /* PRId */ + return cp0->reg[cp0_reg]; + case 1: /* EBase */ + return cp0->ebase_reg; + } + goto unimpl; + + default: + if (sel != 0) + goto unimpl; + return cp0->reg[cp0_reg]; + } +} + +/* Get a cp0 register */ +m_cp0_reg_t mips_cp0_get_reg (cpu_mips_t * cpu, u_int cp0_reg) +{ + return (mips_cp0_get_reg_fast (cpu, cp0_reg, 0)); +} + +void fastcall mips_cp0_exec_mfc0_fastcall (cpu_mips_t * cpu, + mips_insn_t insn) +{ + int rt = bits (insn, 16, 20); + int rd = bits (insn, 11, 15); + int sel = bits (insn, 0, 2); + + cpu->reg_set (cpu, rt, sign_extend (mips_cp0_get_reg_fast (cpu, rd, sel), 32)); +} + +/* MFC0 */ +void mips_cp0_exec_mfc0 (cpu_mips_t * cpu, u_int gp_reg, u_int cp0_reg, + u_int sel) +{ + cpu->reg_set (cpu, gp_reg, + sign_extend (mips_cp0_get_reg_fast (cpu, cp0_reg, sel), 32)); +} + +void fastcall mips_cp0_exec_mtc0_fastcall (cpu_mips_t * cpu, + mips_insn_t insn) +{ + int rt = bits (insn, 16, 20); + int rd = bits (insn, 11, 15); + int sel = bits (insn, 0, 2); + + mips_cp0_set_reg (cpu, rd, sel, cpu->gpr[rt] & 0xffffffff); +} + +void mips_cp0_exec_mtc0 (cpu_mips_t * cpu, u_int gp_reg, u_int cp0_reg, + u_int sel) +{ + mips_cp0_set_reg (cpu, cp0_reg, sel, cpu->gpr[gp_reg] & 0xffffffff); +} + +/* Set a cp0 register */ +void mips_cp0_set_reg (cpu_mips_t * cpu, u_int cp0_reg, u_int sel, + m_uint32_t val) +{ + mips_cp0_t *cp0 = &cpu->cp0; + + if (cpu->vm->debug_level > 2) { + extern const char *cp0reg_name (unsigned cp0reg, unsigned sel); + printf (" %s := %08x\n", cp0reg_name (cp0_reg, sel), val); + fflush (stdout); + } + switch (cp0_reg) { + case MIPS_CP0_STATUS: + switch (sel) { + case 0: /* Status */ + cp0->reg[cp0_reg] = val; + break; + case 1: /* IntCtl */ + cp0->intctl_reg = val; + break; + default: + goto unimpl; + } + break; + + case MIPS_CP0_PRID: + switch (sel) { + case 0: /* PRId */ + /* read only register */ + break; + case 1: /* EBase */ + cp0->ebase_reg = (val & 0x3ffff000) | 0x80000000; + break; + default: + goto unimpl; + } + break; + + case MIPS_CP0_RANDOM: + case MIPS_CP0_WIRED: + /* read only registers */ + if (sel != 0) + goto unimpl; + break; + + case MIPS_CP0_COMPARE: + // Write to compare will clear timer interrupt + if (sel != 0) + goto unimpl; + clear_timer_irq (cpu); + cp0->reg[cp0_reg] = val; + break; + + case MIPS_CP0_CONFIG: + if (! ((1 << sel) & cp0->config_usable)) + goto unimpl; + if (sel != 0) + fprintf (stderr, + "Writing to read only configure register sel %u\n", sel); + if (sel == 0) { + /* only bits 0:2 are writable */ + val &= 3; + cp0->config_reg[sel] &= 0xfffffffc; + cp0->config_reg[sel] += val; + } else + cp0->config_reg[sel] = val; + break; + + default: + if (sel != 0) { +unimpl: fprintf (stderr, + "Writing to unimplemented CP0 register %s\n", + cp0reg_name (cp0_reg, sel)); + break; + } + cp0->reg[cp0_reg] = val; + } +} + +/* Get the VPN2 mask */ +m_cp0_reg_t mips_cp0_get_vpn2_mask (cpu_mips_t * cpu) +{ + if (cpu->addr_mode == 64) + return ((m_cp0_reg_t) MIPS_TLB_VPN2_MASK_64); + else + return ((m_cp0_reg_t) MIPS_TLB_VPN2_MASK_32); +} + +/* TLBP: Probe a TLB entry */ +void fastcall mips_cp0_exec_tlbp (cpu_mips_t * cpu) +{ + mips_cp0_t *cp0 = &cpu->cp0; + + m_uint32_t vpn2, hi_reg, vpn2_mask, page_mask, hi_addr; + tlb_entry_t *entry; + u_int asid; + int i; + vpn2_mask = mips_cp0_get_vpn2_mask (cpu); + hi_reg = cp0->reg[MIPS_CP0_TLB_HI]; + asid = hi_reg & MIPS_TLB_ASID_MASK; + vpn2 = hi_reg & vpn2_mask; + + cp0->reg[MIPS_CP0_INDEX] = 0x80000000; + for (i = 0; i < cp0->tlb_entries; i++) { + entry = &cp0->tlb[i]; + page_mask = ~(entry->mask + 0x1FFF); + hi_addr = entry->hi & mips_cp0_get_vpn2_mask (cpu); + if (((vpn2 & page_mask) == (hi_addr & page_mask)) && + (((entry->hi & MIPS_TLB_G_MASK)) + || ((entry->hi & MIPS_TLB_ASID_MASK) == asid))) { + cp0->reg[MIPS_CP0_INDEX] = i; + cp0->reg[MIPS_CP0_INDEX] &= ~0x80000000ULL; + return; +#if DEBUG_TLB_ACTIVITY + cpu_log (cpu, "", "CPU: CP0_TLBP returned %x\n", i); +#endif + } + } +} + +/* Get the page size corresponding to a page mask */ +static inline m_uint32_t get_page_size (m_uint32_t page_mask) +{ + return ((page_mask + 0x2000) >> 1); +} + +void mips_cp0_unmap_tlb_to_mts (cpu_mips_t * cpu, int index) +{ + m_va_t v0_addr, v1_addr; + m_uint32_t page_size; + tlb_entry_t *entry; + + entry = &cpu->cp0.tlb[index]; + + page_size = get_page_size (entry->mask); + v0_addr = entry->hi & mips_cp0_get_vpn2_mask (cpu); + v1_addr = v0_addr + page_size; + + if (entry->lo0 & MIPS_TLB_V_MASK) + cpu->mts_unmap (cpu, v0_addr, page_size, MTS_ACC_T, index); + + if (entry->lo1 & MIPS_TLB_V_MASK) + cpu->mts_unmap (cpu, v1_addr, page_size, MTS_ACC_T, index); +} + +/* TLBW: Write a TLB entry */ +static forced_inline void mips_cp0_exec_tlbw (cpu_mips_t * cpu, u_int index) +{ + mips_cp0_t *cp0 = &cpu->cp0; + tlb_entry_t *entry; + + if (index < cp0->tlb_entries) { + entry = &cp0->tlb[index]; + + /* Unmap the old entry if it was valid */ + mips_cp0_unmap_tlb_to_mts (cpu, index); + + entry->mask = cp0->reg[MIPS_CP0_PAGEMASK]; + entry->hi = cp0->reg[MIPS_CP0_TLB_HI]; + entry->lo0 = cp0->reg[MIPS_CP0_TLB_LO_0]; + entry->lo1 = cp0->reg[MIPS_CP0_TLB_LO_1]; + /* if G bit is set in lo0 and lo1, set it in hi */ + if ((entry->lo0 & entry->lo1) & MIPS_CP0_LO_G_MASK) + entry->hi |= MIPS_TLB_G_MASK; + + /* Clear G bit in TLB lo0 and lo1 */ + entry->lo0 &= ~MIPS_CP0_LO_G_MASK; + entry->lo1 &= ~MIPS_CP0_LO_G_MASK; + } +} + +/* TLBWI: Write Indexed TLB entry */ +void fastcall mips_cp0_exec_tlbwi (cpu_mips_t * cpu) +{ + m_uint32_t index; + +/*FIX ME: + May be a bug in tlblhandler of 2.6.11. by yajin. + + IN kernel, TLBL exception handler run a tlbp and then tlbw without checking tlbp is successful. + assume + 2aaa8a9c lw t0,(s0) + 1.First we need to load instruction in 2aaa8a9c. A tlbl exception occurs. tlbp failed and tlbw + write tlb entry into entry x. + 2. And then exceute the instruction. load a data from a memory. A tlbl exception occurs. tlbp failed + and tlbw write tlb entry into entry x. and return to pc=2aaa8a9c and do the process 1. + This will cause a infinate loop. + + In fact, we need to check whether is successfully. If success, tlbw. otherwise tlbwr. + + So I first check whether last tlbp failed(check highest bit of index register). If tlbp failed, write + tlbwr instead tlbw. It works well. + */ + + if (cpu->cp0.reg[MIPS_CP0_INDEX] & 0x80000000) { + mips_cp0_exec_tlbwr (cpu); + } else { + + index = cpu->cp0.reg[MIPS_CP0_INDEX]; + mips_cp0_exec_tlbw (cpu, index); + } + +} + +/* TLBWR: Write Random TLB entry */ +void fastcall mips_cp0_exec_tlbwr (cpu_mips_t * cpu) +{ + mips_cp0_exec_tlbw (cpu, mips_cp0_get_random_reg (cpu)); +} + +/* TLBR: Read Indexed TLB entry */ +void fastcall mips_cp0_exec_tlbr (cpu_mips_t * cpu) +{ + mips_cp0_t *cp0 = &cpu->cp0; + tlb_entry_t *entry; + u_int index; + + index = cp0->reg[MIPS_CP0_INDEX]; + +#if DEBUG_TLB_ACTIVITY + cpu_log (cpu, "TLB", "CP0_TLBR: reading entry %u.\n", index); +#endif + + if (index < cp0->tlb_entries) { + entry = &cp0->tlb[index]; + + cp0->reg[MIPS_CP0_PAGEMASK] = entry->mask; + cp0->reg[MIPS_CP0_TLB_HI] = entry->hi; + cp0->reg[MIPS_CP0_TLB_LO_0] = entry->lo0; + cp0->reg[MIPS_CP0_TLB_LO_1] = entry->lo1; + if (entry->hi & MIPS_TLB_G_MASK) { + cp0->reg[MIPS_CP0_TLB_LO_0] |= MIPS_CP0_LO_G_MASK; + cp0->reg[MIPS_CP0_TLB_LO_1] |= MIPS_CP0_LO_G_MASK; + cp0->reg[MIPS_CP0_TLB_HI] &= ~MIPS_TLB_G_MASK; + } + + } +} + +#ifndef SIM_PIC32 +int mips_cp0_tlb_lookup (cpu_mips_t *cpu, m_va_t vaddr, mts_map_t *res) +{ + mips_cp0_t *cp0 = &cpu->cp0; + + m_va_t vpn_addr, hi_addr, page_mask, page_size; + tlb_entry_t *entry; + u_int asid; + int i; + + vpn_addr = vaddr & mips_cp0_get_vpn2_mask (cpu); + + asid = cp0->reg[MIPS_CP0_TLB_HI] & MIPS_TLB_ASID_MASK; + for (i = 0; i < cp0->tlb_entries; i++) { + entry = &cp0->tlb[i]; + page_mask = ~(entry->mask + 0x1FFF); + hi_addr = entry->hi & mips_cp0_get_vpn2_mask (cpu); + + if (((vpn_addr & page_mask) == (hi_addr & page_mask)) && + ((entry->hi & MIPS_TLB_G_MASK) + || ((entry->hi & MIPS_TLB_ASID_MASK) == asid))) { + page_size = get_page_size (entry->mask); + if ((vaddr & page_size) == 0) { + res->tlb_index = i; + + res->vaddr = vaddr & MIPS_MIN_PAGE_MASK; + res->paddr = (entry->lo0 & MIPS_TLB_PFN_MASK) << 6; + res->paddr += ((res->vaddr) & (page_size - 1)); + //res->paddr += ( (vaddr )& (page_size-1)); + + res->paddr &= cpu->addr_bus_mask; + + res->dirty = + (entry->lo0 & MIPS_TLB_D_MASK) >> MIPS_TLB_D_SHIT; + res->valid = + (entry->lo0 & MIPS_TLB_V_MASK) >> MIPS_TLB_V_SHIT; + res->asid = asid; + res->g_bit = entry->hi & MIPS_TLB_G_MASK; + + return (TRUE); + } else { + res->tlb_index = i; + res->vaddr = vaddr & MIPS_MIN_PAGE_MASK; + res->paddr = (entry->lo1 & MIPS_TLB_PFN_MASK) << 6; + res->paddr += ((res->vaddr) & (page_size - 1)); + //res->paddr += ( (vaddr )& (page_size-1)); + res->paddr &= cpu->addr_bus_mask; + + res->dirty = + (entry->lo1 & MIPS_TLB_D_MASK) >> MIPS_TLB_D_SHIT; + res->valid = + (entry->lo1 & MIPS_TLB_V_MASK) >> MIPS_TLB_V_SHIT; + + res->asid = asid; + res->g_bit = entry->hi & MIPS_TLB_G_MASK; + + return (TRUE); + } + } + } + return FALSE; +} +#endif + +#if 0 +/* Write page size in buffer */ +static char *get_page_size_str (char *buffer, size_t len, + m_uint32_t page_mask) +{ + m_uint32_t page_size; + + page_size = get_page_size (page_mask); + + /* Mb ? */ + if (page_size >= (1024 * 1024)) + snprintf (buffer, len, "%uMB", page_size >> 20); + else + snprintf (buffer, len, "%uKB", page_size >> 10); + + return buffer; +} + +/* Dump the specified TLB entry */ +void mips_tlb_dump_entry (cpu_mips_t * cpu, u_int index) +{ + tlb_entry_t *entry; + char buffer[256]; + + entry = &cpu->cp0.tlb[index]; + + /* virtual Address */ + printf (" %2d: vaddr=0x%8.8" LL "x ", index, + entry->hi & mips_cp0_get_vpn2_mask (cpu)); + + /* global or ASID */ + if ((entry->lo0 & MIPS_TLB_G_MASK) && ((entry->lo1 & MIPS_TLB_G_MASK))) + printf ("(global) "); + else + printf ("(asid 0x%2.2" LL "x) ", entry->hi & MIPS_TLB_ASID_MASK); + + /* 1st page: Lo0 */ + printf ("p0="); + + if (entry->lo0 & MIPS_TLB_V_MASK) + printf ("0x%9.9" LL "x", (entry->lo0 & MIPS_TLB_PFN_MASK) << 6); + else + printf ("(invalid) "); + + printf (" %c ", (entry->lo0 & MIPS_TLB_D_MASK) ? 'D' : ' '); + + /* 2nd page: Lo1 */ + printf ("p1="); + + if (entry->lo1 & MIPS_TLB_V_MASK) + printf ("0x%9.9" LL "x", (entry->lo1 & MIPS_TLB_PFN_MASK) << 6); + else + printf ("(invalid) "); + + printf (" %c ", (entry->lo1 & MIPS_TLB_D_MASK) ? 'D' : ' '); + + /* page size */ + printf (" (%s)\n", get_page_size_str (buffer, sizeof (buffer), + entry->mask)); + +} + +/* Human-Readable dump of the TLB */ +void mips_tlb_dump (cpu_mips_t * cpu) +{ + cpu_mips_t *mcpu = (cpu); + u_int i; + + printf ("TLB dump:\n"); + for (i = 0; i < mcpu->cp0.tlb_entries; i++) + mips_tlb_dump_entry (mcpu, i); + + printf ("\n"); +} + +/* Raw dump of the TLB */ +void mips_tlb_raw_dump (cpu_mips_t * cpu) +{ + cpu_mips_t *mcpu = (cpu); + tlb_entry_t *entry; + u_int i; + + printf ("TLB dump:\n"); + + for (i = 0; i < mcpu->cp0.tlb_entries; i++) { + entry = &mcpu->cp0.tlb[i]; + printf (" %2d: mask=0x%16.16" LL "x hi=0x%16.16" LL "x " + "lo0=0x%16.16" LL "x lo1=0x%16.16" LL "x\n", i, entry->mask, + entry->hi, entry->lo0, entry->lo1); + } + printf ("\n"); +} +#endif diff --git a/tools/virtualmips/mips_cp0.h b/tools/virtualmips/mips_cp0.h new file mode 100644 index 0000000..afd95c0 --- /dev/null +++ b/tools/virtualmips/mips_cp0.h @@ -0,0 +1,42 @@ +/* + * Cisco router simulation platform. + * Copyright (c) 2005,2006 Christophe Fillot (cf@utc.fr) + */ + /* + * Copyright (C) yajin 2008 + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + * + */ + +#ifndef __CP0_H__ +#define __CP0_H__ + +#include "utils.h" +#include "system.h" + +/* CP0 register names */ +extern char *mips_cp0_reg_names[]; + +m_cp0_reg_t mips_cp0_get_reg (cpu_mips_t * cpu, u_int cp0_reg); +void fastcall mips_cp0_exec_mfc0_fastcall (cpu_mips_t * cpu, + mips_insn_t insn); +void mips_cp0_exec_mfc0 (cpu_mips_t * cpu, u_int gp_reg, u_int cp0_reg, + u_int sel); +void mips_cp0_exec_mtc0 (cpu_mips_t * cpu, u_int gp_reg, u_int cp0_reg, + u_int sel); +void fastcall mips_cp0_exec_mtc0_fastcall (cpu_mips_t * cpu, + mips_insn_t insn); +void mips_cp0_set_reg (cpu_mips_t * cpu, u_int cp0_reg, u_int sel, + m_uint32_t val); +m_cp0_reg_t mips_cp0_get_vpn2_mask (cpu_mips_t * cpu); +void fastcall mips_cp0_exec_tlbp (cpu_mips_t * cpu); +void fastcall mips_cp0_exec_tlbwi (cpu_mips_t * cpu); +void fastcall mips_cp0_exec_tlbwr (cpu_mips_t * cpu); +void fastcall mips_cp0_exec_tlbr (cpu_mips_t * cpu); +int mips_cp0_tlb_lookup (cpu_mips_t * cpu, m_va_t vaddr, mts_map_t * res); +void mips_tlb_dump (cpu_mips_t * cpu); +void mips_tlb_raw_dump (cpu_mips_t * cpu); + +#endif diff --git a/tools/virtualmips/mips_exec.c b/tools/virtualmips/mips_exec.c new file mode 100644 index 0000000..7f90e59 --- /dev/null +++ b/tools/virtualmips/mips_exec.c @@ -0,0 +1,25 @@ +/* + * Copyright (C) yajin 2008 + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + */ +#include "cpu.h" +#include "vm.h" +#include "mips_exec.h" +#include "mips_fdd.h" +#include "vp_timer.h" + +cpu_mips_t *current_cpu; + +/*select different main loop*/ +void *mips_exec_run_cpu (cpu_mips_t * cpu) +{ +#ifdef _USE_JIT_ + if (cpu->vm->jit_use) { + mips_jit_init (cpu); + return mips_jit_run_cpu (cpu); + } else +#endif + return mips_cpu_fdd (cpu); +} diff --git a/tools/virtualmips/mips_exec.h b/tools/virtualmips/mips_exec.h new file mode 100644 index 0000000..612d6bf --- /dev/null +++ b/tools/virtualmips/mips_exec.h @@ -0,0 +1,37 @@ +/* + * Cisco router simulation platform. + * Copyright (c) 2005,2006 Christophe Fillot (cf@utc.fr) + */ + /* + * Copyright (C) yajin 2008 + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + * + */ + +#ifndef __MIPS64_EXEC_H__ +#define __MIPS64_EXEC_H__ + +#include "utils.h" +#include "system.h" + +#include "mips_jit.h" + +struct mips_op_desc { + char *opname; + int (*func) (cpu_mips_t *, mips_insn_t); + m_uint16_t num; +}; + +struct mips_jit_desc { + char *opname; + int (*emit_func) (cpu_mips_t *, mips_jit_tcb_t *, mips_insn_t); + m_uint16_t num; + int delay_slot; /*can this instruction in delay slot. 1:can. 0: can not */ +}; + +/* Run MIPS code in step-by-step mode */ +void *mips_exec_run_cpu (cpu_mips_t * cpu); + +#endif diff --git a/tools/virtualmips/mips_fdd.c b/tools/virtualmips/mips_fdd.c new file mode 100644 index 0000000..9d312c1 --- /dev/null +++ b/tools/virtualmips/mips_fdd.c @@ -0,0 +1,299 @@ +/* + * This is the basic fetch-decode-dispatch(fdd) routine. + * Emulation speed is slow but easy to debug. + * + * Copyright (C) yajin 2008 + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cpu.h" +#include "vm.h" +#include "mips_exec.h" +#include "mips_memory.h" +#include "mips.h" +#include "mips_cp0.h" +#include "debug.h" +#include "vp_timer.h" +#include "mips_hostalarm.h" + +//#ifdef _USE_FDD_ + +static const struct mips_op_desc mips_opcodes[]; +static const struct mips_op_desc mips_spec_opcodes[]; +static const struct mips_op_desc mips_bcond_opcodes[]; +static const struct mips_op_desc mips_cop0_opcodes[]; +static const struct mips_op_desc mips_spec2_opcodes[]; +static const struct mips_op_desc mips_spec3_opcodes[]; +static const struct mips_op_desc mips_tlb_opcodes[]; + +extern cpu_mips_t *current_cpu; + +/*for emulation performance check*/ +#ifdef DEBUG_MHZ +#define C_1000MHZ 1000000000 +struct timeval pstart, pend; +float timeuse, performance; +m_uint64_t instructions_executed = 0; +#endif + +static void forced_inline mips_main_loop_wait (cpu_mips_t * cpu, + int timeout) +{ + vp_run_timers (&active_timers[VP_TIMER_REALTIME], + vp_get_clock (rt_clock)); +} + +/* Execute a memory operation (2) */ +static int forced_inline mips_exec_memop2 (cpu_mips_t * cpu, int memop, + m_va_t base, int offset, u_int dst_reg, int keep_ll_bit) +{ + m_va_t vaddr = cpu->gpr[base] + sign_extend (offset, 16); + mips_memop_fn fn; + + if (!keep_ll_bit) + cpu->ll_bit = 0; + fn = cpu->mem_op_fn[memop]; + return (fn (cpu, vaddr, dst_reg)); +} + +/* Fetch an instruction */ +int mips_fetch_instruction (cpu_mips_t * cpu, + m_va_t pc, mips_insn_t * insn) +{ + m_va_t exec_page; + m_uint32_t offset; + + exec_page = pc & ~(m_va_t) MIPS_MIN_PAGE_IMASK; + if (unlikely (exec_page != cpu->njm_exec_page)) { + cpu->njm_exec_ptr = cpu->mem_op_lookup (cpu, exec_page); + } + if (cpu->njm_exec_ptr == NULL) { + //exception when fetching instruction + return (1); + } + cpu->njm_exec_page = exec_page; + offset = (pc & MIPS_MIN_PAGE_IMASK) >> 2; + *insn = vmtoh32 (cpu->njm_exec_ptr[offset]); +// printf ("(%08x) %08x\n", pc, *insn); + return (0); +} + +/* Execute a single instruction */ +static forced_inline int mips_exec_single_instruction (cpu_mips_t * cpu, + mips_insn_t instruction) +{ +#ifdef DEBUG_MHZ + if (unlikely (instructions_executed == 0)) { + gettimeofday (&pstart, NULL); + } + instructions_executed++; + if (unlikely (instructions_executed == C_1000MHZ)) { + gettimeofday (&pend, NULL); + timeuse = + 1000000 * (pend.tv_sec - pstart.tv_sec) + pend.tv_usec - + pstart.tv_usec; + timeuse /= 1000000; + performance = 1000 / timeuse; + printf ("Used Time:%f seconds. %f MHZ\n", timeuse, performance); + exit (1); + } +#endif + register uint op; + op = MAJOR_OP (instruction); + return mips_opcodes[op].func (cpu, instruction); +} + +/* Single-step execution */ +void fastcall mips_exec_single_step (cpu_mips_t * cpu, + mips_insn_t instruction) +{ + int res; + + res = mips_exec_single_instruction (cpu, instruction); + /* Normal flow ? */ + if (likely (!res)) + cpu->pc += 4; +} + +void dumpregs (cpu_mips_t *cpu) +{ + printf (" t0 = %8x s0 = %8x t8 = %8x lo = %8x\n", + cpu->gpr[8], cpu->gpr[16], cpu->gpr[24], cpu->lo); + printf ("at = %8x t1 = %8x s1 = %8x t9 = %8x hi = %8x\n", + cpu->gpr[1], cpu->gpr[9], cpu->gpr[17], cpu->gpr[25], cpu->hi); + printf ("v0 = %8x t2 = %8x s2 = %8x status = %8x\n", + cpu->gpr[2], cpu->gpr[10], cpu->gpr[18], cpu->cp0.reg[MIPS_CP0_STATUS]); + printf ("v1 = %8x t3 = %8x s3 = %8x\n", + cpu->gpr[3], cpu->gpr[11], cpu->gpr[19]); + printf ("a0 = %8x t4 = %8x s4 = %8x gp = %8x pc = %8x\n", + cpu->gpr[4], cpu->gpr[12], cpu->gpr[20], cpu->gpr[28], cpu->pc); + printf ("a1 = %8x t5 = %8x s5 = %8x sp = %8x\n", + cpu->gpr[5], cpu->gpr[13], cpu->gpr[21], cpu->gpr[29]); + printf ("a2 = %8x t6 = %8x s6 = %8x fp = %8x\n", + cpu->gpr[6], cpu->gpr[14], cpu->gpr[22], cpu->gpr[30]); + printf ("a3 = %8x t7 = %8x s7 = %8x ra = %8x\n", + cpu->gpr[7], cpu->gpr[15], cpu->gpr[23], cpu->gpr[31]); +} + + +/* + * MIPS64 fetch->decode->dispatch main loop + */ +void *mips_cpu_fdd (cpu_mips_t * cpu) +{ + mips_insn_t insn = 0; + int res; + + cpu->cpu_thread_running = TRUE; + current_cpu = cpu; + + mips_init_host_alarm (); + +start_cpu: + for (;;) { + if (unlikely (cpu->state != CPU_STATE_RUNNING)) + break; + + if (unlikely ((cpu->pause_request) & CPU_INTERRUPT_EXIT)) { + cpu->state = CPU_STATE_PAUSING; + break; + } + + /* Reset "zero register" (for safety) */ + cpu->gpr[0] = 0; + + /* Check IRQ */ + if (unlikely (cpu->irq_pending)) { + mips_trigger_irq (cpu); + continue; + } + /* Fetch the instruction */ + res = mips_fetch_instruction (cpu, cpu->pc, &insn); + + if (cpu->vm->trace_address == cpu->pc) { + /* Trace address. */ + printf ("*** %08x: %08x ", cpu->pc, insn); + print_insn_mips (cpu->pc, insn, stdout); + printf ("\n"); + dumpregs (cpu); + } + + if (unlikely (res == 1)) { + /*exception when fetching instruction */ + printf ("%08x: exception when fetching instruction\n", cpu->pc); + if (cpu->pc == 0) + exit(-1); + continue; + } + if (unlikely ((cpu->vm->mipsy_debug_mode) + && ((cpu_hit_breakpoint (cpu->vm, cpu->pc) == SUCCESS) + || (cpu->vm->gdb_interact_sock == -1) + || (cpu->vm->mipsy_break_nexti == MIPS_BREAKANYCPU)))) { + if (mips_debug (cpu->vm, 1)) { + continue; + } + } + if (cpu->vm->debug_level > 2 || (cpu->vm->debug_level > 1 && + (cpu->cp0.reg[MIPS_CP0_STATUS] & MIPS_CP0_STATUS_UM) && + ! (cpu->cp0.reg[MIPS_CP0_STATUS] & MIPS_CP0_STATUS_EXL))) + { + /* Print instructions in user mode. */ + printf ("%08x: %08x ", cpu->pc, insn); + print_insn_mips (cpu->pc, insn, stdout); + printf ("\n"); + fflush (stdout); +#if 0 + m_uint32_t dummy; + unsigned char *p = physmem_get_hptr (cpu->vm, 0x00010000, 0, MTS_READ, &dummy); + if (p) { + unsigned nbytes; + for (nbytes=0x40; nbytes>0; p+=16, nbytes-=16) { + printf ("%08x: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", + (unsigned) p, p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], + p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]); + } + } +#endif + } + res = mips_exec_single_instruction (cpu, insn); + + /* Normal flow ? */ + if (likely (!res)) + cpu->pc += sizeof (mips_insn_t); + } + + while (cpu->cpu_thread_running) { + switch (cpu->state) { + case CPU_STATE_RUNNING: + cpu->state = CPU_STATE_RUNNING; + goto start_cpu; + + case CPU_STATE_HALTED: + cpu->cpu_thread_running = FALSE; + break; + case CPU_STATE_RESTARTING: + cpu->state = CPU_STATE_RESTARTING; + /*Just waiting for cpu restart. */ + break; + case CPU_STATE_PAUSING: + /*main loop must wait for me. heihei :) */ + mips_main_loop_wait (cpu, 0); + cpu->state = CPU_STATE_RUNNING; + cpu->pause_request &= ~CPU_INTERRUPT_EXIT; + /*start cpu again */ + goto start_cpu; + + } + } + return NULL; +} + +/* Execute the instruction in delay slot */ +static forced_inline int mips_exec_bdslot (cpu_mips_t * cpu) +{ + mips_insn_t insn; + int res = 0; + cpu->is_in_bdslot = 1; + + /* Fetch the instruction in delay slot */ + res = mips_fetch_instruction (cpu, cpu->pc + 4, &insn); + if (res == 1) { + /*exception when fetching instruction */ + cpu->is_in_bdslot = 0; + return (1); + } + cpu->is_in_bdslot = 1; + + if (cpu->vm->debug_level > 2 || (cpu->vm->debug_level > 1 && + (cpu->cp0.reg[MIPS_CP0_STATUS] & MIPS_CP0_STATUS_UM) && + ! (cpu->cp0.reg[MIPS_CP0_STATUS] & MIPS_CP0_STATUS_EXL))) + { + /* Print instructions in user mode. */ + printf ("%08x: %08x ", cpu->pc + 4, insn); + print_insn_mips (cpu->pc, insn, stdout); + printf ("\n"); + fflush (stdout); + } + + /* Execute the instruction */ + res = mips_exec_single_instruction (cpu, insn); + cpu->is_in_bdslot = 0; + return res; +} + +#include "mips_codetable.c" + +//#endif diff --git a/tools/virtualmips/mips_fdd.h b/tools/virtualmips/mips_fdd.h new file mode 100644 index 0000000..cbe3c70 --- /dev/null +++ b/tools/virtualmips/mips_fdd.h @@ -0,0 +1,17 @@ +/* + * Copyright (C) yajin 2008 + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + * + */ + +#ifndef __MIPS64_FDD_H__ +#define __MIPS64_FDD_H__ + +#include "utils.h" +#include "system.h" + +void *mips_cpu_fdd (cpu_mips_t * cpu); + +#endif diff --git a/tools/virtualmips/mips_hostalarm.c b/tools/virtualmips/mips_hostalarm.c new file mode 100644 index 0000000..df14b01 --- /dev/null +++ b/tools/virtualmips/mips_hostalarm.c @@ -0,0 +1,257 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef __linux__ +#include +#endif + +#include "cpu.h" +#include "vm.h" +#include "mips_exec.h" +#include "mips_memory.h" +#include "mips.h" +#include "mips_cp0.h" +#include "debug.h" +#include "vp_timer.h" +#include "mips_hostalarm.h" + +/*code from qemu*/ + +#define TFR(expr) do { if ((expr) != -1) break; } while (errno == EINTR) +static struct qemu_alarm_timer *alarm_timer; + +extern cpu_mips_t *current_cpu; + +#define RTC_FREQ 1024 + +#define ALARM_FLAG_DYNTICKS 0x1 +#define ALARM_FLAG_EXPIRED 0x2 + +/* TODO: MIN_TIMER_REARM_US should be optimized */ +#define MIN_TIMER_REARM_US 250 + +struct hpet_info { + unsigned long hi_ireqfreq; /* Hz */ + unsigned long hi_flags; /* information */ + unsigned short hi_hpet; + unsigned short hi_timer; +}; + +#define HPET_INFO_PERIODIC 0x0001 /* timer is periodic */ + +#define HPET_IE_ON _IO('h', 0x01) /* interrupt on */ +#define HPET_IE_OFF _IO('h', 0x02) /* interrupt off */ +#define HPET_INFO _IOR('h', 0x03, struct hpet_info) +#define HPET_EPI _IO('h', 0x04) /* enable periodic */ +#define HPET_DPI _IO('h', 0x05) /* disable periodic */ +#define HPET_IRQFREQ _IOW('h', 0x6, unsigned long) /* IRQFREQ usec */ + +/* + * Host alarm, fired once 1 ms. + * It will find whether a timer has been expired. + * If so, run timers. + */ +void host_alarm_handler (int host_signum) +{ + if (unlikely (current_cpu->state != CPU_STATE_RUNNING)) + return; + + if (vp_timer_expired (active_timers[VP_TIMER_REALTIME], + vp_get_clock (rt_clock))) { + /* Tell cpu we need to pause because timer out */ + current_cpu->pause_request |= CPU_INTERRUPT_EXIT; + } + + /* Check count and compare */ +#define KHZ 80000 + current_cpu->cp0.reg[MIPS_CP0_COUNT] += KHZ / 2; + if (current_cpu->cp0.reg[MIPS_CP0_COMPARE] != 0) { + if (current_cpu->cp0.reg[MIPS_CP0_COUNT] >= + current_cpu->cp0.reg[MIPS_CP0_COMPARE]) { + set_timer_irq (current_cpu); + } + } +/*printf ("-- count = %u, compare = %u\n", current_cpu->cp0.reg[MIPS_CP0_COUNT], current_cpu->cp0.reg[MIPS_CP0_COMPARE]);*/ + + host_alarm (current_cpu, KHZ); +} + +#ifdef __linux__ + +static void enable_sigio_timer (int fd) +{ + struct sigaction act; + + /* timer signal */ + sigfillset (&act.sa_mask); + act.sa_flags = 0; + act.sa_handler = host_alarm_handler; + + sigaction (SIGIO, &act, NULL); + fcntl (fd, F_SETFL, O_ASYNC); + fcntl (fd, F_SETOWN, getpid ()); +} + +static int hpet_start_timer (struct qemu_alarm_timer *t) +{ + struct hpet_info info; + int r, fd; + + fd = open ("/dev/hpet", O_RDONLY); + if (fd < 0) + return -1; + + /* Set frequency */ + r = ioctl (fd, HPET_IRQFREQ, RTC_FREQ); + if (r < 0) { + fprintf (stderr, + "Could not configure '/dev/hpet' to have a 1024Hz timer. This is not a fatal\n" + "error, but for better emulation accuracy type:\n" + "'echo 1024 > /proc/sys/dev/hpet/max-user-freq' as root.\n"); + goto fail; + } + + /* Check capabilities */ + r = ioctl (fd, HPET_INFO, &info); + if (r < 0) + goto fail; + + /* Enable periodic mode */ + r = ioctl (fd, HPET_EPI, 0); + if (info.hi_flags && (r < 0)) + goto fail; + + /* Enable interrupt */ + r = ioctl (fd, HPET_IE_ON, 0); + if (r < 0) + goto fail; + + enable_sigio_timer (fd); + t->priv = (void *) (long) fd; + + return 0; + fail: + close (fd); + return -1; +} + +static void hpet_stop_timer (struct qemu_alarm_timer *t) +{ + int fd = (long) t->priv; + + close (fd); +} + +static int rtc_start_timer (struct qemu_alarm_timer *t) +{ + int rtc_fd; + + TFR (rtc_fd = open ("/dev/rtc", O_RDONLY)); + if (rtc_fd < 0) + return -1; + if (ioctl (rtc_fd, RTC_IRQP_SET, RTC_FREQ) < 0) { + fprintf (stderr, + "Could not configure '/dev/rtc' to have a 1024 Hz timer. This is not a fatal\n" + "error, but for better emulation accuracy either use a 2.6 host Linux kernel or\n" + "type 'echo 1024 > /proc/sys/dev/rtc/max-user-freq' as root.\n"); + goto fail; + } + if (ioctl (rtc_fd, RTC_PIE_ON, 0) < 0) { + fail: + close (rtc_fd); + return -1; + } + + enable_sigio_timer (rtc_fd); + + t->priv = (void *) (long) rtc_fd; + + return 0; +} + +static void rtc_stop_timer (struct qemu_alarm_timer *t) +{ + int rtc_fd = (long) t->priv; + + close (rtc_fd); +} + +#endif /* __linux__ */ + +static int unix_start_timer (struct qemu_alarm_timer *t) +{ + struct sigaction act; + struct itimerval itv; + int err; + + /* timer signal */ + sigfillset (&act.sa_mask); + act.sa_flags = 0; + act.sa_handler = host_alarm_handler; + + sigaction (SIGALRM, &act, NULL); + + itv.it_interval.tv_sec = 0; + /* for i386 kernel 2.6 to get 1 ms */ + itv.it_interval.tv_usec = 999; + itv.it_value.tv_sec = 0; + itv.it_value.tv_usec = 10 * 1000; + + err = setitimer (ITIMER_REAL, &itv, NULL); + if (err) + return -1; + + return 0; +} + +static void unix_stop_timer (struct qemu_alarm_timer *t) +{ + struct itimerval itv; + + memset (&itv, 0, sizeof (itv)); + setitimer (ITIMER_REAL, &itv, NULL); +} + +static struct qemu_alarm_timer alarm_timers[] = { +#ifdef __linux__ + /* HPET - if available - is preferred */ + {"hpet", 0, hpet_start_timer, hpet_stop_timer, NULL, NULL}, + /* ...otherwise try RTC */ + {"rtc", 0, rtc_start_timer, rtc_stop_timer, NULL, NULL}, +#endif + {"unix", 0, unix_start_timer, unix_stop_timer, NULL, NULL}, + {NULL,} +}; + +/*host alarm*/ +void mips_init_host_alarm (void) +{ + struct qemu_alarm_timer *t; + int i, err = -1; + + for (i = 0; alarm_timers[i].name; i++) { + t = &alarm_timers[i]; + err = t->start (t); + if (! err) + break; + } +/*#define DEBUG_HOST_ALARM*/ +#ifdef DEBUG_HOST_ALARM + printf ("--- Using %s timer\n", alarm_timers[i].name); +#endif + if (err) { + fprintf (stderr, "Unable to find any suitable alarm timer.\n"); + fprintf (stderr, "Terminating\n"); + exit (1); + } + alarm_timer = t; +} diff --git a/tools/virtualmips/mips_hostalarm.h b/tools/virtualmips/mips_hostalarm.h new file mode 100644 index 0000000..77c2168 --- /dev/null +++ b/tools/virtualmips/mips_hostalarm.h @@ -0,0 +1,17 @@ +#ifndef __MIPS64_HOSTALARM_H__ +#define __MIPS64_HOSTALARM_H__ + +struct qemu_alarm_timer { + char const *name; + unsigned int flags; + + int (*start) (struct qemu_alarm_timer * t); + void (*stop) (struct qemu_alarm_timer * t); + void (*rearm) (struct qemu_alarm_timer * t); + void *priv; +}; + +void mips_init_host_alarm (void); +void host_alarm (cpu_mips_t *cpu, int nclocks); + +#endif diff --git a/tools/virtualmips/mips_jit.c b/tools/virtualmips/mips_jit.c new file mode 100644 index 0000000..773f7ec --- /dev/null +++ b/tools/virtualmips/mips_jit.c @@ -0,0 +1,749 @@ +/* + * Copyright (C) yajin 2008 + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cpu.h" +#include "vm.h" +#include "mips_exec.h" +#include "mips_memory.h" +#include "mips.h" +#include "mips_cp0.h" +#include "debug.h" +#include "vp_timer.h" +#include "mips_hostalarm.h" +#include "x86_trans.h" + +#ifdef _USE_JIT_ + +extern struct mips_jit_desc mips_jit[]; +extern cpu_mips_t *current_cpu; + +jmp_buf run_jmp; +static void forced_inline mips_main_loop_wait (cpu_mips_t * cpu, + int timeout) +{ + vp_run_timers (&active_timers[VP_TIMER_REALTIME], + vp_get_clock (rt_clock)); +} + +/* Initialize the JIT structure */ +int mips_jit_init (cpu_mips_t * cpu) +{ + insn_exec_page_t *cp; + u_char *cp_addr; + u_int area_size; + size_t len; + int i; + + /* Physical mapping for executable pages */ + len = MIPS_JIT_PC_HASH_SIZE * sizeof (void *); + cpu->exec_blk_map = m_memalign (4096, len); + memset (cpu->exec_blk_map, 0, len); + + /* Get area size */ + area_size = MIPS_EXEC_AREA_SIZE; + + /* Create executable page area */ + cpu->exec_page_area_size = area_size * 1048576; + cpu->exec_page_area = mmap (NULL, cpu->exec_page_area_size, + PROT_EXEC | PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_ANON, -1, (off_t) 0); + + if (!cpu->exec_page_area) { + fprintf (stderr, + "mips_jit_init: unable to create exec area (size %lu)\n", + (u_long) cpu->exec_page_area_size); + return (-1); + } + + /* Carve the executable page area */ + cpu->exec_page_count = cpu->exec_page_area_size / MIPS_JIT_BUFSIZE; + + cpu->exec_page_array = calloc (cpu->exec_page_count, + sizeof (insn_exec_page_t)); + + if (!cpu->exec_page_array) { + fprintf (stderr, + "mips_jit_init: unable to create exec page array\n"); + return (-1); + } + + for (i = 0, cp_addr = cpu->exec_page_area; i < cpu->exec_page_count; i++) { + cp = &cpu->exec_page_array[i]; + + cp->ptr = cp_addr; + cp_addr += MIPS_JIT_BUFSIZE; + + cp->next = cpu->exec_page_free_list; + cpu->exec_page_free_list = cp; + } + + printf + ("CPU%u: carved JIT exec zone of %lu Mb into %lu pages of %u Kb.\n", + cpu->id, (u_long) (cpu->exec_page_area_size / 1048576), + (u_long) cpu->exec_page_count, MIPS_JIT_BUFSIZE / 1024); + return (0); +} + +/* Flush the JIT */ +int mips_jit_flush (cpu_mips_t * cpu, m_uint32_t threshold) +{ + mips_jit_tcb_t *p, *next; + m_uint32_t pc_hash; + u_int count = 0; + m_uint32_t flush_threadhold = 0; + + if (threshold == 0) + flush_threadhold = (m_uint32_t) (0xffffffff); + for (p = cpu->tcb_list; p; p = next) { + next = p->next; + if ((m_uint32_t) p->acc_count <= flush_threadhold) { + pc_hash = mips_jit_get_pc_hash (cpu, p->start_pc); + cpu->exec_blk_map[pc_hash] = NULL; + mips_jit_tcb_free (cpu, p, TRUE); + count++; + } + } + + cpu->compiled_pages -= count; + return (count); +} + +/* Shutdown the JIT */ +void mips_jit_shutdown (cpu_mips_t * cpu) +{ + mips_jit_tcb_t *p, *next; + + /* Flush the JIT */ + mips_jit_flush (cpu, 0); + + /* Free the instruction blocks */ + for (p = cpu->tcb_free_list; p; p = next) { + next = p->next; + free (p); + } + + /* Unmap the executable page area */ + if (cpu->exec_page_area) + munmap (cpu->exec_page_area, cpu->exec_page_area_size); + + /* Free the exec page array */ + free (cpu->exec_page_array); + + /* Free physical mapping for executable pages */ + free (cpu->exec_blk_map); +} + +/* Allocate an exec page */ +static forced_inline insn_exec_page_t *exec_page_alloc (cpu_mips_t * cpu) +{ + insn_exec_page_t *p; + u_int count; + + /* If the free list is empty, flush JIT */ + if (unlikely (!cpu->exec_page_free_list)) { + if (cpu->jit_flush_method) { + mips_jit_flush (cpu, 0); + } else { + count = mips_jit_flush (cpu, 100); + if (!cpu->exec_page_free_list) + mips_jit_flush (cpu, 0); + } + + /* Use both methods alternatively */ + cpu->jit_flush_method = 1 - cpu->jit_flush_method; + } + + if (unlikely (!(p = cpu->exec_page_free_list))) { + return NULL; + } + + cpu->exec_page_free_list = p->next; + cpu->exec_page_alloc++; + return p; +} + +/* Free an exec page and returns it to the pool */ +static forced_inline void exec_page_free (cpu_mips_t * cpu, + insn_exec_page_t * p) +{ + if (p) { + p->next = cpu->exec_page_free_list; + cpu->exec_page_free_list = p; + cpu->exec_page_alloc--; + } + +} + +/* Fetch a MIPS instruction */ +static forced_inline mips_insn_t insn_fetch (mips_jit_tcb_t * b) +{ + return (vmtoh32 (b->mips_code[b->mips_trans_pos])); +} + +#ifdef DEBUG_JIT +void fastcall jit_debug (cpu_mips_t * cpu, mips_jit_tcb_t * block) +{ + /*Put the debug code here. */ +} + +#endif + +/*What is the meaning of delay_slot? +Search the whole project and you will find delay_slot can be 0/1/2. + +0: we are translating the instruction not in delay slot. +1: we are translating the instruction in delay and update mips_trans_pos. +2: we are translating the instruction in delay and NOT update mips_trans_pos. + +*/ + +/* Fetch a MIPS instruction and emit corresponding translated code */ +int mips_jit_fetch_and_emit (cpu_mips_t * cpu, + mips_jit_tcb_t * block, int delay_slot) +{ + mips_insn_t code; + register uint op; + + code = insn_fetch (block); + op = MAJOR_OP (code); + + /* Branch-delay slot is in another page: slow exec */ + if ((block->mips_trans_pos == (MIPS_INSN_PER_PAGE - 1)) + && (insn_is_jmp (code))) { + block->jit_insn_ptr[block->mips_trans_pos] = block->jit_ptr; + mips_set_pc (block, block->start_pc + (block->mips_trans_pos << 2)); + mips_emit_single_step (block, code); + mips_jit_tcb_push_epilog (block); + block->mips_trans_pos++; + return (0); + } + + if (!delay_slot) + block->jit_insn_ptr[block->mips_trans_pos] = block->jit_ptr; + + if (delay_slot == 0) + block->mips_trans_pos++; + +#ifdef DEBUG_JIT + m_uint32_t jit_pc; + if (delay_slot == 0) + jit_pc = block->start_pc + ((block->mips_trans_pos - 1) << 2); + else + jit_pc = block->start_pc + ((block->mips_trans_pos) << 2); + x86_mov_membase_imm (block->jit_ptr, X86_EDI, OFFSET (cpu_mips_t, jit_pc), + jit_pc, 4); + x86_mov_reg_reg (block->jit_ptr, X86_EAX, X86_EDI, 4); + x86_mov_reg_imm (block->jit_ptr, X86_EDX, block); + mips_emit_basic_c_call (block, jit_debug); +#endif + + if (delay_slot && insn_is_jmp (code)) { + /*why a jump instruction in a delay slot??? yajin + * + * --------- + * |CODE | + * |-------| + * | DATA | + * --------- + * + * When data and code is in one page and we translate a page once. + * Emulator does not know where is data and where is code. So it just translate the whole + * page. + * data : 504f4e4d (jmp) + * data : 54535251 (jmp TOO) + * So 54535251 is in delay slot of 504f4e4d. + * We just add mips_trans_pos and return. + * TODO: a better method is to stop tranlating the page. + * + */ + if (delay_slot == 1) + block->mips_trans_pos++; + return (0); + } + + if (!delay_slot) { + /* Check for IRQs and cpu pausing before jumps */ + if (insn_is_jmp (code)) { + mips_check_cpu_pausing (block); + mips_check_pending_irq (block); + } + } +/*set is_in_bdslot*/ + if ((delay_slot == 1) || (delay_slot == 2)) + x86_mov_membase_imm (block->jit_ptr, X86_EDI, OFFSET (cpu_mips_t, + is_in_bdslot), 0x1, 4); + + mips_jit[op].emit_func (cpu, block, code); +/*clear is_in_bdslot*/ + if ((delay_slot == 1) || (delay_slot == 2)) + x86_mov_membase_imm (block->jit_ptr, X86_EDI, OFFSET (cpu_mips_t, + is_in_bdslot), 0x0, 4); + if (delay_slot == 1) + block->mips_trans_pos++; + + return (0); +} + +/* Add end of JIT block */ +static forced_inline void mips_jit_tcb_add_end (mips_jit_tcb_t * b) +{ + mips_set_pc (b, b->start_pc + (b->mips_trans_pos << 2)); + mips_jit_tcb_push_epilog (b); +} + +/* Record a patch to apply in a compiled block */ +int mips_jit_tcb_record_patch (mips_jit_tcb_t * block, u_char * jit_ptr, + m_va_t vaddr) +{ + struct mips_jit_patch_table *ipt = block->patch_table; + struct mips_insn_patch *patch; + + /* pc must be 32-bit aligned */ + if (vaddr & 0x03) { + fprintf (stderr, + "Block 0x%8.8" LL "x: trying to record an invalid PC " "(0x%8.8" + LL "x) - mips_trans_pos=%d.\n", block->start_pc, vaddr, + block->mips_trans_pos); + return (-1); + } + + if (!ipt || (ipt->cur_patch >= MIPS64_INSN_PATCH_TABLE_SIZE)) { + /* full table or no table, create a new one */ + ipt = malloc (sizeof (*ipt)); + if (!ipt) { + fprintf (stderr, + "Block 0x%8.8" LL "x: unable to create patch table.\n", + block->start_pc); + return (-1); + } + + memset (ipt, 0, sizeof (*ipt)); + ipt->next = block->patch_table; + block->patch_table = ipt; + } +#if DEBUG_BLOCK_PATCH + printf ("Block 0x%8.8llx: recording patch [JIT:%p->mips:0x%8.8llx], " + "MTP=%d\n", block->start_pc, jit_ptr, vaddr, block->mips_trans_pos); +#endif + + patch = &ipt->patches[ipt->cur_patch]; + patch->jit_insn = jit_ptr; + patch->mips_pc = vaddr; + ipt->cur_patch++; + return (0); +} + +/* Apply all patches */ +static int mips_jit_tcb_apply_patches (cpu_mips_t * cpu, + mips_jit_tcb_t * block) +{ + struct mips_jit_patch_table *ipt; + struct mips_insn_patch *patch; + u_char *jit_dst; + int i; + + for (ipt = block->patch_table; ipt; ipt = ipt->next) + for (i = 0; i < ipt->cur_patch; i++) { + patch = &ipt->patches[i]; + jit_dst = mips_jit_tcb_get_host_ptr (block, patch->mips_pc); + + if (jit_dst) { +#if DEBUG_BLOCK_PATCH + printf ("Block 0x%8.8llx: applying patch " + "[JIT:%p->mips:0x%8.8llx=JIT:%p]\n", + block->start_pc, patch->jit_insn, patch->mips_pc, + jit_dst); +#endif + mips_jit_tcb_set_patch (patch->jit_insn, jit_dst); + } + } + + return (0); +} + +/* Free the patch table */ +static void mips_jit_tcb_free_patches (mips_jit_tcb_t * block) +{ + struct mips_jit_patch_table *p, *next; + + for (p = block->patch_table; p; p = next) { + next = p->next; + free (p); + } + + block->patch_table = NULL; +} + +/* Adjust the JIT buffer if its size is not sufficient */ +static int mips_jit_tcb_adjust_buffer (cpu_mips_t * cpu, + mips_jit_tcb_t * block) +{ + insn_exec_page_t *new_buffer; + + if ((block->jit_ptr - block->jit_buffer->ptr) <= (MIPS_JIT_BUFSIZE - 512)) + return (0); + +#if DEBUG_BLOCK_CHUNK + printf ("Block 0x%" LL "x: adjusting JIT buffer...\n", block->start_pc); +#endif + + if (block->jit_chunk_pos >= MIPS_JIT_MAX_CHUNKS) { + fprintf (stderr, "Block 0x%" LL "x: too many JIT chunks.\n", + block->start_pc); + return (-1); + } + + if (!(new_buffer = exec_page_alloc (cpu))) + return (-1); + + /* record the new exec page */ + block->jit_chunks[block->jit_chunk_pos++] = block->jit_buffer; + block->jit_buffer = new_buffer; + + /* jump to the new exec page (link) */ + mips_jit_tcb_set_jump (block->jit_ptr, new_buffer->ptr); + block->jit_ptr = new_buffer->ptr; + + return (0); +} + +/* Allocate an instruction block */ +static inline mips_jit_tcb_t *mips_jit_tcb_alloc (cpu_mips_t * cpu) +{ + mips_jit_tcb_t *p; + + if (cpu->tcb_free_list) { + p = cpu->tcb_free_list; + cpu->tcb_free_list = p->next; + } else { + if (!(p = malloc (sizeof (*p)))) { + return NULL; + } + + } + + memset (p, 0, sizeof (*p)); + return p; +} + +/* Free an instruction block */ +void mips_jit_tcb_free (cpu_mips_t * cpu, mips_jit_tcb_t * block, + int list_removal) +{ + int i; + + if (block) { + if (list_removal) { + /* Remove the block from the linked list */ + if (block->next) + block->next->prev = block->prev; + else + cpu->tcb_last = block->prev; + + if (block->prev) + block->prev->next = block->next; + else + cpu->tcb_list = block->next; + } + + /* Free the patch tables */ + mips_jit_tcb_free_patches (block); + + /* Free code pages */ + for (i = 0; i < MIPS_JIT_MAX_CHUNKS; i++) + exec_page_free (cpu, block->jit_chunks[i]); + + /* Free the current JIT buffer */ + exec_page_free (cpu, block->jit_buffer); + + /* Free the MIPS-to-native code mapping */ + free (block->jit_insn_ptr); + + /* Make the block return to the free list */ + block->next = cpu->tcb_free_list; + cpu->tcb_free_list = block; + } +} + +#ifdef DEBUG_JIT +/*get the tcb count*/ +static void mips_jit_count_tcb (cpu_mips_t * cpu) +{ + + unsigned int i = 0; + insn_exec_page_t *p1; + p1 = cpu->exec_page_free_list; + while (p1 != NULL) { + p1 = p1->next; + i++; + } + printf ("FREE PAGES %x \n", i); + + i = 0; + mips_jit_tcb_t *tcb1; + tcb1 = cpu->tcb_list; + while (tcb1 != NULL) { + tcb1 = tcb1->next; + i++; + } + printf ("tcb list %x \n", i); + + i = 0; + tcb1 = cpu->tcb_free_list; + while (tcb1 != NULL) { + tcb1 = tcb1->next; + i++; + } + printf ("tcb free list %x \n", i); + +} +#endif +/* Create an instruction block */ +static mips_jit_tcb_t *mips_jit_tcb_create (cpu_mips_t * cpu, + m_va_t vaddr) +{ + mips_jit_tcb_t *block = NULL; + m_uint32_t asid; + + if (!(block = mips_jit_tcb_alloc (cpu))) + goto err_block_alloc; + + block->start_pc = vaddr; + + int zone = (vaddr >> 29) & 0x7; + if ((zone == 0x4) || (zone == 0x5)) { + + } else { + mips_cp0_t *cp0 = &cpu->cp0; + asid = cp0->reg[MIPS_CP0_TLB_HI] & MIPS_TLB_ASID_MASK; + block->asid = asid; + } + + /* Allocate the first JIT buffer */ + if (!(block->jit_buffer = exec_page_alloc (cpu))) + goto err_jit_alloc; + + block->jit_ptr = block->jit_buffer->ptr; + block->mips_code = cpu->mem_op_lookup (cpu, block->start_pc); + + if (!block->mips_code) { + /*TLB Exception */ + int zone = (block->start_pc >> 29) & 0x7; + switch (zone) { + case 0x0: + case 0x1: + case 0x2: + case 0x3: + case 0x6: + case 0x7: + /*Return the tcb to tcb free list */ + cpu->exec_blk_map[mips_jit_get_pc_hash (cpu, block->start_pc)] = + NULL; + mips_jit_tcb_free (cpu, block, FALSE); + longjmp (run_jmp, 1); + break; + default: + fprintf (stderr, + "No memory map for code execution at 0x%" LL "x\n", + block->start_pc); + goto err_lookup; + } + + } + + return block; + + err_lookup: + err_jit_alloc: + mips_jit_tcb_free (cpu, block, FALSE); + err_block_alloc: + fprintf (stderr, + "%% Unable to create instruction block for vaddr=0x%" LL "x\n", + vaddr); + return NULL; +} + +/* Compile a MIPS instruction page */ +static inline + mips_jit_tcb_t * mips_jit_tcb_compile (cpu_mips_t * cpu, m_va_t vaddr) +{ + mips_jit_tcb_t *block; + m_uint64_t page_addr; + size_t len; + + page_addr = vaddr & ~(m_uint64_t) MIPS_MIN_PAGE_IMASK; + + if (unlikely (!(block = mips_jit_tcb_create (cpu, page_addr)))) { + fprintf (stderr, "insn_page_compile: unable to create JIT block.\n"); + return NULL; + } + + /* Allocate the array used to convert MIPS code ptr to native code ptr */ + len = MIPS_MIN_PAGE_SIZE / sizeof (mips_insn_t); + + if (!(block->jit_insn_ptr = calloc (len, sizeof (u_char *)))) { + fprintf (stderr, + "insn_page_compile: unable to create JIT mappings.\n"); + goto error; + } + + /* Emit native code for each instruction */ + block->mips_trans_pos = 0; + + while (block->mips_trans_pos < MIPS_INSN_PER_PAGE) { + if (unlikely ((mips_jit_fetch_and_emit (cpu, block, 0) == -1))) { + fprintf (stderr, + "insn_page_compile: unable to fetch instruction.\n"); + goto error; + } +#if DEBUG_BLOCK_COMPILE + printf ("Page 0x%8.8" LL "x: emitted tag 0x%8.8x/0x%8.8x\n", + block->start_pc, tag->mask, tag->value); +#endif + + mips_jit_tcb_adjust_buffer (cpu, block); + } + + mips_jit_tcb_add_end (block); + mips_jit_tcb_apply_patches (cpu, block); + mips_jit_tcb_free_patches (block); + + /* Add the block to the linked list */ + block->next = cpu->tcb_list; + block->prev = NULL; + + if (cpu->tcb_list) + cpu->tcb_list->prev = block; + else + cpu->tcb_last = block; + + cpu->tcb_list = block; + + cpu->compiled_pages++; + return block; + + error: + mips_jit_tcb_free (cpu, block, FALSE); + return NULL; +} + +/* Run a compiled MIPS instruction block */ +static forced_inline + void mips_jit_tcb_run (cpu_mips_t * cpu, mips_jit_tcb_t * block) +{ + + if (unlikely (cpu->pc & 0x03)) { + fprintf (stderr, "mips_jit_tcb_run: Invalid PC 0x%" LL "x.\n", + cpu->pc); + cpu_stop (cpu); + return; + } + /* Execute JIT compiled code */ + mips_jit_tcb_exec (cpu, block); +} + +void *mips_jit_run_cpu (cpu_mips_t * cpu) +{ + + m_uint32_t pc_hash; + mips_jit_tcb_t *block; + + cpu->cpu_thread_running = TRUE; + current_cpu = cpu; + + mips_init_host_alarm (); + + setjmp (run_jmp); + + start_cpu: + for (;;) { + if (unlikely (cpu->state != CPU_STATE_RUNNING)) + break; + + if (unlikely ((cpu->pause_request) & CPU_INTERRUPT_EXIT)) { + cpu->state = CPU_STATE_PAUSING; + break; + } + + /* Reset "zero register" (for safety) */ + cpu->gpr[0] = 0; + + /* Check IRQ */ + if (unlikely (cpu->irq_pending)) { + mips_trigger_irq (cpu); + //continue; + } + + pc_hash = mips_jit_get_pc_hash (cpu, cpu->pc); + block = cpu->exec_blk_map[pc_hash]; + + /* No block found, compile the page */ + if (unlikely (!block) + || unlikely (!mips_jit_tcb_match (cpu, block, cpu->pc))) { + + if (block != NULL) { + mips_jit_tcb_free (cpu, block, TRUE); + cpu->exec_blk_map[pc_hash] = NULL; + } + + block = mips_jit_tcb_compile (cpu, cpu->pc); + if (unlikely (!block)) { + fprintf (stderr, + "VM '%s': unable to compile block for CPU%u PC=0x%" LL + "x\n", cpu->vm->name, cpu->id, cpu->pc); + cpu_stop (cpu); + break; + } + block->acc_count++; + cpu->exec_blk_map[pc_hash] = block; + } + mips_jit_tcb_run (cpu, block); + + } + + while (cpu->cpu_thread_running) { + switch (cpu->state) { + case CPU_STATE_RUNNING: + cpu->state = CPU_STATE_RUNNING; + goto start_cpu; + + case CPU_STATE_HALTED: + cpu->cpu_thread_running = FALSE; + break; + case CPU_STATE_RESTARTING: + cpu->state = CPU_STATE_RESTARTING; + /*Just waiting for cpu restart. */ + break; + case CPU_STATE_PAUSING: + /*main loop must wait for me. heihei :) */ + mips_main_loop_wait (cpu, 0); + cpu->state = CPU_STATE_RUNNING; + cpu->pause_request &= ~CPU_INTERRUPT_EXIT; + /*start cpu again */ + goto start_cpu; + + } + } + return NULL; +} + +#endif diff --git a/tools/virtualmips/mips_jit.h b/tools/virtualmips/mips_jit.h new file mode 100644 index 0000000..5f77079 --- /dev/null +++ b/tools/virtualmips/mips_jit.h @@ -0,0 +1,279 @@ +/* + * Copyright (C) yajin 2008 + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + * + */ + +/* +JIT Support. +In order to improve the simulation speed, JIT is always used in simulators. +Unlike the JIT of high language, virtualmips does not have basic block. +It translates one page(4K) code one time and then run it. + +Problems: + +1. code fetch exception +2. delay slot +3. interrupt emulation +4. Self-modify code +5. debug JIT + +How to debug JIT is the most tricky problem. +I do not have better method, but just logging and comparing with +interpreter. Thanks to the file diff tools. + +If you know how to debug JIT, please tell me. + +Most of the code is stripped from Dynamips. Thanks Christophe Fillot. + +Many optimation chances exist. +1. add asid as a hash key of translated block so that translated block is not fushed too often. +2. A better way to find translated block. red-block tree?? +3. peephole optimation??? +4. Use profile tools such as vtune to find the hot path and then optimize it. + + +*/ + +#ifndef __MIPS64_JIT_H__ +#define __MIPS64_JIT_H__ + +#include "system.h" +#include "utils.h" +#include "sbox.h" +#include "mips.h" +#include "mips_memory.h" + +#ifndef _USE_JIT_ +#define JIT_SUPPORT 0 +#endif + +#ifdef _USE_JIT_ + +#define JIT_SUPPORT 1 + +/* Size of executable page area (in Mb) */ +#ifndef __CYGWIN__ +#define MIPS_EXEC_AREA_SIZE 64 +#else +#define MIPS_EXEC_AREA_SIZE 16 +#endif + +/* Buffer size for JIT code generation */ +#define MIPS_JIT_BUFSIZE 32768 + +/* Maximum number of X86 chunks */ +#define MIPS_JIT_MAX_CHUNKS 32 + +/* Size of hash for PC lookup */ +#define MIPS_JIT_PC_HASH_BITS 16 +#define MIPS_JIT_PC_HASH_MASK ((1 << MIPS_JIT_PC_HASH_BITS) - 1) +#define MIPS_JIT_PC_HASH_SIZE (1 << MIPS_JIT_PC_HASH_BITS) + +/* Instruction jump patch */ +struct mips_insn_patch { + u_char *jit_insn; + m_uint64_t mips_pc; +}; + +/* Instruction patch table */ +#define MIPS64_INSN_PATCH_TABLE_SIZE 32 + +struct mips_jit_patch_table { + struct mips_insn_patch patches[MIPS64_INSN_PATCH_TABLE_SIZE]; + u_int cur_patch; + struct mips_jit_patch_table *next; +}; + +/* Host executable page */ +struct insn_exec_page { + u_char *ptr; + insn_exec_page_t *next; +}; + +/* MIPS64 translated code block */ +struct mips_jit_tcb { + /*start pc in tcb */ + m_va_t start_pc; + m_uint32_t asid; + m_uint32_t acc_count; + /*guest pc to host pc mapping table */ + u_char **jit_insn_ptr; + /*guest code of this tcb */ + mips_insn_t *mips_code; + u_int mips_trans_pos; + u_int jit_chunk_pos; + /*used in translating */ + u_char *jit_ptr; + insn_exec_page_t *jit_buffer; + insn_exec_page_t *jit_chunks[MIPS_JIT_MAX_CHUNKS]; + struct mips_jit_patch_table *patch_table; + mips_jit_tcb_t *prev, *next; +}; + +int mips_jit_init (cpu_mips_t * cpu); +int mips_jit_flush (cpu_mips_t * cpu, m_uint32_t threshold); +void mips_jit_shutdown (cpu_mips_t * cpu); +int mips_jit_fetch_and_emit (cpu_mips_t * cpu, + mips_jit_tcb_t * block, int delay_slot); + +int mips_jit_tcb_record_patch (mips_jit_tcb_t * block, u_char * jit_ptr, + m_va_t vaddr); +void mips_jit_tcb_free (cpu_mips_t * cpu, mips_jit_tcb_t * block, + int list_removal); + +void *mips_jit_run_cpu (cpu_mips_t * cpu); + +/*-----------inline functions-----------------------------*/ +/* Get the JIT instruction pointer in a translated block */ +static forced_inline + u_char * mips_jit_tcb_get_host_ptr (mips_jit_tcb_t * b, m_va_t vaddr) +{ + m_uint32_t offset; + + offset = ((m_uint32_t) vaddr & MIPS_MIN_PAGE_IMASK) >> 2; + return (b->jit_insn_ptr[offset]); +} + +/* Check if the specified address belongs to the specified block */ +static forced_inline + int mips_jit_tcb_local_addr (mips_jit_tcb_t * block, m_va_t vaddr, + u_char ** jit_addr) +{ + if ((vaddr & MIPS_MIN_PAGE_MASK) == block->start_pc) { + *jit_addr = mips_jit_tcb_get_host_ptr (block, vaddr); + return (1); + } + + return (0); +} + +extern int test33; + +/* Check if PC register matches the compiled block virtual address */ +static forced_inline + int mips_jit_tcb_match (cpu_mips_t * cpu, mips_jit_tcb_t * block, + m_va_t vaddr) +{ + m_va_t vpage; + + // vpage = cpu->pc & ~(m_va_t)MIPS_MIN_PAGE_IMASK; + vpage = vaddr & ~(m_va_t) MIPS_MIN_PAGE_IMASK; + if (block->start_pc != vpage) + return 0; + /*block->start_pc == vpage */ + if (!vaddr_mapped (vaddr)) + return 1; + /*block->start_pc == vpage and mapped.check asid */ + int asid = cpu->cp0.reg[MIPS_CP0_TLB_HI] & MIPS_TLB_ASID_MASK; + + return (block->asid == asid); +} + +/* Compute the hash index for the specified PC value */ +/*TODO: Add asid as a hash key. +Currently same pc of different asid will get the same hash value. +*/ +static forced_inline m_uint32_t mips_jit_get_pc_hash (cpu_mips_t * cpu, + m_va_t pc) +{ + m_uint32_t page_hash; + + page_hash = sbox_u32 (pc >> MIPS_MIN_PAGE_SHIFT); + return ((page_hash ^ (page_hash >> 12)) & MIPS_JIT_PC_HASH_MASK); + +} + +/*if the code write to code region, flush the translated page*/ +static forced_inline void jit_handle_self_write (cpu_mips_t * cpu, + m_va_t vaddr) +{ + m_uint32_t pc_hash; + mips_jit_tcb_t *block; + + pc_hash = mips_jit_get_pc_hash (cpu, vaddr); + block = cpu->exec_blk_map[pc_hash]; + if (block != NULL) { + if (unlikely (mips_jit_tcb_match (cpu, block, vaddr))) { + mips_jit_tcb_free (cpu, block, TRUE); + cpu->exec_blk_map[pc_hash] = NULL; + } + } +} + +/*whether instruction is a jump instruction*/ +static forced_inline int insn_is_jmp (unsigned int insn) +{ + /*can insn be in delay slot */ + int op = MAJOR_OP (insn); + uint16_t special_func; + switch (op) { + case 0x0: + { + special_func = bits (insn, 0, 5); + switch (special_func) { + case 0x8: + case 0x9: + return 1; + default: + return 0; + } + + } + case 0x1: + { + special_func = bits (insn, 16, 20); + switch (special_func) { + case 0x0: + case 0x1: + case 0x2: + case 0x3: + case 0x4: + case 0x10: + case 0x11: + case 0x12: + case 0x13: + return 1; + default: + return 0; + } + + } + case 0x2: + case 0x3: + case 0x4: + case 0x5: + case 0x6: + case 0x7: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + return 1; + default: + return 0; + + } + +} + +/* Check if an instruction is in a delay slot or not */ +static forced_inline int mips_jit_is_delay_slot (mips_jit_tcb_t * b, + m_va_t pc) +{ + m_uint32_t offset, insn; + + offset = (pc - b->start_pc) >> 2; + + if (!offset) + return (FALSE); + ASSERT (b->mips_code != NULL, "b->mips_code can not be NULL\n"); + /* Fetch the previous instruction to determine if it is a jump */ + insn = vmtoh32 (b->mips_code[offset - 1]); + return insn_is_jmp (insn); +} +#endif + +#endif diff --git a/tools/virtualmips/mips_memory.c b/tools/virtualmips/mips_memory.c new file mode 100644 index 0000000..f00a6de --- /dev/null +++ b/tools/virtualmips/mips_memory.c @@ -0,0 +1,1520 @@ +/* + * Cisco router simulation platform. + * Copyright (c) 2005,2006 Christophe Fillot (cf@utc.fr) + * Copyright (C) yajin 2008 + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cpu.h" +#include "vm.h" +#include "mips_memory.h" +#include "device.h" +#include "utils.h" +#include "mips_cp0.h" +#include "gdb_interface.h" +#include "mips_jit.h" + +void bad_memory_access (cpu_mips_t * cpu, m_va_t vaddr) +{ + mips_insn_t insn; + + printf ("*** %08x: bad memory reference\n", vaddr); + if (mips_fetch_instruction (cpu, cpu->pc, &insn) == 0) { + printf ("*** %08x: %08x ", cpu->pc, insn); + print_insn_mips (cpu->pc, insn, stdout); + printf ("\n"); + } + if (mips_fetch_instruction (cpu, cpu->pc + 4, &insn) == 0) { + printf ("*** %08x: %08x ", cpu->pc + 4, insn); + print_insn_mips (cpu->pc, insn, stdout); + printf ("\n"); + } + dumpregs (cpu); + if (cpu->vm->mipsy_debug_mode) + bad_memory_access_gdb (cpu->vm); + else + assert (0); +} + +/* + * MTS access with special access mask + */ +void mips_access_special (cpu_mips_t * cpu, m_va_t vaddr, m_uint32_t mask, + u_int op_code, u_int op_type, u_int op_size, m_reg_t * data, u_int * exc) +{ + m_reg_t vpn; + m_uint8_t exc_code; + + switch (mask) { + case MTS_ACC_U: + if (op_type == MTS_READ) + *data = 0; + break; + + case MTS_ACC_T: + case MTS_ACC_M: + case MTS_ACC_AE: + //if (op_code != MIPS_MEMOP_LOOKUP) + //lookup also raise exception + { + cpu->cp0.reg[MIPS_CP0_BADVADDR] = vaddr; + //clear vpn of entry hi + cpu->cp0.reg[MIPS_CP0_TLB_HI] &= + ~(mips_cp0_get_vpn2_mask (cpu)); + //set VPN of entryhi + vpn = vaddr & mips_cp0_get_vpn2_mask (cpu); + cpu->cp0.reg[MIPS_CP0_TLB_HI] |= vpn; + + //set context register + cpu->cp0.reg[MIPS_CP0_CONTEXT] &= ~MIPS_CP0_CONTEXT_BADVPN2_MASK; + vaddr = (vaddr >> 13) << 4; + vaddr = vaddr & MIPS_CP0_CONTEXT_BADVPN2_MASK; + cpu->cp0.reg[MIPS_CP0_CONTEXT] |= vaddr; +#ifdef SIM_PIC32 + if (op_type == MTS_READ) + exc_code = MIPS_CP0_CAUSE_ADDR_LOAD; + else + exc_code = MIPS_CP0_CAUSE_ADDR_SAVE; +#else + if (mask == MTS_ACC_M) + exc_code = MIPS_CP0_CAUSE_TLB_MOD; + else if (mask == MTS_ACC_T) { + if (op_type == MTS_READ) + exc_code = MIPS_CP0_CAUSE_TLB_LOAD; + else + exc_code = MIPS_CP0_CAUSE_TLB_SAVE; + } else if (mask == MTS_ACC_AE) { + if (op_type == MTS_READ) + exc_code = MIPS_CP0_CAUSE_ADDR_LOAD; + else + exc_code = MIPS_CP0_CAUSE_ADDR_SAVE; + } else + assert (0); +#endif + mips_trigger_exception (cpu, exc_code, cpu->is_in_bdslot); + } + *exc = 1; + break; + } +} + +/* === MTS for 32-bit address space ======================================= */ +#ifdef MTS_ADDR_SIZE +#undef MTS_ADDR_SIZE +#endif + +#define MTS_ADDR_SIZE 32 + +static int mips_mts32_translate (cpu_mips_t * cpu, m_va_t vaddr, + m_uint32_t * phys_page); + +/* + * Initialize the MTS subsystem for the specified CPU + */ +int mips_mts32_init (cpu_mips_t * cpu) +{ + size_t len; + + /* Initialize the cache entries to 0 (empty) */ + len = MTS32_HASH_SIZE * sizeof (mts32_entry_t); + cpu->mts_u.mts32_cache = malloc (len); + if (! cpu->mts_u.mts32_cache) + return (-1); + + memset (cpu->mts_u.mts32_cache, 0xFF, len); + cpu->mts_lookups = 0; + cpu->mts_misses = 0; + return (0); +} + +/* Free memory used by MTS */ +void mips_mts32_shutdown (cpu_mips_t * cpu) +{ + /* Free the cache itself */ + free (cpu->mts_u.mts32_cache); + cpu->mts_u.mts32_cache = NULL; +} + +/* Show MTS detailed information (debugging only!) */ +void mips_mts32_show_stats (cpu_mips_t * cpu) +{ +#if DEBUG_MTS_MAP_VIRT + mts32_entry_t *entry; + u_int i, count; +#endif + + printf ("\nCPU%u: MTS%d statistics:\n", cpu->id, MTS_ADDR_SIZE); + +#if DEBUG_MTS_MAP_VIRT + /* Valid hash entries */ + for (count = 0, i = 0; i < MTS32_HASH_SIZE; i++) { + entry = &(cpu->mts_u.mts32_cache[i]); + + if (!(entry->gvpa & MTS_INV_ENTRY_MASK)) { + printf (" %4u: vaddr=0x%8.8llx, paddr=0x%8.8llx, hpa=%p\n", + i, (m_uint64_t) entry->gvpa, (m_uint64_t) entry->gppa, + (void *) entry->hpa); + count++; + } + } + + printf (" %u/%u valid hash entries.\n", count, MTS32_HASH_SIZE); +#endif + + printf (" Total lookups: %llu, misses: %llu, efficiency: %g%%\n", + cpu->mts_lookups, cpu->mts_misses, + 100 - ((double) (cpu->mts_misses * 100) / (double) cpu->mts_lookups)); +} + +/* Invalidate the complete MTS cache */ +void mips_mts32_invalidate_cache (cpu_mips_t * cpu) +{ + size_t len; + + len = MTS32_HASH_SIZE * sizeof (mts32_entry_t); + memset (cpu->mts_u.mts32_cache, 0xFF, len); +} + +/* Invalidate partially the MTS cache, given a TLB entry index */ +void mips_mts32_invalidate_tlb_entry (cpu_mips_t * cpu, m_va_t vaddr) +{ + mts32_entry_t *entry; + m_uint32_t hash_bucket; + + hash_bucket = MTS32_HASH (vaddr); + entry = &cpu->mts_u.mts32_cache[hash_bucket]; + memset (entry, 0xFF, sizeof (mts32_entry_t)); +} + +/* + * MTS mapping. + * + * It is NOT inlined since it triggers a GCC bug on my config (x86, GCC 3.3.5) + */ +static no_inline mts32_entry_t *mips_mts32_map (cpu_mips_t * cpu, + u_int op_type, mts_map_t * map, mts32_entry_t * entry, + mts32_entry_t * alt_entry, u_int is_fromgdb) +{ + struct vdevice *dev; + m_uint32_t offset; + + dev = dev_lookup (cpu->vm, map->paddr); + if (! dev) { + if (! is_fromgdb) { + printf ("no device!\n"); + printf ("cpu->pc %x vaddr %x paddr %x \n", cpu->pc, map->vaddr, + map->paddr); + exit (-1); + } + return NULL; + } + + if (! dev->host_addr || (dev->flags & VDEVICE_FLAG_NO_MTS_MMAP)) { + offset = map->paddr - dev->phys_addr; + + alt_entry->gvpa = map->vaddr; + alt_entry->gppa = map->paddr; + alt_entry->hpa = (dev->id << MTS_DEVID_SHIFT) + offset; + alt_entry->flags = MTS_FLAG_DEV; + alt_entry->mapped = map->mapped; + return alt_entry; + } + ASSERT (dev->host_addr != 0, "dev->host_addr can not be null\n"); + entry->gvpa = map->vaddr; + entry->gppa = map->paddr; + entry->hpa = dev->host_addr + (map->paddr - dev->phys_addr); + entry->flags = 0; + entry->asid = map->asid; + entry->g_bit = map->g_bit; + entry->dirty_bit = map->dirty; + entry->mapped = map->mapped; + return entry; +} + +/* MTS lookup */ +static fastcall void *mips_mts32_lookup (cpu_mips_t * cpu, m_va_t vaddr) +{ + m_reg_t data; + u_int exc; + m_uint8_t has_set_value = FALSE; + return (mips_mts32_access (cpu, vaddr, MIPS_MEMOP_LOOKUP, 4, MTS_READ, + &data, &exc, &has_set_value, 0)); +} + +/* === MIPS Memory Operations ============================================= */ + +u_int mips_mts32_gdb_lb (cpu_mips_t * cpu, m_va_t vaddr, void *cur) +{ + // m_reg_t data; + void *haddr; + u_int exc; + m_uint8_t has_set_value = FALSE; + + haddr = mips_mts32_access (cpu, vaddr, MIPS_MEMOP_LB, 1, MTS_READ, + (m_reg_t *) cur, &exc, &has_set_value, 1); + + if ((exc) || (haddr == NULL)) + *(m_uint8_t *) cur = 0x0; + else + *(m_uint8_t *) cur = (*(m_uint8_t *) haddr); + + return (0); +} + +/* LB: Load Byte */ +u_int fastcall mips_mts32_lb (cpu_mips_t * cpu, m_va_t vaddr, u_int reg) +{ + m_reg_t data; + void *haddr; + u_int exc; + m_uint8_t has_set_value = FALSE; + + haddr = + mips_mts32_access (cpu, vaddr, MIPS_MEMOP_LB, 1, MTS_READ, &data, + &exc, &has_set_value, 0); + if (exc) + return exc; + if ((haddr == NULL) && (has_set_value == FALSE)) { + bad_memory_access (cpu, vaddr); + } + + if (likely (has_set_value == FALSE)) + data = *(m_uint8_t *) haddr; + if (likely (!exc)) + cpu->reg_set (cpu, reg, sign_extend (data, 8)); + return (exc); +} + +/* LBU: Load Byte Unsigned */ +u_int fastcall mips_mts32_lbu (cpu_mips_t * cpu, m_va_t vaddr, u_int reg) +{ + m_reg_t data; + void *haddr; + u_int exc; + m_uint8_t has_set_value = FALSE; + + haddr = + mips_mts32_access (cpu, vaddr, MIPS_MEMOP_LBU, 1, MTS_READ, &data, + &exc, &has_set_value, 0); + if (exc) + return exc; + if ((haddr == NULL) && (has_set_value == FALSE)) { + bad_memory_access (cpu, vaddr); + } + if (likely (has_set_value == FALSE)) + data = *(m_uint8_t *) haddr; + if (likely (!exc)) + cpu->reg_set (cpu, reg, data & 0xff); + return (exc); +} + +/* LH: Load Half-Word */ +u_int fastcall mips_mts32_lh (cpu_mips_t * cpu, m_va_t vaddr, u_int reg) +{ + m_reg_t data; + void *haddr; + u_int exc; + m_uint8_t has_set_value = FALSE; + + haddr = + mips_mts32_access (cpu, vaddr, MIPS_MEMOP_LH, 2, MTS_READ, &data, + &exc, &has_set_value, 0); + if (exc) + return exc; + if ((haddr == NULL) && (has_set_value == FALSE)) { + bad_memory_access (cpu, vaddr); + } + if (likely (has_set_value == FALSE)) + data = vmtoh16 (*(m_uint16_t *) haddr); + if (likely (!exc)) + cpu->reg_set (cpu, reg, sign_extend (data, 16)); + return (exc); +} + +/* LHU: Load Half-Word Unsigned */ +u_int fastcall mips_mts32_lhu (cpu_mips_t * cpu, m_va_t vaddr, u_int reg) +{ + m_reg_t data; + void *haddr; + u_int exc; + m_uint8_t has_set_value = FALSE; + + haddr = + mips_mts32_access (cpu, vaddr, MIPS_MEMOP_LHU, 2, MTS_READ, &data, + &exc, &has_set_value, 0); + if (exc) + return exc; + if ((haddr == NULL) && (has_set_value == FALSE)) { + bad_memory_access (cpu, vaddr); + } + if (likely (has_set_value == FALSE)) + data = vmtoh16 (*(m_uint16_t *) haddr); + if (likely (!exc)) + cpu->reg_set (cpu, reg, data & 0xffff); + return (exc); +} + +/* LW: Load Word */ +u_int fastcall mips_mts32_lw (cpu_mips_t * cpu, m_va_t vaddr, u_int reg) +{ + m_reg_t data; + void *haddr; + u_int exc; + m_uint8_t has_set_value = FALSE; + haddr = + mips_mts32_access (cpu, vaddr, MIPS_MEMOP_LW, 4, MTS_READ, &data, + &exc, &has_set_value, 0); + if (exc) + return exc; + if ((haddr == NULL) && (has_set_value == FALSE)) { + bad_memory_access (cpu, vaddr); + } + + if (likely (has_set_value == FALSE)) { + data = vmtoh32 (*(m_uint32_t *) haddr); + } + if (likely (!exc)) { + if (cpu->vm->debug_level > 2 || (cpu->vm->debug_level > 1 && + (cpu->cp0.reg[MIPS_CP0_STATUS] & MIPS_CP0_STATUS_UM) && + ! (cpu->cp0.reg[MIPS_CP0_STATUS] & MIPS_CP0_STATUS_EXL) && + vaddr >= 0x7f008000 && vaddr < 0x7f020000)) + { + /* Print memory accesses in user mode. */ + printf (" read %08x -> %08x \n", vaddr, data); + } + cpu->reg_set (cpu, reg, sign_extend (data, 32)); + } + return (exc); +} + +/* LWU: Load Word Unsigned */ +u_int fastcall mips_mts32_lwu (cpu_mips_t * cpu, m_va_t vaddr, u_int reg) +{ + m_reg_t data; + void *haddr; + u_int exc; + m_uint8_t has_set_value = FALSE; + + haddr = + mips_mts32_access (cpu, vaddr, MIPS_MEMOP_LWU, 4, MTS_READ, &data, + &exc, &has_set_value, 0); + if (exc) + return exc; + if ((haddr == NULL) && (has_set_value == FALSE)) { + bad_memory_access (cpu, vaddr); + } + if (likely (has_set_value == FALSE)) + data = vmtoh32 (*(m_uint32_t *) haddr); + if (likely (!exc)) + cpu->reg_set (cpu, reg, data & 0xffffffff); + return (exc); +} + +/* LD: Load Double-Word */ +u_int fastcall mips_mts32_ld (cpu_mips_t * cpu, m_va_t vaddr, u_int reg) +{ + m_reg_t data; + void *haddr; + u_int exc; + m_uint8_t has_set_value = FALSE; + + haddr = + mips_mts32_access (cpu, vaddr, MIPS_MEMOP_LD, 8, MTS_READ, &data, + &exc, &has_set_value, 0); + if (exc) + return exc; + if ((haddr == NULL) && (has_set_value == FALSE)) { + bad_memory_access (cpu, vaddr); + } + if (likely (has_set_value == FALSE)) + data = vmtoh64 (*(m_uint64_t *) haddr); + if (likely (!exc)) + cpu->reg_set (cpu, reg, data); + return (exc); +} + +/* SB: Store Byte */ +u_int fastcall mips_mts32_sb (cpu_mips_t * cpu, m_va_t vaddr, u_int reg) +{ + m_reg_t data; + void *haddr = NULL; + u_int exc; + m_uint8_t has_set_value = FALSE; + + data = cpu->gpr[reg] & 0xff; + haddr = + mips_mts32_access (cpu, vaddr, MIPS_MEMOP_SB, 1, MTS_WRITE, &data, + &exc, &has_set_value, 0); + if (exc) + return exc; + if ((haddr == NULL) && (has_set_value == FALSE)) { + bad_memory_access (cpu, vaddr); + } + if (likely (has_set_value == FALSE)) { +#ifdef _USE_JIT_ + if (cpu->vm->jit_use) + jit_handle_self_write (cpu, vaddr); +#endif + *(m_uint8_t *) haddr = data; + } + + return (exc); +} + +/* SH: Store Half-Word */ +u_int fastcall mips_mts32_sh (cpu_mips_t * cpu, m_va_t vaddr, u_int reg) +{ + m_reg_t data; + void *haddr; + u_int exc; + m_uint8_t has_set_value = FALSE; + + data = cpu->gpr[reg] & 0xffff; + haddr = + mips_mts32_access (cpu, vaddr, MIPS_MEMOP_SH, 2, MTS_WRITE, &data, + &exc, &has_set_value, 0); + if (exc) + return exc; + if ((haddr == NULL) && (has_set_value == FALSE)) { + bad_memory_access (cpu, vaddr); + } + if (likely (has_set_value == FALSE)) { +#ifdef _USE_JIT_ + if (cpu->vm->jit_use) + jit_handle_self_write (cpu, vaddr); +#endif + *(m_uint16_t *) haddr = htovm16 (data); + } + + return (exc); +} + +/* SW: Store Word */ +u_int fastcall mips_mts32_sw (cpu_mips_t * cpu, m_va_t vaddr, u_int reg) +{ + m_reg_t data; + void *haddr; + u_int exc; + m_uint8_t has_set_value = FALSE; + + data = cpu->gpr[reg] & 0xffffffff; + + haddr = + mips_mts32_access (cpu, vaddr, MIPS_MEMOP_SW, 4, MTS_WRITE, &data, + &exc, &has_set_value, 0); + if (exc) + return exc; + if ((haddr == NULL) && (has_set_value == FALSE)) { + bad_memory_access (cpu, vaddr); + } + if (likely (has_set_value == FALSE)) { +#ifdef _USE_JIT_ + if (cpu->vm->jit_use) + jit_handle_self_write (cpu, vaddr); +#endif + *(m_uint32_t *) haddr = htovm32 (data); + if (cpu->vm->debug_level > 2 || (cpu->vm->debug_level > 1 && + (cpu->cp0.reg[MIPS_CP0_STATUS] & MIPS_CP0_STATUS_UM) && + ! (cpu->cp0.reg[MIPS_CP0_STATUS] & MIPS_CP0_STATUS_EXL) && + vaddr >= 0x7f008000 && vaddr < 0x7f020000)) + { + /* Print memory accesses in user mode. */ + printf (" write %08x := %08x \n", vaddr, data); + } + } + return (exc); +} + +/* SD: Store Double-Word */ +u_int fastcall mips_mts32_sd (cpu_mips_t * cpu, m_va_t vaddr, u_int reg) +{ + m_reg_t data; + void *haddr; + u_int exc; + m_uint8_t has_set_value = FALSE; + + data = cpu->gpr[reg]; + haddr = + mips_mts32_access (cpu, vaddr, MIPS_MEMOP_SD, 8, MTS_WRITE, &data, + &exc, &has_set_value, 0); + if (exc) + return exc; + if ((haddr == NULL) && (has_set_value == FALSE)) { + bad_memory_access (cpu, vaddr); + } + if (likely (has_set_value == FALSE)) + *(m_uint64_t *) haddr = htovm64 (data); + return (exc); +} + +/* LDC1: Load Double-Word To Coprocessor 1 */ +u_int fastcall mips_mts32_ldc1 (cpu_mips_t * cpu, m_va_t vaddr, u_int reg) +{ + printf ("mips_mts32_ldc1 pc %x\n", cpu->pc); + exit (-1); + return 0; +} + +u_int fastcall mips_mts32_lwl (cpu_mips_t * cpu, m_va_t vaddr, u_int reg) +{ + void *haddr = NULL; + u_int exc; + m_uint32_t data, naddr, shift = 0, mask1 = 0, mask2 = 0; + m_uint8_t has_set_value = FALSE; + + naddr = vaddr & ~(0x03); + haddr = + mips_mts32_access (cpu, naddr, MIPS_MEMOP_LWL, 4, MTS_READ, &data, + &exc, &has_set_value, 0); + + if (exc) + return exc; + if ((haddr == NULL) && (has_set_value == FALSE)) { + bad_memory_access (cpu, vaddr); + } + if (has_set_value == FALSE) { + data = vmtoh32 (*(m_reg_t *) haddr); + + switch (vaddr & 0x3) { +#if GUEST_BYTE_ORDER==ARCH_LITTLE_ENDIAN + case 0x0: +#elif GUEST_BYTE_ORDER==ARCH_BIG_ENDIAN + case 0x3: +#endif + mask1 = 0xff; + mask2 = 0xff000000; + shift = 24; + break; +#if GUEST_BYTE_ORDER==ARCH_LITTLE_ENDIAN + case 0x1: +#elif GUEST_BYTE_ORDER==ARCH_BIG_ENDIAN + case 0x2: +#endif + mask1 = 0xffff; + mask2 = 0xffff0000; + shift = 16; + break; +#if GUEST_BYTE_ORDER==ARCH_LITTLE_ENDIAN + case 0x2: +#elif GUEST_BYTE_ORDER==ARCH_BIG_ENDIAN + case 0x1: +#endif + mask1 = 0xffffff; + mask2 = 0xffffff00; + shift = 8; + break; +#if GUEST_BYTE_ORDER==ARCH_LITTLE_ENDIAN + case 0x3: +#elif GUEST_BYTE_ORDER==ARCH_BIG_ENDIAN + case 0x0: +#endif + mask1 = 0xffffffff; + mask2 = 0xffffffff; + shift = 0; + break; + } + + data = (data & mask1) << shift; + data &= mask2; + cpu->gpr[reg] &= ~mask2; + cpu->gpr[reg] |= data; + cpu->reg_set (cpu, reg, sign_extend (cpu->gpr[reg], 32)); + } + return 0; +} + +u_int fastcall mips_mts32_lwr (cpu_mips_t * cpu, m_va_t vaddr, u_int reg) +{ + void *haddr = NULL; + u_int exc; + m_uint32_t data, naddr, shift = 0, mask1 = 0, mask2 = 0; + m_uint8_t has_set_value = FALSE; + + naddr = vaddr & ~(0x03); + haddr = + mips_mts32_access (cpu, naddr, MIPS_MEMOP_LWR, 4, MTS_READ, &data, + &exc, &has_set_value, 0); + + if (exc) + return exc; + if ((haddr == NULL) && (has_set_value == FALSE)) { + bad_memory_access (cpu, vaddr); + } + + if (has_set_value == FALSE) { + + data = vmtoh32 (*(m_reg_t *) haddr); + + switch (vaddr & 0x3) { +#if GUEST_BYTE_ORDER==ARCH_LITTLE_ENDIAN + case 0x3: +#elif GUEST_BYTE_ORDER==ARCH_BIG_ENDIAN + case 0x0: +#endif + mask1 = 0xff; + mask2 = 0xff000000; + shift = 24; + break; +#if GUEST_BYTE_ORDER==ARCH_LITTLE_ENDIAN + case 0x2: +#elif GUEST_BYTE_ORDER==ARCH_BIG_ENDIAN + case 0x1: +#endif + mask1 = 0xffff; + mask2 = 0xffff0000; + shift = 16; + break; +#if GUEST_BYTE_ORDER==ARCH_LITTLE_ENDIAN + case 0x1: +#elif GUEST_BYTE_ORDER==ARCH_BIG_ENDIAN + case 0x2: +#endif + + mask1 = 0xffffff; + mask2 = 0xffffff00; + shift = 8; + break; +#if GUEST_BYTE_ORDER==ARCH_LITTLE_ENDIAN + case 0x0: +#elif GUEST_BYTE_ORDER==ARCH_BIG_ENDIAN + case 0x3: +#endif + mask1 = 0xffffffff; + mask2 = 0xffffffff; + shift = 0; + break; + } + + data = (data & mask2) >> shift; + data &= mask1; + cpu->gpr[reg] &= ~mask1; + cpu->gpr[reg] |= data; + cpu->reg_set (cpu, reg, sign_extend (cpu->gpr[reg], 32)); + } + return 0; +} + +/* LDL: Load Double-Word Left */ +u_int fastcall mips_mts32_ldl (cpu_mips_t * cpu, m_va_t vaddr, u_int reg) +{ + m_reg_t r_mask, naddr; + m_reg_t data; + u_int m_shift; + void *haddr; + u_int exc; + m_uint8_t has_set_value = FALSE; + + naddr = vaddr & ~(0x07); + haddr = + mips_mts32_access (cpu, naddr, MIPS_MEMOP_LDL, 8, MTS_READ, &data, + &exc, &has_set_value, 0); + if (exc) + return exc; + if ((haddr == NULL) && (has_set_value == FALSE)) { + bad_memory_access (cpu, vaddr); + } + + if (likely (haddr != NULL)) + data = (m_reg_t) (vmtoh64 (*(m_uint64_t *) haddr)); + + if (likely (!exc)) { + m_shift = (vaddr & 0x07) << 3; + r_mask = (1ULL << m_shift) - 1; + data <<= m_shift; + + cpu->gpr[reg] &= r_mask; + cpu->gpr[reg] |= data; + } + return (exc); +} + +/* LDR: Load Double-Word Right */ +u_int fastcall mips_mts32_ldr (cpu_mips_t * cpu, m_va_t vaddr, u_int reg) +{ + m_reg_t r_mask, naddr; + m_reg_t data; + u_int m_shift; + void *haddr; + u_int exc; + m_uint8_t has_set_value = FALSE; + + naddr = vaddr & ~(0x07); + haddr = + mips_mts32_access (cpu, naddr, MIPS_MEMOP_LDR, 8, MTS_READ, &data, + &exc, &has_set_value, 0); + if (exc) + return exc; + if ((haddr == NULL) && (has_set_value == FALSE)) { + bad_memory_access (cpu, vaddr); + } + + if (likely (haddr != NULL)) + data = (m_reg_t) (vmtoh64 (*(m_uint64_t *) haddr)); + + if (likely (!exc)) { + m_shift = ((vaddr & 0x07) + 1) << 3; + r_mask = (1ULL << m_shift) - 1; + data >>= (64 - m_shift); + + cpu->gpr[reg] &= ~r_mask; + cpu->gpr[reg] |= data; + } + return (exc); +} + +u_int fastcall mips_mts32_swl (cpu_mips_t * cpu, m_va_t vaddr, u_int reg) +{ + void *haddr = NULL; + u_int exc; + m_uint32_t data, naddr, temp, mask1 = 0, mask2 = 0, shift = 0; + m_uint8_t has_set_value = FALSE; + + naddr = vaddr & ~(0x03ULL); + data = cpu->gpr[reg] & 0xffffffff; + haddr = + mips_mts32_access (cpu, naddr, MIPS_MEMOP_SWL, 4, MTS_WRITE, &data, + &exc, &has_set_value, 0); + if (exc) + return exc; + if ((haddr == NULL) && (has_set_value == FALSE)) { + bad_memory_access (cpu, vaddr); + } + + if (has_set_value == FALSE) { + switch (vaddr & 0x3) { +#if GUEST_BYTE_ORDER==ARCH_LITTLE_ENDIAN + case 0x0: +#elif GUEST_BYTE_ORDER==ARCH_BIG_ENDIAN + case 0x3: +#endif + mask1 = 0xff; + mask2 = 0xff000000; + shift = 24; + break; +#if GUEST_BYTE_ORDER==ARCH_LITTLE_ENDIAN + case 0x1: +#elif GUEST_BYTE_ORDER==ARCH_BIG_ENDIAN + case 0x2: +#endif + mask1 = 0xffff; + mask2 = 0xffff0000; + shift = 16; + break; +#if GUEST_BYTE_ORDER==ARCH_LITTLE_ENDIAN + case 0x2: +#elif GUEST_BYTE_ORDER==ARCH_BIG_ENDIAN + case 0x1: +#endif + mask1 = 0xffffff; + mask2 = 0xffffff00; + shift = 8; + break; +#if GUEST_BYTE_ORDER==ARCH_LITTLE_ENDIAN + case 0x3: +#elif GUEST_BYTE_ORDER==ARCH_BIG_ENDIAN + case 0x0: +#endif + mask1 = 0xffffffff; + mask2 = 0xffffffff; + shift = 0; + break; + } + + data = (data & mask2) >> shift; + data &= mask1; + temp = vmtoh32 (*(m_uint32_t *) haddr); + + temp &= ~mask1; + temp = temp | data; + *(m_uint32_t *) haddr = htovm32 (temp); + + } + + return 0; +} + +u_int fastcall mips_mts32_swr (cpu_mips_t * cpu, m_va_t vaddr, u_int reg) +{ + void *haddr = NULL; + u_int exc; + m_uint32_t data, naddr, temp, mask1 = 0, mask2 = 0, shift = 0; + m_uint8_t has_set_value = FALSE; + + naddr = vaddr & ~(0x03ULL); + data = cpu->gpr[reg] & 0xffffffff; + haddr = + mips_mts32_access (cpu, naddr, MIPS_MEMOP_SWR, 4, MTS_WRITE, &data, + &exc, &has_set_value, 0); + if (exc) + return exc; + if ((haddr == NULL) && (has_set_value == FALSE)) { + bad_memory_access (cpu, vaddr); + } + if (has_set_value == FALSE) { + switch (vaddr & 0x3) { +#if GUEST_BYTE_ORDER==ARCH_LITTLE_ENDIAN + case 0x3: +#elif GUEST_BYTE_ORDER==ARCH_BIG_ENDIAN + case 0x0: +#endif + mask1 = 0xff; + mask2 = 0xff000000; + shift = 24; + break; +#if GUEST_BYTE_ORDER==ARCH_LITTLE_ENDIAN + case 0x2: +#elif GUEST_BYTE_ORDER==ARCH_BIG_ENDIAN + case 0x1: +#endif + mask1 = 0xffff; + mask2 = 0xffff0000; + shift = 16; + break; +#if GUEST_BYTE_ORDER==ARCH_LITTLE_ENDIAN + case 0x1: +#elif GUEST_BYTE_ORDER==ARCH_BIG_ENDIAN + case 0x2: +#endif + mask1 = 0xffffff; + mask2 = 0xffffff00; + shift = 8; + break; +#if GUEST_BYTE_ORDER==ARCH_LITTLE_ENDIAN + case 0x0: +#elif GUEST_BYTE_ORDER==ARCH_BIG_ENDIAN + case 0x3: +#endif + mask1 = 0xffffffff; + mask2 = 0xffffffff; + shift = 0; + break; + } + + data = (data & mask1) << shift; + data &= mask2; + temp = vmtoh32 (*(m_uint32_t *) haddr); + + temp &= ~mask2; + temp = temp | data; + *(m_uint32_t *) haddr = htovm32 (temp); + } + + return 0; +} + +/* SDL: Store Double-Word Left */ +u_int fastcall mips_mts32_sdl (cpu_mips_t * cpu, m_va_t vaddr, u_int reg) +{ + m_reg_t d_mask, naddr; + m_reg_t data; + u_int r_shift; + void *haddr; + u_int exc; + m_uint8_t has_set_value = FALSE; + + naddr = vaddr & ~(0x07); + haddr = + mips_mts32_access (cpu, naddr, MIPS_MEMOP_SDL, 8, MTS_READ, &data, + &exc, &has_set_value, 0); + if (exc) + return exc; + if ((haddr == NULL) && (has_set_value == FALSE)) { + bad_memory_access (cpu, vaddr); + } + if (unlikely (exc)) + return (exc); + + if (likely (haddr != NULL)) + data = (m_reg_t) (vmtoh64 (*(m_uint64_t *) haddr)); + + r_shift = (vaddr & 0x07) << 3; + d_mask = 0xffffffffffffffffULL >> r_shift; + + data &= ~d_mask; + data |= cpu->gpr[reg] >> r_shift; + + haddr = + mips_mts32_access (cpu, naddr, MIPS_MEMOP_SDL, 8, MTS_WRITE, &data, + &exc, &has_set_value, 0); + if ((haddr == NULL) && (has_set_value == FALSE)) { + bad_memory_access (cpu, vaddr); + } + if (likely (haddr != NULL)) + *(m_reg_t *) (m_uint64_t *) haddr = (m_reg_t) (htovm64 (data)); + return (exc); +} + +/* SDR: Store Double-Word Right */ +u_int fastcall mips_mts32_sdr (cpu_mips_t * cpu, m_va_t vaddr, u_int reg) +{ + m_reg_t d_mask, naddr; + m_reg_t data; + u_int r_shift; + void *haddr; + u_int exc; + + m_uint8_t has_set_value = FALSE; + + naddr = vaddr & ~(0x07); + haddr = + mips_mts32_access (cpu, naddr, MIPS_MEMOP_SDR, 8, MTS_READ, &data, + &exc, &has_set_value, 0); + if (exc) + return exc; + if ((haddr == NULL) && (has_set_value == FALSE)) { + bad_memory_access (cpu, vaddr); + } + if (unlikely (exc)) + return (exc); + + if (likely (haddr != NULL)) + data = vmtoh64 (*(m_uint64_t *) haddr); + + r_shift = ((vaddr & 0x07) + 1) << 3; + d_mask = 0xffffffffffffffffULL >> r_shift; + + data &= d_mask; + data |= cpu->gpr[reg] << (64 - r_shift); + + haddr = + mips_mts32_access (cpu, naddr, MIPS_MEMOP_SDR, 8, MTS_WRITE, &data, + &exc, &has_set_value, 0); + if ((haddr == NULL) && (has_set_value == FALSE)) { + bad_memory_access (cpu, vaddr); + } + if (likely (haddr != NULL)) + *(m_reg_t *) (m_uint64_t *) haddr = (m_reg_t) (htovm64 (data)); + return (exc); +} + +/* LL: Load Linked */ +u_int fastcall mips_mts32_ll (cpu_mips_t * cpu, m_va_t vaddr, u_int reg) +{ + m_reg_t data; + void *haddr; + u_int exc; + m_uint8_t has_set_value = FALSE; + + haddr = + mips_mts32_access (cpu, vaddr, MIPS_MEMOP_LL, 4, MTS_READ, &data, + &exc, &has_set_value, 0); + if (exc) + return exc; + if ((haddr == NULL) && (has_set_value == FALSE)) { + bad_memory_access (cpu, vaddr); + } + if (likely (haddr != NULL)) + data = vmtoh32 (*(m_uint32_t *) haddr); + + if (likely (!exc)) { + cpu->reg_set (cpu, reg, sign_extend (data, 32)); + cpu->ll_bit = 1; + } + return (exc); +} + +/* SC: Store Conditional */ +u_int fastcall mips_mts32_sc (cpu_mips_t * cpu, m_va_t vaddr, u_int reg) +{ + m_reg_t data; + void *haddr; + u_int exc = 0; + m_uint8_t has_set_value = FALSE; + + if (cpu->ll_bit) { + data = cpu->gpr[reg] & 0xffffffff; + haddr = + mips_mts32_access (cpu, vaddr, MIPS_MEMOP_SC, 4, MTS_WRITE, &data, + &exc, &has_set_value, 0); + if (exc) + return exc; + if ((haddr == NULL) && (has_set_value == FALSE)) { + bad_memory_access (cpu, vaddr); + } + if (likely (haddr != NULL)) + *(m_uint32_t *) haddr = htovm32 (data); + } + + if (likely (!exc)) + cpu->reg_set (cpu, reg, cpu->ll_bit); + return (exc); +} + +/* SDC1: Store Double-Word from Coprocessor 1 */ +u_int fastcall mips_mts32_sdc1 (cpu_mips_t * cpu, m_va_t vaddr, u_int reg) +{ + /* m_uint64_t data; + * void *haddr; + * u_int exc; + * m_uint8_t has_set_value=FALSE; + * + * + * data = cpu->fpu.reg[reg]; + * haddr = mips_mts32_access(cpu,vaddr,MIPS_MEMOP_SDC1,8,MTS_WRITE, + * &data,&exc,&has_set_value); + * if ((haddr==NULL)&&(has_set_value==FALSE)) + * { + * bad_memory_access(cpu,vaddr); + * } + * if (likely(haddr != NULL)) *(m_uint64_t *)haddr = htovm64(data); + * return(exc); */ + printf ("mips_mts32_sdc1 pc %x\n", cpu->pc); + exit (-1); + return 0; +} + +/* CACHE: Cache operation */ +u_int fastcall mips_mts32_cache (cpu_mips_t * cpu, m_va_t vaddr, u_int op) +{ + return (0); +} + +/* === MTS Cache Management ============================================= */ + +/* MTS map/unmap/rebuild "API" functions */ +void mips_mts32_api_map (cpu_mips_t * cpu, m_va_t vaddr, m_pa_t paddr, + m_uint32_t len, int cache_access, int tlb_index) +{ + /* nothing to do, the cache will be filled on-the-fly */ +} + +void mips_mts32_api_unmap (cpu_mips_t * cpu, m_va_t vaddr, m_uint32_t len, + m_uint32_t val, int tlb_index) +{ + /* Invalidate the TLB entry or the full cache if no index is specified */ + if (tlb_index != -1) + mips_mts32_invalidate_tlb_entry (cpu, vaddr); + else + mips_mts32_invalidate_cache (cpu); +} + +void mips_mts32_api_rebuild (cpu_mips_t * cpu) +{ + mips_mts32_invalidate_cache ((cpu)); +} + +/* ======================================================================== */ + +/* Initialize memory access vectors */ +void mips_mts32_init_memop_vectors (cpu_mips_t * cpu) +{ + /* XXX TODO: + * - LD/SD forbidden in Supervisor/User modes with 32-bit addresses. + */ + + cpu->addr_mode = 32; + + /* API vectors */ + cpu->mts_map = mips_mts32_api_map; + cpu->mts_unmap = mips_mts32_api_unmap; + + /* Memory lookup operation */ + cpu->mem_op_lookup = mips_mts32_lookup; + + /* Translation operation */ + cpu->translate = mips_mts32_translate; + + /* Shutdown operation */ + cpu->mts_shutdown = mips_mts32_shutdown; + + /* Rebuild MTS data structures */ + cpu->mts_rebuild = mips_mts32_api_rebuild; + + /* Show statistics */ + //cpu->mts_show_stats = mips_mts32_show_stats; + + cpu->mips_mts_gdb_lb = mips_mts32_gdb_lb; + + /* Load Operations */ + cpu->mem_op_fn[MIPS_MEMOP_LB] = mips_mts32_lb; + cpu->mem_op_fn[MIPS_MEMOP_LBU] = mips_mts32_lbu; + cpu->mem_op_fn[MIPS_MEMOP_LH] = mips_mts32_lh; + cpu->mem_op_fn[MIPS_MEMOP_LHU] = mips_mts32_lhu; + cpu->mem_op_fn[MIPS_MEMOP_LW] = mips_mts32_lw; + cpu->mem_op_fn[MIPS_MEMOP_LWU] = mips_mts32_lwu; + cpu->mem_op_fn[MIPS_MEMOP_LD] = mips_mts32_ld; + cpu->mem_op_fn[MIPS_MEMOP_LDL] = mips_mts32_ldl; + cpu->mem_op_fn[MIPS_MEMOP_LDR] = mips_mts32_ldr; + + /* Store Operations */ + cpu->mem_op_fn[MIPS_MEMOP_SB] = mips_mts32_sb; + cpu->mem_op_fn[MIPS_MEMOP_SH] = mips_mts32_sh; + cpu->mem_op_fn[MIPS_MEMOP_SW] = mips_mts32_sw; + cpu->mem_op_fn[MIPS_MEMOP_SD] = mips_mts32_sd; + + /* Load Left/Right operations */ + cpu->mem_op_fn[MIPS_MEMOP_LWL] = mips_mts32_lwl; + cpu->mem_op_fn[MIPS_MEMOP_LWR] = mips_mts32_lwr; + cpu->mem_op_fn[MIPS_MEMOP_LDL] = mips_mts32_ldl; + cpu->mem_op_fn[MIPS_MEMOP_LDR] = mips_mts32_ldr; + + /* Store Left/Right operations */ + cpu->mem_op_fn[MIPS_MEMOP_SWL] = mips_mts32_swl; + cpu->mem_op_fn[MIPS_MEMOP_SWR] = mips_mts32_swr; + cpu->mem_op_fn[MIPS_MEMOP_SDL] = mips_mts32_sdl; + cpu->mem_op_fn[MIPS_MEMOP_SDR] = mips_mts32_sdr; + + /* LL/SC - Load Linked / Store Conditional */ + cpu->mem_op_fn[MIPS_MEMOP_LL] = mips_mts32_ll; + cpu->mem_op_fn[MIPS_MEMOP_SC] = mips_mts32_sc; + + /* Coprocessor 1 memory access functions */ + cpu->mem_op_fn[MIPS_MEMOP_LDC1] = mips_mts32_ldc1; + cpu->mem_op_fn[MIPS_MEMOP_SDC1] = mips_mts32_sdc1; + + /* Cache Operation */ + cpu->mem_op_fn[MIPS_MEMOP_CACHE] = mips_mts32_cache; +} + +/* === Specific operations for MTS32 ====================================== */ + +/* + * MTS32 slow lookup + */ +static mts32_entry_t *mips_mts32_slow_lookup (cpu_mips_t * cpu, + m_uint64_t vaddr, u_int op_code, u_int op_size, u_int op_type, + m_reg_t * data, u_int * exc, mts32_entry_t * alt_entry, u_int is_fromgdb) +{ + m_uint32_t hash_bucket, zone; + mts32_entry_t *entry; + mts_map_t map; + + map.tlb_index = -1; + hash_bucket = MTS32_HASH (vaddr); + entry = &cpu->mts_u.mts32_cache[hash_bucket]; + zone = (vaddr >> 29) & 0x7; + +#if DEBUG_MTS_STATS + cpu->mts_misses++; +#endif + + switch (zone) { + case 0x00: + case 0x01: + case 0x02: + case 0x03: /* kuseg */ +#ifdef SIM_PIC32 + if (vaddr == 0) + goto err_undef; + map.vaddr = vaddr & MIPS_MIN_PAGE_MASK; + map.paddr = map.vaddr & 0x1ffff; + map.mapped = FALSE; +#else + /* trigger TLB exception if no matching entry found */ + if (! mips_cp0_tlb_lookup (cpu, vaddr, &map)) + goto err_tlb; + + if ((map.valid & 0x1) != 0x1) + goto err_tlb; + if ((MTS_WRITE == op_type) && ((map.dirty & 0x1) != 0x1)) + goto err_mod; + + map.mapped = TRUE; +#endif + entry = mips_mts32_map (cpu, op_type, &map, entry, alt_entry, + is_fromgdb); + if (! entry) + goto err_undef; + return (entry); + + case 0x04: /* kseg0 */ + map.vaddr = vaddr & MIPS_MIN_PAGE_MASK; + map.paddr = map.vaddr - (m_pa_t) 0xFFFFFFFF80000000ULL; + map.mapped = FALSE; + + entry = mips_mts32_map (cpu, op_type, &map, entry, alt_entry, + is_fromgdb); + if (! entry) + goto err_undef; + return (entry); + + case 0x05: /* kseg1 */ + map.vaddr = vaddr & MIPS_MIN_PAGE_MASK; + map.paddr = map.vaddr - (m_pa_t) 0xFFFFFFFFA0000000ULL; + map.mapped = FALSE; + + entry = mips_mts32_map (cpu, op_type, &map, entry, alt_entry, + is_fromgdb); + if (! entry) + goto err_undef; + return (entry); + + case 0x06: /* ksseg */ + case 0x07: /* kseg3 */ +#ifdef SIM_PIC32 + map.vaddr = vaddr & MIPS_MIN_PAGE_MASK; + map.paddr = map.vaddr & 0x1ffff; + map.mapped = FALSE; +#else + //ASSERT(0,"not implemented upper 1G memory space \n"); + /* trigger TLB exception if no matching entry found */ + if (! mips_cp0_tlb_lookup (cpu, vaddr, &map)) + goto err_tlb; + if ((map.valid & 0x1) != 0x1) + goto err_tlb; + if ((MTS_WRITE == op_type) && ((map.dirty & 0x1) != 0x1)) + goto err_mod; + map.mapped = TRUE; +#endif + entry = mips_mts32_map (cpu, op_type, &map, entry, alt_entry, + is_fromgdb); + if (! entry) + goto err_undef; + return (entry); + } +#ifndef SIM_PIC32 +err_mod: + if (is_fromgdb) + return NULL; + mips_access_special (cpu, vaddr, MTS_ACC_M, op_code, op_type, op_size, + data, exc); + return NULL; +err_tlb: + if (is_fromgdb) + return NULL; + mips_access_special (cpu, vaddr, MTS_ACC_T, op_code, op_type, op_size, + data, exc); + return NULL; +#endif +err_undef: + if (is_fromgdb) + return NULL; + mips_access_special (cpu, vaddr, MTS_ACC_U, op_code, op_type, op_size, + data, exc); + return NULL; +} + +static forced_inline int mips_mts32_check_tlbcache (cpu_mips_t * cpu, + m_va_t vaddr, u_int op_type, mts32_entry_t * entry) +{ + m_uint32_t asid; + mips_cp0_t *cp0 = &cpu->cp0; + asid = cp0->reg[MIPS_CP0_TLB_HI] & MIPS_TLB_ASID_MASK; + if (((m_uint32_t) vaddr & MIPS_MIN_PAGE_MASK) != entry->gvpa) + return 0; + if (entry->mapped == TRUE) { + if ((op_type == MTS_WRITE) && (!entry->dirty_bit)) + return 0; + if ((!entry->g_bit) && (asid != entry->asid)) + return 0; + } + return 1; +} + +/* MTS32 access */ +void *mips_mts32_access (cpu_mips_t * cpu, m_va_t vaddr, + u_int op_code, u_int op_size, u_int op_type, m_reg_t * data, + u_int * exc, m_uint8_t * has_set_value, u_int is_fromgdb) +{ + mts32_entry_t *entry, alt_entry; + m_uint32_t hash_bucket; + m_iptr_t haddr; + u_int dev_id; + +/* +A job need to be done first: check whether access is aligned!!! +MIPS FPU Emulator use a unaligned lw access to cause exception and then handle it. + 72 + 73 * The strategy is to push the instruction onto the user stack + 74 * and put a trap after it which we can catch and jump to + 75 * the required address any alternative apart from full + 76 * instruction simulation!!. + 77 * + 78 * Algorithmics used a system call instruction, and + 79 * borrowed that vector. MIPS/Linux version is a bit + 80 * more heavyweight in the interests of portability and + 81 * multiprocessor support. For Linux we generate a + 82 * an unaligned access and force an address error exception. + 83 * + 84 * For embedded systems (stand-alone) we prefer to use a + 85 * non-existing CP1 instruction. This prevents us from emulating + 86 * branches, but gives us a cleaner interface to the exception + 87 * handler (single entry point). + 88 + +I did not check it before version 0.04 and hwclock/qtopia always segment fault. +Very hard to debug this problem!!!! +yajin +*/ +//if (vaddr == 0x7f010020) +//printf ("%08x: %s address %08x\n", cpu->pc, +//(op_type == MTS_WRITE) ? "write" : "read", (unsigned) vaddr); + + if (MTS_HALF_WORD == op_size) { + if (unlikely ((vaddr & 0x00000001UL) != 0x0)) { +err_addr: if (is_fromgdb) + return NULL; + mips_access_special (cpu, vaddr, MTS_ACC_AE, op_code, op_type, + op_size, data, exc); + return NULL; + } + } else if (MTS_WORD == op_size) { + if ((op_code != MIPS_MEMOP_LWL) && (op_code != MIPS_MEMOP_LWR) + && (op_code != MIPS_MEMOP_SWL) && (op_code != MIPS_MEMOP_SWR)) { + if (unlikely ((vaddr & 0x00000003UL) != 0x0)) + goto err_addr; + } + } + + *exc = 0; + hash_bucket = MTS32_HASH (vaddr); + entry = &cpu->mts_u.mts32_cache [hash_bucket]; + + if (unlikely (mips_mts32_check_tlbcache (cpu, vaddr, op_type, + entry) == 0)) { + entry = mips_mts32_slow_lookup (cpu, vaddr, op_code, op_size, op_type, + data, exc, &alt_entry, is_fromgdb); + if (! entry) + return NULL; + if (entry->flags & MTS_FLAG_DEV) { + dev_id = (entry->hpa & MTS_DEVID_MASK) >> MTS_DEVID_SHIFT; + haddr = entry->hpa & MTS_DEVOFF_MASK; + haddr += vaddr - entry->gvpa; + + void *addr = dev_access_fast (cpu, dev_id, haddr, op_size, op_type, + data, has_set_value); +/*printf ("%08x: mts32_access fast returned %p\n", cpu->pc, addr);*/ + return addr; + } + } + + /* Raw memory access */ + haddr = entry->hpa + (vaddr & MIPS_MIN_PAGE_IMASK); + return ((void *) haddr); +} + +/* MTS32 virtual address to physical address translation */ +static int mips_mts32_translate (cpu_mips_t * cpu, m_va_t vaddr, + m_pa_t * phys_page) +{ + mts32_entry_t *entry, alt_entry; + m_uint32_t hash_bucket; + m_reg_t data = 0; + u_int exc = 0; + + hash_bucket = MTS32_HASH (vaddr); + entry = &cpu->mts_u.mts32_cache[hash_bucket]; + + if (unlikely (mips_mts32_check_tlbcache (cpu, vaddr, MTS_READ, + entry) == 0)) { + entry = + mips_mts32_slow_lookup (cpu, vaddr, MIPS_MEMOP_LOOKUP, 4, + MTS_READ, &data, &exc, &alt_entry, 0); + if (! entry) + return (-1); + + ASSERT (! (entry->flags & MTS_FLAG_DEV), + "error when translating virtual address to phyaddrss \n"); + } + *phys_page = entry->gppa >> MIPS_MIN_PAGE_SHIFT; + return (0); + +} + +/* ======================================================================== */ + +/* Shutdown MTS subsystem */ +void mips_mem_shutdown (cpu_mips_t * cpu) +{ + if (cpu->mts_shutdown != NULL) + cpu->mts_shutdown (cpu); +} + +/* Set the address mode */ +int mips_set_addr_mode (cpu_mips_t * cpu, u_int addr_mode) +{ + if (cpu->addr_mode != addr_mode) { + mips_mem_shutdown (cpu); + + switch (addr_mode) { + case 32: + mips_mts32_init (cpu); + mips_mts32_init_memop_vectors (cpu); + break; + /*case 64: + * TODO: 64 bit memory operation + * mips_mts64_init(cpu); + * mips_mts64_init_memop_vectors(cpu); + * break; */ + default: + fprintf (stderr, + "mts_set_addr_mode: internal error (addr_mode=%u)\n", + addr_mode); + exit (EXIT_FAILURE); + } + } + + return (0); +} + +/*------------------DMA------------------------*/ + +/* Get host pointer for the physical ram address */ +void *physmem_get_hptr (vm_instance_t * vm, m_pa_t paddr, u_int op_size, + u_int op_type, m_uint32_t * data) +{ + + struct vdevice *dev; + m_uint32_t offset; + + m_uint8_t has_set_value; + + if (!(dev = dev_lookup (vm, paddr))) + return NULL; + + /*Only for RAM */ + if ((dev->host_addr != 0) && !(dev->flags & VDEVICE_FLAG_NO_MTS_MMAP)) + return ((void *) dev->host_addr + (paddr - dev->phys_addr)); + + if (op_size == 0) + return NULL; + + ASSERT (0, "physmem_get_hptr error\n"); + offset = paddr - dev->phys_addr; + return (dev->handler (vm->boot_cpu, dev, offset, op_size, op_type, data, + &has_set_value)); +} + +/* DMA transfer operation */ +void physmem_dma_transfer (vm_instance_t * vm, m_pa_t src, m_pa_t dst, + size_t len) +{ + m_uint32_t dummy; + u_char *sptr, *dptr; + size_t clen, sl, dl; + + while (len > 0) { + sptr = physmem_get_hptr (vm, src, 0, MTS_READ, &dummy); + dptr = physmem_get_hptr (vm, dst, 0, MTS_WRITE, &dummy); + + if (!sptr || !dptr) { + vm_log (vm, "DMA", + "unable to transfer from 0x%" LL "x to 0x%" LL "x\n", src, + dst); + ASSERT (0, "physmem_dma_transfer src %x dst %x\n", src, dst); + return; + } + + sl = VM_PAGE_SIZE - (src & VM_PAGE_IMASK); + dl = VM_PAGE_SIZE - (dst & VM_PAGE_IMASK); + clen = m_min (sl, dl); + clen = m_min (clen, len); + + memcpy (dptr, sptr, clen); + + src += clen; + dst += clen; + len -= clen; + } +} diff --git a/tools/virtualmips/mips_memory.h b/tools/virtualmips/mips_memory.h new file mode 100644 index 0000000..8e30ad3 --- /dev/null +++ b/tools/virtualmips/mips_memory.h @@ -0,0 +1,111 @@ +/* + * Cisco router simulation platform. + * Copyright (c) 2006 Christophe Fillot (cf@utc.fr) + */ + + /* + * Copyright (C) yajin 2008 + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + * + */ + +#ifndef __MIPS64_MEM_H__ +#define __MIPS64_MEM_H__ + +#include +#include "utils.h" +#include "system.h" +/* MTS operation */ +#define MTS_READ 0 +#define MTS_WRITE 1 + +#define MTS_BYTE 1 +#define MTS_HALF_WORD 2 +#define MTS_WORD 4 + +/* 0.5GB value */ +#define MTS_SIZE_512M 0x20000000 + +/* MTS flag bits: D (device), ACC (memory access), C (chain) */ +#define MTS_FLAG_BITS 4 +#define MTS_FLAG_MASK 0x0000000fUL + +/* Masks for MTS entries */ +#define MTS_CHAIN_MASK 0x00000001 +#define MTS_ACC_MASK 0x00000006 +#define MTS_DEV_MASK 0x00000008 +#define MTS_ADDR_MASK (~MTS_FLAG_MASK) + +/* Device ID mask and shift, device offset mask */ +#define MTS_DEVID_MASK 0xfc000000 +#define MTS_DEVID_SHIFT 26 +#define MTS_DEVOFF_MASK 0x03fffff0 + +/* Memory access flags */ +#define MTS_ACC_OK 0x00000000 /* Access OK */ +#define MTS_ACC_AE 0x00000002 /* Address Error */ +#define MTS_ACC_T 0x00000004 /* TLB Exception */ +#define MTS_ACC_U 0x00000006 /* Unexistent */ +#define MTS_ACC_M 0x00000008 /* TLB MODE */ + +/* Hash table size for MTS64 (default: [shift:16,bits:12]) */ +#define MTS64_HASH_SHIFT 12 +#define MTS64_HASH_BITS 14 +#define MTS64_HASH_SIZE (1 << MTS64_HASH_BITS) +#define MTS64_HASH_MASK (MTS64_HASH_SIZE - 1) + +/* MTS64 hash on virtual addresses */ +#define MTS64_HASH(vaddr) (((vaddr) >> MTS64_HASH_SHIFT) & MTS64_HASH_MASK) + +/* Hash table size for MTS32 (default: [shift:15,bits:15]) */ +#define MTS32_HASH_SHIFT 12 +#define MTS32_HASH_BITS 14 +#define MTS32_HASH_SIZE (1 << MTS32_HASH_BITS) +#define MTS32_HASH_MASK (MTS32_HASH_SIZE - 1) + +/* MTS32 hash on virtual addresses */ +#define MTS32_HASH(vaddr) (((vaddr) >> MTS32_HASH_SHIFT) & MTS32_HASH_MASK) + +/* Number of entries per chunk */ +#define MTS64_CHUNK_SIZE 256 +#define MTS32_CHUNK_SIZE 256 + +/* MTS64: chunk definition */ +struct mts64_chunk { + mts64_entry_t entry[MTS64_CHUNK_SIZE]; + struct mts64_chunk *next; + u_int count; +}; + +/* MTS32: chunk definition */ +struct mts32_chunk { + mts32_entry_t entry[MTS32_CHUNK_SIZE]; + struct mts32_chunk *next; + u_int count; +}; + +/*check whether vaddr need map*/ +static int forced_inline vaddr_mapped (m_va_t vaddr) +{ + int zone = (vaddr >> 29) & 0x7; + if ((zone == 0x4) || (zone == 0x5)) { + return 0; + } else { + return 1; + } +} + +/* Shutdown the MTS subsystem */ +void mips_mem_shutdown (cpu_mips_t * cpu); + +/* Set the address mode */ +int mips_set_addr_mode (cpu_mips_t * cpu, u_int addr_mode); + +void physmem_dma_transfer (vm_instance_t * vm, m_pa_t src, m_pa_t dst, + size_t len); +void *physmem_get_hptr (vm_instance_t * vm, m_pa_t paddr, u_int op_size, + u_int op_type, m_uint32_t * data); + +#endif diff --git a/tools/virtualmips/net.h b/tools/virtualmips/net.h new file mode 100644 index 0000000..62b1784 --- /dev/null +++ b/tools/virtualmips/net.h @@ -0,0 +1,38 @@ +#ifndef __NET_H__ +#define __NET_H__ + +#include "utils.h" + +/* Ethernet Constants */ +#define N_ETH_ALEN 6 +#define N_ETH_HLEN sizeof(n_eth_hdr_t) + +/* Ethernet Address */ +typedef struct { + m_uint8_t eth_addr_byte[N_ETH_ALEN]; +} __attribute__ ((__packed__)) n_eth_addr_t; +/* Ethernet Header */ +typedef struct { + n_eth_addr_t daddr; /* destination eth addr */ + n_eth_addr_t saddr; /* source ether addr */ + m_uint16_t type; /* packet type ID field */ +} __attribute__ ((__packed__)) n_eth_hdr_t; + +/* Check for a broadcast/multicast ethernet address */ +static inline int eth_addr_is_bcast (n_eth_addr_t * addr) +{ + return ((addr->eth_addr_byte[0] == 0xff) + && (addr->eth_addr_byte[1] == 0xff) + && (addr->eth_addr_byte[2] == 0xff) + && (addr->eth_addr_byte[3] == 0xff) + && (addr->eth_addr_byte[4] == 0xff) + && (addr->eth_addr_byte[5] == 0xff)); +} + +static inline int eth_addr_is_mcast (n_eth_addr_t * addr) +{ + return ((!eth_addr_is_bcast (addr)) && (addr->eth_addr_byte[0] & 1)); + +} + +#endif diff --git a/tools/virtualmips/net_io.c b/tools/virtualmips/net_io.c new file mode 100644 index 0000000..85ccebb --- /dev/null +++ b/tools/virtualmips/net_io.c @@ -0,0 +1,1529 @@ +/* + * Cisco router simulation platform. + * Copyright (c) 2005,2006 Christophe Fillot (cf@utc.fr) + * + * Network Input/Output Abstraction Layer. + */ + +/* By default, Cygwin supports only 64 FDs with select()! */ +#ifdef __CYGWIN__ +#define FD_SETSIZE 1024 +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __linux__ +#include +#include +#endif + +#include "net.h" +#include "net_io.h" + +/* Free a NetIO descriptor */ +static int netio_free (void *data, void *arg); +#if 0 +/* NIO RX listener */ +static pthread_mutex_t netio_rxl_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t netio_rxq_mutex = PTHREAD_MUTEX_INITIALIZER; +static struct netio_rx_listener *netio_rxl_list = NULL; +static struct netio_rx_listener *netio_rxl_add_list = NULL; +static netio_desc_t *netio_rxl_remove_list = NULL; +static pthread_t netio_rxl_thread; +static pthread_cond_t netio_rxl_cond; + +#define NETIO_RXL_LOCK() pthread_mutex_lock(&netio_rxl_mutex); +#define NETIO_RXL_UNLOCK() pthread_mutex_unlock(&netio_rxl_mutex); + +#define NETIO_RXQ_LOCK() pthread_mutex_lock(&netio_rxq_mutex); +#define NETIO_RXQ_UNLOCK() pthread_mutex_unlock(&netio_rxq_mutex); +#endif + +/* NetIO type */ +typedef struct { + char *name; + char *desc; +} netio_type_t; + +/* NETIO types (must follow the enum definition) */ +static netio_type_t netio_types[NETIO_TYPE_MAX] = { + {"unix", "UNIX local sockets"}, + {"vde", "Virtual Distributed Ethernet / UML switch"}, + {"tap", "Linux/FreeBSD TAP device"}, + {"udp", "UDP sockets"}, + {"tcp_cli", "TCP client"}, + {"tcp_ser", "TCP server"}, +#ifdef LINUX_ETH + {"linux_eth", "Linux Ethernet device"}, +#endif +#ifdef GEN_ETH + {"gen_eth", "Generic Ethernet device (PCAP)"}, +#endif + {"fifo", "FIFO (intra-hypervisor)"}, + {"null", "Null device"}, +}; + +/* Get NETIO type given a description */ +int netio_get_type (char *type) +{ + int i; + + for (i = 0; i < NETIO_TYPE_MAX; i++) + if (!strcmp (type, netio_types[i].name)) + return (i); + + return (-1); +} + +/* Show the NETIO types */ +void netio_show_types (void) +{ + int i; + + printf ("Available NETIO types:\n"); + + for (i = 0; i < NETIO_TYPE_MAX; i++) + printf (" * %-10s : %s\n", netio_types[i].name, netio_types[i].desc); + + printf ("\n"); +} + +/* Create a new NetIO descriptor */ +static netio_desc_t *netio_create (char *name) +{ + netio_desc_t *nio; + + if (!(nio = malloc (sizeof (*nio)))) + return NULL; + + /* setup as a NULL descriptor */ + memset (nio, 0, sizeof (*nio)); + nio->type = NETIO_TYPE_NULL; + + /* save name for registry */ + if (!(nio->name = strdup (name))) { + free (nio); + return NULL; + } + + return nio; +} + +/* Send a packet through a NetIO descriptor */ +ssize_t netio_send (netio_desc_t * nio, void *pkt, size_t len) +{ + + if (!nio) + return (-1); + + if (nio->debug) { + printf ("NIO %s: sending a packet of %lu bytes:\n", nio->name, + (u_long) len); + mem_dump (stdout, pkt, len); + } + + return (nio->send (nio->dptr, pkt, len)); +} + +/* Receive a packet through a NetIO descriptor */ +ssize_t netio_recv (netio_desc_t * nio, void *pkt, size_t max_len) +{ + ssize_t len; + + if (!nio) + return (-1); + + /* Receive the packet */ + if ((len = nio->recv (nio->dptr, pkt, max_len)) <= 0) + return (-1); + + if (nio->debug) { + printf ("NIO %s: receiving a packet of %ld bytes:\n", nio->name, + (long) len); + mem_dump (stdout, pkt, len); + } + + return (len); +} + +/* Get a NetIO FD */ +int netio_get_fd (netio_desc_t * nio) +{ + int fd = -1; + + switch (nio->type) { + //case NETIO_TYPE_UNIX: + // fd = nio->u.nud.fd; + // break; + //case NETIO_TYPE_VDE: + // fd = nio->u.nvd.data_fd; + // break; + case NETIO_TYPE_TAP: + fd = nio->u.ntd.fd; + break; + //case NETIO_TYPE_TCP_CLI: + //case NETIO_TYPE_TCP_SER: + //case NETIO_TYPE_UDP: + // fd = nio->u.nid.fd; + // break; +//#ifdef LINUX_ETH +// case NETIO_TYPE_LINUX_ETH: +// fd = nio->u.nled.fd; +// break; +//#endif + } + + return (fd); +} + +#if 0 +/* + * ========================================================================= + * UNIX sockets + * ========================================================================= + */ + +/* Create an UNIX socket */ +static int netio_unix_create_socket (netio_unix_desc_t * nud) +{ + struct sockaddr_un local_sock; + + if ((nud->fd = socket (AF_UNIX, SOCK_DGRAM, 0)) == -1) { + perror ("netio_unix: socket"); + return (-1); + } + + memset (&local_sock, 0, sizeof (local_sock)); + local_sock.sun_family = AF_UNIX; + strcpy (local_sock.sun_path, nud->local_filename); + + if (bind (nud->fd, (struct sockaddr *) &local_sock, + sizeof (local_sock)) == -1) { + perror ("netio_unix: bind"); + return (-1); + } + + return (nud->fd); +} + +/* Free a NetIO unix descriptor */ +static void netio_unix_free (netio_unix_desc_t * nud) +{ + if (nud->fd != -1) + close (nud->fd); + + if (nud->local_filename) { + unlink (nud->local_filename); + free (nud->local_filename); + } +} + +/* Allocate a new NetIO UNIX descriptor */ +static int netio_unix_create (netio_unix_desc_t * nud, char *local, + char *remote) +{ + memset (nud, 0, sizeof (*nud)); + nud->fd = -1; + + /* check lengths */ + if ((strlen (local) >= sizeof (nud->remote_sock.sun_path)) + || (strlen (remote) >= sizeof (nud->remote_sock.sun_path))) + goto nomem_error; + + if (!(nud->local_filename = strdup (local))) + goto nomem_error; + + if (netio_unix_create_socket (nud) == -1) + return (-1); + + /* prepare the remote info */ + nud->remote_sock.sun_family = AF_UNIX; + strcpy (nud->remote_sock.sun_path, remote); + return (0); + + nomem_error: + fprintf (stderr, + "netio_unix_create: " "invalid file size or insufficient memory\n"); + return (-1); +} + +/* Write a packet to an UNIX socket */ +static ssize_t netio_unix_send (netio_unix_desc_t * nud, void *pkt, + size_t pkt_len) +{ + return (sendto (nud->fd, pkt, pkt_len, 0, + (struct sockaddr *) &nud->remote_sock, + sizeof (&nud->remote_sock))); +} + +/* Receive a packet from an UNIX socket */ +static ssize_t netio_unix_recv (netio_unix_desc_t * nud, void *pkt, + size_t max_len) +{ + return (recvfrom (nud->fd, pkt, max_len, 0, NULL, NULL)); +} + +/* Save the NIO configuration */ +static void netio_unix_save_cfg (netio_desc_t * nio, FILE * fd) +{ + netio_unix_desc_t *nud = nio->dptr; + fprintf (fd, "nio create_unix %s %s %s\n", nio->name, nud->local_filename, + nud->remote_sock.sun_path); +} + +/* Create a new NetIO descriptor with UNIX method */ +netio_desc_t *netio_desc_create_unix (char *nio_name, char *local, + char *remote) +{ + netio_desc_t *nio; + + if (!(nio = netio_create (nio_name))) + return NULL; + + if (netio_unix_create (&nio->u.nud, local, remote) == -1) { + netio_free (nio, NULL); + return NULL; + } + + nio->type = NETIO_TYPE_UNIX; + nio->send = (void *) netio_unix_send; + nio->recv = (void *) netio_unix_recv; + nio->save_cfg = netio_unix_save_cfg; + nio->dptr = &nio->u.nud; + + if (netio_record (nio) == -1) { + netio_free (nio, NULL); + return NULL; + } + + return nio; +} + +/* + * ========================================================================= + * VDE (Virtual Distributed Ethernet) interface + * ========================================================================= + */ + +/* Free a NetIO VDE descriptor */ +static void netio_vde_free (netio_vde_desc_t * nvd) +{ + if (nvd->data_fd != -1) + close (nvd->data_fd); + + if (nvd->ctrl_fd != -1) + close (nvd->ctrl_fd); + + if (nvd->local_filename) { + unlink (nvd->local_filename); + free (nvd->local_filename); + } +} + +/* Create a new NetIO VDE descriptor */ +static int netio_vde_create (netio_vde_desc_t * nvd, char *control, + char *local) +{ + struct sockaddr_un ctrl_sock, tst; + struct vde_request_v3 req; + ssize_t len; + int res; + + memset (nvd, 0, sizeof (*nvd)); + nvd->ctrl_fd = nvd->data_fd = -1; + + if ((strlen (control) >= sizeof (ctrl_sock.sun_path)) + || (strlen (local) >= sizeof (nvd->remote_sock.sun_path))) { + fprintf (stderr, "netio_vde_create: bad filenames specified\n"); + return (-1); + } + + /* Copy the local filename */ + if (!(nvd->local_filename = strdup (local))) { + fprintf (stderr, "netio_vde_create: insufficient memory\n"); + return (-1); + } + + /* Connect to the VDE switch controller */ + nvd->ctrl_fd = socket (AF_UNIX, SOCK_STREAM, 0); + if (nvd->ctrl_fd < 0) { + perror ("netio_vde_create: socket(control)"); + return (-1); + } + + memset (&ctrl_sock, 0, sizeof (ctrl_sock)); + ctrl_sock.sun_family = AF_UNIX; + strcpy (ctrl_sock.sun_path, control); + + res = + connect (nvd->ctrl_fd, (struct sockaddr *) &ctrl_sock, + sizeof (ctrl_sock)); + + if (res < 0) { + perror ("netio_vde_create: connect(control)"); + return (-1); + } + + tst.sun_family = AF_UNIX; + strcpy (tst.sun_path, local); + + /* Create the data connection */ + nvd->data_fd = socket (AF_UNIX, SOCK_DGRAM, 0); + if (nvd->data_fd < 0) { + perror ("netio_vde_create: socket(data)"); + return (-1); + } + + if (bind (nvd->data_fd, (struct sockaddr *) &tst, sizeof (tst)) < 0) { + perror ("netio_vde_create: bind(data)"); + return (-1); + } + + /* Now, process to registration */ + memset (&req, 0, sizeof (req)); + req.sock.sun_family = AF_UNIX; + strcpy (req.sock.sun_path, local); + req.magic = VDE_SWITCH_MAGIC; + req.version = VDE_SWITCH_VERSION; + req.type = VDE_REQ_NEW_CONTROL; + + len = write (nvd->ctrl_fd, &req, sizeof (req)); + if (len != sizeof (req)) { + perror ("netio_vde_create: write(req)"); + return (-1); + } + + /* Read the remote socket descriptor */ + len = read (nvd->ctrl_fd, &nvd->remote_sock, sizeof (nvd->remote_sock)); + if (len != sizeof (nvd->remote_sock)) { + perror ("netio_vde_create: read(req)"); + return (-1); + } + + return (0); +} + +/* Write a packet to a VDE data socket */ +static ssize_t netio_vde_send (netio_vde_desc_t * nvd, void *pkt, + size_t pkt_len) +{ + return (sendto (nvd->data_fd, pkt, pkt_len, 0, + (struct sockaddr *) &nvd->remote_sock, + sizeof (nvd->remote_sock))); +} + +/* Receive a packet from a VDE socket */ +static ssize_t netio_vde_recv (netio_vde_desc_t * nvd, void *pkt, + size_t max_len) +{ + return (recvfrom (nvd->data_fd, pkt, max_len, 0, NULL, NULL)); +} + +/* Save the NIO configuration */ +static void netio_vde_save_cfg (netio_desc_t * nio, FILE * fd) +{ + netio_vde_desc_t *nvd = nio->dptr; + fprintf (fd, "nio create_vde %s %s %s\n", nio->name, + nvd->remote_sock.sun_path, nvd->local_filename); +} + +/* Create a new NetIO descriptor with VDE method */ +netio_desc_t *netio_desc_create_vde (char *nio_name, char *control, + char *local) +{ + netio_vde_desc_t *nvd; + netio_desc_t *nio; + + if (!(nio = netio_create (nio_name))) + return NULL; + + nvd = &nio->u.nvd; + + if (netio_vde_create (nvd, control, local) == -1) { + netio_free (nio, NULL); + return NULL; + } + + nio->type = NETIO_TYPE_VDE; + nio->send = (void *) netio_vde_send; + nio->recv = (void *) netio_vde_recv; + nio->save_cfg = netio_vde_save_cfg; + nio->dptr = &nio->u.nvd; + + if (netio_record (nio) == -1) { + netio_free (nio, NULL); + return NULL; + } + + return nio; +} +#endif +/* + * ========================================================================= + * TAP devices + * ========================================================================= + */ + +/* Free a NetIO TAP descriptor */ +static void netio_tap_free (netio_tap_desc_t * ntd) +{ + if (ntd->fd != -1) + close (ntd->fd); +} + +/* Open a TAP device */ +static int netio_tap_open (char *tap_devname) +{ +#ifdef __linux__ + struct ifreq ifr; + int fd, err; + + if ((fd = open ("/dev/net/tun", O_RDWR)) < 0) + return (-1); + + memset (&ifr, 0, sizeof (ifr)); + + /* Flags: IFF_TUN - TUN device (no Ethernet headers) + * IFF_TAP - TAP device + * + * IFF_NO_PI - Do not provide packet information + */ + ifr.ifr_flags = IFF_TAP | IFF_NO_PI; + if (*tap_devname) + strncpy (ifr.ifr_name, tap_devname, IFNAMSIZ); + + if ((err = ioctl (fd, TUNSETIFF, (void *) &ifr)) < 0) { + close (fd); + return err; + } + + strcpy (tap_devname, ifr.ifr_name); + return (fd); +#else + int i, fd = -1; + + if (*tap_devname) { + fd = open (tap_devname, O_RDWR); + } else { + for (i = 0; i < 16; i++) { + snprintf (tap_devname, NETIO_DEV_MAXLEN, "/dev/tap%d", i); + + if ((fd = open (tap_devname, O_RDWR)) >= 0) + break; + } + } + + return (fd); +#endif +} + +/* Allocate a new NetIO TAP descriptor */ +static int netio_tap_create (netio_tap_desc_t * ntd, char *tap_name) +{ + if (strlen (tap_name) >= NETIO_DEV_MAXLEN) { + fprintf (stderr, + "netio_tap_create: bad TAP device string specified.\n"); + return (-1); + } + + memset (ntd, 0, sizeof (*ntd)); + strcpy (ntd->filename, tap_name); + ntd->fd = netio_tap_open (ntd->filename); + + if (ntd->fd == -1) { + fprintf (stderr, + "netio_tap_create: unable to open TAP device %s (%s)\n", tap_name, + strerror (errno)); + return (-1); + } + /*SET NO BLOCKING */ + if (fcntl (ntd->fd, F_SETFL, O_NONBLOCK) == -1) + printf ("Set file descriptor to non-blocking mode failed\n"); + + return (0); +} + +/* Write a packet to a TAP device */ +static ssize_t netio_tap_send (netio_tap_desc_t * ntd, void *pkt, + size_t pkt_len) +{ + return (write (ntd->fd, pkt, pkt_len)); +} + +/* Receive a packet through a TAP device */ +static ssize_t netio_tap_recv (netio_tap_desc_t * ntd, void *pkt, + size_t max_len) +{ + return (read (ntd->fd, pkt, max_len)); +} + +/* Create a new NetIO descriptor with TAP method */ +netio_desc_t *netio_desc_create_tap (char *nio_name, char *tap_name) +{ + netio_tap_desc_t *ntd; + netio_desc_t *nio; + + if (!(nio = netio_create (nio_name))) + return NULL; + + ntd = &nio->u.ntd; + + if (netio_tap_create (ntd, tap_name) == -1) { + netio_free (nio, NULL); + return NULL; + } + + nio->type = NETIO_TYPE_TAP; + nio->send = (void *) netio_tap_send; + nio->recv = (void *) netio_tap_recv; + nio->dptr = &nio->u.ntd; + + return nio; +} + +#if 0 +/* + * ========================================================================= + * TCP sockets + * ========================================================================= + */ + +/* Free a NetIO TCP descriptor */ +static void netio_tcp_free (netio_inet_desc_t * nid) +{ + if (nid->fd != -1) + close (nid->fd); +} + +/* + * very simple protocol to send packets over tcp + * 32 bits in network format - size of packet, then packet itself and so on. + */ +static ssize_t netio_tcp_send (netio_inet_desc_t * nid, void *pkt, + size_t pkt_len) +{ + u_long l = htonl (pkt_len); + + if (write (nid->fd, &l, sizeof (l)) == -1) + return (-1); + + return (write (nid->fd, pkt, pkt_len)); +} + +static ssize_t netio_tcp_recv (netio_inet_desc_t * nid, void *pkt, + size_t max_len) +{ + u_long l; + + if (read (nid->fd, &l, sizeof (l)) != sizeof (l)) + return (-1); + + if (ntohl (l) > max_len) + return (-1); + + return (read (nid->fd, pkt, ntohl (l))); +} + +static int netio_tcp_cli_create (netio_inet_desc_t * nid, char *host, + char *port) +{ + struct sockaddr_in serv; + struct servent *sp; + struct hostent *hp; + + if ((nid->fd = socket (PF_INET, SOCK_STREAM, 0)) < 0) { + perror ("netio_tcp_cli_create: socket"); + return (-1); + } + + memset (&serv, 0, sizeof (serv)); + serv.sin_family = AF_INET; + + if (atoi (port) == 0) { + if (!(sp = getservbyname (port, "tcp"))) { + fprintf (stderr, + "netio_tcp_cli_create: port %s is neither " + "number not service %s\n", port, strerror (errno)); + close (nid->fd); + return (-1); + } + serv.sin_port = sp->s_port; + } else + serv.sin_port = htons (atoi (port)); + + if (inet_addr (host) == INADDR_NONE) { + if (!(hp = gethostbyname (host))) { + fprintf (stderr, "netio_tcp_cli_create: no host %s\n", host); + close (nid->fd); + return (-1); + } + serv.sin_addr.s_addr = *hp->h_addr; + } else + serv.sin_addr.s_addr = inet_addr (host); + + if (connect (nid->fd, (struct sockaddr *) &serv, sizeof (serv)) < 0) { + fprintf (stderr, "netio_tcp_cli_create: connect to %s:%s failed %s\n", + host, port, strerror (errno)); + close (nid->fd); + return (-1); + } + return (0); +} + +/* Create a new NetIO descriptor with TCP_CLI method */ +netio_desc_t *netio_desc_create_tcp_cli (char *nio_name, char *host, + char *port) +{ + netio_desc_t *nio; + + if (!(nio = netio_create (nio_name))) + return NULL; + + if (netio_tcp_cli_create (&nio->u.nid, host, port) < 0) { + netio_free (nio, NULL); + return NULL; + } + + nio->type = NETIO_TYPE_TCP_CLI; + nio->send = (void *) netio_tcp_send; + nio->recv = (void *) netio_tcp_recv; + nio->dptr = &nio->u.nid; + + if (netio_record (nio) == -1) { + netio_free (nio, NULL); + return NULL; + } + + return nio; +} + +static int netio_tcp_ser_create (netio_inet_desc_t * nid, char *port) +{ + struct sockaddr_in serv; + struct servent *sp; + int sock_fd; + + if ((sock_fd = socket (PF_INET, SOCK_STREAM, 0)) < 0) { + perror ("netio_tcp_cli_create: socket\n"); + return (-1); + } + + memset (&serv, 0, sizeof (serv)); + serv.sin_family = AF_INET; + serv.sin_addr.s_addr = htonl (INADDR_ANY); + + if (atoi (port) == 0) { + if (!(sp = getservbyname (port, "tcp"))) { + fprintf (stderr, + "netio_tcp_ser_create: port %s is neither " + "number not service %s\n", port, strerror (errno)); + close (sock_fd); + return (-1); + } + serv.sin_port = sp->s_port; + } else + serv.sin_port = htons (atoi (port)); + + if (bind (sock_fd, (struct sockaddr *) &serv, sizeof (serv)) < 0) { + fprintf (stderr, "netio_tcp_ser_create: bind %s failed %s\n", port, + strerror (errno)); + close (sock_fd); + return (-1); + } + + if (listen (sock_fd, 1) < 0) { + fprintf (stderr, "netio_tcp_ser_create: listen %s failed %s\n", port, + strerror (errno)); + close (sock_fd); + return (-1); + } + + fprintf (stderr, "Waiting connection on port %s...\n", port); + + if ((nid->fd = accept (sock_fd, NULL, NULL)) < 0) { + fprintf (stderr, "netio_tcp_ser_create: accept %s failed %s\n", port, + strerror (errno)); + close (sock_fd); + return (-1); + } + + fprintf (stderr, "Connected\n"); + + close (sock_fd); + return (0); +} + +/* Create a new NetIO descriptor with TCP_SER method */ +netio_desc_t *netio_desc_create_tcp_ser (char *nio_name, char *port) +{ + netio_desc_t *nio; + + if (!(nio = netio_create (nio_name))) + return NULL; + + if (netio_tcp_ser_create (&nio->u.nid, port) == -1) { + netio_free (nio, NULL); + return NULL; + } + + nio->type = NETIO_TYPE_TCP_SER; + nio->send = (void *) netio_tcp_send; + nio->recv = (void *) netio_tcp_recv; + nio->dptr = &nio->u.nid; + + if (netio_record (nio) == -1) { + netio_free (nio, NULL); + return NULL; + } + + return nio; +} + +/* + * ========================================================================= + * UDP sockets + * ========================================================================= + */ + +/* Free a NetIO UDP descriptor */ +static void netio_udp_free (netio_inet_desc_t * nid) +{ + if (nid->remote_host) { + free (nid->remote_host); + nid->remote_host = NULL; + } + + if (nid->fd != -1) + close (nid->fd); +} + +/* Write a packet to an UDP socket */ +static ssize_t netio_udp_send (netio_inet_desc_t * nid, void *pkt, + size_t pkt_len) +{ + return (send (nid->fd, pkt, pkt_len, 0)); +} + +/* Receive a packet from an UDP socket */ +static ssize_t netio_udp_recv (netio_inet_desc_t * nid, void *pkt, + size_t max_len) +{ + return (recvfrom (nid->fd, pkt, max_len, 0, NULL, NULL)); +} + +/* Save the NIO configuration */ +static void netio_udp_save_cfg (netio_desc_t * nio, FILE * fd) +{ + netio_inet_desc_t *nid = nio->dptr; + fprintf (fd, "nio create_udp %s %d %s %d\n", nio->name, nid->local_port, + nid->remote_host, nid->remote_port); +} + +/* Create a new NetIO descriptor with UDP method */ +netio_desc_t *netio_desc_create_udp (char *nio_name, int local_port, + char *remote_host, int remote_port) +{ + netio_inet_desc_t *nid; + netio_desc_t *nio; + + if (!(nio = netio_create (nio_name))) + return NULL; + + nid = &nio->u.nid; + nid->local_port = local_port; + nid->remote_port = remote_port; + + if (!(nid->remote_host = strdup (remote_host))) { + fprintf (stderr, "netio_desc_create_udp: insufficient memory\n"); + goto error; + } + + if ((nid->fd = udp_connect (local_port, remote_host, remote_port)) < 0) { + fprintf (stderr, + "netio_desc_create_udp: unable to connect to %s:%d\n", + remote_host, remote_port); + goto error; + } + + nio->type = NETIO_TYPE_UDP; + nio->send = (void *) netio_udp_send; + nio->recv = (void *) netio_udp_recv; + nio->save_cfg = netio_udp_save_cfg; + nio->dptr = &nio->u.nid; + + if (netio_record (nio) == -1) + goto error; + + return nio; + + error: + netio_free (nio, NULL); + return NULL; +} + +/* + * ========================================================================= + * Linux RAW Ethernet driver + * ========================================================================= + */ +#ifdef LINUX_ETH +/* Free a NetIO raw ethernet descriptor */ +static void netio_lnxeth_free (netio_lnxeth_desc_t * nled) +{ + if (nled->fd != -1) + close (nled->fd); +} + +/* Write a packet to a raw Ethernet socket */ +static ssize_t netio_lnxeth_send (netio_lnxeth_desc_t * nled, void *pkt, + size_t pkt_len) +{ + return (lnx_eth_send (nled->fd, nled->dev_id, pkt, pkt_len)); +} + +/* Receive a packet from an raw Ethernet socket */ +static ssize_t netio_lnxeth_recv (netio_lnxeth_desc_t * nled, void *pkt, + size_t max_len) +{ + return (lnx_eth_recv (nled->fd, pkt, max_len)); +} + +/* Save the NIO configuration */ +static void netio_lnxeth_save_cfg (netio_desc_t * nio, FILE * fd) +{ + netio_lnxeth_desc_t *nled = nio->dptr; + fprintf (fd, "nio create_linux_eth %s %s\n", nio->name, nled->dev_name); +} + +/* Create a new NetIO descriptor with raw Ethernet method */ +netio_desc_t *netio_desc_create_lnxeth (char *nio_name, char *dev_name) +{ + netio_lnxeth_desc_t *nled; + netio_desc_t *nio; + + if (!(nio = netio_create (nio_name))) + return NULL; + + nled = &nio->u.nled; + + if (strlen (dev_name) >= NETIO_DEV_MAXLEN) { + fprintf (stderr, + "netio_desc_create_lnxeth: bad Ethernet device string " + "specified.\n"); + netio_free (nio, NULL); + return NULL; + } + + strcpy (nled->dev_name, dev_name); + + nled->fd = lnx_eth_init_socket (dev_name); + nled->dev_id = lnx_eth_get_dev_index (dev_name); + + if (nled->fd < 0) { + netio_free (nio, NULL); + return NULL; + } + + nio->type = NETIO_TYPE_LINUX_ETH; + nio->send = (void *) netio_lnxeth_send; + nio->recv = (void *) netio_lnxeth_recv; + nio->save_cfg = netio_lnxeth_save_cfg; + nio->dptr = &nio->u.nled; + + if (netio_record (nio) == -1) { + netio_free (nio, NULL); + return NULL; + } + + return nio; +} +#endif /* LINUX_ETH */ + +/* + * ========================================================================= + * Generic RAW Ethernet driver + * ========================================================================= + */ +#ifdef GEN_ETH +/* Free a NetIO raw ethernet descriptor */ +static void netio_geneth_free (netio_geneth_desc_t * nged) +{ + gen_eth_close (nged->pcap_dev); +} + +/* Write a packet to an Ethernet device */ +static ssize_t netio_geneth_send (netio_geneth_desc_t * nged, void *pkt, + size_t pkt_len) +{ + return (gen_eth_send (nged->pcap_dev, pkt, pkt_len)); +} + +/* Receive a packet from an Ethernet device */ +static ssize_t netio_geneth_recv (netio_geneth_desc_t * nged, void *pkt, + size_t max_len) +{ + return (gen_eth_recv (nged->pcap_dev, pkt, max_len)); +} + +/* Save the NIO configuration */ +static void netio_geneth_save_cfg (netio_desc_t * nio, FILE * fd) +{ + netio_geneth_desc_t *nged = nio->dptr; + fprintf (fd, "nio create_gen_eth %s %s\n", nio->name, nged->dev_name); +} + +/* Create a new NetIO descriptor with generic raw Ethernet method */ +netio_desc_t *netio_desc_create_geneth (char *nio_name, char *dev_name) +{ + netio_geneth_desc_t *nged; + netio_desc_t *nio; + + if (!(nio = netio_create (nio_name))) + return NULL; + + nged = &nio->u.nged; + + if (strlen (dev_name) >= NETIO_DEV_MAXLEN) { + fprintf (stderr, + "netio_desc_create_geneth: bad Ethernet device string " + "specified.\n"); + netio_free (nio, NULL); + return NULL; + } + + strcpy (nged->dev_name, dev_name); + + if (!(nged->pcap_dev = gen_eth_init (dev_name))) { + netio_free (nio, NULL); + return NULL; + } + + nio->type = NETIO_TYPE_GEN_ETH; + nio->send = (void *) netio_geneth_send; + nio->recv = (void *) netio_geneth_recv; + nio->save_cfg = netio_geneth_save_cfg; + nio->dptr = &nio->u.nged; + + if (netio_record (nio) == -1) { + netio_free (nio, NULL); + return NULL; + } + + return nio; +} +#endif /* GEN_ETH */ + +/* + * ========================================================================= + * FIFO Driver (intra-hypervisor communications) + * ========================================================================= + */ + +/* Extract the first packet of the FIFO */ +static netio_fifo_pkt_t *netio_fifo_extract_pkt (netio_fifo_desc_t * nfd) +{ + netio_fifo_pkt_t *p; + + if (!(p = nfd->head)) + return NULL; + + nfd->pkt_count--; + nfd->head = p->next; + + if (!nfd->head) + nfd->last = NULL; + + return p; +} + +/* Insert a packet into the FIFO (in tail) */ +static void netio_fifo_insert_pkt (netio_fifo_desc_t * nfd, + netio_fifo_pkt_t * p) +{ + pthread_mutex_lock (&nfd->lock); + + nfd->pkt_count++; + p->next = NULL; + + if (nfd->last) { + nfd->last->next = p; + } else { + nfd->head = p; + } + + nfd->last = p; + pthread_mutex_unlock (&nfd->lock); +} + +/* Free the packet list */ +static void netio_fifo_free_pkt_list (netio_fifo_desc_t * nfd) +{ + netio_fifo_pkt_t *p, *next; + + for (p = nfd->head; p; p = next) { + next = p->next; + free (p); + } + + nfd->head = nfd->last = NULL; + nfd->pkt_count = 0; +} + +/* Establish a cross-connect between two FIFO NetIO */ +int netio_fifo_crossconnect (netio_desc_t * a, netio_desc_t * b) +{ + netio_fifo_desc_t *pa, *pb; + + if ((a->type != NETIO_TYPE_FIFO) || (b->type != NETIO_TYPE_FIFO)) + return (-1); + + pa = &a->u.nfd; + pb = &b->u.nfd; + + /* A => B */ + pthread_mutex_lock (&pa->endpoint_lock); + pthread_mutex_lock (&pa->lock); + pa->endpoint = pb; + netio_fifo_free_pkt_list (pa); + pthread_mutex_unlock (&pa->lock); + pthread_mutex_unlock (&pa->endpoint_lock); + + /* B => A */ + pthread_mutex_lock (&pb->endpoint_lock); + pthread_mutex_lock (&pb->lock); + pb->endpoint = pa; + netio_fifo_free_pkt_list (pb); + pthread_mutex_unlock (&pb->lock); + pthread_mutex_unlock (&pb->endpoint_lock); + return (0); +} + +/* Unbind an endpoint */ +static void netio_fifo_unbind_endpoint (netio_fifo_desc_t * nfd) +{ + pthread_mutex_lock (&nfd->endpoint_lock); + nfd->endpoint = NULL; + pthread_mutex_unlock (&nfd->endpoint_lock); +} + +/* Free a NetIO FIFO descriptor */ +static void netio_fifo_free (netio_fifo_desc_t * nfd) +{ + if (nfd->endpoint) + netio_fifo_unbind_endpoint (nfd->endpoint); + + netio_fifo_free_pkt_list (nfd); + pthread_mutex_destroy (&nfd->lock); + pthread_cond_destroy (&nfd->cond); +} + +/* Send a packet (to the endpoint FIFO) */ +static ssize_t netio_fifo_send (netio_fifo_desc_t * nfd, void *pkt, + size_t pkt_len) +{ + netio_fifo_pkt_t *p; + size_t len; + + pthread_mutex_lock (&nfd->endpoint_lock); + + /* The cross-connect must have been established before */ + if (!nfd->endpoint) + goto error; + + /* Allocate a a new packet and insert it into the endpoint FIFO */ + len = sizeof (netio_fifo_pkt_t) + pkt_len; + if (!(p = malloc (len))) + goto error; + + memcpy (p->pkt, pkt, pkt_len); + p->pkt_len = pkt_len; + netio_fifo_insert_pkt (nfd->endpoint, p); + pthread_cond_signal (&nfd->endpoint->cond); + pthread_mutex_unlock (&nfd->endpoint_lock); + return (pkt_len); + + error: + pthread_mutex_unlock (&nfd->endpoint_lock); + return (-1); +} + +/* Read a packet from the local FIFO queue */ +static ssize_t netio_fifo_recv (netio_fifo_desc_t * nfd, void *pkt, + size_t max_len) +{ + struct timespec ts; + m_tmcnt_t expire; + netio_fifo_pkt_t *p; + size_t len = -1; + + /* Wait for the endpoint to signal a new arriving packet */ + expire = m_gettime_usec () + 50000; + ts.tv_sec = expire / 1000000; + ts.tv_nsec = (expire % 1000000) * 1000; + + pthread_mutex_lock (&nfd->lock); + pthread_cond_timedwait (&nfd->cond, &nfd->lock, &ts); + + /* Extract a packet from the list */ + p = netio_fifo_extract_pkt (nfd); + pthread_mutex_unlock (&nfd->lock); + + if (p) { + len = m_min (p->pkt_len, max_len); + memcpy (pkt, p->pkt, len); + free (p); + } + + return (len); +} + +/* Create a new NetIO descriptor with FIFO method */ +netio_desc_t *netio_desc_create_fifo (char *nio_name) +{ + netio_fifo_desc_t *nfd; + netio_desc_t *nio; + + if (!(nio = netio_create (nio_name))) + return NULL; + + nfd = &nio->u.nfd; + pthread_mutex_init (&nfd->lock, NULL); + pthread_mutex_init (&nfd->endpoint_lock, NULL); + pthread_cond_init (&nfd->cond, NULL); + + nio->type = NETIO_TYPE_FIFO; + nio->send = (void *) netio_fifo_send; + nio->recv = (void *) netio_fifo_recv; + nio->dptr = nfd; + + if (netio_record (nio) == -1) { + netio_free (nio, NULL); + return NULL; + } + + return nio; +} + +/* + * ========================================================================= + * NULL Driver (does nothing, used for debugging) + * ========================================================================= + */ +static ssize_t netio_null_send (void *null_ptr, void *pkt, size_t pkt_len) +{ + return (pkt_len); +} + +static ssize_t netio_null_recv (void *null_ptr, void *pkt, size_t max_len) +{ + usleep (200000); + return (-1); +} + +static void netio_null_save_cfg (netio_desc_t * nio, FILE * fd) +{ + fprintf (fd, "nio create_null %s\n", nio->name); +} + +/* Create a new NetIO descriptor with NULL method */ +netio_desc_t *netio_desc_create_null (char *nio_name) +{ + netio_desc_t *nio; + + if (!(nio = netio_create (nio_name))) + return NULL; + + nio->type = NETIO_TYPE_NULL; + nio->send = (void *) netio_null_send; + nio->recv = (void *) netio_null_recv; + nio->save_cfg = netio_null_save_cfg; + nio->dptr = NULL; + + if (netio_record (nio) == -1) { + netio_free (nio, NULL); + return NULL; + } + + return nio; +} +#endif + +/* Free a NetIO descriptor */ +static int netio_free (void *data, void *arg) +{ + netio_desc_t *nio = data; + + if (nio) { + + switch (nio->type) { + case NETIO_TYPE_TAP: + netio_tap_free (&nio->u.ntd); + break; + case NETIO_TYPE_NULL: + break; + default: + fprintf (stderr, "NETIO: unknown descriptor type %u\n", + nio->type); + } + free (nio->name); + free (nio); + } + + return (TRUE); +} + +#if 0 +/* + * ========================================================================= + * RX Listeners + * ========================================================================= + */ + +/* Find a RX listener */ +static inline struct netio_rx_listener *netio_rxl_find (netio_desc_t * nio) +{ + struct netio_rx_listener *rxl; + + for (rxl = netio_rxl_list; rxl; rxl = rxl->next) + if (rxl->nio == nio) + return rxl; + + return NULL; +} + +/* Remove a NIO from the listener list */ +static int netio_rxl_remove_internal (netio_desc_t * nio) +{ + struct netio_rx_listener *rxl; + int res = -1; + + if ((rxl = netio_rxl_find (nio))) { + /* we suppress this NIO only when the ref count hits 0 */ + rxl->ref_count--; + + if (!rxl->ref_count) { + /* remove this listener from the double linked list */ + if (rxl->next) + rxl->next->prev = rxl->prev; + + if (rxl->prev) + rxl->prev->next = rxl->next; + else + netio_rxl_list = rxl->next; + + /* if this is non-FD NIO, wait for thread to terminate */ + if (netio_get_fd (rxl->nio) == -1) { + rxl->running = FALSE; + pthread_join (rxl->spec_thread, NULL); + } + + free (rxl); + } + + res = 0; + } + + return (res); +} + +/* Add a RXL listener to the listener list */ +static void netio_rxl_add_internal (struct netio_rx_listener *rxl) +{ + struct netio_rx_listener *tmp; + + if ((tmp = netio_rxl_find (rxl->nio))) { + tmp->ref_count++; + free (rxl); + } else { + rxl->prev = NULL; + rxl->next = netio_rxl_list; + if (rxl->next) + rxl->next->prev = rxl; + netio_rxl_list = rxl; + } +} + +/* RX Listener dedicated thread (for non-FD NIO) */ +static void *netio_rxl_spec_thread (void *arg) +{ + struct netio_rx_listener *rxl = arg; + netio_desc_t *nio = rxl->nio; + ssize_t pkt_len; + while (rxl->running) { + + pkt_len = netio_recv (nio, nio->rx_pkt, sizeof (nio->rx_pkt)); + if (pkt_len > 0) { + rxl->rx_handler (nio, nio->rx_pkt, pkt_len, rxl->arg1, rxl->arg2); + } + } + + return NULL; +} + +/* RX Listener General Thread */ +void *netio_rxl_gen_thread (void *arg) +{ + struct netio_rx_listener *rxl; + ssize_t pkt_len; + netio_desc_t *nio; + struct timeval tv; + int fd, fd_max, res; + fd_set rfds; + + for (;;) { + NETIO_RXL_LOCK (); + + NETIO_RXQ_LOCK (); + /* Add the new waiting NIO to the active list */ + while (netio_rxl_add_list != NULL) { + rxl = netio_rxl_add_list; + netio_rxl_add_list = netio_rxl_add_list->next; + netio_rxl_add_internal (rxl); + } + + /* Delete the NIO present in the remove list */ + while (netio_rxl_remove_list != NULL) { + nio = netio_rxl_remove_list; + netio_rxl_remove_list = netio_rxl_remove_list->rxl_next; + netio_rxl_remove_internal (nio); + } + + pthread_cond_broadcast (&netio_rxl_cond); + NETIO_RXQ_UNLOCK (); + + /* Build the FD set */ + FD_ZERO (&rfds); + fd_max = -1; + for (rxl = netio_rxl_list; rxl; rxl = rxl->next) { + if ((fd = netio_get_fd (rxl->nio)) == -1) + continue; + + if (fd > fd_max) + fd_max = fd; + FD_SET (fd, &rfds); + } + NETIO_RXL_UNLOCK (); + + /* Wait for incoming packets */ + tv.tv_sec = 0; + tv.tv_usec = 2 * 1000; /* 2 ms */ + res = select (fd_max + 1, &rfds, NULL, NULL, &tv); + + if (res == -1) { + if (errno != EINTR) + perror ("netio_rxl_thread: select"); + continue; + } + + /* Examine active FDs and call user handlers */ + NETIO_RXL_LOCK (); + + for (rxl = netio_rxl_list; rxl; rxl = rxl->next) { + nio = rxl->nio; + + if ((fd = netio_get_fd (nio)) == -1) + continue; + + if (FD_ISSET (fd, &rfds)) { + { + pkt_len = + netio_recv (nio, nio->rx_pkt, sizeof (nio->rx_pkt)); + + if (pkt_len > 0) { + rxl->rx_handler (nio, nio->rx_pkt, pkt_len, rxl->arg1, + rxl->arg2); + } + } + } + } + } + NETIO_RXL_UNLOCK (); +} + +return NULL; +} + +/* Add a RX listener in the listener list */ +int netio_rxl_add (netio_desc_t * nio, netio_rx_handler_t rx_handler, + void *arg1, void *arg2) +{ + struct netio_rx_listener *rxl; + + NETIO_RXQ_LOCK (); + + if (!(rxl = malloc (sizeof (*rxl)))) { + NETIO_RXQ_UNLOCK (); + fprintf (stderr, "netio_rxl_add: unable to create structure.\n"); + return (-1); + } + + memset (rxl, 0, sizeof (*rxl)); + rxl->nio = nio; + rxl->ref_count = 1; + rxl->rx_handler = rx_handler; + rxl->arg1 = arg1; + rxl->arg2 = arg2; + rxl->running = TRUE; + + if ((netio_get_fd (rxl->nio) == -1) && + pthread_create (&rxl->spec_thread, NULL, netio_rxl_spec_thread, rxl)) { + NETIO_RXQ_UNLOCK (); + fprintf (stderr, + "netio_rxl_add: unable to create specific thread.\n"); + free (rxl); + return (-1); + } + + rxl->next = netio_rxl_add_list; + netio_rxl_add_list = rxl; + + pthread_cond_wait (&netio_rxl_cond, &netio_rxq_mutex); + NETIO_RXQ_UNLOCK (); + return (0); +} + +/* Remove a NIO from the listener list */ +int netio_rxl_remove (netio_desc_t * nio) +{ + NETIO_RXQ_LOCK (); + nio->rxl_next = netio_rxl_remove_list; + netio_rxl_remove_list = nio; + pthread_cond_wait (&netio_rxl_cond, &netio_rxq_mutex); + NETIO_RXQ_UNLOCK (); + return (0); +} + +/* Initialize the RXL thread */ +int netio_rxl_init (void) +{ + pthread_cond_init (&netio_rxl_cond, NULL); + + if (pthread_create (&netio_rxl_thread, NULL, netio_rxl_gen_thread, NULL)) { + perror ("netio_rxl_init: pthread_create"); + return (-1); + } + + return (0); +} + +#endif diff --git a/tools/virtualmips/net_io.h b/tools/virtualmips/net_io.h new file mode 100644 index 0000000..1d38a8f --- /dev/null +++ b/tools/virtualmips/net_io.h @@ -0,0 +1,293 @@ +/* + * Cisco router simulation platform. + * Copyright (c) 2005,2006 Christophe Fillot (cf@utc.fr) + * + * Network I/O Layer. + */ + +#ifndef __NET_IO_H__ +#define __NET_IO_H__ + +#include +#include +#include +#include +#include "utils.h" + +/* Maximum packet size */ +#define NETIO_MAX_PKT_SIZE 32768 + +/* Maximum device length */ +#define NETIO_DEV_MAXLEN 64 + +enum { + NETIO_TYPE_UNIX = 0, + NETIO_TYPE_VDE, + NETIO_TYPE_TAP, + NETIO_TYPE_UDP, + NETIO_TYPE_TCP_CLI, + NETIO_TYPE_TCP_SER, +#ifdef LINUX_ETH + NETIO_TYPE_LINUX_ETH, +#endif +#ifdef GEN_ETH + NETIO_TYPE_GEN_ETH, +#endif + NETIO_TYPE_FIFO, + NETIO_TYPE_NULL, + NETIO_TYPE_MAX, +}; + +enum { + NETIO_FILTER_ACTION_DROP = 0, + NETIO_FILTER_ACTION_PASS, + NETIO_FILTER_ACTION_ALTER, + NETIO_FILTER_ACTION_DUPLICATE, +}; + +typedef struct netio_desc netio_desc_t; + +/* VDE switch definitions */ +enum vde_request_type { VDE_REQ_NEW_CONTROL }; + +#define VDE_SWITCH_MAGIC 0xfeedface +#define VDE_SWITCH_VERSION 3 + +struct vde_request_v3 { + m_uint32_t magic; + m_uint32_t version; + enum vde_request_type type; + struct sockaddr_un sock; +}; + +/* netio unix descriptor */ +typedef struct netio_unix_desc netio_unix_desc_t; +struct netio_unix_desc { + char *local_filename; + struct sockaddr_un remote_sock; + int fd; +}; + +/* netio vde descriptor */ +typedef struct netio_vde_desc netio_vde_desc_t; +struct netio_vde_desc { + char *local_filename; + struct sockaddr_un remote_sock; + int ctrl_fd, data_fd; +}; + +/* netio tap descriptor */ +typedef struct netio_tap_desc netio_tap_desc_t; +struct netio_tap_desc { + char filename[NETIO_DEV_MAXLEN]; + int fd; +}; + +/* netio udp/tcp descriptor */ +typedef struct netio_inet_desc netio_inet_desc_t; +struct netio_inet_desc { + int local_port, remote_port; + char *remote_host; + int fd; +}; + +#ifdef LINUX_ETH +/* netio linux raw ethernet descriptor */ +typedef struct netio_lnxeth_desc netio_lnxeth_desc_t; +struct netio_lnxeth_desc { + char dev_name[NETIO_DEV_MAXLEN]; + int dev_id, fd; +}; +#endif + +#ifdef GEN_ETH +/* netio generic raw ethernet descriptor */ +typedef struct netio_geneth_desc netio_geneth_desc_t; +struct netio_geneth_desc { + char dev_name[NETIO_DEV_MAXLEN]; + pcap_t *pcap_dev; +}; +#endif + +/* FIFO packet */ +typedef struct netio_fifo_pkt netio_fifo_pkt_t; +struct netio_fifo_pkt { + netio_fifo_pkt_t *next; + size_t pkt_len; + char pkt[0]; +}; + +/* Netio FIFO */ +typedef struct netio_fifo_desc netio_fifo_desc_t; +struct netio_fifo_desc { + pthread_cond_t cond; + pthread_mutex_t lock, endpoint_lock; + netio_fifo_desc_t *endpoint; + netio_fifo_pkt_t *head, *last; + u_int pkt_count; +}; + +/* Packet filter */ +typedef struct netio_pktfilter netio_pktfilter_t; +struct netio_pktfilter { + char *name; + int (*setup) (netio_desc_t * nio, void **opt, int argc, char *argv[]); + void (*free) (netio_desc_t * nio, void **opt); + int (*pkt_handler) (netio_desc_t * nio, void *pkt, size_t len, void *opt); + netio_pktfilter_t *next; +}; + +/* Generic netio descriptor */ +struct netio_desc { + u_int type; + void *dptr; + char *name; + int debug; + + /*can nio recv packet now? */ + //u_int can_recv; + + /* Frame Relay specific information */ + //m_uint8_t fr_lmi_seq; + //void *fr_conn_list; + + /* Ethernet specific information */ + //u_int vlan_port_type; + //m_uint16_t vlan_id; + //void *vlan_input_vector; + + union { + //netio_unix_desc_t nud; + //netio_vde_desc_t nvd; + netio_tap_desc_t ntd; + //netio_inet_desc_t nid; +#ifdef LINUX_ETH + //netio_lnxeth_desc_t nled; +#endif +#ifdef GEN_ETH + //netio_geneth_desc_t nged; +#endif + //netio_fifo_desc_t nfd; + } u; + + /* Send and receive prototypes */ + ssize_t (*send) (void *desc, void *pkt, size_t len); + ssize_t (*recv) (void *desc, void *pkt, size_t len); + + /* Configuration saving */ + //void (*save_cfg)(netio_desc_t *nio,FILE *fd); + + /* Packet filters */ + //netio_pktfilter_t *rx_filter,*tx_filter,*both_filter; + //void *rx_filter_data,*tx_filter_data,*both_filter_data; + + /* Next pointer (for RX listener) */ + netio_desc_t *rxl_next; + + /* Packet data */ + u_char rx_pkt[NETIO_MAX_PKT_SIZE]; +}; + +/* RX listener */ +typedef int (*netio_rx_handler_t) (netio_desc_t * nio, u_char * pkt, + ssize_t pkt_len, void *arg1, void *arg2); + +struct netio_rx_listener { + netio_desc_t *nio; + u_int ref_count; + volatile int running; + netio_rx_handler_t rx_handler; + void *arg1, *arg2; + pthread_t spec_thread; + struct netio_rx_listener *prev, *next; + +}; + +/* Get NETIO type given a description */ +int netio_get_type (char *type); + +/* Show the NETIO types */ +void netio_show_types (void); + +/* Create a new NetIO descriptor */ +netio_desc_t *netio_desc_create_unix (char *nio_name, char *local, + char *remote); + +/* Create a new NetIO descriptor with VDE method */ +netio_desc_t *netio_desc_create_vde (char *nio_name, char *control, + char *local); + +/* Create a new NetIO descriptor with TAP method */ +netio_desc_t *netio_desc_create_tap (char *nio_name, char *tap_name); + +/* Create a new NetIO descriptor with TCP_CLI method */ +netio_desc_t *netio_desc_create_tcp_cli (char *nio_name, char *addr, + char *port); + +/* Create a new NetIO descriptor with TCP_SER method */ +netio_desc_t *netio_desc_create_tcp_ser (char *nio_name, char *port); + +/* Create a new NetIO descriptor with UDP method */ +netio_desc_t *netio_desc_create_udp (char *nio_name, int local_port, + char *remote_host, int remote_port); + +#ifdef LINUX_ETH +/* Create a new NetIO descriptor with raw Ethernet method */ +netio_desc_t *netio_desc_create_lnxeth (char *nio_name, char *dev_name); +#endif + +#ifdef GEN_ETH +/* Create a new NetIO descriptor with generic raw Ethernet method */ +netio_desc_t *netio_desc_create_geneth (char *nio_name, char *dev_name); +#endif + +/* Establish a cross-connect between two FIFO NetIO */ +int netio_fifo_crossconnect (netio_desc_t * a, netio_desc_t * b); + +/* Create a new NetIO descriptor with FIFO method */ +netio_desc_t *netio_desc_create_fifo (char *nio_name); + +/* Create a new NetIO descriptor with NULL method */ +netio_desc_t *netio_desc_create_null (char *nio_name); + +/* Acquire a reference to NIO from registry (increment reference count) */ +netio_desc_t *netio_acquire (char *name); + +/* Release an NIO (decrement reference count) */ +int netio_release (char *name); + +/* Delete a NetIO descriptor */ +int netio_delete (char *name); + +/* Delete all NetIO descriptors */ +int netio_delete_all (void); + +/* Save the configuration of a NetIO descriptor */ +void netio_save_config (netio_desc_t * nio, FILE * fd); + +/* Save configurations of all NetIO descriptors */ +void netio_save_config_all (FILE * fd); + +/* Send a packet through a NetIO descriptor */ +ssize_t netio_send (netio_desc_t * nio, void *pkt, size_t len); + +/* Receive a packet through a NetIO descriptor */ +ssize_t netio_recv (netio_desc_t * nio, void *pkt, size_t max_len); + +/* Get a NetIO FD */ +int netio_get_fd (netio_desc_t * nio); + +/* Enable a RX listener */ +int netio_rxl_enable (netio_desc_t * nio); + +/* Add an RX listener in the listener list */ +int netio_rxl_add (netio_desc_t * nio, netio_rx_handler_t rx_handler, + void *arg1, void *arg2); + +/* Remove a NIO from the listener list */ +int netio_rxl_remove (netio_desc_t * nio); + +/* Initialize the RXL thread */ +int netio_rxl_init (void); + +#endif diff --git a/tools/virtualmips/pavo.c b/tools/virtualmips/pavo.c new file mode 100644 index 0000000..84374cf --- /dev/null +++ b/tools/virtualmips/pavo.c @@ -0,0 +1,397 @@ + /* + * Copyright (C) yajin 2008 + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + */ + +#define _GNU_SOURCE +#include +#include +#include +#include + +#include "vp_lock.h" +#include "utils.h" +#include "mips.h" +#include "vm.h" +#include "cpu.h" +#include "mips_exec.h" +#include "debug.h" + +#include "pavo.h" +#include "device.h" +#include "dev_cs8900.h" +#include "mips_jit.h" + +#define MIPS_TIMER_INTERRUPT 7 + +extern m_uint32_t jz4740_int_table[JZ4740_INT_INDEX_MAX]; +int dev_jz4740_gpio_init (vm_instance_t * vm, char *name, m_pa_t paddr, + m_uint32_t len); +int dev_jz4740_uart_init (vm_instance_t * vm, char *name, m_pa_t paddr, + m_uint32_t len, u_int irq, vtty_t * vtty); +int dev_jz4740_cpm_init (vm_instance_t * vm, char *name, m_pa_t paddr, + m_uint32_t len); +int dev_jz4740_emc_init (vm_instance_t * vm, char *name, m_pa_t paddr, + m_uint32_t len); +int dev_jz4740_rtc_init (vm_instance_t * vm, char *name, m_pa_t paddr, + m_uint32_t len); +int dev_jz4740_wdt_tcu_init (vm_instance_t * vm, char *name, m_pa_t paddr, + m_uint32_t len); +int dev_jz4740_int_init (vm_instance_t * vm, char *name, m_pa_t paddr, + m_uint32_t len); +int dev_jz4740_dma_init (vm_instance_t * vm, char *name, m_pa_t paddr, + m_uint32_t len); +int dev_jz4740_lcd_init (vm_instance_t * vm, char *name, m_pa_t paddr, + m_uint32_t len); + +void dev_jz4740_gpio_setirq (int irq); +void dev_jz4740_gpio_clearirq (int irq); + +/* Initialize default parameters for pavo */ +static void pavo_init_defaults (pavo_t * pavo) +{ + vm_instance_t *vm = pavo->vm; + + if (vm->configure_filename == NULL) + vm->configure_filename = strdup (PAVO_DEFAULT_CONFIG_FILE); + vm->ram_size = PAVO_DEFAULT_RAM_SIZE; + vm->boot_method = PAVO_DEFAULT_BOOT_METHOD; + vm->kernel_filename = strdup (PAVO_DEFAULT_KERNEL_FILENAME); +} + +int pavo_init_cs8900 (pavo_t * pavo, char *name, m_pa_t paddr, m_uint32_t len, + int irq_no) +{ + + struct vm_instance *vm = pavo->vm; + + int nio_type = -1; + netio_desc_t *nio; + int count; + char *tokens[10]; + struct cs8900_data *d; + + if ((count = m_strsplit (pavo->cs8900_iotype, ':', tokens, 10)) < 2) { + vm_error (vm, "unable to parse NIO description '%s'.\n", + pavo->cs8900_iotype); + return (-1); + } + nio_type = netio_get_type (tokens[0]); + + switch (nio_type) { + case NETIO_TYPE_TAP: + nio = netio_desc_create_tap (name, tokens[1]); + break; + //case NETIO_TYPE_LINUX_ETH: + // nio=netio_desc_create_lnxeth(name,tokens[1]); + // break; + default: + return (-1); + } + if (!nio) { + vm_error (vm, "unable to create NETIO descriptor %s\n", tokens[0]); + return (-1); + } + d = dev_cs8900_init (vm, name, paddr, len, irq_no); + if (!d) { + vm_error (vm, "unable to int cs8900\n"); + return (-1); + } + if (dev_cs8900_set_nio (d, nio) == -1) { + vm_error (vm, "unable to set cs8900 nio \n"); + return (-1); + } + + return 0; + +} + +/* Initialize the PAVO Platform (MIPS) */ +static int pavo_init_platform (pavo_t * pavo) +{ + struct vm_instance *vm = pavo->vm; + cpu_mips_t *cpu0; + void *(*cpu_run_fn) (void *); + + vm_init_vtty (vm); + + /* Create a CPU group */ + vm->cpu_group = cpu_group_create ("System CPU"); + + /* Initialize the virtual MIPS processor */ + if (!(cpu0 = cpu_create (vm, CPU_TYPE_MIPS32, 0))) { + vm_error (vm, "unable to create CPU0!\n"); + return (-1); + } + /* Add this CPU to the system CPU group */ + cpu_group_add (vm->cpu_group, cpu0); + vm->boot_cpu = cpu0; + + cpu_run_fn = (void *) mips_exec_run_cpu; + /* create the CPU thread execution */ + if (pthread_create (&cpu0->cpu_thread, NULL, cpu_run_fn, cpu0) != 0) { + fprintf (stderr, "cpu_create: unable to create thread for CPU%u\n", + 0); + free (cpu0); + return (-1); + } + cpu0->addr_bus_mask = PAVO_ADDR_BUS_MASK; + + /* Initialize RAM */ + vm_ram_init (vm, 0x00000000ULL); + + /*create 1GB nand flash */ + if ((vm->flash_size == 0x400) && (vm->flash_type = FLASH_TYPE_NAND_FLASH)) + if (dev_nand_flash_1g_init (vm, "NAND FLASH 1G", NAND_DATAPORT, + 0x10004, &(pavo->nand_flash)) == -1) + return (-1); + if (dev_jz4740_gpio_init (vm, "JZ4740 GPIO", JZ4740_GPIO_BASE, + JZ4740_GPIO_SIZE) == -1) + return (-1); + if (dev_jz4740_uart_init (vm, "JZ4740 UART0", JZ4740_UART0_BASE, + JZ4740_UART0_SIZE, 9, vm->vtty_con1) == -1) + return (-1); + if (dev_jz4740_uart_init (vm, "JZ4740 UART1", JZ4740_UART1_BASE, + JZ4740_UART1_SIZE, 8, vm->vtty_con2) == -1) + return (-1); + + if (dev_jz4740_cpm_init (vm, "JZ4740 CPM", JZ4740_CPM_BASE, + JZ4740_CPM_SIZE) == -1) + return (-1); + if (dev_jz4740_emc_init (vm, "JZ4740 EMC", JZ4740_EMC_BASE, + JZ4740_EMC_SIZE) == -1) + return (-1); + if (dev_jz4740_rtc_init (vm, "JZ4740 RTC", JZ4740_RTC_BASE, + JZ4740_RTC_SIZE) == -1) + return (-1); + if (dev_jz4740_wdt_tcu_init (vm, "JZ4740 WDT/TCU", JZ4740_WDT_TCU_BASE, + JZ4740_WDT_TCU_SIZE) == -1) + return (-1); + if (dev_jz4740_int_init (vm, "JZ4740 INT", JZ4740_INT_BASE, + JZ4740_INT_SIZE) == -1) + return (-1); + if (dev_jz4740_dma_init (vm, "JZ4740 DMA", JZ4740_DMA_BASE, + JZ4740_DMA_SIZE) == -1) + return (-1); + + if (pavo->cs8900_enable == 1) { + if (pavo_init_cs8900 (pavo, "CS8900A", CS8900_IO_BASE, CS8900_SIZE, + CS8900_DEFAULT_IRQ) == -1) + return (-1); + } + + /*LCD*/ +#ifdef SIM_LCD + if (dev_jz4740_lcd_init (vm, "JZ4740 LCD", JZ4740_LCD_BASE, + JZ4740_LCD_SIZE) == -1) + return (-1); + +#endif + + return (0); +} + +static int pavo_boot (pavo_t * pavo) +{ + vm_instance_t *vm = pavo->vm; + + if (!vm->boot_cpu) + return (-1); + + return jz4740_reset (vm); + +} + +void pavo_clear_irq (vm_instance_t * vm, u_int irq) +{ + m_uint32_t irq_mask; + + irq_mask = 1 << irq; + + /*clear ISR and IPR */ + jz4740_int_table[INTC_ISR / 4] &= ~irq_mask; + jz4740_int_table[INTC_IPR / 4] &= ~irq_mask; + +} + +/*map irq to soc irq*/ +int forced_inline plat_soc_irq (u_int irq) +{ + if ((irq >= 48) && (irq <= 175)) { + dev_jz4740_gpio_setirq (irq); + /*GPIO IRQ */ + if ((irq >= 48) && (irq <= 79)) + irq = IRQ_GPIO0; + else if ((irq >= 80) && (irq <= 111)) + irq = IRQ_GPIO1; + else if ((irq >= 112) && (irq <= 143)) + irq = IRQ_GPIO2; + else if ((irq >= 144) && (irq <= 175)) + irq = IRQ_GPIO3; + } + return irq; +} + +void pavo_set_irq (vm_instance_t * vm, u_int irq) +{ + m_uint32_t irq_mask; + + irq = plat_soc_irq (irq); + + irq_mask = 1 << irq; + jz4740_int_table[INTC_ISR / 4] |= irq_mask; + /*first check ICMR. masked interrupt is **invisible** to cpu */ + if (unlikely (jz4740_int_table[INTC_IMR / 4] & irq_mask)) { + /*the irq is masked. clear IPR */ + jz4740_int_table[INTC_IPR / 4] &= ~irq_mask; + } else { + /*the irq is not masked */ + + /*set IPR */ + /* + * we set IPR, not *or* . yajin + * + * JZ Kernel 'plat_irq_dispatch' determine which is the highest priority interrupt + * and handle. + * It uses a function ffs to find first set irq from least bit to highest bit. + * 260 irq = ffs(intc_ipr) - 1; + * + * That means when tcu0 irq and gpio1 irq occurs at the same time ,INTC_IPR=0x8800000 + * and irq handler will handle tcu0 irq(bit 23) not gpio1 irq(bit 27). + * + * In pavo gpio1->cs8900 int + * + * TCU0 irq occurs every 10 ms and gpio1 occurs about 10ms (cs8900 has received a packet + * or has txed a packet), jz kernel always handle tcu0 irq. gpio1 irq is hungry. So I just set + * jz4740_int_table[INTC_IPR/4]= irq_mask not or(|) irq_mask. TCU0 irq may be lost. However, + * gpio1 irq is not so ofen so it is not a big problem. + * + * In emulator, irq is not a good method for hardware to tell kernel something has happened. + * Emulator likes polling more than interrupt :) . + * + */ + jz4740_int_table[INTC_IPR / 4] = irq_mask; + + mips_set_irq (vm->boot_cpu, JZ4740_INT_TO_MIPS); + mips_update_irq_flag (vm->boot_cpu); + } +} + +COMMON_CONFIG_INFO_ARRAY; +static void printf_configure (pavo_t * pavo) +{ + + vm_instance_t *vm = pavo->vm; + PRINT_COMMON_CONFIG_OPTION; + + /*print other configure information here */ + if (pavo->cs8900_enable == 1) { + printf ("CS8900 net card enabled\n"); + printf ("CS8900 iotype %s \n", pavo->cs8900_iotype); + } else + printf ("CS8900 net card disenabled\n"); +} + +static void pavo_parse_configure (pavo_t * pavo) +{ + vm_instance_t *vm = pavo->vm; + cfg_opt_t opts[] = { + COMMON_CONFIG_OPTION + /*add other configure information here */ + CFG_SIMPLE_INT ("cs8900_enable", &(pavo->cs8900_enable)), + CFG_SIMPLE_STR ("cs8900_iotype", &(pavo->cs8900_iotype)), + CFG_SIMPLE_INT ("jit_use", &(vm->jit_use)), + + CFG_END () + }; + cfg_t *cfg; + + cfg = cfg_init (opts, 0); + cfg_parse (cfg, vm->configure_filename); + cfg_free (cfg); + + VALID_COMMON_CONFIG_OPTION; + + /*add other configure information validation here */ + if (vm->boot_method == BOOT_BINARY) { + ASSERT (vm->boot_from == 2, + "boot_from must be 2(NAND Flash)\n pavo only can boot from NAND Flash.\n"); + } + if (vm->flash_size != 0) { + ASSERT (vm->flash_size == 4, + "flash_size should be 4.\n We only support 4MB NOR flash emulation\n"); + } + if (pavo->cs8900_enable == 1) { + ASSERT (pavo->cs8900_iotype != NULL, "You must set cs8900_enable \n"); + } + if (vm->jit_use == 1) { + ASSERT (JIT_SUPPORT == 1, + "You must compile with JIT Support to use jit. \n"); + } + + /*Print the configure information */ + printf_configure (pavo); + +} + +/* Clear timer interrupt */ +void clear_timer_irq (cpu_mips_t *cpu) +{ + mips_clear_irq (cpu, MIPS_TIMER_INTERRUPT); + mips_update_irq_flag (cpu); +} + +/* Create a router instance */ +vm_instance_t *create_instance (char *configure_filename) +{ + pavo_t *pavo; + char *name; + if (!(pavo = malloc (sizeof (*pavo)))) { + fprintf (stderr, "ADM5120': Unable to create new instance!\n"); + return NULL; + } + + memset (pavo, 0, sizeof (*pavo)); + name = strdup ("pavo"); + + if (!(pavo->vm = vm_create (name, VM_TYPE_PAVO))) { + fprintf (stderr, "PAVO : unable to create VM instance!\n"); + goto err_vm; + } + free (name); + + if (configure_filename != NULL) + pavo->vm->configure_filename = strdup (configure_filename); + pavo_init_defaults (pavo); + pavo_parse_configure (pavo); + /*init gdb debug */ + vm_debug_init (pavo->vm); + + pavo->vm->hw_data = pavo; + + return (pavo->vm); + + err_vm: + free (name); + free (pavo); + return NULL; + +} + +int init_instance (vm_instance_t * vm) +{ + pavo_t *pavo = VM_PAVO (vm); + + if (pavo_init_platform (pavo) == -1) { + vm_error (vm, "unable to initialize the platform hardware.\n"); + return (-1); + } + /* IRQ routing */ + vm->set_irq = pavo_set_irq; + vm->clear_irq = pavo_clear_irq; + + return (pavo_boot (pavo)); + +} diff --git a/tools/virtualmips/pavo.conf b/tools/virtualmips/pavo.conf new file mode 100644 index 0000000..a9a1018 --- /dev/null +++ b/tools/virtualmips/pavo.conf @@ -0,0 +1,32 @@ +#configure file for pavo + +# RAM size in kbytes. If not set, default value is 65536. +ram_size = 65536 + +#1:Binary 2:elf +boot_method = 1 + +#1:NOR FLASH 2 NAND FLASH +boot_from = 2 + + +kernel_file_name = "vmlinux-pavo" + +#1 NOR 2 NAND +flash_type = 2 +flash_size = 0x400 /*Mbytes*/ +#flash_file_name = "flash.bin" only need for nor flash +#flash_phy_address = 0x1fc00000 only need for nor flash + + + +gdb_debug = 0 +gdb_port = 5555 + + +cs8900_enable = 1 +cs8900_iotype = "tap:tap0" + +#JIT. MUST compile with JIT support if you set jit_use=1 +#JIT is only supported on X86_32 host. AMD64 is not supported. +#jit_use = 1 diff --git a/tools/virtualmips/pavo.h b/tools/virtualmips/pavo.h new file mode 100644 index 0000000..77d5b36 --- /dev/null +++ b/tools/virtualmips/pavo.h @@ -0,0 +1,49 @@ + /* + * Copyright (C) yajin 2008 + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + * + */ + +#ifndef __PAVO_H__ +#define __PAVO_H__ + +#include "jz4740.h" +#include "dev_nand_flash_1g.h" + +#ifdef SIM_LCD +#include "vp_sdl.h" +#endif + +#define PAVO_DEFAULT_CONFIG_FILE "pavo.conf" +#define PAVO_DEFAULT_RAM_SIZE 16 +#define PAVO_DEFAULT_BOOT_METHOD BOOT_BINARY +#define PAVO_DEFAULT_KERNEL_FILENAME "vmlinux" +#define PAVO_ADDR_BUS_MASK 0xffffffff /*32bit phy address */ + +struct pavo_system { + /* Associated VM instance */ + vm_instance_t *vm; + nand_flash_1g_data_t *nand_flash; + + m_uint32_t cs8900_enable; + char *cs8900_iotype; + + /*For LCD */ +//#ifdef SIM_LCD +//struct DisplayState *ds; +//#endif + +}; + +typedef struct pavo_system pavo_t; + +#define VM_PAVO(vm) ((pavo_t *)vm->hw_data) + +vm_instance_t *create_instance (char *conf); +int init_instance (vm_instance_t * vm); +//void virtual_timer(cpu_mips_t *cpu); +int pavo_reset (vm_instance_t * vm); + +#endif diff --git a/tools/virtualmips/pic32.c b/tools/virtualmips/pic32.c new file mode 100644 index 0000000..72c81db --- /dev/null +++ b/tools/virtualmips/pic32.c @@ -0,0 +1,689 @@ +/* + * PIC32 emulation. + * + * Copyright (C) 2011 Serge Vakulenko + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + */ +#define _GNU_SOURCE +#include +#include +#include + +#include "vp_lock.h" +#include "utils.h" +#include "mips.h" +#include "vm.h" +#include "cpu.h" +#include "mips_exec.h" +#include "debug.h" + +#include "pic32.h" +#include "device.h" +#include "mips_jit.h" + +/* + * Translate IRQ number to interrupt vector. + */ +static const int irq_to_vector[] = { + PIC32_VECT_CT, /* 0 - Core Timer Interrupt */ + PIC32_VECT_CS0, /* 1 - Core Software Interrupt 0 */ + PIC32_VECT_CS1, /* 2 - Core Software Interrupt 1 */ + PIC32_VECT_INT0, /* 3 - External Interrupt 0 */ + PIC32_VECT_T1, /* 4 - Timer1 */ + PIC32_VECT_IC1, /* 5 - Input Capture 1 */ + PIC32_VECT_OC1, /* 6 - Output Compare 1 */ + PIC32_VECT_INT1, /* 7 - External Interrupt 1 */ + PIC32_VECT_T2, /* 8 - Timer2 */ + PIC32_VECT_IC2, /* 9 - Input Capture 2 */ + PIC32_VECT_OC2, /* 10 - Output Compare 2 */ + PIC32_VECT_INT2, /* 11 - External Interrupt 2 */ + PIC32_VECT_T3, /* 12 - Timer3 */ + PIC32_VECT_IC3, /* 13 - Input Capture 3 */ + PIC32_VECT_OC3, /* 14 - Output Compare 3 */ + PIC32_VECT_INT3, /* 15 - External Interrupt 3 */ + PIC32_VECT_T4, /* 16 - Timer4 */ + PIC32_VECT_IC4, /* 17 - Input Capture 4 */ + PIC32_VECT_OC4, /* 18 - Output Compare 4 */ + PIC32_VECT_INT4, /* 19 - External Interrupt 4 */ + PIC32_VECT_T5, /* 20 - Timer5 */ + PIC32_VECT_IC5, /* 21 - Input Capture 5 */ + PIC32_VECT_OC5, /* 22 - Output Compare 5 */ + PIC32_VECT_SPI1, /* 23 - SPI1 Fault */ + PIC32_VECT_SPI1, /* 24 - SPI1 Transfer Done */ + PIC32_VECT_SPI1, /* 25 - SPI1 Receive Done */ + + PIC32_VECT_U1 | /* 26 - UART1 Error */ + PIC32_VECT_SPI3 | /* 26 - SPI3 Fault */ + PIC32_VECT_I2C3, /* 26 - I2C3 Bus Collision Event */ + + PIC32_VECT_U1 | /* 27 - UART1 Receiver */ + PIC32_VECT_SPI3 | /* 27 - SPI3 Transfer Done */ + PIC32_VECT_I2C3, /* 27 - I2C3 Slave Event */ + + PIC32_VECT_U1 | /* 28 - UART1 Transmitter */ + PIC32_VECT_SPI3 | /* 28 - SPI3 Receive Done */ + PIC32_VECT_I2C3, /* 28 - I2C3 Master Event */ + + PIC32_VECT_I2C1, /* 29 - I2C1 Bus Collision Event */ + PIC32_VECT_I2C1, /* 30 - I2C1 Slave Event */ + PIC32_VECT_I2C1, /* 31 - I2C1 Master Event */ + PIC32_VECT_CN, /* 32 - Input Change Interrupt */ + PIC32_VECT_AD1, /* 33 - ADC1 Convert Done */ + PIC32_VECT_PMP, /* 34 - Parallel Master Port */ + PIC32_VECT_CMP1, /* 35 - Comparator Interrupt */ + PIC32_VECT_CMP2, /* 36 - Comparator Interrupt */ + + PIC32_VECT_U3 | /* 37 - UART3 Error */ + PIC32_VECT_SPI2 | /* 37 - SPI2 Fault */ + PIC32_VECT_I2C4, /* 37 - I2C4 Bus Collision Event */ + + PIC32_VECT_U3 | /* 38 - UART3 Receiver */ + PIC32_VECT_SPI2 | /* 38 - SPI2 Transfer Done */ + PIC32_VECT_I2C4, /* 38 - I2C4 Slave Event */ + + PIC32_VECT_U3 | /* 39 - UART3 Transmitter */ + PIC32_VECT_SPI2 | /* 39 - SPI2 Receive Done */ + PIC32_VECT_I2C4, /* 39 - I2C4 Master Event */ + + PIC32_VECT_U2 | /* 40 - UART2 Error */ + PIC32_VECT_SPI4 | /* 40 - SPI4 Fault */ + PIC32_VECT_I2C5, /* 40 - I2C5 Bus Collision Event */ + + PIC32_VECT_U2 | /* 41 - UART2 Receiver */ + PIC32_VECT_SPI4 | /* 41 - SPI4 Transfer Done */ + PIC32_VECT_I2C5, /* 41 - I2C5 Slave Event */ + + PIC32_VECT_U2 | /* 42 - UART2 Transmitter */ + PIC32_VECT_SPI4 | /* 42 - SPI4 Receive Done */ + PIC32_VECT_I2C5, /* 42 - I2C5 Master Event */ + + PIC32_VECT_I2C2, /* 43 - I2C2 Bus Collision Event */ + PIC32_VECT_I2C2, /* 44 - I2C2 Slave Event */ + PIC32_VECT_I2C2, /* 45 - I2C2 Master Event */ + PIC32_VECT_FSCM, /* 46 - Fail-Safe Clock Monitor */ + PIC32_VECT_RTCC, /* 47 - Real-Time Clock and Calendar */ + PIC32_VECT_DMA0, /* 48 - DMA Channel 0 */ + PIC32_VECT_DMA1, /* 49 - DMA Channel 1 */ + PIC32_VECT_DMA2, /* 50 - DMA Channel 2 */ + PIC32_VECT_DMA3, /* 51 - DMA Channel 3 */ + PIC32_VECT_DMA4, /* 52 - DMA Channel 4 */ + PIC32_VECT_DMA5, /* 53 - DMA Channel 5 */ + PIC32_VECT_DMA6, /* 54 - DMA Channel 6 */ + PIC32_VECT_DMA7, /* 55 - DMA Channel 7 */ + PIC32_VECT_FCE, /* 56 - Flash Control Event */ + PIC32_VECT_USB, /* 57 - USB */ + PIC32_VECT_CAN1, /* 58 - Control Area Network 1 */ + PIC32_VECT_CAN2, /* 59 - Control Area Network 2 */ + PIC32_VECT_ETH, /* 60 - Ethernet Interrupt */ + PIC32_VECT_IC1, /* 61 - Input Capture 1 Error */ + PIC32_VECT_IC2, /* 62 - Input Capture 2 Error */ + PIC32_VECT_IC3, /* 63 - Input Capture 3 Error */ + PIC32_VECT_IC4, /* 64 - Input Capture 4 Error */ + PIC32_VECT_IC5, /* 65 - Input Capture 5 Error */ + PIC32_VECT_PMP, /* 66 - Parallel Master Port Error */ + PIC32_VECT_U4, /* 67 - UART4 Error */ + PIC32_VECT_U4, /* 68 - UART4 Receiver */ + PIC32_VECT_U4, /* 69 - UART4 Transmitter */ + PIC32_VECT_U6, /* 70 - UART6 Error */ + PIC32_VECT_U6, /* 71 - UART6 Receiver */ + PIC32_VECT_U6, /* 72 - UART6 Transmitter */ + PIC32_VECT_U5, /* 73 - UART5 Error */ + PIC32_VECT_U5, /* 74 - UART5 Receiver */ + PIC32_VECT_U5, /* 75 - UART5 Transmitter */ +}; + +/* Initialize the PIC32 Platform (MIPS) */ +static int pic32_init_platform (pic32_t *pic32) +{ + struct vm_instance *vm = pic32->vm; + cpu_mips_t *cpu0; + void *(*cpu_run_fn) (void *); + + vm_init_vtty (vm); + + /* Create a CPU group */ + vm->cpu_group = cpu_group_create ("System CPU"); + + /* Initialize the virtual MIPS processor */ + cpu0 = cpu_create (vm, CPU_TYPE_MIPS32, 0); + if (! cpu0) { + vm_error (vm, "unable to create CPU0!\n"); + return (-1); + } + /* Add this CPU to the system CPU group */ + cpu_group_add (vm->cpu_group, cpu0); + vm->boot_cpu = cpu0; + + /* create the CPU thread execution */ + cpu_run_fn = (void *) mips_exec_run_cpu; + if (pthread_create (&cpu0->cpu_thread, NULL, cpu_run_fn, cpu0) != 0) { + fprintf (stderr, "cpu_create: unable to create thread for CPU%u\n", + 0); + free (cpu0); + return (-1); + } + /* 32-bit address */ + cpu0->addr_bus_mask = 0xffffffff; + + /* Initialize RAM */ + vm_ram_init (vm, 0x00000000ULL); + + /* Initialize two flash areas */ + if (vm->flash_size != 0) + if (dev_pic32_flash_init (vm, "Program flash", vm->flash_size, + vm->flash_address, vm->flash_filename) == -1) + return (-1); + if (pic32->boot_flash_size != 0) + if (dev_pic32_flash_init (vm, "Boot flash", pic32->boot_flash_size, + pic32->boot_flash_address, pic32->boot_file_name) == -1) + return (-1); + + /* Initialize peripherals */ + if (dev_pic32_uart_init (vm, "UART1", PIC32_U1MODE, + PIC32_IRQ_U1E, vm->vtty_con[0]) == -1) + return (-1); + if (dev_pic32_uart_init (vm, "UART2", PIC32_U2MODE, + PIC32_IRQ_U2E, vm->vtty_con[1]) == -1) + return (-1); +#if NVTTY >= 3 + if (dev_pic32_uart_init (vm, "UART3", PIC32_U3MODE, + PIC32_IRQ_U3E, vm->vtty_con[2]) == -1) + return (-1); +#endif +#if NVTTY >= 4 + if (dev_pic32_uart_init (vm, "UART4", PIC32_U4MODE, + PIC32_IRQ_U4E, vm->vtty_con[3]) == -1) + return (-1); +#endif +#if NVTTY >= 5 + if (dev_pic32_uart_init (vm, "UART5", PIC32_U5MODE, + PIC32_IRQ_U5E, vm->vtty_con[4]) == -1) + return (-1); +#endif +#if NVTTY >= 6 + if (dev_pic32_uart_init (vm, "UART6", PIC32_U6MODE, + PIC32_IRQ_U6E, vm->vtty_con[5]) == -1) + return (-1); +#endif + if (dev_pic32_intcon_init (vm, "INTCON", PIC32_INTCON) == -1) + return (-1); + if (dev_pic32_dmacon_init (vm, "DMACON", PIC32_DMACON) == -1) + return (-1); + if (dev_pic32_syscon_init (vm, "SYSCON", PIC32_OSCCON) == -1) + return (-1); + if (dev_pic32_adc_init (vm, "ADC", PIC32_AD1CON1) == -1) + return (-1); + if (dev_pic32_prefetch_init (vm, "Prefetch", PIC32_CHECON) == -1) + return (-1); + if (dev_pic32_bmxcon_init (vm, "BMX", PIC32_BMXCON) == -1) + return (-1); + if (dev_pic32_rtcc_init (vm, "RTCC", PIC32_RTCCON) == -1) + return (-1); + if (dev_pic32_gpio_init (vm, "GPIO", PIC32_TRISA) == -1) + return (-1); + if (dev_pic32_spi_init (vm, "SPI1", PIC32_SPI1CON, + PIC32_IRQ_SPI1E) == -1) + return (-1); + if (dev_pic32_spi_init (vm, "SPI2", PIC32_SPI2CON, + PIC32_IRQ_SPI2E) == -1) + return (-1); + if (dev_pic32_spi_init (vm, "SPI3", PIC32_SPI3CON, + PIC32_IRQ_SPI3E) == -1) + return (-1); + if (dev_pic32_spi_init (vm, "SPI4", PIC32_SPI4CON, + PIC32_IRQ_SPI4E) == -1) + return (-1); + pic32->timer1 = dev_pic32_timer_init (vm, "Timer1", PIC32_T1CON, PIC32_IRQ_T1); + pic32->timer2 = dev_pic32_timer_init (vm, "Timer2", PIC32_T2CON, PIC32_IRQ_T2); + pic32->timer3 = dev_pic32_timer_init (vm, "Timer3", PIC32_T3CON, PIC32_IRQ_T3); + pic32->timer4 = dev_pic32_timer_init (vm, "Timer4", PIC32_T4CON, PIC32_IRQ_T4); + pic32->timer5 = dev_pic32_timer_init (vm, "Timer5", PIC32_T5CON, PIC32_IRQ_T5); + if (! pic32->timer1 || ! pic32->timer2 || ! pic32->timer3 || + ! pic32->timer4 || ! pic32->timer5) + return (-1); + if (dev_sdcard_init (&pic32->sdcard[0], "SD0", pic32->sdcard0_size, + pic32->sdcard0_file_name) < 0) + return (-1); + if (dev_sdcard_init (&pic32->sdcard[1], "SD1", pic32->sdcard1_size, + pic32->sdcard1_file_name) < 0) + return (-1); + if (dev_swap_init (&pic32->swap, "Swap") < 0) + return (-1); + + /* Initialize DEVCFG area */ + if (dev_pic32_devcfg_init (vm, "DEVCFG", 0x1fc02f00) < 0) + return (-1); + + pic32->sdcard[1].unit = 1; + return (0); +} + +/* + * Find pending interrupt with the biggest priority. + * Setup INTSTAT and cause registers. + * Update irq_pending flag for CPU. + */ +void pic32_update_irq_flag (pic32_t *pic32) +{ + cpu_mips_t *cpu = pic32->vm->boot_cpu; + int vector, level, irq, n, v; + + /* Assume no interrupts pending. */ + cpu->irq_cause = 0; + cpu->irq_pending = 0; + pic32->intstat = 0; + + if ((pic32->ifs[0] & pic32->iec[0]) || + (pic32->ifs[1] & pic32->iec[1]) || + (pic32->ifs[2] & pic32->iec[2])) + { + /* Find the most prioritive pending interrupt, + * it's vector and level. */ + vector = 0; + level = 0; + for (irq=0; irq> 5; + if ((pic32->ifs[n] & pic32->iec[n]) >> (irq & 31) & 1) { + /* Interrupt is pending. */ + v = irq_to_vector [irq]; + if (v < 0) + continue; + if (pic32->ivprio[v] > level) { + vector = v; + level = pic32->ivprio[v]; + } + } + } + pic32->intstat = vector | (level << 8); + + cpu->irq_cause = level << 10; +/*printf ("-- vector = %d, level = %d\n", vector, level);*/ + } +/*else printf ("-- no irq pending\n");*/ + + mips_update_irq_flag (cpu); +} + +void pic32_clear_irq (vm_instance_t *vm, u_int irq) +{ + pic32_t *pic32 = (pic32_t*) vm->hw_data; + + /* Clear interrupt flag status */ + pic32->ifs [irq >> 5] &= ~(1 << (irq & 31)); + + pic32_update_irq_flag (pic32); +} + +void pic32_set_irq (vm_instance_t *vm, u_int irq) +{ + pic32_t *pic32 = (pic32_t*) vm->hw_data; + + /* Set interrupt flag status */ + pic32->ifs [irq >> 5] |= 1 << (irq & 31); + + pic32_update_irq_flag (pic32); +} + +/* + * Activate core timer interrupt + */ +void set_timer_irq (cpu_mips_t *cpu) +{ + pic32_set_irq (cpu->vm, PIC32_VECT_CT); +} + +/* + * Clear core timer interrupt + */ +void clear_timer_irq (cpu_mips_t *cpu) +{ + pic32_clear_irq (cpu->vm, PIC32_VECT_CT); +} + +/* + * Increment timers. + */ +void host_alarm (cpu_mips_t *cpu, int nclocks) +{ + pic32_t *pic32 = (pic32_t*) cpu->vm->hw_data; + + dev_pic32_timer_tick (cpu, pic32->timer1, nclocks); + dev_pic32_timer_tick (cpu, pic32->timer2, nclocks); + dev_pic32_timer_tick (cpu, pic32->timer3, nclocks); + dev_pic32_timer_tick (cpu, pic32->timer4, nclocks); + dev_pic32_timer_tick (cpu, pic32->timer5, nclocks); +} + +/* + * Configuration information. + */ +static char *boot_method_string[2] = {"Binary", "ELF"}; +static char *boot_from_string[2] = {"NOR FLASH", "NAND FLASH"}; +static char *flash_type_string[2] = {"NOR FLASH", "NAND FLASH"}; + +static char *start_address = 0; +static char *trace_address = 0; +static char *uart_type[NVTTY] = {0}; +static char *uart_port[NVTTY] = {0}; + +static void configure_parameter (void *arg, char *section, char *param, char *value) +{ + pic32_t *pic32 = arg; + vm_instance_t *vm = pic32->vm; + + if (strcmp (param, "ram_size") == 0) + vm->ram_size = strtoul (value, 0, 0); + else if (strcmp (param, "gdb_debug") == 0) + vm->gdb_debug = strtoul (value, 0, 0); + else if (strcmp (param, "gdb_port") == 0) + vm->gdb_port = strtoul (value, 0, 0); + else if (strcmp (param, "flash_size") == 0) + vm->flash_size = strtoul (value, 0, 0); + else if (strcmp (param, "flash_type") == 0) + vm->flash_type = strtoul (value, 0, 0); + else if (strcmp (param, "flash_file_name") == 0) + vm->flash_filename = strdup (value); + else if (strcmp (param, "flash_phy_address") == 0) + vm->flash_address = strtoul (value, 0, 0); + else if (strcmp (param, "boot_method") == 0) + vm->boot_method = strtoul (value, 0, 0); + else if (strcmp (param, "boot_from") == 0) + vm->boot_from = strtoul (value, 0, 0); + else if (strcmp (param, "kernel_file_name") == 0) + vm->kernel_filename = strdup (value); + else if (strcmp (param, "jit_use") == 0) + vm->jit_use = strtoul (value, 0, 0); + else if (strcmp (param, "debug_level") == 0) + vm->debug_level = strtoul (value, 0, 0); + else if (strcmp (param, "boot_flash_size") == 0) + pic32->boot_flash_size = strtoul (value, 0, 0); + else if (strcmp (param, "boot_flash_address")== 0) + pic32->boot_flash_address = strtoul (value, 0, 0); + else if (strcmp (param, "boot_file_name") == 0) + pic32->boot_file_name = strdup (value); + else if (strcmp (param, "start_address") == 0) + start_address = strdup (value); + else if (strcmp (param, "trace_address") == 0) + trace_address = strdup (value); + else if (strcmp (param, "sdcard_port") == 0) + pic32->sdcard_port = strtoul (value, 0, 0); + else if (strcmp (param, "sdcard0_size") == 0) + pic32->sdcard0_size = strtoul (value, 0, 0); + else if (strcmp (param, "sdcard1_size") == 0) + pic32->sdcard1_size = strtoul (value, 0, 0); + else if (strcmp (param, "sdcard0_file_name") == 0) + pic32->sdcard0_file_name = strdup (value); + else if (strcmp (param, "sdcard1_file_name") == 0) + pic32->sdcard1_file_name = strdup (value); + else if (strcmp (param, "uart1_type") == 0) + uart_type[0] = strdup (value); + else if (strcmp (param, "uart2_type") == 0) + uart_type[1] = strdup (value); + else if (strcmp (param, "uart3_type") == 0) + uart_type[2] = strdup (value); + else if (strcmp (param, "uart4_type") == 0) + uart_type[3] = strdup (value); + else if (strcmp (param, "uart5_type") == 0) + uart_type[4] = strdup (value); + else if (strcmp (param, "uart6_type") == 0) + uart_type[5] = strdup (value); + else if (strcmp (param, "uart1_port") == 0) + uart_port[0] = strdup (value); + else if (strcmp (param, "uart2_port") == 0) + uart_port[1] = strdup (value); + else if (strcmp (param, "uart3_port") == 0) + uart_port[2] = strdup (value); + else if (strcmp (param, "uart4_port") == 0) + uart_port[3] = strdup (value); + else if (strcmp (param, "uart5_port") == 0) + uart_port[4] = strdup (value); + else if (strcmp (param, "uart6_port") == 0) + uart_port[5] = strdup (value); + else { + fprintf (stderr, "%s: unknown parameter `%s'\n", vm->configure_filename, param); + exit (-1); + } + //printf ("Configure: %s = '%s'\n", param, value); +} + +static void pic32_parse_configure (pic32_t *pic32) +{ + vm_instance_t *vm = pic32->vm; + int i; + + conf_parse (vm->configure_filename, configure_parameter, pic32); + if (start_address) + pic32->start_address = strtoul (start_address, 0, 0); + if (trace_address) + vm->trace_address = strtoul (trace_address, 0, 0); + for (i=0; ivtty_type[i] = VTTY_TYPE_TERM; + else if (strcmp (uart_type[i], "tcp") == 0) + vm->vtty_type[i] = VTTY_TYPE_TCP; + else if (strcmp (uart_type[i], "none") == 0) + vm->vtty_type[i] = VTTY_TYPE_NONE; + else { + printf ("Unknown option: uart%d_type = %s\n", + i+1, uart_type[i]); + continue; + } + if (uart_port[i]) { + vm->vtty_tcp_port[i] = strtoul (uart_port[i], 0, 0); + } else if (vm->vtty_type[i] == VTTY_TYPE_TCP) { + vm->vtty_tcp_port[i] = 2300 + i; + } + } + + ASSERT(vm->ram_size != 0, "ram_size can not be 0\n"); + if (vm->flash_type == FLASH_TYPE_NOR_FLASH) { + if (vm->flash_size != 0) { + /*ASSERT(vm->flash_filename!=NULL, "flash_file_name can not be NULL\n");*/ + /* flash_filename can be null. virtualmips will create it. */ + ASSERT(vm->flash_address != 0, "flash_address can not be 0\n"); + } + } else if (vm->flash_type == FLASH_TYPE_NAND_FLASH) { + ASSERT(vm->flash_size == 0x400, "flash_size should be 0x400.\n We only support 1G byte NAND flash emulation\n"); + assert(1); + } else + ASSERT(0, "error flash_type. valid value: 1:NOR FLASH 2:NAND FLASH\n"); + + ASSERT(vm->boot_method != 0, "boot_method can not be 0\n 1:binary 2:elf \n"); + + if (vm->boot_method == BOOT_BINARY) { + /* boot from binary image */ + ASSERT(vm->boot_from != 0, "boot_from can not be 0\n 1:NOR FLASH 2:NAND FLASH\n"); + if (vm->boot_from==BOOT_FROM_NOR_FLASH) { + ASSERT(vm->flash_type == FLASH_TYPE_NOR_FLASH, "flash_type must be 1(NOR FLASH)\n"); + ASSERT(vm->flash_size != 0, "flash_size can not be 0\n"); + ASSERT(vm->flash_filename != NULL, "flash_filename can not be NULL\n"); + ASSERT(vm->flash_address != 0, "flash_address can not be 0\n"); + } else if (vm->boot_from == BOOT_FROM_NAND_FLASH) { + ASSERT(vm->flash_type == FLASH_TYPE_NAND_FLASH, "flash_type must be 2(NAND FLASH)\n"); + ASSERT(vm->flash_size != 0, "flash_size can not be 0\n"); + /*ASSERT(vm->flash_filename!=NULL,"flash_filename can not be NULL\n");*/ + } else + ASSERT(0, "error boot_from. valid value: 1:NOR FLASH 2:NAND FLASH\n"); + } else if (vm->boot_method == BOOT_ELF) { + ASSERT(vm->kernel_filename!=0,"kernel_file_name can not be NULL\n "); + } else + ASSERT(0, "error boot_method. valid value: 1:binary 2:elf \n"); + + /* Add other configure information validation here */ + if (vm->jit_use) { + ASSERT (JIT_SUPPORT == 1, + "You must compile with JIT Support to use jit.\n"); + } + + /* Print the configure information */ + printf("Using configure file: %s\n", vm->configure_filename); + printf("ram_size: %dk bytes \n", vm->ram_size); + printf("boot_method: %s \n", boot_method_string[vm->boot_method-1]); + if (vm->flash_size != 0) { + printf("flash_type: %s \n",flash_type_string[vm->flash_type-1]); + printf("flash_size: %dk bytes \n",vm->flash_size); + if (vm->flash_type == FLASH_TYPE_NOR_FLASH) { + printf("flash_file_name: %s \n",vm->flash_filename); + printf("flash_phy_address: 0x%x \n",vm->flash_address); + } + } + if (vm->boot_method == BOOT_BINARY) { + printf("boot_from: %s \n",boot_from_string[vm->boot_from-1]); + } + if (vm->boot_method == BOOT_ELF) { + printf("kernel_file_name: %s \n",vm->kernel_filename); + } + + if (vm->gdb_debug != 0) { + printf("GDB debug enable\n"); + printf("GDB port: %d \n",vm->gdb_port); + } + + /* print other configure information here */ + if (pic32->boot_flash_size > 0) { + printf ("boot_flash_size: %dk bytes\n", pic32->boot_flash_size); + printf ("boot_flash_address: 0x%x\n", pic32->boot_flash_address); + printf ("boot_file_name: %s\n", pic32->boot_file_name); + } + if (pic32->sdcard_port) { + printf ("sdcard_port: SPI%d\n", pic32->sdcard_port); + } + if (pic32->sdcard0_size > 0) { + printf ("sdcard0_size: %dM bytes\n", pic32->sdcard0_size); + printf ("sdcard0_file_name: %s\n", pic32->sdcard0_file_name); + } + if (pic32->sdcard1_size > 0) { + printf ("sdcard1_size: %dM bytes\n", pic32->sdcard1_size); + printf ("sdcard1_file_name: %s\n", pic32->sdcard1_file_name); + } + + printf ("start_address: 0x%x\n", pic32->start_address); + if (vm->trace_address != 0) + printf ("trace_address: 0x%x\n", vm->trace_address); + for (i=0; ivtty_type[i] != VTTY_TYPE_NONE) + printf ("uart%d_type = %s\n", i+1, + vm->vtty_type[i] == VTTY_TYPE_TERM ? "console" : + vm->vtty_type[i] == VTTY_TYPE_TCP ? "tcp" : "???"); + if (vm->vtty_tcp_port[i]) + printf ("uart%d_type = %u\n", i+1, + vm->vtty_tcp_port[i]); + } +} + +/* + * Create an instance of virtual machine. + */ +vm_instance_t *create_instance (char *configure_filename) +{ + vm_instance_t *vm; + pic32_t *pic32; + const char *name = "pic32"; + int i; + + pic32 = malloc (sizeof (*pic32)); + if (! pic32) { + fprintf (stderr, "PIC32: unable to create new instance!\n"); + return NULL; + } + memset (pic32, 0, sizeof (*pic32)); + + vm = vm_create (name, VM_TYPE_PIC32); + if (! vm) { + fprintf (stderr, "PIC32: unable to create VM instance!\n"); + free (pic32); + return NULL; + } + vm->hw_data = pic32; + pic32->vm = vm; + vm->vtty_type[0] = VTTY_TYPE_TERM; + for (i=1; ivtty_type[i] = VTTY_TYPE_NONE; + + /* Initialize default parameters for pic32 */ + if (configure_filename == NULL) +#ifdef UBW32 + configure_filename = "pic32_ubw32.conf"; +#elif defined EXPLORER16 + configure_filename = "pic32_explorer16.conf"; +#elif defined MAXIMITE + configure_filename = "pic32_maximite.conf"; +#elif defined MAX32 + configure_filename = "pic32_max32.conf"; +#endif + vm->configure_filename = strdup (configure_filename); + vm->ram_size = 128; /* kilobytes */ + vm->boot_method = BOOT_BINARY; + vm->boot_from = BOOT_FROM_NOR_FLASH; + vm->flash_type = FLASH_TYPE_NOR_FLASH; + + pic32_parse_configure (pic32); + + /* init gdb debug */ + vm_debug_init (pic32->vm); + + return pic32->vm; +} + +int init_instance (vm_instance_t * vm) +{ + pic32_t *pic32 = (pic32_t *) vm->hw_data; + cpu_mips_t *cpu; + + if (pic32_init_platform (pic32) == -1) { + vm_error (vm, "unable to initialize the platform hardware.\n"); + return (-1); + } + if (! vm->boot_cpu) { + vm_error (vm, "unable to boot cpu.\n"); + return (-1); + } + + /* IRQ routing */ + vm->set_irq = pic32_set_irq; + vm->clear_irq = pic32_clear_irq; + + vm_suspend (vm); + + /* Check that CPU activity is really suspended */ + if (cpu_group_sync_state (vm->cpu_group) == -1) { + vm_error (vm, "unable to sync with system CPUs.\n"); + return (-1); + } + + /* Reset the boot CPU */ + cpu = vm->boot_cpu; + mips_reset (cpu); + + /* Set config0-config3 registers. */ + cpu->cp0.config_usable = 0x0f; + cpu->cp0.config_reg[0] = 0xa4010582; + cpu->cp0.config_reg[1] = 0x80000004; + cpu->cp0.config_reg[2] = 0x80000000; + cpu->cp0.config_reg[3] = 0x00000060; + + /* set PC and PRID */ + cpu->cp0.reg[MIPS_CP0_PRID] = 0x00ff8700; /* TODO */ + cpu->cp0.tlb_entries = 0; + cpu->pc = pic32->start_address; + + /* reset all devices */ + dev_reset_all (vm); + dev_sdcard_reset (cpu); + +#ifdef _USE_JIT_ + /* if jit is used. flush all jit buffer */ + if (vm->jit_use) + mips_jit_flush (cpu, 0); +#endif + + /* Launch the simulation */ + printf ("--- Start simulation: PC=0x%" LL "x, JIT %sabled\n", + cpu->pc, vm->jit_use ? "en" : "dis"); + vm->status = VM_STATUS_RUNNING; + cpu_start (vm->boot_cpu); + return (0); +} diff --git a/tools/virtualmips/pic32.h b/tools/virtualmips/pic32.h new file mode 100644 index 0000000..3e3a5fe --- /dev/null +++ b/tools/virtualmips/pic32.h @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2011 Serge Vakulenko + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + */ +#ifndef __PIC32_H__ +#define __PIC32_H__ + +#include "types.h" +#include "pic32mx.h" +#include "dev_sdcard.h" +#include "dev_swap.h" + +#define DATA_WIDTH 32 /* MIPS32 architecture */ +#define LL /* empty - printf format for machine word */ + +/* + * Data types + */ +typedef m_uint32_t m_va_t; +typedef m_uint32_t m_pa_t; +typedef m_uint32_t m_reg_t; +typedef m_int32_t m_ireg_t; +typedef m_uint32_t m_cp0_reg_t; + +/*Guest endian*/ +#define GUEST_BYTE_ORDER ARCH_LITTLE_ENDIAN + +/* Host to VM conversion functions */ +#if HOST_BYTE_ORDER == GUEST_BYTE_ORDER +#define htovm16(x) (x) +#define htovm32(x) (x) +#define htovm64(x) (x) + +#define vmtoh16(x) (x) +#define vmtoh32(x) (x) +#define vmtoh64(x) (x) +#else //host:big guest:little + +#define htovm16(x) (ntohs(x)) +#define htovm32(x) (ntohl(x)) +#define htovm64(x) (swap64(x)) + +#define vmtoh16(x) (htons(x)) +#define vmtoh32(x) (htonl(x)) +#define vmtoh64(x) (swap64(x)) +#endif + +struct pic32_system { + /* Associated VM instance */ + vm_instance_t *vm; + + unsigned start_address; /* jump here on reset */ + unsigned boot_flash_size; /* size of boot flash in kbytes */ + unsigned boot_flash_address; /* physical address of boot flash */ + char *boot_file_name; /* image of boot flash */ + + unsigned sdcard_port; /* SPI port number */ + unsigned sdcard0_size; /* size of SD card 0 in Mbytes */ + unsigned sdcard1_size; /* size of SD card 1 in Mbytes */ + char *sdcard0_file_name; /* image of SD card 0 */ + char *sdcard1_file_name; /* image of SD card 1 */ + sdcard_t sdcard [2]; /* max number of sdcards */ + + swap_t swap; /* swap device */ + + struct vdevice *intdev; /* interrupt controller */ + unsigned intcon; /* interrupt control */ + unsigned intstat; /* interrupt status */ + unsigned iptmr; /* temporal proximity */ + unsigned ifs[3]; /* interrupt flag status */ + unsigned iec[3]; /* interrupt enable control */ + unsigned ipc[12]; /* interrupt priority control */ + unsigned ivprio[64]; /* priority of interrupt vectors */ + + struct vdevice *timer1; /* timer 1 */ + struct vdevice *timer2; /* timer 2 */ + struct vdevice *timer3; /* timer 3 */ + struct vdevice *timer4; /* timer 4 */ + struct vdevice *timer5; /* timer 5 */ + + struct vdevice *bmxdev; /* memory controller */ + unsigned bmxcon; /* memory control */ + unsigned bmx_ram_kpba; /* RAM kernel program base address */ + unsigned bmx_ram_udba; /* RAM user data base address */ + unsigned bmx_ram_upba; /* RAM user program base address */ + unsigned bmx_flash_upba; /* Flash user program base address */ + + struct vdevice *rtcdev; /* RTCC controller */ + unsigned rtccon; /* RTC control */ + + struct vdevice *dmadev; /* DMA controller */ + unsigned dmacon; /* DMA control */ + unsigned dmastat; /* DMA status */ + unsigned dmaaddr; /* DMA address */ + + struct vdevice *sysdev; /* System controller */ + unsigned osccon; + unsigned osctun; + unsigned ddpcon; /* Debug data port control */ + unsigned devid; /* Device identifier */ + unsigned syskey; + unsigned rcon; + unsigned rswrst; + + unsigned ad1con1; /* Analog to digital converter */ + unsigned ad1con2; + unsigned ad1con3; + unsigned ad1chs; + unsigned ad1cssl; + unsigned ad1pcfg; + + struct vdevice *cfgdev; /* Device configuration */ + unsigned devcfg3; + unsigned devcfg2; + unsigned devcfg1; + unsigned devcfg0; + + struct vdevice *prefetch; /* Prefetch cache controller */ + unsigned checon; +}; + +typedef struct pic32_system pic32_t; +struct virtual_tty; + +vm_instance_t *create_instance (char *conf); +int init_instance (vm_instance_t *vm); +int pic32_reset (vm_instance_t *vm); +void pic32_update_irq_flag (pic32_t *pic32); +void pic32_set_irq (vm_instance_t *vm, unsigned irq); +void pic32_clear_irq (vm_instance_t *vm, unsigned irq); +int dev_pic32_flash_init (vm_instance_t *vm, char *name, + unsigned flash_kbytes, unsigned flash_address, char *filename); +int dev_pic32_uart_init (vm_instance_t *vm, char *name, unsigned paddr, + unsigned irq, struct virtual_tty *vtty); +int dev_pic32_intcon_init (vm_instance_t *vm, char *name, unsigned paddr); +int dev_pic32_dmacon_init (vm_instance_t *vm, char *name, unsigned paddr); +int dev_pic32_syscon_init (vm_instance_t *vm, char *name, unsigned paddr); +int dev_pic32_adc_init (vm_instance_t *vm, char *name, unsigned paddr); +int dev_pic32_prefetch_init (vm_instance_t *vm, char *name, unsigned paddr); +int dev_pic32_bmxcon_init (vm_instance_t *vm, char *name, unsigned paddr); +int dev_pic32_rtcc_init (vm_instance_t *vm, char *name, unsigned paddr); +int dev_pic32_spi_init (vm_instance_t *vm, char *name, unsigned paddr, + unsigned irq); +struct vdevice *dev_pic32_timer_init (vm_instance_t *vm, char *name, + unsigned paddr, unsigned irq); +int dev_pic32_gpio_init (vm_instance_t *vm, char *name, unsigned paddr); +int dev_pic32_devcfg_init (vm_instance_t *vm, char *name, unsigned paddr); +void dev_pic32_timer_tick (cpu_mips_t *cpu, struct vdevice *dev, unsigned nclocks); +void dumpregs (cpu_mips_t *cpu); + +#endif diff --git a/tools/virtualmips/pic32_dev_adc.c b/tools/virtualmips/pic32_dev_adc.c new file mode 100644 index 0000000..4c21088 --- /dev/null +++ b/tools/virtualmips/pic32_dev_adc.c @@ -0,0 +1,157 @@ +/* + * System controller for PIC32. + * + * Copyright (C) 2011 Serge Vakulenko + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + */ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include + +#include "device.h" +#include "mips_memory.h" +#include "cpu.h" +#include "pic32.h" + +#define ADC_REG_SIZE 0x170 + +extern cpu_mips_t *current_cpu; + +/* + * Perform an assign/clear/set/invert operation. + */ +static inline unsigned write_op (a, b, op) +{ + switch (op & 0xc) { + case 0x0: /* Assign */ + a = b; + break; + case 0x4: /* Clear */ + a &= ~b; + break; + case 0x8: /* Set */ + a |= b; + break; + case 0xc: /* Invert */ + a ^= b; + break; + } + return a; +} + +void *dev_pic32_adc_access (cpu_mips_t *cpu, struct vdevice *dev, + m_uint32_t offset, u_int op_size, u_int op_type, m_reg_t *data, + m_uint8_t *has_set_value) +{ + pic32_t *pic32 = dev->priv_data; + + if (offset >= ADC_REG_SIZE) { + *data = 0; + return NULL; + } + if (op_type == MTS_READ) + *data = 0; + switch (offset & 0xff0) { + case PIC32_AD1CON1 & 0xff0: /* Control register 1 */ + if (op_type == MTS_READ) { + *data = pic32->ad1con1; + } else { + pic32->ad1con1 = write_op (pic32->ad1con1, *data, offset); + } + break; + + case PIC32_AD1CON2 & 0xff0: /* Control register 2 */ + if (op_type == MTS_READ) { + *data = pic32->ad1con2; + } else { + pic32->ad1con2 = write_op (pic32->ad1con2, *data, offset); + } + break; + + case PIC32_AD1CON3 & 0xff0: /* Control register 3 */ + if (op_type == MTS_READ) { + *data = pic32->ad1con3; + } else { + pic32->ad1con3 = write_op (pic32->ad1con3, *data, offset); + } + break; + + case PIC32_AD1CHS & 0xff0: /* Channel select */ + if (op_type == MTS_READ) { + *data = pic32->ad1chs; + } else { + pic32->ad1chs = write_op (pic32->ad1chs, *data, offset); + } + break; + + case PIC32_AD1CSSL & 0xff0: /* Input scan selection */ + if (op_type == MTS_READ) { + *data = pic32->ad1cssl; + } else { + pic32->ad1cssl = write_op (pic32->ad1cssl, *data, offset); + } + break; + + case PIC32_AD1PCFG & 0xff0: /* Port configuration */ + if (op_type == MTS_READ) { + *data = pic32->ad1pcfg; + } else { + pic32->ad1pcfg = write_op (pic32->ad1pcfg, *data, offset); + } + break; + + case PIC32_ADC1BUF0 & 0xff0: case PIC32_ADC1BUF1 & 0xff0: + case PIC32_ADC1BUF2 & 0xff0: case PIC32_ADC1BUF3 & 0xff0: + case PIC32_ADC1BUF4 & 0xff0: case PIC32_ADC1BUF5 & 0xff0: + case PIC32_ADC1BUF6 & 0xff0: case PIC32_ADC1BUF7 & 0xff0: + case PIC32_ADC1BUF8 & 0xff0: case PIC32_ADC1BUF9 & 0xff0: + case PIC32_ADC1BUFA & 0xff0: case PIC32_ADC1BUFB & 0xff0: + case PIC32_ADC1BUFC & 0xff0: case PIC32_ADC1BUFD & 0xff0: + case PIC32_ADC1BUFE & 0xff0: case PIC32_ADC1BUFF & 0xff0: + if (op_type == MTS_READ) { /* Result words */ + *data = 0; // TODO + } + break; + + default: + ASSERT (0, "unknown adc offset %x\n", offset); + } + *has_set_value = TRUE; + return NULL; +} + +void dev_pic32_adc_reset (cpu_mips_t *cpu, struct vdevice *dev) +{ + pic32_t *pic32 = dev->priv_data; + + pic32->ad1con1 = 0; + pic32->ad1con2 = 0; + pic32->ad1con3 = 0; + pic32->ad1chs = 0; + pic32->ad1cssl = 0; + pic32->ad1pcfg = 0; +} + +int dev_pic32_adc_init (vm_instance_t *vm, char *name, unsigned paddr) +{ + pic32_t *pic32 = (pic32_t *) vm->hw_data; + + pic32->sysdev = dev_create (name); + if (! pic32->sysdev) + return (-1); + pic32->sysdev->priv_data = pic32; + pic32->sysdev->phys_addr = paddr; + pic32->sysdev->phys_len = ADC_REG_SIZE; + pic32->sysdev->handler = dev_pic32_adc_access; + pic32->sysdev->reset_handler = dev_pic32_adc_reset; + pic32->sysdev->flags = VDEVICE_FLAG_NO_MTS_MMAP; + + vm_bind_device (vm, pic32->sysdev); + return (0); +} diff --git a/tools/virtualmips/pic32_dev_bmxcon.c b/tools/virtualmips/pic32_dev_bmxcon.c new file mode 100644 index 0000000..20f6052 --- /dev/null +++ b/tools/virtualmips/pic32_dev_bmxcon.c @@ -0,0 +1,157 @@ +/* + * Interrupt controller for PIC32. + * + * Copyright (C) 2011 Serge Vakulenko + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + */ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include + +#include "device.h" +#include "mips_memory.h" +#include "cpu.h" +#include "pic32.h" + +#define BMXCON_REG_SIZE 0x80 + +extern cpu_mips_t *current_cpu; + +/* + * Perform an assign/clear/set/invert operation. + */ +static inline unsigned write_op (a, b, op) +{ + switch (op & 0xc) { + case 0x0: /* Assign */ + a = b; + break; + case 0x4: /* Clear */ + a &= ~b; + break; + case 0x8: /* Set */ + a |= b; + break; + case 0xc: /* Invert */ + a ^= b; + break; + } + return a; +} + +void *dev_pic32_bmxcon_access (cpu_mips_t *cpu, struct vdevice *dev, + m_uint32_t offset, u_int op_size, u_int op_type, m_reg_t *data, + m_uint8_t *has_set_value) +{ + pic32_t *pic32 = dev->priv_data; + + if (offset >= BMXCON_REG_SIZE) { + *data = 0; + return NULL; + } + if (op_type == MTS_READ) + *data = 0; + switch (offset & 0x1f0) { + case PIC32_BMXCON & 0x1f0: /* Interrupt Control */ + if (op_type == MTS_READ) { + *data = pic32->bmxcon; + if (cpu->vm->debug_level > 2) + printf (" read BMXCON -> %08x\n", *data); + } else { + pic32->bmxcon = write_op (pic32->bmxcon, *data, offset); + if (cpu->vm->debug_level > 2) + printf (" BMXCON := %08x\n", pic32->bmxcon); + } + break; + + case PIC32_BMXDKPBA & 0x1f0: /* Data RAM kernel program base address */ + if (op_type == MTS_READ) { + *data = pic32->bmx_ram_kpba; + } else { + pic32->bmx_ram_kpba = write_op (pic32->bmx_ram_kpba, *data, offset); + } + break; + + case PIC32_BMXDUDBA & 0x1f0: /* Data RAM user data base address */ + if (op_type == MTS_READ) { + *data = pic32->bmx_ram_udba; + } else { + pic32->bmx_ram_udba = write_op (pic32->bmx_ram_udba, *data, offset); + } + break; + + case PIC32_BMXDUPBA & 0x1f0: /* Data RAM user program base address */ + if (op_type == MTS_READ) { + *data = pic32->bmx_ram_upba; + } else { + pic32->bmx_ram_upba = write_op (pic32->bmx_ram_upba, *data, offset); + } + break; + + case PIC32_BMXPUPBA & 0x1f0: /* Program Flash user program base address */ + if (op_type == MTS_READ) { + *data = pic32->bmx_flash_upba; + } else { + pic32->bmx_flash_upba = write_op (pic32->bmx_flash_upba, *data, offset); + } + break; + + case PIC32_BMXDRMSZ & 0x1f0: /* Data RAM memory size */ + if (op_type == MTS_READ) { + *data = cpu->vm->ram_size * 1024; + } + break; + + case PIC32_BMXPFMSZ & 0x1f0: /* Program Flash memory size */ + if (op_type == MTS_READ) { + *data = cpu->vm->flash_size * 1024; + } + break; + + case PIC32_BMXBOOTSZ & 0x1f0: /* Boot Flash size */ + if (op_type == MTS_READ) { + *data = pic32->boot_flash_size * 1024; + } + break; + + default: + ASSERT (0, "unknown bmxcon offset %x\n", offset); + } + *has_set_value = TRUE; + return NULL; +} + +void dev_pic32_bmxcon_reset (cpu_mips_t *cpu, struct vdevice *dev) +{ + pic32_t *pic32 = dev->priv_data; + + pic32->bmxcon = 0x001f0041; + pic32->bmx_ram_kpba = 0; + pic32->bmx_ram_udba = 0; + pic32->bmx_ram_upba = 0; + pic32->bmx_flash_upba = 0; +} + +int dev_pic32_bmxcon_init (vm_instance_t *vm, char *name, unsigned paddr) +{ + pic32_t *pic32 = (pic32_t *) vm->hw_data; + + pic32->bmxdev = dev_create (name); + if (! pic32->bmxdev) + return (-1); + pic32->bmxdev->priv_data = pic32; + pic32->bmxdev->phys_addr = paddr; + pic32->bmxdev->phys_len = BMXCON_REG_SIZE; + pic32->bmxdev->handler = dev_pic32_bmxcon_access; + pic32->bmxdev->reset_handler = dev_pic32_bmxcon_reset; + pic32->bmxdev->flags = VDEVICE_FLAG_NO_MTS_MMAP; + + vm_bind_device (vm, pic32->bmxdev); + return (0); +} diff --git a/tools/virtualmips/pic32_dev_devcfg.c b/tools/virtualmips/pic32_dev_devcfg.c new file mode 100644 index 0000000..1fd5ad1 --- /dev/null +++ b/tools/virtualmips/pic32_dev_devcfg.c @@ -0,0 +1,101 @@ +/* + * Device configuration registers for PIC32. + * + * Copyright (C) 2012 Serge Vakulenko + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + */ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include + +#include "device.h" +#include "mips_memory.h" +#include "cpu.h" +#include "pic32.h" + +#define DEVCFG_REG_SIZE 0x100 + +void *dev_pic32_devcfg_access (cpu_mips_t *cpu, struct vdevice *dev, + m_uint32_t offset, u_int op_size, u_int op_type, m_reg_t *data, + m_uint8_t *has_set_value) +{ + pic32_t *pic32 = dev->priv_data; + + if (offset >= DEVCFG_REG_SIZE) { + *data = 0; + return NULL; + } + if (op_type == MTS_READ) + *data = 0; + switch (offset & 0xfc) { + case 0xf0: /* DEVCFG3 */ + if (op_type == MTS_READ) { + *data = pic32->devcfg3; + if (cpu->vm->debug_level > 2) + printf (" read DEVCFG3 -> %08x\n", *data); + } + break; + case 0xf4: /* DEVCFG2 */ + if (op_type == MTS_READ) { + *data = pic32->devcfg2; + if (cpu->vm->debug_level > 2) + printf (" read DEVCFG3 -> %08x\n", *data); + } + break; + case 0xf8: /* DEVCFG1 */ + if (op_type == MTS_READ) { + *data = pic32->devcfg1; + if (cpu->vm->debug_level > 2) + printf (" read DEVCFG3 -> %08x\n", *data); + } + break; + case 0xfc: /* DEVCFG0 */ + if (op_type == MTS_READ) { + *data = pic32->devcfg0; + if (cpu->vm->debug_level > 2) + printf (" read DEVCFG3 -> %08x\n", *data); + } + break; + + // TODO: other registers. + + default: + ASSERT (0, "unknown devcfg offset %x\n", offset); + } + *has_set_value = TRUE; + return NULL; +} + +void dev_pic32_devcfg_reset (cpu_mips_t *cpu, struct vdevice *dev) +{ + pic32_t *pic32 = dev->priv_data; + + pic32->devcfg3 = 0xffff0722; // From Max32 bootloader + pic32->devcfg2 = 0xd979f8f9; + pic32->devcfg1 = 0x5bfd6aff; + pic32->devcfg0 = 0xffffff7f; +} + +int dev_pic32_devcfg_init (vm_instance_t *vm, char *name, unsigned paddr) +{ + pic32_t *pic32 = (pic32_t *) vm->hw_data; + + pic32->cfgdev = dev_create (name); + if (! pic32->cfgdev) + return (-1); + pic32->cfgdev->priv_data = pic32; + pic32->cfgdev->phys_addr = paddr; + pic32->cfgdev->phys_len = DEVCFG_REG_SIZE; + pic32->cfgdev->handler = dev_pic32_devcfg_access; + pic32->cfgdev->reset_handler = dev_pic32_devcfg_reset; + pic32->cfgdev->flags = VDEVICE_FLAG_NO_MTS_MMAP; + + vm_bind_device (vm, pic32->cfgdev); + return (0); +} diff --git a/tools/virtualmips/pic32_dev_dmacon.c b/tools/virtualmips/pic32_dev_dmacon.c new file mode 100644 index 0000000..cb52404 --- /dev/null +++ b/tools/virtualmips/pic32_dev_dmacon.c @@ -0,0 +1,127 @@ +/* + * DMA controller for PIC32. + * + * Copyright (C) 2011 Serge Vakulenko + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + */ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include + +#include "device.h" +#include "mips_memory.h" +#include "cpu.h" +#include "pic32.h" + +#define DMACON_REG_SIZE 0x660 + +extern cpu_mips_t *current_cpu; + +/* + * Perform an assign/clear/set/invert operation. + */ +static inline unsigned write_op (a, b, op) +{ + switch (op & 0xc) { + case 0x0: /* Assign */ + a = b; + break; + case 0x4: /* Clear */ + a &= ~b; + break; + case 0x8: /* Set */ + a |= b; + break; + case 0xc: /* Invert */ + a ^= b; + break; + } + return a; +} + +void *dev_pic32_dmacon_access (cpu_mips_t *cpu, struct vdevice *dev, + m_uint32_t offset, u_int op_size, u_int op_type, m_reg_t *data, + m_uint8_t *has_set_value) +{ + pic32_t *pic32 = dev->priv_data; + + if (offset >= DMACON_REG_SIZE) { + *data = 0; + return NULL; + } + if (op_type == MTS_READ) + *data = 0; + switch (offset & 0x1f0) { + case PIC32_DMACON & 0x1f0: /* DMA Control */ + if (op_type == MTS_READ) { + *data = pic32->dmacon; + if (cpu->vm->debug_level > 2) + printf (" read DMACON -> %08x\n", *data); + } else { + pic32->dmacon = write_op (pic32->dmacon, *data, offset); + if (cpu->vm->debug_level > 2) + printf (" DMACON := %08x\n", pic32->dmacon); + } + break; + + case PIC32_DMASTAT: /* DMA Status */ + if (op_type == MTS_READ) { + *data = pic32->dmastat; + if (cpu->vm->debug_level > 2) + printf (" read DMASTAT -> %08x\n", *data); + } + break; + + case PIC32_DMAADDR: /* DMA address */ + if (op_type == MTS_READ) { + *data = pic32->dmaaddr; + if (cpu->vm->debug_level > 2) + printf (" read DMAADDR -> %08x\n", *data); + } else { + pic32->dmaaddr = *data; + if (cpu->vm->debug_level > 2) + printf (" DMAADDR := %08x\n", *data); + } + break; + + // TODO: other registers. + + default: + ASSERT (0, "unknown dmacon offset %x\n", offset); + } + *has_set_value = TRUE; + return NULL; +} + +void dev_pic32_dmacon_reset (cpu_mips_t *cpu, struct vdevice *dev) +{ + pic32_t *pic32 = dev->priv_data; + + pic32->dmacon = 0; + pic32->dmastat = 0; + pic32->dmaaddr = 0; +} + +int dev_pic32_dmacon_init (vm_instance_t *vm, char *name, unsigned paddr) +{ + pic32_t *pic32 = (pic32_t *) vm->hw_data; + + pic32->dmadev = dev_create (name); + if (! pic32->dmadev) + return (-1); + pic32->dmadev->priv_data = pic32; + pic32->dmadev->phys_addr = paddr; + pic32->dmadev->phys_len = DMACON_REG_SIZE; + pic32->dmadev->handler = dev_pic32_dmacon_access; + pic32->dmadev->reset_handler = dev_pic32_dmacon_reset; + pic32->dmadev->flags = VDEVICE_FLAG_NO_MTS_MMAP; + + vm_bind_device (vm, pic32->dmadev); + return (0); +} diff --git a/tools/virtualmips/pic32_dev_flash.c b/tools/virtualmips/pic32_dev_flash.c new file mode 100644 index 0000000..f0c2142 --- /dev/null +++ b/tools/virtualmips/pic32_dev_flash.c @@ -0,0 +1,137 @@ +/* + * Internal Flash memory of PIC32 microcontroller. + + * Copyright (C) 2011 Serge Vakulenko + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + */ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "device.h" +#include "mips_memory.h" +#include "pic32.h" + +/* flash private data */ +typedef struct flash_data { + struct vdevice *dev; + m_uint8_t *flash_ptr; + m_uint32_t flash_size; + m_uint8_t *flash_file_name; +} flash_data_t; + +void *dev_flash_access (cpu_mips_t * cpu, struct vdevice *dev, + m_uint32_t offset, u_int op_size, u_int op_type, + m_uint32_t * data, m_uint8_t * has_set_value) +{ + flash_data_t *d = dev->priv_data; + + if (offset >= d->flash_size) { + printf ("-- flash: access %08x -- out of memory\n", dev->phys_addr + offset); + *data = 0xff; + *has_set_value = TRUE; + return NULL; + } + if (op_type == MTS_READ) { +#if 0 + printf ("-- flash: read %08x -> %08x\n", dev->phys_addr + offset, + *(unsigned *) (d->flash_ptr + offset)); +#endif + return d->flash_ptr + offset; + } + if (op_type == MTS_WRITE) { + printf ("-- flash: write %08x ***\n", dev->phys_addr + offset); + return NULL; + } + assert (0); +} + +static int dev_flash_load (char *flash_file_name, unsigned flash_len, + unsigned char **flash_data_hp) +{ + int fd; + struct stat sb; + + fd = open (flash_file_name, O_RDONLY); + if (fd < 0) { + fprintf (stderr, "%s does not exist.\n", flash_file_name); + return (-1); + } + fstat (fd, &sb); + if (flash_len < sb.st_size) { + fprintf (stderr, + "Too large flash file.\nFlash len: %d kbytes, file name %s, " + "file legth: %d bytes.\n", flash_len / 1024, flash_file_name, + (int) sb.st_size); + return (-1); + } + if (sb.st_size <= 0) { + fprintf (stderr, "%s: empty flash file.\n", flash_file_name); + return (-1); + } + *flash_data_hp = mmap (NULL, sb.st_size, PROT_READ, MAP_SHARED, fd, 0); + if (*flash_data_hp == MAP_FAILED) { + fprintf (stderr, "%s: ", flash_file_name); + perror ("mmap"); + return (-1); + } + return 0; +} + +static void dev_flash_reset (cpu_mips_t * cpu, struct vdevice *dev) +{ + //flash_data_t *d = dev->priv_data; + + //d->state = 0; +} + +/* + * Initialize a NOR Flash zone + */ +int dev_pic32_flash_init (vm_instance_t * vm, char *name, + unsigned flash_kbytes, unsigned flash_address, char *filename) +{ + flash_data_t *d; + unsigned char *flash_data_hp; + + /* load rom data */ + if (dev_flash_load (filename, flash_kbytes * 1024, &flash_data_hp) < 0) + return (-1); + + /* allocate the private data structure */ + d = malloc (sizeof (*d)); + if (!d) { + fprintf (stderr, "FLASH: unable to create device.\n"); + return (-1); + } + + memset (d, 0, sizeof (*d)); + d->flash_ptr = flash_data_hp; + d->flash_size = flash_kbytes * 1024; + + d->dev = dev_create (name); + if (!d->dev) { + free (d); + return (-1); + } + d->dev->priv_data = d; + d->dev->phys_addr = flash_address; + d->dev->phys_len = flash_kbytes * 1024; + d->dev->handler = dev_flash_access; + d->dev->reset_handler = dev_flash_reset; + d->dev->flags = VDEVICE_FLAG_NO_MTS_MMAP; + + /* Map this device to the VM */ + vm_bind_device (vm, d->dev); + return (0); +} diff --git a/tools/virtualmips/pic32_dev_gpio.c b/tools/virtualmips/pic32_dev_gpio.c new file mode 100644 index 0000000..5ab8887 --- /dev/null +++ b/tools/virtualmips/pic32_dev_gpio.c @@ -0,0 +1,568 @@ +/* + * GPIO emulation for PIC32. + * + * Copyright (C) 2011 Serge Vakulenko + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + */ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include + +#include "device.h" +#include "mips_memory.h" +#include "pic32.h" +#include "cpu.h" +#include "vp_timer.h" + +#define GPIO_REG_SIZE 0x1F0 + +#ifdef UBW32 +#define MASKA_CS0 (1 << 9) // A9: sd0 on SPI1 +#define MASKA_CS1 (1 << 10) // A10: sd1 on SPI1 +#define MASKC_LDADDR (1 << 1) // C1: swap LDADDR +#define MASKE_WR (1 << 9) // E8: swap WR +#define MASKE_RD (1 << 8) // E8: swap RD +#define MASKE_DATA (0xff << 0) // E0-E7: swap DATA +#define SHIFTE_DATA 0 + +#elif defined MAXIMITE +#define MASKE_CS0 (1 << 0) // E0: sd0 on SPI4 +#define MASKE_CS1 // reserved +#define MASKD_PS2C (1 << 6) // PS2 keyboard +#define MASKD_PS2D (1 << 7) + +#elif defined MAX32 +#define MASKD_CS0 (1 << 3) // D3: sd0 on SPI4 +#define MASKD_CS1 (1 << 4) // D4: sd1 on SPI4 + +#elif defined EXPLORER16 +#define MASKB_CS0 (1 << 1) // B1: sd0 on SPI1 +#define MASKB_CS1 (1 << 2) // B2: sd1 on SPI1 +#endif + +struct pic32_gpio_data { + struct vdevice *dev; + vtty_t *vtty; + vm_instance_t *vm; + pic32_t *pic32; + + unsigned tris_a; /* 0x00 - port A mask of inputs */ + unsigned port_a; /* 0x10 - port A pins */ + unsigned lat_a; /* 0x20 - port A latched outputs */ + unsigned odc_a; /* 0x30 - port A open drain configuration */ + + unsigned tris_b; /* 0x40 - port B mask of inputs */ + unsigned port_b; /* 0x50 - port B pins */ + unsigned lat_b; /* 0x60 - port B latched outputs */ + unsigned odc_b; /* 0x70 - port B open drain configuration */ + + unsigned tris_c; /* 0x80 - port C mask of inputs */ + unsigned port_c; /* 0x90 - port C pins */ + unsigned lat_c; /* 0xA0 - port C latched outputs */ + unsigned odc_c; /* 0xB0 - port C open drain configuration */ + + unsigned tris_d; /* 0xC0 - port D mask of inputs */ + unsigned port_d; /* 0xD0 - port D pins */ + unsigned lat_d; /* 0xE0 - port D latched outputs */ + unsigned odc_d; /* 0xF0 - port D open drain configuration */ + + unsigned tris_e; /* 0x00 - port E mask of inputs */ + unsigned port_e; /* 0x10 - port E pins */ + unsigned lat_e; /* 0x20 - port E latched outputs */ + unsigned odc_e; /* 0x30 - port E open drain configuration */ + + unsigned tris_f; /* 0x40 - port F mask of inputs */ + unsigned port_f; /* 0x50 - port F pins */ + unsigned lat_f; /* 0x60 - port F latched outputs */ + unsigned odc_f; /* 0x70 - port F open drain configuration */ + + unsigned tris_g; /* 0x80 - port G mask of inputs */ + unsigned port_g; /* 0x90 - port G pins */ + unsigned lat_g; /* 0xA0 - port G latched outputs */ + unsigned odc_g; /* 0xB0 - port G open drain configuration */ + + unsigned cncon; /* 0xC0 - interrupt-on-change control */ + unsigned cnen; /* 0xD0 - input change interrupt enable */ + unsigned cnpue; /* 0xE0 - input pin pull-up enable */ +}; + +extern cpu_mips_t *current_cpu; + +/* + * Perform an assign/clear/set/invert operation. + */ +static inline unsigned write_op (a, b, op) +{ + switch (op & 0xc) { + case 0x0: /* Assign */ + a = b; + break; + case 0x4: /* Clear */ + a &= ~b; + break; + case 0x8: /* Set */ + a |= b; + break; + case 0xc: /* Invert */ + a ^= b; + break; + } + return a; +} + +void *dev_pic32_gpio_access (cpu_mips_t *cpu, struct vdevice *dev, + m_uint32_t offset, u_int op_size, u_int op_type, + m_reg_t * data, m_uint8_t * has_set_value) +{ + struct pic32_gpio_data *d = dev->priv_data; + + if (offset >= GPIO_REG_SIZE) { + printf ("gpio: overhit\n"); + *data = 0; + return NULL; + } + //printf ("gpio: %s offset %#x\n", (op_type == MTS_READ) ? "read" : "write", offset); + if (op_type == MTS_READ) + *data = 0; + switch (offset & 0x1f0) { + /* + * Port A + */ + case PIC32_TRISA & 0x1f0: /* Port A: mask of inputs */ + if (op_type == MTS_READ) { + *data = d->tris_a; + } else { + d->tris_a = write_op (d->tris_a, *data, offset); + } + break; + + case PIC32_PORTA & 0x1f0: /* Port A: read inputs, write outputs */ + if (op_type == MTS_READ) { + *data = d->port_a; + } else { + goto lat_a; + } + break; + + case PIC32_LATA & 0x1f0: /* Port A: read/write outputs */ + if (op_type == MTS_READ) { + *data = d->lat_a; + } else { +lat_a: d->lat_a = write_op (d->lat_a, *data, offset); +#ifdef UBW32 + /* Control SD card 0 */ + if (d->lat_a & MASKA_CS0) + dev_sdcard_select (cpu, 0, 0); + else + dev_sdcard_select (cpu, 0, 1); + + /* Control SD card 1 */ + if (d->lat_a & MASKA_CS1) + dev_sdcard_select (cpu, 1, 0); + else + dev_sdcard_select (cpu, 1, 1); +#endif + } + break; + + case PIC32_ODCA & 0x1f0: /* Port A: open drain configuration */ + if (op_type == MTS_READ) { + *data = d->odc_a; + } else { + d->odc_a = write_op (d->odc_a, *data, offset); + } + break; + + /* + * Port B + */ + case PIC32_TRISB & 0x1f0: /* Port B: mask of inputs */ + if (op_type == MTS_READ) { + *data = d->tris_b; + } else { + d->tris_b = write_op (d->tris_b, *data, offset); + } + break; + + case PIC32_PORTB & 0x1f0: /* Port B: read inputs, write outputs */ + if (op_type == MTS_READ) { + *data = d->port_b; + } else { + goto lat_b; + } + break; + + case PIC32_LATB & 0x1f0: /* Port B: read/write outputs */ + if (op_type == MTS_READ) { + *data = d->lat_b; + } else { +lat_b: d->lat_b = write_op (d->lat_b, *data, offset); +#ifdef EXPLORER16 + /* Control SD card 0 */ + if (d->lat_b & MASKB_CS0) + dev_sdcard_select (cpu, 0, 0); + else + dev_sdcard_select (cpu, 0, 1); + + /* Control SD card 1 */ + if (d->lat_b & MASKB_CS1) + dev_sdcard_select (cpu, 1, 0); + else + dev_sdcard_select (cpu, 1, 1); +#endif + } + break; + + case PIC32_ODCB & 0x1f0: /* Port B: open drain configuration */ + if (op_type == MTS_READ) { + *data = d->odc_b; + } else { + d->odc_b = write_op (d->odc_b, *data, offset); + } + break; + + /* + * Port C + */ + case PIC32_TRISC & 0x1f0: /* Port C: mask of inputs */ + if (op_type == MTS_READ) { + *data = d->tris_c; + } else { + d->tris_c = write_op (d->tris_c, *data, offset); + } + break; + + case PIC32_PORTC & 0x1f0: /* Port C: read inputs, write outputs */ + if (op_type == MTS_READ) { + *data = d->port_c; + } else { + goto lat_c; + } + break; + + case PIC32_LATC & 0x1f0: /* Port C: read/write outputs */ + if (op_type == MTS_READ) { + *data = d->lat_c; + } else { +lat_c: d->lat_c = write_op (d->lat_c, *data, offset); +#ifdef UBW32 + if (d->lat_c & MASKC_LDADDR) /* Swap disk: LDADDR */ + dev_swap_ldaddr (cpu, 0); + else + dev_swap_ldaddr (cpu, 1); +#endif + } + break; + + case PIC32_ODCC & 0x1f0: /* Port C: open drain configuration */ + if (op_type == MTS_READ) { + *data = d->odc_c; + } else { + d->odc_c = write_op (d->odc_c, *data, offset); + } + break; + + /* + * Port D + */ + case PIC32_TRISD & 0x1f0: /* Port D: mask of inputs */ + if (op_type == MTS_READ) { + *data = d->tris_d; + } else { + d->tris_d = write_op (d->tris_d, *data, offset); + } + break; + + case PIC32_PORTD & 0x1f0: /* Port D: read inputs, write outputs */ +#ifndef MAXIMITE + if (op_type == MTS_READ) { + *data = d->port_d; + } else { + goto lat_d; + } +#else + if (op_type == MTS_READ) { +#if 0 + /* Poll PS2 keyboard */ + if (dev_keyboard_clock (cpu)) + d->port_d &= ~MASKD_PS2C; + else + d->port_d |= MASKD_PS2C; + if (dev_keyboard_data (cpu)) + d->port_d &= ~MASKD_PS2D; + else + d->port_d |= MASKD_PS2D; +#endif + *data = d->port_d; + } else { + goto lat_d; + } +#endif + break; + + case PIC32_LATD & 0x1f0: /* Port D: read/write outputs */ + if (op_type == MTS_READ) { + *data = d->lat_d; + } else { +lat_d: d->lat_d = write_op (d->lat_d, *data, offset); +#ifdef MAX32 + /* Control SD card 0 */ + if (d->lat_d & MASKD_CS0) + dev_sdcard_select (cpu, 0, 0); + else + dev_sdcard_select (cpu, 0, 1); + + /* Control SD card 1 */ + if (d->lat_d & MASKD_CS1) + dev_sdcard_select (cpu, 1, 0); + else + dev_sdcard_select (cpu, 1, 1); +#endif + } + break; + + case PIC32_ODCD & 0x1f0: /* Port D: open drain configuration */ + if (op_type == MTS_READ) { + *data = d->odc_d; + } else { + d->odc_d = write_op (d->odc_d, *data, offset); + } + break; + + /* + * Port E + */ + case PIC32_TRISE & 0x1f0: /* Port E: mask of inputs */ + if (op_type == MTS_READ) { + *data = d->tris_e; + } else { + d->tris_e = write_op (d->tris_e, *data, offset); + } + break; + + case PIC32_PORTE & 0x1f0: /* Port E: read inputs, write outputs */ + if (op_type == MTS_READ) { +#ifdef UBW32 + /* Swap disk: DATA */ + d->port_e &= ~MASKE_DATA; + d->port_e |= dev_swap_io (cpu, 0, 0xff); +#endif + *data = d->port_e; + } else { + goto lat_e; + } + break; + + case PIC32_LATE & 0x1f0: /* Port E: read/write outputs */ + if (op_type == MTS_READ) { + *data = d->lat_e; + } else { +lat_e: d->lat_e = write_op (d->lat_e, *data, offset); +#ifdef MAXIMITE + /* Control SD card 0 */ + if (d->lat_e & MASKE_CS0) + dev_sdcard_select (cpu, 0, 0); + else + dev_sdcard_select (cpu, 0, 1); +#if 0 + /* Control SD card 1 */ + if (d->lat_e & MASKE_CS1) + dev_sdcard_select (cpu, 1, 0); + else + dev_sdcard_select (cpu, 1, 1); +#endif +#endif +#ifdef UBW32 + if (d->lat_e & MASKE_RD) /* Swap disk: RD */ + dev_swap_rd (cpu, 0); + else + dev_swap_rd (cpu, 1); + + if (d->lat_e & MASKE_WR) /* Swap disk: WR */ + dev_swap_wr (cpu, 0); + else + dev_swap_wr (cpu, 1); + + /* Swap disk: DATA */ + dev_swap_io (cpu, d->lat_e >> SHIFTE_DATA, + d->tris_e >> SHIFTE_DATA); +#endif + } + break; + + case PIC32_ODCE & 0x1f0: /* Port E: open drain configuration */ + if (op_type == MTS_READ) { + *data = d->odc_e; + } else { + d->odc_e = write_op (d->odc_e, *data, offset); + } + break; + + /* + * Port F + */ + case PIC32_TRISF & 0x1f0: /* Port F: mask of inputs */ + if (op_type == MTS_READ) { + *data = d->tris_f; + } else { + d->tris_f = write_op (d->tris_f, *data, offset); + } + break; + + case PIC32_PORTF & 0x1f0: /* Port F: read inputs, write outputs */ + if (op_type == MTS_READ) { + *data = d->port_f; + } else { + goto lat_f; + } + break; + + case PIC32_LATF & 0x1f0: /* Port F: read/write outputs */ + if (op_type == MTS_READ) { + *data = d->lat_f; + } else { +lat_f: d->lat_f = write_op (d->lat_f, *data, offset); + } + break; + + case PIC32_ODCF & 0x1f0: /* Port F: open drain configuration */ + if (op_type == MTS_READ) { + *data = d->odc_f; + } else { + d->odc_f = write_op (d->odc_f, *data, offset); + } + break; + + /* + * Port G + */ + case PIC32_TRISG & 0x1f0: /* Port G: mask of inputs */ + if (op_type == MTS_READ) { + *data = d->tris_g; + } else { + d->tris_g = write_op (d->tris_g, *data, offset); + } + break; + + case PIC32_PORTG & 0x1f0: /* Port G: read inputs, write outputs */ + if (op_type == MTS_READ) { + *data = d->port_g; + } else { + goto lat_g; + } + break; + + case PIC32_LATG & 0x1f0: /* Port G: read/write outputs */ + if (op_type == MTS_READ) { + *data = d->lat_g; + } else { +lat_g: d->lat_g = write_op (d->lat_g, *data, offset); + } + break; + + case PIC32_ODCG & 0x1f0: /* Port G: open drain configuration */ + if (op_type == MTS_READ) { + *data = d->odc_g; + } else { + d->odc_g = write_op (d->odc_g, *data, offset); + } + break; + + /* + * Change notifier + */ + case PIC32_CNCON & 0x1f0: /* Interrupt-on-change control */ + if (op_type == MTS_READ) { + *data = d->cncon; + } else { + d->cncon = write_op (d->cncon, *data, offset); + } + break; + + case PIC32_CNEN & 0x1f0: /* Input change interrupt enable */ + if (op_type == MTS_READ) { + *data = d->cnen; + } else { + d->cnen = write_op (d->cnen, *data, offset); + } + break; + + case PIC32_CNPUE & 0x1f0: /* Input pin pull-up enable */ + if (op_type == MTS_READ) { + *data = d->cnpue; + } else { + d->cnpue = write_op (d->cnpue, *data, offset); + } + break; +/* TODO */ +//printf ("%s: read data.\n", dev->name); +/* TODO */ +//printf ("%s: write %02x.\n", dev->name, d->buf); + default: + ASSERT (0, "%s: unknown offset 0x%x\n", dev->name, offset); + } + *has_set_value = TRUE; + return NULL; +} + +void dev_pic32_gpio_reset (cpu_mips_t * cpu, struct vdevice *dev) +{ + struct pic32_gpio_data *d = dev->priv_data; + + /* All pins are inputs. */ + d->tris_a = d->tris_b = d->tris_c = d->tris_d = + d->tris_e = d->tris_f = d->tris_g = 0xFFFF; + + /* All inputs are high. */ + d->port_a = d->port_b = d->port_c = d->port_d = + d->port_e = d->port_f = d->port_g = 0xFFFF; + + /* All outputs are high. */ + d->lat_a = d->lat_b = d->lat_c = d->lat_d = + d->lat_e = d->lat_f = d->lat_g = 0xFFFF; + + /* All open drains are disabled. */ + d->odc_a = d->odc_b = d->odc_c = d->odc_d = + d->odc_e = d->odc_f = d->odc_g = 0; + + /* No interrupts, no pullups. */ + d->cncon = 0; + d->cnen = 0; + d->cnpue = 0; +} + +int dev_pic32_gpio_init (vm_instance_t *vm, char *name, unsigned paddr) +{ + struct pic32_gpio_data *d; + pic32_t *pic32 = (pic32_t *) vm->hw_data; + + /* allocate the private data structure */ + d = malloc (sizeof (*d)); + if (!d) { + fprintf (stderr, "PIC32 GPIO: unable to create device.\n"); + return (-1); + } + memset (d, 0, sizeof (*d)); + d->dev = dev_create (name); + if (!d->dev) { + free (d); + return (-1); + } + d->dev->priv_data = d; + d->dev->phys_addr = paddr; + d->dev->phys_len = GPIO_REG_SIZE; + d->dev->flags = VDEVICE_FLAG_NO_MTS_MMAP; + d->vm = vm; + d->pic32 = pic32; + d->dev->handler = dev_pic32_gpio_access; + d->dev->reset_handler = dev_pic32_gpio_reset; + + vm_bind_device (vm, d->dev); + return (0); +} diff --git a/tools/virtualmips/pic32_dev_intcon.c b/tools/virtualmips/pic32_dev_intcon.c new file mode 100644 index 0000000..fe8c222 --- /dev/null +++ b/tools/virtualmips/pic32_dev_intcon.c @@ -0,0 +1,174 @@ +/* + * Interrupt controller for PIC32. + * + * Copyright (C) 2011 Serge Vakulenko + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + */ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include + +#include "device.h" +#include "mips_memory.h" +#include "cpu.h" +#include "pic32.h" + +#define INTCON_REG_SIZE 0x190 + +extern cpu_mips_t *current_cpu; + +/* + * Perform an assign/clear/set/invert operation. + */ +static inline unsigned write_op (a, b, op) +{ + switch (op & 0xc) { + case 0x0: /* Assign */ + a = b; + break; + case 0x4: /* Clear */ + a &= ~b; + break; + case 0x8: /* Set */ + a |= b; + break; + case 0xc: /* Invert */ + a ^= b; + break; + } + return a; +} + +void *dev_pic32_intcon_access (cpu_mips_t *cpu, struct vdevice *dev, + m_uint32_t offset, u_int op_size, u_int op_type, m_reg_t *data, + m_uint8_t *has_set_value) +{ + pic32_t *pic32 = dev->priv_data; + unsigned n, v; + + if (offset >= INTCON_REG_SIZE) { + *data = 0; + return NULL; + } + if (op_type == MTS_READ) + *data = 0; + switch (offset & 0x1f0) { + case PIC32_INTCON & 0x1f0: /* Interrupt Control */ + if (op_type == MTS_READ) { + *data = pic32->intcon; + } else { + pic32->intcon = write_op (pic32->intcon, *data, offset); + } + break; + + case PIC32_INTSTAT & 0x1f0: /* Interrupt Status */ + if (op_type == MTS_READ) { + *data = pic32->intstat; + } + break; + + case PIC32_IPTMR & 0x1f0: /* Temporal Proximity Timer */ + if (op_type == MTS_READ) { + *data = pic32->iptmr; + } else { + pic32->iptmr = write_op (pic32->iptmr, *data, offset); + } + break; + + case PIC32_IFS(0) & 0x1f0: /* IFS(0..2) - Interrupt Flag Status */ + case PIC32_IFS(1) & 0x1f0: + case PIC32_IFS(2) & 0x1f0: + n = (offset - (PIC32_IFS(0) & 0x1f0)) >> 4; + if (op_type == MTS_READ) { + *data = pic32->ifs[n]; + } else { + pic32->ifs[n] = write_op (pic32->ifs[n], *data, offset); + pic32_update_irq_flag (pic32); + } + break; + + case PIC32_IEC(0) & 0x1f0: /* IEC(0..2) - Interrupt Enable Control */ + case PIC32_IEC(1) & 0x1f0: + case PIC32_IEC(2) & 0x1f0: + n = (offset - (PIC32_IEC(0) & 0x1f0)) >> 4; + if (op_type == MTS_READ) { + *data = pic32->iec[n]; + } else { + pic32->iec[n] = write_op (pic32->iec[n], *data, offset); + pic32_update_irq_flag (pic32); + } + break; + + case PIC32_IPC(0) & 0x1f0: /* IPC(0..11) - Interrupt Priority Control */ + case PIC32_IPC(1) & 0x1f0: + case PIC32_IPC(2) & 0x1f0: + case PIC32_IPC(3) & 0x1f0: + case PIC32_IPC(4) & 0x1f0: + case PIC32_IPC(5) & 0x1f0: + case PIC32_IPC(6) & 0x1f0: + case PIC32_IPC(7) & 0x1f0: + case PIC32_IPC(8) & 0x1f0: + case PIC32_IPC(9) & 0x1f0: + case PIC32_IPC(10) & 0x1f0: + case PIC32_IPC(11) & 0x1f0: + case PIC32_IPC(12) & 0x1f0: + n = (offset - (PIC32_IPC(0) & 0x1f0)) >> 4; + if (op_type == MTS_READ) { + *data = pic32->ipc[n]; + } else { + pic32->ipc[n] = write_op (pic32->ipc[n], *data, offset); + v = n << 2; + pic32->ivprio[v] = pic32->ipc[n] >> 2 & 63; + pic32->ivprio[v+1] = pic32->ipc[n] >> 10 & 63; + pic32->ivprio[v+2] = pic32->ipc[n] >> 18 & 63; + pic32->ivprio[v+3] = pic32->ipc[n] >> 26 & 63; + pic32_update_irq_flag (pic32); + } + break; + + default: + ASSERT (0, "unknown intcon offset %x\n", offset); + } + *has_set_value = TRUE; + return NULL; +} + +void dev_pic32_intcon_reset (cpu_mips_t *cpu, struct vdevice *dev) +{ + pic32_t *pic32 = dev->priv_data; + + pic32->intcon = 0; + pic32->intstat = 0; + pic32->iptmr = 0; + memset (pic32->ifs, 0, sizeof (pic32->ifs)); + memset (pic32->iec, 0, sizeof (pic32->iec)); + memset (pic32->ipc, 0, sizeof (pic32->ipc)); + memset (pic32->ivprio, 0, sizeof (pic32->ivprio)); + + cpu->irq_cause = 0; + cpu->irq_pending = 0; +} + +int dev_pic32_intcon_init (vm_instance_t *vm, char *name, unsigned paddr) +{ + pic32_t *pic32 = (pic32_t *) vm->hw_data; + + pic32->intdev = dev_create (name); + if (! pic32->intdev) + return (-1); + pic32->intdev->priv_data = pic32; + pic32->intdev->phys_addr = paddr; + pic32->intdev->phys_len = INTCON_REG_SIZE; + pic32->intdev->handler = dev_pic32_intcon_access; + pic32->intdev->reset_handler = dev_pic32_intcon_reset; + pic32->intdev->flags = VDEVICE_FLAG_NO_MTS_MMAP; + + vm_bind_device (vm, pic32->intdev); + return (0); +} diff --git a/tools/virtualmips/pic32_dev_prefetch.c b/tools/virtualmips/pic32_dev_prefetch.c new file mode 100644 index 0000000..1fb3133 --- /dev/null +++ b/tools/virtualmips/pic32_dev_prefetch.c @@ -0,0 +1,105 @@ +/* + * Prefetch controller for PIC32. + * + * Copyright (C) 2011 Serge Vakulenko + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + */ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include + +#include "device.h" +#include "mips_memory.h" +#include "cpu.h" +#include "pic32.h" + +#define PREFETCH_REG_SIZE 0xd0 + +extern cpu_mips_t *current_cpu; + +/* + * Perform an assign/clear/set/invert operation. + */ +static inline unsigned write_op (a, b, op) +{ + switch (op & 0xc) { + case 0x0: /* Assign */ + a = b; + break; + case 0x4: /* Clear */ + a &= ~b; + break; + case 0x8: /* Set */ + a |= b; + break; + case 0xc: /* Invert */ + a ^= b; + break; + } + return a; +} + +void *dev_pic32_prefetch_access (cpu_mips_t *cpu, struct vdevice *dev, + m_uint32_t offset, u_int op_size, u_int op_type, m_reg_t *data, + m_uint8_t *has_set_value) +{ + pic32_t *pic32 = dev->priv_data; + + if (offset >= PREFETCH_REG_SIZE) { + *data = 0; + return NULL; + } + if (op_type == MTS_READ) + *data = 0; + switch (offset & 0x1f0) { + case PIC32_CHECON & 0xf0: /* Prefetch Control */ + if (op_type == MTS_READ) { + *data = pic32->checon; + if (cpu->vm->debug_level > 2) + printf (" read CHECON -> %08x\n", *data); + } else { + pic32->checon = write_op (pic32->checon, *data, offset); + if (cpu->vm->debug_level > 2) + printf (" CHECON := %08x\n", pic32->checon); + } + break; + + // TODO: other registers. + + default: + ASSERT (0, "unknown prefetch offset %x\n", offset); + } + *has_set_value = TRUE; + return NULL; +} + +void dev_pic32_prefetch_reset (cpu_mips_t *cpu, struct vdevice *dev) +{ + pic32_t *pic32 = dev->priv_data; + + pic32->checon = 0x00000007; +} + +int dev_pic32_prefetch_init (vm_instance_t *vm, char *name, unsigned paddr) +{ + pic32_t *pic32 = (pic32_t *) vm->hw_data; + + pic32->prefetch = dev_create (name); + if (! pic32->prefetch) + return (-1); + pic32->prefetch->priv_data = pic32; + pic32->prefetch->phys_addr = paddr; + pic32->prefetch->phys_len = PREFETCH_REG_SIZE; + pic32->prefetch->handler = dev_pic32_prefetch_access; + pic32->prefetch->reset_handler = dev_pic32_prefetch_reset; + pic32->prefetch->flags = VDEVICE_FLAG_NO_MTS_MMAP; + + vm_bind_device (vm, pic32->prefetch); + return (0); +} diff --git a/tools/virtualmips/pic32_dev_rtcc.c b/tools/virtualmips/pic32_dev_rtcc.c new file mode 100644 index 0000000..93cfcf3 --- /dev/null +++ b/tools/virtualmips/pic32_dev_rtcc.c @@ -0,0 +1,143 @@ +/* + * Interrupt controller for PIC32. + * + * Copyright (C) 2011 Serge Vakulenko + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + */ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include + +#include "device.h" +#include "mips_memory.h" +#include "cpu.h" +#include "pic32.h" + +#define RTCC_REG_SIZE 0x80 + +extern cpu_mips_t *current_cpu; + +/* + * Perform an assign/clear/set/invert operation. + */ +static inline unsigned write_op (a, b, op) +{ + switch (op & 0xc) { + case 0x0: /* Assign */ + a = b; + break; + case 0x4: /* Clear */ + a &= ~b; + break; + case 0x8: /* Set */ + a |= b; + break; + case 0xc: /* Invert */ + a ^= b; + break; + } + return a; +} + +void *dev_pic32_rtcc_access (cpu_mips_t *cpu, struct vdevice *dev, + m_uint32_t offset, u_int op_size, u_int op_type, m_reg_t *data, + m_uint8_t *has_set_value) +{ + pic32_t *pic32 = dev->priv_data; + + if (offset >= RTCC_REG_SIZE) { + *data = 0; + return NULL; + } + if (op_type == MTS_READ) + *data = 0; + switch (offset & 0x1f0) { + case PIC32_RTCCON & 0x1f0: /* RTC Control */ + if (op_type == MTS_READ) { + *data = pic32->rtccon; + if (cpu->vm->debug_level > 2) + printf (" read RTCCON -> %08x\n", *data); + } else { + pic32->rtccon = write_op (pic32->rtccon, *data, offset); + if (cpu->vm->debug_level > 2) + printf (" RTCCON := %08x\n", pic32->rtccon); + } + break; + + case PIC32_RTCALRM & 0x1f0: /* RTC alarm control */ + if (op_type == MTS_READ) { + *data = 0; + } else { + //pic32->rtcalrm = write_op (pic32->rtcalrm, *data, offset); + } + break; + + case PIC32_RTCTIME & 0x1f0: /* RTC time value */ + if (op_type == MTS_READ) { + *data = 0; + } else { + //pic32->rtctime = write_op (pic32->rtctime, *data, offset); + } + break; + + case PIC32_RTCDATE & 0x1f0: /* RTC date value */ + if (op_type == MTS_READ) { + *data = 0; + } else { + //pic32->rtcdate = write_op (pic32->rtcdate, *data, offset); + } + break; + + case PIC32_ALRMTIME & 0x1f0: /* Alarm time value */ + if (op_type == MTS_READ) { + *data = 0; + } else { + //pic32->alrmtime = write_op (pic32->alrmtime, *data, offset); + } + break; + + case PIC32_ALRMDATE & 0x1f0: /* Alarm date value */ + if (op_type == MTS_READ) { + *data = 0; + } else { + //pic32->alrmdate = write_op (pic32->alrmdate, *data, offset); + } + break; + + default: + ASSERT (0, "unknown rtcc offset %x\n", offset); + } + *has_set_value = TRUE; + return NULL; +} + +void dev_pic32_rtcc_reset (cpu_mips_t *cpu, struct vdevice *dev) +{ + pic32_t *pic32 = dev->priv_data; + + pic32->rtccon = 0; +} + +int dev_pic32_rtcc_init (vm_instance_t *vm, char *name, unsigned paddr) +{ + pic32_t *pic32 = (pic32_t *) vm->hw_data; + + pic32->rtcdev = dev_create (name); + if (! pic32->rtcdev) + return (-1); + pic32->rtcdev->priv_data = pic32; + pic32->rtcdev->phys_addr = paddr; + pic32->rtcdev->phys_len = RTCC_REG_SIZE; + pic32->rtcdev->handler = dev_pic32_rtcc_access; + pic32->rtcdev->reset_handler = dev_pic32_rtcc_reset; + pic32->rtcdev->flags = VDEVICE_FLAG_NO_MTS_MMAP; + + vm_bind_device (vm, pic32->rtcdev); + return (0); +} diff --git a/tools/virtualmips/pic32_dev_spi.c b/tools/virtualmips/pic32_dev_spi.c new file mode 100644 index 0000000..b4bf664 --- /dev/null +++ b/tools/virtualmips/pic32_dev_spi.c @@ -0,0 +1,227 @@ +/* + * SPI emulation for PIC32. + * Two SD/MMC disks attached to SPI1. + * + * Copyright (C) 2011 Serge Vakulenko + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + */ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include + +#include "device.h" +#include "mips_memory.h" +#include "pic32.h" +#include "cpu.h" +#include "vp_timer.h" +#include "dev_sdcard.h" + +#define SPI_REG_SIZE 0x40 + +struct pic32_spi_data { + struct vdevice *dev; + vm_instance_t *vm; + pic32_t *pic32; + + u_int irq; /* base irq number */ +#define IRQ_FAULT 0 /* error interrupt */ +#define IRQ_TX 1 /* transmitter interrupt */ +#define IRQ_RX 2 /* receiver interrupt */ + + unsigned con; /* 0x00 - Control */ + unsigned stat; /* 0x10 - Status */ + unsigned buf [4]; /* 0x20 - Transmit and receive buffer */ + unsigned brg; /* 0x40 - Baud rate generator */ + + unsigned rfifo; /* read fifo counter */ + unsigned wfifo; /* write fifo counter */ +}; + +extern cpu_mips_t *current_cpu; + +/* + * Perform an assign/clear/set/invert operation. + */ +static inline unsigned write_op (a, b, op) +{ + switch (op & 0xc) { + case 0x0: /* Assign */ + a = b; + break; + case 0x4: /* Clear */ + a &= ~b; + break; + case 0x8: /* Set */ + a |= b; + break; + case 0xc: /* Invert */ + a ^= b; + break; + } + return a; +} + +void *dev_pic32_spi_access (cpu_mips_t * cpu, struct vdevice *dev, + m_uint32_t offset, u_int op_size, u_int op_type, + m_reg_t * data, m_uint8_t * has_set_value) +{ + struct pic32_spi_data *d = dev->priv_data; + unsigned newval; + + if (offset >= SPI_REG_SIZE) { + *data = 0; + return NULL; + } + if (op_type == MTS_READ) + *data = 0; + switch (offset & 0x1f0) { + case PIC32_SPI1CON & 0x1f0: /* SPIx Control */ + if (op_type == MTS_READ) { + *data = d->con; + } else { + d->con = write_op (d->con, *data, offset); + if (! (d->con & PIC32_SPICON_ON)) { + d->vm->clear_irq (d->vm, d->irq + IRQ_FAULT); + d->vm->clear_irq (d->vm, d->irq + IRQ_RX); + d->vm->clear_irq (d->vm, d->irq + IRQ_TX); + d->stat = PIC32_SPISTAT_SPITBE; + } else if (! (d->con & PIC32_SPICON_ENHBUF)) { + d->rfifo = 0; + d->wfifo = 0; + } + } + break; + + case PIC32_SPI1STAT & 0x1f0: /* SPIx Status */ + if (op_type == MTS_READ) { + *data = d->stat; + } else { + /* Only ROV bit is writable. */ + newval = write_op (d->stat, *data, offset); + d->stat = (d->stat & ~PIC32_SPISTAT_SPIROV) | + (newval & PIC32_SPISTAT_SPIROV); + } + break; + + case PIC32_SPI1BUF & 0x1ff: /* SPIx SPIx Buffer */ + if (op_type == MTS_READ) { + *data = d->buf [d->rfifo]; + if (d->con & PIC32_SPICON_ENHBUF) { + d->rfifo++; + d->rfifo &= 3; + } + if (d->stat & PIC32_SPISTAT_SPIRBF) { + d->stat &= ~PIC32_SPISTAT_SPIRBF; + //d->vm->clear_irq (d->vm, d->irq + IRQ_RX); + } + } else { + unsigned sdcard_port = d->pic32->sdcard_port; + + /* Perform SD card i/o on configured SPI port. */ + if ((dev->phys_addr == PIC32_SPI1CON && sdcard_port == 1) || + (dev->phys_addr == PIC32_SPI2CON && sdcard_port == 2) || + (dev->phys_addr == PIC32_SPI3CON && sdcard_port == 3) || + (dev->phys_addr == PIC32_SPI4CON && sdcard_port == 4)) + { + unsigned val = *data; + + if (d->con & PIC32_SPICON_MODE32) { + /* 32-bit data width */ + d->buf [d->wfifo] = (unsigned char) dev_sdcard_io (cpu, val >> 24) << 24; + d->buf [d->wfifo] |= (unsigned char) dev_sdcard_io (cpu, val >> 16) << 16; + d->buf [d->wfifo] |= (unsigned char) dev_sdcard_io (cpu, val >> 8) << 8; + d->buf [d->wfifo] |= (unsigned char) dev_sdcard_io (cpu, val); + + } else if (d->con & PIC32_SPICON_MODE16) { + /* 16-bit data width */ + d->buf [d->wfifo] = (unsigned char) dev_sdcard_io (cpu, val >> 8) << 8; + d->buf [d->wfifo] |= (unsigned char) dev_sdcard_io (cpu, val); + + } else { + /* 8-bit data width */ + d->buf [d->wfifo] = (unsigned char) dev_sdcard_io (cpu, val); + } + } else { + /* No device */ + d->buf [d->wfifo] = ~0; + } + if (d->stat & PIC32_SPISTAT_SPIRBF) { + d->stat |= PIC32_SPISTAT_SPIROV; + //d->vm->set_irq (d->vm, d->irq + IRQ_FAULT); + } else if (d->con & PIC32_SPICON_ENHBUF) { + d->wfifo++; + d->wfifo &= 3; + if (d->wfifo == d->rfifo) { + d->stat |= PIC32_SPISTAT_SPIRBF; + //d->vm->set_irq (d->vm, d->irq + IRQ_RX); + } + } else { + d->stat |= PIC32_SPISTAT_SPIRBF; + //d->vm->set_irq (d->vm, d->irq + IRQ_RX); + } + } + break; + + case PIC32_SPI1BRG & 0x1f0: /* SPIx Baud rate */ + if (op_type == MTS_READ) { + *data = d->brg; + } else { + d->brg = write_op (d->brg, *data, offset); + } + break; + + default: + ASSERT (0, "unknown spi offset %x\n", offset); + } + *has_set_value = TRUE; + return NULL; +} + +void dev_pic32_spi_reset (cpu_mips_t *cpu, struct vdevice *dev) +{ + struct pic32_spi_data *d = dev->priv_data; + + d->con = 0; + d->stat = PIC32_SPISTAT_SPITBE; /* Transmit buffer is empty */ + d->wfifo = 0; + d->rfifo = 0; + d->brg = 0; +} + +int dev_pic32_spi_init (vm_instance_t *vm, char *name, unsigned paddr, + unsigned irq) +{ + struct pic32_spi_data *d; + pic32_t *pic32 = (pic32_t *) vm->hw_data; + + /* allocate the private data structure */ + d = malloc (sizeof (*d)); + if (!d) { + fprintf (stderr, "PIC32 SPI: unable to create device.\n"); + return (-1); + } + memset (d, 0, sizeof (*d)); + d->dev = dev_create (name); + if (! d->dev) { + free (d); + return (-1); + } + d->dev->priv_data = d; + d->dev->phys_addr = paddr; + d->dev->phys_len = SPI_REG_SIZE; + d->dev->flags = VDEVICE_FLAG_NO_MTS_MMAP; + d->vm = vm; + d->irq = irq; + d->pic32 = pic32; + d->dev->handler = dev_pic32_spi_access; + d->dev->reset_handler = dev_pic32_spi_reset; + + vm_bind_device (vm, d->dev); + return (0); +} diff --git a/tools/virtualmips/pic32_dev_syscon.c b/tools/virtualmips/pic32_dev_syscon.c new file mode 100644 index 0000000..63038fb --- /dev/null +++ b/tools/virtualmips/pic32_dev_syscon.c @@ -0,0 +1,191 @@ +/* + * System controller for PIC32. + * + * Copyright (C) 2011 Serge Vakulenko + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + */ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include + +#include "device.h" +#include "mips_memory.h" +#include "cpu.h" +#include "pic32.h" + +#define SYSCON_REG_SIZE 0x1000 + +extern cpu_mips_t *current_cpu; + +static int syskey_unlock; + +static void soft_reset (cpu_mips_t *cpu) +{ + pic32_t *pic32 = (pic32_t*) cpu->vm->hw_data; + + mips_reset (cpu); + cpu->pc = pic32->start_address; + + /* reset all devices */ + dev_reset_all (cpu->vm); + dev_sdcard_reset (cpu); +} + +void *dev_pic32_syscon_access (cpu_mips_t *cpu, struct vdevice *dev, + m_uint32_t offset, u_int op_size, u_int op_type, m_reg_t *data, + m_uint8_t *has_set_value) +{ + pic32_t *pic32 = dev->priv_data; + + if (offset >= SYSCON_REG_SIZE) { + *data = 0; + return NULL; + } + if (op_type == MTS_READ) + *data = 0; + switch (offset & 0xff0) { + case PIC32_OSCCON & 0xff0: + if (op_type == MTS_READ) { + *data = pic32->osccon; + if (cpu->vm->debug_level > 2) + printf (" read OSCCON -> %08x\n", *data); + } else { + pic32->osccon = *data; + if (cpu->vm->debug_level > 2) + printf (" OSCCON := %08x\n", *data); + } + break; + + case PIC32_OSCTUN & 0xff0: + if (op_type == MTS_READ) { + *data = pic32->osctun; + if (cpu->vm->debug_level > 2) + printf (" read OSCTUN -> %08x\n", *data); + } else { + pic32->osctun = *data; + if (cpu->vm->debug_level > 2) + printf (" OSCTUN := %08x\n", *data); + } + break; + + case PIC32_DDPCON & 0xff0: /* Debug Data Port Control */ + if (op_type == MTS_READ) { + *data = pic32->ddpcon; + if (cpu->vm->debug_level > 2) + printf (" read DDPCON -> %08x\n", *data); + } else { + pic32->ddpcon = *data; + if (cpu->vm->debug_level > 2) + printf (" DDPCON := %08x\n", *data); + } + break; + + case PIC32_DEVID & 0xff0: /* Device identifier */ + /* read-only register */ + if (op_type == MTS_READ) { + *data = pic32->devid; + if (cpu->vm->debug_level > 2) + printf (" read DEVID -> %08x\n", *data); + } + break; + + case PIC32_SYSKEY & 0xff0: + if (op_type == MTS_READ) { + *data = pic32->syskey; + if (cpu->vm->debug_level > 2) + printf (" read SYSKEY -> %08x\n", *data); + } else { + pic32->syskey = *data; + if (cpu->vm->debug_level > 2) + printf (" SYSKEY := %08x\n", *data); + + /* Unlock state machine. */ + switch (syskey_unlock) { + case 0: + if (pic32->syskey == 0xaa996655) + syskey_unlock = 1; + else + syskey_unlock = 0; + break; + case 1: + if (pic32->syskey == 0x556699aa) + syskey_unlock = 2; + else + syskey_unlock = 0; + break; + default: + syskey_unlock = 0; + break; + } + } + break; + case PIC32_RCON & 0xff0: + if (op_type == MTS_READ) { + *data = pic32->rcon; + if (cpu->vm->debug_level > 2) + printf (" read RCON -> %08x\n", *data); + } else { + pic32->rcon = *data; + if (cpu->vm->debug_level > 2) + printf (" RCON := %08x\n", *data); + } + break; + case PIC32_RSWRST & 0xff0: + if (op_type == MTS_READ) { + *data = pic32->rswrst; + if (cpu->vm->debug_level > 2) + printf (" read RSWRST -> %08x\n", *data); + } else { + pic32->rswrst = *data; + if (cpu->vm->debug_level > 2) + printf (" RSWRST := %08x\n", *data); + + if (syskey_unlock == 2 && (pic32->rswrst & 1)) + soft_reset (cpu); + } + break; + + default: + ASSERT (0, "unknown syscon offset %x\n", offset); + } + *has_set_value = TRUE; + return NULL; +} + +void dev_pic32_syscon_reset (cpu_mips_t *cpu, struct vdevice *dev) +{ + pic32_t *pic32 = dev->priv_data; + + pic32->osccon = 0x01453320; /* from ubw32 board */ + pic32->osctun = 0; + pic32->ddpcon = 0; + pic32->devid = 0x04307053; /* 795F512L */ + pic32->syskey = 0; + pic32->rcon = 0; + pic32->rswrst = 0; + syskey_unlock = 0; +} + +int dev_pic32_syscon_init (vm_instance_t *vm, char *name, unsigned paddr) +{ + pic32_t *pic32 = (pic32_t *) vm->hw_data; + + pic32->sysdev = dev_create (name); + if (! pic32->sysdev) + return (-1); + pic32->sysdev->priv_data = pic32; + pic32->sysdev->phys_addr = paddr; + pic32->sysdev->phys_len = SYSCON_REG_SIZE; + pic32->sysdev->handler = dev_pic32_syscon_access; + pic32->sysdev->reset_handler = dev_pic32_syscon_reset; + pic32->sysdev->flags = VDEVICE_FLAG_NO_MTS_MMAP; + + vm_bind_device (vm, pic32->sysdev); + return (0); +} diff --git a/tools/virtualmips/pic32_dev_timer.c b/tools/virtualmips/pic32_dev_timer.c new file mode 100644 index 0000000..1857a43 --- /dev/null +++ b/tools/virtualmips/pic32_dev_timer.c @@ -0,0 +1,190 @@ +/* + * Timer emulation for PIC32. + * + * Copyright (C) 2012 Serge Vakulenko + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + */ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include + +#include "device.h" +#include "mips_memory.h" +#include "pic32.h" +#include "cpu.h" +#include "vp_timer.h" +#include "dev_sdcard.h" + +#define TIMER_REG_SIZE 0x30 + +struct pic32_timer_data { + struct vdevice *dev; + vm_instance_t *vm; + pic32_t *pic32; + + unsigned irq; /* irq number */ + unsigned con; /* 0x00 - Control */ + unsigned count; /* 0x10 - Count */ + unsigned period; /* 0x20 - Period */ + unsigned scale; /* prescale value */ +}; + +extern cpu_mips_t *current_cpu; + +static const int timer_scale[8] = { + 1, 2, 4, 8, 16, 32, 64, 256, +}; + +/* + * Perform an assign/clear/set/invert operation. + */ +static inline unsigned write_op (a, b, op) +{ + switch (op & 0xc) { + case 0x0: /* Assign */ + a = b; + break; + case 0x4: /* Clear */ + a &= ~b; + break; + case 0x8: /* Set */ + a |= b; + break; + case 0xc: /* Invert */ + a ^= b; + break; + } + return a; +} + +void *dev_pic32_timer_access (cpu_mips_t * cpu, struct vdevice *dev, + m_uint32_t offset, u_int op_size, u_int op_type, + m_reg_t * data, m_uint8_t * has_set_value) +{ + struct pic32_timer_data *d = dev->priv_data; + unsigned newval; + + if (offset >= TIMER_REG_SIZE) { + *data = 0; + return NULL; + } + if (op_type == MTS_READ) + *data = 0; + switch (offset & 0x1f0) { + case PIC32_T1CON & 0x1f0: /* Timer control */ + if (op_type == MTS_READ) { + *data = d->con; +fprintf (stderr, "%s read TCON -> %04x\n", dev->name, d->con); + } else { + d->con = write_op (d->con, *data, offset); + d->scale = timer_scale [(d->con >> 4) & 7]; +fprintf (stderr, "%s write TCON %04x\n", dev->name, d->con); + if (! (d->con & PIC32_TCON_ON)) { + d->vm->clear_irq (d->vm, d->irq); + d->count = 0; + } + } + break; + + case PIC32_TMR1 & 0x1f0: /* Timer count */ + if (op_type == MTS_READ) { + *data = d->count / d->scale; +fprintf (stderr, "%s read TMR -> %04x\n", dev->name, d->count / d->scale); + } else { + newval = write_op (d->count / d->scale, *data, offset); +fprintf (stderr, "%s write TMR %04x\n", dev->name, newval); + d->count = newval * d->scale; + } + break; + + case PIC32_PR1 & 0x1ff: /* Timer period */ + if (op_type == MTS_READ) { + *data = d->period; +fprintf (stderr, "%s read PR -> %04x\n", dev->name, d->period); + //d->vm->clear_irq (d->vm, d->irq); + } else { + newval = write_op (d->period, *data, offset); +fprintf (stderr, "%s write PR %04x\n", dev->name, newval); + d->period = newval; + //d->vm->set_irq (d->vm, d->irq); + } + break; + + default: + ASSERT (0, "unknown timer offset %x\n", offset); + } + *has_set_value = TRUE; + return NULL; +} + +/* + * Increment timer counter. + * Fire periodic interrupt. + */ +void dev_pic32_timer_tick (cpu_mips_t *cpu, struct vdevice *dev, unsigned nclocks) +{ + struct pic32_timer_data *d = dev->priv_data; + + /* Check that timer is enabled. */ + if (! (d->con & PIC32_TCON_ON) || d->period == 0) + return; + + /* Update counter and check overflow. */ + d->count += nclocks; + if (d->count < d->period * d->scale) + return; + + /* Counter matched. */ + d->count %= d->period * d->scale; + pic32_set_irq (cpu->vm, d->irq); +fprintf (stderr, "%s irq %u\n", dev->name, d->irq); +} + +void dev_pic32_timer_reset (cpu_mips_t *cpu, struct vdevice *dev) +{ + struct pic32_timer_data *d = dev->priv_data; + + d->con = 0; + d->count = 0; + d->period = 0; + d->scale = 1; + pic32_clear_irq (cpu->vm, d->irq); +} + +struct vdevice *dev_pic32_timer_init (vm_instance_t *vm, char *name, + unsigned paddr, unsigned irq) +{ + struct pic32_timer_data *d; + pic32_t *pic32 = (pic32_t *) vm->hw_data; + + /* allocate the private data structure */ + d = malloc (sizeof (*d)); + if (!d) { + fprintf (stderr, "PIC32 timer: unable to create device.\n"); + return 0; + } + memset (d, 0, sizeof (*d)); + d->dev = dev_create (name); + if (! d->dev) { + free (d); + return 0; + } + d->dev->priv_data = d; + d->dev->phys_addr = paddr; + d->dev->phys_len = TIMER_REG_SIZE; + d->dev->flags = VDEVICE_FLAG_NO_MTS_MMAP; + d->vm = vm; + d->irq = irq; + d->pic32 = pic32; + d->dev->handler = dev_pic32_timer_access; + d->dev->reset_handler = dev_pic32_timer_reset; + + vm_bind_device (vm, d->dev); + return d->dev; +} diff --git a/tools/virtualmips/pic32_dev_uart.c b/tools/virtualmips/pic32_dev_uart.c new file mode 100644 index 0000000..091fa24 --- /dev/null +++ b/tools/virtualmips/pic32_dev_uart.c @@ -0,0 +1,328 @@ +/* + * UART emulation for PIC32. + * + * Copyright (C) 2011 Serge Vakulenko + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + */ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include + +#include "device.h" +#include "mips_memory.h" +#include "pic32.h" +#include "cpu.h" +#include "vp_timer.h" + +#define UART_REG_SIZE 0x50 +#define UART_TIME_OUT 1 + +struct pic32_uart_data { + struct vdevice *dev; + vtty_t *vtty; + vm_instance_t *vm; + vp_timer_t *uart_timer; + + u_int output; + u_int irq; /* base irq number */ +#define IRQ_ERR 0 /* error interrupt */ +#define IRQ_RX 1 /* receiver interrupt */ +#define IRQ_TX 2 /* transmitter interrupt */ + + m_uint32_t mode; /* 0x00 - mode */ + m_uint32_t sta; /* 0x10 - status and control */ + m_uint32_t txreg; /* 0x20 - transmit */ + m_uint32_t rxreg; /* 0x30 - receive */ + m_uint32_t brg; /* 0x40 - baud rate */ +}; + +extern cpu_mips_t *current_cpu; + +static void pic32_tty_con_input (vtty_t * vtty) +{ + struct pic32_uart_data *d = vtty->priv_data; + + if (d->mode & PIC32_UMODE_ON) { + /* UART enabled. */ + if (d->sta & PIC32_USTA_URXEN) { + /* Receiver enabled - activate interrupt. */ + d->vm->set_irq (d->vm, d->irq + IRQ_RX); + + /* Receive data available */ + d->sta |= PIC32_USTA_URXDA; + } + } +} + +void *dev_pic32_uart_access (cpu_mips_t * cpu, struct vdevice *dev, + m_uint32_t offset, u_int op_size, u_int op_type, + m_reg_t * data, m_uint8_t * has_set_value) +{ + struct pic32_uart_data *d = dev->priv_data; + unsigned newval; + + if (offset >= UART_REG_SIZE) { + *data = 0; + return NULL; + } + if (op_type == MTS_READ) { + /* + * Reading UART registers. + */ + switch (offset) { + case PIC32_U1RXREG & 0xff: /* Receive data */ + *data = vtty_get_char (d->vtty); + if (vtty_is_char_avail (d->vtty)) { + d->sta |= PIC32_USTA_URXDA; + } else { + d->sta &= ~PIC32_USTA_URXDA; + d->vm->clear_irq (d->vm, d->irq + IRQ_RX); + } + break; + + case PIC32_U1BRG & 0xff: /* Baud rate */ + *data = d->brg; + break; + + case PIC32_U1MODE & 0xff: /* Mode */ + *data = d->mode; + break; + + case PIC32_U1STA & 0xff: /* Status and control */ + d->sta |= PIC32_USTA_RIDLE | /* Receiver is idle */ + PIC32_USTA_TRMT; /* Transmit shift register is empty */ + if (vtty_is_char_avail (d->vtty)) + d->sta |= PIC32_USTA_URXDA; + *data = d->sta; +#if 0 + printf ("<%x>", d->sta); + fflush (stdout); +#endif + break; + + case PIC32_U1TXREG & 0xff: /* Transmit */ + case PIC32_U1MODECLR & 0xff: + case PIC32_U1MODESET & 0xff: + case PIC32_U1MODEINV & 0xff: + case PIC32_U1STACLR & 0xff: + case PIC32_U1STASET & 0xff: + case PIC32_U1STAINV & 0xff: + case PIC32_U1BRGCLR & 0xff: + case PIC32_U1BRGSET & 0xff: + case PIC32_U1BRGINV & 0xff: + *data = 0; + break; + + default: + ASSERT (0, "reading unknown uart offset %x\n", offset); + } + *has_set_value = TRUE; +#if 0 + printf ("--- uart: read %02x -> %08x\n", offset, *data); + fflush (stdout); +#endif + } else { + /* + * Writing UART registers. + */ +#if 0 + printf ("--- uart: write %02x := %08x\n", offset, *data); + fflush (stdout); +#endif + switch (offset) { + case PIC32_U1TXREG & 0xff: /* Transmit */ + /* Skip ^M. */ + if ((char) (*data) != '\r') + vtty_put_char (d->vtty, (char) (*data)); + if ((d->mode & PIC32_UMODE_ON) && + (d->sta & PIC32_USTA_UTXEN) && (d->output == 0)) { + /* + * yajin. + * + * In order to put the next data more quickly, + * just set irq not waiting for + * host_alarm_handler to set irq. Sorry uart, + * too much work for you. + * + * Sometimes, linux kernel prints "serial8250: + * too much work for irq9" if we print large + * data on screen. Please patch the kernel. + * comment "printk(KERN_ERR "serial8250: too + * much work for " "irq%d\n", irq);" qemu has + * some question. + * http://lkml.org/lkml/2008/1/12/135 + * http://kerneltrap.org/mailarchive/linux-ker + * nel/2008/2/7/769924 + * + * If jit is used in future, we may not need to + * set irq here because simulation is quick + * enough. Then we have no "too much work for + * irq9" problem. + */ + d->output = TRUE; + d->vm->set_irq (d->vm, d->irq + IRQ_TX); + } + break; + + case PIC32_U1MODE & 0xff: /* Mode */ + newval = *data; +write_mode: + d->mode = newval; + if (!(d->mode & PIC32_UMODE_ON)) { + d->vm->clear_irq (d->vm, d->irq + IRQ_RX); + d->vm->clear_irq (d->vm, d->irq + IRQ_TX); + d->sta &= ~PIC32_USTA_URXDA; + d->sta &= ~(PIC32_USTA_URXDA | PIC32_USTA_FERR | + PIC32_USTA_PERR | PIC32_USTA_UTXBF); + d->sta |= PIC32_USTA_RIDLE | PIC32_USTA_TRMT; + } + break; + case PIC32_U1MODECLR & 0xff: + newval = d->mode & ~*data; + goto write_mode; + case PIC32_U1MODESET & 0xff: + newval = d->mode | *data; + goto write_mode; + case PIC32_U1MODEINV & 0xff: + newval = d->mode ^ *data; + goto write_mode; + + case PIC32_U1STA & 0xff: /* Status and control */ + newval = *data; +write_sta: + d->sta &= PIC32_USTA_URXDA | PIC32_USTA_FERR | + PIC32_USTA_PERR | PIC32_USTA_RIDLE | + PIC32_USTA_TRMT | PIC32_USTA_UTXBF; + d->sta |= newval & ~(PIC32_USTA_URXDA | PIC32_USTA_FERR | + PIC32_USTA_PERR | PIC32_USTA_RIDLE | + PIC32_USTA_TRMT | PIC32_USTA_UTXBF); + if (!(d->sta & PIC32_USTA_URXEN)) { + d->vm->clear_irq (d->vm, d->irq + IRQ_RX); + d->sta &= ~(PIC32_USTA_URXDA | PIC32_USTA_FERR | + PIC32_USTA_PERR); + } + if (!(d->sta & PIC32_USTA_UTXEN)) { + d->vm->clear_irq (d->vm, d->irq + IRQ_TX); + d->sta &= ~PIC32_USTA_UTXBF; + d->sta |= PIC32_USTA_TRMT; + } + break; + case PIC32_U1STACLR & 0xff: + newval = d->sta & ~*data; + goto write_sta; + case PIC32_U1STASET & 0xff: + newval = d->sta | *data; + goto write_sta; + case PIC32_U1STAINV & 0xff: + newval = d->sta ^ *data; + goto write_sta; + + case PIC32_U1BRG & 0xff: /* Baud rate */ + newval = *data; +write_brg: + d->brg = newval; + break; + case PIC32_U1BRGCLR & 0xff: + newval = d->brg & ~*data; + goto write_brg; + case PIC32_U1BRGSET & 0xff: + newval = d->brg | *data; + goto write_brg; + case PIC32_U1BRGINV & 0xff: + newval = d->brg ^ *data; + goto write_brg; + + case PIC32_U1RXREG & 0xff: /* Receive */ + /* Ignore */ + break; + + default: + ASSERT (0, "writing unknown uart offset %x\n", offset); + } + *has_set_value = TRUE; + } + return NULL; +} + +void dev_pic32_uart_reset (cpu_mips_t * cpu, struct vdevice *dev) +{ + struct pic32_uart_data *d = dev->priv_data; + + d->mode = 0; + d->sta = PIC32_USTA_RIDLE | /* Receiver is idle */ + PIC32_USTA_TRMT; /* Transmit shift register is empty */ + d->txreg = 0; + d->rxreg = 0; + d->brg = 0; +} + +void dev_pic32_uart_cb (void *opaque) +{ + struct pic32_uart_data *d = (struct pic32_uart_data *) opaque; + + d->output = 0; + if (d->mode & PIC32_UMODE_ON) { + /* UART enabled. */ + if ((d->sta & PIC32_USTA_URXEN) && vtty_is_char_avail (d->vtty)) { + /* Receive data available */ + d->sta |= PIC32_USTA_URXDA; + + /* Activate receive interrupt. */ + d->vm->set_irq (d->vm, d->irq + IRQ_RX); + vp_mod_timer (d->uart_timer, + vp_get_clock (rt_clock) + UART_TIME_OUT); + return; + } + if ((d->sta & PIC32_USTA_UTXEN) && (d->output == 0)) { + /* Activate transmit interrupt. */ + d->output = TRUE; + d->vm->set_irq (d->vm, d->irq + IRQ_TX); + vp_mod_timer (d->uart_timer, + vp_get_clock (rt_clock) + UART_TIME_OUT); + return; + } + } + vp_mod_timer (d->uart_timer, vp_get_clock (rt_clock) + UART_TIME_OUT); +} + +int dev_pic32_uart_init (vm_instance_t *vm, char *name, unsigned paddr, + unsigned irq, vtty_t *vtty) +{ + struct pic32_uart_data *d; + + /* allocate the private data structure */ + d = malloc (sizeof (*d)); + if (!d) { + fprintf (stderr, "PIC32 UART: unable to create device.\n"); + return (-1); + } + memset (d, 0, sizeof (*d)); + d->dev = dev_create (name); + if (!d->dev) { + free (d); + return (-1); + } + d->dev->priv_data = d; + d->dev->phys_addr = paddr; + d->dev->phys_len = UART_REG_SIZE; + d->dev->flags = VDEVICE_FLAG_NO_MTS_MMAP; + d->vm = vm; + (*d).vtty = vtty; + d->irq = irq; + vtty->priv_data = d; + d->dev->handler = dev_pic32_uart_access; + d->dev->reset_handler = dev_pic32_uart_reset; + (*d).vtty->read_notifier = pic32_tty_con_input; + d->uart_timer = vp_new_timer (rt_clock, dev_pic32_uart_cb, d); + + vp_mod_timer (d->uart_timer, vp_get_clock (rt_clock) + UART_TIME_OUT); + + vm_bind_device (vm, d->dev); + return (0); +} diff --git a/tools/virtualmips/pic32_explorer16.conf b/tools/virtualmips/pic32_explorer16.conf new file mode 100644 index 0000000..fbde208 --- /dev/null +++ b/tools/virtualmips/pic32_explorer16.conf @@ -0,0 +1,42 @@ +# +# Configure file for Explorer16 board +# +gdb_debug = 0 +gdb_port = 5555 + +# +# Data memory +# +ram_size = 128 # kbytes + +# +# Program flash +# +flash_size = 492 # kbytes +flash_phy_address = 0x1d000000 +flash_file_name = ../../sys/pic32/explorer16/unix.bin + +start_address = 0x9d001000 # user program + +# +# SD/MMC cards +# +sdcard_port = 1 # SPI1 +sdcard0_size = 16 # Mbytes +sdcard0_file_name = ../../filesys.img + +# +# UARTs 1..6 +# +uart1_type = none +uart2_type = console + +# +# Debug level: +# 0 - quiet +# 1 - trace system calls and exceptions +# 2 - trace inctructions in user mode +# 3 - trace all inctructions +# +debug_level = 0 +#trace_address = 0x9d00720c diff --git a/tools/virtualmips/pic32_max32.conf b/tools/virtualmips/pic32_max32.conf new file mode 100644 index 0000000..2bce54f --- /dev/null +++ b/tools/virtualmips/pic32_max32.conf @@ -0,0 +1,41 @@ +# +# Configure file for MAX32 +# +gdb_debug = 0 +gdb_port = 5555 + +# +# Data memory +# +ram_size = 128 # kbytes + +# +# Program flash +# +flash_size = 492 # kbytes +flash_phy_address = 0x1d000000 +flash_file_name = ../../sys/pic32/max32/unix.bin + +start_address = 0x9d001000 # user program + +# +# SD/MMC cards +# +sdcard_port = 4 # SPI4 +sdcard0_size = 340 # Mbytes +sdcard0_file_name = ../../sdcard.rd + +# +# UARTs 1..6 +# +uart1_type = console + +# +# Debug level: +# 0 - quiet +# 1 - trace system calls and exceptions +# 2 - trace inctructions in user mode +# 3 - trace all inctructions +# +debug_level = 0 +#trace_address = 0x9d00720c diff --git a/tools/virtualmips/pic32_maximite.conf b/tools/virtualmips/pic32_maximite.conf new file mode 100644 index 0000000..28e103d --- /dev/null +++ b/tools/virtualmips/pic32_maximite.conf @@ -0,0 +1,42 @@ +# +# Configure file for Maximite +# +gdb_debug = 0 +gdb_port = 5555 + +# +# Data memory +# +ram_size = 128 # kbytes + +# +# Program flash +# +flash_size = 492 # kbytes +flash_phy_address = 0x1d005000 +flash_file_name = ../../sys/pic32/maximite/unix.bin + +start_address = 0x9d006000 # user program + +# +# SD/MMC cards +# +sdcard_port = 4 # SPI4 +sdcard0_size = 16 # Mbytes +sdcard0_file_name = ../../filesys.img + +# +# UARTs 1..6 +# +uart1_type = none +uart4_type = console + +# +# Debug level: +# 0 - quiet +# 1 - trace system calls and exceptions +# 2 - trace inctructions in user mode +# 3 - trace all inctructions +# +debug_level = 0 +#trace_address = 0x9d00720c diff --git a/tools/virtualmips/pic32_ubw32.conf b/tools/virtualmips/pic32_ubw32.conf new file mode 100644 index 0000000..2ccd87b --- /dev/null +++ b/tools/virtualmips/pic32_ubw32.conf @@ -0,0 +1,56 @@ +# +# Configure file for UBW32 +# +gdb_debug = 0 +gdb_port = 5555 + +# +# Data memory +# +ram_size = 128 # kbytes + +# +# Program flash +# +flash_size = 492 # kbytes +flash_phy_address = 0x1d005000 +flash_file_name = ../../sys/pic32/ubw32-uart/unix.bin + +start_address = 0x9d006000 # user program + +# +# SD/MMC cards +# +sdcard_port = 1 # SPI1 +sdcard0_size = 16 # Mbytes +sdcard0_file_name = ../../filesys.img +#sdcard1_size = 2 # Mbytes +#sdcard1_file_name = ../../home.img + +# +# UARTs 1..6 +# +uart1_type = console + +#uart1_type = tcp +#uart1_port = 2302 +#uart2_type = tcp +#uart2_port = 2302 +#uart3_type = tcp +#uart3_port = 2303 +#uart4_type = tcp +#uart4_port = 2304 +#uart5_type = tcp +#uart5_port = 2305 +#uart6_type = tcp +#uart6_port = 2306 + +# +# Debug level: +# 0 - quiet +# 1 - trace system calls and exceptions +# 2 - trace inctructions in user mode +# 3 - trace all inctructions +# +debug_level = 0 +#trace_address = 0x9d00720c diff --git a/tools/virtualmips/pic32mx.h b/tools/virtualmips/pic32mx.h new file mode 100644 index 0000000..529079a --- /dev/null +++ b/tools/virtualmips/pic32mx.h @@ -0,0 +1,906 @@ +/* + * Hardware register defines for Microchip PIC32MX microcontrollers. + * + * Copyright (C) 2010 Serge Vakulenko, + * + * 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 the copyright notice and this + * permission notice and warranty disclaimer appear in supporting + * documentation, and that the name of the author not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * + * The author disclaim all warranties with regard to this + * software, including all implied warranties of merchantability + * and fitness. In no event shall the author 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. + */ +#ifndef _IO_PIC32MX_H +#define _IO_PIC32MX_H + +/*-------------------------------------- + * Peripheral registers. + */ +#define PIC32_R(a) (0x1F800000 + (a)) + +/*-------------------------------------- + * Interrupt controller registers. + */ +#define PIC32_INTCON PIC32_R (0x81000) /* Interrupt Control */ +#define PIC32_INTCONCLR PIC32_R (0x81004) +#define PIC32_INTCONSET PIC32_R (0x81008) +#define PIC32_INTCONINV PIC32_R (0x8100C) +#define PIC32_INTSTAT PIC32_R (0x81010) /* Interrupt Status */ +#define PIC32_IPTMR PIC32_R (0x81020) /* Temporal Proximity Timer */ +#define PIC32_IPTMRCLR PIC32_R (0x81024) +#define PIC32_IPTMRSET PIC32_R (0x81028) +#define PIC32_IPTMRINV PIC32_R (0x8102C) +#define PIC32_IFS(n) PIC32_R (0x81030+((n)<<4)) /* IFS(0..2) - Interrupt Flag Status */ +#define PIC32_IFSCLR(n) PIC32_R (0x81034+((n)<<4)) +#define PIC32_IFSSET(n) PIC32_R (0x81038+((n)<<4)) +#define PIC32_IFSINV(n) PIC32_R (0x8103C+((n)<<4)) +#define PIC32_IEC(n) PIC32_R (0x81060+((n)<<4)) /* IEC(0..2) - Interrupt Enable Control */ +#define PIC32_IECCLR(n) PIC32_R (0x81064+((n)<<4)) +#define PIC32_IECSET(n) PIC32_R (0x81068+((n)<<4)) +#define PIC32_IECINV(n) PIC32_R (0x8106C+((n)<<4)) +#define PIC32_IPC(n) PIC32_R (0x81090+((n)<<4)) /* IPC(0..12) - Interrupt Priority Control */ +#define PIC32_IPCCLR(n) PIC32_R (0x81094+((n)<<4)) +#define PIC32_IPCSET(n) PIC32_R (0x81098+((n)<<4)) +#define PIC32_IPCINV(n) PIC32_R (0x8109C+((n)<<4)) + +/* + * Interrupt Control register. + */ +#define PIC32_INTCON_INT0EP 0x0001 /* External interrupt 0 polarity rising edge */ +#define PIC32_INTCON_INT1EP 0x0002 /* External interrupt 1 polarity rising edge */ +#define PIC32_INTCON_INT2EP 0x0004 /* External interrupt 2 polarity rising edge */ +#define PIC32_INTCON_INT3EP 0x0008 /* External interrupt 3 polarity rising edge */ +#define PIC32_INTCON_INT4EP 0x0010 /* External interrupt 4 polarity rising edge */ +#define PIC32_INTCON_TPC(x) ((x)<<8) /* Temporal proximity group priority */ +#define PIC32_INTCON_MVEC 0x1000 /* Multi-vectored mode */ +#define PIC32_INTCON_FRZ 0x4000 /* Freeze in debug mode */ +#define PIC32_INTCON_SS0 0x8000 /* Single vector has a shadow register set */ + +/* + * Interrupt Status register. + */ +#define PIC32_INTSTAT_VEC(s) ((s) & 0xFF) /* Interrupt vector */ +#define PIC32_INTSTAT_SRIPL(s) ((s) >> 8 & 7) /* Requested priority level */ + +/* + * Interrupt Prority Control register. + */ +#define PIC32_IPC_IS0(x) (x) /* Interrupt 0 subpriority */ +#define PIC32_IPC_IP0(x) ((x)<<2) /* Interrupt 0 priority */ +#define PIC32_IPC_IS1(x) ((x)<<8) /* Interrupt 1 subpriority */ +#define PIC32_IPC_IP1(x) ((x)<<10) /* Interrupt 1 priority */ +#define PIC32_IPC_IS2(x) ((x)<<16) /* Interrupt 2 subpriority */ +#define PIC32_IPC_IP2(x) ((x)<<18) /* Interrupt 2 priority */ +#define PIC32_IPC_IS3(x) ((x)<<24) /* Interrupt 3 subpriority */ +#define PIC32_IPC_IP3(x) ((x)<<26) /* Interrupt 3 priority */ + +/* + * IRQ numbers for PIC32MX3xx/4xx/5xx/6xx/7xx. + */ +#define PIC32_IRQ_CT 0 /* Core Timer Interrupt */ +#define PIC32_IRQ_CS0 1 /* Core Software Interrupt 0 */ +#define PIC32_IRQ_CS1 2 /* Core Software Interrupt 1 */ +#define PIC32_IRQ_INT0 3 /* External Interrupt 0 */ +#define PIC32_IRQ_T1 4 /* Timer1 */ +#define PIC32_IRQ_IC1 5 /* Input Capture 1 */ +#define PIC32_IRQ_OC1 6 /* Output Compare 1 */ +#define PIC32_IRQ_INT1 7 /* External Interrupt 1 */ +#define PIC32_IRQ_T2 8 /* Timer2 */ +#define PIC32_IRQ_IC2 9 /* Input Capture 2 */ +#define PIC32_IRQ_OC2 10 /* Output Compare 2 */ +#define PIC32_IRQ_INT2 11 /* External Interrupt 2 */ +#define PIC32_IRQ_T3 12 /* Timer3 */ +#define PIC32_IRQ_IC3 13 /* Input Capture 3 */ +#define PIC32_IRQ_OC3 14 /* Output Compare 3 */ +#define PIC32_IRQ_INT3 15 /* External Interrupt 3 */ +#define PIC32_IRQ_T4 16 /* Timer4 */ +#define PIC32_IRQ_IC4 17 /* Input Capture 4 */ +#define PIC32_IRQ_OC4 18 /* Output Compare 4 */ +#define PIC32_IRQ_INT4 19 /* External Interrupt 4 */ +#define PIC32_IRQ_T5 20 /* Timer5 */ +#define PIC32_IRQ_IC5 21 /* Input Capture 5 */ +#define PIC32_IRQ_OC5 22 /* Output Compare 5 */ +#define PIC32_IRQ_SPI1E 23 /* SPI1 Fault */ +#define PIC32_IRQ_SPI1TX 24 /* SPI1 Transfer Done */ +#define PIC32_IRQ_SPI1RX 25 /* SPI1 Receive Done */ + +#define PIC32_IRQ_SPI3E 26 /* SPI3 Fault */ +#define PIC32_IRQ_SPI3TX 27 /* SPI3 Transfer Done */ +#define PIC32_IRQ_SPI3RX 28 /* SPI3 Receive Done */ +#define PIC32_IRQ_U1E 26 /* UART1 Error */ +#define PIC32_IRQ_U1RX 27 /* UART1 Receiver */ +#define PIC32_IRQ_U1TX 28 /* UART1 Transmitter */ +#define PIC32_IRQ_I2C3B 26 /* I2C3 Bus Collision Event */ +#define PIC32_IRQ_I2C3S 27 /* I2C3 Slave Event */ +#define PIC32_IRQ_I2C3M 28 /* I2C3 Master Event */ + +#define PIC32_IRQ_I2C1B 29 /* I2C1 Bus Collision Event */ +#define PIC32_IRQ_I2C1S 30 /* I2C1 Slave Event */ +#define PIC32_IRQ_I2C1M 31 /* I2C1 Master Event */ +#define PIC32_IRQ_CN 32 /* Input Change Interrupt */ +#define PIC32_IRQ_AD1 33 /* ADC1 Convert Done */ +#define PIC32_IRQ_PMP 34 /* Parallel Master Port */ +#define PIC32_IRQ_CMP1 35 /* Comparator Interrupt */ +#define PIC32_IRQ_CMP2 36 /* Comparator Interrupt */ + +#define PIC32_IRQ_SPI2E 37 /* SPI2 Fault */ +#define PIC32_IRQ_SPI2TX 38 /* SPI2 Transfer Done */ +#define PIC32_IRQ_SPI2RX 39 /* SPI2 Receive Done */ +#define PIC32_IRQ_U3E 37 /* UART3 Error */ +#define PIC32_IRQ_U3RX 38 /* UART3 Receiver */ +#define PIC32_IRQ_U3TX 39 /* UART3 Transmitter */ +#define PIC32_IRQ_I2C4B 37 /* I2C4 Bus Collision Event */ +#define PIC32_IRQ_I2C4S 38 /* I2C4 Slave Event */ +#define PIC32_IRQ_I2C4M 39 /* I2C4 Master Event */ + +#define PIC32_IRQ_SPI4E 40 /* SPI4 Fault */ +#define PIC32_IRQ_SPI4TX 41 /* SPI4 Transfer Done */ +#define PIC32_IRQ_SPI4RX 42 /* SPI4 Receive Done */ +#define PIC32_IRQ_U2E 40 /* UART2 Error */ +#define PIC32_IRQ_U2RX 41 /* UART2 Receiver */ +#define PIC32_IRQ_U2TX 42 /* UART2 Transmitter */ +#define PIC32_IRQ_I2C5B 40 /* I2C5 Bus Collision Event */ +#define PIC32_IRQ_I2C5S 41 /* I2C5 Slave Event */ +#define PIC32_IRQ_I2C5M 42 /* I2C5 Master Event */ + +#define PIC32_IRQ_I2C2B 43 /* I2C2 Bus Collision Event */ +#define PIC32_IRQ_I2C2S 44 /* I2C2 Slave Event */ +#define PIC32_IRQ_I2C2M 45 /* I2C2 Master Event */ +#define PIC32_IRQ_FSCM 46 /* Fail-Safe Clock Monitor */ +#define PIC32_IRQ_RTCC 47 /* Real-Time Clock and Calendar */ +#define PIC32_IRQ_DMA0 48 /* DMA Channel 0 */ +#define PIC32_IRQ_DMA1 49 /* DMA Channel 1 */ +#define PIC32_IRQ_DMA2 50 /* DMA Channel 2 */ +#define PIC32_IRQ_DMA3 51 /* DMA Channel 3 */ +#define PIC32_IRQ_DMA4 52 /* DMA Channel 4 */ +#define PIC32_IRQ_DMA5 53 /* DMA Channel 5 */ +#define PIC32_IRQ_DMA6 54 /* DMA Channel 6 */ +#define PIC32_IRQ_DMA7 55 /* DMA Channel 7 */ +#define PIC32_IRQ_FCE 56 /* Flash Control Event */ +#define PIC32_IRQ_USB 57 /* USB */ +#define PIC32_IRQ_CAN1 58 /* Control Area Network 1 */ +#define PIC32_IRQ_CAN2 59 /* Control Area Network 2 */ +#define PIC32_IRQ_ETH 60 /* Ethernet Interrupt */ +#define PIC32_IRQ_IC1E 61 /* Input Capture 1 Error */ +#define PIC32_IRQ_IC2E 62 /* Input Capture 2 Error */ +#define PIC32_IRQ_IC3E 63 /* Input Capture 3 Error */ +#define PIC32_IRQ_IC4E 64 /* Input Capture 4 Error */ +#define PIC32_IRQ_IC5E 65 /* Input Capture 5 Error */ +#define PIC32_IRQ_PMPE 66 /* Parallel Master Port Error */ +#define PIC32_IRQ_U4E 67 /* UART4 Error */ +#define PIC32_IRQ_U4RX 68 /* UART4 Receiver */ +#define PIC32_IRQ_U4TX 69 /* UART4 Transmitter */ +#define PIC32_IRQ_U6E 70 /* UART6 Error */ +#define PIC32_IRQ_U6RX 71 /* UART6 Receiver */ +#define PIC32_IRQ_U6TX 72 /* UART6 Transmitter */ +#define PIC32_IRQ_U5E 73 /* UART5 Error */ +#define PIC32_IRQ_U5RX 74 /* UART5 Receiver */ +#define PIC32_IRQ_U5TX 75 /* UART5 Transmitter */ + +/* + * Interrupt vector numbers for PIC32MX3xx/4xx/5xx/6xx/7xx. + */ +#define PIC32_VECT_CT 0 /* Core Timer Interrupt */ +#define PIC32_VECT_CS0 1 /* Core Software Interrupt 0 */ +#define PIC32_VECT_CS1 2 /* Core Software Interrupt 1 */ +#define PIC32_VECT_INT0 3 /* External Interrupt 0 */ +#define PIC32_VECT_T1 4 /* Timer1 */ +#define PIC32_VECT_IC1 5 /* Input Capture 1 */ +#define PIC32_VECT_OC1 6 /* Output Compare 1 */ +#define PIC32_VECT_INT1 7 /* External Interrupt 1 */ +#define PIC32_VECT_T2 8 /* Timer2 */ +#define PIC32_VECT_IC2 9 /* Input Capture 2 */ +#define PIC32_VECT_OC2 10 /* Output Compare 2 */ +#define PIC32_VECT_INT2 11 /* External Interrupt 2 */ +#define PIC32_VECT_T3 12 /* Timer3 */ +#define PIC32_VECT_IC3 13 /* Input Capture 3 */ +#define PIC32_VECT_OC3 14 /* Output Compare 3 */ +#define PIC32_VECT_INT3 15 /* External Interrupt 3 */ +#define PIC32_VECT_T4 16 /* Timer4 */ +#define PIC32_VECT_IC4 17 /* Input Capture 4 */ +#define PIC32_VECT_OC4 18 /* Output Compare 4 */ +#define PIC32_VECT_INT4 19 /* External Interrupt 4 */ +#define PIC32_VECT_T5 20 /* Timer5 */ +#define PIC32_VECT_IC5 21 /* Input Capture 5 */ +#define PIC32_VECT_OC5 22 /* Output Compare 5 */ +#define PIC32_VECT_SPI1 23 /* SPI1 */ + +#define PIC32_VECT_SPI3 24 /* SPI3 */ +#define PIC32_VECT_U1 24 /* UART1 */ +#define PIC32_VECT_I2C3 24 /* I2C3 */ + +#define PIC32_VECT_I2C1 25 /* I2C1 */ +#define PIC32_VECT_CN 26 /* Input Change Interrupt */ +#define PIC32_VECT_AD1 27 /* ADC1 Convert Done */ +#define PIC32_VECT_PMP 28 /* Parallel Master Port */ +#define PIC32_VECT_CMP1 29 /* Comparator Interrupt */ +#define PIC32_VECT_CMP2 30 /* Comparator Interrupt */ + +#define PIC32_VECT_SPI2 31 /* SPI2 */ +#define PIC32_VECT_U3 31 /* UART3 */ +#define PIC32_VECT_I2C4 31 /* I2C4 */ + +#define PIC32_VECT_SPI4 32 /* SPI4 */ +#define PIC32_VECT_U2 32 /* UART2 */ +#define PIC32_VECT_I2C5 32 /* I2C5 */ + +#define PIC32_VECT_I2C2 33 /* I2C2 */ +#define PIC32_VECT_FSCM 34 /* Fail-Safe Clock Monitor */ +#define PIC32_VECT_RTCC 35 /* Real-Time Clock and Calendar */ +#define PIC32_VECT_DMA0 36 /* DMA Channel 0 */ +#define PIC32_VECT_DMA1 37 /* DMA Channel 1 */ +#define PIC32_VECT_DMA2 38 /* DMA Channel 2 */ +#define PIC32_VECT_DMA3 39 /* DMA Channel 3 */ +#define PIC32_VECT_DMA4 40 /* DMA Channel 4 */ +#define PIC32_VECT_DMA5 41 /* DMA Channel 5 */ +#define PIC32_VECT_DMA6 42 /* DMA Channel 6 */ +#define PIC32_VECT_DMA7 43 /* DMA Channel 7 */ +#define PIC32_VECT_FCE 44 /* Flash Control Event */ +#define PIC32_VECT_USB 45 /* USB */ +#define PIC32_VECT_CAN1 46 /* Control Area Network 1 */ +#define PIC32_VECT_CAN2 47 /* Control Area Network 2 */ +#define PIC32_VECT_ETH 48 /* Ethernet Interrupt */ +#define PIC32_VECT_U4 49 /* UART4 */ +#define PIC32_VECT_U6 50 /* UART6 */ +#define PIC32_VECT_U5 51 /* UART5 */ + +/*-------------------------------------- + * DMA controller registers. + */ +#define PIC32_DMACON PIC32_R (0x83000) /* DMA Control */ +#define PIC32_DMACONCLR PIC32_R (0x83004) +#define PIC32_DMACONSET PIC32_R (0x83008) +#define PIC32_DMACONINV PIC32_R (0x8300C) +#define PIC32_DMASTAT PIC32_R (0x83010) /* DMA Status */ +#define PIC32_DMAADDR PIC32_R (0x83020) /* DMA Address */ +// TODO: other DMA registers. + +/*-------------------------------------- + * System controller registers. + */ +#define PIC32_OSCCON PIC32_R (0xf000) +#define PIC32_OSCTUN PIC32_R (0xf010) +#define PIC32_DDPCON PIC32_R (0xf200) /* Debug Data Port Control */ +#define PIC32_DEVID PIC32_R (0xf220) +#define PIC32_SYSKEY PIC32_R (0xf230) +#define PIC32_RCON PIC32_R (0xf600) +#define PIC32_RSWRST PIC32_R (0xf610) + +/*-------------------------------------- + * Prefetch cache controller registers. + */ +#define PIC32_CHECON PIC32_R (0x84000) /* Prefetch cache control */ +// TODO: other prefetech registers + +/*-------------------------------------- + * Bus matrix control registers. + */ +#define PIC32_BMXCON PIC32_R (0x82000) /* Memory configuration */ +#define PIC32_BMXDKPBA PIC32_R (0x82010) /* Data RAM kernel program base address */ +#define PIC32_BMXDUDBA PIC32_R (0x82020) /* Data RAM user data base address */ +#define PIC32_BMXDUPBA PIC32_R (0x82030) /* Data RAM user program base address */ +#define PIC32_BMXDRMSZ PIC32_R (0x82040) /* Data RAM size */ +#define PIC32_BMXPUPBA PIC32_R (0x82050) /* Program Flash user program base address */ +#define PIC32_BMXPFMSZ PIC32_R (0x82060) /* Program Flash size */ +#define PIC32_BMXBOOTSZ PIC32_R (0x82070) /* Boot Flash size */ + +/*-------------------------------------- + * Real time clock and calendar. + */ +#define PIC32_RTCCON PIC32_R (0x0200) /* RTC control */ +#define PIC32_RTCALRM PIC32_R (0x0210) /* RTC alarm control */ +#define PIC32_RTCTIME PIC32_R (0x0220) /* RTC time value */ +#define PIC32_RTCDATE PIC32_R (0x0230) /* RTC date value */ +#define PIC32_ALRMTIME PIC32_R (0x0240) /* Alarm time value */ +#define PIC32_ALRMDATE PIC32_R (0x0250) /* Alarm date value */ + +/*-------------------------------------- + * Timer registers. + */ +#define PIC32_T1CON PIC32_R (0x0600) /* Timer 1 control */ +#define PIC32_TMR1 PIC32_R (0x0610) /* Timer 1 count */ +#define PIC32_PR1 PIC32_R (0x0620) /* Timer 1 period */ +#define PIC32_T2CON PIC32_R (0x0800) /* Timer 2 control */ +#define PIC32_TMR2 PIC32_R (0x0810) /* Timer 2 count */ +#define PIC32_PR2 PIC32_R (0x0820) /* Timer 2 period */ +#define PIC32_T3CON PIC32_R (0x0A00) /* Timer 3 control */ +#define PIC32_TMR3 PIC32_R (0x0A10) /* Timer 3 count */ +#define PIC32_PR3 PIC32_R (0x0A20) /* Timer 3 period */ +#define PIC32_T4CON PIC32_R (0x0C00) /* Timer 4 control */ +#define PIC32_TMR4 PIC32_R (0x0C10) /* Timer 4 count */ +#define PIC32_PR4 PIC32_R (0x0C20) /* Timer 4 period */ +#define PIC32_T5CON PIC32_R (0x0E00) /* Timer 5 control */ +#define PIC32_TMR5 PIC32_R (0x0E10) /* Timer 5 count */ +#define PIC32_PR5 PIC32_R (0x0E20) /* Timer 5 period */ + +/* + * Timer Control register. + */ +#define PIC32_TCON_ON 0x8000 /* Timer is enabled */ +#define PIC32_TCON_FRZ 0x4000 /* Freeze when CPU is in Debug mode */ +#define PIC32_TCON_SIDL 0x2000 /* Stop in Idle mode */ +#define PIC32_TCON_TWDIS 0x1000 /* (Timer A) Asynchronous Timer Write Disable */ +#define PIC32_TCON_TWIP 0x0800 /* (Timer A) Asynchronous Timer Write in Progress */ +#define PIC32_TCON_TGATE 0x0080 /* Enable gated time accumulation (only when TCS=0) */ +#define PIC32_TCON_TCKPS_MASK 0x0070 /* Timer Input Clock Prescale Select */ +#define PIC32_TCON_TCKPS_256 0x0070 /* 1:256 */ +#define PIC32_TCON_TCKPS_64 0x0060 /* 1:64 */ +#define PIC32_TCON_TCKPS_32 0x0050 /* 1:32 */ +#define PIC32_TCON_TCKPS_16 0x0040 /* 1:16 */ +#define PIC32_TCON_TCKPS_8 0x0030 /* 1:8 */ +#define PIC32_TCON_TCKPS_4 0x0020 /* 1:4 */ +#define PIC32_TCON_TCKPS_2 0x0010 /* 1:2 */ +#define PIC32_TCON_TCKPS_1 0x0000 /* 1:1 */ +#define PIC32_TCON_T32 0x0008 /* (Timer B) TMRx and TMRy form a 32-bit timer */ +#define PIC32_TCON_TSYNC 0x0004 /* (Timer A) External clock input is synchronized */ +#define PIC32_TCON_TCS 0x0002 /* External clock from TxCKI pin */ + +/*-------------------------------------- + * UART registers. + */ +#define PIC32_U1MODE PIC32_R (0x6000) /* Mode */ +#define PIC32_U1MODECLR PIC32_R (0x6004) +#define PIC32_U1MODESET PIC32_R (0x6008) +#define PIC32_U1MODEINV PIC32_R (0x600C) +#define PIC32_U1STA PIC32_R (0x6010) /* Status and control */ +#define PIC32_U1STACLR PIC32_R (0x6014) +#define PIC32_U1STASET PIC32_R (0x6018) +#define PIC32_U1STAINV PIC32_R (0x601C) +#define PIC32_U1TXREG PIC32_R (0x6020) /* Transmit */ +#define PIC32_U1RXREG PIC32_R (0x6030) /* Receive */ +#define PIC32_U1BRG PIC32_R (0x6040) /* Baud rate */ +#define PIC32_U1BRGCLR PIC32_R (0x6044) +#define PIC32_U1BRGSET PIC32_R (0x6048) +#define PIC32_U1BRGINV PIC32_R (0x604C) + +#ifdef PIC32MX4 +#define PIC32_U2MODE PIC32_R (0x6200) /* Mode */ +#define PIC32_U2MODECLR PIC32_R (0x6204) +#define PIC32_U2MODESET PIC32_R (0x6208) +#define PIC32_U2MODEINV PIC32_R (0x620C) +#define PIC32_U2STA PIC32_R (0x6210) /* Status and control */ +#define PIC32_U2STACLR PIC32_R (0x6214) +#define PIC32_U2STASET PIC32_R (0x6218) +#define PIC32_U2STAINV PIC32_R (0x621C) +#define PIC32_U2TXREG PIC32_R (0x6220) /* Transmit */ +#define PIC32_U2RXREG PIC32_R (0x6230) /* Receive */ +#define PIC32_U2BRG PIC32_R (0x6240) /* Baud rate */ +#define PIC32_U2BRGCLR PIC32_R (0x6244) +#define PIC32_U2BRGSET PIC32_R (0x6248) +#define PIC32_U2BRGINV PIC32_R (0x624C) +#endif +#ifdef PIC32MX7 +#define PIC32_U4MODE PIC32_R (0x6200) /* Mode */ +#define PIC32_U4MODECLR PIC32_R (0x6204) +#define PIC32_U4MODESET PIC32_R (0x6208) +#define PIC32_U4MODEINV PIC32_R (0x620C) +#define PIC32_U4STA PIC32_R (0x6210) /* Status and control */ +#define PIC32_U4STACLR PIC32_R (0x6214) +#define PIC32_U4STASET PIC32_R (0x6218) +#define PIC32_U4STAINV PIC32_R (0x621C) +#define PIC32_U4TXREG PIC32_R (0x6220) /* Transmit */ +#define PIC32_U4RXREG PIC32_R (0x6230) /* Receive */ +#define PIC32_U4BRG PIC32_R (0x6240) /* Baud rate */ +#define PIC32_U4BRGCLR PIC32_R (0x6244) +#define PIC32_U4BRGSET PIC32_R (0x6248) +#define PIC32_U4BRGINV PIC32_R (0x624C) + +#define PIC32_U3MODE PIC32_R (0x6400) /* Mode */ +#define PIC32_U3MODECLR PIC32_R (0x6404) +#define PIC32_U3MODESET PIC32_R (0x6408) +#define PIC32_U3MODEINV PIC32_R (0x640C) +#define PIC32_U3STA PIC32_R (0x6410) /* Status and control */ +#define PIC32_U3STACLR PIC32_R (0x6414) +#define PIC32_U3STASET PIC32_R (0x6418) +#define PIC32_U3STAINV PIC32_R (0x641C) +#define PIC32_U3TXREG PIC32_R (0x6420) /* Transmit */ +#define PIC32_U3RXREG PIC32_R (0x6430) /* Receive */ +#define PIC32_U3BRG PIC32_R (0x6440) /* Baud rate */ +#define PIC32_U3BRGCLR PIC32_R (0x6444) +#define PIC32_U3BRGSET PIC32_R (0x6448) +#define PIC32_U3BRGINV PIC32_R (0x644C) + +#define PIC32_U6MODE PIC32_R (0x6600) /* Mode */ +#define PIC32_U6MODECLR PIC32_R (0x6604) +#define PIC32_U6MODESET PIC32_R (0x6608) +#define PIC32_U6MODEINV PIC32_R (0x660C) +#define PIC32_U6STA PIC32_R (0x6610) /* Status and control */ +#define PIC32_U6STACLR PIC32_R (0x6614) +#define PIC32_U6STASET PIC32_R (0x6618) +#define PIC32_U6STAINV PIC32_R (0x661C) +#define PIC32_U6TXREG PIC32_R (0x6620) /* Transmit */ +#define PIC32_U6RXREG PIC32_R (0x6630) /* Receive */ +#define PIC32_U6BRG PIC32_R (0x6640) /* Baud rate */ +#define PIC32_U6BRGCLR PIC32_R (0x6644) +#define PIC32_U6BRGSET PIC32_R (0x6648) +#define PIC32_U6BRGINV PIC32_R (0x664C) + +#define PIC32_U2MODE PIC32_R (0x6800) /* Mode */ +#define PIC32_U2MODECLR PIC32_R (0x6804) +#define PIC32_U2MODESET PIC32_R (0x6808) +#define PIC32_U2MODEINV PIC32_R (0x680C) +#define PIC32_U2STA PIC32_R (0x6810) /* Status and control */ +#define PIC32_U2STACLR PIC32_R (0x6814) +#define PIC32_U2STASET PIC32_R (0x6818) +#define PIC32_U2STAINV PIC32_R (0x681C) +#define PIC32_U2TXREG PIC32_R (0x6820) /* Transmit */ +#define PIC32_U2RXREG PIC32_R (0x6830) /* Receive */ +#define PIC32_U2BRG PIC32_R (0x6840) /* Baud rate */ +#define PIC32_U2BRGCLR PIC32_R (0x6844) +#define PIC32_U2BRGSET PIC32_R (0x6848) +#define PIC32_U2BRGINV PIC32_R (0x684C) + +#define PIC32_U5MODE PIC32_R (0x6A00) /* Mode */ +#define PIC32_U5MODECLR PIC32_R (0x6A04) +#define PIC32_U5MODESET PIC32_R (0x6A08) +#define PIC32_U5MODEINV PIC32_R (0x6A0C) +#define PIC32_U5STA PIC32_R (0x6A10) /* Status and control */ +#define PIC32_U5STACLR PIC32_R (0x6A14) +#define PIC32_U5STASET PIC32_R (0x6A18) +#define PIC32_U5STAINV PIC32_R (0x6A1C) +#define PIC32_U5TXREG PIC32_R (0x6A20) /* Transmit */ +#define PIC32_U5RXREG PIC32_R (0x6A30) /* Receive */ +#define PIC32_U5BRG PIC32_R (0x6A40) /* Baud rate */ +#define PIC32_U5BRGCLR PIC32_R (0x6A44) +#define PIC32_U5BRGSET PIC32_R (0x6A48) +#define PIC32_U5BRGINV PIC32_R (0x6A4C) +#endif + +/* + * UART Mode register. + */ +#define PIC32_UMODE_STSEL 0x0001 /* 2 Stop bits */ +#define PIC32_UMODE_PDSEL 0x0006 /* Bitmask: */ +#define PIC32_UMODE_PDSEL_8NPAR 0x0000 /* 8-bit data, no parity */ +#define PIC32_UMODE_PDSEL_8EVEN 0x0002 /* 8-bit data, even parity */ +#define PIC32_UMODE_PDSEL_8ODD 0x0004 /* 8-bit data, odd parity */ +#define PIC32_UMODE_PDSEL_9NPAR 0x0006 /* 9-bit data, no parity */ +#define PIC32_UMODE_BRGH 0x0008 /* High Baud Rate Enable */ +#define PIC32_UMODE_RXINV 0x0010 /* Receive Polarity Inversion */ +#define PIC32_UMODE_ABAUD 0x0020 /* Auto-Baud Enable */ +#define PIC32_UMODE_LPBACK 0x0040 /* UARTx Loopback Mode */ +#define PIC32_UMODE_WAKE 0x0080 /* Wake-up on start bit during Sleep Mode */ +#define PIC32_UMODE_UEN 0x0300 /* Bitmask: */ +#define PIC32_UMODE_UEN_RTS 0x0100 /* Using UxRTS pin */ +#define PIC32_UMODE_UEN_RTSCTS 0x0200 /* Using UxCTS and UxRTS pins */ +#define PIC32_UMODE_UEN_BCLK 0x0300 /* Using UxBCLK pin */ +#define PIC32_UMODE_RTSMD 0x0800 /* UxRTS Pin Simplex mode */ +#define PIC32_UMODE_IREN 0x1000 /* IrDA Encoder and Decoder Enable bit */ +#define PIC32_UMODE_SIDL 0x2000 /* Stop in Idle Mode */ +#define PIC32_UMODE_FRZ 0x4000 /* Freeze in Debug Exception Mode */ +#define PIC32_UMODE_ON 0x8000 /* UART Enable */ + +/* + * UART Control and status register. + */ +#define PIC32_USTA_URXDA 0x00000001 /* Receive Data Available (read-only) */ +#define PIC32_USTA_OERR 0x00000002 /* Receive Buffer Overrun */ +#define PIC32_USTA_FERR 0x00000004 /* Framing error detected (read-only) */ +#define PIC32_USTA_PERR 0x00000008 /* Parity error detected (read-only) */ +#define PIC32_USTA_RIDLE 0x00000010 /* Receiver is idle (read-only) */ +#define PIC32_USTA_ADDEN 0x00000020 /* Address Detect mode */ +#define PIC32_USTA_URXISEL 0x000000C0 /* Bitmask: receive interrupt is set when... */ +#define PIC32_USTA_URXISEL_NEMP 0x00000000 /* ...receive buffer is not empty */ +#define PIC32_USTA_URXISEL_HALF 0x00000040 /* ...receive buffer becomes 1/2 full */ +#define PIC32_USTA_URXISEL_3_4 0x00000080 /* ...receive buffer becomes 3/4 full */ +#define PIC32_USTA_TRMT 0x00000100 /* Transmit shift register is empty (read-only) */ +#define PIC32_USTA_UTXBF 0x00000200 /* Transmit buffer is full (read-only) */ +#define PIC32_USTA_UTXEN 0x00000400 /* Transmit Enable */ +#define PIC32_USTA_UTXBRK 0x00000800 /* Transmit Break */ +#define PIC32_USTA_URXEN 0x00001000 /* Receiver Enable */ +#define PIC32_USTA_UTXINV 0x00002000 /* Transmit Polarity Inversion */ +#define PIC32_USTA_UTXISEL 0x0000C000 /* Bitmask: TX interrupt is generated when... */ +#define PIC32_USTA_UTXISEL_1 0x00000000 /* ...the transmit buffer contains at least one empty space */ +#define PIC32_USTA_UTXISEL_ALL 0x00004000 /* ...all characters have been transmitted */ +#define PIC32_USTA_UTXISEL_EMP 0x00008000 /* ...the transmit buffer becomes empty */ +#define PIC32_USTA_ADDR 0x00FF0000 /* Automatic Address Mask */ +#define PIC32_USTA_ADM_EN 0x01000000 /* Automatic Address Detect */ + +/* + * Compute the 16-bit baud rate divisor, given + * the oscillator frequency and baud rate. + * Round to the nearest integer. + */ +#define PIC32_BRG_BAUD(fr,bd) ((((fr)/8 + (bd)) / (bd) / 2) - 1) + +/*-------------------------------------- + * SPI registers. + */ +#ifdef PIC32MX4 +#define PIC32_SPI1CON PIC32_R (0x5800) /* Control */ +#define PIC32_SPI1CONCLR PIC32_R (0x5804) +#define PIC32_SPI1CONSET PIC32_R (0x5808) +#define PIC32_SPI1CONINV PIC32_R (0x580C) +#define PIC32_SPI1STAT PIC32_R (0x5810) /* Status */ +#define PIC32_SPI1STATCLR PIC32_R (0x5814) +#define PIC32_SPI1STATSET PIC32_R (0x5818) +#define PIC32_SPI1STATINV PIC32_R (0x581C) +#define PIC32_SPI1BUF PIC32_R (0x5820) /* Transmit and receive buffer */ +#define PIC32_SPI1BRG PIC32_R (0x5830) /* Baud rate generator */ +#define PIC32_SPI1BRGCLR PIC32_R (0x5834) +#define PIC32_SPI1BRGSET PIC32_R (0x5838) +#define PIC32_SPI1BRGINV PIC32_R (0x583C) +#endif +#ifdef PIC32MX7 +#define PIC32_SPI3CON PIC32_R (0x5800) /* Control */ +#define PIC32_SPI3CONCLR PIC32_R (0x5804) +#define PIC32_SPI3CONSET PIC32_R (0x5808) +#define PIC32_SPI3CONINV PIC32_R (0x580C) +#define PIC32_SPI3STAT PIC32_R (0x5810) /* Status */ +#define PIC32_SPI3STATCLR PIC32_R (0x5814) +#define PIC32_SPI3STATSET PIC32_R (0x5818) +#define PIC32_SPI3STATINV PIC32_R (0x581C) +#define PIC32_SPI3BUF PIC32_R (0x5820) /* Transmit and receive buffer */ +#define PIC32_SPI3BRG PIC32_R (0x5830) /* Baud rate generator */ +#define PIC32_SPI3BRGCLR PIC32_R (0x5834) +#define PIC32_SPI3BRGSET PIC32_R (0x5838) +#define PIC32_SPI3BRGINV PIC32_R (0x583C) + +#define PIC32_SPI4CON PIC32_R (0x5C00) /* Control */ +#define PIC32_SPI4CONCLR PIC32_R (0x5C04) +#define PIC32_SPI4CONSET PIC32_R (0x5C08) +#define PIC32_SPI4CONINV PIC32_R (0x5C0C) +#define PIC32_SPI4STAT PIC32_R (0x5C10) /* Status */ +#define PIC32_SPI4STATCLR PIC32_R (0x5C14) +#define PIC32_SPI4STATSET PIC32_R (0x5C18) +#define PIC32_SPI4STATINV PIC32_R (0x5C1C) +#define PIC32_SPI4BUF PIC32_R (0x5C20) /* Transmit and receive buffer */ +#define PIC32_SPI4BRG PIC32_R (0x5C30) /* Baud rate generator */ +#define PIC32_SPI4BRGCLR PIC32_R (0x5C34) +#define PIC32_SPI4BRGSET PIC32_R (0x5C38) +#define PIC32_SPI4BRGINV PIC32_R (0x5C3C) + +#define PIC32_SPI1CON PIC32_R (0x5E00) /* Control */ +#define PIC32_SPI1CONCLR PIC32_R (0x5E04) +#define PIC32_SPI1CONSET PIC32_R (0x5E08) +#define PIC32_SPI1CONINV PIC32_R (0x5E0C) +#define PIC32_SPI1STAT PIC32_R (0x5E10) /* Status */ +#define PIC32_SPI1STATCLR PIC32_R (0x5E14) +#define PIC32_SPI1STATSET PIC32_R (0x5E18) +#define PIC32_SPI1STATINV PIC32_R (0x5E1C) +#define PIC32_SPI1BUF PIC32_R (0x5E20) /* Transmit and receive buffer */ +#define PIC32_SPI1BRG PIC32_R (0x5E30) /* Baud rate generator */ +#define PIC32_SPI1BRGCLR PIC32_R (0x5E34) +#define PIC32_SPI1BRGSET PIC32_R (0x5E38) +#define PIC32_SPI1BRGINV PIC32_R (0x5E3C) +#endif + +#define PIC32_SPI2CON PIC32_R (0x5A00) /* Control */ +#define PIC32_SPI2CONCLR PIC32_R (0x5A04) +#define PIC32_SPI2CONSET PIC32_R (0x5A08) +#define PIC32_SPI2CONINV PIC32_R (0x5A0C) +#define PIC32_SPI2STAT PIC32_R (0x5A10) /* Status */ +#define PIC32_SPI2STATCLR PIC32_R (0x5A14) +#define PIC32_SPI2STATSET PIC32_R (0x5A18) +#define PIC32_SPI2STATINV PIC32_R (0x5A1C) +#define PIC32_SPI2BUF PIC32_R (0x5A20) /* Transmit and receive buffer */ +#define PIC32_SPI2BRG PIC32_R (0x5A30) /* Baud rate generator */ +#define PIC32_SPI2BRGCLR PIC32_R (0x5A34) +#define PIC32_SPI2BRGSET PIC32_R (0x5A38) +#define PIC32_SPI2BRGINV PIC32_R (0x5A3C) + +/* + * SPI Control register. + */ +#define PIC32_SPICON_MSTEN 0x00000020 /* Master mode */ +#define PIC32_SPICON_CKP 0x00000040 /* Idle clock is high level */ +#define PIC32_SPICON_SSEN 0x00000080 /* Slave mode: SSx pin enable */ +#define PIC32_SPICON_CKE 0x00000100 /* Output data changes on + * transition from active clock + * state to Idle clock state */ +#define PIC32_SPICON_SMP 0x00000200 /* Master mode: input data sampled + * at end of data output time. */ +#define PIC32_SPICON_MODE16 0x00000400 /* 16-bit data width */ +#define PIC32_SPICON_MODE32 0x00000800 /* 32-bit data width */ +#define PIC32_SPICON_DISSDO 0x00001000 /* SDOx pin is not used */ +#define PIC32_SPICON_SIDL 0x00002000 /* Stop in Idle mode */ +#define PIC32_SPICON_FRZ 0x00004000 /* Freeze in Debug mode */ +#define PIC32_SPICON_ON 0x00008000 /* SPI Peripheral is enabled */ +#define PIC32_SPICON_ENHBUF 0x00010000 /* Enhanced buffer enable */ +#define PIC32_SPICON_SPIFE 0x00020000 /* Frame synchronization pulse + * coincides with the first bit clock */ +#define PIC32_SPICON_FRMPOL 0x20000000 /* Frame pulse is active-high */ +#define PIC32_SPICON_FRMSYNC 0x40000000 /* Frame sync pulse input (Slave mode) */ +#define PIC32_SPICON_FRMEN 0x80000000 /* Framed SPI support */ + +/* + * SPI Status register. + */ +#define PIC32_SPISTAT_SPIRBF 0x00000001 /* Receive buffer is full */ +#define PIC32_SPISTAT_SPITBE 0x00000008 /* Transmit buffer is empty */ +#define PIC32_SPISTAT_SPIROV 0x00000040 /* Receive overflow flag */ +#define PIC32_SPISTAT_SPIBUSY 0x00000800 /* SPI is busy */ + +/*-------------------------------------- + * Port A-G registers. + */ +#define PIC32_TRISA PIC32_R (0x86000) /* Port A: mask of inputs */ +#define PIC32_TRISACLR PIC32_R (0x86004) +#define PIC32_TRISASET PIC32_R (0x86008) +#define PIC32_TRISAINV PIC32_R (0x8600C) +#define PIC32_PORTA PIC32_R (0x86010) /* Port A: read inputs, write outputs */ +#define PIC32_PORTACLR PIC32_R (0x86014) +#define PIC32_PORTASET PIC32_R (0x86018) +#define PIC32_PORTAINV PIC32_R (0x8601C) +#define PIC32_LATA PIC32_R (0x86020) /* Port A: read/write outputs */ +#define PIC32_LATACLR PIC32_R (0x86024) +#define PIC32_LATASET PIC32_R (0x86028) +#define PIC32_LATAINV PIC32_R (0x8602C) +#define PIC32_ODCA PIC32_R (0x86030) /* Port A: open drain configuration */ +#define PIC32_ODCACLR PIC32_R (0x86034) +#define PIC32_ODCASET PIC32_R (0x86038) +#define PIC32_ODCAINV PIC32_R (0x8603C) + +#define PIC32_TRISB PIC32_R (0x86040) /* Port B: mask of inputs */ +#define PIC32_TRISBCLR PIC32_R (0x86044) +#define PIC32_TRISBSET PIC32_R (0x86048) +#define PIC32_TRISBINV PIC32_R (0x8604C) +#define PIC32_PORTB PIC32_R (0x86050) /* Port B: read inputs, write outputs */ +#define PIC32_PORTBCLR PIC32_R (0x86054) +#define PIC32_PORTBSET PIC32_R (0x86058) +#define PIC32_PORTBINV PIC32_R (0x8605C) +#define PIC32_LATB PIC32_R (0x86060) /* Port B: read/write outputs */ +#define PIC32_LATBCLR PIC32_R (0x86064) +#define PIC32_LATBSET PIC32_R (0x86068) +#define PIC32_LATBINV PIC32_R (0x8606C) +#define PIC32_ODCB PIC32_R (0x86070) /* Port B: open drain configuration */ +#define PIC32_ODCBCLR PIC32_R (0x86074) +#define PIC32_ODCBSET PIC32_R (0x86078) +#define PIC32_ODCBINV PIC32_R (0x8607C) + +#define PIC32_TRISC PIC32_R (0x86080) /* Port C: mask of inputs */ +#define PIC32_TRISCCLR PIC32_R (0x86084) +#define PIC32_TRISCSET PIC32_R (0x86088) +#define PIC32_TRISCINV PIC32_R (0x8608C) +#define PIC32_PORTC PIC32_R (0x86090) /* Port C: read inputs, write outputs */ +#define PIC32_PORTCCLR PIC32_R (0x86094) +#define PIC32_PORTCSET PIC32_R (0x86098) +#define PIC32_PORTCINV PIC32_R (0x8609C) +#define PIC32_LATC PIC32_R (0x860A0) /* Port C: read/write outputs */ +#define PIC32_LATCCLR PIC32_R (0x860A4) +#define PIC32_LATCSET PIC32_R (0x860A8) +#define PIC32_LATCINV PIC32_R (0x860AC) +#define PIC32_ODCC PIC32_R (0x860B0) /* Port C: open drain configuration */ +#define PIC32_ODCCCLR PIC32_R (0x860B4) +#define PIC32_ODCCSET PIC32_R (0x860B8) +#define PIC32_ODCCINV PIC32_R (0x860BC) + +#define PIC32_TRISD PIC32_R (0x860C0) /* Port D: mask of inputs */ +#define PIC32_TRISDCLR PIC32_R (0x860C4) +#define PIC32_TRISDSET PIC32_R (0x860C8) +#define PIC32_TRISDINV PIC32_R (0x860CC) +#define PIC32_PORTD PIC32_R (0x860D0) /* Port D: read inputs, write outputs */ +#define PIC32_PORTDCLR PIC32_R (0x860D4) +#define PIC32_PORTDSET PIC32_R (0x860D8) +#define PIC32_PORTDINV PIC32_R (0x860DC) +#define PIC32_LATD PIC32_R (0x860E0) /* Port D: read/write outputs */ +#define PIC32_LATDCLR PIC32_R (0x860E4) +#define PIC32_LATDSET PIC32_R (0x860E8) +#define PIC32_LATDINV PIC32_R (0x860EC) +#define PIC32_ODCD PIC32_R (0x860F0) /* Port D: open drain configuration */ +#define PIC32_ODCDCLR PIC32_R (0x860F4) +#define PIC32_ODCDSET PIC32_R (0x860F8) +#define PIC32_ODCDINV PIC32_R (0x860FC) + +#define PIC32_TRISE PIC32_R (0x86100) /* Port E: mask of inputs */ +#define PIC32_TRISECLR PIC32_R (0x86104) +#define PIC32_TRISESET PIC32_R (0x86108) +#define PIC32_TRISEINV PIC32_R (0x8610C) +#define PIC32_PORTE PIC32_R (0x86110) /* Port E: read inputs, write outputs */ +#define PIC32_PORTECLR PIC32_R (0x86114) +#define PIC32_PORTESET PIC32_R (0x86118) +#define PIC32_PORTEINV PIC32_R (0x8611C) +#define PIC32_LATE PIC32_R (0x86120) /* Port E: read/write outputs */ +#define PIC32_LATECLR PIC32_R (0x86124) +#define PIC32_LATESET PIC32_R (0x86128) +#define PIC32_LATEINV PIC32_R (0x8612C) +#define PIC32_ODCE PIC32_R (0x86130) /* Port E: open drain configuration */ +#define PIC32_ODCECLR PIC32_R (0x86134) +#define PIC32_ODCESET PIC32_R (0x86138) +#define PIC32_ODCEINV PIC32_R (0x8613C) + +#define PIC32_TRISF PIC32_R (0x86140) /* Port F: mask of inputs */ +#define PIC32_TRISFCLR PIC32_R (0x86144) +#define PIC32_TRISFSET PIC32_R (0x86148) +#define PIC32_TRISFINV PIC32_R (0x8614C) +#define PIC32_PORTF PIC32_R (0x86150) /* Port F: read inputs, write outputs */ +#define PIC32_PORTFCLR PIC32_R (0x86154) +#define PIC32_PORTFSET PIC32_R (0x86158) +#define PIC32_PORTFINV PIC32_R (0x8615C) +#define PIC32_LATF PIC32_R (0x86160) /* Port F: read/write outputs */ +#define PIC32_LATFCLR PIC32_R (0x86164) +#define PIC32_LATFSET PIC32_R (0x86168) +#define PIC32_LATFINV PIC32_R (0x8616C) +#define PIC32_ODCF PIC32_R (0x86170) /* Port F: open drain configuration */ +#define PIC32_ODCFCLR PIC32_R (0x86174) +#define PIC32_ODCFSET PIC32_R (0x86178) +#define PIC32_ODCFINV PIC32_R (0x8617C) + +#define PIC32_TRISG PIC32_R (0x86180) /* Port G: mask of inputs */ +#define PIC32_TRISGCLR PIC32_R (0x86184) +#define PIC32_TRISGSET PIC32_R (0x86188) +#define PIC32_TRISGINV PIC32_R (0x8618C) +#define PIC32_PORTG PIC32_R (0x86190) /* Port G: read inputs, write outputs */ +#define PIC32_PORTGCLR PIC32_R (0x86194) +#define PIC32_PORTGSET PIC32_R (0x86198) +#define PIC32_PORTGINV PIC32_R (0x8619C) +#define PIC32_LATG PIC32_R (0x861A0) /* Port G: read/write outputs */ +#define PIC32_LATGCLR PIC32_R (0x861A4) +#define PIC32_LATGSET PIC32_R (0x861A8) +#define PIC32_LATGINV PIC32_R (0x861AC) +#define PIC32_ODCG PIC32_R (0x861B0) /* Port G: open drain configuration */ +#define PIC32_ODCGCLR PIC32_R (0x861B4) +#define PIC32_ODCGSET PIC32_R (0x861B8) +#define PIC32_ODCGINV PIC32_R (0x861BC) + +#define PIC32_CNCON PIC32_R (0x861C0) /* Interrupt-on-change control */ +#define PIC32_CNCONCLR PIC32_R (0x861C4) +#define PIC32_CNCONSET PIC32_R (0x861C8) +#define PIC32_CNCONINV PIC32_R (0x861CC) +#define PIC32_CNEN PIC32_R (0x861D0) /* Input change interrupt enable */ +#define PIC32_CNENCLR PIC32_R (0x861D4) +#define PIC32_CNENSET PIC32_R (0x861D8) +#define PIC32_CNENINV PIC32_R (0x861DC) +#define PIC32_CNPUE PIC32_R (0x861E0) /* Input pin pull-up enable */ +#define PIC32_CNPUECLR PIC32_R (0x861E4) +#define PIC32_CNPUESET PIC32_R (0x861E8) +#define PIC32_CNPUEINV PIC32_R (0x861EC) + +/*-------------------------------------- + * A/D Converter registers. + */ +#define PIC32_AD1CON1 PIC32_R (0x9000) /* Control register 1 */ +#define PIC32_AD1CON1CLR PIC32_R (0x9004) +#define PIC32_AD1CON1SET PIC32_R (0x9008) +#define PIC32_AD1CON1INV PIC32_R (0x900C) +#define PIC32_AD1CON2 PIC32_R (0x9010) /* Control register 2 */ +#define PIC32_AD1CON2CLR PIC32_R (0x9014) +#define PIC32_AD1CON2SET PIC32_R (0x9018) +#define PIC32_AD1CON2INV PIC32_R (0x901C) +#define PIC32_AD1CON3 PIC32_R (0x9020) /* Control register 3 */ +#define PIC32_AD1CON3CLR PIC32_R (0x9024) +#define PIC32_AD1CON3SET PIC32_R (0x9028) +#define PIC32_AD1CON3INV PIC32_R (0x902C) +#define PIC32_AD1CHS PIC32_R (0x9040) /* Channel select */ +#define PIC32_AD1CHSCLR PIC32_R (0x9044) +#define PIC32_AD1CHSSET PIC32_R (0x9048) +#define PIC32_AD1CHSINV PIC32_R (0x904C) +#define PIC32_AD1CSSL PIC32_R (0x9050) /* Input scan selection */ +#define PIC32_AD1CSSLCLR PIC32_R (0x9054) +#define PIC32_AD1CSSLSET PIC32_R (0x9058) +#define PIC32_AD1CSSLINV PIC32_R (0x905C) +#define PIC32_AD1PCFG PIC32_R (0x9060) /* Port configuration */ +#define PIC32_AD1PCFGCLR PIC32_R (0x9064) +#define PIC32_AD1PCFGSET PIC32_R (0x9068) +#define PIC32_AD1PCFGINV PIC32_R (0x906C) +#define PIC32_ADC1BUF0 PIC32_R (0x9070) /* Result words */ +#define PIC32_ADC1BUF1 PIC32_R (0x9080) +#define PIC32_ADC1BUF2 PIC32_R (0x9090) +#define PIC32_ADC1BUF3 PIC32_R (0x90A0) +#define PIC32_ADC1BUF4 PIC32_R (0x90B0) +#define PIC32_ADC1BUF5 PIC32_R (0x90C0) +#define PIC32_ADC1BUF6 PIC32_R (0x90D0) +#define PIC32_ADC1BUF7 PIC32_R (0x90E0) +#define PIC32_ADC1BUF8 PIC32_R (0x90F0) +#define PIC32_ADC1BUF9 PIC32_R (0x9100) +#define PIC32_ADC1BUFA PIC32_R (0x9110) +#define PIC32_ADC1BUFB PIC32_R (0x9120) +#define PIC32_ADC1BUFC PIC32_R (0x9130) +#define PIC32_ADC1BUFD PIC32_R (0x9140) +#define PIC32_ADC1BUFE PIC32_R (0x9150) +#define PIC32_ADC1BUFF PIC32_R (0x9160) + +/*-------------------------------------- + * Parallel master port registers. + */ +#define PIC32_PMCON PIC32_R (0x7000) /* Control */ +#define PIC32_PMCONCLR PIC32_R (0x7004) +#define PIC32_PMCONSET PIC32_R (0x7008) +#define PIC32_PMCONINV PIC32_R (0x700C) +#define PIC32_PMMODE PIC32_R (0x7010) /* Mode */ +#define PIC32_PMMODECLR PIC32_R (0x7014) +#define PIC32_PMMODESET PIC32_R (0x7018) +#define PIC32_PMMODEINV PIC32_R (0x701C) +#define PIC32_PMADDR PIC32_R (0x7020) /* Address */ +#define PIC32_PMADDRCLR PIC32_R (0x7024) +#define PIC32_PMADDRSET PIC32_R (0x7028) +#define PIC32_PMADDRINV PIC32_R (0x702C) +#define PIC32_PMDOUT PIC32_R (0x7030) /* Data output */ +#define PIC32_PMDOUTCLR PIC32_R (0x7034) +#define PIC32_PMDOUTSET PIC32_R (0x7038) +#define PIC32_PMDOUTINV PIC32_R (0x703C) +#define PIC32_PMDIN PIC32_R (0x7040) /* Data input */ +#define PIC32_PMDINCLR PIC32_R (0x7044) +#define PIC32_PMDINSET PIC32_R (0x7048) +#define PIC32_PMDININV PIC32_R (0x704C) +#define PIC32_PMAEN PIC32_R (0x7050) /* Pin enable */ +#define PIC32_PMAENCLR PIC32_R (0x7054) +#define PIC32_PMAENSET PIC32_R (0x7058) +#define PIC32_PMAENINV PIC32_R (0x705C) +#define PIC32_PMSTAT PIC32_R (0x7060) /* Status (slave only) */ +#define PIC32_PMSTATCLR PIC32_R (0x7064) +#define PIC32_PMSTATSET PIC32_R (0x7068) +#define PIC32_PMSTATINV PIC32_R (0x706C) + +/* + * PMP Control register. + */ +#define PIC32_PMCON_RDSP 0x0001 /* Read strobe polarity active-high */ +#define PIC32_PMCON_WRSP 0x0002 /* Write strobe polarity active-high */ +#define PIC32_PMCON_CS1P 0x0008 /* Chip select 0 polarity active-high */ +#define PIC32_PMCON_CS2P 0x0010 /* Chip select 1 polarity active-high */ +#define PIC32_PMCON_ALP 0x0020 /* Address latch polarity active-high */ +#define PIC32_PMCON_CSF 0x00C0 /* Chip select function bitmask: */ +#define PIC32_PMCON_CSF_NONE 0x0000 /* PMCS2 and PMCS1 as A[15:14] */ +#define PIC32_PMCON_CSF_CS2 0x0040 /* PMCS2 as chip select */ +#define PIC32_PMCON_CSF_CS21 0x0080 /* PMCS2 and PMCS1 as chip select */ +#define PIC32_PMCON_PTRDEN 0x0100 /* Read/write strobe port enable */ +#define PIC32_PMCON_PTWREN 0x0200 /* Write enable strobe port enable */ +#define PIC32_PMCON_PMPTTL 0x0400 /* TTL input buffer select */ +#define PIC32_PMCON_ADRMUX 0x1800 /* Address/data mux selection bitmask: */ +#define PIC32_PMCON_ADRMUX_NONE 0x0000 /* Address and data separate */ +#define PIC32_PMCON_ADRMUX_AD 0x0800 /* Lower address on PMD[7:0], high on PMA[15:8] */ +#define PIC32_PMCON_ADRMUX_D8 0x1000 /* All address on PMD[7:0] */ +#define PIC32_PMCON_ADRMUX_D16 0x1800 /* All address on PMD[15:0] */ +#define PIC32_PMCON_SIDL 0x2000 /* Stop in idle */ +#define PIC32_PMCON_FRZ 0x4000 /* Freeze in debug exception */ +#define PIC32_PMCON_ON 0x8000 /* Parallel master port enable */ + +/* + * PMP Mode register. + */ +#define PIC32_PMMODE_WAITE(x) ((x)<<0) /* Wait states: data hold after RW strobe */ +#define PIC32_PMMODE_WAITM(x) ((x)<<2) /* Wait states: data RW strobe */ +#define PIC32_PMMODE_WAITB(x) ((x)<<6) /* Wait states: data setup to RW strobe */ +#define PIC32_PMMODE_MODE 0x0300 /* Mode select bitmask: */ +#define PIC32_PMMODE_MODE_SLAVE 0x0000 /* Legacy slave */ +#define PIC32_PMMODE_MODE_SLENH 0x0100 /* Enhanced slave */ +#define PIC32_PMMODE_MODE_MAST2 0x0200 /* Master mode 2 */ +#define PIC32_PMMODE_MODE_MAST1 0x0300 /* Master mode 1 */ +#define PIC32_PMMODE_MODE16 0x0400 /* 16-bit mode */ +#define PIC32_PMMODE_INCM 0x1800 /* Address increment mode bitmask: */ +#define PIC32_PMMODE_INCM_NONE 0x0000 /* No increment/decrement */ +#define PIC32_PMMODE_INCM_INC 0x0800 /* Increment address */ +#define PIC32_PMMODE_INCM_DEC 0x1000 /* Decrement address */ +#define PIC32_PMMODE_INCM_SLAVE 0x1800 /* Slave auto-increment */ +#define PIC32_PMMODE_IRQM 0x6000 /* Interrupt request bitmask: */ +#define PIC32_PMMODE_IRQM_DIS 0x0000 /* No interrupt generated */ +#define PIC32_PMMODE_IRQM_END 0x2000 /* Interrupt at end of read/write cycle */ +#define PIC32_PMMODE_IRQM_A3 0x4000 /* Interrupt on address 3 */ +#define PIC32_PMMODE_BUSY 0x8000 /* Port is busy */ + +/* + * PMP Address register. + */ +#define PIC32_PMADDR_PADDR 0x3FFF /* Destination address */ +#define PIC32_PMADDR_CS1 0x4000 /* Chip select 1 is active */ +#define PIC32_PMADDR_CS2 0x8000 /* Chip select 2 is active */ + +/* + * PMP status register (slave only). + */ +#define PIC32_PMSTAT_OB0E 0x0001 /* Output buffer 0 empty */ +#define PIC32_PMSTAT_OB1E 0x0002 /* Output buffer 1 empty */ +#define PIC32_PMSTAT_OB2E 0x0004 /* Output buffer 2 empty */ +#define PIC32_PMSTAT_OB3E 0x0008 /* Output buffer 3 empty */ +#define PIC32_PMSTAT_OBUF 0x0040 /* Output buffer underflow */ +#define PIC32_PMSTAT_OBE 0x0080 /* Output buffer empty */ +#define PIC32_PMSTAT_IB0F 0x0100 /* Input buffer 0 full */ +#define PIC32_PMSTAT_IB1F 0x0200 /* Input buffer 1 full */ +#define PIC32_PMSTAT_IB2F 0x0400 /* Input buffer 2 full */ +#define PIC32_PMSTAT_IB3F 0x0800 /* Input buffer 3 full */ +#define PIC32_PMSTAT_IBOV 0x4000 /* Input buffer overflow */ +#define PIC32_PMSTAT_IBF 0x8000 /* Input buffer full */ + +#endif /* _IO_PIC32MX_H */ diff --git a/tools/virtualmips/sbox.c b/tools/virtualmips/sbox.c new file mode 100644 index 0000000..5e80811 --- /dev/null +++ b/tools/virtualmips/sbox.c @@ -0,0 +1,87 @@ +/* + * Cisco router simulation platform. + * Copyright (c) 2007 Christophe Fillot (cf@utc.fr) + * + * S-Box: http://bretm.home.comcast.net/hash/10.html + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "utils.h" +#include "sbox.h" + +m_uint32_t sbox_array[] = { + 0xF53E1837, 0x5F14C86B, 0x9EE3964C, 0xFA796D53, + 0x32223FC3, 0x4D82BC98, 0xA0C7FA62, 0x63E2C982, + 0x24994A5B, 0x1ECE7BEE, 0x292B38EF, 0xD5CD4E56, + 0x514F4303, 0x7BE12B83, 0x7192F195, 0x82DC7300, + 0x084380B4, 0x480B55D3, 0x5F430471, 0x13F75991, + 0x3F9CF22C, 0x2FE0907A, 0xFD8E1E69, 0x7B1D5DE8, + 0xD575A85C, 0xAD01C50A, 0x7EE00737, 0x3CE981E8, + 0x0E447EFA, 0x23089DD6, 0xB59F149F, 0x13600EC7, + 0xE802C8E6, 0x670921E4, 0x7207EFF0, 0xE74761B0, + 0x69035234, 0xBFA40F19, 0xF63651A0, 0x29E64C26, + 0x1F98CCA7, 0xD957007E, 0xE71DDC75, 0x3E729595, + 0x7580B7CC, 0xD7FAF60B, 0x92484323, 0xA44113EB, + 0xE4CBDE08, 0x346827C9, 0x3CF32AFA, 0x0B29BCF1, + 0x6E29F7DF, 0xB01E71CB, 0x3BFBC0D1, 0x62EDC5B8, + 0xB7DE789A, 0xA4748EC9, 0xE17A4C4F, 0x67E5BD03, + 0xF3B33D1A, 0x97D8D3E9, 0x09121BC0, 0x347B2D2C, + 0x79A1913C, 0x504172DE, 0x7F1F8483, 0x13AC3CF6, + 0x7A2094DB, 0xC778FA12, 0xADF7469F, 0x21786B7B, + 0x71A445D0, 0xA8896C1B, 0x656F62FB, 0x83A059B3, + 0x972DFE6E, 0x4122000C, 0x97D9DA19, 0x17D5947B, + 0xB1AFFD0C, 0x6EF83B97, 0xAF7F780B, 0x4613138A, + 0x7C3E73A6, 0xCF15E03D, 0x41576322, 0x672DF292, + 0xB658588D, 0x33EBEFA9, 0x938CBF06, 0x06B67381, + 0x07F192C6, 0x2BDA5855, 0x348EE0E8, 0x19DBB6E3, + 0x3222184B, 0xB69D5DBA, 0x7E760B88, 0xAF4D8154, + 0x007A51AD, 0x35112500, 0xC9CD2D7D, 0x4F4FB761, + 0x694772E3, 0x694C8351, 0x4A7E3AF5, 0x67D65CE1, + 0x9287DE92, 0x2518DB3C, 0x8CB4EC06, 0xD154D38F, + 0xE19A26BB, 0x295EE439, 0xC50A1104, 0x2153C6A7, + 0x82366656, 0x0713BC2F, 0x6462215A, 0x21D9BFCE, + 0xBA8EACE6, 0xAE2DF4C1, 0x2A8D5E80, 0x3F7E52D1, + 0x29359399, 0xFEA1D19C, 0x18879313, 0x455AFA81, + 0xFADFE838, 0x62609838, 0xD1028839, 0x0736E92F, + 0x3BCA22A3, 0x1485B08A, 0x2DA7900B, 0x852C156D, + 0xE8F24803, 0x00078472, 0x13F0D332, 0x2ACFD0CF, + 0x5F747F5C, 0x87BB1E2F, 0xA7EFCB63, 0x23F432F0, + 0xE6CE7C5C, 0x1F954EF6, 0xB609C91B, 0x3B4571BF, + 0xEED17DC0, 0xE556CDA0, 0xA7846A8D, 0xFF105F94, + 0x52B7CCDE, 0x0E33E801, 0x664455EA, 0xF2C70414, + 0x73E7B486, 0x8F830661, 0x8B59E826, 0xBB8AEDCA, + 0xF3D70AB9, 0xD739F2B9, 0x4A04C34A, 0x88D0F089, + 0xE02191A2, 0xD89D9C78, 0x192C2749, 0xFC43A78F, + 0x0AAC88CB, 0x9438D42D, 0x9E280F7A, 0x36063802, + 0x38E8D018, 0x1C42A9CB, 0x92AAFF6C, 0xA24820C5, + 0x007F077F, 0xCE5BC543, 0x69668D58, 0x10D6FF74, + 0xBE00F621, 0x21300BBE, 0x2E9E8F46, 0x5ACEA629, + 0xFA1F86C7, 0x52F206B8, 0x3EDF1A75, 0x6DA8D843, + 0xCF719928, 0x73E3891F, 0xB4B95DD6, 0xB2A42D27, + 0xEDA20BBF, 0x1A58DBDF, 0xA449AD03, 0x6DDEF22B, + 0x900531E6, 0x3D3BFF35, 0x5B24ABA2, 0x472B3E4C, + 0x387F2D75, 0x4D8DBA36, 0x71CB5641, 0xE3473F3F, + 0xF6CD4B7F, 0xBF7D1428, 0x344B64D0, 0xC5CDFCB6, + 0xFE2E0182, 0x2C37A673, 0xDE4EB7A3, 0x63FDC933, + 0x01DC4063, 0x611F3571, 0xD167BFAF, 0x4496596F, + 0x3DEE0689, 0xD8704910, 0x7052A114, 0x068C9EC5, + 0x75D0E766, 0x4D54CC20, 0xB44ECDE2, 0x4ABC653E, + 0x2C550A21, 0x1A52C0DB, 0xCFED03D0, 0x119BAFE2, + 0x876A6133, 0xBC232088, 0x435BA1B2, 0xAE99BBFA, + 0xBB4F08E4, 0xA62B5F49, 0x1DA4B695, 0x336B84DE, + 0xDC813D31, 0x00C134FB, 0x397A98E6, 0x151F0E64, + 0xD9EB3E69, 0xD3C7DF60, 0xD2F2C336, 0x2DDD067B, + 0xBD122835, 0xB0B3BD3A, 0xB0D54E46, 0x8641F1E4, + 0xA0B38F96, 0x51D39199, 0x37A6AD75, 0xDF84EE41, + 0x3C034CBA, 0xACDA62FC, 0x11923B8B, 0x45EF170A, +}; diff --git a/tools/virtualmips/sbox.h b/tools/virtualmips/sbox.h new file mode 100644 index 0000000..3e8cec3 --- /dev/null +++ b/tools/virtualmips/sbox.h @@ -0,0 +1,49 @@ +/* + * Cisco router simulation platform. + * Copyright (c) 2007 Christophe Fillot (cf@utc.fr) + * + * S-box functions. + */ + +#ifndef __SBOX_H__ +#define __SBOX_H__ + +#include +#include "utils.h" + +extern m_uint32_t sbox_array[]; + +static inline m_uint32_t sbox_compute (m_uint8_t * data, int len) +{ + m_uint32_t hash = 0; + + while (len > 0) { + hash ^= sbox_array[*data]; + hash *= 3; + data++; + } + + return (hash); +} + +static forced_inline m_uint32_t sbox_u32 (m_uint32_t val) +{ + m_uint32_t hash = 0; + + hash ^= sbox_array[(m_uint8_t) val]; + hash *= 3; + val >>= 8; + + hash ^= sbox_array[(m_uint8_t) val]; + hash *= 3; + val >>= 8; + + hash ^= sbox_array[(m_uint8_t) val]; + hash *= 3; + val >>= 8; + + hash ^= sbox_array[(m_uint8_t) val]; + return (hash); +} + +#endif diff --git a/tools/virtualmips/system.h b/tools/virtualmips/system.h new file mode 100644 index 0000000..71d18c4 --- /dev/null +++ b/tools/virtualmips/system.h @@ -0,0 +1,24 @@ + /* + * Copyright (C) yajin 2008 + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + * + */ + +#ifndef __SYSTEM_H__ +#define __SYSTEM_H__ + +#ifdef SIM_ADM5120 +#include "adm5120.h" +#endif + +#ifdef SIM_PAVO +#include "pavo.h" +#endif + +#ifdef SIM_PIC32 +#include "pic32.h" +#endif + +#endif diff --git a/tools/virtualmips/types.h b/tools/virtualmips/types.h new file mode 100644 index 0000000..dd1e9d2 --- /dev/null +++ b/tools/virtualmips/types.h @@ -0,0 +1,78 @@ + /* + * Copyright (C) yajin 2008 + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + * + */ + +#ifndef __TYPES_H__ +#define __TYPES_H__ + +#include + +/*types from qemu*/ +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; + +#if defined(__linux__) || defined(__APPLE__) +typedef u_int64_t uint64_t; +#endif + +#ifndef __sun__ +typedef signed char int8_t; +#endif +typedef signed short int16_t; +typedef signed int int32_t; + +/*used in dynamips. so just typedef again*/ +/* Common types */ +typedef uint8_t m_uint8_t; +typedef int8_t m_int8_t; + +typedef uint16_t m_uint16_t; +typedef int16_t m_int16_t; + +typedef uint32_t m_uint32_t; +typedef int32_t m_int32_t; + +typedef uint64_t m_uint64_t; +typedef int64_t m_int64_t; + +typedef unsigned long m_iptr_t; +typedef m_uint64_t m_tmcnt_t; + +#if defined (__x86_64__) || defined(__ia64) +/*function label address*/ +typedef m_uint64_t m_hiptr_t; +#else +typedef m_uint32_t m_hiptr_t; +#endif + +typedef void (*pvoid) (void); + +/* MIPS instruction */ +typedef m_uint32_t mips_insn_t; + +/* True/False definitions */ +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef TRUE +#define TRUE 1 +#endif + +//for gdb interface +/* Used for functions which can fail */ +enum result_t { SUCCESS, FAILURE, STALL, BUSERROR, SCFAILURE }; + +/* Forward declarations */ +typedef struct cpu_mips cpu_mips_t; +typedef struct vm_instance vm_instance_t; +typedef struct vdevice vdevice_t; +typedef struct mips_jit_tcb mips_jit_tcb_t; +typedef struct insn_exec_page insn_exec_page_t; + +#endif diff --git a/tools/virtualmips/utils.c b/tools/virtualmips/utils.c new file mode 100644 index 0000000..51c383b --- /dev/null +++ b/tools/virtualmips/utils.c @@ -0,0 +1,516 @@ +/* + * Cisco router simulation platform. + * Copyright (c) 2005,2006 Christophe Fillot. All rights reserved. + * + * Utility functions. + */ + /* + * Copyright (C) yajin 2008 + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + * + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef __CYGWIN__ +#include +#endif + +#include "utils.h" + +extern FILE *log_file; + +unsigned int get_file_size (const char *file_path) +{ + struct stat statbuf; + if (stat (file_path, &statbuf) == -1) { + printf ("Get stat on %s Error:%s\n", file_path, strerror (errno)); + return (0); + } + if (S_ISDIR (statbuf.st_mode)) + return (0); + if (S_ISREG (statbuf.st_mode)) + return (statbuf.st_size); + + return 0; +} + +/* Dynamic sprintf */ +char *dyn_sprintf (const char *fmt, ...) +{ + int n, size = 512; + va_list ap; + char *p, *p2; + + if ((p = malloc (size)) == NULL) { + perror ("dyn_sprintf: malloc"); + return NULL; + } + + for (;;) { + /* Try to print in the allocated space */ + va_start (ap, fmt); + n = vsnprintf (p, size, fmt, ap); + va_end (ap); + + /* If that worked, return the string */ + if ((n > -1) && (n < size)) + return p; + + /* Else try again with more space. */ + if (n > -1) + size = n + 1; + else + size *= 2; + free (p); + if ((p2 = malloc (size)) == NULL) { + perror ("dyn_sprintf: realloc"); + return NULL; + } + + p = p2; + } + free (p2); +} + +/* Split a string */ +int m_strsplit (char *str, char delim, char **array, int max_count) +{ + int i, pos = 0; + size_t len; + char *ptr; + + for (i = 0; i < max_count; i++) + array[i] = NULL; + + do { + if (pos == max_count) + goto error; + + ptr = strchr (str, delim); + if (!ptr) + ptr = str + strlen (str); + + len = ptr - str; + + if (!(array[pos] = malloc (len + 1))) + goto error; + + memcpy (array[pos], str, len); + array[pos][len] = 0; + + str = ptr + 1; + pos++; + } + while (*ptr); + return (pos); + + error: + for (i = 0; i < max_count; i++) + free (array[i]); + return (-1); +} + +/* Tokenize a string */ +int m_strtok (char *str, char delim, char **array, int max_count) +{ + int i, pos = 0; + size_t len; + char *ptr; + + for (i = 0; i < max_count; i++) + array[i] = NULL; + + do { + if (pos == max_count) + goto error; + + ptr = strchr (str, delim); + if (!ptr) + ptr = str + strlen (str); + + len = ptr - str; + + if (!(array[pos] = malloc (len + 1))) + goto error; + + memcpy (array[pos], str, len); + array[pos][len] = 0; + + while (*ptr == delim) + ptr++; + + str = ptr; + pos++; + } + while (*ptr); + + return (pos); + + error: + for (i = 0; i < max_count; i++) + free (array[i]); + return (-1); +} + +/* Quote a string */ +char *m_strquote (char *buffer, size_t buf_len, char *str) +{ + char *p; + + if (!(p = strpbrk (str, " \t\"'"))) + return str; + + snprintf (buffer, buf_len, "\"%s\"", str); + return buffer; +} + +/* Ugly function that dumps a structure in hexa and ascii. */ +void mem_dump (FILE * f_output, u_char * pkt, u_int len) +{ + u_int x, i = 0, tmp; + + while (i < len) { + if ((len - i) > 16) + x = 16; + else + x = len - i; + + fprintf (f_output, "%4.4x: ", i); + + for (tmp = 0; tmp < x; tmp++) + fprintf (f_output, "%2.2x ", pkt[i + tmp]); + for (tmp = x; tmp < 16; tmp++) + fprintf (f_output, " "); + + for (tmp = 0; tmp < x; tmp++) { + char c = pkt[i + tmp]; + + if (((c >= 'A') && (c <= 'Z')) || ((c >= 'a') && (c <= 'z')) + || ((c >= '0') && (c <= '9'))) + fprintf (f_output, "%c", c); + else + fputs (".", f_output); + } + + i += x; + fprintf (f_output, "\n"); + } + + fprintf (f_output, "\n"); +} + +/* Logging function */ +void m_flog (FILE * fd, char *module, char *fmt, va_list ap) +{ + struct timeval now; + static char buf[256]; + time_t ct; + + gettimeofday (&now, 0); + ct = now.tv_sec; + strftime (buf, sizeof (buf), "%b %d %H:%M:%S", localtime (&ct)); + if (fd) { + fprintf (fd, "%s.%03ld %s: ", buf, (long) now.tv_usec / 1000, module); + vfprintf (fd, fmt, ap); + fflush (fd); + } +} + +#if 0 +/* Logging function */ +void m_log (char *module, char *fmt, ...) +{ + va_list ap; + + va_start (ap, fmt); + m_flog (log_file, module, fmt, ap); + va_end (ap); +} +#endif + +/* Returns a line from specified file (remove trailing '\n') */ +char *m_fgets (char *buffer, int size, FILE * fd) +{ + int len; + + buffer[0] = '\0'; + if (fgets (buffer, size, fd) == NULL) + return NULL; + + len = strlen (buffer); + if (len == 0) + return NULL; + + /* remove trailing '\n' */ + if (buffer[len - 1] == '\n') + buffer[len - 1] = '\0'; + + return buffer; +} + +/* Read a file and returns it in a buffer */ +ssize_t m_read_file (char *filename, char **buffer) +{ + char tmp[256], *ptr, *nptr; + size_t len, tot_len; + FILE *fd; + + *buffer = ptr = NULL; + tot_len = 0; + + /* Open file for reading */ + if ((fd = fopen (filename, "r")) == NULL) + return (-1); + + while ((len = fread (tmp, 1, sizeof (tmp), fd)) > 0) { + /* Reallocate memory */ + nptr = realloc (ptr, tot_len + len + 1); + if (nptr == NULL) { + if (ptr) + free (ptr); + fclose (fd); + return (-1); + } + + ptr = nptr; + + /* Ok, memory could be allocated */ + memcpy (&ptr[tot_len], tmp, len); + tot_len += len; + } + + fclose (fd); + *buffer = ptr; + return (tot_len); +} + +/* Allocate aligned memory */ +void *m_memalign (size_t boundary, size_t size) +{ + void *p; + +#if defined(__linux__) || defined(__APPLE__) + if (posix_memalign ((void *) &p, boundary, size)) +#else +#if defined(__CYGWIN__) || defined(SUNOS) + if (!(p = memalign (boundary, size))) +#else + if (!(p = malloc (size))) +#endif +#endif + return NULL; + + assert (((m_iptr_t) p & (boundary - 1)) == 0); + return p; +} + +/* Block specified signal for calling thread */ +int m_signal_block (int sig) +{ + sigset_t sig_mask; + sigemptyset (&sig_mask); + sigaddset (&sig_mask, sig); + return (pthread_sigmask (SIG_BLOCK, &sig_mask, NULL)); +} + +/* Unblock specified signal for calling thread */ +int m_signal_unblock (int sig) +{ + sigset_t sig_mask; + sigemptyset (&sig_mask); + sigaddset (&sig_mask, sig); + return (pthread_sigmask (SIG_UNBLOCK, &sig_mask, NULL)); +} + +/* Set non-blocking mode on a file descriptor */ +int m_fd_set_non_block (int fd) +{ + int flags; + + if ((flags = fcntl (fd, F_GETFL, 0)) < 1) + return (-1); + + return (fcntl (fd, F_SETFL, flags | O_NONBLOCK)); +} + +/* Map a memory zone from a file */ +u_char *memzone_map_file (int fd, size_t len) +{ + return (mmap (NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, + (off_t) 0)); +} + +/* Map a memory zone from a file, with copy-on-write (COW) */ +u_char *memzone_map_cow_file (int fd, size_t len) +{ + return (mmap (NULL, len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, + (off_t) 0)); +} + +/* Create a file to serve as a memory zone */ +int memzone_create_file (char *filename, size_t len, u_char ** ptr) +{ + int fd; + + if ((fd = open (filename, O_CREAT | O_RDWR, S_IRWXU)) == -1) { + perror ("memzone_create_file: open"); + return (-1); + } + + if (ftruncate (fd, len) == -1) { + perror ("memzone_create_file: ftruncate"); + close (fd); + return (-1); + } + + *ptr = memzone_map_file (fd, len); + + if (!*ptr) { + close (fd); + fd = -1; + } + + return (fd); +} + +/* Open a file to serve as a COW memory zone */ +int memzone_open_cow_file (char *filename, size_t len, u_char ** ptr) +{ + int fd; + + if ((fd = open (filename, O_RDWR, S_IRWXU)) == -1) { + perror ("memzone_open_file: open"); + return (-1); + } + + *ptr = memzone_map_cow_file (fd, len); + + if (!*ptr) { + close (fd); + fd = -1; + } + + return (fd); +} + +/* Open a file and map it in memory */ +int memzone_open_file (char *filename, u_char ** ptr, off_t * fsize) +{ + struct stat fprop; + int fd; + + if ((fd = open (filename, O_RDWR, S_IRWXU)) == -1) + return (-1); + + if (fstat (fd, &fprop) == -1) + goto err_fstat; + + *fsize = fprop.st_size; + if (!(*ptr = memzone_map_file (fd, *fsize))) + goto err_mmap; + + return (fd); + + err_mmap: + err_fstat: + close (fd); + return (-1); +} + +/* Compute NVRAM checksum */ +m_uint16_t nvram_cksum (m_uint16_t * ptr, size_t count) +{ + m_uint32_t sum = 0; + + while (count > 1) { + sum = sum + ntohs (*ptr); + ptr++; + count -= sizeof (m_uint16_t); + } + + if (count > 0) + sum = sum + ((ntohs (*ptr) & 0xFF) << 8); + + while (sum >> 16) + sum = (sum & 0xffff) + (sum >> 16); + + return (~sum); +} + +/* Byte-swap a memory block */ +void mem_bswap32 (void *ptr, size_t len) +{ + m_uint32_t *p = ptr; + size_t count = len >> 2; + int i; + + for (i = 0; i < count; i++, p++) + *p = swap32 (*p); +} + +/* Reverse a byte */ +m_uint8_t m_reverse_u8 (m_uint8_t val) +{ + m_uint8_t res = 0; + int i; + + for (i = 0; i < 8; i++) + if (val & (1 << i)) + res |= 1 << (7 - i); + + return (res); +} + +void SubstituteLLx (char *out, const char *text, int maxlen) +{ + int i; + for (i = 0; i < maxlen && text[i]; i++) { + out[i] = text[i]; + } + out[i] = text[i]; +} + +/***************************************************************** + * Debug + * Print a debug message, if flag is enabled. Like printf, + * only with an extra argument on the front. + * to output debug infomation , you should excute "simos -d [flag]" + ****************************************************************/ +void Debug (char flag, char *format, ...) +{ + // if (DebugIsEnabled(flag)) { + char llformat[1024]; + va_list ap; + va_start (ap, format); + + SubstituteLLx (llformat, format, 1024); + + /* Make this go to stderr also... */ + vfprintf (stderr, llformat, ap); + + //vCPUPrint(llformat, ap); + fprintf (stderr, "\r"); + fflush (stderr); + va_end (ap); + + //} +} diff --git a/tools/virtualmips/utils.h b/tools/virtualmips/utils.h new file mode 100644 index 0000000..b40f256 --- /dev/null +++ b/tools/virtualmips/utils.h @@ -0,0 +1,348 @@ + /* + * Copyright (C) yajin 2008 + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + * + */ + +#ifndef __UTILS_H__ +#define __UTILS_H__ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "types.h" +#include "system.h" + +/* Endianness */ +#define ARCH_BIG_ENDIAN 0x4321 +#define ARCH_LITTLE_ENDIAN 0x1234 + +#if defined(PPC) || defined(__powerpc__) || defined(__ppc__) +#define HOST_BYTE_ORDER ARCH_BIG_ENDIAN +#elif defined(__sparc) || defined(__sparc__) +#define HOST_BYTE_ORDER ARCH_BIG_ENDIAN +#elif defined(__alpha) || defined(__alpha__) +#define HOST_BYTE_ORDER ARCH_LITTLE_ENDIAN +#elif defined(__i386) || defined(__i386__) || defined(i386) +#define HOST_BYTE_ORDER ARCH_LITTLE_ENDIAN +#elif defined(__x86_64__) +#define HOST_BYTE_ORDER ARCH_LITTLE_ENDIAN +#endif + +#ifndef HOST_BYTE_ORDER +#error Please define your architecture in utils.h! +#endif + +#if __GNUC__ > 2 +#define forced_inline inline __attribute__((always_inline)) +#define no_inline __attribute__ ((noinline)) +/* http://kerneltrap.org/node/4705 */ +#define likely(x) __builtin_expect((x),1) +#define unlikely(x) __builtin_expect((x),0) +#else +#define forced_inline inline +#define no_inline +#define likely(x) (x) +#define unlikely(x) (x) +#endif + +#define fastcall __attribute__((regparm(3))) +#define asmlinkage __attribute__((regparm(0))) + +#define ASSERT(a,format,args...) do{ if ((format!=NULL)&&(!(a))) fprintf(stderr,format, ##args); assert((a));} while(0) + +/* BOOT METHOD */ +enum { + BOOT_BINARY = 1, + BOOT_ELF = 2, +}; +/* BOOT FROM */ +enum { + BOOT_FROM_NOR_FLASH = 1, + BOOT_FROM_NAND_FLASH = 2, +}; +/* FLASH TYPE */ +enum { + FLASH_TYPE_NOR_FLASH = 1, + FLASH_TYPE_NAND_FLASH = 2, +}; + +/* Size of a field in a structure */ +#define SIZEOF(st,field) (sizeof(((st *)NULL)->field)) + +/* Compute offset of a field in a structure */ +#define OFFSET(st,f) ((long)&((st *)(NULL))->f) +/* Max and min macro */ +#define m_max(a,b) (((a) > (b)) ? (a) : (b)) +#define m_min(a,b) (((a) < (b)) ? (a) : (b)) + +/* MTS mapping info */ +typedef struct { + m_va_t vaddr; + m_pa_t paddr; + m_uint64_t len; + + // m_uint32_t cached; + m_uint32_t tlb_index; + m_uint8_t mapped; + m_uint8_t dirty; + m_uint8_t valid; + m_uint32_t asid; + m_uint8_t g_bit; + +} mts_map_t; + +/* Invalid VTLB entry */ +#define MTS_INV_ENTRY_MASK 0x00000001 + +/* MTS entry flags */ +#define MTS_FLAG_DEV 0x000000001 /* Virtual device used */ +#define MTS_FLAG_COW 0x000000002 /* Copy-On-Write */ +#define MTS_FLAG_EXEC 0x000000004 /* Exec page */ + +/* Virtual TLB entry (32-bit MMU) */ + +struct mts32_entry { + m_uint32_t gvpa; /* Guest Virtual Page Address */ + m_uint32_t gppa; /* Guest Physical Page Address */ + m_iptr_t hpa; /* Host Page Address */ + m_uint32_t asid; + m_uint8_t g_bit; + m_uint8_t dirty_bit; + m_uint8_t mapped; + m_uint32_t flags; /* Flags */ +} __attribute__ ((aligned (16))); +typedef struct mts32_entry mts32_entry_t; + +/* Virtual TLB entry (64-bit MMU) */ + +struct mts64_entry { + m_va_t gvpa; /* Guest Virtual Page Address */ + m_pa_t gppa; /* Guest Physical Page Address */ + m_iptr_t hpa; /* Host Page Address */ + m_uint32_t flags; /* Flags */ +} __attribute__ ((aligned (16))); +typedef struct mts64_entry mts64_entry_t; + +/* Host register allocation */ +#define HREG_FLAG_ALLOC_LOCKED 1 +#define HREG_FLAG_ALLOC_FORCED 2 + +struct hreg_map { + int hreg, vreg; + int flags; + struct hreg_map *prev, *next; +}; + +/* Global logfile */ +extern FILE *log_file; + +/* Check status of a bit */ +static inline int check_bit (u_int old, u_int new, u_int bit) +{ + int mask = 1 << bit; + + if ((old & mask) && !(new & mask)) + return (1); /* bit unset */ + + if (!(old & mask) && (new & mask)) + return (2); /* bit set */ + + /* no change */ + return (0); +} + +/* Sign-extension */ +#if DATA_WIDTH==64 +static forced_inline m_int64_t sign_extend (m_int64_t x, int len) +#elif DATA_WIDTH==32 +static forced_inline m_int32_t sign_extend (m_int32_t x, int len) +#else +#error Undefined DATA_WIDTH +#endif +{ + len = DATA_WIDTH - len; + return (x << len) >> len; +} + +/* Sign-extension (32-bit) */ +static forced_inline m_int32_t sign_extend_32 (m_int32_t x, int len) +{ + len = 32 - len; + return (x << len) >> len; +} + +/* Extract bits from a 32-bit values */ +static inline int bits (m_uint32_t val, int start, int end) +{ + return ((val >> start) & ((1 << (end - start + 1)) - 1)); +} + +/* Normalize a size */ +static inline u_int normalize_size (u_int val, u_int nb, int shift) +{ + return (((val + nb - 1) & ~(nb - 1)) >> shift); +} + +/* Convert a 16-bit number between little and big endian */ +static forced_inline m_uint16_t swap16 (m_uint16_t value) +{ + return ((value >> 8) | ((value & 0xFF) << 8)); +} + +/* Convert a 32-bit number between little and big endian */ +static forced_inline m_uint32_t swap32 (m_uint32_t value) +{ + m_uint32_t result; + + result = value >> 24; + result |= ((value >> 16) & 0xff) << 8; + result |= ((value >> 8) & 0xff) << 16; + result |= (value & 0xff) << 24; + return (result); +} + +/* Convert a 64-bit number between little and big endian */ +static forced_inline m_uint64_t swap64 (m_uint64_t value) +{ + m_uint64_t result; + + result = (m_uint64_t) swap32 (value & 0xffffffff) << 32; + result |= swap32 (value >> 32); + return (result); +} + +/* Get current time in number of msec since epoch */ +static inline m_tmcnt_t m_gettime (void) +{ + struct timeval tvp; + + gettimeofday (&tvp, NULL); + return (((m_tmcnt_t) tvp.tv_sec * 1000) + + ((m_tmcnt_t) tvp.tv_usec / 1000)); +} + +/* Get current time in number of usec since epoch */ +static inline m_tmcnt_t m_gettime_usec (void) +{ + struct timeval tvp; + + gettimeofday (&tvp, NULL); + return (((m_tmcnt_t) tvp.tv_sec * 1000000) + (m_tmcnt_t) tvp.tv_usec); +} + +#ifdef __CYGWIN__ +#define GET_TIMEZONE _timezone +#else +#define GET_TIMEZONE timezone +#endif + +/* Get current time in number of ms (localtime) */ +static inline m_tmcnt_t m_gettime_adj (void) +{ + struct timeval tvp; + struct tm tmx; + time_t gmt_adjust; + time_t ct; + + gettimeofday (&tvp, NULL); + ct = tvp.tv_sec; + localtime_r (&ct, &tmx); + +#if defined(__CYGWIN__) || defined(SUNOS) + gmt_adjust = -(tmx.tm_isdst ? GET_TIMEZONE - 3600 : GET_TIMEZONE); +#else + gmt_adjust = tmx.tm_gmtoff; +#endif + + tvp.tv_sec += gmt_adjust; + return (((m_tmcnt_t) tvp.tv_sec * 1000) + + ((m_tmcnt_t) tvp.tv_usec / 1000)); +} + +//#if 0 +#define DEBUGGING_DISABLED +//#endif +#ifndef DEBUGGING_DISABLED +#define SIM_DEBUG(arg1) Debug arg1 +#else +#define SIM_DEBUG(arg1) +#endif + +/*return a file size*/ +unsigned int get_file_size (const char *filename); + +/* Dynamic sprintf */ +char *dyn_sprintf (const char *fmt, ...); + +/* Split a string */ +int m_strsplit (char *str, char delim, char **array, int max_count); + +/* Tokenize a string */ +int m_strtok (char *str, char delim, char **array, int max_count); + +/* Quote a string */ +char *m_strquote (char *buffer, size_t buf_len, char *str); + +/* Ugly function that dumps a structure in hexa and ascii. */ +void mem_dump (FILE * f_output, u_char * pkt, u_int len); + +/* Logging function */ +void m_flog (FILE * fd, char *module, char *fmt, va_list ap); + +/* Logging function */ +//void m_log(char *module,char *fmt,...); + +/* Returns a line from specified file (remove trailing '\n') */ +char *m_fgets (char *buffer, int size, FILE * fd); + +/* Read a file and returns it in a buffer */ +ssize_t m_read_file (char *filename, char **buffer); + +/* Allocate aligned memory */ +void *m_memalign (size_t boundary, size_t size); + +/* Block specified signal for calling thread */ +int m_signal_block (int sig); + +/* Unblock specified signal for calling thread */ +int m_signal_unblock (int sig); + +/* Set non-blocking mode on a file descriptor */ +int m_fd_set_non_block (int fd); + +/* Map a memory zone from a file */ +u_char *memzone_map_file (int fd, size_t len); + +/* Map a memory zone from a file, with copy-on-write (COW) */ +u_char *memzone_map_cow_file (int fd, size_t len); + +/* Create a file to serve as a memory zone */ +int memzone_create_file (char *filename, size_t len, u_char ** ptr); + +/* Open a file to serve as a COW memory zone */ +int memzone_open_cow_file (char *filename, size_t len, u_char ** ptr); + +/* Open a file and map it in memory */ +int memzone_open_file (char *filename, u_char ** ptr, off_t * fsize); + +/* Compute NVRAM checksum */ +m_uint16_t nvram_cksum (m_uint16_t * ptr, size_t count); + +/* Byte-swap a memory block */ +void mem_bswap32 (void *ptr, size_t len); + +/* Reverse a byte */ +m_uint8_t m_reverse_u8 (m_uint8_t val); +void Debug (char flag, char *format, ...); + +#endif diff --git a/tools/virtualmips/vm.c b/tools/virtualmips/vm.c new file mode 100644 index 0000000..aa96f35 --- /dev/null +++ b/tools/virtualmips/vm.c @@ -0,0 +1,458 @@ +/* + * Cisco router simulation platform. + * Copyright (c) 2005,2006 Christophe Fillot (cf@utc.fr) + * + * Virtual machine abstraction. + */ + /* + * Copyright (C) yajin 2008 + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + * + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include + +#include "device.h" +#include "cpu.h" +#include "vm.h" +#include "dev_vtty.h" +#include "debug.h" + +/* Get VM type */ +char *vm_get_type (vm_instance_t * vm) +{ + char *machine; + + switch (vm->type) { + case VM_TYPE_SWARM: + machine = "swarm"; + break; + case VM_TYPE_ADM5120: + machine = "ADM5120"; + break; + case VM_TYPE_PAVO: + machine = "PAVO"; + break; + case VM_TYPE_PIC32: + machine = "PIC32"; + break; + default: + machine = "unknown"; + break; + } + return machine; +} + +/* Get platform type */ +char *vm_get_platform_type (vm_instance_t * vm) +{ + char *machine; + + switch (vm->type) { + case VM_TYPE_SWARM: + machine = "swarm"; + break; + case VM_TYPE_ADM5120: + machine = "ADM5120"; + break; + case VM_TYPE_PIC32: + machine = "PIC32"; + break; + default: + machine = "VM"; + break; + } + + return machine; +} + +/* Generate a filename for use by the instance */ +static char *vm_build_filename (vm_instance_t * vm, char *name) +{ + char *filename; + + filename = dyn_sprintf ("%s-%s", vm->name, name); + + assert (filename != NULL); + return filename; +} + +/* Log a message */ +void vm_flog (vm_instance_t * vm, char *module, char *format, va_list ap) +{ + if (vm->log_fd) + m_flog (vm->log_fd, module, format, ap); +} + +/* Log a message */ +void vm_log (vm_instance_t * vm, char *module, char *format, ...) +{ + va_list ap; + + if (vm->log_fd) { + va_start (ap, format); + vm_flog (vm, module, format, ap); + va_end (ap); + } +} + +/* Close the log file */ +int vm_close_log (vm_instance_t * vm) +{ + if (vm->log_fd) + fclose (vm->log_fd); + + free (vm->log_file); + + vm->log_file = NULL; + vm->log_fd = NULL; + return (0); +} + +/* Create the log file */ +int vm_create_log (vm_instance_t * vm) +{ + if (vm->log_file_enabled) { + vm_close_log (vm); + + if (!(vm->log_file = vm_build_filename (vm, "log.txt"))) + return (-1); + + if (!(vm->log_fd = fopen (vm->log_file, "w"))) { + fprintf (stderr, "VM %s: unable to create log file '%s'\n", + vm->name, vm->log_file); + free (vm->log_file); + vm->log_file = NULL; + return (-1); + } + } + + return (0); +} + +/* Error message */ +void vm_error (vm_instance_t * vm, char *format, ...) +{ + char buffer[2048]; + va_list ap; + + va_start (ap, format); + vsnprintf (buffer, sizeof (buffer), format, ap); + va_end (ap); + + fprintf (stderr, "%s '%s': %s", vm_get_platform_type (vm), vm->name, + buffer); +} + +/* Create a new VM instance */ +vm_instance_t *vm_create (const char *name, int machine_type) +{ + vm_instance_t *vm; + int i; + + vm = malloc (sizeof (*vm)); + if (!vm) { + fprintf (stderr, "VM %s: unable to create new instance!\n", name); + return NULL; + } + + memset (vm, 0, sizeof (*vm)); + vm->type = machine_type; + vm->status = VM_STATUS_HALTED; + vm->jit_use = 0; + vm->vtty_type[0] = VTTY_TYPE_TERM; + for (i=1; ivtty_type[i] = VTTY_TYPE_NONE; + //vm->timer_irq_check_itv = VM_TIMER_IRQ_CHECK_ITV; + vm->log_file_enabled = TRUE; + + vm->name = strdup (name); + if (!name) { + fprintf (stderr, "VM %s: unable to store instance name!\n", name); + goto err_name; + } + + /* create log file */ + if (vm_create_log (vm) == -1) { + free (vm->name); + err_name: + free (vm); + return NULL; + } + return vm; +} + +/* + * Shutdown hardware resources used by a VM. + * The CPU must have been stopped. + */ +static int vm_hardware_shutdown (vm_instance_t * vm) +{ + //int i; + + if ((vm->status == VM_STATUS_HALTED) || !vm->cpu_group) { + vm_log (vm, "VM", "trying to shutdown an inactive VM.\n"); + return (-1); + } + + vm_log (vm, "VM", "shutdown procedure engaged.\n"); + + /* Mark the VM as halted */ + vm->status = VM_STATUS_HALTED; + + /* Disable NVRAM operations */ + // vm->nvram_extract_config = NULL; + // vm->nvram_push_config = NULL; + + /* Free the object list */ + // vm_object_free_list(vm); + + /* Free resources used by PCI busses */ + // vm_log(vm,"VM","removing PCI busses.\n"); + // pci_io_data_remove(vm,vm->pci_io_space); + // pci_bus_remove(vm->pci_bus[0]); + // pci_bus_remove(vm->pci_bus[1]); + // vm->pci_bus[0] = vm->pci_bus[1] = NULL; + + /* Free the PCI bus pool */ + /* for(i=0;ipci_bus_pool[i] != NULL) { + * pci_bus_remove(vm->pci_bus_pool[i]); + * vm->pci_bus_pool[i] = NULL; + * } + * } */ + + /* Remove the IRQ routing vectors */ + vm->set_irq = NULL; + vm->clear_irq = NULL; + + /* Delete the VTTY for Console and AUX ports */ + vm_log (vm, "VM", "deleting VTTY.\n"); + vm_delete_vtty (vm); + + /* Delete system CPU group */ + vm_log (vm, "VM", "deleting system CPUs.\n"); + cpu_group_delete (vm->cpu_group); + vm->cpu_group = NULL; + vm->boot_cpu = NULL; + + vm_log (vm, "VM", "shutdown procedure completed.\n"); + return (0); +} + +/* Free resources used by a VM */ +void vm_free (vm_instance_t * vm) +{ + if (vm != NULL) { + /* Free hardware resources */ + vm_hardware_shutdown (vm); + + /* Close log file */ + vm_close_log (vm); + + /* Remove the lock file */ + // vm_release_lock(vm,TRUE); + + /* Free all chunks */ + // vm_chunk_free_all(vm); + + /* Free various elements */ + // free(vm->ghost_ram_filename); + // free(vm->sym_filename); + //free(vm->ios_image); + // free(vm->ios_config); + //free(vm->rom_filename); + free (vm->name); + free (vm); + } +} + +int dev_ram_init (vm_instance_t * vm, char *name, m_pa_t paddr, + m_uint32_t len); + +/* + * Initialize RAM + */ +int vm_ram_init (vm_instance_t * vm, m_pa_t paddr) +{ + m_uint32_t len; + + len = vm->ram_size * 1024; + +#ifdef SIM_PAVO +/* +Why plus 0x2000 (8k) for PAVO?? +It seems that jz4740 has an extra 8k boot memory. +I am not sure. But uboot use the extra memory space beyond 64M memory space. +So I just add 0x2000 to ram. +*/ + len += 0x2000; +#endif + return (dev_ram_init (vm, "ram", paddr, len)); +} + +/* Initialize VTTY */ +int vm_init_vtty (vm_instance_t * vm) +{ + int i; + + /* Create Console and AUX ports */ + vm->vtty_con[0] = vtty_create (vm, "Console port", + vm->vtty_type[0], vm->vtty_tcp_port[0], + &vm->vtty_serial_option[0]); + + for (i=1; ivtty_con[i] = vtty_create (vm, "UART port", + vm->vtty_type[i], vm->vtty_tcp_port[i], + &vm->vtty_serial_option[i]); + return (0); +} + +/* Delete VTTY */ +void vm_delete_vtty (vm_instance_t * vm) +{ + int i; + + for (i=0; ivtty_con[i]); + vm->vtty_con[i] = NULL; + } +} + +/* Bind a device to a virtual machine */ +int vm_bind_device (vm_instance_t * vm, struct vdevice *dev) +{ + struct vdevice **cur; + u_int i; + + /* + * Add this device to the device array. The index in the device array + * is used by the MTS subsystem. + */ + for (i = 0; i < VM_DEVICE_MAX; i++) + if (!vm->dev_array[i]) + break; + + if (i == VM_DEVICE_MAX) { + fprintf (stderr, "VM: vm_bind_device: device table full.\n"); + return (-1); + } + + vm->dev_array[i] = dev; + dev->id = i; + + /* + * Add it to the linked-list (devices are ordered by physical addresses). + */ + for (cur = &vm->dev_list; *cur; cur = &(*cur)->next) + if ((*cur)->phys_addr > dev->phys_addr) + break; + + dev->next = *cur; + if (*cur) + (*cur)->pprev = &dev->next; + dev->pprev = cur; + *cur = dev; + return (0); +} + +/* Unbind a device from a virtual machine */ +int vm_unbind_device (vm_instance_t * vm, struct vdevice *dev) +{ + u_int i; + + if (!dev || !dev->pprev) + return (-1); + + /* Remove the device from the linked list */ + if (dev->next) + dev->next->pprev = dev->pprev; + + *(dev->pprev) = dev->next; + + /* Remove the device from the device array */ + for (i = 0; i < VM_DEVICE_MAX; i++) + if (vm->dev_array[i] == dev) { + vm->dev_array[i] = NULL; + break; + } + + /* Clear device list info */ + dev->next = NULL; + dev->pprev = NULL; + return (0); +} + +/* Map a device at the specified physical address */ +int vm_map_device (vm_instance_t * vm, struct vdevice *dev, m_pa_t base_addr) +{ +#if 0 + /* Suspend VM activity */ + vm_suspend (vm); + + if (cpu_group_sync_state (vm->cpu_group) == -1) { + fprintf (stderr, "VM%u: unable to sync with system CPUs.\n", + vm->instance_id); + return (-1); + } +#endif + + /* Unbind the device if it was already active */ + vm_unbind_device (vm, dev); + + /* Map the device at the new base address and rebuild MTS */ + dev->phys_addr = base_addr; + vm_bind_device (vm, dev); + cpu_group_rebuild_mts (vm->cpu_group); + +#if 0 + vm_resume (vm); +#endif + return (0); +} + +/* Suspend a VM instance */ +int vm_suspend (vm_instance_t * vm) +{ + if (vm->status == VM_STATUS_RUNNING) { + cpu_group_save_state (vm->cpu_group); + cpu_group_set_state (vm->cpu_group, CPU_STATE_SUSPENDED); + vm->status = VM_STATUS_SUSPENDED; + } + return (0); +} + +/* Resume a VM instance */ +int vm_resume (vm_instance_t * vm) +{ + if (vm->status == VM_STATUS_SUSPENDED) { + cpu_group_restore_state (vm->cpu_group); + vm->status = VM_STATUS_RUNNING; + } + return (0); +} + +/* Stop an instance */ +int vm_stop (vm_instance_t * vm) +{ + cpu_group_stop_all_cpu (vm->cpu_group); + vm->status = VM_STATUS_SHUTDOWN; + return (0); +} + +/* Monitor an instance periodically */ +void vm_monitor (vm_instance_t * vm) +{ + while (vm->status != VM_STATUS_SHUTDOWN) + usleep (1000); +} diff --git a/tools/virtualmips/vm.h b/tools/virtualmips/vm.h new file mode 100644 index 0000000..1428e12 --- /dev/null +++ b/tools/virtualmips/vm.h @@ -0,0 +1,129 @@ +/* + * Cisco router simulation platform. + * Copyright (c) 2005,2006 Christophe Fillot (cf@utc.fr) + * + * Virtual machine abstraction. + */ + /* + * Copyright (C) yajin 2008 + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + * + */ + +#ifndef __VM_H__ +#define __VM_H__ + +#include + +#include "cpu.h" +#include "dev_vtty.h" +#include "system.h" +#include "gdb_interface.h" + +#define VM_PAGE_SHIFT 12 +#define VM_PAGE_SIZE (1 << VM_PAGE_SHIFT) +#define VM_PAGE_IMASK (VM_PAGE_SIZE - 1) +#define VM_PAGE_MASK (~(VM_PAGE_IMASK)) + +/* Maximum number of devices per VM */ +#define VM_DEVICE_MAX (1 << 6) +/* VM types */ +enum { + VM_TYPE_SWARM = 0, + VM_TYPE_ADM5120, + VM_TYPE_PIC32, + VM_TYPE_PAVO, +}; + +/* VM instance status */ +enum { + VM_STATUS_HALTED = 0, /* VM is halted and no HW resources are used */ + VM_STATUS_SHUTDOWN, /* Shutdown procedure engaged */ + VM_STATUS_RUNNING, /* VM is running */ + VM_STATUS_SUSPENDED, /* VM is suspended */ +}; + +/* VM instance */ +struct vm_instance { + char *name; + int type; + int status; /* Instance status */ + + char *log_file; /* Log filename */ + int log_file_enabled; /* Logging enabled */ + u_int ram_size; /* RAM size in Mb */ + //u_int rom_size; /* ROM size in Mb */ + //char *rom_filename; /* ROM filename */ + //m_pa_t rom_address; /* ROM phy address */ + + u_int flash_size; /* FLASH size in Mb */ + char *flash_filename; /* FLASH filename */ + m_pa_t flash_address; /* FLASH phy address */ + u_int flash_type; /* NAND Flash OR NOR FLASH */ + + u_int boot_method; /* binary or elf */ + char *kernel_filename; + u_int boot_from; + + char *configure_filename; + + FILE *lock_fd, *log_fd; /* Lock/Log file descriptors */ + int debug_level; /* Debugging Level */ + u_int trace_address; /* Trace this address */ + int jit_use; /* CPUs use JIT */ + + /* Basic hardware: system CPU */ + cpu_group_t *cpu_group; + cpu_mips_t *boot_cpu; + + /* Memory mapped devices */ + struct vdevice *dev_list; + struct vdevice *dev_array[VM_DEVICE_MAX]; + + /* IRQ routing */ + void (*set_irq) (vm_instance_t * vm, u_int irq); + void (*clear_irq) (vm_instance_t * vm, u_int irq); + + /* Console VTTY type and parameters */ +#define NVTTY 6 + int vtty_type [NVTTY]; + int vtty_tcp_port[NVTTY]; + vtty_serial_option_t vtty_serial_option[NVTTY]; + /* Virtual TTY for Console and AUX ports */ + vtty_t *vtty_con [NVTTY]; + + /* Specific hardware data */ + void *hw_data; + + /* gdb interface */ + m_uint32_t gdb_debug, gdb_port; + int gdb_interact_sock; //connect socket + int gdb_listen_sock; //listen socket + int gdb_debug_from_poll; + virtual_breakpoint_t *breakpoint_head, *breakpoint_tail; + int mipsy_debug_mode; + int mipsy_break_nexti; +}; + +char *vm_get_type (vm_instance_t * vm); +char *vm_get_platform_type (vm_instance_t * vm); +void vm_flog (vm_instance_t * vm, char *module, char *format, va_list ap); +void vm_log (vm_instance_t * vm, char *module, char *format, ...); +int vm_close_log (vm_instance_t * vm); +int vm_create_log (vm_instance_t * vm); +void vm_error (vm_instance_t * vm, char *format, ...); +vm_instance_t *vm_create (const char *name, int machine_type); +void vm_free (vm_instance_t * vm); +int vm_ram_init (vm_instance_t * vm, m_pa_t paddr); +int vm_init_vtty (vm_instance_t * vm); +void vm_delete_vtty (vm_instance_t * vm); +int vm_bind_device (vm_instance_t * vm, struct vdevice *dev); +int vm_unbind_device (vm_instance_t * vm, struct vdevice *dev); +int vm_map_device (vm_instance_t * vm, struct vdevice *dev, m_pa_t base_addr); +int vm_suspend (vm_instance_t * vm); +int vm_resume (vm_instance_t * vm); +int vm_stop (vm_instance_t * vm); +void vm_monitor (vm_instance_t * vm); +#endif diff --git a/tools/virtualmips/vp_clock.c b/tools/virtualmips/vp_clock.c new file mode 100644 index 0000000..55da534 --- /dev/null +++ b/tools/virtualmips/vp_clock.c @@ -0,0 +1,72 @@ + /* + * Copyright (C) yajin 2008 + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + * + */ + +#include +#include +#include "utils.h" +#include "vp_clock.h" + +static int use_rt_clock; +vp_clock_t *rt_clock; +vp_clock_t *vm_clock; + +void init_get_clock (void) +{ + use_rt_clock = 0; +#if defined(__linux__) + { + struct timespec ts; + if (clock_gettime (CLOCK_MONOTONIC, &ts) == 0) { + use_rt_clock = 1; + } + } +#endif +} + +/*ns*/ +static m_int64_t get_clock (void) +{ +#if defined(__linux__) + if (use_rt_clock) { + struct timespec ts; + clock_gettime (CLOCK_MONOTONIC, &ts); + return ts.tv_sec * 1000000000LL + ts.tv_nsec; + } else +#endif + { + /* XXX: using gettimeofday leads to problems if the date + * changes, so it should be avoided. */ + struct timeval tv; + gettimeofday (&tv, NULL); + return tv.tv_sec * 1000000000LL + (tv.tv_usec * 1000); + } +} + +/*ms*/ +m_int64_t vp_get_clock (vp_clock_t * clock) +{ + switch (clock->type) { + case VP_TIMER_REALTIME: + return get_clock () / 1000000; + default: + case VP_TIMER_VIRTUAL: + ASSERT (0, "not support yet\n"); + } + return 0; +} + +vp_clock_t *vp_new_clock (int type) +{ + vp_clock_t *clock; + clock = malloc (sizeof (vp_clock_t)); + memset (clock, 0x0, sizeof (*clock)); + if (!clock) + return NULL; + clock->type = type; + return clock; +} diff --git a/tools/virtualmips/vp_clock.h b/tools/virtualmips/vp_clock.h new file mode 100644 index 0000000..d310f30 --- /dev/null +++ b/tools/virtualmips/vp_clock.h @@ -0,0 +1,31 @@ + /* + * Copyright (C) yajin 2008 + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + * + */ + +#ifndef __VP_CLOCK_H__ +#define __VP_CLOCK_H__ + +#include "utils.h" +/*clock utils from qemu*/ + +#define VP_TIMER_REALTIME 0 +#define VP_TIMER_VIRTUAL 1 + +struct vp_clock { + int type; + /* XXX: add frequency */ +}; +typedef struct vp_clock vp_clock_t; + +extern vp_clock_t *rt_clock; +extern vp_clock_t *vm_clock; + +void init_get_clock (void); +vp_clock_t *vp_new_clock (int type); +m_int64_t vp_get_clock (vp_clock_t * clock); + +#endif diff --git a/tools/virtualmips/vp_lock.h b/tools/virtualmips/vp_lock.h new file mode 100644 index 0000000..09bfc4f --- /dev/null +++ b/tools/virtualmips/vp_lock.h @@ -0,0 +1,45 @@ + /* + * Copyright (C) yajin 2008 + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + * + */ + +#ifndef __VP_LOCK_H__ +#define __VP_LOCK_H__ + +/*testandset from QEMU*/ + +#ifdef __i386__ +static inline int testandset (int *p) +{ + long int readval = 0; + + __asm__ __volatile__ ("lock; cmpxchgl %2, %0":"+m" (*p), + "+a" (readval):"r" (1):"cc"); + return readval; +} +#endif + +#ifdef __x86_64__ +static inline int testandset (int *p) +{ + long int readval = 0; + + __asm__ __volatile__ ("lock; cmpxchgl %2, %0":"+m" (*p), + "+a" (readval):"r" (1):"cc"); + return readval; +} +#endif + +#ifdef __ia64 +#include + +static inline int testandset (int *p) +{ + return __sync_lock_test_and_set (p, 1); +} +#endif + +#endif diff --git a/tools/virtualmips/vp_sdl.c b/tools/virtualmips/vp_sdl.c new file mode 100644 index 0000000..f79ecd4 --- /dev/null +++ b/tools/virtualmips/vp_sdl.c @@ -0,0 +1,142 @@ + /* + * Copyright (C) yajin 2008 + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + * + */ + +#ifdef SIM_LCD +#include "vp_sdl.h" +#include + +SDL_Surface *screen; +SDL_Event ev; + +static void sdl_update (DisplayState * ds, int x, int y, int w, int h) +{ + SDL_UpdateRect (screen, x, y, w, h); +} + +static void sdl_resize (DisplayState * ds, int w, int h) +{ + int flags; + + // printf("resizing to %d %d\n", w, h); + + flags = SDL_HWSURFACE | SDL_ASYNCBLIT | SDL_HWACCEL; + again: + screen = SDL_SetVideoMode (w, h, ds->depth, flags); + if (!screen) { + fprintf (stderr, "Could not open SDL display\n"); + exit (1); + } + if (!screen->pixels && (flags & SDL_HWSURFACE) + && (flags & SDL_FULLSCREEN)) { + flags &= ~SDL_HWSURFACE; + goto again; + } + + if (!screen->pixels) { + fprintf (stderr, "Could not open SDL display\n"); + exit (1); + } + ds->data = screen->pixels; + ds->linesize = screen->pitch; + //ds->depth = screen->format->BitsPerPixel; + if (ds->depth == 32 && screen->format->Rshift == 0) { + ds->bgr = 1; + } else { + ds->bgr = 0; + } +} + +SDL_Event *sdl_getmouse_down () +{ + if (SDL_PollEvent (&ev)) { + if (ev.type == SDL_MOUSEBUTTONDOWN) { + return &ev; + } + } + return NULL; +} + +SDL_Event *sdl_getmouse_up () +{ + if (SDL_PollEvent (&ev)) { + if (ev.type == SDL_MOUSEBUTTONUP) { + return &ev; + } + } + return NULL; +} + +static void sdl_refresh (DisplayState * ds) +{ + +} + +static void sdl_update_caption (void) +{ + char buf[1024]; + strcpy (buf, "VirtualMIPS"); + SDL_WM_SetCaption (buf, ""); +} + +/* +loading VirtualMIPS logo. +A bit ugly logo. +Sorry CNN, I have not learned how to ps pictures. Please forgive me. +*/ +static void sdl_display_logo (void) +{ + SDL_Surface *image; + SDL_Rect dest; + image = SDL_LoadBMP ("logo.bmp"); + if (image == NULL) { + fprintf (stderr, "can not load logo logo.bmp: %s\n", SDL_GetError ()); + return; + } + dest.x = 0; + dest.y = 0; + dest.w = image->w; + dest.h = image->h; + SDL_BlitSurface (image, NULL, screen, &dest); + + SDL_UpdateRects (screen, 1, &dest); + +} + +static void sdl_cleanup (void) +{ + printf ("SDL Clean \n"); + SDL_Quit (); +} + +void sdl_display_init (DisplayState * ds, int full_screen) +{ + int flags; + + flags = SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE; + if (SDL_Init (flags)) { + fprintf (stderr, "Could not initialize SDL - exiting\n"); + exit (1); + } +#ifndef _WIN32 + signal (SIGINT, SIG_DFL); + signal (SIGQUIT, SIG_DFL); +#endif + + ds->dpy_update = sdl_update; + ds->dpy_resize = sdl_resize; + ds->dpy_refresh = sdl_refresh; + + sdl_resize (ds, ds->width, ds->height); + sdl_update_caption (); + sdl_display_logo (); + SDL_EnableUNICODE (1); + + atexit (sdl_cleanup); +} + +#endif diff --git a/tools/virtualmips/vp_sdl.h b/tools/virtualmips/vp_sdl.h new file mode 100644 index 0000000..a66ec78 --- /dev/null +++ b/tools/virtualmips/vp_sdl.h @@ -0,0 +1,93 @@ + /* + * Copyright (C) yajin 2008 + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + * + */ + +#ifndef __VSDL_H__ +#define __VSDL_H__ + +#ifdef SIM_LCD /*defined in Makefile */ + +#include "utils.h" +#include "SDL/SDL.h" + +struct DisplayState { + uint8_t *data; + int linesize; + int depth; + int bgr; /* BGR color order instead of RGB. Only valid for depth == 32 */ + int width; + int height; + void *opaque; + + void (*dpy_update) (struct DisplayState * s, int x, int y, int w, int h); + void (*dpy_resize) (struct DisplayState * s, int w, int h); + void (*dpy_refresh) (struct DisplayState * s); + void (*dpy_copy) (struct DisplayState * s, int src_x, int src_y, + int dst_x, int dst_y, int w, int h); +}; + +typedef struct DisplayState DisplayState; + +static inline void dpy_update (DisplayState * s, int x, int y, int w, int h) +{ + s->dpy_update (s, x, y, w, h); +} + +static inline void dpy_resize (DisplayState * s, int w, int h) +{ + s->dpy_resize (s, w, h); +} + +/* +static inline void draw_pixel(SDL_Surface *screen, Uint8 R, Uint8 G, Uint8 B,Uint32 x,Uint32 y) +{ + Uint32 color = SDL_MapRGB(screen->format, R, G, B); + + switch (screen->format->BytesPerPixel) { + case 1: { + Uint8 *bufp; + + bufp = (Uint8 *)screen->pixels + y*screen->pitch + x; + *bufp = color; + } + break; + + case 2: { + Uint16 *bufp; + + bufp = (Uint16 *)screen->pixels + y*screen->pitch/2 + x; + *bufp = color; + } + break; + + case 3: { + Uint8 *bufp; + + bufp = (Uint8 *)screen->pixels + y*screen->pitch + x; + *(bufp+screen->format->Rshift/8) = R; + *(bufp+screen->format->Gshift/8) = G; + *(bufp+screen->format->Bshift/8) = B; + } + break; + + case 4: { + Uint32 *bufp; + + bufp = (Uint32 *)screen->pixels + y*screen->pitch/4 + x; + *bufp = color; + } + break; + } + +} +*/ +void sdl_display_init (DisplayState * ds, int full_screen); +SDL_Event *sdl_getmouse_down (); +SDL_Event *sdl_getmouse_up (); +#endif + +#endif diff --git a/tools/virtualmips/vp_timer.c b/tools/virtualmips/vp_timer.c new file mode 100644 index 0000000..6e08cdb --- /dev/null +++ b/tools/virtualmips/vp_timer.c @@ -0,0 +1,129 @@ + /* + * Copyright (C) yajin 2008 + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + * + */ + +/* +Timer routine. +Emulator has many timers. Every 1ms, emulator will check +whether there is timer request and pause the cpu when +processing timer event. +Codes are from qemu. +yajin +*/ +#include +#include +#include "vp_timer.h" +#include "vp_clock.h" + +vp_timer_t *active_timers[2]; + +m_int64_t ticks_per_sec; +vp_timer_t *vp_new_timer (vp_clock_t * clock, vp_timer_cb * cb, void *opaque) +{ + vp_timer_t *ts; + + ts = malloc (sizeof (vp_timer_t)); + memset (ts, 0x0, sizeof (*ts)); + if (ts == NULL) + return NULL; + ts->clock = clock; + ts->cb = cb; + ts->opaque = opaque; + return ts; +} + +void vp_free_timer (vp_timer_t * ts) +{ + ASSERT (ts != NULL, "ts==NULL. NULL can not be freed\n"); + free (ts); +} + +/* stop a timer, but do not dealloc it */ +void vp_del_timer (vp_timer_t * ts) +{ + vp_timer_t **pt, *t; + + /* NOTE: this code must be signal safe because + * qemu_timer_expired() can be called from a signal. */ + pt = &active_timers[ts->clock->type]; + for (;;) { + t = *pt; + if (!t) + break; + if (t == ts) { + *pt = t->next; + break; + } + pt = &t->next; + } +} + +/* modify the current timer so that it will be fired when current_time + >= expire_time. The corresponding callback will be called. */ +void vp_mod_timer (vp_timer_t * ts, m_int64_t expire_time) +{ + vp_timer_t **pt, *t; + + vp_del_timer (ts); + + /* add the timer in the sorted list */ + /* NOTE: this code must be signal safe because + * qemu_timer_expired() can be called from a signal. */ + pt = &active_timers[ts->clock->type]; + for (;;) { + t = *pt; + if (!t) + break; + if (t->expire_time > expire_time) + break; + pt = &t->next; + } + ts->expire_time = expire_time; + ts->next = *pt; + *pt = ts; +} + +int vp_timer_pending (vp_timer_t * ts) +{ + vp_timer_t *t; + for (t = active_timers[ts->clock->type]; t != NULL; t = t->next) { + if (t == ts) + return 1; + } + return 0; +} + +inline int vp_timer_expired (vp_timer_t * timer_head, m_int64_t current_time) +{ + if (!timer_head) + return 0; + return (timer_head->expire_time <= current_time); +} + +void vp_run_timers (vp_timer_t ** ptimer_head, m_int64_t current_time) +{ + vp_timer_t *ts; + + for (;;) { + ts = *ptimer_head; + if (!ts || ts->expire_time > current_time) + break; + /* remove timer from the list before calling the callback */ + *ptimer_head = ts->next; + ts->next = NULL; + /* run the callback (the timer list can be modified) */ + ts->cb (ts->opaque); + } +} + +void init_timers (void) +{ + init_get_clock (); + ticks_per_sec = VP_TIMER_BASE; + rt_clock = vp_new_clock (VP_TIMER_REALTIME); + vm_clock = vp_new_clock (VP_TIMER_VIRTUAL); +} diff --git a/tools/virtualmips/vp_timer.h b/tools/virtualmips/vp_timer.h new file mode 100644 index 0000000..fec68f3 --- /dev/null +++ b/tools/virtualmips/vp_timer.h @@ -0,0 +1,39 @@ + /* + * Copyright (C) yajin 2008 + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + * + */ + +#ifndef __VP_TIMER_H__ +#define __VP_TIMER_H__ + +#include "vp_clock.h" +#include "utils.h" + +#define VP_TIMER_BASE 1000000000LL + +typedef void vp_timer_cb (void *opaque); + +struct vp_timer { + vp_clock_t *clock; + m_int64_t expire_time; + m_int64_t set_time; + vp_timer_cb *cb; + void *opaque; + struct vp_timer *next; +}; +typedef struct vp_timer vp_timer_t; +extern vp_timer_t *active_timers[2]; + +vp_timer_t *vp_new_timer (vp_clock_t * clock, vp_timer_cb * cb, void *opaque); +void vp_free_timer (vp_timer_t * ts); +void vp_mod_timer (vp_timer_t * ts, m_int64_t expire_time); +void vp_del_timer (vp_timer_t * ts); +int vp_timer_pending (vp_timer_t * ts); +int vp_timer_expired (vp_timer_t * timer_head, m_int64_t current_time); +void vp_run_timers (vp_timer_t ** ptimer_head, m_int64_t current_time); +void init_timers (void); + +#endif diff --git a/tools/virtualmips/x86-codegen.h b/tools/virtualmips/x86-codegen.h new file mode 100644 index 0000000..64d23c3 --- /dev/null +++ b/tools/virtualmips/x86-codegen.h @@ -0,0 +1,1708 @@ +/* + * x86-codegen.h: Macros for generating x86 code + * + * Authors: + * Paolo Molaro (lupus@ximian.com) + * Intel Corporation (ORP Project) + * Sergey Chaban (serge@wildwestsoftware.com) + * Dietmar Maurer (dietmar@ximian.com) + * Patrik Torstensson + * + * Copyright (C) 2000 Intel Corporation. All rights reserved. + * Copyright (C) 2001, 2002 Ximian, Inc. + */ + +#ifndef X86_H +#define X86_H +#include +/* +// x86 register numbers +*/ +typedef enum { + X86_EAX = 0, + X86_ECX = 1, + X86_EDX = 2, + X86_EBX = 3, + X86_ESP = 4, + X86_EBP = 5, + X86_ESI = 6, + X86_EDI = 7, + X86_NREG +} X86_Reg_No; +/* +// opcodes for alu instructions +*/ +typedef enum { + X86_ADD = 0, + X86_OR = 1, + X86_ADC = 2, + X86_SBB = 3, + X86_AND = 4, + X86_SUB = 5, + X86_XOR = 6, + X86_CMP = 7, + X86_NALU +} X86_ALU_Opcode; +/* +// opcodes for shift instructions +*/ +typedef enum { + X86_SHLD, + X86_SHLR, + X86_ROL = 0, + X86_ROR = 1, + X86_RCL = 2, + X86_RCR = 3, + X86_SHL = 4, + X86_SHR = 5, + X86_SAR = 7, + X86_NSHIFT = 8 +} X86_Shift_Opcode; +/* +// opcodes for floating-point instructions +*/ +typedef enum { + X86_FADD = 0, + X86_FMUL = 1, + X86_FCOM = 2, + X86_FCOMP = 3, + X86_FSUB = 4, + X86_FSUBR = 5, + X86_FDIV = 6, + X86_FDIVR = 7, + X86_NFP = 8 +} X86_FP_Opcode; +/* +// integer conditions codes +*/ +typedef enum { + X86_CC_EQ = 0, X86_CC_E = 0, X86_CC_Z = 0, + X86_CC_NE = 1, X86_CC_NZ = 1, + X86_CC_LT = 2, X86_CC_B = 2, X86_CC_C = 2, X86_CC_NAE = 2, + X86_CC_LE = 3, X86_CC_BE = 3, X86_CC_NA = 3, + X86_CC_GT = 4, X86_CC_A = 4, X86_CC_NBE = 4, + X86_CC_GE = 5, X86_CC_AE = 5, X86_CC_NB = 5, X86_CC_NC = 5, + X86_CC_LZ = 6, X86_CC_S = 6, + X86_CC_GEZ = 7, X86_CC_NS = 7, + X86_CC_P = 8, X86_CC_PE = 8, + X86_CC_NP = 9, X86_CC_PO = 9, + X86_CC_O = 10, + X86_CC_NO = 11, + X86_NCC +} X86_CC; + +/* FP status */ +enum { + X86_FP_C0 = 0x100, + X86_FP_C1 = 0x200, + X86_FP_C2 = 0x400, + X86_FP_C3 = 0x4000, + X86_FP_CC_MASK = 0x4500 +}; + +/* FP control word */ +enum { + X86_FPCW_INVOPEX_MASK = 0x1, + X86_FPCW_DENOPEX_MASK = 0x2, + X86_FPCW_ZERODIV_MASK = 0x4, + X86_FPCW_OVFEX_MASK = 0x8, + X86_FPCW_UNDFEX_MASK = 0x10, + X86_FPCW_PRECEX_MASK = 0x20, + X86_FPCW_PRECC_MASK = 0x300, + X86_FPCW_ROUNDC_MASK = 0xc00, + + /* values for precision control */ + X86_FPCW_PREC_SINGLE = 0, + X86_FPCW_PREC_DOUBLE = 0x200, + X86_FPCW_PREC_EXTENDED = 0x300, + + /* values for rounding control */ + X86_FPCW_ROUND_NEAREST = 0, + X86_FPCW_ROUND_DOWN = 0x400, + X86_FPCW_ROUND_UP = 0x800, + X86_FPCW_ROUND_TOZERO = 0xc00 +}; + +/* +// prefix code +*/ +typedef enum { + X86_LOCK_PREFIX = 0xF0, + X86_REPNZ_PREFIX = 0xF2, + X86_REPZ_PREFIX = 0xF3, + X86_REP_PREFIX = 0xF3, + X86_CS_PREFIX = 0x2E, + X86_SS_PREFIX = 0x36, + X86_DS_PREFIX = 0x3E, + X86_ES_PREFIX = 0x26, + X86_FS_PREFIX = 0x64, + X86_GS_PREFIX = 0x65, + X86_UNLIKELY_PREFIX = 0x2E, + X86_LIKELY_PREFIX = 0x3E, + X86_OPERAND_PREFIX = 0x66, + X86_ADDRESS_PREFIX = 0x67 +} X86_Prefix; + +static const unsigned char + x86_cc_unsigned_map[X86_NCC] = { + 0x74, /* eq */ + 0x75, /* ne */ + 0x72, /* lt */ + 0x76, /* le */ + 0x77, /* gt */ + 0x73, /* ge */ + 0x78, /* lz */ + 0x79, /* gez */ + 0x7a, /* p */ + 0x7b, /* np */ + 0x70, /* o */ + 0x71, /* no */ +}; + +static const unsigned char + x86_cc_signed_map[X86_NCC] = { + 0x74, /* eq */ + 0x75, /* ne */ + 0x7c, /* lt */ + 0x7e, /* le */ + 0x7f, /* gt */ + 0x7d, /* ge */ + 0x78, /* lz */ + 0x79, /* gez */ + 0x7a, /* p */ + 0x7b, /* np */ + 0x70, /* o */ + 0x71, /* no */ +}; + +typedef union { + int val; + unsigned char b[4]; +} x86_imm_buf; + +#define X86_NOBASEREG (-1) + +/* +// bitvector mask for callee-saved registers +*/ +#define X86_ESI_MASK (1<> 6) +#define x86_modrm_reg(modrm) (((modrm) >> 3) & 0x7) +#define x86_modrm_rm(modrm) ((modrm) & 0x7) + +#define x86_address_byte(inst,m,o,r) do { *(inst)++ = ((((m)&0x03)<<6)|(((o)&0x07)<<3)|(((r)&0x07))); } while (0) +#define x86_imm_emit32(inst,imm) \ + do { \ + x86_imm_buf imb; imb.val = (int) (imm); \ + *(inst)++ = imb.b [0]; \ + *(inst)++ = imb.b [1]; \ + *(inst)++ = imb.b [2]; \ + *(inst)++ = imb.b [3]; \ + } while (0) +#define x86_imm_emit16(inst,imm) do { *(short*)(inst) = (imm); (inst) += 2; } while (0) +#define x86_imm_emit8(inst,imm) do { *(inst) = (unsigned char)((imm) & 0xff); ++(inst); } while (0) +#define x86_is_imm8(imm) (((int)(imm) >= -128 && (int)(imm) <= 127)) +#define x86_is_imm16(imm) (((int)(imm) >= -(1<<16) && (int)(imm) <= ((1<<16)-1))) + +#define x86_reg_emit(inst,r,regno) do { x86_address_byte ((inst), 3, (r), (regno)); } while (0) +#define x86_reg8_emit(inst,r,regno,is_rh,is_rnoh) do {x86_address_byte ((inst), 3, (is_rh)?((r)|4):(r), (is_rnoh)?((regno)|4):(regno));} while (0) +#define x86_regp_emit(inst,r,regno) do { x86_address_byte ((inst), 0, (r), (regno)); } while (0) +#define x86_mem_emit(inst,r,disp) do { x86_address_byte ((inst), 0, (r), 5); x86_imm_emit32((inst), (disp)); } while (0) + +#define x86_membase_emit(inst,r,basereg,disp) do {\ + if ((basereg) == X86_ESP) { \ + if ((disp) == 0) { \ + x86_address_byte ((inst), 0, (r), X86_ESP); \ + x86_address_byte ((inst), 0, X86_ESP, X86_ESP); \ + } else if (x86_is_imm8((disp))) { \ + x86_address_byte ((inst), 1, (r), X86_ESP); \ + x86_address_byte ((inst), 0, X86_ESP, X86_ESP); \ + x86_imm_emit8 ((inst), (disp)); \ + } else { \ + x86_address_byte ((inst), 2, (r), X86_ESP); \ + x86_address_byte ((inst), 0, X86_ESP, X86_ESP); \ + x86_imm_emit32 ((inst), (disp)); \ + } \ + break; \ + } \ + if ((disp) == 0 && (basereg) != X86_EBP) { \ + x86_address_byte ((inst), 0, (r), (basereg)); \ + break; \ + } \ + if (x86_is_imm8((disp))) { \ + x86_address_byte ((inst), 1, (r), (basereg)); \ + x86_imm_emit8 ((inst), (disp)); \ + } else { \ + x86_address_byte ((inst), 2, (r), (basereg)); \ + x86_imm_emit32 ((inst), (disp)); \ + } \ + } while (0) + +#define x86_memindex_emit(inst,r,basereg,disp,indexreg,shift) \ + do { \ + if ((basereg) == X86_NOBASEREG) { \ + x86_address_byte ((inst), 0, (r), 4); \ + x86_address_byte ((inst), (shift), (indexreg), 5); \ + x86_imm_emit32 ((inst), (disp)); \ + } else if ((disp) == 0 && (basereg) != X86_EBP) { \ + x86_address_byte ((inst), 0, (r), 4); \ + x86_address_byte ((inst), (shift), (indexreg), (basereg)); \ + } else if (x86_is_imm8((disp))) { \ + x86_address_byte ((inst), 1, (r), 4); \ + x86_address_byte ((inst), (shift), (indexreg), (basereg)); \ + x86_imm_emit8 ((inst), (disp)); \ + } else { \ + x86_address_byte ((inst), 2, (r), 4); \ + x86_address_byte ((inst), (shift), (indexreg), 5); \ + x86_imm_emit32 ((inst), (disp)); \ + } \ + } while (0) + +/* + * target is the position in the code where to jump to: + * target = code; + * .. output loop code... + * x86_mov_reg_imm (code, X86_EAX, 0); + * loop = code; + * x86_loop (code, -1); + * ... finish method + * + * patch displacement + * x86_patch (loop, target); + * + * ins should point at the start of the instruction that encodes a target. + * the instruction is inspected for validity and the correct displacement + * is inserted. + */ +#define x86_patch(ins,target) \ + do { \ + unsigned char* pos = (ins) + 1; \ + int disp, size = 0; \ + switch (*(unsigned char*)(ins)) { \ + case 0xe8: case 0xe9: ++size; break; /* call, jump32 */ \ + case 0x0f: if (!(*pos >= 0x70 && *pos <= 0x8f)) assert (0); \ + ++size; ++pos; break; /* prefix for 32-bit disp */ \ + case 0xe0: case 0xe1: case 0xe2: /* loop */ \ + case 0xeb: /* jump8 */ \ + /* conditional jump opcodes */ \ + case 0x70: case 0x71: case 0x72: case 0x73: \ + case 0x74: case 0x75: case 0x76: case 0x77: \ + case 0x78: case 0x79: case 0x7a: case 0x7b: \ + case 0x7c: case 0x7d: case 0x7e: case 0x7f: \ + break; \ + default: assert (0); \ + } \ + disp = (target) - pos; \ + if (size) x86_imm_emit32 (pos, disp - 4); \ + else if (x86_is_imm8 (disp - 1)) x86_imm_emit8 (pos, disp - 1); \ + else assert (0); \ + } while (0) + +#define x86_breakpoint(inst) \ + do { \ + *(inst)++ = 0xcc; \ + } while (0) + +#define x86_clc(inst) do { *(inst)++ =(unsigned char)0xf8; } while (0) +#define x86_cld(inst) do { *(inst)++ =(unsigned char)0xfc; } while (0) +#define x86_stosb(inst) do { *(inst)++ =(unsigned char)0xaa; } while (0) +#define x86_stosl(inst) do { *(inst)++ =(unsigned char)0xab; } while (0) +#define x86_stosd(inst) x86_stosl((inst)) +#define x86_movsb(inst) do { *(inst)++ =(unsigned char)0xa4; } while (0) +#define x86_movsl(inst) do { *(inst)++ =(unsigned char)0xa5; } while (0) +#define x86_movsd(inst) x86_movsl((inst)) + +#define x86_prefix(inst,p) do { *(inst)++ =(unsigned char) (p); } while (0) + +#define x86_bswap(inst,reg) \ + do { \ + *(inst)++ = 0x0f; \ + *(inst)++ = (unsigned char)0xc8 + (reg); \ + } while (0) + +#define x86_rdtsc(inst) \ + do { \ + *(inst)++ = 0x0f; \ + *(inst)++ = 0x31; \ + } while (0) + +#define x86_cmpxchg_reg_reg(inst,dreg,reg) \ + do { \ + *(inst)++ = (unsigned char)0x0f; \ + *(inst)++ = (unsigned char)0xb1; \ + x86_reg_emit ((inst), (reg), (dreg)); \ + } while (0) + +#define x86_cmpxchg_mem_reg(inst,mem,reg) \ + do { \ + *(inst)++ = (unsigned char)0x0f; \ + *(inst)++ = (unsigned char)0xb1; \ + x86_mem_emit ((inst), (reg), (mem)); \ + } while (0) + +#define x86_cmpxchg_membase_reg(inst,basereg,disp,reg) \ + do { \ + *(inst)++ = (unsigned char)0x0f; \ + *(inst)++ = (unsigned char)0xb1; \ + x86_membase_emit ((inst), (reg), (basereg), (disp)); \ + } while (0) + +#define x86_xchg_reg_reg(inst,dreg,reg,size) \ + do { \ + if ((size) == 1) \ + *(inst)++ = (unsigned char)0x86; \ + else \ + *(inst)++ = (unsigned char)0x87; \ + x86_reg_emit ((inst), (reg), (dreg)); \ + } while (0) + +#define x86_xchg_mem_reg(inst,mem,reg,size) \ + do { \ + if ((size) == 1) \ + *(inst)++ = (unsigned char)0x86; \ + else \ + *(inst)++ = (unsigned char)0x87; \ + x86_mem_emit ((inst), (reg), (mem)); \ + } while (0) + +#define x86_xchg_membase_reg(inst,basereg,disp,reg,size) \ + do { \ + if ((size) == 1) \ + *(inst)++ = (unsigned char)0x86; \ + else \ + *(inst)++ = (unsigned char)0x87; \ + x86_membase_emit ((inst), (reg), (basereg), (disp)); \ + } while (0) + +#define x86_xadd_reg_reg(inst,dreg,reg,size) \ + do { \ + *(inst)++ = (unsigned char)0x0F; \ + if ((size) == 1) \ + *(inst)++ = (unsigned char)0xC0; \ + else \ + *(inst)++ = (unsigned char)0xC1; \ + x86_reg_emit ((inst), (reg), (dreg)); \ + } while (0) + +#define x86_xadd_mem_reg(inst,mem,reg,size) \ + do { \ + *(inst)++ = (unsigned char)0x0F; \ + if ((size) == 1) \ + *(inst)++ = (unsigned char)0xC0; \ + else \ + *(inst)++ = (unsigned char)0xC1; \ + x86_mem_emit ((inst), (reg), (mem)); \ + } while (0) + +#define x86_xadd_membase_reg(inst,basereg,disp,reg,size) \ + do { \ + *(inst)++ = (unsigned char)0x0F; \ + if ((size) == 1) \ + *(inst)++ = (unsigned char)0xC0; \ + else \ + *(inst)++ = (unsigned char)0xC1; \ + x86_membase_emit ((inst), (reg), (basereg), (disp)); \ + } while (0) + +#define x86_inc_mem(inst,mem) \ + do { \ + *(inst)++ = (unsigned char)0xff; \ + x86_mem_emit ((inst), 0, (mem)); \ + } while (0) + +#define x86_inc_membase(inst,basereg,disp) \ + do { \ + *(inst)++ = (unsigned char)0xff; \ + x86_membase_emit ((inst), 0, (basereg), (disp)); \ + } while (0) + +#define x86_inc_reg(inst,reg) do { *(inst)++ = (unsigned char)0x40 + (reg); } while (0) + +#define x86_dec_mem(inst,mem) \ + do { \ + *(inst)++ = (unsigned char)0xff; \ + x86_mem_emit ((inst), 1, (mem)); \ + } while (0) + +#define x86_dec_membase(inst,basereg,disp) \ + do { \ + *(inst)++ = (unsigned char)0xff; \ + x86_membase_emit ((inst), 1, (basereg), (disp)); \ + } while (0) + +#define x86_dec_reg(inst,reg) do { *(inst)++ = (unsigned char)0x48 + (reg); } while (0) + +#define x86_not_mem(inst,mem) \ + do { \ + *(inst)++ = (unsigned char)0xf7; \ + x86_mem_emit ((inst), 2, (mem)); \ + } while (0) + +#define x86_not_membase(inst,basereg,disp) \ + do { \ + *(inst)++ = (unsigned char)0xf7; \ + x86_membase_emit ((inst), 2, (basereg), (disp)); \ + } while (0) + +#define x86_not_reg(inst,reg) \ + do { \ + *(inst)++ = (unsigned char)0xf7; \ + x86_reg_emit ((inst), 2, (reg)); \ + } while (0) + +#define x86_neg_mem(inst,mem) \ + do { \ + *(inst)++ = (unsigned char)0xf7; \ + x86_mem_emit ((inst), 3, (mem)); \ + } while (0) + +#define x86_neg_membase(inst,basereg,disp) \ + do { \ + *(inst)++ = (unsigned char)0xf7; \ + x86_membase_emit ((inst), 3, (basereg), (disp)); \ + } while (0) + +#define x86_neg_reg(inst,reg) \ + do { \ + *(inst)++ = (unsigned char)0xf7; \ + x86_reg_emit ((inst), 3, (reg)); \ + } while (0) + +#define x86_nop(inst) do { *(inst)++ = (unsigned char)0x90; } while (0) + +#define x86_alu_reg_imm(inst,opc,reg,imm) \ + do { \ + if ((reg) == X86_EAX) { \ + *(inst)++ = (((unsigned char)(opc)) << 3) + 5; \ + x86_imm_emit32 ((inst), (imm)); \ + break; \ + } \ + if (x86_is_imm8((imm))) { \ + *(inst)++ = (unsigned char)0x83; \ + x86_reg_emit ((inst), (opc), (reg)); \ + x86_imm_emit8 ((inst), (imm)); \ + } else { \ + *(inst)++ = (unsigned char)0x81; \ + x86_reg_emit ((inst), (opc), (reg)); \ + x86_imm_emit32 ((inst), (imm)); \ + } \ + } while (0) + +#define x86_alu_mem_imm(inst,opc,mem,imm) \ + do { \ + if (x86_is_imm8((imm))) { \ + *(inst)++ = (unsigned char)0x83; \ + x86_mem_emit ((inst), (opc), (mem)); \ + x86_imm_emit8 ((inst), (imm)); \ + } else { \ + *(inst)++ = (unsigned char)0x81; \ + x86_mem_emit ((inst), (opc), (mem)); \ + x86_imm_emit32 ((inst), (imm)); \ + } \ + } while (0) + +#define x86_alu_membase_imm(inst,opc,basereg,disp,imm) \ + do { \ + if (x86_is_imm8((imm))) { \ + *(inst)++ = (unsigned char)0x83; \ + x86_membase_emit ((inst), (opc), (basereg), (disp)); \ + x86_imm_emit8 ((inst), (imm)); \ + } else { \ + *(inst)++ = (unsigned char)0x81; \ + x86_membase_emit ((inst), (opc), (basereg), (disp)); \ + x86_imm_emit32 ((inst), (imm)); \ + } \ + } while (0) + +#define x86_alu_membase8_imm(inst,opc,basereg,disp,imm) \ + do { \ + *(inst)++ = (unsigned char)0x80; \ + x86_membase_emit ((inst), (opc), (basereg), (disp)); \ + x86_imm_emit8 ((inst), (imm)); \ + } while (0) + +#define x86_alu_mem_reg(inst,opc,mem,reg) \ + do { \ + *(inst)++ = (((unsigned char)(opc)) << 3) + 1; \ + x86_mem_emit ((inst), (reg), (mem)); \ + } while (0) + +#define x86_alu_membase_reg(inst,opc,basereg,disp,reg) \ + do { \ + *(inst)++ = (((unsigned char)(opc)) << 3) + 1; \ + x86_membase_emit ((inst), (reg), (basereg), (disp)); \ + } while (0) + +#define x86_alu_reg_reg(inst,opc,dreg,reg) \ + do { \ + *(inst)++ = (((unsigned char)(opc)) << 3) + 3; \ + x86_reg_emit ((inst), (dreg), (reg)); \ + } while (0) + +/** + * @x86_alu_reg8_reg8: + * Supports ALU operations between two 8-bit registers. + * dreg := dreg opc reg + * X86_Reg_No enum is used to specify the registers. + * Additionally is_*_h flags are used to specify what part + * of a given 32-bit register is used - high (TRUE) or low (FALSE). + * For example: dreg = X86_EAX, is_dreg_h = TRUE -> use AH + */ +#define x86_alu_reg8_reg8(inst,opc,dreg,reg,is_dreg_h,is_reg_h) \ + do { \ + *(inst)++ = (((unsigned char)(opc)) << 3) + 2; \ + x86_reg8_emit ((inst), (dreg), (reg), (is_dreg_h), (is_reg_h)); \ + } while (0) + +#define x86_alu_reg_mem(inst,opc,reg,mem) \ + do { \ + *(inst)++ = (((unsigned char)(opc)) << 3) + 3; \ + x86_mem_emit ((inst), (reg), (mem)); \ + } while (0) + +#define x86_alu_reg_membase(inst,opc,reg,basereg,disp) \ + do { \ + *(inst)++ = (((unsigned char)(opc)) << 3) + 3; \ + x86_membase_emit ((inst), (reg), (basereg), (disp)); \ + } while (0) + +#define x86_test_reg_imm(inst,reg,imm) \ + do { \ + if ((reg) == X86_EAX) { \ + *(inst)++ = (unsigned char)0xa9; \ + } else { \ + *(inst)++ = (unsigned char)0xf7; \ + x86_reg_emit ((inst), 0, (reg)); \ + } \ + x86_imm_emit32 ((inst), (imm)); \ + } while (0) + +#define x86_test_mem_imm(inst,mem,imm) \ + do { \ + *(inst)++ = (unsigned char)0xf7; \ + x86_mem_emit ((inst), 0, (mem)); \ + x86_imm_emit32 ((inst), (imm)); \ + } while (0) + +#define x86_test_membase_imm(inst,basereg,disp,imm) \ + do { \ + *(inst)++ = (unsigned char)0xf7; \ + x86_membase_emit ((inst), 0, (basereg), (disp)); \ + x86_imm_emit32 ((inst), (imm)); \ + } while (0) + +#define x86_test_reg_reg(inst,dreg,reg) \ + do { \ + *(inst)++ = (unsigned char)0x85; \ + x86_reg_emit ((inst), (reg), (dreg)); \ + } while (0) + +#define x86_test_mem_reg(inst,mem,reg) \ + do { \ + *(inst)++ = (unsigned char)0x85; \ + x86_mem_emit ((inst), (reg), (mem)); \ + } while (0) + +#define x86_test_membase_reg(inst,basereg,disp,reg) \ + do { \ + *(inst)++ = (unsigned char)0x85; \ + x86_membase_emit ((inst), (reg), (basereg), (disp)); \ + } while (0) + +#define x86_shift_reg_imm(inst,opc,reg,imm) \ + do { \ + if ((imm) == 1) { \ + *(inst)++ = (unsigned char)0xd1; \ + x86_reg_emit ((inst), (opc), (reg)); \ + } else { \ + *(inst)++ = (unsigned char)0xc1; \ + x86_reg_emit ((inst), (opc), (reg)); \ + x86_imm_emit8 ((inst), (imm)); \ + } \ + } while (0) + +#define x86_shift_mem_imm(inst,opc,mem,imm) \ + do { \ + if ((imm) == 1) { \ + *(inst)++ = (unsigned char)0xd1; \ + x86_mem_emit ((inst), (opc), (mem)); \ + } else { \ + *(inst)++ = (unsigned char)0xc1; \ + x86_mem_emit ((inst), (opc), (mem)); \ + x86_imm_emit8 ((inst), (imm)); \ + } \ + } while (0) + +#define x86_shift_membase_imm(inst,opc,basereg,disp,imm) \ + do { \ + if ((imm) == 1) { \ + *(inst)++ = (unsigned char)0xd1; \ + x86_membase_emit ((inst), (opc), (basereg), (disp)); \ + } else { \ + *(inst)++ = (unsigned char)0xc1; \ + x86_membase_emit ((inst), (opc), (basereg), (disp)); \ + x86_imm_emit8 ((inst), (imm)); \ + } \ + } while (0) + +#define x86_shift_reg(inst,opc,reg) \ + do { \ + *(inst)++ = (unsigned char)0xd3; \ + x86_reg_emit ((inst), (opc), (reg)); \ + } while (0) + +#define x86_shift_mem(inst,opc,mem) \ + do { \ + *(inst)++ = (unsigned char)0xd3; \ + x86_mem_emit ((inst), (opc), (mem)); \ + } while (0) + +#define x86_shift_membase(inst,opc,basereg,disp) \ + do { \ + *(inst)++ = (unsigned char)0xd3; \ + x86_membase_emit ((inst), (opc), (basereg), (disp)); \ + } while (0) + +/* + * Multi op shift missing. + */ + +#define x86_shrd_reg(inst,dreg,reg) \ + do { \ + *(inst)++ = (unsigned char)0x0f; \ + *(inst)++ = (unsigned char)0xad; \ + x86_reg_emit ((inst), (reg), (dreg)); \ + } while (0) + +#define x86_shrd_reg_imm(inst,dreg,reg,shamt) \ + do { \ + *(inst)++ = (unsigned char)0x0f; \ + *(inst)++ = (unsigned char)0xac; \ + x86_reg_emit ((inst), (reg), (dreg)); \ + x86_imm_emit8 ((inst), (shamt)); \ + } while (0) + +#define x86_shld_reg(inst,dreg,reg) \ + do { \ + *(inst)++ = (unsigned char)0x0f; \ + *(inst)++ = (unsigned char)0xa5; \ + x86_reg_emit ((inst), (reg), (dreg)); \ + } while (0) + +#define x86_shld_reg_imm(inst,dreg,reg,shamt) \ + do { \ + *(inst)++ = (unsigned char)0x0f; \ + *(inst)++ = (unsigned char)0xa4; \ + x86_reg_emit ((inst), (reg), (dreg)); \ + x86_imm_emit8 ((inst), (shamt)); \ + } while (0) + +/* + * EDX:EAX = EAX * rm + */ +#define x86_mul_reg(inst,reg,is_signed) \ + do { \ + *(inst)++ = (unsigned char)0xf7; \ + x86_reg_emit ((inst), 4 + ((is_signed) ? 1 : 0), (reg)); \ + } while (0) + +#define x86_mul_mem(inst,mem,is_signed) \ + do { \ + *(inst)++ = (unsigned char)0xf7; \ + x86_mem_emit ((inst), 4 + ((is_signed) ? 1 : 0), (mem)); \ + } while (0) + +#define x86_mul_membase(inst,basereg,disp,is_signed) \ + do { \ + *(inst)++ = (unsigned char)0xf7; \ + x86_membase_emit ((inst), 4 + ((is_signed) ? 1 : 0), (basereg), (disp)); \ + } while (0) + +/* + * r *= rm + */ +#define x86_imul_reg_reg(inst,dreg,reg) \ + do { \ + *(inst)++ = (unsigned char)0x0f; \ + *(inst)++ = (unsigned char)0xaf; \ + x86_reg_emit ((inst), (dreg), (reg)); \ + } while (0) + +#define x86_imul_reg_mem(inst,reg,mem) \ + do { \ + *(inst)++ = (unsigned char)0x0f; \ + *(inst)++ = (unsigned char)0xaf; \ + x86_mem_emit ((inst), (reg), (mem)); \ + } while (0) + +#define x86_imul_reg_membase(inst,reg,basereg,disp) \ + do { \ + *(inst)++ = (unsigned char)0x0f; \ + *(inst)++ = (unsigned char)0xaf; \ + x86_membase_emit ((inst), (reg), (basereg), (disp)); \ + } while (0) + +/* + * dreg = rm * imm + */ +#define x86_imul_reg_reg_imm(inst,dreg,reg,imm) \ + do { \ + if (x86_is_imm8 ((imm))) { \ + *(inst)++ = (unsigned char)0x6b; \ + x86_reg_emit ((inst), (dreg), (reg)); \ + x86_imm_emit8 ((inst), (imm)); \ + } else { \ + *(inst)++ = (unsigned char)0x69; \ + x86_reg_emit ((inst), (dreg), (reg)); \ + x86_imm_emit32 ((inst), (imm)); \ + } \ + } while (0) + +#define x86_imul_reg_mem_imm(inst,reg,mem,imm) \ + do { \ + if (x86_is_imm8 ((imm))) { \ + *(inst)++ = (unsigned char)0x6b; \ + x86_mem_emit ((inst), (reg), (mem)); \ + x86_imm_emit8 ((inst), (imm)); \ + } else { \ + *(inst)++ = (unsigned char)0x69; \ + x86_reg_emit ((inst), (reg), (mem)); \ + x86_imm_emit32 ((inst), (imm)); \ + } \ + } while (0) + +#define x86_imul_reg_membase_imm(inst,reg,basereg,disp,imm) \ + do { \ + if (x86_is_imm8 ((imm))) { \ + *(inst)++ = (unsigned char)0x6b; \ + x86_membase_emit ((inst), (reg), (basereg), (disp)); \ + x86_imm_emit8 ((inst), (imm)); \ + } else { \ + *(inst)++ = (unsigned char)0x69; \ + x86_membase_emit ((inst), (reg), (basereg), (disp)); \ + x86_imm_emit32 ((inst), (imm)); \ + } \ + } while (0) + +/* + * divide EDX:EAX by rm; + * eax = quotient, edx = remainder + */ + +#define x86_div_reg(inst,reg,is_signed) \ + do { \ + *(inst)++ = (unsigned char)0xf7; \ + x86_reg_emit ((inst), 6 + ((is_signed) ? 1 : 0), (reg)); \ + } while (0) + +#define x86_div_mem(inst,mem,is_signed) \ + do { \ + *(inst)++ = (unsigned char)0xf7; \ + x86_mem_emit ((inst), 6 + ((is_signed) ? 1 : 0), (mem)); \ + } while (0) + +#define x86_div_membase(inst,basereg,disp,is_signed) \ + do { \ + *(inst)++ = (unsigned char)0xf7; \ + x86_membase_emit ((inst), 6 + ((is_signed) ? 1 : 0), (basereg), (disp)); \ + } while (0) + +#define x86_mov_mem_reg(inst,mem,reg,size) \ + do { \ + switch ((size)) { \ + case 1: *(inst)++ = (unsigned char)0x88; break; \ + case 2: *(inst)++ = (unsigned char)0x66; /* fall through */ \ + case 4: *(inst)++ = (unsigned char)0x89; break; \ + default: assert (0); \ + } \ + x86_mem_emit ((inst), (reg), (mem)); \ + } while (0) + +#define x86_mov_regp_reg(inst,regp,reg,size) \ + do { \ + switch ((size)) { \ + case 1: *(inst)++ = (unsigned char)0x88; break; \ + case 2: *(inst)++ = (unsigned char)0x66; /* fall through */ \ + case 4: *(inst)++ = (unsigned char)0x89; break; \ + default: assert (0); \ + } \ + x86_regp_emit ((inst), (reg), (regp)); \ + } while (0) + +#define x86_mov_membase_reg(inst,basereg,disp,reg,size) \ + do { \ + switch ((size)) { \ + case 1: *(inst)++ = (unsigned char)0x88; break; \ + case 2: *(inst)++ = (unsigned char)0x66; /* fall through */ \ + case 4: *(inst)++ = (unsigned char)0x89; break; \ + default: assert (0); \ + } \ + x86_membase_emit ((inst), (reg), (basereg), (disp)); \ + } while (0) + +#define x86_mov_memindex_reg(inst,basereg,disp,indexreg,shift,reg,size) \ + do { \ + switch ((size)) { \ + case 1: *(inst)++ = (unsigned char)0x88; break; \ + case 2: *(inst)++ = (unsigned char)0x66; /* fall through */ \ + case 4: *(inst)++ = (unsigned char)0x89; break; \ + default: assert (0); \ + } \ + x86_memindex_emit ((inst), (reg), (basereg), (disp), (indexreg), (shift)); \ + } while (0) + +#define x86_mov_reg_reg(inst,dreg,reg,size) \ + do { \ + switch ((size)) { \ + case 1: *(inst)++ = (unsigned char)0x8a; break; \ + case 2: *(inst)++ = (unsigned char)0x66; /* fall through */ \ + case 4: *(inst)++ = (unsigned char)0x8b; break; \ + default: assert (0); \ + } \ + x86_reg_emit ((inst), (dreg), (reg)); \ + } while (0) + +#define x86_mov_reg_mem(inst,reg,mem,size) \ + do { \ + switch ((size)) { \ + case 1: *(inst)++ = (unsigned char)0x8a; break; \ + case 2: *(inst)++ = (unsigned char)0x66; /* fall through */ \ + case 4: *(inst)++ = (unsigned char)0x8b; break; \ + default: assert (0); \ + } \ + x86_mem_emit ((inst), (reg), (mem)); \ + } while (0) + +#define x86_mov_reg_membase(inst,reg,basereg,disp,size) \ + do { \ + switch ((size)) { \ + case 1: *(inst)++ = (unsigned char)0x8a; break; \ + case 2: *(inst)++ = (unsigned char)0x66; /* fall through */ \ + case 4: *(inst)++ = (unsigned char)0x8b; break; \ + default: assert (0); \ + } \ + x86_membase_emit ((inst), (reg), (basereg), (disp)); \ + } while (0) + +#define x86_mov_reg_memindex(inst,reg,basereg,disp,indexreg,shift,size) \ + do { \ + switch ((size)) { \ + case 1: *(inst)++ = (unsigned char)0x8a; break; \ + case 2: *(inst)++ = (unsigned char)0x66; /* fall through */ \ + case 4: *(inst)++ = (unsigned char)0x8b; break; \ + default: assert (0); \ + } \ + x86_memindex_emit ((inst), (reg), (basereg), (disp), (indexreg), (shift)); \ + } while (0) + +/* + * Note: x86_clear_reg () chacnges the condition code! + */ +#define x86_clear_reg(inst,reg) x86_alu_reg_reg((inst), X86_XOR, (reg), (reg)) + +#define x86_mov_reg_imm(inst,reg,imm) \ + do { \ + *(inst)++ = (unsigned char)0xb8 + (reg); \ + x86_imm_emit32 ((inst), (imm)); \ + } while (0) + +#define x86_mov_mem_imm(inst,mem,imm,size) \ + do { \ + if ((size) == 1) { \ + *(inst)++ = (unsigned char)0xc6; \ + x86_mem_emit ((inst), 0, (mem)); \ + x86_imm_emit8 ((inst), (imm)); \ + } else if ((size) == 2) { \ + *(inst)++ = (unsigned char)0x66; \ + *(inst)++ = (unsigned char)0xc7; \ + x86_mem_emit ((inst), 0, (mem)); \ + x86_imm_emit16 ((inst), (imm)); \ + } else { \ + *(inst)++ = (unsigned char)0xc7; \ + x86_mem_emit ((inst), 0, (mem)); \ + x86_imm_emit32 ((inst), (imm)); \ + } \ + } while (0) + +#define x86_mov_membase_imm(inst,basereg,disp,imm,size) \ + do { \ + if ((size) == 1) { \ + *(inst)++ = (unsigned char)0xc6; \ + x86_membase_emit ((inst), 0, (basereg), (disp)); \ + x86_imm_emit8 ((inst), (imm)); \ + } else if ((size) == 2) { \ + *(inst)++ = (unsigned char)0x66; \ + *(inst)++ = (unsigned char)0xc7; \ + x86_membase_emit ((inst), 0, (basereg), (disp)); \ + x86_imm_emit16 ((inst), (imm)); \ + } else { \ + *(inst)++ = (unsigned char)0xc7; \ + x86_membase_emit ((inst), 0, (basereg), (disp)); \ + x86_imm_emit32 ((inst), (imm)); \ + } \ + } while (0) + +#define x86_mov_memindex_imm(inst,basereg,disp,indexreg,shift,imm,size) \ + do { \ + if ((size) == 1) { \ + *(inst)++ = (unsigned char)0xc6; \ + x86_memindex_emit ((inst), 0, (basereg), (disp), (indexreg), (shift)); \ + x86_imm_emit8 ((inst), (imm)); \ + } else if ((size) == 2) { \ + *(inst)++ = (unsigned char)0x66; \ + *(inst)++ = (unsigned char)0xc7; \ + x86_memindex_emit ((inst), 0, (basereg), (disp), (indexreg), (shift)); \ + x86_imm_emit16 ((inst), (imm)); \ + } else { \ + *(inst)++ = (unsigned char)0xc7; \ + x86_memindex_emit ((inst), 0, (basereg), (disp), (indexreg), (shift)); \ + x86_imm_emit32 ((inst), (imm)); \ + } \ + } while (0) + +#define x86_lea_mem(inst,reg,mem) \ + do { \ + *(inst)++ = (unsigned char)0x8d; \ + x86_mem_emit ((inst), (reg), (mem)); \ + } while (0) + +#define x86_lea_membase(inst,reg,basereg,disp) \ + do { \ + *(inst)++ = (unsigned char)0x8d; \ + x86_membase_emit ((inst), (reg), (basereg), (disp)); \ + } while (0) + +#define x86_lea_memindex(inst,reg,basereg,disp,indexreg,shift) \ + do { \ + *(inst)++ = (unsigned char)0x8d; \ + x86_memindex_emit ((inst), (reg), (basereg), (disp), (indexreg), (shift)); \ + } while (0) + +#define x86_widen_reg(inst,dreg,reg,is_signed,is_half) \ + do { \ + unsigned char op = 0xb6; \ + assert (is_half || X86_IS_BYTE_REG (reg)); \ + *(inst)++ = (unsigned char)0x0f; \ + if ((is_signed)) op += 0x08; \ + if ((is_half)) op += 0x01; \ + *(inst)++ = op; \ + x86_reg_emit ((inst), (dreg), (reg)); \ + } while (0) + +#define x86_widen_mem(inst,dreg,mem,is_signed,is_half) \ + do { \ + unsigned char op = 0xb6; \ + *(inst)++ = (unsigned char)0x0f; \ + if ((is_signed)) op += 0x08; \ + if ((is_half)) op += 0x01; \ + *(inst)++ = op; \ + x86_mem_emit ((inst), (dreg), (mem)); \ + } while (0) + +#define x86_widen_membase(inst,dreg,basereg,disp,is_signed,is_half) \ + do { \ + unsigned char op = 0xb6; \ + *(inst)++ = (unsigned char)0x0f; \ + if ((is_signed)) op += 0x08; \ + if ((is_half)) op += 0x01; \ + *(inst)++ = op; \ + x86_membase_emit ((inst), (dreg), (basereg), (disp)); \ + } while (0) + +#define x86_widen_memindex(inst,dreg,basereg,disp,indexreg,shift,is_signed,is_half) \ + do { \ + unsigned char op = 0xb6; \ + *(inst)++ = (unsigned char)0x0f; \ + if ((is_signed)) op += 0x08; \ + if ((is_half)) op += 0x01; \ + *(inst)++ = op; \ + x86_memindex_emit ((inst), (dreg), (basereg), (disp), (indexreg), (shift)); \ + } while (0) + +#define x86_lahf(inst) do { *(inst)++ = (unsigned char)0x9f; } while (0) +#define x86_sahf(inst) do { *(inst)++ = (unsigned char)0x9e; } while (0) +#define x86_xchg_ah_al(inst) \ + do { \ + *(inst)++ = (unsigned char)0x86; \ + *(inst)++ = (unsigned char)0xe0; \ + } while (0) + +#define x86_cdq(inst) do { *(inst)++ = (unsigned char)0x99; } while (0) +#define x86_wait(inst) do { *(inst)++ = (unsigned char)0x9b; } while (0) + +#define x86_fp_op_mem(inst,opc,mem,is_double) \ + do { \ + *(inst)++ = (is_double) ? (unsigned char)0xdc : (unsigned char)0xd8; \ + x86_mem_emit ((inst), (opc), (mem)); \ + } while (0) + +#define x86_fp_op_membase(inst,opc,basereg,disp,is_double) \ + do { \ + *(inst)++ = (is_double) ? (unsigned char)0xdc : (unsigned char)0xd8; \ + x86_membase_emit ((inst), (opc), (basereg), (disp)); \ + } while (0) + +#define x86_fp_op(inst,opc,index) \ + do { \ + *(inst)++ = (unsigned char)0xd8; \ + *(inst)++ = (unsigned char)0xc0+((opc)<<3)+((index)&0x07); \ + } while (0) + +#define x86_fp_op_reg(inst,opc,index,pop_stack) \ + do { \ + static const unsigned char map[] = { 0, 1, 2, 3, 5, 4, 7, 6, 8}; \ + *(inst)++ = (pop_stack) ? (unsigned char)0xde : (unsigned char)0xdc; \ + *(inst)++ = (unsigned char)0xc0+(map[(opc)]<<3)+((index)&0x07); \ + } while (0) + +/** + * @x86_fp_int_op_membase + * Supports FPU operations between ST(0) and integer operand in memory. + * Operation encoded using X86_FP_Opcode enum. + * Operand is addressed by [basereg + disp]. + * is_int specifies whether operand is int32 (TRUE) or int16 (FALSE). + */ +#define x86_fp_int_op_membase(inst,opc,basereg,disp,is_int) \ + do { \ + *(inst)++ = (is_int) ? (unsigned char)0xda : (unsigned char)0xde; \ + x86_membase_emit ((inst), opc, (basereg), (disp)); \ + } while (0) + +#define x86_fstp(inst,index) \ + do { \ + *(inst)++ = (unsigned char)0xdd; \ + *(inst)++ = (unsigned char)0xd8+(index); \ + } while (0) + +#define x86_fcompp(inst) \ + do { \ + *(inst)++ = (unsigned char)0xde; \ + *(inst)++ = (unsigned char)0xd9; \ + } while (0) + +#define x86_fucompp(inst) \ + do { \ + *(inst)++ = (unsigned char)0xda; \ + *(inst)++ = (unsigned char)0xe9; \ + } while (0) + +#define x86_fnstsw(inst) \ + do { \ + *(inst)++ = (unsigned char)0xdf; \ + *(inst)++ = (unsigned char)0xe0; \ + } while (0) + +#define x86_fnstcw(inst,mem) \ + do { \ + *(inst)++ = (unsigned char)0xd9; \ + x86_mem_emit ((inst), 7, (mem)); \ + } while (0) + +#define x86_fnstcw_membase(inst,basereg,disp) \ + do { \ + *(inst)++ = (unsigned char)0xd9; \ + x86_membase_emit ((inst), 7, (basereg), (disp)); \ + } while (0) + +#define x86_fldcw(inst,mem) \ + do { \ + *(inst)++ = (unsigned char)0xd9; \ + x86_mem_emit ((inst), 5, (mem)); \ + } while (0) + +#define x86_fldcw_membase(inst,basereg,disp) \ + do { \ + *(inst)++ = (unsigned char)0xd9; \ + x86_membase_emit ((inst), 5, (basereg), (disp)); \ + } while (0) + +#define x86_fchs(inst) \ + do { \ + *(inst)++ = (unsigned char)0xd9; \ + *(inst)++ = (unsigned char)0xe0; \ + } while (0) + +#define x86_frem(inst) \ + do { \ + *(inst)++ = (unsigned char)0xd9; \ + *(inst)++ = (unsigned char)0xf8; \ + } while (0) + +#define x86_fxch(inst,index) \ + do { \ + *(inst)++ = (unsigned char)0xd9; \ + *(inst)++ = (unsigned char)0xc8 + ((index) & 0x07); \ + } while (0) + +#define x86_fcomi(inst,index) \ + do { \ + *(inst)++ = (unsigned char)0xdb; \ + *(inst)++ = (unsigned char)0xf0 + ((index) & 0x07); \ + } while (0) + +#define x86_fcomip(inst,index) \ + do { \ + *(inst)++ = (unsigned char)0xdf; \ + *(inst)++ = (unsigned char)0xf0 + ((index) & 0x07); \ + } while (0) + +#define x86_fucomi(inst,index) \ + do { \ + *(inst)++ = (unsigned char)0xdb; \ + *(inst)++ = (unsigned char)0xe8 + ((index) & 0x07); \ + } while (0) + +#define x86_fucomip(inst,index) \ + do { \ + *(inst)++ = (unsigned char)0xdf; \ + *(inst)++ = (unsigned char)0xe8 + ((index) & 0x07); \ + } while (0) + +#define x86_fld(inst,mem,is_double) \ + do { \ + *(inst)++ = (is_double) ? (unsigned char)0xdd : (unsigned char)0xd9; \ + x86_mem_emit ((inst), 0, (mem)); \ + } while (0) + +#define x86_fld_membase(inst,basereg,disp,is_double) \ + do { \ + *(inst)++ = (is_double) ? (unsigned char)0xdd : (unsigned char)0xd9; \ + x86_membase_emit ((inst), 0, (basereg), (disp)); \ + } while (0) + +#define x86_fld80_mem(inst,mem) \ + do { \ + *(inst)++ = (unsigned char)0xdb; \ + x86_mem_emit ((inst), 5, (mem)); \ + } while (0) + +#define x86_fld80_membase(inst,basereg,disp) \ + do { \ + *(inst)++ = (unsigned char)0xdb; \ + x86_membase_emit ((inst), 5, (basereg), (disp)); \ + } while (0) + +#define x86_fild(inst,mem,is_long) \ + do { \ + if ((is_long)) { \ + *(inst)++ = (unsigned char)0xdf; \ + x86_mem_emit ((inst), 5, (mem)); \ + } else { \ + *(inst)++ = (unsigned char)0xdb; \ + x86_mem_emit ((inst), 0, (mem)); \ + } \ + } while (0) + +#define x86_fild_membase(inst,basereg,disp,is_long) \ + do { \ + if ((is_long)) { \ + *(inst)++ = (unsigned char)0xdf; \ + x86_membase_emit ((inst), 5, (basereg), (disp)); \ + } else { \ + *(inst)++ = (unsigned char)0xdb; \ + x86_membase_emit ((inst), 0, (basereg), (disp)); \ + } \ + } while (0) + +#define x86_fld_reg(inst,index) \ + do { \ + *(inst)++ = (unsigned char)0xd9; \ + *(inst)++ = (unsigned char)0xc0 + ((index) & 0x07); \ + } while (0) + +#define x86_fldz(inst) \ + do { \ + *(inst)++ = (unsigned char)0xd9; \ + *(inst)++ = (unsigned char)0xee; \ + } while (0) + +#define x86_fld1(inst) \ + do { \ + *(inst)++ = (unsigned char)0xd9; \ + *(inst)++ = (unsigned char)0xe8; \ + } while (0) + +#define x86_fldpi(inst) \ + do { \ + *(inst)++ = (unsigned char)0xd9; \ + *(inst)++ = (unsigned char)0xeb; \ + } while (0) + +#define x86_fst(inst,mem,is_double,pop_stack) \ + do { \ + *(inst)++ = (is_double) ? (unsigned char)0xdd: (unsigned char)0xd9; \ + x86_mem_emit ((inst), 2 + ((pop_stack) ? 1 : 0), (mem)); \ + } while (0) + +#define x86_fst_membase(inst,basereg,disp,is_double,pop_stack) \ + do { \ + *(inst)++ = (is_double) ? (unsigned char)0xdd: (unsigned char)0xd9; \ + x86_membase_emit ((inst), 2 + ((pop_stack) ? 1 : 0), (basereg), (disp)); \ + } while (0) + +#define x86_fst80_mem(inst,mem) \ + do { \ + *(inst)++ = (unsigned char)0xdb; \ + x86_mem_emit ((inst), 7, (mem)); \ + } while (0) + +#define x86_fst80_membase(inst,basereg,disp) \ + do { \ + *(inst)++ = (unsigned char)0xdb; \ + x86_membase_emit ((inst), 7, (basereg), (disp)); \ + } while (0) + +#define x86_fist_pop(inst,mem,is_long) \ + do { \ + if ((is_long)) { \ + *(inst)++ = (unsigned char)0xdf; \ + x86_mem_emit ((inst), 7, (mem)); \ + } else { \ + *(inst)++ = (unsigned char)0xdb; \ + x86_mem_emit ((inst), 3, (mem)); \ + } \ + } while (0) + +#define x86_fist_pop_membase(inst,basereg,disp,is_long) \ + do { \ + if ((is_long)) { \ + *(inst)++ = (unsigned char)0xdf; \ + x86_membase_emit ((inst), 7, (basereg), (disp)); \ + } else { \ + *(inst)++ = (unsigned char)0xdb; \ + x86_membase_emit ((inst), 3, (basereg), (disp)); \ + } \ + } while (0) + +#define x86_fstsw(inst) \ + do { \ + *(inst)++ = (unsigned char)0x9b; \ + *(inst)++ = (unsigned char)0xdf; \ + *(inst)++ = (unsigned char)0xe0; \ + } while (0) + +/** + * @x86_fist_membase + * Converts content of ST(0) to integer and stores it at memory location + * addressed by [basereg + disp]. + * is_int specifies whether destination is int32 (TRUE) or int16 (FALSE). + */ +#define x86_fist_membase(inst,basereg,disp,is_int) \ + do { \ + if ((is_int)) { \ + *(inst)++ = (unsigned char)0xdb; \ + x86_membase_emit ((inst), 2, (basereg), (disp)); \ + } else { \ + *(inst)++ = (unsigned char)0xdf; \ + x86_membase_emit ((inst), 2, (basereg), (disp)); \ + } \ + } while (0) + +#define x86_push_reg(inst,reg) \ + do { \ + *(inst)++ = (unsigned char)0x50 + (reg); \ + } while (0) + +#define x86_push_regp(inst,reg) \ + do { \ + *(inst)++ = (unsigned char)0xff; \ + x86_regp_emit ((inst), 6, (reg)); \ + } while (0) + +#define x86_push_mem(inst,mem) \ + do { \ + *(inst)++ = (unsigned char)0xff; \ + x86_mem_emit ((inst), 6, (mem)); \ + } while (0) + +#define x86_push_membase(inst,basereg,disp) \ + do { \ + *(inst)++ = (unsigned char)0xff; \ + x86_membase_emit ((inst), 6, (basereg), (disp)); \ + } while (0) + +#define x86_push_memindex(inst,basereg,disp,indexreg,shift) \ + do { \ + *(inst)++ = (unsigned char)0xff; \ + x86_memindex_emit ((inst), 6, (basereg), (disp), (indexreg), (shift)); \ + } while (0) + +#define x86_push_imm_template(inst) x86_push_imm (inst, 0xf0f0f0f0) + +#define x86_push_imm(inst,imm) \ + do { \ + int _imm = (int) (imm); \ + if (x86_is_imm8 (_imm)) { \ + *(inst)++ = (unsigned char)0x6A; \ + x86_imm_emit8 ((inst), (_imm)); \ + } else { \ + *(inst)++ = (unsigned char)0x68; \ + x86_imm_emit32 ((inst), (_imm)); \ + } \ + } while (0) + +#define x86_pop_reg(inst,reg) \ + do { \ + *(inst)++ = (unsigned char)0x58 + (reg); \ + } while (0) + +#define x86_pop_mem(inst,mem) \ + do { \ + *(inst)++ = (unsigned char)0x87; \ + x86_mem_emit ((inst), 0, (mem)); \ + } while (0) + +#define x86_pop_membase(inst,basereg,disp) \ + do { \ + *(inst)++ = (unsigned char)0x87; \ + x86_membase_emit ((inst), 0, (basereg), (disp)); \ + } while (0) + +#define x86_pushad(inst) do { *(inst)++ = (unsigned char)0x60; } while (0) +#define x86_pushfd(inst) do { *(inst)++ = (unsigned char)0x9c; } while (0) +#define x86_popad(inst) do { *(inst)++ = (unsigned char)0x61; } while (0) +#define x86_popfd(inst) do { *(inst)++ = (unsigned char)0x9d; } while (0) + +#define x86_loop(inst,imm) \ + do { \ + *(inst)++ = (unsigned char)0xe2; \ + x86_imm_emit8 ((inst), (imm)); \ + } while (0) + +#define x86_loope(inst,imm) \ + do { \ + *(inst)++ = (unsigned char)0xe1; \ + x86_imm_emit8 ((inst), (imm)); \ + } while (0) + +#define x86_loopne(inst,imm) \ + do { \ + *(inst)++ = (unsigned char)0xe0; \ + x86_imm_emit8 ((inst), (imm)); \ + } while (0) + +#define x86_jump32(inst,imm) \ + do { \ + *(inst)++ = (unsigned char)0xe9; \ + x86_imm_emit32 ((inst), (imm)); \ + } while (0) + +#define x86_jump8(inst,imm) \ + do { \ + *(inst)++ = (unsigned char)0xeb; \ + x86_imm_emit8 ((inst), (imm)); \ + } while (0) + +#define x86_jump_reg(inst,reg) \ + do { \ + *(inst)++ = (unsigned char)0xff; \ + x86_reg_emit ((inst), 4, (reg)); \ + } while (0) + +#define x86_jump_mem(inst,mem) \ + do { \ + *(inst)++ = (unsigned char)0xff; \ + x86_mem_emit ((inst), 4, (mem)); \ + } while (0) + +#define x86_jump_membase(inst,basereg,disp) \ + do { \ + *(inst)++ = (unsigned char)0xff; \ + x86_membase_emit ((inst), 4, (basereg), (disp)); \ + } while (0) + +/* + * target is a pointer in our buffer. + */ +#define x86_jump_code(inst,target) \ + do { \ + int t = (unsigned char*)(target) - (inst) - 2; \ + if (x86_is_imm8(t)) { \ + x86_jump8 ((inst), t); \ + } else { \ + t -= 3; \ + x86_jump32 ((inst), t); \ + } \ + } while (0) + +#define x86_jump_disp(inst,disp) \ + do { \ + int t = (disp) - 2; \ + if (x86_is_imm8(t)) { \ + x86_jump8 ((inst), t); \ + } else { \ + t -= 3; \ + x86_jump32 ((inst), t); \ + } \ + } while (0) + +#define x86_branch8(inst,cond,imm,is_signed) \ + do { \ + if ((is_signed)) \ + *(inst)++ = x86_cc_signed_map [(cond)]; \ + else \ + *(inst)++ = x86_cc_unsigned_map [(cond)]; \ + x86_imm_emit8 ((inst), (imm)); \ + } while (0) + +#define x86_branch32(inst,cond,imm,is_signed) \ + do { \ + *(inst)++ = (unsigned char)0x0f; \ + if ((is_signed)) \ + *(inst)++ = x86_cc_signed_map [(cond)] + 0x10; \ + else \ + *(inst)++ = x86_cc_unsigned_map [(cond)] + 0x10; \ + x86_imm_emit32 ((inst), (imm)); \ + } while (0) + +#define x86_branch(inst,cond,target,is_signed) \ + do { \ + int offset = (target) - (inst) - 2; \ + if (x86_is_imm8 ((offset))) \ + x86_branch8 ((inst), (cond), offset, (is_signed)); \ + else { \ + offset -= 4; \ + x86_branch32 ((inst), (cond), offset, (is_signed)); \ + } \ + } while (0) + +#define x86_branch_disp(inst,cond,disp,is_signed) \ + do { \ + int offset = (disp) - 2; \ + if (x86_is_imm8 ((offset))) \ + x86_branch8 ((inst), (cond), offset, (is_signed)); \ + else { \ + offset -= 4; \ + x86_branch32 ((inst), (cond), offset, (is_signed)); \ + } \ + } while (0) + +#define x86_set_reg(inst,cond,reg,is_signed) \ + do { \ + assert (X86_IS_BYTE_REG (reg)); \ + *(inst)++ = (unsigned char)0x0f; \ + if ((is_signed)) \ + *(inst)++ = x86_cc_signed_map [(cond)] + 0x20; \ + else \ + *(inst)++ = x86_cc_unsigned_map [(cond)] + 0x20; \ + x86_reg_emit ((inst), 0, (reg)); \ + } while (0) + +#define x86_set_mem(inst,cond,mem,is_signed) \ + do { \ + *(inst)++ = (unsigned char)0x0f; \ + if ((is_signed)) \ + *(inst)++ = x86_cc_signed_map [(cond)] + 0x20; \ + else \ + *(inst)++ = x86_cc_unsigned_map [(cond)] + 0x20; \ + x86_mem_emit ((inst), 0, (mem)); \ + } while (0) + +#define x86_set_membase(inst,cond,basereg,disp,is_signed) \ + do { \ + *(inst)++ = (unsigned char)0x0f; \ + if ((is_signed)) \ + *(inst)++ = x86_cc_signed_map [(cond)] + 0x20; \ + else \ + *(inst)++ = x86_cc_unsigned_map [(cond)] + 0x20; \ + x86_membase_emit ((inst), 0, (basereg), (disp)); \ + } while (0) + +#define x86_call_imm(inst,disp) \ + do { \ + *(inst)++ = (unsigned char)0xe8; \ + x86_imm_emit32 ((inst), (int)(disp)); \ + } while (0) + +#define x86_call_reg(inst,reg) \ + do { \ + *(inst)++ = (unsigned char)0xff; \ + x86_reg_emit ((inst), 2, (reg)); \ + } while (0) + +#define x86_call_mem(inst,mem) \ + do { \ + *(inst)++ = (unsigned char)0xff; \ + x86_mem_emit ((inst), 2, (mem)); \ + } while (0) + +#define x86_call_membase(inst,basereg,disp) \ + do { \ + *(inst)++ = (unsigned char)0xff; \ + x86_membase_emit ((inst), 2, (basereg), (disp)); \ + } while (0) + +#define x86_call_code(inst,target) \ + do { \ + int _x86_offset = (unsigned char*)(target) - (inst); \ + _x86_offset -= 5; \ + x86_call_imm ((inst), _x86_offset); \ + } while (0) + +#define x86_ret(inst) do { *(inst)++ = (unsigned char)0xc3; } while (0) + +#define x86_ret_imm(inst,imm) \ + do { \ + if ((imm) == 0) { \ + x86_ret ((inst)); \ + } else { \ + *(inst)++ = (unsigned char)0xc2; \ + x86_imm_emit16 ((inst), (imm)); \ + } \ + } while (0) + +#define x86_cmov_reg(inst,cond,is_signed,dreg,reg) \ + do { \ + *(inst)++ = (unsigned char) 0x0f; \ + if ((is_signed)) \ + *(inst)++ = x86_cc_signed_map [(cond)] - 0x30; \ + else \ + *(inst)++ = x86_cc_unsigned_map [(cond)] - 0x30; \ + x86_reg_emit ((inst), (dreg), (reg)); \ + } while (0) + +#define x86_cmov_mem(inst,cond,is_signed,reg,mem) \ + do { \ + *(inst)++ = (unsigned char) 0x0f; \ + if ((is_signed)) \ + *(inst)++ = x86_cc_signed_map [(cond)] - 0x30; \ + else \ + *(inst)++ = x86_cc_unsigned_map [(cond)] - 0x30; \ + x86_mem_emit ((inst), (reg), (mem)); \ + } while (0) + +#define x86_cmov_membase(inst,cond,is_signed,reg,basereg,disp) \ + do { \ + *(inst)++ = (unsigned char) 0x0f; \ + if ((is_signed)) \ + *(inst)++ = x86_cc_signed_map [(cond)] - 0x30; \ + else \ + *(inst)++ = x86_cc_unsigned_map [(cond)] - 0x30; \ + x86_membase_emit ((inst), (reg), (basereg), (disp)); \ + } while (0) + +#define x86_enter(inst,framesize) \ + do { \ + *(inst)++ = (unsigned char)0xc8; \ + x86_imm_emit16 ((inst), (framesize)); \ + *(inst)++ = 0; \ + } while (0) + +#define x86_leave(inst) do { *(inst)++ = (unsigned char)0xc9; } while (0) +#define x86_sahf(inst) do { *(inst)++ = (unsigned char)0x9e; } while (0) + +#define x86_fsin(inst) do { *(inst)++ = (unsigned char)0xd9; *(inst)++ = (unsigned char)0xfe; } while (0) +#define x86_fcos(inst) do { *(inst)++ = (unsigned char)0xd9; *(inst)++ = (unsigned char)0xff; } while (0) +#define x86_fabs(inst) do { *(inst)++ = (unsigned char)0xd9; *(inst)++ = (unsigned char)0xe1; } while (0) +#define x86_ftst(inst) do { *(inst)++ = (unsigned char)0xd9; *(inst)++ = (unsigned char)0xe4; } while (0) +#define x86_fxam(inst) do { *(inst)++ = (unsigned char)0xd9; *(inst)++ = (unsigned char)0xe5; } while (0) +#define x86_fpatan(inst) do { *(inst)++ = (unsigned char)0xd9; *(inst)++ = (unsigned char)0xf3; } while (0) +#define x86_fprem(inst) do { *(inst)++ = (unsigned char)0xd9; *(inst)++ = (unsigned char)0xf8; } while (0) +#define x86_fprem1(inst) do { *(inst)++ = (unsigned char)0xd9; *(inst)++ = (unsigned char)0xf5; } while (0) +#define x86_frndint(inst) do { *(inst)++ = (unsigned char)0xd9; *(inst)++ = (unsigned char)0xfc; } while (0) +#define x86_fsqrt(inst) do { *(inst)++ = (unsigned char)0xd9; *(inst)++ = (unsigned char)0xfa; } while (0) +#define x86_fptan(inst) do { *(inst)++ = (unsigned char)0xd9; *(inst)++ = (unsigned char)0xf2; } while (0) + +#define x86_padding(inst,size) \ + do { \ + switch ((size)) { \ + case 1: x86_nop ((inst)); break; \ + case 2: *(inst)++ = 0x8b; \ + *(inst)++ = 0xc0; break; \ + case 3: *(inst)++ = 0x8d; *(inst)++ = 0x6d; \ + *(inst)++ = 0x00; break; \ + case 4: *(inst)++ = 0x8d; *(inst)++ = 0x64; \ + *(inst)++ = 0x24; *(inst)++ = 0x00; \ + break; \ + case 5: *(inst)++ = 0x8d; *(inst)++ = 0x64; \ + *(inst)++ = 0x24; *(inst)++ = 0x00; \ + x86_nop ((inst)); break; \ + case 6: *(inst)++ = 0x8d; *(inst)++ = 0xad; \ + *(inst)++ = 0x00; *(inst)++ = 0x00; \ + *(inst)++ = 0x00; *(inst)++ = 0x00; \ + break; \ + case 7: *(inst)++ = 0x8d; *(inst)++ = 0xa4; \ + *(inst)++ = 0x24; *(inst)++ = 0x00; \ + *(inst)++ = 0x00; *(inst)++ = 0x00; \ + *(inst)++ = 0x00; break; \ + default: assert (0); \ + } \ + } while (0) + +#define x86_prolog(inst,frame_size,reg_mask) \ + do { \ + unsigned i, m = 1; \ + x86_enter ((inst), (frame_size)); \ + for (i = 0; i < X86_NREG; ++i, m <<= 1) { \ + if ((reg_mask) & m) \ + x86_push_reg ((inst), i); \ + } \ + } while (0) + +#define x86_epilog(inst,reg_mask) \ + do { \ + unsigned i, m = 1 << X86_EDI; \ + for (i = X86_EDI; m != 0; i--, m=m>>1) { \ + if ((reg_mask) & m) \ + x86_pop_reg ((inst), i); \ + } \ + x86_leave ((inst)); \ + x86_ret ((inst)); \ + } while (0) + +#endif // X86_H diff --git a/tools/virtualmips/x86_trans.c b/tools/virtualmips/x86_trans.c new file mode 100644 index 0000000..48c68ea --- /dev/null +++ b/tools/virtualmips/x86_trans.c @@ -0,0 +1,3025 @@ +/* + * Copyright (C) yajin 2008 + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cpu.h" +#include "vm.h" +#include "mips_exec.h" +#include "mips_memory.h" +#include "mips.h" +#include "mips_cp0.h" +#include "debug.h" +#include "vp_timer.h" +#include "x86_trans.h" + +#ifdef _USE_JIT_ +struct mips_jit_desc mips_jit[]; +static struct mips_jit_desc mips_spec_jit[]; +static struct mips_jit_desc mips_bcond_jit[]; +static struct mips_jit_desc mips_cop0_jit[]; +static struct mips_jit_desc mips_mad_jit[]; +static struct mips_jit_desc mips_tlb_jit[]; +void fastcall mips_exec_single_step (cpu_mips_t * cpu, + mips_insn_t instruction); + +#define REG_OFFSET(reg) (OFFSET(cpu_mips_t,gpr[(reg)])) +#define CP0_REG_OFFSET(c0reg) (OFFSET(cpu_mips_t,cp0.reg[(c0reg)])) +#define MEMOP_OFFSET(op) (OFFSET(cpu_mips_t,mem_op_fn[(op)])) + +/* Set the Pointer Counter (PC) register */ +void mips_set_pc (mips_jit_tcb_t * b, m_va_t new_pc) +{ + x86_mov_membase_imm (b->jit_ptr, X86_EDI, OFFSET (cpu_mips_t, pc), + new_pc & 0xFFFFFFFF, 4); +} + +/* Set the Return Address (RA) register */ +void mips_set_ra (mips_jit_tcb_t * b, m_va_t ret_pc) +{ + + x86_mov_membase_imm (b->jit_ptr, X86_EDI, REG_OFFSET (MIPS_GPR_RA), + ret_pc & 0xFFFFFFFF, 4); + +} + +/* + * Try to branch directly to the specified JIT block without returning to + * main loop. + */ +static void mips_try_direct_far_jump (cpu_mips_t * cpu, + mips_jit_tcb_t * b, m_va_t new_pc) +{ + m_va_t new_page; + m_uint32_t pc_hash, pc_offset; + u_char *test1, *test2, *test3, *test4, *test5, *test6; + + new_page = new_pc & MIPS_MIN_PAGE_MASK; + pc_offset = (new_pc & MIPS_MIN_PAGE_IMASK) >> 2; + pc_hash = mips_jit_get_pc_hash (cpu, new_pc); + + /* Get JIT block info in %edx */ + x86_mov_reg_membase (b->jit_ptr, X86_EBX, + X86_EDI, OFFSET (cpu_mips_t, exec_blk_map), 4); + x86_mov_reg_membase (b->jit_ptr, X86_EDX, X86_EBX, + pc_hash * sizeof (void *), 4); + + /* no JIT block found ? */ + x86_test_reg_reg (b->jit_ptr, X86_EDX, X86_EDX); + test1 = b->jit_ptr; + x86_branch8 (b->jit_ptr, X86_CC_Z, 0, 1); + + /* Check block PC */ + x86_mov_reg_imm (b->jit_ptr, X86_EAX, (m_uint32_t) new_page); + x86_alu_reg_membase (b->jit_ptr, X86_CMP, X86_EAX, X86_EDX, + OFFSET (mips_jit_tcb_t, start_pc)); + test2 = b->jit_ptr; + x86_branch8 (b->jit_ptr, X86_CC_NE, 0, 1); + + /*whether newpc is mapped */ + x86_shift_reg_imm (b->jit_ptr, X86_SHR, X86_EAX, 29); + x86_alu_reg_imm (b->jit_ptr, X86_AND, X86_EAX, 0x7); + + x86_alu_reg_imm (b->jit_ptr, X86_CMP, X86_EAX, 0x4); + test4 = b->jit_ptr; + x86_branch8 (b->jit_ptr, X86_CC_E, 0, 1); + + x86_alu_reg_imm (b->jit_ptr, X86_CMP, X86_EAX, 0x5); + test5 = b->jit_ptr; + x86_branch8 (b->jit_ptr, X86_CC_E, 0, 1); + + /*check ASID */ + x86_lea_membase (b->jit_ptr, X86_ESI, X86_EDI, OFFSET (cpu_mips_t, cp0)); + //x86_mov_reg_membase(b->jit_ptr,X86_ESI, + // X86_EDI,OFFSET(cpu_mips_t,cp0),4); + x86_mov_reg_membase (b->jit_ptr, X86_EBX, + X86_ESI, OFFSET (mips_cp0_t, reg[MIPS_CP0_TLB_HI]), 4); + x86_alu_reg_imm (b->jit_ptr, X86_AND, X86_EBX, MIPS_TLB_ASID_MASK); + x86_alu_reg_membase (b->jit_ptr, X86_CMP, X86_EBX, X86_EDX, + OFFSET (mips_jit_tcb_t, asid)); + test6 = b->jit_ptr; + x86_branch8 (b->jit_ptr, X86_CC_NE, 0, 1); + + x86_patch (test4, b->jit_ptr); + x86_patch (test5, b->jit_ptr); + /* Jump to the code */ + x86_mov_reg_membase (b->jit_ptr, X86_ESI, + X86_EDX, OFFSET (mips_jit_tcb_t, jit_insn_ptr), 4); + x86_mov_reg_membase (b->jit_ptr, X86_EBX, + X86_ESI, pc_offset * sizeof (void *), 4); + + x86_test_reg_reg (b->jit_ptr, X86_EBX, X86_EBX); + test3 = b->jit_ptr; + x86_branch8 (b->jit_ptr, X86_CC_Z, 0, 1); + x86_jump_reg (b->jit_ptr, X86_EBX); + + /* Returns to caller... */ + x86_patch (test1, b->jit_ptr); + x86_patch (test2, b->jit_ptr); + x86_patch (test3, b->jit_ptr); + x86_patch (test6, b->jit_ptr); + + mips_set_pc (b, new_pc); + mips_jit_tcb_push_epilog (b); +} + +/* Set Jump */ +static void mips_set_jump (cpu_mips_t * cpu, mips_jit_tcb_t * b, + m_va_t new_pc, int local_jump) +{ + int return_to_caller = FALSE; + u_char *jump_ptr; + + if (!local_jump) + return_to_caller = TRUE; + + if (!return_to_caller && mips_jit_tcb_local_addr (b, new_pc, &jump_ptr)) { + if (jump_ptr) { + x86_jump_code (b->jit_ptr, jump_ptr); + } else { + /* Never jump directly to code in a delay slot. */ + /*Hi yajin, why a delay slot can have entry point or why have to jmp + * to delay slot? + * The following is the code from celinux 2.4. + * + * 802a19d4: 1500004a bnez t0,802a1b00 + * + * 802a19d8 : + * 802a19d8: 00064142 srl t0,a2,0x5 + * + * if call function both_aligned(0x802a19d8), it is in delay slot of 0x802a19d4 but it is + * the entry of function both_aligned. + * Just set pc to 0x802a19d8 and return main loop. + */ + if (mips_jit_is_delay_slot (b, new_pc)) { + mips_set_pc (b, new_pc); + mips_jit_tcb_push_epilog (b); + return; + } + + mips_jit_tcb_record_patch (b, b->jit_ptr, new_pc); + x86_jump32 (b->jit_ptr, 0); + } + } else { + mips_try_direct_far_jump (cpu, b, new_pc); + +#if 0 + if (cpu->exec_blk_direct_jump) { + /* Block lookup optimization */ + mips_try_direct_far_jump (cpu, b, new_pc); + } else { + mips_set_pc (b, new_pc); + mips_jit_tcb_push_epilog (b); + } +#endif + } + +} + +/* Basic C call */ +void mips_emit_basic_c_call (mips_jit_tcb_t * b, void *f) +{ + x86_mov_reg_imm (b->jit_ptr, X86_EBX, f); + x86_call_reg (b->jit_ptr, X86_EBX); +} + +/* Emit a simple call to a C function without any parameter */ +static void mips_emit_c_call (mips_jit_tcb_t * b, void *f) +{ + mips_set_pc (b, b->start_pc + ((b->mips_trans_pos - 1) << 2)); + mips_emit_basic_c_call (b, f); +} + +/* Single-step operation */ +void mips_emit_single_step (mips_jit_tcb_t * b, mips_insn_t insn) +{ + x86_mov_reg_reg (b->jit_ptr, X86_EAX, X86_EDI, 4); + x86_mov_reg_imm (b->jit_ptr, X86_EDX, insn); + mips_emit_basic_c_call (b, mips_exec_single_step); +} + +/* Memory operation */ +/*we use EAX EDX ECX to transfer parameter. yajin. +Makesure memory operation DONOT have more than 3 parameters*/ +static void mips_emit_memop (mips_jit_tcb_t * b, int op, int base, + int offset, int target, int keep_ll_bit) +{ + m_va_t val = sign_extend (offset, 16); + m_uint8_t *test1; + + /* Save PC for exception handling */ + mips_set_pc (b, b->start_pc + ((b->mips_trans_pos - 1) << 2)); + + if (!keep_ll_bit) { + x86_clear_reg (b->jit_ptr, X86_EAX); + x86_mov_membase_reg (b->jit_ptr, X86_EDI, OFFSET (cpu_mips_t, ll_bit), + X86_EAX, 4); + } + + x86_mov_reg_imm (b->jit_ptr, X86_EDX, val); + + /* EDX = GPR[base] + sign-extended offset */ + x86_alu_reg_membase (b->jit_ptr, X86_ADD, X86_EDX, X86_EDI, + REG_OFFSET (base)); + + /* ECX = target register */ + x86_mov_reg_imm (b->jit_ptr, X86_ECX, target); + + /* EAX = CPU instance pointer */ + x86_mov_reg_reg (b->jit_ptr, X86_EAX, X86_EDI, 4); + + x86_mov_reg_membase (b->jit_ptr, X86_EBX, X86_EDI, MEMOP_OFFSET (op), 4); + x86_call_reg (b->jit_ptr, X86_EBX); + + /*check the return value */ + x86_alu_reg_imm (b->jit_ptr, X86_CMP, X86_EAX, 0); + /*IF return value==0.NO exception. */ + test1 = b->jit_ptr; + x86_branch8 (b->jit_ptr, X86_CC_E, 0, 1); + mips_jit_tcb_push_epilog (b); + x86_patch (test1, b->jit_ptr); + +} + +/* Unknown opcode handler */ +static asmlinkage void mips_unknown_opcode (cpu_mips_t * cpu, + m_uint32_t opcode) +{ + printf ("MIPS64: unhandled opcode 0x%8.8x at 0x%" LL "x (ra=0x%" LL + "x)\n", opcode, cpu->pc, cpu->gpr[MIPS_GPR_RA]); + + //mips_dump_regs(cpu); +} + +/* Emit unhandled instruction code */ +static int mips_emit_unknown (cpu_mips_t * cpu, mips_jit_tcb_t * b, + mips_insn_t opcode) +{ + x86_mov_reg_imm (b->jit_ptr, X86_EAX, opcode); + x86_alu_reg_imm (b->jit_ptr, X86_SUB, X86_ESP, 4); + x86_push_reg (b->jit_ptr, X86_EAX); + x86_push_reg (b->jit_ptr, X86_EDI); + mips_emit_c_call (b, mips_unknown_opcode); + x86_alu_reg_imm (b->jit_ptr, X86_ADD, X86_ESP, 12); + return (0); +} + +/* Invalid delay slot handler */ +static fastcall void mips_invalid_delay_slot (cpu_mips_t * cpu) +{ + printf ("MIPS64: invalid instruction in delay slot at 0x%" LL "x (ra=0x%" + LL "x)\n", cpu->pc, cpu->gpr[MIPS_GPR_RA]); + + //mips_dump_regs(cpu); + + /* Halt the virtual CPU */ + cpu->pc = 0; +} + +/* Emit unhandled instruction code */ +int mips_emit_invalid_delay_slot (mips_jit_tcb_t * b) +{ + x86_mov_reg_reg (b->jit_ptr, X86_EAX, X86_EDI, 4); + mips_emit_c_call (b, mips_invalid_delay_slot); + x86_alu_reg_imm (b->jit_ptr, X86_ADD, X86_ESP, 12); + + mips_jit_tcb_push_epilog (b); + return (0); +} + +void mips_check_cpu_pausing (mips_jit_tcb_t * b) +{ + u_char *test1; + + /* Check pause_request */ + x86_mov_reg_membase (b->jit_ptr, X86_EAX, + X86_EDI, OFFSET (cpu_mips_t, pause_request), 4); + x86_alu_reg_imm (b->jit_ptr, X86_AND, X86_EAX, CPU_INTERRUPT_EXIT); + x86_alu_reg_imm (b->jit_ptr, X86_CMP, X86_EAX, CPU_INTERRUPT_EXIT); + test1 = b->jit_ptr; + x86_branch32 (b->jit_ptr, X86_CC_NE, 0, 1); + /*if (cpu->pause_request)&CPU_INTERRUPT_EXIT==CPU_INTERRUPT_EXIT, + * set cpu->state and return to main loop */ + mips_set_pc (b, b->start_pc + ((b->mips_trans_pos - 1) << 2)); + x86_mov_membase_imm (b->jit_ptr, X86_EDI, OFFSET (cpu_mips_t, state), + CPU_STATE_PAUSING, 4); + mips_jit_tcb_push_epilog (b); + /*else do noting */ + x86_patch (test1, b->jit_ptr); + +} + +/* Check if there are pending IRQ */ +void mips_check_pending_irq (mips_jit_tcb_t * b) +{ + u_char *test1; + + /* Check the pending IRQ flag */ + x86_mov_reg_membase (b->jit_ptr, X86_EAX, + X86_EDI, OFFSET (cpu_mips_t, irq_pending), 4); + x86_test_reg_reg (b->jit_ptr, X86_EAX, X86_EAX); + test1 = b->jit_ptr; + x86_branch32 (b->jit_ptr, X86_CC_Z, 0, 1); + + /* Save PC */ + mips_set_pc (b, b->start_pc + ((b->mips_trans_pos - 1) << 2)); + + /* Trigger the IRQ */ + x86_mov_reg_reg (b->jit_ptr, X86_EAX, X86_EDI, 4); + mips_emit_basic_c_call (b, mips_trigger_irq); + mips_jit_tcb_push_epilog (b); + + x86_patch (test1, b->jit_ptr); +} + +/* ADD */ +static int mips_emit_add (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + int rs = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + int rd = bits (insn, 11, 15); + //printf("rs %d rt %d rd %d \n",rs,rt,rd); + + /* TODO: Exception handling */ + x86_mov_reg_membase (b->jit_ptr, X86_EAX, X86_EDI, REG_OFFSET (rs), 4); + x86_alu_reg_membase (b->jit_ptr, X86_ADD, X86_EAX, X86_EDI, + REG_OFFSET (rt)); + x86_mov_membase_reg (b->jit_ptr, X86_EDI, REG_OFFSET (rd), X86_EAX, 4); + + return (0); +} + +/* ADDI */ +static int mips_emit_addi (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + int rs = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + int imm = bits (insn, 0, 15); + m_uint32_t val = sign_extend (imm, 16); + // printf("rs %d rt %d val %d \n",rs,rt,val); + /* TODO: Exception handling */ + + x86_mov_reg_imm (b->jit_ptr, X86_EAX, val); + x86_alu_reg_membase (b->jit_ptr, X86_ADD, X86_EAX, X86_EDI, + REG_OFFSET (rs)); + x86_mov_membase_reg (b->jit_ptr, X86_EDI, REG_OFFSET (rt), X86_EAX, 4); + return (0); +} + +/* ADDI */ +static int mips_emit_addiu (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + int rs = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + int imm = bits (insn, 0, 15); + m_uint32_t val = sign_extend (imm, 16); + // printf("rs %d rt %d val %d \n",rs,rt,val); + /* TODO: Exception handling */ + + x86_mov_reg_imm (b->jit_ptr, X86_EAX, val); + x86_alu_reg_membase (b->jit_ptr, X86_ADD, X86_EAX, X86_EDI, + REG_OFFSET (rs)); + x86_mov_membase_reg (b->jit_ptr, X86_EDI, REG_OFFSET (rt), X86_EAX, 4); + return (0); +} + +/* ADDu */ +static int mips_emit_addu (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + int rs = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + int rd = bits (insn, 11, 15); + // printf("rs %d rt %d rd %d \n",rs,rt,rd); + + x86_mov_reg_membase (b->jit_ptr, X86_EAX, X86_EDI, REG_OFFSET (rs), 4); + x86_alu_reg_membase (b->jit_ptr, X86_ADD, X86_EAX, X86_EDI, + REG_OFFSET (rt)); + x86_mov_membase_reg (b->jit_ptr, X86_EDI, REG_OFFSET (rd), X86_EAX, 4); + + return (0); +} + +/* AND */ +static int mips_emit_and (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + int rs = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + int rd = bits (insn, 11, 15); + + x86_mov_reg_membase (b->jit_ptr, X86_EAX, X86_EDI, REG_OFFSET (rs), 4); + x86_alu_reg_membase (b->jit_ptr, X86_AND, X86_EAX, X86_EDI, + REG_OFFSET (rt)); + x86_mov_membase_reg (b->jit_ptr, X86_EDI, REG_OFFSET (rd), X86_EAX, 4); + return (0); +} + +/* ANDI */ +static int mips_emit_andi (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + int rs = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + int imm = bits (insn, 0, 15); + + x86_mov_reg_imm (b->jit_ptr, X86_EAX, imm); + x86_alu_reg_membase (b->jit_ptr, X86_AND, X86_EAX, X86_EDI, + REG_OFFSET (rs)); + x86_mov_membase_reg (b->jit_ptr, X86_EDI, REG_OFFSET (rt), X86_EAX, 4); + return (0); +} + +static int mips_emit_bcond (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + uint16_t special_func = bits (insn, 16, 20); + return mips_bcond_jit[special_func].emit_func (cpu, b, insn); +} + +/* +Hi yajin, why we need call mips_jit_fetch_and_emit twice? +Why do we translate beq like this: + +mips_jit_fetch_and_emit(cpu,b,1); +x86_mov_reg_membase(b->jit_ptr,X86_EAX,X86_EDI,REG_OFFSET(rs),4); +x86_alu_reg_membase(b->jit_ptr,X86_CMP,X86_EAX,X86_EDI,REG_OFFSET(rt)); +test1 = b->jit_ptr; +x86_branch32(b->jit_ptr, X86_CC_NE, 0, 1); +mips_set_jump(cpu,b,new_pc,1); +x86_patch(test1,b->jit_ptr); + +That is fetching the delay slot code first and then jumping to new pc according to +the comparing result of register rs and register rt. + +This seems right but it is wrong and not easy to catch this bug!!! + +The instruction in delay slot may change the content of register rs and rt and the +comparing result can not be trusted anymore. +We MUST compare register rs and rt and then run the code in delay slot. + +*/ +/* BEQ (Branch On Equal) */ +static int mips_emit_beq (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + int rs = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + int offset = bits (insn, 0, 15); + u_char *test1; + m_va_t new_pc; + + /* compute the new pc */ + new_pc = b->start_pc + (b->mips_trans_pos << 2); + new_pc += sign_extend (offset << 2, 18); + + /* + * compare gpr[rs] and gpr[rt]. + * compare the low 32 bits first (higher probability). + */ + x86_mov_reg_membase (b->jit_ptr, X86_EAX, X86_EDI, REG_OFFSET (rs), 4); + x86_alu_reg_membase (b->jit_ptr, X86_CMP, X86_EAX, X86_EDI, + REG_OFFSET (rt)); + test1 = b->jit_ptr; + x86_branch32 (b->jit_ptr, X86_CC_NE, 0, 1); + + /* insert the instruction in the delay slot */ + mips_jit_fetch_and_emit (cpu, b, 2); + + /* set the new pc in cpu structure */ + mips_set_jump (cpu, b, new_pc, 1); + + x86_patch (test1, b->jit_ptr); + + /* if the branch is not taken, we have to execute the delay slot too */ + mips_jit_fetch_and_emit (cpu, b, 1); + return (0); +} + +/* BEQL (Branch On Equal Likely) */ +static int mips_emit_beql (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + int rs = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + int offset = bits (insn, 0, 15); + u_char *test1; + m_va_t new_pc; + + /* compute the new pc */ + new_pc = b->start_pc + (b->mips_trans_pos << 2); + new_pc += sign_extend (offset << 2, 18); + + /* + * compare gpr[rs] and gpr[rt]. + * compare the low 32 bits first (higher probability). + */ + x86_mov_reg_membase (b->jit_ptr, X86_EAX, X86_EDI, REG_OFFSET (rs), 4); + x86_alu_reg_membase (b->jit_ptr, X86_CMP, X86_EAX, X86_EDI, + REG_OFFSET (rt)); + test1 = b->jit_ptr; + x86_branch32 (b->jit_ptr, X86_CC_NE, 0, 1); + /* insert the instruction in the delay slot */ + mips_jit_fetch_and_emit (cpu, b, 1); + /* set the new pc in cpu structure */ + mips_set_jump (cpu, b, new_pc, 1); + + x86_patch (test1, b->jit_ptr); + return (0); +} + +/* BGEZ (Branch On Greater or Equal Than Zero) */ +static int mips_emit_bgez (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + int rs = bits (insn, 21, 25); + int offset = bits (insn, 0, 15); + u_char *test1; + m_va_t new_pc; + + /* compute the new pc */ + new_pc = b->start_pc + (b->mips_trans_pos << 2); + new_pc += sign_extend (offset << 2, 18); + + /* If sign bit is set, don't take the branch */ + x86_mov_reg_membase (b->jit_ptr, X86_EAX, X86_EDI, REG_OFFSET (rs), 4); + x86_test_reg_reg (b->jit_ptr, X86_EAX, X86_EAX); + test1 = b->jit_ptr; + x86_branch32 (b->jit_ptr, X86_CC_S, 0, 1); + + /* insert the instruction in the delay slot */ + mips_jit_fetch_and_emit (cpu, b, 2); + + /* set the new pc in cpu structure */ + mips_set_jump (cpu, b, new_pc, 1); + + x86_patch (test1, b->jit_ptr); + + /* if the branch is not taken, we have to execute the delay slot too */ + mips_jit_fetch_and_emit (cpu, b, 1); + return (0); +} + +/* BGEZAL (Branch On Greater or Equal Than Zero And Link) */ +static int mips_emit_bgezal (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + int rs = bits (insn, 21, 25); + int offset = bits (insn, 0, 15); + u_char *test1; + m_va_t new_pc; + + /* compute the new pc */ + new_pc = b->start_pc + (b->mips_trans_pos << 2); + new_pc += sign_extend (offset << 2, 18); + + /* set the return address (instruction after the delay slot) */ + mips_set_ra (b, b->start_pc + ((b->mips_trans_pos + 1) << 2)); + + /* If sign bit is set, don't take the branch */ + x86_mov_reg_membase (b->jit_ptr, X86_EAX, X86_EDI, REG_OFFSET (rs), 4); + x86_test_reg_reg (b->jit_ptr, X86_EAX, X86_EAX); + test1 = b->jit_ptr; + x86_branch32 (b->jit_ptr, X86_CC_S, 0, 1); + + /* insert the instruction in the delay slot */ + mips_jit_fetch_and_emit (cpu, b, 2); + + /* set the new pc in cpu structure */ + mips_set_jump (cpu, b, new_pc, 1); + + x86_patch (test1, b->jit_ptr); + + /* if the branch is not taken, we have to execute the delay slot too */ + mips_jit_fetch_and_emit (cpu, b, 1); + return (0); +} + +/* BGEZALL (Branch On Greater or Equal Than Zero and Link Likely) */ +static int mips_emit_bgezall (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + int rs = bits (insn, 21, 25); + int offset = bits (insn, 0, 15); + u_char *test1; + m_va_t new_pc; + + /* compute the new pc */ + new_pc = b->start_pc + (b->mips_trans_pos << 2); + new_pc += sign_extend (offset << 2, 18); + + /* set the return address (instruction after the delay slot) */ + mips_set_ra (b, b->start_pc + ((b->mips_trans_pos + 1) << 2)); + + /* if sign bit is set, don't take the branch */ + x86_mov_reg_membase (b->jit_ptr, X86_EAX, X86_EDI, REG_OFFSET (rs), 4); + x86_test_reg_reg (b->jit_ptr, X86_EAX, X86_EAX); + test1 = b->jit_ptr; + x86_branch32 (b->jit_ptr, X86_CC_S, 0, 1); + + /* insert the instruction in the delay slot */ + mips_jit_fetch_and_emit (cpu, b, 1); + + /* set the new pc in cpu structure */ + mips_set_jump (cpu, b, new_pc, 1); + + x86_patch (test1, b->jit_ptr); + return (0); +} + +/* BGEZL (Branch On Greater or Equal Than Zero Likely) */ +static int mips_emit_bgezl (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + int rs = bits (insn, 21, 25); + int offset = bits (insn, 0, 15); + u_char *test1; + m_va_t new_pc; + + /* compute the new pc */ + new_pc = b->start_pc + (b->mips_trans_pos << 2); + new_pc += sign_extend (offset << 2, 18); + + /* if sign bit is set, don't take the branch */ + x86_mov_reg_membase (b->jit_ptr, X86_EAX, X86_EDI, REG_OFFSET (rs), 4); + x86_test_reg_reg (b->jit_ptr, X86_EAX, X86_EAX); + test1 = b->jit_ptr; + x86_branch32 (b->jit_ptr, X86_CC_S, 0, 1); + + /* insert the instruction in the delay slot */ + mips_jit_fetch_and_emit (cpu, b, 1); + + /* set the new pc in cpu structure */ + mips_set_jump (cpu, b, new_pc, 1); + + x86_patch (test1, b->jit_ptr); + return (0); +} + +/* BGTZ (Branch On Greater Than Zero) */ +static int mips_emit_bgtz (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + int rs = bits (insn, 21, 25); + int offset = bits (insn, 0, 15); + u_char *test1, *test2; + m_va_t new_pc; + + /* compute the new pc */ + new_pc = b->start_pc + (b->mips_trans_pos << 2); + new_pc += sign_extend (offset << 2, 18); + + x86_mov_reg_membase (b->jit_ptr, X86_EAX, X86_EDI, REG_OFFSET (rs), 4); + x86_test_reg_reg (b->jit_ptr, X86_EAX, X86_EAX); + /*goto end if <0 */ + test1 = b->jit_ptr; + x86_branch32 (b->jit_ptr, X86_CC_S, 0, 1); + /*goto end if =0 */ + test2 = b->jit_ptr; + x86_branch32 (b->jit_ptr, X86_CC_Z, 0, 1); + + /* here, we take the branch */ + //x86_patch(test2,b->jit_ptr); + + /* insert the instruction in the delay slot */ + mips_jit_fetch_and_emit (cpu, b, 2); + + /* set the new pc in cpu structure */ + mips_set_jump (cpu, b, new_pc, 1); + + x86_patch (test1, b->jit_ptr); + x86_patch (test2, b->jit_ptr); + + /* if the branch is not taken, we have to execute the delay slot too */ + mips_jit_fetch_and_emit (cpu, b, 1); + return (0); +} + +/* BGTZL (Branch On Greater Than Zero Likely) */ +static int mips_emit_bgtzl (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + int rs = bits (insn, 21, 25); + int offset = bits (insn, 0, 15); + u_char *test1, *test2; + m_va_t new_pc; + + /* compute the new pc */ + new_pc = b->start_pc + (b->mips_trans_pos << 2); + new_pc += sign_extend (offset << 2, 18); + + x86_mov_reg_membase (b->jit_ptr, X86_EAX, X86_EDI, REG_OFFSET (rs), 4); + x86_test_reg_reg (b->jit_ptr, X86_EAX, X86_EAX); + /*goto end if <0 */ + test1 = b->jit_ptr; + x86_branch32 (b->jit_ptr, X86_CC_S, 0, 1); + /*goto end if =0 */ + test2 = b->jit_ptr; + x86_branch32 (b->jit_ptr, X86_CC_Z, 0, 1); + + /* here, we take the branch */ + // x86_patch(test2,b->jit_ptr); + + /* insert the instruction in the delay slot */ + mips_jit_fetch_and_emit (cpu, b, 1); + + /* set the new pc in cpu structure */ + mips_set_jump (cpu, b, new_pc, 1); + + x86_patch (test1, b->jit_ptr); + x86_patch (test2, b->jit_ptr); + return (0); +} + +/* BLEZ (Branch On Less or Equal Than Zero) */ +static int mips_emit_blez (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + int rs = bits (insn, 21, 25); + int offset = bits (insn, 0, 15); + u_char *test1, *test2; + m_va_t new_pc; + + /* compute the new pc */ + new_pc = b->start_pc + (b->mips_trans_pos << 2); + new_pc += sign_extend (offset << 2, 18); + + x86_mov_reg_membase (b->jit_ptr, X86_EAX, X86_EDI, REG_OFFSET (rs), 4); + x86_test_reg_reg (b->jit_ptr, X86_EAX, X86_EAX); + /*if <0, take the branch */ + test1 = b->jit_ptr; + x86_branch32 (b->jit_ptr, X86_CC_S, 0, 1); + /*else if !=0, do not take the branch */ + test2 = b->jit_ptr; + x86_branch32 (b->jit_ptr, X86_CC_NZ, 0, 1); + + /* here, we take the branch */ + x86_patch (test1, b->jit_ptr); + + /* insert the instruction in the delay slot */ + mips_jit_fetch_and_emit (cpu, b, 2); + + /* set the new pc in cpu structure */ + mips_set_jump (cpu, b, new_pc, 1); + + x86_patch (test2, b->jit_ptr); + + /* if the branch is not taken, we have to execute the delay slot too */ + mips_jit_fetch_and_emit (cpu, b, 1); + return (0); +} + +/* BLEZL (Branch On Less or Equal Than Zero Likely) */ +static int mips_emit_blezl (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + int rs = bits (insn, 21, 25); + int offset = bits (insn, 0, 15); + u_char *test1, *test2; + m_va_t new_pc; + + /* compute the new pc */ + new_pc = b->start_pc + (b->mips_trans_pos << 2); + new_pc += sign_extend (offset << 2, 18); + + x86_mov_reg_membase (b->jit_ptr, X86_EAX, X86_EDI, REG_OFFSET (rs), 4); + x86_test_reg_reg (b->jit_ptr, X86_EAX, X86_EAX); + /*if <0, take the branch */ + test1 = b->jit_ptr; + x86_branch32 (b->jit_ptr, X86_CC_S, 0, 1); + /*else if !=0, do not take the branch */ + test2 = b->jit_ptr; + x86_branch32 (b->jit_ptr, X86_CC_NZ, 0, 1); + + /* here, we take the branch */ + x86_patch (test1, b->jit_ptr); + + /* insert the instruction in the delay slot */ + mips_jit_fetch_and_emit (cpu, b, 1); + + /* set the new pc in cpu structure */ + mips_set_jump (cpu, b, new_pc, 1); + + x86_patch (test2, b->jit_ptr); + return (0); +} + +/* BLTZ (Branch On Less Than Zero) */ +static int mips_emit_bltz (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + int rs = bits (insn, 21, 25); + int offset = bits (insn, 0, 15); + u_char *test1; + m_va_t new_pc; + + /* compute the new pc */ + new_pc = b->start_pc + (b->mips_trans_pos << 2); + new_pc += sign_extend (offset << 2, 18); + + /* + * test the sign bit of gpr[rs], if set, take the branch. + */ + x86_mov_reg_membase (b->jit_ptr, X86_EAX, X86_EDI, REG_OFFSET (rs), 4); + x86_test_reg_reg (b->jit_ptr, X86_EAX, X86_EAX); + test1 = b->jit_ptr; + x86_branch32 (b->jit_ptr, X86_CC_NS, 0, 1); + + /* insert the instruction in the delay slot */ + mips_jit_fetch_and_emit (cpu, b, 2); + + /* set the new pc in cpu structure */ + mips_set_jump (cpu, b, new_pc, 1); + + x86_patch (test1, b->jit_ptr); + + /* if the branch is not taken, we have to execute the delay slot too */ + mips_jit_fetch_and_emit (cpu, b, 1); + return (0); +} + +/* BLTZAL (Branch On Less Than Zero And Link) */ +static int mips_emit_bltzal (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + int rs = bits (insn, 21, 25); + int offset = bits (insn, 0, 15); + u_char *test1; + m_va_t new_pc; + + /* compute the new pc */ + new_pc = b->start_pc + (b->mips_trans_pos << 2); + new_pc += sign_extend (offset << 2, 18); + + /* set the return address (instruction after the delay slot) */ + mips_set_ra (b, b->start_pc + ((b->mips_trans_pos + 1) << 2)); + + /* + * test the sign bit of gpr[rs], if set, take the branch. + */ + x86_mov_reg_membase (b->jit_ptr, X86_EAX, X86_EDI, REG_OFFSET (rs), 4); + x86_test_reg_reg (b->jit_ptr, X86_EAX, X86_EAX); + test1 = b->jit_ptr; + x86_branch32 (b->jit_ptr, X86_CC_NS, 0, 1); + + /* insert the instruction in the delay slot */ + mips_jit_fetch_and_emit (cpu, b, 2); + + /* set the new pc in cpu structure */ + mips_set_jump (cpu, b, new_pc, 1); + + x86_patch (test1, b->jit_ptr); + + /* if the branch is not taken, we have to execute the delay slot too */ + mips_jit_fetch_and_emit (cpu, b, 1); + return (0); +} + +/* BLTZALL (Branch On Less Than Zero And Link Likely) */ +static int mips_emit_bltzall (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + int rs = bits (insn, 21, 25); + int offset = bits (insn, 0, 15); + u_char *test1; + m_va_t new_pc; + + /* compute the new pc */ + new_pc = b->start_pc + (b->mips_trans_pos << 2); + new_pc += sign_extend (offset << 2, 18); + + /* set the return address (instruction after the delay slot) */ + mips_set_ra (b, b->start_pc + ((b->mips_trans_pos + 1) << 2)); + + /* + * test the sign bit of gpr[rs], if set, take the branch. + */ + x86_mov_reg_membase (b->jit_ptr, X86_EAX, X86_EDI, REG_OFFSET (rs), 4); + x86_test_reg_reg (b->jit_ptr, X86_EAX, X86_EAX); + test1 = b->jit_ptr; + x86_branch32 (b->jit_ptr, X86_CC_NS, 0, 1); + + /* insert the instruction in the delay slot */ + mips_jit_fetch_and_emit (cpu, b, 1); + + /* set the new pc in cpu structure */ + mips_set_jump (cpu, b, new_pc, 1); + + x86_patch (test1, b->jit_ptr); + return (0); +} + +/* BLTZL (Branch On Less Than Zero Likely) */ +static int mips_emit_bltzl (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + int rs = bits (insn, 21, 25); + int offset = bits (insn, 0, 15); + u_char *test1; + m_va_t new_pc; + + /* compute the new pc */ + new_pc = b->start_pc + (b->mips_trans_pos << 2); + new_pc += sign_extend (offset << 2, 18); + + /* + * test the sign bit of gpr[rs], if set, take the branch. + */ + x86_mov_reg_membase (b->jit_ptr, X86_EAX, X86_EDI, REG_OFFSET (rs), 4); + x86_test_reg_reg (b->jit_ptr, X86_EAX, X86_EAX); + test1 = b->jit_ptr; + x86_branch32 (b->jit_ptr, X86_CC_NS, 0, 1); + + /* insert the instruction in the delay slot */ + mips_jit_fetch_and_emit (cpu, b, 1); + + /* set the new pc in cpu structure */ + mips_set_jump (cpu, b, new_pc, 1); + + x86_patch (test1, b->jit_ptr); + return (0); +} + +/* BNE (Branch On Not Equal) */ +static int mips_emit_bne (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + int rs = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + int offset = bits (insn, 0, 15); + u_char *test2; + m_va_t new_pc; + + /* compute the new pc */ + new_pc = b->start_pc + (b->mips_trans_pos << 2); + new_pc += sign_extend (offset << 2, 18); + + /* + * compare gpr[rs] and gpr[rt]. + * compare the low 32 bits first (higher probability). + */ + x86_mov_reg_membase (b->jit_ptr, X86_EAX, X86_EDI, REG_OFFSET (rs), 4); + x86_alu_reg_membase (b->jit_ptr, X86_CMP, X86_EAX, X86_EDI, + REG_OFFSET (rt)); + test2 = b->jit_ptr; + x86_branch32 (b->jit_ptr, X86_CC_E, 0, 1); + + /* insert the instruction in the delay slot */ + mips_jit_fetch_and_emit (cpu, b, 2); + + /* set the new pc in cpu structure */ + mips_set_jump (cpu, b, new_pc, 1); + + x86_patch (test2, b->jit_ptr); + + /* if the branch is not taken, we have to execute the delay slot too */ + mips_jit_fetch_and_emit (cpu, b, 1); + return (0); +} + +/* BNEL (Branch On Not Equal Likely) */ +static int mips_emit_bnel (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + int rs = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + int offset = bits (insn, 0, 15); + u_char *test2; + m_va_t new_pc; + + /* compute the new pc */ + new_pc = b->start_pc + (b->mips_trans_pos << 2); + new_pc += sign_extend (offset << 2, 18); + + /* + * compare gpr[rs] and gpr[rt]. + * compare the low 32 bits first (higher probability). + */ + x86_mov_reg_membase (b->jit_ptr, X86_EAX, X86_EDI, REG_OFFSET (rs), 4); + x86_alu_reg_membase (b->jit_ptr, X86_CMP, X86_EAX, X86_EDI, + REG_OFFSET (rt)); + test2 = b->jit_ptr; + x86_branch32 (b->jit_ptr, X86_CC_E, 0, 1); + + /* insert the instruction in the delay slot */ + mips_jit_fetch_and_emit (cpu, b, 1); + + /* set the new pc in cpu structure */ + mips_set_jump (cpu, b, new_pc, 1); + + x86_patch (test2, b->jit_ptr); + + return (0); +} + +/* BREAK */ +static int mips_emit_break (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + u_int code = bits (insn, 6, 25); + + //x86_alu_reg_imm(b->jit_ptr,X86_SUB,X86_ESP,12); + x86_mov_reg_imm (b->jit_ptr, X86_EDX, code); + x86_mov_reg_reg (b->jit_ptr, X86_EAX, X86_EDI, 4); + mips_emit_basic_c_call (b, mips_exec_break); + x86_alu_reg_imm (b->jit_ptr, X86_ADD, X86_ESP, 12); + + mips_jit_tcb_push_epilog (b); + return (0); +} + +/* CACHE */ +static int mips_emit_cache (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + int base = bits (insn, 21, 25); + int op = bits (insn, 16, 20); + int offset = bits (insn, 0, 15); + + mips_emit_memop (b, MIPS_MEMOP_CACHE, base, offset, op, FALSE); + return (0); +} + +static int mips_emit_cfc0 (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + mips_emit_unknown (cpu, b, insn); + return (0); +} + +static int fastcall clz_emu (cpu_mips_t * cpu, mips_insn_t insn) +{ + int rs = bits (insn, 21, 25); + int rd = bits (insn, 11, 15); + int i; + m_uint32_t val; + val = 32; + for (i = 31; i >= 0; i--) { + if (cpu->gpr[rs] & (1 << i)) { + val = 31 - i; + break; + } + } + cpu->gpr[rd] = val; + return (0); + +} + +static int mips_emit_clz (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + //x86_alu_reg_imm(b->jit_ptr,X86_SUB,X86_ESP,12); + x86_mov_reg_imm (b->jit_ptr, X86_EDX, insn); + x86_mov_reg_reg (b->jit_ptr, X86_EAX, X86_EDI, 4); + mips_emit_basic_c_call (b, clz_emu); + return (0); +} + +static int mips_emit_cop0 (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + uint16_t special_func = bits (insn, 21, 25); + return mips_cop0_jit[special_func].emit_func (cpu, b, insn); +} + +static int mips_emit_cop1 (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ +#if SOFT_FPU + /* Save PC for exception handling */ + mips_set_pc (b, b->start_pc + ((b->mips_trans_pos - 1) << 2)); + x86_mov_reg_reg (b->jit_ptr, X86_EAX, X86_EDI, 4); + mips_emit_basic_c_call (b, mips_exec_soft_fpu); + mips_jit_tcb_push_epilog (b); + return (0); +#else + mips_emit_unknown (cpu, b, insn); + return (0); +#endif +} + +static int mips_emit_cop1x (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ +#if SOFT_FPU + /* Save PC for exception handling */ + mips_set_pc (b, b->start_pc + ((b->mips_trans_pos - 1) << 2)); + x86_mov_reg_reg (b->jit_ptr, X86_EAX, X86_EDI, 4); + mips_emit_basic_c_call (b, mips_exec_soft_fpu); + mips_jit_tcb_push_epilog (b); + return (0); +#else + mips_emit_unknown (cpu, b, insn); + return (0); +#endif + +} + +static int mips_emit_cop2 (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + mips_emit_unknown (cpu, b, insn); + return (0); +} + +static int mips_emit_dadd (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + mips_emit_unknown (cpu, b, insn); + return (0); +} + +static int mips_emit_daddi (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + mips_emit_unknown (cpu, b, insn); + return (0); +} + +static int mips_emit_daddiu (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + mips_emit_unknown (cpu, b, insn); + return (0); +} + +static int mips_emit_daddu (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + mips_emit_unknown (cpu, b, insn); + return (0); +} + +static int mips_emit_ddiv (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + mips_emit_unknown (cpu, b, insn); + return (0); +} + +static int mips_emit_ddivu (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + mips_emit_unknown (cpu, b, insn); + return (0); +} + +static int mips_emit_div (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + int rs = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + + /* eax = gpr[rs] */ + x86_mov_reg_membase (b->jit_ptr, X86_EAX, X86_EDI, REG_OFFSET (rs), 4); + x86_cdq (b->jit_ptr); + /* ebx = gpr[rt] */ + x86_mov_reg_membase (b->jit_ptr, X86_EBX, X86_EDI, REG_OFFSET (rt), 4); + + /* eax = quotient (LO), edx = remainder (HI) */ + x86_div_reg (b->jit_ptr, X86_EBX, 1); + + /* store LO */ + x86_mov_membase_reg (b->jit_ptr, X86_EDI, OFFSET (cpu_mips_t, lo), + X86_EAX, 4); + /* store HI */ + x86_mov_membase_reg (b->jit_ptr, X86_EDI, OFFSET (cpu_mips_t, hi), + X86_EDX, 4); + + return (0); +} + +static int mips_emit_divu (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + int rs = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + + /* eax = gpr[rs] */ + x86_clear_reg (b->jit_ptr, X86_EDX); + x86_mov_reg_membase (b->jit_ptr, X86_EAX, X86_EDI, REG_OFFSET (rs), 4); + /* ebx = gpr[rt] */ + x86_mov_reg_membase (b->jit_ptr, X86_EBX, X86_EDI, REG_OFFSET (rt), 4); + + /* eax = quotient (LO), edx = remainder (HI) */ + x86_div_reg (b->jit_ptr, X86_EBX, 0); + + /* store LO */ + x86_mov_membase_reg (b->jit_ptr, X86_EDI, OFFSET (cpu_mips_t, lo), + X86_EAX, 4); + /* store HI */ + x86_mov_membase_reg (b->jit_ptr, X86_EDI, OFFSET (cpu_mips_t, hi), + X86_EDX, 4); + return (0); +} + +static int mips_emit_dmfc0 (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + mips_emit_unknown (cpu, b, insn); + return (0); +} + +static int mips_emit_dmtc0 (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + mips_emit_unknown (cpu, b, insn); + return (0); +} + +static int mips_emit_dmult (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + mips_emit_unknown (cpu, b, insn); + return (0); +} + +static int mips_emit_dmultu (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + mips_emit_unknown (cpu, b, insn); + return (0); +} + +static int mips_emit_dsll (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + mips_emit_unknown (cpu, b, insn); + return (0); +} + +static int mips_emit_dsllv (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + mips_emit_unknown (cpu, b, insn); + return (0); +} + +static int mips_emit_dsrlv (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + mips_emit_unknown (cpu, b, insn); + return (0); +} + +static int mips_emit_dsrav (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + mips_emit_unknown (cpu, b, insn); + return (0); +} + +static int mips_emit_dsub (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + mips_emit_unknown (cpu, b, insn); + return (0); +} + +static int mips_emit_dsubu (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + mips_emit_unknown (cpu, b, insn); + return (0); +} + +static int mips_emit_dsrl (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + mips_emit_unknown (cpu, b, insn); + return (0); +} + +static int mips_emit_dsra (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + mips_emit_unknown (cpu, b, insn); + return (0); +} + +static int mips_emit_dsll32 (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + mips_emit_unknown (cpu, b, insn); + return (0); +} + +static int mips_emit_dsrl32 (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + mips_emit_unknown (cpu, b, insn); + return (0); +} + +static int mips_emit_dsra32 (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + mips_emit_unknown (cpu, b, insn); + return (0); +} + +static int mips_emit_eret (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + mips_set_pc (b, b->start_pc + ((b->mips_trans_pos - 1) << 2)); + + x86_mov_reg_reg (b->jit_ptr, X86_EAX, X86_EDI, 4); + mips_emit_basic_c_call (b, mips_exec_eret); + mips_jit_tcb_push_epilog (b); + return (0); +} + +/* J (Jump) */ +static int mips_emit_j (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + u_int instr_index = bits (insn, 0, 25); + m_va_t new_pc; + + /* compute the new pc */ + new_pc = b->start_pc + (b->mips_trans_pos << 2); + new_pc &= ~((1 << 28) - 1); + new_pc |= instr_index << 2; + + /* insert the instruction in the delay slot */ + mips_jit_fetch_and_emit (cpu, b, 1); + + /* set the new pc in cpu structure */ + mips_set_jump (cpu, b, new_pc, 1); + return (0); +} + +static int mips_emit_jal (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + u_int instr_index = bits (insn, 0, 25); + m_va_t new_pc, ret_pc; + + /* compute the new pc */ + new_pc = b->start_pc + (b->mips_trans_pos << 2); + new_pc &= ~((1 << 28) - 1); + new_pc |= instr_index << 2; + + /* set the return address (instruction after the delay slot) */ + ret_pc = b->start_pc + ((b->mips_trans_pos + 1) << 2); + mips_set_ra (b, ret_pc); + + /* insert the instruction in the delay slot */ + mips_jit_fetch_and_emit (cpu, b, 1); + + /* set the new pc in cpu structure */ + mips_set_jump (cpu, b, new_pc, 0); + return (0); + +} + +static int mips_emit_jalr (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + int rs = bits (insn, 21, 25); + int rd = bits (insn, 11, 15); + m_va_t ret_pc; + + /* set the return pc (instruction after the delay slot) in GPR[rd] */ + ret_pc = b->start_pc + ((b->mips_trans_pos + 1) << 2); + x86_mov_membase_imm (b->jit_ptr, X86_EDI, REG_OFFSET (rd), ret_pc, 4); + + /* get the new pc */ + x86_mov_reg_membase (b->jit_ptr, X86_ECX, X86_EDI, REG_OFFSET (rs), 4); + x86_mov_membase_reg (b->jit_ptr, X86_EDI, OFFSET (cpu_mips_t, ret_pc), + X86_ECX, 4); + + /* insert the instruction in the delay slot */ + mips_jit_fetch_and_emit (cpu, b, 1); + + /* set the new pc */ + x86_mov_reg_membase (b->jit_ptr, X86_ECX, + X86_EDI, OFFSET (cpu_mips_t, ret_pc), 4); + x86_mov_membase_reg (b->jit_ptr, X86_EDI, OFFSET (cpu_mips_t, pc), + X86_ECX, 4); + + /* returns to the caller which will determine the next path */ + mips_jit_tcb_push_epilog (b); + return (0); + +} + +static int mips_emit_jr (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + int rs = bits (insn, 21, 25); + + /* get the new pc */ + x86_mov_reg_membase (b->jit_ptr, X86_ECX, X86_EDI, REG_OFFSET (rs), 4); + x86_mov_membase_reg (b->jit_ptr, X86_EDI, OFFSET (cpu_mips_t, ret_pc), + X86_ECX, 4); + + /* insert the instruction in the delay slot */ + mips_jit_fetch_and_emit (cpu, b, 1); + + /* set the new pc */ + x86_mov_reg_membase (b->jit_ptr, X86_ECX, + X86_EDI, OFFSET (cpu_mips_t, ret_pc), 4); + x86_mov_membase_reg (b->jit_ptr, X86_EDI, OFFSET (cpu_mips_t, pc), + X86_ECX, 4); + /* returns to the caller which will determine the next path */ + mips_jit_tcb_push_epilog (b); + return (0); + +} + +static int mips_emit_lb (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + int base = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + int offset = bits (insn, 0, 15); + + mips_emit_memop (b, MIPS_MEMOP_LB, base, offset, rt, TRUE); + return (0); +} + +static int mips_emit_lbu (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + int base = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + int offset = bits (insn, 0, 15); + + mips_emit_memop (b, MIPS_MEMOP_LBU, base, offset, rt, TRUE); + return (0); +} + +static int mips_emit_ld (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + mips_emit_unknown (cpu, b, insn); + return (0); +} + +static int mips_emit_ldc1 (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + mips_emit_unknown (cpu, b, insn); + return (0); +} + +static int mips_emit_ldc2 (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + mips_emit_unknown (cpu, b, insn); + return (0); +} + +static int mips_emit_ldl (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + mips_emit_unknown (cpu, b, insn); + return (0); +} + +static int mips_emit_ldr (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + mips_emit_unknown (cpu, b, insn); + return (0); +} + +static int mips_emit_lh (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + int base = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + int offset = bits (insn, 0, 15); + + mips_emit_memop (b, MIPS_MEMOP_LH, base, offset, rt, TRUE); + return (0); +} + +static int mips_emit_lhu (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + int base = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + int offset = bits (insn, 0, 15); + + mips_emit_memop (b, MIPS_MEMOP_LHU, base, offset, rt, TRUE); + return (0); +} + +static int mips_emit_ll (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + int base = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + int offset = bits (insn, 0, 15); + + mips_emit_memop (b, MIPS_MEMOP_LL, base, offset, rt, TRUE); + return (0); +} + +static int mips_emit_lld (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + mips_emit_unknown (cpu, b, insn); + return (0); +} + +static int mips_emit_lui (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + int rt = bits (insn, 16, 20); + int imm = bits (insn, 0, 15); + m_reg_t val = sign_extend (imm, 16) << 16; + + x86_mov_membase_imm (b->jit_ptr, X86_EDI, REG_OFFSET (rt), val, 4); + + return (0); +} + +static int mips_emit_lw (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + int base = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + int offset = bits (insn, 0, 15); + + mips_emit_memop (b, MIPS_MEMOP_LW, base, offset, rt, TRUE); + return (0); +} + +static int mips_emit_lwc1 (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ +#if SOFT_FPU + /* Save PC for exception handling */ + mips_set_pc (b, b->start_pc + ((b->mips_trans_pos - 1) << 2)); + x86_mov_reg_reg (b->jit_ptr, X86_EAX, X86_EDI, 4); + mips_emit_basic_c_call (b, mips_exec_soft_fpu); + mips_jit_tcb_push_epilog (b); + return (0); +#else + mips_emit_unknown (cpu, b, insn); + return (0); +#endif + +} + +static int mips_emit_lwc2 (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + mips_emit_unknown (cpu, b, insn); + return (0); +} + +static int mips_emit_lwl (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + int base = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + int offset = bits (insn, 0, 15); + + mips_emit_memop (b, MIPS_MEMOP_LWL, base, offset, rt, TRUE); + return (0); +} + +static int mips_emit_lwr (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + int base = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + int offset = bits (insn, 0, 15); + + mips_emit_memop (b, MIPS_MEMOP_LWR, base, offset, rt, TRUE); + return (0); +} + +static int mips_emit_lwu (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + int base = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + int offset = bits (insn, 0, 15); + + mips_emit_memop (b, MIPS_MEMOP_LWU, base, offset, rt, TRUE); + return (0); +} + +static int mips_emit_mad (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + int index = bits (insn, 0, 5); + return mips_mad_jit[index].emit_func (cpu, b, insn); +} + +static int fastcall madd_emu (cpu_mips_t * cpu, mips_insn_t insn) +{ + int rs = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + m_int64_t val, temp; + + val = (m_int32_t) (m_int32_t) cpu->gpr[rs]; + val *= (m_int32_t) (m_int32_t) cpu->gpr[rt]; + + temp = cpu->hi; + temp = temp << 32; + temp += cpu->lo; + val += temp; + + cpu->lo = sign_extend (val, 32); + cpu->hi = sign_extend (val >> 32, 32); + return (0); + +} + +static int mips_emit_madd (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + //x86_alu_reg_imm(b->jit_ptr,X86_SUB,X86_ESP,12); + x86_mov_reg_imm (b->jit_ptr, X86_EDX, insn); + x86_mov_reg_reg (b->jit_ptr, X86_EAX, X86_EDI, 4); + mips_emit_basic_c_call (b, madd_emu); + return (0); +} + +static int fastcall maddu_emu (cpu_mips_t * cpu, mips_insn_t insn) +{ + int rs = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + m_int64_t val, temp; + + val = (m_uint32_t) (m_uint32_t) cpu->gpr[rs]; + val *= (m_uint32_t) (m_uint32_t) cpu->gpr[rt]; + + temp = cpu->hi; + temp = temp << 32; + temp += cpu->lo; + val += temp; + + cpu->lo = sign_extend (val, 32); + cpu->hi = sign_extend (val >> 32, 32); + return (0); + +} + +static int mips_emit_maddu (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + //x86_alu_reg_imm(b->jit_ptr,X86_SUB,X86_ESP,12); + x86_mov_reg_imm (b->jit_ptr, X86_EDX, insn); + x86_mov_reg_reg (b->jit_ptr, X86_EAX, X86_EDI, 4); + mips_emit_basic_c_call (b, maddu_emu); + return (0); +} + +static int mips_emit_mfc0 (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + x86_mov_reg_imm (b->jit_ptr, X86_EDX, insn); + x86_mov_reg_reg (b->jit_ptr, X86_EAX, X86_EDI, 4); + mips_emit_basic_c_call (b, mips_cp0_exec_mfc0_fastcall); + return (0); + +} + +static int mips_emit_mfhi (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + int rd = bits (insn, 11, 15); + x86_mov_reg_membase (b->jit_ptr, X86_EAX, X86_EDI, OFFSET (cpu_mips_t, + hi), 4); + x86_mov_membase_reg (b->jit_ptr, X86_EDI, REG_OFFSET (rd), X86_EAX, 4); + + return (0); +} + +static int mips_emit_mflo (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + int rd = bits (insn, 11, 15); + x86_mov_reg_membase (b->jit_ptr, X86_EAX, X86_EDI, OFFSET (cpu_mips_t, + lo), 4); + x86_mov_membase_reg (b->jit_ptr, X86_EDI, REG_OFFSET (rd), X86_EAX, 4); + return (0); +} + +static int mips_emit_movc (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + mips_emit_unknown (cpu, b, insn); + return (0); +} + +static int mips_emit_movz (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + int rs = bits (insn, 21, 25); + int rd = bits (insn, 11, 15); + int rt = bits (insn, 16, 20); + u_char *test1; + + x86_mov_reg_membase (b->jit_ptr, X86_EAX, X86_EDI, REG_OFFSET (rt), 4); + x86_test_reg_reg (b->jit_ptr, X86_EAX, X86_EAX); + /*goto end if !=0 */ + test1 = b->jit_ptr; + x86_branch32 (b->jit_ptr, X86_CC_NZ, 0, 1); + x86_mov_reg_membase (b->jit_ptr, X86_EAX, X86_EDI, REG_OFFSET (rs), 4); + x86_mov_membase_reg (b->jit_ptr, X86_EDI, REG_OFFSET (rd), X86_EAX, 4); + + x86_patch (test1, b->jit_ptr); + return (0); + +} + +static int mips_emit_movn (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + int rs = bits (insn, 21, 25); + int rd = bits (insn, 11, 15); + int rt = bits (insn, 16, 20); + u_char *test1; + + x86_mov_reg_membase (b->jit_ptr, X86_EAX, X86_EDI, REG_OFFSET (rt), 4); + x86_test_reg_reg (b->jit_ptr, X86_EAX, X86_EAX); + /*goto end if ==0 */ + test1 = b->jit_ptr; + x86_branch32 (b->jit_ptr, X86_CC_Z, 0, 1); + x86_mov_reg_membase (b->jit_ptr, X86_EAX, X86_EDI, REG_OFFSET (rs), 4); + x86_mov_membase_reg (b->jit_ptr, X86_EDI, REG_OFFSET (rd), X86_EAX, 4); + + x86_patch (test1, b->jit_ptr); + return (0); + +} + +static int fastcall msub_emu (cpu_mips_t * cpu, mips_insn_t insn) +{ + int rs = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + m_int64_t val, temp; + + val = (m_int32_t) (m_int32_t) cpu->gpr[rs]; + val *= (m_int32_t) (m_int32_t) cpu->gpr[rt]; + + temp = cpu->hi; + temp = temp << 32; + temp += cpu->lo; + + temp -= val; + //val += temp; + + cpu->lo = sign_extend (temp, 32); + cpu->hi = sign_extend (temp >> 32, 32); + return (0); + +} + +static int mips_emit_msub (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + //x86_alu_reg_imm(b->jit_ptr,X86_SUB,X86_ESP,12); + x86_mov_reg_imm (b->jit_ptr, X86_EDX, insn); + x86_mov_reg_reg (b->jit_ptr, X86_EAX, X86_EDI, 4); + mips_emit_basic_c_call (b, msub_emu); + return (0); +} + +static int fastcall msubu_emu (cpu_mips_t * cpu, mips_insn_t insn) +{ + int rs = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + m_int64_t val, temp; + + val = (m_uint32_t) (m_uint32_t) cpu->gpr[rs]; + val *= (m_uint32_t) (m_uint32_t) cpu->gpr[rt]; + + temp = cpu->hi; + temp = temp << 32; + temp += cpu->lo; + + temp -= val; + + cpu->lo = sign_extend (temp, 32); + cpu->hi = sign_extend (temp >> 32, 32); + return (0); + +} + +static int mips_emit_msubu (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + //x86_alu_reg_imm(b->jit_ptr,X86_SUB,X86_ESP,12); + x86_mov_reg_imm (b->jit_ptr, X86_EDX, insn); + x86_mov_reg_reg (b->jit_ptr, X86_EAX, X86_EDI, 4); + mips_emit_basic_c_call (b, msubu_emu); + return (0); +} + +static int mips_emit_mtc0 (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + x86_mov_reg_imm (b->jit_ptr, X86_EDX, insn); + x86_mov_reg_reg (b->jit_ptr, X86_EAX, X86_EDI, 4); + mips_emit_basic_c_call (b, mips_cp0_exec_mtc0_fastcall); + return (0); + +} + +static fastcall int mthi_emu (cpu_mips_t * cpu, mips_insn_t insn) +{ + int rs = bits (insn, 21, 25); + + cpu->hi = cpu->gpr[rs]; + return (0); +} + +static fastcall int mtlo_emu (cpu_mips_t * cpu, mips_insn_t insn) +{ + int rs = bits (insn, 21, 25); + + cpu->lo = cpu->gpr[rs]; + return (0); + +} + +static int mips_emit_mthi (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + //x86_alu_reg_imm(b->jit_ptr,X86_SUB,X86_ESP,12); + x86_mov_reg_imm (b->jit_ptr, X86_EDX, insn); + x86_mov_reg_reg (b->jit_ptr, X86_EAX, X86_EDI, 4); + mips_emit_basic_c_call (b, mthi_emu); + return (0); +} + +static int mips_emit_mtlo (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + //x86_alu_reg_imm(b->jit_ptr,X86_SUB,X86_ESP,12); + x86_mov_reg_imm (b->jit_ptr, X86_EDX, insn); + x86_mov_reg_reg (b->jit_ptr, X86_EAX, X86_EDI, 4); + mips_emit_basic_c_call (b, mtlo_emu); + return (0); +} + +/* MUL */ +static int mips_emit_mul (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + int rs = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + int rd = bits (insn, 11, 15); + + x86_mov_reg_membase (b->jit_ptr, X86_EAX, X86_EDI, REG_OFFSET (rs), 4); + x86_mov_reg_membase (b->jit_ptr, X86_EBX, X86_EDI, REG_OFFSET (rt), 4); + + x86_mul_reg (b->jit_ptr, X86_EBX, 1); + + /* store result in gpr[rd] */ + x86_mov_membase_reg (b->jit_ptr, X86_EDI, REG_OFFSET (rd), X86_EAX, 4); + return (0); +} + +static int mips_emit_mult (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + int rs = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + + x86_mov_reg_membase (b->jit_ptr, X86_EAX, X86_EDI, REG_OFFSET (rs), 4); + x86_mov_reg_membase (b->jit_ptr, X86_EBX, X86_EDI, REG_OFFSET (rt), 4); + + x86_mul_reg (b->jit_ptr, X86_EBX, 1); + + /* store LO */ + x86_mov_membase_reg (b->jit_ptr, X86_EDI, OFFSET (cpu_mips_t, lo), + X86_EAX, 4); + /* store HI */ + x86_mov_membase_reg (b->jit_ptr, X86_EDI, OFFSET (cpu_mips_t, hi), + X86_EDX, 4); + return (0); +} + +static int mips_emit_multu (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + int rs = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + + x86_mov_reg_membase (b->jit_ptr, X86_EAX, X86_EDI, REG_OFFSET (rs), 4); + x86_mov_reg_membase (b->jit_ptr, X86_EBX, X86_EDI, REG_OFFSET (rt), 4); + + x86_mul_reg (b->jit_ptr, X86_EBX, 0); + + /* store LO */ + x86_mov_membase_reg (b->jit_ptr, X86_EDI, OFFSET (cpu_mips_t, lo), + X86_EAX, 4); + /* store HI */ + x86_mov_membase_reg (b->jit_ptr, X86_EDI, OFFSET (cpu_mips_t, hi), + X86_EDX, 4); + return (0); +} + +static int mips_emit_nor (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + int rs = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + int rd = bits (insn, 11, 15); + + x86_mov_reg_membase (b->jit_ptr, X86_EAX, X86_EDI, REG_OFFSET (rs), 4); + x86_alu_reg_membase (b->jit_ptr, X86_OR, X86_EAX, X86_EDI, + REG_OFFSET (rt)); + x86_not_reg (b->jit_ptr, X86_EAX); + x86_mov_membase_reg (b->jit_ptr, X86_EDI, REG_OFFSET (rd), X86_EAX, 4); + return (0); + +} + +static int mips_emit_or (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + int rs = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + int rd = bits (insn, 11, 15); + + x86_mov_reg_membase (b->jit_ptr, X86_EAX, X86_EDI, REG_OFFSET (rs), 4); + x86_alu_reg_membase (b->jit_ptr, X86_OR, X86_EAX, X86_EDI, + REG_OFFSET (rt)); + x86_mov_membase_reg (b->jit_ptr, X86_EDI, REG_OFFSET (rd), X86_EAX, 4); + return (0); + +} + +static int mips_emit_ori (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + int rs = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + int imm = bits (insn, 0, 15); + + x86_mov_reg_imm (b->jit_ptr, X86_EAX, imm & 0xffff); + x86_alu_reg_membase (b->jit_ptr, X86_OR, X86_EAX, X86_EDI, + REG_OFFSET (rs)); + x86_mov_membase_reg (b->jit_ptr, X86_EDI, REG_OFFSET (rt), X86_EAX, 4); + return (0); + +} + +static int mips_emit_pref (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + return (0); +} + +static int mips_emit_sb (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + int base = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + int offset = bits (insn, 0, 15); + + mips_emit_memop (b, MIPS_MEMOP_SB, base, offset, rt, TRUE); + return (0); +} + +static int mips_emit_sc (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + int base = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + int offset = bits (insn, 0, 15); + + mips_emit_memop (b, MIPS_MEMOP_SC, base, offset, rt, TRUE); + return (0); +} + +static int mips_emit_scd (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + mips_emit_unknown (cpu, b, insn); + return (0); +} + +static int mips_emit_sd (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + mips_emit_unknown (cpu, b, insn); + return (0); +} + +static int mips_emit_sdc1 (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ +#if SOFT_FPU + /* Save PC for exception handling */ + mips_set_pc (b, b->start_pc + ((b->mips_trans_pos - 1) << 2)); + x86_mov_reg_reg (b->jit_ptr, X86_EAX, X86_EDI, 4); + mips_emit_basic_c_call (b, mips_exec_soft_fpu); + mips_jit_tcb_push_epilog (b); + return (0); +#else + mips_emit_unknown (cpu, b, insn); + return (0); +#endif + +} + +static int mips_emit_sdc2 (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + mips_emit_unknown (cpu, b, insn); + return (0); +} + +static int mips_emit_sdl (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + mips_emit_unknown (cpu, b, insn); + return (0); +} + +static int mips_emit_sdr (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + mips_emit_unknown (cpu, b, insn); + return (0); +} + +static int mips_emit_sh (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + int base = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + int offset = bits (insn, 0, 15); + + mips_emit_memop (b, MIPS_MEMOP_SH, base, offset, rt, TRUE); + return (0); +} + +static int mips_emit_sll (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + int rt = bits (insn, 16, 20); + int rd = bits (insn, 11, 15); + int sa = bits (insn, 6, 10); + + x86_mov_reg_membase (b->jit_ptr, X86_EAX, X86_EDI, REG_OFFSET (rt), 4); + x86_shift_reg_imm (b->jit_ptr, X86_SHL, X86_EAX, sa); + + x86_mov_membase_reg (b->jit_ptr, X86_EDI, REG_OFFSET (rd), X86_EAX, 4); + return (0); +} + +static int mips_emit_sllv (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + int rs = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + int rd = bits (insn, 11, 15); + + x86_mov_reg_membase (b->jit_ptr, X86_ECX, X86_EDI, REG_OFFSET (rs), 4); + x86_alu_reg_imm (b->jit_ptr, X86_AND, X86_ECX, 0x1f); + + x86_mov_reg_membase (b->jit_ptr, X86_EAX, X86_EDI, REG_OFFSET (rt), 4); + x86_shift_reg (b->jit_ptr, X86_SHL, X86_EAX); + + x86_mov_membase_reg (b->jit_ptr, X86_EDI, REG_OFFSET (rd), X86_EAX, 4); + return (0); + +} + +static int mips_emit_slt (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + int rs = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + int rd = bits (insn, 11, 15); + u_char *test1; + + /* eax = gpr[rt] */ + x86_mov_reg_membase (b->jit_ptr, X86_EAX, X86_EDI, REG_OFFSET (rt), 4); + /* ecx = gpr[rs] */ + x86_mov_reg_membase (b->jit_ptr, X86_ECX, X86_EDI, REG_OFFSET (rs), 4); + + /* we set rd to 1 when gpr[rs] < gpr[rt] */ + x86_clear_reg (b->jit_ptr, X86_ESI); + x86_mov_membase_reg (b->jit_ptr, X86_EDI, REG_OFFSET (rd), X86_ESI, 4); + + x86_alu_reg_reg (b->jit_ptr, X86_CMP, X86_ECX, X86_EAX); + /* rs >= rt => end */ + test1 = b->jit_ptr; + x86_branch8 (b->jit_ptr, X86_CC_GE, 0, 1); + x86_inc_membase (b->jit_ptr, X86_EDI, REG_OFFSET (rd)); + /* end */ + x86_patch (test1, b->jit_ptr); + return (0); + +} + +static int mips_emit_slti (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + int rs = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + int imm = bits (insn, 0, 15); + m_ireg_t val = sign_extend (imm, 16); + u_char *test1; + + /* eax =val */ + x86_mov_reg_imm (b->jit_ptr, X86_EAX, val); + /* ecx = gpr[rs] */ + x86_mov_reg_membase (b->jit_ptr, X86_ECX, X86_EDI, REG_OFFSET (rs), 4); + + /* we set rt to 1 when gpr[rs] < val */ + x86_clear_reg (b->jit_ptr, X86_ESI); + x86_mov_membase_reg (b->jit_ptr, X86_EDI, REG_OFFSET (rt), X86_ESI, 4); + + x86_alu_reg_reg (b->jit_ptr, X86_CMP, X86_ECX, X86_EAX); + /* rs >= val => end */ + test1 = b->jit_ptr; + x86_branch8 (b->jit_ptr, X86_CC_GE, 0, 1); + x86_inc_membase (b->jit_ptr, X86_EDI, REG_OFFSET (rt)); + /* end */ + x86_patch (test1, b->jit_ptr); + return (0); + +} + +static int mips_emit_sltiu (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + int rs = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + int imm = bits (insn, 0, 15); + m_reg_t val = sign_extend (imm, 16); + u_char *test1; + + /* eax =val */ + x86_mov_reg_imm (b->jit_ptr, X86_EAX, val); + /* ecx = gpr[rs] */ + x86_mov_reg_membase (b->jit_ptr, X86_ECX, X86_EDI, REG_OFFSET (rs), 4); + + /* we set rt to 1 when gpr[rs] < val */ + x86_clear_reg (b->jit_ptr, X86_ESI); + x86_mov_membase_reg (b->jit_ptr, X86_EDI, REG_OFFSET (rt), X86_ESI, 4); + + x86_alu_reg_reg (b->jit_ptr, X86_CMP, X86_ECX, X86_EAX); + /* rs() >= val => end */ + test1 = b->jit_ptr; + x86_branch8 (b->jit_ptr, X86_CC_GE, 0, 0); + x86_inc_membase (b->jit_ptr, X86_EDI, REG_OFFSET (rt)); + /* end */ + x86_patch (test1, b->jit_ptr); + return (0); + +} + +static int mips_emit_sltu (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + int rs = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + int rd = bits (insn, 11, 15); + u_char *test1; + + /* eax = gpr[rt] */ + x86_mov_reg_membase (b->jit_ptr, X86_EAX, X86_EDI, REG_OFFSET (rt), 4); + /* ecx = gpr[rs] */ + x86_mov_reg_membase (b->jit_ptr, X86_ECX, X86_EDI, REG_OFFSET (rs), 4); + + /* we set rd to 1 when gpr[rs] < gpr[rt] */ + x86_clear_reg (b->jit_ptr, X86_ESI); + x86_mov_membase_reg (b->jit_ptr, X86_EDI, REG_OFFSET (rd), X86_ESI, 4); + + x86_alu_reg_reg (b->jit_ptr, X86_CMP, X86_ECX, X86_EAX); + /* rs() >= rt(high) => end */ + test1 = b->jit_ptr; + x86_branch8 (b->jit_ptr, X86_CC_GE, 0, 0); + x86_inc_membase (b->jit_ptr, X86_EDI, REG_OFFSET (rd)); + /* end */ + x86_patch (test1, b->jit_ptr); + return (0); + +} + +static int mips_emit_spec (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + uint16_t special_func = bits (insn, 0, 5); + return mips_spec_jit[special_func].emit_func (cpu, b, insn); +} + +static int mips_emit_sra (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + int rt = bits (insn, 16, 20); + int rd = bits (insn, 11, 15); + int sa = bits (insn, 6, 10); + + x86_mov_reg_membase (b->jit_ptr, X86_EAX, X86_EDI, REG_OFFSET (rt), 4); + x86_shift_reg_imm (b->jit_ptr, X86_SAR, X86_EAX, sa); + + x86_mov_membase_reg (b->jit_ptr, X86_EDI, REG_OFFSET (rd), X86_EAX, 4); + return (0); + +} + +static int mips_emit_srav (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + int rs = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + int rd = bits (insn, 11, 15); + + x86_mov_reg_membase (b->jit_ptr, X86_ECX, X86_EDI, REG_OFFSET (rs), 4); + x86_alu_reg_imm (b->jit_ptr, X86_AND, X86_ECX, 0x1f); + + x86_mov_reg_membase (b->jit_ptr, X86_EAX, X86_EDI, REG_OFFSET (rt), 4); + x86_shift_reg (b->jit_ptr, X86_SAR, X86_EAX); + + x86_mov_membase_reg (b->jit_ptr, X86_EDI, REG_OFFSET (rd), X86_EAX, 4); + return (0); + +} + +static int mips_emit_srl (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + int rt = bits (insn, 16, 20); + int rd = bits (insn, 11, 15); + int sa = bits (insn, 6, 10); + + x86_mov_reg_membase (b->jit_ptr, X86_EAX, X86_EDI, REG_OFFSET (rt), 4); + x86_shift_reg_imm (b->jit_ptr, X86_SHR, X86_EAX, sa); + + x86_mov_membase_reg (b->jit_ptr, X86_EDI, REG_OFFSET (rd), X86_EAX, 4); + return (0); + +} + +static int mips_emit_srlv (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + int rs = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + int rd = bits (insn, 11, 15); + + x86_mov_reg_membase (b->jit_ptr, X86_ECX, X86_EDI, REG_OFFSET (rs), 4); + x86_alu_reg_imm (b->jit_ptr, X86_AND, X86_ECX, 0x1f); + + x86_mov_reg_membase (b->jit_ptr, X86_EAX, X86_EDI, REG_OFFSET (rt), 4); + x86_shift_reg (b->jit_ptr, X86_SHR, X86_EAX); + + x86_mov_membase_reg (b->jit_ptr, X86_EDI, REG_OFFSET (rd), X86_EAX, 4); + return (0); + +} + +static int mips_emit_sub (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + int rs = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + int rd = bits (insn, 11, 15); + + /* TODO: Exception handling */ + x86_mov_reg_membase (b->jit_ptr, X86_EAX, X86_EDI, REG_OFFSET (rs), 4); + x86_alu_reg_membase (b->jit_ptr, X86_SUB, X86_EAX, X86_EDI, + REG_OFFSET (rt)); + + x86_mov_membase_reg (b->jit_ptr, X86_EDI, REG_OFFSET (rd), X86_EAX, 4); + return (0); + +} + +static int mips_emit_subu (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + int rs = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + int rd = bits (insn, 11, 15); + + x86_mov_reg_membase (b->jit_ptr, X86_EAX, X86_EDI, REG_OFFSET (rs), 4); + x86_alu_reg_membase (b->jit_ptr, X86_SUB, X86_EAX, X86_EDI, + REG_OFFSET (rt)); + + x86_mov_membase_reg (b->jit_ptr, X86_EDI, REG_OFFSET (rd), X86_EAX, 4); + return (0); + +} + +static int mips_emit_sw (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + int base = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + int offset = bits (insn, 0, 15); + + mips_emit_memop (b, MIPS_MEMOP_SW, base, offset, rt, TRUE); + return (0); +} + +static int mips_emit_swc1 (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ +#if SOFT_FPU + /* Save PC for exception handling */ + mips_set_pc (b, b->start_pc + ((b->mips_trans_pos - 1) << 2)); + x86_mov_reg_reg (b->jit_ptr, X86_EAX, X86_EDI, 4); + mips_emit_basic_c_call (b, mips_exec_soft_fpu); + mips_jit_tcb_push_epilog (b); + return (0); +#else + mips_emit_unknown (cpu, b, insn); + return (0); +#endif + +} + +static int mips_emit_swc2 (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + mips_emit_unknown (cpu, b, insn); + return (0); +} + +static int mips_emit_swl (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + int base = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + int offset = bits (insn, 0, 15); + + mips_emit_memop (b, MIPS_MEMOP_SWL, base, offset, rt, TRUE); + return (0); +} + +static int mips_emit_swr (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + int base = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + int offset = bits (insn, 0, 15); + + mips_emit_memop (b, MIPS_MEMOP_SWR, base, offset, rt, TRUE); + return (0); +} + +static int mips_emit_sync (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + return (0); +} + +static int mips_emit_syscall (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + mips_set_pc (b, b->start_pc + ((b->mips_trans_pos - 1) << 2)); + + x86_mov_reg_reg (b->jit_ptr, X86_EAX, X86_EDI, 4); + mips_emit_basic_c_call (b, mips_exec_syscall); + + mips_jit_tcb_push_epilog (b); + return (0); + +} + +static int mips_emit_teq (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + int rs = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + u_char *test1; + + /* Compare low part */ + x86_mov_reg_membase (b->jit_ptr, X86_ECX, X86_EDI, REG_OFFSET (rs), 4); + x86_alu_reg_membase (b->jit_ptr, X86_CMP, X86_ECX, X86_EDI, + REG_OFFSET (rt)); + test1 = b->jit_ptr; + x86_branch32 (b->jit_ptr, X86_CC_NE, 0, 1); + + /* Generate trap exception */ + x86_alu_reg_imm (b->jit_ptr, X86_SUB, X86_ESP, 12); + x86_mov_reg_reg (b->jit_ptr, X86_EAX, X86_EDI, 4); + mips_emit_c_call (b, mips_trigger_trap_exception); + x86_alu_reg_imm (b->jit_ptr, X86_ADD, X86_ESP, 12); + + mips_jit_tcb_push_epilog (b); + + /* end */ + x86_patch (test1, b->jit_ptr); + return (0); + +} + +static int mips_emit_teqi (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + int rs = bits (insn, 21, 25); + int imm = bits (insn, 0, 15); + m_reg_t val = sign_extend (imm, 16); + u_char *test1; + + /* edx:eax = val */ + x86_mov_reg_imm (b->jit_ptr, X86_EAX, val); + + /* Compare low part */ + x86_mov_reg_membase (b->jit_ptr, X86_ECX, X86_EDI, REG_OFFSET (rs), 4); + x86_alu_reg_reg (b->jit_ptr, X86_CMP, X86_ECX, X86_EAX); + test1 = b->jit_ptr; + x86_branch32 (b->jit_ptr, X86_CC_NE, 0, 1); + + /* Generate trap exception */ + x86_alu_reg_imm (b->jit_ptr, X86_SUB, X86_ESP, 12); + x86_mov_reg_reg (b->jit_ptr, X86_EAX, X86_EDI, 4); + mips_emit_c_call (b, mips_trigger_trap_exception); + x86_alu_reg_imm (b->jit_ptr, X86_ADD, X86_ESP, 12); + + mips_jit_tcb_push_epilog (b); + + /* end */ + x86_patch (test1, b->jit_ptr); + return (0); + +} + +static int mips_emit_tlb (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + uint16_t func = bits (insn, 0, 5); + return mips_tlb_jit[func].emit_func (cpu, b, insn); +} + +static int mips_emit_tlbp (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + mips_set_pc (b, b->start_pc + ((b->mips_trans_pos - 1) << 2)); + x86_mov_reg_reg (b->jit_ptr, X86_EAX, X86_EDI, 4); + mips_emit_basic_c_call (b, mips_cp0_exec_tlbp); + return (0); + +} + +static int mips_emit_tlbr (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + mips_set_pc (b, b->start_pc + ((b->mips_trans_pos - 1) << 2)); + x86_mov_reg_reg (b->jit_ptr, X86_EAX, X86_EDI, 4); + mips_emit_basic_c_call (b, mips_cp0_exec_tlbr); + return (0); + +} + +static int mips_emit_tlbwi (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + mips_set_pc (b, b->start_pc + ((b->mips_trans_pos - 1) << 2)); + x86_mov_reg_reg (b->jit_ptr, X86_EAX, X86_EDI, 4); + mips_emit_basic_c_call (b, mips_cp0_exec_tlbwi); + return (0); + +} + +static int mips_emit_tlbwr (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + mips_set_pc (b, b->start_pc + ((b->mips_trans_pos - 1) << 2)); + x86_mov_reg_reg (b->jit_ptr, X86_EAX, X86_EDI, 4); + mips_emit_basic_c_call (b, mips_cp0_exec_tlbwr); + return (0); + +} + +static int mips_emit_tge (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + mips_emit_unknown (cpu, b, insn); + return (0); +} + +static int mips_emit_tgei (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + mips_emit_unknown (cpu, b, insn); + return (0); +} + +static int mips_emit_tgeu (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + mips_emit_unknown (cpu, b, insn); + return (0); +} + +static int mips_emit_tgeiu (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + mips_emit_unknown (cpu, b, insn); + return (0); +} + +static int mips_emit_tlt (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + mips_emit_unknown (cpu, b, insn); + return (0); +} + +static int mips_emit_tlti (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + mips_emit_unknown (cpu, b, insn); + return (0); +} + +static int mips_emit_tltiu (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + mips_emit_unknown (cpu, b, insn); + return (0); +} + +static int mips_emit_tltu (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + mips_emit_unknown (cpu, b, insn); + return (0); +} + +static int fastcall tne_emu (cpu_mips_t * cpu, mips_insn_t insn) +{ + int rs = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + + if ((m_ireg_t) cpu->gpr[rs] != (m_ireg_t) cpu->gpr[rt]) { + /*take a trap */ + mips_trigger_trap_exception (cpu); + return (1); + } else + return (0); + +} + +static int mips_emit_tne (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + x86_mov_reg_imm (b->jit_ptr, X86_EDX, insn); + x86_mov_reg_reg (b->jit_ptr, X86_EAX, X86_EDI, 4); + mips_emit_basic_c_call (b, tne_emu); + return (0); + +} + +static int mips_emit_tnei (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + mips_emit_unknown (cpu, b, insn); + return (0); +} + +static int mips_emit_wait (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + return (0); +} + +static int mips_emit_xor (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + int rs = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + int rd = bits (insn, 11, 15); + + x86_mov_reg_membase (b->jit_ptr, X86_EAX, X86_EDI, REG_OFFSET (rs), 4); + + x86_alu_reg_membase (b->jit_ptr, X86_XOR, X86_EAX, X86_EDI, + REG_OFFSET (rt)); + + x86_mov_membase_reg (b->jit_ptr, X86_EDI, REG_OFFSET (rd), X86_EAX, 4); + + return (0); + +} + +static int mips_emit_xori (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + int rs = bits (insn, 21, 25); + int rt = bits (insn, 16, 20); + int imm = bits (insn, 0, 15); + + x86_mov_reg_imm (b->jit_ptr, X86_EAX, imm); + x86_alu_reg_membase (b->jit_ptr, X86_XOR, X86_EAX, X86_EDI, + REG_OFFSET (rs)); + + x86_mov_membase_reg (b->jit_ptr, X86_EDI, REG_OFFSET (rt), X86_EAX, 4); + + return (0); + +} + +static int mips_emit_undef (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + mips_emit_unknown (cpu, b, insn); + return (0); +} + +static int mips_emit_unknownBcond (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + mips_emit_unknown (cpu, b, insn); + return (0); +} + +static int mips_emit_unknowncop0 (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + mips_emit_unknown (cpu, b, insn); + return (0); +} + +static int mips_emit_unknownmad (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + mips_emit_unknown (cpu, b, insn); + return (0); +} + +static int mips_emit_unknownSpec (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + mips_emit_unknown (cpu, b, insn); + return (0); +} + +static int mips_emit_unknowntlb (cpu_mips_t * cpu, mips_jit_tcb_t * b, + unsigned int insn) +{ + mips_emit_unknown (cpu, b, insn); + return (0); +} + +/*instruction table*/ + +struct mips_jit_desc mips_jit[] = { + {"spec", mips_emit_spec, 0x00, 0x99}, + {"bcond", mips_emit_bcond, 0x01, 0x99}, + {"j", mips_emit_j, 0x02, 0x0}, + {"jal", mips_emit_jal, 0x03, 0x0}, + {"beq", mips_emit_beq, 0x04, 0x0}, + {"bne", mips_emit_bne, 0x05, 0x0}, + {"blez", mips_emit_blez, 0x06, 0x0}, + {"bgtz", mips_emit_bgtz, 0x07, 0x0}, + {"addi", mips_emit_addi, 0x08, 0x1}, + {"addiu", mips_emit_addiu, 0x09, 0x1}, + {"slti", mips_emit_slti, 0x0A, 0x1}, + {"sltiu", mips_emit_sltiu, 0x0B, 0x1}, + {"andi", mips_emit_andi, 0x0C, 0x1}, + {"ori", mips_emit_ori, 0x0D, 0x1}, + {"xori", mips_emit_xori, 0x0E, 0x1}, + {"lui", mips_emit_lui, 0x0F, 0x1}, + {"cop0", mips_emit_cop0, 0x10, 0x99}, + {"cop1", mips_emit_cop1, 0x11, 0x1}, + {"cop2", mips_emit_cop2, 0x12, 0x1}, + {"cop1x", mips_emit_cop1x, 0x13, 0x1}, + {"beql", mips_emit_beql, 0x14, 0x0}, + {"bnel", mips_emit_bnel, 0x15, 0x0}, + {"blezl", mips_emit_blezl, 0x16, 0x0}, + {"bgtzl", mips_emit_bgtzl, 0x17, 0x0}, + {"daddi", mips_emit_daddi, 0x18, 0x1}, + {"daddiu", mips_emit_daddiu, 0x19, 0x1}, + {"ldl", mips_emit_ldl, 0x1A, 0x1}, + {"ldr", mips_emit_ldr, 0x1B, 0x1}, + {"undef", mips_emit_mad, 0x1C, 0x99}, + {"undef", mips_emit_undef, 0x1D, 0x1}, + {"undef", mips_emit_undef, 0x1E, 0x1}, + {"undef", mips_emit_undef, 0x1F, 0x1}, + {"lb", mips_emit_lb, 0x20, 0x1}, + {"lh", mips_emit_lh, 0x21, 0x1}, + {"lwl", mips_emit_lwl, 0x22, 0x1}, + {"lw", mips_emit_lw, 0x23, 0x1}, + {"lbu", mips_emit_lbu, 0x24, 0x1}, + {"lhu", mips_emit_lhu, 0x25, 0x1}, + {"lwr", mips_emit_lwr, 0x26, 0x1}, + {"lwu", mips_emit_lwu, 0x27, 0x1}, + {"sb", mips_emit_sb, 0x28, 0x1}, + {"sh", mips_emit_sh, 0x29, 0x1}, + {"swl", mips_emit_swl, 0x2A, 0x1}, + {"sw", mips_emit_sw, 0x2B, 0x1}, + {"sdl", mips_emit_sdl, 0x2C, 0x1}, + {"sdr", mips_emit_sdr, 0x2D, 0x1}, + {"swr", mips_emit_swr, 0x2E, 0x1}, + {"cache", mips_emit_cache, 0x2F, 0x1}, + {"ll", mips_emit_ll, 0x30, 0x1}, + {"lwc1", mips_emit_lwc1, 0x31, 0x1}, + {"lwc2", mips_emit_lwc2, 0x32, 0x1}, + {"pref", mips_emit_pref, 0x33, 0x1}, + {"lld", mips_emit_lld, 0x34, 0x1}, + {"ldc1", mips_emit_ldc1, 0x35, 0x1}, + {"ldc2", mips_emit_ldc2, 0x36, 0x1}, + {"ld", mips_emit_ld, 0x37, 0x1}, + {"sc", mips_emit_sc, 0x38, 0x1}, + {"swc1", mips_emit_swc1, 0x39, 0x1}, + {"swc2", mips_emit_swc2, 0x3A, 0x1}, + {"undef", mips_emit_undef, 0x3B, 0x1}, + {"scd", mips_emit_scd, 0x3C, 0x1}, + {"sdc1", mips_emit_sdc1, 0x3D, 0x1}, + {"sdc2", mips_emit_sdc2, 0x3E, 0x1}, + {"sd", mips_emit_sd, 0x3F, 0x1}, +}; + +/* Based on the func field of spec opcode */ +static struct mips_jit_desc mips_spec_jit[] = { + {"sll", mips_emit_sll, 0x00, 0x1}, + {"movc", mips_emit_movc, 0x01, 0x1}, + {"srl", mips_emit_srl, 0x02, 0x1}, + {"sra", mips_emit_sra, 0x03, 0x1}, + {"sllv", mips_emit_sllv, 0x04, 0x1}, + {"unknownSpec", mips_emit_unknownSpec, 0x05, 0x1}, + {"srlv", mips_emit_srlv, 0x06, 0x1}, + {"srav", mips_emit_srav, 0x07, 0x1}, + {"jr", mips_emit_jr, 0x08, 0x0}, + {"jalr", mips_emit_jalr, 0x09, 0x0}, + {"movz", mips_emit_movz, 0x0A, 0x1}, + {"movn", mips_emit_movn, 0x0B, 0x1}, + {"syscall", mips_emit_syscall, 0x0C, 0x1}, + {"break", mips_emit_break, 0x0D, 0x1}, + {"spim", mips_emit_unknownSpec, 0x0E, 0x1}, + {"sync", mips_emit_sync, 0x0F, 0x1}, + {"mfhi", mips_emit_mfhi, 0x10, 0x1}, + {"mthi", mips_emit_mthi, 0x11, 0x1}, + {"mflo", mips_emit_mflo, 0x12, 0x1}, + {"mtlo", mips_emit_mtlo, 0x13, 0x1}, + {"dsllv", mips_emit_dsllv, 0x14, 0x1}, + {"unknownSpec", mips_emit_unknownSpec, 0x15, 0x1}, + {"dsrlv", mips_emit_dsrlv, 0x16, 0x1}, + {"dsrav", mips_emit_dsrav, 0x17, 0x1}, + {"mult", mips_emit_mult, 0x18, 0x1}, + {"multu", mips_emit_multu, 0x19, 0x1}, + {"div", mips_emit_div, 0x1A, 0x1}, + {"divu", mips_emit_divu, 0x1B, 0x1}, + {"dmult", mips_emit_dmult, 0x1C, 0x1}, + {"dmultu", mips_emit_dmultu, 0x1D, 0x1}, + {"ddiv", mips_emit_ddiv, 0x1E, 0x1}, + {"ddivu", mips_emit_ddivu, 0x1F, 0x1}, + {"add", mips_emit_add, 0x20, 0x1}, + {"addu", mips_emit_addu, 0x21, 0x1}, + {"sub", mips_emit_sub, 0x22, 0x1}, + {"subu", mips_emit_subu, 0x23, 0x1}, + {"and", mips_emit_and, 0x24, 0x1}, + {"or", mips_emit_or, 0x25, 0x1}, + {"xor", mips_emit_xor, 0x26, 0x1}, + {"nor", mips_emit_nor, 0x27, 0x1}, + {"unknownSpec", mips_emit_unknownSpec, 0x28, 0x1}, + {"unknownSpec", mips_emit_unknownSpec, 0x29, 0x1}, + {"slt", mips_emit_slt, 0x2A, 0x1}, + {"sltu", mips_emit_sltu, 0x2B, 0x1}, + {"dadd", mips_emit_dadd, 0x2C, 0x1}, + {"daddu", mips_emit_daddu, 0x2D, 0x1}, + {"dsub", mips_emit_dsub, 0x2E, 0x1}, + {"dsubu", mips_emit_dsubu, 0x2F, 0x1}, + {"tge", mips_emit_tge, 0x30, 0x1}, + {"tgeu", mips_emit_tgeu, 0x31, 0x1}, + {"tlt", mips_emit_tlt, 0x32, 0x1}, + {"tltu", mips_emit_tltu, 0x33, 0x1}, + {"teq", mips_emit_teq, 0x34, 0x1}, + {"unknownSpec", mips_emit_unknownSpec, 0x35, 0x1}, + {"tne", mips_emit_tne, 0x36, 0x1}, + {"unknownSpec", mips_emit_unknownSpec, 0x37, 0x1}, + {"dsll", mips_emit_dsll, 0x38, 0x1}, + {"unknownSpec", mips_emit_unknownSpec, 0x39, 0x1}, + {"dsrl", mips_emit_dsrl, 0x3A, 0x1}, + {"dsra", mips_emit_dsra, 0x3B, 0x1}, + {"dsll32", mips_emit_dsll32, 0x3C, 0x1}, + {"unknownSpec", mips_emit_unknownSpec, 0x3D, 0x1}, + {"dsrl32", mips_emit_dsrl32, 0x3E, 0x1}, + {"dsra32", mips_emit_dsra32, 0x3F, 0x1} +}; + +/* Based on the rt field of bcond opcodes */ +static struct mips_jit_desc mips_bcond_jit[] = { + {"bltz", mips_emit_bltz, 0x00, 0x0}, + {"bgez", mips_emit_bgez, 0x01, 0x0}, + {"bltzl", mips_emit_bltzl, 0x02, 0x0}, + {"bgezl", mips_emit_bgezl, 0x03, 0x0}, + {"spimi", mips_emit_unknownBcond, 0x04, 0x0}, + {"unknownBcond", mips_emit_unknownBcond, 0x05, 0x1}, + {"unknownBcond", mips_emit_unknownBcond, 0x06, 0x1}, + {"unknownBcond", mips_emit_unknownBcond, 0x07, 0x1}, + {"tgei", mips_emit_tgei, 0x08, 0x1}, + {"tgeiu", mips_emit_tgeiu, 0x09, 0x1}, + {"tlti", mips_emit_tlti, 0x0A, 0x1}, + {"tltiu", mips_emit_tltiu, 0x0B, 0x1}, + {"teqi", mips_emit_teqi, 0x0C, 0x1}, + {"unknownBcond", mips_emit_unknownBcond, 0x0D, 0x1}, + {"tnei", mips_emit_tnei, 0x0E, 0x1}, + {"unknownBcond", mips_emit_unknownBcond, 0x0F, 0x1}, + {"bltzal", mips_emit_bltzal, 0x10, 0x0}, + {"bgezal", mips_emit_bgezal, 0x11, 0x0}, + {"bltzall", mips_emit_bltzall, 0x12, 0x0}, + {"bgezall", mips_emit_bgezall, 0x13, 0x0}, + {"unknownBcond", mips_emit_unknownBcond, 0x14, 0x1}, + {"unknownBcond", mips_emit_unknownBcond, 0x15, 0x1}, + {"unknownBcond", mips_emit_unknownBcond, 0x16, 0x1}, + {"unknownBcond", mips_emit_unknownBcond, 0x17, 0x1}, + {"unknownBcond", mips_emit_unknownBcond, 0x18, 0x1}, + {"unknownBcond", mips_emit_unknownBcond, 0x19, 0x1}, + {"unknownBcond", mips_emit_unknownBcond, 0x1A, 0x1}, + {"unknownBcond", mips_emit_unknownBcond, 0x1B, 0x1}, + {"unknownBcond", mips_emit_unknownBcond, 0x1C, 0x1}, + {"unknownBcond", mips_emit_unknownBcond, 0x1D, 0x1}, + {"unknownBcond", mips_emit_unknownBcond, 0x1E, 0x1}, + {"unknownBcond", mips_emit_unknownBcond, 0x1F, 0x1} +}; + +static struct mips_jit_desc mips_cop0_jit[] = { + {"mfc0", mips_emit_mfc0, 0x0, 0x1}, + {"dmfc0", mips_emit_dmfc0, 0x1, 0x1}, + {"cfc0", mips_emit_cfc0, 0x2, 0x1}, + {"unknowncop0", mips_emit_unknowncop0, 0x3, 0x1}, + {"mtc0", mips_emit_mtc0, 0x4, 0x1}, + {"dmtc0", mips_emit_dmtc0, 0x5, 0x1}, + {"unknowncop0", mips_emit_unknowncop0, 0x6, 0x1}, + {"unknowncop0", mips_emit_unknowncop0, 0x7, 0x1}, + {"unknowncop0", mips_emit_unknowncop0, 0x8, 0x1}, + {"unknowncop0", mips_emit_unknowncop0, 0x9, 0x1}, + {"unknowncop0", mips_emit_unknowncop0, 0xa, 0x1}, + {"unknowncop0", mips_emit_unknowncop0, 0xb, 0x1}, + {"unknowncop0", mips_emit_unknowncop0, 0xc, 0x1}, + {"unknowncop0", mips_emit_unknowncop0, 0xd, 0x1}, + {"unknowncop0", mips_emit_unknowncop0, 0xe, 0x1}, + {"unknowncop0", mips_emit_unknowncop0, 0xf, 0x1}, + {"tlb", mips_emit_tlb, 0x10, 0x1}, + {"unknowncop0", mips_emit_unknowncop0, 0x11, 0x1}, + {"unknowncop0", mips_emit_unknowncop0, 0x12, 0x1}, + {"unknowncop0", mips_emit_unknowncop0, 0x13, 0x1}, + {"unknowncop0", mips_emit_unknowncop0, 0x14, 0x1}, + {"unknowncop0", mips_emit_unknowncop0, 0x15, 0x1}, + {"unknowncop0", mips_emit_unknowncop0, 0x16, 0x1}, + {"unknowncop0", mips_emit_unknowncop0, 0x17, 0x1}, + {"unknowncop0", mips_emit_unknowncop0, 0x18, 0x1}, + {"unknowncop0", mips_emit_unknowncop0, 0x19, 0x1}, + {"unknowncop0", mips_emit_unknowncop0, 0x1a, 0x1}, + {"unknowncop0", mips_emit_unknowncop0, 0x1b, 0x1}, + {"unknowncop0", mips_emit_unknowncop0, 0x1c, 0x1}, + {"unknowncop0", mips_emit_unknowncop0, 0x1d, 0x1}, + {"unknowncop0", mips_emit_unknowncop0, 0x1e, 0x1}, + {"unknowncop0", mips_emit_unknowncop0, 0x1f, 0x1}, + +}; + +static struct mips_jit_desc mips_mad_jit[] = { + {"mad", mips_emit_madd, 0x0, 0x1}, + {"maddu", mips_emit_maddu, 0x1, 0x1}, + {"mul", mips_emit_mul, 0x2, 0x1}, + {"unknownmad_op", mips_emit_unknownmad, 0x3, 0x1}, + {"msub", mips_emit_msub, 0x4, 0x1}, + {"msubu", mips_emit_msubu, 0x5, 0x1}, + {"unknownmad_op", mips_emit_unknownmad, 0x6, 0x1}, + {"unknownmad_op", mips_emit_unknownmad, 0x7, 0x1}, + {"unknownmad_op", mips_emit_unknownmad, 0x8, 0x1}, + {"unknownmad_op", mips_emit_unknownmad, 0x9, 0x1}, + {"unknownmad_op", mips_emit_unknownmad, 0xa, 0x1}, + {"unknownmad_op", mips_emit_unknownmad, 0xb, 0x1}, + {"unknownmad_op", mips_emit_unknownmad, 0xc, 0x1}, + {"unknownmad_op", mips_emit_unknownmad, 0xd, 0x1}, + {"unknownmad_op", mips_emit_unknownmad, 0xe, 0x1}, + {"unknownmad_op", mips_emit_unknownmad, 0xf, 0x1}, + {"unknownmad_op", mips_emit_unknownmad, 0x10, 0x1}, + {"unknownmad_op", mips_emit_unknownmad, 0x11, 0x1}, + {"unknownmad_op", mips_emit_unknownmad, 0x12, 0x1}, + {"unknownmad_op", mips_emit_unknownmad, 0x13, 0x1}, + {"unknownmad_op", mips_emit_unknownmad, 0x14, 0x1}, + {"unknownmad_op", mips_emit_unknownmad, 0x15, 0x1}, + {"unknownmad_op", mips_emit_unknownmad, 0x16, 0x1}, + {"unknownmad_op", mips_emit_unknownmad, 0x17, 0x1}, + {"unknownmad_op", mips_emit_unknownmad, 0x18, 0x1}, + {"unknownmad_op", mips_emit_unknownmad, 0x19, 0x1}, + {"unknownmad_op", mips_emit_unknownmad, 0x1a, 0x1}, + {"unknownmad_op", mips_emit_unknownmad, 0x1b, 0x1}, + {"unknownmad_op", mips_emit_unknownmad, 0x1c, 0x1}, + {"unknownmad_op", mips_emit_unknownmad, 0x1d, 0x1}, + {"unknownmad_op", mips_emit_unknownmad, 0x1e, 0x1}, + {"unknownmad_op", mips_emit_unknownmad, 0x1f, 0x1}, + {"clz", mips_emit_clz, 0x20, 0x1}, + {"unknownmad_op", mips_emit_unknownmad, 0x21, 0x1}, + {"unknownmad_op", mips_emit_unknownmad, 0x22, 0x1}, + {"unknownmad_op", mips_emit_unknownmad, 0x23, 0x1}, + {"unknownmad_op", mips_emit_unknownmad, 0x24, 0x1}, + {"unknownmad_op", mips_emit_unknownmad, 0x25, 0x1}, + {"unknownmad_op", mips_emit_unknownmad, 0x26, 0x1}, + {"unknownmad_op", mips_emit_unknownmad, 0x27, 0x1}, + {"unknownmad_op", mips_emit_unknownmad, 0x28, 0x1}, + {"unknownmad_op", mips_emit_unknownmad, 0x29, 0x1}, + {"unknownmad_op", mips_emit_unknownmad, 0x2a, 0x1}, + {"unknownmad_op", mips_emit_unknownmad, 0x2b, 0x1}, + {"unknownmad_op", mips_emit_unknownmad, 0x2c, 0x1}, + {"unknownmad_op", mips_emit_unknownmad, 0x2d, 0x1}, + {"unknownmad_op", mips_emit_unknownmad, 0x2e, 0x1}, + {"unknownmad_op", mips_emit_unknownmad, 0x2f, 0x1}, + {"unknownmad_op", mips_emit_unknownmad, 0x30, 0x1}, + {"unknownmad_op", mips_emit_unknownmad, 0x31, 0x1}, + {"unknownmad_op", mips_emit_unknownmad, 0x32, 0x1}, + {"unknownmad_op", mips_emit_unknownmad, 0x33, 0x1}, + {"unknownmad_op", mips_emit_unknownmad, 0x34, 0x1}, + {"unknownmad_op", mips_emit_unknownmad, 0x35, 0x1}, + {"unknownmad_op", mips_emit_unknownmad, 0x36, 0x1}, + {"unknownmad_op", mips_emit_unknownmad, 0x37, 0x1}, + {"unknownmad_op", mips_emit_unknownmad, 0x38, 0x1}, + {"unknownmad_op", mips_emit_unknownmad, 0x39, 0x1}, + {"unknownmad_op", mips_emit_unknownmad, 0x3a, 0x1}, + {"unknownmad_op", mips_emit_unknownmad, 0x3b, 0x1}, + {"unknownmad_op", mips_emit_unknownmad, 0x3c, 0x1}, + {"unknownmad_op", mips_emit_unknownmad, 0x3d, 0x1}, + {"unknownmad_op", mips_emit_unknownmad, 0x3e, 0x1}, + {"unknownmad_op", mips_emit_unknownmad, 0x3f, 0x1}, + +}; + +static struct mips_jit_desc mips_tlb_jit[] = { + {"unknowntlb_op", mips_emit_unknowntlb, 0x0, 0x1}, + {"tlbr", mips_emit_tlbr, 0x1, 0x1}, + {"tlbwi", mips_emit_tlbwi, 0x2, 0x1}, + {"unknowntlb_op", mips_emit_unknowntlb, 0x3, 0x1}, + {"unknowntlb_op", mips_emit_unknowntlb, 0x4, 0x1}, + {"unknowntlb_op", mips_emit_unknowntlb, 0x5, 0x1}, + {"tlbwi", mips_emit_tlbwr, 0x6, 0x1}, + {"unknowntlb_op", mips_emit_unknowntlb, 0x7, 0x1}, + {"tlbp", mips_emit_tlbp, 0x8, 0x1}, + {"unknowntlb_op", mips_emit_unknowntlb, 0x9, 0x1}, + {"unknowntlb_op", mips_emit_unknowntlb, 0xa, 0x1}, + {"unknowntlb_op", mips_emit_unknowntlb, 0xb, 0x1}, + {"unknowntlb_op", mips_emit_unknowntlb, 0xc, 0x1}, + {"unknowntlb_op", mips_emit_unknowntlb, 0xd, 0x1}, + {"unknowntlb_op", mips_emit_unknowntlb, 0xe, 0x1}, + {"unknowntlb_op", mips_emit_unknowntlb, 0xf, 0x1}, + {"unknowntlb_op", mips_emit_unknowntlb, 0x10, 0x1}, + {"unknowntlb_op", mips_emit_unknowntlb, 0x11, 0x1}, + {"unknowntlb_op", mips_emit_unknowntlb, 0x12, 0x1}, + {"unknowntlb_op", mips_emit_unknowntlb, 0x13, 0x1}, + {"unknowntlb_op", mips_emit_unknowntlb, 0x14, 0x1}, + {"unknowntlb_op", mips_emit_unknowntlb, 0x15, 0x1}, + {"unknowntlb_op", mips_emit_unknowntlb, 0x16, 0x1}, + {"unknowntlb_op", mips_emit_unknowntlb, 0x17, 0x1}, + {"eret", mips_emit_eret, 0x18, 0x1}, + {"unknowntlb_op", mips_emit_unknowntlb, 0x19, 0x1}, + {"unknowntlb_op", mips_emit_unknowntlb, 0x1a, 0x1}, + {"unknowntlb_op", mips_emit_unknowntlb, 0x1b, 0x1}, + {"unknowntlb_op", mips_emit_unknowntlb, 0x1c, 0x1}, + {"unknowntlb_op", mips_emit_unknowntlb, 0x1d, 0x1}, + {"unknowntlb_op", mips_emit_unknowntlb, 0x1e, 0x1}, + {"unknowntlb_op", mips_emit_unknowntlb, 0x1f, 0x1}, + {"wait", mips_emit_wait, 0x20, 0x1}, + {"unknowntlb_op", mips_emit_unknowntlb, 0x21, 0x1}, + {"unknowntlb_op", mips_emit_unknowntlb, 0x22, 0x1}, + {"unknowntlb_op", mips_emit_unknowntlb, 0x23, 0x1}, + {"unknowntlb_op", mips_emit_unknowntlb, 0x24, 0x1}, + {"unknowntlb_op", mips_emit_unknowntlb, 0x25, 0x1}, + {"unknowntlb_op", mips_emit_unknowntlb, 0x26, 0x1}, + {"unknowntlb_op", mips_emit_unknowntlb, 0x27, 0x1}, + {"unknowntlb_op", mips_emit_unknowntlb, 0x28, 0x1}, + {"unknowntlb_op", mips_emit_unknowntlb, 0x29, 0x1}, + {"unknowntlb_op", mips_emit_unknowntlb, 0x2a, 0x1}, + {"unknowntlb_op", mips_emit_unknowntlb, 0x2b, 0x1}, + {"unknowntlb_op", mips_emit_unknowntlb, 0x2c, 0x1}, + {"unknowntlb_op", mips_emit_unknowntlb, 0x2d, 0x1}, + {"unknowntlb_op", mips_emit_unknowntlb, 0x2e, 0x1}, + {"unknowntlb_op", mips_emit_unknowntlb, 0x2f, 0x1}, + {"unknowntlb_op", mips_emit_unknowntlb, 0x30, 0x1}, + {"unknowntlb_op", mips_emit_unknowntlb, 0x31, 0x1}, + {"unknowntlb_op", mips_emit_unknowntlb, 0x32, 0x1}, + {"unknowntlb_op", mips_emit_unknowntlb, 0x33, 0x1}, + {"unknowntlb_op", mips_emit_unknowntlb, 0x34, 0x1}, + {"unknowntlb_op", mips_emit_unknowntlb, 0x35, 0x1}, + {"unknowntlb_op", mips_emit_unknowntlb, 0x36, 0x1}, + {"unknowntlb_op", mips_emit_unknowntlb, 0x37, 0x1}, + {"unknowntlb_op", mips_emit_unknowntlb, 0x38, 0x1}, + {"unknowntlb_op", mips_emit_unknowntlb, 0x39, 0x1}, + {"unknowntlb_op", mips_emit_unknowntlb, 0x3a, 0x1}, + {"unknowntlb_op", mips_emit_unknowntlb, 0x3b, 0x1}, + {"unknowntlb_op", mips_emit_unknowntlb, 0x3c, 0x1}, + {"unknowntlb_op", mips_emit_unknowntlb, 0x3d, 0x1}, + {"unknowntlb_op", mips_emit_unknowntlb, 0x3e, 0x1}, + {"unknowntlb_op", mips_emit_unknowntlb, 0x3f, 0x1}, + +}; +#endif diff --git a/tools/virtualmips/x86_trans.h b/tools/virtualmips/x86_trans.h new file mode 100644 index 0000000..330c02b --- /dev/null +++ b/tools/virtualmips/x86_trans.h @@ -0,0 +1,75 @@ +/* + * Cisco router simulation platform. + * Copyright (c) 2005,2006 Christophe Fillot (cf@utc.fr) + */ +/* + * Copyright (C) yajin 2008 + * + * This file is part of the virtualmips distribution. + * See LICENSE file for terms of the license. + * + */ + +#ifndef __MIPS64_X86_TRANS_H__ + +#define __MIPS64_X86_TRANS_H__ + +#include "system.h" +#include "x86-codegen.h" + +#ifdef _USE_JIT_ + +/* Manipulate bitmasks atomically */ +static forced_inline void x86_atomic_or (m_uint32_t * v, m_uint32_t m) +{ + __asm__ __volatile__ ("lock; orl %1,%0":"=m" (*v):"ir" (m), "m" (*v)); +} + +static forced_inline void x86_atomic_and (m_uint32_t * v, m_uint32_t m) +{ + __asm__ __volatile__ ("lock; andl %1,%0":"=m" (*v):"ir" (m), "m" (*v)); +} + +/* Wrappers to x86-codegen functions */ +#define mips_jit_tcb_set_patch x86_patch +#define mips_jit_tcb_set_jump x86_jump_code + +/* Push epilog for an x86 instruction block */ +static forced_inline void mips_jit_tcb_push_epilog (mips_jit_tcb_t * + block) +{ + x86_ret (block->jit_ptr); +} + +/* Translated block function pointer */ +typedef void (*insn_tblock_fptr) (void); +void fastcall mips_exec_single_step (cpu_mips_t * cpu, + mips_insn_t instruction); + +/* Execute JIT code */ +static forced_inline + void mips_jit_tcb_exec (cpu_mips_t * cpu, mips_jit_tcb_t * block) +{ + insn_tblock_fptr jit_code; + m_uint32_t offset; + + offset = (cpu->pc & MIPS_MIN_PAGE_IMASK) >> 2; + jit_code = (insn_tblock_fptr) block->jit_insn_ptr[offset]; + + if (unlikely (!jit_code)) { + mips_exec_single_step (cpu, vmtoh32 (block->mips_code[offset])); + return; + } + + asm volatile ("movl %0,%%edi"::"r" (cpu): "esi", "edi", "ecx", "edx"); + jit_code (); +} + +void mips_set_pc (mips_jit_tcb_t * b, m_va_t new_pc); +void mips_emit_single_step (mips_jit_tcb_t * b, mips_insn_t insn); +void mips_check_cpu_pausing (mips_jit_tcb_t * b); +void mips_check_pending_irq (mips_jit_tcb_t * b); + +#endif + +#endif diff --git a/var/log/messages b/var/log/messages new file mode 100644 index 0000000..e69de29 diff --git a/var/log/wtmp b/var/log/wtmp new file mode 100644 index 0000000..e69de29